summaryrefslogtreecommitdiffstats
path: root/svx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /svx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'svx')
-rw-r--r--svx/AllLangMoTarget_svx.mk11
-rw-r--r--svx/CppunitTest_svx_core.mk49
-rw-r--r--svx/CppunitTest_svx_dialogs_test.mk71
-rw-r--r--svx/CppunitTest_svx_gallery_test.mk56
-rw-r--r--svx/CppunitTest_svx_removewhichrange.mk62
-rw-r--r--svx/CppunitTest_svx_styles.mk44
-rw-r--r--svx/CppunitTest_svx_unit.mk65
-rw-r--r--svx/Executable_gengal.mk68
-rw-r--r--svx/IwyuFilter_svx.yaml157
-rw-r--r--svx/JunitTest_svx_unoapi.mk24
-rw-r--r--svx/Library_svx.mk291
-rw-r--r--svx/Library_svxcore.mk497
-rw-r--r--svx/Library_textconversiondlgs.mk53
-rw-r--r--svx/Makefile7
-rw-r--r--svx/Module_svx.mk78
-rw-r--r--svx/Package_gengal.mk24
-rw-r--r--svx/README.md105
-rw-r--r--svx/UIConfig_svx.mk151
-rw-r--r--svx/UITest_svx_table.mk16
-rw-r--r--svx/doc/UML/edit_engine_UNO_implementation.zuml1
-rw-r--r--svx/doc/UML/grid_control_implementation.zumlbin0 -> 36412 bytes
-rw-r--r--svx/doc/UML/readme.txt9
-rw-r--r--svx/doc/drawing_layer_UNO_objects.odgbin0 -> 13284 bytes
-rw-r--r--svx/inc/AccessibleTableShape.hxx216
-rw-r--r--svx/inc/AffineMatrixItem.hxx44
-rw-r--r--svx/inc/CommonStylePreviewRenderer.hxx49
-rw-r--r--svx/inc/DescriptionGenerator.hxx140
-rw-r--r--svx/inc/GalleryControl.hxx52
-rw-r--r--svx/inc/ParaLineSpacingPopup.hxx46
-rw-r--r--svx/inc/TextCharacterSpacingPopup.hxx44
-rw-r--r--svx/inc/TextUnderlinePopup.hxx44
-rw-r--r--svx/inc/XPropertyTable.hxx35
-rw-r--r--svx/inc/bitmaps.hlst288
-rw-r--r--svx/inc/colrctrl.hxx102
-rw-r--r--svx/inc/dbcharsethelper.hxx34
-rw-r--r--svx/inc/dragmt3d.hxx122
-rw-r--r--svx/inc/dstribut_enum.hxx39
-rw-r--r--svx/inc/extrud3d.hxx112
-rw-r--r--svx/inc/extrusiondepthdialog.hxx41
-rw-r--r--svx/inc/fieldunit.hrc46
-rw-r--r--svx/inc/fmstring.hrc57
-rw-r--r--svx/inc/formnavi.hrc53
-rw-r--r--svx/inc/frmsel.hrc57
-rw-r--r--svx/inc/galbrws2.hxx185
-rw-r--r--svx/inc/galleryobjectbinarystorage.hxx35
-rw-r--r--svx/inc/galleryobjectxmlstorage.hxx35
-rw-r--r--svx/inc/galobj.hxx177
-rw-r--r--svx/inc/getallcharpropids.hxx36
-rw-r--r--svx/inc/helpids.h66
-rw-r--r--svx/inc/inspectorvalues.hrc29
-rw-r--r--svx/inc/layctrl.hxx62
-rw-r--r--svx/inc/lboxctrl.hxx57
-rw-r--r--svx/inc/numberingtype.hrc70
-rw-r--r--svx/inc/palettes.hxx97
-rw-r--r--svx/inc/pch/precompiled_svx.cxx12
-rw-r--r--svx/inc/pch/precompiled_svx.hxx443
-rw-r--r--svx/inc/pch/precompiled_svxcore.cxx12
-rw-r--r--svx/inc/pch/precompiled_svxcore.hxx552
-rw-r--r--svx/inc/polygn3d.hxx65
-rw-r--r--svx/inc/rotationstrings.hrc28
-rw-r--r--svx/inc/samecontent.hrc28
-rw-r--r--svx/inc/sdgcoitm.hxx69
-rw-r--r--svx/inc/sdginitm.hxx39
-rw-r--r--svx/inc/sdgtritm.hxx40
-rw-r--r--svx/inc/sdr/attribute/sdreffectstextattribute.hxx67
-rw-r--r--svx/inc/sdr/attribute/sdrfilltextattribute.hxx60
-rw-r--r--svx/inc/sdr/attribute/sdrformtextattribute.hxx81
-rw-r--r--svx/inc/sdr/attribute/sdrformtextoutlineattribute.hxx74
-rw-r--r--svx/inc/sdr/attribute/sdrlineeffectstextattribute.hxx62
-rw-r--r--svx/inc/sdr/attribute/sdrlinefilleffectstextattribute.hxx63
-rw-r--r--svx/inc/sdr/attribute/sdrtextattribute.hxx116
-rw-r--r--svx/inc/sdr/contact/objectcontactofobjlistpainter.hxx114
-rw-r--r--svx/inc/sdr/contact/viewcontactofe3d.hxx93
-rw-r--r--svx/inc/sdr/contact/viewcontactofe3dcube.hxx52
-rw-r--r--svx/inc/sdr/contact/viewcontactofe3dextrude.hxx53
-rw-r--r--svx/inc/sdr/contact/viewcontactofe3dlathe.hxx53
-rw-r--r--svx/inc/sdr/contact/viewcontactofe3dpolygon.hxx51
-rw-r--r--svx/inc/sdr/contact/viewcontactofe3dsphere.hxx53
-rw-r--r--svx/inc/sdr/contact/viewcontactofgraphic.hxx74
-rw-r--r--svx/inc/sdr/contact/viewcontactofgroup.hxx57
-rw-r--r--svx/inc/sdr/contact/viewcontactofmasterpagedescriptor.hxx68
-rw-r--r--svx/inc/sdr/contact/viewcontactofpageobj.hxx53
-rw-r--r--svx/inc/sdr/contact/viewcontactofsdrcaptionobj.hxx46
-rw-r--r--svx/inc/sdr/contact/viewcontactofsdrcircobj.hxx52
-rw-r--r--svx/inc/sdr/contact/viewcontactofsdredgeobj.hxx52
-rw-r--r--svx/inc/sdr/contact/viewcontactofsdrmeasureobj.hxx52
-rw-r--r--svx/inc/sdr/contact/viewcontactofsdrobjcustomshape.hxx55
-rw-r--r--svx/inc/sdr/contact/viewcontactofsdrole2obj.hxx70
-rw-r--r--svx/inc/sdr/contact/viewcontactofsdrpage.hxx204
-rw-r--r--svx/inc/sdr/contact/viewcontactofsdrpathobj.hxx52
-rw-r--r--svx/inc/sdr/contact/viewcontactofsdrrectobj.hxx46
-rw-r--r--svx/inc/sdr/contact/viewcontactoftextobj.hxx37
-rw-r--r--svx/inc/sdr/contact/viewcontactofunocontrol.hxx77
-rw-r--r--svx/inc/sdr/contact/viewobjectcontactofe3d.hxx52
-rw-r--r--svx/inc/sdr/contact/viewobjectcontactofe3dscene.hxx47
-rw-r--r--svx/inc/sdr/contact/viewobjectcontactofgraphic.hxx42
-rw-r--r--svx/inc/sdr/contact/viewobjectcontactofgroup.hxx45
-rw-r--r--svx/inc/sdr/contact/viewobjectcontactofmasterpagedescriptor.hxx45
-rw-r--r--svx/inc/sdr/contact/viewobjectcontactofpageobj.hxx50
-rw-r--r--svx/inc/sdr/contact/viewobjectcontactofsdrmediaobj.hxx69
-rw-r--r--svx/inc/sdr/contact/viewobjectcontactofsdrole2obj.hxx44
-rw-r--r--svx/inc/sdr/contact/viewobjectcontactofsdrpage.hxx176
-rw-r--r--svx/inc/sdr/contact/viewobjectcontactofunocontrol.hxx125
-rw-r--r--svx/inc/sdr/overlay/overlaycrosshair.hxx45
-rw-r--r--svx/inc/sdr/overlay/overlayhandle.hxx41
-rw-r--r--svx/inc/sdr/overlay/overlayhelpline.hxx54
-rw-r--r--svx/inc/sdr/overlay/overlayline.hxx53
-rw-r--r--svx/inc/sdr/overlay/overlaymanagerbuffered.hxx76
-rw-r--r--svx/inc/sdr/overlay/overlayobjectcell.hxx50
-rw-r--r--svx/inc/sdr/overlay/overlayrectangle.hxx65
-rw-r--r--svx/inc/sdr/overlay/overlayrollingrectangle.hxx62
-rw-r--r--svx/inc/sdr/overlay/overlaytools.hxx289
-rw-r--r--svx/inc/sdr/overlay/overlaytriangle.hxx45
-rw-r--r--svx/inc/sdr/primitive2d/primitivefactory2d.hxx68
-rw-r--r--svx/inc/sdr/primitive2d/sdrattributecreator.hxx128
-rw-r--r--svx/inc/sdr/primitive2d/sdrcaptionprimitive2d.hxx72
-rw-r--r--svx/inc/sdr/primitive2d/sdrconnectorprimitive2d.hxx62
-rw-r--r--svx/inc/sdr/primitive2d/sdrcustomshapeprimitive2d.hxx80
-rw-r--r--svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx88
-rw-r--r--svx/inc/sdr/primitive2d/sdrellipseprimitive2d.hxx94
-rw-r--r--svx/inc/sdr/primitive2d/sdrgrafprimitive2d.hxx65
-rw-r--r--svx/inc/sdr/primitive2d/sdrmeasureprimitive2d.hxx118
-rw-r--r--svx/inc/sdr/primitive2d/sdrole2primitive2d.hxx65
-rw-r--r--svx/inc/sdr/primitive2d/sdrolecontentprimitive2d.hxx73
-rw-r--r--svx/inc/sdr/primitive2d/sdrpathprimitive2d.hxx82
-rw-r--r--svx/inc/sdr/primitive2d/sdrprimitivetools.hxx42
-rw-r--r--svx/inc/sdr/primitive2d/sdrrectangleprimitive2d.hxx73
-rw-r--r--svx/inc/sdr/primitive2d/sdrtextprimitive2d.hxx335
-rw-r--r--svx/inc/sdr/primitive3d/sdrattributecreator3d.hxx44
-rw-r--r--svx/inc/sdr/properties/attributeproperties.hxx96
-rw-r--r--svx/inc/sdr/properties/captionproperties.hxx62
-rw-r--r--svx/inc/sdr/properties/circleproperties.hxx62
-rw-r--r--svx/inc/sdr/properties/connectorproperties.hxx58
-rw-r--r--svx/inc/sdr/properties/customshapeproperties.hxx86
-rw-r--r--svx/inc/sdr/properties/e3dcompoundproperties.hxx63
-rw-r--r--svx/inc/sdr/properties/e3dextrudeproperties.hxx52
-rw-r--r--svx/inc/sdr/properties/e3dlatheproperties.hxx52
-rw-r--r--svx/inc/sdr/properties/e3dproperties.hxx56
-rw-r--r--svx/inc/sdr/properties/e3dsceneproperties.hxx78
-rw-r--r--svx/inc/sdr/properties/e3dsphereproperties.hxx52
-rw-r--r--svx/inc/sdr/properties/emptyproperties.hxx75
-rw-r--r--svx/inc/sdr/properties/graphicproperties.hxx65
-rw-r--r--svx/inc/sdr/properties/groupproperties.hxx97
-rw-r--r--svx/inc/sdr/properties/itemsettools.hxx59
-rw-r--r--svx/inc/sdr/properties/measureproperties.hxx62
-rw-r--r--svx/inc/sdr/properties/oleproperties.hxx55
-rw-r--r--svx/inc/sdr/properties/pageproperties.hxx80
-rw-r--r--svx/inc/sdr/properties/rectangleproperties.hxx56
-rw-r--r--svx/inc/sdr/properties/textproperties.hxx88
-rw-r--r--svx/inc/spacing.hrc95
-rw-r--r--svx/inc/strings.hxx394
-rw-r--r--svx/inc/svxerr.hrc78
-rw-r--r--svx/inc/swframeposstrings.hrc78
-rw-r--r--svx/inc/sxallitm.hxx63
-rw-r--r--svx/inc/sxcaitm.hxx48
-rw-r--r--svx/inc/sxcikitm.hxx41
-rw-r--r--svx/inc/sxfiitm.hxx39
-rw-r--r--svx/inc/sxlayitm.hxx43
-rw-r--r--svx/inc/sxlogitm.hxx45
-rw-r--r--svx/inc/sxmfsitm.hxx35
-rw-r--r--svx/inc/sxmkitm.hxx44
-rw-r--r--svx/inc/sxmoitm.hxx42
-rw-r--r--svx/inc/sxmovitm.hxx45
-rw-r--r--svx/inc/sxmsitm.hxx43
-rw-r--r--svx/inc/sxmtaitm.hxx50
-rw-r--r--svx/inc/sxoneitm.hxx63
-rw-r--r--svx/inc/sxopitm.hxx45
-rw-r--r--svx/inc/sxreaitm.hxx46
-rw-r--r--svx/inc/sxreoitm.hxx46
-rw-r--r--svx/inc/sxroaitm.hxx40
-rw-r--r--svx/inc/sxrooitm.hxx36
-rw-r--r--svx/inc/sxsaitm.hxx40
-rw-r--r--svx/inc/sxsalitm.hxx45
-rw-r--r--svx/inc/sxsiitm.hxx30
-rw-r--r--svx/inc/sxsoitm.hxx45
-rw-r--r--svx/inc/sxtraitm.hxx63
-rw-r--r--svx/inc/tabwin.hrc36
-rw-r--r--svx/inc/tbxcolorupdate.hxx150
-rw-r--r--svx/inc/textchain.hxx106
-rw-r--r--svx/inc/textchaincursor.hxx63
-rw-r--r--svx/inc/textchainflow.hxx100
-rw-r--r--svx/inc/txenctab.hrc115
-rw-r--r--svx/inc/uiobject.hxx54
-rw-r--r--svx/inc/unomlstr.hxx49
-rw-r--r--svx/inc/verttexttbxctrl.hxx74
-rw-r--r--svx/inc/xftshtit.hxx37
-rw-r--r--svx/inc/xpolyimp.hxx63
-rw-r--r--svx/qa/uitest/table/tablecontroller.py76
-rw-r--r--svx/qa/unit/XTableImportExportTest.cxx80
-rw-r--r--svx/qa/unit/classicshapes.cxx211
-rw-r--r--svx/qa/unit/core.cxx128
-rw-r--r--svx/qa/unit/customshapes.cxx1405
-rw-r--r--svx/qa/unit/data/0-width-text-wrap.pptxbin0 -> 26504 bytes
-rw-r--r--svx/qa/unit/data/3d-object-fallback.odpbin0 -> 44589 bytes
-rw-r--r--svx/qa/unit/data/FontWork.odgbin0 -> 10515 bytes
-rw-r--r--svx/qa/unit/data/GraphicObjectResolverTest.zipbin0 -> 740 bytes
-rw-r--r--svx/qa/unit/data/auto-height-multi-col-shape.pptxbin0 -> 16350 bytes
-rw-r--r--svx/qa/unit/data/chart.odsbin0 -> 19734 bytes
-rw-r--r--svx/qa/unit/data/graphic.pdfbin0 -> 7243 bytes
-rw-r--r--svx/qa/unit/data/page-view-draw-layer-clip.docxbin0 -> 20764 bytes
-rw-r--r--svx/qa/unit/data/shadow-scale-origin.pptxbin0 -> 31984 bytes
-rw-r--r--svx/qa/unit/data/slide-background.odpbin0 -> 28090 bytes
-rw-r--r--svx/qa/unit/data/slide-background.pngbin0 -> 18426 bytes
-rw-r--r--svx/qa/unit/data/svx-dialogs-test.txt80
-rw-r--r--svx/qa/unit/data/table-shadow-blur.pptxbin0 -> 33745 bytes
-rw-r--r--svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odpbin0 -> 12420 bytes
-rw-r--r--svx/qa/unit/data/tdf103474_commandT_CaseZeroHeight.odpbin0 -> 12833 bytes
-rw-r--r--svx/qa/unit/data/tdf115813_HandleMovementOOXMLPresetShapes.pptxbin0 -> 34858 bytes
-rw-r--r--svx/qa/unit/data/tdf121761_Accuracy_command_X.odpbin0 -> 11177 bytes
-rw-r--r--svx/qa/unit/data/tdf121845_HalfEllipseVML.docbin0 -> 27648 bytes
-rw-r--r--svx/qa/unit/data/tdf121845_Two_commands_U.odgbin0 -> 10751 bytes
-rw-r--r--svx/qa/unit/data/tdf121845_WidthOrientation_command_U.odgbin0 -> 9908 bytes
-rw-r--r--svx/qa/unit/data/tdf121845_start40_swing480.docbin0 -> 27648 bytes
-rw-r--r--svx/qa/unit/data/tdf121952_Toggle_direction_command_X.odpbin0 -> 12029 bytes
-rw-r--r--svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptxbin0 -> 15580 bytes
-rw-r--r--svx/qa/unit/data/tdf122964_MultipleMoveTo.odgbin0 -> 9666 bytes
-rw-r--r--svx/qa/unit/data/tdf124029_Arc_position.docbin0 -> 19456 bytes
-rw-r--r--svx/qa/unit/data/tdf124212_handle_position.odgbin0 -> 10108 bytes
-rw-r--r--svx/qa/unit/data/tdf124740_HandleInOOXMLUserShape.pptxbin0 -> 14929 bytes
-rw-r--r--svx/qa/unit/data/tdf125782_QuadraticCurveTo.odgbin0 -> 9910 bytes
-rw-r--r--svx/qa/unit/data/tdf126060_3D_Z_Rotation.pptxbin0 -> 32602 bytes
-rw-r--r--svx/qa/unit/data/tdf126512_OOXMLHandleMovementInODF.odpbin0 -> 62627 bytes
-rw-r--r--svx/qa/unit/data/tdf127785_Mirror.odpbin0 -> 13742 bytes
-rw-r--r--svx/qa/unit/data/tdf127785_TextRotateAngle.odpbin0 -> 12841 bytes
-rw-r--r--svx/qa/unit/data/tdf127785_asymmetricTextBoxFlipV.odgbin0 -> 12166 bytes
-rw-r--r--svx/qa/unit/data/tdf128413_tbrl_OnOff.odpbin0 -> 14170 bytes
-rw-r--r--svx/qa/unit/data/tdf129532_MatrixFlipV.odgbin0 -> 10036 bytes
-rw-r--r--svx/qa/unit/data/tdf130076_FlipOnSectorSection.odgbin0 -> 13736 bytes
-rw-r--r--svx/qa/unit/data/tdf136176_rot30_flip.odgbin0 -> 10344 bytes
-rw-r--r--svx/qa/unit/data/tdf138945_resizeRotatedShape.odgbin0 -> 9457 bytes
-rw-r--r--svx/qa/unit/data/tdf140321_Matte_import.pptbin0 -> 13312 bytes
-rw-r--r--svx/qa/unit/data/tdf140321_material_specular.odpbin0 -> 12939 bytes
-rw-r--r--svx/qa/unit/data/tdf140321_metal.odpbin0 -> 16876 bytes
-rw-r--r--svx/qa/unit/data/tdf140321_phong.odpbin0 -> 14088 bytes
-rw-r--r--svx/qa/unit/data/tdf141021_ExtrusionNorth.odpbin0 -> 14261 bytes
-rw-r--r--svx/qa/unit/data/tdf141268.odpbin0 -> 12987 bytes
-rw-r--r--svx/qa/unit/data/tdf144988_Fontwork_FontSize.odpbin0 -> 11169 bytes
-rw-r--r--svx/qa/unit/data/tdf145004_gap_by_ScaleX.pptxbin0 -> 16077 bytes
-rw-r--r--svx/qa/unit/data/tdf145111_TL_BL_Fontwork.odpbin0 -> 13908 bytes
-rw-r--r--svx/qa/unit/data/tdf145245_ExtrusionPosition.odpbin0 -> 12983 bytes
-rw-r--r--svx/qa/unit/data/tdf145700_3D_FirstLightHarsh.docbin0 -> 27136 bytes
-rw-r--r--svx/qa/unit/data/tdf145700_3D_FrontLightDim.docbin0 -> 27136 bytes
-rw-r--r--svx/qa/unit/data/tdf145700_3D_NonUI.docbin0 -> 29184 bytes
-rw-r--r--svx/qa/unit/data/tdf145904_center_Y0dot25.docbin0 -> 27136 bytes
-rw-r--r--svx/qa/unit/data/tdf145904_center_Y0dot25.odtbin0 -> 10618 bytes
-rw-r--r--svx/qa/unit/data/tdf145904_center_Zminus2000.odtbin0 -> 9602 bytes
-rw-r--r--svx/qa/unit/data/tdf145956_Origin.odpbin0 -> 28073 bytes
-rw-r--r--svx/qa/unit/data/tdf147409_GeomItemHash.odgbin0 -> 14274 bytes
-rw-r--r--svx/qa/unit/data/tdf148501_OctagonBevel.odpbin0 -> 15018 bytes
-rw-r--r--svx/qa/unit/data/tdf148707_two_commands_B_V.odpbin0 -> 13389 bytes
-rw-r--r--svx/qa/unit/data/tdf148714_CurvedArrows.pptbin0 -> 99840 bytes
-rw-r--r--svx/qa/unit/data/tdf60684.jpgbin0 -> 35738 bytes
-rw-r--r--svx/qa/unit/data/tdf93998.odpbin0 -> 11308 bytes
-rw-r--r--svx/qa/unit/data/tdf98583_ShearHorizontal.odpbin0 -> 14328 bytes
-rw-r--r--svx/qa/unit/data/tdf98584_ShearVertical.odgbin0 -> 9109 bytes
-rw-r--r--svx/qa/unit/data/theme.pptxbin0 -> 30646 bytes
-rw-r--r--svx/qa/unit/data/unodraw-writer-image.odtbin0 -> 9564 bytes
-rw-r--r--svx/qa/unit/data/video-snapshot.pptxbin0 -> 40331 bytes
-rw-r--r--svx/qa/unit/data/viewBox_positive_twolines_strict.odpbin0 -> 12107 bytes
-rw-r--r--svx/qa/unit/gallery/data/galtest1.pngbin0 -> 172 bytes
-rw-r--r--svx/qa/unit/gallery/data/galtest2.pngbin0 -> 138 bytes
-rw-r--r--svx/qa/unit/gallery/data/galtest3.jpgbin0 -> 762 bytes
-rw-r--r--svx/qa/unit/gallery/test_gallery.cxx482
-rw-r--r--svx/qa/unit/removewhichrange.cxx122
-rw-r--r--svx/qa/unit/sdr.cxx149
-rw-r--r--svx/qa/unit/styles.cxx156
-rw-r--r--svx/qa/unit/svdraw.cxx554
-rw-r--r--svx/qa/unit/svdraw/test_SdrTextObject.cxx46
-rw-r--r--svx/qa/unit/svx-dialogs-test.cxx58
-rw-r--r--svx/qa/unit/table.cxx142
-rw-r--r--svx/qa/unit/unodraw.cxx249
-rw-r--r--svx/qa/unit/xml.cxx68
-rw-r--r--svx/qa/unit/xoutdev.cxx156
-rw-r--r--svx/qa/unoapi/knownissues.xcl108
-rw-r--r--svx/qa/unoapi/svx.sce49
-rw-r--r--svx/qa/unoapi/testdocuments/SvxShape.sxdbin0 -> 6344 bytes
-rw-r--r--svx/qa/unoapi/testdocuments/crazy-blue.jpgbin0 -> 4451 bytes
-rw-r--r--svx/qa/unoapi/testdocuments/space-metal.jpgbin0 -> 4313 bytes
-rw-r--r--svx/sdi/fmslots.sdi747
-rw-r--r--svx/sdi/svx.sdi12649
-rw-r--r--svx/sdi/svxitems.sdi461
-rw-r--r--svx/sdi/svxslots.hrc25
-rw-r--r--svx/sdi/svxslots.sdi33
-rw-r--r--svx/sdi/xoitems.sdi171
-rw-r--r--svx/source/accessibility/AccessibleControlShape.cxx879
-rw-r--r--svx/source/accessibility/AccessibleEmptyEditSource.cxx329
-rw-r--r--svx/source/accessibility/AccessibleEmptyEditSource.hxx93
-rw-r--r--svx/source/accessibility/AccessibleFrameSelector.cxx380
-rw-r--r--svx/source/accessibility/AccessibleGraphicShape.cxx144
-rw-r--r--svx/source/accessibility/AccessibleOLEShape.cxx172
-rw-r--r--svx/source/accessibility/AccessibleShape.cxx1314
-rw-r--r--svx/source/accessibility/AccessibleShapeInfo.cxx63
-rw-r--r--svx/source/accessibility/AccessibleShapeTreeInfo.cxx117
-rw-r--r--svx/source/accessibility/AccessibleTextEventQueue.cxx92
-rw-r--r--svx/source/accessibility/AccessibleTextEventQueue.hxx90
-rw-r--r--svx/source/accessibility/AccessibleTextHelper.cxx1779
-rw-r--r--svx/source/accessibility/ChildrenManager.cxx115
-rw-r--r--svx/source/accessibility/ChildrenManagerImpl.cxx1051
-rw-r--r--svx/source/accessibility/ChildrenManagerImpl.hxx494
-rw-r--r--svx/source/accessibility/DescriptionGenerator.cxx187
-rw-r--r--svx/source/accessibility/GraphCtlAccessibleContext.cxx772
-rw-r--r--svx/source/accessibility/ShapeTypeHandler.cxx306
-rw-r--r--svx/source/accessibility/SvxShapeTypes.cxx165
-rw-r--r--svx/source/accessibility/charmapacc.cxx584
-rw-r--r--svx/source/accessibility/lookupcolorname.cxx121
-rw-r--r--svx/source/accessibility/lookupcolorname.hxx57
-rw-r--r--svx/source/accessibility/svxpixelctlaccessiblecontext.cxx468
-rw-r--r--svx/source/accessibility/svxrectctaccessiblecontext.cxx647
-rw-r--r--svx/source/core/extedit.cxx204
-rw-r--r--svx/source/core/graphichelper.cxx485
-rw-r--r--svx/source/customshapes/EnhancedCustomShape2d.cxx3053
-rw-r--r--svx/source/customshapes/EnhancedCustomShape3d.cxx1037
-rw-r--r--svx/source/customshapes/EnhancedCustomShape3d.hxx37
-rw-r--r--svx/source/customshapes/EnhancedCustomShapeEngine.cxx488
-rw-r--r--svx/source/customshapes/EnhancedCustomShapeFontWork.cxx956
-rw-r--r--svx/source/customshapes/EnhancedCustomShapeFontWork.hxx42
-rw-r--r--svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx1164
-rw-r--r--svx/source/customshapes/EnhancedCustomShapeGeometry.cxx8567
-rw-r--r--svx/source/customshapes/EnhancedCustomShapeHandle.cxx91
-rw-r--r--svx/source/customshapes/EnhancedCustomShapeHandle.hxx57
-rw-r--r--svx/source/customshapes/EnhancedCustomShapeTypeNames.cxx548
-rw-r--r--svx/source/diagram/IDiagramHelper.cxx430
-rw-r--r--svx/source/diagram/datamodel.cxx501
-rw-r--r--svx/source/dialog/AccessibilityCheckDialog.cxx59
-rw-r--r--svx/source/dialog/ClassificationCommon.cxx125
-rw-r--r--svx/source/dialog/ClassificationDialog.cxx693
-rw-r--r--svx/source/dialog/ClassificationEditView.cxx82
-rw-r--r--svx/source/dialog/ClassificationEditView.hxx54
-rw-r--r--svx/source/dialog/FileExportedDialog.cxx42
-rw-r--r--svx/source/dialog/GenericCheckDialog.cxx70
-rw-r--r--svx/source/dialog/SafeModeDialog.cxx307
-rw-r--r--svx/source/dialog/SafeModeDialog.hxx67
-rw-r--r--svx/source/dialog/SafeModeUI.cxx79
-rw-r--r--svx/source/dialog/SpellDialogChildWindow.cxx90
-rw-r--r--svx/source/dialog/SvxNumOptionsTabPageHelper.cxx88
-rw-r--r--svx/source/dialog/_bmpmask.cxx1057
-rw-r--r--svx/source/dialog/_contdlg.cxx675
-rw-r--r--svx/source/dialog/charmap.cxx1938
-rw-r--r--svx/source/dialog/compressgraphicdialog.cxx455
-rw-r--r--svx/source/dialog/connctrl.cxx310
-rw-r--r--svx/source/dialog/contimp.hxx132
-rw-r--r--svx/source/dialog/contwnd.cxx271
-rw-r--r--svx/source/dialog/contwnd.hxx70
-rw-r--r--svx/source/dialog/crashreportdlg.cxx111
-rw-r--r--svx/source/dialog/crashreportdlg.hxx39
-rw-r--r--svx/source/dialog/crashreportui.cxx81
-rw-r--r--svx/source/dialog/ctredlin.cxx1000
-rw-r--r--svx/source/dialog/databaseregistrationui.cxx45
-rw-r--r--svx/source/dialog/dialcontrol.cxx479
-rw-r--r--svx/source/dialog/dialmgr.cxx26
-rw-r--r--svx/source/dialog/dlgctl3d.cxx1173
-rw-r--r--svx/source/dialog/dlgctrl.cxx1479
-rw-r--r--svx/source/dialog/dlgunit.hxx55
-rw-r--r--svx/source/dialog/dlgutil.cxx74
-rw-r--r--svx/source/dialog/docrecovery.cxx1104
-rw-r--r--svx/source/dialog/fntctrl.cxx1089
-rw-r--r--svx/source/dialog/fontwork.cxx794
-rw-r--r--svx/source/dialog/framelink.cxx320
-rw-r--r--svx/source/dialog/framelinkarray.cxx1530
-rw-r--r--svx/source/dialog/frmdirlbox.cxx32
-rw-r--r--svx/source/dialog/frmsel.cxx1303
-rw-r--r--svx/source/dialog/graphctl.cxx850
-rw-r--r--svx/source/dialog/grfflt.cxx294
-rw-r--r--svx/source/dialog/hdft.cxx1052
-rw-r--r--svx/source/dialog/hexcolorcontrol.cxx111
-rw-r--r--svx/source/dialog/hyperdlg.cxx81
-rw-r--r--svx/source/dialog/imapdlg.cxx727
-rw-r--r--svx/source/dialog/imapimp.hxx51
-rw-r--r--svx/source/dialog/imapwnd.cxx743
-rw-r--r--svx/source/dialog/imapwnd.hxx141
-rw-r--r--svx/source/dialog/langbox.cxx502
-rw-r--r--svx/source/dialog/linkwarn.cxx61
-rw-r--r--svx/source/dialog/measctrl.cxx159
-rw-r--r--svx/source/dialog/optgrid.cxx281
-rw-r--r--svx/source/dialog/page.hrc104
-rw-r--r--svx/source/dialog/pagectrl.cxx396
-rw-r--r--svx/source/dialog/pagenumberlistbox.cxx52
-rw-r--r--svx/source/dialog/papersizelistbox.cxx74
-rw-r--r--svx/source/dialog/paraprev.cxx214
-rw-r--r--svx/source/dialog/passwd.cxx91
-rw-r--r--svx/source/dialog/relfld.cxx103
-rw-r--r--svx/source/dialog/rlrcitem.cxx148
-rw-r--r--svx/source/dialog/rlrcitem.hxx42
-rw-r--r--svx/source/dialog/rubydialog.cxx878
-rw-r--r--svx/source/dialog/rulritem.cxx732
-rw-r--r--svx/source/dialog/samecontentlistbox.cxx39
-rw-r--r--svx/source/dialog/searchcharmap.cxx441
-rw-r--r--svx/source/dialog/signaturelinehelper.cxx165
-rw-r--r--svx/source/dialog/spacinglistbox.cxx76
-rw-r--r--svx/source/dialog/srchctrl.cxx71
-rw-r--r--svx/source/dialog/srchctrl.hxx39
-rw-r--r--svx/source/dialog/srchdlg.cxx2466
-rw-r--r--svx/source/dialog/strarray.cxx88
-rw-r--r--svx/source/dialog/svxbmpnumvalueset.cxx533
-rw-r--r--svx/source/dialog/svxdlg.cxx29
-rw-r--r--svx/source/dialog/svxgraphicitem.cxx39
-rw-r--r--svx/source/dialog/svxruler.cxx3577
-rw-r--r--svx/source/dialog/swframeexample.cxx714
-rw-r--r--svx/source/dialog/swframeposstrings.cxx38
-rw-r--r--svx/source/dialog/txencbox.cxx267
-rw-r--r--svx/source/dialog/txenctab.cxx49
-rw-r--r--svx/source/dialog/weldeditview.cxx1682
-rw-r--r--svx/source/engine3d/camera3d.cxx180
-rw-r--r--svx/source/engine3d/cube3d.cxx153
-rw-r--r--svx/source/engine3d/deflt3d.cxx52
-rw-r--r--svx/source/engine3d/dragmt3d.cxx732
-rw-r--r--svx/source/engine3d/e3dsceneupdater.cxx109
-rw-r--r--svx/source/engine3d/e3dundo.cxx91
-rw-r--r--svx/source/engine3d/extrud3d.cxx219
-rw-r--r--svx/source/engine3d/float3d.cxx2944
-rw-r--r--svx/source/engine3d/helperhittest3d.cxx277
-rw-r--r--svx/source/engine3d/helperminimaldepth3d.cxx201
-rw-r--r--svx/source/engine3d/helperminimaldepth3d.hxx45
-rw-r--r--svx/source/engine3d/lathe3d.cxx201
-rw-r--r--svx/source/engine3d/obj3d.cxx617
-rw-r--r--svx/source/engine3d/objfac3d.cxx71
-rw-r--r--svx/source/engine3d/polygn3d.cxx239
-rw-r--r--svx/source/engine3d/scene3d.cxx898
-rw-r--r--svx/source/engine3d/sphere3d.cxx148
-rw-r--r--svx/source/engine3d/svx3ditems.cxx277
-rw-r--r--svx/source/engine3d/view3d.cxx1593
-rw-r--r--svx/source/engine3d/view3d1.cxx177
-rw-r--r--svx/source/engine3d/viewpt3d2.cxx153
-rw-r--r--svx/source/fmcomp/dbaexchange.cxx630
-rw-r--r--svx/source/fmcomp/dbaobjectex.cxx140
-rw-r--r--svx/source/fmcomp/fmgridcl.cxx2096
-rw-r--r--svx/source/fmcomp/fmgridif.cxx2808
-rw-r--r--svx/source/fmcomp/gridcell.cxx4615
-rw-r--r--svx/source/fmcomp/gridcols.cxx103
-rw-r--r--svx/source/fmcomp/gridctrl.cxx3396
-rw-r--r--svx/source/fmcomp/xmlexchg.cxx61
-rw-r--r--svx/source/form/ParseContext.cxx198
-rw-r--r--svx/source/form/dataaccessdescriptor.cxx356
-rw-r--r--svx/source/form/databaselocationinput.cxx246
-rw-r--r--svx/source/form/datalistener.cxx91
-rw-r--r--svx/source/form/datanavi.cxx3090
-rw-r--r--svx/source/form/dbcharsethelper.cxx48
-rw-r--r--svx/source/form/delayedevent.cxx48
-rw-r--r--svx/source/form/filtnav.cxx1850
-rw-r--r--svx/source/form/fmPropBrw.cxx581
-rw-r--r--svx/source/form/fmcontrolbordermanager.cxx425
-rw-r--r--svx/source/form/fmcontrollayout.cxx312
-rw-r--r--svx/source/form/fmdmod.cxx92
-rw-r--r--svx/source/form/fmdocumentclassification.cxx197
-rw-r--r--svx/source/form/fmdpage.cxx115
-rw-r--r--svx/source/form/fmexch.cxx347
-rw-r--r--svx/source/form/fmexpl.cxx527
-rw-r--r--svx/source/form/fmmodel.cxx209
-rw-r--r--svx/source/form/fmobj.cxx653
-rw-r--r--svx/source/form/fmobjfac.cxx231
-rw-r--r--svx/source/form/fmpage.cxx172
-rw-r--r--svx/source/form/fmpgeimp.cxx713
-rw-r--r--svx/source/form/fmscriptingenv.cxx928
-rw-r--r--svx/source/form/fmservs.cxx74
-rw-r--r--svx/source/form/fmshell.cxx1417
-rw-r--r--svx/source/form/fmshimp.cxx3960
-rw-r--r--svx/source/form/fmsrccfg.cxx286
-rw-r--r--svx/source/form/fmsrcimp.cxx1058
-rw-r--r--svx/source/form/fmtextcontroldialogs.cxx78
-rw-r--r--svx/source/form/fmtextcontrolfeature.cxx118
-rw-r--r--svx/source/form/fmtextcontrolshell.cxx1315
-rw-r--r--svx/source/form/fmtools.cxx371
-rw-r--r--svx/source/form/fmundo.cxx1263
-rw-r--r--svx/source/form/fmview.cxx599
-rw-r--r--svx/source/form/fmvwimp.cxx1918
-rw-r--r--svx/source/form/formcontrolfactory.cxx702
-rw-r--r--svx/source/form/formcontroller.cxx4168
-rw-r--r--svx/source/form/formcontrolling.cxx497
-rw-r--r--svx/source/form/formdispatchinterceptor.cxx176
-rw-r--r--svx/source/form/formfeaturedispatcher.cxx194
-rw-r--r--svx/source/form/formtoolbars.cxx93
-rw-r--r--svx/source/form/labelitemwindow.cxx45
-rw-r--r--svx/source/form/legacyformcontroller.cxx201
-rw-r--r--svx/source/form/navigatortree.cxx2044
-rw-r--r--svx/source/form/navigatortreemodel.cxx907
-rw-r--r--svx/source/form/sdbdatacolumn.cxx55
-rw-r--r--svx/source/form/sqlparserclient.cxx50
-rw-r--r--svx/source/form/tabwin.cxx304
-rw-r--r--svx/source/form/tbxform.cxx208
-rw-r--r--svx/source/form/typemap.cxx52
-rw-r--r--svx/source/form/xfm_addcondition.cxx157
-rw-r--r--svx/source/gallery2/GalleryControl.cxx47
-rw-r--r--svx/source/gallery2/codec.cxx148
-rw-r--r--svx/source/gallery2/codec.hxx40
-rw-r--r--svx/source/gallery2/galbrws1.cxx485
-rw-r--r--svx/source/gallery2/galbrws1.hxx91
-rw-r--r--svx/source/gallery2/galbrws2.cxx1242
-rw-r--r--svx/source/gallery2/galctrl.cxx408
-rw-r--r--svx/source/gallery2/galexpl.cxx299
-rw-r--r--svx/source/gallery2/galini.cxx95
-rw-r--r--svx/source/gallery2/gallery1.cxx724
-rw-r--r--svx/source/gallery2/gallerybinaryengine.cxx810
-rw-r--r--svx/source/gallery2/gallerybinaryengineentry.cxx180
-rw-r--r--svx/source/gallery2/gallerybinarystoragelocations.cxx75
-rw-r--r--svx/source/gallery2/gallerydrawmodel.hxx39
-rw-r--r--svx/source/gallery2/galleryfilestorage.cxx24
-rw-r--r--svx/source/gallery2/galleryfilestorageentry.cxx24
-rw-r--r--svx/source/gallery2/galleryobjectbinarystorage.cxx25
-rw-r--r--svx/source/gallery2/galleryobjectcollection.cxx60
-rw-r--r--svx/source/gallery2/galleryobjectstorage.cxx24
-rw-r--r--svx/source/gallery2/galleryobjectxmlstorage.cxx25
-rw-r--r--svx/source/gallery2/gallerystoragelocations.cxx24
-rw-r--r--svx/source/gallery2/galmisc.cxx563
-rw-r--r--svx/source/gallery2/galobj.cxx493
-rw-r--r--svx/source/gallery2/galtheme.cxx780
-rw-r--r--svx/source/gengal/gengal.cxx326
-rwxr-xr-xsvx/source/gengal/gengal.sh95
-rw-r--r--svx/source/inc/AccessibleFrameSelector.hxx137
-rw-r--r--svx/source/inc/DefaultShapesPanel.hxx82
-rw-r--r--svx/source/inc/GraphCtlAccessibleContext.hxx190
-rw-r--r--svx/source/inc/ShapesUtil.hxx39
-rw-r--r--svx/source/inc/StylesPreviewToolBoxControl.hxx70
-rw-r--r--svx/source/inc/StylesPreviewWindow.hxx146
-rw-r--r--svx/source/inc/cell.hxx220
-rw-r--r--svx/source/inc/celltypes.hxx95
-rw-r--r--svx/source/inc/charmapacc.hxx222
-rw-r--r--svx/source/inc/clonelist.hxx47
-rw-r--r--svx/source/inc/datalistener.hxx72
-rw-r--r--svx/source/inc/datanavi.hxx580
-rw-r--r--svx/source/inc/delayedevent.hxx81
-rw-r--r--svx/source/inc/docrecovery.hxx503
-rw-r--r--svx/source/inc/filtnav.hxx339
-rw-r--r--svx/source/inc/findtextfield.hxx70
-rw-r--r--svx/source/inc/fmPropBrw.hxx104
-rw-r--r--svx/source/inc/fmcontrolbordermanager.hxx230
-rw-r--r--svx/source/inc/fmcontrollayout.hxx62
-rw-r--r--svx/source/inc/fmdocumentclassification.hxx71
-rw-r--r--svx/source/inc/fmexch.hxx243
-rw-r--r--svx/source/inc/fmexpl.hxx551
-rw-r--r--svx/source/inc/fmobj.hxx116
-rw-r--r--svx/source/inc/fmpgeimp.hxx144
-rw-r--r--svx/source/inc/fmprop.hxx153
-rw-r--r--svx/source/inc/fmscriptingenv.hxx97
-rw-r--r--svx/source/inc/fmservs.hxx110
-rw-r--r--svx/source/inc/fmshimp.hxx562
-rw-r--r--svx/source/inc/fmslotinvalidator.hxx32
-rw-r--r--svx/source/inc/fmtextcontroldialogs.hxx50
-rw-r--r--svx/source/inc/fmtextcontrolfeature.hxx92
-rw-r--r--svx/source/inc/fmtextcontrolshell.hxx201
-rw-r--r--svx/source/inc/fmundo.hxx199
-rw-r--r--svx/source/inc/fmurl.hxx55
-rw-r--r--svx/source/inc/fmvwimp.hxx302
-rw-r--r--svx/source/inc/formcontrolfactory.hxx107
-rw-r--r--svx/source/inc/formcontroller.hxx570
-rw-r--r--svx/source/inc/formcontrolling.hxx213
-rw-r--r--svx/source/inc/formdispatchinterceptor.hxx107
-rw-r--r--svx/source/inc/formfeaturedispatcher.hxx111
-rw-r--r--svx/source/inc/formtoolbars.hxx62
-rw-r--r--svx/source/inc/frmselimpl.hxx285
-rw-r--r--svx/source/inc/gridcell.hxx1067
-rw-r--r--svx/source/inc/gridcols.hxx54
-rw-r--r--svx/source/inc/sdbdatacolumn.hxx59
-rw-r--r--svx/source/inc/sqlparserclient.hxx70
-rw-r--r--svx/source/inc/svdobjplusdata.hxx46
-rw-r--r--svx/source/inc/svdobjuserdatalist.hxx37
-rw-r--r--svx/source/inc/svdoutlinercache.hxx51
-rw-r--r--svx/source/inc/svdpdf.hxx142
-rw-r--r--svx/source/inc/svxpixelctlaccessiblecontext.hxx154
-rw-r--r--svx/source/inc/svxrectctaccessiblecontext.hxx235
-rw-r--r--svx/source/inc/tablemodel.hxx209
-rw-r--r--svx/source/inc/tabwin.hxx92
-rw-r--r--svx/source/inc/tbxform.hxx105
-rw-r--r--svx/source/inc/treevisitor.hxx104
-rw-r--r--svx/source/inc/xfm_addcondition.hxx76
-rw-r--r--svx/source/inc/xmlxtexp.hxx63
-rw-r--r--svx/source/inc/xmlxtimp.hxx55
-rw-r--r--svx/source/items/SmartTagItem.cxx96
-rw-r--r--svx/source/items/algitem.cxx315
-rw-r--r--svx/source/items/autoformathelper.cxx393
-rw-r--r--svx/source/items/chrtitem.cxx178
-rw-r--r--svx/source/items/clipfmtitem.cxx151
-rw-r--r--svx/source/items/customshapeitem.cxx347
-rw-r--r--svx/source/items/drawitem.cxx349
-rw-r--r--svx/source/items/e3ditem.cxx100
-rw-r--r--svx/source/items/galleryitem.cxx140
-rw-r--r--svx/source/items/grfitem.cxx121
-rw-r--r--svx/source/items/hlnkitem.cxx184
-rw-r--r--svx/source/items/legacyitem.cxx105
-rw-r--r--svx/source/items/numfmtsh.cxx1593
-rw-r--r--svx/source/items/numinf.cxx131
-rw-r--r--svx/source/items/ofaitem.cxx56
-rw-r--r--svx/source/items/pageitem.cxx289
-rw-r--r--svx/source/items/postattr.cxx154
-rw-r--r--svx/source/items/rotmodit.cxx123
-rw-r--r--svx/source/items/svxerr.cxx36
-rw-r--r--svx/source/items/viewlayoutitem.cxx170
-rw-r--r--svx/source/items/zoomslideritem.cxx219
-rw-r--r--svx/source/mnuctrls/clipboardctl.cxx119
-rw-r--r--svx/source/mnuctrls/smarttagmenu.cxx248
-rw-r--r--svx/source/sdr/animation/animationstate.cxx130
-rw-r--r--svx/source/sdr/animation/objectanimator.cxx35
-rw-r--r--svx/source/sdr/animation/scheduler.cxx173
-rw-r--r--svx/source/sdr/attribute/sdrallfillattributeshelper.cxx244
-rw-r--r--svx/source/sdr/attribute/sdreffectstextattribute.cxx76
-rw-r--r--svx/source/sdr/attribute/sdrfilltextattribute.cxx65
-rw-r--r--svx/source/sdr/attribute/sdrformtextattribute.cxx372
-rw-r--r--svx/source/sdr/attribute/sdrformtextoutlineattribute.cxx141
-rw-r--r--svx/source/sdr/attribute/sdrlineeffectstextattribute.cxx75
-rw-r--r--svx/source/sdr/attribute/sdrlinefilleffectstextattribute.cxx77
-rw-r--r--svx/source/sdr/attribute/sdrtextattribute.cxx422
-rw-r--r--svx/source/sdr/contact/displayinfo.cxx87
-rw-r--r--svx/source/sdr/contact/objectcontact.cxx217
-rw-r--r--svx/source/sdr/contact/objectcontactofobjlistpainter.cxx198
-rw-r--r--svx/source/sdr/contact/objectcontactofpageview.cxx451
-rw-r--r--svx/source/sdr/contact/sdrmediawindow.cxx174
-rw-r--r--svx/source/sdr/contact/sdrmediawindow.hxx60
-rw-r--r--svx/source/sdr/contact/viewcontact.cxx295
-rw-r--r--svx/source/sdr/contact/viewcontactofe3d.cxx195
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dcube.cxx88
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dextrude.cxx83
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dlathe.cxx96
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dpolygon.cxx169
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dscene.cxx446
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dsphere.cxx80
-rw-r--r--svx/source/sdr/contact/viewcontactofgraphic.cxx391
-rw-r--r--svx/source/sdr/contact/viewcontactofgroup.cxx78
-rw-r--r--svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx103
-rw-r--r--svx/source/sdr/contact/viewcontactofpageobj.cxx79
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx190
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrcircobj.cxx102
-rw-r--r--svx/source/sdr/contact/viewcontactofsdredgeobj.cxx66
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrmeasureobj.cxx127
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx129
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrobj.cxx179
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx238
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrole2obj.cxx179
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrpage.cxx598
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrpathobj.cxx210
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrrectobj.cxx88
-rw-r--r--svx/source/sdr/contact/viewcontactoftextobj.cxx33
-rw-r--r--svx/source/sdr/contact/viewcontactofunocontrol.cxx133
-rw-r--r--svx/source/sdr/contact/viewcontactofvirtobj.cxx100
-rw-r--r--svx/source/sdr/contact/viewobjectcontact.cxx570
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofe3d.cxx72
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofe3dscene.cxx137
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofgraphic.cxx57
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofgroup.cxx87
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx132
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofpageobj.cxx315
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofsdrmediaobj.cxx175
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx193
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofsdrole2obj.cxx147
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofsdrpage.cxx579
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx1777
-rw-r--r--svx/source/sdr/contact/viewobjectcontactredirector.cxx39
-rw-r--r--svx/source/sdr/misc/ImageMapInfo.cxx121
-rw-r--r--svx/source/sdr/overlay/overlayanimatedbitmapex.cxx113
-rw-r--r--svx/source/sdr/overlay/overlaybitmapex.cxx72
-rw-r--r--svx/source/sdr/overlay/overlaycrosshair.cxx67
-rw-r--r--svx/source/sdr/overlay/overlayhandle.cxx55
-rw-r--r--svx/source/sdr/overlay/overlayhelpline.cxx74
-rw-r--r--svx/source/sdr/overlay/overlayline.cxx74
-rw-r--r--svx/source/sdr/overlay/overlaymanager.cxx346
-rw-r--r--svx/source/sdr/overlay/overlaymanagerbuffered.cxx441
-rw-r--r--svx/source/sdr/overlay/overlayobject.cxx228
-rw-r--r--svx/source/sdr/overlay/overlayobjectcell.cxx81
-rw-r--r--svx/source/sdr/overlay/overlayobjectlist.cxx144
-rw-r--r--svx/source/sdr/overlay/overlaypolypolygon.cxx128
-rw-r--r--svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx42
-rw-r--r--svx/source/sdr/overlay/overlayrectangle.cxx113
-rw-r--r--svx/source/sdr/overlay/overlayrollingrectangle.cxx117
-rw-r--r--svx/source/sdr/overlay/overlayselection.cxx218
-rw-r--r--svx/source/sdr/overlay/overlaytools.cxx601
-rw-r--r--svx/source/sdr/overlay/overlaytriangle.cxx61
-rw-r--r--svx/source/sdr/primitive2d/primitivefactory2d.cxx98
-rw-r--r--svx/source/sdr/primitive2d/sdrattributecreator.cxx1151
-rw-r--r--svx/source/sdr/primitive2d/sdrcaptionprimitive2d.cxx159
-rw-r--r--svx/source/sdr/primitive2d/sdrconnectorprimitive2d.cxx107
-rw-r--r--svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx130
-rw-r--r--svx/source/sdr/primitive2d/sdrdecompositiontools.cxx884
-rw-r--r--svx/source/sdr/primitive2d/sdrellipseprimitive2d.cxx266
-rw-r--r--svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx928
-rw-r--r--svx/source/sdr/primitive2d/sdrgrafprimitive2d.cxx167
-rw-r--r--svx/source/sdr/primitive2d/sdrmeasureprimitive2d.cxx498
-rw-r--r--svx/source/sdr/primitive2d/sdrole2primitive2d.cxx176
-rw-r--r--svx/source/sdr/primitive2d/sdrolecontentprimitive2d.cxx179
-rw-r--r--svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx156
-rw-r--r--svx/source/sdr/primitive2d/sdrprimitivetools.cxx64
-rw-r--r--svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx152
-rw-r--r--svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx545
-rw-r--r--svx/source/sdr/primitive3d/sdrattributecreator3d.cxx145
-rw-r--r--svx/source/sdr/properties/attributeproperties.cxx541
-rw-r--r--svx/source/sdr/properties/captionproperties.cxx101
-rw-r--r--svx/source/sdr/properties/circleproperties.cxx125
-rw-r--r--svx/source/sdr/properties/connectorproperties.cxx89
-rw-r--r--svx/source/sdr/properties/customshapeproperties.cxx230
-rw-r--r--svx/source/sdr/properties/defaultproperties.cxx251
-rw-r--r--svx/source/sdr/properties/e3dcompoundproperties.cxx144
-rw-r--r--svx/source/sdr/properties/e3dextrudeproperties.cxx74
-rw-r--r--svx/source/sdr/properties/e3dlatheproperties.cxx84
-rw-r--r--svx/source/sdr/properties/e3dproperties.cxx75
-rw-r--r--svx/source/sdr/properties/e3dsceneproperties.cxx296
-rw-r--r--svx/source/sdr/properties/e3dsphereproperties.cxx69
-rw-r--r--svx/source/sdr/properties/emptyproperties.cxx89
-rw-r--r--svx/source/sdr/properties/graphicproperties.cxx150
-rw-r--r--svx/source/sdr/properties/groupproperties.cxx240
-rw-r--r--svx/source/sdr/properties/itemsettools.cxx87
-rw-r--r--svx/source/sdr/properties/measureproperties.cxx130
-rw-r--r--svx/source/sdr/properties/oleproperties.cxx73
-rw-r--r--svx/source/sdr/properties/pageproperties.cxx106
-rw-r--r--svx/source/sdr/properties/properties.cxx178
-rw-r--r--svx/source/sdr/properties/rectangleproperties.cxx69
-rw-r--r--svx/source/sdr/properties/textproperties.cxx631
-rw-r--r--svx/source/sidebar/ContextChangeEventMultiplexer.cxx90
-rw-r--r--svx/source/sidebar/EmptyPanel.cxx34
-rw-r--r--svx/source/sidebar/EmptyPanel.hxx43
-rw-r--r--svx/source/sidebar/PanelFactory.cxx220
-rw-r--r--svx/source/sidebar/SelectionAnalyzer.cxx479
-rw-r--r--svx/source/sidebar/SelectionChangeHandler.cxx100
-rw-r--r--svx/source/sidebar/area/AreaPropertyPanel.cxx158
-rw-r--r--svx/source/sidebar/area/AreaPropertyPanel.hxx94
-rw-r--r--svx/source/sidebar/area/AreaPropertyPanelBase.cxx1371
-rw-r--r--svx/source/sidebar/area/AreaTransparencyGradientPopup.cxx179
-rw-r--r--svx/source/sidebar/effect/EffectPropertyPanel.cxx178
-rw-r--r--svx/source/sidebar/effect/EffectPropertyPanel.hxx63
-rw-r--r--svx/source/sidebar/fontwork/FontworkPropertyPanel.cxx59
-rw-r--r--svx/source/sidebar/fontwork/FontworkPropertyPanel.hxx48
-rw-r--r--svx/source/sidebar/graphic/GraphicPropertyPanel.cxx246
-rw-r--r--svx/source/sidebar/graphic/GraphicPropertyPanel.hxx89
-rw-r--r--svx/source/sidebar/inspector/InspectorTextPanel.cxx173
-rw-r--r--svx/source/sidebar/line/LinePropertyPanel.cxx165
-rw-r--r--svx/source/sidebar/line/LinePropertyPanel.hxx96
-rw-r--r--svx/source/sidebar/line/LinePropertyPanelBase.cxx470
-rw-r--r--svx/source/sidebar/line/LineWidthPopup.cxx223
-rw-r--r--svx/source/sidebar/line/LineWidthValueSet.cxx172
-rw-r--r--svx/source/sidebar/line/LineWidthValueSet.hxx55
-rw-r--r--svx/source/sidebar/lists/ListsPropertyPanel.cxx61
-rw-r--r--svx/source/sidebar/lists/ListsPropertyPanel.hxx50
-rw-r--r--svx/source/sidebar/media/MediaPlaybackPanel.cxx175
-rw-r--r--svx/source/sidebar/media/MediaPlaybackPanel.hxx80
-rw-r--r--svx/source/sidebar/nbdtmg.cxx905
-rw-r--r--svx/source/sidebar/nbdtmgfact.cxx42
-rw-r--r--svx/source/sidebar/paragraph/ParaLineSpacingControl.cxx439
-rw-r--r--svx/source/sidebar/paragraph/ParaLineSpacingControl.hxx80
-rw-r--r--svx/source/sidebar/paragraph/ParaLineSpacingPopup.cxx99
-rw-r--r--svx/source/sidebar/paragraph/ParaPropertyPanel.cxx491
-rw-r--r--svx/source/sidebar/paragraph/ParaPropertyPanel.hxx135
-rw-r--r--svx/source/sidebar/paragraph/ParaSpacingControl.cxx257
-rw-r--r--svx/source/sidebar/paragraph/ParaSpacingWindow.cxx341
-rw-r--r--svx/source/sidebar/paragraph/ParaSpacingWindow.hxx110
-rw-r--r--svx/source/sidebar/possize/PosSizePropertyPanel.cxx1079
-rw-r--r--svx/source/sidebar/possize/PosSizePropertyPanel.hxx193
-rw-r--r--svx/source/sidebar/shadow/ShadowPropertyPanel.cxx362
-rw-r--r--svx/source/sidebar/shadow/ShadowPropertyPanel.hxx89
-rw-r--r--svx/source/sidebar/shapes/DefaultShapesPanel.cxx155
-rw-r--r--svx/source/sidebar/shapes/ShapesUtil.cxx212
-rw-r--r--svx/source/sidebar/styles/StylesPropertyPanel.cxx50
-rw-r--r--svx/source/sidebar/styles/StylesPropertyPanel.hxx38
-rw-r--r--svx/source/sidebar/text/TextCharacterSpacingControl.cxx224
-rw-r--r--svx/source/sidebar/text/TextCharacterSpacingControl.hxx69
-rw-r--r--svx/source/sidebar/text/TextCharacterSpacingPopup.cxx82
-rw-r--r--svx/source/sidebar/text/TextPropertyPanel.cxx155
-rw-r--r--svx/source/sidebar/text/TextPropertyPanel.hxx78
-rw-r--r--svx/source/sidebar/text/TextUnderlineControl.cxx141
-rw-r--r--svx/source/sidebar/text/TextUnderlineControl.hxx60
-rw-r--r--svx/source/sidebar/text/TextUnderlinePopup.cxx82
-rw-r--r--svx/source/sidebar/textcolumns/TextColumnsPropertyPanel.cxx118
-rw-r--r--svx/source/sidebar/textcolumns/TextColumnsPropertyPanel.hxx48
-rw-r--r--svx/source/sidebar/tools/ValueSetWithTextControl.cxx121
-rw-r--r--svx/source/smarttags/SmartTagMgr.cxx527
-rw-r--r--svx/source/stbctrls/insctrl.cxx83
-rw-r--r--svx/source/stbctrls/modctrl.cxx159
-rw-r--r--svx/source/stbctrls/modctrl_internal.hxx30
-rw-r--r--svx/source/stbctrls/pszctrl.cxx486
-rw-r--r--svx/source/stbctrls/selctrl.cxx195
-rw-r--r--svx/source/stbctrls/stbctrls.h35
-rw-r--r--svx/source/stbctrls/xmlsecctrl.cxx162
-rw-r--r--svx/source/stbctrls/zoomctrl.cxx229
-rw-r--r--svx/source/stbctrls/zoomsliderctrl.cxx392
-rw-r--r--svx/source/styles/ColorSets.cxx375
-rw-r--r--svx/source/styles/CommonStyleManager.cxx26
-rw-r--r--svx/source/styles/CommonStylePreviewRenderer.cxx233
-rw-r--r--svx/source/svdraw/ActionDescriptionProvider.cxx66
-rw-r--r--svx/source/svdraw/MediaShellHelpers.cxx108
-rw-r--r--svx/source/svdraw/charthelper.cxx135
-rw-r--r--svx/source/svdraw/clonelist.cxx127
-rw-r--r--svx/source/svdraw/gradtrns.cxx527
-rw-r--r--svx/source/svdraw/gradtrns.hxx55
-rw-r--r--svx/source/svdraw/polypolygoneditor.cxx182
-rw-r--r--svx/source/svdraw/presetooxhandleadjustmentrelations.cxx343
-rw-r--r--svx/source/svdraw/presetooxhandleadjustmentrelations.hxx34
-rw-r--r--svx/source/svdraw/sdrhittesthelper.cxx176
-rw-r--r--svx/source/svdraw/sdrmasterpagedescriptor.cxx104
-rw-r--r--svx/source/svdraw/sdrpagewindow.cxx531
-rw-r--r--svx/source/svdraw/sdrpaintwindow.cxx346
-rw-r--r--svx/source/svdraw/sdrundomanager.cxx184
-rw-r--r--svx/source/svdraw/selectioncontroller.cxx124
-rw-r--r--svx/source/svdraw/svdattr.cxx2042
-rw-r--r--svx/source/svdraw/svdcrtv.cxx916
-rw-r--r--svx/source/svdraw/svddrag.cxx129
-rw-r--r--svx/source/svdraw/svddrgm1.hxx232
-rw-r--r--svx/source/svdraw/svddrgmt.cxx3860
-rw-r--r--svx/source/svdraw/svddrgv.cxx919
-rw-r--r--svx/source/svdraw/svdedtv.cxx1103
-rw-r--r--svx/source/svdraw/svdedtv1.cxx2019
-rw-r--r--svx/source/svdraw/svdedtv2.cxx2250
-rw-r--r--svx/source/svdraw/svdedxv.cxx2871
-rw-r--r--svx/source/svdraw/svdetc.cxx726
-rw-r--r--svx/source/svdraw/svdfmtf.cxx1641
-rw-r--r--svx/source/svdraw/svdfmtf.hxx173
-rw-r--r--svx/source/svdraw/svdglev.cxx400
-rw-r--r--svx/source/svdraw/svdglue.cxx394
-rw-r--r--svx/source/svdraw/svdhdl.cxx2675
-rw-r--r--svx/source/svdraw/svdhlpln.cxx109
-rw-r--r--svx/source/svdraw/svditer.cxx140
-rw-r--r--svx/source/svdraw/svdlayer.cxx361
-rw-r--r--svx/source/svdraw/svdmark.cxx791
-rw-r--r--svx/source/svdraw/svdmodel.cxx1941
-rw-r--r--svx/source/svdraw/svdmrkv.cxx2733
-rw-r--r--svx/source/svdraw/svdmrkv1.cxx547
-rw-r--r--svx/source/svdraw/svdoashp.cxx3245
-rw-r--r--svx/source/svdraw/svdoattr.cxx103
-rw-r--r--svx/source/svdraw/svdobj.cxx3375
-rw-r--r--svx/source/svdraw/svdobjplusdata.cxx62
-rw-r--r--svx/source/svdraw/svdobjuserdatalist.cxx36
-rw-r--r--svx/source/svdraw/svdocapt.cxx756
-rw-r--r--svx/source/svdraw/svdocirc.cxx1154
-rw-r--r--svx/source/svdraw/svdoedge.cxx2647
-rw-r--r--svx/source/svdraw/svdograf.cxx1274
-rw-r--r--svx/source/svdraw/svdogrp.cxx835
-rw-r--r--svx/source/svdraw/svdomeas.cxx1429
-rw-r--r--svx/source/svdraw/svdomedia.cxx457
-rw-r--r--svx/source/svdraw/svdoole2.cxx1990
-rw-r--r--svx/source/svdraw/svdopage.cxx175
-rw-r--r--svx/source/svdraw/svdopath.cxx2994
-rw-r--r--svx/source/svdraw/svdorect.cxx567
-rw-r--r--svx/source/svdraw/svdotext.cxx2174
-rw-r--r--svx/source/svdraw/svdotextdecomposition.cxx1698
-rw-r--r--svx/source/svdraw/svdotextpathdecomposition.cxx748
-rw-r--r--svx/source/svdraw/svdotxat.cxx457
-rw-r--r--svx/source/svdraw/svdotxdr.cxx248
-rw-r--r--svx/source/svdraw/svdotxed.cxx360
-rw-r--r--svx/source/svdraw/svdotxfl.cxx28
-rw-r--r--svx/source/svdraw/svdotxln.cxx277
-rw-r--r--svx/source/svdraw/svdotxtr.cxx496
-rw-r--r--svx/source/svdraw/svdouno.cxx502
-rw-r--r--svx/source/svdraw/svdoutl.cxx107
-rw-r--r--svx/source/svdraw/svdoutlinercache.cxx95
-rw-r--r--svx/source/svdraw/svdovirt.cxx567
-rw-r--r--svx/source/svdraw/svdpage.cxx1895
-rw-r--r--svx/source/svdraw/svdpagv.cxx894
-rw-r--r--svx/source/svdraw/svdpdf.cxx1052
-rw-r--r--svx/source/svdraw/svdpntv.cxx1206
-rw-r--r--svx/source/svdraw/svdpoev.cxx652
-rw-r--r--svx/source/svdraw/svdsnpv.cxx633
-rw-r--r--svx/source/svdraw/svdtext.cxx154
-rw-r--r--svx/source/svdraw/svdtrans.cxx867
-rw-r--r--svx/source/svdraw/svdundo.cxx1834
-rw-r--r--svx/source/svdraw/svdview.cxx1544
-rw-r--r--svx/source/svdraw/svdviter.cxx164
-rw-r--r--svx/source/svdraw/svdxcgv.cxx784
-rw-r--r--svx/source/svdraw/textchain.cxx128
-rw-r--r--svx/source/svdraw/textchaincursor.cxx203
-rw-r--r--svx/source/svdraw/textchainflow.cxx314
-rw-r--r--svx/source/table/accessiblecell.cxx600
-rw-r--r--svx/source/table/accessiblecell.hxx132
-rw-r--r--svx/source/table/accessibletableshape.cxx1324
-rw-r--r--svx/source/table/cell.cxx1712
-rw-r--r--svx/source/table/cellcursor.cxx546
-rw-r--r--svx/source/table/cellcursor.hxx71
-rw-r--r--svx/source/table/cellrange.cxx116
-rw-r--r--svx/source/table/cellrange.hxx61
-rw-r--r--svx/source/table/propertyset.cxx206
-rw-r--r--svx/source/table/propertyset.hxx96
-rw-r--r--svx/source/table/svdotable.cxx2534
-rw-r--r--svx/source/table/tablecolumn.cxx289
-rw-r--r--svx/source/table/tablecolumn.hxx83
-rw-r--r--svx/source/table/tablecolumns.cxx121
-rw-r--r--svx/source/table/tablecolumns.hxx61
-rw-r--r--svx/source/table/tablecontroller.cxx3363
-rw-r--r--svx/source/table/tabledesign.cxx705
-rw-r--r--svx/source/table/tablehandles.cxx313
-rw-r--r--svx/source/table/tablehandles.hxx89
-rw-r--r--svx/source/table/tablelayouter.cxx1311
-rw-r--r--svx/source/table/tablelayouter.hxx172
-rw-r--r--svx/source/table/tablemodel.cxx1127
-rw-r--r--svx/source/table/tablerow.cxx351
-rw-r--r--svx/source/table/tablerow.hxx84
-rw-r--r--svx/source/table/tablerows.cxx114
-rw-r--r--svx/source/table/tablerows.hxx59
-rw-r--r--svx/source/table/tablertfexporter.cxx235
-rw-r--r--svx/source/table/tablertfimporter.cxx503
-rw-r--r--svx/source/table/tableundo.cxx516
-rw-r--r--svx/source/table/tableundo.hxx258
-rw-r--r--svx/source/table/viewcontactoftableobj.cxx547
-rw-r--r--svx/source/table/viewcontactoftableobj.hxx45
-rw-r--r--svx/source/tbxctrls/Palette.cxx377
-rw-r--r--svx/source/tbxctrls/PaletteManager.cxx442
-rw-r--r--svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx189
-rw-r--r--svx/source/tbxctrls/StylesPreviewWindow.cxx520
-rw-r--r--svx/source/tbxctrls/SvxColorChildWindow.cxx43
-rw-r--r--svx/source/tbxctrls/SvxColorValueSet.cxx166
-rw-r--r--svx/source/tbxctrls/SvxPresetListBox.cxx112
-rw-r--r--svx/source/tbxctrls/bulletsnumbering.cxx242
-rw-r--r--svx/source/tbxctrls/colrctrl.cxx423
-rw-r--r--svx/source/tbxctrls/extrusioncontrols.cxx968
-rw-r--r--svx/source/tbxctrls/extrusioncontrols.hxx224
-rw-r--r--svx/source/tbxctrls/fillctrl.cxx1087
-rw-r--r--svx/source/tbxctrls/fontworkgallery.cxx799
-rw-r--r--svx/source/tbxctrls/formatpaintbrushctrl.cxx105
-rw-r--r--svx/source/tbxctrls/grafctrl.cxx961
-rw-r--r--svx/source/tbxctrls/itemwin.cxx347
-rw-r--r--svx/source/tbxctrls/layctrl.cxx798
-rw-r--r--svx/source/tbxctrls/lboxctrl.cxx347
-rw-r--r--svx/source/tbxctrls/linectrl.cxx650
-rw-r--r--svx/source/tbxctrls/linemetricbox.hxx56
-rw-r--r--svx/source/tbxctrls/linewidthctrl.cxx101
-rw-r--r--svx/source/tbxctrls/tbcontrl.cxx4186
-rw-r--r--svx/source/tbxctrls/tbunocontroller.cxx538
-rw-r--r--svx/source/tbxctrls/tbunosearchcontrollers.cxx1662
-rw-r--r--svx/source/tbxctrls/tbxcolor.cxx95
-rw-r--r--svx/source/tbxctrls/tbxcolorupdate.cxx355
-rw-r--r--svx/source/tbxctrls/tbxdrctl.cxx99
-rw-r--r--svx/source/tbxctrls/verttexttbxctrl.cxx162
-rw-r--r--svx/source/toolbars/extrusionbar.cxx1338
-rw-r--r--svx/source/toolbars/fontworkbar.cxx566
-rw-r--r--svx/source/uitest/sdrobject.cxx206
-rw-r--r--svx/source/uitest/uiobject.cxx104
-rw-r--r--svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.cxx676
-rw-r--r--svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.hxx168
-rw-r--r--svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog.cxx227
-rw-r--r--svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog.hxx119
-rw-r--r--svx/source/unodialogs/textconversiondlgs/chinese_translationdialog.cxx97
-rw-r--r--svx/source/unodialogs/textconversiondlgs/chinese_translationdialog.hxx51
-rw-r--r--svx/source/unodraw/SvxXTextColumns.cxx338
-rw-r--r--svx/source/unodraw/UnoGraphicExporter.cxx1318
-rw-r--r--svx/source/unodraw/UnoGraphicExporter.hxx33
-rw-r--r--svx/source/unodraw/UnoNameItemTable.cxx282
-rw-r--r--svx/source/unodraw/UnoNameItemTable.hxx94
-rw-r--r--svx/source/unodraw/UnoNamespaceMap.cxx275
-rw-r--r--svx/source/unodraw/XPropertyTable.cxx663
-rw-r--r--svx/source/unodraw/gluepts.cxx513
-rw-r--r--svx/source/unodraw/gluepts.hxx37
-rw-r--r--svx/source/unodraw/recoveryui.cxx331
-rw-r--r--svx/source/unodraw/shapeimpl.hxx96
-rw-r--r--svx/source/unodraw/shapepropertynotifier.cxx143
-rw-r--r--svx/source/unodraw/tableshape.cxx178
-rw-r--r--svx/source/unodraw/unobrushitemhelper.cxx342
-rw-r--r--svx/source/unodraw/unobtabl.cxx102
-rw-r--r--svx/source/unodraw/unoctabl.cxx181
-rw-r--r--svx/source/unodraw/unodtabl.cxx83
-rw-r--r--svx/source/unodraw/unogtabl.cxx79
-rw-r--r--svx/source/unodraw/unohtabl.cxx86
-rw-r--r--svx/source/unodraw/unomlstr.cxx60
-rw-r--r--svx/source/unodraw/unomod.cxx670
-rw-r--r--svx/source/unodraw/unomtabl.cxx423
-rw-r--r--svx/source/unodraw/unopage.cxx898
-rw-r--r--svx/source/unodraw/unopool.cxx375
-rw-r--r--svx/source/unodraw/unoprov.cxx2107
-rw-r--r--svx/source/unodraw/unoshap2.cxx1798
-rw-r--r--svx/source/unodraw/unoshap3.cxx1052
-rw-r--r--svx/source/unodraw/unoshap4.cxx1115
-rw-r--r--svx/source/unodraw/unoshape.cxx4042
-rw-r--r--svx/source/unodraw/unoshcol.cxx252
-rw-r--r--svx/source/unodraw/unoshtxt.cxx1009
-rw-r--r--svx/source/unodraw/unottabl.cxx85
-rw-r--r--svx/source/unogallery/unogalitem.cxx368
-rw-r--r--svx/source/unogallery/unogalitem.hxx104
-rw-r--r--svx/source/unogallery/unogaltheme.cxx362
-rw-r--r--svx/source/unogallery/unogaltheme.hxx100
-rw-r--r--svx/source/unogallery/unogalthemeprovider.cxx247
-rw-r--r--svx/source/xml/xmleohlp.cxx717
-rw-r--r--svx/source/xml/xmlexport.cxx239
-rw-r--r--svx/source/xml/xmlgrhlp.cxx1190
-rw-r--r--svx/source/xml/xmlxtexp.cxx485
-rw-r--r--svx/source/xml/xmlxtimp.cxx461
-rw-r--r--svx/source/xoutdev/XPropertyEntry.cxx29
-rw-r--r--svx/source/xoutdev/_xoutbmp.cxx389
-rw-r--r--svx/source/xoutdev/_xpoly.cxx947
-rw-r--r--svx/source/xoutdev/xattr.cxx3118
-rw-r--r--svx/source/xoutdev/xattr2.cxx731
-rw-r--r--svx/source/xoutdev/xattrbmp.cxx342
-rw-r--r--svx/source/xoutdev/xpool.cxx219
-rw-r--r--svx/source/xoutdev/xtabbtmp.cxx114
-rw-r--r--svx/source/xoutdev/xtabcolr.cxx172
-rw-r--r--svx/source/xoutdev/xtabdash.cxx220
-rw-r--r--svx/source/xoutdev/xtabgrdt.cxx216
-rw-r--r--svx/source/xoutdev/xtabhtch.cxx195
-rw-r--r--svx/source/xoutdev/xtable.cxx392
-rw-r--r--svx/source/xoutdev/xtablend.cxx163
-rw-r--r--svx/source/xoutdev/xtabptrn.cxx149
-rw-r--r--svx/uiconfig/ui/absrecbox.ui43
-rw-r--r--svx/uiconfig/ui/acceptrejectchangesdialog.ui218
-rw-r--r--svx/uiconfig/ui/accessibilitycheckdialog.ui136
-rw-r--r--svx/uiconfig/ui/accessibilitycheckentry.ui42
-rw-r--r--svx/uiconfig/ui/addconditiondialog.ui225
-rw-r--r--svx/uiconfig/ui/adddataitemdialog.ui462
-rw-r--r--svx/uiconfig/ui/addinstancedialog.ui201
-rw-r--r--svx/uiconfig/ui/addmodeldialog.ui165
-rw-r--r--svx/uiconfig/ui/addnamespacedialog.ui169
-rw-r--r--svx/uiconfig/ui/addsubmissiondialog.ui279
-rw-r--r--svx/uiconfig/ui/applystylebox.ui31
-rw-r--r--svx/uiconfig/ui/asianphoneticguidedialog.ui507
-rw-r--r--svx/uiconfig/ui/cellmenu.ui17
-rw-r--r--svx/uiconfig/ui/charsetmenu.ui41
-rw-r--r--svx/uiconfig/ui/checkbuttonbox.ui27
-rw-r--r--svx/uiconfig/ui/chineseconversiondialog.ui257
-rw-r--r--svx/uiconfig/ui/chinesedictionary.ui581
-rw-r--r--svx/uiconfig/ui/classificationdialog.ui630
-rw-r--r--svx/uiconfig/ui/clipboardmenu.ui9
-rw-r--r--svx/uiconfig/ui/colorwindow.ui203
-rw-r--r--svx/uiconfig/ui/colsmenu.ui97
-rw-r--r--svx/uiconfig/ui/columnswindow.ui57
-rw-r--r--svx/uiconfig/ui/compressgraphicdialog.ui731
-rw-r--r--svx/uiconfig/ui/crashreportdlg.ui162
-rw-r--r--svx/uiconfig/ui/currencywindow.ui96
-rw-r--r--svx/uiconfig/ui/datanavigator.ui372
-rw-r--r--svx/uiconfig/ui/defaultshapespanel.ui358
-rw-r--r--svx/uiconfig/ui/deletefooterdialog.ui71
-rw-r--r--svx/uiconfig/ui/deleteheaderdialog.ui71
-rw-r--r--svx/uiconfig/ui/depthwindow.ui168
-rw-r--r--svx/uiconfig/ui/directionwindow.ui96
-rw-r--r--svx/uiconfig/ui/docking3deffects.ui2519
-rw-r--r--svx/uiconfig/ui/dockingcolorreplace.ui572
-rw-r--r--svx/uiconfig/ui/dockingcolorwindow.ui42
-rw-r--r--svx/uiconfig/ui/dockingfontwork.ui593
-rw-r--r--svx/uiconfig/ui/docrecoverybrokendialog.ui225
-rw-r--r--svx/uiconfig/ui/docrecoveryprogressdialog.ui78
-rw-r--r--svx/uiconfig/ui/docrecoveryrecoverdialog.ui212
-rw-r--r--svx/uiconfig/ui/docrecoverysavedialog.ui185
-rw-r--r--svx/uiconfig/ui/extrustiondepthdialog.ui160
-rw-r--r--svx/uiconfig/ui/fileexporteddialog.ui89
-rw-r--r--svx/uiconfig/ui/fillctrlbox.ui112
-rw-r--r--svx/uiconfig/ui/filtermenu.ui41
-rw-r--r--svx/uiconfig/ui/filternavigator.ui74
-rw-r--r--svx/uiconfig/ui/findbox.ui30
-rw-r--r--svx/uiconfig/ui/findreplacedialog-mobile.ui1117
-rw-r--r--svx/uiconfig/ui/findreplacedialog.ui1233
-rw-r--r--svx/uiconfig/ui/floatingareastyle.ui346
-rw-r--r--svx/uiconfig/ui/floatingcontour.ui532
-rw-r--r--svx/uiconfig/ui/floatingframeborder.ui50
-rw-r--r--svx/uiconfig/ui/floatinglineend.ui49
-rw-r--r--svx/uiconfig/ui/floatinglineproperty.ui95
-rw-r--r--svx/uiconfig/ui/floatinglinestyle.ui50
-rw-r--r--svx/uiconfig/ui/floatingundoredo.ui69
-rw-r--r--svx/uiconfig/ui/fontnamebox.ui31
-rw-r--r--svx/uiconfig/ui/fontsizebox.ui30
-rw-r--r--svx/uiconfig/ui/fontworkalignmentcontrol.ui109
-rw-r--r--svx/uiconfig/ui/fontworkcharacterspacingcontrol.ui125
-rw-r--r--svx/uiconfig/ui/fontworkgallerydialog.ui147
-rw-r--r--svx/uiconfig/ui/fontworkspacingdialog.ui121
-rw-r--r--svx/uiconfig/ui/formdatamenu.ui55
-rw-r--r--svx/uiconfig/ui/formfielddialog.ui100
-rw-r--r--svx/uiconfig/ui/formlinkwarndialog.ui69
-rw-r--r--svx/uiconfig/ui/formnavigator.ui78
-rw-r--r--svx/uiconfig/ui/formnavimenu.ui109
-rw-r--r--svx/uiconfig/ui/formpropertydialog.ui77
-rw-r--r--svx/uiconfig/ui/functionmenu.ui73
-rw-r--r--svx/uiconfig/ui/gallerymenu1.ui67
-rw-r--r--svx/uiconfig/ui/gallerymenu2.ui95
-rw-r--r--svx/uiconfig/ui/genericcheckdialog.ui132
-rw-r--r--svx/uiconfig/ui/genericcheckentry.ui56
-rw-r--r--svx/uiconfig/ui/grafctrlbox.ui44
-rw-r--r--svx/uiconfig/ui/grafmodebox.ui23
-rw-r--r--svx/uiconfig/ui/headfootformatpage.ui427
-rw-r--r--svx/uiconfig/ui/imapdialog.ui629
-rw-r--r--svx/uiconfig/ui/imapmenu.ui107
-rw-r--r--svx/uiconfig/ui/inspectortextpanel.ui105
-rw-r--r--svx/uiconfig/ui/labelbox.ui26
-rw-r--r--svx/uiconfig/ui/lightingwindow.ui119
-rw-r--r--svx/uiconfig/ui/linkwarndialog.ui86
-rw-r--r--svx/uiconfig/ui/measurewidthbar.ui108
-rw-r--r--svx/uiconfig/ui/medialine.ui287
-rw-r--r--svx/uiconfig/ui/mediaplayback.ui272
-rw-r--r--svx/uiconfig/ui/mediawindow.ui272
-rw-r--r--svx/uiconfig/ui/metricfieldbox.ui31
-rw-r--r--svx/uiconfig/ui/namespacedialog.ui261
-rw-r--r--svx/uiconfig/ui/navigationbar.ui224
-rw-r--r--svx/uiconfig/ui/numberingwindow.ui70
-rw-r--r--svx/uiconfig/ui/optgridpage.ui756
-rw-r--r--svx/uiconfig/ui/paralinespacingcontrol.ui251
-rw-r--r--svx/uiconfig/ui/paralrspacing.ui168
-rw-r--r--svx/uiconfig/ui/paraulspacing.ui123
-rw-r--r--svx/uiconfig/ui/passwd.ui286
-rw-r--r--svx/uiconfig/ui/presetmenu.ui25
-rw-r--r--svx/uiconfig/ui/querydeletecontourdialog.ui36
-rw-r--r--svx/uiconfig/ui/querydeleteobjectdialog.ui37
-rw-r--r--svx/uiconfig/ui/querydeletethemedialog.ui37
-rw-r--r--svx/uiconfig/ui/querymodifyimagemapchangesdialog.ui54
-rw-r--r--svx/uiconfig/ui/querynewcontourdialog.ui34
-rw-r--r--svx/uiconfig/ui/querysavecontchangesdialog.ui55
-rw-r--r--svx/uiconfig/ui/querysaveimagemapchangesdialog.ui54
-rw-r--r--svx/uiconfig/ui/queryunlinkgraphicsdialog.ui35
-rw-r--r--svx/uiconfig/ui/redlinecontrol.ui57
-rw-r--r--svx/uiconfig/ui/redlinefilterpage.ui448
-rw-r--r--svx/uiconfig/ui/redlineviewpage.ui366
-rw-r--r--svx/uiconfig/ui/rowsmenu.ui33
-rw-r--r--svx/uiconfig/ui/rulermenu.ui97
-rw-r--r--svx/uiconfig/ui/safemodedialog.ui477
-rw-r--r--svx/uiconfig/ui/savemodifieddialog.ui82
-rw-r--r--svx/uiconfig/ui/selectionmenu.ui45
-rw-r--r--svx/uiconfig/ui/sidebararea.ui372
-rw-r--r--svx/uiconfig/ui/sidebareffect.ui240
-rw-r--r--svx/uiconfig/ui/sidebarempty.ui49
-rw-r--r--svx/uiconfig/ui/sidebarfontwork.ui85
-rw-r--r--svx/uiconfig/ui/sidebargallery.ui501
-rw-r--r--svx/uiconfig/ui/sidebargraphic.ui217
-rw-r--r--svx/uiconfig/ui/sidebarline.ui365
-rw-r--r--svx/uiconfig/ui/sidebarlists.ui126
-rw-r--r--svx/uiconfig/ui/sidebarparagraph.ui719
-rw-r--r--svx/uiconfig/ui/sidebarpossize.ui606
-rw-r--r--svx/uiconfig/ui/sidebarshadow.ui263
-rw-r--r--svx/uiconfig/ui/sidebarstylespanel.ui130
-rw-r--r--svx/uiconfig/ui/sidebartextcolumnspanel.ui106
-rw-r--r--svx/uiconfig/ui/sidebartextpanel.ui428
-rw-r--r--svx/uiconfig/ui/stylemenu.ui25
-rw-r--r--svx/uiconfig/ui/stylespreview.ui63
-rw-r--r--svx/uiconfig/ui/surfacewindow.ui134
-rw-r--r--svx/uiconfig/ui/tablewindow.ui59
-rw-r--r--svx/uiconfig/ui/textcharacterspacingcontrol.ui203
-rw-r--r--svx/uiconfig/ui/textcontrolchardialog.ui254
-rw-r--r--svx/uiconfig/ui/textcontrolparadialog.ui303
-rw-r--r--svx/uiconfig/ui/textunderlinecontrol.ui265
-rw-r--r--svx/uiconfig/ui/toolbarpopover.ui20
-rw-r--r--svx/uiconfig/ui/xformspage.ui167
-rw-r--r--svx/uiconfig/ui/xmlsecstatmenu.ui17
-rw-r--r--svx/uiconfig/ui/zoommenu.ui93
-rw-r--r--svx/util/svx.component137
-rw-r--r--svx/util/svx.component.crashreport7
-rw-r--r--svx/util/svx.component.recoveryui7
-rw-r--r--svx/util/svxcore.component100
-rw-r--r--svx/util/svxcore.component.draw7
-rw-r--r--svx/util/textconversiondlgs.component26
1123 files changed, 385908 insertions, 0 deletions
diff --git a/svx/AllLangMoTarget_svx.mk b/svx/AllLangMoTarget_svx.mk
new file mode 100644
index 000000000..b1fa1c861
--- /dev/null
+++ b/svx/AllLangMoTarget_svx.mk
@@ -0,0 +1,11 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+$(eval $(call gb_AllLangMoTarget_AllLangMoTarget,svx))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/CppunitTest_svx_core.mk b/svx/CppunitTest_svx_core.mk
new file mode 100644
index 000000000..67445767c
--- /dev/null
+++ b/svx/CppunitTest_svx_core.mk
@@ -0,0 +1,49 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,svx_core))
+
+$(eval $(call gb_CppunitTest_use_externals,svx_core,\
+ boost_headers \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,svx_core, \
+ svx/qa/unit/core \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,svx_core, \
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ svx \
+ svxcore \
+ test \
+ tl \
+ unotest \
+ utl \
+ vcl \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,svx_core))
+
+$(eval $(call gb_CppunitTest_use_ure,svx_core))
+$(eval $(call gb_CppunitTest_use_vcl,svx_core))
+
+$(eval $(call gb_CppunitTest_use_rdb,svx_core,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,svx_core,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,svx_core))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/CppunitTest_svx_dialogs_test.mk b/svx/CppunitTest_svx_dialogs_test.mk
new file mode 100644
index 000000000..efc2903b2
--- /dev/null
+++ b/svx/CppunitTest_svx_dialogs_test.mk
@@ -0,0 +1,71 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitScreenShot,svx_dialogs_test))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,svx_dialogs_test, \
+ svx/qa/unit/svx-dialogs-test \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,svx_dialogs_test))
+
+$(eval $(call gb_CppunitTest_set_include,svx_dialogs_test,\
+ -I$(SRCDIR)/svx/source/inc \
+ -I$(SRCDIR)/svx/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,svx_dialogs_test, \
+ basegfx \
+ comphelper \
+ cppu \
+ cppuhelper \
+ drawinglayer \
+ editeng \
+ i18nlangtag \
+ i18nutil \
+ msfilter \
+ oox \
+ sal \
+ salhelper \
+ sax \
+ sfx \
+ sot \
+ svl \
+ svt \
+ svx \
+ svxcore \
+ test \
+ tl \
+ tk \
+ ucbhelper \
+ unotest \
+ utl \
+ vcl \
+ xo \
+))
+
+$(eval $(call gb_CppunitTest_use_external,svx_dialogs_test,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,svx_dialogs_test))
+
+$(eval $(call gb_CppunitTest_use_ure,svx_dialogs_test))
+$(eval $(call gb_CppunitTest_use_vcl_non_headless_with_windows,svx_dialogs_test))
+
+$(eval $(call gb_CppunitTest_use_rdb,svx_dialogs_test,services))
+
+$(eval $(call gb_CppunitTest_use_configuration,svx_dialogs_test))
+
+$(eval $(call gb_CppunitTest_use_uiconfigs,svx_dialogs_test,\
+ svx \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/CppunitTest_svx_gallery_test.mk b/svx/CppunitTest_svx_gallery_test.mk
new file mode 100644
index 000000000..1415dce92
--- /dev/null
+++ b/svx/CppunitTest_svx_gallery_test.mk
@@ -0,0 +1,56 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitScreenShot,svx_gallery_test))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,svx_gallery_test, \
+ svx/qa/unit/gallery/test_gallery \
+))
+
+$(eval $(call gb_CppunitTest_set_include,svx_gallery_test,\
+ -I$(SRCDIR)/svx/source/inc \
+ -I$(SRCDIR)/svx/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,svx_gallery_test, \
+ sal \
+ utl \
+ svxcore \
+ comphelper \
+ tl \
+ svl \
+ sfx \
+ unotest \
+ test \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,svx_gallery_test,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_vcl,svx_gallery_test))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,svx_gallery_test))
+
+$(eval $(call gb_CppunitTest_use_configuration,svx_gallery_test))
+
+$(eval $(call gb_CppunitTest_use_rdb,svx_gallery_test,services))
+
+$(eval $(call gb_CppunitTest_use_ure,svx_gallery_test))
+
+
+
+
+
+
+
+
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/CppunitTest_svx_removewhichrange.mk b/svx/CppunitTest_svx_removewhichrange.mk
new file mode 100644
index 000000000..6819c4452
--- /dev/null
+++ b/svx/CppunitTest_svx_removewhichrange.mk
@@ -0,0 +1,62 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,svx_removewhichrange))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,svx_removewhichrange, \
+ svx/qa/unit/removewhichrange \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,svx_removewhichrange, \
+ boost_headers \
+ libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,svx_removewhichrange, \
+ basegfx \
+ comphelper \
+ cppu \
+ cppuhelper \
+ drawinglayer \
+ drawinglayercore \
+ editeng \
+ fwk \
+ i18nlangtag \
+ i18nutil \
+ sal \
+ salhelper \
+ sax \
+ sb \
+ sfx \
+ sot \
+ svl \
+ svt \
+ tk \
+ tl \
+ ucbhelper \
+ utl \
+ vcl \
+ xo \
+ $(call gb_Helper_optional,AVMEDIA,avmedia) \
+ $(call gb_Helper_optional,DBCONNECTIVITY,dbtools) \
+))
+
+$(eval $(call gb_CppunitTest_use_library_objects,svx_removewhichrange, \
+ svxcore \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,svx_removewhichrange))
+
+ifeq ($(OS),MACOSX)
+$(eval $(call gb_CppunitTest_use_system_darwin_frameworks,svx_removewhichrange, \
+ Foundation \
+))
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/CppunitTest_svx_styles.mk b/svx/CppunitTest_svx_styles.mk
new file mode 100644
index 000000000..f617668ad
--- /dev/null
+++ b/svx/CppunitTest_svx_styles.mk
@@ -0,0 +1,44 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,svx_styles))
+
+$(eval $(call gb_CppunitTest_use_externals,svx_styles,\
+ boost_headers \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,svx_styles, \
+ svx/qa/unit/styles \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,svx_styles, \
+ comphelper \
+ cppu \
+ svx \
+ sal \
+ test \
+ unotest \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,svx_styles))
+
+$(eval $(call gb_CppunitTest_use_ure,svx_styles))
+$(eval $(call gb_CppunitTest_use_vcl,svx_styles))
+
+$(eval $(call gb_CppunitTest_use_rdb,svx_styles,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,svx_styles,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,svx_styles))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/CppunitTest_svx_unit.mk b/svx/CppunitTest_svx_unit.mk
new file mode 100644
index 000000000..8bc66bcd4
--- /dev/null
+++ b/svx/CppunitTest_svx_unit.mk
@@ -0,0 +1,65 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,svx_unit))
+
+$(eval $(call gb_CppunitTest_use_externals,svx_unit,\
+ boost_headers \
+ libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,svx_unit))
+
+$(eval $(call gb_CppunitTest_set_include,svx_unit,\
+ -I$(SRCDIR)/svx/source/inc \
+ -I$(SRCDIR)/svx/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,svx_unit, \
+ svx/qa/unit/svdraw/test_SdrTextObject \
+ svx/qa/unit/customshapes \
+ svx/qa/unit/classicshapes \
+ svx/qa/unit/sdr \
+ svx/qa/unit/svdraw \
+ svx/qa/unit/table \
+ svx/qa/unit/unodraw \
+ svx/qa/unit/xoutdev \
+ svx/qa/unit/xml \
+ svx/qa/unit/XTableImportExportTest \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,svx_unit, \
+ basegfx \
+ drawinglayer \
+ drawinglayercore \
+ editeng \
+ sal \
+ sfx \
+ svl \
+ svxcore \
+ svx \
+ tl \
+ unotest \
+ vcl \
+ utl \
+ comphelper \
+ cppuhelper \
+ cppu \
+ test \
+ unotest \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,svx_unit))
+$(eval $(call gb_CppunitTest_use_ure,svx_unit))
+$(eval $(call gb_CppunitTest_use_vcl,svx_unit))
+$(eval $(call gb_CppunitTest_use_rdb,svx_unit,services))
+$(eval $(call gb_CppunitTest_use_configuration,svx_unit))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/Executable_gengal.mk b/svx/Executable_gengal.mk
new file mode 100644
index 000000000..2b16d8f74
--- /dev/null
+++ b/svx/Executable_gengal.mk
@@ -0,0 +1,68 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Executable_Executable,gengal))
+
+$(eval $(call gb_Executable_set_include,gengal,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/svx/inc/ \
+ -I$(SRCDIR)/svx/inc/pch \
+))
+
+$(eval $(call gb_Executable_use_external,gengal,boost_headers))
+
+$(eval $(call gb_Executable_use_sdk_api,gengal))
+
+ifneq (,$(filter-out MACOSX WNT,$(OS)))
+$(eval $(call gb_Executable_use_package,gengal,svx_gengal))
+endif
+
+$(eval $(call gb_Executable_use_libraries,gengal,\
+ basegfx \
+ sal \
+ tl \
+ sfx \
+ svl \
+ svt \
+ comphelper \
+ cppu \
+ cppuhelper \
+ utl \
+ svxcore \
+ vcl \
+))
+
+$(eval $(call gb_Executable_use_vclmain,gengal))
+
+$(eval $(call gb_Executable_add_exception_objects,gengal,\
+ svx/source/gengal/gengal \
+))
+
+ifeq ($(OS),WNT)
+$(eval $(call gb_Executable_use_system_win32_libs,gengal,\
+ kernel32 \
+ msvcrt \
+ oldnames \
+ user32 \
+))
+endif
+
+$(eval $(call gb_Executable_add_default_nativeres,gengal))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/IwyuFilter_svx.yaml b/svx/IwyuFilter_svx.yaml
new file mode 100644
index 000000000..4929d9a2c
--- /dev/null
+++ b/svx/IwyuFilter_svx.yaml
@@ -0,0 +1,157 @@
+---
+assumeFilename: svx/source/svdraw/svdobj.cxx
+excludelist:
+ svx/source/accessibility/ChildrenManagerImpl.cxx:
+ # Actually used
+ - com/sun/star/beans/XPropertySet.hpp
+ svx/source/accessibility/DescriptionGenerator.cxx:
+ # Actually used
+ - com/sun/star/drawing/XShape.hpp
+ svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx:
+ # Boost wrapper is needed
+ - boost/spirit/include/classic_core.hpp
+ svx/source/dialog/ClassificationCommon.cxx:
+ # Actually used
+ - com/sun/star/beans/XPropertyContainer.hpp
+ svx/source/dialog/svxruler.cxx:
+ # Needed for rtl::math::round
+ - rtl/math.hxx
+ svx/source/dialog/srchdlg.cxx:
+ # Actually used
+ - comphelper/scopeguard.hxx
+ svx/source/fmcomp/dbaobjectex.cxx:
+ # Actually used
+ - com/sun/star/ucb/XContent.hpp
+ svx/source/fmcomp/dbaexchange.cxx:
+ # Actually used
+ - com/sun/star/sdbc/XConnection.hpp
+ - com/sun/star/beans/XPropertySet.hpp
+ svx/source/fmcomp/gridcell.cxx:
+ # Needed to avoid mysterious linking error on WIN32 no-pch
+ - toolkit/helper/listenermultiplexer.hxx
+ svx/source/gallery2/gallerybinaryengine.cxx:
+ # Don't propose hxx -> h change in URE libs
+ - osl/thread.hxx
+ svx/source/gallery2/galtheme.cxx:
+ # Don't propose hxx -> h change in URE libs
+ - osl/thread.hxx
+ svx/source/gallery2/galobj.cxx:
+ # Actually used
+ - com/sun/star/frame/XModel.hpp
+ svx/source/items/galleryitem.cxx:
+ # Actually used
+ - com/sun/star/graphic/XGraphic.hpp
+ - com/sun/star/lang/XComponent.hpp
+ svx/source/form/formcontrolfactory.cxx:
+ # Actually used
+ - com/sun/star/sdbc/XDataSource.hpp
+ svx/source/form/dataaccessdescriptor.cxx:
+ # Actually used
+ - com/sun/star/beans/XPropertySet.hpp
+ svx/source/form/fmcontrolbordermanager.cxx:
+ # Actually used
+ - com/sun/star/form/validation/XValidatableFormComponent.hpp
+ svx/source/form/databaselocationinput.cxx:
+ # Actually used
+ - com/sun/star/uno/XComponentContext.hpp
+ svx/source/form/tabwin.cxx:
+ # Needed for UnoType instantiation
+ - com/sun/star/sdbc/XConnection.hpp
+ svx/source/form/typemap.cxx:
+ # Needed for svxslots.hxx
+ - config_options.h
+ - sfx2/objitem.hxx
+ - sfx2/msg.hxx
+ - svl/memberid.h
+ - editeng/wghtitem.hxx
+ - editeng/udlnitem.hxx
+ - editeng/crossedoutitem.hxx
+ - editeng/contouritem.hxx
+ - editeng/shdditem.hxx
+ - editeng/postitem.hxx
+ - svx/clipfmtitem.hxx
+ - editeng/fhgtitem.hxx
+ - editeng/fontitem.hxx
+ - editeng/charreliefitem.hxx
+ - editeng/escapementitem.hxx
+ - editeng/colritem.hxx
+ - editeng/wrlmitem.hxx
+ - editeng/charscaleitem.hxx
+ - editeng/autokernitem.hxx
+ - editeng/ulspitem.hxx
+ - editeng/lrspitem.hxx
+ - editeng/lspcitem.hxx
+ - editeng/langitem.hxx
+ - editeng/kernitem.hxx
+ - editeng/adjustitem.hxx
+ - editeng/emphasismarkitem.hxx
+ - editeng/memberids.h
+ svx/source/sdr/contact/viewcontactofe3d.cxx:
+ # Needed for direct member access
+ - drawinglayer/attribute/sdrlightattribute3d.hxx
+ svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx:
+ # Actually used
+ - com/sun/star/awt/XControlContainer.hpp
+ - comphelper/scopeguard.hxx
+ svx/source/svdraw/charthelper.cxx:
+ # Actually used
+ - com/sun/star/embed/XEmbeddedObject.hpp
+ svx/source/svdraw/svdocapt.cxx:
+ # Needed for direct member access
+ - svx/svdopath.hxx
+ svx/source/svdraw/svdoashp.cxx:
+ # Actually used
+ - com/sun/star/drawing/XShape.hpp
+ - com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp
+ svx/source/svdraw/svdocirc.cxx:
+ # Needed for direct member access
+ - svx/svdopath.hxx
+ svx/source/svdraw/svdoedge.cxx:
+ # Needed for direct member access
+ - svx/svdopath.hxx
+ svx/source/svdraw/svdoole2.cxx:
+ # Actually used
+ - com/sun/star/embed/XEmbeddedObject.hpp
+ svx/source/svdraw/svdorect.cxx:
+ # Actually used
+ - svx/svdopath.hxx
+ svx/source/svdraw/svdpagv.cxx:
+ # Actually used
+ - comphelper/scopeguard.hxx
+ svx/source/table/accessiblecell.cxx:
+ # Needed for SvxTextEditSource object instantiation
+ - svx/svdotext.hxx
+ svx/source/table/accessibletableshape.cxx:
+ # Actually used
+ - com/sun/star/drawing/XShape.hpp
+ svx/source/table/tablecolumns.cxx:
+ # Complete type is needed for template class
+ - tablecolumn.hxx
+ svx/source/tbxctrls/tbunocontroller.cxx:
+ # Needed for rtl::math::round
+ - rtl/math.hxx
+ svx/source/unodraw/recoveryui.cxx:
+ # Needed for LIBO_ETC_FOLDER on WIN32
+ - config_folders.h
+ svx/source/unodraw/unoshcol.cxx:
+ # Don't propose hxx -> h change in URE libs
+ - cppuhelper/interfacecontainer.hxx
+ svx/source/unodraw/unoshape.cxx:
+ # Actually used
+ - comphelper/scopeguard.hxx
+ svx/source/unodraw/unoprov.cxx:
+ # Needed for UnoType instantiation
+ - com/sun/star/lang/Locale.hpp
+ svx/qa/unit/xoutdev.cxx:
+ # Needed for system-cppunit
+ - unotest/bootstrapfixturebase.hxx
+ svx/qa/unit/XTableImportExportTest.cxx:
+ # Needed for --with-system-cppunit
+ - unotest/bootstrapfixturebase.hxx
+ svx/sdi/svxslots.hrc:
+ # Needed for building svx/sdi/svx.sdi
+ - sfx2/sfxsids.hrc
+ - editeng/memberids.h
+ - editeng/editids.hrc
+ - svx/svxids.hrc
+ - svx/unomid.hxx
diff --git a/svx/JunitTest_svx_unoapi.mk b/svx/JunitTest_svx_unoapi.mk
new file mode 100644
index 000000000..f095a9b09
--- /dev/null
+++ b/svx/JunitTest_svx_unoapi.mk
@@ -0,0 +1,24 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_JunitTest_JunitTest,svx_unoapi))
+
+$(eval $(call gb_JunitTest_set_unoapi_test_defaults,svx_unoapi))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/Library_svx.mk b/svx/Library_svx.mk
new file mode 100644
index 000000000..092a4613f
--- /dev/null
+++ b/svx/Library_svx.mk
@@ -0,0 +1,291 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Library_Library,svx))
+
+$(eval $(call gb_Library_set_componentfile,svx,svx/util/svx,services))
+
+$(eval $(call gb_Library_add_componentimpls,svx, \
+ $(call gb_Helper_optional,BREAKPAD,crashreport) \
+ $(if $(ENABLE_WASM_STRIP_RECOVERYUI),,recoveryui) \
+))
+
+$(eval $(call gb_Library_set_include,svx,\
+ -I$(SRCDIR)/svx/inc \
+ -I$(SRCDIR)/svx/source/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_Library_use_sdk_api,svx))
+
+$(eval $(call gb_Library_use_custom_headers,svx,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_Library_add_defs,svx,\
+ -DSVX_DLLIMPLEMENTATION \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,svx,svx/inc/pch/precompiled_svx))
+
+$(eval $(call gb_Library_use_libraries,svx,\
+ $(call gb_Helper_optional,AVMEDIA,avmedia) \
+ basegfx \
+ sb \
+ comphelper \
+ cppuhelper \
+ cppu \
+ $(call gb_Helper_optional,BREAKPAD, \
+ crashreport) \
+ $(call gb_Helper_optional,DBCONNECTIVITY, \
+ dbtools) \
+ drawinglayercore \
+ drawinglayer \
+ editeng \
+ fwk \
+ i18nlangtag \
+ i18nutil \
+ sal \
+ salhelper \
+ sfx \
+ sot \
+ svl \
+ svt \
+ svxcore \
+ tk \
+ tl \
+ ucbhelper \
+ utl \
+ vcl \
+ xo \
+ xmlscript \
+))
+
+$(eval $(call gb_Library_use_externals,svx,\
+ boost_headers \
+ $(call gb_Helper_optional,BREAKPAD, \
+ curl) \
+ icuuc \
+ icu_headers \
+))
+
+ifneq ($(ENABLE_WASM_STRIP_RECOVERYUI),TRUE)
+$(eval $(call gb_Library_add_exception_objects,svx,\
+ svx/source/dialog/docrecovery \
+ svx/source/unodraw/recoveryui \
+))
+endif
+
+ifneq ($(ENABLE_WASM_STRIP_ACCESSIBILITY),TRUE)
+$(eval $(call gb_Library_add_exception_objects,svx,\
+ svx/source/accessibility/AccessibleControlShape \
+ svx/source/accessibility/AccessibleEmptyEditSource \
+ svx/source/accessibility/AccessibleGraphicShape \
+ svx/source/accessibility/AccessibleOLEShape \
+ svx/source/accessibility/AccessibleShape \
+ svx/source/accessibility/AccessibleShapeInfo \
+ svx/source/accessibility/AccessibleShapeTreeInfo \
+ svx/source/accessibility/AccessibleTextEventQueue \
+ svx/source/accessibility/AccessibleTextHelper \
+ svx/source/accessibility/ChildrenManager \
+ svx/source/accessibility/ChildrenManagerImpl \
+ svx/source/accessibility/DescriptionGenerator \
+ svx/source/accessibility/GraphCtlAccessibleContext \
+ svx/source/accessibility/ShapeTypeHandler \
+ svx/source/accessibility/SvxShapeTypes \
+ svx/source/accessibility/lookupcolorname \
+))
+endif
+
+$(eval $(call gb_Library_add_exception_objects,svx,\
+ svx/source/accessibility/AccessibleFrameSelector \
+ svx/source/accessibility/charmapacc \
+ svx/source/accessibility/svxpixelctlaccessiblecontext \
+ svx/source/accessibility/svxrectctaccessiblecontext \
+ svx/source/customshapes/EnhancedCustomShape3d \
+ svx/source/customshapes/EnhancedCustomShapeEngine \
+ svx/source/customshapes/EnhancedCustomShapeFontWork \
+ svx/source/customshapes/EnhancedCustomShapeHandle \
+ svx/source/dialog/AccessibilityCheckDialog \
+ svx/source/dialog/GenericCheckDialog \
+ svx/source/dialog/_bmpmask \
+ svx/source/dialog/charmap \
+ svx/source/dialog/searchcharmap \
+ svx/source/dialog/connctrl \
+ svx/source/dialog/_contdlg \
+ svx/source/dialog/contwnd \
+ svx/source/dialog/compressgraphicdialog \
+ $(call gb_Helper_optional,BREAKPAD, \
+ svx/source/dialog/crashreportdlg \
+ svx/source/dialog/crashreportui) \
+ svx/source/dialog/ctredlin \
+ svx/source/dialog/ClassificationCommon \
+ svx/source/dialog/ClassificationDialog \
+ svx/source/dialog/ClassificationEditView \
+ svx/source/dialog/databaseregistrationui \
+ svx/source/dialog/dialcontrol \
+ svx/source/dialog/dlgctl3d \
+ svx/source/dialog/dlgctrl \
+ svx/source/dialog/fntctrl \
+ svx/source/dialog/fontwork \
+ svx/source/dialog/frmdirlbox \
+ svx/source/dialog/frmsel \
+ svx/source/dialog/graphctl \
+ svx/source/dialog/grfflt \
+ svx/source/dialog/hdft \
+ svx/source/dialog/hyperdlg \
+ svx/source/dialog/imapdlg \
+ svx/source/dialog/imapwnd \
+ svx/source/dialog/linkwarn \
+ svx/source/dialog/measctrl \
+ svx/source/dialog/optgrid \
+ svx/source/dialog/pagectrl \
+ svx/source/dialog/paraprev \
+ svx/source/dialog/passwd \
+ svx/source/dialog/relfld \
+ svx/source/dialog/rlrcitem \
+ svx/source/dialog/rubydialog \
+ svx/source/dialog/rulritem \
+ svx/source/dialog/SafeModeDialog \
+ svx/source/dialog/FileExportedDialog \
+ svx/source/dialog/SafeModeUI \
+ svx/source/dialog/SpellDialogChildWindow \
+ svx/source/dialog/srchctrl \
+ svx/source/dialog/srchdlg \
+ svx/source/dialog/strarray \
+ svx/source/dialog/svxbmpnumvalueset \
+ svx/source/dialog/svxgraphicitem \
+ svx/source/dialog/svxruler \
+ svx/source/dialog/swframeexample \
+ svx/source/dialog/swframeposstrings \
+ svx/source/dialog/txencbox \
+ svx/source/dialog/txenctab \
+ svx/source/dialog/weldeditview \
+ svx/source/dialog/signaturelinehelper \
+ svx/source/engine3d/float3d \
+ svx/source/fmcomp/dbaobjectex \
+ svx/source/form/databaselocationinput \
+ svx/source/form/dbcharsethelper \
+ $(call gb_Helper_optional,DBCONNECTIVITY,svx/source/form/filtnav) \
+ svx/source/form/fmobjfac \
+ svx/source/form/fmPropBrw \
+ svx/source/form/fmsrccfg \
+ svx/source/form/fmsrcimp \
+ svx/source/form/tabwin \
+ svx/source/form/tbxform \
+ svx/source/items/algitem \
+ svx/source/items/autoformathelper \
+ svx/source/items/hlnkitem \
+ svx/source/items/numfmtsh \
+ svx/source/items/legacyitem \
+ svx/source/items/numinf \
+ svx/source/items/ofaitem \
+ svx/source/items/pageitem \
+ svx/source/items/postattr \
+ svx/source/items/rotmodit \
+ svx/source/items/SmartTagItem \
+ svx/source/items/svxerr \
+ svx/source/items/viewlayoutitem \
+ svx/source/items/zoomslideritem \
+ svx/source/mnuctrls/clipboardctl \
+ svx/source/mnuctrls/smarttagmenu \
+ svx/source/sidebar/ContextChangeEventMultiplexer \
+ svx/source/sidebar/EmptyPanel \
+ svx/source/sidebar/inspector/InspectorTextPanel \
+ svx/source/sidebar/nbdtmg \
+ svx/source/sidebar/nbdtmgfact \
+ svx/source/sidebar/PanelFactory \
+ svx/source/sidebar/SelectionAnalyzer \
+ svx/source/sidebar/SelectionChangeHandler \
+ svx/source/sidebar/text/TextCharacterSpacingControl \
+ svx/source/sidebar/text/TextCharacterSpacingPopup \
+ svx/source/sidebar/text/TextUnderlineControl \
+ svx/source/sidebar/text/TextUnderlinePopup \
+ svx/source/sidebar/text/TextPropertyPanel \
+ svx/source/sidebar/styles/StylesPropertyPanel \
+ svx/source/sidebar/lists/ListsPropertyPanel \
+ svx/source/sidebar/paragraph/ParaLineSpacingControl \
+ svx/source/sidebar/paragraph/ParaLineSpacingPopup \
+ svx/source/sidebar/paragraph/ParaPropertyPanel \
+ svx/source/sidebar/paragraph/ParaSpacingWindow \
+ svx/source/sidebar/paragraph/ParaSpacingControl \
+ svx/source/sidebar/area/AreaPropertyPanel \
+ svx/source/sidebar/area/AreaPropertyPanelBase \
+ svx/source/sidebar/area/AreaTransparencyGradientPopup \
+ svx/source/sidebar/effect/EffectPropertyPanel \
+ svx/source/sidebar/fontwork/FontworkPropertyPanel \
+ svx/source/sidebar/shadow/ShadowPropertyPanel \
+ svx/source/sidebar/graphic/GraphicPropertyPanel \
+ svx/source/sidebar/line/LinePropertyPanel \
+ svx/source/sidebar/line/LinePropertyPanelBase \
+ svx/source/sidebar/line/LineWidthValueSet \
+ svx/source/sidebar/line/LineWidthPopup \
+ $(call gb_Helper_optional,AVMEDIA,svx/source/sidebar/media/MediaPlaybackPanel) \
+ svx/source/sidebar/possize/PosSizePropertyPanel \
+ svx/source/sidebar/shapes/DefaultShapesPanel \
+ svx/source/sidebar/shapes/ShapesUtil \
+ svx/source/sidebar/textcolumns/TextColumnsPropertyPanel \
+ svx/source/sidebar/tools/ValueSetWithTextControl \
+ svx/source/stbctrls/pszctrl \
+ svx/source/stbctrls/insctrl \
+ svx/source/stbctrls/selctrl \
+ svx/source/stbctrls/xmlsecctrl \
+ svx/source/stbctrls/modctrl \
+ svx/source/stbctrls/zoomsliderctrl \
+ svx/source/stbctrls/zoomctrl \
+ svx/source/svdraw/ActionDescriptionProvider \
+ svx/source/svdraw/MediaShellHelpers \
+ svx/source/smarttags/SmartTagMgr \
+ svx/source/table/accessiblecell \
+ svx/source/table/accessibletableshape \
+ svx/source/table/tabledesign \
+ svx/source/table/tablertfexporter \
+ svx/source/table/tablertfimporter \
+ svx/source/tbxctrls/bulletsnumbering \
+ svx/source/tbxctrls/colrctrl \
+ svx/source/tbxctrls/SvxColorChildWindow \
+ svx/source/tbxctrls/fillctrl \
+ svx/source/tbxctrls/formatpaintbrushctrl \
+ svx/source/tbxctrls/grafctrl \
+ svx/source/tbxctrls/itemwin \
+ svx/source/tbxctrls/layctrl \
+ svx/source/tbxctrls/lboxctrl \
+ svx/source/tbxctrls/linewidthctrl \
+ svx/source/tbxctrls/tbunocontroller \
+ svx/source/tbxctrls/tbunosearchcontrollers \
+ svx/source/tbxctrls/tbxcolor \
+ svx/source/tbxctrls/tbxdrctl \
+ svx/source/tbxctrls/verttexttbxctrl \
+ svx/source/uitest/uiobject \
+ svx/source/unodraw/unoctabl \
+ svx/source/unodraw/UnoNamespaceMap \
+ svx/source/unodraw/unopool \
+ svx/source/unodraw/unoshcol \
+ svx/source/unogallery/unogalitem \
+ svx/source/unogallery/unogaltheme \
+ svx/source/unogallery/unogalthemeprovider \
+))
+
+ifeq ($(OS),WNT)
+$(eval $(call gb_Library_use_system_win32_libs,svx,\
+ advapi32 \
+))
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/Library_svxcore.mk b/svx/Library_svxcore.mk
new file mode 100644
index 000000000..5cacdf82e
--- /dev/null
+++ b/svx/Library_svxcore.mk
@@ -0,0 +1,497 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Library_Library,svxcore))
+
+$(eval $(call gb_Library_set_componentfile,svxcore,svx/util/svxcore,services))
+
+$(eval $(call gb_Library_add_componentimpls,svxcore, \
+ $(if $(ENABLE_WASM_STRIP_BASIC_CALC_DRAW_MATH_IMPRESS),,draw) \
+))
+
+$(eval $(call gb_Library_add_sdi_headers,svxcore,svx/sdi/svxslots))
+
+$(eval $(call gb_Library_use_custom_headers,svxcore,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_Library_use_sdk_api,svxcore))
+
+$(eval $(call gb_Library_set_include,svxcore,\
+ -I$(SRCDIR)/svx/inc \
+ -I$(SRCDIR)/svx/source/inc \
+ $$(INCLUDE) \
+ -I$(WORKDIR)/SdiTarget/svx/sdi \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,svxcore,svx/inc/pch/precompiled_svxcore))
+
+#BOOST switch in customshapes
+#dialog:
+#.IF "$(OS)"=="WNT"
+#CFLAGS+= -DUNICODE -D_UNICODE
+#.ENDIF
+
+$(eval $(call gb_Library_add_defs,svxcore,\
+ -DSVXCORE_DLLIMPLEMENTATION \
+))
+
+$(eval $(call gb_Library_use_libraries,svxcore,\
+ avmedia \
+ basegfx \
+ sb \
+ comphelper \
+ cppuhelper \
+ cppu \
+ $(call gb_Helper_optional,DBCONNECTIVITY, \
+ dbtools) \
+ drawinglayercore \
+ drawinglayer \
+ editeng \
+ fwk \
+ i18nlangtag \
+ i18nutil \
+ lng \
+ sal \
+ salhelper \
+ sax \
+ sfx \
+ sot \
+ svl \
+ svt \
+ tk \
+ tl \
+ ucbhelper \
+ utl \
+ vcl \
+ xo \
+))
+
+$(eval $(call gb_Library_use_externals,svxcore,\
+ boost_headers \
+ epoxy \
+ icuuc \
+ icu_headers \
+ libxml2 \
+))
+
+ifeq ($(OS),MACOSX)
+
+$(eval $(call gb_Library_add_cxxflags,svxcore,\
+ $(gb_OBJCXXFLAGS) \
+))
+
+$(eval $(call gb_Library_use_system_darwin_frameworks,svxcore,\
+ Foundation \
+))
+
+endif
+
+$(eval $(call gb_Library_add_exception_objects,svxcore,\
+ svx/source/core/extedit \
+ svx/source/core/graphichelper \
+ svx/source/customshapes/EnhancedCustomShape2d \
+ svx/source/customshapes/EnhancedCustomShapeFunctionParser \
+ svx/source/customshapes/EnhancedCustomShapeGeometry \
+ svx/source/customshapes/EnhancedCustomShapeTypeNames \
+ svx/source/diagram/datamodel \
+ svx/source/diagram/IDiagramHelper \
+ svx/source/dialog/dialmgr \
+ svx/source/dialog/dlgutil \
+ svx/source/dialog/hexcolorcontrol \
+ svx/source/dialog/framelink \
+ svx/source/dialog/framelinkarray \
+ svx/source/dialog/langbox \
+ svx/source/dialog/pagenumberlistbox \
+ svx/source/dialog/papersizelistbox \
+ svx/source/dialog/samecontentlistbox \
+ svx/source/dialog/spacinglistbox \
+ svx/source/dialog/svxdlg \
+ svx/source/dialog/SvxNumOptionsTabPageHelper \
+ svx/source/engine3d/camera3d \
+ svx/source/engine3d/cube3d \
+ svx/source/engine3d/deflt3d \
+ svx/source/engine3d/dragmt3d \
+ svx/source/engine3d/e3dsceneupdater \
+ svx/source/engine3d/e3dundo \
+ svx/source/engine3d/extrud3d \
+ svx/source/engine3d/helperhittest3d \
+ svx/source/engine3d/helperminimaldepth3d \
+ svx/source/engine3d/lathe3d \
+ svx/source/engine3d/obj3d \
+ svx/source/engine3d/objfac3d \
+ svx/source/engine3d/polygn3d \
+ svx/source/engine3d/scene3d \
+ svx/source/engine3d/sphere3d \
+ svx/source/engine3d/svx3ditems \
+ svx/source/engine3d/view3d \
+ svx/source/engine3d/view3d1 \
+ svx/source/engine3d/viewpt3d2 \
+ svx/source/fmcomp/dbaexchange \
+ svx/source/fmcomp/fmgridcl \
+ svx/source/fmcomp/fmgridif \
+ svx/source/fmcomp/gridcell \
+ svx/source/fmcomp/gridcols \
+ svx/source/fmcomp/gridctrl \
+ svx/source/fmcomp/xmlexchg \
+ svx/source/form/dataaccessdescriptor \
+ svx/source/form/datalistener \
+ svx/source/form/datanavi \
+ svx/source/form/delayedevent \
+ svx/source/form/labelitemwindow \
+ svx/source/form/fmcontrolbordermanager \
+ svx/source/form/fmcontrollayout \
+ svx/source/form/fmdmod \
+ svx/source/form/fmdocumentclassification \
+ svx/source/form/fmdpage \
+ svx/source/form/fmexch \
+ svx/source/form/fmexpl \
+ svx/source/form/fmmodel \
+ svx/source/form/fmobj \
+ svx/source/form/fmpage \
+ svx/source/form/fmpgeimp \
+ svx/source/form/fmscriptingenv \
+ svx/source/form/fmservs \
+ svx/source/form/fmshell \
+ svx/source/form/fmshimp \
+ svx/source/form/fmtextcontroldialogs \
+ svx/source/form/fmtextcontrolfeature \
+ svx/source/form/fmtextcontrolshell \
+ svx/source/form/fmtools \
+ svx/source/form/fmundo \
+ svx/source/form/fmview \
+ svx/source/form/fmvwimp \
+ svx/source/form/formcontrolfactory \
+ svx/source/form/formcontroller \
+ svx/source/form/formcontrolling \
+ svx/source/form/formdispatchinterceptor \
+ svx/source/form/formfeaturedispatcher \
+ svx/source/form/formtoolbars \
+ svx/source/form/legacyformcontroller \
+ svx/source/form/navigatortree \
+ svx/source/form/navigatortreemodel \
+ svx/source/form/ParseContext \
+ svx/source/form/sdbdatacolumn \
+ svx/source/form/sqlparserclient \
+ svx/source/form/typemap \
+ svx/source/form/xfm_addcondition \
+ svx/source/gallery2/codec \
+ svx/source/gallery2/galbrws1 \
+ svx/source/gallery2/galbrws2 \
+ svx/source/gallery2/galctrl \
+ svx/source/gallery2/galexpl \
+ svx/source/gallery2/galini \
+ svx/source/gallery2/gallery1 \
+ svx/source/gallery2/galmisc \
+ svx/source/gallery2/galobj \
+ svx/source/gallery2/galtheme \
+ svx/source/gallery2/GalleryControl \
+ svx/source/gallery2/gallerybinaryengine \
+ svx/source/gallery2/gallerybinaryengineentry \
+ svx/source/gallery2/gallerystoragelocations \
+ svx/source/gallery2/gallerybinarystoragelocations \
+ svx/source/gallery2/galleryobjectcollection \
+ svx/source/gallery2/galleryfilestorage \
+ svx/source/gallery2/galleryfilestorageentry \
+ svx/source/gallery2/galleryobjectstorage \
+ svx/source/gallery2/galleryobjectbinarystorage \
+ svx/source/gallery2/galleryobjectxmlstorage \
+ svx/source/items/chrtitem \
+ svx/source/items/clipfmtitem \
+ svx/source/items/customshapeitem \
+ svx/source/items/drawitem \
+ svx/source/items/e3ditem \
+ svx/source/items/galleryitem \
+ svx/source/items/grfitem \
+ svx/source/sdr/animation/scheduler \
+ svx/source/sdr/animation/objectanimator \
+ svx/source/sdr/animation/animationstate \
+ svx/source/sdr/attribute/sdrallfillattributeshelper \
+ svx/source/sdr/attribute/sdrlinefilleffectstextattribute \
+ svx/source/sdr/attribute/sdrfilltextattribute \
+ svx/source/sdr/attribute/sdreffectstextattribute \
+ svx/source/sdr/attribute/sdrtextattribute \
+ svx/source/sdr/attribute/sdrlineeffectstextattribute \
+ svx/source/sdr/attribute/sdrformtextattribute \
+ svx/source/sdr/attribute/sdrformtextoutlineattribute \
+ svx/source/sdr/contact/viewobjectcontactofgroup \
+ svx/source/sdr/contact/viewobjectcontactofsdrpage \
+ svx/source/sdr/contact/viewcontactofpageobj \
+ svx/source/sdr/contact/viewcontactofe3d \
+ svx/source/sdr/contact/viewcontactofe3dcube \
+ svx/source/sdr/contact/viewcontactofsdrmediaobj \
+ svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor \
+ svx/source/sdr/contact/viewobjectcontactofpageobj \
+ svx/source/sdr/contact/viewobjectcontactofe3dscene \
+ svx/source/sdr/contact/viewcontactofgraphic \
+ svx/source/sdr/contact/viewobjectcontactredirector \
+ svx/source/sdr/contact/viewcontactofsdrcircobj \
+ svx/source/sdr/contact/viewcontactofgroup \
+ svx/source/sdr/contact/viewcontactofunocontrol \
+ svx/source/sdr/contact/viewcontactofsdrobjcustomshape \
+ svx/source/sdr/contact/viewcontactofsdrobj \
+ svx/source/sdr/contact/objectcontact \
+ svx/source/sdr/contact/viewcontactoftextobj \
+ svx/source/sdr/contact/viewcontactofe3dlathe \
+ svx/source/sdr/contact/viewcontactofsdrpage \
+ svx/source/sdr/contact/viewcontactofe3dextrude \
+ svx/source/sdr/contact/viewcontactofmasterpagedescriptor \
+ svx/source/sdr/contact/viewcontact \
+ svx/source/sdr/contact/viewcontactofsdrole2obj \
+ svx/source/sdr/contact/displayinfo \
+ svx/source/sdr/contact/viewcontactofe3dscene \
+ svx/source/sdr/contact/viewcontactofsdrrectobj \
+ svx/source/sdr/contact/viewobjectcontactofsdrole2obj \
+ svx/source/sdr/contact/viewobjectcontactofunocontrol \
+ svx/source/sdr/contact/viewobjectcontactofgraphic \
+ $(call gb_Helper_optional,AVMEDIA,svx/source/sdr/contact/sdrmediawindow) \
+ svx/source/sdr/contact/viewobjectcontactofsdrmediaobj \
+ svx/source/sdr/contact/viewcontactofsdrcaptionobj \
+ svx/source/sdr/contact/viewcontactofvirtobj \
+ svx/source/sdr/contact/viewcontactofe3dsphere \
+ svx/source/sdr/contact/viewcontactofe3dpolygon \
+ svx/source/sdr/contact/viewcontactofsdredgeobj \
+ svx/source/sdr/contact/viewobjectcontact \
+ svx/source/sdr/contact/viewobjectcontactofsdrobj \
+ svx/source/sdr/contact/objectcontactofpageview \
+ svx/source/sdr/contact/viewcontactofsdrpathobj \
+ svx/source/sdr/contact/viewcontactofsdrmeasureobj \
+ svx/source/sdr/contact/objectcontactofobjlistpainter \
+ svx/source/sdr/contact/viewobjectcontactofe3d \
+ svx/source/sdr/overlay/overlayline \
+ svx/source/sdr/overlay/overlaycrosshair \
+ svx/source/sdr/overlay/overlayrollingrectangle \
+ svx/source/sdr/overlay/overlaytriangle \
+ svx/source/sdr/overlay/overlayselection \
+ svx/source/sdr/overlay/overlayrectangle \
+ svx/source/sdr/overlay/overlaybitmapex \
+ svx/source/sdr/overlay/overlaymanagerbuffered \
+ svx/source/sdr/overlay/overlayhelpline \
+ svx/source/sdr/overlay/overlayanimatedbitmapex \
+ svx/source/sdr/overlay/overlaypolypolygon \
+ svx/source/sdr/overlay/overlayobjectcell \
+ svx/source/sdr/overlay/overlaytools \
+ svx/source/sdr/overlay/overlayprimitive2dsequenceobject \
+ svx/source/sdr/overlay/overlayobject \
+ svx/source/sdr/overlay/overlaymanager \
+ svx/source/sdr/overlay/overlayobjectlist \
+ svx/source/sdr/overlay/overlayhandle \
+ svx/source/sdr/misc/ImageMapInfo \
+ svx/source/sdr/primitive2d/sdrellipseprimitive2d \
+ svx/source/sdr/primitive2d/sdrprimitivetools \
+ svx/source/sdr/primitive2d/sdrtextprimitive2d \
+ svx/source/sdr/primitive2d/primitivefactory2d \
+ svx/source/sdr/primitive2d/sdrolecontentprimitive2d \
+ svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d \
+ svx/source/sdr/primitive2d/sdrgrafprimitive2d \
+ svx/source/sdr/primitive2d/sdrole2primitive2d \
+ svx/source/sdr/primitive2d/sdrpathprimitive2d \
+ svx/source/sdr/primitive2d/sdrrectangleprimitive2d \
+ svx/source/sdr/primitive2d/sdrcaptionprimitive2d \
+ svx/source/sdr/primitive2d/sdrconnectorprimitive2d \
+ svx/source/sdr/primitive2d/sdrmeasureprimitive2d \
+ svx/source/sdr/primitive2d/sdrframeborderprimitive2d \
+ svx/source/sdr/primitive2d/sdrattributecreator \
+ svx/source/sdr/primitive2d/sdrdecompositiontools \
+ svx/source/sdr/primitive3d/sdrattributecreator3d \
+ svx/source/sdr/properties/pageproperties \
+ svx/source/sdr/properties/e3dsceneproperties \
+ svx/source/sdr/properties/itemsettools \
+ svx/source/sdr/properties/captionproperties \
+ svx/source/sdr/properties/e3dextrudeproperties \
+ svx/source/sdr/properties/e3dproperties \
+ svx/source/sdr/properties/measureproperties \
+ svx/source/sdr/properties/customshapeproperties \
+ svx/source/sdr/properties/rectangleproperties \
+ svx/source/sdr/properties/groupproperties \
+ svx/source/sdr/properties/properties \
+ svx/source/sdr/properties/e3dlatheproperties \
+ svx/source/sdr/properties/graphicproperties \
+ svx/source/sdr/properties/circleproperties \
+ svx/source/sdr/properties/emptyproperties \
+ svx/source/sdr/properties/e3dsphereproperties \
+ svx/source/sdr/properties/defaultproperties \
+ svx/source/sdr/properties/textproperties \
+ svx/source/sdr/properties/attributeproperties \
+ svx/source/sdr/properties/connectorproperties \
+ svx/source/sdr/properties/e3dcompoundproperties \
+ svx/source/sdr/properties/oleproperties \
+ svx/source/svdraw/clonelist \
+ svx/source/svdraw/charthelper \
+ svx/source/svdraw/gradtrns \
+ svx/source/svdraw/polypolygoneditor \
+ svx/source/svdraw/presetooxhandleadjustmentrelations \
+ svx/source/svdraw/sdrhittesthelper \
+ svx/source/svdraw/sdrmasterpagedescriptor \
+ svx/source/svdraw/sdrpagewindow \
+ svx/source/svdraw/sdrpaintwindow \
+ svx/source/svdraw/sdrundomanager \
+ svx/source/svdraw/selectioncontroller \
+ svx/source/svdraw/svdattr \
+ svx/source/svdraw/svdcrtv \
+ svx/source/svdraw/svddrag \
+ svx/source/svdraw/svddrgmt \
+ svx/source/svdraw/svddrgv \
+ svx/source/svdraw/svdedtv \
+ svx/source/svdraw/svdedtv1 \
+ svx/source/svdraw/svdedtv2 \
+ svx/source/svdraw/svdedxv \
+ svx/source/svdraw/svdetc \
+ svx/source/svdraw/svdfmtf \
+ svx/source/svdraw/svdglev \
+ svx/source/svdraw/svdglue \
+ svx/source/svdraw/svdhdl \
+ svx/source/svdraw/svdhlpln \
+ svx/source/svdraw/svditer \
+ svx/source/svdraw/svdlayer \
+ svx/source/svdraw/svdmark \
+ svx/source/svdraw/svdmodel \
+ svx/source/svdraw/svdmrkv \
+ svx/source/svdraw/svdmrkv1 \
+ svx/source/svdraw/svdoashp \
+ svx/source/svdraw/svdoattr \
+ svx/source/svdraw/svdobj \
+ svx/source/svdraw/svdobjplusdata \
+ svx/source/svdraw/svdobjuserdatalist \
+ svx/source/svdraw/svdocapt \
+ svx/source/svdraw/svdocirc \
+ svx/source/svdraw/svdoedge \
+ svx/source/svdraw/svdograf \
+ svx/source/svdraw/svdogrp \
+ svx/source/svdraw/svdomeas \
+ svx/source/svdraw/svdomedia \
+ svx/source/svdraw/svdoole2 \
+ svx/source/svdraw/svdopage \
+ svx/source/svdraw/svdopath \
+ svx/source/svdraw/svdorect \
+ svx/source/svdraw/svdotext \
+ svx/source/svdraw/svdotextdecomposition \
+ svx/source/svdraw/svdotextpathdecomposition \
+ svx/source/svdraw/svdotxat \
+ svx/source/svdraw/svdotxdr \
+ svx/source/svdraw/svdotxed \
+ svx/source/svdraw/svdotxfl \
+ svx/source/svdraw/svdotxln \
+ svx/source/svdraw/svdotxtr \
+ svx/source/svdraw/svdouno \
+ svx/source/svdraw/svdoutl \
+ svx/source/svdraw/svdoutlinercache \
+ svx/source/svdraw/svdovirt \
+ svx/source/svdraw/svdpage \
+ svx/source/svdraw/svdpagv \
+ svx/source/svdraw/svdpdf \
+ svx/source/svdraw/svdpntv \
+ svx/source/svdraw/svdpoev \
+ svx/source/svdraw/svdsnpv \
+ svx/source/svdraw/svdtext \
+ svx/source/svdraw/svdtrans \
+ svx/source/svdraw/svdundo \
+ svx/source/svdraw/svdview \
+ svx/source/svdraw/svdviter \
+ svx/source/svdraw/svdxcgv \
+ svx/source/svdraw/textchain \
+ svx/source/svdraw/textchainflow \
+ svx/source/svdraw/textchaincursor \
+ svx/source/styles/CommonStylePreviewRenderer \
+ svx/source/styles/CommonStyleManager \
+ svx/source/styles/ColorSets \
+ svx/source/table/cell \
+ svx/source/table/cellcursor \
+ svx/source/table/cellrange \
+ svx/source/table/propertyset \
+ svx/source/table/svdotable \
+ svx/source/table/tablecolumn \
+ svx/source/table/tablecolumns \
+ svx/source/table/tablecontroller \
+ svx/source/table/tablehandles \
+ svx/source/table/tablelayouter \
+ svx/source/table/tablemodel \
+ svx/source/table/tablerow \
+ svx/source/table/tablerows \
+ svx/source/table/tableundo \
+ svx/source/table/viewcontactoftableobj \
+ svx/source/tbxctrls/extrusioncontrols \
+ svx/source/tbxctrls/fontworkgallery \
+ svx/source/tbxctrls/linectrl \
+ svx/source/tbxctrls/Palette \
+ svx/source/tbxctrls/PaletteManager \
+ svx/source/tbxctrls/tbcontrl \
+ svx/source/tbxctrls/tbxcolorupdate \
+ svx/source/tbxctrls/SvxColorValueSet \
+ svx/source/tbxctrls/SvxPresetListBox \
+ svx/source/tbxctrls/StylesPreviewToolBoxControl \
+ svx/source/tbxctrls/StylesPreviewWindow \
+ svx/source/toolbars/extrusionbar \
+ svx/source/toolbars/fontworkbar \
+ svx/source/uitest/sdrobject \
+ svx/source/unodraw/gluepts \
+ svx/source/unodraw/shapepropertynotifier \
+ svx/source/unodraw/SvxXTextColumns \
+ svx/source/unodraw/tableshape \
+ svx/source/unodraw/unobrushitemhelper \
+ svx/source/unodraw/unobtabl \
+ svx/source/unodraw/unodtabl \
+ svx/source/unodraw/UnoGraphicExporter \
+ svx/source/unodraw/unogtabl \
+ svx/source/unodraw/unohtabl \
+ svx/source/unodraw/unomlstr \
+ svx/source/unodraw/unomod \
+ svx/source/unodraw/unomtabl \
+ svx/source/unodraw/UnoNameItemTable \
+ svx/source/unodraw/unopage \
+ svx/source/unodraw/unoprov \
+ svx/source/unodraw/unoshap2 \
+ svx/source/unodraw/unoshap3 \
+ svx/source/unodraw/unoshap4 \
+ svx/source/unodraw/unoshape \
+ svx/source/unodraw/unoshtxt \
+ svx/source/unodraw/unottabl \
+ svx/source/unodraw/XPropertyTable \
+ svx/source/xml/xmleohlp \
+ svx/source/xml/xmlexport \
+ svx/source/xml/xmlgrhlp \
+ svx/source/xml/xmlxtexp \
+ svx/source/xml/xmlxtimp \
+ svx/source/xoutdev/xattr \
+ svx/source/xoutdev/xattr2 \
+ svx/source/xoutdev/xattrbmp \
+ svx/source/xoutdev/_xoutbmp \
+ svx/source/xoutdev/_xpoly \
+ svx/source/xoutdev/xpool \
+ svx/source/xoutdev/xtabbtmp \
+ svx/source/xoutdev/xtabcolr \
+ svx/source/xoutdev/xtabdash \
+ svx/source/xoutdev/xtabgrdt \
+ svx/source/xoutdev/xtabhtch \
+ svx/source/xoutdev/xtable \
+ svx/source/xoutdev/xtabptrn \
+ svx/source/xoutdev/XPropertyEntry \
+ svx/source/xoutdev/xtablend \
+))
+
+$(eval $(call gb_SdiTarget_SdiTarget,svx/sdi/svxslots,svx/sdi/svx))
+
+$(eval $(call gb_SdiTarget_set_include,svx/sdi/svxslots,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/svx/inc \
+ -I$(SRCDIR)/svx/sdi \
+ -I$(SRCDIR)/sfx2/sdi \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/Library_textconversiondlgs.mk b/svx/Library_textconversiondlgs.mk
new file mode 100644
index 000000000..dcf885369
--- /dev/null
+++ b/svx/Library_textconversiondlgs.mk
@@ -0,0 +1,53 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Library_Library,textconversiondlgs))
+
+$(eval $(call gb_Library_set_componentfile,textconversiondlgs,svx/util/textconversiondlgs,services))
+
+$(eval $(call gb_Library_set_include,textconversiondlgs,\
+ -I$(SRCDIR)/svx/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_Library_use_external,textconversiondlgs,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,textconversiondlgs))
+
+$(eval $(call gb_Library_use_libraries,textconversiondlgs,\
+ comphelper \
+ cppuhelper \
+ cppu \
+ sal \
+ i18nlangtag \
+ svl \
+ svt \
+ tk \
+ tl \
+ utl \
+ vcl \
+))
+
+$(eval $(call gb_Library_add_exception_objects,textconversiondlgs,\
+ svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog \
+ svx/source/unodialogs/textconversiondlgs/chinese_translationdialog \
+ svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/Makefile b/svx/Makefile
new file mode 100644
index 000000000..ccb1c85a0
--- /dev/null
+++ b/svx/Makefile
@@ -0,0 +1,7 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+
+module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/Module_svx.mk b/svx/Module_svx.mk
new file mode 100644
index 000000000..40e65bd70
--- /dev/null
+++ b/svx/Module_svx.mk
@@ -0,0 +1,78 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Module_Module,svx))
+
+$(eval $(call gb_Module_add_targets,svx,\
+ Library_svx \
+ Library_svxcore \
+))
+
+ifeq ($(gb_Side),host)
+$(eval $(call gb_Module_add_targets,svx,\
+ Library_textconversiondlgs \
+ UIConfig_svx \
+))
+endif
+
+$(eval $(call gb_Module_add_l10n_targets,svx,\
+ AllLangMoTarget_svx \
+))
+
+$(eval $(call gb_Module_add_check_targets,svx,\
+ CppunitTest_svx_unit \
+ CppunitTest_svx_gallery_test \
+ CppunitTest_svx_removewhichrange \
+ CppunitTest_svx_styles \
+ CppunitTest_svx_core \
+))
+
+# screenshots
+$(eval $(call gb_Module_add_screenshot_targets,svx,\
+ CppunitTest_svx_dialogs_test \
+))
+
+ifneq (,$(filter DESKTOP,$(BUILD_TYPE)))
+ifeq (,$(DISABLE_DYNLOADING))
+$(eval $(call gb_Module_add_targets,svx,\
+ Executable_gengal \
+ $(if $(filter-out MACOSX WNT,$(OS)), \
+ Package_gengal) \
+))
+endif
+else # !DESKTOP
+ifeq ($(WITH_GALLERY_BUILD),TRUE)
+$(eval $(call gb_Module_add_targets_for_build,svx,\
+ Executable_gengal \
+))
+endif
+endif # !DESKTOP
+
+$(eval $(call gb_Module_add_subsequentcheck_targets,svx,\
+ JunitTest_svx_unoapi \
+))
+
+$(eval $(call gb_Module_add_uicheck_targets,svx,\
+ UITest_svx_table \
+))
+
+#todo: noopt for EnhanceCustomShapesFunctionParser.cxx on Solaris Sparc and MacOSX
+#todo: -DUNICODE and -D_UNICODE on WNT for source/dialog
+#todo: component file
+# vim: set noet sw=4 ts=4:
diff --git a/svx/Package_gengal.mk b/svx/Package_gengal.mk
new file mode 100644
index 000000000..ebc959a0f
--- /dev/null
+++ b/svx/Package_gengal.mk
@@ -0,0 +1,24 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Package_Package,svx_gengal,$(SRCDIR)/svx/source/gengal))
+
+$(eval $(call gb_Package_add_file,svx_gengal,$(LIBO_BIN_FOLDER)/gengal,gengal.sh))
+
+# vim: set noet ts=4 sw=4:
diff --git a/svx/README.md b/svx/README.md
new file mode 100644
index 000000000..dc4345ad6
--- /dev/null
+++ b/svx/README.md
@@ -0,0 +1,105 @@
+# Graphics Related Helper Code
+
+Contains graphics related helper code. Lots of the draw and impress code is in this shared library.
+
+- `xoutdev`
+
+ this is where a lot of wht work would happen to move to the canvas. (what does that mean?)
+
+- `svdraw`
+
+ transparent gradient stuff. [seriously? surely much more, too]
+
+## SdrObject
+
+The shapes you can see in LibreOffice (like rectangle, etc.) are SdrObjects.
+They are declared as a hierarchy:
+
+ SdrObject <- SdrAttrObj <- E3dObject <- E3dCompoundObject <- E3dCubeObj
+ ^ ^ ^ ^ ^ | | ^ ^
+ | | | | | | | | +--- E3dExtrudeObj
+ | | | | | | | +----- E3dLatheObj
+ | | | | | | +------- E3dPolygonObj
+ | | | | | +--------- E3dSphereObj
+ | | | | +--- E3dScene...
+ | | | |
+ | | | +--- SdrTextObj <- SdrObjCustomShape...
+ | | | ^ ^ ^ ^ ^
+ | | | | | | | +--- SdrEdgeObj...
+ | | | | | | +----- SdrMeasureObj...
+ | | | | | +------- SdrPathObj...
+ | | | | +--------- SdrRectObj...
+ | | | +----------- SdrTableObj...
+ | | +--- SdrObjGroup...
+ | + ---- SdrPageObj...
+ +------- SdrVirtObj...
+
+The above is incomplete of course.
+
+## SdrModel / SdrView
+
+Copied from `svdview.hxx`:
+
+ First of all the app creates a `SdrModel`.
+ Then it opens a Win and creates a `SdrView`.
+ `ShowSdrPage()` announces a page at `SdrView`.
+ It's possible to show `SdrView` in any Wins at once.
+
+ `SdrView` can show as many Wins as it wants at once. Pages are announced
+ or checked out with the help of `ShowSdrPage()`/`HideSdrPage()`. For every announced
+ page there is a `SdrPageView` instance in container aPages. If more than one page
+ is showed, you have to pay attention that the offset parameter of `ShowSdrPage()`
+ is conformed to the size of the page (to prevent overlapping of two pages).
+
+`SdrView` itself is inherited from many objects in a chain of inheritance (all
+that starts with `SdrPaintView` - that is itself inherited from few classes
+too):
+
+ SdrPaintView <- SdrSnapView <- SdrMarkView <- SdrEditView <- SdrPolyEditView
+ ^
+ +----------------------------------------------------------------+
+ |
+ SdrGlueEditView <- SdrObjEditView <- SdrExchangeView <- SdrDragView
+ ^
+ +----------------------------------------------------------------+
+ |
+ SdrCreateView <- SdrView
+
+From `SdrView` on, it is not flat, but a real hierarchy again.
+
+## Drawing Layer / SdrObject(s)
+
+See `drawinglayer/README.md` for general information about drawinglayer.
+
+Below is the class diagram that comes from
+<https://web.archive.org/web/20160827020830if_/http://www.openoffice.org:80/marketing/ooocon2006/presentations/wednesday_g11.odp>
+slide number 6.
+
+ .------- Model --------------. .------- View -----------------------------------------.
+ | SdrObject - ViewContact | 1..* | ViewObjectContact |
+ | getChild() |------| getPrimitiveList() -----> Object(s) ---> SdrView |
+ | getVOC() | | getRecPrimitiveList() Contact |
+ | getViewInd... | |________|_____________________________________________|
+ | ...ependentPrimitiveList() | |
+ |____________________________| generates
+ | ______
+ V / |
+ .----------------------. |
+ | basePrimitive | |
+ | getRange() |<---'
+ | getDecomposition() |
+ |______________________|
+
+For `SdrObjects`, there are own `DrawingLayer` primitives in
+`svx/source/sdr/primitive2d`
+
+The `ViewContact` / `ViewObject` / `ViewObjectContact` are in `svx/source/sdr/contact`
+Decomposes the `SdrObjects`, and does all sort of operations on them.
+
+If the number of visualizable objects (e.g. `SdrObjects`) is `X`, and the number of
+`SdrViews` is `Y`, then:
+
+- there are `X` `ViewContact` instances (1:1 relation with a visualizable object)
+- there are `Y` `ObjectContact` instances (1:1 relation with an `SdrView`)
+- there are `X*Y` `ViewObjectContact` instances (1:N relation to both
+ visualizable objects and `SdrView`s)
diff --git a/svx/UIConfig_svx.mk b/svx/UIConfig_svx.mk
new file mode 100644
index 000000000..33bc1797f
--- /dev/null
+++ b/svx/UIConfig_svx.mk
@@ -0,0 +1,151 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_UIConfig_UIConfig,svx))
+
+$(eval $(call gb_UIConfig_add_uifiles,svx,\
+ svx/uiconfig/ui/absrecbox \
+ svx/uiconfig/ui/acceptrejectchangesdialog \
+ svx/uiconfig/ui/accessibilitycheckdialog \
+ svx/uiconfig/ui/accessibilitycheckentry \
+ svx/uiconfig/ui/addconditiondialog \
+ svx/uiconfig/ui/adddataitemdialog \
+ svx/uiconfig/ui/addinstancedialog \
+ svx/uiconfig/ui/addmodeldialog \
+ svx/uiconfig/ui/addnamespacedialog \
+ svx/uiconfig/ui/addsubmissiondialog \
+ svx/uiconfig/ui/asianphoneticguidedialog \
+ svx/uiconfig/ui/applystylebox \
+ svx/uiconfig/ui/cellmenu \
+ svx/uiconfig/ui/charsetmenu \
+ svx/uiconfig/ui/checkbuttonbox \
+ svx/uiconfig/ui/chineseconversiondialog \
+ svx/uiconfig/ui/chinesedictionary \
+ svx/uiconfig/ui/classificationdialog \
+ svx/uiconfig/ui/clipboardmenu \
+ svx/uiconfig/ui/colorwindow \
+ svx/uiconfig/ui/currencywindow \
+ svx/uiconfig/ui/colsmenu \
+ svx/uiconfig/ui/columnswindow \
+ svx/uiconfig/ui/compressgraphicdialog \
+ svx/uiconfig/ui/crashreportdlg \
+ svx/uiconfig/ui/datanavigator \
+ svx/uiconfig/ui/defaultshapespanel \
+ svx/uiconfig/ui/deleteheaderdialog \
+ svx/uiconfig/ui/deletefooterdialog \
+ svx/uiconfig/ui/depthwindow \
+ svx/uiconfig/ui/directionwindow \
+ svx/uiconfig/ui/docking3deffects \
+ svx/uiconfig/ui/dockingcolorreplace \
+ svx/uiconfig/ui/dockingcolorwindow \
+ svx/uiconfig/ui/dockingfontwork \
+ svx/uiconfig/ui/docrecoverybrokendialog \
+ svx/uiconfig/ui/docrecoveryprogressdialog \
+ svx/uiconfig/ui/docrecoveryrecoverdialog \
+ svx/uiconfig/ui/docrecoverysavedialog \
+ svx/uiconfig/ui/extrustiondepthdialog \
+ svx/uiconfig/ui/fillctrlbox \
+ svx/uiconfig/ui/filtermenu \
+ svx/uiconfig/ui/filternavigator \
+ svx/uiconfig/ui/findbox \
+ svx/uiconfig/ui/findreplacedialog \
+ svx/uiconfig/ui/findreplacedialog-mobile \
+ svx/uiconfig/ui/floatingareastyle \
+ svx/uiconfig/ui/floatingcontour \
+ svx/uiconfig/ui/floatingframeborder \
+ svx/uiconfig/ui/floatinglineend \
+ svx/uiconfig/ui/floatinglineproperty \
+ svx/uiconfig/ui/floatinglinestyle \
+ svx/uiconfig/ui/floatingundoredo \
+ svx/uiconfig/ui/fontworkalignmentcontrol \
+ svx/uiconfig/ui/fontworkcharacterspacingcontrol \
+ svx/uiconfig/ui/fontworkgallerydialog \
+ svx/uiconfig/ui/fontworkspacingdialog \
+ svx/uiconfig/ui/fontsizebox \
+ svx/uiconfig/ui/fontnamebox \
+ svx/uiconfig/ui/formdatamenu \
+ svx/uiconfig/ui/formfielddialog \
+ svx/uiconfig/ui/formlinkwarndialog \
+ svx/uiconfig/ui/formnavigator \
+ svx/uiconfig/ui/formnavimenu \
+ svx/uiconfig/ui/formpropertydialog \
+ svx/uiconfig/ui/functionmenu \
+ svx/uiconfig/ui/gallerymenu1 \
+ svx/uiconfig/ui/gallerymenu2 \
+ svx/uiconfig/ui/genericcheckdialog \
+ svx/uiconfig/ui/genericcheckentry \
+ svx/uiconfig/ui/grafctrlbox \
+ svx/uiconfig/ui/grafmodebox \
+ svx/uiconfig/ui/headfootformatpage \
+ svx/uiconfig/ui/imapdialog \
+ svx/uiconfig/ui/imapmenu \
+ svx/uiconfig/ui/inspectortextpanel \
+ svx/uiconfig/ui/labelbox \
+ svx/uiconfig/ui/lightingwindow \
+ svx/uiconfig/ui/linkwarndialog \
+ svx/uiconfig/ui/measurewidthbar \
+ svx/uiconfig/ui/medialine \
+ svx/uiconfig/ui/mediaplayback \
+ svx/uiconfig/ui/mediawindow \
+ svx/uiconfig/ui/metricfieldbox \
+ svx/uiconfig/ui/namespacedialog \
+ svx/uiconfig/ui/navigationbar \
+ svx/uiconfig/ui/numberingwindow \
+ svx/uiconfig/ui/optgridpage \
+ svx/uiconfig/ui/paralinespacingcontrol \
+ svx/uiconfig/ui/paralrspacing \
+ svx/uiconfig/ui/paraulspacing \
+ svx/uiconfig/ui/passwd \
+ svx/uiconfig/ui/presetmenu \
+ svx/uiconfig/ui/fileexporteddialog \
+ svx/uiconfig/ui/querydeletecontourdialog \
+ svx/uiconfig/ui/querydeleteobjectdialog \
+ svx/uiconfig/ui/querydeletethemedialog \
+ svx/uiconfig/ui/querymodifyimagemapchangesdialog \
+ svx/uiconfig/ui/querynewcontourdialog \
+ svx/uiconfig/ui/querysavecontchangesdialog \
+ svx/uiconfig/ui/querysaveimagemapchangesdialog \
+ svx/uiconfig/ui/queryunlinkgraphicsdialog \
+ svx/uiconfig/ui/redlinecontrol \
+ svx/uiconfig/ui/redlinefilterpage \
+ svx/uiconfig/ui/redlineviewpage \
+ svx/uiconfig/ui/rowsmenu \
+ svx/uiconfig/ui/rulermenu \
+ svx/uiconfig/ui/safemodedialog \
+ svx/uiconfig/ui/savemodifieddialog \
+ svx/uiconfig/ui/selectionmenu \
+ svx/uiconfig/ui/sidebararea \
+ svx/uiconfig/ui/sidebarempty \
+ svx/uiconfig/ui/sidebareffect \
+ svx/uiconfig/ui/sidebarfontwork \
+ svx/uiconfig/ui/sidebarshadow \
+ svx/uiconfig/ui/sidebargallery \
+ svx/uiconfig/ui/sidebargraphic \
+ svx/uiconfig/ui/sidebarline \
+ svx/uiconfig/ui/sidebarparagraph \
+ svx/uiconfig/ui/sidebarlists \
+ svx/uiconfig/ui/sidebarpossize \
+ svx/uiconfig/ui/sidebarstylespanel \
+ svx/uiconfig/ui/sidebartextcolumnspanel \
+ svx/uiconfig/ui/sidebartextpanel \
+ svx/uiconfig/ui/stylemenu \
+ svx/uiconfig/ui/surfacewindow \
+ svx/uiconfig/ui/tablewindow \
+ svx/uiconfig/ui/stylespreview \
+ svx/uiconfig/ui/textcharacterspacingcontrol \
+ svx/uiconfig/ui/textcontrolchardialog \
+ svx/uiconfig/ui/textcontrolparadialog \
+ svx/uiconfig/ui/textunderlinecontrol \
+ svx/uiconfig/ui/toolbarpopover \
+ svx/uiconfig/ui/xmlsecstatmenu \
+ svx/uiconfig/ui/xformspage \
+ svx/uiconfig/ui/zoommenu \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/UITest_svx_table.mk b/svx/UITest_svx_table.mk
new file mode 100644
index 000000000..df24798f5
--- /dev/null
+++ b/svx/UITest_svx_table.mk
@@ -0,0 +1,16 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_UITest_UITest,svx_table))
+
+$(eval $(call gb_UITest_add_modules,svx_table,$(SRCDIR)/svx/qa/uitest,\
+ table/ \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svx/doc/UML/edit_engine_UNO_implementation.zuml b/svx/doc/UML/edit_engine_UNO_implementation.zuml
new file mode 100644
index 000000000..d0faf5ade
--- /dev/null
+++ b/svx/doc/UML/edit_engine_UNO_implementation.zuml
@@ -0,0 +1 @@
+PK2l¼ \ No newline at end of file
diff --git a/svx/doc/UML/grid_control_implementation.zuml b/svx/doc/UML/grid_control_implementation.zuml
new file mode 100644
index 000000000..139cd3fd8
--- /dev/null
+++ b/svx/doc/UML/grid_control_implementation.zuml
Binary files differ
diff --git a/svx/doc/UML/readme.txt b/svx/doc/UML/readme.txt
new file mode 100644
index 000000000..7b9fc0a73
--- /dev/null
+++ b/svx/doc/UML/readme.txt
@@ -0,0 +1,9 @@
+This folder contains UML diagrams for certain implementations within this project.
+
+To view/edit them, you need "Poseidon for UML". The free community edition (which
+is completely sufficient for all documents herein) is available from
+http://www.gentleware.com/.
+
+It is probably also possible to open the documents with ArgoUML, the free open source
+UML tool which Poseidon for UML is based on. Visit http://argouml.tigris.org/ to
+obtain ArgoUML.
diff --git a/svx/doc/drawing_layer_UNO_objects.odg b/svx/doc/drawing_layer_UNO_objects.odg
new file mode 100644
index 000000000..69b0ceb44
--- /dev/null
+++ b/svx/doc/drawing_layer_UNO_objects.odg
Binary files differ
diff --git a/svx/inc/AccessibleTableShape.hxx b/svx/inc/AccessibleTableShape.hxx
new file mode 100644
index 000000000..16dcf4fe3
--- /dev/null
+++ b/svx/inc/AccessibleTableShape.hxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_ACCESSIBLETABLESHAPE_HXX
+#define INCLUDED_SVX_INC_ACCESSIBLETABLESHAPE_HXX
+
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+
+#include <rtl/ref.hxx>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <svx/AccessibleShape.hxx>
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+#include <com/sun/star/accessibility/XAccessibleTableSelection.hpp>
+
+namespace sdr::table { class SvxTableController; }
+
+namespace accessibility
+{
+ class AccessibleTableShapeImpl;
+ class AccessibleCell;
+
+ typedef ::cppu::ImplInheritanceHelper< AccessibleShape,
+ css::accessibility::XAccessibleTable,
+ css::view::XSelectionChangeListener
+ > AccessibleTableShape_Base;
+class AccessibleTableShape final : public AccessibleTableShape_Base, public css::accessibility::XAccessibleTableSelection
+{
+ sal_Int32 mnPreviousSelectionCount;
+public:
+ AccessibleTableShape( const AccessibleShapeInfo& rShapeInfo, const AccessibleShapeTreeInfo& rShapeTreeInfo );
+ virtual ~AccessibleTableShape( ) override;
+ AccessibleTableShape(const AccessibleTableShape&) = delete;
+ AccessibleTableShape& operator=(const AccessibleTableShape&) = delete;
+
+ virtual void Init() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire( ) noexcept override;
+ virtual void SAL_CALL release( ) noexcept override;
+
+ // XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole() override;
+
+ // XAccessibleTable
+ virtual sal_Int32 SAL_CALL getAccessibleRowCount() override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumnCount( ) override;
+ virtual OUString SAL_CALL getAccessibleRowDescription( sal_Int32 nRow ) override;
+ virtual OUString SAL_CALL getAccessibleColumnDescription( sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL getAccessibleRowHeaders( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL getAccessibleColumnHeaders( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getSelectedAccessibleRows( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getSelectedAccessibleColumns( ) override;
+ virtual sal_Bool SAL_CALL isAccessibleRowSelected( sal_Int32 nRow ) override;
+ virtual sal_Bool SAL_CALL isAccessibleColumnSelected( sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleCaption( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleSummary( ) override;
+ virtual sal_Bool SAL_CALL isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleRow( sal_Int32 nChildIndex ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumn( sal_Int32 nChildIndex ) override;
+
+ // XAccessibleSelection
+ virtual void SAL_CALL selectAccessibleChild( sal_Int32 nChildIndex ) override;
+ virtual sal_Bool SAL_CALL isAccessibleChildSelected( sal_Int32 nChildIndex ) override;
+ virtual void SAL_CALL clearAccessibleSelection( ) override;
+ virtual void SAL_CALL selectAllAccessibleChildren( ) override;
+ virtual sal_Int32 SAL_CALL getSelectedAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) override;
+ virtual void SAL_CALL deselectAccessibleChild( sal_Int32 nChildIndex ) override;
+ // XAccessibleTableSelection
+ virtual sal_Bool SAL_CALL selectRow( sal_Int32 row ) override ;
+ virtual sal_Bool SAL_CALL selectColumn( sal_Int32 column ) override ;
+ virtual sal_Bool SAL_CALL unselectRow( sal_Int32 row ) override ;
+ virtual sal_Bool SAL_CALL unselectColumn( sal_Int32 column ) override ;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ // XComponent
+ virtual void SAL_CALL disposing( ) override;
+
+ // XSelectionChangeListener
+ virtual void SAL_CALL
+ disposing (const css::lang::EventObject& Source) override;
+ virtual void SAL_CALL
+ selectionChanged (const css::lang::EventObject& rEvent) override;
+ using AccessibleShape::disposing;
+ friend class AccessibleTableHeaderShape;
+
+ /// @throws css::lang::IndexOutOfBoundsException
+ void getColumnAndRow( sal_Int32 nChildIndex, sal_Int32& rnColumn, sal_Int32& rnRow );
+ // overwrite the SetState & ResetState to do special operation for table cell's internal text
+ virtual bool SetState (sal_Int16 aState) override;
+ virtual bool ResetState (sal_Int16 aState) override;
+ // The following two methods are used to set state directly on table object, instead of the internal cell or paragraph.
+ bool SetStateDirectly (sal_Int16 aState);
+ bool ResetStateDirectly (sal_Int16 aState);
+ // Get the currently active cell which is text editing
+ AccessibleCell* GetActiveAccessibleCell();
+
+private:
+ virtual OUString CreateAccessibleBaseName() override;
+
+ sdr::table::SvxTableController* getTableController();
+
+ /// @throws css::lang::IndexOutOfBoundsException
+ void checkCellPosition( sal_Int32 nCol, sal_Int32 nRow );
+
+ rtl::Reference< AccessibleTableShapeImpl > mxImpl;
+ sal_Int32 GetIndexOfSelectedChild( sal_Int32 nSelectedChildIndex ) const;
+};
+
+typedef ::cppu::WeakImplHelper<
+ css::accessibility::XAccessible,
+ css::accessibility::XAccessibleComponent,
+ css::accessibility::XAccessibleContext,
+ css::accessibility::XAccessibleTable,
+ css::accessibility::XAccessibleTableSelection >
+ AccessibleTableHeaderShape_BASE;
+
+class AccessibleTableHeaderShape final : public cppu::BaseMutex,
+ public AccessibleTableHeaderShape_BASE
+{
+public:
+ // bRow, true means rowheader, false means columnheader
+ AccessibleTableHeaderShape( AccessibleTableShape* pTable, bool bRow );
+ virtual ~AccessibleTableHeaderShape() override;
+ AccessibleTableHeaderShape(const AccessibleTableHeaderShape&) = delete;
+ AccessibleTableHeaderShape& operator=(const AccessibleTableHeaderShape&) = delete;
+
+ // XAccessible
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext> SAL_CALL getAccessibleContext( ) override;
+
+ // XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+ virtual css::lang::Locale SAL_CALL getLocale( ) override;
+
+ //XAccessibleComponent
+ virtual sal_Bool SAL_CALL containsPoint( const css::awt::Point& aPoint ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+ virtual css::awt::Rectangle SAL_CALL getBounds( ) override;
+ virtual css::awt::Point SAL_CALL getLocation( ) override;
+ virtual css::awt::Point SAL_CALL getLocationOnScreen( ) override;
+ virtual css::awt::Size SAL_CALL getSize( ) override;
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+ virtual void SAL_CALL grabFocus( ) override;
+
+ // XAccessibleTable
+ virtual sal_Int32 SAL_CALL getAccessibleRowCount() override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumnCount( ) override;
+ virtual OUString SAL_CALL getAccessibleRowDescription( sal_Int32 nRow ) override;
+ virtual OUString SAL_CALL getAccessibleColumnDescription( sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL getAccessibleRowHeaders( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL getAccessibleColumnHeaders( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getSelectedAccessibleRows( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getSelectedAccessibleColumns( ) override;
+ virtual sal_Bool SAL_CALL isAccessibleRowSelected( sal_Int32 nRow ) override;
+ virtual sal_Bool SAL_CALL isAccessibleColumnSelected( sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleCaption( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleSummary( ) override;
+ virtual sal_Bool SAL_CALL isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleRow( sal_Int32 nChildIndex ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumn( sal_Int32 nChildIndex ) override;
+
+ // XAccessibleTableSelection
+ virtual sal_Bool SAL_CALL selectRow( sal_Int32 row ) override ;
+ virtual sal_Bool SAL_CALL selectColumn( sal_Int32 column ) override ;
+ virtual sal_Bool SAL_CALL unselectRow( sal_Int32 row ) override ;
+ virtual sal_Bool SAL_CALL unselectColumn( sal_Int32 column ) override ;
+private:
+ bool mbRow;
+ rtl::Reference< AccessibleTableShape > mpTable;
+};
+
+} // end of namespace accessibility
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/AffineMatrixItem.hxx b/svx/inc/AffineMatrixItem.hxx
new file mode 100644
index 000000000..c7eb5cb71
--- /dev/null
+++ b/svx/inc/AffineMatrixItem.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/geometry/AffineMatrix2D.hpp>
+#include <sal/types.h>
+#include <svl/poolitem.hxx>
+
+class SfxItemPool;
+
+class AffineMatrixItem final : public SfxPoolItem
+{
+private:
+ css::geometry::AffineMatrix2D maMatrix;
+
+public:
+ AffineMatrixItem(const css::geometry::AffineMatrix2D* pMatrix);
+ AffineMatrixItem(const AffineMatrixItem&);
+ virtual ~AffineMatrixItem() override;
+
+ virtual bool operator==(const SfxPoolItem&) const override;
+ virtual AffineMatrixItem* Clone(SfxItemPool* pPool = nullptr) const override;
+
+ virtual bool QueryValue(css::uno::Any& rVal, sal_uInt8 nMemberId = 0) const override;
+ virtual bool PutValue(const css::uno::Any& rVal, sal_uInt8 nMemberId) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/CommonStylePreviewRenderer.hxx b/svx/inc/CommonStylePreviewRenderer.hxx
new file mode 100644
index 000000000..b613f489f
--- /dev/null
+++ b/svx/inc/CommonStylePreviewRenderer.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include <editeng/svxfont.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/StylePreviewRenderer.hxx>
+#include <rtl/ustring.hxx>
+#include <tools/color.hxx>
+#include <tools/gen.hxx>
+
+class OutputDevice;
+class SfxStyleSheetBase;
+
+namespace svx
+{
+class CommonStylePreviewRenderer final : public sfx2::StylePreviewRenderer
+{
+ std::optional<SvxFont> m_oFont;
+ Color maFontColor;
+ Color maHighlightColor;
+ Color maBackgroundColor;
+ Size maPixelSize;
+ OUString maStyleName;
+
+ Size getRenderSize() const;
+
+public:
+ CommonStylePreviewRenderer(const SfxObjectShell& rShell, OutputDevice& rOutputDev,
+ SfxStyleSheetBase* pStyle, tools::Long nMaxHeight);
+ virtual ~CommonStylePreviewRenderer() override;
+
+ virtual bool recalculate() override;
+ virtual bool render(const tools::Rectangle& aRectangle,
+ RenderAlign eRenderAlign = RenderAlign::CENTER) override;
+};
+
+} // end namespace svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/DescriptionGenerator.hxx b/svx/inc/DescriptionGenerator.hxx
new file mode 100644
index 000000000..b696cc33e
--- /dev/null
+++ b/svx/inc/DescriptionGenerator.hxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace com::sun::star::beans
+{
+class XPropertySet;
+}
+namespace com::sun::star::drawing
+{
+class XShape;
+}
+
+namespace accessibility
+{
+/** This class creates description strings for shapes.
+ <p>Initialized with a given shape additional calls to the
+ <member>addProperty</member> method will build a descriptive string that
+ starts with a general shape description and the shapes style. Appended
+ are all the specified property names and values that differ from the
+ default values in the style.</p>
+*/
+class DescriptionGenerator
+{
+public:
+ enum class PropertyType
+ {
+ Color,
+ Integer
+ };
+
+ /** Creates a new description generator with an empty description
+ string. Usually you will want to call initialize next to specify
+ a general description of the shape.
+ @param xShape
+ The shape from which properties will be extracted by later calls
+ to <member>addProperty</member>.
+ */
+ DescriptionGenerator(const css::uno::Reference<css::drawing::XShape>& xShape);
+
+ ~DescriptionGenerator();
+
+ /** Initialize the description with the given prefix followed by the
+ shape style in parentheses and a colon.
+ @param sPrefix
+ An introductory description of the shape that is made more
+ specific by later calls to <member>addProperty</member>.
+ */
+ void Initialize(std::u16string_view sPrefix);
+
+ /** Initialize the description with the specified string from the
+ resource followed by the shape style in parentheses and a colon.
+ @param pResourceId
+ A resource id the specifies the introductory description of the
+ shape that is made more specific by later calls to
+ <member>addProperty</member>.
+ */
+ void Initialize(TranslateId pResourceId);
+
+ /** Returns the description string and then resets it. Usually called
+ as last method before destroying the object.
+ @return
+ The description string in its current form.
+ */
+ OUString operator()(void);
+
+ /** Add the given property name and its associated value to the
+ description string. If the property value does not differ from the
+ default value of the shape's style then the description string is
+ not modified.
+ @param sPropertyName
+ The Name of the property to append.
+ @param aType
+ Type of the property's value. It controls the transformation
+ into the value's string representation.
+ @param sLocalizedName
+ Localized name of the property. An empty string tells the
+ method to use the property name instead.
+ */
+ void AddProperty(const OUString& sPropertyName, PropertyType aType);
+
+ /** Append the given string as is to the current description.
+ @param sString
+ String to append to the current description. It is not modified
+ in any way.
+ */
+ void AppendString(std::u16string_view sString);
+
+private:
+ /// Reference to the shape from which the properties are extracted.
+ css::uno::Reference<css::drawing::XShape> mxShape;
+
+ /// Reference to the shape's property set.
+ css::uno::Reference<css::beans::XPropertySet> mxSet;
+
+ /// The description string that is build.
+ OUStringBuffer msDescription;
+
+ /** This flag is used to determine whether to insert a separator e.g. a
+ comma before the next property.
+ */
+ bool mbIsFirstProperty;
+
+ /** Add a property value formatted as color to the description string.
+ */
+ void AddColor(const OUString& sPropertyName);
+
+ /** Add a property value formatted as integer to the description string.
+ */
+ void AddInteger(const OUString& sPropertyName);
+};
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/GalleryControl.hxx b/svx/inc/GalleryControl.hxx
new file mode 100644
index 000000000..d5835fb57
--- /dev/null
+++ b/svx/inc/GalleryControl.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_GALLERYCONTROL_HXX
+#define INCLUDED_SVX_INC_GALLERYCONTROL_HXX
+
+#include <config_options.h>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <svx/svxdllapi.h>
+
+class SfxBindings;
+
+class Gallery;
+class GalleryBrowser1;
+class GalleryBrowser2;
+class FmFormModel;
+class Splitter;
+
+namespace svx::sidebar
+{
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) GalleryControl final : public PanelLayout
+{
+public:
+ GalleryControl(weld::Widget* pParentWindow);
+ virtual ~GalleryControl() override;
+
+private:
+ Gallery* mpGallery;
+ std::unique_ptr<GalleryBrowser1> mxBrowser1;
+ std::unique_ptr<GalleryBrowser2> mxBrowser2;
+};
+
+} // end of namespace svx::sidebar
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/ParaLineSpacingPopup.hxx b/svx/inc/ParaLineSpacingPopup.hxx
new file mode 100644
index 000000000..0b042f44b
--- /dev/null
+++ b/svx/inc/ParaLineSpacingPopup.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svtools/popupwindowcontroller.hxx>
+
+namespace svx
+{
+class SvxLineSpacingToolBoxControl final : public svt::PopupWindowController
+{
+public:
+ explicit SvxLineSpacingToolBoxControl(
+ const css::uno::Reference<css::uno::XComponentContext>& rContext);
+ virtual ~SvxLineSpacingToolBoxControl() override;
+
+ virtual void SAL_CALL execute(sal_Int16 KeyModifier) override;
+
+ virtual VclPtr<vcl::Window> createVclPopupWindow(vcl::Window* pParent) override;
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/TextCharacterSpacingPopup.hxx b/svx/inc/TextCharacterSpacingPopup.hxx
new file mode 100644
index 000000000..bb1092c82
--- /dev/null
+++ b/svx/inc/TextCharacterSpacingPopup.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svtools/popupwindowcontroller.hxx>
+
+namespace svx
+{
+class TextCharacterSpacingPopup final : public svt::PopupWindowController
+{
+public:
+ TextCharacterSpacingPopup(const css::uno::Reference<css::uno::XComponentContext>& rContext);
+ virtual ~TextCharacterSpacingPopup() override;
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow(vcl::Window* pParent) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override;
+};
+
+} // end of namespace svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/TextUnderlinePopup.hxx b/svx/inc/TextUnderlinePopup.hxx
new file mode 100644
index 000000000..973f50c53
--- /dev/null
+++ b/svx/inc/TextUnderlinePopup.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svtools/popupwindowcontroller.hxx>
+
+namespace svx
+{
+class TextUnderlinePopup final : public svt::PopupWindowController
+{
+public:
+ TextUnderlinePopup(const css::uno::Reference<css::uno::XComponentContext>& rContext);
+ virtual ~TextUnderlinePopup() override;
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow(vcl::Window* pParent) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override;
+};
+
+} // end of namespace svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/XPropertyTable.hxx b/svx/inc/XPropertyTable.hxx
new file mode 100644
index 000000000..e9f76965e
--- /dev/null
+++ b/svx/inc/XPropertyTable.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <svx/xtable.hxx>
+
+// FIXME: should have a single factory method with an enumeration here [!]
+
+css::uno::Reference< css::container::XNameContainer > SvxUnoXColorTable_createInstance( XPropertyList& rList ) noexcept;
+css::uno::Reference< css::container::XNameContainer > SvxUnoXLineEndTable_createInstance( XPropertyList& rList ) noexcept;
+css::uno::Reference< css::container::XNameContainer > SvxUnoXDashTable_createInstance( XPropertyList& rList ) noexcept;
+css::uno::Reference< css::container::XNameContainer > SvxUnoXHatchTable_createInstance( XPropertyList& rList ) noexcept;
+css::uno::Reference< css::container::XNameContainer > SvxUnoXGradientTable_createInstance( XPropertyList& rList ) noexcept;
+css::uno::Reference< css::container::XNameContainer > SvxUnoXBitmapTable_createInstance( XPropertyList& rList ) noexcept;
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/bitmaps.hlst b/svx/inc/bitmaps.hlst
new file mode 100644
index 000000000..4b2fcf0ce
--- /dev/null
+++ b/svx/inc/bitmaps.hlst
@@ -0,0 +1,288 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+inline constexpr OUStringLiteral RID_SVXCTRL_RECTBTNS = u"svx/res/rectbtns.png";
+
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW1 = u"svx/res/frmsel1.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW2 = u"svx/res/frmsel2.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW3 = u"svx/res/frmsel3.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW4 = u"svx/res/frmsel4.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW5 = u"svx/res/frmsel5.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW6 = u"svx/res/frmsel6.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW7 = u"svx/res/frmsel7.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW8 = u"svx/res/frmsel8.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW9 = u"svx/res/frmsel9.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW10 = u"svx/res/frmsel10.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW11 = u"svx/res/frmsel11.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW12 = u"svx/res/frmsel12.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW13 = u"svx/res/frmsel13.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW14 = u"svx/res/frmsel14.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW15 = u"svx/res/frmsel15.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRMSEL_ARROW16 = u"svx/res/frmsel16.png";
+
+inline constexpr OUStringLiteral RID_SVXBMP_NOTCHECKED = u"svx/res/notcheck.png";
+inline constexpr OUStringLiteral RID_SVXBMP_CHECKED = u"svx/res/lngcheck.png";
+
+inline constexpr OUStringLiteral RID_SVXBMP_GREENCHECK = u"svx/res/nu01.png";
+inline constexpr OUStringLiteral RID_SVXBMP_YELLOWCHECK = u"svx/res/nu04.png";
+inline constexpr OUStringLiteral RID_SVXBMP_REDCROSS = u"svx/res/nu02.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SHADOW_ANGLE = u"svx/res/fw018.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SHADOW_SIZE = u"svx/res/fw019.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SHADOW_XDIST = u"svx/res/fw016.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SHADOW_YDIST = u"svx/res/fw017.png";
+
+inline constexpr OUStringLiteral RID_SVXBMP_DIRECTION_DIRECTION_NW = u"svx/res/directionnorthwest_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DIRECTION_DIRECTION_N = u"svx/res/directionnorth_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DIRECTION_DIRECTION_NE = u"svx/res/directionnortheast_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DIRECTION_DIRECTION_W = u"svx/res/directionwest_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DIRECTION_DIRECTION_NONE = u"svx/res/directionstraight_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DIRECTION_DIRECTION_E = u"svx/res/directioneast_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DIRECTION_DIRECTION_SW = u"svx/res/directionsouthwest_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DIRECTION_DIRECTION_S = u"svx/res/directionsouth_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DIRECTION_DIRECTION_SE = u"svx/res/directionsoutheast_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_OFF_FROM_TOP_LEFT = u"svx/res/lightofffromtopleft_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_OFF_FROM_TOP = u"svx/res/lightofffromtop_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_OFF_FROM_TOP_RIGHT = u"svx/res/lightofffromtopright_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_OFF_FROM_LEFT = u"svx/res/lightofffromleft_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_OFF_FROM_RIGHT = u"svx/res/lightofffromright_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_OFF_FROM_BOTTOM_LEFT = u"svx/res/lightofffrombottomleft_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_OFF_FROM_BOTTOM = u"svx/res/lightofffrombottom_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_OFF_FROM_BOTTOM_RIGHT = u"svx/res/lightofffrombottomright_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_ON_FROM_TOP_LEFT = u"svx/res/lightonfromtopleft_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_ON_FROM_TOP = u"svx/res/lightonfromtop_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_ON_FROM_TOP_RIGHT = u"svx/res/lightonfromtopright_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_ON_FROM_LEFT = u"svx/res/lightonfromleft_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_ON_FROM_RIGHT = u"svx/res/lightonfromright_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_ON_FROM_BOTTOM_LEFT = u"svx/res/lightonfrombottomleft_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_ON_FROM_BOTTOM = u"svx/res/lightonfrombottom_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_ON_FROM_BOTTOM_RIGHT = u"svx/res/lightonfrombottomright_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_PREVIEW_FROM_TOP_LEFT = u"svx/res/lightfromtopleft_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_PREVIEW_FROM_TOP = u"svx/res/lightfromtop_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_PREVIEW_FROM_TOP_RIGHT = u"svx/res/lightfromtopright_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_PREVIEW_FROM_LEFT = u"svx/res/lightfromleft_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_PREVIEW_FROM_RIGHT = u"svx/res/lightfromright_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_PREVIEW_FROM_FRONT = u"svx/res/lightfromfront_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_PREVIEW_FROM_BOTTOM_LEFT = u"svx/res/lightfrombottomleft_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_PREVIEW_FROM_BOTTOM = u"svx/res/lightfrombottom_22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LIGHT_PREVIEW_FROM_BOTTOM_RIGHT = u"svx/res/lightfrombottomright_22.png";
+
+inline constexpr OUStringLiteral RID_SVXBMP_LAMP_ON = u"svx/res/lighton.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LAMP_OFF = u"svx/res/light.png";
+
+inline constexpr OUStringLiteral RID_SVXBMP_ELEMENT = u"res/da03.png";
+inline constexpr OUStringLiteral RID_SVXBMP_ATTRIBUTE = u"res/da04.png";
+inline constexpr OUStringLiteral RID_SVXBMP_TEXT = u"res/da05.png";
+inline constexpr OUStringLiteral RID_SVXBMP_OTHER = u"res/da06.png";
+
+inline constexpr OUStringLiteral RID_SVXBMP_FORM = u"res/sx10593.png";
+inline constexpr OUStringLiteral RID_SVXBMP_CONTROL = u"res/sx10144.png";
+inline constexpr OUStringLiteral RID_SVXBMP_BUTTON = u"res/sx10594.png";
+inline constexpr OUStringLiteral RID_SVXBMP_RADIOBUTTON = u"res/sx10595.png";
+inline constexpr OUStringLiteral RID_SVXBMP_CHECKBOX = u"res/sx10596.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FIXEDTEXT = u"res/sx10597.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GROUPBOX = u"res/sx10598.png";
+inline constexpr OUStringLiteral RID_SVXBMP_EDITBOX = u"res/sx10599.png";
+inline constexpr OUStringLiteral RID_SVXBMP_LISTBOX = u"res/sx10600.png";
+inline constexpr OUStringLiteral RID_SVXBMP_COMBOBOX = u"res/sx10601.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FORMS = u"res/sx18013.png";
+inline constexpr OUStringLiteral RID_SVXBMP_IMAGEBUTTON = u"res/sx10604.png";
+inline constexpr OUStringLiteral RID_SVXBMP_IMAGECONTROL = u"res/sx10710.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FILECONTROL = u"res/sx10605.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DATEFIELD = u"res/sx10704.png";
+inline constexpr OUStringLiteral RID_SVXBMP_TIMEFIELD = u"res/sx10705.png";
+inline constexpr OUStringLiteral RID_SVXBMP_NUMERICFIELD = u"res/sx10706.png";
+inline constexpr OUStringLiteral RID_SVXBMP_CURRENCYFIELD = u"res/sx10707.png";
+inline constexpr OUStringLiteral RID_SVXBMP_PATTERNFIELD = u"res/sx10708.png";
+inline constexpr OUStringLiteral RID_SVXBMP_HIDDEN = u"res/sx18022.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GRID = u"res/sx10603.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FORMATTEDFIELD = u"res/sx10728.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FILTER = u"res/sx10715.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DATE_N_TIME_FIELDS = u"res/sx10757.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FIELD = u"res/sx18027.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SCROLLBAR = u"res/sx10768.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SPINBUTTON = u"res/sx10769.png";
+inline constexpr OUStringLiteral RID_SVXBMP_NAVIGATIONBAR = u"res/sx10607.png";
+
+inline constexpr OUStringLiteral RID_SVXBMP_THEME_NORMAL = u"svx/res/galnors.png";
+inline constexpr OUStringLiteral RID_SVXBMP_THEME_READONLY = u"svx/res/galrdos.png";
+inline constexpr OUStringLiteral RID_SVXBMP_THEME_DEFAULT = u"svx/res/galdefs.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GALLERY_MEDIA = u"svx/res/galmedia.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GALLERY_SOUND_1 = u"svx/res/galsnd1.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GALLERY_SOUND_2 = u"svx/res/galsnd2.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GALLERY_SOUND_3 = u"svx/res/galsnd3.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GALLERY_SOUND_4 = u"svx/res/galsnd4.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GALLERY_SOUND_5 = u"svx/res/galsnd5.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GALLERY_SOUND_6 = u"svx/res/galsnd6.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GALLERY_SOUND_7 = u"svx/res/galsnd7.png";
+
+inline constexpr OUStringLiteral BMP_NONE_ICON = u"svx/res/symphony/blank.png";
+inline constexpr OUStringLiteral BMP_WIDTH1_ICON = u"svx/res/symphony/width1.png";
+inline constexpr OUStringLiteral BMP_WIDTH2_ICON = u"svx/res/symphony/width2.png";
+inline constexpr OUStringLiteral BMP_WIDTH3_ICON = u"svx/res/symphony/width3.png";
+inline constexpr OUStringLiteral BMP_WIDTH4_ICON = u"svx/res/symphony/width4.png";
+inline constexpr OUStringLiteral BMP_WIDTH5_ICON = u"svx/res/symphony/width5.png";
+inline constexpr OUStringLiteral BMP_WIDTH6_ICON = u"svx/res/symphony/width6.png";
+inline constexpr OUStringLiteral BMP_WIDTH7_ICON = u"svx/res/symphony/width7.png";
+inline constexpr OUStringLiteral BMP_WIDTH8_ICON = u"svx/res/symphony/width8.png";
+inline constexpr OUStringLiteral RID_SVXBMP_WIDTH_CUSTOM = u"svx/res/symphony/last_custom_common.png";
+inline constexpr OUStringLiteral RID_SVXBMP_WIDTH_CUSTOM_GRAY = u"svx/res/symphony/last_custom_common_grey.png";
+
+inline constexpr OUStringLiteral BMP_AXIAL = u"svx/res/symphony/axial.png";
+inline constexpr OUStringLiteral BMP_ELLI = u"svx/res/symphony/ellipsoid.png";
+inline constexpr OUStringLiteral BMP_QUAD = u"svx/res/symphony/Quadratic.png";
+inline constexpr OUStringLiteral BMP_RADIAL = u"svx/res/symphony/radial.png";
+inline constexpr OUStringLiteral BMP_SQUARE = u"svx/res/symphony/Square.png";
+inline constexpr OUStringLiteral BMP_LINEAR = u"svx/res/symphony/linear.png";
+
+inline constexpr OUStringLiteral RID_SVXBMP_STANDARD_SELECTION = u"svx/res/standard-selection_10x22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_EXTENDING_SELECTION = u"svx/res/extending-selection_10x22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_ADDING_SELECTION = u"svx/res/adding-selection_10x22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_BLOCK_SELECTION = u"svx/res/block-selection_10x22.png";
+inline constexpr OUStringLiteral RID_SVXBMP_POSITION = u"res/sc10223.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SIZE = u"res/sc10224.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SIGNET = u"svx/res/signet_11x16.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SIGNET_BROKEN = u"svx/res/caution_11x16.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SIGNET_NOTVALIDATED = u"svx/res/notcertificate_16.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SLIDERBUTTON = u"svx/res/slidezoombutton_10.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SLIDERDECREASE = u"svx/res/slidezoomout_10.png";
+inline constexpr OUStringLiteral RID_SVXBMP_SLIDERINCREASE = u"svx/res/slidezoomin_10.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DOC_MODIFIED_YES = u"svx/res/doc_modified_yes_14.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DOC_MODIFIED_NO = u"svx/res/doc_modified_no_14.png";
+inline constexpr OUStringLiteral RID_SVXBMP_DOC_MODIFIED_FEEDBACK = u"svx/res/doc_modified_feedback.png";
+inline constexpr OUStringLiteral RID_SVXBMP_ZOOM_PAGE = u"svx/res/zoom_page_statusbar.png";
+
+inline constexpr OUStringLiteral BMAP_GrafikEi = u"res/grafikei.png";
+inline constexpr OUStringLiteral SIP_SA_PAGESHADOW35X35 = u"svx/res/pageshadow35x35.png";
+inline constexpr OUStringLiteral SIP_SA_MARKERS = u"svx/res/markers.png";
+inline constexpr OUStringLiteral BMP_SVXOLEOBJ = u"res/oleobj.png";
+inline constexpr OUStringLiteral SIP_SA_CROP_MARKERS = u"svx/res/cropmarkers.png";
+#define BMP_MARKER_ANCHOR "svx/res/marker-anchor.png"
+#define BMP_MARKER_ANCHOR_PRESSED "svx/res/marker-anchor-pressed.png"
+#define BMP_MARKER_CIRC7_1 "svx/res/marker-circ7-1.png"
+#define BMP_MARKER_CIRC7_2 "svx/res/marker-circ7-2.png"
+#define BMP_MARKER_CIRC7_3 "svx/res/marker-circ7-3.png"
+#define BMP_MARKER_CIRC7_4 "svx/res/marker-circ7-4.png"
+#define BMP_MARKER_CIRC7_5 "svx/res/marker-circ7-5.png"
+#define BMP_MARKER_CIRC7_6 "svx/res/marker-circ7-6.png"
+#define BMP_MARKER_CIRC9_1 "svx/res/marker-circ9-1.png"
+#define BMP_MARKER_CIRC9_2 "svx/res/marker-circ9-2.png"
+#define BMP_MARKER_CIRC9_3 "svx/res/marker-circ9-3.png"
+#define BMP_MARKER_CIRC9_4 "svx/res/marker-circ9-4.png"
+#define BMP_MARKER_CIRC9_5 "svx/res/marker-circ9-5.png"
+#define BMP_MARKER_CIRC9_6 "svx/res/marker-circ9-6.png"
+#define BMP_MARKER_CIRC11_1 "svx/res/marker-circ11-1.png"
+#define BMP_MARKER_CIRC11_2 "svx/res/marker-circ11-2.png"
+#define BMP_MARKER_CIRC11_3 "svx/res/marker-circ11-3.png"
+#define BMP_MARKER_CIRC11_4 "svx/res/marker-circ11-4.png"
+#define BMP_MARKER_CIRC11_5 "svx/res/marker-circ11-5.png"
+#define BMP_MARKER_CIRC11_6 "svx/res/marker-circ11-6.png"
+#define BMP_MARKER_CROSS "svx/res/marker-cross.png"
+#define BMP_MARKER_ELLI7x9_1 "svx/res/marker-elli7x9-1.png"
+#define BMP_MARKER_ELLI7x9_2 "svx/res/marker-elli7x9-2.png"
+#define BMP_MARKER_ELLI7x9_3 "svx/res/marker-elli7x9-3.png"
+#define BMP_MARKER_ELLI7x9_4 "svx/res/marker-elli7x9-4.png"
+#define BMP_MARKER_ELLI7x9_5 "svx/res/marker-elli7x9-5.png"
+#define BMP_MARKER_ELLI7x9_6 "svx/res/marker-elli7x9-6.png"
+#define BMP_MARKER_ELLI9x7_1 "svx/res/marker-elli9x7-1.png"
+#define BMP_MARKER_ELLI9x7_2 "svx/res/marker-elli9x7-2.png"
+#define BMP_MARKER_ELLI9x7_3 "svx/res/marker-elli9x7-3.png"
+#define BMP_MARKER_ELLI9x7_4 "svx/res/marker-elli9x7-4.png"
+#define BMP_MARKER_ELLI9x7_5 "svx/res/marker-elli9x7-5.png"
+#define BMP_MARKER_ELLI9x7_6 "svx/res/marker-elli9x7-6.png"
+#define BMP_MARKER_ELLI9x11_1 "svx/res/marker-elli9x11-1.png"
+#define BMP_MARKER_ELLI9x11_2 "svx/res/marker-elli9x11-2.png"
+#define BMP_MARKER_ELLI9x11_3 "svx/res/marker-elli9x11-3.png"
+#define BMP_MARKER_ELLI9x11_4 "svx/res/marker-elli9x11-4.png"
+#define BMP_MARKER_ELLI9x11_5 "svx/res/marker-elli9x11-5.png"
+#define BMP_MARKER_ELLI9x11_6 "svx/res/marker-elli9x11-6.png"
+#define BMP_MARKER_ELLI11x9_1 "svx/res/marker-elli11x9-1.png"
+#define BMP_MARKER_ELLI11x9_2 "svx/res/marker-elli11x9-2.png"
+#define BMP_MARKER_ELLI11x9_3 "svx/res/marker-elli11x9-3.png"
+#define BMP_MARKER_ELLI11x9_4 "svx/res/marker-elli11x9-4.png"
+#define BMP_MARKER_ELLI11x9_5 "svx/res/marker-elli11x9-5.png"
+#define BMP_MARKER_ELLI11x9_6 "svx/res/marker-elli11x9-6.png"
+#define BMP_MARKER_GLUE_SELECTED "svx/res/marker-glue-selected.png"
+#define BMP_MARKER_GLUE_UNSELECTED "svx/res/marker-glue-unselected.png"
+#define BMP_MARKER_RECT7_1 "svx/res/marker-rect7-1.png"
+#define BMP_MARKER_RECT7_2 "svx/res/marker-rect7-2.png"
+#define BMP_MARKER_RECT7_3 "svx/res/marker-rect7-3.png"
+#define BMP_MARKER_RECT7_4 "svx/res/marker-rect7-4.png"
+#define BMP_MARKER_RECT7_5 "svx/res/marker-rect7-5.png"
+#define BMP_MARKER_RECT7_6 "svx/res/marker-rect7-6.png"
+#define BMP_MARKER_RECT9_1 "svx/res/marker-rect9-1.png"
+#define BMP_MARKER_RECT9_2 "svx/res/marker-rect9-2.png"
+#define BMP_MARKER_RECT9_3 "svx/res/marker-rect9-3.png"
+#define BMP_MARKER_RECT9_4 "svx/res/marker-rect9-4.png"
+#define BMP_MARKER_RECT9_5 "svx/res/marker-rect9-5.png"
+#define BMP_MARKER_RECT9_6 "svx/res/marker-rect9-6.png"
+#define BMP_MARKER_RECT11_1 "svx/res/marker-rect11-1.png"
+#define BMP_MARKER_RECT11_2 "svx/res/marker-rect11-2.png"
+#define BMP_MARKER_RECT11_3 "svx/res/marker-rect11-3.png"
+#define BMP_MARKER_RECT11_4 "svx/res/marker-rect11-4.png"
+#define BMP_MARKER_RECT11_5 "svx/res/marker-rect11-5.png"
+#define BMP_MARKER_RECT11_6 "svx/res/marker-rect11-6.png"
+#define BMP_MARKER_RECT13_1 "svx/res/marker-rect13-1.png"
+#define BMP_MARKER_RECT13_2 "svx/res/marker-rect13-2.png"
+#define BMP_MARKER_RECT13_3 "svx/res/marker-rect13-3.png"
+#define BMP_MARKER_RECT13_4 "svx/res/marker-rect13-4.png"
+#define BMP_MARKER_RECT13_5 "svx/res/marker-rect13-5.png"
+#define BMP_MARKER_RECT13_6 "svx/res/marker-rect13-6.png"
+#define BMP_MARKER_RECTPLUS7_1 "svx/res/marker-rectplus7-1.png"
+#define BMP_MARKER_RECTPLUS7_2 "svx/res/marker-rectplus7-2.png"
+#define BMP_MARKER_RECTPLUS7_3 "svx/res/marker-rectplus7-3.png"
+#define BMP_MARKER_RECTPLUS7_4 "svx/res/marker-rectplus7-4.png"
+#define BMP_MARKER_RECTPLUS7_5 "svx/res/marker-rectplus7-5.png"
+#define BMP_MARKER_RECTPLUS7_6 "svx/res/marker-rectplus7-6.png"
+#define BMP_MARKER_RECTPLUS9_1 "svx/res/marker-rectplus9-1.png"
+#define BMP_MARKER_RECTPLUS9_2 "svx/res/marker-rectplus9-2.png"
+#define BMP_MARKER_RECTPLUS9_3 "svx/res/marker-rectplus9-3.png"
+#define BMP_MARKER_RECTPLUS9_4 "svx/res/marker-rectplus9-4.png"
+#define BMP_MARKER_RECTPLUS9_5 "svx/res/marker-rectplus9-5.png"
+#define BMP_MARKER_RECTPLUS9_6 "svx/res/marker-rectplus9-6.png"
+#define BMP_MARKER_RECTPLUS11_1 "svx/res/marker-rectplus11-1.png"
+#define BMP_MARKER_RECTPLUS11_2 "svx/res/marker-rectplus11-2.png"
+#define BMP_MARKER_RECTPLUS11_3 "svx/res/marker-rectplus11-3.png"
+#define BMP_MARKER_RECTPLUS11_4 "svx/res/marker-rectplus11-4.png"
+#define BMP_MARKER_RECTPLUS11_5 "svx/res/marker-rectplus11-5.png"
+#define BMP_MARKER_RECTPLUS11_6 "svx/res/marker-rectplus11-6.png"
+
+/*
+ * Bitmaps for SvxFrameWindow
+ */
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME1 = u"svx/res/fr01.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME2 = u"svx/res/fr02.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME3 = u"svx/res/fr03.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME4 = u"svx/res/fr04.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME5 = u"svx/res/fr05.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME6 = u"svx/res/fr06.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME7 = u"svx/res/fr07.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME8 = u"svx/res/fr08.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME9 = u"svx/res/fr09.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME10 = u"svx/res/fr010.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME11 = u"svx/res/fr011.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME12 = u"svx/res/fr012.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME13 = u"svx/res/fr013.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME14 = u"svx/res/fr014.png";
+inline constexpr OUStringLiteral RID_SVXBMP_FRAME15 = u"svx/res/fr015.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GRAF_RED = u"res/sc10865.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GRAF_GREEN = u"res/sc10866.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GRAF_BLUE = u"res/sc10867.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GRAF_LUMINANCE = u"res/sc10863.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GRAF_CONTRAST = u"res/sc10864.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GRAF_GAMMA = u"res/sc10868.png";
+inline constexpr OUStringLiteral RID_SVXBMP_GRAF_TRANSPARENCE = u"res/sc10869.png";
+
+inline constexpr OUStringLiteral RID_UNODRAW_OBJECTS = u"svx/res/objects.png";
+inline constexpr OUStringLiteral RID_UNODRAW_OLE2 = u"svx/res/ole.png";
+inline constexpr OUStringLiteral RID_UNODRAW_GRAPHICS = u"svx/res/graphic.png";
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/inc/colrctrl.hxx b/svx/inc/colrctrl.hxx
new file mode 100644
index 000000000..012f00855
--- /dev/null
+++ b/svx/inc/colrctrl.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/types.h>
+#include <sfx2/dockwin.hxx>
+#include <svl/lstner.hxx>
+#include <svx/SvxColorValueSet.hxx>
+#include <svx/xtable.hxx>
+#include <tools/gen.hxx>
+#include <tools/link.hxx>
+#include <vcl/vclptr.hxx>
+#include <com/sun/star/drawing/FillStyle.hpp>
+
+namespace vcl { class Window; }
+
+class SfxBindings;
+class SfxBroadcaster;
+class SfxChildWindow;
+class SfxHint;
+class SvxColorValueSetData;
+
+/*************************************************************************
+|*
+|* SvxColorValueSet_docking
+|*
+\************************************************************************/
+
+class SAL_WARN_UNUSED SvxColorValueSet_docking final : public SvxColorValueSet
+{
+ rtl::Reference<SvxColorValueSetData> m_xHelper;
+ bool mbLeftButton;
+
+ // ValueSet
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+ virtual bool StartDrag() override;
+
+public:
+ SvxColorValueSet_docking(std::unique_ptr<weld::ScrolledWindow> pWindow);
+
+ bool IsLeftButton() const { return mbLeftButton; }
+};
+
+/*************************************************************************
+|*
+|* SvxColorDockingWindow
+|*
+\************************************************************************/
+
+class SAL_WARN_UNUSED SvxColorDockingWindow final : public SfxDockingWindow, public SfxListener
+{
+friend class SvxColorChildWindow;
+
+private:
+ XColorListRef pColorList;
+ std::unique_ptr<SvxColorValueSet_docking> xColorSet;
+ std::unique_ptr<weld::CustomWeld> xColorSetWin;
+
+ void FillValueSet();
+
+ DECL_LINK(SelectHdl, ValueSet*, void);
+
+ /** This function is called when the window gets the focus. It grabs
+ the focus to the color value set so that it can be controlled with
+ the keyboard.
+ */
+ virtual void GetFocus() override;
+
+ virtual bool Close() override;
+
+public:
+ SvxColorDockingWindow(SfxBindings* pBindings,
+ SfxChildWindow *pCW,
+ vcl::Window* pParent);
+ virtual ~SvxColorDockingWindow() override;
+ virtual void dispose() override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual bool EventNotify( NotifyEvent& rNEvt ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/dbcharsethelper.hxx b/svx/inc/dbcharsethelper.hxx
new file mode 100644
index 000000000..8dfaf27ca
--- /dev/null
+++ b/svx/inc/dbcharsethelper.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/textenc.h>
+
+#include <vector>
+
+namespace svxform::charset_helper
+{
+/** enumerates all supported charsets
+ @return the number of charsets supported
+ */
+sal_Int32 getSupportedTextEncodings(::std::vector<rtl_TextEncoding>& _rEncs);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/dragmt3d.hxx b/svx/inc/dragmt3d.hxx
new file mode 100644
index 000000000..79402d0de
--- /dev/null
+++ b/svx/inc/dragmt3d.hxx
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_DRAGMT3D_HXX
+#define INCLUDED_SVX_INC_DRAGMT3D_HXX
+
+#include <svx/def3d.hxx>
+#include <svx/svddrgmt.hxx>
+#include <svx/view3d.hxx>
+#include <basegfx/polygon/b3dpolypolygon.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
+
+// Parameters for the interaction of a 3D object
+class E3dDragMethodUnit
+{
+public:
+ E3dObject& mr3DObj;
+ basegfx::B3DPolyPolygon maWireframePoly;
+ basegfx::B3DHomMatrix maDisplayTransform;
+ basegfx::B3DHomMatrix maInvDisplayTransform;
+ basegfx::B3DHomMatrix maInitTransform;
+ basegfx::B3DHomMatrix maTransform;
+ Degree100 mnStartAngle;
+ Degree100 mnLastAngle;
+
+ E3dDragMethodUnit(E3dObject& r3DObj)
+ : mr3DObj(r3DObj),
+ maWireframePoly(),
+ maDisplayTransform(),
+ maInvDisplayTransform(),
+ maInitTransform(),
+ maTransform(),
+ mnStartAngle(0),
+ mnLastAngle(0)
+ {
+ }
+};
+
+// Derivative of SdrDragMethod for 3D objects
+class E3dDragMethod : public SdrDragMethod
+{
+protected:
+ ::std::vector< E3dDragMethodUnit > maGrp;
+ E3dDragConstraint meConstraint;
+ Point maLastPos;
+ tools::Rectangle maFullBound;
+ bool mbMoveFull;
+ bool mbMovedAtAll;
+
+public:
+ E3dDragMethod(
+ SdrDragView &rView,
+ const SdrMarkList& rMark,
+ E3dDragConstraint eConstr,
+ bool bFull);
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual bool BeginSdrDrag() override;
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual void CancelSdrDrag() override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+
+ // for migration from XOR to overlay
+ virtual void CreateOverlayGeometry(
+ sdr::overlay::OverlayManager& rOverlayManager,
+ const sdr::contact::ObjectContact& rObjectContact) override;
+};
+
+// Derivative of SdrDragMethod for spinning 3D objects
+class E3dDragRotate final : public E3dDragMethod
+{
+ basegfx::B3DPoint maGlobalCenter;
+
+public:
+ E3dDragRotate(
+ SdrDragView &rView,
+ const SdrMarkList& rMark,
+ E3dDragConstraint eConstr,
+ bool bFull);
+
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+};
+
+// Derivative of SdrDragMethod for moving 3D sub-objects
+class E3dDragMove final : public E3dDragMethod
+{
+ SdrHdlKind meWhatDragHdl;
+ Point maScaleFixPos;
+
+public:
+ E3dDragMove(
+ SdrDragView &rView,
+ const SdrMarkList& rMark,
+ SdrHdlKind eDrgHdl,
+ E3dDragConstraint eConstr,
+ bool bFull);
+
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+};
+
+
+#endif // INCLUDED_SVX_INC_DRAGMT3D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/dstribut_enum.hxx b/svx/inc/dstribut_enum.hxx
new file mode 100644
index 000000000..98d962850
--- /dev/null
+++ b/svx/inc/dstribut_enum.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+enum class SvxDistributeHorizontal
+{
+ NONE = 0,
+ Left,
+ Center,
+ Distance,
+ Right
+};
+
+enum class SvxDistributeVertical
+{
+ NONE = 0,
+ Top,
+ Center,
+ Distance,
+ Bottom
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/extrud3d.hxx b/svx/inc/extrud3d.hxx
new file mode 100644
index 000000000..1b0e5a248
--- /dev/null
+++ b/svx/inc/extrud3d.hxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <config_options.h>
+#include <svl/intitem.hxx>
+#include <svl/itemset.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/svxdllapi.h>
+#include <svx/svddef.hxx>
+#include <svx/svx3ditems.hxx>
+
+class E3dDefaultAttributes;
+
+/*************************************************************************
+|*
+|* 3D extrusion object created from the provided 2D polygon
+|*
+\************************************************************************/
+
+class SAL_WARN_UNUSED UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) E3dExtrudeObj final : public E3dCompoundObject
+{
+private:
+ // to allow sdr::properties::E3dExtrudeProperties access to SetGeometryValid()
+ friend class sdr::properties::E3dExtrudeProperties;
+
+ // geometry, which determines the object
+ basegfx::B2DPolyPolygon maExtrudePolygon;
+
+ virtual std::unique_ptr<sdr::contact::ViewContact> CreateObjectSpecificViewContact() override;
+ virtual std::unique_ptr<sdr::properties::BaseProperties> CreateObjectSpecificProperties() override;
+ void SetDefaultAttributes(const E3dDefaultAttributes& rDefault);
+
+private:
+ // protected destructor - due to final, make private
+ virtual ~E3dExtrudeObj() override;
+
+public:
+ E3dExtrudeObj(
+ SdrModel& rSdrModel,
+ const E3dDefaultAttributes& rDefault,
+ const basegfx::B2DPolyPolygon& rPP,
+ double fDepth);
+ E3dExtrudeObj(SdrModel& rSdrModel, E3dExtrudeObj const & rSource);
+ E3dExtrudeObj(SdrModel& rSdrModel);
+
+ // PercentDiagonal: 0..100, before 0.0..0.5
+ sal_uInt16 GetPercentDiagonal() const
+ { return GetObjectItemSet().Get(SDRATTR_3DOBJ_PERCENT_DIAGONAL).GetValue(); }
+
+ // BackScale: 0..100, before 0.0..1.0
+ sal_uInt16 GetPercentBackScale() const
+ { return GetObjectItemSet().Get(SDRATTR_3DOBJ_BACKSCALE).GetValue(); }
+
+ // BackScale: 0..100, before 0.0..1.0
+ sal_uInt32 GetExtrudeDepth() const
+ { return GetObjectItemSet().Get(SDRATTR_3DOBJ_DEPTH).GetValue(); }
+
+ // #107245# GetSmoothNormals() for bExtrudeSmoothed
+ bool GetSmoothNormals() const
+ { return GetObjectItemSet().Get(SDRATTR_3DOBJ_SMOOTH_NORMALS).GetValue(); }
+
+ // #107245# GetSmoothLids() for bExtrudeSmoothFrontBack
+ bool GetSmoothLids() const
+ { return GetObjectItemSet().Get(SDRATTR_3DOBJ_SMOOTH_LIDS).GetValue(); }
+
+ // #107245# GetCharacterMode() for bExtrudeCharacterMode
+ bool GetCharacterMode() const
+ { return GetObjectItemSet().Get(SDRATTR_3DOBJ_CHARACTER_MODE).GetValue(); }
+
+ // #107245# GetCloseFront() for bExtrudeCloseFront
+ bool GetCloseFront() const
+ { return GetObjectItemSet().Get(SDRATTR_3DOBJ_CLOSE_FRONT).GetValue(); }
+
+ // #107245# GetCloseBack() for bExtrudeCloseBack
+ bool GetCloseBack() const
+ { return GetObjectItemSet().Get(SDRATTR_3DOBJ_CLOSE_BACK).GetValue(); }
+
+ virtual SdrObjKind GetObjIdentifier() const override;
+
+ virtual E3dExtrudeObj* CloneSdrObject(SdrModel& rTargetModel) const override;
+
+ // TakeObjName...() is for the display in the UI (for example "3 frames selected")
+ virtual OUString TakeObjNameSingul() const override;
+ virtual OUString TakeObjNamePlural() const override;
+
+ // set/get local parameters with geometry regeneration
+ void SetExtrudePolygon(const basegfx::B2DPolyPolygon &rNew);
+ const basegfx::B2DPolyPolygon &GetExtrudePolygon() const { return maExtrudePolygon; }
+
+ virtual bool IsBreakObjPossible() override;
+ virtual std::unique_ptr<SdrAttrObj,SdrObjectFreeOp> GetBreakObj() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/extrusiondepthdialog.hxx b/svx/inc/extrusiondepthdialog.hxx
new file mode 100644
index 000000000..11d69c170
--- /dev/null
+++ b/svx/inc/extrusiondepthdialog.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_EXTRUSIONDEPTHDIALOG_HXX
+#define INCLUDED_SVX_INC_EXTRUSIONDEPTHDIALOG_HXX
+
+#include <vcl/weld.hxx>
+
+namespace svx
+{
+class ExtrusionDepthDialog final : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::MetricSpinButton> m_xMtrDepth;
+
+public:
+ ExtrusionDepthDialog(weld::Window* pParent, double fDepth, FieldUnit eDefaultUnit);
+ virtual ~ExtrusionDepthDialog() override;
+
+ double getDepth() const;
+};
+}
+
+#endif // INCLUDED_SVX_INC_EXTRUSIONDEPTHDIALOG_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/fieldunit.hrc b/svx/inc/fieldunit.hrc
new file mode 100644
index 000000000..7de4c1cd7
--- /dev/null
+++ b/svx/inc/fieldunit.hrc
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_PAGE_HRC
+#define INCLUDED_SVX_INC_PAGE_HRC
+
+#include <tools/fldunit.hxx>
+#include <utility>
+#include <unotools/resmgr.hxx>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+const std::pair<TranslateId, FieldUnit> RID_SVXSTR_FIELDUNIT_TABLE[] =
+{
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Millimeter") , FieldUnit::MM },
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Centimeter") , FieldUnit::CM },
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Meter") , FieldUnit::M },
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Kilometer") , FieldUnit::KM },
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Inch") , FieldUnit::INCH },
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Foot") , FieldUnit::FOOT },
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Miles") , FieldUnit::MILE },
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Pica") , FieldUnit::PICA },
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Point") , FieldUnit::POINT },
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Char") , FieldUnit::CHAR },
+ { NC_("RID_SVXSTR_FIELDUNIT_TABLE", "Line") , FieldUnit::LINE },
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/fmstring.hrc b/svx/inc/fmstring.hrc
new file mode 100644
index 000000000..01919405b
--- /dev/null
+++ b/svx/inc/fmstring.hrc
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_FMSTRING_HRC
+#define INCLUDED_SVX_INC_FMSTRING_HRC
+
+#include <unotools/resmgr.hxx>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+const TranslateId RID_RSC_SQL_INTERNATIONAL[] =
+{
+ NC_("RID_RSC_SQL_INTERNATIONAL", "LIKE"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "NOT"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "EMPTY"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "TRUE"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "FALSE"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "IS"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "BETWEEN"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "OR"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "AND"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Average"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Count"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Maximum"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Minimum"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Sum"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Every"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Any"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Some"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "STDDEV_POP"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "STDDEV_SAMP"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "VAR_SAMP"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "VAR_POP"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Collect"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Fusion"),
+ NC_("RID_RSC_SQL_INTERNATIONAL", "Intersection")
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/formnavi.hrc b/svx/inc/formnavi.hrc
new file mode 100644
index 000000000..8af028117
--- /dev/null
+++ b/svx/inc/formnavi.hrc
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_FRMSEL_HRC
+#define INCLUDED_SVX_INC_FRMSEL_HRC
+
+#include <unotools/resmgr.hxx>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+const TranslateId RID_SVXSW_CONVERTMENU[] =
+{
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToEdit", "~Text Box"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToButton", "~Button"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToFixed", "La~bel field"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToList", "L~ist Box"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToCheckBox", "~Check Box"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToRadio", "~Radio Button"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToGroup", "G~roup Box"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToCombo", "Combo Bo~x"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToImageBtn", "I~mage Button"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToFileControl", "~File Selection"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToDate", "~Date Field"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToTime", "Tim~e Field"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToNumeric", "~Numerical Field"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToCurrency", "C~urrency Field"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToPattern", "~Pattern Field"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToImageControl", "Ima~ge Control"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToFormatted", "Fo~rmatted Field"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToScrollBar", "Scroll bar"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToSpinButton", "Spin Button"),
+ NC_("RID_SVXSW_CONVERTMENU|ConvertToNavigationBar", "Navigation Bar")
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/frmsel.hrc b/svx/inc/frmsel.hrc
new file mode 100644
index 000000000..84fe78a23
--- /dev/null
+++ b/svx/inc/frmsel.hrc
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_FRMSEL_HRC
+#define INCLUDED_SVX_INC_FRMSEL_HRC
+
+#include <utility>
+#include <sal/types.h>
+#include <unotools/resmgr.hxx>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+std::pair<TranslateId, sal_uInt16> RID_SVXSTR_FRMSEL_TEXTS[] =
+{
+ { NC_("RID_SVXSTR_FRMSEL_TEXTS", "Border setting") , 0 },
+ { NC_("RID_SVXSTR_FRMSEL_TEXTS", "Left border line") , 1 },
+ { NC_("RID_SVXSTR_FRMSEL_TEXTS", "Right border line") , 2 },
+ { NC_("RID_SVXSTR_FRMSEL_TEXTS", "Top border line") , 3 },
+ { NC_("RID_SVXSTR_FRMSEL_TEXTS", "Bottom border line") , 4 },
+ { NC_("RID_SVXSTR_FRMSEL_TEXTS", "Horizontal border line") , 5 },
+ { NC_("RID_SVXSTR_FRMSEL_TEXTS", "Vertical border line") , 6 },
+ { NC_("RID_SVXSTR_FRMSEL_TEXTS", "Diagonal border line from top left to bottom right") , 7 },
+ { NC_("RID_SVXSTR_FRMSEL_TEXTS", "Diagonal border line from bottom left to top right") , 8 },
+};
+
+std::pair<TranslateId, sal_uInt16> RID_SVXSTR_FRMSEL_DESCRIPTIONS[] =
+{
+ { NC_("RID_SVXSTR_FRMSEL_DESCRIPTIONS", "Border setting") , 0 },
+ { NC_("RID_SVXSTR_FRMSEL_DESCRIPTIONS", "Left border line") , 1 },
+ { NC_("RID_SVXSTR_FRMSEL_DESCRIPTIONS", "Right border line") , 2 },
+ { NC_("RID_SVXSTR_FRMSEL_DESCRIPTIONS", "Top border line") , 3 },
+ { NC_("RID_SVXSTR_FRMSEL_DESCRIPTIONS", "Bottom border line") , 4 },
+ { NC_("RID_SVXSTR_FRMSEL_DESCRIPTIONS", "Horizontal border line") , 5 },
+ { NC_("RID_SVXSTR_FRMSEL_DESCRIPTIONS", "Vertical border line") , 6 },
+ { NC_("RID_SVXSTR_FRMSEL_DESCRIPTIONS", "Diagonal border line from top left to bottom right") , 7 },
+ { NC_("RID_SVXSTR_FRMSEL_DESCRIPTIONS", "Diagonal border line from bottom left to top right") , 8 },
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/galbrws2.hxx b/svx/inc/galbrws2.hxx
new file mode 100644
index 000000000..2cf8609ed
--- /dev/null
+++ b/svx/inc/galbrws2.hxx
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_GALBRWS2_HXX
+#define INCLUDED_SVX_INC_GALBRWS2_HXX
+
+#include <vcl/transfer.hxx>
+#include <svl/lstner.hxx>
+#include <svx/galctrl.hxx>
+
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+
+
+enum GalleryBrowserMode
+{
+ GALLERYBROWSERMODE_NONE = 0,
+ GALLERYBROWSERMODE_ICON = 1,
+ GALLERYBROWSERMODE_LIST = 2,
+ GALLERYBROWSERMODE_PREVIEW = 3
+};
+
+
+enum class GalleryBrowserTravel
+{
+ First, Last, Previous, Next
+};
+
+enum class GalleryItemFlags {
+ Title = 0x0002,
+ Path = 0x0004
+};
+namespace o3tl
+{
+ template<> struct typed_flags<GalleryItemFlags> : is_typed_flags<GalleryItemFlags, 0x0006> {};
+}
+
+
+class Gallery;
+class GalleryDragDrop;
+class GalleryTheme;
+class GalleryIconView;
+class GalleryListView;
+class GalleryPreview;
+class GalleryTransferable;
+class Menu;
+class SgaObject;
+struct DispatchInfo;
+
+namespace svx::sidebar { class GalleryControl; }
+
+class GalleryBrowser2 final : public SfxListener
+{
+ friend class GalleryBrowser;
+ friend class svx::sidebar::GalleryControl;
+
+private:
+
+ Gallery* mpGallery;
+ GalleryTheme* mpCurTheme;
+ std::unique_ptr<GalleryIconView> mxIconView;
+ std::unique_ptr<weld::CustomWeld> mxIconViewWin;
+ std::unique_ptr<weld::TreeView> mxListView;
+ std::unique_ptr<GalleryDragDrop> mxDragDropTargetHelper;
+ std::unique_ptr<GalleryPreview> mxPreview;
+ std::unique_ptr<weld::CustomWeld> mxPreviewWin;
+ std::unique_ptr<weld::ToggleButton> mxIconButton;
+ std::unique_ptr<weld::ToggleButton> mxListButton;
+ std::unique_ptr<weld::Label> mxInfoBar;
+ Size maPreviewSize;
+ rtl::Reference<GalleryTransferable> m_xHelper;
+ sal_uInt32 mnCurActionPos;
+ GalleryBrowserMode meMode;
+ GalleryBrowserMode meLastMode;
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::util::XURLTransformer > m_xTransformer;
+
+ void ImplUpdateViews( sal_uInt16 nSelectionId );
+ void ImplUpdateInfoBar();
+ sal_uInt32 ImplGetSelectedItemId( const Point* pSelPosPixel, Point& rSelPos );
+ void ImplSelectItemId(sal_uInt32 nItemId);
+ void ImplUpdateSelection();
+ void UpdateRows(bool bVisibleOnly);
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ DECL_LINK( SelectObjectHdl, weld::TreeView&, void );
+ DECL_LINK( SelectObjectValueSetHdl, ValueSet*, void );
+ DECL_LINK( SelectTbxHdl, weld::Toggleable&, void );
+ DECL_LINK( PopupMenuHdl, const CommandEvent&, bool );
+ DECL_LINK( KeyInputHdl, const KeyEvent&, bool );
+ DECL_LINK( RowActivatedHdl, weld::TreeView&, bool );
+ DECL_LINK( DragBeginHdl, bool&, bool );
+ DECL_LINK( VisRowsScrolledHdl, weld::TreeView&, void );
+ DECL_LINK( SizeAllocHdl, const Size&, void );
+
+private:
+
+ static GalleryBrowserMode meInitMode;
+
+public:
+
+ static OUString GetItemText( const SgaObject& rObj, GalleryItemFlags nItemTextFlags );
+
+public:
+
+ GalleryBrowser2(weld::Builder& rBuilder, Gallery* pGallery);
+ ~GalleryBrowser2();
+
+ void SelectTheme( std::u16string_view rThemeName );
+
+ GalleryBrowserMode GetMode() const { return meMode; }
+ void SetMode( GalleryBrowserMode eMode );
+
+ weld::Widget* GetViewWindow() const;
+
+ void Travel( GalleryBrowserTravel eTravel );
+
+ INetURLObject GetURL() const;
+ OUString GetFilterName() const;
+
+ sal_Int8 AcceptDrop( const DropTargetHelper& rTarget );
+ sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt );
+ bool StartDrag();
+ void TogglePreview();
+ void ShowContextMenu(const CommandEvent& rCEvt);
+ bool KeyInput(const KeyEvent& rEvt);
+ bool ViewBoxHasFocus() const;
+
+ static css::uno::Reference< css::frame::XFrame > GetFrame();
+ const css::uno::Reference< css::util::XURLTransformer >& GetURLTransformer() const { return m_xTransformer; }
+
+ void Execute(std::string_view rIdent);
+ void DispatchAdd(const css::uno::Reference<css::frame::XDispatch> &rxDispatch,
+ const css::util::URL &rURL);
+
+ DECL_STATIC_LINK( GalleryBrowser2, AsyncDispatch_Impl, void*, void );
+};
+
+class GalleryDragDrop final : public DropTargetHelper
+{
+private:
+ GalleryBrowser2* m_pParent;
+
+ virtual sal_Int8 AcceptDrop(const AcceptDropEvent& /*rEvt*/) override
+ {
+ return m_pParent->AcceptDrop(*this);
+ }
+
+ virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
+ {
+ return m_pParent->ExecuteDrop(rEvt);
+ }
+
+public:
+ GalleryDragDrop(GalleryBrowser2* pParent, const css::uno::Reference<css::datatransfer::dnd::XDropTarget>& rDropTarget)
+ : DropTargetHelper(rDropTarget)
+ , m_pParent(pParent)
+ {
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/galleryobjectbinarystorage.hxx b/svx/inc/galleryobjectbinarystorage.hxx
new file mode 100644
index 000000000..611ff637b
--- /dev/null
+++ b/svx/inc/galleryobjectbinarystorage.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/urlobj.hxx>
+#include <svx/galleryobjectstorage.hxx>
+
+class GalleryObjectBinaryStorage final : public GalleryObjectStorage
+{
+private:
+ INetURLObject m_aURL;
+
+public:
+ void setURL(INetURLObject aURL);
+ const INetURLObject& getURL() const { return m_aURL; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/galleryobjectxmlstorage.hxx b/svx/inc/galleryobjectxmlstorage.hxx
new file mode 100644
index 000000000..f72d7067a
--- /dev/null
+++ b/svx/inc/galleryobjectxmlstorage.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/urlobj.hxx>
+#include <svx/galleryobjectstorage.hxx>
+
+class GalleryObjectXMLStorage final : public GalleryObjectStorage
+{
+private:
+ INetURLObject m_aURL;
+
+public:
+ void setURL(INetURLObject aURL);
+ const INetURLObject& getURL() const { return m_aURL; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/galobj.hxx b/svx/inc/galobj.hxx
new file mode 100644
index 000000000..29c053baa
--- /dev/null
+++ b/svx/inc/galobj.hxx
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_GALOBJ_HXX
+#define INCLUDED_SVX_INC_GALOBJ_HXX
+
+#include <config_options.h>
+#include <tools/urlobj.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/gdimtf.hxx>
+#include <svx/galmisc.hxx>
+
+#define S_THUMB 80
+
+
+enum GalSoundType
+{
+ SOUND_STANDARD = 0,
+ SOUND_COMPUTER = 1,
+ SOUND_MISC = 2,
+ SOUND_MUSIC = 3,
+ SOUND_NATURE = 4,
+ SOUND_SPEECH = 5,
+ SOUND_TECHNIC = 6,
+ SOUND_ANIMAL = 7
+};
+
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) SgaObject
+{
+ friend class GalleryTheme;
+ friend class GalleryBinaryEngine;
+
+private:
+
+ void ImplUpdateURL( const INetURLObject& rNewURL ) { aURL = rNewURL; }
+
+protected:
+
+ BitmapEx aThumbBmp; // Allow transparence to survive
+ GDIMetaFile aThumbMtf;
+ INetURLObject aURL;
+ OUString aTitle;
+ bool bIsValid;
+ bool bIsThumbBmp;
+
+ virtual void WriteData( SvStream& rOut, const OUString& rDestDir ) const;
+ virtual void ReadData( SvStream& rIn, sal_uInt16& rReadVersion );
+
+ bool CreateThumb( const Graphic& rGraphic );
+
+public:
+ SgaObject();
+ SgaObject(const SgaObject& aObject);
+
+ virtual ~SgaObject() {};
+
+ virtual SgaObjKind GetObjKind() const = 0;
+ virtual sal_uInt16 GetVersion() const = 0;
+
+ virtual BitmapEx GetThumbBmp() const { return aThumbBmp; }
+ const GDIMetaFile& GetThumbMtf() const { return aThumbMtf; }
+ const INetURLObject& GetURL() const { return aURL; }
+ bool IsValid() const { return bIsValid; }
+ bool IsThumbBitmap() const { return bIsThumbBmp; }
+
+ OUString const & GetTitle() const;
+ void SetTitle( const OUString& rTitle );
+
+ friend SvStream& WriteSgaObject( SvStream& rOut, const SgaObject& rObj );
+ friend SvStream& ReadSgaObject( SvStream& rIn, SgaObject& rObj );
+
+ BitmapEx createPreviewBitmapEx(const Size& rSizePixel) const;
+};
+
+class SgaObjectSound final : public SgaObject
+{
+private:
+
+ GalSoundType eSoundType;
+
+ virtual void WriteData( SvStream& rOut, const OUString& rDestDir ) const override;
+ virtual void ReadData( SvStream& rIn, sal_uInt16& rReadVersion ) override;
+
+ virtual sal_uInt16 GetVersion() const override { return 6; }
+
+public:
+
+ SgaObjectSound();
+ SgaObjectSound( const INetURLObject& rURL );
+ virtual ~SgaObjectSound() override;
+
+ virtual SgaObjKind GetObjKind() const override { return SgaObjKind::Sound; }
+ virtual BitmapEx GetThumbBmp() const override;
+};
+
+class FmFormModel;
+
+class SgaObjectSvDraw final : public SgaObject
+{
+ using SgaObject::CreateThumb;
+
+private:
+
+ bool CreateThumb( const FmFormModel& rModel );
+
+ virtual void WriteData( SvStream& rOut, const OUString& rDestDir ) const override;
+ virtual void ReadData( SvStream& rIn, sal_uInt16& rReadVersion ) override;
+
+ virtual sal_uInt16 GetVersion() const override { return 5; }
+
+public:
+
+ SgaObjectSvDraw();
+ SgaObjectSvDraw( const FmFormModel& rModel, const INetURLObject& rURL );
+ SgaObjectSvDraw( SvStream& rIStm, const INetURLObject& rURL );
+
+ virtual SgaObjKind GetObjKind() const override { return SgaObjKind::SvDraw; }
+};
+
+class SgaObjectBmp: public SgaObject
+{
+private:
+
+ void Init( const Graphic& rGraphic, const INetURLObject& rURL );
+
+ virtual void WriteData( SvStream& rOut, const OUString& rDestDir ) const override;
+ virtual void ReadData( SvStream& rIn, sal_uInt16& rReadVersion ) override;
+
+ virtual sal_uInt16 GetVersion() const override { return 5; }
+
+public:
+
+ SgaObjectBmp();
+ SgaObjectBmp( const INetURLObject& rURL );
+ SgaObjectBmp( const Graphic& rGraphic, const INetURLObject& rURL );
+
+ virtual SgaObjKind GetObjKind() const override { return SgaObjKind::Bitmap; }
+};
+
+class SgaObjectAnim : public SgaObjectBmp
+{
+public:
+
+ SgaObjectAnim();
+ SgaObjectAnim( const Graphic& rGraphic, const INetURLObject& rURL );
+
+ virtual SgaObjKind GetObjKind() const override { return SgaObjKind::Animation; }
+};
+
+class SgaObjectINet final : public SgaObjectAnim
+{
+public:
+
+ SgaObjectINet();
+ SgaObjectINet( const Graphic& rGraphic, const INetURLObject& rURL );
+
+ virtual SgaObjKind GetObjKind() const override { return SgaObjKind::Inet; }
+};
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/getallcharpropids.hxx b/svx/inc/getallcharpropids.hxx
new file mode 100644
index 000000000..e5c8d98f3
--- /dev/null
+++ b/svx/inc/getallcharpropids.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_GETALLCHARPROPIDS_HXX
+#define INCLUDED_SVX_INC_GETALLCHARPROPIDS_HXX
+
+#include <sal/config.h>
+#include <sal/types.h>
+#include <o3tl/span.hxx>
+#include <vector>
+
+class SfxItemSet;
+class SfxPoolItem;
+
+std::vector<sal_uInt16> GetAllCharPropIds(const SfxItemSet& rSet);
+std::vector<sal_uInt16> GetAllCharPropIds(o3tl::span<const SfxPoolItem* const> aChangedItems);
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/helpids.h b/svx/inc/helpids.h
new file mode 100644
index 000000000..625cc4304
--- /dev/null
+++ b/svx/inc/helpids.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_HELPIDS_H
+#define INCLUDED_SVX_INC_HELPIDS_H
+
+#include <rtl/string.hxx>
+
+inline constexpr OStringLiteral HID_BMPMASK_CTL_QCOL_1 = "SVX_HID_BMPMASK_CTL_QCOL_1";
+inline constexpr OStringLiteral HID_COLOR_CTL_COLORS = "SVX_HID_COLOR_CTL_COLORS";
+inline constexpr OStringLiteral HID_CTRL3D_HSCROLL = "SVX_HID_CTRL3D_HSCROLL";
+inline constexpr OStringLiteral HID_CTRL3D_SWITCHER = "SVX_HID_CTRL3D_SWITCHER";
+inline constexpr OStringLiteral HID_CTRL3D_VSCROLL = "SVX_HID_CTRL3D_VSCROLL";
+inline constexpr OStringLiteral HID_CTRL_COLOR = "SVX_HID_CTRL_COLOR";
+inline constexpr OStringLiteral HID_GALLERY_ICONVIEW = "SVX_HID_GALLERY_ICONVIEW";
+inline constexpr OStringLiteral HID_GALLERY_LISTVIEW = "SVX_HID_GALLERY_LISTVIEW";
+inline constexpr OStringLiteral HID_GALLERY_NEWTHEME = "SVX_HID_GALLERY_NEWTHEME";
+inline constexpr OStringLiteral HID_GALLERY_THEMELIST = "SVX_HID_GALLERY_THEMELIST";
+inline constexpr OStringLiteral HID_GALLERY_WINDOW = "SVX_HID_GALLERY_WINDOW";
+inline constexpr OStringLiteral HID_POPUP_COLOR = "SVX_HID_POPUP_COLOR";
+inline constexpr OStringLiteral HID_POPUP_COLOR_CTRL = "SVX_HID_POPUP_COLOR_CTRL";
+inline constexpr OStringLiteral HID_POPUP_FRAME = "SVX_HID_POPUP_FRAME";
+inline constexpr OStringLiteral HID_POPUP_LINE = "SVX_HID_POPUP_LINE";
+inline constexpr OStringLiteral HID_POPUP_LINEEND = "SVX_HID_POPUP_LINEEND";
+inline constexpr OStringLiteral HID_POPUP_LINEEND_CTRL = "SVX_HID_POPUP_LINEEND_CTRL";
+inline constexpr OStringLiteral HID_STYLE_LISTBOX = "SVX_HID_STYLE_LISTBOX";
+inline constexpr OStringLiteral HID_VALUESET_EXTRUSION_LIGHTING = "SVX_HID_VALUESET_EXTRUSION_LIGHTING";
+inline constexpr OStringLiteral HID_UNDERLINE_BTN = "SVX_HID_UNDERLINE_BTN";
+inline constexpr OStringLiteral HID_SPACING_MB_KERN = "SVX_HID_SPACING_MB_KERN";
+
+inline constexpr OStringLiteral HID_FORM_NAVIGATOR = "SVX_HID_FORM_NAVIGATOR";
+inline constexpr OStringLiteral HID_FORM_NAVIGATOR_WIN = "SVX_HID_FORM_NAVIGATOR_WIN";
+inline constexpr OStringLiteral HID_FIELD_SEL = "SVX_HID_FIELD_SEL";
+inline constexpr OStringLiteral HID_FIELD_SEL_WIN = "SVX_HID_FIELD_SEL_WIN";
+inline constexpr OStringLiteral HID_FILTER_NAVIGATOR = "SVX_HID_FILTER_NAVIGATOR";
+inline constexpr OStringLiteral HID_FILTER_NAVIGATOR_WIN = "SVX_HID_FILTER_NAVIGATOR_WIN";
+inline constexpr OStringLiteral HID_GRID_TRAVEL_FIRST = "SVX_HID_GRID_TRAVEL_FIRST";
+inline constexpr OStringLiteral HID_GRID_TRAVEL_PREV = "SVX_HID_GRID_TRAVEL_PREV";
+inline constexpr OStringLiteral HID_GRID_TRAVEL_NEXT = "SVX_HID_GRID_TRAVEL_NEXT";
+inline constexpr OStringLiteral HID_GRID_TRAVEL_LAST = "SVX_HID_GRID_TRAVEL_LAST";
+inline constexpr OStringLiteral HID_GRID_TRAVEL_NEW = "SVX_HID_GRID_TRAVEL_NEW";
+inline constexpr OStringLiteral HID_GRID_TRAVEL_ABSOLUTE = "SVX_HID_GRID_TRAVEL_ABSOLUTE";
+inline constexpr OStringLiteral HID_GRID_NUMBEROFRECORDS = "SVX_HID_GRID_NUMBEROFRECORDS";
+
+// Help IDs for Manage Track Changes
+inline constexpr OStringLiteral HID_REDLINE_CTRL_VIEW = "SVX_HID_REDLINE_CTRL_VIEW";
+inline constexpr OStringLiteral HID_REDLINE_CTRL_FILTER = "SVX_HID_REDLINE_CTRL_FILTER";
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/inspectorvalues.hrc b/svx/inc/inspectorvalues.hrc
new file mode 100644
index 000000000..0c09dc4a0
--- /dev/null
+++ b/svx/inc/inspectorvalues.hrc
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+#define NNC_(Context, StringSingular, StringPlural) TranslateNId(Context, reinterpret_cast<char const *>(u8##StringSingular), reinterpret_cast<char const *>(u8##StringPlural))
+
+/*--------------------------------------------------------------------
+ Description: API names for Paragraph, Character
+ and Text cursor values
+ --------------------------------------------------------------------*/
+
+// Node names
+#define RID_NORMAL NC_("RID_ATTRIBUTE_NAMES_MAP", "Normal")
+#define RID_BOLD NC_("RID_ATTRIBUTE_NAMES_MAP", "Bold")
+#define RID_ITALIC NC_("RID_ATTRIBUTE_NAMES_MAP", "Italic")
+
+#define RID_FALSE NC_("RID_ATTRIBUTE_NAMES_MAP", "False")
+#define RID_TRUE NC_("RID_ATTRIBUTE_NAMES_MAP", "True")
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/layctrl.hxx b/svx/inc/layctrl.hxx
new file mode 100644
index 000000000..34ccc6e54
--- /dev/null
+++ b/svx/inc/layctrl.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svtools/popupwindowcontroller.hxx>
+
+class SvxTableToolBoxControl final : public svt::PopupWindowController
+{
+public:
+ SvxTableToolBoxControl(const css::uno::Reference<css::uno::XComponentContext>& rContext);
+ virtual ~SvxTableToolBoxControl() override;
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow(vcl::Window* pParent) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ void TableDialog(const css::uno::Sequence<css::beans::PropertyValue>& rArgs);
+ void CloseAndShowTableDialog();
+};
+
+class SvxColumnsToolBoxControl final : public svt::PopupWindowController
+{
+public:
+ SvxColumnsToolBoxControl(const css::uno::Reference<css::uno::XComponentContext>& rContext);
+ virtual ~SvxColumnsToolBoxControl() override;
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow(vcl::Window* pParent) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ void InsertColumns(const css::uno::Sequence<css::beans::PropertyValue>& rArgs);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/lboxctrl.hxx b/svx/inc/lboxctrl.hxx
new file mode 100644
index 000000000..e09477d72
--- /dev/null
+++ b/svx/inc/lboxctrl.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <vector>
+#include <svtools/popupwindowcontroller.hxx>
+
+class ToolBox;
+class SvxPopupWindowListBox;
+
+class SvxUndoRedoControl final : public svt::PopupWindowController
+{
+ std::vector<OUString> aUndoRedoList;
+ OUString aDefaultTooltip;
+
+public:
+ SvxUndoRedoControl(const css::uno::Reference<css::uno::XComponentContext>& rContext);
+ virtual ~SvxUndoRedoControl() override;
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow(vcl::Window* pParent) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& rEvent) override;
+
+ void Do(sal_Int16 nCount);
+
+ void SetText(const OUString& rText);
+
+ void SetInfo(sal_Int32 nCount);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/numberingtype.hrc b/svx/inc/numberingtype.hrc
new file mode 100644
index 000000000..4e2ab1f6d
--- /dev/null
+++ b/svx/inc/numberingtype.hrc
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_NUMBERINGTYPE_HRC
+#define INCLUDED_SVX_INC_NUMBERINGTYPE_HRC
+
+#include <unotools/resmgr.hxx>
+
+#include <utility>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+const std::pair<TranslateId, int> RID_SVXSTRARY_NUMBERINGTYPE[] =
+{
+ { /* SVX_NUM_NUMBER_NONE */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "None") , 5 },
+ { /* SVX_NUM_CHAR_SPECIAL */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Bullet") , 6 },
+ { /* SVX_NUM_BITMAP */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Graphics") , 8 },
+ { /* SVX_NUM_BITMAP|0x80 */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Linked graphics") , 136 },
+ { /* SVX_NUM_ARABIC */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "1, 2, 3, ...") , 4 },
+ { /* SVX_NUM_CHARS_UPPER_LETTER */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "A, B, C, ...") , 0 },
+ { /* SVX_NUM_CHARS_LOWER_LETTER */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "a, b, c, ...") , 1 },
+ { /* SVX_NUM_ROMAN_UPPER */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "I, II, III, ...") , 2 },
+ { /* SVX_NUM_ROMAN_LOWER */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "i, ii, iii, ...") , 3 },
+ { /* TEXT_NUMBER */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "1st, 2nd, 3rd, ...") , 60 },
+ { /* TEXT_CARDINAL */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "One, Two, Three, ...") , 61 },
+ { /* TEXT_ORDINAL */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "First, Second, Third, ...") , 62 },
+ { /* SVX_NUM_CHARS_UPPER_LETTER_N */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "A, .., AA, .., AAA, ...") , 9 },
+ { /* SVX_NUM_CHARS_LOWER_LETTER_N */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "a, .., aa, .., aaa, ...") , 10 },
+ { /* SYMBOL_CHICAGO */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "*, †, ‡, §, **, ††, ...") , 63 },
+ { /* NATIVE_NUMBERING */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Native Numbering") , 12 },
+ { /* CHARS_CYRILLIC_UPPER_LETTER_BG */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Ð, Б, .., Ðа, Ðб, ... (Bulgarian)") , 38 },
+ { /* CHARS_CYRILLIC_LOWER_LETTER_BG */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "а, б, .., аа, аб, ... (Bulgarian)") , 39 },
+ { /* CHARS_CYRILLIC_UPPER_LETTER_N_BG */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Ð, Б, .., Ðа, Бб, ... (Bulgarian)") , 40 },
+ { /* CHARS_CYRILLIC_LOWER_LETTER_N_BG */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "а, б, .., аа, бб, ... (Bulgarian)") , 41 },
+ { /* CHARS_CYRILLIC_UPPER_LETTER_RU */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Ð, Б, .., Ðа, Ðб, ... (Russian)") , 42 },
+ { /* CHARS_CYRILLIC_LOWER_LETTER_RU */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "а, б, .., аа, аб, ... (Russian)") , 43 },
+ { /* CHARS_CYRILLIC_UPPER_LETTER_N_RU */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Ð, Б, .., Ðа, Бб, ... (Russian)") , 44 },
+ { /* CHARS_CYRILLIC_LOWER_LETTER_N_RU */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "а, б, .., аа, бб, ... (Russian)") , 45 },
+ { /* CHARS_CYRILLIC_UPPER_LETTER_SR */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Ð, Б, .., Ðа, Ðб, ... (Serbian)") , 48 },
+ { /* CHARS_CYRILLIC_LOWER_LETTER_SR */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "а, б, .., аа, аб, ... (Serbian)") , 49 },
+ { /* CHARS_CYRILLIC_UPPER_LETTER_N_SR */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Ð, Б, .., Ðа, Бб, ... (Serbian)") , 50 },
+ { /* CHARS_CYRILLIC_LOWER_LETTER_N_SR */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "а, б, .., аа, бб, ... (Serbian)") , 51 },
+ { /* CHARS_GREEK_UPPER_LETTER */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Α, Β, Γ, ... (Greek)"), 52 },
+ { /* CHARS_GREEK_LOWER_LETTER */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "α, β, γ, ... (Greek)"), 53 },
+ { /* NUMBER_HEBREW */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "×...×™, ×™×...×›, ...") , 56 },
+ { /* CHARS_HEBREW */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "×...ת, ××...תת, ...") , 33 },
+ { /* NUMBER_ARABIC_INDIC */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Ù¡, Ù¢, Ù£, Ù¤, ... (Arabic)"), 57 },
+ { /* NUMBER_EAST_ARABIC_INDIC */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "Û±, Û², Û³, Û´, ... (Farsi)"), 58 },
+ { /* NUMBER_INDIC_DEVANAGARI */ NC_("RID_SVXSTRARY_NUMBERINGTYPE", "१, २, ३, ..."), 59 },
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/palettes.hxx b/svx/inc/palettes.hxx
new file mode 100644
index 000000000..9469659d2
--- /dev/null
+++ b/svx/inc/palettes.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_PALETTE_HXX
+#define INCLUDED_SVX_INC_PALETTE_HXX
+
+#include <svx/Palette.hxx>
+#include <svx/SvxColorValueSet.hxx>
+#include <svx/xtable.hxx>
+
+class SvFileStream;
+
+typedef std::vector< NamedColor > ColorList;
+
+// ASE = Adobe Swatch Exchange
+
+class PaletteASE final : public Palette
+{
+ bool mbValidPalette;
+ OUString maFPath;
+ OUString maASEPaletteName;
+ ColorList maColors;
+
+ void LoadPalette();
+public:
+ PaletteASE( const OUString &rFPath, const OUString &rFName );
+ virtual ~PaletteASE() override;
+
+ virtual const OUString& GetName() override;
+ virtual const OUString& GetPath() override;
+ virtual void LoadColorSet(SvxColorValueSet& rColorSet) override;
+
+ virtual bool IsValid() override;
+};
+
+// GPL - this is *not* GNU Public License, but is the Gimp PaLette
+
+class PaletteGPL final : public Palette
+{
+ bool mbLoadedPalette;
+ bool mbValidPalette;
+ OUString maFName;
+ OUString maFPath;
+ OUString maGPLPaletteName;
+ ColorList maColors;
+
+ bool ReadPaletteHeader(SvFileStream& rFileStream);
+ void LoadPaletteHeader();
+ void LoadPalette();
+public:
+ PaletteGPL( const OUString &rFPath, const OUString &rFName );
+ virtual ~PaletteGPL() override;
+
+ virtual const OUString& GetName() override;
+ virtual const OUString& GetPath() override;
+ virtual void LoadColorSet(SvxColorValueSet& rColorSet) override;
+
+ virtual bool IsValid() override;
+};
+
+// SOC - Star Office Color-table
+
+class PaletteSOC final : public Palette
+{
+ bool mbLoadedPalette;
+ OUString maFPath;
+ OUString maSOCPaletteName;
+ XColorListRef mpColorList;
+public:
+ PaletteSOC( const OUString &rFPath, const OUString &rFName );
+ virtual ~PaletteSOC() override;
+
+ virtual const OUString& GetName() override;
+ virtual const OUString& GetPath() override;
+ virtual void LoadColorSet(SvxColorValueSet& rColorSet) override;
+
+ virtual bool IsValid() override;
+};
+
+#endif // INCLUDED_SVX_INC_PALETTE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/pch/precompiled_svx.cxx b/svx/inc/pch/precompiled_svx.cxx
new file mode 100644
index 000000000..a05a248ab
--- /dev/null
+++ b/svx/inc/pch/precompiled_svx.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_svx.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/pch/precompiled_svx.hxx b/svx/inc/pch/precompiled_svx.hxx
new file mode 100644
index 000000000..f6206e076
--- /dev/null
+++ b/svx/inc/pch/precompiled_svx.hxx
@@ -0,0 +1,443 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2022-01-26 09:16:16 using:
+ ./bin/update_pch svx svx --cutoff=3 --exclude:system --exclude:module --include:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./svx/inc/pch/precompiled_svx.hxx "make svx.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <climits>
+#include <cstddef>
+#include <cstdlib>
+#include <deque>
+#include <functional>
+#include <limits.h>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <numeric>
+#include <optional>
+#include <ostream>
+#include <set>
+#include <stddef.h>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/ptree_fwd.hpp>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/endian.h>
+#include <osl/file.hxx>
+#include <osl/interlck.h>
+#include <osl/mutex.hxx>
+#include <osl/thread.h>
+#include <rtl/alloc.h>
+#include <rtl/bootstrap.hxx>
+#include <rtl/instance.hxx>
+#include <rtl/math.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/string.hxx>
+#include <rtl/tencinfo.h>
+#include <rtl/textenc.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/uuid.h>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+#include <sal/saldllapi.h>
+#include <sal/types.h>
+#include <sal/typesizes.h>
+#include <vcl/BitmapFilter.hxx>
+#include <vcl/EnumContext.hxx>
+#include <vcl/GraphicObject.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <vcl/Scanline.hxx>
+#include <vcl/alpha.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/dllapi.h>
+#include <vcl/errcode.hxx>
+#include <vcl/errinf.hxx>
+#include <vcl/event.hxx>
+#include <vcl/fieldvalues.hxx>
+#include <vcl/font.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/image.hxx>
+#include <vcl/imap.hxx>
+#include <vcl/imapobj.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/status.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/task.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/toolboxid.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/vclenum.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+#include <vcl/window.hxx>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <basegfx/basegfxdllapi.h>
+#include <basegfx/color/bcolor.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/point/b2ipoint.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/range/basicrange.hxx>
+#include <basegfx/tuple/b2dtuple.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/vector/b2enums.hxx>
+#include <basegfx/vector/b3dvector.hxx>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/awt/GradientStyle.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/datatransfer/XTransferable2.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp>
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/datatransfer/dnd/DropTargetDragEvent.hpp>
+#include <com/sun/star/datatransfer/dnd/DropTargetDropEvent.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragGestureListener.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSourceListener.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetListener.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineCap.hpp>
+#include <com/sun/star/drawing/TextFitToSizeType.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/frame/XToolbarController.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/i18n/BreakIterator.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/EventObject.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/text/DefaultNumberingProvider.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/textfield/Type.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/XWeak.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+#include <com/sun/star/util/XUpdatable.hpp>
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/compbase.hxx>
+#include <comphelper/comphelperdllapi.h>
+#include <comphelper/interfacecontainer4.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/multicontainer2.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/weak.hxx>
+#include <cppu/unotype.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/cppuhelperdllapi.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/weakagg.hxx>
+#include <drawinglayer/drawinglayerdllapi.h>
+#include <drawinglayer/primitive2d/CommonTypes.hxx>
+#include <drawinglayer/primitive2d/Primitive2DContainer.hxx>
+#include <drawinglayer/primitive2d/Primitive2DVisitor.hxx>
+#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editengdllapi.h>
+#include <editeng/editstat.hxx>
+#include <editeng/eedata.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/frmdir.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/numdef.hxx>
+#include <editeng/numitem.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/overflowingtxt.hxx>
+#include <editeng/paragraphdata.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/svxenum.hxx>
+#include <editeng/svxfont.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <i18nlangtag/lang.h>
+#include <i18nlangtag/languagetag.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <o3tl/cow_wrapper.hxx>
+#include <o3tl/deleter.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/sorted_vector.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <o3tl/underlyingenumvalue.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/chalign.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/ctrlitem.hxx>
+#include <sfx2/dialoghelper.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/dllapi.h>
+#include <sfx2/dockwin.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/shell.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <sfx2/stbitem.hxx>
+#include <sfx2/tabdlg.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/weldutils.hxx>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <sot/sotdllapi.h>
+#include <svl/SfxBroadcaster.hxx>
+#include <svl/cenumitm.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <svl/eitem.hxx>
+#include <svl/hint.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <svl/languageoptions.hxx>
+#include <svl/lstner.hxx>
+#include <svl/metitem.hxx>
+#include <svl/poolitem.hxx>
+#include <svl/srchitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/style.hxx>
+#include <svl/stylesheetuser.hxx>
+#include <svl/svldllapi.h>
+#include <svl/typedwhich.hxx>
+#include <svl/undo.hxx>
+#include <svl/whiter.hxx>
+#include <svl/zforlist.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svtools/ehdl.hxx>
+#include <svtools/popupwindowcontroller.hxx>
+#include <svtools/svtdllapi.h>
+#include <svtools/svtresid.hxx>
+#include <svtools/toolbarmenu.hxx>
+#include <svtools/toolboxcontroller.hxx>
+#include <svtools/unitconv.hxx>
+#include <svtools/valueset.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/UnitConversion.hxx>
+#include <tools/color.hxx>
+#include <tools/date.hxx>
+#include <tools/datetime.hxx>
+#include <tools/debug.hxx>
+#include <tools/degree.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/fldunit.hxx>
+#include <tools/fract.hxx>
+#include <tools/gen.hxx>
+#include <tools/globname.hxx>
+#include <tools/helpers.hxx>
+#include <tools/link.hxx>
+#include <tools/long.hxx>
+#include <tools/mapunit.hxx>
+#include <tools/poly.hxx>
+#include <tools/resary.hxx>
+#include <tools/solar.h>
+#include <tools/stream.hxx>
+#include <tools/time.hxx>
+#include <tools/toolsdllapi.h>
+#include <tools/urlobj.hxx>
+#include <typelib/typedescription.h>
+#include <uno/data.h>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <unotools/fontcvt.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/resmgr.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/unotoolsdllapi.h>
+#include <unotools/viewoptions.hxx>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <cell.hxx>
+#include <charmapacc.hxx>
+#include <fmprop.hxx>
+#include <fmservs.hxx>
+#include <helpids.h>
+#include <svx/algitem.hxx>
+#include <svx/charmap.hxx>
+#include <svx/colorbox.hxx>
+#include <svx/deflt3d.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/dlgctrl.hxx>
+#include <svx/dlgutil.hxx>
+#include <svx/drawitem.hxx>
+#include <svx/e3ditem.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/fmtools.hxx>
+#include <svx/framebordertype.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/itemwin.hxx>
+#include <svx/itextprovider.hxx>
+#include <svx/labelitemwindow.hxx>
+#include <svx/numvset.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <svx/rulritem.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/sdtaditm.hxx>
+#include <svx/sdtaitm.hxx>
+#include <svx/sdtakitm.hxx>
+#include <svx/srchdlg.hxx>
+#include <svx/strarray.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/svdoattr.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdtext.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdtypes.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svx3ditems.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/svxdllapi.h>
+#include <svx/unomid.hxx>
+#include <svx/view3d.hxx>
+#include <svx/viewpt3d.hxx>
+#include <svx/xcolit.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xenum.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xgrad.hxx>
+#include <svx/xit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xpoly.hxx>
+#include <svx/xtable.hxx>
+#include <uiobject.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/pch/precompiled_svxcore.cxx b/svx/inc/pch/precompiled_svxcore.cxx
new file mode 100644
index 000000000..0848af1b6
--- /dev/null
+++ b/svx/inc/pch/precompiled_svxcore.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "precompiled_svxcore.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/pch/precompiled_svxcore.hxx b/svx/inc/pch/precompiled_svxcore.hxx
new file mode 100644
index 000000000..1f963c6e9
--- /dev/null
+++ b/svx/inc/pch/precompiled_svxcore.hxx
@@ -0,0 +1,552 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2022-01-26 09:16:35 using:
+ ./bin/update_pch svx svxcore --cutoff=7 --exclude:system --include:module --exclude:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./svx/inc/pch/precompiled_svxcore.hxx "make svx.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <chrono>
+#include <cmath>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <deque>
+#include <float.h>
+#include <functional>
+#include <initializer_list>
+#include <iomanip>
+#include <limits.h>
+#include <limits>
+#include <map>
+#include <math.h>
+#include <memory>
+#include <mutex>
+#include <new>
+#include <numeric>
+#include <optional>
+#include <ostream>
+#include <set>
+#include <stack>
+#include <stddef.h>
+#include <string.h>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+#include <boost/optional/optional.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/ptree_fwd.hpp>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/diagnose.hxx>
+#include <osl/doublecheckedlocking.h>
+#include <osl/endian.h>
+#include <osl/file.hxx>
+#include <osl/getglobalmutex.hxx>
+#include <osl/interlck.h>
+#include <osl/mutex.h>
+#include <osl/mutex.hxx>
+#include <osl/process.h>
+#include <osl/time.h>
+#include <rtl/alloc.h>
+#include <rtl/character.hxx>
+#include <rtl/instance.hxx>
+#include <rtl/locale.h>
+#include <rtl/math.h>
+#include <rtl/math.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/strbuf.h>
+#include <rtl/string.h>
+#include <rtl/string.hxx>
+#include <rtl/stringconcat.hxx>
+#include <rtl/stringutils.hxx>
+#include <rtl/textcvt.h>
+#include <rtl/textenc.h>
+#include <rtl/unload.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <rtl/uuid.h>
+#include <sal/backtrace.hxx>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+#include <sal/saldllapi.h>
+#include <sal/types.h>
+#include <sal/typesizes.h>
+#include <vcl/AccessibleBrowseBoxObjType.hxx>
+#include <vcl/BinaryDataContainer.hxx>
+#include <vcl/BitmapColor.hxx>
+#include <vcl/GraphicAttributes.hxx>
+#include <vcl/GraphicExternalLink.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <vcl/Scanline.hxx>
+#include <vcl/alpha.hxx>
+#include <vcl/animate/Animation.hxx>
+#include <vcl/animate/AnimationBitmap.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmap/BitmapTypes.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/checksum.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/ctrl.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/dllapi.h>
+#include <vcl/dockwin.hxx>
+#include <vcl/errcode.hxx>
+#include <vcl/event.hxx>
+#include <vcl/fntstyle.hxx>
+#include <vcl/font.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/gfxlink.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/headbar.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/image.hxx>
+#include <vcl/mapmod.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/region.hxx>
+#include <vcl/scopedbitmapaccess.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/syswin.hxx>
+#include <vcl/task.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/toolboxid.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/vclenum.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/vectorgraphicdata.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/window.hxx>
+#include <vcl/windowstate.hxx>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <basegfx/basegfxdllapi.h>
+#include <basegfx/color/bcolor.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/point/b2ipoint.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b3dpolypolygon.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/range/b3drange.hxx>
+#include <basegfx/range/basicrange.hxx>
+#include <basegfx/tuple/Tuple2D.hxx>
+#include <basegfx/tuple/Tuple3D.hxx>
+#include <basegfx/tuple/b2dtuple.hxx>
+#include <basegfx/tuple/b2ituple.hxx>
+#include <basegfx/tuple/b3dtuple.hxx>
+#include <basegfx/utils/common.hxx>
+#include <basegfx/vector/b2dsize.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/vector/b2enums.hxx>
+#include <basegfx/vector/b2ivector.hxx>
+#include <basegfx/vector/b3dvector.hxx>
+#include <basic/basicdllapi.h>
+#include <basic/sbxcore.hxx>
+#include <basic/sbxdef.hxx>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/XFocusListener.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/beans/XPropertySetOption.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/beans/XVetoableChangeListener.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/datatransfer/XTransferable2.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp>
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/datatransfer/dnd/DropTargetDragEvent.hpp>
+#include <com/sun/star/datatransfer/dnd/DropTargetDropEvent.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragGestureListener.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSourceListener.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetListener.hpp>
+#include <com/sun/star/drawing/LineCap.hpp>
+#include <com/sun/star/drawing/NormalsKind.hpp>
+#include <com/sun/star/drawing/TextureKind2.hpp>
+#include <com/sun/star/drawing/TextureMode.hpp>
+#include <com/sun/star/drawing/TextureProjectionMode.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/frame/XToolbarController.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/graphic/XPrimitive2D.hpp>
+#include <com/sun/star/graphic/XPrimitive3D.hpp>
+#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/EventObject.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/text/textfield/Type.hpp>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Type.h>
+#include <com/sun/star/uno/Type.hxx>
+#include <com/sun/star/uno/TypeClass.hdl>
+#include <com/sun/star/uno/XAggregation.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/XWeak.hpp>
+#include <com/sun/star/uno/genfunc.h>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/XAccounting.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/util/XUpdatable.hpp>
+#include <com/sun/star/xml/sax/XFastAttributeList.hpp>
+#include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/compbase.hxx>
+#include <comphelper/comphelperdllapi.h>
+#include <comphelper/interfacecontainer2.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/multicontainer2.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propagg.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/propertycontainerhelper.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/propstate.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/uno3.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <cppu/cppudllapi.h>
+#include <cppu/unotype.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/compbase_ex.hxx>
+#include <cppuhelper/cppuhelperdllapi.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/implbase_ex.hxx>
+#include <cppuhelper/implbase_ex_post.hxx>
+#include <cppuhelper/implbase_ex_pre.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/weakagg.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+#include <drawinglayer/attribute/sdrallattribute3d.hxx>
+#include <drawinglayer/attribute/sdrfillattribute.hxx>
+#include <drawinglayer/attribute/sdrlineattribute.hxx>
+#include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
+#include <drawinglayer/attribute/sdrobjectattribute3d.hxx>
+#include <drawinglayer/attribute/sdrshadowattribute.hxx>
+#include <drawinglayer/drawinglayerdllapi.h>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/CommonTypes.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/Primitive2DContainer.hxx>
+#include <drawinglayer/primitive2d/Primitive2DVisitor.hxx>
+#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
+#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <drawinglayer/primitive3d/baseprimitive3d.hxx>
+#include <drawinglayer/primitive3d/sdrextrudelathetools3d.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/editengdllapi.h>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/eedata.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/svxenum.hxx>
+#include <editeng/udlnitem.hxx>
+#include <i18nlangtag/i18nlangtagdllapi.h>
+#include <i18nlangtag/lang.h>
+#include <i18nlangtag/languagetag.hxx>
+#include <libxml/xmlwriter.h>
+#include <o3tl/cow_wrapper.hxx>
+#include <o3tl/deleter.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/sorted_vector.hxx>
+#include <o3tl/span.hxx>
+#include <o3tl/strong_int.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <o3tl/underlyingenumvalue.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <salhelper/salhelperdllapi.h>
+#include <salhelper/simplereferenceobject.hxx>
+#include <salhelper/singletonref.hxx>
+#include <salhelper/thread.hxx>
+#include <sax/fastattribs.hxx>
+#include <sax/saxdllapi.h>
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/dllapi.h>
+#include <sfx2/objsh.hxx>
+#include <sfx2/shell.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <sot/sotdllapi.h>
+#include <svl/SfxBroadcaster.hxx>
+#include <svl/cenumitm.hxx>
+#include <svl/cintitem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/hint.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <svl/languageoptions.hxx>
+#include <svl/lstner.hxx>
+#include <svl/poolitem.hxx>
+#include <svl/style.hxx>
+#include <svl/svldllapi.h>
+#include <svl/typedwhich.hxx>
+#include <svl/undo.hxx>
+#include <svl/whiter.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <svtools/svtdllapi.h>
+#include <svtools/valueset.hxx>
+#include <toolkit/dllapi.h>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/UnitConversion.hxx>
+#include <tools/bigint.hxx>
+#include <tools/color.hxx>
+#include <tools/date.hxx>
+#include <tools/datetime.hxx>
+#include <tools/debug.hxx>
+#include <tools/degree.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/fldunit.hxx>
+#include <tools/fontenum.hxx>
+#include <tools/gen.hxx>
+#include <tools/globname.hxx>
+#include <tools/helpers.hxx>
+#include <tools/lineend.hxx>
+#include <tools/link.hxx>
+#include <tools/long.hxx>
+#include <tools/mapunit.hxx>
+#include <tools/poly.hxx>
+#include <tools/ref.hxx>
+#include <tools/solar.h>
+#include <tools/stream.hxx>
+#include <tools/time.hxx>
+#include <tools/toolsdllapi.h>
+#include <tools/urlobj.hxx>
+#include <tools/wintypes.hxx>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <typelib/uik.h>
+#include <uno/any2.h>
+#include <uno/data.h>
+#include <uno/sequence2.h>
+#include <unotools/configmgr.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/options.hxx>
+#include <unotools/resmgr.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/unotoolsdllapi.h>
+#include <xmloff/dllapi.h>
+#include <xmloff/families.hxx>
+#include <xmloff/xmltoken.hxx>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <cell.hxx>
+#include <fmobj.hxx>
+#include <fmpgeimp.hxx>
+#include <fmprop.hxx>
+#include <fmservs.hxx>
+#include <fmundo.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/e3dsceneupdater.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/fmtools.hxx>
+#include <svx/fmview.hxx>
+#include <svx/gallery1.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/ipolypolygoneditorcontroller.hxx>
+#include <svx/lathe3d.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/sdasitm.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sdr/animation/scheduler.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdr/overlay/overlayobject.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <svx/sdrhittesthelper.hxx>
+#include <svx/sdrobjectuser.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/sdtfchim.hxx>
+#include <svx/sdynitm.hxx>
+#include <svx/selectioncontroller.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svdedtv.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svdhlpln.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdlayer.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdmrkv.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdobjkind.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdpntv.hxx>
+#include <svx/svdpoev.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdsnpv.hxx>
+#include <svx/svdsob.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdtypes.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/svxdllapi.h>
+#include <svx/unoapi.hxx>
+#include <svx/unofill.hxx>
+#include <svx/unomid.hxx>
+#include <svx/unopage.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/unoshprp.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xpoly.hxx>
+#include <svx/xtable.hxx>
+#include <tablemodel.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/polygn3d.hxx b/svx/inc/polygn3d.hxx
new file mode 100644
index 000000000..5a4a234eb
--- /dev/null
+++ b/svx/inc/polygn3d.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <config_options.h>
+#include <svx/obj3d.hxx>
+#include <svx/svxdllapi.h>
+
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) E3dPolygonObj final : public E3dCompoundObject
+{
+ // parameters
+ basegfx::B3DPolyPolygon aPolyPoly3D;
+ basegfx::B3DPolyPolygon aPolyNormals3D;
+ basegfx::B2DPolyPolygon aPolyTexture2D;
+ bool bLineOnly;
+
+ SVX_DLLPRIVATE void CreateDefaultNormals();
+ SVX_DLLPRIVATE void CreateDefaultTexture();
+
+ virtual std::unique_ptr<sdr::contact::ViewContact> CreateObjectSpecificViewContact() override;
+
+ // protected destructor
+ virtual ~E3dPolygonObj() override;
+
+public:
+ void SetPolyPolygon3D(const basegfx::B3DPolyPolygon& rNewPolyPoly3D);
+ void SetPolyNormals3D(const basegfx::B3DPolyPolygon& rNewPolyPoly3D);
+ void SetPolyTexture2D(const basegfx::B2DPolyPolygon& rNewPolyPoly2D);
+
+ E3dPolygonObj(SdrModel& rSdrModel, const basegfx::B3DPolyPolygon& rPolyPoly3D);
+ E3dPolygonObj(SdrModel& rSdrModel);
+ E3dPolygonObj(SdrModel& rSdrModel, E3dPolygonObj const& rSource);
+
+ const basegfx::B3DPolyPolygon& GetPolyPolygon3D() const { return aPolyPoly3D; }
+ const basegfx::B3DPolyPolygon& GetPolyNormals3D() const { return aPolyNormals3D; }
+ const basegfx::B2DPolyPolygon& GetPolyTexture2D() const { return aPolyTexture2D; }
+
+ virtual SdrObjKind GetObjIdentifier() const override;
+ virtual SdrObjectUniquePtr DoConvertToPolyObj(bool bBezier, bool bAddText) const override;
+
+ virtual E3dPolygonObj* CloneSdrObject(SdrModel& rTargetModel) const override;
+
+ // LineOnly?
+ bool GetLineOnly() const { return bLineOnly; }
+ void SetLineOnly(bool bNew);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/rotationstrings.hrc b/svx/inc/rotationstrings.hrc
new file mode 100644
index 000000000..c4e8d2879
--- /dev/null
+++ b/svx/inc/rotationstrings.hrc
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SVX_INC_ROTATIONSTRINGS_HRC
+#define INCLUDED_SVX_INC_ROTATIONSTRINGS_HRC
+
+#include <unotools/resmgr.hxx>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+const TranslateId RID_SVXITEMS_ROTATE_MODE[] =
+{
+ // enum SvxRotateMode ----------------------------------------------------
+ NC_("RID_SVXITEMS_ROTATE_MODE_STANDARD", "Rotation only within cell"),
+ NC_("RID_SVXITEMS_ROTATE_MODE_TOP", "From upper cell edge"),
+ NC_("RID_SVXITEMS_ROTATE_MODE_CENTER", "From vertical middle cell"),
+ NC_("RID_SVXITEMS_ROTATE_MODE_BOTTOM", "From lower cell edge"),
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/samecontent.hrc b/svx/inc/samecontent.hrc
new file mode 100644
index 000000000..bb3afa499
--- /dev/null
+++ b/svx/inc/samecontent.hrc
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#ifndef INCLUDED_SVX_INC_SPACING_HRC
+#define INCLUDED_SVX_INC_SPACING_HRC
+
+#include <unotools/resmgr.hxx>
+
+#include <utility>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+const std::pair<TranslateId, int> RID_SVXSTRARY_SAMECONTENT[] =
+{
+ { NC_("RID_SVXSTRARY_SAMECONTENT", "All Pages"), 0 },
+ { NC_("RID_SVXSTRARY_SAMECONTENT", "First Page"), 1 },
+ { NC_("RID_SVXSTRARY_SAMECONTENT", "Left and Right Pages"), 2 },
+ { NC_("RID_SVXSTRARY_SAMECONTENT", "First, Left and Right Pages"), 3 }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/inc/sdgcoitm.hxx b/svx/inc/sdgcoitm.hxx
new file mode 100644
index 000000000..d49bad207
--- /dev/null
+++ b/svx/inc/sdgcoitm.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <config_options.h>
+#include <svx/sdprcitm.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svxdllapi.h>
+
+
+// SdrGrafRedItem -
+
+
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) SdrGrafRedItem final : public SdrSignedPercentItem
+{
+public:
+
+
+ SdrGrafRedItem( short nRedPercent = 0 ) : SdrSignedPercentItem( SDRATTR_GRAFRED, nRedPercent ) {}
+
+ virtual SdrGrafRedItem* Clone( SfxItemPool* pPool = nullptr ) const override;
+};
+
+
+// SdrGrafGreenItem -
+
+
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) SdrGrafGreenItem final : public SdrSignedPercentItem
+{
+public:
+
+
+ SdrGrafGreenItem( short nGreenPercent = 0 ) : SdrSignedPercentItem( SDRATTR_GRAFGREEN, nGreenPercent ) {}
+
+ virtual SdrGrafGreenItem* Clone( SfxItemPool* pPool = nullptr ) const override;
+};
+
+
+// SdrGrafBlueItem -
+
+
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) SdrGrafBlueItem final : public SdrSignedPercentItem
+{
+public:
+
+
+ SdrGrafBlueItem( short nBluePercent = 0 ) : SdrSignedPercentItem( SDRATTR_GRAFBLUE, nBluePercent ) {}
+
+ virtual SdrGrafBlueItem* Clone( SfxItemPool* pPool = nullptr ) const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdginitm.hxx b/svx/inc/sdginitm.hxx
new file mode 100644
index 000000000..35cfa3da7
--- /dev/null
+++ b/svx/inc/sdginitm.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/sdooitm.hxx>
+#include <svx/svddef.hxx>
+
+
+// SdrGrafInvertItem -
+
+
+class SdrGrafInvertItem final : public SdrOnOffItem
+{
+public:
+
+
+ SdrGrafInvertItem( bool bInvert = false ) : SdrOnOffItem( SDRATTR_GRAFINVERT, bInvert ) {}
+
+ virtual SdrGrafInvertItem* Clone( SfxItemPool* pPool = nullptr ) const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdgtritm.hxx b/svx/inc/sdgtritm.hxx
new file mode 100644
index 000000000..084ac6944
--- /dev/null
+++ b/svx/inc/sdgtritm.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <config_options.h>
+#include <svx/sdprcitm.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svxdllapi.h>
+
+
+// SdrGrafTransparenceItem -
+
+
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) SdrGrafTransparenceItem final : public SdrPercentItem
+{
+public:
+
+ SdrGrafTransparenceItem( sal_uInt16 nTransparencePercent = 0 ) : SdrPercentItem( SDRATTR_GRAFTRANSPARENCE, nTransparencePercent ) {}
+
+ virtual SdrGrafTransparenceItem* Clone( SfxItemPool* pPool = nullptr ) const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/attribute/sdreffectstextattribute.hxx b/svx/inc/sdr/attribute/sdreffectstextattribute.hxx
new file mode 100644
index 000000000..e1826552d
--- /dev/null
+++ b/svx/inc/sdr/attribute/sdreffectstextattribute.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <drawinglayer/attribute/sdrshadowattribute.hxx>
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
+
+
+namespace drawinglayer::attribute
+ {
+ class SdrEffectsTextAttribute
+ {
+ // shadow and text attributes
+ SdrShadowAttribute maShadow; // shadow attributes (if used)
+ SdrTextAttribute maTextAttribute; // text and text attributes (if used)
+
+ // glow effect
+ SdrGlowAttribute maGlow;
+
+ // soft edge
+ sal_Int32 mnSoftEdgeRadius = 0;
+
+ public:
+ SdrEffectsTextAttribute(
+ const SdrShadowAttribute& rShadow,
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow,
+ sal_Int32 nSoftEdgeRadius);
+ SdrEffectsTextAttribute();
+ SdrEffectsTextAttribute(const SdrEffectsTextAttribute& rCandidate);
+ SdrEffectsTextAttribute& operator=(const SdrEffectsTextAttribute& rCandidate);
+
+ // checks if the incarnation is default constructed
+ bool isDefault() const;
+
+ // compare operator
+ bool operator==(const SdrEffectsTextAttribute& rCandidate) const;
+
+ // data access
+ const SdrShadowAttribute& getShadow() const { return maShadow; }
+ const SdrTextAttribute& getText() const { return maTextAttribute; }
+ const SdrGlowAttribute& getGlow() const { return maGlow; }
+ sal_Int32 getSoftEdgeRadius() const { return mnSoftEdgeRadius; }
+ };
+
+} // end of namespace drawinglayer::attribute
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/attribute/sdrfilltextattribute.hxx b/svx/inc/sdr/attribute/sdrfilltextattribute.hxx
new file mode 100644
index 000000000..3bb66c809
--- /dev/null
+++ b/svx/inc/sdr/attribute/sdrfilltextattribute.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_ATTRIBUTE_SDRFILLTEXTATTRIBUTE_HXX
+#define INCLUDED_SVX_INC_SDR_ATTRIBUTE_SDRFILLTEXTATTRIBUTE_HXX
+
+#include <drawinglayer/attribute/sdrfillattribute.hxx>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+#include <sdr/attribute/sdrtextattribute.hxx>
+
+
+namespace drawinglayer::attribute
+ {
+ class SdrFillTextAttribute
+ {
+ // shadow and text attributes
+ SdrFillAttribute maFill; // fill attributes (if used)
+ FillGradientAttribute maFillFloatTransGradient; // fill float transparence gradient (if used)
+ SdrTextAttribute maTextAttribute; // text and text attributes (if used)
+
+ public:
+ SdrFillTextAttribute(
+ const SdrFillAttribute& rFill,
+ const FillGradientAttribute& rFillFloatTransGradient,
+ const SdrTextAttribute& rTextAttribute);
+ SdrFillTextAttribute();
+ SdrFillTextAttribute(const SdrFillTextAttribute& rCandidate);
+ SdrFillTextAttribute& operator=(const SdrFillTextAttribute& rCandidate);
+
+ // compare operator
+ bool operator==(const SdrFillTextAttribute& rCandidate) const;
+
+ // data access
+ const SdrFillAttribute& getFill() const { return maFill; }
+ const FillGradientAttribute& getFillFloatTransGradient() const { return maFillFloatTransGradient; }
+ const SdrTextAttribute& getText() const { return maTextAttribute; }
+ };
+
+} // end of namespace drawinglayer::attribute
+
+
+#endif // INCLUDED_SVX_INC_SDR_ATTRIBUTE_SDRFILLTEXTATTRIBUTE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/attribute/sdrformtextattribute.hxx b/svx/inc/sdr/attribute/sdrformtextattribute.hxx
new file mode 100644
index 000000000..7167bf615
--- /dev/null
+++ b/svx/inc/sdr/attribute/sdrformtextattribute.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <svx/xenum.hxx>
+#include <tools/color.hxx>
+#include <o3tl/cow_wrapper.hxx>
+
+// predefines
+
+class SfxItemSet;
+
+namespace drawinglayer::attribute {
+ class ImpSdrFormTextAttribute;
+ class SdrFormTextOutlineAttribute;
+}
+
+
+namespace drawinglayer::attribute
+ {
+ class SdrFormTextAttribute
+ {
+ public:
+ typedef o3tl::cow_wrapper< ImpSdrFormTextAttribute > ImplType;
+
+ private:
+ ImplType mpSdrFormTextAttribute;
+
+ public:
+ /// constructors/assignmentoperator/destructor
+ SdrFormTextAttribute(const SfxItemSet& rSet);
+ SdrFormTextAttribute();
+ SdrFormTextAttribute(const SdrFormTextAttribute& rCandidate);
+ SdrFormTextAttribute(SdrFormTextAttribute&& rCandidate) noexcept;
+ SdrFormTextAttribute& operator=(const SdrFormTextAttribute& rCandidate);
+ SdrFormTextAttribute& operator=(SdrFormTextAttribute&& rCandidate) noexcept;
+ ~SdrFormTextAttribute();
+
+ // checks if the incarnation is default constructed
+ bool isDefault() const;
+
+ // compare operator
+ bool operator==(const SdrFormTextAttribute& rCandidate) const;
+
+ // data read access
+ sal_Int32 getFormTextDistance() const;
+ sal_Int32 getFormTextStart() const;
+ sal_Int32 getFormTextShdwXVal() const;
+ sal_Int32 getFormTextShdwYVal() const;
+ XFormTextStyle getFormTextStyle() const;
+ XFormTextAdjust getFormTextAdjust() const;
+ XFormTextShadow getFormTextShadow() const;
+ Color const & getFormTextShdwColor() const;
+ const SdrFormTextOutlineAttribute& getOutline() const;
+ const SdrFormTextOutlineAttribute& getShadowOutline() const;
+ bool getFormTextMirror() const;
+ bool getFormTextOutline() const;
+ };
+
+} // end of namespace drawinglayer::attribute
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/attribute/sdrformtextoutlineattribute.hxx b/svx/inc/sdr/attribute/sdrformtextoutlineattribute.hxx
new file mode 100644
index 000000000..34086c2c8
--- /dev/null
+++ b/svx/inc/sdr/attribute/sdrformtextoutlineattribute.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_ATTRIBUTE_SDRFORMTEXTOUTLINEATTRIBUTE_HXX
+#define INCLUDED_SVX_INC_SDR_ATTRIBUTE_SDRFORMTEXTOUTLINEATTRIBUTE_HXX
+
+#include <sal/types.h>
+#include <o3tl/cow_wrapper.hxx>
+
+// predefines
+
+namespace drawinglayer::attribute {
+ class ImpSdrFormTextOutlineAttribute;
+ class LineAttribute;
+ class StrokeAttribute;
+}
+
+
+namespace drawinglayer::attribute
+ {
+ class SdrFormTextOutlineAttribute
+ {
+ public:
+ typedef o3tl::cow_wrapper< ImpSdrFormTextOutlineAttribute > ImplType;
+
+ private:
+ ImplType mpSdrFormTextOutlineAttribute;
+
+ public:
+ /// constructors/assignmentoperator/destructor
+ SdrFormTextOutlineAttribute(
+ const LineAttribute& rLineAttribute,
+ const StrokeAttribute& rStrokeAttribute,
+ sal_uInt8 nTransparence);
+ SdrFormTextOutlineAttribute();
+ SdrFormTextOutlineAttribute(const SdrFormTextOutlineAttribute& rCandidate);
+ SdrFormTextOutlineAttribute& operator=(const SdrFormTextOutlineAttribute& rCandidate);
+ SdrFormTextOutlineAttribute& operator=(SdrFormTextOutlineAttribute&& rCandidate) noexcept;
+ ~SdrFormTextOutlineAttribute();
+
+ // checks if the incarnation is default constructed
+ bool isDefault() const;
+
+ // compare operator
+ bool operator==(const SdrFormTextOutlineAttribute& rCandidate) const;
+
+ // data read access
+ const LineAttribute& getLineAttribute() const;
+ const StrokeAttribute& getStrokeAttribute() const;
+ sal_uInt8 getTransparence() const;
+ };
+
+} // end of namespace drawinglayer::attribute
+
+
+#endif // INCLUDED_SVX_INC_SDR_ATTRIBUTE_SDRFORMTEXTOUTLINEATTRIBUTE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/attribute/sdrlineeffectstextattribute.hxx b/svx/inc/sdr/attribute/sdrlineeffectstextattribute.hxx
new file mode 100644
index 000000000..1e7f694c7
--- /dev/null
+++ b/svx/inc/sdr/attribute/sdrlineeffectstextattribute.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdr/attribute/sdreffectstextattribute.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
+#include <drawinglayer/attribute/sdrlineattribute.hxx>
+#include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
+
+
+namespace drawinglayer::attribute
+ {
+ class SdrLineEffectsTextAttribute : public SdrEffectsTextAttribute
+ {
+ // line, shadow, lineStartEnd and text attributes
+ SdrLineAttribute maLine; // line attributes (if used)
+ SdrLineStartEndAttribute maLineStartEnd; // line start end (if used)
+
+ public:
+ SdrLineEffectsTextAttribute(
+ const SdrLineAttribute& rLine,
+ const SdrLineStartEndAttribute& rLineStartEnd,
+ const SdrShadowAttribute& rShadow,
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow,
+ sal_Int32 nSoftEdgeRadius);
+ SdrLineEffectsTextAttribute();
+ SdrLineEffectsTextAttribute(const SdrLineEffectsTextAttribute& rCandidate);
+ SdrLineEffectsTextAttribute& operator=(const SdrLineEffectsTextAttribute& rCandidate);
+
+ // checks if the incarnation is default constructed
+ bool isDefault() const;
+
+ // compare operator
+ bool operator==(const SdrLineEffectsTextAttribute& rCandidate) const;
+
+ // data access
+ const SdrLineAttribute& getLine() const { return maLine; }
+ const SdrLineStartEndAttribute& getLineStartEnd() const { return maLineStartEnd; }
+ };
+
+} // end of namespace drawinglayer::attribute
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/attribute/sdrlinefilleffectstextattribute.hxx b/svx/inc/sdr/attribute/sdrlinefilleffectstextattribute.hxx
new file mode 100644
index 000000000..7bb85e897
--- /dev/null
+++ b/svx/inc/sdr/attribute/sdrlinefilleffectstextattribute.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdr/attribute/sdrlineeffectstextattribute.hxx>
+#include <drawinglayer/attribute/sdrfillattribute.hxx>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+
+
+namespace drawinglayer::attribute
+ {
+ class SdrLineFillEffectsTextAttribute : public SdrLineEffectsTextAttribute
+ {
+ // add fill and transGradient attributes
+ SdrFillAttribute maFill; // fill attributes (if used)
+ FillGradientAttribute maFillFloatTransGradient; // fill float transparence gradient (if used)
+
+ public:
+ SdrLineFillEffectsTextAttribute(
+ const SdrLineAttribute& rLine,
+ const SdrFillAttribute& rFill,
+ const SdrLineStartEndAttribute& rLineStartEnd,
+ const SdrShadowAttribute& rShadow,
+ const FillGradientAttribute& rFillFloatTransGradient,
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow,
+ sal_Int32 nSoftEdgeRadius);
+ SdrLineFillEffectsTextAttribute();
+ SdrLineFillEffectsTextAttribute(const SdrLineFillEffectsTextAttribute& rCandidate);
+ SdrLineFillEffectsTextAttribute& operator=(const SdrLineFillEffectsTextAttribute& rCandidate);
+
+ // checks if the incarnation is default constructed
+ bool isDefault() const;
+
+ // compare operator
+ bool operator==(const SdrLineFillEffectsTextAttribute& rCandidate) const;
+
+ // data access
+ const SdrFillAttribute& getFill() const { return maFill; }
+ const FillGradientAttribute& getFillFloatTransGradient() const { return maFillFloatTransGradient; }
+ };
+
+} // end of namespace drawinglayer::attribute
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/attribute/sdrtextattribute.hxx b/svx/inc/sdr/attribute/sdrtextattribute.hxx
new file mode 100644
index 000000000..19b52d611
--- /dev/null
+++ b/svx/inc/sdr/attribute/sdrtextattribute.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <svx/xenum.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/sdtaitm.hxx>
+#include <o3tl/cow_wrapper.hxx>
+
+// predefines
+
+class SdrText;
+namespace drawinglayer::animation { class AnimationEntryList; }
+namespace drawinglayer::attribute { class SdrFormTextAttribute; }
+namespace drawinglayer::attribute { class ImpSdrTextAttribute; }
+
+
+namespace drawinglayer::attribute
+ {
+ class SdrTextAttribute
+ {
+ public:
+ typedef o3tl::cow_wrapper< ImpSdrTextAttribute > ImplType;
+
+ private:
+ ImplType mpSdrTextAttribute;
+
+ public:
+ /// constructors/assignmentoperator/destructor
+ SdrTextAttribute(
+ const SdrText& rSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ XFormTextStyle eFormTextStyle,
+ sal_Int32 aTextLeftDistance,
+ sal_Int32 aTextUpperDistance,
+ sal_Int32 aTextRightDistance,
+ sal_Int32 aTextLowerDistance,
+ SdrTextHorzAdjust aSdrTextHorzAdjust,
+ SdrTextVertAdjust aSdrTextVertAdjust,
+ bool bContour,
+ bool bFitToSize,
+ bool bAutoFit,
+ bool bHideContour,
+ bool bBlink,
+ bool bScroll,
+ bool bInEditMode,
+ bool bFixedCellHeight,
+ bool bWrongSpell,
+ bool bChainable);
+
+ SdrTextAttribute();
+ SdrTextAttribute(const SdrTextAttribute& rCandidate);
+ SdrTextAttribute(SdrTextAttribute&& rCandidate) noexcept;
+ SdrTextAttribute& operator=(const SdrTextAttribute& rCandidate);
+ SdrTextAttribute& operator=(SdrTextAttribute&& rCandidate) noexcept;
+ ~SdrTextAttribute();
+
+ // checks if the incarnation is default constructed
+ bool isDefault() const;
+
+ // compare operator
+ bool operator==(const SdrTextAttribute& rCandidate) const;
+
+ // data read access
+ const SdrText& getSdrText() const;
+ const OutlinerParaObject& getOutlinerParaObject() const;
+ bool isContour() const;
+ bool isFitToSize() const;
+ bool isAutoFit() const;
+ bool isHideContour() const;
+ bool isBlink() const;
+ bool isScroll() const;
+ bool isInEditMode() const;
+ bool isFixedCellHeight() const;
+ const SdrFormTextAttribute& getSdrFormTextAttribute() const;
+ sal_Int32 getTextLeftDistance() const;
+ sal_Int32 getTextUpperDistance() const;
+ sal_Int32 getTextRightDistance() const;
+ sal_Int32 getTextLowerDistance() const;
+ SdrTextHorzAdjust getSdrTextHorzAdjust() const;
+ SdrTextVertAdjust getSdrTextVertAdjust() const;
+
+ bool isChainable() const;
+
+
+ // helpers: animation timing generators
+ void getBlinkTextTiming(
+ drawinglayer::animation::AnimationEntryList& rAnimList) const;
+ void getScrollTextTiming(
+ drawinglayer::animation::AnimationEntryList& rAnimList,
+ double fFrameLength,
+ double fTextLength) const;
+ };
+
+} // end of namespace drawinglayer::attribute
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/objectcontactofobjlistpainter.hxx b/svx/inc/sdr/contact/objectcontactofobjlistpainter.hxx
new file mode 100644
index 000000000..af72593ad
--- /dev/null
+++ b/svx/inc/sdr/contact/objectcontactofobjlistpainter.hxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <config_options.h>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/svxdllapi.h>
+#include <svx/svdpage.hxx>
+#include <unotools/weakref.hxx>
+
+class SdrPage;
+class SdrObject;
+
+namespace sdr::contact {
+
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) ObjectContactPainter : public ObjectContact
+{
+protected:
+ // Hierarchy access methods
+ virtual sal_uInt32 GetPaintObjectCount() const = 0;
+ virtual ViewContact& GetPaintObjectViewContact(sal_uInt32 nIndex) = 0;
+
+public:
+ // basic constructor/destructor
+ ObjectContactPainter();
+ virtual ~ObjectContactPainter() override;
+};
+
+// typedef for transferring SdrObject
+typedef ::std::vector< SdrObject* > SdrObjectVector;
+
+class SVXCORE_DLLPUBLIC ObjectContactOfObjListPainter final : public ObjectContactPainter
+{
+ // Target OutputDevice
+ OutputDevice& mrTargetOutputDevice;
+
+ // Set StartPoint for next run, also given in constructor
+ SdrObjectVector maStartObjects;
+
+ // the processed page which is the base e.g. for PageNumberFields
+ const SdrPage* mpProcessedPage;
+
+ // Hierarchy access methods
+ virtual sal_uInt32 GetPaintObjectCount() const override;
+ virtual ViewContact& GetPaintObjectViewContact(sal_uInt32 nIndex) override;
+
+public:
+ // basic constructor/destructor
+ ObjectContactOfObjListPainter(
+ OutputDevice& rTargetDevice,
+ SdrObjectVector&& rObjects,
+ const SdrPage* pProcessedPage);
+ virtual ~ObjectContactOfObjListPainter() override;
+
+ // Process the whole displaying
+ virtual void ProcessDisplay(DisplayInfo& rDisplayInfo) override;
+
+ // recording MetaFile? Default is false
+ virtual bool isOutputToRecordingMetaFile() const override;
+
+ // pdf export? Default is false
+ virtual bool isOutputToPDFFile() const override;
+ virtual bool isExportTaggedPDF() const override;
+
+ virtual OutputDevice* TryToGetOutputDevice() const override;
+};
+
+class ObjectContactOfPagePainter : public ObjectContactPainter
+{
+ // the original ObjectContact this painter is working on
+ ObjectContact& mrOriginalObjectContact;
+
+ // Set StartPoint for next run, also given in constructor
+ unotools::WeakReference<SdrPage> mxStartPage;
+
+protected:
+ // Hierarchy access methods
+ virtual sal_uInt32 GetPaintObjectCount() const override;
+ virtual ViewContact& GetPaintObjectViewContact(sal_uInt32 nIndex) override;
+
+public:
+ // basic constructor
+ ObjectContactOfPagePainter(ObjectContact& rOriginalObjectContact);
+ virtual ~ObjectContactOfPagePainter() override;
+
+ // set another page
+ void SetStartPage(const SdrPage* pPage);
+ const SdrPage* GetStartPage() const { return mxStartPage.get().get(); }
+ SdrPage* GetStartPage() { return mxStartPage.get().get(); }
+
+ virtual OutputDevice* TryToGetOutputDevice() const override;
+};
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofe3d.hxx b/svx/inc/sdr/contact/viewcontactofe3d.hxx
new file mode 100644
index 000000000..553407deb
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofe3d.hxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/obj3d.hxx>
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+#include <drawinglayer/primitive3d/baseprimitive3d.hxx>
+
+namespace drawinglayer::attribute
+{
+class SdrLineAttribute;
+}
+namespace basegfx
+{
+class BColor;
+class B3DHomMatrix;
+}
+
+namespace sdr::contact
+{
+class ViewContactOfE3dScene;
+
+class ViewContactOfE3d : public ViewContactOfSdrObj
+{
+protected:
+ // Create an Object-Specific ViewObjectContact, set ViewContact and
+ // ObjectContact. Always needs to return something.
+ virtual ViewObjectContact&
+ CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+
+public:
+ // basic constructor, used from E3dObject.
+ explicit ViewContactOfE3d(E3dObject& rObj);
+ virtual ~ViewContactOfE3d() override;
+
+ // access to E3dObject
+ const E3dObject& GetE3dObject() const { return static_cast<const E3dObject&>(GetSdrObject()); }
+
+ // public helpers
+ drawinglayer::primitive2d::Primitive2DContainer impCreateWithGivenPrimitive3DContainer(
+ const drawinglayer::primitive3d::Primitive3DContainer& rxContent3D) const;
+
+ // primitive stuff
+
+ // Primitive3DContainer of the ViewContact. This contains all necessary information
+ // for the graphical visualisation and needs to be supported by all 3D VCs which
+ // can be visualized. It does NOT contain the object transformation to be able to
+ // buffer for all possible usages
+ drawinglayer::primitive3d::Primitive3DContainer mxViewIndependentPrimitive3DContainer;
+
+protected:
+ // This method is responsible for creating the graphical visualisation data which is
+ // stored in mxViewIndependentPrimitive3DContainer, but without object transformation
+ virtual drawinglayer::primitive3d::Primitive3DContainer
+ createViewIndependentPrimitive3DContainer() const = 0;
+
+ // This method is responsible for creating the graphical visualisation data derived ONLY from
+ // the model data. The default implementation will try to create a 3D to 2D embedding (will work
+ // when scene is known) which can then be used for 2D processing concerning ranges
+ virtual void createViewIndependentPrimitive2DSequence(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ // access to the local primitive without the object's local 3D transform. This is e.g. needed
+ // to get the not-yet transformed BoundVolume for e.g. interactions
+ drawinglayer::primitive3d::Primitive3DContainer const& getVIP3DSWithoutObjectTransform() const;
+
+ // access to the local primitive. This will ensure that the list is
+ // current in comparing the local list content with a fresh created incarnation. It will
+ // use getVIP3DSWithoutObjectTransform and embed to 3d transform primitive when object's
+ // local 3d transform is used
+ drawinglayer::primitive3d::Primitive3DContainer getViewIndependentPrimitive3DContainer() const;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofe3dcube.hxx b/svx/inc/sdr/contact/viewcontactofe3dcube.hxx
new file mode 100644
index 000000000..5f9a6e4a1
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofe3dcube.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DCUBE_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DCUBE_HXX
+
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <svx/cube3d.hxx>
+
+namespace sdr::contact
+ {
+ class ViewContactOfE3dCube final : public ViewContactOfE3d
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ ViewContactOfE3dCube(E3dCubeObj& rCubeObj);
+ virtual ~ViewContactOfE3dCube() override;
+
+ // access to SdrObject
+ const E3dCubeObj& GetE3dCubeObj() const
+ {
+ return static_cast<const E3dCubeObj&>(GetE3dObject());
+ }
+
+ private:
+ // This method is responsible for creating the graphical visualisation data which is
+ // stored in the local primitive list. Default creates a yellow replacement rectangle.
+ virtual drawinglayer::primitive3d::Primitive3DContainer createViewIndependentPrimitive3DContainer() const override;
+ };
+
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DCUBE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofe3dextrude.hxx b/svx/inc/sdr/contact/viewcontactofe3dextrude.hxx
new file mode 100644
index 000000000..c31accc2d
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofe3dextrude.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DEXTRUDE_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DEXTRUDE_HXX
+
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <extrud3d.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewContactOfE3dExtrude final : public ViewContactOfE3d
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfE3dExtrude(E3dExtrudeObj& rExtrude);
+ virtual ~ViewContactOfE3dExtrude() override;
+
+ // access to SdrObject
+ const E3dExtrudeObj& GetE3dExtrudeObj() const
+ {
+ return static_cast<const E3dExtrudeObj&>(GetE3dObject());
+ }
+
+ private:
+ // This method is responsible for creating the graphical visualisation data which is
+ // stored in the local primitive list. Default creates a yellow replacement rectangle.
+ virtual drawinglayer::primitive3d::Primitive3DContainer createViewIndependentPrimitive3DContainer() const override;
+ };
+
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DEXTRUDE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofe3dlathe.hxx b/svx/inc/sdr/contact/viewcontactofe3dlathe.hxx
new file mode 100644
index 000000000..d90b33dae
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofe3dlathe.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DLATHE_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DLATHE_HXX
+
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <svx/lathe3d.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewContactOfE3dLathe final : public ViewContactOfE3d
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfE3dLathe(E3dLatheObj& rLathe);
+ virtual ~ViewContactOfE3dLathe() override;
+
+ // access to SdrObject
+ const E3dLatheObj& GetE3dLatheObj() const
+ {
+ return static_cast<const E3dLatheObj&>(GetE3dObject());
+ }
+
+ private:
+ // This method is responsible for creating the graphical visualisation data which is
+ // stored in the local primitive list. Default creates a yellow replacement rectangle.
+ virtual drawinglayer::primitive3d::Primitive3DContainer createViewIndependentPrimitive3DContainer() const override;
+ };
+
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DLATHE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofe3dpolygon.hxx b/svx/inc/sdr/contact/viewcontactofe3dpolygon.hxx
new file mode 100644
index 000000000..bc907451c
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofe3dpolygon.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DPOLYGON_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DPOLYGON_HXX
+
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <polygn3d.hxx>
+
+namespace sdr::contact
+ {
+ class ViewContactOfE3dPolygon final : public ViewContactOfE3d
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfE3dPolygon(E3dPolygonObj& rPolygon);
+ virtual ~ViewContactOfE3dPolygon() override;
+
+ // access to SdrObject
+ const E3dPolygonObj& GetE3dPolygonObj() const
+ {
+ return static_cast<const E3dPolygonObj&>(GetE3dObject());
+ }
+
+ // This method is responsible for creating the graphical visualisation data which is
+ // stored in the local primitive list. Default creates a yellow replacement rectangle.
+ virtual drawinglayer::primitive3d::Primitive3DContainer createViewIndependentPrimitive3DContainer() const override;
+ };
+
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DPOLYGON_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofe3dsphere.hxx b/svx/inc/sdr/contact/viewcontactofe3dsphere.hxx
new file mode 100644
index 000000000..3bd58dcce
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofe3dsphere.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DSPHERE_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DSPHERE_HXX
+
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <svx/sphere3d.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewContactOfE3dSphere final : public ViewContactOfE3d
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfE3dSphere(E3dSphereObj& rSphere);
+ virtual ~ViewContactOfE3dSphere() override;
+
+ // access to SdrObject
+ const E3dSphereObj& GetE3dSphereObj() const
+ {
+ return static_cast<const E3dSphereObj&>(GetE3dObject());
+ }
+
+ private:
+ // This method is responsible for creating the graphical visualisation data which is
+ // stored in the local primitive list. Default creates a yellow replacement rectangle.
+ virtual drawinglayer::primitive3d::Primitive3DContainer createViewIndependentPrimitive3DContainer() const override;
+ };
+
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFE3DSPHERE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofgraphic.hxx b/svx/inc/sdr/contact/viewcontactofgraphic.hxx
new file mode 100644
index 000000000..bf3ecabcd
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofgraphic.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFGRAPHIC_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFGRAPHIC_HXX
+
+#include <sdr/contact/viewcontactoftextobj.hxx>
+#include <svx/svdograf.hxx>
+
+namespace drawinglayer::attribute { class SdrLineFillEffectsTextAttribute; }
+class GraphicAttr;
+
+namespace sdr::contact
+ {
+ class ViewContactOfGraphic final : public ViewContactOfTextObj
+ {
+ private:
+ // helpers for constructing various primitive visualisations in various states
+ drawinglayer::primitive2d::Primitive2DContainer createVIP2DSForPresObj(
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute& rAttribute) const;
+ drawinglayer::primitive2d::Primitive2DContainer createVIP2DSForDraft(
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute& rAttribute) const;
+
+ // Create an Object-Specific ViewObjectContact, set ViewContact and
+ // ObjectContact. Always needs to return something.
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+
+ public:
+ // access to SdrObject
+ const SdrGrafObj& GetGrafObject() const
+ {
+ return static_cast<const SdrGrafObj&>(GetSdrObject());
+ }
+ SdrGrafObj& GetGrafObject()
+ {
+ return static_cast<SdrGrafObj&>(GetSdrObject());
+ }
+
+ // basic constructor, destructor
+ explicit ViewContactOfGraphic(SdrGrafObj& rGrafObj);
+ virtual ~ViewContactOfGraphic() override;
+
+ // helpers for visualisation state
+ bool visualisationUsesPresObj() const;
+ bool visualisationUsesDraft() const;
+
+ private:
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+} // end of namespace sdr::contact
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFGRAPHIC_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofgroup.hxx b/svx/inc/sdr/contact/viewcontactofgroup.hxx
new file mode 100644
index 000000000..de1b4aa7f
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofgroup.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFGROUP_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFGROUP_HXX
+
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+#include <svx/svdogrp.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewContactOfGroup final : public ViewContactOfSdrObj
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfGroup(SdrObjGroup& rGroup);
+ virtual ~ViewContactOfGroup() override;
+
+ private:
+ // Create an Object-Specific ViewObjectContact, set ViewContact and
+ // ObjectContact. Always needs to return something. Default is to create
+ // a standard ViewObjectContact containing the given ObjectContact and *this
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+
+ // internal access to SdrObject
+ const SdrObjGroup& GetSdrObjGroup() const
+ {
+ return static_cast<const SdrObjGroup&>(GetSdrObject());
+ }
+
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFGROUP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofmasterpagedescriptor.hxx b/svx/inc/sdr/contact/viewcontactofmasterpagedescriptor.hxx
new file mode 100644
index 000000000..9d6f86f09
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofmasterpagedescriptor.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFMASTERPAGEDESCRIPTOR_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFMASTERPAGEDESCRIPTOR_HXX
+
+#include <sal/types.h>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdrmasterpagedescriptor.hxx>
+
+class SfxItemSet;
+class Bitmap;
+class MapMode;
+
+namespace sdr::contact
+ {
+ class ViewContactOfMasterPageDescriptor final : public ViewContact
+ {
+ // the owner of this ViewContact. Set from constructor and not
+ // to be changed in any way.
+ sdr::MasterPageDescriptor& mrMasterPageDescriptor;
+
+ // Create an Object-Specific ViewObjectContact
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+
+ // This method is responsible for creating the graphical visualisation data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ // basic constructor
+ explicit ViewContactOfMasterPageDescriptor(sdr::MasterPageDescriptor& rDescriptor);
+
+ // The destructor.
+ virtual ~ViewContactOfMasterPageDescriptor() override;
+
+ // access to MasterPageDescriptor
+ sdr::MasterPageDescriptor& GetMasterPageDescriptor() const
+ {
+ return mrMasterPageDescriptor;
+ }
+
+ // Access to possible sub-hierarchy and parent
+ virtual sal_uInt32 GetObjectCount() const override;
+ virtual ViewContact& GetViewContact(sal_uInt32 nIndex) const override;
+ virtual ViewContact* GetParentContact() const override;
+ };
+
+} // end of namespace sdr::contact
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFMASTERPAGEDESCRIPTOR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofpageobj.hxx b/svx/inc/sdr/contact/viewcontactofpageobj.hxx
new file mode 100644
index 000000000..672d42042
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofpageobj.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+#include <svx/svdopage.hxx>
+
+class SdrPage;
+
+namespace sdr::contact
+{
+class ViewContactOfPageObj final : public ViewContactOfSdrObj
+{
+ // Create an Object-Specific ViewObjectContact, set ViewContact and
+ // ObjectContact. Always needs to return something.
+ virtual ViewObjectContact&
+ CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+
+ // create graphical visualisation data
+ virtual void createViewIndependentPrimitive2DSequence(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfPageObj(SdrPageObj& rPageObj);
+ virtual ~ViewContactOfPageObj() override;
+
+ // #WIP# React on changes of the object of this ViewContact
+ virtual void ActionChanged() override;
+
+ // access to SdrObject
+ const SdrPageObj& GetPageObj() const { return static_cast<const SdrPageObj&>(GetSdrObject()); }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofsdrcaptionobj.hxx b/svx/inc/sdr/contact/viewcontactofsdrcaptionobj.hxx
new file mode 100644
index 000000000..d39758be3
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofsdrcaptionobj.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRCAPTIONOBJ_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRCAPTIONOBJ_HXX
+
+#include <sdr/contact/viewcontactofsdrrectobj.hxx>
+#include <svx/svdocapt.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewContactOfSdrCaptionObj final : public ViewContactOfSdrRectObj
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfSdrCaptionObj(SdrCaptionObj& rCaptionObj);
+ virtual ~ViewContactOfSdrCaptionObj() override;
+
+ private:
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRCAPTIONOBJ_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofsdrcircobj.hxx b/svx/inc/sdr/contact/viewcontactofsdrcircobj.hxx
new file mode 100644
index 000000000..281cad956
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofsdrcircobj.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRCIRCOBJ_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRCIRCOBJ_HXX
+
+#include <sdr/contact/viewcontactofsdrrectobj.hxx>
+#include <svx/svdocirc.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewContactOfSdrCircObj final : public ViewContactOfSdrRectObj
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfSdrCircObj(SdrCircObj& rCircObj);
+ virtual ~ViewContactOfSdrCircObj() override;
+
+ private:
+ // internal access to SdrCircObj
+ const SdrCircObj& GetCircObj() const
+ {
+ return static_cast<const SdrCircObj&>(GetSdrObject());
+ }
+
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRCIRCOBJ_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofsdredgeobj.hxx b/svx/inc/sdr/contact/viewcontactofsdredgeobj.hxx
new file mode 100644
index 000000000..24ed40285
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofsdredgeobj.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDREDGEOBJ_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDREDGEOBJ_HXX
+
+#include <sdr/contact/viewcontactoftextobj.hxx>
+#include <svx/svdoedge.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewContactOfSdrEdgeObj final : public ViewContactOfTextObj
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfSdrEdgeObj(SdrEdgeObj& rEdgeObj);
+ virtual ~ViewContactOfSdrEdgeObj() override;
+
+ private:
+ // internal access to SdrEdgeObj
+ const SdrEdgeObj& GetEdgeObj() const
+ {
+ return static_cast<const SdrEdgeObj&>(GetSdrObject());
+ }
+
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDREDGEOBJ_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofsdrmeasureobj.hxx b/svx/inc/sdr/contact/viewcontactofsdrmeasureobj.hxx
new file mode 100644
index 000000000..6b4d89323
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofsdrmeasureobj.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRMEASUREOBJ_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRMEASUREOBJ_HXX
+
+#include <sdr/contact/viewcontactoftextobj.hxx>
+#include <svx/svdomeas.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewContactOfSdrMeasureObj final : public ViewContactOfTextObj
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfSdrMeasureObj(SdrMeasureObj& rMeasureObj);
+ virtual ~ViewContactOfSdrMeasureObj() override;
+
+ private:
+ // internal access to SdrMeasureObj
+ const SdrMeasureObj& GetMeasureObj() const
+ {
+ return static_cast<const SdrMeasureObj&>(GetSdrObject());
+ }
+
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRMEASUREOBJ_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofsdrobjcustomshape.hxx b/svx/inc/sdr/contact/viewcontactofsdrobjcustomshape.hxx
new file mode 100644
index 000000000..6bdcbb5df
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofsdrobjcustomshape.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDROBJCUSTOMSHAPE_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDROBJCUSTOMSHAPE_HXX
+
+#include <sdr/contact/viewcontactoftextobj.hxx>
+#include <svx/svdoashp.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewContactOfSdrObjCustomShape final : public ViewContactOfTextObj
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfSdrObjCustomShape(SdrObjCustomShape& rCustomShape);
+ virtual ~ViewContactOfSdrObjCustomShape() override;
+
+ private:
+ // internal access to SdrObjCustomShape
+ const SdrObjCustomShape& GetCustomShapeObj() const
+ {
+ return static_cast<const SdrObjCustomShape&>(GetSdrObject());
+ }
+
+ // #i101684# internal tooling
+ basegfx::B2DRange getCorrectedTextBoundRect() const;
+
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDROBJCUSTOMSHAPE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofsdrole2obj.hxx b/svx/inc/sdr/contact/viewcontactofsdrole2obj.hxx
new file mode 100644
index 000000000..d5ca82fbc
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofsdrole2obj.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDROLE2OBJ_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDROLE2OBJ_HXX
+
+#include <sdr/contact/viewcontactofsdrrectobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+class Graphic;
+
+namespace sdr::contact
+{
+class ViewContactOfSdrOle2Obj final : public ViewContactOfSdrRectObj
+{
+private:
+ // Create an Object-Specific ViewObjectContact, set ViewContact and
+ // ObjectContact. Always needs to return something.
+ virtual ViewObjectContact&
+ CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+
+public:
+ // access to SdrOle2Obj
+ const SdrOle2Obj& GetOle2Obj() const { return static_cast<const SdrOle2Obj&>(GetSdrObject()); }
+
+ /// helper to create transformation from SdrObject
+ basegfx::B2DHomMatrix createObjectTransform() const;
+
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfSdrOle2Obj(SdrOle2Obj& rOle2Obj);
+ virtual ~ViewContactOfSdrOle2Obj() override;
+
+ // helper for creating an OLE sequence for this object. It takes care od attributes, needed
+ // scaling (e.g. for EmptyPresObj's), the correct graphic and other stuff. It is used from
+ // createViewIndependentPrimitive2DSequence with false, and with evtl. HighContrast true
+ // from the VOC which knows that
+ void createPrimitive2DSequenceWithParameters(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const;
+
+ virtual basegfx::B2DRange
+ getRange(const drawinglayer::geometry::ViewInformation2D& rViewInfo2D) const override;
+
+private:
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data, just wraps to call createPrimitive2DSequenceWithParameters(false)
+ virtual void createViewIndependentPrimitive2DSequence(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+};
+}
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDROLE2OBJ_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofsdrpage.hxx b/svx/inc/sdr/contact/viewcontactofsdrpage.hxx
new file mode 100644
index 000000000..98d6f577e
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofsdrpage.hxx
@@ -0,0 +1,204 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRPAGE_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRPAGE_HXX
+
+#include <sal/types.h>
+#include <svx/sdr/contact/viewcontact.hxx>
+
+class SdrPage;
+
+namespace sdr::contact {
+
+class ViewContactOfSdrPage;
+
+class ViewContactOfPageSubObject : public ViewContact
+{
+ ViewContactOfSdrPage& mrParentViewContactOfSdrPage;
+
+public:
+ explicit ViewContactOfPageSubObject(ViewContactOfSdrPage& rParentViewContactOfSdrPage);
+ virtual ~ViewContactOfPageSubObject() override;
+
+ virtual ViewContact* GetParentContact() const override;
+ const SdrPage& getPage() const;
+};
+
+class ViewContactOfPageBackground final : public ViewContactOfPageSubObject
+{
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ explicit ViewContactOfPageBackground(ViewContactOfSdrPage& rParentViewContactOfSdrPage);
+ virtual ~ViewContactOfPageBackground() override;
+};
+
+class ViewContactOfPageShadow final : public ViewContactOfPageSubObject
+{
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ explicit ViewContactOfPageShadow(ViewContactOfSdrPage& rParentViewContactOfSdrPage);
+ virtual ~ViewContactOfPageShadow() override;
+};
+
+class ViewContactOfPageFill final : public ViewContactOfPageSubObject
+{
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ explicit ViewContactOfPageFill(ViewContactOfSdrPage& rParentViewContactOfSdrPage);
+ virtual ~ViewContactOfPageFill() override;
+};
+
+class ViewContactOfMasterPage final : public ViewContactOfPageSubObject
+{
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ explicit ViewContactOfMasterPage(ViewContactOfSdrPage& rParentViewContactOfSdrPage);
+ virtual ~ViewContactOfMasterPage() override;
+};
+
+class ViewContactOfOuterPageBorder final : public ViewContactOfPageSubObject
+{
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ explicit ViewContactOfOuterPageBorder(ViewContactOfSdrPage& rParentViewContactOfSdrPage);
+ virtual ~ViewContactOfOuterPageBorder() override;
+};
+
+class ViewContactOfInnerPageBorder final : public ViewContactOfPageSubObject
+{
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ explicit ViewContactOfInnerPageBorder(ViewContactOfSdrPage& rParentViewContactOfSdrPage);
+ virtual ~ViewContactOfInnerPageBorder() override;
+};
+
+/**
+ * This view contact corresponds with all SdrObject instances in a single
+ * SdrPage. Its GetObjectCount() returns the number of SdrObject instances
+ * in the SdrPage that it represents, and its GetViewContact() returns the
+ * view contact of the SdrObject instance associated with the identifier
+ * passed to the method.
+ */
+class ViewContactOfPageHierarchy final : public ViewContactOfPageSubObject
+{
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ explicit ViewContactOfPageHierarchy(ViewContactOfSdrPage& rParentViewContactOfSdrPage);
+ virtual ~ViewContactOfPageHierarchy() override;
+
+ virtual sal_uInt32 GetObjectCount() const override;
+ virtual ViewContact& GetViewContact(sal_uInt32 nIndex) const override;
+};
+
+class ViewContactOfGrid final : public ViewContactOfPageSubObject
+{
+ bool mbFront : 1;
+
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ ViewContactOfGrid(ViewContactOfSdrPage& rParentViewContactOfSdrPage, bool bFront);
+ virtual ~ViewContactOfGrid() override;
+
+ bool getFront() const { return mbFront; }
+};
+
+class ViewContactOfHelplines final : public ViewContactOfPageSubObject
+{
+ bool mbFront : 1;
+
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ ViewContactOfHelplines(ViewContactOfSdrPage& rParentViewContactOfSdrPage, bool bFront);
+ virtual ~ViewContactOfHelplines() override;
+
+ bool getFront() const { return mbFront; }
+};
+
+class ViewContactOfSdrPage final : public ViewContact
+{
+ // the owner of this ViewContact. Set from constructor and not
+ // to be changed in any way.
+ SdrPage& mrPage;
+
+ // helper viewContacts to build a clear paint hierarchy
+ ViewContactOfPageBackground maViewContactOfPageBackground;
+ ViewContactOfPageShadow maViewContactOfPageShadow;
+ ViewContactOfPageFill maViewContactOfPageFill;
+ ViewContactOfMasterPage maViewContactOfMasterPage;
+ ViewContactOfOuterPageBorder maViewContactOfOuterPageBorder;
+ ViewContactOfInnerPageBorder maViewContactOfInnerPageBorder;
+ ViewContactOfGrid maViewContactOfGridBack;
+ ViewContactOfHelplines maViewContactOfHelplinesBack;
+ ViewContactOfPageHierarchy maViewContactOfPageHierarchy;
+ ViewContactOfGrid maViewContactOfGridFront;
+ ViewContactOfHelplines maViewContactOfHelplinesFront;
+
+ // Create an Object-Specific ViewObjectContact, set ViewContact and
+ // ObjectContact. Always needs to return something. Default is to create
+ // a standard ViewObjectContact containing the given ObjectContact and *this
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+
+public:
+ // access to SdrObject
+ SdrPage& GetSdrPage() const
+ {
+ return mrPage;
+ }
+
+ // basic constructor, used from SdrPage.
+ explicit ViewContactOfSdrPage(SdrPage& rObj);
+ virtual ~ViewContactOfSdrPage() override;
+
+ // Access to possible sub-hierarchy
+ virtual sal_uInt32 GetObjectCount() const override;
+ virtual ViewContact& GetViewContact(sal_uInt32 nIndex) const override;
+
+ // React on changes of the object of this ViewContact
+ virtual void ActionChanged() override;
+
+private:
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+};
+
+}
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRPAGE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofsdrpathobj.hxx b/svx/inc/sdr/contact/viewcontactofsdrpathobj.hxx
new file mode 100644
index 000000000..bc4063a42
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofsdrpathobj.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRPATHOBJ_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRPATHOBJ_HXX
+
+#include <sdr/contact/viewcontactoftextobj.hxx>
+#include <svx/svdopath.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewContactOfSdrPathObj final : public ViewContactOfTextObj
+ {
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfSdrPathObj(SdrPathObj& rTextObj);
+ virtual ~ViewContactOfSdrPathObj() override;
+
+ private:
+ // internal access to SdrPathObj
+ const SdrPathObj& GetPathObj() const
+ {
+ return static_cast<const SdrPathObj&>(GetSdrObject());
+ }
+
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFSDRPATHOBJ_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofsdrrectobj.hxx b/svx/inc/sdr/contact/viewcontactofsdrrectobj.hxx
new file mode 100644
index 000000000..6971f8f0c
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofsdrrectobj.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdr/contact/viewcontactoftextobj.hxx>
+#include <svx/svdorect.hxx>
+
+namespace sdr::contact
+{
+class ViewContactOfSdrRectObj : public ViewContactOfTextObj
+{
+protected:
+ // internal access to SdrRectObj
+ const SdrRectObj& GetRectObj() const { return static_cast<const SdrRectObj&>(GetSdrObject()); }
+
+public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfSdrRectObj(SdrRectObj& rTextObj);
+ virtual ~ViewContactOfSdrRectObj() override;
+
+protected:
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactoftextobj.hxx b/svx/inc/sdr/contact/viewcontactoftextobj.hxx
new file mode 100644
index 000000000..cdf88e10c
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactoftextobj.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+
+class SdrTextObj;
+
+namespace sdr::contact
+{
+class ViewContactOfTextObj : public ViewContactOfSdrObj
+{
+public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfTextObj(SdrTextObj& rTextObj);
+ virtual ~ViewContactOfTextObj() override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewcontactofunocontrol.hxx b/svx/inc/sdr/contact/viewcontactofunocontrol.hxx
new file mode 100644
index 000000000..04cdf7c07
--- /dev/null
+++ b/svx/inc/sdr/contact/viewcontactofunocontrol.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFUNOCONTROL_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFUNOCONTROL_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+#include <svx/svdouno.hxx>
+
+class OutputDevice;
+namespace vcl { class Window; }
+namespace com::sun::star {
+ namespace awt {
+ class XControl;
+ class XControlContainer;
+ }
+}
+
+
+namespace sdr::contact {
+
+
+ //= ViewContactOfUnoControl
+
+ class ViewContactOfUnoControl final : public ViewContactOfSdrObj
+ {
+ public:
+ // access to SdrObject
+ const SdrUnoObj& GetSdrUnoObj() const
+ {
+ return static_cast<const SdrUnoObj&>(GetSdrObject());
+ }
+
+ explicit ViewContactOfUnoControl( SdrUnoObj& _rUnoObject );
+ virtual ~ViewContactOfUnoControl() override;
+
+ /** retrieves a temporary XControl instance, whose parent is the given window
+ @seealso SdrUnoObj::GetTemporaryControlForWindow
+ */
+ css::uno::Reference< css::awt::XControl >
+ getTemporaryControlForWindow( const vcl::Window& _rWindow, css::uno::Reference< css::awt::XControlContainer >& _inout_ControlContainer ) const;
+
+ private:
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact( ObjectContact& _rObjectContact ) override;
+
+ ViewContactOfUnoControl( const ViewContactOfUnoControl& ) = delete;
+ ViewContactOfUnoControl& operator=( const ViewContactOfUnoControl& ) = delete;
+
+ // This method is responsible for creating the graphical visualisation data
+ // ONLY based on model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+
+
+} // namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWCONTACTOFUNOCONTROL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewobjectcontactofe3d.hxx b/svx/inc/sdr/contact/viewobjectcontactofe3d.hxx
new file mode 100644
index 000000000..591ed6504
--- /dev/null
+++ b/svx/inc/sdr/contact/viewobjectcontactofe3d.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFE3D_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFE3D_HXX
+
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <drawinglayer/primitive3d/baseprimitive3d.hxx>
+
+namespace sdr::contact {
+ class ViewObjectContactOfE3dScene;
+}
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfE3d final : public ViewObjectContactOfSdrObj
+ {
+ // also override the 2d method to deliver a 2d object with embedded 3d and the 3d transformation which is able to
+ // answer the get2DRange question accordingly
+ virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ ViewObjectContactOfE3d(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfE3d() override;
+
+ // access to the local primitive sequence. This will ensure that the list is
+ // current in comparing the local list content with a fresh created incarnation
+ // This method will not handle included hierarchies or visibility.
+ drawinglayer::primitive3d::Primitive3DContainer getPrimitive3DContainer(const DisplayInfo& rDisplayInfo) const;
+ };
+
+} // end of namespace sdr::contact
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFE3D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewobjectcontactofe3dscene.hxx b/svx/inc/sdr/contact/viewobjectcontactofe3dscene.hxx
new file mode 100644
index 000000000..cc1b2e7c3
--- /dev/null
+++ b/svx/inc/sdr/contact/viewobjectcontactofe3dscene.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFE3DSCENE_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFE3DSCENE_HXX
+
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfE3dScene final : public ViewObjectContactOfSdrObj
+ {
+ // 2d primitive creator
+ virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ // basic constructor.
+ ViewObjectContactOfE3dScene(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfE3dScene() override;
+
+ // process this primitive: Eventually also recursively travel an existing hierarchy,
+ // e.g. for group objects, scenes or pages. This method will test geometrical visibility.
+ virtual void getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor ) const override;
+ };
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFE3DSCENE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewobjectcontactofgraphic.hxx b/svx/inc/sdr/contact/viewobjectcontactofgraphic.hxx
new file mode 100644
index 000000000..74e616a45
--- /dev/null
+++ b/svx/inc/sdr/contact/viewobjectcontactofgraphic.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFGRAPHIC_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFGRAPHIC_HXX
+
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+
+class SdrGrafObj;
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfGraphic final : public ViewObjectContactOfSdrObj
+ {
+ // This method is responsible for creating the graphical visualisation data
+ virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ ViewObjectContactOfGraphic(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfGraphic() override;
+ };
+} // end of namespace sdr::contact
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFGRAPHIC_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewobjectcontactofgroup.hxx b/svx/inc/sdr/contact/viewobjectcontactofgroup.hxx
new file mode 100644
index 000000000..96697b020
--- /dev/null
+++ b/svx/inc/sdr/contact/viewobjectcontactofgroup.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFGROUP_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFGROUP_HXX
+
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfGroup final : public ViewObjectContactOfSdrObj
+ {
+ public:
+ // basic constructor.
+ ViewObjectContactOfGroup(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfGroup() override;
+
+ // This method recursively paints the draw hierarchy.
+ virtual void getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor ) const override;
+
+ private:
+ virtual bool isPrimitiveVisibleOnAnyLayer(const SdrLayerIDSet& aLayers) const override;
+ };
+
+} // end of namespace sdr::contact
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFGROUP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewobjectcontactofmasterpagedescriptor.hxx b/svx/inc/sdr/contact/viewobjectcontactofmasterpagedescriptor.hxx
new file mode 100644
index 000000000..613e7f8b0
--- /dev/null
+++ b/svx/inc/sdr/contact/viewobjectcontactofmasterpagedescriptor.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFMASTERPAGEDESCRIPTOR_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFMASTERPAGEDESCRIPTOR_HXX
+
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+
+namespace sdr {
+ class MasterPageDescriptor;
+}
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfMasterPageDescriptor final : public ViewObjectContact
+ {
+ public:
+ ViewObjectContactOfMasterPageDescriptor(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfMasterPageDescriptor() override;
+
+ virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const override;
+ virtual void getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor ) const override;
+ };
+
+} // end of namespace sdr::contact
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFMASTERPAGEDESCRIPTOR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewobjectcontactofpageobj.hxx b/svx/inc/sdr/contact/viewobjectcontactofpageobj.hxx
new file mode 100644
index 000000000..b651e083e
--- /dev/null
+++ b/svx/inc/sdr/contact/viewobjectcontactofpageobj.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <memory>
+
+class SdrPage;
+
+namespace sdr::contact
+{
+class PagePrimitiveExtractor;
+
+class ViewObjectContactOfPageObj final : public ViewObjectContactOfSdrObj
+{
+private:
+ // the page painter helper
+ std::unique_ptr<PagePrimitiveExtractor> mpExtractor;
+
+ // This method is responsible for creating the graphical visualisation data which is
+ // stored/cached in the local primitive.
+ // This method will not handle included hierarchies and not check geometric visibility.
+ virtual void createPrimitive2DSequence(
+ const DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ ViewObjectContactOfPageObj(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfPageObj() override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewobjectcontactofsdrmediaobj.hxx b/svx/inc/sdr/contact/viewobjectcontactofsdrmediaobj.hxx
new file mode 100644
index 000000000..891c920ae
--- /dev/null
+++ b/svx/inc/sdr/contact/viewobjectcontactofsdrmediaobj.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFSDRMEDIAOBJ_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFSDRMEDIAOBJ_HXX
+
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <config_features.h>
+#include <tools/gen.hxx>
+#include <memory>
+
+namespace avmedia { class MediaItem; }
+namespace vcl { class Window; }
+
+namespace sdr::contact
+ {
+ class SdrMediaWindow;
+
+ class ViewObjectContactOfSdrMediaObj final : public ViewObjectContactOfSdrObj
+ {
+ public:
+
+ ViewObjectContactOfSdrMediaObj( ObjectContact& rObjectContact,
+ ViewContact& rViewContact,
+ const ::avmedia::MediaItem& rMediaItem );
+ virtual ~ViewObjectContactOfSdrMediaObj() override;
+
+ public:
+
+ vcl::Window* getWindow() const;
+
+ Size getPreferredSize() const;
+
+ void updateMediaItem( ::avmedia::MediaItem& rItem ) const;
+ void executeMediaItem( const ::avmedia::MediaItem& rItem );
+
+ virtual void ActionChanged() override;
+
+ private:
+ void updateMediaWindow(bool bShow) const;
+
+#if HAVE_FEATURE_AVMEDIA
+ std::unique_ptr<sdr::contact::SdrMediaWindow> mpMediaWindow;
+#endif
+ };
+
+} // end of namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFSDRMEDIAOBJ_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewobjectcontactofsdrole2obj.hxx b/svx/inc/sdr/contact/viewobjectcontactofsdrole2obj.hxx
new file mode 100644
index 000000000..2279f9b45
--- /dev/null
+++ b/svx/inc/sdr/contact/viewobjectcontactofsdrole2obj.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFSDROLE2OBJ_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFSDROLE2OBJ_HXX
+
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+
+class SdrOle2Obj;
+
+namespace sdr::contact
+{
+class ViewObjectContactOfSdrOle2Obj final : public ViewObjectContactOfSdrObj
+{
+ // This method is responsible for creating the graphical visualisation data
+ virtual void createPrimitive2DSequence(
+ const DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+public:
+ ViewObjectContactOfSdrOle2Obj(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfSdrOle2Obj() override;
+};
+}
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFSDROLE2OBJ_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewobjectcontactofsdrpage.hxx b/svx/inc/sdr/contact/viewobjectcontactofsdrpage.hxx
new file mode 100644
index 000000000..a6fa46d43
--- /dev/null
+++ b/svx/inc/sdr/contact/viewobjectcontactofsdrpage.hxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFSDRPAGE_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFSDRPAGE_HXX
+
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+
+class SdrPage;
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfPageSubObject : public ViewObjectContact
+ {
+ protected:
+ const SdrPage& getPage() const;
+
+ public:
+ ViewObjectContactOfPageSubObject(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfPageSubObject() override;
+
+ virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const override;
+ virtual bool isPrimitiveGhosted(const DisplayInfo& rDisplayInfo) const override;
+ };
+
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfPageBackground final : public ViewObjectContactOfPageSubObject
+ {
+ virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ ViewObjectContactOfPageBackground(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfPageBackground() override;
+
+ virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const override;
+ };
+
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfMasterPage final : public ViewObjectContactOfPageSubObject
+ {
+ protected:
+ public:
+ ViewObjectContactOfMasterPage(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfMasterPage() override;
+
+ virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const override;
+ };
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfPageFill final : public ViewObjectContactOfPageSubObject
+ {
+ virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ ViewObjectContactOfPageFill(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfPageFill() override;
+
+ virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const override;
+ };
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfPageShadow final : public ViewObjectContactOfPageSubObject
+ {
+ public:
+ ViewObjectContactOfPageShadow(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfPageShadow() override;
+
+ virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const override;
+ };
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfOuterPageBorder final : public ViewObjectContactOfPageSubObject
+ {
+ public:
+ ViewObjectContactOfOuterPageBorder(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfOuterPageBorder() override;
+
+ virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const override;
+ };
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfInnerPageBorder final : public ViewObjectContactOfPageSubObject
+ {
+ public:
+ ViewObjectContactOfInnerPageBorder(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfInnerPageBorder() override;
+
+ virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const override;
+ };
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfPageHierarchy final : public ViewObjectContactOfPageSubObject
+ {
+ public:
+ ViewObjectContactOfPageHierarchy(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfPageHierarchy() override;
+
+ virtual void getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor ) const override;
+ };
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfPageGrid final : public ViewObjectContactOfPageSubObject
+ {
+ virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ ViewObjectContactOfPageGrid(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfPageGrid() override;
+
+ virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const override;
+ };
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfPageHelplines final : public ViewObjectContactOfPageSubObject
+ {
+ virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ ViewObjectContactOfPageHelplines(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfPageHelplines() override;
+
+ virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const override;
+ };
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+ {
+ class ViewObjectContactOfSdrPage final : public ViewObjectContact
+ {
+ public:
+ ViewObjectContactOfSdrPage(ObjectContact& rObjectContact, ViewContact& rViewContact);
+ virtual ~ViewObjectContactOfSdrPage() override;
+
+ virtual void getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor ) const override;
+ };
+} // end of namespace sdr::contact
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFSDRPAGE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/contact/viewobjectcontactofunocontrol.hxx b/svx/inc/sdr/contact/viewobjectcontactofunocontrol.hxx
new file mode 100644
index 000000000..d7dc8ffdd
--- /dev/null
+++ b/svx/inc/sdr/contact/viewobjectcontactofunocontrol.hxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFUNOCONTROL_HXX
+#define INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFUNOCONTROL_HXX
+
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <rtl/ref.hxx>
+
+class OutputDevice;
+namespace vcl { class Window; }
+class SdrUnoObj;
+namespace com::sun::star {
+ namespace awt {
+ class XControl;
+ class XControlContainer;
+ }
+}
+
+
+namespace sdr::contact {
+
+
+ class ViewContactOfUnoControl;
+ class ObjectContactOfPageView;
+
+ //= ViewObjectContactOfUnoControl
+
+ class ViewObjectContactOfUnoControl_Impl;
+ class ViewObjectContactOfUnoControl : public ViewObjectContactOfSdrObj
+ {
+ protected:
+ ::rtl::Reference< ViewObjectContactOfUnoControl_Impl > m_pImpl;
+
+ public:
+ ViewObjectContactOfUnoControl( ObjectContact& _rObjectContact, ViewContactOfUnoControl& _rViewContact );
+
+ /// returns the ->XControl instance belonging to the instance, creates it if necessary
+ css::uno::Reference< css::awt::XControl >
+ getControl();
+
+ /** retrieves a temporary XControl instance, whose parent is the given device
+ @seealso SdrUnoObj::GetTemporaryControlForWindow
+ */
+ static css::uno::Reference< css::awt::XControl >
+ getTemporaryControlForWindow(
+ const vcl::Window& _rWindow,
+ css::uno::Reference< css::awt::XControlContainer >& _inout_ControlContainer,
+ const SdrUnoObj& _rUnoObject
+ );
+
+ /// ensures that the control belonging to this instances has a given visibility
+ void ensureControlVisibility( bool _bVisible ) const;
+
+ /** sets the design/alive mode of the control
+ */
+ void setControlDesignMode( bool _bDesignMode ) const;
+
+ /** callback from impl class to react on changes of properties form the XControlModel
+ */
+ void propertyChange();
+
+ /** React on changes of the object of this ViewContact
+ */
+ virtual void ActionChanged() override;
+
+ /** to be called when any aspect of the control which requires view updates changed
+ */
+ struct ImplAccess { friend class ViewObjectContactOfUnoControl_Impl; friend class ViewObjectContactOfUnoControl; private: ImplAccess() { } };
+ void onControlChangedOrModified( ImplAccess ) { impl_onControlChangedOrModified(); }
+
+ protected:
+ virtual ~ViewObjectContactOfUnoControl() override;
+
+ // support for Primitive2D
+ virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ // visibility check
+ virtual bool isPrimitiveVisible( const DisplayInfo& _rDisplayInfo ) const override;
+ /// to be called when any aspect of the control which requires view updates changed
+ void impl_onControlChangedOrModified();
+
+ private:
+ ViewObjectContactOfUnoControl( const ViewObjectContactOfUnoControl& ) = delete;
+ ViewObjectContactOfUnoControl& operator=( const ViewObjectContactOfUnoControl& ) = delete;
+ };
+
+ class UnoControlPrintOrPreviewContact final : public ViewObjectContactOfUnoControl
+ {
+ public:
+ UnoControlPrintOrPreviewContact( ObjectContactOfPageView& _rObjectContact, ViewContactOfUnoControl& _rViewContact );
+ virtual ~UnoControlPrintOrPreviewContact() override;
+
+ private:
+ UnoControlPrintOrPreviewContact( const UnoControlPrintOrPreviewContact& ) = delete;
+ UnoControlPrintOrPreviewContact& operator=( const UnoControlPrintOrPreviewContact& ) = delete;
+
+ virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+
+
+} // namespace sdr::contact
+
+
+#endif // INCLUDED_SVX_INC_SDR_CONTACT_VIEWOBJECTCONTACTOFUNOCONTROL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/overlay/overlaycrosshair.hxx b/svx/inc/sdr/overlay/overlaycrosshair.hxx
new file mode 100644
index 000000000..09dccf4a8
--- /dev/null
+++ b/svx/inc/sdr/overlay/overlaycrosshair.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYCROSSHAIR_HXX
+#define INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYCROSSHAIR_HXX
+
+#include <svx/sdr/overlay/overlayobject.hxx>
+
+
+namespace sdr::overlay
+ {
+ class OverlayCrosshairStriped final : public OverlayObjectWithBasePosition
+ {
+ // geometry creation for OverlayObject
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+ public:
+ explicit OverlayCrosshairStriped(const basegfx::B2DPoint& rBasePos);
+ virtual ~OverlayCrosshairStriped() override;
+
+ // react on stripe definition change
+ virtual void stripeDefinitionHasChanged() override;
+ };
+} // end of namespace sdr::overlay
+
+
+#endif // INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYCROSSHAIR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/overlay/overlayhandle.hxx b/svx/inc/sdr/overlay/overlayhandle.hxx
new file mode 100644
index 000000000..882fb702c
--- /dev/null
+++ b/svx/inc/sdr/overlay/overlayhandle.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#ifndef INCLUDED_SVX_SDR_OVERLAY_OVERLAYHANDLE_HXX
+#define INCLUDED_SVX_SDR_OVERLAY_OVERLAYHANDLE_HXX
+
+#include <svx/sdr/overlay/overlayobject.hxx>
+#include <basegfx/vector/b2dsize.hxx>
+
+namespace sdr::overlay {
+
+
+class OverlayHandle final : public OverlayObjectWithBasePosition
+{
+ basegfx::B2DSize maSize;
+ Color maStrokeColor;
+
+ // geometry creation for OverlayObject
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+public:
+ OverlayHandle(const basegfx::B2DPoint& rBasePos,
+ const basegfx::B2DSize& rSize,
+ Color const & rStrokeColor,
+ Color const & rFillColor);
+
+ virtual ~OverlayHandle() override;
+};
+
+} // end of namespace sdr::overlay
+
+#endif // INCLUDED_SVX_SDR_OVERLAY_OVERLAYHANDLE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/overlay/overlayhelpline.hxx b/svx/inc/sdr/overlay/overlayhelpline.hxx
new file mode 100644
index 000000000..834f7e40a
--- /dev/null
+++ b/svx/inc/sdr/overlay/overlayhelpline.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYHELPLINE_HXX
+#define INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYHELPLINE_HXX
+
+#include <svx/sdr/overlay/overlayobject.hxx>
+#include <svx/svdhlpln.hxx>
+
+
+namespace sdr::overlay
+ {
+ class OverlayHelplineStriped final : public OverlayObjectWithBasePosition
+ {
+ // remember HelpLineKind
+ SdrHelpLineKind meKind;
+
+ // geometry creation for OverlayObject
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+ public:
+ explicit OverlayHelplineStriped(
+ const basegfx::B2DPoint& rBasePos,
+ SdrHelpLineKind eNewKind);
+ virtual ~OverlayHelplineStriped() override;
+
+ // dat read access
+ SdrHelpLineKind getKind() const { return meKind; }
+
+ // react on stripe definition change
+ virtual void stripeDefinitionHasChanged() override;
+ };
+} // end of namespace sdr::overlay
+
+
+#endif // INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYHELPLINE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/overlay/overlayline.hxx b/svx/inc/sdr/overlay/overlayline.hxx
new file mode 100644
index 000000000..425ea96b7
--- /dev/null
+++ b/svx/inc/sdr/overlay/overlayline.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYLINE_HXX
+#define INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYLINE_HXX
+
+#include <svx/sdr/overlay/overlayobject.hxx>
+
+
+namespace sdr::overlay
+ {
+ class OverlayLineStriped final : public OverlayObjectWithBasePosition
+ {
+ // second position in pixel
+ basegfx::B2DPoint maSecondPosition;
+
+ // geometry creation for OverlayObject
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+ public:
+ OverlayLineStriped(
+ const basegfx::B2DPoint& rBasePos,
+ const basegfx::B2DPoint& rSecondPos);
+ virtual ~OverlayLineStriped() override;
+
+ // change second position
+ const basegfx::B2DPoint& getSecondPosition() const { return maSecondPosition; }
+
+ // react on stripe definition change
+ virtual void stripeDefinitionHasChanged() override;
+ };
+} // end of namespace sdr::overlay
+
+
+#endif // INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYLINE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/overlay/overlaymanagerbuffered.hxx b/svx/inc/sdr/overlay/overlaymanagerbuffered.hxx
new file mode 100644
index 000000000..a5acd6abc
--- /dev/null
+++ b/svx/inc/sdr/overlay/overlaymanagerbuffered.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYMANAGERBUFFERED_HXX
+#define INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYMANAGERBUFFERED_HXX
+
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/idle.hxx>
+
+
+namespace sdr::overlay
+ {
+ class OverlayManagerBuffered final : public OverlayManager
+ {
+ // The VirtualDevice for draw window content buffering, this
+ // is the view content without overlay
+ ScopedVclPtr<VirtualDevice> mpBufferDevice;
+
+ // #i73602# The VirtualDevice for OverlayPaint buffering. This
+ // is an extra device to avoid flickering of overlay paints
+ ScopedVclPtr<VirtualDevice> mpOutputBufferDevice;
+
+ // Idle for buffering
+ Idle maBufferIdle;
+
+ // Range for buffering (in pixel to be independent from mapMode)
+ basegfx::B2IRange maBufferRememberedRangePixel;
+
+ // link for timer
+ DECL_LINK(ImpBufferTimerHandler, Timer*, void);
+
+ // Internal methods for buffering
+ void ImpPrepareBufferDevice();
+ void ImpRestoreBackground() const ;
+ void ImpRestoreBackground(const vcl::Region& rRegionPixel) const;
+ void ImpSaveBackground(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice);
+
+ OverlayManagerBuffered(OutputDevice& rOutputDevice);
+ virtual ~OverlayManagerBuffered() override;
+
+ public:
+ static rtl::Reference<OverlayManager> create(OutputDevice& rOutputDevice);
+
+ // complete redraw
+ virtual void completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice = nullptr) const override;
+
+ // flush. Do buffered updates.
+ virtual void flush() override;
+
+ // invalidate the given range at local OutputDevice
+ virtual void invalidateRange(const basegfx::B2DRange& rRange) override;
+ };
+} // end of namespace sdr::overlay
+
+
+#endif // INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYMANAGERBUFFERED_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/overlay/overlayobjectcell.hxx b/svx/inc/sdr/overlay/overlayobjectcell.hxx
new file mode 100644
index 000000000..566f8156d
--- /dev/null
+++ b/svx/inc/sdr/overlay/overlayobjectcell.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/sdr/overlay/overlayobject.hxx>
+
+#include <vector>
+
+
+namespace sdr::overlay
+ {
+ // OverlayObjectCell - used for cell cursor, selection and AutoFill handle
+
+ class OverlayObjectCell final : public OverlayObject
+ {
+ public:
+ typedef ::std::vector< basegfx::B2DRange > RangeVector;
+
+ private:
+ RangeVector maRectangles;
+
+ // geometry creation for OverlayObject
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+ public:
+ OverlayObjectCell( const Color& rColor, RangeVector&& rRects);
+ virtual ~OverlayObjectCell() override;
+ };
+
+} // end of namespace sdr::overlay
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/overlay/overlayrectangle.hxx b/svx/inc/sdr/overlay/overlayrectangle.hxx
new file mode 100644
index 000000000..399a9d5c9
--- /dev/null
+++ b/svx/inc/sdr/overlay/overlayrectangle.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYRECTANGLE_HXX
+#define INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYRECTANGLE_HXX
+
+#include <svx/sdr/overlay/overlayobject.hxx>
+
+namespace tools { class PolyPolygon; }
+
+namespace sdr::overlay
+ {
+ class OverlayRectangle final : public OverlayObjectWithBasePosition
+ {
+ // geometric definitions
+ basegfx::B2DPoint maSecondPosition;
+ const double mfTransparence;
+ const double mfDiscreteGrow;
+ const double mfDiscreteShrink;
+ const double mfRotation;
+
+ // #i53216# added CursorBlinkTime (in ms)
+ sal_uInt32 mnBlinkTime;
+
+ // Flag to remember which state to draw. Inited with false (0)
+ bool mbOverlayState : 1;
+
+ // geometry creation for OverlayObject
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+ public:
+ OverlayRectangle(
+ const basegfx::B2DPoint& rBasePosition,
+ const basegfx::B2DPoint& rSecondPosition,
+ const Color& rHatchColor,
+ double fTransparence,
+ double fDiscreteGrow,
+ double fDiscreteShrink,
+ double fRotation,
+ bool bAnimate);
+
+ // execute event from base class sdr::animation::Event. Default
+ // implementation does nothing and does not create a new event.
+ virtual void Trigger(sal_uInt32 nTime) override;
+ };
+} // end of namespace sdr::overlay
+
+#endif // INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYRECTANGLE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/overlay/overlayrollingrectangle.hxx b/svx/inc/sdr/overlay/overlayrollingrectangle.hxx
new file mode 100644
index 000000000..ecdfd1a50
--- /dev/null
+++ b/svx/inc/sdr/overlay/overlayrollingrectangle.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYROLLINGRECTANGLE_HXX
+#define INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYROLLINGRECTANGLE_HXX
+
+#include <svx/sdr/overlay/overlayobject.hxx>
+
+
+namespace sdr::overlay
+ {
+ class OverlayRollingRectangleStriped final : public OverlayObjectWithBasePosition
+ {
+ // second position in pixel
+ basegfx::B2DPoint maSecondPosition;
+
+ // Flag to switch on/off long lines to the OutputDevice bounds
+ bool mbExtendedLines : 1;
+
+ // Flag to switch on/off the bounds itself
+ bool mbShowBounds : 1;
+
+ // geometry creation for OverlayObject
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+ public:
+ OverlayRollingRectangleStriped(
+ const basegfx::B2DPoint& rBasePos,
+ const basegfx::B2DPoint& rSecondPos,
+ bool bExtendedLines,
+ bool bShowBounds = true);
+ virtual ~OverlayRollingRectangleStriped() override;
+
+ // change second position
+ const basegfx::B2DPoint& getSecondPosition() const { return maSecondPosition; }
+ void setSecondPosition(const basegfx::B2DPoint& rNew);
+
+ // react on stripe definition change
+ virtual void stripeDefinitionHasChanged() override;
+ };
+} // end of namespace sdr::overlay
+
+
+#endif // INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYROLLINGRECTANGLE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/overlay/overlaytools.hxx b/svx/inc/sdr/overlay/overlaytools.hxx
new file mode 100644
index 000000000..c058116f4
--- /dev/null
+++ b/svx/inc/sdr/overlay/overlaytools.hxx
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYTOOLS_HXX
+#define INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYTOOLS_HXX
+
+#include <drawinglayer/primitive2d/primitivetools2d.hxx>
+#include <vcl/bitmapex.hxx>
+#include <basegfx/vector/b2dsize.hxx>
+
+namespace drawinglayer::primitive2d {
+
+class OverlayStaticRectanglePrimitive final : public DiscreteMetricDependentPrimitive2D
+{
+private:
+ basegfx::B2DPoint maPosition;
+ basegfx::B2DSize maSize;
+
+ // the graphic definition
+ basegfx::BColor maStrokeColor;
+ basegfx::BColor maFillColor;
+ double mfTransparence;
+
+ // the rotation of the primitive itself
+ double mfRotation;
+
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
+
+public:
+ OverlayStaticRectanglePrimitive(
+ const basegfx::B2DPoint& rPosition,
+ const basegfx::B2DSize& rSize,
+ const basegfx::BColor& rStrokeColor,
+ const basegfx::BColor& rFillColor,
+ double fTransparence,
+ double fRotation);
+
+ // compare operator
+ virtual bool operator==( const BasePrimitive2D& rPrimitive ) const override;
+
+ virtual sal_uInt32 getPrimitive2DID() const override;
+};
+
+} // end of namespace drawinglayer::primitive2d
+
+// Overlay helper class which holds a BotmapEx which is to be visualized
+// at the given logic position with the Bitmap's pixel size, unscaled and
+// unrotated (like a marker). The discrete pixel on the bitmap assocciated
+// with the target position is given in discrete X,Y coordinates
+namespace drawinglayer::primitive2d
+ {
+ class OverlayBitmapExPrimitive final : public DiscreteMetricDependentPrimitive2D
+ {
+ private:
+ // The BitmapEx to use, PixelSize is used
+ BitmapEx maBitmapEx;
+
+ // The logic position
+ basegfx::B2DPoint maBasePosition;
+
+ // The pixel inside the BitmapEx which is assocciated with
+ // the target position (offset in the bitmap)
+ sal_uInt16 mnCenterX;
+ sal_uInt16 mnCenterY;
+
+ // evtl. rotation and shear around center
+ double mfShearX;
+ double mfRotation;
+
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
+
+ public:
+ OverlayBitmapExPrimitive(
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DPoint& rBasePosition,
+ sal_uInt16 nCenterX,
+ sal_uInt16 nCenterY,
+ double fShearX,
+ double fRotation);
+
+ // data access
+ const BitmapEx& getBitmapEx() const { return maBitmapEx; }
+ const basegfx::B2DPoint& getBasePosition() const { return maBasePosition; }
+ sal_uInt16 getCenterX() const { return mnCenterX; }
+ sal_uInt16 getCenterY() const { return mnCenterY; }
+ double getShearX() const { return mfShearX; }
+ double getRotation() const { return mfRotation; }
+
+ // compare operator
+ virtual bool operator==( const BasePrimitive2D& rPrimitive ) const override;
+
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+// Overlay helper class for a crosshair
+namespace drawinglayer::primitive2d
+ {
+ class OverlayCrosshairPrimitive final : public ViewportDependentPrimitive2D
+ {
+ private:
+ // The logic position
+ basegfx::B2DPoint maBasePosition;
+
+ // The stripe colors and length
+ basegfx::BColor maRGBColorA;
+ basegfx::BColor maRGBColorB;
+ double mfDiscreteDashLength;
+
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
+
+ public:
+ OverlayCrosshairPrimitive(
+ const basegfx::B2DPoint& rBasePosition,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength);
+
+ // data access
+ const basegfx::B2DPoint& getBasePosition() const { return maBasePosition; }
+ const basegfx::BColor& getRGBColorA() const { return maRGBColorA; }
+ const basegfx::BColor& getRGBColorB() const { return maRGBColorB; }
+ double getDiscreteDashLength() const { return mfDiscreteDashLength; }
+
+ // compare operator
+ virtual bool operator==( const BasePrimitive2D& rPrimitive ) const override;
+
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+// Overlay helper class for a hatch rectangle as used e.g. for text object
+// selection highlighting
+namespace drawinglayer::primitive2d
+ {
+ class OverlayRectanglePrimitive final : public DiscreteMetricDependentPrimitive2D
+ {
+ private:
+ // the logic rectangle definition
+ basegfx::B2DRange maObjectRange;
+
+ // the graphic definition
+ basegfx::BColor maColor;
+ double mfTransparence;
+
+ // the discrete grow and shrink of the box
+ double mfDiscreteGrow;
+ double mfDiscreteShrink;
+
+ // the rotation of the primitive itself
+ double mfRotation;
+
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
+
+ public:
+ OverlayRectanglePrimitive(
+ const basegfx::B2DRange& rObjectRange,
+ const basegfx::BColor& rColor,
+ double fTransparence,
+ double fDiscreteGrow,
+ double fDiscreteShrink,
+ double fRotation);
+
+ // data access
+ const basegfx::B2DRange& getObjectRange() const { return maObjectRange; }
+ const basegfx::BColor& getColor() const { return maColor; }
+ double getTransparence() const { return mfTransparence; }
+ double getDiscreteGrow() const { return mfDiscreteGrow; }
+ double getDiscreteShrink() const { return mfDiscreteShrink; }
+ double getRotation() const { return mfRotation; }
+
+ // compare operator
+ virtual bool operator==( const BasePrimitive2D& rPrimitive ) const override;
+
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+// Overlay helper class for a striped helpline
+
+namespace drawinglayer::primitive2d
+ {
+ enum HelplineStyle
+ {
+ HELPLINESTYLE_POINT,
+ HELPLINESTYLE_VERTICAL,
+ HELPLINESTYLE_HORIZONTAL
+ };
+
+ class OverlayHelplineStripedPrimitive final : public ViewportDependentPrimitive2D
+ {
+ private:
+ // The logic position
+ basegfx::B2DPoint maBasePosition;
+
+ // the style
+ HelplineStyle meStyle;
+
+ // The stripe colors and length
+ basegfx::BColor maRGBColorA;
+ basegfx::BColor maRGBColorB;
+ double mfDiscreteDashLength;
+
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
+
+ public:
+ OverlayHelplineStripedPrimitive(
+ const basegfx::B2DPoint& rBasePosition,
+ HelplineStyle eStyle,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength);
+
+ // data access
+ const basegfx::B2DPoint& getBasePosition() const { return maBasePosition; }
+ HelplineStyle getStyle() const { return meStyle; }
+ const basegfx::BColor& getRGBColorA() const { return maRGBColorA; }
+ const basegfx::BColor& getRGBColorB() const { return maRGBColorB; }
+ double getDiscreteDashLength() const { return mfDiscreteDashLength; }
+
+ // compare operator
+ virtual bool operator==( const BasePrimitive2D& rPrimitive ) const override;
+
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+// Overlay helper class for rolling rectangle helplines. This primitive is
+// only for the extended lines to the ends of the view
+
+namespace drawinglayer::primitive2d
+ {
+ class OverlayRollingRectanglePrimitive final : public ViewportDependentPrimitive2D
+ {
+ private:
+ // The logic range
+ basegfx::B2DRange maRollingRectangle;
+
+ // The stripe colors and length
+ basegfx::BColor maRGBColorA;
+ basegfx::BColor maRGBColorB;
+ double mfDiscreteDashLength;
+
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
+
+ public:
+ OverlayRollingRectanglePrimitive(
+ const basegfx::B2DRange& aRollingRectangle,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength);
+
+ // data access
+ const basegfx::B2DRange& getRollingRectangle() const { return maRollingRectangle; }
+ const basegfx::BColor& getRGBColorA() const { return maRGBColorA; }
+ const basegfx::BColor& getRGBColorB() const { return maRGBColorB; }
+ double getDiscreteDashLength() const { return mfDiscreteDashLength; }
+
+ // compare operator
+ virtual bool operator==( const BasePrimitive2D& rPrimitive ) const override;
+
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_OVERLAY_OVERLAYTOOLS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/overlay/overlaytriangle.hxx b/svx/inc/sdr/overlay/overlaytriangle.hxx
new file mode 100644
index 000000000..0601122a5
--- /dev/null
+++ b/svx/inc/sdr/overlay/overlaytriangle.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/sdr/overlay/overlayobject.hxx>
+
+namespace sdr::overlay
+ {
+ class OverlayTriangle final : public OverlayObjectWithBasePosition
+ {
+ // second and third position in pixel
+ basegfx::B2DPoint maSecondPosition;
+ basegfx::B2DPoint maThirdPosition;
+
+ // geometry creation for OverlayObject
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+ public:
+ OverlayTriangle(
+ const basegfx::B2DPoint& rBasePos,
+ const basegfx::B2DPoint& rSecondPos,
+ const basegfx::B2DPoint& rThirdPos,
+ Color aTriangleColor);
+ virtual ~OverlayTriangle() override;
+ };
+} // end of namespace sdr::overlay
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/primitivefactory2d.hxx b/svx/inc/sdr/primitive2d/primitivefactory2d.hxx
new file mode 100644
index 000000000..ffe099e60
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/primitivefactory2d.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <drawinglayer/primitive2d/Primitive2DVisitor.hxx>
+#include <com/sun/star/graphic/XPrimitiveFactory2D.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <comphelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+typedef comphelper::WeakComponentImplHelper<css::graphic::XPrimitiveFactory2D,
+ css::lang::XServiceInfo>
+ PrimitiveFactory2DImplBase;
+
+// base class for C++ implementation of css::graphic::XPrimitiveFactory2D
+class PrimitiveFactory2D final : public PrimitiveFactory2DImplBase
+{
+public:
+ PrimitiveFactory2D() {}
+
+ // Methods from XPrimitiveFactory2D
+ virtual css::uno::Sequence<css::uno::Reference<css::graphic::XPrimitive2D>>
+ SAL_CALL createPrimitivesFromXShape(
+ const css::uno::Reference<css::drawing::XShape>& xShape,
+ const css::uno::Sequence<css::beans::PropertyValue>& aParms) override;
+ virtual css::uno::Sequence<css::uno::Reference<css::graphic::XPrimitive2D>>
+ SAL_CALL createPrimitivesFromXDrawPage(
+ const css::uno::Reference<css::drawing::XDrawPage>& xDrawPage,
+ const css::uno::Sequence<css::beans::PropertyValue>& aParms) override;
+
+ static void createPrimitivesFromXShape(
+ const css::uno::Reference<css::drawing::XShape>& xShape,
+ const css::uno::Sequence<css::beans::PropertyValue>& /*aParms*/,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor);
+
+ OUString SAL_CALL getImplementationName() override
+ {
+ return "com.sun.star.comp.graphic.PrimitiveFactory2D";
+ }
+
+ sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
+ {
+ return css::uno::Sequence<OUString>{ "com.sun.star.graphic.PrimitiveFactory2D" };
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrattributecreator.hxx b/svx/inc/sdr/primitive2d/sdrattributecreator.hxx
new file mode 100644
index 000000000..f372741fa
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrattributecreator.hxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <svx/svxdllapi.h>
+
+
+// predefines
+class SfxItemSet;
+class SdrText;
+
+namespace drawinglayer::attribute {
+ class SdrLineAttribute;
+ class SdrLineStartEndAttribute;
+ class SdrShadowAttribute;
+ class SdrGlowAttribute;
+ class SdrFillAttribute;
+ class SdrTextAttribute;
+ class FillGradientAttribute;
+ class SdrFillGraphicAttribute;
+ class SdrEffectsTextAttribute;
+ class SdrLineEffectsTextAttribute;
+ class SdrLineFillEffectsTextAttribute;
+ class SdrLineFillShadowAttribute3D;
+ class SdrSceneAttribute;
+ class SdrLightingAttribute;
+ class SdrFillTextAttribute;
+}
+
+namespace basegfx {
+ class B2DRange;
+}
+
+
+namespace drawinglayer::primitive2d
+ {
+ // SdrAttribute creators
+ attribute::SdrLineAttribute SVXCORE_DLLPUBLIC createNewSdrLineAttribute(
+ const SfxItemSet& rSet);
+
+ attribute::SdrLineStartEndAttribute SVXCORE_DLLPUBLIC createNewSdrLineStartEndAttribute(
+ const SfxItemSet& rSet,
+ double fWidth);
+
+ attribute::SdrShadowAttribute createNewSdrShadowAttribute(
+ const SfxItemSet& rSet);
+
+ attribute::SdrFillAttribute SVXCORE_DLLPUBLIC createNewSdrFillAttribute(
+ const SfxItemSet& rSet);
+
+ // #i101508# Support handing over given text-to-border distances
+ attribute::SdrTextAttribute createNewSdrTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText& rText,
+ const sal_Int32* pLeft = nullptr,
+ const sal_Int32* pUpper = nullptr,
+ const sal_Int32* pRight = nullptr,
+ const sal_Int32* pLower = nullptr);
+
+ attribute::FillGradientAttribute SVXCORE_DLLPUBLIC createNewTransparenceGradientAttribute(
+ const SfxItemSet& rSet);
+
+ attribute::SdrFillGraphicAttribute createNewSdrFillGraphicAttribute(
+ const SfxItemSet& rSet);
+
+ attribute::SdrEffectsTextAttribute createNewSdrEffectsTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText,
+ bool bSuppressText); // #i98072# added option to suppress text on demand
+
+ attribute::SdrLineEffectsTextAttribute createNewSdrLineEffectsTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText);
+
+ attribute::SdrLineFillEffectsTextAttribute createNewSdrLineFillEffectsTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText,
+ bool bHasContent); // used from OLE and graphic
+
+ attribute::SdrLineFillShadowAttribute3D createNewSdrLineFillShadowAttribute(
+ const SfxItemSet& rSet,
+ bool bSuppressFill);
+
+ attribute::SdrSceneAttribute createNewSdrSceneAttribute(
+ const SfxItemSet& rSet);
+
+ attribute::SdrLightingAttribute createNewSdrLightingAttribute(
+ const SfxItemSet& rSet);
+
+ // #i101508# Support handing over given text-to-border distances
+ attribute::SdrFillTextAttribute createNewSdrFillTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pSdrText,
+ const sal_Int32* pLeft = nullptr,
+ const sal_Int32* pUpper = nullptr,
+ const sal_Int32* pRight = nullptr,
+ const sal_Int32* pLower = nullptr);
+
+ // helpers
+ void calculateRelativeCornerRadius(
+ sal_Int32 nRadius,
+ const ::basegfx::B2DRange& rObjectRange,
+ double& rfCornerRadiusX,
+ double& rfCornerRadiusY);
+
+
+} // end of namespace drawinglayer::primitive2d
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrcaptionprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrcaptionprimitive2d.hxx
new file mode 100644
index 000000000..1051fbb7e
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrcaptionprimitive2d.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRCAPTIONPRIMITIVE2D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRCAPTIONPRIMITIVE2D_HXX
+
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+
+// predefines
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrCaptionPrimitive2D final : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ ::basegfx::B2DHomMatrix maTransform;
+ attribute::SdrLineFillEffectsTextAttribute maSdrLFSTAttribute;
+ ::basegfx::B2DPolygon maTail;
+ double mfCornerRadiusX; // [0.0..1.0] relative to 1/2 width
+ double mfCornerRadiusY; // [0.0..1.0] relative to 1/2 height
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrCaptionPrimitive2D(
+ const ::basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ const ::basegfx::B2DPolygon& rTail,
+ double fCornerRadiusX,
+ double fCornerRadiusY);
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // data access
+ const ::basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
+ const attribute::SdrLineFillEffectsTextAttribute& getSdrLFSTAttribute() const { return maSdrLFSTAttribute; }
+ const ::basegfx::B2DPolygon& getTail() const { return maTail; }
+ double getCornerRadiusX() const { return mfCornerRadiusX; }
+ double getCornerRadiusY() const { return mfCornerRadiusY; }
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRCAPTIONPRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrconnectorprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrconnectorprimitive2d.hxx
new file mode 100644
index 000000000..d105a5c87
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrconnectorprimitive2d.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRCONNECTORPRIMITIVE2D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRCONNECTORPRIMITIVE2D_HXX
+
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <sdr/attribute/sdrlineeffectstextattribute.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+
+// predefines
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrConnectorPrimitive2D final : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ attribute::SdrLineEffectsTextAttribute maSdrLSTAttribute;
+ ::basegfx::B2DPolygon maUnitPolygon;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrConnectorPrimitive2D(
+ const attribute::SdrLineEffectsTextAttribute& rSdrLSTAttribute,
+ const ::basegfx::B2DPolygon& rUnitPolygon);
+
+ // data access
+ const attribute::SdrLineEffectsTextAttribute& getSdrLSTAttribute() const { return maSdrLSTAttribute; }
+ const ::basegfx::B2DPolygon& getUnitPolygon() const { return maUnitPolygon; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRCONNECTORPRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrcustomshapeprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrcustomshapeprimitive2d.hxx
new file mode 100644
index 000000000..f5ed1f6b2
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrcustomshapeprimitive2d.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRCUSTOMSHAPEPRIMITIVE2D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRCUSTOMSHAPEPRIMITIVE2D_HXX
+
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/attribute/sdreffectstextattribute.hxx>
+
+
+// predefines
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrCustomShapePrimitive2D final : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ attribute::SdrEffectsTextAttribute maSdrSTAttribute;
+ Primitive2DContainer maSubPrimitives;
+ basegfx::B2DHomMatrix maTextBox;
+
+ // defines if SdrTextWordWrapItem was set at SdrObjCustomShape which means
+ // that the text needs to be block formatted
+ bool mbWordWrap : 1;
+
+ // defines that the object contains/is a 3D AutoShape. Needed for
+ // making exceptions with shadow generation
+ bool mb3DShape : 1;
+
+ basegfx::B2DHomMatrix maTransform;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrCustomShapePrimitive2D(
+ const attribute::SdrEffectsTextAttribute& rSdrSTAttribute,
+ Primitive2DContainer&& rSubPrimitives,
+ const basegfx::B2DHomMatrix& rTextBox,
+ bool bWordWrap,
+ bool b3DShape,
+ const basegfx::B2DHomMatrix& rObjectMatrix);
+
+ // data access
+ const attribute::SdrEffectsTextAttribute& getSdrSTAttribute() const { return maSdrSTAttribute; }
+ const Primitive2DContainer& getSubPrimitives() const { return maSubPrimitives; }
+ const basegfx::B2DHomMatrix& getTextBox() const { return maTextBox; }
+ bool getWordWrap() const { return mbWordWrap; }
+ bool get3DShape() const { return mb3DShape; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRCUSTOMSHAPEPRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx b/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx
new file mode 100644
index 000000000..ac65e0eda
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
+#include <drawinglayer/primitive2d/Primitive2DContainer.hxx>
+
+#include <svx/svxdllapi.h>
+
+// predefines
+namespace basegfx {
+ class B2DPolygon;
+ class B2DPolyPolygon;
+ class B2DHomMatrix;
+}
+
+namespace drawinglayer::attribute {
+ class SdrFillAttribute;
+ class SdrLineAttribute;
+ class FillGradientAttribute;
+ class SdrShadowAttribute;
+ class SdrLineStartEndAttribute;
+ class SdrTextAttribute;
+}
+
+
+namespace drawinglayer::primitive2d
+ {
+ Primitive2DReference SVXCORE_DLLPUBLIC createPolyPolygonFillPrimitive(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const attribute::SdrFillAttribute& rFill,
+ const attribute::FillGradientAttribute& rFillGradient);
+
+ Primitive2DReference SVXCORE_DLLPUBLIC createPolyPolygonFillPrimitive(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const basegfx::B2DRange& rDefinitionRange,
+ const attribute::SdrFillAttribute& rFill,
+ const attribute::FillGradientAttribute& rFillGradient);
+
+ Primitive2DReference SVXCORE_DLLPUBLIC createPolygonLinePrimitive(
+ const basegfx::B2DPolygon& rPolygon,
+ const attribute::SdrLineAttribute& rLine,
+ const attribute::SdrLineStartEndAttribute& rStroke);
+
+ Primitive2DReference SVXCORE_DLLPUBLIC createTextPrimitive(
+ const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
+ const basegfx::B2DHomMatrix& rObjectTransform,
+ const attribute::SdrTextAttribute& rText,
+ const attribute::SdrLineAttribute& rStroke,
+ bool bCellText,
+ bool bWordWrap);
+
+ Primitive2DContainer SVXCORE_DLLPUBLIC createEmbeddedShadowPrimitive(
+ Primitive2DContainer&& rContent,
+ const attribute::SdrShadowAttribute& rShadow,
+ const basegfx::B2DHomMatrix& rObjectMatrix = basegfx::B2DHomMatrix(),
+ const Primitive2DContainer* pContentForShadow = nullptr);
+
+ Primitive2DContainer SVXCORE_DLLPUBLIC createEmbeddedGlowPrimitive(
+ Primitive2DContainer&& rContent,
+ const attribute::SdrGlowAttribute& rGlow);
+
+ Primitive2DContainer SVXCORE_DLLPUBLIC createEmbeddedSoftEdgePrimitive(
+ Primitive2DContainer&& aContent,
+ sal_Int32 nRadius);
+
+} // end of namespace drawinglayer::primitive2d
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrellipseprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrellipseprimitive2d.hxx
new file mode 100644
index 000000000..9b4bf4ebe
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrellipseprimitive2d.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRELLIPSEPRIMITIVE2D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRELLIPSEPRIMITIVE2D_HXX
+
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
+
+
+// predefines
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrEllipsePrimitive2D : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ ::basegfx::B2DHomMatrix maTransform;
+ attribute::SdrLineFillEffectsTextAttribute maSdrLFSTAttribute;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrEllipsePrimitive2D(
+ const ::basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute);
+
+ // data access
+ const ::basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
+ const attribute::SdrLineFillEffectsTextAttribute& getSdrLFSTAttribute() const { return maSdrLFSTAttribute; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrEllipseSegmentPrimitive2D final : public SdrEllipsePrimitive2D
+ {
+ private:
+ double mfStartAngle;
+ double mfEndAngle;
+
+ bool mbCloseSegment : 1;
+ bool mbCloseUsingCenter : 1;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrEllipseSegmentPrimitive2D(
+ const ::basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ double fStartAngle,
+ double fEndAngle,
+ bool bCloseSegment,
+ bool bCloseUsingCenter);
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRELLIPSEPRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrgrafprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrgrafprimitive2d.hxx
new file mode 100644
index 000000000..5e349de4c
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrgrafprimitive2d.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <vcl/GraphicObject.hxx>
+#include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
+
+namespace drawinglayer::primitive2d
+{
+class SdrGrafPrimitive2D final : public BufferedDecompositionPrimitive2D
+{
+private:
+ ::basegfx::B2DHomMatrix maTransform;
+ attribute::SdrLineFillEffectsTextAttribute maSdrLFSTAttribute;
+ GraphicObject maGraphicObject;
+ GraphicAttr maGraphicAttr;
+
+ // local decomposition.
+ virtual void
+ create2DDecomposition(Primitive2DContainer& rContainer,
+ const geometry::ViewInformation2D& aViewInformation) const override;
+
+public:
+ SdrGrafPrimitive2D(const ::basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ const GraphicObject& rGraphicObject, const GraphicAttr& rGraphicAttr);
+
+ // data access
+ const ::basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
+ const attribute::SdrLineFillEffectsTextAttribute& getSdrLFSTAttribute() const
+ {
+ return maSdrLFSTAttribute;
+ }
+ const GraphicObject& getGraphicObject() const { return maGraphicObject; }
+ const GraphicAttr& getGraphicAttr() const { return maGraphicAttr; }
+ bool isTransparent() const;
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+};
+} // end of namespace drawinglayer::primitive2d
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrmeasureprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrmeasureprimitive2d.hxx
new file mode 100644
index 000000000..4bc8de10b
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrmeasureprimitive2d.hxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRMEASUREPRIMITIVE2D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRMEASUREPRIMITIVE2D_HXX
+
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <sdr/attribute/sdrlineeffectstextattribute.hxx>
+
+
+// predefines
+
+namespace drawinglayer::primitive2d {
+ enum MeasureTextPosition
+ {
+ MEASURETEXTPOSITION_AUTOMATIC,
+ MEASURETEXTPOSITION_NEGATIVE,
+ MEASURETEXTPOSITION_CENTERED,
+ MEASURETEXTPOSITION_POSITIVE
+ };
+}
+
+namespace drawinglayer::attribute {
+ class SdrLineAttribute;
+}
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrMeasurePrimitive2D final : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ attribute::SdrLineEffectsTextAttribute maSdrLSTAttribute;
+ basegfx::B2DPoint maStart;
+ basegfx::B2DPoint maEnd;
+ MeasureTextPosition meHorizontal;
+ MeasureTextPosition meVertical;
+ double mfDistance;
+ double mfUpper;
+ double mfLower;
+ double mfLeftDelta;
+ double mfRightDelta;
+
+ bool mbBelow : 1;
+ bool mbTextRotation : 1;
+ bool mbTextAutoAngle : 1;
+
+ // internal decomposition helper
+ Primitive2DReference impCreatePart(
+ const attribute::SdrLineAttribute& rLineAttribute,
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const basegfx::B2DPoint& rStart,
+ const basegfx::B2DPoint& rEnd,
+ bool bLeftActive,
+ bool bRightActive) const;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrMeasurePrimitive2D(
+ const attribute::SdrLineEffectsTextAttribute& rSdrLSTAttribute,
+ const basegfx::B2DPoint& rStart,
+ const basegfx::B2DPoint& rEnd,
+ MeasureTextPosition eHorizontal,
+ MeasureTextPosition eVertical,
+ double fDistance,
+ double fUpper,
+ double fLower,
+ double fLeftDelta,
+ double fRightDelta,
+ bool bBelow,
+ bool bTextRotation,
+ bool bTextAutoAngle);
+
+ // data access
+ const attribute::SdrLineEffectsTextAttribute& getSdrLSTAttribute() const { return maSdrLSTAttribute; }
+ const basegfx::B2DPoint& getStart() const { return maStart; }
+ const basegfx::B2DPoint& getEnd() const { return maEnd; }
+ MeasureTextPosition getHorizontal() const { return meHorizontal; }
+ MeasureTextPosition getVertical() const { return meVertical; }
+ double getDistance() const { return mfDistance; }
+ double getUpper() const { return mfUpper; }
+ double getLower() const { return mfLower; }
+ double getLeftDelta() const { return mfLeftDelta; }
+ double getRightDelta() const { return mfRightDelta; }
+ bool getBelow() const { return mbBelow; }
+ bool getTextRotation() const { return mbTextRotation; }
+ bool getTextAutoAngle() const { return mbTextAutoAngle; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRMEASUREPRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrole2primitive2d.hxx b/svx/inc/sdr/primitive2d/sdrole2primitive2d.hxx
new file mode 100644
index 000000000..615eb3299
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrole2primitive2d.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDROLE2PRIMITIVE2D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDROLE2PRIMITIVE2D_HXX
+
+#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
+
+
+// predefines
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrOle2Primitive2D final : public BasePrimitive2D
+ {
+ private:
+ Primitive2DContainer maOLEContent;
+ basegfx::B2DHomMatrix maTransform;
+ attribute::SdrLineFillEffectsTextAttribute maSdrLFSTAttribute;
+
+ public:
+ SdrOle2Primitive2D(
+ Primitive2DContainer&& rOLEContent,
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute);
+
+ // data access
+ const Primitive2DContainer& getOLEContent() const { return maOLEContent; }
+ const basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
+ const attribute::SdrLineFillEffectsTextAttribute& getSdrLFSTAttribute() const { return maSdrLFSTAttribute; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // local decomposition.
+ virtual void get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDROLE2PRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrolecontentprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrolecontentprimitive2d.hxx
new file mode 100644
index 000000000..c73478042
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrolecontentprimitive2d.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDROLECONTENTPRIMITIVE2D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDROLECONTENTPRIMITIVE2D_HXX
+
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <tools/weakbase.h>
+
+
+// predefinitions
+
+class SdrOle2Obj;
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrOleContentPrimitive2D final : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ tools::WeakReference<SdrOle2Obj> mpSdrOle2Obj;
+ basegfx::B2DHomMatrix maObjectTransform;
+
+ // #i104867# The GraphicVersion number to identify in operator== if
+ // the graphic has changed, but without fetching it (which may
+ // be expensive, e.g. triggering chart creation)
+ sal_uInt32 mnGraphicVersion;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrOleContentPrimitive2D(
+ const SdrOle2Obj& rSdrOle2Obj,
+ const basegfx::B2DHomMatrix& rObjectTransform,
+ sal_uInt32 nGraphicVersion
+ );
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // The default implementation will use getDecomposition results to create the range
+ virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
+
+ // data access
+ const basegfx::B2DHomMatrix& getObjectTransform() const { return maObjectTransform; }
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDROLECONTENTPRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrpathprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrpathprimitive2d.hxx
new file mode 100644
index 000000000..6e4819a89
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrpathprimitive2d.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRPATHPRIMITIVE2D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRPATHPRIMITIVE2D_HXX
+
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+
+// predefines
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrPathPrimitive2D final : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ basegfx::B2DHomMatrix maTransform;
+ attribute::SdrLineFillEffectsTextAttribute maSdrLFSTAttribute;
+ basegfx::B2DPolyPolygon maUnitPolyPolygon;
+
+ // OperationSmiley: Added to be able to define a FillGeometry different from local
+ // geometry. It is ignored when empty and/or equal to UnitPolyPolygon.
+ // If used and there is a fill, the object's geometry (maUnitPolyPolygon) will be filled,
+ // but UnitDefinitionPolyPolygon will be used to define the FillStyle. Thus when
+ // using the 'same' UnitDefinitionPolyPolygon for multiple definitions,
+ // all filled stuff using it will fit seamlessly together.
+ // 'same' is in quotes since it is a UnitPolygon, so being relative to the
+ // unit polygon of the local geometry (UnitPolyPolygon). The definition is complete
+ // when applying the also given transformation (maTransform)
+ basegfx::B2DPolyPolygon maUnitDefinitionPolyPolygon;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ // OperationSmiley: Extended to UnitDefinitionPolyPolygon, but when needed
+ // a 2nd version without can be defined that just does not set the
+ // maUnitDefinitionPolyPolygon or set equal to UnitPolyPolygon
+ SdrPathPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
+ const basegfx::B2DPolyPolygon& rUnitDefinitionPolyPolygon);
+
+ // data access
+ const basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
+ const attribute::SdrLineFillEffectsTextAttribute& getSdrLFSTAttribute() const { return maSdrLFSTAttribute; }
+ const basegfx::B2DPolyPolygon& getUnitPolyPolygon() const { return maUnitPolyPolygon; }
+ const basegfx::B2DPolyPolygon& getUnitDefinitionPolyPolygon() const { return maUnitDefinitionPolyPolygon; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRPATHPRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrprimitivetools.hxx b/svx/inc/sdr/primitive2d/sdrprimitivetools.hxx
new file mode 100644
index 000000000..71e50cdf7
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrprimitivetools.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRPRIMITIVETOOLS_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRPRIMITIVETOOLS_HXX
+
+#include <vcl/bitmapex.hxx>
+
+// predefines
+
+namespace basegfx
+{
+class BColor;
+}
+
+// helper methods
+
+namespace drawinglayer::primitive2d
+{
+// create a 3x3 cross in given color as BitmapEx
+BitmapEx createDefaultCross_3x3(const basegfx::BColor& rBColor);
+} // end of namespace drawinglayer::primitive2d
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRPRIMITIVETOOLS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrrectangleprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrrectangleprimitive2d.hxx
new file mode 100644
index 000000000..6480f03c6
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrrectangleprimitive2d.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRRECTANGLEPRIMITIVE2D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRRECTANGLEPRIMITIVE2D_HXX
+
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
+
+
+// predefines
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrRectanglePrimitive2D final : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ basegfx::B2DHomMatrix maTransform;
+ attribute::SdrLineFillEffectsTextAttribute maSdrLFSTAttribute;
+ double mfCornerRadiusX; // [0.0..1.0] relative to 1/2 width
+ double mfCornerRadiusY; // [0.0..1.0] relative to 1/2 height
+
+ // flag which decides if the HitArea should be the filled geometry
+ bool mbForceFillForHitTest : 1;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrRectanglePrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ double fCornerRadiusX,
+ double fCornerRadiusY,
+ bool bForceFillForHitTest);
+
+ // data access
+ const basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
+ const attribute::SdrLineFillEffectsTextAttribute& getSdrLFSTAttribute() const { return maSdrLFSTAttribute; }
+ double getCornerRadiusX() const { return mfCornerRadiusX; }
+ double getCornerRadiusY() const { return mfCornerRadiusY; }
+ bool getForceFillForHitTest() const { return mbForceFillForHitTest; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRRECTANGLEPRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive2d/sdrtextprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrtextprimitive2d.hxx
new file mode 100644
index 000000000..ab1483be7
--- /dev/null
+++ b/svx/inc/sdr/primitive2d/sdrtextprimitive2d.hxx
@@ -0,0 +1,335 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRTEXTPRIMITIVE2D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRTEXTPRIMITIVE2D_HXX
+
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <editeng/outlobj.hxx>
+#include <tools/color.hxx>
+#include <sdr/attribute/sdrformtextattribute.hxx>
+#include <tools/weakbase.h>
+#include <svx/sdtaitm.hxx>
+#include <rtl/ref.hxx>
+
+
+// predefines
+class SdrText;
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrTextPrimitive2D : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ // The text model data; this should later just be the OutlinerParaObject or
+ // something equal
+ ::tools::WeakReference< SdrText > mrSdrText;
+
+ // #i97628#
+ // The text content; now as local OutlinerParaObject copy (internally RefCounted and
+ // COW) and in exclusive, local form as needed in a primitive
+ const OutlinerParaObject maOutlinerParaObject;
+
+ // remember last VisualizingPage for which a decomposition was made. If the new target
+ // is not given or different, the decomposition needs to be potentially removed
+ // for supporting e.g. page number change on MasterPage objects or the different
+ // field renderings in SubGeometry and MasterPage node
+ css::uno::Reference< css::drawing::XDrawPage > mxLastVisualizingPage;
+
+ // remember last PageNumber for which a decomposition was made. This is only used
+ // when mbContainsPageField is true, else it is 0
+ sal_Int16 mnLastPageNumber;
+
+ // remember last PageCount for which a decomposition was made. This is only used
+ // when mbContainsPageCountField is true, else it is 0
+ sal_Int16 mnLastPageCount;
+
+ // #i101443# remember last TextBackgroundColor to decide if a new decomposition is
+ // needed because of background color change
+ Color maLastTextBackgroundColor;
+
+ // is there a PageNumber, Header, Footer or DateTimeField used? Evaluated at construction
+ bool mbContainsPageField : 1;
+ bool mbContainsPageCountField : 1;
+ bool mbContainsOtherFields : 1;
+
+ protected:
+ // support for XTEXT_PAINTSHAPE_BEGIN/XTEXT_PAINTSHAPE_END Metafile comments
+ static void encapsulateWithTextHierarchyBlockPrimitive2D(Primitive2DContainer& rContainer, Primitive2DContainer&& aCandidate);
+
+ public:
+ SdrTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObjectPtr);
+
+ // get data
+ const SdrText* getSdrText() const;
+ const OutlinerParaObject& getOutlinerParaObject() const { return maOutlinerParaObject; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // own get2DDecomposition to take aspect of decomposition with or without spell checker
+ // into account
+ virtual void get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const override;
+
+ // transformed clone operator
+ virtual rtl::Reference<SdrTextPrimitive2D> createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const = 0;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrContourTextPrimitive2D final : public SdrTextPrimitive2D
+ {
+ private:
+ // unit contour polygon (scaled to [0.0 .. 1.0])
+ basegfx::B2DPolyPolygon maUnitPolyPolygon;
+
+ // complete contour polygon transform (scale, rotate, shear, translate)
+ basegfx::B2DHomMatrix maObjectTransform;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrContourTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObjectPtr,
+ const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
+ const basegfx::B2DHomMatrix& rObjectTransform);
+
+ // get data
+ const basegfx::B2DPolyPolygon& getUnitPolyPolygon() const { return maUnitPolyPolygon; }
+ const basegfx::B2DHomMatrix& getObjectTransform() const { return maObjectTransform; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // transformed clone operator
+ virtual rtl::Reference<SdrTextPrimitive2D> createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrPathTextPrimitive2D final : public SdrTextPrimitive2D
+ {
+ private:
+ // the path to use. Each paragraph will use one Polygon.
+ basegfx::B2DPolyPolygon maPathPolyPolygon;
+
+ // the Fontwork parameters
+ attribute::SdrFormTextAttribute maSdrFormTextAttribute;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrPathTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObjectPtr,
+ const basegfx::B2DPolyPolygon& rPathPolyPolygon,
+ const attribute::SdrFormTextAttribute& rSdrFormTextAttribute);
+
+ // get data
+ const basegfx::B2DPolyPolygon& getPathPolyPolygon() const { return maPathPolyPolygon; }
+ const attribute::SdrFormTextAttribute& getSdrFormTextAttribute() const { return maSdrFormTextAttribute; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // transformed clone operator
+ virtual rtl::Reference<SdrTextPrimitive2D> createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrBlockTextPrimitive2D final : public SdrTextPrimitive2D
+ {
+ private:
+ // text range transformation from unit range ([0.0 .. 1.0]) to text range
+ basegfx::B2DHomMatrix maTextRangeTransform;
+
+ // text alignments
+ SdrTextHorzAdjust maSdrTextHorzAdjust;
+ SdrTextVertAdjust maSdrTextVertAdjust;
+
+ bool mbFixedCellHeight : 1;
+ bool mbUnlimitedPage : 1; // force layout with no text break
+ bool mbCellText : 1; // this is a cell text as block text
+ bool mbWordWrap : 1; // for CustomShapes text layout
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrBlockTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObjectPtr,
+ const basegfx::B2DHomMatrix& rTextRangeTransform,
+ SdrTextHorzAdjust aSdrTextHorzAdjust,
+ SdrTextVertAdjust aSdrTextVertAdjust,
+ bool bFixedCellHeight,
+ bool bUnlimitedPage,
+ bool bCellText,
+ bool bWordWrap);
+
+ // get data
+ const basegfx::B2DHomMatrix& getTextRangeTransform() const { return maTextRangeTransform; }
+ SdrTextHorzAdjust getSdrTextHorzAdjust() const { return maSdrTextHorzAdjust; }
+ SdrTextVertAdjust getSdrTextVertAdjust() const { return maSdrTextVertAdjust; }
+ bool isFixedCellHeight() const { return mbFixedCellHeight; }
+ bool getUnlimitedPage() const { return mbUnlimitedPage; }
+ bool getCellText() const { return mbCellText; }
+ bool getWordWrap() const { return mbWordWrap; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // transformed clone operator
+ virtual rtl::Reference<SdrTextPrimitive2D> createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrStretchTextPrimitive2D final : public SdrTextPrimitive2D
+ {
+ private:
+ // text range transformation from unit range ([0.0 .. 1.0]) to text range
+ basegfx::B2DHomMatrix maTextRangeTransform;
+
+ bool mbFixedCellHeight : 1;
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrStretchTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObjectPtr,
+ const basegfx::B2DHomMatrix& rTextRangeTransform,
+ bool bFixedCellHeight);
+
+ // get data
+ const basegfx::B2DHomMatrix& getTextRangeTransform() const { return maTextRangeTransform; }
+ bool isFixedCellHeight() const { return mbFixedCellHeight; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // transformed clone operator
+ virtual rtl::Reference<SdrTextPrimitive2D> createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrAutoFitTextPrimitive2D final : public SdrTextPrimitive2D
+ {
+ private:
+ ::basegfx::B2DHomMatrix maTextRangeTransform; // text range transformation from unit range ([0.0 .. 1.0]) to text range
+
+ bool mbWordWrap : 1; // for CustomShapes text layout
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrAutoFitTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObjectPtr,
+ const ::basegfx::B2DHomMatrix& rTextRangeTransform,
+ bool bWordWrap);
+
+ // get data
+ const basegfx::B2DHomMatrix& getTextRangeTransform() const { return maTextRangeTransform; }
+ bool getWordWrap() const { return mbWordWrap; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // transformed clone operator
+ virtual rtl::Reference<SdrTextPrimitive2D> createTransformedClone(const ::basegfx::B2DHomMatrix& rTransform) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+namespace drawinglayer::primitive2d
+ {
+ class SdrChainedTextPrimitive2D final : public SdrTextPrimitive2D
+ {
+ private:
+ // XXX: might have position of overflowing text
+
+ ::basegfx::B2DHomMatrix maTextRangeTransform; // text range transformation from unit range ([0.0 .. 1.0]) to text range
+
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrChainedTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObjectPtrs,
+ const ::basegfx::B2DHomMatrix& rTextRangeTransform);
+
+ // get data
+ const basegfx::B2DHomMatrix& getTextRangeTransform() const { return maTextRangeTransform; }
+ //bool getWordWrap() const { return true; } // XXX: Hack! Should have a proper implementation//
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // transformed clone operator
+ virtual rtl::Reference<SdrTextPrimitive2D> createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+} // end of namespace drawinglayer::primitive2d
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRTEXTPRIMITIVE2D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/primitive3d/sdrattributecreator3d.hxx b/svx/inc/sdr/primitive3d/sdrattributecreator3d.hxx
new file mode 100644
index 000000000..3f5178427
--- /dev/null
+++ b/svx/inc/sdr/primitive3d/sdrattributecreator3d.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE3D_SDRATTRIBUTECREATOR3D_HXX
+#define INCLUDED_SVX_INC_SDR_PRIMITIVE3D_SDRATTRIBUTECREATOR3D_HXX
+
+#include <drawinglayer/attribute/sdrobjectattribute3d.hxx>
+
+// predefines
+class SfxItemSet;
+namespace basegfx {
+ class B2DRange;
+}
+
+
+namespace drawinglayer::primitive2d
+{
+ // SdrAttribute creators
+ attribute::Sdr3DObjectAttribute createNewSdr3DObjectAttribute(const SfxItemSet& rSet);
+
+ // helpers
+
+} // end of namespace drawinglayer::attribute
+
+
+#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE3D_SDRATTRIBUTECREATOR3D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/attributeproperties.hxx b/svx/inc/sdr/properties/attributeproperties.hxx
new file mode 100644
index 000000000..d2f1aa15a
--- /dev/null
+++ b/svx/inc/sdr/properties/attributeproperties.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SDR_PROPERTIES_ATTRIBUTEPROPERTIES_HXX
+#define INCLUDED_SVX_SDR_PROPERTIES_ATTRIBUTEPROPERTIES_HXX
+
+#include <svl/lstner.hxx>
+#include <svl/stylesheetuser.hxx>
+#include <svx/sdr/properties/defaultproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class AttributeProperties : public DefaultProperties, public SfxListener, public svl::StyleSheetUser
+ {
+ // core to set parent at SfxItemSet and to execute the hard attribute computations
+ void ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr);
+
+ // add style sheet, do all the necessary handling
+ void ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr);
+
+ // remove StyleSheet, do all the necessary handling
+ void ImpRemoveStyleSheet();
+
+ protected:
+ // the StyleSheet of this object
+ SfxStyleSheet* mpStyleSheet;
+
+ // create a new itemset
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& pPool) override;
+
+ // Do the ItemChange, may do special handling
+ virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = nullptr) override;
+
+ // react on ItemSet changes
+ virtual void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ // apply the correct SfyStyleSheet from SdrObject's SdrModel
+ virtual void applyDefaultStyleSheetFromSdrModel();
+
+ public:
+ // basic constructor
+ explicit AttributeProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ AttributeProperties(const AttributeProperties& rProps, SdrObject& rObj);
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // Get the local ItemSet. This directly returns the local ItemSet of the object. No
+ // merging of ItemSets is done for e.g. Group objects.
+ virtual const SfxItemSet& GetObjectItemSet() const override;
+
+ // destructor
+ virtual ~AttributeProperties() override;
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // get the installed StyleSheet
+ virtual SfxStyleSheet* GetStyleSheet() const override;
+
+ // force all attributes which come from styles to hard attributes
+ // to be able to live without the style.
+ virtual void ForceStyleToHardAttributes() override;
+
+ // This is the Notify(...) from 2nd base class SfxListener
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+ virtual bool isUsedByModel() const override;
+ };
+
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_SDR_PROPERTIES_ATTRIBUTEPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/captionproperties.hxx b/svx/inc/sdr/properties/captionproperties.hxx
new file mode 100644
index 000000000..238ec4682
--- /dev/null
+++ b/svx/inc/sdr/properties/captionproperties.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_CAPTIONPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_CAPTIONPROPERTIES_HXX
+
+#include <sdr/properties/rectangleproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class CaptionProperties final : public RectangleProperties
+ {
+ // create a new itemset
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
+
+ // react on ItemSet changes
+ virtual void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ public:
+ // basic constructor
+ explicit CaptionProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ CaptionProperties(const CaptionProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~CaptionProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // force default attributes for a specific object type, called from
+ // DefaultProperties::GetObjectItemSet() if a new ItemSet is created
+ virtual void ForceDefaultAttributes() override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_CAPTIONPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/circleproperties.hxx b/svx/inc/sdr/properties/circleproperties.hxx
new file mode 100644
index 000000000..9eaa09dbc
--- /dev/null
+++ b/svx/inc/sdr/properties/circleproperties.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_CIRCLEPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_CIRCLEPROPERTIES_HXX
+
+#include <sdr/properties/rectangleproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class CircleProperties final : public RectangleProperties
+ {
+ // create a new itemset
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
+
+ // react on ItemSet changes
+ virtual void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ public:
+ // basic constructor
+ explicit CircleProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ CircleProperties(const CircleProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~CircleProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // force default attributes for a specific object type, called from
+ // DefaultProperties::GetObjectItemSet() if a new ItemSet is created
+ virtual void ForceDefaultAttributes() override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_CIRCLEPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/connectorproperties.hxx b/svx/inc/sdr/properties/connectorproperties.hxx
new file mode 100644
index 000000000..b3f116289
--- /dev/null
+++ b/svx/inc/sdr/properties/connectorproperties.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_CONNECTORPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_CONNECTORPROPERTIES_HXX
+
+#include <sdr/properties/textproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class ConnectorProperties final : public TextProperties
+ {
+ // create a new itemset
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
+
+ // react on ItemSet changes
+ virtual void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ public:
+ // basic constructor
+ explicit ConnectorProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ ConnectorProperties(const ConnectorProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~ConnectorProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_CONNECTORPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/customshapeproperties.hxx b/svx/inc/sdr/properties/customshapeproperties.hxx
new file mode 100644
index 000000000..1cc83a2cf
--- /dev/null
+++ b/svx/inc/sdr/properties/customshapeproperties.hxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_CUSTOMSHAPEPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_CUSTOMSHAPEPROPERTIES_HXX
+
+#include <sdr/properties/textproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class CustomShapeProperties final : public TextProperties
+ {
+ private:
+ void UpdateTextFrameStatus(bool bInvalidateRenderGeometry);
+
+ // create a new itemset
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
+
+ // test changeability for a single item
+ virtual bool AllowItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = nullptr) const override;
+
+ // react on ItemSet changes
+ virtual void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ // react on Item change
+ virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = nullptr) override;
+
+ // Called after ItemChange() is done for all items. Allows local reactions on
+ // specific item changes
+ virtual void PostItemChange(const sal_uInt16 nWhich) override;
+
+ // clear single item
+ virtual void ClearObjectItem(const sal_uInt16 nWhich = 0) override;
+
+ // clear single item direct, do not do any notifies or things like that.
+ // Also supports complete deletion of items when default parameter 0 is used.
+ virtual void ClearObjectItemDirect(const sal_uInt16 nWhich) override;
+
+ public:
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // force default attributes for a specific object type, called from
+ // DefaultProperties::GetObjectItemSet() if a new ItemSet is created
+ virtual void ForceDefaultAttributes() override;
+
+ // basic constructor
+ explicit CustomShapeProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ CustomShapeProperties(const CustomShapeProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~CustomShapeProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // This is the notifier from SfxListener
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_CUSTOMSHAPEPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/e3dcompoundproperties.hxx b/svx/inc/sdr/properties/e3dcompoundproperties.hxx
new file mode 100644
index 000000000..96abc06f2
--- /dev/null
+++ b/svx/inc/sdr/properties/e3dcompoundproperties.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SDR_PROPERTIES_E3DCOMPOUNDPROPERTIES_HXX
+#define INCLUDED_SVX_SDR_PROPERTIES_E3DCOMPOUNDPROPERTIES_HXX
+
+#include <sdr/properties/e3dproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class E3dCompoundProperties : public E3dProperties
+ {
+ protected:
+ // Called after ItemChange() is done for all items.
+ virtual void PostItemChange(const sal_uInt16 nWhich) override;
+
+ public:
+ // basic constructor
+ explicit E3dCompoundProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ E3dCompoundProperties(const E3dCompoundProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~E3dCompoundProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // Get merged ItemSet. Normally, this maps directly to GetObjectItemSet(), but may
+ // be overridden e.g for group objects to return a merged ItemSet of the object.
+ // When using this method the returned ItemSet may contain items in the state
+ // SfxItemState::DONTCARE which means there were several such items with different
+ // values.
+ virtual const SfxItemSet& GetMergedItemSet() const override;
+
+ // Set merged ItemSet. Normally, this maps to SetObjectItemSet().
+ virtual void SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems = false) override;
+ };
+
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_SDR_PROPERTIES_E3DCOMPOUNDPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/e3dextrudeproperties.hxx b/svx/inc/sdr/properties/e3dextrudeproperties.hxx
new file mode 100644
index 000000000..072b1c796
--- /dev/null
+++ b/svx/inc/sdr/properties/e3dextrudeproperties.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_E3DEXTRUDEPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_E3DEXTRUDEPROPERTIES_HXX
+
+#include <sdr/properties/e3dcompoundproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class E3dExtrudeProperties final : public E3dCompoundProperties
+ {
+ // Called after ItemChange() is done for all items.
+ virtual void PostItemChange(const sal_uInt16 nWhich) override;
+
+ public:
+ // basic constructor
+ explicit E3dExtrudeProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ E3dExtrudeProperties(const E3dExtrudeProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~E3dExtrudeProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+ };
+
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_E3DEXTRUDEPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/e3dlatheproperties.hxx b/svx/inc/sdr/properties/e3dlatheproperties.hxx
new file mode 100644
index 000000000..56e46fb8b
--- /dev/null
+++ b/svx/inc/sdr/properties/e3dlatheproperties.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_E3DLATHEPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_E3DLATHEPROPERTIES_HXX
+
+#include <sdr/properties/e3dcompoundproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class E3dLatheProperties final : public E3dCompoundProperties
+ {
+ // Called after ItemChange() is done for all items.
+ virtual void PostItemChange(const sal_uInt16 nWhich) override;
+
+ public:
+ // basic constructor
+ explicit E3dLatheProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ E3dLatheProperties(const E3dLatheProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~E3dLatheProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+ };
+
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_E3DLATHEPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/e3dproperties.hxx b/svx/inc/sdr/properties/e3dproperties.hxx
new file mode 100644
index 000000000..caef0ff57
--- /dev/null
+++ b/svx/inc/sdr/properties/e3dproperties.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SDR_PROPERTIES_E3DPROPERTIES_HXX
+#define INCLUDED_SVX_SDR_PROPERTIES_E3DPROPERTIES_HXX
+
+#include <sdr/properties/attributeproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class E3dProperties : public AttributeProperties
+ {
+ protected:
+ // create a new itemset
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
+
+ // react on ItemSet changes
+ virtual void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ public:
+ // basic constructor
+ explicit E3dProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ E3dProperties(const E3dProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~E3dProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+ };
+
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_SDR_PROPERTIES_E3DPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/e3dsceneproperties.hxx b/svx/inc/sdr/properties/e3dsceneproperties.hxx
new file mode 100644
index 000000000..4606499bd
--- /dev/null
+++ b/svx/inc/sdr/properties/e3dsceneproperties.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_E3DSCENEPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_E3DSCENEPROPERTIES_HXX
+
+#include <sdr/properties/e3dproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class E3dSceneProperties final : public E3dProperties
+ {
+ // Called after ItemChange() is done for all items.
+ virtual void PostItemChange(const sal_uInt16 nWhich) override;
+
+ public:
+ // basic constructor
+ explicit E3dSceneProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ E3dSceneProperties(const E3dSceneProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~E3dSceneProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // get merged ItemSet. Normally, this maps directly to GetObjectItemSet(), but may
+ // be overridden e.g for group objects to return a merged ItemSet of the object.
+ // When using this method the returned ItemSet may contain items in the state
+ // SfxItemState::DONTCARE which means there were several such items with different
+ // values.
+ virtual const SfxItemSet& GetMergedItemSet() const override;
+
+ // Set merged ItemSet. Normally, this maps to SetObjectItemSet().
+ virtual void SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems = false) override;
+
+ // Set a single item, iterate over hierarchies if necessary.
+ virtual void SetMergedItem(const SfxPoolItem& rItem) override;
+
+ // Clear a single item, iterate over hierarchies if necessary.
+ virtual void ClearMergedItem(const sal_uInt16 nWhich) override;
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // get the installed StyleSheet
+ virtual SfxStyleSheet* GetStyleSheet() const override;
+
+ // Special for scene:
+ void SetSceneItemsFromCamera();
+ };
+
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_E3DSCENEPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/e3dsphereproperties.hxx b/svx/inc/sdr/properties/e3dsphereproperties.hxx
new file mode 100644
index 000000000..61870c939
--- /dev/null
+++ b/svx/inc/sdr/properties/e3dsphereproperties.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_E3DSPHEREPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_E3DSPHEREPROPERTIES_HXX
+
+#include <sdr/properties/e3dcompoundproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class E3dSphereProperties final : public E3dCompoundProperties
+ {
+ // Called after ItemChange() is done for all items.
+ virtual void PostItemChange(const sal_uInt16 nWhich) override;
+
+ public:
+ // basic constructor
+ explicit E3dSphereProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ E3dSphereProperties(const E3dSphereProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~E3dSphereProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+ };
+
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_E3DSPHEREPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/emptyproperties.hxx b/svx/inc/sdr/properties/emptyproperties.hxx
new file mode 100644
index 000000000..f51c97a01
--- /dev/null
+++ b/svx/inc/sdr/properties/emptyproperties.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SDR_PROPERTIES_EMPTYPROPERTIES_HXX
+#define INCLUDED_SVX_SDR_PROPERTIES_EMPTYPROPERTIES_HXX
+
+#include <sal/config.h>
+
+#include <optional>
+
+#include <svx/sdr/properties/properties.hxx>
+#include <svl/itemset.hxx>
+
+
+namespace sdr::properties
+ {
+ class EmptyProperties final : public BaseProperties
+ {
+ public:
+ // basic constructor
+ explicit EmptyProperties(SdrObject& rObj);
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // create a new object specific itemset with object specific ranges.
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& pPool) override;
+
+ // get itemset
+ virtual const SfxItemSet& GetObjectItemSet() const override;
+
+ // set single item
+ virtual void SetObjectItem(const SfxPoolItem& rItem) override;
+
+ // set single item direct, do not do any notifies or things like that
+ virtual void SetObjectItemDirect(const SfxPoolItem& rItem) override;
+
+ // clear single item
+ virtual void ClearObjectItem(const sal_uInt16 nWhich = 0) override;
+
+ // clear single item direct, do not do any notifies or things like that.
+ // Also supports complete deletion of items when default parameter 0 is used.
+ virtual void ClearObjectItemDirect(const sal_uInt16 nWhich) override;
+
+ // set complete item set
+ virtual void SetObjectItemSet(const SfxItemSet& rSet) override;
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // get the installed StyleSheet
+ virtual SfxStyleSheet* GetStyleSheet() const override;
+ };
+} // end of namespace sdr::properties
+
+#endif // INCLUDED_SVX_SDR_PROPERTIES_EMPTYPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/graphicproperties.hxx b/svx/inc/sdr/properties/graphicproperties.hxx
new file mode 100644
index 000000000..7f842a9dc
--- /dev/null
+++ b/svx/inc/sdr/properties/graphicproperties.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_GRAPHICPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_GRAPHICPROPERTIES_HXX
+
+#include <sdr/properties/rectangleproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class GraphicProperties final : public RectangleProperties
+ {
+ // apply the correct SfyStyleSheet from SdrObject's SdrModel
+ virtual void applyDefaultStyleSheetFromSdrModel() override;
+
+ // create a new itemset
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
+
+ // react on ItemSet changes
+ virtual void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ public:
+ // basic constructor
+ explicit GraphicProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ GraphicProperties(const GraphicProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~GraphicProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // force default attributes for a specific object type, called from
+ // DefaultProperties::GetObjectItemSet() if a new ItemSet is created
+ virtual void ForceDefaultAttributes() override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_GRAPHICPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/groupproperties.hxx b/svx/inc/sdr/properties/groupproperties.hxx
new file mode 100644
index 000000000..40e944eb5
--- /dev/null
+++ b/svx/inc/sdr/properties/groupproperties.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_GROUPPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_GROUPPROPERTIES_HXX
+
+#include <svx/sdr/properties/properties.hxx>
+#include <svl/itemset.hxx>
+#include <optional>
+
+namespace sdr::properties
+ {
+ class GroupProperties final : public BaseProperties
+ {
+ // the to be used ItemSet
+ mutable std::optional<SfxItemSet> mxItemSet;
+ public:
+ // basic constructor
+ explicit GroupProperties(SdrObject& rObj);
+
+ // destructor
+ virtual ~GroupProperties() override;
+
+ // create a new object specific itemset with object specific ranges.
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& pPool) override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // get itemset
+ virtual const SfxItemSet& GetObjectItemSet() const override;
+
+ // get merged ItemSet. Normally, this maps directly to GetObjectItemSet(), but may
+ // be overridden e.g for group objects to return a merged ItemSet of the object.
+ // When using this method the returned ItemSet may contain items in the state
+ // SfxItemState::DONTCARE which means there were several such items with different
+ // values.
+ virtual const SfxItemSet& GetMergedItemSet() const override;
+
+ // Set merged ItemSet. Normally, this maps to SetObjectItemSet().
+ virtual void SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems = false) override;
+
+ // set single item
+ virtual void SetObjectItem(const SfxPoolItem& rItem) override;
+
+ // set single item direct, do not do any notifies or things like that
+ virtual void SetObjectItemDirect(const SfxPoolItem& rItem) override;
+
+ // clear single item
+ virtual void ClearObjectItem(const sal_uInt16 nWhich = 0) override;
+
+ // clear single item direct, do not do any notifies or things like that.
+ // Also supports complete deletion of items when default parameter 0 is used.
+ virtual void ClearObjectItemDirect(const sal_uInt16 nWhich) override;
+
+ // Set a single item, iterate over hierarchies if necessary.
+ virtual void SetMergedItem(const SfxPoolItem& rItem) override;
+
+ // Clear a single item, iterate over hierarchies if necessary.
+ virtual void ClearMergedItem(const sal_uInt16 nWhich) override;
+
+ // set complete item set
+ virtual void SetObjectItemSet(const SfxItemSet& rSet) override;
+
+ // set a new StyleSheet
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // get the local StyleSheet
+ virtual SfxStyleSheet* GetStyleSheet() const override;
+
+ // force all attributes which come from styles to hard attributes
+ // to be able to live without the style.
+ virtual void ForceStyleToHardAttributes() override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_GROUPPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/itemsettools.hxx b/svx/inc/sdr/properties/itemsettools.hxx
new file mode 100644
index 000000000..3f7225161
--- /dev/null
+++ b/svx/inc/sdr/properties/itemsettools.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_ITEMSETTOOLS_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_ITEMSETTOOLS_HXX
+
+#include <sal/types.h>
+#include <tools/gen.hxx>
+#include <vector>
+
+class SdrObject;
+class SfxItemSet;
+class Fraction;
+
+// class to remember broadcast start positions
+namespace sdr::properties
+ {
+ class ItemChangeBroadcaster
+ {
+ std::vector< tools::Rectangle > maRectangles;
+
+ public:
+ explicit ItemChangeBroadcaster(const SdrObject& rObj);
+
+ sal_uInt32 GetRectangleCount() const
+ {
+ return maRectangles.size();
+ }
+ const tools::Rectangle& GetRectangle(sal_uInt32 nIndex) const
+ {
+ return maRectangles[nIndex];
+ }
+ };
+} // end of namespace sdr::properties
+
+namespace sdr::properties
+ {
+ void ScaleItemSet(SfxItemSet& rSet, const Fraction& rScale);
+} // end of namespace sdr::properties
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_ITEMSETTOOLS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/measureproperties.hxx b/svx/inc/sdr/properties/measureproperties.hxx
new file mode 100644
index 000000000..001f9778c
--- /dev/null
+++ b/svx/inc/sdr/properties/measureproperties.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_MEASUREPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_MEASUREPROPERTIES_HXX
+
+#include <sdr/properties/textproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class MeasureProperties final : public TextProperties
+ {
+ // create a new itemset
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
+
+ // react on ItemSet changes
+ virtual void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ public:
+ // basic constructor
+ explicit MeasureProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ MeasureProperties(const MeasureProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~MeasureProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // force default attributes for a specific object type, called from
+ // DefaultProperties::GetObjectItemSet() if a new ItemSet is created
+ virtual void ForceDefaultAttributes() override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_MEASUREPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/oleproperties.hxx b/svx/inc/sdr/properties/oleproperties.hxx
new file mode 100644
index 000000000..abd321ba7
--- /dev/null
+++ b/svx/inc/sdr/properties/oleproperties.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_OLEPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_OLEPROPERTIES_HXX
+
+#include <sdr/properties/rectangleproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class OleProperties final : public RectangleProperties
+ {
+ // apply the correct SfyStyleSheet from SdrObject's SdrModel
+ virtual void applyDefaultStyleSheetFromSdrModel() override;
+
+ public:
+ // basic constructor
+ explicit OleProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ OleProperties(const OleProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~OleProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // force default attributes for a specific object type, called from
+ // DefaultProperties::GetObjectItemSet() if a new ItemSet is created
+ virtual void ForceDefaultAttributes() override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_OLEPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/pageproperties.hxx b/svx/inc/sdr/properties/pageproperties.hxx
new file mode 100644
index 000000000..acd1d919f
--- /dev/null
+++ b/svx/inc/sdr/properties/pageproperties.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SDR_PROPERTIES_PAGEPROPERTIES_HXX
+#define INCLUDED_SVX_INC_SDR_PROPERTIES_PAGEPROPERTIES_HXX
+
+#include <svx/sdr/properties/properties.hxx>
+#include <svl/itemset.hxx>
+#include <optional>
+
+namespace sdr::properties
+ {
+ class PageProperties final : public BaseProperties
+ {
+ // the to be used ItemSet
+ mutable std::optional<SfxItemSet> mxEmptyItemSet;
+
+ public:
+ // basic constructor
+ explicit PageProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ PageProperties(const PageProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~PageProperties() override;
+
+ // create a new object specific itemset with object specific ranges.
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& pPool) override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ virtual const SfxItemSet& GetObjectItemSet() const override;
+
+ // get the installed StyleSheet
+ virtual SfxStyleSheet* GetStyleSheet() const override;
+
+ // set the installed StyleSheet
+ virtual void SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // clear single item
+ virtual void ClearObjectItem(const sal_uInt16 nWhich = 0) override;
+
+ // set single item
+ virtual void SetObjectItem(const SfxPoolItem& rItem) override;
+
+ // set single item direct, do not do any notifies or things like that
+ virtual void SetObjectItemDirect(const SfxPoolItem& rItem) override;
+
+ // clear single item direct, do not do any notifies or things like that.
+ // Also supports complete deletion of items when default parameter 0 is used.
+ virtual void ClearObjectItemDirect(const sal_uInt16 nWhich) override;
+
+ // set complete item set
+ virtual void SetObjectItemSet(const SfxItemSet& rSet) override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_INC_SDR_PROPERTIES_PAGEPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/rectangleproperties.hxx b/svx/inc/sdr/properties/rectangleproperties.hxx
new file mode 100644
index 000000000..7694e9d3c
--- /dev/null
+++ b/svx/inc/sdr/properties/rectangleproperties.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SDR_PROPERTIES_RECTANGLEPROPERTIES_HXX
+#define INCLUDED_SVX_SDR_PROPERTIES_RECTANGLEPROPERTIES_HXX
+
+#include <sdr/properties/textproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class RectangleProperties : public TextProperties
+ {
+ protected:
+ // react on ItemSet changes
+ virtual void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ public:
+ // basic constructor
+ explicit RectangleProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ RectangleProperties(const RectangleProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~RectangleProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_SDR_PROPERTIES_RECTANGLEPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sdr/properties/textproperties.hxx b/svx/inc/sdr/properties/textproperties.hxx
new file mode 100644
index 000000000..916e5a7f6
--- /dev/null
+++ b/svx/inc/sdr/properties/textproperties.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SDR_PROPERTIES_TEXTPROPERTIES_HXX
+#define INCLUDED_SVX_SDR_PROPERTIES_TEXTPROPERTIES_HXX
+
+#include <svx/itextprovider.hxx>
+#include <sdr/properties/attributeproperties.hxx>
+
+
+namespace sdr::properties
+ {
+ class TextProperties : public AttributeProperties
+ {
+ private:
+ // #i101556# versioning support
+ sal_uInt32 maVersion;
+
+ protected:
+ // create a new itemset
+ virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
+
+ // Do the ItemChange, may do special handling
+ virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = nullptr) override;
+
+ // react on ItemSet changes
+ virtual void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ /// Get the TextProvider related to our SdrObject
+ virtual const svx::ITextProvider& getTextProvider() const;
+
+ public:
+ // basic constructor
+ explicit TextProperties(SdrObject& rObj);
+
+ // constructor for copying, but using new object
+ TextProperties(const TextProperties& rProps, SdrObject& rObj);
+
+ // destructor
+ virtual ~TextProperties() override;
+
+ // Clone() operator, normally just calls the local copy constructor
+ virtual std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ // set a new StyleSheet and broadcast
+ virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast) override;
+
+ // force default attributes for a specific object type, called from
+ // DefaultProperties::GetObjectItemSet() if a new ItemSet is created
+ virtual void ForceDefaultAttributes() override;
+
+ // force all attributes which come from styles to hard attributes
+ // to be able to live without the style.
+ virtual void ForceStyleToHardAttributes() override;
+
+ // This is the notifier from SfxListener
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+ // Set single item at the local ItemSet. *Does not use* AllowItemChange(),
+ // ItemChange(), PostItemChange() and ItemSetChanged() calls.
+ void SetObjectItemNoBroadcast(const SfxPoolItem& rItem);
+
+ // #i101556# versioning support
+ virtual sal_uInt32 getVersion() const override;
+ };
+} // end of namespace sdr::properties
+
+
+#endif // INCLUDED_SVX_SDR_PROPERTIES_TEXTPROPERTIES_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/spacing.hrc b/svx/inc/spacing.hrc
new file mode 100644
index 000000000..1719d215d
--- /dev/null
+++ b/svx/inc/spacing.hrc
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#ifndef INCLUDED_SVX_INC_SPACING_HRC
+#define INCLUDED_SVX_INC_SPACING_HRC
+
+#include <unotools/resmgr.hxx>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+struct measurement
+{
+ TranslateId key;
+ int twips;
+ int human;
+};
+
+// To translators: this is a listbox labelled by "Spacing:", inch units
+const measurement RID_SVXSTRARY_SPACING_INCH[] =
+{
+ { NC_("RID_SVXSTRARY_SPACING_INCH", "None"), 0, 0 },
+ { NC_("RID_SVXSTRARY_SPACING_INCH", "Extra Small (1/16″)"), 91, 0 },
+ { NC_("RID_SVXSTRARY_SPACING_INCH", "Small (1/8″)"), 181, 0 },
+ { NC_("RID_SVXSTRARY_SPACING_INCH", "Small Medium (1/4″)"), 363, 0 },
+ { NC_("RID_SVXSTRARY_SPACING_INCH", "Medium (3/8″)"), 539, 0 },
+ { NC_("RID_SVXSTRARY_SPACING_INCH", "Medium Large (1/2″)"), 720, 0 },
+ { NC_("RID_SVXSTRARY_SPACING_INCH", "Large (3/4″)"), 1077, 0 },
+ { NC_("RID_SVXSTRARY_SPACING_INCH", "Extra Large (1″)"), 1440, 0 },
+ { {}, 0, 0 }
+};
+
+// To translators: this is a listbox labelled by "Spacing:", cm units
+const measurement RID_SVXSTRARY_SPACING_CM[] =
+{
+ { NC_("RID_SVXSTRARY_SPACING_CM", "None"), 0, 0 },
+ // Extra Small (0.16 cm)
+ { NC_("RID_SVXSTRARY_SPACING_CM", "Extra Small (%1)"), 91, 16 },
+ // Small (0.32 cm)
+ { NC_("RID_SVXSTRARY_SPACING_CM", "Small (%1)"), 181, 32 },
+ // Small Medium (0.64 cm)
+ { NC_("RID_SVXSTRARY_SPACING_CM", "Small Medium (%1)"), 363, 64 },
+ // Medium (0.95 cm)
+ { NC_("RID_SVXSTRARY_SPACING_CM", "Medium (%1)"), 539, 95 },
+ // Medium Large (1.27 cm)
+ { NC_("RID_SVXSTRARY_SPACING_CM", "Medium Large (%1)"), 720, 127 },
+ // Large (1.9 cm)
+ { NC_("RID_SVXSTRARY_SPACING_CM", "Large (%1)"), 1077, 190 },
+ // Extra Large (2.54 cm)
+ { NC_("RID_SVXSTRARY_SPACING_CM", "Extra Large (%1)"), 1440, 254 },
+ { {}, 0, 0 }
+};
+
+// To translators: this is a listbox labelled by "Margins:", inch units
+const measurement RID_SVXSTRARY_MARGINS_INCH[] =
+{
+ { NC_("RID_SVXSTRARY_MARGINS_INCH", "None"), 0, 0 },
+ { NC_("RID_SVXSTRARY_MARGINS_INCH", "Extra Small (1/16″)"), 91, 0 },
+ { NC_("RID_SVXSTRARY_MARGINS_INCH", "Small (1/8″)"), 181, 0 },
+ { NC_("RID_SVXSTRARY_MARGINS_INCH", "Small Medium (1/4″)"), 363, 0 },
+ { NC_("RID_SVXSTRARY_MARGINS_INCH", "Medium (3/8″)"), 539, 0 },
+ { NC_("RID_SVXSTRARY_MARGINS_INCH", "Medium Large (1/2″)"), 720, 0 },
+ { NC_("RID_SVXSTRARY_MARGINS_INCH", "Large (3/4″)"), 1077, 0 },
+ { NC_("RID_SVXSTRARY_MARGINS_INCH", "Extra Large (1″)"), 1440, 0 },
+ { {}, 0, 0 }
+};
+
+// To translators: this is a listbox labelled by "Margins:", cm units
+const measurement RID_SVXSTRARY_MARGINS_CM[] =
+{
+ { NC_("RID_SVXSTRARY_MARGINS_CM", "None"), 0, 0 },
+ // Extra Small (0.16 cm)
+ { NC_("RID_SVXSTRARY_MARGINS_CM", "Extra Small (%1)"), 91, 16 },
+ // Small (0.32 cm)
+ { NC_("RID_SVXSTRARY_MARGINS_CM", "Small (%1)"), 181, 32 },
+ // Small Medium (0.64 cm)
+ { NC_("RID_SVXSTRARY_MARGINS_CM", "Small Medium (%1)"), 363, 64 },
+ // Medium (0.95 cm)
+ { NC_("RID_SVXSTRARY_MARGINS_CM", "Medium (%1)"), 539, 95 },
+ // Medium Large (1.27 cm)
+ { NC_("RID_SVXSTRARY_MARGINS_CM", "Medium Large (%1)"), 720, 127 },
+ // Large (1.9 cm)
+ { NC_("RID_SVXSTRARY_MARGINS_CM", "Large (%1)"), 1077, 190 },
+ // Extra Large (2.54 cm)
+ { NC_("RID_SVXSTRARY_MARGINS_CM", "Extra Large (%1)"), 1440, 254 },
+ { {}, 0, 0 }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/inc/strings.hxx b/svx/inc/strings.hxx
new file mode 100644
index 000000000..1c917bee9
--- /dev/null
+++ b/svx/inc/strings.hxx
@@ -0,0 +1,394 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+inline constexpr OUStringLiteral RID_GALLERYSTR_THEME_HTMLBUTTONS = u"private://gallery/hidden/HtmlExportButtons";
+inline constexpr OUStringLiteral RID_GALLERYSTR_THEME_POWERPOINT = u"private://gallery/hidden/imgppt";
+inline constexpr OUStringLiteral RID_GALLERYSTR_THEME_RULERS = u"Rulers";
+inline constexpr OUStringLiteral RID_GALLERYSTR_THEME_USERSOUNDS = u"private://gallery/hidden/usersounds";
+inline constexpr OUStringLiteral RID_GALLERYSTR_THEME_DUMMY5 = u"Dummy 5";
+inline constexpr OUStringLiteral RID_GALLERYSTR_THEME_FONTWORK = u"private://gallery/hidden/fontwork";
+inline constexpr OUStringLiteral RID_GALLERYSTR_THEME_FONTWORK_VERTICAL = u"private://gallery/hidden/fontworkvertical";
+
+// Reference-strings for standardcolor-table
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_BLACK_DEF = u"Black";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_BLUE_DEF = u"Blue";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_GREEN_DEF = u"Green";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_RED_DEF = u"Red";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_GREY_DEF = u"Gray";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_YELLOW_DEF = u"Yellow";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_WHITE_DEF = u"White";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_BLUEGREY_DEF = u"Blue gray";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_ORANGE_DEF = u"Orange";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MAGENTA_DEF = u"Magenta";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_BORDEAUX_DEF = u"Bordeaux";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_PALE_YELLOW_DEF = u"Pale yellow";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_PALE_GREEN_DEF = u"Pale green";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKVIOLET_DEF = u"Dark violet";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_SALMON_DEF = u"Salmon";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_SEABLUE_DEF = u"Sea blue";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_CHART_DEF = u"Chart";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_PURPLE_DEF = u"Purple";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_SKYBLUE_DEF = u"Sky blue";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_YELLOWGREEN_DEF = u"Yellow green";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_PINK_DEF = u"Pink";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_TURQUOISE_DEF = u"Turquoise";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_BLUE_CLASSIC_DEF = u"Blue classic";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_GOLD_DEF = u"Gold";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_BRICK_DEF = u"Brick";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_INDIGO_DEF = u"Indigo";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_TEAL_DEF = u"Teal";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIME_DEF = u"Lime";
+// Reference strings: Light variants of the standard color palette
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTGRAY_DEF = u"Light Gray";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTYELLOW_DEF = u"Light Yellow";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTGOLD_DEF = u"Light Gold";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTORANGE_DEF = u"Light Orange";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTBRICK_DEF = u"Light Brick";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTRED_DEF = u"Light Red";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTMAGENTA_DEF = u"Light Magenta";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTPURPLE_DEF = u"Light Purple";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTINDIGO_DEF = u"Light Indigo";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTBLUE_DEF = u"Light Blue";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTTEAL_DEF = u"Light Teal";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTGREEN_DEF = u"Light Green";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIGHTLIME_DEF = u"Light Lime";
+// Reference strings: Dark variants of the standard color palette
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKGRAY_DEF = u"Dark Gray";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKYELLOW_DEF = u"Dark Yellow";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKGOLD_DEF = u"Dark Gold";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKORANGE_DEF = u"Dark Orange";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKBRICK_DEF = u"Dark Brick";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKRED_DEF = u"Dark Red";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKMAGENTA_DEF = u"Dark Magenta";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKPURPLE_DEF = u"Dark Purple";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKINDIGO_DEF = u"Dark Indigo";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKBLUE_DEF = u"Dark Blue";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKTEAL_DEF = u"Dark Teal";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKGREEN_DEF = u"Dark Green";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_DARKLIME_DEF = u"Dark Lime";
+// Reference strings for the Tonal palette
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_VIOLET_DEF = u"Violet";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_VIOLET_OUG_DEF = u"Violet (Out of Gamut)";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_BLUE_OUG_DEF = u"Blue (Out of Gamut)";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_AZURE_OUG_DEF = u"Azure (Out of Gamut)";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_SPRINGGREEN_OUG_DEF = u"Spring Green (Out of Gamut)";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_GREEN_OUG_DEF = u"Green (Out of Gamut)";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_CHARTREUSEGREEN_OUG_DEF = u"Chartreuse Green (Out of Gamut)";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_ORANGE_OUG_DEF = u"Orange (Out of Gamut)";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_RED_OUG_DEF = u"Red (Out of Gamut)";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_ROSE_OUG_DEF = u"Rose (Out of Gamut)";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_AZURE_DEF = u"Azure";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_CYAN_DEF = u"Cyan";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_SPRINGGREEN_DEF = u"Spring Green";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_CHARTREUSEGREEN_DEF = u"Chartreuse Green";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_ROSE_DEF = u"Rose";
+// Reference strings for the Material palette
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_GRAY_A_DEF = u"Gray A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_YELLOW_A_DEF = u"Yellow A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_AMBER_A_DEF = u"Amber A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_AMBER_DEF = u"Amber";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_ORANGE_A_DEF = u"Orange A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_DEEP_ORANGE_A_DEF = u"Deep Orange A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_DEEP_ORANGE_DEF = u"Deep Orange";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_RED_A_DEF = u"Red A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_PINK_A_DEF = u"Pink A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_PURPLE_A_DEF = u"Purple A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_DEEP_PURPLE_A_DEF = u"Deep Purple A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_DEEP_PURPLE_DEF = u"Deep Purple";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_INDIGO_A_DEF = u"Indigo A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_BLUE_A_DEF = u"Blue A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_LIGHT_BLUE_A_DEF = u"Light Blue A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_CYAN_A_DEF = u"Cyan A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_TEAL_A_DEF = u"Teal A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_GREEN_A_DEF = u"Green A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_LIGHT_GREEN_A_DEF = u"Light Green A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_LIME_A_DEF = u"Lime A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_BROWN_A_DEF = u"Brown A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_BROWN_DEF = u"Brown";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_BLUE_GRAY_A_DEF = u"Blue Gray A";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_MATERIAL_BLUE_GRAY_DEF = u"Blue Gray";
+// Reference-strings for standard-gradient-table
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT0_DEF = u"Gradient";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT1_DEF = u"Linear blue/white";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT2_DEF = u"Linear magenta/green";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT3_DEF = u"Linear yellow/brown";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT4_DEF = u"Radial green/black";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT5_DEF = u"Radial red/yellow";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT6_DEF = u"Rectangular red/white";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT7_DEF = u"Square yellow/white";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT8_DEF = u"Ellipsoid blue grey/light blue";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT9_DEF = u"Axial light red/white";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT10_DEF = u"Diagonal 1l";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT11_DEF = u"Diagonal 1r";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT12_DEF = u"Diagonal 2l";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT13_DEF = u"Diagonal 2r";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT14_DEF = u"Diagonal 3l";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT15_DEF = u"Diagonal 3r";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT16_DEF = u"Diagonal 4l";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT17_DEF = u"Diagonal 4r";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT18_DEF = u"Diagonal Blue";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT19_DEF = u"Diagonal Green";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT20_DEF = u"Diagonal Orange";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT21_DEF = u"Diagonal Red";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT22_DEF = u"Diagonal Turquoise";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT23_DEF = u"Diagonal Violet";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT24_DEF = u"From a Corner";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT25_DEF = u"From a Corner, Blue";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT26_DEF = u"From a Corner, Green";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT27_DEF = u"From a Corner, Orange";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT28_DEF = u"From a Corner, Red";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT29_DEF = u"From a Corner, Turquoise";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT30_DEF = u"From a Corner, Violet";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT31_DEF = u"From the Middle";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT32_DEF = u"From the Middle, Blue";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT33_DEF = u"From the Middle, Green";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT34_DEF = u"From the Middle, Orange";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT35_DEF = u"From the Middle, Red";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT36_DEF = u"From the Middle, Turquoise";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT37_DEF = u"From the Middle, Violet";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT38_DEF = u"Horizontal";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT39_DEF = u"Horizontal Blue";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT40_DEF = u"Horizontal Green";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT41_DEF = u"Horizontal Orange";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT42_DEF = u"Horizontal Red";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT43_DEF = u"Horizontal Turquoise";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT44_DEF = u"Horizontal Violet";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT45_DEF = u"Radial";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT46_DEF = u"Radial Blue";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT47_DEF = u"Radial Green";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT48_DEF = u"Radial Orange";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT49_DEF = u"Radial Red";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT50_DEF = u"Radial Turquoise";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT51_DEF = u"Radial Violet";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT52_DEF = u"Vertical";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT53_DEF = u"Vertical Blue";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT54_DEF = u"Vertical Green";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT55_DEF = u"Vertical Orange";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT56_DEF = u"Vertical Red";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT57_DEF = u"Vertical Turquoise";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT58_DEF = u"Vertical Violet";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT59_DEF = u"Gray Gradient";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT60_DEF = u"Yellow Gradient";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT61_DEF = u"Orange Gradient";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT62_DEF = u"Red Gradient";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT63_DEF = u"Pink Gradient";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT64_DEF = u"Sky";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT65_DEF = u"Cyan Gradient";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT66_DEF = u"Blue Gradient";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT67_DEF = u"Purple Pipe";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT68_DEF = u"Night";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT69_DEF = u"Green Gradient";
+//actual gradients defined for 6.1
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT70_DEF = u"Pastel Bouquet";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT71_DEF = u"Pastel Dream";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT72_DEF = u"Blue Touch";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT73_DEF = u"Blank with Gray";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT74_DEF = u"Spotted Gray";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT75_DEF = u"London Mist";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT76_DEF = u"Teal to Blue";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT77_DEF = u"Midnight";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT78_DEF = u"Deep Ocean";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT79_DEF = u"Submarine";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT80_DEF = u"Green Grass";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT81_DEF = u"Neon Light";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT82_DEF = u"Sunshine";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT83_DEF = u"Present";
+inline constexpr OUStringLiteral RID_SVXSTR_GRDT84_DEF = u"Mahogany";
+// Reference-strings for standard-hatch-table
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH0_DEF = u"Black 0 Degrees";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH1_DEF = u"Black 90 Degrees";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH2_DEF = u"Black 180 Degrees Crossed";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH3_DEF = u"Blue 45 Degrees";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH4_DEF = u"Blue -45 Degrees";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH5_DEF = u"Blue 45 Degrees Crossed";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH6_DEF = u"Green 30 Degrees";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH7_DEF = u"Green 60 Degrees";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH8_DEF = u"Green 90 Degrees Triple";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH9_DEF = u"Red 45 Degrees";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH10_DEF = u"Red 90 Degrees Crossed";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH11_DEF = u"Red -45 Degrees Triple";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH12_DEF = u"Yellow 45 Degrees";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH13_DEF = u"Yellow 45 Degrees Crossed";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH14_DEF = u"Yellow 45 Degrees Triple";
+inline constexpr OUStringLiteral RID_SVXSTR_HATCH15_DEF = u"Hatching";
+// Reference-strings for standard-bitmap-table
+inline constexpr OUStringLiteral RID_SVXSTR_BMP0_DEF = u"Empty";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP1_DEF = u"Painted White";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP2_DEF = u"Paper Texture";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP3_DEF = u"Paper Crumpled";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP4_DEF = u"Paper Graph";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP5_DEF = u"Parchment Paper";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP6_DEF = u"Fence";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP7_DEF = u"Wooden Board";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP8_DEF = u"Maple Leaves";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP9_DEF = u"Lawn";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP10_DEF = u"Colorful Pebbles";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP11_DEF = u"Coffee Beans";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP12_DEF = u"Little Clouds";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP13_DEF = u"Bathroom Tiles";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP14_DEF = u"Wall of Rock";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP15_DEF = u"Zebra";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP16_DEF = u"Color Stripes";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP17_DEF = u"Gravel";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP18_DEF = u"Parchment Studio";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP19_DEF = u"Night Sky";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP20_DEF = u"Pool";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP21_DEF = u"Bitmap";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP79_DEF = u"Invoice Paper";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP80_DEF = u"Concrete";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP81_DEF = u"Brick Wall";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP82_DEF = u"Stone Wall";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP83_DEF = u"Floral";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP84_DEF = u"Space";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP85_DEF = u"Ice light";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP86_DEF = u"Marble";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP87_DEF = u"Sand light";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP88_DEF = u"Stone";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP89_DEF = u"White Diffusion";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP90_DEF = u"Surface";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP91_DEF = u"Cardboard";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP92_DEF = u"Studio";
+// Reference strings for patterns - they are a variation of bitmaps
+inline constexpr OUStringLiteral RID_SVXSTR_BMP22_DEF = u"5 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP23_DEF = u"10 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP24_DEF = u"20 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP25_DEF = u"25 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP26_DEF = u"30 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP27_DEF = u"40 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP28_DEF = u"50 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP29_DEF = u"60 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP30_DEF = u"70 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP31_DEF = u"75 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP32_DEF = u"80 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP33_DEF = u"90 Percent";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP34_DEF = u"Light Downward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP35_DEF = u"Light Upward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP36_DEF = u"Dark Downward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP37_DEF = u"Dark Upward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP38_DEF = u"Wide Downward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP39_DEF = u"Wide Upward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP40_DEF = u"Light Vertical";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP41_DEF = u"Light Horizontal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP42_DEF = u"Narrow Vertical";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP43_DEF = u"Narrow Horizontal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP44_DEF = u"Dark Vertical";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP45_DEF = u"Dark Horizontal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP46_DEF = u"Dashed Downward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP47_DEF = u"Dashed Upward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP48_DEF = u"Dashed Horizontal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP49_DEF = u"Dashed Vertical";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP50_DEF = u"Small Confetti";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP51_DEF = u"Large Confetti";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP52_DEF = u"Zig Zag";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP53_DEF = u"Wave";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP54_DEF = u"Diagonal Brick";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP55_DEF = u"Horizontal Brick";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP56_DEF = u"Weave";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP57_DEF = u"Plaid";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP58_DEF = u"Divot";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP59_DEF = u"Dotted Grid";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP60_DEF = u"Dotted Diamond";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP61_DEF = u"Shingle";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP62_DEF = u"Trellis";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP63_DEF = u"Sphere";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP64_DEF = u"Small Grid";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP65_DEF = u"Large Grid";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP66_DEF = u"Small Checker Board";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP67_DEF = u"Large Checker Board";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP68_DEF = u"Outlined Diamond";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP69_DEF = u"Solid Diamond";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP70_DEF = u"Vertical";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP71_DEF = u"Horizontal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP72_DEF = u"Downward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP73_DEF = u"Upward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP74_DEF = u"Cross";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP75_DEF = u"Diagonal Cross";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP76_DEF = u"Dashed Dotted";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP77_DEF = u"Dashed Dotted Upward Diagonal";
+inline constexpr OUStringLiteral RID_SVXSTR_BMP78_DEF = u"Solid Dotted";
+// Reference-strings for standard-dash-table;
+inline constexpr OUStringLiteral RID_SVXSTR_DASH0_DEF = u"Dot";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH1_DEF = u"Long Dot";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH2_DEF = u"Dot (Rounded)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH3_DEF = u"Dash";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH4_DEF = u"Long Dash";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH5_DEF = u"Double Dash";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH6_DEF = u"Long Dash Dot";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH7_DEF = u"Double Dash Dot";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH8_DEF = u"Double Dash Dot Dot";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH9_DEF = u"Ultrafine Dotted (var)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH10_DEF = u"Fine Dotted";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH11_DEF = u"Ultrafine Dashed";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH12_DEF = u"Fine Dashed";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH13_DEF = u"Fine Dashed (var)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH14_DEF = u"Dashed (var)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH15_DEF = u"Line Style 9";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH16_DEF = u"3 Dashes 3 Dots (var)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH17_DEF = u"Ultrafine 2 Dots 3 Dashes";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH18_DEF = u"2 Dots 1 Dash";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH19_DEF = u"Line with Fine Dots";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH20_DEF = u"Dash Dot";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH21_DEF = u"Long Dot (Rounded)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH22_DEF = u"Dash Dot Dot";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH23_DEF = u"Dash (Rounded)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH24_DEF = u"Long Dash (Rounded)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH25_DEF = u"Double Dash (Rounded)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH26_DEF = u"Dash Dot (Rounded)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH27_DEF = u"Long Dash Dot (Rounded)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH28_DEF = u"Double Dash Dot (Rounded)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH29_DEF = u"Dash Dot Dot (Rounded)";
+inline constexpr OUStringLiteral RID_SVXSTR_DASH30_DEF = u"Double Dash Dot Dot (Rounded)";
+
+// Reference-strings for standard-line-end-table
+inline constexpr OUStringLiteral RID_SVXSTR_LEND0_DEF = u"Concave short";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND1_DEF = u"Square 45";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND2_DEF = u"Arrow short";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND3_DEF = u"Dimension Lines";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND4_DEF = u"Double Arrow";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND5_DEF = u"Triangle";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND6_DEF = u"Concave";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND7_DEF = u"Arrow large";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND8_DEF = u"Dimension Line";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND9_DEF = u"Circle";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND10_DEF = u"Square";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND11_DEF = u"Arrow";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND12_DEF = u"Half Circle";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND13_DEF = u"Triangle unfilled";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND14_DEF = u"Diamond unfilled";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND15_DEF = u"Diamond";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND16_DEF = u"Circle unfilled";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND17_DEF = u"Square 45 unfilled";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND18_DEF = u"Square unfilled";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND19_DEF = u"Half Circle unfilled";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND20_DEF = u"Dimension Line Arrow";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND21_DEF = u"Line short";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND22_DEF = u"Line";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND23_DEF = u"Half Arrow left";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND24_DEF = u"Half Arrow right";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND25_DEF = u"Reversed Arrow";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND26_DEF = u"CF One";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND27_DEF = u"CF Only One";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND28_DEF = u"CF Many";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND29_DEF = u"CF Many One";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND30_DEF = u"CF Zero One";
+inline constexpr OUStringLiteral RID_SVXSTR_LEND31_DEF = u"CF Zero Many";
+// Reference-strings for standard transparence gradients
+inline constexpr OUStringLiteral RID_SVXSTR_TRASNGR0_DEF = u"Transparency";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIBRE_GREEN_1_DEF = u"Green 1 (%PRODUCTNAME Main Color)";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIBRE_GREEN_ACCENT_DEF = u"Green Accent";;
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIBRE_BLUE_ACCENT_DEF = u"Blue Accent";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIBRE_ORANGE_ACCENT_DEF = u"Orange Accent";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIBRE_PURPLE_DEF = u"Purple";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIBRE_PURPLE_ACCENT_DEF = u"Purple Accent";
+inline constexpr OUStringLiteral RID_SVXSTR_COLOR_LIBRE_YELLOW_ACCENT_DEF = u"Yellow Accent";
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/inc/svxerr.hrc b/svx/inc/svxerr.hrc
new file mode 100644
index 000000000..40066df41
--- /dev/null
+++ b/svx/inc/svxerr.hrc
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SVXERR_HRC
+#define INCLUDED_SVX_INC_SVXERR_HRC
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+#include <svx/svxerr.hxx>
+#include <editeng/editerr.hxx>
+
+// Error-Context ---------------------------------------------------------
+const ErrMsgCode RID_SVXERRCTX[] =
+{
+ { NC_("RID_SVXERRCTX", "$(ERR) executing the thesaurus.") ,
+ ErrCode(ERRCTX_SVX_LINGU_THESAURUS) },
+ { NC_("RID_SVXERRCTX", "$(ERR) executing the spellcheck.") ,
+ ErrCode(ERRCTX_SVX_LINGU_SPELLING) },
+ { NC_("RID_SVXERRCTX", "$(ERR) executing the hyphenation.") ,
+ ErrCode(ERRCTX_SVX_LINGU_HYPHENATION) },
+ { NC_("RID_SVXERRCTX", "$(ERR) creating a dictionary.") ,
+ ErrCode(ERRCTX_SVX_LINGU_DICTIONARY) },
+ { NC_("RID_SVXERRCTX", "$(ERR) setting background attribute.") ,
+ ErrCode(ERRCTX_SVX_BACKGROUND) },
+ { NC_("RID_SVXERRCTX", "$(ERR) loading the graphics.") ,
+ ErrCode(ERRCTX_SVX_IMPORT_GRAPHIC) },
+ { {}, ERRCODE_NONE }
+};
+
+// Error-Code ------------------------------------------------------------
+const ErrMsgCode RID_SVXERRCODE[] =
+{
+ { NC_("RID_SVXERRCODE", "$(ARG1) is not supported by the spellcheck function or is not presently active.\nPlease check your installation and, if necessary, install the required language module\nor activate it under 'Tools - Options - Language Settings - Writing Aids'."),
+ ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS },
+ { NC_("RID_SVXERRCODE", "Spellcheck is not available.") ,
+ ERRCODE_SVX_LINGU_LINGUNOTEXISTS },
+ { NC_("RID_SVXERRCODE", "The custom dictionary $(ARG1) cannot be created.") ,
+ ERRCODE_SVX_LINGU_DICT_NOTWRITEABLE },
+ { NC_("RID_SVXERRCODE", "The graphic $(ARG1) could not be found.") ,
+ ERRCODE_SVX_GRAPHIC_NOTREADABLE },
+ { NC_("RID_SVXERRCODE", "An unlinked graphic could not be loaded."),
+ ERRCODE_SVX_GRAPHIC_WRONG_FILEFORMAT },
+ { NC_("RID_SVXERRCODE", "A language has not been fixed for the selected term."),
+ ERRCODE_SVX_LINGU_NOLANGUAGE },
+ { NC_("RID_SVXERRCODE", "All changes to the Basic Code are lost. The original VBA Macro Code is saved instead."),
+ ERRCODE_SVX_MODIFIED_VBASIC_STORAGE },
+ { NC_("RID_SVXERRCODE", "The original VBA Basic Code contained in the document will not be saved."),
+ ERRCODE_SVX_VBASIC_STORAGE_EXIST },
+ { NC_("RID_SVXERRCODE", "The password is incorrect. The document cannot be opened."),
+ ERRCODE_SVX_WRONGPASS },
+ { NC_("RID_SVXERRCODE", "The encryption method used in this document is not supported. Only Microsoft Office 97/2000 compatible password encryption is supported."),
+ ERRCODE_SVX_READ_FILTER_CRYPT },
+ { NC_("RID_SVXERRCODE", "The loading of password-encrypted Microsoft PowerPoint presentations is not supported."),
+ ERRCODE_SVX_READ_FILTER_PPOINT },
+ { NC_("RID_SVXERRCODE", "Password protection is not supported when documents are saved in a Microsoft Office format.\nDo you want to save the document without password protection?"),
+ ERRCODE_SVX_EXPORT_FILTER_CRYPT },
+ { {}, ERRCODE_NONE }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/swframeposstrings.hrc b/svx/inc/swframeposstrings.hrc
new file mode 100644
index 000000000..f7c845dba
--- /dev/null
+++ b/svx/inc/swframeposstrings.hrc
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_SWFRAMEPOSSTRINGS_HRC
+#define INCLUDED_SVX_INC_SWFRAMEPOSSTRINGS_HRC
+
+#include <unotools/resmgr.hxx>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+//the following string have to match the (enum values) positions in svx/swframeposstrings.hxx!
+const TranslateId RID_SVXSW_FRAMEPOSITIONS[] =
+{
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Left"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Right"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "From left"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Inside"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Outside"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "From inside"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Entire paragraph area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Paragraph text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Left of page text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Right of page text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Left of paragraph text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Right of paragraph text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Inner page border"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Outer page border"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Inner paragraph border"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Outer paragraph border"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Entire page"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Page text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Above page text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Below page text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Base line"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Character"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Row"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Entire paragraph area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Paragraph text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Left of frame text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Right of frame text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Entire frame"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Frame text area"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Inner frame border"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Outer frame border"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Top"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Bottom"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Center"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Center"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "From top"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "From bottom"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Below"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "From right"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Top page border"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Bottom page border"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Top paragraph border"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Bottom paragraph border"),
+ NC_("RID_SVXSW_FRAMEPOSITIONS", "Line of text")
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxallitm.hxx b/svx/inc/sxallitm.hxx
new file mode 100644
index 000000000..144d3bae2
--- /dev/null
+++ b/svx/inc/sxallitm.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXALLITM_HXX
+#define INCLUDED_SVX_INC_SXALLITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdmetitm.hxx>
+
+class SdrAllPositionXItem final : public SdrMetricItem {
+public:
+ SdrAllPositionXItem(tools::Long nPosX=0): SdrMetricItem(SDRATTR_ALLPOSITIONX,nPosX) {}
+ virtual SdrAllPositionXItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrAllPositionXItem(*this);
+ }
+};
+
+class SdrAllPositionYItem final : public SdrMetricItem {
+public:
+ SdrAllPositionYItem(tools::Long nPosY=0): SdrMetricItem(SDRATTR_ALLPOSITIONY,nPosY) {}
+ virtual SdrAllPositionYItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrAllPositionYItem(*this);
+ }
+};
+
+class SdrAllSizeWidthItem final : public SdrMetricItem {
+public:
+ SdrAllSizeWidthItem(tools::Long nWdt=0): SdrMetricItem(SDRATTR_ALLSIZEWIDTH,nWdt) {}
+ virtual SdrAllSizeWidthItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrAllSizeWidthItem(*this);
+ }
+};
+
+class SdrAllSizeHeightItem final : public SdrMetricItem {
+public:
+ SdrAllSizeHeightItem(tools::Long nHgt=0): SdrMetricItem(SDRATTR_ALLSIZEHEIGHT,nHgt) {}
+ virtual SdrAllSizeHeightItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrAllSizeHeightItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxcaitm.hxx b/svx/inc/sxcaitm.hxx
new file mode 100644
index 000000000..26d4a3194
--- /dev/null
+++ b/svx/inc/sxcaitm.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svx/svddef.hxx>
+
+#include <svx/sdangitm.hxx>
+
+// SDRATTR_CAPTIONFIXEDANGLE SdrOnOffItem:
+// sal_True=angle predefined by SdrCaptionAngleItem
+// sal_False=free angle
+
+// class SdrCaptionAngleItem
+// angle in 1/100 degree
+// only if Type2, Type3 and Type4
+// and only if SdrCaptionIsFixedAngleItem=TRUE
+
+class SdrCaptionAngleItem final : public SdrAngleItem
+{
+public:
+ SdrCaptionAngleItem(Degree100 nAngle = 0_deg100)
+ : SdrAngleItem(SDRATTR_CAPTIONANGLE, nAngle)
+ {
+ }
+ virtual SdrCaptionAngleItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrCaptionAngleItem(*this);
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxcikitm.hxx b/svx/inc/sxcikitm.hxx
new file mode 100644
index 000000000..738e59366
--- /dev/null
+++ b/svx/inc/sxcikitm.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXCIKITM_HXX
+#define INCLUDED_SVX_INC_SXCIKITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svl/eitem.hxx>
+#include <svx/svdocirc.hxx>
+
+class SdrCircKindItem final : public SfxEnumItem<SdrCircKind> {
+public:
+ SdrCircKindItem(SdrCircKind eKind=SdrCircKind::Full): SfxEnumItem(SDRATTR_CIRCKIND, eKind) {}
+ virtual SdrCircKindItem* Clone(SfxItemPool* pPool=nullptr) const override;
+ virtual sal_uInt16 GetValueCount() const override; // { return 4; }
+
+ virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override;
+ virtual bool PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) override;
+
+ static OUString GetValueTextByPos(sal_uInt16 nPos);
+ virtual bool GetPresentation(SfxItemPresentation ePres, MapUnit eCoreMetric, MapUnit ePresMetric, OUString& rText, const IntlWrapper&) const override;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxfiitm.hxx b/svx/inc/sxfiitm.hxx
new file mode 100644
index 000000000..b629acfeb
--- /dev/null
+++ b/svx/inc/sxfiitm.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svl/poolitem.hxx>
+#include <tools/fract.hxx>
+
+/*************************************************************************/
+/* FractionItem */
+/*************************************************************************/
+
+class SdrFractionItem: public SfxPoolItem {
+ Fraction nValue;
+public:
+ SdrFractionItem(sal_uInt16 nId, const Fraction& rVal): SfxPoolItem(nId), nValue(rVal) {}
+ virtual bool operator==(const SfxPoolItem&) const override;
+ virtual bool GetPresentation(SfxItemPresentation ePresentation, MapUnit eCoreMetric, MapUnit ePresentationMetric, OUString &rText, const IntlWrapper&) const override;
+ virtual SdrFractionItem* Clone(SfxItemPool *pPool=nullptr) const override;
+ const Fraction& GetValue() const { return nValue; }
+};
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxlayitm.hxx b/svx/inc/sxlayitm.hxx
new file mode 100644
index 000000000..be444bec3
--- /dev/null
+++ b/svx/inc/sxlayitm.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXLAYITM_HXX
+#define INCLUDED_SVX_INC_SXLAYITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svl/stritem.hxx>
+#include <svl/intitem.hxx>
+#include <svx/svdtypes.hxx>
+
+class SdrLayerIdItem final : public SfxInt16Item {
+public:
+ SdrLayerIdItem(SdrLayerID nId): SfxInt16Item(SDRATTR_LAYERID,nId.get()) {}
+ SdrLayerID GetValue() const { return SdrLayerID(SfxInt16Item::GetValue()); }
+ virtual SdrLayerIdItem* Clone(SfxItemPool* pPool=nullptr) const override;
+};
+
+class SdrLayerNameItem final : public SfxStringItem {
+public:
+ SdrLayerNameItem() : SfxStringItem() { SetWhich(SDRATTR_LAYERNAME); }
+ SdrLayerNameItem(const OUString& rStr) : SfxStringItem(SDRATTR_LAYERNAME,rStr) {}
+ virtual SdrLayerNameItem* Clone(SfxItemPool* pPool=nullptr) const override;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxlogitm.hxx b/svx/inc/sxlogitm.hxx
new file mode 100644
index 000000000..20d61724b
--- /dev/null
+++ b/svx/inc/sxlogitm.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXLOGITM_HXX
+#define INCLUDED_SVX_INC_SXLOGITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdmetitm.hxx>
+
+class SdrLogicSizeWidthItem final : public SdrMetricItem {
+public:
+ SdrLogicSizeWidthItem(tools::Long nWdt=0): SdrMetricItem(SDRATTR_LOGICSIZEWIDTH,nWdt) {}
+ virtual SdrLogicSizeWidthItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrLogicSizeWidthItem(*this);
+ }
+};
+
+class SdrLogicSizeHeightItem final : public SdrMetricItem {
+public:
+ SdrLogicSizeHeightItem(tools::Long nHgt=0): SdrMetricItem(SDRATTR_LOGICSIZEHEIGHT,nHgt) {}
+ virtual SdrLogicSizeHeightItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrLogicSizeHeightItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxmfsitm.hxx b/svx/inc/sxmfsitm.hxx
new file mode 100644
index 000000000..c3c070952
--- /dev/null
+++ b/svx/inc/sxmfsitm.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svx/svddef.hxx>
+#include <svl/stritem.hxx>
+
+// Format string (similar to Calc), e.g. "#.###,00km"
+// overwrites SdrMeasureUnitItem and SdrMeasureShowUnitItem
+class SdrMeasureFormatStringItem final : public SfxStringItem {
+public:
+ SdrMeasureFormatStringItem() : SfxStringItem() { SetWhich(SDRATTR_MEASUREFORMATSTRING); }
+ virtual SdrMeasureFormatStringItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrMeasureFormatStringItem(*this);
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxmkitm.hxx b/svx/inc/sxmkitm.hxx
new file mode 100644
index 000000000..12769a085
--- /dev/null
+++ b/svx/inc/sxmkitm.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXMKITM_HXX
+#define INCLUDED_SVX_INC_SXMKITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svl/eitem.hxx>
+
+enum SdrMeasureKind {SDRMEASURE_STD,SDRMEASURE_RADIUS}; // n.i.
+
+
+
+class SdrMeasureKindItem final : public SfxEnumItem<SdrMeasureKind> {
+public:
+ SdrMeasureKindItem() : SfxEnumItem(SDRATTR_MEASUREKIND, SDRMEASURE_STD) {}
+ virtual SdrMeasureKindItem* Clone(SfxItemPool* pPool=nullptr) const override;
+ virtual sal_uInt16 GetValueCount() const override; // { return 2; }
+
+ virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override;
+ virtual bool PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) override;
+
+ static OUString GetValueTextByPos(sal_uInt16 nPos);
+ virtual bool GetPresentation(SfxItemPresentation ePres, MapUnit eCoreMetric, MapUnit ePresMetric, OUString& rText, const IntlWrapper&) const override;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxmoitm.hxx b/svx/inc/sxmoitm.hxx
new file mode 100644
index 000000000..f207f7411
--- /dev/null
+++ b/svx/inc/sxmoitm.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXMOITM_HXX
+#define INCLUDED_SVX_INC_SXMOITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdmetitm.hxx>
+
+// Overlap of the measure line over the measure helper lines
+// Only of the measure arrows are on the outside
+class SdrMeasureOverhangItem final : public SdrMetricItem
+{
+public:
+ SdrMeasureOverhangItem(tools::Long nVal)
+ : SdrMetricItem(SDRATTR_MEASUREOVERHANG, nVal)
+ {
+ }
+ virtual SdrMeasureOverhangItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrMeasureOverhangItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxmovitm.hxx b/svx/inc/sxmovitm.hxx
new file mode 100644
index 000000000..eda423e27
--- /dev/null
+++ b/svx/inc/sxmovitm.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXMOVITM_HXX
+#define INCLUDED_SVX_INC_SXMOVITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdmetitm.hxx>
+
+class SdrMoveXItem final : public SdrMetricItem {
+public:
+ SdrMoveXItem(): SdrMetricItem(SDRATTR_MOVEX,0) {}
+ SdrMoveXItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrMoveXItem(*this);
+ }
+};
+
+class SdrMoveYItem final : public SdrMetricItem {
+public:
+ SdrMoveYItem(): SdrMetricItem(SDRATTR_MOVEY,0) {}
+ SdrMoveYItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrMoveYItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxmsitm.hxx b/svx/inc/sxmsitm.hxx
new file mode 100644
index 000000000..f821c73fe
--- /dev/null
+++ b/svx/inc/sxmsitm.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXMSITM_HXX
+#define INCLUDED_SVX_INC_SXMSITM_HXX
+
+#include <svx/svddef.hxx>
+#include "sxsiitm.hxx"
+
+// Measure scale setting
+// We do not overwrite a measure scale (UIScale), If the model already has one set.
+// Instead, we multiply them with each other.
+class SdrMeasureScaleItem final : public SdrScaleItem
+{
+public:
+ SdrMeasureScaleItem()
+ : SdrScaleItem(SDRATTR_MEASURESCALE, Fraction(1, 1))
+ {
+ }
+ virtual SdrMeasureScaleItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrMeasureScaleItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxmtaitm.hxx b/svx/inc/sxmtaitm.hxx
new file mode 100644
index 000000000..cb94874bd
--- /dev/null
+++ b/svx/inc/sxmtaitm.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXMTAITM_HXX
+#define INCLUDED_SVX_INC_SXMTAITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdynitm.hxx>
+#include <svx/sdangitm.hxx>
+
+// Turn text automatically in wright position (automatic UpsideDown).
+// TextUpsideDown stays active and turns the text again if sal_True.
+class SdrMeasureTextAutoAngleItem final : public SdrYesNoItem {
+public:
+ SdrMeasureTextAutoAngleItem(bool bOn=true): SdrYesNoItem(SDRATTR_MEASURETEXTAUTOANGLE,bOn) {}
+ virtual SdrMeasureTextAutoAngleItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrMeasureTextAutoAngleItem(*this);
+ }
+};
+
+// Preferred perspective for reading text is only evaluated if TextAutoAngle=TRUE.
+// Angle in 1/100deg from viewpoint of the user.
+class SdrMeasureTextAutoAngleViewItem final : public SdrAngleItem {
+public:
+ SdrMeasureTextAutoAngleViewItem(Degree100 nVal=31500_deg100): SdrAngleItem(SDRATTR_MEASURETEXTAUTOANGLEVIEW,nVal) {}
+ virtual SdrMeasureTextAutoAngleViewItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrMeasureTextAutoAngleViewItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxoneitm.hxx b/svx/inc/sxoneitm.hxx
new file mode 100644
index 000000000..424563008
--- /dev/null
+++ b/svx/inc/sxoneitm.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXONEITM_HXX
+#define INCLUDED_SVX_INC_SXONEITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdmetitm.hxx>
+
+class SdrOnePositionXItem final : public SdrMetricItem {
+public:
+ SdrOnePositionXItem(tools::Long nPosX=0): SdrMetricItem(SDRATTR_ONEPOSITIONX,nPosX) {}
+ virtual SdrOnePositionXItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrOnePositionXItem(*this);
+ }
+};
+
+class SdrOnePositionYItem final : public SdrMetricItem {
+public:
+ SdrOnePositionYItem(tools::Long nPosY=0): SdrMetricItem(SDRATTR_ONEPOSITIONY,nPosY) {}
+ virtual SdrOnePositionYItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrOnePositionYItem(*this);
+ }
+};
+
+class SdrOneSizeWidthItem final : public SdrMetricItem {
+public:
+ SdrOneSizeWidthItem(tools::Long nWdt=0): SdrMetricItem(SDRATTR_ONESIZEWIDTH,nWdt) {}
+ virtual SdrOneSizeWidthItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrOneSizeWidthItem(*this);
+ }
+};
+
+class SdrOneSizeHeightItem final : public SdrMetricItem {
+public:
+ SdrOneSizeHeightItem(tools::Long nHgt=0): SdrMetricItem(SDRATTR_ONESIZEHEIGHT,nHgt) {}
+ virtual SdrOneSizeHeightItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrOneSizeHeightItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxopitm.hxx b/svx/inc/sxopitm.hxx
new file mode 100644
index 000000000..cd7d2bb1f
--- /dev/null
+++ b/svx/inc/sxopitm.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXOPITM_HXX
+#define INCLUDED_SVX_INC_SXOPITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdynitm.hxx>
+
+class SdrObjPrintableItem final : public SdrYesNoItem {
+public:
+ SdrObjPrintableItem(bool bOn=false): SdrYesNoItem(SDRATTR_OBJPRINTABLE,bOn) {}
+ virtual SdrObjPrintableItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrObjPrintableItem(*this);
+ }
+};
+
+class SdrObjVisibleItem final : public SdrYesNoItem {
+public:
+ SdrObjVisibleItem(bool bOn=true): SdrYesNoItem(SDRATTR_OBJVISIBLE,bOn) {}
+ virtual SdrObjVisibleItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrObjVisibleItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxreaitm.hxx b/svx/inc/sxreaitm.hxx
new file mode 100644
index 000000000..2887e8ba0
--- /dev/null
+++ b/svx/inc/sxreaitm.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXREAITM_HXX
+#define INCLUDED_SVX_INC_SXREAITM_HXX
+
+#include <svx/svddef.hxx>
+
+#include "sxfiitm.hxx"
+
+class SdrResizeXAllItem final : public SdrFractionItem {
+public:
+ SdrResizeXAllItem(): SdrFractionItem(SDRATTR_RESIZEXALL,Fraction(1,1)) {}
+ virtual SdrResizeXAllItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrResizeXAllItem(*this);
+ }
+};
+
+class SdrResizeYAllItem final : public SdrFractionItem {
+public:
+ SdrResizeYAllItem(): SdrFractionItem(SDRATTR_RESIZEYALL,Fraction(1,1)) {}
+ virtual SdrResizeYAllItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrResizeYAllItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxreoitm.hxx b/svx/inc/sxreoitm.hxx
new file mode 100644
index 000000000..19d1cb6b8
--- /dev/null
+++ b/svx/inc/sxreoitm.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXREOITM_HXX
+#define INCLUDED_SVX_INC_SXREOITM_HXX
+
+#include <svx/svddef.hxx>
+
+#include "sxfiitm.hxx"
+
+class SdrResizeXOneItem final : public SdrFractionItem {
+public:
+ SdrResizeXOneItem(): SdrFractionItem(SDRATTR_RESIZEXONE,Fraction(1,1)) {}
+ SdrResizeXOneItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrResizeXOneItem(*this);
+ }
+};
+
+class SdrResizeYOneItem final : public SdrFractionItem {
+public:
+ SdrResizeYOneItem(): SdrFractionItem(SDRATTR_RESIZEYONE,Fraction(1,1)) {}
+ SdrResizeYOneItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrResizeYOneItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxroaitm.hxx b/svx/inc/sxroaitm.hxx
new file mode 100644
index 000000000..7f1aec1c5
--- /dev/null
+++ b/svx/inc/sxroaitm.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXROAITM_HXX
+#define INCLUDED_SVX_INC_SXROAITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdangitm.hxx>
+
+class SdrRotateAllItem final : public SdrAngleItem
+{
+public:
+ SdrRotateAllItem()
+ : SdrAngleItem(SDRATTR_ROTATEALL, 0_deg100)
+ {
+ }
+ virtual SdrRotateAllItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrRotateAllItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxrooitm.hxx b/svx/inc/sxrooitm.hxx
new file mode 100644
index 000000000..f14bcf77f
--- /dev/null
+++ b/svx/inc/sxrooitm.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXROOITM_HXX
+#define INCLUDED_SVX_INC_SXROOITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdangitm.hxx>
+
+class SdrRotateOneItem final : public SdrAngleItem {
+public:
+ SdrRotateOneItem(): SdrAngleItem(SDRATTR_ROTATEONE,0_deg100) {}
+ SdrRotateOneItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrRotateOneItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxsaitm.hxx b/svx/inc/sxsaitm.hxx
new file mode 100644
index 000000000..190d66d7b
--- /dev/null
+++ b/svx/inc/sxsaitm.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXSAITM_HXX
+#define INCLUDED_SVX_INC_SXSAITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdangitm.hxx>
+
+class SdrShearAngleItem final : public SdrAngleItem
+{
+public:
+ SdrShearAngleItem(Degree100 nAngle = 0_deg100)
+ : SdrAngleItem(SDRATTR_SHEARANGLE, nAngle)
+ {
+ }
+ virtual SdrShearAngleItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrShearAngleItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxsalitm.hxx b/svx/inc/sxsalitm.hxx
new file mode 100644
index 000000000..304396206
--- /dev/null
+++ b/svx/inc/sxsalitm.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXSALITM_HXX
+#define INCLUDED_SVX_INC_SXSALITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdangitm.hxx>
+
+class SdrHorzShearAllItem final : public SdrAngleItem {
+public:
+ SdrHorzShearAllItem(): SdrAngleItem(SDRATTR_HORZSHEARALL,0_deg100) {}
+ virtual SdrHorzShearAllItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrHorzShearAllItem(*this);
+ }
+};
+
+class SdrVertShearAllItem final : public SdrAngleItem {
+public:
+ SdrVertShearAllItem(): SdrAngleItem(SDRATTR_VERTSHEARALL,0_deg100) {}
+ virtual SdrVertShearAllItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrVertShearAllItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxsiitm.hxx b/svx/inc/sxsiitm.hxx
new file mode 100644
index 000000000..2a5d65863
--- /dev/null
+++ b/svx/inc/sxsiitm.hxx
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "sxfiitm.hxx"
+
+class SdrScaleItem: public SdrFractionItem {
+public:
+ SdrScaleItem(sal_uInt16 nId, const Fraction& rVal): SdrFractionItem(nId,rVal) {}
+ virtual bool GetPresentation(SfxItemPresentation ePresentation, MapUnit eCoreMetric, MapUnit ePresentationMetric, OUString &rText, const IntlWrapper&) const override;
+ virtual SdrScaleItem* Clone(SfxItemPool *pPool=nullptr) const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxsoitm.hxx b/svx/inc/sxsoitm.hxx
new file mode 100644
index 000000000..ce5ce237e
--- /dev/null
+++ b/svx/inc/sxsoitm.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXSOITM_HXX
+#define INCLUDED_SVX_INC_SXSOITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdangitm.hxx>
+
+class SdrHorzShearOneItem final : public SdrAngleItem {
+public:
+ SdrHorzShearOneItem(): SdrAngleItem(SDRATTR_HORZSHEARONE,0_deg100) {}
+ SdrHorzShearOneItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrHorzShearOneItem(*this);
+ }
+};
+
+class SdrVertShearOneItem final : public SdrAngleItem {
+public:
+ SdrVertShearOneItem(): SdrAngleItem(SDRATTR_VERTSHEARONE,0_deg100) {}
+ SdrVertShearOneItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrVertShearOneItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/sxtraitm.hxx b/svx/inc/sxtraitm.hxx
new file mode 100644
index 000000000..2a1fdec4c
--- /dev/null
+++ b/svx/inc/sxtraitm.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_SXTRAITM_HXX
+#define INCLUDED_SVX_INC_SXTRAITM_HXX
+
+#include <svx/svddef.hxx>
+#include <svx/sdmetitm.hxx>
+
+class SdrTransformRef1XItem final : public SdrMetricItem {
+public:
+ SdrTransformRef1XItem(tools::Long nHgt=0): SdrMetricItem(SDRATTR_TRANSFORMREF1X,nHgt) {}
+ virtual SdrTransformRef1XItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrTransformRef1XItem(*this);
+ }
+};
+
+class SdrTransformRef1YItem final : public SdrMetricItem {
+public:
+ SdrTransformRef1YItem(tools::Long nHgt=0): SdrMetricItem(SDRATTR_TRANSFORMREF1Y,nHgt) {}
+ virtual SdrTransformRef1YItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrTransformRef1YItem(*this);
+ }
+};
+
+class SdrTransformRef2XItem final : public SdrMetricItem {
+public:
+ SdrTransformRef2XItem(tools::Long nHgt=0): SdrMetricItem(SDRATTR_TRANSFORMREF2X,nHgt) {}
+ virtual SdrTransformRef2XItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrTransformRef2XItem(*this);
+ }
+};
+
+class SdrTransformRef2YItem final : public SdrMetricItem {
+public:
+ SdrTransformRef2YItem(tools::Long nHgt=0): SdrMetricItem(SDRATTR_TRANSFORMREF2Y,nHgt) {}
+ virtual SdrTransformRef2YItem* Clone(SfxItemPool*) const override
+ {
+ return new SdrTransformRef2YItem(*this);
+ }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/tabwin.hrc b/svx/inc/tabwin.hrc
new file mode 100644
index 000000000..fbfda4ff9
--- /dev/null
+++ b/svx/inc/tabwin.hrc
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_TABWIN_HRC
+#define INCLUDED_SVX_INC_TABWIN_HRC
+
+#include <unotools/resmgr.hxx>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+const TranslateId RID_RSC_TABWIN_PREFIX[] =
+{
+ NC_("RID_RSC_TABWIN_PREFIX", "Table"),
+ NC_("RID_RSC_TABWIN_PREFIX", "Query"),
+ NC_("RID_RSC_TABWIN_PREFIX", "SQL")
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/tbxcolorupdate.hxx b/svx/inc/tbxcolorupdate.hxx
new file mode 100644
index 000000000..478937674
--- /dev/null
+++ b/svx/inc/tbxcolorupdate.hxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/gen.hxx>
+#include <tools/color.hxx>
+#include <vcl/vclenum.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/toolboxid.hxx>
+#include <svx/Palette.hxx>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/frame/FeatureStateEvent.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+
+class ToolBox;
+class VirtualDevice;
+
+namespace weld
+{
+ class Toolbar;
+}
+
+namespace svx
+{
+
+
+ //= ToolboxButtonColorUpdater
+
+ /** helper class to update a color in a toolbox button image
+
+ formerly known as SvxTbxButtonColorUpdater_Impl, residing in svx/source/tbxctrls/colorwindow.hxx.
+ */
+ class ToolboxButtonColorUpdaterBase
+ {
+ public:
+ ToolboxButtonColorUpdaterBase(bool bWideButton, const OUString& rCommandLabel,
+ const OUString& rCommandURL,
+ const css::uno::Reference<css::frame::XFrame>& rFrame);
+
+ virtual ~ToolboxButtonColorUpdaterBase();
+
+ void Update( const NamedColor& rNamedColor );
+ void Update( const Color& rColor, bool bForceUpdate = false );
+ Color const & GetCurrentColor() const { return maCurColor; }
+ OUString GetCurrentColorName() const;
+
+ private:
+ ToolboxButtonColorUpdaterBase(ToolboxButtonColorUpdaterBase const &) = delete;
+ ToolboxButtonColorUpdaterBase& operator =(ToolboxButtonColorUpdaterBase const &) = delete;
+
+ protected:
+ bool mbWideButton;
+ bool mbWasHiContrastMode;
+ Color maCurColor;
+ tools::Rectangle maUpdRect;
+ Size maBmpSize;
+ vcl::ImageType meImageType;
+ OUString maCommandLabel;
+ OUString maCommandURL;
+ css::uno::Reference<css::frame::XFrame> mxFrame;
+
+ void Init(sal_uInt16 nSlotId);
+
+ virtual void SetQuickHelpText(const OUString& rText) = 0;
+ virtual OUString GetQuickHelpText() const = 0;
+ virtual void SetImage(VirtualDevice* pVirDev) = 0;
+ virtual VclPtr<VirtualDevice> CreateVirtualDevice() const = 0;
+ // true -> use Device to Record to Metafile, false -> Render to Device
+ virtual bool RecordVirtualDevice() const = 0;
+ virtual vcl::ImageType GetImageSize() const = 0;
+ virtual Size GetItemSize(const Size& rImageSize) const = 0;
+ };
+
+ class VclToolboxButtonColorUpdater final : public ToolboxButtonColorUpdaterBase
+ {
+ public:
+ VclToolboxButtonColorUpdater(sal_uInt16 nSlotId, ToolBoxItemId nTbxBtnId, ToolBox* ptrTbx, bool bWideButton,
+ const OUString& rCommandLabel, const OUString& rCommandURL,
+ const css::uno::Reference<css::frame::XFrame>& rFrame);
+
+
+ private:
+ ToolBoxItemId mnBtnId;
+ VclPtr<ToolBox> mpTbx;
+
+ virtual void SetQuickHelpText(const OUString& rText) override;
+ virtual OUString GetQuickHelpText() const override;
+ virtual void SetImage(VirtualDevice* pVirDev) override;
+ virtual VclPtr<VirtualDevice> CreateVirtualDevice() const override;
+ virtual bool RecordVirtualDevice() const override
+ {
+ return true;
+ }
+ virtual vcl::ImageType GetImageSize() const override;
+ virtual Size GetItemSize(const Size& rImageSize) const override;
+ };
+
+ class ToolboxButtonColorUpdater final : public ToolboxButtonColorUpdaterBase
+ {
+ public:
+ ToolboxButtonColorUpdater(sal_uInt16 nSlotId, const OString& rTbxBtnId, weld::Toolbar* ptrTbx, bool bWideButton,
+ const OUString& rCommandLabel, const css::uno::Reference<css::frame::XFrame>& rFrame);
+
+ private:
+ OString msBtnId;
+ weld::Toolbar* mpTbx;
+
+ virtual void SetQuickHelpText(const OUString& rText) override;
+ virtual OUString GetQuickHelpText() const override;
+ virtual void SetImage(VirtualDevice* pVirDev) override;
+ virtual VclPtr<VirtualDevice> CreateVirtualDevice() const override;
+ virtual bool RecordVirtualDevice() const override
+ {
+ return false;
+ }
+ virtual vcl::ImageType GetImageSize() const override;
+ virtual Size GetItemSize(const Size& rImageSize) const override;
+ };
+
+ class ToolboxButtonLineStyleUpdater
+ {
+ private:
+ css::drawing::LineStyle m_eXLS;
+ int m_nDashStyleIndex;
+ public:
+ ToolboxButtonLineStyleUpdater();
+ void Update(const css::frame::FeatureStateEvent& rEvent);
+ int GetStyleIndex() const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/textchain.hxx b/svx/inc/textchain.hxx
new file mode 100644
index 000000000..0607052b1
--- /dev/null
+++ b/svx/inc/textchain.hxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <editeng/editdata.hxx>
+#include <map>
+
+class ImpChainLinkProperties;
+class SdrTextObj;
+class SdrModel;
+
+namespace rtl
+{
+class OUString;
+}
+
+typedef OUString ChainLinkId;
+
+enum class CursorChainingEvent : sal_uInt8
+{
+ TO_NEXT_LINK,
+ TO_PREV_LINK,
+ UNCHANGED,
+ NULL_EVENT
+};
+
+class ImpChainLinkProperties
+{
+protected:
+ friend class TextChain;
+
+ ImpChainLinkProperties()
+ {
+ aNilChainingEvent = false;
+ aCursorEvent = CursorChainingEvent::NULL_EVENT;
+ aPreChainingSel = ESelection(0, 0, 0, 0);
+ aPostChainingSel = ESelection(0, 0, 0, 0);
+ aIsPartOfLastParaInNextLink = false; // XXX: Should come from file
+ aSwitchingToNextBox = false;
+ }
+
+private:
+ // NOTE: Remember to set default value in constructor when adding field
+ ESelection aPreChainingSel;
+ ESelection aPostChainingSel;
+ CursorChainingEvent aCursorEvent;
+ bool aNilChainingEvent;
+ bool aIsPartOfLastParaInNextLink;
+ bool aSwitchingToNextBox;
+};
+
+class TextChain
+{
+public:
+ ~TextChain();
+
+ ImpChainLinkProperties* GetLinkProperties(const SdrTextObj*);
+
+ // Specific Link Properties
+ CursorChainingEvent const& GetCursorEvent(const SdrTextObj*);
+ void SetCursorEvent(const SdrTextObj*, CursorChainingEvent const&);
+
+ bool GetNilChainingEvent(const SdrTextObj*);
+ void SetNilChainingEvent(const SdrTextObj*, bool);
+
+ ESelection const& GetPreChainingSel(const SdrTextObj*);
+ void SetPreChainingSel(const SdrTextObj*, ESelection const&);
+
+ ESelection const& GetPostChainingSel(const SdrTextObj*);
+ void SetPostChainingSel(const SdrTextObj*, ESelection const&);
+
+ // return whether a paragraph is split between this box and the next
+ bool GetIsPartOfLastParaInNextLink(const SdrTextObj*);
+ void SetIsPartOfLastParaInNextLink(const SdrTextObj*, bool);
+
+ // return whether we are currently moving the cursor to the next box (useful to know whether we should prevent SetOutlinerParaObject invocations in SdrTextObj::EndTextEdit)
+ bool GetSwitchingToNextBox(const SdrTextObj*);
+ void SetSwitchingToNextBox(const SdrTextObj*, bool);
+
+protected:
+ TextChain();
+
+private:
+ std::map<ChainLinkId, ImpChainLinkProperties*> maLinkPropertiesMap;
+
+ friend class SdrModel;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/textchaincursor.hxx b/svx/inc/textchaincursor.hxx
new file mode 100644
index 000000000..30399207a
--- /dev/null
+++ b/svx/inc/textchaincursor.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+class SdrObjEditView;
+class SdrTextObj;
+class KeyEvent;
+class SdrOutliner;
+enum class CursorChainingEvent : sal_uInt8;
+struct ESelection;
+
+
+class TextChainCursorManager
+{
+public:
+ TextChainCursorManager(SdrObjEditView *pEditView, const SdrTextObj *pTextObj);
+
+ bool HandleKeyEvent( const KeyEvent& rKEvt );
+
+ // Used by HandledKeyEvent and basic building block for handling cursor event
+ void HandleCursorEvent(const CursorChainingEvent aCurEvt,
+ const ESelection& aNewSel);
+
+ // To be used after chaining event to deal with some nuisances
+ void HandleCursorEventAfterChaining(const CursorChainingEvent aCurEvt,
+ const ESelection& aNewSel);
+
+private:
+ SdrObjEditView *mpEditView;
+ const SdrTextObj *mpTextObj;
+
+ // flag for handling of CANC which is kind of an exceptional case
+ bool mbHandlingDel;
+
+ void impChangeEditingTextObj(SdrTextObj *pTargetTextObj, ESelection aNewSel);
+ void impDetectEvent(const KeyEvent& rKEvt,
+ CursorChainingEvent& rOutCursorEvt,
+ ESelection& rOutSel,
+ bool& rOutHandled);
+};
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/svx/inc/textchainflow.hxx b/svx/inc/textchainflow.hxx
new file mode 100644
index 000000000..d423939b6
--- /dev/null
+++ b/svx/inc/textchainflow.hxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "textchain.hxx"
+#include <memory>
+
+class SdrTextObj;
+class SdrOutliner;
+class NonOverflowingText;
+class OverflowingText;
+class TextChain;
+class OutlinerParaObject;
+class OFlowChainedText;
+class UFlowChainedText;
+
+class TextChainFlow
+{
+public:
+ TextChainFlow(SdrTextObj* pChainTarget);
+ virtual ~TextChainFlow();
+
+ // Check for flow events in Outliner
+ virtual void CheckForFlowEvents(SdrOutliner*);
+
+ void ExecuteUnderflow(SdrOutliner*);
+
+ // Uses two outliners: one for the non-overflow text and one for overflowing (might be the same)
+ void ExecuteOverflow(SdrOutliner*, SdrOutliner*);
+
+ bool IsOverflow() const;
+ bool IsUnderflow() const;
+
+ SdrTextObj* GetLinkTarget() const;
+
+protected:
+ void impCheckForFlowEvents(SdrOutliner*, SdrOutliner*);
+
+ TextChain* GetTextChain() const;
+
+ virtual void impLeaveOnlyNonOverflowingText(SdrOutliner*);
+ void impMoveChainedTextToNextLink(SdrOutliner*);
+
+ virtual void impSetFlowOutlinerParams(SdrOutliner*, SdrOutliner*);
+
+private:
+ void impUpdateCursorInfo();
+
+protected:
+ std::unique_ptr<OFlowChainedText> mpOverflChText;
+ std::unique_ptr<UFlowChainedText> mpUnderflChText;
+ // Cursor related
+ ESelection maOverflowPosSel;
+ ESelection maPostChainingSel;
+ bool mbPossiblyCursorOut;
+
+private:
+ SdrTextObj* mpTargetLink;
+ SdrTextObj* mpNextLink;
+ TextChain* mpTextChain;
+ bool mbOFisUFinduced;
+ bool bUnderflow;
+ bool bOverflow;
+};
+
+// NOTE: EditingTextChainFlow might be strongly coupled with behavior in SdrTextObj::onChainingEvent
+class EditingTextChainFlow final : public TextChainFlow
+{
+public:
+ EditingTextChainFlow(SdrTextObj*);
+ virtual void CheckForFlowEvents(SdrOutliner*) override;
+
+ //virtual void ExecuteOverflow(SdrOutliner *, SdrOutliner *) override;
+
+private:
+ virtual void impLeaveOnlyNonOverflowingText(SdrOutliner*) override;
+
+ virtual void impSetFlowOutlinerParams(SdrOutliner*, SdrOutliner*) override;
+
+ void impBroadcastCursorInfo() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/txenctab.hrc b/svx/inc/txenctab.hrc
new file mode 100644
index 000000000..dc3e7ef6c
--- /dev/null
+++ b/svx/inc/txenctab.hrc
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_TXENCTAB_HRC
+#define INCLUDED_SVX_INC_TXENCTAB_HRC
+
+#include <rtl/textenc.h>
+#include <unotools/resmgr.hxx>
+#include <utility>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+// Encodings for which no conversion exist yet are commented out.
+
+const std::pair<TranslateId, rtl_TextEncoding> RID_SVXSTR_TEXTENCODING_TABLE[] =
+{
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (Windows-1252/WinLatin 1)") , RTL_TEXTENCODING_MS_1252 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (Apple Macintosh)") , RTL_TEXTENCODING_APPLE_ROMAN },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (DOS/OS2-850/International)") , RTL_TEXTENCODING_IBM_850 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (DOS/OS2-437/US)") , RTL_TEXTENCODING_IBM_437 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (DOS/OS2-860/Portuguese)") , RTL_TEXTENCODING_IBM_860 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (DOS/OS2-861/Icelandic)") , RTL_TEXTENCODING_IBM_861 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (DOS/OS2-863/French (Can.))") , RTL_TEXTENCODING_IBM_863 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (DOS/OS2-865/Nordic)") , RTL_TEXTENCODING_IBM_865 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (ASCII/US)") , RTL_TEXTENCODING_ASCII_US },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (ISO-8859-1)") , RTL_TEXTENCODING_ISO_8859_1 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Eastern Europe (ISO-8859-2)") , RTL_TEXTENCODING_ISO_8859_2 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Latin 3 (ISO-8859-3)") , RTL_TEXTENCODING_ISO_8859_3 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Baltic (ISO-8859-4)") , RTL_TEXTENCODING_ISO_8859_4 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Cyrillic (ISO-8859-5)") , RTL_TEXTENCODING_ISO_8859_5 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Arabic (ISO-8859-6)") , RTL_TEXTENCODING_ISO_8859_6 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Greek (ISO-8859-7)") , RTL_TEXTENCODING_ISO_8859_7 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Hebrew (ISO-8859-8)") , RTL_TEXTENCODING_ISO_8859_8 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Turkish (ISO-8859-9)") , RTL_TEXTENCODING_ISO_8859_9 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (ISO-8859-14)") , RTL_TEXTENCODING_ISO_8859_14 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (ISO-8859-15/EURO)") , RTL_TEXTENCODING_ISO_8859_15 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Greek (DOS/OS2-737)") , RTL_TEXTENCODING_IBM_737 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Baltic (DOS/OS2-775)") , RTL_TEXTENCODING_IBM_775 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Eastern Europe (DOS/OS2-852)") , RTL_TEXTENCODING_IBM_852 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Cyrillic (DOS/OS2-855)") , RTL_TEXTENCODING_IBM_855 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Turkish (DOS/OS2-857)") , RTL_TEXTENCODING_IBM_857 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Hebrew (DOS/OS2-862)") , RTL_TEXTENCODING_IBM_862 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Arabic (DOS/OS2-864)") , RTL_TEXTENCODING_IBM_864 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Cyrillic (DOS/OS2-866/Russian)") , RTL_TEXTENCODING_IBM_866 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Greek (DOS/OS2-869/Modern)") , RTL_TEXTENCODING_IBM_869 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Eastern Europe (Windows-1250/WinLatin 2)") , RTL_TEXTENCODING_MS_1250 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Cyrillic (Windows-1251)") , RTL_TEXTENCODING_MS_1251 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Greek (Windows-1253)") , RTL_TEXTENCODING_MS_1253 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Turkish (Windows-1254)") , RTL_TEXTENCODING_MS_1254 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Hebrew (Windows-1255)") , RTL_TEXTENCODING_MS_1255 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Arabic (Windows-1256)") , RTL_TEXTENCODING_MS_1256 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Baltic (Windows-1257)") , RTL_TEXTENCODING_MS_1257 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Vietnamese (Windows-1258)") , RTL_TEXTENCODING_MS_1258 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Eastern Europe (Apple Macintosh)") , RTL_TEXTENCODING_APPLE_CENTEURO },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Eastern Europe (Apple Macintosh/Croatian)") , RTL_TEXTENCODING_APPLE_CROATIAN },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Cyrillic (Apple Macintosh)") , RTL_TEXTENCODING_APPLE_CYRILLIC },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Greek (Apple Macintosh)") , RTL_TEXTENCODING_APPLE_GREEK },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Western Europe (Apple Macintosh/Icelandic)") , RTL_TEXTENCODING_APPLE_ICELAND },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Eastern Europe (Apple Macintosh/Romanian)") , RTL_TEXTENCODING_APPLE_ROMANIAN },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Turkish (Apple Macintosh)") , RTL_TEXTENCODING_APPLE_TURKISH },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Cyrillic (Apple Macintosh/Ukrainian)") , RTL_TEXTENCODING_APPLE_UKRAINIAN },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese simplified (Apple Macintosh)") , RTL_TEXTENCODING_APPLE_CHINSIMP },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese traditional (Apple Macintosh)") , RTL_TEXTENCODING_APPLE_CHINTRAD },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Japanese (Apple Macintosh)") , RTL_TEXTENCODING_APPLE_JAPANESE },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Korean (Apple Macintosh)") , RTL_TEXTENCODING_APPLE_KOREAN },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Japanese (Windows-932)") , RTL_TEXTENCODING_MS_932 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese simplified (Windows-936)") , RTL_TEXTENCODING_MS_936 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Korean (Windows-949)") , RTL_TEXTENCODING_MS_949 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese traditional (Windows-950)") , RTL_TEXTENCODING_MS_950 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Japanese (Shift-JIS)") , RTL_TEXTENCODING_SHIFT_JIS },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese simplified (GB-2312)") , RTL_TEXTENCODING_GB_2312 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese simplified (GB-18030)") , RTL_TEXTENCODING_GB_18030 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese traditional (GBT-12345)") , RTL_TEXTENCODING_GBT_12345 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese simplified (GBK/GB-2312-80)") , RTL_TEXTENCODING_GBK },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese traditional (Big5)") , RTL_TEXTENCODING_BIG5 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese traditional (BIG5-HKSCS)") , RTL_TEXTENCODING_BIG5_HKSCS },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Japanese (EUC-JP)") , RTL_TEXTENCODING_EUC_JP },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese simplified (EUC-CN)") , RTL_TEXTENCODING_EUC_CN },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese traditional (EUC-TW)") , RTL_TEXTENCODING_EUC_TW },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Japanese (ISO-2022-JP)") , RTL_TEXTENCODING_ISO_2022_JP },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Chinese simplified (ISO-2022-CN)") , RTL_TEXTENCODING_ISO_2022_CN },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Cyrillic (KOI8-R)") , RTL_TEXTENCODING_KOI8_R },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Unicode (UTF-7)") , RTL_TEXTENCODING_UTF7 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Unicode (UTF-8)") , RTL_TEXTENCODING_UTF8 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Eastern Europe (ISO-8859-10)") , RTL_TEXTENCODING_ISO_8859_10 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Eastern Europe (ISO-8859-13)") , RTL_TEXTENCODING_ISO_8859_13 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Korean (EUC-KR)") , RTL_TEXTENCODING_EUC_KR },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Korean (ISO-2022-KR)") , RTL_TEXTENCODING_ISO_2022_KR },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Korean (Windows-Johab-1361)") , RTL_TEXTENCODING_MS_1361 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Unicode (UTF-16)") , RTL_TEXTENCODING_UCS2 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Thai (ISO-8859-11/TIS-620)") , RTL_TEXTENCODING_TIS_620 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Thai (Windows-874)") , RTL_TEXTENCODING_MS_874 },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Cyrillic (KOI8-U)") , RTL_TEXTENCODING_KOI8_U },
+ { NC_("RID_SVXSTR_TEXTENCODING_TABLE", "Cyrillic (PT154)") , RTL_TEXTENCODING_PT154 }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/uiobject.hxx b/svx/inc/uiobject.hxx
new file mode 100644
index 000000000..bddf321a1
--- /dev/null
+++ b/svx/inc/uiobject.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SVX_INC_UIOBJECT_HXX
+#define INCLUDED_SVX_INC_UIOBJECT_HXX
+
+#include <memory>
+#include <vcl/uitest/uiobject.hxx>
+#include <svx/numvset.hxx>
+
+class SvxShowCharSet;
+class SvxNumValueSet;
+
+class SvxShowCharSetUIObject final : public DrawingAreaUIObject
+{
+ SvxShowCharSet* mpCharSet;
+
+public:
+ SvxShowCharSetUIObject(const VclPtr<vcl::Window>& rCharSetWin);
+
+ virtual void execute(const OUString& rAction, const StringMap& rParameters) override;
+
+ static std::unique_ptr<UIObject> create(vcl::Window* pWindow);
+
+private:
+ OUString get_name() const override;
+};
+
+class SvxNumValueSetUIObject final : public DrawingAreaUIObject
+{
+ SvxNumValueSet* mpNumValueSet;
+
+public:
+ SvxNumValueSetUIObject(vcl::Window* pNumValueSetWin);
+
+ virtual void execute(const OUString& rAction, const StringMap& rParameters) override;
+
+ static std::unique_ptr<UIObject> create(vcl::Window* pWindow);
+
+ virtual StringMap get_state() override;
+
+private:
+ OUString get_name() const override;
+};
+
+#endif // INCLUDED_SVX_INC_UIOBJECT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/unomlstr.hxx b/svx/inc/unomlstr.hxx
new file mode 100644
index 000000000..989fa3cc4
--- /dev/null
+++ b/svx/inc/unomlstr.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_INC_UNOMLSTR_HXX
+#define INCLUDED_SVX_INC_UNOMLSTR_HXX
+
+#include <com/sun/star/util/XModifyListener.hpp>
+
+#include <cppuhelper/implbase1.hxx>
+
+class SdrObject;
+
+class SvxUnoShapeModifyListener final
+ : public ::cppu::WeakAggImplHelper1<css::util::XModifyListener>
+{
+ SdrObject* mpObj;
+
+public:
+ SvxUnoShapeModifyListener(SdrObject* pObj) noexcept;
+ virtual ~SvxUnoShapeModifyListener() noexcept override;
+
+ // css::util::XModifyListener
+ virtual void SAL_CALL modified(const css::lang::EventObject& aEvent) override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // internal
+ void invalidate() noexcept;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/verttexttbxctrl.hxx b/svx/inc/verttexttbxctrl.hxx
new file mode 100644
index 000000000..05b675f1e
--- /dev/null
+++ b/svx/inc/verttexttbxctrl.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <svtools/toolboxcontroller.hxx>
+
+//HACK to avoid duplicate ImplInheritanceHelper symbols with MSVC:
+class SAL_DLLPUBLIC_TEMPLATE SvxVertCTLTextTbxCtrl_Base
+ : public cppu::ImplInheritanceHelper<svt::ToolboxController, css::lang::XServiceInfo>
+{
+ using ImplInheritanceHelper::ImplInheritanceHelper;
+};
+
+/*
+ control to remove/insert cjk settings dependent vertical text toolbox item
+ */
+class SvxVertCTLTextTbxCtrl : public SvxVertCTLTextTbxCtrl_Base
+{
+ bool m_bVisible;
+
+public:
+ explicit SvxVertCTLTextTbxCtrl(
+ const css::uno::Reference<css::uno::XComponentContext>& rContext);
+
+ virtual ~SvxVertCTLTextTbxCtrl() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override = 0;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& rEvent) override;
+};
+
+class SvxCTLTextTbxCtrl final : public SvxVertCTLTextTbxCtrl
+{
+public:
+ SvxCTLTextTbxCtrl(const css::uno::Reference<css::uno::XComponentContext>& rContext);
+
+ virtual OUString SAL_CALL getImplementationName() override;
+};
+
+class SvxVertTextTbxCtrl final : public SvxVertCTLTextTbxCtrl
+{
+public:
+ SvxVertTextTbxCtrl(const css::uno::Reference<css::uno::XComponentContext>& rContext);
+
+ virtual OUString SAL_CALL getImplementationName() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/xftshtit.hxx b/svx/inc/xftshtit.hxx
new file mode 100644
index 000000000..aaefab951
--- /dev/null
+++ b/svx/inc/xftshtit.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svl/intitem.hxx>
+
+/*************************************************************************
+|*
+|* FormText item for transparent shadow
+|*
+\************************************************************************/
+
+class XFormTextShadowTranspItem final : public SfxUInt16Item
+{
+public:
+ XFormTextShadowTranspItem(sal_uInt16 nShdwTransparence = 0);
+ virtual XFormTextShadowTranspItem* Clone(SfxItemPool* pPool = nullptr) const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/inc/xpolyimp.hxx b/svx/inc/xpolyimp.hxx
new file mode 100644
index 000000000..425d2a551
--- /dev/null
+++ b/svx/inc/xpolyimp.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_INC_XPOLYIMP_HXX
+#define INCLUDED_SVX_INC_XPOLYIMP_HXX
+
+#include <svx/xpoly.hxx>
+#include <memory>
+#include <vector>
+
+class Point;
+
+class ImpXPolygon
+{
+public:
+ std::unique_ptr<Point[]> pPointAry;
+ std::unique_ptr<PolyFlags[]>
+ pFlagAry;
+ Point* pOldPointAry;
+ bool bDeleteOldPoints;
+ sal_uInt16 nSize;
+ sal_uInt16 nResize;
+ sal_uInt16 nPoints;
+
+ ImpXPolygon( sal_uInt16 nInitSize, sal_uInt16 nResize=16 );
+ ImpXPolygon( const ImpXPolygon& rImpXPoly );
+ ~ImpXPolygon();
+
+ bool operator==(const ImpXPolygon& rImpXPoly) const;
+
+ void CheckPointDelete() const;
+
+ void Resize( sal_uInt16 nNewSize, bool bDeletePoints = true );
+ void InsertSpace( sal_uInt16 nPos, sal_uInt16 nCount );
+ void Remove( sal_uInt16 nPos, sal_uInt16 nCount );
+};
+
+class ImpXPolyPolygon
+{
+public:
+ ::std::vector< XPolygon > aXPolyList;
+};
+
+
+#endif // INCLUDED_SVX_INC_XPOLYIMP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/uitest/table/tablecontroller.py b/svx/qa/uitest/table/tablecontroller.py
new file mode 100644
index 000000000..26390cb5c
--- /dev/null
+++ b/svx/qa/uitest/table/tablecontroller.py
@@ -0,0 +1,76 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+from uitest.framework import UITestCase
+from uitest.uihelper.common import select_pos
+from libreoffice.uno.propertyvalue import mkPropertyValues
+
+
+# Test for SvxTableController.
+class SvxTableControllerTest(UITestCase):
+
+ def testOnFormatTable(self):
+ # Create an Impress document with a single table in it.
+ with self.ui_test.create_doc_in_start_center("impress") as component:
+ template = self.xUITest.getTopFocusWindow()
+ self.ui_test.close_dialog_through_button(template.getChild("close"))
+ self.xUITest.executeCommand(".uno:SelectAll")
+ self.xUITest.executeCommand(".uno:Delete")
+ self.xUITest.executeCommand(".uno:InsertTable?Columns:short=2&Rows:short=2")
+
+ # Enable shadow.
+ with self.ui_test.execute_dialog_through_command(".uno:TableDialog") as tableDialog:
+ tabs = tableDialog.getChild("tabcontrol")
+ # Select "shadow".
+ select_pos(tabs, "4")
+ shadowCheckbox = tableDialog.getChild("TSB_SHOW_SHADOW")
+ shadowCheckbox.executeAction("CLICK", tuple())
+
+ # Check if the shadow was enabled.
+ drawPage = component.getDrawPages().getByIndex(0)
+ shape = drawPage.getByIndex(0)
+ # Without the accompanying fix in place, this test would have failed with:
+ # AssertionError: False != True
+ # i.e. the table still had no shadow.
+ self.assertEqual(shape.Shadow, True)
+
+ # Close the document.
+
+ def testUndoCrash(self):
+ # Given an Impress document with a single table in it:
+ with self.ui_test.create_doc_in_start_center("impress"):
+ template = self.xUITest.getTopFocusWindow()
+ self.ui_test.close_dialog_through_button(template.getChild("close"))
+ self.xUITest.executeCommand(".uno:SelectAll")
+ self.xUITest.executeCommand(".uno:Delete")
+ self.xUITest.executeCommand(".uno:InsertTable?Columns:short=3&Rows:short=3")
+ self.xUITest.executeCommand(".uno:SelectAll")
+
+ # When enabling shadow on the shape while text edit is active:
+ doc = self.xUITest.getTopFocusWindow()
+ impress = doc.getChild("impress_win")
+ impress.executeAction("TYPE", mkPropertyValues({"TEXT": "A1"}))
+ for i in range(6):
+ impress.executeAction("TYPE", mkPropertyValues({"KEYCODE": "CTRL+TAB"}))
+ impress.executeAction("TYPE", mkPropertyValues({"TEXT": "A3"}))
+ self.xUITest.executeCommand(".uno:SelectAll")
+ with self.ui_test.execute_dialog_through_command(".uno:TableDialog") as tableDialog:
+ tabs = tableDialog.getChild("tabcontrol")
+ # Select "shadow".
+ select_pos(tabs, "4")
+ shadowCheckbox = tableDialog.getChild("TSB_SHOW_SHADOW")
+ shadowCheckbox.executeAction("CLICK", tuple())
+
+ # Then make sure we don't crash:
+ # Without the accompanying fix in place, this test would have failed crashed due to a
+ # use-after-free: text edit ended but an undo action of the text edit remained on the undo
+ # stack.
+ for i in range(2):
+ self.xUITest.executeCommand(".uno:Undo")
+
+ # Close the document.
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/svx/qa/unit/XTableImportExportTest.cxx b/svx/qa/unit/XTableImportExportTest.cxx
new file mode 100644
index 000000000..b97a7c50b
--- /dev/null
+++ b/svx/qa/unit/XTableImportExportTest.cxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <unotest/bootstrapfixturebase.hxx>
+
+#include <sal/types.h>
+#include <sfx2/app.hxx>
+#include <unotools/tempfile.hxx>
+#include <svx/xtable.hxx>
+#include <vcl/bitmapex.hxx>
+
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+
+using namespace css;
+
+class XTableImportExportTest : public CppUnit::TestFixture
+{
+public:
+ virtual void setUp() override
+ {
+ CppUnit::TestFixture::setUp();
+ SfxApplication::GetOrCreate();
+ }
+};
+
+CPPUNIT_TEST_FIXTURE(XTableImportExportTest, testImportExport)
+{
+ utl::TempFile aTempFile(nullptr, true);
+ aTempFile.EnableKillingFile();
+ OUString aTempURL = aTempFile.GetURL();
+ BitmapChecksum aChecksum(0);
+
+ {
+ rtl::Reference<XBitmapList> xBitmapList = new XBitmapList(aTempURL, "REF");
+ uno::Reference<container::XNameContainer> xNameContainer(xBitmapList->createInstance());
+ CPPUNIT_ASSERT(xNameContainer.is());
+
+ Bitmap aBitmap(Size(5, 5), vcl::PixelFormat::N24_BPP);
+ aBitmap.Erase(COL_RED);
+ BitmapEx aBitmapEx(aBitmap);
+ Graphic aGraphic(aBitmapEx);
+ uno::Reference<awt::XBitmap> xBitmap(aGraphic.GetXGraphic(), css::uno::UNO_QUERY);
+
+ xNameContainer->insertByName("SomeBitmap", uno::Any(xBitmap));
+ xBitmapList->Save();
+
+ aChecksum = aBitmap.GetChecksum();
+ }
+
+ {
+ rtl::Reference<XBitmapList> xBitmapList = new XBitmapList(aTempURL, "REF");
+ bool bResult = xBitmapList->Load();
+ CPPUNIT_ASSERT(bResult);
+ uno::Reference<container::XNameContainer> xNameContainer(xBitmapList->createInstance());
+ CPPUNIT_ASSERT(xNameContainer.is());
+
+ uno::Any aAny = xNameContainer->getByName("SomeBitmap");
+ CPPUNIT_ASSERT(aAny.has<uno::Reference<awt::XBitmap>>());
+ auto xBitmap = aAny.get<uno::Reference<awt::XBitmap>>();
+ CPPUNIT_ASSERT(xBitmap.is());
+ uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xGraphic.is());
+ Graphic aGraphic(xGraphic);
+ CPPUNIT_ASSERT(!aGraphic.IsNone());
+ Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap();
+ CPPUNIT_ASSERT_EQUAL(aChecksum, aBitmap.GetChecksum());
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/classicshapes.cxx b/svx/qa/unit/classicshapes.cxx
new file mode 100644
index 000000000..bb5bea745
--- /dev/null
+++ b/svx/qa/unit/classicshapes.cxx
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+#include <rtl/ustring.hxx>
+#include <editeng/unoprnms.hxx>
+
+#include <cppunit/TestAssert.h>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+constexpr OUStringLiteral sDataDirectory(u"svx/qa/unit/data/");
+
+/// Tests not about special features of custom shapes, but about shapes in general.
+class ClassicshapesTest : public test::BootstrapFixture, public unotest::MacrosTest
+{
+protected:
+ uno::Reference<lang::XComponent> mxComponent;
+ uno::Reference<drawing::XShape> getShape(sal_uInt8 nShapeIndex, sal_uInt8 nPageIndex);
+
+public:
+ virtual void setUp() override
+ {
+ test::BootstrapFixture::setUp();
+ mxDesktop.set(frame::Desktop::create(m_xContext));
+ }
+
+ virtual void tearDown() override
+ {
+ if (mxComponent.is())
+ {
+ mxComponent->dispose();
+ }
+ test::BootstrapFixture::tearDown();
+ }
+};
+
+uno::Reference<drawing::XShape> ClassicshapesTest::getShape(sal_uInt8 nShapeIndex,
+ sal_uInt8 nPageIndex)
+{
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent,
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_MESSAGE("Could not get XDrawPagesSupplier", xDrawPagesSupplier.is());
+ uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages());
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(nPageIndex),
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_MESSAGE("Could not get xDrawPage", xDrawPage.is());
+ uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(nShapeIndex), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get xShape", xShape.is());
+ return xShape;
+}
+
+CPPUNIT_TEST_FIXTURE(ClassicshapesTest, testTdf98584ShearVertical)
+{
+ // The document contains draw:rect, draw:polygon and draw:path objects.
+ // They are vertical sheared by skewY(-0.927295218002) or by matrix(1 2 0 1 1cm 1cm).
+ // Notice, skewY and matrix are interpreted on file open, but not written on file save.
+ // They are converted to rotate * shear horizontal * scale.
+ // Besides using a wrong sign in shear angle, error was, that TRSetGeometry of SdrPathObj did
+ // not consider the additional scaling (tdf#98565).
+ const OUString sURL(m_directories.getURLFromSrc(sDataDirectory) + "tdf98584_ShearVertical.odg");
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ // Tests skewY
+ for (sal_uInt8 nPageIndex = 0; nPageIndex < 3; ++nPageIndex)
+ {
+ awt::Rectangle aFrameRect;
+ uno::Reference<drawing::XShape> xShape(getShape(0, nPageIndex));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRect;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ OUString("Incorrect Width on skewY page " + OUString::number(nPageIndex))
+ .toUtf8()
+ .getStr(),
+ 5001.0, aFrameRect.Width, 2.0);
+ double nShearA;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_SHEARANGLE) >>= nShearA;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ OUString("Incorrect Share angle on skewY page " + OUString::number(nPageIndex))
+ .toUtf8()
+ .getStr(),
+ -5313.0, nShearA, 2.0);
+ double nRotA;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_ROTATEANGLE) >>= nRotA;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ OUString("Incorrect Rotate angle on skewY page " + OUString::number(nPageIndex))
+ .toUtf8()
+ .getStr(),
+ 30687.0, nRotA, 2.0);
+ }
+
+ // Tests matrix
+ for (sal_uInt8 nPageIndex = 3; nPageIndex < 6; ++nPageIndex)
+ {
+ awt::Rectangle aFrameRect;
+ uno::Reference<drawing::XShape> xShape(getShape(0, nPageIndex));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRect;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ OUString("Incorrect Width on matrix page " + OUString::number(nPageIndex))
+ .toUtf8()
+ .getStr(),
+ 5001.0, aFrameRect.Width, 2.0);
+ double nShearA;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_SHEARANGLE) >>= nShearA;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ OUString("Incorrect Share angle on matrix page " + OUString::number(nPageIndex))
+ .toUtf8()
+ .getStr(),
+ -6343.0, nShearA, 2.0);
+ double nRotA;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_ROTATEANGLE) >>= nRotA;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ OUString("Incorrect Rotate angle on matrix page " + OUString::number(nPageIndex))
+ .toUtf8()
+ .getStr(),
+ 29657.0, nRotA, 2.0);
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(ClassicshapesTest, testTdf98583ShearHorizontal)
+{
+ // The document contains rectangles with LT 3000,5000 and RB 5000,9000.
+ // skewX (-0.78539816339744830961) = skewX(-45deg) is applied on the first page
+ // matrix(1 0 1 1 0cm 0cm) on the second page. Both should result in a parallelogram with
+ // LT 8000,5000 and RB 14000, 9000, which means width 6001, height 4001.
+ // Error was, that not the mathematical matrix was used, but the API matrix, which has
+ // wrong sign in shear angle.
+ const OUString sURL(m_directories.getURLFromSrc(sDataDirectory)
+ + "tdf98583_ShearHorizontal.odp");
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument");
+
+ for (sal_uInt8 nPageIndex = 0; nPageIndex < 2; ++nPageIndex)
+ {
+ awt::Rectangle aFrameRect;
+ uno::Reference<drawing::XShape> xShape(getShape(0, nPageIndex));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRect;
+
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ OUString("Incorrect Left Position on page " + OUString::number(nPageIndex))
+ .toUtf8()
+ .getStr(),
+ 8000.0, aFrameRect.X, 2.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ OUString("Incorrect Top Position on page " + OUString::number(nPageIndex))
+ .toUtf8()
+ .getStr(),
+ 5000.0, aFrameRect.Y, 2.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ OUString("Incorrect Width on page " + OUString::number(nPageIndex)).toUtf8().getStr(),
+ 6001.0, aFrameRect.Width, 2.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ OUString("Incorrect Height on page " + OUString::number(nPageIndex)).toUtf8().getStr(),
+ 4001.0, aFrameRect.Height, 2.0);
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(ClassicshapesTest, testTdf130076Flip)
+{
+ // The document contains sections of a circle, one of which is scaled
+ // (1, -1), one of which is scaled (-1,1), one of which is transformed
+ // by a matrix equivalent to a vertical flip, and another which is
+ // transformed by a matrix equivalent to a horizontal flip. Error was
+ // that the transformation was made before the CircleKind was set,
+ // resulting in the flip being performed incorrectly.
+ const OUString sURL(m_directories.getURLFromSrc(sDataDirectory)
+ + "tdf130076_FlipOnSectorSection.odg");
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ for (sal_uInt8 nPageIndex = 0; nPageIndex < 2; ++nPageIndex)
+ {
+ double nAngle1(0.0), nAngle2(0.0);
+ uno::Reference<drawing::XShape> xShape(getShape(1, nPageIndex));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape2(getShape(2, nPageIndex));
+ uno::Reference<beans::XPropertySet> xShapeProps2(xShape2, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xShapeProps->getPropertyValue("CircleStartAngle") >>= nAngle1);
+ CPPUNIT_ASSERT(xShapeProps2->getPropertyValue("CircleStartAngle") >>= nAngle2);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(OUString("Incorrect vertical flip starting angle on page "
+ + OUString::number(nPageIndex))
+ .toUtf8()
+ .getStr(),
+ 26000.0, nAngle1);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(OUString("Incorrect horizontal flip starting angle on page "
+ + OUString::number(nPageIndex))
+ .toUtf8()
+ .getStr(),
+ 26000.0, nAngle2);
+ }
+}
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/core.cxx b/svx/qa/unit/core.cxx
new file mode 100644
index 000000000..396601001
--- /dev/null
+++ b/svx/qa/unit/core.cxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+
+#include <comphelper/storagehelper.hxx>
+
+#include <svx/graphichelper.hxx>
+#include <svx/xmlgrhlp.hxx>
+#include <unotools/tempfile.hxx>
+#include <vcl/filter/PDFiumLibrary.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for svx/source/core/ code.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/svx/qa/unit/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testChartExportToPdf)
+{
+ // Given a Calc document with a chart in it:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "chart.ods";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+
+ // When exporting that chart to PDF:
+ utl::TempFile aTempFile;
+ GraphicHelper::SaveShapeAsGraphicToPath(getComponent(), xShape, "application/pdf",
+ aTempFile.GetURL());
+
+ // Then make sure we get a valid, non-empty PDF:
+ auto pPdfium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPdfium)
+ return;
+ SvMemoryStream aMemory;
+ aMemory.WriteStream(*aTempFile.GetStream(StreamMode::READ));
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument
+ = pPdfium->openDocument(aMemory.GetData(), aMemory.GetSize(), OString());
+ // Without the accompanying fix in place, this test would have failed, because the output was
+ // empty (0 bytes).
+ CPPUNIT_ASSERT(pPdfDocument);
+ int nPageCount = pPdfDocument->getPageCount();
+ CPPUNIT_ASSERT_GREATER(0, nPageCount);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testGraphicObjectResolver)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "GraphicObjectResolverTest.zip";
+ uno::Reference<embed::XStorage> xStorage
+ = comphelper::OStorageHelper::GetStorageOfFormatFromURL(ZIP_STORAGE_FORMAT_STRING, aURL,
+ embed::ElementModes::READWRITE);
+ CPPUNIT_ASSERT(xStorage.is());
+
+ rtl::Reference<SvXMLGraphicHelper> xGraphicHelper
+ = SvXMLGraphicHelper::Create(xStorage, SvXMLGraphicHelperMode::Read);
+ CPPUNIT_ASSERT(xGraphicHelper.is());
+
+ // Test name in root folder
+ {
+ uno::Reference<graphic::XGraphic> xGraphic = xGraphicHelper->loadGraphic("SomeImage.png");
+ CPPUNIT_ASSERT_EQUAL(true, xGraphic.is());
+ }
+
+ // Test name in sub-folder
+ {
+ uno::Reference<graphic::XGraphic> xGraphic
+ = xGraphicHelper->loadGraphic("Pictures/SomeOtherImage.png");
+ CPPUNIT_ASSERT_EQUAL(true, xGraphic.is());
+ }
+
+ // Test non-existent name
+ {
+ uno::Reference<graphic::XGraphic> xGraphic;
+ try
+ {
+ xGraphic = xGraphicHelper->loadGraphic("NoneExistent.png");
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ CPPUNIT_ASSERT_EQUAL(false, xGraphic.is());
+ }
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/customshapes.cxx b/svx/qa/unit/customshapes.cxx
new file mode 100644
index 000000000..0b1970378
--- /dev/null
+++ b/svx/qa/unit/customshapes.cxx
@@ -0,0 +1,1405 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <cstdlib>
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+#include <rtl/ustring.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <editeng/unoprnms.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svl/intitem.hxx>
+#include <svx/EnhancedCustomShape2d.hxx>
+#include <svx/extrusionbar.hxx>
+#include <svx/graphichelper.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svxids.hrc>
+#include <unotools/mediadescriptor.hxx>
+#include <unotools/tempfile.hxx>
+#include <vcl/filter/PngImageReader.hxx>
+#include <vcl/BitmapReadAccess.hxx>
+
+#include <cppunit/TestAssert.h>
+
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
+#include <com/sun/star/drawing/GraphicExportFilter.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+constexpr OUStringLiteral sDataDirectory(u"svx/qa/unit/data/");
+
+/// Tests for svx/source/customshapes/ code.
+class CustomshapesTest : public test::BootstrapFixture, public unotest::MacrosTest
+{
+protected:
+ uno::Reference<lang::XComponent> mxComponent;
+ // get shape nShapeIndex from page 0
+ uno::Reference<drawing::XShape> getShape(sal_uInt8 nShapeIndex);
+ sal_uInt8 countShapes();
+
+public:
+ virtual void setUp() override
+ {
+ test::BootstrapFixture::setUp();
+ mxDesktop.set(frame::Desktop::create(m_xContext));
+ }
+
+ virtual void tearDown() override
+ {
+ if (mxComponent.is())
+ {
+ mxComponent->dispose();
+ }
+ test::BootstrapFixture::tearDown();
+ }
+};
+
+uno::Reference<drawing::XShape> CustomshapesTest::getShape(sal_uInt8 nShapeIndex)
+{
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent,
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_MESSAGE("Could not get XDrawPagesSupplier", xDrawPagesSupplier.is());
+ uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages());
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_MESSAGE("Could not get xDrawPage", xDrawPage.is());
+ uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(nShapeIndex), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get xShape", xShape.is());
+ return xShape;
+}
+
+sal_uInt8 CustomshapesTest::countShapes()
+{
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent,
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_MESSAGE("Could not get XDrawPagesSupplier", xDrawPagesSupplier.is());
+ uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages());
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_MESSAGE("Could not get xDrawPage", xDrawPage.is());
+ return xDrawPage->getCount();
+}
+
+void lcl_AssertRectEqualWithTolerance(std::string_view sInfo, const tools::Rectangle& rExpected,
+ const tools::Rectangle& rActual, const sal_Int32 nTolerance)
+{
+ // Left
+ OString sMsg = OString::Concat(sInfo) + " Left expected " + OString::number(rExpected.Left())
+ + " actual " + OString::number(rActual.Left()) + " Tolerance "
+ + OString::number(nTolerance);
+ CPPUNIT_ASSERT_MESSAGE(sMsg.getStr(),
+ std::abs(rExpected.Left() - rActual.Left()) <= nTolerance);
+
+ // Top
+ sMsg = OString::Concat(sInfo) + " Top expected " + OString::number(rExpected.Top()) + " actual "
+ + OString::number(rActual.Top()) + " Tolerance " + OString::number(nTolerance);
+ CPPUNIT_ASSERT_MESSAGE(sMsg.getStr(), std::abs(rExpected.Top() - rActual.Top()) <= nTolerance);
+
+ // Width
+ sMsg = OString::Concat(sInfo) + " Width expected " + OString::number(rExpected.GetWidth())
+ + " actual " + OString::number(rActual.GetWidth()) + " Tolerance "
+ + OString::number(nTolerance);
+ CPPUNIT_ASSERT_MESSAGE(sMsg.getStr(),
+ std::abs(rExpected.GetWidth() - rActual.GetWidth()) <= nTolerance);
+
+ // Height
+ sMsg = OString::Concat(sInfo) + " Height expected " + OString::number(rExpected.GetHeight())
+ + " actual " + OString::number(rActual.GetHeight()) + " Tolerance "
+ + OString::number(nTolerance);
+ CPPUNIT_ASSERT_MESSAGE(sMsg.getStr(),
+ std::abs(rExpected.GetHeight() - rActual.GetHeight()) <= nTolerance);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf147409_GeomItemHash)
+{
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf147409_GeomItemHash.odg";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.drawing.DrawingDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ SdrObjCustomShape* pSdrCustomShape(
+ static_cast<SdrObjCustomShape*>(SdrObject::getSdrObjectFromXShape(xShape)));
+
+ // Mark Object
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ SdrView* pSdrView = pViewShell->GetDrawView();
+ pSdrView->MarkObj(pSdrCustomShape, pSdrView->GetSdrPageView());
+
+ // Apply FontworkSameLetterHeights toggle
+ // Without patch a debug build fails assert in SfxItemPool::PutImpl and so crashes.
+ dispatchCommand(mxComponent, ".uno:FontworkSameLetterHeights", {});
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf146866_GeomItemHash)
+{
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf147409_GeomItemHash.odg";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.drawing.DrawingDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ SdrObjCustomShape* pSdrCustomShape(
+ static_cast<SdrObjCustomShape*>(SdrObject::getSdrObjectFromXShape(xShape)));
+
+ // Mark Object
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ SdrView* pSdrView = pViewShell->GetDrawView();
+ pSdrView->MarkObj(pSdrCustomShape, pSdrView->GetSdrPageView());
+
+ // Apply extrusion toggle
+ // Without patch a debug build fails assert in SfxItemPool::PutImpl and so crashes.
+ dispatchCommand(mxComponent, ".uno:ExtrusionToggle", {});
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145700_3D_NonUI)
+{
+ // The document contains first light soft, no ambient color, no second light and shininess 6.
+ // Such settings are not available in the UI. It tests the actual color, not the geometry.
+ // Load document
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145700_3D_NonUI.doc";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument");
+
+ // Generate bitmap from shape
+ uno::Reference<drawing::XShape> xShape = getShape(0);
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ GraphicHelper::SaveShapeAsGraphicToPath(mxComponent, xShape, "image/png", aTempFile.GetURL());
+
+ // Read bitmap and test color
+ // The expected values are taken from an image generated by Word
+ // Without the changed methods the colors were in range RGB(17,11,17) to RGB(87,55,89).
+ SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
+ vcl::PngImageReader aPNGReader(aFileStream);
+ BitmapEx aBMPEx = aPNGReader.read();
+ Bitmap aBMP = aBMPEx.GetBitmap();
+ Bitmap::ScopedReadAccess pRead(aBMP);
+ Size aSize = aBMP.GetSizePixel();
+ // GetColor(Y,X)
+ Color aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() * 0.125);
+ Color aExpectedColor(107, 67, 109);
+ sal_uInt16 nColorDistance = aExpectedColor.GetColorError(aActualColor);
+ CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance);
+ // The current solution for soft light still can be improved. nColorDistance is high.
+ aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() * 0.45);
+ aExpectedColor = Color(179, 113, 183);
+ nColorDistance = aExpectedColor.GetColorError(aActualColor);
+ CPPUNIT_ASSERT_LESS(sal_uInt16(54), nColorDistance);
+ // This point tests whether shininess is read and used. With default shininess it would be white.
+ aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() * 0.72);
+ aExpectedColor = Color(255, 231, 255);
+ nColorDistance = aExpectedColor.GetColorError(aActualColor);
+ CPPUNIT_ASSERT_LESS(sal_uInt16(14), nColorDistance);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145700_3D_FrontLightDim)
+{
+ // This tests the actual color, not the geometry.
+ // Load document
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145700_3D_FrontLightDim.doc";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument");
+
+ // Generate bitmap from shape
+ uno::Reference<drawing::XShape> xShape = getShape(0);
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ GraphicHelper::SaveShapeAsGraphicToPath(mxComponent, xShape, "image/png", aTempFile.GetURL());
+
+ // Read bitmap and test color
+ // The expected values are taken from an image generated by Word
+ // Without the changed methods the nColorDistance was 476 and 173 respectively.
+ SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
+ vcl::PngImageReader aPNGReader(aFileStream);
+ BitmapEx aBMPEx = aPNGReader.read();
+ Bitmap aBMP = aBMPEx.GetBitmap();
+ Bitmap::ScopedReadAccess pRead(aBMP);
+ Size aSize = aBMP.GetSizePixel();
+ // GetColor(Y,X)
+ Color aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() * 0.4);
+ Color aExpectedColor(240, 224, 229);
+ sal_uInt16 nColorDistance = aExpectedColor.GetColorError(aActualColor);
+ CPPUNIT_ASSERT_LESS(sal_uInt16(9), nColorDistance);
+ aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() * 0.9);
+ aExpectedColor = Color(96, 90, 92);
+ nColorDistance = aExpectedColor.GetColorError(aActualColor);
+ CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145700_3D_FirstLightHarsh)
+{
+ // Load document
+ OUString aURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf145700_3D_FirstLightHarsh.doc";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument");
+
+ // Generate bitmap from shape
+ uno::Reference<drawing::XShape> xShape = getShape(0);
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ GraphicHelper::SaveShapeAsGraphicToPath(mxComponent, xShape, "image/png", aTempFile.GetURL());
+
+ // Read bitmap and test color in center
+ SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
+ vcl::PngImageReader aPNGReader(aFileStream);
+ BitmapEx aBMPEx = aPNGReader.read();
+ Bitmap aBMP = aBMPEx.GetBitmap();
+ Bitmap::ScopedReadAccess pRead(aBMP);
+ Size aSize = aBMP.GetSizePixel();
+ // GetColor(Y,X)
+ const Color aActualColor = pRead->GetColor(aSize.Height() / 2, aSize.Width() / 2);
+ const Color aExpectedColor(211, 247, 255); // from image generated by Word
+ sal_uInt16 nColorDistance = aExpectedColor.GetColorError(aActualColor);
+ CPPUNIT_ASSERT_LESS(sal_uInt16(3), nColorDistance);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145956_Origin_Relative_BoundRect)
+{
+ // The ViewPoint is relative to point Origin. The coordinates of point Origin are fractions of
+ // the actual (2D) bounding rectangle of the shape, including rotation around z-axis and flip.
+ // Error (among others) was, that the unrotated snap rectangle was used.
+
+ // Load document
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145956_Origin.odp";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.presentation.PresentationDocument");
+
+ // The shape is extruded with 10cm. viewpoint="(0cm 0cm 25cm)", origin="0 0".
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the properties", xPropSet.is());
+ awt::Rectangle aBoundRect;
+ xPropSet->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ sal_Int32 nActualTop = aBoundRect.Y;
+
+ // Without the fix it would have failed with top = 9462.
+ // The tolerance 10 is estimated and can be adjusted if required for HiDPI.
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("top", 10448, nActualTop, 10);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145904_Extrusion_CenterZ_odt)
+{
+ // The Z-component of the extrusion rotation center specifies the position in Hmm.
+ // Error (among others) was, that the value was interpreted as Twips.
+
+ // Load document
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145904_center_Zminus2000.odt";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument");
+
+ // The shape is extruded and tilt left 60deg. The rotation center is at -2000Hmm on the z-axis.
+ // That is a position behind the back face of the extruded shape.
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the properties", xPropSet.is());
+ awt::Rectangle aBoundRect;
+ xPropSet->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ awt::Point aAnchorPosition;
+ xPropSet->getPropertyValue("AnchorPosition") >>= aAnchorPosition;
+ sal_Int32 nActualLeft = aBoundRect.X - aAnchorPosition.X;
+
+ // Without the fix it would have failed with left = 7731.
+ // The tolerance 10 is estimated and can be adjusted if required for HiDPI.
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("left", 3501, nActualLeft, 10);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145904_Extrusion_CenterY_odt)
+{
+ // The X- and Y-component of the extrusion rotation center specify the position as fraction of
+ // shape size. Error was, that the relative fraction was handled as absolute value in Hmm.
+
+ // Load document
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145904_center_Y0dot25.odt";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument");
+
+ // The shape is extruded and tilt down 90deg. The rotation center is in the middle between shape
+ // center and bottom shape edge. The bottom edge of the projected solid has roughly the
+ // y-coordinate of the rotation center.
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the properties", xPropSet.is());
+ awt::Rectangle aBoundRect;
+ xPropSet->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ awt::Point aAnchorPosition;
+ xPropSet->getPropertyValue("AnchorPosition") >>= aAnchorPosition;
+ sal_Int32 nActualTop = aBoundRect.Y - aAnchorPosition.Y;
+
+ // Without the fix it would have failed with top = 2252.
+ // The tolerance 10 is estimated and can be adjusted if required for HiDPI.
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("top", 3208, nActualTop, 10);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145904_Extrusion_CenterY_doc)
+{
+ // The X- and Y-component of the extrusion rotation center specify the position as fraction of
+ // shape size. Error was, that the relative fraction was handled as absolute value in EMU.
+
+ // Load document
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145904_center_Y0dot25.doc";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument");
+
+ // The shape is extruded and tilt down 90deg. The rotation center is in the middle between shape
+ // center and bottom shape edge. The bottom edge of the projected solid has roughly the
+ // y-coordinate of the center.
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the properties", xPropSet.is());
+ awt::Rectangle aBoundRect;
+ xPropSet->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ awt::Point aAnchorPosition;
+ xPropSet->getPropertyValue("AnchorPosition") >>= aAnchorPosition;
+ sal_Int32 nActualTop = aBoundRect.Y - aAnchorPosition.Y;
+
+ // Without the fix it would have failed with top = 2330
+ // The tolerance 10 is estimated and can be adjusted if required for HiDPI.
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("top", 3208, nActualTop, 10);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145245_ExtrusionPosition)
+{
+ // The second parameter of the extrusion-depth property specifies how much of the extrusion
+ // lies before the shape. The file contains three shapes which have the values 0, 0.5 and 1.
+ // They are rotated around the x-axis so that the extrusion becomes visible. The extrusion
+ // depth itself is 5cm. Y-coordinate of shape is 6cm.
+
+ // Load document
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145245_ExtrusionPosition.odp";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument");
+
+ // The tolerance 40 is estimated and can be adjusted if required for HiDPI.
+ {
+ // First shape has extrusion behind the shape.
+ uno::Reference<drawing::XShape> xShape0(getShape(0));
+ SdrObjCustomShape& rSdrCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape0)));
+ tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect());
+ tools::Rectangle aExpected(Point(1000, 1000), Size(6002, 5001));
+ lcl_AssertRectEqualWithTolerance("Pos 0.0 extrusion", aExpected, aBoundRect, 40);
+ }
+ {
+ // Second shape has half of extrusion behind the shape.
+ uno::Reference<drawing::XShape> xShape(getShape(1));
+ SdrObjCustomShape& rSdrCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ // Without the fix the height was 1 instead of 5001.
+ tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect());
+ tools::Rectangle aExpected(Point(9000, 3500), Size(6002, 5001));
+ lcl_AssertRectEqualWithTolerance("Pos 0.5 extrusion", aExpected, aBoundRect, 40);
+ }
+ {
+ // Third shape has extrusion before the shape.
+ uno::Reference<drawing::XShape> xShape(getShape(2));
+ SdrObjCustomShape& rSdrCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ // Without the fix the y-coordinate was 1000 instead of 6000.
+ tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect());
+ tools::Rectangle aExpected(Point(18000, 6000), Size(6002, 5001));
+ lcl_AssertRectEqualWithTolerance("Pos 1.0 extrusion", aExpected, aBoundRect, 40);
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145111_Fontwork_rendering_font_size)
+{
+ // The tested position and height depend on dpi.
+ if (!IsDefaultDPI())
+ return;
+
+ // tdf#144988 In case ScaleX is true in property TextPath, the rendering font size should be
+ // reduced in case any of the paragraphs would be longer as its sub-path. That was wrong, if
+ // the first paragraph was too long and the second would fit. It resulted in wrong position
+ // and height and overlapping characters.
+
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf144988_Fontwork_FontSize.odp";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ SdrObjCustomShape& rSdrCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+
+ // Without the fix in place left|top, width x height was 1279|1279, 2815 x 2448.
+ // The expected values 1501|1777, 3941 x 1446 are only valid for 96dpi.
+ tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect());
+ tools::Rectangle aExpected(Point(1501, 1777), Size(3941, 1446));
+ lcl_AssertRectEqualWithTolerance("Wrong text rendering", aExpected, aBoundRect, 5);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145111_anchor_in_Fontwork)
+{
+ // The tested positions depend on dpi.
+ if (!IsDefaultDPI())
+ return;
+
+ // tdf#145004 In case ScaleX is true in property TextPath, SDRTEXTVERTADJUST is
+ // evaluated and should shift the Fontwork text. That did not work for
+ // 'Top-Left' and 'Bottom-Left'.
+
+ // Load document
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145111_TL_BL_Fontwork.odp";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument");
+
+ {
+ // First shape has anchor set to Top-Left, which shifts Fontwork text down.
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ SdrObjCustomShape& rSdrCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+
+ // Without the fix in place top was 2295, but should be 2916 for 96dpi.
+ // Was 2184, should be 2886 for 120dpi.
+ tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(2916), aBoundRect.Top(), 5);
+ }
+ {
+ // Second shape has anchor set to Bottom-Left, which shifts Fontwork text up.
+ uno::Reference<drawing::XShape> xShape(getShape(1));
+ SdrObjCustomShape& rSdrCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+
+ // Without the fix in place top was 10294, but should be 9519 for 96dpi.
+ // Was 10184, should be 9481 for 120dpi.
+ tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(9519), aBoundRect.Top(), 5);
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf145004_gap_by_ScaleX)
+{
+ if (!IsDefaultDPI())
+ return;
+ // tdf#145004 In case property ScaleX=true was set in property 'TextPath' an additional
+ // padding was added to the scaling factor. That results in a gap at start or/and end of
+ // the text. Such gap should not be there.
+
+ // Load document and get shape. It is a custom shape from pptx import of a WordArt of
+ // kind 'Follow Path'.
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf145004_gap_by_ScaleX.pptx";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ SdrObjCustomShape& rSdrCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+
+ // Verify width. Without the fix in place the width was 8231, but should be 8496 for 96dpi.
+ // Was 8328, should be 8527 for 120dpi.
+ tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(8496), aBoundRect.GetWidth(), 5);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf141021ExtrusionNorth)
+{
+ // tdf#141021 Setting extrusion direction in projection method 'perspective' to
+ // 'Extrusion North' had used a wrong origin for the ViewPoint and thus the
+ // side faces were wrong calculated.
+
+ // Load document and get shape. It is a custom shape in 3D mode.
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf141021_ExtrusionNorth.odp";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ SdrObjCustomShape& rSdrCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+
+ // Mark Object
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ SdrView* pSdrView = pViewShell->GetDrawView();
+ pSdrView->MarkObj(&rSdrCustomShape, pSdrView->GetSdrPageView());
+
+ // Set direction
+ SfxRequest aReq(pViewShell->GetViewFrame(), SID_EXTRUSION_DIRECTION);
+ SfxInt32Item aItem(SID_EXTRUSION_DIRECTION, 90);
+ aReq.AppendItem(aItem);
+ svx::ExtrusionBar::execute(pSdrView, aReq, SfxViewFrame::Current()->GetBindings());
+
+ // Verify height. Without the fix in place the height would 4001.
+ tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect());
+ CPPUNIT_ASSERT_EQUAL(tools::Long(5895), aBoundRect.GetHeight());
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testResizeRotatedShape)
+{
+ // tdf#138945 Setting width or height for a rotated or sheared shape in the Position&Size dialog
+ // had resulted in a mismatch of handle position and shape outline. That becomes visible in object
+ // properties as mismatch of frame rectangle and bound rectangle.
+ // Problem was, that fObjectRotation was not updated.
+
+ // Load document and get shape. It is a rectangle custom shape with 45° shear and 330° rotation.
+ OUString aURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf138945_resizeRotatedShape.odg";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+
+ // Change height and mirror vertical
+ {
+ SdrObjCustomShape& rSdrShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ rSdrShape.NbcResize(rSdrShape.GetRelativePos(), Fraction(1.0), Fraction(-0.5));
+ tools::Rectangle aSnapRect(rSdrShape.GetSnapRect());
+ tools::Rectangle aBoundRect(rSdrShape.GetCurrentBoundRect());
+ lcl_AssertRectEqualWithTolerance("height changed, mirror vert", aSnapRect, aBoundRect, 3);
+ }
+
+ // Change height
+ {
+ SdrObjCustomShape& rSdrShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ rSdrShape.NbcResize(rSdrShape.GetRelativePos(), Fraction(1.0), Fraction(2.0));
+ tools::Rectangle aSnapRect(rSdrShape.GetSnapRect());
+ tools::Rectangle aBoundRect(rSdrShape.GetCurrentBoundRect());
+ lcl_AssertRectEqualWithTolerance("height changed", aSnapRect, aBoundRect, 3);
+ }
+
+ // Change width
+ {
+ SdrObjCustomShape& rSdrShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ rSdrShape.NbcResize(rSdrShape.GetRelativePos(), Fraction(2.0), Fraction(1.0));
+ tools::Rectangle aSnapRect(rSdrShape.GetSnapRect());
+ tools::Rectangle aBoundRect(rSdrShape.GetCurrentBoundRect());
+ lcl_AssertRectEqualWithTolerance("width changed", aSnapRect, aBoundRect, 3);
+ }
+
+ // Change width and mirror horizontal
+ {
+ SdrObjCustomShape& rSdrShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ rSdrShape.NbcResize(rSdrShape.GetRelativePos(), Fraction(-0.5), Fraction(1.0));
+ tools::Rectangle aSnapRect(rSdrShape.GetSnapRect());
+ tools::Rectangle aBoundRect(rSdrShape.GetCurrentBoundRect());
+ lcl_AssertRectEqualWithTolerance("width changed, mirror hori", aSnapRect, aBoundRect, 3);
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testViewBoxLeftTop)
+{
+ // tdf#121890 formula values "left" and "top" are wrongly calculated
+ // Load a document with two custom shapes of type "non-primitive"
+ OUString aURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "viewBox_positive_twolines_strict.odp";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument");
+ // Get the shape "leftright". Error was, that the identifier "left" was always set to zero, thus
+ // the path was outside the frame rectangle for a viewBox having a positive "left" value.
+ uno::Reference<drawing::XShape> xShapeLR(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeLRProps(xShapeLR, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape 'leftright' properties", xShapeLRProps.is());
+ awt::Rectangle aFrameRectLR;
+ xShapeLRProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRectLR;
+ awt::Rectangle aBoundRectLR;
+ xShapeLRProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectLR;
+ // difference should be zero, but allow some rounding errors
+ CPPUNIT_ASSERT_LESS(sal_Int32(3), std::abs(aFrameRectLR.X - aBoundRectLR.X));
+
+ // Get the shape "topbottom". Error was, that the identifier "top" was always set to zero, thus
+ // the path was outside the frame rectangle for a viewBox having a positive "top" value.
+ uno::Reference<drawing::XShape> xShapeTB(getShape(1));
+ uno::Reference<beans::XPropertySet> xShapeTBProps(xShapeTB, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape 'topbottom' properties", xShapeTBProps.is());
+ awt::Rectangle aFrameRectTB;
+ xShapeTBProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRectTB;
+ awt::Rectangle aBoundRectTB;
+ xShapeTBProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectTB;
+ // difference should be zero, but allow some rounding errors
+ CPPUNIT_ASSERT_LESS(sal_Int32(3), std::abs(aFrameRectTB.Y - aBoundRectTB.Y));
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testAccuracyCommandX)
+{
+ // 121761 Increase accuracy of quarter circles drawn by command X or Y
+ // The loaded document has a quarter circle with radius 10000 (unit 1/100 mm)
+ // which is rotated by 45deg. The test considers the segment.
+ OUString aURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf121761_Accuracy_command_X.odp";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument");
+ // Get the shape "arc_45deg_rotated". Error was, that a Bezier curve with bad parameters
+ // was used, thus the segment height was obviously smaller than for a true circle.
+ // Math: segment height approx 10000 * ( 1 - sqrt(0.5)) + line width
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aBoundRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ double fHeight = static_cast<double>(aBoundRect.Height);
+ // The tolerance is a guess, might be smaller.
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("segment height out of tolerance", 2942.0, fHeight, 8.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testToggleCommandXY)
+{
+ // 121952 Toggle x- and y-direction if command X has several parameters
+ // The loaded document has a shape with command X and two parameter placed on a diagonal.
+ // The radius of the quarter circles are both 10000 (unit 1/100 mm).
+ // The shape is rotated by 45deg, so you get two segments, one up and one down.
+ OUString aURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf121952_Toggle_direction_command_X.odp";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument");
+ // Error was, that the second segment was drawn with same direction as first one. If drawn
+ // correctly, the bounding box height of the segments together is about twice the single
+ // segment height. Math: segment height approx 10000 * ( 1 - sqrt(0.5)) + line width
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aBoundRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ double fHeight = static_cast<double>(aBoundRect.Height);
+ // The tolerance is a guess, might be smaller.
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("segment height out of tolerance", 5871.0, fHeight, 16.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testMultipleMoveTo)
+{
+ // tdf122964 Multiple moveTo has to be treated as lineTo in draw:enhanced-path
+ // Load a document with path "M 0 0 5 10 10 0 N"
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf122964_MultipleMoveTo.odg";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.drawing.DrawingDocument");
+ // Error was, that the second and further parameter pairs were treated as moveTo,
+ // and so the generated path was empty, resulting in zero width and height of the
+ // bounding box. It has to be treated same as "M 0 0 L 5 10 10 0 N".
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aBoundRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ bool bIsZero(aBoundRect.Height == 0 && aBoundRect.Width == 0);
+ CPPUNIT_ASSERT_MESSAGE("Path is empty", !bIsZero);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testWidthOrientationCommandU)
+{
+ // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
+ // Load a document with path "M 750 0 L 750 500 250 500 250 0 U 500 0 500 500 0 180 N"
+ // in viewBox="0 0 1000 500" and width="10cm", height="5cm".
+ const OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf121845_WidthOrientation_command_U.odg";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+ // Error was, that the width and height of the ellipse was halved and that the ellipse
+ // was not drawn clockwise but counter clockwise.
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aBoundRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ const double fWidth = static_cast<double>(aBoundRect.Width);
+ // Need some tolerance for line width
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong width", 10000.0, fWidth, 40.0);
+ const double fHeight = static_cast<double>(aBoundRect.Height);
+ // Wrong orientation draws segment above the top of the viewBox and so increases 'Height'.
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong orientation", 5000.0, fHeight, 40.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testHalfEllipseVML)
+{
+ // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
+ // Load a document which was converted from VML to doc by Word. It had a VML
+ // path="m750,al500,,500,500,,-11796480e" resulting in a lower half circle.
+ const OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf121845_HalfEllipseVML.doc";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.text.TextDocument");
+ // Error was, that a full circle instead of the half circle was draw.
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aBoundRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ const double fDiff2HmW = static_cast<double>(2 * aBoundRect.Height - aBoundRect.Width);
+ // Need some tolerance for line width
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("not a half circle", 0.0, fDiff2HmW, 40.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testLargeSwingAngleVML)
+{
+ // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
+ // Load a document which was converted from VML to doc by Word. It had a VML
+ // path="al50,50,45,45,2621440,31457280e" resulting in a full circle plus 120 deg segment.
+ const OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf121845_start40_swing480.doc";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.text.TextDocument");
+ // Error was, that only the 120 deg segment was drawn.
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aBoundRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ const double fDiffWmH = static_cast<double>(aBoundRect.Width - aBoundRect.Height);
+ // Need some tolerance for line width
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Full circle plus segment expected", 0.0, fDiffWmH, 10.0);
+}
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf121845_two_commands_U)
+{
+ // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
+ // Load a document with path "U 950 250 200 200 90 180 250 250 200 200 180 270 N"
+ // Error was, that the second ellipse segment was interpreted as command T and
+ // thus a line from first to second segment was drawn.
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf121845_Two_commands_U.odg";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ // In case no line is drawn, two polygons are generated; with line only one polygon
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape);
+ SdrPathObjUniquePtr pPathObj(
+ static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry().release()));
+ CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj);
+ const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32>(2),
+ aPolyPolygon.count());
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf124212_handle_position)
+{
+ // tdf124212 Adjustment handle reacts wrongly, if custom shape has a non
+ // default viewBox. Load a document with svg:viewBox="10800 0 10800 21600"
+ // Error was, that moving the controller results in a handle position that
+ // does not reflect the movement.
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf124212_handle_position.odg";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ // The shape has one, horizontal adjust handle.
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape);
+ Point aInitialPosition;
+ aCustomShape2d.GetHandlePosition(0, aInitialPosition);
+ css::awt::Point aDesiredPosition(aInitialPosition.X() + 1000, aInitialPosition.Y());
+ aCustomShape2d.SetHandleControllerPosition(0, aDesiredPosition);
+ Point aObservedPosition;
+ aCustomShape2d.GetHandlePosition(0, aObservedPosition);
+ sal_Int32 nDesiredX(aDesiredPosition.X); // awt::Point
+ sal_Int32 nObservedX(aObservedPosition.X()); // tools::Point
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("handle X coordinate", nDesiredX, nObservedX);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf124029_arc_position)
+{
+ // tdf121029 MS binary custom shape mso_sptArc has wrong position
+ // MS uses the sector for position reference. Error was, that
+ // LibreOffice has used the underlying ellipse.
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf124029_Arc_position.doc";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.text.TextDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ // The visual wrong position is due to a wrong shape width.
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aFrameRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRect;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("shape width", static_cast<sal_uInt32>(1610),
+ static_cast<sal_uInt32>(aFrameRect.Width));
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf124740_handle_path_coordsystem)
+{
+ // tdf124740 OOXML shape with handle and w and h attribute on path has wrong
+ // handle position
+ // The handle position was scaled erroneously twice.
+ OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf124740_HandleInOOXMLUserShape.pptx";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ // The shape has one, horizontal adjust handle. It is about 1/5 of 10cm from left
+ // shape edge, shape is 6cm from left . That results in a position
+ // of 8cm from left page edge, which is 8000 in 1/100 mm unit.
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape);
+ Point aPosition;
+ aCustomShape2d.GetHandlePosition(0, aPosition);
+ double fX(aPosition.X());
+ // tolerance for rounding to integer
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("handle X coordinate", 8000.0, fX, 2.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf115813_OOXML_XY_handle)
+{
+ // The test covers all preset shapes with handles. Only these ones are
+ // excluded: arc, blockArc, chord, circularArrow, gear6, gear9, mathNotEqual, pie,
+ // leftCircularArrow, leftRightCircularArrow, swooshArrow.
+ // Connectors are included as ordinary shapes to prevent converting.
+ // Error was, that the handle movement and the changes to the shape did not follow
+ // the mouse movement.
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory)
+ + "tdf115813_HandleMovementOOXMLPresetShapes.pptx";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ // values in vector InteractionsHandles are in 1/100 mm and refer to page
+ for (sal_uInt8 i = 0; i < countShapes(); i++)
+ {
+ uno::Reference<drawing::XShape> xShape(getShape(i));
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ OUString sShapeType("non-primitive"); // default for ODF
+ const SdrCustomShapeGeometryItem& rGeometryItem(
+ rSdrObjCustomShape.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY));
+ const uno::Any* pAny = rGeometryItem.GetPropertyValueByName("Type");
+ if (pAny)
+ *pAny >>= sShapeType;
+
+ sal_uInt8 nHandlesCount = rSdrObjCustomShape.GetInteractionHandles().size();
+ for (sal_uInt8 j = 0; j < nHandlesCount; j++)
+ {
+ css::awt::Point aInitialPosition(
+ rSdrObjCustomShape.GetInteractionHandles()[j].aPosition);
+ // The handles are initialized in the test document, so that if the handle is moveable in
+ // that direction at all, then it can move at least with an amount of 100.
+ Point aDesiredPosition(aInitialPosition.X + 100, aInitialPosition.Y + 100);
+ rSdrObjCustomShape.DragMoveCustomShapeHdl(aDesiredPosition, j, false);
+ css::awt::Point aObservedPosition(
+ rSdrObjCustomShape.GetInteractionHandles()[j].aPosition);
+ sal_Int32 nDesiredX(aDesiredPosition.X()); // tools::Point
+ sal_Int32 nDesiredY(aDesiredPosition.Y());
+ sal_Int32 nObservedX(aObservedPosition.X); // css::awt::Point
+ sal_Int32 nObservedY(aObservedPosition.Y);
+ // If a handle only moves in one direction, the difference is 100 for the other direction.
+ // There exists some rounding differences, therefore '<= 1' instead of '== 0'.
+ // The condition has the form '!(good cases)'.
+ if (!((abs(nDesiredX - nObservedX) <= 1 && abs(nDesiredY - nObservedY) == 100)
+ || (abs(nDesiredX - nObservedX) == 100 && abs(nDesiredY - nObservedY) <= 1)
+ || (abs(nDesiredX - nObservedX) <= 1 && abs(nDesiredY - nObservedY) <= 1)))
+ {
+ OUString sError
+ = OUString::number(i) + " " + sShapeType + ": " + OUString::number(j) + " X "
+ + OUString::number(nDesiredX) + "|" + OUString::number(nObservedX) + " Y "
+ + OUString::number(nDesiredY) + "|" + OUString::number(nObservedY);
+ CPPUNIT_FAIL(sError.toUtf8().getStr());
+ }
+ }
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testQuadraticCurveTo)
+{
+ // tdf125782 command Q (quadraticcurveto) uses wrong 'current point'.
+ // When converting to cubic Bezier curve, this had resulted in a wrong first control point.
+ // The quadraticcurveto segment starts in shape center in the test file. The first control
+ // point should produce a horizontal tangent in the start point.
+ const OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf125782_QuadraticCurveTo.odg";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aBoundRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+ const double fHeight = static_cast<double>(aBoundRect.Height);
+ //Add some tolerance
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("bad height of quadraticcurveto", 3004, fHeight, 10.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf126512_OOXML_handle_in_ODP)
+{
+ // The test covers all preset shapes with handles. Connectors are included as ordinary
+ // shapes to prevent converting. The file was created in PowerPoint 365 and then
+ // opened and exported to ODF format by LibreOffice.
+ // Error was, that for shapes, which were originally imported from OOXML, the handles
+ // could not be moved at all.
+ OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf126512_OOXMLHandleMovementInODF.odp";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ for (sal_uInt8 i = 0; i < countShapes(); i++)
+ {
+ uno::Reference<drawing::XShape> xShape(getShape(i));
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ OUString sShapeType("non-primitive"); // only to initialize, value not used here
+ const SdrCustomShapeGeometryItem& rGeometryItem(
+ rSdrObjCustomShape.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY));
+ const uno::Any* pAny = rGeometryItem.GetPropertyValueByName("Type");
+ if (pAny)
+ *pAny >>= sShapeType;
+
+ sal_uInt8 nHandlesCount = rSdrObjCustomShape.GetInteractionHandles().size();
+ for (sal_uInt8 j = 0; j < nHandlesCount; j++)
+ {
+ css::awt::Point aInitialPosition(
+ rSdrObjCustomShape.GetInteractionHandles()[j].aPosition);
+ // The handles are initialized in the test document, so that if the handle is moveable
+ // in that direction at all, then it can move at least with an amount of 100.
+ Point aDesiredPosition(aInitialPosition.X + 100, aInitialPosition.Y + 100);
+ rSdrObjCustomShape.DragMoveCustomShapeHdl(aDesiredPosition, j, false);
+ css::awt::Point aObservedPosition(
+ rSdrObjCustomShape.GetInteractionHandles()[j].aPosition);
+ if (aInitialPosition.X == aObservedPosition.X
+ && aInitialPosition.Y == aObservedPosition.Y)
+ {
+ OUString sError
+ = OUString::number(i) + " " + sShapeType + " " + OUString::number(j);
+ CPPUNIT_FAIL(sError.toUtf8().getStr());
+ }
+ }
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf127785_Mirror)
+{
+ // The document contains two shapes, one with horizontal flip, the other with vertical
+ // flip. They are diamonds, so their text frame is symmetric to the center of the shape.
+ // The shapes have not stroke and no fill, so that the bounding box surrounds the text
+ // and therefore equals approximately the text frame.
+ // Error was, that because of wrong calculation, the flipped shapes do not use the
+ // text frame but the frame rectangle for their text.
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf127785_Mirror.odp";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ uno::Reference<drawing::XShape> xShapeV(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeVProps(xShapeV, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeVProps.is());
+ awt::Rectangle aBoundRectV;
+ xShapeVProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectV;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip vertical wrong size.", 8000.0, aBoundRectV.Height,
+ 10.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip vertical wrong size.", 8000.0, aBoundRectV.Width,
+ 10.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip vertical wrong position.", 1000.0, aBoundRectV.X,
+ 10.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip vertical wrong position.", 2000.0, aBoundRectV.Y,
+ 10.0);
+
+ uno::Reference<drawing::XShape> xShapeH(getShape(1));
+ uno::Reference<beans::XPropertySet> xShapeHProps(xShapeH, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeHProps.is());
+ awt::Rectangle aBoundRectH;
+ xShapeHProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectH;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip horizontal wrong size.", 8000.0, aBoundRectH.Height,
+ 10.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip horizontal wrong size.", 8000.0, aBoundRectH.Width,
+ 10.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip horizontal wrong position.", 13000.0, aBoundRectH.X,
+ 10.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip horizontal wrong position.", 2000.0, aBoundRectH.Y,
+ 10.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf126060_3D_Z_Rotation)
+{
+ // The document contains one textbox with inside overflowed text
+ // and the text has 3D z rotation. When we open the document we
+ // should see the text vertically and rotated from text bound center not text box.
+
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf126060_3D_Z_Rotation.pptx";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong text camera Z rotation", 90.0,
+ rSdrObjCustomShape.GetCameraZRotation());
+
+ basegfx::B2DHomMatrix aObjectTransform;
+ basegfx::B2DPolyPolygon aObjectPolyPolygon;
+ rSdrObjCustomShape.TRGetBaseGeometry(aObjectTransform, aObjectPolyPolygon);
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 0,0 position", 1492.0,
+ aObjectTransform.get(0, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 0,1 position", 0.0,
+ aObjectTransform.get(0, 1));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 0,2 position", 1129.0,
+ aObjectTransform.get(0, 2));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 1,0 position", 0.0,
+ aObjectTransform.get(1, 0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 1,1 position", 2500.0,
+ aObjectTransform.get(1, 1));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 1,2 position", 5846.0,
+ aObjectTransform.get(1, 2));
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf127785_Asymmetric)
+{
+ // The document contains a shapes with vertical flip and text frame asymmetrical
+ // to shape. The shape has not stroke and no fill, so that the bounding box surrounds
+ // the text and therefore equals approximately the text frame.
+ // Error was, that the 180deg text rotation was not compensated for the position of
+ // the flipped text box.
+ OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf127785_asymmetricTextBoxFlipV.odg";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aBoundRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong left", 9000.0, aBoundRect.X, 10.0);
+ const double nRight = aBoundRect.X + aBoundRect.Width - 1;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong right", 19000.0, nRight, 10.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong top", 3000.0, aBoundRect.Y, 10.0);
+ const double nBottom = aBoundRect.Y + aBoundRect.Height - 1;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong bottom", 18000.0, nBottom, 10.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf127785_TextRotateAngle)
+{
+ // The document contains a shapes with vertical flip and a text frame with own
+ // rotate angle. The shape has not stroke and no fill, so that the bounding box
+ // surrounds the text and therefore equals approximately the text frame.
+ // Error was, that the compensation for the 180° rotation added for vertical
+ // flip were not made to the text box position but to the text matrix.
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf127785_TextRotateAngle.odp";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aBoundRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect;
+
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong left", 2000.0, aBoundRect.X, 10.0);
+ const double nRight = aBoundRect.X + aBoundRect.Width - 1;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong right", 14000.0, nRight, 10.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong top", 3000.0, aBoundRect.Y, 10.0);
+ const double nBottom = aBoundRect.Y + aBoundRect.Height - 1;
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong bottom", 9000.0, nBottom, 10.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf128413_tbrlOnOff)
+{
+ // The document contains a rotated shape with text. The error was, that switching
+ // tb-rl writing-mode on, changed the shape size and position.
+
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf128413_tbrl_OnOff.odp";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is());
+ awt::Rectangle aOrigRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aOrigRect;
+
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ rSdrObjCustomShape.SetVerticalWriting(true);
+
+ awt::Rectangle aObservedRect;
+ xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aObservedRect;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong width", aOrigRect.Width, aObservedRect.Width);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong height", aOrigRect.Height, aObservedRect.Height);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong X position", aOrigRect.X, aObservedRect.X);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong Y position", aOrigRect.Y, aObservedRect.Y);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf129532_MatrixFlipV)
+{
+ // The document contains two rotated shapes with the same geometry. For one of them
+ // "matrix(1 0 0 -1 0cm 0cm)" was manually added to the value of the draw:transform
+ // attribute. That should result in mirroring on the x-axis. Error was, that the lines
+ // which are drawn on the shape rectangle were mirrored, but not the rectangle itself.
+ // The rectangle was only shifted.
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf129532_MatrixFlipV.odg";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ uno::Reference<drawing::XShape> xShape0(getShape(0));
+ uno::Reference<beans::XPropertySet> xShape0Props(xShape0, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShape0Props.is());
+ awt::Rectangle aBoundRect0;
+ xShape0Props->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect0;
+
+ uno::Reference<drawing::XShape> xShape1(getShape(1));
+ uno::Reference<beans::XPropertySet> xShape1Props(xShape1, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShape1Props.is());
+ awt::Rectangle aBoundRect1;
+ xShape1Props->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect1;
+
+ // The size of the two BoundRect rectangles are the same in case of correct
+ // vertical mirroring.
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Incorrect width", aBoundRect0.Width, aBoundRect1.Width);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Incorrect height", aBoundRect0.Height, aBoundRect1.Height);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf103474_commandT_CaseZeroHeight)
+{
+ // tdf103474 custom shape with command T to create quarter ellipses in a bracket,
+ // corner case where the ellipse has zero height.
+ // Error was, that the calculation of the circle angle from the ellipse
+ // angle results in a wrong angle for the case 180° and height zero.
+ OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf103474_commandT_CaseZeroHeight.odp";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ // The end points of the straight line segment should have the same x-coordinate of left
+ // of shape, and different y-coordinates, one top and the other bottom of the shape.
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape);
+ SdrPathObjUniquePtr pPathObj(
+ static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry().release()));
+ CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj);
+ const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32>(1),
+ aPolyPolygon.count());
+ const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0));
+ // Get the middle points of the polygon. They are the endpoints of the
+ // straight line segment regardless of the quarter ellipse parts, because
+ // the shape is symmetric.
+ const basegfx::B2DPoint aStart(aPolygon.getB2DPoint(aPolygon.count() / 2 - 1));
+ const basegfx::B2DPoint aEnd(aPolygon.getB2DPoint(aPolygon.count() / 2));
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart x-coordinate", 13999.0, aStart.getX(), 1.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd x-coordinate", 13999.0, aEnd.getX(), 1.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart y-coordinate", 9999.0, aStart.getY(), 1.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd y-coordinate", 1999.0, aEnd.getY(), 1.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf103474_commandG_CaseZeroHeight)
+{
+ // Some as above, but with shape with command G.
+ OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf103474_commandG_CaseZeroHeight.odp";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ // The end points of the straight line segment should have the same x-coordinate of left
+ // of shape, and different y-coordinates, one top and the other bottom of the shape.
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape);
+ SdrPathObjUniquePtr pPathObj(
+ static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry().release()));
+ CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj);
+ const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32>(1),
+ aPolyPolygon.count());
+ const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0));
+ // Get the middle points of the polygon. They are the endpoints of the
+ // straight line segment regardless of the quarter ellipse parts, because
+ // the shape is symmetric.
+ const basegfx::B2DPoint aStart(aPolygon.getB2DPoint(aPolygon.count() / 2 - 1));
+ const basegfx::B2DPoint aEnd(aPolygon.getB2DPoint(aPolygon.count() / 2));
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart x-coordinate", 1999.0, aStart.getX(), 1.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd x-coordinate", 1999.0, aEnd.getX(), 1.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart y-coordinate", 9999.0, aStart.getY(), 1.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd y-coordinate", 1999.0, aEnd.getY(), 1.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf122323_largeSwingAngle)
+{
+ // SwingAngles are clamped to [-360;360] in MS Office. Error was, that LO calculated
+ // the end angle and used it modulo 360, no full ellipse was drawn.
+ OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf122323_swingAngle_larger360deg.pptx";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape);
+ SdrPathObjUniquePtr pPathObj(
+ static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry().release()));
+ CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj);
+ const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly());
+ const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0));
+ const basegfx::B2DPoint aStart(aPolygon.getB2DPoint(0));
+ // last point comes from line to center, therefore -2 instead of -1
+ const basegfx::B2DPoint aEnd(aPolygon.getB2DPoint(aPolygon.count() - 2));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Start <> End", aStart, aEnd);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf141268)
+{
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf141268.odp";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument");
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ SdrObjCustomShape& rSdrCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+
+ // Check left/bottom of bound rect. Without fix it would be left=6722, bottom=9483.
+ tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect());
+ CPPUNIT_ASSERT_EQUAL(tools::Long(7620), aBoundRect.Left());
+ CPPUNIT_ASSERT_EQUAL(tools::Long(8584), aBoundRect.Bottom());
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf136176)
+{
+ // Error was, that fObjectRotation was not correctly updated after shearing.
+ // The problem becomes visible after save and reload.
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf136176_rot30_flip.odg";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ for (sal_uInt16 i = 0; i < 3; i++)
+ {
+ // get shape
+ uno::Reference<drawing::XShape> xShape(getShape(i));
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ // apply shearing 20deg
+ const Point aCenter = rSdrObjCustomShape.GetSnapRect().Center();
+ rSdrObjCustomShape.Shear(aCenter, 2000_deg100, tan(basegfx::deg2rad(20.0)), false);
+ }
+
+ // Save and reload
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["FilterName"] <<= OUString("draw8");
+ xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+ mxComponent->dispose();
+ mxComponent = loadFromDesktop(aTempFile.GetURL());
+
+ // Expected values of point 4 of the shape polygon
+ const OString sTestCase[] = { "FlipH", "FlipV", "FlipHV" };
+ const double fX[] = { 14981.0, 3849.0, 15214.0 };
+ const double fY[] = { 9366.0, 16464.0, 23463.0 };
+
+ // Verify correct positions
+ for (sal_uInt16 i = 0; i < 3; i++)
+ {
+ // Get shape
+ const uno::Reference<drawing::XShape> xShape(getShape(i));
+ const SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ // Create polygon from shape and examine point 4 of the polygon
+ const basegfx::B2DPolyPolygon aLineGeometry = rSdrObjCustomShape.GetLineGeometry(false);
+ const basegfx::B2DPoint aPoint(aLineGeometry.getB2DPolygon(0).getB2DPoint(4));
+ // Allow some tolerance for rounding errors
+ if (fabs(aPoint.getX() - fX[i]) > 2.0 || fabs(aPoint.getY() - fY[i]) > 2.0)
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(sTestCase[i].getStr(), aPoint,
+ basegfx::B2DPoint(fX[i], fY[i]));
+ }
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf148501_OctagonBevel)
+{
+ // The document contains a shape "Octagon Bevel". It should use shadings 40%, 20%, -20%, -40%
+ // from left-top to bottom-right. The test examines actual color, not the geometry.
+ // Load document
+ OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf148501_OctagonBevel.odp";
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.presentation.PresentationDocument");
+
+ // Generate bitmap from shape
+ uno::Reference<drawing::XShape> xShape = getShape(0);
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ GraphicHelper::SaveShapeAsGraphicToPath(mxComponent, xShape, "image/png", aTempFile.GetURL());
+
+ // Read bitmap and test color
+ // expected in order top-left, top, top-right, right, bottom-right:
+ // RGB(165|195|266), RGB(139|176|217), RGB(91|127|166), RGB(68|95|124), RGB(68|95|124)
+ // Without applied patch the colors were:
+ // RGB(193|214,236), RGB(193|214,236), RGB(80|111|145), RGB(23|32|41), RGB(193|214|236)
+ // So we test segments top, right and bottom-right.
+ SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
+ vcl::PngImageReader aPNGReader(aFileStream);
+ BitmapEx aBMPEx = aPNGReader.read();
+ Bitmap aBMP = aBMPEx.GetBitmap();
+ Bitmap::ScopedReadAccess pRead(aBMP);
+ Size aSize = aBMP.GetSizePixel();
+
+ // GetColor(Y,X). The chosen threshold for the ColorDistance can be adapted if necessary.
+ Color aActualColor = pRead->GetColor(aSize.Height() * 0.17, aSize.Width() * 0.5); // top
+ Color aExpectedColor(139, 176, 217);
+ sal_uInt16 nColorDistance = aExpectedColor.GetColorError(aActualColor);
+ CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance);
+ aActualColor = pRead->GetColor(aSize.Height() * 0.5, aSize.Width() * 0.83); // right
+ aExpectedColor = Color(68, 95, 124); // same for right and bottom-right
+ nColorDistance = aExpectedColor.GetColorError(aActualColor);
+ CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance);
+ aActualColor = pRead->GetColor(aSize.Height() * 0.75, aSize.Width() * 0.75); // bottom-right
+ nColorDistance = aExpectedColor.GetColorError(aActualColor);
+ CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance);
+}
+
+bool lcl_getShapeSegments(uno::Sequence<drawing::EnhancedCustomShapeSegment>& rSegments,
+ const uno::Reference<drawing::XShape>& xShape)
+{
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY_THROW);
+ uno::Any anotherAny = xShapeProps->getPropertyValue("CustomShapeGeometry");
+ uno::Sequence<beans::PropertyValue> aCustomShapeGeometry;
+ if (!(anotherAny >>= aCustomShapeGeometry))
+ return false;
+ uno::Sequence<beans::PropertyValue> aPathProps;
+ for (beans::PropertyValue const& rProp : std::as_const(aCustomShapeGeometry))
+ {
+ if (rProp.Name == "Path")
+ {
+ rProp.Value >>= aPathProps;
+ break;
+ }
+ }
+
+ for (beans::PropertyValue const& rProp : std::as_const(aPathProps))
+ {
+ if (rProp.Name == "Segments")
+ {
+ rProp.Value >>= rSegments;
+ break;
+ }
+ }
+ if (rSegments.getLength() > 2)
+ return true;
+ else
+ return false;
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf148714_CurvedArrows)
+{
+ // Error was, that the line between 1. and 2. arc was missing.
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf148714_CurvedArrows.ppt";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.presentation.PresentationDocument");
+
+ for (sal_Int32 nShapeIndex = 0; nShapeIndex < 4; nShapeIndex++)
+ {
+ uno::Reference<drawing::XShape> xShape(getShape(nShapeIndex));
+ uno::Sequence<drawing::EnhancedCustomShapeSegment> aSegments;
+ CPPUNIT_ASSERT(lcl_getShapeSegments(aSegments, xShape));
+
+ if (nShapeIndex == 0 || nShapeIndex == 3)
+ {
+ // curvedDownArrow or curvedLeftArrow. Segments should start with VW. Without fix it was
+ // V with count 2, which means VV.
+ CPPUNIT_ASSERT_EQUAL(
+ sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC),
+ aSegments[0].Command);
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments[0].Count);
+ CPPUNIT_ASSERT_EQUAL(
+ sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO),
+ aSegments[1].Command);
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments[1].Count);
+ }
+ else
+ {
+ // curvedUpArrow or curvedRightArrow. Segments should start with BA. Without fix is was
+ // B with count 2, which means BB.
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::ARC),
+ aSegments[0].Command);
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments[0].Count);
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::ARCTO),
+ aSegments[1].Command);
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments[1].Count);
+ }
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf148707_two_commands_B_V)
+{
+ // tdf148707 custom shape with multiple command B or multiple command V were drawn with a line
+ // between the arcs as if the second command was a A or W respectively.
+ // The test document has a shape with path "V 0 0 50 100 0 50 25 0 50 0 100 100 75 0 100 50 N"
+ // and a shape with path "B 0 0 50 100 0 50 25 100 50 0 100 100 75 100 100 50 N".
+ OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf148707_two_commands_B_V.odp";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+ for (sal_uInt8 i = 0; i < 2; i++)
+ {
+ uno::Reference<drawing::XShape> xShape(getShape(i));
+ // In case no line is drawn, two polygons are generated; with line only one polygon
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
+ EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape);
+ SdrPathObjUniquePtr pPathObj(
+ static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry().release()));
+ CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj);
+ const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", sal_uInt32(2), aPolyPolygon.count());
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/data/0-width-text-wrap.pptx b/svx/qa/unit/data/0-width-text-wrap.pptx
new file mode 100644
index 000000000..17349924d
--- /dev/null
+++ b/svx/qa/unit/data/0-width-text-wrap.pptx
Binary files differ
diff --git a/svx/qa/unit/data/3d-object-fallback.odp b/svx/qa/unit/data/3d-object-fallback.odp
new file mode 100644
index 000000000..5ced0be47
--- /dev/null
+++ b/svx/qa/unit/data/3d-object-fallback.odp
Binary files differ
diff --git a/svx/qa/unit/data/FontWork.odg b/svx/qa/unit/data/FontWork.odg
new file mode 100644
index 000000000..e14d2f70b
--- /dev/null
+++ b/svx/qa/unit/data/FontWork.odg
Binary files differ
diff --git a/svx/qa/unit/data/GraphicObjectResolverTest.zip b/svx/qa/unit/data/GraphicObjectResolverTest.zip
new file mode 100644
index 000000000..4c19bf2b0
--- /dev/null
+++ b/svx/qa/unit/data/GraphicObjectResolverTest.zip
Binary files differ
diff --git a/svx/qa/unit/data/auto-height-multi-col-shape.pptx b/svx/qa/unit/data/auto-height-multi-col-shape.pptx
new file mode 100644
index 000000000..12f232b0f
--- /dev/null
+++ b/svx/qa/unit/data/auto-height-multi-col-shape.pptx
Binary files differ
diff --git a/svx/qa/unit/data/chart.ods b/svx/qa/unit/data/chart.ods
new file mode 100644
index 000000000..d9e9bdf18
--- /dev/null
+++ b/svx/qa/unit/data/chart.ods
Binary files differ
diff --git a/svx/qa/unit/data/graphic.pdf b/svx/qa/unit/data/graphic.pdf
new file mode 100644
index 000000000..4b53d2056
--- /dev/null
+++ b/svx/qa/unit/data/graphic.pdf
Binary files differ
diff --git a/svx/qa/unit/data/page-view-draw-layer-clip.docx b/svx/qa/unit/data/page-view-draw-layer-clip.docx
new file mode 100644
index 000000000..7136a800f
--- /dev/null
+++ b/svx/qa/unit/data/page-view-draw-layer-clip.docx
Binary files differ
diff --git a/svx/qa/unit/data/shadow-scale-origin.pptx b/svx/qa/unit/data/shadow-scale-origin.pptx
new file mode 100644
index 000000000..a0a164a3c
--- /dev/null
+++ b/svx/qa/unit/data/shadow-scale-origin.pptx
Binary files differ
diff --git a/svx/qa/unit/data/slide-background.odp b/svx/qa/unit/data/slide-background.odp
new file mode 100644
index 000000000..ea62bd639
--- /dev/null
+++ b/svx/qa/unit/data/slide-background.odp
Binary files differ
diff --git a/svx/qa/unit/data/slide-background.png b/svx/qa/unit/data/slide-background.png
new file mode 100644
index 000000000..3a8c5ceb4
--- /dev/null
+++ b/svx/qa/unit/data/slide-background.png
Binary files differ
diff --git a/svx/qa/unit/data/svx-dialogs-test.txt b/svx/qa/unit/data/svx-dialogs-test.txt
new file mode 100644
index 000000000..d9974a384
--- /dev/null
+++ b/svx/qa/unit/data/svx-dialogs-test.txt
@@ -0,0 +1,80 @@
+# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+# This file contains all dialogs that the unit tests in the module
+# will work on if it is in script mode. It will read one-by-one,
+# try to open it and create a screenshot that will be saved in
+# workdir/screenshots using the pattern of the ui-file name.
+#
+# Syntax:
+# - empty lines are allowed
+# - lines starting with '#' are treated as comment
+# - all other lines should contain a *.ui filename in the same
+# notation as in the dialog constructors (see code)
+
+#
+# The 'known' dialogs which have a hard-coded representation
+# in registerKnownDialogsByID/createDialogByID
+#
+
+# No known dialogs in svx for now
+
+#
+# Dialogs without a hard-coded representation. These will
+# be visualized using a fallback based on weld::Builder
+#
+
+# currently deactivated, leads to problems and the test to not work
+# This is typically a hint that these should be hard-coded in the
+# test case since they need some document and model data to work
+#
+# svx/ui/asianphoneticguidedialog.ui <- problems under linux
+
+svx/ui/textcontrolchardialog.ui
+svx/ui/textcontrolparadialog.ui
+svx/ui/datanavigator.ui
+svx/ui/redlineviewpage.ui
+svx/ui/redlinefilterpage.ui
+svx/ui/headfootformatpage.ui
+svx/ui/optgridpage.ui
+svx/ui/xformspage.ui
+svx/ui/compressgraphicdialog.ui
+svx/ui/compressgraphicdialog.ui
+svx/ui/docrecoveryprogressdialog.ui
+svx/ui/docrecoverybrokendialog.ui
+svx/ui/passwd.ui
+svx/ui/adddataitemdialog.ui
+svx/ui/addconditiondialog.ui
+svx/ui/namespacedialog.ui
+svx/ui/addnamespacedialog.ui
+svx/ui/addsubmissiondialog.ui
+svx/ui/addmodeldialog.ui
+svx/ui/addinstancedialog.ui
+svx/ui/extrustiondepthdialog.ui
+svx/ui/fontworkgallerydialog.ui
+svx/ui/fontworkspacingdialog.ui
+svx/ui/chinesedictionary.ui
+svx/ui/chineseconversiondialog.ui
+svx/ui/imapdialog.ui
+svx/ui/findreplacedialog.ui
+svx/ui/crashreportdlg.ui
+svx/ui/docrecoverysavedialog.ui
+svx/ui/docrecoveryrecoverdialog.ui
+svx/ui/querysavecontchangesdialog.ui
+svx/ui/querydeletecontourdialog.ui
+svx/ui/queryunlinkgraphicsdialog.ui
+svx/ui/querynewcontourdialog.ui
+svx/ui/querymodifyimagemapchangesdialog.ui
+svx/ui/querysaveimagemapchangesdialog.ui
+svx/ui/querysaveimagemapchangesdialog.ui
+svx/ui/linkwarndialog.ui
+svx/ui/formlinkwarndialog.ui
+svx/ui/savemodifieddialog.ui
+svx/ui/querydeletethemedialog.ui
+svx/ui/querydeleteobjectdialog.ui
diff --git a/svx/qa/unit/data/table-shadow-blur.pptx b/svx/qa/unit/data/table-shadow-blur.pptx
new file mode 100644
index 000000000..959940e09
--- /dev/null
+++ b/svx/qa/unit/data/table-shadow-blur.pptx
Binary files differ
diff --git a/svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odp b/svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odp
new file mode 100644
index 000000000..9b36d45ee
--- /dev/null
+++ b/svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf103474_commandT_CaseZeroHeight.odp b/svx/qa/unit/data/tdf103474_commandT_CaseZeroHeight.odp
new file mode 100644
index 000000000..54a4377ca
--- /dev/null
+++ b/svx/qa/unit/data/tdf103474_commandT_CaseZeroHeight.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf115813_HandleMovementOOXMLPresetShapes.pptx b/svx/qa/unit/data/tdf115813_HandleMovementOOXMLPresetShapes.pptx
new file mode 100644
index 000000000..3435fef61
--- /dev/null
+++ b/svx/qa/unit/data/tdf115813_HandleMovementOOXMLPresetShapes.pptx
Binary files differ
diff --git a/svx/qa/unit/data/tdf121761_Accuracy_command_X.odp b/svx/qa/unit/data/tdf121761_Accuracy_command_X.odp
new file mode 100644
index 000000000..1de391758
--- /dev/null
+++ b/svx/qa/unit/data/tdf121761_Accuracy_command_X.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf121845_HalfEllipseVML.doc b/svx/qa/unit/data/tdf121845_HalfEllipseVML.doc
new file mode 100644
index 000000000..043e4e15f
--- /dev/null
+++ b/svx/qa/unit/data/tdf121845_HalfEllipseVML.doc
Binary files differ
diff --git a/svx/qa/unit/data/tdf121845_Two_commands_U.odg b/svx/qa/unit/data/tdf121845_Two_commands_U.odg
new file mode 100644
index 000000000..c0f7ff34f
--- /dev/null
+++ b/svx/qa/unit/data/tdf121845_Two_commands_U.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf121845_WidthOrientation_command_U.odg b/svx/qa/unit/data/tdf121845_WidthOrientation_command_U.odg
new file mode 100644
index 000000000..349c2eb81
--- /dev/null
+++ b/svx/qa/unit/data/tdf121845_WidthOrientation_command_U.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf121845_start40_swing480.doc b/svx/qa/unit/data/tdf121845_start40_swing480.doc
new file mode 100644
index 000000000..ff37aab3f
--- /dev/null
+++ b/svx/qa/unit/data/tdf121845_start40_swing480.doc
Binary files differ
diff --git a/svx/qa/unit/data/tdf121952_Toggle_direction_command_X.odp b/svx/qa/unit/data/tdf121952_Toggle_direction_command_X.odp
new file mode 100644
index 000000000..fbe1b7d40
--- /dev/null
+++ b/svx/qa/unit/data/tdf121952_Toggle_direction_command_X.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptx b/svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptx
new file mode 100644
index 000000000..919675ef9
--- /dev/null
+++ b/svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptx
Binary files differ
diff --git a/svx/qa/unit/data/tdf122964_MultipleMoveTo.odg b/svx/qa/unit/data/tdf122964_MultipleMoveTo.odg
new file mode 100644
index 000000000..63d80fd06
--- /dev/null
+++ b/svx/qa/unit/data/tdf122964_MultipleMoveTo.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf124029_Arc_position.doc b/svx/qa/unit/data/tdf124029_Arc_position.doc
new file mode 100644
index 000000000..d5396c375
--- /dev/null
+++ b/svx/qa/unit/data/tdf124029_Arc_position.doc
Binary files differ
diff --git a/svx/qa/unit/data/tdf124212_handle_position.odg b/svx/qa/unit/data/tdf124212_handle_position.odg
new file mode 100644
index 000000000..7a4eb0517
--- /dev/null
+++ b/svx/qa/unit/data/tdf124212_handle_position.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf124740_HandleInOOXMLUserShape.pptx b/svx/qa/unit/data/tdf124740_HandleInOOXMLUserShape.pptx
new file mode 100644
index 000000000..dd6df7b03
--- /dev/null
+++ b/svx/qa/unit/data/tdf124740_HandleInOOXMLUserShape.pptx
Binary files differ
diff --git a/svx/qa/unit/data/tdf125782_QuadraticCurveTo.odg b/svx/qa/unit/data/tdf125782_QuadraticCurveTo.odg
new file mode 100644
index 000000000..ba7b49536
--- /dev/null
+++ b/svx/qa/unit/data/tdf125782_QuadraticCurveTo.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf126060_3D_Z_Rotation.pptx b/svx/qa/unit/data/tdf126060_3D_Z_Rotation.pptx
new file mode 100644
index 000000000..8c8798f21
--- /dev/null
+++ b/svx/qa/unit/data/tdf126060_3D_Z_Rotation.pptx
Binary files differ
diff --git a/svx/qa/unit/data/tdf126512_OOXMLHandleMovementInODF.odp b/svx/qa/unit/data/tdf126512_OOXMLHandleMovementInODF.odp
new file mode 100644
index 000000000..7dd283f88
--- /dev/null
+++ b/svx/qa/unit/data/tdf126512_OOXMLHandleMovementInODF.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf127785_Mirror.odp b/svx/qa/unit/data/tdf127785_Mirror.odp
new file mode 100644
index 000000000..ff867839f
--- /dev/null
+++ b/svx/qa/unit/data/tdf127785_Mirror.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf127785_TextRotateAngle.odp b/svx/qa/unit/data/tdf127785_TextRotateAngle.odp
new file mode 100644
index 000000000..742f12d4d
--- /dev/null
+++ b/svx/qa/unit/data/tdf127785_TextRotateAngle.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf127785_asymmetricTextBoxFlipV.odg b/svx/qa/unit/data/tdf127785_asymmetricTextBoxFlipV.odg
new file mode 100644
index 000000000..ea700eaf7
--- /dev/null
+++ b/svx/qa/unit/data/tdf127785_asymmetricTextBoxFlipV.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf128413_tbrl_OnOff.odp b/svx/qa/unit/data/tdf128413_tbrl_OnOff.odp
new file mode 100644
index 000000000..f10f98bbe
--- /dev/null
+++ b/svx/qa/unit/data/tdf128413_tbrl_OnOff.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf129532_MatrixFlipV.odg b/svx/qa/unit/data/tdf129532_MatrixFlipV.odg
new file mode 100644
index 000000000..eb0c10b3d
--- /dev/null
+++ b/svx/qa/unit/data/tdf129532_MatrixFlipV.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf130076_FlipOnSectorSection.odg b/svx/qa/unit/data/tdf130076_FlipOnSectorSection.odg
new file mode 100644
index 000000000..058e7e044
--- /dev/null
+++ b/svx/qa/unit/data/tdf130076_FlipOnSectorSection.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf136176_rot30_flip.odg b/svx/qa/unit/data/tdf136176_rot30_flip.odg
new file mode 100644
index 000000000..75707a0f5
--- /dev/null
+++ b/svx/qa/unit/data/tdf136176_rot30_flip.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf138945_resizeRotatedShape.odg b/svx/qa/unit/data/tdf138945_resizeRotatedShape.odg
new file mode 100644
index 000000000..20a2825af
--- /dev/null
+++ b/svx/qa/unit/data/tdf138945_resizeRotatedShape.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf140321_Matte_import.ppt b/svx/qa/unit/data/tdf140321_Matte_import.ppt
new file mode 100644
index 000000000..83e790fd4
--- /dev/null
+++ b/svx/qa/unit/data/tdf140321_Matte_import.ppt
Binary files differ
diff --git a/svx/qa/unit/data/tdf140321_material_specular.odp b/svx/qa/unit/data/tdf140321_material_specular.odp
new file mode 100644
index 000000000..03869914f
--- /dev/null
+++ b/svx/qa/unit/data/tdf140321_material_specular.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf140321_metal.odp b/svx/qa/unit/data/tdf140321_metal.odp
new file mode 100644
index 000000000..a81ee0dfb
--- /dev/null
+++ b/svx/qa/unit/data/tdf140321_metal.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf140321_phong.odp b/svx/qa/unit/data/tdf140321_phong.odp
new file mode 100644
index 000000000..989a08485
--- /dev/null
+++ b/svx/qa/unit/data/tdf140321_phong.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf141021_ExtrusionNorth.odp b/svx/qa/unit/data/tdf141021_ExtrusionNorth.odp
new file mode 100644
index 000000000..559b2c0d5
--- /dev/null
+++ b/svx/qa/unit/data/tdf141021_ExtrusionNorth.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf141268.odp b/svx/qa/unit/data/tdf141268.odp
new file mode 100644
index 000000000..41d0dc446
--- /dev/null
+++ b/svx/qa/unit/data/tdf141268.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf144988_Fontwork_FontSize.odp b/svx/qa/unit/data/tdf144988_Fontwork_FontSize.odp
new file mode 100644
index 000000000..943bc143b
--- /dev/null
+++ b/svx/qa/unit/data/tdf144988_Fontwork_FontSize.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf145004_gap_by_ScaleX.pptx b/svx/qa/unit/data/tdf145004_gap_by_ScaleX.pptx
new file mode 100644
index 000000000..900a89675
--- /dev/null
+++ b/svx/qa/unit/data/tdf145004_gap_by_ScaleX.pptx
Binary files differ
diff --git a/svx/qa/unit/data/tdf145111_TL_BL_Fontwork.odp b/svx/qa/unit/data/tdf145111_TL_BL_Fontwork.odp
new file mode 100644
index 000000000..257023cfa
--- /dev/null
+++ b/svx/qa/unit/data/tdf145111_TL_BL_Fontwork.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf145245_ExtrusionPosition.odp b/svx/qa/unit/data/tdf145245_ExtrusionPosition.odp
new file mode 100644
index 000000000..a356cf9ed
--- /dev/null
+++ b/svx/qa/unit/data/tdf145245_ExtrusionPosition.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf145700_3D_FirstLightHarsh.doc b/svx/qa/unit/data/tdf145700_3D_FirstLightHarsh.doc
new file mode 100644
index 000000000..28b8b018d
--- /dev/null
+++ b/svx/qa/unit/data/tdf145700_3D_FirstLightHarsh.doc
Binary files differ
diff --git a/svx/qa/unit/data/tdf145700_3D_FrontLightDim.doc b/svx/qa/unit/data/tdf145700_3D_FrontLightDim.doc
new file mode 100644
index 000000000..5849e3eac
--- /dev/null
+++ b/svx/qa/unit/data/tdf145700_3D_FrontLightDim.doc
Binary files differ
diff --git a/svx/qa/unit/data/tdf145700_3D_NonUI.doc b/svx/qa/unit/data/tdf145700_3D_NonUI.doc
new file mode 100644
index 000000000..d62d57cf0
--- /dev/null
+++ b/svx/qa/unit/data/tdf145700_3D_NonUI.doc
Binary files differ
diff --git a/svx/qa/unit/data/tdf145904_center_Y0dot25.doc b/svx/qa/unit/data/tdf145904_center_Y0dot25.doc
new file mode 100644
index 000000000..f4f9b28f2
--- /dev/null
+++ b/svx/qa/unit/data/tdf145904_center_Y0dot25.doc
Binary files differ
diff --git a/svx/qa/unit/data/tdf145904_center_Y0dot25.odt b/svx/qa/unit/data/tdf145904_center_Y0dot25.odt
new file mode 100644
index 000000000..fcdbbff6c
--- /dev/null
+++ b/svx/qa/unit/data/tdf145904_center_Y0dot25.odt
Binary files differ
diff --git a/svx/qa/unit/data/tdf145904_center_Zminus2000.odt b/svx/qa/unit/data/tdf145904_center_Zminus2000.odt
new file mode 100644
index 000000000..9a19f4cbd
--- /dev/null
+++ b/svx/qa/unit/data/tdf145904_center_Zminus2000.odt
Binary files differ
diff --git a/svx/qa/unit/data/tdf145956_Origin.odp b/svx/qa/unit/data/tdf145956_Origin.odp
new file mode 100644
index 000000000..7bba1dadd
--- /dev/null
+++ b/svx/qa/unit/data/tdf145956_Origin.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf147409_GeomItemHash.odg b/svx/qa/unit/data/tdf147409_GeomItemHash.odg
new file mode 100644
index 000000000..770b7a6c0
--- /dev/null
+++ b/svx/qa/unit/data/tdf147409_GeomItemHash.odg
Binary files differ
diff --git a/svx/qa/unit/data/tdf148501_OctagonBevel.odp b/svx/qa/unit/data/tdf148501_OctagonBevel.odp
new file mode 100644
index 000000000..9dafaf7c2
--- /dev/null
+++ b/svx/qa/unit/data/tdf148501_OctagonBevel.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf148707_two_commands_B_V.odp b/svx/qa/unit/data/tdf148707_two_commands_B_V.odp
new file mode 100644
index 000000000..c26d371ef
--- /dev/null
+++ b/svx/qa/unit/data/tdf148707_two_commands_B_V.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf148714_CurvedArrows.ppt b/svx/qa/unit/data/tdf148714_CurvedArrows.ppt
new file mode 100644
index 000000000..23e4ed0ad
--- /dev/null
+++ b/svx/qa/unit/data/tdf148714_CurvedArrows.ppt
Binary files differ
diff --git a/svx/qa/unit/data/tdf60684.jpg b/svx/qa/unit/data/tdf60684.jpg
new file mode 100644
index 000000000..2218cdd72
--- /dev/null
+++ b/svx/qa/unit/data/tdf60684.jpg
Binary files differ
diff --git a/svx/qa/unit/data/tdf93998.odp b/svx/qa/unit/data/tdf93998.odp
new file mode 100644
index 000000000..889aeeb02
--- /dev/null
+++ b/svx/qa/unit/data/tdf93998.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf98583_ShearHorizontal.odp b/svx/qa/unit/data/tdf98583_ShearHorizontal.odp
new file mode 100644
index 000000000..37719e825
--- /dev/null
+++ b/svx/qa/unit/data/tdf98583_ShearHorizontal.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf98584_ShearVertical.odg b/svx/qa/unit/data/tdf98584_ShearVertical.odg
new file mode 100644
index 000000000..457521d50
--- /dev/null
+++ b/svx/qa/unit/data/tdf98584_ShearVertical.odg
Binary files differ
diff --git a/svx/qa/unit/data/theme.pptx b/svx/qa/unit/data/theme.pptx
new file mode 100644
index 000000000..08e4a3b6f
--- /dev/null
+++ b/svx/qa/unit/data/theme.pptx
Binary files differ
diff --git a/svx/qa/unit/data/unodraw-writer-image.odt b/svx/qa/unit/data/unodraw-writer-image.odt
new file mode 100644
index 000000000..5264118a3
--- /dev/null
+++ b/svx/qa/unit/data/unodraw-writer-image.odt
Binary files differ
diff --git a/svx/qa/unit/data/video-snapshot.pptx b/svx/qa/unit/data/video-snapshot.pptx
new file mode 100644
index 000000000..76f7c0d50
--- /dev/null
+++ b/svx/qa/unit/data/video-snapshot.pptx
Binary files differ
diff --git a/svx/qa/unit/data/viewBox_positive_twolines_strict.odp b/svx/qa/unit/data/viewBox_positive_twolines_strict.odp
new file mode 100644
index 000000000..3425582b8
--- /dev/null
+++ b/svx/qa/unit/data/viewBox_positive_twolines_strict.odp
Binary files differ
diff --git a/svx/qa/unit/gallery/data/galtest1.png b/svx/qa/unit/gallery/data/galtest1.png
new file mode 100644
index 000000000..37be81f9d
--- /dev/null
+++ b/svx/qa/unit/gallery/data/galtest1.png
Binary files differ
diff --git a/svx/qa/unit/gallery/data/galtest2.png b/svx/qa/unit/gallery/data/galtest2.png
new file mode 100644
index 000000000..bf1aac397
--- /dev/null
+++ b/svx/qa/unit/gallery/data/galtest2.png
Binary files differ
diff --git a/svx/qa/unit/gallery/data/galtest3.jpg b/svx/qa/unit/gallery/data/galtest3.jpg
new file mode 100644
index 000000000..59f67e9aa
--- /dev/null
+++ b/svx/qa/unit/gallery/data/galtest3.jpg
Binary files differ
diff --git a/svx/qa/unit/gallery/test_gallery.cxx b/svx/qa/unit/gallery/test_gallery.cxx
new file mode 100644
index 000000000..da224b439
--- /dev/null
+++ b/svx/qa/unit/gallery/test_gallery.cxx
@@ -0,0 +1,482 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+* This file is part of the LibreOffice project.
+*
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/.
+*/
+#include <test/bootstrapfixture.hxx>
+
+#include <tools/urlobj.hxx>
+#include <sfx2/app.hxx>
+#include <unotools/tempfile.hxx>
+#include <comphelper/DirectoryHelper.hxx>
+
+#include <svx/gallery1.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/gallerybinarystoragelocations.hxx>
+#include <svx/gallerystoragelocations.hxx>
+#include <galobj.hxx>
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+class GalleryObjTest : public test::BootstrapFixture
+{
+public:
+ void TestCreateTheme();
+ void TestDeleteTheme();
+ void TestSetThemeName();
+ void TestThemeURLCase();
+ void TestThemeCount();
+ void TestGalleryThemeEntry();
+ void TestInsertGalleryObject();
+ void TestRemoveGalleryObject();
+ void TestChangePositionGalleryObject();
+ void TestGetThemeNameFromGalleryTheme();
+
+ CPPUNIT_TEST_SUITE(GalleryObjTest);
+
+ CPPUNIT_TEST(TestCreateTheme);
+ CPPUNIT_TEST(TestDeleteTheme);
+ CPPUNIT_TEST(TestSetThemeName);
+ CPPUNIT_TEST(TestThemeURLCase);
+ CPPUNIT_TEST(TestThemeCount);
+ CPPUNIT_TEST(TestGalleryThemeEntry);
+ CPPUNIT_TEST(TestInsertGalleryObject);
+ CPPUNIT_TEST(TestRemoveGalleryObject);
+ CPPUNIT_TEST(TestChangePositionGalleryObject);
+ CPPUNIT_TEST(TestGetThemeNameFromGalleryTheme);
+
+ CPPUNIT_TEST_SUITE_END();
+};
+
+// Create and Dereference a theme, check that file exists
+void GalleryObjTest::TestCreateTheme()
+{
+ // Create theme
+ std::unique_ptr<utl::TempFile> pTempDir;
+ pTempDir.reset(new utl::TempFile(nullptr, true));
+ CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid());
+ pTempDir->EnableKillingFile();
+ const OUString aGalleryURL = pTempDir->GetURL();
+
+ // Check if directory exists
+ CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory",
+ comphelper::DirectoryHelper::dirExists(aGalleryURL));
+
+ std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL));
+ CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr));
+ static const OUStringLiteral myThemeName = u"addytesttheme";
+ CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName));
+
+ // check if files exist
+ CPPUNIT_ASSERT_MESSAGE(
+ "Could not find .thm file inside it",
+ comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".thm"));
+ CPPUNIT_ASSERT_MESSAGE(
+ "Could not find .sdv file inside it",
+ comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".sdv"));
+}
+
+// Create and Delete Theme, check the file doesn't exist
+void GalleryObjTest::TestDeleteTheme()
+{
+ // Create theme
+ std::unique_ptr<utl::TempFile> pTempDir;
+ pTempDir.reset(new utl::TempFile(nullptr, true));
+ CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid());
+ pTempDir->EnableKillingFile();
+ const OUString aGalleryURL = pTempDir->GetURL();
+
+ std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL));
+ CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr));
+ static const OUStringLiteral myThemeName = u"addytesttheme";
+ CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName));
+
+ // Delete Theme
+ CPPUNIT_ASSERT_MESSAGE("Could not remove theme", pGallery->RemoveTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not remove theme, theme found even after trying to remove",
+ !pGallery->HasTheme(myThemeName));
+
+ // Check that files do not exist
+ CPPUNIT_ASSERT_MESSAGE(
+ "Found .thm file inside it after deletion",
+ !comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".thm"));
+ CPPUNIT_ASSERT_MESSAGE(
+ "Found .sdv file inside it after deletion",
+ !comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".sdv"));
+ CPPUNIT_ASSERT_MESSAGE(
+ "Found .sdg file inside it after deletion",
+ !comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".sdg"));
+ CPPUNIT_ASSERT_MESSAGE(
+ "Found .str file inside it after deletion",
+ !comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".str"));
+}
+
+// Create theme, set name, assert the name is expected
+void GalleryObjTest::TestSetThemeName()
+{
+ // Create theme
+ std::unique_ptr<utl::TempFile> pTempDir;
+ pTempDir.reset(new utl::TempFile(nullptr, true));
+ CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid());
+ pTempDir->EnableKillingFile();
+ const OUString aGalleryURL = pTempDir->GetURL();
+
+ std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL));
+ CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr));
+ static const OUStringLiteral myThemeName = u"addytesttheme";
+ CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName));
+
+ // Rename theme
+ static const OUStringLiteral myNewThemeName = u"addytestthemenew";
+ pGallery->RenameTheme(myThemeName, myNewThemeName);
+ CPPUNIT_ASSERT_MESSAGE("Could not rename theme because old theme name still exists",
+ !pGallery->HasTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find new renamed theme", pGallery->HasTheme(myNewThemeName));
+
+ // Check that files are not renamed
+ CPPUNIT_ASSERT_MESSAGE(
+ "Could not find .thm file inside it",
+ comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".thm"));
+ CPPUNIT_ASSERT_MESSAGE(
+ "Could not find .sdv file inside it",
+ comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".sdv"));
+}
+
+void GalleryObjTest::TestThemeURLCase()
+{
+ // Create theme
+ std::unique_ptr<utl::TempFile> pTempDir;
+ pTempDir.reset(new utl::TempFile(nullptr, true));
+ CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid());
+ pTempDir->EnableKillingFile();
+ const OUString aGalleryURL = pTempDir->GetURL();
+
+ // Check if directory exists
+ CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory",
+ comphelper::DirectoryHelper::dirExists(aGalleryURL));
+
+ std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL));
+ CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr));
+
+ // Mixed Case Theme Name
+ const OUString myThemeName = "AddyTestTheme";
+
+ CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName));
+
+#if defined(LINUX)
+ CPPUNIT_ASSERT_MESSAGE("[LINUX] Could not find .thm in lowercase",
+ comphelper::DirectoryHelper::fileExists(
+ aGalleryURL + "/" + myThemeName.toAsciiLowerCase() + ".thm"));
+ CPPUNIT_ASSERT_MESSAGE("[LINUX] Could not find .sdv in lowercase",
+ comphelper::DirectoryHelper::fileExists(
+ aGalleryURL + "/" + myThemeName.toAsciiLowerCase() + ".sdv"));
+#else
+ CPPUNIT_ASSERT_MESSAGE(
+ "[WINDOWS] Could not find .thm in mixed case",
+ comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".thm"));
+ CPPUNIT_ASSERT_MESSAGE(
+ "[WINDOWS] Could not find .sdv in mixed case",
+ comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".sdv"));
+#endif
+}
+
+void GalleryObjTest::TestThemeCount()
+{
+ std::unique_ptr<utl::TempFile> pTempDir;
+ pTempDir.reset(new utl::TempFile(nullptr, true));
+ CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid());
+ pTempDir->EnableKillingFile();
+ const OUString aGalleryURL = pTempDir->GetURL();
+
+ // Check if directory exists
+ CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory",
+ comphelper::DirectoryHelper::dirExists(aGalleryURL));
+
+ std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL));
+ CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr));
+
+ // Loop through and test theme count in each pass.
+ sal_uInt32 nLimit = 10;
+ for (sal_uInt32 i = 1; i <= nLimit; i++)
+ {
+ OUString myThemeName = "addytesttheme" + OUString::number(i);
+ // Create theme
+ CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Inconsistent theme count",
+ static_cast<sal_uInt32>(pGallery->GetThemeCount()), i);
+ }
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Inconsistent theme count",
+ static_cast<sal_uInt32>(pGallery->GetThemeCount()), nLimit);
+ for (sal_uInt32 i = nLimit; i > 0; i--)
+ {
+ OUString myThemeName = "addytesttheme" + OUString::number(i);
+ // Delete Theme
+ CPPUNIT_ASSERT_MESSAGE("Could not remove theme", pGallery->RemoveTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not remove theme, theme found even after trying to remove",
+ !pGallery->HasTheme(myThemeName));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Inconsistent theme count",
+ static_cast<sal_uInt32>(pGallery->GetThemeCount()), i - 1);
+ }
+}
+
+void GalleryObjTest::TestGalleryThemeEntry()
+{
+ // Create theme
+ std::unique_ptr<utl::TempFile> pTempDir;
+ pTempDir.reset(new utl::TempFile(nullptr, true));
+ CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid());
+ pTempDir->EnableKillingFile();
+ const OUString aGalleryURL = pTempDir->GetURL();
+
+ // Check if directory exists
+ CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory",
+ comphelper::DirectoryHelper::dirExists(aGalleryURL));
+
+ std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL));
+ CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr));
+ const OUString myThemeName = "addytesttheme";
+ CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName));
+
+ // Get Theme Entry Object
+ const GalleryThemeEntry* mpThemeEntry = pGallery->GetThemeInfo(myThemeName);
+
+ // Check Theme Name
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Theme name doesn't match", mpThemeEntry->GetThemeName(),
+ myThemeName);
+
+ // Check URLs
+ GalleryBinaryStorageLocations& aGalleryBinaryStorageLocations
+ = dynamic_cast<GalleryBinaryStorageLocations&>(mpThemeEntry->getGalleryStorageLocations());
+ INetURLObject aURL(aGalleryURL);
+ aURL.Append(myThemeName);
+ INetURLObject aThemeURL(aURL), aSdvURL(aURL), aSdgURL(aURL), aStrURL(aURL);
+ aThemeURL.setExtension(u"thm");
+ aSdvURL.setExtension(u"sdv");
+ aSdgURL.setExtension(u"sdg");
+ aStrURL.setExtension(u"str");
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Theme URL doesn't match",
+ aGalleryBinaryStorageLocations.GetThmURL().GetMainURL(
+ INetURLObject::DecodeMechanism::Unambiguous),
+ aThemeURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Sdv URL doesn't match",
+ aGalleryBinaryStorageLocations.GetSdvURL().GetMainURL(
+ INetURLObject::DecodeMechanism::Unambiguous),
+ aSdvURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Sdg URL doesn't match",
+ aGalleryBinaryStorageLocations.GetSdgURL().GetMainURL(
+ INetURLObject::DecodeMechanism::Unambiguous),
+ aSdgURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Str URL doesn't match",
+ aGalleryBinaryStorageLocations.GetStrURL().GetMainURL(
+ INetURLObject::DecodeMechanism::Unambiguous),
+ aStrURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous));
+}
+
+void GalleryObjTest::TestInsertGalleryObject()
+{
+ // Create theme
+ std::unique_ptr<utl::TempFile> pTempDir;
+ pTempDir.reset(new utl::TempFile(nullptr, true));
+ CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid());
+ pTempDir->EnableKillingFile();
+ const OUString aGalleryURL = pTempDir->GetURL();
+
+ // Check if directory exists
+ CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory",
+ comphelper::DirectoryHelper::dirExists(aGalleryURL));
+
+ std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL));
+ CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr));
+ static const OUStringLiteral myThemeName = u"addytesttheme";
+ CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName));
+
+ // Create Sfx Instance
+ SfxListener aListener;
+ SfxApplication::GetOrCreate();
+
+ // Insert Objects Into Theme
+ GalleryTheme* pGalleryTheme = pGallery->AcquireTheme(myThemeName, aListener);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Object count inconsistent", sal_uInt32(0),
+ pGalleryTheme->GetObjectCount());
+
+ std::vector<OUString> imageList{ "galtest1.png", "galtest2.png", "galtest3.jpg" };
+
+ for (sal_uInt32 i = 0; i < static_cast<sal_uInt32>(imageList.size()); i++)
+ {
+ OUString imageNameFromList(imageList[i]);
+ OUString aURL(m_directories.getURLFromSrc(u"/svx/qa/unit/gallery/data/")
+ + imageNameFromList);
+ CPPUNIT_ASSERT_MESSAGE("Could not insert object into theme",
+ pGalleryTheme->InsertURL(INetURLObject(aURL)));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Inconsistent object Count", pGalleryTheme->GetObjectCount(),
+ i + 1);
+ std::unique_ptr<SgaObject> pObj = pGalleryTheme->AcquireObject(i);
+ CPPUNIT_ASSERT_MESSAGE("Acquired Object Invalid", pObj->IsValid());
+ }
+ pGallery->ReleaseTheme(pGalleryTheme, aListener);
+}
+
+void GalleryObjTest::TestRemoveGalleryObject()
+{
+ // Create theme
+ std::unique_ptr<utl::TempFile> pTempDir;
+ pTempDir.reset(new utl::TempFile(nullptr, true));
+ CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid());
+ pTempDir->EnableKillingFile();
+ const OUString aGalleryURL = pTempDir->GetURL();
+
+ // Check if directory exists
+ CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory",
+ comphelper::DirectoryHelper::dirExists(aGalleryURL));
+
+ std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL));
+ CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr));
+ static const OUStringLiteral myThemeName = u"addytesttheme";
+ CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName));
+
+ // Create Sfx Instance
+ SfxListener aListener;
+ SfxApplication::GetOrCreate();
+
+ // Insert Objects Into Theme
+ GalleryTheme* pGalleryTheme = pGallery->AcquireTheme(myThemeName, aListener);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Object count inconsistent", sal_uInt32(0),
+ pGalleryTheme->GetObjectCount());
+
+ std::vector<OUString> imageList{ "galtest1.png", "galtest2.png", "galtest3.jpg" };
+
+ for (sal_uInt32 i = 0; i < static_cast<sal_uInt32>(imageList.size()); i++)
+ {
+ OUString imageNameFromList(imageList[i]);
+ OUString aURL(m_directories.getURLFromSrc(u"/svx/qa/unit/gallery/data/")
+ + imageNameFromList);
+ CPPUNIT_ASSERT_MESSAGE("Could not insert object into theme",
+ pGalleryTheme->InsertURL(INetURLObject(aURL)));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Inconsistent object Count", pGalleryTheme->GetObjectCount(),
+ i + 1);
+ std::unique_ptr<SgaObject> pObj = pGalleryTheme->AcquireObject(i);
+ CPPUNIT_ASSERT_MESSAGE("Acquired Object Invalid", pObj->IsValid());
+ }
+
+ for (sal_uInt32 i = static_cast<sal_uInt32>(imageList.size()); i > 0; i--)
+ {
+ std::unique_ptr<SgaObject> pObj = pGalleryTheme->AcquireObject(i - 1);
+ CPPUNIT_ASSERT_MESSAGE("Acquired Object Invalid", pObj->IsValid());
+ pGalleryTheme->RemoveObject(i - 1);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Inconsistent object Count", pGalleryTheme->GetObjectCount(),
+ i - 1);
+ }
+
+ pGallery->ReleaseTheme(pGalleryTheme, aListener);
+}
+
+void GalleryObjTest::TestChangePositionGalleryObject()
+{
+ // Create theme
+ std::unique_ptr<utl::TempFile> pTempDir;
+ pTempDir.reset(new utl::TempFile(nullptr, true));
+ CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid());
+ pTempDir->EnableKillingFile();
+ const OUString aGalleryURL = pTempDir->GetURL();
+
+ // Check if directory exists
+ CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory",
+ comphelper::DirectoryHelper::dirExists(aGalleryURL));
+
+ std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL));
+ CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr));
+ static const OUStringLiteral myThemeName = u"addytesttheme";
+ CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName));
+
+ // Create Sfx Instance
+ SfxListener aListener;
+ SfxApplication::GetOrCreate();
+
+ // Insert Objects Into Theme
+ GalleryTheme* pGalleryTheme = pGallery->AcquireTheme(myThemeName, aListener);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Object count inconsistent", sal_uInt32(0),
+ pGalleryTheme->GetObjectCount());
+
+ OUString imageList[] = { "galtest1.png", "galtest2.png", "galtest3.jpg" };
+
+ for (sal_uInt32 i = 0; i < (sizeof(imageList) / sizeof(imageList[0])); i++)
+ {
+ OUString imageNameFromList(imageList[i]);
+ OUString aURL(m_directories.getURLFromSrc(u"/svx/qa/unit/gallery/data/")
+ + imageNameFromList);
+ CPPUNIT_ASSERT_MESSAGE("Could not insert object into theme",
+ pGalleryTheme->InsertURL(INetURLObject(aURL)));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Inconsistent object Count", pGalleryTheme->GetObjectCount(),
+ i + 1);
+ std::unique_ptr<SgaObject> pObj = pGalleryTheme->AcquireObject(i);
+ CPPUNIT_ASSERT_MESSAGE("Acquired Object Invalid", pObj->IsValid());
+ }
+
+ CPPUNIT_ASSERT(pGalleryTheme->ChangeObjectPos(1, 3));
+ std::unique_ptr<SgaObject> pObj = pGalleryTheme->AcquireObject(0);
+ INetURLObject aURL = pObj->GetURL();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Failure to change object position", imageList[0],
+ aURL.GetLastName());
+
+ pObj = pGalleryTheme->AcquireObject(1);
+ aURL = pObj->GetURL();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Failure to change object position", imageList[2],
+ aURL.GetLastName());
+
+ pObj = pGalleryTheme->AcquireObject(2);
+ aURL = pObj->GetURL();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Failure to change object position", imageList[1],
+ aURL.GetLastName());
+
+ pGallery->ReleaseTheme(pGalleryTheme, aListener);
+}
+
+void GalleryObjTest::TestGetThemeNameFromGalleryTheme()
+{
+ // Create theme
+ std::unique_ptr<utl::TempFile> pTempDir;
+ pTempDir.reset(new utl::TempFile(nullptr, true));
+ CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid());
+ pTempDir->EnableKillingFile();
+ const OUString aGalleryURL = pTempDir->GetURL();
+
+ // Check if directory exists
+ CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory",
+ comphelper::DirectoryHelper::dirExists(aGalleryURL));
+
+ std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL));
+ CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr));
+ const OUString myThemeName = "addytesttheme";
+ CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName));
+ CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName));
+
+ // Create Sfx Instance
+ SfxListener aListener;
+ SfxApplication::GetOrCreate();
+
+ GalleryTheme* pGalleryTheme = pGallery->AcquireTheme(myThemeName, aListener);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Object count inconsistent", sal_uInt32(0),
+ pGalleryTheme->GetObjectCount());
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Theme name not matching", myThemeName, pGalleryTheme->GetName());
+
+ pGallery->ReleaseTheme(pGalleryTheme, aListener);
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(GalleryObjTest);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/svx/qa/unit/removewhichrange.cxx b/svx/qa/unit/removewhichrange.cxx
new file mode 100644
index 000000000..d5856f6c7
--- /dev/null
+++ b/svx/qa/unit/removewhichrange.cxx
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <sal/types.h>
+#include <svx/svdetc.hxx>
+
+namespace
+{
+class TestRemoveWhichRange : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestRemoveWhichRange);
+ CPPUNIT_TEST(testRemoveWhichRange);
+ CPPUNIT_TEST_SUITE_END();
+
+ void testRemoveWhichRange()
+ {
+ {
+ WhichRangesContainer in;
+ auto const out = RemoveWhichRange(in, 10, 20);
+ CPPUNIT_ASSERT(out.empty());
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 30, 40>);
+ auto const out = RemoveWhichRange(in, 0, 20);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(30), out[0].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(40), out[0].second);
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 30, 40>);
+ auto const out = RemoveWhichRange(in, 10, 20);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(30), out[0].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(40), out[0].second);
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 30, 40>);
+ auto const out = RemoveWhichRange(in, 15, 20);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(10), out[0].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(14), out[0].second);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(30), out[1].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(40), out[1].second);
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 30, 40>);
+ auto const out = RemoveWhichRange(in, 30, 40);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(10), out[0].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(20), out[0].second);
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 30, 40>);
+ auto const out = RemoveWhichRange(in, 30, 50);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(10), out[0].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(20), out[0].second);
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 30, 40>);
+ auto const out = RemoveWhichRange(in, 30, 35);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(10), out[0].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(20), out[0].second);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(36), out[1].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(40), out[1].second);
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 30, 40>);
+ auto const out = RemoveWhichRange(in, 15, 35);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(10), out[0].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(14), out[0].second);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(36), out[1].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(40), out[1].second);
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 30, 40>);
+ auto const out = RemoveWhichRange(in, 12, 15);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(10), out[0].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(11), out[0].second);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(16), out[1].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(20), out[1].second);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(30), out[2].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(40), out[2].second);
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 30, 40>);
+ auto const out = RemoveWhichRange(in, 0, 100);
+ CPPUNIT_ASSERT(out.empty());
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 40, 50>);
+ auto const out = RemoveWhichRange(in, 25, 35);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(10), out[0].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(20), out[0].second);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(40), out[1].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(50), out[1].second);
+ }
+ {
+ WhichRangesContainer in(svl::Items<10, 20, 40, 50>);
+ auto const out = RemoveWhichRange(in, 50, 100);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(10), out[0].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(20), out[0].second);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(40), out[1].first);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(49), out[1].second);
+ }
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestRemoveWhichRange);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/qa/unit/sdr.cxx b/svx/qa/unit/sdr.cxx
new file mode 100644
index 000000000..d665987b1
--- /dev/null
+++ b/svx/qa/unit/sdr.cxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+#include <test/xmltesttools.hxx>
+
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+
+#include <drawinglayer/tools/primitive2dxmldump.hxx>
+#include <rtl/ustring.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unopage.hxx>
+#include <vcl/virdev.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for svx/source/sdr/ code.
+class SdrTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
+{
+protected:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ virtual void setUp() override
+ {
+ test::BootstrapFixture::setUp();
+ mxDesktop.set(frame::Desktop::create(m_xContext));
+ }
+
+ virtual void tearDown() override
+ {
+ if (mxComponent.is())
+ {
+ mxComponent->dispose();
+ }
+ test::BootstrapFixture::tearDown();
+ }
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+
+ drawinglayer::primitive2d::Primitive2DContainer
+ renderPageToPrimitives(const uno::Reference<drawing::XDrawPage>& xDrawPage);
+};
+
+drawinglayer::primitive2d::Primitive2DContainer
+SdrTest::renderPageToPrimitives(const uno::Reference<drawing::XDrawPage>& xDrawPage)
+{
+ auto pDrawPage = dynamic_cast<SvxDrawPage*>(xDrawPage.get());
+ CPPUNIT_ASSERT(pDrawPage);
+ SdrPage* pSdrPage = pDrawPage->GetSdrPage();
+ ScopedVclPtrInstance<VirtualDevice> aVirtualDevice;
+ sdr::contact::ObjectContactOfObjListPainter aObjectContact(*aVirtualDevice,
+ { pSdrPage->GetObj(0) }, nullptr);
+ const sdr::contact::ViewObjectContact& rDrawPageVOContact
+ = pSdrPage->GetViewContact().GetViewObjectContact(aObjectContact);
+ sdr::contact::DisplayInfo aDisplayInfo;
+ drawinglayer::primitive2d::Primitive2DContainer aContainer;
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo, aContainer);
+ return aContainer;
+}
+
+CPPUNIT_TEST_FIXTURE(SdrTest, testShadowScaleOrigin)
+{
+ // Load a document containing a custom shape.
+ test::Directories aDirectories;
+ OUString aURL = aDirectories.getURLFromSrc(u"svx/qa/unit/data/shadow-scale-origin.pptx");
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence
+ = renderPageToPrimitives(xDrawPage);
+
+ // Examine the created primitives.
+ drawinglayer::Primitive2dXmlDump aDumper;
+ xmlDocUniquePtr pDocument = aDumper.dumpAndParse(xPrimitiveSequence);
+ sal_Int32 fShadowX = getXPath(pDocument, "//shadow/transform", "xy13").toInt32();
+ sal_Int32 fShadowY = getXPath(pDocument, "//shadow/transform", "xy23").toInt32();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: -705
+ // - Actual : -158
+ // i.e. the shadow origin was not the top right corner for scaling (larger x position, so it was
+ // visible on the right of the shape as well).
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(-705), fShadowX);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(-684), fShadowY);
+}
+
+CPPUNIT_TEST_FIXTURE(SdrTest, testZeroWidthTextWrap)
+{
+ // Load a document containing a 0-width shape with text.
+ test::Directories aDirectories;
+ OUString aURL = aDirectories.getURLFromSrc(u"svx/qa/unit/data/0-width-text-wrap.pptx");
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence
+ = renderPageToPrimitives(xDrawPage);
+
+ // Examine the created primitives.
+ drawinglayer::Primitive2dXmlDump aDumper;
+ xmlDocUniquePtr pDocument = aDumper.dumpAndParse(xPrimitiveSequence);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 12
+ // i.e. the text on the only shape on the slide had 12 lines, not a single one.
+ assertXPath(pDocument, "//textsimpleportion", 1);
+}
+
+CPPUNIT_TEST_FIXTURE(SdrTest, testSlideBackground)
+{
+ // Given a document with a slide what has a linked background image:
+ test::Directories aDirectories;
+ OUString aURL = aDirectories.getURLFromSrc(u"svx/qa/unit/data/slide-background.odp");
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+
+ // When rendering that document:
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence
+ = renderPageToPrimitives(xDrawPage);
+
+ // Then make sure that the background has a bitmap:
+ drawinglayer::Primitive2dXmlDump aDumper;
+ xmlDocUniquePtr pDocument = aDumper.dumpAndParse(xPrimitiveSequence);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. the rendering did not find the bitmap.
+ assertXPath(pDocument, "//bitmap", 1);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/styles.cxx b/svx/qa/unit/styles.cxx
new file mode 100644
index 000000000..dd27e24f0
--- /dev/null
+++ b/svx/qa/unit/styles.cxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XMasterPageTarget.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for svx/source/styles/ code.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/svx/qa/unit/data/";
+
+/// Get the character color of the first text portion in xShape.
+sal_Int32 GetShapeTextColor(const uno::Reference<text::XTextRange>& xShape)
+{
+ uno::Reference<container::XEnumerationAccess> xText(xShape->getText(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xPara(xText->createEnumeration()->nextElement(),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xPortion(xPara->createEnumeration()->nextElement(),
+ uno::UNO_QUERY);
+ sal_Int32 nColor{};
+ xPortion->getPropertyValue("CharColor") >>= nColor;
+ return nColor;
+}
+
+/// Get the solid fill color of xShape.
+sal_Int32 GetShapeFillColor(const uno::Reference<beans::XPropertySet>& xShape)
+{
+ sal_Int32 nColor{};
+ xShape->getPropertyValue("FillColor") >>= nColor;
+ return nColor;
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testThemeChange)
+{
+ // Given a document, with a first slide and blue shape text from theme:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "theme.pptx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ // The draw page also contains a group shape to make sure we don't crash on group shapes.
+ uno::Reference<drawing::XMasterPageTarget> xDrawPage(
+ xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<drawing::XShapes> xDrawPageShapes(xDrawPage, uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xShape(xDrawPageShapes->getByIndex(0), uno::UNO_QUERY);
+ // Blue.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0x4472c4), GetShapeTextColor(xShape));
+ uno::Reference<text::XTextRange> xShape2(xDrawPageShapes->getByIndex(1), uno::UNO_QUERY);
+ // Blue, lighter.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xb4c7e7), GetShapeTextColor(xShape2));
+ uno::Reference<text::XTextRange> xShape3(xDrawPageShapes->getByIndex(2), uno::UNO_QUERY);
+ // Blue, darker.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0x2f5597), GetShapeTextColor(xShape3));
+ // Shape fill:
+ uno::Reference<beans::XPropertySet> xShape4(xDrawPageShapes->getByIndex(4), uno::UNO_QUERY);
+ // Blue.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0x4472c4), GetShapeFillColor(xShape4));
+ // The theme index of this filled shape is set by the PPTX import:
+ sal_Int16 nColorTheme = -1;
+ xShape4->getPropertyValue("FillColorTheme") >>= nColorTheme;
+ // 4 means accent1, this was -1 without the PPTX import bit in place.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(4), nColorTheme);
+ uno::Reference<beans::XPropertySet> xShape5(xDrawPageShapes->getByIndex(5), uno::UNO_QUERY);
+ // Blue, lighter.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xb4c7e7), GetShapeFillColor(xShape5));
+ // The theme index, and effects (lum mod, lum off) are set by the PPTX import:
+ nColorTheme = -1;
+ xShape5->getPropertyValue("FillColorTheme") >>= nColorTheme;
+ // 4 means accent1, this was -1 without the PPTX import bit in place.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(4), nColorTheme);
+ sal_Int16 nColorLumMod = 10000;
+ xShape5->getPropertyValue("FillColorLumMod") >>= nColorLumMod;
+ // This was 10000 without the PPTX import bit in place.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(4000), nColorLumMod);
+ sal_Int16 nColorLumOff = 0;
+ xShape5->getPropertyValue("FillColorLumOff") >>= nColorLumOff;
+ // This was 0 without the PPTX import bit in place.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(6000), nColorLumOff);
+
+ // When changing the master slide of slide 1 to use the theme of the second master slide:
+ uno::Reference<drawing::XMasterPageTarget> xDrawPage2(
+ xDrawPagesSupplier->getDrawPages()->getByIndex(1), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xMasterPage2(xDrawPage2->getMasterPage(), uno::UNO_QUERY);
+ uno::Any aTheme = xMasterPage2->getPropertyValue("Theme");
+ uno::Reference<beans::XPropertySet> xMasterPage(xDrawPage->getMasterPage(), uno::UNO_QUERY);
+ xMasterPage->setPropertyValue("Theme", aTheme);
+
+ // Then make sure the shape text color is now green:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 9486886 (#90c226, green)
+ // - Actual : 4485828 (#4472c4, blue)
+ // i.e. shape text was not updated on theme change.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0x90c226), GetShapeTextColor(xShape));
+ // Green, lighter:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 14020002 (#d5eda2, light green)
+ // - Actual : 9486886 (#90c226, stock green)
+ // i.e. the "light" effect on green was not applied.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xd5eda2), GetShapeTextColor(xShape2));
+ // Green, darker.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0x6c911d), GetShapeTextColor(xShape3));
+ // Shape fill:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 9486886 (#90c226, green)
+ // - Actual : 4485828 (#4472c4, blue)
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0x90c226), GetShapeFillColor(xShape4));
+ // Green, lighter:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 14020002 (#d5eda2, light green)
+ // - Actual : 9486886 (#90c226, green)
+ // i.e. the "light" effect on green was not applied.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xd5eda2), GetShapeFillColor(xShape5));
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx
new file mode 100644
index 000000000..564998bcf
--- /dev/null
+++ b/svx/qa/unit/svdraw.cxx
@@ -0,0 +1,554 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+#include <test/xmltesttools.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/drawing/HomogenMatrix3.hpp>
+
+#include <drawinglayer/tools/primitive2dxmldump.hxx>
+#include <rtl/ustring.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/unopage.hxx>
+#include <svx/svdview.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnstwit.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svl/itempool.hxx>
+#include <svx/svdomedia.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <vcl/filter/PDFiumLibrary.hxx>
+
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for svx/source/svdraw/ code.
+class SvdrawTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
+{
+protected:
+ uno::Reference<lang::XComponent> mxComponent;
+ SdrPage* getFirstDrawPageWithAssert();
+
+public:
+ virtual void setUp() override
+ {
+ test::BootstrapFixture::setUp();
+ mxDesktop.set(frame::Desktop::create(m_xContext));
+ }
+
+ virtual void tearDown() override
+ {
+ if (mxComponent.is())
+ {
+ mxComponent->dispose();
+ }
+ test::BootstrapFixture::tearDown();
+ }
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+SdrPage* SvdrawTest::getFirstDrawPageWithAssert()
+{
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent,
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT(xDrawPagesSupplier.is());
+ uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages());
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT(xDrawPage.is());
+
+ auto pDrawPage = dynamic_cast<SvxDrawPage*>(xDrawPage.get());
+ CPPUNIT_ASSERT(pDrawPage);
+ return pDrawPage->GetSdrPage();
+}
+
+xmlDocUniquePtr lcl_dumpAndParseFirstObjectWithAssert(SdrPage* pSdrPage)
+{
+ ScopedVclPtrInstance<VirtualDevice> aVirtualDevice;
+ sdr::contact::ObjectContactOfObjListPainter aObjectContact(*aVirtualDevice,
+ { pSdrPage->GetObj(0) }, nullptr);
+ const auto& rDrawPageVOContact
+ = pSdrPage->GetViewContact().GetViewObjectContact(aObjectContact);
+ sdr::contact::DisplayInfo aDisplayInfo;
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence;
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo, xPrimitiveSequence);
+
+ drawinglayer::Primitive2dXmlDump aDumper;
+ xmlDocUniquePtr pXmlDoc = aDumper.dumpAndParse(xPrimitiveSequence);
+ CPPUNIT_ASSERT(pXmlDoc);
+ return pXmlDoc;
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testSemiTransparentText)
+{
+ // Create a new Draw document with a rectangle.
+ getComponent() = loadFromDesktop("private:factory/sdraw");
+ uno::Reference<lang::XMultiServiceFactory> xFactory(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(10000, 10000));
+ xShape->setPosition(awt::Point(1000, 1000));
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ xDrawPage->add(xShape);
+
+ // Add semi-transparent text on the rectangle.
+ uno::Reference<text::XTextRange> xShapeText(xShape, uno::UNO_QUERY);
+ xShapeText->getText()->setString("hello");
+
+ uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
+ xShapeProperties->setPropertyValue("CharColor", uno::Any(COL_RED));
+ sal_Int16 nTransparence = 75;
+ xShapeProperties->setPropertyValue("CharTransparence", uno::Any(nTransparence));
+
+ // Generates drawinglayer primitives for the page.
+ auto pDrawPage = dynamic_cast<SvxDrawPage*>(xDrawPage.get());
+ CPPUNIT_ASSERT(pDrawPage);
+ SdrPage* pSdrPage = pDrawPage->GetSdrPage();
+ xmlDocUniquePtr pDocument = lcl_dumpAndParseFirstObjectWithAssert(pSdrPage);
+
+ // Make sure the text is semi-transparent.
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // - XPath '//unifiedtransparence' number of nodes is incorrect
+ // i.e. the text was just plain red, not semi-transparent.
+ sal_Int16 fTransparence
+ = getXPath(pDocument, "//unifiedtransparence", "transparence").toInt32();
+ CPPUNIT_ASSERT_EQUAL(nTransparence, fTransparence);
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testHandlePathObjScale)
+{
+ // Given a path object:
+ getComponent() = loadFromDesktop("private:factory/sdraw");
+ uno::Reference<lang::XMultiServiceFactory> xFactory(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.ClosedBezierShape"), uno::UNO_QUERY);
+
+ // When setting its scale by both using setSize() and scaling in a transform matrix:
+ // Set size and basic properties.
+ xShape->setPosition(awt::Point(2512, 6062));
+ xShape->setSize(awt::Size(112, 112));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ xShapeProps->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_SOLID));
+ xShapeProps->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_SOLID));
+ xShapeProps->setPropertyValue("FillColor", uno::Any(static_cast<sal_Int32>(0)));
+ // Add it to the draw page.
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ xDrawPage->add(xShape);
+ // Set polygon coordinates.
+ drawing::PolyPolygonBezierCoords aPolyPolygonBezierCoords;
+ aPolyPolygonBezierCoords.Coordinates = {
+ {
+ awt::Point(2624, 6118),
+ awt::Point(2624, 6087),
+ awt::Point(2599, 6062),
+ awt::Point(2568, 6062),
+ awt::Point(2537, 6062),
+ awt::Point(2512, 6087),
+ awt::Point(2512, 6118),
+ awt::Point(2512, 6149),
+ awt::Point(2537, 6175),
+ awt::Point(2568, 6174),
+ awt::Point(2599, 6174),
+ awt::Point(2625, 6149),
+ awt::Point(2624, 6118),
+ },
+ };
+ aPolyPolygonBezierCoords.Flags = {
+ {
+ drawing::PolygonFlags_NORMAL,
+ drawing::PolygonFlags_CONTROL,
+ drawing::PolygonFlags_CONTROL,
+ drawing::PolygonFlags_NORMAL,
+ drawing::PolygonFlags_CONTROL,
+ drawing::PolygonFlags_CONTROL,
+ drawing::PolygonFlags_NORMAL,
+ drawing::PolygonFlags_CONTROL,
+ drawing::PolygonFlags_CONTROL,
+ drawing::PolygonFlags_NORMAL,
+ drawing::PolygonFlags_CONTROL,
+ drawing::PolygonFlags_CONTROL,
+ drawing::PolygonFlags_NORMAL,
+ },
+ };
+ xShapeProps->setPropertyValue("PolyPolygonBezier", uno::Any(aPolyPolygonBezierCoords));
+ drawing::HomogenMatrix3 aMatrix;
+ aMatrix.Line1.Column1 = 56;
+ aMatrix.Line2.Column1 = -97;
+ aMatrix.Line3.Column1 = 0;
+ aMatrix.Line1.Column2 = 97;
+ aMatrix.Line2.Column2 = 56;
+ aMatrix.Line3.Column2 = 0;
+ aMatrix.Line1.Column3 = 3317;
+ aMatrix.Line2.Column3 = 5583;
+ aMatrix.Line3.Column3 = 1;
+ xShapeProps->setPropertyValue("Transformation", uno::Any(aMatrix));
+
+ // Then make sure the scaling is only applied once:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 113
+ // - Actual : 12566
+ // i.e. the scaling was applied twice.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(113), xShape->getSize().Width);
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testTextEditEmptyGrabBag)
+{
+ // Given a document with a groupshape, which has 2 children.
+ getComponent() = loadFromDesktop("private:factory/sdraw");
+ uno::Reference<lang::XMultiServiceFactory> xFactory(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xRect1(
+ xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xRect1->setPosition(awt::Point(1000, 1000));
+ xRect1->setSize(awt::Size(10000, 10000));
+ uno::Reference<drawing::XShape> xRect2(
+ xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xRect2->setPosition(awt::Point(1000, 1000));
+ xRect2->setSize(awt::Size(10000, 10000));
+ uno::Reference<drawing::XShapes> xGroup(
+ xFactory->createInstance("com.sun.star.drawing.GroupShape"), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xGroupShape(xGroup, uno::UNO_QUERY);
+ xDrawPage->add(xGroupShape);
+ xGroup->add(xRect1);
+ xGroup->add(xRect2);
+ uno::Reference<text::XTextRange> xRect2Text(xRect2, uno::UNO_QUERY);
+ xRect2Text->setString("x");
+ uno::Sequence<beans::PropertyValue> aGrabBag = {
+ comphelper::makePropertyValue("OOXLayout", true),
+ };
+ uno::Reference<beans::XPropertySet> xGroupProps(xGroup, uno::UNO_QUERY);
+ xGroupProps->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag));
+
+ // When editing the shape text of the 2nd rectangle (insert a char at the start).
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ SdrView* pSdrView = pViewShell->GetDrawView();
+ SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xRect2);
+ pSdrView->SdrBeginTextEdit(pObject);
+ EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView();
+ rEditView.InsertText("y");
+ pSdrView->SdrEndTextEdit();
+
+ // Then make sure that grab-bag is empty to avoid losing the new text.
+ xGroupProps->getPropertyValue("InteropGrabBag") >>= aGrabBag;
+ // Without the accompanying fix in place, this test would have failed with:
+ // assertion failed
+ // - Expression: !aGrabBag.hasElements()
+ // i.e. the grab-bag was still around after modifying the shape, and that grab-bag contained the
+ // old text.
+ CPPUNIT_ASSERT(!aGrabBag.hasElements());
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testRectangleObject)
+{
+ std::unique_ptr<SdrModel> pModel(new SdrModel(nullptr, nullptr, true));
+ pModel->GetItemPool().FreezeIdRanges();
+
+ rtl::Reference<SdrPage> pPage(new SdrPage(*pModel, false));
+ pPage->SetSize(Size(1000, 1000));
+ pModel->InsertPage(pPage.get(), 0);
+
+ tools::Rectangle aSize(Point(), Size(100, 100));
+ auto* pRectangle = new SdrRectObj(*pModel, aSize);
+ pPage->NbcInsertObject(pRectangle);
+ pRectangle->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
+ pRectangle->SetMergedItem(XLineStartWidthItem(200));
+
+ ScopedVclPtrInstance<VirtualDevice> aVirtualDevice;
+ aVirtualDevice->SetOutputSize(Size(2000, 2000));
+
+ SdrView aView(*pModel, aVirtualDevice);
+ aView.hideMarkHandles();
+ aView.ShowSdrPage(pPage.get());
+
+ sdr::contact::ObjectContactOfObjListPainter aObjectContact(*aVirtualDevice,
+ { pPage->GetObj(0) }, nullptr);
+ const sdr::contact::ViewObjectContact& rDrawPageVOContact
+ = pPage->GetViewContact().GetViewObjectContact(aObjectContact);
+
+ sdr::contact::DisplayInfo aDisplayInfo;
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence;
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo, xPrimitiveSequence);
+
+ drawinglayer::Primitive2dXmlDump aDumper;
+ xmlDocUniquePtr pXmlDoc = aDumper.dumpAndParse(xPrimitiveSequence);
+
+ assertXPath(pXmlDoc, "/primitive2D", 1);
+
+ OString aBasePath("/primitive2D/sdrrectangle/polypolygoncolor");
+ assertXPath(pXmlDoc, aBasePath, "color", "#729fcf");
+
+ assertXPath(pXmlDoc, aBasePath + "/polypolygon", "height",
+ "99"); // weird Rectangle is created with size 100
+ assertXPath(pXmlDoc, aBasePath + "/polypolygon", "width", "99");
+ assertXPath(pXmlDoc, aBasePath + "/polypolygon", "minx", "0");
+ assertXPath(pXmlDoc, aBasePath + "/polypolygon", "miny", "0");
+ assertXPath(pXmlDoc, aBasePath + "/polypolygon", "maxx", "99");
+ assertXPath(pXmlDoc, aBasePath + "/polypolygon", "maxy", "99");
+
+ aBasePath = "/primitive2D/sdrrectangle/polypolygoncolor/polypolygon/polygon";
+
+ assertXPath(pXmlDoc, aBasePath + "/point", 5);
+ assertXPath(pXmlDoc, aBasePath + "/point[1]", "x", "49.5"); // hmm, weird, why?
+ assertXPath(pXmlDoc, aBasePath + "/point[1]", "y", "99");
+ assertXPath(pXmlDoc, aBasePath + "/point[2]", "x", "0");
+ assertXPath(pXmlDoc, aBasePath + "/point[2]", "y", "99");
+ assertXPath(pXmlDoc, aBasePath + "/point[3]", "x", "0");
+ assertXPath(pXmlDoc, aBasePath + "/point[3]", "y", "0");
+ assertXPath(pXmlDoc, aBasePath + "/point[4]", "x", "99");
+ assertXPath(pXmlDoc, aBasePath + "/point[4]", "y", "0");
+ assertXPath(pXmlDoc, aBasePath + "/point[5]", "x", "99");
+ assertXPath(pXmlDoc, aBasePath + "/point[5]", "y", "99");
+
+ aBasePath = "/primitive2D/sdrrectangle/polygonstroke";
+ assertXPath(pXmlDoc, aBasePath, 1);
+
+ assertXPath(pXmlDoc, aBasePath + "/line", "color", "#3465a4");
+ assertXPath(pXmlDoc, aBasePath + "/line", "width", "0");
+ assertXPath(pXmlDoc, aBasePath + "/line", "linejoin", "Round");
+ assertXPath(pXmlDoc, aBasePath + "/line", "linecap", "BUTT");
+
+ assertXPathContent(pXmlDoc, aBasePath + "/polygon", "49.5,99 0,99 0,0 99,0 99,99");
+
+ // If solid line, then there is no line stroke information
+ assertXPath(pXmlDoc, aBasePath + "/stroke", 0);
+
+ pPage->RemoveObject(0);
+
+ SdrObject* pObject(pRectangle);
+ SdrObject::Free(pObject);
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testAutoHeightMultiColShape)
+{
+ // Given a document containing a shape that has:
+ // 1) automatic height (resize shape to fix text)
+ // 2) multiple columns (2)
+ OUString aURL
+ = m_directories.getURLFromSrc(u"svx/qa/unit/data/auto-height-multi-col-shape.pptx");
+
+ // When loading that document:
+ getComponent().set(loadFromDesktop(aURL, "com.sun.star.presentation.PresentationDocument"));
+
+ // Make sure the in-file shape height is kept, even if nominally the shape height is
+ // automatic:
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 6882
+ // - Actual : 3452
+ // i.e. the shape height was smaller than expected, leading to a 2 columns layout instead of
+ // laying out all the text in the first column.
+ // 2477601 is from slide1.xml, <a:ext cx="4229467" cy="2477601"/>.
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(
+ static_cast<sal_Int32>(o3tl::convert(2477601, o3tl::Length::emu, o3tl::Length::mm100)),
+ xShape->getSize().Height, 1);
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testFontWorks)
+{
+ OUString aURL = m_directories.getURLFromSrc(u"svx/qa/unit/data/FontWork.odg");
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.drawing.DrawingDocument");
+
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent,
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT(xDrawPagesSupplier.is());
+ uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages());
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT(xDrawPage.is());
+ uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xShape.is());
+
+ auto pDrawPage = dynamic_cast<SvxDrawPage*>(xDrawPage.get());
+ CPPUNIT_ASSERT(pDrawPage);
+ SdrPage* pSdrPage = pDrawPage->GetSdrPage();
+ xmlDocUniquePtr pXmlDoc = lcl_dumpAndParseFirstObjectWithAssert(pSdrPage);
+
+ assertXPath(pXmlDoc, "/primitive2D", 1);
+
+ assertXPath(pXmlDoc, "//scene", "projectionMode", "Perspective");
+ assertXPath(pXmlDoc, "//scene/extrude3D[1]/fill", "color", "#ff0000");
+ assertXPath(pXmlDoc, "//scene/extrude3D[1]/object3Dattributes/material", "color", "#ff0000");
+ // ODF default 50% is represented by Specular Intensity = 2^5. The relationship is not linear.
+ assertXPath(pXmlDoc, "//scene/extrude3D[1]/object3Dattributes/material", "specularIntensity",
+ "32");
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testSurfaceMetal)
+{
+ OUString aURL = m_directories.getURLFromSrc(u"svx/qa/unit/data/tdf140321_metal.odp");
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.presentation.PresentationDocument");
+
+ SdrPage* pSdrPage = getFirstDrawPageWithAssert();
+
+ xmlDocUniquePtr pXmlDoc = lcl_dumpAndParseFirstObjectWithAssert(pSdrPage);
+
+ // ODF specifies for metal = true specular color as rgb(200,200,200) and adding 15 to specularity
+ // Together with extrusion-first-light-level 67% and extrusion-specularity 80% factor is
+ // 0.67*0.8 * 200/255 = 0.42 and color #6b6b6b
+ assertXPath(pXmlDoc, "(//material)[1]", "specular", "#6b6b6b");
+ // 3D specularIntensity = 2^(50/10) + 15 = 47, with default extrusion-shininess 50%
+ assertXPath(pXmlDoc, "(//material)[1]", "specularIntensity", "47");
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testExtrusionPhong)
+{
+ OUString aURL = m_directories.getURLFromSrc(u"svx/qa/unit/data/tdf140321_phong.odp");
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.presentation.PresentationDocument");
+
+ SdrPage* pSdrPage = getFirstDrawPageWithAssert();
+
+ xmlDocUniquePtr pXmlDoc = lcl_dumpAndParseFirstObjectWithAssert(pSdrPage);
+
+ // The rendering method and normals kind were always 'Flat' without the patch.
+ assertXPath(pXmlDoc, "//scene", "shadeMode", "Phong");
+ assertXPath(pXmlDoc, "//object3Dattributes", "normalsKind", "Specific");
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testSurfaceMattePPT)
+{
+ OUString aURL = m_directories.getURLFromSrc(u"svx/qa/unit/data/tdf140321_Matte_import.ppt");
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.presentation.PresentationDocument");
+
+ SdrPage* pSdrPage = getFirstDrawPageWithAssert();
+
+ xmlDocUniquePtr pXmlDoc = lcl_dumpAndParseFirstObjectWithAssert(pSdrPage);
+
+ // The preset 'matte' sets the specularity of material to 0. But that alone does not make the
+ // rendering 'matte' in LO. To get a 'matte' effect in LO, specularity of the light need to be
+ // false in addition. To get this, first light is set off and values from first light are copied
+ // to forth light, as only first light is specular. Because first and third lights are off, the
+ // forth light is the second one in the dump. The gray color corresponding to
+ // FirstLightLevel = 38000/2^16 is #949494.
+ assertXPath(pXmlDoc, "(//material)[1]", "specular", "#000000");
+ assertXPath(pXmlDoc, "(//light)[2]", "color", "#949494");
+ // To make the second light soft, part of its intensity is moved to lights 5,6,7 and 8.
+ assertXPath(pXmlDoc, "(//light)[1]", "color", "#1e1e1e");
+ assertXPath(pXmlDoc, "(//light)[3]", "color", "#3b3b3b");
+ // The 3D property specularIntensity is not related to 'extrusion-specularity' but to
+ // 'extrusion-shininess'. specularIntensity = 2^(shininess/10), here default 32.
+ assertXPath(pXmlDoc, "(//material)[1]", "specularIntensity", "32");
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testMaterialSpecular)
+{
+ OUString aURL
+ = m_directories.getURLFromSrc(u"svx/qa/unit/data/tdf140321_material_specular.odp");
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.presentation.PresentationDocument");
+
+ SdrPage* pSdrPage = getFirstDrawPageWithAssert();
+
+ xmlDocUniquePtr pXmlDoc = lcl_dumpAndParseFirstObjectWithAssert(pSdrPage);
+ CPPUNIT_ASSERT(pXmlDoc);
+
+ // 3D specular color is derived from properties 'extrusion-specularity' and 'extrusion-first-light
+ // -level'. 3D specularIntensity is derived from property 'draw:extrusion-shininess'. Both are
+ // object properties, not scene properties. Those were wrong in various forms before the patch.
+ // Specularity = 77% * first-light-level 67% = 0.5159, which corresponds to gray color #848484.
+ assertXPath(pXmlDoc, "(//material)[1]", "specular", "#848484");
+ // extrusion-shininess 50% corresponds to 3D specularIntensity 32, use 2^(50/10).
+ assertXPath(pXmlDoc, "(//material)[1]", "specularIntensity", "32");
+ // extrusion-first-light-level 67% corresponds to gray color #ababab, use 255 * 0.67.
+ assertXPath(pXmlDoc, "(//light)[1]", "color", "#ababab");
+ // The first light is harsh, the second light soft. So the 3D scene should have 6 lights (1+1+4).
+ assertXPath(pXmlDoc, "//light", 6);
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testVideoSnapshot)
+{
+ // Given a slide with a media shape, containing a 4 sec video, red-green-blue-black being the 4
+ // seconds:
+ OUString aURL = m_directories.getURLFromSrc(u"svx/qa/unit/data/video-snapshot.pptx");
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.presentation.PresentationDocument");
+ SdrPage* pSdrPage = getFirstDrawPageWithAssert();
+ auto pSdrMediaObj = dynamic_cast<SdrMediaObj*>(pSdrPage->GetObj(0));
+
+ // When getting the red snapshot of the video:
+ Graphic aSnapshot(pSdrMediaObj->getSnapshot());
+
+ // Then make sure the color is correct:
+ const BitmapEx& rBitmap = aSnapshot.GetBitmapExRef();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: rgba[ff0000ff]
+ // - Actual : rgba[000000ff]
+ // i.e. the preview was black, not ~red; since we seeked 3 secs into the video, while PowerPoint
+ // doesn't do that.
+ CPPUNIT_ASSERT_EQUAL(Color(0xfe, 0x0, 0x0), rBitmap.GetPixelColor(0, 0));
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 321
+ // - Actual : 640
+ // i.e. ~25% crop from left and right should result in half width, but it was not reduced.
+ CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(321), rBitmap.GetSizePixel().getWidth());
+}
+
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testPageViewDrawLayerClip)
+{
+ // Given a document with 2 pages, first page footer has an off-page line shape:
+ OUString aURL = m_directories.getURLFromSrc(u"svx/qa/unit/data/page-view-draw-layer-clip.docx");
+ mxComponent = loadFromDesktop(aURL);
+
+ // When saving that document to PDF:
+ utl::TempFile aTempFile;
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
+ xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+
+ // Then make sure that line shape gets clipped:
+ SvFileStream aFile(aTempFile.GetURL(), StreamMode::READ);
+ SvMemoryStream aMemory;
+ aMemory.WriteStream(aFile);
+ std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPDFium)
+ {
+ return;
+ }
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pDoc
+ = pPDFium->openDocument(aMemory.GetData(), aMemory.GetSize(), OString());
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPage1 = pDoc->openPage(0);
+ CPPUNIT_ASSERT_EQUAL(3, pPage1->getObjectCount());
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPage2 = pDoc->openPage(1);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2
+ // - Actual : 3
+ // i.e. the 2nd page had a line shape from the first page's footer.
+ CPPUNIT_ASSERT_EQUAL(2, pPage2->getObjectCount());
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/svdraw/test_SdrTextObject.cxx b/svx/qa/unit/svdraw/test_SdrTextObject.cxx
new file mode 100644
index 000000000..218db2a52
--- /dev/null
+++ b/svx/qa/unit/svdraw/test_SdrTextObject.cxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <svx/svdotext.hxx>
+#include <rtl/ustring.hxx>
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+class SdrTextObjTest : public CppUnit::TestFixture
+{
+public:
+ void AllFamiliesCanBeRestoredFromSavedString();
+
+ CPPUNIT_TEST_SUITE(SdrTextObjTest);
+ CPPUNIT_TEST(AllFamiliesCanBeRestoredFromSavedString);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void SdrTextObjTest::AllFamiliesCanBeRestoredFromSavedString()
+{
+ std::vector<SfxStyleFamily> allFamilies{ SfxStyleFamily::Char, SfxStyleFamily::Para,
+ SfxStyleFamily::Page, SfxStyleFamily::Pseudo };
+
+ for (SfxStyleFamily family : allFamilies)
+ {
+ OUString styleName = "styleName";
+ SdrTextObj::AppendFamilyToStyleName(styleName, family);
+ SfxStyleFamily readFamily = SdrTextObj::ReadFamilyFromStyleName(styleName);
+ CPPUNIT_ASSERT_EQUAL(static_cast<int>(family), static_cast<int>(readFamily));
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SdrTextObjTest);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/svx-dialogs-test.cxx b/svx/qa/unit/svx-dialogs-test.cxx
new file mode 100644
index 000000000..32c632c99
--- /dev/null
+++ b/svx/qa/unit/svx-dialogs-test.cxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+#include <test/screenshot_test.hxx>
+#include <vcl/abstdlg.hxx>
+
+using namespace ::com::sun::star;
+
+/// Test opening a dialog in svx
+class SvxDialogsTest : public ScreenshotTest
+{
+private:
+ /// helper method to populate KnownDialogs, called in setUp(). Needs to be
+ /// written and has to add entries to KnownDialogs
+ virtual void registerKnownDialogsByID(mapType& rKnownDialogs) override;
+
+ /// dialog creation for known dialogs by ID. Has to be implemented for
+ /// each registered known dialog
+ virtual VclPtr<VclAbstractDialog> createDialogByID(sal_uInt32 nID) override;
+
+public:
+ SvxDialogsTest();
+
+ // try to open a dialog
+ void openAnyDialog();
+
+ CPPUNIT_TEST_SUITE(SvxDialogsTest);
+ CPPUNIT_TEST(openAnyDialog);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+SvxDialogsTest::SvxDialogsTest() {}
+
+void SvxDialogsTest::registerKnownDialogsByID(mapType& /*rKnownDialogs*/)
+{
+ // fill map of known dialogs
+}
+
+VclPtr<VclAbstractDialog> SvxDialogsTest::createDialogByID(sal_uInt32 /*nID*/) { return nullptr; }
+
+void SvxDialogsTest::openAnyDialog()
+{
+ /// process input file containing the UXMLDescriptions of the dialogs to dump
+ processDialogBatchFile(u"svx/qa/unit/data/svx-dialogs-test.txt");
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SvxDialogsTest);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/table.cxx b/svx/qa/unit/table.cxx
new file mode 100644
index 000000000..c68abe18b
--- /dev/null
+++ b/svx/qa/unit/table.cxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+#include <test/xmltesttools.hxx>
+
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+
+#include <drawinglayer/tools/primitive2dxmldump.hxx>
+#include <rtl/ustring.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unopage.hxx>
+#include <vcl/virdev.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sdr/table/tablecontroller.hxx>
+#include <editeng/editobj.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for svx/source/table/ code.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
+{
+protected:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ virtual void setUp() override
+ {
+ test::BootstrapFixture::setUp();
+ mxDesktop.set(frame::Desktop::create(m_xContext));
+ }
+
+ virtual void tearDown() override
+ {
+ if (mxComponent.is())
+ {
+ mxComponent->dispose();
+ }
+ test::BootstrapFixture::tearDown();
+ }
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+
+ drawinglayer::primitive2d::Primitive2DContainer
+ renderPageToPrimitives(const uno::Reference<drawing::XDrawPage>& xDrawPage);
+};
+
+drawinglayer::primitive2d::Primitive2DContainer
+Test::renderPageToPrimitives(const uno::Reference<drawing::XDrawPage>& xDrawPage)
+{
+ auto pDrawPage = dynamic_cast<SvxDrawPage*>(xDrawPage.get());
+ CPPUNIT_ASSERT(pDrawPage);
+ SdrPage* pSdrPage = pDrawPage->GetSdrPage();
+ ScopedVclPtrInstance<VirtualDevice> aVirtualDevice;
+ sdr::contact::ObjectContactOfObjListPainter aObjectContact(*aVirtualDevice,
+ { pSdrPage->GetObj(0) }, nullptr);
+ const sdr::contact::ViewObjectContact& rDrawPageVOContact
+ = pSdrPage->GetViewContact().GetViewObjectContact(aObjectContact);
+ sdr::contact::DisplayInfo aDisplayInfo;
+ drawinglayer::primitive2d::Primitive2DContainer aContainer;
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo, aContainer);
+ return aContainer;
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTableShadowBlur)
+{
+ // Given a document containing a table with a blurry shadow:
+ test::Directories aDirectories;
+ OUString aURL = aDirectories.getURLFromSrc(u"svx/qa/unit/data/table-shadow-blur.pptx");
+ getComponent() = loadFromDesktop(aURL);
+
+ // When rendering the table shadow to primitives:
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence
+ = renderPageToPrimitives(xDrawPage);
+
+ // Then make sure that the cell fill part of the shadow is excluded from blurring:
+ drawinglayer::Primitive2dXmlDump aDumper;
+ xmlDocUniquePtr pDocument = aDumper.dumpAndParse(xPrimitiveSequence);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - number of nodes is incorrect
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. the shadow itself was not transparent and that resulted in a non-transparent rendering
+ // as well, while the rendering transparency should be based on the transparency of the shadow
+ // itself and the transparency of the cell fill.
+ assertXPath(pDocument, "//objectinfo/unifiedtransparence[1]", "transparence", "80");
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testSvxTableControllerSetAttrToSelectedShape)
+{
+ // Given a document with a table shape, editing cell text:
+ getComponent() = loadFromDesktop("private:factory/simpress",
+ "com.sun.star.presentation.PresentationDocument");
+ uno::Sequence<beans::PropertyValue> aArgs
+ = { comphelper::makePropertyValue("Rows", sal_Int32(2)),
+ comphelper::makePropertyValue("Columns", sal_Int32(2)) };
+ dispatchCommand(mxComponent, ".uno:InsertTable", aArgs);
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ auto pDrawPage = dynamic_cast<SvxDrawPage*>(xDrawPage.get());
+ CPPUNIT_ASSERT(pDrawPage);
+ SdrPage* pSdrPage = pDrawPage->GetSdrPage();
+ auto pSdrObject
+ = dynamic_cast<sdr::table::SdrTableObj*>(pSdrPage->GetObj(pSdrPage->GetObjCount() - 1));
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ SdrView* pSdrView = pViewShell->GetDrawView();
+ pSdrView->SdrBeginTextEdit(pSdrObject);
+ CPPUNIT_ASSERT(pSdrView->IsTextEdit());
+ const EditTextObject& rEdit = pSdrObject->getText(0)->GetOutlinerParaObject()->GetTextObject();
+ SfxItemSet aSet(rEdit.GetParaAttribs(0));
+ auto pTableController
+ = dynamic_cast<sdr::table::SvxTableController*>(pSdrView->getSelectionController().get());
+
+ // When applying attributes which only affect the cell text, not the table shape:
+ pTableController->SetAttrToSelectedShape(aSet);
+
+ // Then make sure the text edit is not ended:
+ CPPUNIT_ASSERT(pSdrView->IsTextEdit());
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/unodraw.cxx b/svx/qa/unit/unodraw.cxx
new file mode 100644
index 000000000..d026e07bc
--- /dev/null
+++ b/svx/qa/unit/unodraw.cxx
@@ -0,0 +1,249 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <cppunit/TestAssert.h>
+
+#include <com/sun/star/drawing/GraphicExportFilter.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/text/ControlCharacter.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+#include <unotools/tempfile.hxx>
+#include <svx/unopage.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <drawinglayer/tools/primitive2dxmldump.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <test/xmltesttools.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <vcl/filter/PngImageReader.hxx>
+
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+constexpr OUStringLiteral DATA_DIRECTORY = u"/svx/qa/unit/data/";
+
+/// Tests for svx/source/unodraw/ code.
+class UnodrawTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
+{
+protected:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+};
+
+void UnodrawTest::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void UnodrawTest::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+CPPUNIT_TEST_FIXTURE(UnodrawTest, testWriterGraphicExport)
+{
+ // Load a document with a Writer picture in it.
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "unodraw-writer-image.odt";
+ mxComponent = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<lang::XComponent> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+
+ // Export it as JPEG.
+ uno::Reference<drawing::XGraphicExportFilter> xExportFilter
+ = drawing::GraphicExportFilter::create(mxComponentContext);
+ // This resulted in a css::lang::IllegalArgumentException for a Writer
+ // picture.
+ xExportFilter->setSourceDocument(xShape);
+
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ uno::Sequence<beans::PropertyValue> aProperties(
+ comphelper::InitPropertySequence({ { "URL", uno::Any(aTempFile.GetURL()) },
+ { "MediaType", uno::Any(OUString("image/jpeg")) } }));
+ CPPUNIT_ASSERT(xExportFilter->filter(aProperties));
+}
+
+CPPUNIT_TEST_FIXTURE(UnodrawTest, testTdf93998)
+{
+ mxComponent = loadFromDesktop(m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf93998.odp");
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xDrawPagesSupplier.is());
+
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xDrawPage.is());
+
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xShape.is());
+
+ uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory();
+ uno::Reference<awt::XControlModel> xModel(
+ xFactory->createInstance("com.sun.star.awt.UnoControlDialogModel"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xModel.is());
+
+ uno::Reference<beans::XPropertySet> xModelProps(xModel, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xModelProps.is());
+
+ // This resulted in a uno::RuntimeException, assigning a shape to a dialog model's image was
+ // broken.
+ xModelProps->setPropertyValue("ImageURL", xShape->getPropertyValue("GraphicURL"));
+ uno::Reference<graphic::XGraphic> xGraphic;
+ xModelProps->getPropertyValue("Graphic") >>= xGraphic;
+ CPPUNIT_ASSERT(xGraphic.is());
+}
+
+CPPUNIT_TEST_FIXTURE(UnodrawTest, testTableShadowDirect)
+{
+ // Create an Impress document an insert a table shape.
+ mxComponent = loadFromDesktop("private:factory/simpress",
+ "com.sun.star.presentation.PresentationDocument");
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.TableShape"), uno::UNO_QUERY);
+ xShape->setPosition(awt::Point(1000, 1000));
+ xShape->setSize(awt::Size(10000, 10000));
+ uno::Reference<drawing::XDrawPagesSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPages> xDrawPages = xSupplier->getDrawPages();
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY);
+ xDrawPage->add(xShape);
+
+ // Create a red shadow on it without touching its style.
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with throwing a
+ // beans.UnknownPropertyException, as shadow-as-direct-formatting on tables were not possible.
+ xShapeProps->setPropertyValue("Shadow", uno::Any(true));
+ sal_Int32 nRed = 0xff0000;
+ xShapeProps->setPropertyValue("ShadowColor", uno::Any(nRed));
+ CPPUNIT_ASSERT(xShapeProps->getPropertyValue("ShadowColor") >>= nRed);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xff0000), nRed);
+
+ // Add text.
+ uno::Reference<table::XCellRange> xTable(xShapeProps->getPropertyValue("Model"),
+ uno::UNO_QUERY);
+ uno::Reference<text::XTextRange> xCell(xTable->getCellByPosition(0, 0), uno::UNO_QUERY);
+ xCell->setString("A1");
+
+ // Generates drawinglayer primitives for the shape.
+ auto pDrawPage = dynamic_cast<SvxDrawPage*>(xDrawPage.get());
+ CPPUNIT_ASSERT(pDrawPage);
+ SdrPage* pSdrPage = pDrawPage->GetSdrPage();
+ ScopedVclPtrInstance<VirtualDevice> aVirtualDevice;
+ sdr::contact::ObjectContactOfObjListPainter aObjectContact(*aVirtualDevice,
+ { pSdrPage->GetObj(0) }, nullptr);
+ const sdr::contact::ViewObjectContact& rDrawPageVOContact
+ = pSdrPage->GetViewContact().GetViewObjectContact(aObjectContact);
+ sdr::contact::DisplayInfo aDisplayInfo;
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence;
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo, xPrimitiveSequence);
+
+ // Check the primitives.
+ drawinglayer::Primitive2dXmlDump aDumper;
+ xmlDocUniquePtr pDocument = aDumper.dumpAndParse(xPrimitiveSequence);
+ assertXPath(pDocument, "//shadow", /*nNumberOfNodes=*/1);
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : 1
+ // i.e. there was shadow for the cell text, while here PowerPoint-compatible output is expected,
+ // which has no shadow for cell text (only for cell borders and cell background).
+ assertXPath(pDocument, "//shadow//sdrblocktext", /*nNumberOfNodes=*/0);
+}
+
+CPPUNIT_TEST_FIXTURE(UnodrawTest, testTitleShapeBullets)
+{
+ // Create a title shape with 2 paragraphs in it.
+ mxComponent = loadFromDesktop("private:factory/simpress",
+ "com.sun.star.presentation.PresentationDocument");
+ uno::Reference<drawing::XDrawPagesSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPages> xDrawPages = xSupplier->getDrawPages();
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY);
+ // A default document contains a title shape and a text shape on the first slide.
+ uno::Reference<drawing::XShape> xTitleShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<lang::XServiceInfo> xTitleShapeInfo(xTitleShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xTitleShapeInfo->supportsService("com.sun.star.presentation.TitleTextShape"));
+ uno::Reference<text::XTextRange> xTitleShapeText(xTitleShape, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTitleShapeText->getText();
+ uno::Reference<text::XTextRange> xCursor = xText->createTextCursor();
+ xText->insertString(xCursor, "foo", /*bAbsorb=*/false);
+ xText->insertControlCharacter(xCursor, text::ControlCharacter::APPEND_PARAGRAPH,
+ /*bAbsorb=*/false);
+ xText->insertString(xCursor, "bar", /*bAbsorb=*/false);
+
+ // Check that the title shape has 2 paragraphs.
+ uno::Reference<container::XEnumerationAccess> xTextEA(xText, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xTextE = xTextEA->createEnumeration();
+ // Has a first paragraph.
+ CPPUNIT_ASSERT(xTextE->hasMoreElements());
+ xTextE->nextElement();
+ // Has a second paragraph.
+ // Without the accompanying fix in place, this test would have failed, because the 2 paragraphs
+ // were merged together (e.g. 1 bullet instead of 2 bullets for bulleted paragraphs).
+ CPPUNIT_ASSERT(xTextE->hasMoreElements());
+}
+
+CPPUNIT_TEST_FIXTURE(UnodrawTest, testPngExport)
+{
+ // Given an empty Impress document:
+ mxComponent = loadFromDesktop("private:factory/simpress",
+ "com.sun.star.presentation.PresentationDocument");
+
+ // When exporting that document to PNG with a JSON size:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY_THROW);
+ SvMemoryStream aStream;
+ uno::Reference<io::XOutputStream> xOut = new utl::OOutputStreamWrapper(aStream);
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["FilterName"] <<= OUString("impress_png_Export");
+ aMediaDescriptor["FilterOptions"]
+ <<= OUString("{\"PixelHeight\":{\"type\":\"long\",\"value\":\"192\"},"
+ "\"PixelWidth\":{\"type\":\"long\",\"value\":\"192\"}}");
+ aMediaDescriptor["OutputStream"] <<= xOut;
+ xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList());
+
+ // Then make sure that the size request is handled:
+ aStream.Seek(STREAM_SEEK_TO_BEGIN);
+ vcl::PngImageReader aPngReader(aStream);
+ BitmapEx aBitmapEx;
+ aPngReader.read(aBitmapEx);
+ Size aSize = aBitmapEx.GetSizePixel();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 192
+ // - Actual : 595
+ // i.e. it was not possible to influence the size from the cmdline.
+ CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(192), aSize.getHeight());
+ CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(192), aSize.getWidth());
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/xml.cxx b/svx/qa/unit/xml.cxx
new file mode 100644
index 000000000..de16b39be
--- /dev/null
+++ b/svx/qa/unit/xml.cxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+
+#include <rtl/ustring.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for svx/source/xml/ code.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+protected:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ virtual void setUp() override
+ {
+ test::BootstrapFixture::setUp();
+ mxDesktop.set(frame::Desktop::create(m_xContext));
+ }
+
+ virtual void tearDown() override
+ {
+ if (mxComponent.is())
+ {
+ mxComponent->dispose();
+ }
+ test::BootstrapFixture::tearDown();
+ }
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+CPPUNIT_TEST_FIXTURE(Test, test3DObjectFallback)
+{
+ // Load a document which has a 3D model we don't understand, but has a fallback PNG.
+ test::Directories aDirectories;
+ OUString aURL = aDirectories.getURLFromSrc(u"svx/qa/unit/data/3d-object-fallback.odp");
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<graphic::XGraphic> xGraphic;
+ xShape->getPropertyValue("Graphic") >>= xGraphic;
+ // Without the accompanying fix in place, this test would have failed, we could not read
+ // Models/Fallbacks/duck.png, as we assumed a format like Pictures/something.png, i.e. a single
+ // slash in the path.
+ CPPUNIT_ASSERT(xGraphic.is());
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/xoutdev.cxx b/svx/qa/unit/xoutdev.cxx
new file mode 100644
index 000000000..41b460164
--- /dev/null
+++ b/svx/qa/unit/xoutdev.cxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <sal/types.h>
+#include <sfx2/app.hxx>
+#include <tools/stream.hxx>
+#include <unotest/directories.hxx>
+#include <unotools/tempfile.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <svx/xoutbmp.hxx>
+#include <vcl/filter/PDFiumLibrary.hxx>
+
+using namespace com::sun::star;
+
+class XOutdevTest : public test::BootstrapFixture, public unotest::MacrosTest
+{
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ virtual void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void XOutdevTest::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void XOutdevTest::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+CPPUNIT_TEST_FIXTURE(XOutdevTest, testPdfGraphicExport)
+{
+ auto pPdfium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPdfium)
+ {
+ return;
+ }
+
+ // Import the graphic.
+ Graphic aGraphic;
+ test::Directories aDirectories;
+ OUString aURL = aDirectories.getURLFromSrc(u"svx/qa/unit/data/graphic.pdf");
+ SvFileStream aStream(aURL, StreamMode::READ);
+ CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE,
+ GraphicFilter::GetGraphicFilter().ImportGraphic(aGraphic, aURL, aStream));
+
+ // Export it.
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ XOutFlags const eFlags = XOutFlags::DontExpandFilename | XOutFlags::DontAddExtension
+ | XOutFlags::UseNativeIfPossible;
+ OUString aTempURL = aTempFile.GetURL();
+ XOutBitmap::WriteGraphic(aGraphic, aTempURL, "pdf", eFlags);
+
+ // Assert that the output looks like a PDF.
+ SvStream* pStream = aTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream->TellEnd() > 5);
+ sal_uInt8 sFirstBytes[5];
+ pStream->ReadBytes(sFirstBytes, 5);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('%'), sFirstBytes[0]);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('P'), sFirstBytes[1]);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('D'), sFirstBytes[2]);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('F'), sFirstBytes[3]);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('-'), sFirstBytes[4]);
+}
+
+CPPUNIT_TEST_FIXTURE(XOutdevTest, testTdf60684)
+{
+ Graphic aGraphic;
+ test::Directories aDirectories;
+ OUString aURL = aDirectories.getURLFromSrc(u"svx/qa/unit/data/tdf60684.jpg");
+ SvFileStream aStream(aURL, StreamMode::READ);
+ CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE,
+ GraphicFilter::GetGraphicFilter().ImportGraphic(aGraphic, aURL, aStream));
+
+ // Export it.
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ XOutFlags const eFlags = XOutFlags::DontExpandFilename | XOutFlags::DontAddExtension
+ | XOutFlags::UseNativeIfPossible;
+ OUString aTempURL = aTempFile.GetURL();
+ XOutBitmap::WriteGraphic(aGraphic, aTempURL, "png", eFlags);
+
+ SvStream* pStream = aTempFile.GetStream(StreamMode::READ);
+ CPPUNIT_ASSERT(pStream->TellEnd() > 4);
+ sal_uInt8 sFirstBytes[4];
+ pStream->ReadBytes(sFirstBytes, 4);
+
+ //Checks if the file's header matches a PNG's expected header
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('P'), sFirstBytes[1]);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('N'), sFirstBytes[2]);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('G'), sFirstBytes[3]);
+}
+
+CPPUNIT_TEST_FIXTURE(XOutdevTest, testFillColorThemeUnoApi)
+{
+ // Given an empty Impress document with a (title) shape:
+ getComponent() = loadFromDesktop("private:factory/simpress",
+ "com.sun.star.presentation.PresentationDocument");
+
+ // When setting the theme index of the shape's fill color:
+ uno::Reference<drawing::XDrawPagesSupplier> xPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xPage(xPagesSupplier->getDrawPages()->getByIndex(0),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xShape(xPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int16 nExpected = 4; // Accent 1
+ xShape->setPropertyValue("FillColorTheme", uno::Any(nExpected));
+
+ // 80% lighter
+ sal_Int16 nExpectedLumMod = 2000;
+ xShape->setPropertyValue("FillColorLumMod", uno::Any(nExpectedLumMod));
+ sal_Int16 nExpectedLumOff = 8000;
+ xShape->setPropertyValue("FillColorLumOff", uno::Any(nExpectedLumOff));
+
+ // Then make sure the value we read back is the expected one:
+ sal_Int16 nActual = -1;
+ xShape->getPropertyValue("FillColorTheme") >>= nActual;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 4
+ // - Actual : -1
+ // i.e. setting the value was broken.
+ CPPUNIT_ASSERT_EQUAL(nExpected, nActual);
+ xShape->getPropertyValue("FillColorLumMod") >>= nActual;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2000
+ // - Actual : 8000
+ // i.e. FillColorLumOff was set as FillColor, then getting FillColorLumMod returned FillColor.
+ CPPUNIT_ASSERT_EQUAL(nExpectedLumMod, nActual);
+ xShape->getPropertyValue("FillColorLumOff") >>= nActual;
+ CPPUNIT_ASSERT_EQUAL(nExpectedLumOff, nActual);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unoapi/knownissues.xcl b/svx/qa/unoapi/knownissues.xcl
new file mode 100644
index 000000000..e5d4b3a17
--- /dev/null
+++ b/svx/qa/unoapi/knownissues.xcl
@@ -0,0 +1,108 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+### i85263 ###
+svx.SvxShape::com::sun::star::drawing::TextProperties::TextWritingMode
+svx.SvxShapeConnector::com::sun::star::drawing::TextProperties::TextWritingMode
+# -> disabled in svx.sce
+
+### i46736 ###
+svx.AccessibleImageBullet
+# -> disabled in svx.sce
+
+### i85501 ###
+svx.SvxGraphCtrlAccessibleContext
+# -> disabled in svx.sce
+
+### i85539 ###
+svx.AccessiblePresentationShape
+# -> disabled in svx.sce
+
+### i85476 ###
+svx.SvxUnoText::com::sun::star::text::XTextRangeMover
+
+### i85478 ###
+svx.SvxUnoTextRange::com::sun::star::text::XTextRange
+
+### i35965 ###
+svx.SvxGraphCtrlAccessibleContext::com::sun::star::accessibility::XAccessibleEventBroadcaster
+
+### i85479 ###
+svx.AccessiblePageShape::com::sun::star::accessibility::XAccessibleEventBroadcaster
+
+### i85481 ###
+svx.SvxUnoTextCursor::com::sun::star::beans::XMultiPropertyStates
+
+### i58108 ###
+svx.SvxUnoText::com::sun::star::text::XTextRangeCompare
+
+### i38623 ###
+svx.SvxUnoTextCursor::com::sun::star::text::XTextRange
+
+### i73993 ###
+svx.SvxUnoTextContent::com::sun::star::style::ParagraphProperties
+svx.SvxUnoTextCursor::com::sun::star::style::ParagraphProperties
+svx.SvxUnoTextRange::com::sun::star::style::ParagraphProperties
+svx.SvxGraphicObject::com::sun::star::style::ParagraphProperties
+svx.SvxShape::com::sun::star::style::ParagraphProperties
+svx.SvxShapeCircle::com::sun::star::style::ParagraphProperties
+svx.SvxShapeConnector::com::sun::star::style::ParagraphProperties
+svx.SvxShapeDimensioning::com::sun::star::style::ParagraphProperties
+svx.SvxShapePolyPolygon::com::sun::star::style::ParagraphProperties
+svx.SvxShapePolyPolygonBezier::com::sun::star::style::ParagraphProperties
+
+### i23461 ###
+svx.SvxDrawPage::com::sun::star::drawing::XMasterPageTarget
+
+### i85485 ###
+svx.SvxShapeDimensioning::com::sun::star::drawing::XShape
+
+### i58125 ###
+svx.SvxGraphicObject::com::sun::star::drawing::GraphicObjectShape
+
+### i87698 ###
+svx.SvxShapeDimensioning::com::sun::star::drawing::TextProperties
+
+### i87746 ###
+svx.SvxGraphicObject
+svx.SvxShapeCircle
+svx.SvxShapeControl
+svx.SvxShapeDimensioning
+svx.SvxShapeGroup
+svx.SvxShapePolyPolygon
+svx.SvxShapePolyPolygonBezier
+
+### i88543 ###
+svx.SvxUnoTextRange::com::sun::star::beans::XPropertySet
+
+### i90294 ###
+svx.GraphicExporter
+# -> disabled in svx.sce
+
+### i98339 ###
+svx.AccessibleControlShape
+# -> disabled in svx.sce
+
+### i111114 ###
+svx.AccessiblePresentationOLEShape::com::sun::star::accessibility::XAccessibleComponent
+
+### i111169 ###
+svx.AccessiblePageShape::com::sun::star::accessibility::XAccessibleComponent
+
+### i114642 ###
+svx.SvxUnoTextContent::com::sun::star::style::CharacterProperties
diff --git a/svx/qa/unoapi/svx.sce b/svx/qa/unoapi/svx.sce
new file mode 100644
index 000000000..1c3925f58
--- /dev/null
+++ b/svx/qa/unoapi/svx.sce
@@ -0,0 +1,49 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+#i98339 -o svx.AccessibleControlShape
+#i111278 -o svx.AccessibleEditableTextPara
+#i111252 -o svx.AccessibleGraphicShape
+#i46736 -o svx.AccessibleImageBullet
+#i111252 -o svx.AccessibleOLEShape
+#i111252 -o svx.AccessiblePageShape
+#i111216 -o svx.AccessiblePresentationGraphicShape
+#i111216 -o svx.AccessiblePresentationOLEShape
+#i85539 -o svx.AccessiblePresentationShape
+-o svx.AccessibleShape
+#i90294 -o svx.GraphicExporter
+-o svx.SvxDrawPage
+#i85501 -o svx.SvxGraphCtrlAccessibleContext
+#i87746 -o svx.SvxGraphicObject
+#i85263 -o svx.SvxShape
+#i87746 -o svx.SvxShapeCircle
+-o svx.SvxShapeCollection
+#i85263 -o svx.SvxShapeConnector
+#i87746 -o svx.SvxShapeControl
+#i87746 -o svx.SvxShapeDimensioning
+#i87746 -o svx.SvxShapeGroup
+#i87746 -o svx.SvxShapePolyPolygon
+#i87746 -o svx.SvxShapePolyPolygonBezier
+-o svx.SvxUnoNumberingRules
+-o svx.SvxUnoText
+-o svx.SvxUnoTextContent
+-o svx.SvxUnoTextContentEnum
+-o svx.SvxUnoTextCursor
+-o svx.SvxUnoTextField
+-o svx.SvxUnoTextRange
+-o svx.SvxUnoTextRangeEnumeration
diff --git a/svx/qa/unoapi/testdocuments/SvxShape.sxd b/svx/qa/unoapi/testdocuments/SvxShape.sxd
new file mode 100644
index 000000000..27f06d541
--- /dev/null
+++ b/svx/qa/unoapi/testdocuments/SvxShape.sxd
Binary files differ
diff --git a/svx/qa/unoapi/testdocuments/crazy-blue.jpg b/svx/qa/unoapi/testdocuments/crazy-blue.jpg
new file mode 100644
index 000000000..001c88b63
--- /dev/null
+++ b/svx/qa/unoapi/testdocuments/crazy-blue.jpg
Binary files differ
diff --git a/svx/qa/unoapi/testdocuments/space-metal.jpg b/svx/qa/unoapi/testdocuments/space-metal.jpg
new file mode 100644
index 000000000..d23344389
--- /dev/null
+++ b/svx/qa/unoapi/testdocuments/space-metal.jpg
Binary files differ
diff --git a/svx/sdi/fmslots.sdi b/svx/sdi/fmslots.sdi
new file mode 100644
index 000000000..d1dd4fdb4
--- /dev/null
+++ b/svx/sdi/fmslots.sdi
@@ -0,0 +1,747 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+interface Form
+{
+ SID_FM_CONFIG // ole : no, status : ?
+ []
+ SID_FM_PUSHBUTTON
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_RADIOBUTTON
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CHECKBOX
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_FIXEDTEXT
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_GROUPBOX
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_LISTBOX
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_COMBOBOX
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_NAVIGATIONBAR
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_EDIT
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_DBGRID
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_IMAGEBUTTON
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_IMAGECONTROL
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_FILECONTROL
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_DATEFIELD
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_TIMEFIELD
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_NUMERICFIELD
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CURRENCYFIELD
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_PATTERNFIELD
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_FORMATTEDFIELD
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_SCROLLBAR
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_SPINBUTTON
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CTL_PROPERTIES
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_PROPERTIES
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_TAB_DIALOG
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_ADD_FIELD
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_DESIGN_MODE
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_OPEN_READONLY
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_USE_WIZARDS
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_AUTOCONTROLFOCUS
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_SHOW_FMEXPLORER
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_SHOW_PROPERTY_BROWSER
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_SHOW_DATANAVIGATOR
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_RECORD_FIRST
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_RECORD_NEXT
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_RECORD_PREV
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_RECORD_LAST
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_RECORD_NEW
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_RECORD_DELETE
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_RECORD_ABSOLUTE
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_RECORD_TEXT
+ [
+ ]
+ SID_FM_RECORD_FROM_TEXT
+ [
+ ]
+ SID_FM_RECORD_TOTAL
+ [
+ StateMethod = GetState ;
+ ]
+ SID_FM_RECORD_SAVE
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_RECORD_UNDO
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_FORM_FILTERED
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_REMOVE_FILTER_SORT
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_SORTUP
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_SORTDOWN
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_ORDERCRIT
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_FILTER_START
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_AUTOFILTER
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_REFRESH
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_REFRESH_FORM_CONTROL
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_SEARCH
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_FILTER_NAVIGATOR
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_FILTER_EXIT
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_FILTER_EXECUTE
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+
+ SID_FM_FMEXPLORER_CONTROL
+ [
+ StateMethod = GetState ;
+ ]
+
+ SID_FM_DATANAVIGATOR_CONTROL
+ [
+ StateMethod = GetState ;
+ ]
+
+ SID_FM_FIELDS_CONTROL
+ [
+ StateMethod = GetState ;
+ ]
+
+ SID_FM_PROPERTY_CONTROL
+ [
+ StateMethod = GetState ;
+ ]
+
+ SID_FM_FILTER_NAVIGATOR_CONTROL
+ [
+ StateMethod = GetState ;
+ ]
+
+ SID_FM_SHOW_PROPERTIES
+ [
+ StateMethod = GetState ;
+ ExecMethod = Execute ;
+ ]
+
+ SID_FM_VIEW_AS_GRID
+ [
+ StateMethod = GetState ;
+ ExecMethod = Execute ;
+ ]
+}
+
+interface FormTextAttributeShell
+{
+ SID_CUT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_COPY
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_PASTE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_SELECTALL
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+
+ SID_ATTR_PARA_ADJUST
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_PARA_ADJUST_LEFT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_PARA_ADJUST_CENTER
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_PARA_ADJUST_RIGHT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_PARA_ADJUST_BLOCK
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_SET_SUPER_SCRIPT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_SET_SUB_SCRIPT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_UNDERLINE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_OVERLINE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_WEIGHT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_POSTURE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_STRIKEOUT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_SHADOWED
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_CHAR_DLG
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_PARA_DLG
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_FONT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_FONTHEIGHT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_PARA_LINESPACE_10
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_PARA_LINESPACE_15
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_PARA_LINESPACE_20
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_CONTOUR
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_CLIPBOARD_FORMAT_ITEMS
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_WORDLINEMODE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_COLOR
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_RELIEF
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_ESCAPEMENT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_SCALEWIDTH
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_KERNING
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_AUTOKERN
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_LANGUAGE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_PARA_LINESPACE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_ULSPACE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_LRSPACE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_PARA_LEFT_TO_RIGHT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_PARA_RIGHT_TO_LEFT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+
+ /**** <HACK> ****/
+ // the following is a slight hack. Problem is that the form shell needs to translate
+ // slot names/args into URL dispatch names/args. For this, the SfxSlotPool is used
+ // - it provides convenient methods for this. However, the "pool" is not really a
+ // "pool" - it only knows slots, if there is a shell on the dispatcher stack which
+ // which is responsible for this slot.
+ // So, we declare the form shell as responsible for the following slots.
+ SID_ATTR_CHAR_CJK_FONT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_CTL_FONT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_CJK_FONTHEIGHT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_CTL_FONTHEIGHT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_CJK_WEIGHT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_CTL_WEIGHT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_CJK_POSTURE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_CTL_POSTURE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_EMPHASISMARK
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_LATIN_FONT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_LATIN_FONTHEIGHT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_LATIN_LANGUAGE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_LATIN_POSTURE
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ SID_ATTR_CHAR_LATIN_WEIGHT
+ [
+ ExecMethod = ExecuteTextAttribute;
+ StateMethod = GetTextAttributeState;
+ ]
+ /**** </HACK> ****/
+}
+
+shell FmFormShell
+{
+ import FormTextAttributeShell;
+ import Form;
+
+ SID_FM_CONFIG // ole : no, status : ?
+ []
+ SID_FM_FORM_DESIGN_TOOLS
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_LEAVE_CREATE
+ [
+ ExecMethod = Execute ;
+ ]
+ SID_FM_TOGGLECONTROLFOCUS
+ [
+ ExecMethod = Execute ;
+ ]
+ SID_FM_CHANGECONTROLTYPE
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_EDIT
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_BUTTON
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_FIXEDTEXT
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_LISTBOX
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_CHECKBOX
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_RADIOBUTTON
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_GROUPBOX
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_COMBOBOX
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_IMAGEBUTTON
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_FILECONTROL
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_DATE
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_TIME
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_NUMERIC
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_CURRENCY
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_PATTERN
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_IMAGECONTROL
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_FORMATTED
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_SCROLLBAR
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_SPINBUTTON
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+ SID_FM_CONVERTTO_NAVIGATIONBAR
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+}
+
diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi
new file mode 100644
index 000000000..0336b6c2d
--- /dev/null
+++ b/svx/sdi/svx.sdi
@@ -0,0 +1,12649 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+SfxInt32Item AbsoluteRecord SID_FM_RECORD_ABSOLUTE
+(SfxInt32Item Position FN_PARAM_1)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem AddField SID_FM_ADD_FIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem AddTable SID_FM_ADDTABLE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem LineToolbox SID_DRAWTBX_LINES
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxBoolItem Polygon SID_DRAW_POLYGON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxBoolItem AlignCenter SID_OBJECT_ALIGN_CENTER
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem AlignDown SID_OBJECT_ALIGN_DOWN
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem ObjectAlignLeft SID_OBJECT_ALIGN_LEFT
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxAdjustItem Alignment SID_ATTR_PARA_ADJUST
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem AlignMiddle SID_OBJECT_ALIGN_MIDDLE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem ObjectAlignRight SID_OBJECT_ALIGN_RIGHT
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem AlignUp SID_OBJECT_ALIGN_UP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem Arc SID_DRAW_ARC
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y,SfxUInt32Item StartAngle ID_VAL_ANGLESTART,SfxUInt32Item EndAngle ID_VAL_ANGLEEND)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Assign3D SID_3D_ASSIGN
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxBoolItem AutoControlFocus SID_FM_AUTOCONTROLFOCUS
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem AutoFilter SID_FM_AUTOFILTER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem AutoFormat SID_AUTOFORMAT
+(SfxStringItem aFormatName SID_AUTOFORMAT)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxStringItem BackgroundImage SID_GALLERY_BG_BRUSH
+(SvxBrushItem Background SID_GALLERY_BG_BRUSH, SfxUInt16Item Position SID_GALLERY_BG_POS)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+
+SfxVoidItem TableStyle SID_TABLE_STYLE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+
+SfxVoidItem TableStyleSettings SID_TABLE_STYLE_SETTINGS
+(SfxBoolItem UseFirstRowStyle ID_VAL_USEFIRSTROWSTYLE,
+ SfxBoolItem UseLastRowStyle ID_VAL_USELASTROWSTYLE,
+ SfxBoolItem UseBandingRowStyle ID_VAL_USEBANDINGROWSTYLE,
+ SfxBoolItem UseFirstColumnStyle ID_VAL_USEFIRSTCOLUMNSTYLE,
+ SfxBoolItem UseLastColumnStyle ID_VAL_USELASTCOLUMNSTYLE,
+ SfxBoolItem UseBandingColumnStyle ID_VAL_USEBANDINGCOLUMNSTYLE)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem TableDesign SID_TABLEDESIGN
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SvxColorItem BackgroundColor SID_BACKGROUND_COLOR
+(SfxStringItem Color SID_ATTR_COLOR_STR, SvxColorItem BackgroundColor SID_BACKGROUND_COLOR)
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SvxColorItem TableCellBackgroundColor SID_TABLE_CELL_BACKGROUND_COLOR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SvxBrushItem BackgroundPattern SID_ATTR_BRUSH
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxBrushItem BackgroundPatternController SID_BACKGROUND_PATTERN
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem Bezier_Unfilled SID_DRAW_BEZIER_NOFILL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxStringItem BezierClose SID_BEZIER_CLOSE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxStringItem BezierConvert SID_BEZIER_CONVERT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem BezierCutLine SID_BEZIER_CUTLINE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem BezierDelete SID_BEZIER_DELETE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem BezierEdge SID_BEZIER_EDGE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem BezierEliminatePoints SID_BEZIER_ELIMINATE_POINTS
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem BezierFill SID_DRAW_BEZIER_FILL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem BezierInsert SID_BEZIER_INSERT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem BezierMove SID_BEZIER_MOVE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem BezierSmooth SID_BEZIER_SMOOTH
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem BezierSymmetric SID_BEZIER_SYMMTR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxVoidItem BezierTo SID_BEZIERTO
+(SfxUInt32Item MouseEndX ID_VAL_MOUSEEND_X,SfxUInt32Item MouseEndY ID_VAL_MOUSEEND_Y)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SfxBoolItem BmpMask SID_BMPMASK
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+SfxBoolItem BmpMaskExec SID_BMPMASK_EXEC
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+SfxBoolItem BmpMaskPipette SID_BMPMASK_PIPETTE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+SvxWeightItem Bold SID_ATTR_CHAR_WEIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxWeightItem BoldLatin SID_ATTR_CHAR_LATIN_WEIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxWeightItem BoldCJK SID_ATTR_CHAR_CJK_WEIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxWeightItem BoldCTL SID_ATTR_CHAR_CTL_WEIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxBoxInfoItem BorderInner SID_ATTR_BORDER_INNER
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxBoxItem BorderOuter SID_ATTR_BORDER_OUTER
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxBoxItem SetBorderStyle SID_ATTR_BORDER
+(SvxBoxItem OuterBorder SID_ATTR_BORDER_OUTER,SvxBoxInfoItem InnerBorder SID_ATTR_BORDER_INNER)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem BringToFront SID_FRAME_TO_TOP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem DrawCaption SID_DRAW_CAPTION
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SvxCaseMapItem CaseMap SID_ATTR_CHAR_CASEMAP
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem CenterPara SID_ATTR_PARA_ADJUST_CENTER
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ChangeCaseToFullWidth SID_TRANSLITERATE_FULLWIDTH
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ChangeCaseToHalfWidth SID_TRANSLITERATE_HALFWIDTH
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ChangeCaseToHiragana SID_TRANSLITERATE_HIRAGANA
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ChangeCaseToKatakana SID_TRANSLITERATE_KATAKANA
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ChangeCaseToSentenceCase SID_TRANSLITERATE_SENTENCE_CASE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ChangeCaseToTitleCase SID_TRANSLITERATE_TITLE_CASE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ChangeCaseToToggleCase SID_TRANSLITERATE_TOGGLE_CASE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ChangeCaseRotateCase SID_TRANSLITERATE_ROTATE_CASE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ChangeCaseToLower SID_TRANSLITERATE_LOWER
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ChangeCaseToUpper SID_TRANSLITERATE_UPPER
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem ChangeControlType SID_FM_CHANGECONTROLTYPE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SvxFontItem CharFontName SID_ATTR_CHAR_FONT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SvxFontItem CharPreviewFontName SID_ATTR_CHAR_PREVIEW_FONT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ NoRecord;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+SvxFontItem CharEndPreviewFontName SID_ATTR_CHAR_ENDPREVIEW_FONT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ NoRecord;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SvxFontItem CharFontNameLatin SID_ATTR_CHAR_LATIN_FONT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxFontItem CharFontNameCJK SID_ATTR_CHAR_CJK_FONT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxFontItem CharFontNameCTL SID_ATTR_CHAR_CTL_FONT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem Checkbox SID_INSERT_CHECKBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem CheckBox SID_FM_CHECKBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem ChooseControls SID_CHOOSE_CONTROLS
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Circle SID_DRAW_CIRCLE
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Circle_Unfilled SID_DRAW_CIRCLE_NOFILL
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem CircleArc SID_DRAW_CIRCLEARC
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y,SfxUInt32Item StartAngle ID_VAL_ANGLESTART,SfxUInt32Item EndAngle ID_VAL_ANGLEEND)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem CircleCut SID_DRAW_CIRCLECUT
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y,SfxUInt32Item StartAngle ID_VAL_ANGLESTART,SfxUInt32Item EndAngle ID_VAL_ANGLEEND)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem CircleCut_Unfilled SID_DRAW_CIRCLECUT_NOFILL
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y,SfxUInt32Item StartAngle ID_VAL_ANGLESTART,SfxUInt32Item EndAngle ID_VAL_ANGLEEND)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem CirclePie SID_DRAW_CIRCLEPIE
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y,SfxUInt32Item StartAngle ID_VAL_ANGLESTART,SfxUInt32Item EndAngle ID_VAL_ANGLEEND)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem CirclePie_Unfilled SID_DRAW_CIRCLEPIE_NOFILL
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y,SfxUInt32Item StartAngle ID_VAL_ANGLESTART,SfxUInt32Item EndAngle ID_VAL_ANGLEEND)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxVoidItem ClearOutline SID_OUTLINE_DELETEALL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Data;
+]
+
+
+SvxColorItem Color SID_ATTR_CHAR_COLOR
+(SfxStringItem Color SID_ATTR_COLOR_STR, SvxColorItem Color SID_ATTR_CHAR_COLOR, SfxInt16Item ColorThemeIndex SID_ATTR_COLOR_THEME_INDEX, SfxInt16Item ColorLumMod SID_ATTR_COLOR_LUM_MOD, SfxInt16Item ColorLumOff SID_ATTR_COLOR_LUM_OFF)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SvxColorItem CharBackColor SID_ATTR_CHAR_BACK_COLOR
+(SfxStringItem Color SID_ATTR_COLOR_STR, SvxColorItem CharBackColor SID_ATTR_CHAR_BACK_COLOR)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxBoolItem ColorControl SID_COLOR_CONTROL
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem ComboBox SID_FM_COMBOBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem NavigationBar SID_FM_NAVIGATIONBAR
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Combobox SID_INSERT_COMBOBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem Config SID_FM_CONFIG
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem FormDesignTools SID_FM_FORM_DESIGN_TOOLS
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ContourDialog SID_CONTOUR_DLG
+
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Graphic;
+]
+
+
+SfxBoolItem ContourExecute SID_CONTOUR_EXEC
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxBoolItem ControlProperties SID_FM_CTL_PROPERTIES
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToButton SID_FM_CONVERTTO_BUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToCheckBox SID_FM_CONVERTTO_CHECKBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToCombo SID_FM_CONVERTTO_COMBOBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToCurrency SID_FM_CONVERTTO_CURRENCY
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToDate SID_FM_CONVERTTO_DATE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToEdit SID_FM_CONVERTTO_EDIT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToFileControl SID_FM_CONVERTTO_FILECONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToFixed SID_FM_CONVERTTO_FIXEDTEXT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToFormatted SID_FM_CONVERTTO_FORMATTED
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToScrollBar SID_FM_CONVERTTO_SCROLLBAR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToSpinButton SID_FM_CONVERTTO_SPINBUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToGroup SID_FM_CONVERTTO_GROUPBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToImageBtn SID_FM_CONVERTTO_IMAGEBUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToImageControl SID_FM_CONVERTTO_IMAGECONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToList SID_FM_CONVERTTO_LISTBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToNumeric SID_FM_CONVERTTO_NUMERIC
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToPattern SID_FM_CONVERTTO_PATTERN
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToRadio SID_FM_CONVERTTO_RADIOBUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToTime SID_FM_CONVERTTO_TIME
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ConvertToNavigationBar SID_FM_CONVERTTO_NAVIGATIONBAR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem CreateControl SID_FM_CREATE_CONTROL
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertCurrencyField SID_INSERT_CURRENCYFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem CurrencyField SID_FM_CURRENCYFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem Dash SID_DASH
+(SfxStringItem Name ID_VAL_INDEX,SfxUInt32Item Style ID_VAL_STYLE,SfxUInt32Item Dots ID_VAL_DOTS,SfxUInt32Item DotLen ID_VAL_DOTLEN,SfxUInt32Item Dashes ID_VAL_DASHES,SfxUInt32Item DashLen ID_VAL_DASHLEN,SfxUInt32Item Distance ID_VAL_DISTANCE)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+SfxBoolItem AddDateField SID_INSERT_DATEFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem DateField SID_FM_DATEFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem DefaultBullet FN_NUM_BULLET_ON
+(SfxBoolItem On FN_PARAM_1)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Enumeration;
+]
+
+
+SfxBoolItem DeleteRecord SID_FM_RECORD_DELETE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem SwitchControlDesignMode SID_FM_DESIGN_MODE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+SfxVoidItem DistributeSelection SID_DISTRIBUTE_DLG
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem DistributeHorzLeft SID_DISTRIBUTE_HLEFT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+SfxVoidItem DistributeHorzCenter SID_DISTRIBUTE_HCENTER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+SfxVoidItem DistributeHorzDistance SID_DISTRIBUTE_HDISTANCE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+SfxVoidItem DistributeHorzRight SID_DISTRIBUTE_HRIGHT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+SfxVoidItem DistributeVertTop SID_DISTRIBUTE_VTOP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+SfxVoidItem DistributeVertCenter SID_DISTRIBUTE_VCENTER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+SfxVoidItem DistributeVertDistance SID_DISTRIBUTE_VDISTANCE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+SfxVoidItem DistributeVertBottom SID_DISTRIBUTE_VBOTTOM
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+SfxBoolItem DrawSelect SID_DRAW_SELECT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem InsertDraw SID_INSERT_DRAW
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem DSBrowserExplorer SID_DSBROWSER_EXPLORER
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Edit SID_FM_EDIT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertEdit SID_INSERT_EDIT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Ellipse SID_DRAW_ELLIPSE
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Ellipse_Unfilled SID_DRAW_ELLIPSE_NOFILL
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem EllipseCut SID_DRAW_ELLIPSECUT
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y,SfxUInt32Item StartAngle ID_VAL_ANGLESTART,SfxUInt32Item EndAngle ID_VAL_ANGLEEND)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem EllipseCut_Unfilled SID_DRAW_ELLIPSECUT_NOFILL
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y,SfxUInt32Item StartAngle ID_VAL_ANGLESTART,SfxUInt32Item EndAngle ID_VAL_ANGLEEND)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxVoidItem EnterGroup SID_ENTER_GROUP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem RegenerateDiagram SID_REGENERATE_DIAGRAM
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+SfxVoidItem EditDiagram SID_EDIT_DIAGRAM
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SvxEscapementItem Escapement SID_ATTR_CHAR_ESCAPEMENT
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxObjectItem FieldController SID_FM_FIELDS_CONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SfxBoolItem FileControl SID_FM_FILECONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertFileControl SID_INSERT_FILECONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertTreeControl SID_INSERT_TREECONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+SfxBoolItem InsertHyperlinkControl SID_INSERT_HYPERLINKCONTROL
+()
+[
+ /* flags: */
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ /* config: */
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+XFillBitmapItem FillBitmap SID_ATTR_FILL_BITMAP
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+XFillBitmapItem FillPageBitmap SID_ATTR_PAGE_BITMAP
+
+[
+ /* flags: */
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ /* config: */
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+XFillColorItem FillColor SID_ATTR_FILL_COLOR
+(SfxStringItem Color SID_ATTR_COLOR_STR, XFillColorItem FillColor SID_ATTR_FILL_COLOR, SfxInt16Item ColorThemeIndex SID_ATTR_COLOR_THEME_INDEX, SfxInt16Item ColorLumMod SID_ATTR_COLOR_LUM_MOD, SfxInt16Item ColorLumOff SID_ATTR_COLOR_LUM_OFF)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+XFillColorItem FillPageColor SID_ATTR_PAGE_COLOR
+(SfxStringItem Color SID_ATTR_COLOR_STR)
+[
+ /* flags: */
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ /* config: */
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+// FillGradientJSON is used by online: i.e. loleaflet/src/control/Control.JSDialogBuilder.js
+XFillGradientItem FillGradient SID_ATTR_FILL_GRADIENT
+(SfxStringItem FillGradientJSON SID_FILL_GRADIENT_JSON)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+// FillPageGradientJSON is used by online: i.e. loleaflet/src/control/Control.JSDialogBuilder.js
+XFillGradientItem FillPageGradient SID_ATTR_PAGE_GRADIENT
+(SfxStringItem FillPageGradientJSON SID_FILL_GRADIENT_JSON)
+[
+ /* flags: */
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ /* config: */
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+XFillHatchItem FillHatch SID_ATTR_FILL_HATCH
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+XFillHatchItem FillPageHatch SID_ATTR_PAGE_HATCH
+
+[
+ /* flags: */
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ /* config: */
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+XFillStyleItem FillStyle SID_ATTR_FILL_STYLE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+XFillStyleItem FillPageStyle SID_ATTR_PAGE_FILLSTYLE
+
+[
+ /* flags: */
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ /* config: */
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem FilterCrit SID_FM_FILTERCRIT
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxBoolItem FirstRecord SID_FM_RECORD_FIRST
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxObjectItem FmExplorerController SID_FM_FMEXPLORER_CONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SfxObjectItem FmFilterNavigatorController SID_FM_FILTER_NAVIGATOR_CONTROL
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SfxVoidItem FontDialog SID_CHAR_DLG
+(SfxStringItem Page FN_PARAM_1)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem FontEffectsDialog SID_CHAR_DLG_EFFECT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem FontPositionDialog SID_CHAR_DLG_POSITION
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxFontHeightItem FontHeight SID_ATTR_CHAR_FONTHEIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxFontHeightItem FontHeighLatin SID_ATTR_CHAR_LATIN_FONTHEIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxFontHeightItem FontHeightCJK SID_ATTR_CHAR_CJK_FONTHEIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxFontHeightItem FontHeightCTL SID_ATTR_CHAR_CTL_FONTHEIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem FontWork SID_FONTWORK
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+XFormTextAdjustItem FontWorkTextAdjust SID_FORMTEXT_ADJUST
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+XFormTextDistanceItem FontWorkTextDistance SID_FORMTEXT_DISTANCE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+XFormTextMirrorItem FontWorkTextMirror SID_FORMTEXT_MIRROR
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+XFormTextOutlineItem FontWorkTextOutline SID_FORMTEXT_OUTLINE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+XFormTextShadowItem FontWorkTextShadow SID_FORMTEXT_SHADOW
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+XFormTextShadowColorItem FontWorkTextShadowColor SID_FORMTEXT_SHDWCOLOR
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+XFormTextShadowXValItem FontWorkTextShadowXVal SID_FORMTEXT_SHDWXVAL
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+XFormTextShadowYValItem FontWorkTextShadowYVal SID_FORMTEXT_SHDWYVAL
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+XFormTextStartItem FontWorkTextStart SID_FORMTEXT_START
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+XFormTextStyleItem FontWorkTextStyle SID_FORMTEXT_STYLE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+SfxVoidItem FormatArea SID_ATTRIBUTES_AREA
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+XFormTextHideFormItem FormatFontWorkClose SID_FORMTEXT_HIDEFORM
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+SfxVoidItem FormatGroup SID_GROUP
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem FormatLine SID_ATTRIBUTES_LINE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem FormattedField SID_FM_FORMATTEDFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ScrollBar SID_FM_SCROLLBAR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem SpinButton SID_FM_SPINBUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertFormattedField SID_INSERT_FORMATTEDFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem FormatUngroup SID_UNGROUP
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem FormFilter SID_FM_FILTER_START
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxBoolItem FormFiltered SID_FM_FORM_FILTERED
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem FormFilterExecute SID_FM_FILTER_EXECUTE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem FormFilterExit SID_FM_FILTER_EXIT
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem FormFilterNavigator SID_FM_FILTER_NAVIGATOR
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxBoolItem FormProperties SID_FM_PROPERTIES
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Freeline SID_DRAW_FREELINE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Freeline_Unfilled SID_DRAW_FREELINE_NOFILL
+(SfxUInt16Item Transparence FN_PARAM_1, SfxStringItem Color FN_PARAM_2,
+ SfxUInt16Item Width FN_PARAM_3, SfxBoolItem IsSticky FN_PARAM_4,
+ SfxStringItem ShapeName SID_SHAPE_NAME)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxVoidItem Gallery SID_GALLERY
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = TRUE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxBoolItem GalleryEnableAddCopy SID_GALLERY_ENABLE_ADDCOPY
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxStringListItem GetRedoStrings SID_GETREDOSTRINGS
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxStringListItem GetUndoStrings SID_GETUNDOSTRINGS
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxVoidItem GrafAttrCrop SID_ATTR_GRAF_CROP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxInt16Item GrafBlue SID_ATTR_GRAF_BLUE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxInt16Item GrafContrast SID_ATTR_GRAF_CONTRAST
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxUInt32Item GrafGamma SID_ATTR_GRAF_GAMMA
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxInt16Item GrafGreen SID_ATTR_GRAF_GREEN
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem GrafInvert SID_ATTR_GRAF_INVERT
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxInt16Item GrafLuminance SID_ATTR_GRAF_LUMINANCE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxUInt16Item GrafMode SID_ATTR_GRAF_MODE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxInt16Item GrafRed SID_ATTR_GRAF_RED
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxUInt16Item GrafTransparence SID_ATTR_GRAF_TRANSPARENCE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem GraphicFilterInvert SID_GRFFILTER_INVERT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterMosaic SID_GRFFILTER_MOSAIC
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterPopart SID_GRFFILTER_POPART
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterPoster SID_GRFFILTER_POSTER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterRelief SID_GRFFILTER_EMBOSS
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterRemoveNoise SID_GRFFILTER_REMOVENOISE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterSepia SID_GRFFILTER_SEPIA
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterSharpen SID_GRFFILTER_SHARPEN
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterSmooth SID_GRFFILTER_SMOOTH
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterSobel SID_GRFFILTER_SOBEL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterSolarize SID_GRFFILTER_SOLARIZE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem GraphicFilterToolbox SID_GRFFILTER
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxBoolItem Grid SID_FM_DBGRID
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem GridUse SID_GRID_USE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxBoolItem GridVisible SID_GRID_VISIBLE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxBoolItem GroupBox SID_FM_GROUPBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Groupbox SID_INSERT_GROUPBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxRectangleItem HeaderFooterBorder SID_RULER_LR_MIN_MAX
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SfxBoolItem HelplinesMove SID_HELPLINES_MOVE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxBoolItem HFixedLine SID_INSERT_HFIXEDLINE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem HScrollbar SID_INSERT_HSCROLLBAR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SvxHyperlinkItem Hyperlink SID_HYPERLINK_GETLINK
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxBoolItem Imagebutton SID_FM_IMAGEBUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ImageControl SID_FM_IMAGECONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertImageControl SID_INSERT_IMAGECONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ImageMapDialog SID_IMAP
+
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Graphic;
+]
+
+
+SfxBoolItem ImageMapExecute SID_IMAP_EXEC
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SfxVoidItem ExternalEdit SID_EXTERNAL_EDIT
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Graphic;
+]
+
+SfxVoidItem RotateLeft SID_ROTATE_GRAPHIC_LEFT
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Graphic;
+]
+SfxVoidItem Rotate180 SID_ROTATE_GRAPHIC_180
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Graphic;
+]
+SfxVoidItem RotateRight SID_ROTATE_GRAPHIC_RIGHT
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Graphic;
+]
+
+SfxVoidItem RotateReset SID_ROTATE_GRAPHIC_RESET
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Graphic;
+]
+
+SfxBoolItem Crop SID_OBJECT_CROP
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Document ;
+]
+
+SfxVoidItem ChangePicture SID_CHANGE_PICTURE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Graphic;
+]
+
+SfxVoidItem SaveGraphic SID_SAVE_GRAPHIC
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Modify;
+]
+
+SfxVoidItem CompressGraphic SID_COMPRESS_GRAPHIC
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Modify;
+]
+
+SfxVoidItem ClassificationDialog SID_CLASSIFICATION_DIALOG
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Document;
+]
+
+SfxVoidItem ParagraphClassificationDialog SID_PARAGRAPH_SIGN_CLASSIFY_DLG
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Document;
+]
+
+SfxBoolItem Init3D SID_3D_INIT
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxVoidItem InPlaceObjectResize SID_OBJECTRESIZE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+SfxVoidItem InsertAnnotation SID_INSERT_POSTIT
+(SvxPostItAuthorItem Author SID_ATTR_POSTIT_AUTHOR,SvxPostItDateItem Date SID_ATTR_POSTIT_DATE,SvxPostItTextItem Text SID_ATTR_POSTIT_TEXT)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem EditAnnotation SID_EDIT_POSTIT
+(SvxPostItIdItem Id SID_ATTR_POSTIT_ID,
+ SvxPostItAuthorItem Author SID_ATTR_POSTIT_AUTHOR,
+ SvxPostItDateItem Date SID_ATTR_POSTIT_DATE,
+ SvxPostItTextItem Text SID_ATTR_POSTIT_TEXT,
+ SfxInt32Item PositionX SID_ATTR_POSTIT_POSITION_X
+ SfxInt32Item PositionY SID_ATTR_POSTIT_POSITION_Y)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SfxVoidItem ShowAnnotations SID_TOGGLE_NOTES
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+SfxVoidItem ShowResolvedAnnotations SID_TOGGLE_RESOLVED_NOTES
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem ReplyToAnnotation SID_REPLYTO_POSTIT
+(SvxPostItIdItem Id SID_ATTR_POSTIT_ID,SvxPostItTextItem Text SID_ATTR_POSTIT_TEXT)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+
+SfxVoidItem DeleteAnnotation SID_DELETE_POSTIT
+(SvxPostItIdItem Id SID_ATTR_POSTIT_ID)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+
+SfxVoidItem DeleteAllAnnotation SID_DELETEALL_POSTIT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Document;
+]
+
+SfxVoidItem DeleteAllAnnotationByAuthor SID_DELETEALLBYAUTHOR_POSTIT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+
+SfxVoidItem NextAnnotation SID_NEXT_POSTIT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+
+SfxVoidItem PreviousAnnotation SID_PREVIOUS_POSTIT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem InsertGalleryPic SID_GALLERY_FORMATS
+(SvxGalleryItem GalleryItem SID_GALLERY_FORMATS)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxVoidItem InsertGraphic SID_INSERT_GRAPHIC
+(SfxStringItem FileName SID_INSERT_GRAPHIC,SfxStringItem FilterName FN_PARAM_FILTER,SfxBoolItem AsLink FN_PARAM_1,SfxStringItem Style FN_PARAM_2)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxVoidItem InsertMath SID_INSERT_MATH
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxBoolItem InsertMode SID_ATTR_INSERT
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxBoolItem DefaultNumbering FN_NUM_NUMBERING_ON
+(SfxBoolItem On FN_PARAM_1)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Enumeration;
+]
+
+SfxUInt16Item CurrentBulletListType FN_BUL_NUM_RULE_INDEX
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Enumeration;
+]
+SfxUInt16Item CurrentNumListType FN_NUM_NUM_RULE_INDEX
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Enumeration;
+]
+
+
+SfxVoidItem InsertObject SID_INSERT_OBJECT
+( SfxGlobalNameItem ClassId SID_INSERT_OBJECT )
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxVoidItem InsertObjectChart SID_INSERT_DIAGRAM
+(SfxBoolItem ColHeaders FN_PARAM_1,SfxBoolItem RowHeaders FN_PARAM_2,SfxBoolItem InNewTable FN_PARAM_4,SfxStringItem RangeList FN_PARAM_5)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxVoidItem InsertSymbol SID_CHARMAP
+(SfxStringItem Symbols SID_CHARMAP, SfxStringItem FontName SID_ATTR_SPECIALCHAR)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxVoidItem InsertSpreadsheet SID_ATTR_TABLE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+
+SfxUInt16Item InsertTable SID_INSERT_TABLE
+(SfxUInt16Item Columns SID_ATTR_TABLE_COLUMN,SfxUInt16Item Rows SID_ATTR_TABLE_ROW )
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxVoidItem InsertTextFrame SID_INSERT_FRAME
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxVoidItem InternetDialog SID_INET_DLG
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxVoidItem Intersect SID_POLY_INTERSECT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SvxPostureItem Italic SID_ATTR_CHAR_POSTURE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxPostureItem ItalicLatin SID_ATTR_CHAR_LATIN_POSTURE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxPostureItem ItalicCJK SID_ATTR_CHAR_CJK_POSTURE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxPostureItem ItalicCTL SID_ATTR_CHAR_CTL_POSTURE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem JustifyPara SID_ATTR_PARA_ADJUST_BLOCK
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem InsertFixedText SID_INSERT_FIXEDTEXT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Label SID_FM_FIXEDTEXT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SvxLanguageItem Language SID_ATTR_CHAR_LANGUAGE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLanguageItem LanguageLatin SID_ATTR_CHAR_LATIN_LANGUAGE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem LastRecord SID_FM_RECORD_LAST
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem LeaveFMCreateMode SID_FM_LEAVE_CREATE
+(SfxBoolItem Leave SID_FM_LEAVE_CREATE)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxVoidItem LeaveGroup SID_LEAVE_GROUP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem LeftPara SID_ATTR_PARA_ADJUST_LEFT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLRSpaceItem LeftRightMargin SID_ATTR_LRSPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLRSpaceItem LeftRightParaMargin SID_ATTR_PARA_LRSPACE
+(SvxLRSpaceItem LRSpace SID_ATTR_PARA_LRSPACE)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLRSpaceItem LeftParaMargin SID_ATTR_PARA_LEFTSPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLRSpaceItem FirstLineParaMargin SID_ATTR_PARA_FIRSTLINESPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLRSpaceItem RightParaMargin SID_ATTR_PARA_RIGHTSPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem LeftRightParaMargin_Vertical SID_ATTR_PARA_LRSPACE_VERTICAL
+(SvxLRSpaceItem LRSpace SID_ATTR_PARA_LRSPACE_VERTICAL)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem MeasureLine SID_DRAW_MEASURELINE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Line SID_DRAW_LINE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxBoolItem LineArrowCircle SID_LINE_ARROW_CIRCLE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxBoolItem LineArrowEnd SID_LINE_ARROW_END
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxBoolItem LineArrows SID_LINE_ARROWS
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxBoolItem LineArrowSquare SID_LINE_ARROW_SQUARE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxBoolItem LineArrowStart SID_LINE_ARROW_START
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxBoolItem LineCircleArrow SID_LINE_CIRCLE_ARROW
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxBoolItem LineSquareArrow SID_LINE_SQUARE_ARROW
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxBoolItem Line_Diagonal SID_DRAW_XLINE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SfxVoidItem ArrowsToolbox SID_DRAWTBX_ARROWS
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SvxColorItem FrameLineColor SID_FRAME_LINECOLOR
+(SfxStringItem Color SID_ATTR_COLOR_STR, SvxColorItem FrameLineColor SID_FRAME_LINECOLOR)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Frame;
+]
+
+
+XLineDashItem LineDash SID_ATTR_LINE_DASH
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem LineEndStyle SID_ATTR_LINEEND_STYLE
+(XLineStartItem LineStart SID_ATTR_LINE_START,XLineEndItem LineEnd SID_ATTR_LINE_END,SfxUInt32Item StartWidth SID_ATTR_LINE_STARTWIDTH,SfxUInt32Item EndWidth SID_ATTR_LINE_ENDWIDTH)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLineSpacingItem LineSpacing SID_ATTR_PARA_LINESPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SvxULSpaceItem ULSpacing SID_ATTR_PARA_ULSPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxULSpaceItem AboveSpacing SID_ATTR_PARA_ABOVESPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxULSpaceItem BelowSpacing SID_ATTR_PARA_BELOWSPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLineItem LineStyle SID_FRAME_LINESTYLE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Frame;
+]
+
+// SID_ATTR_LINE_WIDTH_ARG is used by online: i.e. loleaflet/src/control/Control.JSDialogBuilder.js
+XLineWidthItem LineWidth SID_ATTR_LINE_WIDTH
+(SvxDoubleItem Width SID_ATTR_LINE_WIDTH_ARG, XLineWidthItem LineWidth SID_ATTR_LINE_WIDTH)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem ListBox SID_FM_LISTBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertListbox SID_INSERT_LISTBOX
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem Merge SID_POLY_MERGE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+
+SfxBoolItem NewRecord SID_FM_RECORD_NEW
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem NextRecord SID_FM_RECORD_NEXT
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem NumericField SID_FM_NUMERICFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertNumericField SID_INSERT_NUMERICFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem ObjectAlign SID_OBJECT_ALIGN
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ObjectBackOne SID_FRAME_DOWN
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ObjectForwardOne SID_FRAME_UP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem OpenReadOnly SID_FM_OPEN_READONLY
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem OrderCrit SID_FM_ORDERCRIT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SvxOrphansItem Orphan SID_ATTR_PARA_ORPHANS
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem OutlineBullet SID_OUTLINE_BULLET
+(SfxStringItem Page FN_PARAM_1)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxUInt16Item SetNumber FN_SVX_SET_NUMBER
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+SfxUInt16Item SetBullet FN_SVX_SET_BULLET
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+SfxVoidItem OutlineCollapse SID_OUTLINE_COLLAPSE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem OutlineCollapseAll SID_OUTLINE_COLLAPSE_ALL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem OutlineDown SID_OUTLINE_DOWN
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem OutlineExpand SID_OUTLINE_EXPAND
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem OutlineExpandAll SID_OUTLINE_EXPAND_ALL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SvxContourItem OutlineFont SID_ATTR_CHAR_CONTOUR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem OutlineFormat SID_OUTLINE_FORMAT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem OutlineLeft SID_OUTLINE_LEFT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem OutlineRight SID_OUTLINE_RIGHT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem OutlineUp SID_OUTLINE_UP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SvxFormatBreakItem Pagebreak SID_ATTR_PARA_PAGEBREAK
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxPaperBinItem PagePaperBin SID_ATTR_PAGE_PAPERBIN
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxSizeItem AttributePageSize SID_ATTR_PAGE_SIZE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxPageModelItem AttributeParaModel SID_ATTR_PARA_MODEL
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxPageItem AttributePage SID_ATTR_PAGE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxPageItem Orientation SID_ATTR_PAGE_ORIENTATION
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLongULSpaceItem PageULMargin SID_ATTR_PAGE_ULSPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLongLRSpaceItem PageLRMargin SID_ATTR_PAGE_LRSPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxAutoKernItem PairKerning SID_ATTR_CHAR_AUTOKERN
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ParagraphDialog SID_PARA_DLG
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxFormatKeepItem ParaKeepTogether SID_ATTR_PARA_KEEP
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxFormatSplitItem ParaSplit SID_ATTR_PARA_SPLIT
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem InsertPatternField SID_INSERT_PATTERNFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem PatternField SID_FM_PATTERNFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+SfxBoolItem InsertGridControl SID_INSERT_GRIDCONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+SfxBoolItem Pie SID_DRAW_PIE
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y,SfxUInt32Item StartAngle ID_VAL_ANGLESTART,SfxUInt32Item EndAngle ID_VAL_ANGLEEND)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Pie_Unfilled SID_DRAW_PIE_NOFILL
+(SfxUInt32Item CenterX ID_VAL_CENTER_X,SfxUInt32Item CenterY ID_VAL_CENTER_Y,SfxUInt32Item AxisX ID_VAL_AXIS_X,SfxUInt32Item AxisY ID_VAL_AXIS_Y,SfxUInt32Item StartAngle ID_VAL_ANGLESTART,SfxUInt32Item EndAngle ID_VAL_ANGLEEND)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Polygon_Diagonal SID_DRAW_XPOLYGON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Polygon_Diagonal_Unfilled SID_DRAW_XPOLYGON_NOFILL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Polygon_Unfilled SID_DRAW_POLYGON_NOFILL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxPointItem Position SID_ATTR_POSITION
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxBoolItem PrevRecord SID_FM_RECORD_PREV
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ProgressBar SID_INSERT_PROGRESSBAR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxObjectItem PropertyController SID_FM_PROPERTY_CONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SfxBoolItem Pushbutton SID_FM_PUSHBUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertPushbutton SID_INSERT_PUSHBUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+
+SfxBoolItem InsertFormRadio SID_INSERT_FORM_RADIO
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertFormCheck SID_INSERT_FORM_CHECK
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertFormList SID_INSERT_FORM_LIST
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertFormCombo SID_INSERT_FORM_COMBO
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+SfxBoolItem InsertFormSpin SID_INSERT_FORM_SPIN
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem InsertFormVScroll SID_INSERT_FORM_VSCROLL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+
+SfxBoolItem InsertFormHScroll SID_INSERT_FORM_HSCROLL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Radiobutton SID_INSERT_RADIOBUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem RadioButton SID_FM_RADIOBUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ReadOnlyMode SID_READONLY_MODE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxBoolItem RecFromText SID_FM_RECORD_FROM_TEXT
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem RecSave SID_FM_RECORD_SAVE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem RecSearch SID_FM_SEARCH
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Rect SID_DRAW_RECT
+(SfxUInt32Item MouseStartX ID_VAL_MOUSESTART_X, SfxUInt32Item MouseStartY ID_VAL_MOUSESTART_Y,
+ SfxUInt32Item MouseEndX ID_VAL_MOUSEEND_X, SfxUInt32Item MouseEndY ID_VAL_MOUSEEND_Y,
+ SfxUInt16Item FillTransparence FN_PARAM_1, SfxStringItem FillColor FN_PARAM_2,
+ SfxUInt16Item LineStyle FN_PARAM_3, SfxBoolItem IsSticky FN_PARAM_4,
+ SfxStringItem ShapeName SID_SHAPE_NAME)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Rect_Rounded SID_DRAW_RECT_ROUND
+(SfxUInt32Item MouseStartX ID_VAL_MOUSESTART_X,SfxUInt32Item MouseStartY ID_VAL_MOUSESTART_Y,SfxUInt32Item MouseEndX ID_VAL_MOUSEEND_X,SfxUInt32Item MouseEndY ID_VAL_MOUSEEND_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Rect_Rounded_Unfilled SID_DRAW_RECT_ROUND_NOFILL
+(SfxUInt32Item MouseStartX ID_VAL_MOUSESTART_X,SfxUInt32Item MouseStartY ID_VAL_MOUSESTART_Y,SfxUInt32Item MouseEndX ID_VAL_MOUSEEND_X,SfxUInt32Item MouseEndY ID_VAL_MOUSEEND_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Rect_Unfilled SID_DRAW_RECT_NOFILL
+(SfxUInt32Item MouseStartX ID_VAL_MOUSESTART_X,SfxUInt32Item MouseStartY ID_VAL_MOUSESTART_Y,SfxUInt32Item MouseEndX ID_VAL_MOUSEEND_X,SfxUInt32Item MouseEndY ID_VAL_MOUSEEND_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem RecText SID_FM_RECORD_TEXT
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxStringItem RecTotal SID_FM_RECORD_TOTAL
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem RecUndo SID_FM_RECORD_UNDO
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem Refresh SID_FM_REFRESH
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem RefreshFormControl SID_FM_REFRESH_FORM_CONTROL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem RefreshView SID_REFRESH_VIEW
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+SfxVoidItem RemoveFilterSort SID_FM_REMOVE_FILTER_SORT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem ReplaceSet FID_SEARCH_REPLACESET
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxBoolItem RightPara SID_ATTR_PARA_ADJUST_RIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLRSpaceItem RulerBorderDistance SID_RULER_BORDER_DISTANCE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SvxColumnItem RulerBorders SID_RULER_BORDERS
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SvxColumnItem RulerBordersVertical SID_RULER_BORDERS_VERTICAL
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxPointItem RulerNullOffset SID_RULER_NULL_OFFSET
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SvxPagePosSizeItem RulerPagePos SID_RULER_PAGE_POS
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SvxProtectItem RulerProtect SID_RULER_PROTECT
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
+SfxVoidItem RulerChangeState SID_RULER_CHANGE_STATE
+(SfxStringItem Margin1 SID_RULER_MARGIN1, SfxStringItem Margin2 SID_RULER_MARGIN2)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+SfxVoidItem ChangeTabStop SID_TABSTOP_ADD_OR_CHANGE
+ (SfxInt32Item Index SID_TABSTOP_ATTR_INDEX,
+ SfxInt32Item Position SID_TABSTOP_ATTR_POSITION,
+ SfxBoolItem Remove SID_TABSTOP_ATTR_REMOVE)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+SfxVoidItem ParagraphChangeState SID_PARAGRAPH_CHANGE_STATE
+(SfxStringItem FirstLineIndent SID_PARAGRAPH_FIRST_LINE_INDENT, SfxStringItem LeftParaIndent SID_PARAGRAPH_LEFT_INDENT, SfxStringItem RightParaIndent SID_PARAGRAPH_RIGHT_INDENT)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+SfxVoidItem TableChangeCurrentBorderPosition SID_TABLE_CHANGE_CURRENT_BORDER_POSITION
+ (SfxStringItem BorderType SID_TABLE_BORDER_TYPE,
+ SfxUInt16Item Index SID_TABLE_BORDER_INDEX,
+ SfxInt32Item Offset SID_TABLE_BORDER_OFFSET)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+SfxVoidItem SbaExecuteSql SID_FM_EXECUTE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem SbaNativeSql SID_FM_NATIVESQL
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem Scan SID_SCAN
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxVoidItem ScEditOptions SID_SC_EDITOPTIONS
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = TRUE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxVoidItem SchEditOptions SID_SCH_EDITOPTIONS
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = TRUE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxVoidItem SdEditOptions SID_SD_EDITOPTIONS
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = TRUE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxVoidItem SdGraphicOptions SID_SD_GRAPHIC_OPTIONS
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = TRUE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxVoidItem SearchOff FID_SEARCH_OFF
+(SvxSearchItem SearchItem SID_SEARCH_ITEM)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxVoidItem SearchOn FID_SEARCH_ON
+(SvxSearchItem SearchItem SID_SEARCH_ITEM)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxVoidItem SearchSet FID_SEARCH_SEARCHSET
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxVoidItem Select SID_SELECT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxVoidItem SendToBack SID_FRAME_TO_BOTTOM
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem SetDefault SID_SET_DEFAULT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem SetHyperlink SID_HYPERLINK_SETLINK
+(SvxHyperlinkItem Hyperlink SID_HYPERLINK_SETLINK)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SvxHyphenZoneItem SetHyphenZone SID_ATTR_PARA_HYPHENZONE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxLongLRSpaceItem SetLongLeftRightMargin SID_ATTR_LONG_LRSPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SvxLongULSpaceItem SetLongTopBottomMargin SID_ATTR_LONG_ULSPACE
+(SvxLongULSpaceItem Space SID_ATTR_LONG_ULSPACE)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem SetObjectToBackground SID_OBJECT_HELL
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem SetObjectToForeground SID_OBJECT_HEAVEN
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem SetPageMaxSize SID_ATTR_PAGE_MAXSIZE
+(SvxSizeItem Size SID_ATTR_PAGE_MAXSIZE)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxShadowItem BorderShadow SID_ATTR_BORDER_SHADOW
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SdrOnOffItem FillShadow SID_ATTR_FILL_SHADOW
+
+[
+
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Document;
+]
+
+XColorItem FillShadowColor SID_ATTR_SHADOW_COLOR
+(SfxStringItem Color SID_ATTR_COLOR_STR)
+[
+
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+SdrPercentItem FillShadowTransparency SID_ATTR_SHADOW_TRANSPARENCE
+
+[
+
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+SdrMetricItem ShadowBlur SID_ATTR_SHADOW_BLUR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+SdrMetricItem FillShadowXDistance SID_ATTR_SHADOW_XDISTANCE
+
+[
+
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+SdrMetricItem FillShadowYDistance SID_ATTR_SHADOW_YDISTANCE
+
+[
+
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+SvxShadowedItem Shadowed SID_ATTR_CHAR_SHADOWED
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem ShowFmExplorer SID_FM_SHOW_FMEXPLORER
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+
+SfxBoolItem ShowPropBrowser SID_SHOW_PROPERTYBROWSER
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ShowProperties SID_FM_SHOW_PROPERTIES
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+ Asynchron;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ShowPropertyBrowser SID_FM_SHOW_PROPERTY_BROWSER
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ShowRuler SID_RULER
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SvxSizeItem Size SID_ATTR_SIZE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem SmEditOptions SID_SM_EDITOPTIONS
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = TRUE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxVoidItem SortDown SID_FM_SORTDOWN
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem Sortup SID_FM_SORTUP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxBoolItem SpacePara1 SID_ATTR_PARA_LINESPACE_10
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxBoolItem SpacePara115 SID_ATTR_PARA_LINESPACE_115
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxBoolItem SpacePara15 SID_ATTR_PARA_LINESPACE_15
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem SpacePara2 SID_ATTR_PARA_LINESPACE_20
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxKerningItem Spacing SID_ATTR_CHAR_KERNING
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem SpellOnline SID_AUTOSPELL_CHECK
+(SfxBoolItem Enable FN_PARAM_1)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxBoolItem Spinbutton SID_INSERT_SPINBUTTON
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Square SID_DRAW_SQUARE
+(SfxUInt32Item MouseStartX ID_VAL_MOUSESTART_X,SfxUInt32Item MouseStartY ID_VAL_MOUSESTART_Y,SfxUInt32Item MouseEndX ID_VAL_MOUSEEND_X,SfxUInt32Item MouseEndY ID_VAL_MOUSEEND_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Square_Rounded SID_DRAW_SQUARE_ROUND
+(SfxUInt32Item MouseStartX ID_VAL_MOUSESTART_X,SfxUInt32Item MouseStartY ID_VAL_MOUSESTART_Y,SfxUInt32Item MouseEndX ID_VAL_MOUSEEND_X,SfxUInt32Item MouseEndY ID_VAL_MOUSEEND_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Square_Rounded_Unfilled SID_DRAW_SQUARE_ROUND_NOFILL
+(SfxUInt32Item MouseStartX ID_VAL_MOUSESTART_X,SfxUInt32Item MouseStartY ID_VAL_MOUSESTART_Y,SfxUInt32Item MouseEndX ID_VAL_MOUSEEND_X,SfxUInt32Item MouseEndY ID_VAL_MOUSEEND_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Square_Unfilled SID_DRAW_SQUARE_NOFILL
+(SfxUInt32Item MouseStartX ID_VAL_MOUSESTART_X,SfxUInt32Item MouseStartY ID_VAL_MOUSESTART_Y,SfxUInt32Item MouseEndX ID_VAL_MOUSEEND_X,SfxUInt32Item MouseEndY ID_VAL_MOUSEEND_Y)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxUInt32Item State3D SID_3D_STATE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SvxCrossedOutItem Strikeout SID_ATTR_CHAR_STRIKEOUT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem SubScript SID_SET_SUB_SCRIPT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem Substract SID_POLY_SUBSTRACT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+SfxVoidItem EqualizeWidth SID_EQUALIZEWIDTH
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+SfxVoidItem EqualizeHeight SID_EQUALIZEHEIGHT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+SfxBoolItem SuperScript SID_SET_SUPER_SCRIPT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem SwEditOptions SID_SW_EDITOPTIONS
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = TRUE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxBoolItem TabDialog SID_FM_TAB_DIALOG
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SvxTabStopItem Tabstops SID_ATTR_TABSTOP
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxTabStopItem TabstopsVertical SID_ATTR_TABSTOP_VERTICAL
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem TestMode SID_DIALOG_TESTMODE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem Text SID_ATTR_CHAR
+(SfxBoolItem CreateDirectly FN_PARAM_1)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem DrawText SID_DRAW_TEXT
+(SfxBoolItem CreateDirectly FN_PARAM_1)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem Text_Marquee SID_DRAW_TEXT_MARQUEE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem TextdirectionLeftToRight SID_TEXTDIRECTION_LEFT_TO_RIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem TextdirectionTopToBottom SID_TEXTDIRECTION_TOP_TO_BOTTOM
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SdrTextFitToSizeTypeItem TextFitToSize SID_ATTR_TEXT_FITTOSIZE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem ThesaurusDialog SID_THESAURUS
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxBoolItem InsertTimeField SID_INSERT_TIMEFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem TimeField SID_FM_TIMEFIELD
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem ToggleObjectBezierMode SID_BEZIER_EDIT
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxVoidItem ToggleObjectRotateMode SID_OBJECT_ROTATE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem ToolEdit SID_TEXTEDIT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+SfxBoolItem SelectObject SID_OBJECT_SELECT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SvxULSpaceItem TopBottomMargin SID_ATTR_ULSPACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem TransformDialog SID_ATTR_TRANSFORM
+(SfxUInt32Item TransformPosX SID_ATTR_TRANSFORM_POS_X,SfxUInt32Item TransformPosY SID_ATTR_TRANSFORM_POS_Y,SfxUInt32Item TransformWidth SID_ATTR_TRANSFORM_WIDTH, SfxUInt32Item TransformHeight SID_ATTR_TRANSFORM_HEIGHT,SdrAngleItem TransformRotationDeltaAngle SID_ATTR_TRANSFORM_DELTA_ANGLE,SdrAngleItem TransformRotationAngle SID_ATTR_TRANSFORM_ANGLE,SfxUInt32Item TransformRotationX SID_ATTR_TRANSFORM_ROT_X,SfxUInt32Item TransformRotationY SID_ATTR_TRANSFORM_ROT_Y)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem MeasureAttributes SID_MEASURE_DLG
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem TwainSelect SID_TWAIN_SELECT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SfxVoidItem TwainTransfer SID_TWAIN_TRANSFER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+
+SvxUnderlineItem Underline SID_ATTR_CHAR_UNDERLINE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxOverlineItem Overline SID_ATTR_CHAR_OVERLINE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem UseWizards SID_FM_USE_WIZARDS
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem VerticalCaption SID_DRAW_CAPTION_VERTICAL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem VerticalText SID_DRAW_TEXT_VERTICAL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem VFixedLine SID_INSERT_VFIXEDLINE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ViewFormAsGrid SID_FM_VIEW_AS_GRID
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem VScrollbar SID_INSERT_VSCROLLBAR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SvxWidowsItem Widow SID_ATTR_PARA_WIDOWS
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem Window3D SID_3D_WIN
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SvxWordLineModeItem WordMode SID_ATTR_CHAR_WORDLINEMODE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+XLineColorItem XLineColor SID_ATTR_LINE_COLOR
+(SfxStringItem Color SID_ATTR_COLOR_STR, XLineColorItem XLineColor SID_ATTR_LINE_COLOR)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+XLineStyleItem XLineStyle SID_ATTR_LINE_STYLE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem Zoom100Percent SID_SIZE_REAL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem ZoomObjects SID_SIZE_OPTIMAL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem ZoomOptimal SID_SIZE_ALL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem ZoomPage SID_SIZE_PAGE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem ZoomPageWidth SID_SIZE_PAGE_WIDTH
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem ZoomVisArea SID_SIZE_VISAREA
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+SfxVoidItem ToggleControlFocus SID_FM_TOGGLECONTROLFOCUS
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem CreateFieldControl SID_FM_CREATE_FIELDCONTROL
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem SelectMode SID_INSERT_SELECT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SvxParaVertAlignItem VerticalParagraphAlignment SID_PARA_VERTALIGN
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SvxCharReliefItem CharacterRelief SID_ATTR_CHAR_RELIEF
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SvxBrushItem CharacterBackgroundPattern SID_ATTR_BRUSH_CHAR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxCharRotateItem CharacterRotation SID_ATTR_CHAR_ROTATED
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxCharScaleWidthItem CharacterWidthScalingFactor SID_ATTR_CHAR_SCALEWIDTH
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxUInt32Item NumberFormatValue SID_ATTR_NUMBERFORMAT_VALUE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxHorJustifyItem HorizontalJustification SID_ATTR_ALIGN_HOR_JUSTIFY
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxVerJustifyItem VerticalJustification SID_ATTR_ALIGN_VER_JUSTIFY
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxUInt16Item AlignmentIndent SID_ATTR_ALIGN_INDENT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem AlignmentHyphenation SID_ATTR_ALIGN_HYPHENATION
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxInt32Item AlignmentRotation SID_ATTR_ALIGN_DEGREES
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxRotateModeItem AlignmentRotationMode SID_ATTR_ALIGN_LOCKPOS
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SvxMarginItem AlignmentMargin SID_ATTR_ALIGN_MARGIN
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem AlignmentStacked SID_ATTR_ALIGN_STACKED
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem ParaLeftToRight SID_ATTR_PARA_LEFT_TO_RIGHT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem ParaRightToLeft SID_ATTR_PARA_RIGHT_TO_LEFT
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem TextRTL SID_RULER_TEXT_RIGHT_TO_LEFT
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxVoidItem OpenHyperlinkOnCursor SID_OPEN_HYPERLINK
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SfxVoidItem EditHyperlink SID_EDIT_HYPERLINK
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SfxBoolItem CTLFontState SID_CTLFONT_STATE
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Application;
+]
+
+SfxBoolItem VerticalTextState SID_VERTICALTEXT_STATE
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Application;
+]
+
+
+SfxVoidItem OpenXMLFilterSettings SID_OPEN_XML_FILTERSETTINGS
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxVoidItem HangulHanjaConversion SID_HANGUL_HANJA_CONVERSION
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+SfxVoidItem ChineseConversion SID_CHINESE_CONVERSION
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxBoolItem SpellDialog SID_SPELL_DIALOG
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SvxColumnItem RulerRows SID_RULER_ROWS
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
+SvxColumnItem RulerRowsVertical SID_RULER_ROWS_VERTICAL
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
+
+
+SfxVoidItem FontNameList SID_ATTR_CHAR_FONTLIST
+()
+[
+ // flags:
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ // config:
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+SfxBoolItem ExtrusionToggle SID_EXTRUSION_TOGGLE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxVoidItem ExtrusionTiltDown SID_EXTRUSION_TILT_DOWN
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxVoidItem ExtrusionTiltUp SID_EXTRUSION_TILT_UP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxVoidItem ExtrusionTiltLeft SID_EXTRUSION_TILT_LEFT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxVoidItem ExtrusionTiltRight SID_EXTRUSION_TILT_RIGHT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem ExtrusionDepthFloater SID_EXTRUSION_DEPTH_FLOATER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SvxDoubleItem ExtrusionDepthDialog SID_EXTRUSION_DEPTH_DIALOG
+(SvxDoubleItem Depth SID_EXTRUSION_DEPTH,SfxUInt16Item Metric SID_ATTR_METRIC)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem ExtrusionDirectionFloater SID_EXTRUSION_DIRECTION_FLOATER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem ExtrusionLightingFloater SID_EXTRUSION_LIGHTING_FLOATER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem ExtrusionSurfaceFloater SID_EXTRUSION_SURFACE_FLOATER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SvxColorItem Extrusion3DColor SID_EXTRUSION_3D_COLOR
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SvxDoubleItem ExtrusionDepth SID_EXTRUSION_DEPTH
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxInt32Item ExtrusionDirection SID_EXTRUSION_DIRECTION
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxInt32Item ExtrusionProjection SID_EXTRUSION_PROJECTION
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxInt32Item ExtrusionLightingDirection SID_EXTRUSION_LIGHTING_DIRECTION
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxInt32Item ExtrusionLightingIntensity SID_EXTRUSION_LIGHTING_INTENSITY
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxInt32Item ExtrusionSurface SID_EXTRUSION_SURFACE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem FontworkGalleryFloater SID_FONTWORK_GALLERY_FLOATER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxStringItem FontworkShapeType SID_FONTWORK_SHAPE_TYPE
+(SfxStringItem FontworkShapeType SID_FONTWORK_SHAPE_TYPE)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxBoolItem FontworkSameLetterHeights SID_FONTWORK_SAME_LETTER_HEIGHTS
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem FontworkAlignmentFloater SID_FONTWORK_ALIGNMENT_FLOATER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem FontworkCharacterSpacingFloater SID_FONTWORK_CHARACTER_SPACING_FLOATER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxInt32Item FontworkShape SID_FONTWORK_SHAPE
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxInt32Item FontworkAlignment SID_FONTWORK_ALIGNMENT
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxInt32Item FontworkCharacterSpacing SID_FONTWORK_CHARACTER_SPACING
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxInt32Item FontworkCharacterSpacingDialog SID_FONTWORK_CHARACTER_SPACING_DIALOG
+(SfxInt32Item FontworkCharacterSpacing SID_FONTWORK_CHARACTER_SPACING)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxBoolItem FontworkKernCharacterPairs SID_FONTWORK_KERN_CHARACTER_PAIRS
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+
+SfxVoidItem GetColorTable SID_GET_COLORLIST
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxVoidItem SpellCheckerChanged SID_SPELLCHECKER_CHANGED
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = TRUE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+SfxVoidItem Year2000 SID_ATTR_YEAR2000
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Intern;
+]
+
+
+SfxVoidItem IncrementIndent SID_INC_INDENT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem DecrementIndent SID_DEC_INDENT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxStringItem StateTableCell SID_TABLE_CELL
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxVoidItem SendOutlineToImpress SID_OUTLINE_TO_IMPRESS
+(SfxLockBytesItem RtfOutline SID_OUTLINE_TO_IMPRESS)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+SfxUInt16Item DefTabStop SID_ATTR_DEFTABSTOP
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SvxLanguageItem DocumentLanguage SID_ATTR_LANGUAGE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SvxLanguageItem DocumentLanguageCJK SID_ATTR_CHAR_CJK_LANGUAGE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SvxLanguageItem DocumentLanguageCTL SID_ATTR_CHAR_CTL_LANGUAGE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SfxBoolItem OptionsLocaleChanged SID_OPT_LOCALE_CHANGED
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = TRUE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+SfxVoidItem SbaBrwInsert SID_SBA_BRW_INSERT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Data;
+]
+
+
+SfxStringItem BasicShapes SID_DRAWTBX_CS_BASIC
+(SfxStringItem BasicShapes SID_DRAWTBX_CS_BASIC, SfxBoolItem CreateDirectly FN_PARAM_1)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxStringItem SymbolShapes SID_DRAWTBX_CS_SYMBOL
+(SfxStringItem SymbolShapes SID_DRAWTBX_CS_SYMBOL)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxStringItem ArrowShapes SID_DRAWTBX_CS_ARROW
+(SfxStringItem ArrowShapes SID_DRAWTBX_CS_ARROW)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxStringItem FlowChartShapes SID_DRAWTBX_CS_FLOWCHART
+(SfxStringItem FlowChartShapes SID_DRAWTBX_CS_FLOWCHART)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxStringItem CalloutShapes SID_DRAWTBX_CS_CALLOUT
+(SfxStringItem CalloutShapes SID_DRAWTBX_CS_CALLOUT)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxStringItem StarShapes SID_DRAWTBX_CS_STAR
+(SfxStringItem StarShapes SID_DRAWTBX_CS_STAR)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Options;
+]
+
+
+SfxStringItem CustomShape SID_DRAW_CS_ID
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Drawing;
+]
+
+SvxDashListItem DashListState SID_DASH_LIST
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SvxLineEndListItem LineEndListState SID_LINEEND_LIST
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SvxColorListItem ColorTableState SID_COLOR_TABLE
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SvxGradientListItem GradientListState SID_GRADIENT_LIST
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SvxHatchListItem HatchListState SID_HATCH_LIST
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SvxBitmapListItem BitmapListState SID_BITMAP_LIST
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SvxPatternListItem PatternListState SID_PATTERN_LIST
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SvxEmphasisMarkItem EmphasisMark SID_ATTR_CHAR_EMPHASISMARK
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxBoolItem ShowDataNavigator SID_FM_SHOW_DATANAVIGATOR
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxObjectItem FmDataNavigatorController SID_FM_DATANAVIGATOR_CONTROL
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = ;
+]
+
+
+SfxVoidItem CommonAlignLeft SID_ALIGN_ANY_LEFT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem CommonAlignHorizontalCenter SID_ALIGN_ANY_HCENTER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem CommonAlignRight SID_ALIGN_ANY_RIGHT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem CommonAlignJustified SID_ALIGN_ANY_JUSTIFIED
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem CommonAlignTop SID_ALIGN_ANY_TOP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem CommonAlignVerticalCenter SID_ALIGN_ANY_VCENTER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem CommonAlignBottom SID_ALIGN_ANY_BOTTOM
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem CommonAlignHorizontalDefault SID_ALIGN_ANY_HDEFAULT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem CommonAlignVerticalDefault SID_ALIGN_ANY_VDEFAULT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+avmedia_MediaItem AVMediaToolBox SID_AVMEDIA_TOOLBOX
+( avmedia_MediaItem AVMediaToolBox SID_AVMEDIA_TOOLBOX )
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Application;
+]
+
+
+
+SfxBoolItem BorderReducedMode SID_BORDER_REDUCED_MODE
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxBoolItem ColorSettings SID_COLOR_SETTINGS
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = TRUE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Modify;
+]
+
+
+SfxVoidItem MailExportFinished SID_MAIL_EXPORT_FINISHED
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Explorer;
+]
+
+SfxVoidItem InsertZWSP SID_INSERT_ZWSP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem InsertWJ SID_INSERT_WJ
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem InsertLRM SID_INSERT_LRM
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem InsertRLM SID_INSERT_RLM
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem InsertSoftHyphen FN_INSERT_SOFT_HYPHEN
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem InsertHardHyphen FN_INSERT_HARDHYPHEN
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem InsertNonBreakingSpace FN_INSERT_HARD_SPACE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem InsertNarrowNobreakSpace FN_INSERT_NNBSP
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem ManageLanguage SID_BASICIDE_MANAGE_LANG
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+
+SfxStringItem CurrentLanguage SID_BASICIDE_CURRENT_LANG
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+
+SfxVoidItem MergeCells SID_TABLE_MERGE_CELLS
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem SplitCell SID_TABLE_SPLIT_CELLS
+(SfxInt32Item Amount SID_TABLE_SPLIT_CELLS,SfxBoolItem Horizontal FN_PARAM_1, SfxBoolItem Proportional FN_PARAM_2)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem OptimizeTable SID_OPTIMIZE_TABLE
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxBoolItem CellVertBottom SID_TABLE_VERT_BOTTOM
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxBoolItem CellVertCenter SID_TABLE_VERT_CENTER
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxBoolItem CellVertTop SID_TABLE_VERT_NONE
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem InsertRows SID_TABLE_INSERT_ROW
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem InsertColumns SID_TABLE_INSERT_COL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem DeleteRows SID_TABLE_DELETE_ROW
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem DeleteColumns SID_TABLE_DELETE_COL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem DeleteTable SID_TABLE_DELETE_TABLE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem SelectTable SID_TABLE_SELECT_ALL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem EntireColumn SID_TABLE_SELECT_COL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem EntireRow SID_TABLE_SELECT_ROW
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem TableDialog SID_FORMAT_TABLE_DLG
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem AutoSum SID_TABLE_AUTOSUM
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SfxVoidItem TableSort SID_TABLE_SORT_DIALOG
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+
+SvxSmartTagItem OpenSmartTagMenuOnCursor SID_OPEN_SMARTTAGMENU
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+
+SvxZoomSliderItem ZoomSlider SID_ATTR_ZOOMSLIDER
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
+
+SfxStringListItem LanguageStatus SID_LANGUAGE_STATUS
+(SfxStringItem Language SID_LANGUAGE_STATUS)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxVoidItem FontDialogForParagraph SID_CHAR_DLG_FOR_PARAGRAPH
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxVoidItem Grow SID_GROW_FONT_SIZE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxVoidItem Shrink SID_SHRINK_FONT_SIZE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+SfxVoidItem RecheckDocument SID_RECHECK_DOCUMENT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Document;
+]
+
+
+
+SfxVoidItem InsertColumnDialog SID_TABLE_INSERT_COL_DLG
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem InsertColumnsBefore SID_TABLE_INSERT_COL_BEFORE
+()
+[
+ /* flags: */
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ /* config: */
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem InsertColumnsAfter SID_TABLE_INSERT_COL_AFTER
+()
+[
+ /* flags: */
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ /* config: */
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem InsertRowDialog SID_TABLE_INSERT_ROW_DLG
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem InsertRowsBefore SID_TABLE_INSERT_ROW_BEFORE
+()
+[
+ /* flags: */
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ /* config: */
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxVoidItem InsertRowsAfter SID_TABLE_INSERT_ROW_AFTER
+()
+[
+ /* flags: */
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ /* config: */
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Table;
+]
+
+SfxBoolItem PrepareMailExport SID_MAIL_PREPAREEXPORT
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Explorer;
+]
+
+/* TODO: SfxBoolItem or XFillUseSlideBackgroundItem ? */
+SfxBoolItem FillUseSlideBackground SID_ATTR_FILL_USE_SLIDE_BACKGROUND
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxUInt16Item FillTransparence SID_ATTR_FILL_TRANSPARENCE
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+XFillFloatTransparenceItem FillFloatTransparence SID_ATTR_FILL_FLOATTRANSPARENCE
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxUInt16Item LineTransparence SID_ATTR_LINE_TRANSPARENCE
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+
+
+
+XLineJointItem LineJoint SID_ATTR_LINE_JOINT
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+XLineCapItem LineCap SID_ATTR_LINE_CAP
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+XLineStartItem LineStart SID_ATTR_LINE_START
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+XLineEndItem LineEnd SID_ATTR_LINE_END
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxUInt32Item TransformPosX SID_ATTR_TRANSFORM_POS_X
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+
+SfxUInt32Item TransformPosY SID_ATTR_TRANSFORM_POS_Y
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+
+SfxUInt32Item TransformWidth SID_ATTR_TRANSFORM_WIDTH
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+
+SfxUInt32Item TransformHeight SID_ATTR_TRANSFORM_HEIGHT
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+
+SdrAngleItem TransformRotationAngle SID_ATTR_TRANSFORM_ANGLE
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxUInt32Item TransformRotationX SID_ATTR_TRANSFORM_ROT_X
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxUInt32Item TransformRotationY SID_ATTR_TRANSFORM_ROT_Y
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxBoolItem ProtectPos SID_ATTR_TRANSFORM_PROTECT_POS
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxBoolItem ProtectSize SID_ATTR_TRANSFORM_PROTECT_SIZE
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxVoidItem FlipHorizontal SID_FLIP_HORIZONTAL
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxVoidItem FlipVertical SID_FLIP_VERTICAL
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxBoolItem AutomaticWidth SID_ATTR_TRANSFORM_AUTOWIDTH
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+
+SfxBoolItem AutomaticHeight SID_ATTR_TRANSFORM_AUTOHEIGHT
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Special;
+]
+
+
+SvxLineItem BorderTLBR SID_ATTR_BORDER_DIAG_TLBR
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SvxLineItem BorderBLTR SID_ATTR_BORDER_DIAG_BLTR
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+
+
+SfxVoidItem FormatCellBorders SID_CELL_FORMAT_BORDER
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerItem;
+ Asynchron;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem ParaspaceDecrease SID_PARASPACE_DECREASE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem ParaspaceIncrease SID_PARASPACE_INCREASE
+()
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem SetOutline FN_SVX_SET_OUTLINE
+(SfxUInt16Item SetOutline FN_SVX_SET_OUTLINE)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Enumeration;
+]
+
+SfxUInt16Item CurrentOutlineType FN_OUTLINE_RULE_INDEX
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Enumeration;
+]
+
+SfxVoidItem HangingIndent SID_HANGING_INDENT
+
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem AnchorMenu SID_ANCHOR_MENU
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem InsertSignatureLine SID_INSERT_SIGNATURELINE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem EditSignatureLine SID_EDIT_SIGNATURELINE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SfxVoidItem SignSignatureLine SID_SIGN_SIGNATURELINE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SfxVoidItem RemoveHyperlink SID_REMOVE_HYPERLINK
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SfxVoidItem CopyHyperlinkLocation SID_COPY_HYPERLINK_LOCATION
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SfxVoidItem InsertQrCode SID_INSERT_QRCODE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem EditQrCode SID_EDIT_QRCODE
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Edit;
+]
+
+SfxVoidItem SpellCheckIgnore SID_SPELLCHECK_IGNORE
+(SfxStringItem Type FN_PARAM_1)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem SpellCheckIgnoreAll SID_SPELLCHECK_IGNORE_ALL
+(SfxStringItem Type FN_PARAM_1)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem SpellCheckApplySuggestion SID_SPELLCHECK_APPLY_SUGGESTION
+(SfxStringItem ApplyRule FN_PARAM_1)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxVoidItem GraphicSizeCheck SID_GRAPHIC_SIZE_CHECK
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Modify;
+]
+
+SfxVoidItem AccessibilityCheck SID_ACCESSIBILITY_CHECK
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Modify;
+]
+
+XColorItem GlowColor SID_ATTR_GLOW_COLOR
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+SdrMetricItem GlowRadius SID_ATTR_GLOW_RADIUS
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+SdrPercentItem GlowTransparency SID_ATTR_GLOW_TRANSPARENCY
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+SdrMetricItem SoftEdgeRadius SID_ATTR_SOFTEDGE_RADIUS
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Document;
+]
+
+SfxVoidItem MoveShapeHandle SID_MOVE_SHAPE_HANDLE
+(SfxUInt32Item HandleNum FN_PARAM_1 SfxUInt32Item NewPosX FN_PARAM_2 SfxUInt32Item NewPosY FN_PARAM_3 SfxInt32Item OrdNum FN_PARAM_4)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SfxInt16Item TextColumnsNumber SID_ATTR_TEXTCOLUMNS_NUMBER
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
+
+SdrMetricItem TextColumnsSpacing SID_ATTR_TEXTCOLUMNS_SPACING
+
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::Format;
+]
diff --git a/svx/sdi/svxitems.sdi b/svx/sdi/svxitems.sdi
new file mode 100644
index 000000000..df389994a
--- /dev/null
+++ b/svx/sdi/svxitems.sdi
@@ -0,0 +1,461 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+enum SvxCellHorJustifyEnum
+{
+ SVX_HOR_JUSTIFY_STANDARD,
+ SVX_HOR_JUSTIFY_LEFT,
+ SVX_HOR_JUSTIFY_CENTER,
+ SVX_HOR_JUSTIFY_RIGHT,
+ SVX_HOR_JUSTIFY_BLOCK,
+ SVX_HOR_JUSTIFY_REPEAT
+};
+
+enum SvxCellVerJustifyEnum
+{
+ SVX_VER_JUSTIFY_STANDARD,
+ SVX_VER_JUSTIFY_TOP,
+ SVX_VER_JUSTIFY_CENTER,
+ SVX_VER_JUSTIFY_BOTTOM
+};
+
+enum SvxCellOrientationEnum
+{
+ SVX_ORIENTATION_STANDARD,
+ SVX_ORIENTATION_TOPBOTTOM,
+ SVX_ORIENTATION_BOTTOMTOP,
+ SVX_ORIENTATION_STACKED
+};
+
+enum SvxAdjust
+{
+ SVX_ADJUST_LEFT,
+ SVX_ADJUST_RIGHT,
+ SVX_ADJUST_BLOCK,
+ SVX_ADJUST_CENTER,
+ SVX_ADJUST_BLOCKLINE,
+ SVX_ADJUST_END
+};
+
+struct SvxAdjustStruct
+{
+ SvxAdjust ParagraphAdjustment MID_PARA_ADJUST;
+ SvxAdjust LastLineAdjustment MID_LAST_LINE_ADJUST;
+ BOOL ExpandSingleWord MID_EXPAND_SINGLE;
+};
+item SvxAdjustStruct SvxAdjustItem;
+
+enum SvxCaseMap
+{
+ SVX_CASEMAP_NOT_MAPPED,
+ SVX_CASEMAP_UPPERCASE,
+ SVX_CASEMAP_LOWERCASE,
+ SVX_CASEMAP_TITLE,
+ SVX_CASEMAP_SMALLCAPS,
+ SVX_CASEMAP_END
+};
+item SvxCaseMap SvxCaseMapItem;
+
+enum CharSet
+{
+ CHARSET_DONTKNOW,
+ CHARSET_ANSI,
+ CHARSET_MAC,
+ CHARSET_IBMPC_437,
+ CHARSET_IBMPC_850,
+ CHARSET_IBMPC_860,
+ CHARSET_IBMPC_861,
+ CHARSET_IBMPC_863,
+ CHARSET_IBMPC_865,
+ CHARSET_SYSTEM,
+ CHARSET_SYMBOL
+};
+
+enum FontFamily
+{
+ FAMILY_DONTKNOW,
+ FAMILY_DECORATIVE,
+ FAMILY_MODERN,
+ FAMILY_ROMAN,
+ FAMILY_SCRIPT,
+ FAMILY_SWISS,
+ FAMILY_SYSTEM
+};
+
+enum FontPitch
+{
+ PITCH_DONTKNOW,
+ PITCH_FIXED,
+ PITCH_VARIABLE
+};
+
+struct SvxFont
+{
+ String StyleName MID_FONT_STYLE_NAME;
+ FontPitch Pitch MID_FONT_PITCH; // INT16
+ CharSet CharSet MID_FONT_CHAR_SET; // INT16
+ FontFamily Family MID_FONT_FAMILY; // INT16
+ String FamilyName MID_FONT_FAMILY_NAME;
+};
+item SvxFont SvxFontItem;
+
+enum FontWeight
+{
+ WEIGHT_DONTKNOW,
+ WEIGHT_THIN,
+ WEIGHT_ULTRALIGHT,
+ WEIGHT_LIGHT,
+ WEIGHT_SEMILIGHT,
+ WEIGHT_NORMAL,
+ WEIGHT_MEDIUM,
+ WEIGHT_SEMIBOLD,
+ WEIGHT_BOLD,
+ WEIGHT_ULTRABOLD,
+ WEIGHT_BLACK
+};
+item FontWeight SvxWeightItem;
+
+enum FontUnderline
+{
+ UNDERLINE_NONE,
+ UNDERLINE_SINGLE,
+ UNDERLINE_DOUBLE,
+ UNDERLINE_DOTTED
+};
+
+enum FontStrikeout
+{
+ STRIKEOUT_NONE,
+ STRIKEOUT_SINGLE,
+ STRIKEOUT_DOUBLE
+};
+
+enum FontItalic
+{
+ ITALIC_NONE,
+ ITALIC_OBLIQUE,
+ ITALIC_NORMAL
+};
+item FontItalic SvxPostureItem;
+
+enum SvxShadowLocation
+{
+ SVX_SHADOW_NONE,
+ SVX_SHADOW_TOPLEFT,
+ SVX_SHADOW_TOPRIGHT,
+ SVX_SHADOW_BOTTOMLEFT,
+ SVX_SHADOW_BOTTOMRIGHT,
+ SVX_SHADOW_END
+};
+item SvxShadowLocation SvxShadowLocationItem;
+
+item INT16 SvxCharScaleWidthItem;
+item INT16 SvxParaVertAlignItem;
+item INT16 SvxCharReliefItem;
+item BOOL SvxBlinkItem;
+item BOOL SvxAutoKernItem;
+item INT32 SvxColorItem;
+item BOOL SvxContourItem;
+item INT16 SvxFormatBreakItem; // enum
+item BOOL SvxFormatKeepItem;
+item BOOL SvxFormatSplitItem;
+item INT16 SvxKerningItem;
+item INT16 SvxLanguageItem;
+item BYTE SvxOrphansItem;
+item BYTE SvxPaperBinItem;
+item String SvxPostItAuthorItem;
+item String SvxPostItDateItem;
+item String SvxPostItTextItem;
+item INT32 SvxPostItIdItem;
+item FontItalic SvxPostureItem; // enum
+item BOOL SvxPrintItem;
+item UINT16 SvxPropSizeItem; // derived from UInt16Item
+item BOOL SvxShadowedItem;
+item BYTE SvxWidowsItem;
+item BOOL SvxWordLineModeItem;
+item SvxCellHorJustifyEnum SvxHorJustifyItem;
+item SvxCellVerJustifyEnum SvxVerJustifyItem;
+item SvxCellOrientationEnum SvxOrientationItem;
+item BOOL SdrOnOffItem;
+item INT32 SdrAngleItem; // derived from SfxInt32Item
+item INT16 SdrTextFitToSizeTypeItem; // enum
+item String SfxStringListItem; // serialized into one concatenated string
+item double SvxDoubleItem;
+item String OfaXColorListItem;
+item String SvxDashListItem;
+item String SvxLineEndListItem;
+item String SvxColorListItem;
+item String SvxGradientListItem;
+item String SvxHatchListItem;
+item String SvxBitmapListItem;
+item String SvxPatternListItem;
+item String SfxLockBytesItem;
+item String SvxFontListItem;
+item String avmedia_MediaItem;
+item INT32 XColorItem;
+item INT16 SdrPercentItem;
+item INT32 SdrMetricItem;
+
+item BYTE SfxGlobalNameItem;
+
+struct SvxCrossedOut
+{
+ FontStrikeout Kind MID_CROSS_OUT;
+};
+item SvxCrossedOut SvxCrossedOutItem;
+
+struct SvxTextLine
+{
+ FontUnderline LineStyle MID_TL_STYLE;
+ BOOL HasColor MID_TL_HASCOLOR;
+ INT32 Color MID_TL_COLOR;
+};
+item SvxTextLine SvxUnderlineItem;
+item SvxTextLine SvxOverlineItem;
+
+struct SvxBrush
+{
+ BOOL Transparent MID_GRAPHIC_TRANSPARENT;
+ INT32 BackColor MID_BACK_COLOR;
+ String Filtername MID_GRAPHIC_FILTER;
+ INT16 Position MID_GRAPHIC_POSITION;
+};
+item SvxBrush SvxBrushItem;
+
+struct SvxEscapement
+{
+ INT16 Escapement MID_ESC;
+ BYTE Height MID_ESC_HEIGHT;
+ BOOL Auto MID_AUTO_ESC;
+};
+item SvxEscapement SvxEscapementItem;
+
+struct SvxFontHeight
+{
+ float Height MID_FONTHEIGHT; // may be converted to INT32
+ INT16 Prop MID_FONTHEIGHT_PROP;
+ float Diff MID_FONTHEIGHT_DIFF; // may be converted to INT32
+};
+item SvxFontHeight SvxFontHeightItem;
+
+struct SvxHyphenZone
+{
+ BOOL Hyphen MID_IS_HYPHEN;
+ INT16 MinLead MID_HYPHEN_MIN_LEAD;
+ INT16 MinTrail MID_HYPHEN_MIN_TRAIL;
+ INT16 MaxHyphens MID_HYPHEN_MAX_HYPHENS;
+ INT16 MinWordLength MID_HYPHEN_MIN_WORD_LENGTH;
+ INT16 HyphenZone MID_HYPHEN_ZONE;
+};
+item SvxHyphenZone SvxHyphenZoneItem;
+
+struct SvxLine
+{
+ INT32 LineFGColor MID_FG_COLOR;
+ INT32 LineOutWidth MID_OUTER_WIDTH;
+ INT32 LineInWidth MID_INNER_WIDTH;
+ INT32 LineDistance MID_DISTANCE;
+};
+item SvxLine SvxLineItem;
+
+struct SvxLRSpace
+{
+ INT32 LeftMargin MID_L_MARGIN; // % or direct
+ INT32 TextLeftMargin MID_TXT_LMARGIN;
+ INT32 RightMargin MID_R_MARGIN; // % or direct
+ INT16 LeftRelMargin MID_L_REL_MARGIN;
+ INT16 RightRelMargin MID_R_REL_MARGIN;
+ INT32 FirstLineIndent MID_FIRST_LINE_INDENT; // % or direct
+ INT32 FirstLineRelIdent MID_FIRST_LINE_REL_INDENT;
+ BOOL AutoFirst MID_FIRST_AUTO;
+};
+item SvxLRSpace SvxLRSpaceItem;
+
+struct SvxLineSpacing
+{
+ INT16 Mode MID_LINESPACE;
+ INT16 Height MID_HEIGHT;
+};
+item SvxLineSpacing SvxLineSpacingItem;
+
+struct SvxPage
+{
+ BOOL Landscape MID_PAGE_ORIENTATION;
+ INT16 Layout MID_PAGE_LAYOUT;
+ INT16 NumType MID_PAGE_NUMTYPE;
+};
+item SvxPage SvxPageItem;
+
+struct SvxPagePosSize
+{
+ INT32 XPos MID_X; // ???
+ INT32 YPos MID_Y; // ???
+ INT32 Width MID_WIDTH; // ???
+ INT32 Height MID_HEIGHT; // ???
+};
+item SvxPagePosSize SvxPagePosSizeItem;
+
+struct SvxShadow
+{
+ SvxShadowLocation Location MID_LOCATION;
+ INT16 Width MID_WIDTH;
+ BOOL IsTransparent MID_TRANSPARENT;
+ INT32 Color MID_BG_COLOR;
+};
+item SvxShadow SvxShadowItem;
+
+struct SvxULSpace
+{
+ INT32 TopMargin MID_UP_MARGIN; // % or direct
+ INT32 BottomMargin MID_LO_MARGIN; // % or direct
+ BOOL ContextMargin MID_CTX_MARGIN;
+ INT16 TopRelMargin MID_UP_REL_MARGIN;
+ INT16 BottomRelMargin MID_LO_REL_MARGIN;
+};
+item SvxULSpace SvxULSpaceItem
+
+struct SvxLongLRSpace
+{
+ INT32 Left MID_LEFT; // ???
+ INT32 Right MID_RIGHT; // ???
+};
+item SvxLongLRSpace SvxLongLRSpaceItem;
+
+struct SvxLongULSpace
+{
+ INT32 Upper MID_UPPER; // ???
+ INT32 Lower MID_LOWER; // ???
+};
+item SvxLongULSpace SvxLongULSpaceItem;
+
+struct SvxHyperlink
+{
+ String Text MID_HLINK_TEXT;
+ String URL MID_HLINK_URL;
+ String Target MID_HLINK_TARGET;
+ String Name MID_HLINK_NAME;
+ INT32 Type MID_HLINK_TYPE;
+};
+item SvxHyperlink SvxHyperlinkItem;
+
+struct PageModel
+{
+ BOOL Auto MID_AUTO;
+ String Name MID_NAME;
+};
+item PageModel SvxPageModelItem;
+
+struct SvxProtect
+{
+ BOOL Content MID_PROTECT_CONTENT;
+ BOOL Size MID_PROTECT_SIZE;
+ BOOL Position MID_PROTECT_POSITION;
+};
+item SvxProtect SvxProtectItem;
+
+struct SvxRulerObject
+{
+ INT32 StartX MID_START_X;
+ INT32 StartY MID_START_Y;
+ INT32 EndX MID_END_X;
+ INT32 EndY MID_END_Y;
+ BOOL Limited MID_LIMIT;
+};
+item SvxRulerObject SvxObjectItem;
+
+item String LineBorder; // dummy for sequence
+struct SvxBox
+{
+ LineBorder LeftBorder MID_LEFT_BORDER;
+ INT32 LeftDistance LEFT_BORDER_DISTANCE;
+ LineBorder RightBorder MID_RIGHT_BORDER;
+ INT32 RightDistance RIGHT_BORDER_DISTANCE;
+ LineBorder TopBorder MID_TOP_BORDER;
+ INT32 TopDistance TOP_BORDER_DISTANCE;
+ LineBorder BottomBorder MID_BOTTOM_BORDER;
+ INT32 BottomDistance BOTTOM_BORDER_DISTANCE;
+};
+item SvxBox SvxBoxItem;
+
+struct SvxBoxInfo
+{
+ LineBorder Horizontal MID_HORIZONTAL;
+ LineBorder Vertical MID_VERTICAL;
+ INT16 Flags MID_FLAGS;
+ INT16 ValidFlags MID_VALIDFLAGS;
+ INT32 DefaultDistance MID_DISTANCE;
+};
+item SvxBoxInfo SvxBoxInfoItem;
+
+item String SvxColumns; // dummy for sequence
+struct SvxColumnDescription
+{
+ SvxColumns Columns MID_COLUMNARRAY; // currently not implemented
+ INT32 Left MID_LEFT;
+ INT32 Right MID_RIGHT;
+ INT32 Actual MID_ACTUAL;
+ BOOL Orthogonal MID_ORTHO;
+ BOOL Table MID_TABLE;
+};
+item SvxColumnDescription SvxColumnItem;
+
+struct SvxTabStop
+{
+ String TabStops MID_TABSTOPS; // dummy, will be represented by array of structs
+ //INT32 StandardTabStop MID_STD_TAB;
+};
+item SvxTabStop SvxTabStopItem;
+
+struct SvxCharRotate
+{
+ INT16 Rotation MID_ROTATE;
+ BOOL FitToLine MID_FITTOLINE;
+};
+item SvxCharRotate SvxCharRotateItem;
+
+item String SfxSetItem; // dummy
+item INT16 SvxRotateModeItem; // enum
+
+struct SvxMargin
+{
+ INT32 LeftMargin MID_MARGIN_L_MARGIN;
+ INT32 RightMargin MID_MARGIN_R_MARGIN;
+ INT32 UpperMargin MID_MARGIN_UP_MARGIN;
+ INT32 LowerMargin MID_MARGIN_LO_MARGIN;
+};
+item SvxMargin SvxMarginItem;
+
+struct SvxEmphasisMark
+{
+ INT32 Emphasis MID_EMPHASIS;
+};
+item SvxEmphasisMark SvxEmphasisMarkItem;
+
+item String SvxSmartTagItem; // dummy for sequence
+
+item String Points; // dummy for sequence
+struct ZoomSlider
+{
+ INT16 CurrentZoom MID_ZOOMSLIDER_CURRENTZOOM;
+ Points SnappingPoints MID_ZOOMSLIDER_SNAPPINGPOINTS;
+ INT16 SvxMinZoom MID_ZOOMSLIDER_MINZOOM;
+ INT16 SvxMaxZoom MID_ZOOMSLIDER_MAXZOOM;
+};
+item ZoomSlider SvxZoomSliderItem;
+
+item String SvxGalleryItem; // dummy for sequence
diff --git a/svx/sdi/svxslots.hrc b/svx/sdi/svxslots.hrc
new file mode 100644
index 000000000..28bc5655c
--- /dev/null
+++ b/svx/sdi/svxslots.hrc
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <sfx2/sfxsids.hrc>
+#include <editeng/memberids.h>
+#include <editeng/editids.hrc>
+#include <svx/svxids.hrc>
+#include <svx/unomid.hxx>
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/sdi/svxslots.sdi b/svx/sdi/svxslots.sdi
new file mode 100644
index 000000000..b29a9026b
--- /dev/null
+++ b/svx/sdi/svxslots.sdi
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+module
+SvxItems
+[
+SlotIdFile( "svxslots.hrc" )
+]
+{
+
+ include "sfxitems.sdi"
+ include "sfx.sdi"
+ include "svxitems.sdi"
+ include "xoitems.sdi"
+ include "svx.sdi"
+ include "fmslots.sdi"
+
+}
+
diff --git a/svx/sdi/xoitems.sdi b/svx/sdi/xoitems.sdi
new file mode 100644
index 000000000..015ead6e0
--- /dev/null
+++ b/svx/sdi/xoitems.sdi
@@ -0,0 +1,171 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+//item String XFillAttrSetItem; SfxSetItem!
+struct XFillBitmap
+{
+ String Name MID_NAME;
+// com::sun::star::awt::XBitmap
+};
+item XFillBitmap XFillBitmapItem;
+
+item INT32 XFillColorItem; // XColorItem
+
+enum SvxGradientStyle
+{
+ SVX_GRADIENTSTYLE_LINEAR,
+ SVX_GRADIENTSTYLE_AXIAL,
+ SVX_GRADIENTSTYLE_RADIAL,
+ SVX_GRADIENTSTYLE_ELLIPTICAL,
+ SVX_GRADIENTSTYLE_SQUARE,
+ SVX_GRADIENTSTYLE_RECT
+};
+
+struct XFillGradient
+{
+ String Name MID_NAME;
+ // com::sun::star::awt::Gradient
+ SvxGradientStyle Style MID_GRADIENT_STYLE;
+ INT32 StartColor MID_GRADIENT_STARTCOLOR;
+ INT32 EndColor MID_GRADIENT_ENDCOLOR;
+ INT16 Angle MID_GRADIENT_ANGLE;
+ INT16 Border MID_GRADIENT_BORDER;
+ INT16 XOffset MID_GRADIENT_XOFFSET;
+ INT16 YOffset MID_GRADIENT_YOFFSET;
+ INT16 StartIntensity MID_GRADIENT_STARTINTENSITY;
+ INT16 EndIntensity MID_GRADIENT_ENDINTENSITY;
+ INT16 StepCount MID_GRADIENT_STEPCOUNT;
+};
+item XFillGradient XFillGradientItem;
+
+enum SvxHatchStyle
+{
+ SVX_HATCHSTYLE_SINGLE,
+ SVX_HATCHSTYLE_DOUBLE,
+ SVX_HATCHSTYLE_TRIPLE
+};
+
+struct XFillHatch
+{
+ String Name MID_NAME;
+ // com::sun::star::drawing::Hatch
+ SvxHatchStyle Style MID_HATCH_STYLE;
+ INT32 Color MID_HATCH_COLOR;
+ INT32 Distance MID_HATCH_DISTANCE;
+ INT32 Angle MID_HATCH_ANGLE;
+};
+item XFillHatch XFillHatchItem;
+
+enum SvxFillStyle
+{
+ SVX_FILLSTYLE_NONE,
+ SVX_FILLSTYLE_SOLID,
+ SVX_FILLSTYLE_GRADIENT,
+ SVX_FILLSTYLE_HATCH,
+ SVX_FILLSTYLE_BITMAP
+};
+
+item SvxFillStyle XFillStyleItem;
+
+//item String XLineAttrSetItem; SfxSetItem!
+
+item INT32 XLineColorItem;
+
+enum SvxDashStyle
+{
+ SVX_DASHSTYLE_RECT,
+ SVX_DASHSTYLE_ROUND,
+ SVX_DASHSTYLE_RECTRELATIVE,
+ SVX_DASHSTYLE_ROUNDRELATIVE
+};
+
+struct XLineDash
+{
+ String Name MID_NAME;
+ // com::sun::star::drawing::LineDash
+ SvxDashStyle Style MID_LINEDASH_STYLE;
+ INT16 Dots MID_LINEDASH_DOTS;
+ INT32 DotLen MID_LINEDASH_DOTLEN;
+ INT16 Dashes MID_LINEDASH_DASHES;
+ INT32 DashLen MID_LINEDASH_DASHLEN;
+ INT32 Distance MID_LINEDASH_DISTANCE;
+};
+item XLineDash XLineDashItem;
+
+struct XLineEnd
+{
+ String Name MID_NAME;
+// com::sun::star::drawing::PolyPolygonBezierCoords
+};
+item XLineEnd XLineEndItem;
+
+struct XLineStart
+{
+ String Name MID_NAME;
+// com::sun::star::drawing::PolyPolygonBezierCoords
+};
+item XLineStart XLineStartItem;
+
+enum SvxLineStyle
+{
+ SVX_LINESTYLE_NONE,
+ SVX_LINESTYLE_SOLID,
+ SVX_LINESTYLE_DASH
+};
+item SvxLineStyle XLineStyleItem;
+
+enum SvxLineJoint
+{
+ // com::sun::star::drawing::LineJoint
+ SVX_LINEJOINT_NONE, // no rounding
+ SVX_LINEJOINT_MIDDLE, // calc middle value between joints
+ SVX_LINEJOINT_BEVEL, // join edges with line
+ SVX_LINEJOINT_MITER, // extend till cut
+ SVX_LINEJOINT_ROUND // create arc
+};
+
+item SvxLineJoint XLineJointItem;
+
+enum SvxLineCap
+{
+ // com::sun::star::drawing::LineCap
+ SVX_LINECAP_BUTT,
+ SVX_LINECAP_ROUND,
+ SVX_LINECAP_SQUARE
+};
+
+item SvxLineCap XLineCapItem;
+
+item INT32 XLineWidthItem;
+item INT32 XFormTextStyleItem;
+item INT32 XFormTextAdjustItem;
+
+item INT32 XFormTextDistanceItem; // SfxInt32Item
+item INT32 XFormTextStartItem; // SfxInt32Item
+item BOOL XFormTextMirrorItem; // SfxBoolItem
+
+item BOOL XFormTextHideFormItem; // SfxBoolItem
+item BOOL XFormTextOutlineItem; // SfxBoolItem
+item INT32 XFormTextShadowItem; // SfxEnumItem
+item INT32 XFormTextShadowColorItem; // XColorItem
+item INT32 XFormTextShadowXValItem; // SfxMetricItem/SfxInt32Item
+item INT32 XFormTextShadowYValItem; // SfxMetricItem/SfxInt32Item
+
+item XFillGradient XFillFloatTransparenceItem; // XFillGradient
+
+// eof
diff --git a/svx/source/accessibility/AccessibleControlShape.cxx b/svx/source/accessibility/AccessibleControlShape.cxx
new file mode 100644
index 000000000..45b7edd75
--- /dev/null
+++ b/svx/source/accessibility/AccessibleControlShape.cxx
@@ -0,0 +1,879 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/AccessibleControlShape.hxx>
+#include <svx/AccessibleShapeInfo.hxx>
+#include <DescriptionGenerator.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+#include <com/sun/star/util/XModeChangeBroadcaster.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/property.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <svx/IAccessibleParent.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/ShapeTypeHandler.hxx>
+#include <svx/SvxShapeTypes.hxx>
+#include <comphelper/accessiblewrapper.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/strings.hrc>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::accessibility;
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::reflection;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::container;
+
+namespace
+{
+ OUString lcl_getNamePropertyName( )
+ {
+ return "Name";
+ }
+ OUString lcl_getDescPropertyName( )
+ {
+ return "HelpText";
+ }
+ OUString lcl_getLabelPropertyName( )
+ {
+ return "Label";
+ }
+ OUString lcl_getLabelControlPropertyName( )
+ {
+ return "LabelControl";
+ }
+ // return the property which should be used as AccessibleName
+ OUString lcl_getPreferredAccNameProperty( const Reference< XPropertySetInfo >& _rxPSI )
+ {
+ if ( _rxPSI.is() && _rxPSI->hasPropertyByName( lcl_getLabelPropertyName() ) )
+ return lcl_getLabelPropertyName();
+ else
+ return lcl_getNamePropertyName();
+ }
+
+ // determines whether or not a state which belongs to the inner context needs to be forwarded to the "composed"
+ // context
+ bool isComposedState( const sal_Int16 _nState )
+ {
+ return ( ( AccessibleStateType::INVALID != _nState )
+ && ( AccessibleStateType::DEFUNC != _nState )
+ && ( AccessibleStateType::ICONIFIED != _nState )
+ && ( AccessibleStateType::RESIZABLE != _nState )
+ && ( AccessibleStateType::SELECTABLE != _nState )
+ && ( AccessibleStateType::SHOWING != _nState )
+ && ( AccessibleStateType::MANAGES_DESCENDANTS != _nState )
+ && ( AccessibleStateType::VISIBLE != _nState )
+ );
+ }
+
+ /// determines whether the given control is in alive mode
+ bool isAliveMode( const Reference< XControl >& _rxControl )
+ {
+ OSL_PRECOND( _rxControl.is(), "AccessibleControlShape::isAliveMode: invalid control" );
+ return _rxControl.is() && !_rxControl->isDesignMode();
+ }
+}
+
+AccessibleControlShape::AccessibleControlShape (
+ const AccessibleShapeInfo& rShapeInfo,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo)
+ : AccessibleShape (rShapeInfo, rShapeTreeInfo)
+ , m_bListeningForName( false )
+ , m_bListeningForDesc( false )
+ , m_bMultiplexingStates( false )
+ , m_bDisposeNativeContext( false )
+ , m_bWaitingForControl( false )
+{
+ m_pChildManager = new comphelper::OWrappedAccessibleChildrenManager( comphelper::getProcessComponentContext() );
+
+ osl_atomic_increment( &m_refCount );
+ {
+ m_pChildManager->setOwningAccessible( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+AccessibleControlShape::~AccessibleControlShape()
+{
+ m_pChildManager.clear();
+
+ if ( m_xControlContextProxy.is() )
+ m_xControlContextProxy->setDelegator( nullptr );
+ m_xControlContextProxy.clear();
+ m_xControlContextTypeAccess.clear();
+ m_xControlContextComponent.clear();
+ // this should remove the _only_ three "real" reference (means not delegated to
+ // ourself) to this proxy, and thus delete it
+}
+
+namespace {
+ Reference< XContainer > lcl_getControlContainer( const OutputDevice* _pWin, const SdrView* _pView )
+ {
+ Reference< XContainer > xReturn;
+ DBG_ASSERT( _pView, "lcl_getControlContainer: invalid view!" );
+ if ( _pView && _pView->GetSdrPageView())
+ {
+ xReturn.set(_pView->GetSdrPageView()->GetControlContainer( *_pWin ), css::uno::UNO_QUERY);
+ }
+ return xReturn;
+ }
+}
+
+void AccessibleControlShape::Init()
+{
+ AccessibleShape::Init();
+
+ OSL_ENSURE( !m_xControlContextProxy.is(), "AccessibleControlShape::Init: already initialized!" );
+ try
+ {
+ // What we need to do here is merge the functionality of the AccessibleContext of our UNO control
+ // with our own AccessibleContext-related functionality.
+
+ // The problem is that we do not know the interfaces our "inner" context supports - this may be any
+ // XAccessibleXXX interface (or even any other) which makes sense for it.
+
+ // In theory, we could implement all possible interfaces ourself, and re-route all functionality to
+ // the inner context (except those we implement ourself, like XAccessibleComponent). But this is in no
+ // way future-proof - as soon as an inner context appears which implements an additional interface,
+ // we would need to adjust our implementation to support this new interface, too. Bad idea.
+
+ // The usual solution for such a problem is aggregation. Aggregation means using UNO's own mechanism
+ // for merging an inner with an outer component, and get a component which behaves as it is exactly one.
+ // This is what XAggregation is for. Unfortunately, aggregation requires _exact_ control over the ref count
+ // of the inner object, which we do not have at all.
+ // Bad, too.
+
+ // But there is a solution: com.sun.star.reflection.ProxyFactory. This service is able to create a proxy
+ // for any component, which supports _exactly_ the same interfaces as the component. In addition, it can
+ // be aggregated, as by definition the proxy's ref count is exactly 1 when returned from the factory.
+ // Sounds better. Though this yields the problem of slightly degraded performance, it's the only solution
+ // I'm aware of at the moment...
+
+ // get the control which belongs to our model (relative to our view)
+ const vcl::Window* pViewWindow = maShapeTreeInfo.GetWindow();
+ SdrUnoObj* pUnoObjectImpl = dynamic_cast<SdrUnoObj*>(SdrObject::getSdrObjectFromXShape(mxShape));
+ SdrView* pView = maShapeTreeInfo.GetSdrView();
+ OSL_ENSURE( pView && pViewWindow && pUnoObjectImpl, "AccessibleControlShape::Init: no view, or no view window, no SdrUnoObj!" );
+
+ if ( pView && pViewWindow && pUnoObjectImpl )
+ {
+ // get the context of the control - it will be our "inner" context
+ m_xUnoControl = pUnoObjectImpl->GetUnoControl( *pView, *pViewWindow->GetOutDev() );
+
+ if ( !m_xUnoControl.is() )
+ {
+ // the control has not yet been created. Though speaking strictly, it is a bug that
+ // our instance here is created without an existing control (because an AccessibleControlShape
+ // is a representation of a view object, and can only live if the view it should represent
+ // is complete, which implies a living control), it's by far the easiest and most riskless way
+ // to fix this here in this class.
+ // Okay, we will add as listener to the control container where we expect our control to appear.
+ OSL_ENSURE( !m_bWaitingForControl, "AccessibleControlShape::Init: already waiting for the control!" );
+
+ Reference< XContainer > xControlContainer = lcl_getControlContainer( pViewWindow->GetOutDev(), maShapeTreeInfo.GetSdrView() );
+ OSL_ENSURE( xControlContainer.is(), "AccessibleControlShape::Init: unable to find my ControlContainer!" );
+ if ( xControlContainer.is() )
+ {
+ xControlContainer->addContainerListener( this );
+ m_bWaitingForControl = true;
+ }
+ }
+ else
+ {
+ Reference< XModeChangeBroadcaster > xControlModes( m_xUnoControl, UNO_QUERY );
+ Reference< XAccessible > xControlAccessible( xControlModes, UNO_QUERY );
+ Reference< XAccessibleContext > xNativeControlContext;
+ if ( xControlAccessible.is() )
+ xNativeControlContext = xControlAccessible->getAccessibleContext();
+ OSL_ENSURE( xNativeControlContext.is(), "AccessibleControlShape::Init: no AccessibleContext for the control!" );
+ m_aControlContext = WeakReference< XAccessibleContext >( xNativeControlContext );
+
+ // add as listener to the context - we want to multiplex some states
+ if ( isAliveMode( m_xUnoControl ) && xNativeControlContext.is() )
+ { // (but only in alive mode)
+ startStateMultiplexing( );
+ }
+
+ // now that we have all information about our control, do some adjustments
+ adjustAccessibleRole();
+ initializeComposedState();
+
+ // some initialization for our child manager, which is used in alive mode only
+ if ( isAliveMode( m_xUnoControl ) )
+ {
+ Reference< XAccessibleStateSet > xStates( getAccessibleStateSet( ) );
+ OSL_ENSURE( xStates.is(), "AccessibleControlShape::AccessibleControlShape: no inner state set!" );
+ m_pChildManager->setTransientChildren( !xStates.is() || xStates->contains( AccessibleStateType::MANAGES_DESCENDANTS ) );
+ }
+
+ // finally, aggregate a proxy for the control context
+ // first a factory for the proxy
+ Reference< XProxyFactory > xFactory = ProxyFactory::create( comphelper::getProcessComponentContext() );
+ // then the proxy itself
+ if ( xNativeControlContext.is() )
+ {
+ m_xControlContextProxy = xFactory->createProxy( xNativeControlContext );
+ m_xControlContextTypeAccess.set( xNativeControlContext, UNO_QUERY_THROW );
+ m_xControlContextComponent.set( xNativeControlContext, UNO_QUERY_THROW );
+
+ // aggregate the proxy
+ osl_atomic_increment( &m_refCount );
+ if ( m_xControlContextProxy.is() )
+ {
+ // At this point in time, the proxy has a ref count of exactly one - in m_xControlContextProxy.
+ // Remember to _not_ reset this member unless the delegator of the proxy has been reset, too!
+ m_xControlContextProxy->setDelegator( *this );
+ }
+ osl_atomic_decrement( &m_refCount );
+
+ m_bDisposeNativeContext = true;
+
+ // Finally, we need to add ourself as mode listener to the control. In case the mode switches,
+ // we need to dispose ourself.
+ xControlModes->addModeChangeListener( this );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "AccessibleControlShape::Init: could not \"aggregate\" the controls XAccessibleContext!" );
+ }
+}
+
+void SAL_CALL AccessibleControlShape::grabFocus()
+{
+ if ( !m_xUnoControl.is() || !isAliveMode( m_xUnoControl ) )
+ {
+ // in design mode, we simply forward the request to the base class
+ AccessibleShape::grabFocus();
+ }
+ else
+ {
+ Reference< XWindow > xWindow( m_xUnoControl, UNO_QUERY );
+ OSL_ENSURE( xWindow.is(), "AccessibleControlShape::grabFocus: invalid control!" );
+ if ( xWindow.is() )
+ xWindow->setFocus();
+ }
+}
+
+OUString SAL_CALL AccessibleControlShape::getImplementationName()
+{
+ return "com.sun.star.comp.accessibility.AccessibleControlShape";
+}
+
+OUString AccessibleControlShape::CreateAccessibleBaseName()
+{
+ OUString sName;
+
+ ShapeTypeId nShapeType = ShapeTypeHandler::Instance().GetTypeId (mxShape);
+ switch (nShapeType)
+ {
+ case DRAWING_CONTROL:
+ sName = "ControlShape";
+ break;
+ default:
+ sName = "UnknownAccessibleControlShape";
+ if (mxShape.is())
+ sName += ": " + mxShape->getShapeType();
+ }
+
+ return sName;
+}
+
+OUString
+ AccessibleControlShape::CreateAccessibleDescription()
+{
+ DescriptionGenerator aDG (mxShape);
+ ShapeTypeId nShapeType = ShapeTypeHandler::Instance().GetTypeId (mxShape);
+ switch (nShapeType)
+ {
+ case DRAWING_CONTROL:
+ {
+ // check if we can obtain the "Desc" property from the model
+ OUString sDesc( getControlModelStringProperty( lcl_getDescPropertyName() ) );
+ if ( sDesc.isEmpty() )
+ { // no -> use the default
+ aDG.Initialize (STR_ObjNameSingulUno);
+ aDG.AddProperty ("ControlBackground", DescriptionGenerator::PropertyType::Color);
+ aDG.AddProperty ( "ControlBorder", DescriptionGenerator::PropertyType::Integer);
+ }
+ // ensure that we are listening to the Name property
+ m_bListeningForDesc = ensureListeningState( m_bListeningForDesc, true, lcl_getDescPropertyName() );
+ }
+ break;
+
+ default:
+ aDG.Initialize (u"Unknown accessible control shape");
+ if (mxShape.is())
+ {
+ aDG.AppendString (u"service name=");
+ aDG.AppendString (mxShape->getShapeType());
+ }
+ }
+
+ return aDG();
+}
+
+IMPLEMENT_FORWARD_REFCOUNT( AccessibleControlShape, AccessibleShape )
+IMPLEMENT_GET_IMPLEMENTATION_ID( AccessibleControlShape )
+
+void SAL_CALL AccessibleControlShape::propertyChange( const PropertyChangeEvent& _rEvent )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // check if it is the name or the description
+ if ( _rEvent.PropertyName == lcl_getNamePropertyName()
+ || _rEvent.PropertyName == lcl_getLabelPropertyName() )
+ {
+ SetAccessibleName(
+ CreateAccessibleName(),
+ AccessibleContextBase::AutomaticallyCreated);
+ }
+ else if ( _rEvent.PropertyName == lcl_getDescPropertyName() )
+ {
+ SetAccessibleDescription(
+ CreateAccessibleDescription(),
+ AccessibleContextBase::AutomaticallyCreated);
+ }
+#if OSL_DEBUG_LEVEL > 0
+ else
+ {
+ OSL_FAIL( "AccessibleControlShape::propertyChange: where did this come from?" );
+ }
+#endif
+}
+
+Any SAL_CALL AccessibleControlShape::queryInterface( const Type& _rType )
+{
+ Any aReturn = AccessibleShape::queryInterface( _rType );
+ if ( !aReturn.hasValue() )
+ {
+ aReturn = AccessibleControlShape_Base::queryInterface( _rType );
+ if ( !aReturn.hasValue() && m_xControlContextProxy.is() )
+ aReturn = m_xControlContextProxy->queryAggregation( _rType );
+ }
+ return aReturn;
+}
+
+Sequence< Type > SAL_CALL AccessibleControlShape::getTypes()
+{
+ Sequence< Type > aShapeTypes = AccessibleShape::getTypes();
+ Sequence< Type > aOwnTypes = AccessibleControlShape_Base::getTypes();
+
+ Sequence< Type > aAggregateTypes;
+ if ( m_xControlContextTypeAccess.is() )
+ aAggregateTypes = m_xControlContextTypeAccess->getTypes();
+
+ // remove duplicates
+ return comphelper::combineSequences(comphelper::concatSequences( aShapeTypes, aOwnTypes), aAggregateTypes );
+}
+
+void SAL_CALL AccessibleControlShape::notifyEvent( const AccessibleEventObject& _rEvent )
+{
+ if ( AccessibleEventId::STATE_CHANGED == _rEvent.EventId )
+ {
+ // multiplex this change
+ sal_Int16 nLostState( 0 ), nGainedState( 0 );
+ _rEvent.OldValue >>= nLostState;
+ _rEvent.NewValue >>= nGainedState;
+
+ // don't multiplex states which the inner context is not responsible for
+ if ( isComposedState( nLostState ) )
+ AccessibleShape::ResetState( nLostState );
+
+ if ( isComposedState( nGainedState ) )
+ AccessibleShape::SetState( nGainedState );
+ }
+ else
+ {
+ AccessibleEventObject aTranslatedEvent( _rEvent );
+
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // let the child manager translate the event
+ aTranslatedEvent.Source = *this;
+ m_pChildManager->translateAccessibleEvent( _rEvent, aTranslatedEvent );
+
+ // see if any of these notifications affect our child manager
+ m_pChildManager->handleChildNotification( _rEvent );
+ }
+
+ FireEvent( aTranslatedEvent );
+ }
+}
+
+void SAL_CALL AccessibleControlShape::modeChanged(const ModeChangeEvent& rSource)
+{
+ // did it come from our inner context (the real one, not it's proxy!)?
+ SAL_INFO("sw.uno", "AccessibleControlShape::modeChanged");
+ Reference<XControl> xSource(rSource.Source, UNO_QUERY); // for faster compare
+ if(xSource.get() != m_xUnoControl.get())
+ {
+ SAL_WARN("sw.uno", "AccessibleControlShape::modeChanged: where did this come from?");
+ return;
+ }
+ SolarMutexGuard g;
+ // If our "pseudo-aggregated" inner context does not live anymore,
+ // we don't want to live, too. This is accomplished by asking our
+ // parent to replace this object with a new one. Disposing this
+ // object and sending notifications about the replacement are in
+ // the responsibility of our parent.
+ const bool bReplaced = mpParent->ReplaceChild(this, mxShape, 0, maShapeTreeInfo);
+ SAL_WARN_IF(!bReplaced, "sw.uno", "AccessibleControlShape::modeChanged: replacing ourselves away did fail");
+}
+
+void SAL_CALL AccessibleControlShape::disposing (const EventObject& _rSource)
+{
+ AccessibleShape::disposing( _rSource );
+}
+
+bool AccessibleControlShape::ensureListeningState(
+ const bool _bCurrentlyListening, const bool _bNeedNewListening,
+ const OUString& _rPropertyName )
+{
+ if ( ( _bCurrentlyListening == _bNeedNewListening ) || !ensureControlModelAccess() )
+ // nothing to do
+ return _bCurrentlyListening;
+
+ try
+ {
+ if ( !m_xModelPropsMeta.is() || m_xModelPropsMeta->hasPropertyByName( _rPropertyName ) )
+ {
+ // add or revoke as listener
+ if ( _bNeedNewListening )
+ m_xControlModel->addPropertyChangeListener( _rPropertyName, static_cast< XPropertyChangeListener* >( this ) );
+ else
+ m_xControlModel->removePropertyChangeListener( _rPropertyName, static_cast< XPropertyChangeListener* >( this ) );
+ }
+ else
+ OSL_FAIL( "AccessibleControlShape::ensureListeningState: this property does not exist at this model!" );
+ }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "AccessibleControlShape::ensureListeningState: could not change the listening state!" );
+ }
+
+ return _bNeedNewListening;
+}
+
+sal_Int32 SAL_CALL AccessibleControlShape::getAccessibleChildCount( )
+{
+ if ( !m_xUnoControl.is() )
+ return 0;
+ else if ( !isAliveMode( m_xUnoControl ) )
+ // no special action required when in design mode
+ return AccessibleShape::getAccessibleChildCount( );
+ else
+ {
+ // in alive mode, we have the full control over our children - they are determined by the children
+ // of the context of our UNO control
+ Reference< XAccessibleContext > xControlContext( m_aControlContext );
+ OSL_ENSURE( xControlContext.is(), "AccessibleControlShape::getAccessibleChildCount: control context already dead! How this!" );
+ return xControlContext.is() ? xControlContext->getAccessibleChildCount() : 0;
+ }
+}
+
+Reference< XAccessible > SAL_CALL AccessibleControlShape::getAccessibleChild( sal_Int32 i )
+{
+ Reference< XAccessible > xChild;
+ if ( !m_xUnoControl.is() )
+ {
+ throw IndexOutOfBoundsException();
+ }
+ if ( !isAliveMode( m_xUnoControl ) )
+ {
+ // no special action required when in design mode - let the base class handle this
+ xChild = AccessibleShape::getAccessibleChild( i );
+ }
+ else
+ {
+ // in alive mode, we have the full control over our children - they are determined by the children
+ // of the context of our UNO control
+
+ Reference< XAccessibleContext > xControlContext( m_aControlContext );
+ OSL_ENSURE( xControlContext.is(), "AccessibleControlShape::getAccessibleChildCount: control context already dead! How this!" );
+ if ( xControlContext.is() )
+ {
+ Reference< XAccessible > xInnerChild( xControlContext->getAccessibleChild( i ) );
+ OSL_ENSURE( xInnerChild.is(), "AccessibleControlShape::getAccessibleChild: control context returned nonsense!" );
+ if ( xInnerChild.is() )
+ {
+ // we need to wrap this inner child into an own implementation
+ xChild = m_pChildManager->getAccessibleWrapperFor( xInnerChild );
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ sal_Int32 nChildIndex = -1;
+ Reference< XAccessibleContext > xContext;
+ if ( xChild.is() )
+ xContext = xChild->getAccessibleContext( );
+ if ( xContext.is() )
+ nChildIndex = xContext->getAccessibleIndexInParent( );
+ SAL_WARN_IF( nChildIndex != i, "svx", "AccessibleControlShape::getAccessibleChild: index mismatch,"
+ " nChildIndex=" << nChildIndex << " vs i=" << i );
+#endif
+ return xChild;
+}
+
+Reference< XAccessibleRelationSet > SAL_CALL AccessibleControlShape::getAccessibleRelationSet( )
+{
+ rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSetHelper = new utl::AccessibleRelationSetHelper;
+ ensureControlModelAccess();
+ AccessibleControlShape* pCtlAccShape = GetLabeledByControlShape();
+ if(pCtlAccShape)
+ {
+ Reference < XAccessible > xAcc (pCtlAccShape->getAccessibleContext(), UNO_QUERY);
+
+ css::uno::Sequence< css::uno::Reference< css::uno::XInterface > > aSequence { xAcc };
+ if( getAccessibleRole() == AccessibleRole::RADIO_BUTTON )
+ {
+ pRelationSetHelper->AddRelation( AccessibleRelation( AccessibleRelationType::MEMBER_OF, aSequence ) );
+ }
+ else
+ {
+ pRelationSetHelper->AddRelation( AccessibleRelation( AccessibleRelationType::LABELED_BY, aSequence ) );
+ }
+ }
+ return pRelationSetHelper;
+}
+
+OUString AccessibleControlShape::CreateAccessibleName()
+{
+ ensureControlModelAccess();
+
+ OUString sName;
+ sal_Int16 aAccessibleRole = getAccessibleRole();
+ if ( aAccessibleRole != AccessibleRole::SHAPE
+ && aAccessibleRole != AccessibleRole::RADIO_BUTTON )
+ {
+ AccessibleControlShape* pCtlAccShape = GetLabeledByControlShape();
+ if(pCtlAccShape)
+ {
+ sName = pCtlAccShape->CreateAccessibleName();
+ }
+ }
+
+ if (sName.isEmpty())
+ {
+ // check if we can obtain the "Name" resp. "Label" property from the model
+ const OUString& rAccNameProperty = lcl_getPreferredAccNameProperty( m_xModelPropsMeta );
+ sName = getControlModelStringProperty( rAccNameProperty );
+ if ( !sName.getLength() )
+ { // no -> use the default
+ sName = AccessibleShape::CreateAccessibleName();
+ }
+ }
+
+ // now that somebody first asked us for our name, ensure that we are listening to name changes on the model
+ m_bListeningForName = ensureListeningState( m_bListeningForName, true, lcl_getPreferredAccNameProperty( m_xModelPropsMeta ) );
+
+ return sName;
+}
+
+void SAL_CALL AccessibleControlShape::disposing()
+{
+ // ensure we're not listening
+ m_bListeningForName = ensureListeningState( m_bListeningForName, false, lcl_getPreferredAccNameProperty( m_xModelPropsMeta ) );
+ m_bListeningForDesc = ensureListeningState( m_bListeningForDesc, false, lcl_getDescPropertyName() );
+
+ if ( m_bMultiplexingStates )
+ stopStateMultiplexing( );
+
+ // dispose the child cache/map
+ m_pChildManager->dispose();
+
+ // release the model
+ m_xControlModel.clear();
+ m_xModelPropsMeta.clear();
+ m_aControlContext = WeakReference< XAccessibleContext >();
+
+ // stop listening at the control container (should never be necessary here, but who knows...)
+ if ( m_bWaitingForControl )
+ {
+ OSL_FAIL( "AccessibleControlShape::disposing: this should never happen!" );
+ Reference< XContainer > xContainer = lcl_getControlContainer( maShapeTreeInfo.GetWindow()->GetOutDev(), maShapeTreeInfo.GetSdrView() );
+ if ( xContainer.is() )
+ {
+ m_bWaitingForControl = false;
+ xContainer->removeContainerListener( this );
+ }
+ }
+
+ // forward the disposal to our inner context
+ if ( m_bDisposeNativeContext )
+ {
+ // don't listen for mode changes anymore
+ Reference< XModeChangeBroadcaster > xControlModes( m_xUnoControl, UNO_QUERY );
+ OSL_ENSURE( xControlModes.is(), "AccessibleControlShape::disposing: don't have a mode broadcaster anymore!" );
+ if ( xControlModes.is() )
+ xControlModes->removeModeChangeListener( this );
+
+ if ( m_xControlContextComponent.is() )
+ m_xControlContextComponent->dispose();
+ // do _not_ clear m_xControlContextProxy! This has to be done in the dtor for correct ref-count handling
+
+ // no need to dispose the proxy/inner context anymore
+ m_bDisposeNativeContext = false;
+ }
+
+ m_xUnoControl.clear();
+
+ // let the base do its stuff
+ AccessibleShape::disposing();
+}
+
+bool AccessibleControlShape::ensureControlModelAccess()
+{
+ if ( m_xControlModel.is() )
+ return true;
+
+ try
+ {
+ Reference< XControlShape > xShape( mxShape, UNO_QUERY );
+ if ( xShape.is() )
+ m_xControlModel.set(xShape->getControl(), css::uno::UNO_QUERY);
+
+ if ( m_xControlModel.is() )
+ m_xModelPropsMeta = m_xControlModel->getPropertySetInfo();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "AccessibleControlShape::ensureControlModelAccess" );
+ }
+
+ return m_xControlModel.is();
+}
+
+void AccessibleControlShape::startStateMultiplexing()
+{
+ OSL_PRECOND( !m_bMultiplexingStates, "AccessibleControlShape::startStateMultiplexing: already multiplexing!" );
+
+#if OSL_DEBUG_LEVEL > 0
+ // we should have a control, and it should be in alive mode
+ OSL_PRECOND( isAliveMode( m_xUnoControl ),
+ "AccessibleControlShape::startStateMultiplexing: should be done in alive mode only!" );
+#endif
+ // we should have the native context of the control
+ Reference< XAccessibleEventBroadcaster > xBroadcaster( m_aControlContext.get(), UNO_QUERY );
+ OSL_ENSURE( xBroadcaster.is(), "AccessibleControlShape::startStateMultiplexing: no AccessibleEventBroadcaster on the native context!" );
+
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->addAccessibleEventListener( this );
+ m_bMultiplexingStates = true;
+ }
+}
+
+void AccessibleControlShape::stopStateMultiplexing()
+{
+ OSL_PRECOND( m_bMultiplexingStates, "AccessibleControlShape::stopStateMultiplexing: not multiplexing!" );
+
+ // we should have the native context of the control
+ Reference< XAccessibleEventBroadcaster > xBroadcaster( m_aControlContext.get(), UNO_QUERY );
+ OSL_ENSURE( xBroadcaster.is(), "AccessibleControlShape::stopStateMultiplexing: no AccessibleEventBroadcaster on the native context!" );
+
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->removeAccessibleEventListener( this );
+ m_bMultiplexingStates = false;
+ }
+}
+
+OUString AccessibleControlShape::getControlModelStringProperty( const OUString& _rPropertyName ) const
+{
+ OUString sReturn;
+ try
+ {
+ if ( const_cast< AccessibleControlShape* >( this )->ensureControlModelAccess() )
+ {
+ if ( !m_xModelPropsMeta.is() || m_xModelPropsMeta->hasPropertyByName( _rPropertyName ) )
+ // ask only if a) the control does not have a PropertySetInfo object or b) it has, and the
+ // property in question is available
+ m_xControlModel->getPropertyValue( _rPropertyName ) >>= sReturn;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "OAccessibleControlContext::getModelStringProperty" );
+ }
+ return sReturn;
+}
+
+void AccessibleControlShape::adjustAccessibleRole( )
+{
+ // if we're in design mode, we are a simple SHAPE, in alive mode, we use the role of our inner context
+ if ( !isAliveMode( m_xUnoControl ) )
+ return;
+
+ // we're in alive mode -> determine the role of the inner context
+ Reference< XAccessibleContext > xNativeContext( m_aControlContext );
+ OSL_PRECOND( xNativeContext.is(), "AccessibleControlShape::adjustAccessibleRole: no inner context!" );
+ if ( xNativeContext.is() )
+ SetAccessibleRole( xNativeContext->getAccessibleRole( ) );
+}
+
+#ifdef DBG_UTIL
+
+bool AccessibleControlShape::SetState( sal_Int16 _nState )
+{
+ OSL_ENSURE( !isAliveMode( m_xUnoControl ) || !isComposedState( _nState ),
+ "AccessibleControlShape::SetState: a state which should be determined by the control context is set from outside!" );
+ return AccessibleShape::SetState( _nState );
+}
+#endif // DBG_UTIL
+
+void AccessibleControlShape::initializeComposedState()
+{
+ if ( !isAliveMode( m_xUnoControl ) )
+ // no action necessary for design mode
+ return;
+
+ // get our own state set implementation
+ ::utl::AccessibleStateSetHelper* pComposedStates = mxStateSet.get();
+ OSL_PRECOND( pComposedStates,
+ "AccessibleControlShape::initializeComposedState: no composed set!" );
+
+ // we need to reset some states of the composed set, because they either do not apply
+ // for controls in alive mode, or are in the responsibility of the UNO-control, anyway
+ pComposedStates->RemoveState( AccessibleStateType::ENABLED ); // this is controlled by the UNO-control
+ pComposedStates->RemoveState( AccessibleStateType::SENSITIVE ); // this is controlled by the UNO-control
+ pComposedStates->RemoveState( AccessibleStateType::FOCUSABLE ); // this is controlled by the UNO-control
+ pComposedStates->RemoveState( AccessibleStateType::SELECTABLE ); // this does not hold for an alive UNO-control
+#if OSL_DEBUG_LEVEL > 0
+ // now, only states which are not in the responsibility of the UNO control should be part of this state set
+ {
+ const Sequence< sal_Int16 > aInitStates = pComposedStates->getStates();
+ for ( sal_Int16 state : aInitStates )
+ OSL_ENSURE( !isComposedState( state ),
+ "AccessibleControlShape::initializeComposedState: invalid initial composed state (should be controlled by the UNO-control)!" );
+ }
+#endif
+
+ // get my inner context
+ Reference< XAccessibleContext > xInnerContext( m_aControlContext );
+ OSL_PRECOND( xInnerContext.is(), "AccessibleControlShape::initializeComposedState: no inner context!" );
+ if ( !xInnerContext.is() )
+ return;
+
+ // get all states of the inner context
+ Reference< XAccessibleStateSet > xInnerStates( xInnerContext->getAccessibleStateSet() );
+ OSL_ENSURE( xInnerStates.is(), "AccessibleControlShape::initializeComposedState: no inner states!" );
+ Sequence< sal_Int16 > aInnerStates;
+ if ( xInnerStates.is() )
+ aInnerStates = xInnerStates->getStates();
+
+ // look which one are to be propagated to the composed context
+ for ( const sal_Int16 nState : std::as_const(aInnerStates) )
+ {
+ if ( isComposedState( nState ) && !pComposedStates->contains( nState ) )
+ {
+ pComposedStates->AddState( nState );
+ }
+ }
+}
+
+void SAL_CALL AccessibleControlShape::elementInserted( const css::container::ContainerEvent& _rEvent )
+{
+ Reference< XContainer > xContainer( _rEvent.Source, UNO_QUERY );
+ Reference< XControl > xControl( _rEvent.Element, UNO_QUERY );
+
+ OSL_ENSURE( xContainer.is() && xControl.is(),
+ "AccessibleControlShape::elementInserted: invalid event description!" );
+
+ if ( !xControl.is() )
+ return;
+
+ ensureControlModelAccess();
+
+ Reference< XInterface > xNewNormalized( xControl->getModel(), UNO_QUERY );
+ Reference< XInterface > xMyModelNormalized( m_xControlModel, UNO_QUERY );
+ if ( !(xNewNormalized && xMyModelNormalized) )
+ return;
+
+ // now finally the control for the model we're responsible for has been inserted into the container
+ Reference< XInterface > xKeepAlive( *this );
+
+ // first, we're not interested in any more container events
+ if ( xContainer.is() )
+ {
+ xContainer->removeContainerListener( this );
+ m_bWaitingForControl = false;
+ }
+
+ // second, we need to replace ourself with a new version, which now can be based on the
+ // control
+ OSL_VERIFY( mpParent->ReplaceChild ( this, mxShape, 0, maShapeTreeInfo ) );
+}
+
+void SAL_CALL AccessibleControlShape::elementRemoved( const css::container::ContainerEvent& )
+{
+ // not interested in
+}
+
+void SAL_CALL AccessibleControlShape::elementReplaced( const css::container::ContainerEvent& )
+{
+ // not interested in
+}
+
+AccessibleControlShape* AccessibleControlShape::GetLabeledByControlShape( )
+{
+ if(m_xControlModel.is())
+ {
+ const OUString& rAccLabelControlProperty = lcl_getLabelControlPropertyName();
+ Any sCtlLabelBy;
+ // get the "label by" property value of the control
+ if (::comphelper::hasProperty(rAccLabelControlProperty, m_xControlModel))
+ {
+ sCtlLabelBy = m_xControlModel->getPropertyValue(rAccLabelControlProperty);
+ if( sCtlLabelBy.hasValue() )
+ {
+ Reference< XPropertySet > xAsSet (sCtlLabelBy, UNO_QUERY);
+ AccessibleControlShape* pCtlAccShape = mpParent->GetAccControlShapeFromModel(xAsSet.get());
+ return pCtlAccShape;
+ }
+ }
+ }
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleEmptyEditSource.cxx b/svx/source/accessibility/AccessibleEmptyEditSource.cxx
new file mode 100644
index 000000000..e1426d239
--- /dev/null
+++ b/svx/source/accessibility/AccessibleEmptyEditSource.cxx
@@ -0,0 +1,329 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+// Global header
+
+
+#include <memory>
+#include <svl/itemset.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/outliner.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpool.hxx>
+
+
+// Project-local header
+
+
+#include "AccessibleEmptyEditSource.hxx"
+#include <svx/unoshtxt.hxx>
+
+namespace accessibility
+{
+ namespace {
+
+ /** This class simply wraps a SvxTextEditSource, forwarding all
+ methods except the GetBroadcaster() call
+ */
+ class AccessibleProxyEditSource_Impl : public SvxEditSource
+ {
+ public:
+ /** Construct AccessibleEmptyEditSource_Impl
+
+ @param rBrdCast
+
+ Proxy broadcaster to allow seamless flipping of edit source implementations. ProxyEditSource and EmptyEditSource
+ */
+ AccessibleProxyEditSource_Impl( SdrObject& rObj,
+ SdrView& rView,
+ const OutputDevice& rViewWindow );
+
+ // from the SvxEditSource interface
+ SvxTextForwarder* GetTextForwarder() override;
+ SvxViewForwarder* GetViewForwarder() override;
+ SvxEditViewForwarder* GetEditViewForwarder( bool bCreate = false ) override;
+
+ std::unique_ptr<SvxEditSource> Clone() const override;
+
+ void UpdateData() override;
+
+ SfxBroadcaster& GetBroadcaster() const override;
+
+ private:
+ SvxTextEditSource maEditSource;
+
+ };
+
+ /** Dummy class, faking exactly one empty paragraph for EditEngine accessibility
+ */
+ class AccessibleEmptyEditSource_Impl : public SvxEditSource, public SvxViewForwarder, public SvxTextForwarder, public SfxBroadcaster
+ {
+ public:
+
+ AccessibleEmptyEditSource_Impl() {}
+
+ // SvxEditSource
+ SvxTextForwarder* GetTextForwarder() override { return this; }
+ SvxViewForwarder* GetViewForwarder() override { return this; }
+ std::unique_ptr<SvxEditSource> Clone() const override { return nullptr; }
+ void UpdateData() override {}
+ SfxBroadcaster& GetBroadcaster() const override { return *const_cast<AccessibleEmptyEditSource_Impl*>(this); }
+
+ // SvxTextForwarder
+ sal_Int32 GetParagraphCount() const override { return 1; }
+ sal_Int32 GetTextLen( sal_Int32 /*nParagraph*/ ) const override { return 0; }
+ OUString GetText( const ESelection& /*rSel*/ ) const override { return OUString(); }
+ SfxItemSet GetAttribs( const ESelection& /*rSel*/, EditEngineAttribs /*nOnlyHardAttrib*/ = EditEngineAttribs::All ) const override
+ {
+ // AW: Very dangerous: The former implementation used a SfxItemPool created on the
+ // fly which of course was deleted again ASAP. Thus, the returned SfxItemSet was using
+ // a deleted Pool by design.
+ return SfxItemSet(SdrObject::GetGlobalDrawObjectItemPool());
+ }
+ SfxItemSet GetParaAttribs( sal_Int32 /*nPara*/ ) const override { return GetAttribs(ESelection()); }
+ void SetParaAttribs( sal_Int32 /*nPara*/, const SfxItemSet& /*rSet*/ ) override {}
+ void RemoveAttribs( const ESelection& /*rSelection*/ ) override {}
+ void GetPortions( sal_Int32 /*nPara*/, std::vector<sal_Int32>& /*rList*/ ) const override {}
+
+ SfxItemState GetItemState( const ESelection& /*rSel*/, sal_uInt16 /*nWhich*/ ) const override { return SfxItemState::UNKNOWN; }
+ SfxItemState GetItemState( sal_Int32 /*nPara*/, sal_uInt16 /*nWhich*/ ) const override { return SfxItemState::UNKNOWN; }
+
+ SfxItemPool* GetPool() const override { return nullptr; }
+
+ void QuickInsertText( const OUString& /*rText*/, const ESelection& /*rSel*/ ) override {}
+ void QuickInsertField( const SvxFieldItem& /*rFld*/, const ESelection& /*rSel*/ ) override {}
+ void QuickSetAttribs( const SfxItemSet& /*rSet*/, const ESelection& /*rSel*/ ) override {}
+ void QuickInsertLineBreak( const ESelection& /*rSel*/ ) override {}
+
+ const SfxItemSet * GetEmptyItemSetPtr() override { return nullptr; }
+
+ void AppendParagraph() override {}
+ sal_Int32 AppendTextPortion( sal_Int32 /*nPara*/, const OUString & /*rText*/, const SfxItemSet & /*rSet*/ ) override { return 0; }
+
+ //XTextCopy
+ void CopyText(const SvxTextForwarder& ) override {}
+
+ OUString CalcFieldValue( const SvxFieldItem& /*rField*/, sal_Int32 /*nPara*/, sal_Int32 /*nPos*/, std::optional<Color>& /*rpTxtColor*/, std::optional<Color>& /*rpFldColor*/ ) override
+ {
+ return OUString();
+ }
+ void FieldClicked( const SvxFieldItem& ) override {}
+
+ bool IsValid() const override { return true; }
+
+ LanguageType GetLanguage( sal_Int32, sal_Int32 ) const override { return LANGUAGE_DONTKNOW; }
+ sal_Int32 GetFieldCount( sal_Int32 ) const override { return 0; }
+ EFieldInfo GetFieldInfo( sal_Int32, sal_uInt16 ) const override { return EFieldInfo(); }
+ EBulletInfo GetBulletInfo( sal_Int32 ) const override { return EBulletInfo(); }
+ tools::Rectangle GetCharBounds( sal_Int32, sal_Int32 ) const override { return tools::Rectangle(); }
+ tools::Rectangle GetParaBounds( sal_Int32 ) const override { return tools::Rectangle(); }
+ MapMode GetMapMode() const override { return MapMode(); }
+ OutputDevice* GetRefDevice() const override { return nullptr; }
+ bool GetIndexAtPoint( const Point&, sal_Int32&, sal_Int32& ) const override { return false; }
+ bool GetWordIndices( sal_Int32, sal_Int32, sal_Int32&, sal_Int32& ) const override { return false; }
+ bool GetAttributeRun( sal_Int32&, sal_Int32&, sal_Int32, sal_Int32, bool ) const override { return false; }
+ sal_Int32 GetLineCount( sal_Int32 nPara ) const override { return nPara == 0 ? 1 : 0; }
+ sal_Int32 GetLineLen( sal_Int32, sal_Int32 ) const override { return 0; }
+ void GetLineBoundaries( /*out*/sal_Int32 & rStart, /*out*/sal_Int32 & rEnd, sal_Int32 /*nParagraph*/, sal_Int32 /*nLine*/ ) const override { rStart = rEnd = 0; }
+ sal_Int32 GetLineNumberAtIndex( sal_Int32 /*nPara*/, sal_Int32 /*nIndex*/ ) const override { return 0; }
+
+ // the following two methods would, strictly speaking, require
+ // a switch to a real EditSource, too. Fortunately, the
+ // AccessibleEditableTextPara implementation currently always
+ // calls GetEditViewForwarder(true) before doing
+ // changes. Thus, we rely on this behaviour here (problem
+ // when that changes: via accessibility API, it would no
+ // longer be possible to enter text in previously empty
+ // shapes).
+ bool Delete( const ESelection& ) override { return false; }
+ bool InsertText( const OUString&, const ESelection& ) override { return false; }
+ bool QuickFormatDoc( bool ) override { return true; }
+ sal_Int16 GetDepth( sal_Int32 ) const override { return -1; }
+ bool SetDepth( sal_Int32, sal_Int16 ) override { return true; }
+
+ Point LogicToPixel( const Point& rPoint, const MapMode& /*rMapMode*/ ) const override { return rPoint; }
+ Point PixelToLogic( const Point& rPoint, const MapMode& /*rMapMode*/ ) const override { return rPoint; }
+
+ };
+
+ }
+
+ // Implementing AccessibleProxyEditSource_Impl
+
+
+ AccessibleProxyEditSource_Impl::AccessibleProxyEditSource_Impl( SdrObject& rObj,
+ SdrView& rView,
+ const OutputDevice& rViewWindow ) :
+ maEditSource( rObj, nullptr, rView, rViewWindow )
+ {
+ }
+
+ SvxTextForwarder* AccessibleProxyEditSource_Impl::GetTextForwarder()
+ {
+ return maEditSource.GetTextForwarder();
+ }
+
+ SvxViewForwarder* AccessibleProxyEditSource_Impl::GetViewForwarder()
+ {
+ return maEditSource.GetViewForwarder();
+ }
+
+ SvxEditViewForwarder* AccessibleProxyEditSource_Impl::GetEditViewForwarder( bool bCreate )
+ {
+ return maEditSource.GetEditViewForwarder( bCreate );
+ }
+
+ std::unique_ptr<SvxEditSource> AccessibleProxyEditSource_Impl::Clone() const
+ {
+ return maEditSource.Clone();
+ }
+
+ void AccessibleProxyEditSource_Impl::UpdateData()
+ {
+ maEditSource.UpdateData();
+ }
+
+ SfxBroadcaster& AccessibleProxyEditSource_Impl::GetBroadcaster() const
+ {
+ return maEditSource.GetBroadcaster();
+ }
+
+
+ // Implementing AccessibleEmptyEditSource
+
+
+ AccessibleEmptyEditSource::AccessibleEmptyEditSource( SdrObject& rObj,
+ SdrView& rView,
+ const OutputDevice& rViewWindow ) :
+ mpEditSource( new AccessibleEmptyEditSource_Impl() ),
+ mrObj(rObj),
+ mrView(rView),
+ mrViewWindow(rViewWindow),
+ mbEditSourceEmpty( true )
+ {
+ StartListening( mrObj.getSdrModelFromSdrObject() );
+ }
+
+ AccessibleEmptyEditSource::~AccessibleEmptyEditSource()
+ {
+ if( !mbEditSourceEmpty )
+ {
+ // deregister as listener
+ if (mpEditSource)
+ EndListening( mpEditSource->GetBroadcaster() );
+ }
+ else
+ {
+ EndListening( mrObj.getSdrModelFromSdrObject() );
+ }
+ }
+
+ SvxTextForwarder* AccessibleEmptyEditSource::GetTextForwarder()
+ {
+ if (!mpEditSource)
+ return nullptr;
+
+ return mpEditSource->GetTextForwarder();
+ }
+
+ SvxViewForwarder* AccessibleEmptyEditSource::GetViewForwarder()
+ {
+ if (!mpEditSource)
+ return nullptr;
+
+ return mpEditSource->GetViewForwarder();
+ }
+
+ void AccessibleEmptyEditSource::Switch2ProxyEditSource()
+ {
+ // deregister EmptyEditSource model listener
+ EndListening( mrObj.getSdrModelFromSdrObject() );
+
+ ::std::unique_ptr< SvxEditSource > pProxySource( new AccessibleProxyEditSource_Impl(mrObj, mrView, mrViewWindow) );
+ mpEditSource.swap(pProxySource);
+
+ // register as listener
+ StartListening( mpEditSource->GetBroadcaster() );
+
+ // we've irrevocably a full EditSource now.
+ mbEditSourceEmpty = false;
+ }
+
+ SvxEditViewForwarder* AccessibleEmptyEditSource::GetEditViewForwarder( bool bCreate )
+ {
+ if (!mpEditSource)
+ return nullptr;
+
+ // switch edit source, if not yet done
+ if( mbEditSourceEmpty && bCreate )
+ Switch2ProxyEditSource();
+
+ return mpEditSource->GetEditViewForwarder( bCreate );
+ }
+
+ std::unique_ptr<SvxEditSource> AccessibleEmptyEditSource::Clone() const
+ {
+ if (!mpEditSource)
+ return nullptr;
+
+ return mpEditSource->Clone();
+ }
+
+ void AccessibleEmptyEditSource::UpdateData()
+ {
+ if (mpEditSource)
+ mpEditSource->UpdateData();
+ }
+
+ SfxBroadcaster& AccessibleEmptyEditSource::GetBroadcaster() const
+ {
+ return *const_cast<AccessibleEmptyEditSource*>(this);
+ }
+
+ void AccessibleEmptyEditSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+ {
+ const SdrHint* pSdrHint = ( rHint.GetId() == SfxHintId::ThisIsAnSdrHint ? static_cast<const SdrHint*>(&rHint) : nullptr );
+
+ if( pSdrHint && pSdrHint->GetKind() == SdrHintKind::BeginEdit &&
+ &mrObj == pSdrHint->GetObject() && mpEditSource )
+ {
+ // switch edit source, if not yet done. This is necessary
+ // to become a full-fledged EditSource the first time a
+ // user start entering text in a previously empty object.
+ if( mbEditSourceEmpty )
+ Switch2ProxyEditSource();
+ }
+ else if (pSdrHint && pSdrHint->GetObject()!=nullptr)
+ {
+ // When the SdrObject just got a para outliner object then
+ // switch the edit source.
+ if (pSdrHint->GetObject()->GetOutlinerParaObject() != nullptr)
+ Switch2ProxyEditSource();
+ }
+
+ // forward messages
+ Broadcast( rHint );
+ }
+
+} // end of namespace accessibility
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleEmptyEditSource.hxx b/svx/source/accessibility/AccessibleEmptyEditSource.hxx
new file mode 100644
index 000000000..6cfceeda4
--- /dev/null
+++ b/svx/source/accessibility/AccessibleEmptyEditSource.hxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_ACCESSIBILITY_ACCESSIBLEEMPTYEDITSOURCE_HXX
+#define INCLUDED_SVX_SOURCE_ACCESSIBILITY_ACCESSIBLEEMPTYEDITSOURCE_HXX
+
+#include <svl/SfxBroadcaster.hxx>
+#include <svl/lstner.hxx>
+
+#include <memory>
+#include <editeng/unoedsrc.hxx>
+
+class SdrObject;
+class SdrView;
+class OutputDevice;
+
+namespace accessibility
+{
+ /** Proxy edit source for shapes without text
+
+ Extracted from old SvxDummyEditSource
+ */
+ class AccessibleEmptyEditSource : public SvxEditSource, public SfxListener, public SfxBroadcaster
+ {
+ public:
+ /** Create proxy edit source for shapes without text
+
+ Since the views don't broadcast their dying, make sure that
+ this object gets destroyed if the view becomes invalid
+
+ The window is necessary, since our views can display on multiple windows
+
+ Make sure you only create such an object if the shape _really_
+ does not contain text.
+ */
+ AccessibleEmptyEditSource( SdrObject& rObj, SdrView& rView, const OutputDevice& rViewWindow );
+ virtual ~AccessibleEmptyEditSource() override;
+
+ // from the SvxEditSource interface
+ SvxTextForwarder* GetTextForwarder() override;
+ SvxViewForwarder* GetViewForwarder() override;
+
+ std::unique_ptr<SvxEditSource> Clone() const override;
+
+ // this method internally switches from empty to proxy mode,
+ // creating an SvxTextEditSource for the functionality.
+ SvxEditViewForwarder* GetEditViewForwarder( bool bCreate = false ) override;
+
+ void UpdateData() override;
+ SfxBroadcaster& GetBroadcaster() const override;
+
+ // from the SfxListener interface
+ void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ private:
+ void Switch2ProxyEditSource();
+
+ /** Pointer to edit source implementation. This is switched on
+ a GetEditViewForwarder( true ) call, to actually create a
+ SvxTextEditSource.
+
+ @dyn
+ */
+ std::unique_ptr< SvxEditSource > mpEditSource;
+
+ SdrObject& mrObj;
+ SdrView& mrView;
+ const OutputDevice& mrViewWindow;
+
+ bool mbEditSourceEmpty;
+ };
+
+} // namespace accessibility
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleFrameSelector.cxx b/svx/source/accessibility/AccessibleFrameSelector.cxx
new file mode 100644
index 000000000..3c3007fc0
--- /dev/null
+++ b/svx/source/accessibility/AccessibleFrameSelector.cxx
@@ -0,0 +1,380 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleFrameSelector.hxx>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <svx/frmsel.hxx>
+#include <svx/dialmgr.hxx>
+
+#include <frmsel.hrc>
+
+namespace svx::a11y {
+
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::RuntimeException;
+
+using namespace ::com::sun::star::accessibility;
+
+
+AccFrameSelector::AccFrameSelector(FrameSelector& rFrameSel)
+ : mpFrameSel(&rFrameSel)
+{
+}
+
+AccFrameSelector::~AccFrameSelector()
+{
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( AccFrameSelector, OAccessibleComponentHelper, OAccessibleHelper_Base )
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( AccFrameSelector, OAccessibleComponentHelper, OAccessibleHelper_Base )
+
+Reference< XAccessibleContext > AccFrameSelector::getAccessibleContext( )
+{
+ return this;
+}
+
+sal_Int32 AccFrameSelector::getAccessibleChildCount( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ return mpFrameSel->GetEnabledBorderCount();
+}
+
+Reference< XAccessible > AccFrameSelector::getAccessibleChild( sal_Int32 i )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ Reference< XAccessible > xRet = mpFrameSel->GetChildAccessible( i );
+ if( !xRet.is() )
+ throw RuntimeException();
+ return xRet;
+}
+
+Reference< XAccessible > AccFrameSelector::getAccessibleParent( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ Reference< XAccessible > xRet = mpFrameSel->getAccessibleParent();
+ return xRet;
+}
+
+sal_Int16 AccFrameSelector::getAccessibleRole( )
+{
+ return AccessibleRole::OPTION_PANE;
+}
+
+OUString AccFrameSelector::getAccessibleDescription( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ return SvxResId(RID_SVXSTR_FRMSEL_DESCRIPTIONS[0].first);
+}
+
+OUString AccFrameSelector::getAccessibleName( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ return SvxResId(RID_SVXSTR_FRMSEL_TEXTS[0].first);
+}
+
+Reference< XAccessibleRelationSet > AccFrameSelector::getAccessibleRelationSet( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ return mpFrameSel->get_accessible_relation_set();
+}
+
+Reference< XAccessibleStateSet > AccFrameSelector::getAccessibleStateSet( )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSetHelper = new utl::AccessibleStateSetHelper;
+
+ if(!mpFrameSel)
+ pStateSetHelper->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ const sal_Int16 aStandardStates[] =
+ {
+ AccessibleStateType::EDITABLE,
+ AccessibleStateType::FOCUSABLE,
+ AccessibleStateType::MULTI_SELECTABLE,
+ AccessibleStateType::SELECTABLE,
+ AccessibleStateType::SHOWING,
+ AccessibleStateType::VISIBLE,
+ AccessibleStateType::OPAQUE,
+ 0};
+ sal_Int16 nState = 0;
+ while(aStandardStates[nState])
+ {
+ pStateSetHelper->AddState(aStandardStates[nState++]);
+ }
+ if(mpFrameSel->IsEnabled())
+ {
+ pStateSetHelper->AddState(AccessibleStateType::ENABLED);
+ pStateSetHelper->AddState(AccessibleStateType::SENSITIVE);
+ }
+
+ if (mpFrameSel->HasFocus())
+ {
+ pStateSetHelper->AddState(AccessibleStateType::ACTIVE);
+ pStateSetHelper->AddState(AccessibleStateType::FOCUSED);
+ pStateSetHelper->AddState(AccessibleStateType::SELECTED);
+ }
+ }
+ return pStateSetHelper;
+}
+
+Reference< XAccessible > AccFrameSelector::getAccessibleAtPoint(
+ const css::awt::Point& aPt )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ //aPt is relative to the frame selector
+ return mpFrameSel->GetChildAccessible( Point( aPt.X, aPt.Y ) );
+}
+
+void AccFrameSelector::grabFocus( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ mpFrameSel->GrabFocus();
+}
+
+sal_Int32 AccFrameSelector::getForeground( )
+{
+ SolarMutexGuard aGuard;
+
+ //see FrameSelector::Paint
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ return sal_Int32(rStyles.GetLabelTextColor());
+}
+
+sal_Int32 AccFrameSelector::getBackground( )
+{
+ SolarMutexGuard aGuard;
+
+ //see FrameSelector::Paint
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ return sal_Int32(rStyles.GetDialogColor());
+}
+
+css::awt::Rectangle AccFrameSelector::implGetBounds()
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+
+ css::awt::Rectangle aRet;
+
+ const Point aOutPos;
+ Size aOutSize(mpFrameSel->GetOutputSizePixel());
+
+ aRet.X = aOutPos.X();
+ aRet.Y = aOutPos.Y();
+ aRet.Width = aOutSize.Width();
+ aRet.Height = aOutSize.Height();
+
+ return aRet;
+}
+
+void AccFrameSelector::IsValid()
+{
+ if(!mpFrameSel)
+ throw RuntimeException();
+}
+
+void AccFrameSelector::Invalidate()
+{
+ mpFrameSel = nullptr;
+}
+
+AccFrameSelectorChild::AccFrameSelectorChild(FrameSelector& rFrameSel, FrameBorderType eBorder)
+ : mpFrameSel(&rFrameSel)
+ , meBorder(eBorder)
+{
+}
+
+AccFrameSelectorChild::~AccFrameSelectorChild()
+{
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( AccFrameSelectorChild, OAccessibleComponentHelper, OAccessibleHelper_Base )
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( AccFrameSelectorChild, OAccessibleComponentHelper, OAccessibleHelper_Base )
+
+Reference< XAccessibleContext > AccFrameSelectorChild::getAccessibleContext( )
+{
+ return this;
+}
+
+sal_Int32 AccFrameSelectorChild::getAccessibleChildCount( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ return 0;
+}
+
+Reference< XAccessible > AccFrameSelectorChild::getAccessibleChild( sal_Int32 )
+{
+ throw RuntimeException();
+}
+
+Reference< XAccessible > AccFrameSelectorChild::getAccessibleParent( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ Reference< XAccessible > xRet = mpFrameSel->CreateAccessible();
+ return xRet;
+}
+
+sal_Int16 AccFrameSelectorChild::getAccessibleRole( )
+{
+ return AccessibleRole::CHECK_BOX;
+}
+
+OUString AccFrameSelectorChild::getAccessibleDescription( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ return SvxResId(RID_SVXSTR_FRMSEL_DESCRIPTIONS[static_cast<sal_uInt32>(meBorder)].first);
+}
+
+OUString AccFrameSelectorChild::getAccessibleName( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ return SvxResId(RID_SVXSTR_FRMSEL_TEXTS[static_cast<sal_uInt32>(meBorder)].first);
+}
+
+Reference< XAccessibleRelationSet > AccFrameSelectorChild::getAccessibleRelationSet( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ Reference< XAccessibleRelationSet > xRet = new utl::AccessibleRelationSetHelper;
+ return xRet;
+}
+
+Reference< XAccessibleStateSet > AccFrameSelectorChild::getAccessibleStateSet( )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSetHelper = new utl::AccessibleStateSetHelper;
+
+ if(!mpFrameSel)
+ pStateSetHelper->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ const sal_Int16 aStandardStates[] =
+ {
+ AccessibleStateType::EDITABLE,
+ AccessibleStateType::FOCUSABLE,
+ AccessibleStateType::MULTI_SELECTABLE,
+ AccessibleStateType::SELECTABLE,
+ AccessibleStateType::SHOWING,
+ AccessibleStateType::VISIBLE,
+ AccessibleStateType::OPAQUE,
+ 0};
+ sal_Int16 nState = 0;
+ while(aStandardStates[nState])
+ {
+ pStateSetHelper->AddState(aStandardStates[nState++]);
+ }
+ if(mpFrameSel->IsEnabled())
+ {
+ pStateSetHelper->AddState(AccessibleStateType::ENABLED);
+ pStateSetHelper->AddState(AccessibleStateType::SENSITIVE);
+ }
+
+ if (mpFrameSel->HasFocus() && mpFrameSel->IsBorderSelected(meBorder))
+ {
+ pStateSetHelper->AddState(AccessibleStateType::ACTIVE);
+ pStateSetHelper->AddState(AccessibleStateType::FOCUSED);
+ pStateSetHelper->AddState(AccessibleStateType::SELECTED);
+ }
+ }
+ return pStateSetHelper;
+}
+
+Reference< XAccessible > AccFrameSelectorChild::getAccessibleAtPoint(
+ const css::awt::Point& aPt )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ //aPt is relative to the frame selector
+ return mpFrameSel->GetChildAccessible( Point( aPt.X, aPt.Y ) );
+}
+
+css::awt::Rectangle AccFrameSelectorChild::implGetBounds( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ const tools::Rectangle aSpot = mpFrameSel->GetClickBoundRect( meBorder );
+ Point aPos = aSpot.TopLeft();
+ Size aSz = aSpot.GetSize();
+ css::awt::Rectangle aRet;
+ aRet.X = aPos.X();
+ aRet.Y = aPos.Y();
+ aRet.Width = aSz.Width();
+ aRet.Height = aSz.Height();
+ return aRet;
+}
+
+void AccFrameSelectorChild::grabFocus( )
+{
+ SolarMutexGuard aGuard;
+ IsValid();
+ mpFrameSel->GrabFocus();
+}
+
+sal_Int32 AccFrameSelectorChild::getForeground( )
+{
+ SolarMutexGuard aGuard;
+
+ //see FrameSelector::Paint
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ return sal_Int32(rStyles.GetLabelTextColor());
+}
+
+sal_Int32 AccFrameSelectorChild::getBackground( )
+{
+ SolarMutexGuard aGuard;
+
+ //see FrameSelector::Paint
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ return sal_Int32(rStyles.GetDialogColor());
+}
+
+void AccFrameSelectorChild::IsValid()
+{
+ if(!mpFrameSel)
+ throw RuntimeException();
+}
+
+void AccFrameSelectorChild::Invalidate()
+{
+ mpFrameSel = nullptr;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleGraphicShape.cxx b/svx/source/accessibility/AccessibleGraphicShape.cxx
new file mode 100644
index 000000000..d94ce4886
--- /dev/null
+++ b/svx/source/accessibility/AccessibleGraphicShape.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/AccessibleGraphicShape.hxx>
+
+#include <svx/ShapeTypeHandler.hxx>
+#include <svx/SvxShapeTypes.hxx>
+#include <svx/svdobj.hxx>
+
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/XShapeDescriptor.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+using namespace ::accessibility;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+// internal
+AccessibleGraphicShape::AccessibleGraphicShape (
+ const AccessibleShapeInfo& rShapeInfo,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo)
+ : AccessibleShape (rShapeInfo, rShapeTreeInfo)
+{
+}
+
+
+AccessibleGraphicShape::~AccessibleGraphicShape()
+{
+}
+
+// XAccessibleImage
+OUString SAL_CALL AccessibleGraphicShape::getAccessibleImageDescription()
+{
+ if (m_pShape)
+ return m_pShape->GetTitle();
+ return AccessibleShape::getAccessibleDescription ();
+}
+
+
+sal_Int32 SAL_CALL AccessibleGraphicShape::getAccessibleImageHeight()
+{
+ return AccessibleShape::getSize().Height;
+}
+
+
+sal_Int32 SAL_CALL AccessibleGraphicShape::getAccessibleImageWidth()
+{
+ return AccessibleShape::getSize().Width;
+}
+
+// XInterface
+css::uno::Any SAL_CALL
+ AccessibleGraphicShape::queryInterface (const css::uno::Type & rType)
+{
+ css::uno::Any aReturn = AccessibleShape::queryInterface (rType);
+ if ( ! aReturn.hasValue())
+ aReturn = ::cppu::queryInterface (rType,
+ static_cast<XAccessibleImage*>(this));
+ return aReturn;
+}
+
+
+void SAL_CALL
+ AccessibleGraphicShape::acquire()
+ noexcept
+{
+ AccessibleShape::acquire ();
+}
+
+
+void SAL_CALL
+ AccessibleGraphicShape::release()
+ noexcept
+{
+ AccessibleShape::release ();
+}
+
+// XServiceInfo
+OUString SAL_CALL
+ AccessibleGraphicShape::getImplementationName()
+{
+ return "AccessibleGraphicShape";
+}
+
+
+css::uno::Sequence< OUString> SAL_CALL
+ AccessibleGraphicShape::getSupportedServiceNames()
+{
+ ThrowIfDisposed ();
+ const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleGraphicShape" };
+ return comphelper::concatSequences(AccessibleShape::getSupportedServiceNames(), vals);
+}
+
+// XTypeProvider
+uno::Sequence<uno::Type> SAL_CALL
+ AccessibleGraphicShape::getTypes()
+{
+ // Get list of types from the context base implementation...
+ return comphelper::concatSequences(AccessibleShape::getTypes(),
+ uno::Sequence { cppu::UnoType<XAccessibleImage>::get() });
+}
+
+
+/// Create the base name of this object, i.e. the name without appended number.
+OUString
+ AccessibleGraphicShape::CreateAccessibleBaseName()
+{
+ OUString sName;
+
+ ShapeTypeId nShapeType = ShapeTypeHandler::Instance().GetTypeId (mxShape);
+ switch (nShapeType)
+ {
+ case DRAWING_GRAPHIC_OBJECT:
+ sName = "GraphicObjectShape";
+ break;
+
+ default:
+ sName = "UnknownAccessibleGraphicShape";
+ uno::Reference<drawing::XShapeDescriptor> xDescriptor (mxShape);
+ if (xDescriptor.is())
+ sName += ": " + xDescriptor->getShapeType();
+ }
+
+ return sName;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleOLEShape.cxx b/svx/source/accessibility/AccessibleOLEShape.cxx
new file mode 100644
index 000000000..9275ad180
--- /dev/null
+++ b/svx/source/accessibility/AccessibleOLEShape.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/AccessibleOLEShape.hxx>
+
+#include <svx/ShapeTypeHandler.hxx>
+#include <svx/SvxShapeTypes.hxx>
+#include <svx/svdoole2.hxx>
+
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/XShapeDescriptor.hpp>
+
+using namespace ::accessibility;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+
+// internal
+AccessibleOLEShape::AccessibleOLEShape (
+ const AccessibleShapeInfo& rShapeInfo,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo)
+ : AccessibleShape (rShapeInfo, rShapeTreeInfo)
+{
+}
+
+
+AccessibleOLEShape::~AccessibleOLEShape()
+{
+}
+
+// XAccessibleAction
+sal_Int32 SAL_CALL AccessibleOLEShape::getAccessibleActionCount()
+{
+ return 0;
+}
+
+
+sal_Bool SAL_CALL AccessibleOLEShape::doAccessibleAction (sal_Int32 /*nIndex*/)
+{
+ throw lang::IndexOutOfBoundsException();
+}
+
+
+OUString SAL_CALL AccessibleOLEShape::getAccessibleActionDescription (sal_Int32 /*nIndex*/)
+{
+ throw lang::IndexOutOfBoundsException();
+}
+
+
+Reference<XAccessibleKeyBinding> SAL_CALL AccessibleOLEShape::getAccessibleActionKeyBinding (sal_Int32 /*nIndex*/)
+{
+ throw lang::IndexOutOfBoundsException();
+}
+
+// XInterface
+css::uno::Any SAL_CALL
+ AccessibleOLEShape::queryInterface (const css::uno::Type & rType)
+{
+ css::uno::Any aReturn = AccessibleShape::queryInterface (rType);
+ if ( ! aReturn.hasValue())
+ aReturn = ::cppu::queryInterface (rType,
+ static_cast<XAccessibleAction*>(this));
+ return aReturn;
+}
+
+
+void SAL_CALL
+ AccessibleOLEShape::acquire()
+ noexcept
+{
+ AccessibleShape::acquire ();
+}
+
+
+void SAL_CALL
+ AccessibleOLEShape::release()
+ noexcept
+{
+ AccessibleShape::release ();
+}
+
+// XServiceInfo
+OUString SAL_CALL
+ AccessibleOLEShape::getImplementationName()
+{
+ return "AccessibleOLEShape";
+}
+
+
+css::uno::Sequence< OUString> SAL_CALL
+ AccessibleOLEShape::getSupportedServiceNames()
+{
+ ThrowIfDisposed();
+ const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleOLEShape" };
+ return comphelper::concatSequences(AccessibleShape::getSupportedServiceNames(), vals);
+}
+
+// XTypeProvider
+uno::Sequence<uno::Type> SAL_CALL AccessibleOLEShape::getTypes()
+{
+ // Get list of types from the context base implementation...
+ return comphelper::concatSequences(AccessibleShape::getTypes(),
+ uno::Sequence { cppu::UnoType<XAccessibleAction>::get() } );
+}
+
+// XAccessibleExtendedAttributes
+uno::Any SAL_CALL AccessibleOLEShape::getExtendedAttributes()
+{
+ uno::Any strRet;
+ OUString style;
+ if( m_pShape )
+ {
+ style = "style:" + static_cast<SdrOle2Obj*>(m_pShape)->GetStyleString();
+ }
+ style += ";";
+ strRet <<= style;
+ return strRet;
+}
+
+/// Set this object's name if is different to the current name.
+OUString
+ AccessibleOLEShape::CreateAccessibleBaseName()
+{
+ OUString sName;
+
+ ShapeTypeId nShapeType = ShapeTypeHandler::Instance().GetTypeId (mxShape);
+ switch (nShapeType)
+ {
+ case DRAWING_APPLET:
+ sName = "AppletOLEShape";
+ break;
+ case DRAWING_FRAME:
+ sName = "FrameOLEShape";
+ break;
+ case DRAWING_OLE:
+ sName = "OLEShape";
+ break;
+ case DRAWING_PLUGIN:
+ sName = "PluginOLEShape";
+ break;
+
+ default:
+ sName = "UnknownAccessibleOLEShape";
+ uno::Reference<drawing::XShapeDescriptor> xDescriptor (mxShape);
+ if (xDescriptor.is())
+ sName += ": " + xDescriptor->getShapeType();
+ }
+
+ return sName;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleShape.cxx b/svx/source/accessibility/AccessibleShape.cxx
new file mode 100644
index 000000000..03996fe7f
--- /dev/null
+++ b/svx/source/accessibility/AccessibleShape.cxx
@@ -0,0 +1,1314 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/AccessibleShape.hxx>
+#include <svx/AccessibleShapeInfo.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <sal/log.hxx>
+#include <editeng/unoedsrc.hxx>
+#include <svx/AccessibleTextHelper.hxx>
+#include <svx/ChildrenManager.hxx>
+#include <svx/IAccessibleParent.hxx>
+#include <svx/IAccessibleViewForwarder.hxx>
+#include <svx/unoshtxt.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/ShapeTypeHandler.hxx>
+#include <svx/SvxShapeTypes.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <svx/svdview.hxx>
+#include <tools/diagnose_ex.h>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/sequence.hxx>
+#include "AccessibleEmptyEditSource.hxx"
+
+#include <algorithm>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::lang::IndexOutOfBoundsException;
+using ::com::sun::star::uno::RuntimeException;
+
+namespace accessibility {
+
+namespace {
+
+OUString GetOptionalProperty (
+ const Reference<beans::XPropertySet>& rxSet,
+ const OUString& rsPropertyName)
+{
+ OUString sValue;
+
+ if (rxSet.is())
+ {
+ const Reference<beans::XPropertySetInfo> xInfo (rxSet->getPropertySetInfo());
+ if ( ! xInfo.is() || xInfo->hasPropertyByName(rsPropertyName))
+ {
+ try
+ {
+ rxSet->getPropertyValue(rsPropertyName) >>= sValue;
+ }
+ catch (beans::UnknownPropertyException&)
+ {
+ // This exception should only be thrown when the property
+ // does not exits (of course) and the XPropertySetInfo is
+ // not available.
+ }
+ }
+ }
+ return sValue;
+}
+
+} // end of anonymous namespace
+
+// internal
+AccessibleShape::AccessibleShape (
+ const AccessibleShapeInfo& rShapeInfo,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo)
+ : AccessibleContextBase (rShapeInfo.mxParent,AccessibleRole::SHAPE),
+ mxShape (rShapeInfo.mxShape),
+ maShapeTreeInfo (rShapeTreeInfo),
+ m_nIndexInParent(-1),
+ mpParent (rShapeInfo.mpChildrenManager)
+{
+ m_pShape = SdrObject::getSdrObjectFromXShape(mxShape);
+ UpdateNameAndDescription();
+}
+
+AccessibleShape::~AccessibleShape()
+{
+ mpChildrenManager.reset();
+ mpText.reset();
+ SAL_INFO("svx", "~AccessibleShape");
+
+ // Unregistering from the various broadcasters should be unnecessary
+ // since this destructor would not have been called if one of the
+ // broadcasters would still hold a strong reference to this object.
+}
+
+void AccessibleShape::Init()
+{
+ // Update the OPAQUE and SELECTED shape.
+ UpdateStates ();
+
+ // Create a children manager when this shape has children of its own.
+ Reference<drawing::XShapes> xShapes (mxShape, uno::UNO_QUERY);
+ if (xShapes.is() && xShapes->getCount() > 0)
+ mpChildrenManager.reset( new ChildrenManager (
+ this, xShapes, maShapeTreeInfo, *this) );
+ if (mpChildrenManager != nullptr)
+ mpChildrenManager->Update();
+
+ // Register at model as document::XEventListener.
+ if (mxShape.is() && maShapeTreeInfo.GetModelBroadcaster().is())
+ maShapeTreeInfo.GetModelBroadcaster()->addShapeEventListener(mxShape,
+ static_cast<document::XShapeEventListener*>(this));
+
+ // Beware! Here we leave the paths of the UNO API and descend into the
+ // depths of the core. Necessary for making the edit engine
+ // accessible.
+ Reference<text::XText> xText (mxShape, uno::UNO_QUERY);
+ if (!xText.is())
+ return;
+
+ SdrView* pView = maShapeTreeInfo.GetSdrView ();
+ const vcl::Window* pWindow = maShapeTreeInfo.GetWindow ();
+ if (!(pView != nullptr && pWindow != nullptr && mxShape.is()))
+ return;
+
+ // #107948# Determine whether shape text is empty
+ SdrObject* pSdrObject = SdrObject::getSdrObjectFromXShape(mxShape);
+ if( !pSdrObject )
+ return;
+
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( pSdrObject );
+ const bool hasOutlinerParaObject = (pTextObj && pTextObj->CanCreateEditOutlinerParaObject()) || (pSdrObject->GetOutlinerParaObject() != nullptr);
+
+ // create AccessibleTextHelper to handle this shape's text
+ if( !hasOutlinerParaObject )
+ {
+ // empty text -> use proxy edit source to delay creation of EditEngine
+ mpText.reset( new AccessibleTextHelper( std::make_unique<AccessibleEmptyEditSource >(*pSdrObject, *pView, *pWindow->GetOutDev()) ) );
+ }
+ else
+ {
+ // non-empty text -> use full-fledged edit source right away
+ mpText.reset( new AccessibleTextHelper( std::make_unique<SvxTextEditSource >(*pSdrObject, nullptr, *pView, *pWindow->GetOutDev()) ) );
+ }
+ if( pWindow->HasFocus() )
+ mpText->SetFocus();
+
+ mpText->SetEventSource(this);
+}
+
+
+void AccessibleShape::UpdateStates()
+{
+ if (mxStateSet == nullptr)
+ return;
+
+ // Set the opaque state for certain shape types when their fill style is
+ // solid.
+ bool bShapeIsOpaque = false;
+ switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
+ {
+ case DRAWING_PAGE:
+ case DRAWING_RECTANGLE:
+ case DRAWING_TEXT:
+ {
+ uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
+ if (xSet.is())
+ {
+ try
+ {
+ drawing::FillStyle aFillStyle;
+ bShapeIsOpaque = ( xSet->getPropertyValue ("FillStyle") >>= aFillStyle)
+ && aFillStyle == drawing::FillStyle_SOLID;
+ }
+ catch (css::beans::UnknownPropertyException&)
+ {
+ // Ignore.
+ }
+ }
+ }
+ }
+ if (bShapeIsOpaque)
+ mxStateSet->AddState (AccessibleStateType::OPAQUE);
+ else
+ mxStateSet->RemoveState (AccessibleStateType::OPAQUE);
+
+ // Set the selected state.
+ bool bShapeIsSelected = false;
+ // XXX fix_me this has to be done with an extra interface later on
+ if ( m_pShape && maShapeTreeInfo.GetSdrView() )
+ {
+ bShapeIsSelected = maShapeTreeInfo.GetSdrView()->IsObjMarked(m_pShape);
+ }
+
+ if (bShapeIsSelected)
+ mxStateSet->AddState (AccessibleStateType::SELECTED);
+ else
+ mxStateSet->RemoveState (AccessibleStateType::SELECTED);
+}
+
+OUString AccessibleShape::GetStyle() const
+{
+ return ShapeTypeHandler::CreateAccessibleBaseName( mxShape );
+}
+
+bool AccessibleShape::SetState (sal_Int16 aState)
+{
+ bool bStateHasChanged = false;
+
+ if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
+ {
+ // Offer FOCUSED state to edit engine and detect whether the state
+ // changes.
+ bool bIsFocused = mpText->HaveFocus ();
+ mpText->SetFocus();
+ bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
+ }
+ else
+ bStateHasChanged = AccessibleContextBase::SetState (aState);
+
+ return bStateHasChanged;
+}
+
+
+bool AccessibleShape::ResetState (sal_Int16 aState)
+{
+ bool bStateHasChanged = false;
+
+ if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
+ {
+ // Try to remove FOCUSED state from the edit engine and detect
+ // whether the state changes.
+ bool bIsFocused = mpText->HaveFocus ();
+ mpText->SetFocus (false);
+ bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
+ }
+ else
+ bStateHasChanged = AccessibleContextBase::ResetState (aState);
+
+ return bStateHasChanged;
+}
+
+
+bool AccessibleShape::GetState (sal_Int16 aState)
+{
+ if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
+ {
+ // Just delegate the call to the edit engine. The state is not
+ // merged into the state set.
+ return mpText->HaveFocus();
+ }
+ else
+ return AccessibleContextBase::GetState (aState);
+}
+
+// OverWrite the parent's getAccessibleName method
+OUString SAL_CALL AccessibleShape::getAccessibleName()
+{
+ ThrowIfDisposed ();
+ if (m_pShape && !m_pShape->GetTitle().isEmpty())
+ return CreateAccessibleName() + " " + m_pShape->GetTitle();
+ else
+ return CreateAccessibleName();
+}
+
+OUString SAL_CALL AccessibleShape::getAccessibleDescription()
+{
+ ThrowIfDisposed ();
+ if( m_pShape && !m_pShape->GetDescription().isEmpty())
+ return m_pShape->GetDescription() ;
+ else
+ return " ";
+}
+
+// XAccessibleContext
+/** The children of this shape come from two sources: The children from
+ group or scene shapes and the paragraphs of text.
+*/
+sal_Int32 SAL_CALL
+ AccessibleShape::getAccessibleChildCount ()
+{
+ if (IsDisposed())
+ {
+ return 0;
+ }
+
+ sal_Int32 nChildCount = 0;
+
+ // Add the number of shapes that are children of this shape.
+ if (mpChildrenManager != nullptr)
+ nChildCount += mpChildrenManager->GetChildCount ();
+ // Add the number text paragraphs.
+ if (mpText != nullptr)
+ nChildCount += mpText->GetChildCount ();
+
+ return nChildCount;
+}
+
+
+/** Forward the request to the shape. Return the requested shape or throw
+ an exception for a wrong index.
+*/
+uno::Reference<XAccessible> SAL_CALL
+ AccessibleShape::getAccessibleChild (sal_Int32 nIndex)
+{
+ ThrowIfDisposed ();
+
+ uno::Reference<XAccessible> xChild;
+
+ // Depending on the index decide whether to delegate this call to the
+ // children manager or the edit engine.
+ if ((mpChildrenManager != nullptr)
+ && (nIndex < mpChildrenManager->GetChildCount()))
+ {
+ xChild = mpChildrenManager->GetChild (nIndex);
+ }
+ else if (mpText != nullptr)
+ {
+ sal_Int32 nI = nIndex;
+ if (mpChildrenManager != nullptr)
+ nI -= mpChildrenManager->GetChildCount();
+ xChild = mpText->GetChild (nI);
+ }
+ else
+ throw lang::IndexOutOfBoundsException (
+ "shape has no child with index " + OUString::number(nIndex),
+ static_cast<uno::XWeak*>(this));
+
+ return xChild;
+}
+
+uno::Reference<XAccessibleRelationSet> SAL_CALL
+ AccessibleShape::getAccessibleRelationSet()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+ if (mpParent == nullptr)
+ return uno::Reference<XAccessibleRelationSet>();
+
+ rtl::Reference<::utl::AccessibleRelationSetHelper> pRelationSet = new utl::AccessibleRelationSetHelper;
+
+ //this mxshape is the captioned shape
+ uno::Sequence< uno::Reference< uno::XInterface > > aSequence { mpParent->GetAccessibleCaption(mxShape) };
+ if(aSequence[0])
+ {
+ pRelationSet->AddRelation(
+ AccessibleRelation( AccessibleRelationType::DESCRIBED_BY, aSequence ) );
+ }
+ return pRelationSet;
+}
+
+/** Return a copy of the state set.
+ Possible states are:
+ ENABLED
+ SHOWING
+ VISIBLE
+*/
+uno::Reference<XAccessibleStateSet> SAL_CALL
+ AccessibleShape::getAccessibleStateSet()
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ if (IsDisposed())
+ {
+ // Return a minimal state set that only contains the DEFUNC state.
+ return AccessibleContextBase::getAccessibleStateSet ();
+ }
+
+ ::utl::AccessibleStateSetHelper* pStateSet = mxStateSet.get();
+
+ if (!pStateSet)
+ return Reference<XAccessibleStateSet>();
+
+ // Merge current FOCUSED state from edit engine.
+ if (mpText)
+ {
+ if (mpText->HaveFocus())
+ pStateSet->AddState (AccessibleStateType::FOCUSED);
+ else
+ pStateSet->RemoveState (AccessibleStateType::FOCUSED);
+ }
+ //Just when the document is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
+ css::uno::Reference<XAccessible> xTempAcc = getAccessibleParent();
+ if( xTempAcc.is() )
+ {
+ css::uno::Reference<XAccessibleContext>
+ xTempAccContext = xTempAcc->getAccessibleContext();
+ if( xTempAccContext.is() )
+ {
+ css::uno::Reference<XAccessibleStateSet> rState =
+ xTempAccContext->getAccessibleStateSet();
+ if (rState.is())
+ {
+ const css::uno::Sequence<short> aStates = rState->getStates();
+ if (std::find(aStates.begin(), aStates.end(), AccessibleStateType::EDITABLE) != aStates.end())
+ {
+ pStateSet->AddState (AccessibleStateType::EDITABLE);
+ pStateSet->AddState (AccessibleStateType::RESIZABLE);
+ pStateSet->AddState (AccessibleStateType::MOVEABLE);
+ }
+ }
+ }
+ }
+
+ // Create a copy of the state set that may be modified by the
+ // caller without affecting the current state set.
+ Reference<XAccessibleStateSet> xStateSet(new ::utl::AccessibleStateSetHelper(*pStateSet));
+
+ if (mpParent && mpParent->IsDocumentSelAll())
+ {
+ ::utl::AccessibleStateSetHelper* pCopyStateSet =
+ static_cast<::utl::AccessibleStateSetHelper*>(xStateSet.get());
+ pCopyStateSet->AddState (AccessibleStateType::SELECTED);
+ }
+
+ return xStateSet;
+}
+
+// XAccessibleComponent
+/** The implementation below is at the moment straightforward. It iterates
+ over all children (and thereby instances all children which have not
+ been already instantiated) until a child covering the specified point is
+ found.
+ This leaves room for improvement. For instance, first iterate only over
+ the already instantiated children and only if no match is found
+ instantiate the remaining ones.
+*/
+uno::Reference<XAccessible > SAL_CALL
+ AccessibleShape::getAccessibleAtPoint (
+ const awt::Point& aPoint)
+{
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ sal_Int32 nChildCount = getAccessibleChildCount ();
+ for (sal_Int32 i=0; i<nChildCount; ++i)
+ {
+ Reference<XAccessible> xChild (getAccessibleChild (i));
+ if (xChild.is())
+ {
+ Reference<XAccessibleComponent> xChildComponent (
+ xChild->getAccessibleContext(), uno::UNO_QUERY);
+ if (xChildComponent.is())
+ {
+ awt::Rectangle aBBox (xChildComponent->getBounds());
+ if ( (aPoint.X >= aBBox.X)
+ && (aPoint.Y >= aBBox.Y)
+ && (aPoint.X < aBBox.X+aBBox.Width)
+ && (aPoint.Y < aBBox.Y+aBBox.Height) )
+ return xChild;
+ }
+ }
+ }
+
+ // Have not found a child under the given point. Returning empty
+ // reference to indicate this.
+ return uno::Reference<XAccessible>();
+}
+
+
+awt::Rectangle SAL_CALL AccessibleShape::getBounds()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ ThrowIfDisposed ();
+ awt::Rectangle aBoundingBox;
+ if ( mxShape.is() )
+ {
+
+ static constexpr OUStringLiteral sBoundRectName = u"BoundRect";
+ static constexpr OUStringLiteral sAnchorPositionName = u"AnchorPosition";
+
+ // Get the shape's bounding box in internal coordinates (in 100th of
+ // mm). Use the property BoundRect. Only if that is not supported ask
+ // the shape for its position and size directly.
+ Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
+ Reference<beans::XPropertySetInfo> xSetInfo;
+ bool bFoundBoundRect = false;
+ if (xSet.is())
+ {
+ xSetInfo = xSet->getPropertySetInfo ();
+ if (xSetInfo.is())
+ {
+ if (xSetInfo->hasPropertyByName (sBoundRectName))
+ {
+ try
+ {
+ uno::Any aValue = xSet->getPropertyValue (sBoundRectName);
+ aValue >>= aBoundingBox;
+ bFoundBoundRect = true;
+ }
+ catch (beans::UnknownPropertyException const&)
+ {
+ // Handled below (bFoundBoundRect stays false).
+ }
+ }
+ else
+ SAL_WARN("svx", "no property BoundRect");
+ }
+ }
+
+ // Fallback when there is no BoundRect Property.
+ if ( ! bFoundBoundRect )
+ {
+ awt::Point aPosition (mxShape->getPosition());
+ awt::Size aSize (mxShape->getSize());
+ aBoundingBox = awt::Rectangle (
+ aPosition.X, aPosition.Y,
+ aSize.Width, aSize.Height);
+
+ // While BoundRects have absolute positions, the position returned
+ // by XPosition::getPosition is relative. Get the anchor position
+ // (usually not (0,0) for Writer shapes).
+ if (xSetInfo.is())
+ {
+ if (xSetInfo->hasPropertyByName (sAnchorPositionName))
+ {
+ uno::Any aPos = xSet->getPropertyValue (sAnchorPositionName);
+ awt::Point aAnchorPosition;
+ aPos >>= aAnchorPosition;
+ aBoundingBox.X += aAnchorPosition.X;
+ aBoundingBox.Y += aAnchorPosition.Y;
+ }
+ }
+ }
+
+ // Transform coordinates from internal to pixel.
+ if (maShapeTreeInfo.GetViewForwarder() == nullptr)
+ throw uno::RuntimeException (
+ "AccessibleShape has no valid view forwarder",
+ static_cast<uno::XWeak*>(this));
+ ::Size aPixelSize = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
+ ::Size (aBoundingBox.Width, aBoundingBox.Height));
+ ::Point aPixelPosition = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
+ ::Point (aBoundingBox.X, aBoundingBox.Y));
+
+ // Clip the shape's bounding box with the bounding box of its parent.
+ Reference<XAccessibleComponent> xParentComponent (
+ getAccessibleParent(), uno::UNO_QUERY);
+ if (xParentComponent.is())
+ {
+ // Make the coordinates relative to the parent.
+ awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
+ int x = aPixelPosition.getX() - aParentLocation.X;
+ int y = aPixelPosition.getY() - aParentLocation.Y;
+
+ // Clip with parent (with coordinates relative to itself).
+ ::tools::Rectangle aBBox (
+ x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
+ awt::Size aParentSize (xParentComponent->getSize());
+ ::tools::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
+ aBBox = aBBox.GetIntersection (aParentBBox);
+ aBoundingBox = awt::Rectangle (
+ aBBox.Left(),
+ aBBox.Top(),
+ aBBox.getWidth(),
+ aBBox.getHeight());
+ }
+ else
+ {
+ SAL_INFO("svx", "parent does not support component");
+ aBoundingBox = awt::Rectangle (
+ aPixelPosition.getX(), aPixelPosition.getY(),
+ aPixelSize.getWidth(), aPixelSize.getHeight());
+ }
+ }
+
+ return aBoundingBox;
+}
+
+
+awt::Point SAL_CALL AccessibleShape::getLocation()
+{
+ ThrowIfDisposed ();
+ awt::Rectangle aBoundingBox (getBounds());
+ return awt::Point (aBoundingBox.X, aBoundingBox.Y);
+}
+
+
+awt::Point SAL_CALL AccessibleShape::getLocationOnScreen()
+{
+ ThrowIfDisposed ();
+
+ // Get relative position...
+ awt::Point aLocation (getLocation ());
+
+ // ... and add absolute position of the parent.
+ uno::Reference<XAccessibleComponent> xParentComponent (
+ getAccessibleParent(), uno::UNO_QUERY);
+ if (xParentComponent.is())
+ {
+ awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
+ aLocation.X += aParentLocation.X;
+ aLocation.Y += aParentLocation.Y;
+ }
+ else
+ SAL_WARN("svx", "parent does not support XAccessibleComponent");
+ return aLocation;
+}
+
+
+awt::Size SAL_CALL AccessibleShape::getSize()
+{
+ ThrowIfDisposed ();
+ awt::Rectangle aBoundingBox (getBounds());
+ return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
+}
+
+
+sal_Int32 SAL_CALL AccessibleShape::getForeground()
+{
+ ThrowIfDisposed ();
+ sal_Int32 nColor (0x0ffffffL);
+
+ try
+ {
+ uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
+ if (aSet.is())
+ {
+ uno::Any aColor;
+ aColor = aSet->getPropertyValue ("LineColor");
+ aColor >>= nColor;
+ }
+ }
+ catch (const css::beans::UnknownPropertyException &)
+ {
+ // Ignore exception and return default color.
+ }
+ return nColor;
+}
+
+
+sal_Int32 SAL_CALL AccessibleShape::getBackground()
+{
+ ThrowIfDisposed ();
+ Color nColor;
+
+ try
+ {
+ uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
+ if (aSet.is())
+ {
+ uno::Any aColor;
+ aColor = aSet->getPropertyValue ("FillColor");
+ aColor >>= nColor;
+ aColor = aSet->getPropertyValue ("FillTransparence");
+ short nTrans=0;
+ aColor >>= nTrans;
+ Color crBk(nColor);
+ if (nTrans == 0 )
+ {
+ crBk.SetAlpha(0);
+ }
+ else
+ {
+ nTrans = short(256 - nTrans / 100. * 256);
+ crBk.SetAlpha(255 - sal_uInt8(nTrans));
+ }
+ nColor = crBk;
+ }
+ }
+ catch (const css::beans::UnknownPropertyException &)
+ {
+ // Ignore exception and return default color.
+ }
+ return sal_Int32(nColor);
+}
+
+// XAccessibleEventBroadcaster
+void SAL_CALL AccessibleShape::addAccessibleEventListener (
+ const Reference<XAccessibleEventListener >& rxListener)
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ {
+ uno::Reference<uno::XInterface> xThis (
+ static_cast<lang::XComponent *>(this), uno::UNO_QUERY);
+ rxListener->disposing (lang::EventObject (xThis));
+ }
+ else
+ {
+ AccessibleContextBase::addAccessibleEventListener (rxListener);
+ if (mpText != nullptr)
+ mpText->AddEventListener (rxListener);
+ }
+}
+
+
+void SAL_CALL AccessibleShape::removeAccessibleEventListener (
+ const Reference<XAccessibleEventListener >& rxListener)
+{
+ AccessibleContextBase::removeAccessibleEventListener (rxListener);
+ if (mpText != nullptr)
+ mpText->RemoveEventListener (rxListener);
+}
+
+// XInterface
+css::uno::Any SAL_CALL
+ AccessibleShape::queryInterface (const css::uno::Type & rType)
+{
+ css::uno::Any aReturn = AccessibleContextBase::queryInterface (rType);
+ if ( ! aReturn.hasValue())
+ aReturn = ::cppu::queryInterface (rType,
+ static_cast<XAccessibleComponent*>(this),
+ static_cast<XAccessibleExtendedComponent*>(this),
+ static_cast< css::accessibility::XAccessibleSelection* >(this),
+ static_cast< css::accessibility::XAccessibleExtendedAttributes* >(this),
+ static_cast<document::XShapeEventListener*>(this),
+ static_cast<lang::XUnoTunnel*>(this),
+ static_cast<XAccessibleGroupPosition*>(this),
+ static_cast<XAccessibleHypertext*>(this)
+ );
+ return aReturn;
+}
+
+
+void SAL_CALL
+ AccessibleShape::acquire()
+ noexcept
+{
+ AccessibleContextBase::acquire ();
+}
+
+
+void SAL_CALL
+ AccessibleShape::release()
+ noexcept
+{
+ AccessibleContextBase::release ();
+}
+
+// XAccessibleSelection
+void SAL_CALL AccessibleShape::selectAccessibleChild( sal_Int32 )
+{
+}
+
+
+sal_Bool SAL_CALL AccessibleShape::isAccessibleChildSelected( sal_Int32 nChildIndex )
+{
+ uno::Reference<XAccessible> xAcc = getAccessibleChild( nChildIndex );
+ uno::Reference<XAccessibleContext> xContext;
+ if( xAcc.is() )
+ {
+ xContext = xAcc->getAccessibleContext();
+ }
+
+ if( xContext.is() )
+ {
+ if( xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH )
+ {
+ uno::Reference< css::accessibility::XAccessibleText >
+ xText(xAcc, uno::UNO_QUERY);
+ if( xText.is() )
+ {
+ if( xText->getSelectionStart() >= 0 ) return true;
+ }
+ }
+ else if( xContext->getAccessibleRole() == AccessibleRole::SHAPE )
+ {
+ Reference< XAccessibleStateSet > pRState = xContext->getAccessibleStateSet();
+ if( !pRState.is() )
+ return false;
+
+ const uno::Sequence<short> aStates = pRState->getStates();
+ return std::find(aStates.begin(), aStates.end(), AccessibleStateType::SELECTED) != aStates.end();
+ }
+ }
+
+ return false;
+}
+
+
+void SAL_CALL AccessibleShape::clearAccessibleSelection( )
+{
+}
+
+
+void SAL_CALL AccessibleShape::selectAllAccessibleChildren( )
+{
+}
+
+
+sal_Int32 SAL_CALL AccessibleShape::getSelectedAccessibleChildCount()
+{
+ sal_Int32 nCount = 0;
+ sal_Int32 TotalCount = getAccessibleChildCount();
+ for( sal_Int32 i = 0; i < TotalCount; i++ )
+ if( isAccessibleChildSelected(i) ) nCount++;
+
+ return nCount;
+}
+
+
+Reference<XAccessible> SAL_CALL AccessibleShape::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
+{
+ if ( nSelectedChildIndex > getSelectedAccessibleChildCount() )
+ throw IndexOutOfBoundsException();
+ sal_Int32 i1, i2;
+ for( i1 = 0, i2 = 0; i1 < getAccessibleChildCount(); i1++ )
+ if( isAccessibleChildSelected(i1) )
+ {
+ if( i2 == nSelectedChildIndex )
+ return getAccessibleChild( i1 );
+ i2++;
+ }
+ return Reference<XAccessible>();
+}
+
+
+void SAL_CALL AccessibleShape::deselectAccessibleChild( sal_Int32 )
+{
+
+}
+
+// XAccessibleExtendedAttributes
+uno::Any SAL_CALL AccessibleShape::getExtendedAttributes()
+{
+ uno::Any strRet;
+ OUString style;
+ if( getAccessibleRole() != AccessibleRole::SHAPE ) return strRet;
+ if( m_pShape )
+ {
+ style = "style:" + GetStyle();
+ }
+ style += ";";
+ strRet <<= style;
+ return strRet;
+}
+
+// XServiceInfo
+OUString SAL_CALL
+ AccessibleShape::getImplementationName()
+{
+ return "AccessibleShape";
+}
+
+
+uno::Sequence<OUString> SAL_CALL
+ AccessibleShape::getSupportedServiceNames()
+{
+ ThrowIfDisposed ();
+ const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleShape" };
+ return comphelper::concatSequences(AccessibleContextBase::getSupportedServiceNames(), vals);
+}
+
+// XTypeProvider
+uno::Sequence<uno::Type> SAL_CALL
+ AccessibleShape::getTypes()
+{
+ ThrowIfDisposed ();
+ // Get list of types from the context base implementation, ...
+ uno::Sequence<uno::Type> aTypeList (AccessibleContextBase::getTypes());
+ // ... get list of types from component base implementation, ...
+ uno::Sequence<uno::Type> aComponentTypeList (AccessibleComponentBase::getTypes());
+ // ... define local types
+ uno::Sequence<uno::Type> localTypesList = {
+ cppu::UnoType<lang::XEventListener>::get(),
+ cppu::UnoType<document::XEventListener>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get()
+ };
+
+ return comphelper::concatSequences(aTypeList, aComponentTypeList, localTypesList);
+}
+
+// lang::XEventListener
+/** Disposing calls are accepted only from the model: Just reset the
+ reference to the model in the shape tree info. Otherwise this object
+ remains functional.
+*/
+void AccessibleShape::disposing (const lang::EventObject& aEvent)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ try
+ {
+ if (aEvent.Source == maShapeTreeInfo.GetModelBroadcaster())
+ {
+ // Remove reference to model broadcaster to allow it to pass
+ // away.
+ maShapeTreeInfo.SetModelBroadcaster(nullptr);
+ }
+
+ }
+ catch (uno::RuntimeException const&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "caught exception while disposing");
+ }
+}
+
+// document::XShapeEventListener
+void SAL_CALL
+ AccessibleShape::notifyShapeEvent (const document::EventObject& rEventObject)
+{
+ if (rEventObject.EventName != "ShapeModified")
+ return;
+
+ //Need to update text children when receiving ShapeModified hint when exiting edit mode for text box
+ if (mpText)
+ mpText->UpdateChildren();
+
+
+ // Some property of a shape has been modified. Send an event
+ // that indicates a change of the visible data to all listeners.
+ CommitChange (
+ AccessibleEventId::VISIBLE_DATA_CHANGED,
+ uno::Any(),
+ uno::Any());
+
+ // Name and Description may have changed. Update the local
+ // values accordingly.
+ UpdateNameAndDescription();
+}
+
+// lang::XUnoTunnel
+UNO3_GETIMPLEMENTATION_IMPL(AccessibleShape)
+
+// IAccessibleViewForwarderListener
+void AccessibleShape::ViewForwarderChanged()
+{
+ // Inform all listeners that the graphical representation (i.e. size
+ // and/or position) of the shape has changed.
+ CommitChange (AccessibleEventId::VISIBLE_DATA_CHANGED,
+ uno::Any(),
+ uno::Any());
+
+ // Tell children manager of the modified view forwarder.
+ if (mpChildrenManager != nullptr)
+ mpChildrenManager->ViewForwarderChanged();
+
+ // update our children that our screen position might have changed
+ if( mpText )
+ mpText->UpdateChildren();
+}
+
+// protected internal
+// Set this object's name if is different to the current name.
+OUString AccessibleShape::CreateAccessibleBaseName()
+{
+ return ShapeTypeHandler::CreateAccessibleBaseName( mxShape );
+}
+
+
+OUString AccessibleShape::CreateAccessibleName()
+{
+ return GetFullAccessibleName(this);
+}
+
+OUString AccessibleShape::GetFullAccessibleName (AccessibleShape *shape)
+{
+ OUString sName (shape->CreateAccessibleBaseName());
+ // Append the shape's index to the name to disambiguate between shapes
+ // of the same type. If such an index where not given to the
+ // constructor then use the z-order instead. If even that does not exist
+ // we throw an exception.
+ OUString nameStr;
+ if (shape->m_pShape)
+ nameStr = shape->m_pShape->GetName();
+ if (nameStr.isEmpty())
+ {
+ sName += " ";
+ }
+ else
+ {
+ sName = nameStr;
+ }
+
+ //If the new produced name if not the same with last,notify name changed
+ //Event
+ if (aAccName != sName && !aAccName.isEmpty())
+ {
+ uno::Any aOldValue, aNewValue;
+ aOldValue <<= aAccName;
+ aNewValue <<= sName;
+ CommitChange(
+ AccessibleEventId::NAME_CHANGED,
+ aNewValue,
+ aOldValue);
+ }
+ aAccName = sName;
+ return sName;
+}
+
+// protected
+void AccessibleShape::disposing()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ // Make sure to send an event that this object loses the focus in the
+ // case that it has the focus.
+ ::utl::AccessibleStateSetHelper* pStateSet = mxStateSet.get();
+ if (pStateSet != nullptr)
+ pStateSet->RemoveState (AccessibleStateType::FOCUSED);
+
+ // Unregister from model.
+ if (mxShape.is() && maShapeTreeInfo.GetModelBroadcaster().is())
+ maShapeTreeInfo.GetModelBroadcaster()->removeShapeEventListener(mxShape,
+ static_cast<document::XShapeEventListener*>(this));
+
+ // Release the child containers.
+ if (mpChildrenManager != nullptr)
+ {
+ mpChildrenManager.reset();
+ }
+ if (mpText != nullptr)
+ {
+ mpText->Dispose();
+ mpText.reset();
+ }
+
+ // Cleanup. Remove references to objects to allow them to be
+ // destroyed.
+ mxShape = nullptr;
+ maShapeTreeInfo.dispose();
+
+ // Call base classes.
+ AccessibleContextBase::dispose ();
+}
+
+sal_Int32 SAL_CALL
+ AccessibleShape::getAccessibleIndexInParent()
+{
+ ThrowIfDisposed ();
+ // Use a simple but slow solution for now. Optimize later.
+
+ sal_Int32 nIndex = m_nIndexInParent;
+ if ( -1 == nIndex )
+ nIndex = AccessibleContextBase::getAccessibleIndexInParent();
+ return nIndex;
+}
+
+
+void AccessibleShape::UpdateNameAndDescription()
+{
+ // Ignore missing title, name, or description. There are fallbacks for
+ // them.
+ try
+ {
+ Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY_THROW);
+
+ // Get the accessible name.
+ OUString sString = GetOptionalProperty(xSet, "Title");
+ if (!sString.isEmpty())
+ {
+ SetAccessibleName(sString, AccessibleContextBase::FromShape);
+ }
+ else
+ {
+ sString = GetOptionalProperty(xSet, "Name");
+ if (!sString.isEmpty())
+ SetAccessibleName(sString, AccessibleContextBase::FromShape);
+ }
+
+ // Get the accessible description.
+ sString = GetOptionalProperty(xSet, "Description");
+ if (!sString.isEmpty())
+ SetAccessibleDescription(sString, AccessibleContextBase::FromShape);
+ }
+ catch (uno::RuntimeException&)
+ {
+ }
+}
+
+// Return this object's role.
+sal_Int16 SAL_CALL AccessibleShape::getAccessibleRole()
+{
+ sal_Int16 nAccessibleRole = AccessibleRole::SHAPE ;
+ switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
+ {
+ case DRAWING_GRAPHIC_OBJECT:
+ nAccessibleRole = AccessibleRole::GRAPHIC ; break;
+ case DRAWING_OLE:
+ nAccessibleRole = AccessibleRole::EMBEDDED_OBJECT ; break;
+
+ default:
+ nAccessibleRole = AccessibleContextBase::getAccessibleRole();
+ break;
+ }
+
+ return nAccessibleRole;
+}
+
+namespace {
+
+//sort the drawing objects from up to down, from left to right
+struct XShapePosCompareHelper
+{
+ bool operator() ( const uno::Reference<drawing::XShape>& xshape1,
+ const uno::Reference<drawing::XShape>& xshape2 ) const
+ {
+ SdrObject* pObj1 = SdrObject::getSdrObjectFromXShape(xshape1);
+ SdrObject* pObj2 = SdrObject::getSdrObjectFromXShape(xshape2);
+ if(pObj1 && pObj2)
+ return pObj1->GetOrdNum() < pObj2->GetOrdNum();
+ else
+ return false;
+ }
+};
+
+}
+//end of group position
+
+// XAccessibleGroupPosition
+uno::Sequence< sal_Int32 > SAL_CALL
+AccessibleShape::getGroupPosition( const uno::Any& )
+{
+ // we will return the:
+ // [0] group level
+ // [1] similar items counts in the group
+ // [2] the position of the object in the group
+ uno::Sequence< sal_Int32 > aRet{ 0, 0, 0 };
+
+ css::uno::Reference<XAccessible> xParent = getAccessibleParent();
+ if (!xParent.is())
+ {
+ return aRet;
+ }
+ SdrObject *pObj = SdrObject::getSdrObjectFromXShape(mxShape);
+
+
+ if(pObj == nullptr )
+ {
+ return aRet;
+ }
+
+ // Compute object's group level.
+ sal_Int32 nGroupLevel = 0;
+ SdrObject * pUper = pObj->getParentSdrObjectFromSdrObject();
+ while( pUper )
+ {
+ ++nGroupLevel;
+ pUper = pUper->getParentSdrObjectFromSdrObject();
+ }
+
+ css::uno::Reference<XAccessibleContext> xParentContext = xParent->getAccessibleContext();
+ if( xParentContext->getAccessibleRole() == AccessibleRole::DOCUMENT ||
+ xParentContext->getAccessibleRole() == AccessibleRole::DOCUMENT_PRESENTATION ||
+ xParentContext->getAccessibleRole() == AccessibleRole::DOCUMENT_SPREADSHEET ||
+ xParentContext->getAccessibleRole() == AccessibleRole::DOCUMENT_TEXT )//Document
+ {
+ Reference< XAccessibleGroupPosition > xGroupPosition( xParent,uno::UNO_QUERY );
+ if ( xGroupPosition.is() )
+ {
+ aRet = xGroupPosition->getGroupPosition( uno::Any( getAccessibleContext() ) );
+ }
+ return aRet;
+ }
+ if (xParentContext->getAccessibleRole() != AccessibleRole::SHAPE)
+ {
+ return aRet;
+ }
+
+ SdrObjList *pGrpList = nullptr;
+ if( pObj->getParentSdrObjectFromSdrObject() )
+ pGrpList = pObj->getParentSdrObjectFromSdrObject()->GetSubList();
+ else
+ return aRet;
+
+ std::vector< uno::Reference<drawing::XShape> > vXShapes;
+ if (pGrpList)
+ {
+ const size_t nObj = pGrpList->GetObjCount();
+ for(size_t i = 0 ; i < nObj ; ++i)
+ {
+ SdrObject *pSubObj = pGrpList->GetObj(i);
+ if (pSubObj &&
+ xParentContext->getAccessibleChild(i)->getAccessibleContext()->getAccessibleRole() != AccessibleRole::GROUP_BOX)
+ {
+ vXShapes.push_back( GetXShapeForSdrObject(pSubObj) );
+ }
+ }
+ }
+
+ std::sort( vXShapes.begin(), vXShapes.end(), XShapePosCompareHelper() );
+
+ //get the index of the selected object in the group
+ //we start counting position from 1
+ sal_Int32 nPos = 1;
+ for ( const auto& rpShape : vXShapes )
+ {
+ if ( rpShape.get() == mxShape.get() )
+ {
+ sal_Int32* pArray = aRet.getArray();
+ pArray[0] = nGroupLevel;
+ pArray[1] = vXShapes.size();
+ pArray[2] = nPos;
+ break;
+ }
+ nPos++;
+ }
+
+ return aRet;
+}
+
+OUString AccessibleShape::getObjectLink( const uno::Any& )
+{
+ OUString aRet;
+
+ SdrObject *pObj = SdrObject::getSdrObjectFromXShape(mxShape);
+ if(pObj == nullptr )
+ {
+ return aRet;
+ }
+ if (maShapeTreeInfo.GetDocumentWindow().is())
+ {
+ Reference< XAccessibleGroupPosition > xGroupPosition( maShapeTreeInfo.GetDocumentWindow(), uno::UNO_QUERY );
+ if (xGroupPosition.is())
+ {
+ aRet = xGroupPosition->getObjectLink( uno::Any( getAccessibleContext() ) );
+ }
+ }
+ return aRet;
+}
+
+// XAccessibleHypertext
+sal_Int32 SAL_CALL AccessibleShape::getHyperLinkCount()
+{
+ // MT: Introduced with IA2 CWS, but SvxAccessibleHyperlink was redundant to svx::AccessibleHyperlink which we introduced meanwhile.
+ // Code need to be adapted...
+ return 0;
+
+ /*
+ SvxAccessibleHyperlink* pLink = new SvxAccessibleHyperlink(m_pShape,this);
+ if (pLink->IsValidHyperlink())
+ return 1;
+ else
+ return 0;
+ */
+}
+uno::Reference< XAccessibleHyperlink > SAL_CALL
+ AccessibleShape::getHyperLink( sal_Int32 )
+{
+ uno::Reference< XAccessibleHyperlink > xRet;
+ // MT: Introduced with IA2 CWS, but SvxAccessibleHyperlink was redundant to svx::AccessibleHyperlink which we introduced meanwhile.
+ // Code need to be adapted...
+ /*
+ SvxAccessibleHyperlink* pLink = new SvxAccessibleHyperlink(m_pShape,this);
+ if (pLink->IsValidHyperlink())
+ xRet = pLink;
+ if( !xRet.is() )
+ throw css::lang::IndexOutOfBoundsException();
+ */
+ return xRet;
+}
+sal_Int32 SAL_CALL AccessibleShape::getHyperLinkIndex( sal_Int32 )
+{
+ return 0;
+}
+// XAccessibleText
+sal_Int32 SAL_CALL AccessibleShape::getCaretPosition( ){return 0;}
+sal_Bool SAL_CALL AccessibleShape::setCaretPosition( sal_Int32 ){return false;}
+sal_Unicode SAL_CALL AccessibleShape::getCharacter( sal_Int32 ){return 0;}
+css::uno::Sequence< css::beans::PropertyValue > SAL_CALL AccessibleShape::getCharacterAttributes( sal_Int32, const css::uno::Sequence< OUString >& )
+{
+ uno::Sequence< css::beans::PropertyValue > aValues(0);
+ return aValues;
+}
+css::awt::Rectangle SAL_CALL AccessibleShape::getCharacterBounds( sal_Int32 )
+{
+ return css::awt::Rectangle(0, 0, 0, 0 );
+}
+sal_Int32 SAL_CALL AccessibleShape::getCharacterCount( ){return 0;}
+sal_Int32 SAL_CALL AccessibleShape::getIndexAtPoint( const css::awt::Point& ){return 0;}
+OUString SAL_CALL AccessibleShape::getSelectedText( ){return OUString();}
+sal_Int32 SAL_CALL AccessibleShape::getSelectionStart( ){return 0;}
+sal_Int32 SAL_CALL AccessibleShape::getSelectionEnd( ){return 0;}
+sal_Bool SAL_CALL AccessibleShape::setSelection( sal_Int32, sal_Int32 ){return true;}
+OUString SAL_CALL AccessibleShape::getText( ){return OUString();}
+OUString SAL_CALL AccessibleShape::getTextRange( sal_Int32, sal_Int32 ){return OUString();}
+css::accessibility::TextSegment SAL_CALL AccessibleShape::getTextAtIndex( sal_Int32, sal_Int16 )
+{
+ css::accessibility::TextSegment aResult;
+ return aResult;
+}
+css::accessibility::TextSegment SAL_CALL AccessibleShape::getTextBeforeIndex( sal_Int32, sal_Int16 )
+{
+ css::accessibility::TextSegment aResult;
+ return aResult;
+}
+css::accessibility::TextSegment SAL_CALL AccessibleShape::getTextBehindIndex( sal_Int32, sal_Int16 )
+{
+ css::accessibility::TextSegment aResult;
+ return aResult;
+}
+sal_Bool SAL_CALL AccessibleShape::copyText( sal_Int32, sal_Int32 ){return true;}
+sal_Bool SAL_CALL AccessibleShape::scrollSubstringTo( sal_Int32, sal_Int32, AccessibleScrollType ){return false;}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleShapeInfo.cxx b/svx/source/accessibility/AccessibleShapeInfo.cxx
new file mode 100644
index 000000000..7a70ca4d7
--- /dev/null
+++ b/svx/source/accessibility/AccessibleShapeInfo.cxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/AccessibleShapeInfo.hxx>
+
+
+namespace accessibility {
+
+AccessibleShapeInfo::AccessibleShapeInfo (
+ const css::uno::Reference<css::drawing::XShape>& rxShape,
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ IAccessibleParent* pChildrenManager)
+ : mxShape (rxShape),
+ mxParent (rxParent),
+ mpChildrenManager (pChildrenManager)
+{
+ // empty.
+}
+
+
+AccessibleShapeInfo::AccessibleShapeInfo (
+ const css::uno::Reference<css::drawing::XShape>& rxShape,
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent)
+ : mxShape (rxShape),
+ mxParent (rxParent),
+ mpChildrenManager (nullptr)
+{
+ // empty.
+}
+
+AccessibleShapeInfo::AccessibleShapeInfo (const AccessibleShapeInfo &rOther)
+ : mxShape (rOther.mxShape),
+ mxParent (rOther.mxParent),
+ mpChildrenManager (rOther.mpChildrenManager)
+{
+ // empty.
+}
+
+
+AccessibleShapeInfo::~AccessibleShapeInfo()
+{
+ // empty.
+}
+
+} // end of namespace accessibility.
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleShapeTreeInfo.cxx b/svx/source/accessibility/AccessibleShapeTreeInfo.cxx
new file mode 100644
index 000000000..df6136f94
--- /dev/null
+++ b/svx/source/accessibility/AccessibleShapeTreeInfo.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/AccessibleShapeTreeInfo.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+using ::com::sun::star::uno::Reference;
+
+namespace accessibility {
+
+AccessibleShapeTreeInfo::AccessibleShapeTreeInfo()
+ : mpView (nullptr),
+ mpWindow (nullptr),
+ mpViewForwarder (nullptr)
+{
+ // Empty.
+}
+
+
+AccessibleShapeTreeInfo::AccessibleShapeTreeInfo (const AccessibleShapeTreeInfo& rInfo)
+ : mxDocumentWindow (rInfo.mxDocumentWindow),
+ mxModelBroadcaster (rInfo.mxModelBroadcaster),
+ mpView (rInfo.mpView),
+ mxController (rInfo.mxController),
+ mpWindow (rInfo.mpWindow),
+ mpViewForwarder (rInfo.mpViewForwarder)
+{
+ // Empty.
+}
+
+void AccessibleShapeTreeInfo::dispose()
+{
+ mxDocumentWindow.clear();
+ mxModelBroadcaster.clear();
+ mpView = nullptr;
+ mxController.clear();
+ mpWindow.reset();
+ mpViewForwarder = nullptr;
+}
+
+AccessibleShapeTreeInfo& AccessibleShapeTreeInfo::operator= (const AccessibleShapeTreeInfo& rInfo)
+{
+ if ( this != &rInfo )
+ {
+ mxDocumentWindow = rInfo.mxDocumentWindow;
+ mxModelBroadcaster = rInfo.mxModelBroadcaster;
+ mpView = rInfo.mpView;
+ mxController = rInfo.mxController;
+ mpWindow = rInfo.mpWindow;
+ mpViewForwarder = rInfo.mpViewForwarder;
+ }
+ return *this;
+}
+
+AccessibleShapeTreeInfo::~AccessibleShapeTreeInfo()
+{
+ SolarMutexGuard g;
+ mpWindow.reset();
+}
+
+void AccessibleShapeTreeInfo::SetDocumentWindow (
+ const Reference<XAccessibleComponent>& rxDocumentWindow)
+{
+ if (mxDocumentWindow != rxDocumentWindow)
+ mxDocumentWindow = rxDocumentWindow;
+}
+
+void AccessibleShapeTreeInfo::SetModelBroadcaster (
+ const Reference<document::XShapeEventBroadcaster>& rxModelBroadcaster)
+{
+ mxModelBroadcaster = rxModelBroadcaster;
+}
+
+void AccessibleShapeTreeInfo::SetSdrView (SdrView* pView)
+{
+ mpView = pView;
+}
+
+void AccessibleShapeTreeInfo::SetController (
+ const Reference<frame::XController>& rxController)
+{
+ mxController = rxController;
+}
+
+void AccessibleShapeTreeInfo::SetWindow(vcl::Window* pDevice)
+{
+ mpWindow = pDevice;
+}
+
+void AccessibleShapeTreeInfo::SetViewForwarder (const IAccessibleViewForwarder* pViewForwarder)
+{
+ mpViewForwarder = pViewForwarder;
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleTextEventQueue.cxx b/svx/source/accessibility/AccessibleTextEventQueue.cxx
new file mode 100644
index 000000000..a39123c45
--- /dev/null
+++ b/svx/source/accessibility/AccessibleTextEventQueue.cxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "AccessibleTextEventQueue.hxx"
+
+#include <editeng/unoedhlp.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpntv.hxx>
+
+namespace accessibility
+{
+
+
+ // EventQueue implementation
+
+
+ AccessibleTextEventQueue::AccessibleTextEventQueue()
+ {
+ }
+
+ AccessibleTextEventQueue::~AccessibleTextEventQueue()
+ {
+ Clear();
+ }
+
+ void AccessibleTextEventQueue::Append( const SdrHint& rHint )
+ {
+ // only enqueue the events we actually care about in
+ // AccessibleTextHelper_Impl::ProcessQueue(), because
+ // the cost of some events adds up.
+ auto eKind = rHint.GetKind();
+ if (eKind == SdrHintKind::BeginEdit
+ || eKind == SdrHintKind::EndEdit)
+ maEventQueue.push_back( new SdrHint( rHint ) );
+ }
+
+ void AccessibleTextEventQueue::Append( const TextHint& rHint )
+ {
+ maEventQueue.push_back( new TextHint( rHint ) );
+ }
+
+ void AccessibleTextEventQueue::Append( const SvxViewChangedHint& rHint )
+ {
+ maEventQueue.push_back( new SvxViewChangedHint( rHint ) );
+ }
+
+ void AccessibleTextEventQueue::Append( const SvxEditSourceHint& rHint )
+ {
+ maEventQueue.push_back( new SvxEditSourceHint( rHint ) );
+ }
+
+ ::std::unique_ptr< SfxHint > AccessibleTextEventQueue::PopFront()
+ {
+ ::std::unique_ptr< SfxHint > aRes( *(maEventQueue.begin()) );
+ maEventQueue.pop_front();
+ return aRes;
+ }
+
+ bool AccessibleTextEventQueue::IsEmpty() const
+ {
+ return maEventQueue.empty();
+ }
+
+ void AccessibleTextEventQueue::Clear()
+ {
+ // clear queue
+ for( auto p : maEventQueue)
+ delete p;
+ maEventQueue.clear();
+ }
+
+} // end of namespace accessibility
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleTextEventQueue.hxx b/svx/source/accessibility/AccessibleTextEventQueue.hxx
new file mode 100644
index 000000000..23dbf9faa
--- /dev/null
+++ b/svx/source/accessibility/AccessibleTextEventQueue.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_ACCESSIBILITY_ACCESSIBLETEXTEVENTQUEUE_HXX
+#define INCLUDED_SVX_SOURCE_ACCESSIBILITY_ACCESSIBLETEXTEVENTQUEUE_HXX
+
+#include <memory>
+#include <deque>
+#include <algorithm>
+
+class SfxHint;
+class SdrHint;
+class TextHint;
+class SvxViewChangedHint;
+class SvxEditSourceHint;
+
+namespace accessibility
+{
+ /** This class handles the notification events for the
+ AccessibleTextHelper class.
+
+ For various reasons, we cannot process EditEngine events as
+ they arrive, but have to queue and handle them in a batch.
+ */
+ class AccessibleTextEventQueue
+ {
+ public:
+ typedef ::std::deque< SfxHint* > EventQueue;
+
+ AccessibleTextEventQueue();
+ ~AccessibleTextEventQueue();
+
+ /// Append event to end of queue
+ void Append( const SdrHint& rHint );
+ /// Append event to end of queue
+ void Append( const TextHint& rHint );
+ /// Append event to end of queue
+ void Append( const SvxViewChangedHint& rHint );
+ /// Append event to end of queue
+ void Append( const SvxEditSourceHint& rHint );
+
+ /** Pop first queue element
+
+ return first queue element, ownership transfers to caller
+ */
+ ::std::unique_ptr< SfxHint > PopFront();
+
+ /** Apply functor to every queue member
+
+ @param rFunctor
+ Functor to apply. Functor receives queue element as
+ parameter: void func( const SfxHint* );
+ */
+ template < typename Functor > void ForEach( Functor& rFunctor ) const
+ {
+ // #109864# Make sure results are put back into rFunctor
+ rFunctor = ::std::for_each( maEventQueue.begin(), maEventQueue.end(), rFunctor );
+ }
+
+ /// Query whether queue is empty
+ bool IsEmpty() const;
+
+ /// Clear event queue
+ void Clear();
+
+ private:
+ EventQueue maEventQueue;
+ };
+
+} // end of namespace accessibility
+
+#endif // INCLUDED_SVX_SOURCE_ACCESSIBILITY_ACCESSIBLETEXTEVENTQUEUE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/AccessibleTextHelper.cxx b/svx/source/accessibility/AccessibleTextHelper.cxx
new file mode 100644
index 000000000..809bd25d3
--- /dev/null
+++ b/svx/source/accessibility/AccessibleTextHelper.cxx
@@ -0,0 +1,1779 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstdlib>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <algorithm>
+#include <sal/log.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <comphelper/accessibleeventnotifier.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/textdata.hxx>
+#include <vcl/unohelp.hxx>
+
+
+// Project-local header
+
+
+#include "AccessibleTextEventQueue.hxx"
+#include <svx/AccessibleTextHelper.hxx>
+
+#include <editeng/unoedhlp.hxx>
+#include <editeng/unoedprx.hxx>
+#include <editeng/AccessibleParaManager.hxx>
+#include <editeng/AccessibleEditableTextPara.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpntv.hxx>
+#include <cell.hxx>
+#include "../table/accessiblecell.hxx"
+#include <editeng/editdata.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+namespace accessibility
+{
+
+// AccessibleTextHelper_Impl declaration
+
+ template < typename first_type, typename second_type >
+ static ::std::pair< first_type, second_type > makeSortedPair( first_type first,
+ second_type second )
+ {
+ if( first > second )
+ return ::std::make_pair( second, first );
+ else
+ return ::std::make_pair( first, second );
+ }
+
+ class AccessibleTextHelper_Impl : public SfxListener
+ {
+ public:
+ typedef ::std::vector< sal_Int16 > VectorOfStates;
+
+ // receive pointer to our frontend class and view window
+ AccessibleTextHelper_Impl();
+ virtual ~AccessibleTextHelper_Impl() override;
+
+ // XAccessibleContext child handling methods
+ sal_Int32 getAccessibleChildCount() const;
+ uno::Reference< XAccessible > getAccessibleChild( sal_Int32 i );
+
+ // XAccessibleEventBroadcaster child related methods
+ void addAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener );
+ void removeAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener );
+
+ // XAccessibleComponent child related methods
+ uno::Reference< XAccessible > getAccessibleAtPoint( const awt::Point& aPoint );
+
+ SvxEditSourceAdapter& GetEditSource() const;
+
+ void SetEditSource( ::std::unique_ptr< SvxEditSource > && pEditSource );
+
+ void SetEventSource( const uno::Reference< XAccessible >& rInterface )
+ {
+ mxFrontEnd = rInterface;
+ }
+
+ void SetOffset( const Point& );
+ Point GetOffset() const
+ {
+ std::scoped_lock aGuard( maMutex ); Point aPoint( maOffset );
+ return aPoint;
+ }
+
+ void SetStartIndex( sal_Int32 nOffset );
+ sal_Int32 GetStartIndex() const
+ {
+ // Strictly correct only with locked solar mutex, // but
+ // here we rely on the fact that sal_Int32 access is
+ // atomic
+ return mnStartIndex;
+ }
+
+ void SetAdditionalChildStates( VectorOfStates&& rChildStates );
+
+ void Dispose();
+
+ // do NOT hold object mutex when calling this! Danger of deadlock
+ void FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue = uno::Any(), const uno::Any& rOldValue = uno::Any() ) const;
+ void FireEvent( const AccessibleEventObject& rEvent ) const;
+
+ void SetFocus( bool bHaveFocus );
+ bool HaveFocus() const
+ {
+ // No locking of solar mutex here, since we rely on the fact
+ // that sal_Bool access is atomic
+ return mbThisHasFocus;
+ }
+ void SetChildFocus( sal_Int32 nChild, bool bHaveFocus );
+ void SetShapeFocus( bool bHaveFocus );
+ void ChangeChildFocus( sal_Int32 nNewChild );
+
+#ifdef DBG_UTIL
+ void CheckInvariants() const;
+#endif
+
+ // checks all children for visibility, throws away invisible ones
+ void UpdateVisibleChildren( bool bBroadcastEvents=true );
+
+ // check all children for changes in position and size
+ void UpdateBoundRect();
+
+ // calls SetSelection on the forwarder and updates maLastSelection
+ // cache.
+ void UpdateSelection();
+
+ private:
+
+ // Process event queue
+ void ProcessQueue();
+
+ // syntactic sugar for FireEvent
+ void GotPropertyEvent( const uno::Any& rNewValue, const sal_Int16 nEventId ) const { FireEvent( nEventId, rNewValue ); }
+
+ // shutdown usage of current edit source on myself and the children.
+ void ShutdownEditSource();
+
+ void ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast );
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ comphelper::AccessibleEventNotifier::TClientId getNotifierClientId() const { return mnNotifierClientId; }
+
+ // lock solar mutex before
+ SvxTextForwarder& GetTextForwarder() const;
+ // lock solar mutex before
+ SvxViewForwarder& GetViewForwarder() const;
+ // lock solar mutex before
+ SvxEditViewForwarder& GetEditViewForwarder() const;
+
+ // are we in edit mode?
+ bool IsActive() const;
+
+ // our frontend class (the one implementing the actual
+ // interface). That's not necessarily the one containing the impl
+ // pointer!
+ uno::Reference< XAccessible > mxFrontEnd;
+
+ // a wrapper for the text forwarders (guarded by solar mutex)
+ mutable SvxEditSourceAdapter maEditSource;
+
+ // store last selection (to correctly report selection changes, guarded by solar mutex)
+ ESelection maLastSelection;
+
+ // cache range of visible children (guarded by solar mutex)
+ sal_Int32 mnFirstVisibleChild;
+ sal_Int32 mnLastVisibleChild;
+
+ // offset to add to all our children (unguarded, relying on
+ // the fact that sal_Int32 access is atomic)
+ sal_Int32 mnStartIndex;
+
+ // the object handling our children (guarded by solar mutex)
+ ::accessibility::AccessibleParaManager maParaManager;
+
+ // Queued events from Notify() (guarded by solar mutex)
+ AccessibleTextEventQueue maEventQueue;
+
+ // spin lock to prevent notify in notify (guarded by solar mutex)
+ bool mbInNotify;
+
+ // whether the object or its children has the focus set (guarded by solar mutex)
+ bool mbGroupHasFocus;
+
+ // whether we (this object) has the focus set (guarded by solar mutex)
+ bool mbThisHasFocus;
+
+ mutable std::mutex maMutex;
+
+ /// our current offset to the containing shape/cell (guarded by maMutex)
+ Point maOffset;
+
+ /// client Id from AccessibleEventNotifier
+ comphelper::AccessibleEventNotifier::TClientId mnNotifierClientId;
+ static constexpr comphelper::AccessibleEventNotifier::TClientId snNotifierClientRevoked
+ = std::numeric_limits<comphelper::AccessibleEventNotifier::TClientId>::max();
+ };
+
+ AccessibleTextHelper_Impl::AccessibleTextHelper_Impl() :
+ maLastSelection( EE_PARA_NOT_FOUND,EE_INDEX_NOT_FOUND,EE_PARA_NOT_FOUND,EE_INDEX_NOT_FOUND ),
+ mnFirstVisibleChild( -1 ),
+ mnLastVisibleChild( -2 ),
+ mnStartIndex( 0 ),
+ mbInNotify( false ),
+ mbGroupHasFocus( false ),
+ mbThisHasFocus( false ),
+ maOffset(0,0),
+ // well, that's strictly exception safe, though not really
+ // robust. We rely on the fact that this member is constructed
+ // last, and that the constructor body is empty, thus no
+ // chance for exceptions once the Id is fetched. Nevertheless,
+ // normally should employ RAII here...
+ mnNotifierClientId(::comphelper::AccessibleEventNotifier::registerClient())
+ {
+ SAL_INFO("svx", "received ID: " << mnNotifierClientId );
+ }
+
+ AccessibleTextHelper_Impl::~AccessibleTextHelper_Impl()
+ {
+ SolarMutexGuard aGuard;
+
+ try
+ {
+ // call Dispose here, too, since we've some resources not
+ // automatically freed otherwise
+ Dispose();
+ }
+ catch( const uno::Exception& ) {}
+ }
+
+ SvxTextForwarder& AccessibleTextHelper_Impl::GetTextForwarder() const
+ {
+ if( !maEditSource.IsValid() )
+ throw uno::RuntimeException("Unknown edit source", mxFrontEnd);
+
+ SvxTextForwarder* pTextForwarder = maEditSource.GetTextForwarder();
+
+ if( !pTextForwarder )
+ throw uno::RuntimeException("Unable to fetch text forwarder, model might be dead", mxFrontEnd);
+
+ if( !pTextForwarder->IsValid() )
+ throw uno::RuntimeException("Text forwarder is invalid, model might be dead", mxFrontEnd);
+
+ return *pTextForwarder;
+ }
+
+ SvxViewForwarder& AccessibleTextHelper_Impl::GetViewForwarder() const
+ {
+ if( !maEditSource.IsValid() )
+ throw uno::RuntimeException("Unknown edit source", mxFrontEnd);
+
+ SvxViewForwarder* pViewForwarder = maEditSource.GetViewForwarder();
+
+ if( !pViewForwarder )
+ throw uno::RuntimeException("Unable to fetch view forwarder, model might be dead", mxFrontEnd);
+
+ if( !pViewForwarder->IsValid() )
+ throw uno::RuntimeException("View forwarder is invalid, model might be dead", mxFrontEnd);
+
+ return *pViewForwarder;
+ }
+
+ SvxEditViewForwarder& AccessibleTextHelper_Impl::GetEditViewForwarder() const
+ {
+ if( !maEditSource.IsValid() )
+ throw uno::RuntimeException("Unknown edit source", mxFrontEnd);
+
+ SvxEditViewForwarder* pViewForwarder = maEditSource.GetEditViewForwarder();
+
+ if( !pViewForwarder )
+ {
+ throw uno::RuntimeException("No edit view forwarder, object not in edit mode", mxFrontEnd);
+ }
+
+ if( !pViewForwarder->IsValid() )
+ {
+ throw uno::RuntimeException("View forwarder is invalid, object not in edit mode", mxFrontEnd);
+ }
+
+ return *pViewForwarder;
+ }
+
+ SvxEditSourceAdapter& AccessibleTextHelper_Impl::GetEditSource() const
+ {
+ if( !maEditSource.IsValid() )
+ throw uno::RuntimeException("AccessibleTextHelper_Impl::GetEditSource: no edit source", mxFrontEnd );
+ return maEditSource;
+ }
+
+ namespace {
+
+ // functor for sending child events (no stand-alone function, they are maybe not inlined)
+ class AccessibleTextHelper_OffsetChildIndex
+ {
+ public:
+ explicit AccessibleTextHelper_OffsetChildIndex( sal_Int32 nDifference ) : mnDifference(nDifference) {}
+ void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
+ {
+ rPara.SetIndexInParent( rPara.GetIndexInParent() + mnDifference );
+ }
+
+ private:
+ const sal_Int32 mnDifference;
+ };
+
+ }
+
+ void AccessibleTextHelper_Impl::SetStartIndex( sal_Int32 nOffset )
+ {
+ sal_Int32 nOldOffset( mnStartIndex );
+
+ mnStartIndex = nOffset;
+
+ if( nOldOffset != nOffset )
+ {
+ // update children
+ AccessibleTextHelper_OffsetChildIndex aFunctor( nOffset - nOldOffset );
+
+ ::std::for_each( maParaManager.begin(), maParaManager.end(),
+ AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_OffsetChildIndex > (aFunctor) );
+ }
+ }
+
+ void AccessibleTextHelper_Impl::SetAdditionalChildStates( VectorOfStates&& rChildStates )
+ {
+ maParaManager.SetAdditionalChildStates( std::move(rChildStates) );
+ }
+
+ void AccessibleTextHelper_Impl::SetChildFocus( sal_Int32 nChild, bool bHaveFocus )
+ {
+ if( bHaveFocus )
+ {
+ if( mbThisHasFocus )
+ SetShapeFocus( false );
+
+ maParaManager.SetFocus( nChild );
+
+ // we just received the focus, also send caret event then
+ UpdateSelection();
+
+ SAL_INFO("svx", "Paragraph " << nChild << " received focus");
+ }
+ else
+ {
+ maParaManager.SetFocus( -1 );
+
+ SAL_INFO("svx", "Paragraph " << nChild << " lost focus");
+
+ if( mbGroupHasFocus )
+ SetShapeFocus( true );
+ }
+ }
+
+ void AccessibleTextHelper_Impl::ChangeChildFocus( sal_Int32 nNewChild )
+ {
+ if( mbThisHasFocus )
+ SetShapeFocus( false );
+
+ mbGroupHasFocus = true;
+ maParaManager.SetFocus( nNewChild );
+
+ SAL_INFO("svx", "Paragraph " << nNewChild << " received focus");
+ }
+
+ void AccessibleTextHelper_Impl::SetShapeFocus( bool bHaveFocus )
+ {
+ bool bOldFocus( mbThisHasFocus );
+
+ mbThisHasFocus = bHaveFocus;
+
+ if( bOldFocus == bHaveFocus )
+ return;
+
+ if( bHaveFocus )
+ {
+ if( mxFrontEnd.is() )
+ {
+ AccessibleCell* pAccessibleCell = dynamic_cast< AccessibleCell* > ( mxFrontEnd.get() );
+ if ( !pAccessibleCell )
+ GotPropertyEvent( uno::Any(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED );
+ else // the focus event on cell should be fired on table directly
+ {
+ AccessibleTableShape* pAccTable = pAccessibleCell->GetParentTable();
+ if (pAccTable)
+ pAccTable->SetStateDirectly(AccessibleStateType::FOCUSED);
+ }
+ }
+ SAL_INFO("svx", "Parent object received focus" );
+ }
+ else
+ {
+ // The focus state should be reset directly on table.
+ //LostPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED );
+ if( mxFrontEnd.is() )
+ {
+ AccessibleCell* pAccessibleCell = dynamic_cast< AccessibleCell* > ( mxFrontEnd.get() );
+ if ( !pAccessibleCell )
+ FireEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), uno::Any(AccessibleStateType::FOCUSED) );
+ else
+ {
+ AccessibleTableShape* pAccTable = pAccessibleCell->GetParentTable();
+ if (pAccTable)
+ pAccTable->ResetStateDirectly(AccessibleStateType::FOCUSED);
+ }
+ }
+ SAL_INFO("svx", "Parent object lost focus" );
+ }
+ }
+
+ void AccessibleTextHelper_Impl::SetFocus( bool bHaveFocus )
+ {
+ bool bOldFocus( mbGroupHasFocus );
+
+ mbGroupHasFocus = bHaveFocus;
+
+ if( IsActive() )
+ {
+ try
+ {
+ // find the one with the cursor and get/set focus accordingly
+ ESelection aSelection;
+ if( GetEditViewForwarder().GetSelection( aSelection ) )
+ SetChildFocus( aSelection.nEndPara, bHaveFocus );
+ }
+ catch( const uno::Exception& ) {}
+ }
+ else if( bOldFocus != bHaveFocus )
+ {
+ SetShapeFocus( bHaveFocus );
+ }
+
+ SAL_INFO("svx", "focus changed, Object " << this << ", state: " << (bHaveFocus ? "focused" : "not focused") );
+ }
+
+ bool AccessibleTextHelper_Impl::IsActive() const
+ {
+ try
+ {
+ SvxEditSource& rEditSource = GetEditSource();
+ SvxEditViewForwarder* pViewForwarder = rEditSource.GetEditViewForwarder();
+
+ if( !pViewForwarder )
+ return false;
+
+ if( mxFrontEnd.is() )
+ {
+ AccessibleCell* pAccessibleCell = dynamic_cast< AccessibleCell* > ( mxFrontEnd.get() );
+ if ( pAccessibleCell )
+ {
+ sdr::table::CellRef xCell = pAccessibleCell->getCellRef();
+ if ( xCell.is() )
+ return xCell->IsActiveCell();
+ }
+ }
+ return pViewForwarder->IsValid();
+ }
+ catch( const uno::RuntimeException& )
+ {
+ return false;
+ }
+ }
+
+ void AccessibleTextHelper_Impl::UpdateSelection()
+ {
+ try
+ {
+ ESelection aSelection;
+ if( GetEditViewForwarder().GetSelection( aSelection ) )
+ {
+ if( maLastSelection != aSelection &&
+ aSelection.nEndPara < maParaManager.GetNum() )
+ {
+ // #103998# Not that important, changed from assertion to trace
+ if( mbThisHasFocus )
+ {
+ SAL_INFO("svx", "Parent has focus!");
+ }
+
+ sal_Int32 nMaxValidParaIndex( GetTextForwarder().GetParagraphCount() - 1 );
+
+ // notify all affected paragraphs (TODO: may be suboptimal,
+ // since some paragraphs might stay selected)
+ if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND )
+ {
+ // Did the caret move from one paragraph to another?
+ // #100530# no caret events if not focused.
+ if( mbGroupHasFocus &&
+ maLastSelection.nEndPara != aSelection.nEndPara )
+ {
+ if( maLastSelection.nEndPara < maParaManager.GetNum() )
+ {
+ maParaManager.FireEvent( ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ),
+ ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex )+1,
+ AccessibleEventId::CARET_CHANGED,
+ uno::Any(static_cast<sal_Int32>(-1)),
+ uno::Any(maLastSelection.nEndPos) );
+ }
+
+ ChangeChildFocus( aSelection.nEndPara );
+
+ SAL_INFO(
+ "svx",
+ "focus changed, Object: " << this
+ << ", Paragraph: " << aSelection.nEndPara
+ << ", Last paragraph: "
+ << maLastSelection.nEndPara);
+ }
+ }
+
+ // #100530# no caret events if not focused.
+ if( mbGroupHasFocus )
+ {
+ uno::Any aOldCursor;
+
+ // #i13705# The old cursor can only contain valid
+ // values if it's the same paragraph!
+ if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND &&
+ maLastSelection.nEndPara == aSelection.nEndPara )
+ {
+ aOldCursor <<= maLastSelection.nEndPos;
+ }
+ else
+ {
+ aOldCursor <<= static_cast<sal_Int32>(-1);
+ }
+
+ maParaManager.FireEvent( aSelection.nEndPara,
+ aSelection.nEndPara+1,
+ AccessibleEventId::CARET_CHANGED,
+ uno::Any(aSelection.nEndPos),
+ aOldCursor );
+ }
+
+ SAL_INFO(
+ "svx",
+ "caret changed, Object: " << this << ", New pos: "
+ << aSelection.nEndPos << ", Old pos: "
+ << maLastSelection.nEndPos << ", New para: "
+ << aSelection.nEndPara << ", Old para: "
+ << maLastSelection.nEndPara);
+
+ // #108947# Sort new range before calling FireEvent
+ ::std::pair<sal_Int32, sal_Int32> sortedSelection(
+ makeSortedPair(::std::min( aSelection.nStartPara, nMaxValidParaIndex ),
+ ::std::min( aSelection.nEndPara, nMaxValidParaIndex ) ) );
+
+ // #108947# Sort last range before calling FireEvent
+ ::std::pair<sal_Int32, sal_Int32> sortedLastSelection(
+ makeSortedPair(::std::min( maLastSelection.nStartPara, nMaxValidParaIndex ),
+ ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ) ) );
+
+ // event TEXT_SELECTION_CHANGED has to be submitted. (#i27299#)
+ const sal_Int16 nTextSelChgEventId =
+ AccessibleEventId::TEXT_SELECTION_CHANGED;
+ // #107037# notify selection change
+ if( maLastSelection.nStartPara == EE_PARA_NOT_FOUND )
+ {
+ // last selection is undefined
+ // use method <ESelection::HasRange()> (#i27299#)
+ if ( aSelection.HasRange() )
+ {
+ // selection was undefined, now is on
+ maParaManager.FireEvent( sortedSelection.first,
+ sortedSelection.second+1,
+ nTextSelChgEventId );
+ }
+ }
+ else
+ {
+ // last selection is valid
+ // use method <ESelection::HasRange()> (#i27299#)
+ if ( maLastSelection.HasRange() &&
+ !aSelection.HasRange() )
+ {
+ // selection was on, now is empty
+ maParaManager.FireEvent( sortedLastSelection.first,
+ sortedLastSelection.second+1,
+ nTextSelChgEventId );
+ }
+ // use method <ESelection::HasRange()> (#i27299#)
+ else if( !maLastSelection.HasRange() &&
+ aSelection.HasRange() )
+ {
+ // selection was empty, now is on
+ maParaManager.FireEvent( sortedSelection.first,
+ sortedSelection.second+1,
+ nTextSelChgEventId );
+ }
+ // no event TEXT_SELECTION_CHANGED event, if new and
+ // last selection are empty. (#i27299#)
+ else if ( maLastSelection.HasRange() &&
+ aSelection.HasRange() )
+ {
+ // use sorted last and new selection
+ ESelection aTmpLastSel( maLastSelection );
+ aTmpLastSel.Adjust();
+ ESelection aTmpSel( aSelection );
+ aTmpSel.Adjust();
+ // first submit event for new and changed selection
+ sal_Int32 nPara = aTmpSel.nStartPara;
+ for ( ; nPara <= aTmpSel.nEndPara; ++nPara )
+ {
+ if ( nPara < aTmpLastSel.nStartPara ||
+ nPara > aTmpLastSel.nEndPara )
+ {
+ // new selection on paragraph <nPara>
+ maParaManager.FireEvent( nPara,
+ nTextSelChgEventId );
+ }
+ else
+ {
+ // check for changed selection on paragraph <nPara>
+ const sal_Int32 nParaStartPos =
+ nPara == aTmpSel.nStartPara
+ ? aTmpSel.nStartPos : 0;
+ const sal_Int32 nParaEndPos =
+ nPara == aTmpSel.nEndPara
+ ? aTmpSel.nEndPos : -1;
+ const sal_Int32 nLastParaStartPos =
+ nPara == aTmpLastSel.nStartPara
+ ? aTmpLastSel.nStartPos : 0;
+ const sal_Int32 nLastParaEndPos =
+ nPara == aTmpLastSel.nEndPara
+ ? aTmpLastSel.nEndPos : -1;
+ if ( nParaStartPos != nLastParaStartPos ||
+ nParaEndPos != nLastParaEndPos )
+ {
+ maParaManager.FireEvent(
+ nPara, nTextSelChgEventId );
+ }
+ }
+ }
+ // second submit event for 'old' selections
+ nPara = aTmpLastSel.nStartPara;
+ for ( ; nPara <= aTmpLastSel.nEndPara; ++nPara )
+ {
+ if ( nPara < aTmpSel.nStartPara ||
+ nPara > aTmpSel.nEndPara )
+ {
+ maParaManager.FireEvent( nPara,
+ nTextSelChgEventId );
+ }
+ }
+ }
+ }
+
+ maLastSelection = aSelection;
+ }
+ }
+ }
+ // no selection? no update actions
+ catch( const uno::RuntimeException& ) {}
+ }
+
+ void AccessibleTextHelper_Impl::ShutdownEditSource()
+ {
+ // This should only be called with solar mutex locked, i.e. from the main office thread
+
+ // This here is somewhat clumsy: As soon as our children have
+ // a NULL EditSource (maParaManager.SetEditSource()), they
+ // enter the disposed state and cannot be reanimated. Thus, it
+ // is unavoidable and a hard requirement to let go and create
+ // from scratch each and every child.
+
+ // invalidate children
+ maParaManager.Dispose();
+ maParaManager.SetNum(0);
+
+ // lost all children
+ if( mxFrontEnd.is() )
+ FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
+
+ // quit listen on stale edit source
+ if( maEditSource.IsValid() )
+ EndListening( maEditSource.GetBroadcaster() );
+
+ maEditSource.SetEditSource( ::std::unique_ptr< SvxEditSource >() );
+ }
+
+ void AccessibleTextHelper_Impl::SetEditSource( ::std::unique_ptr< SvxEditSource > && pEditSource )
+ {
+ // This should only be called with solar mutex locked, i.e. from the main office thread
+
+ // shutdown old edit source
+ ShutdownEditSource();
+
+ // set new edit source
+ maEditSource.SetEditSource( std::move(pEditSource) );
+
+ // init child vector to the current child count
+ if( maEditSource.IsValid() )
+ {
+ maParaManager.SetNum( GetTextForwarder().GetParagraphCount() );
+
+ // listen on new edit source
+ StartListening( maEditSource.GetBroadcaster() );
+
+ UpdateVisibleChildren();
+ }
+ }
+
+ void AccessibleTextHelper_Impl::SetOffset( const Point& rPoint )
+ {
+ // guard against non-atomic access to maOffset data structure
+ {
+ std::scoped_lock aGuard( maMutex );
+ maOffset = rPoint;
+ }
+
+ maParaManager.SetEEOffset( rPoint );
+
+ // in all cases, check visibility afterwards.
+ UpdateVisibleChildren();
+ UpdateBoundRect();
+ }
+
+ void AccessibleTextHelper_Impl::UpdateVisibleChildren( bool bBroadcastEvents )
+ {
+ try
+ {
+ SvxTextForwarder& rCacheTF = GetTextForwarder();
+ sal_Int32 nParas=rCacheTF.GetParagraphCount();
+
+ // GetTextForwarder might have replaced everything, update
+ // paragraph count in case it's outdated
+ maParaManager.SetNum( nParas );
+
+ mnFirstVisibleChild = -1;
+ mnLastVisibleChild = -2;
+
+ for( sal_Int32 nCurrPara=0; nCurrPara<nParas; ++nCurrPara )
+ {
+ if (nCurrPara == 0)
+ mnFirstVisibleChild = nCurrPara;
+ mnLastVisibleChild = nCurrPara;
+ if (mxFrontEnd.is() && bBroadcastEvents)
+ {
+ // child not yet created?
+ if (!maParaManager.HasCreatedChild(nCurrPara))
+ {
+ GotPropertyEvent( uno::Any( maParaManager.CreateChild( nCurrPara - mnFirstVisibleChild,
+ mxFrontEnd, GetEditSource(), nCurrPara ).first ),
+ AccessibleEventId::CHILD );
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ OSL_FAIL("AccessibleTextHelper_Impl::UpdateVisibleChildren error while determining visible children");
+
+ // something failed - currently no children
+ mnFirstVisibleChild = -1;
+ mnLastVisibleChild = -2;
+ maParaManager.SetNum(0);
+
+ // lost all children
+ if( bBroadcastEvents )
+ FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
+ }
+ }
+
+ void AccessibleTextHelper_Impl::UpdateBoundRect()
+ {
+ // send BOUNDRECT_CHANGED to affected children
+ for(auto it = maParaManager.begin(); it != maParaManager.end(); ++it)
+ {
+ ::accessibility::AccessibleParaManager::WeakChild& rChild = *it;
+ // retrieve hard reference from weak one
+ auto aHardRef( rChild.first.get() );
+
+ if( aHardRef.is() )
+ {
+ awt::Rectangle aNewRect = aHardRef->getBounds();
+ const awt::Rectangle& aOldRect = rChild.second;
+
+ if( aNewRect.X != aOldRect.X ||
+ aNewRect.Y != aOldRect.Y ||
+ aNewRect.Width != aOldRect.Width ||
+ aNewRect.Height != aOldRect.Height )
+ {
+ // visible data changed
+ aHardRef->FireEvent( AccessibleEventId::BOUNDRECT_CHANGED );
+
+ // update internal bounds
+ rChild = ::accessibility::AccessibleParaManager::WeakChild( rChild.first, aNewRect );
+ }
+ }
+ }
+ }
+
+#ifdef DBG_UTIL
+ void AccessibleTextHelper_Impl::CheckInvariants() const
+ {
+ if( mnFirstVisibleChild >= 0 &&
+ mnFirstVisibleChild > mnLastVisibleChild )
+ {
+ OSL_FAIL( "AccessibleTextHelper: range invalid" );
+ }
+ }
+#endif
+
+ namespace {
+
+ // functor for sending child events (no stand-alone function, they are maybe not inlined)
+ class AccessibleTextHelper_LostChildEvent
+ {
+ public:
+ explicit AccessibleTextHelper_LostChildEvent( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {}
+ void operator()( const ::accessibility::AccessibleParaManager::WeakChild& rPara )
+ {
+ // retrieve hard reference from weak one
+ auto aHardRef( rPara.first.get() );
+
+ if( aHardRef.is() )
+ mrImpl.FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::Any(css::uno::Reference<css::accessibility::XAccessible>(aHardRef)) );
+ }
+
+ private:
+ AccessibleTextHelper_Impl& mrImpl;
+ };
+
+ }
+
+ void AccessibleTextHelper_Impl::ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast )
+ {
+ const sal_Int32 nParas = GetTextForwarder().GetParagraphCount();
+
+ /* rotate paragraphs
+ * =================
+ *
+ * Three cases:
+ *
+ * 1.
+ * ... nParagraph ... nParam1 ... nParam2 ...
+ * |______________[xxxxxxxxxxx]
+ * becomes
+ * [xxxxxxxxxxx]|______________
+ *
+ * tail is 0
+ *
+ * 2.
+ * ... nParam1 ... nParagraph ... nParam2 ...
+ * [xxxxxxxxxxx|xxxxxxxxxxxxxx]____________
+ * becomes
+ * ____________[xxxxxxxxxxx|xxxxxxxxxxxxxx]
+ *
+ * tail is nParagraph - nParam1
+ *
+ * 3.
+ * ... nParam1 ... nParam2 ... nParagraph ...
+ * [xxxxxxxxxxx]___________|____________
+ * becomes
+ * ___________|____________[xxxxxxxxxxx]
+ *
+ * tail is nParam2 - nParam1
+ */
+
+ // sort nParagraph, nParam1 and nParam2 in ascending order, calc range
+ if( nMiddle < nFirst )
+ {
+ ::std::swap(nFirst, nMiddle);
+ }
+ else if( nMiddle < nLast )
+ {
+ nLast = nLast + nMiddle - nFirst;
+ }
+ else
+ {
+ ::std::swap(nMiddle, nLast);
+ nLast = nLast + nMiddle - nFirst;
+ }
+
+ if( !(nFirst < nParas && nMiddle < nParas && nLast < nParas) )
+ return;
+
+ // since we have no "paragraph index
+ // changed" event on UAA, remove
+ // [first,last] and insert again later (in
+ // UpdateVisibleChildren)
+
+ // maParaManager.Rotate( nFirst, nMiddle, nLast );
+
+ // send CHILD_EVENT to affected children
+ ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin();
+ ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin;
+
+ ::std::advance( begin, nFirst );
+ ::std::advance( end, nLast+1 );
+
+ // TODO: maybe optimize here in the following way. If the
+ // number of removed children exceeds a certain threshold,
+ // use InvalidateFlags::Children
+ AccessibleTextHelper_LostChildEvent aFunctor( *this );
+
+ ::std::for_each( begin, end, aFunctor );
+
+ maParaManager.Release(nFirst, nLast+1);
+ // should be no need for UpdateBoundRect, since all affected children are cleared.
+ }
+
+ namespace {
+
+ // functor for sending child events (no stand-alone function, they are maybe not inlined)
+ class AccessibleTextHelper_ChildrenTextChanged
+ {
+ public:
+ void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
+ {
+ rPara.TextChanged();
+ }
+ };
+
+ /** functor processing queue events
+
+ Reacts on SfxHintId::TextParaInserted/REMOVED events and stores
+ their content
+ */
+ class AccessibleTextHelper_QueueFunctor
+ {
+ public:
+ AccessibleTextHelper_QueueFunctor() :
+ mnParasChanged( 0 ),
+ mnParaIndex(-1),
+ mnHintId(SfxHintId::NONE)
+ {}
+ void operator()( const SfxHint* pEvent )
+ {
+ if( !pEvent || mnParasChanged == -1 )
+ return;
+
+ // determine hint type
+ const TextHint* pTextHint = dynamic_cast<const TextHint*>( pEvent );
+ const SvxEditSourceHint* pEditSourceHint = dynamic_cast<const SvxEditSourceHint*>( pEvent );
+
+ if( !(!pEditSourceHint && pTextHint &&
+ (pTextHint->GetId() == SfxHintId::TextParaInserted ||
+ pTextHint->GetId() == SfxHintId::TextParaRemoved )) )
+ return;
+
+ if( pTextHint->GetValue() == EE_PARA_ALL )
+ {
+ mnParasChanged = -1;
+ }
+ else
+ {
+ mnHintId = pTextHint->GetId();
+ mnParaIndex = pTextHint->GetValue();
+ ++mnParasChanged;
+ }
+ }
+
+ /** Query number of paragraphs changed during queue processing.
+
+ @return number of changed paragraphs, -1 for
+ "every paragraph changed"
+ */
+ sal_Int32 GetNumberOfParasChanged() const { return mnParasChanged; }
+ /** Query index of last added/removed paragraph
+
+ @return index of lastly added paragraphs, -1 for none
+ added so far.
+ */
+ sal_Int32 GetParaIndex() const { return mnParaIndex; }
+ /** Query hint id of last interesting event
+
+ @return hint id of last interesting event (REMOVED/INSERTED).
+ */
+ SfxHintId GetHintId() const { return mnHintId; }
+
+ private:
+ /** number of paragraphs changed during queue processing. -1 for
+ "every paragraph changed"
+ */
+ sal_Int32 mnParasChanged;
+ /// index of paragraph added/removed last
+ sal_Int32 mnParaIndex;
+ /// TextHint ID (removed/inserted) of last interesting event
+ SfxHintId mnHintId;
+ };
+
+ }
+
+ void AccessibleTextHelper_Impl::ProcessQueue()
+ {
+ // inspect queue for paragraph insert/remove events. If there
+ // is exactly _one_ of those in the queue, and the number of
+ // paragraphs has changed by exactly one, use that event to
+ // determine a priori which paragraph was added/removed. This
+ // is necessary, since I must sync right here with the
+ // EditEngine state (number of paragraphs etc.), since I'm
+ // potentially sending listener events right away.
+ AccessibleTextHelper_QueueFunctor aFunctor;
+ maEventQueue.ForEach( aFunctor );
+
+ const sal_Int32 nNewParas( GetTextForwarder().GetParagraphCount() );
+ const sal_Int32 nCurrParas( maParaManager.GetNum() );
+
+ // whether every paragraph already is updated (no need to
+ // repeat that later on, e.g. for PARA_MOVED events)
+ bool bEverythingUpdated( false );
+
+ if( std::abs( nNewParas - nCurrParas ) == 1 &&
+ aFunctor.GetNumberOfParasChanged() == 1 )
+ {
+ // #103483# Exactly one paragraph added/removed. This is
+ // the normal case, optimize event handling here.
+
+ if( aFunctor.GetHintId() == SfxHintId::TextParaInserted )
+ {
+ // update num of paras
+ maParaManager.SetNum( nNewParas );
+
+ // release everything from the insertion position until the end
+ maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas);
+
+ // TODO: Clarify whether this behaviour _really_ saves
+ // anybody anything!
+ // update children, _don't_ broadcast
+ UpdateVisibleChildren( false );
+ UpdateBoundRect();
+
+ // send insert event
+ // #109864# Enforce creation of this paragraph
+ try
+ {
+ GotPropertyEvent( uno::Any( getAccessibleChild( aFunctor.GetParaIndex() -
+ mnFirstVisibleChild + GetStartIndex() ) ),
+ AccessibleEventId::CHILD );
+ }
+ catch( const uno::Exception& )
+ {
+ OSL_FAIL("AccessibleTextHelper_Impl::ProcessQueue: could not create new paragraph");
+ }
+ }
+ else if( aFunctor.GetHintId() == SfxHintId::TextParaRemoved )
+ {
+ ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin();
+ ::std::advance( begin, aFunctor.GetParaIndex() );
+ ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin;
+ ::std::advance( end, 1 );
+
+ // #i61812# remember para to be removed for later notification
+ // AFTER the new state is applied (that after the para got removed)
+ ::uno::Reference< XAccessible > xPara(begin->first.get());
+
+ // release everything from the remove position until the end
+ maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas);
+
+ // update num of paras
+ maParaManager.SetNum( nNewParas );
+
+ // TODO: Clarify whether this behaviour _really_ saves
+ // anybody anything!
+ // update children, _don't_ broadcast
+ UpdateVisibleChildren( false );
+ UpdateBoundRect();
+
+ // #i61812# notification for removed para
+ if (xPara.is())
+ FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::Any( xPara) );
+ }
+#ifdef DBG_UTIL
+ else
+ OSL_FAIL("AccessibleTextHelper_Impl::ProcessQueue() invalid hint id");
+#endif
+ }
+ else if( nNewParas != nCurrParas )
+ {
+ // release all paras
+ maParaManager.Release(0, nCurrParas);
+
+ // update num of paras
+ maParaManager.SetNum( nNewParas );
+
+ // #109864# create from scratch, don't broadcast
+ UpdateVisibleChildren( false );
+ UpdateBoundRect();
+
+ // number of paragraphs somehow changed - but we have no
+ // chance determining how. Thus, throw away everything and
+ // create from scratch.
+ // (child events should be broadcast after the changes are done...)
+ FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN);
+
+ // no need for further updates later on
+ bEverythingUpdated = true;
+ }
+
+ bool bUpdatedBoundRectAndVisibleChildren(false);
+
+ while( !maEventQueue.IsEmpty() )
+ {
+ ::std::unique_ptr< SfxHint > pHint( maEventQueue.PopFront() );
+ if (pHint)
+ {
+ const SfxHint& rHint = *pHint;
+
+ // Note, if you add events here, you need to update the AccessibleTextEventQueue::Append
+ // code, because only the events we process here, are actually queued there.
+
+ try
+ {
+
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast< const SdrHint* >( &rHint );
+
+ switch( pSdrHint->GetKind() )
+ {
+ case SdrHintKind::BeginEdit:
+ {
+ if(!IsActive())
+ {
+ break;
+ }
+ // change children state
+ maParaManager.SetActive();
+
+ // per definition, edit mode text has the focus
+ SetFocus( true );
+ break;
+ }
+
+ case SdrHintKind::EndEdit:
+ {
+ // focused child now loses focus
+ ESelection aSelection;
+ if( GetEditViewForwarder().GetSelection( aSelection ) )
+ SetChildFocus( aSelection.nEndPara, false );
+
+ // change children state
+ maParaManager.SetActive( false );
+
+ maLastSelection = ESelection( EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND,
+ EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ else if( const SvxEditSourceHint* pEditSourceHint = dynamic_cast<const SvxEditSourceHint*>( &rHint ) )
+ {
+ switch( pEditSourceHint->GetId() )
+ {
+ case SfxHintId::EditSourceParasMoved:
+ {
+ DBG_ASSERT( pEditSourceHint->GetStartValue() < GetTextForwarder().GetParagraphCount() &&
+ pEditSourceHint->GetEndValue() < GetTextForwarder().GetParagraphCount(),
+ "AccessibleTextHelper_Impl::NotifyHdl: Invalid notification");
+
+ if( !bEverythingUpdated )
+ {
+ ParagraphsMoved(pEditSourceHint->GetStartValue(),
+ pEditSourceHint->GetValue(),
+ pEditSourceHint->GetEndValue());
+
+ // in all cases, check visibility afterwards.
+ UpdateVisibleChildren();
+ }
+ break;
+ }
+
+ case SfxHintId::EditSourceSelectionChanged:
+ // notify listeners
+ try
+ {
+ UpdateSelection();
+ }
+ // maybe we're not in edit mode (this is not an error)
+ catch( const uno::Exception& ) {}
+ break;
+ default: break;
+ }
+ }
+ else if( const TextHint* pTextHint = dynamic_cast<const TextHint*>( &rHint ) )
+ {
+ const sal_Int32 nParas = GetTextForwarder().GetParagraphCount();
+
+ switch( pTextHint->GetId() )
+ {
+ case SfxHintId::TextModified:
+ {
+ // notify listeners
+ sal_Int32 nPara( pTextHint->GetValue() );
+
+ // #108900# Delegate change event to children
+ AccessibleTextHelper_ChildrenTextChanged aNotifyChildrenFunctor;
+
+ if( nPara == EE_PARA_ALL )
+ {
+ // #108900# Call every child
+ ::std::for_each( maParaManager.begin(), maParaManager.end(),
+ AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) );
+ }
+ else
+ if( nPara < nParas )
+ {
+ // #108900# Call child at index nPara
+ ::std::for_each( maParaManager.begin()+nPara, maParaManager.begin()+nPara+1,
+ AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) );
+ }
+ break;
+ }
+
+ case SfxHintId::TextParaInserted:
+ // already happened above
+ break;
+
+ case SfxHintId::TextParaRemoved:
+ // already happened above
+ break;
+
+ case SfxHintId::TextHeightChanged:
+ // visibility changed, done below
+ break;
+
+ case SfxHintId::TextViewScrolled:
+ // visibility changed, done below
+ break;
+ default: break;
+ }
+
+ // in all cases, check visibility afterwards.
+ if (!bUpdatedBoundRectAndVisibleChildren)
+ {
+ UpdateVisibleChildren();
+ UpdateBoundRect();
+ bUpdatedBoundRectAndVisibleChildren = true;
+ }
+ }
+ else if ( dynamic_cast<const SvxViewChangedHint*>( &rHint ) )
+ {
+ // just check visibility
+ if (!bUpdatedBoundRectAndVisibleChildren)
+ {
+ UpdateVisibleChildren();
+ UpdateBoundRect();
+ bUpdatedBoundRectAndVisibleChildren = true;
+ }
+ }
+ // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above!
+ else if( rHint.GetId() == SfxHintId::Dying)
+ {
+ // edit source is dying under us, become defunc then
+ try
+ {
+ // make edit source inaccessible
+ // Note: cannot destroy it here, since we're called from there!
+ ShutdownEditSource();
+ }
+ catch( const uno::Exception& ) {}
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+ }
+
+ void AccessibleTextHelper_Impl::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+ {
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ // precondition: not in a recursion
+ if( mbInNotify )
+ return;
+
+ mbInNotify = true;
+
+ try
+ {
+ // Process notification event, arranged in order of likelihood of
+ // occurrence to avoid unnecessary dynamic_cast. Note that
+ // SvxEditSourceHint is derived from TextHint, so has to be checked
+ // before that.
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast< const SdrHint* >( &rHint );
+ // process drawing layer events right away, if not
+ // within an open EE notification frame. Otherwise,
+ // event processing would be delayed until next EE
+ // notification sequence.
+ maEventQueue.Append( *pSdrHint );
+ }
+ else if( const SvxViewChangedHint* pViewHint = dynamic_cast<const SvxViewChangedHint*>( &rHint ) )
+ {
+ // process visibility right away, if not within an
+ // open EE notification frame. Otherwise, event
+ // processing would be delayed until next EE
+ // notification sequence.
+ maEventQueue.Append( *pViewHint );
+ }
+ else if( const SvxEditSourceHint* pEditSourceHint = dynamic_cast<const SvxEditSourceHint*>( &rHint ) )
+ {
+ // EditEngine should emit TEXT_SELECTION_CHANGED events (#i27299#)
+ maEventQueue.Append( *pEditSourceHint );
+ }
+ else if( const TextHint* pTextHint = dynamic_cast<const TextHint*>( &rHint ) )
+ {
+ // EditEngine should emit TEXT_SELECTION_CHANGED events (#i27299#)
+ if(pTextHint->GetId() == SfxHintId::TextProcessNotifications)
+ ProcessQueue();
+ else
+ maEventQueue.Append( *pTextHint );
+ }
+ // it's VITAL to keep the SfxHint last! It's the base of the classes above!
+ else if( rHint.GetId() == SfxHintId::Dying )
+ {
+ // handle this event _at once_, because after that, objects are invalid
+ // edit source is dying under us, become defunc then
+ maEventQueue.Clear();
+ try
+ {
+ // make edit source inaccessible
+ // Note: cannot destroy it here, since we're called from there!
+ ShutdownEditSource();
+ }
+ catch( const uno::Exception& ) {}
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ mbInNotify = false;
+ }
+
+ mbInNotify = false;
+ }
+
+ void AccessibleTextHelper_Impl::Dispose()
+ {
+ if( getNotifierClientId() != snNotifierClientRevoked)
+ {
+ try
+ {
+ // #106234# Unregister from EventNotifier
+ ::comphelper::AccessibleEventNotifier::revokeClient( getNotifierClientId() );
+ SAL_INFO("svx", "disposed ID: " << mnNotifierClientId );
+ }
+ catch( const uno::Exception& ) {}
+
+ mnNotifierClientId = snNotifierClientRevoked;
+ }
+
+ try
+ {
+ // dispose children
+ maParaManager.Dispose();
+ }
+ catch( const uno::Exception& ) {}
+
+ // quit listen on stale edit source
+ if( maEditSource.IsValid() )
+ EndListening( maEditSource.GetBroadcaster() );
+
+ // clear references
+ maEditSource.SetEditSource( ::std::unique_ptr< SvxEditSource >() );
+ mxFrontEnd = nullptr;
+ }
+
+ void AccessibleTextHelper_Impl::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const
+ {
+ // -- object locked --
+ AccessibleEventObject aEvent;
+ {
+ std::scoped_lock aGuard(maMutex);
+
+ DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper::FireEvent: no event source set");
+
+ if (mxFrontEnd.is())
+ aEvent = AccessibleEventObject(mxFrontEnd->getAccessibleContext(), nEventId,
+ rNewValue, rOldValue);
+ else
+ aEvent = AccessibleEventObject(uno::Reference<uno::XInterface>(), nEventId,
+ rNewValue, rOldValue);
+
+ // no locking necessary, FireEvent internally copies listeners
+ // if someone removes/adds in between Further locking,
+ // actually, might lead to deadlocks, since we're calling out
+ // of this object
+ }
+ // -- until here --
+
+ FireEvent(aEvent);
+ }
+
+ void AccessibleTextHelper_Impl::FireEvent( const AccessibleEventObject& rEvent ) const
+ {
+ // #106234# Delegate to EventNotifier
+ if (getNotifierClientId() != snNotifierClientRevoked)
+ ::comphelper::AccessibleEventNotifier::addEvent( getNotifierClientId(), rEvent );
+ }
+
+ // XAccessibleContext
+ sal_Int32 AccessibleTextHelper_Impl::getAccessibleChildCount() const
+ {
+ return mnLastVisibleChild - mnFirstVisibleChild + 1;
+ }
+
+ uno::Reference< XAccessible > AccessibleTextHelper_Impl::getAccessibleChild( sal_Int32 i )
+ {
+ i -= GetStartIndex();
+
+ if( 0 > i || i >= getAccessibleChildCount() ||
+ GetTextForwarder().GetParagraphCount() <= i )
+ {
+ throw lang::IndexOutOfBoundsException("Invalid child index", mxFrontEnd);
+ }
+
+ DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper_Impl::UpdateVisibleChildren: no frontend set");
+
+ if( mxFrontEnd.is() )
+ return maParaManager.CreateChild( i, mxFrontEnd, GetEditSource(), mnFirstVisibleChild + i ).first;
+ else
+ return nullptr;
+ }
+
+ void AccessibleTextHelper_Impl::addAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
+ {
+ if( getNotifierClientId() != snNotifierClientRevoked )
+ ::comphelper::AccessibleEventNotifier::addEventListener( getNotifierClientId(), xListener );
+ }
+
+ void AccessibleTextHelper_Impl::removeAccessibleEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
+ {
+ if( getNotifierClientId() == snNotifierClientRevoked )
+ return;
+
+ const sal_Int32 nListenerCount = ::comphelper::AccessibleEventNotifier::removeEventListener( getNotifierClientId(), xListener );
+ if ( !nListenerCount )
+ {
+ // no listeners anymore
+ // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
+ // and at least to us not firing any events anymore, in case somebody calls
+ // NotifyAccessibleEvent, again
+ ::comphelper::AccessibleEventNotifier::TClientId nId( getNotifierClientId() );
+ mnNotifierClientId = snNotifierClientRevoked;
+ ::comphelper::AccessibleEventNotifier::revokeClient( nId );
+ }
+ }
+
+ uno::Reference< XAccessible > AccessibleTextHelper_Impl::getAccessibleAtPoint( const awt::Point& _aPoint )
+ {
+ // make given position relative
+ if( !mxFrontEnd.is() )
+ throw uno::RuntimeException("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid", mxFrontEnd );
+
+ uno::Reference< XAccessibleContext > xFrontEndContext = mxFrontEnd->getAccessibleContext();
+
+ if( !xFrontEndContext.is() )
+ throw uno::RuntimeException("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid", mxFrontEnd );
+
+ uno::Reference< XAccessibleComponent > xFrontEndComponent( xFrontEndContext, uno::UNO_QUERY_THROW );
+
+ // #103862# No longer need to make given position relative
+ Point aPoint( _aPoint.X, _aPoint.Y );
+
+ // respect EditEngine offset to surrounding shape/cell
+ aPoint -= GetOffset();
+
+ // convert to EditEngine coordinate system
+ SvxTextForwarder& rCacheTF = GetTextForwarder();
+ Point aLogPoint( GetViewForwarder().PixelToLogic( aPoint, rCacheTF.GetMapMode() ) );
+
+ // iterate over all visible children (including those not yet created)
+ sal_Int32 nChild;
+ for( nChild=mnFirstVisibleChild; nChild <= mnLastVisibleChild; ++nChild )
+ {
+ DBG_ASSERT(nChild >= 0,
+ "AccessibleTextHelper_Impl::getAccessibleAt: index value overflow");
+
+ tools::Rectangle aParaBounds( rCacheTF.GetParaBounds( nChild ) );
+
+ if( aParaBounds.Contains( aLogPoint ) )
+ return getAccessibleChild( nChild - mnFirstVisibleChild + GetStartIndex() );
+ }
+
+ // found none
+ return nullptr;
+ }
+
+
+ // AccessibleTextHelper implementation (simply forwards to impl)
+
+ AccessibleTextHelper::AccessibleTextHelper( ::std::unique_ptr< SvxEditSource > && pEditSource ) :
+ mpImpl( new AccessibleTextHelper_Impl() )
+ {
+ SolarMutexGuard aGuard;
+
+ SetEditSource( std::move(pEditSource) );
+ }
+
+ AccessibleTextHelper::~AccessibleTextHelper()
+ {
+ }
+
+ const SvxEditSource& AccessibleTextHelper::GetEditSource() const
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ const SvxEditSource& aEditSource = mpImpl->GetEditSource();
+
+ mpImpl->CheckInvariants();
+
+ return aEditSource;
+#else
+ return mpImpl->GetEditSource();
+#endif
+ }
+
+ void AccessibleTextHelper::SetEditSource( ::std::unique_ptr< SvxEditSource > && pEditSource )
+ {
+#ifdef DBG_UTIL
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->SetEditSource( std::move(pEditSource) );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ void AccessibleTextHelper::SetEventSource( const uno::Reference< XAccessible >& rInterface )
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->SetEventSource( rInterface );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ void AccessibleTextHelper::SetFocus( bool bHaveFocus )
+ {
+#ifdef DBG_UTIL
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->SetFocus( bHaveFocus );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ bool AccessibleTextHelper::HaveFocus()
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ bool bRet( mpImpl->HaveFocus() );
+
+ mpImpl->CheckInvariants();
+
+ return bRet;
+#else
+ return mpImpl->HaveFocus();
+#endif
+ }
+
+ void AccessibleTextHelper::SetOffset( const Point& rPoint )
+ {
+#ifdef DBG_UTIL
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->SetOffset( rPoint );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ void AccessibleTextHelper::SetStartIndex( sal_Int32 nOffset )
+ {
+#ifdef DBG_UTIL
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->SetStartIndex( nOffset );
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ sal_Int32 AccessibleTextHelper::GetStartIndex() const
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ sal_Int32 nOffset = mpImpl->GetStartIndex();
+
+ mpImpl->CheckInvariants();
+
+ return nOffset;
+#else
+ return mpImpl->GetStartIndex();
+#endif
+ }
+
+ void AccessibleTextHelper::SetAdditionalChildStates( VectorOfStates&& rChildStates )
+ {
+ mpImpl->SetAdditionalChildStates( std::move(rChildStates) );
+ }
+
+ void AccessibleTextHelper::UpdateChildren()
+ {
+#ifdef DBG_UTIL
+ // precondition: solar mutex locked
+ DBG_TESTSOLARMUTEX();
+
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->UpdateVisibleChildren();
+ mpImpl->UpdateBoundRect();
+
+ mpImpl->UpdateSelection();
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ void AccessibleTextHelper::Dispose()
+ {
+ // As Dispose calls ShutdownEditSource, which in turn
+ // deregisters as listener on the edit source, have to lock
+ // here
+ SolarMutexGuard aGuard;
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+
+ mpImpl->Dispose();
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+#endif
+ }
+
+ // XAccessibleContext
+ sal_Int32 AccessibleTextHelper::GetChildCount() const
+ {
+ SolarMutexGuard aGuard;
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ sal_Int32 nRet = mpImpl->getAccessibleChildCount();
+
+ mpImpl->CheckInvariants();
+
+ return nRet;
+#else
+ return mpImpl->getAccessibleChildCount();
+#endif
+ }
+
+ uno::Reference< XAccessible > AccessibleTextHelper::GetChild( sal_Int32 i )
+ {
+ SolarMutexGuard aGuard;
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ uno::Reference< XAccessible > xRet = mpImpl->getAccessibleChild( i );
+
+ mpImpl->CheckInvariants();
+
+ return xRet;
+#else
+ return mpImpl->getAccessibleChild( i );
+#endif
+ }
+
+ void AccessibleTextHelper::AddEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ mpImpl->addAccessibleEventListener( xListener );
+
+ mpImpl->CheckInvariants();
+#else
+ mpImpl->addAccessibleEventListener( xListener );
+#endif
+ }
+
+ void AccessibleTextHelper::RemoveEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
+ {
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ mpImpl->removeAccessibleEventListener( xListener );
+
+ mpImpl->CheckInvariants();
+#else
+ mpImpl->removeAccessibleEventListener( xListener );
+#endif
+ }
+
+ // XAccessibleComponent
+ uno::Reference< XAccessible > AccessibleTextHelper::GetAt( const awt::Point& aPoint )
+ {
+ SolarMutexGuard aGuard;
+
+#ifdef DBG_UTIL
+ mpImpl->CheckInvariants();
+
+ uno::Reference< XAccessible > xChild = mpImpl->getAccessibleAtPoint( aPoint );
+
+ mpImpl->CheckInvariants();
+
+ return xChild;
+#else
+ return mpImpl->getAccessibleAtPoint( aPoint );
+#endif
+ }
+
+} // end of namespace accessibility
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/ChildrenManager.cxx b/svx/source/accessibility/ChildrenManager.cxx
new file mode 100644
index 000000000..71983f46e
--- /dev/null
+++ b/svx/source/accessibility/ChildrenManager.cxx
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/ChildrenManager.hxx>
+#include "ChildrenManagerImpl.hxx"
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+using ::com::sun::star::uno::Reference;
+
+namespace accessibility {
+
+// AccessibleChildrenManager
+ChildrenManager::ChildrenManager (
+ const css::uno::Reference<XAccessible>& rxParent,
+ const css::uno::Reference<drawing::XShapes>& rxShapeList,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo,
+ AccessibleContextBase& rContext)
+ : mpImpl(
+ new ChildrenManagerImpl(
+ rxParent, rxShapeList, rShapeTreeInfo, rContext))
+{
+ mpImpl->Init ();
+}
+
+
+ChildrenManager::~ChildrenManager()
+{
+ mpImpl->dispose();
+
+ // empty
+ SAL_INFO("svx", "~ChildrenManager");
+}
+
+tools::Long ChildrenManager::GetChildCount() const noexcept
+{
+ return mpImpl->GetChildCount();
+}
+
+css::uno::Reference<XAccessible> ChildrenManager::GetChild (tools::Long nIndex)
+{
+ return mpImpl->GetChild (nIndex);
+}
+
+css::uno::Reference<css::drawing::XShape> ChildrenManager::GetChildShape(tools::Long nIndex)
+{
+ return mpImpl->GetChildShape(nIndex);
+}
+
+void ChildrenManager::Update (bool bCreateNewObjectsOnDemand)
+{
+ mpImpl->Update (bCreateNewObjectsOnDemand);
+}
+
+void ChildrenManager::SetShapeList (const css::uno::Reference<css::drawing::XShapes>& xShapeList)
+{
+ mpImpl->SetShapeList (xShapeList);
+}
+
+void ChildrenManager::AddAccessibleShape (css::uno::Reference<css::accessibility::XAccessible> const & shape)
+{
+ mpImpl->AddAccessibleShape (shape);
+}
+
+void ChildrenManager::ClearAccessibleShapeList()
+{
+ mpImpl->ClearAccessibleShapeList ();
+}
+
+void ChildrenManager::SetInfo (AccessibleShapeTreeInfo const & rShapeTreeInfo)
+{
+ mpImpl->SetInfo (rShapeTreeInfo);
+}
+
+void ChildrenManager::UpdateSelection()
+{
+ mpImpl->UpdateSelection ();
+}
+
+bool ChildrenManager::HasFocus() const
+{
+ return mpImpl->HasFocus ();
+}
+
+void ChildrenManager::RemoveFocus()
+{
+ mpImpl->RemoveFocus ();
+}
+
+// IAccessibleViewForwarderListener
+void ChildrenManager::ViewForwarderChanged()
+{
+ mpImpl->ViewForwarderChanged();
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/ChildrenManagerImpl.cxx b/svx/source/accessibility/ChildrenManagerImpl.cxx
new file mode 100644
index 000000000..b557e00a9
--- /dev/null
+++ b/svx/source/accessibility/ChildrenManagerImpl.cxx
@@ -0,0 +1,1051 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include "ChildrenManagerImpl.hxx"
+#include <svx/ShapeTypeHandler.hxx>
+#include <svx/AccessibleControlShape.hxx>
+#include <svx/AccessibleShapeInfo.hxx>
+#include <svx/IAccessibleViewForwarder.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <comphelper/types.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/sorted_vector.hxx>
+#include <rtl/ustring.hxx>
+#include <tools/debug.hxx>
+#include <svx/SvxShapeTypes.hxx>
+#include <vcl/window.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+using ::com::sun::star::uno::Reference;
+
+namespace accessibility {
+
+namespace
+{
+void adjustIndexInParentOfShapes(ChildDescriptorListType& _rList)
+{
+ sal_Int32 i=0;
+ for (auto& rItem : _rList)
+ {
+ rItem.setIndexAtAccessibleShape(i);
+ ++i;
+ }
+}
+}
+
+// AccessibleChildrenManager
+ChildrenManagerImpl::ChildrenManagerImpl (
+ const uno::Reference<XAccessible>& rxParent,
+ const uno::Reference<drawing::XShapes>& rxShapeList,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo,
+ AccessibleContextBase& rContext)
+ : mxShapeList (rxShapeList),
+ mxParent (rxParent),
+ maShapeTreeInfo (rShapeTreeInfo),
+ mrContext (rContext),
+ mpFocusedShape(nullptr)
+{
+}
+
+
+ChildrenManagerImpl::~ChildrenManagerImpl()
+{
+ DBG_ASSERT (m_bDisposed, "~AccessibleDrawDocumentView: object has not been disposed");
+}
+
+
+void ChildrenManagerImpl::Init()
+{
+ // Register as view::XSelectionChangeListener.
+ Reference<frame::XController> xController(maShapeTreeInfo.GetController());
+ Reference<view::XSelectionSupplier> xSelectionSupplier (
+ xController, uno::UNO_QUERY);
+ if (xSelectionSupplier.is())
+ {
+ xController->addEventListener(
+ static_cast<document::XEventListener*>(this));
+
+ xSelectionSupplier->addSelectionChangeListener (
+ static_cast<view::XSelectionChangeListener*>(this));
+ }
+
+ // Register at model as document::XEventListener.
+ if (maShapeTreeInfo.GetModelBroadcaster().is())
+ maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
+ static_cast<document::XEventListener*>(this));
+}
+
+
+tools::Long ChildrenManagerImpl::GetChildCount() const noexcept
+{
+ return maVisibleChildren.size();
+}
+
+
+css::uno::Reference<css::drawing::XShape> ChildrenManagerImpl::GetChildShape(tools::Long nIndex)
+{
+ uno::Reference<XAccessible> xAcc = GetChild(nIndex);
+ auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
+ [&xAcc](const ChildDescriptor& rChild) { return rChild.mxAccessibleShape == xAcc; });
+ if (I != maVisibleChildren.end())
+ return I->mxShape;
+ return uno::Reference< drawing::XShape > ();
+}
+
+/** Return the requested accessible child object. Create it if it is not
+ yet in the cache.
+*/
+uno::Reference<XAccessible>
+ ChildrenManagerImpl::GetChild (tools::Long nIndex)
+{
+ // Check whether the given index is valid.
+ if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= maVisibleChildren.size())
+ throw lang::IndexOutOfBoundsException (
+ "no accessible child with index " + OUString::number(nIndex),
+ mxParent);
+
+ return GetChild (maVisibleChildren[nIndex],nIndex);
+}
+
+
+/** Return the requested accessible child object. Create it if it is not
+ yet in the cache.
+*/
+uno::Reference<XAccessible>
+ ChildrenManagerImpl::GetChild (ChildDescriptor& rChildDescriptor,sal_Int32 _nIndex)
+{
+ if ( ! rChildDescriptor.mxAccessibleShape.is())
+ {
+ SolarMutexGuard g;
+ // Make sure that the requested accessible object has not been
+ // created while locking the global mutex.
+ if ( ! rChildDescriptor.mxAccessibleShape.is())
+ {
+ AccessibleShapeInfo aShapeInfo(
+ rChildDescriptor.mxShape,
+ mxParent,
+ this);
+ // Create accessible object that corresponds to the descriptor's
+ // shape.
+ rtl::Reference<AccessibleShape> pShape(
+ ShapeTypeHandler::Instance().CreateAccessibleObject (
+ aShapeInfo,
+ maShapeTreeInfo));
+ rChildDescriptor.mxAccessibleShape = pShape;
+ if ( pShape.is() )
+ {
+ pShape->Init();
+ pShape->setIndexInParent(_nIndex);
+ }
+ }
+ }
+
+ return rChildDescriptor.mxAccessibleShape;
+}
+
+
+/** Find all shapes among the specified shapes that lie fully or partially
+ inside the visible area. Put those shapes into the cleared cache. The
+ corresponding accessible objects will be created on demand.
+
+ At the moment, first all accessible objects are removed from the cache
+ and the appropriate listeners are informed of this. Next, the list is
+ created again. This should be optimized in the future to not remove and
+ create objects that will be in the list before and after the update
+ method.
+*/
+void ChildrenManagerImpl::Update (bool bCreateNewObjectsOnDemand)
+{
+ if (maShapeTreeInfo.GetViewForwarder() == nullptr)
+ return;
+ tools::Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
+
+ // 1. Create a local list of visible shapes.
+ ChildDescriptorListType aChildList;
+ CreateListOfVisibleShapes (aChildList);
+
+ // 2. Merge the information that is already known about the visible
+ // shapes from the current list into the new list.
+ MergeAccessibilityInformation (aChildList);
+
+ // 3. Replace the current list of visible shapes with the new one. Do
+ // the same with the visible area.
+ {
+ SolarMutexGuard g;
+ adjustIndexInParentOfShapes(aChildList);
+
+ // Use swap to copy the contents of the new list in constant time.
+ maVisibleChildren.swap (aChildList);
+
+ // aChildList now contains all the old children, while maVisibleChildren
+ // contains all the current children
+
+ // 4. Find all shapes in the old list that are not in the current list,
+ // send appropriate events and remove the accessible shape.
+
+ // Do this *after* we have set our new list of children, because
+ // removing a child may cause
+
+ // ChildDescriptor::disposeAccessibleObject -->
+ // AccessibleContextBase::CommitChange -->
+ // AtkListener::notifyEvent ->
+ // AtkListener::handleChildRemoved ->
+ // AtkListener::updateChildList
+ // AccessibleDrawDocumentView::getAccessibleChildCount ->
+ // ChildrenManagerImpl::GetChildCount ->
+ // maVisibleChildren.size()
+
+ // to be fired, and so the operations will take place on
+ // the list we are trying to replace
+
+ RemoveNonVisibleChildren (maVisibleChildren, aChildList);
+
+ aChildList.clear();
+
+ maVisibleArea = aVisibleArea;
+ }
+
+ // 5. If the visible area has changed then send events that signal a
+ // change of their bounding boxes for all shapes that are members of
+ // both the current and the new list of visible shapes.
+ if (maVisibleArea != aVisibleArea)
+ SendVisibleAreaEvents (maVisibleChildren);
+
+ // 6. If children have to be created immediately and not on demand then
+ // create the missing accessible objects now.
+ if (bCreateNewObjectsOnDemand)
+ return;
+
+ //operate on a copy of the list and restore it afterwards to guard
+ //against the pathological case where maVisibleChildren gets modified
+ //by other calls to this object while CreateAccessibilityObjects
+ //executes which can happen when java is disabled and the "enable-java"
+ //dialog appears during the instantiation of the linguistic components
+ //triggered by the creation of shapes belonging to the a11y objects
+ //
+ //i.e. launch start-center, launch impress with java disabled and
+ //a java-using linguistic component installed
+ maVisibleChildren.swap(aChildList);
+ CreateAccessibilityObjects(aChildList);
+ maVisibleChildren.swap(aChildList);
+}
+
+void ChildrenManagerImpl::CreateListOfVisibleShapes (
+ ChildDescriptorListType& raDescriptorList)
+{
+ SolarMutexGuard g;
+
+ OSL_ASSERT (maShapeTreeInfo.GetViewForwarder() != nullptr);
+
+ tools::Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
+
+ // Add the visible shapes for which the accessible objects already exist.
+ for (const auto& rpShape : maAccessibleShapes)
+ {
+ if (rpShape.is())
+ {
+ uno::Reference<XAccessibleComponent> xComponent (
+ rpShape->getAccessibleContext(), uno::UNO_QUERY);
+ if (xComponent.is())
+ {
+ // The bounding box of the object already is clipped to the
+ // visible area. The object is therefore visible if the
+ // bounding box has non-zero extensions.
+ awt::Rectangle aPixelBBox (xComponent->getBounds());
+ if ((aPixelBBox.Width > 0) && (aPixelBBox.Height > 0))
+ raDescriptorList.emplace_back(rpShape);
+ }
+ }
+ }
+
+ // Add the visible shapes for which only the XShapes exist.
+ if (!mxShapeList.is() || !mxShapeList->hasElements())
+ return;
+
+ sal_Int32 nShapeCount = mxShapeList->getCount();
+ raDescriptorList.reserve( nShapeCount );
+ awt::Point aPos;
+ awt::Size aSize;
+ tools::Rectangle aBoundingBox;
+ uno::Reference<drawing::XShape> xShape;
+ for (sal_Int32 i=0; i<nShapeCount; ++i)
+ {
+ mxShapeList->getByIndex(i) >>= xShape;
+ aPos = xShape->getPosition();
+ aSize = xShape->getSize();
+
+ aBoundingBox.SetLeft( aPos.X );
+ aBoundingBox.SetTop( aPos.Y );
+ aBoundingBox.SetRight( aPos.X + aSize.Width );
+ aBoundingBox.SetBottom( aPos.Y + aSize.Height );
+
+ // Insert shape if it is visible, i.e. its bounding box overlaps
+ // the visible area.
+ if ( aBoundingBox.Overlaps(aVisibleArea) )
+ raDescriptorList.emplace_back(xShape);
+ }
+}
+
+void ChildrenManagerImpl::RemoveNonVisibleChildren (
+ const ChildDescriptorListType& rNewChildList,
+ ChildDescriptorListType& rOldChildList)
+{
+ // Iterate over list of formerly visible children and remove those that
+ // are not visible anymore, i.e. member of the new list of visible
+ // children.
+ for (auto& rChild : rOldChildList)
+ {
+ if (::std::find(rNewChildList.begin(), rNewChildList.end(), rChild) == rNewChildList.end())
+ {
+ // The child is disposed when there is a UNO shape from which
+ // the accessible shape can be created when the shape becomes
+ // visible again. When there is no such UNO shape then simply
+ // reset the descriptor but keep the accessibility object.
+ if (rChild.mxShape.is())
+ {
+ UnregisterAsDisposeListener (rChild.mxShape);
+ rChild.disposeAccessibleObject (mrContext);
+ }
+ else
+ {
+ AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
+ pAccessibleShape->ResetState (AccessibleStateType::VISIBLE);
+ rChild.mxAccessibleShape = nullptr;
+ }
+ }
+ }
+}
+
+void ChildrenManagerImpl::MergeAccessibilityInformation (
+ ChildDescriptorListType& raNewChildList)
+{
+ ChildDescriptorListType::const_iterator aStartVisibleChildren = maVisibleChildren.begin();
+ ChildDescriptorListType::const_iterator aEndVisibleChildren = maVisibleChildren.end();
+
+ for (auto& rChild : raNewChildList)
+ {
+ ChildDescriptorListType::const_iterator aOldChildDescriptor =
+ std::find(aStartVisibleChildren, aEndVisibleChildren, rChild);
+
+ // Copy accessible shape if that exists in the old descriptor.
+ if (aOldChildDescriptor != aEndVisibleChildren &&
+ aOldChildDescriptor->mxAccessibleShape.is())
+ {
+ rChild.mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape;
+ rChild.mbCreateEventPending = false;
+ }
+ else
+ RegisterAsDisposeListener (rChild.mxShape);
+ }
+}
+
+void ChildrenManagerImpl::SendVisibleAreaEvents (
+ ChildDescriptorListType& raNewChildList)
+{
+ for (const auto& rChild : raNewChildList)
+ {
+ // Tell shape of changed visible area. To do this, fake a
+ // change of the view forwarder. (Actually we usually get here
+ // as a result of a change of the view forwarder).
+ AccessibleShape* pShape = rChild.GetAccessibleShape ();
+ if (pShape != nullptr)
+ pShape->ViewForwarderChanged();
+ }
+}
+
+
+void ChildrenManagerImpl::CreateAccessibilityObjects (
+ ChildDescriptorListType& raNewChildList)
+{
+ sal_Int32 nPos = 0;
+ for ( auto& rChild : raNewChildList)
+ {
+ // Create the associated accessible object when the flag says so and
+ // it does not yet exist.
+ if ( ! rChild.mxAccessibleShape.is() )
+ GetChild (rChild, nPos);
+ if (rChild.mxAccessibleShape.is() && rChild.mbCreateEventPending)
+ {
+ rChild.mbCreateEventPending = false;
+ mrContext.CommitChange (
+ AccessibleEventId::CHILD,
+ uno::Any(rChild.mxAccessibleShape),
+ uno::Any());
+ }
+ ++nPos;
+ }
+}
+
+
+void ChildrenManagerImpl::AddShape (const Reference<drawing::XShape>& rxShape)
+{
+ if (!rxShape.is())
+ return;
+
+ SolarMutexClearableGuard aGuard;
+
+ // Test visibility of the shape.
+ tools::Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
+ awt::Point aPos = rxShape->getPosition();
+ awt::Size aSize = rxShape->getSize();
+
+ tools::Rectangle aBoundingBox (
+ aPos.X,
+ aPos.Y,
+ aPos.X + aSize.Width,
+ aPos.Y + aSize.Height);
+
+ // Add the shape only when it belongs to the list of shapes stored
+ // in mxShapeList (which is either a page or a group shape).
+ Reference<container::XChild> xChild (rxShape, uno::UNO_QUERY);
+ if (!xChild.is())
+ return;
+
+ Reference<drawing::XShapes> xParent (xChild->getParent(), uno::UNO_QUERY);
+ if (xParent != mxShapeList)
+ return;
+
+ if (!aBoundingBox.Overlaps(aVisibleArea))
+ return;
+
+ // Add shape to list of visible shapes.
+ maVisibleChildren.emplace_back(rxShape);
+
+ // Create accessibility object.
+ ChildDescriptor& rDescriptor = maVisibleChildren.back();
+ GetChild (rDescriptor, maVisibleChildren.size()-1);
+
+ // Inform listeners about new child.
+ uno::Any aNewShape;
+ aNewShape <<= rDescriptor.mxAccessibleShape;
+ aGuard.clear();
+ mrContext.CommitChange (
+ AccessibleEventId::CHILD,
+ aNewShape,
+ uno::Any());
+ RegisterAsDisposeListener(rxShape);
+}
+
+
+void ChildrenManagerImpl::RemoveShape (const Reference<drawing::XShape>& rxShape)
+{
+ if (!rxShape.is())
+ return;
+
+ SolarMutexGuard g;
+
+ // Search shape in list of visible children.
+ ChildDescriptorListType::iterator I (
+ ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
+ ChildDescriptor (rxShape)));
+ if (I == maVisibleChildren.end())
+ return;
+
+ // Remove descriptor from that list.
+ Reference<XAccessible> xHoldAlive(I->mxAccessibleShape);
+
+ UnregisterAsDisposeListener (I->mxShape);
+ // Dispose the accessible object.
+ I->disposeAccessibleObject (mrContext);
+
+ // Now we can safely remove the child descriptor and thus
+ // invalidate the iterator.
+ maVisibleChildren.erase (I);
+
+ adjustIndexInParentOfShapes(maVisibleChildren);
+}
+
+
+void ChildrenManagerImpl::SetShapeList (const css::uno::Reference<css::drawing::XShapes>& xShapeList)
+{
+ mxShapeList = xShapeList;
+}
+
+
+void ChildrenManagerImpl::AddAccessibleShape (css::uno::Reference<css::accessibility::XAccessible> const & shape)
+{
+ assert(shape.is());
+ maAccessibleShapes.push_back (shape);
+}
+
+
+void ChildrenManagerImpl::ClearAccessibleShapeList()
+{
+ // Copy the list of (visible) shapes to local lists and clear the
+ // originals.
+ ChildDescriptorListType aLocalVisibleChildren;
+ aLocalVisibleChildren.swap(maVisibleChildren);
+ AccessibleShapeList aLocalAccessibleShapes;
+ aLocalAccessibleShapes.swap(maAccessibleShapes);
+
+ // Tell the listeners that all children are gone.
+ mrContext.CommitChange (
+ AccessibleEventId::INVALIDATE_ALL_CHILDREN,
+ uno::Any(),
+ uno::Any());
+
+ // Now the objects in the local lists can be safely disposed without
+ // having problems with callers that want to update their child lists.
+
+ // Clear the list of visible accessible objects. Objects not created on
+ // demand for XShapes are treated below.
+ for (auto& rChild : aLocalVisibleChildren)
+ if ( rChild.mxAccessibleShape.is() && rChild.mxShape.is() )
+ {
+ ::comphelper::disposeComponent(rChild.mxAccessibleShape);
+ rChild.mxAccessibleShape = nullptr;
+ }
+
+ // Dispose all objects in the accessible shape list.
+ for (auto& rpShape : aLocalAccessibleShapes)
+ if (rpShape.is())
+ {
+ // Dispose the object.
+ ::comphelper::disposeComponent(rpShape);
+ rpShape = nullptr;
+ }
+}
+
+
+/** If the broadcasters change at which this object is registered then
+ unregister at old and register at new broadcasters.
+*/
+void ChildrenManagerImpl::SetInfo (const AccessibleShapeTreeInfo& rShapeTreeInfo)
+{
+ // Remember the current broadcasters and exchange the shape tree info.
+ Reference<document::XEventBroadcaster> xCurrentBroadcaster;
+ Reference<frame::XController> xCurrentController;
+ Reference<view::XSelectionSupplier> xCurrentSelectionSupplier;
+ {
+ SolarMutexGuard g;
+ xCurrentBroadcaster = maShapeTreeInfo.GetModelBroadcaster();
+ xCurrentController = maShapeTreeInfo.GetController();
+ xCurrentSelectionSupplier.set( xCurrentController, uno::UNO_QUERY);
+ maShapeTreeInfo = rShapeTreeInfo;
+ }
+
+ // Move registration to new model.
+ if (maShapeTreeInfo.GetModelBroadcaster() != xCurrentBroadcaster)
+ {
+ // Register at new broadcaster.
+ if (maShapeTreeInfo.GetModelBroadcaster().is())
+ maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
+ static_cast<document::XEventListener*>(this));
+
+ // Unregister at old broadcaster.
+ if (xCurrentBroadcaster.is())
+ xCurrentBroadcaster->removeEventListener (
+ static_cast<document::XEventListener*>(this));
+ }
+
+ // Move registration to new selection supplier.
+ Reference<frame::XController> xNewController(maShapeTreeInfo.GetController());
+ Reference<view::XSelectionSupplier> xNewSelectionSupplier (
+ xNewController, uno::UNO_QUERY);
+ if (xNewSelectionSupplier == xCurrentSelectionSupplier)
+ return;
+
+ // Register at new broadcaster.
+ if (xNewSelectionSupplier.is())
+ {
+ xNewController->addEventListener(
+ static_cast<document::XEventListener*>(this));
+
+ xNewSelectionSupplier->addSelectionChangeListener (
+ static_cast<view::XSelectionChangeListener*>(this));
+ }
+
+ // Unregister at old broadcaster.
+ if (xCurrentSelectionSupplier.is())
+ {
+ xCurrentSelectionSupplier->removeSelectionChangeListener (
+ static_cast<view::XSelectionChangeListener*>(this));
+
+ xCurrentController->removeEventListener(
+ static_cast<document::XEventListener*>(this));
+ }
+}
+
+// lang::XEventListener
+void SAL_CALL
+ ChildrenManagerImpl::disposing (const lang::EventObject& rEventObject)
+{
+ if (rEventObject.Source == maShapeTreeInfo.GetModelBroadcaster()
+ || rEventObject.Source == maShapeTreeInfo.GetController())
+ {
+ impl_dispose();
+ }
+
+ // Handle disposing UNO shapes.
+ else
+ {
+ Reference<drawing::XShape> xShape (rEventObject.Source, uno::UNO_QUERY);
+
+ // Find the descriptor for the given shape.
+ ChildDescriptorListType::iterator I (
+ ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
+ ChildDescriptor (xShape)));
+ if (I != maVisibleChildren.end())
+ {
+ // Clear the descriptor.
+ I->disposeAccessibleObject (mrContext);
+ I->mxShape = nullptr;
+ }
+ }
+}
+
+// document::XEventListener
+/** Listen for new and removed shapes.
+*/
+void SAL_CALL
+ ChildrenManagerImpl::notifyEvent (
+ const document::EventObject& rEventObject)
+{
+ if (rEventObject.EventName == "ShapeInserted")
+ AddShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
+ else if (rEventObject.EventName == "ShapeRemoved")
+ RemoveShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
+ // else ignore unknown event.
+}
+
+// view::XSelectionChangeListener
+void SAL_CALL
+ ChildrenManagerImpl::selectionChanged (const lang::EventObject& /*rEvent*/)
+{
+ UpdateSelection ();
+}
+
+
+void ChildrenManagerImpl::impl_dispose()
+{
+ Reference<frame::XController> xController(maShapeTreeInfo.GetController());
+ // Remove from broadcasters.
+ try
+ {
+ Reference<view::XSelectionSupplier> xSelectionSupplier (
+ xController, uno::UNO_QUERY);
+ if (xSelectionSupplier.is())
+ {
+ xSelectionSupplier->removeSelectionChangeListener (
+ static_cast<view::XSelectionChangeListener*>(this));
+ }
+ }
+ catch( uno::RuntimeException&)
+ {}
+
+ try
+ {
+ if (xController.is())
+ xController->removeEventListener(
+ static_cast<document::XEventListener*>(this));
+ }
+ catch( uno::RuntimeException&)
+ {}
+
+ maShapeTreeInfo.SetController (nullptr);
+
+ try
+ {
+ // Remove from broadcaster.
+ if (maShapeTreeInfo.GetModelBroadcaster().is())
+ maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
+ static_cast<document::XEventListener*>(this));
+ maShapeTreeInfo.SetModelBroadcaster (nullptr);
+ }
+ catch( uno::RuntimeException& )
+ {}
+
+ ClearAccessibleShapeList ();
+ SetShapeList (nullptr);
+}
+
+
+void ChildrenManagerImpl::disposing(std::unique_lock<std::mutex>&)
+{
+ impl_dispose();
+}
+
+// IAccessibleViewForwarderListener
+void ChildrenManagerImpl::ViewForwarderChanged()
+{
+ Update(false);
+}
+
+// IAccessibleParent
+bool ChildrenManagerImpl::ReplaceChild (
+ AccessibleShape* pCurrentChild,
+ const css::uno::Reference< css::drawing::XShape >& _rxShape,
+ const tools::Long /*_nIndex*/,
+ const AccessibleShapeTreeInfo& _rShapeTreeInfo)
+{
+ // Iterate over the visible children. If one of them has an already
+ // created accessible object that matches pCurrentChild then replace
+ // it. Otherwise the child to replace is either not in the list or has
+ // not ye been created (and is therefore not in the list, too) and a
+ // replacement is not necessary.
+ auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
+ [&pCurrentChild](const ChildDescriptor& rChild) { return rChild.GetAccessibleShape() == pCurrentChild; });
+
+ if (I != maVisibleChildren.end())
+ {
+ // Dispose the current child and send an event about its deletion.
+ pCurrentChild->dispose();
+ mrContext.CommitChange (
+ AccessibleEventId::CHILD,
+ uno::Any(),
+ uno::Any (I->mxAccessibleShape));
+
+ // Replace with replacement and send an event about existence
+ // of the new child.
+ AccessibleShapeInfo aShapeInfo( _rxShape, pCurrentChild->getAccessibleParent(), this );
+ // create the new child
+ rtl::Reference<AccessibleShape> pNewChild(ShapeTypeHandler::Instance().CreateAccessibleObject (
+ aShapeInfo,
+ _rShapeTreeInfo
+ ));
+ if ( pNewChild.is() )
+ pNewChild->Init();
+
+ I->mxAccessibleShape = pNewChild.get();
+ mrContext.CommitChange (
+ AccessibleEventId::CHILD,
+ uno::Any (I->mxAccessibleShape),
+ uno::Any());
+
+ return true;
+ }
+
+ // When not found among the visible children we have to search the list
+ // of accessible shapes. This is not yet implemented.
+ return false;
+}
+
+// Add the impl method for IAccessibleParent interface
+AccessibleControlShape * ChildrenManagerImpl::GetAccControlShapeFromModel(css::beans::XPropertySet* pSet)
+{
+ sal_Int32 count = GetChildCount();
+ for (sal_Int32 index=0;index<count;index++)
+ {
+ AccessibleShape* pAccShape = maVisibleChildren[index].GetAccessibleShape();
+ if (pAccShape && ::accessibility::ShapeTypeHandler::Instance().GetTypeId(pAccShape->GetXShape()) == DRAWING_CONTROL)
+ {
+ auto* pCtlAccShape = static_cast<::accessibility::AccessibleControlShape*>(pAccShape);
+ if (pCtlAccShape->GetControlModel() == pSet)
+ return pCtlAccShape;
+ }
+ }
+ return nullptr;
+}
+uno::Reference<XAccessible>
+ ChildrenManagerImpl::GetAccessibleCaption (const uno::Reference<drawing::XShape>& xShape)
+{
+ auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
+ [&xShape](const ChildDescriptor& rChild) { return rChild.mxShape.get() == xShape.get(); });
+ if (I != maVisibleChildren.end())
+ return I->mxAccessibleShape;
+ return uno::Reference<XAccessible> ();
+}
+
+/** Update the <const>SELECTED</const> and the <const>FOCUSED</const> state
+ of all visible children. Maybe this should be changed to all children.
+
+ Iterate over all descriptors of visible accessible shapes and look them
+ up in the selection.
+
+ If there is no valid controller then all shapes are deselected and
+ unfocused. If the controller's frame is not active then all shapes are
+ unfocused.
+*/
+void ChildrenManagerImpl::UpdateSelection()
+{
+ // Remember the current and new focused shape.
+ AccessibleShape* pCurrentlyFocusedShape = nullptr;
+ AccessibleShape* pNewFocusedShape = nullptr;
+ typedef std::pair< AccessibleShape* , sal_Bool > PAIR_SHAPE;//sal_Bool Selected,UnSelected.
+ typedef std::vector< PAIR_SHAPE > VEC_SHAPE;
+ VEC_SHAPE vecSelect;
+ int nAddSelect=0;
+ bool bHasSelectedShape=false;
+ if (!maVisibleChildren.empty())
+ {
+ Reference<frame::XController> xController(maShapeTreeInfo.GetController());
+ Reference<view::XSelectionSupplier> xSelectionSupplier (
+ xController, uno::UNO_QUERY);
+
+ // Try to cast the selection both to a multi selection and to a single
+ // selection.
+ Reference<container::XIndexAccess> xSelectedShapeAccess;
+ Reference<drawing::XShape> xSelectedShape;
+ if (xSelectionSupplier.is())
+ {
+ xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
+ xSelectedShape.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
+ }
+
+ // tdf#139220 to quickly find if a given drawing::XShape is selected
+ o3tl::sorted_vector<css::uno::Reference<css::drawing::XShape>> aSortedSelectedShapes;
+ if (!xSelectedShape.is() && xSelectedShapeAccess.is())
+ {
+ sal_Int32 nCount = xSelectedShapeAccess->getCount();
+ aSortedSelectedShapes.reserve(nCount);
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ css::uno::Reference<css::drawing::XShape> xShape(xSelectedShapeAccess->getByIndex(i), uno::UNO_QUERY);
+ aSortedSelectedShapes.insert(xShape);
+ }
+ }
+
+ for (const auto& rChild : maVisibleChildren)
+ {
+ AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
+ if (rChild.mxAccessibleShape.is() && rChild.mxShape.is() && pAccessibleShape!=nullptr)
+ {
+ short nRole = pAccessibleShape->getAccessibleRole();
+ bool bDrawShape = (
+ nRole == AccessibleRole::GRAPHIC ||
+ nRole == AccessibleRole::EMBEDDED_OBJECT ||
+ nRole == AccessibleRole::SHAPE ||
+ nRole == AccessibleRole::IMAGE_MAP ||
+ nRole == AccessibleRole::TABLE_CELL ||
+ nRole == AccessibleRole::TABLE );
+ bool bShapeIsSelected = false;
+
+ // Look up the shape in the (single or multi-) selection.
+ if (xSelectedShape.is())
+ {
+ if (rChild.mxShape == xSelectedShape)
+ {
+ bShapeIsSelected = true;
+ pNewFocusedShape = pAccessibleShape;
+ }
+ }
+ else if (!aSortedSelectedShapes.empty())
+ {
+ if (aSortedSelectedShapes.find(rChild.mxShape) != aSortedSelectedShapes.end())
+ {
+ bShapeIsSelected = true;
+ // In a multi-selection no shape has the focus.
+ if (aSortedSelectedShapes.size() == 1)
+ pNewFocusedShape = pAccessibleShape;
+ }
+ }
+
+ // Set or reset the SELECTED state.
+ if (bShapeIsSelected)
+ {
+ if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
+ {
+ if (bDrawShape)
+ {
+ vecSelect.emplace_back(pAccessibleShape,true);
+ ++nAddSelect;
+ }
+ }
+ else
+ {//Selected not change,has selected shape before
+ bHasSelectedShape=true;
+ }
+ }
+ else
+ //pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
+ {
+ if(pAccessibleShape->ResetState (AccessibleStateType::SELECTED))
+ {
+ if(bDrawShape)
+ {
+ vecSelect.emplace_back(pAccessibleShape,false);
+ }
+ }
+ }
+ // Does the shape have the current selection?
+ if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
+ pCurrentlyFocusedShape = pAccessibleShape;
+ }
+ }
+ }
+
+ vcl::Window *pParentWindow = maShapeTreeInfo.GetWindow();
+ bool bShapeActive= false;
+ // For table cell, the table's parent must be checked to make sure it has focus.
+ if (pParentWindow)
+ {
+ vcl::Window *pPWindow = pParentWindow->GetParent();
+ if (pParentWindow->HasFocus() || (pPWindow && pPWindow->HasFocus()))
+ bShapeActive =true;
+ }
+ // Move focus from current to newly focused shape.
+ if (pCurrentlyFocusedShape != pNewFocusedShape)
+ {
+ if (pCurrentlyFocusedShape != nullptr)
+ pCurrentlyFocusedShape->ResetState (AccessibleStateType::FOCUSED);
+ if (pNewFocusedShape != nullptr && bShapeActive)
+ pNewFocusedShape->SetState (AccessibleStateType::FOCUSED);
+ }
+
+ if (nAddSelect >= 10 )//fire selection within
+ {
+ mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN,uno::Any(),uno::Any());
+ nAddSelect =0 ;//not fire selection event
+ }
+ for (VEC_SHAPE::reverse_iterator vi = vecSelect.rbegin(), aEndVecSelect = vecSelect.rend(); vi != aEndVecSelect ;++vi)
+ {
+ PAIR_SHAPE &pairShape= *vi;
+ Reference< XAccessible > xShape(pairShape.first);
+ uno::Any anyShape;
+ anyShape <<= xShape;
+
+ if (pairShape.second)//Selection add
+ {
+ if (bHasSelectedShape)
+ {
+ if ( nAddSelect > 0 )
+ {
+ mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD,anyShape,uno::Any());
+ }
+ }
+ else
+ {
+ //if has not selected shape ,first selected shape is fire selection event;
+ if (nAddSelect > 0 )
+ {
+ mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED,anyShape,uno::Any());
+ }
+ if (nAddSelect > 1 )//check other selected shape fire selection add event
+ {
+ bHasSelectedShape=true;
+ }
+ }
+ }
+ else //selection remove
+ {
+ mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE,anyShape,uno::Any());
+ }
+ }
+
+ // Remember whether there is a shape that now has the focus.
+ mpFocusedShape = pNewFocusedShape;
+}
+
+
+bool ChildrenManagerImpl::HasFocus() const
+{
+ return mpFocusedShape != nullptr;
+}
+
+
+void ChildrenManagerImpl::RemoveFocus()
+{
+ if (mpFocusedShape != nullptr)
+ {
+ mpFocusedShape->ResetState (AccessibleStateType::FOCUSED);
+ mpFocusedShape = nullptr;
+ }
+}
+
+
+void ChildrenManagerImpl::RegisterAsDisposeListener (
+ const Reference<drawing::XShape>& xShape)
+{
+ Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener (
+ static_cast<document::XEventListener*>(this));
+}
+
+
+void ChildrenManagerImpl::UnregisterAsDisposeListener (
+ const Reference<drawing::XShape>& xShape)
+{
+ Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener (
+ static_cast<document::XEventListener*>(this));
+}
+
+// AccessibleChildDescriptor
+ChildDescriptor::ChildDescriptor (const Reference<drawing::XShape>& xShape)
+ : mxShape (xShape),
+ mbCreateEventPending (true)
+{
+ // Empty.
+}
+
+
+ChildDescriptor::ChildDescriptor (const Reference<XAccessible>& rxAccessibleShape)
+ : mxAccessibleShape (rxAccessibleShape),
+ mbCreateEventPending (true)
+{
+ // Make sure that the accessible object has the <const>VISIBLE</const>
+ // state set.
+ AccessibleShape* pAccessibleShape = GetAccessibleShape();
+ pAccessibleShape->SetState (AccessibleStateType::VISIBLE);
+}
+
+AccessibleShape* ChildDescriptor::GetAccessibleShape() const
+{
+ return static_cast<AccessibleShape*> (mxAccessibleShape.get());
+}
+
+void ChildDescriptor::setIndexAtAccessibleShape(sal_Int32 _nIndex)
+{
+ AccessibleShape* pShape = GetAccessibleShape();
+ if ( pShape )
+ pShape->setIndexInParent(_nIndex);
+}
+
+
+void ChildDescriptor::disposeAccessibleObject (AccessibleContextBase& rParent)
+{
+ if (!mxAccessibleShape.is())
+ return;
+
+ // Send event that the shape has been removed.
+ uno::Any aOldValue;
+ aOldValue <<= mxAccessibleShape;
+ rParent.CommitChange (
+ AccessibleEventId::CHILD,
+ uno::Any(),
+ aOldValue);
+
+ // Dispose and remove the object.
+ Reference<lang::XComponent> xComponent (mxAccessibleShape, uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->dispose ();
+
+ mxAccessibleShape = nullptr;
+}
+
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/ChildrenManagerImpl.hxx b/svx/source/accessibility/ChildrenManagerImpl.hxx
new file mode 100644
index 000000000..f4105c878
--- /dev/null
+++ b/svx/source/accessibility/ChildrenManagerImpl.hxx
@@ -0,0 +1,494 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_ACCESSIBILITY_CHILDRENMANAGERIMPL_HXX
+#define INCLUDED_SVX_SOURCE_ACCESSIBILITY_CHILDRENMANAGERIMPL_HXX
+
+#include <svx/IAccessibleViewForwarderListener.hxx>
+#include <svx/IAccessibleParent.hxx>
+#include <svx/AccessibleShapeTreeInfo.hxx>
+#include <editeng/AccessibleContextBase.hxx>
+#include <comphelper/compbase.hxx>
+#include <tools/gen.hxx>
+#include <vector>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/document/XEventListener.hpp>
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+
+namespace accessibility {
+
+class AccessibleShape;
+
+class ChildDescriptor; // See below for declaration.
+typedef ::std::vector<ChildDescriptor> ChildDescriptorListType;
+
+// Re-using MutexOwner class defined in AccessibleContextBase.hxx
+
+/** This class contains the actual implementation of the children manager.
+
+ <p>It maintains a set of visible accessible shapes in
+ <member>maVisibleChildren</member>. The objects in this list stem from
+ two sources. The first is a list of UNO shapes like the list of shapes
+ in a draw page. A reference to this list is held in
+ <member>maShapeList</member>. Accessible objects for these shapes are
+ created on demand. The list can be replaced by calls to the
+ <member>SetShapeList</member> method. The second source is a list of
+ already accessible objects. It can be modified by calls to the
+ <member>AddAccessibleShape</member> and
+ <member>ClearAccessibleShapeList</member> methods.</p>
+
+ <p>Each call of the <member>Update</member> method leads to a
+ re-calculation of the visible shapes which then can be queried with the
+ <member>GetChildCount</member> and <member>GetChild</member> methods.
+ Events are sent informing all listeners about the removed shapes which are
+ not visible anymore and about the added shapes.</p>
+
+ <p> The visible area which is used to determine the visibility of the
+ shapes is taken from the view forwarder. Thus, to signal a change of
+ the visible area call <member>ViewForwarderChanged</member>.</p>
+
+ <p>The children manager adds itself as disposing() listener at every UNO
+ shape it creates an accessible object for so that when the UNO shape
+ passes away it can dispose() the associated accessible object.</p>
+
+ @see ChildrenManager
+*/
+class ChildrenManagerImpl final
+ : public comphelper::WeakComponentImplHelper<
+ css::document::XEventListener,
+ css::view::XSelectionChangeListener>,
+ public IAccessibleViewForwarderListener,
+ public IAccessibleParent
+{
+public:
+ /** Create a children manager, which manages the children of the given
+ parent. The parent is used for creating accessible objects. The
+ list of shapes for which to create those objects is not derived from
+ the parent and has to be provided separately by calling one of the
+ update methods.
+ @param rxParent
+ The parent of the accessible objects which will be created
+ on demand at some point of time in the future.
+ @param rxShapeList
+ List of UNO shapes to manage.
+ @param rShapeTreeInfo
+ Bundle of information passed down the shape tree.
+ @param rContext
+ An accessible context object that is called for firing events
+ for new and deleted children, i.e. that holds a list of
+ listeners to be informed.
+ */
+ ChildrenManagerImpl (const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ const css::uno::Reference<css::drawing::XShapes>& rxShapeList,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo,
+ AccessibleContextBase& rContext);
+
+ /** If there still are managed children these are disposed and
+ released.
+ */
+ virtual ~ChildrenManagerImpl() override;
+
+ /** Do that part of the initialization that you can not or should not do
+ in the constructor like registering at broadcasters.
+ */
+ void Init();
+
+ /** Return the number of currently visible accessible children.
+ @return
+ If there are no children a 0 is returned.
+ */
+ tools::Long GetChildCount() const noexcept;
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IndexOutOfBoundsException
+ css::uno::Reference<css::drawing::XShape> GetChildShape(tools::Long nIndex);
+ /** Return the requested accessible child or throw and
+ IndexOutOfBoundsException if the given index is invalid.
+ @param nIndex
+ Index of the requested child. Call getChildCount for obtaining
+ the number of children.
+ @return
+ In case of a valid index this method returns a reference to the
+ requested accessible child. This reference is empty if it has
+ not been possible to create the accessible object of the
+ corresponding shape.
+ @throws
+ Throws an IndexOutOfBoundsException if the index is not valid.
+ */
+ css::uno::Reference<css::accessibility::XAccessible>
+ GetChild (tools::Long nIndex);
+
+ /** Return the requested accessible child.
+ @param aChildDescriptor
+ This object contains references to the original shape and its
+ associated accessible object.
+ @param _nIndex
+ The index which will be used in getAccessibleIndexInParent of the accessible shape.
+ @return
+ Returns a reference to the requested accessible child. This
+ reference is empty if it has not been possible to create the
+ accessible object of the corresponding shape.
+ @throws css::uno::RuntimeException
+ */
+ css::uno::Reference<css::accessibility::XAccessible>
+ GetChild (ChildDescriptor& aChildDescriptor,sal_Int32 _nIndex);
+
+ /** Update the child manager. Take care of a modified set of children
+ and modified visible area. This method can optimize the update
+ process with respect separate updates of a modified children list
+ and visible area.
+ @param bCreateNewObjectsOnDemand
+ If </true> then accessible objects associated with the visible
+ shapes are created only when asked for. No event is sent on
+ creation. If </false> then the accessible objects are created
+ before this method returns and events are sent to inform the
+ listeners of the new object.
+ */
+ void Update (bool bCreateNewObjectsOnDemand);
+
+ /** Set the list of UNO shapes to the given list. This removes the old
+ list and does not add to it. The list of accessible shapes that is
+ build up by calls to <member>AddAccessibleShape</member> is not
+ modified. Neither is the list of visible children. Accessible
+ objects are created on demand.
+ @param xShapeList
+ The list of UNO shapes that replaces the old list.
+ */
+ void SetShapeList (const css::uno::Reference<css::drawing::XShapes>& xShapeList);
+
+ /** Add an accessible shape. This does not modify the list of UNO shapes
+ or the list of visible shapes. Accessible shapes are, at the
+ moment, not tested against the visible area but are always appended
+ to the list of visible children.
+ @param shape
+ The new shape that is added to the list of accessible shapes; must
+ be non-null.
+ */
+ void AddAccessibleShape (css::uno::Reference<css::accessibility::XAccessible> const & shape);
+
+ /** Clear the lists of accessible shapes and that of visible accessible
+ shapes. The list of UNO shapes is not modified.
+ */
+ void ClearAccessibleShapeList();
+
+ /** Set a new event shape tree info. Call this method to inform the
+ children manager of a change of the info bundle.
+ @param rShapeTreeInfo
+ The new info that replaces the current one.
+ */
+ void SetInfo (const AccessibleShapeTreeInfo& rShapeTreeInfo);
+
+ /** Update the SELECTED and FOCUSED states of all visible children
+ according to the given selection. This includes setting
+ <em>and</em> resetting the states.
+ */
+ void UpdateSelection();
+
+ /** Return whether one of the shapes managed by this object has
+ currently the focus.
+ @return
+ Returns <true/> when there is a shape that has the focus and
+ <false/> when there is no such shape.
+ */
+ bool HasFocus() const;
+
+ /** When there is a shape that currently has the focus,
+ i.e. <member>HasFocus()</member> returns <true/> then remove the
+ focus from that shape. Otherwise nothing changes.
+ */
+ void RemoveFocus();
+
+ // lang::XEventListener
+ virtual void SAL_CALL
+ disposing (const css::lang::EventObject& rEventObject) override;
+
+ // document::XEventListener
+ virtual void SAL_CALL
+ notifyEvent (const css::document::EventObject& rEventObject) override;
+
+ // view::XSelectionChangeListener
+ virtual void SAL_CALL
+ selectionChanged (const css::lang::EventObject& rEvent) override;
+
+ // IAccessibleViewForwarderListener
+ /** Informs this children manager and its children about a change of one
+ (or more) aspect of the view forwarder.
+ @param aChangeType
+ A change type of <const>VISIBLE_AREA</const> leads to a call to
+ the <member>Update</member> which creates accessible objects of
+ new shapes immediately. Other change types are passed to the
+ visible accessible children without calling
+ <member>Update</member>.
+ @param pViewForwarder
+ The modified view forwarder. Use this one from now on.
+ */
+ virtual void ViewForwarderChanged() override;
+
+ // IAccessibleParent
+ /** Replace the specified child with a replacement.
+ @param pCurrentChild
+ This child is to be replaced.
+ @param pReplacement
+ The replacement for the current child.
+ @return
+ The returned value indicates whether the replacement has been
+ finished successfully.
+ */
+ virtual bool ReplaceChild (
+ AccessibleShape* pCurrentChild,
+ const css::uno::Reference< css::drawing::XShape >& _rxShape,
+ const tools::Long _nIndex,
+ const AccessibleShapeTreeInfo& _rShapeTreeInfo
+ ) override;
+
+ // Add the impl method for IAccessibleParent interface
+ virtual AccessibleControlShape* GetAccControlShapeFromModel
+ (css::beans::XPropertySet* pSet) override;
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ GetAccessibleCaption (const css::uno::Reference<css::drawing::XShape>& xShape) override;
+
+private:
+ /** This list holds the descriptors of all currently visible shapes and
+ associated accessible object.
+
+ <p>With the descriptors it maintains a mapping of shapes to
+ accessible objects. It acts as a cache in that accessible objects
+ are only created on demand and released with every update (where the
+ latter may be optimized by the update methods).<p>
+
+ <p>The list is realized as a vector because it remains unchanged
+ between updates (i.e. complete rebuilds of the list) and allows a
+ fast (constant time) access to its elements for given indices.</p>
+ */
+ ChildDescriptorListType maVisibleChildren;
+
+ /** The original list of UNO shapes. The visible shapes are inserted
+ into the list of visible children
+ <member>maVisibleChildren</member>.
+ */
+ css::uno::Reference<css::drawing::XShapes> mxShapeList;
+
+ /** This list of additional accessible shapes that can or shall not be
+ created by the shape factory.
+ */
+ typedef std::vector< css::uno::Reference< css::accessibility::XAccessible> > AccessibleShapeList;
+ AccessibleShapeList maAccessibleShapes;
+
+ /** Rectangle that describes the visible area in which a shape has to lie
+ at least partly, to be accessible through this class. Used to
+ detect changes of the visible area after changes of the view forwarder.
+ */
+ tools::Rectangle maVisibleArea;
+
+ /** The parent of the shapes. It is used for creating accessible
+ objects for given shapes.
+ */
+ css::uno::Reference<css::accessibility::XAccessible> mxParent;
+
+ /** Bundle of information passed down the shape tree.
+ */
+ AccessibleShapeTreeInfo maShapeTreeInfo;
+
+ /** Reference to an accessible context object that is used to inform its
+ listeners of new and removed children.
+ */
+ AccessibleContextBase& mrContext;
+
+ /** This method is called from the component helper base class while
+ disposing.
+ */
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ void impl_dispose();
+
+ ChildrenManagerImpl (const ChildrenManagerImpl&) = delete;
+ ChildrenManagerImpl& operator= (const ChildrenManagerImpl&) = delete;
+
+ /** This member points to the currently focused shape. It is NULL when
+ there is no focused shape.
+ */
+ AccessibleShape* mpFocusedShape;
+
+ /** Three helper functions for the <member>Update</member> method.
+ */
+
+ /** Create a list of visible shapes from the list of UNO shapes
+ <member>maShapeList</member> and the list of accessible objects.
+ @param raChildList
+ For every visible shape from the two sources mentioned above one
+ descriptor is added to this list.
+ */
+ void CreateListOfVisibleShapes (ChildDescriptorListType& raChildList);
+
+ /** From the old list of (former) visible shapes remove those that
+ are not member of the new list. Send appropriate events for every
+ such shape.
+ @param raNewChildList
+ The new list of visible children against which the old one
+ is compared.
+ @param raOldChildList
+ The old list of visible children against which the new one
+ is compared.
+ */
+ void RemoveNonVisibleChildren (
+ const ChildDescriptorListType& raNewChildList,
+ ChildDescriptorListType& raOldChildList);
+
+ /** Merge the information that is already known about the visible shapes
+ from the current list into the new list.
+ @param raChildList
+ Information is merged from the current list of visible children
+ to this list.
+ */
+ void MergeAccessibilityInformation (ChildDescriptorListType& raChildList);
+
+ /** If the visible area has changed then send events that signal a
+ change of their bounding boxes for all shapes that are members of
+ both the current and the new list of visible shapes.
+ @param raChildList
+ Events are sent to all entries of this list that already contain
+ an accessible object.
+ */
+ static void SendVisibleAreaEvents (ChildDescriptorListType& raChildList);
+
+ /** If children have to be created immediately and not on demand the
+ create the missing accessible objects now.
+ @param raDescriptorList
+ Create an accessible object for every member of this list where
+ that object does not already exist.
+ */
+ void CreateAccessibilityObjects (ChildDescriptorListType& raChildList);
+
+ /** Add a single shape. Update all relevant data structures
+ accordingly. Use this method instead of <member>Update()</member>
+ when only a single shape has been added.
+ */
+ void AddShape (const css::uno::Reference<css::drawing::XShape>& xShape);
+
+ /** Remove a single shape. Update all relevant data structures
+ accordingly. Use this method instead of <member>Update()</member>
+ when only a single shape has been removed.
+ */
+ void RemoveShape (const css::uno::Reference<css::drawing::XShape>& xShape);
+
+ /** Add the children manager as dispose listener at the given shape so
+ that the associated accessible object can be disposed when the shape
+ is disposed.
+ @param xShape
+ Register at this shape as dispose listener.
+ */
+ void RegisterAsDisposeListener (const css::uno::Reference<css::drawing::XShape>& xShape);
+
+ /** Remove the children manager as dispose listener at the given shape
+ @param xShape
+ Unregister at this shape as dispose listener.
+ */
+ void UnregisterAsDisposeListener (const css::uno::Reference<css::drawing::XShape>& xShape);
+};
+
+
+/** A child descriptor holds a reference to a UNO shape and the
+ corresponding accessible object. There are two use cases:
+ <ol><li>The accessible object is only created on demand and is then
+ initially empty.</li>
+ <li>There is no UNO shape. The accessible object is given as argument
+ to the constructor.</li>
+ </ol>
+ In both cases the child descriptor assumes ownership over the accessible
+ object.
+*/
+class ChildDescriptor
+{
+public:
+ /** Reference to a (partially) visible shape.
+ */
+ css::uno::Reference<css::drawing::XShape> mxShape;
+
+ /** The corresponding accessible object. This reference is initially
+ empty and only replaced by a reference to a new object when that is
+ requested from the outside.
+ */
+ css::uno::Reference<css::accessibility::XAccessible> mxAccessibleShape;
+
+ /** Return a pointer to the implementation object of the accessible
+ shape of this descriptor.
+ @return
+ The result is NULL if either the UNO reference to the accessible
+ shape is empty or it can not be transformed into a pointer to
+ the desired class.
+ */
+ AccessibleShape* GetAccessibleShape() const;
+
+ /** set the index _nIndex at the accessible shape
+ @param _nIndex
+ The new index in parent.
+ */
+ void setIndexAtAccessibleShape(sal_Int32 _nIndex);
+
+ /** This flag is set during the visibility calculation and indicates
+ that at one time in this process an event is sent that informs the
+ listeners of the creation of a new accessible object. This flags is
+ not reset afterwards. Don't use it unless you know exactly what you
+ are doing.
+ */
+ bool mbCreateEventPending;
+
+ /** Create a new descriptor for the specified shape with empty reference
+ to accessible object.
+ */
+ explicit ChildDescriptor (const css::uno::Reference<css::drawing::XShape>& xShape);
+
+ /** Create a new descriptor for the specified shape with empty reference
+ to the original shape.
+ */
+ explicit ChildDescriptor (const css::uno::Reference<css::accessibility::XAccessible>& rxAccessibleShape);
+
+ /** Dispose the accessible object of this descriptor. If that object
+ does not exist then do nothing.
+ @param rParent
+ The parent of the accessible object to dispose. A child event
+ is sent in its name.
+ */
+ void disposeAccessibleObject (AccessibleContextBase& rParent);
+
+ /** Compare two child descriptors. Take into account that a child
+ descriptor may be based on a UNO shape or, already, on an accessible
+ shape.
+ */
+ bool operator == (const ChildDescriptor& aDescriptor) const
+ {
+ return (
+ this == &aDescriptor ||
+ (
+ (mxShape.get() == aDescriptor.mxShape.get() ) &&
+ (mxShape.is() || mxAccessibleShape.get() == aDescriptor.mxAccessibleShape.get())
+ )
+ );
+ }
+
+};
+
+
+} // end of namespace accessibility
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/DescriptionGenerator.cxx b/svx/source/accessibility/DescriptionGenerator.cxx
new file mode 100644
index 000000000..fe4109149
--- /dev/null
+++ b/svx/source/accessibility/DescriptionGenerator.cxx
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <DescriptionGenerator.hxx>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <vcl/svapp.hxx>
+
+// Includes for string resources.
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+#include "lookupcolorname.hxx"
+
+using namespace ::com::sun::star;
+
+namespace accessibility
+{
+DescriptionGenerator::DescriptionGenerator(const uno::Reference<drawing::XShape>& xShape)
+ : mxShape(xShape)
+ , mxSet(mxShape, uno::UNO_QUERY)
+ , mbIsFirstProperty(true)
+{
+}
+
+DescriptionGenerator::~DescriptionGenerator() {}
+
+void DescriptionGenerator::Initialize(TranslateId pResourceId)
+{
+ // Get the string from the resource for the specified id.
+ OUString sPrefix;
+ {
+ SolarMutexGuard aGuard;
+ sPrefix = SvxResId(pResourceId);
+ }
+
+ // Forward the call with the resulting string.
+ Initialize(sPrefix);
+}
+
+void DescriptionGenerator::Initialize(std::u16string_view sPrefix)
+{
+ msDescription = sPrefix;
+ if (!mxSet.is())
+ return;
+
+ {
+ SolarMutexGuard aGuard;
+
+ msDescription.append(' ');
+ msDescription.append(SvxResId(RID_SVXSTR_A11Y_WITH));
+ msDescription.append(' ');
+
+ msDescription.append(SvxResId(RID_SVXSTR_A11Y_STYLE));
+ msDescription.append('=');
+ }
+
+ try
+ {
+ if (mxSet.is())
+ {
+ uno::Any aValue = mxSet->getPropertyValue("Style");
+ uno::Reference<container::XNamed> xStyle(aValue, uno::UNO_QUERY);
+ if (xStyle.is())
+ msDescription.append(xStyle->getName());
+ }
+ else
+ msDescription.append("<no style>");
+ }
+ catch (const css::beans::UnknownPropertyException&)
+ {
+ msDescription.append("<unknown>");
+ }
+}
+
+OUString DescriptionGenerator::operator()()
+{
+ msDescription.append('.');
+ return msDescription.makeStringAndClear();
+}
+
+void DescriptionGenerator::AddProperty(const OUString& sPropertyName, PropertyType aType)
+{
+ uno::Reference<beans::XPropertyState> xState(mxShape, uno::UNO_QUERY);
+ if (!xState.is()
+ || xState->getPropertyState(sPropertyName) == beans::PropertyState_DEFAULT_VALUE)
+ return;
+
+ if (!mxSet.is())
+ return;
+
+ // Append a separator from previous Properties.
+ if (!mbIsFirstProperty)
+ msDescription.append(',');
+ else
+ {
+ SolarMutexGuard aGuard;
+
+ msDescription.append(' ');
+ msDescription.append(SvxResId(RID_SVXSTR_A11Y_AND));
+ msDescription.append(' ');
+ mbIsFirstProperty = false;
+ }
+
+ // Delegate to type specific property handling.
+ switch (aType)
+ {
+ case PropertyType::Color:
+ AddColor(sPropertyName);
+ break;
+ case PropertyType::Integer:
+ AddInteger(sPropertyName);
+ break;
+ }
+}
+
+void DescriptionGenerator::AppendString(std::u16string_view sString)
+{
+ msDescription.append(sString);
+}
+
+/** Search for the given color in the global color table. If found append
+ its name to the description. Otherwise append its RGB tuple.
+*/
+void DescriptionGenerator::AddColor(const OUString& sPropertyName)
+{
+ msDescription.append('=');
+
+ try
+ {
+ tools::Long nValue(0);
+ if (mxSet.is())
+ {
+ uno::Any aValue = mxSet->getPropertyValue(sPropertyName);
+ aValue >>= nValue;
+ }
+
+ msDescription.append(lookUpColorName(nValue));
+ }
+ catch (const css::beans::UnknownPropertyException&)
+ {
+ msDescription.append("<unknown>");
+ }
+}
+
+void DescriptionGenerator::AddInteger(const OUString& sPropertyName)
+{
+ msDescription.append('=');
+
+ try
+ {
+ if (mxSet.is())
+ {
+ uno::Any aValue = mxSet->getPropertyValue(sPropertyName);
+ tools::Long nValue = 0;
+ aValue >>= nValue;
+ msDescription.append(nValue);
+ }
+ }
+ catch (const css::beans::UnknownPropertyException&)
+ {
+ msDescription.append("<unknown>");
+ }
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/GraphCtlAccessibleContext.cxx b/svx/source/accessibility/GraphCtlAccessibleContext.cxx
new file mode 100644
index 000000000..531b75eb6
--- /dev/null
+++ b/svx/source/accessibility/GraphCtlAccessibleContext.cxx
@@ -0,0 +1,772 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/IllegalAccessibleComponentStateException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/mutex.hxx>
+#include <tools/gen.hxx>
+#include <svtools/colorcfg.hxx>
+#include <comphelper/accessibleeventnotifier.hxx>
+#include <svx/sdrpaintwindow.hxx>
+
+#include <svx/ShapeTypeHandler.hxx>
+#include <svx/AccessibleShapeInfo.hxx>
+#include <GraphCtlAccessibleContext.hxx>
+#include <svx/graphctl.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdpage.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/sdrhittesthelper.hxx>
+
+// namespaces
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::accessibility;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::accessibility;
+
+// internal
+/** initialize this component and set default values */
+SvxGraphCtrlAccessibleContext::SvxGraphCtrlAccessibleContext(
+ GraphCtrl& rRepr ) :
+
+ SvxGraphCtrlAccessibleContext_Base( m_aMutex ),
+ mpControl( &rRepr ),
+ mpModel (nullptr),
+ mpPage (nullptr),
+ mpView (nullptr),
+ mnClientId( 0 ),
+ mbDisposed( false )
+{
+ if (mpControl != nullptr)
+ {
+ mpModel = mpControl->GetSdrModel();
+ if (mpModel != nullptr)
+ mpPage = mpModel->GetPage( 0 );
+ mpView = mpControl->GetSdrView();
+
+ if( mpModel == nullptr || mpPage == nullptr || mpView == nullptr )
+ {
+ mbDisposed = true;
+ // Set all the pointers to NULL just in case they are used as
+ // a disposed flag.
+ mpModel = nullptr;
+ mpPage = nullptr;
+ mpView = nullptr;
+ }
+ }
+
+ {
+ ::SolarMutexGuard aSolarGuard;
+ msName = SvxResId( RID_SVXSTR_GRAPHCTRL_ACC_NAME );
+ msDescription = SvxResId( RID_SVXSTR_GRAPHCTRL_ACC_DESCRIPTION );
+ }
+
+ maTreeInfo.SetSdrView( mpView );
+ maTreeInfo.SetWindow(mpControl->GetDrawingArea()->get_ref_device().GetOwnerWindow());
+ maTreeInfo.SetViewForwarder( this );
+}
+
+
+/** on destruction, this component is disposed and all dispose listeners
+ are called, except if this component was already disposed */
+SvxGraphCtrlAccessibleContext::~SvxGraphCtrlAccessibleContext()
+{
+ disposing();
+}
+
+
+/** returns the XAccessible interface for a given SdrObject.
+ Multiple calls for the same SdrObject return the same XAccessible.
+*/
+Reference< XAccessible > SvxGraphCtrlAccessibleContext::getAccessible( const SdrObject* pObj )
+{
+ Reference<XAccessible> xAccessibleShape;
+
+ if( pObj )
+ {
+ // see if we already created an XAccessible for the given SdrObject
+ ShapesMapType::const_iterator iter = mxShapes.find( pObj );
+
+ if( iter != mxShapes.end() )
+ {
+ // if we already have one, return it
+ xAccessibleShape = (*iter).second.get();
+ }
+ else
+ {
+ // create a new one and remember in our internal map
+ Reference< XShape > xShape( Reference< XShape >::query( const_cast<SdrObject*>(pObj)->getUnoShape() ) );
+
+ css::uno::Reference<css::accessibility::XAccessible> xParent(getAccessibleParent());
+ AccessibleShapeInfo aShapeInfo (xShape,xParent);
+ // Create accessible object that corresponds to the descriptor's shape.
+ rtl::Reference<AccessibleShape> pAcc(ShapeTypeHandler::Instance().CreateAccessibleObject(
+ aShapeInfo, maTreeInfo));
+ xAccessibleShape = pAcc.get();
+ if (pAcc.is())
+ {
+ pAcc->Init ();
+ }
+ mxShapes[pObj] = pAcc;
+
+ // Create event and inform listeners of the object creation.
+ CommitChange( AccessibleEventId::CHILD, Any( xAccessibleShape ), Any( Reference<XAccessible>() ) );
+ }
+ }
+
+ return xAccessibleShape;
+}
+
+// XAccessible
+Reference< XAccessibleContext > SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleContext()
+{
+ return this;
+}
+
+// XAccessibleComponent
+sal_Bool SAL_CALL SvxGraphCtrlAccessibleContext::containsPoint( const awt::Point& rPoint )
+{
+ // no guard -> done in getSize()
+ awt::Size aSize (getSize());
+ return (rPoint.X >= 0)
+ && (rPoint.X < aSize.Width)
+ && (rPoint.Y >= 0)
+ && (rPoint.Y < aSize.Height);
+}
+
+
+Reference< XAccessible > SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleAtPoint( const awt::Point& rPoint )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XAccessible > xAccessible;
+
+ if( !mpControl )
+ {
+ throw DisposedException();
+ }
+
+ Point aPnt( rPoint.X, rPoint.Y );
+ aPnt = mpControl->GetDrawingArea()->get_ref_device().PixelToLogic(aPnt);
+
+ SdrObject* pObj = nullptr;
+
+ if(mpView && mpView->GetSdrPageView())
+ {
+ pObj = SdrObjListPrimitiveHit(*mpPage, aPnt, 1, *mpView->GetSdrPageView(), nullptr, false);
+ }
+
+ if( pObj )
+ xAccessible = getAccessible( pObj );
+
+ return xAccessible;
+}
+
+awt::Rectangle SAL_CALL SvxGraphCtrlAccessibleContext::getBounds()
+{
+ const SolarMutexGuard aSolarGuard;
+
+ if (nullptr == mpControl)
+ throw DisposedException();
+
+ const Point aOutPos;
+ const Size aOutSize( mpControl->GetOutputSizePixel() );
+ awt::Rectangle aRet;
+
+ aRet.X = aOutPos.X();
+ aRet.Y = aOutPos.Y();
+ aRet.Width = aOutSize.Width();
+ aRet.Height = aOutSize.Height();
+
+ return aRet;
+}
+
+awt::Point SAL_CALL SvxGraphCtrlAccessibleContext::getLocation()
+{
+ const SolarMutexGuard aSolarGuard;
+
+ if (nullptr == mpControl)
+ throw DisposedException();
+
+ const awt::Rectangle aRect( getBounds() );
+ awt::Point aRet;
+
+ aRet.X = aRect.X;
+ aRet.Y = aRect.Y;
+
+ return aRet;
+}
+
+awt::Point SAL_CALL SvxGraphCtrlAccessibleContext::getLocationOnScreen()
+{
+ const SolarMutexGuard aSolarGuard;
+
+ if (nullptr == mpControl)
+ throw DisposedException();
+
+ awt::Point aScreenLoc(0, 0);
+
+ auto xParent(getAccessibleParent());
+ if (xParent)
+ {
+ css::uno::Reference<css::accessibility::XAccessibleContext> xParentContext(xParent->getAccessibleContext());
+ css::uno::Reference<css::accessibility::XAccessibleComponent> xParentComponent(xParentContext, css::uno::UNO_QUERY);
+ OSL_ENSURE( xParentComponent.is(), "ValueSetAcc::getLocationOnScreen: no parent component!" );
+ if ( xParentComponent.is() )
+ {
+ awt::Point aParentScreenLoc( xParentComponent->getLocationOnScreen() );
+ awt::Point aOwnRelativeLoc( getLocation() );
+ aScreenLoc.X = aParentScreenLoc.X + aOwnRelativeLoc.X;
+ aScreenLoc.Y = aParentScreenLoc.Y + aOwnRelativeLoc.Y;
+ }
+ }
+
+ return aScreenLoc;
+}
+
+awt::Size SAL_CALL SvxGraphCtrlAccessibleContext::getSize()
+{
+ const SolarMutexGuard aSolarGuard;
+
+ if (nullptr == mpControl)
+ throw DisposedException();
+
+ const awt::Rectangle aRect( getBounds() );
+ awt::Size aRet;
+
+ aRet.Width = aRect.Width;
+ aRet.Height = aRect.Height;
+
+ return aRet;
+}
+
+// XAccessibleContext
+sal_Int32 SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleChildCount()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpPage )
+ throw DisposedException();
+
+ return mpPage->GetObjCount();
+}
+
+
+/** returns the SdrObject at index nIndex from the model of this graph */
+SdrObject* SvxGraphCtrlAccessibleContext::getSdrObject( sal_Int32 nIndex )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpPage )
+ throw DisposedException();
+
+ if( (nIndex < 0) || ( o3tl::make_unsigned(nIndex) >= mpPage->GetObjCount() ) )
+ throw lang::IndexOutOfBoundsException();
+
+ return mpPage->GetObj( nIndex );
+}
+
+
+/** sends an AccessibleEventObject to all added XAccessibleEventListeners */
+void SvxGraphCtrlAccessibleContext::CommitChange (
+ sal_Int16 nEventId,
+ const uno::Any& rNewValue,
+ const uno::Any& rOldValue)
+{
+ AccessibleEventObject aEvent (
+ static_cast<uno::XWeak*>(this),
+ nEventId,
+ rNewValue,
+ rOldValue);
+
+ if (mnClientId)
+ comphelper::AccessibleEventNotifier::addEvent( mnClientId, aEvent );
+}
+
+Reference< XAccessible > SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleChild( sal_Int32 nIndex )
+{
+ ::SolarMutexGuard aGuard;
+
+ return getAccessible( getSdrObject( nIndex ) );
+}
+
+Reference< XAccessible > SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleParent()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpControl )
+ throw DisposedException();
+
+ return mpControl->GetDrawingArea()->get_accessible_parent();
+}
+
+sal_Int32 SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleIndexInParent()
+{
+ ::SolarMutexGuard aGuard;
+ // Use a simple but slow solution for now. Optimize later.
+
+ // Iterate over all the parent's children and search for this object.
+ css::uno::Reference<css::accessibility::XAccessible> xParent(getAccessibleParent());
+ if (xParent.is())
+ {
+ Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
+ if( xParentContext.is() )
+ {
+ sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
+ for( sal_Int32 i = 0 ; i < nChildCount ; ++i )
+ {
+ Reference< XAccessible > xChild( xParentContext->getAccessibleChild( i ) );
+ if( xChild.is() )
+ {
+ Reference< XAccessibleContext > xChildContext = xChild->getAccessibleContext();
+ if( xChildContext == static_cast<XAccessibleContext*>(this) )
+ return i;
+ }
+ }
+ }
+ }
+
+ // Return -1 to indicate that this object's parent does not know about the
+ // object.
+ return -1;
+}
+
+
+sal_Int16 SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleRole()
+{
+ return AccessibleRole::PANEL;
+}
+
+
+OUString SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleDescription()
+{
+ ::SolarMutexGuard aGuard;
+ return msDescription;
+}
+
+
+OUString SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleName()
+{
+ ::SolarMutexGuard aGuard;
+ return msName;
+}
+
+
+/** Return empty reference to indicate that the relation set is not
+ supported.
+*/
+Reference< XAccessibleRelationSet > SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleRelationSet()
+{
+ return Reference< XAccessibleRelationSet >();
+}
+
+
+Reference< XAccessibleStateSet > SAL_CALL SvxGraphCtrlAccessibleContext::getAccessibleStateSet()
+{
+ ::SolarMutexGuard aGuard;
+
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSetHelper = new utl::AccessibleStateSetHelper;
+
+ if ( rBHelper.bDisposed || mbDisposed )
+ {
+ pStateSetHelper->AddState( AccessibleStateType::DEFUNC );
+ }
+ else
+ {
+ pStateSetHelper->AddState( AccessibleStateType::FOCUSABLE );
+ if( mpControl->HasFocus() )
+ pStateSetHelper->AddState( AccessibleStateType::FOCUSED );
+ pStateSetHelper->AddState( AccessibleStateType::OPAQUE );
+ pStateSetHelper->AddState( AccessibleStateType::SHOWING );
+ pStateSetHelper->AddState( AccessibleStateType::VISIBLE );
+ }
+
+ return pStateSetHelper;
+}
+
+
+lang::Locale SAL_CALL SvxGraphCtrlAccessibleContext::getLocale()
+{
+ ::SolarMutexGuard aGuard;
+
+ css::uno::Reference<css::accessibility::XAccessible> xParent(getAccessibleParent());
+ if (xParent.is())
+ {
+ Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
+ if( xParentContext.is() )
+ return xParentContext->getLocale();
+ }
+
+ // No parent. Therefore throw exception to indicate this cluelessness.
+ throw IllegalAccessibleComponentStateException();
+}
+
+// XAccessibleEventListener
+void SAL_CALL SvxGraphCtrlAccessibleContext::addAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener )
+{
+ if (xListener.is())
+ {
+ ::SolarMutexGuard aGuard;
+ if (!mnClientId)
+ mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
+ comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener );
+ }
+}
+
+
+void SAL_CALL SvxGraphCtrlAccessibleContext::removeAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener )
+{
+ if (!xListener.is())
+ return;
+
+ ::SolarMutexGuard aGuard;
+
+ sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener );
+ if ( !nListenerCount )
+ {
+ // no listeners anymore
+ // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
+ // and at least to us not firing any events anymore, in case somebody calls
+ // NotifyAccessibleEvent, again
+ comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
+ mnClientId = 0;
+ }
+}
+
+void SAL_CALL SvxGraphCtrlAccessibleContext::grabFocus()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpControl )
+ throw DisposedException();
+
+ mpControl->GrabFocus();
+}
+
+sal_Int32 SAL_CALL SvxGraphCtrlAccessibleContext::getForeground()
+{
+ svtools::ColorConfig aColorConfig;
+ Color nColor = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor;
+ return static_cast<sal_Int32>(nColor);
+}
+
+sal_Int32 SAL_CALL SvxGraphCtrlAccessibleContext::getBackground()
+{
+ Color nColor = Application::GetSettings().GetStyleSettings().GetWindowColor();
+ return static_cast<sal_Int32>(nColor);
+}
+
+// XServiceInfo
+OUString SAL_CALL SvxGraphCtrlAccessibleContext::getImplementationName()
+{
+ return "com.sun.star.comp.ui.SvxGraphCtrlAccessibleContext";
+}
+
+sal_Bool SAL_CALL SvxGraphCtrlAccessibleContext::supportsService( const OUString& sServiceName )
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+Sequence< OUString > SAL_CALL SvxGraphCtrlAccessibleContext::getSupportedServiceNames()
+{
+ return { "com.sun.star.accessibility.Accessible",
+ "com.sun.star.accessibility.AccessibleContext",
+ "com.sun.star.drawing.AccessibleGraphControl" };
+}
+
+// XTypeProvider
+Sequence<sal_Int8> SAL_CALL SvxGraphCtrlAccessibleContext::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XServiceName
+OUString SvxGraphCtrlAccessibleContext::getServiceName()
+{
+ return "com.sun.star.accessibility.AccessibleContext";
+}
+
+// XAccessibleSelection
+void SAL_CALL SvxGraphCtrlAccessibleContext::selectAccessibleChild( sal_Int32 nIndex )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpView )
+ throw DisposedException();
+
+ SdrObject* pObj = getSdrObject( nIndex );
+
+ if( pObj )
+ mpView->MarkObj( pObj, mpView->GetSdrPageView());
+}
+
+
+sal_Bool SAL_CALL SvxGraphCtrlAccessibleContext::isAccessibleChildSelected( sal_Int32 nIndex )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpView )
+ throw DisposedException();
+
+ return mpView->IsObjMarked( getSdrObject( nIndex ) );
+}
+
+
+void SAL_CALL SvxGraphCtrlAccessibleContext::clearAccessibleSelection()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpView )
+ throw DisposedException();
+
+ mpView->UnmarkAllObj();
+}
+
+
+void SAL_CALL SvxGraphCtrlAccessibleContext::selectAllAccessibleChildren()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpView )
+ throw DisposedException();
+
+ mpView->MarkAllObj();
+}
+
+
+sal_Int32 SAL_CALL SvxGraphCtrlAccessibleContext::getSelectedAccessibleChildCount()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( nullptr == mpView )
+ throw DisposedException();
+
+ const SdrMarkList& rList = mpView->GetMarkedObjectList();
+ return static_cast<sal_Int32>(rList.GetMarkCount());
+}
+
+
+Reference< XAccessible > SAL_CALL SvxGraphCtrlAccessibleContext::getSelectedAccessibleChild( sal_Int32 nIndex )
+{
+ ::SolarMutexGuard aGuard;
+
+ checkChildIndexOnSelection( nIndex );
+
+ Reference< XAccessible > xAccessible;
+
+ const SdrMarkList& rList = mpView->GetMarkedObjectList();
+ SdrObject* pObj = rList.GetMark(static_cast<size_t>(nIndex))->GetMarkedSdrObj();
+ if( pObj )
+ xAccessible = getAccessible( pObj );
+
+ return xAccessible;
+}
+
+
+void SAL_CALL SvxGraphCtrlAccessibleContext::deselectAccessibleChild( sal_Int32 nIndex )
+{
+ ::SolarMutexGuard aGuard;
+
+ checkChildIndexOnSelection( nIndex );
+
+ if( !mpView )
+ return;
+
+ const SdrMarkList& rList = mpView->GetMarkedObjectList();
+
+ SdrObject* pObj = getSdrObject( nIndex );
+ if( !pObj )
+ return;
+
+ SdrMarkList aRefList( rList );
+
+ SdrPageView* pPV = mpView->GetSdrPageView();
+ mpView->UnmarkAllObj( pPV );
+
+ const size_t nCount = aRefList.GetMarkCount();
+ for( size_t nMark = 0; nMark < nCount; ++nMark )
+ {
+ if( aRefList.GetMark(nMark)->GetMarkedSdrObj() != pObj )
+ mpView->MarkObj( aRefList.GetMark(nMark)->GetMarkedSdrObj(), pPV );
+ }
+}
+
+// internals
+void SvxGraphCtrlAccessibleContext::checkChildIndexOnSelection( tools::Long nIndex )
+{
+ if( nIndex < 0 || nIndex >= getSelectedAccessibleChildCount() )
+ throw lang::IndexOutOfBoundsException();
+}
+
+
+/** Replace the model, page, and view pointers by the ones provided
+ (explicitly and implicitly).
+*/
+void SvxGraphCtrlAccessibleContext::setModelAndView (
+ SdrModel* pModel,
+ SdrView* pView)
+{
+ ::SolarMutexGuard aGuard;
+
+ mpModel = pModel;
+ if (mpModel != nullptr)
+ mpPage = mpModel->GetPage( 0 );
+ mpView = pView;
+
+ if (mpModel == nullptr || mpPage == nullptr || mpView == nullptr)
+ {
+ mbDisposed = true;
+
+ // Set all the pointers to NULL just in case they are used as
+ // a disposed flag.
+ mpModel = nullptr;
+ mpPage = nullptr;
+ mpView = nullptr;
+ }
+
+ maTreeInfo.SetSdrView (mpView);
+}
+
+
+void SAL_CALL SvxGraphCtrlAccessibleContext::disposing()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( mbDisposed )
+ return;
+
+ mbDisposed = true;
+
+ mpControl = nullptr; // object dies with representation
+ mpView = nullptr;
+ mpPage = nullptr;
+
+ {
+ for (const auto& rEntry : mxShapes)
+ {
+ rtl::Reference<XAccessible> pAcc(rEntry.second);
+ Reference< XComponent > xComp( pAcc.get(), UNO_QUERY );
+ if( xComp.is() )
+ xComp->dispose();
+ }
+
+ mxShapes.clear();
+ }
+
+ // Send a disposing to all listeners.
+ if ( mnClientId )
+ {
+ comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this );
+ mnClientId = 0;
+ }
+}
+
+void SvxGraphCtrlAccessibleContext::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+{
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>( &rHint );
+ switch( pSdrHint->GetKind() )
+ {
+ case SdrHintKind::ObjectChange:
+ {
+ ShapesMapType::iterator iter = mxShapes.find( pSdrHint->GetObject() );
+
+ if( iter != mxShapes.end() )
+ {
+ // if we already have one, return it
+ rtl::Reference<AccessibleShape> pShape((*iter).second);
+
+ if( pShape.is() )
+ pShape->CommitChange( AccessibleEventId::VISIBLE_DATA_CHANGED, uno::Any(), uno::Any() );
+ }
+ }
+ break;
+
+ case SdrHintKind::ObjectInserted:
+ CommitChange( AccessibleEventId::CHILD, Any( getAccessible( pSdrHint->GetObject() ) ) , uno::Any());
+ break;
+ case SdrHintKind::ObjectRemoved:
+ CommitChange( AccessibleEventId::CHILD, uno::Any(), Any( getAccessible( pSdrHint->GetObject() ) ) );
+ break;
+ case SdrHintKind::ModelCleared:
+ dispose();
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // Has our SdDrawDocument just died?
+ if(rHint.GetId() == SfxHintId::Dying)
+ {
+ dispose();
+ }
+ }
+}
+
+// IAccessibleViewforwarder
+tools::Rectangle SvxGraphCtrlAccessibleContext::GetVisibleArea() const
+{
+ tools::Rectangle aVisArea;
+
+ if( mpView && mpView->PaintWindowCount())
+ {
+ SdrPaintWindow* pPaintWindow = mpView->GetPaintWindow(0);
+ aVisArea = pPaintWindow->GetVisibleArea();
+ }
+
+ return aVisArea;
+}
+
+Point SvxGraphCtrlAccessibleContext::LogicToPixel (const Point& rPoint) const
+{
+ if( mpControl )
+ {
+ return mpControl->GetDrawingArea()->get_ref_device().LogicToPixel (rPoint) + mpControl->GetPositionInDialog();
+ }
+ else
+ {
+ return rPoint;
+ }
+}
+
+Size SvxGraphCtrlAccessibleContext::LogicToPixel (const Size& rSize) const
+{
+ if( mpControl )
+ return mpControl->GetDrawingArea()->get_ref_device().LogicToPixel(rSize);
+ else
+ return rSize;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/ShapeTypeHandler.cxx b/svx/source/accessibility/ShapeTypeHandler.cxx
new file mode 100644
index 000000000..1b169c761
--- /dev/null
+++ b/svx/source/accessibility/ShapeTypeHandler.cxx
@@ -0,0 +1,306 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/ShapeTypeHandler.hxx>
+#include <svx/SvxShapeTypes.hxx>
+#include <svx/AccessibleShapeInfo.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/AccessibleShape.hxx>
+#include <svx/dialmgr.hxx>
+
+#include <svx/svdoashp.hxx>
+
+#include <svx/strings.hrc>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+namespace accessibility {
+
+// Pointer to the shape type handler singleton.
+ShapeTypeHandler* ShapeTypeHandler::instance = nullptr;
+
+
+// Create an empty reference to an accessible object.
+static rtl::Reference<AccessibleShape>
+ CreateEmptyShapeReference (
+ const AccessibleShapeInfo& /*rShapeInfo*/,
+ const AccessibleShapeTreeInfo& /*rShapeTreeInfo*/,
+ ShapeTypeId /*nId*/)
+{
+ return nullptr;
+}
+
+
+ShapeTypeHandler& ShapeTypeHandler::Instance()
+{
+ // Using double check pattern to make sure that exactly one instance of
+ // the shape type handler is instantiated.
+ if (instance == nullptr)
+ {
+ SolarMutexGuard aGuard;
+ if (instance == nullptr)
+ {
+ // Create the single instance of the shape type handler.
+ instance = new ShapeTypeHandler;
+
+ // Register the basic SVX shape types.
+ RegisterDrawShapeTypes ();
+ }
+ }
+
+ return *instance;
+}
+
+
+/** The given service name is first transformed into a slot id that
+ identifies the place of the type descriptor. From that descriptor the
+ shape type id is returned.
+*/
+ShapeTypeId ShapeTypeHandler::GetTypeId (const OUString& aServiceName) const
+{
+ tServiceNameToSlotId::const_iterator I (maServiceNameToSlotId.find (aServiceName));
+ if (I != maServiceNameToSlotId.end())
+ {
+ return maShapeTypeDescriptorList[I->second].mnShapeTypeId;
+ }
+ else
+ return -1;
+}
+
+
+/** Extract the specified shape's service name and forward the request to
+ the appropriate method.
+*/
+ShapeTypeId ShapeTypeHandler::GetTypeId (const uno::Reference<drawing::XShape>& rxShape) const
+{
+ if (rxShape.is())
+ return GetTypeId (rxShape->getShapeType());
+ else
+ return -1;
+}
+
+
+/** This factory method determines the type descriptor for the type of the
+ given shape, then calls the descriptor's create function, and finally
+ initializes the new object.
+*/
+rtl::Reference<AccessibleShape>
+ ShapeTypeHandler::CreateAccessibleObject (
+ const AccessibleShapeInfo& rShapeInfo,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo) const
+{
+ ShapeTypeId nSlotId (GetSlotId (rShapeInfo.mxShape));
+ rtl::Reference<AccessibleShape> pShape(
+ maShapeTypeDescriptorList[nSlotId].maCreateFunction (
+ rShapeInfo,
+ rShapeTreeInfo,
+ maShapeTypeDescriptorList[nSlotId].mnShapeTypeId));
+ return pShape;
+}
+
+
+/** Create the single instance of this class and initialize its list of
+ type descriptors with an entry of an unknown type.
+*/
+ShapeTypeHandler::ShapeTypeHandler()
+ : maShapeTypeDescriptorList (1)
+{
+ // Make sure that at least the UNKNOWN entry is present.
+ // Resize the list, if necessary, so that the new type can be inserted.
+ maShapeTypeDescriptorList[0].mnShapeTypeId = UNKNOWN_SHAPE_TYPE;
+ maShapeTypeDescriptorList[0].msServiceName = "UNKNOWN_SHAPE_TYPE";
+ maShapeTypeDescriptorList[0].maCreateFunction = CreateEmptyShapeReference;
+ maServiceNameToSlotId[maShapeTypeDescriptorList[0].msServiceName] = 0;
+}
+
+
+ShapeTypeHandler::~ShapeTypeHandler()
+{
+ // Because this class is a singleton and the only instance, whose
+ // destructor has just been called, is pointed to from instance,
+ // we reset the static variable instance, so that further calls to
+ // getInstance do not return an undefined object but create a new
+ // singleton.
+ instance = nullptr;
+}
+
+
+void ShapeTypeHandler::AddShapeTypeList (int nDescriptorCount,
+ ShapeTypeDescriptor const aDescriptorList[])
+{
+ SolarMutexGuard aGuard;
+
+ // Determine first id of new type descriptor(s).
+ int nFirstId = maShapeTypeDescriptorList.size();
+
+ // Resize the list, if necessary, so that the types can be inserted.
+ maShapeTypeDescriptorList.resize (nFirstId + nDescriptorCount);
+
+ for (int i=0; i<nDescriptorCount; i++)
+ {
+ // Fill Type descriptor.
+ maShapeTypeDescriptorList[nFirstId+i].mnShapeTypeId = aDescriptorList[i].mnShapeTypeId;
+ maShapeTypeDescriptorList[nFirstId+i].msServiceName = aDescriptorList[i].msServiceName;
+ maShapeTypeDescriptorList[nFirstId+i].maCreateFunction = aDescriptorList[i].maCreateFunction;
+
+ // Update inverse mapping from service name to the descriptor's position.
+ maServiceNameToSlotId[aDescriptorList[i].msServiceName] = nFirstId+i;
+ }
+}
+
+
+tools::Long ShapeTypeHandler::GetSlotId (const OUString& aServiceName) const
+{
+ tServiceNameToSlotId::const_iterator I (maServiceNameToSlotId.find (aServiceName));
+ if (I != maServiceNameToSlotId.end())
+ return I->second;
+ else
+ return 0;
+}
+
+
+// Extract the given shape's service name and forward request to appropriate
+// method.
+tools::Long ShapeTypeHandler::GetSlotId (const uno::Reference<drawing::XShape>& rxShape) const
+{
+ if (rxShape.is())
+ return GetSlotId (rxShape->getShapeType());
+ else
+ return 0;
+}
+
+/// get the accessible base name for an object
+OUString ShapeTypeHandler::CreateAccessibleBaseName (const uno::Reference<drawing::XShape>& rxShape)
+{
+ TranslateId pResourceId;
+ OUString sName;
+
+ switch (ShapeTypeHandler::Instance().GetTypeId (rxShape))
+ {
+ // case DRAWING_3D_POLYGON: was removed in original code in
+ // AccessibleShape::CreateAccessibleBaseName. See issue 11190 for details.
+ // Id can be removed from SvxShapeTypes.hxx as well.
+ case DRAWING_3D_CUBE:
+ pResourceId = STR_ObjNameSingulCube3d;
+ break;
+ case DRAWING_3D_EXTRUDE:
+ pResourceId = STR_ObjNameSingulExtrude3d;
+ break;
+ case DRAWING_3D_LATHE:
+ pResourceId = STR_ObjNameSingulLathe3d;
+ break;
+ case DRAWING_3D_SCENE:
+ pResourceId = STR_ObjNameSingulScene3d;
+ break;
+ case DRAWING_3D_SPHERE:
+ pResourceId = STR_ObjNameSingulSphere3d;
+ break;
+ case DRAWING_CAPTION:
+ pResourceId = STR_ObjNameSingulCAPTION;
+ break;
+ case DRAWING_CLOSED_BEZIER:
+ pResourceId = STR_ObjNameSingulPATHFILL;
+ break;
+ case DRAWING_CLOSED_FREEHAND:
+ pResourceId = STR_ObjNameSingulFREEFILL;
+ break;
+ case DRAWING_CONNECTOR:
+ pResourceId = STR_ObjNameSingulEDGE;
+ break;
+ case DRAWING_CONTROL:
+ pResourceId = STR_ObjNameSingulUno;
+ break;
+ case DRAWING_ELLIPSE:
+ pResourceId = STR_ObjNameSingulCIRCE;
+ break;
+ case DRAWING_GROUP:
+ pResourceId = STR_ObjNameSingulGRUP;
+ break;
+ case DRAWING_LINE:
+ pResourceId = STR_ObjNameSingulLINE;
+ break;
+ case DRAWING_MEASURE:
+ pResourceId = STR_ObjNameSingulMEASURE;
+ break;
+ case DRAWING_OPEN_BEZIER:
+ pResourceId = STR_ObjNameSingulPATHLINE;
+ break;
+ case DRAWING_OPEN_FREEHAND:
+ pResourceId = STR_ObjNameSingulFREELINE;
+ break;
+ case DRAWING_PAGE:
+ pResourceId = STR_ObjNameSingulPAGE;
+ break;
+ case DRAWING_POLY_LINE:
+ pResourceId = STR_ObjNameSingulPLIN;
+ break;
+ case DRAWING_POLY_LINE_PATH:
+ pResourceId = STR_ObjNameSingulPLIN;
+ break;
+ case DRAWING_POLY_POLYGON:
+ pResourceId = STR_ObjNameSingulPOLY;
+ break;
+ case DRAWING_POLY_POLYGON_PATH:
+ pResourceId = STR_ObjNameSingulPOLY;
+ break;
+ case DRAWING_RECTANGLE:
+ pResourceId = STR_ObjNameSingulRECT;
+ break;
+ case DRAWING_CUSTOM:
+ pResourceId = STR_ObjNameSingulCUSTOMSHAPE;
+
+ if (SdrObject* pSdrObject = SdrObject::getSdrObjectFromXShape(rxShape))
+ {
+ if (auto pCustomShape = dynamic_cast<SdrObjCustomShape*>(pSdrObject))
+ {
+ if (pCustomShape->IsTextPath())
+ pResourceId = STR_ObjNameSingulFONTWORK;
+ else
+ {
+ pResourceId = {};
+ sName = pCustomShape->GetCustomShapeName();
+ }
+ }
+ }
+ break;
+ case DRAWING_TEXT:
+ pResourceId = STR_ObjNameSingulTEXT;
+ break;
+ default:
+ pResourceId = {};
+ sName = "UnknownAccessibleShape";
+ if (rxShape.is())
+ sName += ": " + rxShape->getShapeType();
+ break;
+ }
+
+ if (pResourceId)
+ {
+ SolarMutexGuard aGuard;
+ sName = SvxResId(pResourceId);
+ }
+
+ return sName;
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/SvxShapeTypes.cxx b/svx/source/accessibility/SvxShapeTypes.cxx
new file mode 100644
index 000000000..b02a153a4
--- /dev/null
+++ b/svx/source/accessibility/SvxShapeTypes.cxx
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/SvxShapeTypes.hxx>
+#include <svx/AccessibleShape.hxx>
+#include <svx/AccessibleGraphicShape.hxx>
+#include <svx/AccessibleOLEShape.hxx>
+#include <svx/AccessibleControlShape.hxx>
+#include <svx/ShapeTypeHandler.hxx>
+#include <AccessibleTableShape.hxx>
+
+namespace accessibility {
+
+static rtl::Reference<AccessibleShape> CreateSvxAccessibleShape (
+ const AccessibleShapeInfo& rShapeInfo,
+ const AccessibleShapeTreeInfo& rShapeTreeInfo,
+ ShapeTypeId nId)
+{
+ switch (nId)
+ {
+ case DRAWING_3D_CUBE:
+ case DRAWING_3D_EXTRUDE:
+ case DRAWING_3D_LATHE:
+ case DRAWING_3D_SCENE:
+ case DRAWING_3D_SPHERE:
+ case DRAWING_CAPTION:
+ case DRAWING_CLOSED_BEZIER:
+ case DRAWING_CLOSED_FREEHAND:
+ case DRAWING_CONNECTOR:
+ case DRAWING_ELLIPSE:
+ case DRAWING_GROUP:
+ case DRAWING_LINE:
+ case DRAWING_MEASURE:
+ case DRAWING_OPEN_BEZIER:
+ case DRAWING_OPEN_FREEHAND:
+ case DRAWING_PAGE:
+ case DRAWING_POLY_POLYGON:
+ case DRAWING_POLY_LINE:
+ case DRAWING_POLY_POLYGON_PATH:
+ case DRAWING_POLY_LINE_PATH:
+ case DRAWING_RECTANGLE:
+ case DRAWING_TEXT:
+ // Default accessibility shape for
+ // css::drawing::CustomShape (#i37790#)
+ case DRAWING_CUSTOM:
+ // Default accessibility shape for
+ // css::drawing::MediaShape (#i85429#)
+ case DRAWING_MEDIA:
+ return new AccessibleShape (rShapeInfo, rShapeTreeInfo);
+
+ case DRAWING_CONTROL:
+ return new AccessibleControlShape (rShapeInfo, rShapeTreeInfo);
+
+ case DRAWING_GRAPHIC_OBJECT:
+ return new AccessibleGraphicShape (rShapeInfo, rShapeTreeInfo);
+
+ case DRAWING_APPLET:
+ case DRAWING_FRAME:
+ case DRAWING_OLE:
+ case DRAWING_PLUGIN:
+ return new AccessibleOLEShape (rShapeInfo, rShapeTreeInfo);
+
+ case DRAWING_TABLE:
+ return new AccessibleTableShape( rShapeInfo, rShapeTreeInfo );
+
+ default:
+ return nullptr;
+ }
+}
+
+void RegisterDrawShapeTypes()
+{
+ /** List of shape type descriptors corresponding to the
+ <type>SvxShapeTypes</type> enum.
+ */
+ static ShapeTypeDescriptor const aSvxShapeTypeList[] = {
+ ShapeTypeDescriptor ( DRAWING_TEXT, "com.sun.star.drawing.TextShape",
+ CreateSvxAccessibleShape),
+ ShapeTypeDescriptor (DRAWING_RECTANGLE, "com.sun.star.drawing.RectangleShape",
+ CreateSvxAccessibleShape),
+ ShapeTypeDescriptor ( DRAWING_ELLIPSE, "com.sun.star.drawing.EllipseShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_CONTROL, "com.sun.star.drawing.ControlShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_CONNECTOR, "com.sun.star.drawing.ConnectorShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_MEASURE, "com.sun.star.drawing.MeasureShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_LINE, "com.sun.star.drawing.LineShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_POLY_POLYGON, "com.sun.star.drawing.PolyPolygonShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_POLY_LINE, "com.sun.star.drawing.PolyLineShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_OPEN_BEZIER, "com.sun.star.drawing.OpenBezierShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_CLOSED_BEZIER, "com.sun.star.drawing.ClosedBezierShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_OPEN_FREEHAND, "com.sun.star.drawing.OpenFreeHandShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_CLOSED_FREEHAND, "com.sun.star.drawing.ClosedFreeHandShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_POLY_POLYGON_PATH, "com.sun.star.drawing.PolyPolygonPathShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_POLY_LINE_PATH, "com.sun.star.drawing.PolyLinePathShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_GRAPHIC_OBJECT, "com.sun.star.drawing.GraphicObjectShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_GROUP, "com.sun.star.drawing.GroupShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_OLE, "com.sun.star.drawing.OLE2Shape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_PAGE, "com.sun.star.drawing.PageShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_CAPTION, "com.sun.star.drawing.CaptionShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_FRAME, "com.sun.star.drawing.FrameShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_PLUGIN, "com.sun.star.drawing.PluginShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_APPLET, "com.sun.star.drawing.AppletShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_3D_SCENE, "com.sun.star.drawing.Shape3DSceneObject",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_3D_CUBE, "com.sun.star.drawing.Shape3DCubeObject",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_3D_SPHERE, "com.sun.star.drawing.Shape3DSphereObject",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_3D_LATHE, "com.sun.star.drawing.Shape3DLatheObject",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_3D_EXTRUDE, "com.sun.star.drawing.Shape3DExtrudeObject",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_CUSTOM, "com.sun.star.drawing.CustomShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_TABLE, "com.sun.star.drawing.TableShape",
+ CreateSvxAccessibleShape ),
+ ShapeTypeDescriptor ( DRAWING_MEDIA, "com.sun.star.drawing.MediaShape",
+ CreateSvxAccessibleShape ),
+
+ };
+
+ // Crash while inserting callout with activated accessibility (#i37790#)
+ ShapeTypeHandler::Instance().AddShapeTypeList ( DRAWING_END, aSvxShapeTypeList);
+}
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/charmapacc.cxx b/svx/source/accessibility/charmapacc.cxx
new file mode 100644
index 000000000..0de91ccee
--- /dev/null
+++ b/svx/source/accessibility/charmapacc.cxx
@@ -0,0 +1,584 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unotools/accessiblestatesethelper.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <stdio.h>
+#include <svx/charmap.hxx>
+#include <charmapacc.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <o3tl/temporary.hxx>
+#include <osl/interlck.h>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <comphelper/types.hxx>
+
+namespace svx
+{
+ using namespace comphelper;
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::accessibility;
+
+SvxShowCharSetItem::SvxShowCharSetItem( SvxShowCharSet& rParent,SvxShowCharSetAcc* _pParent,sal_uInt16 _nPos ) :
+ mrParent( rParent )
+ ,mnId( _nPos )
+ ,m_pParent(_pParent)
+{
+}
+
+SvxShowCharSetItem::~SvxShowCharSetItem()
+{
+ if ( m_xItem.is() )
+ {
+ m_xItem->ParentDestroyed();
+ m_xItem.clear();
+ }
+}
+
+uno::Reference< css::accessibility::XAccessible > SvxShowCharSetItem::GetAccessible()
+{
+ if( !m_xItem.is() )
+ {
+ m_xItem = new SvxShowCharSetItemAcc( this );
+ }
+
+ return m_xItem;
+}
+
+SvxShowCharSetAcc::SvxShowCharSetAcc(SvxShowCharSet* pParent)
+ : m_pParent(pParent)
+{
+ osl_atomic_increment(&m_refCount);
+ {
+ lateInit(this);
+ }
+ osl_atomic_decrement(&m_refCount);
+}
+
+SvxShowCharSetAcc::~SvxShowCharSetAcc()
+{
+ ensureDisposed();
+}
+
+void SAL_CALL SvxShowCharSetAcc::disposing()
+{
+ OAccessibleSelectionHelper::disposing();
+ for (auto& rChild : m_aChildren)
+ ::comphelper::disposeComponent(rChild);
+
+ m_aChildren.clear();
+ m_pParent = nullptr;
+}
+
+
+IMPLEMENT_FORWARD_XINTERFACE2( SvxShowCharSetAcc, OAccessibleSelectionHelper, OAccessibleHelper_Base )
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( SvxShowCharSetAcc, OAccessibleSelectionHelper, OAccessibleHelper_Base )
+
+bool SvxShowCharSetAcc::implIsSelected( sal_Int32 nAccessibleChildIndex )
+{
+ return m_pParent && m_pParent->IsSelected(
+ sal::static_int_cast<sal_uInt16>(nAccessibleChildIndex));
+}
+
+ // select the specified child => watch for special ChildIndexes (ACCESSIBLE_SELECTION_CHILD_xxx)
+void SvxShowCharSetAcc::implSelect(sal_Int32 nAccessibleChildIndex, bool bSelect)
+{
+ if ( m_pParent )
+ {
+ if ( bSelect )
+ m_pParent->SelectIndex(nAccessibleChildIndex, true);
+ else
+ m_pParent->DeSelect();
+ }
+}
+
+css::awt::Rectangle SvxShowCharSetAcc::implGetBounds()
+{
+ awt::Rectangle aRet;
+
+ if (m_pParent)
+ {
+ const Point aOutPos;//( m_pParent->GetPosPixel() );
+ Size aOutSize( m_pParent->GetOutputSizePixel());
+
+ aRet.X = aOutPos.X();
+ aRet.Y = aOutPos.Y();
+ aRet.Width = aOutSize.Width();
+ aRet.Height = aOutSize.Height();
+ }
+
+ return aRet;
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetAcc::getAccessibleChildCount()
+{
+ OExternalLockGuard aGuard( this );
+
+ return m_pParent->getMaxCharCount();
+}
+
+uno::Reference< css::accessibility::XAccessible > SAL_CALL SvxShowCharSetAcc::getAccessibleChild( sal_Int32 i )
+{
+ OExternalLockGuard aGuard( this );
+
+ uno::Reference< css::accessibility::XAccessible > xRet;
+ SvxShowCharSetItem* pItem = m_pParent->ImplGetItem( static_cast< sal_uInt16 >( i ) );
+
+ if( !pItem )
+ throw lang::IndexOutOfBoundsException();
+
+ pItem->m_pParent = this;
+ xRet = pItem->GetAccessible();
+ m_aChildren.push_back(xRet);
+
+ return xRet;
+}
+
+uno::Reference< css::accessibility::XAccessible > SAL_CALL SvxShowCharSetAcc::getAccessibleParent()
+{
+ OExternalLockGuard aGuard( this );
+
+ if (m_pParent)
+ return m_pParent->getAccessibleParent();
+ return uno::Reference<css::accessibility::XAccessible>();
+}
+
+sal_Int16 SAL_CALL SvxShowCharSetAcc::getAccessibleRole()
+{
+ return css::accessibility::AccessibleRole::TABLE;
+}
+
+OUString SAL_CALL SvxShowCharSetAcc::getAccessibleDescription()
+{
+ OExternalLockGuard aGuard( this );
+ return SvxResId( RID_SVXSTR_CHARACTER_SELECTION );
+}
+
+
+OUString SAL_CALL SvxShowCharSetAcc::getAccessibleName()
+{
+ OExternalLockGuard aGuard( this );
+
+ return SvxResId( RID_SVXSTR_CHAR_SEL_DESC );
+}
+
+
+uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL SvxShowCharSetAcc::getAccessibleRelationSet()
+{
+ return uno::Reference< css::accessibility::XAccessibleRelationSet >();
+}
+
+
+uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL SvxShowCharSetAcc::getAccessibleStateSet()
+{
+ OExternalLockGuard aGuard( this );
+
+ rtl::Reference<::utl::AccessibleStateSetHelper> pStateSet = new ::utl::AccessibleStateSetHelper;
+
+ if (m_pParent)
+ {
+ // SELECTABLE
+ pStateSet->AddState( AccessibleStateType::FOCUSABLE );
+ if (m_pParent->HasFocus())
+ {
+ pStateSet->AddState( AccessibleStateType::FOCUSED );
+ pStateSet->AddState( AccessibleStateType::ACTIVE );
+ }
+ if (m_pParent->IsEnabled())
+ {
+ pStateSet->AddState( AccessibleStateType::ENABLED );
+ pStateSet->AddState( AccessibleStateType::SENSITIVE );
+ }
+ if (m_pParent->IsVisible())
+ pStateSet->AddState( AccessibleStateType::VISIBLE );
+
+ pStateSet->AddState( AccessibleStateType::MANAGES_DESCENDANTS );
+ }
+
+ return pStateSet;
+}
+
+
+uno::Reference< css::accessibility::XAccessible > SAL_CALL SvxShowCharSetAcc::getAccessibleAtPoint( const awt::Point& aPoint )
+{
+ OExternalLockGuard aGuard( this );
+
+ uno::Reference< css::accessibility::XAccessible > xRet;
+ const sal_uInt16 nItemId = sal::static_int_cast<sal_uInt16>(
+ m_pParent->PixelToMapIndex( Point( aPoint.X, aPoint.Y ) ));
+
+ if( sal_uInt16(-1) != nItemId )
+ {
+ SvxShowCharSetItem* pItem = m_pParent->ImplGetItem( nItemId );
+ xRet = pItem->GetAccessible();
+ }
+ return xRet;
+}
+
+void SAL_CALL SvxShowCharSetAcc::grabFocus()
+{
+ OExternalLockGuard aGuard( this );
+
+ m_pParent->GrabFocus();
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetAcc::getAccessibleRowCount( )
+{
+ return ((getAccessibleChildCount()-1) / COLUMN_COUNT) + 1;
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetAcc::getAccessibleColumnCount( )
+{
+ return COLUMN_COUNT;
+}
+
+OUString SAL_CALL SvxShowCharSetAcc::getAccessibleRowDescription( sal_Int32 /*nRow*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL SvxShowCharSetAcc::getAccessibleColumnDescription( sal_Int32 /*nColumn*/ )
+{
+ return OUString();
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetAcc::getAccessibleRowExtentAt( sal_Int32 /*nRow*/, sal_Int32 /*nColumn*/ )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetAcc::getAccessibleColumnExtentAt( sal_Int32 /*nRow*/, sal_Int32 /*nColumn*/ )
+{
+ return 1;
+}
+
+Reference< XAccessibleTable > SAL_CALL SvxShowCharSetAcc::getAccessibleRowHeaders( )
+{
+ return Reference< XAccessibleTable >();
+}
+
+Reference< XAccessibleTable > SAL_CALL SvxShowCharSetAcc::getAccessibleColumnHeaders( )
+{
+ return Reference< XAccessibleTable >();
+}
+
+Sequence< sal_Int32 > SAL_CALL SvxShowCharSetAcc::getSelectedAccessibleRows( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return { SvxShowCharSet::GetRowPos(m_pParent->GetSelectIndexId()) };
+}
+
+Sequence< sal_Int32 > SAL_CALL SvxShowCharSetAcc::getSelectedAccessibleColumns( )
+{
+ OExternalLockGuard aGuard( this );
+
+ return { SvxShowCharSet::GetColumnPos(m_pParent->GetSelectIndexId()) };
+}
+
+sal_Bool SAL_CALL SvxShowCharSetAcc::isAccessibleRowSelected( sal_Int32 nRow )
+{
+ OExternalLockGuard aGuard( this );
+
+ return SvxShowCharSet::GetRowPos(m_pParent->GetSelectIndexId()) == nRow;
+}
+
+sal_Bool SAL_CALL SvxShowCharSetAcc::isAccessibleColumnSelected( sal_Int32 nColumn )
+{
+ OExternalLockGuard aGuard( this );
+ ensureAlive();
+ return SvxShowCharSet::GetColumnPos(m_pParent->GetSelectIndexId()) == nColumn;
+}
+
+Reference< XAccessible > SAL_CALL SvxShowCharSetAcc::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ OExternalLockGuard aGuard( this );
+
+ svx::SvxShowCharSetItem* pItem = m_pParent->ImplGetItem(
+ sal::static_int_cast<sal_uInt16>(getAccessibleIndex(nRow,nColumn) ));
+ if ( !pItem )
+ throw IndexOutOfBoundsException();
+ return pItem->GetAccessible();
+}
+
+Reference< XAccessible > SAL_CALL SvxShowCharSetAcc::getAccessibleCaption( )
+{
+ return Reference< XAccessible >();
+}
+
+Reference< XAccessible > SAL_CALL SvxShowCharSetAcc::getAccessibleSummary( )
+{
+ return Reference< XAccessible >();
+}
+
+sal_Bool SAL_CALL SvxShowCharSetAcc::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ OExternalLockGuard aGuard( this );
+
+ return m_pParent->GetSelectIndexId() == getAccessibleIndex(nRow,nColumn);
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetAcc::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ return (nRow*COLUMN_COUNT) + nColumn;
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetAcc::getAccessibleRow( sal_Int32 nChildIndex )
+{
+ OExternalLockGuard aGuard( this );
+
+ return SvxShowCharSet::GetRowPos(sal::static_int_cast<sal_uInt16>(nChildIndex));
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetAcc::getAccessibleColumn( sal_Int32 nChildIndex )
+{
+ OExternalLockGuard aGuard( this );
+
+ return SvxShowCharSet::GetColumnPos(sal::static_int_cast<sal_uInt16>(nChildIndex));
+}
+
+
+SvxShowCharSetItemAcc::SvxShowCharSetItemAcc( SvxShowCharSetItem* pParent ) : mpParent( pParent )
+{
+ OSL_ENSURE(pParent,"NO parent supplied!");
+ osl_atomic_increment(&m_refCount);
+ { // #b6211265 #
+ lateInit(this);
+ }
+ osl_atomic_decrement(&m_refCount);
+}
+
+
+SvxShowCharSetItemAcc::~SvxShowCharSetItemAcc()
+{
+ ensureDisposed();
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( SvxShowCharSetItemAcc, OAccessibleComponentHelper, OAccessibleHelper_Base_3 )
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( SvxShowCharSetItemAcc, OAccessibleComponentHelper, OAccessibleHelper_Base_3 )
+
+void SvxShowCharSetItemAcc::ParentDestroyed()
+{
+ const ::osl::MutexGuard aGuard( GetMutex() );
+ mpParent = nullptr;
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetItemAcc::getAccessibleChildCount()
+{
+ return 0;
+}
+
+
+uno::Reference< css::accessibility::XAccessible > SAL_CALL SvxShowCharSetItemAcc::getAccessibleChild( sal_Int32 /*i*/ )
+{
+ throw lang::IndexOutOfBoundsException();
+}
+
+
+uno::Reference< css::accessibility::XAccessible > SAL_CALL SvxShowCharSetItemAcc::getAccessibleParent()
+{
+ OExternalLockGuard aGuard( this );
+
+ return mpParent->m_pParent;
+}
+
+
+sal_Int16 SAL_CALL SvxShowCharSetItemAcc::getAccessibleRole()
+{
+ return css::accessibility::AccessibleRole::TABLE_CELL;
+}
+
+
+OUString SAL_CALL SvxShowCharSetItemAcc::getAccessibleDescription()
+{
+ OExternalLockGuard aGuard( this );
+
+ OUString sDescription;
+
+ const OUString aCharStr( mpParent->maText);
+ const sal_UCS4 c = aCharStr.iterateCodePoints( &o3tl::temporary(sal_Int32(0)) );
+ const int tmp_len = (c < 0x10000) ? 4 : 6;
+ char buf[16] = "0x0000";
+ sal_UCS4 c_Shifted = c;
+ for( int i = 0; i < tmp_len; ++i )
+ {
+ char h = static_cast<char>(c_Shifted & 0x0F);
+ buf[tmp_len+1-i] = (h > 9) ? (h - 10 + 'A') : (h + '0');
+ c_Shifted >>= 4;
+ }
+ if( c < 256 )
+ snprintf( buf+6, 10, " (%" SAL_PRIuUINT32 ")", c );
+
+ sDescription = SvxResId( RID_SVXSTR_CHARACTER_CODE )
+ + " "
+ + OUString(buf, strlen(buf), RTL_TEXTENCODING_ASCII_US);
+
+ return sDescription;
+}
+
+
+OUString SAL_CALL SvxShowCharSetItemAcc::getAccessibleName()
+{
+ OExternalLockGuard aGuard( this );
+
+ OUString aRet;
+
+ if( mpParent )
+ {
+ aRet = mpParent->maText;
+
+ if (aRet.isEmpty())
+ aRet = getAccessibleDescription();
+ }
+
+ return aRet;
+}
+
+
+uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL SvxShowCharSetItemAcc::getAccessibleRelationSet()
+{
+ return uno::Reference< css::accessibility::XAccessibleRelationSet >();
+}
+
+
+uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL SvxShowCharSetItemAcc::getAccessibleStateSet()
+{
+ OExternalLockGuard aGuard( this );
+
+ rtl::Reference<::utl::AccessibleStateSetHelper> pStateSet = new ::utl::AccessibleStateSetHelper;
+
+ if( mpParent )
+ {
+ if (mpParent->mrParent.IsEnabled())
+ {
+ pStateSet->AddState( css::accessibility::AccessibleStateType::ENABLED );
+ // SELECTABLE
+ pStateSet->AddState( css::accessibility::AccessibleStateType::SELECTABLE );
+ pStateSet->AddState( css::accessibility::AccessibleStateType::FOCUSABLE );
+ }
+
+ // SELECTED
+ if( mpParent->mrParent.GetSelectIndexId() == mpParent->mnId )
+ {
+ pStateSet->AddState( css::accessibility::AccessibleStateType::SELECTED );
+ pStateSet->AddState( css::accessibility::AccessibleStateType::FOCUSED );
+ }
+ if ( mpParent->mnId >= mpParent->mrParent.FirstInView() && mpParent->mnId <= mpParent->mrParent.LastInView() )
+ {
+ pStateSet->AddState( AccessibleStateType::VISIBLE );
+ pStateSet->AddState( AccessibleStateType::SHOWING );
+ }
+ pStateSet->AddState( AccessibleStateType::TRANSIENT );
+ }
+
+ return pStateSet;
+}
+
+
+sal_Int32 SvxShowCharSetItemAcc::getAccessibleActionCount()
+{
+ return 1;
+}
+
+
+sal_Bool SvxShowCharSetItemAcc::doAccessibleAction ( sal_Int32 nIndex )
+{
+ OExternalLockGuard aGuard( this );
+
+ if( nIndex == 0 )
+ {
+ mpParent->mrParent.OutputIndex( mpParent->mnId );
+ return true;
+ }
+ throw IndexOutOfBoundsException();
+}
+
+
+OUString SvxShowCharSetItemAcc::getAccessibleActionDescription ( sal_Int32 nIndex )
+{
+ if( nIndex == 0 )
+ return "press";
+ throw IndexOutOfBoundsException();
+}
+
+
+Reference< css::accessibility::XAccessibleKeyBinding > SvxShowCharSetItemAcc::getAccessibleActionKeyBinding( sal_Int32 nIndex )
+{
+ if( nIndex == 0 )
+ return Reference< css::accessibility::XAccessibleKeyBinding >();
+ throw IndexOutOfBoundsException();
+}
+
+
+void SAL_CALL SvxShowCharSetItemAcc::grabFocus()
+{
+ // nothing to do
+}
+
+awt::Rectangle SvxShowCharSetItemAcc::implGetBounds( )
+{
+ awt::Rectangle aRet;
+
+ if( mpParent )
+ {
+ tools::Rectangle aRect( mpParent->maRect );
+ tools::Rectangle aParentRect(Point(), mpParent->mrParent.GetOutputSizePixel());
+
+ aRect.Intersection( aParentRect );
+
+ aRet.X = aRect.Left();
+ aRet.Y = aRect.Top();
+ aRet.Width = aRect.GetWidth();
+ aRet.Height = aRect.GetHeight();
+ }
+
+ return aRet;
+}
+
+uno::Reference< css::accessibility::XAccessible > SAL_CALL SvxShowCharSetItemAcc::getAccessibleAtPoint( const awt::Point& /*aPoint*/ )
+{
+ return uno::Reference< css::accessibility::XAccessible >();
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetAcc::getForeground( )
+{
+ OExternalLockGuard aGuard( this );
+
+ //see SvxShowCharSet::InitSettings
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ return static_cast<sal_Int32>(rStyleSettings.GetDialogTextColor());
+}
+
+sal_Int32 SAL_CALL SvxShowCharSetAcc::getBackground( )
+{
+ OExternalLockGuard aGuard( this );
+
+ //see SvxShowCharSet::InitSettings
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ return static_cast<sal_Int32>(rStyleSettings.GetWindowColor());
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/lookupcolorname.cxx b/svx/source/accessibility/lookupcolorname.cxx
new file mode 100644
index 000000000..373dae469
--- /dev/null
+++ b/svx/source/accessibility/lookupcolorname.cxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/drawing/ColorTable.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <comphelper/processfactory.hxx>
+#include <rtl/ustring.hxx>
+#include <vcl/svapp.hxx>
+
+#include "lookupcolorname.hxx"
+#include <unordered_map>
+
+namespace
+{
+class ColorNameMap
+{
+public:
+ ColorNameMap();
+ ColorNameMap(const ColorNameMap&) = delete;
+ ColorNameMap& operator=(const ColorNameMap&) = delete;
+
+ OUString lookUp(tools::Long color) const;
+
+private:
+ typedef std::unordered_map<tools::Long, OUString> Map;
+
+ Map map_;
+};
+
+ColorNameMap::ColorNameMap()
+{
+ css::uno::Sequence<OUString> aNames;
+ css::uno::Reference<css::container::XNameAccess> xNA;
+
+ try
+ {
+ // Create color table in which to look up the given color.
+ css::uno::Reference<css::container::XNameContainer> xColorTable
+ = css::drawing::ColorTable::create(comphelper::getProcessComponentContext());
+
+ // Get list of color names in order to iterate over the color table.
+
+ // Lock the solar mutex here as workaround for missing lock in
+ // called function.
+ SolarMutexGuard aGuard;
+ xNA = xColorTable;
+ aNames = xColorTable->getElementNames();
+ }
+ catch (css::uno::RuntimeException const&)
+ {
+ // When an exception occurred then we have an empty name sequence
+ // and the loop below is not entered.
+ }
+
+ // Fill the map to convert from numerical color values to names.
+ if (!xNA.is())
+ return;
+
+ for (const auto& rName : std::as_const(aNames))
+ {
+ // Get the numerical value for the i-th color name.
+ try
+ {
+ css::uno::Any aColor = xNA->getByName(rName);
+ tools::Long nColor = 0;
+ aColor >>= nColor;
+ map_[nColor] = rName;
+ }
+ catch (css::uno::RuntimeException const&)
+ {
+ // Ignore the exception: the color who lead to the exception
+ // is not included into the map.
+ }
+ }
+}
+
+OUString ColorNameMap::lookUp(tools::Long color) const
+{
+ Map::const_iterator i(map_.find(color));
+ if (i != map_.end())
+ {
+ return i->second;
+ }
+ // Did not find the given color; return its RGB tuple representation:
+ return "#" + OUString::number(color, 16);
+}
+}
+
+namespace accessibility
+{
+OUString lookUpColorName(tools::Long color)
+{
+ static ColorNameMap theColorNameMap;
+ return theColorNameMap.lookUp(color);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/lookupcolorname.hxx b/svx/source/accessibility/lookupcolorname.hxx
new file mode 100644
index 000000000..0d752c0fa
--- /dev/null
+++ b/svx/source/accessibility/lookupcolorname.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_ACCESSIBILITY_LOOKUPCOLORNAME_HXX
+#define INCLUDED_SVX_SOURCE_ACCESSIBILITY_LOOKUPCOLORNAME_HXX
+
+#include <sal/config.h>
+
+#include <rtl/ustring.hxx>
+#include <tools/long.hxx>
+
+namespace accessibility
+{
+/** This is a color name lookup targeted to be used by the accessibility
+ <type>DescriptionGenerator</type> class. It encapsulates a
+ <type>com.sun.star.drawing.ColorTable</type> and provides an inverse look
+ up of color names for given numerical color descriptions (the RGB values
+ encoded as an integer).
+
+ <p>The implementation uses as singleton so that the
+ <type>com.sun.star.drawing.ColorTable</type> object needs to be created
+ only once. That singleton instance for now lives until the application
+ terminates. However, the color table from which it takes its values may
+ change during this time. Reacting to these changes remains a task for the
+ future.</p>
+
+ @param nColor
+ This integer is the sum of the 8 Bit red value shifted left 16 Bits, the
+ green value shifted left 8 Bits, and the unshifted blue value.
+
+ @return
+ The returned string is either the color name of the specified color or,
+ when no name exists, a string of the form "#RRGGBB" with two hexadecimal
+ digits for each color component.
+*/
+OUString lookUpColorName(tools::Long color);
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/svxpixelctlaccessiblecontext.cxx b/svx/source/accessibility/svxpixelctlaccessiblecontext.cxx
new file mode 100644
index 000000000..4873b3cfe
--- /dev/null
+++ b/svx/source/accessibility/svxpixelctlaccessiblecontext.cxx
@@ -0,0 +1,468 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <toolkit/helper/convert.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <osl/mutex.hxx>
+#include <tools/debug.hxx>
+#include <tools/gen.hxx>
+
+#include <svx/dlgctrl.hxx>
+
+#include <svxpixelctlaccessiblecontext.hxx>
+
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+
+SvxPixelCtlAccessible::SvxPixelCtlAccessible(SvxPixelCtl* pControl)
+ : mpPixelCtl(pControl)
+{
+}
+
+SvxPixelCtlAccessible::~SvxPixelCtlAccessible()
+{
+ ensureDisposed();
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( SvxPixelCtlAccessible, OAccessibleSelectionHelper, OAccessibleHelper_Base )
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( SvxPixelCtlAccessible, OAccessibleSelectionHelper, OAccessibleHelper_Base )
+
+uno::Reference< XAccessibleContext > SvxPixelCtlAccessible::getAccessibleContext( )
+{
+ return this;
+}
+
+sal_Int32 SvxPixelCtlAccessible::getAccessibleChildCount( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return SvxPixelCtl::GetSquares();
+}
+uno::Reference< XAccessible > SvxPixelCtlAccessible::getAccessibleChild( sal_Int32 i )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( i < 0 || i >= getAccessibleChildCount())
+ throw lang::IndexOutOfBoundsException();
+ Reference< XAccessible > xChild;
+ if (mpPixelCtl)
+ xChild = CreateChild(i, mpPixelCtl->IndexToPoint(i));
+ return xChild;
+}
+
+uno::Reference< XAccessible > SvxPixelCtlAccessible::getAccessibleParent( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (mpPixelCtl)
+ return mpPixelCtl->getAccessibleParent();
+ return uno::Reference<css::accessibility::XAccessible>();
+}
+
+sal_Int16 SvxPixelCtlAccessible::getAccessibleRole( )
+{
+ return AccessibleRole::LIST;
+}
+
+OUString SvxPixelCtlAccessible::getAccessibleDescription( )
+{
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return mpPixelCtl ? mpPixelCtl->GetAccessibleDescription() : "";
+}
+
+OUString SvxPixelCtlAccessible::getAccessibleName( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return mpPixelCtl ? mpPixelCtl->GetAccessibleName() : "";
+}
+
+Reference< XAccessibleRelationSet > SAL_CALL SvxPixelCtlAccessible::getAccessibleRelationSet()
+{
+ if (mpPixelCtl)
+ return mpPixelCtl->get_accessible_relation_set();
+ return uno::Reference<css::accessibility::XAccessibleRelationSet>();
+}
+
+uno::Reference< XAccessibleStateSet > SvxPixelCtlAccessible::getAccessibleStateSet( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSetHelper = new utl::AccessibleStateSetHelper;
+
+ if (mpPixelCtl)
+ {
+ const sal_Int16 aStandardStates[] =
+ {
+ AccessibleStateType::FOCUSABLE,
+ AccessibleStateType::SELECTABLE,
+ AccessibleStateType::SHOWING,
+ AccessibleStateType::VISIBLE,
+ AccessibleStateType::OPAQUE,
+ 0
+ };
+
+ sal_Int16 nState = 0;
+ while (aStandardStates[nState])
+ {
+ pStateSetHelper->AddState(aStandardStates[nState++]);
+ }
+ if (mpPixelCtl->IsEnabled())
+ pStateSetHelper->AddState(AccessibleStateType::ENABLED);
+ if (mpPixelCtl->HasFocus())
+ pStateSetHelper->AddState(AccessibleStateType::FOCUSED);
+ pStateSetHelper->AddState(AccessibleStateType::MANAGES_DESCENDANTS);
+ }
+
+ return pStateSetHelper;
+}
+
+uno::Reference<XAccessible > SAL_CALL SvxPixelCtlAccessible::getAccessibleAtPoint (
+ const awt::Point& rPoint)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XAccessible > xRet;
+
+ if (mpPixelCtl)
+ {
+ tools::Long nIndex = mpPixelCtl->PointToIndex(Point(rPoint.X, rPoint.Y));
+ xRet = CreateChild(nIndex, mpPixelCtl->IndexToPoint(nIndex));
+ }
+
+ return xRet;
+}
+
+awt::Rectangle SvxPixelCtlAccessible::implGetBounds()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ awt::Rectangle aRet;
+
+ if (mpPixelCtl)
+ {
+ const Point aOutPos;
+ Size aOutSize(mpPixelCtl->GetOutputSizePixel());
+
+ aRet.X = aOutPos.X();
+ aRet.Y = aOutPos.Y();
+ aRet.Width = aOutSize.Width();
+ aRet.Height = aOutSize.Height();
+ }
+
+ return aRet;
+}
+
+void SvxPixelCtlAccessible::grabFocus( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (mpPixelCtl)
+ mpPixelCtl->GrabFocus();
+}
+
+sal_Int32 SvxPixelCtlAccessible::getForeground( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ //see SvxPixelCtl::Paint
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ return sal_Int32(rStyles.GetLabelTextColor());
+}
+
+sal_Int32 SvxPixelCtlAccessible::getBackground( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ //see SvxPixelCtl::Paint
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ return sal_Int32(rStyles.GetDialogColor());
+}
+
+void SvxPixelCtlAccessible::implSelect(sal_Int32 nChildIndex, bool bSelect)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
+ throw lang::IndexOutOfBoundsException();
+
+ if (!mpPixelCtl)
+ return;
+
+ tools::Long nIndex = mpPixelCtl->ShowPosition(mpPixelCtl->IndexToPoint(nChildIndex));
+ NotifyChild(nIndex, bSelect, false);
+}
+
+bool SvxPixelCtlAccessible::implIsSelected(sal_Int32 nChildIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (!mpPixelCtl)
+ return false;
+
+ return mpPixelCtl->GetFocusPosIndex() == nChildIndex;
+}
+
+void SAL_CALL SvxPixelCtlAccessible::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ OAccessibleSelectionHelper::disposing();
+ m_xCurChild.clear();
+ mpPixelCtl = nullptr;
+}
+
+void SvxPixelCtlAccessible::NotifyChild(tools::Long nIndex,bool bSelect ,bool bCheck)
+{
+ DBG_ASSERT( !(!bSelect && !bCheck),"" );//non is false
+
+ SvxPixelCtlAccessibleChild *pChild= nullptr;
+
+ if (m_xCurChild.is())
+ {
+ pChild= static_cast<SvxPixelCtlAccessibleChild*>(m_xCurChild.get());
+ DBG_ASSERT(pChild,"Child Must be Valid");
+ if (pChild->getAccessibleIndexInParent() == nIndex )
+ {
+ if (bSelect)
+ {
+ pChild->SelectChild(true);
+ }
+ if (bCheck)
+ {
+ pChild->ChangePixelColorOrBG(mpPixelCtl->GetBitmapPixel(sal_uInt16(nIndex)) != 0);
+ pChild->CheckChild();
+ }
+ return ;
+ }
+ }
+ uno::Reference <XAccessible> xNewChild =CreateChild(nIndex, mpPixelCtl->IndexToPoint(nIndex));
+ SvxPixelCtlAccessibleChild *pNewChild= static_cast<SvxPixelCtlAccessibleChild*>(xNewChild.get());
+ DBG_ASSERT(pNewChild,"Child Must be Valid");
+
+ Any aNewValue,aOldValue;
+ aNewValue<<= xNewChild;
+ NotifyAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldValue, aNewValue);
+
+ if (bSelect)
+ {
+ if (pChild)
+ {
+ pChild->SelectChild(false);
+ }
+ pNewChild->SelectChild(true);
+ }
+ if (bCheck)
+ {
+ pNewChild->CheckChild();
+ }
+ m_xCurChild= xNewChild;
+}
+
+uno::Reference<XAccessible> SvxPixelCtlAccessible::CreateChild (tools::Long nIndex,Point mPoint)
+{
+ bool bPixelColorOrBG = mpPixelCtl->GetBitmapPixel(sal_uInt16(nIndex)) != 0;
+ Size size(mpPixelCtl->GetWidth() / SvxPixelCtl::GetLineCount(), mpPixelCtl->GetHeight() / SvxPixelCtl::GetLineCount());
+ uno::Reference<XAccessible> xChild = new SvxPixelCtlAccessibleChild(*mpPixelCtl,
+ bPixelColorOrBG,
+ tools::Rectangle(mPoint,size),
+ this,
+ nIndex);
+
+ return xChild;
+}
+
+void SvxPixelCtlAccessibleChild::CheckChild()
+{
+ Any aChecked;
+ aChecked <<= AccessibleStateType::CHECKED;
+
+ if (m_bPixelColorOrBG)//Current Child State
+ {
+ NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, Any(), aChecked);
+ }
+ else
+ {
+ NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, aChecked, Any());
+ }
+}
+
+void SvxPixelCtlAccessibleChild::SelectChild( bool bSelect)
+{
+ Any aSelected;
+ aSelected <<= AccessibleStateType::SELECTED;
+
+ if (bSelect)
+ {
+ NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, Any(), aSelected);
+ }
+ else
+ {
+ NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, aSelected, Any());
+ }
+}
+
+SvxPixelCtlAccessibleChild::SvxPixelCtlAccessibleChild( SvxPixelCtl& rWindow, bool bPixelColorOrBG,
+ const tools::Rectangle& rBoundingBox, const rtl::Reference<SvxPixelCtlAccessible>& rxParent,
+ tools::Long nIndexInParent)
+ : mrParentWindow( rWindow )
+ , mxParent(rxParent)
+ , m_bPixelColorOrBG(bPixelColorOrBG)
+ , maBoundingBox( rBoundingBox )
+ , mnIndexInParent( nIndexInParent )
+{
+}
+
+SvxPixelCtlAccessibleChild::~SvxPixelCtlAccessibleChild()
+{
+ ensureDisposed();
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( SvxPixelCtlAccessibleChild, OAccessibleComponentHelper, OAccessibleHelper_Base )
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( SvxPixelCtlAccessibleChild, OAccessibleComponentHelper, OAccessibleHelper_Base )
+
+// XAccessible
+uno::Reference< XAccessibleContext> SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleContext()
+{
+ return this;
+}
+
+uno::Reference< XAccessible > SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleAtPoint( const awt::Point& )
+{
+ return uno::Reference< XAccessible >();
+}
+
+void SAL_CALL SvxPixelCtlAccessibleChild::grabFocus()
+{
+}
+
+sal_Int32 SvxPixelCtlAccessibleChild::getForeground()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return mxParent.is() ? mxParent->getForeground() : -1;
+}
+
+sal_Int32 SvxPixelCtlAccessibleChild::getBackground()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return mxParent.is() ? mxParent->getBackground() : -1;
+}
+
+// XAccessibleContext
+sal_Int32 SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleChildCount()
+{
+ return 0;
+}
+
+uno::Reference< XAccessible > SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleChild( sal_Int32 )
+{
+ throw lang::IndexOutOfBoundsException();
+}
+
+uno::Reference< XAccessible > SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleParent()
+{
+ return mxParent;
+}
+
+sal_Int16 SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleRole()
+{
+ return AccessibleRole::CHECK_BOX;
+}
+
+OUString SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleDescription()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return GetName();
+}
+
+OUString SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleName()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return GetName();
+}
+
+/** Return empty uno::Reference to indicate that the relation set is not
+ supported.
+*/
+uno::Reference<XAccessibleRelationSet> SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleRelationSet()
+{
+ return uno::Reference< XAccessibleRelationSet >();
+}
+
+uno::Reference< XAccessibleStateSet > SAL_CALL SvxPixelCtlAccessibleChild::getAccessibleStateSet()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSetHelper = new utl::AccessibleStateSetHelper;
+
+ if (!rBHelper.bDisposed)
+ {
+
+ pStateSetHelper->AddState( AccessibleStateType::TRANSIENT );
+ pStateSetHelper->AddState( AccessibleStateType::ENABLED );
+ pStateSetHelper->AddState( AccessibleStateType::OPAQUE );
+ pStateSetHelper->AddState( AccessibleStateType::SELECTABLE );
+ pStateSetHelper->AddState( AccessibleStateType::SHOWING );
+ pStateSetHelper->AddState( AccessibleStateType::VISIBLE );
+
+ tools::Long nIndex = mrParentWindow.GetFocusPosIndex();
+ if ( nIndex == mnIndexInParent)
+ {
+ pStateSetHelper->AddState( AccessibleStateType::SELECTED );
+ }
+ if (mrParentWindow.GetBitmapPixel(sal_uInt16(mnIndexInParent)))
+ {
+ pStateSetHelper->AddState( AccessibleStateType::CHECKED );
+ }
+ }
+ else
+ pStateSetHelper->AddState( AccessibleStateType::DEFUNC );
+
+ return pStateSetHelper;
+}
+
+void SAL_CALL SvxPixelCtlAccessibleChild::disposing()
+{
+ OAccessibleComponentHelper::disposing();
+ mxParent.clear();
+}
+
+awt::Rectangle SvxPixelCtlAccessibleChild::implGetBounds()
+{
+ // no guard necessary, because no one changes maBoundingBox after creating it
+ return AWTRectangle(maBoundingBox);
+}
+
+OUString SvxPixelCtlAccessibleChild::GetName() const
+{
+ sal_Int32 nXIndex = mnIndexInParent % SvxPixelCtl::GetLineCount();
+ sal_Int32 nYIndex = mnIndexInParent / SvxPixelCtl::GetLineCount();
+
+ OUString str = "("
+ + OUString::number(nXIndex)
+ + ","
+ + OUString::number(nYIndex)
+ + ")";
+ return str;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/accessibility/svxrectctaccessiblecontext.cxx b/svx/source/accessibility/svxrectctaccessiblecontext.cxx
new file mode 100644
index 000000000..bca421c29
--- /dev/null
+++ b/svx/source/accessibility/svxrectctaccessiblecontext.cxx
@@ -0,0 +1,647 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svxrectctaccessiblecontext.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <toolkit/helper/convert.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+#include <tools/debug.hxx>
+#include <tools/gen.hxx>
+#include <sal/log.hxx>
+#include <vcl/settings.hxx>
+#include <svx/strings.hrc>
+#include <svx/dlgctrl.hxx>
+#include <svx/dialmgr.hxx>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <unotools/accessiblerelationsethelper.hxx>
+
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+
+using namespace ::com::sun::star::lang;
+
+#define MAX_NUM_OF_CHILDREN 9
+#define NOCHILDSELECTED -1
+
+// internal
+namespace
+{
+ struct ChildIndexToPointData
+ {
+ TranslateId pResIdName;
+ TranslateId pResIdDescr;
+ RectPoint ePoint;
+ };
+}
+
+
+static const ChildIndexToPointData* IndexToPoint( tools::Long nIndex )
+{
+ DBG_ASSERT( nIndex < 9 && nIndex >= 0, "-IndexToPoint(): invalid child index! You have been warned..." );
+
+ // corners are counted from left to right and top to bottom
+ static const ChildIndexToPointData pCornerData[] =
+ { // index
+ { RID_SVXSTR_RECTCTL_ACC_CHLD_LT, RID_SVXSTR_RECTCTL_ACC_CHLD_LT, RectPoint::LT }, // 0
+ { RID_SVXSTR_RECTCTL_ACC_CHLD_MT, RID_SVXSTR_RECTCTL_ACC_CHLD_MT, RectPoint::MT }, // 1
+ { RID_SVXSTR_RECTCTL_ACC_CHLD_RT, RID_SVXSTR_RECTCTL_ACC_CHLD_RT, RectPoint::RT }, // 2
+ { RID_SVXSTR_RECTCTL_ACC_CHLD_LM, RID_SVXSTR_RECTCTL_ACC_CHLD_LM, RectPoint::LM }, // 3
+ { RID_SVXSTR_RECTCTL_ACC_CHLD_MM, RID_SVXSTR_RECTCTL_ACC_CHLD_MM, RectPoint::MM }, // 4
+ { RID_SVXSTR_RECTCTL_ACC_CHLD_RM, RID_SVXSTR_RECTCTL_ACC_CHLD_RM, RectPoint::RM }, // 5
+ { RID_SVXSTR_RECTCTL_ACC_CHLD_LB, RID_SVXSTR_RECTCTL_ACC_CHLD_LB, RectPoint::LB }, // 6
+ { RID_SVXSTR_RECTCTL_ACC_CHLD_MB, RID_SVXSTR_RECTCTL_ACC_CHLD_MB, RectPoint::MB }, // 7
+ { RID_SVXSTR_RECTCTL_ACC_CHLD_RB, RID_SVXSTR_RECTCTL_ACC_CHLD_RB, RectPoint::RB } // 8
+ };
+
+ return pCornerData + nIndex;
+}
+
+
+static tools::Long PointToIndex( RectPoint ePoint )
+{
+ tools::Long nRet( static_cast<tools::Long>(ePoint) );
+ // corner control
+ // corners are counted from left to right and top to bottom
+ DBG_ASSERT( int(RectPoint::LT) == 0 && int(RectPoint::MT) == 1 && int(RectPoint::RT) == 2 && int(RectPoint::LM) == 3 && int(RectPoint::MM) == 4 && int(RectPoint::RM) == 5 &&
+ int(RectPoint::LB) == 6 && int(RectPoint::MB) == 7 && int(RectPoint::RB) == 8, "*PointToIndex(): unexpected enum value!" );
+
+ nRet = static_cast<tools::Long>(ePoint);
+
+ return nRet;
+}
+
+SvxRectCtlAccessibleContext::SvxRectCtlAccessibleContext(SvxRectCtl* pRepr)
+ : mpRepr(pRepr)
+ , mnSelectedChild(NOCHILDSELECTED)
+{
+ {
+ ::SolarMutexGuard aSolarGuard;
+ msName = SvxResId( RID_SVXSTR_RECTCTL_ACC_CORN_NAME );
+ msDescription = SvxResId( RID_SVXSTR_RECTCTL_ACC_CORN_DESCR );
+ }
+
+ mvChildren.resize(MAX_NUM_OF_CHILDREN);
+}
+
+SvxRectCtlAccessibleContext::~SvxRectCtlAccessibleContext()
+{
+ ensureDisposed();
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( SvxRectCtlAccessibleContext, OAccessibleSelectionHelper, OAccessibleHelper_Base )
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( SvxRectCtlAccessibleContext, OAccessibleSelectionHelper, OAccessibleHelper_Base )
+
+Reference< XAccessible > SAL_CALL SvxRectCtlAccessibleContext::getAccessibleAtPoint( const awt::Point& rPoint )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XAccessible > xRet;
+
+ tools::Long nChild = mpRepr ? PointToIndex(mpRepr->GetApproxRPFromPixPt(rPoint)) : NOCHILDSELECTED;
+
+ if (nChild != NOCHILDSELECTED)
+ xRet = getAccessibleChild( nChild );
+
+ return xRet;
+}
+
+// XAccessibleContext
+sal_Int32 SAL_CALL SvxRectCtlAccessibleContext::getAccessibleChildCount()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return SvxRectCtl::NO_CHILDREN;
+}
+
+Reference< XAccessible > SAL_CALL SvxRectCtlAccessibleContext::getAccessibleChild( sal_Int32 nIndex )
+{
+ checkChildIndex( nIndex );
+
+ Reference< XAccessible > xChild(mvChildren[ nIndex ]);
+ if( !xChild.is() )
+ {
+ ::SolarMutexGuard aSolarGuard;
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ xChild = mvChildren[ nIndex ].get();
+
+ if (!xChild.is() && mpRepr)
+ {
+ const ChildIndexToPointData* p = IndexToPoint( nIndex );
+ OUString aName(SvxResId(p->pResIdName));
+ OUString aDescr(SvxResId(p->pResIdDescr));
+
+ tools::Rectangle aFocusRect( mpRepr->CalculateFocusRectangle( p->ePoint ) );
+
+ rtl::Reference<SvxRectCtlChildAccessibleContext> pChild = new SvxRectCtlChildAccessibleContext(this, aName,
+ aDescr, aFocusRect, nIndex );
+ mvChildren[ nIndex ] = pChild;
+ xChild = pChild;
+
+ // set actual state
+ if( mnSelectedChild == nIndex )
+ pChild->setStateChecked( true );
+ }
+ }
+
+ return xChild;
+}
+
+Reference< XAccessible > SAL_CALL SvxRectCtlAccessibleContext::getAccessibleParent()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (mpRepr)
+ return mpRepr->getAccessibleParent();
+ return uno::Reference<css::accessibility::XAccessible>();
+}
+
+sal_Int16 SAL_CALL SvxRectCtlAccessibleContext::getAccessibleRole()
+{
+ return AccessibleRole::PANEL;
+}
+
+OUString SAL_CALL SvxRectCtlAccessibleContext::getAccessibleDescription()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return msDescription + " Please use arrow key to selection.";
+}
+
+OUString SAL_CALL SvxRectCtlAccessibleContext::getAccessibleName()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return msName;
+}
+
+/** Return empty reference to indicate that the relation set is not
+ supported.
+*/
+Reference< XAccessibleRelationSet > SAL_CALL SvxRectCtlAccessibleContext::getAccessibleRelationSet()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (mpRepr)
+ return mpRepr->get_accessible_relation_set();
+ return uno::Reference<css::accessibility::XAccessibleRelationSet>();
+}
+
+Reference< XAccessibleStateSet > SAL_CALL SvxRectCtlAccessibleContext::getAccessibleStateSet()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSetHelper = new utl::AccessibleStateSetHelper;
+
+ if (mpRepr)
+ {
+ pStateSetHelper->AddState( AccessibleStateType::ENABLED );
+ pStateSetHelper->AddState( AccessibleStateType::FOCUSABLE );
+ if( mpRepr->HasFocus() )
+ pStateSetHelper->AddState( AccessibleStateType::FOCUSED );
+ pStateSetHelper->AddState( AccessibleStateType::OPAQUE );
+
+ pStateSetHelper->AddState( AccessibleStateType::SHOWING );
+
+ if( mpRepr->IsVisible() )
+ pStateSetHelper->AddState( AccessibleStateType::VISIBLE );
+ }
+ else
+ pStateSetHelper->AddState( AccessibleStateType::DEFUNC );
+
+ return pStateSetHelper;
+}
+
+void SAL_CALL SvxRectCtlAccessibleContext::grabFocus()
+{
+ ::SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (mpRepr)
+ mpRepr->GrabFocus();
+}
+
+sal_Int32 SvxRectCtlAccessibleContext::getForeground()
+{
+ ::SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ //see SvxRectCtl::Paint
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ return sal_Int32(rStyles.GetLabelTextColor());
+}
+
+sal_Int32 SvxRectCtlAccessibleContext::getBackground( )
+{
+ ::SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ //see SvxRectCtl::Paint
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ return sal_Int32(rStyles.GetDialogColor());
+}
+
+// XAccessibleSelection
+void SvxRectCtlAccessibleContext::implSelect(sal_Int32 nIndex, bool bSelect)
+{
+ ::SolarMutexGuard aSolarGuard;
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ checkChildIndex( nIndex );
+
+ const ChildIndexToPointData* pData = IndexToPoint( nIndex );
+
+ DBG_ASSERT(pData, "SvxRectCtlAccessibleContext::selectAccessibleChild(): this is an impossible state! Or at least should be...");
+
+ if (mpRepr)
+ {
+ if (bSelect)
+ {
+ // this does all what is needed, including the change of the child's state!
+ mpRepr->SetActualRP( pData->ePoint );
+ }
+ else
+ {
+ SAL_WARN( "svx", "SvxRectCtlAccessibleContext::clearAccessibleSelection() is not possible!" );
+ }
+ }
+}
+
+bool SvxRectCtlAccessibleContext::implIsSelected( sal_Int32 nIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ checkChildIndex( nIndex );
+
+ return nIndex == mnSelectedChild;
+}
+
+// internals
+void SvxRectCtlAccessibleContext::checkChildIndex( tools::Long nIndex )
+{
+ if( nIndex < 0 || nIndex >= getAccessibleChildCount() )
+ throw lang::IndexOutOfBoundsException();
+}
+
+void SvxRectCtlAccessibleContext::FireChildFocus( RectPoint eButton )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ tools::Long nNew = PointToIndex( eButton );
+ tools::Long nNumOfChildren = getAccessibleChildCount();
+ if( nNew < nNumOfChildren )
+ {
+ // select new child
+ mnSelectedChild = nNew;
+ if( nNew != NOCHILDSELECTED )
+ {
+ if( mvChildren[ nNew ].is() )
+ mvChildren[ nNew ]->FireFocusEvent();
+ }
+ else
+ {
+ Any aOld;
+ Any aNew;
+ aNew <<= AccessibleStateType::FOCUSED;
+ NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, aOld, aNew);
+ }
+ }
+ else
+ mnSelectedChild = NOCHILDSELECTED;
+}
+
+void SvxRectCtlAccessibleContext::selectChild( tools::Long nNew )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if( nNew == mnSelectedChild )
+ return;
+
+ tools::Long nNumOfChildren = getAccessibleChildCount();
+ if( nNew < nNumOfChildren )
+ { // valid index
+ if( mnSelectedChild != NOCHILDSELECTED )
+ { // deselect old selected child if one is selected
+ SvxRectCtlChildAccessibleContext* pChild = mvChildren[ mnSelectedChild ].get();
+ if( pChild )
+ pChild->setStateChecked( false );
+ }
+
+ // select new child
+ mnSelectedChild = nNew;
+
+ if( nNew != NOCHILDSELECTED )
+ {
+ if( mvChildren[ nNew ].is() )
+ mvChildren[ nNew ]->setStateChecked( true );
+ }
+ }
+ else
+ mnSelectedChild = NOCHILDSELECTED;
+}
+
+void SvxRectCtlAccessibleContext::selectChild(RectPoint eButton )
+{
+ // no guard -> is done in next selectChild
+ selectChild(PointToIndex( eButton ));
+}
+
+void SAL_CALL SvxRectCtlAccessibleContext::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ OAccessibleSelectionHelper::disposing();
+ for (auto & rxChild : mvChildren)
+ {
+ if( rxChild.is() )
+ rxChild->dispose();
+ }
+ mvChildren.clear();
+ mpRepr = nullptr;
+}
+
+awt::Rectangle SvxRectCtlAccessibleContext::implGetBounds()
+{
+ ::SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ awt::Rectangle aRet;
+
+ if (mpRepr)
+ {
+ const Point aOutPos;
+ Size aOutSize(mpRepr->GetOutputSizePixel());
+
+ aRet.X = aOutPos.X();
+ aRet.Y = aOutPos.Y();
+ aRet.Width = aOutSize.Width();
+ aRet.Height = aOutSize.Height();
+ }
+
+ return aRet;
+}
+
+SvxRectCtlChildAccessibleContext::SvxRectCtlChildAccessibleContext(
+ const Reference<XAccessible>& rxParent,
+ const OUString& rName,
+ const OUString& rDescription,
+ const tools::Rectangle& rBoundingBox,
+ tools::Long nIndexInParent )
+ : msDescription( rDescription )
+ , msName( rName )
+ , mxParent(rxParent)
+ , maBoundingBox( rBoundingBox )
+ , mnIndexInParent( nIndexInParent )
+ , mbIsChecked( false )
+{
+}
+
+SvxRectCtlChildAccessibleContext::~SvxRectCtlChildAccessibleContext()
+{
+ ensureDisposed();
+}
+
+Reference< XAccessible > SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleAtPoint( const awt::Point& /*rPoint*/ )
+{
+ return Reference< XAccessible >();
+}
+
+void SAL_CALL SvxRectCtlChildAccessibleContext::grabFocus()
+{
+}
+
+sal_Int32 SvxRectCtlChildAccessibleContext::getForeground( )
+{
+ ::SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ //see SvxRectCtl::Paint
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ return sal_Int32(rStyles.GetLabelTextColor());
+}
+
+sal_Int32 SvxRectCtlChildAccessibleContext::getBackground( )
+{
+ ::SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ //see SvxRectCtl::Paint
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ return sal_Int32(rStyles.GetDialogColor());
+}
+
+// XAccessibleContext
+sal_Int32 SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleChildCount()
+{
+ return 0;
+}
+
+Reference< XAccessible > SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleChild( sal_Int32 /*nIndex*/ )
+{
+ throw lang::IndexOutOfBoundsException();
+}
+
+Reference< XAccessible > SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleParent()
+{
+ return mxParent;
+}
+
+sal_Int16 SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleRole()
+{
+ return AccessibleRole::RADIO_BUTTON;
+}
+
+OUString SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleDescription()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return msDescription;
+}
+
+OUString SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleName()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return msName;
+}
+
+/** Return empty reference to indicate that the relation set is not
+ supported.
+*/
+Reference<XAccessibleRelationSet> SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleRelationSet()
+{
+ rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSetHelper = new utl::AccessibleRelationSetHelper;
+ if( mxParent.is() )
+ {
+ uno::Sequence< uno::Reference< uno::XInterface > > aSequence { mxParent };
+ pRelationSetHelper->AddRelation( css::accessibility::AccessibleRelation( css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) );
+ }
+
+ return pRelationSetHelper;
+}
+
+Reference< XAccessibleStateSet > SAL_CALL SvxRectCtlChildAccessibleContext::getAccessibleStateSet()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSetHelper = new utl::AccessibleStateSetHelper;
+
+ if (!rBHelper.bDisposed)
+ {
+ if( mbIsChecked )
+ {
+ pStateSetHelper->AddState( AccessibleStateType::CHECKED );
+ }
+
+ pStateSetHelper->AddState( AccessibleStateType::ENABLED );
+ pStateSetHelper->AddState( AccessibleStateType::SENSITIVE );
+ pStateSetHelper->AddState( AccessibleStateType::OPAQUE );
+ pStateSetHelper->AddState( AccessibleStateType::SELECTABLE );
+ pStateSetHelper->AddState( AccessibleStateType::SHOWING );
+ pStateSetHelper->AddState( AccessibleStateType::VISIBLE );
+ }
+ else
+ pStateSetHelper->AddState( AccessibleStateType::DEFUNC );
+
+ return pStateSetHelper;
+}
+
+// XAccessibleValue
+Any SAL_CALL SvxRectCtlChildAccessibleContext::getCurrentValue()
+{
+ Any aRet;
+ aRet <<= ( mbIsChecked? 1.0 : 0.0 );
+ return aRet;
+}
+
+sal_Bool SAL_CALL SvxRectCtlChildAccessibleContext::setCurrentValue( const Any& /*aNumber*/ )
+{
+ return false;
+}
+
+Any SAL_CALL SvxRectCtlChildAccessibleContext::getMaximumValue()
+{
+ Any aRet;
+ aRet <<= 1.0;
+ return aRet;
+}
+
+Any SAL_CALL SvxRectCtlChildAccessibleContext::getMinimumValue()
+{
+ Any aRet;
+ aRet <<= 0.0;
+ return aRet;
+}
+
+Any SAL_CALL SvxRectCtlChildAccessibleContext::getMinimumIncrement()
+{
+ Any aRet;
+ aRet <<= 1.0;
+ return aRet;
+}
+
+
+// XAccessibleAction
+
+
+sal_Int32 SvxRectCtlChildAccessibleContext::getAccessibleActionCount( )
+{
+ return 1;
+}
+
+
+sal_Bool SvxRectCtlChildAccessibleContext::doAccessibleAction ( sal_Int32 nIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( nIndex < 0 || nIndex >= getAccessibleActionCount() )
+ throw IndexOutOfBoundsException();
+
+ Reference<XAccessibleSelection> xSelection( mxParent, UNO_QUERY);
+
+ xSelection->selectAccessibleChild(mnIndexInParent);
+
+ return true;
+}
+
+
+OUString SvxRectCtlChildAccessibleContext::getAccessibleActionDescription ( sal_Int32 nIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( nIndex < 0 || nIndex >= getAccessibleActionCount() )
+ throw IndexOutOfBoundsException();
+
+ return "select";
+}
+
+
+Reference< XAccessibleKeyBinding > SvxRectCtlChildAccessibleContext::getAccessibleActionKeyBinding( sal_Int32 nIndex )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( nIndex < 0 || nIndex >= getAccessibleActionCount() )
+ throw IndexOutOfBoundsException();
+
+ return Reference< XAccessibleKeyBinding >();
+}
+
+void SAL_CALL SvxRectCtlChildAccessibleContext::disposing()
+{
+ OAccessibleComponentHelper::disposing();
+ mxParent.clear();
+}
+
+awt::Rectangle SvxRectCtlChildAccessibleContext::implGetBounds( )
+{
+ // no guard necessary, because no one changes maBoundingBox after creating it
+ return AWTRectangle(maBoundingBox);
+}
+
+void SvxRectCtlChildAccessibleContext::setStateChecked( bool bChecked )
+{
+ if( mbIsChecked == bChecked )
+ return;
+
+ mbIsChecked = bChecked;
+
+ Any aOld;
+ Any aNew;
+ Any& rMod = bChecked? aNew : aOld;
+
+ //Send the STATE_CHANGED(Focused) event to accessible
+ rMod <<= AccessibleStateType::FOCUSED;
+ NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, aOld, aNew);
+
+ rMod <<= AccessibleStateType::CHECKED;
+
+ NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, aOld, aNew);
+}
+
+void SvxRectCtlChildAccessibleContext::FireFocusEvent()
+{
+ Any aOld;
+ Any aNew;
+ aNew <<= AccessibleStateType::FOCUSED;
+ NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, aOld, aNew);
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( SvxRectCtlChildAccessibleContext, OAccessibleComponentHelper, OAccessibleHelper_Base_3 )
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( SvxRectCtlChildAccessibleContext, OAccessibleComponentHelper, OAccessibleHelper_Base_3 )
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/core/extedit.cxx b/svx/source/core/extedit.cxx
new file mode 100644
index 000000000..3225e47f0
--- /dev/null
+++ b/svx/source/core/extedit.cxx
@@ -0,0 +1,204 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <svx/extedit.hxx>
+
+#include <vcl/graph.hxx>
+#include <vcl/GraphicObject.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <svx/xoutbmp.hxx>
+#include <svx/graphichelper.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/fmview.hxx>
+#include <salhelper/thread.hxx>
+#include <sal/log.hxx>
+#include <osl/file.hxx>
+#include <svtools/filechangedchecker.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <memory>
+
+#include <com/sun/star/system/SystemShellExecute.hpp>
+#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
+
+using namespace css::uno;
+using namespace css::system;
+
+ExternalToolEdit::ExternalToolEdit()
+{
+}
+
+ExternalToolEdit::~ExternalToolEdit()
+{
+}
+
+void ExternalToolEdit::HandleCloseEvent(ExternalToolEdit* pData)
+{
+ Graphic newGraphic;
+
+ //import the temp file image stream into the newGraphic
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(pData->m_aFileName, StreamMode::READ));
+ if(pStream)
+ {
+ GraphicConverter::Import(*pStream, newGraphic);
+
+ // Now update the Graphic in the shell by re-reading from the newGraphic
+ pData->Update( newGraphic );
+ }
+}
+
+void ExternalToolEdit::StartListeningEvent()
+{
+ //Start an event listener implemented via VCL timeout
+ assert(!m_pChecker);
+ m_pChecker.reset(new FileChangedChecker(
+ m_aFileName, [this] () { return HandleCloseEvent(this); }));
+}
+
+namespace {
+
+// self-destructing thread to make shell execute async
+class ExternalToolEditThread
+ : public ::salhelper::Thread
+{
+private:
+ OUString const m_aFileName;
+
+ virtual void execute() override;
+
+public:
+ explicit ExternalToolEditThread(OUString const& rFileName)
+ : ::salhelper::Thread("ExternalToolEdit")
+ , m_aFileName(rFileName)
+ {}
+};
+
+}
+
+void ExternalToolEditThread::execute()
+{
+ try
+ {
+ Reference<XSystemShellExecute> const xSystemShellExecute(
+ SystemShellExecute::create( ::comphelper::getProcessComponentContext()));
+ xSystemShellExecute->execute(m_aFileName, OUString(),
+ SystemShellExecuteFlags::URIS_ONLY);
+ }
+ catch (Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "ExternalToolEditThread");
+ }
+}
+
+void ExternalToolEdit::Edit(GraphicObject const*const pGraphicObject)
+{
+ //Get the graphic from the GraphicObject
+ const Graphic& aGraphic = pGraphicObject->GetGraphic();
+
+ //get the Preferred File Extension for this graphic
+ OUString fExtension;
+ GraphicHelper::GetPreferredExtension(fExtension, aGraphic);
+
+ //Create the temp File
+ OUString aTempFileBase;
+ OUString aTempFileName;
+
+ osl::FileBase::RC rc =
+ osl::FileBase::createTempFile(nullptr, nullptr, &aTempFileBase);
+ if (osl::FileBase::E_None != rc)
+ {
+ SAL_WARN("svx", "ExternalToolEdit::Edit: cannot create temp file");
+ return;
+ }
+
+ // Move it to a file name with image extension properly set
+ aTempFileName = aTempFileBase + "." + fExtension;
+ // FIXME: this is pretty stupid, need a better osl temp file API
+ rc = osl::File::move(aTempFileBase, aTempFileName);
+ if (osl::FileBase::E_None != rc)
+ {
+ SAL_WARN("svx", "ExternalToolEdit::Edit: cannot move temp file");
+ return;
+ }
+
+ //Write Graphic to the Temp File
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ sal_uInt16 nFilter(rGraphicFilter.GetExportFormatNumberForShortName(fExtension));
+
+ OUString aFilter(rGraphicFilter.GetExportFormatShortName(nFilter));
+
+ // Write the Graphic to the file now
+ XOutBitmap::WriteGraphic(aGraphic, aTempFileName, aFilter, XOutFlags::UseNativeIfPossible | XOutFlags::DontExpandFilename);
+
+ // There is a possibility that sPath extension might have been changed if the
+ // provided extension is not writable
+ m_aFileName = aTempFileName;
+
+ //Create a thread
+
+ rtl::Reference<ExternalToolEditThread> const pThread(
+ new ExternalToolEditThread(m_aFileName));
+ pThread->launch();
+
+ StartListeningEvent();
+}
+
+SdrExternalToolEdit::SdrExternalToolEdit(
+ FmFormView* pView,
+ SdrObject* pObj)
+: m_pView(pView)
+ ,m_pObj(pObj)
+{
+ assert(m_pObj && m_pView);
+ StartListening(m_pObj->getSdrModelFromSdrObject());
+}
+
+
+void SdrExternalToolEdit::Notify(SfxBroadcaster & rBC, SfxHint const& rHint)
+{
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ SdrHint const*const pSdrHint(static_cast<SdrHint const*>(&rHint));
+ if (SdrHintKind::ModelCleared == pSdrHint->GetKind()
+ || (pSdrHint->GetObject() == m_pObj
+ && SdrHintKind::ObjectRemoved == pSdrHint->GetKind()))
+ {
+ m_pView = nullptr;
+ m_pObj = nullptr;
+ m_pChecker.reset(); // avoid modifying deleted object
+ EndListening(rBC);
+ }
+}
+
+void SdrExternalToolEdit::Update(Graphic & rGraphic)
+{
+ assert(m_pObj && m_pView); // timer should be deleted by Notify() too
+ SdrPageView *const pPageView = m_pView->GetSdrPageView();
+ if (!pPageView)
+ return;
+
+ SdrGrafObj *const pNewObj(static_cast<SdrGrafObj*>(m_pObj->CloneSdrObject(m_pObj->getSdrModelFromSdrObject())));
+ assert(pNewObj);
+ OUString const description =
+ m_pView->GetDescriptionOfMarkedObjects() + " External Edit";
+ m_pView->BegUndo(description);
+ pNewObj->SetGraphicObject(rGraphic);
+ // set to new object before ReplaceObjectAtView() so that Notify() will
+ // not delete the running timer and crash
+ SdrObject *const pOldObj = m_pObj;
+ m_pObj = pNewObj;
+ m_pView->ReplaceObjectAtView(pOldObj, *pPageView, pNewObj);
+ m_pView->EndUndo();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/core/graphichelper.cxx b/svx/source/core/graphichelper.cxx
new file mode 100644
index 000000000..853be47d3
--- /dev/null
+++ b/svx/source/core/graphichelper.cxx
@@ -0,0 +1,485 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/graphicfilter.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <svx/xoutbmp.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/graphichelper.hxx>
+#include <svx/strings.hrc>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/drawing/GraphicExportFilter.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+#include <com/sun/star/task/ErrorCodeIOException.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/drawing/ShapeCollection.hpp>
+
+#include <map>
+
+#include <unotools/streamwrap.hxx>
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::graphic;
+using namespace css::ucb;
+using namespace css::beans;
+using namespace css::io;
+using namespace css::document;
+using namespace css::ui::dialogs;
+using namespace css::container;
+using namespace com::sun::star::task;
+
+using namespace sfx2;
+
+namespace drawing = com::sun::star::drawing;
+
+void GraphicHelper::GetPreferredExtension( OUString& rExtension, const Graphic& rGraphic )
+{
+ OUString aExtension = "png";
+ auto const & rVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
+
+ if (rVectorGraphicDataPtr && !rVectorGraphicDataPtr->getBinaryDataContainer().isEmpty())
+ {
+ switch (rVectorGraphicDataPtr->getType())
+ {
+ case VectorGraphicDataType::Wmf:
+ aExtension = "wmf";
+ break;
+ case VectorGraphicDataType::Emf:
+ aExtension = "emf";
+ break;
+ default: // case VectorGraphicDataType::Svg:
+ aExtension = "svg";
+ break;
+ }
+
+ rExtension = aExtension;
+ return;
+ }
+
+ switch( rGraphic.GetGfxLink().GetType() )
+ {
+ case GfxLinkType::NativeGif:
+ aExtension = "gif";
+ break;
+ case GfxLinkType::NativeTif:
+ aExtension = "tif";
+ break;
+ case GfxLinkType::NativeWmf:
+ aExtension = "wmf";
+ break;
+ case GfxLinkType::NativeMet:
+ aExtension = "met";
+ break;
+ case GfxLinkType::NativePct:
+ aExtension = "pct";
+ break;
+ case GfxLinkType::NativeJpg:
+ aExtension = "jpg";
+ break;
+ case GfxLinkType::NativeBmp:
+ aExtension = "bmp";
+ break;
+ case GfxLinkType::NativeSvg:
+ aExtension = "svg";
+ break;
+ case GfxLinkType::NativePdf:
+ aExtension = "pdf";
+ break;
+ case GfxLinkType::NativeWebp:
+ aExtension = "webp";
+ break;
+ default:
+ break;
+ }
+ rExtension = aExtension;
+}
+
+OUString GraphicHelper::GetImageType(const Graphic& rGraphic)
+{
+ OUString aGraphicTypeString = SvxResId(STR_IMAGE_UNKNOWN);
+ auto pGfxLink = rGraphic.GetSharedGfxLink();
+ if (pGfxLink)
+ {
+ switch (pGfxLink->GetType())
+ {
+ case GfxLinkType::NativeGif:
+ aGraphicTypeString = SvxResId(STR_IMAGE_GIF);
+ break;
+ case GfxLinkType::NativeJpg:
+ aGraphicTypeString = SvxResId(STR_IMAGE_JPEG);
+ break;
+ case GfxLinkType::NativePng:
+ aGraphicTypeString = SvxResId(STR_IMAGE_PNG);
+ break;
+ case GfxLinkType::NativeTif:
+ aGraphicTypeString = SvxResId(STR_IMAGE_TIFF);
+ break;
+ case GfxLinkType::NativeWmf:
+ aGraphicTypeString = SvxResId(STR_IMAGE_WMF);
+ break;
+ case GfxLinkType::NativeMet:
+ aGraphicTypeString = SvxResId(STR_IMAGE_MET);
+ break;
+ case GfxLinkType::NativePct:
+ aGraphicTypeString = SvxResId(STR_IMAGE_PCT);
+ break;
+ case GfxLinkType::NativeSvg:
+ aGraphicTypeString = SvxResId(STR_IMAGE_SVG);
+ break;
+ case GfxLinkType::NativeBmp:
+ aGraphicTypeString = SvxResId(STR_IMAGE_BMP);
+ break;
+ case GfxLinkType::NativeWebp:
+ aGraphicTypeString = SvxResId(STR_IMAGE_WEBP);
+ break;
+ default:
+ break;
+ }
+ }
+ return aGraphicTypeString;
+}
+namespace {
+
+
+bool lcl_ExecuteFilterDialog( const Sequence< PropertyValue >& rPropsForDialog,
+ Sequence< PropertyValue >& rFilterData )
+{
+ bool bStatus = false;
+ try
+ {
+ Reference< XExecutableDialog > xFilterDialog(
+ comphelper::getProcessServiceFactory()->createInstance( "com.sun.star.svtools.SvFilterOptionsDialog" ), UNO_QUERY );
+ Reference< XPropertyAccess > xFilterProperties( xFilterDialog, UNO_QUERY );
+
+ if( xFilterDialog.is() && xFilterProperties.is() )
+ {
+ xFilterProperties->setPropertyValues( rPropsForDialog );
+ if( xFilterDialog->execute() )
+ {
+ bStatus = true;
+ const Sequence< PropertyValue > aPropsFromDialog = xFilterProperties->getPropertyValues();
+ for ( const auto& rProp : aPropsFromDialog )
+ {
+ if (rProp.Name == "FilterData")
+ {
+ rProp.Value >>= rFilterData;
+ }
+ }
+ }
+ }
+ }
+ catch( const NoSuchElementException& e )
+ {
+ // the filter name is unknown
+ throw ErrorCodeIOException(
+ ("lcl_ExecuteFilterDialog: NoSuchElementException"
+ " \"" + e.Message + "\": ERRCODE_IO_ABORT"),
+ Reference< XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
+ }
+ catch( const ErrorCodeIOException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("sfx.doc", "ignoring");
+ }
+
+ return bStatus;
+}
+} // anonymous ns
+
+OUString GraphicHelper::ExportGraphic(weld::Window* pParent, const Graphic& rGraphic, const OUString& rGraphicName)
+{
+ FileDialogHelper aDialogHelper(TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, pParent);
+ Reference < XFilePicker3 > xFilePicker = aDialogHelper.GetFilePicker();
+
+ // fish out the graphic's name
+ aDialogHelper.SetContext(FileDialogHelper::ExportImage);
+ aDialogHelper.SetTitle( SvxResId(RID_SVXSTR_EXPORT_GRAPHIC_TITLE));
+ INetURLObject aURL;
+ aURL.SetSmartURL( rGraphicName );
+ aDialogHelper.SetFileName(aURL.GetLastName());
+
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ const sal_uInt16 nCount = rGraphicFilter.GetExportFormatCount();
+
+ OUString aExtension(aURL.GetFileExtension());
+ if( aExtension.isEmpty() )
+ {
+ GetPreferredExtension( aExtension, rGraphic );
+ }
+
+ aExtension = aExtension.toAsciiLowerCase();
+ sal_uInt16 nDefaultFilter = USHRT_MAX;
+
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ xFilePicker->appendFilter( rGraphicFilter.GetExportFormatName( i ), rGraphicFilter.GetExportWildcard( i ) );
+ OUString aFormatShortName = rGraphicFilter.GetExportFormatShortName( i );
+ if ( aFormatShortName.equalsIgnoreAsciiCase( aExtension ) )
+ {
+ nDefaultFilter = i;
+ }
+ }
+ if ( USHRT_MAX == nDefaultFilter )
+ {
+ // "wrong" extension?
+ GetPreferredExtension( aExtension, rGraphic );
+ for ( sal_uInt16 i = 0; i < nCount; ++i )
+ if ( aExtension == rGraphicFilter.GetExportFormatShortName( i ).toAsciiLowerCase() )
+ {
+ nDefaultFilter = i;
+ break;
+ }
+ }
+
+ if( USHRT_MAX != nDefaultFilter )
+ {
+ xFilePicker->setCurrentFilter( rGraphicFilter.GetExportFormatName( nDefaultFilter ) ) ;
+
+ if( aDialogHelper.Execute() == ERRCODE_NONE )
+ {
+ OUString sPath( xFilePicker->getFiles().getConstArray()[0] );
+ if( !rGraphicName.isEmpty() &&
+ nDefaultFilter == rGraphicFilter.GetExportFormatNumber( xFilePicker->getCurrentFilter()))
+ {
+ // try to save the original graphic
+ SfxMedium aIn( rGraphicName, StreamMode::READ | StreamMode::NOCREATE );
+ if( aIn.GetInStream() && !aIn.GetInStream()->GetError() )
+ {
+ SfxMedium aOut( sPath, StreamMode::WRITE | StreamMode::SHARE_DENYNONE);
+ if( aOut.GetOutStream() && !aOut.GetOutStream()->GetError())
+ {
+ aOut.GetOutStream()->WriteStream( *aIn.GetInStream() );
+ if ( ERRCODE_NONE == aIn.GetError() )
+ {
+ aOut.Close();
+ aOut.Commit();
+ if ( ERRCODE_NONE == aOut.GetError() )
+ return sPath;
+ }
+ }
+ }
+ }
+
+ sal_uInt16 nFilter;
+ if ( !xFilePicker->getCurrentFilter().isEmpty() && rGraphicFilter.GetExportFormatCount() )
+ {
+ nFilter = rGraphicFilter.GetExportFormatNumber( xFilePicker->getCurrentFilter() );
+ }
+ else
+ {
+ nFilter = GRFILTER_FORMAT_DONTKNOW;
+ }
+ OUString aFilter( rGraphicFilter.GetExportFormatShortName( nFilter ) );
+
+ if ( rGraphic.GetType() == GraphicType::Bitmap )
+ {
+ Graphic aGraphic = rGraphic;
+ Reference<XGraphic> xGraphic = aGraphic.GetXGraphic();
+
+ OUString aExportFilter = rGraphicFilter.GetExportInternalFilterName(nFilter);
+
+ Sequence< PropertyValue > aPropsForDialog{
+ comphelper::makePropertyValue("Graphic", xGraphic),
+ comphelper::makePropertyValue("FilterName", aExportFilter)
+ };
+
+ Sequence< PropertyValue > aFilterData;
+ bool bStatus = lcl_ExecuteFilterDialog(aPropsForDialog, aFilterData);
+ if (bStatus)
+ {
+ sal_Int32 nWidth = 0;
+ sal_Int32 nHeight = 0;
+
+ for (const auto& rProp : std::as_const(aFilterData))
+ {
+ if (rProp.Name == "PixelWidth")
+ {
+ rProp.Value >>= nWidth;
+ }
+ else if (rProp.Name == "PixelHeight")
+ {
+ rProp.Value >>= nHeight;
+ }
+ }
+
+ // scaling must performed here because png/jpg writer s
+ // do not take care of that.
+ Size aSizePixel( aGraphic.GetSizePixel() );
+ if( nWidth && nHeight &&
+ ( ( nWidth != aSizePixel.Width() ) ||
+ ( nHeight != aSizePixel.Height() ) ) )
+ {
+ BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
+ // export: use highest quality
+ aBmpEx.Scale( Size( nWidth, nHeight ), BmpScaleFlag::Lanczos );
+ aGraphic = aBmpEx;
+ }
+
+ XOutBitmap::WriteGraphic( aGraphic, sPath, aFilter,
+ XOutFlags::DontExpandFilename |
+ XOutFlags::DontAddExtension |
+ XOutFlags::UseNativeIfPossible,
+ nullptr, &aFilterData );
+ return sPath;
+ }
+ }
+ else
+ {
+ XOutBitmap::WriteGraphic( rGraphic, sPath, aFilter,
+ XOutFlags::DontExpandFilename |
+ XOutFlags::DontAddExtension |
+ XOutFlags::UseNativeIfPossible );
+ }
+ }
+ }
+ return OUString();
+}
+
+void GraphicHelper::SaveShapeAsGraphicToPath(
+ const css::uno::Reference<css::lang::XComponent>& xComponent,
+ const css::uno::Reference<css::drawing::XShape>& xShape, const OUString& aExportMimeType,
+ const OUString& sPath)
+{
+ Reference<XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ Reference<XInputStream> xGraphStream;
+
+ if (xGraphStream.is())
+ {
+ Reference<XSimpleFileAccess3> xFileAccess = SimpleFileAccess::create(xContext);
+ xFileAccess->writeFile(sPath, xGraphStream);
+ }
+ else if (xComponent.is() && aExportMimeType == "application/pdf")
+ {
+ css::uno::Reference<css::lang::XMultiServiceFactory> xMSF(xContext->getServiceManager(),
+ css::uno::UNO_QUERY);
+ css::uno::Reference<css::document::XExporter> xExporter(
+ xMSF->createInstance("com.sun.star.comp.PDF.PDFFilter"), css::uno::UNO_QUERY);
+ xExporter->setSourceDocument(xComponent);
+
+ css::uno::Reference<css::drawing::XShapes> xShapes
+ = css::drawing::ShapeCollection::create(comphelper::getProcessComponentContext());
+ xShapes->add(xShape);
+ css::uno::Sequence<PropertyValue> aFilterData{
+ comphelper::makePropertyValue("Selection", xShapes),
+ };
+ SvFileStream aStream(sPath, StreamMode::READWRITE | StreamMode::TRUNC);
+ css::uno::Reference<css::io::XOutputStream> xStream(new utl::OStreamWrapper(aStream));
+ css::uno::Sequence<PropertyValue> aDescriptor{
+ comphelper::makePropertyValue("FilterData", aFilterData),
+ comphelper::makePropertyValue("OutputStream", xStream)
+ };
+ css::uno::Reference<css::document::XFilter> xFilter(xExporter, css::uno::UNO_QUERY);
+ xFilter->filter(aDescriptor);
+ }
+ else
+ {
+ Reference<css::drawing::XGraphicExportFilter> xGraphicExporter
+ = css::drawing::GraphicExportFilter::create(xContext);
+
+ Sequence<PropertyValue> aDescriptor{ comphelper::makePropertyValue("MediaType",
+ aExportMimeType),
+ comphelper::makePropertyValue("URL", sPath) };
+
+ Reference<XComponent> xSourceDocument(xShape, UNO_QUERY_THROW);
+ xGraphicExporter->setSourceDocument(xSourceDocument);
+ xGraphicExporter->filter(aDescriptor);
+ }
+}
+
+void GraphicHelper::SaveShapeAsGraphic(weld::Window* pParent,
+ const css::uno::Reference<css::lang::XComponent>& xComponent,
+ const Reference<drawing::XShape>& xShape)
+{
+ try
+ {
+ Reference< XPropertySet > xShapeSet( xShape, UNO_QUERY_THROW );
+
+ FileDialogHelper aDialogHelper(TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, pParent);
+ Reference < XFilePicker3 > xFilePicker = aDialogHelper.GetFilePicker();
+ aDialogHelper.SetContext(FileDialogHelper::ExportImage);
+ aDialogHelper.SetTitle( SvxResId(RID_SVXSTR_SAVEAS_IMAGE) );
+
+ // populate filter dialog filter list and select default filter to match graphic mime type
+
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ static const OUStringLiteral aDefaultMimeType(u"image/png");
+ OUString aDefaultFormatName;
+ sal_uInt16 nCount = rGraphicFilter.GetExportFormatCount();
+
+ std::map< OUString, OUString > aMimeTypeMap;
+
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ const OUString aExportFormatName( rGraphicFilter.GetExportFormatName( i ) );
+ const OUString aFilterMimeType( rGraphicFilter.GetExportFormatMediaType( i ) );
+ xFilePicker->appendFilter( aExportFormatName, rGraphicFilter.GetExportWildcard( i ) );
+ aMimeTypeMap[ aExportFormatName ] = aFilterMimeType;
+ if( aDefaultMimeType == aFilterMimeType )
+ aDefaultFormatName = aExportFormatName;
+ }
+
+ if( !aDefaultFormatName.isEmpty() )
+ xFilePicker->setCurrentFilter( aDefaultFormatName );
+
+ // execute dialog
+
+ if( aDialogHelper.Execute() == ERRCODE_NONE )
+ {
+ OUString sPath( xFilePicker->getFiles().getConstArray()[0] );
+ OUString aExportMimeType( aMimeTypeMap[xFilePicker->getCurrentFilter()] );
+
+ GraphicHelper::SaveShapeAsGraphicToPath(xComponent, xShape, aExportMimeType, sPath);
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+short GraphicHelper::HasToSaveTransformedImage(weld::Widget* pWin)
+{
+ OUString aMsg(SvxResId(RID_SVXSTR_SAVE_MODIFIED_IMAGE));
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
+ VclMessageType::Question, VclButtonsType::YesNo, aMsg));
+ return xBox->run();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShape2d.cxx b/svx/source/customshapes/EnhancedCustomShape2d.cxx
new file mode 100644
index 000000000..87c081628
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShape2d.cxx
@@ -0,0 +1,3053 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/string_view.hxx>
+#include <svx/EnhancedCustomShape2d.hxx>
+#include <svx/EnhancedCustomShapeGeometry.hxx>
+#include <svx/EnhancedCustomShapeTypeNames.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnedcit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xgrad.hxx>
+#include <svx/xhatch.hxx>
+#include <svx/sdshitm.hxx>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/color/bcolortools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <sal/log.hxx>
+
+#include <algorithm>
+#include <cstdlib>
+#include <string_view>
+#include <unordered_set>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::drawing::EnhancedCustomShapeSegmentCommand;
+
+void EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( EnhancedCustomShapeParameter& rParameter, const sal_Int32 nValue )
+{
+ sal_uInt32 nDat = static_cast<sal_uInt32>(nValue);
+ sal_Int32 nNewValue = nValue;
+
+ // check if this is a special point
+ if ( ( nDat >> 16 ) == 0x8000 )
+ {
+ nNewValue = static_cast<sal_uInt16>(nDat);
+ rParameter.Type = EnhancedCustomShapeParameterType::EQUATION;
+ }
+ else
+ rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
+ rParameter.Value <<= nNewValue;
+}
+
+OUString EnhancedCustomShape2d::GetEquation( const sal_uInt16 nFlags, sal_Int32 nP1, sal_Int32 nP2, sal_Int32 nP3 )
+{
+ OUString aEquation;
+ bool b1Special = ( nFlags & 0x2000 ) != 0;
+ bool b2Special = ( nFlags & 0x4000 ) != 0;
+ bool b3Special = ( nFlags & 0x8000 ) != 0;
+ switch( nFlags & 0xff )
+ {
+ case 0 :
+ case 14 :
+ {
+ sal_Int32 nOptimize = 0;
+ if ( nP1 )
+ nOptimize |= 1;
+ if ( nP2 )
+ nOptimize |= 2;
+ if ( b1Special )
+ nOptimize |= 4;
+ if ( b2Special )
+ nOptimize |= 8;
+ switch( nOptimize )
+ {
+ case 0 :
+ break;
+ case 1 :
+ case 4 :
+ case 5 :
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ break;
+ case 2 :
+ case 8 :
+ case 10:
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ break;
+ default :
+ {
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "+";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ }
+ break;
+ }
+ if ( b3Special || nP3 )
+ {
+ aEquation += "-";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ }
+ }
+ break;
+ case 1 :
+ {
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ if ( b2Special || ( nP2 != 1 ) )
+ {
+ aEquation += "*";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ }
+ if ( b3Special || ( ( nP3 != 1 ) && ( nP3 != 0 ) ) )
+ {
+ aEquation += "/";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ }
+ }
+ break;
+ case 2 :
+ {
+ aEquation += "(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "+";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += ")/2";
+ }
+ break;
+ case 3 :
+ {
+ aEquation += "abs(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += ")";
+ }
+ break;
+ case 4 :
+ {
+ aEquation += "min(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += ",";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += ")";
+ }
+ break;
+ case 5 :
+ {
+ aEquation += "max(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += ",";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += ")";
+ }
+ break;
+ case 6 :
+ {
+ aEquation += "if(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += ",";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += ",";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += ")";
+ }
+ break;
+ case 7 :
+ {
+ aEquation += "sqrt(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "*";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "+";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += "*";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += "+";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += "*";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += ")";
+ }
+ break;
+ case 8 :
+ {
+ aEquation += "atan2(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += ",";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += ")/(pi/180)";
+ }
+ break;
+ case 9 :
+ {
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "*sin(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += "*(pi/180))";
+ }
+ break;
+ case 10 :
+ {
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "*cos(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += "*(pi/180))";
+ }
+ break;
+ case 11 :
+ {
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "*cos(atan2(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += ",";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += "))";
+ }
+ break;
+ case 12 :
+ {
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "*sin(atan2(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += ",";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += "))";
+ }
+ break;
+ case 13 :
+ {
+ aEquation += "sqrt(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += ")";
+ }
+ break;
+ case 15 :
+ {
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += "*sqrt(1-(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "/";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += ")"
+ "*(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "/";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += "))";
+ }
+ break;
+ case 16 :
+ {
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "*tan(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += ")";
+ }
+ break;
+ case 0x80 :
+ {
+ aEquation += "sqrt(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += "*";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += "-";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "*";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += ")";
+ }
+ break;
+ case 0x81 :
+ {
+ aEquation += "(cos(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += "*(pi/180))*(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "-10800)+sin(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += "*(pi/180))*(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += "-10800))+10800";
+ }
+ break;
+ case 0x82 :
+ {
+ aEquation += "-(sin(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += "*(pi/180))*(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
+ aEquation += "-10800)-cos(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
+ aEquation += "*(pi/180))*(";
+ EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
+ aEquation += "-10800))+10800";
+ }
+ break;
+ }
+ return aEquation;
+}
+
+void EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( OUString& rParameter, const sal_Int32 nPara, const bool bIsSpecialValue )
+{
+ if ( bIsSpecialValue )
+ {
+ if ( nPara & 0x400 )
+ {
+ rParameter += "?";
+ rParameter += OUString::number( nPara & 0xff );
+ rParameter += " ";
+ }
+ else
+ {
+ switch( nPara )
+ {
+ case DFF_Prop_adjustValue :
+ case DFF_Prop_adjust2Value :
+ case DFF_Prop_adjust3Value :
+ case DFF_Prop_adjust4Value :
+ case DFF_Prop_adjust5Value :
+ case DFF_Prop_adjust6Value :
+ case DFF_Prop_adjust7Value :
+ case DFF_Prop_adjust8Value :
+ case DFF_Prop_adjust9Value :
+ case DFF_Prop_adjust10Value :
+ {
+ rParameter += "$";
+ rParameter += OUString::number( nPara - DFF_Prop_adjustValue );
+ rParameter += " ";
+ }
+ break;
+ case DFF_Prop_geoLeft :
+ {
+ rParameter += "left";
+ }
+ break;
+ case DFF_Prop_geoTop :
+ {
+ rParameter += "top";
+ }
+ break;
+ case DFF_Prop_geoRight :
+ {
+ rParameter += "right";
+ }
+ break;
+ case DFF_Prop_geoBottom :
+ {
+ rParameter += "bottom";
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ rParameter += OUString::number( nPara );
+ }
+}
+
+void EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( EnhancedCustomShapeParameter& rParameter, const sal_Int32 nPara, const bool bIsSpecialValue, bool bHorz )
+{
+ sal_Int32 nValue = 0;
+ if ( bIsSpecialValue )
+ {
+ if ( ( nPara >= 0x100 ) && ( nPara <= 0x107 ) )
+ {
+ nValue = nPara & 0xff;
+ rParameter.Type = EnhancedCustomShapeParameterType::ADJUSTMENT;
+ }
+ else if ( ( nPara >= 3 ) && ( nPara <= 0x82 ) )
+ {
+ nValue = nPara - 3;
+ rParameter.Type = EnhancedCustomShapeParameterType::EQUATION;
+ }
+ else if ( nPara == 0 )
+ {
+ nValue = 0;
+ if ( bHorz )
+ rParameter.Type = EnhancedCustomShapeParameterType::LEFT;
+ else
+ rParameter.Type = EnhancedCustomShapeParameterType::TOP;
+ }
+ else if ( nPara == 1 )
+ {
+ nValue = 0;
+ if ( bHorz )
+ rParameter.Type = EnhancedCustomShapeParameterType::RIGHT;
+ else
+ rParameter.Type = EnhancedCustomShapeParameterType::BOTTOM;
+ }
+ else if ( nPara == 2 ) // means to be centered, but should not be
+ { // used in our implementation
+ nValue = 5600;
+ rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
+ }
+ else
+ {
+ nValue = nPara;
+ rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
+ }
+ }
+ else
+ {
+ nValue = nPara;
+ rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
+ }
+ rParameter.Value <<= nValue;
+}
+
+bool EnhancedCustomShape2d::ConvertSequenceToEnhancedCustomShape2dHandle(
+ const css::beans::PropertyValues& rHandleProperties,
+ EnhancedCustomShape2d::Handle& rDestinationHandle )
+{
+ bool bRetValue = false;
+ if ( rHandleProperties.hasElements() )
+ {
+ rDestinationHandle.nFlags = HandleFlags::NONE;
+ for ( const css::beans::PropertyValue& rPropVal : rHandleProperties )
+ {
+ if ( rPropVal.Name == "Position" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.aPosition )
+ bRetValue = true;
+ }
+ else if ( rPropVal.Name == "MirroredX" )
+ {
+ bool bMirroredX;
+ if ( rPropVal.Value >>= bMirroredX )
+ {
+ if ( bMirroredX )
+ rDestinationHandle.nFlags |= HandleFlags::MIRRORED_X;
+ }
+ }
+ else if ( rPropVal.Name == "MirroredY" )
+ {
+ bool bMirroredY;
+ if ( rPropVal.Value >>= bMirroredY )
+ {
+ if ( bMirroredY )
+ rDestinationHandle.nFlags |= HandleFlags::MIRRORED_Y;
+ }
+ }
+ else if ( rPropVal.Name == "Switched" )
+ {
+ bool bSwitched;
+ if ( rPropVal.Value >>= bSwitched )
+ {
+ if ( bSwitched )
+ rDestinationHandle.nFlags |= HandleFlags::SWITCHED;
+ }
+ }
+ else if ( rPropVal.Name == "Polar" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.aPolar )
+ rDestinationHandle.nFlags |= HandleFlags::POLAR;
+ }
+ else if ( rPropVal.Name == "RefX" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.nRefX )
+ rDestinationHandle.nFlags |= HandleFlags::REFX;
+ }
+ else if ( rPropVal.Name == "RefY" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.nRefY )
+ rDestinationHandle.nFlags |= HandleFlags::REFY;
+ }
+ else if ( rPropVal.Name == "RefAngle" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.nRefAngle )
+ rDestinationHandle.nFlags |= HandleFlags::REFANGLE;
+ }
+ else if ( rPropVal.Name == "RefR" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.nRefR )
+ rDestinationHandle.nFlags |= HandleFlags::REFR;
+ }
+ else if ( rPropVal.Name == "RadiusRangeMinimum" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.aRadiusRangeMinimum )
+ rDestinationHandle.nFlags |= HandleFlags::RADIUS_RANGE_MINIMUM;
+ }
+ else if ( rPropVal.Name == "RadiusRangeMaximum" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.aRadiusRangeMaximum )
+ rDestinationHandle.nFlags |= HandleFlags::RADIUS_RANGE_MAXIMUM;
+ }
+ else if ( rPropVal.Name == "RangeXMinimum" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.aXRangeMinimum )
+ rDestinationHandle.nFlags |= HandleFlags::RANGE_X_MINIMUM;
+ }
+ else if ( rPropVal.Name == "RangeXMaximum" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.aXRangeMaximum )
+ rDestinationHandle.nFlags |= HandleFlags::RANGE_X_MAXIMUM;
+ }
+ else if ( rPropVal.Name == "RangeYMinimum" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.aYRangeMinimum )
+ rDestinationHandle.nFlags |= HandleFlags::RANGE_Y_MINIMUM;
+ }
+ else if ( rPropVal.Name == "RangeYMaximum" )
+ {
+ if ( rPropVal.Value >>= rDestinationHandle.aYRangeMaximum )
+ rDestinationHandle.nFlags |= HandleFlags::RANGE_Y_MAXIMUM;
+ }
+ }
+ }
+ return bRetValue;
+}
+
+void EnhancedCustomShape2d::ApplyShapeAttributes( const SdrCustomShapeGeometryItem& rGeometryItem )
+{
+ // AdjustmentValues
+ static constexpr OUStringLiteral sAdjustmentValues( u"AdjustmentValues" );
+ const Any* pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sAdjustmentValues );
+ if ( pAny )
+ *pAny >>= seqAdjustmentValues;
+
+
+ // Coordsize
+ static constexpr OUStringLiteral sViewBox( u"ViewBox" );
+ const Any* pViewBox = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sViewBox );
+ css::awt::Rectangle aViewBox;
+ if ( pViewBox && (*pViewBox >>= aViewBox ) )
+ {
+ nCoordLeft = aViewBox.X;
+ nCoordTop = aViewBox.Y;
+ nCoordWidthG = std::abs( aViewBox.Width );
+ nCoordHeightG = std::abs( aViewBox.Height);
+ }
+ static constexpr OUStringLiteral sPath( u"Path" );
+ static constexpr OUStringLiteral sCoordinates( u"Coordinates" );
+ static constexpr OUStringLiteral sGluePoints( u"GluePoints" );
+ static constexpr OUStringLiteral sSegments( u"Segments" );
+ static constexpr OUStringLiteral sSubViewSize( u"SubViewSize" );
+ static constexpr OUStringLiteral sStretchX( u"StretchX" );
+ static constexpr OUStringLiteral sStretchY( u"StretchY" );
+ static constexpr OUStringLiteral sTextFrames( u"TextFrames" );
+ static constexpr OUStringLiteral sEquations( u"Equations" );
+ static constexpr OUStringLiteral sHandles( u"Handles" );
+
+
+ // Path/Coordinates
+ pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sPath, sCoordinates );
+ if ( pAny )
+ *pAny >>= seqCoordinates;
+
+
+ // Path/GluePoints
+ pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sPath, sGluePoints );
+ if ( pAny )
+ *pAny >>= seqGluePoints;
+
+
+ // Path/Segments
+ pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sPath, sSegments );
+ if ( pAny )
+ *pAny >>= seqSegments;
+
+
+ // Path/SubViewSize
+ pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sPath, sSubViewSize );
+ if ( pAny )
+ *pAny >>= seqSubViewSize;
+
+
+ // Path/StretchX
+ pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sPath, sStretchX );
+ if ( pAny )
+ {
+ sal_Int32 nStretchX = 0;
+ if ( *pAny >>= nStretchX )
+ nXRef = nStretchX;
+ }
+
+
+ // Path/StretchY
+ pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sPath, sStretchY );
+ if ( pAny )
+ {
+ sal_Int32 nStretchY = 0;
+ if ( *pAny >>= nStretchY )
+ nYRef = nStretchY;
+ }
+
+
+ // Path/TextFrames
+ pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sPath, sTextFrames );
+ if ( pAny )
+ *pAny >>= seqTextFrames;
+
+
+ // Equations
+ pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sEquations );
+ if ( pAny )
+ *pAny >>= seqEquations;
+
+
+ // Handles
+ pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sHandles );
+ if ( pAny )
+ *pAny >>= seqHandles;
+}
+
+EnhancedCustomShape2d::~EnhancedCustomShape2d()
+{
+}
+
+void EnhancedCustomShape2d::SetPathSize( sal_Int32 nIndex )
+{
+ sal_Int32 nWidth = 0;
+ sal_Int32 nHeight = 0;
+
+ if ( seqSubViewSize.hasElements() && nIndex < seqSubViewSize.getLength() ) {
+ nWidth = seqSubViewSize[ nIndex ].Width;
+ nHeight = seqSubViewSize[ nIndex ].Height;
+ SAL_INFO(
+ "svx",
+ "set subpath " << nIndex << " size: " << nWidth << " x "
+ << nHeight);
+ }
+
+ if ( nWidth && nHeight ) {
+ nCoordWidth = nWidth;
+ nCoordHeight = nHeight;
+ } else {
+ nCoordWidth = nCoordWidthG;
+ nCoordHeight = nCoordHeightG;
+ }
+
+ fXScale = nCoordWidth == 0 ? 0.0 : static_cast<double>(aLogicRect.GetWidth()) / static_cast<double>(nCoordWidth);
+ fYScale = nCoordHeight == 0 ? 0.0 : static_cast<double>(aLogicRect.GetHeight()) / static_cast<double>(nCoordHeight);
+ if ( bOOXMLShape )
+ {
+ SAL_INFO(
+ "svx",
+ "ooxml shape, path width: " << nCoordWidth << " height: "
+ << nCoordHeight);
+
+ // Try to set up scale separately, if given only width or height
+ // This is possible case in OOXML when only width or height is non-zero
+ if ( nCoordWidth == 0 )
+ {
+ if ( nWidth )
+ fXScale = static_cast<double>(aLogicRect.GetWidth()) / static_cast<double>(nWidth);
+ else
+ fXScale = 1.0;
+ }
+ if ( nCoordHeight == 0 )
+ {
+ if ( nHeight )
+ fYScale = static_cast<double>(aLogicRect.GetHeight()) / static_cast<double>(nHeight);
+ else
+ fYScale = 1.0;
+ }
+ }
+ if ( static_cast<sal_uInt32>(nXRef) != 0x80000000 && aLogicRect.GetHeight() )
+ {
+ fXRatio = static_cast<double>(aLogicRect.GetWidth()) / static_cast<double>(aLogicRect.GetHeight());
+ if ( fXRatio > 1 )
+ fXScale /= fXRatio;
+ else
+ fXRatio = 1.0;
+ }
+ else
+ fXRatio = 1.0;
+ if ( static_cast<sal_uInt32>(nYRef) != 0x80000000 && aLogicRect.GetWidth() )
+ {
+ fYRatio = static_cast<double>(aLogicRect.GetHeight()) / static_cast<double>(aLogicRect.GetWidth());
+ if ( fYRatio > 1 )
+ fYScale /= fYRatio;
+ else
+ fYRatio = 1.0;
+ }
+ else
+ fYRatio = 1.0;
+}
+
+EnhancedCustomShape2d::EnhancedCustomShape2d(SdrObjCustomShape& rSdrObjCustomShape)
+: SfxItemSet ( rSdrObjCustomShape.GetMergedItemSet() ),
+ mrSdrObjCustomShape ( rSdrObjCustomShape ),
+ eSpType ( mso_sptNil ),
+ nCoordLeft ( 0 ),
+ nCoordTop ( 0 ),
+ nCoordWidthG ( 21600 ),
+ nCoordHeightG ( 21600 ),
+ bOOXMLShape ( false ),
+ nXRef ( 0x80000000 ),
+ nYRef ( 0x80000000 ),
+ nColorData ( 0 ),
+ bFilled ( rSdrObjCustomShape.GetMergedItem( XATTR_FILLSTYLE ).GetValue() != drawing::FillStyle_NONE ),
+ bStroked ( rSdrObjCustomShape.GetMergedItem( XATTR_LINESTYLE ).GetValue() != drawing::LineStyle_NONE ),
+ bFlipH ( false ),
+ bFlipV ( false )
+{
+ // bTextFlow needs to be set before clearing the TextDirection Item
+
+ ClearItem( SDRATTR_TEXTDIRECTION ); //SJ: vertical writing is not required, by removing this item no outliner is created
+
+ // #i105323# For 2D AutoShapes, the shadow attribute does not need to be applied to any
+ // of the constructed helper SdrObjects. This would lead to problems since the shadow
+ // of one helper object would fall on one helper object behind it (e.g. with the
+ // eyes of the smiley shape). This is not wanted; instead a single shadow 'behind'
+ // the AutoShape visualisation is wanted. This is done with primitive functionality
+ // now in SdrCustomShapePrimitive2D::create2DDecomposition, but only for 2D objects
+ // (see there and in EnhancedCustomShape3d::Create3DObject to read more).
+ // This exception may be removed later when AutoShapes will create primitives directly.
+ // So, currently remove the ShadowAttribute from the ItemSet to not apply it to any
+ // 2D helper shape.
+ ClearItem(SDRATTR_SHADOW);
+
+ Point aP( mrSdrObjCustomShape.GetSnapRect().Center() );
+ Size aS( mrSdrObjCustomShape.GetLogicRect().GetSize() );
+ aP.AdjustX( -(aS.Width() / 2) );
+ aP.AdjustY( -(aS.Height() / 2) );
+ aLogicRect = tools::Rectangle( aP, aS );
+
+ OUString sShapeType;
+ const SdrCustomShapeGeometryItem& rGeometryItem(mrSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
+ static constexpr OUStringLiteral sType = u"Type";
+ const Any* pAny = rGeometryItem.GetPropertyValueByName( sType );
+ if ( pAny ) {
+ *pAny >>= sShapeType;
+ bOOXMLShape = sShapeType.startsWith("ooxml-");
+ SAL_INFO("svx", "shape type: " << sShapeType << " " << bOOXMLShape);
+ }
+ eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
+
+ static constexpr OUStringLiteral sMirroredX = u"MirroredX";
+ static constexpr OUStringLiteral sMirroredY = u"MirroredY";
+ pAny = rGeometryItem.GetPropertyValueByName( sMirroredX );
+ if ( pAny )
+ *pAny >>= bFlipH;
+ pAny = rGeometryItem.GetPropertyValueByName( sMirroredY );
+ if ( pAny )
+ *pAny >>= bFlipV;
+
+ nRotateAngle = Degree100(static_cast<sal_Int32>(mrSdrObjCustomShape.GetObjectRotation() * 100.0));
+
+ /*const sal_Int32* pDefData =*/ ApplyShapeAttributes( rGeometryItem );
+ SetPathSize();
+
+ switch( eSpType )
+ {
+ case mso_sptCan : nColorData = 0x20400000; break;
+ case mso_sptCube : nColorData = 0x302e0000; break;
+ case mso_sptActionButtonBlank : nColorData = 0x502ce400; break;
+ case mso_sptActionButtonHome : nColorData = 0x702ce4ce; break;
+ case mso_sptActionButtonHelp : nColorData = 0x602ce4c0; break;
+ case mso_sptActionButtonInformation : nColorData = 0x702ce4c5; break;
+ case mso_sptActionButtonBackPrevious : nColorData = 0x602ce4c0; break;
+ case mso_sptActionButtonForwardNext : nColorData = 0x602ce4c0; break;
+ case mso_sptActionButtonBeginning : nColorData = 0x602ce4c0; break;
+ case mso_sptActionButtonEnd : nColorData = 0x602ce4c0; break;
+ case mso_sptActionButtonReturn : nColorData = 0x602ce4c0; break;
+ case mso_sptActionButtonDocument : nColorData = 0x702ce4ec; break;
+ case mso_sptActionButtonSound : nColorData = 0x602ce4c0; break;
+ case mso_sptActionButtonMovie : nColorData = 0x602ce4c0; break;
+ case mso_sptBevel : nColorData = 0x502ce400; break;
+ case mso_sptFoldedCorner : nColorData = 0x20e00000; break;
+ case mso_sptSmileyFace : nColorData = 0x20e00000; break;
+ case mso_sptNil :
+ {
+ // Because calculation method has changed in #i102797 original color encoding for
+ // Octagon Bevel and Diamond Bevel can no longer be used. We keep the color coding
+ // only for self-created shapes, as authors may have already considered the change.
+ // We use ColorData compatible to OOXML.
+ if (sShapeType == "col-60da8460") // Octagon Bevel
+ {
+ nColorData = 0x60ecc240;
+ }
+ else if (sShapeType == "col-502ad400") // Diamond Bevel
+ {
+ nColorData = 0x502ce400;
+ }
+ else if (sShapeType.getLength() > 4 && sShapeType.match( "col-" ))
+ {
+ nColorData = o3tl::toUInt32(sShapeType.subView( 4 ), 16);
+ }
+ }
+ break;
+ case mso_sptCurvedLeftArrow :
+ case mso_sptCurvedRightArrow :
+ case mso_sptCurvedUpArrow :
+ case mso_sptCurvedDownArrow : nColorData = 0x20d00000; break;
+ case mso_sptRibbon2 : nColorData = 0x30ee0000; break;
+ case mso_sptRibbon : nColorData = 0x30ee0000; break;
+
+ case mso_sptEllipseRibbon2 : nColorData = 0x30ee0000; break;
+ case mso_sptEllipseRibbon : nColorData = 0x30ee0000; break;
+
+ case mso_sptVerticalScroll : nColorData = 0x30ee0000; break;
+ case mso_sptHorizontalScroll : nColorData = 0x30ee0000; break;
+ default:
+ break;
+ }
+
+ sal_Int32 nLength = seqEquations.getLength();
+
+ if ( !nLength )
+ return;
+
+ vNodesSharedPtr.resize( nLength );
+ vEquationResults.resize( nLength );
+ for ( sal_Int32 i = 0; i < nLength; i++ )
+ {
+ vEquationResults[ i ].bReady = false;
+ try
+ {
+ vNodesSharedPtr[ i ] = EnhancedCustomShape::FunctionParser::parseFunction( seqEquations[ i ], *this );
+ }
+ catch ( EnhancedCustomShape::ParseError& )
+ {
+ SAL_INFO(
+ "svx",
+ "error: equation number: " << i << ", parser failed ("
+ << seqEquations[i] << ")");
+ }
+ }
+}
+
+using EnhancedCustomShape::ExpressionFunct;
+
+double EnhancedCustomShape2d::GetEnumFunc( const ExpressionFunct eFunc ) const
+{
+ double fRet = 0.0;
+ switch( eFunc )
+ {
+ case ExpressionFunct::EnumPi : fRet = M_PI; break;
+ case ExpressionFunct::EnumLeft : fRet = static_cast<double>(nCoordLeft); break;
+ case ExpressionFunct::EnumTop : fRet = static_cast<double>(nCoordTop); break;
+ case ExpressionFunct::EnumRight : fRet = (static_cast<double>(nCoordLeft) + static_cast<double>(nCoordWidth)) * fXRatio; break;
+ case ExpressionFunct::EnumBottom : fRet = (static_cast<double>(nCoordTop) + static_cast<double>(nCoordHeight)) * fYRatio; break;
+ case ExpressionFunct::EnumXStretch : fRet = nXRef; break;
+ case ExpressionFunct::EnumYStretch : fRet = nYRef; break;
+ case ExpressionFunct::EnumHasStroke : fRet = bStroked ? 1.0 : 0.0; break;
+ case ExpressionFunct::EnumHasFill : fRet = bFilled ? 1.0 : 0.0; break;
+ case ExpressionFunct::EnumWidth : fRet = nCoordWidth; break;
+ case ExpressionFunct::EnumHeight : fRet = nCoordHeight; break;
+ case ExpressionFunct::EnumLogWidth : fRet = aLogicRect.GetWidth(); break;
+ case ExpressionFunct::EnumLogHeight : fRet = aLogicRect.GetHeight(); break;
+ default: break;
+ }
+ return fRet;
+}
+double EnhancedCustomShape2d::GetAdjustValueAsDouble( const sal_Int32 nIndex ) const
+{
+ double fNumber = 0.0;
+ if ( nIndex < seqAdjustmentValues.getLength() )
+ {
+ if ( seqAdjustmentValues[ nIndex ].Value.getValueTypeClass() == TypeClass_DOUBLE )
+ seqAdjustmentValues[ nIndex ].Value >>= fNumber;
+ else
+ {
+ sal_Int32 nNumber = 0;
+ seqAdjustmentValues[ nIndex ].Value >>= nNumber;
+ fNumber = static_cast<double>(nNumber);
+ }
+ }
+ return fNumber;
+}
+double EnhancedCustomShape2d::GetEquationValueAsDouble( const sal_Int32 nIndex ) const
+{
+ double fNumber = 0.0;
+ static sal_uInt32 nLevel = 0;
+ if ( nIndex < static_cast<sal_Int32>(vNodesSharedPtr.size()) )
+ {
+ if ( vNodesSharedPtr[ nIndex ] ) {
+ nLevel ++;
+ try
+ {
+ if ( vEquationResults[ nIndex ].bReady )
+ fNumber = vEquationResults[ nIndex ].fValue;
+ else {
+ // cast to non const, so that we can optimize by caching
+ // equation results, without changing all the const in the stack
+ struct EquationResult &aResult = const_cast<EnhancedCustomShape2d*>(this)->vEquationResults[ nIndex ];
+
+ fNumber = aResult.fValue = (*vNodesSharedPtr[ nIndex ])();
+ aResult.bReady = true;
+
+ SAL_INFO("svx", "equation " << nLevel << " (level: " << seqEquations[nIndex] << "): "
+ << fNumber << " --> " << 180.0*fNumber/10800000.0);
+ }
+ if ( !std::isfinite( fNumber ) )
+ fNumber = 0.0;
+ }
+ catch ( ... )
+ {
+ SAL_WARN("svx", "EnhancedCustomShape2d::GetEquationValueAsDouble failed");
+ }
+ nLevel --;
+ }
+ SAL_INFO(
+ "svx",
+ "?" << nIndex << " --> " << fNumber << " (angle: "
+ << 180.0*fNumber/10800000.0 << ")");
+ }
+
+ return fNumber;
+}
+
+bool EnhancedCustomShape2d::SetAdjustValueAsDouble( const double& rValue, const sal_Int32 nIndex )
+{
+ bool bRetValue = false;
+ if ( nIndex < seqAdjustmentValues.getLength() )
+ {
+ // updating our local adjustment sequence
+ auto pseqAdjustmentValues = seqAdjustmentValues.getArray();
+ pseqAdjustmentValues[ nIndex ].Value <<= rValue;
+ pseqAdjustmentValues[ nIndex ].State = css::beans::PropertyState_DIRECT_VALUE;
+ bRetValue = true;
+ }
+ return bRetValue;
+}
+
+basegfx::B2DPoint EnhancedCustomShape2d::GetPointAsB2DPoint( const css::drawing::EnhancedCustomShapeParameterPair& rPair,
+ const bool bScale, const bool bReplaceGeoSize ) const
+{
+ double fValX, fValY;
+ // width
+ GetParameter(fValX, rPair.First, bReplaceGeoSize, false);
+ fValX -= nCoordLeft;
+ if (bScale)
+ {
+ fValX *= fXScale;
+ }
+ // height
+ GetParameter(fValY, rPair.Second, false, bReplaceGeoSize);
+ fValY -= nCoordTop;
+ if (bScale)
+ {
+ fValY *= fYScale;
+ }
+ return basegfx::B2DPoint(fValX,fValY);
+}
+
+Point EnhancedCustomShape2d::GetPoint( const css::drawing::EnhancedCustomShapeParameterPair& rPair,
+ const bool bScale, const bool bReplaceGeoSize ) const
+{
+ basegfx::B2DPoint aPoint(GetPointAsB2DPoint(rPair, bScale, bReplaceGeoSize));
+ return Point(static_cast<tools::Long>(aPoint.getX()), static_cast<tools::Long>(aPoint.getY()));
+}
+
+void EnhancedCustomShape2d::GetParameter( double& rRetValue, const EnhancedCustomShapeParameter& rParameter,
+ const bool bReplaceGeoWidth, const bool bReplaceGeoHeight ) const
+{
+ rRetValue = 0.0;
+ switch ( rParameter.Type )
+ {
+ case EnhancedCustomShapeParameterType::ADJUSTMENT :
+ {
+ sal_Int32 nAdjustmentIndex = 0;
+ if ( rParameter.Value >>= nAdjustmentIndex )
+ {
+ rRetValue = GetAdjustValueAsDouble( nAdjustmentIndex );
+ }
+ }
+ break;
+ case EnhancedCustomShapeParameterType::EQUATION :
+ {
+ sal_Int32 nEquationIndex = 0;
+ if ( rParameter.Value >>= nEquationIndex )
+ {
+ rRetValue = GetEquationValueAsDouble( nEquationIndex );
+ }
+ }
+ break;
+ case EnhancedCustomShapeParameterType::NORMAL :
+ {
+ if ( rParameter.Value.getValueTypeClass() == TypeClass_DOUBLE )
+ {
+ double fValue(0.0);
+ if ( rParameter.Value >>= fValue )
+ {
+ rRetValue = fValue;
+ }
+ }
+ else
+ {
+ sal_Int32 nValue = 0;
+ if ( rParameter.Value >>= nValue )
+ {
+ rRetValue = nValue;
+ if ( bReplaceGeoWidth && ( nValue == nCoordWidth ) )
+ rRetValue *= fXRatio;
+ else if ( bReplaceGeoHeight && ( nValue == nCoordHeight ) )
+ rRetValue *= fYRatio;
+ }
+ }
+ }
+ break;
+ case EnhancedCustomShapeParameterType::LEFT :
+ {
+ rRetValue = 0.0;
+ }
+ break;
+ case EnhancedCustomShapeParameterType::TOP :
+ {
+ rRetValue = 0.0;
+ }
+ break;
+ case EnhancedCustomShapeParameterType::RIGHT :
+ {
+ rRetValue = nCoordWidth;
+ }
+ break;
+ case EnhancedCustomShapeParameterType::BOTTOM :
+ {
+ rRetValue = nCoordHeight;
+ }
+ break;
+ }
+}
+
+// nLumDat 28-31 = number of luminance entries in nLumDat
+// nLumDat 27-24 = nLumDatEntry 0
+// nLumDat 23-20 = nLumDatEntry 1 ...
+// each 4bit entry is to be interpreted as a 10 percent signed luminance changing
+sal_Int32 EnhancedCustomShape2d::GetLuminanceChange( sal_uInt32 nIndex ) const
+{
+ const sal_uInt32 nCount = nColorData >> 28;
+ if ( !nCount )
+ return 0;
+
+ if ( nIndex >= nCount )
+ nIndex = nCount - 1;
+
+ const sal_Int32 nLumDat = nColorData << ( ( 1 + nIndex ) << 2 );
+ return ( nLumDat >> 28 ) * 10;
+}
+
+Color EnhancedCustomShape2d::GetColorData( const Color& rFillColor, sal_uInt32 nIndex, double dBrightness ) const
+{
+ if ( bOOXMLShape || ( mso_sptMin == eSpType /* ODF "non-primitive" */ ) )
+ { //do LibreOffice way, using dBrightness
+ if ( dBrightness == 0.0)
+ {
+ return rFillColor;
+ }
+ else
+ {
+ if (dBrightness >=0.0)
+ { //lighten, blending with white
+ return Color( static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetRed() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0) )),
+ static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetGreen() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0) )),
+ static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetBlue() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0) )) );
+ }
+ else
+ { //darken (indicated by negative sign), blending with black
+ return Color( static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetRed() * (1.0+dBrightness), 0.0, 255.0) )),
+ static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetGreen() * (1.0+dBrightness), 0.0, 255.0) )),
+ static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(rFillColor.GetBlue() * (1.0+dBrightness), 0.0, 255.0) )) );
+ }
+ }
+ }
+ else
+ { //do OpenOffice way, using nColorData
+ const sal_Int32 nLuminance = GetLuminanceChange(nIndex);
+ if( !nLuminance )
+ return rFillColor;
+
+ basegfx::BColor aHSVColor=
+ basegfx::utils::rgb2hsv(
+ basegfx::BColor(rFillColor.GetRed()/255.0,
+ rFillColor.GetGreen()/255.0,
+ rFillColor.GetBlue()/255.0));
+
+ if( nLuminance > 0 )
+ {
+ aHSVColor.setGreen(
+ aHSVColor.getGreen() * (1.0-nLuminance/100.0));
+ aHSVColor.setBlue(
+ nLuminance/100.0 +
+ (1.0-nLuminance/100.0)*aHSVColor.getBlue());
+ }
+ else if( nLuminance < 0 )
+ {
+ aHSVColor.setBlue(
+ (1.0+nLuminance/100.0)*aHSVColor.getBlue());
+ }
+
+ aHSVColor = basegfx::utils::hsv2rgb(aHSVColor);
+ return Color( static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(aHSVColor.getRed(),0.0,1.0) * 255.0 + 0.5 )),
+ static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(aHSVColor.getGreen(),0.0,1.0) * 255.0 + 0.5 )),
+ static_cast<sal_uInt8>(static_cast< sal_Int32 >( std::clamp(aHSVColor.getBlue(),0.0,1.0) * 255.0 + 0.5 )) );
+ }
+}
+
+tools::Rectangle EnhancedCustomShape2d::GetTextRect() const
+{
+ if ( !seqTextFrames.hasElements() )
+ return aLogicRect;
+ sal_Int32 nIndex = 0;
+ Point aTopLeft( GetPoint( seqTextFrames[ nIndex ].TopLeft, !bOOXMLShape, true ) );
+ Point aBottomRight( GetPoint( seqTextFrames[ nIndex ].BottomRight, !bOOXMLShape, true ) );
+ tools::Rectangle aRect( aTopLeft, aBottomRight );
+ if ( bFlipH )
+ {
+ aRect.SetLeft(aLogicRect.GetWidth() - 1 - aBottomRight.X());
+ aRect.SetRight( aLogicRect.GetWidth() - 1 - aTopLeft.X());
+ }
+ if ( bFlipV )
+ {
+ aRect.SetTop(aLogicRect.GetHeight() - 1 - aBottomRight.Y());
+ aRect.SetBottom(aLogicRect.GetHeight() - 1 - aTopLeft.Y());
+ }
+ SAL_INFO("svx", aRect.GetWidth() << " x " << aRect.GetHeight());
+ if( aRect.GetWidth() <= 1 || aRect.GetHeight() <= 1 )
+ return aLogicRect;
+ aRect.Move( aLogicRect.Left(), aLogicRect.Top() );
+ aRect.Justify();
+ return aRect;
+}
+
+sal_uInt32 EnhancedCustomShape2d::GetHdlCount() const
+{
+ return seqHandles.getLength();
+}
+
+bool EnhancedCustomShape2d::GetHandlePosition( const sal_uInt32 nIndex, Point& rReturnPosition ) const
+{
+ bool bRetValue = false;
+ if ( nIndex < GetHdlCount() )
+ {
+ Handle aHandle;
+ if ( ConvertSequenceToEnhancedCustomShape2dHandle( seqHandles[ nIndex ], aHandle ) )
+ {
+ if ( aHandle.nFlags & HandleFlags::POLAR )
+ {
+ Point aReferencePoint( GetPoint( aHandle.aPolar ) );
+
+ double fAngle;
+ double fRadius;
+ GetParameter( fRadius, aHandle.aPosition.First, false, false );
+ GetParameter( fAngle, aHandle.aPosition.Second, false, false );
+
+ double a = basegfx::deg2rad(360.0 - fAngle);
+ double dx = fRadius * fXScale;
+ double fX = dx * cos( a );
+ double fY =-dx * sin( a );
+ rReturnPosition =
+ Point(
+ FRound( fX + aReferencePoint.X() ),
+ basegfx::fTools::equalZero(fXScale) ? aReferencePoint.Y() :
+ FRound( ( fY * fYScale ) / fXScale + aReferencePoint.Y() ) );
+ }
+ else
+ {
+ if ( aHandle.nFlags & HandleFlags::SWITCHED )
+ {
+ if ( aLogicRect.GetHeight() > aLogicRect.GetWidth() )
+ {
+ css::drawing::EnhancedCustomShapeParameter aFirst = aHandle.aPosition.First;
+ css::drawing::EnhancedCustomShapeParameter aSecond = aHandle.aPosition.Second;
+ aHandle.aPosition.First = aSecond;
+ aHandle.aPosition.Second = aFirst;
+ }
+ }
+ if (bOOXMLShape)
+ rReturnPosition = GetPoint(aHandle.aPosition, false /*bScale*/);
+ else
+ rReturnPosition = GetPoint(aHandle.aPosition, true /*bScale*/);
+ }
+ const GeoStat aGeoStat(mrSdrObjCustomShape.GetGeoStat());
+ if ( aGeoStat.nShearAngle )
+ {
+ double nTan = aGeoStat.mfTanShearAngle;
+ if (bFlipV != bFlipH)
+ nTan = -nTan;
+ ShearPoint( rReturnPosition, Point( aLogicRect.GetWidth() / 2, aLogicRect.GetHeight() / 2 ), nTan );
+ }
+ if ( nRotateAngle )
+ {
+ double a = toRadians(nRotateAngle);
+ RotatePoint( rReturnPosition, Point( aLogicRect.GetWidth() / 2, aLogicRect.GetHeight() / 2 ), sin( a ), cos( a ) );
+ }
+ if ( bFlipH )
+ rReturnPosition.setX( aLogicRect.GetWidth() - rReturnPosition.X() );
+ if ( bFlipV )
+ rReturnPosition.setY( aLogicRect.GetHeight() - rReturnPosition.Y() );
+ rReturnPosition.Move( aLogicRect.Left(), aLogicRect.Top() );
+ bRetValue = true;
+ }
+ }
+ return bRetValue;
+}
+
+static double lcl_getXAdjustmentValue(std::u16string_view rShapeType, const sal_uInt32 nHandleIndex,
+ const double fX, const double fW, const double fH)
+{
+ // degenerated shapes are not worth to calculate special case for each shape type
+ if (fW <= 0.0 || fH <= 0.0)
+ return 50000;
+
+ // pattern (w - x) / ss * 100000 or (r - x) / ss * 100000
+ if ((rShapeType == u"ooxml-bentArrow" && nHandleIndex == 2) || (rShapeType == u"ooxml-chevron")
+ || (rShapeType == u"ooxml-curvedRightArrow") || (rShapeType == u"ooxml-foldedCorner")
+ || (rShapeType == u"ooxml-homePlate") || (rShapeType == u"ooxml-notchedRightArrow")
+ || (rShapeType == u"ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-rightArrow")
+ || (rShapeType == u"ooxml-rightArrowCallout" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-round1Rect")
+ || (rShapeType == u"ooxml-round2DiagRect" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-round2SameRect" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-snip1Rect")
+ || (rShapeType == u"ooxml-snip2DiagRect" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-snip2SameRect" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-snipRoundRect" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-swooshArrow") || (rShapeType == u"ooxml-stripedRightArrow"))
+ return (fW - fX) / std::min(fW, fH) * 100000.0;
+
+ // pattern x / ss * 100000 or (x - l) / ss * 100000
+ if ((rShapeType == u"ooxml-bentArrow" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-bentArrow" && nHandleIndex == 3)
+ || (rShapeType == u"ooxml-corner")
+ || (rShapeType == u"ooxml-curvedDownArrow") || (rShapeType == u"ooxml-curvedLeftArrow")
+ || (rShapeType == u"ooxml-curvedUpArrow") || (rShapeType == u"ooxml-leftArrow")
+ || (rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-leftRightArrow")
+ || (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-leftRightRibbon")
+ || (rShapeType == u"ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-parallelogram")
+ || (rShapeType == u"ooxml-round2DiagRect" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-round2SameRect" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-roundRect")
+ || (rShapeType == u"ooxml-snip2DiagRect" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-snip2SameRect" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-snipRoundRect" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 3))
+ return fX / std::min(fW, fH) * 100000.0;
+
+ // pattern (hc - x) / ss * 200000
+ if ((rShapeType == u"ooxml-downArrowCallout" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-leftRightUpArrow" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-quadArrow" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 0))
+ return (fW / 2.0 - fX) / std::min(fW, fH) * 200000.0;
+
+ // pattern (hc - x) / ss * 100000
+ if ((rShapeType == u"ooxml-downArrowCallout" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-leftRightUpArrow" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-quadArrow" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 1))
+ return (fW / 2.0 - fX) / std::min(fW, fH) * 100000.0;
+
+ // pattern (w - x) / ss * 50000 or (r - x) / ss * 50000
+ if ((rShapeType == u"ooxml-bentUpArrow") || (rShapeType == u"ooxml-leftUpArrow")
+ || (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 1))
+ return (fW - fX) / std::min(fW, fH) * 50000.0;
+
+ // pattern x / ss * 200000
+ if (rShapeType == u"ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 0)
+ return fX / std::min(fW, fH) * 200000.0;
+
+ // pattern (hc - x) / w * 200000
+ if ((rShapeType == u"ooxml-downArrow" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-ellipseRibbon") || (rShapeType == u"ooxml-ellipseRibbon2")
+ || (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 3)
+ || (rShapeType == u"ooxml-ribbon") || (rShapeType == u"ooxml-ribbon2")
+ || (rShapeType == u"ooxml-upArrow" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-upDownArrow" && nHandleIndex == 0))
+ return (fW / 2.0 - fX) / fW * 200000.0;
+
+ // pattern (x - hc) / w * 100000
+ if ((rShapeType == u"ooxml-cloudCallout") || (rShapeType == u"ooxml-doubleWave")
+ || (rShapeType == u"ooxml-wave") || (rShapeType == u"ooxml-wedgeEllipseCallout")
+ || (rShapeType == u"ooxml-wedgeRectCallout")
+ || (rShapeType == u"ooxml-wedgeRoundRectCallout"))
+ return (fX - fW / 2.0) / fW * 100000.0;
+
+ // pattern (x - hc) / w * 200000
+ if (rShapeType == u"ooxml-teardrop")
+ return (fX - fW / 2.0) / fW * 200000.0;
+
+ // pattern (w - x) / w * 100000 or (r - x) / w * 100000
+ if (rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 3)
+ return (fW - fX) / fW * 100000.0;
+
+ // pattern (hc - x) / h * 100000
+ if (rShapeType == u"ooxml-mathDivide")
+ return (fW / 2.0 - fX) / fH * 100000.0;
+
+ // pattern x / w * 100000, simple scaling
+ if (o3tl::starts_with(rShapeType, u"ooxml-"))
+ return fX / fW * 100000.0;
+
+ return fX; // method is unknown
+}
+
+static double lcl_getYAdjustmentValue(std::u16string_view rShapeType, const sal_uInt32 nHandleIndex,
+ const double fY, const double fW, const double fH)
+{
+ // degenerated shapes are not worth to calculate a special case for each shape type
+ if (fW <= 0.0 || fH <= 0.0)
+ return 50000;
+
+ // pattern (vc - y) / ss * 100000
+ if ((rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-rightArrowCallout" && nHandleIndex == 1))
+ return (fH / 2.0 - fY) / std::min(fW, fH) * 100000.0;
+
+ // pattern (vc - y) / ss * 200000
+ if ((rShapeType == u"ooxml-curvedLeftArrow") || (rShapeType == u"ooxml-curvedRightArrow")
+ || (rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-mathPlus")
+ || (rShapeType == u"ooxml-rightArrowCallout" && nHandleIndex == 0))
+ return (fH / 2.0 - fY) / std::min(fW, fH) * 200000.0;
+
+ // pattern (h - y) / ss * 100000 or (b - y) / ss * 100000
+ if ((rShapeType == u"ooxml-bentUpArrow" && nHandleIndex == 0) || (rShapeType == u"ooxml-corner")
+ || (rShapeType == u"ooxml-curvedDownArrow") || (rShapeType == u"ooxml-downArrow")
+ || (rShapeType == u"ooxml-downArrowCallout" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 2))
+ return (fH - fY) / std::min(fW, fH) * 100000.0;
+
+ // pattern (h - y) / ss * 200000 or (b - y) / ss * 200000
+ if (rShapeType == u"ooxml-leftUpArrow" && nHandleIndex == 0) // - adj2 * 2 outside
+ return (fH - fY) / std::min(fW, fH) * 200000.0;
+
+ // pattern y / ss * 100000 or (y - t) / ss * 100000
+ if ((rShapeType == u"ooxml-bentUpArrow" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-bracePair") || (rShapeType == u"ooxml-bracketPair")
+ || (rShapeType == u"ooxml-can") || (rShapeType == u"ooxml-cube")
+ || (rShapeType == u"ooxml-curvedUpArrow") || (rShapeType == u"ooxml-halfFrame")
+ || (rShapeType == u"ooxml-leftBrace" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-leftBracket") || (rShapeType == u"ooxml-leftRightUpArrow")
+ || (rShapeType == u"ooxml-leftUpArrow" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-mathMultiply") || (rShapeType == u"ooxml-quadArrow")
+ || (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-rightBrace" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-rightBracket") || (rShapeType == u"ooxml-upArrow")
+ || (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-upDownArrow")
+ || (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-verticalScroll"))
+ return fY / std::min(fW, fH) * 100000.0;
+
+ // pattern y / ss * 50000
+ if (rShapeType == u"ooxml-bentArrow")
+ return fY / std::min(fW, fH) * 50000.0;
+
+ // pattern (vc - y) / h * 100000
+ if ((rShapeType == u"ooxml-mathDivide" && nHandleIndex == 1) // -adj1 / 2 - adj3 outside
+ || (rShapeType == u"ooxml-mathEqual" && nHandleIndex == 0) // -adj2 / 2 outside
+ || (rShapeType == u"ooxml-mathNotEqual" && nHandleIndex == 0) // -adj3 / 2 outside
+ || (rShapeType == u"ooxml-star4") || (rShapeType == u"ooxml-star6")
+ || (rShapeType == u"ooxml-star8") || (rShapeType == u"ooxml-star10")
+ || (rShapeType == u"ooxml-star12") || (rShapeType == u"ooxml-star16")
+ || (rShapeType == u"ooxml-star24") || (rShapeType == u"ooxml-star32"))
+ return (fH / 2.0 - fY) / fH * 100000.0;
+
+ // pattern (vc - y) / h * 200000
+ if ((rShapeType == u"ooxml-leftArrow") || (rShapeType == u"ooxml-leftRightArrow")
+ || (rShapeType == u"ooxml-mathDivide" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-mathEqual" && nHandleIndex == 1)
+ || (rShapeType == u"ooxml-mathMinus") || (rShapeType == u"ooxml-notchedRightArrow")
+ || (rShapeType == u"ooxml-mathNotEqual" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 3)
+ || (rShapeType == u"ooxml-rightArrow") || (rShapeType == u"ooxml-stripedRightArrow")
+ || (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 3))
+ return (fH / 2.0 - fY) / fH * 200000.0;
+
+ // pattern (y - vc) / h * 100000
+ if ((rShapeType == u"ooxml-cloudCallout") || (rShapeType == u"ooxml-wedgeEllipseCallout")
+ || (rShapeType == u"ooxml-wedgeRectCallout")
+ || (rShapeType == u"ooxml-wedgeRoundRectCallout"))
+ return (fY - fH / 2.0) / fH * 100000.0;
+
+ // pattern (h - y) / h * 100000 or (b - y) / h * 100000
+ if ((rShapeType == u"ooxml-ellipseRibbon" && nHandleIndex == 2)
+ || (rShapeType == u"ooxml-ellipseRibbon2" && nHandleIndex == 0)
+ || (rShapeType == u"ooxml-ribbon2")
+ || (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 3))
+ return (fH - fY) / fH * 100000.0;
+
+ // special pattern smiley
+ if (rShapeType == u"ooxml-smileyFace")
+ return (fY - fH * 16515.0 / 21600.0) / fH * 100000.0;
+
+ // special pattern for star with odd number of tips, because center of star not center of shape
+ if (rShapeType == u"ooxml-star5")
+ return (fH / 2.0 - fY * 100000.0 / 110557.0) / fH * 100000.0;
+ if (rShapeType == u"ooxml-star7")
+ return (fH / 2.0 - fY * 100000.0 / 105210.0) / fH * 100000.0;
+
+ // special pattern swooshArrow
+ if (rShapeType == u"ooxml-swooshArrow")
+ return (fY - std::min(fW, fH) / 8.0) / fH * 100000.0;
+
+ // special pattern leftRightRibbon
+ if (rShapeType == u"ooxml-leftRightRibbon")
+ return fY / fH * 200000 - 100000;
+
+ // pattern y / h * 100000, simple scaling
+ if (o3tl::starts_with(rShapeType, u"ooxml-"))
+ return fY / fH * 100000.0;
+
+ return fY; // method is unknown
+}
+
+static double lcl_getAngleInOOXMLUnit(double fDY, double fDX)
+{
+ if (fDX != 0.0 || fDY != 0.0)
+ {
+ double fAngleRad(atan2(fDY, fDX));
+ double fAngle = basegfx::rad2deg(fAngleRad);
+ // atan2 returns angle in ]-pi; pi], OOXML preset shapes use [0;360[.
+ if (fAngle < 0.0)
+ fAngle += 360.0;
+ // OOXML uses angle unit 1/60000 degree.
+ fAngle *= 60000.0;
+ return fAngle;
+ }
+ return 0.0; // no angle defined for origin in polar coordinate system
+}
+
+static double lcl_getRadiusDistance(double fWR, double fHR, double fX, double fY)
+{
+ // Get D so, that point (fX|fY) is on the ellipse, that has width fWR-D and
+ // height fHR-D and center in origin.
+ // Get solution of ellipse equation (fX/(fWR-D))^2 + (fY/(fHR-D)^2 = 1 by solving
+ // fX^2*(fHR-D)^2 + fY^2*(fWR-D)^2 - (fWR-D)^2 * (fHR-D)^2 = 0 with Newton-method.
+ if (fX == 0.0)
+ return std::min(fHR - fY, fWR);
+ else if (fY == 0.0)
+ return std::min(fWR - fX, fHR);
+
+ double fD = std::min(fWR, fHR) - std::hypot(fX, fY); // iteration start value
+ sal_uInt8 nIter(0);
+ bool bFound(false);
+ do
+ {
+ ++nIter;
+ const double fOldD(fD);
+ const double fWRmD(fWR - fD);
+ const double fHRmD(fHR - fD);
+ double fNumerator
+ = fX * fX * fHRmD * fHRmD + fY * fY * fWRmD * fWRmD - fWRmD * fWRmD * fHRmD * fHRmD;
+ double fDenominator
+ = 2.0 * (fHRmD * (fWRmD * fWRmD - fX * fX) + fWRmD * (fHRmD * fHRmD - fY * fY));
+ if (fDenominator != 0.0)
+ {
+ fD = fD - fNumerator / fDenominator;
+ bFound = fabs(fOldD - fD) < 1.0E-12;
+ }
+ else
+ fD = fD * 0.9; // new start value
+ } while (nIter < 50 && !bFound);
+ return fD;
+}
+
+bool EnhancedCustomShape2d::SetHandleControllerPosition( const sal_uInt32 nIndex, const css::awt::Point& rPosition )
+{
+ // The method name is misleading. Essentially it calculates the adjustment values from a given
+ // handle position.
+
+ // For ooxml-foo shapes, the way to calculate the adjustment value from the handle position depends on
+ // the type of the shape, therefore need 'Type'.
+ OUString sShapeType("non-primitive"); // default for ODF
+ const SdrCustomShapeGeometryItem& rGeometryItem(mrSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
+ const Any* pAny = rGeometryItem.GetPropertyValueByName("Type");
+ if (pAny)
+ *pAny >>= sShapeType;
+
+ bool bRetValue = false;
+ if ( nIndex < GetHdlCount() )
+ {
+ Handle aHandle;
+ if ( ConvertSequenceToEnhancedCustomShape2dHandle( seqHandles[ nIndex ], aHandle ) )
+ {
+ Point aP( rPosition.X, rPosition.Y );
+ // apply the negative object rotation to the controller position
+
+ aP.Move( -aLogicRect.Left(), -aLogicRect.Top() );
+ if ( bFlipH )
+ aP.setX( aLogicRect.GetWidth() - aP.X() );
+ if ( bFlipV )
+ aP.setY( aLogicRect.GetHeight() - aP.Y() );
+ if ( nRotateAngle )
+ {
+ double a = -toRadians(nRotateAngle);
+ RotatePoint( aP, Point( aLogicRect.GetWidth() / 2, aLogicRect.GetHeight() / 2 ), sin( a ), cos( a ) );
+ }
+ const GeoStat aGeoStat(mrSdrObjCustomShape.GetGeoStat());
+ if ( aGeoStat.nShearAngle )
+ {
+ double nTan = -aGeoStat.mfTanShearAngle;
+ if (bFlipV != bFlipH)
+ nTan = -nTan;
+ ShearPoint( aP, Point( aLogicRect.GetWidth() / 2, aLogicRect.GetHeight() / 2 ), nTan );
+ }
+
+ double fPos1 = aP.X(); //( bFlipH ) ? aLogicRect.GetWidth() - aP.X() : aP.X();
+ double fPos2 = aP.Y(); //( bFlipV ) ? aLogicRect.GetHeight() -aP.Y() : aP.Y();
+ fPos1 = !basegfx::fTools::equalZero(fXScale) ? (fPos1 / fXScale) : SAL_MAX_INT32;
+ fPos2 = !basegfx::fTools::equalZero(fYScale) ? (fPos2 / fYScale) : SAL_MAX_INT32;
+ // revert -nCoordLeft and -nCoordTop aus GetPoint()
+ fPos1 += nCoordLeft;
+ fPos2 += nCoordTop;
+
+ // Used for scaling the adjustment values based on handle positions
+ double fWidth;
+ double fHeight;
+
+ if ( nCoordWidth || nCoordHeight )
+ {
+ fWidth = nCoordWidth;
+ fHeight = nCoordHeight;
+ }
+ else
+ {
+ fWidth = aLogicRect.GetWidth();
+ fHeight = aLogicRect.GetHeight();
+ }
+
+ if ( aHandle.nFlags & HandleFlags::SWITCHED )
+ {
+ if ( aLogicRect.GetHeight() > aLogicRect.GetWidth() )
+ {
+ double fX = fPos1;
+ double fY = fPos2;
+ double fTmp = fWidth;
+ fPos1 = fY;
+ fPos2 = fX;
+ fHeight = fWidth;
+ fWidth = fTmp;
+ }
+ }
+
+ sal_Int32 nFirstAdjustmentValue = -1, nSecondAdjustmentValue = -1;
+
+ // ODF shapes are expected to use a direct binding between position and adjustment
+ // values. OOXML preset shapes use known formulas. These are calculated backward to
+ // get the adjustment values. So far we do not have a general method to calculate
+ // the adjustment values for any shape from the handle position.
+ if ( aHandle.aPosition.First.Type == EnhancedCustomShapeParameterType::ADJUSTMENT )
+ aHandle.aPosition.First.Value >>= nFirstAdjustmentValue;
+ if ( aHandle.aPosition.Second.Type == EnhancedCustomShapeParameterType::ADJUSTMENT )
+ aHandle.aPosition.Second.Value>>= nSecondAdjustmentValue;
+
+ if ( aHandle.nFlags & ( HandleFlags::POLAR | HandleFlags::REFR | HandleFlags::REFANGLE))
+ { // Polar-Handle
+
+ if (aHandle.nFlags & HandleFlags::REFR)
+ nFirstAdjustmentValue = aHandle.nRefR;
+ if (aHandle.nFlags & HandleFlags::REFANGLE)
+ nSecondAdjustmentValue = aHandle.nRefAngle;
+
+ double fAngle(0.0);
+ double fRadius(0.0);
+ // 'then' treats only shapes of type "ooxml-foo", fontwork shapes have been mapped
+ // to MS binary import and will be treated in 'else'.
+ if (bOOXMLShape)
+ {
+ // DrawingML polar handles set REFR or REFANGLE instead of POLAR
+ // use the shape center instead.
+ double fDX = fPos1 - fWidth / 2.0;
+ double fDY = fPos2 - fHeight / 2.0;
+
+ // There exists no common pattern. 'radius' or 'angle' might have special meaning.
+ if (sShapeType == "ooxml-blockArc" && nIndex == 1)
+ {
+ // usual angle, special radius
+ fAngle = lcl_getAngleInOOXMLUnit(fDY, fDX);
+ // The value connected to REFR is the _difference_ between the outer
+ // ellipse given by shape width and height and the inner ellipse through
+ // the handle position.
+ double fRadiusDifference
+ = lcl_getRadiusDistance(fWidth / 2.0, fHeight / 2.0, fDX, fDY);
+ double fss(std::min(fWidth, fHeight));
+ if (fss != 0)
+ fRadius = fRadiusDifference * 100000.0 / fss;
+ }
+ else if (sShapeType == "ooxml-donut" || sShapeType == "ooxml-noSmoking")
+ {
+ // no angle adjustment, radius bound to x-coordinate of handle
+ double fss(std::min(fWidth, fHeight));
+ if (fss != 0.0)
+ fRadius = fPos1 * 100000.0 / fss;
+ }
+ else if ((sShapeType == "ooxml-circularArrow"
+ || sShapeType == "ooxml-leftRightCircularArrow"
+ || sShapeType == "ooxml-leftCircularArrow")
+ && nIndex == 0)
+ {
+ // The value adj2 is the increase compared to the angle in adj3
+ double fHandleAngle = lcl_getAngleInOOXMLUnit(fDY, fDX);
+ if (sShapeType == "ooxml-leftCircularArrow")
+ fAngle = GetAdjustValueAsDouble(2) - fHandleAngle;
+ else
+ fAngle = fHandleAngle - GetAdjustValueAsDouble(2);
+ if (fAngle < 0.0) // 0deg to 360deg cut
+ fAngle += 21600000.0;
+ // no REFR
+ }
+ else if ((sShapeType == "ooxml-circularArrow"
+ || sShapeType == "ooxml-leftCircularArrow"
+ || sShapeType == "ooxml-leftRightCircularArrow")
+ && nIndex == 2)
+ {
+ // The value adj1 connected to REFR is the thickness of the arc. The adjustvalue adj5
+ // has the _difference_ between the outer ellipse given by shape width and height
+ // and the middle ellipse of the arc. The handle is on the outer side of the
+ // arc. So we calculate the difference between the ellipse through the handle
+ // and the outer ellipse and subtract then.
+ double fRadiusDifferenceHandle
+ = lcl_getRadiusDistance(fWidth / 2.0, fHeight / 2.0, fDX, fDY);
+ double fadj5(GetAdjustValueAsDouble(4));
+ double fss(std::min(fWidth, fHeight));
+ if (fss != 0.0)
+ {
+ fadj5 = fadj5 * fss / 100000.0;
+ fRadius = 2.0 * (fadj5 - fRadiusDifferenceHandle);
+ fRadius = fRadius * 100000.0 / fss;
+ }
+ // ToDo: Get angle adj3 exact. Use approximation for now
+ fAngle = lcl_getAngleInOOXMLUnit(fDY, fDX);
+ }
+ else if ((sShapeType == "ooxml-circularArrow"
+ || sShapeType == "ooxml-leftCircularArrow"
+ || sShapeType == "ooxml-leftRightCircularArrow")
+ && nIndex == 3)
+ {
+ // ToDo: Getting handle position from adjustment value adj5 is complex.
+ // Analytical or numerical solution for backward calculation is missing.
+ // Approximation for now, using a line from center through handle position.
+ double fAngleRad(0.0);
+ if (fDX != 0.0 || fDY != 0.0)
+ fAngleRad = atan2(fDY, fDX);
+ double fHelpX = cos(fAngleRad) * fHeight / 2.0;
+ double fHelpY = sin(fAngleRad) * fWidth / 2.0;
+ if (fHelpX != 0.0 || fHelpY != 0.0)
+ {
+ double fHelpAngle = atan2(fHelpY, fHelpX);
+ double fOuterX = fWidth / 2.0 * cos(fHelpAngle);
+ double fOuterY = fHeight / 2.0 * sin(fHelpAngle);
+ double fOuterRadius = std::hypot(fOuterX, fOuterY);
+ double fHandleRadius = std::hypot(fDX, fDY);
+ fRadius = (fOuterRadius - fHandleRadius) / 2.0;
+ double fss(std::min(fWidth, fHeight));
+ if (fss != 0.0)
+ fRadius = fRadius * 100000.0 / fss;
+ }
+ // no REFANGLE
+ }
+ else if (sShapeType == "ooxml-mathNotEqual" && nIndex == 1)
+ {
+ double fadj1(GetAdjustValueAsDouble(0));
+ double fadj3(GetAdjustValueAsDouble(2));
+ fadj1 = fadj1 * fHeight / 100000.0;
+ fadj3 = fadj3 * fHeight / 100000.0;
+ double fDYRefHorizBar = fDY + fadj1 + fadj3;
+ if (fDX != 0.0 || fDYRefHorizBar != 0.0)
+ {
+ double fRawAngleDeg = basegfx::rad2deg(atan2(fDYRefHorizBar, fDX));
+ fAngle = (fRawAngleDeg + 180.0) * 60000.0;
+ }
+ // no REFR
+ }
+ else
+ {
+ // no special meaning of radius or angle, suitable for "ooxml-arc",
+ // "ooxml-chord", "ooxml-pie" and circular arrows value adj4.
+ fAngle = lcl_getAngleInOOXMLUnit(fDY, fDX);
+ fRadius = std::hypot(fDX, fDY);
+ double fss(std::min(fWidth, fHeight));
+ if (fss != 0.0)
+ fRadius = fRadius * 100000.0 / fss;
+ }
+ }
+ else // e.g. shapes from ODF, MS binary import or shape type "fontwork-foo"
+ {
+ double fXRef, fYRef;
+ if (aHandle.nFlags & HandleFlags::POLAR)
+ {
+ GetParameter(fXRef, aHandle.aPolar.First, false, false);
+ GetParameter(fYRef, aHandle.aPolar.Second, false, false);
+ }
+ else
+ {
+ fXRef = fWidth / 2.0;
+ fYRef = fHeight / 2.0;
+ }
+ const double fDX = fPos1 - fXRef;
+ const double fDY = fPos2 - fYRef;
+ // ToDo: MS binary uses fixed-point number for the angle. Make sure conversion
+ // to double is done in import and export.
+ // ToDo: Angle unit is degree, but range ]-180;180] or [0;360[? Assume ]-180;180].
+ if (fDX != 0.0 || fDY != 0.0)
+ {
+ fRadius = std::hypot(fDX, fDY);
+ fAngle = basegfx::rad2deg(atan2(fDY, fDX));
+ }
+ }
+
+ // All formats can restrict the radius to a range
+ if ( aHandle.nFlags & HandleFlags::RADIUS_RANGE_MINIMUM )
+ {
+ double fMin;
+ GetParameter( fMin, aHandle.aRadiusRangeMinimum, false, false );
+ if ( fRadius < fMin )
+ fRadius = fMin;
+ }
+ if ( aHandle.nFlags & HandleFlags::RADIUS_RANGE_MAXIMUM )
+ {
+ double fMax;
+ GetParameter( fMax, aHandle.aRadiusRangeMaximum, false, false );
+ if ( fRadius > fMax )
+ fRadius = fMax;
+ }
+
+ if ( nFirstAdjustmentValue >= 0 )
+ SetAdjustValueAsDouble( fRadius, nFirstAdjustmentValue );
+ if ( nSecondAdjustmentValue >= 0 )
+ SetAdjustValueAsDouble( fAngle, nSecondAdjustmentValue );
+ }
+ else // XY-Handle
+ {
+ // Calculating the adjustment values follows in most cases some patterns, which only
+ // need width and height of the shape and handle position. These patterns are calculated
+ // in the static, local methods. More complex calculations or additional steps are
+ // done here.
+ // Values for corner cases like 'root(negative)' or 'div zero' are meaningless dummies.
+ // Identifiers often refer to guide names in OOXML shape definitions.
+ double fAdjustX = fPos1;
+ double fAdjustY = fPos2;
+ if (aHandle.nFlags & HandleFlags::REFX)
+ {
+ nFirstAdjustmentValue = aHandle.nRefX;
+ if ((sShapeType == "ooxml-gear6") || (sShapeType == "ooxml-gear9"))
+ {
+ // special, needs angle calculations
+ double fss(std::min(fWidth, fHeight));
+ double fadj1(GetAdjustValueAsDouble(0)); // from point D6 or D9
+ double fth(fadj1 * fss / 100000.0); // radius difference
+ double frw(fWidth / 2.0 - fth); // inner ellipse
+ double frh(fHeight / 2.0 - fth);
+ double fDX(fPos1 - fWidth / 2.0);
+ double fDY(fPos2 - fHeight / 2.0);
+ double fbA(-1.7); // effective angle for point A6 or A9, dummy value
+ if (fDX != 0.0 || fDY != 0.0)
+ fbA = atan2(fDY, fDX);
+ double faA(fbA); // corresponding circle angle, dummy value
+ double ftmpX(frh * cos(fbA));
+ double ftmpY(frw * sin(fbA));
+ if (ftmpX != 0.0 || ftmpY != 0.0)
+ faA = atan2(ftmpY, ftmpX); // range ]-pi..pi], here -pi < faA < -pi/2
+ // screen 270 deg = mathematic coordinate system -pi/2
+ double fha(-M_PI_2 - faA); // positive circle angle difference to 270 deg
+ if (abs(fha) == M_PI_2) // should not happen, but ensure no tan(90deg)
+ fha = 0.12; // dummy value
+ double flFD(2 * std::min(frw, frh) * tan(fha) - fth);
+ if (fss != 0.0)
+ fAdjustX = flFD / fss * 100000.0;
+ }
+ else
+ {
+ fAdjustX
+ = lcl_getXAdjustmentValue(sShapeType, nIndex, fPos1, fWidth, fHeight);
+ if ((sShapeType == "ooxml-curvedDownArrow")
+ || (sShapeType == "ooxml-curvedUpArrow"))
+ {
+ double fss(std::min(fWidth, fHeight));
+ if (fss != 0.0)
+ {
+ double fadj3(GetAdjustValueAsDouble(2));
+ double fHScaled(100000.0 * fHeight / fss);
+ double fRadicand(fHScaled * fHScaled - fadj3 * fadj3);
+ double fSqrt = fRadicand >= 0.0 ? sqrt(fRadicand) : 0.0;
+ double fPart(200000.0 * fWidth / fss * (fSqrt + fHScaled));
+ fAdjustX = fPart - 4.0 * fHScaled * fAdjustX;
+ if (nIndex == 0)
+ {
+ // calculate adj1
+ double fadj2(GetAdjustValueAsDouble(1));
+ fAdjustX = fAdjustX - fadj2 * (fSqrt + fHScaled);
+ double fDenominator(fSqrt - 3.0 * fHScaled);
+ fAdjustX /= fDenominator != 0.0 ? fDenominator : 1.0;
+ }
+ else
+ {
+ // nIndex == 1, calculate adj2
+ double fadj1(GetAdjustValueAsDouble(0));
+ fAdjustX = fAdjustX - fadj1 * (fSqrt - fHScaled);
+ double fDenominator(fSqrt + 3.0 * fHScaled);
+ fAdjustX /= fDenominator != 0.0 ? fDenominator : 1.0;
+ }
+ }
+ }
+ }
+ }
+
+ if (aHandle.nFlags & HandleFlags::REFY)
+ {
+ nSecondAdjustmentValue = aHandle.nRefY;
+ if ((sShapeType == "ooxml-gear6") || (sShapeType == "ooxml-gear9"))
+ {
+ // special, acts more like a polar handle radius
+ double fDX = fPos1 - fWidth / 2.0;
+ double fDY = fPos2 - fHeight / 2.0;
+ double fRadiusDifference
+ = lcl_getRadiusDistance(fWidth / 2.0, fHeight / 2.0, fDX, fDY);
+ double fss(std::min(fWidth, fHeight));
+ if (fss != 0)
+ fAdjustY = fRadiusDifference / fss * 100000.0;
+ }
+ else
+ {
+ fAdjustY
+ = lcl_getYAdjustmentValue(sShapeType, nIndex, fPos2, fWidth, fHeight);
+ if (sShapeType == "ooxml-mathDivide" && nIndex == 1)
+ fAdjustY = fAdjustY - GetAdjustValueAsDouble(0) / 2.0
+ - GetAdjustValueAsDouble(2);
+ else if (sShapeType == "ooxml-mathEqual" && nIndex == 0)
+ fAdjustY -= GetAdjustValueAsDouble(1) / 2.0;
+ else if (sShapeType == "ooxml-mathNotEqual" && nIndex == 0)
+ fAdjustY -= GetAdjustValueAsDouble(2) / 2.0;
+ else if (sShapeType == "ooxml-leftUpArrow" && nIndex == 0)
+ fAdjustY -= GetAdjustValueAsDouble(1) * 2.0;
+ else if ((sShapeType == "ooxml-curvedRightArrow")
+ || (sShapeType == "ooxml-curvedLeftArrow"))
+ {
+ double fss(std::min(fWidth, fHeight));
+ if (fss != 0.0)
+ {
+ double fadj3(GetAdjustValueAsDouble(2));
+ double fWScaled(100000.0 * fWidth / fss);
+ double fRadicand(fWScaled * fWScaled - fadj3 * fadj3);
+ double fSqrt = fRadicand >= 0.0 ? sqrt(fRadicand) : 0.0;
+ if (nIndex == 0)
+ {
+ // calculate adj1
+ double fadj2(GetAdjustValueAsDouble(1));
+ fAdjustY = fWScaled * (2.0 * fAdjustY - fadj2);
+ fAdjustY += (200000.0 / fss * fHeight - fadj2) * fSqrt;
+ double fDenominator(fSqrt + fWScaled);
+ fAdjustY /= fDenominator != 0.0 ? fDenominator : 1.0;
+ }
+ else
+ {
+ // nIndex == 1, calculate adj2
+ double fadj1(GetAdjustValueAsDouble(0));
+ fAdjustY = fWScaled * (2.0 * fAdjustY + fadj1);
+ fAdjustY += (200000.0 / fss * fHeight - fadj1) * fSqrt;
+ double fDenominator(fSqrt + 3.0 * fWScaled);
+ fAdjustY /= fDenominator != 0.0 ? fDenominator : 1.0;
+ }
+ }
+ }
+ else if (sShapeType == "ooxml-uturnArrow" && nIndex == 2)
+ {
+ double fss(std::min(fWidth, fHeight));
+ if (fss != 0.0)
+ {
+ double fadj5(GetAdjustValueAsDouble(4));
+ fAdjustY += fHeight / fss * (fadj5 - 100000.0);
+ }
+ }
+ else if (sShapeType == "ooxml-leftRightRibbon")
+ {
+ if (nIndex == 0)
+ fAdjustY = GetAdjustValueAsDouble(2) - fAdjustY;
+ else // nIndex == 2
+ fAdjustY = GetAdjustValueAsDouble(0) + fAdjustY;
+ }
+ }
+ }
+
+ if ( nFirstAdjustmentValue >= 0 )
+ {
+ if ( aHandle.nFlags & HandleFlags::RANGE_X_MINIMUM ) // check if horizontal handle needs to be within a range
+ {
+ double fXMin;
+ GetParameter( fXMin, aHandle.aXRangeMinimum, false, false );
+ if (fAdjustX < fXMin)
+ fAdjustX = fXMin;
+ }
+ if ( aHandle.nFlags & HandleFlags::RANGE_X_MAXIMUM ) // check if horizontal handle needs to be within a range
+ {
+ double fXMax;
+ GetParameter( fXMax, aHandle.aXRangeMaximum, false, false );
+ if (fAdjustX > fXMax)
+ fAdjustX = fXMax;
+ }
+ SetAdjustValueAsDouble(fAdjustX, nFirstAdjustmentValue);
+ }
+ if ( nSecondAdjustmentValue >= 0 )
+ {
+ if ( aHandle.nFlags & HandleFlags::RANGE_Y_MINIMUM ) // check if vertical handle needs to be within a range
+ {
+ double fYMin;
+ GetParameter( fYMin, aHandle.aYRangeMinimum, false, false );
+ if (fAdjustY < fYMin)
+ fAdjustY = fYMin;
+ }
+ if ( aHandle.nFlags & HandleFlags::RANGE_Y_MAXIMUM ) // check if vertical handle needs to be within a range
+ {
+ double fYMax;
+ GetParameter( fYMax, aHandle.aYRangeMaximum, false, false );
+ if (fAdjustY > fYMax)
+ fAdjustY = fYMax;
+ }
+ SetAdjustValueAsDouble(fAdjustY, nSecondAdjustmentValue);
+ }
+ }
+ // and writing them back into the GeometryItem
+ SdrCustomShapeGeometryItem aGeometryItem(mrSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
+ css::beans::PropertyValue aPropVal;
+ aPropVal.Name = "AdjustmentValues";
+ aPropVal.Value <<= seqAdjustmentValues;
+ aGeometryItem.SetPropertyValue( aPropVal );
+ mrSdrObjCustomShape.SetMergedItem( aGeometryItem );
+ bRetValue = true;
+ }
+ }
+ return bRetValue;
+}
+
+void EnhancedCustomShape2d::SwapStartAndEndArrow( SdrObject* pObj ) //#108274
+{
+ XLineStartItem aLineStart;
+ aLineStart.SetLineStartValue(pObj->GetMergedItem( XATTR_LINEEND ).GetLineEndValue());
+ XLineStartWidthItem aLineStartWidth(pObj->GetMergedItem( XATTR_LINEENDWIDTH ).GetValue());
+ XLineStartCenterItem aLineStartCenter(pObj->GetMergedItem( XATTR_LINEENDCENTER ).GetValue());
+
+ XLineEndItem aLineEnd;
+ aLineEnd.SetLineEndValue(pObj->GetMergedItem( XATTR_LINESTART ).GetLineStartValue());
+ XLineEndWidthItem aLineEndWidth(pObj->GetMergedItem( XATTR_LINESTARTWIDTH ).GetValue());
+ XLineEndCenterItem aLineEndCenter(pObj->GetMergedItem( XATTR_LINESTARTCENTER ).GetValue());
+
+ pObj->SetMergedItem( aLineStart );
+ pObj->SetMergedItem( aLineStartWidth );
+ pObj->SetMergedItem( aLineStartCenter );
+ pObj->SetMergedItem( aLineEnd );
+ pObj->SetMergedItem( aLineEndWidth );
+ pObj->SetMergedItem( aLineEndCenter );
+}
+
+static basegfx::B2DPolygon CreateArc( const tools::Rectangle& rRect, const Point& rStart, const Point& rEnd, const bool bClockwise )
+{
+ tools::Rectangle aRect( rRect );
+ Point aStart( rStart );
+ Point aEnd( rEnd );
+
+ sal_Int32 bSwapStartEndAngle = 0;
+
+ if ( aRect.Left() > aRect.Right() )
+ bSwapStartEndAngle ^= 0x01;
+ if ( aRect.Top() > aRect.Bottom() )
+ bSwapStartEndAngle ^= 0x11;
+ if ( bSwapStartEndAngle )
+ {
+ aRect.Justify();
+ if ( bSwapStartEndAngle & 1 )
+ {
+ Point aTmp( aStart );
+ aStart = aEnd;
+ aEnd = aTmp;
+ }
+ }
+
+ tools::Polygon aTempPoly( aRect, aStart, aEnd, PolyStyle::Arc );
+ basegfx::B2DPolygon aRetval;
+
+ if ( bClockwise )
+ {
+ for ( sal_uInt16 j = aTempPoly.GetSize(); j--; )
+ {
+ aRetval.append(basegfx::B2DPoint(aTempPoly[ j ].X(), aTempPoly[ j ].Y()));
+ }
+ }
+ else
+ {
+ for ( sal_uInt16 j = 0; j < aTempPoly.GetSize(); j++ )
+ {
+ aRetval.append(basegfx::B2DPoint(aTempPoly[ j ].X(), aTempPoly[ j ].Y()));
+ }
+ }
+
+ return aRetval;
+}
+
+static double lcl_getNormalizedCircleAngleRad(const double fWR, const double fHR, const double fEllipseAngleDeg)
+{
+ double fRet(0.0);
+ double fEAngleDeg(fmod(fEllipseAngleDeg, 360.0));
+ if (fEAngleDeg < 0.0)
+ fEAngleDeg += 360.0;
+ if (fEAngleDeg == 0.0 || fEAngleDeg == 90.0 || fEAngleDeg == 180.0 || fEAngleDeg == 270.0)
+ return basegfx::deg2rad(fEAngleDeg);
+ const double fX(fHR * cos(basegfx::deg2rad(fEAngleDeg)));
+ const double fY(fWR * sin(basegfx::deg2rad(fEAngleDeg)));
+ if (fX != 0.0 || fY != 0.0)
+ {
+ fRet = atan2(fY, fX);
+ if (fRet < 0.0)
+ fRet += 2 * M_PI;
+ }
+ return fRet;
+}
+
+static double lcl_getNormalizedAngleRad(const double fCircleAngleDeg)
+{
+ double fRet(fmod(fCircleAngleDeg, 360.0));
+ if (fRet < 0.0)
+ fRet += 360.0;
+ return basegfx::deg2rad(fRet);
+}
+
+void EnhancedCustomShape2d::CreateSubPath(
+ sal_Int32& rSrcPt,
+ sal_Int32& rSegmentInd,
+ std::vector< std::pair< SdrPathObjUniquePtr, double> >& rObjectList,
+ const bool bLineGeometryNeededOnly,
+ const bool bSortFilledObjectsToBack,
+ sal_Int32 nIndex)
+{
+ bool bNoFill = false;
+ bool bNoStroke = false;
+ double dBrightness = 0.0; //no blending
+
+ basegfx::B2DPolyPolygon aNewB2DPolyPolygon;
+ basegfx::B2DPolygon aNewB2DPolygon;
+
+ SetPathSize( nIndex );
+
+ sal_Int32 nSegInfoSize = seqSegments.getLength();
+ if ( !nSegInfoSize )
+ {
+ for ( const EnhancedCustomShapeParameterPair& rCoordinate : std::as_const(seqCoordinates) )
+ {
+ const Point aTempPoint(GetPoint( rCoordinate, true, true ));
+ aNewB2DPolygon.append(basegfx::B2DPoint(aTempPoint.X(), aTempPoint.Y()));
+ }
+
+ aNewB2DPolygon.setClosed(true);
+ }
+ else
+ {
+ sal_Int32 nCoordSize = seqCoordinates.getLength();
+ for ( ;rSegmentInd < nSegInfoSize; )
+ {
+ sal_Int16 nCommand = seqSegments[ rSegmentInd ].Command;
+ sal_Int16 nPntCount= seqSegments[ rSegmentInd++ ].Count;
+
+ switch ( nCommand )
+ {
+ case NOFILL :
+ bNoFill = true;
+ break;
+ case NOSTROKE :
+ bNoStroke = true;
+ break;
+ case DARKEN :
+ dBrightness = -0.4; //use sign to distinguish DARKEN from LIGHTEN
+ break;
+ case DARKENLESS :
+ dBrightness = -0.2;
+ break;
+ case LIGHTEN :
+ dBrightness = 0.4;
+ break;
+ case LIGHTENLESS :
+ dBrightness = 0.2;
+ break;
+ case MOVETO :
+ {
+ if(aNewB2DPolygon.count() > 1)
+ {
+ // #i76201# Add conversion to closed polygon when first and last points are equal
+ basegfx::utils::checkClosed(aNewB2DPolygon);
+ aNewB2DPolyPolygon.append(aNewB2DPolygon);
+ }
+
+ aNewB2DPolygon.clear();
+
+ if ( rSrcPt < nCoordSize )
+ {
+ const Point aTempPoint(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
+ SAL_INFO(
+ "svx",
+ "moveTo: " << aTempPoint.X() << ","
+ << aTempPoint.Y());
+ aNewB2DPolygon.append(basegfx::B2DPoint(aTempPoint.X(), aTempPoint.Y()));
+ }
+ }
+ break;
+ case ENDSUBPATH :
+ break;
+ case CLOSESUBPATH :
+ {
+ if(aNewB2DPolygon.count())
+ {
+ if(aNewB2DPolygon.count() > 1)
+ {
+ aNewB2DPolygon.setClosed(true);
+ aNewB2DPolyPolygon.append(aNewB2DPolygon);
+ }
+
+ aNewB2DPolygon.clear();
+ }
+ }
+ break;
+ case CURVETO :
+ {
+ for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( ( rSrcPt + 2 ) < nCoordSize ); i++ )
+ {
+ const Point aControlA(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
+ const Point aControlB(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
+ const Point aEnd(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
+
+ DBG_ASSERT(aNewB2DPolygon.count(), "EnhancedCustomShape2d::CreateSubPath: Error in adding control point (!)");
+ aNewB2DPolygon.appendBezierSegment(
+ basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
+ basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
+ basegfx::B2DPoint(aEnd.X(), aEnd.Y()));
+ }
+ }
+ break;
+
+ case ANGLEELLIPSE: // command U
+ case ANGLEELLIPSETO: // command T
+ {
+ // Some shapes will need special handling, decide on property 'Type'.
+ OUString sShpType;
+ SdrCustomShapeGeometryItem& rGeometryItem = const_cast<SdrCustomShapeGeometryItem&>(mrSdrObjCustomShape.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY));
+ Any* pAny = rGeometryItem.GetPropertyValueByName("Type");
+ if (pAny)
+ *pAny >>= sShpType;
+ // User defined shapes in MS binary format, which contain command U or T after import
+ // in LibreOffice, starts with "mso".
+ const bool bIsFromBinaryImport(sShpType.startsWith("mso"));
+ // The only own or imported preset shapes with U command are those listed below.
+ // Command T is not used in preset shapes.
+ const std::unordered_set<OUString> aPresetShapesWithU =
+ { "ellipse", "ring", "smiley", "sun", "forbidden", "flowchart-connector",
+ "flowchart-summing-junction", "flowchart-or", "cloud-callout"};
+ std::unordered_set<OUString>::const_iterator aIter = aPresetShapesWithU.find(sShpType);
+ const bool bIsPresetShapeWithU(aIter != aPresetShapesWithU.end());
+
+ for (sal_uInt16 i = 0; (i < nPntCount) && ((rSrcPt + 2) < nCoordSize); i++)
+ {
+ // ANGLEELLIPSE is the same as ANGLEELLIPSETO, only that it
+ // makes an implicit MOVETO. That ends the previous subpath.
+ if (ANGLEELLIPSE == nCommand)
+ {
+ if (aNewB2DPolygon.count() > 1)
+ {
+ // #i76201# Add conversion to closed polygon when first and last points are equal
+ basegfx::utils::checkClosed(aNewB2DPolygon);
+ aNewB2DPolyPolygon.append(aNewB2DPolygon);
+ }
+ aNewB2DPolygon.clear();
+ }
+
+ // Read all parameters, but do not finally handle them.
+ basegfx::B2DPoint aCenter(GetPointAsB2DPoint(seqCoordinates[ rSrcPt ], true, true));
+ double fWR; // horizontal ellipse radius
+ double fHR; // vertical ellipse radius
+ GetParameter(fWR, seqCoordinates[rSrcPt + 1].First, true, false);
+ GetParameter(fHR, seqCoordinates[rSrcPt + 1].Second, false, true);
+ double fStartAngle;
+ GetParameter(fStartAngle, seqCoordinates[rSrcPt + 2].First, false, false);
+ double fEndAngle;
+ GetParameter(fEndAngle, seqCoordinates[rSrcPt + 2].Second, false, false);
+ // Increasing here allows flat case differentiation tree by using 'continue'.
+ rSrcPt += 3;
+
+ double fScaledWR(fWR * fXScale);
+ double fScaledHR(fHR * fYScale);
+ if (fScaledWR == 0.0 && fScaledHR == 0.0)
+ {
+ // degenerated ellipse, add center point
+ aNewB2DPolygon.append(aCenter);
+ continue;
+ }
+
+ if (bIsFromBinaryImport)
+ {
+ // If a shape comes from MS binary ('escher') import, the angles are in degrees*2^16
+ // and the second angle is not an end angle, but a swing angle.
+ // MS Word shows this behavior: 0deg right, 90deg top, 180deg left and 270deg
+ // bottom. Third and forth parameter are horizontal and vertical radius, not width
+ // and height as noted in VML spec. A positive swing angle goes counter-clock
+ // wise (in user view). The swing angle might go several times around in case
+ // abs(swing angle) >= 360deg. Stroke accumulates, so that e.g. dash-dot might fill the
+ // gaps of previous turn. Fill does not accumulate but uses even-odd rule, semi-transparent
+ // fill does not become darker. The start and end points of the arc are calculated by
+ // using the angles on a circle and then scaling the circle to the ellipse. Caution, that
+ // is different from angle handling in ARCANGLETO and ODF.
+ // The following implementation generates such rendering. It is only for rendering legacy
+ // MS shapes and independent of the meaning of commands U and T in ODF specification.
+
+ // The WordArt shape 'RingOutside' has already angles in degree, all other need
+ // conversion from fixed-point number.
+ double fSwingAngle = fEndAngle;
+ if (sShpType != "mso-spt143")
+ {
+ fStartAngle /= 65536.0;
+ fSwingAngle = fEndAngle / 65536.0;
+ }
+ // Convert orientation
+ fStartAngle = -fStartAngle;
+ fSwingAngle = -fSwingAngle;
+
+ fEndAngle = fStartAngle + fSwingAngle;
+ if (fSwingAngle < 0.0)
+ std::swap(fStartAngle, fEndAngle);
+ double fFrom(fStartAngle);
+ double fTo(fFrom + 180.0);
+ basegfx::B2DPolygon aTempB2DPolygon;
+ double fS; // fFrom in radians in [0..2Pi[
+ double fE; // fTo or fEndAngle in radians in [0..2PI[
+ while (fTo < fEndAngle)
+ {
+ fS = lcl_getNormalizedAngleRad(fFrom);
+ fE = lcl_getNormalizedAngleRad(fTo);
+ aTempB2DPolygon.append(basegfx::utils::createPolygonFromEllipseSegment(aCenter, fScaledWR, fScaledHR, fS,fE));
+ fFrom = fTo;
+ fTo += 180.0;
+ }
+ fS = lcl_getNormalizedAngleRad(fFrom);
+ fE = lcl_getNormalizedAngleRad(fEndAngle);
+ aTempB2DPolygon.append(basegfx::utils::createPolygonFromEllipseSegment(aCenter, fScaledWR, fScaledHR,fS, fE));
+ if (fSwingAngle < 0)
+ aTempB2DPolygon.flip();
+ aNewB2DPolygon.append(aTempB2DPolygon);
+ continue;
+ }
+
+ // The not yet handled shapes are own preset shapes, or preset shapes from MS binary import, or user
+ // defined shapes, or foreign shapes. Shapes from OOXML import do not use ANGLEELLIPSE or
+ // ANGLEELLIPSETO, but use ARCANGLETO.
+ if (bIsPresetShapeWithU)
+ {
+ // Besides "cloud-callout" all preset shapes have angle values '0 360'.
+ // The imported "cloud-callout" has angle values '0 360' too, only our own "cloud-callout"
+ // has values '0 23592960'. But that is fixedfloat and means 360*2^16. Thus all these shapes
+ // have a full ellipse with start at 0deg.
+ aNewB2DPolygon.append(basegfx::utils::createPolygonFromEllipse(aCenter, fScaledWR, fScaledHR));
+ continue;
+ }
+
+ // In all other cases, full ODF conform handling is necessary. ODF rules:
+ // Third and forth parameter are horizontal and vertical radius.
+ // An angle determines the start or end point of the segment by intersection of the second angle
+ // leg with the ellipse. The first angle leg is always the positive x-axis. For the position
+ // of the intersection points the angle is used modulo 360deg in range [0deg..360deg[.
+ // The position of range [0deg..360deg[ is the same as in command ARCANGLETO, with 0deg right,
+ // 90deg bottom, 180deg left and 270deg top. Only if abs(end angle - start angle) == 360 deg,
+ // a full ellipse is drawn. The segment is always drawn clock wise (in user view) from start
+ // point to end point. The end point of the segment becomes the new "current" point.
+
+ if (fabs(fabs(fEndAngle - fStartAngle) - 360.0) < 1.0E-15)
+ {
+ // draw full ellipse
+ // Because createPolygonFromEllipseSegment cannot create full ellipse and
+ // createPolygonFromEllipse has no varying starts, we use two half ellipses.
+ const double fS(lcl_getNormalizedCircleAngleRad(fWR, fHR, fStartAngle));
+ const double fH(lcl_getNormalizedCircleAngleRad(fWR, fHR, fStartAngle + 180.0));
+ const double fE(lcl_getNormalizedCircleAngleRad(fWR, fHR, fEndAngle));
+ aNewB2DPolygon.append(basegfx::utils::createPolygonFromEllipseSegment(aCenter, fScaledWR, fScaledHR, fS, fH));
+ aNewB2DPolygon.append(basegfx::utils::createPolygonFromEllipseSegment(aCenter, fScaledWR, fScaledHR, fH, fE));
+ continue;
+ }
+
+ // remaining cases with central segment angle < 360
+ double fS(lcl_getNormalizedCircleAngleRad(fWR, fHR, fStartAngle));
+ double fE(lcl_getNormalizedCircleAngleRad(fWR, fHR, fEndAngle));
+ aNewB2DPolygon.append(basegfx::utils::createPolygonFromEllipseSegment(aCenter, fScaledWR, fScaledHR, fS, fE));
+ } // end for
+ } // end case
+ break;
+
+ case QUADRATICCURVETO :
+ {
+ for ( sal_Int32 i(0); ( i < nPntCount ) && ( rSrcPt + 1 < nCoordSize ); i++ )
+ {
+ DBG_ASSERT(aNewB2DPolygon.count(), "EnhancedCustomShape2d::CreateSubPath: Error no previous point for Q (!)");
+ if (aNewB2DPolygon.count() > 0)
+ {
+ const basegfx::B2DPoint aPreviousEndPoint(aNewB2DPolygon.getB2DPoint(aNewB2DPolygon.count()-1));
+ const basegfx::B2DPoint aControlQ(GetPointAsB2DPoint( seqCoordinates[ rSrcPt++ ], true, true ));
+ const basegfx::B2DPoint aEnd(GetPointAsB2DPoint( seqCoordinates[ rSrcPt++ ], true, true ));
+ const basegfx::B2DPoint aControlA((aPreviousEndPoint + (aControlQ * 2)) / 3);
+ const basegfx::B2DPoint aControlB(((aControlQ * 2) + aEnd) / 3);
+ aNewB2DPolygon.appendBezierSegment(aControlA, aControlB, aEnd);
+ }
+ else // no previous point; ill structured path, but try to draw as much as possible
+ {
+ rSrcPt++; // skip control point
+ const basegfx::B2DPoint aEnd(GetPointAsB2DPoint( seqCoordinates[ rSrcPt++ ], true, true ));
+ aNewB2DPolygon.append(aEnd);
+ }
+ }
+ }
+ break;
+
+ case LINETO :
+ {
+ for ( sal_Int32 i(0); ( i < nPntCount ) && ( rSrcPt < nCoordSize ); i++ )
+ {
+ const Point aTempPoint(GetPoint( seqCoordinates[ rSrcPt++ ], true, true ));
+ SAL_INFO(
+ "svx",
+ "lineTo: " << aTempPoint.X() << ","
+ << aTempPoint.Y());
+ aNewB2DPolygon.append(basegfx::B2DPoint(aTempPoint.X(), aTempPoint.Y()));
+ }
+ }
+ break;
+
+ case ARC :
+ case CLOCKWISEARC :
+ case ARCTO :
+ case CLOCKWISEARCTO :
+ {
+ bool bClockwise = ( nCommand == CLOCKWISEARC ) || ( nCommand == CLOCKWISEARCTO );
+ bool bImplicitMoveTo = (nCommand == ARC) || (nCommand == CLOCKWISEARC);
+ sal_uInt32 nXor = bClockwise ? 3 : 2;
+ for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( ( rSrcPt + 3 ) < nCoordSize ); i++ )
+ {
+ if (bImplicitMoveTo)
+ {
+ if (aNewB2DPolygon.count() > 1)
+ {
+ // #i76201# Add conversion to closed polygon when first and last
+ // points are equal
+ basegfx::utils::checkClosed(aNewB2DPolygon);
+ aNewB2DPolyPolygon.append(aNewB2DPolygon);
+ }
+ aNewB2DPolygon.clear();
+ }
+ tools::Rectangle aRect = tools::Rectangle::Justify( GetPoint( seqCoordinates[ rSrcPt ], true, true ), GetPoint( seqCoordinates[ rSrcPt + 1 ], true, true ) );
+ if ( aRect.GetWidth() && aRect.GetHeight() )
+ {
+ Point aStart( GetPoint( seqCoordinates[ static_cast<sal_uInt16>( rSrcPt + nXor ) ], true, true ) );
+ Point aEnd( GetPoint( seqCoordinates[ static_cast<sal_uInt16>( rSrcPt + ( nXor ^ 1 ) ) ], true, true ) );
+ aNewB2DPolygon.append(CreateArc( aRect, aStart, aEnd, bClockwise));
+ }
+ rSrcPt += 4;
+ }
+ }
+ break;
+
+ case ARCANGLETO :
+ {
+ double fWR, fHR; // in Shape coordinate system
+ double fStartAngle, fSwingAngle; // in deg
+
+ for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( rSrcPt + 1 < nCoordSize ); i++ )
+ {
+ basegfx::B2DPoint aTempPair;
+ aTempPair = GetPointAsB2DPoint(seqCoordinates[static_cast<sal_uInt16>(rSrcPt)], false /*bScale*/, false /*bReplaceGeoSize*/);
+ fWR = aTempPair.getX();
+ fHR = aTempPair.getY();
+ aTempPair = GetPointAsB2DPoint(seqCoordinates[static_cast<sal_uInt16>(rSrcPt + 1)], false /*bScale*/, false /*bReplaceGeoSize*/);
+ fStartAngle = aTempPair.getX();
+ fSwingAngle = aTempPair.getY();
+
+ // tdf#122323 MS Office clamps the swing angle to [-360,360]. Such restriction
+ // is neither in OOXML nor in ODF. Nevertheless, to be compatible we do it for
+ // "ooxml-foo" shapes. Those shapes have their origin in MS Office.
+ if (bOOXMLShape)
+ {
+ fSwingAngle = std::clamp(fSwingAngle, -360.0, 360.0);
+ }
+
+ SAL_INFO("svx", "ARCANGLETO scale: " << fWR << "x" << fHR << " angles: " << fStartAngle << "," << fSwingAngle);
+
+ if (aNewB2DPolygon.count() > 0) // otherwise no "current point"
+ {
+ // use similar methods as in command U
+ basegfx::B2DPolygon aTempB2DPolygon;
+
+ if (fWR == 0.0 && fHR == 0.0)
+ {
+ // degenerated ellipse, add this one point
+ aTempB2DPolygon.append(basegfx::B2DPoint(0.0, 0.0));
+ }
+ else
+ {
+ double fEndAngle = fStartAngle + fSwingAngle;
+ // Generate arc with ellipse left|top = 0|0.
+ basegfx::B2DPoint aCenter(fWR, fHR);
+ if (fSwingAngle < 0.0)
+ std::swap(fStartAngle, fEndAngle);
+ double fS; // fFrom in radians in [0..2Pi[
+ double fE; // fTo or fEndAngle in radians in [0..2PI[
+ double fFrom(fStartAngle);
+ // createPolygonFromEllipseSegment expects angles in [0..2PI[.
+ if (fSwingAngle >= 360.0 || fSwingAngle <= -360.0)
+ {
+ double fTo(fFrom + 180.0);
+ while (fTo < fEndAngle)
+ {
+ fS = lcl_getNormalizedCircleAngleRad(fWR, fHR, fFrom);
+ fE = lcl_getNormalizedCircleAngleRad(fWR, fHR, fTo);
+ aTempB2DPolygon.append(basegfx::utils::createPolygonFromEllipseSegment(aCenter, fWR, fHR, fS,fE));
+ fFrom = fTo;
+ fTo += 180.0;
+ }
+ }
+ fS = lcl_getNormalizedCircleAngleRad(fWR, fHR, fFrom);
+ fE = lcl_getNormalizedCircleAngleRad(fWR, fHR, fEndAngle);
+ aTempB2DPolygon.append(basegfx::utils::createPolygonFromEllipseSegment(aCenter, fWR, fHR,fS, fE));
+ if (fSwingAngle < 0)
+ aTempB2DPolygon.flip();
+ aTempB2DPolygon.removeDoublePoints();
+ }
+ // Scale arc to 1/100mm
+ basegfx::B2DHomMatrix aMatrix = basegfx::utils::createScaleB2DHomMatrix(fXScale, fYScale);
+ aTempB2DPolygon.transform(aMatrix);
+
+ // Now that we have the arc, move it to the "current point".
+ basegfx::B2DPoint aCurrentPointB2D( aNewB2DPolygon.getB2DPoint(aNewB2DPolygon.count() - 1 ) );
+ const double fDx(aCurrentPointB2D.getX() - aTempB2DPolygon.getB2DPoint(0).getX());
+ const double fDy(aCurrentPointB2D.getY() - aTempB2DPolygon.getB2DPoint(0).getY());
+ aMatrix = basegfx::utils::createTranslateB2DHomMatrix(fDx, fDy);
+ aTempB2DPolygon.transform(aMatrix);
+ aNewB2DPolygon.append(aTempB2DPolygon);
+ }
+
+ rSrcPt += 2;
+ }
+ }
+ break;
+
+ case ELLIPTICALQUADRANTX :
+ case ELLIPTICALQUADRANTY :
+ {
+ if (nPntCount && (rSrcPt < nCoordSize))
+ {
+ // The arc starts at the previous point and ends at the point given in the parameter.
+ basegfx::B2DPoint aStart;
+ basegfx::B2DPoint aEnd;
+ sal_uInt16 i = 0;
+ if (rSrcPt)
+ {
+ aStart = GetPointAsB2DPoint(seqCoordinates[rSrcPt - 1], true, true);
+ }
+ else
+ { // no previous point, path is ill-structured. But we want to show as much as possible.
+ // Thus make a moveTo to the point given as parameter and continue from there.
+ aStart = GetPointAsB2DPoint(seqCoordinates[static_cast<sal_uInt16>(rSrcPt)], true, true);
+ aNewB2DPolygon.append(aStart);
+ rSrcPt++;
+ i++;
+ }
+ // If there are several points, then the direction changes with every point.
+ bool bIsXDirection(nCommand == ELLIPTICALQUADRANTX);
+ basegfx::B2DPolygon aArc;
+ for ( ; ( i < nPntCount ) && ( rSrcPt < nCoordSize ); i++ )
+ {
+ aEnd = GetPointAsB2DPoint(seqCoordinates[rSrcPt], true, true);
+ basegfx::B2DPoint aCenter;
+ double fRadiusX = fabs(aEnd.getX() - aStart.getX());
+ double fRadiusY = fabs(aEnd.getY() - aStart.getY());
+ if (bIsXDirection)
+ {
+ aCenter = basegfx::B2DPoint(aStart.getX(),aEnd.getY());
+ if (aEnd.getX()<aStart.getX())
+ {
+ if (aEnd.getY()<aStart.getY()) // left, up
+ {
+ aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, M_PI_2, M_PI);
+ }
+ else // left, down
+ {
+ aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, M_PI, 1.5*M_PI);
+ aArc.flip();
+ }
+ }
+ else // aEnd.getX()>=aStart.getX()
+ {
+ if (aEnd.getY()<aStart.getY()) // right, up
+ {
+ aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, 0.0, M_PI_2);
+ aArc.flip();
+ }
+ else // right, down
+ {
+ aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, 1.5*M_PI, 2*M_PI);
+ }
+ }
+ }
+ else // y-direction
+ {
+ aCenter = basegfx::B2DPoint(aEnd.getX(),aStart.getY());
+ if (aEnd.getX()<aStart.getX())
+ {
+ if (aEnd.getY()<aStart.getY()) // up, left
+ {
+ aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, 1.5*M_PI, 2*M_PI);
+ aArc.flip();
+ }
+ else // down, left
+ {
+ aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, 0.0, M_PI_2);
+ }
+ }
+ else // aEnd.getX()>=aStart.getX()
+ {
+ if (aEnd.getY()<aStart.getY()) // up, right
+ {
+ aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, M_PI, 1.5*M_PI);
+ }
+ else // down, right
+ {
+ aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, M_PI_2, M_PI);
+ aArc.flip();
+ }
+ }
+ }
+ aNewB2DPolygon.append(aArc);
+ rSrcPt++;
+ bIsXDirection = !bIsXDirection;
+ aStart = aEnd;
+ }
+ }
+ // else error in path syntax, do nothing
+ }
+ break;
+
+#ifdef DBG_CUSTOMSHAPE
+ case UNKNOWN :
+ default :
+ {
+ SAL_WARN( "svx", "CustomShapes::unknown PolyFlagValue :" << nCommand );
+ }
+ break;
+#endif
+ }
+ if ( nCommand == ENDSUBPATH )
+ break;
+ }
+ }
+ if ( rSegmentInd == nSegInfoSize )
+ rSegmentInd++;
+
+ if(aNewB2DPolygon.count() > 1)
+ {
+ // #i76201# Add conversion to closed polygon when first and last points are equal
+ basegfx::utils::checkClosed(aNewB2DPolygon);
+ aNewB2DPolyPolygon.append(aNewB2DPolygon);
+ }
+
+ if(!aNewB2DPolyPolygon.count())
+ return;
+
+ // #i37011#
+ bool bForceCreateTwoObjects(false);
+
+ if(!bSortFilledObjectsToBack && !aNewB2DPolyPolygon.isClosed() && !bNoStroke)
+ {
+ bForceCreateTwoObjects = true;
+ }
+
+ if(bLineGeometryNeededOnly)
+ {
+ bForceCreateTwoObjects = true;
+ bNoFill = true;
+ bNoStroke = false;
+ }
+
+ if(bForceCreateTwoObjects || bSortFilledObjectsToBack)
+ {
+ if(bFilled && !bNoFill)
+ {
+ basegfx::B2DPolyPolygon aClosedPolyPolygon(aNewB2DPolyPolygon);
+ aClosedPolyPolygon.setClosed(true);
+ SdrPathObjUniquePtr pFill(new SdrPathObj(
+ mrSdrObjCustomShape.getSdrModelFromSdrObject(),
+ SdrObjKind::Polygon,
+ aClosedPolyPolygon));
+ SfxItemSet aTempSet(*this);
+ aTempSet.Put(makeSdrShadowItem(false));
+ aTempSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ pFill->SetMergedItemSet(aTempSet);
+ rObjectList.push_back(std::pair< SdrPathObjUniquePtr, double >(std::move(pFill), dBrightness));
+ }
+
+ if(!bNoStroke)
+ {
+ // there is no reason to use OBJ_PLIN here when the polygon is actually closed,
+ // the non-fill is defined by XFILL_NONE. Since SdrPathObj::ImpForceKind() needs
+ // to correct the polygon (here: open it) using the type, the last edge may get lost.
+ // Thus, use a type that fits the polygon
+ SdrPathObjUniquePtr pStroke(new SdrPathObj(
+ mrSdrObjCustomShape.getSdrModelFromSdrObject(),
+ aNewB2DPolyPolygon.isClosed() ? SdrObjKind::Polygon : SdrObjKind::PolyLine,
+ aNewB2DPolyPolygon));
+ SfxItemSet aTempSet(*this);
+ aTempSet.Put(makeSdrShadowItem(false));
+ aTempSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ pStroke->SetMergedItemSet(aTempSet);
+ rObjectList.push_back(std::pair< SdrPathObjUniquePtr, double >(std::move(pStroke), dBrightness));
+ }
+ }
+ else
+ {
+ SdrPathObjUniquePtr pObj;
+ SfxItemSet aTempSet(*this);
+ aTempSet.Put(makeSdrShadowItem(false));
+
+ if(bNoFill)
+ {
+ // see comment above about OBJ_PLIN
+ pObj.reset(new SdrPathObj(
+ mrSdrObjCustomShape.getSdrModelFromSdrObject(),
+ aNewB2DPolyPolygon.isClosed() ? SdrObjKind::Polygon : SdrObjKind::PolyLine,
+ aNewB2DPolyPolygon));
+ aTempSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ else
+ {
+ aNewB2DPolyPolygon.setClosed(true);
+ pObj.reset(new SdrPathObj(
+ mrSdrObjCustomShape.getSdrModelFromSdrObject(),
+ SdrObjKind::Polygon,
+ aNewB2DPolyPolygon));
+ }
+
+ if(bNoStroke)
+ {
+ aTempSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ }
+
+ pObj->SetMergedItemSet(aTempSet);
+ rObjectList.push_back(std::pair< SdrPathObjUniquePtr, double >(std::move(pObj), dBrightness));
+ }
+}
+
+static void CorrectCalloutArrows(
+ MSO_SPT eSpType,
+ sal_uInt32 nLineObjectCount,
+ std::vector< std::pair< SdrPathObjUniquePtr, double> >& vObjectList )
+{
+ bool bAccent = false;
+ switch( eSpType )
+ {
+ case mso_sptCallout1 :
+ case mso_sptBorderCallout1 :
+ case mso_sptCallout90 :
+ case mso_sptBorderCallout90 :
+ default:
+ break;
+
+ case mso_sptAccentCallout1 :
+ case mso_sptAccentBorderCallout1 :
+ case mso_sptAccentCallout90 :
+ case mso_sptAccentBorderCallout90 :
+ {
+ sal_uInt32 nLine = 0;
+
+ for ( const std::pair< SdrPathObjUniquePtr, double >& rCandidate : vObjectList )
+ {
+ SdrPathObj* pObj(rCandidate.first.get());
+
+ if(pObj->IsLine())
+ {
+ nLine++;
+ if ( nLine == nLineObjectCount )
+ {
+ pObj->ClearMergedItem( XATTR_LINESTART );
+ pObj->ClearMergedItem( XATTR_LINEEND );
+ }
+ }
+ }
+ }
+ break;
+
+ // switch start & end
+ case mso_sptAccentCallout2 :
+ case mso_sptAccentBorderCallout2 :
+ bAccent = true;
+ [[fallthrough]];
+ case mso_sptCallout2 :
+ case mso_sptBorderCallout2 :
+ {
+ sal_uInt32 nLine = 0;
+
+ for ( const std::pair< SdrPathObjUniquePtr, double >& rCandidate : vObjectList )
+ {
+ SdrPathObj* pObj(rCandidate.first.get());
+
+ if(pObj->IsLine())
+ {
+ nLine++;
+ if ( nLine == 1 )
+ pObj->ClearMergedItem( XATTR_LINEEND );
+ else if ( ( bAccent && ( nLine == nLineObjectCount - 1 ) ) || ( !bAccent && ( nLine == nLineObjectCount ) ) )
+ pObj->ClearMergedItem( XATTR_LINESTART );
+ else
+ {
+ pObj->ClearMergedItem( XATTR_LINESTART );
+ pObj->ClearMergedItem( XATTR_LINEEND );
+ }
+ }
+ }
+ }
+ break;
+
+ case mso_sptAccentCallout3 :
+ case mso_sptAccentBorderCallout3 :
+ case mso_sptCallout3 :
+ case mso_sptBorderCallout3 :
+ {
+ sal_uInt32 nLine = 0;
+
+ for ( const std::pair< SdrPathObjUniquePtr, double >& rCandidate : vObjectList )
+ {
+ SdrPathObj* pObj(rCandidate.first.get());
+
+ if(pObj->IsLine())
+ {
+ if ( nLine )
+ {
+ pObj->ClearMergedItem( XATTR_LINESTART );
+ pObj->ClearMergedItem( XATTR_LINEEND );
+ }
+ else
+ EnhancedCustomShape2d::SwapStartAndEndArrow( pObj );
+
+ nLine++;
+ }
+ }
+ }
+ break;
+ }
+}
+
+void EnhancedCustomShape2d::AdaptObjColor(
+ SdrPathObj& rObj,
+ double dBrightness,
+ const SfxItemSet& rCustomShapeSet,
+ sal_uInt32& nColorIndex,
+ sal_uInt32 nColorCount)
+{
+ if ( rObj.IsLine() )
+ return;
+
+ const drawing::FillStyle eFillStyle = rObj.GetMergedItem(XATTR_FILLSTYLE).GetValue();
+ if (eFillStyle == drawing::FillStyle_NONE)
+ return;
+
+ switch( eFillStyle )
+ {
+ default:
+ case drawing::FillStyle_SOLID:
+ {
+ if ( nColorCount || 0.0 != dBrightness )
+ {
+ Color aFillColor = GetColorData(
+ rCustomShapeSet.Get( XATTR_FILLCOLOR ).GetColorValue(),
+ std::min(nColorIndex, nColorCount-1),
+ dBrightness );
+ rObj.SetMergedItem( XFillColorItem( "", aFillColor ) );
+ }
+ break;
+ }
+ case drawing::FillStyle_GRADIENT:
+ {
+ XGradient aXGradient(rObj.GetMergedItem(XATTR_FILLGRADIENT).GetGradientValue());
+
+ if ( nColorCount || 0.0 != dBrightness )
+ {
+ aXGradient.SetStartColor(
+ GetColorData(
+ aXGradient.GetStartColor(),
+ std::min(nColorIndex, nColorCount-1),
+ dBrightness ));
+ aXGradient.SetEndColor(
+ GetColorData(
+ aXGradient.GetEndColor(),
+ std::min(nColorIndex, nColorCount-1),
+ dBrightness ));
+ }
+
+ rObj.SetMergedItem( XFillGradientItem( "", aXGradient ) );
+ break;
+ }
+ case drawing::FillStyle_HATCH:
+ {
+ XHatch aXHatch(rObj.GetMergedItem(XATTR_FILLHATCH).GetHatchValue());
+
+ if ( nColorCount || 0.0 != dBrightness )
+ {
+ aXHatch.SetColor(
+ GetColorData(
+ aXHatch.GetColor(),
+ std::min(nColorIndex, nColorCount-1),
+ dBrightness ));
+ }
+
+ rObj.SetMergedItem( XFillHatchItem( "", aXHatch ) );
+ break;
+ }
+ case drawing::FillStyle_BITMAP:
+ {
+ if ( nColorCount || 0.0 != dBrightness )
+ {
+ BitmapEx aBitmap(rObj.GetMergedItem(XATTR_FILLBITMAP).GetGraphicObject().GetGraphic().GetBitmapEx());
+
+ short nLuminancePercent = static_cast< short > ( GetLuminanceChange(
+ std::min(nColorIndex, nColorCount-1)));
+ aBitmap.Adjust( nLuminancePercent, 0, 0, 0, 0 );
+
+ rObj.SetMergedItem(XFillBitmapItem(OUString(), Graphic(aBitmap)));
+ }
+
+ break;
+ }
+ }
+
+ if ( nColorIndex < nColorCount )
+ nColorIndex++;
+}
+
+SdrObjectUniquePtr EnhancedCustomShape2d::CreatePathObj( bool bLineGeometryNeededOnly )
+{
+ if ( !seqCoordinates.hasElements() )
+ {
+ return nullptr;
+ }
+
+ std::vector< std::pair< SdrPathObjUniquePtr, double > > vObjectList;
+ const bool bSortFilledObjectsToBack(SortFilledObjectsToBackByDefault(eSpType));
+ sal_Int32 nSubPathIndex(0);
+ sal_Int32 nSrcPt(0);
+ sal_Int32 nSegmentInd(0);
+ SdrObjectUniquePtr pRet;
+
+ while( nSegmentInd <= seqSegments.getLength() )
+ {
+ CreateSubPath(
+ nSrcPt,
+ nSegmentInd,
+ vObjectList,
+ bLineGeometryNeededOnly,
+ bSortFilledObjectsToBack,
+ nSubPathIndex);
+ nSubPathIndex++;
+ }
+
+ if ( !vObjectList.empty() )
+ {
+ const SfxItemSet& rCustomShapeSet(mrSdrObjCustomShape.GetMergedItemSet());
+ const sal_uInt32 nColorCount(nColorData >> 28);
+ sal_uInt32 nColorIndex(0);
+
+ // #i37011# remove invisible objects
+ std::vector< std::pair< SdrPathObjUniquePtr, double> > vNewList;
+
+ for ( std::pair< SdrPathObjUniquePtr, double >& rCandidate : vObjectList )
+ {
+ SdrPathObj* pObj(rCandidate.first.get());
+ const drawing::LineStyle eLineStyle(pObj->GetMergedItem(XATTR_LINESTYLE).GetValue());
+ const drawing::FillStyle eFillStyle(pObj->GetMergedItem(XATTR_FILLSTYLE).GetValue());
+ const auto pText = pObj->getActiveText();
+
+ // #i40600# if bLineGeometryNeededOnly is set, linestyle does not matter
+ if(pText || bLineGeometryNeededOnly || (drawing::LineStyle_NONE != eLineStyle) || (drawing::FillStyle_NONE != eFillStyle))
+ vNewList.push_back(std::move(rCandidate));
+ }
+
+ vObjectList = std::move(vNewList);
+
+ if(1 == vObjectList.size())
+ {
+ // a single object, correct some values
+ AdaptObjColor(
+ *vObjectList.begin()->first,
+ vObjectList.begin()->second,
+ rCustomShapeSet,
+ nColorIndex,
+ nColorCount);
+ }
+ else
+ {
+ sal_Int32 nLineObjectCount(0);
+
+ // correct some values and collect content data
+ for ( const std::pair< SdrPathObjUniquePtr, double >& rCandidate : vObjectList )
+ {
+ SdrPathObj* pObj(rCandidate.first.get());
+
+ if(pObj->IsLine())
+ {
+ nLineObjectCount++;
+ }
+ else
+ {
+ AdaptObjColor(
+ *pObj,
+ rCandidate.second,
+ rCustomShapeSet,
+ nColorIndex,
+ nColorCount);
+
+ // OperationSmiley: when we have access to the SdrObjCustomShape and the
+ // CustomShape is built with more than a single filled Geometry, use it
+ // to define that all helper geometries defined here (SdrObjects currently)
+ // will use the same FillGeometryDefinition (from the referenced SdrObjCustomShape).
+ // This will all same-filled objects look like filled smoothly with the same style.
+ pObj->setFillGeometryDefiningShape(&mrSdrObjCustomShape);
+ }
+ }
+
+ // #i88870# correct line arrows for callouts
+ if ( nLineObjectCount )
+ {
+ CorrectCalloutArrows(
+ eSpType,
+ nLineObjectCount,
+ vObjectList);
+ }
+
+ // sort objects so that filled ones are in front. Necessary
+ // for some strange objects
+ if(bSortFilledObjectsToBack)
+ {
+ std::vector< std::pair< SdrPathObjUniquePtr, double> > vTempList;
+ vTempList.reserve(vObjectList.size());
+
+ for ( std::pair< SdrPathObjUniquePtr, double >& rCandidate : vObjectList )
+ {
+ SdrPathObj* pObj(rCandidate.first.get());
+ if ( !pObj->IsLine() )
+ vTempList.push_back(std::move(rCandidate));
+ }
+
+ for ( std::pair< SdrPathObjUniquePtr, double >& rCandidate : vObjectList )
+ {
+ if ( rCandidate.first )
+ vTempList.push_back(std::move(rCandidate));
+ }
+
+ vObjectList = std::move(vTempList);
+ }
+ }
+ }
+
+ // #i37011#
+ if(!vObjectList.empty())
+ {
+ // copy remaining objects to pRet
+ if(vObjectList.size() > 1)
+ {
+ pRet.reset(new SdrObjGroup(mrSdrObjCustomShape.getSdrModelFromSdrObject()));
+
+ for ( std::pair< SdrPathObjUniquePtr, double >& rCandidate : vObjectList )
+ {
+ pRet->GetSubList()->NbcInsertObject(rCandidate.first.release());
+ }
+ }
+ else if(1 == vObjectList.size())
+ {
+ pRet.reset(vObjectList.begin()->first.release());
+ }
+
+ if(pRet)
+ {
+ // move to target position
+ tools::Rectangle aCurRect(pRet->GetSnapRect());
+ aCurRect.Move(aLogicRect.Left(), aLogicRect.Top());
+ pRet->NbcSetSnapRect(aCurRect);
+ }
+ }
+
+ return pRet;
+}
+
+SdrObjectUniquePtr EnhancedCustomShape2d::CreateObject( bool bLineGeometryNeededOnly )
+{
+ SdrObjectUniquePtr pRet;
+
+ if ( eSpType == mso_sptRectangle )
+ {
+ pRet.reset(new SdrRectObj(mrSdrObjCustomShape.getSdrModelFromSdrObject(), aLogicRect));
+ pRet->SetMergedItemSet( *this );
+ }
+ if ( !pRet )
+ pRet = CreatePathObj( bLineGeometryNeededOnly );
+
+ return pRet;
+}
+
+void EnhancedCustomShape2d::ApplyGluePoints( SdrObject* pObj )
+{
+ if ( !pObj )
+ return;
+
+ for ( const auto& rGluePoint : std::as_const(seqGluePoints) )
+ {
+ SdrGluePoint aGluePoint;
+
+ aGluePoint.SetPos( GetPoint( rGluePoint, true, true ) );
+ aGluePoint.SetPercent( false );
+ aGluePoint.SetAlign( SdrAlign::VERT_TOP | SdrAlign::HORZ_LEFT );
+ aGluePoint.SetEscDir( SdrEscapeDirection::SMART );
+ SdrGluePointList* pList = pObj->ForceGluePointList();
+ if( pList )
+ /* sal_uInt16 nId = */ pList->Insert( aGluePoint );
+ }
+}
+
+SdrObjectUniquePtr EnhancedCustomShape2d::CreateLineGeometry()
+{
+ return CreateObject( true );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShape3d.cxx b/svx/source/customshapes/EnhancedCustomShape3d.cxx
new file mode 100644
index 000000000..00a59ebf5
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShape3d.cxx
@@ -0,0 +1,1037 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "EnhancedCustomShape3d.hxx"
+#include <o3tl/unit_conversion.hxx>
+#include <svx/deflt3d.hxx>
+#include <svx/svdmodel.hxx>
+#include <tools/poly.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoashp.hxx>
+#include <svl/itemset.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xsflclit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svx3ditems.hxx>
+#include <extrud3d.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/sdasitm.hxx>
+#include <svx/scene3d.hxx>
+#include <com/sun/star/drawing/Position3D.hpp>
+#include <com/sun/star/drawing/Direction3D.hpp>
+#include <com/sun/star/drawing/NormalsKind.hpp>
+#include <com/sun/star/drawing/ShadeMode.hpp>
+#include <svx/sdr/properties/properties.hxx>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
+#include <com/sun/star/drawing/ProjectionMode.hpp>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b3dpolygon.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <drawinglayer/attribute/sdrlineattribute.hxx>
+#include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xfltrit.hxx>
+#include <basegfx/color/bcolor.hxx>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+
+namespace {
+
+void GetOrigin( const SdrCustomShapeGeometryItem& rItem, double& rOriginX, double& rOriginY )
+{
+ css::drawing::EnhancedCustomShapeParameterPair aOriginParaPair;
+ const Any* pAny = rItem.GetPropertyValueByName( "Extrusion", "Origin" );
+ if ( ! ( pAny && ( *pAny >>= aOriginParaPair ) && ( aOriginParaPair.First.Value >>= rOriginX ) && ( aOriginParaPair.Second.Value >>= rOriginY ) ) )
+ {
+ rOriginX = 0.50;
+ rOriginY =-0.50;
+ }
+}
+
+void GetRotateAngle( const SdrCustomShapeGeometryItem& rItem, double& rAngleX, double& rAngleY )
+{
+ css::drawing::EnhancedCustomShapeParameterPair aRotateAngleParaPair;
+ const Any* pAny = rItem.GetPropertyValueByName( "Extrusion", "RotateAngle" );
+ if ( ! ( pAny && ( *pAny >>= aRotateAngleParaPair ) && ( aRotateAngleParaPair.First.Value >>= rAngleX ) && ( aRotateAngleParaPair.Second.Value >>= rAngleY ) ) )
+ {
+ rAngleX = 0.0;
+ rAngleY = 0.0;
+ }
+ rAngleX = basegfx::deg2rad(rAngleX);
+ rAngleY = basegfx::deg2rad(rAngleY);
+}
+
+void GetSkew( const SdrCustomShapeGeometryItem& rItem, double& rSkewAmount, double& rSkewAngle )
+{
+ css::drawing::EnhancedCustomShapeParameterPair aSkewParaPair;
+ const Any* pAny = rItem.GetPropertyValueByName( "Extrusion", "Skew" );
+ if ( ! ( pAny && ( *pAny >>= aSkewParaPair ) && ( aSkewParaPair.First.Value >>= rSkewAmount ) && ( aSkewParaPair.Second.Value >>= rSkewAngle ) ) )
+ {
+ rSkewAmount = 50;
+ // ODF default is 45, but older ODF documents expect -135 as default. For intermediate
+ // solution see tdf#141301 and tdf#141127.
+ // MS Office default -135 is set in msdffimp.cxx to make import independent from setting here.
+ rSkewAngle = -135;
+ }
+ rSkewAngle = basegfx::deg2rad(rSkewAngle);
+}
+
+void GetExtrusionDepth( const SdrCustomShapeGeometryItem& rItem, const double* pMap, double& rBackwardDepth, double& rForwardDepth )
+{
+ css::drawing::EnhancedCustomShapeParameterPair aDepthParaPair;
+ double fDepth = 0, fFraction = 0;
+ const Any* pAny = rItem.GetPropertyValueByName( "Extrusion", "Depth" );
+ if ( pAny && ( *pAny >>= aDepthParaPair ) && ( aDepthParaPair.First.Value >>= fDepth ) && ( aDepthParaPair.Second.Value >>= fFraction ) )
+ {
+ rForwardDepth = fDepth * fFraction;
+ rBackwardDepth = fDepth - rForwardDepth;
+ }
+ else
+ {
+ rBackwardDepth = 1270;
+ rForwardDepth = 0;
+ }
+ if ( pMap )
+ {
+ double fMap = *pMap;
+ rBackwardDepth *= fMap;
+ rForwardDepth *= fMap;
+ }
+}
+
+double GetDouble( const SdrCustomShapeGeometryItem& rItem, const OUString& rPropertyName, double fDefault )
+{
+ double fRetValue = fDefault;
+ const Any* pAny = rItem.GetPropertyValueByName( "Extrusion", rPropertyName );
+ if ( pAny )
+ *pAny >>= fRetValue;
+ return fRetValue;
+}
+
+drawing::ShadeMode GetShadeMode( const SdrCustomShapeGeometryItem& rItem, const drawing::ShadeMode eDefault )
+{
+ drawing::ShadeMode eRet( eDefault );
+ const Any* pAny = rItem.GetPropertyValueByName( "Extrusion", "ShadeMode" );
+ if ( pAny )
+ *pAny >>= eRet;
+ return eRet;
+}
+
+bool GetBool( const SdrCustomShapeGeometryItem& rItem, const OUString& rPropertyName, const bool bDefault )
+{
+ bool bRetValue = bDefault;
+ const Any* pAny = rItem.GetPropertyValueByName( "Extrusion", rPropertyName );
+ if ( pAny )
+ *pAny >>= bRetValue;
+ return bRetValue;
+}
+
+drawing::Position3D GetPosition3D( const SdrCustomShapeGeometryItem& rItem, const OUString& rPropertyName,
+ const drawing::Position3D& rDefault, const double* pMap )
+{
+ drawing::Position3D aRetValue( rDefault );
+ const Any* pAny = rItem.GetPropertyValueByName( "Extrusion", rPropertyName );
+ if ( pAny )
+ *pAny >>= aRetValue;
+ if ( pMap )
+ {
+ aRetValue.PositionX *= *pMap;
+ aRetValue.PositionY *= *pMap;
+ aRetValue.PositionZ *= *pMap;
+ }
+ return aRetValue;
+}
+
+drawing::Direction3D GetDirection3D( const SdrCustomShapeGeometryItem& rItem, const OUString& rPropertyName, const drawing::Direction3D& rDefault )
+{
+ drawing::Direction3D aRetValue( rDefault );
+ const Any* pAny = rItem.GetPropertyValueByName( "Extrusion", rPropertyName );
+ if ( pAny )
+ *pAny >>= aRetValue;
+ return aRetValue;
+}
+
+sal_Int16 GetMetalType(const SdrCustomShapeGeometryItem& rItem, const sal_Int16 eDefault)
+{
+ sal_Int16 aRetValue(eDefault);
+ const Any* pAny = rItem.GetPropertyValueByName("Extrusion", "MetalType");
+ if (pAny)
+ *pAny >>= aRetValue;
+ return aRetValue;
+}
+
+// Calculates the light directions for the additional lights, which are used to emulate soft
+// lights of MS Office. Method needs to be documented in the Wiki
+// https://wiki.documentfoundation.org/Development/ODF_Implementer_Notes in part
+// List_of_LibreOffice_ODF_implementation-defined_items
+// The method expects vector rLight to be normalized and results normalized vectors.
+void lcl_SoftLightsDirection(const basegfx::B3DVector& rLight, basegfx::B3DVector& rSoftUp,
+ basegfx::B3DVector& rSoftDown, basegfx::B3DVector& rSoftRight,
+ basegfx::B3DVector& rSoftLeft)
+{
+ constexpr double fAngle = basegfx::deg2rad(60); // angle between regular light and soft light
+
+ // We first create directions around (0|0|1) and then rotate them to the light position.
+ rSoftUp = basegfx::B3DVector(0.0, sin(fAngle), cos(fAngle));
+ rSoftDown = basegfx::B3DVector(0.0, -sin(fAngle), cos(fAngle));
+ rSoftRight = basegfx::B3DVector(sin(fAngle), 0.0, cos(fAngle));
+ rSoftLeft = basegfx::B3DVector(-sin(fAngle), 0.0, cos(fAngle));
+
+ basegfx::B3DHomMatrix aRotateMat;
+ aRotateMat.rotate(0.0, 0.0, M_PI_4);
+ if (rLight.getX() == 0.0 && rLight.getZ() == 0.0)
+ {
+ // Special case with light from top or bottom
+ if (rLight.getY() >= 0.0)
+ aRotateMat.rotate(-M_PI_2, 0.0, 0.0);
+ else
+ aRotateMat.rotate(M_PI_2, 0.0, 0.0);
+ }
+ else
+ {
+ // Azimuth from z-axis to x-axis. (0|0|1) to (1|0|0) is 90deg.
+ double fAzimuth = atan2(rLight.getX(), rLight.getZ());
+ // Elevation from xz-plane to y-axis. (0|0|1) to (0|1|0) is 90deg.
+ double fElevation = atan2(rLight.getY(), std::hypot(rLight.getX(), rLight.getZ()));
+ aRotateMat.rotate(-fElevation, fAzimuth, 0.0);
+ }
+
+ rSoftUp = aRotateMat * rSoftUp;
+ rSoftDown = aRotateMat * rSoftDown;
+ rSoftRight = aRotateMat * rSoftRight;
+ rSoftLeft = aRotateMat * rSoftLeft;
+}
+}
+
+SdrObject* EnhancedCustomShape3d::Create3DObject(
+ const SdrObject* pShape2d,
+ const SdrObjCustomShape& rSdrObjCustomShape)
+{
+ SdrObject* pRet(nullptr);
+ const SdrCustomShapeGeometryItem& rGeometryItem(rSdrObjCustomShape.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY));
+ double fMap(1.0), *pMap = nullptr;
+ Fraction aFraction( rSdrObjCustomShape.getSdrModelFromSdrObject().GetScaleFraction() );
+
+ if ( aFraction.GetNumerator() != 1 || aFraction.GetDenominator() != 1 )
+ {
+ fMap *= double(aFraction);
+ pMap = &fMap;
+ }
+
+ if ( rSdrObjCustomShape.getSdrModelFromSdrObject().GetScaleUnit() != MapUnit::Map100thMM )
+ {
+ DBG_ASSERT( rSdrObjCustomShape.getSdrModelFromSdrObject().GetScaleUnit() == MapUnit::MapTwip, "EnhancedCustomShape3d::Current MapMode is Unsupported" );
+ // But we could use MapToO3tlUnit from <tools/UnitConversion> ... ?
+ fMap *= o3tl::convert(1.0, o3tl::Length::mm100, o3tl::Length::twip);
+ pMap = &fMap;
+ }
+
+ if ( GetBool( rGeometryItem, "Extrusion", false ) )
+ {
+ bool bIsMirroredX(rSdrObjCustomShape.IsMirroredX());
+ bool bIsMirroredY(rSdrObjCustomShape.IsMirroredY());
+ tools::Rectangle aSnapRect(rSdrObjCustomShape.GetLogicRect());
+ Degree100 nObjectRotation(rSdrObjCustomShape.GetRotateAngle());
+ if ( nObjectRotation )
+ {
+ double a = toRadians(36000_deg100 - nObjectRotation);
+ tools::Long dx = aSnapRect.Right() - aSnapRect.Left();
+ tools::Long dy = aSnapRect.Bottom()- aSnapRect.Top();
+ Point aP( aSnapRect.TopLeft() );
+ RotatePoint( aP, rSdrObjCustomShape.GetSnapRect().Center(), sin( a ), cos( a ) );
+ aSnapRect.SetLeft( aP.X() );
+ aSnapRect.SetTop( aP.Y() );
+ aSnapRect.SetRight( aSnapRect.Left() + dx );
+ aSnapRect.SetBottom( aSnapRect.Top() + dy );
+ }
+ Point aCenter( aSnapRect.Center() );
+
+ SfxItemSet aSet( rSdrObjCustomShape.GetMergedItemSet() );
+
+ //SJ: vertical writing is not required, by removing this item no outliner is created
+ aSet.ClearItem( SDRATTR_TEXTDIRECTION );
+
+ // #i105323# For 3D AutoShapes, the shadow attribute has to be applied to each
+ // created visualisation helper model shape individually. The shadow itself
+ // will then be rendered from the 3D renderer correctly for the whole 3D scene
+ // (and thus behind all objects of which the visualisation may be built). So,
+ // do NOT remove it from the ItemSet here.
+ // aSet.ClearItem(SDRATTR_SHADOW);
+
+ std::vector< E3dCompoundObject* > aPlaceholderObjectList;
+
+ double fExtrusionBackward, fExtrusionForward;
+ GetExtrusionDepth( rGeometryItem, pMap, fExtrusionBackward, fExtrusionForward );
+ double fDepth = fExtrusionBackward + fExtrusionForward;
+ if ( fDepth < 1.0 )
+ fDepth = 1.0;
+
+ drawing::ProjectionMode eProjectionMode( drawing::ProjectionMode_PARALLEL );
+ const Any* pAny = rGeometryItem.GetPropertyValueByName( "Extrusion", "ProjectionMode" );
+ if ( pAny )
+ *pAny >>= eProjectionMode;
+ // pShape2d Convert in scenes which include 3D Objects
+ E3dDefaultAttributes a3DDefaultAttr;
+ a3DDefaultAttr.SetDefaultLatheCharacterMode( true );
+ a3DDefaultAttr.SetDefaultExtrudeCharacterMode( true );
+
+ E3dScene* pScene = new E3dScene(rSdrObjCustomShape.getSdrModelFromSdrObject());
+
+ bool bSceneHasObjects ( false );
+ bool bUseTwoFillStyles( false );
+
+ drawing::ShadeMode eShadeMode( GetShadeMode( rGeometryItem, drawing::ShadeMode_FLAT ) );
+ bool bUseExtrusionColor = GetBool( rGeometryItem, "Color", false );
+
+ drawing::FillStyle eFillStyle( aSet.Get(XATTR_FILLSTYLE).GetValue() );
+ pScene->GetProperties().SetObjectItem( Svx3DShadeModeItem(static_cast<sal_uInt16>(eShadeMode)));
+ aSet.Put( makeSvx3DPercentDiagonalItem( 0 ) );
+ aSet.Put( Svx3DTextureModeItem( 1 ) );
+ // SPECIFIC needed for ShadeMode_SMOOTH and ShadeMode_PHONG, otherwise FLAT is faster.
+ if (eShadeMode == drawing::ShadeMode_SMOOTH || eShadeMode == drawing::ShadeMode_PHONG)
+ aSet.Put( Svx3DNormalsKindItem(static_cast<sal_uInt16>(drawing::NormalsKind_SPECIFIC)));
+ else
+ aSet.Put( Svx3DNormalsKindItem(static_cast<sal_uInt16>(drawing::NormalsKind_FLAT)));
+
+ if ( eShadeMode == drawing::ShadeMode_DRAFT )
+ {
+ aSet.Put( XLineStyleItem( drawing::LineStyle_SOLID ) );
+ aSet.Put( XFillStyleItem ( drawing::FillStyle_NONE ) );
+ aSet.Put( makeSvx3DDoubleSidedItem( true ) );
+ }
+ else
+ {
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ if ( eFillStyle == drawing::FillStyle_NONE )
+ aSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ else if ( ( eFillStyle == drawing::FillStyle_BITMAP ) || ( eFillStyle == drawing::FillStyle_GRADIENT ) || bUseExtrusionColor )
+ bUseTwoFillStyles = true;
+
+ // If shapes are mirrored once (mirroring two times correct geometry again)
+ // double-sided at the object and two-sided-lighting at the scene need to be set.
+
+ // #i122777# Also use double sided for two fill styles since there several 3d objects get
+ // created with a depth of 0; one of them is the backside which needs double-sided to
+ // get visible
+ if(bUseTwoFillStyles || (bIsMirroredX && !bIsMirroredY) || (!bIsMirroredX && bIsMirroredY))
+ {
+ aSet.Put( makeSvx3DDoubleSidedItem( true ) );
+ pScene->GetProperties().SetObjectItem( makeSvx3DTwoSidedLightingItem( true ) );
+ }
+ }
+
+ tools::Rectangle aBoundRect2d;
+ basegfx::B2DPolyPolygon aTotalPolyPoly;
+ SdrObjListIter aIter( *pShape2d, SdrIterMode::DeepNoGroups );
+ const bool bMultipleSubObjects(aIter.Count() > 1);
+
+ while( aIter.IsMore() )
+ {
+ const SdrObject* pNext = aIter.Next();
+ bool bIsPlaceholderObject = (pNext->GetMergedItem( XATTR_FILLSTYLE ).GetValue() == drawing::FillStyle_NONE )
+ && (pNext->GetMergedItem( XATTR_LINESTYLE ).GetValue() == drawing::LineStyle_NONE );
+ basegfx::B2DPolyPolygon aPolyPoly;
+ SfxItemSet aLocalSet(aSet);
+ drawing::FillStyle aLocalFillStyle(eFillStyle);
+
+ if ( auto pPathObj = dynamic_cast<const SdrPathObj*>(pNext) )
+ {
+ const SfxItemSet& rSet = pNext->GetMergedItemSet();
+ bool bNeedToConvertToContour(false);
+
+ // do conversion only for single line objects; for all others a fill and a
+ // line object get created. When we have fill, we want no line. That line has
+ // always been there, but since it was never converted to contour, it kept
+ // invisible (all this 'hidden' logic should be migrated to primitives).
+ if(!bMultipleSubObjects)
+ {
+ const drawing::FillStyle eStyle(rSet.Get(XATTR_FILLSTYLE).GetValue());
+
+ if(drawing::FillStyle_NONE == eStyle)
+ {
+ const drawinglayer::attribute::SdrLineAttribute aLine(
+ drawinglayer::primitive2d::createNewSdrLineAttribute(rSet));
+
+ bNeedToConvertToContour = (0.0 < aLine.getWidth() || 0.0 != aLine.getFullDotDashLen());
+
+ if(!bNeedToConvertToContour && !aLine.isDefault())
+ {
+ const drawinglayer::attribute::SdrLineStartEndAttribute aLineStartEnd(
+ drawinglayer::primitive2d::createNewSdrLineStartEndAttribute(rSet, aLine.getWidth()));
+
+ if((aLineStartEnd.getStartWidth() && aLineStartEnd.isStartActive())
+ || (aLineStartEnd.getEndWidth() && aLineStartEnd.isEndActive()))
+ {
+ bNeedToConvertToContour = true;
+ }
+ }
+ }
+ }
+
+ if(bNeedToConvertToContour)
+ {
+ SdrObject* pNewObj = pNext->ConvertToContourObj(const_cast< SdrObject* >(pNext));
+ SdrPathObj* pNewPathObj = dynamic_cast< SdrPathObj* >(pNewObj);
+
+ if(pNewPathObj)
+ {
+ aPolyPoly = pNewPathObj->GetPathPoly();
+
+ if(aPolyPoly.isClosed())
+ {
+ // correct item properties from line to fill style
+ if(eShadeMode == drawing::ShadeMode_DRAFT)
+ {
+ // for draft, create wireframe with fixed line width
+ aLocalSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
+ aLocalSet.Put(XLineWidthItem(40));
+ aLocalFillStyle = drawing::FillStyle_NONE;
+ }
+ else
+ {
+ // switch from line to fill, copy line attr to fill attr (color, transparence)
+ aLocalSet.Put(XLineWidthItem(0));
+ aLocalSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ aLocalSet.Put(XFillColorItem(OUString(), aLocalSet.Get(XATTR_LINECOLOR).GetColorValue()));
+ aLocalSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ aLocalSet.Put(XFillTransparenceItem(aLocalSet.Get(XATTR_LINETRANSPARENCE).GetValue()));
+ aLocalFillStyle = drawing::FillStyle_SOLID;
+ }
+ }
+ else
+ {
+ // correct item properties to hairlines
+ aLocalSet.Put(XLineWidthItem(0));
+ aLocalSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
+ }
+ }
+
+ SdrObject::Free(pNewObj);
+ }
+ else
+ {
+ aPolyPoly = pPathObj->GetPathPoly();
+ }
+ }
+ else
+ {
+ SdrObjectUniquePtr pNewObj = pNext->ConvertToPolyObj( false, false );
+ SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pNewObj.get() );
+ if ( pPath )
+ aPolyPoly = pPath->GetPathPoly();
+ }
+
+ if( aPolyPoly.count() )
+ {
+ if(aPolyPoly.areControlPointsUsed())
+ {
+ aPolyPoly = basegfx::utils::adaptiveSubdivideByAngle(aPolyPoly);
+ }
+
+ const basegfx::B2DRange aTempRange(basegfx::utils::getRange(aPolyPoly));
+ const tools::Rectangle aBoundRect(basegfx::fround(aTempRange.getMinX()), basegfx::fround(aTempRange.getMinY()), basegfx::fround(aTempRange.getMaxX()), basegfx::fround(aTempRange.getMaxY()));
+ aTotalPolyPoly.append(aPolyPoly);
+ aBoundRect2d.Union( aBoundRect );
+
+ // #i122777# depth 0 is okay for planes when using double-sided
+ E3dCompoundObject* p3DObj = new E3dExtrudeObj(
+ rSdrObjCustomShape.getSdrModelFromSdrObject(),
+ a3DDefaultAttr,
+ aPolyPoly,
+ bUseTwoFillStyles ? 0 : fDepth );
+
+ p3DObj->NbcSetLayer( pShape2d->GetLayer() );
+ p3DObj->SetMergedItemSet( aLocalSet );
+
+ if ( bIsPlaceholderObject )
+ aPlaceholderObjectList.push_back( p3DObj );
+ else if ( bUseTwoFillStyles )
+ {
+ BitmapEx aFillBmp;
+ bool bFillBmpTile = p3DObj->GetMergedItem( XATTR_FILLBMP_TILE ).GetValue();
+ if ( bFillBmpTile )
+ {
+ const XFillBitmapItem& rBmpItm = p3DObj->GetMergedItem(XATTR_FILLBITMAP);
+ aFillBmp = rBmpItm.GetGraphicObject().GetGraphic().GetBitmapEx();
+
+ // #i122777# old adaptation of FillStyle bitmap size to 5-times the original size; this is not needed
+ // anymore and was used in old times to male the fill look better when converting to 3D. Removed
+ // from regular 3D objects for some time, also needs to be removed from CustomShapes
+
+ //Size aLogicalSize = aFillBmp.GetPrefSize();
+ //if ( aFillBmp.GetPrefMapMode() == MapUnit::MapPixel )
+ // aLogicalSize = Application::GetDefaultDevice()->PixelToLogic( aLogicalSize, MapUnit::Map100thMM );
+ //else
+ // aLogicalSize = OutputDevice::LogicToLogic( aLogicalSize, aFillBmp.GetPrefMapMode(), MapUnit::Map100thMM );
+ //aLogicalSize.Width() *= 5; ;// :-( nice scaling, look at engine3d/obj3d.cxx
+ //aLogicalSize.Height() *= 5;
+ //aFillBmp.SetPrefSize( aLogicalSize );
+ //aFillBmp.SetPrefMapMode( MapUnit::Map100thMM );
+ //p3DObj->SetMergedItem(XFillBitmapItem(String(), Graphic(aFillBmp)));
+ }
+ else
+ {
+ if ( aSnapRect != aBoundRect && aSnapRect.GetWidth() > 0 && aSnapRect.GetHeight() > 0)
+ {
+ const XFillBitmapItem& rBmpItm = p3DObj->GetMergedItem(XATTR_FILLBITMAP);
+ aFillBmp = rBmpItm.GetGraphicObject().GetGraphic().GetBitmapEx();
+ Size aBmpSize( aFillBmp.GetSizePixel() );
+ double fXScale = static_cast<double>(aBoundRect.GetWidth()) / static_cast<double>(aSnapRect.GetWidth());
+ double fYScale = static_cast<double>(aBoundRect.GetHeight()) / static_cast<double>(aSnapRect.GetHeight());
+
+ Point aPt( static_cast<sal_Int32>( static_cast<double>( aBoundRect.Left() - aSnapRect.Left() )* static_cast<double>(aBmpSize.Width()) / static_cast<double>(aSnapRect.GetWidth()) ),
+ static_cast<sal_Int32>( static_cast<double>( aBoundRect.Top() - aSnapRect.Top() ) * static_cast<double>(aBmpSize.Height()) / static_cast<double>(aSnapRect.GetHeight()) ) );
+ Size aSize( static_cast<sal_Int32>( aBmpSize.Width() * fXScale ),
+ static_cast<sal_Int32>( aBmpSize.Height() * fYScale ) );
+ tools::Rectangle aCropRect( aPt, aSize );
+ aFillBmp.Crop( aCropRect );
+ p3DObj->SetMergedItem(XFillBitmapItem(OUString(), Graphic(aFillBmp)));
+ }
+ }
+ pScene->InsertObject( p3DObj );
+ p3DObj = new E3dExtrudeObj(
+ rSdrObjCustomShape.getSdrModelFromSdrObject(),
+ a3DDefaultAttr,
+ aPolyPoly,
+ fDepth);
+ p3DObj->NbcSetLayer( pShape2d->GetLayer() );
+ p3DObj->SetMergedItemSet( aLocalSet );
+ if ( bUseExtrusionColor )
+ p3DObj->SetMergedItem( XFillColorItem( "", rSdrObjCustomShape.GetMergedItem( XATTR_SECONDARYFILLCOLOR ).GetColorValue() ) );
+ p3DObj->SetMergedItem( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ p3DObj->SetMergedItem( Svx3DCloseFrontItem( false ) );
+ p3DObj->SetMergedItem( Svx3DCloseBackItem( false ) );
+ pScene->InsertObject( p3DObj );
+
+ // #i122777# depth 0 is okay for planes when using double-sided
+ p3DObj = new E3dExtrudeObj(
+ rSdrObjCustomShape.getSdrModelFromSdrObject(),
+ a3DDefaultAttr,
+ aPolyPoly,
+ 0);
+
+ p3DObj->NbcSetLayer( pShape2d->GetLayer() );
+ p3DObj->SetMergedItemSet( aLocalSet );
+
+ basegfx::B3DHomMatrix aFrontTransform( p3DObj->GetTransform() );
+ aFrontTransform.translate( 0.0, 0.0, fDepth );
+ p3DObj->NbcSetTransform( aFrontTransform );
+
+ if ( ( aLocalFillStyle == drawing::FillStyle_BITMAP ) && !aFillBmp.IsEmpty() )
+ {
+ p3DObj->SetMergedItem(XFillBitmapItem(OUString(), Graphic(aFillBmp)));
+ }
+ }
+ else if ( aLocalFillStyle == drawing::FillStyle_NONE )
+ {
+ const XLineColorItem& rLineColor = p3DObj->GetMergedItem( XATTR_LINECOLOR );
+ p3DObj->SetMergedItem( XFillColorItem( "", rLineColor.GetColorValue() ) );
+ p3DObj->SetMergedItem( makeSvx3DDoubleSidedItem( true ) );
+ p3DObj->SetMergedItem( Svx3DCloseFrontItem( false ) );
+ p3DObj->SetMergedItem( Svx3DCloseBackItem( false ) );
+ }
+ pScene->InsertObject( p3DObj );
+ bSceneHasObjects = true;
+ }
+ }
+
+ if ( bSceneHasObjects ) // is the SdrObject properly converted
+ {
+ // then we can change the return value
+ pRet = pScene;
+
+ // Camera settings, Perspective ...
+ Camera3D rCamera = pScene->GetCamera();
+ pScene->NbcSetSnapRect( aSnapRect );
+
+ // InitScene replacement
+ double fW = aBoundRect2d.getWidth();
+ double fH = aBoundRect2d.getHeight();
+ rCamera.SetAutoAdjustProjection( false );
+ rCamera.SetViewWindow( -fW / 2, - fH / 2, fW, fH);
+ basegfx::B3DPoint aLookAt( 0.0, 0.0, 0.0 );
+ basegfx::B3DPoint aCamPos( 0.0, 0.0, 100.0 );
+ rCamera.SetPosAndLookAt( aCamPos, aLookAt );
+ rCamera.SetFocalLength( 1.0 );
+ ProjectionType eProjectionType( eProjectionMode == drawing::ProjectionMode_PARALLEL ? ProjectionType::Parallel : ProjectionType::Perspective );
+ rCamera.SetProjection( eProjectionType );
+ pScene->SetCamera( rCamera );
+ pScene->SetBoundAndSnapRectsDirty();
+
+ basegfx::B3DHomMatrix aNewTransform( pScene->GetTransform() );
+ basegfx::B2DHomMatrix aPolyPolyTransform;
+ // Apply flip and z-rotation to scene transformation (y up). At same time transform
+ // aTotalPolyPoly (y down) which will be used for 2D boundRect of shape having 2D
+ // transformations applied.
+
+ // API values use shape center as origin. Move scene so, that shape center is origin.
+ aNewTransform.translate( -aCenter.X(), aCenter.Y(), -fExtrusionBackward);
+ aPolyPolyTransform.translate(-aCenter.X(), -aCenter.Y());
+
+ double fZRotate(basegfx::deg2rad(rSdrObjCustomShape.GetObjectRotation()));
+ if ( fZRotate != 0.0 )
+ {
+ aNewTransform.rotate( 0.0, 0.0, fZRotate );
+ aPolyPolyTransform.rotate(-fZRotate);
+ }
+ if ( bIsMirroredX )
+ {
+ aNewTransform.scale( -1.0, 1, 1 );
+ aPolyPolyTransform.scale(-1.0, 1);
+ }
+ if ( bIsMirroredY )
+ {
+ aNewTransform.scale( 1, -1.0, 1 );
+ aPolyPolyTransform.scale(1, -1.0);
+ }
+ aPolyPolyTransform.translate(aCenter.X(), aCenter.Y());
+ aTotalPolyPoly.transform(aPolyPolyTransform);
+
+ // x- and y-rotation have an own rotation center. x- and y-value of rotation center are
+ // fractions of shape size, z-value is in Hmm in property. Shape center is (0 0 0).
+ // Values in property are in custom shape extrusion space with y-axis down.
+ double fXRotate, fYRotate;
+ GetRotateAngle( rGeometryItem, fXRotate, fYRotate );
+ drawing::Direction3D aRotationCenterDefault( 0, 0, 0 );
+ drawing::Direction3D aRotationCenter( GetDirection3D( rGeometryItem, "RotationCenter", aRotationCenterDefault ) );
+ aRotationCenter.DirectionX *= aSnapRect.getWidth();
+ aRotationCenter.DirectionY *= aSnapRect.getHeight();
+ if (pMap)
+ {
+ aRotationCenter.DirectionZ *= *pMap;
+ }
+ aNewTransform.translate( -aRotationCenter.DirectionX, aRotationCenter.DirectionY, -aRotationCenter.DirectionZ );
+ if( fYRotate != 0.0 )
+ aNewTransform.rotate( 0.0, -fYRotate, 0.0 );
+ if( fXRotate != 0.0 )
+ aNewTransform.rotate( -fXRotate, 0.0, 0.0 );
+ aNewTransform.translate(aRotationCenter.DirectionX, -aRotationCenter.DirectionY, aRotationCenter.DirectionZ);
+
+ // oblique parallel projection is done by shearing the object, not by moving the camera
+ if (eProjectionMode == drawing::ProjectionMode_PARALLEL)
+ {
+ double fSkew, fAlpha;
+ GetSkew( rGeometryItem, fSkew, fAlpha );
+ if ( fSkew != 0.0 )
+ {
+ double fInvTanBeta( fSkew / 100.0 );
+ if(fInvTanBeta)
+ {
+ aNewTransform.shearXY(
+ fInvTanBeta * cos(fAlpha),
+ fInvTanBeta * sin(fAlpha));
+ }
+ }
+ }
+
+ pScene->NbcSetTransform( aNewTransform );
+
+ // These values are used later again, so declare them outside the if-statement. They will
+ // contain the absolute values of ViewPoint in 3D scene coordinate system, y-axis up.
+ double fViewPointX = 0; // dummy values
+ double fViewPointY = 0;
+ double fViewPointZ = 25000;
+ if (eProjectionMode == drawing::ProjectionMode_PERSPECTIVE)
+ {
+ double fOriginX, fOriginY;
+ // Calculate BoundRect of shape, including flip and z-rotation, from aTotalPolyPoly.
+ tools::Rectangle aBoundAfter2DTransform; // aBoundAfter2DTransform has y-axis down.
+ basegfx::B2DRange aTotalPolyPolyRange(aTotalPolyPoly.getB2DRange());
+ aBoundAfter2DTransform.SetLeft(aTotalPolyPolyRange.getMinX());
+ aBoundAfter2DTransform.SetTop(aTotalPolyPolyRange.getMinY());
+ aBoundAfter2DTransform.SetRight(aTotalPolyPolyRange.getMaxX());
+ aBoundAfter2DTransform.SetBottom(aTotalPolyPolyRange.getMaxY());
+
+ // Property "Origin" in API is relative to bounding box of shape after 2D
+ // transformations. Range is [-0.5;0.5] with center of bounding box as 0.
+ // Resolve "Origin" fractions to length
+ GetOrigin( rGeometryItem, fOriginX, fOriginY );
+ fOriginX *= aBoundAfter2DTransform.GetWidth();
+ fOriginY *= aBoundAfter2DTransform.GetHeight();
+ // Resolve length to absolute value for 3D
+ fOriginX += aBoundAfter2DTransform.Center().X();
+ fOriginY += aBoundAfter2DTransform.Center().Y();
+ fOriginY = - fOriginY;
+ // Scene is translated so that shape center is origin of coordinate system.
+ // Translate point "Origin" too.
+ fOriginX -= aCenter.X();
+ fOriginY -= -aCenter.Y();
+ // API ViewPoint values are relative to point "Origin" and have y-axis down.
+ // ToDo: These default ViewPoint values are used as default by MS Office. But ODF
+ // default is (3500, -3500, 25000), details in tdf#146192.
+ drawing::Position3D aViewPointDefault( 3472, -3472, 25000 );
+ drawing::Position3D aViewPoint( GetPosition3D( rGeometryItem, "ViewPoint", aViewPointDefault, pMap ) );
+ fViewPointX = aViewPoint.PositionX + fOriginX;
+ fViewPointY = - aViewPoint.PositionY + fOriginY;
+ fViewPointZ = aViewPoint.PositionZ;
+ }
+
+ // now set correct camera position
+ if (eProjectionMode == drawing::ProjectionMode_PARALLEL)
+ {
+ basegfx::B3DPoint _aLookAt( 0.0, 0.0, 0.0 );
+ basegfx::B3DPoint _aNewCamPos( 0.0, 0.0, 25000.0 );
+ rCamera.SetPosAndLookAt( _aNewCamPos, _aLookAt );
+ pScene->SetCamera( rCamera );
+ }
+ else
+ {
+ basegfx::B3DPoint _aLookAt(fViewPointX, fViewPointY, 0.0);
+ basegfx::B3DPoint aNewCamPos(fViewPointX, fViewPointY, fViewPointZ);
+ rCamera.SetPosAndLookAt( aNewCamPos, _aLookAt );
+ pScene->SetCamera( rCamera );
+ }
+
+ // NbcSetTransform has not updated the scene 2D rectangles.
+ // Idea: Get a bound volume as polygon from bound rectangle of shape without 2D
+ // transformations. Calculate its projection to the XY-plane. Then calculate the bounding
+ // rectangle of the projection and convert this rectangle back to absolute 2D coordinates.
+ // Set that as 2D rectangle of the scene.
+ const tools::Polygon aPolygon(aBoundRect2d); // y-up
+ basegfx::B3DPolygon aPolygonBoundVolume; // y-down, scene coordinates
+ for (sal_uInt16 i = 0; i < 4; i++ )
+ {
+ aPolygonBoundVolume.append(basegfx::B3DPoint(aPolygon[i].X(), -aPolygon[i].Y(), 0));
+ }
+ for (sal_uInt16 i = 0; i < 4; i++ )
+ {
+ aPolygonBoundVolume.append(basegfx::B3DPoint(aPolygon[i].X(), -aPolygon[i].Y(), fDepth));
+ }
+ aPolygonBoundVolume.transform(aNewTransform);
+
+ // projection
+ tools::Polygon a2DProjectionResult(8); // in fact 3D points with z=0
+ for (sal_uInt16 i = 0; i < 8; i++ )
+ {
+ const basegfx::B3DPoint aPoint3D(aPolygonBoundVolume.getB3DPoint(i));
+
+ if (eProjectionMode == drawing::ProjectionMode_PARALLEL)
+ {
+ a2DProjectionResult[i].setX(aPoint3D.getX());
+ a2DProjectionResult[i].setY(aPoint3D.getY());
+ }
+ else
+ {
+ // skip point if line from viewpoint to point is parallel to xy-plane
+ if (double fDiv = aPoint3D.getZ() - fViewPointZ; fDiv != 0.0)
+ {
+ double f = (- fViewPointZ) / fDiv;
+ double fX = (aPoint3D.getX() - fViewPointX) * f + fViewPointX;
+ double fY = (aPoint3D.getY() - fViewPointY) * f + fViewPointY;;
+ a2DProjectionResult[i].setX(static_cast<sal_Int32>(fX));
+ a2DProjectionResult[i].setY(static_cast<sal_Int32>(fY));
+ }
+ }
+ }
+ // Convert to y-axis down
+ for (sal_uInt16 i = 0; i < 8; i++ )
+ {
+ a2DProjectionResult[i].setY(- a2DProjectionResult[i].Y());
+ }
+ // Shift back to shape center
+ a2DProjectionResult.Translate(aCenter);
+
+ pScene->SetLogicRect(a2DProjectionResult.GetBoundRect());
+
+
+ // light and material
+
+ // "LightFace" has nothing corresponding in 3D rendering engine.
+ /* bool bLightFace = */ GetBool(rGeometryItem, "LightFace", true); // default in ODF
+
+ // Light directions
+
+ drawing::Direction3D aFirstLightDirectionDefault(50000.0, 0.0, 10000.0);
+ drawing::Direction3D aFirstLightDirection(GetDirection3D( rGeometryItem, "FirstLightDirection", aFirstLightDirectionDefault));
+ if (aFirstLightDirection.DirectionX == 0.0 && aFirstLightDirection.DirectionY == 0.0
+ && aFirstLightDirection.DirectionZ == 0.0)
+ aFirstLightDirection.DirectionZ = 1.0;
+ basegfx::B3DVector aLight1Vector(aFirstLightDirection.DirectionX, -aFirstLightDirection.DirectionY, aFirstLightDirection.DirectionZ);
+ aLight1Vector.normalize();
+
+ drawing::Direction3D aSecondLightDirectionDefault(-50000.0, 0.0, 10000.0);
+ drawing::Direction3D aSecondLightDirection(GetDirection3D( rGeometryItem, "SecondLightDirection", aSecondLightDirectionDefault));
+ if (aSecondLightDirection.DirectionX == 0.0 && aSecondLightDirection.DirectionY == 0.0
+ && aSecondLightDirection.DirectionZ == 0.0)
+ aSecondLightDirection.DirectionZ = 1.0;
+ basegfx::B3DVector aLight2Vector(aSecondLightDirection.DirectionX, -aSecondLightDirection.DirectionY, aSecondLightDirection.DirectionZ);
+ aLight2Vector.normalize();
+
+ // Light Intensity
+
+ // For "FirstLight" the 3D-Scene light "1" is regularly used. In case of surface "Matte"
+ // the light 4 is used instead. For "SecondLight" the 3D-Scene light "2" is regularly used.
+ // In case first or second light is not harsh, the lights 5 to 8 are used in addition
+ // to get a soft light appearance.
+ // The 3D-Scene light "3" is currently not used.
+
+ // ODF default 66%. MS Office default 38000/65536=0.579 is set in import filter.
+ double fLight1Intensity = GetDouble(rGeometryItem, "FirstLightLevel", 66) / 100.0;
+ // ODF and MS Office have both default 'true'.
+ bool bFirstLightHarsh = GetBool(rGeometryItem, "FirstLightHarsh", true);
+ // ODF default 66%. MS Office default 38000/65536=0.579 is set in import filter
+ double fLight2Intensity = GetDouble(rGeometryItem, "SecondLightLevel", 66) / 100.0;
+ // ODF has default 'true'. MS Office default 'false' is set in import.
+ bool bSecondLightHarsh = GetBool(rGeometryItem, "SecondLightHarsh", true);
+
+ // ODF default 33%. MS Office default 20000/65536=0.305 is set in import filter.
+ double fAmbientIntensity = GetDouble(rGeometryItem, "Brightness", 33) / 100.0;
+
+ double fLight1IntensityForSpecular(fLight1Intensity); // remember original value
+ if (!bFirstLightHarsh || !bSecondLightHarsh) // might need softing lights
+ {
+ bool bNeedSoftLights(false); // catch case of lights with zero intensity.
+ basegfx::B3DVector aLight5Vector;
+ basegfx::B3DVector aLight6Vector;
+ basegfx::B3DVector aLight7Vector;
+ basegfx::B3DVector aLight8Vector;
+ // The needed light intensities depend on the angle between regular light and
+ // additional lights, currently for 60deg.
+ Color aHoriSoftLightColor;
+ Color aVertSoftLightColor;
+
+ if (!bSecondLightHarsh && fLight2Intensity > 0.0
+ && (bFirstLightHarsh || fLight1Intensity == 0.0)) // only second light soft
+ {
+ // That is default for shapes generated in the UI, for LO and MS Office as well.
+ bNeedSoftLights = true;
+ double fLight2SoftIntensity = fLight2Intensity * 0.40;
+ aHoriSoftLightColor = Color(basegfx::BColor(fLight2SoftIntensity).clamp());
+ aVertSoftLightColor = aHoriSoftLightColor;
+ fLight2Intensity *= 0.2;
+
+ lcl_SoftLightsDirection(aLight2Vector, aLight5Vector, aLight6Vector,
+ aLight7Vector, aLight8Vector);
+ }
+ else if (!bFirstLightHarsh && fLight1Intensity > 0.0
+ && (bSecondLightHarsh || fLight2Intensity == 0.0)) // only first light soft
+ {
+ bNeedSoftLights = true;
+ double fLight1SoftIntensity = fLight1Intensity * 0.40;
+ aHoriSoftLightColor = Color(basegfx::BColor(fLight1SoftIntensity).clamp());
+ aVertSoftLightColor = aHoriSoftLightColor;
+ fLight1Intensity *= 0.2;
+
+ lcl_SoftLightsDirection(aLight1Vector, aLight5Vector, aLight6Vector,
+ aLight7Vector, aLight8Vector);
+ }
+ else if (!bFirstLightHarsh && fLight1Intensity > 0.0 && !bSecondLightHarsh
+ && fLight2Intensity > 0.0) // both lights soft
+ {
+ bNeedSoftLights = true;
+ // We do not hat enough lights. We use two soft lights for FirstLight and two for
+ // SecondLight and double intensity.
+ double fLight1SoftIntensity = fLight1Intensity * 0.8;
+ fLight1Intensity *= 0.4;
+ aHoriSoftLightColor = Color(basegfx::BColor(fLight1SoftIntensity).clamp());
+ basegfx::B3DVector aDummy1, aDummy2;
+ lcl_SoftLightsDirection(aLight1Vector, aDummy1, aDummy2, aLight7Vector,
+ aLight8Vector);
+
+ double fLight2SoftIntensity = fLight2Intensity * 0.8;
+ aVertSoftLightColor = Color(basegfx::BColor(fLight2SoftIntensity).clamp());
+ fLight2Intensity *= 0.4;
+ lcl_SoftLightsDirection(aLight2Vector, aLight5Vector, aLight6Vector, aDummy1,
+ aDummy2);
+ }
+
+ if (bNeedSoftLights)
+ {
+ pScene->GetProperties().SetObjectItem(
+ makeSvx3DLightDirection5Item(aLight5Vector));
+ pScene->GetProperties().SetObjectItem(
+ makeSvx3DLightcolor5Item(aVertSoftLightColor));
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff5Item(true));
+ pScene->GetProperties().SetObjectItem(
+ makeSvx3DLightDirection6Item(aLight6Vector));
+ pScene->GetProperties().SetObjectItem(
+ makeSvx3DLightcolor6Item(aVertSoftLightColor));
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff6Item(true));
+ pScene->GetProperties().SetObjectItem(
+ makeSvx3DLightDirection7Item(aLight7Vector));
+ pScene->GetProperties().SetObjectItem(
+ makeSvx3DLightcolor7Item(aHoriSoftLightColor));
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff7Item(true));
+ pScene->GetProperties().SetObjectItem(
+ makeSvx3DLightDirection8Item(aLight8Vector));
+ pScene->GetProperties().SetObjectItem(
+ makeSvx3DLightcolor8Item(aHoriSoftLightColor));
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff8Item(true));
+ }
+ }
+
+ // ToDo: MSO seems to add half of the surplus to ambient color. ODF restricts value to <1.
+ if (fLight1Intensity > 1.0)
+ {
+ fAmbientIntensity += (fLight1Intensity - 1.0) / 2.0;
+ }
+
+ // ToDo: How to handle fAmbientIntensity larger 1.0 ? Perhaps lighten object color?
+
+ // Now set the regularly 3D-scene light attributes.
+ Color aAmbientColor(basegfx::BColor(fAmbientIntensity).clamp());
+ pScene->GetProperties().SetObjectItem(makeSvx3DAmbientcolorItem(aAmbientColor));
+
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightDirection1Item(aLight1Vector));
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff1Item(fLight1Intensity > 0.0));
+ Color aLight1Color(basegfx::BColor(fLight1Intensity).clamp());
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightcolor1Item(aLight1Color));
+
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightDirection2Item(aLight2Vector));
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff2Item(fLight2Intensity > 0.0));
+ Color aLight2Color(basegfx::BColor(fLight2Intensity).clamp());
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightcolor2Item(aLight2Color));
+
+ // Object reactions on light
+ // Diffusion, Specular-Color and -Intensity are object properties, not scene properties.
+ // Surface flag "Metal" is an object property too.
+
+ // Property "Diffusion" would correspond to style attribute "drd3:diffuse-color".
+ // But that is not implemented. We cannot ignore the attribute because MS Office sets
+ // attribute c3DDiffuseAmt to 43712 (Type Fixed 16.16, approx 66,9%) instead of MSO
+ // default 65536 (100%), if the user sets surface 'Metal' in the UI of MS Office.
+ // We will change the material color of the 3D object as ersatz.
+ // ODF data type is percent with default 0%. MSO default is set in import filter.
+ double fDiffusion = GetDouble(rGeometryItem, "Diffusion", 0.0) / 100.0;
+
+ // ODF standard specifies for value true: "the specular color for the shading of an
+ // extruded shape is gray (red, green and blue values of 200) instead of white and 15% is
+ // added to the specularity."
+ // Neither 'specularity' nor 'specular color' is clearly defined in the standard. ODF term
+ // 'specularity' seems to correspond to UI field 'Specular Intensity' for 3D scenes.
+ // MS Office uses current material color in case 'Metal' is set. To detect, whether
+ // rendering similar to MS Office has to be used the property 'MetalType' is used. It is
+ // set on import and in the extrusion bar.
+ bool bMetal = GetBool(rGeometryItem, "Metal", false);
+ sal_Int16 eMetalType(
+ GetMetalType(rGeometryItem, drawing::EnhancedCustomShapeMetalType::MetalODF));
+ bool bMetalMSCompatible
+ = eMetalType == drawing::EnhancedCustomShapeMetalType::MetalMSCompatible;
+
+ // Property "Specularity" corresponds to 3D object style attribute dr3d:specular-color.
+ double fSpecularity = GetDouble(rGeometryItem, "Specularity", 0) / 100.0;
+
+ if (bMetal && !bMetalMSCompatible)
+ {
+ fSpecularity *= 200.0 / 255.0;
+ }
+
+ // MS Office seems to render as if 'Specular Color' = Specularity * Light1Intensity.
+ double fShadingFactor = fLight1IntensityForSpecular * fSpecularity;
+ Color aSpecularCol(basegfx::BColor(fShadingFactor).clamp());
+ // In case of bMetalMSCompatible the color will be recalculated in the below loop.
+
+ // Shininess ODF default 50 (unit %). MS Office default 5, import filter makes *10.
+ // Shininess corresponds to "Specular Intensity" with the nonlinear relationship
+ // "Specular Intensity" = 2^c3DShininess = 2^("Shininess" / 10)
+ double fShininess = GetDouble(rGeometryItem, "Shininess", 50) / 10.0;
+ fShininess = std::clamp<double>(pow(2, fShininess), 0.0, 100.0);
+ sal_uInt16 nIntensity = static_cast<sal_uInt16>(basegfx::fround(fShininess));
+ if (bMetal && !bMetalMSCompatible)
+ {
+ nIntensity += 15; // as specified in ODF
+ nIntensity = std::clamp<sal_uInt16>(nIntensity, 0, 100);
+ }
+
+ SdrObjListIter aSceneIter(*pScene, SdrIterMode::DeepNoGroups);
+ while (aSceneIter.IsMore())
+ {
+ const SdrObject* pNext = aSceneIter.Next();
+
+ // Change material color as ersatz for missing style attribute "drd3:diffuse-color".
+ // For this ersatz we exclude case fDiffusion == 0.0, because for older documents this
+ // attribute is not written out to draw:extrusion-diffusion and ODF default 0 would
+ // produce black objects.
+ const Color& rMatColor
+ = pNext->GetProperties().GetItem(XATTR_FILLCOLOR).GetColorValue();
+ Color aOldMatColor(rMatColor);
+ if (basegfx::fTools::more(fDiffusion, 0.0)
+ && !basegfx::fTools::equal(fDiffusion, 1.0))
+ {
+ // Occurs e.g. with MS surface preset 'Metal'.
+ sal_uInt16 nHue;
+ sal_uInt16 nSaturation;
+ sal_uInt16 nBrightness;
+ rMatColor.RGBtoHSB(nHue, nSaturation, nBrightness);
+ nBrightness
+ = static_cast<sal_uInt16>(static_cast<double>(nBrightness) * fDiffusion);
+ nBrightness = std::clamp<sal_uInt16>(nBrightness, 0, 100);
+ Color aNewMatColor = Color::HSBtoRGB(nHue, nSaturation, nBrightness);
+ pNext->GetProperties().SetObjectItem(XFillColorItem("", aNewMatColor));
+ }
+
+ // Using material color instead of gray in case of MS Office compatible rendering.
+ if (bMetal && bMetalMSCompatible)
+ {
+ sal_uInt16 nHue;
+ sal_uInt16 nSaturation;
+ sal_uInt16 nBrightness;
+ aOldMatColor.RGBtoHSB(nHue, nSaturation, nBrightness);
+ nBrightness = static_cast<sal_uInt16>(static_cast<double>(nBrightness)
+ * fShadingFactor);
+ nBrightness = std::clamp<sal_uInt16>(nBrightness, 0, 100);
+ aSpecularCol = Color::HSBtoRGB(nHue, nSaturation, nBrightness);
+ }
+
+ pNext->GetProperties().SetObjectItem(makeSvx3DMaterialSpecularItem(aSpecularCol));
+ pNext->GetProperties().SetObjectItem(
+ makeSvx3DMaterialSpecularIntensityItem(nIntensity));
+ }
+
+ // fSpecularity = 0 is used to indicate surface preset "Matte".
+ if (basegfx::fTools::equalZero(fSpecularity))
+ {
+ // First light in LO 3D engine is always specular, all other lights are never specular.
+ // We copy light1 values to light4 and use it instead of light1 in the 3D scene.
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff1Item(false));
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff4Item(true));
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightcolor4Item(aLight1Color));
+ pScene->GetProperties().SetObjectItem(makeSvx3DLightDirection4Item(aLight1Vector));
+ }
+
+ // removing placeholder objects
+ for (E3dCompoundObject* pTemp : aPlaceholderObjectList)
+ {
+ pScene->RemoveObject( pTemp->GetOrdNum() );
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp2(pTemp);
+ SdrObject::Free(pTemp2);
+ }
+ }
+ else
+ {
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pScene);
+ SdrObject::Free(pTemp);
+ }
+ }
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShape3d.hxx b/svx/source/customshapes/EnhancedCustomShape3d.hxx
new file mode 100644
index 000000000..77e7d350f
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShape3d.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_CUSTOMSHAPES_ENHANCEDCUSTOMSHAPE3D_HXX
+#define INCLUDED_SVX_SOURCE_CUSTOMSHAPES_ENHANCEDCUSTOMSHAPE3D_HXX
+
+class SdrObject;
+class SdrObjCustomShape;
+
+class EnhancedCustomShape3d final
+{
+
+public:
+ static SdrObject* Create3DObject(
+ const SdrObject* pShape2d,
+ const SdrObjCustomShape& rSdrObjCustomShape);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShapeEngine.cxx b/svx/source/customshapes/EnhancedCustomShapeEngine.cxx
new file mode 100644
index 000000000..ae919904a
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShapeEngine.cxx
@@ -0,0 +1,488 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/drawing/XCustomShapeEngine.hpp>
+#include <svx/EnhancedCustomShape2d.hxx>
+#include "EnhancedCustomShape3d.hxx"
+#include "EnhancedCustomShapeFontWork.hxx"
+#include "EnhancedCustomShapeHandle.hxx"
+#include <svx/unoshape.hxx>
+#include <svx/unopage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/svdogrp.hxx>
+#include <editeng/outlobj.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svditer.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <com/sun/star/document/XActionLockable.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+class SdrObject;
+class SdrObjCustomShape;
+
+namespace {
+
+class EnhancedCustomShapeEngine : public cppu::WeakImplHelper
+<
+ css::lang::XInitialization,
+ css::lang::XServiceInfo,
+ css::drawing::XCustomShapeEngine
+>
+{
+ css::uno::Reference< css::drawing::XShape > mxShape;
+ bool mbForceGroupWithText;
+
+ std::unique_ptr<SdrObject, SdrObjectFreeOp> ImplForceGroupWithText(
+ const SdrObjCustomShape& rSdrObjCustomShape,
+ std::unique_ptr<SdrObject, SdrObjectFreeOp> pRenderedShape);
+
+public:
+ EnhancedCustomShapeEngine();
+
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XCustomShapeEngine
+ virtual css::uno::Reference< css::drawing::XShape > SAL_CALL render() override;
+ virtual css::awt::Rectangle SAL_CALL getTextBounds() override;
+ virtual css::drawing::PolyPolygonBezierCoords SAL_CALL getLineGeometry() override;
+ virtual css::uno::Sequence< css::uno::Reference< css::drawing::XCustomShapeHandle > > SAL_CALL getInteraction() override;
+};
+
+EnhancedCustomShapeEngine::EnhancedCustomShapeEngine() :
+ mbForceGroupWithText ( false )
+{
+}
+
+// XInterface
+void SAL_CALL EnhancedCustomShapeEngine::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+void SAL_CALL EnhancedCustomShapeEngine::release() noexcept
+{
+ OWeakObject::release();
+}
+
+// XInitialization
+void SAL_CALL EnhancedCustomShapeEngine::initialize( const Sequence< Any >& aArguments )
+{
+ Sequence< beans::PropertyValue > aParameter;
+ for ( const auto& rArgument : aArguments )
+ {
+ if ( rArgument >>= aParameter )
+ break;
+ }
+ for ( const beans::PropertyValue& rProp : std::as_const(aParameter) )
+ {
+ if ( rProp.Name == "CustomShape" )
+ rProp.Value >>= mxShape;
+ else if ( rProp.Name == "ForceGroupWithText" )
+ rProp.Value >>= mbForceGroupWithText;
+ }
+}
+
+// XServiceInfo
+OUString SAL_CALL EnhancedCustomShapeEngine::getImplementationName()
+{
+ return "com.sun.star.drawing.EnhancedCustomShapeEngine";
+}
+sal_Bool SAL_CALL EnhancedCustomShapeEngine::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+Sequence< OUString > SAL_CALL EnhancedCustomShapeEngine::getSupportedServiceNames()
+{
+ return { "com.sun.star.drawing.CustomShapeEngine" };
+}
+
+// XCustomShapeEngine
+std::unique_ptr<SdrObject, SdrObjectFreeOp> EnhancedCustomShapeEngine::ImplForceGroupWithText(
+ const SdrObjCustomShape& rSdrObjCustomShape,
+ std::unique_ptr<SdrObject, SdrObjectFreeOp> pRenderedShape)
+{
+ const bool bHasText(rSdrObjCustomShape.HasText());
+
+ if ( pRenderedShape || bHasText )
+ {
+ // applying shadow
+ const SdrObject* pShadowGeometry(rSdrObjCustomShape.GetSdrObjectShadowFromCustomShape());
+
+ if ( pShadowGeometry )
+ {
+ if ( pRenderedShape )
+ {
+ if ( dynamic_cast<const SdrObjGroup*>( pRenderedShape.get() ) == nullptr )
+ {
+ auto pTmp = std::move(pRenderedShape);
+ pRenderedShape.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject()));
+ static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() );
+ }
+
+ static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject(
+ pShadowGeometry->CloneSdrObject(pShadowGeometry->getSdrModelFromSdrObject()),
+ 0);
+ }
+ else
+ {
+ pRenderedShape.reset( pShadowGeometry->CloneSdrObject(pShadowGeometry->getSdrModelFromSdrObject()) );
+ }
+ }
+
+ // apply text
+ if ( bHasText )
+ {
+ // #i37011# also create a text object and add at rPos + 1
+ std::unique_ptr<SdrObject, SdrObjectFreeOp> pTextObj( SdrObjFactory::MakeNewObject(
+ rSdrObjCustomShape.getSdrModelFromSdrObject(),
+ rSdrObjCustomShape.GetObjInventor(),
+ SdrObjKind::Text) );
+
+ // Copy text content
+ OutlinerParaObject* pParaObj(rSdrObjCustomShape.GetOutlinerParaObject());
+
+ if( pParaObj )
+ pTextObj->NbcSetOutlinerParaObject( *pParaObj );
+
+ // copy all attributes
+ SfxItemSet aTargetItemSet(rSdrObjCustomShape.GetMergedItemSet());
+
+ // clear fill and line style
+ aTargetItemSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ aTargetItemSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+
+ // get the text bounds and set at text object
+ tools::Rectangle aTextBounds(rSdrObjCustomShape.GetSnapRect());
+ auto pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
+
+ if(pSdrObjCustomShape)
+ {
+ EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
+ aTextBounds = aCustomShape2d.GetTextRect();
+ }
+
+ pTextObj->SetSnapRect( aTextBounds );
+
+ // if rotated, copy GeoStat, too.
+ const GeoStat& rSourceGeo(rSdrObjCustomShape.GetGeoStat());
+ if ( rSourceGeo.nRotationAngle )
+ {
+ pTextObj->NbcRotate(
+ rSdrObjCustomShape.GetSnapRect().Center(),
+ rSourceGeo.nRotationAngle,
+ rSourceGeo.mfSinRotationAngle,
+ rSourceGeo.mfCosRotationAngle);
+ }
+
+ // set modified ItemSet at text object
+ pTextObj->SetMergedItemSet(aTargetItemSet);
+
+ if ( pRenderedShape )
+ {
+ if ( dynamic_cast<const SdrObjGroup*>( pRenderedShape.get() ) == nullptr )
+ {
+ auto pTmp = std::move(pRenderedShape);
+ pRenderedShape.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject()));
+ static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() );
+ }
+ static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTextObj.release() );
+ }
+ else
+ pRenderedShape = std::move(pTextObj);
+ }
+
+ // force group
+ if ( pRenderedShape )
+ {
+ if ( dynamic_cast<const SdrObjGroup*>( pRenderedShape.get() ) == nullptr )
+ {
+ auto pTmp = std::move(pRenderedShape);
+ pRenderedShape.reset(new SdrObjGroup(rSdrObjCustomShape.getSdrModelFromSdrObject()));
+ static_cast<SdrObjGroup*>(pRenderedShape.get())->GetSubList()->NbcInsertObject( pTmp.release() );
+ }
+ }
+ }
+
+ return pRenderedShape;
+}
+
+void SetTemporary( uno::Reference< drawing::XShape > const & xShape )
+{
+ if ( xShape.is() )
+ {
+ SvxShape* pShape = comphelper::getFromUnoTunnel<SvxShape>( xShape );
+ if ( pShape )
+ pShape->TakeSdrObjectOwnership();
+ }
+}
+
+Reference< drawing::XShape > SAL_CALL EnhancedCustomShapeEngine::render()
+{
+ SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
+
+ if(!pSdrObjCustomShape)
+ {
+ return Reference< drawing::XShape >();
+ }
+
+ // retrieving the TextPath property to check if feature is enabled
+ const SdrCustomShapeGeometryItem& rGeometryItem(pSdrObjCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
+ bool bTextPathOn = false;
+ const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "TextPath", "TextPath" );
+ if ( pAny )
+ *pAny >>= bTextPathOn;
+
+ EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
+ Degree100 nRotateAngle = aCustomShape2d.GetRotateAngle();
+
+ bool bFlipV = aCustomShape2d.IsFlipVert();
+ bool bFlipH = aCustomShape2d.IsFlipHorz();
+ bool bLineGeometryNeededOnly = bTextPathOn;
+
+ std::unique_ptr<SdrObject, SdrObjectFreeOp> xRenderedShape(aCustomShape2d.CreateObject(bLineGeometryNeededOnly));
+ if (xRenderedShape)
+ {
+ if ( bTextPathOn )
+ {
+ std::unique_ptr<SdrObject, SdrObjectFreeOp> xRenderedFontWork(
+ EnhancedCustomShapeFontWork::CreateFontWork(
+ xRenderedShape.get(),
+ *pSdrObjCustomShape));
+
+ if (xRenderedFontWork)
+ {
+ xRenderedShape = std::move(xRenderedFontWork);
+ }
+ }
+ std::unique_ptr<SdrObject, SdrObjectFreeOp> xRenderedShape3d(EnhancedCustomShape3d::Create3DObject(xRenderedShape.get(), *pSdrObjCustomShape));
+ if (xRenderedShape3d)
+ {
+ bFlipV = bFlipH = false;
+ nRotateAngle = 0_deg100;
+ xRenderedShape = std::move(xRenderedShape3d);
+ }
+
+ tools::Rectangle aRect(pSdrObjCustomShape->GetSnapRect());
+ const GeoStat& rGeoStat(pSdrObjCustomShape->GetGeoStat());
+
+ if ( rGeoStat.nShearAngle )
+ {
+ Degree100 nShearAngle = rGeoStat.nShearAngle;
+ double nTan = rGeoStat.mfTanShearAngle;
+ if (bFlipV != bFlipH)
+ {
+ nShearAngle = -nShearAngle;
+ nTan = -nTan;
+ }
+
+ xRenderedShape->Shear(pSdrObjCustomShape->GetSnapRect().Center(), nShearAngle, nTan, false);
+ }
+ if(nRotateAngle )
+ xRenderedShape->NbcRotate(pSdrObjCustomShape->GetSnapRect().Center(), nRotateAngle);
+ if ( bFlipV )
+ {
+ Point aLeft( aRect.Left(), ( aRect.Top() + aRect.Bottom() ) >> 1 );
+ Point aRight( aLeft.X() + 1000, aLeft.Y() );
+ xRenderedShape->NbcMirror( aLeft, aRight );
+ }
+ if ( bFlipH )
+ {
+ Point aTop( ( aRect.Left() + aRect.Right() ) >> 1, aRect.Top() );
+ Point aBottom( aTop.X(), aTop.Y() + 1000 );
+ xRenderedShape->NbcMirror( aTop, aBottom );
+ }
+
+ xRenderedShape->NbcSetStyleSheet(pSdrObjCustomShape->GetStyleSheet(), true);
+ xRenderedShape->RecalcSnapRect();
+ }
+
+ if ( mbForceGroupWithText )
+ {
+ xRenderedShape = ImplForceGroupWithText(
+ *pSdrObjCustomShape,
+ std::move(xRenderedShape));
+ }
+
+ Reference< drawing::XShape > xShape;
+
+ if (xRenderedShape)
+ {
+ aCustomShape2d.ApplyGluePoints(xRenderedShape.get());
+ SdrObject* pRenderedShape = xRenderedShape.release();
+ xShape = SvxDrawPage::CreateShapeByTypeAndInventor( pRenderedShape->GetObjIdentifier(),
+ pRenderedShape->GetObjInventor(), pRenderedShape );
+ }
+
+ SetTemporary( xShape );
+
+ return xShape;
+}
+
+awt::Rectangle SAL_CALL EnhancedCustomShapeEngine::getTextBounds()
+{
+ awt::Rectangle aTextRect;
+ if (SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape)))
+ {
+ uno::Reference< document::XActionLockable > xLockable( mxShape, uno::UNO_QUERY );
+
+ if(xLockable.is() && !xLockable->isActionLocked())
+ {
+ EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
+ tools::Rectangle aRect( aCustomShape2d.GetTextRect() );
+ aTextRect.X = aRect.Left();
+ aTextRect.Y = aRect.Top();
+ aTextRect.Width = aRect.GetWidth();
+ aTextRect.Height = aRect.GetHeight();
+ }
+ }
+
+ return aTextRect;
+}
+
+drawing::PolyPolygonBezierCoords SAL_CALL EnhancedCustomShapeEngine::getLineGeometry()
+{
+ drawing::PolyPolygonBezierCoords aPolyPolygonBezierCoords;
+ SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
+
+ if(pSdrObjCustomShape)
+ {
+ EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
+ SdrObjectUniquePtr pObj = aCustomShape2d.CreateLineGeometry();
+
+ if ( pObj )
+ {
+ tools::Rectangle aRect(pSdrObjCustomShape->GetSnapRect());
+ bool bFlipV = aCustomShape2d.IsFlipVert();
+ bool bFlipH = aCustomShape2d.IsFlipHorz();
+ const GeoStat& rGeoStat(pSdrObjCustomShape->GetGeoStat());
+
+ if ( rGeoStat.nShearAngle )
+ {
+ Degree100 nShearAngle = rGeoStat.nShearAngle;
+ double nTan = rGeoStat.mfTanShearAngle;
+ if (bFlipV != bFlipH)
+ {
+ nShearAngle = -nShearAngle;
+ nTan = -nTan;
+ }
+ pObj->Shear( aRect.Center(), nShearAngle, nTan, false);
+ }
+ Degree100 nRotateAngle = aCustomShape2d.GetRotateAngle();
+ if( nRotateAngle )
+ pObj->NbcRotate( aRect.Center(), nRotateAngle );
+ if ( bFlipH )
+ {
+ Point aTop( ( aRect.Left() + aRect.Right() ) >> 1, aRect.Top() );
+ Point aBottom( aTop.X(), aTop.Y() + 1000 );
+ pObj->NbcMirror( aTop, aBottom );
+ }
+ if ( bFlipV )
+ {
+ Point aLeft( aRect.Left(), ( aRect.Top() + aRect.Bottom() ) >> 1 );
+ Point aRight( aLeft.X() + 1000, aLeft.Y() );
+ pObj->NbcMirror( aLeft, aRight );
+ }
+
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ SdrObjListIter aIter( *pObj, SdrIterMode::DeepWithGroups );
+
+ while ( aIter.IsMore() )
+ {
+ basegfx::B2DPolyPolygon aPP;
+ const SdrObject* pNext = aIter.Next();
+
+ if ( auto pPathObj = dynamic_cast<const SdrPathObj*>(pNext) )
+ {
+ aPP = pPathObj->GetPathPoly();
+ }
+ else
+ {
+ SdrObjectUniquePtr pNewObj = pNext->ConvertToPolyObj( false, false );
+ SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pNewObj.get() );
+ if ( pPath )
+ aPP = pPath->GetPathPoly();
+ }
+
+ if ( aPP.count() )
+ aPolyPolygon.append(aPP);
+ }
+ pObj.reset();
+ basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( aPolyPolygon,
+ aPolyPolygonBezierCoords );
+ }
+ }
+
+ return aPolyPolygonBezierCoords;
+}
+
+Sequence< Reference< drawing::XCustomShapeHandle > > SAL_CALL EnhancedCustomShapeEngine::getInteraction()
+{
+ sal_uInt32 i, nHdlCount = 0;
+ SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxShape));
+
+ if(pSdrObjCustomShape)
+ {
+ EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
+ nHdlCount = aCustomShape2d.GetHdlCount();
+ }
+
+ Sequence< Reference< drawing::XCustomShapeHandle > > aSeq( nHdlCount );
+ auto aSeqRange = asNonConstRange(aSeq);
+
+ for ( i = 0; i < nHdlCount; i++ )
+ aSeqRange[ i ] = new EnhancedCustomShapeHandle( mxShape, i );
+ return aSeq;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_drawing_EnhancedCustomShapeEngine_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new EnhancedCustomShapeEngine);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx b/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx
new file mode 100644
index 000000000..0043b69cd
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx
@@ -0,0 +1,956 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "EnhancedCustomShapeFontWork.hxx"
+#include <svl/itemset.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svdopath.hxx>
+#include <vcl/metric.hxx>
+#include <svx/sdasitm.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/svditer.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/sdshitm.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <o3tl/numeric.hxx>
+#include <vector>
+#include <numeric>
+#include <algorithm>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/i18n/BreakIterator.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sal/log.hxx>
+#include <rtl/math.hxx>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+
+namespace {
+
+struct FWCharacterData // representing a single character
+{
+ std::vector< tools::PolyPolygon > vOutlines;
+ tools::Rectangle aBoundRect;
+};
+struct FWParagraphData // representing a single paragraph
+{
+ OUString aString;
+ std::vector< FWCharacterData > vCharacters;
+ tools::Rectangle aBoundRect;
+ SvxFrameDirection nFrameDirection;
+};
+struct FWTextArea // representing multiple concluding paragraphs
+{
+ std::vector< FWParagraphData > vParagraphs;
+ tools::Rectangle aBoundRect;
+};
+struct FWData // representing the whole text
+{
+ std::vector< FWTextArea > vTextAreas;
+ double fHorizontalTextScaling;
+ double fVerticalTextScaling;
+ sal_uInt32 nMaxParagraphsPerTextArea;
+ sal_Int32 nSingleLineHeight;
+ bool bSingleLineMode;
+ bool bScaleX;
+};
+
+}
+
+static bool InitializeFontWorkData(
+ const SdrObjCustomShape& rSdrObjCustomShape,
+ const sal_uInt16 nOutlinesCount2d,
+ FWData& rFWData)
+{
+ bool bNoErr = false;
+ bool bSingleLineMode = false;
+ sal_uInt16 nTextAreaCount = nOutlinesCount2d;
+ if ( nOutlinesCount2d & 1 )
+ bSingleLineMode = true;
+ else
+ nTextAreaCount >>= 1;
+
+ const SdrCustomShapeGeometryItem& rGeometryItem( rSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ const css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "TextPath", "ScaleX" );
+ if (pAny)
+ *pAny >>= rFWData.bScaleX;
+ else
+ rFWData.bScaleX = false;
+
+ if ( nTextAreaCount )
+ {
+ rFWData.bSingleLineMode = bSingleLineMode;
+
+ // setting the strings
+ OutlinerParaObject* pParaObj(rSdrObjCustomShape.GetOutlinerParaObject());
+
+ if ( pParaObj )
+ {
+ const EditTextObject& rTextObj = pParaObj->GetTextObject();
+ sal_Int32 nParagraphsLeft = rTextObj.GetParagraphCount();
+
+ rFWData.nMaxParagraphsPerTextArea = ( ( nParagraphsLeft - 1 ) / nTextAreaCount ) + 1;
+ sal_Int32 j = 0;
+ while( nParagraphsLeft && nTextAreaCount )
+ {
+ FWTextArea aTextArea;
+ sal_Int32 i, nParagraphs = ( ( nParagraphsLeft - 1 ) / nTextAreaCount ) + 1;
+ for ( i = 0; i < nParagraphs; ++i, ++j )
+ {
+ FWParagraphData aParagraphData;
+ aParagraphData.aString = rTextObj.GetText( j );
+
+ const SfxItemSet& rParaSet = rTextObj.GetParaAttribs( j ); // retrieving some paragraph attributes
+ aParagraphData.nFrameDirection = rParaSet.Get( EE_PARA_WRITINGDIR ).GetValue();
+ aTextArea.vParagraphs.push_back( aParagraphData );
+ }
+ rFWData.vTextAreas.push_back( aTextArea );
+ nParagraphsLeft -= nParagraphs;
+ nTextAreaCount--;
+ }
+ bNoErr = true;
+ }
+ }
+ return bNoErr;
+}
+
+static double GetLength( const tools::Polygon& rPolygon )
+{
+ double fLength = 0;
+ if ( rPolygon.GetSize() > 1 )
+ {
+ sal_uInt16 nCount = rPolygon.GetSize();
+ while( --nCount )
+ fLength += rPolygon.CalcDistance( nCount, nCount - 1 );
+ }
+ return fLength;
+}
+
+
+/* CalculateHorizontalScalingFactor returns the horizontal scaling factor for
+the whole text object, so that each text will match its corresponding 2d Outline */
+static void CalculateHorizontalScalingFactor(
+ const SdrObjCustomShape& rSdrObjCustomShape,
+ FWData& rFWData,
+ const tools::PolyPolygon& rOutline2d)
+{
+ double fScalingFactor = 1.0;
+ rFWData.fVerticalTextScaling = 1.0;
+
+ sal_uInt16 i = 0;
+ bool bSingleLineMode = false;
+ sal_uInt16 nOutlinesCount2d = rOutline2d.Count();
+
+ vcl::Font aFont;
+ const SvxFontItem& rFontItem( rSdrObjCustomShape.GetMergedItem( EE_CHAR_FONTINFO ) );
+ const SvxFontHeightItem& rFontHeight( rSdrObjCustomShape.GetMergedItem( EE_CHAR_FONTHEIGHT ) );
+ sal_Int32 nFontSize = rFontHeight.GetHeight();
+
+ SAL_WARN_IF(nFontSize > SAL_MAX_INT16, "svx", "CalculateHorizontalScalingFactor suspiciously large font height: " << nFontSize);
+
+ if (rFWData.bScaleX)
+ aFont.SetFontHeight( nFontSize );
+ else
+ aFont.SetFontHeight( rSdrObjCustomShape.GetLogicRect().GetHeight() / rFWData.nMaxParagraphsPerTextArea );
+
+ aFont.SetAlignment( ALIGN_TOP );
+ aFont.SetFamilyName( rFontItem.GetFamilyName() );
+ aFont.SetFamily( rFontItem.GetFamily() );
+ aFont.SetStyleName( rFontItem.GetStyleName() );
+ const SvxPostureItem& rPostureItem = rSdrObjCustomShape.GetMergedItem( EE_CHAR_ITALIC );
+ aFont.SetItalic( rPostureItem.GetPosture() );
+
+ const SvxWeightItem& rWeightItem = rSdrObjCustomShape.GetMergedItem( EE_CHAR_WEIGHT );
+ aFont.SetWeight( rWeightItem.GetWeight() );
+ aFont.SetOrientation( 0_deg10 );
+ // initializing virtual device
+
+ ScopedVclPtrInstance< VirtualDevice > pVirDev(DeviceFormat::DEFAULT);
+ pVirDev->SetMapMode(MapMode(MapUnit::Map100thMM));
+ pVirDev->SetFont( aFont );
+
+ if ( nOutlinesCount2d & 1 )
+ bSingleLineMode = true;
+
+ // In case of rFWData.bScaleX == true it loops with reduced font size until the current run
+ // results in a fScalingFactor >=1.0. The fact, that case rFWData.bScaleX == true keeps font
+ // size if possible, is not done here with scaling factor 1 but is done in method
+ // FitTextOutlinesToShapeOutlines()
+ do
+ {
+ i = 0;
+ bool bScalingFactorDefined = false; // New calculation for each font size
+ for( const auto& rTextArea : rFWData.vTextAreas )
+ {
+ // calculating the width of the corresponding 2d text area
+ double fWidth = GetLength( rOutline2d.GetObject( i++ ) );
+ if ( !bSingleLineMode )
+ {
+ fWidth += GetLength( rOutline2d.GetObject( i++ ) );
+ fWidth /= 2.0;
+ }
+
+ for( const auto& rParagraph : rTextArea.vParagraphs )
+ {
+ double fTextWidth = pVirDev->GetTextWidth( rParagraph.aString );
+ if ( fTextWidth > 0.0 )
+ {
+ double fScale = fWidth / fTextWidth;
+ if ( !bScalingFactorDefined )
+ {
+ fScalingFactor = fScale;
+ bScalingFactorDefined = true;
+ }
+ else if (fScale < fScalingFactor)
+ {
+ fScalingFactor = fScale;
+ }
+ }
+ }
+ }
+
+ if (fScalingFactor < 1.0)
+ {
+ // if we have a very large font that will require scaling down to a very small value then
+ // skip directly to a small font size
+ if (nFontSize > 128)
+ {
+ double nEstimatedFinalFontSize = nFontSize * fScalingFactor;
+ double nOnePercentFontSize = nFontSize / 100.0;
+ if (nEstimatedFinalFontSize < nOnePercentFontSize)
+ {
+ nFontSize = std::max<int>(16, std::ceil(5 * nEstimatedFinalFontSize));
+ SAL_WARN("svx", "CalculateHorizontalScalingFactor skipping direct to: " << nFontSize << " from " << rFontHeight.GetHeight());
+ }
+ }
+ nFontSize--;
+ aFont.SetFontHeight( nFontSize );
+ pVirDev->SetFont( aFont );
+ }
+ }
+ while (rFWData.bScaleX && fScalingFactor < 1.0 && nFontSize > 1 );
+
+ if (nFontSize > 1)
+ rFWData.fVerticalTextScaling = static_cast<double>(nFontSize) / rFontHeight.GetHeight();
+
+ rFWData.fHorizontalTextScaling = fScalingFactor;
+}
+
+static void GetTextAreaOutline(
+ const FWData& rFWData,
+ const SdrObjCustomShape& rSdrObjCustomShape,
+ FWTextArea& rTextArea,
+ bool bSameLetterHeights)
+{
+ bool bIsVertical(rSdrObjCustomShape.IsVerticalWriting());
+ sal_Int32 nVerticalOffset = rFWData.nMaxParagraphsPerTextArea > rTextArea.vParagraphs.size()
+ ? rFWData.nSingleLineHeight / 2 : 0;
+
+ for( auto& rParagraph : rTextArea.vParagraphs )
+ {
+ const OUString& rText = rParagraph.aString;
+ if ( !rText.isEmpty() )
+ {
+ // generating vcl/font
+ sal_uInt16 nScriptType = i18n::ScriptType::LATIN;
+ Reference< i18n::XBreakIterator > xBI( EnhancedCustomShapeFontWork::GetBreakIterator() );
+ if ( xBI.is() )
+ {
+ nScriptType = xBI->getScriptType( rText, 0 );
+ if( i18n::ScriptType::WEAK == nScriptType )
+ {
+ sal_Int32 nChg = xBI->endOfScript( rText, 0, nScriptType );
+ if (nChg < rText.getLength() && nChg >= 0)
+ nScriptType = xBI->getScriptType( rText, nChg );
+ else
+ nScriptType = i18n::ScriptType::LATIN;
+ }
+ }
+ sal_uInt16 nFntItm = EE_CHAR_FONTINFO;
+ if ( nScriptType == i18n::ScriptType::COMPLEX )
+ nFntItm = EE_CHAR_FONTINFO_CTL;
+ else if ( nScriptType == i18n::ScriptType::ASIAN )
+ nFntItm = EE_CHAR_FONTINFO_CJK;
+ const SvxFontItem& rFontItem = static_cast<const SvxFontItem&>(rSdrObjCustomShape.GetMergedItem( nFntItm ));
+ vcl::Font aFont;
+
+ aFont.SetFontHeight( rFWData.nSingleLineHeight );
+
+ aFont.SetAlignment( ALIGN_TOP );
+
+ aFont.SetFamilyName( rFontItem.GetFamilyName() );
+ aFont.SetFamily( rFontItem.GetFamily() );
+ aFont.SetStyleName( rFontItem.GetStyleName() );
+ aFont.SetOrientation( 0_deg10 );
+
+ const SvxPostureItem& rPostureItem = rSdrObjCustomShape.GetMergedItem( EE_CHAR_ITALIC );
+ aFont.SetItalic( rPostureItem.GetPosture() );
+
+ const SvxWeightItem& rWeightItem = rSdrObjCustomShape.GetMergedItem( EE_CHAR_WEIGHT );
+ aFont.SetWeight( rWeightItem.GetWeight() );
+
+ // initializing virtual device
+ ScopedVclPtrInstance< VirtualDevice > pVirDev(DeviceFormat::DEFAULT);
+ pVirDev->SetMapMode(MapMode(MapUnit::Map100thMM));
+ pVirDev->SetFont( aFont );
+ pVirDev->EnableRTL();
+ if ( rParagraph.nFrameDirection == SvxFrameDirection::Horizontal_RL_TB )
+ pVirDev->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::BiDiRtl );
+
+ const SvxCharScaleWidthItem& rCharScaleWidthItem = rSdrObjCustomShape.GetMergedItem( EE_CHAR_FONTWIDTH );
+ sal_uInt16 nCharScaleWidth = rCharScaleWidthItem.GetValue();
+ sal_Int32 nWidth = 0;
+
+ // VERTICAL
+ if ( bIsVertical )
+ {
+ // vertical _> each single character needs to be rotated by 90
+ sal_Int32 i;
+ sal_Int32 nHeight = 0;
+ tools::Rectangle aSingleCharacterUnion;
+ for ( i = 0; i < rText.getLength(); i++ )
+ {
+ FWCharacterData aCharacterData;
+ OUString aCharText( rText[ i ] );
+ if ( pVirDev->GetTextOutlines( aCharacterData.vOutlines, aCharText, 0, 0, -1, nWidth, {} ) )
+ {
+ sal_Int32 nTextWidth = pVirDev->GetTextWidth( aCharText);
+ if ( aCharacterData.vOutlines.empty() )
+ {
+ nHeight += rFWData.nSingleLineHeight;
+ }
+ else
+ {
+ for ( auto& rOutline : aCharacterData.vOutlines )
+ {
+ // rotating
+ rOutline.Rotate( Point( nTextWidth / 2, rFWData.nSingleLineHeight / 2 ), 900_deg10 );
+ aCharacterData.aBoundRect.Union( rOutline.GetBoundRect() );
+ }
+ for ( auto& rOutline : aCharacterData.vOutlines )
+ {
+ sal_Int32 nM = - aCharacterData.aBoundRect.Left() + nHeight;
+ rOutline.Move( nM, 0 );
+ aCharacterData.aBoundRect.Move( nM, 0 );
+ }
+ nHeight += aCharacterData.aBoundRect.GetWidth() + ( rFWData.nSingleLineHeight / 5 );
+ aSingleCharacterUnion.Union( aCharacterData.aBoundRect );
+ }
+ }
+ rParagraph.vCharacters.push_back( aCharacterData );
+ }
+ for ( auto& rCharacter : rParagraph.vCharacters )
+ {
+ for ( auto& rOutline : rCharacter.vOutlines )
+ {
+ rOutline.Move( ( aSingleCharacterUnion.GetWidth() - rCharacter.aBoundRect.GetWidth() ) / 2, 0 );
+ }
+ }
+ }
+ else
+ {
+ std::vector<sal_Int32> aDXArry;
+ if ( ( nCharScaleWidth != 100 ) && nCharScaleWidth )
+ { // applying character spacing
+ pVirDev->GetTextArray( rText, &aDXArry);
+ FontMetric aFontMetric( pVirDev->GetFontMetric() );
+ aFont.SetAverageFontWidth( static_cast<sal_Int32>( static_cast<double>(aFontMetric.GetAverageFontWidth()) * ( double(100) / static_cast<double>(nCharScaleWidth) ) ) );
+ pVirDev->SetFont( aFont );
+ }
+ FWCharacterData aCharacterData;
+ if ( pVirDev->GetTextOutlines( aCharacterData.vOutlines, rText, 0, 0, -1, nWidth, aDXArry ) )
+ {
+ rParagraph.vCharacters.push_back( aCharacterData );
+ }
+ else
+ {
+ // GetTextOutlines failed what usually means that it is
+ // not implemented. To make FontWork not fail (it is
+ // dependent of graphic content to get a Range) create
+ // a rectangle substitution for now
+ pVirDev->GetTextArray( rText, &aDXArry);
+ aCharacterData.vOutlines.clear();
+
+ if(aDXArry.size())
+ {
+ for(size_t a(0); a < aDXArry.size(); a++)
+ {
+ const basegfx::B2DPolygon aPolygon(
+ basegfx::utils::createPolygonFromRect(
+ basegfx::B2DRange(
+ 0 == a ? 0 : aDXArry[a - 1],
+ 0,
+ aDXArry[a],
+ aFont.GetFontHeight()
+ )));
+ aCharacterData.vOutlines.push_back(tools::PolyPolygon(tools::Polygon(aPolygon)));
+ }
+ }
+ else
+ {
+ const basegfx::B2DPolygon aPolygon(
+ basegfx::utils::createPolygonFromRect(
+ basegfx::B2DRange(
+ 0,
+ 0,
+ aDXArry.empty() ? 10 : aDXArry.back(),
+ aFont.GetFontHeight()
+ )));
+ aCharacterData.vOutlines.push_back(tools::PolyPolygon(tools::Polygon(aPolygon)));
+ }
+
+
+ rParagraph.vCharacters.push_back( aCharacterData );
+ }
+ }
+
+ // vertical alignment
+ for ( auto& rCharacter : rParagraph.vCharacters )
+ {
+ for( tools::PolyPolygon& rPolyPoly : rCharacter.vOutlines )
+ {
+ if ( nVerticalOffset )
+ rPolyPoly.Move( 0, nVerticalOffset );
+
+ // retrieving the boundrect for the paragraph
+ tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
+ rParagraph.aBoundRect.Union( aBoundRect );
+ }
+ }
+ }
+ // updating the boundrect for the text area by merging the current paragraph boundrect
+ if ( rParagraph.aBoundRect.IsEmpty() )
+ {
+ if ( rTextArea.aBoundRect.IsEmpty() )
+ rTextArea.aBoundRect = tools::Rectangle( Point( 0, 0 ), Size( 1, rFWData.nSingleLineHeight ) );
+ else
+ rTextArea.aBoundRect.AdjustBottom(rFWData.nSingleLineHeight );
+ }
+ else
+ {
+ tools::Rectangle& rParagraphBoundRect = rParagraph.aBoundRect;
+ rTextArea.aBoundRect.Union( rParagraphBoundRect );
+
+ if ( bSameLetterHeights )
+ {
+ for ( auto& rCharacter : rParagraph.vCharacters )
+ {
+ for( auto& rOutline : rCharacter.vOutlines )
+ {
+ tools::Rectangle aPolyPolyBoundRect( rOutline.GetBoundRect() );
+ if (aPolyPolyBoundRect.GetHeight() != rParagraphBoundRect.GetHeight() && aPolyPolyBoundRect.GetHeight())
+ rOutline.Scale( 1.0, static_cast<double>(rParagraphBoundRect.GetHeight()) / aPolyPolyBoundRect.GetHeight() );
+ aPolyPolyBoundRect = rOutline.GetBoundRect();
+ sal_Int32 nMove = aPolyPolyBoundRect.Top() - rParagraphBoundRect.Top();
+ if ( nMove )
+ rOutline.Move( 0, -nMove );
+ }
+ }
+ }
+ }
+ if ( bIsVertical )
+ nVerticalOffset -= rFWData.nSingleLineHeight;
+ else
+ nVerticalOffset += rFWData.nSingleLineHeight;
+ }
+}
+
+static bool GetFontWorkOutline(
+ FWData& rFWData,
+ const SdrObjCustomShape& rSdrObjCustomShape)
+{
+ SdrTextHorzAdjust eHorzAdjust(rSdrObjCustomShape.GetMergedItem( SDRATTR_TEXT_HORZADJUST ).GetValue());
+ drawing::TextFitToSizeType const eFTS(rSdrObjCustomShape.GetMergedItem( SDRATTR_TEXT_FITTOSIZE ).GetValue());
+
+ bool bSameLetterHeights = false;
+ const SdrCustomShapeGeometryItem& rGeometryItem(rSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
+ const css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "TextPath", "SameLetterHeights" );
+ if ( pAny )
+ *pAny >>= bSameLetterHeights;
+
+ const SvxFontHeightItem& rFontHeight( rSdrObjCustomShape.GetMergedItem( EE_CHAR_FONTHEIGHT ) );
+ if (rFWData.bScaleX)
+ rFWData.nSingleLineHeight = rFWData.fVerticalTextScaling * rFontHeight.GetHeight();
+ else
+ rFWData.nSingleLineHeight = static_cast<sal_Int32>( ( static_cast<double>( rSdrObjCustomShape.GetLogicRect().GetHeight() )
+ / rFWData.nMaxParagraphsPerTextArea ) * rFWData.fHorizontalTextScaling );
+
+ if (rFWData.nSingleLineHeight == SAL_MIN_INT32)
+ return false;
+
+ for ( auto& rTextArea : rFWData.vTextAreas )
+ {
+ GetTextAreaOutline(
+ rFWData,
+ rSdrObjCustomShape,
+ rTextArea,
+ bSameLetterHeights);
+
+ if (eFTS == drawing::TextFitToSizeType_ALLLINES ||
+ // tdf#97630 interpret PROPORTIONAL same as ALLLINES so we don't
+ // need another ODF attribute!
+ eFTS == drawing::TextFitToSizeType_PROPORTIONAL)
+ {
+ for ( auto& rParagraph : rTextArea.vParagraphs )
+ {
+ sal_Int32 nParaWidth = rParagraph.aBoundRect.GetWidth();
+ if ( nParaWidth )
+ {
+ double fScale = static_cast<double>(rTextArea.aBoundRect.GetWidth()) / nParaWidth;
+
+ for ( auto& rCharacter : rParagraph.vCharacters )
+ {
+ for( auto& rOutline : rCharacter.vOutlines )
+ {
+ rOutline.Scale( fScale, 1.0 );
+ }
+ }
+ }
+ }
+ }
+ else if (rFWData.bScaleX)
+ {
+ const SdrTextVertAdjust nVertJustify = rSdrObjCustomShape.GetMergedItem( SDRATTR_TEXT_VERTADJUST ).GetValue();
+ double fFactor = nVertJustify == SdrTextVertAdjust::SDRTEXTVERTADJUST_BOTTOM ? -0.5 : ( nVertJustify == SdrTextVertAdjust::SDRTEXTVERTADJUST_TOP ? 0.5 : 0 );
+
+ for ( auto& rParagraph : rTextArea.vParagraphs )
+ {
+ sal_Int32 nHorzDiff = 0;
+ sal_Int32 nVertDiff = static_cast<double>( rFWData.nSingleLineHeight ) * fFactor * ( rTextArea.vParagraphs.size() - 1 );
+
+ if ( eHorzAdjust == SDRTEXTHORZADJUST_CENTER )
+ nHorzDiff = ( rFWData.fHorizontalTextScaling * rTextArea.aBoundRect.GetWidth() - rParagraph.aBoundRect.GetWidth() ) / 2;
+ else if ( eHorzAdjust == SDRTEXTHORZADJUST_RIGHT )
+ nHorzDiff = ( rFWData.fHorizontalTextScaling * rTextArea.aBoundRect.GetWidth() - rParagraph.aBoundRect.GetWidth() );
+
+ if (nHorzDiff || nVertDiff)
+ {
+ for ( auto& rCharacter : rParagraph.vCharacters )
+ {
+ for( auto& rOutline : rCharacter.vOutlines )
+ {
+ rOutline.Move( nHorzDiff, nVertDiff );
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ switch( eHorzAdjust )
+ {
+ case SDRTEXTHORZADJUST_RIGHT :
+ case SDRTEXTHORZADJUST_CENTER:
+ {
+ for ( auto& rParagraph : rTextArea.vParagraphs )
+ {
+ sal_Int32 nHorzDiff = 0;
+ if ( eHorzAdjust == SDRTEXTHORZADJUST_CENTER )
+ nHorzDiff = ( rTextArea.aBoundRect.GetWidth() - rParagraph.aBoundRect.GetWidth() ) / 2;
+ else if ( eHorzAdjust == SDRTEXTHORZADJUST_RIGHT )
+ nHorzDiff = ( rTextArea.aBoundRect.GetWidth() - rParagraph.aBoundRect.GetWidth() );
+ if ( nHorzDiff )
+ {
+ for ( auto& rCharacter : rParagraph.vCharacters )
+ {
+ for( auto& rOutline : rCharacter.vOutlines )
+ {
+ rOutline.Move( nHorzDiff, 0 );
+ }
+ }
+ }
+ }
+ }
+ break;
+ default:
+ case SDRTEXTHORZADJUST_BLOCK : break; // don't know
+ case SDRTEXTHORZADJUST_LEFT : break; // already left aligned -> nothing to do
+ }
+ }
+ }
+
+ return true;
+}
+
+static basegfx::B2DPolyPolygon GetOutlinesFromShape2d( const SdrObject* pShape2d )
+{
+ basegfx::B2DPolyPolygon aOutlines2d;
+
+ SdrObjListIter aObjListIter( *pShape2d, SdrIterMode::DeepWithGroups );
+ while( aObjListIter.IsMore() )
+ {
+ SdrObject* pPartObj = aObjListIter.Next();
+ if ( auto pPathObj = dynamic_cast<const SdrPathObj*>( pPartObj))
+ {
+ basegfx::B2DPolyPolygon aCandidate(pPathObj->GetPathPoly());
+ if(aCandidate.areControlPointsUsed())
+ {
+ aCandidate = basegfx::utils::adaptiveSubdivideByAngle(aCandidate);
+ }
+ aOutlines2d.append(aCandidate);
+ }
+ }
+
+ return aOutlines2d;
+}
+
+static void CalcDistances( const tools::Polygon& rPoly, std::vector< double >& rDistances )
+{
+ sal_uInt16 i, nCount = rPoly.GetSize();
+ if ( nCount <= 1 )
+ return;
+
+ for ( i = 0; i < nCount; i++ )
+ {
+ double fDistance = i ? rPoly.CalcDistance( i, i - 1 ) : 0.0;
+ rDistances.push_back( fDistance );
+ }
+ std::partial_sum( rDistances.begin(), rDistances.end(), rDistances.begin() );
+ double fLength = rDistances[ rDistances.size() - 1 ];
+ if ( fLength > 0.0 )
+ {
+ for ( auto& rDistance : rDistances )
+ rDistance /= fLength;
+ }
+}
+
+static void InsertMissingOutlinePoints( const std::vector< double >& rDistances,
+ const tools::Rectangle& rTextAreaBoundRect, tools::Polygon& rPoly )
+{
+ sal_uInt16 nSize = rPoly.GetSize();
+ if (nSize == 0)
+ return;
+
+ tools::Long nTextWidth = rTextAreaBoundRect.GetWidth();
+
+ if (nTextWidth == 0)
+ throw o3tl::divide_by_zero();
+
+ double fLastDistance = 0.0;
+ for (sal_uInt16 i = 0; i < nSize; ++i)
+ {
+ Point& rPoint = rPoly[ i ];
+ double fDistance = static_cast<double>( rPoint.X() - rTextAreaBoundRect.Left() ) / static_cast<double>(nTextWidth);
+ if ( i )
+ {
+ if ( fDistance > fLastDistance )
+ {
+ std::vector< double >::const_iterator aIter = std::upper_bound( rDistances.begin(), rDistances.end(), fLastDistance );
+ if ( aIter != rDistances.end() && ( *aIter > fLastDistance ) && ( *aIter < fDistance ) )
+ {
+ Point& rPt0 = rPoly[ i - 1 ];
+ sal_Int32 fX = rPoint.X() - rPt0.X();
+ sal_Int32 fY = rPoint.Y() - rPt0.Y();
+ double fd = ( 1.0 / ( fDistance - fLastDistance ) ) * ( *aIter - fLastDistance );
+ rPoly.Insert( i, Point( static_cast<sal_Int32>( rPt0.X() + fX * fd ), static_cast<sal_Int32>( rPt0.Y() + fY * fd ) ) );
+ fDistance = *aIter;
+ }
+ }
+ else if ( fDistance < fLastDistance )
+ {
+ std::vector< double >::const_iterator aIter = std::lower_bound( rDistances.begin(), rDistances.end(), fLastDistance );
+ if ( aIter != rDistances.begin() )
+ {
+ --aIter;
+ if ( ( *aIter > fDistance ) && ( *aIter < fLastDistance ) )
+ {
+ Point& rPt0 = rPoly[ i - 1 ];
+ sal_Int32 fX = rPoint.X() - rPt0.X();
+ sal_Int32 fY = rPoint.Y() - rPt0.Y();
+ double fd = ( 1.0 / ( fDistance - fLastDistance ) ) * ( *aIter - fLastDistance );
+ rPoly.Insert( i, Point( static_cast<sal_Int32>( rPt0.X() + fX * fd ), static_cast<sal_Int32>( rPt0.Y() + fY * fd ) ) );
+ fDistance = *aIter;
+ }
+ }
+ }
+ }
+ fLastDistance = fDistance;
+ }
+}
+
+static void GetPoint( const tools::Polygon& rPoly, const std::vector< double >& rDistances, const double& fX, double& fx1, double& fy1 )
+{
+ fy1 = fx1 = 0.0;
+ if ( rPoly.GetSize() <= 1 )
+ return;
+
+ std::vector< double >::const_iterator aIter = std::lower_bound( rDistances.begin(), rDistances.end(), fX );
+ sal_uInt16 nIdx = sal::static_int_cast<sal_uInt16>( std::distance( rDistances.begin(), aIter ) );
+ if ( aIter == rDistances.end() )
+ nIdx--;
+ const Point& rPt = rPoly[ nIdx ];
+ fx1 = rPt.X();
+ fy1 = rPt.Y();
+ if ( !nIdx || ( aIter == rDistances.end() ) || rtl::math::approxEqual( *aIter, fX ) )
+ return;
+
+ nIdx = sal::static_int_cast<sal_uInt16>( std::distance( rDistances.begin(), aIter ) );
+ double fDist0 = *( aIter - 1 );
+ double fd = ( 1.0 / ( *aIter - fDist0 ) ) * ( fX - fDist0 );
+ const Point& rPt2 = rPoly[ nIdx - 1 ];
+ double fWidth = rPt.X() - rPt2.X();
+ double fHeight= rPt.Y() - rPt2.Y();
+ fWidth *= fd;
+ fHeight*= fd;
+ fx1 = rPt2.X() + fWidth;
+ fy1 = rPt2.Y() + fHeight;
+}
+
+static void FitTextOutlinesToShapeOutlines( const tools::PolyPolygon& aOutlines2d, FWData& rFWData )
+{
+ sal_uInt16 nOutline2dIdx = 0;
+ for( auto& rTextArea : rFWData.vTextAreas )
+ {
+ tools::Rectangle rTextAreaBoundRect = rTextArea.aBoundRect;
+ sal_Int32 nLeft = rTextAreaBoundRect.Left();
+ sal_Int32 nTop = rTextAreaBoundRect.Top();
+ sal_Int32 nWidth = rTextAreaBoundRect.GetWidth();
+ sal_Int32 nHeight= rTextAreaBoundRect.GetHeight();
+
+ if (rFWData.bScaleX)
+ {
+ nWidth *= rFWData.fHorizontalTextScaling;
+ }
+
+ if ( rFWData.bSingleLineMode && nHeight && nWidth )
+ {
+ if ( nOutline2dIdx >= aOutlines2d.Count() )
+ break;
+ const tools::Polygon& rOutlinePoly( aOutlines2d[ nOutline2dIdx++ ] );
+ const sal_uInt16 nPointCount = rOutlinePoly.GetSize();
+ if ( nPointCount > 1 )
+ {
+ std::vector< double > vDistances;
+ vDistances.reserve( nPointCount );
+ CalcDistances( rOutlinePoly, vDistances );
+ if ( !vDistances.empty() )
+ {
+ for( auto& rParagraph : rTextArea.vParagraphs )
+ {
+ for ( auto& rCharacter : rParagraph.vCharacters )
+ {
+ for( tools::PolyPolygon& rPolyPoly : rCharacter.vOutlines )
+ {
+ tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
+ double fx1 = aBoundRect.Left() - nLeft;
+ double fx2 = aBoundRect.Right() - nLeft;
+ double fy1, fy2;
+ double fM1 = fx1 / static_cast<double>(nWidth);
+ double fM2 = fx2 / static_cast<double>(nWidth);
+
+ GetPoint( rOutlinePoly, vDistances, fM1, fx1, fy1 );
+ GetPoint( rOutlinePoly, vDistances, fM2, fx2, fy2 );
+
+ double fvx = fy2 - fy1;
+ double fvy = - ( fx2 - fx1 );
+ fx1 = fx1 + ( ( fx2 - fx1 ) * 0.5 );
+ fy1 = fy1 + ( ( fy2 - fy1 ) * 0.5 );
+
+ double fAngle = atan2( -fvx, -fvy );
+ double fL = hypot( fvx, fvy );
+ if (fL == 0.0)
+ {
+ SAL_WARN("svx", "FitTextOutlinesToShapeOutlines div-by-zero, abandon fit");
+ break;
+ }
+ fvx = fvx / fL;
+ fvy = fvy / fL;
+ fL = rTextArea.aBoundRect.GetHeight() / 2.0 + rTextArea.aBoundRect.Top() - rParagraph.aBoundRect.Center().Y();
+ fvx *= fL;
+ fvy *= fL;
+ rPolyPoly.Rotate( Point( aBoundRect.Center().X(), rParagraph.aBoundRect.Center().Y() ), sin( fAngle ), cos( fAngle ) );
+ rPolyPoly.Move( static_cast<sal_Int32>( ( fx1 + fvx )- aBoundRect.Center().X() ), static_cast<sal_Int32>( ( fy1 + fvy ) - rParagraph.aBoundRect.Center().Y() ) );
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( ( nOutline2dIdx + 1 ) >= aOutlines2d.Count() )
+ break;
+ const tools::Polygon& rOutlinePoly( aOutlines2d[ nOutline2dIdx++ ] );
+ const tools::Polygon& rOutlinePoly2( aOutlines2d[ nOutline2dIdx++ ] );
+ const sal_uInt16 nPointCount = rOutlinePoly.GetSize();
+ const sal_uInt16 nPointCount2 = rOutlinePoly2.GetSize();
+ if ( ( nPointCount > 1 ) && ( nPointCount2 > 1 ) )
+ {
+ std::vector< double > vDistances;
+ vDistances.reserve( nPointCount );
+ std::vector< double > vDistances2;
+ vDistances2.reserve( nPointCount2 );
+ CalcDistances( rOutlinePoly, vDistances );
+ CalcDistances( rOutlinePoly2, vDistances2 );
+ for( auto& rParagraph : rTextArea.vParagraphs )
+ {
+ for ( auto& rCharacter : rParagraph.vCharacters )
+ {
+ for( tools::PolyPolygon& rPolyPoly : rCharacter.vOutlines )
+ {
+ sal_uInt16 i, nPolyCount = rPolyPoly.Count();
+ for ( i = 0; i < nPolyCount; i++ )
+ {
+ // #i35928#
+ basegfx::B2DPolygon aCandidate(rPolyPoly[ i ].getB2DPolygon());
+
+ if(aCandidate.areControlPointsUsed())
+ {
+ aCandidate = basegfx::utils::adaptiveSubdivideByAngle(aCandidate);
+ }
+
+ // create local polygon copy to work on
+ tools::Polygon aLocalPoly(aCandidate);
+
+ InsertMissingOutlinePoints( vDistances, rTextAreaBoundRect, aLocalPoly );
+ InsertMissingOutlinePoints( vDistances2, rTextAreaBoundRect, aLocalPoly );
+
+ sal_uInt16 _nPointCount = aLocalPoly.GetSize();
+ if (_nPointCount)
+ {
+ if (!nWidth || !nHeight)
+ throw o3tl::divide_by_zero();
+ for (sal_uInt16 j = 0; j < _nPointCount; ++j)
+ {
+ Point& rPoint = aLocalPoly[ j ];
+ rPoint.AdjustX( -nLeft );
+ rPoint.AdjustY( -nTop );
+ double fX = static_cast<double>(rPoint.X()) / static_cast<double>(nWidth);
+ double fY = static_cast<double>(rPoint.Y()) / static_cast<double>(nHeight);
+
+ double fx1, fy1, fx2, fy2;
+ GetPoint( rOutlinePoly, vDistances, fX, fx1, fy1 );
+ GetPoint( rOutlinePoly2, vDistances2, fX, fx2, fy2 );
+ double fWidth = fx2 - fx1;
+ double fHeight= fy2 - fy1;
+ rPoint.setX( static_cast<sal_Int32>( fx1 + fWidth * fY ) );
+ rPoint.setY( static_cast<sal_Int32>( fy1 + fHeight* fY ) );
+ }
+ }
+
+ // write back polygon
+ rPolyPoly[ i ] = aLocalPoly;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static SdrObject* CreateSdrObjectFromParagraphOutlines(
+ const FWData& rFWData,
+ const SdrObjCustomShape& rSdrObjCustomShape)
+{
+ SdrObject* pRet = nullptr;
+ basegfx::B2DPolyPolygon aPolyPoly;
+ if ( !rFWData.vTextAreas.empty() )
+ {
+ for ( const auto& rTextArea : rFWData.vTextAreas )
+ {
+ for ( const auto& rParagraph : rTextArea.vParagraphs )
+ {
+ for ( const auto& rCharacter : rParagraph.vCharacters )
+ {
+ for( const auto& rOutline : rCharacter.vOutlines )
+ {
+ aPolyPoly.append( rOutline.getB2DPolyPolygon() );
+ }
+ }
+ }
+ }
+
+ pRet = new SdrPathObj(
+ rSdrObjCustomShape.getSdrModelFromSdrObject(),
+ SdrObjKind::Polygon,
+ aPolyPoly);
+
+ SfxItemSet aSet(rSdrObjCustomShape.GetMergedItemSet());
+ aSet.ClearItem( SDRATTR_TEXTDIRECTION ); //SJ: vertical writing is not required, by removing this item no outliner is created
+ aSet.Put(makeSdrShadowItem(false)); // #i37011# NO shadow for FontWork geometry
+ pRet->SetMergedItemSet( aSet ); // * otherwise we would crash, because the outliner tries to create a Paraobject, but there is no model
+ }
+
+ return pRet;
+}
+
+Reference < i18n::XBreakIterator > EnhancedCustomShapeFontWork::mxBreakIterator;
+
+Reference < i18n::XBreakIterator > const & EnhancedCustomShapeFontWork::GetBreakIterator()
+{
+ if ( !mxBreakIterator.is() )
+ {
+ Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ mxBreakIterator = i18n::BreakIterator::create(xContext);
+ }
+ return mxBreakIterator;
+}
+
+SdrObject* EnhancedCustomShapeFontWork::CreateFontWork(
+ const SdrObject* pShape2d,
+ const SdrObjCustomShape& rSdrObjCustomShape)
+{
+ SdrObject* pRet = nullptr;
+
+ tools::PolyPolygon aOutlines2d( GetOutlinesFromShape2d( pShape2d ) );
+ sal_uInt16 nOutlinesCount2d = aOutlines2d.Count();
+ if ( nOutlinesCount2d )
+ {
+ FWData aFWData;
+
+ if(InitializeFontWorkData(rSdrObjCustomShape, nOutlinesCount2d, aFWData))
+ {
+ /* retrieves the horizontal scaling factor that has to be used
+ to fit each paragraph text into its corresponding 2d outline */
+ CalculateHorizontalScalingFactor(
+ rSdrObjCustomShape,
+ aFWData,
+ aOutlines2d);
+
+ /* retrieving the Outlines for the each Paragraph. */
+ if(!GetFontWorkOutline(
+ aFWData,
+ rSdrObjCustomShape))
+ {
+ return nullptr;
+ }
+
+ FitTextOutlinesToShapeOutlines( aOutlines2d, aFWData );
+
+ pRet = CreateSdrObjectFromParagraphOutlines(
+ aFWData,
+ rSdrObjCustomShape);
+ }
+ }
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShapeFontWork.hxx b/svx/source/customshapes/EnhancedCustomShapeFontWork.hxx
new file mode 100644
index 000000000..335701be4
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShapeFontWork.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_CUSTOMSHAPES_ENHANCEDCUSTOMSHAPEFONTWORK_HXX
+#define INCLUDED_SVX_SOURCE_CUSTOMSHAPES_ENHANCEDCUSTOMSHAPEFONTWORK_HXX
+
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+
+class SdrObject;
+class SdrObjCustomShape;
+
+class EnhancedCustomShapeFontWork
+{
+ static css::uno::Reference < css::i18n::XBreakIterator > mxBreakIterator;
+
+ public:
+
+ static css::uno::Reference < css::i18n::XBreakIterator > const & GetBreakIterator();
+ static SdrObject* CreateFontWork(
+ const SdrObject* pShape2d,
+ const SdrObjCustomShape& rSdrObjCustomShape);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx b/svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx
new file mode 100644
index 000000000..f7aa223f4
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx
@@ -0,0 +1,1164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <svx/EnhancedCustomShape2d.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <tools/fract.hxx>
+
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
+
+// Makes parser a static resource,
+// we're synchronized externally.
+// But watch out, the parser might have
+// state not visible to this code!
+
+#define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
+
+#if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
+#define BOOST_SPIRIT_DEBUG
+#endif
+#include <boost/spirit/include/classic_core.hpp>
+
+#include <functional>
+#include <algorithm>
+#include <stack>
+
+#include <math.h>
+using namespace EnhancedCustomShape;
+using namespace com::sun::star;
+using namespace com::sun::star::drawing;
+
+void EnhancedCustomShape::FillEquationParameter( const EnhancedCustomShapeParameter& rSource, const sal_Int32 nDestPara, EnhancedCustomShapeEquation& rDest )
+{
+ sal_Int32 nValue = 0;
+ if ( rSource.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
+ {
+ double fValue(0.0);
+ if ( rSource.Value >>= fValue )
+ nValue = static_cast<sal_Int32>(fValue);
+ }
+ else
+ rSource.Value >>= nValue;
+
+ switch( rSource.Type )
+ {
+ case css::drawing::EnhancedCustomShapeParameterType::EQUATION :
+ {
+ if ( nValue & 0x40000000 )
+ {
+ nValue ^= 0x40000000;
+ rDest.nOperation |= 0x20000000 << nDestPara; // the bit is indicating that this value has to be adjusted later
+ }
+ nValue |= 0x400;
+ }
+ break;
+ case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT : nValue += DFF_Prop_adjustValue; break;
+ case css::drawing::EnhancedCustomShapeParameterType::BOTTOM : nValue = DFF_Prop_geoBottom; break;
+ case css::drawing::EnhancedCustomShapeParameterType::RIGHT : nValue = DFF_Prop_geoRight; break;
+ case css::drawing::EnhancedCustomShapeParameterType::TOP : nValue = DFF_Prop_geoTop; break;
+ case css::drawing::EnhancedCustomShapeParameterType::LEFT : nValue = DFF_Prop_geoLeft; break;
+ }
+ if ( rSource.Type != css::drawing::EnhancedCustomShapeParameterType::NORMAL )
+ rDest.nOperation |= ( 0x2000 << nDestPara );
+ rDest.nPara[ nDestPara ] = nValue;
+}
+
+ExpressionNode::~ExpressionNode()
+{}
+
+namespace
+{
+
+
+// EXPRESSION NODES
+
+
+class ConstantValueExpression : public ExpressionNode
+{
+ double maValue;
+
+public:
+
+ explicit ConstantValueExpression( double rValue ) :
+ maValue( rValue )
+ {
+ }
+ virtual double operator()() const override
+ {
+ return maValue;
+ }
+ virtual bool isConstant() const override
+ {
+ return true;
+ }
+ virtual ExpressionFunct getType() const override
+ {
+ return ExpressionFunct::Const;
+ }
+ virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) override
+ {
+ EnhancedCustomShapeParameter aRet;
+ Fraction aFract( maValue );
+ if ( aFract.GetDenominator() == 1 )
+ {
+ aRet.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aRet.Value <<= aFract.GetNumerator();
+ }
+ else
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation = 1;
+ aEquation.nPara[ 0 ] = 1;
+ aEquation.nPara[ 1 ] = static_cast<sal_Int16>(aFract.GetNumerator());
+ aEquation.nPara[ 2 ] = static_cast<sal_Int16>(aFract.GetDenominator());
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ return aRet;
+ }
+};
+
+class AdjustmentExpression : public ExpressionNode
+{
+ sal_Int32 mnIndex;
+ const EnhancedCustomShape2d& mrCustoShape;
+
+public:
+
+ AdjustmentExpression( const EnhancedCustomShape2d& rCustoShape, sal_Int32 nIndex )
+ : mnIndex ( nIndex )
+ , mrCustoShape( rCustoShape )
+
+ {
+ }
+ virtual double operator()() const override
+ {
+ SAL_INFO(
+ "svx",
+ "$" << mnIndex << " --> "
+ << mrCustoShape.GetAdjustValueAsDouble(mnIndex) << " (angle: "
+ << 180.0*mrCustoShape.GetAdjustValueAsDouble(mnIndex)/10800000.0
+ << ")");
+ return mrCustoShape.GetAdjustValueAsDouble( mnIndex );
+ }
+ virtual bool isConstant() const override
+ {
+ return false;
+ }
+ virtual ExpressionFunct getType() const override
+ {
+ return ExpressionFunct::EnumAdjustment;
+ }
+ virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) override
+ {
+ EnhancedCustomShapeParameter aRet;
+ aRet.Type = EnhancedCustomShapeParameterType::ADJUSTMENT;
+ aRet.Value <<= mnIndex;
+ return aRet;
+ }
+};
+
+class EquationExpression : public ExpressionNode
+{
+ const sal_Int32 mnIndex;
+ const EnhancedCustomShape2d& mrCustoShape;
+ mutable bool mbGettingValueGuard;
+
+public:
+
+ EquationExpression( const EnhancedCustomShape2d& rCustoShape, sal_Int32 nIndex )
+ : mnIndex ( nIndex )
+ , mrCustoShape( rCustoShape )
+ , mbGettingValueGuard(false)
+ {
+ }
+ virtual double operator()() const override
+ {
+ if (mbGettingValueGuard)
+ throw ParseError("Loop in Expression");
+ mbGettingValueGuard = true;
+ double fRet = mrCustoShape.GetEquationValueAsDouble(mnIndex);
+ mbGettingValueGuard = false;
+ return fRet;
+ }
+ virtual bool isConstant() const override
+ {
+ return false;
+ }
+ virtual ExpressionFunct getType() const override
+ {
+ return ExpressionFunct::EnumEquation;
+ }
+ virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) override
+ {
+ EnhancedCustomShapeParameter aRet;
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= mnIndex | 0x40000000; // the bit is indicating that this equation needs to be adjusted later
+ return aRet;
+ }
+};
+
+class EnumValueExpression : public ExpressionNode
+{
+ const ExpressionFunct meFunct;
+ const EnhancedCustomShape2d& mrCustoShape;
+
+public:
+
+ EnumValueExpression( const EnhancedCustomShape2d& rCustoShape, const ExpressionFunct eFunct )
+ : meFunct ( eFunct )
+ , mrCustoShape ( rCustoShape )
+ {
+ }
+ virtual double operator()() const override
+ {
+ SAL_INFO("svx", meFunct << " --> " << mrCustoShape.GetEnumFunc(meFunct) << "(angle: " <<
+ 180.0 * mrCustoShape.GetEnumFunc(meFunct) / 10800000.0 << ")");
+
+ return mrCustoShape.GetEnumFunc( meFunct );
+ }
+ virtual bool isConstant() const override
+ {
+ return false;
+ }
+ virtual ExpressionFunct getType() const override
+ {
+ return meFunct;
+ }
+ virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags ) override
+ {
+ EnhancedCustomShapeParameter aRet;
+
+ aRet.Value <<= sal_Int32(1);
+
+ switch( meFunct )
+ {
+ case ExpressionFunct::EnumWidth : // TODO: do not use this as constant value
+ case ExpressionFunct::EnumHeight :
+ case ExpressionFunct::EnumLogWidth :
+ case ExpressionFunct::EnumLogHeight :
+ case ExpressionFunct::EnumPi :
+ {
+ ConstantValueExpression aConstantValue( mrCustoShape.GetEnumFunc( meFunct ) );
+ aRet = aConstantValue.fillNode( rEquations, nullptr, nFlags );
+ }
+ break;
+ case ExpressionFunct::EnumLeft : aRet.Type = EnhancedCustomShapeParameterType::LEFT; break;
+ case ExpressionFunct::EnumTop : aRet.Type = EnhancedCustomShapeParameterType::TOP; break;
+ case ExpressionFunct::EnumRight : aRet.Type = EnhancedCustomShapeParameterType::RIGHT; break;
+ case ExpressionFunct::EnumBottom : aRet.Type = EnhancedCustomShapeParameterType::BOTTOM; break;
+
+ // not implemented so far
+ case ExpressionFunct::EnumXStretch :
+ case ExpressionFunct::EnumYStretch :
+ case ExpressionFunct::EnumHasStroke :
+ case ExpressionFunct::EnumHasFill : aRet.Type = EnhancedCustomShapeParameterType::NORMAL; break;
+
+ default:
+ break;
+ }
+ return aRet;
+ }
+};
+
+/** ExpressionNode implementation for unary
+ function over one ExpressionNode
+ */
+class UnaryFunctionExpression : public ExpressionNode
+{
+ const ExpressionFunct meFunct;
+ std::shared_ptr<ExpressionNode> mpArg;
+
+public:
+ UnaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rArg ) :
+ meFunct( eFunct ),
+ mpArg( rArg )
+ {
+ }
+ static double getValue( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rArg )
+ {
+ double fRet = 0;
+ switch( eFunct )
+ {
+ case ExpressionFunct::UnaryAbs : fRet = fabs( (*rArg)() ); break;
+ case ExpressionFunct::UnarySqrt: fRet = sqrt( (*rArg)() ); break;
+ case ExpressionFunct::UnarySin : fRet = sin( (*rArg)() ); break;
+ case ExpressionFunct::UnaryCos : fRet = cos( (*rArg)() ); break;
+ case ExpressionFunct::UnaryTan : fRet = tan( (*rArg)() ); break;
+ case ExpressionFunct::UnaryAtan: fRet = atan( (*rArg)() ); break;
+ case ExpressionFunct::UnaryNeg : fRet = ::std::negate<double>()( (*rArg)() ); break;
+ default:
+ break;
+ }
+ return fRet;
+ }
+ virtual double operator()() const override
+ {
+ return getValue( meFunct, mpArg );
+ }
+ virtual bool isConstant() const override
+ {
+ return mpArg->isConstant();
+ }
+ virtual ExpressionFunct getType() const override
+ {
+ return meFunct;
+ }
+ virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* pOptionalArg, sal_uInt32 nFlags ) override
+ {
+ EnhancedCustomShapeParameter aRet;
+ switch( meFunct )
+ {
+ case ExpressionFunct::UnaryAbs :
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 3;
+ FillEquationParameter( mpArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ case ExpressionFunct::UnarySqrt:
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 13;
+ FillEquationParameter( mpArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ case ExpressionFunct::UnarySin :
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 9;
+ if ( pOptionalArg )
+ FillEquationParameter( pOptionalArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ else
+ aEquation.nPara[ 0 ] = 1;
+
+ EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, nullptr, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) );
+ if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL )
+ { // sumangle needed :-(
+ EnhancedCustomShapeEquation _aEquation;
+ _aEquation.nOperation |= 0xe; // sumangle
+ FillEquationParameter( aSource, 1, _aEquation );
+ aSource.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aSource.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( _aEquation );
+ }
+ FillEquationParameter( aSource, 1, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ case ExpressionFunct::UnaryCos :
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 10;
+ if ( pOptionalArg )
+ FillEquationParameter( pOptionalArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ else
+ aEquation.nPara[ 0 ] = 1;
+
+ EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, nullptr, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) );
+ if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL )
+ { // sumangle needed :-(
+ EnhancedCustomShapeEquation aTmpEquation;
+ aTmpEquation.nOperation |= 0xe; // sumangle
+ FillEquationParameter( aSource, 1, aTmpEquation );
+ aSource.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aSource.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aTmpEquation );
+ }
+ FillEquationParameter( aSource, 1, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ case ExpressionFunct::UnaryTan :
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 16;
+ if ( pOptionalArg )
+ FillEquationParameter( pOptionalArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ else
+ aEquation.nPara[ 0 ] = 1;
+
+ EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, nullptr, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) );
+ if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL )
+ { // sumangle needed :-(
+ EnhancedCustomShapeEquation aTmpEquation;
+ aTmpEquation.nOperation |= 0xe; // sumangle
+ FillEquationParameter( aSource, 1, aTmpEquation );
+ aSource.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aSource.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aTmpEquation );
+ }
+ FillEquationParameter( aSource, 1, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ case ExpressionFunct::UnaryAtan:
+ {
+// TODO:
+ aRet.Type = EnhancedCustomShapeParameterType::NORMAL;
+ }
+ break;
+ case ExpressionFunct::UnaryNeg:
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 1;
+ aEquation.nPara[ 1 ] = -1;
+ aEquation.nPara[ 2 ] = 1;
+ FillEquationParameter( mpArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ default:
+ break;
+ }
+ return aRet;
+ }
+};
+
+/** ExpressionNode implementation for unary
+ function over two ExpressionNodes
+ */
+class BinaryFunctionExpression : public ExpressionNode
+{
+ const ExpressionFunct meFunct;
+ std::shared_ptr<ExpressionNode> mpFirstArg;
+ std::shared_ptr<ExpressionNode> mpSecondArg;
+
+public:
+
+ BinaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rFirstArg, const std::shared_ptr<ExpressionNode>& rSecondArg ) :
+ meFunct( eFunct ),
+ mpFirstArg( rFirstArg ),
+ mpSecondArg( rSecondArg )
+ {
+ }
+#if defined(__clang__) || (defined (__GNUC__) && __GNUC__ >= 8)
+ //GetEquationValueAsDouble calls isFinite on the result
+ __attribute__((no_sanitize("float-divide-by-zero")))
+#endif
+ static double getValue( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rFirstArg, const std::shared_ptr<ExpressionNode>& rSecondArg )
+ {
+ double fRet = 0;
+ switch( eFunct )
+ {
+ case ExpressionFunct::BinaryPlus : fRet = (*rFirstArg)() + (*rSecondArg)(); break;
+ case ExpressionFunct::BinaryMinus: fRet = (*rFirstArg)() - (*rSecondArg)(); break;
+ case ExpressionFunct::BinaryMul : fRet = (*rFirstArg)() * (*rSecondArg)(); break;
+ case ExpressionFunct::BinaryDiv : fRet = (*rFirstArg)() / (*rSecondArg)(); break;
+ case ExpressionFunct::BinaryMin : fRet = ::std::min( (*rFirstArg)(), (*rSecondArg)() ); break;
+ case ExpressionFunct::BinaryMax : fRet = ::std::max( (*rFirstArg)(), (*rSecondArg)() ); break;
+ case ExpressionFunct::BinaryAtan2: fRet = atan2( (*rFirstArg)(), (*rSecondArg)() ); break;
+ default:
+ break;
+ }
+ return fRet;
+ }
+ virtual double operator()() const override
+ {
+ return getValue( meFunct, mpFirstArg, mpSecondArg );
+ }
+ virtual bool isConstant() const override
+ {
+ return mpFirstArg->isConstant() && mpSecondArg->isConstant();
+ }
+ virtual ExpressionFunct getType() const override
+ {
+ return meFunct;
+ }
+ virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags ) override
+ {
+ EnhancedCustomShapeParameter aRet;
+ switch( meFunct )
+ {
+ case ExpressionFunct::BinaryPlus :
+ {
+ if ( nFlags & EXPRESSION_FLAG_SUMANGLE_MODE )
+ {
+ if ( mpFirstArg->getType() == ExpressionFunct::EnumAdjustment )
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 0xe; // sumangle
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ else if ( mpSecondArg->getType() == ExpressionFunct::EnumAdjustment )
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 0xe; // sumangle
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ else
+ {
+ EnhancedCustomShapeEquation aSumangle1;
+ aSumangle1.nOperation |= 0xe; // sumangle
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags &~EXPRESSION_FLAG_SUMANGLE_MODE ), 1, aSumangle1 );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aSumangle1 );
+
+ EnhancedCustomShapeEquation aSumangle2;
+ aSumangle2.nOperation |= 0xe; // sumangle
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags &~EXPRESSION_FLAG_SUMANGLE_MODE ), 1, aSumangle2 );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aSumangle2 );
+
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 0;
+ aEquation.nPara[ 0 ] = ( rEquations.size() - 2 ) | 0x400;
+ aEquation.nPara[ 1 ] = ( rEquations.size() - 1 ) | 0x400;
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ }
+ else
+ {
+ bool bFirstIsEmpty = mpFirstArg->isConstant() && ( (*mpFirstArg)() == 0 );
+ bool bSecondIsEmpty = mpSecondArg->isConstant() && ( (*mpSecondArg)() == 0 );
+
+ if ( bFirstIsEmpty )
+ aRet = mpSecondArg->fillNode( rEquations, nullptr, nFlags );
+ else if ( bSecondIsEmpty )
+ aRet = mpFirstArg->fillNode( rEquations, nullptr, nFlags );
+ else
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 0;
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ }
+ }
+ break;
+ case ExpressionFunct::BinaryMinus:
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 0;
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 2, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ case ExpressionFunct::BinaryMul :
+ {
+ // in the dest. format the cos function is using integer as result :-(
+ // so we can't use the generic algorithm
+ if ( ( mpFirstArg->getType() == ExpressionFunct::UnarySin ) || ( mpFirstArg->getType() == ExpressionFunct::UnaryCos ) || ( mpFirstArg->getType() == ExpressionFunct::UnaryTan ) )
+ aRet = mpFirstArg->fillNode( rEquations, mpSecondArg.get(), nFlags );
+ else if ( ( mpSecondArg->getType() == ExpressionFunct::UnarySin ) || ( mpSecondArg->getType() == ExpressionFunct::UnaryCos ) || ( mpSecondArg->getType() == ExpressionFunct::UnaryTan ) )
+ aRet = mpSecondArg->fillNode( rEquations, mpFirstArg.get(), nFlags );
+ else
+ {
+ if ( mpFirstArg->isConstant() && (*mpFirstArg)() == 1 )
+ aRet = mpSecondArg->fillNode( rEquations, nullptr, nFlags );
+ else if ( mpSecondArg->isConstant() && (*mpSecondArg)() == 1 )
+ aRet = mpFirstArg->fillNode( rEquations, nullptr, nFlags );
+ else if ( ( mpFirstArg->getType() == ExpressionFunct::BinaryDiv ) // don't care of (pi/180)
+ && ( static_cast<BinaryFunctionExpression*>(mpFirstArg.get())->mpFirstArg->getType() == ExpressionFunct::EnumPi )
+ && ( static_cast<BinaryFunctionExpression*>(mpFirstArg.get())->mpSecondArg->getType() == ExpressionFunct::Const ) )
+ {
+ aRet = mpSecondArg->fillNode( rEquations, nullptr, nFlags );
+ }
+ else if ( ( mpSecondArg->getType() == ExpressionFunct::BinaryDiv ) // don't care of (pi/180)
+ && ( static_cast<BinaryFunctionExpression*>(mpSecondArg.get())->mpFirstArg->getType() == ExpressionFunct::EnumPi )
+ && ( static_cast<BinaryFunctionExpression*>(mpSecondArg.get())->mpSecondArg->getType() == ExpressionFunct::Const ) )
+ {
+ aRet = mpFirstArg->fillNode( rEquations, nullptr, nFlags );
+ }
+ else
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 1;
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
+ aEquation.nPara[ 2 ] = 1;
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ }
+ }
+ break;
+ case ExpressionFunct::BinaryDiv :
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 1;
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ aEquation.nPara[ 1 ] = 1;
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 2, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ case ExpressionFunct::BinaryMin :
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 4;
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ case ExpressionFunct::BinaryMax :
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 5;
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ case ExpressionFunct::BinaryAtan2:
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 8;
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ rEquations.push_back( aEquation );
+ }
+ break;
+ default:
+ break;
+ }
+ return aRet;
+ }
+};
+
+class IfExpression : public ExpressionNode
+{
+ std::shared_ptr<ExpressionNode> mpFirstArg;
+ std::shared_ptr<ExpressionNode> mpSecondArg;
+ std::shared_ptr<ExpressionNode> mpThirdArg;
+
+public:
+
+ IfExpression( const std::shared_ptr<ExpressionNode>& rFirstArg,
+ const std::shared_ptr<ExpressionNode>& rSecondArg,
+ const std::shared_ptr<ExpressionNode>& rThirdArg ) :
+ mpFirstArg( rFirstArg ),
+ mpSecondArg( rSecondArg ),
+ mpThirdArg( rThirdArg )
+ {
+ }
+ virtual bool isConstant() const override
+ {
+ return
+ mpFirstArg->isConstant() &&
+ mpSecondArg->isConstant() &&
+ mpThirdArg->isConstant();
+ }
+ virtual double operator()() const override
+ {
+ return (*mpFirstArg)() > 0 ? (*mpSecondArg)() : (*mpThirdArg)();
+ }
+ virtual ExpressionFunct getType() const override
+ {
+ return ExpressionFunct::TernaryIf;
+ }
+ virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags ) override
+ {
+ EnhancedCustomShapeParameter aRet;
+ aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
+ aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation |= 6;
+ FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
+ FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
+ FillEquationParameter( mpThirdArg->fillNode( rEquations, nullptr, nFlags ), 2, aEquation );
+ rEquations.push_back( aEquation );
+ }
+ return aRet;
+ }
+};
+
+
+// FUNCTION PARSER
+
+
+typedef const char* StringIteratorT;
+
+struct ParserContext
+{
+ typedef ::std::stack< std::shared_ptr<ExpressionNode> > OperandStack;
+
+ // stores a stack of not-yet-evaluated operands. This is used
+ // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
+ // arguments from. If all arguments to an operator are constant,
+ // the operator pushes a precalculated result on the stack, and
+ // a composite ExpressionNode otherwise.
+ OperandStack maOperandStack;
+
+ const EnhancedCustomShape2d* mpCustoShape;
+
+};
+
+typedef std::shared_ptr< ParserContext > ParserContextSharedPtr;
+
+/** Generate parse-dependent-but-then-constant value
+ */
+class DoubleConstantFunctor
+{
+ ParserContextSharedPtr mxContext;
+
+public:
+ explicit DoubleConstantFunctor( const ParserContextSharedPtr& rContext ) :
+ mxContext( rContext )
+ {
+ }
+ void operator()( double n ) const
+ {
+ mxContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( n ) );
+ }
+};
+
+class EnumFunctor
+{
+ const ExpressionFunct meFunct;
+ ParserContextSharedPtr mxContext;
+
+public:
+
+ EnumFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext )
+ : meFunct( eFunct )
+ , mxContext( rContext )
+ {
+ }
+ void operator()( StringIteratorT rFirst, StringIteratorT rSecond ) const
+ {
+ /*double nVal = mnValue;*/
+ switch( meFunct )
+ {
+ case ExpressionFunct::EnumAdjustment :
+ {
+ OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
+ mxContext->maOperandStack.push( std::make_shared<AdjustmentExpression>( *mxContext->mpCustoShape, aVal.toInt32() ) );
+ }
+ break;
+ case ExpressionFunct::EnumEquation :
+ {
+ OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
+ mxContext->maOperandStack.push( std::make_shared<EquationExpression>( *mxContext->mpCustoShape, aVal.toInt32() ) );
+ }
+ break;
+ default:
+ mxContext->maOperandStack.push( std::make_shared<EnumValueExpression>( *mxContext->mpCustoShape, meFunct ) );
+ }
+ }
+};
+
+class UnaryFunctionFunctor
+{
+ const ExpressionFunct meFunct;
+ ParserContextSharedPtr mxContext;
+
+public:
+
+ UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
+ meFunct( eFunct ),
+ mxContext( rContext )
+ {
+ }
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+ ParserContext::OperandStack& rNodeStack( mxContext->maOperandStack );
+
+ if( rNodeStack.empty() )
+ throw ParseError( "Not enough arguments for unary operator" );
+
+ // retrieve arguments
+ std::shared_ptr<ExpressionNode> pArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+
+ if( pArg->isConstant() ) // check for constness
+ rNodeStack.push( std::make_shared<ConstantValueExpression>( UnaryFunctionExpression::getValue( meFunct, pArg ) ) );
+ else // push complex node, that calcs the value on demand
+ rNodeStack.push( std::make_shared<UnaryFunctionExpression>( meFunct, pArg ) );
+ }
+};
+
+/** Implements a binary function over two ExpressionNodes
+
+ @tpl Generator
+ Generator functor, to generate an ExpressionNode of
+ appropriate type
+
+ */
+class BinaryFunctionFunctor
+{
+ const ExpressionFunct meFunct;
+ ParserContextSharedPtr mxContext;
+
+public:
+
+ BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
+ meFunct( eFunct ),
+ mxContext( rContext )
+ {
+ }
+
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+ ParserContext::OperandStack& rNodeStack( mxContext->maOperandStack );
+
+ if( rNodeStack.size() < 2 )
+ throw ParseError( "Not enough arguments for binary operator" );
+
+ // retrieve arguments
+ std::shared_ptr<ExpressionNode> pSecondArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+ std::shared_ptr<ExpressionNode> pFirstArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+
+ assert(pSecondArg && pFirstArg && "count of arg checked before we get here");
+
+ // create combined ExpressionNode
+ auto pNode = std::make_shared<BinaryFunctionExpression>( meFunct, pFirstArg, pSecondArg );
+ // check for constness
+ if( pFirstArg->isConstant() && pSecondArg->isConstant() ) // call the operator() at pNode, store result in constant value ExpressionNode.
+ rNodeStack.push( std::make_shared<ConstantValueExpression>( (*pNode)() ) );
+ else // push complex node, that calcs the value on demand
+ rNodeStack.push( pNode );
+ }
+};
+
+class IfFunctor
+{
+ ParserContextSharedPtr mxContext;
+
+public:
+
+ explicit IfFunctor( const ParserContextSharedPtr& rContext ) :
+ mxContext( rContext )
+ {
+ }
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+ ParserContext::OperandStack& rNodeStack( mxContext->maOperandStack );
+
+ if( rNodeStack.size() < 3 )
+ throw ParseError( "Not enough arguments for ternary operator" );
+
+ // retrieve arguments
+ std::shared_ptr<ExpressionNode> pThirdArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+ std::shared_ptr<ExpressionNode> pSecondArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+ std::shared_ptr<ExpressionNode> pFirstArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+
+ assert(pThirdArg && pSecondArg && pFirstArg);
+
+ // create combined ExpressionNode
+ auto pNode = std::make_shared<IfExpression>( pFirstArg, pSecondArg, pThirdArg );
+ // check for constness
+ if( pFirstArg->isConstant() && pSecondArg->isConstant() && pThirdArg->isConstant() )
+ rNodeStack.push( std::make_shared<ConstantValueExpression>( (*pNode)() ) ); // call the operator() at pNode, store result in constant value ExpressionNode.
+ else
+ rNodeStack.push( pNode ); // push complex node, that calcs the value on demand
+ }
+};
+
+// Workaround for MSVC compiler anomaly (stack trashing)
+
+// The default ureal_parser_policies implementation of parse_exp
+// triggers a really weird error in MSVC7 (Version 13.00.9466), in
+// that the real_parser_impl::parse_main() call of parse_exp()
+// overwrites the frame pointer _on the stack_ (EBP of the calling
+// function gets overwritten while lying on the stack).
+
+// For the time being, our parser thus can only read the 1.0E10
+// notation, not the 1.0e10 one.
+
+// TODO(F1): Also handle the 1.0e10 case here.
+template< typename T > struct custom_real_parser_policies : public ::boost::spirit::classic::ureal_parser_policies<T>
+{
+ template< typename ScannerT >
+ static typename ::boost::spirit::classic::parser_result< ::boost::spirit::classic::chlit<>, ScannerT >::type
+ parse_exp(ScannerT& scan)
+ {
+ // as_lower_d somehow breaks MSVC7
+ return ::boost::spirit::classic::ch_p('E').parse(scan);
+ }
+};
+
+/* This class implements the following grammar (more or
+ less literally written down below, only slightly
+ obfuscated by the parser actions):
+
+ identifier = '$'|'pi'|'e'|'X'|'Y'|'Width'|'Height'
+
+ function = 'abs'|'sqrt'|'sin'|'cos'|'tan'|'atan'|'acos'|'asin'|'exp'|'log'
+
+ basic_expression =
+ number |
+ identifier |
+ function '(' additive_expression ')' |
+ '(' additive_expression ')'
+
+ unary_expression =
+ '-' basic_expression |
+ basic_expression
+
+ multiplicative_expression =
+ unary_expression ( ( '*' unary_expression )* |
+ ( '/' unary_expression )* )
+
+ additive_expression =
+ multiplicative_expression ( ( '+' multiplicative_expression )* |
+ ( '-' multiplicative_expression )* )
+
+ */
+
+class ExpressionGrammar : public ::boost::spirit::classic::grammar< ExpressionGrammar >
+{
+public:
+ /** Create an arithmetic expression grammar
+
+ @param rParserContext
+ Contains context info for the parser
+ */
+ explicit ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
+ mpParserContext( rParserContext )
+ {
+ }
+
+ template< typename ScannerT > class definition
+ {
+ public:
+ // grammar definition
+ explicit definition( const ExpressionGrammar& self )
+ {
+ using ::boost::spirit::classic::str_p;
+ using ::boost::spirit::classic::range_p;
+ using ::boost::spirit::classic::lexeme_d;
+ using ::boost::spirit::classic::real_parser;
+
+ identifier =
+ str_p( "pi" )[ EnumFunctor(ExpressionFunct::EnumPi, self.getContext() ) ]
+ | str_p( "left" )[ EnumFunctor(ExpressionFunct::EnumLeft, self.getContext() ) ]
+ | str_p( "top" )[ EnumFunctor(ExpressionFunct::EnumTop, self.getContext() ) ]
+ | str_p( "right" )[ EnumFunctor(ExpressionFunct::EnumRight, self.getContext() ) ]
+ | str_p( "bottom" )[ EnumFunctor(ExpressionFunct::EnumBottom, self.getContext() ) ]
+ | str_p( "xstretch" )[ EnumFunctor(ExpressionFunct::EnumXStretch, self.getContext() ) ]
+ | str_p( "ystretch" )[ EnumFunctor(ExpressionFunct::EnumYStretch, self.getContext() ) ]
+ | str_p( "hasstroke" )[ EnumFunctor(ExpressionFunct::EnumHasStroke, self.getContext() ) ]
+ | str_p( "hasfill" )[ EnumFunctor(ExpressionFunct::EnumHasFill, self.getContext() ) ]
+ | str_p( "width" )[ EnumFunctor(ExpressionFunct::EnumWidth, self.getContext() ) ]
+ | str_p( "height" )[ EnumFunctor(ExpressionFunct::EnumHeight, self.getContext() ) ]
+ | str_p( "logwidth" )[ EnumFunctor(ExpressionFunct::EnumLogWidth, self.getContext() ) ]
+ | str_p( "logheight" )[ EnumFunctor(ExpressionFunct::EnumLogHeight, self.getContext() ) ]
+ ;
+
+ unaryFunction =
+ (str_p( "abs" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryAbs, self.getContext()) ]
+ | (str_p( "sqrt" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnarySqrt, self.getContext()) ]
+ | (str_p( "sin" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnarySin, self.getContext()) ]
+ | (str_p( "cos" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryCos, self.getContext()) ]
+ | (str_p( "tan" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryTan, self.getContext()) ]
+ | (str_p( "atan" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryAtan, self.getContext()) ]
+ ;
+
+ binaryFunction =
+ (str_p( "min" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( ExpressionFunct::BinaryMin, self.getContext()) ]
+ | (str_p( "max" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( ExpressionFunct::BinaryMax, self.getContext()) ]
+ | (str_p( "atan2") >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( ExpressionFunct::BinaryAtan2,self.getContext()) ]
+ ;
+
+ ternaryFunction =
+ (str_p( "if" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ IfFunctor( self.getContext() ) ]
+ ;
+
+ funcRef_decl =
+ lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ];
+
+ functionReference =
+ (str_p( "?" ) >> funcRef_decl )[ EnumFunctor( ExpressionFunct::EnumEquation, self.getContext() ) ];
+
+ modRef_decl =
+ lexeme_d[ +( range_p('0','9') ) ];
+
+ modifierReference =
+ (str_p( "$" ) >> modRef_decl )[ EnumFunctor( ExpressionFunct::EnumAdjustment, self.getContext() ) ];
+
+ basicExpression =
+ real_parser<double, custom_real_parser_policies<double> >()[ DoubleConstantFunctor(self.getContext()) ]
+ | identifier
+ | functionReference
+ | modifierReference
+ | unaryFunction
+ | binaryFunction
+ | ternaryFunction
+ | '(' >> additiveExpression >> ')'
+ ;
+
+ unaryExpression =
+ ('-' >> basicExpression)[ UnaryFunctionFunctor( ExpressionFunct::UnaryNeg, self.getContext()) ]
+ | basicExpression
+ ;
+
+ multiplicativeExpression =
+ unaryExpression
+ >> *( ('*' >> unaryExpression)[ BinaryFunctionFunctor( ExpressionFunct::BinaryMul, self.getContext()) ]
+ | ('/' >> unaryExpression)[ BinaryFunctionFunctor( ExpressionFunct::BinaryDiv, self.getContext()) ]
+ )
+ ;
+
+ additiveExpression =
+ multiplicativeExpression
+ >> *( ('+' >> multiplicativeExpression)[ BinaryFunctionFunctor( ExpressionFunct::BinaryPlus, self.getContext()) ]
+ | ('-' >> multiplicativeExpression)[ BinaryFunctionFunctor( ExpressionFunct::BinaryMinus, self.getContext()) ]
+ )
+ ;
+
+ BOOST_SPIRIT_DEBUG_RULE(additiveExpression);
+ BOOST_SPIRIT_DEBUG_RULE(multiplicativeExpression);
+ BOOST_SPIRIT_DEBUG_RULE(unaryExpression);
+ BOOST_SPIRIT_DEBUG_RULE(basicExpression);
+ BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
+ BOOST_SPIRIT_DEBUG_RULE(binaryFunction);
+ BOOST_SPIRIT_DEBUG_RULE(ternaryFunction);
+ BOOST_SPIRIT_DEBUG_RULE(identifier);
+ }
+
+ const ::boost::spirit::classic::rule< ScannerT >& start() const
+ {
+ return additiveExpression;
+ }
+
+ private:
+ // the constituents of the Spirit arithmetic expression grammar.
+ // For the sake of readability, without 'ma' prefix.
+ ::boost::spirit::classic::rule< ScannerT > additiveExpression;
+ ::boost::spirit::classic::rule< ScannerT > multiplicativeExpression;
+ ::boost::spirit::classic::rule< ScannerT > unaryExpression;
+ ::boost::spirit::classic::rule< ScannerT > basicExpression;
+ ::boost::spirit::classic::rule< ScannerT > unaryFunction;
+ ::boost::spirit::classic::rule< ScannerT > binaryFunction;
+ ::boost::spirit::classic::rule< ScannerT > ternaryFunction;
+ ::boost::spirit::classic::rule< ScannerT > funcRef_decl;
+ ::boost::spirit::classic::rule< ScannerT > functionReference;
+ ::boost::spirit::classic::rule< ScannerT > modRef_decl;
+ ::boost::spirit::classic::rule< ScannerT > modifierReference;
+ ::boost::spirit::classic::rule< ScannerT > identifier;
+ };
+
+ const ParserContextSharedPtr& getContext() const
+ {
+ return mpParserContext;
+ }
+
+private:
+ ParserContextSharedPtr mpParserContext; // might get modified during parsing
+};
+
+const ParserContextSharedPtr& getParserContext()
+{
+ static ParserContextSharedPtr lcl_parserContext = std::make_shared<ParserContext>();
+
+ // clear node stack (since we reuse the static object, that's
+ // the whole point here)
+ while( !lcl_parserContext->maOperandStack.empty() )
+ lcl_parserContext->maOperandStack.pop();
+
+ return lcl_parserContext;
+}
+
+}
+
+namespace EnhancedCustomShape {
+
+
+std::shared_ptr<ExpressionNode> const & FunctionParser::parseFunction( std::u16string_view rFunction, const EnhancedCustomShape2d& rCustoShape )
+{
+ // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
+ // gives better conversion robustness here (we might want to map space
+ // etc. to ASCII space here)
+ const OString& rAsciiFunction(
+ OUStringToOString( rFunction, RTL_TEXTENCODING_ASCII_US ) );
+
+ StringIteratorT aStart( rAsciiFunction.getStr() );
+ StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
+
+ // static parser context, because the actual
+ // Spirit parser is also a static object
+ ParserContextSharedPtr pContext = getParserContext();
+ pContext->mpCustoShape = &rCustoShape;
+
+ ExpressionGrammar aExpressionGrammer( pContext );
+ const ::boost::spirit::classic::parse_info<StringIteratorT> aParseInfo(
+ ::boost::spirit::classic::parse( aStart,
+ aEnd,
+ aExpressionGrammer >> ::boost::spirit::classic::end_p,
+ ::boost::spirit::classic::space_p ) );
+
+ // input fully congested by the parser?
+ if( !aParseInfo.full )
+ throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): string not fully parseable" );
+
+ // parser's state stack now must contain exactly _one_ ExpressionNode,
+ // which represents our formula.
+ if( pContext->maOperandStack.size() != 1 )
+ throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): incomplete or empty expression" );
+
+
+ return pContext->maOperandStack.top();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShapeGeometry.cxx b/svx/source/customshapes/EnhancedCustomShapeGeometry.cxx
new file mode 100644
index 000000000..0f999ed42
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShapeGeometry.cxx
@@ -0,0 +1,8567 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cmath>
+#include <limits>
+
+#include <svx/EnhancedCustomShapeGeometry.hxx>
+#include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
+
+const sal_Int32 MIN_INT32 = std::numeric_limits<sal_Int32>::min();
+
+const sal_Int32 mso_sptDefault1400[] =
+{
+ 1, 1400
+};
+const sal_Int32 mso_sptDefault1800[] =
+{
+ 1, 1800
+};
+const sal_Int32 mso_sptDefault2500[] =
+{
+ 1, 2500
+};
+const sal_Int32 mso_sptDefault2700[] =
+{
+ 1, 2700
+};
+const sal_Int32 mso_sptDefault3600[] =
+{
+ 1, 3600
+};
+const sal_Int32 mso_sptDefault3700[] =
+{
+ 1, 3700
+};
+const sal_Int32 mso_sptDefault5400[] =
+{
+ 1, 5400
+};
+const sal_Int32 mso_sptDefault7200[] =
+{
+ 1, 7200
+};
+const sal_Int32 mso_sptDefault8100[] =
+{
+ 1, 8100
+};
+const sal_Int32 mso_sptDefault9600[] =
+{
+ 1, 9600
+};
+const sal_Int32 mso_sptDefault10800[] =
+{
+ 1, 10800
+};
+const sal_Int32 mso_sptDefault12000[] =
+{
+ 1, 12000
+};
+const sal_Int32 mso_sptDefault13500[] =
+{
+ 1, 13500
+};
+const sal_Int32 mso_sptDefault16200[] =
+{
+ 1, 16200
+};
+const sal_Int32 mso_sptDefault16200and5400[] =
+{
+ 2, 16200, 5400
+};
+
+const SvxMSDffVertPair mso_sptArcVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 3 MSO_I, 1 MSO_I }, { 7 MSO_I, 5 MSO_I }, { 10800, 10800 },
+ { 0, 0 }, { 21600, 21600 }, { 3 MSO_I, 1 MSO_I }, { 7 MSO_I, 5 MSO_I }
+};
+const sal_uInt16 mso_sptArcSegm[] =
+{
+ 0xa604, 0xab00, 0x0001, 0x6001, 0x8000,
+ 0xa604, 0xaa00, 0x8000
+};
+const SvxMSDffCalculationData mso_sptArcCalc[] =
+{
+ { 0x4009, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x2000, { 0x400, 10800, 0 } },
+ { 0x400a, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x2000, { 0x402, 10800, 0 } },
+ { 0x4009, { 10800, DFF_Prop_adjust2Value, 0 } },
+ { 0x2000, { 0x404, 10800, 0 } },
+ { 0x400a, { 10800, DFF_Prop_adjust2Value, 0 } },
+ { 0x2000, { 0x406, 10800, 0 } }
+};
+const sal_Int32 mso_sptArcDefault[] =
+{
+ 2, 270, 0
+};
+const SvxMSDffVertPair mso_sptStandardGluePoints[] =
+{
+ { 10800, 0 }, { 0, 10800 }, { 10800, 21600 }, { 21600, 10800 }
+};
+const SvxMSDffHandle mso_sptArcHandle[] =
+{
+ { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE,
+ 10800, 0x100, 10800, 10800, 10800, 10800, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE,
+ 10800, 0x101, 10800, 10800, 10800, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoArc =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptArcVert), SAL_N_ELEMENTS( mso_sptArcVert ),
+ const_cast<sal_uInt16*>(mso_sptArcSegm), sizeof( mso_sptArcSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptArcCalc), SAL_N_ELEMENTS( mso_sptArcCalc ),
+ const_cast<sal_Int32*>(mso_sptArcDefault),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptArcHandle), SAL_N_ELEMENTS( mso_sptArcHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptTextSimpleVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0, 0 }
+};
+const mso_CustomShape msoTextSimple =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextSimpleVert), SAL_N_ELEMENTS( mso_sptTextSimpleVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptRectangleVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0, 0 }
+};
+const mso_CustomShape msoRectangle =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptRectangleVert), SAL_N_ELEMENTS( mso_sptRectangleVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptRoundRectangleVert[] = // adj value 0 -> 10800
+{
+ { 7 MSO_I, 0 }, { 0, 8 MSO_I }, { 0, 9 MSO_I }, { 7 MSO_I, 21600 },
+ { 10 MSO_I, 21600 }, { 21600, 9 MSO_I }, { 21600, 8 MSO_I }, { 10 MSO_I, 0 }
+};
+const sal_uInt16 mso_sptRoundRectangleSegm[] =
+{
+ 0x4000, 0xa701, 0x0001, 0xa801, 0x0001, 0xa701, 0x0001, 0xa801, 0x6000, 0x8000
+};
+const SvxMSDffCalculationData mso_sptRoundRectangleCalc[] =
+{
+ { 0x000e, { 0, 45, 0 } },
+ { 0x6009, { DFF_Prop_adjustValue, 0x400, 0 } },
+ { 0x2001, { 0x401, 3163, 7636 } },
+ { 0x6000, { DFF_Prop_geoLeft, 0x402, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, 0x402, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x402 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x402 } },
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } }
+};
+const SvxMSDffTextRectangles mso_sptRoundRectangleTextRect[] =
+{
+ { { 3 MSO_I, 4 MSO_I }, { 5 MSO_I, 6 MSO_I } }
+};
+const SvxMSDffHandle mso_sptRoundRectangleHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED,
+ 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoRoundRectangle =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptRoundRectangleVert), SAL_N_ELEMENTS( mso_sptRoundRectangleVert ),
+ const_cast<sal_uInt16*>(mso_sptRoundRectangleSegm), sizeof( mso_sptRoundRectangleSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptRoundRectangleCalc), SAL_N_ELEMENTS( mso_sptRoundRectangleCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault3600),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptRoundRectangleTextRect), SAL_N_ELEMENTS( mso_sptRoundRectangleTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptRoundRectangleHandle), SAL_N_ELEMENTS( mso_sptRoundRectangleHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptRightTriangleVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0, 0 }
+};
+const SvxMSDffTextRectangles mso_sptRightTriangleTextRect[] =
+{
+ { { 1900, 12700 }, { 12700, 19700 } }
+};
+const SvxMSDffVertPair mso_sptRightTriangleGluePoints[] =
+{
+ { 0, 0 }, { 0, 10800 }, { 0, 21600 }, { 10800, 21600 }, { 21600, 21600 }, { 10800, 10800 }
+};
+const mso_CustomShape msoRightTriangle =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptRightTriangleVert), SAL_N_ELEMENTS( mso_sptRightTriangleVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptRightTriangleTextRect), SAL_N_ELEMENTS( mso_sptRightTriangleTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptRightTriangleGluePoints), SAL_N_ELEMENTS( mso_sptRightTriangleGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptEllipseVert[] =
+{
+ { 10800, 10800 }, { 10800, 10800 }, { 0, 360 }
+};
+const sal_uInt16 mso_sptEllipseSegm[] =
+{
+ 0xa203, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptEllipseTextRect[] =
+{
+ { { 3163, 3163 }, { 18437, 18437 } }
+};
+const SvxMSDffVertPair mso_sptEllipseGluePoints[] =
+{
+ { 10800, 0 }, { 3163, 3163 }, { 0, 10800 }, { 3163, 18437 }, { 10800, 21600 }, { 18437, 18437 }, { 21600, 10800 }, { 18437, 3163 }
+};
+const mso_CustomShape msoEllipse =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptEllipseVert), SAL_N_ELEMENTS( mso_sptEllipseVert ),
+ const_cast<sal_uInt16*>(mso_sptEllipseSegm), sizeof( mso_sptEllipseSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptEllipseTextRect), SAL_N_ELEMENTS( mso_sptEllipseTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptParallelogramVert[] = // adjustment1 : 0 - 21600
+{
+ { 0 MSO_I, 0 }, { 21600, 0 }, { 1 MSO_I, 21600 }, { 0, 21600 }
+};
+const sal_uInt16 mso_sptParallelogramSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptParallelogramCalc[] =
+{
+ { 0x4000, { 0, DFF_Prop_adjustValue, 0 } },
+ { 0x8000, { 0, 21600, DFF_Prop_adjustValue } },
+ { 0x2001, { DFF_Prop_adjustValue, 10, 24 } },
+ { 0x2000, { 0x0402, 1750, 0 } },
+ { 0x8000, { 21600, 0, 0x0403 } },
+ { 0x2001, { 0x400, 1, 2 } },
+ { 0x4000, { 10800, 0x405, 0 } },
+ { 0x2000, { 0x400, 0, 10800 } },
+ { 0x6006, { 0x407, 0x40d, 0 } },
+ { 0x8000, { 10800, 0, 0x405 } },
+ { 0x6006, { 0x407, 0x40c, 21600 } },
+ { 0x8000, { 21600, 0, 0x405 } },
+ { 0x8001, { 21600, 10800, 0x400 } },
+ { 0x8000, { 21600, 0, 0x40c } }
+};
+const SvxMSDffTextRectangles mso_sptParallelogramTextRect[] =
+{
+ { { 3 MSO_I, 3 MSO_I }, { 4 MSO_I, 4 MSO_I } }
+};
+const SvxMSDffVertPair mso_sptParallelogramGluePoints[] =
+{
+ { 6 MSO_I, 0 }, { 10800, 8 MSO_I }, { 11 MSO_I, 10800 }, { 9 MSO_I, 21600 }, { 10800, 10 MSO_I }, { 5 MSO_I, 10800 }
+};
+const SvxMSDffHandle mso_sptParallelogramHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0, 10800, 10800, 0, 21600, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoParallelogram =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptParallelogramVert), SAL_N_ELEMENTS( mso_sptParallelogramVert ),
+ const_cast<sal_uInt16*>(mso_sptParallelogramSegm), sizeof( mso_sptParallelogramSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptParallelogramCalc), SAL_N_ELEMENTS( mso_sptParallelogramCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptParallelogramTextRect), SAL_N_ELEMENTS( mso_sptParallelogramTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptParallelogramGluePoints), SAL_N_ELEMENTS( mso_sptParallelogramGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptParallelogramHandle), SAL_N_ELEMENTS( mso_sptParallelogramHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptDiamondVert[] =
+{
+ { 10800, 0 }, { 21600, 10800 }, { 10800, 21600 }, { 0, 10800 }, { 10800, 0 }
+};
+const SvxMSDffTextRectangles mso_sptDiamondTextRect[] =
+{
+ { { 5400, 5400 }, { 16200, 16200 } }
+};
+const mso_CustomShape msoDiamond =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptDiamondVert), SAL_N_ELEMENTS( mso_sptDiamondVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptDiamondTextRect), SAL_N_ELEMENTS( mso_sptDiamondTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptTrapezoidVert[] = // adjustment1 : 0 - 10800
+{
+ { 0, 0 }, { 21600, 0 }, {0 MSO_I, 21600 }, { 1 MSO_I, 21600 }
+};
+const sal_uInt16 mso_sptTrapezoidSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptTrapezoidCalc[] =
+{
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2001, { DFF_Prop_adjustValue, 10, 18 } },
+ { 0x2000, { 0x0402, 1750, 0 } },
+ { 0x8000, { 21600, 0, 0x403 } },
+ { 0x2001, { DFF_Prop_adjustValue, 1, 2 } },
+ { 0x8000, { 21600, 0, 0x405 } }
+};
+const SvxMSDffTextRectangles mso_sptTrapezoidTextRect[] =
+{
+ { { 3 MSO_I, 3 MSO_I }, { 4 MSO_I, 4 MSO_I } }
+};
+const SvxMSDffVertPair mso_sptTrapezoidGluePoints[] =
+{
+ { 6 MSO_I, 10800 }, { 10800, 21600 }, { 5 MSO_I, 10800 }, { 10800, 0 }
+};
+const SvxMSDffHandle mso_sptTrapezoidHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 1, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoTrapezoid =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTrapezoidVert), SAL_N_ELEMENTS( mso_sptTrapezoidVert ),
+ const_cast<sal_uInt16*>(mso_sptTrapezoidSegm), sizeof( mso_sptTrapezoidSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTrapezoidCalc), SAL_N_ELEMENTS( mso_sptTrapezoidCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptTrapezoidTextRect), SAL_N_ELEMENTS( mso_sptTrapezoidTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptTrapezoidGluePoints), SAL_N_ELEMENTS( mso_sptTrapezoidGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptTrapezoidHandle), SAL_N_ELEMENTS( mso_sptTrapezoidHandle ) // handles
+};
+
+/*
+
+ The side of the enclosing square for the regular (all sides the
+ same, all angles the same) octagon described below is 21600. Let's
+ call that 'a'.
+
+ The "adjustment1" is the horizontal (or vertical) distance from a
+ side of the square to the nearest vertex. Let's call that 'd'.
+
+ Let's call the side of the regular octagon 'b'.
+
+ We know a. We want d. d=(a-b)/2
+
+ Pythagoras says that b^2 = 2d^2
+
+ Solving for b, we get b = (sqrt(2)-1)a
+
+
+ !------------a=21600-------!
+
+ !--d--!
+ x--------------x
+ / \
+ / \
+ / \
+ / \
+ / \
+ x x
+ ! !
+ ! !
+ ! !
+ ! !
+ ! !
+ ! !
+ x x
+ \ /
+ \ /
+ \ /
+ \ /
+ \ /
+ x--------------x
+
+*/
+
+const SvxMSDffVertPair mso_sptOctagonVert[] = // adjustment1 : 0 - 10800
+{
+ { 0 MSO_I, 0 }, { 2 MSO_I, 0 }, { 21600, 1 MSO_I }, { 21600, 3 MSO_I },
+ { 2 MSO_I, 21600 }, { 0 MSO_I, 21600 }, { 0, 3 MSO_I }, { 0, 1 MSO_I }
+};
+const sal_uInt16 mso_sptOctagonSegm[] =
+{
+ 0x4000, 0x0007, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptOctagonCalc[] =
+{
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { DFF_Prop_adjustValue, 1, 2 } },
+ { 0x6000, { DFF_Prop_geoLeft, 0x404, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, 0x404, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x404 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x404 } }
+};
+const sal_Int32 mso_sptOctagonDefault[] =
+{
+ 1, static_cast<sal_Int32>((21600 - ((M_SQRT2-1)*21600)) / 2)
+};
+const SvxMSDffTextRectangles mso_sptOctagonTextRect[] =
+{
+ { { 5 MSO_I, 6 MSO_I }, { 7 MSO_I, 8 MSO_I } }
+};
+const SvxMSDffHandle mso_sptOctagonHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoOctagon =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptOctagonVert), SAL_N_ELEMENTS( mso_sptOctagonVert ),
+ const_cast<sal_uInt16*>(mso_sptOctagonSegm), sizeof( mso_sptOctagonSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptOctagonCalc), SAL_N_ELEMENTS( mso_sptOctagonCalc ),
+ const_cast<sal_Int32*>(mso_sptOctagonDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptOctagonTextRect), SAL_N_ELEMENTS( mso_sptOctagonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptOctagonHandle), SAL_N_ELEMENTS( mso_sptOctagonHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptIsocelesTriangleVert[] = // adjustment1 : 0 - 21600
+{
+ { 0 MSO_I, 0 }, { 21600, 21600 }, { 0, 21600 }
+};
+const sal_uInt16 mso_sptIsocelesTriangleSegm[] =
+{
+ 0x4000, 0x0002, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptIsocelesTriangleCalc[] =
+{
+ { 0x4000, { 0, DFF_Prop_adjustValue, 0 } },
+ { 0x2001, { DFF_Prop_adjustValue, 1, 2 } },
+ { 0x2000, { 0x401, 10800, 0 } },
+ { 0x2001, { DFF_Prop_adjustValue, 2, 3 } },
+ { 0x2000, { 0x403, 7200, 0 } },
+ { 0x8000, { 21600, 0, 0x400 } },
+ { 0x2001, { 0x405, 1, 2 } },
+ { 0x8000, { 21600, 0, 0x406 } }
+};
+const SvxMSDffTextRectangles mso_sptIsocelesTriangleTextRect[] =
+{
+ { { 1 MSO_I, 10800 }, { 2 MSO_I, 18000 } },
+ { { 3 MSO_I, 7200 }, { 4 MSO_I, 21600 } }
+};
+const SvxMSDffVertPair mso_sptIsocelesTriangleGluePoints[] =
+{
+ { 0 MSO_I, 0 }, { 1 MSO_I, 10800 }, { 0, 21600 }, { 10800, 21600 }, { 21600, 21600 }, { 7 MSO_I, 10800 }
+};
+const SvxMSDffHandle mso_sptIsocelesTriangleHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0, 10800, 10800, 0, 21600, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoIsocelesTriangle =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptIsocelesTriangleVert), SAL_N_ELEMENTS( mso_sptIsocelesTriangleVert ),
+ const_cast<sal_uInt16*>(mso_sptIsocelesTriangleSegm), sizeof( mso_sptIsocelesTriangleSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptIsocelesTriangleCalc), SAL_N_ELEMENTS( mso_sptIsocelesTriangleCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault10800),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptIsocelesTriangleTextRect), SAL_N_ELEMENTS( mso_sptIsocelesTriangleTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptIsocelesTriangleGluePoints), SAL_N_ELEMENTS( mso_sptIsocelesTriangleGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptIsocelesTriangleHandle), SAL_N_ELEMENTS( mso_sptIsocelesTriangleHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptHexagonVert[] = // adjustment1 : 0 - 10800
+{
+ { 0 MSO_I, 0 }, { 1 MSO_I, 0 }, { 21600, 10800 }, { 1 MSO_I, 21600 },
+ { 0 MSO_I, 21600 }, { 0, 10800 }
+};
+const sal_uInt16 mso_sptHexagonSegm[] =
+{
+ 0x4000, 0x0005, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptHexagonCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { DFF_Prop_adjustValue, 100, 234 } },
+ { 0x2000, { 0x402, 1700, 0 } },
+ { 0x8000, { 21600, 0, 0x403 } }
+};
+const SvxMSDffTextRectangles mso_sptHexagonTextRect[] =
+{
+ { { 3 MSO_I, 3 MSO_I }, { 4 MSO_I, 4 MSO_I } }
+};
+const SvxMSDffHandle mso_sptHexagonHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoHexagon =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptHexagonVert), SAL_N_ELEMENTS( mso_sptHexagonVert ),
+ const_cast<sal_uInt16*>(mso_sptHexagonSegm), sizeof( mso_sptHexagonSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptHexagonCalc), SAL_N_ELEMENTS( mso_sptHexagonCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptHexagonTextRect), SAL_N_ELEMENTS( mso_sptHexagonTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptHexagonHandle), SAL_N_ELEMENTS( mso_sptHexagonHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptPentagonVert[] =
+{
+ { 10800, 0 }, { 0, 8260 }, { 4230, 21600 }, { 17370, 21600 },
+ { 21600, 8260 }, { 10800, 0 }
+};
+const SvxMSDffTextRectangles mso_sptPentagonTextRect[] =
+{
+ { { 4230, 5080 }, { 17370, 21600 } }
+};
+const SvxMSDffVertPair mso_sptPentagonGluePoints[] =
+{
+ { 10800, 0 }, { 0, 8260 }, { 4230, 21600 }, { 10800, 21600 },
+ { 17370, 21600 }, { 21600, 8260 }
+};
+const mso_CustomShape msoPentagon =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptPentagonVert), SAL_N_ELEMENTS( mso_sptPentagonVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptPentagonTextRect), SAL_N_ELEMENTS( mso_sptPentagonTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptPentagonGluePoints), SAL_N_ELEMENTS( mso_sptPentagonGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptPlusVert[] = // adjustment1 : 0 - 10800
+{
+ { 1 MSO_I, 0 }, { 2 MSO_I, 0 }, { 2 MSO_I, 1 MSO_I }, { 21600, 1 MSO_I },
+ { 21600, 3 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 2 MSO_I, 21600 }, { 1 MSO_I, 21600 },
+ { 1 MSO_I, 3 MSO_I }, { 0, 3 MSO_I }, { 0, 1 MSO_I }, { 1 MSO_I, 1 MSO_I }, { 1 MSO_I, 0 }
+};
+const SvxMSDffCalculationData mso_sptPlusCalc[] =
+{
+ { 0x2001, { DFF_Prop_adjustValue, 10799, 10800 } },
+ { 0x2000, { 0x400, 0, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x400 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x400 } }
+};
+const SvxMSDffTextRectangles mso_sptPlusTextRect[] =
+{
+ { { 1 MSO_I, 1 MSO_I }, { 2 MSO_I, 3 MSO_I } }
+};
+const SvxMSDffHandle mso_sptPlusHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED,
+ 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoPlus =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptPlusVert), SAL_N_ELEMENTS( mso_sptPlusVert ),
+ nullptr, 0,
+ const_cast<SvxMSDffCalculationData*>(mso_sptPlusCalc), SAL_N_ELEMENTS( mso_sptPlusCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptPlusTextRect), SAL_N_ELEMENTS( mso_sptPlusTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptPlusHandle), SAL_N_ELEMENTS( mso_sptPlusHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptCanVert[] = // adjustment1 : 0 - 10800
+{
+ { 44, 0 },
+ { 20, 0 }, { 0, 2 MSO_I }, { 0, 0 MSO_I }, // ccp
+ { 0, 3 MSO_I }, // p
+ { 0, 4 MSO_I }, { 20, 21600 }, { 44, 21600 }, // ccp
+ { 68, 21600 }, { 88, 4 MSO_I }, { 88, 3 MSO_I }, // ccp
+ { 88, 0 MSO_I }, // p
+ { 88, 2 MSO_I }, { 68, 0 }, { 44, 0 }, // ccp
+ { 44, 0 }, // p
+ { 20, 0 }, { 0, 2 MSO_I }, { 0, 0 MSO_I }, // ccp
+ { 0, 5 MSO_I }, { 20, 6 MSO_I }, { 44, 6 MSO_I }, // ccp
+ { 68, 6 MSO_I },{ 88, 5 MSO_I }, { 88, 0 MSO_I }, // ccp
+ { 88, 2 MSO_I },{ 68, 0 }, { 44, 0 } // ccp
+};
+const sal_uInt16 mso_sptCanSegm[] =
+{
+ 0x4000, 0x2001, 0x0001, 0x2002, 0x0001, 0x2001, 0x6001, 0x8000,
+ 0x4000, 0x2004, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptCanCalc[] =
+{
+ { 0x2001, { DFF_Prop_adjustValue, 2, 4 } }, // 1/4
+ { 0x2001, { 0x0400, 6, 11 } },
+ { 0xa000, { 0x0400, 0, 0x0401 } },
+ { 0x8000, { 21600, 0, 0x0400 } },
+ { 0x6000, { 0x0403, 0x0401, 0 } },
+ { 0x6000, { 0x0400, 0x0401, 0 } },
+ { 0x2001, { DFF_Prop_adjustValue, 2, 2 } },
+ { 0x0000, { 44, 0, 0 } }
+};
+const SvxMSDffTextRectangles mso_sptCanTextRect[] =
+{
+ { { 0, 6 MSO_I }, { 88, 3 MSO_I } }
+};
+const SvxMSDffVertPair mso_sptCanGluePoints[] =
+{
+ { 44, 6 MSO_I }, { 44, 0 }, { 0, 10800 }, { 44, 21600 }, { 88, 10800 }
+};
+const SvxMSDffHandle mso_sptCanHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 7 + 3, 0x100, 44, 10800, MIN_INT32, 0x7fffffff, 0, 10800 }
+};
+const mso_CustomShape msoCan =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCanVert), SAL_N_ELEMENTS( mso_sptCanVert ),
+ const_cast<sal_uInt16*>(mso_sptCanSegm), sizeof( mso_sptCanSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCanCalc), SAL_N_ELEMENTS( mso_sptCanCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptCanTextRect), SAL_N_ELEMENTS( mso_sptCanTextRect ),
+ 88, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptCanGluePoints), SAL_N_ELEMENTS( mso_sptCanGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptCanHandle), SAL_N_ELEMENTS( mso_sptCanHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptArrowVert[] = // adjustment1: x 0 - 21600
+{ // adjustment2: y 0 - 10800
+ { 0, 0 MSO_I }, { 1 MSO_I, 0 MSO_I }, { 1 MSO_I, 0 }, { 21600, 10800 },
+ { 1 MSO_I, 21600 }, { 1 MSO_I, 2 MSO_I }, { 0, 2 MSO_I }
+};
+const sal_uInt16 mso_sptArrowSegm[] =
+{
+ 0x4000, 0x0006, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptArrowCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjust2Value } },
+ { 0x8000, { 21600, 0, 0x401 } },
+ { 0x6001, { 0x403, 0x400, 10800 } },
+ { 0x6000, { 0x401, 0x404, 0 } },
+ { 0x6001, { 0x401, 0x400, 10800 } },
+ { 0xa000, { 0x401, 0, 0x406 } }
+};
+const SvxMSDffTextRectangles mso_sptArrowTextRect[] =
+{
+ { { 0, 0 MSO_I }, { 5 MSO_I, 2 MSO_I } }
+};
+const SvxMSDffHandle mso_sptArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0x101, 10800, 10800, 0, 21600, 0, 10800 }
+};
+const mso_CustomShape msoArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptArrowVert), SAL_N_ELEMENTS( mso_sptArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptArrowSegm), sizeof( mso_sptArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptArrowCalc), SAL_N_ELEMENTS( mso_sptArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault16200and5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptArrowTextRect), SAL_N_ELEMENTS( mso_sptArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptArrowHandle), SAL_N_ELEMENTS( mso_sptArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptLeftArrowVert[] = // adjustment1: x 0 - 21600
+{ // adjustment2: y 0 - 10800
+ { 21600, 0 MSO_I }, { 1 MSO_I, 0 MSO_I }, { 1 MSO_I, 0 }, { 0, 10800 },
+ { 1 MSO_I, 21600 }, { 1 MSO_I, 2 MSO_I }, { 21600, 2 MSO_I }
+};
+const sal_uInt16 mso_sptLeftArrowSegm[] =
+{
+ 0x4000, 0x0006, 0x6001, 0x8000
+};
+const sal_Int32 mso_sptLeftArrowDefault[] =
+{
+ 2, 5400, 5400
+};
+const SvxMSDffTextRectangles mso_sptLeftArrowTextRect[] =
+{
+ { { 7 MSO_I, 0 MSO_I }, { 21600, 2 MSO_I } }
+};
+const SvxMSDffHandle mso_sptLeftArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0x101, 10800, 10800, 0, 21600, 0, 10800 }
+};
+const mso_CustomShape msoLeftArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptLeftArrowVert), SAL_N_ELEMENTS( mso_sptLeftArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptLeftArrowSegm), sizeof( mso_sptLeftArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptArrowCalc), SAL_N_ELEMENTS( mso_sptArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptLeftArrowDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptLeftArrowTextRect), SAL_N_ELEMENTS( mso_sptLeftArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptLeftArrowHandle), SAL_N_ELEMENTS( mso_sptLeftArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptDownArrowVert[] = // adjustment1: x 0 - 21600
+{ // adjustment2: y 0 - 10800
+ { 0 MSO_I, 0 }, { 0 MSO_I, 1 MSO_I }, { 0, 1 MSO_I }, { 10800, 21600 },
+ { 21600, 1 MSO_I }, { 2 MSO_I, 1 MSO_I }, { 2 MSO_I, 0 }
+};
+const sal_uInt16 mso_sptDownArrowSegm[] =
+{
+ 0x4000, 0x0006, 0x6001, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptDownArrowTextRect[] =
+{
+ { { 0 MSO_I, 0 }, { 2 MSO_I, 5 MSO_I } }
+};
+const SvxMSDffHandle mso_sptDownArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x101, 0x100, 10800, 10800, 0, 10800, 0, 21600 }
+};
+const mso_CustomShape msoDownArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptDownArrowVert), SAL_N_ELEMENTS( mso_sptDownArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptDownArrowSegm), sizeof( mso_sptDownArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptArrowCalc), SAL_N_ELEMENTS( mso_sptArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault16200and5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptDownArrowTextRect), SAL_N_ELEMENTS( mso_sptDownArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptDownArrowHandle), SAL_N_ELEMENTS( mso_sptDownArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptUpArrowVert[] = // adjustment1: x 0 - 21600
+{ // adjustment2: y 0 - 10800
+ { 0 MSO_I, 21600 }, { 0 MSO_I, 1 MSO_I }, { 0, 1 MSO_I }, { 10800, 0 },
+ { 21600, 1 MSO_I }, { 2 MSO_I, 1 MSO_I }, { 2 MSO_I, 21600 }
+};
+const sal_uInt16 mso_sptUpArrowSegm[] =
+{
+ 0x4000, 0x0006, 0x6001, 0x8000
+};
+const sal_Int32 mso_sptUpArrowDefault[] =
+{
+ 2, 5400, 5400
+};
+const SvxMSDffTextRectangles mso_sptUpArrowTextRect[] =
+{
+ { { 0 MSO_I, 7 MSO_I }, { 2 MSO_I, 21600 } }
+};
+const SvxMSDffHandle mso_sptUpArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x101, 0x100, 10800, 10800, 0, 10800, 0, 21600 }
+};
+const mso_CustomShape msoUpArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptUpArrowVert), SAL_N_ELEMENTS( mso_sptUpArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptUpArrowSegm), sizeof( mso_sptUpArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptArrowCalc), SAL_N_ELEMENTS( mso_sptArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptUpArrowDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptUpArrowTextRect), SAL_N_ELEMENTS( mso_sptUpArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptUpArrowHandle), SAL_N_ELEMENTS( mso_sptUpArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptLeftRightArrowVert[] = // adjustment1: x 0 - 10800
+{ // adjustment2: y 0 - 10800
+ { 0, 10800 }, { 0 MSO_I, 0 }, { 0 MSO_I, 1 MSO_I }, { 2 MSO_I, 1 MSO_I },
+ { 2 MSO_I, 0 }, { 21600, 10800 }, { 2 MSO_I, 21600 }, { 2 MSO_I, 3 MSO_I },
+ { 0 MSO_I, 3 MSO_I }, { 0 MSO_I, 21600 }
+};
+const sal_uInt16 mso_sptLeftRightArrowSegm[] =
+{
+ 0x4000, 0x0009, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptDoubleArrowCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjust2Value } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjust2Value } },
+ { 0x6001, { DFF_Prop_adjustValue, 0x404, 10800 } },
+ { 0x8000, { 21600, 0, 0x405 } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } },
+ { 0x6001, { DFF_Prop_adjust2Value, 0x407, 10800 } },
+ { 0x8000, { 21600, 0, 0x408 } }
+};
+const sal_Int32 mso_sptLeftRightArrowDefault[] =
+{
+ 2, 4300, 5400
+};
+const SvxMSDffTextRectangles mso_sptLeftRightArrowTextRect[] =
+{
+ { { 5 MSO_I, 1 MSO_I }, { 6 MSO_I, 3 MSO_I } }
+};
+const SvxMSDffHandle mso_sptLeftRightArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0x101, 10800, 10800, 0, 10800, 0, 10800 }
+};
+const mso_CustomShape msoLeftRightArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptLeftRightArrowVert), SAL_N_ELEMENTS( mso_sptLeftRightArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptLeftRightArrowSegm), sizeof( mso_sptLeftRightArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptDoubleArrowCalc), SAL_N_ELEMENTS( mso_sptDoubleArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptLeftRightArrowDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptLeftRightArrowTextRect), SAL_N_ELEMENTS( mso_sptLeftRightArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptLeftRightArrowHandle), SAL_N_ELEMENTS( mso_sptLeftRightArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptUpDownArrowVert[] = // adjustment1: x 0 - 10800
+{ // adjustment2: y 0 - 10800
+ { 0, 1 MSO_I }, { 10800, 0 }, { 21600, 1 MSO_I }, { 2 MSO_I, 1 MSO_I },
+ { 2 MSO_I, 3 MSO_I }, { 21600, 3 MSO_I }, { 10800, 21600 }, { 0, 3 MSO_I },
+ { 0 MSO_I, 3 MSO_I }, { 0 MSO_I, 1 MSO_I }
+};
+const sal_uInt16 mso_sptUpDownArrowSegm[] =
+{
+ 0x4000, 0x0009, 0x6001, 0x8000
+};
+const sal_Int32 mso_sptUpDownArrowDefault[] =
+{
+ 2, 5400, 4300
+};
+const SvxMSDffTextRectangles mso_sptUpDownArrowTextRect[] =
+{
+ { { 0 MSO_I, 8 MSO_I }, { 2 MSO_I, 9 MSO_I } }
+};
+const SvxMSDffHandle mso_sptUpDownArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0x101, 10800, 10800, 0, 10800, 0, 10800 }
+};
+const mso_CustomShape msoUpDownArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptUpDownArrowVert), SAL_N_ELEMENTS( mso_sptUpDownArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptUpDownArrowSegm), sizeof( mso_sptUpDownArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptDoubleArrowCalc), SAL_N_ELEMENTS( mso_sptDoubleArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptUpDownArrowDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptUpDownArrowTextRect), SAL_N_ELEMENTS( mso_sptUpDownArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptUpDownArrowHandle), SAL_N_ELEMENTS( mso_sptUpDownArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptQuadArrowVert[] = // adjustment1: x 0 - 10800, adjustment2: x 0 - 10800
+{ // adjustment3: y 0 - 10800
+ { 0, 10800 }, { 0 MSO_I, 1 MSO_I }, { 0 MSO_I, 2 MSO_I }, { 2 MSO_I, 2 MSO_I },
+ { 2 MSO_I, 0 MSO_I }, { 1 MSO_I, 0 MSO_I }, { 10800, 0 }, { 3 MSO_I, 0 MSO_I },
+ { 4 MSO_I, 0 MSO_I }, { 4 MSO_I, 2 MSO_I }, { 5 MSO_I, 2 MSO_I }, { 5 MSO_I, 1 MSO_I },
+ { 21600, 10800 }, { 5 MSO_I, 3 MSO_I }, { 5 MSO_I, 4 MSO_I }, { 4 MSO_I, 4 MSO_I },
+ { 4 MSO_I, 5 MSO_I }, { 3 MSO_I, 5 MSO_I }, { 10800, 21600 }, { 1 MSO_I, 5 MSO_I },
+ { 2 MSO_I, 5 MSO_I }, { 2 MSO_I, 4 MSO_I }, { 0 MSO_I, 4 MSO_I }, { 0 MSO_I, 3 MSO_I }
+};
+const sal_uInt16 mso_sptQuadArrowSegm[] =
+{
+ 0x4000, 0x0017, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptQuadArrowCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjust2Value } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjust3Value } }
+};
+const sal_Int32 mso_sptQuadArrowDefault[] =
+{
+ 3, 6500, 8600, 4300
+};
+const SvxMSDffTextRectangles mso_sptQuadArrowTextRect[] = // todo
+{
+ { { 0, 0 }, { 21600, 21600 } }
+};
+const SvxMSDffHandle mso_sptQuadArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL,
+ 0x101, 0x102, 10800, 10800, 0x100, 10800, 0, 0x100 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x100, 0, 10800, 10800, 0x102, 0x101, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoQuadArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptQuadArrowVert), SAL_N_ELEMENTS( mso_sptQuadArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptQuadArrowSegm), sizeof( mso_sptQuadArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptQuadArrowCalc), SAL_N_ELEMENTS( mso_sptQuadArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptQuadArrowDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptQuadArrowTextRect), SAL_N_ELEMENTS( mso_sptQuadArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptQuadArrowHandle), SAL_N_ELEMENTS( mso_sptQuadArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptLeftRightUpArrowVert[] = // adjustment1: x 0 - 10800, adjustment2: x 0 - 10800
+{ // adjustment3: y 0 - 21600
+ { 10800, 0 }, { 3 MSO_I, 2 MSO_I }, { 4 MSO_I, 2 MSO_I }, { 4 MSO_I, 1 MSO_I },
+ { 5 MSO_I, 1 MSO_I }, { 5 MSO_I, 0 MSO_I }, { 21600, 10800 }, { 5 MSO_I, 3 MSO_I },
+ { 5 MSO_I, 4 MSO_I }, { 2 MSO_I, 4 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 0, 10800 },
+ { 2 MSO_I, 0 MSO_I }, { 2 MSO_I, 1 MSO_I }, { 1 MSO_I, 1 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 0 MSO_I, 2 MSO_I }
+};
+const sal_uInt16 mso_sptLeftRightUpArrowSegm[] =
+{
+ 0x4000, 0x0010, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptLeftRightUpArrowCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 0
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } }, // 1
+ { 0x6001, { 0x0403, DFF_Prop_adjust3Value, 21600 } }, // 2
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }, // 3
+ { 0x8000, { 21600, 0, DFF_Prop_adjust2Value } }, // 4
+ { 0x8000, { 21600, 0, 0x0402 } } // 5
+};
+const sal_Int32 mso_sptLeftRightUpArrowDefault[] =
+{
+ 3, 6500, 8600, 6200
+};
+const SvxMSDffTextRectangles mso_sptLeftRightUpArrowTextRect[] = // todo
+{
+ { { 0, 0 }, { 21600, 21600 } }
+};
+const SvxMSDffHandle mso_sptLeftRightUpArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL,
+ 0x101, 0x102, 10800, 10800, 0x100, 10800, 0, 0x100 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x100, 0, 10800, 10800, 0x102, 0x101, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoLeftRightUpArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptLeftRightUpArrowVert), SAL_N_ELEMENTS( mso_sptLeftRightUpArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptLeftRightUpArrowSegm), sizeof( mso_sptLeftRightUpArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptLeftRightUpArrowCalc), SAL_N_ELEMENTS( mso_sptLeftRightUpArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptLeftRightUpArrowDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptLeftRightUpArrowTextRect), SAL_N_ELEMENTS( mso_sptLeftRightUpArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptLeftRightUpArrowHandle), SAL_N_ELEMENTS( mso_sptLeftRightUpArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptBentArrowVert[] = // adjustment1 : x 12427 - 21600
+{ // adjustment2 : y 0 - 6079
+ { 0, 21600 }, { 0, 12160 }, { 12427, 1 MSO_I }, { 0 MSO_I, 1 MSO_I },
+ { 0 MSO_I, 0 }, { 21600, 6079 }, { 0 MSO_I, 12158 }, { 0 MSO_I, 2 MSO_I },
+ { 12427, 2 MSO_I }, { 4 MSO_I, 12160 }, { 4 MSO_I, 21600 }
+};
+const sal_uInt16 mso_sptBentArrowSegm[] =
+{
+ 0x4000, 0x0001, 0xa801, 0x0006, 0xa701, 0x0001, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptBentArrowCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x8000, { 12158, 0, DFF_Prop_adjust2Value } },
+ { 0x8000, { 6079, 0, DFF_Prop_adjust2Value } },
+ { 0x2001, { 0x0403, 2, 1 } }
+};
+const sal_Int32 mso_sptBentArrowDefault[] =
+{
+ 2, 15100, 2900
+};
+const SvxMSDffTextRectangles mso_sptBentArrowTextRect[] = // todo
+{
+ { { 0, 0 }, { 21600, 21600 } }
+};
+const SvxMSDffHandle mso_sptBentArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0x101, 10800, 10800, 12427, 21600, 0, 6079 }
+};
+const mso_CustomShape msoBentArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBentArrowVert), SAL_N_ELEMENTS( mso_sptBentArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptBentArrowSegm), sizeof( mso_sptBentArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBentArrowCalc), SAL_N_ELEMENTS( mso_sptBentArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptBentArrowDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptBentArrowTextRect), SAL_N_ELEMENTS( mso_sptBentArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptBentArrowHandle), SAL_N_ELEMENTS( mso_sptBentArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptUturnArrowVert[] =
+{
+ { 0, 21600 }, { 0, 8550 }, // pp
+ { 0, 3540 }, { 4370, 0 }, { 9270, 0 }, // ccp
+ { 13890, 0 }, { 18570, 3230 }, { 18600, 8300 }, // ccp
+ { 21600, 8300 }, { 15680, 14260 }, { 9700, 8300 }, { 12500, 8300 }, // pppp
+ { 12320, 6380 }, { 10870, 5850 }, { 9320, 5850 }, // ccp
+ { 7770, 5850 }, { 6040, 6410 }, { 6110, 8520 }, // ccp
+ { 6110, 21600 }
+};
+const sal_uInt16 mso_sptUturnArrowSegm[] =
+{
+ 0x4000, 0x0001, 0x2002, 0x0004, 0x2002, 0x0001, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptUturnArrowTextRect[] =
+{
+ { { 0, 8280 }, { 6110, 21600 } }
+};
+const mso_CustomShape msoUturnArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptUturnArrowVert), SAL_N_ELEMENTS( mso_sptUturnArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptUturnArrowSegm), sizeof( mso_sptUturnArrowSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptUturnArrowTextRect), SAL_N_ELEMENTS( mso_sptUturnArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptLeftUpArrowVert[] = // adjustment1 : x 0 - 21600, adjustment2 : x 0 - 21600
+{ // adjustment3 : y 0 - 21600
+ { 0, 5 MSO_I }, { 2 MSO_I, 0 MSO_I }, { 2 MSO_I, 7 MSO_I }, { 7 MSO_I, 7 MSO_I },
+ { 7 MSO_I, 2 MSO_I }, { 0 MSO_I, 2 MSO_I }, { 5 MSO_I, 0 }, { 21600, 2 MSO_I },
+ { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 1 MSO_I }, { 2 MSO_I, 1 MSO_I }, { 2 MSO_I, 21600 }
+};
+const sal_uInt16 mso_sptLeftUpArrowSegm[] =
+{
+ 0x4000, 0x000b, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptLeftUpArrowCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 0
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } }, // 1
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } }, // 2
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }, // 3
+ { 0x2001, { 0x0403, 1, 2 } }, // 4
+ { 0x6000, { DFF_Prop_adjustValue, 0x0404, 0 } }, // 5
+ { 0x8000, { 21600, 0, DFF_Prop_adjust2Value } }, // 6
+ { 0x6000, { DFF_Prop_adjustValue, 0x0406, 0 } }, // 7
+ { 0x8000, { 21600, 0, 0x406 } }, // 8
+ { 0xa000, { 0x408, 0, 0x406 } } // 9
+};
+const sal_Int32 mso_sptLeftUpArrowDefault[] =
+{
+ 3, 9340, 18500, 6200
+};
+const SvxMSDffTextRectangles mso_sptLeftUpArrowTextRect[] =
+{
+ { { 2 MSO_I, 7 MSO_I }, { 1 MSO_I, 1 MSO_I } },
+ { { 7 MSO_I, 2 MSO_I }, { 1 MSO_I, 1 MSO_I } }
+};
+const SvxMSDffHandle mso_sptLeftUpArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL,
+ 0x101, 0x102, 10800, 10800, 3 + 5, 21600, 0, 0x100 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x100, 0, 10800, 10800, 0x102, 3 + 9, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoLeftUpArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptLeftUpArrowVert), SAL_N_ELEMENTS( mso_sptLeftUpArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptLeftUpArrowSegm), sizeof( mso_sptLeftUpArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptLeftUpArrowCalc), SAL_N_ELEMENTS( mso_sptLeftUpArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptLeftUpArrowDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptLeftUpArrowTextRect), SAL_N_ELEMENTS( mso_sptLeftUpArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptLeftUpArrowHandle), SAL_N_ELEMENTS( mso_sptLeftUpArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptBentUpArrowVert[] = // adjustment1 : x 0 - 21600, adjustment2 : x 0 - 21600
+{ // adjustment3 : y 0 - 21600
+ { 0, 8 MSO_I }, { 7 MSO_I, 8 MSO_I }, { 7 MSO_I, 2 MSO_I }, { 0 MSO_I, 2 MSO_I },
+ { 5 MSO_I, 0 }, { 21600, 2 MSO_I }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 21600 },
+ { 0, 21600 }
+};
+const sal_uInt16 mso_sptBentUpArrowSegm[] =
+{
+ 0x4000, 0x0008, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptBentUpArrowCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 0
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } }, // 1
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } }, // 2
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }, // 3
+ { 0x2001, { 0x0403, 1, 2 } }, // 4
+ { 0x6000, { DFF_Prop_adjustValue, 0x0404, 0 } }, // 5
+ { 0x8000, { 21600, 0, DFF_Prop_adjust2Value } }, // 6
+ { 0x6000, { DFF_Prop_adjustValue, 0x0406, 0 } }, // 7
+ { 0x6000, { 0x0407, 0x0406, 0 } }, // 8
+ { 0x8000, { 21600, 0, 0x406 } }, // 9
+ { 0xa000, { 0x409, 0, 0x406 } } // a
+};
+const sal_Int32 mso_sptBentUpArrowDefault[] =
+{
+ 3, 9340, 18500, 7200
+};
+const SvxMSDffTextRectangles mso_sptBentUpArrowTextRect[] =
+{
+ { { 2 MSO_I, 7 MSO_I }, { 1 MSO_I, 1 MSO_I } },
+ { { 7 MSO_I, 2 MSO_I }, { 1 MSO_I, 1 MSO_I } }
+};
+const SvxMSDffHandle mso_sptBentUpArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL,
+ 0x101, 0x102, 10800, 10800, 3 + 5, 21600, 0, 0x100 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x100, 0, 10800, 10800, 0x102, 3 + 10, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoBentUpArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBentUpArrowVert), SAL_N_ELEMENTS( mso_sptBentUpArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptBentUpArrowSegm), sizeof( mso_sptBentUpArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBentUpArrowCalc), SAL_N_ELEMENTS( mso_sptBentUpArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptBentUpArrowDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptBentUpArrowTextRect), SAL_N_ELEMENTS( mso_sptBentUpArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptBentUpArrowHandle), SAL_N_ELEMENTS( mso_sptBentUpArrowHandle )
+};
+
+const SvxMSDffVertPair mso_sptCurvedRightVert[] =
+{
+ { 0, 0 }, { 23 MSO_I, 3 MSO_I }, { 22 MSO_I, 0 }, { 0, 4 MSO_I }, { 0, 15 MSO_I }, { 23 MSO_I, 1 MSO_I }, { 0, 7 MSO_I }, { 2 MSO_I, 13 MSO_I },
+ { 2 MSO_I, 14 MSO_I }, { 22 MSO_I, 8 MSO_I }, { 2 MSO_I, 12 MSO_I },
+ { 0, 0 }, { 23 MSO_I, 3 MSO_I }, { 2 MSO_I, 11 MSO_I }, { 26 MSO_I, 17 MSO_I }, { 0, 15 MSO_I }, { 23 MSO_I, 1 MSO_I }, { 26 MSO_I, 17 MSO_I }, { 22 MSO_I, 15 MSO_I },
+ { 0, 0 }, { 23 MSO_I, 3 MSO_I }, { 22 MSO_I, 0 }, { 0, 4 MSO_I },
+ { 0, 0 }, { 23 MSO_I, 3 MSO_I }, { 0, 4 MSO_I }, { 26 MSO_I, 17 MSO_I },
+ { 0, 15 MSO_I }, { 23 MSO_I, 1 MSO_I }, { 26 MSO_I, 17 MSO_I }, { 22 MSO_I, 15 MSO_I }
+};
+const sal_uInt16 mso_sptCurvedRightSegm[] =
+{
+ 0xa404,
+ 0xa304,
+ 0x0003,
+ 0xa508,
+ 0x6000,
+ 0x8000,
+ 0xa404,
+ 0xa304,
+ 0xa504,
+ 0x6000,
+ 0x8000
+};
+const SvxMSDffCalculationData mso_sptCurvedRightCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0xa000, { DFF_Prop_adjustValue, 21600, DFF_Prop_adjust2Value } },
+ { 0x2001, { 0x403, 1, 2 } },
+ { 0x6000, { DFF_Prop_adjust2Value, DFF_Prop_adjust2Value, 21600 } },
+ { 0xe000, { 0x405, DFF_Prop_adjust2Value, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x406, 1, 2 } },
+ { 0x4002, { 21600, DFF_Prop_adjustValue, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjust3Value } },
+ { 0xa00f, { 0x409, 21600, 0x404 } },
+ { 0x6000, { 0x404, 0x40a, 0 } },
+ { 0x6000, { 0x40b, DFF_Prop_adjust2Value, 21600 } },
+ { 0x6000, { 0x407, 0x40a, 0 } },
+ { 0xa000, { 0x40c, 21600, DFF_Prop_adjustValue } },
+ { 0xa000, { 0x405, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x40f, 1, 2 } },
+ { 0x6002, { 0x404, 0x407, 0 } },
+ { 0x6000, { DFF_Prop_adjustValue, DFF_Prop_adjust2Value, 21600 } },
+ { 0x2001, { 0x412, 1, 2 } },
+ { 0xa000, { 0x411, 0, 0x413 } },
+ { 0x0000, { 21600, 0, 0 } },
+ { 0x0000, { 21600, 0, 0 } },
+ { 0x0001, { 21600, 2, 1 } },
+ { 0xa000, { 0x411, 0, 0x404 } },
+ { 0x600f, { 0x418, 0x404, 21600 } },
+ { 0x8000, { 21600, 0, 0x419 } },
+ { 0x2000, { 0x408, 128, 0 } },
+ { 0x2001, { 0x405, 1, 2 } },
+ { 0x2000, { 0x405, 0, 128 } },
+ { 0xe000, { DFF_Prop_adjustValue, 0x411, 0x40c } },
+ { 0x600f, { 0x414, 0x404, 21600 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x420, 1, 2 } },
+ { 0x0001, { 21600, 21600, 1 } },
+ { 0x6001, { 0x409, 0x409, 1 } },
+ { 0xa000, { 0x422, 0, 0x423 } },
+ { 0x200d, { 0x424, 0, 0 } },
+ { 0x2000, { 0x425, 21600, 0 } },
+ { 0x8001, { 21600, 21600, 0x426 } },
+ { 0x2000, { 0x427, 64, 0 } },
+ { 0x2001, { DFF_Prop_adjustValue, 1, 2 } },
+ { 0x600f, { 0x421, 0x429, 21600 } },
+ { 0x8000, { 21600, 0, 0x42a } },
+ { 0x2000, { 0x42b, 64, 0 } },
+ { 0x2001, { 0x404, 1, 2 } },
+ { 0xa000, { DFF_Prop_adjust2Value, 0, 0x42d } },
+ { 0x0001, { 21600, 2195, 16384 } },
+ { 0x0001, { 21600, 14189, 16384 } }
+};
+const sal_Int32 mso_sptCurvedRightDefault[] =
+{
+ 3, 12960, 19440, 14400
+};
+const SvxMSDffTextRectangles mso_sptCurvedRightTextRect[] =
+{
+ { { 47 MSO_I, 45 MSO_I }, { 48 MSO_I, 46 MSO_I } }
+};
+const SvxMSDffVertPair mso_sptCurvedRightGluePoints[] =
+{
+ { 0, 17 MSO_I }, { 2 MSO_I, 14 MSO_I }, { 22 MSO_I, 8 MSO_I }, { 2 MSO_I, 12 MSO_I }, { 22 MSO_I, 16 MSO_I }
+};
+const SvxMSDffHandle mso_sptCurvedRightHandles[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 21600, 0x100, 10800, 10800, 0, 10800, 3 + 40, 3 + 29 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 21600, 0x101, 10800, 10800, 0, 10800, 3 + 27, 3 + 21 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x102, 21600, 10800, 10800, 3 + 44, 3 + 22, 3375, 21600 }
+};
+const mso_CustomShape msoCurvedRightArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedRightVert), SAL_N_ELEMENTS( mso_sptCurvedRightVert ),
+ const_cast<sal_uInt16*>(mso_sptCurvedRightSegm), sizeof( mso_sptCurvedRightSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCurvedRightCalc), SAL_N_ELEMENTS( mso_sptCurvedRightCalc ),
+ const_cast<sal_Int32*>(mso_sptCurvedRightDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptCurvedRightTextRect), SAL_N_ELEMENTS( mso_sptCurvedRightTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedRightGluePoints), SAL_N_ELEMENTS( mso_sptCurvedRightGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptCurvedRightHandles), SAL_N_ELEMENTS( mso_sptCurvedRightHandles )
+};
+
+const SvxMSDffVertPair mso_sptCurvedDownVert[] =
+{
+ { 0, 0 }, { 3 MSO_I, 23 MSO_I }, { 0, 22 MSO_I }, { 4 MSO_I, 0 },
+ { 15 MSO_I, 0 }, { 1 MSO_I, 23 MSO_I }, { 7 MSO_I, 0 }, { 13 MSO_I, 2 MSO_I },
+ { 14 MSO_I, 2 MSO_I }, { 8 MSO_I, 22 MSO_I }, { 12 MSO_I, 2 MSO_I },
+ { 0, 0 }, { 3 MSO_I, 23 MSO_I }, { 11 MSO_I, 2 MSO_I }, { 17 MSO_I, 26 MSO_I }, { 15 MSO_I, 0 },
+ { 1 MSO_I, 23 MSO_I }, { 17 MSO_I, 26 MSO_I }, { 15 MSO_I, 22 MSO_I },
+ { 0, 0 }, { 3 MSO_I, 23 MSO_I }, { 0, 22 MSO_I }, { 4 MSO_I, 0 },
+ { 0, 0 }, { 3 MSO_I, 23 MSO_I }, { 4 MSO_I, 0 }, { 17 MSO_I, 26 MSO_I },
+ { 15 MSO_I, 0 }, { 1 MSO_I, 23 MSO_I }, { 17 MSO_I, 26 MSO_I }, { 15 MSO_I, 22 MSO_I }
+};
+const sal_uInt16 mso_sptCurvedDownSegm[] =
+{
+ 0xa604,
+ 0xa504,
+ 0x0003,
+ 0xa308,
+ 0x6000,
+ 0x8000,
+ 0xa604,
+ 0xa504,
+ 0xa304,
+ 0x6000,
+ 0x8000
+};
+const SvxMSDffTextRectangles mso_sptCurvedDownTextRect[] =
+{
+ { { 45 MSO_I, 47 MSO_I }, { 46 MSO_I, 48 MSO_I } }
+};
+const SvxMSDffVertPair mso_sptCurvedDownGluePoints[] =
+{
+ { 17 MSO_I, 0 }, { 16 MSO_I, 22 MSO_I }, { 12 MSO_I, 2 MSO_I }, { 8 MSO_I, 22 MSO_I }, { 14 MSO_I, 2 MSO_I }
+};
+const SvxMSDffHandle mso_sptCurvedDownHandles[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x100, 21600, 10800, 10800, 3 + 40, 3 + 29, 0, 10800 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x101, 21600, 10800, 10800, 3 + 27, 3 + 21, 0, 10800 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 21600, 0x102, 10800, 10800, 3375, 21600, 3 + 44, 3 + 22 }
+};
+
+const mso_CustomShape msoCurvedDownArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedDownVert), SAL_N_ELEMENTS( mso_sptCurvedDownVert ),
+ const_cast<sal_uInt16*>(mso_sptCurvedDownSegm), sizeof( mso_sptCurvedDownSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCurvedRightCalc), SAL_N_ELEMENTS( mso_sptCurvedRightCalc ),
+ const_cast<sal_Int32*>(mso_sptCurvedRightDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptCurvedDownTextRect), SAL_N_ELEMENTS( mso_sptCurvedDownTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedDownGluePoints), SAL_N_ELEMENTS( mso_sptCurvedDownGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptCurvedDownHandles), SAL_N_ELEMENTS( mso_sptCurvedDownHandles )
+};
+
+const SvxMSDffVertPair mso_sptCurvedUpVert[] =
+{
+ { 0, 22 MSO_I }, { 3 MSO_I, 21 MSO_I }, { 0, 0 }, { 4 MSO_I, 21 MSO_I },
+ { 14 MSO_I, 22 MSO_I }, { 1 MSO_I, 21 MSO_I }, { 7 MSO_I, 21 MSO_I },
+ { 12 MSO_I, 2 MSO_I }, { 13 MSO_I, 2 MSO_I }, { 8 MSO_I, 0 }, { 11 MSO_I, 2 MSO_I },
+ { 0, 22 MSO_I }, { 3 MSO_I, 21 MSO_I }, { 10 MSO_I, 2 MSO_I }, { 16 MSO_I, 24 MSO_I },
+ { 14 MSO_I, 22 MSO_I }, { 1 MSO_I, 21 MSO_I }, { 16 MSO_I, 24 MSO_I }, { 14 MSO_I, 0 },
+ { 0, 22 MSO_I }, { 3 MSO_I, 21 MSO_I }, { 0, 0 }, { 4 MSO_I, 21 MSO_I },
+ { 14 MSO_I, 22 MSO_I }, { 1 MSO_I, 21 MSO_I }, { 7 MSO_I, 21 MSO_I }, { 16 MSO_I, 24 MSO_I },
+ { 14 MSO_I, 22 MSO_I }, { 1 MSO_I, 21 MSO_I }, { 16 MSO_I, 24 MSO_I }, { 14 MSO_I, 0 }
+};
+const sal_uInt16 mso_sptCurvedUpSegm[] =
+{
+ 0xa404,
+ 0xa304,
+ 0x0003,
+ 0xa508,
+ 0x6000,
+ 0x8000,
+ 0xa404,
+ 0xa508,
+ 0xa504,
+ 0x6000,
+ 0x8000
+};
+const SvxMSDffCalculationData mso_sptCurvedUpCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0xa000, { DFF_Prop_adjustValue, 21600, DFF_Prop_adjust2Value } },
+ { 0x2001, { 0x403, 1, 2 } },
+ { 0x6000, { DFF_Prop_adjust2Value, DFF_Prop_adjust2Value, 21600 } },
+ { 0xe000, { 0x405, DFF_Prop_adjust2Value, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x406, 1, 2 } },
+ { 0x4002, { 21600, DFF_Prop_adjustValue, 0 } },
+ { 0xa00f, { DFF_Prop_adjust3Value, 21600, 0x404 } },
+ { 0x6000, { 0x404, 0x409, 0 } },
+ { 0x6000, { 0x40a, DFF_Prop_adjust2Value, 21600 } },
+ { 0x6000, { 0x407, 0x409, 0 } },
+ { 0xa000, { 0x40b, 21600, DFF_Prop_adjustValue } },
+ { 0xa000, { 0x405, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x40e, 1, 2 } },
+ { 0x6002, { 0x404, 0x407, 0 } },
+ { 0x6000, { DFF_Prop_adjustValue, DFF_Prop_adjust2Value, 21600 } },
+ { 0x2001, { 0x411, 1, 2 } },
+ { 0xa000, { 0x410, 0, 0x412 } },
+ { 0x0000, { 21600, 0, 0 } },
+ { 0x0000, { 21600, 0, 0 } },
+ { 0x0000, { 0, 0, 21600 } },
+ { 0xa000, { 0x410, 0, 0x404 } },
+ { 0x600f, { 0x417, 0x404, 21600 } },
+ { 0x2000, { 0x408, 128, 0 } },
+ { 0x2001, { 0x405, 1, 2 } },
+ { 0x2000, { 0x405, 0, 128 } },
+ { 0xe000, { DFF_Prop_adjustValue, 0x410, 0x40b } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x41d, 1, 2 } },
+ { 0x0001, { 21600, 21600, 1 } },
+ { 0x6001, { DFF_Prop_adjust3Value, DFF_Prop_adjust3Value, 1 } },
+ { 0xa000, { 0x41f, 0, 0x420 } },
+ { 0x200d, { 0x421, 0, 0 } },
+ { 0x2000, { 0x422, 21600, 0 } },
+ { 0x8001, { 21600, 21600, 0x423 } },
+ { 0x2000, { 0x424, 64, 0 } },
+ { 0x2001, { DFF_Prop_adjustValue, 1, 2 } },
+ { 0x600f, { 0x41e, 0x426, 21600 } },
+ { 0x2000, { 0x427, 0, 64 } },
+ { 0x2001, { 0x404, 1, 2 } },
+ { 0xa000, { DFF_Prop_adjust2Value, 0, 0x429 } },
+ { 0x0001, { 21600, 2195, 16384 } },
+ { 0x0001, { 21600, 14189, 16384 } }
+};
+const sal_Int32 mso_sptCurvedUpDefault[] =
+{
+ 3, 12960, 19440, 7200
+};
+const SvxMSDffTextRectangles mso_sptCurvedUpTextRect[] =
+{
+ { { 41 MSO_I, 43 MSO_I }, { 42 MSO_I, 44 MSO_I } }
+};
+const SvxMSDffVertPair mso_sptCurvedUpGluePoints[] =
+{
+ { 8 MSO_I, 0 }, { 11 MSO_I, 2 MSO_I }, { 15 MSO_I, 0 }, { 16 MSO_I, 21 MSO_I }, { 13 MSO_I, 2 MSO_I }
+};
+const SvxMSDffHandle mso_sptCurvedUpHandles[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x100, 0, 10800, 10800, 3 + 37, 3 + 27, 0, 10800 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x101, 0, 10800, 10800, 3 + 25, 3 + 20, 0, 10800 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 21600, 0x102, 10800, 10800, 3375, 21600, 0, 3 + 40 }
+};
+const mso_CustomShape msoCurvedUpArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedUpVert), SAL_N_ELEMENTS( mso_sptCurvedUpVert ),
+ const_cast<sal_uInt16*>(mso_sptCurvedUpSegm), sizeof( mso_sptCurvedUpSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCurvedUpCalc), SAL_N_ELEMENTS( mso_sptCurvedUpCalc ),
+ const_cast<sal_Int32*>(mso_sptCurvedUpDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptCurvedUpTextRect), SAL_N_ELEMENTS( mso_sptCurvedUpTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedUpGluePoints), SAL_N_ELEMENTS( mso_sptCurvedUpGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptCurvedUpHandles), SAL_N_ELEMENTS( mso_sptCurvedUpHandles )
+};
+
+const SvxMSDffVertPair mso_sptCurvedLeftVert[] =
+{
+ { 22 MSO_I, 0 }, { 21 MSO_I, 3 MSO_I }, { 0, 0 }, { 21 MSO_I, 4 MSO_I },
+ { 22 MSO_I, 14 MSO_I }, { 21 MSO_I, 1 MSO_I }, { 21 MSO_I, 7 MSO_I }, { 2 MSO_I, 12 MSO_I },
+ { 2 MSO_I, 13 MSO_I }, { 0, 8 MSO_I }, { 2 MSO_I, 11 MSO_I },
+ { 22 MSO_I, 0 }, { 21 MSO_I, 3 MSO_I }, { 2 MSO_I, 10 MSO_I }, { 24 MSO_I, 16 MSO_I },
+ { 22 MSO_I, 14 MSO_I }, { 21 MSO_I, 1 MSO_I }, { 24 MSO_I, 16 MSO_I }, { 0, 14 MSO_I },
+ { 22 MSO_I, 0 }, { 21 MSO_I, 3 MSO_I }, { 0, 0 }, { 21 MSO_I, 4 MSO_I },
+ { 22 MSO_I, 14 MSO_I }, { 21 MSO_I, 1 MSO_I }, { 21 MSO_I, 7 MSO_I }, { 24 MSO_I, 16 MSO_I },
+ { 22 MSO_I, 14 MSO_I }, { 21 MSO_I, 1 MSO_I }, { 24 MSO_I, 16 MSO_I }, { 0, 14 MSO_I }
+};
+const sal_uInt16 mso_sptCurvedLeftSegm[] =
+{
+ 0xa604,
+ 0xa504,
+ 0x0003,
+ 0xa308,
+ 0x6000,
+ 0x8000,
+ 0xa604,
+ 0xa308,
+ 0x6000,
+ 0x8000
+};
+const SvxMSDffTextRectangles mso_sptCurvedLeftTextRect[] =
+{
+ { { 43 MSO_I, 41 MSO_I }, { 44 MSO_I, 42 MSO_I } }
+};
+const SvxMSDffVertPair mso_sptCurvedLeftGluePoints[] =
+{
+ { 0, 15 MSO_I }, { 2 MSO_I, 11 MSO_I }, { 0, 8 MSO_I }, { 2 MSO_I, 13 MSO_I }, { 21 MSO_I, 16 MSO_I }
+};
+const SvxMSDffHandle mso_sptCurvedLeftHandles[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0, 0x100, 10800, 10800, 0, 10800, 3 + 37, 3 + 27 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0, 0x101, 10800, 10800, 0, 10800, 3 + 25, 3 + 20 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x102, 21600, 10800, 10800, 0, 3 + 40, 3375, 21600 }
+};
+const mso_CustomShape msoCurvedLeftArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedLeftVert), SAL_N_ELEMENTS( mso_sptCurvedLeftVert ),
+ const_cast<sal_uInt16*>(mso_sptCurvedLeftSegm), sizeof( mso_sptCurvedLeftSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCurvedUpCalc), SAL_N_ELEMENTS( mso_sptCurvedUpCalc ),
+ const_cast<sal_Int32*>(mso_sptCurvedUpDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptCurvedLeftTextRect), SAL_N_ELEMENTS( mso_sptCurvedLeftTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedLeftGluePoints), SAL_N_ELEMENTS( mso_sptCurvedLeftGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptCurvedLeftHandles), SAL_N_ELEMENTS( mso_sptCurvedLeftHandles )
+};
+
+const SvxMSDffVertPair mso_sptStripedRightArrowVert[] = // adjustment1 : x 3375 - 21600
+{ // adjustment2 : y 0 - 10800
+ { 3375, 0 MSO_I }, { 1 MSO_I, 0 MSO_I }, { 1 MSO_I, 0 }, { 21600, 10800 },
+ { 1 MSO_I, 21600 }, { 1 MSO_I, 2 MSO_I }, { 3375, 2 MSO_I }, { 0, 0 MSO_I },
+ { 675, 0 MSO_I }, { 675, 2 MSO_I }, { 0, 2 MSO_I }, { 1350, 0 MSO_I },
+ { 2700, 0 MSO_I }, { 2700, 2 MSO_I }, { 1350, 2 MSO_I }
+};
+const sal_uInt16 mso_sptStripedRightArrowSegm[] =
+{
+ 0x4000, 0x0006, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptStripedRightArrowCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjust2Value } },
+ { 0x8000, { 21600, 0, 0x401 } },
+ { 0x6001, { 0x403, 0x400, 10800 } },
+ { 0x6000, { 0x401, 0x404, 0 } }
+};
+const SvxMSDffTextRectangles mso_sptStripedRightArrowTextRect[] =
+{
+ { { 3375, 0 MSO_I }, { 5 MSO_I, 2 MSO_I } }
+};
+const SvxMSDffHandle mso_sptStripedRightArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0x101, 10800, 10800, 3375, 21600, 0, 10800 }
+};
+const mso_CustomShape msoStripedRightArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptStripedRightArrowVert), SAL_N_ELEMENTS( mso_sptStripedRightArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptStripedRightArrowSegm), sizeof( mso_sptStripedRightArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptStripedRightArrowCalc), SAL_N_ELEMENTS( mso_sptStripedRightArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault16200and5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptStripedRightArrowTextRect), SAL_N_ELEMENTS( mso_sptStripedRightArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptStripedRightArrowHandle), SAL_N_ELEMENTS( mso_sptStripedRightArrowHandle )
+};
+
+const SvxMSDffVertPair mso_sptNotchedRightArrowVert[] = // adjustment1 : x 0 - 21600 (default 16200)
+{ // adjustment2 : y 0 - 10800 (default 5400)
+ { 0, 1 MSO_I }, { 0 MSO_I, 1 MSO_I }, { 0 MSO_I, 0 }, { 21600, 10800 },
+ { 0 MSO_I, 21600 }, { 0 MSO_I, 2 MSO_I }, { 0, 2 MSO_I }, { 5 MSO_I, 10800 }, { 0, 1 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptNotchedRightArrowCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjust2Value } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjust2Value } },
+ { 0x6001, { 0x403, 0x404, 10800 } },
+ { 0x8000, { 21600, 0, 0x405 }}
+};
+const SvxMSDffTextRectangles mso_sptNotchedRightArrowTextRect[] = // todo
+{
+ { { 5 MSO_I, 1 MSO_I }, { 6 MSO_I, 2 MSO_I } }
+};
+const SvxMSDffHandle mso_sptNotchedRightArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0x101, 10800, 10800, 0, 21600, 0, 10800 }
+};
+const mso_CustomShape msoNotchedRightArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptNotchedRightArrowVert), SAL_N_ELEMENTS( mso_sptNotchedRightArrowVert ),
+ nullptr, 0,
+ const_cast<SvxMSDffCalculationData*>(mso_sptNotchedRightArrowCalc), SAL_N_ELEMENTS( mso_sptNotchedRightArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault16200and5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptNotchedRightArrowTextRect), SAL_N_ELEMENTS( mso_sptNotchedRightArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptNotchedRightArrowHandle), SAL_N_ELEMENTS( mso_sptNotchedRightArrowHandle )
+};
+
+const SvxMSDffVertPair mso_sptHomePlateVert[] = // adjustment1 : x 0 - 21600
+{
+ { 0, 0 }, { 0 MSO_I, 0 }, { 21600, 10800 }, { 0 MSO_I, 21600 },
+ { 0, 21600 }
+};
+const sal_uInt16 mso_sptHomePlateSegm[] =
+{
+ 0x4000, 0x0004, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptHomePlateCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }
+};
+const sal_Int32 mso_sptHomePlateDefault[] =
+{
+ 1, 16200
+};
+const SvxMSDffTextRectangles mso_sptHomePlateTextRect[] = // todo
+{
+ { { 0, 0 }, { 21600, 21600 } }
+};
+const SvxMSDffHandle mso_sptHomePlateHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0, 10800, 10800, 0, 21600, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoHomePlate =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptHomePlateVert), SAL_N_ELEMENTS( mso_sptHomePlateVert ),
+ const_cast<sal_uInt16*>(mso_sptHomePlateSegm), sizeof( mso_sptHomePlateSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptHomePlateCalc), SAL_N_ELEMENTS( mso_sptHomePlateCalc ),
+ const_cast<sal_Int32*>(mso_sptHomePlateDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptHomePlateTextRect), SAL_N_ELEMENTS( mso_sptHomePlateTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptHomePlateHandle), SAL_N_ELEMENTS( mso_sptHomePlateHandle )
+};
+
+const SvxMSDffVertPair mso_sptChevronVert[] = // adjustment1 : x 0 - 21600
+{
+ { 0, 0 }, { 0 MSO_I, 0 }, { 21600, 10800 }, { 0 MSO_I, 21600 },
+ { 0, 21600 }, { 1 MSO_I, 10800 }
+};
+const sal_uInt16 mso_sptChevronSegm[] =
+{
+ 0x4000, 0x0005, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptChevronCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, 0x0400 } }
+};
+const sal_Int32 mso_sptChevronDefault[] =
+{
+ 1, 16200
+};
+const SvxMSDffTextRectangles mso_sptChevronTextRect[] = // todo
+{
+ { { 0, 0 }, { 21600, 21600 } }
+};
+const SvxMSDffHandle mso_sptChevronHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0, 10800, 10800, 0, 21600, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoChevron =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptChevronVert), SAL_N_ELEMENTS( mso_sptChevronVert ),
+ const_cast<sal_uInt16*>(mso_sptChevronSegm), sizeof( mso_sptChevronSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptChevronCalc), SAL_N_ELEMENTS( mso_sptChevronCalc ),
+ const_cast<sal_Int32*>(mso_sptChevronDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptChevronTextRect), SAL_N_ELEMENTS( mso_sptChevronTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptChevronHandle), SAL_N_ELEMENTS( mso_sptChevronHandle )
+};
+
+const SvxMSDffVertPair mso_sptRightArrowCalloutVert[] = // adjustment1 : x 0 - 21000
+{ // adjustment2 : y 0 - 10800
+ { 0, 0 }, { 0 MSO_I, 0 }, { 0 MSO_I, 3 MSO_I }, { 2 MSO_I, 3 MSO_I },
+ { 2 MSO_I, 1 MSO_I }, { 21600, 10800 }, { 2 MSO_I, 4 MSO_I }, { 2 MSO_I, 5 MSO_I },
+ { 0 MSO_I, 5 MSO_I }, { 0 MSO_I, 21600 }, { 0, 21600 }
+};
+const sal_uInt16 mso_sptRightArrowCalloutSegm[] =
+{
+ 0x4000, 0x000a, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptRightArrowCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust4Value, 0, 0 } },
+ { 0x8000, { 21600, 0, 0x0401 } },
+ { 0x8000, { 21600, 0, 0x0403 } }
+};
+const sal_Int32 mso_sptRightArrowCalloutDefault[] =
+{
+ 4, 14400, 5400, 18000, 8100
+};
+const SvxMSDffTextRectangles mso_sptRightArrowCalloutTextRect[] =
+{
+ { { 0, 0 }, { 0 MSO_I, 21600 } }
+};
+const SvxMSDffHandle mso_sptRightArrowCalloutHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x100, 0, 10800, 10800, 0, 0x102, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 0x102, 0x103, 10800, 10800, 0x100, 21600, 0x101, 10800 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 1, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 0x103 }
+};
+const mso_CustomShape msoRightArrowCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptRightArrowCalloutVert), SAL_N_ELEMENTS( mso_sptRightArrowCalloutVert ),
+ const_cast<sal_uInt16*>(mso_sptRightArrowCalloutSegm), sizeof( mso_sptRightArrowCalloutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptRightArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptRightArrowCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptRightArrowCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptRightArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptRightArrowCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptRightArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptRightArrowCalloutHandle )
+};
+
+const SvxMSDffVertPair mso_sptLeftArrowCalloutVert[] = // adjustment1 : x 0 - 21600, adjustment2 : y 0 - 10800
+{ // adjustment3 : x 0 - 21600, adjustment4 : y 0 - 10800
+ { 0 MSO_I, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0 MSO_I, 21600 },
+ { 0 MSO_I, 5 MSO_I }, { 2 MSO_I, 5 MSO_I }, { 2 MSO_I, 4 MSO_I }, { 0, 10800 },
+ { 2 MSO_I, 1 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 0 MSO_I, 3 MSO_I }
+};
+const sal_uInt16 mso_sptLeftArrowCalloutSegm[] =
+{
+ 0x4000, 0x000a, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptLeftArrowCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust4Value, 0, 0 } },
+ { 0x8000, { 21600, 0, 0x0401 } },
+ { 0x8000, { 21600, 0, 0x0403 } }
+};
+const sal_Int32 mso_sptLeftArrowCalloutDefault[] =
+{
+ 4, 7200, 5400, 3600, 8100
+};
+const SvxMSDffTextRectangles mso_sptLeftArrowCalloutTextRect[] =
+{
+ { { 0 MSO_I, 0 }, { 21600, 21600 } }
+};
+const SvxMSDffHandle mso_sptLeftArrowCalloutHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL,
+ 0x100, 0, 10800, 10800, 0x102, 21600, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 0x102, 0x103, 10800, 10800, 0, 0x100, 0x101, 10800 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 0x103 }
+};
+const mso_CustomShape msoLeftArrowCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptLeftArrowCalloutVert), SAL_N_ELEMENTS( mso_sptLeftArrowCalloutVert ),
+ const_cast<sal_uInt16*>(mso_sptLeftArrowCalloutSegm), sizeof( mso_sptLeftArrowCalloutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptLeftArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptLeftArrowCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptLeftArrowCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptLeftArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptLeftArrowCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptLeftArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptLeftArrowCalloutHandle )
+};
+
+const SvxMSDffVertPair mso_sptUpArrowCalloutVert[] =
+{
+ { 21600, 0 MSO_I }, { 21600, 21600 }, { 0, 21600 }, { 0, 0 MSO_I },
+ { 3 MSO_I, 0 MSO_I }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I }, { 10800, 0 },
+ { 4 MSO_I, 2 MSO_I }, { 5 MSO_I, 2 MSO_I }, { 5 MSO_I, 0 MSO_I }
+};
+const sal_uInt16 mso_sptUpArrowCalloutSegm[] =
+{
+ 0x4000, 0x000a, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptUpArrowCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust4Value, 0, 0 } },
+ { 0x8000, { 21600, 0, 0x0401 } },
+ { 0x8000, { 21600, 0, 0x0403 } }
+};
+const sal_Int32 mso_sptUpArrowCalloutDefault[] =
+{
+ 4, 7200, 5400, 3600, 8100
+};
+const SvxMSDffTextRectangles mso_sptUpArrowCalloutTextRect[] =
+{
+ { { 0, 0 MSO_I }, { 21600, 21600 } }
+};
+const SvxMSDffHandle mso_sptUpArrowCalloutHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0x102, 21600 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0x103, 0x102, 10800, 10800, 0x101, 10800, 0, 0x100 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x101, 0, 10800, 10800, 0, 0x103, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoUpArrowCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptUpArrowCalloutVert), SAL_N_ELEMENTS( mso_sptUpArrowCalloutVert ),
+ const_cast<sal_uInt16*>(mso_sptUpArrowCalloutSegm), sizeof( mso_sptUpArrowCalloutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptUpArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptUpArrowCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptUpArrowCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptUpArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptUpArrowCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptUpArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptUpArrowCalloutHandle )
+};
+
+const SvxMSDffVertPair mso_sptDownArrowCalloutVert[] =
+{
+ { 0, 0 MSO_I }, { 0, 0 }, { 21600, 0 }, { 21600, 0 MSO_I },
+ { 5 MSO_I, 0 MSO_I }, { 5 MSO_I, 2 MSO_I }, { 4 MSO_I, 2 MSO_I }, { 10800, 21600 },
+ { 1 MSO_I, 2 MSO_I }, { 3 MSO_I, 2 MSO_I }, { 3 MSO_I, 0 MSO_I }
+};
+const sal_uInt16 mso_sptDownArrowCalloutSegm[] =
+{
+ 0x4000, 0x000a, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptDownArrowCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust4Value, 0, 0 } },
+ { 0x8000, { 21600, 0, 0x0401 } },
+ { 0x8000, { 21600, 0, 0x0403 } }
+};
+const sal_Int32 mso_sptDownArrowCalloutDefault[] =
+{
+ 4, 14400, 5400, 18000, 8100
+};
+const SvxMSDffTextRectangles mso_sptDownArrowCalloutTextRect[] =
+{
+ { { 0, 0 }, { 21600, 0 MSO_I } }
+};
+const SvxMSDffHandle mso_sptDownArrowCalloutHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 0x102 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 0x103, 0x102, 10800, 10800, 0x101, 10800, 0x100, 21600 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x101, 1, 10800, 10800, 0, 0x103, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoDownArrowCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptDownArrowCalloutVert), SAL_N_ELEMENTS( mso_sptDownArrowCalloutVert ),
+ const_cast<sal_uInt16*>(mso_sptDownArrowCalloutSegm), sizeof( mso_sptDownArrowCalloutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptDownArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptDownArrowCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptDownArrowCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptDownArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptDownArrowCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptDownArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptDownArrowCalloutHandle )
+};
+
+const SvxMSDffVertPair mso_sptLeftRightArrowCalloutVert[] =
+{
+ { 0 MSO_I, 0 }, { 4 MSO_I, 0 }, { 4 MSO_I, 3 MSO_I }, { 6 MSO_I, 3 MSO_I },
+ { 6 MSO_I, 1 MSO_I }, { 21600, 10800 }, { 6 MSO_I, 5 MSO_I }, { 6 MSO_I, 7 MSO_I },
+ { 4 MSO_I, 7 MSO_I }, { 4 MSO_I, 21600 }, { 0 MSO_I, 21600 }, { 0 MSO_I, 7 MSO_I },
+ { 2 MSO_I, 7 MSO_I }, { 2 MSO_I, 5 MSO_I }, { 0, 10800 }, { 2 MSO_I, 1 MSO_I },
+ { 2 MSO_I, 3 MSO_I }, { 0 MSO_I, 3 MSO_I }
+};
+const sal_uInt16 mso_sptLeftRightArrowCalloutSegm[] =
+{
+ 0x4000, 0x0011, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptLeftRightArrowCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust4Value, 0, 0 } },
+ { 0x8000, { 21600, 0, 0x0400 } },
+ { 0x8000, { 21600, 0, 0x0401 } },
+ { 0x8000, { 21600, 0, 0x0402 } },
+ { 0x8000, { 21600, 0, 0x0403 } }
+};
+const sal_Int32 mso_sptLeftRightArrowCalloutDefault[] =
+{
+ 4, 5400, 5500, 2700, 8100
+};
+const SvxMSDffTextRectangles mso_sptLeftRightArrowCalloutTextRect[] =
+{
+ { { 0 MSO_I, 0 }, { 4 MSO_I, 21600 } }
+};
+const SvxMSDffHandle mso_sptLeftRightArrowCalloutHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL,
+ 0x100, 0, 10800, 10800, 0x102, 10800, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 0x102, 0x103, 10800, 10800, 0, 0x100, 0x101, 10800 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 0x103 }
+};
+const mso_CustomShape msoLeftRightArrowCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptLeftRightArrowCalloutVert), SAL_N_ELEMENTS( mso_sptLeftRightArrowCalloutVert ),
+ const_cast<sal_uInt16*>(mso_sptLeftRightArrowCalloutSegm), sizeof( mso_sptLeftRightArrowCalloutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptLeftRightArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptLeftRightArrowCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptLeftRightArrowCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptLeftRightArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptLeftRightArrowCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptLeftRightArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptLeftRightArrowCalloutHandle )
+};
+
+const SvxMSDffVertPair mso_sptUpDownArrowCalloutVert[] =
+{
+ { 0, 0 MSO_I }, { 0, 4 MSO_I }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 6 MSO_I },
+ { 1 MSO_I, 6 MSO_I }, { 10800, 21600 }, { 5 MSO_I, 6 MSO_I }, { 7 MSO_I, 6 MSO_I },
+ { 7 MSO_I, 4 MSO_I }, { 21600, 4 MSO_I }, { 21600, 0 MSO_I }, { 7 MSO_I, 0 MSO_I },
+ { 7 MSO_I, 2 MSO_I }, { 5 MSO_I, 2 MSO_I }, { 10800, 0 }, { 1 MSO_I, 2 MSO_I },
+ { 3 MSO_I, 2 MSO_I }, { 3 MSO_I, 0 MSO_I }
+};
+const sal_uInt16 mso_sptUpDownArrowCalloutSegm[] =
+{
+ 0x4000, 0x0011, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptUpDownArrowCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust4Value, 0, 0 } },
+ { 0x8000, { 21600, 0, 0x0400 } },
+ { 0x8000, { 21600, 0, 0x0401 } },
+ { 0x8000, { 21600, 0, 0x0402 } },
+ { 0x8000, { 21600, 0, 0x0403 } }
+};
+const sal_Int32 mso_sptUpDownArrowCalloutDefault[] =
+{
+ 4, 5400, 5500, 2700, 8100
+};
+const SvxMSDffTextRectangles mso_sptUpDownArrowCalloutTextRect[] =
+{
+ { { 0, 0 MSO_I }, { 21600, 4 MSO_I } }
+};
+const SvxMSDffHandle mso_sptUpDownArrowCalloutHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0x102, 10800 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0x103, 0x102, 10800, 10800, 0x101, 10800, 0, 0x100 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 0x101, 0, 10800, 10800, 0, 0x103, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoUpDownArrowCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptUpDownArrowCalloutVert), SAL_N_ELEMENTS( mso_sptUpDownArrowCalloutVert ),
+ const_cast<sal_uInt16*>(mso_sptUpDownArrowCalloutSegm), sizeof( mso_sptUpDownArrowCalloutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptUpDownArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptUpDownArrowCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptUpDownArrowCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptUpDownArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptUpDownArrowCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptUpDownArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptUpDownArrowCalloutHandle )
+};
+
+const SvxMSDffVertPair mso_sptQuadArrowCalloutVert[] =
+{
+ { 0 MSO_I, 0 MSO_I }, { 3 MSO_I, 0 MSO_I }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 10800, 0 }, { 5 MSO_I, 2 MSO_I }, { 7 MSO_I, 2 MSO_I }, { 7 MSO_I, 0 MSO_I },
+ { 4 MSO_I, 0 MSO_I }, { 4 MSO_I, 3 MSO_I }, { 6 MSO_I, 3 MSO_I }, { 6 MSO_I, 1 MSO_I },
+ { 21600, 10800 }, { 6 MSO_I, 5 MSO_I }, { 6 MSO_I, 7 MSO_I }, { 4 MSO_I, 7 MSO_I },
+ { 4 MSO_I, 4 MSO_I }, { 7 MSO_I, 4 MSO_I }, { 7 MSO_I, 6 MSO_I }, { 5 MSO_I, 6 MSO_I },
+ { 10800, 21600 }, { 1 MSO_I, 6 MSO_I }, { 3 MSO_I, 6 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0 MSO_I, 4 MSO_I }, { 0 MSO_I, 7 MSO_I }, { 2 MSO_I, 7 MSO_I }, { 2 MSO_I, 5 MSO_I },
+ { 0, 10800 }, { 2 MSO_I, 1 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 0 MSO_I, 3 MSO_I }
+};
+const sal_uInt16 mso_sptQuadArrowCalloutSegm[] =
+{
+ 0x4000, 0x001f, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptQuadArrowCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust4Value, 0, 0 } },
+ { 0x8000, { 21600, 0, 0x0400 } },
+ { 0x8000, { 21600, 0, 0x0401 } },
+ { 0x8000, { 21600, 0, 0x0402 } },
+ { 0x8000, { 21600, 0, 0x0403 } }
+};
+const sal_Int32 mso_sptQuadArrowCalloutDefault[] =
+{
+ 4, 5400, 8100, 2700, 9400
+};
+const SvxMSDffTextRectangles mso_sptQuadArrowCalloutTextRect[] =
+{
+ { { 0 MSO_I, 0 MSO_I }, { 4 MSO_I, 4 MSO_I } }
+};
+const SvxMSDffHandle mso_sptQuadArrowCalloutHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0x102, 0x101 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL,
+ 0x101, 0, 10800, 10800, 0x100, 10800, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0x103, 0x102, 10800, 10800, 0x101, 10800, 0, 0x100 }
+};
+const mso_CustomShape msoQuadArrowCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptQuadArrowCalloutVert), SAL_N_ELEMENTS( mso_sptQuadArrowCalloutVert ),
+ const_cast<sal_uInt16*>(mso_sptQuadArrowCalloutSegm), sizeof( mso_sptQuadArrowCalloutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptQuadArrowCalloutCalc), SAL_N_ELEMENTS( mso_sptQuadArrowCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptQuadArrowCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptQuadArrowCalloutTextRect), SAL_N_ELEMENTS( mso_sptQuadArrowCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptQuadArrowCalloutHandle), SAL_N_ELEMENTS( mso_sptQuadArrowCalloutHandle )
+};
+
+const SvxMSDffVertPair mso_sptCircularArrowVert[] =
+{
+ { 0x03 MSO_I, 0x03 MSO_I },
+ { 0x14 MSO_I, 0x14 MSO_I },
+ { 0x13 MSO_I, 0x12 MSO_I },
+ { 0x11 MSO_I, 0x10 MSO_I },
+ { 0, 0 }, { 21600, 21600 },
+ { 0x09 MSO_I, 0x08 MSO_I },
+ { 0x0B MSO_I, 0x0A MSO_I },
+ { 0x18 MSO_I, 0x17 MSO_I },
+ { 0x2F MSO_I, 0x2E MSO_I },
+ { 0x1D MSO_I, 0x1C MSO_I }
+};
+const sal_uInt16 mso_sptCircularArrowSegm[] =
+{
+ 0xa404, 0xa504, 0x0003, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptCircularArrowCalc[] =
+{
+ { 0x2000, { 0x0147, 0x0000, 0x0000 } },
+ { 0x2000, { 0x0148, 0x0000, 0x0000 } },
+ { 0x2000, { 0x0149, 0x0000, 0x0000 } },
+ { 0x4000, { 0x2A30, 0x0149, 0x0000 } },
+ { 0x4009, { 0x2A30, 0x0147, 0x0000 } },
+ { 0x400A, { 0x2A30, 0x0147, 0x0000 } },
+ { 0x4009, { 0x2A30, 0x0148, 0x0000 } },
+ { 0x400A, { 0x2A30, 0x0148, 0x0000 } },
+ { 0x2000, { 0x0404, 0x2A30, 0x0000 } },
+ { 0x2000, { 0x0405, 0x2A30, 0x0000 } },
+ { 0x2000, { 0x0406, 0x2A30, 0x0000 } },
+ { 0x2000, { 0x0407, 0x2A30, 0x0000 } },
+ { 0x6009, { 0x0403, 0x0147, 0x0000 } },
+ { 0x600A, { 0x0403, 0x0147, 0x0000 } },
+ { 0x6009, { 0x0403, 0x0148, 0x0000 } },
+ { 0x600A, { 0x0403, 0x0148, 0x0000 } },
+ { 0x2000, { 0x040C, 0x2A30, 0x0000 } },
+ { 0x2000, { 0x040D, 0x2A30, 0x0000 } },
+ { 0x2000, { 0x040E, 0x2A30, 0x0000 } },
+ { 0x2000, { 0x040F, 0x2A30, 0x0000 } },
+ { 0x8000, { 0x5460, 0x0000, 0x0403 } },
+ { 0x4009, { 0x34BC, 0x0148, 0x0000 } },
+ { 0x400A, { 0x34BC, 0x0148, 0x0000 } },
+ { 0x2000, { 0x0415, 0x2A30, 0x0000 } },
+ { 0x2000, { 0x0416, 0x2A30, 0x0000 } },
+ { 0x2000, { 0x0149, 0x0000, 0x0A8C } },
+ { 0x6009, { 0x0419, 0x0148, 0x0000 } },
+ { 0x600A, { 0x0419, 0x0148, 0x0000 } },
+ { 0x2000, { 0x041A, 0x2A30, 0x0000 } },
+ { 0x2000, { 0x041B, 0x2A30, 0x0000 } },
+ { 0xA000, { 0x041D, 0x0000, 0x0418 } },
+ { 0xA000, { 0x041D, 0x0000, 0x0418 } },
+ { 0x6001, { 0x041E, 0x041F, 0x0001 } },
+ { 0xA000, { 0x041C, 0x0000, 0x0417 } },
+ { 0xA000, { 0x041C, 0x0000, 0x0417 } },
+ { 0x6001, { 0x0421, 0x0422, 0x0001 } },
+ { 0x6000, { 0x0420, 0x0423, 0x0000 } },
+ { 0x200D, { 0x0424, 0x0000, 0x0000 } },
+ { 0x200E, { 0x0148, 0x002D, 0x0000 } },
+ { 0x6009, { 0x0425, 0x0426, 0x0000 } },
+ { 0x200E, { 0x0148, 0x002D, 0x0000 } },
+ { 0x600A, { 0x0425, 0x0428, 0x0000 } },
+ { 0x000E, { 0x0000, 0x002D, 0x0000 } },
+ { 0x6009, { 0x0427, 0x042A, 0x0000 } },
+ { 0x000E, { 0x0000, 0x002D, 0x0000 } },
+ { 0x6009, { 0x0429, 0x042C, 0x0000 } },
+ { 0x6000, { 0x041C, 0x042B, 0x0000 } },
+ { 0x6000, { 0x041D, 0x042D, 0x0000 } }
+};
+const sal_Int32 mso_sptCircularArrowDefault[] =
+{
+ 3, 180, 0, 5500
+};
+const SvxMSDffTextRectangles mso_sptCircularArrowTextRect[] = // todo
+{
+ { { 0, 0 }, { 21600, 21600 } }
+};
+const SvxMSDffHandle mso_sptCircularArrowHandle[] =
+{
+ { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE,
+ 10800, 0x100, 10800, 10800, 10800, 10800, -0x7f4c0000, 0x00b40000 },
+ { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE,
+ 0x102, 0x101, 10800, 10800, 0, 10800, -0x7f4c0000, 0x00b40000 }
+};
+const mso_CustomShape msoCircularArrow =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCircularArrowVert), SAL_N_ELEMENTS( mso_sptCircularArrowVert ),
+ const_cast<sal_uInt16*>(mso_sptCircularArrowSegm), sizeof( mso_sptCircularArrowSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCircularArrowCalc), SAL_N_ELEMENTS( mso_sptCircularArrowCalc ),
+ const_cast<sal_Int32*>(mso_sptCircularArrowDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptCircularArrowTextRect), SAL_N_ELEMENTS( mso_sptCircularArrowTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCircularArrowHandle), SAL_N_ELEMENTS( mso_sptCircularArrowHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptCubeVert[] =
+{
+ { 0, 12 MSO_I }, { 0, 1 MSO_I }, { 2 MSO_I, 0 }, { 11 MSO_I, 0 }, { 11 MSO_I, 3 MSO_I }, { 4 MSO_I, 12 MSO_I },
+ { 0, 1 MSO_I }, { 2 MSO_I, 0 }, { 11 MSO_I, 0 }, { 4 MSO_I, 1 MSO_I },
+ { 4 MSO_I, 12 MSO_I }, { 4 MSO_I, 1 MSO_I }, { 11 MSO_I, 0 }, { 11 MSO_I, 3 MSO_I }
+};
+const sal_uInt16 mso_sptCubeSegm[] =
+{
+ 0x4000, 0x0005, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptCubeCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, 0x400, 0 } },
+ { 0x6000, { DFF_Prop_geoLeft, 0x400, 0 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x400 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x400 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x402 } }, // 5
+ { 0x2001, { 0x405, 1, 2 } }, // 6
+ { 0x6000, { 0x402, 0x406, 0 } }, // 7
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x401 } }, // 8
+ { 0x2001, { 0x408, 1, 2 } }, // 9
+ { 0x6000, { 0x401, 0x409, 0 } }, // 10
+ { 0x2000, { DFF_Prop_geoRight, 0, 0 } }, // 11
+ { 0x2000, { DFF_Prop_geoBottom, 0, 0 } } // 12
+};
+const SvxMSDffTextRectangles mso_sptCubeTextRect[] =
+{
+ { { 0, 1 MSO_I }, { 4 MSO_I, 12 MSO_I } }
+};
+const SvxMSDffHandle mso_sptCubeHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 21600 }
+};
+const SvxMSDffVertPair mso_sptCubeGluePoints[] =
+{
+ { 7 MSO_I, 0 }, { 6 MSO_I, 1 MSO_I }, { 0, 10 MSO_I }, { 6 MSO_I, 21600 }, { 4 MSO_I, 10 MSO_I }, { 21600, 9 MSO_I }
+};
+const mso_CustomShape msoCube =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCubeVert), SAL_N_ELEMENTS( mso_sptCubeVert ),
+ const_cast<sal_uInt16*>(mso_sptCubeSegm), sizeof( mso_sptCubeSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCubeCalc), SAL_N_ELEMENTS( mso_sptCubeCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptCubeTextRect), SAL_N_ELEMENTS( mso_sptCubeTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ const_cast<SvxMSDffVertPair*>(mso_sptCubeGluePoints), SAL_N_ELEMENTS( mso_sptCubeGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptCubeHandle), SAL_N_ELEMENTS( mso_sptCubeHandle )
+};
+
+const SvxMSDffVertPair mso_sptBevelVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 1 MSO_I, 0 MSO_I }, { 0 MSO_I, 0 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 0 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 0 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 0 MSO_I, 0 MSO_I }, { 0 MSO_I, 2 MSO_I }
+};
+const sal_uInt16 mso_sptBevelSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptBevelCalc[] =
+{
+ { 0x2001, { DFF_Prop_adjustValue, 21599, 21600 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x400 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x400 } }
+};
+
+const SvxMSDffTextRectangles mso_sptBevelTextRect[] =
+{
+ { { 0 MSO_I, 0 MSO_I }, { 1 MSO_I, 2 MSO_I } }
+};
+const SvxMSDffHandle mso_sptBevelHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED,
+ 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoBevel =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBevelVert), SAL_N_ELEMENTS( mso_sptBevelVert ),
+ const_cast<sal_uInt16*>(mso_sptBevelSegm), sizeof( mso_sptBevelSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBevelCalc), SAL_N_ELEMENTS( mso_sptBevelCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault2700),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptBevelTextRect), SAL_N_ELEMENTS( mso_sptBevelTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptBevelHandle), SAL_N_ELEMENTS( mso_sptBevelHandle )
+};
+
+const SvxMSDffVertPair mso_sptFoldedCornerVert[] = // adjustment1 : x 10800 - 21600
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 0 MSO_I }, { 0 MSO_I, 21600 },
+ { 0, 21600 }, { 0 MSO_I, 21600 }, { 3 MSO_I, 0 MSO_I }, { 8 MSO_I, 9 MSO_I },
+ { 10 MSO_I, 11 MSO_I }, { 21600, 0 MSO_I }
+};
+const sal_uInt16 mso_sptFoldedCornerSegm[] =
+{
+ 0x4000, 0x0004, 0x6001, 0x8000,
+ 0x4000, 0x0001, 0x2001, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptFoldedCornerCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, 0x400 } },
+ { 0x2001, { 0x0401, 8000, 10800 } },
+ { 0x8000, { 21600, 0, 0x0402 } },
+ { 0x2001, { 0x0401, 1, 2 } },
+ { 0x2001, { 0x0401, 1, 4 } },
+ { 0x2001, { 0x0401, 1, 7 } },
+ { 0x2001, { 0x0401, 1, 16 } },
+ { 0x6000, { 0x0403, 0x405, 0 } },
+ { 0x6000, { 0x0400, 0x406, 0 } },
+ { 0x8000, { 21600, 0, 0x404 } },
+ { 0x6000, { 0x400, 0x407, 0 } }
+};
+const sal_Int32 mso_sptFoldedCornerDefault[] =
+{
+ 1, 18900
+};
+const SvxMSDffTextRectangles mso_sptFoldedCornerTextRect[] =
+{
+ { { 0, 0 }, { 21600, 11 MSO_I } }
+};
+const SvxMSDffHandle mso_sptFoldedCornerHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 1, 10800, 10800, 10800, 21600, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoFoldedCorner =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFoldedCornerVert), SAL_N_ELEMENTS( mso_sptFoldedCornerVert ),
+ const_cast<sal_uInt16*>(mso_sptFoldedCornerSegm), sizeof( mso_sptFoldedCornerSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptFoldedCornerCalc), SAL_N_ELEMENTS( mso_sptFoldedCornerCalc ),
+ const_cast<sal_Int32*>(mso_sptFoldedCornerDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFoldedCornerTextRect), SAL_N_ELEMENTS( mso_sptFoldedCornerTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptFoldedCornerHandle), SAL_N_ELEMENTS( mso_sptFoldedCornerHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonBlankVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 1 MSO_I, 0 MSO_I }, { 0 MSO_I, 0 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 0 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 0 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 0 MSO_I, 0 MSO_I }, { 0 MSO_I, 2 MSO_I }
+};
+const sal_uInt16 mso_sptActionButtonBlankSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptActionButtonBlankCalc[] =
+{
+ { 0x2001, { DFF_Prop_adjustValue, 21599, 21600 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x400 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x400 } }
+};
+const SvxMSDffTextRectangles mso_sptActionButtonBlankTextRect[] =
+{
+ { { 0 MSO_I, 0 MSO_I }, { 1 MSO_I, 2 MSO_I } }
+};
+const SvxMSDffHandle mso_sptButtonHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED,
+ 0x100, 0, 10800, 10800, 0, 5400, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoActionButtonBlank =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonBlankVert), SAL_N_ELEMENTS( mso_sptActionButtonBlankVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonBlankSegm), sizeof( mso_sptActionButtonBlankSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonBlankCalc), SAL_N_ELEMENTS( mso_sptActionButtonBlankCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonBlankTextRect), SAL_N_ELEMENTS( mso_sptActionButtonBlankTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffTextRectangles mso_sptActionButtonTextRect[] =
+{
+ { { 1 MSO_I, 2 MSO_I }, { 3 MSO_I, 4 MSO_I } }
+};
+const SvxMSDffVertPair mso_sptActionButtonHomeVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 4 MSO_I },
+
+ { 7 MSO_I, 0xa MSO_I }, { 0xc MSO_I, 0xe MSO_I }, { 0xc MSO_I, 0x10 MSO_I }, { 0x12 MSO_I, 0x10 MSO_I },
+ { 0x12 MSO_I, 0x14 MSO_I }, { 0x16 MSO_I, 8 MSO_I }, { 0x18 MSO_I, 8 MSO_I }, { 0x18 MSO_I, 0x1a MSO_I },
+ { 0x1c MSO_I, 0x1a MSO_I }, { 0x1c MSO_I, 8 MSO_I }, { 0x1e MSO_I, 8 MSO_I },
+
+ { 0xc MSO_I, 0xe MSO_I }, { 0xc MSO_I, 0x10 MSO_I }, { 0x12 MSO_I, 0x10 MSO_I },{ 0x12 MSO_I, 0x14 MSO_I },
+
+ { 0x20 MSO_I, 0x24 MSO_I }, { 0x22 MSO_I, 0x24 MSO_I }, { 0x22 MSO_I, 0x1a MSO_I }, { 0x18 MSO_I, 0x1a MSO_I },
+ { 0x18 MSO_I, 8 MSO_I }, { 0x1c MSO_I, 8 MSO_I }, { 0x1c MSO_I, 0x1a MSO_I }, { 0x20 MSO_I, 0x1a MSO_I }
+
+};
+const sal_uInt16 mso_sptActionButtonHomeSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x000a, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0007, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptActionButtonHomeCalc[] = // adj value 0 - 5400
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x0405, 1, 10800 } }, // scaling 6
+ { 0x2001, { DFF_Prop_geoRight, 1, 2 } }, // lr center 7
+ { 0x2001, { DFF_Prop_geoBottom, 1, 2 } }, // ul center 8
+
+ { 0x4001, { -8000, 0x0406, 1 } }, // 9
+ { 0x6000, { 0x0409, 0x0408, 0 } }, // a
+ { 0x4001, { 2960, 0x0406, 1 } }, // b
+ { 0x6000, { 0x040b, 0x0407, 0 } }, // c
+ { 0x4001, { -5000, 0x0406, 1 } }, // d
+ { 0x6000, { 0x040d, 0x0408, 0 } }, // e
+ { 0x4001, { -7000, 0x0406, 1 } }, // f
+ { 0x6000, { 0x040f, 0x0408, 0 } }, // 10
+ { 0x4001, { 5000, 0x0406, 1 } }, // 11
+ { 0x6000, { 0x0411, 0x0407, 0 } }, // 12
+ { 0x4001, { -2960, 0x0406, 1 } }, // 13
+ { 0x6000, { 0x0413, 0x0408, 0 } }, // 14
+ { 0x4001, { 8000, 0x0406, 1 } }, // 15
+ { 0x6000, { 0x0415,0x0407, 0 } }, // 16
+ { 0x4001, { 6100, 0x0406, 1 } }, // 17
+ { 0x6000, { 0x0417,0x0407, 0 } }, // 18
+ { 0x4001, { 8260, 0x0406, 1 } }, // 19
+ { 0x6000, { 0x0419, 0x0408, 0 } }, // 1a
+ { 0x4001, { -6100, 0x0406, 1 } }, // 1b
+ { 0x6000, { 0x041b, 0x0407, 0 } }, // 1c
+ { 0x4001, { -8000, 0x0406, 1 } }, // 1d
+ { 0x6000, { 0x041d, 0x0407, 0 } }, // 1e
+ { 0x4001, { -1060, 0x0406, 1 } }, // 1f
+ { 0x6000, { 0x041f, 0x0407, 0 } }, // 20
+ { 0x4001, { 1060, 0x0406, 1 } }, // 21
+ { 0x6000, { 0x0421, 0x0407, 0 } }, // 22
+ { 0x4001, { 4020, 0x0406, 1 } }, // 23
+ { 0x6000, { 0x0423, 0x0408, 0 } } // 24
+
+};
+const mso_CustomShape msoActionButtonHome =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonHomeVert), SAL_N_ELEMENTS( mso_sptActionButtonHomeVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonHomeSegm), sizeof( mso_sptActionButtonHomeSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonHomeCalc), SAL_N_ELEMENTS( mso_sptActionButtonHomeCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonHelpVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I,4 MSO_I },
+ { 7 MSO_I, 0xc MSO_I }, { 0xa MSO_I, 0x3e MSO_I }, { 7 MSO_I, 0x10 MSO_I }, { 0xe MSO_I, 0x3e MSO_I }, { 7 MSO_I, 0xc MSO_I },
+ { 0x12 MSO_I, 0x14 MSO_I }, { 0x12 MSO_I, 0x16 MSO_I }, // pp
+ { 0x12 MSO_I, 0x18 MSO_I }, { 0x1a MSO_I, 8 MSO_I }, { 0x1c MSO_I, 8 MSO_I }, // ccp
+ { 0x1e MSO_I, 8 MSO_I }, { 0x20 MSO_I, 0x22 MSO_I }, { 0x20 MSO_I, 0x24 MSO_I }, // ccp
+ { 0x20 MSO_I, 0x26 MSO_I }, { 0x28 MSO_I, 0x2a MSO_I }, { 7 MSO_I, 0x2a MSO_I }, // ccp
+ { 0x2c MSO_I, 0x2a MSO_I }, { 0x2e MSO_I, 0x26 MSO_I }, { 0x2e MSO_I, 0x24 MSO_I }, // ccp
+ { 0x30 MSO_I, 0x24 MSO_I }, { 0x30 MSO_I, 0x32 MSO_I }, { 0x34 MSO_I, 0x36 MSO_I }, // ccp
+ { 7 MSO_I, 0x36 MSO_I }, // p
+ { 0x12 MSO_I, 0x36 MSO_I }, { 0x1c MSO_I, 0x32 MSO_I }, { 0x1c MSO_I, 0x24 MSO_I }, // ccp
+ { 0x1c MSO_I, 0x38 MSO_I }, { 0x3a MSO_I, 0x3c MSO_I }, { 0x12 MSO_I, 0x3c MSO_I }, // ccp
+ { 7 MSO_I, 0x3c MSO_I }, { 0x34 MSO_I, 8 MSO_I }, { 0x34 MSO_I, 0x16 MSO_I }, // ccp
+ { 0x34 MSO_I, 0x14 MSO_I }
+};
+const sal_uInt16 mso_sptActionButtonHelpSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0xa704, 0x6000, 0x8000,
+ 0x4000, 0x0001, 0x2004, 0x0001, 0x2004, 0x0001, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptActionButtonHelpCalc[] = // adj value 0 - 5400
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x0405, 1, 10800 } }, // scaling 6
+ { 0x2001, { DFF_Prop_geoRight, 1, 2 } }, // lr center 7
+ { 0x2001, { DFF_Prop_geoBottom, 1, 2 } }, // ul center 8
+
+ { 0x4001, { -1690, 0x0406, 1 } }, // 9
+ { 0x6000, { 0x0409, 0x0407, 0 } }, // a
+ { 0x4001, { 4600, 0x0406, 1 } }, // b
+ { 0x6000, { 0x040b, 0x0408, 0 } }, // c
+ { 0x4001, { 1690, 0x0406, 1 } }, // d
+ { 0x6000, { 0x040d, 0x0407, 0 } }, // e
+ { 0x4001, { 7980, 0x0406, 1 } }, // f
+ { 0x6000, { 0x040f, 0x0408, 0 } }, // 10
+ { 0x4001, { 1270, 0x0406, 1 } }, // 11
+ { 0x6000, { 0x0411, 0x0407, 0 } }, // 12
+ { 0x4001, { 4000, 0x0406, 1 } }, // 13
+ { 0x6000, { 0x0413, 0x0408, 0 } }, // 14
+ { 0x4001, { 1750, 0x0406, 1 } }, // 15
+ { 0x6000, { 0x0415, 0x0408, 0 } }, // 16
+ { 0x4001, { 800, 0x0406, 1 } }, // 17
+ { 0x6000, { 0x0417, 0x0408, 0 } }, // 18
+ { 0x4001, { 1650, 0x0406, 1 } }, // 19
+ { 0x6000, { 0x0419, 0x0407, 0 } }, // 1a
+ { 0x4001, { 2340, 0x0406, 1 } }, // 1b
+ { 0x6000, { 0x041b, 0x0407, 0 } }, // 1c
+ { 0x4001, { 3640, 0x0406, 1 } }, // 1d
+ { 0x6000, { 0x041d, 0x0407, 0 } }, // 1e
+ { 0x4001, { 4670, 0x0406, 1 } }, // 1f
+ { 0x6000, { 0x041f, 0x0407, 0 } }, // 20
+ { 0x4001, { -1570, 0x0406, 1 } }, // 21
+ { 0x6000, { 0x0421, 0x0408, 0 } }, // 22
+ { 0x4001, { -3390, 0x0406, 1 } }, // 23
+ { 0x6000, { 0x0423, 0x0408, 0 } }, // 24
+ { 0x4001, { -6050, 0x0406, 1 } }, // 25
+ { 0x6000, { 0x0425, 0x0408, 0 } }, // 26
+ { 0x4001, { 2540, 0x0406, 1 } }, // 27
+ { 0x6000, { 0x0427, 0x0407, 0 } }, // 28
+ { 0x4001, { -8050, 0x0406, 1 } }, // 29
+ { 0x6000, { 0x0429, 0x0408, 0 } }, // 2a
+ { 0x4001, { -2540, 0x0406, 1 } }, // 2b
+ { 0x6000, { 0x042b, 0x0407, 0 } }, // 2c
+ { 0x4001, { -4460, 0x0406, 1 } }, // 2d
+ { 0x6000, { 0x042d, 0x0407, 0 } }, // 2e
+ { 0x4001, { -2330, 0x0406, 1 } }, // 2f
+ { 0x6000, { 0x042f, 0x0407, 0 } }, // 30
+ { 0x4001, { -4700, 0x0406, 1 } }, // 31
+ { 0x6000, { 0x0431, 0x0408, 0 } }, // 32
+ { 0x4001, { -1270, 0x0406, 1 } }, // 33
+ { 0x6000, { 0x0433, 0x0407, 0 } }, // 34
+ { 0x4001, { -5720, 0x0406, 1 } }, // 35
+ { 0x6000, { 0x0435, 0x0408, 0 } }, // 36
+ { 0x4001, { -2540, 0x0406, 1 } }, // 37
+ { 0x6000, { 0x0437, 0x0408, 0 } }, // 38
+ { 0x4001, { 1800, 0x0406, 1 } }, // 39
+ { 0x6000, { 0x0439, 0x0407, 0 } }, // 3a
+ { 0x4001, { -1700, 0x0406, 1 } }, // 3b
+ { 0x6000, { 0x043b, 0x0408, 0 } }, // 3c
+ { 0x4001, { 6290, 0x0406, 1 } }, // 3d
+ { 0x6000, { 0x043d, 0x0408, 0 } } // 3e
+};
+const mso_CustomShape msoActionButtonHelp =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonHelpVert), SAL_N_ELEMENTS( mso_sptActionButtonHelpVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonHelpSegm), sizeof( mso_sptActionButtonHelpSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonHelpCalc), SAL_N_ELEMENTS( mso_sptActionButtonHelpCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonInformationVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 4 MSO_I },
+ { 0x7 MSO_I, 0xc MSO_I }, { 0xa MSO_I, 0x8 MSO_I }, { 0x7 MSO_I, 0x10 MSO_I }, { 0xe MSO_I, 8 MSO_I }, { 0x7 MSO_I, 0xc MSO_I },
+ { 0x7 MSO_I, 0x14 MSO_I }, { 0x12 MSO_I, 0x2a MSO_I }, { 0x7 MSO_I, 0x18 MSO_I }, { 0x16 MSO_I, 0x2a MSO_I }, { 0x7 MSO_I, 0x14 MSO_I },
+ { 0x1a MSO_I, 0x1c MSO_I }, { 0x1e MSO_I, 0x1c MSO_I }, { 0x1e MSO_I, 0x20 MSO_I }, { 0x22 MSO_I, 0x20 MSO_I },
+ { 0x22 MSO_I, 0x24 MSO_I }, { 0x1a MSO_I, 0x24 MSO_I }, { 0x1a MSO_I, 0x20 MSO_I }, { 0x26 MSO_I, 0x20 MSO_I },
+ { 0x26 MSO_I, 0x28 MSO_I }, { 0x1a MSO_I, 0x28 MSO_I }
+};
+const sal_uInt16 mso_sptActionButtonInformationSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0xa704, 0x6000, 0x8000,
+ 0x4000, 0xa704, 0x6000, 0x8000,
+ 0x4000, 0x0009, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptActionButtonInformationCalc[] = // adj value 0 - 5400
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x0405, 1, 10800 } }, // scaling 6
+ { 0x2001, { DFF_Prop_geoRight, 1, 2 } }, // lr center 7
+ { 0x2001, { DFF_Prop_geoBottom, 1, 2 } }, // ul center 8
+
+ { 0x4001, { -8050, 0x0406, 1 } }, // 9
+ { 0x6000, { 0x0409, 0x0407, 0 } }, // a
+ { 0x4001, { -8050, 0x0406, 1 } }, // b
+ { 0x6000, { 0x040b, 0x0408, 0 } }, // c
+ { 0x4001, { 8050, 0x0406, 1 } }, // d
+ { 0x6000, { 0x040d, 0x0407, 0 } }, // e
+ { 0x4001, { 8050, 0x0406, 1 } }, // f
+ { 0x6000, { 0x040f, 0x0408, 0 } }, // 10
+
+ { 0x4001, { -2060, 0x0406, 1 } }, // 11
+ { 0x6000, { 0x0411, 0x0407, 0 } }, // 12
+ { 0x4001, { -7620, 0x0406, 1 } }, // 13
+ { 0x6000, { 0x0413, 0x0408, 0 } }, // 14
+ { 0x4001, { 2060, 0x0406, 1 } }, // 15
+ { 0x6000, { 0x0415, 0x0407, 0 } }, // 16
+ { 0x4001, { -3500, 0x0406, 1 } }, // 17
+ { 0x6000, { 0x0417, 0x0408, 0 } }, // 18
+
+ { 0x4001, { -2960, 0x0406, 1 } }, // 19
+ { 0x6000, { 0x0419, 0x0407, 0 } }, // 1a
+ { 0x4001, { -2960, 0x0406, 1 } }, // 1b
+ { 0x6000, { 0x041b, 0x0408, 0 } }, // 1c
+ { 0x4001, { 1480, 0x0406, 1 } }, // 1d
+ { 0x6000, { 0x041d, 0x0407, 0 } }, // 1e
+ { 0x4001, { 5080, 0x0406, 1 } }, // 1f
+ { 0x6000, { 0x041f, 0x0408, 0 } }, // 20
+ { 0x4001, { 2960, 0x0406, 1 } }, // 21
+ { 0x6000, { 0x0421, 0x0407, 0 } }, // 22
+ { 0x4001, { 6140, 0x0406, 1 } }, // 23
+ { 0x6000, { 0x0423, 0x0408, 0 } }, // 24
+ { 0x4001, { -1480, 0x0406, 1 } }, // 25
+ { 0x6000, { 0x0425, 0x0407, 0 } }, // 26
+ { 0x4001, { -1920, 0x0406, 1 } }, // 27
+ { 0x6000, { 0x0427, 0x0408, 0 } }, // 28
+
+ { 0x4001, { -5560, 0x0406, 1 } }, // 29
+ { 0x6000, { 0x0429, 0x0408, 0 } }, // 2a
+
+};
+const mso_CustomShape msoActionButtonInformation =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonInformationVert), SAL_N_ELEMENTS( mso_sptActionButtonInformationVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonInformationSegm), sizeof( mso_sptActionButtonInformationSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonInformationCalc), SAL_N_ELEMENTS( mso_sptActionButtonInformationCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonBackPreviousVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I,4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 4 MSO_I },
+
+ { 0xa MSO_I, 8 MSO_I }, { 0xe MSO_I, 0xc MSO_I }, { 0xe MSO_I, 0x10 MSO_I }
+};
+const sal_uInt16 mso_sptActionButtonForwardBackSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0002, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptActionButtonForwardBackCalc[] = // adj value 0 - 5400
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x0405, 1, 10800 } }, // scaling 6
+ { 0x2001, { DFF_Prop_geoRight, 1, 2 } }, // lr center 7
+ { 0x2001, { DFF_Prop_geoBottom, 1, 2 } }, // ul center 8
+
+ { 0x4001, { -8050, 0x0406, 1 } }, // 9
+ { 0x6000, { 0x0409, 0x0407, 0 } }, // a
+ { 0x4001, { -8050, 0x0406, 1 } }, // b
+ { 0x6000, { 0x040b, 0x0408, 0 } }, // c
+ { 0x4001, { 8050, 0x0406, 1 } }, // d
+ { 0x6000, { 0x040d, 0x0407, 0 } }, // e
+ { 0x4001, { 8050, 0x0406, 1 } }, // f
+ { 0x6000, { 0x040f, 0x0408, 0 } } // 10
+};
+const mso_CustomShape msoActionButtonBackPrevious =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonBackPreviousVert), SAL_N_ELEMENTS( mso_sptActionButtonBackPreviousVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonForwardBackSegm), sizeof( mso_sptActionButtonForwardBackSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonForwardBackCalc), SAL_N_ELEMENTS( mso_sptActionButtonForwardBackCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonForwardNextVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 4 MSO_I },
+
+ { 0xa MSO_I, 0xc MSO_I }, { 0xe MSO_I, 8 MSO_I }, { 0xa MSO_I, 0x10 MSO_I }
+};
+const mso_CustomShape msoActionButtonForwardNext =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonForwardNextVert), SAL_N_ELEMENTS( mso_sptActionButtonForwardNextVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonForwardBackSegm), sizeof( mso_sptActionButtonForwardBackSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonForwardBackCalc), SAL_N_ELEMENTS( mso_sptActionButtonForwardBackCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonBeginningVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 4 MSO_I },
+
+ { 0xa MSO_I, 8 MSO_I }, { 0xe MSO_I, 0xc MSO_I }, { 0xe MSO_I, 0x10 MSO_I }, { 0x12 MSO_I, 0xc MSO_I },
+ { 0x14 MSO_I, 0xc MSO_I }, { 0x14 MSO_I, 0x10 MSO_I }, { 0x12 MSO_I, 0x10 MSO_I }
+};
+const sal_uInt16 mso_sptActionButtonBeginningEndSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+
+ 0x4000, 0x0002, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptActionButtonBeginningEndCalc[] = // adj value 0 - 5400
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x0405, 1, 10800 } }, // scaling 6
+ { 0x2001, { DFF_Prop_geoRight, 1, 2 } }, // lr center 7
+ { 0x2001, { DFF_Prop_geoBottom, 1, 2 } }, // ul center 8
+
+ { 0x4001, { -4020, 0x0406, 1 } }, // 9
+ { 0x6000, { 0x0409, 0x0407, 0 } }, // a
+ { 0x4001, { -8050, 0x0406, 1 } }, // b
+ { 0x6000, { 0x040b, 0x0408, 0 } }, // c
+ { 0x4001, { 8050, 0x0406, 1 } }, // d
+ { 0x6000, { 0x040d, 0x0407, 0 } }, // e
+ { 0x4001, { 8050, 0x0406, 1 } }, // f
+ { 0x6000, { 0x040f, 0x0408, 0 } }, // 10
+
+ { 0x4001, { -8050, 0x0406, 1 } }, // 11
+ { 0x6000, { 0x0411, 0x0407, 0 } }, // 12
+ { 0x4001, { -6140, 0x0406, 1 } }, // 13
+ { 0x6000, { 0x0413, 0x0407, 0 } }, // 14
+
+
+ { 0x4001, { 4020, 0x0406, 1 } }, // 15
+ { 0x6000, { 0x0415, 0x0407, 0 } }, // 16
+ { 0x4001, { 6140, 0x0406, 1 } }, // 17
+ { 0x6000, { 0x0417, 0x0407, 0 } } // 18
+};
+const mso_CustomShape msoActionButtonBeginning =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonBeginningVert), SAL_N_ELEMENTS( mso_sptActionButtonBeginningVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonBeginningEndSegm), sizeof( mso_sptActionButtonBeginningEndSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonBeginningEndCalc), SAL_N_ELEMENTS( mso_sptActionButtonBeginningEndCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonEndVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 4 MSO_I },
+
+ { 0x16 MSO_I, 8 MSO_I }, { 0x12 MSO_I, 0x10 MSO_I }, { 0x12 MSO_I, 0xc MSO_I },
+
+ { 0x18 MSO_I, 0xc MSO_I }, { 0x18 MSO_I, 0x10 MSO_I }, { 0xe MSO_I, 0x10 MSO_I }, { 0xe MSO_I, 0xc MSO_I }
+};
+const mso_CustomShape msoActionButtonEnd =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonEndVert), SAL_N_ELEMENTS( mso_sptActionButtonEndVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonBeginningEndSegm), sizeof( mso_sptActionButtonBeginningEndSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonBeginningEndCalc), SAL_N_ELEMENTS( mso_sptActionButtonBeginningEndCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonReturnVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 4 MSO_I },
+
+ { 0xa MSO_I, 0xc MSO_I }, { 0xe MSO_I, 0xc MSO_I }, { 0xe MSO_I, 0x10 MSO_I }, // ppp
+ { 0xe MSO_I, 0x12 MSO_I }, { 0x14 MSO_I, 0x16 MSO_I }, { 0x18 MSO_I, 0x16 MSO_I }, // ccp
+ { 7 MSO_I, 0x16 MSO_I }, // p
+ { 0x1a MSO_I, 0x16 MSO_I }, { 0x1c MSO_I, 0x12 MSO_I }, { 0x1c MSO_I, 0x10 MSO_I }, // ccp
+ { 0x1c MSO_I, 0xc MSO_I }, { 7 MSO_I, 0xc MSO_I }, { 0x1e MSO_I, 0x20 MSO_I }, { 0x22 MSO_I, 0xc MSO_I },// pppp
+ { 0x24 MSO_I, 0xc MSO_I }, { 0x24 MSO_I, 0x10 MSO_I }, // pp
+ { 0x24 MSO_I, 0x26 MSO_I }, { 0x28 MSO_I, 0x2a MSO_I }, { 7 MSO_I, 0x2a MSO_I }, // ccp
+ { 0x18 MSO_I, 0x2a MSO_I }, // p
+ { 0x2c MSO_I, 0x2a MSO_I }, { 0xa MSO_I, 0x26 MSO_I }, { 0xa MSO_I, 0x10 MSO_I } // ccp
+};
+const sal_uInt16 mso_sptActionButtonReturnSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0002, 0x2001, 0x0001, 0x2001, 0x0006,0x2001, 0x0001, 0x2001, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptActionButtonReturnCalc[] = // adj value 0 - 5400
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x0405, 1, 10800 } }, // scaling 6
+ { 0x2001, { DFF_Prop_geoRight, 1, 2 } }, // lr center 7
+ { 0x2001, { DFF_Prop_geoBottom, 1, 2 } }, // ul center 8
+
+ { 0x4001, { -8050, 0x0406, 1 } }, // 9
+ { 0x6000, { 0x0409, 0x0407, 0 } }, // a
+ { 0x4001, { -3800, 0x0406, 1 } }, // b
+ { 0x6000, { 0x040b, 0x0408, 0 } }, // c
+ { 0x4001, { -4020, 0x0406, 1 } }, // d
+ { 0x6000, { 0x040d, 0x0407, 0 } }, // e
+ { 0x4001, { 2330, 0x0406, 1 } }, // f
+ { 0x6000, { 0x040f, 0x0408, 0 } }, // 10
+ { 0x4001, { 3390, 0x0406, 1 } }, // 11
+ { 0x6000, { 0x0411, 0x0408, 0 } }, // 12
+ { 0x4001, { -3100, 0x0406, 1 } }, // 13
+ { 0x6000, { 0x0413, 0x0407, 0 } }, // 14
+ { 0x4001, { 4230, 0x0406, 1 } }, // 15
+ { 0x6000, { 0x0415, 0x0408, 0 } }, // 16
+ { 0x4001, { -1910, 0x0406, 1 } }, // 17
+ { 0x6000, { 0x0417, 0x0407, 0 } }, // 18
+ { 0x4001, { 1190, 0x0406, 1 } }, // 19
+ { 0x6000, { 0x0419, 0x0407, 0 } }, // 1a
+ { 0x4001, { 2110, 0x0406, 1 } }, // 1b
+ { 0x6000, { 0x041b, 0x0407, 0 } }, // 1c
+ { 0x4001, { 4030, 0x0406, 1 } }, // 1d
+ { 0x6000, { 0x041d, 0x0407, 0 } }, // 1e
+ { 0x4001, { -7830, 0x0406, 1 } }, // 1f
+ { 0x6000, { 0x041f, 0x0408, 0 } }, // 20
+ { 0x4001, { 8250, 0x0406, 1 } }, // 21
+ { 0x6000, { 0x0421, 0x0407, 0 } }, // 22
+ { 0x4001, { 6140, 0x0406, 1 } }, // 23
+ { 0x6000, { 0x0423, 0x0407, 0 } }, // 24
+ { 0x4001, { 5510, 0x0406, 1 } }, // 25
+ { 0x6000, { 0x0425, 0x0408, 0 } }, // 26
+ { 0x4001, { 3180, 0x0406, 1 } }, // 27
+ { 0x6000, { 0x0427, 0x0407, 0 } }, // 28
+ { 0x4001, { 8450, 0x0406, 1 } }, // 29
+ { 0x6000, { 0x0429, 0x0408, 0 } }, // 2a
+ { 0x4001, { -5090, 0x0406, 1 } }, // 2b
+ { 0x6000, { 0x042b, 0x0407, 0 } } // 2c
+};
+const mso_CustomShape msoActionButtonReturn =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonReturnVert), SAL_N_ELEMENTS( mso_sptActionButtonReturnVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonReturnSegm), sizeof( mso_sptActionButtonReturnSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonReturnCalc), SAL_N_ELEMENTS( mso_sptActionButtonReturnCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonDocumentVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 4 MSO_I },
+
+ { 0xa MSO_I, 0xc MSO_I }, { 0xe MSO_I, 0xc MSO_I }, { 0x10 MSO_I, 0x12 MSO_I }, { 0x10 MSO_I, 0x14 MSO_I },
+ { 0xa MSO_I, 0x14 MSO_I }, { 0xe MSO_I, 0xc MSO_I }, { 0x10 MSO_I, 0x12 MSO_I }, { 0xe MSO_I, 0x12 MSO_I }
+};
+const sal_uInt16 mso_sptActionButtonDocumentSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+
+ 0x4000, 0x0004, 0x6001, 0x8000,
+ 0x4000, 0x0002, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptActionButtonDocumentCalc[] = // adj value 0 - 5400
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x0405, 1, 10800 } }, // scaling 6
+ { 0x2001, { DFF_Prop_geoRight, 1, 2 } }, // lr center 7
+ { 0x2001, { DFF_Prop_geoBottom, 1, 2 } }, // ul center 8
+
+ { 0x4001, { -6350, 0x0406, 1 } }, // 9
+ { 0x6000, { 0x0409, 0x0407, 0 } }, // a
+ { 0x4001, { -7830, 0x0406, 1 } }, // b
+ { 0x6000, { 0x040b, 0x0408, 0 } }, // c
+ { 0x4001, { 1690, 0x0406, 1 } }, // d
+ { 0x6000, { 0x040d, 0x0407, 0 } }, // e
+ { 0x4001, { 6350, 0x0406, 1 } }, // f
+ { 0x6000, { 0x040f, 0x0407, 0 } }, // 10
+ { 0x4001, { -3810, 0x0406, 1 } }, // 11
+ { 0x6000, { 0x0411, 0x0408, 0 } }, // 12
+ { 0x4001, { 7830, 0x0406, 1 } }, // 13
+ { 0x6000, { 0x0413, 0x0408, 0 } } // 14
+};
+const mso_CustomShape msoActionButtonDocument =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonDocumentVert), SAL_N_ELEMENTS( mso_sptActionButtonDocumentVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonDocumentSegm), sizeof( mso_sptActionButtonDocumentSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonDocumentCalc), SAL_N_ELEMENTS( mso_sptActionButtonDocumentCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonSoundVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 4 MSO_I },
+
+ { 0xa MSO_I, 0xc MSO_I }, { 0xe MSO_I, 0xc MSO_I }, { 0x10 MSO_I, 0x12 MSO_I }, { 0x10 MSO_I, 0x14 MSO_I },
+ { 0xe MSO_I, 0x16 MSO_I }, { 0xa MSO_I, 0x16 MSO_I }, { 0x18 MSO_I, 8 MSO_I }, { 0x1a MSO_I, 8 MSO_I },
+
+ { 0x18 MSO_I, 0xc MSO_I }, { 0x1a MSO_I, 0x1c MSO_I },
+
+ { 0x18 MSO_I, 0x16 MSO_I }, { 0x1a MSO_I, 0x1e MSO_I }
+};
+const sal_uInt16 mso_sptActionButtonSoundSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+
+ 0x4000, 0x0005, 0x6001, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptActionButtonSoundCalc[] = // adj value 0 - 5400
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x0405, 1, 10800 } }, // scaling 6
+ { 0x2001, { DFF_Prop_geoRight, 1, 2 } }, // lr center 7
+ { 0x2001, { DFF_Prop_geoBottom, 1, 2 } }, // ul center 8
+
+ { 0x4001, { -8050, 0x0406, 1 } }, // 9
+ { 0x6000, { 0x0409, 0x0407, 0 } }, // a
+ { 0x4001, { -2750, 0x0406, 1 } }, // b
+ { 0x6000, { 0x040b, 0x0408, 0 } }, // c
+ { 0x4001, { -2960, 0x0406, 1 } }, // d
+ { 0x6000, { 0x040d, 0x0407, 0 } }, // e
+ { 0x4001, { 2120, 0x0406, 1 } }, // f
+ { 0x6000, { 0x040f, 0x0407, 0 } }, // 10
+ { 0x4001, { -8050, 0x0406, 1 } }, // 11
+ { 0x6000, { 0x0411, 0x0408, 0 } }, // 12
+ { 0x4001, { 8050, 0x0406, 1 } }, // 13
+ { 0x6000, { 0x0413, 0x0408, 0 } }, // 14
+ { 0x4001, { 2750, 0x0406, 1 } }, // 15
+ { 0x6000, { 0x0415, 0x0408, 0 } }, // 16
+ { 0x4001, { 4020, 0x0406, 1 } }, // 17
+ { 0x6000, { 0x0417, 0x0407, 0 } }, // 18
+ { 0x4001, { 8050, 0x0406, 1 } }, // 19
+ { 0x6000, { 0x0419, 0x0407, 0 } }, // 1a
+ { 0x4001, { -5930, 0x0406, 1 } }, // 1b
+ { 0x6000, { 0x041b, 0x0408, 0 } }, // 1c
+ { 0x4001, { 5930, 0x0406, 1 } }, // 1d
+ { 0x6000, { 0x041d, 0x0408, 0 } } // 1e
+};
+const mso_CustomShape msoActionButtonSound =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonSoundVert), SAL_N_ELEMENTS( mso_sptActionButtonSoundVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonSoundSegm), sizeof( mso_sptActionButtonSoundSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonSoundCalc), SAL_N_ELEMENTS( mso_sptActionButtonSoundCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptActionButtonMovieVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 0 }, { 21600, 0 }, { 3 MSO_I, 2 MSO_I }, { 1 MSO_I, 2 MSO_I },
+ { 21600, 0 }, { 21600, 21600 }, { 3 MSO_I, 4 MSO_I }, { 3 MSO_I, 2 MSO_I },
+ { 21600, 21600 }, { 0, 21600 }, { 1 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 0, 21600 }, { 0, 0 }, { 1 MSO_I, 2 MSO_I }, { 1 MSO_I, 4 MSO_I },
+
+ { 0xa MSO_I, 0xc MSO_I }, { 0xe MSO_I, 0xc MSO_I }, { 0x10 MSO_I, 0x12 MSO_I }, { 0x14 MSO_I, 0x12 MSO_I },
+ { 0x16 MSO_I, 0x18 MSO_I }, { 0x16 MSO_I, 0x1a MSO_I }, { 0x1c MSO_I, 0x1a MSO_I }, { 0x1e MSO_I, 0x18 MSO_I },
+ { 0x20 MSO_I, 0x18 MSO_I }, { 0x20 MSO_I, 0x22 MSO_I }, { 0x1e MSO_I, 0x22 MSO_I }, { 0x1c MSO_I, 0x24 MSO_I },
+ { 0x16 MSO_I, 0x24 MSO_I }, { 0x16 MSO_I, 0x26 MSO_I }, { 0x2a MSO_I, 0x26 MSO_I }, { 0x2a MSO_I, 0x28 MSO_I },
+ { 0x10 MSO_I, 0x28 MSO_I }, { 0xe MSO_I, 0x2c MSO_I }, { 0xa MSO_I, 0x2c MSO_I }
+};
+const sal_uInt16 mso_sptActionButtonMovieSegm[] =
+{
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0003, 0x6001, 0x8000,
+ 0x4000, 0x0012, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptActionButtonMovieCalc[] = // adj value 0 - 5400
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x0405, 1, 10800 } }, // scaling 6
+ { 0x2001, { DFF_Prop_geoRight, 1, 2 } }, // lr center 7
+ { 0x2001, { DFF_Prop_geoBottom, 1, 2 } }, // ul center 8
+
+ { 0x4001, { -8050, 0x0406, 1 } }, // 9
+ { 0x6000, { 0x0409, 0x0407, 0 } }, // a
+ { 0x4001, { -4020, 0x0406, 1 } }, // b
+ { 0x6000, { 0x040b, 0x0408, 0 } }, // c
+ { 0x4001, { -7000, 0x0406, 1 } }, // d
+ { 0x6000, { 0x040d, 0x0407, 0 } }, // e
+ { 0x4001, { -6560, 0x0406, 1 } }, // f
+ { 0x6000, { 0x040f, 0x0407, 0 } }, // 10
+ { 0x4001, { -3600, 0x0406, 1 } }, // 11
+ { 0x6000, { 0x0411, 0x0408, 0 } }, // 12
+ { 0x4001, { 4020, 0x0406, 1 } }, // 13
+ { 0x6000, { 0x0413, 0x0407, 0 } }, // 14
+ { 0x4001, { 4660, 0x0406, 1 } }, // 15
+ { 0x6000, { 0x0415, 0x0407, 0 } }, // 16
+ { 0x4001, { -2960, 0x0406, 1 } }, // 17
+ { 0x6000, { 0x0417, 0x0408, 0 } }, // 18
+ { 0x4001, { -2330, 0x0406, 1 } }, // 19
+ { 0x6000, { 0x0419, 0x0408, 0 } }, // 1a
+ { 0x4001, { 6780, 0x0406, 1 } }, // 1b
+ { 0x6000, { 0x041b, 0x0407, 0 } }, // 1c
+ { 0x4001, { 7200, 0x0406, 1 } }, // 1d
+ { 0x6000, { 0x041d, 0x0407, 0 } }, // 1e
+ { 0x4001, { 8050, 0x0406, 1 } }, // 1f
+ { 0x6000, { 0x041f, 0x0407, 0 } }, // 20
+ { 0x4001, { 2960, 0x0406, 1 } }, // 21
+ { 0x6000, { 0x0421, 0x0408, 0 } }, // 22
+ { 0x4001, { 2330, 0x0406, 1 } }, // 23
+ { 0x6000, { 0x0423, 0x0408, 0 } }, // 24
+ { 0x4001, { 3800, 0x0406, 1 } }, // 25
+ { 0x6000, { 0x0425, 0x0408, 0 } }, // 26
+ { 0x4001, { -1060, 0x0406, 1 } }, // 27
+ { 0x6000, { 0x0427, 0x0408, 0 } }, // 28
+ { 0x4001, { -6350, 0x0406, 1 } }, // 29
+ { 0x6000, { 0x0429, 0x0407, 0 } }, // 2a
+ { 0x4001, { -640, 0x0406, 1 } }, // 2b
+ { 0x6000, { 0x042b, 0x0408, 0 } } // 2c
+};
+const mso_CustomShape msoActionButtonMovie =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptActionButtonMovieVert), SAL_N_ELEMENTS( mso_sptActionButtonMovieVert ),
+ const_cast<sal_uInt16*>(mso_sptActionButtonMovieSegm), sizeof( mso_sptActionButtonMovieSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptActionButtonMovieCalc), SAL_N_ELEMENTS( mso_sptActionButtonMovieCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptActionButtonTextRect), SAL_N_ELEMENTS( mso_sptActionButtonTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptButtonHandle), SAL_N_ELEMENTS( mso_sptButtonHandle )
+};
+
+const SvxMSDffVertPair mso_sptSmileyFaceVert[] = // adj value 15510 - 17520
+{
+ { 10800, 10800 }, { 10800, 10800 }, { 0, 360 },
+ { 7305, 7515 }, { 1000, 1865 }, { 0, 360 },
+ { 14295, 7515 }, { 1000, 1865 }, { 0, 360 },
+ { 4870, 1 MSO_I }, { 8680, 2 MSO_I }, { 12920, 2 MSO_I }, { 16730, 1 MSO_I }
+};
+const sal_uInt16 mso_sptSmileyFaceSegm[] =
+{
+ 0xa203, 0x6000, 0x8000,
+ 0xa203, 0x6000, 0x8000,
+ 0xa203, 0x6000, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000
+};
+const SvxMSDffCalculationData mso_sptSmileyFaceCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 14510 } },
+ { 0x8000, { 18520, 0, 0x400 } },
+ { 0x4000, { 14510, 0x400, 0 } }
+};
+
+const sal_Int32 mso_sptSmileyFaceDefault[] =
+{
+ 1, 18520
+};
+const SvxMSDffHandle mso_sptSmileyHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 14510, 18520 }
+};
+const mso_CustomShape msoSmileyFace =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptSmileyFaceVert), SAL_N_ELEMENTS( mso_sptSmileyFaceVert ),
+ const_cast<sal_uInt16*>(mso_sptSmileyFaceSegm), sizeof( mso_sptSmileyFaceSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptSmileyFaceCalc), SAL_N_ELEMENTS( mso_sptSmileyFaceCalc ),
+ const_cast<sal_Int32*>(mso_sptSmileyFaceDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptEllipseTextRect), SAL_N_ELEMENTS( mso_sptEllipseTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptSmileyHandle), SAL_N_ELEMENTS( mso_sptSmileyHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptDonutVert[] = // adj value 0 - 10800
+{
+ { 10800, 10800 }, { 10800, 10800 }, { 0, 360 },
+ { 10800, 10800 }, { 1 MSO_I, 1 MSO_I }, { 0, 360 }
+};
+const sal_uInt16 mso_sptDonutSegm[] =
+{
+ 0xa203, 0x6000, 0xa203, 0x8000
+};
+const SvxMSDffCalculationData mso_sptDonutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } }
+};
+const SvxMSDffHandle mso_sptDonutHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 10800, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoDonut =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptDonutVert), SAL_N_ELEMENTS( mso_sptDonutVert ),
+ const_cast<sal_uInt16*>(mso_sptDonutSegm), sizeof( mso_sptDonutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptDonutCalc), SAL_N_ELEMENTS( mso_sptDonutCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptEllipseTextRect), SAL_N_ELEMENTS( mso_sptEllipseTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptDonutHandle), SAL_N_ELEMENTS( mso_sptDonutHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptNoSmokingVert[] = // adj value 0 - 7200
+{
+ { 10800, 10800 }, { 10800, 10800 }, { 0, 360 },
+ { 0 MSO_I, 0 MSO_I }, { 1 MSO_I, 1 MSO_I },
+ { 9 MSO_I, 0xa MSO_I }, { 0xb MSO_I, 0xc MSO_I }, { 0 MSO_I, 0 MSO_I }, { 1 MSO_I, 1 MSO_I },
+ { 0xd MSO_I, 0xe MSO_I }, { 0xf MSO_I, 0x10 MSO_I }
+};
+const sal_uInt16 mso_sptNoSmokingSegm[] =
+{
+ 0xa203, 0x6000, 0xa404, 0x6000, 0xa404, 0x6000, 0x8000
+};
+const SvxMSDffCalculationData mso_sptNoSmokingCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 0
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }, // 1
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } }, // 2
+ { 0x2001, { DFF_Prop_adjustValue, 1, 2 } }, // 3
+ { 0xa080, { 0x403, 0, 0x402 } }, // 4
+ { 0x8000, { 10800, 0, 0x403 } }, // 5 x1
+ { 0x4000, { 10800, 0x403, 0 } }, // 6 x2
+ { 0x8000, { 10800, 0, 0x404 } }, // 7 y1
+ { 0x4000, { 10800, 0x404, 0 } }, // 8 y2
+ { 0x6081, { 0x405, 0x407, 45 } }, // 9
+ { 0x6082, { 0x405, 0x407, 45 } }, // a
+ { 0x6081, { 0x405, 0x408, 45 } }, // b
+ { 0x6082, { 0x405, 0x408, 45 } }, // c
+ { 0x6081, { 0x406, 0x408, 45 } }, // d
+ { 0x6082, { 0x406, 0x408, 45 } }, // e
+ { 0x6081, { 0x406, 0x407, 45 } }, // f
+ { 0x6082, { 0x406, 0x407, 45 } } // 10
+};
+const SvxMSDffHandle mso_sptNoSmokingHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 10800, 10800, 10800, 0, 7200, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoNoSmoking =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptNoSmokingVert), SAL_N_ELEMENTS( mso_sptNoSmokingVert ),
+ const_cast<sal_uInt16*>(mso_sptNoSmokingSegm), sizeof( mso_sptNoSmokingSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptNoSmokingCalc), SAL_N_ELEMENTS( mso_sptNoSmokingCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault2700),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptEllipseTextRect), SAL_N_ELEMENTS( mso_sptEllipseTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptNoSmokingHandle), SAL_N_ELEMENTS( mso_sptNoSmokingHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptBlockArcVert[] = // adj value 0 (degrees)
+{ // adj value 1: 0 -> 10800;
+ { 0, 0 }, { 21600, 21600 }, { 4 MSO_I, 3 MSO_I }, { 2 MSO_I, 3 MSO_I },
+ { 5 MSO_I, 5 MSO_I }, { 6 MSO_I, 6 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 4 MSO_I, 3 MSO_I }
+};
+const sal_uInt16 mso_sptBlockArcSegm[] =
+{
+ 0xA404, 0xa504, 0x6001, 0x8000
+};
+const sal_Int32 mso_sptBlockArcDefault[] =
+{
+ 2, 180, 5400
+};
+const SvxMSDffCalculationData mso_sptBlockArcCalc[] =
+{
+ { 0x400a, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x4009, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x2000, { 0x400, 10800, 0 } },
+ { 0x2000, { 0x401, 10800, 0 } },
+ { 0x8000, { 21600, 0, 0x402 } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjust2Value } },
+ { 0x4000, { 10800, DFF_Prop_adjust2Value, 0 } },
+ { 0x600a, { 0x405, DFF_Prop_adjustValue, 0 } },
+ { 0x6009, { 0x405, DFF_Prop_adjustValue, 0 } }
+};
+const SvxMSDffHandle mso_sptBlockArcHandle[] =
+{
+ { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE,
+ 0x101, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoBlockArc =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBlockArcVert), SAL_N_ELEMENTS( mso_sptBlockArcVert ),
+ const_cast<sal_uInt16*>(mso_sptBlockArcSegm), sizeof( mso_sptBlockArcSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBlockArcCalc), SAL_N_ELEMENTS( mso_sptBlockArcCalc ),
+ const_cast<sal_Int32*>(mso_sptBlockArcDefault),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptBlockArcHandle), SAL_N_ELEMENTS( mso_sptBlockArcHandle ) // handles
+};
+
+// aware : control points are always part of the bounding box
+const SvxMSDffVertPair mso_sptHeartVert[] =
+{
+ { 10800, 21599 }, { 321, 6886 }, { 70, 6036 }, // ppp
+ { -9, 5766 }, { -1, 5474 }, { 2, 5192 }, // ccp
+ { 6, 4918 }, { 43, 4641 }, { 101, 4370 }, // ccp
+ { 159, 4103 }, { 245, 3837 }, { 353, 3582 }, // ccp
+ { 460, 3326 }, { 591, 3077 }, { 741, 2839 }, // ccp
+ { 892, 2598 }, { 1066, 2369 }, { 1253, 2155 }, // ccp
+ { 1443, 1938 }, { 1651, 1732 }, { 1874, 1543 }, // ccp
+ { 2097, 1351 }, { 2337, 1174 }, { 2587, 1014 }, // ccp
+ { 2839, 854 }, { 3106, 708 }, { 3380, 584 }, // ccp
+ { 3656, 459 }, { 3945, 350 }, { 4237, 264 }, // ccp
+ { 4533, 176 }, { 4838, 108 }, { 5144, 66 }, // ccp
+ { 5454, 22 }, { 5771, 1 }, { 6086, 3 }, // ccp
+ { 6407, 7 }, { 6731, 35 }, { 7048, 89 }, // ccp
+ { 7374, 144 }, { 7700, 226 }, { 8015, 335 }, // ccp
+ { 8344, 447 }, { 8667, 590 }, { 8972, 756 }, // ccp
+ { 9297, 932 }, { 9613, 1135 }, { 9907, 1363 }, // ccp
+ { 10224, 1609 }, { 10504, 1900 }, { 10802, 2169 }, // ccp
+ { 11697, 1363 }, // p
+ { 11971, 1116 }, { 12304, 934 }, { 12630, 756 }, // ccp
+ { 12935, 590 }, { 13528, 450 }, { 13589, 335 }, // ccp
+ { 13901, 226 }, { 14227, 144 }, { 14556, 89 }, // ccp
+ { 14872, 35 }, { 15195, 7 }, { 15517, 3 }, // ccp
+ { 15830, 0 }, { 16147, 22 }, { 16458, 66 }, // ccp
+ { 16764, 109 }, { 17068, 177 }, { 17365, 264 }, // ccp
+ { 17658, 349 }, { 17946, 458 }, { 18222, 584 }, // ccp
+ { 18496, 708 }, { 18762, 854 }, { 19015, 1014 }, // ccp
+ { 19264, 1172 }, { 19504, 1349 }, { 19730, 1543 }, // ccp
+ { 19950, 1731 }, { 20158, 1937 }, { 20350, 2155 }, // ccp
+ { 20536, 2369 }, { 20710, 2598 }, { 20861, 2839 }, // ccp
+ { 21010, 3074 }, { 21143, 3323 }, { 21251, 3582 }, // ccp
+ { 21357, 3835 }, { 21443, 4099 }, { 21502, 4370 }, // ccp
+ { 21561, 4639 }, { 21595, 4916 }, { 21600, 5192 }, // ccp
+ { 21606, 5474 }, { 21584, 5760 }, { 21532, 6036 }, // ccp
+ { 21478, 6326 }, { 21366, 6603 }, { 21282, 6887 }, // ccp
+ { 10802, 21602 } // p
+};
+const sal_uInt16 mso_sptHeartSegm[] =
+{
+ 0x4000, 0x0002, 0x2010, 0x0001, 0x2010, 0x0001, 0x6001, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptHeartTextRect[] =
+{
+ { { 5080, 2540 }, { 16520, 13550 } }
+};
+const SvxMSDffVertPair mso_sptHeartGluePoints[] =
+{
+ { 10800, 2180 }, { 3090, 10800 }, { 10800, 21600 }, { 18490, 10800 }
+};
+const mso_CustomShape msoHeart =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptHeartVert), SAL_N_ELEMENTS( mso_sptHeartVert ),
+ const_cast<sal_uInt16*>(mso_sptHeartSegm), sizeof( mso_sptHeartSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptHeartTextRect), SAL_N_ELEMENTS( mso_sptHeartTextRect ),
+ 21615, 21602,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptHeartGluePoints), SAL_N_ELEMENTS( mso_sptHeartGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptLightningBoldVert[] =
+{
+ { 8458, 0 }, { 0, 3923 }, { 7564, 8416 }, { 4993, 9720 },
+ { 12197, 13904 }, { 9987, 14934 }, { 21600, 21600 }, { 14768, 12911 },
+ { 16558, 12016 }, { 11030, 6840 }, { 12831, 6120 }, { 8458, 0 }
+};
+const SvxMSDffTextRectangles mso_sptLightningBoldTextRect[] =
+{
+ { { 8680, 7410 }, { 13970, 14190 } }
+};
+const SvxMSDffVertPair mso_sptLightningBoldGluePoints[] =
+{
+ { 8458, 0 }, { 0, 3923 }, { 4993, 9720 }, { 9987, 14934 }, { 21600, 21600 },
+ { 16558, 12016 }, { 12831, 6120 }
+};
+const mso_CustomShape msoLightningBold =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptLightningBoldVert), SAL_N_ELEMENTS( mso_sptLightningBoldVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptLightningBoldTextRect), SAL_N_ELEMENTS( mso_sptLightningBoldTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptLightningBoldGluePoints), SAL_N_ELEMENTS( mso_sptLightningBoldGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptSunVert[] = // adj value 2700 -> 10125
+{
+ { 0, 10800 }, { 4 MSO_I, 8 MSO_I }, { 4 MSO_I, 9 MSO_I },
+ { 0x0a MSO_I, 0x0b MSO_I }, { 0x0c MSO_I, 0x0d MSO_I }, { 0x0e MSO_I, 0x0f MSO_I },
+ { 0x10 MSO_I, 0x11 MSO_I }, { 0x12 MSO_I, 0x13 MSO_I }, { 0x14 MSO_I, 0x15 MSO_I },
+ { 0x16 MSO_I, 0x17 MSO_I }, { 0x18 MSO_I, 0x19 MSO_I }, { 0x1a MSO_I, 0x1b MSO_I },
+ { 0x1c MSO_I, 0x1d MSO_I }, { 0x1e MSO_I, 0x1f MSO_I }, { 0x20 MSO_I, 0x21 MSO_I },
+ { 0x22 MSO_I, 0x23 MSO_I }, { 0x24 MSO_I, 0x25 MSO_I }, { 0x26 MSO_I, 0x27 MSO_I },
+ { 0x28 MSO_I, 0x29 MSO_I }, { 0x2a MSO_I, 0x2b MSO_I }, { 0x2c MSO_I, 0x2d MSO_I },
+ { 0x2e MSO_I, 0x2f MSO_I }, { 0x30 MSO_I, 0x31 MSO_I }, { 0x32 MSO_I, 0x33 MSO_I },
+ { 10800, 10800 }, { 0x36 MSO_I, 0x36 MSO_I }, { 0, 360 }
+};
+const sal_uInt16 mso_sptSunSegm[] =
+{
+ 0x4000, 0x0002, 0x6001, 0x8000,
+ 0x4000, 0x0002, 0x6001, 0x8000,
+ 0x4000, 0x0002, 0x6001, 0x8000,
+ 0x4000, 0x0002, 0x6001, 0x8000,
+ 0x4000, 0x0002, 0x6001, 0x8000,
+ 0x4000, 0x0002, 0x6001, 0x8000,
+ 0x4000, 0x0002, 0x6001, 0x8000,
+ 0x4000, 0x0002, 0x6001, 0x8000,
+ 0xa203, 0x6000, 0x8000
+};
+const SvxMSDffCalculationData mso_sptSunCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x2000, { DFF_Prop_adjustValue, 0, 2700 } },
+ { 0x2001, { 0x402, 5080, 7425 } },
+ { 0x2000, { 0x403, 2540, 0 } },
+ { 0x8000, { 10125, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x405, 2120, 7425 } },
+ { 0x2000, { 0x406, 210, 0 } },
+ { 0x4000, { 10800, 0x407, 0 } }, // y1 (0x8)
+ { 0x8000, { 10800, 0, 0x407 } }, // y2 (0x9)
+ { 0x0081, { 0, 10800, 45 } }, // 0xa
+ { 0x0082, { 0, 10800, 45 } }, // 0xb
+ { 0x6081, { 0x404, 0x408, 45 } }, // 0xc
+ { 0x6082, { 0x404, 0x408, 45 } }, // 0xd
+ { 0x6081, { 0x404, 0x409, 45 } }, // 0xe
+ { 0x6082, { 0x404, 0x409, 45 } }, // 0xf
+ { 0x0081, { 0, 10800, 90 } }, // 0x10
+ { 0x0082, { 0, 10800, 90 } }, // 0x11
+ { 0x6081, { 0x404, 0x408, 90 } }, // 0x12
+ { 0x6082, { 0x404, 0x408, 90 } }, // 0x13
+ { 0x6081, { 0x404, 0x409, 90 } }, // 0x14
+ { 0x6082, { 0x404, 0x409, 90 } }, // 0x15
+ { 0x0081, { 0, 10800, 135 } }, // 0x16
+ { 0x0082, { 0, 10800, 135 } }, // 0x17
+ { 0x6081, { 0x404, 0x408, 135 } }, // 0x18
+ { 0x6082, { 0x404, 0x408, 135 } }, // 0x19
+ { 0x6081, { 0x404, 0x409, 135 } }, // 0x1a
+ { 0x6082, { 0x404, 0x409, 135 } }, // 0x1b
+ { 0x0081, { 0, 10800, 180 } }, // 0x1c
+ { 0x0082, { 0, 10800, 180 } }, // 0x1d
+ { 0x6081, { 0x404, 0x408, 180 } }, // 0x1e
+ { 0x6082, { 0x404, 0x408, 180 } }, // 0x1f
+ { 0x6081, { 0x404, 0x409, 180 } }, // 0x20
+ { 0x6082, { 0x404, 0x409, 180 } }, // 0x21
+ { 0x0081, { 0, 10800, 225 } }, // 0x22
+ { 0x0082, { 0, 10800, 225 } }, // 0x23
+ { 0x6081, { 0x404, 0x408, 225 } }, // 0x24
+ { 0x6082, { 0x404, 0x408, 225 } }, // 0x25
+ { 0x6081, { 0x404, 0x409, 225 } }, // 0x26
+ { 0x6082, { 0x404, 0x409, 225 } }, // 0x27
+ { 0x0081, { 0, 10800, 270 } }, // 0x28
+ { 0x0082, { 0, 10800, 270 } }, // 0x29
+ { 0x6081, { 0x404, 0x408, 270 } }, // 0x2a
+ { 0x6082, { 0x404, 0x408, 270 } }, // 0x2b
+ { 0x6081, { 0x404, 0x409, 270 } }, // 0x2c
+ { 0x6082, { 0x404, 0x409, 270 } }, // 0x2d
+ { 0x0081, { 0, 10800, 315 } }, // 0x2e
+ { 0x0082, { 0, 10800, 315 } }, // 0x2f
+ { 0x6081, { 0x404, 0x408, 315 } }, // 0x30
+ { 0x6082, { 0x404, 0x408, 315 } }, // 0x31
+ { 0x6081, { 0x404, 0x409, 315 } }, // 0x32
+ { 0x6082, { 0x404, 0x409, 315 } }, // 0x33
+ { 0x2081, { DFF_Prop_adjustValue, 10800, 45 } }, // 0x34 ( textbox )
+ { 0x2081, { DFF_Prop_adjustValue, 10800, 225 } }, // 0x35
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } }
+};
+const SvxMSDffTextRectangles mso_sptSunTextRect[] =
+{
+ { { 0x34 MSO_I, 0x34 MSO_I }, { 0x35 MSO_I, 0x35 MSO_I } }
+};
+const SvxMSDffHandle mso_sptSunHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 10800, 10800, 10800, 2700, 10125, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoSun =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptSunVert), SAL_N_ELEMENTS( mso_sptSunVert ),
+ const_cast<sal_uInt16*>(mso_sptSunSegm), sizeof( mso_sptSunSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptSunCalc), SAL_N_ELEMENTS( mso_sptSunCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptSunTextRect), SAL_N_ELEMENTS( mso_sptSunTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptSunHandle), SAL_N_ELEMENTS( mso_sptSunHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptMoonVert[] = // adj value 0 -> 18900
+{
+ { 21600, 0 },
+ { 3 MSO_I, 4 MSO_I }, { 0 MSO_I, 5080 }, { 0 MSO_I, 10800 }, // ccp
+ { 0 MSO_I, 16520 }, { 3 MSO_I, 5 MSO_I }, { 21600, 21600 }, // ccp
+ { 9740, 21600 }, { 0, 16730 }, { 0, 10800 }, // ccp
+ { 0, 4870 }, { 9740, 0 }, { 21600, 0 } // ccp
+};
+const sal_uInt16 mso_sptMoonSegm[] =
+{
+ 0x4000, 0x2004, 0x6000, 0x8000
+};
+const SvxMSDffCalculationData mso_sptMoonCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x401, 1, 2 } },
+ { 0x6000, { 0x402, DFF_Prop_adjustValue, 0 } },
+ { 0x2001, { DFF_Prop_adjustValue, 1794, 10000 } },
+ { 0x8000, { 21600, 0, 0x0404 } },
+ { 0x2001, { DFF_Prop_adjustValue, 400, 18900 } },
+ { 0x8081, { 0, 10800, 0x406 } },
+ { 0x8082, { 0, 10800, 0x406 } },
+ { 0x6000, { 0x407, 0x407, 0 } },
+ { 0x8000, { 21600, 0, 0x408 } }
+};
+const SvxMSDffTextRectangles mso_sptMoonTextRect[] =
+{
+ { { 9 MSO_I, 8 MSO_I }, { 0 MSO_I, 0xa MSO_I } }
+};
+const SvxMSDffVertPair mso_sptMoonGluePoints[] =
+{
+ { 21600, 0 }, { 0, 10800 }, { 21600, 21600 }, { 0 MSO_I, 10800 }
+};
+const SvxMSDffHandle mso_sptMoonHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 10800, 10800, 10800, 0, 18900, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoMoon =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptMoonVert), SAL_N_ELEMENTS( mso_sptMoonVert ),
+ const_cast<sal_uInt16*>(mso_sptMoonSegm), sizeof( mso_sptMoonSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptMoonCalc), SAL_N_ELEMENTS( mso_sptMoonCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault10800),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptMoonTextRect), SAL_N_ELEMENTS( mso_sptMoonTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptMoonGluePoints), SAL_N_ELEMENTS( mso_sptMoonGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptMoonHandle), SAL_N_ELEMENTS( mso_sptMoonHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptBracketPairVert[] = // adj value 0 -> 10800
+{
+ { 0 MSO_I, 0 }, { 0, 1 MSO_I }, // left top alignment
+ { 0, 2 MSO_I }, { 0 MSO_I, 21600 }, // left bottom "
+ { 3 MSO_I, 21600 }, { 21600, 2 MSO_I }, // right bottom "
+ { 21600, 1 MSO_I }, { 3 MSO_I, 0 }, // right top "
+ { 0 MSO_I, 0 }, { 0, 1 MSO_I }, // filling area
+ { 0, 2 MSO_I }, { 0 MSO_I, 21600 },
+ { 3 MSO_I, 21600 }, { 21600, 2 MSO_I },
+ { 21600, 1 MSO_I }, { 3 MSO_I, 0 }
+};
+const sal_uInt16 mso_sptBracketPairSegm[] =
+{
+ 0x4000, 0xa701, 0x0001, 0xa801, 0xaa00, 0x8000,
+ 0x4000, 0xa701, 0x0001, 0xa801, 0xaa00, 0x8000,
+ 0x4000, 0xa701, 0x0001, 0xa801, 0x0001, // filling area
+ 0xa701, 0x0001, 0xa801, 0x6000, 0xab00, 0x8000
+};
+const SvxMSDffCalculationData mso_sptBracketPairCalc[] =
+{
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0x2082, { DFF_Prop_adjustValue, 0, 45 } },
+ { 0x2000, { 0x404, 0, 10800 } },
+ { 0x8000, { 0, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { 0x406, 0, 0x405 } },
+ { 0xa000, { DFF_Prop_geoLeft, 0, 0x407 } },
+ { 0xa000, { DFF_Prop_geoTop, 0, 0x407 } },
+ { 0x6000, { DFF_Prop_geoRight, 0x407, 0 } },
+ { 0x6000, { DFF_Prop_geoBottom, 0x407, 0 } },
+ { 0xa000, { DFF_Prop_geoLeft, 0, 0x405 } },
+ { 0xa000, { DFF_Prop_geoTop, 0, 0x405 } },
+ { 0x6000, { DFF_Prop_geoRight, 0x405, 0 } },
+ { 0x6000, { DFF_Prop_geoBottom, 0x405, 0 } }
+};
+const SvxMSDffTextRectangles mso_sptBracketPairTextRect[] =
+{
+ { { 8 MSO_I, 9 MSO_I }, { 0xa MSO_I, 0xb MSO_I } }
+};
+const SvxMSDffHandle mso_sptBracketPairHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED,
+ 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoBracketPair =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBracketPairVert), SAL_N_ELEMENTS( mso_sptBracketPairVert ),
+ const_cast<sal_uInt16*>(mso_sptBracketPairSegm), sizeof( mso_sptBracketPairSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBracketPairCalc), SAL_N_ELEMENTS( mso_sptBracketPairCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault3700),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptBracketPairTextRect), SAL_N_ELEMENTS( mso_sptBracketPairTextRect ),
+ 21600, 21600,
+ 10800, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptBracketPairHandle), SAL_N_ELEMENTS( mso_sptBracketPairHandle ) // handles
+};
+
+const sal_uInt16 mso_sptPlaqueSegm[] =
+{
+ 0x4000, 0xa801, 0x0001, 0xa701, 0x0001, 0xa801, 0x0001, 0xa701, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptPlaqueTextRect[] =
+{
+ { { 0xc MSO_I, 0xd MSO_I }, { 0xe MSO_I, 0xf MSO_I } }
+};
+const SvxMSDffHandle mso_sptPlaqueHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED,
+ 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoPlaque =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBracketPairVert), SAL_N_ELEMENTS( mso_sptBracketPairVert ),
+ const_cast<sal_uInt16*>(mso_sptPlaqueSegm), sizeof( mso_sptPlaqueSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBracketPairCalc), SAL_N_ELEMENTS( mso_sptBracketPairCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault3600),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptPlaqueTextRect), SAL_N_ELEMENTS( mso_sptPlaqueTextRect ),
+ 21600, 21600,
+ 10800, 10800,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptPlaqueHandle), SAL_N_ELEMENTS( mso_sptPlaqueHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptBracePairVert[] = // adj value 0 -> 5400
+{
+ { 4 MSO_I, 0 }, { 0 MSO_I, 1 MSO_I }, { 0 MSO_I, 6 MSO_I }, { 0 ,10800 }, // left bracket
+ { 0 MSO_I, 7 MSO_I }, { 0 MSO_I, 2 MSO_I }, { 4 MSO_I, 21600 },
+ { 8 MSO_I, 21600 }, { 3 MSO_I, 2 MSO_I }, { 3 MSO_I, 7 MSO_I }, { 21600, 10800 }, // right bracket
+ { 3 MSO_I, 6 MSO_I }, { 3 MSO_I, 1 MSO_I }, { 8 MSO_I, 0 },
+ { 4 MSO_I, 0 }, { 0 MSO_I, 1 MSO_I }, { 0 MSO_I, 6 MSO_I }, { 0 ,10800 }, // filling area
+ { 0 MSO_I, 7 MSO_I }, { 0 MSO_I, 2 MSO_I }, { 4 MSO_I, 21600 },
+ { 8 MSO_I, 21600 }, { 3 MSO_I, 2 MSO_I }, { 3 MSO_I, 7 MSO_I }, { 21600, 10800 },
+ { 3 MSO_I, 6 MSO_I }, { 3 MSO_I, 1 MSO_I }, { 8 MSO_I, 0 }
+};
+const sal_uInt16 mso_sptBracePairSegm[] =
+{
+ 0x4000, 0xa701, 0x0001, 0xa801, 0xa701, 0x0001, 0xa801, 0xaa00, 0x8000,
+ 0x4000, 0xa701, 0x0001, 0xa801, 0xa701, 0x0001, 0xa801, 0xaa00, 0x8000,
+ 0x4000, 0xa701, 0x0001, 0xa801, 0xa701, 0x0001, 0xa801, 0x0001, // filling area
+ 0xa701, 0x0001, 0xa801, 0xa701, 0x0001, 0xa801, 0x6000, 0xab00, 0x8000
+};
+const SvxMSDffCalculationData mso_sptBracePairCalc[] =
+{
+ { 0x6000, { DFF_Prop_geoLeft, DFF_Prop_adjustValue, 0 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { DFF_Prop_geoRight, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x400, 2, 1 } }, // 4
+ { 0x2001, { DFF_Prop_adjustValue, 2, 1 } }, // 5
+ { 0x8000, { 10800, 0, DFF_Prop_adjustValue } }, // 6
+ { 0x8000, { 21600, 0, 0x406 } }, // 7
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x405 } }, // 8
+ { 0x2001, { DFF_Prop_adjustValue, 1, 3 } }, // 9
+ { 0x6000, { 0x409, DFF_Prop_adjustValue, 0 } }, // xa
+ { 0x6000, { DFF_Prop_geoLeft, 0x40a, 0 } }, // xb
+ { 0x6000, { DFF_Prop_geoTop, 0x409, 0 } }, // xc
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x40a } }, // xd
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x409 } } // xe
+};
+const SvxMSDffTextRectangles mso_sptBracePairTextRect[] =
+{
+ { { 0xb MSO_I, 0xc MSO_I }, { 0xd MSO_I, 0xe MSO_I } }
+};
+const SvxMSDffHandle mso_sptBracePairHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::SWITCHED,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 5400 }
+};
+const mso_CustomShape msoBracePair =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBracePairVert), SAL_N_ELEMENTS( mso_sptBracePairVert ),
+ const_cast<sal_uInt16*>(mso_sptBracePairSegm), sizeof( mso_sptBracePairSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBracePairCalc), SAL_N_ELEMENTS( mso_sptBracePairCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1800),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptBracePairTextRect), SAL_N_ELEMENTS( mso_sptBracePairTextRect ),
+ 21600, 21600,
+ 10800, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptBracePairHandle), SAL_N_ELEMENTS( mso_sptBracePairHandle ) // handles
+};
+
+const SvxMSDffCalculationData mso_sptBracketCalc[] =
+{
+ { 0x2001, { DFF_Prop_adjustValue, 1, 2 } },
+ { 0x6000, { DFF_Prop_geoTop, DFF_Prop_adjustValue, 0 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, DFF_Prop_adjustValue } },
+ { 0x6000, { DFF_Prop_geoTop, 0x400, 0 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x400 } }
+};
+const sal_uInt16 mso_sptBracketSegm[] =
+{
+ 0x4000, 0x2001, 0x0001, 0x2001, 0x8000
+};
+const SvxMSDffVertPair mso_sptLeftBracketVert[] = // adj value 0 -> 10800
+{
+ { 21600, 0 }, { 10800, 0 }, { 0, 3 MSO_I }, { 0, 1 MSO_I },
+ { 0, 2 MSO_I }, { 0, 4 MSO_I }, { 10800, 21600 }, { 21600, 21600 }
+};
+const SvxMSDffTextRectangles mso_sptLeftBracketTextRect[] =
+{
+ { { 6350, 3 MSO_I }, { 21600, 4 MSO_I } }
+};
+const SvxMSDffVertPair mso_sptLeftBracketGluePoints[] =
+{
+ { 21600, 0 }, { 0, 10800 }, { 21600, 21600 }
+};
+const SvxMSDffHandle mso_sptLeftBracketHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10800 }
+};
+const mso_CustomShape msoLeftBracket =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptLeftBracketVert), SAL_N_ELEMENTS( mso_sptLeftBracketVert ),
+ const_cast<sal_uInt16*>(mso_sptBracketSegm), sizeof( mso_sptBracketSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBracketCalc), SAL_N_ELEMENTS( mso_sptBracketCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1800),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptLeftBracketTextRect), SAL_N_ELEMENTS( mso_sptLeftBracketTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptLeftBracketGluePoints), SAL_N_ELEMENTS( mso_sptLeftBracketGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptLeftBracketHandle), SAL_N_ELEMENTS( mso_sptLeftBracketHandle ) // handles
+};
+const SvxMSDffVertPair mso_sptRightBracketVert[] = // adj value 0 -> 10800
+{
+ { 0, 0 }, { 10800, 0 }, { 21600, 3 MSO_I }, { 21600, 1 MSO_I },
+ { 21600, 2 MSO_I }, { 21600, 4 MSO_I }, { 10800, 21600 }, { 0, 21600 }
+};
+const SvxMSDffTextRectangles mso_sptRightBracketTextRect[] =
+{
+ { { 0, 3 MSO_I }, { 15150, 4 MSO_I } }
+};
+const SvxMSDffVertPair mso_sptRightBracketGluePoints[] =
+{
+ { 0, 0 }, { 0, 21600 }, { 21600, 10800 }
+};
+const SvxMSDffHandle mso_sptRightBracketHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 1, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10800 }
+};
+const mso_CustomShape msoRightBracket =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptRightBracketVert), SAL_N_ELEMENTS( mso_sptRightBracketVert ),
+ const_cast<sal_uInt16*>(mso_sptBracketSegm), sizeof( mso_sptBracketSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBracketCalc), SAL_N_ELEMENTS( mso_sptBracketCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault1800),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptRightBracketTextRect), SAL_N_ELEMENTS( mso_sptRightBracketTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptRightBracketGluePoints), SAL_N_ELEMENTS( mso_sptRightBracketGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptRightBracketHandle), SAL_N_ELEMENTS( mso_sptRightBracketHandle ) // handles
+};
+
+const SvxMSDffCalculationData mso_sptBraceCalc[] =
+{
+ { 0x2001, { DFF_Prop_adjustValue, 1, 2 } },
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0xa000, { 0x404, 0, DFF_Prop_adjustValue } },
+ { 0xa000, { 0x404, 0, 0x400 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x6000, { 0x404, 0x400, 0 } },
+ { 0x6000, { 0x404, DFF_Prop_adjustValue, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x8000, { 21600, 0, 0x400 } },
+ { 0x2001, { DFF_Prop_adjustValue, 10000, 31953 } },
+ { 0x8000, { 21600, 0, 0x409 } }
+};
+const sal_uInt16 mso_sptBraceSegm[] =
+{
+ 0x4000, 0x2001, 0x0001, 0x2002, 0x0001, 0x2001, 0x8000
+};
+const sal_Int32 mso_sptBraceDefault[] =
+{
+ 2, 1800, 10800
+};
+const SvxMSDffVertPair mso_sptLeftBraceVert[] =
+{
+ { 21600, 0 }, // p
+ { 16200, 0 }, { 10800, 0 MSO_I }, { 10800, 1 MSO_I }, // ccp
+ { 10800, 2 MSO_I }, // p
+ { 10800, 3 MSO_I }, { 5400, 4 MSO_I }, { 0, 4 MSO_I }, // ccp
+ { 5400, 4 MSO_I }, { 10800, 5 MSO_I }, { 10800, 6 MSO_I }, // ccp
+ { 10800, 7 MSO_I }, // p
+ { 10800, 8 MSO_I }, { 16200, 21600 }, { 21600, 21600 } // ccp
+};
+const SvxMSDffTextRectangles mso_sptLeftBraceTextRect[] =
+{
+ { { 13800, 9 MSO_I }, { 21600, 10 MSO_I } }
+};
+const SvxMSDffHandle mso_sptLeftBraceHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 5400 },
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 21600 }
+};
+const mso_CustomShape msoLeftBrace = // adj value0 0 -> 5400
+{ // adj value1 0 -> 21600
+ const_cast<SvxMSDffVertPair*>(mso_sptLeftBraceVert), SAL_N_ELEMENTS( mso_sptLeftBraceVert ),
+ const_cast<sal_uInt16*>(mso_sptBraceSegm), sizeof( mso_sptBraceSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBraceCalc), SAL_N_ELEMENTS( mso_sptBraceCalc ),
+ const_cast<sal_Int32*>(mso_sptBraceDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptLeftBraceTextRect), SAL_N_ELEMENTS( mso_sptLeftBraceTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptLeftBracketGluePoints), SAL_N_ELEMENTS( mso_sptLeftBracketGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptLeftBraceHandle), SAL_N_ELEMENTS( mso_sptLeftBraceHandle ) // handles
+};
+const SvxMSDffVertPair mso_sptRightBraceVert[] =
+{
+ { 0, 0 }, // p
+ { 5400, 0 }, { 10800, 0 MSO_I }, { 10800, 1 MSO_I }, // ccp
+ { 10800, 2 MSO_I }, // p
+ { 10800, 3 MSO_I }, { 16200, 4 MSO_I }, { 21600, 4 MSO_I }, // ccp
+ { 16200, 4 MSO_I }, { 10800, 5 MSO_I }, { 10800, 6 MSO_I }, // ccp
+ { 10800, 7 MSO_I }, // p
+ { 10800, 8 MSO_I }, { 5400, 21600 }, { 0, 21600 } // ccp
+};
+const SvxMSDffTextRectangles mso_sptRightBraceTextRect[] =
+{
+ { { 0, 9 MSO_I }, { 7800, 10 MSO_I } }
+};
+const SvxMSDffHandle mso_sptRightBraceHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 5400 },
+ { SvxMSDffHandleFlags::RANGE,
+ 1, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 21600 }
+};
+const mso_CustomShape msoRightBrace = // adj value0 0 -> 5400
+{ // adj value1 0 -> 21600
+ const_cast<SvxMSDffVertPair*>(mso_sptRightBraceVert), SAL_N_ELEMENTS( mso_sptRightBraceVert ),
+ const_cast<sal_uInt16*>(mso_sptBraceSegm), sizeof( mso_sptBraceSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBraceCalc), SAL_N_ELEMENTS( mso_sptBraceCalc ),
+ const_cast<sal_Int32*>(mso_sptBraceDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptRightBraceTextRect), SAL_N_ELEMENTS( mso_sptRightBraceTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptRightBracketGluePoints), SAL_N_ELEMENTS( mso_sptRightBracketGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptRightBraceHandle), SAL_N_ELEMENTS( mso_sptRightBraceHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptIrregularSeal1Vert[] =
+{
+ { 10901, 5905 }, { 8458, 2399 }, { 7417, 6425 }, { 476, 2399 },
+ { 4732, 7722 }, { 106, 8718 }, { 3828, 11880 }, { 243, 14689 },
+ { 5772, 14041 }, { 4868, 17719 }, { 7819, 15730 }, { 8590, 21600 },
+ { 10637, 15038 }, { 13349, 19840 }, { 14125, 14561 }, { 18248, 18195 },
+ { 16938, 13044 }, { 21600, 13393 }, { 17710, 10579 }, { 21198, 8242 },
+ { 16806, 7417 }, { 18482, 4560 }, { 14257, 5429 }, { 14623, 106 }, { 10901, 5905 }
+};
+const SvxMSDffTextRectangles mso_sptIrregularSeal1TextRect[] =
+{
+ { { 4680, 6570 }, { 16140, 13280 } }
+};
+const SvxMSDffVertPair mso_sptIrregularSeal1GluePoints[] =
+{
+ { 14623, 106 }, { 106, 8718 }, { 8590, 21600 }, { 21600, 13393 }
+};
+const mso_CustomShape msoIrregularSeal1 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptIrregularSeal1Vert), SAL_N_ELEMENTS( mso_sptIrregularSeal1Vert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptIrregularSeal1TextRect), SAL_N_ELEMENTS( mso_sptIrregularSeal1TextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptIrregularSeal1GluePoints), SAL_N_ELEMENTS( mso_sptIrregularSeal1GluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptIrregularSeal2Vert[] =
+{
+ { 11464, 4340 }, { 9722, 1887 }, { 8548, 6383 }, { 4503, 3626 },
+ { 5373, 7816 }, { 1174, 8270 }, { 3934, 11592 }, { 0, 12875 },
+ { 3329, 15372 }, { 1283, 17824 }, { 4804, 18239 }, { 4918, 21600 },
+ { 7525, 18125 }, { 8698, 19712 }, { 9871, 17371 }, { 11614, 18844 },
+ { 12178, 15937 }, { 14943, 17371 }, { 14640, 14348 }, { 18878, 15632 },
+ { 16382, 12311 }, { 18270, 11292 }, { 16986, 9404 }, { 21600, 6646 },
+ { 16382, 6533 }, { 18005, 3172 }, { 14524, 5778 }, { 14789, 0 },
+ { 11464, 4340 }
+};
+const SvxMSDffTextRectangles mso_sptIrregularSeal2TextRect[] =
+{
+ { { 5400, 6570 }, { 14160, 15290 } }
+};
+const SvxMSDffVertPair mso_sptIrregularSeal2GluePoints[] =
+{
+ { 9722, 1887 }, { 0, 12875 }, { 11614, 18844 }, { 21600, 6646 }
+};
+const mso_CustomShape msoIrregularSeal2 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptIrregularSeal2Vert), SAL_N_ELEMENTS( mso_sptIrregularSeal2Vert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptIrregularSeal2TextRect), SAL_N_ELEMENTS( mso_sptIrregularSeal2TextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptIrregularSeal2GluePoints), SAL_N_ELEMENTS( mso_sptIrregularSeal2GluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptSeal4Vert[] = // adjustment1 : 0 - 10800
+{
+ { 0, 10800 }, { 4 MSO_I, 4 MSO_I }, { 10800, 0 }, { 3 MSO_I, 4 MSO_I },
+ { 21600, 10800 }, { 3 MSO_I, 3 MSO_I }, { 10800, 21600 }, { 4 MSO_I, 3 MSO_I },
+ { 0, 10800 }
+};
+const SvxMSDffCalculationData mso_sptSeal4Calc[] =
+{
+ { 0x0000, { 7600, 0, 0 } },
+ { 0x6001, { 0x400, DFF_Prop_adjustValue, 10800 } },
+ { 0xa000, { 0x400, 0, 0x401 } },
+ { 0x4000, { 10800, 0x402, 0 } },
+ { 0x8000, { 10800, 0, 0x402 } }
+};
+const SvxMSDffTextRectangles mso_sptSeal4TextRect[] =
+{
+ { { 4 MSO_I, 4 MSO_I }, { 3 MSO_I, 3 MSO_I } }
+};
+const SvxMSDffHandle mso_sptSealHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 10800, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoSeal4 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptSeal4Vert), SAL_N_ELEMENTS( mso_sptSeal4Vert ),
+ nullptr, 0,
+ const_cast<SvxMSDffCalculationData*>(mso_sptSeal4Calc), SAL_N_ELEMENTS( mso_sptSeal4Calc ),
+ const_cast<sal_Int32*>(mso_sptDefault8100),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptSeal4TextRect), SAL_N_ELEMENTS( mso_sptSeal4TextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptSealHandle), SAL_N_ELEMENTS( mso_sptSealHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptStarVert[] =
+{
+ { 10797, 0 }, { 8278, 8256 }, { 0, 8256 }, { 6722, 13405 },
+ { 4198, 21600 }, { 10797, 16580 }, { 17401, 21600 }, { 14878, 13405 },
+ { 21600, 8256 }, { 13321, 8256 }, { 10797, 0 }
+};
+const SvxMSDffTextRectangles mso_sptStarTextRect[] =
+{
+ { { 6722, 8256 }, { 14878, 15460 } }
+};
+const mso_CustomShape msoStar =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptStarVert), SAL_N_ELEMENTS( mso_sptStarVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptStarTextRect), SAL_N_ELEMENTS( mso_sptStarTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ nullptr, 0 // handles
+};
+
+const SvxMSDffCalculationData mso_sptSeal24Calc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 0x00
+ { 0x2081, { 0x400, 10800, 315 } }, // 0x01 ( textframe )
+ { 0x2082, { 0x400, 10800, 315 } }, // 0x02
+ { 0x2081, { 0x400, 10800, 135 } }, // 0x03
+ { 0x2082, { 0x400, 10800, 135 } }, // 0x04
+ { 0x0081, { 0, 10800, 0 } },
+ { 0x0082, { 0, 10800, 0 } },
+ { 0x2081, { 0x400, 10800, 7 } },
+ { 0x2082, { 0x400, 10800, 7 } },
+ { 0x0081, { 0, 10800, 15 } },
+ { 0x0082, { 0, 10800, 15 } },
+ { 0x2081, { 0x400, 10800, 22 } },
+ { 0x2082, { 0x400, 10800, 22 } },
+ { 0x0081, { 0, 10800, 30 } },
+ { 0x0082, { 0, 10800, 30 } },
+ { 0x2081, { 0x400, 10800, 37 } },
+ { 0x2082, { 0x400, 10800, 37 } },
+ { 0x0081, { 0, 10800, 45 } },
+ { 0x0082, { 0, 10800, 45 } },
+ { 0x2081, { 0x400, 10800, 52 } },
+ { 0x2082, { 0x400, 10800, 52 } },
+ { 0x0081, { 0, 10800, 60 } },
+ { 0x0082, { 0, 10800, 60 } },
+ { 0x2081, { 0x400, 10800, 67 } },
+ { 0x2082, { 0x400, 10800, 67 } },
+ { 0x0081, { 0, 10800, 75 } },
+ { 0x0082, { 0, 10800, 75 } },
+ { 0x2081, { 0x400, 10800, 82 } },
+ { 0x2082, { 0x400, 10800, 82 } },
+ { 0x0081, { 0, 10800, 90 } },
+ { 0x0082, { 0, 10800, 90 } },
+ { 0x2081, { 0x400, 10800, 97 } },
+ { 0x2082, { 0x400, 10800, 97 } },
+ { 0x0081, { 0, 10800, 105 } },
+ { 0x0082, { 0, 10800, 105 } },
+ { 0x2081, { 0x400, 10800, 112 } },
+ { 0x2082, { 0x400, 10800, 112 } },
+ { 0x0081, { 0, 10800, 120 } },
+ { 0x0082, { 0, 10800, 120 } },
+ { 0x2081, { 0x400, 10800, 127 } },
+ { 0x2082, { 0x400, 10800, 127 } },
+ { 0x0081, { 0, 10800, 135 } },
+ { 0x0082, { 0, 10800, 135 } },
+ { 0x2081, { 0x400, 10800, 142 } },
+ { 0x2082, { 0x400, 10800, 142 } },
+ { 0x0081, { 0, 10800, 150 } },
+ { 0x0082, { 0, 10800, 150 } },
+ { 0x2081, { 0x400, 10800, 157 } },
+ { 0x2082, { 0x400, 10800, 157 } },
+ { 0x0081, { 0, 10800, 165 } },
+ { 0x0082, { 0, 10800, 165 } },
+ { 0x2081, { 0x400, 10800, 172 } },
+ { 0x2082, { 0x400, 10800, 172 } },
+ { 0x0081, { 0, 10800, 180 } },
+ { 0x0082, { 0, 10800, 180 } },
+ { 0x2081, { 0x400, 10800, 187 } },
+ { 0x2082, { 0x400, 10800, 187 } },
+ { 0x0081, { 0, 10800, 195 } },
+ { 0x0082, { 0, 10800, 195 } },
+ { 0x2081, { 0x400, 10800, 202 } },
+ { 0x2082, { 0x400, 10800, 202 } },
+ { 0x0081, { 0, 10800, 210 } },
+ { 0x0082, { 0, 10800, 210 } },
+ { 0x2081, { 0x400, 10800, 217 } },
+ { 0x2082, { 0x400, 10800, 217 } },
+ { 0x0081, { 0, 10800, 225 } },
+ { 0x0082, { 0, 10800, 225 } },
+ { 0x2081, { 0x400, 10800, 232 } },
+ { 0x2082, { 0x400, 10800, 232 } },
+ { 0x0081, { 0, 10800, 240 } },
+ { 0x0082, { 0, 10800, 240 } },
+ { 0x2081, { 0x400, 10800, 247 } },
+ { 0x2082, { 0x400, 10800, 247 } },
+ { 0x0081, { 0, 10800, 255 } },
+ { 0x0082, { 0, 10800, 255 } },
+ { 0x2081, { 0x400, 10800, 262 } },
+ { 0x2082, { 0x400, 10800, 262 } },
+ { 0x0081, { 0, 10800, 270 } },
+ { 0x0082, { 0, 10800, 270 } },
+ { 0x2081, { 0x400, 10800, 277 } },
+ { 0x2082, { 0x400, 10800, 277 } },
+ { 0x0081, { 0, 10800, 285 } },
+ { 0x0082, { 0, 10800, 285 } },
+ { 0x2081, { 0x400, 10800, 292 } },
+ { 0x2082, { 0x400, 10800, 292 } },
+ { 0x0081, { 0, 10800, 300 } },
+ { 0x0082, { 0, 10800, 300 } },
+ { 0x2081, { 0x400, 10800, 307 } },
+ { 0x2082, { 0x400, 10800, 307 } },
+ { 0x0081, { 0, 10800, 315 } },
+ { 0x0082, { 0, 10800, 315 } },
+ { 0x2081, { 0x400, 10800, 322 } },
+ { 0x2082, { 0x400, 10800, 322 } },
+ { 0x0081, { 0, 10800, 330 } },
+ { 0x0082, { 0, 10800, 330 } },
+ { 0x2081, { 0x400, 10800, 337 } },
+ { 0x2082, { 0x400, 10800, 337 } },
+ { 0x0081, { 0, 10800, 345 } },
+ { 0x0082, { 0, 10800, 345 } },
+ { 0x2081, { 0x400, 10800, 352 } },
+ { 0x2082, { 0x400, 10800, 352 } }
+};
+const SvxMSDffVertPair mso_sptSeal8Vert[] = // adj value 0 -> 10800
+{
+ { 5 MSO_I, 6 MSO_I }, { 11 MSO_I, 12 MSO_I }, { 17 MSO_I, 18 MSO_I }, { 23 MSO_I, 24 MSO_I },
+ { 29 MSO_I, 30 MSO_I }, { 35 MSO_I, 36 MSO_I }, { 41 MSO_I, 42 MSO_I }, { 47 MSO_I, 48 MSO_I },
+ { 53 MSO_I, 54 MSO_I }, { 59 MSO_I, 60 MSO_I }, { 65 MSO_I, 66 MSO_I }, { 71 MSO_I, 72 MSO_I },
+ { 77 MSO_I, 78 MSO_I }, { 83 MSO_I, 84 MSO_I }, { 89 MSO_I, 90 MSO_I }, { 95 MSO_I, 96 MSO_I },
+ { 5 MSO_I, 6 MSO_I }
+};
+const SvxMSDffTextRectangles mso_sptSealTextRect[] =
+{
+ { { 1 MSO_I, 2 MSO_I }, { 3 MSO_I, 4 MSO_I } }
+};
+const mso_CustomShape msoSeal8 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptSeal8Vert), SAL_N_ELEMENTS( mso_sptSeal8Vert ),
+ nullptr, 0,
+ const_cast<SvxMSDffCalculationData*>(mso_sptSeal24Calc), SAL_N_ELEMENTS( mso_sptSeal24Calc ),
+ const_cast<sal_Int32*>(mso_sptDefault2500),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptSealTextRect), SAL_N_ELEMENTS( mso_sptSealTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptSealHandle), SAL_N_ELEMENTS( mso_sptSealHandle ) // handles
+};
+const SvxMSDffVertPair mso_sptSeal16Vert[] = // adj value 0 -> 10800
+{
+ { 0x05 MSO_I, 0x06 MSO_I }, { 0x07 MSO_I, 0x08 MSO_I }, { 0x09 MSO_I, 0x0a MSO_I }, { 0x0b MSO_I, 0x0c MSO_I },
+ { 0x0d MSO_I, 0x0e MSO_I }, { 0x0f MSO_I, 0x10 MSO_I }, { 0x11 MSO_I, 0x12 MSO_I }, { 0x13 MSO_I, 0x14 MSO_I },
+ { 0x15 MSO_I, 0x16 MSO_I }, { 0x17 MSO_I, 0x18 MSO_I }, { 0x19 MSO_I, 0x1a MSO_I }, { 0x1b MSO_I, 0x1c MSO_I },
+ { 0x1d MSO_I, 0x1e MSO_I }, { 0x1f MSO_I, 0x20 MSO_I }, { 0x21 MSO_I, 0x22 MSO_I }, { 0x23 MSO_I, 0x24 MSO_I },
+ { 0x25 MSO_I, 0x26 MSO_I }, { 0x27 MSO_I, 0x28 MSO_I }, { 0x29 MSO_I, 0x2a MSO_I }, { 0x2b MSO_I, 0x2c MSO_I },
+ { 0x2d MSO_I, 0x2e MSO_I }, { 0x2f MSO_I, 0x30 MSO_I }, { 0x31 MSO_I, 0x32 MSO_I }, { 0x33 MSO_I, 0x34 MSO_I },
+ { 0x35 MSO_I, 0x36 MSO_I }, { 0x37 MSO_I, 0x38 MSO_I }, { 0x39 MSO_I, 0x3a MSO_I }, { 0x3b MSO_I, 0x3c MSO_I },
+ { 0x3d MSO_I, 0x3e MSO_I }, { 0x3f MSO_I, 0x40 MSO_I }, { 0x41 MSO_I, 0x42 MSO_I }, { 0x43 MSO_I, 0x44 MSO_I },
+ { 0x05 MSO_I, 0x06 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptSeal16Calc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 0x00
+ { 0x2081, { 0x400, 10800, 315 } }, // 0x01 ( textframe )
+ { 0x2082, { 0x400, 10800, 315 } }, // 0x02
+ { 0x2081, { 0x400, 10800, 135 } }, // 0x03
+ { 0x2082, { 0x400, 10800, 135 } }, // 0x04
+ { 0x0081, { 0, 10800, 0 } },
+ { 0x0082, { 0, 10800, 0 } },
+ { 0x2081, { 0x400, 10800, 11 } },
+ { 0x2082, { 0x400, 10800, 11 } },
+ { 0x0081, { 0, 10800, 22 } },
+ { 0x0082, { 0, 10800, 22 } },
+ { 0x2081, { 0x400, 10800, 33 } },
+ { 0x2082, { 0x400, 10800, 33 } },
+ { 0x0081, { 0, 10800, 45 } },
+ { 0x0082, { 0, 10800, 45 } },
+ { 0x2081, { 0x400, 10800, 56 } },
+ { 0x2082, { 0x400, 10800, 56 } },
+ { 0x0081, { 0, 10800, 67 } },
+ { 0x0082, { 0, 10800, 67 } },
+ { 0x2081, { 0x400, 10800, 78 } },
+ { 0x2082, { 0x400, 10800, 78 } },
+ { 0x0081, { 0, 10800, 90 } },
+ { 0x0082, { 0, 10800, 90 } },
+ { 0x2081, { 0x400, 10800, 101 } },
+ { 0x2082, { 0x400, 10800, 101 } },
+ { 0x0081, { 0, 10800, 112 } },
+ { 0x0082, { 0, 10800, 112 } },
+ { 0x2081, { 0x400, 10800, 123 } },
+ { 0x2082, { 0x400, 10800, 123 } },
+ { 0x0081, { 0, 10800, 135 } },
+ { 0x0082, { 0, 10800, 135 } },
+ { 0x2081, { 0x400, 10800, 146 } },
+ { 0x2082, { 0x400, 10800, 146 } },
+ { 0x0081, { 0, 10800, 157 } },
+ { 0x0082, { 0, 10800, 157 } },
+ { 0x2081, { 0x400, 10800, 168 } },
+ { 0x2082, { 0x400, 10800, 168 } },
+ { 0x0081, { 0, 10800, 180 } },
+ { 0x0082, { 0, 10800, 180 } },
+ { 0x2081, { 0x400, 10800, 191 } },
+ { 0x2082, { 0x400, 10800, 191 } },
+ { 0x0081, { 0, 10800, 202 } },
+ { 0x0082, { 0, 10800, 202 } },
+ { 0x2081, { 0x400, 10800, 213 } },
+ { 0x2082, { 0x400, 10800, 213 } },
+ { 0x0081, { 0, 10800, 225 } },
+ { 0x0082, { 0, 10800, 225 } },
+ { 0x2081, { 0x400, 10800, 236 } },
+ { 0x2082, { 0x400, 10800, 236 } },
+ { 0x0081, { 0, 10800, 247 } },
+ { 0x0082, { 0, 10800, 247 } },
+ { 0x2081, { 0x400, 10800, 258 } },
+ { 0x2082, { 0x400, 10800, 258 } },
+ { 0x0081, { 0, 10800, 270 } },
+ { 0x0082, { 0, 10800, 270 } },
+ { 0x2081, { 0x400, 10800, 281 } },
+ { 0x2082, { 0x400, 10800, 281 } },
+ { 0x0081, { 0, 10800, 292 } },
+ { 0x0082, { 0, 10800, 292 } },
+ { 0x2081, { 0x400, 10800, 303 } },
+ { 0x2082, { 0x400, 10800, 303 } },
+ { 0x0081, { 0, 10800, 315 } },
+ { 0x0082, { 0, 10800, 315 } },
+ { 0x2081, { 0x400, 10800, 326 } },
+ { 0x2082, { 0x400, 10800, 326 } },
+ { 0x0081, { 0, 10800, 337 } },
+ { 0x0082, { 0, 10800, 337 } },
+ { 0x2081, { 0x400, 10800, 348 } },
+ { 0x2082, { 0x400, 10800, 348 } }
+};
+const mso_CustomShape msoSeal16 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptSeal16Vert), SAL_N_ELEMENTS( mso_sptSeal16Vert ),
+ nullptr, 0,
+ const_cast<SvxMSDffCalculationData*>(mso_sptSeal16Calc), SAL_N_ELEMENTS( mso_sptSeal16Calc ),
+ const_cast<sal_Int32*>(mso_sptDefault2500),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptSealTextRect), SAL_N_ELEMENTS( mso_sptSealTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptSealHandle), SAL_N_ELEMENTS( mso_sptSealHandle ) // handles
+};
+const SvxMSDffVertPair mso_sptSeal24Vert[] =
+{
+ { 0x05 MSO_I, 0x06 MSO_I }, { 0x07 MSO_I, 0x08 MSO_I }, { 0x09 MSO_I, 0x0a MSO_I }, { 0x0b MSO_I, 0x0c MSO_I },
+ { 0x0d MSO_I, 0x0e MSO_I }, { 0x0f MSO_I, 0x10 MSO_I }, { 0x11 MSO_I, 0x12 MSO_I }, { 0x13 MSO_I, 0x14 MSO_I },
+ { 0x15 MSO_I, 0x16 MSO_I }, { 0x17 MSO_I, 0x18 MSO_I }, { 0x19 MSO_I, 0x1a MSO_I }, { 0x1b MSO_I, 0x1c MSO_I },
+ { 0x1d MSO_I, 0x1e MSO_I }, { 0x1f MSO_I, 0x20 MSO_I }, { 0x21 MSO_I, 0x22 MSO_I }, { 0x23 MSO_I, 0x24 MSO_I },
+ { 0x25 MSO_I, 0x26 MSO_I }, { 0x27 MSO_I, 0x28 MSO_I }, { 0x29 MSO_I, 0x2a MSO_I }, { 0x2b MSO_I, 0x2c MSO_I },
+ { 0x2d MSO_I, 0x2e MSO_I }, { 0x2f MSO_I, 0x30 MSO_I }, { 0x31 MSO_I, 0x32 MSO_I }, { 0x33 MSO_I, 0x34 MSO_I },
+ { 0x35 MSO_I, 0x36 MSO_I }, { 0x37 MSO_I, 0x38 MSO_I }, { 0x39 MSO_I, 0x3a MSO_I }, { 0x3b MSO_I, 0x3c MSO_I },
+ { 0x3d MSO_I, 0x3e MSO_I }, { 0x3f MSO_I, 0x40 MSO_I }, { 0x41 MSO_I, 0x42 MSO_I }, { 0x43 MSO_I, 0x44 MSO_I },
+ { 0x45 MSO_I, 0x46 MSO_I }, { 0x47 MSO_I, 0x48 MSO_I }, { 0x49 MSO_I, 0x4a MSO_I }, { 0x4b MSO_I, 0x4c MSO_I },
+ { 0x4d MSO_I, 0x4e MSO_I }, { 0x4f MSO_I, 0x50 MSO_I }, { 0x51 MSO_I, 0x52 MSO_I }, { 0x53 MSO_I, 0x54 MSO_I },
+ { 0x55 MSO_I, 0x56 MSO_I }, { 0x57 MSO_I, 0x58 MSO_I }, { 0x59 MSO_I, 0x5a MSO_I }, { 0x5b MSO_I, 0x5c MSO_I },
+ { 0x5d MSO_I, 0x5e MSO_I }, { 0x5f MSO_I, 0x60 MSO_I }, { 0x61 MSO_I, 0x62 MSO_I }, { 0x63 MSO_I, 0x64 MSO_I },
+ { 0x05 MSO_I, 0x06 MSO_I }
+};
+const mso_CustomShape msoSeal24 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptSeal24Vert), SAL_N_ELEMENTS( mso_sptSeal24Vert ),
+ nullptr, 0,
+ const_cast<SvxMSDffCalculationData*>(mso_sptSeal24Calc), SAL_N_ELEMENTS( mso_sptSeal24Calc ),
+ const_cast<sal_Int32*>(mso_sptDefault2500),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptSealTextRect), SAL_N_ELEMENTS( mso_sptSealTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptSealHandle), SAL_N_ELEMENTS( mso_sptSealHandle ) // handles
+};
+const SvxMSDffCalculationData mso_sptSeal32Calc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 0x00
+ { 0x2081, { 0x400, 10800, 315 } }, // 0x01 ( textframe )
+ { 0x2082, { 0x400, 10800, 315 } }, // 0x02
+ { 0x2081, { 0x400, 10800, 135 } }, // 0x03
+ { 0x2082, { 0x400, 10800, 135 } }, // 0x04
+ { 0x0081, { 0, 10800, 0 } },
+ { 0x0082, { 0, 10800, 0 } },
+ { 0x2081, { 0x400, 10800, 5 } },
+ { 0x2082, { 0x400, 10800, 5 } },
+ { 0x0081, { 0, 10800, 11 } },
+ { 0x0082, { 0, 10800, 11 } },
+ { 0x2081, { 0x400, 10800, 16 } },
+ { 0x2082, { 0x400, 10800, 16 } },
+ { 0x0081, { 0, 10800, 22 } },
+ { 0x0082, { 0, 10800, 22 } },
+ { 0x2081, { 0x400, 10800, 28 } },
+ { 0x2082, { 0x400, 10800, 28 } },
+ { 0x0081, { 0, 10800, 33 } },
+ { 0x0082, { 0, 10800, 33 } },
+ { 0x2081, { 0x400, 10800, 39 } },
+ { 0x2082, { 0x400, 10800, 39 } },
+ { 0x0081, { 0, 10800, 45 } },
+ { 0x0082, { 0, 10800, 45 } },
+ { 0x2081, { 0x400, 10800, 50 } },
+ { 0x2082, { 0x400, 10800, 50 } },
+ { 0x0081, { 0, 10800, 56 } },
+ { 0x0082, { 0, 10800, 56 } },
+ { 0x2081, { 0x400, 10800, 61 } },
+ { 0x2082, { 0x400, 10800, 61 } },
+ { 0x0081, { 0, 10800, 67 } },
+ { 0x0082, { 0, 10800, 67 } },
+ { 0x2081, { 0x400, 10800, 73 } },
+ { 0x2082, { 0x400, 10800, 73 } },
+ { 0x0081, { 0, 10800, 78 } },
+ { 0x0082, { 0, 10800, 78 } },
+ { 0x2081, { 0x400, 10800, 84 } },
+ { 0x2082, { 0x400, 10800, 84 } },
+ { 0x0081, { 0, 10800, 90 } },
+ { 0x0082, { 0, 10800, 90 } },
+ { 0x2081, { 0x400, 10800, 95 } },
+ { 0x2082, { 0x400, 10800, 95 } },
+ { 0x0081, { 0, 10800, 101 } },
+ { 0x0082, { 0, 10800, 101 } },
+ { 0x2081, { 0x400, 10800, 106 } },
+ { 0x2082, { 0x400, 10800, 106 } },
+ { 0x0081, { 0, 10800, 112 } },
+ { 0x0082, { 0, 10800, 112 } },
+ { 0x2081, { 0x400, 10800, 118 } },
+ { 0x2082, { 0x400, 10800, 118 } },
+ { 0x0081, { 0, 10800, 123 } },
+ { 0x0082, { 0, 10800, 123 } },
+ { 0x2081, { 0x400, 10800, 129 } },
+ { 0x2082, { 0x400, 10800, 129 } },
+ { 0x0081, { 0, 10800, 135 } },
+ { 0x0082, { 0, 10800, 135 } },
+ { 0x2081, { 0x400, 10800, 140 } },
+ { 0x2082, { 0x400, 10800, 140 } },
+ { 0x0081, { 0, 10800, 146 } },
+ { 0x0082, { 0, 10800, 146 } },
+ { 0x2081, { 0x400, 10800, 151 } },
+ { 0x2082, { 0x400, 10800, 151 } },
+ { 0x0081, { 0, 10800, 157 } },
+ { 0x0082, { 0, 10800, 157 } },
+ { 0x2081, { 0x400, 10800, 163 } },
+ { 0x2082, { 0x400, 10800, 163 } },
+ { 0x0081, { 0, 10800, 168 } },
+ { 0x0082, { 0, 10800, 168 } },
+ { 0x2081, { 0x400, 10800, 174 } },
+ { 0x2082, { 0x400, 10800, 174 } },
+ { 0x0081, { 0, 10800, 180 } },
+ { 0x0082, { 0, 10800, 180 } },
+ { 0x2081, { 0x400, 10800, 185 } },
+ { 0x2082, { 0x400, 10800, 185 } },
+ { 0x0081, { 0, 10800, 191 } },
+ { 0x0082, { 0, 10800, 191 } },
+ { 0x2081, { 0x400, 10800, 196 } },
+ { 0x2082, { 0x400, 10800, 196 } },
+ { 0x0081, { 0, 10800, 202 } },
+ { 0x0082, { 0, 10800, 202 } },
+ { 0x2081, { 0x400, 10800, 208 } },
+ { 0x2082, { 0x400, 10800, 208 } },
+ { 0x0081, { 0, 10800, 213 } },
+ { 0x0082, { 0, 10800, 213 } },
+ { 0x2081, { 0x400, 10800, 219 } },
+ { 0x2082, { 0x400, 10800, 219 } },
+ { 0x0081, { 0, 10800, 225 } },
+ { 0x0082, { 0, 10800, 225 } },
+ { 0x2081, { 0x400, 10800, 230 } },
+ { 0x2082, { 0x400, 10800, 230 } },
+ { 0x0081, { 0, 10800, 236 } },
+ { 0x0082, { 0, 10800, 236 } },
+ { 0x2081, { 0x400, 10800, 241 } },
+ { 0x2082, { 0x400, 10800, 241 } },
+ { 0x0081, { 0, 10800, 247 } },
+ { 0x0082, { 0, 10800, 247 } },
+ { 0x2081, { 0x400, 10800, 253 } },
+ { 0x2082, { 0x400, 10800, 253 } },
+ { 0x0081, { 0, 10800, 258 } },
+ { 0x0082, { 0, 10800, 258 } },
+ { 0x2081, { 0x400, 10800, 264 } },
+ { 0x2082, { 0x400, 10800, 264 } },
+ { 0x0081, { 0, 10800, 270 } },
+ { 0x0082, { 0, 10800, 270 } },
+ { 0x2081, { 0x400, 10800, 275 } },
+ { 0x2082, { 0x400, 10800, 275 } },
+ { 0x0081, { 0, 10800, 281 } },
+ { 0x0082, { 0, 10800, 281 } },
+ { 0x2081, { 0x400, 10800, 286 } },
+ { 0x2082, { 0x400, 10800, 286 } },
+ { 0x0081, { 0, 10800, 292 } },
+ { 0x0082, { 0, 10800, 292 } },
+ { 0x2081, { 0x400, 10800, 298 } },
+ { 0x2082, { 0x400, 10800, 298 } },
+ { 0x0081, { 0, 10800, 303 } },
+ { 0x0082, { 0, 10800, 303 } },
+ { 0x2081, { 0x400, 10800, 309 } },
+ { 0x2082, { 0x400, 10800, 309 } },
+ { 0x0081, { 0, 10800, 315 } },
+ { 0x0082, { 0, 10800, 315 } },
+ { 0x2081, { 0x400, 10800, 320 } },
+ { 0x2082, { 0x400, 10800, 320 } },
+ { 0x0081, { 0, 10800, 326 } },
+ { 0x0082, { 0, 10800, 326 } },
+ { 0x2081, { 0x400, 10800, 331 } },
+ { 0x2082, { 0x400, 10800, 331 } },
+ { 0x0081, { 0, 10800, 337 } },
+ { 0x0082, { 0, 10800, 337 } },
+ { 0x2081, { 0x400, 10800, 343 } },
+ { 0x2082, { 0x400, 10800, 343 } },
+ { 0x0081, { 0, 10800, 348 } },
+ { 0x0082, { 0, 10800, 348 } },
+ { 0x2081, { 0x400, 10800, 354 } },
+ { 0x2082, { 0x400, 10800, 354 } }
+};
+const SvxMSDffVertPair mso_sptSeal32Vert[] =
+{
+ { 0x05 MSO_I, 0x06 MSO_I }, { 0x07 MSO_I, 0x08 MSO_I }, { 0x09 MSO_I, 0x0a MSO_I }, { 0x0b MSO_I, 0x0c MSO_I },
+ { 0x0d MSO_I, 0x0e MSO_I }, { 0x0f MSO_I, 0x10 MSO_I }, { 0x11 MSO_I, 0x12 MSO_I }, { 0x13 MSO_I, 0x14 MSO_I },
+ { 0x15 MSO_I, 0x16 MSO_I }, { 0x17 MSO_I, 0x18 MSO_I }, { 0x19 MSO_I, 0x1a MSO_I }, { 0x1b MSO_I, 0x1c MSO_I },
+ { 0x1d MSO_I, 0x1e MSO_I }, { 0x1f MSO_I, 0x20 MSO_I }, { 0x21 MSO_I, 0x22 MSO_I }, { 0x23 MSO_I, 0x24 MSO_I },
+ { 0x25 MSO_I, 0x26 MSO_I }, { 0x27 MSO_I, 0x28 MSO_I }, { 0x29 MSO_I, 0x2a MSO_I }, { 0x2b MSO_I, 0x2c MSO_I },
+ { 0x2d MSO_I, 0x2e MSO_I }, { 0x2f MSO_I, 0x30 MSO_I }, { 0x31 MSO_I, 0x32 MSO_I }, { 0x33 MSO_I, 0x34 MSO_I },
+ { 0x35 MSO_I, 0x36 MSO_I }, { 0x37 MSO_I, 0x38 MSO_I }, { 0x39 MSO_I, 0x3a MSO_I }, { 0x3b MSO_I, 0x3c MSO_I },
+ { 0x3d MSO_I, 0x3e MSO_I }, { 0x3f MSO_I, 0x40 MSO_I }, { 0x41 MSO_I, 0x42 MSO_I }, { 0x43 MSO_I, 0x44 MSO_I },
+ { 0x45 MSO_I, 0x46 MSO_I }, { 0x47 MSO_I, 0x48 MSO_I }, { 0x49 MSO_I, 0x4a MSO_I }, { 0x4b MSO_I, 0x4c MSO_I },
+ { 0x4d MSO_I, 0x4e MSO_I }, { 0x4f MSO_I, 0x50 MSO_I }, { 0x51 MSO_I, 0x52 MSO_I }, { 0x53 MSO_I, 0x54 MSO_I },
+ { 0x55 MSO_I, 0x56 MSO_I }, { 0x57 MSO_I, 0x58 MSO_I }, { 0x59 MSO_I, 0x5a MSO_I }, { 0x5b MSO_I, 0x5c MSO_I },
+ { 0x5d MSO_I, 0x5e MSO_I }, { 0x5f MSO_I, 0x60 MSO_I }, { 0x61 MSO_I, 0x62 MSO_I }, { 0x63 MSO_I, 0x64 MSO_I },
+ { 0x65 MSO_I, 0x66 MSO_I }, { 0x67 MSO_I, 0x68 MSO_I }, { 0x69 MSO_I, 0x6a MSO_I }, { 0x6b MSO_I, 0x6c MSO_I },
+ { 0x6d MSO_I, 0x6e MSO_I }, { 0x6f MSO_I, 0x70 MSO_I }, { 0x71 MSO_I, 0x72 MSO_I }, { 0x73 MSO_I, 0x74 MSO_I },
+ { 0x75 MSO_I, 0x76 MSO_I }, { 0x77 MSO_I, 0x78 MSO_I }, { 0x79 MSO_I, 0x7a MSO_I }, { 0x7b MSO_I, 0x7c MSO_I },
+ { 0x7d MSO_I, 0x7e MSO_I }, { 0x7f MSO_I, 0x80 MSO_I }, { 0x81 MSO_I, 0x82 MSO_I }, { 0x83 MSO_I, 0x84 MSO_I },
+ { 0x05 MSO_I, 0x06 MSO_I }
+};
+const mso_CustomShape msoSeal32 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptSeal32Vert), SAL_N_ELEMENTS( mso_sptSeal32Vert ),
+ nullptr, 0,
+ const_cast<SvxMSDffCalculationData*>(mso_sptSeal32Calc), SAL_N_ELEMENTS( mso_sptSeal32Calc ),
+ const_cast<sal_Int32*>(mso_sptDefault2500),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptSealTextRect), SAL_N_ELEMENTS( mso_sptSealTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptSealHandle), SAL_N_ELEMENTS( mso_sptSealHandle )
+};
+
+const SvxMSDffVertPair mso_sptRibbon2Vert[] = // adjustment1 : x 2700 - 8100 def 5400
+{ // adjustment2 : y 14400 - 21600 def 18900
+ { 12 MSO_I, 1 MSO_I }, { 12 MSO_I, 13 MSO_I }, // pp
+ { 12 MSO_I, 14 MSO_I }, { 15 MSO_I, 21600 }, { 16 MSO_I, 21600 }, // ccp
+ { 0, 21600 }, { 2750, 7 MSO_I }, { 0, 2 MSO_I }, { 0 MSO_I, 2 MSO_I }, // pppp
+ { 0 MSO_I, 4 MSO_I }, // p
+ { 0 MSO_I, 5 MSO_I }, { 10 MSO_I, 0 }, { 11 MSO_I, 0 }, // ccp
+ { 17 MSO_I, 0 }, // p
+ { 18 MSO_I, 0 }, { 19 MSO_I, 5 MSO_I }, { 19 MSO_I, 4 MSO_I }, // ccp
+ { 19 MSO_I, 2 MSO_I }, { 21600, 2 MSO_I }, { 18850, 7 MSO_I }, { 21600, 21600 }, // pppp
+ { 20 MSO_I, 21600 }, // p
+ { 21 MSO_I, 21600 }, { 22 MSO_I, 14 MSO_I }, { 22 MSO_I, 13 MSO_I }, // ccp
+ { 22 MSO_I, 1 MSO_I }, { 12 MSO_I, 1 MSO_I }, { 12 MSO_I, 13 MSO_I }, // ppp
+ { 12 MSO_I, 23 MSO_I }, { 15 MSO_I, 24 MSO_I }, { 16 MSO_I, 24 MSO_I }, // ccp
+ { 11 MSO_I, 24 MSO_I }, // p
+ { 10 MSO_I, 24 MSO_I }, { 0 MSO_I, 26 MSO_I }, { 0 MSO_I, 25 MSO_I }, // ccp
+ { 0 MSO_I, 27 MSO_I }, { 10 MSO_I, 1 MSO_I }, { 11 MSO_I, 1 MSO_I }, // ccp
+
+ { 22 MSO_I, 1 MSO_I }, { 22 MSO_I, 13 MSO_I }, // pp
+ { 22 MSO_I, 23 MSO_I }, { 21 MSO_I, 24 MSO_I }, { 20 MSO_I, 24 MSO_I }, // ccp
+ { 17 MSO_I, 24 MSO_I }, // p
+ { 18 MSO_I, 24 MSO_I }, { 19 MSO_I, 26 MSO_I }, { 19 MSO_I, 25 MSO_I }, // ccp
+ { 19 MSO_I, 27 MSO_I }, { 18 MSO_I, 1 MSO_I }, { 17 MSO_I, 1 MSO_I }, // ccp
+
+ { 0 MSO_I, 25 MSO_I }, { 0 MSO_I, 2 MSO_I }, // pp
+
+ { 19 MSO_I, 25 MSO_I }, { 19 MSO_I, 2 MSO_I } // pp
+};
+const sal_uInt16 mso_sptRibbon2Segm[] =
+{
+ 0x4000, 0x0001, 0x2001, 0x0005, 0x2001, 0x0001, 0x2001, 0x0005, 0x2001, 0x0001, 0x6001, 0x8000,
+ 0x4000, 0x0001, 0x2001, 0x0001, 0x2002, 0x6001, 0x8000,
+ 0x4000, 0x0001, 0x2001, 0x0001, 0x2002, 0x6001, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptRibbon2Calc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 00
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } }, // 01
+ { 0x8000, { 21600, 0, 0x401 } }, // 02
+ { 0x2001, { 0x402, 1, 2 } }, // 03
+ { 0x2001, { 0x403, 1, 2 } }, // 04
+ { 0x2001, { 0x404, 1, 2 } }, // 05
+ { 0x2001, { 0x401, 1, 2 } }, // 06
+ { 0x8000, { 21600, 0, 0x406 } }, // 07
+ { 0x0000, { 420, 0, 0 } }, // 08
+ { 0x2001, { 0x408, 2, 1 } }, // 09
+ { 0x6000, { 0x400, 0x408, 0 } }, // 10
+ { 0x6000, { 0x400, 0x409, 0 } }, // 11
+ { 0x2000, { 0x400, 2700, 0 } }, // 12
+ { 0x8000, { 21600, 0, 0x404 } }, // 13
+ { 0x8000, { 21600, 0, 0x405 } }, // 14
+ { 0xa000, { 0x40c, 0, 0x408 } }, // 15
+ { 0xa000, { 0x40c, 0, 0x409 } }, // 16
+
+ { 0x8000, { 21600, 0, 0x40b } }, // 17
+ { 0x8000, { 21600, 0, 0x40a } }, // 18
+ { 0x8000, { 21600, 0, 0x400 } }, // 19
+ { 0x8000, { 21600, 0, 0x410 } }, // 20
+ { 0x8000, { 21600, 0, 0x40f } }, // 21
+ { 0x8000, { 21600, 0, 0x40c } }, // 22
+
+ { 0xa000, { 0x40d, 0, 0x405 } }, // 23
+ { 0x6000, { 0x401, 0x403, 0 } }, // 24
+ { 0x6000, { 0x401, 0x404, 0 } }, // 25
+ { 0x6000, { 0x419, 0x405, 0 } }, // 26
+ { 0xa000, { 0x419, 0, 0x405 } } // 27
+};
+const sal_Int32 mso_sptRibbon2Default[] =
+{
+ 2, 5400, 18900
+};
+const SvxMSDffTextRectangles mso_sptRibbon2TextRect[] =
+{
+ { { 0 MSO_I, 0 }, { 19 MSO_I, 1 MSO_I } }
+};
+const SvxMSDffHandle mso_sptRibbon2Handle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0, 10800, 10800, 2700, 8100, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, 14400, 21600 }
+};
+const mso_CustomShape msoRibbon2 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptRibbon2Vert), SAL_N_ELEMENTS( mso_sptRibbon2Vert ),
+ const_cast<sal_uInt16*>(mso_sptRibbon2Segm), sizeof( mso_sptRibbon2Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptRibbon2Calc), SAL_N_ELEMENTS( mso_sptRibbon2Calc ),
+ const_cast<sal_Int32*>(mso_sptRibbon2Default),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptRibbon2TextRect), SAL_N_ELEMENTS( mso_sptRibbon2TextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptRibbon2Handle), SAL_N_ELEMENTS( mso_sptRibbon2Handle )
+};
+
+const SvxMSDffVertPair mso_sptRibbonVert[] =
+{
+ { 0, 0 }, { 3 MSO_I, 0 },
+ { 4 MSO_I, 11 MSO_I }, { 4 MSO_I, 10 MSO_I }, { 5 MSO_I, 10 MSO_I }, { 5 MSO_I, 11 MSO_I },
+ { 6 MSO_I, 0 }, { 21600, 0 }, { 18 MSO_I, 14 MSO_I }, { 21600, 15 MSO_I }, { 9 MSO_I, 15 MSO_I }, { 9 MSO_I, 16 MSO_I }, { 8 MSO_I, 21600 }, { 1 MSO_I, 21600 },
+ { 0 MSO_I, 16 MSO_I }, { 0 MSO_I, 15 MSO_I }, { 0, 15 MSO_I }, { 2700, 14 MSO_I },
+
+ { 4 MSO_I, 11 MSO_I },
+ { 3 MSO_I, 12 MSO_I }, { 1 MSO_I, 12 MSO_I },
+ { 0 MSO_I, 13 MSO_I }, { 1 MSO_I, 10 MSO_I }, { 4 MSO_I, 10 MSO_I },
+ { 5 MSO_I, 11 MSO_I },
+ { 6 MSO_I, 12 MSO_I }, { 8 MSO_I, 12 MSO_I },
+ { 9 MSO_I, 13 MSO_I }, { 8 MSO_I, 10 MSO_I }, { 5 MSO_I, 10 MSO_I },
+ { 0 MSO_I, 13 MSO_I },
+ { 0 MSO_I, 15 MSO_I },
+ { 9 MSO_I, 13 MSO_I },
+ { 9 MSO_I, 15 MSO_I }
+};
+const sal_uInt16 mso_sptRibbonSegm[] =
+{
+ 0x4000, 0x0001, 0xa701, 0x0003, 0xa801, 0x0005, 0xa801, 0x0001, 0xa701, 0x0003, 0x6000, 0x8000,
+ 0x4000, 0xaa00, 0xa801, 0x0001, 0xa702, 0x0001, 0x8000,
+ 0x4000, 0xaa00, 0xa801, 0x0001, 0xa702, 0x0001, 0x8000,
+ 0x4000, 0xaa00, 0x0001, 0x8000,
+ 0x4000, 0xaa00, 0x0001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptRibbonCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 00
+ { 0x2000, { 0x400, 675, 0 } }, // 01
+ { 0x2000, { 0x401, 675, 0 } }, // 02
+ { 0x2000, { 0x402, 675, 0 } }, // 03
+ { 0x2000, { 0x403, 675, 0 } }, // 04
+ { 0x8000, { 21600, 0, 0x404 } }, // 05
+ { 0x8000, { 21600, 0, 0x403 } }, // 06
+ { 0x8000, { 21600, 0, 0x402 } }, // 07
+ { 0x8000, { 21600, 0, 0x401 } }, // 08
+ { 0x8000, { 21600, 0, 0x400 } }, // 09
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } }, // 10
+ { 0x2001, { 0x40a, 1, 4 } }, // 11
+ { 0x2001, { 0x40b, 2, 1 } }, // 12
+ { 0x2001, { 0x40b, 3, 1 } }, // 13
+ { 0x8000, { 10800, 0, 0x40c } }, // 14
+ { 0x8000, { 21600, 0, 0x40a } }, // 15
+ { 0x8000, { 21600, 0, 0x40b } }, // 16
+ { 0x0001, { 21600, 1, 2 } }, // 17
+ { 0x0000, { 21600, 0, 2700 } }, // 18
+ { 0x2000, { 0x411, 0, 2700 } } // 19
+};
+const sal_Int32 mso_sptRibbonDefault[] =
+{
+ 2, 5400, 2700
+};
+const SvxMSDffTextRectangles mso_sptRibbonTextRect[] =
+{
+ { { 0 MSO_I, 10 MSO_I }, { 9 MSO_I, 21600 } }
+};
+const SvxMSDffVertPair mso_sptRibbonGluePoints[] =
+{
+ { 17 MSO_I, 10 MSO_I }, { 2700, 14 MSO_I }, { 17 MSO_I, 21600 }, { 18 MSO_I, 14 MSO_I }
+};
+const SvxMSDffHandle mso_sptRibbonHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0, 10800, 10800, 2700, 8100, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 7200 }
+};
+const mso_CustomShape msoRibbon =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptRibbonVert), SAL_N_ELEMENTS( mso_sptRibbonVert ),
+ const_cast<sal_uInt16*>(mso_sptRibbonSegm), sizeof( mso_sptRibbonSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptRibbonCalc), SAL_N_ELEMENTS( mso_sptRibbonCalc ),
+ const_cast<sal_Int32*>(mso_sptRibbonDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptRibbonTextRect), SAL_N_ELEMENTS( mso_sptRibbonTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptRibbonGluePoints), SAL_N_ELEMENTS( mso_sptRibbonGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptRibbonHandle), SAL_N_ELEMENTS( mso_sptRibbonHandle )
+};
+//msosptEllipseRibbon
+//svg path = ar@9@38@8@37,0@27@0@26@9@13@8@4@0@25@22@25@9@38@8@37@22@26@3@27l@7@40@3,wa@9@35@8@10@3,0@21@33@9@36@8@1@21@31@20@31@9@35@8@10@20@33,,l@5@40xewr@9@36@8@1@20@31@0@32nfl@20@33ear@9@36@8@1@21@31@22@32nfl@21@33em@0@26nfl@0@32em@22@26nfl@22@32e
+//odp path = A ?f9 ?f38 ?f8 ?f37 0 ?f27 ?f0 ?f26 ?f9 ?f13 ?f8 ?f4 ?f0 ?f25 ?f22 ?f25 ?f9 ?f38 ?f8 ?f37 ?f22 ?f26 ?f3 ?f27 L ?f7 ?f40 ?f3 0 W ?f9 ?f35 ?f8 ?f10 ?f3 0 ?f21 ?f33 ?f9 ?f36 ?f8 ?f1 ?f21 ?f31 ?f20 ?f31 ?f9 ?f35 ?f8 ?f10 ?f20 ?f33 0 0 L ?f5 ?f40 Z N W ?f9 ?f36 ?f8 ?f1 ?f20 ?f31 ?f0 ?f32 F L ?f20 ?f33 N A ?f9 ?f36 ?f8 ?f1 ?f21 ?f31 ?f22 ?f32 F L ?f21 ?f33 N M ?f0 ?f26 F L ?f0 ?f32 N M ?f22 ?f26 F L ?f22 ?f32 N
+const SvxMSDffVertPair mso_sptEllipseRibbonVert[] =
+{
+ { 9 MSO_I , 38 MSO_I },
+ { 8 MSO_I , 37 MSO_I },
+ { 0 , 27 MSO_I },
+ { 0 MSO_I , 26 MSO_I },
+ { 9 MSO_I , 13 MSO_I },
+ { 8 MSO_I , 4 MSO_I },
+ { 0 MSO_I , 25 MSO_I },
+ { 22 MSO_I , 25 MSO_I },
+ { 9 MSO_I , 38 MSO_I },
+ { 8 MSO_I , 37 MSO_I },
+ { 22 MSO_I , 26 MSO_I },
+ { 3 MSO_I , 27 MSO_I },
+ { 7 MSO_I , 40 MSO_I },
+ { 3 MSO_I , 0 },
+ { 9 MSO_I , 35 MSO_I },
+ { 8 MSO_I , 10 MSO_I },
+ { 3 MSO_I , 0 },
+ { 21 MSO_I , 33 MSO_I },
+ { 9 MSO_I , 36 MSO_I },
+ { 8 MSO_I , 1 MSO_I },
+ { 21 MSO_I , 31 MSO_I },
+ { 20 MSO_I , 31 MSO_I },
+ { 9 MSO_I , 35 MSO_I },
+ { 8 MSO_I , 10 MSO_I },
+ { 20 MSO_I , 33 MSO_I },
+ { 0 , 0 },
+ { 5 MSO_I , 40 MSO_I },
+ { 9 MSO_I , 36 MSO_I },
+ { 8 MSO_I , 1 MSO_I },
+ { 20 MSO_I , 31 MSO_I },
+ { 0 MSO_I , 32 MSO_I },
+ { 20 MSO_I , 33 MSO_I },
+ { 9 MSO_I , 36 MSO_I },
+ { 8 MSO_I , 1 MSO_I },
+ { 21 MSO_I , 31 MSO_I },
+ { 22 MSO_I , 32 MSO_I },
+ { 21 MSO_I , 33 MSO_I },
+ { 0 MSO_I , 26 MSO_I },
+ { 0 MSO_I , 32 MSO_I },
+ { 22 MSO_I , 26 MSO_I },
+ { 22 MSO_I , 32 MSO_I }
+};
+
+const sal_uInt16 mso_sptEllipseRibbonSegm[] =
+{
+ 0xa30c /*ar*/,0x0002/*l*/,0xa50c/*wa*/,0x0001/*l*/,
+ 0x6001/*x*/, 0x8000/*e*/,0xa504/*wr*/,0xaa00/*nf*/,
+ 0x0001/*l*/, 0x8000/*e*/,0xa304/*ar*/,0xaa00/*nf*/,
+ 0x0001/*l*/, 0x8000/*e*/,0x4000/*m*/,0xaa00/*nf*/,
+ 0x0001/*l*/, 0x8000/*e*/,0x4000/*m*/,0xaa00/*nf*/,
+ 0x0001/*l*/, 0x8000/*e*/
+};
+
+const SvxMSDffCalculationData mso_sptEllipseRibbonCalc[] =
+{
+ { 0x2000 , { DFF_Prop_adjustValue , 0 , 0 } }, //val #0
+ { 0x2000 , { DFF_Prop_adjust2Value , 0 , 0 } }, //val #1
+ { 0x2000 , { DFF_Prop_adjust3Value , 0 , 0 } }, //val #2
+ { 0x2000 , { DFF_Prop_geoRight , 0 , 0 } }, //val width
+ { 0x2000 , { DFF_Prop_geoBottom , 0 , 0 } }, //val height
+ { 0x2001 , { DFF_Prop_geoRight , 1 , 8 } }, //prod width 1 8
+ { 0x2001 , { DFF_Prop_geoRight , 1 , 2 } }, //prod width 1 2
+ { 0x2001 , { DFF_Prop_geoRight , 7 , 8 } }, //prod width 7 8
+ { 0x2001 , { DFF_Prop_geoRight , 3 , 2 } }, //prod width 3 2
+ { 0x8000 , { 0 , 0 , 0x406 } }, //sum 0 0 @6
+ { 0xa000 , { DFF_Prop_geoBottom , 0 , DFF_Prop_adjust3Value } }, //sum height 0 #2
+ { 0x2001 , { 0x40a , 30573 , 4096 } }, //prod @10 30573 4096
+ { 0x2001 , { 0x40b , 2 , 1 } }, //prod @11 2 1
+ { 0xa000 , { DFF_Prop_geoBottom , 0 , 0x40c } }, //sum height 0 @12
+ { 0x6000 , { 0x40b , DFF_Prop_adjust3Value , 0 } }, //sum @11 #2 0
+ { 0xe000 , { 0x40b , DFF_Prop_geoBottom , DFF_Prop_adjust2Value } }, //sum @11 height #1
+ { 0xa000 , { DFF_Prop_geoBottom , 0 , DFF_Prop_adjust2Value } }, //sum height 0 #1
+ { 0x2001 , { 0x410 , 1 , 2 } }, //prod @16 1 2
+ { 0x6000 , { 0x40b , 0x411 , 0 } }, //sum @11 @17 0
+ { 0xe000 , { 0x40e , DFF_Prop_adjust2Value , DFF_Prop_geoBottom } }, //sum @14 #1 height
+ { 0x6000 , { DFF_Prop_adjustValue , 0x405 , 0 } }, //sum #0 @5 0
+ { 0xa000 , { DFF_Prop_geoRight , 0 , 0x414 } }, //sum width 0 @20
+ { 0xa000 , { DFF_Prop_geoRight , 0 , DFF_Prop_adjustValue } }, //sum width 0 #0
+ { 0xa000 , { 0x406 , 0 , DFF_Prop_adjustValue } }, //sum @6 0 #0
+ { 0xe00f , { 0x417 , DFF_Prop_geoRight , 0x40b } }, //ellipse @23 width @11
+ { 0xe000 , { 0x418 , DFF_Prop_geoBottom , 0x40b } }, //sum @24 height @11
+ { 0xe000 , { 0x419 , 0x40b , 0x413 } }, //sum @25 @11 @19
+ { 0xe000 , { DFF_Prop_adjust3Value , 0x40b , 0x413 } }, //sum #2 @11 @19
+ { 0x2001 , { 0x40b , 2391 , 32768 } }, //prod @11 2391 32768
+ { 0xa000 , { 0x406 , 0 , 0x414 } }, //sum @6 0 @20
+ { 0xe00f , { 0x41d , DFF_Prop_geoRight , 0x40b } }, //ellipse @29 width @11
+ { 0xe000 , { DFF_Prop_adjust2Value , 0x41e , 0x40b } }, //sum #1 @30 @11
+ { 0xe000 , { 0x419 , DFF_Prop_adjust2Value , DFF_Prop_geoBottom } }, //sum @25 #1 height
+ { 0xe000 , { DFF_Prop_geoBottom , 0x41e , 0x40e } }, //sum height @30 @14
+ { 0x6000 , { 0x40b , 0x40e , 0 } }, //sum @11 @14 0
+ { 0xa000 , { DFF_Prop_geoBottom , 0 , 0x422 } }, //sum height 0 @34
+ { 0xe000 , { 0x423 , 0x413 , 0x40b } }, //sum @35 @19 @11
+ { 0xe000 , { 0x40a , 0x40f , 0x40b } }, //sum @10 @15 @11
+ { 0xe000 , { 0x423 , 0x40f , 0x40b } }, //sum @35 @15 @11
+ { 0xe000 , { 0x41c , 0x40e , 0x412 } }, //sum @28 @14 @18
+ { 0xa000 , { DFF_Prop_geoBottom , 0 , 0x427 } }, //sum height 0 @39
+ { 0xa000 , { 0x413 , 0 , 0x412 } }, //sum @19 0 @18
+ { 0x2001 , { 0x429 , 2 , 3 } }, //prod @41 2 3
+ { 0xa000 , { DFF_Prop_adjust2Value , 0 , 0x42a } }, //sum #1 0 @42
+ { 0xa000 , { DFF_Prop_adjust3Value , 0 , 0x42a } }, //sum #2 0 @42
+ { 0x2004 , { 0x42c , 20925 , 0 } }, //min @44 20925
+ { 0x2001 , { DFF_Prop_geoRight , 3 , 8 } }, //prod width 3 8
+ { 0x2000 , { 0x42e , 0 , 4 } }, //sum @46 0 4
+};
+
+const SvxMSDffTextRectangles mso_sptEllipseRibbonTextRect[] =
+{//@0,@1,@22,@25
+ { { 0 MSO_I, 1 MSO_I }, { 22 MSO_I, 25 MSO_I } }
+};
+
+const sal_Int32 mso_sptEllipseRibbonDefault[] =
+{
+ 3,5400,5400,18900
+};
+
+const SvxMSDffHandle mso_sptEllipseRibbonHandle[] =
+{
+//position="#0,bottomRight" xrange="@5,@47
+//position="center,#1" yrange="@10,@43
+//position="topLeft,#2" yrange="@27,@45
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL| SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL,
+ 0x100, 21600, 0, 0, 0x8/*5+3*/, 0x32/*47+3*/, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 10800, 0x101, 0, 0, MIN_INT32, 0x7fffffff,0xd/*10+3*/, 0x2e /*43+3*/ },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 0, 0x102, 0, 0, MIN_INT32, 0x7fffffff,0x1e/*27+3*/, 0x30 /*45+3*/ }
+};
+
+const mso_CustomShape msosptEllipseRibbon =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptEllipseRibbonVert), SAL_N_ELEMENTS( mso_sptEllipseRibbonVert ),
+ const_cast<sal_uInt16*>(mso_sptEllipseRibbonSegm), sizeof( mso_sptEllipseRibbonSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptEllipseRibbonCalc), SAL_N_ELEMENTS( mso_sptEllipseRibbonCalc ),
+ const_cast<sal_Int32*>(mso_sptEllipseRibbonDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptEllipseRibbonTextRect), SAL_N_ELEMENTS( mso_sptEllipseRibbonTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptEllipseRibbonHandle), SAL_N_ELEMENTS( mso_sptEllipseRibbonHandle )
+};
+
+//msosptEllipseRibbon2
+//svg path = wr@9@34@8@35,0@24@0@23@9,0@8@11@0@22@19@22@9@34@8@35@19@23@3@24l@7@36@3@4at@9@31@8@32@3@4@18@30@9@1@8@33@18@28@17@28@9@31@8@32@17@30,0@4l@5@36xear@9@1@8@33@17@28@0@29nfl@17@30ewr@9@1@8@33@18@28@19@29nfl@18@30em@0@23nfl@0@29em@19@23nfl@19@29e
+const SvxMSDffVertPair mso_sptEllipseRibbon2Vert[] =
+{
+ { 9 MSO_I , 34 MSO_I },
+ { 8 MSO_I , 35 MSO_I },
+ { 0 , 24 MSO_I },
+ { 0 MSO_I , 23 MSO_I },
+ { 9 MSO_I , 0 },
+ { 8 MSO_I , 11 MSO_I },
+ { 0 MSO_I , 22 MSO_I },
+ { 19 MSO_I , 22 MSO_I },
+ { 9 MSO_I , 34 MSO_I },
+ { 8 MSO_I , 35 MSO_I },
+ { 19 MSO_I , 23 MSO_I },
+ { 3 MSO_I , 24 MSO_I },
+ { 7 MSO_I , 36 MSO_I },
+ { 3 MSO_I , 4 MSO_I },
+ { 9 MSO_I , 31 MSO_I },
+ { 8 MSO_I , 32 MSO_I },
+ { 3 MSO_I , 4 MSO_I },
+ { 18 MSO_I , 30 MSO_I },
+ { 9 MSO_I , 1 MSO_I },
+ { 8 MSO_I , 33 MSO_I },
+ { 18 MSO_I , 28 MSO_I },
+ { 17 MSO_I , 28 MSO_I },
+ { 9 MSO_I , 31 MSO_I },
+ { 8 MSO_I , 32 MSO_I },
+ { 17 MSO_I , 30 MSO_I },
+ { 0 , 4l MSO_I },
+ { 5 MSO_I , 36 MSO_I },
+ { 9 MSO_I , 1 MSO_I },
+ { 8 MSO_I , 33 MSO_I },
+ { 17 MSO_I , 28 MSO_I },
+ { 0 MSO_I , 29 MSO_I },
+ { 17 MSO_I , 30 MSO_I },
+ { 9 MSO_I , 1 MSO_I },
+ { 8 MSO_I , 33 MSO_I },
+ { 18 MSO_I , 28 MSO_I },
+ { 19 MSO_I , 29 MSO_I },
+ { 18 MSO_I , 30 MSO_I },
+ { 0 MSO_I , 23 MSO_I },
+ { 0 MSO_I , 29 MSO_I },
+ { 19 MSO_I , 23 MSO_I },
+ { 19 MSO_I , 29 MSO_I }
+};
+const sal_uInt16 mso_sptEllipseRibbon2Segm[] =
+{
+ 0xa50c/*wr*/,0x0002/*l*/,0xa30c/*at*/,0x0001/*l*/,
+ 0x6001/*x*/, 0x8000/*e*/,0xa304/*ar*/,0xaa00/*nf*/,
+ 0x0001/*l*/, 0x8000/*e*/,0xa504/*wr*/,0xaa00/*nf*/,
+ 0x0001/*l*/, 0x8000/*e*/,0x4000/*m*/,0xaa00/*nf*/,
+ 0x0001/*l*/, 0x8000/*e*/,0x4000/*m*/,0xaa00/*nf*/,
+ 0x0001/*l*/, 0x8000/*e*/
+};
+
+const SvxMSDffCalculationData mso_sptEllipseRibbon2Calc[] =
+{
+ { 0x2000 , { DFF_Prop_adjustValue , 0 , 0 } }, //val #0
+ { 0x2000 , { DFF_Prop_adjust2Value , 0 , 0 } }, //val #1
+ { 0x2000 , { DFF_Prop_adjust3Value , 0 , 0 } }, //val #2
+ { 0x2000 , { DFF_Prop_geoRight , 0 , 0 } }, //val width
+ { 0x2000 , { DFF_Prop_geoBottom , 0 , 0 } }, //val height
+ { 0x2001 , { DFF_Prop_geoRight , 1 , 8 } }, //prod width 1 8
+ { 0x2001 , { DFF_Prop_geoRight , 1 , 2 } }, //prod width 1 2
+ { 0x2001 , { DFF_Prop_geoRight , 7 , 8 } }, //prod width 7 8
+ { 0x2001 , { DFF_Prop_geoRight , 3 , 2 } }, //prod width 3 2
+ { 0x8000 , { 0 , 0 , 0x406 } }, //sum 0 0 @6
+ { 0x2001 , { DFF_Prop_adjust3Value , 30573 , 4096 } }, //prod #2 30573 4096
+ { 0x2001 , { 0x40a , 2 , 1 } }, //prod @10 2 1
+ { 0xe000 , { 0x40a , DFF_Prop_geoBottom , DFF_Prop_adjust3Value } }, //sum @10 height #2
+ { 0x6000 , { 0x40a , DFF_Prop_adjust2Value , 0 } }, //sum @10 #1 0
+ { 0x2001 , { DFF_Prop_adjust2Value , 1 , 2 } }, //prod #1 1 2
+ { 0x6000 , { 0x40a , 0x40e , 0 } }, //sum @10 @14 0
+ { 0xa000 , { 0x40c , 0 , DFF_Prop_adjust2Value } }, //sum @12 0 #1
+ { 0x6000 , { DFF_Prop_adjustValue , 0x405 , 0 } }, //sum #0 @5 0
+ { 0xa000 , { DFF_Prop_geoRight , 0 , 0x411 } }, //sum width 0 @17
+ { 0xa000 , { DFF_Prop_geoRight , 0 , DFF_Prop_adjustValue } }, //sum width 0 #0
+ { 0xa000 , { 0x406 , 0 , DFF_Prop_adjustValue } }, //sum @6 0 #0
+ { 0xe00f , { 0x414 , DFF_Prop_geoRight , 0x40a } }, //ellipse @20 width @10
+ { 0xa000 , { 0x40a , 0 , 0x415 } }, //sum @10 0 @21
+ { 0xe000 , { 0x416 , 0x410 , 0x40a } }, //sum @22 @16 @10
+ { 0xe000 , { DFF_Prop_adjust3Value , 0x410 , 0x40a } }, //sum #2 @16 @10
+ { 0x2001 , { 0x40a , 2391 , 32768 } }, //prod @10 2391 32768
+ { 0xa000 , { 0x406 , 0 , 0x411 } }, //sum @6 0 @17
+ { 0xe00f , { 0x41a , DFF_Prop_geoRight , 0x40a } }, //ellipse @26 width @10
+ { 0xe000 , { 0x40a , DFF_Prop_adjust2Value , 0x41b } }, //sum @10 #1 @27
+ { 0x6000 , { 0x416 , DFF_Prop_adjust2Value , 0 } }, //sum @22 #1 0
+ { 0xa000 , { 0x40c , 0 , 0x41b } }, //sum @12 0 @27
+ { 0xa000 , { DFF_Prop_geoBottom , 0 , DFF_Prop_adjust3Value } }, //sum height 0 #2
+ { 0x6000 , { 0x40a , 0x40c , 0 } }, //sum @10 @12 0
+ { 0xe000 , { 0x420 , 0x40a , 0x410 } }, //sum @32 @10 @16
+ { 0xe000 , { 0x41f , 0x40a , 0x40d } }, //sum @31 @10 @13
+ { 0xe000 , { 0x420 , 0x40a , 0x40d } }, //sum @32 @10 @13
+ { 0xe000 , { 0x419 , 0x40c , 0x40f } }, //sum @25 @12 @15
+ { 0xa000 , { 0x410 , 0 , 0x40f } }, //sum @16 0 @15
+ { 0x2001 , { 0x425 , 2 , 3 } }, //prod @37 2 3
+ { 0x6000 , { 0x401 , 0x426 , 0 } }, //sum @1 @38 0
+ { 0x6000 , { DFF_Prop_adjust3Value , 0x426 , 0 } }, //sum #2 @38 0
+ { 0x2005 , { 0x428 , 675 , 0 } }, //max @40 675
+ { 0x2001 , { DFF_Prop_geoRight , 3 , 8 } }, //prod width 3 8
+ { 0x2000 , { 0x42a , 0 , 4 } } //sum @42 0 4
+};
+
+const SvxMSDffTextRectangles mso_sptEllipseRibbon2TextRect[] =
+{//@0,@22,@19,@1
+ { { 0 MSO_I, 22 MSO_I }, { 19 MSO_I, 1 MSO_I } }
+};
+
+const sal_Int32 mso_sptEllipseRibbon2Default[] =
+{
+ 3,5400,16200,2700
+};
+
+const SvxMSDffHandle mso_sptEllipseRibbon2Handle[] =
+{
+//position="#0,topLeft" xrange="@5,@43
+//position="center,#1" yrange="@39,@31
+//position="topLeft,#2" yrange="@41,@24
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL| SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL,
+ 0x100, 0, 0, 0, 0x8/*5+3*/, 0x2e/*43+3*/, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 10800, 0x101, 0, 0, MIN_INT32, 0x7fffffff,0x2a/*39+3*/, 0x22 /*31+3*/ },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 0, 0x102, 0, 0, MIN_INT32, 0x7fffffff,0x2c/*41+3*/, 0x1b /*24+3*/ }
+};
+
+const mso_CustomShape msosptEllipseRibbon2 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptEllipseRibbon2Vert), SAL_N_ELEMENTS( mso_sptEllipseRibbon2Vert ),
+ const_cast<sal_uInt16*>(mso_sptEllipseRibbon2Segm), sizeof( mso_sptEllipseRibbon2Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptEllipseRibbon2Calc), SAL_N_ELEMENTS( mso_sptEllipseRibbon2Calc ),
+ const_cast<sal_Int32*>(mso_sptEllipseRibbon2Default),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptEllipseRibbon2TextRect), SAL_N_ELEMENTS( mso_sptEllipseRibbon2TextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptEllipseRibbon2Handle), SAL_N_ELEMENTS( mso_sptEllipseRibbon2Handle )
+};
+// End
+const SvxMSDffVertPair mso_sptVerticalScrollVert[] = // adjustment1 : 0 - 5400
+{
+ { 1 MSO_I, 21600 }, { 0, 11 MSO_I }, { 1 MSO_I, 12 MSO_I }, { 0 MSO_I, 12 MSO_I },
+ { 0 MSO_I, 1 MSO_I }, { 4 MSO_I, 0 }, { 2 MSO_I, 0 }, { 21600, 1 MSO_I },
+ { 2 MSO_I, 0 MSO_I }, { 3 MSO_I, 0 MSO_I }, { 3 MSO_I, 11 MSO_I }, { 5 MSO_I, 21600 },
+
+ { 6 MSO_I, 1 MSO_I }, { 4 MSO_I, 0 MSO_I }, { 8 MSO_I, 9 MSO_I }, { 4 MSO_I, 1 MSO_I },
+
+ { 0 MSO_I, 11 MSO_I }, { 1 MSO_I, 21600 }, { 0, 11 MSO_I }, { 1 MSO_I, 12 MSO_I },
+ { 9 MSO_I, 10 MSO_I }, { 1 MSO_I, 11 MSO_I },
+
+ { 4 MSO_I, 0 }, { 6 MSO_I, 1 MSO_I },
+
+ { 0 MSO_I, 12 MSO_I }, { 0 MSO_I, 11 MSO_I },
+
+ { 4 MSO_I, 0 MSO_I },
+ { 2 MSO_I, 0 MSO_I }
+};
+const sal_uInt16 mso_sptVerticalScrollSegm[] =
+{
+ 0x4000, 0xa702, 0x0002, 0xa801, 0x0001, 0xa702, 0x0002, 0xa801, 0x6001, 0x8000,
+ 0x4000, 0xa801, 0xa702, 0x6000, 0x8000,
+ 0x4000, 0xa803, 0xa702, 0x6001, 0x8000,
+ 0x4000, 0xa701, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptScrollCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2001, { 0x400, 1, 2 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x401 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x400 } },
+ { 0x6000, { 0x400, 0x401, 0 } },
+ { 0xa000, { DFF_Prop_geoRight, 0, 0x404 } },
+ { 0x2001, { 0x400, 2, 1 } },
+ { 0x2001, { 0x401, 1, 2 } },
+ { 0x6000, { 0x400, 0x407, 0 } },
+ { 0x6000, { 0x401, 0x407, 0 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x409 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x401 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x400 } },
+ { 0xa000, { DFF_Prop_geoBottom, 0, 0x404 } }
+};
+const SvxMSDffTextRectangles mso_sptScrollTextRect[] =
+{
+ { { 0 MSO_I, 0 MSO_I }, { 3 MSO_I, 12 MSO_I } }
+};
+const SvxMSDffHandle mso_sptVerticalScrollHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 5400 }
+};
+const mso_CustomShape msoVerticalScroll =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptVerticalScrollVert), SAL_N_ELEMENTS( mso_sptVerticalScrollVert ),
+ const_cast<sal_uInt16*>(mso_sptVerticalScrollSegm), sizeof( mso_sptVerticalScrollSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptScrollCalc), SAL_N_ELEMENTS( mso_sptScrollCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault2700),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptScrollTextRect), SAL_N_ELEMENTS( mso_sptScrollTextRect ),
+ 21600, 21600,
+ 11000, 10800,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptVerticalScrollHandle), SAL_N_ELEMENTS( mso_sptVerticalScrollHandle )
+};
+const SvxMSDffVertPair mso_sptHorizontalScrollVert[] = // adjustment1 : 0 - 5400
+{
+ { 0, 4 MSO_I }, { 1 MSO_I, 0 MSO_I }, { 3 MSO_I, 0 MSO_I }, { 3 MSO_I, 1 MSO_I },
+ { 2 MSO_I, 0 }, { 21600, 1 MSO_I }, { 21600, 13 MSO_I }, { 2 MSO_I, 12 MSO_I },
+ { 0 MSO_I, 12 MSO_I }, { 0 MSO_I, 11 MSO_I }, { 1 MSO_I, 21600 }, { 0, 11 MSO_I },
+
+ { 1 MSO_I, 4 MSO_I }, { 9 MSO_I, 8 MSO_I }, { 0 MSO_I, 4 MSO_I }, { 1 MSO_I, 6 MSO_I },
+
+ { 2 MSO_I, 1 MSO_I }, { 3 MSO_I, 9 MSO_I }, { 3 MSO_I, 1 MSO_I }, { 2 MSO_I, 0 },
+ { 21600, 1 MSO_I }, { 2 MSO_I, 0 MSO_I },
+
+ { 1 MSO_I, 6 MSO_I },
+ { 0, 4 MSO_I },
+
+ { 2 MSO_I, 0 MSO_I },
+ { 3 MSO_I, 0 MSO_I },
+
+ { 0 MSO_I, 4 MSO_I },
+ { 0 MSO_I, 11 MSO_I }
+};
+const sal_uInt16 mso_sptHorizontalScrollSegm[] =
+{
+ 0x4000, 0xa801, 0x0002, 0xa802, 0x0001, 0xa801, 0x0002, 0xa802, 0x6001, 0x8000,
+ 0x4000, 0xa803, 0x6000, 0x8000,
+ 0x4000, 0xa803, 0xa702, 0x6000, 0x8000,
+ 0x4000, 0xa701, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffHandle mso_sptHorizontalScrollHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0, 10800, 10800, 0, 5400, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoHorizontalScroll =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptHorizontalScrollVert), SAL_N_ELEMENTS( mso_sptHorizontalScrollVert ),
+ const_cast<sal_uInt16*>(mso_sptHorizontalScrollSegm), sizeof( mso_sptHorizontalScrollSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptScrollCalc), SAL_N_ELEMENTS( mso_sptScrollCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault2700),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptScrollTextRect), SAL_N_ELEMENTS( mso_sptScrollTextRect ),
+ 21600, 21600,
+ 10800, 11000,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptHorizontalScrollHandle), SAL_N_ELEMENTS( mso_sptHorizontalScrollHandle )
+};
+
+const SvxMSDffVertPair mso_sptFlowChartProcessVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0, 0 }
+};
+const mso_CustomShape msoFlowChartProcess =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartProcessVert), SAL_N_ELEMENTS( mso_sptFlowChartProcessVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartAlternateProcessVert[] =
+{
+ { 0, 2 MSO_I }, { 0 MSO_I, 0 }, { 1 MSO_I, 0 }, { 21600, 2 MSO_I },
+ { 21600, 3 MSO_I }, { 1 MSO_I, 21600 }, { 0 MSO_I, 21600 }, { 0, 3 MSO_I }
+};
+const sal_uInt16 mso_sptFlowChartAlternateProcessSegm[] =
+{
+ 0x4000, 0xa801, 0x0001, 0xa701, 0x0001, 0xa801, 0x0001, 0xa701, 0x6000, 0x8000
+};
+const SvxMSDffCalculationData mso_sptFlowChartAlternateProcessCalc[] =
+{
+ { 0x2000, { DFF_Prop_geoLeft, 2540, 0 } },
+ { 0x2000, { DFF_Prop_geoRight, 0, 2540 } },
+ { 0x2000, { DFF_Prop_geoTop, 2540, 0 } },
+ { 0x2000, { DFF_Prop_geoBottom, 0, 2540 } },
+ { 0x2000, { DFF_Prop_geoLeft, 800, 0 } },
+ { 0x2000, { DFF_Prop_geoRight, 0, 800 } },
+ { 0x2000, { DFF_Prop_geoTop, 800, 0 } },
+ { 0x2000, { DFF_Prop_geoBottom,0, 800 } }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartAlternateProcessTextRect[] =
+{
+ { { 4 MSO_I, 6 MSO_I }, { 5 MSO_I, 7 MSO_I } }
+};
+const mso_CustomShape msoFlowChartAlternateProcess =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartAlternateProcessVert), SAL_N_ELEMENTS( mso_sptFlowChartAlternateProcessVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartAlternateProcessSegm), sizeof( mso_sptFlowChartAlternateProcessSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptFlowChartAlternateProcessCalc), SAL_N_ELEMENTS( mso_sptFlowChartAlternateProcessCalc ),
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartAlternateProcessTextRect), SAL_N_ELEMENTS( mso_sptFlowChartAlternateProcessTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartDecisionVert[] =
+{
+ { 0, 10800 }, { 10800, 0 }, { 21600, 10800 }, { 10800, 21600 }, { 0, 10800 }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartDecisionTextRect[] =
+{
+ { { 5400, 5400 }, { 16200, 16200 } }
+};
+const mso_CustomShape msoFlowChartDecision =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartDecisionVert), SAL_N_ELEMENTS( mso_sptFlowChartDecisionVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartDecisionTextRect), SAL_N_ELEMENTS( mso_sptFlowChartDecisionTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartInputOutputVert[] =
+{
+ { 4230, 0 }, { 21600, 0 }, { 17370, 21600 }, { 0, 21600 }, { 4230, 0 }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartInputOutputTextRect[] =
+{
+ { { 4230, 0 }, { 17370, 21600 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartInputOutputGluePoints[] =
+{
+ { 12960, 0 }, { 10800, 0 }, { 2160, 10800 }, { 8600, 21600 }, { 10800, 21600 }, { 19400, 10800 }
+};
+const mso_CustomShape msoFlowChartInputOutput =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartInputOutputVert), SAL_N_ELEMENTS( mso_sptFlowChartInputOutputVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartInputOutputTextRect), SAL_N_ELEMENTS( mso_sptFlowChartInputOutputTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartInputOutputGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartInputOutputGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartPredefinedProcessVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+
+ { 2540, 0 }, { 2540, 21600 },
+
+ { 21600 - 2540, 0 }, { 21600 - 2540, 21600 }
+};
+const sal_uInt16 mso_sptFlowChartPredefinedProcessSegm[] =
+{
+ 0x4000, 0x0003, 0x6000, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartPredefinedProcessTextRect[] =
+{
+ { { 2540, 0 }, { 21600 - 2540, 21600 } }
+};
+const mso_CustomShape msoFlowChartPredefinedProcess =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartPredefinedProcessVert), SAL_N_ELEMENTS( mso_sptFlowChartPredefinedProcessVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartPredefinedProcessSegm), sizeof( mso_sptFlowChartPredefinedProcessSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartPredefinedProcessTextRect), SAL_N_ELEMENTS( mso_sptFlowChartPredefinedProcessTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartInternalStorageVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+
+ { 4230, 0 }, { 4230, 21600 },
+
+ { 0, 4230 }, { 21600, 4230 }
+};
+const sal_uInt16 mso_sptFlowChartInternalStorageSegm[] =
+{
+ 0x4000, 0x0003, 0x6000, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartInternalStorageTextRect[] =
+{
+ { { 4230, 4230 }, { 21600, 21600 } }
+};
+const mso_CustomShape msoFlowChartInternalStorage =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartInternalStorageVert), SAL_N_ELEMENTS( mso_sptFlowChartInternalStorageVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartInternalStorageSegm), sizeof( mso_sptFlowChartInternalStorageSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartInternalStorageTextRect), SAL_N_ELEMENTS( mso_sptFlowChartInternalStorageTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartDocumentVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 17360 },
+ { 13050, 17220 }, { 13340, 20770 }, { 5620, 21600 }, // ccp
+ { 2860, 21100 }, { 1850, 20700 }, { 0, 20120 } // ccp
+};
+const sal_uInt16 mso_sptFlowChartDocumentSegm[] =
+{
+ 0x4000, 0x0002, 0x2002, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartDocumentTextRect[] =
+{
+ { { 0, 0 }, { 21600, 17360 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartDocumentGluePoints[] =
+{
+ { 10800, 0 }, { 0, 10800 }, { 10800, 20320 }, { 21600, 10800 }
+};
+const mso_CustomShape msoFlowChartDocument =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartDocumentVert), SAL_N_ELEMENTS( mso_sptFlowChartDocumentVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartDocumentSegm), sizeof( mso_sptFlowChartDocumentSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartDocumentTextRect), SAL_N_ELEMENTS( mso_sptFlowChartDocumentTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartDocumentGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartDocumentGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartMultidocumentVert[] =
+{
+ { 0, 3600 }, { 1500, 3600 }, { 1500, 1800 }, { 3000, 1800 },
+ { 3000, 0 }, { 21600, 0 }, { 21600, 14409 }, { 21600 - 1500, 14409 },
+ { 21600 - 1500, 14409 + 1800 }, { 21600 - 3000, 14409 + 1800 }, { 21600 - 3000, 14409 + 3600 },
+ { 11610, 14293 + 3600 }, { 11472, 17239 + 3600 }, { 4833, 17928 + 3600 }, // ccp
+ { 2450, 17513 + 3600 }, { 1591, 17181 + 3600 }, { 0, 16700 + 3600 }, // ccp
+
+ { 1500, 3600 }, { 21600 - 3000, 3600 }, { 21600 - 3000, 14409 + 1800 },
+
+ { 3000, 1800 }, { 21600 - 1500, 1800 }, { 21600 - 1500, 14409 }
+};
+const sal_uInt16 mso_sptFlowChartMultidocumentSegm[] =
+{
+ 0x4000, 0x000a, 0x2002, 0x6000, 0x8000,
+ 0x4000, 0xaa00, 0x0002, 0x8000, // NO FILL
+ 0x4000, 0xaa00, 0x0002, 0x8000 // NO FILL
+};
+const SvxMSDffTextRectangles mso_sptFlowChartMultidocumentTextRect[] =
+{
+ { { 0, 3600 }, { 21600 - 3000, 14409 + 3600 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartMultidocumentGluePoints[] =
+{
+ { 10800, 0 }, { 0, 10800 }, { 10800, 19890 }, { 21600, 10800 }
+};
+const mso_CustomShape msoFlowChartMultidocument =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartMultidocumentVert), SAL_N_ELEMENTS( mso_sptFlowChartMultidocumentVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartMultidocumentSegm), sizeof( mso_sptFlowChartMultidocumentSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartMultidocumentTextRect), SAL_N_ELEMENTS( mso_sptFlowChartMultidocumentTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartMultidocumentGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartMultidocumentGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartTerminatorVert[] =
+{
+ { 3470, 21600 }, { 0, 10800 }, { 3470, 0 }, { 18130, 0 },
+ { 21600, 10800 }, { 18130, 21600 }
+};
+const sal_uInt16 mso_sptFlowChartTerminatorSegm[] =
+{
+ 0x4000, 0xa702, 0x0001, 0xa702, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartTerminatorTextRect[] =
+{
+ { { 1060, 3180 }, { 20540, 18420 } }
+};
+const mso_CustomShape msoFlowChartTerminator =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartTerminatorVert), SAL_N_ELEMENTS( mso_sptFlowChartTerminatorVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartTerminatorSegm), sizeof( mso_sptFlowChartTerminatorSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartTerminatorTextRect), SAL_N_ELEMENTS( mso_sptFlowChartTerminatorTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartPreparationVert[] =
+{
+ { 4350, 0 }, { 17250, 0 }, { 21600, 10800 }, { 17250, 21600 },
+ { 4350, 21600 }, { 0, 10800 }, { 4350, 0 }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartPreparationTextRect[] =
+{
+ { { 4350, 0 }, { 17250, 21600 } }
+};
+const mso_CustomShape msoFlowChartPreparation =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartPreparationVert), SAL_N_ELEMENTS( mso_sptFlowChartPreparationVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartPreparationTextRect), SAL_N_ELEMENTS( mso_sptFlowChartPreparationTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartManualInputVert[] =
+{
+ { 0, 4300 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0, 4300 }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartManualInputTextRect[] =
+{
+ { { 0, 4300 }, { 21600, 21600 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartManualInputGluePoints[] =
+{
+ { 10800, 2150 }, { 0, 10800 }, { 10800, 19890 }, { 21600, 10800 }
+};
+const mso_CustomShape msoFlowChartManualInput =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartManualInputVert), SAL_N_ELEMENTS( mso_sptFlowChartManualInputVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartManualInputTextRect), SAL_N_ELEMENTS( mso_sptFlowChartManualInputTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartManualInputGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartManualInputGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartManualOperationVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 17250, 21600 }, { 4350, 21600 }, { 0, 0 }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartManualOperationTextRect[] =
+{
+ { { 4350, 0 }, { 17250, 21600 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartManualOperationGluePoints[] =
+{
+ { 10800, 0 }, { 2160, 10800 }, { 10800, 21600 }, { 19440, 10800 }
+};
+const mso_CustomShape msoFlowChartManualOperation =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartManualOperationVert), SAL_N_ELEMENTS( mso_sptFlowChartManualOperationVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartManualOperationTextRect), SAL_N_ELEMENTS( mso_sptFlowChartManualOperationTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartManualOperationGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartManualOperationGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartConnectorVert[] =
+{
+ { 10800, 10800 }, { 10800, 10800 }, { 0, 360 }
+};
+const sal_uInt16 mso_sptFlowChartConnectorSegm[] =
+{
+ 0xa203, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartConnectorTextRect[] =
+{
+ { { 3180, 3180 }, { 18420, 18420 } }
+};
+const mso_CustomShape msoFlowChartConnector =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartConnectorVert), SAL_N_ELEMENTS( mso_sptFlowChartConnectorVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartConnectorSegm), sizeof( mso_sptFlowChartConnectorSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartConnectorTextRect), SAL_N_ELEMENTS( mso_sptFlowChartConnectorTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartOffpageConnectorVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 17150 }, { 10800, 21600 },
+ { 0, 17150 }, { 0, 0 }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartOffpageConnectorTextRect[] =
+{
+ { { 0, 0 }, { 21600, 17150 } }
+};
+const mso_CustomShape msoFlowChartOffpageConnector =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartOffpageConnectorVert), SAL_N_ELEMENTS( mso_sptFlowChartOffpageConnectorVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartOffpageConnectorTextRect), SAL_N_ELEMENTS( mso_sptFlowChartOffpageConnectorTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartPunchedCardVert[] =
+{
+ { 4300, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 },
+ { 0, 4300 }, { 4300, 0 }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartPunchedCardTextRect[] =
+{
+ { { 0, 4300 }, { 21600, 21600 } }
+};
+const mso_CustomShape msoFlowChartPunchedCard =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartPunchedCardVert), SAL_N_ELEMENTS( mso_sptFlowChartPunchedCardVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartPunchedCardTextRect), SAL_N_ELEMENTS( mso_sptFlowChartPunchedCardTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartPunchedTapeVert[] =
+{
+ { 0, 2230 }, // p
+ { 820, 3990 }, { 3410, 3980 }, { 5370, 4360 }, // ccp
+ { 7430, 4030 }, { 10110, 3890 }, { 10690, 2270 }, // ccp
+ { 11440, 300 }, { 14200, 160 }, { 16150, 0 }, // ccp
+ { 18670, 170 }, { 20690, 390 }, { 21600, 2230 }, // ccp
+ { 21600, 19420 }, // p
+ { 20640, 17510 }, { 18320, 17490 }, { 16140, 17240 }, // ccp
+ { 14710, 17370 }, { 11310, 17510 }, { 10770, 19430 }, // ccp
+ { 10150, 21150 }, { 7380, 21290 }, { 5290, 21600 }, // ccp
+ { 3220, 21250 }, { 610, 21130 }, { 0, 19420 } // ccp
+};
+const sal_uInt16 mso_sptFlowChartPunchedTapeSegm[] =
+{
+ 0x4000, 0x2004, 0x0001, 0x2004, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartPunchedTapeTextRect[] =
+{
+ { { 0, 4360 }, { 21600, 17240 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartPunchedTapeGluePoints[] =
+{
+ { 10800, 2020 }, { 0, 10800 }, { 10800, 19320 }, { 21600, 10800 }
+};
+const mso_CustomShape msoFlowChartPunchedTape =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartPunchedTapeVert), SAL_N_ELEMENTS( mso_sptFlowChartPunchedTapeVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartPunchedTapeSegm), sizeof( mso_sptFlowChartPunchedTapeSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartPunchedTapeTextRect), SAL_N_ELEMENTS( mso_sptFlowChartPunchedTapeTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartPunchedTapeGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartPunchedTapeGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartSummingJunctionVert[] =
+{
+ { 10800, 10800 }, { 10800, 10800 }, { 0, 360 },
+
+ { 3100, 3100 },
+ { 18500, 18500 },
+
+ { 3100, 18500 },
+ { 18500, 3100 }
+};
+const sal_uInt16 mso_sptFlowChartSummingJunctionSegm[] =
+{
+ 0xa203, 0x6000, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartSummingJunctionTextRect[] =
+{
+ { { 3100, 3100 }, { 18500, 18500 } }
+};
+const mso_CustomShape msoFlowChartSummingJunction =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartSummingJunctionVert), SAL_N_ELEMENTS( mso_sptFlowChartSummingJunctionVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartSummingJunctionSegm), sizeof( mso_sptFlowChartSummingJunctionSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartSummingJunctionTextRect), SAL_N_ELEMENTS( mso_sptFlowChartSummingJunctionTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartOrVert[] =
+{
+ { 10800, 10800 }, { 10800, 10800 }, { 0, 360 },
+
+ { 0, 10800 }, { 21600, 10800 },
+
+ { 10800, 0 }, { 10800, 21600 }
+};
+const sal_uInt16 mso_sptFlowChartOrSegm[] =
+{
+ 0xa203, 0x6000, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartOrTextRect[] =
+{
+ { { 3100, 3100 }, { 18500, 18500 } }
+};
+const mso_CustomShape msoFlowChartOr =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartOrVert), SAL_N_ELEMENTS( mso_sptFlowChartOrVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartOrSegm), sizeof( mso_sptFlowChartOrSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartOrTextRect), SAL_N_ELEMENTS( mso_sptFlowChartOrTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptEllipseGluePoints), SAL_N_ELEMENTS( mso_sptEllipseGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartCollateVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 0, 21600 }, { 21600, 0 }, { 0, 0 }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartCollateTextRect[] =
+{
+ { { 5400, 5400 }, { 16200, 16200 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartCollateGluePoints[] =
+{
+ { 10800, 0 }, { 10800, 10800 }, { 10800, 21600 }
+};
+const mso_CustomShape msoFlowChartCollate =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartCollateVert), SAL_N_ELEMENTS( mso_sptFlowChartCollateVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartCollateTextRect), SAL_N_ELEMENTS( mso_sptFlowChartCollateTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartCollateGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartCollateGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartSortVert[] =
+{
+ { 0, 10800 }, { 10800, 0 }, { 21600, 10800 }, { 10800, 21600 },
+
+ { 0, 10800 }, { 21600, 10800 }
+};
+const sal_uInt16 mso_sptFlowChartSortSegm[] =
+{
+ 0x4000, 0x0003, 0x6000, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartSortTextRect[] =
+{
+ { { 5400, 5400 }, { 16200, 16200 } }
+};
+const mso_CustomShape msoFlowChartSort =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartSortVert), SAL_N_ELEMENTS( mso_sptFlowChartSortVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartSortSegm), sizeof( mso_sptFlowChartSortSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartSortTextRect), SAL_N_ELEMENTS( mso_sptFlowChartSortTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartExtractVert[] =
+{
+ { 10800, 0 }, { 21600, 21600 }, { 0, 21600 }, { 10800, 0 }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartExtractTextRect[] =
+{
+ { { 5400, 10800 }, { 16200, 21600 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartExtractGluePoints[] =
+{
+ { 10800, 0 }, { 5400, 10800 }, { 10800, 21600 }, { 16200, 10800 }
+};
+const mso_CustomShape msoFlowChartExtract =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartExtractVert), SAL_N_ELEMENTS( mso_sptFlowChartExtractVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartExtractTextRect), SAL_N_ELEMENTS( mso_sptFlowChartExtractTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartExtractGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartExtractGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartMergeVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 10800, 21600 }, { 0, 0 }
+};
+const SvxMSDffTextRectangles mso_sptFlowChartMergeTextRect[] =
+{
+ { { 5400, 0 }, { 16200, 10800 } }
+};
+const mso_CustomShape msoFlowChartMerge =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartMergeVert), SAL_N_ELEMENTS( mso_sptFlowChartMergeVert ),
+ nullptr, 0,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartMergeTextRect), SAL_N_ELEMENTS( mso_sptFlowChartMergeTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartExtractGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartExtractGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartOnlineStorageVert[] =
+{
+ { 3600, 21600 }, { 0, 10800 }, { 3600, 0 }, { 21600, 0 },
+ { 18000, 10800 }, { 21600, 21600 }
+};
+const sal_uInt16 mso_sptFlowChartOnlineStorageSegm[] =
+{
+ 0x4000, 0xa702, 0x0001, 0xa702, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartOnlineStorageTextRect[] =
+{
+ { { 3600, 0 }, { 18000, 21600 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartOnlineStorageGluePoints[] =
+{
+ { 10800, 0 }, { 0, 10800 }, { 10800, 21600 }, { 18000, 10800 }
+};
+const mso_CustomShape msoFlowChartOnlineStorage =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartOnlineStorageVert), SAL_N_ELEMENTS( mso_sptFlowChartOnlineStorageVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartOnlineStorageSegm), sizeof( mso_sptFlowChartOnlineStorageSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartOnlineStorageTextRect), SAL_N_ELEMENTS( mso_sptFlowChartOnlineStorageTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartOnlineStorageGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartOnlineStorageGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartDelayVert[] =
+{
+ { 10800, 0 }, { 21600, 10800 }, { 10800, 21600 }, { 0, 21600 },
+ { 0, 0 }
+};
+const sal_uInt16 mso_sptFlowChartDelaySegm[] =
+{
+ 0x4000, 0xa702, 0x0002, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartDelayTextRect[] =
+{
+ { { 0, 3100 }, { 18500, 18500 } }
+};
+const mso_CustomShape msoFlowChartDelay =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartDelayVert), SAL_N_ELEMENTS( mso_sptFlowChartDelayVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartDelaySegm), sizeof( mso_sptFlowChartDelaySegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartDelayTextRect), SAL_N_ELEMENTS( mso_sptFlowChartDelayTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartMagneticTapeVert[] =
+{
+ { 20980, 18150 }, { 20980, 21600 }, { 10670, 21600 },
+ { 4770, 21540 }, { 0, 16720 }, { 0, 10800 }, // ccp
+ { 0, 4840 }, { 4840, 0 }, { 10800, 0 }, // ccp
+ { 16740, 0 }, { 21600, 4840 }, { 21600, 10800 }, // ccp
+ { 21600, 13520 }, { 20550, 16160 }, { 18670, 18170 } // ccp
+};
+const sal_uInt16 mso_sptFlowChartMagneticTapeSegm[] =
+{
+ 0x4000, 0x0002, 0x2004, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartMagneticTapeTextRect[] =
+{
+ { { 3100, 3100 }, { 18500, 18500 } }
+};
+const mso_CustomShape msoFlowChartMagneticTape =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartMagneticTapeVert), SAL_N_ELEMENTS( mso_sptFlowChartMagneticTapeVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartMagneticTapeSegm), sizeof( mso_sptFlowChartMagneticTapeSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartMagneticTapeTextRect), SAL_N_ELEMENTS( mso_sptFlowChartMagneticTapeTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartMagneticDiskVert[] =
+{
+ { 0, 3400 }, { 10800, 0 }, { 21600, 3400 }, { 21600, 18200 },
+ { 10800, 21600 }, { 0, 18200 },
+
+ { 0, 3400 }, { 10800, 6800 }, { 21600, 3400 }
+};
+const sal_uInt16 mso_sptFlowChartMagneticDiskSegm[] =
+{
+ 0x4000, 0xa802, 0x0001, 0xa802, 0x6000, 0x8000,
+ 0x4000, 0xa802, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartMagneticDiskTextRect[] =
+{
+ { { 0, 6800 }, { 21600, 18200 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartMagneticDiskGluePoints[] =
+{
+ { 10800, 6800 }, { 10800, 0 }, { 0, 10800 }, { 10800, 21600 }, { 21600, 10800 }
+};
+const mso_CustomShape msoFlowChartMagneticDisk =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartMagneticDiskVert), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDiskVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartMagneticDiskSegm), sizeof( mso_sptFlowChartMagneticDiskSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartMagneticDiskTextRect), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDiskTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartMagneticDiskGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDiskGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartMagneticDrumVert[] =
+{
+ { 18200, 0 }, { 21600, 10800 }, { 18200, 21600 }, { 3400, 21600 },
+ { 0, 10800 }, { 3400, 0 },
+
+ { 18200, 0 }, { 14800, 10800 }, { 18200, 21600 }
+};
+const sal_uInt16 mso_sptFlowChartMagneticDrumSegm[] =
+{
+ 0x4000, 0xa702, 0x0001, 0xa702, 0x6000, 0x8000,
+ 0x4000, 0xa702, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartMagneticDrumTextRect[] =
+{
+ { { 3400, 0 }, { 14800, 21600 } }
+};
+const SvxMSDffVertPair mso_sptFlowChartMagneticDrumGluePoints[] =
+{
+ { 10800, 0 }, { 0, 10800 }, { 10800, 21600 }, { 14800, 10800 }, { 21600, 10800 }
+};
+const mso_CustomShape msoFlowChartMagneticDrum =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartMagneticDrumVert), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDrumVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartMagneticDrumSegm), sizeof( mso_sptFlowChartMagneticDrumSegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartMagneticDrumTextRect), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDrumTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartMagneticDrumGluePoints), SAL_N_ELEMENTS( mso_sptFlowChartMagneticDrumGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptFlowChartDisplayVert[] =
+{
+ { 3600, 0 }, { 17800, 0 }, { 21600, 10800 }, { 17800, 21600 },
+ { 3600, 21600 }, { 0, 10800 }
+};
+const sal_uInt16 mso_sptFlowChartDisplaySegm[] =
+{
+ 0x4000, 0x0001, 0xa702, 0x0002, 0x6000, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptFlowChartDisplayTextRect[] =
+{
+ { { 3600, 0 }, { 17800, 21600 } }
+};
+const mso_CustomShape msoFlowChartDisplay =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptFlowChartDisplayVert), SAL_N_ELEMENTS( mso_sptFlowChartDisplayVert ),
+ const_cast<sal_uInt16*>(mso_sptFlowChartDisplaySegm), sizeof( mso_sptFlowChartDisplaySegm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFlowChartDisplayTextRect), SAL_N_ELEMENTS( mso_sptFlowChartDisplayTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptStandardGluePoints), SAL_N_ELEMENTS( mso_sptStandardGluePoints ),
+ nullptr, 0 // handles
+};
+
+const SvxMSDffVertPair mso_sptWedgeRectCalloutVert[] =
+{
+ { 0, 0 },
+ { 0, 3590 }, { 2 MSO_I, 3 MSO_I }, { 0, 8970 },
+ { 0, 12630 },{ 4 MSO_I, 5 MSO_I }, { 0, 18010 },
+ { 0, 21600 },
+ { 3590, 21600 }, { 6 MSO_I, 7 MSO_I }, { 8970, 21600 },
+ { 12630, 21600 }, { 8 MSO_I, 9 MSO_I }, { 18010, 21600 },
+ { 21600, 21600 },
+ { 21600, 18010 }, { 10 MSO_I, 11 MSO_I }, { 21600, 12630 },
+ { 21600, 8970 }, { 12 MSO_I, 13 MSO_I }, { 21600, 3590 },
+ { 21600, 0 },
+ { 18010, 0 }, { 14 MSO_I, 15 MSO_I }, { 12630, 0 },
+ { 8970, 0 }, { 16 MSO_I, 17 MSO_I }, { 3590, 0 },
+ { 0, 0 }
+};
+const SvxMSDffCalculationData mso_sptWedgeRectCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 10800 } }, //0x400
+ { 0x2000, { DFF_Prop_adjust2Value, 0,10800 } },
+ { 0x6006, { 0x412, DFF_Prop_adjustValue, 0 } }, //0x402
+ { 0x6006, { 0x412, DFF_Prop_adjust2Value, 6280 } },
+ { 0x6006, { 0x417, DFF_Prop_adjustValue, 0 } }, //0x404
+ { 0x6006, { 0x417, DFF_Prop_adjust2Value, 15320 } },
+ { 0x6006, { 0x41a, DFF_Prop_adjustValue, 6280 } }, //0x406
+ { 0x6006, { 0x41a, DFF_Prop_adjust2Value, 21600 } },
+ { 0x6006, { 0x41d, DFF_Prop_adjustValue, 15320 } }, //0x408
+ { 0x6006, { 0x41d, DFF_Prop_adjust2Value, 21600 } },
+ { 0x6006, { 0x420, DFF_Prop_adjustValue, 21600 } }, //0x40a
+ { 0x6006, { 0x420, DFF_Prop_adjust2Value, 15320 } },
+ { 0x6006, { 0x422, DFF_Prop_adjustValue, 21600 } }, //0x40c
+ { 0x6006, { 0x422, DFF_Prop_adjust2Value, 6280 } },
+ { 0x6006, { 0x424, DFF_Prop_adjustValue, 15320 } }, //0x40e
+ { 0x6006, { 0x424, DFF_Prop_adjust2Value, 0 } },
+ { 0x6006, { 0x426, DFF_Prop_adjustValue, 6280 } }, //0x410
+ { 0x6006, { 0x426, DFF_Prop_adjust2Value, 0 } },
+ { 0xa006, { DFF_Prop_adjustValue, -1, 0x413 } }, //0x412
+ { 0xa006, { 0x401, -1, 0x416 } },
+ { 0x2003, { 0x400, 0, 0 } }, //0x414
+ { 0x2003, { 0x401, 0, 0 } },
+ { 0xa000, { 0x414, 0, 0x415 } }, //0x416
+ { 0xa006, { DFF_Prop_adjustValue, -1, 0x418 } },
+ { 0x6006, { 0x401, 0x416, -1 } }, //0x418
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 21600 } },
+ { 0x6006, { 0x419, 0x41b, -1 } }, //0x41a
+ { 0xa006, { 0x400, -1, 0x41c } },
+ { 0xa000, { 0x415, 0, 0x414 } }, //0x41c
+ { 0x6006, { 0x419, 0x41e, -1 } },
+ { 0x6006, { 0x400, 0x41c, -1 } }, //0x41e
+ { 0x2000, { DFF_Prop_adjustValue, 0, 21600 } },
+ { 0x6006, { 0x41f, 0x421, -1 } }, //0x420
+ { 0x6006, { 0x401, 0x416, -1 } },
+ { 0x6006, { 0x41f, 0x423, -1 } }, //0x422
+ { 0xa006, { 0x401, -1, 0x416 } },
+ { 0xa006, { DFF_Prop_adjust2Value, -1, 0x425 } }, //0x424
+ { 0x6006, { 0x400, 0x41c, -1 } },
+ { 0xa006, { DFF_Prop_adjust2Value, -1, 0x427 } }, //0x426
+ { 0xa006, { 0x400, -1, 0x41c } },
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, //0x428
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } }
+};
+const sal_Int32 mso_sptWedgeRectCalloutDefault[] =
+{
+ 2, 1400, 25920
+};
+const SvxMSDffTextRectangles mso_sptWedgeRectCalloutTextRect[] =
+{
+ { { 0, 0 }, { 21600, 21600 } }
+};
+const SvxMSDffVertPair mso_sptWedgeRectCalloutGluePoints[] =
+{
+ { 10800, 0 }, { 0, 10800 }, { 10800, 21600 }, { 21600, 10800 }, { 40 MSO_I, 41 MSO_I }
+};
+const SvxMSDffHandle mso_sptCalloutHandle[] =
+{
+ {
+ SvxMSDffHandleFlags::NONE,
+ 0x100, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff
+ }
+};
+const mso_CustomShape msoWedgeRectCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptWedgeRectCalloutVert), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutVert ),
+ nullptr, 0,
+ const_cast<SvxMSDffCalculationData*>(mso_sptWedgeRectCalloutCalc), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptWedgeRectCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptWedgeRectCalloutTextRect), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptWedgeRectCalloutGluePoints), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle), SAL_N_ELEMENTS( mso_sptCalloutHandle ) // handles
+};
+const SvxMSDffVertPair mso_sptWedgeRRectCalloutVert[] =
+{
+ { 3590, 0 },
+ { 0, 3590 },
+ { 2 MSO_I, 3 MSO_I }, { 0, 8970 },
+ { 0, 12630 },{ 4 MSO_I, 5 MSO_I }, { 0, 18010 },
+ { 3590, 21600 },
+ { 6 MSO_I, 7 MSO_I }, { 8970, 21600 },
+ { 12630, 21600 }, { 8 MSO_I, 9 MSO_I }, { 18010, 21600 },
+ { 21600, 18010 },
+ { 10 MSO_I, 11 MSO_I }, { 21600, 12630 },
+ { 21600, 8970 }, { 12 MSO_I, 13 MSO_I }, { 21600, 3590 },
+ { 18010, 0 },
+ { 14 MSO_I, 15 MSO_I }, { 12630, 0 },
+ { 8970, 0 }, { 16 MSO_I, 17 MSO_I }
+};
+const sal_uInt16 mso_sptWedgeRRectCalloutSegm[] =
+{
+ 0x4000, 0xa701, 0x0005, 0xa801, 0x0005, 0xa701, 0x0005, 0xa801, 0x0004, 0x6001, 0x8000
+};
+const SvxMSDffTextRectangles mso_sptWedgeRRectCalloutTextRect[] =
+{
+ { { 800, 800 }, { 20800, 20800 } }
+};
+const mso_CustomShape msoWedgeRRectCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptWedgeRRectCalloutVert), SAL_N_ELEMENTS( mso_sptWedgeRRectCalloutVert ),
+ const_cast<sal_uInt16*>(mso_sptWedgeRRectCalloutSegm), sizeof( mso_sptWedgeRRectCalloutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptWedgeRectCalloutCalc), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptWedgeRectCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptWedgeRRectCalloutTextRect), SAL_N_ELEMENTS( mso_sptWedgeRRectCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle), SAL_N_ELEMENTS( mso_sptCalloutHandle ) // handles
+};
+const SvxMSDffVertPair mso_sptBalloonVert[] =
+{
+ { 3590, 0 },
+ { 0, 3590 },
+ { 0, 14460 },
+ { 3590, 18050 },
+ { 40 MSO_I, 21600 }, { 5420, 18050 },
+ { 18010, 18050 },
+ { 21600, 14460 },
+ { 21600, 3590 },
+ { 18010, 0 }
+};
+const sal_uInt16 mso_sptBalloonSegm[] =
+{
+ 0x4000, 0xa701, 0x0001, 0xa801, 0x0003, 0xa701, 0x0001, 0xa801, 0x6001, 0x8000
+};
+const SvxMSDffHandle mso_sptBalloonHandle[] =
+{
+ {
+ SvxMSDffHandleFlags::RANGE,
+ 0x100, 1, 10800, 10800, 0, 8990, MIN_INT32, 0x7fffffff
+ }
+};
+const SvxMSDffTextRectangles mso_sptBalloonTextRect[] =
+{
+ { { 800, 800 }, { 20800, 17250 } }
+};
+const mso_CustomShape msoBalloon =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBalloonVert), SAL_N_ELEMENTS( mso_sptBalloonVert ),
+ const_cast<sal_uInt16*>(mso_sptBalloonSegm), sizeof( mso_sptBalloonSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptWedgeRectCalloutCalc), SAL_N_ELEMENTS( mso_sptWedgeRectCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptWedgeRectCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptBalloonTextRect), SAL_N_ELEMENTS( mso_sptBalloonTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptBalloonHandle), SAL_N_ELEMENTS( mso_sptBalloonHandle ) // handles
+};
+const SvxMSDffVertPair mso_sptWedgeEllipseCalloutVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 0x16 MSO_I, 0x17 MSO_I }, { 0x12 MSO_I, 0x13 MSO_I }, { 0xe MSO_I, 0xf MSO_I }
+};
+const sal_uInt16 mso_sptWedgeEllipseCalloutSegm[] =
+{
+ 0xa504, 0x0001, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptWedgeEllipseCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 10800 } }, // 00 rad x
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 10800 } }, // 01 rad y
+ { 0x6001, { 0x400, 0x400, 1 } }, // 02 rad x^2
+ { 0x6001, { 0x401, 0x401, 1 } }, // 03 rad y^2
+ { 0x6000, { 0x402, 0x403, 0 } }, // 04
+ { 0x200d, { 0x404, 0, 0 } }, // 05
+ { 0x2000, { 0x405, 0, 10800 } }, // 06 > 0 ? spur needs to be drawn : 10800
+ { 0x6008, { 0x400, 0x401, 0 } }, // 07 atan2 -> angle
+ { 0x2000, { 0x407, 0, 10 } }, // 08
+ { 0x2000, { 0x407, 10, 0 } }, // 09
+ { 0x400a, { 10800, 0x407, 0 } }, // 0a
+ { 0x4009, { 10800, 0x407, 0 } }, // 0b
+ { 0x2000, { 0x40a, 10800, 0 } }, // 0c
+ { 0x2000, { 0x40b, 10800, 0 } }, // 0d
+ { 0xe006, { 0x406, DFF_Prop_adjustValue, 0x40c } }, // 0e
+ { 0xe006, { 0x406, DFF_Prop_adjust2Value, 0x40d } },// 0f
+ { 0x400a, { 10800, 0x408, 0 } }, // 10
+ { 0x4009, { 10800, 0x408, 0 } }, // 11
+ { 0x2000, { 0x410, 10800, 0 } }, // 12
+ { 0x2000, { 0x411, 10800, 0 } }, // 13
+ { 0x400a, { 10800, 0x409, 0 } }, // 14
+ { 0x4009, { 10800, 0x409, 0 } }, // 15
+ { 0x2000, { 0x414, 10800, 0 } }, // 16
+ { 0x2000, { 0x415, 10800, 0 } } // 17
+};
+const sal_Int32 mso_sptWedgeEllipseCalloutDefault[] =
+{
+ 2, 1350, 25920
+};
+const SvxMSDffVertPair mso_sptWedgeEllipseCalloutGluePoints[] =
+{
+ { 10800, 0 }, { 3160, 3160 }, { 0, 10800 }, { 3160, 18440 }, { 10800, 21600 }, { 18440, 18440 }, { 21600, 10800 }, { 18440, 3160 }, { 0xe MSO_I, 0xf MSO_I }
+};
+const SvxMSDffTextRectangles mso_sptWedgeEllipseCalloutTextRect[] =
+{
+ { { 3200, 3200 }, { 18400, 18400 } }
+};
+const mso_CustomShape msoWedgeEllipseCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptWedgeEllipseCalloutVert), SAL_N_ELEMENTS( mso_sptWedgeEllipseCalloutVert ),
+ const_cast<sal_uInt16*>(mso_sptWedgeEllipseCalloutSegm), sizeof( mso_sptWedgeEllipseCalloutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptWedgeEllipseCalloutCalc), SAL_N_ELEMENTS( mso_sptWedgeEllipseCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptWedgeEllipseCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptWedgeEllipseCalloutTextRect), SAL_N_ELEMENTS( mso_sptWedgeEllipseCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptWedgeEllipseCalloutGluePoints), SAL_N_ELEMENTS( mso_sptWedgeEllipseCalloutGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle), SAL_N_ELEMENTS( mso_sptCalloutHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptCloudCalloutVert[] =
+{
+ { 1930,7160 }, // p
+ { 1530,4490 }, { 3400,1970 }, { 5270,1970 }, // ccp
+ { 5860,1950 }, { 6470,2210 }, { 6970,2600 }, // ccp
+ { 7450,1390 }, { 8340,650 }, { 9340,650 }, // ccp
+ { 10004,690 }, { 10710,1050 }, { 11210,1700 }, // ccp
+ { 11570,630 }, { 12330,0 }, { 13150,0 }, // ccp
+ { 13840,0 }, { 14470,460 }, { 14870,1160 }, // ccp
+ { 15330,440 }, { 16020,0 }, { 16740,0 }, // ccp
+ { 17910,0 }, { 18900,1130 }, { 19110,2710 }, // ccp
+ { 20240,3150 }, { 21060,4580 }, { 21060,6220 }, // ccp
+ { 21060,6720 }, { 21000,7200 }, { 20830,7660 }, // ccp
+ { 21310,8460 }, { 21600,9450 }, { 21600,10460 }, // ccp
+ { 21600,12750 }, { 20310,14680 }, { 18650,15010 }, // ccp
+ { 18650,17200 }, { 17370,18920 }, { 15770,18920 }, // ccp
+ { 15220,18920 }, { 14700,18710 }, { 14240,18310 }, // ccp
+ { 13820,20240 }, { 12490,21600 }, { 11000,21600 }, // ccp
+ { 9890,21600 }, { 8840,20790 }, { 8210,19510 }, // ccp
+ { 7620,20000 }, { 7930,20290 }, { 6240,20290 }, // ccp
+ { 4850,20290 }, { 3570,19280 }, { 2900,17640 }, // ccp
+ { 1300,17600 }, { 480,16300 }, { 480,14660 }, // ccp
+ { 480,13900 }, { 690,13210 }, { 1070,12640 }, // ccp
+ { 380,12160 }, { 0,11210 }, { 0,10120 }, // ccp
+ { 0,8590 }, { 840,7330 }, { 1930,7160 }, // ccp
+
+ { 1930, 7160 }, { 1950, 7410 }, { 2040, 7690 }, { 2090, 7920 }, // pccp
+ { 6970, 2600 }, { 7200, 2790 }, { 7480, 3050 }, { 7670, 3310 }, // pccp
+ { 11210, 1700 }, { 11130, 1910 }, { 11080, 2160 }, { 11030, 2400 }, // pccp
+ { 14870, 1160 }, { 14720, 1400 }, { 14640, 1720 }, { 14540, 2010 }, // pccp
+ { 19110, 2710 }, { 19130, 2890 }, { 19230, 3290 }, { 19190, 3380 }, // pccp
+ { 20830, 7660 }, { 20660, 8170 }, { 20430, 8620 }, { 20110, 8990 }, // pccp
+ { 18660, 15010 }, { 18740, 14200 }, { 18280, 12200 }, { 17000, 11450 }, // pccp
+ { 14240, 18310 }, { 14320, 17980 }, { 14350, 17680 }, { 14370, 17360 }, // pccp
+ { 8220, 19510 }, { 8060, 19250 }, { 7960, 18950 }, { 7860, 18640 }, // pccp
+ { 2900, 17640 }, { 3090, 17600 }, { 3280, 17540 }, { 3460, 17450 }, // pccp
+ { 1070, 12640 }, { 1400, 12900 }, { 1780, 13130 }, { 2330, 13040 }, // pccp
+
+ { 0x11 MSO_I, 0x12 MSO_I }, { 1800, 1800 }, { 0, 360 }, // circ1
+ { 0x13 MSO_I, 0x14 MSO_I }, { 1200, 1200 }, { 0, 360 }, // circ2
+ { 0xd MSO_I, 0xe MSO_I }, { 700, 700 }, { 0, 360 } // circ3
+};
+const sal_uInt16 mso_sptCloudCalloutSegm[] =
+{
+ 0x4000, 0x2016, 0x6001, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0x4000, 0x2001, 0xaa00, 0x8000,
+ 0xa203, 0x6001, 0x8000,
+ 0xa203, 0x6001, 0x8000,
+ 0xa203, 0x6001, 0x8000
+};
+const SvxMSDffCalculationData mso_sptCloudCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 10800 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 10800 } },
+ { 0x6008, { 0x400, 0x401, 0 } },
+ { 0x400a, { 10800, 0x402, 0 } }, // 3
+ { 0x4009, { 10800, 0x402, 0 } }, // 4
+ { 0x2000, { 0x403, 10800, 0 } }, // 5
+ { 0x2000, { 0x404, 10800, 0 } }, // 6
+ { 0xa000, { DFF_Prop_adjustValue, 0, 0x405 } }, // 7
+ { 0xa000, { DFF_Prop_adjust2Value,0, 0x406 } }, // 8
+ { 0x2001, { 0x407, 1, 3 } }, // 9
+ { 0x2001, { 0x408, 1, 3 } }, // 0xa
+ { 0x2001, { 0x407, 2, 3 } }, // 0xb
+ { 0x2001, { 0x408, 2, 3 } }, // 0xc
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 0xd
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } }, // 0xe
+ { 0x2001, { 0x403, 1, 10800 / 900 } }, // 0xf taking half x distance of the radius from the first bobble
+ { 0x2001, { 0x404, 1, 10800 / 900 } }, // 0x10
+ { 0xe000, { 0x409, 0x405, 0x40f } }, // 0x11
+ { 0xe000, { 0x40a, 0x406, 0x410 } }, // 0x12
+ { 0x6000, { 0x40b, 0x405, 0 } }, // 0x13
+ { 0x6000, { 0x40c, 0x406, 0 } } // 0x14
+};
+const sal_Int32 mso_sptCloudCalloutDefault[] =
+{
+ 2, 1350, 25920
+};
+const SvxMSDffTextRectangles mso_sptCloudCalloutTextRect[] =
+{
+ { { 3000, 3320 }, { 17110, 17330 } }
+};
+const mso_CustomShape msoCloudCallout =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCloudCalloutVert), SAL_N_ELEMENTS( mso_sptCloudCalloutVert ),
+ const_cast<sal_uInt16*>(mso_sptCloudCalloutSegm), sizeof( mso_sptCloudCalloutSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCloudCalloutCalc), SAL_N_ELEMENTS( mso_sptCloudCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCloudCalloutDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptCloudCalloutTextRect), SAL_N_ELEMENTS( mso_sptCloudCalloutTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle), SAL_N_ELEMENTS( mso_sptCalloutHandle ) // handles
+};
+
+const SvxMSDffVertPair mso_sptWaveVert[] = // adjustment1 : 0 - 4460
+{ // adjustment2 : 8640 - 12960
+ { 7 MSO_I, 0 MSO_I }, { 15 MSO_I, 9 MSO_I }, { 16 MSO_I, 10 MSO_I }, { 12 MSO_I, 0 MSO_I },
+ { 24 MSO_I, 1 MSO_I }, { 25 MSO_I, 26 MSO_I }, { 27 MSO_I, 28 MSO_I }, { 29 MSO_I, 1 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptWaveCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, //400 (vert.adj)
+ { 0x8000, { 21600, 0, 0x400 } }, //401
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },//402 (horz.adj)
+ { 0x2000, { 0x402, 0, 10800 } }, //403 -2160 -> 2160 (horz.adj)
+ { 0x2001, { 0x403, 2, 1 } }, //404 -4320 -> 4320 (horz.adj)
+ { 0x2003, { 0x404, 0, 0 } }, //405 abs( 0x404 ) (horz.adj)
+ { 0x8000, { 4320, 0, 0x405 } }, //406
+ { 0xa006, { 0x403, 0, 0x405 } }, //407
+ { 0x4001, { 15800, 0x400, 4460 } }, //408 0 -> 15800 (vert.adj)
+ { 0xa000, { 0x400, 0, 0x408 } }, //409
+ { 0x6000, { 0x400, 0x408, 0 } }, //40a
+ { 0x8000, { 21600, 0, 0x404 } }, //40b
+ { 0x6006, { 0x403, 0x40b, 21600 } }, //40c
+ { 0xa000, { 0x40c, 0, 0x407 } }, //40d width between p0 and p1
+ { 0x2001, { 0x405, 1, 2 } }, //40e
+ { 0xa000, { 0x407, 7200, 0x40e } }, //40f
+ { 0x6000, { 0x40c, 0x40e, 7200 } }, //410
+ { 0x2001, { 0x40d, 1, 2 } }, //411 1/2 width
+ { 0x6000, { 0x407, 0x411, 0 } }, //412 top center glue xpos
+ { 0x8000, { 21600, 0, 0x412 } }, //413 bottom center glue xpos
+ { 0x2001, { 0x405, 1, 2 } }, //414 left glue x pos
+ { 0x8000, { 21600, 0, 0x414 } }, //415 right glue x pos
+ { 0x2001, { 0x400, 2, 1 } }, //416 y1 (textbox)
+ { 0x8000, { 21600, 0, 0x416 } }, //417 y2 (textbox)
+
+ { 0x8000, { 21600, 0, 0x407 } }, //418 p2
+
+ { 0x8000, { 21600, 0, 0x40f } }, //419 c
+ { 0x6000, { 0x401, 0x408, 0 } }, //41a
+
+ { 0x8000, { 21600, 0, 0x410 } }, //41b c
+ { 0xa000, { 0x401, 0, 0x408 } }, //41c
+
+ { 0x8000, { 21600, 0, 0x40c } } //41d p3
+};
+const SvxMSDffVertPair mso_sptWaveGluePoints[] =
+{
+ { 0x12 MSO_I, 0 MSO_I }, { 0x14 MSO_I, 10800 }, { 0x13 MSO_I, 1 MSO_I }, { 0x15 MSO_I, 10800 }
+};
+const sal_uInt16 mso_sptWaveSegm[] =
+{
+ 0x4000, 0x2001, 0x0001, 0x2001, 0x6000, 0x8000
+};
+const SvxMSDffHandle mso_sptWaveHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 4460 },
+ { SvxMSDffHandleFlags::RANGE,
+ 0x101, 21600, 10800, 10800, 8640, 12960, MIN_INT32, 0x7fffffff }
+};
+const sal_Int32 mso_sptWaveDefault[] =
+{
+ 2, 1400, 10800
+};
+const SvxMSDffTextRectangles mso_sptWaveTextRect[] =
+{
+ { { 5 MSO_I, 22 MSO_I }, { 11 MSO_I, 23 MSO_I } }
+};
+const mso_CustomShape msoWave =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptWaveVert), SAL_N_ELEMENTS( mso_sptWaveVert ),
+ const_cast<sal_uInt16*>(mso_sptWaveSegm), sizeof( mso_sptWaveSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptWaveCalc), SAL_N_ELEMENTS( mso_sptWaveCalc ),
+ const_cast<sal_Int32*>(mso_sptWaveDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptWaveTextRect), SAL_N_ELEMENTS( mso_sptWaveTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptWaveGluePoints), SAL_N_ELEMENTS( mso_sptWaveGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptWaveHandle), SAL_N_ELEMENTS( mso_sptWaveHandle )
+};
+
+const SvxMSDffVertPair mso_sptDoubleWaveVert[] = // adjustment1 : 0 - 2230
+{ // adjustment2 : 8640 - 12960
+ { 7 MSO_I, 0 MSO_I }, { 15 MSO_I, 9 MSO_I }, { 0x1f MSO_I, 10 MSO_I }, { 0x12 MSO_I, 0 MSO_I }, { 0x1e MSO_I, 9 MSO_I }, { 16 MSO_I, 10 MSO_I }, { 12 MSO_I, 0 MSO_I },
+ { 24 MSO_I, 1 MSO_I }, { 25 MSO_I, 26 MSO_I }, { 0x20 MSO_I, 28 MSO_I }, { 0x13 MSO_I, 1 MSO_I }, { 0x21 MSO_I, 26 MSO_I }, { 27 MSO_I, 28 MSO_I }, { 29 MSO_I, 1 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptDoubleWaveCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, //400 (vert.adj)
+ { 0x8000, { 21600, 0, 0x400 } }, //401
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },//402 (horz.adj)
+ { 0x2000, { 0x402, 0, 10800 } }, //403 -2160 -> 2160 (horz.adj)
+ { 0x2001, { 0x403, 2, 1 } }, //404 -4320 -> 4320 (horz.adj)
+ { 0x2003, { 0x404, 0, 0 } }, //405 abs( 0x404 ) (horz.adj)
+ { 0x8000, { 4320, 0, 0x405 } }, //406 -> not used
+ { 0xa006, { 0x403, 0, 0x405 } }, //407
+ { 0x4001, { 7900, 0x400, 2230 } }, //408 0 -> 7900 (vert.adj)
+ { 0xa000, { 0x400, 0, 0x408 } }, //409
+ { 0x6000, { 0x400, 0x408, 0 } }, //40a
+ { 0x8000, { 21600, 0, 0x404 } }, //40b
+ { 0x6006, { 0x403, 0x40b, 21600 } }, //40c
+ { 0xa000, { 0x40c, 0, 0x407 } }, //40d width between p0 and p1
+ { 0x2001, { 0x405, 1, 2 } }, //40e
+ { 0xa000, { 0x407, 3600, 0x40e } }, //40f
+ { 0x6000, { 0x40c, 0x40e, 3600 } }, //410
+ { 0x2001, { 0x40d, 1, 2 } }, //411 1/2 width
+ { 0x6000, { 0x407, 0x411, 0 } }, //412 top center glue xpos
+ { 0x8000, { 21600, 0, 0x412 } }, //413 bottom center glue xpos
+ { 0x2001, { 0x405, 1, 2 } }, //414 left glue x pos
+ { 0x8000, { 21600, 0, 0x414 } }, //415 right glue x pos
+ { 0x2001, { 0x400, 2, 1 } }, //416 y1 (textbox)
+ { 0x8000, { 21600, 0, 0x416 } }, //417 y2 (textbox)
+
+ { 0x8000, { 21600, 0, 0x407 } }, //418 p2
+
+ { 0x8000, { 21600, 0, 0x40f } }, //419 c
+ { 0x6000, { 0x401, 0x408, 0 } }, //41a
+
+ { 0x8000, { 21600, 0, 0x410 } }, //41b c
+ { 0xa000, { 0x401, 0, 0x408 } }, //41c
+
+ { 0x8000, { 21600, 0, 0x40c } }, //41d p3
+ { 0xa000, { 0x412, 3600, 0x40e } }, //41e
+ { 0x6000, { 0x412, 0x40e, 3600 } }, //41f
+ { 0xa000, { 0x413, 3600, 0x40e } }, //420
+ { 0x6000, { 0x413, 0x40e, 3600 } } //421
+};
+const SvxMSDffVertPair mso_sptDoubleWaveGluePoints[] =
+{
+ { 0x12 MSO_I, 0 MSO_I }, { 0x14 MSO_I, 10800 }, { 0x13 MSO_I, 1 MSO_I }, { 0x15 MSO_I, 10800 }
+};
+const sal_uInt16 mso_sptDoubleWaveSegm[] =
+{
+ 0x4000, 0x2002, 0x0001, 0x2002, 0x6000, 0x8000
+};
+const SvxMSDffHandle mso_sptDoubleWaveHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 2230 },
+ { SvxMSDffHandleFlags::RANGE,
+ 0x101, 21600, 10800, 10800, 8640, 12960, MIN_INT32, 0x7fffffff }
+};
+const sal_Int32 mso_sptDoubleWaveDefault[] =
+{
+ 2, 1400, 10800
+};
+const SvxMSDffTextRectangles mso_sptDoubleWaveTextRect[] =
+{
+ { { 5 MSO_I, 22 MSO_I }, { 11 MSO_I, 23 MSO_I } }
+};
+const mso_CustomShape msoDoubleWave =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptDoubleWaveVert), SAL_N_ELEMENTS( mso_sptDoubleWaveVert ),
+ const_cast<sal_uInt16*>(mso_sptDoubleWaveSegm), sizeof( mso_sptDoubleWaveSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptDoubleWaveCalc), SAL_N_ELEMENTS( mso_sptDoubleWaveCalc ),
+ const_cast<sal_Int32*>(mso_sptDoubleWaveDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptDoubleWaveTextRect), SAL_N_ELEMENTS( mso_sptDoubleWaveTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptDoubleWaveGluePoints), SAL_N_ELEMENTS( mso_sptDoubleWaveGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptDoubleWaveHandle), SAL_N_ELEMENTS( mso_sptDoubleWaveHandle )
+};
+
+// for each shapetype a bit of 1 is indicating that the shape is NOT filled by default
+const sal_uInt16 mso_DefaultFillingTable[] =
+{
+ 0x0000, 0x0018, 0x01ff, 0x0000, 0x0c00, 0x01e0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
+};
+bool IsCustomShapeFilledByDefault( MSO_SPT eSpType )
+{
+ bool bIsFilledByDefault = true;
+ sal_uInt32 i = static_cast<sal_uInt32>(eSpType);
+ if ( i < 0x100 )
+ bIsFilledByDefault = ( mso_DefaultFillingTable[ i >> 4 ] & ( 1 << ( i & 0xf ) ) ) == 0;
+ return bIsFilledByDefault;
+}
+sal_Int16 GetCustomShapeConnectionTypeDefault( MSO_SPT eSpType )
+{
+ sal_Int16 nGluePointType = css::drawing::EnhancedCustomShapeGluePointType::SEGMENTS;
+ const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eSpType );
+ if ( pDefCustomShape && pDefCustomShape->nGluePoints )
+ nGluePointType = css::drawing::EnhancedCustomShapeGluePointType::CUSTOM;
+ else
+ {
+ switch( eSpType )
+ {
+ case mso_sptRectangle :
+ case mso_sptRoundRectangle :
+ case mso_sptPictureFrame :
+ case mso_sptFlowChartProcess :
+ case mso_sptFlowChartPredefinedProcess :
+ case mso_sptFlowChartInternalStorage :
+ case mso_sptTextPlainText :
+ case mso_sptTextBox :
+ case mso_sptVerticalScroll :
+ case mso_sptHorizontalScroll :
+ nGluePointType = css::drawing::EnhancedCustomShapeGluePointType::RECT;
+ break;
+ default: break;
+ }
+ }
+ return nGluePointType;
+}
+
+// for each shapetype a bit of 1 is indicating that the shape is NOT stroked by default
+// #i28269#
+const sal_uInt16 mso_DefaultStrokingTable[] =
+{
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0800, 0x0000, 0x0000, 0x0000, // #i28269# Added shape 75 (mso_sptPictureFrame)
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000
+};
+// #i28269#
+bool IsCustomShapeStrokedByDefault( MSO_SPT eSpType )
+{
+ bool bIsStrokedByDefault = true;
+ sal_uInt32 i = static_cast<sal_uInt32>(eSpType);
+ if ( i < 0x100 )
+ bIsStrokedByDefault = ( mso_DefaultStrokingTable[ i >> 4 ] & ( 1 << ( i & 0xf ) ) ) == 0;
+ return bIsStrokedByDefault;
+}
+
+const sal_uInt16 msoSortFilledObjectsToBackTable[] =
+{
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+bool SortFilledObjectsToBackByDefault( MSO_SPT eSpType )
+{
+ bool bSortFilledObjectsToBackByDefault = true;
+ sal_uInt32 i = static_cast<sal_uInt32>(eSpType);
+ if ( i < 0x100 )
+ bSortFilledObjectsToBackByDefault = ( msoSortFilledObjectsToBackTable[ i >> 4 ] & ( 1 << ( i & 0xf ) ) ) != 0;
+ return bSortFilledObjectsToBackByDefault;
+}
+
+const SvxMSDffTextRectangles mso_sptFontWorkTextRect[] =
+{
+ { { 0, 0 }, { 21600, 21600 } }
+};
+
+const SvxMSDffVertPair mso_sptTextPlainTextVert[] =
+{
+ { 3 MSO_I, 0 }, { 5 MSO_I, 0 }, { 6 MSO_I, 21600 }, { 7 MSO_I, 21600 }
+};
+const SvxMSDffCalculationData mso_sptTextPlainTextCalc[] = // adjustment1 : 6629 - 14971
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 10800 } },
+ { 0x2001, { 0x400, 2, 1 } },
+ { 0x2003, { 0x401, 0, 0 } },
+ { 0xa006, { 0x401, 0, 0x402 } }, // x1(3)
+ { 0x8000, { 21600, 0, 0x402 } },
+ { 0x6006, { 0x401, 0x404, 21600 } }, // x2(5)
+ { 0x6006, { 0x401, 0x402, 0 } }, // x2
+ { 0xa006, { 0x401, 21600, 0x404 } } // x3(7)
+};
+const sal_uInt16 mso_sptTextPlainTextSegm[] =
+{
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffHandle mso_sptTextPlainTextHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 21600, 10800, 10800, 6629, 14971, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoTextPlainText =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextPlainTextVert), SAL_N_ELEMENTS( mso_sptTextPlainTextVert ),
+ const_cast<sal_uInt16*>(mso_sptTextPlainTextSegm), sizeof( mso_sptTextPlainTextSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextPlainTextCalc), SAL_N_ELEMENTS( mso_sptTextPlainTextCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault10800),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextPlainTextHandle), SAL_N_ELEMENTS( mso_sptTextPlainTextHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextStopVert[] =
+{
+ { 0, 0 MSO_I }, { 7200, 0 }, { 14400, 0 }, { 21600, 0 MSO_I },
+ { 0, 1 MSO_I }, { 7200, 21600 }, { 14400, 21600 }, { 21600, 1 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextStopCalc[] = // adjustment1 : 3080 - 10800
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }
+};
+const sal_uInt16 mso_sptTextStopSegm[] =
+{
+ 0x4000, 0x0003, 0x8000,
+ 0x4000, 0x0003, 0x8000
+};
+const sal_Int32 mso_sptTextStopDefault[] =
+{
+ 1, 2700
+};
+const SvxMSDffHandle mso_sptTextStopHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 3080, 10800 }
+};
+const mso_CustomShape msoTextStop =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextStopVert), SAL_N_ELEMENTS( mso_sptTextStopVert ),
+ const_cast<sal_uInt16*>(mso_sptTextStopSegm), sizeof( mso_sptTextStopSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextStopCalc), SAL_N_ELEMENTS( mso_sptTextStopCalc ),
+ const_cast<sal_Int32*>(mso_sptTextStopDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextStopHandle), SAL_N_ELEMENTS( mso_sptTextStopHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextTriangleVert[] =
+{
+ { 0, 0 MSO_I }, { 10800, 0 }, { 21600, 0 MSO_I }, { 0, 21600 }, { 21600, 21600 }
+};
+const SvxMSDffCalculationData mso_sptTextTriangleCalc[] = // adjustment1 : 6629 - 14971
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }
+};
+const sal_uInt16 mso_sptTextTriangleSegm[] =
+{
+ 0x4000, 0x0002, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffHandle mso_sptTextTriangleHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 21600 }
+};
+const mso_CustomShape msoTextTriangle =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextTriangleVert), SAL_N_ELEMENTS( mso_sptTextTriangleVert ),
+ const_cast<sal_uInt16*>(mso_sptTextTriangleSegm), sizeof( mso_sptTextTriangleSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextTriangleCalc), SAL_N_ELEMENTS( mso_sptTextTriangleCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault10800),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextTriangleHandle), SAL_N_ELEMENTS( mso_sptTextTriangleHandle )
+};
+const SvxMSDffVertPair mso_sptTextTriangleInvertedVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 0, 0 MSO_I }, { 10800, 21600 }, { 21600, 0 MSO_I }
+};
+const sal_uInt16 mso_sptTextTriangleInvertedSegm[] =
+{
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0002, 0x8000
+};
+const mso_CustomShape msoTextTriangleInverted =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextTriangleInvertedVert), SAL_N_ELEMENTS( mso_sptTextTriangleInvertedVert ),
+ const_cast<sal_uInt16*>(mso_sptTextTriangleInvertedSegm), sizeof( mso_sptTextTriangleInvertedSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextTriangleCalc), SAL_N_ELEMENTS( mso_sptTextTriangleCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault10800),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextTriangleHandle), SAL_N_ELEMENTS( mso_sptTextTriangleHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextChevronVert[] =
+{
+ { 0, 0 MSO_I }, { 10800, 0 }, { 21600, 0 MSO_I }, { 0, 21600 }, { 10800, 1 MSO_I }, { 21600, 21600 }
+};
+const SvxMSDffCalculationData mso_sptTextChevronCalc[] = // adjustment1 : 6629 - 14971
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }
+};
+const sal_uInt16 mso_sptTextChevronSegm[] =
+{
+ 0x4000, 0x0002, 0x8000,
+ 0x4000, 0x0002, 0x8000
+};
+const SvxMSDffHandle mso_sptTextChevronHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10800 }
+};
+const mso_CustomShape msoTextChevron =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextChevronVert), SAL_N_ELEMENTS( mso_sptTextChevronVert ),
+ const_cast<sal_uInt16*>(mso_sptTextChevronSegm), sizeof( mso_sptTextChevronSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextChevronCalc), SAL_N_ELEMENTS( mso_sptTextChevronCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault5400),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextChevronHandle), SAL_N_ELEMENTS( mso_sptTextChevronHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextChevronInvertedVert[] =
+{
+ { 0, 0 }, { 10800, 1 MSO_I }, { 21600, 0 }, { 0, 0 MSO_I }, { 10800, 21600 }, { 21600, 0 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextChevronInvertedCalc[] = // adjustment1 : 6629 - 14971
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }
+};
+const sal_uInt16 mso_sptTextChevronInvertedSegm[] =
+{
+ 0x4000, 0x0002, 0x8000,
+ 0x4000, 0x0002, 0x8000
+};
+const SvxMSDffHandle mso_sptTextChevronInvertedHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 10800, 21600 }
+};
+const mso_CustomShape msoTextChevronInverted =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextChevronInvertedVert), SAL_N_ELEMENTS( mso_sptTextChevronInvertedVert ),
+ const_cast<sal_uInt16*>(mso_sptTextChevronInvertedSegm), sizeof( mso_sptTextChevronInvertedSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextChevronInvertedCalc), SAL_N_ELEMENTS( mso_sptTextChevronInvertedCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault16200),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextChevronInvertedHandle), SAL_N_ELEMENTS( mso_sptTextChevronInvertedHandle )
+};
+//V 0 0 21600 ?f2 0 ?f0 21600 ?f0
+//W 0 0 21600 ?f2 21600 ?f0 0 ?f0 N
+//V 0 ?f3 21600 21600 0 ?f1 21600 ?f1
+//W 0 ?f3 21600 21600 21600 ?f1 0 ?f1 N
+//mso_sptTextRingInside
+const SvxMSDffVertPair mso_sptTextRingInsideVert[] =
+{
+ { 0, 0 }, { 21600, 2 MSO_I }, { 0, 0 MSO_I },{ 21600, 0 MSO_I },//V
+ { 0, 0 }, { 21600, 2 MSO_I }, { 21600, 0 MSO_I },{ 0, 0 MSO_I },//W
+ { 0, 3 MSO_I }, { 21600, 21600 }, { 0, 1 MSO_I },{ 21600, 1 MSO_I },//V
+ { 0, 3 MSO_I }, { 21600, 21600 }, { 21600, 1 MSO_I },{ 0, 1 MSO_I }//W
+};
+const SvxMSDffCalculationData mso_sptTextRingInsideCalc[] = // adjustment1 : 6629 - 14971
+{
+ { 0x2001, { DFF_Prop_adjustValue, 1, 2 } },
+ { 0x8000, { 21600, 0, 0x400 } },
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, //$0
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }//21600-$0
+};
+const sal_uInt16 mso_sptTextRingInsideSegm[] =
+{
+ 0xa604, 0xa504,0x8000,
+ 0xa604, 0xa504,0x8000
+};
+const SvxMSDffHandle mso_sptTextRingInsideHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE| SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 10800, 21600 }
+};
+const mso_CustomShape msoTextRingInside =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextRingInsideVert), SAL_N_ELEMENTS( mso_sptTextRingInsideVert ),
+ const_cast<sal_uInt16*>(mso_sptTextRingInsideSegm), sizeof( mso_sptTextRingInsideSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextRingInsideCalc), SAL_N_ELEMENTS( mso_sptTextRingInsideCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault13500),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextRingInsideHandle), SAL_N_ELEMENTS( mso_sptTextRingInsideHandle )
+};
+//mso_sptTextRingOutside
+//path = U 10800 ?f0 10800 ?f2 180 539 N U 10800 ?f1 10800 ?f2 180 539 N
+// MSO binary format has swing angle, not end angle, therefore 359 instead of 539.
+const SvxMSDffVertPair mso_sptTextRingOutsideVert[] =
+{
+ { 10800, 0 MSO_I }, { 10800, 0 MSO_I }, { 180, 359 },
+ { 10800, 1 MSO_I }, { 10800, 0 MSO_I }, { 180, 359 }
+};
+const SvxMSDffCalculationData mso_sptTextRingOutsideCalc[] = // adjustment1 : 6629 - 14971
+{
+ { 0x2001, { DFF_Prop_adjustValue, 1, 2 } },
+ { 0x8000, { 21600, 0, 0x400 } }
+};
+const sal_uInt16 mso_sptTextRingOutsideSegm[] =
+{
+ 0xA203, 0x8000,
+ 0xA203, 0x8000
+};
+const SvxMSDffHandle mso_sptTextRingOutsideHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 10800, 21600 }
+};
+const mso_CustomShape msoTextRingOutside =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextRingOutsideVert), SAL_N_ELEMENTS( mso_sptTextRingOutsideVert ),
+ const_cast<sal_uInt16*>(mso_sptTextRingOutsideSegm), sizeof( mso_sptTextRingOutsideSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextRingOutsideCalc), SAL_N_ELEMENTS( mso_sptTextRingOutsideCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault13500),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextRingOutsideHandle), SAL_N_ELEMENTS( mso_sptTextRingOutsideHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextFadeRightVert[] =
+{
+ { 0, 0 }, { 21600, 0 MSO_I }, { 0, 21600 }, { 21600, 1 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextFadeCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }
+};
+const sal_uInt16 mso_sptTextFadeSegm[] =
+{
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffHandle mso_sptTextFadeRightHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 21600, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10800 }
+};
+const mso_CustomShape msoTextFadeRight =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextFadeRightVert), SAL_N_ELEMENTS( mso_sptTextFadeRightVert ),
+ const_cast<sal_uInt16*>(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault7200),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextFadeRightHandle), SAL_N_ELEMENTS( mso_sptTextFadeRightHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextFadeLeftVert[] =
+{
+ { 0, 0 MSO_I }, { 21600, 0 }, { 0, 1 MSO_I }, { 21600, 21600 }
+};
+const SvxMSDffHandle mso_sptTextFadeLeftHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10800 }
+};
+const mso_CustomShape msoTextFadeLeft =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextFadeLeftVert), SAL_N_ELEMENTS( mso_sptTextFadeLeftVert ),
+ const_cast<sal_uInt16*>(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault7200),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextFadeLeftHandle), SAL_N_ELEMENTS( mso_sptTextFadeLeftHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextFadeUpVert[] =
+{
+ { 0 MSO_I, 0 }, { 1 MSO_I, 0 }, { 0, 21600 }, { 21600, 21600 }
+};
+const SvxMSDffHandle mso_sptTextFadeUpHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 0, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoTextFadeUp =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextFadeUpVert), SAL_N_ELEMENTS( mso_sptTextFadeUpVert ),
+ const_cast<sal_uInt16*>(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault7200),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextFadeUpHandle), SAL_N_ELEMENTS( mso_sptTextFadeUpHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextFadeDownVert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 0 MSO_I, 21600 }, { 1 MSO_I, 21600 }
+};
+const SvxMSDffHandle mso_sptTextFadeDownHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 21600, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoTextFadeDown =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextFadeDownVert), SAL_N_ELEMENTS( mso_sptTextFadeDownVert ),
+ const_cast<sal_uInt16*>(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault7200),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextFadeDownHandle), SAL_N_ELEMENTS( mso_sptTextFadeDownHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextSlantUpVert[] =
+{
+ { 0, 0 MSO_I }, { 21600, 0 }, { 0, 21600 }, { 21600, 1 MSO_I }
+};
+const SvxMSDffHandle mso_sptTextSlantUpHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 15400 }
+};
+const mso_CustomShape msoTextSlantUp =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextSlantUpVert), SAL_N_ELEMENTS( mso_sptTextSlantUpVert ),
+ const_cast<sal_uInt16*>(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault12000),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextSlantUpHandle), SAL_N_ELEMENTS( mso_sptTextSlantUpHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextSlantDownVert[] =
+{
+ { 0, 0 }, { 21600, 1 MSO_I }, { 0, 0 MSO_I }, { 21600, 21600 }
+};
+const SvxMSDffHandle mso_sptTextSlantDownHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 6200, 21600 }
+};
+const mso_CustomShape msoTextSlantDown =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextSlantDownVert), SAL_N_ELEMENTS( mso_sptTextSlantDownVert ),
+ const_cast<sal_uInt16*>(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextFadeCalc), SAL_N_ELEMENTS( mso_sptTextFadeCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault12000),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextSlantDownHandle), SAL_N_ELEMENTS( mso_sptTextSlantDownHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextCascadeUpVert[] =
+{
+ { 0, 2 MSO_I }, { 21600, 0 }, { 0, 21600 }, { 21600, 0 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextCascadeCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } },
+ { 0x2001, { 0x401, 1, 4 } }
+};
+const SvxMSDffHandle mso_sptTextCascadeUpHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 21600, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 6200, 21600 }
+};
+const mso_CustomShape msoTextCascadeUp =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextCascadeUpVert), SAL_N_ELEMENTS( mso_sptTextCascadeUpVert ),
+ const_cast<sal_uInt16*>(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextCascadeCalc), SAL_N_ELEMENTS( mso_sptTextCascadeCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault9600),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextCascadeUpHandle), SAL_N_ELEMENTS( mso_sptTextCascadeUpHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextCascadeDownVert[] =
+{
+ { 0, 0 }, { 21600, 2 MSO_I }, { 0, 0 MSO_I }, { 21600, 21600 }
+};
+const SvxMSDffHandle mso_sptTextCascadeDownHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 6200, 21600 }
+};
+const mso_CustomShape msoTextCascadeDown =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextCascadeDownVert), SAL_N_ELEMENTS( mso_sptTextCascadeDownVert ),
+ const_cast<sal_uInt16*>(mso_sptTextFadeSegm), sizeof( mso_sptTextFadeSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextCascadeCalc), SAL_N_ELEMENTS( mso_sptTextCascadeCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault9600),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextCascadeDownHandle), SAL_N_ELEMENTS( mso_sptTextCascadeDownHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextArchUpCurveVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 2 MSO_I, 3 MSO_I }, { 4 MSO_I, 3 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextArchCurveCalc[] =
+{
+ { 0x400a, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x4009, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x2000, { 0x400, 10800, 0 } },
+ { 0x2000, { 0x401, 10800, 0 } },
+ { 0x8000, { 21600, 0, 0x402 } }
+};
+const sal_uInt16 mso_sptTextArchUpCurveSegm[] =
+{
+ 0xA504, 0x8000 // clockwise arc
+};
+const SvxMSDffHandle mso_sptTextArchUpCurveHandle[] =
+{
+ { SvxMSDffHandleFlags::POLAR,
+ 10800, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const sal_Int32 mso_sptTextArchUpCurveDefault[] =
+{
+ 1, 180
+};
+const mso_CustomShape msoTextArchUpCurve =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextArchUpCurveVert), SAL_N_ELEMENTS( mso_sptTextArchUpCurveVert ),
+ const_cast<sal_uInt16*>(mso_sptTextArchUpCurveSegm), sizeof( mso_sptTextArchUpCurveSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextArchCurveCalc), SAL_N_ELEMENTS( mso_sptTextArchCurveCalc ),
+ const_cast<sal_Int32*>(mso_sptTextArchUpCurveDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextArchUpCurveHandle), SAL_N_ELEMENTS( mso_sptTextArchUpCurveHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextArchDownCurveVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 4 MSO_I, 3 MSO_I }, { 2 MSO_I, 3 MSO_I }
+};
+const sal_uInt16 mso_sptTextArchDownCurveSegm[] =
+{
+ 0xA304, 0x8000 // counter clockwise arc to
+};
+const SvxMSDffHandle mso_sptTextArchDownCurveHandle[] =
+{
+ { SvxMSDffHandleFlags::POLAR,
+ 10800, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const sal_Int32 mso_sptTextArchDownCurveDefault[] =
+{
+ 1, 0
+};
+const mso_CustomShape msoTextArchDownCurve =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextArchDownCurveVert), SAL_N_ELEMENTS( mso_sptTextArchDownCurveVert ),
+ const_cast<sal_uInt16*>(mso_sptTextArchDownCurveSegm), sizeof( mso_sptTextArchDownCurveSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextArchCurveCalc), SAL_N_ELEMENTS( mso_sptTextArchCurveCalc ),
+ const_cast<sal_Int32*>(mso_sptTextArchDownCurveDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextArchDownCurveHandle), SAL_N_ELEMENTS( mso_sptTextArchDownCurveHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextCircleCurveVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 2 MSO_I, 3 MSO_I }, { 2 MSO_I, 4 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextCircleCurveCalc[] =
+{
+ { 0x400a, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x4009, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x2000, { 0x400, 10800, 0 } },
+ { 0x2000, { 0x401, 10800, 0 } },
+ { 0x8000, { 21600, 0, 0x403 } }
+};
+const sal_uInt16 mso_sptTextCircleCurveSegm[] =
+{
+ 0xA504, 0x8000 // clockwise arc to
+};
+const SvxMSDffHandle mso_sptTextCircleCurveHandle[] =
+{
+ { SvxMSDffHandleFlags::POLAR,
+ 10800, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const sal_Int32 mso_sptTextCircleCurveDefault[] =
+{
+ 1, -179
+};
+const mso_CustomShape msoTextCircleCurve =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextCircleCurveVert), SAL_N_ELEMENTS( mso_sptTextCircleCurveVert ),
+ const_cast<sal_uInt16*>(mso_sptTextCircleCurveSegm), sizeof( mso_sptTextCircleCurveSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextCircleCurveCalc), SAL_N_ELEMENTS( mso_sptTextCircleCurveCalc ),
+ const_cast<sal_Int32*>(mso_sptTextCircleCurveDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextCircleCurveHandle), SAL_N_ELEMENTS( mso_sptTextCircleCurveHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextButtonCurveVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 2 MSO_I, 3 MSO_I }, { 4 MSO_I, 3 MSO_I },
+ { 0, 10800 }, { 21600, 10800 },
+ { 0, 0 }, { 21600, 21600 }, { 2 MSO_I, 5 MSO_I }, { 4 MSO_I, 5 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextButtonCurveCalc[] =
+{
+ { 0x400a, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x4009, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x2000, { 0x400, 10800, 0 } },
+ { 0x2000, { 0x401, 10800, 0 } },
+ { 0x8000, { 21600, 0, 0x402 } },
+ { 0x8000, { 21600, 0, 0x403 } }
+};
+const sal_uInt16 mso_sptTextButtonCurveSegm[] =
+{
+ 0xA504, 0x8000, // clockwise arc
+ 0x4000, 0x0001, 0x8000,
+ 0xA304, 0x8000 // counter clockwise
+};
+const SvxMSDffHandle mso_sptTextButtonCurveHandle[] =
+{
+ { SvxMSDffHandleFlags::POLAR,
+ 10800, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const sal_Int32 mso_sptTextButtonCurveDefault[] =
+{
+ 1, 180
+};
+const mso_CustomShape msoTextButtonCurve =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextButtonCurveVert), SAL_N_ELEMENTS( mso_sptTextButtonCurveVert ),
+ const_cast<sal_uInt16*>(mso_sptTextButtonCurveSegm), sizeof( mso_sptTextButtonCurveSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextButtonCurveCalc), SAL_N_ELEMENTS( mso_sptTextButtonCurveCalc ),
+ const_cast<sal_Int32*>(mso_sptTextButtonCurveDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextButtonCurveHandle), SAL_N_ELEMENTS( mso_sptTextButtonCurveHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextArchUpPourVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 2 MSO_I, 3 MSO_I }, { 4 MSO_I, 3 MSO_I },
+ { 5 MSO_I, 5 MSO_I }, { 11 MSO_I, 11 MSO_I }, { 8 MSO_I, 9 MSO_I }, { 0xa MSO_I, 9 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextArchPourCalc[] =
+{
+ { 0x400a, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x4009, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x2000, { 0x400, 10800, 0 } },
+ { 0x2000, { 0x401, 10800, 0 } },
+ { 0x8000, { 21600, 0, 0x402 } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjust2Value } },
+ { 0x600a, { 0x405, DFF_Prop_adjustValue, 0 } }, // 6
+ { 0x6009, { 0x405, DFF_Prop_adjustValue, 0 } },
+ { 0x2000, { 0x406, 10800, 0 } }, // 8
+ { 0x2000, { 0x407, 10800, 0 } },
+ { 0x8000, { 21600, 0, 0x408 } }, // 10
+ { 0x8000, { 21600, 0, 0x405 } }
+};
+const sal_uInt16 mso_sptTextArchUpPourSegm[] =
+{
+ 0xA504, 0x8000, 0xA504, 0x8000
+};
+const SvxMSDffHandle mso_sptTextArchPourHandle[] =
+{
+ { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE,
+ 0x101, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const sal_Int32 mso_sptTextArchUpPourDefault[] =
+{
+ 2, 180, 5400
+};
+const mso_CustomShape msoTextArchUpPour =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextArchUpPourVert), SAL_N_ELEMENTS( mso_sptTextArchUpPourVert ),
+ const_cast<sal_uInt16*>(mso_sptTextArchUpPourSegm), sizeof( mso_sptTextArchUpPourSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextArchPourCalc), SAL_N_ELEMENTS( mso_sptTextArchPourCalc ),
+ const_cast<sal_Int32*>(mso_sptTextArchUpPourDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextArchPourHandle), SAL_N_ELEMENTS( mso_sptTextArchPourHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextArchDownPourVert[] =
+{
+ { 5 MSO_I, 5 MSO_I }, { 11 MSO_I, 11 MSO_I }, { 0xa MSO_I, 9 MSO_I }, { 8 MSO_I, 9 MSO_I },
+ { 0, 0 }, { 21600, 21600 }, { 4 MSO_I, 3 MSO_I }, { 2 MSO_I, 3 MSO_I }
+};
+const sal_uInt16 mso_sptTextArchDownPourSegm[] =
+{
+ 0xA304, 0x8000, 0xA304, 0x8000
+};
+const sal_Int32 mso_sptTextArchDownPourDefault[] =
+{
+ 2, 0, 5400
+};
+const mso_CustomShape msoTextArchDownPour =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextArchDownPourVert), SAL_N_ELEMENTS( mso_sptTextArchDownPourVert ),
+ const_cast<sal_uInt16*>(mso_sptTextArchDownPourSegm), sizeof( mso_sptTextArchDownPourSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextArchPourCalc), SAL_N_ELEMENTS( mso_sptTextArchPourCalc ),
+ const_cast<sal_Int32*>(mso_sptTextArchDownPourDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextArchPourHandle), SAL_N_ELEMENTS( mso_sptTextArchPourHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextCirclePourVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 2 MSO_I, 3 MSO_I }, { 2 MSO_I, 4 MSO_I },
+ { 5 MSO_I, 5 MSO_I }, { 11 MSO_I, 11 MSO_I }, { 8 MSO_I, 9 MSO_I }, { 8 MSO_I, 0xa MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextCirclePourCalc[] =
+{
+ { 0x400a, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x4009, { 10800, DFF_Prop_adjustValue, 0 } },
+ { 0x2000, { 0x400, 10800, 0 } },
+ { 0x2000, { 0x401, 10800, 0 } },
+ { 0x8000, { 21600, 0, 0x403 } },
+ { 0x8000, { 10800, 0, DFF_Prop_adjust2Value } },
+ { 0x600a, { 0x405, DFF_Prop_adjustValue, 0 } }, // 6
+ { 0x6009, { 0x405, DFF_Prop_adjustValue, 0 } },
+ { 0x2000, { 0x406, 10800, 0 } }, // 8
+ { 0x2000, { 0x407, 10800, 0 } },
+ { 0x8000, { 21600, 0, 0x409 } }, // 10
+ { 0x8000, { 21600, 0, 0x405 } },
+ { 0x000, { 21600, 0, 0 } }
+};
+const sal_uInt16 mso_sptTextCirclePourSegm[] =
+{
+ 0xA504, 0x8000, 0xA504, 0x8000
+};
+const SvxMSDffHandle mso_sptTextCirclePourHandle[] =
+{
+ { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE,
+ 0x101, 0x100, 10800, 10800, 0, 10800, MIN_INT32, 0x7fffffff }
+};
+const sal_Int32 mso_sptTextCirclePourDefault[] =
+{
+ 2, -179, 5400
+};
+const mso_CustomShape msoTextCirclePour =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextCirclePourVert), SAL_N_ELEMENTS( mso_sptTextCirclePourVert ),
+ const_cast<sal_uInt16*>(mso_sptTextCirclePourSegm), sizeof( mso_sptTextCirclePourSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextCirclePourCalc), SAL_N_ELEMENTS( mso_sptTextCirclePourCalc ),
+ const_cast<sal_Int32*>(mso_sptTextCirclePourDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextCirclePourHandle), SAL_N_ELEMENTS( mso_sptTextCirclePourHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextButtonPourVert[] =
+{
+ { 0, 0 }, { 21600, 21600 }, { 2 MSO_I, 3 MSO_I }, { 4 MSO_I, 3 MSO_I },
+ { 6 MSO_I, 6 MSO_I }, { 7 MSO_I, 7 MSO_I }, { 10 MSO_I, 11 MSO_I }, { 12 MSO_I, 11 MSO_I },
+ { 0x16 MSO_I, 16 MSO_I }, { 0x15 MSO_I, 16 MSO_I },
+ { 0x16 MSO_I, 15 MSO_I }, { 0x15 MSO_I, 15 MSO_I },
+ { 6 MSO_I, 6 MSO_I }, { 7 MSO_I, 7 MSO_I }, { 10 MSO_I, 13 MSO_I }, { 12 MSO_I, 13 MSO_I },
+ { 0, 0 }, { 21600, 21600 }, { 2 MSO_I, 5 MSO_I }, { 4 MSO_I, 5 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextButtonPourCalc[] =
+{
+ { 0x400a, { 10800, DFF_Prop_adjustValue, 0 } }, // 0x00
+ { 0x4009, { 10800, DFF_Prop_adjustValue, 0 } }, // 0x01
+ { 0x2000, { 0x400, 10800, 0 } }, // 0x02
+ { 0x2000, { 0x401, 10800, 0 } }, // 0x03
+ { 0x8000, { 21600, 0, 0x402 } }, // 0x04
+ { 0x8000, { 21600, 0, 0x403 } }, // 0x05
+
+ { 0x8000, { 10800, 0, DFF_Prop_adjust2Value } }, // 0x06
+ { 0x8000, { 21600, 0, 0x406 } }, // 0x07
+
+ { 0x600a, { DFF_Prop_adjust2Value, DFF_Prop_adjustValue, 0 } }, // 0x08
+ { 0x6009, { DFF_Prop_adjust2Value, DFF_Prop_adjustValue, 0 } }, // 0x09
+ { 0x2000, { 0x408, 10800, 0 } }, // 0x0a
+ { 0x2000, { 0x409, 10800, 0 } }, // 0x0b
+ { 0x8000, { 21600, 0, 0x40a } }, // 0x0c
+ { 0x8000, { 21600, 0, 0x40b } }, // 0x0d
+ { 0x2001, { 0x406, 1, 2 } }, // 0x0e
+ { 0x4000, { 10800, 0x40e, 0 } }, // 0x0f
+ { 0x8000, { 10800, 0, 0x40e } }, // 0x10
+ { 0x6001, { 0x40e, 0x40e, 1 } }, // 0x11
+ { 0x6001, { DFF_Prop_adjust2Value, DFF_Prop_adjust2Value, 1 } }, // 0x12
+ { 0xA000, { 0x412, 0, 0x411 } }, // 0x13
+ { 0x200d, { 0x413, 0, 0 } }, // 0x14
+ { 0x4000, { 10800, 0x414, 0 } }, // 0x15
+ { 0x8000, { 10800, 0, 0x414 } } // 0x16
+};
+const sal_uInt16 mso_sptTextButtonPourSegm[] =
+{
+ 0xA504, 0x8000, // clockwise arc
+ 0xA504, 0x8000, // clockwise arc
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0xA304, 0x8000, // counter clockwise
+ 0xA304, 0x8000 // counter clockwise
+};
+const SvxMSDffHandle mso_sptTextButtonPourHandle[] =
+{
+ { SvxMSDffHandleFlags::POLAR | SvxMSDffHandleFlags::RADIUS_RANGE,
+ 0x101, 0x100, 10800, 10800, 4320, 10800, MIN_INT32, 0x7fffffff }
+};
+const sal_Int32 mso_sptTextButtonPourDefault[] =
+{
+ 2, 180, 5400
+};
+const mso_CustomShape msoTextButtonPour =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextButtonPourVert), SAL_N_ELEMENTS( mso_sptTextButtonPourVert ),
+ const_cast<sal_uInt16*>(mso_sptTextButtonPourSegm), sizeof( mso_sptTextButtonPourSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextButtonPourCalc), SAL_N_ELEMENTS( mso_sptTextButtonPourCalc ),
+ const_cast<sal_Int32*>(mso_sptTextButtonPourDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextButtonPourHandle), SAL_N_ELEMENTS( mso_sptTextButtonPourHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextCurveUpVert[] =
+{
+ { 0, 0 MSO_I }, { 4900, 1 MSO_I /*12170->0 14250 ->0*/ }, { 11640, 2 MSO_I /*12170->0 12800 ->0*/ }, { 21600, 0 },
+ { 0, 4 MSO_I /*12170->0 17220 ->21600*/ }, { 3700, 21600 }, { 8500, 21600 }, { 10100, 21600 }, { 14110, 21600 }, { 15910, 21600 }, { 21600, 4 MSO_I /*12170->0 17220 ->21600*/ }
+};
+const SvxMSDffCalculationData mso_sptTextCurveUpCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400
+ { 0x4001, { 14250, 0x400, 12170 } }, // 401
+ { 0x4001, { 12800, 0x400, 12170 } }, // 402
+ { 0x4001, { 6380, 0x400, 12170 } }, // 403
+ { 0x8000, { 21600, 0, 0x403 } } // 404
+};
+const sal_uInt16 mso_sptTextCurveUpSegm[] =
+{
+ 0x4000, 0x2001, 0x8000,
+ 0x4000, 0x2002, 0x8000
+};
+const SvxMSDffHandle mso_sptTextCurveUpHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 12170 }
+};
+const sal_Int32 mso_sptTextCurveUpDefault[] =
+{
+ 1, 9900
+};
+const mso_CustomShape msoTextCurveUp =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextCurveUpVert), SAL_N_ELEMENTS( mso_sptTextCurveUpVert ),
+ const_cast<sal_uInt16*>(mso_sptTextCurveUpSegm), sizeof( mso_sptTextCurveUpSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextCurveUpCalc), SAL_N_ELEMENTS( mso_sptTextCurveUpCalc ),
+ const_cast<sal_Int32*>(mso_sptTextCurveUpDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextCurveUpHandle), SAL_N_ELEMENTS( mso_sptTextCurveUpHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextCurveDownVert[] =
+{
+// { 0, 0 MSO_I }, { 4900, 1 MSO_I /*12170->0 14250 ->0*/ }, { 11640, 2 MSO_I /*12170->0 12800 ->0*/ }, { 21600, 0 },
+ { 0, 0 }, { 9960, 2 MSO_I }, { 16700, 1 MSO_I }, { 21600, 0 MSO_I },
+
+// { 0, 4 MSO_I /*12170->0 17220 ->21600*/ }, { 3700, 21600 }, { 8500, 21600 }, { 10100, 21600 }, { 14110, 21600 }, { 15910, 21600 }, { 21600, 4 MSO_I /*12170->0 17220 ->21600*/ }
+ { 0, 4 MSO_I }, { 5690, 21600 }, { 7490, 21600 }, { 11500, 21600 }, { 13100, 21600 }, { 17900, 21600 }, { 21600, 4 MSO_I }
+};
+const SvxMSDffHandle mso_sptTextCurveDownHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 21600, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 12170 }
+};
+const mso_CustomShape msoTextCurveDown =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextCurveDownVert), SAL_N_ELEMENTS( mso_sptTextCurveDownVert ),
+ const_cast<sal_uInt16*>(mso_sptTextCurveUpSegm), sizeof( mso_sptTextCurveUpSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextCurveUpCalc), SAL_N_ELEMENTS( mso_sptTextCurveUpCalc ),
+ const_cast<sal_Int32*>(mso_sptTextCurveUpDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextCurveDownHandle), SAL_N_ELEMENTS( mso_sptTextCurveDownHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextCanUpVert[] =
+{
+ { 0, 1 MSO_I }, { 900, 0 }, { 7100, 0 }, { 10800, 0 }, { 14500, 0 }, { 20700, 0 }, { 21600, 1 MSO_I },
+ { 0, 21600 }, { 900, 4 MSO_I }, { 7100, 0 MSO_I }, { 10800, 0 MSO_I }, { 14500, 0 MSO_I }, { 20700, 4 MSO_I }, { 21600, 21600 }
+};
+const SvxMSDffCalculationData mso_sptTextCanUpCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }, // 401
+ { 0x2000, { DFF_Prop_adjustValue, 0, 14400 } }, // 402
+ { 0x4001, { 5470, 0x402, 7200 } }, // 403
+ { 0x4000, { 16130, 0x403, 0 } } // 404
+};
+const sal_uInt16 mso_sptTextCanUpSegm[] =
+{
+ 0x4000, 0x2002, 0x8000,
+ 0x4000, 0x2002, 0x8000
+};
+const SvxMSDffHandle mso_sptTextCanUpHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 14400, 21600 }
+};
+const sal_Int32 mso_sptTextCanUpDefault[] =
+{
+ 1, 18500
+};
+const mso_CustomShape msoTextCanUp =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextCanUpVert), SAL_N_ELEMENTS( mso_sptTextCanUpVert ),
+ const_cast<sal_uInt16*>(mso_sptTextCanUpSegm), sizeof( mso_sptTextCanUpSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextCanUpCalc), SAL_N_ELEMENTS( mso_sptTextCanUpCalc ),
+ const_cast<sal_Int32*>(mso_sptTextCanUpDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextCanUpHandle), SAL_N_ELEMENTS( mso_sptTextCanUpHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextCanDownVert[] =
+{
+ { 0, 0 }, { 900, 2 MSO_I }, { 7100, 0 MSO_I }, { 10800, 0 MSO_I }, { 14500, 0 MSO_I }, { 20700, 2 MSO_I }, { 21600, 0 },
+ { 0, 1 MSO_I }, { 900, 21600 }, { 7100, 21600 }, { 10800, 21600 }, { 14500, 21600 }, { 20700, 21600 }, { 21600, 1 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextCanDownCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400
+ { 0x8000, { 21600, 0, DFF_Prop_adjustValue } }, // 401
+ { 0x4001, { 5470, 0x400, 7200 } } // 402
+};
+const SvxMSDffHandle mso_sptTextCanDownHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 7200 }
+};
+const sal_Int32 mso_sptTextCanDownDefault[] =
+{
+ 1, 3100
+};
+const mso_CustomShape msoTextCanDown =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextCanDownVert), SAL_N_ELEMENTS( mso_sptTextCanDownVert ),
+ const_cast<sal_uInt16*>(mso_sptTextCanUpSegm), sizeof( mso_sptTextCanUpSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextCanDownCalc), SAL_N_ELEMENTS( mso_sptTextCanDownCalc ),
+ const_cast<sal_Int32*>(mso_sptTextCanDownDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextCanDownHandle), SAL_N_ELEMENTS( mso_sptTextCanDownHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextInflateVert[] =
+{
+ { 0, 0 MSO_I }, { 4100, 1 MSO_I }, { 7300, 0 }, { 10800, 0 }, { 14300, 0 }, { 17500, 1 MSO_I }, { 21600, 0 MSO_I },
+ { 0, 2 MSO_I }, { 4100, 3 MSO_I }, { 7300, 21600 }, { 10800, 21600 }, { 14300, 21600 }, { 17500, 3 MSO_I }, { 21600, 2 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextInflateCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400
+ { 0x4001, { 1530, 0x400, 4650 } }, // 401
+ { 0x8000, { 21600, 0, 0x400 } }, // 402
+ { 0x8000, { 21600, 0, 0x401 } } // 403
+};
+const SvxMSDffHandle mso_sptTextInflateHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 4650 }
+};
+const sal_Int32 mso_sptTextInflateDefault[] =
+{
+ 1, 2950
+};
+const mso_CustomShape msoTextInflate =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextInflateVert), SAL_N_ELEMENTS( mso_sptTextInflateVert ),
+ const_cast<sal_uInt16*>(mso_sptTextCanUpSegm), sizeof( mso_sptTextCanUpSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextInflateCalc), SAL_N_ELEMENTS( mso_sptTextInflateCalc ),
+ const_cast<sal_Int32*>(mso_sptTextInflateDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextInflateHandle), SAL_N_ELEMENTS( mso_sptTextInflateHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextDeflateVert[] =
+{
+ { 0, 0 }, { 3500, 1 MSO_I }, { 7100, 0 MSO_I }, { 10800, 0 MSO_I }, { 14500, 0 MSO_I }, { 18100, 1 MSO_I }, { 21600, 0 },
+ { 0, 21600 }, { 3500, 3 MSO_I }, { 7100, 2 MSO_I }, { 10800, 2 MSO_I }, { 14500, 2 MSO_I }, { 18100, 3 MSO_I }, { 21600, 21600 }
+};
+const SvxMSDffCalculationData mso_sptTextDeflateCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400
+ { 0x2001, { 0x400, 5320, 7100 } }, // 401
+ { 0x8000, { 21600, 0, 0x400 } }, // 402
+ { 0x8000, { 21600, 0, 0x401 } } // 403
+};
+const SvxMSDffHandle mso_sptTextDeflateHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 8100 }
+};
+const mso_CustomShape msoTextDeflate =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextDeflateVert), SAL_N_ELEMENTS( mso_sptTextDeflateVert ),
+ const_cast<sal_uInt16*>(mso_sptTextCanUpSegm), sizeof( mso_sptTextCanUpSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextDeflateCalc), SAL_N_ELEMENTS( mso_sptTextDeflateCalc ),
+ const_cast<sal_Int32*>(mso_sptDefault8100),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextDeflateHandle), SAL_N_ELEMENTS( mso_sptTextDeflateHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextInflateBottomVert[] =
+{
+ { 0, 0 }, { 21600, 0 },
+ { 0, 0 MSO_I }, { 3500, 3 MSO_I }, { 7300, 21600 }, { 10800, 21600 }, { 14300, 21600 }, { 18100, 3 MSO_I }, { 21600, 0 MSO_I }
+};
+const SvxMSDffCalculationData mso_sptTextInflateBottomCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400
+ { 0x2000, { 0x400, 0, 11150 } }, // 401 0->10450
+ { 0x2001, { 0x401, 3900, 10450 } }, // 402
+ { 0x2000, { 0x402, 17700, 0 } } // 403
+};
+const sal_uInt16 mso_sptTextInflateBottomSegm[] =
+{
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x2002, 0x8000
+};
+const SvxMSDffHandle mso_sptTextInflateBottomHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 11150, 21600 }
+};
+const sal_Int32 mso_sptTextInflateBottomDefault[] =
+{
+ 1, 14700
+};
+const mso_CustomShape msoTextInflateBottom =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextInflateBottomVert), SAL_N_ELEMENTS( mso_sptTextInflateBottomVert ),
+ const_cast<sal_uInt16*>(mso_sptTextInflateBottomSegm), sizeof( mso_sptTextInflateBottomSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextInflateBottomCalc), SAL_N_ELEMENTS( mso_sptTextInflateBottomCalc ),
+ const_cast<sal_Int32*>(mso_sptTextInflateBottomDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextInflateBottomHandle), SAL_N_ELEMENTS( mso_sptTextInflateBottomHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextDeflateBottomVert[] =
+{
+ { 0, 0 }, { 21600, 0 },
+ { 0, 21600 }, { 2900, 3 MSO_I }, { 7200, 0 MSO_I }, { 10800, 0 MSO_I }, { 14400, 0 MSO_I }, { 18700, 3 MSO_I }, { 21600, 21600 }
+};
+const SvxMSDffCalculationData mso_sptTextDeflateBottomCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400
+ { 0x2000, { 0x400, 0, 1350 } }, // 401 0->20250
+ { 0x2001, { 0x401, 12070, 20250 } }, // 402
+ { 0x2000, { 0x402, 9530, 0 } } // 403
+};
+const sal_uInt16 mso_sptTextDeflateBottomSegm[] =
+{
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x2002, 0x8000
+};
+const SvxMSDffHandle mso_sptTextDeflateBottomHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 1350, 21600 }
+};
+const sal_Int32 mso_sptTextDeflateBottomDefault[] =
+{
+ 1, 11500
+};
+const mso_CustomShape msoTextDeflateBottom =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextDeflateBottomVert), SAL_N_ELEMENTS( mso_sptTextDeflateBottomVert ),
+ const_cast<sal_uInt16*>(mso_sptTextDeflateBottomSegm), sizeof( mso_sptTextDeflateBottomSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextDeflateBottomCalc), SAL_N_ELEMENTS( mso_sptTextDeflateBottomCalc ),
+ const_cast<sal_Int32*>(mso_sptTextDeflateBottomDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextDeflateBottomHandle), SAL_N_ELEMENTS( mso_sptTextDeflateBottomHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextInflateTopVert[] =
+{
+ { 0, 0 MSO_I }, { 3500, 1 MSO_I }, { 7300, 0 }, { 10800, 0 }, { 14300, 0 }, { 18100, 1 MSO_I }, { 21600, 0 MSO_I },
+ { 0, 21600 }, { 21600, 21600 }
+};
+const SvxMSDffCalculationData mso_sptTextInflateTopCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400
+ { 0x2001, { 0x400, 3900, 10450 } } // 401
+};
+const sal_uInt16 mso_sptTextInflateTopSegm[] =
+{
+ 0x4000, 0x2002, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffHandle mso_sptTextInflateTopHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 10450 }
+};
+const sal_Int32 mso_sptTextInflateTopDefault[] =
+{
+ 1, 6900
+};
+const mso_CustomShape msoTextInflateTop =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextInflateTopVert), SAL_N_ELEMENTS( mso_sptTextInflateTopVert ),
+ const_cast<sal_uInt16*>(mso_sptTextInflateTopSegm), sizeof( mso_sptTextInflateTopSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextInflateTopCalc), SAL_N_ELEMENTS( mso_sptTextInflateTopCalc ),
+ const_cast<sal_Int32*>(mso_sptTextInflateTopDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextInflateTopHandle), SAL_N_ELEMENTS( mso_sptTextInflateTopHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextDeflateTopVert[] =
+{
+ { 0, 0 }, { 2900, 1 MSO_I }, { 7200, 0 MSO_I }, { 10800, 0 MSO_I }, { 14400, 0 MSO_I }, { 18700, 1 MSO_I }, { 21600, 0 },
+ { 0, 21600 }, { 21600, 21600 }
+};
+const SvxMSDffCalculationData mso_sptTextDeflateTopCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400
+ { 0x2001, { 0x400, 12070, 20250 } } // 402
+};
+const sal_uInt16 mso_sptTextDeflateTopSegm[] =
+{
+ 0x4000, 0x2002, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffHandle mso_sptTextDeflateTopHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 0, 20250 }
+};
+const sal_Int32 mso_sptTextDeflateTopDefault[] =
+{
+ 1, 10100
+};
+const mso_CustomShape msoTextDeflateTop =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextDeflateTopVert), SAL_N_ELEMENTS( mso_sptTextDeflateTopVert ),
+ const_cast<sal_uInt16*>(mso_sptTextDeflateTopSegm), sizeof( mso_sptTextDeflateTopSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextDeflateTopCalc), SAL_N_ELEMENTS( mso_sptTextDeflateTopCalc ),
+ const_cast<sal_Int32*>(mso_sptTextDeflateTopDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextDeflateTopHandle), SAL_N_ELEMENTS( mso_sptTextDeflateTopHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextDeflateInflateVert[] =
+{
+ { 0, 0 }, { 21600, 0 },
+ { 0, 10100 }, { 3300, 3 MSO_I }, { 7100, 5 MSO_I }, { 10800, 5 MSO_I }, { 14500, 5 MSO_I }, { 18300, 3 MSO_I }, { 21600, 10100 },
+ { 0, 11500 }, { 3300, 4 MSO_I }, { 7100, 6 MSO_I }, { 10800, 6 MSO_I }, { 14500, 6 MSO_I }, { 18300, 4 MSO_I }, { 21600, 11500 },
+ { 0, 21600 }, { 21600, 21600 }
+};
+const SvxMSDffCalculationData mso_sptTextDeflateInflateCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }, // 400
+ { 0x8000, { 10800, 0, 0x400 } }, // 401
+ { 0x2001, { 0x401, 5770, 9500 } }, // 402
+ { 0x8000, { 10100, 0, 0x402 } }, // 403
+ { 0x8000, { 11500, 0, 0x402 } }, // 404
+ { 0x2000, { 0x400, 0, 700 } }, // 405
+ { 0x2000, { 0x400, 700, 0 } } // 406
+};
+const sal_uInt16 mso_sptTextDeflateInflateSegm[] =
+{
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x2002, 0x8000,
+ 0x4000, 0x2002, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffHandle mso_sptTextDeflateInflateHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 1300, 20300 }
+};
+const sal_Int32 mso_sptTextDeflateInflateDefault[] =
+{
+ 1, 6500
+};
+const mso_CustomShape msoTextDeflateInflate =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextDeflateInflateVert), SAL_N_ELEMENTS( mso_sptTextDeflateInflateVert ),
+ const_cast<sal_uInt16*>(mso_sptTextDeflateInflateSegm), sizeof( mso_sptTextDeflateInflateSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextDeflateInflateCalc), SAL_N_ELEMENTS( mso_sptTextDeflateInflateCalc ),
+ const_cast<sal_Int32*>(mso_sptTextDeflateInflateDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextDeflateInflateHandle), SAL_N_ELEMENTS( mso_sptTextDeflateInflateHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextDeflateInflateDeflateVert[] =
+{
+ { 0, 0 }, { 21600, 0 },
+ { 0, 6600 }, { 3600, 3 MSO_I }, { 7250, 4 MSO_I }, { 10800, 4 MSO_I }, { 14350, 4 MSO_I }, { 18000, 3 MSO_I }, { 21600, 6600 },
+ { 0, 7500 }, { 3600, 5 MSO_I }, { 7250, 6 MSO_I }, { 10800, 6 MSO_I }, { 14350, 6 MSO_I }, { 18000, 5 MSO_I }, { 21600, 7500 },
+ { 0, 14100 }, { 3600, 9 MSO_I }, { 7250, 10 MSO_I }, { 10800, 10 MSO_I }, { 14350, 10 MSO_I }, { 18000, 9 MSO_I }, { 21600, 14100 },
+ { 0, 15000 }, { 3600, 7 MSO_I }, { 7250, 8 MSO_I }, { 10800, 8 MSO_I }, { 14350, 8 MSO_I }, { 18000, 7 MSO_I }, { 21600, 15000 },
+ { 0, 21600 }, { 21600, 21600 }
+};
+const SvxMSDffCalculationData mso_sptTextDeflateInflateDeflateCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 850 } }, // 400
+ { 0x2001, { 0x400, 6120, 8700 } },
+ { 0x2000, { 0x401, 0, 4280 } },
+ { 0x4000, { 6600, 0x402, 0 } },
+ { 0x2000, { DFF_Prop_adjustValue, 0, 450 } }, // 404
+ { 0x2000, { 0x403, 900, 0 } }, // 405
+ { 0x2000, { 0x404, 900, 0 } }, // 406
+ { 0x8000, { 21600, 0, 0x403 } }, // 407
+ { 0x8000, { 21600, 0, 0x404 } }, // 408
+ { 0x8000, { 21600, 0, 0x405 } }, // 409
+ { 0x8000, { 21600, 0, 0x406 } } // 410
+};
+const sal_uInt16 mso_sptTextDeflateInflateDeflateSegm[] =
+{
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x2002, 0x8000,
+ 0x4000, 0x2002, 0x8000,
+ 0x4000, 0x2002, 0x8000,
+ 0x4000, 0x2002, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffHandle mso_sptTextDeflateInflateDeflateHandle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 10800, 0x100, 10800, 10800, MIN_INT32, 0x7fffffff, 850, 9550 }
+};
+const sal_Int32 mso_sptTextDeflateInflateDeflateDefault[] =
+{
+ 1, 6050
+};
+const mso_CustomShape msoTextDeflateInflateDeflate =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextDeflateInflateDeflateVert), SAL_N_ELEMENTS( mso_sptTextDeflateInflateDeflateVert ),
+ const_cast<sal_uInt16*>(mso_sptTextDeflateInflateDeflateSegm), sizeof( mso_sptTextDeflateInflateDeflateSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTextDeflateInflateDeflateCalc), SAL_N_ELEMENTS( mso_sptTextDeflateInflateDeflateCalc ),
+ const_cast<sal_Int32*>(mso_sptTextDeflateInflateDeflateDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTextDeflateInflateDeflateHandle), SAL_N_ELEMENTS( mso_sptTextDeflateInflateDeflateHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextWave1Vert[] = // adjustment1 : 0 - 4459
+{ // adjustment2 : 8640 - 12960
+ { 7 MSO_I, 0 MSO_I }, { 15 MSO_I, 9 MSO_I }, { 16 MSO_I, 10 MSO_I }, { 12 MSO_I, 0 MSO_I },
+ { 29 MSO_I, 1 MSO_I }, { 27 MSO_I, 28 MSO_I }, { 25 MSO_I, 26 MSO_I }, { 24 MSO_I, 1 MSO_I }
+};
+const sal_uInt16 mso_sptTextWave1Segm[] =
+{
+ 0x4000, 0x2001, 0x8000,
+ 0x4000, 0x2001, 0x8000
+};
+const mso_CustomShape msoTextWave1 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextWave1Vert), SAL_N_ELEMENTS( mso_sptTextWave1Vert ),
+ const_cast<sal_uInt16*>(mso_sptTextWave1Segm), sizeof( mso_sptTextWave1Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptWaveCalc), SAL_N_ELEMENTS( mso_sptWaveCalc ),
+ const_cast<sal_Int32*>(mso_sptWaveDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptWaveGluePoints), SAL_N_ELEMENTS( mso_sptWaveGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptWaveHandle), SAL_N_ELEMENTS( mso_sptWaveHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextWave2Vert[] = // adjustment1 : 0 - 4459
+{ // adjustment2 : 8640 - 12960
+ { 7 MSO_I, 0 MSO_I }, { 15 MSO_I, 10 MSO_I }, { 16 MSO_I, 9 MSO_I }, { 12 MSO_I, 0 MSO_I },
+ { 29 MSO_I, 1 MSO_I }, { 27 MSO_I, 26 MSO_I }, { 25 MSO_I, 28 MSO_I }, { 24 MSO_I, 1 MSO_I }
+};
+const mso_CustomShape msoTextWave2 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextWave2Vert), SAL_N_ELEMENTS( mso_sptTextWave2Vert ),
+ const_cast<sal_uInt16*>(mso_sptTextWave1Segm), sizeof( mso_sptTextWave1Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptWaveCalc), SAL_N_ELEMENTS( mso_sptWaveCalc ),
+ const_cast<sal_Int32*>(mso_sptWaveDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptFontWorkTextRect), SAL_N_ELEMENTS( mso_sptFontWorkTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptWaveGluePoints), SAL_N_ELEMENTS( mso_sptWaveGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptWaveHandle), SAL_N_ELEMENTS( mso_sptWaveHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextWave3Vert[] = // adjustment1 : 0 - 2230
+{ // adjustment2 : 8640 - 12960
+ { 7 MSO_I, 0 MSO_I }, { 15 MSO_I, 9 MSO_I }, { 0x1f MSO_I, 10 MSO_I }, { 0x12 MSO_I, 0 MSO_I }, { 0x1e MSO_I, 9 MSO_I }, { 16 MSO_I, 10 MSO_I }, { 12 MSO_I, 0 MSO_I },
+ { 29 MSO_I, 1 MSO_I }, { 27 MSO_I, 28 MSO_I }, { 0x21 MSO_I, 26 MSO_I }, { 0x13 MSO_I, 1 MSO_I }, { 0x20 MSO_I, 28 MSO_I }, { 25 MSO_I, 26 MSO_I }, { 24 MSO_I, 1 MSO_I }
+};
+const sal_uInt16 mso_sptTextWave3Segm[] =
+{
+ 0x4000, 0x2002, 0x8000,
+ 0x4000, 0x2002, 0x8000
+};
+const mso_CustomShape msoTextWave3 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextWave3Vert), SAL_N_ELEMENTS( mso_sptTextWave3Vert ),
+ const_cast<sal_uInt16*>(mso_sptTextWave3Segm), sizeof( mso_sptTextWave3Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptDoubleWaveCalc), SAL_N_ELEMENTS( mso_sptDoubleWaveCalc ),
+ const_cast<sal_Int32*>(mso_sptDoubleWaveDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptDoubleWaveTextRect), SAL_N_ELEMENTS( mso_sptDoubleWaveTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptDoubleWaveGluePoints), SAL_N_ELEMENTS( mso_sptDoubleWaveGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptDoubleWaveHandle), SAL_N_ELEMENTS( mso_sptDoubleWaveHandle )
+};
+
+const SvxMSDffVertPair mso_sptTextWave4Vert[] = // adjustment1 : 0 - 2230
+{ // adjustment2 : 8640 - 12960
+ { 7 MSO_I, 0 MSO_I }, { 15 MSO_I, 10 MSO_I }, { 0x1f MSO_I, 9 MSO_I }, { 0x12 MSO_I, 0 MSO_I }, { 0x1e MSO_I, 10 MSO_I }, { 16 MSO_I, 9 MSO_I }, { 12 MSO_I, 0 MSO_I },
+ { 29 MSO_I, 1 MSO_I }, { 27 MSO_I, 26 MSO_I }, { 0x21 MSO_I, 28 MSO_I }, { 0x13 MSO_I, 1 MSO_I }, { 0x20 MSO_I, 26 MSO_I }, { 25 MSO_I, 28 MSO_I }, { 24 MSO_I, 1 MSO_I }
+};
+const mso_CustomShape msoTextWave4 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTextWave4Vert), SAL_N_ELEMENTS( mso_sptTextWave4Vert ),
+ const_cast<sal_uInt16*>(mso_sptTextWave3Segm), sizeof( mso_sptTextWave3Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptDoubleWaveCalc), SAL_N_ELEMENTS( mso_sptDoubleWaveCalc ),
+ const_cast<sal_Int32*>(mso_sptDoubleWaveDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptDoubleWaveTextRect), SAL_N_ELEMENTS( mso_sptDoubleWaveTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ const_cast<SvxMSDffVertPair*>(mso_sptDoubleWaveGluePoints), SAL_N_ELEMENTS( mso_sptDoubleWaveGluePoints ),
+ const_cast<SvxMSDffHandle*>(mso_sptDoubleWaveHandle), SAL_N_ELEMENTS( mso_sptDoubleWaveHandle )
+};
+
+const sal_Int32 mso_sptCalloutDefault1[] =
+{
+ 4, -1800, 24500, -1800, 4000
+};
+const sal_Int32 mso_sptCalloutDefault2[] =
+{
+ 4, -8300, 24500, -1800, 4000
+};
+const sal_Int32 mso_sptCalloutDefault3[] =
+{
+ 6, -10000, 24500, -3600, 4000, -1800, 4000
+};
+const sal_Int32 mso_sptCalloutDefault4[] =
+{
+ 8, 23400, 24500, 25200, 21600, 25200, 4000, 23400, 4000
+};
+const SvxMSDffVertPair mso_sptCalloutVert1[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0 MSO_I, 1 MSO_I }, { 2 MSO_I, 3 MSO_I }
+};
+const SvxMSDffHandle mso_sptCalloutHandle1[] =
+{
+ { SvxMSDffHandleFlags::NONE,
+ 0x100, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::NONE,
+ 0x102, 0x103, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff }
+};
+const sal_uInt16 mso_sptCalloutSegm1a[] =
+{
+ 0x4000, 0x0003, 0x6000, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const sal_uInt16 mso_sptCalloutSegm1b[] =
+{
+ 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffVertPair mso_sptCallout1Vert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0 MSO_I, 1 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 2 MSO_I, 0 }, { 2 MSO_I, 21600 }
+};
+const sal_uInt16 mso_sptCallout1Segm1a[] =
+{
+ 0x4000, 0x0003, 0x6000, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const sal_uInt16 mso_sptCallout1Segm1b[] =
+{
+ 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffVertPair mso_sptCallout2Verta[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0 MSO_I, 1 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 4 MSO_I, 5 MSO_I }
+};
+const SvxMSDffVertPair mso_sptCallout2Vertb[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 0 MSO_I, 1 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 4 MSO_I, 5 MSO_I }, { 4 MSO_I, 0 }, { 4 MSO_I, 21600 }
+};
+const SvxMSDffHandle mso_sptCalloutHandle2[] =
+{
+ { SvxMSDffHandleFlags::NONE,
+ 0x100, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::NONE,
+ 0x102, 0x103, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::NONE,
+ 0x104, 0x105, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff }
+};
+const sal_uInt16 mso_sptCallout2Segm1a[] =
+{
+ 0x4000, 0x0003, 0x6000, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const sal_uInt16 mso_sptCallout2Segm1b[] =
+{
+ 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const sal_uInt16 mso_sptCallout2Segm1c[] =
+{
+ 0x4000, 0x0003, 0x6000, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const sal_uInt16 mso_sptCallout2Segm1d[] =
+{
+ 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000,
+ 0x4000, 0x0001, 0x8000
+};
+const SvxMSDffVertPair mso_sptCallout3Verta[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 6 MSO_I, 7 MSO_I }, { 4 MSO_I, 5 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 0 MSO_I, 1 MSO_I }
+};
+const SvxMSDffVertPair mso_sptCallout3Vertb[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }, { 0, 21600 }, { 6 MSO_I, 7 MSO_I }, { 4 MSO_I, 5 MSO_I }, { 2 MSO_I, 3 MSO_I }, { 0 MSO_I, 1 MSO_I }, { 6 MSO_I, 0 }, { 6 MSO_I, 21600 }
+};
+const SvxMSDffHandle mso_sptCalloutHandle3[] =
+{
+ { SvxMSDffHandleFlags::NONE,
+ 0x100, 0x101, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::NONE,
+ 0x102, 0x103, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::NONE,
+ 0x104, 0x105, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::NONE,
+ 0x106, 0x107, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff }
+};
+const sal_uInt16 mso_sptCallout3Segm1a[] =
+{
+ 0x4000, 0x0003, 0x6000, 0x8000,
+ 0x4000, 0xaa00, 0x0003, 0x8000 // NO_FILL
+};
+const sal_uInt16 mso_sptCallout3Segm1b[] =
+{
+ 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE
+ 0x4000, 0xaa00, 0x0003, 0x8000 // NO FILL
+};
+const sal_uInt16 mso_sptCallout3Segm1c[] =
+{
+ 0x4000, 0x0003, 0x6000, 0x8000,
+ 0x4000, 0xaa00, 0x0003, 0x8000, // NO FILL
+ 0x4000, 0x0001, 0x8000
+};
+const sal_uInt16 mso_sptCallout3Segm1d[] =
+{
+ 0x4000, 0xab00, 0x0003, 0x6000, 0x8000, // NO STROKE
+ 0x4000, 0xaa00, 0x0003, 0x8000, // NO FILL
+ 0x4000, 0x0001, 0x8000
+};
+
+const SvxMSDffCalculationData mso_sptCalloutCalc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust4Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust5Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust6Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust7Value, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust8Value, 0, 0 } }
+};
+
+const mso_CustomShape msoCallout90 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ),
+ const_cast<sal_uInt16*>(mso_sptCalloutSegm1b), sizeof( mso_sptCalloutSegm1b ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault1),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 )
+};
+const mso_CustomShape msoCallout1 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ),
+ const_cast<sal_uInt16*>(mso_sptCalloutSegm1b), sizeof( mso_sptCalloutSegm1b ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault2),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 )
+};
+const mso_CustomShape msoCallout2 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCallout2Verta), SAL_N_ELEMENTS( mso_sptCallout2Verta ),
+ const_cast<sal_uInt16*>(mso_sptCallout2Segm1b), sizeof( mso_sptCallout2Segm1b ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault3),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle2), SAL_N_ELEMENTS( mso_sptCalloutHandle2 )
+};
+const mso_CustomShape msoCallout3 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCallout3Verta), SAL_N_ELEMENTS( mso_sptCallout3Verta ),
+ const_cast<sal_uInt16*>(mso_sptCallout3Segm1b), sizeof( mso_sptCallout3Segm1b ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault4),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle3), SAL_N_ELEMENTS( mso_sptCalloutHandle3 )
+};
+const mso_CustomShape msoAccentCallout90 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ),
+ const_cast<sal_uInt16*>(mso_sptCalloutSegm1b), sizeof( mso_sptCalloutSegm1b ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault1),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 )
+};
+const mso_CustomShape msoAccentCallout1 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCallout1Vert), SAL_N_ELEMENTS( mso_sptCallout1Vert ),
+ const_cast<sal_uInt16*>(mso_sptCallout1Segm1b), sizeof( mso_sptCallout1Segm1b ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault2),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 )
+};
+const mso_CustomShape msoAccentCallout2 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCallout2Vertb), SAL_N_ELEMENTS( mso_sptCallout2Vertb ),
+ const_cast<sal_uInt16*>(mso_sptCallout2Segm1d), sizeof( mso_sptCallout2Segm1d ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault3),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle2), SAL_N_ELEMENTS( mso_sptCalloutHandle2 )
+};
+const mso_CustomShape msoAccentCallout3 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCallout3Vertb), SAL_N_ELEMENTS( mso_sptCallout3Vertb ),
+ const_cast<sal_uInt16*>(mso_sptCallout3Segm1d), sizeof( mso_sptCallout3Segm1d ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault4),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle3), SAL_N_ELEMENTS( mso_sptCalloutHandle3 )
+};
+const mso_CustomShape msoBorderCallout90 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ),
+ const_cast<sal_uInt16*>(mso_sptCalloutSegm1a), sizeof( mso_sptCalloutSegm1a ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault1),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 )
+};
+const mso_CustomShape msoBorderCallout1 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ),
+ const_cast<sal_uInt16*>(mso_sptCalloutSegm1a), sizeof( mso_sptCalloutSegm1a ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault2),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 )
+};
+const mso_CustomShape msoBorderCallout2 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCallout2Verta), SAL_N_ELEMENTS( mso_sptCallout2Verta ),
+ const_cast<sal_uInt16*>(mso_sptCallout2Segm1a), sizeof( mso_sptCallout2Segm1a ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault3),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle2), SAL_N_ELEMENTS( mso_sptCalloutHandle2 )
+};
+const mso_CustomShape msoBorderCallout3 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCallout3Verta), SAL_N_ELEMENTS( mso_sptCallout3Verta ),
+ const_cast<sal_uInt16*>(mso_sptCallout3Segm1a), sizeof( mso_sptCallout3Segm1a ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault4),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle3), SAL_N_ELEMENTS( mso_sptCalloutHandle3 )
+};
+const mso_CustomShape msoAccentBorderCallout90 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCalloutVert1), SAL_N_ELEMENTS( mso_sptCalloutVert1 ),
+ const_cast<sal_uInt16*>(mso_sptCalloutSegm1a), sizeof( mso_sptCalloutSegm1a ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault1),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 )
+};
+const mso_CustomShape msoAccentBorderCallout1 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCallout1Vert), SAL_N_ELEMENTS( mso_sptCallout1Vert ),
+ const_cast<sal_uInt16*>(mso_sptCallout1Segm1a), sizeof( mso_sptCallout1Segm1a ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault2),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle1), SAL_N_ELEMENTS( mso_sptCalloutHandle1 )
+};
+const mso_CustomShape msoAccentBorderCallout2 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCallout2Vertb), SAL_N_ELEMENTS( mso_sptCallout2Vertb ),
+ const_cast<sal_uInt16*>(mso_sptCallout2Segm1c), sizeof( mso_sptCallout2Segm1c ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault3),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle2), SAL_N_ELEMENTS( mso_sptCalloutHandle2 )
+};
+const mso_CustomShape msoAccentBorderCallout3 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCallout3Vertb), SAL_N_ELEMENTS( mso_sptCallout3Vertb ),
+ const_cast<sal_uInt16*>(mso_sptCallout3Segm1c), sizeof( mso_sptCallout3Segm1c ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCalloutCalc), SAL_N_ELEMENTS( mso_sptCalloutCalc ),
+ const_cast<sal_Int32*>(mso_sptCalloutDefault4),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCalloutHandle3), SAL_N_ELEMENTS( mso_sptCalloutHandle3 )
+};
+
+const SvxMSDffVertPair mso_sptStraightConnector1Vert[] =
+{
+ { 0, 0 }, { 21600, 21600 }
+};
+const sal_uInt16 mso_sptStraightConnector1Segm[] =
+{
+ 0x4000, 0x0001, 0x8000
+};
+const mso_CustomShape msoStraightConnector1 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptStraightConnector1Vert), SAL_N_ELEMENTS( mso_sptStraightConnector1Vert ),
+ const_cast<sal_uInt16*>(mso_sptStraightConnector1Segm), sizeof( mso_sptStraightConnector1Segm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ nullptr, 0
+};
+
+const SvxMSDffVertPair mso_sptBentConnector2Vert[] =
+{
+ { 0, 0 }, { 21600, 0 }, { 21600, 21600 }
+};
+const sal_uInt16 mso_sptBentConnector2Segm[] =
+{
+ 0x4000, 0x0002, 0x8000
+};
+const mso_CustomShape msoBentConnector2 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBentConnector2Vert), SAL_N_ELEMENTS( mso_sptBentConnector2Vert ),
+ const_cast<sal_uInt16*>(mso_sptBentConnector2Segm), sizeof( mso_sptBentConnector2Segm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ nullptr, 0
+};
+
+const SvxMSDffVertPair mso_sptBentConnector3Vert[] =
+{
+ { 0, 0 }, { 0 MSO_I, 0 }, { 0 MSO_I, 21600 }, { 21600, 21600 }
+};
+const sal_uInt16 mso_sptBentConnector3Segm[] =
+{
+ 0x4000, 0x0003, 0x8000
+};
+const SvxMSDffCalculationData mso_sptBentConnector3Calc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } }
+};
+const sal_Int32 mso_sptBentConnector3Default[] =
+{
+ 1, 10800
+};
+const SvxMSDffHandle mso_sptBentConnector3Handle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 10800, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoBentConnector3 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBentConnector3Vert), SAL_N_ELEMENTS( mso_sptBentConnector3Vert ),
+ const_cast<sal_uInt16*>(mso_sptBentConnector3Segm), sizeof( mso_sptBentConnector3Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBentConnector3Calc), SAL_N_ELEMENTS( mso_sptBentConnector3Calc ),
+ const_cast<sal_Int32*>(mso_sptBentConnector3Default),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptBentConnector3Handle), SAL_N_ELEMENTS( mso_sptBentConnector3Handle )
+};
+
+const SvxMSDffVertPair mso_sptBentConnector4Vert[] =
+{
+ { 0, 0 }, { 0 MSO_I, 0 }, { 0 MSO_I, 1 MSO_I }, { 21600, 1 MSO_I }, { 21600, 21600 }
+};
+const sal_uInt16 mso_sptBentConnector4Segm[] =
+{
+ 0x4000, 0x0004, 0x8000
+};
+const SvxMSDffCalculationData mso_sptBentConnector4Calc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2000, { 0x400, 21600, 0 } },
+ { 0x2001, { 0x402, 1, 2 } },
+ { 0x2001, { 0x401, 1, 2 } }
+};
+const sal_Int32 mso_sptBentConnector4Default[] =
+{
+ 2, 10800, 10800
+};
+const SvxMSDffHandle mso_sptBentConnector4Handle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0x100, 4 + 3, 10800, 10800, MIN_INT32, 0x7fffffff, 4 + 3, 4 + 3 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 3 + 3, 0x101, 10800, 10800, 3 + 3, 3 + 3, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoBentConnector4 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBentConnector4Vert), SAL_N_ELEMENTS( mso_sptBentConnector4Vert ),
+ const_cast<sal_uInt16*>(mso_sptBentConnector4Segm), sizeof( mso_sptBentConnector4Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBentConnector4Calc), SAL_N_ELEMENTS( mso_sptBentConnector4Calc ),
+ const_cast<sal_Int32*>(mso_sptBentConnector4Default),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptBentConnector4Handle), SAL_N_ELEMENTS( mso_sptBentConnector4Handle )
+};
+
+const SvxMSDffVertPair mso_sptBentConnector5Vert[] =
+{
+ { 0, 0 }, { 0 MSO_I, 0 }, { 0 MSO_I, 4 MSO_I }, { 1 MSO_I, 4 MSO_I }, { 1 MSO_I, 21600 }, { 21600, 21600 }
+};
+const sal_uInt16 mso_sptBentConnector5Segm[] =
+{
+ 0x4000, 0x0005, 0x8000
+};
+const SvxMSDffCalculationData mso_sptBentConnector5Calc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x6000, { 0x400, 0x401, 0 } },
+ { 0x2001, { 0x402, 1, 2 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2001, { 0x404, 1, 2 } },
+ { 0x4000, { 21600, 0x404, 0 } },
+ { 0x2001, { 0x406, 1, 2 } }
+};
+const sal_Int32 mso_sptBentConnector5Default[] =
+{
+ 3, 10800, 10800, 10800
+};
+const SvxMSDffHandle mso_sptBentConnector5Handle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0x100, 5 + 3, 10800, 10800, MIN_INT32, 0x7fffffff, 5 + 3, 5 + 3 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 3 + 3, 0x101, 10800, 10800, 3 + 3, 3 + 3, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0x102, 7 + 3, 10800, 10800, MIN_INT32, 0x7fffffff, 7 + 3, 7 + 3 }
+};
+const mso_CustomShape msoBentConnector5 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptBentConnector5Vert), SAL_N_ELEMENTS( mso_sptBentConnector5Vert ),
+ const_cast<sal_uInt16*>(mso_sptBentConnector5Segm), sizeof( mso_sptBentConnector5Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptBentConnector5Calc), SAL_N_ELEMENTS( mso_sptBentConnector5Calc ),
+ const_cast<sal_Int32*>(mso_sptBentConnector5Default),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptBentConnector5Handle), SAL_N_ELEMENTS( mso_sptBentConnector5Handle )
+};
+
+const SvxMSDffVertPair mso_sptCurvedConnector2Vert[] =
+{
+ { 0, 0 }, { 10800, 0 }, { 21600, 10800 }, { 21600, 21600 }
+};
+const sal_uInt16 mso_sptCurvedConnector2Segm[] =
+{
+ 0x4000, 0x2001, 0x8000
+};
+const mso_CustomShape msoCurvedConnector2 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedConnector2Vert), SAL_N_ELEMENTS( mso_sptCurvedConnector2Vert ),
+ const_cast<sal_uInt16*>(mso_sptCurvedConnector2Segm), sizeof( mso_sptCurvedConnector2Segm ) >> 1,
+ nullptr, 0,
+ nullptr,
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ nullptr, 0
+};
+
+const SvxMSDffVertPair mso_sptCurvedConnector3Vert[] =
+{
+ { 0, 0 }, { 1 MSO_I, 0 }, { 0 MSO_I, 5400 }, { 0 MSO_I, 10800 }, { 0 MSO_I, 16200 }, { 3 MSO_I, 21600 }, { 21600, 21600 }
+};
+const sal_uInt16 mso_sptCurvedConnector3Segm[] =
+{
+ 0x4000, 0x2002, 0x8000
+};
+const SvxMSDffCalculationData mso_sptCurvedConnector3Calc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2001, { 0x400, 1, 2 } },
+ { 0x2000, { 0x400, 21600, 0 } },
+ { 0x2001, { 0x402, 1, 2 } }
+};
+const sal_Int32 mso_sptCurvedConnector3Default[] =
+{
+ 1, 10800
+};
+const SvxMSDffHandle mso_sptCurvedConnector3Handle[] =
+{
+ { SvxMSDffHandleFlags::RANGE,
+ 0x100, 10800, 10800, 10800, MIN_INT32, 0x7fffffff, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoCurvedConnector3 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedConnector3Vert), SAL_N_ELEMENTS( mso_sptCurvedConnector3Vert ),
+ const_cast<sal_uInt16*>(mso_sptCurvedConnector3Segm), sizeof( mso_sptCurvedConnector3Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCurvedConnector3Calc), SAL_N_ELEMENTS( mso_sptCurvedConnector3Calc ),
+ const_cast<sal_Int32*>(mso_sptCurvedConnector3Default),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCurvedConnector3Handle), SAL_N_ELEMENTS( mso_sptCurvedConnector3Handle )
+};
+
+const SvxMSDffVertPair mso_sptCurvedConnector4Vert[] =
+{
+ { 0, 0 }, { 1 MSO_I, 0 }, { 0 MSO_I, 10 MSO_I }, { 0 MSO_I, 9 MSO_I },
+ { 0 MSO_I, 12 MSO_I }, { 5 MSO_I, 8 MSO_I }, { 3 MSO_I, 8 MSO_I },
+ { 7 MSO_I, 8 MSO_I }, { 21600, 14 MSO_I }, { 21600, 21600 }
+
+};
+const sal_uInt16 mso_sptCurvedConnector4Segm[] =
+{
+ 0x4000, 0x2003, 0x8000
+};
+const SvxMSDffCalculationData mso_sptCurvedConnector4Calc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2001, { 0x400, 1, 2 } },
+ { 0x4000, { 21600, 0x400, 0 } },
+ { 0x2001, { 0x402, 1, 2 } },
+ { 0x6000, { 0x400, 0x403, 0 } },
+ { 0x2001, { 0x404, 1, 2 } },
+ { 0x2000, { 0x403, 21600, 0 } },
+ { 0x2001, { 0x406, 1, 2 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x2001, { DFF_Prop_adjust2Value, 1, 2 } },
+ { 0x2001, { DFF_Prop_adjust2Value, 1, 4 } },
+ { 0x6000, { 0x408, 0x409, 0 } },
+ { 0x2001, { 0x40b, 1, 2 } },
+ { 0x2000, { 0x408, 21600, 0 } },
+ { 0x2001, { 0x40d, 1, 2 } }
+};
+const sal_Int32 mso_sptCurvedConnector4Default[] =
+{
+ 2, 10800, 10800
+};
+const SvxMSDffHandle mso_sptCurvedConnector4Handle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0x100, 9 + 3, 10800, 10800, MIN_INT32, 0x7fffffff, 9 + 3, 9 + 3 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 3 + 3, 0x101, 10800, 10800, 3 + 3, 3 + 3, MIN_INT32, 0x7fffffff }
+};
+const mso_CustomShape msoCurvedConnector4 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedConnector4Vert), SAL_N_ELEMENTS( mso_sptCurvedConnector4Vert ),
+ const_cast<sal_uInt16*>(mso_sptCurvedConnector4Segm), sizeof( mso_sptCurvedConnector4Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCurvedConnector4Calc), SAL_N_ELEMENTS( mso_sptCurvedConnector4Calc ),
+ const_cast<sal_Int32*>(mso_sptCurvedConnector4Default),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCurvedConnector4Handle), SAL_N_ELEMENTS( mso_sptCurvedConnector4Handle )
+};
+
+const SvxMSDffVertPair mso_sptCurvedConnector5Vert[] =
+{
+ { 0, 0 },
+ { 21 MSO_I, 0 }, { 0 MSO_I, 12 MSO_I }, { 0 MSO_I, 11 MSO_I },
+ { 0 MSO_I, 14 MSO_I }, { 6 MSO_I, 4 MSO_I }, { 3 MSO_I, 4 MSO_I },
+ { 8 MSO_I, 4 MSO_I }, { 1 MSO_I, 18 MSO_I }, { 1 MSO_I, 16 MSO_I },
+ { 1 MSO_I, 20 MSO_I }, { 10 MSO_I, 21600 }, { 21600, 21600 }
+};
+const sal_uInt16 mso_sptCurvedConnector5Segm[] =
+{
+ 0x4000, 0x2004, 0x8000
+};
+const SvxMSDffCalculationData mso_sptCurvedConnector5Calc[] =
+{
+ { 0x2000, { DFF_Prop_adjustValue, 0, 0 } },
+ { 0x2000, { DFF_Prop_adjust3Value, 0, 0 } },
+ { 0x6000, { 0x400, 0x401, 0 } },
+ { 0x2001, { 0x402, 1, 2 } },
+ { 0x2000, { DFF_Prop_adjust2Value, 0, 0 } },
+ { 0x6000, { 0x400, 0x403, 0 } },
+ { 0x2001, { 0x405, 1, 2 } },
+ { 0x6000, { 0x401, 0x403, 0 } },
+ { 0x2001, { 0x407, 1, 2 } },
+ { 0x2000, { 0x401, 21600, 0 } },
+ { 0x2001, { 0x409, 1, 2 } },
+ { 0x2001, { 0x404, 1, 2 } },
+ { 0x2001, { 0x40b, 1, 2 } },
+ { 0x6000, { 0x404, 0x40b, 0 } },
+ { 0x2001, { 0x40d, 1, 2 } },
+ { 0x2000, { 0x404, 21600, 0 } },
+ { 0x2001, { 0x40f, 1, 2 } },
+ { 0x6000, { 0x404, 0x410, 0 } },
+ { 0x2001, { 0x411, 1, 2 } },
+ { 0x2000, { 0x410, 21600, 0 } },
+ { 0x2001, { 0x413, 1, 2 } },
+ { 0x2001, { 0x400, 1, 2 } }
+};
+const sal_Int32 mso_sptCurvedConnector5Default[] =
+{
+ 3, 10800, 10800, 10800
+};
+const SvxMSDffHandle mso_sptCurvedConnector5Handle[] =
+{
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0x100, 11 + 3, 10800, 10800, MIN_INT32, 0x7fffffff, 11 + 3, 11 + 3 },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL,
+ 3 + 3, 0x101, 10800, 10800, 3 + 3, 3 + 3, MIN_INT32, 0x7fffffff },
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL | SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL,
+ 0x102, 16 + 3, 10800, 10800, MIN_INT32, 0x7fffffff, 16 + 3, 16 + 3 }
+};
+const mso_CustomShape msoCurvedConnector5 =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptCurvedConnector5Vert), SAL_N_ELEMENTS( mso_sptCurvedConnector5Vert ),
+ const_cast<sal_uInt16*>(mso_sptCurvedConnector5Segm), sizeof( mso_sptCurvedConnector5Segm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptCurvedConnector5Calc), SAL_N_ELEMENTS( mso_sptCurvedConnector5Calc ),
+ const_cast<sal_Int32*>(mso_sptCurvedConnector5Default),
+ nullptr, 0,
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptCurvedConnector5Handle), SAL_N_ELEMENTS( mso_sptCurvedConnector5Handle )
+};
+
+/////////////////////////////teardrop
+const SvxMSDffVertPair mso_sptTearDropVert[] =
+{
+ { 10800, 0 },
+ { 0, 10800 }, // X
+ { 10800, 21600 }, // Y
+ { 21600, 10800 }, // X
+ { 21600, 10800 }, { 21600, 3 MSO_I }, { 0 MSO_I, 1 MSO_I }, // C
+ { 0 MSO_I, 1 MSO_I }, { 4 MSO_I, 0 }, { 10800, 0 }
+};
+
+// the last number (0x***n) : 0 = sum, 1 = prod, 2 = mid, 3 = abs, 4 = min, 5 = max, 6 = if, 13 = sqrt, 15 = eclipse ...
+// the first number(0xn***) : 2/4/8 the first/second/third value is not directly value
+const SvxMSDffCalculationData mso_sptTearDropCalc[] =
+{
+ { 0x2000 , { DFF_Prop_adjustValue , 0 , 0 } }, // 0 adjust value #0
+ { 0x8000 , { 21600 , 0 , 0x0400 } }, // 1 21600 - @0 y0
+ { 0x8000 , { 32400 , 0 , 0x0400 } }, // 2 (32400 - @0)
+ { 0x2001 , { 0x0402 , 1 , 2 } }, // 3 (32400 - @0)/2 y1
+ { 0x2002 , { 0x0400 , 10800 , 0 } }, // 4 (@0+10800)/2 x2
+};
+
+//m, qx, qy, qx,C,C
+//the last number(0x***n) : repeat number of this current Segm
+const sal_uInt16 mso_sptTearDropSegm[] =
+{
+ 0x4000, 0xa701, 0xa801, 0xa701, 0x2002, 0x6000, 0x8000
+};
+
+const SvxMSDffTextRectangles mso_sptTearDropTextRect[] =
+{
+ { { 2863, 2863 }, { 18737, 18737 } }
+};
+
+//the range of adjust values
+const SvxMSDffHandle mso_sptTearDropHandle[] =
+{
+ //position="$0,0" xrange="10800,32400"
+ { SvxMSDffHandleFlags::RANGE | SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL| SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL,
+ 0x100, 0, 10800, 10800, 10800, 32400, MIN_INT32, 0x7fffffff }
+};
+
+//the number of adjust values, the default values
+const sal_Int32 mso_sptTearDropDefault[] =
+{
+ 1, 21600
+};
+
+const mso_CustomShape msoTearDrop =
+{
+ const_cast<SvxMSDffVertPair*>(mso_sptTearDropVert), SAL_N_ELEMENTS( mso_sptTearDropVert ),
+ const_cast<sal_uInt16*>(mso_sptTearDropSegm), sizeof( mso_sptTearDropSegm ) >> 1,
+ const_cast<SvxMSDffCalculationData*>(mso_sptTearDropCalc), SAL_N_ELEMENTS(mso_sptTearDropCalc),
+ const_cast<sal_Int32*>(mso_sptTearDropDefault),
+ const_cast<SvxMSDffTextRectangles*>(mso_sptTearDropTextRect), SAL_N_ELEMENTS( mso_sptTearDropTextRect ),
+ 21600, 21600,
+ MIN_INT32, MIN_INT32,
+ nullptr, 0,
+ const_cast<SvxMSDffHandle*>(mso_sptTearDropHandle), SAL_N_ELEMENTS(mso_sptTearDropHandle) // handles
+};
+
+
+const mso_CustomShape* GetCustomShapeContent( MSO_SPT eSpType )
+{
+ const mso_CustomShape* pCustomShape = nullptr;
+ switch( eSpType )
+ {
+ case mso_sptArc : pCustomShape = &msoArc; break;
+ case mso_sptLine: pCustomShape = &msoStraightConnector1; break;
+ case mso_sptRectangle : pCustomShape = &msoRectangle; break;
+ case mso_sptParallelogram : pCustomShape = &msoParallelogram; break;
+ case mso_sptTrapezoid : pCustomShape = &msoTrapezoid; break;
+ case mso_sptDiamond : pCustomShape = &msoDiamond; break;
+ case mso_sptRoundRectangle : pCustomShape = &msoRoundRectangle; break;
+ case mso_sptOctagon : pCustomShape = &msoOctagon; break;
+ case mso_sptIsocelesTriangle : pCustomShape = &msoIsocelesTriangle; break;
+ case mso_sptRightTriangle : pCustomShape = &msoRightTriangle; break;
+ case mso_sptEllipse : pCustomShape = &msoEllipse; break;
+ case mso_sptHexagon : pCustomShape = &msoHexagon; break;
+ case mso_sptPlus : pCustomShape = &msoPlus; break;
+ case mso_sptPentagon : pCustomShape = &msoPentagon; break;
+ case mso_sptCan : pCustomShape = &msoCan; break;
+ case mso_sptCube : pCustomShape = &msoCube; break;
+ case mso_sptBalloon : pCustomShape = &msoBalloon; break;
+ case mso_sptActionButtonBlank : pCustomShape = &msoActionButtonBlank; break;
+ case mso_sptActionButtonHome : pCustomShape = &msoActionButtonHome; break;
+ case mso_sptActionButtonHelp : pCustomShape = &msoActionButtonHelp; break;
+ case mso_sptActionButtonInformation : pCustomShape = &msoActionButtonInformation; break;
+ case mso_sptActionButtonBackPrevious : pCustomShape = &msoActionButtonBackPrevious; break;
+ case mso_sptActionButtonForwardNext : pCustomShape = &msoActionButtonForwardNext; break;
+ case mso_sptActionButtonBeginning : pCustomShape = &msoActionButtonBeginning; break;
+ case mso_sptActionButtonEnd : pCustomShape = &msoActionButtonEnd; break;
+ case mso_sptActionButtonReturn : pCustomShape = &msoActionButtonReturn; break;
+ case mso_sptActionButtonDocument : pCustomShape = &msoActionButtonDocument; break;
+ case mso_sptActionButtonSound : pCustomShape = &msoActionButtonSound; break;
+ case mso_sptActionButtonMovie : pCustomShape = &msoActionButtonMovie; break;
+ case mso_sptBevel : pCustomShape = &msoBevel; break;
+ case mso_sptFoldedCorner : pCustomShape = &msoFoldedCorner; break;
+ case mso_sptSmileyFace : pCustomShape = &msoSmileyFace; break;
+ case mso_sptDonut : pCustomShape = &msoDonut; break;
+ case mso_sptNoSmoking : pCustomShape = &msoNoSmoking; break;
+ case mso_sptBlockArc : pCustomShape = &msoBlockArc; break;
+ case mso_sptHeart : pCustomShape = &msoHeart; break;
+ case mso_sptLightningBolt : pCustomShape = &msoLightningBold; break;
+ case mso_sptSun : pCustomShape = &msoSun; break;
+ case mso_sptMoon : pCustomShape = &msoMoon; break;
+ case mso_sptBracketPair : pCustomShape = &msoBracketPair; break;
+ case mso_sptBracePair : pCustomShape = &msoBracePair; break;
+ case mso_sptPlaque : pCustomShape = &msoPlaque; break;
+ case mso_sptLeftBracket : pCustomShape = &msoLeftBracket; break;
+ case mso_sptRightBracket : pCustomShape = &msoRightBracket; break;
+ case mso_sptLeftBrace : pCustomShape = &msoLeftBrace; break;
+ case mso_sptRightBrace : pCustomShape = &msoRightBrace; break;
+ case mso_sptArrow : pCustomShape = &msoArrow; break;
+ case mso_sptUpArrow : pCustomShape = &msoUpArrow; break;
+ case mso_sptDownArrow : pCustomShape = &msoDownArrow; break;
+ case mso_sptLeftArrow : pCustomShape = &msoLeftArrow; break;
+ case mso_sptLeftRightArrow : pCustomShape = &msoLeftRightArrow; break;
+ case mso_sptUpDownArrow : pCustomShape = &msoUpDownArrow; break;
+ case mso_sptQuadArrow : pCustomShape = &msoQuadArrow; break;
+ case mso_sptLeftRightUpArrow : pCustomShape = &msoLeftRightUpArrow; break;
+ case mso_sptBentArrow : pCustomShape = &msoBentArrow; break;
+ case mso_sptUturnArrow : pCustomShape = &msoUturnArrow; break;
+ case mso_sptLeftUpArrow : pCustomShape = &msoLeftUpArrow; break;
+ case mso_sptBentUpArrow : pCustomShape = &msoBentUpArrow; break;
+ case mso_sptCurvedRightArrow : pCustomShape = &msoCurvedRightArrow; break;
+ case mso_sptCurvedLeftArrow : pCustomShape = &msoCurvedLeftArrow; break;
+ case mso_sptCurvedUpArrow : pCustomShape = &msoCurvedUpArrow; break;
+ case mso_sptCurvedDownArrow : pCustomShape = &msoCurvedDownArrow; break;
+ case mso_sptStripedRightArrow : pCustomShape = &msoStripedRightArrow; break;
+ case mso_sptNotchedRightArrow : pCustomShape = &msoNotchedRightArrow; break;
+ case mso_sptHomePlate : pCustomShape = &msoHomePlate; break;
+ case mso_sptChevron : pCustomShape = &msoChevron; break;
+ case mso_sptRightArrowCallout : pCustomShape = &msoRightArrowCallout; break;
+ case mso_sptLeftArrowCallout : pCustomShape = &msoLeftArrowCallout; break;
+ case mso_sptUpArrowCallout : pCustomShape = &msoUpArrowCallout; break;
+ case mso_sptDownArrowCallout : pCustomShape = &msoDownArrowCallout; break;
+ case mso_sptLeftRightArrowCallout : pCustomShape = &msoLeftRightArrowCallout; break;
+ case mso_sptUpDownArrowCallout : pCustomShape = &msoUpDownArrowCallout; break;
+ case mso_sptQuadArrowCallout : pCustomShape = &msoQuadArrowCallout; break;
+ case mso_sptCircularArrow : pCustomShape = &msoCircularArrow; break;
+ case mso_sptIrregularSeal1 : pCustomShape = &msoIrregularSeal1; break;
+ case mso_sptIrregularSeal2 : pCustomShape = &msoIrregularSeal2; break;
+ case mso_sptSeal4 : pCustomShape = &msoSeal4; break;
+ case mso_sptStar : pCustomShape = &msoStar; break;
+ case mso_sptSeal8 : pCustomShape = &msoSeal8; break;
+ case mso_sptSeal :
+ case mso_sptSeal16 : pCustomShape = &msoSeal16; break;
+ case mso_sptSeal24 : pCustomShape = &msoSeal24; break;
+ case mso_sptSeal32 : pCustomShape = &msoSeal32; break;
+ case mso_sptRibbon2 : pCustomShape = &msoRibbon2; break;
+ case mso_sptRibbon : pCustomShape = &msoRibbon; break;
+ case mso_sptEllipseRibbon2 : pCustomShape = &msosptEllipseRibbon2; break; // SJ: TODO
+ case mso_sptEllipseRibbon : pCustomShape = &msosptEllipseRibbon; break; // SJ: TODO
+ case mso_sptVerticalScroll : pCustomShape = &msoVerticalScroll; break;
+ case mso_sptHorizontalScroll : pCustomShape = &msoHorizontalScroll; break;
+ case mso_sptFlowChartProcess : pCustomShape = &msoFlowChartProcess; break;
+ case mso_sptFlowChartAlternateProcess : pCustomShape = &msoFlowChartAlternateProcess; break;
+ case mso_sptFlowChartDecision : pCustomShape = &msoFlowChartDecision; break;
+ case mso_sptFlowChartInputOutput : pCustomShape = &msoFlowChartInputOutput; break;
+ case mso_sptFlowChartPredefinedProcess :pCustomShape = &msoFlowChartPredefinedProcess; break;
+ case mso_sptFlowChartInternalStorage : pCustomShape = &msoFlowChartInternalStorage; break;
+ case mso_sptFlowChartDocument : pCustomShape = &msoFlowChartDocument; break;
+ case mso_sptFlowChartMultidocument : pCustomShape = &msoFlowChartMultidocument; break;
+ case mso_sptFlowChartTerminator : pCustomShape = &msoFlowChartTerminator; break;
+ case mso_sptFlowChartPreparation : pCustomShape = &msoFlowChartPreparation; break;
+ case mso_sptFlowChartManualInput : pCustomShape = &msoFlowChartManualInput; break;
+ case mso_sptFlowChartManualOperation : pCustomShape = &msoFlowChartManualOperation; break;
+ case mso_sptFlowChartConnector : pCustomShape = &msoFlowChartConnector; break;
+ case mso_sptFlowChartOffpageConnector : pCustomShape = &msoFlowChartOffpageConnector; break;
+ case mso_sptFlowChartPunchedCard : pCustomShape = &msoFlowChartPunchedCard; break;
+ case mso_sptFlowChartPunchedTape : pCustomShape = &msoFlowChartPunchedTape; break;
+ case mso_sptFlowChartSummingJunction : pCustomShape = &msoFlowChartSummingJunction; break;
+ case mso_sptFlowChartOr : pCustomShape = &msoFlowChartOr; break;
+ case mso_sptFlowChartCollate : pCustomShape = &msoFlowChartCollate; break;
+ case mso_sptFlowChartSort : pCustomShape = &msoFlowChartSort; break;
+ case mso_sptFlowChartExtract : pCustomShape = &msoFlowChartExtract; break;
+ case mso_sptFlowChartMerge : pCustomShape = &msoFlowChartMerge; break;
+ case mso_sptFlowChartOnlineStorage : pCustomShape = &msoFlowChartOnlineStorage; break;
+ case mso_sptFlowChartDelay : pCustomShape = &msoFlowChartDelay; break;
+ case mso_sptFlowChartMagneticTape : pCustomShape = &msoFlowChartMagneticTape; break;
+ case mso_sptFlowChartMagneticDisk : pCustomShape = &msoFlowChartMagneticDisk; break;
+ case mso_sptFlowChartMagneticDrum : pCustomShape = &msoFlowChartMagneticDrum; break;
+ case mso_sptFlowChartDisplay : pCustomShape = &msoFlowChartDisplay; break;
+ case mso_sptWedgeRectCallout : pCustomShape = &msoWedgeRectCallout; break;
+ case mso_sptWedgeRRectCallout : pCustomShape = &msoWedgeRRectCallout; break;
+ case mso_sptWedgeEllipseCallout : pCustomShape = &msoWedgeEllipseCallout; break;
+ case mso_sptCloudCallout : pCustomShape = &msoCloudCallout; break;
+ case mso_sptWave : pCustomShape = &msoWave; break;
+ case mso_sptDoubleWave : pCustomShape = &msoDoubleWave; break;
+
+ // callout
+ case mso_sptCallout1 : pCustomShape = &msoCallout1; break;
+ case mso_sptCallout2 : pCustomShape = &msoCallout2; break;
+ case mso_sptCallout3 : pCustomShape = &msoCallout3; break;
+ case mso_sptAccentCallout1 : pCustomShape = &msoAccentCallout1; break;
+ case mso_sptAccentCallout2 : pCustomShape = &msoAccentCallout2; break;
+ case mso_sptAccentCallout3 : pCustomShape = &msoAccentCallout3; break;
+ case mso_sptBorderCallout1 : pCustomShape = &msoBorderCallout1; break;
+ case mso_sptBorderCallout2 : pCustomShape = &msoBorderCallout2; break;
+ case mso_sptBorderCallout3 : pCustomShape = &msoBorderCallout3; break;
+ case mso_sptAccentBorderCallout1 : pCustomShape = &msoAccentBorderCallout1; break;
+ case mso_sptAccentBorderCallout2 : pCustomShape = &msoAccentBorderCallout2; break;
+ case mso_sptAccentBorderCallout3 : pCustomShape = &msoAccentBorderCallout3; break;
+ case mso_sptCallout90 : pCustomShape = &msoCallout90; break;
+ case mso_sptAccentCallout90 : pCustomShape = &msoAccentCallout90; break;
+ case mso_sptBorderCallout90 : pCustomShape = &msoBorderCallout90; break;
+ case mso_sptAccentBorderCallout90 : pCustomShape = &msoAccentBorderCallout90; break;
+
+ // connectors
+ case mso_sptStraightConnector1 : pCustomShape = &msoStraightConnector1; break;
+ case mso_sptBentConnector2 : pCustomShape = &msoBentConnector2; break;
+ case mso_sptBentConnector3 : pCustomShape = &msoBentConnector3; break;
+ case mso_sptBentConnector4 : pCustomShape = &msoBentConnector4; break;
+ case mso_sptBentConnector5 : pCustomShape = &msoBentConnector5; break;
+ case mso_sptCurvedConnector2 : pCustomShape = &msoCurvedConnector2; break;
+ case mso_sptCurvedConnector3 : pCustomShape = &msoCurvedConnector3; break;
+ case mso_sptCurvedConnector4 : pCustomShape = &msoCurvedConnector4; break;
+ case mso_sptCurvedConnector5 : pCustomShape = &msoCurvedConnector5; break;
+
+ // Don't know, simply mapping to TextSimple
+ case mso_sptTextOnRing :
+ case mso_sptTextOnCurve :
+ case mso_sptTextRing :
+ case mso_sptTextWave :
+ case mso_sptTextCurve :
+ case mso_sptTextHexagon :
+ case mso_sptTextOctagon :
+ case mso_sptTextBox : pCustomShape = &msoTextSimple; break;
+
+ // FontWork
+ case mso_sptTextSimple :
+ case mso_sptTextPlainText : pCustomShape = &msoTextPlainText; break;
+ case mso_sptTextStop : pCustomShape = &msoTextStop; break;
+ case mso_sptTextTriangle : pCustomShape = &msoTextTriangle; break;
+ case mso_sptTextTriangleInverted : pCustomShape = &msoTextTriangleInverted; break;
+ case mso_sptTextChevron : pCustomShape = &msoTextChevron; break;
+ case mso_sptTextChevronInverted : pCustomShape = &msoTextChevronInverted; break;
+ case mso_sptTextRingInside : pCustomShape = &msoTextRingInside; break; // SJ: TODO->the orientation of the ellipse needs to be changed
+ case mso_sptTextRingOutside : pCustomShape = &msoTextRingOutside; break;
+ case mso_sptTextFadeRight : pCustomShape = &msoTextFadeRight; break;
+ case mso_sptTextFadeLeft : pCustomShape = &msoTextFadeLeft; break;
+ case mso_sptTextFadeUp : pCustomShape = &msoTextFadeUp; break;
+ case mso_sptTextFadeDown : pCustomShape = &msoTextFadeDown; break;
+ case mso_sptTextSlantUp : pCustomShape = &msoTextSlantUp; break;
+ case mso_sptTextSlantDown : pCustomShape = &msoTextSlantDown; break;
+ case mso_sptTextCascadeUp : pCustomShape = &msoTextCascadeUp; break;
+ case mso_sptTextCascadeDown : pCustomShape = &msoTextCascadeDown; break;
+ case mso_sptTextArchUpCurve : pCustomShape = &msoTextArchUpCurve; break;
+ case mso_sptTextArchDownCurve : pCustomShape = &msoTextArchDownCurve; break;
+ case mso_sptTextCircleCurve : pCustomShape = &msoTextCircleCurve; break;
+ case mso_sptTextButtonCurve : pCustomShape = &msoTextButtonCurve; break;
+ case mso_sptTextArchUpPour : pCustomShape = &msoTextArchUpPour; break;
+ case mso_sptTextArchDownPour : pCustomShape = &msoTextArchDownPour; break;
+ case mso_sptTextCirclePour : pCustomShape = &msoTextCirclePour; break;
+ case mso_sptTextButtonPour : pCustomShape = &msoTextButtonPour; break;
+ case mso_sptTextCurveUp : pCustomShape = &msoTextCurveUp; break;
+ case mso_sptTextCurveDown : pCustomShape = &msoTextCurveDown; break;
+ case mso_sptTextCanUp : pCustomShape = &msoTextCanUp; break;
+ case mso_sptTextCanDown : pCustomShape = &msoTextCanDown; break;
+ case mso_sptTextInflate : pCustomShape = &msoTextInflate; break;
+ case mso_sptTextDeflate : pCustomShape = &msoTextDeflate; break;
+ case mso_sptTextInflateBottom : pCustomShape = &msoTextInflateBottom; break;
+ case mso_sptTextDeflateBottom : pCustomShape = &msoTextDeflateBottom; break;
+ case mso_sptTextInflateTop : pCustomShape = &msoTextInflateTop; break;
+ case mso_sptTextDeflateTop : pCustomShape = &msoTextDeflateTop; break;
+ case mso_sptTextDeflateInflate : pCustomShape = &msoTextDeflateInflate; break;
+ case mso_sptTextDeflateInflateDeflate : pCustomShape = &msoTextDeflateInflateDeflate; break;
+ case mso_sptTextWave1 : pCustomShape = &msoTextWave1; break;
+ case mso_sptTextWave2 : pCustomShape = &msoTextWave2; break;
+ case mso_sptTextWave3 : pCustomShape = &msoTextWave3; break;
+ case mso_sptTextWave4 : pCustomShape = &msoTextWave4; break;
+ case mso_sptTearDrop : pCustomShape = &msoTearDrop; break;
+ default :
+ break;
+ }
+ return pCustomShape;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShapeHandle.cxx b/svx/source/customshapes/EnhancedCustomShapeHandle.cxx
new file mode 100644
index 000000000..8dce09c1c
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShapeHandle.cxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "EnhancedCustomShapeHandle.hxx"
+#include <svx/EnhancedCustomShape2d.hxx>
+#include <svx/svdoashp.hxx>
+
+
+EnhancedCustomShapeHandle::EnhancedCustomShapeHandle( css::uno::Reference< css::drawing::XShape > const & xCustomShape, sal_uInt32 nIndex ) :
+ mnIndex ( nIndex ),
+ mxCustomShape ( xCustomShape )
+{
+}
+
+
+EnhancedCustomShapeHandle::~EnhancedCustomShapeHandle()
+{
+}
+
+
+void SAL_CALL EnhancedCustomShapeHandle::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+
+void SAL_CALL EnhancedCustomShapeHandle::release() noexcept
+{
+ OWeakObject::release();
+}
+
+// XCustomShapeHandle
+css::awt::Point SAL_CALL EnhancedCustomShapeHandle::getPosition()
+{
+ auto pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxCustomShape));
+
+ if(!pSdrObjCustomShape)
+ {
+ throw css::uno::RuntimeException();
+ }
+
+ Point aPosition;
+ EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
+
+ if(!aCustomShape2d.GetHandlePosition(mnIndex, aPosition))
+ {
+ throw css::uno::RuntimeException();
+ }
+
+ return css::awt::Point( aPosition.X(), aPosition.Y() );
+}
+
+void SAL_CALL EnhancedCustomShapeHandle::setControllerPosition( const css::awt::Point& aPnt )
+{
+ auto pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(mxCustomShape));
+
+ if(!pSdrObjCustomShape)
+ {
+ throw css::uno::RuntimeException();
+ }
+
+ EnhancedCustomShape2d aCustomShape2d(*pSdrObjCustomShape);
+
+ if(!aCustomShape2d.SetHandleControllerPosition(mnIndex, aPnt))
+ {
+ throw css::uno::RuntimeException();
+ }
+}
+
+// XInitialization
+void SAL_CALL EnhancedCustomShapeHandle::initialize( const css::uno::Sequence< css::uno::Any >& /* aArguments */ )
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShapeHandle.hxx b/svx/source/customshapes/EnhancedCustomShapeHandle.hxx
new file mode 100644
index 000000000..b56909420
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShapeHandle.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_CUSTOMSHAPES_ENHANCEDCUSTOMSHAPEHANDLE_HXX
+#define INCLUDED_SVX_SOURCE_CUSTOMSHAPES_ENHANCEDCUSTOMSHAPEHANDLE_HXX
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/XCustomShapeHandle.hpp>
+#include <com/sun/star/awt/Point.hpp>
+
+class EnhancedCustomShapeHandle : public cppu::WeakImplHelper
+<
+ css::drawing::XCustomShapeHandle,
+ css::lang::XInitialization
+>
+{
+ sal_uInt32 mnIndex;
+ css::uno::Reference< css::drawing::XShape > mxCustomShape;
+
+public:
+
+ EnhancedCustomShapeHandle( css::uno::Reference< css::drawing::XShape > const & xCustomShape, sal_uInt32 nIndex );
+ virtual ~EnhancedCustomShapeHandle() override;
+
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XCustomShapeHandle
+ virtual css::awt::Point SAL_CALL getPosition() override;
+ virtual void SAL_CALL setControllerPosition( const css::awt::Point& ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/customshapes/EnhancedCustomShapeTypeNames.cxx b/svx/source/customshapes/EnhancedCustomShapeTypeNames.cxx
new file mode 100644
index 000000000..70c15ca66
--- /dev/null
+++ b/svx/source/customshapes/EnhancedCustomShapeTypeNames.cxx
@@ -0,0 +1,548 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/EnhancedCustomShapeTypeNames.hxx>
+#include <unordered_map>
+
+namespace {
+
+struct NameTypeTable
+{
+ const char* pS;
+ MSO_SPT pE;
+};
+
+}
+
+const NameTypeTable pNameTypeTableArray[] =
+{
+ { "non-primitive", mso_sptMin },
+ { "rectangle", mso_sptRectangle },
+ { "round-rectangle", mso_sptRoundRectangle },
+ { "ellipse", mso_sptEllipse },
+ { "diamond", mso_sptDiamond },
+ { "isosceles-triangle", mso_sptIsocelesTriangle },
+ { "right-triangle", mso_sptRightTriangle },
+ { "parallelogram", mso_sptParallelogram },
+ { "trapezoid", mso_sptTrapezoid },
+ { "hexagon", mso_sptHexagon },
+ { "octagon", mso_sptOctagon },
+ { "cross", mso_sptPlus },
+ { "star5", mso_sptStar },
+ { "right-arrow", mso_sptArrow },
+ { "mso-spt14", mso_sptThickArrow },
+ { "pentagon-right", mso_sptHomePlate },
+ { "cube", mso_sptCube },
+ { "mso-spt17", mso_sptBalloon },
+ { "mso-spt18", mso_sptSeal },
+ { "mso-spt19", mso_sptArc },
+ { "mso-spt20", mso_sptLine },
+ { "mso-spt21", mso_sptPlaque },
+ { "can", mso_sptCan },
+ { "ring", mso_sptDonut },
+ { "mso-spt24", mso_sptTextSimple },
+ { "mso-spt25", mso_sptTextOctagon },
+ { "mso-spt26", mso_sptTextHexagon },
+ { "mso-spt27", mso_sptTextCurve },
+ { "mso-spt28", mso_sptTextWave },
+ { "mso-spt29", mso_sptTextRing },
+ { "mso-spt30", mso_sptTextOnCurve },
+ { "mso-spt31", mso_sptTextOnRing },
+ { "mso-spt32", mso_sptStraightConnector1 },
+ { "mso-spt33", mso_sptBentConnector2 },
+ { "mso-spt34", mso_sptBentConnector3 },
+ { "mso-spt35", mso_sptBentConnector4 },
+ { "mso-spt36", mso_sptBentConnector5 },
+ { "mso-spt37", mso_sptCurvedConnector2 },
+ { "mso-spt38", mso_sptCurvedConnector3 },
+ { "mso-spt39", mso_sptCurvedConnector4 },
+ { "mso-spt40", mso_sptCurvedConnector5 },
+ { "mso-spt41", mso_sptCallout1 },
+ { "mso-spt42", mso_sptCallout2 },
+ { "mso-spt43", mso_sptCallout3 },
+ { "mso-spt44", mso_sptAccentCallout1 },
+ { "mso-spt45", mso_sptAccentCallout2 },
+ { "mso-spt46", mso_sptAccentCallout3 },
+ { "line-callout-1", mso_sptBorderCallout1 },
+ { "line-callout-2", mso_sptBorderCallout2 },
+ { "mso-spt49", mso_sptBorderCallout3 },
+ { "mso-spt50", mso_sptAccentBorderCallout1 },
+ { "mso-spt51", mso_sptAccentBorderCallout2 },
+ { "mso-spt52", mso_sptAccentBorderCallout3 },
+ { "mso-spt53", mso_sptRibbon },
+ { "mso-spt54", mso_sptRibbon2 },
+ { "chevron", mso_sptChevron },
+ { "pentagon", mso_sptPentagon },
+ { "forbidden", mso_sptNoSmoking },
+ { "star8", mso_sptSeal8 },
+ { "mso-spt59", mso_sptSeal16 },
+ { "mso-spt60", mso_sptSeal32 },
+ { "rectangular-callout", mso_sptWedgeRectCallout },
+ { "round-rectangular-callout", mso_sptWedgeRRectCallout },
+ { "round-callout", mso_sptWedgeEllipseCallout },
+ { "mso-spt64", mso_sptWave },
+ { "paper", mso_sptFoldedCorner },
+ { "left-arrow", mso_sptLeftArrow },
+ { "down-arrow", mso_sptDownArrow },
+ { "up-arrow", mso_sptUpArrow },
+ { "left-right-arrow", mso_sptLeftRightArrow },
+ { "up-down-arrow", mso_sptUpDownArrow },
+ { "mso-spt71", mso_sptIrregularSeal1 },
+ { "bang", mso_sptIrregularSeal2 },
+ { "lightning", mso_sptLightningBolt },
+ { "heart", mso_sptHeart },
+ { "mso-spt75", mso_sptPictureFrame },
+ { "quad-arrow", mso_sptQuadArrow },
+ { "left-arrow-callout", mso_sptLeftArrowCallout },
+ { "right-arrow-callout", mso_sptRightArrowCallout },
+ { "up-arrow-callout", mso_sptUpArrowCallout },
+ { "down-arrow-callout", mso_sptDownArrowCallout },
+ { "left-right-arrow-callout", mso_sptLeftRightArrowCallout },
+ { "up-down-arrow-callout", mso_sptUpDownArrowCallout },
+ { "quad-arrow-callout", mso_sptQuadArrowCallout },
+ { "quad-bevel", mso_sptBevel },
+ { "left-bracket", mso_sptLeftBracket },
+ { "right-bracket", mso_sptRightBracket },
+ { "left-brace", mso_sptLeftBrace },
+ { "right-brace", mso_sptRightBrace },
+ { "mso-spt89", mso_sptLeftUpArrow },
+ { "mso-spt90", mso_sptBentUpArrow },
+ { "mso-spt91", mso_sptBentArrow },
+ { "star24", mso_sptSeal24 },
+ { "striped-right-arrow", mso_sptStripedRightArrow },
+ { "notched-right-arrow", mso_sptNotchedRightArrow },
+ { "block-arc", mso_sptBlockArc },
+ { "smiley", mso_sptSmileyFace },
+ { "vertical-scroll", mso_sptVerticalScroll },
+ { "horizontal-scroll", mso_sptHorizontalScroll },
+ { "circular-arrow", mso_sptCircularArrow },
+ { "mso-spt100", mso_sptNotchedCircularArrow },
+ { "mso-spt101", mso_sptUturnArrow },
+ { "mso-spt102", mso_sptCurvedRightArrow },
+ { "mso-spt103", mso_sptCurvedLeftArrow },
+ { "mso-spt104", mso_sptCurvedUpArrow },
+ { "mso-spt105", mso_sptCurvedDownArrow },
+ { "cloud-callout", mso_sptCloudCallout },
+ { "mso-spt107", mso_sptEllipseRibbon },
+ { "mso-spt108", mso_sptEllipseRibbon2 },
+ { "flowchart-process", mso_sptFlowChartProcess },
+ { "flowchart-decision", mso_sptFlowChartDecision },
+ { "flowchart-data", mso_sptFlowChartInputOutput },
+ { "flowchart-predefined-process", mso_sptFlowChartPredefinedProcess },
+ { "flowchart-internal-storage", mso_sptFlowChartInternalStorage },
+ { "flowchart-document", mso_sptFlowChartDocument },
+ { "flowchart-multidocument", mso_sptFlowChartMultidocument },
+ { "flowchart-terminator", mso_sptFlowChartTerminator },
+ { "flowchart-preparation", mso_sptFlowChartPreparation },
+ { "flowchart-manual-input", mso_sptFlowChartManualInput },
+ { "flowchart-manual-operation", mso_sptFlowChartManualOperation },
+ { "flowchart-connector", mso_sptFlowChartConnector },
+ { "flowchart-card", mso_sptFlowChartPunchedCard },
+ { "flowchart-punched-tape", mso_sptFlowChartPunchedTape },
+ { "flowchart-summing-junction", mso_sptFlowChartSummingJunction },
+ { "flowchart-or", mso_sptFlowChartOr },
+ { "flowchart-collate", mso_sptFlowChartCollate },
+ { "flowchart-sort", mso_sptFlowChartSort },
+ { "flowchart-extract", mso_sptFlowChartExtract },
+ { "flowchart-merge", mso_sptFlowChartMerge },
+ { "mso-spt129", mso_sptFlowChartOfflineStorage },
+ { "flowchart-stored-data", mso_sptFlowChartOnlineStorage },
+ { "flowchart-sequential-access", mso_sptFlowChartMagneticTape },
+ { "flowchart-magnetic-disk", mso_sptFlowChartMagneticDisk },
+ { "flowchart-direct-access-storage", mso_sptFlowChartMagneticDrum },
+ { "flowchart-display", mso_sptFlowChartDisplay },
+ { "flowchart-delay", mso_sptFlowChartDelay },
+ { "fontwork-plain-text", mso_sptTextPlainText },
+ { "fontwork-stop", mso_sptTextStop },
+ { "fontwork-triangle-up", mso_sptTextTriangle },
+ { "fontwork-triangle-down", mso_sptTextTriangleInverted },
+ { "fontwork-chevron-up", mso_sptTextChevron },
+ { "fontwork-chevron-down", mso_sptTextChevronInverted },
+ { "mso-spt142", mso_sptTextRingInside },
+ { "mso-spt143", mso_sptTextRingOutside },
+ { "fontwork-arch-up-curve", mso_sptTextArchUpCurve },
+ { "fontwork-arch-down-curve", mso_sptTextArchDownCurve },
+ { "fontwork-circle-curve", mso_sptTextCircleCurve },
+ { "fontwork-open-circle-curve", mso_sptTextButtonCurve },
+ { "fontwork-arch-up-pour", mso_sptTextArchUpPour },
+ { "fontwork-arch-down-pour", mso_sptTextArchDownPour },
+ { "fontwork-circle-pour", mso_sptTextCirclePour },
+ { "fontwork-open-circle-pour", mso_sptTextButtonPour },
+ { "fontwork-curve-up", mso_sptTextCurveUp },
+ { "fontwork-curve-down", mso_sptTextCurveDown },
+ { "fontwork-fade-up-and-right", mso_sptTextCascadeUp },
+ { "fontwork-fade-up-and-left", mso_sptTextCascadeDown },
+ { "fontwork-wave", mso_sptTextWave1 },
+ { "mso-spt157", mso_sptTextWave2 },
+ { "mso-spt158", mso_sptTextWave3 },
+ { "mso-spt159", mso_sptTextWave4 },
+ { "fontwork-inflate", mso_sptTextInflate },
+ { "mso-spt161", mso_sptTextDeflate },
+ { "mso-spt162", mso_sptTextInflateBottom },
+ { "mso-spt163", mso_sptTextDeflateBottom },
+ { "mso-spt164", mso_sptTextInflateTop },
+ { "mso-spt165", mso_sptTextDeflateTop },
+ { "mso-spt166", mso_sptTextDeflateInflate },
+ { "mso-spt167", mso_sptTextDeflateInflateDeflate },
+ { "fontwork-fade-right", mso_sptTextFadeRight },
+ { "fontwork-fade-left", mso_sptTextFadeLeft },
+ { "fontwork-fade-up", mso_sptTextFadeUp },
+ { "fontwork-fade-down", mso_sptTextFadeDown },
+ { "fontwork-slant-up", mso_sptTextSlantUp },
+ { "fontwork-slant-down", mso_sptTextSlantDown },
+ { "mso-spt174", mso_sptTextCanUp },
+ { "mso-spt175", mso_sptTextCanDown },
+ { "flowchart-alternate-process", mso_sptFlowChartAlternateProcess },
+ { "flowchart-off-page-connector", mso_sptFlowChartOffpageConnector },
+ { "mso-spt178", mso_sptCallout90 },
+ { "mso-spt179", mso_sptAccentCallout90 },
+ { "mso-spt180", mso_sptBorderCallout90 },
+ { "line-callout-3", mso_sptAccentBorderCallout90 },
+ { "mso-spt182", mso_sptLeftRightUpArrow },
+ { "sun", mso_sptSun },
+ { "moon", mso_sptMoon },
+ { "bracket-pair", mso_sptBracketPair },
+ { "brace-pair", mso_sptBracePair },
+ { "star4", mso_sptSeal4 },
+ { "mso-spt188", mso_sptDoubleWave },
+ { "mso-spt189", mso_sptActionButtonBlank },
+ { "mso-spt190", mso_sptActionButtonHome },
+ { "mso-spt191", mso_sptActionButtonHelp },
+ { "mso-spt192", mso_sptActionButtonInformation },
+ { "mso-spt193", mso_sptActionButtonForwardNext },
+ { "mso-spt194", mso_sptActionButtonBackPrevious },
+ { "mso-spt195", mso_sptActionButtonEnd },
+ { "mso-spt196", mso_sptActionButtonBeginning },
+ { "mso-spt197", mso_sptActionButtonReturn },
+ { "mso-spt198", mso_sptActionButtonDocument },
+ { "mso-spt199", mso_sptActionButtonSound },
+ { "mso-spt200", mso_sptActionButtonMovie },
+ { "mso-spt201", mso_sptHostControl },
+ { "mso-spt202", mso_sptTextBox },
+ { "teardrop", mso_sptTearDrop },
+ { "ooxml-rect", mso_sptRectangle }
+};
+
+ // gallery: quadrat
+ // gallery: round-quadrat
+ // gallery: circle
+ // gallery: circle-pie
+ // gallery: frame
+ // gallery: flower
+ // gallery: cloud
+ // gallery: puzzle
+ // gallery: octagon-bevel
+ // gallery: diamond-bevel
+ // gallery: up-right-arrow
+ // gallery: up-right-down-arrow
+ // gallery: corner-right-arrow
+ // gallery: split-arrow
+ // gallery: up-right-arrow-callout
+ // gallery: split-round-arrow
+ // gallery: s-sharped-arrow
+ // Gallery: star6
+ // Gallery: star12
+ // Gallery: concave-star6
+ // Gallery: signet
+ // Gallery: doorplate
+ // gallery: fontwork-arch-left-curve
+ // gallery: fontwork-arch-right-curve
+ // gallery: fontwork-arch-left-pour
+ // gallery: fontwork-arch-right-pour
+
+
+typedef std::unordered_map< OUString, MSO_SPT> TypeNameHashMap;
+
+static const TypeNameHashMap& GetTypeNameHashMap()
+{
+ static TypeNameHashMap aMap = []()
+ {
+ TypeNameHashMap map;
+ for (auto const & i : pNameTypeTableArray)
+ map[OUString::createFromAscii(i.pS)] = i.pE;
+ return map;
+ }();
+ return aMap;
+}
+
+
+MSO_SPT EnhancedCustomShapeTypeNames::Get( const OUString& rShapeType )
+{
+ const TypeNameHashMap & rTypeMap = GetTypeNameHashMap();
+ MSO_SPT eRetValue = mso_sptNil;
+ auto aHashIter = rTypeMap.find( rShapeType );
+ if ( aHashIter != rTypeMap.end() )
+ eRetValue = (*aHashIter).second;
+ return eRetValue;
+}
+
+OUString EnhancedCustomShapeTypeNames::Get( const MSO_SPT eShapeType )
+{
+ return (eShapeType <= mso_sptTextBox && eShapeType >= mso_sptMin)
+ ? OUString::createFromAscii( pNameTypeTableArray[ eShapeType ].pS )
+ : OUString();
+}
+
+namespace {
+
+struct ACCNameTypeTable
+{
+ const char* pS;
+ const char* pE;
+};
+
+}
+
+const ACCNameTypeTable pACCNameTypeTableArray[] =
+{
+ { "non-primitive", "Non Primitive Shape" },
+ { "rectangle", "Rectangle" },
+ { "round-rectangle", "Rounded Rectangle" },
+ { "ellipse", "Ellipse" },
+ { "diamond", "Diamond" },
+ { "isosceles-triangle", "Triangle" },
+ { "right-triangle", "Right Triangle" },
+ { "parallelogram", "Parallelogram" },
+ { "trapezoid", "Trapezoid" },
+ { "hexagon", "Hexagon" },
+ { "octagon", "Octagon" },
+ { "cross", "Cross" },
+ { "star5", "5-Point Star" },
+ { "right-arrow", "Right Arrow" },
+ //{ "mso-spt14", mso_sptThickArrow },
+ { "pentagon-right", "Pentagon" },
+ { "cube", "Cube" },
+ { "mso-spt21", "Doorplate" },
+ /*{ "mso-spt17", mso_sptBalloon },
+ { "mso-spt18", mso_sptSeal },
+ { "mso-spt19", mso_sptArc },
+ { "mso-spt20", mso_sptLine },
+ { "mso-spt21", mso_sptPlaque },
+ { "can", mso_sptCan },*/
+ { "ring", "Ring" },
+ /*{ "mso-spt24", mso_sptTextSimple },
+ { "mso-spt25", mso_sptTextOctagon },
+ { "mso-spt26", mso_sptTextHexagon },
+ { "mso-spt27", mso_sptTextCurve },
+ { "mso-spt28", mso_sptTextWave },
+ { "mso-spt29", mso_sptTextRing },
+ { "mso-spt30", mso_sptTextOnCurve },
+ { "mso-spt31", mso_sptTextOnRing },
+ { "mso-spt32", mso_sptStraightConnector1 },
+ { "mso-spt33", mso_sptBentConnector2 },
+ { "mso-spt34", mso_sptBentConnector3 },
+ { "mso-spt35", mso_sptBentConnector4 },
+ { "mso-spt36", mso_sptBentConnector5 },
+ { "mso-spt37", mso_sptCurvedConnector2 },
+ { "mso-spt38", mso_sptCurvedConnector3 },
+ { "mso-spt39", mso_sptCurvedConnector4 },
+ { "mso-spt40", mso_sptCurvedConnector5 },
+ { "mso-spt41", mso_sptCallout1 },
+ { "mso-spt42", mso_sptCallout2 },
+ { "mso-spt43", mso_sptCallout3 },
+ { "mso-spt44", mso_sptAccentCallout1 },
+ { "mso-spt45", mso_sptAccentCallout2 },
+ { "mso-spt46", mso_sptAccentCallout3 },*/
+ { "line-callout-1", "Line Callout 1" },
+ { "line-callout-2", "Line Callout 2" },
+ /*{ "mso-spt49", mso_sptBorderCallout3 },
+ { "mso-spt50", mso_sptAccentBorderCallout1 },
+ { "mso-spt51", mso_sptAccentBorderCallout2 },
+ { "mso-spt52", mso_sptAccentBorderCallout3 },
+ { "mso-spt53", mso_sptRibbon },
+ { "mso-spt54", mso_sptRibbon2 },*/
+ { "chevron", "Chevron" },
+ { "pentagon", "Regular Pentagon" },
+ { "forbidden", "'No' Symbol" },
+ { "star8", "8-Point Star" },
+ /*{ "mso-spt59", mso_sptSeal16 },
+ { "mso-spt60", mso_sptSeal32 },*/
+ { "rectangular-callout", "Rectangular Callout" },
+ { "round-rectangular-callout", "Rounded Rectangular Callout" },
+ { "round-callout", "Round Callout" },
+ //{ "mso-spt64", mso_sptWave },
+ { "paper", "Folded Corner" },
+ { "left-arrow", "Left Arrow" },
+ { "down-arrow", "Down Arrow" },
+ { "up-arrow", "Up Arrow" },
+ { "left-right-arrow", "Left and Right Arrow" },
+ { "up-down-arrow", "Up and Down Arrow" },
+ //{ "mso-spt71", mso_sptIrregularSeal1 },
+ { "bang", "Explosion" },
+ { "lightning", "Lighting Bolt" },
+ { "heart", "Heart" },
+ //{ "mso-spt75", mso_sptPictureFrame },
+ { "quad-arrow", "4-Way Arrow" },
+ { "left-arrow-callout", "Left Arrow Callout" },
+ { "right-arrow-callout", "Right Arrow Callout" },
+ { "up-arrow-callout", "Up Arrow Callout" },
+ { "down-arrow-callout", "Down Arrow Callout" },
+ { "left-right-arrow-callout", "Left and Right Arrow Callout" },
+ { "up-down-arrow-callout", "Up and Down Arrow Callout" },
+ { "quad-arrow-callout", "4-Way Arrow Callout" },
+ { "quad-bevel", "Square Bevel" },
+ { "left-bracket", "Left Bracket" },
+ { "right-bracket", "Right Bracket" },
+ { "left-brace", "Left Brace" },
+ { "right-brace", "Right Brace" },
+ { "mso-spt89", "Up and Left Arrow" },
+ //{ "mso-spt90", mso_sptBentUpArrow },
+ //{ "mso-spt91", mso_sptBentArrow },
+ { "star24", "24-Point Star" },
+ { "striped-right-arrow", "Striped Right Arrow" },
+ { "notched-right-arrow", "Notched Right Arrow" },
+ { "block-arc", "Block Arc" },
+ { "smiley", "Smile Face" },
+ { "vertical-scroll", "Vertical Scroll" },
+ { "horizontal-scroll", "Horizontal Scroll" },
+ { "circular-arrow", "Circular Arrow" },
+ { "mso-spt100", "Notched Circular Arrow" },
+ /*
+ { "mso-spt101", mso_sptUturnArrow },
+ { "mso-spt102", mso_sptCurvedRightArrow },
+ { "mso-spt103", mso_sptCurvedLeftArrow },
+ { "mso-spt104", mso_sptCurvedUpArrow },
+ { "mso-spt105", mso_sptCurvedDownArrow },*/
+ { "cloud-callout", "Cloud Callout" },
+ /*{ "mso-spt107", mso_sptEllipseRibbon },
+ { "mso-spt108", mso_sptEllipseRibbon2 },*/
+ { "flowchart-process", "Flowchart:Process" },
+ { "flowchart-decision", "Flowchart:Decision" },
+ { "flowchart-data", "Flowchart:Data" },
+ { "flowchart-predefined-process", "Flowchart:Predefined Process" },
+ { "flowchart-internal-storage", "Flowchart:Internal Storage" },
+ { "flowchart-document", "Flowchart:Document" },
+ { "flowchart-multidocument", "Flowchart:Multidocument" },
+ { "flowchart-terminator", "Flowchart:Terminator" },
+ { "flowchart-preparation", "Flowchart:Preparation" },
+ { "flowchart-manual-input", "Flowchart:Manual Input" },
+ { "flowchart-manual-operation", "Flowchart:Manual Operation" },
+ { "flowchart-connector", "Flowchart:Connector" },
+ { "flowchart-card", "Flowchart:Card" },
+ { "flowchart-punched-tape", "Flowchart:Punched Tape" },
+ { "flowchart-summing-junction", "Flowchart:Summing Junction" },
+ { "flowchart-or", "Flowchart:Or" },
+ { "flowchart-collate", "Flowchart:Collate" },
+ { "flowchart-sort", "Flowchart:Sort" },
+ { "flowchart-extract", "Flowchart:Extract" },
+ { "flowchart-merge", "Flowchart:Merge" },
+ //{ "mso-spt129", mso_sptFlowChartOfflineStorage },
+ { "flowchart-stored-data", "Flowchart:Stored Data" },
+ { "flowchart-sequential-access", "drawingbar.fc.25=Flowchart:Sequential Access" },
+ { "flowchart-magnetic-disk", "Flowchart:Magnetic Disk" },
+ { "flowchart-direct-access-storage", "Flowchart:Direct Access Storage" },
+ { "flowchart-display", "Flowchart:Display" },
+ { "flowchart-delay", "Flowchart:Delay" },
+ /*{ "fontwork-plain-text", mso_sptTextPlainText },
+ { "fontwork-stop", mso_sptTextStop },
+ { "fontwork-triangle-up", mso_sptTextTriangle },
+ { "fontwork-triangle-down", mso_sptTextTriangleInverted },
+ { "fontwork-chevron-up", mso_sptTextChevron },
+ { "fontwork-chevron-down", mso_sptTextChevronInverted },
+ { "mso-spt142", mso_sptTextRingInside },
+ { "mso-spt143", mso_sptTextRingOutside },
+ { "fontwork-arch-up-curve", mso_sptTextArchUpCurve },
+ { "fontwork-arch-down-curve", mso_sptTextArchDownCurve },
+ { "fontwork-circle-curve", mso_sptTextCircleCurve },
+ { "fontwork-open-circle-curve", mso_sptTextButtonCurve },
+ { "fontwork-arch-up-pour", mso_sptTextArchUpPour },
+ { "fontwork-arch-down-pour", mso_sptTextArchDownPour },
+ { "fontwork-circle-pour", mso_sptTextCirclePour },
+ { "fontwork-open-circle-pour", mso_sptTextButtonPour },
+ { "fontwork-curve-up", mso_sptTextCurveUp },
+ { "fontwork-curve-down", mso_sptTextCurveDown },
+ { "fontwork-fade-up-and-right", mso_sptTextCascadeUp },
+ { "fontwork-fade-up-and-left", mso_sptTextCascadeDown },
+ { "fontwork-wave", mso_sptTextWave1 },
+ { "mso-spt157", mso_sptTextWave2 },
+ { "mso-spt158", mso_sptTextWave3 },
+ { "mso-spt159", mso_sptTextWave4 },
+ { "fontwork-inflate", mso_sptTextInflate },
+ { "mso-spt161", mso_sptTextDeflate },
+ { "mso-spt162", mso_sptTextInflateBottom },
+ { "mso-spt163", mso_sptTextDeflateBottom },
+ { "mso-spt164", mso_sptTextInflateTop },
+ { "mso-spt165", mso_sptTextDeflateTop },
+ { "mso-spt166", mso_sptTextDeflateInflate },
+ { "mso-spt167", mso_sptTextDeflateInflateDeflate },
+ { "fontwork-fade-right", mso_sptTextFadeRight },
+ { "fontwork-fade-left", mso_sptTextFadeLeft },
+ { "fontwork-fade-up", mso_sptTextFadeUp },
+ { "fontwork-fade-down", mso_sptTextFadeDown },
+ { "fontwork-slant-up", mso_sptTextSlantUp },
+ { "fontwork-slant-down", mso_sptTextSlantDown },
+ { "mso-spt174", mso_sptTextCanUp },
+ { "mso-spt175", mso_sptTextCanDown },*/
+ { "flowchart-alternate-process", "Flowchart:Alternate Process " },
+ { "flowchart-off-page-connector", "Flowchart:Off-page Connector" },
+ /*{ "mso-spt178", mso_sptCallout90 },
+ { "mso-spt179", mso_sptAccentCallout90 },
+ { "mso-spt180", mso_sptBorderCallout90 },*/
+ { "line-callout-3", "Line Callout 3" },
+ //{ "mso-spt182", mso_sptLeftRightUpArrow },
+ { "sun", "Sun" },
+ { "moon", "Moon" },
+ { "bracket-pair", "Double Bracket" },
+ { "brace-pair", "Double Brace" },
+ { "star4", "4-Point Star" },
+ /*{ "mso-spt188", mso_sptDoubleWave },
+ { "mso-spt189", mso_sptActionButtonBlank },
+ { "mso-spt190", mso_sptActionButtonHome },
+ { "mso-spt191", mso_sptActionButtonHelp },
+ { "mso-spt192", mso_sptActionButtonInformation },
+ { "mso-spt193", mso_sptActionButtonForwardNext },
+ { "mso-spt194", mso_sptActionButtonBackPrevious },
+ { "mso-spt195", mso_sptActionButtonEnd },
+ { "mso-spt196", mso_sptActionButtonBeginning },
+ { "mso-spt197", mso_sptActionButtonReturn },
+ { "mso-spt198", mso_sptActionButtonDocument },
+ { "mso-spt199", mso_sptActionButtonSound },
+ { "mso-spt200", mso_sptActionButtonMovie },
+ { "mso-spt201", mso_sptHostControl },
+ { "mso-spt202", mso_sptTextBox },*/
+ { "frame", "Frame" },
+ { "col-60da8460", "Octagon Bevel" },
+ { "col-502ad400", "Diamond Bevel" }
+};
+
+typedef std::unordered_map<OUString, OUString> TypeACCNameHashMap;
+
+static const TypeACCNameHashMap& GetACCHashMap()
+{
+ static TypeACCNameHashMap aMap = []()
+ {
+ TypeACCNameHashMap map;
+ for (auto const & i : pACCNameTypeTableArray)
+ map[OUString::createFromAscii(i.pS)] = OUString::createFromAscii(i.pE);
+ return map;
+ }();
+ return aMap;
+}
+
+const OUString & EnhancedCustomShapeTypeNames::GetAccName( const OUString& rShapeType )
+{
+ static const OUString EMPTY;
+ const TypeACCNameHashMap& rACCMap = GetACCHashMap();
+ auto aHashIter = rACCMap.find( rShapeType );
+ if ( aHashIter != rACCMap.end() )
+ return aHashIter->second;
+ return EMPTY;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/diagram/IDiagramHelper.cxx b/svx/source/diagram/IDiagramHelper.cxx
new file mode 100644
index 000000000..1803a3d2b
--- /dev/null
+++ b/svx/source/diagram/IDiagramHelper.cxx
@@ -0,0 +1,430 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/diagram/IDiagramHelper.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svdmrkv.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/primitivetools2d.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <comphelper/dispatchcommand.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+namespace {
+
+// helper to create the geometry for a rounded polygon, maybe
+// containing a Lap positioned inside top-left for some text
+basegfx::B2DPolygon createRoundedPolygon(
+ const basegfx::B2DRange& rRange,
+ double fDistance,
+ bool bCreateLap,
+ double fTextWidth)
+{
+ basegfx::B2DPolygon aRetval;
+
+ // TopLeft rounded edge
+ aRetval.append(
+ basegfx::utils::createPolygonFromEllipseSegment(
+ basegfx::B2DPoint(rRange.getMinX(), rRange.getMinY()),
+ fDistance,
+ fDistance,
+ M_PI * 1.0,
+ M_PI * 1.5));
+
+ // create Lap topLeft inside
+ if(bCreateLap)
+ {
+ const double fLapLeft(rRange.getMinX() + fDistance);
+ double fLapRight(rRange.getMinX() + (rRange.getWidth() * 0.5) - fDistance);
+ const double fLapTop(rRange.getMinY() - fDistance);
+ const double fLapBottom(fLapTop + (fDistance * 2.0));
+ const double fExtendedTextWidth(fTextWidth + (fDistance * 3.0));
+
+ if(0.0 != fExtendedTextWidth && fLapLeft + fExtendedTextWidth < fLapRight)
+ {
+ fLapRight = fLapLeft + fExtendedTextWidth;
+ }
+
+ aRetval.append(basegfx::B2DPoint(fLapLeft, fLapTop));
+ aRetval.append(basegfx::B2DPoint(fLapLeft + (fDistance * 0.5), fLapBottom));
+ aRetval.append(basegfx::B2DPoint(fLapRight - (fDistance * 0.5), fLapBottom));
+ aRetval.append(basegfx::B2DPoint(fLapRight, fLapTop));
+ }
+
+ // TopRight rounded edge
+ aRetval.append(
+ basegfx::utils::createPolygonFromEllipseSegment(
+ basegfx::B2DPoint(rRange.getMaxX(), rRange.getMinY()),
+ fDistance,
+ fDistance,
+ M_PI * 1.5,
+ M_PI * 0.0));
+
+ // BottomRight rounded edge
+ aRetval.append(
+ basegfx::utils::createPolygonFromEllipseSegment(
+ basegfx::B2DPoint(rRange.getMaxX(), rRange.getMaxY()),
+ fDistance,
+ fDistance,
+ M_PI * 0.0,
+ M_PI * 0.5));
+
+ // BottomLeft rounded edge
+ aRetval.append(
+ basegfx::utils::createPolygonFromEllipseSegment(
+ basegfx::B2DPoint(rRange.getMinX(), rRange.getMaxY()),
+ fDistance,
+ fDistance,
+ M_PI * 0.5,
+ M_PI * 1.0));
+
+ aRetval.setClosed(true);
+
+ return aRetval;
+}
+
+// helper primitive to create/show the overlay geometry for a DynamicDiagram
+class OverlayDiagramPrimitive final : public drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D
+{
+private:
+ basegfx::B2DHomMatrix maTransformation; // object dimensions
+ double mfDiscreteDistance; // distance from object in pixels
+ double mfDiscreteGap; // gap/width of visualization in pixels
+ Color maColor; // base color (made lighter/darker as needed, should be system selection color)
+
+ virtual void create2DDecomposition(
+ drawinglayer::primitive2d::Primitive2DContainer& rContainer,
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation) const override;
+
+public:
+ OverlayDiagramPrimitive(
+ const basegfx::B2DHomMatrix& rTransformation,
+ double fDiscreteDistance,
+ double fDiscreteGap,
+ Color const & rColor);
+
+ virtual sal_uInt32 getPrimitive2DID() const override;
+};
+
+void OverlayDiagramPrimitive::create2DDecomposition(
+ drawinglayer::primitive2d::Primitive2DContainer& rContainer,
+ const drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/) const
+{
+ // get the dimensions. Do *not* take rotation/shear into account,
+ // this is intended to be a pure expanded/frame visualization as
+ // needed in UI for simplified visualization
+ basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0);
+ aRange.transform(maTransformation);
+
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ const double fInnerDistance(mfDiscreteDistance * getDiscreteUnit());
+ const double fOuterDistance((mfDiscreteDistance + mfDiscreteGap) * getDiscreteUnit());
+ bool bCreateLap(true);
+ basegfx::B2DPolyPolygon aTextAsPolyPolygon;
+ double fTextWidth(0.0);
+
+ // initially try to create lap
+ if(bCreateLap)
+ {
+ // take a resource text (for now existing one that fits)
+ const OUString aName(SvxResId(RID_STR_DATANAV_EDIT_ELEMENT));
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
+ basegfx::B2DPolyPolygonVector aTarget;
+ std::vector<double> aDXArray;
+
+ // to simplify things for now, do not create a TextSimplePortionPrimitive2D
+ // and needed FontAttribute, just get the TextOutlines as geometry
+ aTextLayouter.getTextOutlines(
+ aTarget,
+ aName,
+ 0,
+ aName.getLength(),
+ aDXArray);
+
+ // put into one PolyPolygon (also simplification - overlapping chars
+ // may create XOR gaps, so these exist for a reason, but low probability)
+ for (auto const& elem : aTarget)
+ {
+ aTextAsPolyPolygon.append(elem);
+ }
+
+ // get text dimensions & transform to destination
+ const basegfx::B2DRange aTextRange(aTextAsPolyPolygon.getB2DRange());
+ basegfx::B2DHomMatrix aTextTransform;
+
+ aTextTransform.translate(aTextRange.getMinX(), aTextRange.getMinY());
+ const double fTargetTextHeight((mfDiscreteDistance + mfDiscreteGap - 2.0) * getDiscreteUnit());
+ const double fTextScale(fTargetTextHeight / aTextRange.getHeight());
+ aTextTransform.scale(fTextScale, fTextScale);
+ aTextTransform.translate(
+ aRange.getMinX() + (fInnerDistance * 2.0),
+ aRange.getMinY() + fTargetTextHeight + (fOuterDistance - fInnerDistance) - (2.0 * getDiscreteUnit()));
+ aTextAsPolyPolygon.transform(aTextTransform);
+
+ // check text size/position
+ fTextWidth = aTextRange.getWidth() * fTextScale;
+ const double fLapLeft(aRange.getMinX() + fInnerDistance);
+ const double fLapRight(aRange.getMinX() + (aRange.getWidth() * 0.5) - fInnerDistance);
+
+ // if text is too big, do not create a Lap at all
+ // to avoid trouble. It is expected that the user keeps
+ // the object he works with big enough to do useful actions
+ if(fTextWidth + (4.0 * getDiscreteUnit()) > fLapRight - fLapLeft)
+ bCreateLap = false;
+ }
+
+ // create outer polygon
+ aPolyPolygon.append(
+ createRoundedPolygon(
+ aRange,
+ fOuterDistance,
+ false,
+ 0.0));
+
+ // create inner polygon, maybe with Lap
+ aPolyPolygon.append(
+ createRoundedPolygon(
+ aRange,
+ fInnerDistance,
+ bCreateLap,
+ fTextWidth));
+
+ Color aFillColor(maColor);
+ Color aLineColor(maColor);
+
+ aFillColor.IncreaseLuminance(10);
+ aLineColor.DecreaseLuminance(30);
+
+ const drawinglayer::attribute::LineAttribute aLineAttribute(
+ aLineColor.getBColor(),
+ 1.0 * getDiscreteUnit());
+
+ // filled polygon as BG (may get transparence for better look ?)
+ rContainer.push_back(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ aPolyPolygon,
+ aFillColor.getBColor()));
+
+ // outline polygon for visibility (may be accentuated shaded
+ // top/left, would require alternative creation)
+ rContainer.push_back(
+ new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
+ aPolyPolygon,
+ aLineAttribute));
+
+ // top-left line pattern (as grep-here-sign to signal
+ // that this construct may be also dragged by the user)
+ const double fLapLeft(aRange.getMinX() + fInnerDistance);
+ const double fLapRight(aRange.getMinX() + (aRange.getWidth() * 0.5) - fInnerDistance);
+ const double fLapUp(aRange.getMinY() - ((mfDiscreteDistance + mfDiscreteDistance * 0.666) * getDiscreteUnit()));
+ const double fLapDown(aRange.getMinY() - ((mfDiscreteDistance + mfDiscreteDistance * 0.333) * getDiscreteUnit()));
+ basegfx::B2DPolygon aPolygonLapUp;
+ aPolygonLapUp.append(basegfx::B2DPoint(fLapLeft, fLapUp));
+ aPolygonLapUp.append(basegfx::B2DPoint(fLapRight, fLapUp));
+ basegfx::B2DPolygon aPolygonLapDown;
+ aPolygonLapDown.append(basegfx::B2DPoint(fLapLeft, fLapDown));
+ aPolygonLapDown.append(basegfx::B2DPoint(fLapRight, fLapDown));
+ drawinglayer::attribute::StrokeAttribute aStrokeAttribute({ 2.0 * getDiscreteUnit(), 2.0 * getDiscreteUnit() });
+
+ rContainer.push_back(
+ new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
+ aPolygonLapUp,
+ aLineAttribute,
+ aStrokeAttribute));
+
+ rContainer.push_back(
+ new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
+ aPolygonLapDown,
+ aLineAttribute,
+ aStrokeAttribute));
+
+ // add text last. May use darker text color, go for same color
+ // as accentuation line for now
+ if(bCreateLap && 0 != aTextAsPolyPolygon.count())
+ {
+ rContainer.push_back(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ aTextAsPolyPolygon,
+ aLineColor.getBColor()));
+ }
+}
+
+OverlayDiagramPrimitive::OverlayDiagramPrimitive(
+ const basegfx::B2DHomMatrix& rTransformation,
+ double fDiscreteDistance,
+ double fDiscreteGap,
+ Color const & rColor)
+: drawinglayer::primitive2d::DiscreteMetricDependentPrimitive2D()
+, maTransformation(rTransformation)
+, mfDiscreteDistance(fDiscreteDistance)
+, mfDiscreteGap(fDiscreteGap)
+, maColor(rColor)
+{
+}
+
+sal_uInt32 OverlayDiagramPrimitive::getPrimitive2DID() const
+{
+ return PRIMITIVE2D_ID_OVERLAYDIAGRAMPRIMITIVE2D;
+}
+
+// helper object for DiagramOverlay
+class OverlayDiagramFrame final : public sdr::overlay::OverlayObject
+{
+private:
+ basegfx::B2DHomMatrix maTransformation; // object dimensions
+ Color maColor; // base color
+
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+public:
+ explicit OverlayDiagramFrame(
+ const basegfx::B2DHomMatrix& rTransformation,
+ Color const & rColor);
+};
+
+OverlayDiagramFrame::OverlayDiagramFrame(
+ const basegfx::B2DHomMatrix& rTransformation,
+ const Color& rColor)
+: sdr::overlay::OverlayObject(rColor)
+, maTransformation(rTransformation)
+, maColor(rColor)
+{
+}
+
+drawinglayer::primitive2d::Primitive2DContainer OverlayDiagramFrame::createOverlayObjectPrimitive2DSequence()
+{
+ drawinglayer::primitive2d::Primitive2DContainer aReturnContainer;
+
+ if ( !officecfg::Office::Common::Misc::ExperimentalMode::get() )
+ return aReturnContainer;
+
+ if (getOverlayManager())
+ {
+ aReturnContainer = drawinglayer::primitive2d::Primitive2DContainer {
+ new OverlayDiagramPrimitive(
+ maTransformation,
+ 8.0, // distance from geometry in pixels
+ 8.0, // gap/width of visualization in pixels
+ maColor) };
+ }
+
+ return aReturnContainer;
+}
+
+} // end of anonymous namespace
+
+namespace svx { namespace diagram {
+
+void DiagramFrameHdl::clicked(const Point& /*rPnt*/)
+{
+ // this may check for a direct hit at the text later
+ // and only then take action. That would require
+ // to evaluate & keep that (maybe during creation).
+ // For now, just trigger to open the Dialog
+ comphelper::dispatchCommand(".uno:EditDiagram", {});
+}
+
+void DiagramFrameHdl::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!pView || pView->areMarkHandlesHidden())
+ return;
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ OutputDevice& rOutDev(rPageWindow.GetPaintWindow().GetOutputDevice());
+ const StyleSettings& rStyles(rOutDev.GetSettings().GetStyleSettings());
+ Color aFillColor(rStyles.GetHighlightColor());
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
+ new OverlayDiagramFrame(
+ maTransformation,
+ aFillColor));
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+DiagramFrameHdl::DiagramFrameHdl(const basegfx::B2DHomMatrix& rTransformation)
+: SdrHdl(Point(), SdrHdlKind::Move)
+, maTransformation(rTransformation)
+{
+}
+
+IDiagramHelper::IDiagramHelper()
+: mbUseDiagramThemeData(false)
+, mbUseDiagramModelData(true)
+, mbForceThemePtrRecreation(false)
+{
+}
+
+IDiagramHelper::~IDiagramHelper() {}
+
+void IDiagramHelper::anchorToSdrObjGroup(SdrObjGroup& rTarget)
+{
+ rTarget.mp_DiagramHelper.reset(this);
+}
+
+void IDiagramHelper::AddAdditionalVisualization(const SdrObjGroup& rTarget, SdrHdlList& rHdlList)
+{
+ // create an extra frame visualization here
+ basegfx::B2DHomMatrix aTransformation;
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ rTarget.TRGetBaseGeometry(aTransformation, aPolyPolygon);
+
+ std::unique_ptr<SdrHdl> pHdl(new DiagramFrameHdl(aTransformation));
+ rHdlList.AddHdl(std::move(pHdl));
+}
+
+}} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/diagram/datamodel.cxx b/svx/source/diagram/datamodel.cxx
new file mode 100644
index 000000000..e45fe7fb4
--- /dev/null
+++ b/svx/source/diagram/datamodel.cxx
@@ -0,0 +1,501 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unordered_set>
+#include <algorithm>
+#include <fstream>
+
+#include <svx/diagram/datamodel.hxx>
+#include <comphelper/xmltools.hxx>
+#include <sal/log.hxx>
+
+namespace svx::diagram {
+
+Connection::Connection()
+: mnXMLType( XML_none )
+, mnSourceOrder( 0 )
+, mnDestOrder( 0 )
+{
+}
+
+Point::Point()
+: msTextBody(std::make_shared< TextBody >())
+, msPointStylePtr(std::make_shared< PointStyle >())
+, mnXMLType(XML_none)
+, mnMaxChildren(-1)
+, mnPreferredChildren(-1)
+, mnDirection(XML_norm)
+, mnResizeHandles(XML_rel)
+, mnCustomAngle(-1)
+, mnPercentageNeighbourWidth(-1)
+, mnPercentageNeighbourHeight(-1)
+, mnPercentageOwnWidth(-1)
+, mnPercentageOwnHeight(-1)
+, mnIncludeAngleScale(-1)
+, mnRadiusScale(-1)
+, mnWidthScale(-1)
+, mnHeightScale(-1)
+, mnWidthOverride(-1)
+, mnHeightOverride(-1)
+, mnLayoutStyleCount(-1)
+, mnLayoutStyleIndex(-1)
+, mbOrgChartEnabled(false)
+, mbBulletEnabled(false)
+, mbCoherent3DOffset(false)
+, mbCustomHorizontalFlip(false)
+, mbCustomVerticalFlip(false)
+, mbCustomText(false)
+, mbIsPlaceholder(false)
+{
+}
+
+DiagramData::DiagramData()
+{
+}
+
+DiagramData::~DiagramData()
+{
+}
+
+const Point* DiagramData::getRootPoint() const
+{
+ for (const auto & aCurrPoint : maPoints)
+ if (aCurrPoint.mnXMLType == TypeConstant::XML_doc)
+ return &aCurrPoint;
+
+ SAL_WARN("svx.diagram", "No root point");
+ return nullptr;
+}
+
+OUString DiagramData::getString() const
+{
+ OUStringBuffer aBuf;
+ const Point* pPoint = getRootPoint();
+ getChildrenString(aBuf, pPoint, 0);
+ return aBuf.makeStringAndClear();
+}
+
+bool DiagramData::removeNode(const OUString& rNodeId)
+{
+ // check if it doesn't have children
+ for (const auto& aCxn : maConnections)
+ if (aCxn.mnXMLType == TypeConstant::XML_parOf && aCxn.msSourceId == rNodeId)
+ {
+ SAL_WARN("svx.diagram", "Node has children - can't be removed");
+ return false;
+ }
+
+ Connection aParCxn;
+ for (const auto& aCxn : maConnections)
+ if (aCxn.mnXMLType == TypeConstant::XML_parOf && aCxn.msDestId == rNodeId)
+ aParCxn = aCxn;
+
+ std::unordered_set<OUString> aIdsToRemove;
+ aIdsToRemove.insert(rNodeId);
+ if (!aParCxn.msParTransId.isEmpty())
+ aIdsToRemove.insert(aParCxn.msParTransId);
+ if (!aParCxn.msSibTransId.isEmpty())
+ aIdsToRemove.insert(aParCxn.msSibTransId);
+
+ for (const Point& rPoint : maPoints)
+ if (aIdsToRemove.count(rPoint.msPresentationAssociationId))
+ aIdsToRemove.insert(rPoint.msModelId);
+
+ // insert also transition nodes
+ for (const auto& aCxn : maConnections)
+ if (aIdsToRemove.count(aCxn.msSourceId) || aIdsToRemove.count(aCxn.msDestId))
+ if (!aCxn.msPresId.isEmpty())
+ aIdsToRemove.insert(aCxn.msPresId);
+
+ // remove connections
+ maConnections.erase(std::remove_if(maConnections.begin(), maConnections.end(),
+ [aIdsToRemove](const Connection& rCxn) {
+ return aIdsToRemove.count(rCxn.msSourceId) || aIdsToRemove.count(rCxn.msDestId);
+ }),
+ maConnections.end());
+
+ // remove data and presentation nodes
+ maPoints.erase(std::remove_if(maPoints.begin(), maPoints.end(),
+ [aIdsToRemove](const Point& rPoint) {
+ return aIdsToRemove.count(rPoint.msModelId);
+ }),
+ maPoints.end());
+
+ // TODO: fix source/dest order
+ return true;
+}
+
+DiagramDataState::DiagramDataState(const Connections& rConnections, const Points& rPoints)
+: maConnections(rConnections)
+, maPoints(rPoints)
+{
+}
+
+DiagramDataStatePtr DiagramData::extractDiagramDataState() const
+{
+ // Just copy all Connections && Points. The shared_ptr data in
+ // Point-entries is no problem, it just continues exiting shared
+ return std::make_shared< DiagramDataState >(maConnections, maPoints);
+}
+
+void DiagramData::applyDiagramDataState(const DiagramDataStatePtr& rState)
+{
+ if(rState)
+ {
+ maConnections = rState->getConnections();
+ maPoints = rState->getPoints();
+
+ // Reset temporary buffered ModelData association lists & rebuild them
+ // and the Diagram DataModel. Do that here *immediately* to prevent
+ // re-usage of potentially invalid Connection/Point objects
+ buildDiagramDataModel(true);
+ }
+}
+
+void DiagramData::getChildrenString(
+ OUStringBuffer& rBuf,
+ const svx::diagram::Point* pPoint,
+ sal_Int32 nLevel) const
+{
+ if (!pPoint)
+ return;
+
+ if (nLevel > 0)
+ {
+ for (sal_Int32 i = 0; i < nLevel-1; i++)
+ rBuf.append('\t');
+ rBuf.append('+');
+ rBuf.append(' ');
+ rBuf.append(pPoint->msTextBody->msText);
+ rBuf.append('\n');
+ }
+
+ std::vector< const svx::diagram::Point* > aChildren;
+ for (const auto& rCxn : maConnections)
+ if (rCxn.mnXMLType == TypeConstant::XML_parOf && rCxn.msSourceId == pPoint->msModelId)
+ {
+ if (rCxn.mnSourceOrder >= static_cast<sal_Int32>(aChildren.size()))
+ aChildren.resize(rCxn.mnSourceOrder + 1);
+ const auto pChild = maPointNameMap.find(rCxn.msDestId);
+ if (pChild != maPointNameMap.end())
+ aChildren[rCxn.mnSourceOrder] = pChild->second;
+ }
+
+ for (auto pChild : aChildren)
+ getChildrenString(rBuf, pChild, nLevel + 1);
+}
+
+std::vector<std::pair<OUString, OUString>> DiagramData::getChildren(const OUString& rParentId) const
+{
+ const OUString sModelId = rParentId.isEmpty() ? getRootPoint()->msModelId : rParentId;
+ std::vector<std::pair<OUString, OUString>> aChildren;
+ for (const auto& rCxn : maConnections)
+ if (rCxn.mnXMLType == TypeConstant::XML_parOf && rCxn.msSourceId == sModelId)
+ {
+ if (rCxn.mnSourceOrder >= static_cast<sal_Int32>(aChildren.size()))
+ aChildren.resize(rCxn.mnSourceOrder + 1);
+ const auto pChild = maPointNameMap.find(rCxn.msDestId);
+ if (pChild != maPointNameMap.end())
+ {
+ aChildren[rCxn.mnSourceOrder] = std::make_pair(
+ pChild->second->msModelId,
+ pChild->second->msTextBody->msText);
+ }
+ }
+
+ // HACK: empty items shouldn't appear there
+ aChildren.erase(std::remove_if(aChildren.begin(), aChildren.end(),
+ [](const std::pair<OUString, OUString>& aItem) { return aItem.first.isEmpty(); }),
+ aChildren.end());
+
+ return aChildren;
+}
+
+OUString DiagramData::addNode(const OUString& rText)
+{
+ const svx::diagram::Point& rDataRoot = *getRootPoint();
+ OUString sPresRoot;
+ for (const auto& aCxn : maConnections)
+ if (aCxn.mnXMLType == TypeConstant::XML_presOf && aCxn.msSourceId == rDataRoot.msModelId)
+ sPresRoot = aCxn.msDestId;
+
+ if (sPresRoot.isEmpty())
+ return OUString();
+
+ OUString sNewNodeId = OStringToOUString(comphelper::xml::generateGUIDString(), RTL_TEXTENCODING_UTF8);
+
+ svx::diagram::Point aDataPoint;
+ aDataPoint.mnXMLType = TypeConstant::XML_node;
+ aDataPoint.msModelId = sNewNodeId;
+ aDataPoint.msTextBody->msText = rText;
+
+ OUString sDataSibling;
+ for (const auto& aCxn : maConnections)
+ if (aCxn.mnXMLType == TypeConstant::XML_parOf && aCxn.msSourceId == rDataRoot.msModelId)
+ sDataSibling = aCxn.msDestId;
+
+ OUString sPresSibling;
+ for (const auto& aCxn : maConnections)
+ if (aCxn.mnXMLType == TypeConstant::XML_presOf && aCxn.msSourceId == sDataSibling)
+ sPresSibling = aCxn.msDestId;
+
+ svx::diagram::Point aPresPoint;
+ aPresPoint.mnXMLType = TypeConstant::XML_pres;
+ aPresPoint.msModelId = OStringToOUString(comphelper::xml::generateGUIDString(), RTL_TEXTENCODING_UTF8);
+
+ aPresPoint.msPresentationAssociationId = aDataPoint.msModelId;
+ if (!sPresSibling.isEmpty())
+ {
+ // no idea where to get these values from, so copy from previous sibling
+ const svx::diagram::Point* pSiblingPoint = maPointNameMap[sPresSibling];
+ aPresPoint.msPresentationLayoutName = pSiblingPoint->msPresentationLayoutName;
+ aPresPoint.msPresentationLayoutStyleLabel = pSiblingPoint->msPresentationLayoutStyleLabel;
+ aPresPoint.mnLayoutStyleIndex = pSiblingPoint->mnLayoutStyleIndex;
+ aPresPoint.mnLayoutStyleCount = pSiblingPoint->mnLayoutStyleCount;
+ }
+
+ addConnection(svx::diagram::TypeConstant::XML_parOf, rDataRoot.msModelId, aDataPoint.msModelId);
+ addConnection(svx::diagram::TypeConstant::XML_presParOf, sPresRoot, aPresPoint.msModelId);
+ addConnection(svx::diagram::TypeConstant::XML_presOf, aDataPoint.msModelId, aPresPoint.msModelId);
+
+ // adding at the end, so that references are not invalidated in between
+ maPoints.push_back(aDataPoint);
+ maPoints.push_back(aPresPoint);
+
+ return sNewNodeId;
+}
+
+void DiagramData::addConnection(svx::diagram::TypeConstant nType, const OUString& sSourceId, const OUString& sDestId)
+{
+ sal_Int32 nMaxOrd = -1;
+ for (const auto& aCxn : maConnections)
+ if (aCxn.mnXMLType == nType && aCxn.msSourceId == sSourceId)
+ nMaxOrd = std::max(nMaxOrd, aCxn.mnSourceOrder);
+
+ svx::diagram::Connection& rCxn = maConnections.emplace_back();
+ rCxn.mnXMLType = nType;
+ rCxn.msSourceId = sSourceId;
+ rCxn.msDestId = sDestId;
+ rCxn.mnSourceOrder = nMaxOrd + 1;
+}
+
+// #define DEBUG_OOX_DIAGRAM
+#ifdef DEBUG_OOX_DIAGRAM
+OString normalizeDotName( const OUString& rStr )
+{
+ OUStringBuffer aBuf;
+ aBuf.append('N');
+
+ const sal_Int32 nLen(rStr.getLength());
+ sal_Int32 nCurrIndex(0);
+ while( nCurrIndex < nLen )
+ {
+ const sal_Int32 aChar=rStr.iterateCodePoints(&nCurrIndex);
+ if( aChar != '-' && aChar != '{' && aChar != '}' )
+ aBuf.append((sal_Unicode)aChar);
+ }
+
+ return OUStringToOString(aBuf.makeStringAndClear(),
+ RTL_TEXTENCODING_UTF8);
+}
+#endif
+
+static sal_Int32 calcDepth( std::u16string_view rNodeName,
+ const svx::diagram::Connections& rCnx )
+{
+ // find length of longest path in 'isChild' graph, ending with rNodeName
+ for (auto const& elem : rCnx)
+ {
+ if( !elem.msParTransId.isEmpty() &&
+ !elem.msSibTransId.isEmpty() &&
+ !elem.msSourceId.isEmpty() &&
+ !elem.msDestId.isEmpty() &&
+ elem.mnXMLType == TypeConstant::XML_parOf &&
+ rNodeName == elem.msDestId )
+ {
+ return calcDepth(elem.msSourceId, rCnx) + 1;
+ }
+ }
+
+ return 0;
+}
+
+void DiagramData::buildDiagramDataModel(bool /*bClearOoxShapes*/)
+{
+ // build name-object maps
+ maPointNameMap.clear();
+ maPointsPresNameMap.clear();
+ maConnectionNameMap.clear();
+ maPresOfNameMap.clear();
+ msBackgroundShapeModelID.clear();
+
+#ifdef DEBUG_OOX_DIAGRAM
+ std::ofstream output("tree.dot");
+
+ output << "digraph datatree {" << std::endl;
+#endif
+ svx::diagram::Points& rPoints = getPoints();
+ for (auto & point : rPoints)
+ {
+#ifdef DEBUG_OOX_DIAGRAM
+ output << "\t"
+ << normalizeDotName(point.msModelId).getStr()
+ << "[";
+
+ if( !point.msPresentationLayoutName.isEmpty() )
+ output << "label=\""
+ << OUStringToOString(
+ point.msPresentationLayoutName,
+ RTL_TEXTENCODING_UTF8).getStr() << "\", ";
+ else
+ output << "label=\""
+ << OUStringToOString(
+ point.msModelId,
+ RTL_TEXTENCODING_UTF8).getStr() << "\", ";
+
+ switch( point.mnXMLType )
+ {
+ case TypeConstant::XML_doc: output << "style=filled, color=red"; break;
+ case TypeConstant::XML_asst: output << "style=filled, color=green"; break;
+ default:
+ case TypeConstant::XML_node: output << "style=filled, color=blue"; break;
+ case TypeConstant::XML_pres: output << "style=filled, color=yellow"; break;
+ case TypeConstant::XML_parTrans: output << "color=grey"; break;
+ case TypeConstant::XML_sibTrans: output << " "; break;
+ }
+
+ output << "];" << std::endl;
+#endif
+
+ // does currpoint have any text set?
+ if(!point.msTextBody->msText.isEmpty())
+ {
+#ifdef DEBUG_OOX_DIAGRAM
+ static sal_Int32 nCount=0;
+ output << "\t"
+ << "textNode" << nCount
+ << " ["
+ << "label=\""
+ << OUStringToOString(
+ point.msTextBody->msText,
+ RTL_TEXTENCODING_UTF8).getStr()
+ << "\"" << "];" << std::endl;
+ output << "\t"
+ << normalizeDotName(point.msModelId).getStr()
+ << " -> "
+ << "textNode" << nCount++
+ << ";" << std::endl;
+#endif
+ }
+
+ const bool bInserted1 = getPointNameMap().insert(
+ std::make_pair(point.msModelId,&point)).second;
+
+ SAL_WARN_IF(!bInserted1, "oox.drawingml", "DiagramData::build(): non-unique point model id");
+
+ if( !point.msPresentationLayoutName.isEmpty() )
+ {
+ DiagramData::PointsNameMap::value_type::second_type& rVec=
+ getPointsPresNameMap()[point.msPresentationLayoutName];
+ rVec.push_back(&point);
+ }
+ }
+
+ const svx::diagram::Connections& rConnections = getConnections();
+ for (auto const& connection : rConnections)
+ {
+#ifdef DEBUG_OOX_DIAGRAM
+ if( !connection.msParTransId.isEmpty() ||
+ !connection.msSibTransId.isEmpty() )
+ {
+ if( !connection.msSourceId.isEmpty() ||
+ !connection.msDestId.isEmpty() )
+ {
+ output << "\t"
+ << normalizeDotName(connection.msSourceId).getStr()
+ << " -> "
+ << normalizeDotName(connection.msParTransId).getStr()
+ << " -> "
+ << normalizeDotName(connection.msSibTransId).getStr()
+ << " -> "
+ << normalizeDotName(connection.msDestId).getStr()
+ << " [style=dotted,"
+ << ((connection.mnXMLType == TypeConstant::XML_presOf) ? " color=red, " : ((connection.mnXMLType == TypeConstant::XML_presParOf) ? " color=green, " : " "))
+ << "label=\""
+ << OUStringToOString(connection.msModelId,
+ RTL_TEXTENCODING_UTF8 ).getStr()
+ << "\"];" << std::endl;
+ }
+ else
+ {
+ output << "\t"
+ << normalizeDotName(connection.msParTransId).getStr()
+ << " -> "
+ << normalizeDotName(connection.msSibTransId).getStr()
+ << " ["
+ << ((connection.mnXMLType == TypeConstant::XML_presOf) ? " color=red, " : ((connection.mnXMLType == TypeConstant::XML_presParOf) ? " color=green, " : " "))
+ << "label=\""
+ << OUStringToOString(connection.msModelId,
+ RTL_TEXTENCODING_UTF8 ).getStr()
+ << "\"];" << std::endl;
+ }
+ }
+ else if( !connection.msSourceId.isEmpty() ||
+ !connection.msDestId.isEmpty() )
+ output << "\t"
+ << normalizeDotName(connection.msSourceId).getStr()
+ << " -> "
+ << normalizeDotName(connection.msDestId).getStr()
+ << " [label=\""
+ << OUStringToOString(connection.msModelId,
+ RTL_TEXTENCODING_UTF8 ).getStr()
+ << ((connection.mnXMLType == TypeConstant::XML_presOf) ? "\", color=red]" : ((connection.mnXMLType == TypeConstant::XML_presParOf) ? "\", color=green]" : "\"]"))
+ << ";" << std::endl;
+#endif
+
+ const bool bInserted1 = maConnectionNameMap.insert(
+ std::make_pair(connection.msModelId,&connection)).second;
+
+ SAL_WARN_IF(!bInserted1, "oox.drawingml", "DiagramData::build(): non-unique connection model id");
+
+ if( connection.mnXMLType == TypeConstant::XML_presOf )
+ {
+ DiagramData::StringMap::value_type::second_type& rVec = getPresOfNameMap()[connection.msDestId];
+ rVec[connection.mnDestOrder] = { connection.msSourceId, sal_Int32(0) };
+ }
+ }
+
+ // assign outline levels
+ DiagramData::StringMap& rStringMap = getPresOfNameMap();
+ for (auto & elemPresOf : rStringMap)
+ {
+ for (auto & elem : elemPresOf.second)
+ {
+ const sal_Int32 nDepth = calcDepth(elem.second.msSourceId, getConnections());
+ elem.second.mnDepth = nDepth != 0 ? nDepth : -1;
+ }
+ }
+#ifdef DEBUG_OOX_DIAGRAM
+ output << "}" << std::endl;
+#endif
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/AccessibilityCheckDialog.cxx b/svx/source/dialog/AccessibilityCheckDialog.cxx
new file mode 100644
index 000000000..8fb0c43ce
--- /dev/null
+++ b/svx/source/dialog/AccessibilityCheckDialog.cxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <svx/AccessibilityCheckDialog.hxx>
+
+#include <sfx2/AccessibilityIssue.hxx>
+#include <vcl/svapp.hxx>
+
+namespace svx
+{
+AccessibilityCheckEntry::AccessibilityCheckEntry(
+ weld::Container* pParent, std::shared_ptr<sfx::AccessibilityIssue> const& rAccessibilityIssue)
+ : m_xBuilder(Application::CreateBuilder(pParent, "svx/ui/accessibilitycheckentry.ui"))
+ , m_xContainer(m_xBuilder->weld_container("accessibilityCheckEntryBox"))
+ , m_xLabel(m_xBuilder->weld_label("accessibilityCheckEntryLabel"))
+ , m_xGotoButton(m_xBuilder->weld_button("accessibilityCheckEntryGotoButton"))
+ , m_pAccessibilityIssue(rAccessibilityIssue)
+{
+ m_xLabel->set_label(m_pAccessibilityIssue->m_aIssueText);
+ m_xGotoButton->set_visible(m_pAccessibilityIssue->canGotoIssue());
+ m_xGotoButton->connect_clicked(LINK(this, AccessibilityCheckEntry, GotoButtonClicked));
+ m_xContainer->show();
+}
+
+IMPL_LINK_NOARG(AccessibilityCheckEntry, GotoButtonClicked, weld::Button&, void)
+{
+ m_pAccessibilityIssue->gotoIssue();
+}
+
+AccessibilityCheckDialog::AccessibilityCheckDialog(
+ weld::Window* pParent, sfx::AccessibilityIssueCollection const& rIssueCollection)
+ : GenericDialogController(pParent, "svx/ui/accessibilitycheckdialog.ui",
+ "AccessibilityCheckDialog")
+ , m_aIssueCollection(rIssueCollection)
+ , m_xAccessibilityCheckBox(m_xBuilder->weld_box("accessibilityCheckBox"))
+{
+ sal_Int32 i = 0;
+
+ for (std::shared_ptr<sfx::AccessibilityIssue> const& pIssue : m_aIssueCollection.getIssues())
+ {
+ auto xEntry
+ = std::make_unique<AccessibilityCheckEntry>(m_xAccessibilityCheckBox.get(), pIssue);
+ m_xAccessibilityCheckBox->reorder_child(xEntry->get_widget(), i++);
+ m_aAccessibilityCheckEntries.push_back(std::move(xEntry));
+ }
+}
+
+AccessibilityCheckDialog::~AccessibilityCheckDialog() {}
+
+} // end svx namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ClassificationCommon.cxx b/svx/source/dialog/ClassificationCommon.cxx
new file mode 100644
index 000000000..885dff644
--- /dev/null
+++ b/svx/source/dialog/ClassificationCommon.cxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <svx/ClassificationCommon.hxx>
+#include <svx/ClassificationField.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyContainer.hpp>
+
+using namespace css;
+
+namespace svx::classification
+{
+OUString convertClassificationResultToString(std::vector<svx::ClassificationResult> const& rResults)
+{
+ OUStringBuffer sRepresentation;
+
+ for (svx::ClassificationResult const& rResult : rResults)
+ {
+ switch (rResult.meType)
+ {
+ case svx::ClassificationType::CATEGORY:
+ case svx::ClassificationType::INTELLECTUAL_PROPERTY_PART:
+ case svx::ClassificationType::MARKING:
+ case svx::ClassificationType::TEXT:
+ sRepresentation.append(rResult.msName);
+ break;
+
+ case svx::ClassificationType::PARAGRAPH:
+ sRepresentation.append(" ");
+ break;
+ }
+ }
+ return sRepresentation.makeStringAndClear();
+}
+
+OUString getProperty(uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer,
+ OUString const& rName)
+{
+ try
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(rxPropertyContainer, uno::UNO_QUERY);
+ return xPropertySet->getPropertyValue(rName).get<OUString>();
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+
+ return OUString();
+}
+
+bool containsProperty(uno::Sequence<beans::Property> const& rProperties, std::u16string_view rName)
+{
+ return std::any_of(rProperties.begin(), rProperties.end(),
+ [&](const beans::Property& rProperty) { return rProperty.Name == rName; });
+}
+
+void removeAllProperties(uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer)
+{
+ uno::Reference<beans::XPropertySet> xPropertySet(rxPropertyContainer, uno::UNO_QUERY);
+ const uno::Sequence<beans::Property> aProperties
+ = xPropertySet->getPropertySetInfo()->getProperties();
+
+ for (const beans::Property& rProperty : aProperties)
+ {
+ rxPropertyContainer->removeProperty(rProperty.Name);
+ }
+}
+
+bool addOrInsertDocumentProperty(
+ uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer, OUString const& rsKey,
+ OUString const& rsValue)
+{
+ uno::Reference<beans::XPropertySet> xPropertySet(rxPropertyContainer, uno::UNO_QUERY);
+
+ try
+ {
+ if (containsProperty(xPropertySet->getPropertySetInfo()->getProperties(), rsKey))
+ xPropertySet->setPropertyValue(rsKey, uno::Any(rsValue));
+ else
+ rxPropertyContainer->addProperty(rsKey, beans::PropertyAttribute::REMOVABLE,
+ uno::Any(rsValue));
+ }
+ catch (const uno::Exception& /*rException*/)
+ {
+ return false;
+ }
+ return true;
+}
+
+void insertFullTextualRepresentationAsDocumentProperty(
+ uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer,
+ sfx::ClassificationKeyCreator const& rKeyCreator,
+ std::vector<svx::ClassificationResult> const& rResults)
+{
+ OUString sString = convertClassificationResultToString(rResults);
+ addOrInsertDocumentProperty(rxPropertyContainer, rKeyCreator.makeFullTextualRepresentationKey(),
+ sString);
+}
+
+void insertCreationOrigin(uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer,
+ sfx::ClassificationKeyCreator const& rKeyCreator,
+ sfx::ClassificationCreationOrigin eOrigin)
+{
+ // Nothing to do if origin is "NONE"
+ if (eOrigin == sfx::ClassificationCreationOrigin::NONE)
+ return;
+
+ OUString sValue = (eOrigin == sfx::ClassificationCreationOrigin::BAF_POLICY)
+ ? OUString("BAF_POLICY")
+ : OUString("MANUAL");
+ addOrInsertDocumentProperty(rxPropertyContainer, rKeyCreator.makeCreationOriginKey(), sValue);
+}
+} // end svx::classification namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ClassificationDialog.cxx b/svx/source/dialog/ClassificationDialog.cxx
new file mode 100644
index 000000000..f0dc743f6
--- /dev/null
+++ b/svx/source/dialog/ClassificationDialog.cxx
@@ -0,0 +1,693 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <svx/ClassificationDialog.hxx>
+#include <svx/ClassificationCommon.hxx>
+
+#include <editeng/flditem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/section.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/wghtitem.hxx>
+#include <svl/itemset.hxx>
+#include <osl/file.hxx>
+#include <rtl/bootstrap.hxx>
+#include <config_folders.h>
+#include <tools/stream.hxx>
+#include <tools/XmlWriter.hxx>
+#include <tools/XmlWalker.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <officecfg/Office/Common.hxx>
+
+#include "ClassificationEditView.hxx"
+
+namespace svx {
+
+IMPL_STATIC_LINK(ClassificationDialog, KeyInput, const KeyEvent&, rKeyEvent, bool)
+{
+ bool bTextIsFreeForm = officecfg::Office::Common::Classification::IntellectualPropertyTextInputIsFreeForm::get();
+
+ if (!bTextIsFreeForm)
+ {
+ // Ignore key combination with modifier keys
+ if (rKeyEvent.GetKeyCode().IsMod3()
+ || rKeyEvent.GetKeyCode().IsMod2()
+ || rKeyEvent.GetKeyCode().IsMod1())
+ {
+ return true;
+ }
+
+ switch (rKeyEvent.GetKeyCode().GetCode())
+ {
+ // Allowed characters
+ case KEY_BACKSPACE:
+ case KEY_DELETE:
+ case KEY_DIVIDE:
+ case KEY_SEMICOLON:
+ case KEY_SPACE:
+ return false;
+ // Anything else is ignored
+ default:
+ return true;
+ }
+ }
+
+ return false;
+}
+
+namespace {
+
+constexpr size_t RECENTLY_USED_LIMIT = 5;
+
+constexpr OUStringLiteral constRecentlyUsedFileName(u"recentlyUsed.xml");
+
+OUString lcl_getClassificationUserPath()
+{
+ OUString sPath("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/user/classification/");
+ rtl::Bootstrap::expandMacros(sPath);
+ return sPath;
+}
+
+const SvxFieldItem* findField(editeng::Section const & rSection)
+{
+ for (SfxPoolItem const * pPool : rSection.maAttributes)
+ {
+ if (pPool->Which() == EE_FEATURE_FIELD)
+ return static_cast<const SvxFieldItem*>(pPool);
+ }
+ return nullptr;
+}
+
+bool fileExists(OUString const & sFilename)
+{
+ osl::File aFile(sFilename);
+ osl::FileBase::RC eRC = aFile.open(osl_File_OpenFlag_Read);
+ return osl::FileBase::E_None == eRC;
+}
+
+bool stringToClassificationType(std::string_view rsType, svx::ClassificationType & reType)
+{
+ if (rsType == "CATEGORY")
+ reType = svx::ClassificationType::CATEGORY;
+ else if (rsType == "INTELLECTUAL_PROPERTY_PART")
+ reType = svx::ClassificationType::INTELLECTUAL_PROPERTY_PART;
+ else if (rsType == "MARKING")
+ reType = svx::ClassificationType::MARKING;
+ else if (rsType == "PARAGRAPH")
+ reType = svx::ClassificationType::PARAGRAPH;
+ else if (rsType == "TEXT")
+ reType = svx::ClassificationType::TEXT;
+ else
+ return false;
+ return true;
+}
+
+OUString classificationTypeToString(svx::ClassificationType const & reType)
+{
+ switch(reType)
+ {
+ case svx::ClassificationType::CATEGORY:
+ return "CATEGORY"; break;
+ case svx::ClassificationType::MARKING:
+ return "MARKING"; break;
+ case svx::ClassificationType::TEXT:
+ return "TEXT"; break;
+ case svx::ClassificationType::INTELLECTUAL_PROPERTY_PART:
+ return "INTELLECTUAL_PROPERTY_PART"; break;
+ case svx::ClassificationType::PARAGRAPH:
+ return "PARAGRAPH"; break;
+ }
+ return OUString();
+}
+
+void writeResultToXml(tools::XmlWriter & rXmlWriter,
+ std::vector<ClassificationResult> const & rResultCollection)
+{
+ for (ClassificationResult const & rResult : rResultCollection)
+ {
+ rXmlWriter.startElement("element");
+ OUString sType = classificationTypeToString(rResult.meType);
+ rXmlWriter.attribute("type", sType);
+ rXmlWriter.startElement("string");
+ rXmlWriter.content(rResult.msName);
+ rXmlWriter.endElement();
+ rXmlWriter.startElement("abbreviatedString");
+ rXmlWriter.content(rResult.msAbbreviatedName);
+ rXmlWriter.endElement();
+ rXmlWriter.startElement("identifier");
+ rXmlWriter.content(rResult.msIdentifier);
+ rXmlWriter.endElement();
+ rXmlWriter.endElement();
+ }
+}
+
+} // end anonymous namespace
+
+ClassificationDialog::ClassificationDialog(weld::Window* pParent,const css::uno::Reference<css::document::XDocumentProperties>& rDocProps,
+ const bool bPerParagraph, const std::function<void()>& rParagraphSignHandler)
+ : GenericDialogController(pParent, "svx/ui/classificationdialog.ui", "AdvancedDocumentClassificationDialog")
+ , maHelper(rDocProps)
+ , maInternationalHelper(rDocProps, /*bUseLocalizedPolicy*/ false)
+ , m_bPerParagraph(bPerParagraph)
+ , m_aParagraphSignHandler(rParagraphSignHandler)
+ , m_nCurrentSelectedCategory(-1)
+ , m_xOkButton(m_xBuilder->weld_button("ok"))
+ , m_xSignButton(m_xBuilder->weld_button("signButton"))
+ , m_xToolBox(m_xBuilder->weld_toggle_button("toolbox"))
+ , m_xRecentlyUsedListBox(m_xBuilder->weld_combo_box("recentlyUsedCB"))
+ , m_xClassificationListBox(m_xBuilder->weld_combo_box("classificationCB"))
+ , m_xInternationalClassificationListBox(m_xBuilder->weld_combo_box("internationalClassificationCB"))
+ , m_xMarkingLabel(m_xBuilder->weld_label("markingLabel"))
+ , m_xMarkingListBox(m_xBuilder->weld_tree_view("markingLB"))
+ , m_xIntellectualPropertyPartListBox(m_xBuilder->weld_tree_view("intellectualPropertyPartLB"))
+ , m_xIntellectualPropertyPartNumberListBox(m_xBuilder->weld_tree_view("intellectualPropertyPartNumberLB"))
+ , m_xIntellectualPropertyPartAddButton(m_xBuilder->weld_button("intellectualPropertyPartAddButton"))
+ , m_xIntellectualPropertyPartEdit(m_xBuilder->weld_entry("intellectualPropertyPartEntry"))
+ , m_xIntellectualPropertyExpander(m_xBuilder->weld_expander("intellectualPropertyExpander"))
+ , m_xEditWindow(new ClassificationEditView)
+ , m_xEditWindowWeld(new weld::CustomWeld(*m_xBuilder, "classificationEditWindow", *m_xEditWindow))
+{
+ m_xOkButton->connect_clicked(LINK(this, ClassificationDialog, OkHdl));
+ m_xSignButton->connect_clicked(LINK(this, ClassificationDialog, ButtonClicked));
+ m_xSignButton->set_visible(m_bPerParagraph);
+
+ m_xIntellectualPropertyPartEdit->connect_key_press(LINK(this, ClassificationDialog, KeyInput));
+
+ // no need for BOLD if we do paragraph classification
+ if (m_bPerParagraph)
+ {
+ m_xToolBox->hide();
+ }
+ else
+ {
+ m_xToolBox->connect_toggled(LINK(this, ClassificationDialog, SelectToolboxHdl));
+ }
+
+ m_xIntellectualPropertyPartAddButton->connect_clicked(LINK(this, ClassificationDialog, ButtonClicked));
+
+ m_xClassificationListBox->set_size_request(m_xClassificationListBox->get_approximate_digit_width() * 20, -1);
+ m_xClassificationListBox->connect_changed(LINK(this, ClassificationDialog, SelectClassificationHdl));
+ for (const OUString& rName : maHelper.GetBACNames())
+ m_xClassificationListBox->append_text(rName);
+
+ m_xInternationalClassificationListBox->set_size_request(m_xInternationalClassificationListBox->get_approximate_digit_width() * 20, -1);
+ m_xInternationalClassificationListBox->connect_changed(LINK(this, ClassificationDialog, SelectClassificationHdl));
+ for (const OUString& rName : maInternationalHelper.GetBACNames())
+ m_xInternationalClassificationListBox->append_text(rName);
+
+ if (!maHelper.GetMarkings().empty())
+ {
+ m_xMarkingListBox->set_size_request(m_xMarkingListBox->get_approximate_digit_width() * 10,
+ m_xMarkingListBox->get_height_rows(4));
+ m_xMarkingListBox->connect_row_activated(LINK(this, ClassificationDialog, SelectMarkingHdl));
+
+ for (const OUString& rName : maHelper.GetMarkings())
+ m_xMarkingListBox->append_text(rName);
+ }
+ else
+ {
+ m_xMarkingListBox->hide();
+ m_xMarkingLabel->hide();
+ }
+
+ m_xIntellectualPropertyPartNumberListBox->set_size_request(m_xIntellectualPropertyPartNumberListBox->get_approximate_digit_width() * 10,
+ m_xIntellectualPropertyPartNumberListBox->get_height_rows(5));
+ m_xIntellectualPropertyPartNumberListBox->connect_row_activated(LINK(this, ClassificationDialog, SelectIPPartNumbersHdl));
+ for (const OUString& rName : maHelper.GetIntellectualPropertyPartNumbers())
+ m_xIntellectualPropertyPartNumberListBox->append_text(rName);
+
+ m_xIntellectualPropertyPartNumberListBox->set_size_request(m_xIntellectualPropertyPartNumberListBox->get_approximate_digit_width() * 20,
+ m_xIntellectualPropertyPartListBox->get_height_rows(5));
+ m_xIntellectualPropertyPartListBox->connect_row_activated(LINK(this, ClassificationDialog, SelectIPPartHdl));
+ for (const OUString& rName : maHelper.GetIntellectualPropertyParts())
+ m_xIntellectualPropertyPartListBox->append_text(rName);
+
+ m_xRecentlyUsedListBox->set_size_request(m_xRecentlyUsedListBox->get_approximate_digit_width() * 5, -1);
+ m_xRecentlyUsedListBox->connect_changed(LINK(this, ClassificationDialog, SelectRecentlyUsedHdl));
+
+ m_xIntellectualPropertyExpander->connect_expanded(LINK(this, ClassificationDialog, ExpandedHdl));
+ if (officecfg::Office::Common::Classification::IntellectualPropertySectionExpanded::get())
+ m_nAsyncExpandEvent = Application::PostUserEvent(LINK(this, ClassificationDialog, OnAsyncExpandHdl));
+ else
+ m_nAsyncExpandEvent = nullptr;
+
+ m_xEditWindow->SetModifyHdl(LINK(this, ClassificationDialog, EditWindowModifiedHdl));
+
+ readRecentlyUsed();
+ toggleWidgetsDependingOnCategory();
+
+ int nNumber = 1;
+ if (m_aRecentlyUsedValuesCollection.empty())
+ {
+ m_xRecentlyUsedListBox->set_sensitive(false);
+ }
+ else
+ {
+ for (std::vector<ClassificationResult> const & rResults : m_aRecentlyUsedValuesCollection)
+ {
+ OUString rContentRepresentation = svx::classification::convertClassificationResultToString(rResults);
+ OUString rDescription = OUString::number(nNumber) + ": " + rContentRepresentation;
+ nNumber++;
+
+ m_xRecentlyUsedListBox->append_text(rDescription);
+ }
+ }
+}
+
+//do it async so gtk has a chance to shrink it to best size, otherwise its larger than min
+IMPL_LINK_NOARG(ClassificationDialog, OnAsyncExpandHdl, void*, void)
+{
+ m_nAsyncExpandEvent = nullptr;
+ m_xIntellectualPropertyExpander->set_expanded(true);
+}
+
+ClassificationDialog::~ClassificationDialog()
+{
+ if (m_nAsyncExpandEvent)
+ Application::RemoveUserEvent(m_nAsyncExpandEvent);
+}
+
+void ClassificationDialog::insertCategoryField(sal_Int32 nID)
+{
+ const OUString aFullString = maHelper.GetBACNames()[nID];
+ const OUString aAbbreviatedString = maHelper.GetAbbreviatedBACNames()[nID];
+ const OUString aIdentifierString = maHelper.GetBACIdentifiers()[nID];
+ insertField(ClassificationType::CATEGORY, aAbbreviatedString, aFullString, aIdentifierString);
+}
+
+void ClassificationDialog::insertField(ClassificationType eType, OUString const & rString, OUString const & rFullString, OUString const & rIdentifier)
+{
+ ClassificationField aField(eType, rString, rFullString, rIdentifier);
+ m_xEditWindow->InsertField(SvxFieldItem(aField, EE_FEATURE_FIELD));
+}
+
+void ClassificationDialog::setupValues(std::vector<ClassificationResult> && rInput)
+{
+ m_aInitialValues = std::move(rInput);
+ readIn(m_aInitialValues);
+}
+
+void ClassificationDialog::readRecentlyUsed()
+{
+ OUString sPath = lcl_getClassificationUserPath();
+ OUString sFilePath(sPath + constRecentlyUsedFileName);
+
+ if (!fileExists(sFilePath))
+ return;
+
+ SvFileStream aFileStream(sFilePath, StreamMode::READ);
+ tools::XmlWalker aWalker;
+ if (!aWalker.open(&aFileStream))
+ return;
+
+ if (aWalker.name() != "recentlyUsedClassifications")
+ return;
+
+ aWalker.children();
+ while (aWalker.isValid())
+ {
+ if (aWalker.name() == "elementGroup")
+ {
+ std::vector<ClassificationResult> aResults;
+
+ aWalker.children();
+
+ while (aWalker.isValid())
+ {
+ if (aWalker.name() == "element")
+ {
+ svx::ClassificationType eType = svx::ClassificationType::TEXT;
+ OUString sString;
+ OUString sAbbreviatedString;
+ OUString sIdentifier;
+
+ // Convert string to classification type, but continue only if
+ // conversion was successful.
+ if (stringToClassificationType(aWalker.attribute("type"), eType))
+ {
+ aWalker.children();
+
+ while (aWalker.isValid())
+ {
+ if (aWalker.name() == "string")
+ {
+ sString = OStringToOUString(aWalker.content(), RTL_TEXTENCODING_UTF8);
+ }
+ else if (aWalker.name() == "abbreviatedString")
+ {
+ sAbbreviatedString = OStringToOUString(aWalker.content(), RTL_TEXTENCODING_UTF8);
+ }
+ else if (aWalker.name() == "identifier")
+ {
+ sIdentifier = OStringToOUString(aWalker.content(), RTL_TEXTENCODING_UTF8);
+ }
+ aWalker.next();
+ }
+ aWalker.parent();
+
+ aResults.push_back({ eType, sString, sAbbreviatedString, sIdentifier });
+ }
+ }
+ aWalker.next();
+ }
+ aWalker.parent();
+ m_aRecentlyUsedValuesCollection.push_back(aResults);
+ }
+ aWalker.next();
+ }
+ aWalker.parent();
+}
+
+void ClassificationDialog::writeRecentlyUsed()
+{
+ OUString sPath = lcl_getClassificationUserPath();
+ osl::Directory::createPath(sPath);
+ OUString sFilePath(sPath + constRecentlyUsedFileName);
+
+ std::unique_ptr<SvStream> pStream;
+ pStream.reset(new SvFileStream(sFilePath, StreamMode::STD_READWRITE | StreamMode::TRUNC));
+
+ tools::XmlWriter aXmlWriter(pStream.get());
+
+ if (!aXmlWriter.startDocument())
+ return;
+
+ aXmlWriter.startElement("recentlyUsedClassifications");
+
+ aXmlWriter.startElement("elementGroup");
+
+ writeResultToXml(aXmlWriter, getResult());
+
+ aXmlWriter.endElement();
+
+ if (m_aRecentlyUsedValuesCollection.size() >= RECENTLY_USED_LIMIT)
+ m_aRecentlyUsedValuesCollection.pop_back();
+
+ for (std::vector<ClassificationResult> const & rResultCollection : m_aRecentlyUsedValuesCollection)
+ {
+ aXmlWriter.startElement("elementGroup");
+
+ writeResultToXml(aXmlWriter, rResultCollection);
+
+ aXmlWriter.endElement();
+ }
+
+ aXmlWriter.endElement();
+
+ aXmlWriter.endDocument();
+}
+
+void ClassificationDialog::readIn(std::vector<ClassificationResult> const & rInput)
+{
+ sal_Int32 nParagraph = -1;
+
+ for (ClassificationResult const & rClassificationResult : rInput)
+ {
+
+ switch (rClassificationResult.meType)
+ {
+ case svx::ClassificationType::TEXT:
+ {
+ m_xEditWindow->getEditView().InsertText(rClassificationResult.msName);
+ }
+ break;
+
+ case svx::ClassificationType::CATEGORY:
+ {
+ OUString sName;
+ if (rClassificationResult.msName.isEmpty())
+ sName = maHelper.GetBACNameForIdentifier(rClassificationResult.msIdentifier);
+ else
+ sName = rClassificationResult.msName;
+
+ OUString sAbbreviatedName = rClassificationResult.msAbbreviatedName;
+ if (sAbbreviatedName.isEmpty())
+ sAbbreviatedName = maHelper.GetAbbreviatedBACName(sName);
+
+ m_xClassificationListBox->set_active_text(sName);
+ m_nCurrentSelectedCategory = m_xClassificationListBox->get_active();
+ m_xInternationalClassificationListBox->set_active(m_xClassificationListBox->get_active());
+
+ insertField(rClassificationResult.meType, sAbbreviatedName, sName, rClassificationResult.msIdentifier);
+ }
+ break;
+
+ case svx::ClassificationType::MARKING:
+ {
+ m_xMarkingListBox->select_text(rClassificationResult.msName);
+ insertField(rClassificationResult.meType, rClassificationResult.msName, rClassificationResult.msName, rClassificationResult.msIdentifier);
+ }
+ break;
+
+ case svx::ClassificationType::INTELLECTUAL_PROPERTY_PART:
+ {
+ insertField(rClassificationResult.meType, rClassificationResult.msName, rClassificationResult.msName, rClassificationResult.msIdentifier);
+ }
+ break;
+
+ case svx::ClassificationType::PARAGRAPH:
+ {
+ nParagraph++;
+
+ if (nParagraph != 0)
+ m_xEditWindow->getEditView().InsertParaBreak();
+
+ // Set paragraph font weight
+ FontWeight eWeight = (rClassificationResult.msName == "BOLD") ? WEIGHT_BOLD : WEIGHT_NORMAL;
+
+ ClassificationEditEngine& rEdEngine = m_xEditWindow->getEditEngine();
+ SfxItemSet aSet(rEdEngine.GetParaAttribs(nParagraph));
+ aSet.Put(SvxWeightItem(eWeight, EE_CHAR_WEIGHT));
+ rEdEngine.SetParaAttribs(nParagraph, aSet);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ toggleWidgetsDependingOnCategory();
+}
+
+void ClassificationDialog::toggleWidgetsDependingOnCategory()
+{
+ const EditEngine& rEditEngine = m_xEditWindow->getEditEngine();
+
+ for (sal_Int32 nParagraph = 0; nParagraph < rEditEngine.GetParagraphCount(); ++nParagraph)
+ {
+ sal_uInt16 nFieldCount = rEditEngine.GetFieldCount(nParagraph);
+ for (sal_uInt16 nField = 0; nField < nFieldCount; ++nField)
+ {
+ EFieldInfo aFieldInfo = rEditEngine.GetFieldInfo(nParagraph, nField);
+ if (aFieldInfo.pFieldItem)
+ {
+ const ClassificationField* pClassificationField = dynamic_cast<const ClassificationField*>(aFieldInfo.pFieldItem->GetField());
+ if (pClassificationField && pClassificationField->meType == ClassificationType::CATEGORY)
+ {
+ m_xOkButton->set_sensitive(true);
+ return;
+ }
+ }
+ }
+ }
+
+ // Category field in the text edit has been deleted, so reset the list boxes
+ m_xOkButton->set_sensitive(false);
+ m_xClassificationListBox->set_active(-1);
+ m_xInternationalClassificationListBox->set_active(-1);
+}
+
+std::vector<ClassificationResult> ClassificationDialog::getResult()
+{
+ std::vector<ClassificationResult> aClassificationResults;
+
+ ClassificationEditEngine& rEdEngine = m_xEditWindow->getEditEngine();
+ std::unique_ptr<EditTextObject> pEditText(rEdEngine.CreateTextObject());
+
+ sal_Int32 nCurrentParagraph = -1;
+
+ std::vector<editeng::Section> aSections;
+ pEditText->GetAllSections(aSections);
+ for (editeng::Section const & rSection : aSections)
+ {
+ while (nCurrentParagraph < rSection.mnParagraph)
+ {
+ nCurrentParagraph++;
+
+ // Get Weight of current paragraph
+ FontWeight eFontWeight = WEIGHT_NORMAL;
+ SfxItemSet aItemSet(rEdEngine.GetParaAttribs(nCurrentParagraph));
+ if (const SfxPoolItem* pItem = aItemSet.GetItem(EE_CHAR_WEIGHT, false))
+ {
+ const SvxWeightItem* pWeightItem = dynamic_cast<const SvxWeightItem*>(pItem);
+ if (pWeightItem && pWeightItem->GetWeight() == WEIGHT_BOLD)
+ eFontWeight = WEIGHT_BOLD;
+ }
+ // Font weight to string
+ OUString sWeightProperty = "NORMAL";
+ if (eFontWeight == WEIGHT_BOLD)
+ sWeightProperty = "BOLD";
+ // Insert into collection
+ OUString sBlank;
+ aClassificationResults.push_back({ ClassificationType::PARAGRAPH, sWeightProperty, sBlank, sBlank });
+ }
+
+ const SvxFieldItem* pFieldItem = findField(rSection);
+
+ ESelection aSelection(rSection.mnParagraph, rSection.mnStart, rSection.mnParagraph, rSection.mnEnd);
+ const OUString sDisplayString = rEdEngine.GetText(aSelection);
+ if (!sDisplayString.isEmpty())
+ {
+ const ClassificationField* pClassificationField = pFieldItem ? dynamic_cast<const ClassificationField*>(pFieldItem->GetField()) : nullptr;
+
+ if (pClassificationField)
+ {
+ aClassificationResults.push_back({ pClassificationField->meType, pClassificationField->msFullClassName,
+ pClassificationField->msDescription, pClassificationField->msIdentifier });
+ }
+ else
+ {
+ aClassificationResults.push_back({ ClassificationType::TEXT, sDisplayString, sDisplayString, OUString() });
+ }
+ }
+ }
+
+ return aClassificationResults;
+}
+
+IMPL_LINK(ClassificationDialog, SelectClassificationHdl, weld::ComboBox&, rBox, void)
+{
+ const sal_Int32 nSelected = rBox.get_active();
+ if (nSelected < 0 || m_nCurrentSelectedCategory == nSelected)
+ return;
+
+ std::unique_ptr<EditTextObject> pEditText(m_xEditWindow->getEditEngine().CreateTextObject());
+ std::vector<editeng::Section> aSections;
+ pEditText->GetAllSections(aSections);
+
+ // if we are replacing an existing field
+ bool bReplaceExisting = false;
+ // selection of the existing field, which will be replaced
+ ESelection aExistingFieldSelection;
+
+ for (editeng::Section const & rSection : aSections)
+ {
+ const SvxFieldItem* pFieldItem = findField(rSection);
+ if (pFieldItem)
+ {
+ const ClassificationField* pClassificationField = dynamic_cast<const ClassificationField*>(pFieldItem->GetField());
+ if (pClassificationField && pClassificationField->meType == ClassificationType::CATEGORY)
+ {
+ aExistingFieldSelection = ESelection(rSection.mnParagraph, rSection.mnStart,
+ rSection.mnParagraph, rSection.mnEnd);
+ bReplaceExisting = true;
+ }
+ }
+ }
+
+ if (bReplaceExisting)
+ m_xEditWindow->getEditView().SetSelection(aExistingFieldSelection);
+
+ insertCategoryField(nSelected);
+
+ // Change category to the new selection
+ m_xInternationalClassificationListBox->set_active(nSelected);
+ m_xClassificationListBox->set_active(nSelected);
+ m_nCurrentSelectedCategory = nSelected;
+}
+
+IMPL_LINK(ClassificationDialog, SelectMarkingHdl, weld::TreeView&, rBox, bool)
+{
+ sal_Int32 nSelected = rBox.get_selected_index();
+ if (nSelected >= 0)
+ {
+ const OUString aString = maHelper.GetMarkings()[nSelected];
+ insertField(ClassificationType::MARKING, aString, aString);
+ }
+ return true;
+}
+
+IMPL_LINK(ClassificationDialog, SelectIPPartNumbersHdl, weld::TreeView&, rBox, bool)
+{
+ sal_Int32 nSelected = rBox.get_selected_index();
+ if (nSelected >= 0)
+ {
+ OUString sString = maHelper.GetIntellectualPropertyPartNumbers()[nSelected];
+ m_xIntellectualPropertyPartEdit->replace_selection(sString);
+ m_xIntellectualPropertyPartEdit->grab_focus();
+ }
+ return true;
+}
+
+IMPL_LINK(ClassificationDialog, SelectRecentlyUsedHdl, weld::ComboBox&, rBox, void)
+{
+ sal_Int32 nSelected = rBox.get_active();
+ if (nSelected >= 0)
+ {
+ m_xEditWindow->getEditEngine().Clear();
+ readIn(m_aRecentlyUsedValuesCollection[nSelected]);
+ }
+}
+
+IMPL_LINK(ClassificationDialog, SelectIPPartHdl, weld::TreeView&, rBox, bool)
+{
+ const sal_Int32 nSelected = rBox.get_selected_index();
+ if (nSelected >= 0)
+ {
+ const OUString sString = maHelper.GetIntellectualPropertyParts()[nSelected];
+ m_xIntellectualPropertyPartEdit->replace_selection(sString);
+ m_xIntellectualPropertyPartEdit->grab_focus();
+ }
+ return true;
+}
+
+IMPL_LINK(ClassificationDialog, ButtonClicked, weld::Button&, rButton, void)
+{
+ if (&rButton == m_xSignButton.get())
+ {
+ m_aParagraphSignHandler();
+ }
+ else if (&rButton == m_xIntellectualPropertyPartAddButton.get())
+ {
+ const OUString sString = m_xIntellectualPropertyPartEdit->get_text();
+ insertField(ClassificationType::INTELLECTUAL_PROPERTY_PART, sString, sString);
+ }
+}
+
+IMPL_LINK_NOARG(ClassificationDialog, OkHdl, weld::Button&, void)
+{
+ writeRecentlyUsed();
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ClassificationDialog, SelectToolboxHdl, weld::Toggleable&, void)
+{
+ m_xEditWindow->InvertSelectionWeight();
+}
+
+IMPL_LINK_NOARG(ClassificationDialog, EditWindowModifiedHdl, LinkParamNone*, void)
+{
+ toggleWidgetsDependingOnCategory();
+}
+
+IMPL_STATIC_LINK(ClassificationDialog, ExpandedHdl, weld::Expander&, rExpander, void)
+{
+ std::shared_ptr<comphelper::ConfigurationChanges> aConfigurationChanges(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Classification::IntellectualPropertySectionExpanded::set(rExpander.get_expanded(), aConfigurationChanges);
+ aConfigurationChanges->commit();
+}
+
+} // end svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ClassificationEditView.cxx b/svx/source/dialog/ClassificationEditView.cxx
new file mode 100644
index 000000000..0b6ef3705
--- /dev/null
+++ b/svx/source/dialog/ClassificationEditView.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <svx/ClassificationField.hxx>
+
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/eeitem.hxx>
+
+#include "ClassificationEditView.hxx"
+
+namespace svx {
+
+ClassificationEditEngine::ClassificationEditEngine(SfxItemPool* pItemPool)
+ : EditEngine(pItemPool)
+{}
+
+OUString ClassificationEditEngine::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 /*nPara*/,
+ sal_Int32 /*nPos*/, std::optional<Color>& /*rTxtColor*/, std::optional<Color>& /*rFldColor*/)
+{
+ OUString aString;
+ const ClassificationField* pClassificationField = dynamic_cast<const ClassificationField*>(rField.GetField());
+ if (pClassificationField)
+ aString = pClassificationField->msDescription;
+ else
+ aString = "Unknown";
+ return aString;
+}
+
+ClassificationEditView::ClassificationEditView()
+{
+}
+
+void ClassificationEditView::makeEditEngine()
+{
+ m_xEditEngine.reset(new ClassificationEditEngine(EditEngine::CreatePool().get()));
+}
+
+ClassificationEditView::~ClassificationEditView()
+{
+}
+
+void ClassificationEditView::InsertField(const SvxFieldItem& rFieldItem)
+{
+ m_xEditView->InsertField(rFieldItem);
+ m_xEditView->Invalidate();
+}
+
+void ClassificationEditView::InvertSelectionWeight()
+{
+ ESelection aSelection = m_xEditView->GetSelection();
+
+ for (sal_Int32 nParagraph = aSelection.nStartPara; nParagraph <= aSelection.nEndPara; ++nParagraph)
+ {
+ FontWeight eFontWeight = WEIGHT_BOLD;
+
+ SfxItemSet aSet(m_xEditEngine->GetParaAttribs(nParagraph));
+ if (const SfxPoolItem* pItem = aSet.GetItem(EE_CHAR_WEIGHT, false))
+ {
+ const SvxWeightItem* pWeightItem = dynamic_cast<const SvxWeightItem*>(pItem);
+ if (pWeightItem && pWeightItem->GetWeight() == WEIGHT_BOLD)
+ eFontWeight = WEIGHT_NORMAL;
+ }
+ SvxWeightItem aWeight(eFontWeight, EE_CHAR_WEIGHT);
+ aSet.Put(aWeight);
+ m_xEditEngine->SetParaAttribs(nParagraph, aSet);
+ }
+
+ m_xEditView->Invalidate();
+}
+
+} // end sfx2
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ClassificationEditView.hxx b/svx/source/dialog/ClassificationEditView.hxx
new file mode 100644
index 000000000..b65e95399
--- /dev/null
+++ b/svx/source/dialog/ClassificationEditView.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#ifndef INCLUDED_SVX_CLASSIFICATIONEDITVIEW_HXX
+#define INCLUDED_SVX_CLASSIFICATIONEDITVIEW_HXX
+
+#include <sal/config.h>
+#include <svx/weldeditview.hxx>
+
+namespace svx {
+
+class ClassificationEditEngine final : public EditEngine
+{
+public:
+ ClassificationEditEngine(SfxItemPool* pItemPool);
+
+ virtual OUString CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos, std::optional<Color>& rTxtColor, std::optional<Color>& rFldColor) override;
+};
+
+class ClassificationEditView final : public WeldEditView
+{
+public:
+ ClassificationEditView();
+ virtual ~ClassificationEditView() override;
+
+ virtual void makeEditEngine() override;
+
+ void InsertField(const SvxFieldItem& rField);
+
+ void InvertSelectionWeight();
+
+ ClassificationEditEngine& getEditEngine()
+ {
+ return *static_cast<ClassificationEditEngine*>(m_xEditEngine.get());
+ }
+
+ EditView& getEditView()
+ {
+ return *m_xEditView;
+ }
+};
+
+} // end svx namespace
+
+#endif // INCLUDED_SVX_CLASSIFICATIONEDITVIEW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/FileExportedDialog.cxx b/svx/source/dialog/FileExportedDialog.cxx
new file mode 100644
index 000000000..e352a0621
--- /dev/null
+++ b/svx/source/dialog/FileExportedDialog.cxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <svx/FileExportedDialog.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <comphelper/backupfilehelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/system/XSystemShellExecute.hpp>
+#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
+#include <com/sun/star/system/SystemShellExecute.hpp>
+
+FileExportedDialog::FileExportedDialog(weld::Window* pParent, OUString atitle)
+ : GenericDialogController(pParent, "svx/ui/fileexporteddialog.ui", "FileExportedDialog")
+ , m_xFileLabel(m_xBuilder->weld_label("Filelabel"))
+ , m_xButton(m_xBuilder->weld_button("ok"))
+{
+ m_xFileLabel->set_label(atitle);
+ m_xButton->connect_clicked(LINK(this, FileExportedDialog, OpenHdl));
+}
+
+IMPL_LINK_NOARG(FileExportedDialog, OpenHdl, weld::Button&, void)
+{
+ const OUString uri(comphelper::BackupFileHelper::getUserProfileURL());
+ css::uno::Reference<css::system::XSystemShellExecute> exec(
+ css::system::SystemShellExecute::create(comphelper::getProcessComponentContext()));
+ try
+ {
+ exec->execute(uri, OUString(), css::system::SystemShellExecuteFlags::URIS_ONLY);
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "opening <" << uri << "> failed:");
+ }
+ m_xDialog->response(RET_OK);
+} \ No newline at end of file
diff --git a/svx/source/dialog/GenericCheckDialog.cxx b/svx/source/dialog/GenericCheckDialog.cxx
new file mode 100644
index 000000000..09fc3d678
--- /dev/null
+++ b/svx/source/dialog/GenericCheckDialog.cxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <svx/GenericCheckDialog.hxx>
+#include <vcl/svapp.hxx>
+
+namespace svx
+{
+GenericCheckEntry::GenericCheckEntry(weld::Container* pParent,
+ std::unique_ptr<CheckData>& pCheckData)
+ : m_xBuilder(Application::CreateBuilder(pParent, "svx/ui/genericcheckentry.ui"))
+ , m_xContainer(m_xBuilder->weld_container("checkEntryBox"))
+ , m_xLabel(m_xBuilder->weld_label("label"))
+ , m_xMarkButton(m_xBuilder->weld_button("markButton"))
+ , m_xPropertiesButton(m_xBuilder->weld_button("propertiesButton"))
+ , m_pCheckData(pCheckData)
+{
+ m_xLabel->set_label(m_pCheckData->getText());
+ m_xMarkButton->set_visible(m_pCheckData->canMarkObject());
+ m_xMarkButton->connect_clicked(LINK(this, GenericCheckEntry, MarkButtonClicked));
+ m_xPropertiesButton->set_visible(m_pCheckData->hasProperties());
+ m_xPropertiesButton->connect_clicked(LINK(this, GenericCheckEntry, PropertiesButtonClicked));
+
+ m_xContainer->show();
+}
+
+IMPL_LINK_NOARG(GenericCheckEntry, MarkButtonClicked, weld::Button&, void)
+{
+ m_pCheckData->markObject();
+}
+
+IMPL_LINK_NOARG(GenericCheckEntry, PropertiesButtonClicked, weld::Button&, void)
+{
+ m_pCheckData->runProperties();
+}
+
+GenericCheckDialog::GenericCheckDialog(weld::Window* pParent,
+ CheckDataCollection& rCheckDataCollection)
+ : GenericDialogController(pParent, "svx/ui/genericcheckdialog.ui", "GenericCheckDialog")
+ , m_rCheckDataCollection(rCheckDataCollection)
+ , m_xCheckBox(m_xBuilder->weld_box("checkBox"))
+{
+ set_title(m_rCheckDataCollection.getTitle());
+}
+
+GenericCheckDialog::~GenericCheckDialog() {}
+
+short GenericCheckDialog::run()
+{
+ sal_Int32 i = 0;
+
+ for (std::unique_ptr<CheckData>& pCheckData : m_rCheckDataCollection.getCollection())
+ {
+ auto xEntry = std::make_unique<GenericCheckEntry>(m_xCheckBox.get(), pCheckData);
+ m_xCheckBox->reorder_child(xEntry->get_widget(), i++);
+ m_aCheckEntries.push_back(std::move(xEntry));
+ }
+ return GenericDialogController::run();
+}
+
+} // end svx namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/SafeModeDialog.cxx b/svx/source/dialog/SafeModeDialog.cxx
new file mode 100644
index 000000000..beb530030
--- /dev/null
+++ b/svx/source/dialog/SafeModeDialog.cxx
@@ -0,0 +1,307 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "SafeModeDialog.hxx"
+
+#include <osl/file.hxx>
+#include <sfx2/safemode.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <comphelper/processfactory.hxx>
+#include <unotools/ZipPackageHelper.hxx>
+#include <unotools/configmgr.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/FileExportedDialog.hxx>
+
+#include <com/sun/star/task/OfficeRestartManager.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+
+using namespace css;
+
+SafeModeDialog::SafeModeDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "svx/ui/safemodedialog.ui", "SafeModeDialog")
+ , mxBtnContinue(m_xBuilder->weld_button("btn_continue"))
+ , mxBtnRestart(m_xBuilder->weld_button("btn_restart"))
+ , mxBtnApply(m_xBuilder->weld_button("btn_apply"))
+ , mxBoxRestore(m_xBuilder->weld_container("group_restore"))
+ , mxBoxConfigure(m_xBuilder->weld_container("group_configure"))
+ , mxBoxDeinstall(m_xBuilder->weld_container("group_deinstall"))
+ , mxBoxReset(m_xBuilder->weld_container("group_reset"))
+ , mxRadioRestore(m_xBuilder->weld_radio_button("radio_restore"))
+ , mxRadioConfigure(m_xBuilder->weld_radio_button("radio_configure"))
+ , mxRadioExtensions(m_xBuilder->weld_radio_button("radio_extensions"))
+ , mxRadioReset(m_xBuilder->weld_radio_button("radio_reset"))
+ , mxCBCheckProfilesafeConfig(m_xBuilder->weld_check_button("check_profilesafe_config"))
+ , mxCBCheckProfilesafeExtensions(m_xBuilder->weld_check_button("check_profilesafe_extensions"))
+ , mxCBDisableAllExtensions(m_xBuilder->weld_check_button("check_disable_all_extensions"))
+ , mxCBDeinstallUserExtensions(m_xBuilder->weld_check_button("check_deinstall_user_extensions"))
+ , mxCBResetSharedExtensions(m_xBuilder->weld_check_button("check_reset_shared_extensions"))
+ , mxCBResetBundledExtensions(m_xBuilder->weld_check_button("check_reset_bundled_extensions"))
+ , mxCBDisableHWAcceleration(m_xBuilder->weld_check_button("check_disable_hw_acceleration"))
+ , mxCBResetCustomizations(m_xBuilder->weld_check_button("check_reset_customizations"))
+ , mxCBResetWholeUserProfile(m_xBuilder->weld_check_button("check_reset_whole_userprofile"))
+ , mxBugLink(m_xBuilder->weld_link_button("linkbutton_bugs"))
+ , mxUserProfileLink(m_xBuilder->weld_link_button("linkbutton_profile"))
+ , mxBtnCreateZip(m_xBuilder->weld_button("btn_create_zip"))
+ , mxExpander(m_xBuilder->weld_expander("expander"))
+{
+ m_xDialog->set_centered_on_parent(false);
+ mxRadioRestore->connect_toggled(LINK(this, SafeModeDialog, RadioBtnHdl));
+ mxRadioConfigure->connect_toggled(LINK(this, SafeModeDialog, RadioBtnHdl));
+ mxRadioExtensions->connect_toggled(LINK(this, SafeModeDialog, RadioBtnHdl));
+ mxRadioReset->connect_toggled(LINK(this, SafeModeDialog, RadioBtnHdl));
+
+ mxBtnContinue->connect_clicked(LINK(this, SafeModeDialog, DialogBtnHdl));
+ mxBtnRestart->connect_clicked(LINK(this, SafeModeDialog, DialogBtnHdl));
+ mxBtnApply->connect_clicked(LINK(this, SafeModeDialog, DialogBtnHdl));
+
+ mxCBCheckProfilesafeConfig->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBCheckProfilesafeExtensions->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBDisableAllExtensions->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBDeinstallUserExtensions->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBResetSharedExtensions->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBResetBundledExtensions->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBDisableHWAcceleration->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBResetCustomizations->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBResetWholeUserProfile->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+
+ mxBtnCreateZip->connect_clicked(LINK(this, SafeModeDialog, CreateZipBtnHdl));
+
+ // Disable restart btn until some checkbox is active
+ mxBtnApply->set_sensitive(false);
+
+ // Check the first radio button and call its handler,
+ // it'll disable the relevant parts
+ mxRadioRestore->set_active(true);
+ RadioBtnHdl(*mxRadioRestore);
+
+ // Set URL for help button (module=safemode)
+ OUString sURL("http://hub.libreoffice.org/send-feedback/?LOversion=" + utl::ConfigManager::getAboutBoxProductVersion() +
+ "&LOlocale=" + utl::ConfigManager::getUILocale() + "&LOmodule=safemode");
+ mxBugLink->set_uri(sURL);
+
+ mxUserProfileLink->set_uri(comphelper::BackupFileHelper::getUserProfileURL());
+}
+
+SafeModeDialog::~SafeModeDialog()
+{
+}
+
+void SafeModeDialog::enableDisableWidgets()
+{
+ mxCBCheckProfilesafeConfig->set_sensitive(maBackupFileHelper.isPopPossible());
+ mxCBCheckProfilesafeExtensions->set_sensitive(maBackupFileHelper.isPopPossibleExtensionInfo());
+ mxCBDisableAllExtensions->set_sensitive(comphelper::BackupFileHelper::isTryDisableAllExtensionsPossible());
+ mxCBDeinstallUserExtensions->set_sensitive(comphelper::BackupFileHelper::isTryDeinstallUserExtensionsPossible());
+ mxCBResetSharedExtensions->set_sensitive(comphelper::BackupFileHelper::isTryResetSharedExtensionsPossible());
+ mxCBResetBundledExtensions->set_sensitive(comphelper::BackupFileHelper::isTryResetBundledExtensionsPossible());
+ mxCBResetCustomizations->set_sensitive(comphelper::BackupFileHelper::isTryResetCustomizationsPossible());
+
+ // no disable of mxCBResetWholeUserProfile, always possible (as last choice)
+}
+
+short SafeModeDialog::run()
+{
+ short nRet = weld::GenericDialogController::run();
+ // Remove the safe mode flag before exiting this dialog
+ sfx2::SafeMode::removeFlag();
+ return nRet;
+}
+
+void SafeModeDialog::applyChanges()
+{
+ // Restore
+ if (mxRadioRestore->get_active())
+ {
+ if (mxCBCheckProfilesafeConfig->get_active())
+ {
+ // reset UserConfiguration to last known working state
+ // ProfileSafeMode/BackupFileHelper
+ maBackupFileHelper.tryPop();
+ }
+
+ if (mxCBCheckProfilesafeExtensions->get_active())
+ {
+ // reset State of installed Extensions to last known working state
+ // ProfileSafeMode/BackupFileHelper
+ maBackupFileHelper.tryPopExtensionInfo();
+ }
+ }
+
+ // Configure
+ if (mxRadioConfigure->get_active())
+ {
+ if (mxCBDisableAllExtensions->get_active())
+ {
+ // Disable all extensions
+ comphelper::BackupFileHelper::tryDisableAllExtensions();
+ }
+
+ if (mxCBDisableHWAcceleration->get_active())
+ {
+ comphelper::BackupFileHelper::tryDisableHWAcceleration();
+ }
+ }
+
+ // Deinstall
+ if (mxRadioExtensions->get_active())
+ {
+ if (mxCBDeinstallUserExtensions->get_active())
+ {
+ // Deinstall all User Extensions (installed for User only)
+ comphelper::BackupFileHelper::tryDeinstallUserExtensions();
+ }
+
+ if (mxCBResetSharedExtensions->get_active())
+ {
+ // Reset shared Extensions
+ comphelper::BackupFileHelper::tryResetSharedExtensions();
+ }
+ if (mxCBResetBundledExtensions->get_active())
+ {
+ // Reset bundled Extensions
+ comphelper::BackupFileHelper::tryResetBundledExtensions();
+ }
+ }
+
+ // Reset
+ if (mxRadioReset->get_active())
+ {
+ if (mxCBResetCustomizations->get_active())
+ {
+ // Reset customizations (Settings and UserInterface modifications)
+ comphelper::BackupFileHelper::tryResetCustomizations();
+ }
+
+ if (mxCBResetWholeUserProfile->get_active())
+ {
+ // Reset the whole UserProfile
+ comphelper::BackupFileHelper::tryResetUserProfile();
+ }
+ }
+
+ // finally, restart
+ css::task::OfficeRestartManager::get(comphelper::getProcessComponentContext())->requestRestart(
+ css::uno::Reference< css::task::XInteractionHandler >());
+}
+
+IMPL_LINK(SafeModeDialog, RadioBtnHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+ if (mxRadioRestore->get_active())
+ {
+ // Enable the currently selected box
+ mxBoxRestore->set_sensitive(true);
+ // Make sure only possible choices are active
+ enableDisableWidgets();
+ // Disable the unselected boxes
+ mxBoxReset->set_sensitive(false);
+ mxBoxConfigure->set_sensitive(false);
+ mxBoxDeinstall->set_sensitive(false);
+ }
+ else if (mxRadioConfigure->get_active())
+ {
+ // Enable the currently selected box
+ mxBoxConfigure->set_sensitive(true);
+ // Make sure only possible choices are active
+ enableDisableWidgets();
+ // Disable the unselected boxes
+ mxBoxRestore->set_sensitive(false);
+ mxBoxReset->set_sensitive(false);
+ mxBoxDeinstall->set_sensitive(false);
+
+ }
+ else if (mxRadioExtensions->get_active())
+ {
+ // Enable the currently selected box
+ mxBoxDeinstall->set_sensitive(true);
+ // Make sure only possible choices are active
+ enableDisableWidgets();
+ // Disable the unselected boxes
+ mxBoxRestore->set_sensitive(false);
+ mxBoxConfigure->set_sensitive(false);
+ mxBoxReset->set_sensitive(false);
+ }
+ else if (mxRadioReset->get_active())
+ {
+ // Enable the currently selected box
+ mxBoxReset->set_sensitive(true);
+ // Make sure only possible choices are active
+ enableDisableWidgets();
+ // Disable the unselected boxes
+ mxBoxConfigure->set_sensitive(false);
+ mxBoxRestore->set_sensitive(false);
+ mxBoxDeinstall->set_sensitive(false);
+ }
+}
+
+IMPL_LINK(SafeModeDialog, DialogBtnHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == mxBtnContinue.get())
+ {
+ m_xDialog->response(RET_CLOSE);
+ }
+ else if (&rBtn == mxBtnRestart.get())
+ {
+ sfx2::SafeMode::putRestartFlag();
+ m_xDialog->response(RET_CLOSE);
+ uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
+ css::task::OfficeRestartManager::get(xContext)->requestRestart(
+ css::uno::Reference< css::task::XInteractionHandler >());
+ }
+ else if (&rBtn == mxBtnApply.get())
+ {
+ sfx2::SafeMode::putRestartFlag();
+ m_xDialog->response(RET_CLOSE);
+ applyChanges();
+ }
+}
+
+IMPL_LINK(SafeModeDialog, CreateZipBtnHdl, weld::Button&, /*rBtn*/, void)
+{
+ const OUString zipFileURL(comphelper::BackupFileHelper::getUserProfileURL() + "/libreoffice-profile.zip");
+ osl::File::remove(zipFileURL); // Remove previous exports
+ try
+ {
+ utl::ZipPackageHelper aZipHelper(comphelper::getProcessComponentContext(), zipFileURL);
+ aZipHelper.addFolderWithContent(aZipHelper.getRootFolder(), comphelper::BackupFileHelper::getUserProfileWorkURL());
+ aZipHelper.savePackage();
+ }
+ catch (const uno::Exception &)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SvxResId(RID_SVXSTR_SAFEMODE_ZIP_FAILURE)));
+ xBox->run();
+ return;
+ }
+
+ FileExportedDialog aDialog(m_xDialog.get(),"Your user profile has been exported as 'libreoffice-profile.zip'.");
+ aDialog.run();
+}
+
+IMPL_LINK(SafeModeDialog, CheckBoxHdl, weld::Toggleable&, /*pCheckBox*/, void)
+{
+ const bool bEnable(
+ mxCBCheckProfilesafeConfig->get_active() ||
+ mxCBCheckProfilesafeExtensions->get_active() ||
+ mxCBDisableAllExtensions->get_active() ||
+ mxCBDeinstallUserExtensions->get_active() ||
+ mxCBResetSharedExtensions->get_active() ||
+ mxCBResetBundledExtensions->get_active() ||
+ mxCBDisableHWAcceleration->get_active() ||
+ mxCBResetCustomizations->get_active() ||
+ mxCBResetWholeUserProfile->get_active());
+
+ mxBtnApply->set_sensitive(bEnable);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/SafeModeDialog.hxx b/svx/source/dialog/SafeModeDialog.hxx
new file mode 100644
index 000000000..0f90c1e29
--- /dev/null
+++ b/svx/source/dialog/SafeModeDialog.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_SAFEMODEDIALOG_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_SAFEMODEDIALOG_HXX
+
+#include <comphelper/backupfilehelper.hxx>
+#include <vcl/weld.hxx>
+
+class SafeModeDialog : public weld::GenericDialogController
+{
+public:
+ explicit SafeModeDialog(weld::Window* pParent);
+ virtual short run() override;
+ virtual ~SafeModeDialog() override;
+
+private:
+ std::unique_ptr<weld::Button> mxBtnContinue;
+ std::unique_ptr<weld::Button> mxBtnRestart;
+ std::unique_ptr<weld::Button> mxBtnApply;
+
+ std::unique_ptr<weld::Container> mxBoxRestore;
+ std::unique_ptr<weld::Container> mxBoxConfigure;
+ std::unique_ptr<weld::Container> mxBoxDeinstall;
+ std::unique_ptr<weld::Container> mxBoxReset;
+
+ std::unique_ptr<weld::RadioButton> mxRadioRestore;
+ std::unique_ptr<weld::RadioButton> mxRadioConfigure;
+ std::unique_ptr<weld::RadioButton> mxRadioExtensions;
+ std::unique_ptr<weld::RadioButton> mxRadioReset;
+
+ std::unique_ptr<weld::CheckButton> mxCBCheckProfilesafeConfig;
+ std::unique_ptr<weld::CheckButton> mxCBCheckProfilesafeExtensions;
+ std::unique_ptr<weld::CheckButton> mxCBDisableAllExtensions;
+ std::unique_ptr<weld::CheckButton> mxCBDeinstallUserExtensions;
+ std::unique_ptr<weld::CheckButton> mxCBResetSharedExtensions;
+ std::unique_ptr<weld::CheckButton> mxCBResetBundledExtensions;
+ std::unique_ptr<weld::CheckButton> mxCBDisableHWAcceleration;
+ std::unique_ptr<weld::CheckButton> mxCBResetCustomizations;
+ std::unique_ptr<weld::CheckButton> mxCBResetWholeUserProfile;
+
+ std::unique_ptr<weld::LinkButton> mxBugLink;
+ std::unique_ptr<weld::LinkButton> mxUserProfileLink;
+ std::unique_ptr<weld::Button> mxBtnCreateZip;
+ std::unique_ptr<weld::Expander> mxExpander;
+
+ // local BackupFileHelper for handling possible restores
+ comphelper::BackupFileHelper maBackupFileHelper;
+
+ void enableDisableWidgets();
+ void applyChanges();
+
+ DECL_LINK(RadioBtnHdl, weld::Toggleable&, void);
+ DECL_LINK(CheckBoxHdl, weld::Toggleable&, void);
+ DECL_LINK(CreateZipBtnHdl, weld::Button&, void);
+ DECL_LINK(DialogBtnHdl, weld::Button&, void);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/SafeModeUI.cxx b/svx/source/dialog/SafeModeUI.cxx
new file mode 100644
index 000000000..4e32669f0
--- /dev/null
+++ b/svx/source/dialog/SafeModeUI.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/frame/XSynchronousDispatch.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include "SafeModeDialog.hxx"
+
+namespace {
+
+class SafeModeUI : public ::cppu::WeakImplHelper< css::lang::XServiceInfo,
+ css::frame::XSynchronousDispatch > // => XDispatch!
+{
+public:
+ SafeModeUI();
+
+ // css.lang.XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(const OUString& sServiceName) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+
+ virtual css::uno::Any SAL_CALL dispatchWithReturnValue(const css::util::URL& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override;
+};
+
+SafeModeUI::SafeModeUI()
+{
+}
+
+OUString SAL_CALL SafeModeUI::getImplementationName()
+{
+ return "com.sun.star.comp.svx.SafeModeUI";
+}
+
+sal_Bool SAL_CALL SafeModeUI::supportsService(const OUString& sServiceName)
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL SafeModeUI::getSupportedServiceNames()
+{
+ return { "com.sun.star.dialog.SafeModeUI" };
+}
+
+css::uno::Any SAL_CALL SafeModeUI::dispatchWithReturnValue(const css::util::URL&,
+ const css::uno::Sequence< css::beans::PropertyValue >& )
+{
+ SolarMutexGuard aGuard;
+ css::uno::Any aRet;
+ SafeModeDialog aDialog(Application::GetDefDialogParent());
+ aDialog.run();
+ return aRet;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_SafeModeUI_get_implementation(
+ css::uno::XComponentContext * /*context*/,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SafeModeUI);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/SpellDialogChildWindow.cxx b/svx/source/dialog/SpellDialogChildWindow.cxx
new file mode 100644
index 000000000..ae82769df
--- /dev/null
+++ b/svx/source/dialog/SpellDialogChildWindow.cxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/SpellDialogChildWindow.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <osl/diagnose.h>
+
+namespace svx {
+
+
+SpellDialogChildWindow::SpellDialogChildWindow (
+ vcl::Window* _pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings)
+ : SfxChildWindow (_pParent, nId)
+{
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ m_xAbstractSpellDialog = pFact->CreateSvxSpellDialog(_pParent->GetFrameWeld(),
+ pBindings,
+ this );
+ SetController(m_xAbstractSpellDialog->GetController());
+ SetHideNotDelete(true);
+}
+
+SpellDialogChildWindow::~SpellDialogChildWindow()
+{
+ m_xAbstractSpellDialog.disposeAndClear();
+}
+
+SfxBindings& SpellDialogChildWindow::GetBindings() const
+{
+ assert(m_xAbstractSpellDialog);
+ return m_xAbstractSpellDialog->GetBindings();
+}
+
+void SpellDialogChildWindow::InvalidateSpellDialog()
+{
+ OSL_ASSERT (m_xAbstractSpellDialog);
+ if (m_xAbstractSpellDialog)
+ m_xAbstractSpellDialog->InvalidateDialog();
+}
+
+bool SpellDialogChildWindow::HasAutoCorrection()
+{
+ return false;
+}
+
+void SpellDialogChildWindow::AddAutoCorrection(
+ const OUString& /*rOld*/,
+ const OUString& /*rNew*/,
+ LanguageType /*eLanguage*/)
+{
+ OSL_FAIL("AutoCorrection should have been overridden - if available");
+}
+
+bool SpellDialogChildWindow::HasGrammarChecking()
+{
+ return false;
+}
+
+bool SpellDialogChildWindow::IsGrammarChecking()
+{
+ OSL_FAIL("Grammar checking should have been overridden - if available");
+ return false;
+}
+
+void SpellDialogChildWindow::SetGrammarChecking(bool )
+{
+ OSL_FAIL("Grammar checking should have been overridden - if available");
+}
+} // end of namespace ::svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/SvxNumOptionsTabPageHelper.cxx b/svx/source/dialog/SvxNumOptionsTabPageHelper.cxx
new file mode 100644
index 000000000..0236c8835
--- /dev/null
+++ b/svx/source/dialog/SvxNumOptionsTabPageHelper.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/SvxNumOptionsTabPageHelper.hxx>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/text/DefaultNumberingProvider.hpp>
+#include <com/sun/star/text/XNumberingTypeInfo.hpp>
+#include <comphelper/processfactory.hxx>
+
+using namespace css;
+using namespace css::uno;
+using namespace css::text;
+using namespace css::style;
+
+Reference<XDefaultNumberingProvider> SvxNumOptionsTabPageHelper::GetNumberingProvider()
+{
+ Reference<XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ Reference<XDefaultNumberingProvider> xRet = text::DefaultNumberingProvider::create(xContext);
+ return xRet;
+}
+
+void SvxNumOptionsTabPageHelper::GetI18nNumbering(weld::ComboBox& rFmtLB, sal_uInt16 nDoNotRemove)
+{
+ Reference<XDefaultNumberingProvider> xDefNum = GetNumberingProvider();
+ Reference<XNumberingTypeInfo> xInfo(xDefNum, UNO_QUERY);
+
+ // Extended numbering schemes present in the resource but not offered by
+ // the i18n framework per configuration must be removed from the listbox.
+ // Do not remove a special entry matching nDoNotRemove.
+ const sal_uInt16 nDontRemove = SAL_MAX_UINT16;
+ ::std::vector<sal_uInt16> aRemove(rFmtLB.get_count(), nDontRemove);
+ for (size_t i = 0; i < aRemove.size(); ++i)
+ {
+ sal_uInt16 nEntryData = rFmtLB.get_id(i).toInt32();
+ if (nEntryData > NumberingType::CHARS_LOWER_LETTER_N && nEntryData != nDoNotRemove)
+ aRemove[i] = nEntryData;
+ }
+ if (xInfo.is())
+ {
+ const Sequence<sal_Int16> aTypes = xInfo->getSupportedNumberingTypes();
+ for (const sal_Int16 nCurrent : aTypes)
+ {
+ if (nCurrent > NumberingType::CHARS_LOWER_LETTER_N)
+ {
+ bool bInsert = true;
+ for (int nEntry = 0; nEntry < rFmtLB.get_count(); ++nEntry)
+ {
+ sal_uInt16 nEntryData = rFmtLB.get_id(nEntry).toInt32();
+ if (nEntryData == static_cast<sal_uInt16>(nCurrent))
+ {
+ bInsert = false;
+ aRemove[nEntry] = nDontRemove;
+ break;
+ }
+ }
+ if (bInsert)
+ {
+ OUString aIdent = xInfo->getNumberingIdentifier(nCurrent);
+ rFmtLB.append(OUString::number(nCurrent), aIdent);
+ }
+ }
+ }
+ }
+ for (unsigned short i : aRemove)
+ {
+ if (i == nDontRemove)
+ continue;
+ rFmtLB.remove_id(OUString::number(i));
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/_bmpmask.cxx b/svx/source/dialog/_bmpmask.cxx
new file mode 100644
index 000000000..2be9a7c8d
--- /dev/null
+++ b/svx/source/dialog/_bmpmask.cxx
@@ -0,0 +1,1057 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/event.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/virdev.hxx>
+#include <svtools/valueset.hxx>
+#include <svl/eitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svtools/colrdlg.hxx>
+
+#include <svx/colorbox.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/bmpmask.hxx>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <memory>
+#include <helpids.h>
+
+#define OWN_CALLMODE SfxCallMode::ASYNCHRON | SfxCallMode::RECORD
+
+
+#define TEST_COLS() \
+{ \
+ nR = aCol.GetRed(); nG = aCol.GetGreen(); nB = aCol.GetBlue(); \
+ for( i = 0; i < nCount; i++ ) \
+ { \
+ if ( ( pMinR[i] <= nR ) && ( pMaxR[i] >= nR ) && \
+ ( pMinG[i] <= nG ) && ( pMaxG[i] >= nG ) && \
+ ( pMinB[i] <= nB ) && ( pMaxB[i] >= nB ) ) \
+ { \
+ aCol = pDstCols[i]; bReplace = true; break; \
+ } \
+ } \
+}
+
+SFX_IMPL_DOCKINGWINDOW_WITHID( SvxBmpMaskChildWindow, SID_BMPMASK )
+
+class BmpColorWindow : public weld::CustomWidgetController
+{
+ Color aColor;
+
+
+public:
+ explicit BmpColorWindow()
+ : aColor( COL_WHITE )
+ {
+ }
+
+ void SetColor( const Color& rColor )
+ {
+ aColor = rColor;
+ Invalidate();
+ }
+
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+
+ virtual void SetDrawingArea(weld::DrawingArea* pArea) override
+ {
+ Size aSize(pArea->get_ref_device().LogicToPixel(Size(43, 14), MapMode(MapUnit::MapAppFont)));
+ CustomWidgetController::SetDrawingArea(pArea);
+ pArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ }
+};
+
+class MaskSet : public ValueSet
+{
+ VclPtr<SvxBmpMask> pSvxBmpMask;
+
+public:
+ MaskSet(SvxBmpMask* pMask);
+ virtual void Select() override;
+ virtual bool KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void GetFocus() override;
+ virtual void SetDrawingArea(weld::DrawingArea* pArea) override
+ {
+ Size aSize(pArea->get_ref_device().LogicToPixel(Size(24, 12), MapMode(MapUnit::MapAppFont)));
+ ValueSet::SetDrawingArea(pArea);
+ pArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ SetHelpId(HID_BMPMASK_CTL_QCOL_1);
+ }
+ void onEditColor();
+};
+
+MaskSet::MaskSet(SvxBmpMask* pMask)
+ : ValueSet(nullptr)
+ , pSvxBmpMask(pMask)
+{
+}
+
+void MaskSet::Select()
+{
+ ValueSet::Select();
+
+ pSvxBmpMask->onSelect( this );
+}
+
+void MaskSet::GetFocus()
+{
+ ValueSet::GetFocus();
+ SelectItem( 1 );
+ pSvxBmpMask->onSelect( this );
+}
+
+bool MaskSet::KeyInput( const KeyEvent& rKEvt )
+{
+ bool bRet = false;
+
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ // if the key has a modifier we don't care
+ if( aCode.GetModifier() )
+ {
+ bRet = ValueSet::KeyInput( rKEvt );
+ }
+ else
+ {
+ // check for keys that interests us
+ switch ( aCode.GetCode() )
+ {
+ case KEY_SPACE:
+ onEditColor();
+ bRet = true;
+ break;
+ default:
+ bRet = ValueSet::KeyInput( rKEvt );
+ }
+ }
+ return bRet;
+}
+
+void MaskSet::onEditColor()
+{
+ SvColorDialog aColorDlg;
+
+ aColorDlg.SetColor(GetItemColor(1));
+
+ if (aColorDlg.Execute(pSvxBmpMask->GetFrameWeld()))
+ SetItemColor(1, aColorDlg.GetColor());
+}
+
+class MaskData
+{
+ VclPtr<SvxBmpMask> pMask;
+ bool bIsReady;
+ bool bExecState;
+ SfxBindings& rBindings;
+
+public:
+ MaskData( SvxBmpMask* pBmpMask, SfxBindings& rBind );
+
+ bool IsCbxReady() const { return bIsReady; }
+ void SetExecState( bool bState ) { bExecState = bState; }
+ bool IsExecReady() const { return bExecState; }
+
+ DECL_LINK( PipetteHdl, const OString&, void );
+ DECL_LINK( CbxHdl, weld::Toggleable&, void);
+ DECL_LINK( CbxTransHdl, weld::Toggleable&, void );
+ DECL_LINK( FocusLbHdl, weld::Widget&, void );
+ DECL_LINK(ExecHdl, weld::Button&, void);
+};
+
+
+MaskData::MaskData( SvxBmpMask* pBmpMask, SfxBindings& rBind ) :
+
+ pMask ( pBmpMask ),
+ bIsReady ( false ),
+ bExecState ( false ),
+ rBindings ( rBind )
+
+{
+}
+
+IMPL_LINK( MaskData, PipetteHdl, const OString&, rId, void )
+{
+ SfxBoolItem aBItem( SID_BMPMASK_PIPETTE,
+ pMask->m_xTbxPipette->get_item_active(rId) );
+
+ rBindings.GetDispatcher()->ExecuteList(SID_BMPMASK_PIPETTE, OWN_CALLMODE,
+ { &aBItem });
+}
+
+IMPL_LINK( MaskData, CbxHdl, weld::Toggleable&, rCbx, void )
+{
+ bIsReady = pMask->m_xCbx1->get_active() || pMask->m_xCbx2->get_active() ||
+ pMask->m_xCbx3->get_active() || pMask->m_xCbx4->get_active();
+
+ if ( bIsReady && IsExecReady() )
+ pMask->m_xBtnExec->set_sensitive(true);
+ else
+ pMask->m_xBtnExec->set_sensitive(false);
+
+ // When a checkbox is checked, the pipette is enabled
+ if ( !rCbx.get_active() )
+ return;
+
+ MaskSet* pSet = nullptr;
+
+ if (&rCbx == pMask->m_xCbx1.get())
+ pSet = pMask->m_xQSet1.get();
+ else if (&rCbx == pMask->m_xCbx2.get())
+ pSet = pMask->m_xQSet2.get();
+ else if (&rCbx == pMask->m_xCbx3.get())
+ pSet = pMask->m_xQSet3.get();
+ else // if ( &rCbx == pMask->m_xCbx4 )
+ pSet = pMask->m_xQSet4.get();
+
+ pSet->SelectItem( 1 );
+ pSet->Select();
+
+ pMask->m_xTbxPipette->set_item_active("pipette", true);
+ PipetteHdl("pipette");
+}
+
+IMPL_LINK( MaskData, CbxTransHdl, weld::Toggleable&, rCbx, void )
+{
+ bIsReady = rCbx.get_active();
+ if ( bIsReady )
+ {
+ pMask->m_xQSet1->Disable();
+ pMask->m_xQSet2->Disable();
+ pMask->m_xQSet3->Disable();
+ pMask->m_xQSet4->Disable();
+ pMask->m_xCtlPipette->Disable();
+ pMask->m_xCbx1->set_sensitive(false);
+ pMask->m_xSp1->set_sensitive(false);
+ pMask->m_xCbx2->set_sensitive(false);
+ pMask->m_xSp2->set_sensitive(false);
+ pMask->m_xCbx3->set_sensitive(false);
+ pMask->m_xSp3->set_sensitive(false);
+ pMask->m_xCbx4->set_sensitive(false);
+ pMask->m_xSp4->set_sensitive(false);
+ pMask->m_xTbxPipette->set_sensitive(false);
+
+ pMask->m_xLbColor1->set_sensitive(false);
+ pMask->m_xLbColor2->set_sensitive(false);
+ pMask->m_xLbColor3->set_sensitive(false);
+ pMask->m_xLbColor4->set_sensitive(false);
+ pMask->m_xLbColorTrans->set_sensitive(true);
+ }
+ else
+ {
+ pMask->m_xQSet1->Enable();
+ pMask->m_xQSet2->Enable();
+ pMask->m_xQSet3->Enable();
+ pMask->m_xQSet4->Enable();
+ pMask->m_xCtlPipette->Enable();
+ pMask->m_xCbx1->set_sensitive(true);
+ pMask->m_xSp1->set_sensitive(true);
+ pMask->m_xCbx2->set_sensitive(true);
+ pMask->m_xSp2->set_sensitive(true);
+ pMask->m_xCbx3->set_sensitive(true);
+ pMask->m_xSp3->set_sensitive(true);
+ pMask->m_xCbx4->set_sensitive(true);
+ pMask->m_xSp4->set_sensitive(true);
+ pMask->m_xTbxPipette->set_sensitive(true);
+
+ pMask->m_xLbColor1->set_sensitive(true);
+ pMask->m_xLbColor2->set_sensitive(true);
+ pMask->m_xLbColor3->set_sensitive(true);
+ pMask->m_xLbColor4->set_sensitive(true);
+ pMask->m_xLbColorTrans->set_sensitive(false);
+
+ bIsReady = pMask->m_xCbx1->get_active() || pMask->m_xCbx2->get_active() ||
+ pMask->m_xCbx3->get_active() || pMask->m_xCbx4->get_active();
+ }
+
+ if ( bIsReady && IsExecReady() )
+ pMask->m_xBtnExec->set_sensitive(true);
+ else
+ pMask->m_xBtnExec->set_sensitive(false);
+}
+
+IMPL_LINK( MaskData, FocusLbHdl, weld::Widget&, rLb, void )
+{
+ pMask->m_xQSet1->SelectItem( &rLb == &pMask->m_xLbColor1->get_widget() ? 1 : 0 /* , false */ );
+ pMask->m_xQSet2->SelectItem( &rLb == &pMask->m_xLbColor2->get_widget() ? 1 : 0 /* , false */ );
+ pMask->m_xQSet3->SelectItem( &rLb == &pMask->m_xLbColor3->get_widget() ? 1 : 0 /* , false */ );
+ pMask->m_xQSet4->SelectItem( &rLb == &pMask->m_xLbColor4->get_widget() ? 1 : 0 /* , false */ );
+}
+
+IMPL_LINK_NOARG(MaskData, ExecHdl, weld::Button&, void)
+{
+ SfxBoolItem aBItem( SID_BMPMASK_EXEC, true );
+ rBindings.GetDispatcher()->ExecuteList(SID_BMPMASK_EXEC, OWN_CALLMODE,
+ { &aBItem });
+}
+
+void BmpColorWindow::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& /*Rect*/)
+{
+ rRenderContext.Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR);
+ rRenderContext.SetLineColor(aColor);
+ rRenderContext.SetFillColor(aColor);
+ rRenderContext.DrawRect(tools::Rectangle(Point(), GetOutputSizePixel()));
+ rRenderContext.Pop();
+}
+
+SvxBmpMaskSelectItem::SvxBmpMaskSelectItem( SvxBmpMask& rMask,
+ SfxBindings& rBindings ) :
+ SfxControllerItem ( SID_BMPMASK_EXEC, rBindings ),
+ rBmpMask ( rMask)
+{
+}
+
+void SvxBmpMaskSelectItem::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState /*eState*/,
+ const SfxPoolItem* pItem )
+{
+ if ( ( nSID == SID_BMPMASK_EXEC ) && pItem )
+ {
+ const SfxBoolItem* pStateItem = dynamic_cast<const SfxBoolItem*>( pItem );
+ assert(pStateItem); // SfxBoolItem expected
+ if (pStateItem)
+ rBmpMask.SetExecState( pStateItem->GetValue() );
+ }
+}
+
+SvxBmpMaskChildWindow::SvxBmpMaskChildWindow(vcl::Window* pParent_, sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo)
+ : SfxChildWindow(pParent_, nId)
+{
+ VclPtr<SvxBmpMask> pDlg = VclPtr<SvxBmpMask>::Create(pBindings, this, pParent_);
+
+ SetWindow( pDlg );
+
+ pDlg->Initialize( pInfo );
+}
+
+SvxBmpMask::SvxBmpMask(SfxBindings *pBindinx, SfxChildWindow *pCW, vcl::Window* pParent)
+ : SfxDockingWindow(pBindinx, pCW, pParent, "DockingColorReplace",
+ "svx/ui/dockingcolorreplace.ui")
+ , m_xTbxPipette(m_xBuilder->weld_toolbar("toolbar"))
+ , m_xCtlPipette(new BmpColorWindow)
+ , m_xCtlPipetteWin(new weld::CustomWeld(*m_xBuilder, "toolcolor", *m_xCtlPipette))
+ , m_xBtnExec(m_xBuilder->weld_button("replace"))
+ , m_xCbx1(m_xBuilder->weld_check_button("cbx1"))
+ , m_xQSet1(new MaskSet(this))
+ , m_xQSetWin1(new weld::CustomWeld(*m_xBuilder, "qset1", *m_xQSet1))
+ , m_xSp1(m_xBuilder->weld_metric_spin_button("tol1", FieldUnit::PERCENT))
+ , m_xLbColor1(new ColorListBox(m_xBuilder->weld_menu_button("color1"), [this]{ return GetFrameWeld(); }))
+ , m_xCbx2(m_xBuilder->weld_check_button("cbx2"))
+ , m_xQSet2(new MaskSet(this))
+ , m_xQSetWin2(new weld::CustomWeld(*m_xBuilder, "qset2", *m_xQSet2))
+ , m_xSp2(m_xBuilder->weld_metric_spin_button("tol2", FieldUnit::PERCENT))
+ , m_xLbColor2(new ColorListBox(m_xBuilder->weld_menu_button("color2"), [this]{ return GetFrameWeld(); }))
+ , m_xCbx3(m_xBuilder->weld_check_button("cbx3"))
+ , m_xQSet3(new MaskSet(this))
+ , m_xQSetWin3(new weld::CustomWeld(*m_xBuilder, "qset3", *m_xQSet3))
+ , m_xSp3(m_xBuilder->weld_metric_spin_button("tol3", FieldUnit::PERCENT))
+ , m_xLbColor3(new ColorListBox(m_xBuilder->weld_menu_button("color3"), [this]{ return GetFrameWeld(); }))
+ , m_xCbx4(m_xBuilder->weld_check_button("cbx4"))
+ , m_xQSet4(new MaskSet(this))
+ , m_xQSetWin4(new weld::CustomWeld(*m_xBuilder, "qset4", *m_xQSet4))
+ , m_xSp4(m_xBuilder->weld_metric_spin_button("tol4", FieldUnit::PERCENT))
+ , m_xLbColor4(new ColorListBox(m_xBuilder->weld_menu_button("color4"), [this]{ return GetFrameWeld(); }))
+ , m_xCbxTrans(m_xBuilder->weld_check_button("cbx5"))
+ , m_xLbColorTrans(new ColorListBox(m_xBuilder->weld_menu_button("color5"), [this]{ return GetFrameWeld(); }))
+ , m_xData(new MaskData(this, *pBindinx))
+ , aPipetteColor(COL_WHITE)
+ , aSelItem(*this, *pBindinx)
+{
+ SetText(SvxResId(RID_SVXDLG_BMPMASK_STR_TITLE));
+
+ m_xLbColor1->SetSlotId(SID_BMPMASK_COLOR);
+ m_xLbColor2->SetSlotId(SID_BMPMASK_COLOR);
+ m_xLbColor3->SetSlotId(SID_BMPMASK_COLOR);
+ m_xLbColor4->SetSlotId(SID_BMPMASK_COLOR);
+
+ m_xLbColorTrans->SelectEntry(COL_BLACK);
+ m_xLbColor1->SelectEntry(COL_TRANSPARENT);
+ m_xLbColor2->SelectEntry(COL_TRANSPARENT);
+ m_xLbColor3->SelectEntry(COL_TRANSPARENT);
+ m_xLbColor4->SelectEntry(COL_TRANSPARENT);
+
+ m_xTbxPipette->connect_clicked( LINK( m_xData.get(), MaskData, PipetteHdl ) );
+ m_xBtnExec->connect_clicked( LINK( m_xData.get(), MaskData, ExecHdl ) );
+
+ m_xCbx1->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
+ m_xCbx2->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
+ m_xCbx3->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
+ m_xCbx4->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
+ m_xCbxTrans->connect_toggled( LINK( m_xData.get(), MaskData, CbxTransHdl ) );
+
+ SetAccessibleNames ();
+
+ m_xLbColor1->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
+ m_xLbColor2->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
+ m_xLbColor3->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
+ m_xLbColor4->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
+ m_xLbColorTrans->set_sensitive(false);
+
+ OUString sColorPalette (SvxResId( RID_SVXDLG_BMPMASK_STR_PALETTE));
+ OUString sColorPaletteN;
+
+ m_xQSet1->SetStyle( m_xQSet1->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
+ m_xQSet1->SetColCount();
+ m_xQSet1->SetLineCount( 1 );
+ sColorPaletteN = sColorPalette + " 1";
+ m_xQSet1->InsertItem( 1, aPipetteColor, sColorPaletteN);
+ m_xQSet1->SelectItem( 1 );
+
+ m_xQSet2->SetStyle( m_xQSet2->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
+ m_xQSet2->SetColCount();
+ m_xQSet2->SetLineCount( 1 );
+ sColorPaletteN = sColorPalette + " 2";
+ m_xQSet2->InsertItem( 1, aPipetteColor, sColorPaletteN);
+ m_xQSet2->SelectItem( 0 );
+
+ m_xQSet3->SetStyle( m_xQSet3->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
+ m_xQSet3->SetColCount();
+ m_xQSet3->SetLineCount( 1 );
+ sColorPaletteN = sColorPalette + " 3";
+ m_xQSet3->InsertItem( 1, aPipetteColor, sColorPaletteN);
+ m_xQSet3->SelectItem( 0 );
+
+ m_xQSet4->SetStyle( m_xQSet4->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
+ m_xQSet4->SetColCount();
+ m_xQSet4->SetLineCount( 1 );
+ sColorPaletteN = sColorPalette + " 4";
+ m_xQSet4->InsertItem( 1, aPipetteColor, sColorPaletteN);
+ m_xQSet4->SelectItem( 0 );
+
+ m_xQSet1->Show();
+ m_xQSet2->Show();
+ m_xQSet3->Show();
+ m_xQSet4->Show();
+}
+
+SvxBmpMask::~SvxBmpMask()
+{
+ disposeOnce();
+}
+
+void SvxBmpMask::dispose()
+{
+ m_xQSetWin1.reset();
+ m_xQSet1.reset();
+ m_xQSetWin2.reset();
+ m_xQSet2.reset();
+ m_xQSetWin3.reset();
+ m_xQSet3.reset();
+ m_xQSetWin4.reset();
+ m_xQSet4.reset();
+ m_xCtlPipetteWin.reset();
+ m_xCtlPipette.reset();
+ m_xData.reset();
+ m_xTbxPipette.reset();
+ m_xBtnExec.reset();
+ m_xCbx1.reset();
+ m_xSp1.reset();
+ m_xLbColor1.reset();
+ m_xCbx2.reset();
+ m_xSp2.reset();
+ m_xLbColor2.reset();
+ m_xCbx3.reset();
+ m_xSp3.reset();
+ m_xLbColor3.reset();
+ m_xCbx4.reset();
+ m_xSp4.reset();
+ m_xLbColor4.reset();
+ m_xCbxTrans.reset();
+ m_xLbColorTrans.reset();
+ aSelItem.dispose();
+ SfxDockingWindow::dispose();
+}
+
+/** is called by a MaskSet when it is selected */
+void SvxBmpMask::onSelect( const MaskSet* pSet )
+{
+ // now deselect all other value sets
+ if( pSet != m_xQSet1.get() )
+ m_xQSet1->SelectItem( 0 );
+
+ if( pSet != m_xQSet2.get() )
+ m_xQSet2->SelectItem( 0 );
+
+ if( pSet != m_xQSet3.get() )
+ m_xQSet3->SelectItem( 0 );
+
+ if( pSet != m_xQSet4.get() )
+ m_xQSet4->SelectItem( 0 );
+}
+
+bool SvxBmpMask::Close()
+{
+ SfxBoolItem aItem2( SID_BMPMASK_PIPETTE, false );
+ GetBindings().GetDispatcher()->ExecuteList(SID_BMPMASK_PIPETTE,
+ OWN_CALLMODE, { &aItem2 });
+
+ return SfxDockingWindow::Close();
+}
+
+void SvxBmpMask::SetColor( const Color& rColor )
+{
+ aPipetteColor = rColor;
+ m_xCtlPipette->SetColor( aPipetteColor );
+}
+
+void SvxBmpMask::PipetteClicked()
+{
+ if( m_xQSet1->GetSelectedItemId() == 1 )
+ {
+ m_xCbx1->set_active(true);
+ m_xData->CbxHdl(*m_xCbx1);
+ m_xQSet1->SetItemColor( 1, aPipetteColor );
+ m_xQSet1->SetFormat();
+ }
+ else if( m_xQSet2->GetSelectedItemId() == 1 )
+ {
+ m_xCbx2->set_active(true);
+ m_xData->CbxHdl(*m_xCbx2);
+ m_xQSet2->SetItemColor( 1, aPipetteColor );
+ m_xQSet2->SetFormat();
+ }
+ else if( m_xQSet3->GetSelectedItemId() == 1 )
+ {
+ m_xCbx3->set_active(true);
+ m_xData->CbxHdl(*m_xCbx3);
+ m_xQSet3->SetItemColor( 1, aPipetteColor );
+ m_xQSet3->SetFormat();
+ }
+ else if( m_xQSet4->GetSelectedItemId() == 1 )
+ {
+ m_xCbx4->set_active(true);
+ m_xData->CbxHdl(*m_xCbx4);
+ m_xQSet4->SetItemColor( 1, aPipetteColor );
+ m_xQSet4->SetFormat();
+ }
+
+ m_xTbxPipette->set_item_active("pipette", false);
+ m_xData->PipetteHdl("pipette");
+}
+
+void SvxBmpMask::SetExecState( bool bEnable )
+{
+ m_xData->SetExecState( bEnable );
+
+ if ( m_xData->IsExecReady() && m_xData->IsCbxReady() )
+ m_xBtnExec->set_sensitive(true);
+ else
+ m_xBtnExec->set_sensitive(false);
+}
+
+
+sal_uInt16 SvxBmpMask::InitColorArrays( Color* pSrcCols, Color* pDstCols, sal_uInt8* pTols )
+{
+ sal_uInt16 nCount = 0;
+
+ if ( m_xCbx1->get_active() )
+ {
+ pSrcCols[nCount] = m_xQSet1->GetItemColor( 1 );
+ pDstCols[nCount] = m_xLbColor1->GetSelectEntryColor();
+ pTols[nCount++] = static_cast<sal_uInt8>(m_xSp1->get_value(FieldUnit::PERCENT));
+ }
+
+ if ( m_xCbx2->get_active() )
+ {
+ pSrcCols[nCount] = m_xQSet2->GetItemColor( 1 );
+ pDstCols[nCount] = m_xLbColor2->GetSelectEntryColor();
+ pTols[nCount++] = static_cast<sal_uInt8>(m_xSp2->get_value(FieldUnit::PERCENT));
+ }
+
+ if ( m_xCbx3->get_active() )
+ {
+ pSrcCols[nCount] = m_xQSet3->GetItemColor( 1 );
+ pDstCols[nCount] = m_xLbColor3->GetSelectEntryColor();
+ pTols[nCount++] = static_cast<sal_uInt8>(m_xSp3->get_value(FieldUnit::PERCENT));
+ }
+
+ if ( m_xCbx4->get_active() )
+ {
+ pSrcCols[nCount] = m_xQSet4->GetItemColor( 1 );
+ pDstCols[nCount] = m_xLbColor4->GetSelectEntryColor();
+ pTols[nCount++] = static_cast<sal_uInt8>(m_xSp4->get_value(FieldUnit::PERCENT));
+ }
+
+ return nCount;
+}
+
+void SvxBmpMask::ImpMask( BitmapEx& rBitmap )
+{
+ Color pSrcCols[4];
+ Color pDstCols[4];
+ sal_uInt8 pTols[4];
+ const sal_uInt16 nCount = InitColorArrays( pSrcCols, pDstCols, pTols );
+
+ EnterWait();
+ rBitmap.Replace( pSrcCols, pDstCols, nCount, pTols );
+ LeaveWait();
+}
+
+BitmapEx SvxBmpMask::ImpMaskTransparent( const BitmapEx& rBitmapEx, const Color& rColor, const sal_uInt8 nTol )
+{
+ EnterWait();
+
+ BitmapEx aBmpEx;
+ Bitmap aMask( rBitmapEx.GetBitmap().CreateMask( rColor, nTol ) );
+
+ if( rBitmapEx.IsAlpha() )
+ aMask.CombineOr( rBitmapEx.GetAlpha() );
+
+ aBmpEx = BitmapEx( rBitmapEx.GetBitmap(), aMask );
+ LeaveWait();
+
+ return aBmpEx;
+}
+
+
+Animation SvxBmpMask::ImpMask( const Animation& rAnimation )
+{
+ Animation aAnimation( rAnimation );
+ Color pSrcCols[4];
+ Color pDstCols[4];
+ sal_uInt8 pTols[4];
+ InitColorArrays( pSrcCols, pDstCols, pTols );
+ sal_uInt16 nAnimationCount = aAnimation.Count();
+
+ for( sal_uInt16 i = 0; i < nAnimationCount; i++ )
+ {
+ AnimationBitmap aAnimationBitmap( aAnimation.Get( i ) );
+ aAnimationBitmap.maBitmapEx = Mask(aAnimationBitmap.maBitmapEx).GetBitmapEx();
+ aAnimation.Replace(aAnimationBitmap, i);
+ }
+
+ return aAnimation;
+}
+
+
+GDIMetaFile SvxBmpMask::ImpMask( const GDIMetaFile& rMtf )
+{
+ GDIMetaFile aMtf;
+ Color pSrcCols[4];
+ Color pDstCols[4];
+ sal_uInt8 pTols[4];
+ sal_uInt16 nCount = InitColorArrays( pSrcCols, pDstCols, pTols );
+
+ // If no color is selected, we copy only the Mtf
+ if( !nCount )
+ aMtf = rMtf;
+ else
+ {
+ bool pTrans[4];
+ Color aCol;
+ tools::Long nR;
+ tools::Long nG;
+ tools::Long nB;
+ std::unique_ptr<tools::Long[]> pMinR(new tools::Long[nCount]);
+ std::unique_ptr<tools::Long[]> pMaxR(new tools::Long[nCount]);
+ std::unique_ptr<tools::Long[]> pMinG(new tools::Long[nCount]);
+ std::unique_ptr<tools::Long[]> pMaxG(new tools::Long[nCount]);
+ std::unique_ptr<tools::Long[]> pMinB(new tools::Long[nCount]);
+ std::unique_ptr<tools::Long[]> pMaxB(new tools::Long[nCount]);
+ sal_uInt16 i;
+
+ aMtf.SetPrefSize( rMtf.GetPrefSize() );
+ aMtf.SetPrefMapMode( rMtf.GetPrefMapMode() );
+
+ // Prepare Color comparison array
+ for( i = 0; i < nCount; i++ )
+ {
+ tools::Long nTol = ( pTols[i] * 255 ) / 100;
+
+ tools::Long nVal = static_cast<tools::Long>(pSrcCols[i].GetRed());
+ pMinR[i] = std::max( nVal - nTol, tools::Long(0) );
+ pMaxR[i] = std::min( nVal + nTol, tools::Long(255) );
+
+ nVal = static_cast<tools::Long>(pSrcCols[i].GetGreen());
+ pMinG[i] = std::max( nVal - nTol, tools::Long(0) );
+ pMaxG[i] = std::min( nVal + nTol, tools::Long(255) );
+
+ nVal = static_cast<tools::Long>(pSrcCols[i].GetBlue());
+ pMinB[i] = std::max( nVal - nTol, tools::Long(0) );
+ pMaxB[i] = std::min( nVal + nTol, tools::Long(255) );
+
+ pTrans[ i ] = (pDstCols[ i ] == COL_TRANSPARENT);
+ }
+
+ // Investigate actions and if necessary replace colors
+ for( size_t nAct = 0, nActCount = rMtf.GetActionSize(); nAct < nActCount; nAct++ )
+ {
+ MetaAction* pAction = rMtf.GetAction( nAct );
+
+ bool bReplace = false;
+
+ switch( pAction->GetType() )
+ {
+ case MetaActionType::PIXEL:
+ {
+ MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction);
+
+ aCol = pAct->GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ pAct = new MetaPixelAction( pAct->GetPoint(), aCol );
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::LINECOLOR:
+ {
+ MetaLineColorAction* pAct = static_cast<MetaLineColorAction*>(pAction);
+
+ aCol = pAct->GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ pAct = new MetaLineColorAction( aCol, !pTrans[ i ] );
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::FILLCOLOR:
+ {
+ MetaFillColorAction* pAct = static_cast<MetaFillColorAction*>(pAction);
+
+ aCol = pAct->GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ pAct = new MetaFillColorAction( aCol, !pTrans[ i ] );
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::TEXTCOLOR:
+ {
+ MetaTextColorAction* pAct = static_cast<MetaTextColorAction*>(pAction);
+
+ aCol = pAct->GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ pAct = new MetaTextColorAction( aCol );
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::TEXTFILLCOLOR:
+ {
+ MetaTextFillColorAction* pAct = static_cast<MetaTextFillColorAction*>(pAction);
+
+ aCol = pAct->GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ pAct = new MetaTextFillColorAction( aCol, !pTrans[ i ] );
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::FONT:
+ {
+ MetaFontAction* pAct = static_cast<MetaFontAction*>(pAction);
+ vcl::Font aFont( pAct->GetFont() );
+
+ aCol = aFont.GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ {
+ aFont.SetColor( aCol );
+ pAct = new MetaFontAction( aFont );
+ }
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::WALLPAPER:
+ {
+ MetaWallpaperAction* pAct = static_cast<MetaWallpaperAction*>(pAction);
+ Wallpaper aWall( pAct->GetWallpaper() );
+
+ aCol = aWall.GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ {
+ aWall.SetColor( aCol );
+ pAct = new MetaWallpaperAction( pAct->GetRect(), aWall );
+ }
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMP:
+ {
+ MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pAction);
+ const Bitmap aBmp( Mask(BitmapEx(pAct->GetBitmap())).GetBitmapEx().GetBitmap() );
+
+ pAct = new MetaBmpAction( pAct->GetPoint(), aBmp );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMPSCALE:
+ {
+ MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
+ const Bitmap aBmp( Mask(BitmapEx(pAct->GetBitmap())).GetBitmapEx().GetBitmap() );
+
+ pAct = new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(), aBmp );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMPSCALEPART:
+ {
+ MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
+ const Bitmap aBmp( Mask(BitmapEx(pAct->GetBitmap())).GetBitmapEx().GetBitmap() );
+
+ pAct = new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
+ pAct->GetSrcPoint(), pAct->GetSrcSize(), aBmp );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMPEX:
+ {
+ MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pAction);
+ const BitmapEx aBmpEx( Mask( pAct->GetBitmapEx() ).GetBitmapEx() );
+
+ pAct = new MetaBmpExAction( pAct->GetPoint(), aBmpEx );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMPEXSCALE:
+ {
+ MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
+ const BitmapEx aBmpEx( Mask( pAct->GetBitmapEx() ).GetBitmapEx() );
+
+ pAct = new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(), aBmpEx );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMPEXSCALEPART:
+ {
+ MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
+ const BitmapEx aBmpEx( Mask( pAct->GetBitmapEx() ).GetBitmapEx() );
+
+ pAct = new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
+ pAct->GetSrcPoint(), pAct->GetSrcSize(), aBmpEx );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ default:
+ {
+ aMtf.AddAction( pAction );
+ }
+ break;
+ }
+ }
+ }
+
+ LeaveWait();
+
+ return aMtf;
+}
+
+
+Animation SvxBmpMask::ImpReplaceTransparency( const Animation& rAnim, const Color& rColor )
+{
+ Animation aAnimation( rAnim );
+ sal_uInt16 nAnimationCount = aAnimation.Count();
+
+ for( sal_uInt16 i = 0; i < nAnimationCount; i++ )
+ {
+ AnimationBitmap aAnimationBitmap(aAnimation.Get(i));
+ aAnimationBitmap.maBitmapEx.ReplaceTransparency(rColor);
+ aAnimation.Replace(aAnimationBitmap, i);
+ }
+
+ return aAnimation;
+}
+
+
+GDIMetaFile SvxBmpMask::ImpReplaceTransparency( const GDIMetaFile& rMtf, const Color& rColor )
+{
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ GDIMetaFile aMtf;
+ const MapMode& rPrefMap = rMtf.GetPrefMapMode();
+ const Size& rPrefSize = rMtf.GetPrefSize();
+ const size_t nActionCount = rMtf.GetActionSize();
+
+ pVDev->EnableOutput( false );
+ aMtf.Record( pVDev );
+ aMtf.SetPrefSize( rPrefSize );
+ aMtf.SetPrefMapMode( rPrefMap );
+ pVDev->SetLineColor( rColor );
+ pVDev->SetFillColor( rColor );
+
+ // retrieve one action at the time; first
+ // set the whole area to the replacement color.
+ pVDev->DrawRect( tools::Rectangle( rPrefMap.GetOrigin(), rPrefSize ) );
+ for ( size_t i = 0; i < nActionCount; i++ )
+ {
+ MetaAction* pAct = rMtf.GetAction( i );
+ aMtf.AddAction( pAct );
+ }
+
+ aMtf.Stop();
+ aMtf.WindStart();
+
+ return aMtf;
+}
+
+GDIMetaFile SvxBmpMask::GetMetaFile(const Graphic& rGraphic)
+{
+ // Replace transparency?
+ if (m_xCbxTrans->get_active())
+ return ImpReplaceTransparency(rGraphic.GetGDIMetaFile(), m_xLbColorTrans->GetSelectEntryColor());
+ return ImpMask(rGraphic.GetGDIMetaFile());
+}
+
+Graphic SvxBmpMask::Mask( const Graphic& rGraphic )
+{
+ Graphic aGraphic( rGraphic );
+ const Color aReplColor( m_xLbColorTrans->GetSelectEntryColor() );
+
+ switch( rGraphic.GetType() )
+ {
+ case GraphicType::Bitmap:
+ {
+ if( rGraphic.IsAnimated() )
+ {
+ // Replace transparency?
+ if ( m_xCbxTrans->get_active() )
+ aGraphic = ImpReplaceTransparency( rGraphic.GetAnimation(), aReplColor );
+ else
+ aGraphic = ImpMask( rGraphic.GetAnimation() );
+ }
+ else
+ {
+ // Replace transparency?
+ if( m_xCbxTrans->get_active() )
+ {
+ BitmapEx aBmpEx = aGraphic.GetBitmapEx();
+ aBmpEx.ReplaceTransparency(aReplColor);
+ aGraphic = aBmpEx;
+ }
+ else
+ {
+ Color pSrcCols[4];
+ Color pDstCols[4];
+ sal_uInt8 pTols[4];
+ sal_uInt16 nCount = InitColorArrays( pSrcCols, pDstCols, pTols );
+
+ if( nCount )
+ {
+ // first set all transparent colors
+ for( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ // Do we have a transparent color?
+ if (pDstCols[i] == COL_TRANSPARENT)
+ {
+ BitmapEx aBmpEx( ImpMaskTransparent( aGraphic.GetBitmapEx(),
+ pSrcCols[ i ], pTols[ i ] ) );
+ const Size aSize( aBmpEx.GetSizePixel() );
+
+ if( aSize.Width() && aSize.Height() )
+ aGraphic = aBmpEx;
+ }
+ }
+
+ // now replace it again with the normal colors
+ BitmapEx aBitmapEx( aGraphic.GetBitmapEx() );
+ if ( aBitmapEx.GetSizePixel().Width() && aBitmapEx.GetSizePixel().Height() )
+ {
+ ImpMask( aBitmapEx );
+ if ( aGraphic.IsTransparent() )
+ aGraphic = Graphic( BitmapEx( aBitmapEx.GetBitmap(), aBitmapEx.GetAlpha() ) );
+ else
+ aGraphic = aBitmapEx;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case GraphicType::GdiMetafile:
+ {
+ GDIMetaFile aMtf(GetMetaFile(rGraphic));
+ Size aSize( aMtf.GetPrefSize() );
+ if ( aSize.Width() && aSize.Height() )
+ aGraphic = Graphic( aMtf );
+ else
+ aGraphic = rGraphic;
+ }
+ break;
+
+ default:
+ aGraphic = rGraphic;
+ break;
+ }
+
+ if( aGraphic != rGraphic )
+ {
+ aGraphic.SetPrefSize( rGraphic.GetPrefSize() );
+ aGraphic.SetPrefMapMode( rGraphic.GetPrefMapMode() );
+ }
+
+ return aGraphic;
+}
+
+bool SvxBmpMask::IsEyedropping() const
+{
+ return m_xTbxPipette->get_item_active("pipette");
+}
+
+/** Set an accessible name for the source color check boxes. Without this
+ the lengthy description is read.
+*/
+void SvxBmpMask::SetAccessibleNames()
+{
+ // set the accessible name for valueset
+ OUString sColorPalette (SvxResId( RID_SVXDLG_BMPMASK_STR_PALETTE));
+ OUString sColorPaletteN;
+
+ sColorPaletteN = sColorPalette + " 1";
+ m_xQSet1->SetText (sColorPaletteN);
+ sColorPaletteN = sColorPalette + " 2";
+ m_xQSet2->SetText (sColorPaletteN);
+ sColorPaletteN = sColorPalette + " 3";
+ m_xQSet3->SetText (sColorPaletteN);
+ sColorPaletteN = sColorPalette + " 4";
+ m_xQSet4->SetText (sColorPaletteN);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/_contdlg.cxx b/svx/source/dialog/_contdlg.cxx
new file mode 100644
index 000000000..fbd6f40bc
--- /dev/null
+++ b/svx/source/dialog/_contdlg.cxx
@@ -0,0 +1,675 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <tools/helpers.hxx>
+#include <svl/eitem.hxx>
+#include <sfx2/ctrlitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <unotools/localedatawrapper.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/contdlg.hxx>
+#include "contimp.hxx"
+#include "contwnd.hxx"
+#include <svx/svdopath.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include "dlgunit.hxx"
+#include <vcl/weld.hxx>
+
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(SvxContourDlgChildWindow, SID_CONTOUR_DLG);
+
+SvxContourDlgItem::SvxContourDlgItem( SvxSuperContourDlg& rContourDlg, SfxBindings& rBindings ) :
+ SfxControllerItem ( SID_CONTOUR_EXEC, rBindings ),
+ rDlg ( rContourDlg )
+{
+}
+
+void SvxContourDlgItem::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState /*eState*/, const SfxPoolItem* pItem )
+{
+ if ( pItem && ( SID_CONTOUR_EXEC == nSID ) )
+ {
+ const SfxBoolItem* pStateItem = dynamic_cast<const SfxBoolItem*>( pItem );
+ assert(pStateItem); //SfxBoolItem expected
+ if (pStateItem)
+ rDlg.SetExecState(!pStateItem->GetValue());
+ }
+}
+
+SvxContourDlgChildWindow::SvxContourDlgChildWindow(vcl::Window* _pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo const * pInfo)
+ : SfxChildWindow( _pParent, nId )
+{
+ SetController(std::make_shared<SvxContourDlg>(pBindings, this, _pParent->GetFrameWeld()));
+ SvxContourDlg* pDlg = static_cast<SvxContourDlg*>(GetController().get());
+ pDlg->Initialize( pInfo );
+}
+
+SvxContourDlg::SvxContourDlg(SfxBindings* _pBindings, SfxChildWindow* pCW,
+ weld::Window* _pParent)
+ : SfxModelessDialogController(_pBindings, pCW, _pParent, "svx/ui/floatingcontour.ui", "FloatingContour")
+ , m_xImpl(std::make_unique<SvxSuperContourDlg>(*m_xBuilder, *m_xDialog, _pBindings))
+{
+}
+
+SvxContourDlg::~SvxContourDlg()
+{
+}
+
+tools::PolyPolygon SvxContourDlg::CreateAutoContour( const Graphic& rGraphic,
+ const tools::Rectangle* pRect )
+{
+ Bitmap aBmp;
+ bool bContourEdgeDetect = false;
+
+ if ( rGraphic.GetType() == GraphicType::Bitmap )
+ {
+ if( rGraphic.IsAnimated() )
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ MapMode aTransMap;
+ const Animation aAnim( rGraphic.GetAnimation() );
+ const Size& rSizePix = aAnim.GetDisplaySizePixel();
+ const sal_uInt16 nCount = aAnim.Count();
+
+ if ( pVDev->SetOutputSizePixel( rSizePix ) )
+ {
+ pVDev->SetLineColor( COL_BLACK );
+ pVDev->SetFillColor( COL_BLACK );
+
+ for( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ const AnimationBitmap& rStepBmp = aAnim.Get( i );
+
+ // Push Polygon output to the right place; this is the
+ // offset of the sub-image within the total animation
+ aTransMap.SetOrigin( Point( rStepBmp.maPositionPixel.X(), rStepBmp.maPositionPixel.Y() ) );
+ pVDev->SetMapMode( aTransMap );
+ pVDev->DrawPolyPolygon( CreateAutoContour( rStepBmp.maBitmapEx, pRect ) );
+ }
+
+ aTransMap.SetOrigin( Point() );
+ pVDev->SetMapMode( aTransMap );
+ aBmp = pVDev->GetBitmap( Point(), rSizePix );
+ aBmp.Convert( BmpConversion::N1BitThreshold );
+ }
+ }
+ else if( rGraphic.IsTransparent() )
+ aBmp = rGraphic.GetBitmapEx().GetAlpha();
+ else
+ {
+ aBmp = rGraphic.GetBitmapEx().GetBitmap();
+ bContourEdgeDetect = true;
+ }
+ }
+ else if( rGraphic.GetType() != GraphicType::NONE )
+ {
+ const Graphic aTmpGrf( rGraphic.GetGDIMetaFile().GetMonochromeMtf( COL_BLACK ) );
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Size aSizePix( pVDev->LogicToPixel( aTmpGrf.GetPrefSize(), aTmpGrf.GetPrefMapMode() ) );
+
+ if( aSizePix.Width() && aSizePix.Height() && ( aSizePix.Width() > 512 || aSizePix.Height() > 512 ) )
+ {
+ double fWH = static_cast<double>(aSizePix.Width()) / aSizePix.Height();
+
+ if( fWH <= 1.0 )
+ {
+ aSizePix.setHeight(512);
+ aSizePix.setWidth( FRound( ( aSizePix.Height() ) * fWH ) );
+ }
+ else
+ {
+ aSizePix.setWidth(512);
+ aSizePix.setHeight( FRound( ( aSizePix.Width() ) / fWH ) );
+ }
+ }
+
+ if( pVDev->SetOutputSizePixel( aSizePix ) )
+ {
+ const Point aPt;
+ aTmpGrf.Draw(*pVDev, aPt, aSizePix);
+ aBmp = pVDev->GetBitmap( aPt, aSizePix );
+ }
+
+ bContourEdgeDetect = true;
+ }
+
+ aBmp.SetPrefSize( rGraphic.GetPrefSize() );
+ aBmp.SetPrefMapMode( rGraphic.GetPrefMapMode() );
+
+ return tools::PolyPolygon( BitmapEx(aBmp).GetContour( bContourEdgeDetect, pRect ) );
+}
+
+// Loop through to super class, no virtual Methods to not become incompatible
+// due to IF changes
+
+const Graphic& SvxContourDlg::GetGraphic() const
+{
+ return m_xImpl->GetGraphic();
+}
+
+bool SvxContourDlg::IsGraphicChanged() const
+{
+ return m_xImpl->IsGraphicChanged();
+}
+
+tools::PolyPolygon SvxContourDlg::GetPolyPolygon()
+{
+ return m_xImpl->GetPolyPolygon();
+}
+
+const void* SvxContourDlg::GetEditingObject() const
+{
+ return m_xImpl->GetEditingObject();
+}
+
+void SvxContourDlg::Update( const Graphic& rGraphic, bool bGraphicLinked,
+ const tools::PolyPolygon* pPolyPoly, void* pEditingObj )
+{
+ m_xImpl->UpdateGraphic( rGraphic, bGraphicLinked, pPolyPoly, pEditingObj );
+}
+
+SvxSuperContourDlg::SvxSuperContourDlg(weld::Builder& rBuilder,
+ weld::Dialog& rDialog, SfxBindings* pBindings)
+ : aUpdateIdle( "SvxSuperContourDlg UpdateIdle" )
+ , aCreateIdle( "SvxSuperContourDlg CreateIdle" )
+ , mpBindings(pBindings)
+ , pUpdateEditingObject( nullptr )
+ , pCheckObj( nullptr )
+ , aContourItem( *this, *pBindings )
+ , mnGrfChanged( 0 )
+ , bExecState( false )
+ , bUpdateGraphicLinked( false )
+ , bGraphicLinked( false )
+ , m_rDialog(rDialog)
+ , m_xContourWnd(new ContourWindow(&rDialog))
+ , m_xStbStatusColor(new StatusColor(*m_xContourWnd))
+ , m_xTbx1(rBuilder.weld_toolbar("toolbar"))
+ , m_xMtfTolerance(rBuilder.weld_metric_spin_button("spinbutton", FieldUnit::PERCENT))
+ , m_xStbStatus2(rBuilder.weld_label("statuspos"))
+ , m_xStbStatus3(rBuilder.weld_label("statussize"))
+ , m_xCancelBtn(rBuilder.weld_button("cancel"))
+ , m_xStbStatusColorWeld(new weld::CustomWeld(rBuilder, "statuscolor", *m_xStbStatusColor))
+ , m_xContourWndWeld(new weld::CustomWeld(rBuilder, "container", *m_xContourWnd))
+{
+ m_xCancelBtn->connect_clicked(LINK(this, SvxSuperContourDlg, CancelHdl));
+
+ m_xContourWnd->SetMousePosLink( LINK( this, SvxSuperContourDlg, MousePosHdl ) );
+ m_xContourWnd->SetGraphSizeLink( LINK( this, SvxSuperContourDlg, GraphSizeHdl ) );
+ m_xContourWnd->SetUpdateLink( LINK( this, SvxSuperContourDlg, StateHdl ) );
+ m_xContourWnd->SetPipetteHdl( LINK( this, SvxSuperContourDlg, PipetteHdl ) );
+ m_xContourWnd->SetPipetteClickHdl( LINK( this, SvxSuperContourDlg, PipetteClickHdl ) );
+ m_xContourWnd->SetWorkplaceClickHdl( LINK( this, SvxSuperContourDlg, WorkplaceClickHdl ) );
+
+ m_xTbx1->connect_clicked( LINK( this, SvxSuperContourDlg, Tbx1ClickHdl ) );
+
+ m_xMtfTolerance->set_value(10, FieldUnit::PERCENT);
+
+ aUpdateIdle.SetInvokeHandler( LINK( this, SvxSuperContourDlg, UpdateHdl ) );
+
+ aCreateIdle.SetPriority( TaskPriority::RESIZE );
+ aCreateIdle.SetInvokeHandler( LINK( this, SvxSuperContourDlg, CreateHdl ) );
+}
+
+SvxSuperContourDlg::~SvxSuperContourDlg()
+{
+ m_xContourWnd->SetUpdateLink( Link<GraphCtrl*,void>() );
+ m_xContourWnd.reset();
+}
+
+IMPL_LINK_NOARG(SvxSuperContourDlg, CancelHdl, weld::Button&, void)
+{
+ bool bRet = true;
+
+ if (m_xTbx1->get_item_sensitive("TBI_APPLY"))
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/querysavecontchangesdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QuerySaveContourChangesDialog"));
+ const short nRet = xQBox->run();
+
+ if ( nRet == RET_YES )
+ {
+ SfxBoolItem aBoolItem( SID_CONTOUR_EXEC, true );
+ GetBindings().GetDispatcher()->ExecuteList(
+ SID_CONTOUR_EXEC, SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aBoolItem });
+ }
+ else if ( nRet == RET_CANCEL )
+ bRet = false;
+ }
+
+ if (bRet)
+ m_rDialog.response(RET_CANCEL);
+}
+
+// Enabled or disabled all Controls
+
+void SvxSuperContourDlg::SetExecState( bool bEnable )
+{
+ bExecState = bEnable;
+}
+
+void SvxSuperContourDlg::SetGraphic( const Graphic& rGraphic )
+{
+ aUndoGraphic = aRedoGraphic = Graphic();
+ aGraphic = rGraphic;
+ mnGrfChanged = 0;
+ m_xContourWnd->SetGraphic( aGraphic );
+}
+
+void SvxSuperContourDlg::SetPolyPolygon( const tools::PolyPolygon& rPolyPoly )
+{
+ DBG_ASSERT( m_xContourWnd->GetGraphic().GetType() != GraphicType::NONE, "Graphic must've been set first!" );
+
+ tools::PolyPolygon aPolyPoly( rPolyPoly );
+ const MapMode aMap100( MapUnit::Map100thMM );
+ const MapMode aGrfMap( aGraphic.GetPrefMapMode() );
+ OutputDevice* pOutDev = Application::GetDefaultDevice();
+ bool bPixelMap = aGrfMap.GetMapUnit() == MapUnit::MapPixel;
+
+ for ( sal_uInt16 j = 0, nPolyCount = aPolyPoly.Count(); j < nPolyCount; j++ )
+ {
+ tools::Polygon& rPoly = aPolyPoly[ j ];
+
+ for ( sal_uInt16 i = 0, nCount = rPoly.GetSize(); i < nCount; i++ )
+ {
+ Point& rPt = rPoly[ i ];
+
+ if ( !bPixelMap )
+ rPt = pOutDev->LogicToPixel( rPt, aGrfMap );
+
+ rPt = pOutDev->PixelToLogic( rPt, aMap100 );
+ }
+ }
+
+ m_xContourWnd->SetPolyPolygon( aPolyPoly );
+ m_xContourWnd->GetSdrModel()->SetChanged();
+}
+
+tools::PolyPolygon SvxSuperContourDlg::GetPolyPolygon()
+{
+ tools::PolyPolygon aRetPolyPoly( m_xContourWnd->GetPolyPolygon() );
+
+ const MapMode aMap100( MapUnit::Map100thMM );
+ const MapMode aGrfMap( aGraphic.GetPrefMapMode() );
+ OutputDevice* pOutDev = Application::GetDefaultDevice();
+ bool bPixelMap = aGrfMap.GetMapUnit() == MapUnit::MapPixel;
+
+ for ( sal_uInt16 j = 0, nPolyCount = aRetPolyPoly.Count(); j < nPolyCount; j++ )
+ {
+ tools::Polygon& rPoly = aRetPolyPoly[ j ];
+
+ for ( sal_uInt16 i = 0, nCount = rPoly.GetSize(); i < nCount; i++ )
+ {
+ Point& rPt = rPoly[ i ];
+
+ rPt = pOutDev->LogicToPixel( rPt, aMap100 );
+
+ if ( !bPixelMap )
+ rPt = pOutDev->PixelToLogic( rPt, aGrfMap );
+ }
+ }
+
+ return aRetPolyPoly;
+}
+
+void SvxSuperContourDlg::UpdateGraphic( const Graphic& rGraphic, bool _bGraphicLinked,
+ const tools::PolyPolygon* pPolyPoly, void* pEditingObj )
+{
+ aUpdateGraphic = rGraphic;
+ bUpdateGraphicLinked = _bGraphicLinked;
+ pUpdateEditingObject = pEditingObj;
+
+ if ( pPolyPoly )
+ aUpdatePolyPoly = *pPolyPoly;
+ else
+ aUpdatePolyPoly = tools::PolyPolygon();
+
+ aUpdateIdle.Start();
+}
+
+// Click handler for ToolBox
+
+IMPL_LINK(SvxSuperContourDlg, Tbx1ClickHdl, const OString&, rId, void)
+{
+ if (rId == "TBI_APPLY")
+ {
+ SfxBoolItem aBoolItem( SID_CONTOUR_EXEC, true );
+ GetBindings().GetDispatcher()->ExecuteList(
+ SID_CONTOUR_EXEC, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aBoolItem });
+ }
+ else if (rId == "TBI_WORKPLACE")
+ {
+ if (m_xTbx1->get_item_active("TBI_WORKPLACE"))
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/querydeletecontourdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QueryDeleteContourDialog"));
+
+ if (!m_xContourWnd->IsContourChanged() || (xQBox->run() == RET_YES))
+ m_xContourWnd->SetWorkplaceMode( true );
+ else
+ m_xTbx1->set_item_active("TBI_WORKPLACE", false);
+ }
+ else
+ m_xContourWnd->SetWorkplaceMode( false );
+ }
+ else if (rId == "TBI_SELECT")
+ {
+ SetActiveTool(rId);
+ m_xContourWnd->SetEditMode( true );
+ }
+ else if (rId == "TBI_RECT")
+ {
+ SetActiveTool(rId);
+ m_xContourWnd->SetObjKind( SdrObjKind::Rectangle );
+ }
+ else if (rId == "TBI_CIRCLE")
+ {
+ SetActiveTool(rId);
+ m_xContourWnd->SetObjKind( SdrObjKind::CircleOrEllipse );
+ }
+ else if (rId == "TBI_POLY")
+ {
+ SetActiveTool(rId);
+ m_xContourWnd->SetObjKind( SdrObjKind::Polygon );
+ }
+ else if (rId == "TBI_POLYEDIT")
+ {
+ m_xContourWnd->SetPolyEditMode(m_xTbx1->get_item_active("TBI_POLYEDIT") ? SID_BEZIER_MOVE : 0);
+ }
+ else if (rId == "TBI_POLYMOVE")
+ {
+ SetActivePoly(rId);
+ m_xContourWnd->SetPolyEditMode( SID_BEZIER_MOVE );
+ }
+ else if (rId == "TBI_POLYINSERT")
+ {
+ SetActivePoly(rId);
+ m_xContourWnd->SetPolyEditMode( SID_BEZIER_INSERT );
+ }
+ else if (rId == "TBI_POLYDELETE")
+ {
+ m_xContourWnd->GetSdrView()->DeleteMarkedPoints();
+ }
+ else if (rId == "TBI_UNDO")
+ {
+ mnGrfChanged = mnGrfChanged ? mnGrfChanged - 1 : 0;
+ aRedoGraphic = aGraphic;
+ aGraphic = aUndoGraphic;
+ aUndoGraphic = Graphic();
+ m_xContourWnd->SetGraphic( aGraphic, false );
+ }
+ else if (rId == "TBI_REDO")
+ {
+ mnGrfChanged++;
+ aUndoGraphic = aGraphic;
+ aGraphic = aRedoGraphic;
+ aRedoGraphic = Graphic();
+ m_xContourWnd->SetGraphic( aGraphic, false );
+ }
+ else if (rId == "TBI_AUTOCONTOUR")
+ {
+ aCreateIdle.Start();
+ }
+ else if (rId == "TBI_PIPETTE")
+ {
+ bool bPipette = m_xTbx1->get_item_active("TBI_PIPETTE");
+
+ if ( !bPipette )
+ m_xStbStatusColor->Invalidate();
+ else if ( bGraphicLinked )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/queryunlinkgraphicsdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QueryUnlinkGraphicsDialog"));
+
+ if (xQBox->run() != RET_YES)
+ {
+ bPipette = false;
+ m_xTbx1->set_item_active("TBI_PIPETTE", bPipette);
+ m_xStbStatusColor->Invalidate();
+ }
+ }
+
+ m_xContourWnd->SetPipetteMode( bPipette );
+ }
+ m_xContourWnd->QueueIdleUpdate();
+}
+
+void SvxSuperContourDlg::SetActiveTool(std::string_view rId)
+{
+ m_xTbx1->set_item_active("TBI_SELECT", rId == "TBI_SELECT");
+ m_xTbx1->set_item_active("TBI_RECT", rId == "TBI_RECT");
+ m_xTbx1->set_item_active("TBI_CIRCLE", rId == "TBI_CIRCLE");
+ m_xTbx1->set_item_active("TBI_POLY", rId == "TBI_POLY");
+}
+
+void SvxSuperContourDlg::SetActivePoly(std::string_view rId)
+{
+ m_xTbx1->set_item_active("TBI_POLYMOVE", rId == "TBI_POLYMOVE");
+ m_xTbx1->set_item_active("TBI_POLYINSERT", rId == "TBI_POLYINSERT");
+}
+
+IMPL_LINK( SvxSuperContourDlg, MousePosHdl, GraphCtrl*, pWnd, void )
+{
+ OUString aStr;
+ const FieldUnit eFieldUnit = GetBindings().GetDispatcher()->GetModule()->GetFieldUnit();
+ const Point& rMousePos = pWnd->GetMousePos();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ const sal_Unicode cSep = rLocaleWrapper.getNumDecimalSep()[0];
+
+ aStr = GetUnitString( rMousePos.X(), eFieldUnit, cSep )
+ + " / "
+ + GetUnitString( rMousePos.Y(), eFieldUnit, cSep );
+
+ m_xStbStatus2->set_label( aStr );
+}
+
+IMPL_LINK( SvxSuperContourDlg, GraphSizeHdl, GraphCtrl*, pWnd, void )
+{
+ OUString aStr;
+ const FieldUnit eFieldUnit = GetBindings().GetDispatcher()->GetModule()->GetFieldUnit();
+ const Size& rSize = pWnd->GetGraphicSize();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ const sal_Unicode cSep = rLocaleWrapper.getNumDecimalSep()[0];
+
+ aStr = GetUnitString( rSize.Width(), eFieldUnit, cSep )
+ + " x "
+ + GetUnitString( rSize.Height(), eFieldUnit, cSep );
+
+ m_xStbStatus3->set_label( aStr );
+}
+
+IMPL_LINK_NOARG(SvxSuperContourDlg, UpdateHdl, Timer *, void)
+{
+ aUpdateIdle.Stop();
+
+ if ( pUpdateEditingObject != pCheckObj )
+ {
+ if( !GetEditingObject() )
+ m_xContourWnd->GrabFocus();
+
+ SetGraphic( aUpdateGraphic );
+ SetPolyPolygon( aUpdatePolyPoly );
+ pCheckObj = pUpdateEditingObject;
+ bGraphicLinked = bUpdateGraphicLinked;
+
+ aUpdateGraphic = Graphic();
+ aUpdatePolyPoly = tools::PolyPolygon();
+ bUpdateGraphicLinked = false;
+
+ m_xContourWnd->GetSdrModel()->SetChanged( false );
+ }
+
+ GetBindings().Invalidate( SID_CONTOUR_EXEC );
+ m_xContourWnd->QueueIdleUpdate();
+}
+
+IMPL_LINK_NOARG(SvxSuperContourDlg, CreateHdl, Timer *, void)
+{
+ aCreateIdle.Stop();
+
+ const tools::Rectangle aWorkRect = m_xContourWnd->GetDrawingArea()->get_ref_device().LogicToPixel(
+ m_xContourWnd->GetWorkRect(), MapMode( MapUnit::Map100thMM));
+
+ const Graphic& rGraphic = m_xContourWnd->GetGraphic();
+ const bool bValid = aWorkRect.Left() != aWorkRect.Right() && aWorkRect.Top() != aWorkRect.Bottom();
+
+ weld::WaitObject aWaitObj(&m_rDialog);
+ SetPolyPolygon( SvxContourDlg::CreateAutoContour( rGraphic, bValid ? &aWorkRect : nullptr ) );
+}
+
+IMPL_LINK( SvxSuperContourDlg, StateHdl, GraphCtrl*, pWnd, void )
+{
+ const SdrObject* pObj = pWnd->GetSelectedSdrObject();
+ const SdrView* pView = pWnd->GetSdrView();
+ const bool bPolyEdit = ( pObj != nullptr ) && dynamic_cast<const SdrPathObj*>( pObj) != nullptr;
+ const bool bDrawEnabled = !(bPolyEdit && m_xTbx1->get_item_active("TBI_POLYEDIT"));
+ const bool bPipette = m_xTbx1->get_item_active("TBI_PIPETTE");
+ const bool bWorkplace = m_xTbx1->get_item_active("TBI_WORKPLACE");
+ const bool bDontHide = !( bPipette || bWorkplace );
+ const bool bBitmap = pWnd->GetGraphic().GetType() == GraphicType::Bitmap;
+
+ m_xTbx1->set_item_sensitive("TBI_APPLY", bDontHide && bExecState && pWnd->IsChanged());
+
+ m_xTbx1->set_item_sensitive("TBI_WORKPLACE", !bPipette && bDrawEnabled);
+
+ m_xTbx1->set_item_sensitive("TBI_SELECT", bDontHide && bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_RECT", bDontHide && bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_CIRCLE", bDontHide && bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_POLY", bDontHide && bDrawEnabled);
+
+ m_xTbx1->set_item_sensitive("TBI_POLYEDIT", bDontHide && bPolyEdit);
+ m_xTbx1->set_item_sensitive("TBI_POLYMOVE", bDontHide && !bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_POLYINSERT", bDontHide && !bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_POLYDELETE", bDontHide && !bDrawEnabled && pView->IsDeleteMarkedPointsPossible());
+
+ m_xTbx1->set_item_sensitive("TBI_AUTOCONTOUR", bDontHide && bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_PIPETTE", !bWorkplace && bDrawEnabled && bBitmap);
+
+ m_xTbx1->set_item_sensitive("TBI_UNDO", bDontHide && aUndoGraphic.GetType() != GraphicType::NONE);
+ m_xTbx1->set_item_sensitive("TBI_REDO", bDontHide && aRedoGraphic.GetType() != GraphicType::NONE);
+
+ if ( bPolyEdit )
+ {
+ switch( pWnd->GetPolyEditMode() )
+ {
+ case SID_BEZIER_MOVE:
+ SetActivePoly("TBI_POLYMOVE");
+ break;
+ case SID_BEZIER_INSERT:
+ SetActivePoly("TBI_POLYINSERT");
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ m_xTbx1->set_item_active("TBI_POLYEDIT", false);
+ SetActivePoly("TBI_POLYMOVE");
+ pWnd->SetPolyEditMode( 0 );
+ }
+}
+
+IMPL_LINK_NOARG(SvxSuperContourDlg, PipetteHdl, ContourWindow&, void)
+{
+ m_xStbStatusColor->Invalidate();
+}
+
+void StatusColor::Paint(vcl::RenderContext& rDevice, const tools::Rectangle&)
+{
+ const Color& rOldLineColor = rDevice.GetLineColor();
+ const Color& rOldFillColor = rDevice.GetFillColor();
+
+ tools::Rectangle aRect(Point(), GetOutputSizePixel());
+ const Color& rColor = m_rWnd.GetPipetteColor();
+
+ rDevice.SetLineColor(rColor);
+ rDevice.SetFillColor(rColor);
+
+ aRect.AdjustLeft(4 );
+ aRect.AdjustTop(4 );
+ aRect.AdjustRight( -4 );
+ aRect.AdjustBottom( -4 );
+
+ rDevice.DrawRect( aRect );
+
+ rDevice.SetLineColor(rOldLineColor);
+ rDevice.SetFillColor(rOldFillColor);
+}
+
+IMPL_LINK( SvxSuperContourDlg, PipetteClickHdl, ContourWindow&, rWnd, void )
+{
+ if ( rWnd.IsClickValid() )
+ {
+ const Color& rColor = rWnd.GetPipetteColor();
+
+ weld::WaitObject aWaitObj(&m_rDialog);
+
+ if( aGraphic.GetType() == GraphicType::Bitmap )
+ {
+ const tools::Long nTol = static_cast<tools::Long>(m_xMtfTolerance->get_value(FieldUnit::PERCENT) * 255 / 100);
+
+ Bitmap aMask = aGraphic.GetBitmapEx().GetBitmap().CreateMask( rColor, nTol );
+
+ if( aGraphic.IsTransparent() )
+ aMask.CombineOr( aGraphic.GetBitmapEx().GetAlpha() );
+
+ if( !aMask.IsEmpty() )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/querynewcontourdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QueryNewContourDialog"));
+
+ bool bNewContour;
+
+ aRedoGraphic = Graphic();
+ aUndoGraphic = aGraphic;
+ Bitmap aBmp = aGraphic.GetBitmapEx().GetBitmap();
+ aGraphic = Graphic( BitmapEx( aBmp, aMask ) );
+ mnGrfChanged++;
+
+ bNewContour = (xQBox->run() == RET_YES);
+ rWnd.SetGraphic( aGraphic, bNewContour );
+
+ if( bNewContour )
+ aCreateIdle.Start();
+ }
+ }
+ }
+
+ m_xTbx1->set_item_active("TBI_PIPETTE", false);
+ rWnd.SetPipetteMode( false );
+ m_xStbStatusColor->Invalidate();
+}
+
+IMPL_LINK( SvxSuperContourDlg, WorkplaceClickHdl, ContourWindow&, rWnd, void )
+{
+ m_xTbx1->set_item_active("TBI_WORKPLACE", false);
+ m_xTbx1->set_item_active("TBI_SELECT", true);
+ rWnd.SetWorkplaceMode( false );
+
+ m_xContourWnd->QueueIdleUpdate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/charmap.cxx b/svx/source/dialog/charmap.cxx
new file mode 100644
index 000000000..4d8dd07b5
--- /dev/null
+++ b/svx/source/dialog/charmap.cxx
@@ -0,0 +1,1938 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_wasm_strip.h>
+
+#include <vcl/event.hxx>
+#include <vcl/fontcharmap.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+
+#include <svx/ucsubset.hxx>
+
+
+#include <svx/strings.hrc>
+
+#include <svx/charmap.hxx>
+#include <svx/dialmgr.hxx>
+
+#include <charmapacc.hxx>
+#include <uiobject.hxx>
+
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp>
+#include <officecfg/Office/Common.hxx>
+#include <comphelper/processfactory.hxx>
+#include <unicode/uchar.h>
+#include <vcl/textview.hxx>
+#include <rtl/ustrbuf.hxx>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+sal_uInt32& SvxShowCharSet::getSelectedChar()
+{
+ static sal_uInt32 cSelectedChar = ' '; // keeps selected character over app lifetime
+ return cSelectedChar;
+}
+
+FactoryFunction SvxShowCharSet::GetUITestFactory() const
+{
+ return SvxShowCharSetUIObject::create;
+}
+
+SvxShowCharSet::SvxShowCharSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow, const VclPtr<VirtualDevice>& rVirDev)
+ : mxVirDev(rVirDev)
+ , mxScrollArea(std::move(pScrolledWindow))
+ , nX(0)
+ , nY(0)
+ , maFontSize(0, 0)
+ , maPosition(0,0)
+ , mbRecalculateFont(true)
+ , mbUpdateForeground(true)
+ , mbUpdateBackground(true)
+{
+ init();
+}
+
+void SvxShowCharSet::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+
+ Size aSize(COLUMN_COUNT * pDrawingArea->get_approximate_digit_width() * 5.25,
+ ROW_COUNT * pDrawingArea->get_text_height() * 2);
+
+ nX = aSize.Width() / COLUMN_COUNT;
+ nY = aSize.Height() / ROW_COUNT;
+
+ // tdf#121232 set a size request that will result in a 0 m_nXGap by default
+ mxScrollArea->set_size_request(COLUMN_COUNT * nX + mxScrollArea->get_scroll_thickness() + 2,
+ ROW_COUNT * nY);
+}
+
+void SvxShowCharSet::init()
+{
+ nSelectedIndex = -1; // TODO: move into init list when it is no longer static
+ m_nXGap = 0;
+ m_nYGap = 0;
+
+ mxScrollArea->connect_vadjustment_changed(LINK(this, SvxShowCharSet, VscrollHdl));
+ getFavCharacterList();
+ // other settings depend on selected font => see RecalculateFont
+
+ bDrag = false;
+}
+
+void SvxShowCharSet::Resize()
+{
+ mbRecalculateFont = true;
+}
+
+void SvxShowCharSet::GetFocus()
+{
+ SelectIndex(nSelectedIndex, true);
+}
+
+void SvxShowCharSet::LoseFocus()
+{
+ SelectIndex(nSelectedIndex);
+}
+
+bool SvxShowCharSet::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if ( rMEvt.IsLeft() )
+ {
+ if ( rMEvt.GetClicks() == 1 )
+ {
+ GrabFocus();
+ bDrag = true;
+ CaptureMouse();
+
+ int nIndex = PixelToMapIndex( rMEvt.GetPosPixel() );
+ // Fire the focus event
+ SelectIndex( nIndex, true);
+ }
+
+ if ( !(rMEvt.GetClicks() % 2) )
+ aDoubleClkHdl.Call( this );
+ }
+
+ if (rMEvt.IsRight())
+ {
+ Point aPosition (rMEvt.GetPosPixel());
+ maPosition = aPosition;
+ int nIndex = PixelToMapIndex( rMEvt.GetPosPixel() );
+ // Fire the focus event
+ SelectIndex( nIndex, true);
+ createContextMenu();
+ }
+
+ return true;
+}
+
+bool SvxShowCharSet::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if ( bDrag && rMEvt.IsLeft() )
+ {
+ // released mouse over character map
+ if ( tools::Rectangle(Point(), GetOutputSizePixel()).Contains(rMEvt.GetPosPixel()))
+ aSelectHdl.Call( this );
+ ReleaseMouse();
+ bDrag = false;
+ }
+
+ return true;
+}
+
+bool SvxShowCharSet::MouseMove(const MouseEvent& rMEvt)
+{
+ if ( rMEvt.IsLeft() && bDrag )
+ {
+ Point aPos = rMEvt.GetPosPixel();
+ Size aSize = GetOutputSizePixel();
+
+ if ( aPos.X() < 0 )
+ aPos.setX( 0 );
+ else if ( aPos.X() > aSize.Width()-5 )
+ aPos.setX( aSize.Width()-5 );
+ if ( aPos.Y() < 0 )
+ aPos.setY( 0 );
+ else if ( aPos.Y() > aSize.Height()-5 )
+ aPos.setY( aSize.Height()-5 );
+
+ int nIndex = PixelToMapIndex( aPos );
+ // Fire the focus event.
+ SelectIndex( nIndex, true );
+ }
+
+ return true;
+}
+
+sal_uInt16 SvxShowCharSet::GetRowPos(sal_uInt16 _nPos)
+{
+ return _nPos / COLUMN_COUNT ;
+}
+
+void SvxShowCharSet::getFavCharacterList()
+{
+ maFavCharList.clear();
+ maFavCharFontList.clear();
+ //retrieve recent character list
+ css::uno::Sequence< OUString > rFavCharList( officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::get() );
+ comphelper::sequenceToContainer(maFavCharList, rFavCharList);
+
+ //retrieve recent character font list
+ css::uno::Sequence< OUString > rFavCharFontList( officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::get() );
+ comphelper::sequenceToContainer(maFavCharFontList, rFavCharFontList);
+}
+
+bool SvxShowCharSet::isFavChar(const OUString& sTitle, const OUString& rFont)
+{
+ auto isFavCharTitleExists = std::any_of(maFavCharList.begin(),
+ maFavCharList.end(),
+ [sTitle] (const OUString & a) { return a == sTitle; });
+
+ auto isFavCharFontExists = std::any_of(maFavCharFontList.begin(),
+ maFavCharFontList.end(),
+ [rFont] (const OUString & a) { return a == rFont; });
+
+ // if Fav char to be added is already in list, return true
+ return isFavCharTitleExists && isFavCharFontExists;
+}
+
+void SvxShowCharSet::createContextMenu()
+{
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetDrawingArea(), "svx/ui/charsetmenu.ui"));
+ std::unique_ptr<weld::Menu> xItemMenu(xBuilder->weld_menu("charsetmenu"));
+
+ sal_UCS4 cChar = GetSelectCharacter();
+ OUString aOUStr( &cChar, 1 );
+ if (isFavChar(aOUStr, mxVirDev->GetFont().GetFamilyName()) || maFavCharList.size() >= 16)
+ xItemMenu->set_visible("add", false);
+ else
+ xItemMenu->set_visible("remove", false);
+
+ ContextMenuSelect(xItemMenu->popup_at_rect(GetDrawingArea(), tools::Rectangle(maPosition, Size(1,1))));
+ GrabFocus();
+ Invalidate();
+}
+
+void SvxShowCharSet::ContextMenuSelect(std::string_view rIdent)
+{
+ sal_UCS4 cChar = GetSelectCharacter();
+ OUString aOUStr(&cChar, 1);
+
+ if (rIdent == "insert")
+ aDoubleClkHdl.Call(this);
+ else if (rIdent == "add" || rIdent == "remove")
+ {
+ updateFavCharacterList(aOUStr, mxVirDev->GetFont().GetFamilyName());
+ aFavClickHdl.Call(this);
+ }
+ else if (rIdent == "copy")
+ CopyToClipboard(aOUStr);
+}
+
+void SvxShowCharSet::CopyToClipboard(const OUString& rOUStr)
+{
+ css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard =
+ css::datatransfer::clipboard::SystemClipboard::create(comphelper::getProcessComponentContext());
+
+ if (!xClipboard.is())
+ return;
+
+ rtl::Reference<TETextDataObject> pDataObj = new TETextDataObject(rOUStr);
+
+ try
+ {
+ xClipboard->setContents( pDataObj, nullptr );
+
+ css::uno::Reference<css::datatransfer::clipboard::XFlushableClipboard> xFlushableClipboard(xClipboard, css::uno::UNO_QUERY);
+ if( xFlushableClipboard.is() )
+ xFlushableClipboard->flushClipboard();
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+}
+
+void SvxShowCharSet::updateFavCharacterList(const OUString& sTitle, const OUString& rFont)
+{
+ if(isFavChar(sTitle, rFont))
+ {
+ auto itChar = std::find(maFavCharList.begin(), maFavCharList.end(), sTitle);
+ auto itChar2 = std::find(maFavCharFontList.begin(), maFavCharFontList.end(), rFont);
+
+ // if Fav char to be added is already in list, remove it
+ if( itChar != maFavCharList.end() && itChar2 != maFavCharFontList.end() )
+ {
+ maFavCharList.erase( itChar );
+ maFavCharFontList.erase( itChar2);
+ }
+
+ css::uno::Sequence< OUString > aFavCharList(maFavCharList.size());
+ auto aFavCharListRange = asNonConstRange(aFavCharList);
+ css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
+ auto aFavCharFontListRange = asNonConstRange(aFavCharFontList);
+
+ for (size_t i = 0; i < maFavCharList.size(); ++i)
+ {
+ aFavCharListRange[i] = maFavCharList[i];
+ aFavCharFontListRange[i] = maFavCharFontList[i];
+ }
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
+ batch->commit();
+ return;
+ }
+
+ auto itChar = std::find(maFavCharList.begin(), maFavCharList.end(), sTitle);
+ auto itChar2 = std::find(maFavCharFontList.begin(), maFavCharFontList.end(), rFont);
+
+ // if Fav char to be added is already in list, remove it
+ if( itChar != maFavCharList.end() && itChar2 != maFavCharFontList.end() )
+ {
+ maFavCharList.erase( itChar );
+ maFavCharFontList.erase( itChar2);
+ }
+
+ if (maFavCharList.size() == 16)
+ {
+ maFavCharList.pop_back();
+ maFavCharFontList.pop_back();
+ }
+
+ maFavCharList.push_back(sTitle);
+ maFavCharFontList.push_back(rFont);
+
+ css::uno::Sequence< OUString > aFavCharList(maFavCharList.size());
+ auto aFavCharListRange = asNonConstRange(aFavCharList);
+ css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
+ auto aFavCharFontListRange = asNonConstRange(aFavCharFontList);
+
+ for (size_t i = 0; i < maFavCharList.size(); ++i)
+ {
+ aFavCharListRange[i] = maFavCharList[i];
+ aFavCharFontListRange[i] = maFavCharFontList[i];
+ }
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
+ batch->commit();
+}
+
+sal_uInt16 SvxShowCharSet::GetColumnPos(sal_uInt16 _nPos)
+{
+ return _nPos % COLUMN_COUNT ;
+}
+
+int SvxShowCharSet::FirstInView() const
+{
+ return mxScrollArea->vadjustment_get_value() * COLUMN_COUNT;
+}
+
+int SvxShowCharSet::LastInView() const
+{
+ sal_uInt32 nIndex = FirstInView();
+ nIndex += ROW_COUNT * COLUMN_COUNT - 1;
+ sal_uInt32 nCompare = mxFontCharMap->GetCharCount() - 1;
+ if (nIndex > nCompare)
+ nIndex = nCompare;
+ return nIndex;
+}
+
+Point SvxShowCharSet::MapIndexToPixel( int nIndex ) const
+{
+ const int nBase = FirstInView();
+ int x = ((nIndex - nBase) % COLUMN_COUNT) * nX;
+ int y = ((nIndex - nBase) / COLUMN_COUNT) * nY;
+ return Point( x + m_nXGap, y + m_nYGap );
+}
+
+
+int SvxShowCharSet::PixelToMapIndex( const Point& point) const
+{
+ int nBase = FirstInView();
+ assert(nX != 0);
+ int x = nX == 0 ? 0 : (point.X() - m_nXGap)/nX;
+ assert(nY != 0);
+ int y = nY == 0 ? 0 : (point.Y() - m_nYGap)/nY;
+ return (nBase + x + y * COLUMN_COUNT);
+}
+
+bool SvxShowCharSet::KeyInput(const KeyEvent& rKEvt)
+{
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ if (aCode.GetModifier())
+ return false;
+
+ bool bRet = true;
+
+ int tmpSelected = nSelectedIndex;
+
+ switch (aCode.GetCode())
+ {
+ case KEY_SPACE:
+ aSelectHdl.Call( this );
+ break;
+ case KEY_LEFT:
+ --tmpSelected;
+ break;
+ case KEY_RIGHT:
+ ++tmpSelected;
+ break;
+ case KEY_UP:
+ tmpSelected -= COLUMN_COUNT;
+ break;
+ case KEY_DOWN:
+ tmpSelected += COLUMN_COUNT;
+ break;
+ case KEY_PAGEUP:
+ tmpSelected -= ROW_COUNT * COLUMN_COUNT;
+ break;
+ case KEY_PAGEDOWN:
+ tmpSelected += ROW_COUNT * COLUMN_COUNT;
+ break;
+ case KEY_HOME:
+ tmpSelected = 0;
+ break;
+ case KEY_END:
+ tmpSelected = mxFontCharMap->GetCharCount() - 1;
+ break;
+ case KEY_TAB: // some fonts have a character at these unicode control codes
+ case KEY_ESCAPE:
+ case KEY_RETURN:
+ tmpSelected = - 1; // mark as invalid
+ bRet = false;
+ break;
+ default:
+ {
+ sal_UCS4 cChar = rKEvt.GetCharCode();
+ sal_UCS4 cNext = mxFontCharMap->GetNextChar(cChar - 1);
+ tmpSelected = mxFontCharMap->GetIndexFromChar(cNext);
+ if (tmpSelected < 0 || (cChar != cNext))
+ {
+ tmpSelected = - 1; // mark as invalid
+ bRet = false;
+ }
+ break;
+ }
+ }
+
+ if ( tmpSelected >= 0 )
+ {
+ SelectIndex( tmpSelected, true );
+ aPreSelectHdl.Call( this );
+ }
+
+ return bRet;
+}
+
+void SvxShowCharSet::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ InitSettings(rRenderContext);
+ RecalculateFont(rRenderContext);
+ DrawChars_Impl(rRenderContext, FirstInView(), LastInView());
+}
+
+void SvxShowCharSet::SetFont( const vcl::Font& rFont )
+{
+ maFont = rFont;
+ mbRecalculateFont = true;
+ Invalidate();
+}
+
+void SvxShowCharSet::DeSelect()
+{
+ Invalidate();
+}
+
+// stretch a grid rectangle if it's at the edge to fill unused space
+tools::Rectangle SvxShowCharSet::getGridRectangle(const Point &rPointUL, const Size &rOutputSize) const
+{
+ tools::Long x = rPointUL.X() - 1;
+ tools::Long y = rPointUL.Y() - 1;
+ Point aPointUL(x+1, y+1);
+ Size aGridSize(nX-1, nY-1);
+
+ tools::Long nXDistFromLeft = x - m_nXGap;
+ if (nXDistFromLeft <= 1)
+ {
+ aPointUL.setX( 1 );
+ aGridSize.AdjustWidth(m_nXGap + nXDistFromLeft );
+ }
+ tools::Long nXDistFromRight = rOutputSize.Width() - m_nXGap - nX - x;
+ if (nXDistFromRight <= 1)
+ aGridSize.AdjustWidth(m_nXGap + nXDistFromRight );
+
+ tools::Long nXDistFromTop = y - m_nYGap;
+ if (nXDistFromTop <= 1)
+ {
+ aPointUL.setY( 1 );
+ aGridSize.AdjustHeight(m_nYGap + nXDistFromTop );
+ }
+ tools::Long nXDistFromBottom = rOutputSize.Height() - m_nYGap - nY - y;
+ if (nXDistFromBottom <= 1)
+ aGridSize.AdjustHeight(m_nYGap + nXDistFromBottom );
+
+ return tools::Rectangle(aPointUL, aGridSize);
+}
+
+void SvxShowCharSet::DrawChars_Impl(vcl::RenderContext& rRenderContext, int n1, int n2)
+{
+ if (n1 > LastInView() || n2 < FirstInView())
+ return;
+
+ Size aOutputSize(GetOutputSizePixel());
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Color aWindowTextColor(rStyleSettings.GetFieldTextColor());
+ Color aHighlightColor(rStyleSettings.GetHighlightColor());
+ Color aHighlightTextColor(rStyleSettings.GetHighlightTextColor());
+ Color aFaceColor(rStyleSettings.GetFaceColor());
+ Color aLightColor(rStyleSettings.GetLightColor());
+ Color aShadowColor(rStyleSettings.GetShadowColor());
+
+ int i;
+ rRenderContext.SetLineColor(aShadowColor);
+ for (i = 1; i < COLUMN_COUNT; ++i)
+ {
+ rRenderContext.DrawLine(Point(nX * i + m_nXGap, 0),
+ Point(nX * i + m_nXGap, aOutputSize.Height()));
+ }
+ for (i = 1; i < ROW_COUNT; ++i)
+ {
+ rRenderContext.DrawLine(Point(0, nY * i + m_nYGap),
+ Point(aOutputSize.Width(), nY * i + m_nYGap));
+ }
+
+ int nTextHeight = rRenderContext.GetTextHeight();
+ tools::Rectangle aBoundRect;
+ for (i = n1; i <= n2; ++i)
+ {
+ Point pix = MapIndexToPixel(i);
+ int x = pix.X();
+ int y = pix.Y();
+
+ sal_UCS4 nChar = mxFontCharMap->GetCharFromIndex(i);
+ OUString aCharStr(&nChar, 1);
+ int nTextWidth = rRenderContext.GetTextWidth(aCharStr);
+ int tx = x + (nX - nTextWidth + 1) / 2;
+ int ty = y + (nY - nTextHeight + 1) / 2;
+ Point aPointTxTy(tx, ty);
+
+ // adjust position before it gets out of bounds
+ if (rRenderContext.GetTextBoundRect(aBoundRect, aCharStr) && !aBoundRect.IsEmpty())
+ {
+ // zero advance width => use ink width to center glyph
+ if (!nTextWidth)
+ {
+ aPointTxTy.setX( x - aBoundRect.Left() + (nX - aBoundRect.GetWidth() + 1) / 2 );
+ }
+
+ aBoundRect += aPointTxTy;
+
+ // shift back vertically if needed
+ int nYLDelta = aBoundRect.Top() - y;
+ int nYHDelta = (y + nY) - aBoundRect.Bottom();
+ if (nYLDelta <= 0)
+ aPointTxTy.AdjustY( -(nYLDelta - 1) );
+ else if (nYHDelta <= 0)
+ aPointTxTy.AdjustY(nYHDelta - 1 );
+
+ // shift back horizontally if needed
+ int nXLDelta = aBoundRect.Left() - x;
+ int nXHDelta = (x + nX) - aBoundRect.Right();
+ if (nXLDelta <= 0)
+ aPointTxTy.AdjustX( -(nXLDelta - 1) );
+ else if (nXHDelta <= 0)
+ aPointTxTy.AdjustX(nXHDelta - 1 );
+ }
+
+ // tdf#109214 - highlight the favorite characters
+ if (isFavChar(aCharStr, mxVirDev->GetFont().GetFamilyName()))
+ {
+ const Color aLineCol = rRenderContext.GetLineColor();
+ rRenderContext.SetLineColor(aHighlightColor);
+ rRenderContext.SetFillColor(COL_TRANSPARENT);
+ // Outer border
+ rRenderContext.DrawRect(tools::Rectangle(Point(x - 1, y - 1), Size(nX + 3, nY + 3)));
+ // Inner border
+ rRenderContext.DrawRect(tools::Rectangle(Point(x, y), Size(nX + 1, nY + 1)));
+ rRenderContext.SetLineColor(aLineCol);
+ }
+
+ Color aTextCol = rRenderContext.GetTextColor();
+ if (i != nSelectedIndex)
+ {
+ rRenderContext.SetTextColor(aWindowTextColor);
+ rRenderContext.DrawText(aPointTxTy, aCharStr);
+ }
+ else
+ {
+ Color aLineCol = rRenderContext.GetLineColor();
+ Color aFillCol = rRenderContext.GetFillColor();
+ rRenderContext.SetLineColor();
+ Point aPointUL(x + 1, y + 1);
+ if (HasFocus())
+ {
+ rRenderContext.SetFillColor(aHighlightColor);
+ rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
+
+ rRenderContext.SetTextColor(aHighlightTextColor);
+ rRenderContext.DrawText(aPointTxTy, aCharStr);
+ }
+ else
+ {
+ rRenderContext.SetFillColor(aFaceColor);
+ rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
+
+ rRenderContext.SetLineColor(aLightColor);
+ rRenderContext.DrawLine(aPointUL, Point(x + nX - 1, y + 1));
+ rRenderContext.DrawLine(aPointUL, Point(x + 1, y + nY - 1));
+
+ rRenderContext.SetLineColor(aShadowColor);
+ rRenderContext.DrawLine(Point(x + 1, y + nY - 1), Point(x + nX - 1, y + nY - 1));
+ rRenderContext.DrawLine(Point(x + nX - 1, y + nY - 1), Point(x + nX - 1, y + 1));
+
+ rRenderContext.DrawText(aPointTxTy, aCharStr);
+ }
+ rRenderContext.SetLineColor(aLineCol);
+ rRenderContext.SetFillColor(aFillCol);
+ }
+ rRenderContext.SetTextColor(aTextCol);
+ }
+}
+
+
+void SvxShowCharSet::InitSettings(vcl::RenderContext& rRenderContext)
+{
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+
+ if (mbUpdateForeground)
+ {
+ rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
+ mbUpdateForeground = false;
+ }
+
+ if (mbUpdateBackground)
+ {
+ rRenderContext.SetBackground(rStyleSettings.GetWindowColor());
+ rRenderContext.Erase();
+ mbUpdateBackground = false;
+ }
+
+ vcl::Font aFont(maFont);
+ aFont.SetWeight(WEIGHT_LIGHT);
+ aFont.SetAlignment(ALIGN_TOP);
+ aFont.SetFontSize(maFontSize);
+ aFont.SetTransparent(true);
+ rRenderContext.SetFont(aFont);
+}
+
+sal_UCS4 SvxShowCharSet::GetSelectCharacter() const
+{
+ if( nSelectedIndex >= 0 )
+ getSelectedChar() = mxFontCharMap->GetCharFromIndex( nSelectedIndex );
+ return getSelectedChar();
+}
+
+
+void SvxShowCharSet::RecalculateFont(vcl::RenderContext& rRenderContext)
+{
+ if (!mbRecalculateFont)
+ return;
+
+ // save last selected unicode
+ if (nSelectedIndex >= 0)
+ getSelectedChar() = mxFontCharMap->GetCharFromIndex(nSelectedIndex);
+
+ Size aSize(GetOutputSizePixel());
+
+ vcl::Font aFont = maFont;
+ aFont.SetWeight(WEIGHT_LIGHT);
+ aFont.SetAlignment(ALIGN_TOP);
+ int nFontHeight = (aSize.Height() - 5) * 2 / (3 * ROW_COUNT);
+ maFontSize = rRenderContext.PixelToLogic(Size(0, nFontHeight));
+ aFont.SetFontSize(maFontSize);
+ aFont.SetTransparent(true);
+ rRenderContext.SetFont(aFont);
+ rRenderContext.GetFontCharMap(mxFontCharMap);
+ getFavCharacterList();
+
+ nX = aSize.Width() / COLUMN_COUNT;
+ nY = aSize.Height() / ROW_COUNT;
+
+ const int nLastRow = (mxFontCharMap->GetCharCount() - 1 + COLUMN_COUNT) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_configure(mxScrollArea->vadjustment_get_value(), 0, nLastRow, 1, ROW_COUNT - 1, ROW_COUNT);
+
+ // restore last selected unicode
+ int nMapIndex = mxFontCharMap->GetIndexFromChar(getSelectedChar());
+ if (nMapIndex != nSelectedIndex)
+ SelectIndex(nMapIndex);
+
+ // rearrange CharSet element in sync with nX- and nY-multiples
+ Size aDrawSize(nX * COLUMN_COUNT, nY * ROW_COUNT);
+ m_nXGap = (aSize.Width() - aDrawSize.Width()) / 2;
+ m_nYGap = (aSize.Height() - aDrawSize.Height()) / 2;
+
+ mbRecalculateFont = false;
+}
+
+void SvxShowCharSet::SelectIndex(int nNewIndex, bool bFocus)
+{
+ if (!mxFontCharMap.is())
+ RecalculateFont(*mxVirDev);
+
+ if( nNewIndex < 0 )
+ {
+ // need to scroll see closest unicode
+ sal_uInt32 cPrev = mxFontCharMap->GetPrevChar( getSelectedChar() );
+ int nMapIndex = mxFontCharMap->GetIndexFromChar( cPrev );
+ int nNewPos = nMapIndex / COLUMN_COUNT;
+ mxScrollArea->vadjustment_set_value(nNewPos);
+ nSelectedIndex = bFocus ? nMapIndex+1 : -1;
+ Invalidate();
+ }
+ else if( nNewIndex < FirstInView() )
+ {
+ // need to scroll up to see selected item
+ int nOldPos = mxScrollArea->vadjustment_get_value();
+ int nDelta = (FirstInView() - nNewIndex + COLUMN_COUNT-1) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_set_value(nOldPos - nDelta);
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+ else if( nNewIndex > LastInView() )
+ {
+ // need to scroll down to see selected item
+ int nOldPos = mxScrollArea->vadjustment_get_value();
+ int nDelta = (nNewIndex - LastInView() + COLUMN_COUNT) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_set_value(nOldPos + nDelta);
+ if( nNewIndex < mxFontCharMap->GetCharCount() )
+ {
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+ else if (nOldPos != mxScrollArea->vadjustment_get_value())
+ {
+ Invalidate();
+ }
+ }
+ else
+ {
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+
+ if( nSelectedIndex >= 0 )
+ {
+ getSelectedChar() = mxFontCharMap->GetCharFromIndex( nSelectedIndex );
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( m_xAccessible.is() )
+ {
+ svx::SvxShowCharSetItem* pItem = ImplGetItem(nSelectedIndex);
+ // Don't fire the focus event.
+ if ( bFocus )
+ m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), Any(pItem->GetAccessible()) ); // this call assures that m_pItem is set
+ else
+ m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS, Any(), Any(pItem->GetAccessible()) ); // this call assures that m_pItem is set
+
+ assert(pItem->m_xItem.is() && "No accessible created!");
+ Any aOldAny, aNewAny;
+ aNewAny <<= AccessibleStateType::FOCUSED;
+ // Don't fire the focus event.
+ if ( bFocus )
+ pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
+
+ aNewAny <<= AccessibleStateType::SELECTED;
+ pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
+ }
+#endif
+ }
+ aHighHdl.Call( this );
+}
+
+void SvxShowCharSet::OutputIndex( int nNewIndex )
+{
+ SelectIndex( nNewIndex, true );
+ aSelectHdl.Call( this );
+}
+
+
+void SvxShowCharSet::SelectCharacter( sal_UCS4 cNew )
+{
+ if ( !mxFontCharMap.is() )
+ RecalculateFont(*mxVirDev);
+
+ // get next available char of current font
+ sal_UCS4 cNext = mxFontCharMap->GetNextChar( (cNew > 0) ? cNew - 1 : cNew );
+
+ int nMapIndex = mxFontCharMap->GetIndexFromChar( cNext );
+ SelectIndex( nMapIndex );
+ // move selected item to top row if not in focus
+ mxScrollArea->vadjustment_set_value(nMapIndex / COLUMN_COUNT);
+ Invalidate();
+}
+
+IMPL_LINK_NOARG(SvxShowCharSet, VscrollHdl, weld::ScrolledWindow&, void)
+{
+ if( nSelectedIndex < FirstInView() )
+ {
+ SelectIndex( FirstInView() + (nSelectedIndex % COLUMN_COUNT) );
+ }
+ else if( nSelectedIndex > LastInView() )
+ {
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( m_xAccessible.is() )
+ {
+ css::uno::Any aOldAny, aNewAny;
+ int nLast = LastInView();
+ for ( ; nLast != nSelectedIndex; ++nLast)
+ {
+ aOldAny <<= ImplGetItem(nLast)->GetAccessible();
+ m_xAccessible ->fireEvent( AccessibleEventId::CHILD, aOldAny, aNewAny );
+ }
+ }
+#endif
+ SelectIndex( (LastInView() - COLUMN_COUNT + 1) + (nSelectedIndex % COLUMN_COUNT) );
+ }
+
+ Invalidate();
+}
+
+SvxShowCharSet::~SvxShowCharSet()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccessible.is())
+ {
+ m_aItems.clear();
+ m_xAccessible->clearCharSetControl();
+ m_xAccessible.clear();
+ }
+#endif
+}
+
+css::uno::Reference< XAccessible > SvxShowCharSet::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ OSL_ENSURE(!m_xAccessible.is(),"Accessible already created!");
+ m_xAccessible = new svx::SvxShowCharSetAcc(this);
+#endif
+ return m_xAccessible;
+}
+
+svx::SvxShowCharSetItem* SvxShowCharSet::ImplGetItem( int _nPos )
+{
+ ItemsMap::iterator aFind = m_aItems.find(_nPos);
+ if ( aFind == m_aItems.end() )
+ {
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ OSL_ENSURE(m_xAccessible.is(), "Who wants to create a child of my table without a parent?");
+#endif
+ auto xItem = std::make_shared<svx::SvxShowCharSetItem>(*this,
+ m_xAccessible.get(), sal::static_int_cast< sal_uInt16 >(_nPos));
+ aFind = m_aItems.emplace(_nPos, xItem).first;
+ OUStringBuffer buf;
+ buf.appendUtf32( mxFontCharMap->GetCharFromIndex( _nPos ) );
+ aFind->second->maText = buf.makeStringAndClear();
+ Point pix = MapIndexToPixel( _nPos );
+ aFind->second->maRect = tools::Rectangle( Point( pix.X() + 1, pix.Y() + 1 ), Size(nX-1,nY-1) );
+ }
+
+ return aFind->second.get();
+}
+
+sal_Int32 SvxShowCharSet::getMaxCharCount() const
+{
+ return mxFontCharMap->GetCharCount();
+}
+
+FontCharMapRef const & SvxShowCharSet::GetFontCharMap()
+{
+ RecalculateFont(*mxVirDev);
+ return mxFontCharMap;
+}
+
+// TODO: should be moved into Font Attributes stuff
+// we let it mature here though because it is currently the only use
+
+SubsetMap::SubsetMap( const FontCharMapRef& rxFontCharMap )
+{
+ InitList();
+ ApplyCharMap(rxFontCharMap);
+}
+
+const SubsetVec& SubsetMap::GetSubsetMap() const
+{
+ return maSubsets;
+}
+
+const Subset* SubsetMap::GetSubsetByUnicode( sal_UCS4 cChar ) const
+{
+ for (auto const& subset : maSubsets)
+ if( (subset.GetRangeMin() <= cChar) && (cChar <= subset.GetRangeMax()) )
+ return &subset;
+ return nullptr;
+}
+
+inline Subset::Subset(sal_UCS4 nMin, sal_UCS4 nMax, const OUString& rName)
+: mnRangeMin(nMin), mnRangeMax(nMax), maRangeName(rName)
+{
+}
+
+void SubsetMap::InitList()
+{
+ static SubsetVec s_aAllSubsets = []()
+ {
+ SubsetVec aAllSubsets;
+ //I wish icu had a way to give me the block ranges
+ for (int i = UBLOCK_BASIC_LATIN; i < UBLOCK_COUNT; ++i)
+ {
+ UBlockCode eBlock = static_cast<UBlockCode>(i);
+ switch (eBlock)
+ {
+ case UBLOCK_NO_BLOCK:
+ case UBLOCK_INVALID_CODE:
+ case UBLOCK_COUNT:
+ case UBLOCK_HIGH_SURROGATES:
+ case UBLOCK_HIGH_PRIVATE_USE_SURROGATES:
+ case UBLOCK_LOW_SURROGATES:
+ break;
+ case UBLOCK_BASIC_LATIN:
+ aAllSubsets.emplace_back( 0x0000, 0x007F, SvxResId(RID_SUBSETSTR_BASIC_LATIN) );
+ break;
+ case UBLOCK_LATIN_1_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x0080, 0x00FF, SvxResId(RID_SUBSETSTR_LATIN_1) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x0100, 0x017F, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_A) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_B:
+ aAllSubsets.emplace_back( 0x0180, 0x024F, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_B) );
+ break;
+ case UBLOCK_IPA_EXTENSIONS:
+ aAllSubsets.emplace_back( 0x0250, 0x02AF, SvxResId(RID_SUBSETSTR_IPA_EXTENSIONS) );
+ break;
+ case UBLOCK_SPACING_MODIFIER_LETTERS:
+ aAllSubsets.emplace_back( 0x02B0, 0x02FF, SvxResId(RID_SUBSETSTR_SPACING_MODIFIERS) );
+ break;
+ case UBLOCK_COMBINING_DIACRITICAL_MARKS:
+ aAllSubsets.emplace_back( 0x0300, 0x036F, SvxResId(RID_SUBSETSTR_COMB_DIACRITICAL) );
+ break;
+ case UBLOCK_GREEK:
+ aAllSubsets.emplace_back( 0x0370, 0x03FF, SvxResId(RID_SUBSETSTR_BASIC_GREEK) );
+ break;
+ case UBLOCK_CYRILLIC:
+ aAllSubsets.emplace_back( 0x0400, 0x04FF, SvxResId(RID_SUBSETSTR_CYRILLIC) );
+ break;
+ case UBLOCK_ARMENIAN:
+ aAllSubsets.emplace_back( 0x0530, 0x058F, SvxResId(RID_SUBSETSTR_ARMENIAN) );
+ break;
+ case UBLOCK_HEBREW:
+ aAllSubsets.emplace_back( 0x0590, 0x05FF, SvxResId(RID_SUBSETSTR_BASIC_HEBREW) );
+ break;
+ case UBLOCK_ARABIC:
+ aAllSubsets.emplace_back( 0x0600, 0x065F, SvxResId(RID_SUBSETSTR_BASIC_ARABIC) );
+ break;
+ case UBLOCK_SYRIAC:
+ aAllSubsets.emplace_back( 0x0700, 0x074F, SvxResId(RID_SUBSETSTR_SYRIAC) );
+ break;
+ case UBLOCK_THAANA:
+ aAllSubsets.emplace_back( 0x0780, 0x07BF, SvxResId(RID_SUBSETSTR_THAANA) );
+ break;
+ case UBLOCK_DEVANAGARI:
+ aAllSubsets.emplace_back( 0x0900, 0x097F, SvxResId(RID_SUBSETSTR_DEVANAGARI) );
+ break;
+ case UBLOCK_BENGALI:
+ aAllSubsets.emplace_back( 0x0980, 0x09FF, SvxResId(RID_SUBSETSTR_BENGALI) );
+ break;
+ case UBLOCK_GURMUKHI:
+ aAllSubsets.emplace_back( 0x0A00, 0x0A7F, SvxResId(RID_SUBSETSTR_GURMUKHI) );
+ break;
+ case UBLOCK_GUJARATI:
+ aAllSubsets.emplace_back( 0x0A80, 0x0AFF, SvxResId(RID_SUBSETSTR_GUJARATI) );
+ break;
+ case UBLOCK_ORIYA:
+ aAllSubsets.emplace_back( 0x0B00, 0x0B7F, SvxResId(RID_SUBSETSTR_ODIA) );
+ break;
+ case UBLOCK_TAMIL:
+ aAllSubsets.emplace_back( 0x0B80, 0x0BFF, SvxResId(RID_SUBSETSTR_TAMIL) );
+ break;
+ case UBLOCK_TELUGU:
+ aAllSubsets.emplace_back( 0x0C00, 0x0C7F, SvxResId(RID_SUBSETSTR_TELUGU) );
+ break;
+ case UBLOCK_KANNADA:
+ aAllSubsets.emplace_back( 0x0C80, 0x0CFF, SvxResId(RID_SUBSETSTR_KANNADA) );
+ break;
+ case UBLOCK_MALAYALAM:
+ aAllSubsets.emplace_back( 0x0D00, 0x0D7F, SvxResId(RID_SUBSETSTR_MALAYALAM) );
+ break;
+ case UBLOCK_SINHALA:
+ aAllSubsets.emplace_back( 0x0D80, 0x0DFF, SvxResId(RID_SUBSETSTR_SINHALA) );
+ break;
+ case UBLOCK_THAI:
+ aAllSubsets.emplace_back( 0x0E00, 0x0E7F, SvxResId(RID_SUBSETSTR_THAI) );
+ break;
+ case UBLOCK_LAO:
+ aAllSubsets.emplace_back( 0x0E80, 0x0EFF, SvxResId(RID_SUBSETSTR_LAO) );
+ break;
+ case UBLOCK_TIBETAN:
+ aAllSubsets.emplace_back( 0x0F00, 0x0FBF, SvxResId(RID_SUBSETSTR_TIBETAN) );
+ break;
+ case UBLOCK_MYANMAR:
+ aAllSubsets.emplace_back( 0x1000, 0x109F, SvxResId(RID_SUBSETSTR_MYANMAR) );
+ break;
+ case UBLOCK_GEORGIAN:
+ aAllSubsets.emplace_back( 0x10A0, 0x10FF, SvxResId(RID_SUBSETSTR_BASIC_GEORGIAN) );
+ break;
+ case UBLOCK_HANGUL_JAMO:
+ aAllSubsets.emplace_back( 0x1100, 0x11FF, SvxResId(RID_SUBSETSTR_HANGUL_JAMO) );
+ break;
+ case UBLOCK_ETHIOPIC:
+ aAllSubsets.emplace_back( 0x1200, 0x137F, SvxResId(RID_SUBSETSTR_ETHIOPIC) );
+ break;
+ case UBLOCK_CHEROKEE:
+ aAllSubsets.emplace_back( 0x13A0, 0x13FF, SvxResId(RID_SUBSETSTR_CHEROKEE) );
+ break;
+ case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS:
+ aAllSubsets.emplace_back( 0x1400, 0x167F, SvxResId(RID_SUBSETSTR_CANADIAN_ABORIGINAL) );
+ break;
+ case UBLOCK_OGHAM:
+ aAllSubsets.emplace_back( 0x1680, 0x169F, SvxResId(RID_SUBSETSTR_OGHAM) );
+ break;
+ case UBLOCK_RUNIC:
+ aAllSubsets.emplace_back( 0x16A0, 0x16F0, SvxResId(RID_SUBSETSTR_RUNIC) );
+ break;
+ case UBLOCK_KHMER:
+ aAllSubsets.emplace_back( 0x1780, 0x17FF, SvxResId(RID_SUBSETSTR_KHMER) );
+ break;
+ case UBLOCK_MONGOLIAN:
+ aAllSubsets.emplace_back( 0x1800, 0x18AF, SvxResId(RID_SUBSETSTR_MONGOLIAN) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_ADDITIONAL:
+ aAllSubsets.emplace_back( 0x1E00, 0x1EFF, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_ADDS) );
+ break;
+ case UBLOCK_GREEK_EXTENDED:
+ aAllSubsets.emplace_back( 0x1F00, 0x1FFF, SvxResId(RID_SUBSETSTR_GREEK_EXTENDED) );
+ break;
+ case UBLOCK_GENERAL_PUNCTUATION:
+ aAllSubsets.emplace_back( 0x2000, 0x206F, SvxResId(RID_SUBSETSTR_GENERAL_PUNCTUATION) );
+ break;
+ case UBLOCK_SUPERSCRIPTS_AND_SUBSCRIPTS:
+ aAllSubsets.emplace_back( 0x2070, 0x209F, SvxResId(RID_SUBSETSTR_SUB_SUPER_SCRIPTS) );
+ break;
+ case UBLOCK_CURRENCY_SYMBOLS:
+ aAllSubsets.emplace_back( 0x20A0, 0x20CF, SvxResId(RID_SUBSETSTR_CURRENCY_SYMBOLS) );
+ break;
+ case UBLOCK_COMBINING_MARKS_FOR_SYMBOLS:
+ aAllSubsets.emplace_back( 0x20D0, 0x20FF, SvxResId(RID_SUBSETSTR_COMB_DIACRITIC_SYMS) );
+ break;
+ case UBLOCK_LETTERLIKE_SYMBOLS:
+ aAllSubsets.emplace_back( 0x2100, 0x214F, SvxResId(RID_SUBSETSTR_LETTERLIKE_SYMBOLS) );
+ break;
+ case UBLOCK_NUMBER_FORMS:
+ aAllSubsets.emplace_back( 0x2150, 0x218F, SvxResId(RID_SUBSETSTR_NUMBER_FORMS) );
+ break;
+ case UBLOCK_ARROWS:
+ aAllSubsets.emplace_back( 0x2190, 0x21FF, SvxResId(RID_SUBSETSTR_ARROWS) );
+ break;
+ case UBLOCK_MATHEMATICAL_OPERATORS:
+ aAllSubsets.emplace_back( 0x2200, 0x22FF, SvxResId(RID_SUBSETSTR_MATH_OPERATORS) );
+ break;
+ case UBLOCK_MISCELLANEOUS_TECHNICAL:
+ aAllSubsets.emplace_back( 0x2300, 0x23FF, SvxResId(RID_SUBSETSTR_MISC_TECHNICAL) );
+ break;
+ case UBLOCK_CONTROL_PICTURES:
+ aAllSubsets.emplace_back( 0x2400, 0x243F, SvxResId(RID_SUBSETSTR_CONTROL_PICTURES) );
+ break;
+ case UBLOCK_OPTICAL_CHARACTER_RECOGNITION:
+ aAllSubsets.emplace_back( 0x2440, 0x245F, SvxResId(RID_SUBSETSTR_OPTICAL_CHAR_REC) );
+ break;
+ case UBLOCK_ENCLOSED_ALPHANUMERICS:
+ aAllSubsets.emplace_back( 0x2460, 0x24FF, SvxResId(RID_SUBSETSTR_ENCLOSED_ALPHANUM) );
+ break;
+ case UBLOCK_BOX_DRAWING:
+ aAllSubsets.emplace_back( 0x2500, 0x257F, SvxResId(RID_SUBSETSTR_BOX_DRAWING) );
+ break;
+ case UBLOCK_BLOCK_ELEMENTS:
+ aAllSubsets.emplace_back( 0x2580, 0x259F, SvxResId(RID_SUBSETSTR_BLOCK_ELEMENTS) );
+ break;
+ case UBLOCK_GEOMETRIC_SHAPES:
+ aAllSubsets.emplace_back( 0x25A0, 0x25FF, SvxResId(RID_SUBSETSTR_GEOMETRIC_SHAPES) );
+ break;
+ case UBLOCK_MISCELLANEOUS_SYMBOLS:
+ aAllSubsets.emplace_back( 0x2600, 0x26FF, SvxResId(RID_SUBSETSTR_MISC_DINGBATS) );
+ break;
+ case UBLOCK_DINGBATS:
+ aAllSubsets.emplace_back( 0x2700, 0x27BF, SvxResId(RID_SUBSETSTR_DINGBATS) );
+ break;
+ case UBLOCK_BRAILLE_PATTERNS:
+ aAllSubsets.emplace_back( 0x2800, 0x28FF, SvxResId(RID_SUBSETSTR_BRAILLE_PATTERNS) );
+ break;
+ case UBLOCK_CJK_RADICALS_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x2E80, 0x2EFF, SvxResId(RID_SUBSETSTR_CJK_RADICAL_SUPPL) );
+ break;
+ case UBLOCK_KANGXI_RADICALS:
+ aAllSubsets.emplace_back( 0x2F00, 0x2FDF, SvxResId(RID_SUBSETSTR_KANGXI_RADICALS) );
+ break;
+ case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS:
+ aAllSubsets.emplace_back( 0x2FF0, 0x2FFF, SvxResId(RID_SUBSETSTR_IDEO_DESC_CHARS) );
+ break;
+ case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
+ aAllSubsets.emplace_back( 0x3000, 0x303F, SvxResId(RID_SUBSETSTR_CJK_SYMS_PUNCTUATION) );
+ break;
+ case UBLOCK_HIRAGANA:
+ aAllSubsets.emplace_back( 0x3040, 0x309F, SvxResId(RID_SUBSETSTR_HIRAGANA) );
+ break;
+ case UBLOCK_KATAKANA:
+ aAllSubsets.emplace_back( 0x30A0, 0x30FF, SvxResId(RID_SUBSETSTR_KATAKANA) );
+ break;
+ case UBLOCK_BOPOMOFO:
+ aAllSubsets.emplace_back( 0x3100, 0x312F, SvxResId(RID_SUBSETSTR_BOPOMOFO) );
+ break;
+ case UBLOCK_HANGUL_COMPATIBILITY_JAMO:
+ aAllSubsets.emplace_back( 0x3130, 0x318F, SvxResId(RID_SUBSETSTR_HANGUL_COMPAT_JAMO) );
+ break;
+ case UBLOCK_KANBUN:
+ aAllSubsets.emplace_back( 0x3190, 0x319F, SvxResId(RID_SUBSETSTR_KANBUN) );
+ break;
+ case UBLOCK_BOPOMOFO_EXTENDED:
+ aAllSubsets.emplace_back( 0x31A0, 0x31BF, SvxResId(RID_SUBSETSTR_BOPOMOFO_EXTENDED) );
+ break;
+ case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:
+ aAllSubsets.emplace_back( 0x3200, 0x32FF, SvxResId(RID_SUBSETSTR_ENCLOSED_CJK_LETTERS) );
+ break;
+ case UBLOCK_CJK_COMPATIBILITY:
+ aAllSubsets.emplace_back( 0x3300, 0x33FF, SvxResId(RID_SUBSETSTR_CJK_COMPATIBILITY) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A:
+ aAllSubsets.emplace_back( 0x3400, 0x4DBF, SvxResId(RID_SUBSETSTR_CJK_EXT_A_UNIFIED_IDGRAPH) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS:
+ aAllSubsets.emplace_back( 0x4E00, 0x9FA5, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDGRAPH) );
+ break;
+ case UBLOCK_YI_SYLLABLES:
+ aAllSubsets.emplace_back( 0xA000, 0xA48F, SvxResId(RID_SUBSETSTR_YI_SYLLABLES) );
+ break;
+ case UBLOCK_YI_RADICALS:
+ aAllSubsets.emplace_back( 0xA490, 0xA4CF, SvxResId(RID_SUBSETSTR_YI_RADICALS) );
+ break;
+ case UBLOCK_HANGUL_SYLLABLES:
+ aAllSubsets.emplace_back( 0xAC00, 0xD7AF, SvxResId(RID_SUBSETSTR_HANGUL) );
+ break;
+ case UBLOCK_PRIVATE_USE_AREA:
+ aAllSubsets.emplace_back( 0xE000, 0xF8FF, SvxResId(RID_SUBSETSTR_PRIVATE_USE_AREA) );
+ break;
+ case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS:
+ aAllSubsets.emplace_back( 0xF900, 0xFAFF, SvxResId(RID_SUBSETSTR_CJK_COMPAT_IDGRAPHS) );
+ break;
+ case UBLOCK_ALPHABETIC_PRESENTATION_FORMS:
+ aAllSubsets.emplace_back( 0xFB00, 0xFB4F, SvxResId(RID_SUBSETSTR_ALPHA_PRESENTATION) );
+ break;
+ case UBLOCK_ARABIC_PRESENTATION_FORMS_A:
+ aAllSubsets.emplace_back( 0xFB50, 0xFDFF, SvxResId(RID_SUBSETSTR_ARABIC_PRESENT_A) );
+ break;
+ case UBLOCK_COMBINING_HALF_MARKS:
+ aAllSubsets.emplace_back( 0xFE20, 0xFE2F, SvxResId(RID_SUBSETSTR_COMBINING_HALF_MARKS) );
+ break;
+ case UBLOCK_CJK_COMPATIBILITY_FORMS:
+ aAllSubsets.emplace_back( 0xFE30, 0xFE4F, SvxResId(RID_SUBSETSTR_CJK_COMPAT_FORMS) );
+ break;
+ case UBLOCK_SMALL_FORM_VARIANTS:
+ aAllSubsets.emplace_back( 0xFE50, 0xFE6F, SvxResId(RID_SUBSETSTR_SMALL_FORM_VARIANTS) );
+ break;
+ case UBLOCK_ARABIC_PRESENTATION_FORMS_B:
+ aAllSubsets.emplace_back( 0xFE70, 0xFEFF, SvxResId(RID_SUBSETSTR_ARABIC_PRESENT_B) );
+ break;
+ case UBLOCK_SPECIALS:
+ aAllSubsets.emplace_back( 0xFFF0, 0xFFFF, SvxResId(RID_SUBSETSTR_SPECIALS) );
+ break;
+ case UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS:
+ aAllSubsets.emplace_back( 0xFF00, 0xFFEF, SvxResId(RID_SUBSETSTR_HALFW_FULLW_FORMS) );
+ break;
+ case UBLOCK_OLD_ITALIC:
+ aAllSubsets.emplace_back( 0x10300, 0x1032F, SvxResId(RID_SUBSETSTR_OLD_ITALIC) );
+ break;
+ case UBLOCK_GOTHIC:
+ aAllSubsets.emplace_back( 0x10330, 0x1034F, SvxResId(RID_SUBSETSTR_GOTHIC) );
+ break;
+ case UBLOCK_DESERET:
+ aAllSubsets.emplace_back( 0x10400, 0x1044F, SvxResId(RID_SUBSETSTR_DESERET) );
+ break;
+ case UBLOCK_BYZANTINE_MUSICAL_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1D000, 0x1D0FF, SvxResId(RID_SUBSETSTR_BYZANTINE_MUSICAL_SYMBOLS) );
+ break;
+ case UBLOCK_MUSICAL_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1D100, 0x1D1FF, SvxResId(RID_SUBSETSTR_MUSICAL_SYMBOLS) );
+ break;
+ case UBLOCK_MATHEMATICAL_ALPHANUMERIC_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1D400, 0x1D7FF, SvxResId(RID_SUBSETSTR_MATHEMATICAL_ALPHANUMERIC_SYMBOLS) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B:
+ aAllSubsets.emplace_back( 0x20000, 0x2A6DF, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B) );
+ break;
+ case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x2F800, 0x2FA1F, SvxResId(RID_SUBSETSTR_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT) );
+ break;
+ case UBLOCK_TAGS:
+ aAllSubsets.emplace_back( 0xE0000, 0xE007F, SvxResId(RID_SUBSETSTR_TAGS) );
+ break;
+ case UBLOCK_CYRILLIC_SUPPLEMENTARY:
+ aAllSubsets.emplace_back( 0x0500, 0x052F, SvxResId(RID_SUBSETSTR_CYRILLIC_SUPPLEMENTARY) );
+ break;
+ case UBLOCK_TAGALOG:
+ aAllSubsets.emplace_back( 0x1700, 0x171F, SvxResId(RID_SUBSETSTR_TAGALOG) );
+ break;
+ case UBLOCK_HANUNOO:
+ aAllSubsets.emplace_back( 0x1720, 0x173F, SvxResId(RID_SUBSETSTR_HANUNOO) );
+ break;
+ case UBLOCK_BUHID:
+ aAllSubsets.emplace_back( 0x1740, 0x175F, SvxResId(RID_SUBSETSTR_BUHID) );
+ break;
+ case UBLOCK_TAGBANWA:
+ aAllSubsets.emplace_back( 0x1760, 0x177F, SvxResId(RID_SUBSETSTR_TAGBANWA) );
+ break;
+ case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A:
+ aAllSubsets.emplace_back( 0x27C0, 0x27EF, SvxResId(RID_SUBSETSTR_MISC_MATH_SYMS_A) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_ARROWS_A:
+ aAllSubsets.emplace_back( 0x27F0, 0x27FF, SvxResId(RID_SUBSETSTR_SUPPL_ARROWS_A) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_ARROWS_B:
+ aAllSubsets.emplace_back( 0x2900, 0x297F, SvxResId(RID_SUBSETSTR_SUPPL_ARROWS_B) );
+ break;
+ case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B:
+ aAllSubsets.emplace_back( 0x2980, 0x29FF, SvxResId(RID_SUBSETSTR_MISC_MATH_SYMS_B) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_MATHEMATICAL_OPERATORS:
+ aAllSubsets.emplace_back( 0x2A00, 0x2AFF, SvxResId(RID_SUBSETSTR_MISC_MATH_SYMS_B) );
+ break;
+ case UBLOCK_KATAKANA_PHONETIC_EXTENSIONS:
+ aAllSubsets.emplace_back( 0x31F0, 0x31FF, SvxResId(RID_SUBSETSTR_KATAKANA_PHONETIC) );
+ break;
+ case UBLOCK_VARIATION_SELECTORS:
+ aAllSubsets.emplace_back( 0xFE00, 0xFE0F, SvxResId(RID_SUBSETSTR_VARIATION_SELECTORS) );
+ break;
+ case UBLOCK_SUPPLEMENTARY_PRIVATE_USE_AREA_A:
+ aAllSubsets.emplace_back( 0xF0000, 0xFFFFF, SvxResId(RID_SUBSETSTR_SUPPLEMENTARY_PRIVATE_USE_AREA_A) );
+ break;
+ case UBLOCK_SUPPLEMENTARY_PRIVATE_USE_AREA_B:
+ aAllSubsets.emplace_back( 0x100000, 0x10FFFF, SvxResId(RID_SUBSETSTR_SUPPLEMENTARY_PRIVATE_USE_AREA_B) );
+ break;
+ case UBLOCK_LIMBU:
+ aAllSubsets.emplace_back( 0x1900, 0x194F, SvxResId(RID_SUBSETSTR_LIMBU) );
+ break;
+ case UBLOCK_TAI_LE:
+ aAllSubsets.emplace_back( 0x1950, 0x197F, SvxResId(RID_SUBSETSTR_TAI_LE) );
+ break;
+ case UBLOCK_KHMER_SYMBOLS:
+ aAllSubsets.emplace_back( 0x19E0, 0x19FF, SvxResId(RID_SUBSETSTR_KHMER_SYMBOLS) );
+ break;
+ case UBLOCK_PHONETIC_EXTENSIONS:
+ aAllSubsets.emplace_back( 0x1D00, 0x1D7F, SvxResId(RID_SUBSETSTR_PHONETIC_EXTENSIONS) );
+ break;
+ case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_ARROWS:
+ aAllSubsets.emplace_back( 0x2B00, 0x2BFF, SvxResId(RID_SUBSETSTR_MISCELLANEOUS_SYMBOLS_AND_ARROWS) );
+ break;
+ case UBLOCK_YIJING_HEXAGRAM_SYMBOLS:
+ aAllSubsets.emplace_back( 0x4DC0, 0x4DFF, SvxResId(RID_SUBSETSTR_YIJING_HEXAGRAM_SYMBOLS) );
+ break;
+ case UBLOCK_LINEAR_B_SYLLABARY:
+ aAllSubsets.emplace_back( 0x10000, 0x1007F, SvxResId(RID_SUBSETSTR_LINEAR_B_SYLLABARY) );
+ break;
+ case UBLOCK_LINEAR_B_IDEOGRAMS:
+ aAllSubsets.emplace_back( 0x10080, 0x100FF, SvxResId(RID_SUBSETSTR_LINEAR_B_IDEOGRAMS) );
+ break;
+ case UBLOCK_AEGEAN_NUMBERS:
+ aAllSubsets.emplace_back( 0x10100, 0x1013F, SvxResId(RID_SUBSETSTR_AEGEAN_NUMBERS) );
+ break;
+ case UBLOCK_UGARITIC:
+ aAllSubsets.emplace_back( 0x10380, 0x1039F, SvxResId(RID_SUBSETSTR_UGARITIC) );
+ break;
+ case UBLOCK_SHAVIAN:
+ aAllSubsets.emplace_back( 0x10450, 0x1047F, SvxResId(RID_SUBSETSTR_SHAVIAN) );
+ break;
+ case UBLOCK_OSMANYA:
+ aAllSubsets.emplace_back( 0x10480, 0x104AF, SvxResId(RID_SUBSETSTR_OSMANYA) );
+ break;
+ case UBLOCK_CYPRIOT_SYLLABARY:
+ aAllSubsets.emplace_back( 0x10800, 0x1083F, SvxResId(RID_SUBSETSTR_CYPRIOT_SYLLABARY) );
+ break;
+ case UBLOCK_TAI_XUAN_JING_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1D300, 0x1D35F, SvxResId(RID_SUBSETSTR_TAI_XUAN_JING_SYMBOLS) );
+ break;
+ case UBLOCK_VARIATION_SELECTORS_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0xE0100, 0xE01EF, SvxResId(RID_SUBSETSTR_VARIATION_SELECTORS_SUPPLEMENT) );
+ break;
+ case UBLOCK_ANCIENT_GREEK_MUSICAL_NOTATION:
+ aAllSubsets.emplace_back(0x1D200, 0x1D24F, SvxResId(RID_SUBSETSTR_ANCIENT_GREEK_MUSICAL_NOTATION) );
+ break;
+ case UBLOCK_ANCIENT_GREEK_NUMBERS:
+ aAllSubsets.emplace_back(0x10140, 0x1018F , SvxResId(RID_SUBSETSTR_ANCIENT_GREEK_NUMBERS) );
+ break;
+ case UBLOCK_ARABIC_SUPPLEMENT:
+ aAllSubsets.emplace_back(0x0750, 0x077F , SvxResId(RID_SUBSETSTR_ARABIC_SUPPLEMENT) );
+ break;
+ case UBLOCK_BUGINESE:
+ aAllSubsets.emplace_back(0x1A00, 0x1A1F , SvxResId(RID_SUBSETSTR_BUGINESE) );
+ break;
+ case UBLOCK_CJK_STROKES:
+ aAllSubsets.emplace_back( 0x31C0, 0x31EF, SvxResId(RID_SUBSETSTR_CJK_STROKES) );
+ break;
+ case UBLOCK_COMBINING_DIACRITICAL_MARKS_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1DC0, 0x1DFF , SvxResId(RID_SUBSETSTR_COMBINING_DIACRITICAL_MARKS_SUPPLEMENT) );
+ break;
+ case UBLOCK_COPTIC:
+ aAllSubsets.emplace_back( 0x2C80, 0x2CFF , SvxResId(RID_SUBSETSTR_COPTIC) );
+ break;
+ case UBLOCK_ETHIOPIC_EXTENDED:
+ aAllSubsets.emplace_back( 0x2D80, 0x2DDF , SvxResId(RID_SUBSETSTR_ETHIOPIC_EXTENDED) );
+ break;
+ case UBLOCK_ETHIOPIC_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1380, 0x139F, SvxResId(RID_SUBSETSTR_ETHIOPIC_SUPPLEMENT) );
+ break;
+ case UBLOCK_GEORGIAN_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x2D00, 0x2D2F, SvxResId(RID_SUBSETSTR_GEORGIAN_SUPPLEMENT) );
+ break;
+ case UBLOCK_GLAGOLITIC:
+ aAllSubsets.emplace_back( 0x2C00, 0x2C5F, SvxResId(RID_SUBSETSTR_GLAGOLITIC) );
+ break;
+ case UBLOCK_KHAROSHTHI:
+ aAllSubsets.emplace_back( 0x10A00, 0x10A5F, SvxResId(RID_SUBSETSTR_KHAROSHTHI) );
+ break;
+ case UBLOCK_MODIFIER_TONE_LETTERS:
+ aAllSubsets.emplace_back( 0xA700, 0xA71F, SvxResId(RID_SUBSETSTR_MODIFIER_TONE_LETTERS) );
+ break;
+ case UBLOCK_NEW_TAI_LUE:
+ aAllSubsets.emplace_back( 0x1980, 0x19DF, SvxResId(RID_SUBSETSTR_NEW_TAI_LUE) );
+ break;
+ case UBLOCK_OLD_PERSIAN:
+ aAllSubsets.emplace_back( 0x103A0, 0x103DF, SvxResId(RID_SUBSETSTR_OLD_PERSIAN) );
+ break;
+ case UBLOCK_PHONETIC_EXTENSIONS_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1D80, 0x1DBF, SvxResId(RID_SUBSETSTR_PHONETIC_EXTENSIONS_SUPPLEMENT) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_PUNCTUATION:
+ aAllSubsets.emplace_back( 0x2E00, 0x2E7F, SvxResId(RID_SUBSETSTR_SUPPLEMENTAL_PUNCTUATION) );
+ break;
+ case UBLOCK_SYLOTI_NAGRI:
+ aAllSubsets.emplace_back( 0xA800, 0xA82F, SvxResId(RID_SUBSETSTR_SYLOTI_NAGRI) );
+ break;
+ case UBLOCK_TIFINAGH:
+ aAllSubsets.emplace_back( 0x2D30, 0x2D7F, SvxResId(RID_SUBSETSTR_TIFINAGH) );
+ break;
+ case UBLOCK_VERTICAL_FORMS:
+ aAllSubsets.emplace_back( 0xFE10, 0xFE1F, SvxResId(RID_SUBSETSTR_VERTICAL_FORMS) );
+ break;
+ case UBLOCK_NKO:
+ aAllSubsets.emplace_back( 0x07C0, 0x07FF, SvxResId(RID_SUBSETSTR_NKO) );
+ break;
+ case UBLOCK_BALINESE:
+ aAllSubsets.emplace_back( 0x1B00, 0x1B7F, SvxResId(RID_SUBSETSTR_BALINESE) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_C:
+ aAllSubsets.emplace_back( 0x2C60, 0x2C7F, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_C) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_D:
+ aAllSubsets.emplace_back( 0xA720, 0xA7FF, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_D) );
+ break;
+ case UBLOCK_PHAGS_PA:
+ aAllSubsets.emplace_back( 0xA840, 0xA87F, SvxResId(RID_SUBSETSTR_PHAGS_PA) );
+ break;
+ case UBLOCK_PHOENICIAN:
+ aAllSubsets.emplace_back( 0x10900, 0x1091F, SvxResId(RID_SUBSETSTR_PHOENICIAN) );
+ break;
+ case UBLOCK_CUNEIFORM:
+ aAllSubsets.emplace_back( 0x12000, 0x123FF, SvxResId(RID_SUBSETSTR_CUNEIFORM) );
+ break;
+ case UBLOCK_CUNEIFORM_NUMBERS_AND_PUNCTUATION:
+ aAllSubsets.emplace_back( 0x12400, 0x1247F, SvxResId(RID_SUBSETSTR_CUNEIFORM_NUMBERS_AND_PUNCTUATION) );
+ break;
+ case UBLOCK_COUNTING_ROD_NUMERALS:
+ aAllSubsets.emplace_back( 0x1D360, 0x1D37F, SvxResId(RID_SUBSETSTR_COUNTING_ROD_NUMERALS) );
+ break;
+ case UBLOCK_SUNDANESE:
+ aAllSubsets.emplace_back( 0x1B80, 0x1BBF, SvxResId(RID_SUBSETSTR_SUNDANESE) );
+ break;
+ case UBLOCK_LEPCHA:
+ aAllSubsets.emplace_back( 0x1C00, 0x1C4F, SvxResId(RID_SUBSETSTR_LEPCHA) );
+ break;
+ case UBLOCK_OL_CHIKI:
+ aAllSubsets.emplace_back( 0x1C50, 0x1C7F, SvxResId(RID_SUBSETSTR_OL_CHIKI) );
+ break;
+ case UBLOCK_CYRILLIC_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x2DE0, 0x2DFF, SvxResId(RID_SUBSETSTR_CYRILLIC_EXTENDED_A) );
+ break;
+ case UBLOCK_VAI:
+ aAllSubsets.emplace_back( 0xA500, 0xA63F, SvxResId(RID_SUBSETSTR_VAI) );
+ break;
+ case UBLOCK_CYRILLIC_EXTENDED_B:
+ aAllSubsets.emplace_back( 0xA640, 0xA69F, SvxResId(RID_SUBSETSTR_CYRILLIC_EXTENDED_B) );
+ break;
+ case UBLOCK_SAURASHTRA:
+ aAllSubsets.emplace_back( 0xA880, 0xA8DF, SvxResId(RID_SUBSETSTR_SAURASHTRA) );
+ break;
+ case UBLOCK_KAYAH_LI:
+ aAllSubsets.emplace_back( 0xA900, 0xA92F, SvxResId(RID_SUBSETSTR_KAYAH_LI) );
+ break;
+ case UBLOCK_REJANG:
+ aAllSubsets.emplace_back( 0xA930, 0xA95F, SvxResId(RID_SUBSETSTR_REJANG) );
+ break;
+ case UBLOCK_CHAM:
+ aAllSubsets.emplace_back( 0xAA00, 0xAA5F, SvxResId(RID_SUBSETSTR_CHAM) );
+ break;
+ case UBLOCK_ANCIENT_SYMBOLS:
+ aAllSubsets.emplace_back( 0x10190, 0x101CF, SvxResId(RID_SUBSETSTR_ANCIENT_SYMBOLS) );
+ break;
+ case UBLOCK_PHAISTOS_DISC:
+ aAllSubsets.emplace_back( 0x101D0, 0x101FF, SvxResId(RID_SUBSETSTR_PHAISTOS_DISC) );
+ break;
+ case UBLOCK_LYCIAN:
+ aAllSubsets.emplace_back( 0x10280, 0x1029F, SvxResId(RID_SUBSETSTR_LYCIAN) );
+ break;
+ case UBLOCK_CARIAN:
+ aAllSubsets.emplace_back( 0x102A0, 0x102DF, SvxResId(RID_SUBSETSTR_CARIAN) );
+ break;
+ case UBLOCK_LYDIAN:
+ aAllSubsets.emplace_back( 0x10920, 0x1093F, SvxResId(RID_SUBSETSTR_LYDIAN) );
+ break;
+ case UBLOCK_MAHJONG_TILES:
+ aAllSubsets.emplace_back( 0x1F000, 0x1F02F, SvxResId(RID_SUBSETSTR_MAHJONG_TILES) );
+ break;
+ case UBLOCK_DOMINO_TILES:
+ aAllSubsets.emplace_back( 0x1F030, 0x1F09F, SvxResId(RID_SUBSETSTR_DOMINO_TILES) );
+ break;
+ case UBLOCK_SAMARITAN:
+ aAllSubsets.emplace_back( 0x0800, 0x083F, SvxResId(RID_SUBSETSTR_SAMARITAN) );
+ break;
+ case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED:
+ aAllSubsets.emplace_back( 0x18B0, 0x18FF, SvxResId(RID_SUBSETSTR_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED) );
+ break;
+ case UBLOCK_TAI_THAM:
+ aAllSubsets.emplace_back( 0x1A20, 0x1AAF, SvxResId(RID_SUBSETSTR_TAI_THAM) );
+ break;
+ case UBLOCK_VEDIC_EXTENSIONS:
+ aAllSubsets.emplace_back( 0x1CD0, 0x1CFF, SvxResId(RID_SUBSETSTR_VEDIC_EXTENSIONS) );
+ break;
+ case UBLOCK_LISU:
+ aAllSubsets.emplace_back( 0xA4D0, 0xA4FF, SvxResId(RID_SUBSETSTR_LISU) );
+ break;
+ case UBLOCK_BAMUM:
+ aAllSubsets.emplace_back( 0xA6A0, 0xA6FF, SvxResId(RID_SUBSETSTR_BAMUM) );
+ break;
+ case UBLOCK_COMMON_INDIC_NUMBER_FORMS:
+ aAllSubsets.emplace_back( 0xA830, 0xA83F, SvxResId(RID_SUBSETSTR_COMMON_INDIC_NUMBER_FORMS) );
+ break;
+ case UBLOCK_DEVANAGARI_EXTENDED:
+ aAllSubsets.emplace_back( 0xA8E0, 0xA8FF, SvxResId(RID_SUBSETSTR_DEVANAGARI_EXTENDED) );
+ break;
+ case UBLOCK_HANGUL_JAMO_EXTENDED_A:
+ aAllSubsets.emplace_back( 0xA960, 0xA97F, SvxResId(RID_SUBSETSTR_HANGUL_JAMO_EXTENDED_A) );
+ break;
+ case UBLOCK_JAVANESE:
+ aAllSubsets.emplace_back( 0xA980, 0xA9DF, SvxResId(RID_SUBSETSTR_JAVANESE) );
+ break;
+ case UBLOCK_MYANMAR_EXTENDED_A:
+ aAllSubsets.emplace_back( 0xAA60, 0xAA7F, SvxResId(RID_SUBSETSTR_MYANMAR_EXTENDED_A) );
+ break;
+ case UBLOCK_TAI_VIET:
+ aAllSubsets.emplace_back( 0xAA80, 0xAADF, SvxResId(RID_SUBSETSTR_TAI_VIET) );
+ break;
+ case UBLOCK_MEETEI_MAYEK:
+ aAllSubsets.emplace_back( 0xABC0, 0xABFF, SvxResId(RID_SUBSETSTR_MEETEI_MAYEK) );
+ break;
+ case UBLOCK_HANGUL_JAMO_EXTENDED_B:
+ aAllSubsets.emplace_back( 0xD7B0, 0xD7FF, SvxResId(RID_SUBSETSTR_HANGUL_JAMO_EXTENDED_B) );
+ break;
+ case UBLOCK_IMPERIAL_ARAMAIC:
+ aAllSubsets.emplace_back( 0x10840, 0x1085F, SvxResId(RID_SUBSETSTR_IMPERIAL_ARAMAIC) );
+ break;
+ case UBLOCK_OLD_SOUTH_ARABIAN:
+ aAllSubsets.emplace_back( 0x10A60, 0x10A7F, SvxResId(RID_SUBSETSTR_OLD_SOUTH_ARABIAN) );
+ break;
+ case UBLOCK_AVESTAN:
+ aAllSubsets.emplace_back( 0x10B00, 0x10B3F, SvxResId(RID_SUBSETSTR_AVESTAN) );
+ break;
+ case UBLOCK_INSCRIPTIONAL_PARTHIAN:
+ aAllSubsets.emplace_back( 0x10B40, 0x10B5F, SvxResId(RID_SUBSETSTR_INSCRIPTIONAL_PARTHIAN) );
+ break;
+ case UBLOCK_INSCRIPTIONAL_PAHLAVI:
+ aAllSubsets.emplace_back( 0x10B60, 0x10B7F, SvxResId(RID_SUBSETSTR_INSCRIPTIONAL_PAHLAVI) );
+ break;
+ case UBLOCK_OLD_TURKIC:
+ aAllSubsets.emplace_back( 0x10C00, 0x10C4F, SvxResId(RID_SUBSETSTR_OLD_TURKIC) );
+ break;
+ case UBLOCK_RUMI_NUMERAL_SYMBOLS:
+ aAllSubsets.emplace_back( 0x10E60, 0x10E7F, SvxResId(RID_SUBSETSTR_RUMI_NUMERAL_SYMBOLS) );
+ break;
+ case UBLOCK_KAITHI:
+ aAllSubsets.emplace_back( 0x11080, 0x110CF, SvxResId(RID_SUBSETSTR_KAITHI) );
+ break;
+ case UBLOCK_EGYPTIAN_HIEROGLYPHS:
+ aAllSubsets.emplace_back( 0x13000, 0x1342F, SvxResId(RID_SUBSETSTR_EGYPTIAN_HIEROGLYPHS) );
+ break;
+ case UBLOCK_ENCLOSED_ALPHANUMERIC_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1F100, 0x1F1FF, SvxResId(RID_SUBSETSTR_ENCLOSED_ALPHANUMERIC_SUPPLEMENT) );
+ break;
+ case UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1F200, 0x1F2FF, SvxResId(RID_SUBSETSTR_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C:
+ aAllSubsets.emplace_back( 0x2A700, 0x2B73F, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C) );
+ break;
+ case UBLOCK_MANDAIC:
+ aAllSubsets.emplace_back( 0x0840, 0x085F, SvxResId(RID_SUBSETSTR_MANDAIC) );
+ break;
+ case UBLOCK_BATAK:
+ aAllSubsets.emplace_back( 0x1BC0, 0x1BFF, SvxResId(RID_SUBSETSTR_BATAK) );
+ break;
+ case UBLOCK_ETHIOPIC_EXTENDED_A:
+ aAllSubsets.emplace_back( 0xAB00, 0xAB2F, SvxResId(RID_SUBSETSTR_ETHIOPIC_EXTENDED_A) );
+ break;
+ case UBLOCK_BRAHMI:
+ aAllSubsets.emplace_back( 0x11000, 0x1107F, SvxResId(RID_SUBSETSTR_BRAHMI) );
+ break;
+ case UBLOCK_BAMUM_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x16800, 0x16A3F, SvxResId(RID_SUBSETSTR_BAMUM_SUPPLEMENT) );
+ break;
+ case UBLOCK_KANA_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1B000, 0x1B0FF, SvxResId(RID_SUBSETSTR_KANA_SUPPLEMENT) );
+ break;
+ case UBLOCK_PLAYING_CARDS:
+ aAllSubsets.emplace_back( 0x1F0A0, 0x1F0FF, SvxResId(RID_SUBSETSTR_PLAYING_CARDS) );
+ break;
+ case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS:
+ aAllSubsets.emplace_back( 0x1F300, 0x1F5FF, SvxResId(RID_SUBSETSTR_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS) );
+ break;
+ case UBLOCK_EMOTICONS:
+ aAllSubsets.emplace_back( 0x1F600, 0x1F64F, SvxResId(RID_SUBSETSTR_EMOTICONS) );
+ break;
+ case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1F680, 0x1F6FF, SvxResId(RID_SUBSETSTR_TRANSPORT_AND_MAP_SYMBOLS) );
+ break;
+ case UBLOCK_ALCHEMICAL_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1F700, 0x1F77F, SvxResId(RID_SUBSETSTR_ALCHEMICAL_SYMBOLS) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D:
+ aAllSubsets.emplace_back( 0x2B740, 0x2B81F, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D) );
+ break;
+// Note ICU version 49 (NOT 4.9), so the MAJOR_NUM is two digits.
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+ case UBLOCK_ARABIC_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x08A0, 0x08FF, SvxResId(RID_SUBSETSTR_ARABIC_EXTENDED_A) );
+ break;
+ case UBLOCK_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1EE00, 0x1EEFF, SvxResId(RID_SUBSETSTR_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS) );
+ break;
+ case UBLOCK_CHAKMA:
+ aAllSubsets.emplace_back( 0x11100, 0x1114F, SvxResId(RID_SUBSETSTR_CHAKMA) );
+ break;
+ case UBLOCK_MEETEI_MAYEK_EXTENSIONS:
+ aAllSubsets.emplace_back( 0xAAE0, 0xAAFF, SvxResId(RID_SUBSETSTR_MEETEI_MAYEK_EXTENSIONS) );
+ break;
+ case UBLOCK_MEROITIC_CURSIVE:
+ aAllSubsets.emplace_back( 0x109A0, 0x109FF, SvxResId(RID_SUBSETSTR_MEROITIC_CURSIVE) );
+ break;
+ case UBLOCK_MEROITIC_HIEROGLYPHS:
+ aAllSubsets.emplace_back( 0x10980, 0x1099F, SvxResId(RID_SUBSETSTR_MEROITIC_HIEROGLYPHS) );
+ break;
+ case UBLOCK_MIAO:
+ aAllSubsets.emplace_back( 0x16F00, 0x16F9F, SvxResId(RID_SUBSETSTR_MIAO) );
+ break;
+ case UBLOCK_SHARADA:
+ aAllSubsets.emplace_back( 0x11180, 0x111DF, SvxResId(RID_SUBSETSTR_SHARADA) );
+ break;
+ case UBLOCK_SORA_SOMPENG:
+ aAllSubsets.emplace_back( 0x110D0, 0x110FF, SvxResId(RID_SUBSETSTR_SORA_SOMPENG) );
+ break;
+ case UBLOCK_SUNDANESE_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1CC0, 0x1CCF, SvxResId(RID_SUBSETSTR_SUNDANESE_SUPPLEMENT) );
+ break;
+ case UBLOCK_TAKRI:
+ aAllSubsets.emplace_back( 0x11680, 0x116CF, SvxResId(RID_SUBSETSTR_TAKRI) );
+ break;
+#endif
+#if U_ICU_VERSION_MAJOR_NUM >= 54
+ case UBLOCK_BASSA_VAH:
+ aAllSubsets.emplace_back( 0x16AD0, 0x16AFF, SvxResId(RID_SUBSETSTR_BASSA_VAH) );
+ break;
+ case UBLOCK_CAUCASIAN_ALBANIAN:
+ aAllSubsets.emplace_back( 0x10530, 0x1056F, SvxResId(RID_SUBSETSTR_CAUCASIAN_ALBANIAN) );
+ break;
+ case UBLOCK_COPTIC_EPACT_NUMBERS:
+ aAllSubsets.emplace_back( 0x102E0, 0x102FF, SvxResId(RID_SUBSETSTR_COPTIC_EPACT_NUMBERS) );
+ break;
+ case UBLOCK_COMBINING_DIACRITICAL_MARKS_EXTENDED:
+ aAllSubsets.emplace_back( 0x1AB0, 0x1AFF, SvxResId(RID_SUBSETSTR_COMBINING_DIACRITICAL_MARKS_EXTENDED) );
+ break;
+ case UBLOCK_DUPLOYAN:
+ aAllSubsets.emplace_back( 0x1BC00, 0x1BC9F, SvxResId(RID_SUBSETSTR_DUPLOYAN) );
+ break;
+ case UBLOCK_ELBASAN:
+ aAllSubsets.emplace_back( 0x10500, 0x1052F, SvxResId(RID_SUBSETSTR_ELBASAN) );
+ break;
+ case UBLOCK_GEOMETRIC_SHAPES_EXTENDED:
+ aAllSubsets.emplace_back( 0x1F780, 0x1F7FF, SvxResId(RID_SUBSETSTR_GEOMETRIC_SHAPES_EXTENDED) );
+ break;
+ case UBLOCK_GRANTHA:
+ aAllSubsets.emplace_back( 0x11300, 0x1137F, SvxResId(RID_SUBSETSTR_GRANTHA) );
+ break;
+ case UBLOCK_KHOJKI:
+ aAllSubsets.emplace_back( 0x11200, 0x1124F, SvxResId(RID_SUBSETSTR_KHOJKI) );
+ break;
+ case UBLOCK_KHUDAWADI:
+ aAllSubsets.emplace_back( 0x112B0, 0x112FF, SvxResId(RID_SUBSETSTR_KHUDAWADI) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_E:
+ aAllSubsets.emplace_back( 0xAB30, 0xAB6F, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_E) );
+ break;
+ case UBLOCK_LINEAR_A:
+ aAllSubsets.emplace_back( 0x10600, 0x1077F, SvxResId(RID_SUBSETSTR_LINEAR_A) );
+ break;
+ case UBLOCK_MAHAJANI:
+ aAllSubsets.emplace_back( 0x11150, 0x1117F, SvxResId(RID_SUBSETSTR_MAHAJANI) );
+ break;
+ case UBLOCK_MANICHAEAN:
+ aAllSubsets.emplace_back( 0x10AC0, 0x10AFF, SvxResId(RID_SUBSETSTR_MANICHAEAN) );
+ break;
+ case UBLOCK_MENDE_KIKAKUI:
+ aAllSubsets.emplace_back( 0x1E800, 0x1E8DF, SvxResId(RID_SUBSETSTR_MENDE_KIKAKUI) );
+ break;
+ case UBLOCK_MODI:
+ aAllSubsets.emplace_back( 0x11600, 0x1165F, SvxResId(RID_SUBSETSTR_MODI) );
+ break;
+ case UBLOCK_MRO:
+ aAllSubsets.emplace_back( 0x16A40, 0x16A6F, SvxResId(RID_SUBSETSTR_MRO) );
+ break;
+ case UBLOCK_MYANMAR_EXTENDED_B:
+ aAllSubsets.emplace_back( 0xA9E0, 0xA9FF, SvxResId(RID_SUBSETSTR_MYANMAR_EXTENDED_B) );
+ break;
+ case UBLOCK_NABATAEAN:
+ aAllSubsets.emplace_back( 0x10880, 0x108AF, SvxResId(RID_SUBSETSTR_NABATAEAN) );
+ break;
+ case UBLOCK_OLD_NORTH_ARABIAN:
+ aAllSubsets.emplace_back( 0x10A80, 0x10A9F, SvxResId(RID_SUBSETSTR_OLD_NORTH_ARABIAN) );
+ break;
+ case UBLOCK_OLD_PERMIC:
+ aAllSubsets.emplace_back( 0x10350, 0x1037F, SvxResId(RID_SUBSETSTR_OLD_PERMIC) );
+ break;
+ case UBLOCK_ORNAMENTAL_DINGBATS:
+ aAllSubsets.emplace_back( 0x1F650, 0x1F67F, SvxResId(RID_SUBSETSTR_ORNAMENTAL_DINGBATS) );
+ break;
+ case UBLOCK_PAHAWH_HMONG:
+ aAllSubsets.emplace_back( 0x16B00, 0x16B8F, SvxResId(RID_SUBSETSTR_PAHAWH_HMONG) );
+ break;
+ case UBLOCK_PALMYRENE:
+ aAllSubsets.emplace_back( 0x10860, 0x1087F, SvxResId(RID_SUBSETSTR_PALMYRENE) );
+ break;
+ case UBLOCK_PAU_CIN_HAU:
+ aAllSubsets.emplace_back( 0x11AC0, 0x11AFF, SvxResId(RID_SUBSETSTR_PAU_CIN_HAU) );
+ break;
+ case UBLOCK_PSALTER_PAHLAVI:
+ aAllSubsets.emplace_back( 0x10B80, 0x10BAF, SvxResId(RID_SUBSETSTR_PSALTER_PAHLAVI) );
+ break;
+ case UBLOCK_SHORTHAND_FORMAT_CONTROLS:
+ aAllSubsets.emplace_back( 0x1BCA0, 0x1BCAF, SvxResId(RID_SUBSETSTR_SHORTHAND_FORMAT_CONTROLS) );
+ break;
+ case UBLOCK_SIDDHAM:
+ aAllSubsets.emplace_back( 0x11580, 0x115FF, SvxResId(RID_SUBSETSTR_SIDDHAM) );
+ break;
+ case UBLOCK_SINHALA_ARCHAIC_NUMBERS:
+ aAllSubsets.emplace_back( 0x111E0, 0x111FF, SvxResId(RID_SUBSETSTR_SINHALA_ARCHAIC_NUMBERS) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_ARROWS_C:
+ aAllSubsets.emplace_back( 0x1F800, 0x1F8FF, SvxResId(RID_SUBSETSTR_SUPPLEMENTAL_ARROWS_C) );
+ break;
+ case UBLOCK_TIRHUTA:
+ aAllSubsets.emplace_back( 0x11480, 0x114DF, SvxResId(RID_SUBSETSTR_TIRHUTA) );
+ break;
+ case UBLOCK_WARANG_CITI:
+ aAllSubsets.emplace_back( 0x118A0, 0x118FF, SvxResId(RID_SUBSETSTR_WARANG_CITI) );
+ break;
+#endif
+#if U_ICU_VERSION_MAJOR_NUM >= 56
+ case UBLOCK_AHOM:
+ aAllSubsets.emplace_back( 0x11700, 0x1173F, SvxResId(RID_SUBSETSTR_AHOM) );
+ break;
+ case UBLOCK_ANATOLIAN_HIEROGLYPHS:
+ aAllSubsets.emplace_back( 0x14400, 0x1467F, SvxResId(RID_SUBSETSTR_ANATOLIAN_HIEROGLYPHS) );
+ break;
+ case UBLOCK_CHEROKEE_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0xAB70, 0xABBF, SvxResId(RID_SUBSETSTR_CHEROKEE_SUPPLEMENT) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E:
+ aAllSubsets.emplace_back( 0x2B820, 0x2CEAF, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E) );
+ break;
+ case UBLOCK_EARLY_DYNASTIC_CUNEIFORM:
+ aAllSubsets.emplace_back( 0x12480, 0x1254F, SvxResId(RID_SUBSETSTR_EARLY_DYNASTIC_CUNEIFORM) );
+ break;
+ case UBLOCK_HATRAN:
+ aAllSubsets.emplace_back( 0x108E0, 0x108FF, SvxResId(RID_SUBSETSTR_HATRAN) );
+ break;
+ case UBLOCK_MULTANI:
+ aAllSubsets.emplace_back( 0x11280, 0x112AF, SvxResId(RID_SUBSETSTR_MULTANI) );
+ break;
+ case UBLOCK_OLD_HUNGARIAN:
+ aAllSubsets.emplace_back( 0x10C80, 0x10CFF, SvxResId(RID_SUBSETSTR_OLD_HUNGARIAN) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS:
+ aAllSubsets.emplace_back( 0x1F900, 0x1F9FF, SvxResId(RID_SUBSETSTR_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS) );
+ break;
+ case UBLOCK_SUTTON_SIGNWRITING:
+ aAllSubsets.emplace_back( 0x1D800, 0x1DAAF, SvxResId(RID_SUBSETSTR_SUTTON_SIGNWRITING) );
+ break;
+#endif
+#if (U_ICU_VERSION_MAJOR_NUM >= 58)
+ case UBLOCK_ADLAM:
+ aAllSubsets.emplace_back( 0x1E900, 0x1E95F, SvxResId(RID_SUBSETSTR_ADLAM) );
+ break;
+ case UBLOCK_BHAIKSUKI:
+ aAllSubsets.emplace_back( 0x11C00, 0x11C6F, SvxResId(RID_SUBSETSTR_BHAIKSUKI) );
+ break;
+ case UBLOCK_CYRILLIC_EXTENDED_C:
+ aAllSubsets.emplace_back( 0x1C80, 0x1C8F, SvxResId(RID_SUBSETSTR_CYRILLIC_EXTENDED_C) );
+ break;
+ case UBLOCK_GLAGOLITIC_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1E000, 0x1E02F, SvxResId(RID_SUBSETSTR_GLAGOLITIC_SUPPLEMENT) );
+ break;
+ case UBLOCK_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION:
+ aAllSubsets.emplace_back( 0x16FE0, 0x16FFF, SvxResId(RID_SUBSETSTR_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION) );
+ break;
+ case UBLOCK_MARCHEN:
+ aAllSubsets.emplace_back( 0x11C70, 0x11CBF, SvxResId(RID_SUBSETSTR_MARCHEN) );
+ break;
+ case UBLOCK_MONGOLIAN_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x11660, 0x1167F, SvxResId(RID_SUBSETSTR_MONGOLIAN_SUPPLEMENT) );
+ break;
+ case UBLOCK_NEWA:
+ aAllSubsets.emplace_back( 0x11400, 0x1147F, SvxResId(RID_SUBSETSTR_NEWA) );
+ break;
+ case UBLOCK_OSAGE:
+ aAllSubsets.emplace_back( 0x104B0, 0x104FF, SvxResId(RID_SUBSETSTR_OSAGE) );
+ break;
+ case UBLOCK_TANGUT:
+ aAllSubsets.emplace_back( 0x17000, 0x187FF, SvxResId(RID_SUBSETSTR_TANGUT) );
+ break;
+ case UBLOCK_TANGUT_COMPONENTS:
+ aAllSubsets.emplace_back( 0x18800, 0x18AFF, SvxResId(RID_SUBSETSTR_TANGUT_COMPONENTS) );
+ break;
+#endif
+#if (U_ICU_VERSION_MAJOR_NUM >= 60)
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F:
+ aAllSubsets.emplace_back( 0x2CEB0, 0x2EBE0, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F) );
+ break;
+ case UBLOCK_KANA_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x1B100, 0x1B12F, SvxResId(RID_SUBSETSTR_KANA_EXTENDED_A) );
+ break;
+ case UBLOCK_MASARAM_GONDI:
+ aAllSubsets.emplace_back( 0x11D00, 0x11D5F, SvxResId(RID_SUBSETSTR_MASARAM_GONDI) );
+ break;
+ case UBLOCK_NUSHU:
+ aAllSubsets.emplace_back( 0x1B170, 0x1B2FF, SvxResId(RID_SUBSETSTR_NUSHU) );
+ break;
+ case UBLOCK_SOYOMBO:
+ aAllSubsets.emplace_back( 0x11A50, 0x11AAF, SvxResId(RID_SUBSETSTR_SOYOMBO) );
+ break;
+ case UBLOCK_SYRIAC_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x0860, 0x086f, SvxResId(RID_SUBSETSTR_SYRIAC_SUPPLEMENT) );
+ break;
+ case UBLOCK_ZANABAZAR_SQUARE:
+ aAllSubsets.emplace_back( 0x11A00, 0x11A4F, SvxResId(RID_SUBSETSTR_ZANABAZAR_SQUARE) );
+ break;
+#endif
+#if (U_ICU_VERSION_MAJOR_NUM >= 62)
+ case UBLOCK_CHESS_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1FA00, 0x1FA6F, SvxResId(RID_SUBSETSTR_CHESS_SYMBOLS) );
+ break;
+ case UBLOCK_DOGRA:
+ aAllSubsets.emplace_back( 0x11800, 0x1184F, SvxResId(RID_SUBSETSTR_DOGRA) );
+ break;
+ case UBLOCK_GEORGIAN_EXTENDED:
+ aAllSubsets.emplace_back( 0x1C90, 0x1CBF, SvxResId(RID_SUBSETSTR_GEORGIAN_EXTENDED) );
+ break;
+ case UBLOCK_GUNJALA_GONDI:
+ aAllSubsets.emplace_back( 0x11D60, 0x11DAF, SvxResId(RID_SUBSETSTR_GUNJALA_GONDI) );
+ break;
+ case UBLOCK_HANIFI_ROHINGYA:
+ aAllSubsets.emplace_back( 0x10D00, 0x10D3F, SvxResId(RID_SUBSETSTR_HANIFI_ROHINGYA) );
+ break;
+ case UBLOCK_INDIC_SIYAQ_NUMBERS:
+ aAllSubsets.emplace_back( 0x1EC70, 0x1ECBF, SvxResId(RID_SUBSETSTR_INDIC_SIYAQ_NUMBERS) );
+ break;
+ case UBLOCK_MAKASAR:
+ aAllSubsets.emplace_back( 0x11EE0, 0x11EFF, SvxResId(RID_SUBSETSTR_MAKASAR) );
+ break;
+ case UBLOCK_MAYAN_NUMERALS:
+ aAllSubsets.emplace_back( 0x1D2E0, 0x1D2FF, SvxResId(RID_SUBSETSTR_MAYAN_NUMERALS) );
+ break;
+ case UBLOCK_MEDEFAIDRIN:
+ aAllSubsets.emplace_back( 0x16E40, 0x16E9F, SvxResId(RID_SUBSETSTR_MEDEFAIDRIN) );
+ break;
+ case UBLOCK_OLD_SOGDIAN:
+ aAllSubsets.emplace_back( 0x10F00, 0x10F2F, SvxResId(RID_SUBSETSTR_OLD_SOGDIAN) );
+ break;
+ case UBLOCK_SOGDIAN:
+ aAllSubsets.emplace_back( 0x10F30, 0x10F6F, SvxResId(RID_SUBSETSTR_SOGDIAN) );
+ break;
+#endif
+#if (U_ICU_VERSION_MAJOR_NUM >= 64)
+ case UBLOCK_EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS:
+ aAllSubsets.emplace_back( 0x13430, 0x1343F, SvxResId(RID_SUBSETSTR_EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS) );
+ break;
+ case UBLOCK_ELYMAIC:
+ aAllSubsets.emplace_back( 0x10FE0, 0x10FFF, SvxResId(RID_SUBSETSTR_ELYMAIC) );
+ break;
+ case UBLOCK_NANDINAGARI:
+ aAllSubsets.emplace_back( 0x119A0, 0x119FF, SvxResId(RID_SUBSETSTR_NANDINAGARI) );
+ break;
+ case UBLOCK_NYIAKENG_PUACHUE_HMONG:
+ aAllSubsets.emplace_back( 0x1E100, 0x1E14F, SvxResId(RID_SUBSETSTR_NYIAKENG_PUACHUE_HMONG) );
+ break;
+ case UBLOCK_OTTOMAN_SIYAQ_NUMBERS:
+ aAllSubsets.emplace_back( 0x1ED00, 0x1ED4F, SvxResId(RID_SUBSETSTR_OTTOMAN_SIYAQ_NUMBERS) );
+ break;
+ case UBLOCK_SMALL_KANA_EXTENSION:
+ aAllSubsets.emplace_back( 0x1B130, 0x1B16F, SvxResId(RID_SUBSETSTR_SMALL_KANA_EXTENSION) );
+ break;
+ case UBLOCK_SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x1FA70, 0x1FAFF, SvxResId(RID_SUBSETSTR_SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A) );
+ break;
+ case UBLOCK_TAMIL_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x11FC0, 0x11FFF, SvxResId(RID_SUBSETSTR_TAMIL_SUPPLEMENT) );
+ break;
+ case UBLOCK_WANCHO:
+ aAllSubsets.emplace_back( 0x1E2C0, 0x1E2FF, SvxResId(RID_SUBSETSTR_WANCHO) );
+ break;
+#endif
+#if (U_ICU_VERSION_MAJOR_NUM >= 66)
+ case UBLOCK_CHORASMIAN:
+ aAllSubsets.emplace_back( 0x10FB0, 0x10FDF, SvxResId(RID_SUBSETSTR_CHORASMIAN) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G:
+ aAllSubsets.emplace_back( 0x30000, 0x3134F, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G) );
+ break;
+ case UBLOCK_DIVES_AKURU:
+ aAllSubsets.emplace_back( 0x11900, 0x1195F, SvxResId(RID_SUBSETSTR_DIVES_AKURU) );
+ break;
+ case UBLOCK_KHITAN_SMALL_SCRIPT:
+ aAllSubsets.emplace_back( 0x18B00, 0x18CFF, SvxResId(RID_SUBSETSTR_KHITAN_SMALL_SCRIPT) );
+ break;
+ case UBLOCK_LISU_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x11FB0, 0x11FBF, SvxResId(RID_SUBSETSTR_LISU_SUPPLEMENT) );
+ break;
+ case UBLOCK_SYMBOLS_FOR_LEGACY_COMPUTING:
+ aAllSubsets.emplace_back( 0x1FB00, 0x1FBFF, SvxResId(RID_SUBSETSTR_SYMBOLS_FOR_LEGACY_COMPUTING) );
+ break;
+ case UBLOCK_TANGUT_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x18D00, 0x18D7F, SvxResId(RID_SUBSETSTR_TANGUT_SUPPLEMENT) );
+ break;
+ case UBLOCK_YEZIDI:
+ aAllSubsets.emplace_back( 0x10E80, 0x10EBF, SvxResId(RID_SUBSETSTR_YEZIDI) );
+ break;
+#endif
+#if (U_ICU_VERSION_MAJOR_NUM >= 70)
+ case UBLOCK_ARABIC_EXTENDED_B:
+ aAllSubsets.emplace_back( 0x0870, 0x089F, SvxResId(RID_SUBSETSTR_ARABIC_EXTENDED_B) );
+ break;
+ case UBLOCK_CYPRO_MINOAN:
+ aAllSubsets.emplace_back( 0x12F90, 0x12FFF, SvxResId(RID_SUBSETSTR_CYPRO_MINOAN) );
+ break;
+ case UBLOCK_ETHIOPIC_EXTENDED_B:
+ aAllSubsets.emplace_back( 0x1E7E0, 0x1E7FF, SvxResId(RID_SUBSETSTR_ETHIOPIC_EXTENDED_B) );
+ break;
+ case UBLOCK_KANA_EXTENDED_B:
+ aAllSubsets.emplace_back( 0x1AFF0, 0x1AFFF, SvxResId(RID_SUBSETSTR_KANA_EXTENDED_B) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_F:
+ aAllSubsets.emplace_back( 0x10780, 0x107BF, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_F) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_G:
+ aAllSubsets.emplace_back( 0x1DF00, 0x1DFFF, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_G) );
+ break;
+ case UBLOCK_OLD_UYGHUR:
+ aAllSubsets.emplace_back( 0x10F70, 0x10FAF, SvxResId(RID_SUBSETSTR_OLD_UYGHUR) );
+ break;
+ case UBLOCK_TANGSA:
+ aAllSubsets.emplace_back( 0x16A70, 0x16ACF, SvxResId(RID_SUBSETSTR_TANGSA) );
+ break;
+ case UBLOCK_TOTO:
+ aAllSubsets.emplace_back( 0x1E290, 0x1E2BF, SvxResId(RID_SUBSETSTR_TOTO) );
+ break;
+ case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x11AB0, 0x11ABF, SvxResId(RID_SUBSETSTR_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED_A) );
+ break;
+ case UBLOCK_VITHKUQI:
+ aAllSubsets.emplace_back( 0x10570, 0x105BF, SvxResId(RID_SUBSETSTR_VITHKUQI) );
+ break;
+ case UBLOCK_ZNAMENNY_MUSICAL_NOTATION:
+ aAllSubsets.emplace_back( 0x1CF00, 0x1CFCF, SvxResId(RID_SUBSETSTR_ZNAMENNY_MUSICAL_NOTATION) );
+ break;
+#endif
+
+ }
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+ if (eBlock != UBLOCK_NO_BLOCK &&
+ eBlock != UBLOCK_INVALID_CODE &&
+ eBlock != UBLOCK_COUNT &&
+ eBlock != UBLOCK_HIGH_SURROGATES &&
+ eBlock != UBLOCK_HIGH_PRIVATE_USE_SURROGATES &&
+ eBlock != UBLOCK_LOW_SURROGATES)
+
+ {
+ UBlockCode eBlockStart = ublock_getCode(aAllSubsets.back().GetRangeMin());
+ UBlockCode eBlockEnd = ublock_getCode(aAllSubsets.back().GetRangeMax());
+ assert(eBlockStart == eBlockEnd && eBlockStart == eBlock);
+ }
+#endif
+ }
+
+ std::stable_sort(aAllSubsets.begin(), aAllSubsets.end());
+ return aAllSubsets;
+ }();
+
+ maSubsets = s_aAllSubsets;
+}
+
+void SubsetMap::ApplyCharMap( const FontCharMapRef& rxFontCharMap )
+{
+ if( !rxFontCharMap.is() )
+ return;
+
+ // remove subsets that are not matched in any range
+ maSubsets.erase(std::remove_if(maSubsets.begin(), maSubsets.end(),
+ [&rxFontCharMap](const Subset& rSubset) {
+ sal_uInt32 cMin = rSubset.GetRangeMin();
+ sal_uInt32 cMax = rSubset.GetRangeMax();
+ int nCount = rxFontCharMap->CountCharsInRange( cMin, cMax );
+ return nCount <= 0;
+ }),
+ maSubsets.end());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/compressgraphicdialog.cxx b/svx/source/dialog/compressgraphicdialog.cxx
new file mode 100644
index 000000000..7e80b623e
--- /dev/null
+++ b/svx/source/dialog/compressgraphicdialog.cxx
@@ -0,0 +1,455 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "dlgunit.hxx"
+#include <vcl/fieldvalues.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/weld.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdograf.hxx>
+#include <svx/sdgcpitm.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/graphichelper.hxx>
+#include <svx/compressgraphicdialog.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/propertyvalue.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <tools/stream.hxx>
+#include <unotools/localedatawrapper.hxx>
+
+// tdf#146929 - remember user settings within the current session
+// memp is filled in dtor and restored after initialization
+namespace
+{
+ struct memParam {
+ bool ReduceResolutionCB = false;
+ int MFNewWidth = 1;
+ int MFNewHeight = 1;
+ bool LosslessRB = true;
+ bool JpegCompRB = false;
+ int CompressionMF = 6;
+ int QualityMF = 80;
+ int InterpolationCombo = 3;
+ };
+ memParam memp;
+}
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+
+CompressGraphicsDialog::CompressGraphicsDialog( weld::Window* pParent, SdrGrafObj* pGraphicObj, SfxBindings& rBindings ) :
+ GenericDialogController( pParent, "svx/ui/compressgraphicdialog.ui", "CompressGraphicDialog" ),
+ m_xGraphicObj ( pGraphicObj ),
+ m_aGraphic ( pGraphicObj->GetGraphicObject().GetGraphic() ),
+ m_aViewSize100mm ( pGraphicObj->GetLogicRect().GetSize() ),
+ m_rBindings ( rBindings ),
+ m_dResolution ( 300 )
+{
+ const SdrGrafCropItem& rCrop = m_xGraphicObj->GetMergedItem(SDRATTR_GRAFCROP);
+ m_aCropRectangle = tools::Rectangle(rCrop.GetLeft(), rCrop.GetTop(), rCrop.GetRight(), rCrop.GetBottom());
+
+ Initialize();
+ recallParameter();
+}
+
+CompressGraphicsDialog::CompressGraphicsDialog( weld::Window* pParent, Graphic const & rGraphic, Size rViewSize100mm, tools::Rectangle const & rCropRectangle, SfxBindings& rBindings ) :
+ GenericDialogController( pParent, "svx/ui/compressgraphicdialog.ui", "CompressGraphicDialog" ),
+ m_xGraphicObj ( nullptr ),
+ m_aGraphic ( rGraphic ),
+ m_aViewSize100mm ( rViewSize100mm ),
+ m_aCropRectangle ( rCropRectangle ),
+ m_rBindings ( rBindings ),
+ m_dResolution ( 300 )
+{
+ Initialize();
+ recallParameter();
+}
+
+CompressGraphicsDialog::~CompressGraphicsDialog()
+{
+}
+
+void CompressGraphicsDialog::recallParameter()
+{
+ m_xReduceResolutionCB->set_active( memp.ReduceResolutionCB );
+ if (memp.ReduceResolutionCB && (memp.MFNewWidth > 1))
+ m_xMFNewWidth->set_value( memp.MFNewWidth );
+ if (memp.ReduceResolutionCB && (memp.MFNewHeight > 1))
+ m_xMFNewHeight->set_value( memp.MFNewHeight );
+
+ m_xLosslessRB->set_active( memp.LosslessRB );
+ m_xJpegCompRB->set_active( memp.JpegCompRB );
+ m_xCompressionMF->set_value( memp.CompressionMF );
+ m_xCompressionSlider->set_value( memp.CompressionMF );
+ m_xQualityMF->set_value( memp.QualityMF );
+ m_xQualitySlider->set_value( memp.QualityMF );
+
+ m_xInterpolationCombo->set_active( memp.InterpolationCombo );
+}
+
+void CompressGraphicsDialog::Initialize()
+{
+ m_xLabelGraphicType = m_xBuilder->weld_label("label-graphic-type");
+ m_xFixedText2 = m_xBuilder->weld_label("label-original-size");
+ m_xFixedText3 = m_xBuilder->weld_label("label-view-size");
+ m_xFixedText5 = m_xBuilder->weld_label("label-image-capacity");
+ m_xFixedText6 = m_xBuilder->weld_label("label-new-capacity");
+ m_xJpegCompRB = m_xBuilder->weld_radio_button("radio-jpeg");
+ m_xCompressionMF = m_xBuilder->weld_spin_button("spin-compression");
+ m_xCompressionSlider = m_xBuilder->weld_scale("scale-compression");
+ m_xLosslessRB = m_xBuilder->weld_radio_button("radio-lossless");
+ m_xQualityMF = m_xBuilder->weld_spin_button("spin-quality");
+ m_xQualitySlider = m_xBuilder->weld_scale("scale-quality");
+ m_xReduceResolutionCB = m_xBuilder->weld_check_button("checkbox-reduce-resolution");
+ m_xMFNewWidth = m_xBuilder->weld_spin_button("spin-new-width");
+ m_xMFNewHeight = m_xBuilder->weld_spin_button("spin-new-height");
+ m_xResolutionLB = m_xBuilder->weld_combo_box("combo-resolution");
+ m_xBtnCalculate = m_xBuilder->weld_button("calculate");
+ m_xInterpolationCombo = m_xBuilder->weld_combo_box("interpolation-method-combo");
+ m_xBtnOkay = m_xBuilder->weld_button("ok");
+
+ m_xInterpolationCombo->set_active_text("Lanczos");
+
+ m_xInterpolationCombo->connect_changed(LINK(this, CompressGraphicsDialog, NewInterpolationModifiedHdl));
+
+ m_xMFNewWidth->connect_changed( LINK( this, CompressGraphicsDialog, NewWidthModifiedHdl ));
+ m_xMFNewHeight->connect_changed( LINK( this, CompressGraphicsDialog, NewHeightModifiedHdl ));
+
+ m_xResolutionLB->connect_changed( LINK( this, CompressGraphicsDialog, ResolutionModifiedHdl ));
+ m_xBtnCalculate->connect_clicked( LINK( this, CompressGraphicsDialog, CalculateClickHdl ) );
+
+ m_xLosslessRB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleCompressionRB ) );
+ m_xJpegCompRB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleCompressionRB ) );
+
+ m_xReduceResolutionCB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleReduceResolutionRB ) );
+
+ m_xQualitySlider->connect_value_changed( LINK( this, CompressGraphicsDialog, SlideHdl ));
+ m_xCompressionSlider->connect_value_changed( LINK( this, CompressGraphicsDialog, SlideHdl ));
+ m_xQualityMF->connect_changed( LINK( this, CompressGraphicsDialog, NewQualityModifiedHdl ));
+ m_xCompressionMF->connect_changed( LINK( this, CompressGraphicsDialog, NewCompressionModifiedHdl ));
+
+ m_xJpegCompRB->set_active(true);
+ m_xReduceResolutionCB->set_active(true);
+
+ m_xBtnOkay->connect_clicked( LINK( this, CompressGraphicsDialog, OkayClickHdl ) );
+ UpdateNewWidthMF();
+ UpdateNewHeightMF();
+ UpdateResolutionLB();
+ Update();
+}
+
+void CompressGraphicsDialog::Update()
+{
+ auto pGfxLink = m_aGraphic.GetSharedGfxLink();
+
+ m_xLabelGraphicType->set_label(GraphicHelper::GetImageType(m_aGraphic));
+
+ const FieldUnit eFieldUnit = m_rBindings.GetDispatcher()->GetModule()->GetFieldUnit();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ sal_Unicode cSeparator = rLocaleWrapper.getNumDecimalSep()[0];
+
+ ScopedVclPtrInstance<VirtualDevice> pDummyVDev;
+ pDummyVDev->EnableOutput( false );
+ pDummyVDev->SetMapMode( m_aGraphic.GetPrefMapMode() );
+
+ Size aPixelSize = m_aGraphic.GetSizePixel();
+ Size aOriginalSize100mm(pDummyVDev->PixelToLogic(m_aGraphic.GetSizePixel(), MapMode(MapUnit::Map100thMM)));
+
+ OUString aBitmapSizeString = SvxResId(STR_IMAGE_ORIGINAL_SIZE);
+ OUString aWidthString = GetUnitString( aOriginalSize100mm.Width(), eFieldUnit, cSeparator );
+ OUString aHeightString = GetUnitString( aOriginalSize100mm.Height(), eFieldUnit, cSeparator );
+ aBitmapSizeString = aBitmapSizeString.replaceAll("$(WIDTH)", aWidthString);
+ aBitmapSizeString = aBitmapSizeString.replaceAll("$(HEIGHT)", aHeightString);
+ aBitmapSizeString = aBitmapSizeString.replaceAll("$(WIDTH_IN_PX)", OUString::number(aPixelSize.Width()));
+ aBitmapSizeString = aBitmapSizeString.replaceAll("$(HEIGHT_IN_PX)", OUString::number(aPixelSize.Height()));
+ m_xFixedText2->set_label(aBitmapSizeString);
+
+ int aValX = static_cast<int>(aPixelSize.Width() / GetViewWidthInch());
+
+ OUString aViewSizeString = SvxResId(STR_IMAGE_VIEW_SIZE);
+
+ aWidthString = GetUnitString( m_aViewSize100mm.Width(), eFieldUnit, cSeparator );
+ aHeightString = GetUnitString( m_aViewSize100mm.Height(), eFieldUnit, cSeparator );
+ aViewSizeString = aViewSizeString.replaceAll("$(WIDTH)", aWidthString);
+ aViewSizeString = aViewSizeString.replaceAll("$(HEIGHT)", aHeightString);
+ aViewSizeString = aViewSizeString.replaceAll("$(DPI)", OUString::number(aValX));
+ m_xFixedText3->set_label(aViewSizeString);
+
+ m_aNativeSize = pGfxLink ? pGfxLink->GetDataSize() : 0;
+
+ OUString aNativeSizeString = SvxResId(STR_IMAGE_CAPACITY);
+ aNativeSizeString = aNativeSizeString.replaceAll("$(CAPACITY)", OUString::number( m_aNativeSize / 1024 ));
+ m_xFixedText5->set_label(aNativeSizeString);
+
+ m_xFixedText6->set_label("??");
+}
+
+void CompressGraphicsDialog::UpdateNewWidthMF()
+{
+ int nPixelX = static_cast<sal_Int32>( GetViewWidthInch() * m_dResolution );
+ m_xMFNewWidth->set_value(nPixelX);
+}
+
+void CompressGraphicsDialog::UpdateNewHeightMF()
+{
+ int nPixelY = static_cast<sal_Int32>( GetViewHeightInch() * m_dResolution );
+ m_xMFNewHeight->set_value(nPixelY);
+}
+
+void CompressGraphicsDialog::UpdateResolutionLB()
+{
+ m_xResolutionLB->set_entry_text( OUString::number( static_cast<sal_Int32>(m_dResolution) ) );
+}
+
+double CompressGraphicsDialog::GetViewWidthInch() const
+{
+ return static_cast<double>(vcl::ConvertValue(m_aViewSize100mm.Width(), 2, MapUnit::Map100thMM, FieldUnit::INCH)) / 100.0;
+}
+
+double CompressGraphicsDialog::GetViewHeightInch() const
+{
+ return static_cast<double>(vcl::ConvertValue(m_aViewSize100mm.Height(), 2, MapUnit::Map100thMM, FieldUnit::INCH)) / 100.0;
+}
+
+BmpScaleFlag CompressGraphicsDialog::GetSelectedInterpolationType() const
+{
+ OUString aSelectionText = m_xInterpolationCombo->get_active_text();
+
+ if( aSelectionText == "Lanczos" ) {
+ return BmpScaleFlag::Lanczos;
+ } else if( aSelectionText == "Bilinear" ) {
+ return BmpScaleFlag::BiLinear;
+ } else if( aSelectionText == "Bicubic" ) {
+ return BmpScaleFlag::BiCubic;
+ } else if ( aSelectionText == "None" ) {
+ return BmpScaleFlag::Fast;
+ }
+ return BmpScaleFlag::BestQuality;
+}
+
+void CompressGraphicsDialog::Compress(SvStream& aStream)
+{
+ BitmapEx aBitmap = m_aGraphic.GetBitmapEx();
+ if ( m_xReduceResolutionCB->get_active() )
+ {
+ tools::Long nPixelX = static_cast<tools::Long>( GetViewWidthInch() * m_dResolution );
+ tools::Long nPixelY = static_cast<tools::Long>( GetViewHeightInch() * m_dResolution );
+
+ aBitmap.Scale( Size( nPixelX, nPixelY ), GetSelectedInterpolationType() );
+ }
+ Graphic aScaledGraphic( aBitmap );
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+
+ Sequence< PropertyValue > aFilterData{
+ comphelper::makePropertyValue("Interlaced", sal_Int32(0)),
+ comphelper::makePropertyValue("Compression", static_cast<sal_Int32>(m_xCompressionMF->get_value())),
+ comphelper::makePropertyValue("Quality", static_cast<sal_Int32>(m_xQualityMF->get_value()))
+ };
+
+ OUString aGraphicFormatName = m_xLosslessRB->get_active() ? OUString( "png" ) : OUString( "jpg" );
+
+ sal_uInt16 nFilterFormat = rFilter.GetExportFormatNumberForShortName( aGraphicFormatName );
+ rFilter.ExportGraphic( aScaledGraphic, u"none", aStream, nFilterFormat, &aFilterData );
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, OkayClickHdl, weld::Button&, void )
+{
+ memp.ReduceResolutionCB = m_xReduceResolutionCB->get_active();
+ memp.MFNewWidth = m_xMFNewWidth->get_value();
+ memp.MFNewHeight = m_xMFNewHeight->get_value();
+ memp.LosslessRB = m_xLosslessRB->get_active();
+ memp.JpegCompRB = m_xJpegCompRB->get_active();
+ memp.CompressionMF = m_xCompressionMF->get_value();
+ memp.QualityMF = m_xQualityMF->get_value();
+ memp.InterpolationCombo = m_xInterpolationCombo->get_active();
+ CompressGraphicsDialog::response(RET_OK);
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, NewWidthModifiedHdl, weld::Entry&, void )
+{
+ m_dResolution = m_xMFNewWidth->get_value() / GetViewWidthInch();
+
+ UpdateNewHeightMF();
+ UpdateResolutionLB();
+ Update();
+}
+
+IMPL_LINK( CompressGraphicsDialog, SlideHdl, weld::Scale&, rScale, void )
+{
+ if (&rScale == m_xQualitySlider.get())
+ m_xQualityMF->set_value(m_xQualitySlider->get_value());
+ else
+ m_xCompressionMF->set_value(m_xCompressionSlider->get_value());
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, NewInterpolationModifiedHdl, weld::ComboBox&, void )
+{
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, NewQualityModifiedHdl, weld::Entry&, void )
+{
+ m_xQualitySlider->set_value(m_xQualityMF->get_value());
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, NewCompressionModifiedHdl, weld::Entry&, void )
+{
+ m_xCompressionSlider->set_value(m_xCompressionMF->get_value());
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, NewHeightModifiedHdl, weld::Entry&, void )
+{
+ m_dResolution = m_xMFNewHeight->get_value() / GetViewHeightInch();
+
+ UpdateNewWidthMF();
+ UpdateResolutionLB();
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, ResolutionModifiedHdl, weld::ComboBox&, void )
+{
+ m_dResolution = static_cast<double>(m_xResolutionLB->get_active_text().toInt32());
+
+ UpdateNewWidthMF();
+ UpdateNewHeightMF();
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, ToggleCompressionRB, weld::Toggleable&, void )
+{
+ bool choice = m_xLosslessRB->get_active();
+ m_xCompressionMF->set_sensitive(choice);
+ m_xCompressionSlider->set_sensitive(choice);
+ m_xQualityMF->set_sensitive(!choice);
+ m_xQualitySlider->set_sensitive(!choice);
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, ToggleReduceResolutionRB, weld::Toggleable&, void )
+{
+ bool choice = m_xReduceResolutionCB->get_active();
+ m_xMFNewWidth->set_sensitive(choice);
+ m_xMFNewHeight->set_sensitive(choice);
+ m_xResolutionLB->set_sensitive(choice);
+ m_xInterpolationCombo->set_sensitive(choice);
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, CalculateClickHdl, weld::Button&, void )
+{
+ sal_Int32 aSize = 0;
+
+ if ( m_dResolution > 0.0 )
+ {
+ SvMemoryStream aMemStream;
+ aMemStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
+ Compress( aMemStream );
+ aSize = aMemStream.TellEnd();
+ }
+
+ if ( aSize > 0 )
+ {
+ OUString aSizeAsString = OUString::number(aSize / 1024);
+
+ OUString aReductionSizeAsString;
+ if (m_aNativeSize > 0 )
+ aReductionSizeAsString = OUString::number( static_cast<sal_Int32>((m_aNativeSize - aSize) * 100.0 / m_aNativeSize) );
+ else
+ aReductionSizeAsString = "0";
+
+ OUString aNewSizeString = SvxResId(STR_IMAGE_CAPACITY_WITH_REDUCTION);
+ aNewSizeString = aNewSizeString.replaceAll("$(CAPACITY)", aSizeAsString);
+ aNewSizeString = aNewSizeString.replaceAll("$(REDUCTION)", aReductionSizeAsString);
+ m_xFixedText6->set_label(aNewSizeString);
+ }
+}
+
+tools::Rectangle CompressGraphicsDialog::GetScaledCropRectangle() const
+{
+ if ( m_xReduceResolutionCB->get_active() )
+ {
+ tools::Long nPixelX = static_cast<tools::Long>( GetViewWidthInch() * m_dResolution );
+ tools::Long nPixelY = static_cast<tools::Long>( GetViewHeightInch() * m_dResolution );
+ Size aSize = m_aGraphic.GetBitmapEx().GetSizePixel();
+ double aScaleX = nPixelX / static_cast<double>(aSize.Width());
+ double aScaleY = nPixelY / static_cast<double>(aSize.Height());
+
+ return tools::Rectangle(
+ m_aCropRectangle.Left() * aScaleX,
+ m_aCropRectangle.Top() * aScaleY,
+ m_aCropRectangle.Right() * aScaleX,
+ m_aCropRectangle.Bottom()* aScaleY);
+ }
+ else
+ {
+ return m_aCropRectangle;
+ }
+}
+
+Graphic CompressGraphicsDialog::GetCompressedGraphic()
+{
+ if ( m_dResolution > 0.0 )
+ {
+ SvMemoryStream aMemStream;
+ aMemStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
+ Compress( aMemStream );
+ aMemStream.Seek( STREAM_SEEK_TO_BEGIN );
+ Graphic aResultGraphic;
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ rFilter.ImportGraphic( aResultGraphic, u"import", aMemStream );
+
+ return aResultGraphic;
+ }
+ return Graphic();
+}
+
+SdrGrafObj* CompressGraphicsDialog::GetCompressedSdrGrafObj()
+{
+ if ( m_dResolution > 0.0 )
+ {
+ SdrGrafObj* pNewObject(m_xGraphicObj->CloneSdrObject(m_xGraphicObj->getSdrModelFromSdrObject()));
+
+ if ( m_xReduceResolutionCB->get_active() )
+ {
+ tools::Rectangle aScaledCropedRectangle = GetScaledCropRectangle();
+ SdrGrafCropItem aNewCrop(
+ aScaledCropedRectangle.Left(),
+ aScaledCropedRectangle.Top(),
+ aScaledCropedRectangle.Right(),
+ aScaledCropedRectangle.Bottom());
+
+ pNewObject->SetMergedItem(aNewCrop);
+ }
+ pNewObject->SetGraphic( GetCompressedGraphic() );
+
+ return pNewObject;
+ }
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/connctrl.cxx b/svx/source/dialog/connctrl.cxx
new file mode 100644
index 000000000..0249b5dd9
--- /dev/null
+++ b/svx/source/dialog/connctrl.cxx
@@ -0,0 +1,310 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/svapp.hxx>
+
+#include <svx/connctrl.hxx>
+#include <svx/dlgutil.hxx>
+
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sxelditm.hxx>
+
+#include <vcl/settings.hxx>
+#include <memory>
+
+SvxXConnectionPreview::SvxXConnectionPreview()
+ : pEdgeObj(nullptr)
+ , pView(nullptr)
+{
+ SetMapMode(MapMode(MapUnit::Map100thMM));
+}
+
+void SvxXConnectionPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(118 , 121), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+}
+
+SvxXConnectionPreview::~SvxXConnectionPreview()
+{
+}
+
+void SvxXConnectionPreview::Resize()
+{
+ AdaptSize();
+
+ Invalidate();
+}
+
+void SvxXConnectionPreview::AdaptSize()
+{
+ // Adapt size
+ if( !mxSdrPage )
+ return;
+
+ SetMapMode(MapMode(MapUnit::Map100thMM));
+
+ OutputDevice* pOD = pView->GetFirstOutputDevice(); // GetWin( 0 );
+ tools::Rectangle aRect = mxSdrPage->GetAllObjBoundRect();
+
+ MapMode aMapMode = GetMapMode();
+ aMapMode.SetMapUnit( pOD->GetMapMode().GetMapUnit() );
+ SetMapMode( aMapMode );
+
+ MapMode aDisplayMap( aMapMode );
+ Point aNewPos;
+ Size aNewSize;
+ const Size aWinSize = GetDrawingArea()->get_ref_device().PixelToLogic(GetOutputSizePixel(), aDisplayMap);
+ const tools::Long nWidth = aWinSize.Width();
+ const tools::Long nHeight = aWinSize.Height();
+ if (aRect.GetHeight() == 0)
+ return;
+ double fRectWH = static_cast<double>(aRect.GetWidth()) / aRect.GetHeight();
+ if (nHeight == 0)
+ return;
+ double fWinWH = static_cast<double>(nWidth) / nHeight;
+
+ // Adapt bitmap to Thumb size (not here!)
+ if ( fRectWH < fWinWH)
+ {
+ aNewSize.setWidth( static_cast<tools::Long>( static_cast<double>(nHeight) * fRectWH ) );
+ aNewSize.setHeight( nHeight );
+ }
+ else
+ {
+ aNewSize.setWidth( nWidth );
+ aNewSize.setHeight( static_cast<tools::Long>( static_cast<double>(nWidth) / fRectWH ) );
+ }
+
+ Fraction aFrac1( aWinSize.Width(), aRect.GetWidth() );
+ Fraction aFrac2( aWinSize.Height(), aRect.GetHeight() );
+ Fraction aMinFrac( aFrac1 <= aFrac2 ? aFrac1 : aFrac2 );
+
+ // Implement MapMode
+ aDisplayMap.SetScaleX( aMinFrac );
+ aDisplayMap.SetScaleY( aMinFrac );
+
+ // Centering
+ aNewPos.setX( ( nWidth - aNewSize.Width() ) >> 1 );
+ aNewPos.setY( ( nHeight - aNewSize.Height() ) >> 1 );
+
+ aDisplayMap.SetOrigin(OutputDevice::LogicToLogic(aNewPos, aMapMode, aDisplayMap));
+ SetMapMode( aDisplayMap );
+
+ // Origin
+ aNewPos = aDisplayMap.GetOrigin();
+ aNewPos -= Point( aRect.Left(), aRect.Top() );
+ aDisplayMap.SetOrigin( aNewPos );
+ SetMapMode( aDisplayMap );
+
+ MouseEvent aMEvt( Point(), 1, MouseEventModifiers::NONE, MOUSE_RIGHT );
+ MouseButtonDown( aMEvt );
+}
+
+void SvxXConnectionPreview::Construct()
+{
+ DBG_ASSERT( pView, "No valid view is passed on! ");
+
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+
+ if( nMarkCount >= 1 )
+ {
+ bool bFound = false;
+
+ for( size_t i = 0; i < nMarkCount && !bFound; ++i )
+ {
+ const SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
+ SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nId = pObj->GetObjIdentifier();
+ if( nInv == SdrInventor::Default && nId == SdrObjKind::Edge )
+ {
+ bFound = true;
+
+ // potential memory leak here (!). Create SdrObjList only when there is
+ // not yet one.
+ if(!mxSdrPage)
+ {
+ mxSdrPage = new SdrPage(
+ pView->getSdrModelFromSdrView(),
+ false);
+ }
+
+ const SdrEdgeObj* pTmpEdgeObj = static_cast<const SdrEdgeObj*>(pObj);
+ pEdgeObj = pTmpEdgeObj->CloneSdrObject(mxSdrPage->getSdrModelFromSdrPage());
+
+ SdrObjConnection& rConn1 = pEdgeObj->GetConnection( true );
+ SdrObjConnection& rConn2 = pEdgeObj->GetConnection( false );
+
+ rConn1 = pTmpEdgeObj->GetConnection( true );
+ rConn2 = pTmpEdgeObj->GetConnection( false );
+
+ SdrObject* pTmpObj1 = pTmpEdgeObj->GetConnectedNode( true );
+ SdrObject* pTmpObj2 = pTmpEdgeObj->GetConnectedNode( false );
+
+ if( pTmpObj1 )
+ {
+ SdrObject* pObj1 = pTmpObj1->CloneSdrObject(mxSdrPage->getSdrModelFromSdrPage());
+ mxSdrPage->InsertObject( pObj1 );
+ pEdgeObj->ConnectToNode( true, pObj1 );
+ }
+
+ if( pTmpObj2 )
+ {
+ SdrObject* pObj2 = pTmpObj2->CloneSdrObject(mxSdrPage->getSdrModelFromSdrPage());
+ mxSdrPage->InsertObject( pObj2 );
+ pEdgeObj->ConnectToNode( false, pObj2 );
+ }
+
+ mxSdrPage->InsertObject( pEdgeObj );
+ }
+ }
+ }
+
+ if( !pEdgeObj )
+ {
+ pEdgeObj = new SdrEdgeObj(pView->getSdrModelFromSdrView());
+ }
+
+ AdaptSize();
+}
+
+void SvxXConnectionPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::ALL);
+
+ rRenderContext.SetMapMode(GetMapMode());
+
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ rRenderContext.SetDrawMode(rStyles.GetHighContrastMode() ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR);
+ rRenderContext.SetBackground(Wallpaper(rStyles.GetFieldColor()));
+
+ if (mxSdrPage)
+ {
+ // This will not work anymore. To not start at Adam and Eve, i will
+ // ATM not try to change all this stuff to really using an own model
+ // and a view. I will just try to provide a mechanism to paint such
+ // objects without own model and without a page/view with the new
+ // mechanism.
+
+ // New stuff: Use an ObjectContactOfObjListPainter.
+ sdr::contact::SdrObjectVector aObjectVector;
+
+ for (size_t a = 0; a < mxSdrPage->GetObjCount(); ++a)
+ {
+ SdrObject* pObject = mxSdrPage->GetObj(a);
+ DBG_ASSERT(pObject,
+ "SvxXConnectionPreview::Paint: Corrupt ObjectList (!)");
+ aObjectVector.push_back(pObject);
+ }
+
+ sdr::contact::ObjectContactOfObjListPainter aPainter(rRenderContext, std::move(aObjectVector), nullptr);
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ // do processing
+ aPainter.ProcessDisplay(aDisplayInfo);
+ }
+
+ rRenderContext.Pop();
+}
+
+void SvxXConnectionPreview::SetAttributes( const SfxItemSet& rInAttrs )
+{
+ pEdgeObj->SetMergedItemSetAndBroadcast(rInAttrs);
+
+ Invalidate();
+}
+
+// Get number of lines which are offset based on the preview object
+
+sal_uInt16 SvxXConnectionPreview::GetLineDeltaCount() const
+{
+ const SfxItemSet& rSet = pEdgeObj->GetMergedItemSet();
+ sal_uInt16 nCount(0);
+
+ if(SfxItemState::DONTCARE != rSet.GetItemState(SDRATTR_EDGELINEDELTACOUNT))
+ nCount = rSet.Get(SDRATTR_EDGELINEDELTACOUNT).GetValue();
+
+ return nCount;
+}
+
+bool SvxXConnectionPreview::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ bool bZoomIn = rMEvt.IsLeft() && !rMEvt.IsShift();
+ bool bZoomOut = rMEvt.IsRight() || rMEvt.IsShift();
+ bool bCtrl = rMEvt.IsMod1();
+
+ if( bZoomIn || bZoomOut )
+ {
+ MapMode aMapMode = GetMapMode();
+ Fraction aXFrac = aMapMode.GetScaleX();
+ Fraction aYFrac = aMapMode.GetScaleY();
+ std::unique_ptr<Fraction> pMultFrac;
+
+ if( bZoomIn )
+ {
+ if( bCtrl )
+ pMultFrac.reset(new Fraction( 3, 2 ));
+ else
+ pMultFrac.reset(new Fraction( 11, 10 ));
+ }
+ else
+ {
+ if( bCtrl )
+ pMultFrac.reset(new Fraction( 2, 3 ));
+ else
+ pMultFrac.reset(new Fraction( 10, 11 ));
+ }
+
+ aXFrac *= *pMultFrac;
+ aYFrac *= *pMultFrac;
+ if( static_cast<double>(aXFrac) > 0.001 && static_cast<double>(aXFrac) < 1000.0 &&
+ static_cast<double>(aYFrac) > 0.001 && static_cast<double>(aYFrac) < 1000.0 )
+ {
+ aMapMode.SetScaleX( aXFrac );
+ aMapMode.SetScaleY( aYFrac );
+ SetMapMode( aMapMode );
+
+ Size aOutSize(GetOutputSizePixel());
+ aOutSize = GetDrawingArea()->get_ref_device().PixelToLogic(aOutSize);
+
+ Point aPt( aMapMode.GetOrigin() );
+ tools::Long nX = static_cast<tools::Long>( ( static_cast<double>(aOutSize.Width()) - ( static_cast<double>(aOutSize.Width()) * static_cast<double>(*pMultFrac) ) ) / 2.0 + 0.5 );
+ tools::Long nY = static_cast<tools::Long>( ( static_cast<double>(aOutSize.Height()) - ( static_cast<double>(aOutSize.Height()) * static_cast<double>(*pMultFrac) ) ) / 2.0 + 0.5 );
+ aPt.AdjustX(nX );
+ aPt.AdjustY(nY );
+
+ aMapMode.SetOrigin( aPt );
+ SetMapMode( aMapMode );
+
+ Invalidate();
+ }
+ }
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/contimp.hxx b/svx/source/dialog/contimp.hxx
new file mode 100644
index 000000000..1c7e10959
--- /dev/null
+++ b/svx/source/dialog/contimp.hxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_CONTIMP_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_CONTIMP_HXX
+
+#include <sfx2/ctrlitem.hxx>
+#include "contwnd.hxx"
+#include <vcl/idle.hxx>
+
+class SvxSuperContourDlg;
+
+class SvxContourDlgItem : public SfxControllerItem
+{
+ SvxSuperContourDlg& rDlg;
+
+protected:
+
+ virtual void StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) override;
+
+public:
+
+ SvxContourDlgItem( SvxSuperContourDlg& rDlg, SfxBindings& rBindings );
+};
+
+class ContourWindow;
+
+class StatusColor : public weld::CustomWidgetController
+{
+private:
+ ContourWindow& m_rWnd;
+public:
+ StatusColor(ContourWindow& rWnd)
+ : m_rWnd(rWnd)
+ {
+ }
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
+ {
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_approximate_digit_width() * 3,
+ pDrawingArea->get_text_height());
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ }
+};
+
+class SvxSuperContourDlg
+{
+ Graphic aGraphic;
+ Graphic aUndoGraphic;
+ Graphic aRedoGraphic;
+ Graphic aUpdateGraphic;
+ tools::PolyPolygon aUpdatePolyPoly;
+ Idle aUpdateIdle;
+ Idle aCreateIdle;
+ SfxBindings* mpBindings;
+ void* pUpdateEditingObject;
+ void* pCheckObj;
+ SvxContourDlgItem aContourItem;
+ sal_Int32 mnGrfChanged;
+ bool bExecState;
+ bool bUpdateGraphicLinked;
+ bool bGraphicLinked;
+
+ weld::Dialog& m_rDialog;
+ std::unique_ptr<ContourWindow> m_xContourWnd;
+ std::unique_ptr<StatusColor> m_xStbStatusColor;
+ std::unique_ptr<weld::Toolbar> m_xTbx1;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtfTolerance;
+ std::unique_ptr<weld::Label> m_xStbStatus2;
+ std::unique_ptr<weld::Label> m_xStbStatus3;
+ std::unique_ptr<weld::Button> m_xCancelBtn;
+ std::unique_ptr<weld::CustomWeld> m_xStbStatusColorWeld;
+ std::unique_ptr<weld::CustomWeld> m_xContourWndWeld;
+
+ DECL_LINK( Tbx1ClickHdl, const OString&, void );
+ DECL_LINK( MousePosHdl, GraphCtrl*, void );
+ DECL_LINK( GraphSizeHdl, GraphCtrl*, void );
+ DECL_LINK( UpdateHdl, Timer *, void );
+ DECL_LINK( CreateHdl, Timer *, void );
+ DECL_LINK( StateHdl, GraphCtrl*, void );
+ DECL_LINK( PipetteHdl, ContourWindow&, void );
+ DECL_LINK( PipetteClickHdl, ContourWindow&, void );
+ DECL_LINK( WorkplaceClickHdl, ContourWindow&, void );
+ DECL_LINK( CancelHdl, weld::Button&, void );
+
+ void SetActiveTool(std::string_view rId);
+ void SetActivePoly(std::string_view rId);
+
+ SfxBindings& GetBindings() { return *mpBindings; }
+
+public:
+
+ SvxSuperContourDlg(weld::Builder& rBuilder, weld::Dialog& rDialog, SfxBindings* pBindings);
+ ~SvxSuperContourDlg();
+
+ void SetExecState( bool bEnable );
+
+ void SetGraphic( const Graphic& rGraphic );
+ const Graphic& GetGraphic() const { return aGraphic; }
+ bool IsGraphicChanged() const { return mnGrfChanged > 0; }
+
+ void SetPolyPolygon( const tools::PolyPolygon& rPolyPoly );
+ tools::PolyPolygon GetPolyPolygon();
+
+ const void* GetEditingObject() const { return pCheckObj; }
+
+ void UpdateGraphic( const Graphic& rGraphic, bool bGraphicLinked,
+ const tools::PolyPolygon* pPolyPoly,
+ void* pEditingObj );
+};
+
+
+#endif // INCLUDED_SVX_SOURCE_DIALOG_CONTIMP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/contwnd.cxx b/svx/source/dialog/contwnd.cxx
new file mode 100644
index 000000000..48ace0ac7
--- /dev/null
+++ b/svx/source/dialog/contwnd.cxx
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "contwnd.hxx"
+#include <svx/svdpage.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflclit.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <vcl/ptrstyle.hxx>
+
+using namespace css;
+
+#define TRANSCOL COL_WHITE
+
+ContourWindow::ContourWindow(weld::Dialog* pDialog)
+ : GraphCtrl(pDialog)
+ , aWorkRect(0, 0, 0, 0)
+ , bPipetteMode(false)
+ , bWorkplaceMode(false)
+ , bClickValid(false)
+{
+}
+
+void ContourWindow::SetPolyPolygon(const tools::PolyPolygon& rPolyPoly)
+{
+ SdrPage* pPage = pModel->GetPage(0);
+ const sal_uInt16 nPolyCount = rPolyPoly.Count();
+
+ // First delete all drawing objects
+ aPolyPoly = rPolyPoly;
+
+ // To avoid to have destroyed objects which are still selected, it is necessary to deselect
+ // them first (!)
+ pView->UnmarkAllObj();
+
+ // clear SdrObjects with broadcasting
+ pPage->ClearSdrObjList();
+
+ for (sal_uInt16 i = 0; i < nPolyCount; i++)
+ {
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ aPolyPolygon.append(aPolyPoly[ i ].getB2DPolygon());
+ SdrPathObj* pPathObj = new SdrPathObj(
+ *pModel,
+ SdrObjKind::PathFill,
+ aPolyPolygon);
+
+ SfxItemSet aSet(pModel->GetItemPool());
+
+ aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ aSet.Put(XFillColorItem("", TRANSCOL));
+ aSet.Put(XFillTransparenceItem(50) );
+
+ pPathObj->SetMergedItemSetAndBroadcast(aSet);
+
+ pPage->InsertObject( pPathObj );
+ }
+
+ if (nPolyCount)
+ {
+ pView->MarkAll();
+ pView->CombineMarkedObjects(false);
+ }
+
+ pModel->SetChanged(false);
+}
+
+const tools::PolyPolygon& ContourWindow::GetPolyPolygon()
+{
+ if ( pModel->IsChanged() )
+ {
+ SdrPage* pPage = pModel->GetPage( 0 );
+
+ aPolyPoly = tools::PolyPolygon();
+
+ if ( pPage && pPage->GetObjCount() )
+ {
+ SdrPathObj* pPathObj = static_cast<SdrPathObj*>(pPage->GetObj(0));
+ // Not sure if subdivision is needed for ContourWindow, but maybe it cannot handle
+ // curves at all. Keeping subdivision here for security
+ const basegfx::B2DPolyPolygon aB2DPolyPolygon(basegfx::utils::adaptiveSubdivideByAngle(pPathObj->GetPathPoly()));
+ aPolyPoly = tools::PolyPolygon(aB2DPolyPolygon);
+ }
+
+ pModel->SetChanged( false );
+ }
+
+ return aPolyPoly;
+}
+
+void ContourWindow::InitSdrModel()
+{
+ GraphCtrl::InitSdrModel();
+
+ SfxItemSet aSet( pModel->GetItemPool() );
+
+ aSet.Put( XFillColorItem( "", TRANSCOL ) );
+ aSet.Put( XFillTransparenceItem( 50 ) );
+ pView->SetAttributes( aSet );
+ pView->SetFrameDragSingles();
+}
+
+void ContourWindow::SdrObjCreated( const SdrObject& )
+{
+ pView->MarkAll();
+ pView->CombineMarkedObjects( false );
+}
+
+bool ContourWindow::IsContourChanged() const
+{
+ SdrPage* pPage = pModel->GetPage( 0 );
+ bool bRet = false;
+
+ if ( pPage && pPage->GetObjCount() )
+ bRet = static_cast<SdrPathObj*>( pPage->GetObj( 0 ) )->GetPathPoly().count() && pModel->IsChanged();
+
+ return bRet;
+}
+
+bool ContourWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( bWorkplaceMode )
+ {
+ const Point aLogPt(GetDrawingArea()->get_ref_device().PixelToLogic(rMEvt.GetPosPixel()));
+
+ SetPolyPolygon( tools::PolyPolygon() );
+ aWorkRect = tools::Rectangle( aLogPt, aLogPt );
+ Invalidate(tools::Rectangle(Point(), GetGraphicSize()));
+ SetEditMode( true );
+ }
+
+ if (!bPipetteMode)
+ return GraphCtrl::MouseButtonDown( rMEvt );
+
+ return true;
+}
+
+bool ContourWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ bClickValid = false;
+
+ if ( bPipetteMode )
+ {
+ const Point aLogPt( GetDrawingArea()->get_ref_device().PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ aPipetteColor = GetDrawingArea()->get_ref_device().GetPixel( aLogPt );
+ weld::CustomWidgetController::MouseMove( rMEvt );
+
+ if ( aPipetteLink.IsSet() && tools::Rectangle( Point(), GetGraphicSize() ).Contains( aLogPt ) )
+ {
+ SetPointer( PointerStyle::RefHand );
+ aPipetteLink.Call( *this );
+ }
+
+ return true;
+ }
+
+ return GraphCtrl::MouseMove( rMEvt );
+}
+
+bool ContourWindow::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ const tools::Rectangle aGraphRect( Point(), GetGraphicSize() );
+ const Point aLogPt( GetDrawingArea()->get_ref_device().PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ bClickValid = aGraphRect.Contains( aLogPt );
+ ReleaseMouse();
+
+ if ( bPipetteMode )
+ {
+ weld::CustomWidgetController::MouseButtonUp( rMEvt );
+
+ aPipetteClickLink.Call( *this );
+
+ return true;
+ }
+ else if ( bWorkplaceMode )
+ {
+ GraphCtrl::MouseButtonUp( rMEvt );
+
+ aWorkRect.SetRight( aLogPt.X() );
+ aWorkRect.SetBottom( aLogPt.Y() );
+ aWorkRect.Intersection( aGraphRect );
+ aWorkRect.Justify();
+
+ if ( aWorkRect.Left() != aWorkRect.Right() && aWorkRect.Top() != aWorkRect.Bottom() )
+ {
+ tools::PolyPolygon _aPolyPoly( GetPolyPolygon() );
+
+ _aPolyPoly.Clip( aWorkRect );
+ SetPolyPolygon( _aPolyPoly );
+ pView->SetWorkArea( aWorkRect );
+ }
+ else
+ pView->SetWorkArea( aGraphRect );
+
+ Invalidate( aGraphRect );
+
+ aWorkplaceClickLink.Call( *this );
+
+ return false;
+ }
+
+ return GraphCtrl::MouseButtonUp( rMEvt );
+}
+
+void ContourWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ // #i75482#
+ // encapsulate the redraw using Begin/End and use the returned
+ // data to get the target output device (e.g. when pre-rendering)
+ SdrPaintWindow* pPaintWindow = pView->BeginCompleteRedraw(&rRenderContext);
+ pPaintWindow->SetOutputToWindow(true);
+ OutputDevice& rTarget = pPaintWindow->GetTargetOutputDevice();
+
+ const Graphic& rGraphic = GetGraphic();
+ rTarget.Push(vcl::PushFlags::LINECOLOR |vcl::PushFlags::FILLCOLOR);
+ rTarget.SetLineColor(COL_BLACK);
+ rTarget.SetFillColor(COL_WHITE);
+ rTarget.DrawRect( tools::Rectangle( Point(), GetGraphicSize() ) );
+ rTarget.Pop();
+
+ if (rGraphic.GetType() != GraphicType::NONE)
+ rGraphic.Draw(rTarget, Point(), GetGraphicSize());
+
+ if (aWorkRect.Left() != aWorkRect.Right() && aWorkRect.Top() != aWorkRect.Bottom())
+ {
+ tools::PolyPolygon _aPolyPoly(2);
+ rTarget.Push(vcl::PushFlags::FILLCOLOR);
+ _aPolyPoly.Insert(tools::Rectangle(Point(), GetGraphicSize()));
+ _aPolyPoly.Insert(aWorkRect);
+ rTarget.SetFillColor(COL_LIGHTRED);
+ rTarget.DrawTransparent(_aPolyPoly, 50);
+ rTarget.Pop();
+ }
+
+ // #i75482#
+ const vcl::Region aRepaintRegion(rRect);
+ pView->DoCompleteRedraw(*pPaintWindow, aRepaintRegion);
+ pView->EndCompleteRedraw(*pPaintWindow, true);
+}
+
+void ContourWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ GraphCtrl::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(270, 170), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ SetSdrMode(true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/contwnd.hxx b/svx/source/dialog/contwnd.hxx
new file mode 100644
index 000000000..1bad623c0
--- /dev/null
+++ b/svx/source/dialog/contwnd.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_CONTWND_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_CONTWND_HXX
+
+#include <tools/poly.hxx>
+#include <svx/graphctl.hxx>
+
+class ContourWindow final : public GraphCtrl
+{
+ tools::PolyPolygon aPolyPoly;
+ Color aPipetteColor;
+ tools::Rectangle aWorkRect;
+ Link<ContourWindow&,void> aPipetteLink;
+ Link<ContourWindow&,void> aPipetteClickLink;
+ Link<ContourWindow&,void> aWorkplaceClickLink;
+ bool bPipetteMode;
+ bool bWorkplaceMode;
+ bool bClickValid;
+
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void SdrObjCreated( const SdrObject& rObj ) override;
+ virtual void InitSdrModel() override;
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+public:
+
+ ContourWindow(weld::Dialog* pDialog);
+
+ void SetPolyPolygon( const tools::PolyPolygon& rPolyPoly );
+ const tools::PolyPolygon& GetPolyPolygon();
+
+ void SetPipetteMode( const bool bPipette ) { bPipetteMode = bPipette; }
+ const Color& GetPipetteColor() const { return aPipetteColor; }
+
+ bool IsClickValid() const { return bClickValid; }
+ bool IsContourChanged() const;
+
+ void SetWorkplaceMode( const bool bWorkplace ) { bWorkplaceMode = bWorkplace; }
+ const tools::Rectangle& GetWorkRect() const { return aWorkRect; }
+
+ void SetPipetteHdl( const Link<ContourWindow&,void>& rLink ) { aPipetteLink = rLink; }
+ void SetPipetteClickHdl( const Link<ContourWindow&,void>& rLink ) { aPipetteClickLink = rLink; }
+ void SetWorkplaceClickHdl( const Link<ContourWindow&,void>& rLink ) { aWorkplaceClickLink = rLink; }
+};
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/crashreportdlg.cxx b/svx/source/dialog/crashreportdlg.cxx
new file mode 100644
index 000000000..33c879866
--- /dev/null
+++ b/svx/source/dialog/crashreportdlg.cxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "crashreportdlg.hxx"
+
+#include <desktop/crashreport.hxx>
+#include <sfx2/safemode.hxx>
+#include <comphelper/processfactory.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <unotools/configmgr.hxx>
+#include <officecfg/Office/Common.hxx>
+
+#include <com/sun/star/task/OfficeRestartManager.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+
+CrashReportDialog::CrashReportDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "svx/ui/crashreportdlg.ui", "CrashReportDialog")
+ , mxBtnSend(m_xBuilder->weld_button("btn_send"))
+ , mxBtnCancel(m_xBuilder->weld_button("btn_cancel"))
+ , mxBtnClose(m_xBuilder->weld_button("btn_close"))
+ , mxEditPreUpload(m_xBuilder->weld_label("ed_pre"))
+ , mxEditPostUpload(m_xBuilder->weld_text_view("ed_post"))
+ , mxFtBugReport(m_xBuilder->weld_text_view("ed_bugreport"))
+ , mxCBSafeMode(m_xBuilder->weld_check_button("check_safemode"))
+ , mxPrivacyPolicyButton(m_xBuilder->weld_link_button("btnPrivacyPolicy"))
+{
+ maSuccessMsg = mxEditPostUpload->get_text();
+
+ auto nWidth = mxEditPreUpload->get_preferred_size().Width();
+ nWidth = std::max(nWidth, mxCBSafeMode->get_size_request().Width());
+ mxEditPreUpload->set_size_request(nWidth, -1);
+ mxCBSafeMode->set_size_request(nWidth, -1);
+
+ mxBtnSend->connect_clicked(LINK(this, CrashReportDialog, BtnHdl));
+ mxBtnCancel->connect_clicked(LINK(this, CrashReportDialog, BtnHdl));
+ mxBtnClose->connect_clicked(LINK(this, CrashReportDialog, BtnHdl));
+
+ mxPrivacyPolicyButton->set_uri(
+ officecfg::Office::Common::Menus::PrivacyPolicyURL::get()
+ + "?type=crashreport&LOvers=" + utl::ConfigManager::getProductVersion()
+ + "&LOlocale=" + LanguageTag(utl::ConfigManager::getUILocale()).getBcp47());
+}
+
+CrashReportDialog::~CrashReportDialog() {}
+
+short CrashReportDialog::run()
+{
+ short nRet = GenericDialogController::run();
+
+ // Check whether to go to safe mode
+ if (mxCBSafeMode->get_active())
+ {
+ sfx2::SafeMode::putFlag();
+ css::task::OfficeRestartManager::get(comphelper::getProcessComponentContext())
+ ->requestRestart(css::uno::Reference<css::task::XInteractionHandler>());
+ }
+ return nRet;
+}
+
+IMPL_LINK(CrashReportDialog, BtnHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == mxBtnSend.get())
+ {
+ std::string response;
+ bool bSuccess = CrashReporter::readSendConfig(response);
+
+ OUString aCrashID = OUString::createFromAscii(response.c_str());
+
+ if (bSuccess)
+ {
+ OUString aProcessedMessage
+ = maSuccessMsg.replaceAll("%CRASHID", aCrashID.replaceAll("Crash-ID=", ""));
+
+ // vclbuilder seems to replace _ with ~ even in text
+ mxEditPostUpload->set_text(aProcessedMessage.replaceAll("~", "_"));
+ }
+ else
+ {
+ mxEditPostUpload->set_text(aCrashID);
+ }
+
+ mxBtnClose->show();
+ mxFtBugReport->show();
+ mxEditPostUpload->show();
+ mxBtnSend->set_sensitive(false);
+ mxBtnCancel->set_sensitive(false);
+ mxBtnClose->grab_focus();
+
+ mxEditPreUpload->hide();
+ mxBtnSend->hide();
+ mxBtnCancel->hide();
+
+ m_xDialog->resize_to_request();
+ }
+ else if (&rBtn == mxBtnCancel.get())
+ {
+ m_xDialog->response(RET_CLOSE);
+ }
+ else if (&rBtn == mxBtnClose.get())
+ {
+ m_xDialog->response(RET_CLOSE);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/crashreportdlg.hxx b/svx/source/dialog/crashreportdlg.hxx
new file mode 100644
index 000000000..868f86c58
--- /dev/null
+++ b/svx/source/dialog/crashreportdlg.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_CRASHREPORTDLG_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_CRASHREPORTDLG_HXX
+
+#include <vcl/weld.hxx>
+
+class CrashReportDialog : public weld::GenericDialogController
+{
+public:
+ explicit CrashReportDialog(weld::Window* pParent);
+ virtual short run() override;
+ virtual ~CrashReportDialog() override;
+
+private:
+ std::unique_ptr<weld::Button> mxBtnSend;
+ std::unique_ptr<weld::Button> mxBtnCancel;
+ std::unique_ptr<weld::Button> mxBtnClose;
+ std::unique_ptr<weld::Label> mxEditPreUpload;
+ std::unique_ptr<weld::TextView> mxEditPostUpload;
+ std::unique_ptr<weld::TextView> mxFtBugReport;
+ std::unique_ptr<weld::CheckButton> mxCBSafeMode;
+ std::unique_ptr<weld::LinkButton> mxPrivacyPolicyButton;
+
+ OUString maSuccessMsg;
+
+ DECL_LINK(BtnHdl, weld::Button&, void);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/crashreportui.cxx b/svx/source/dialog/crashreportui.cxx
new file mode 100644
index 000000000..5384e3c18
--- /dev/null
+++ b/svx/source/dialog/crashreportui.cxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/frame/XSynchronousDispatch.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include "crashreportdlg.hxx"
+
+namespace {
+
+class CrashReportUI : public ::cppu::WeakImplHelper< css::lang::XServiceInfo ,
+ css::frame::XSynchronousDispatch > // => XDispatch!
+{
+public:
+ explicit CrashReportUI();
+
+ // css.lang.XServiceInfo
+
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(const OUString& sServiceName) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+
+ virtual css::uno::Any SAL_CALL dispatchWithReturnValue(const css::util::URL& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override;
+};
+
+CrashReportUI::CrashReportUI()
+{
+
+}
+
+OUString SAL_CALL CrashReportUI::getImplementationName()
+{
+ return "com.sun.star.comp.svx.CrashReportUI";
+}
+
+sal_Bool SAL_CALL CrashReportUI::supportsService(const OUString& sServiceName)
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL CrashReportUI::getSupportedServiceNames()
+{
+ return { "com.sun.star.dialog.CrashReportUI" };
+}
+
+css::uno::Any SAL_CALL CrashReportUI::dispatchWithReturnValue(const css::util::URL&,
+ const css::uno::Sequence< css::beans::PropertyValue >& )
+{
+ SolarMutexGuard aGuard;
+ css::uno::Any aRet;
+ CrashReportDialog aDialog(nullptr);
+ aDialog.run();
+ return aRet;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_CrashReportUI_get_implementation(
+ css::uno::XComponentContext * /*context*/,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new CrashReportUI());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ctredlin.cxx b/svx/source/dialog/ctredlin.cxx
new file mode 100644
index 000000000..3a0f1e32e
--- /dev/null
+++ b/svx/source/dialog/ctredlin.cxx
@@ -0,0 +1,1000 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <o3tl/safeint.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/weldutils.hxx>
+#include <svtools/ctrlbox.hxx>
+#include <unotools/textsearch.hxx>
+
+#include <helpids.h>
+
+#include <svx/ctredlin.hxx>
+
+#define WRITER_DATE 2
+#define CALC_DATE 3
+
+RedlinData::RedlinData()
+ : aDateTime(DateTime::EMPTY)
+ , pData(nullptr)
+ , eType(RedlineType::Any)
+ , bDisabled(false)
+{
+}
+
+RedlinData::~RedlinData()
+{
+}
+
+SvxRedlinTable::SvxRedlinTable(std::unique_ptr<weld::TreeView> xWriterControl,
+ std::unique_ptr<weld::TreeView> xCalcControl)
+ : xSorter(new comphelper::string::NaturalStringSorter(::comphelper::getProcessComponentContext(),
+ Application::GetSettings().GetUILanguageTag().getLocale()))
+ , xWriterTreeView(std::move(xWriterControl))
+ , xCalcTreeView(std::move(xCalcControl))
+ , pTreeView(nullptr)
+ , nDatePos(WRITER_DATE)
+ , bAuthor(false)
+ , bDate(false)
+ , bComment(false)
+ , bSorted(false)
+ , nDaTiMode(SvxRedlinDateMode::BEFORE)
+ , aDaTiFirst( DateTime::EMPTY )
+ , aDaTiLast( DateTime::EMPTY )
+ , aDaTiFilterFirst( DateTime::EMPTY )
+ , aDaTiFilterLast( DateTime::EMPTY )
+{
+ if (xWriterTreeView)
+ {
+ xWriterTreeView->connect_column_clicked(LINK(this, SvxRedlinTable, HeaderBarClick));
+ xWriterTreeView->set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter& rRight){
+ return ColCompare(rLeft, rRight);
+ });
+ pTreeView = xWriterTreeView.get();
+ }
+ if (xCalcTreeView)
+ {
+ xCalcTreeView->connect_column_clicked(LINK(this, SvxRedlinTable, HeaderBarClick));
+ xCalcTreeView->set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter& rRight){
+ return ColCompare(rLeft, rRight);
+ });
+ pTreeView = xCalcTreeView.get();
+ }
+}
+
+SvxRedlinTable::~SvxRedlinTable()
+{
+}
+
+IMPL_LINK(SvxRedlinTable, HeaderBarClick, int, nColumn, void)
+{
+ if (!bSorted)
+ {
+ pTreeView->make_sorted();
+ bSorted = true;
+ }
+
+ bool bSortAtoZ = pTreeView->get_sort_order();
+
+ //set new arrow positions in headerbar
+ if (nColumn == pTreeView->get_sort_column())
+ {
+ bSortAtoZ = !bSortAtoZ;
+ pTreeView->set_sort_order(bSortAtoZ);
+ }
+ else
+ {
+ int nOldSortColumn = pTreeView->get_sort_column();
+ if (nOldSortColumn != -1)
+ pTreeView->set_sort_indicator(TRISTATE_INDET, nOldSortColumn);
+ pTreeView->set_sort_column(nColumn);
+ }
+
+ if (nColumn != -1)
+ {
+ //sort lists
+ pTreeView->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
+ }
+}
+
+int SvxRedlinTable::ColCompare(const weld::TreeIter& rLeft, const weld::TreeIter& rRight)
+{
+ sal_Int32 nCompare = 0;
+
+ int nSortCol = pTreeView->get_sort_column();
+
+ if (pTreeView == xWriterTreeView.get() && nSortCol == 0)
+ {
+ RedlinData *pLeftData = weld::fromId<RedlinData*>(pTreeView->get_id(rLeft));
+ RedlinData *pRightData = weld::fromId<RedlinData*>(pTreeView->get_id(rRight));
+
+ if (pLeftData && pRightData)
+ {
+ if (pLeftData->eType < pRightData->eType)
+ nCompare = -1;
+ else if (pLeftData->eType > pRightData->eType)
+ nCompare = 1;
+ return nCompare;
+ }
+ }
+
+ if (nSortCol == nDatePos)
+ {
+ RedlinData *pLeftData = weld::fromId<RedlinData*>(pTreeView->get_id(rLeft));
+ RedlinData *pRightData = weld::fromId<RedlinData*>(pTreeView->get_id(rRight));
+
+ if (pLeftData && pRightData)
+ {
+ if (pLeftData->aDateTime < pRightData->aDateTime)
+ nCompare = -1;
+ else if (pLeftData->aDateTime > pRightData->aDateTime)
+ nCompare = 1;
+ return nCompare;
+ }
+ }
+
+ return xSorter->compare(pTreeView->get_text(rLeft, nSortCol),
+ pTreeView->get_text(rRight, nSortCol));
+}
+
+void SvxRedlinTable::UpdateFilterTest()
+{
+ Date aDateMax( Date::SYSTEM );
+ aDateMax.AddYears(100);
+ Date aDateMin(1,1,1989);
+ tools::Time aTMin(0);
+ tools::Time aTMax(23,59,59);
+
+ DateTime aDTMin(aDateMin);
+ DateTime aDTMax(aDateMax);
+
+ switch(nDaTiMode)
+ {
+ case SvxRedlinDateMode::BEFORE:
+ aDaTiFilterFirst=aDTMin;
+ aDaTiFilterLast=aDaTiFirst;
+ break;
+ case SvxRedlinDateMode::SAVE:
+ case SvxRedlinDateMode::SINCE:
+ aDaTiFilterFirst=aDaTiFirst;
+ aDaTiFilterLast=aDTMax;
+ break;
+ case SvxRedlinDateMode::EQUAL:
+ aDaTiFilterFirst=aDaTiFirst;
+ aDaTiFilterLast=aDaTiFirst;
+ aDaTiFilterFirst.SetTime(aTMin.GetTime());
+ aDaTiFilterLast.SetTime(aTMax.GetTime());
+ break;
+ case SvxRedlinDateMode::NOTEQUAL:
+ aDaTiFilterFirst=aDaTiFirst;
+ aDaTiFilterLast=aDaTiFirst;
+ aDaTiFilterFirst.SetTime(aTMin.GetTime());
+ aDaTiFilterLast.SetTime(aTMax.GetTime());
+ break;
+ case SvxRedlinDateMode::BETWEEN:
+ aDaTiFilterFirst=aDaTiFirst;
+ aDaTiFilterLast=aDaTiLast;
+ break;
+ case SvxRedlinDateMode::NONE:
+ break;
+ }
+}
+
+void SvxRedlinTable::SetFilterDate(bool bFlag)
+{
+ bDate=bFlag;
+}
+
+void SvxRedlinTable::SetDateTimeMode(SvxRedlinDateMode nMode)
+{
+ nDaTiMode=nMode;
+}
+
+void SvxRedlinTable::SetFirstDate(const Date& aDate)
+{
+ aDaTiFirst.SetDate(aDate.GetDate());
+}
+
+void SvxRedlinTable::SetLastDate(const Date& aDate)
+{
+ aDaTiLast.SetDate(aDate.GetDate());
+}
+
+void SvxRedlinTable::SetFirstTime(const tools::Time& aTime)
+{
+ aDaTiFirst.SetTime(aTime.GetTime());
+}
+
+void SvxRedlinTable::SetLastTime(const tools::Time& aTime)
+{
+ aDaTiLast.SetTime(aTime.GetTime());
+}
+
+void SvxRedlinTable::SetFilterAuthor(bool bFlag)
+{
+ bAuthor=bFlag;
+}
+
+void SvxRedlinTable::SetAuthor(const OUString &aString)
+{
+ aAuthor=aString;
+}
+
+void SvxRedlinTable::SetFilterComment(bool bFlag)
+{
+ bComment=bFlag;
+}
+
+void SvxRedlinTable::SetCommentParams( const utl::SearchParam* pSearchPara )
+{
+ if(pSearchPara!=nullptr)
+ {
+ pCommentSearcher.reset(new utl::TextSearch(*pSearchPara, LANGUAGE_SYSTEM ));
+ }
+}
+
+bool SvxRedlinTable::IsValidEntry(std::u16string_view rAuthorStr,
+ const DateTime &rDateTime,
+ const OUString &rCommentStr)
+{
+ return IsValidEntry(rAuthorStr, rDateTime) && IsValidComment(rCommentStr);
+}
+
+bool SvxRedlinTable::IsValidEntry(std::u16string_view rAuthorStr, const DateTime &rDateTime)
+{
+ if (bAuthor && aAuthor!=rAuthorStr)
+ return false;
+
+ if (!bDate)
+ return true;
+
+ const bool bRes = rDateTime.IsBetween(aDaTiFilterFirst, aDaTiFilterLast);
+ return nDaTiMode!=SvxRedlinDateMode::NOTEQUAL ? bRes : !bRes;
+}
+
+bool SvxRedlinTable::IsValidComment(const OUString &rCommentStr)
+{
+ if (!bComment)
+ return true;
+
+ sal_Int32 nStartPos = 0;
+ sal_Int32 nEndPos = rCommentStr.getLength();
+ return pCommentSearcher->SearchForward( rCommentStr, &nStartPos, &nEndPos);
+}
+
+SvxTPage::~SvxTPage()
+{
+}
+
+void SvxTPage::ActivatePage()
+{
+}
+
+SvxTPView::SvxTPView(weld::Container* pParent)
+ : SvxTPage(pParent, "svx/ui/redlineviewpage.ui", "RedlineViewPage")
+ , bEnableAccept(true)
+ , bEnableAcceptAll(true)
+ , bEnableReject(true)
+ , bEnableRejectAll(true)
+ , bEnableUndo(true)
+ , bEnableClearFormat(false)
+ , bEnableClearFormatAll(false)
+ , m_xAccept(m_xBuilder->weld_button("accept"))
+ , m_xReject(m_xBuilder->weld_button("reject"))
+ , m_xAcceptAll(m_xBuilder->weld_button("acceptall"))
+ , m_xRejectAll(m_xBuilder->weld_button("rejectall"))
+ , m_xUndo(m_xBuilder->weld_button("undo"))
+ , m_xViewData(new SvxRedlinTable(m_xBuilder->weld_tree_view("writerchanges"),
+ m_xBuilder->weld_tree_view("calcchanges")))
+{
+ Link<weld::Button&,void> aLink=LINK( this, SvxTPView, PbClickHdl);
+
+ m_xAccept->connect_clicked(aLink);
+ m_xAcceptAll->connect_clicked(aLink);
+ m_xReject->connect_clicked(aLink);
+ m_xRejectAll->connect_clicked(aLink);
+ m_xUndo->connect_clicked(aLink);
+}
+
+void SvxTPView::ActivatePage()
+{
+ m_xAccept->set_sensitive(bEnableAccept);
+ m_xReject->set_sensitive(bEnableReject);
+ m_xAcceptAll->set_sensitive(bEnableAcceptAll);
+ m_xRejectAll->set_sensitive(bEnableRejectAll);
+ m_xUndo->set_sensitive(bEnableUndo);
+}
+
+void SvxTPView::DeactivatePage()
+{
+ m_xAccept->set_sensitive(false);
+ m_xReject->set_sensitive(false);
+ m_xAcceptAll->set_sensitive(false);
+ m_xRejectAll->set_sensitive(false);
+ m_xUndo->set_sensitive(false);
+}
+
+SvxTPView::~SvxTPView()
+{
+}
+
+void SvxRedlinTable::SetWriterView()
+{
+ nDatePos = WRITER_DATE;
+ if (xCalcTreeView)
+ xCalcTreeView->hide();
+ xWriterTreeView->show();
+ pTreeView = xWriterTreeView.get();
+
+ auto nDigitWidth = pTreeView->get_approximate_digit_width();
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(nDigitWidth * 10),
+ o3tl::narrowing<int>(nDigitWidth * 20),
+ o3tl::narrowing<int>(nDigitWidth * 20)
+ };
+ pTreeView->set_column_fixed_widths(aWidths);
+}
+
+void SvxRedlinTable::SetCalcView()
+{
+ nDatePos = CALC_DATE;
+ if (xWriterTreeView)
+ xWriterTreeView->hide();
+ xCalcTreeView->show();
+ pTreeView = xCalcTreeView.get();
+
+ auto nDigitWidth = pTreeView->get_approximate_digit_width();
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(nDigitWidth * 20),
+ o3tl::narrowing<int>(nDigitWidth * 20),
+ o3tl::narrowing<int>(nDigitWidth * 20),
+ o3tl::narrowing<int>(nDigitWidth * 20)
+ };
+ pTreeView->set_column_fixed_widths(aWidths);
+}
+
+void SvxTPView::EnableAccept(bool bFlag)
+{
+ bEnableAccept = bFlag;
+ m_xAccept->set_sensitive(bFlag);
+}
+
+void SvxTPView::EnableAcceptAll(bool bFlag)
+{
+ bEnableAcceptAll = bFlag;
+ m_xAcceptAll->set_sensitive(bFlag);
+}
+
+void SvxTPView::EnableReject(bool bFlag)
+{
+ bEnableReject = bFlag;
+ m_xReject->set_sensitive(bFlag);
+}
+
+void SvxTPView::EnableRejectAll(bool bFlag)
+{
+ bEnableRejectAll = bFlag;
+ m_xRejectAll->set_sensitive(bFlag);
+}
+
+void SvxTPView::EnableClearFormat(bool bFlag)
+{
+ if (bEnableClearFormat == bFlag)
+ return;
+ bEnableClearFormat = bFlag;
+}
+
+void SvxTPView::EnableClearFormatAll(bool bFlag)
+{
+ if (bEnableClearFormatAll == bFlag)
+ return;
+ bEnableClearFormatAll = bFlag;
+}
+
+void SvxTPView::ShowUndo()
+{
+ m_xUndo->show();
+}
+
+void SvxTPView::EnableUndo(bool bFlag)
+{
+ bEnableUndo = bFlag;
+ m_xUndo->set_sensitive(bFlag);
+}
+
+IMPL_LINK( SvxTPView, PbClickHdl, weld::Button&, rPushB, void)
+{
+ if (&rPushB == m_xAccept.get())
+ {
+ AcceptClickLk.Call(this);
+ }
+ else if (&rPushB == m_xAcceptAll.get())
+ {
+ AcceptAllClickLk.Call(this);
+ }
+ else if (&rPushB == m_xReject.get())
+ {
+ RejectClickLk.Call(this);
+ }
+ else if (&rPushB == m_xRejectAll.get())
+ {
+ RejectAllClickLk.Call(this);
+ }
+ else if (&rPushB == m_xUndo.get())
+ {
+ UndoClickLk.Call(this);
+ }
+}
+
+SvxTPage::SvxTPage(weld::Container* pParent, const OUString& rUIXMLDescription, const OString& rID)
+ : m_xBuilder(Application::CreateBuilder(pParent, rUIXMLDescription))
+ , m_xContainer(m_xBuilder->weld_container(rID))
+{
+}
+
+SvxTPFilter::SvxTPFilter(weld::Container* pParent)
+ : SvxTPage(pParent, "svx/ui/redlinefilterpage.ui", "RedlineFilterPage")
+ , bModified(false)
+ , m_pRedlinTable(nullptr)
+ , m_xCbDate(m_xBuilder->weld_check_button("date"))
+ , m_xLbDate(m_xBuilder->weld_combo_box("datecond"))
+ , m_xDfDate(new SvtCalendarBox(m_xBuilder->weld_menu_button("startdate")))
+ , m_xTfDate(m_xBuilder->weld_formatted_spin_button("starttime"))
+ , m_xTfDateFormatter(new weld::TimeFormatter(*m_xTfDate))
+ , m_xIbClock(m_xBuilder->weld_button("startclock"))
+ , m_xFtDate2(m_xBuilder->weld_label("and"))
+ , m_xDfDate2(new SvtCalendarBox(m_xBuilder->weld_menu_button("enddate")))
+ , m_xTfDate2(m_xBuilder->weld_formatted_spin_button("endtime"))
+ , m_xTfDate2Formatter(new weld::TimeFormatter(*m_xTfDate2))
+ , m_xIbClock2(m_xBuilder->weld_button("endclock"))
+ , m_xCbAuthor(m_xBuilder->weld_check_button("author"))
+ , m_xLbAuthor(m_xBuilder->weld_combo_box("authorlist"))
+ , m_xCbRange(m_xBuilder->weld_check_button("range"))
+ , m_xEdRange(m_xBuilder->weld_entry("rangeedit"))
+ , m_xBtnRange(m_xBuilder->weld_button("dotdotdot"))
+ , m_xCbAction(m_xBuilder->weld_check_button("action"))
+ , m_xLbAction(m_xBuilder->weld_combo_box("actionlist"))
+ , m_xCbComment(m_xBuilder->weld_check_button("comment"))
+ , m_xEdComment(m_xBuilder->weld_entry("commentedit"))
+{
+ m_xTfDateFormatter->EnableEmptyField(false);
+ m_xTfDate2Formatter->EnableEmptyField(false);
+
+ m_xLbDate->set_active(0);
+ m_xLbDate->connect_changed( LINK( this, SvxTPFilter, SelDateHdl ) );
+ m_xIbClock->connect_clicked( LINK( this, SvxTPFilter, TimeHdl) );
+ m_xIbClock2->connect_clicked( LINK( this, SvxTPFilter,TimeHdl) );
+ m_xBtnRange->connect_clicked( LINK( this, SvxTPFilter, RefHandle));
+
+ Link<weld::Toggleable&,void> aLink=LINK( this, SvxTPFilter, RowEnableHdl) ;
+ m_xCbDate->connect_toggled(aLink);
+ m_xCbAuthor->connect_toggled(aLink);
+ m_xCbRange->connect_toggled(aLink);
+ m_xCbAction->connect_toggled(aLink);
+ m_xCbComment->connect_toggled(aLink);
+
+ Link<SvtCalendarBox&,void> a2Link=LINK(this, SvxTPFilter, ModifyDate);
+ m_xDfDate->connect_activated(a2Link);
+ m_xDfDate2->connect_activated(a2Link);
+
+ Link<weld::FormattedSpinButton&,void> a3Link=LINK(this, SvxTPFilter, ModifyTime);
+ m_xTfDate->connect_value_changed(a3Link);
+ m_xTfDate2->connect_value_changed(a3Link);
+
+ Link<weld::Entry&,void> a4Link=LINK( this, SvxTPFilter, ModifyHdl);
+ m_xEdRange->connect_changed(a4Link);
+ m_xEdComment->connect_changed(a4Link);
+ m_xLbAction->connect_changed(LINK( this, SvxTPFilter, ModifyListBoxHdl));
+ m_xLbAuthor->connect_changed(LINK( this, SvxTPFilter, ModifyListBoxHdl));
+
+ RowEnableHdl(*m_xCbDate);
+ RowEnableHdl(*m_xCbAuthor);
+ RowEnableHdl(*m_xCbRange);
+ RowEnableHdl(*m_xCbAction);
+ RowEnableHdl(*m_xCbComment);
+
+ DateTime aDateTime(DateTime::SYSTEM);
+ SetFirstDate(aDateTime);
+ SetLastDate(aDateTime);
+ SetFirstTime(aDateTime);
+ SetLastTime(aDateTime);
+ HideRange();
+ ShowAction();
+ bModified=false;
+}
+
+SvxTPFilter::~SvxTPFilter()
+{
+}
+
+void SvxTPFilter::SetRedlinTable(SvxRedlinTable* pTable)
+{
+ m_pRedlinTable = pTable;
+}
+
+void SvxTPFilter::EnableDateLine1(bool bFlag)
+{
+ if(bFlag && m_xCbDate->get_active())
+ {
+ m_xDfDate->set_sensitive(true);
+ m_xTfDate->set_sensitive(true);
+ m_xIbClock->set_sensitive(true);
+ }
+ else
+ {
+ m_xDfDate->set_sensitive(false);
+ m_xTfDate->set_sensitive(false);
+ m_xIbClock->set_sensitive(false);
+ }
+}
+void SvxTPFilter::EnableDateLine2(bool bFlag)
+{
+ if(bFlag && m_xCbDate->get_active())
+ {
+ m_xFtDate2->set_sensitive(true);
+ m_xDfDate2->set_sensitive(true);
+ m_xTfDate2->set_sensitive(true);
+ m_xIbClock2->set_sensitive(true);
+ }
+ else
+ {
+ m_xFtDate2->set_sensitive(false);
+ m_xDfDate2->set_sensitive(false);
+ m_xDfDate2->set_label(OUString());
+ m_xTfDate2->set_sensitive(false);
+ m_xTfDate2->set_text(OUString());
+ m_xIbClock2->set_sensitive(false);
+ }
+}
+
+Date SvxTPFilter::GetFirstDate() const
+{
+ return m_xDfDate->get_date();
+}
+
+void SvxTPFilter::SetFirstDate(const Date &aDate)
+{
+ m_xDfDate->set_date(aDate);
+}
+
+tools::Time SvxTPFilter::GetFirstTime() const
+{
+ return m_xTfDateFormatter->GetTime();
+}
+
+void SvxTPFilter::SetFirstTime(const tools::Time &aTime)
+{
+ m_xTfDateFormatter->SetTime(aTime);
+}
+
+Date SvxTPFilter::GetLastDate() const
+{
+ return m_xDfDate2->get_date();
+}
+
+void SvxTPFilter::SetLastDate(const Date &aDate)
+{
+ m_xDfDate2->set_date(aDate);
+}
+
+tools::Time SvxTPFilter::GetLastTime() const
+{
+ return m_xTfDate2Formatter->GetTime();
+}
+
+void SvxTPFilter::SetLastTime(const tools::Time &aTime)
+{
+ m_xTfDate2Formatter->SetTime(aTime);
+}
+
+void SvxTPFilter::SetDateMode(sal_uInt16 nMode)
+{
+ m_xLbDate->set_active(nMode);
+ SelDateHdl(*m_xLbDate);
+}
+
+SvxRedlinDateMode SvxTPFilter::GetDateMode() const
+{
+ return static_cast<SvxRedlinDateMode>(m_xLbDate->get_active());
+}
+void SvxTPFilter::ClearAuthors()
+{
+ m_xLbAuthor->clear();
+}
+
+void SvxTPFilter::InsertAuthor( const OUString& rString)
+{
+ m_xLbAuthor->append_text(rString);
+}
+
+OUString SvxTPFilter::GetSelectedAuthor() const
+{
+ return m_xLbAuthor->get_active_text();
+}
+
+void SvxTPFilter::SelectedAuthorPos(sal_Int32 nPos)
+{
+ m_xLbAuthor->set_active(nPos);
+}
+
+sal_Int32 SvxTPFilter::SelectAuthor(const OUString& aString)
+{
+ m_xLbAuthor->set_active_text(aString);
+ return m_xLbAuthor->get_active();
+}
+
+void SvxTPFilter::SetRange(const OUString& rString)
+{
+ m_xEdRange->set_text(rString);
+}
+
+OUString SvxTPFilter::GetRange() const
+{
+ return m_xEdRange->get_text();
+}
+
+void SvxTPFilter::SetFocusToRange()
+{
+ m_xEdRange->grab_focus();
+}
+
+void SvxTPFilter::HideRange(bool bHide)
+{
+ if (bHide)
+ {
+ m_xCbRange->hide();
+ m_xEdRange->hide();
+ m_xBtnRange->hide();
+ }
+ else
+ {
+ ShowAction(false);
+ m_xCbRange->show();
+ m_xEdRange->show();
+ m_xBtnRange->show();
+ }
+}
+
+void SvxTPFilter::SetComment(const OUString &rComment)
+{
+ m_xEdComment->set_text(rComment);
+}
+
+OUString SvxTPFilter::GetComment()const
+{
+ return m_xEdComment->get_text();
+}
+
+bool SvxTPFilter::IsDate() const
+{
+ return m_xCbDate->get_active();
+}
+
+bool SvxTPFilter::IsAuthor() const
+{
+ return m_xCbAuthor->get_active();
+}
+
+bool SvxTPFilter::IsRange() const
+{
+ return m_xCbRange->get_active();
+}
+
+bool SvxTPFilter::IsAction() const
+{
+ return m_xCbAction->get_active();
+}
+
+bool SvxTPFilter::IsComment() const
+{
+ return m_xCbComment->get_active();
+}
+
+void SvxTPFilter::CheckDate(bool bFlag)
+{
+ m_xCbDate->set_active(bFlag);
+ RowEnableHdl(*m_xCbDate);
+ bModified=false;
+}
+
+void SvxTPFilter::CheckAuthor(bool bFlag)
+{
+ m_xCbAuthor->set_active(bFlag);
+ RowEnableHdl(*m_xCbAuthor);
+ bModified=false;
+}
+
+void SvxTPFilter::CheckRange(bool bFlag)
+{
+ m_xCbRange->set_active(bFlag);
+ RowEnableHdl(*m_xCbRange);
+ bModified=false;
+}
+
+void SvxTPFilter::CheckAction(bool bFlag)
+{
+ m_xCbAction->set_active(bFlag);
+ RowEnableHdl(*m_xCbAction);
+ bModified=false;
+}
+
+void SvxTPFilter::CheckComment(bool bFlag)
+{
+ m_xCbComment->set_active(bFlag);
+ RowEnableHdl(*m_xCbComment);
+ bModified=false;
+}
+
+void SvxTPFilter::ShowAction(bool bShow)
+{
+ if(!bShow)
+ {
+ m_xCbAction->hide();
+ m_xLbAction->hide();
+ }
+ else
+ {
+ HideRange();
+ m_xCbAction->show();
+ m_xLbAction->show();
+ }
+}
+
+IMPL_LINK_NOARG(SvxTPFilter, SelDateHdl, weld::ComboBox&, void)
+{
+ SvxRedlinDateMode nKind = static_cast<SvxRedlinDateMode>(m_xLbDate->get_active());
+ switch(nKind)
+ {
+ case SvxRedlinDateMode::BEFORE:
+ EnableDateLine1(true);
+ EnableDateLine2(false);
+ break;
+ case SvxRedlinDateMode::SINCE:
+ EnableDateLine1(true);
+ EnableDateLine2(false);
+ break;
+ case SvxRedlinDateMode::EQUAL:
+ EnableDateLine1(true);
+ m_xTfDate->set_sensitive(false);
+ m_xTfDate->set_text(OUString());
+ EnableDateLine2(false);
+ break;
+ case SvxRedlinDateMode::NOTEQUAL:
+ EnableDateLine1(true);
+ m_xTfDate->set_sensitive(false);
+ m_xTfDate->set_text(OUString());
+ EnableDateLine2(false);
+ break;
+ case SvxRedlinDateMode::BETWEEN:
+ EnableDateLine1(true);
+ EnableDateLine2(true);
+ break;
+ case SvxRedlinDateMode::SAVE:
+ EnableDateLine1(false);
+ EnableDateLine2(false);
+ break;
+ case SvxRedlinDateMode::NONE:
+ break;
+ }
+ bModified = true;
+}
+
+IMPL_LINK(SvxTPFilter, RowEnableHdl, weld::Toggleable&, rCB, void)
+{
+ if (&rCB == m_xCbDate.get())
+ {
+ m_xLbDate->set_sensitive(m_xCbDate->get_active());
+ EnableDateLine1(false);
+ EnableDateLine2(false);
+ if(m_xCbDate->get_active()) SelDateHdl(*m_xLbDate);
+ }
+ else if (&rCB == m_xCbAuthor.get())
+ {
+ m_xLbAuthor->set_sensitive(m_xCbAuthor->get_active());
+ }
+ else if (&rCB == m_xCbRange.get())
+ {
+ m_xEdRange->set_sensitive(m_xCbRange->get_active());
+ m_xBtnRange->set_sensitive(m_xCbRange->get_active());
+ }
+ else if (&rCB == m_xCbAction.get())
+ {
+ m_xLbAction->set_sensitive(m_xCbAction->get_active());
+ }
+ else if (&rCB == m_xCbComment.get())
+ {
+ m_xEdComment->set_sensitive(m_xCbComment->get_active());
+ }
+ bModified = true;
+}
+
+IMPL_LINK(SvxTPFilter, TimeHdl, weld::Button&, rIB, void)
+{
+ DateTime aDateTime( DateTime::SYSTEM );
+ if (&rIB == m_xIbClock.get())
+ {
+ SetFirstDate(aDateTime);
+ SetFirstTime(aDateTime);
+ }
+ else if (&rIB == m_xIbClock2.get())
+ {
+ SetLastDate(aDateTime);
+ SetLastTime(aDateTime);
+ }
+ bModified=true;
+}
+
+IMPL_LINK_NOARG(SvxTPFilter, ModifyHdl, weld::Entry&, void)
+{
+ bModified=true;
+}
+
+IMPL_LINK_NOARG(SvxTPFilter, ModifyListBoxHdl, weld::ComboBox&, void)
+{
+ bModified=true;
+}
+
+void SvxTPFilter::DeactivatePage()
+{
+ if(bModified)
+ {
+ if (m_pRedlinTable)
+ {
+ m_pRedlinTable->SetFilterDate(IsDate());
+ m_pRedlinTable->SetDateTimeMode(GetDateMode());
+ m_pRedlinTable->SetFirstDate(GetFirstDate());
+ m_pRedlinTable->SetLastDate(GetLastDate());
+ m_pRedlinTable->SetFirstTime(GetFirstTime());
+ m_pRedlinTable->SetLastTime(GetLastTime());
+ m_pRedlinTable->SetFilterAuthor(IsAuthor());
+ m_pRedlinTable->SetAuthor(GetSelectedAuthor());
+
+ m_pRedlinTable->SetFilterComment(IsComment());
+
+ utl::SearchParam aSearchParam( m_xEdComment->get_text(),
+ utl::SearchParam::SearchType::Regexp,false );
+
+ m_pRedlinTable->SetCommentParams(&aSearchParam);
+
+ m_pRedlinTable->UpdateFilterTest();
+ }
+
+ aReadyLink.Call(this);
+ }
+ bModified=false;
+}
+
+void SvxTPFilter::Enable(bool bEnable)
+{
+ m_xContainer->set_sensitive(bEnable);
+ if (m_xCbDate->get_sensitive())
+ {
+ RowEnableHdl(*m_xCbDate);
+ RowEnableHdl(*m_xCbAuthor);
+ RowEnableHdl(*m_xCbRange);
+ RowEnableHdl(*m_xCbComment);
+ }
+}
+
+IMPL_LINK(SvxTPFilter, ModifyDate, SvtCalendarBox&, rTF, void)
+{
+ Date aDate( Date::SYSTEM );
+ if (m_xDfDate.get() == &rTF)
+ {
+ if (m_xDfDate->get_label().isEmpty())
+ m_xDfDate->set_date(aDate);
+
+ if(m_pRedlinTable!=nullptr)
+ m_pRedlinTable->SetFirstDate(m_xDfDate->get_date());
+ }
+ else if (m_xDfDate2.get() == &rTF)
+ {
+ if (m_xDfDate2->get_label().isEmpty())
+ m_xDfDate2->set_date(aDate);
+
+ if (m_pRedlinTable)
+ m_pRedlinTable->SetLastDate(m_xDfDate2->get_date());
+ }
+ bModified=true;
+}
+
+IMPL_LINK(SvxTPFilter, ModifyTime, weld::FormattedSpinButton&, rTF, void)
+{
+ tools::Time aTime(0);
+ if (m_xTfDate.get() == &rTF)
+ {
+ if (m_xTfDate->get_text().isEmpty())
+ SetFirstTime(aTime);
+
+ if (m_pRedlinTable!=nullptr)
+ m_pRedlinTable->SetFirstTime(GetFirstTime());
+ }
+ else if (m_xTfDate2.get() == &rTF)
+ {
+ if (m_xTfDate2->get_text().isEmpty())
+ SetLastTime(aTime);
+
+ if (m_pRedlinTable!=nullptr)
+ m_pRedlinTable->SetLastTime(GetLastTime());
+
+ }
+ bModified=true;
+}
+
+IMPL_LINK_NOARG(SvxTPFilter, RefHandle, weld::Button&, void)
+{
+ aRefLink.Call(this);
+}
+
+SvxAcceptChgCtr::SvxAcceptChgCtr(weld::Container* pParent)
+ : m_xBuilder(Application::CreateBuilder(pParent, "svx/ui/redlinecontrol.ui"))
+ , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
+{
+ m_xTabCtrl->connect_enter_page(LINK(this, SvxAcceptChgCtr, ActivatePageHdl));
+ m_xTabCtrl->connect_leave_page(LINK(this, SvxAcceptChgCtr, DeactivatePageHdl));
+
+ m_xTPFilter.reset(new SvxTPFilter(m_xTabCtrl->get_page("filter")));
+ m_xTPView.reset(new SvxTPView(m_xTabCtrl->get_page("view")));
+ m_xTPFilter->SetRedlinTable(m_xTPView->GetTableControl());
+ m_xTabCtrl->set_current_page("view");
+ m_xTabCtrl->set_help_id(HID_REDLINE_CTRL_VIEW);
+ m_xTabCtrl->show();
+}
+
+SvxAcceptChgCtr::~SvxAcceptChgCtr()
+{
+ m_xTPFilter.reset();
+ m_xTPView.reset();
+}
+
+void SvxAcceptChgCtr::ShowFilterPage()
+{
+ m_xTabCtrl->set_current_page("filter");
+}
+
+IMPL_LINK(SvxAcceptChgCtr, ActivatePageHdl, const OString&, rPage, void)
+{
+ if (rPage == "filter")
+ {
+ m_xTPFilter->ActivatePage();
+ m_xTabCtrl->set_help_id(HID_REDLINE_CTRL_FILTER);
+ }
+ else if (rPage == "view")
+ {
+ m_xTPView->ActivatePage();
+ m_xTabCtrl->set_help_id(HID_REDLINE_CTRL_VIEW);
+ }
+}
+
+IMPL_LINK(SvxAcceptChgCtr, DeactivatePageHdl, const OString&, rPage, bool)
+{
+ if (rPage == "filter")
+ m_xTPFilter->DeactivatePage();
+ else if (rPage == "view")
+ m_xTPView->DeactivatePage();
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/databaseregistrationui.cxx b/svx/source/dialog/databaseregistrationui.cxx
new file mode 100644
index 000000000..aa62b5b38
--- /dev/null
+++ b/svx/source/dialog/databaseregistrationui.cxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/databaseregistrationui.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <svx/dialogs.hrc>
+
+#include <sfx2/app.hxx>
+#include <svl/itemset.hxx>
+
+namespace svx
+{
+ sal_uInt16 administrateDatabaseRegistration(weld::Window* parentWindow)
+ {
+ sal_uInt16 nResult = RET_CANCEL;
+
+ SfxItemSetFixed<SID_SB_DB_REGISTER, SID_SB_DB_REGISTER> aRegistrationItems( SfxGetpApp()->GetPool() );
+
+ SvxAbstractDialogFactory* pDialogFactory = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractDialog> pDialog(pDialogFactory->CreateSfxDialog(parentWindow, aRegistrationItems, nullptr, RID_SFXPAGE_DBREGISTER));
+ nResult = pDialog->Execute();
+
+ return nResult;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dialcontrol.cxx b/svx/source/dialog/dialcontrol.cxx
new file mode 100644
index 000000000..e6c7c8e43
--- /dev/null
+++ b/svx/source/dialog/dialcontrol.cxx
@@ -0,0 +1,479 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialcontrol.hxx>
+#include <svx/svdtrans.hxx>
+#include <cmath>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+namespace svx {
+
+const tools::Long DIAL_OUTER_WIDTH = 8;
+
+DialControlBmp::DialControlBmp(OutputDevice& rReference)
+ : VirtualDevice(rReference, DeviceFormat::DEFAULT, DeviceFormat::DEFAULT)
+ , mbEnabled(true)
+ , mrParent(rReference)
+ , mnCenterX(0)
+ , mnCenterY(0)
+{
+ EnableRTL(false);
+}
+
+void DialControlBmp::InitBitmap(const vcl::Font& rFont)
+{
+ Init();
+ SetFont(rFont);
+}
+
+void DialControlBmp::CopyBackground( const DialControlBmp& rSrc )
+{
+ Init();
+ SetSize(rSrc.maRect.GetSize());
+ mbEnabled = rSrc.mbEnabled;
+ Point aPos;
+ DrawBitmapEx( aPos, rSrc.GetBitmapEx( aPos, maRect.GetSize() ) );
+}
+
+void DialControlBmp::DrawBackground( const Size& rSize, bool bEnabled )
+{
+ Init();
+ SetSize(rSize);
+ mbEnabled = bEnabled;
+ DrawBackground();
+}
+
+void DialControlBmp::DrawElements( const OUString& rText, Degree100 nAngle )
+{
+ double fAngle = toRadians(nAngle);
+ double fSin = sin( fAngle );
+ double fCos = cos( fAngle );
+ double fWidth = GetTextWidth( rText ) / 2.0;
+ double fHeight = GetTextHeight() / 2.0;
+
+ if ( !rText.isEmpty() )
+ {
+ // rotated text
+ vcl::Font aFont( GetFont() );
+ aFont.SetColor( GetTextColor() );
+ aFont.SetOrientation( to<Degree10>(nAngle) ); // Font uses 1/10 degrees
+ aFont.SetWeight( WEIGHT_BOLD );
+ SetFont( aFont );
+
+ tools::Long nX = static_cast< tools::Long >( mnCenterX - fWidth * fCos - fHeight * fSin );
+ tools::Long nY = static_cast< tools::Long >( mnCenterY + fWidth * fSin - fHeight * fCos );
+ tools::Rectangle aRect( nX, nY, 2 * mnCenterX - nX, 2 * mnCenterY - nY );
+ DrawText( aRect, rText, mbEnabled ? DrawTextFlags::NONE : DrawTextFlags::Disable );
+ }
+ else
+ {
+ // only a line
+ const sal_Int32 nDx (fCos * (maRect.GetWidth()-4) / 2);
+ const sal_Int32 nDy (-fSin * (maRect.GetHeight()-4) / 2);
+ Point pt1( maRect.Center() );
+ Point pt2( pt1.X() + nDx, pt1.Y() + nDy);
+
+ SetLineColor( GetTextColor() );
+ DrawLine( pt1, pt2 );
+ }
+
+ // *** drag button ***
+
+ bool bMain = (nAngle % 4500_deg100) != 0_deg100;
+ SetLineColor( GetButtonLineColor() );
+ SetFillColor( GetButtonFillColor( bMain ) );
+
+ tools::Long nX = mnCenterX - static_cast< tools::Long >( (DIAL_OUTER_WIDTH / 2 - mnCenterX) * fCos );
+ tools::Long nY = mnCenterY - static_cast< tools::Long >( (mnCenterY - DIAL_OUTER_WIDTH / 2) * fSin );
+ tools::Long nSize = bMain ? (DIAL_OUTER_WIDTH / 4) : (DIAL_OUTER_WIDTH / 2 - 1);
+ DrawEllipse( tools::Rectangle( nX - nSize, nY - nSize, nX + nSize, nY + nSize ) );
+}
+
+Color DialControlBmp::GetBackgroundColor() const
+{
+ return GetSettings().GetStyleSettings().GetDialogColor();
+}
+
+const Color& DialControlBmp::GetTextColor() const
+{
+ return GetSettings().GetStyleSettings().GetLabelTextColor();
+}
+
+const Color& DialControlBmp::GetScaleLineColor() const
+{
+ const StyleSettings& rSett = GetSettings().GetStyleSettings();
+ return mbEnabled ? rSett.GetButtonTextColor() : rSett.GetDisableColor();
+}
+
+const Color& DialControlBmp::GetButtonLineColor() const
+{
+ const StyleSettings& rSett = GetSettings().GetStyleSettings();
+ return mbEnabled ? rSett.GetButtonTextColor() : rSett.GetDisableColor();
+}
+
+const Color& DialControlBmp::GetButtonFillColor( bool bMain ) const
+{
+ const StyleSettings& rSett = GetSettings().GetStyleSettings();
+ return mbEnabled ? (bMain ? rSett.GetMenuColor() : rSett.GetHighlightColor()) : rSett.GetDisableColor();
+}
+
+void DialControlBmp::Init()
+{
+ SetSettings(mrParent.GetSettings());
+ SetBackground(GetBackgroundColor());
+}
+
+void DialControlBmp::SetSize( const Size& rSize )
+{
+ maRect.SetPos( Point( 0, 0 ) );
+ maRect.SetSize( rSize );
+ mnCenterX = rSize.Width() / 2;
+ mnCenterY = rSize.Height() / 2;
+ SetOutputSize( rSize );
+}
+
+void DialControlBmp::DrawBackground()
+{
+ // *** background with 3D effect ***
+
+ SetLineColor();
+ SetFillColor();
+ Erase();
+
+ EnableRTL(); // draw 3D effect in correct direction
+
+ sal_uInt8 nDiff = mbEnabled ? 0x18 : 0x10;
+ Color aColor;
+
+ aColor = GetBackgroundColor();
+ SetFillColor( aColor );
+ DrawPie( maRect, maRect.TopRight(), maRect.TopCenter() );
+ DrawPie( maRect, maRect.BottomLeft(), maRect.BottomCenter() );
+
+ aColor.DecreaseLuminance( nDiff );
+ SetFillColor( aColor );
+ DrawPie( maRect, maRect.BottomCenter(), maRect.TopRight() );
+
+ aColor.DecreaseLuminance( nDiff );
+ SetFillColor( aColor );
+ DrawPie( maRect, maRect.BottomRight(), maRect.RightCenter() );
+
+ aColor = GetBackgroundColor();
+ aColor.IncreaseLuminance( nDiff );
+ SetFillColor( aColor );
+ DrawPie( maRect, maRect.TopCenter(), maRect.BottomLeft() );
+
+ aColor.IncreaseLuminance( nDiff );
+ SetFillColor( aColor );
+ DrawPie( maRect, maRect.TopLeft(), maRect.LeftCenter() );
+
+ EnableRTL( false );
+
+ // *** calibration ***
+
+ Point aStartPos( mnCenterX, mnCenterY );
+ Color aFullColor( GetScaleLineColor() );
+ Color aLightColor( GetBackgroundColor() );
+ aLightColor.Merge( aFullColor, 128 );
+
+ for( int nAngle = 0; nAngle < 360; nAngle += 15 )
+ {
+ SetLineColor( (nAngle % 45) ? aLightColor : aFullColor );
+ double fAngle = basegfx::deg2rad(nAngle);
+ tools::Long nX = static_cast< tools::Long >( -mnCenterX * cos( fAngle ) );
+ tools::Long nY = static_cast< tools::Long >( mnCenterY * sin( fAngle ) );
+ DrawLine( aStartPos, Point( mnCenterX - nX, mnCenterY - nY ) );
+ }
+
+ // *** clear inner area ***
+
+ SetLineColor();
+ SetFillColor( GetBackgroundColor() );
+ tools::Rectangle aEllipseRect = maRect;
+ aEllipseRect.shrink(DIAL_OUTER_WIDTH);
+ DrawEllipse( aEllipseRect );
+}
+
+DialControl::DialControl_Impl::DialControl_Impl(OutputDevice& rReference) :
+ mxBmpEnabled(VclPtr<DialControlBmp>::Create(rReference)),
+ mxBmpDisabled(VclPtr<DialControlBmp>::Create(rReference)),
+ mxBmpBuffered(VclPtr<DialControlBmp>::Create(rReference)),
+ mpLinkField( nullptr ),
+ mnLinkedFieldValueMultiplyer( 0 ),
+ mnAngle( 0 ),
+ mnInitialAngle( 0 ),
+ mnOldAngle( 0 ),
+ mnCenterX( 0 ),
+ mnCenterY( 0 ),
+ mbNoRot( false )
+{
+}
+
+void DialControl::DialControl_Impl::Init( const Size& rWinSize, const vcl::Font& rWinFont )
+{
+ maWinFont = rWinFont;
+ maWinFont.SetTransparent(true);
+ mxBmpBuffered->InitBitmap(maWinFont);
+ SetSize(rWinSize);
+}
+
+void DialControl::DialControl_Impl::SetSize( const Size& rWinSize )
+{
+ // make the control squared, and adjusted so that we have a well-defined
+ // center ["(x - 1) | 1" creates odd value <= x]
+ tools::Long nMin = (std::min(rWinSize.Width(), rWinSize.Height()) - 1) | 1;
+
+ maWinSize = Size( nMin, nMin );
+
+ mnCenterX = maWinSize.Width() / 2;
+ mnCenterY = maWinSize.Height() / 2;
+
+ mxBmpEnabled->DrawBackground( maWinSize, true );
+ mxBmpDisabled->DrawBackground( maWinSize, false );
+ mxBmpBuffered->SetSize( maWinSize );
+}
+
+void DialControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ //use same logic as DialControl_Impl::SetSize
+ int nDim = (std::min<int>(pDrawingArea->get_approximate_digit_width() * 12,
+ pDrawingArea->get_text_height() * 6) - 1) | 1;
+ Size aSize(nDim, nDim);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ mpImpl.reset(new DialControl_Impl(pDrawingArea->get_ref_device()));
+ //set size and use that
+ Init(aSize);
+}
+
+void DialControl::Resize()
+{
+ mpImpl->SetSize(GetOutputSizePixel());
+ InvalidateControl();
+}
+
+void DialControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ Point aPos;
+ rRenderContext.DrawBitmapEx(aPos, mpImpl->mxBmpBuffered->GetBitmapEx(aPos, mpImpl->maWinSize));
+}
+
+void DialControl::StyleUpdated()
+{
+ CustomWidgetController::StyleUpdated();
+ Init( mpImpl->maWinSize, mpImpl->maWinFont );
+ InvalidateControl();
+}
+
+bool DialControl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if( rMEvt.IsLeft() )
+ {
+ GrabFocus();
+ CaptureMouse();
+ mpImpl->mnOldAngle = mpImpl->mnAngle;
+ HandleMouseEvent( rMEvt.GetPosPixel(), true );
+ }
+ return true;
+}
+
+bool DialControl::MouseMove( const MouseEvent& rMEvt )
+{
+ if( IsMouseCaptured() && rMEvt.IsLeft() )
+ HandleMouseEvent( rMEvt.GetPosPixel(), false );
+ return true;
+}
+
+bool DialControl::MouseButtonUp(const MouseEvent&)
+{
+ if( IsMouseCaptured() )
+ {
+ ReleaseMouse();
+ if( mpImpl->mpLinkField )
+ mpImpl->mpLinkField->grab_focus();
+ }
+ return true;
+}
+
+bool DialControl::KeyInput( const KeyEvent& rKEvt )
+{
+ const vcl::KeyCode& rKCode = rKEvt.GetKeyCode();
+ if( !rKCode.GetModifier() && (rKCode.GetCode() == KEY_ESCAPE) )
+ {
+ HandleEscapeEvent();
+ return true;
+ }
+ return CustomWidgetController::KeyInput(rKEvt);
+}
+
+void DialControl::LoseFocus()
+{
+ // release captured mouse
+ HandleEscapeEvent();
+}
+
+bool DialControl::HasRotation() const
+{
+ return !mpImpl->mbNoRot;
+}
+
+void DialControl::SetNoRotation()
+{
+ if( !mpImpl->mbNoRot )
+ {
+ mpImpl->mbNoRot = true;
+ InvalidateControl();
+ if (mpImpl->mpLinkField)
+ mpImpl->mpLinkField->set_text("");
+ }
+}
+
+Degree100 DialControl::GetRotation() const
+{
+ return mpImpl->mnAngle;
+}
+
+void DialControl::SetRotation(Degree100 nAngle)
+{
+ SetRotation(nAngle, false);
+}
+
+void DialControl::SetLinkedField(weld::MetricSpinButton* pField, sal_Int32 nDecimalPlaces)
+{
+ mpImpl->mnLinkedFieldValueMultiplyer = 100 / std::pow(10.0, double(nDecimalPlaces));
+
+ // remove modify handler from old linked field
+ if( mpImpl->mpLinkField )
+ {
+ weld::MetricSpinButton& rField = *mpImpl->mpLinkField;
+ rField.connect_value_changed(Link<weld::MetricSpinButton&,void>());
+ }
+ // remember the new linked field
+ mpImpl->mpLinkField = pField;
+ // set modify handler at new linked field
+ if( mpImpl->mpLinkField )
+ {
+ weld::MetricSpinButton& rField = *mpImpl->mpLinkField;
+ rField.connect_value_changed(LINK(this, DialControl, LinkedFieldModifyHdl));
+ }
+}
+
+IMPL_LINK_NOARG(DialControl, LinkedFieldModifyHdl, weld::MetricSpinButton&, void)
+{
+ SetRotation(Degree100(mpImpl->mpLinkField->get_value(FieldUnit::DEGREE) * mpImpl->mnLinkedFieldValueMultiplyer), true);
+}
+
+void DialControl::SaveValue()
+{
+ mpImpl->mnInitialAngle = mpImpl->mnAngle;
+}
+
+bool DialControl::IsValueModified() const
+{
+ return mpImpl->mnInitialAngle != mpImpl->mnAngle;
+}
+
+void DialControl::Init( const Size& rWinSize, const vcl::Font& rWinFont )
+{
+ mpImpl->Init( rWinSize, rWinFont );
+ EnableRTL( false ); // don't mirror mouse handling
+ SetOutputSizePixel( mpImpl->maWinSize );
+}
+
+void DialControl::Init( const Size& rWinSize )
+{
+ //hidpi TODO: GetDefaultFont() picks a font size too small, so fix it here.
+ vcl::Font aDefaultSize = Application::GetSettings().GetStyleSettings().GetLabelFont();
+
+ vcl::Font aFont( OutputDevice::GetDefaultFont(
+ DefaultFontType::UI_SANS, Application::GetSettings().GetUILanguageTag().getLanguageType(), GetDefaultFontFlags::OnlyOne ) );
+
+ aFont.SetFontHeight(aDefaultSize.GetFontHeight());
+ Init( rWinSize, aFont );
+}
+
+void DialControl::InvalidateControl()
+{
+ mpImpl->mxBmpBuffered->CopyBackground( IsEnabled() ? *mpImpl->mxBmpEnabled : *mpImpl->mxBmpDisabled );
+ if( !mpImpl->mbNoRot )
+ mpImpl->mxBmpBuffered->DrawElements(GetText(), mpImpl->mnAngle);
+ Invalidate();
+}
+
+void DialControl::SetRotation(Degree100 nAngle, bool bBroadcast)
+{
+ bool bOldSel = mpImpl->mbNoRot;
+ mpImpl->mbNoRot = false;
+
+ nAngle = NormAngle36000(nAngle);
+
+ if (!bOldSel || (mpImpl->mnAngle != nAngle))
+ {
+ mpImpl->mnAngle = nAngle;
+ InvalidateControl();
+ if( mpImpl->mpLinkField )
+ mpImpl->mpLinkField->set_value(GetRotation().get() / mpImpl->mnLinkedFieldValueMultiplyer, FieldUnit::DEGREE);
+ if( bBroadcast )
+ mpImpl->maModifyHdl.Call(*this);
+ }
+}
+
+void DialControl::SetModifyHdl( const Link<DialControl&,void>& rLink )
+{
+ mpImpl->maModifyHdl = rLink;
+}
+
+void DialControl::HandleMouseEvent( const Point& rPos, bool bInitial )
+{
+ tools::Long nX = rPos.X() - mpImpl->mnCenterX;
+ tools::Long nY = mpImpl->mnCenterY - rPos.Y();
+ double fH = sqrt( static_cast< double >( nX ) * nX + static_cast< double >( nY ) * nY );
+ if( fH != 0.0 )
+ {
+ double fAngle = acos( nX / fH );
+ sal_Int32 nAngle = basegfx::rad2deg<100>(fAngle);
+ if( nY < 0 )
+ nAngle = 36000 - nAngle;
+ if( bInitial ) // round to entire 15 degrees
+ nAngle = ((nAngle + 750) / 1500) * 1500;
+ // Round up to 1 degree
+ nAngle = (((nAngle + 50) / 100) * 100) % 36000;
+ SetRotation(Degree100(nAngle), true);
+ }
+}
+
+void DialControl::HandleEscapeEvent()
+{
+ if( IsMouseCaptured() )
+ {
+ ReleaseMouse();
+ SetRotation(mpImpl->mnOldAngle, true);
+ if( mpImpl->mpLinkField )
+ mpImpl->mpLinkField->grab_focus();
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dialmgr.cxx b/svx/source/dialog/dialmgr.cxx
new file mode 100644
index 000000000..9fdd50dda
--- /dev/null
+++ b/svx/source/dialog/dialmgr.cxx
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+
+std::locale SvxResLocale() { return Translate::Create("svx"); }
+
+OUString SvxResId(TranslateId aId) { return Translate::get(aId, SvxResLocale()); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dlgctl3d.cxx b/svx/source/dialog/dlgctl3d.cxx
new file mode 100644
index 000000000..792485a06
--- /dev/null
+++ b/svx/source/dialog/dlgctl3d.cxx
@@ -0,0 +1,1173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/dlgctl3d.hxx>
+#include <svx/strings.hrc>
+#include <svx/view3d.hxx>
+#include <svx/fmmodel.hxx>
+#include <svl/itempool.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/sphere3d.hxx>
+#include <svx/cube3d.hxx>
+#include <svx/scene3d.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/helperhittest3d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <polygn3d.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <helpids.h>
+#include <svx/dialmgr.hxx>
+#include <tools/helpers.hxx>
+#include <vcl/settings.hxx>
+
+using namespace com::sun::star;
+
+Svx3DPreviewControl::Svx3DPreviewControl()
+ : mpScene(nullptr)
+ , mp3DObj(nullptr)
+ , mnObjectType(SvxPreviewObjectType::SPHERE)
+{
+}
+
+void Svx3DPreviewControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(80, 100), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ SetOutputSizePixel(aSize);
+
+ Construct();
+}
+
+Svx3DPreviewControl::~Svx3DPreviewControl()
+{
+ mxFmPage.clear();
+ mp3DView.reset();
+ mpModel.reset();
+}
+
+void Svx3DPreviewControl::Construct()
+{
+ // Do never mirror the preview window. This explicitly includes right
+ // to left writing environments.
+ EnableRTL (false);
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ rDevice.SetMapMode(MapMode(MapUnit::Map100thMM));
+
+ // Model
+ mpModel.reset(new FmFormModel());
+ mpModel->GetItemPool().FreezeIdRanges();
+
+ // Page
+ mxFmPage = new FmFormPage( *mpModel );
+ mpModel->InsertPage( mxFmPage.get(), 0 );
+
+ // 3D View
+ mp3DView.reset(new E3dView(*mpModel, &rDevice));
+ mp3DView->SetBufferedOutputAllowed(true);
+ mp3DView->SetBufferedOverlayAllowed(true);
+
+ // 3D Scene
+ mpScene = new E3dScene(*mpModel);
+
+ // initially create object
+ SetObjectType(SvxPreviewObjectType::SPHERE);
+
+ // camera and perspective
+ Camera3D rCamera = mpScene->GetCamera();
+ const basegfx::B3DRange& rVolume = mpScene->GetBoundVolume();
+ double fW = rVolume.getWidth();
+ double fH = rVolume.getHeight();
+ double fCamZ = rVolume.getMaxZ() + ((fW + fH) / 2.0);
+
+ rCamera.SetAutoAdjustProjection(false);
+ rCamera.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
+ basegfx::B3DPoint aLookAt;
+ double fDefaultCamPosZ = mp3DView->GetDefaultCamPosZ();
+ basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
+ rCamera.SetPosAndLookAt(aCamPos, aLookAt);
+ double fDefaultCamFocal = mp3DView->GetDefaultCamFocal();
+ rCamera.SetFocalLength(fDefaultCamFocal);
+
+ mpScene->SetCamera( rCamera );
+ mxFmPage->InsertObject( mpScene );
+
+ basegfx::B3DHomMatrix aRotation;
+ aRotation.rotate(basegfx::deg2rad( 25 ), 0.0, 0.0);
+ aRotation.rotate(0.0, basegfx::deg2rad( 40 ), 0.0);
+ mpScene->SetTransform(aRotation * mpScene->GetTransform());
+
+ // invalidate SnapRects of objects
+ mpScene->SetBoundAndSnapRectsDirty();
+
+ SfxItemSetFixed<XATTR_LINESTYLE, XATTR_LINESTYLE,
+ XATTR_FILL_FIRST, XATTR_FILLBITMAP> aSet( mpModel->GetItemPool() );
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ aSet.Put( XFillColorItem( "", COL_WHITE ) );
+
+ mpScene->SetMergedItemSet(aSet);
+
+ // PageView
+ SdrPageView* pPageView = mp3DView->ShowSdrPage( mxFmPage.get() );
+ mp3DView->hideMarkHandles();
+
+ // mark scene
+ mp3DView->MarkObj( mpScene, pPageView );
+}
+
+void Svx3DPreviewControl::Resize()
+{
+ // size of page
+ Size aSize(GetOutputSizePixel());
+ aSize = GetDrawingArea()->get_ref_device().PixelToLogic(aSize);
+ mxFmPage->SetSize(aSize);
+
+ // set size
+ Size aObjSize( aSize.Width()*5/6, aSize.Height()*5/6 );
+ Point aObjPoint( (aSize.Width() - aObjSize.Width()) / 2,
+ (aSize.Height() - aObjSize.Height()) / 2);
+ tools::Rectangle aRect( aObjPoint, aObjSize);
+ mpScene->SetSnapRect( aRect );
+}
+
+void Svx3DPreviewControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ mp3DView->CompleteRedraw(&rRenderContext, vcl::Region(rRect));
+}
+
+bool Svx3DPreviewControl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if (rMEvt.IsShift() && rMEvt.IsMod1())
+ {
+ if(SvxPreviewObjectType::SPHERE == GetObjectType())
+ {
+ SetObjectType(SvxPreviewObjectType::CUBE);
+ }
+ else
+ {
+ SetObjectType(SvxPreviewObjectType::SPHERE);
+ }
+ }
+ return false;
+}
+
+void Svx3DPreviewControl::SetObjectType(SvxPreviewObjectType nType)
+{
+ if(mnObjectType == nType && mp3DObj)
+ return;
+
+ SfxItemSetFixed<SDRATTR_START, SDRATTR_END> aSet(mpModel->GetItemPool());
+ mnObjectType = nType;
+
+ if( mp3DObj )
+ {
+ aSet.Put(mp3DObj->GetMergedItemSet());
+ mpScene->RemoveObject( mp3DObj->GetOrdNum() );
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(mp3DObj);
+ SdrObject::Free(pTemp);
+ }
+
+ switch( nType )
+ {
+ case SvxPreviewObjectType::SPHERE:
+ {
+ mp3DObj = new E3dSphereObj(
+ *mpModel,
+ mp3DView->Get3DDefaultAttributes(),
+ basegfx::B3DPoint( 0, 0, 0 ),
+ basegfx::B3DVector( 5000, 5000, 5000 ));
+ }
+ break;
+
+ case SvxPreviewObjectType::CUBE:
+ {
+ mp3DObj = new E3dCubeObj(
+ *mpModel,
+ mp3DView->Get3DDefaultAttributes(),
+ basegfx::B3DPoint( -2500, -2500, -2500 ),
+ basegfx::B3DVector( 5000, 5000, 5000 ));
+ }
+ break;
+ }
+
+ if (mp3DObj)
+ {
+ mpScene->InsertObject( mp3DObj );
+ mp3DObj->SetMergedItemSet(aSet);
+ }
+
+ Invalidate();
+}
+
+SfxItemSet const & Svx3DPreviewControl::Get3DAttributes() const
+{
+ return mp3DObj->GetMergedItemSet();
+}
+
+void Svx3DPreviewControl::Set3DAttributes( const SfxItemSet& rAttr )
+{
+ mp3DObj->SetMergedItemSet(rAttr, true);
+ Resize();
+ Invalidate();
+}
+
+#define RADIUS_LAMP_PREVIEW_SIZE (4500.0)
+#define RADIUS_LAMP_SMALL (600.0)
+#define RADIUS_LAMP_BIG (1000.0)
+#define NO_LIGHT_SELECTED (0xffffffff)
+#define MAX_NUMBER_LIGHTS (8)
+
+const sal_Int32 g_nInteractionStartDistance = 5 * 5 * 2;
+
+Svx3DLightControl::Svx3DLightControl()
+: maSelectedLight(NO_LIGHT_SELECTED),
+ mpExpansionObject(nullptr),
+ mpLampBottomObject(nullptr),
+ mpLampShaftObject(nullptr),
+ maLightObjects(MAX_NUMBER_LIGHTS, nullptr),
+ mfRotateX(-20.0),
+ mfRotateY(45.0),
+ mfRotateZ(0.0),
+ mfSaveActionStartHor(0.0),
+ mfSaveActionStartVer(0.0),
+ mfSaveActionStartRotZ(0.0),
+ mbMouseMoved(false),
+ mbMouseCaptured(false),
+ mbGeometrySelected(false)
+{
+}
+
+void Svx3DLightControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Svx3DPreviewControl::SetDrawingArea(pDrawingArea);
+ Construct2();
+}
+
+void Svx3DLightControl::Construct2()
+{
+ {
+ // hide all page stuff, use control background (normally gray)
+ const Color aDialogColor(Application::GetSettings().GetStyleSettings().GetDialogColor());
+ mp3DView->SetPageVisible(false);
+ mp3DView->SetApplicationBackgroundColor(aDialogColor);
+ mp3DView->SetApplicationDocumentColor(aDialogColor);
+ }
+
+ {
+ // create invisible expansion object
+ const double fMaxExpansion(RADIUS_LAMP_BIG + RADIUS_LAMP_PREVIEW_SIZE);
+ mpExpansionObject = new E3dCubeObj(
+ *mpModel,
+ mp3DView->Get3DDefaultAttributes(),
+ basegfx::B3DPoint(-fMaxExpansion, -fMaxExpansion, -fMaxExpansion),
+ basegfx::B3DVector(2.0 * fMaxExpansion, 2.0 * fMaxExpansion, 2.0 * fMaxExpansion));
+ mpScene->InsertObject( mpExpansionObject );
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+ mpExpansionObject->SetMergedItemSet(aSet);
+ }
+
+ {
+ // create lamp control object (Yellow lined object)
+ // base circle
+ const basegfx::B2DPolygon a2DCircle(basegfx::utils::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), RADIUS_LAMP_PREVIEW_SIZE));
+ basegfx::B3DPolygon a3DCircle(basegfx::utils::createB3DPolygonFromB2DPolygon(a2DCircle));
+ basegfx::B3DHomMatrix aTransform;
+
+ aTransform.rotate(M_PI_2, 0.0, 0.0);
+ aTransform.translate(0.0, -RADIUS_LAMP_PREVIEW_SIZE, 0.0);
+ a3DCircle.transform(aTransform);
+
+ // create object for it
+ mpLampBottomObject = new E3dPolygonObj(
+ *mpModel,
+ basegfx::B3DPolyPolygon(a3DCircle));
+ mpScene->InsertObject( mpLampBottomObject );
+
+ // half circle with stand
+ basegfx::B2DPolygon a2DHalfCircle;
+ a2DHalfCircle.append(basegfx::B2DPoint(RADIUS_LAMP_PREVIEW_SIZE, 0.0));
+ a2DHalfCircle.append(basegfx::B2DPoint(RADIUS_LAMP_PREVIEW_SIZE, -RADIUS_LAMP_PREVIEW_SIZE));
+ a2DHalfCircle.append(basegfx::utils::createPolygonFromEllipseSegment(
+ basegfx::B2DPoint(0.0, 0.0), RADIUS_LAMP_PREVIEW_SIZE, RADIUS_LAMP_PREVIEW_SIZE, 2 * M_PI - M_PI_2, M_PI_2));
+ basegfx::B3DPolygon a3DHalfCircle(basegfx::utils::createB3DPolygonFromB2DPolygon(a2DHalfCircle));
+
+ // create object for it
+ mpLampShaftObject = new E3dPolygonObj(
+ *mpModel,
+ basegfx::B3DPolyPolygon(a3DHalfCircle));
+ mpScene->InsertObject( mpLampShaftObject );
+
+ // initially invisible
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+
+ mpLampBottomObject->SetMergedItemSet(aSet);
+ mpLampShaftObject->SetMergedItemSet(aSet);
+ }
+
+ {
+ // change camera settings
+ Camera3D rCamera = mpScene->GetCamera();
+ const basegfx::B3DRange& rVolume = mpScene->GetBoundVolume();
+ double fW = rVolume.getWidth();
+ double fH = rVolume.getHeight();
+ double fCamZ = rVolume.getMaxZ() + ((fW + fH) / 2.0);
+
+ rCamera.SetAutoAdjustProjection(false);
+ rCamera.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
+ basegfx::B3DPoint aLookAt;
+ double fDefaultCamPosZ = mp3DView->GetDefaultCamPosZ();
+ basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
+ rCamera.SetPosAndLookAt(aCamPos, aLookAt);
+ double fDefaultCamFocal = mp3DView->GetDefaultCamFocal();
+ rCamera.SetFocalLength(fDefaultCamFocal);
+
+ mpScene->SetCamera( rCamera );
+
+ basegfx::B3DHomMatrix aNeutral;
+ mpScene->SetTransform(aNeutral);
+ }
+
+ // invalidate SnapRects of objects
+ mpScene->SetBoundAndSnapRectsDirty();
+}
+
+void Svx3DLightControl::ConstructLightObjects()
+{
+ for(sal_uInt32 a(0); a < MAX_NUMBER_LIGHTS; a++)
+ {
+ // get rid of possible existing light object
+ if(maLightObjects[a])
+ {
+ mpScene->RemoveObject(maLightObjects[a]->GetOrdNum());
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(maLightObjects[a]);
+ SdrObject::Free(pTemp);
+ maLightObjects[a] = nullptr;
+ }
+
+ if(GetLightOnOff(a))
+ {
+ const bool bIsSelectedLight(a == maSelectedLight);
+ basegfx::B3DVector aDirection(GetLightDirection(a));
+ aDirection.normalize();
+ aDirection *= RADIUS_LAMP_PREVIEW_SIZE;
+
+ const double fLampSize(bIsSelectedLight ? RADIUS_LAMP_BIG : RADIUS_LAMP_SMALL);
+ E3dObject* pNewLight = new E3dSphereObj(
+ *mpModel,
+ mp3DView->Get3DDefaultAttributes(),
+ basegfx::B3DPoint( 0, 0, 0 ),
+ basegfx::B3DVector( fLampSize, fLampSize, fLampSize));
+ mpScene->InsertObject(pNewLight);
+
+ basegfx::B3DHomMatrix aTransform;
+ aTransform.translate(aDirection.getX(), aDirection.getY(), aDirection.getZ());
+ pNewLight->SetTransform(aTransform);
+
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ aSet.Put( XFillColorItem(OUString(), GetLightColor(a)));
+ pNewLight->SetMergedItemSet(aSet);
+
+ maLightObjects[a] = pNewLight;
+ }
+ }
+}
+
+void Svx3DLightControl::AdaptToSelectedLight()
+{
+ if(NO_LIGHT_SELECTED == maSelectedLight)
+ {
+ // make mpLampBottomObject/mpLampShaftObject invisible
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+ mpLampBottomObject->SetMergedItemSet(aSet);
+ mpLampShaftObject->SetMergedItemSet(aSet);
+ }
+ else
+ {
+ basegfx::B3DVector aDirection(GetLightDirection(maSelectedLight));
+ aDirection.normalize();
+
+ // make mpLampBottomObject/mpLampShaftObject visible (yellow hairline)
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put( XLineStyleItem( drawing::LineStyle_SOLID ) );
+ aSet.Put( XLineColorItem(OUString(), COL_YELLOW));
+ aSet.Put( XLineWidthItem(0));
+ aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+ mpLampBottomObject->SetMergedItemSet(aSet);
+ mpLampShaftObject->SetMergedItemSet(aSet);
+
+ // adapt transformation of mpLampShaftObject
+ basegfx::B3DHomMatrix aTransform;
+ double fRotateY(0.0);
+
+ if(!basegfx::fTools::equalZero(aDirection.getZ()) || !basegfx::fTools::equalZero(aDirection.getX()))
+ {
+ fRotateY = atan2(-aDirection.getZ(), aDirection.getX());
+ }
+
+ aTransform.rotate(0.0, fRotateY, 0.0);
+ mpLampShaftObject->SetTransform(aTransform);
+
+ // adapt transformation of selected light
+ E3dObject* pSelectedLight = maLightObjects[sal_Int32(maSelectedLight)];
+
+ if(pSelectedLight)
+ {
+ aTransform.identity();
+ aTransform.translate(
+ aDirection.getX() * RADIUS_LAMP_PREVIEW_SIZE,
+ aDirection.getY() * RADIUS_LAMP_PREVIEW_SIZE,
+ aDirection.getZ() * RADIUS_LAMP_PREVIEW_SIZE);
+ pSelectedLight->SetTransform(aTransform);
+ }
+ }
+}
+
+void Svx3DLightControl::TrySelection(Point aPosPixel)
+{
+ if(!mpScene)
+ return;
+
+ const Point aPosLogic(GetDrawingArea()->get_ref_device().PixelToLogic(aPosPixel));
+ const basegfx::B2DPoint aPoint(aPosLogic.X(), aPosLogic.Y());
+ std::vector< const E3dCompoundObject* > aResult;
+ getAllHit3DObjectsSortedFrontToBack(aPoint, *mpScene, aResult);
+
+ if(aResult.empty())
+ return;
+
+ // exclude expansion object which will be part of
+ // the hits. It's invisible, but for HitTest, it's included
+ const E3dCompoundObject* pResult = nullptr;
+
+ for(auto const & b: aResult)
+ {
+ if(b && b != mpExpansionObject)
+ {
+ pResult = b;
+ break;
+ }
+ }
+
+ if(pResult == mp3DObj)
+ {
+ if(!mbGeometrySelected)
+ {
+ mbGeometrySelected = true;
+ maSelectedLight = NO_LIGHT_SELECTED;
+ ConstructLightObjects();
+ AdaptToSelectedLight();
+ Invalidate();
+
+ if(maSelectionChangeCallback.IsSet())
+ {
+ maSelectionChangeCallback.Call(this);
+ }
+ }
+ }
+ else
+ {
+ sal_uInt32 aNewSelectedLight(NO_LIGHT_SELECTED);
+
+ for(sal_uInt32 a(0); a < MAX_NUMBER_LIGHTS; a++)
+ {
+ if(maLightObjects[a] && maLightObjects[a] == pResult)
+ {
+ aNewSelectedLight = a;
+ }
+ }
+
+ if(aNewSelectedLight != maSelectedLight)
+ {
+ SelectLight(aNewSelectedLight);
+
+ if(maSelectionChangeCallback.IsSet())
+ {
+ maSelectionChangeCallback.Call(this);
+ }
+ }
+ }
+}
+
+void Svx3DLightControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ Svx3DPreviewControl::Paint(rRenderContext, rRect);
+}
+
+tools::Rectangle Svx3DLightControl::GetFocusRect()
+{
+ if (!HasFocus())
+ return tools::Rectangle();
+ Size aFocusSize = GetOutputSizePixel();
+ aFocusSize.AdjustWidth( -4 );
+ aFocusSize.AdjustHeight( -4 );
+ return tools::Rectangle(Point(2, 2), aFocusSize);
+}
+
+bool Svx3DLightControl::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ bool bCallParent(true);
+
+ // switch state
+ if(rMEvt.IsLeft())
+ {
+ if(IsSelectionValid() || mbGeometrySelected)
+ {
+ mbMouseMoved = false;
+ bCallParent = false;
+ maActionStartPoint = rMEvt.GetPosPixel();
+ CaptureMouse();
+ mbMouseCaptured = true;
+ }
+ else
+ {
+ // Single click without moving much trying to do a selection
+ TrySelection(rMEvt.GetPosPixel());
+ bCallParent = false;
+ }
+ }
+
+ // call parent
+ if (bCallParent)
+ return Svx3DPreviewControl::MouseButtonDown(rMEvt);
+ return true;
+}
+
+bool Svx3DLightControl::MouseMove(const MouseEvent& rMEvt)
+{
+ if (!mbMouseCaptured)
+ return false;
+
+ Point aDeltaPos = rMEvt.GetPosPixel() - maActionStartPoint;
+
+ if(!mbMouseMoved)
+ {
+ if(sal_Int32(aDeltaPos.X() * aDeltaPos.X() + aDeltaPos.Y() * aDeltaPos.Y()) > g_nInteractionStartDistance)
+ {
+ if(mbGeometrySelected)
+ {
+ GetRotation(mfSaveActionStartVer, mfSaveActionStartHor, mfSaveActionStartRotZ);
+ }
+ else
+ {
+ // interaction start, save values
+ GetPosition(mfSaveActionStartHor, mfSaveActionStartVer);
+ }
+
+ mbMouseMoved = true;
+ }
+ }
+
+ if(mbMouseMoved)
+ {
+ if(mbGeometrySelected)
+ {
+ double fNewRotX = mfSaveActionStartVer - basegfx::deg2rad(aDeltaPos.Y());
+ double fNewRotY = mfSaveActionStartHor + basegfx::deg2rad(aDeltaPos.X());
+
+ // cut horizontal
+ while(fNewRotY < 0.0)
+ {
+ fNewRotY += 2 * M_PI;
+ }
+
+ while(fNewRotY >= 2 * M_PI)
+ {
+ fNewRotY -= 2 * M_PI;
+ }
+
+ // cut vertical
+ if(fNewRotX < -M_PI_2)
+ {
+ fNewRotX = -M_PI_2;
+ }
+
+ if(fNewRotX > M_PI_2)
+ {
+ fNewRotX = M_PI_2;
+ }
+
+ SetRotation(fNewRotX, fNewRotY, mfSaveActionStartRotZ);
+
+ if(maChangeCallback.IsSet())
+ {
+ maChangeCallback.Call(this);
+ }
+ }
+ else
+ {
+ // interaction in progress
+ double fNewPosHor = mfSaveActionStartHor + static_cast<double>(aDeltaPos.X());
+ double fNewPosVer = mfSaveActionStartVer - static_cast<double>(aDeltaPos.Y());
+
+ // cut horizontal
+ fNewPosHor = NormAngle360(fNewPosHor);
+
+ // cut vertical
+ if(fNewPosVer < -90.0)
+ {
+ fNewPosVer = -90.0;
+ }
+
+ if(fNewPosVer > 90.0)
+ {
+ fNewPosVer = 90.0;
+ }
+
+ SetPosition(fNewPosHor, fNewPosVer);
+
+ if(maChangeCallback.IsSet())
+ {
+ maChangeCallback.Call(this);
+ }
+ }
+ }
+ return true;
+}
+
+bool Svx3DLightControl::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if (!mbMouseCaptured)
+ return false;
+ ReleaseMouse();
+ mbMouseCaptured = false;
+
+ if (mbMouseMoved)
+ {
+ // was change interactively
+ }
+ else
+ {
+ // simple click without much movement, try selection
+ TrySelection(rMEvt.GetPosPixel());
+ }
+
+ return true;
+}
+
+void Svx3DLightControl::Resize()
+{
+ // set size of page
+ const Size aSize(GetDrawingArea()->get_ref_device().PixelToLogic(GetOutputSizePixel()));
+ mxFmPage->SetSize(aSize);
+
+ // set position and size of scene
+ mpScene->SetSnapRect(tools::Rectangle(Point(0, 0), aSize));
+}
+
+void Svx3DLightControl::SetObjectType(SvxPreviewObjectType nType)
+{
+ // call parent
+ Svx3DPreviewControl::SetObjectType(nType);
+
+ // apply object rotation
+ if(mp3DObj)
+ {
+ basegfx::B3DHomMatrix aObjectRotation;
+ aObjectRotation.rotate(mfRotateX, mfRotateY, mfRotateZ);
+ mp3DObj->SetTransform(aObjectRotation);
+ }
+}
+
+bool Svx3DLightControl::IsSelectionValid()
+{
+ return (NO_LIGHT_SELECTED != maSelectedLight) && GetLightOnOff(maSelectedLight);
+}
+
+void Svx3DLightControl::GetPosition(double& rHor, double& rVer)
+{
+ if(IsSelectionValid())
+ {
+ basegfx::B3DVector aDirection(GetLightDirection(maSelectedLight));
+ aDirection.normalize();
+ rHor = basegfx::rad2deg(atan2(-aDirection.getX(), -aDirection.getZ()) + M_PI); // 0..360.0
+ rVer = basegfx::rad2deg(atan2(aDirection.getY(), aDirection.getXZLength())); // -90.0..90.0
+ }
+ if(IsGeometrySelected())
+ {
+ rHor = basegfx::rad2deg(mfRotateY); // 0..360.0
+ rVer = basegfx::rad2deg(mfRotateX); // -90.0..90.0
+ }
+}
+
+void Svx3DLightControl::SetPosition(double fHor, double fVer)
+{
+ if(IsSelectionValid())
+ {
+ // set selected light's direction
+ fHor = basegfx::deg2rad(fHor) - M_PI; // -PI..PI
+ fVer = basegfx::deg2rad(fVer); // -PI2..PI2
+ basegfx::B3DVector aDirection(cos(fVer) * -sin(fHor), sin(fVer), cos(fVer) * -cos(fHor));
+ aDirection.normalize();
+
+ if(!aDirection.equal(GetLightDirection(maSelectedLight)))
+ {
+ // set changed light direction at SdrScene
+ SfxItemSet aSet(mpModel->GetItemPool());
+
+ switch(maSelectedLight)
+ {
+ case 0: aSet.Put(makeSvx3DLightDirection1Item(aDirection)); break;
+ case 1: aSet.Put(makeSvx3DLightDirection2Item(aDirection)); break;
+ case 2: aSet.Put(makeSvx3DLightDirection3Item(aDirection)); break;
+ case 3: aSet.Put(makeSvx3DLightDirection4Item(aDirection)); break;
+ case 4: aSet.Put(makeSvx3DLightDirection5Item(aDirection)); break;
+ case 5: aSet.Put(makeSvx3DLightDirection6Item(aDirection)); break;
+ case 6: aSet.Put(makeSvx3DLightDirection7Item(aDirection)); break;
+ default:
+ case 7: aSet.Put(makeSvx3DLightDirection8Item(aDirection)); break;
+ }
+
+ mpScene->SetMergedItemSet(aSet);
+
+ // correct 3D light's and LampFrame's geometries
+ AdaptToSelectedLight();
+ Invalidate();
+ }
+ }
+ if(!IsGeometrySelected())
+ return;
+
+ if(mfRotateX == fVer && mfRotateY == fHor)
+ return;
+
+ mfRotateX = basegfx::deg2rad(fVer);
+ mfRotateY = basegfx::deg2rad(fHor);
+
+ if(mp3DObj)
+ {
+ basegfx::B3DHomMatrix aObjectRotation;
+ aObjectRotation.rotate(mfRotateX, mfRotateY, mfRotateZ);
+ mp3DObj->SetTransform(aObjectRotation);
+
+ Invalidate();
+ }
+}
+
+void Svx3DLightControl::SetRotation(double fRotX, double fRotY, double fRotZ)
+{
+ if(!IsGeometrySelected())
+ return;
+
+ if(fRotX == mfRotateX && fRotY == mfRotateY && fRotZ == mfRotateZ)
+ return;
+
+ mfRotateX = fRotX;
+ mfRotateY = fRotY;
+ mfRotateZ = fRotZ;
+
+ if(mp3DObj)
+ {
+ basegfx::B3DHomMatrix aObjectRotation;
+ aObjectRotation.rotate(mfRotateX, mfRotateY, mfRotateZ);
+ mp3DObj->SetTransform(aObjectRotation);
+
+ Invalidate();
+ }
+}
+
+void Svx3DLightControl::GetRotation(double& rRotX, double& rRotY, double& rRotZ)
+{
+ rRotX = mfRotateX;
+ rRotY = mfRotateY;
+ rRotZ = mfRotateZ;
+}
+
+void Svx3DLightControl::Set3DAttributes( const SfxItemSet& rAttr )
+{
+ // call parent
+ Svx3DPreviewControl::Set3DAttributes(rAttr);
+
+ if(maSelectedLight != NO_LIGHT_SELECTED && !GetLightOnOff(maSelectedLight))
+ {
+ // selected light is no more active, select new one
+ maSelectedLight = NO_LIGHT_SELECTED;
+ }
+
+ // local updates
+ ConstructLightObjects();
+ AdaptToSelectedLight();
+ Invalidate();
+}
+
+void Svx3DLightControl::SelectLight(sal_uInt32 nLightNumber)
+{
+ if(nLightNumber > 7)
+ {
+ nLightNumber = NO_LIGHT_SELECTED;
+ }
+
+ if(NO_LIGHT_SELECTED != nLightNumber)
+ {
+ if(!GetLightOnOff(nLightNumber))
+ {
+ nLightNumber = NO_LIGHT_SELECTED;
+ }
+ }
+
+ if(nLightNumber != maSelectedLight)
+ {
+ maSelectedLight = nLightNumber;
+ mbGeometrySelected = false;
+ ConstructLightObjects();
+ AdaptToSelectedLight();
+ Invalidate();
+ }
+}
+
+bool Svx3DLightControl::GetLightOnOff(sal_uInt32 nNum) const
+{
+ if(nNum <= 7)
+ {
+ const SfxItemSet aLightItemSet(Get3DAttributes());
+
+ switch(nNum)
+ {
+ case 0 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_1).GetValue();
+ case 1 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_2).GetValue();
+ case 2 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_3).GetValue();
+ case 3 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_4).GetValue();
+ case 4 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_5).GetValue();
+ case 5 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_6).GetValue();
+ case 6 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_7).GetValue();
+ case 7 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_8).GetValue();
+ }
+ }
+
+ return false;
+}
+
+Color Svx3DLightControl::GetLightColor(sal_uInt32 nNum) const
+{
+ if(nNum <= 7)
+ {
+ const SfxItemSet aLightItemSet(Get3DAttributes());
+
+ switch(nNum)
+ {
+ case 0 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_1).GetValue();
+ case 1 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_2).GetValue();
+ case 2 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_3).GetValue();
+ case 3 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_4).GetValue();
+ case 4 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_5).GetValue();
+ case 5 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_6).GetValue();
+ case 6 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_7).GetValue();
+ case 7 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_8).GetValue();
+ }
+ }
+
+ return COL_BLACK;
+}
+
+basegfx::B3DVector Svx3DLightControl::GetLightDirection(sal_uInt32 nNum) const
+{
+ if(nNum <= 7)
+ {
+ const SfxItemSet aLightItemSet(Get3DAttributes());
+
+ switch(nNum)
+ {
+ case 0 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_1).GetValue();
+ case 1 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_2).GetValue();
+ case 2 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_3).GetValue();
+ case 3 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_4).GetValue();
+ case 4 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_5).GetValue();
+ case 5 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_6).GetValue();
+ case 6 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_7).GetValue();
+ case 7 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_8).GetValue();
+ }
+ }
+
+ return basegfx::B3DVector();
+}
+
+SvxLightCtl3D::SvxLightCtl3D(Svx3DLightControl& rLightControl, weld::Scale& rHori,
+ weld::Scale& rVert, weld::Button& rSwitcher)
+ : mrLightControl(rLightControl)
+ , mrHorScroller(rHori)
+ , mrVerScroller(rVert)
+ , mrSwitcher(rSwitcher)
+{
+ // init members
+ Init();
+}
+
+void SvxLightCtl3D::Init()
+{
+ Size aSize(mrLightControl.GetDrawingArea()->get_ref_device().LogicToPixel(Size(80, 100), MapMode(MapUnit::MapAppFont)));
+ mrLightControl.set_size_request(aSize.Width(), aSize.Height());
+
+ // #i58240# set HelpIDs for scrollbars and switcher
+ mrHorScroller.set_help_id(HID_CTRL3D_HSCROLL);
+ mrVerScroller.set_help_id(HID_CTRL3D_VSCROLL);
+ mrSwitcher.set_help_id(HID_CTRL3D_SWITCHER);
+ mrSwitcher.set_accessible_name(SvxResId(STR_SWITCH));
+
+ // Light preview
+ mrLightControl.Show();
+ mrLightControl.SetChangeCallback( LINK(this, SvxLightCtl3D, InternalInteractiveChange) );
+ mrLightControl.SetSelectionChangeCallback( LINK(this, SvxLightCtl3D, InternalSelectionChange) );
+
+ // Horiz Scrollbar
+ mrHorScroller.show();
+ mrHorScroller.set_range(0, 36000);
+ mrHorScroller.connect_value_changed( LINK(this, SvxLightCtl3D, ScrollBarMove) );
+
+ // Vert Scrollbar
+ mrVerScroller.show();
+ mrVerScroller.set_range(0, 18000);
+ mrVerScroller.connect_value_changed( LINK(this, SvxLightCtl3D, ScrollBarMove) );
+
+ // Switch Button
+ mrSwitcher.show();
+ mrSwitcher.connect_clicked( LINK(this, SvxLightCtl3D, ButtonPress) );
+
+ weld::DrawingArea* pArea = mrLightControl.GetDrawingArea();
+ pArea->connect_key_press(Link<const KeyEvent&, bool>()); //acknowledge we first remove the old one
+ pArea->connect_key_press(LINK(this, SvxLightCtl3D, KeyInput));
+
+ pArea->connect_focus_in(Link<weld::Widget&, void>()); //acknowledge we first remove the old one
+ pArea->connect_focus_in(LINK(this, SvxLightCtl3D, FocusIn));
+
+ // check selection
+ CheckSelection();
+}
+
+void SvxLightCtl3D::CheckSelection()
+{
+ const bool bSelectionValid(mrLightControl.IsSelectionValid() || mrLightControl.IsGeometrySelected());
+ mrHorScroller.set_sensitive(bSelectionValid);
+ mrVerScroller.set_sensitive(bSelectionValid);
+
+ if (bSelectionValid)
+ {
+ double fHor(0.0), fVer(0.0);
+ mrLightControl.GetPosition(fHor, fVer);
+ mrHorScroller.set_value( sal_Int32(fHor * 100.0) );
+ mrVerScroller.set_value( 18000 - sal_Int32((fVer + 90.0) * 100.0) );
+ }
+}
+
+void SvxLightCtl3D::move( double fDeltaHor, double fDeltaVer )
+{
+ double fHor(0.0), fVer(0.0);
+
+ mrLightControl.GetPosition(fHor, fVer);
+ fHor += fDeltaHor;
+ fVer += fDeltaVer;
+
+ if( fVer > 90.0 )
+ return;
+
+ if ( fVer < -90.0 )
+ return;
+
+ mrLightControl.SetPosition(fHor, fVer);
+ mrHorScroller.set_value( sal_Int32(fHor * 100.0) );
+ mrVerScroller.set_value( 18000 - sal_Int32((fVer + 90.0) * 100.0) );
+
+ if(maUserInteractiveChangeCallback.IsSet())
+ {
+ maUserInteractiveChangeCallback.Call(this);
+ }
+}
+
+IMPL_LINK(SvxLightCtl3D, KeyInput, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode aCode(rKEvt.GetKeyCode());
+
+ if (aCode.GetModifier())
+ return false;
+
+ bool bHandled = true;
+
+ switch ( aCode.GetCode() )
+ {
+ case KEY_SPACE:
+ {
+ break;
+ }
+ case KEY_LEFT:
+ {
+ move( -4.0, 0.0 ); // #i58242# changed move direction in X
+ break;
+ }
+ case KEY_RIGHT:
+ {
+ move( 4.0, 0.0 ); // #i58242# changed move direction in X
+ break;
+ }
+ case KEY_UP:
+ {
+ move( 0.0, 4.0 );
+ break;
+ }
+ case KEY_DOWN:
+ {
+ move( 0.0, -4.0 );
+ break;
+ }
+ case KEY_PAGEUP:
+ {
+ sal_Int32 nLight(mrLightControl.GetSelectedLight() - 1);
+
+ while((nLight >= 0) && !mrLightControl.GetLightOnOff(nLight))
+ {
+ nLight--;
+ }
+
+ if(nLight < 0)
+ {
+ nLight = 7;
+
+ while((nLight >= 0) && !mrLightControl.GetLightOnOff(nLight))
+ {
+ nLight--;
+ }
+ }
+
+ if(nLight >= 0)
+ {
+ mrLightControl.SelectLight(nLight);
+ CheckSelection();
+
+ if(maUserSelectionChangeCallback.IsSet())
+ {
+ maUserSelectionChangeCallback.Call(this);
+ }
+ }
+
+ break;
+ }
+ case KEY_PAGEDOWN:
+ {
+ sal_Int32 nLight(mrLightControl.GetSelectedLight() - 1);
+
+ while(nLight <= 7 && !mrLightControl.GetLightOnOff(nLight))
+ {
+ nLight++;
+ }
+
+ if(nLight > 7)
+ {
+ nLight = 0;
+
+ while(nLight <= 7 && !mrLightControl.GetLightOnOff(nLight))
+ {
+ nLight++;
+ }
+ }
+
+ if(nLight <= 7)
+ {
+ mrLightControl.SelectLight(nLight);
+ CheckSelection();
+
+ if(maUserSelectionChangeCallback.IsSet())
+ {
+ maUserSelectionChangeCallback.Call(this);
+ }
+ }
+
+ break;
+ }
+ default:
+ {
+ bHandled = false;
+ break;
+ }
+ }
+ return bHandled;
+}
+
+IMPL_LINK_NOARG(SvxLightCtl3D, FocusIn, weld::Widget&, void)
+{
+ if (mrLightControl.IsEnabled())
+ {
+ CheckSelection();
+ }
+}
+
+IMPL_LINK_NOARG(SvxLightCtl3D, ScrollBarMove, weld::Scale&, void)
+{
+ const sal_Int32 nHor(mrHorScroller.get_value());
+ const sal_Int32 nVer(mrVerScroller.get_value());
+
+ mrLightControl.SetPosition(
+ static_cast<double>(nHor) / 100.0,
+ static_cast<double>((18000 - nVer) - 9000) / 100.0);
+
+ if (maUserInteractiveChangeCallback.IsSet())
+ {
+ maUserInteractiveChangeCallback.Call(this);
+ }
+}
+
+IMPL_LINK_NOARG(SvxLightCtl3D, ButtonPress, weld::Button&, void)
+{
+ if(SvxPreviewObjectType::SPHERE == GetSvx3DLightControl().GetObjectType())
+ {
+ GetSvx3DLightControl().SetObjectType(SvxPreviewObjectType::CUBE);
+ }
+ else
+ {
+ GetSvx3DLightControl().SetObjectType(SvxPreviewObjectType::SPHERE);
+ }
+}
+
+IMPL_LINK_NOARG(SvxLightCtl3D, InternalInteractiveChange, Svx3DLightControl*, void)
+{
+ double fHor(0.0), fVer(0.0);
+
+ mrLightControl.GetPosition(fHor, fVer);
+ mrHorScroller.set_value( sal_Int32(fHor * 100.0) );
+ mrVerScroller.set_value( 18000 - sal_Int32((fVer + 90.0) * 100.0) );
+
+ if(maUserInteractiveChangeCallback.IsSet())
+ {
+ maUserInteractiveChangeCallback.Call(this);
+ }
+}
+
+IMPL_LINK_NOARG(SvxLightCtl3D, InternalSelectionChange, Svx3DLightControl*, void)
+{
+ CheckSelection();
+
+ if(maUserSelectionChangeCallback.IsSet())
+ {
+ maUserSelectionChangeCallback.Call(this);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dlgctrl.cxx b/svx/source/dialog/dlgctrl.cxx
new file mode 100644
index 000000000..35737285a
--- /dev/null
+++ b/svx/source/dialog/dlgctrl.cxx
@@ -0,0 +1,1479 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_wasm_strip.h>
+
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/event.hxx>
+#include <sfx2/dialoghelper.hxx>
+#include <sfx2/weldutils.hxx>
+#include <svx/relfld.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xtable.hxx>
+#include <bitmaps.hlst>
+#include <svx/dlgctrl.hxx>
+#include <tools/debug.hxx>
+#include <svxpixelctlaccessiblecontext.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svxrectctaccessiblecontext.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdopath.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <vcl/BitmapTools.hxx>
+
+#define OUTPUT_DRAWMODE_COLOR (DrawModeFlags::Default)
+#define OUTPUT_DRAWMODE_CONTRAST (DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient)
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::accessibility;
+
+// Control for display and selection of the corner points and
+// mid point of an object
+
+BitmapEx& SvxRectCtl::GetRectBitmap()
+{
+ if( !pBitmap )
+ InitRectBitmap();
+
+ return *pBitmap;
+}
+
+SvxRectCtl::SvxRectCtl(SvxTabPage* pPage)
+ : m_pPage(pPage)
+ , nBorderWidth(Application::GetDefaultDevice()->LogicToPixel(Size(200, 0), MapMode(MapUnit::Map100thMM)).Width())
+ , eRP(RectPoint::MM)
+ , eDefRP(RectPoint::MM)
+ , m_nState(CTL_STATE::NONE)
+ , mbCompleteDisable(false)
+{
+}
+
+void SvxRectCtl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_approximate_digit_width() * 25,
+ pDrawingArea->get_text_height() * 5);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ Resize_Impl(aSize);
+}
+
+void SvxRectCtl::SetControlSettings(RectPoint eRpt, sal_uInt16 nBorder)
+{
+ nBorderWidth = Application::GetDefaultDevice()->LogicToPixel(Size(nBorder, 0), MapMode(MapUnit::Map100thMM)).Width();
+ eDefRP = eRpt;
+ Resize();
+}
+
+SvxRectCtl::~SvxRectCtl()
+{
+ pBitmap.reset();
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ pAccContext.clear();
+#endif
+}
+
+void SvxRectCtl::Resize()
+{
+ Resize_Impl(GetOutputSizePixel());
+}
+
+void SvxRectCtl::Resize_Impl(const Size &rSize)
+{
+ aPtLT = Point( 0 + nBorderWidth, 0 + nBorderWidth );
+ aPtMT = Point( rSize.Width() / 2, 0 + nBorderWidth );
+ aPtRT = Point( rSize.Width() - nBorderWidth, 0 + nBorderWidth );
+
+ aPtLM = Point( 0 + nBorderWidth, rSize.Height() / 2 );
+ aPtMM = Point( rSize.Width() / 2, rSize.Height() / 2 );
+ aPtRM = Point( rSize.Width() - nBorderWidth, rSize.Height() / 2 );
+
+ aPtLB = Point( 0 + nBorderWidth, rSize.Height() - nBorderWidth );
+ aPtMB = Point( rSize.Width() / 2, rSize.Height() - nBorderWidth );
+ aPtRB = Point( rSize.Width() - nBorderWidth, rSize.Height() - nBorderWidth );
+
+ Reset();
+ StyleUpdated();
+}
+
+void SvxRectCtl::InitRectBitmap()
+{
+ pBitmap.reset();
+
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ svtools::ColorConfig aColorConfig;
+
+ pBitmap.reset(new BitmapEx(RID_SVXCTRL_RECTBTNS));
+
+ // set bitmap-colors
+ Color aColorAry1[7];
+ Color aColorAry2[7];
+ aColorAry1[0] = Color( 0xC0, 0xC0, 0xC0 ); // light-gray
+ aColorAry1[1] = Color( 0xFF, 0xFF, 0x00 ); // yellow
+ aColorAry1[2] = Color( 0xFF, 0xFF, 0xFF ); // white
+ aColorAry1[3] = Color( 0x80, 0x80, 0x80 ); // dark-gray
+ aColorAry1[4] = Color( 0x00, 0x00, 0x00 ); // black
+ aColorAry1[5] = Color( 0x00, 0xFF, 0x00 ); // green
+ aColorAry1[6] = Color( 0x00, 0x00, 0xFF ); // blue
+ aColorAry2[0] = rStyles.GetDialogColor(); // background
+ aColorAry2[1] = rStyles.GetWindowColor();
+ aColorAry2[2] = rStyles.GetLightColor();
+ aColorAry2[3] = rStyles.GetShadowColor();
+ aColorAry2[4] = rStyles.GetDarkShadowColor();
+ aColorAry2[5] = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor;
+ aColorAry2[6] = rStyles.GetDialogColor();
+
+#ifdef DBG_UTIL
+ static bool bModify = false;
+ bool& rModify = bModify;
+ if( rModify )
+ {
+ static int n = 0;
+ static sal_uInt8 r = 0xFF;
+ static sal_uInt8 g = 0x00;
+ static sal_uInt8 b = 0xFF;
+ int& rn = n;
+ sal_uInt8& rr = r;
+ sal_uInt8& rg = g;
+ sal_uInt8& rb = b;
+ aColorAry2[ rn ] = Color( rr, rg, rb );
+ }
+#endif
+
+ pBitmap->Replace( aColorAry1, aColorAry2, 7 );
+}
+
+void SvxRectCtl::StyleUpdated()
+{
+ pBitmap.reset(); // forces new creating of bitmap
+ CustomWidgetController::StyleUpdated();
+}
+
+void SvxRectCtl::InitSettings(vcl::RenderContext& rRenderContext)
+{
+ svtools::ColorConfig aColorConfig;
+ Color aTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
+ rRenderContext.SetTextColor(aTextColor);
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ rRenderContext.SetBackground(rStyleSettings.GetWindowColor());
+}
+
+// The clicked rectangle (3 x 3) is determined and the parent (dialog)
+// is notified that the item was changed
+bool SvxRectCtl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // CompletelyDisabled() added to have a disabled state for SvxRectCtl
+ if(!IsCompletelyDisabled())
+ {
+ aPtNew = GetApproxLogPtFromPixPt( rMEvt.GetPosPixel() );
+ eRP = GetRPFromPoint( aPtNew );
+ SetActualRP( eRP );
+
+ if (m_pPage)
+ m_pPage->PointChanged(GetDrawingArea(), eRP);
+ }
+ return true;
+}
+
+bool SvxRectCtl::KeyInput(const KeyEvent& rKeyEvt)
+{
+ // CompletelyDisabled() added to have a disabled state for SvxRectCtl
+ if (IsCompletelyDisabled())
+ return false;
+
+ RectPoint eNewRP = eRP;
+
+ switch( rKeyEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_DOWN:
+ {
+ if( !(m_nState & CTL_STATE::NOVERT) )
+ switch( eNewRP )
+ {
+ case RectPoint::LT: eNewRP = RectPoint::LM; break;
+ case RectPoint::MT: eNewRP = RectPoint::MM; break;
+ case RectPoint::RT: eNewRP = RectPoint::RM; break;
+ case RectPoint::LM: eNewRP = RectPoint::LB; break;
+ case RectPoint::MM: eNewRP = RectPoint::MB; break;
+ case RectPoint::RM: eNewRP = RectPoint::RB; break;
+ default: ; //prevent warning
+ }
+ }
+ break;
+ case KEY_UP:
+ {
+ if( !(m_nState & CTL_STATE::NOVERT) )
+ switch( eNewRP )
+ {
+ case RectPoint::LM: eNewRP = RectPoint::LT; break;
+ case RectPoint::MM: eNewRP = RectPoint::MT; break;
+ case RectPoint::RM: eNewRP = RectPoint::RT; break;
+ case RectPoint::LB: eNewRP = RectPoint::LM; break;
+ case RectPoint::MB: eNewRP = RectPoint::MM; break;
+ case RectPoint::RB: eNewRP = RectPoint::RM; break;
+ default: ; //prevent warning
+ }
+ }
+ break;
+ case KEY_LEFT:
+ {
+ if( !(m_nState & CTL_STATE::NOHORZ) )
+ switch( eNewRP )
+ {
+ case RectPoint::MT: eNewRP = RectPoint::LT; break;
+ case RectPoint::RT: eNewRP = RectPoint::MT; break;
+ case RectPoint::MM: eNewRP = RectPoint::LM; break;
+ case RectPoint::RM: eNewRP = RectPoint::MM; break;
+ case RectPoint::MB: eNewRP = RectPoint::LB; break;
+ case RectPoint::RB: eNewRP = RectPoint::MB; break;
+ default: ; //prevent warning
+ }
+ }
+ break;
+ case KEY_RIGHT:
+ {
+ if( !(m_nState & CTL_STATE::NOHORZ) )
+ switch( eNewRP )
+ {
+ case RectPoint::LT: eNewRP = RectPoint::MT; break;
+ case RectPoint::MT: eNewRP = RectPoint::RT; break;
+ case RectPoint::LM: eNewRP = RectPoint::MM; break;
+ case RectPoint::MM: eNewRP = RectPoint::RM; break;
+ case RectPoint::LB: eNewRP = RectPoint::MB; break;
+ case RectPoint::MB: eNewRP = RectPoint::RB; break;
+ default: ; //prevent warning
+ }
+ }
+ break;
+ default:
+ return false;
+ }
+ if( eNewRP != eRP )
+ {
+ SetActualRP( eNewRP );
+
+ if (m_pPage)
+ m_pPage->PointChanged(GetDrawingArea(), eRP);
+ }
+ return true;
+}
+
+// the control (rectangle with 9 circles)
+void SvxRectCtl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ InitSettings(rRenderContext);
+
+ Point aPtDiff(1, 1);
+
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+
+ rRenderContext.SetLineColor(rStyles.GetDialogColor());
+ rRenderContext.SetFillColor(rStyles.GetDialogColor());
+ rRenderContext.DrawRect(tools::Rectangle(Point(0,0), rRenderContext.GetOutputSize()));
+
+ if (IsEnabled())
+ rRenderContext.SetLineColor(rStyles.GetLabelTextColor());
+ else
+ rRenderContext.SetLineColor(rStyles.GetShadowColor());
+
+ rRenderContext.SetFillColor();
+
+ if (!IsEnabled())
+ {
+ Color aOldCol = rRenderContext.GetLineColor();
+ rRenderContext.SetLineColor(rStyles.GetLightColor());
+ rRenderContext.DrawRect(tools::Rectangle(aPtLT + aPtDiff, aPtRB + aPtDiff));
+ rRenderContext.SetLineColor(aOldCol);
+ }
+ rRenderContext.DrawRect(tools::Rectangle(aPtLT, aPtRB));
+
+ rRenderContext.SetFillColor(rRenderContext.GetBackground().GetColor());
+
+ Size aBtnSize(11, 11);
+ Size aDstBtnSize(aBtnSize);
+ Point aToCenter(aDstBtnSize.Width() >> 1, aDstBtnSize.Height() >> 1);
+ Point aBtnPnt1(IsEnabled() ? 0 : 22, 0);
+ Point aBtnPnt2(11, 0);
+ Point aBtnPnt3(22, 0);
+
+ bool bNoHorz = bool(m_nState & CTL_STATE::NOHORZ);
+ bool bNoVert = bool(m_nState & CTL_STATE::NOVERT);
+
+ BitmapEx& rBitmap = GetRectBitmap();
+
+ // CompletelyDisabled() added to have a disabled state for SvxRectCtl
+ if (IsCompletelyDisabled())
+ {
+ rRenderContext.DrawBitmapEx(aPtLT - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtMT - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtRT - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtLM - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtMM - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtRM - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtLB - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtMB - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtRB - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ }
+ else
+ {
+ rRenderContext.DrawBitmapEx(aPtLT - aToCenter, aDstBtnSize, (bNoHorz || bNoVert)?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtMT - aToCenter, aDstBtnSize, bNoVert?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtRT - aToCenter, aDstBtnSize, (bNoHorz || bNoVert)?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtLM - aToCenter, aDstBtnSize, bNoHorz?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+
+ // Center for rectangle and line
+ rRenderContext.DrawBitmapEx(aPtMM - aToCenter, aDstBtnSize, aBtnPnt1, aBtnSize, rBitmap);
+
+ rRenderContext.DrawBitmapEx(aPtRM - aToCenter, aDstBtnSize, bNoHorz?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtLB - aToCenter, aDstBtnSize, (bNoHorz || bNoVert)?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtMB - aToCenter, aDstBtnSize, bNoVert?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtRB - aToCenter, aDstBtnSize, (bNoHorz || bNoVert)?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ }
+
+ // draw active button, avoid center pos for angle
+ // CompletelyDisabled() added to have a disabled state for SvxRectCtl
+ if (!IsCompletelyDisabled())
+ {
+ if (IsEnabled())
+ {
+ Point aCenterPt(aPtNew);
+ aCenterPt -= aToCenter;
+
+ rRenderContext.DrawBitmapEx(aCenterPt, aDstBtnSize, aBtnPnt2, aBtnSize, rBitmap);
+ }
+ }
+}
+
+tools::Rectangle SvxRectCtl::GetFocusRect()
+{
+ tools::Rectangle aRet;
+ if (HasFocus())
+ aRet = CalculateFocusRectangle();
+ return aRet;
+}
+
+// Convert RectPoint Point
+
+const Point& SvxRectCtl::GetPointFromRP( RectPoint _eRP) const
+{
+ switch( _eRP )
+ {
+ case RectPoint::LT: return aPtLT;
+ case RectPoint::MT: return aPtMT;
+ case RectPoint::RT: return aPtRT;
+ case RectPoint::LM: return aPtLM;
+ case RectPoint::MM: return aPtMM;
+ case RectPoint::RM: return aPtRM;
+ case RectPoint::LB: return aPtLB;
+ case RectPoint::MB: return aPtMB;
+ case RectPoint::RB: return aPtRB;
+ }
+ return aPtMM; // default
+}
+
+Point SvxRectCtl::SetActualRPWithoutInvalidate( RectPoint eNewRP )
+{
+ Point aPtLast = aPtNew;
+ aPtNew = GetPointFromRP( eNewRP );
+
+ if( m_nState & CTL_STATE::NOHORZ )
+ aPtNew.setX( aPtMM.X() );
+
+ if( m_nState & CTL_STATE::NOVERT )
+ aPtNew.setY( aPtMM.Y() );
+
+ // fdo#74751 this fix reverse base point on RTL UI.
+ bool bRTL = AllSettings::GetLayoutRTL();
+ eNewRP = GetRPFromPoint( aPtNew, bRTL );
+
+ eDefRP = eNewRP;
+ eRP = eNewRP;
+
+ return aPtLast;
+}
+
+void SvxRectCtl::GetFocus()
+{
+ Invalidate();
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ // Send accessibility event.
+ if (pAccContext.is())
+ {
+ pAccContext->FireChildFocus(GetActualRP());
+ }
+#endif
+}
+
+void SvxRectCtl::LoseFocus()
+{
+ Invalidate();
+}
+
+Point SvxRectCtl::GetApproxLogPtFromPixPt( const Point& rPt ) const
+{
+ Point aPt = rPt;
+ tools::Long x;
+ tools::Long y;
+
+ Size aSize(GetOutputSizePixel());
+
+ if( !( m_nState & CTL_STATE::NOHORZ ) )
+ {
+ if( aPt.X() < aSize.Width() / 3 )
+ x = aPtLT.X();
+ else if( aPt.X() < aSize.Width() * 2 / 3 )
+ x = aPtMM.X();
+ else
+ x = aPtRB.X();
+ }
+ else
+ x = aPtMM.X();
+
+ if( !( m_nState & CTL_STATE::NOVERT ) )
+ {
+ if( aPt.Y() < aSize.Height() / 3 )
+ y = aPtLT.Y();
+ else if( aPt.Y() < aSize.Height() * 2 / 3 )
+ y = aPtMM.Y();
+ else
+ y = aPtRB.Y();
+ }
+ else
+ y = aPtMM.Y();
+
+ return Point( x, y );
+}
+
+
+// Converts Point in RectPoint
+
+RectPoint SvxRectCtl::GetRPFromPoint( Point aPt, bool bRTL ) const
+{
+ RectPoint rPoint = RectPoint::MM; // default
+
+ if (aPt == aPtLT) rPoint = bRTL ? RectPoint::RT : RectPoint::LT;
+ else if( aPt == aPtMT) rPoint = RectPoint::MT;
+ else if( aPt == aPtRT) rPoint = bRTL ? RectPoint::LT : RectPoint::RT;
+ else if( aPt == aPtLM) rPoint = bRTL ? RectPoint::RM : RectPoint::LM;
+ else if( aPt == aPtRM) rPoint = bRTL ? RectPoint::LM : RectPoint::RM;
+ else if( aPt == aPtLB) rPoint = bRTL ? RectPoint::RB : RectPoint::LB;
+ else if( aPt == aPtMB) rPoint = RectPoint::MB;
+ else if( aPt == aPtRB) rPoint = bRTL ? RectPoint::LB : RectPoint::RB;
+
+ return rPoint;
+}
+
+// Resets to the original state of the control
+
+void SvxRectCtl::Reset()
+{
+ aPtNew = GetPointFromRP( eDefRP );
+ eRP = eDefRP;
+ Invalidate();
+}
+
+// Returns the currently selected RectPoint
+
+
+void SvxRectCtl::SetActualRP( RectPoint eNewRP )
+{
+ SetActualRPWithoutInvalidate(eNewRP);
+
+ Invalidate();
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ // notify accessibility object about change
+ if (pAccContext.is())
+ pAccContext->selectChild( eNewRP /* MT, bFireFocus */ );
+#endif
+}
+
+void SvxRectCtl::SetState( CTL_STATE nState )
+{
+ m_nState = nState;
+
+ Point aPtLast( GetPointFromRP( eRP ) );
+ Point _aPtNew( aPtLast );
+
+ if( m_nState & CTL_STATE::NOHORZ )
+ _aPtNew.setX( aPtMM.X() );
+
+ if( m_nState & CTL_STATE::NOVERT)
+ _aPtNew.setY( aPtMM.Y() );
+
+ eRP = GetRPFromPoint( _aPtNew );
+ Invalidate();
+
+ if (m_pPage)
+ m_pPage->PointChanged(GetDrawingArea(), eRP);
+}
+
+tools::Rectangle SvxRectCtl::CalculateFocusRectangle() const
+{
+ Size aDstBtnSize(15, 15);
+ return tools::Rectangle( aPtNew - Point( aDstBtnSize.Width() >> 1, aDstBtnSize.Height() >> 1 ), aDstBtnSize );
+}
+
+tools::Rectangle SvxRectCtl::CalculateFocusRectangle( RectPoint eRectPoint ) const
+{
+ tools::Rectangle aRet;
+ RectPoint eOldRectPoint = GetActualRP();
+
+ if( eOldRectPoint == eRectPoint )
+ aRet = CalculateFocusRectangle();
+ else
+ {
+ SvxRectCtl* pThis = const_cast<SvxRectCtl*>(this);
+
+ pThis->SetActualRPWithoutInvalidate( eRectPoint ); // no invalidation because it's only temporary!
+ aRet = CalculateFocusRectangle();
+
+ pThis->SetActualRPWithoutInvalidate( eOldRectPoint ); // no invalidation because nothing has changed!
+ }
+
+ return aRet;
+}
+
+Reference< XAccessible > SvxRectCtl::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ pAccContext = new SvxRectCtlAccessibleContext(this);
+#endif
+ return pAccContext;
+}
+
+RectPoint SvxRectCtl::GetApproxRPFromPixPt( const css::awt::Point& r ) const
+{
+ return GetRPFromPoint( GetApproxLogPtFromPixPt( Point( r.X, r.Y ) ) );
+}
+
+// CompletelyDisabled() added to have a disabled state for SvxRectCtl
+void SvxRectCtl::DoCompletelyDisable(bool bNew)
+{
+ mbCompleteDisable = bNew;
+ Invalidate();
+}
+
+// Control for editing bitmaps
+
+css::uno::Reference< css::accessibility::XAccessible > SvxPixelCtl::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (!m_xAccess.is())
+ m_xAccess = new SvxPixelCtlAccessible(this);
+#endif
+ return m_xAccess;
+}
+
+tools::Long SvxPixelCtl::PointToIndex(const Point &aPt) const
+{
+ tools::Long nX = aPt.X() * nLines / aRectSize.Width();
+ tools::Long nY = aPt.Y() * nLines / aRectSize.Height();
+
+ return nX + nY * nLines ;
+}
+
+Point SvxPixelCtl::IndexToPoint(tools::Long nIndex) const
+{
+ DBG_ASSERT(nIndex >= 0 && nIndex < nSquares ," Check Index");
+
+ sal_Int32 nXIndex = nIndex % nLines;
+ sal_Int32 nYIndex = nIndex / nLines;
+
+ Point aPtTl;
+ aPtTl.setY( aRectSize.Height() * nYIndex / nLines + 1 );
+ aPtTl.setX( aRectSize.Width() * nXIndex / nLines + 1 );
+
+ return aPtTl;
+}
+
+tools::Long SvxPixelCtl::GetFocusPosIndex() const
+{
+ return aFocusPosition.getX() + aFocusPosition.getY() * nLines ;
+}
+
+tools::Long SvxPixelCtl::ShowPosition( const Point &rPt)
+{
+ sal_Int32 nX = rPt.X() * nLines / aRectSize.Width();
+ sal_Int32 nY = rPt.Y() * nLines / aRectSize.Height();
+
+ ChangePixel( nX + nY * nLines );
+
+ //Solution:Set new focus position and repaint
+ aFocusPosition.setX(nX);
+ aFocusPosition.setY(nY);
+ Invalidate(tools::Rectangle(Point(0,0),aRectSize));
+
+ if (m_pPage)
+ m_pPage->PointChanged(GetDrawingArea(), RectPoint::MM ); // RectPoint is dummy
+
+ return GetFocusPosIndex();
+
+}
+
+SvxPixelCtl::SvxPixelCtl(SvxTabPage* pPage)
+ : m_pPage(pPage)
+ , bPaintable(true)
+ , aFocusPosition(0,0)
+{
+ maPixelData.fill(0);
+}
+
+void SvxPixelCtl::Resize()
+{
+ CustomWidgetController::Resize();
+ aRectSize = GetOutputSizePixel();
+}
+
+void SvxPixelCtl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 25,
+ pDrawingArea->get_text_height() * 10);
+}
+
+SvxPixelCtl::~SvxPixelCtl()
+{
+}
+
+// Changes the foreground or Background color
+
+void SvxPixelCtl::ChangePixel( sal_uInt16 nPixel )
+{
+ if( maPixelData[nPixel] == 0 )
+ maPixelData[nPixel] = 1; // could be extended to more colors
+ else
+ maPixelData[nPixel] = 0;
+}
+
+// The clicked rectangle is identified, to change its color
+
+bool SvxPixelCtl::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if (!aRectSize.Width() || !aRectSize.Height())
+ return true;
+
+ //Grab focus when click in window
+ if (!HasFocus())
+ {
+ GrabFocus();
+ }
+
+ tools::Long nIndex = ShowPosition(rMEvt.GetPosPixel());
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if(m_xAccess.is())
+ {
+ m_xAccess->NotifyChild(nIndex,true, true);
+ }
+#else
+ (void)nIndex;
+#endif
+
+ return true;
+}
+
+tools::Rectangle SvxPixelCtl::GetFocusRect()
+{
+ tools::Rectangle aRet;
+ //Draw visual focus when has focus
+ if (HasFocus())
+ aRet = implCalFocusRect(aFocusPosition);
+ return aRet;
+}
+
+// Draws the Control (Rectangle with nine circles)
+void SvxPixelCtl::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
+{
+ if (!aRectSize.Width() || !aRectSize.Height())
+ return;
+
+ sal_uInt16 i, j, nTmp;
+ Point aPtTl, aPtBr;
+
+ if (bPaintable)
+ {
+ // Draw lines
+ rRenderContext.SetLineColor(Color());
+ for (i = 1; i < nLines; i++)
+ {
+ // horizontal
+ nTmp = static_cast<sal_uInt16>(aRectSize.Height() * i / nLines);
+ rRenderContext.DrawLine(Point(0, nTmp), Point(aRectSize.Width(), nTmp));
+ // vertically
+ nTmp = static_cast<sal_uInt16>( aRectSize.Width() * i / nLines );
+ rRenderContext.DrawLine(Point(nTmp, 0), Point(nTmp, aRectSize.Height()));
+ }
+
+ //Draw Rectangles (squares)
+ rRenderContext.SetLineColor();
+ sal_uInt16 nLastPixel = maPixelData[0] ? 0 : 1;
+
+ for (i = 0; i < nLines; i++)
+ {
+ aPtTl.setY( aRectSize.Height() * i / nLines + 1 );
+ aPtBr.setY( aRectSize.Height() * (i + 1) / nLines - 1 );
+
+ for (j = 0; j < nLines; j++)
+ {
+ aPtTl.setX( aRectSize.Width() * j / nLines + 1 );
+ aPtBr.setX( aRectSize.Width() * (j + 1) / nLines - 1 );
+
+ if (maPixelData[i * nLines + j] != nLastPixel)
+ {
+ nLastPixel = maPixelData[i * nLines + j];
+ // Change color: 0 -> Background color
+ rRenderContext.SetFillColor(nLastPixel ? aPixelColor : aBackgroundColor);
+ }
+ rRenderContext.DrawRect(tools::Rectangle(aPtTl, aPtBr));
+ }
+ }
+ }
+ else
+ {
+ rRenderContext.SetBackground(Wallpaper(COL_LIGHTGRAY));
+ rRenderContext.SetLineColor(COL_LIGHTRED);
+ rRenderContext.DrawLine(Point(0, 0), Point(aRectSize.Width(), aRectSize.Height()));
+ rRenderContext.DrawLine(Point(0, aRectSize.Height()), Point(aRectSize.Width(), 0));
+ }
+}
+
+//Calculate visual focus rectangle via focus position
+tools::Rectangle SvxPixelCtl::implCalFocusRect( const Point& aPosition )
+{
+ tools::Long nLeft,nTop,nRight,nBottom;
+ tools::Long i,j;
+ i = aPosition.Y();
+ j = aPosition.X();
+ nLeft = aRectSize.Width() * j / nLines + 1;
+ nRight = aRectSize.Width() * (j + 1) / nLines - 1;
+ nTop = aRectSize.Height() * i / nLines + 1;
+ nBottom = aRectSize.Height() * (i + 1) / nLines - 1;
+ return tools::Rectangle(nLeft,nTop,nRight,nBottom);
+}
+
+//Solution:Keyboard function
+bool SvxPixelCtl::KeyInput( const KeyEvent& rKEvt )
+{
+ vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
+ sal_uInt16 nCode = aKeyCode.GetCode();
+ bool bIsMod = aKeyCode.IsShift() || aKeyCode.IsMod1() || aKeyCode.IsMod2();
+
+ if( !bIsMod )
+ {
+ Point aRepaintPoint( aRectSize.Width() *( aFocusPosition.getX() - 1)/ nLines - 1,
+ aRectSize.Height() *( aFocusPosition.getY() - 1)/ nLines -1
+ );
+ Size aRepaintSize( aRectSize.Width() *3/ nLines + 2,aRectSize.Height() *3/ nLines + 2);
+ tools::Rectangle aRepaintRect( aRepaintPoint, aRepaintSize );
+ bool bFocusPosChanged=false;
+ switch(nCode)
+ {
+ case KEY_LEFT:
+ if(aFocusPosition.getX() >= 1)
+ {
+ aFocusPosition.setX( aFocusPosition.getX() - 1 );
+ Invalidate(aRepaintRect);
+ bFocusPosChanged=true;
+ }
+ break;
+ case KEY_RIGHT:
+ if( aFocusPosition.getX() < (nLines - 1) )
+ {
+ aFocusPosition.setX( aFocusPosition.getX() + 1 );
+ Invalidate(aRepaintRect);
+ bFocusPosChanged=true;
+ }
+ break;
+ case KEY_UP:
+ if(aFocusPosition.getY() >= 1)
+ {
+ aFocusPosition.setY( aFocusPosition.getY() - 1 );
+ Invalidate(aRepaintRect);
+ bFocusPosChanged=true;
+ }
+ break;
+ case KEY_DOWN:
+ if( aFocusPosition.getY() < ( nLines - 1 ) )
+ {
+ aFocusPosition.setY( aFocusPosition.getY() + 1 );
+ Invalidate(aRepaintRect);
+ bFocusPosChanged=true;
+ }
+ break;
+ case KEY_SPACE:
+ ChangePixel( sal_uInt16(aFocusPosition.getX() + aFocusPosition.getY() * nLines) );
+ Invalidate( implCalFocusRect(aFocusPosition) );
+ break;
+ default:
+ return CustomWidgetController::KeyInput( rKEvt );
+ }
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if(m_xAccess.is())
+ {
+ tools::Long nIndex = GetFocusPosIndex();
+ switch(nCode)
+ {
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ case KEY_UP:
+ case KEY_DOWN:
+ if (bFocusPosChanged)
+ {
+ m_xAccess->NotifyChild(nIndex,false,false);
+ }
+ break;
+ case KEY_SPACE:
+ m_xAccess->NotifyChild(nIndex,false,true);
+ break;
+ default:
+ break;
+ }
+ }
+#else
+ (void)bFocusPosChanged;
+#endif
+ return true;
+ }
+ else
+ {
+ return CustomWidgetController::KeyInput( rKEvt );
+ }
+}
+
+//Draw focus when get focus
+void SvxPixelCtl::GetFocus()
+{
+ Invalidate(implCalFocusRect(aFocusPosition));
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccess.is())
+ {
+ m_xAccess->NotifyChild(GetFocusPosIndex(),true,false);
+ }
+#endif
+}
+
+void SvxPixelCtl::LoseFocus()
+{
+ Invalidate();
+}
+
+void SvxPixelCtl::SetXBitmap(const BitmapEx& rBitmapEx)
+{
+ if (vcl::bitmap::isHistorical8x8(rBitmapEx, aBackgroundColor, aPixelColor))
+ {
+ for (sal_uInt16 i = 0; i < nSquares; i++)
+ {
+ Color aColor = rBitmapEx.GetPixelColor(i%8, i/8);
+ maPixelData[i] = (aColor == aBackgroundColor) ? 0 : 1;
+ }
+ }
+}
+
+// Returns a specific pixel
+
+sal_uInt8 SvxPixelCtl::GetBitmapPixel( const sal_uInt16 nPixel ) const
+{
+ return maPixelData[nPixel];
+}
+
+// Resets to the original state of the control
+
+void SvxPixelCtl::Reset()
+{
+ // clear pixel area
+ maPixelData.fill(0);
+ Invalidate();
+}
+
+SvxLineLB::SvxLineLB(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+ , mbAddStandardFields(true)
+{
+}
+
+void SvxLineLB::setAddStandardFields(bool bNew)
+{
+ if(getAddStandardFields() != bNew)
+ {
+ mbAddStandardFields = bNew;
+ }
+}
+
+// Fills the listbox (provisional) with strings
+
+void SvxLineLB::Fill( const XDashListRef &pList )
+{
+ m_xControl->clear();
+
+ if( !pList.is() )
+ return;
+
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ if(getAddStandardFields())
+ {
+ // entry for 'none'
+ m_xControl->append_text(pList->GetStringForUiNoLine());
+
+ // entry for solid line
+ const BitmapEx aBitmap = pList->GetBitmapForUISolidLine();
+ const Size aBmpSize(aBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), aBitmap);
+ m_xControl->append("", pList->GetStringForUiSolidLine(), *pVD);
+ }
+
+ // entries for dashed lines
+
+ tools::Long nCount = pList->Count();
+ m_xControl->freeze();
+
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ const XDashEntry* pEntry = pList->GetDash(i);
+ const BitmapEx aBitmap = pList->GetUiBitmap( i );
+ if( !aBitmap.IsEmpty() )
+ {
+ const Size aBmpSize(aBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), aBitmap);
+ m_xControl->append("", pEntry->GetName(), *pVD);
+ }
+ else
+ {
+ m_xControl->append_text(pEntry->GetName());
+ }
+ }
+
+ m_xControl->thaw();
+}
+
+void SvxLineLB::Append( const XDashEntry& rEntry, const BitmapEx& rBitmap )
+{
+ if (!rBitmap.IsEmpty())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ const Size aBmpSize(rBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), rBitmap);
+ m_xControl->append("", rEntry.GetName(), *pVD);
+ }
+ else
+ {
+ m_xControl->append_text(rEntry.GetName());
+ }
+}
+
+void SvxLineLB::Modify(const XDashEntry& rEntry, sal_Int32 nPos, const BitmapEx& rBitmap)
+{
+ m_xControl->remove(nPos);
+
+ if (!rBitmap.IsEmpty())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ const Size aBmpSize(rBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), rBitmap);
+ m_xControl->insert(nPos, rEntry.GetName(), nullptr, nullptr, pVD);
+ }
+ else
+ {
+ m_xControl->insert_text(nPos, rEntry.GetName());
+ }
+}
+
+SvxLineEndLB::SvxLineEndLB(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+{
+}
+
+void SvxLineEndLB::Fill( const XLineEndListRef &pList, bool bStart )
+{
+ if( !pList.is() )
+ return;
+
+ tools::Long nCount = pList->Count();
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ m_xControl->freeze();
+
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ const XLineEndEntry* pEntry = pList->GetLineEnd(i);
+ const BitmapEx aBitmap = pList->GetUiBitmap( i );
+ if( !aBitmap.IsEmpty() )
+ {
+ const Size aBmpSize(aBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(Size(aBmpSize.Width() / 2, aBmpSize.Height()), false);
+ pVD->DrawBitmapEx(bStart ? Point() : Point(-aBmpSize.Width() / 2, 0), aBitmap);
+ m_xControl->append("", pEntry->GetName(), *pVD);
+ }
+ else
+ m_xControl->append_text(pEntry->GetName());
+ }
+
+ m_xControl->thaw();
+}
+
+void SvxLineEndLB::Append( const XLineEndEntry& rEntry, const BitmapEx& rBitmap )
+{
+ if(!rBitmap.IsEmpty())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ const Size aBmpSize(rBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(Size(aBmpSize.Width() / 2, aBmpSize.Height()), false);
+ pVD->DrawBitmapEx(Point(-aBmpSize.Width() / 2, 0), rBitmap);
+ m_xControl->append("", rEntry.GetName(), *pVD);
+ }
+ else
+ {
+ m_xControl->append_text(rEntry.GetName());
+ }
+}
+
+void SvxLineEndLB::Modify( const XLineEndEntry& rEntry, sal_Int32 nPos, const BitmapEx& rBitmap )
+{
+ m_xControl->remove(nPos);
+
+ if(!rBitmap.IsEmpty())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ const Size aBmpSize(rBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(Size(aBmpSize.Width() / 2, aBmpSize.Height()), false);
+ pVD->DrawBitmapEx(Point(-aBmpSize.Width() / 2, 0), rBitmap);
+ m_xControl->insert(nPos, rEntry.GetName(), nullptr, nullptr, pVD);
+ }
+ else
+ {
+ m_xControl->insert_text(nPos, rEntry.GetName());
+ }
+}
+
+void SvxXLinePreview::Resize()
+{
+ SvxPreviewBase::Resize();
+
+ const Size aOutputSize(GetOutputSize());
+ const sal_Int32 nDistance(500);
+ const sal_Int32 nAvailableLength(aOutputSize.Width() - (4 * nDistance));
+
+ // create DrawObjectA
+ const sal_Int32 aYPosA(aOutputSize.Height() / 2);
+ const basegfx::B2DPoint aPointA1( nDistance, aYPosA);
+ const basegfx::B2DPoint aPointA2( aPointA1.getX() + ((nAvailableLength * 14) / 20), aYPosA );
+ basegfx::B2DPolygon aPolygonA;
+ aPolygonA.append(aPointA1);
+ aPolygonA.append(aPointA2);
+ mpLineObjA->SetPathPoly(basegfx::B2DPolyPolygon(aPolygonA));
+
+ // create DrawObjectB
+ const sal_Int32 aYPosB1((aOutputSize.Height() * 3) / 4);
+ const sal_Int32 aYPosB2((aOutputSize.Height() * 1) / 4);
+ const basegfx::B2DPoint aPointB1( aPointA2.getX() + nDistance, aYPosB1);
+ const basegfx::B2DPoint aPointB2( aPointB1.getX() + ((nAvailableLength * 2) / 20), aYPosB2 );
+ const basegfx::B2DPoint aPointB3( aPointB2.getX() + ((nAvailableLength * 2) / 20), aYPosB1 );
+ basegfx::B2DPolygon aPolygonB;
+ aPolygonB.append(aPointB1);
+ aPolygonB.append(aPointB2);
+ aPolygonB.append(aPointB3);
+ mpLineObjB->SetPathPoly(basegfx::B2DPolyPolygon(aPolygonB));
+
+ // create DrawObjectC
+ basegfx::B2DPolygon aPolygonC;
+ const basegfx::B2DPoint aPointC1( aPointB3.getX() + nDistance, aYPosB1);
+ const basegfx::B2DPoint aPointC2( aPointC1.getX() + ((nAvailableLength * 1) / 20), aYPosB2 );
+ const basegfx::B2DPoint aPointC3( aPointC2.getX() + ((nAvailableLength * 1) / 20), aYPosB1 );
+ aPolygonC.append(aPointC1);
+ aPolygonC.append(aPointC2);
+ aPolygonC.append(aPointC3);
+ mpLineObjC->SetPathPoly(basegfx::B2DPolyPolygon(aPolygonC));
+}
+
+SvxXLinePreview::SvxXLinePreview()
+ : mpLineObjA(nullptr)
+ , mpLineObjB(nullptr)
+ , mpLineObjC(nullptr)
+ , mpGraphic(nullptr)
+ , mbWithSymbol(false)
+{
+}
+
+void SvxXLinePreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ SvxPreviewBase::SetDrawingArea(pDrawingArea);
+
+ mpLineObjA = new SdrPathObj(getModel(), SdrObjKind::Line);
+ mpLineObjB = new SdrPathObj(getModel(), SdrObjKind::PolyLine);
+ mpLineObjC = new SdrPathObj(getModel(), SdrObjKind::PolyLine);
+
+ Resize();
+ Invalidate();
+}
+
+SvxXLinePreview::~SvxXLinePreview()
+{
+ SdrObject *pFoo = mpLineObjA;
+ SdrObject::Free( pFoo );
+ pFoo = mpLineObjB;
+ SdrObject::Free( pFoo );
+ pFoo = mpLineObjC;
+ SdrObject::Free( pFoo );
+}
+
+void SvxXLinePreview::SetSymbol(Graphic* p,const Size& s)
+{
+ mpGraphic = p;
+ maSymbolSize = s;
+}
+
+void SvxXLinePreview::ResizeSymbol(const Size& s)
+{
+ if ( s != maSymbolSize )
+ {
+ maSymbolSize = s;
+ Invalidate();
+ }
+}
+
+void SvxXLinePreview::SetLineAttributes(const SfxItemSet& rItemSet)
+{
+ // Set ItemSet at objects
+ mpLineObjA->SetMergedItemSet(rItemSet);
+
+ // At line joints, do not use arrows
+ SfxItemSet aTempSet(rItemSet);
+ aTempSet.ClearItem(XATTR_LINESTART);
+ aTempSet.ClearItem(XATTR_LINEEND);
+
+ mpLineObjB->SetMergedItemSet(aTempSet);
+ mpLineObjC->SetMergedItemSet(aTempSet);
+}
+
+void SvxXLinePreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ LocalPrePaint(rRenderContext);
+
+ // paint objects to buffer device
+ sdr::contact::SdrObjectVector aObjectVector;
+ aObjectVector.push_back(mpLineObjA);
+ aObjectVector.push_back(mpLineObjB);
+ aObjectVector.push_back(mpLineObjC);
+
+ sdr::contact::ObjectContactOfObjListPainter aPainter(getBufferDevice(), std::move(aObjectVector), nullptr);
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ // do processing
+ aPainter.ProcessDisplay(aDisplayInfo);
+
+ if ( mbWithSymbol && mpGraphic )
+ {
+ const Size aOutputSize(GetOutputSize());
+ Point aPos( aOutputSize.Width() / 3, aOutputSize.Height() / 2 );
+ aPos.AdjustX( -(maSymbolSize.Width() / 2) );
+ aPos.AdjustY( -(maSymbolSize.Height() / 2) );
+ mpGraphic->Draw(getBufferDevice(), aPos, maSymbolSize);
+ }
+
+ LocalPostPaint(rRenderContext);
+}
+
+SvxXShadowPreview::SvxXShadowPreview()
+ : mpRectangleObject(nullptr)
+ , mpRectangleShadow(nullptr)
+{
+}
+
+void SvxXShadowPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ SvxPreviewBase::SetDrawingArea(pDrawingArea);
+ InitSettings();
+
+ // prepare size
+ Size aSize = GetPreviewSize().GetSize();
+ aSize.setWidth( aSize.Width() / 3 );
+ aSize.setHeight( aSize.Height() / 3 );
+
+ // create RectangleObject
+ const tools::Rectangle aObjectSize( Point( aSize.Width(), aSize.Height() ), aSize );
+ mpRectangleObject = new SdrRectObj(
+ getModel(),
+ aObjectSize);
+
+ // create ShadowObject
+ const tools::Rectangle aShadowSize( Point( aSize.Width(), aSize.Height() ), aSize );
+ mpRectangleShadow = new SdrRectObj(
+ getModel(),
+ aShadowSize);
+}
+
+SvxXShadowPreview::~SvxXShadowPreview()
+{
+ SdrObject::Free(mpRectangleObject);
+ SdrObject::Free(mpRectangleShadow);
+}
+
+void SvxXShadowPreview::SetRectangleAttributes(const SfxItemSet& rItemSet)
+{
+ mpRectangleObject->SetMergedItemSet(rItemSet, true);
+ mpRectangleObject->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+}
+
+void SvxXShadowPreview::SetShadowAttributes(const SfxItemSet& rItemSet)
+{
+ mpRectangleShadow->SetMergedItemSet(rItemSet, true);
+ mpRectangleShadow->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+}
+
+void SvxXShadowPreview::SetShadowPosition(const Point& rPos)
+{
+ maShadowOffset = rPos;
+}
+
+void SvxXShadowPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+ rRenderContext.SetMapMode(MapMode(MapUnit::Map100thMM));
+
+ LocalPrePaint(rRenderContext);
+
+ // prepare size
+ Size aSize = rRenderContext.GetOutputSize();
+ aSize.setWidth( aSize.Width() / 3 );
+ aSize.setHeight( aSize.Height() / 3 );
+
+ tools::Rectangle aObjectRect(Point(aSize.Width(), aSize.Height()), aSize);
+ mpRectangleObject->SetSnapRect(aObjectRect);
+ aObjectRect.Move(maShadowOffset.X(), maShadowOffset.Y());
+ mpRectangleShadow->SetSnapRect(aObjectRect);
+
+ sdr::contact::SdrObjectVector aObjectVector;
+
+ aObjectVector.push_back(mpRectangleShadow);
+ aObjectVector.push_back(mpRectangleObject);
+
+ sdr::contact::ObjectContactOfObjListPainter aPainter(getBufferDevice(), std::move(aObjectVector), nullptr);
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ aPainter.ProcessDisplay(aDisplayInfo);
+
+ LocalPostPaint(rRenderContext);
+
+ rRenderContext.Pop();
+}
+
+void SvxPreviewBase::InitSettings()
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ svtools::ColorConfig aColorConfig;
+ Color aTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
+ getBufferDevice().SetTextColor(aTextColor);
+
+ getBufferDevice().SetBackground(rStyleSettings.GetWindowColor());
+
+ getBufferDevice().SetDrawMode(rStyleSettings.GetHighContrastMode() ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR);
+
+ Invalidate();
+}
+
+SvxPreviewBase::SvxPreviewBase()
+ : mpModel(new SdrModel(nullptr, nullptr, true))
+{
+ // init model
+ mpModel->GetItemPool().FreezeIdRanges();
+}
+
+void SvxPreviewBase::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(getPreviewStripSize(pDrawingArea->get_ref_device()));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+
+ mpBufferDevice = VclPtr<VirtualDevice>::Create(pDrawingArea->get_ref_device());
+ mpBufferDevice->SetMapMode(MapMode(MapUnit::Map100thMM));
+}
+
+SvxPreviewBase::~SvxPreviewBase()
+{
+ mpModel.reset();
+ mpBufferDevice.disposeAndClear();
+}
+
+void SvxPreviewBase::LocalPrePaint(vcl::RenderContext const & rRenderContext)
+{
+ // init BufferDevice
+ if (mpBufferDevice->GetOutputSizePixel() != GetOutputSizePixel())
+ mpBufferDevice->SetOutputSizePixel(GetOutputSizePixel());
+ mpBufferDevice->SetAntialiasing(rRenderContext.GetAntialiasing());
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ if (rStyleSettings.GetPreviewUsesCheckeredBackground())
+ {
+ const Point aNull(0, 0);
+ static const sal_uInt32 nLen(8);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+ const bool bWasEnabled(mpBufferDevice->IsMapModeEnabled());
+
+ mpBufferDevice->EnableMapMode(false);
+ mpBufferDevice->DrawCheckered(aNull, mpBufferDevice->GetOutputSizePixel(), nLen, aW, aG);
+ mpBufferDevice->EnableMapMode(bWasEnabled);
+ }
+ else
+ {
+ mpBufferDevice->Erase();
+ }
+}
+
+void SvxPreviewBase::LocalPostPaint(vcl::RenderContext& rRenderContext)
+{
+ // copy to front (in pixel mode)
+ const bool bWasEnabledSrc(mpBufferDevice->IsMapModeEnabled());
+ const bool bWasEnabledDst(rRenderContext.IsMapModeEnabled());
+ const Point aEmptyPoint;
+
+ mpBufferDevice->EnableMapMode(false);
+ rRenderContext.EnableMapMode(false);
+
+ rRenderContext.DrawOutDev(aEmptyPoint, GetOutputSizePixel(),
+ aEmptyPoint, GetOutputSizePixel(),
+ *mpBufferDevice);
+
+ mpBufferDevice->EnableMapMode(bWasEnabledSrc);
+ rRenderContext.EnableMapMode(bWasEnabledDst);
+}
+
+void SvxPreviewBase::StyleUpdated()
+{
+ InitSettings();
+ CustomWidgetController::StyleUpdated();
+}
+
+SvxXRectPreview::SvxXRectPreview()
+ : mpRectangleObject(nullptr)
+{
+}
+
+tools::Rectangle SvxPreviewBase::GetPreviewSize() const
+{
+ tools::Rectangle aObjectSize(Point(), getBufferDevice().PixelToLogic(GetOutputSizePixel()));
+ return aObjectSize;
+}
+
+void SvxXRectPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ SvxPreviewBase::SetDrawingArea(pDrawingArea);
+ InitSettings();
+
+ // create RectangleObject
+ mpRectangleObject = new SdrRectObj(getModel(), GetPreviewSize());
+}
+
+void SvxXRectPreview::Resize()
+{
+ SdrObject *pOrigObject = mpRectangleObject;
+ if (pOrigObject)
+ {
+ mpRectangleObject = new SdrRectObj(getModel(), GetPreviewSize());
+ SetAttributes(pOrigObject->GetMergedItemSet());
+ SdrObject::Free(pOrigObject);
+ }
+ SvxPreviewBase::Resize();
+}
+
+SvxXRectPreview::~SvxXRectPreview()
+{
+ SdrObject::Free(mpRectangleObject);
+}
+
+void SvxXRectPreview::SetAttributes(const SfxItemSet& rItemSet)
+{
+ mpRectangleObject->SetMergedItemSet(rItemSet, true);
+ mpRectangleObject->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+}
+
+void SvxXRectPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+ rRenderContext.SetMapMode(MapMode(MapUnit::Map100thMM));
+ LocalPrePaint(rRenderContext);
+
+ sdr::contact::SdrObjectVector aObjectVector;
+
+ aObjectVector.push_back(mpRectangleObject);
+
+ sdr::contact::ObjectContactOfObjListPainter aPainter(getBufferDevice(), std::move(aObjectVector), nullptr);
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ aPainter.ProcessDisplay(aDisplayInfo);
+
+ LocalPostPaint(rRenderContext);
+ rRenderContext.Pop();
+}
+
+void limitWidthForSidebar(weld::SpinButton& rSpinButton)
+{
+ // space is limited in the sidebar, so limit MetricSpinButtons to a width of 4 digits
+ const int nMaxDigits = 4;
+ rSpinButton.set_width_chars(std::min(rSpinButton.get_width_chars(), nMaxDigits));
+}
+
+void limitWidthForSidebar(SvxRelativeField& rMetricSpinButton)
+{
+ weld::SpinButton& rSpinButton = rMetricSpinButton.get_widget();
+ limitWidthForSidebar(rSpinButton);
+}
+
+void padWidthForSidebar(weld::Toolbar& rToolbar, const css::uno::Reference<css::frame::XFrame>& rFrame)
+{
+ static int nColumnWidth = -1;
+ static vcl::ImageType eSize;
+ if (nColumnWidth != -1 && eSize != rToolbar.get_icon_size())
+ nColumnWidth = -1;
+ if (nColumnWidth == -1)
+ {
+ // use the, filled-in by dispatcher, width of measurewidth as the width
+ // of a "standard" column in a two column panel
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&rToolbar, "svx/ui/measurewidthbar.ui"));
+ std::unique_ptr<weld::Toolbar> xToolbar1(xBuilder->weld_toolbar("measurewidth1"));
+ ToolbarUnoDispatcher aDispatcher1(*xToolbar1, *xBuilder, rFrame);
+ std::unique_ptr<weld::Toolbar> xToolbar2(xBuilder->weld_toolbar("measurewidth2"));
+ ToolbarUnoDispatcher aDispatcher2(*xToolbar2, *xBuilder, rFrame);
+ nColumnWidth = std::max(xToolbar1->get_preferred_size().Width(), xToolbar2->get_preferred_size().Width());
+ eSize = rToolbar.get_icon_size();
+ }
+ rToolbar.set_size_request(nColumnWidth, -1);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dlgunit.hxx b/svx/source/dialog/dlgunit.hxx
new file mode 100644
index 000000000..bb8ac83d2
--- /dev/null
+++ b/svx/source/dialog/dlgunit.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_DLGUNIT_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_DLGUNIT_HXX
+
+#include <rtl/ustrbuf.hxx>
+#include <svx/svdtrans.hxx>
+#include <vcl/fieldvalues.hxx>
+
+inline OUString GetUnitString(tools::Long nVal_100, FieldUnit eFieldUnit, sal_Unicode cSep)
+{
+ OUStringBuffer aVal
+ = OUString::number(vcl::ConvertValue(nVal_100, 2, MapUnit::Map100thMM, eFieldUnit));
+
+ while (aVal.getLength() < 3)
+ aVal.insert(0, "0");
+
+ aVal.insert(aVal.getLength() - 2, cSep);
+ OUString aSuffix = SdrFormatter::GetUnitStr(eFieldUnit);
+ if (eFieldUnit != FieldUnit::NONE && eFieldUnit != FieldUnit::DEGREE
+ && eFieldUnit != FieldUnit::INCH)
+ aVal.append(" ");
+ if (eFieldUnit == FieldUnit::INCH)
+ {
+ OUString sDoublePrime = u"\u2033";
+ if (aSuffix != "\"" && aSuffix != sDoublePrime)
+ aVal.append(" ");
+ else
+ aSuffix = sDoublePrime;
+ }
+ aVal.append(aSuffix);
+
+ return aVal.makeStringAndClear();
+}
+
+#endif // INCLUDED_SVX_SOURCE_DIALOG_DLGUNIT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dlgutil.cxx b/svx/source/dialog/dlgutil.cxx
new file mode 100644
index 000000000..a33e1ca94
--- /dev/null
+++ b/svx/source/dialog/dlgutil.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dlgutil.hxx>
+#include <svl/itemset.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/module.hxx>
+#include <svl/intitem.hxx>
+#include <svl/eitem.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objsh.hxx>
+#include <sal/log.hxx>
+
+
+FieldUnit GetModuleFieldUnit( const SfxItemSet& rSet )
+{
+ if (const SfxUInt16Item* pItem = rSet.GetItemIfSet(SID_ATTR_METRIC, false))
+ return static_cast<FieldUnit>(pItem->GetValue());
+
+ return SfxModule::GetCurrentFieldUnit();
+}
+
+bool GetApplyCharUnit( const SfxItemSet& rSet )
+{
+ bool bUseCharUnit = false;
+ if ( const SfxBoolItem* pItem = rSet.GetItemIfSet( SID_ATTR_APPLYCHARUNIT, false ) )
+ bUseCharUnit = pItem->GetValue();
+ else
+ {
+ // FIXME - this might be wrong, cf. the DEV300 changes in GetModuleFieldUnit()
+ SfxViewFrame* pFrame = SfxViewFrame::Current();
+ SfxObjectShell* pSh = nullptr;
+ if ( pFrame )
+ pSh = pFrame->GetObjectShell();
+ if ( pSh ) // the object shell is not always available during reload
+ {
+ SfxModule* pModule = pSh->GetModule();
+ if ( pModule )
+ {
+ pItem = pModule->GetItem( SID_ATTR_APPLYCHARUNIT );
+ if ( pItem )
+ bUseCharUnit = pItem->GetValue();
+ }
+ else
+ {
+ SAL_WARN( "svx.dialog", "GetApplyCharUnit(): no module found" );
+ }
+ }
+ }
+ return bUseCharUnit;
+}
+
+FieldUnit GetModuleFieldUnit()
+{
+ return SfxModule::GetCurrentFieldUnit();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/docrecovery.cxx b/svx/source/dialog/docrecovery.cxx
new file mode 100644
index 000000000..181d27b4f
--- /dev/null
+++ b/svx/source/dialog/docrecovery.cxx
@@ -0,0 +1,1104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <bitmaps.hlst>
+#include <docrecovery.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/string.hxx>
+#include <o3tl/safeint.hxx>
+#include <svtools/imagemgr.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/util/URL.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/frame/theAutoRecovery.hpp>
+#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <osl/file.hxx>
+#include <unotools/pathoptions.hxx>
+
+namespace svx::DocRecovery
+{
+
+using namespace ::osl;
+
+RecoveryCore::RecoveryCore(const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ bool bUsedForSaving)
+ : m_xContext ( rxContext )
+ , m_pListener ( nullptr )
+ , m_bListenForSaving(bUsedForSaving)
+{
+ impl_startListening();
+}
+
+
+RecoveryCore::~RecoveryCore()
+{
+ impl_stopListening();
+}
+
+
+const css::uno::Reference< css::uno::XComponentContext >& RecoveryCore::getComponentContext() const
+{
+ return m_xContext;
+}
+
+
+TURLList& RecoveryCore::getURLListAccess()
+{
+ return m_lURLs;
+}
+
+
+bool RecoveryCore::isBrokenTempEntry(const TURLInfo& rInfo)
+{
+ if (rInfo.TempURL.isEmpty())
+ return false;
+
+ // Note: If the original files was recovery ... but a temp file
+ // exists ... an error inside the temp file exists!
+ if (
+ (rInfo.RecoveryState != E_RECOVERY_FAILED ) &&
+ (rInfo.RecoveryState != E_ORIGINAL_DOCUMENT_RECOVERED)
+ )
+ return false;
+
+ return true;
+}
+
+
+void RecoveryCore::saveBrokenTempEntries(const OUString& rPath)
+{
+ if (rPath.isEmpty())
+ return;
+
+ if (!m_xRealCore.is())
+ return;
+
+ // prepare all needed parameters for the following dispatch() request.
+ css::util::URL aCopyURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_BACKUP);
+ css::uno::Sequence< css::beans::PropertyValue > lCopyArgs(3);
+ auto plCopyArgs = lCopyArgs.getArray();
+ plCopyArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plCopyArgs[0].Value <<= false;
+ plCopyArgs[1].Name = PROP_SAVEPATH;
+ plCopyArgs[1].Value <<= rPath;
+ plCopyArgs[2].Name = PROP_ENTRYID;
+ // lCopyArgs[2].Value will be changed during next loop...
+
+ // work on a copied list only...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ if (!RecoveryCore::isBrokenTempEntry(rInfo))
+ continue;
+
+ plCopyArgs[2].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aCopyURL, lCopyArgs);
+ }
+}
+
+
+void RecoveryCore::saveAllTempEntries(const OUString& rPath)
+{
+ if (rPath.isEmpty())
+ return;
+
+ if (!m_xRealCore.is())
+ return;
+
+ // prepare all needed parameters for the following dispatch() request.
+ css::util::URL aCopyURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_BACKUP);
+ css::uno::Sequence< css::beans::PropertyValue > lCopyArgs(3);
+ auto plCopyArgs = lCopyArgs.getArray();
+ plCopyArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plCopyArgs[0].Value <<= false;
+ plCopyArgs[1].Name = PROP_SAVEPATH;
+ plCopyArgs[1].Value <<= rPath;
+ plCopyArgs[2].Name = PROP_ENTRYID;
+ // lCopyArgs[2].Value will be changed during next loop ...
+
+ // work on a copied list only ...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ if (rInfo.TempURL.isEmpty())
+ continue;
+
+ plCopyArgs[2].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aCopyURL, lCopyArgs);
+ }
+}
+
+
+void RecoveryCore::forgetBrokenTempEntries()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
+ css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
+ auto plRemoveArgs = lRemoveArgs.getArray();
+ plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plRemoveArgs[0].Value <<= false;
+ plRemoveArgs[1].Name = PROP_ENTRYID;
+ // lRemoveArgs[1].Value will be changed during next loop ...
+
+ // work on a copied list only ...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ if (!RecoveryCore::isBrokenTempEntry(rInfo))
+ continue;
+
+ plRemoveArgs[1].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
+ }
+}
+
+
+void RecoveryCore::forgetAllRecoveryEntries()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
+ css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
+ auto plRemoveArgs = lRemoveArgs.getArray();
+ plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plRemoveArgs[0].Value <<= false;
+ plRemoveArgs[1].Name = PROP_ENTRYID;
+ // lRemoveArgs[1].Value will be changed during next loop ...
+
+ // work on a copied list only ...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ plRemoveArgs[1].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
+ }
+}
+
+
+void RecoveryCore::forgetBrokenRecoveryEntries()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
+ css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
+ auto plRemoveArgs = lRemoveArgs.getArray();
+ plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plRemoveArgs[0].Value <<= false;
+ plRemoveArgs[1].Name = PROP_ENTRYID;
+ // lRemoveArgs[1].Value will be changed during next loop ...
+
+ // work on a copied list only ...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ if (!RecoveryCore::isBrokenTempEntry(rInfo))
+ continue;
+
+ plRemoveArgs[1].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
+ }
+}
+
+
+void RecoveryCore::setProgressHandler(const css::uno::Reference< css::task::XStatusIndicator >& xProgress)
+{
+ m_xProgress = xProgress;
+}
+
+
+void RecoveryCore::setUpdateListener(IRecoveryUpdateListener* pListener)
+{
+ m_pListener = pListener;
+}
+
+
+void RecoveryCore::doEmergencySavePrepare()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aURL = impl_getParsedURL(RECOVERY_CMD_DO_PREPARE_EMERGENCY_SAVE);
+
+ css::uno::Sequence< css::beans::PropertyValue > lArgs{ comphelper::makePropertyValue(
+ PROP_DISPATCHASYNCHRON, false) };
+
+ m_xRealCore->dispatch(aURL, lArgs);
+}
+
+
+void RecoveryCore::doEmergencySave()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aURL = impl_getParsedURL(RECOVERY_CMD_DO_EMERGENCY_SAVE);
+
+ css::uno::Sequence< css::beans::PropertyValue > lArgs{
+ comphelper::makePropertyValue(PROP_STATUSINDICATOR, m_xProgress),
+ comphelper::makePropertyValue(PROP_DISPATCHASYNCHRON, true)
+ };
+
+ m_xRealCore->dispatch(aURL, lArgs);
+}
+
+
+void RecoveryCore::doRecovery()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aURL = impl_getParsedURL(RECOVERY_CMD_DO_RECOVERY);
+
+ css::uno::Sequence< css::beans::PropertyValue > lArgs{
+ comphelper::makePropertyValue(PROP_STATUSINDICATOR, m_xProgress),
+ comphelper::makePropertyValue(PROP_DISPATCHASYNCHRON, true)
+ };
+
+ m_xRealCore->dispatch(aURL, lArgs);
+}
+
+
+ERecoveryState RecoveryCore::mapDocState2RecoverState(EDocStates eDocState)
+{
+ // ???
+ ERecoveryState eRecState = E_NOT_RECOVERED_YET;
+
+ /* Attention:
+ Some of the following states can occur at the
+ same time. So we have to check for the "worst case" first!
+
+ DAMAGED -> INCOMPLETE -> HANDLED
+ */
+
+ // running ...
+ if (
+ (eDocState & EDocStates::TryLoadBackup ) ||
+ (eDocState & EDocStates::TryLoadOriginal)
+ )
+ eRecState = E_RECOVERY_IS_IN_PROGRESS;
+ // red
+ else if (eDocState & EDocStates::Damaged)
+ eRecState = E_RECOVERY_FAILED;
+ // yellow
+ else if (eDocState & EDocStates::Incomplete)
+ eRecState = E_ORIGINAL_DOCUMENT_RECOVERED;
+ // green
+ else if (eDocState & EDocStates::Succeeded)
+ eRecState = E_SUCCESSFULLY_RECOVERED;
+
+ return eRecState;
+}
+
+
+void SAL_CALL RecoveryCore::statusChanged(const css::frame::FeatureStateEvent& aEvent)
+{
+ // a) special notification about start/stop async dispatch!
+ // FeatureDescriptor = "start" || "stop"
+ if (aEvent.FeatureDescriptor == RECOVERY_OPERATIONSTATE_START)
+ {
+ return;
+ }
+
+ if (aEvent.FeatureDescriptor == RECOVERY_OPERATIONSTATE_STOP)
+ {
+ if (m_pListener)
+ m_pListener->end();
+ return;
+ }
+
+ // b) normal notification about changed items
+ // FeatureDescriptor = "Update"
+ // State = List of information [seq< NamedValue >]
+ if (aEvent.FeatureDescriptor != RECOVERY_OPERATIONSTATE_UPDATE)
+ return;
+
+ ::comphelper::SequenceAsHashMap lInfo(aEvent.State);
+ TURLInfo aNew;
+
+ aNew.ID = lInfo.getUnpackedValueOrDefault(STATEPROP_ID , sal_Int32(0) );
+ aNew.DocState = static_cast<EDocStates>(lInfo.getUnpackedValueOrDefault(STATEPROP_STATE , sal_Int32(0) ));
+ aNew.OrgURL = lInfo.getUnpackedValueOrDefault(STATEPROP_ORGURL , OUString());
+ aNew.TempURL = lInfo.getUnpackedValueOrDefault(STATEPROP_TEMPURL , OUString());
+ aNew.FactoryURL = lInfo.getUnpackedValueOrDefault(STATEPROP_FACTORYURL , OUString());
+ aNew.TemplateURL = lInfo.getUnpackedValueOrDefault(STATEPROP_TEMPLATEURL, OUString());
+ aNew.DisplayName = lInfo.getUnpackedValueOrDefault(STATEPROP_TITLE , OUString());
+ aNew.Module = lInfo.getUnpackedValueOrDefault(STATEPROP_MODULE , OUString());
+
+ if (aNew.OrgURL.isEmpty()) {
+ // If there is no file URL, the window title is used for the display name.
+ // Remove any unwanted elements such as " - LibreOffice Writer".
+ sal_Int32 i = aNew.DisplayName.indexOf(" - ");
+ if (i > 0)
+ aNew.DisplayName = aNew.DisplayName.copy(0, i);
+ } else {
+ // If there is a file URL, parse out the filename part as the display name.
+ INetURLObject aOrgURL(aNew.OrgURL);
+ aNew.DisplayName = aOrgURL.getName(INetURLObject::LAST_SEGMENT, true,
+ INetURLObject::DecodeMechanism::WithCharset);
+ }
+
+ // search for already existing items and update her nState value ...
+ for (TURLInfo& aOld : m_lURLs)
+ {
+ if (aOld.ID == aNew.ID)
+ {
+ // change existing
+ aOld.DocState = aNew.DocState;
+ aOld.RecoveryState = RecoveryCore::mapDocState2RecoverState(aOld.DocState);
+ if (m_pListener)
+ {
+ m_pListener->updateItems();
+ m_pListener->stepNext(&aOld);
+ }
+ return;
+ }
+ }
+
+ // append as new one
+ // TODO think about matching Module name to a corresponding icon
+ OUString sURL = aNew.OrgURL;
+ if (sURL.isEmpty())
+ sURL = aNew.FactoryURL;
+ if (sURL.isEmpty())
+ sURL = aNew.TempURL;
+ if (sURL.isEmpty())
+ sURL = aNew.TemplateURL;
+ INetURLObject aURL(sURL);
+ aNew.StandardImageId = SvFileInformationManager::GetFileImageId(aURL);
+
+ /* set the right UI state for this item to NOT_RECOVERED_YET... because nDocState shows the state of
+ the last emergency save operation before and is interesting for the used recovery core service only...
+ for now! But if there is a further notification for this item (see lines above!) we must
+ map the doc state to an UI state. */
+ aNew.RecoveryState = E_NOT_RECOVERED_YET;
+
+ m_lURLs.push_back(aNew);
+
+ if (m_pListener)
+ m_pListener->updateItems();
+}
+
+
+void SAL_CALL RecoveryCore::disposing(const css::lang::EventObject& /*aEvent*/)
+{
+ m_xRealCore.clear();
+}
+
+
+void RecoveryCore::impl_startListening()
+{
+ // listening already initialized ?
+ if (m_xRealCore.is())
+ return;
+ m_xRealCore = css::frame::theAutoRecovery::get(m_xContext);
+
+ css::util::URL aURL;
+ if (m_bListenForSaving)
+ aURL.Complete = RECOVERY_CMD_DO_EMERGENCY_SAVE;
+ else
+ aURL.Complete = RECOVERY_CMD_DO_RECOVERY;
+ css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
+ xParser->parseStrict(aURL);
+
+ /* Note: addStatusListener() call us synchronous back ... so we
+ will get the complete list of currently open documents! */
+ m_xRealCore->addStatusListener(static_cast< css::frame::XStatusListener* >(this), aURL);
+}
+
+
+void RecoveryCore::impl_stopListening()
+{
+ // Ignore it, if this instance doesn't listen currently
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aURL;
+ if (m_bListenForSaving)
+ aURL.Complete = RECOVERY_CMD_DO_EMERGENCY_SAVE;
+ else
+ aURL.Complete = RECOVERY_CMD_DO_RECOVERY;
+ css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
+ xParser->parseStrict(aURL);
+
+ m_xRealCore->removeStatusListener(static_cast< css::frame::XStatusListener* >(this), aURL);
+ m_xRealCore.clear();
+}
+
+
+css::util::URL RecoveryCore::impl_getParsedURL(const OUString& sURL)
+{
+ css::util::URL aURL;
+ aURL.Complete = sURL;
+
+ css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
+ xParser->parseStrict(aURL);
+
+ return aURL;
+}
+
+PluginProgress::PluginProgress(weld::ProgressBar* pProgressBar)
+ : m_pProgressBar(pProgressBar)
+ , m_nRange(100)
+{
+}
+
+PluginProgress::~PluginProgress()
+{
+}
+
+void SAL_CALL PluginProgress::dispose()
+{
+ m_pProgressBar = nullptr;
+}
+
+void SAL_CALL PluginProgress::addEventListener(const css::uno::Reference< css::lang::XEventListener >& )
+{
+}
+
+void SAL_CALL PluginProgress::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& )
+{
+}
+
+void SAL_CALL PluginProgress::start(const OUString&, sal_Int32 nRange)
+{
+ m_nRange = nRange;
+ if (m_pProgressBar)
+ m_pProgressBar->set_percentage(0);
+}
+
+void SAL_CALL PluginProgress::end()
+{
+ if (m_pProgressBar)
+ m_pProgressBar->set_percentage(m_nRange);
+}
+
+void SAL_CALL PluginProgress::setText(const OUString& rText)
+{
+ if (m_pProgressBar)
+ m_pProgressBar->set_text(rText);
+}
+
+void SAL_CALL PluginProgress::setValue(sal_Int32 nValue)
+{
+ if (m_pProgressBar)
+ m_pProgressBar->set_percentage((nValue * 100) / m_nRange);
+}
+
+void SAL_CALL PluginProgress::reset()
+{
+ if (m_pProgressBar)
+ m_pProgressBar->set_percentage(0);
+}
+
+SaveDialog::SaveDialog(weld::Window* pParent, RecoveryCore* pCore)
+ : GenericDialogController(pParent, "svx/ui/docrecoverysavedialog.ui", "DocRecoverySaveDialog")
+ , m_pCore(pCore)
+ , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
+ , m_xOkBtn(m_xBuilder->weld_button("ok"))
+{
+ m_xFileListLB->set_size_request(-1, m_xFileListLB->get_height_rows(10));
+
+ // Prepare the office for the following crash save step.
+ // E.g. hide all open windows so the user can't influence our
+ // operation .-)
+ m_pCore->doEmergencySavePrepare();
+
+ m_xOkBtn->connect_clicked(LINK(this, SaveDialog, OKButtonHdl));
+
+ // fill listbox with current open documents
+
+ TURLList& rURLs = m_pCore->getURLListAccess();
+
+ for (const TURLInfo& rInfo : rURLs)
+ {
+ m_xFileListLB->append("", rInfo.DisplayName, rInfo.StandardImageId);
+ }
+}
+
+SaveDialog::~SaveDialog()
+{
+}
+
+IMPL_LINK_NOARG(SaveDialog, OKButtonHdl, weld::Button&, void)
+{
+ // start crash-save with progress
+ std::unique_ptr<SaveProgressDialog> xProgress(new SaveProgressDialog(m_xDialog.get(), m_pCore));
+ short nResult = xProgress->run();
+ xProgress.reset();
+
+ // if "CANCEL" => return "CANCEL"
+ // if "OK" => "AUTOLUNCH" always !
+ if (nResult == DLG_RET_OK)
+ nResult = DLG_RET_OK_AUTOLUNCH;
+
+ m_xDialog->response(nResult);
+}
+
+SaveProgressDialog::SaveProgressDialog(weld::Window* pParent, RecoveryCore* pCore)
+ : GenericDialogController(pParent, "svx/ui/docrecoveryprogressdialog.ui", "DocRecoveryProgressDialog")
+ , m_pCore(pCore)
+ , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
+{
+ m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
+ m_xProgress = new PluginProgress(m_xProgressBar.get());
+}
+
+SaveProgressDialog::~SaveProgressDialog()
+{
+ css::uno::Reference<css::lang::XComponent> xComp(m_xProgress, css::uno::UNO_QUERY);
+ if (xComp)
+ xComp->dispose();
+}
+
+short SaveProgressDialog::run()
+{
+ ::SolarMutexGuard aLock;
+
+ m_pCore->setProgressHandler(m_xProgress);
+ m_pCore->setUpdateListener(this);
+ m_pCore->doEmergencySave();
+ short nRet = DialogController::run();
+ m_pCore->setUpdateListener(nullptr);
+ return nRet;
+}
+
+void SaveProgressDialog::updateItems()
+{
+}
+
+void SaveProgressDialog::stepNext(TURLInfo* )
+{
+ /* TODO
+
+ if m_pCore would have a member m_mCurrentItem, you could see,
+ who is current, who is next ... You can show this information
+ in progress report FixText
+ */
+}
+
+void SaveProgressDialog::end()
+{
+ m_xDialog->response(DLG_RET_OK);
+}
+
+static short impl_askUserForWizardCancel(weld::Widget* pParent, TranslateId pRes)
+{
+ std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(pParent,
+ VclMessageType::Question, VclButtonsType::YesNo, SvxResId(pRes)));
+ if (xQuery->run() == RET_YES)
+ return DLG_RET_OK;
+ else
+ return DLG_RET_CANCEL;
+}
+
+RecoveryDialog::RecoveryDialog(weld::Window* pParent, RecoveryCore* pCore)
+ : GenericDialogController(pParent, "svx/ui/docrecoveryrecoverdialog.ui", "DocRecoveryRecoverDialog")
+ , m_aTitleRecoveryInProgress(SvxResId(RID_SVXSTR_RECOVERY_INPROGRESS))
+ , m_aRecoveryOnlyFinish (SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH))
+ , m_aRecoveryOnlyFinishDescr(SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH_DESCR))
+ , m_pCore(pCore)
+ , m_eRecoveryState(RecoveryDialog::E_RECOVERY_PREPARED)
+ , m_bWaitForCore(false)
+ , m_bWasRecoveryStarted(false)
+ , m_aSuccessRecovStr(SvxResId(RID_SVXSTR_SUCCESSRECOV))
+ , m_aOrigDocRecovStr(SvxResId(RID_SVXSTR_ORIGDOCRECOV))
+ , m_aRecovFailedStr(SvxResId(RID_SVXSTR_RECOVFAILED))
+ , m_aRecovInProgrStr(SvxResId(RID_SVXSTR_RECOVINPROGR))
+ , m_aNotRecovYetStr(SvxResId(RID_SVXSTR_NOTRECOVYET))
+ , m_xDescrFT(m_xBuilder->weld_label("desc"))
+ , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
+ , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
+ , m_xNextBtn(m_xBuilder->weld_button("next"))
+ , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
+{
+ const auto nWidth = m_xFileListLB->get_approximate_digit_width() * 70;
+ m_xFileListLB->set_size_request(nWidth, m_xFileListLB->get_height_rows(10));
+ m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
+ m_xProgress = new PluginProgress(m_xProgressBar.get());
+
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(m_xFileListLB->get_checkbox_column_width()),
+ o3tl::narrowing<int>(60 * nWidth / 100),
+ o3tl::narrowing<int>(m_xFileListLB->get_checkbox_column_width())
+ };
+ m_xFileListLB->set_column_fixed_widths(aWidths);
+
+ m_xNextBtn->set_sensitive(true);
+ m_xNextBtn->connect_clicked( LINK( this, RecoveryDialog, NextButtonHdl ) );
+ m_xCancelBtn->connect_clicked( LINK( this, RecoveryDialog, CancelButtonHdl ) );
+
+ // fill list box first time
+ TURLList& rURLList = m_pCore->getURLListAccess();
+ for (size_t i = 0, nCount = rURLList.size(); i < nCount; ++i)
+ {
+ const TURLInfo& rInfo = rURLList[i];
+ m_xFileListLB->append();
+ m_xFileListLB->set_id(i, weld::toId(&rInfo));
+ m_xFileListLB->set_image(i, rInfo.StandardImageId, 0);
+ m_xFileListLB->set_text(i, rInfo.DisplayName, 1);
+ m_xFileListLB->set_image(i, impl_getStatusImage(rInfo), 2);
+ m_xFileListLB->set_text(i, impl_getStatusString(rInfo), 3);
+ }
+
+ // mark first item
+ if (m_xFileListLB->n_children())
+ m_xFileListLB->set_cursor(0);
+}
+
+RecoveryDialog::~RecoveryDialog()
+{
+ css::uno::Reference<css::lang::XComponent> xComp(m_xProgress, css::uno::UNO_QUERY);
+ if (xComp)
+ xComp->dispose();
+}
+
+short RecoveryDialog::execute()
+{
+ ::SolarMutexGuard aSolarLock;
+
+ switch (m_eRecoveryState)
+ {
+ case RecoveryDialog::E_RECOVERY_IN_PROGRESS :
+ {
+ // user decided to start recovery ...
+ m_bWasRecoveryStarted = true;
+ // do it asynchronous (to allow repaints)
+ // and wait for this asynchronous operation.
+ m_xDescrFT->set_label( m_aTitleRecoveryInProgress );
+ m_xNextBtn->set_sensitive(false);
+ m_xCancelBtn->set_sensitive(false);
+ m_pCore->setProgressHandler(m_xProgress);
+ m_pCore->setUpdateListener(this);
+ m_pCore->doRecovery();
+
+ m_bWaitForCore = true;
+ while(m_bWaitForCore && !Application::IsQuit())
+ Application::Yield();
+
+ m_pCore->setUpdateListener(nullptr);
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_CORE_DONE;
+ return execute();
+ }
+
+ case RecoveryDialog::E_RECOVERY_CORE_DONE :
+ {
+ // the core finished it's task.
+ // let the user decide the next step.
+ m_xDescrFT->set_label(m_aRecoveryOnlyFinishDescr);
+ m_xNextBtn->set_label(m_aRecoveryOnlyFinish);
+ m_xNextBtn->set_sensitive(true);
+ m_xCancelBtn->set_sensitive(false);
+ return 0;
+ }
+
+ case RecoveryDialog::E_RECOVERY_DONE :
+ {
+ // All documents were recovered.
+ // User decided to step to the "next" wizard page.
+ // Do it ... but check first, if there exist some
+ // failed recovery documents. They must be saved to
+ // a user selected directory.
+ short nRet = DLG_RET_UNKNOWN;
+ BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
+ OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default dir
+ if (aBrokenRecoveryDialog.isExecutionNeeded())
+ {
+ nRet = aBrokenRecoveryDialog.run();
+ sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
+ }
+
+ switch(nRet)
+ {
+ // no broken temp files exists
+ // step to the next wizard page
+ case DLG_RET_UNKNOWN :
+ {
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
+ return DLG_RET_OK;
+ }
+
+ // user decided to save the broken temp files
+ // do and forget it
+ // step to the next wizard page
+ case DLG_RET_OK :
+ {
+ m_pCore->saveBrokenTempEntries(sSaveDir);
+ m_pCore->forgetBrokenTempEntries();
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
+ return DLG_RET_OK;
+ }
+
+ // user decided to ignore broken temp files.
+ // Ask it again ... may be this decision was wrong.
+ // Results:
+ // IGNORE => remove broken temp files
+ // => step to the next wizard page
+ // CANCEL => step back to the recovery page
+ case DLG_RET_CANCEL :
+ {
+ // TODO ask user ...
+ m_pCore->forgetBrokenTempEntries();
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
+ return DLG_RET_OK;
+ }
+ }
+
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
+ return DLG_RET_OK;
+ }
+
+ case RecoveryDialog::E_RECOVERY_CANCELED :
+ {
+ // "YES" => break recovery
+ // But there exist different states, where "cancel" can be called.
+ // Handle it different.
+ if (m_bWasRecoveryStarted)
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED_AFTERWARDS;
+ else
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED_BEFORE;
+ return execute();
+ }
+
+ case RecoveryDialog::E_RECOVERY_CANCELED_BEFORE :
+ case RecoveryDialog::E_RECOVERY_CANCELED_AFTERWARDS :
+ {
+ // We have to check if there exists some temp. files.
+ // They should be saved to a user defined location.
+ // If no temp files exists or user decided to ignore it ...
+ // we have to remove all recovery/session data anyway!
+ short nRet = DLG_RET_UNKNOWN;
+ BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
+ OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default save location
+
+ // dialog itself checks if there is a need to copy files for this mode.
+ // It uses the information m_bWasRecoveryStarted doing so.
+ if (aBrokenRecoveryDialog.isExecutionNeeded())
+ {
+ nRet = aBrokenRecoveryDialog.run();
+ sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
+ }
+
+ // Possible states:
+ // a) nRet == DLG_RET_UNKNOWN
+ // dialog was not shown ...
+ // because there exists no temp file for copy.
+ // => remove all recovery data
+ // b) nRet == DLG_RET_OK
+ // dialog was shown ...
+ // user decided to save temp files
+ // => save all OR broken temp files (depends from the time, where cancel was called)
+ // => remove all recovery data
+ // c) nRet == DLG_RET_CANCEL
+ // dialog was shown ...
+ // user decided to ignore temp files
+ // => remove all recovery data
+ // => a)/c) are the same ... b) has one additional operation
+
+ // b)
+ if (nRet == DLG_RET_OK)
+ {
+ if (m_bWasRecoveryStarted)
+ m_pCore->saveBrokenTempEntries(sSaveDir);
+ else
+ m_pCore->saveAllTempEntries(sSaveDir);
+ }
+
+ // a,b,c)
+ if (m_bWasRecoveryStarted)
+ m_pCore->forgetBrokenRecoveryEntries();
+ else
+ m_pCore->forgetAllRecoveryEntries();
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
+
+ // THERE IS NO WAY BACK. see impl_askUserForWizardCancel()!
+ return DLG_RET_CANCEL;
+ }
+ }
+
+ // should never be reached .-)
+ OSL_FAIL("Should never be reached!");
+ return DLG_RET_OK;
+}
+
+void RecoveryDialog::updateItems()
+{
+ int c = m_xFileListLB->n_children();
+ for (int i = 0; i < c; ++i)
+ {
+ TURLInfo* pInfo = weld::fromId<TURLInfo*>(m_xFileListLB->get_id(i));
+ if ( !pInfo )
+ continue;
+
+ m_xFileListLB->set_image(i, impl_getStatusImage(*pInfo), 2);
+ OUString sStatus = impl_getStatusString( *pInfo );
+ if (!sStatus.isEmpty())
+ m_xFileListLB->set_text(i, sStatus, 3);
+ }
+}
+
+void RecoveryDialog::stepNext(TURLInfo* pItem)
+{
+ int c = m_xFileListLB->n_children();
+ for (int i=0; i < c; ++i)
+ {
+ TURLInfo* pInfo = weld::fromId<TURLInfo*>(m_xFileListLB->get_id(i));
+ if (pInfo->ID != pItem->ID)
+ continue;
+
+ m_xFileListLB->set_cursor(i);
+ m_xFileListLB->scroll_to_row(i);
+ break;
+ }
+}
+
+void RecoveryDialog::end()
+{
+ m_bWaitForCore = false;
+}
+
+IMPL_LINK_NOARG(RecoveryDialog, NextButtonHdl, weld::Button&, void)
+{
+ switch (m_eRecoveryState)
+ {
+ case RecoveryDialog::E_RECOVERY_PREPARED:
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_IN_PROGRESS;
+ execute();
+ break;
+ case RecoveryDialog::E_RECOVERY_CORE_DONE:
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_DONE;
+ execute();
+ break;
+ }
+
+ if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
+ {
+ m_xDialog->response(DLG_RET_OK);
+ }
+}
+
+IMPL_LINK_NOARG(RecoveryDialog, CancelButtonHdl, weld::Button&, void)
+{
+ switch (m_eRecoveryState)
+ {
+ case RecoveryDialog::E_RECOVERY_PREPARED:
+ if (impl_askUserForWizardCancel(m_xDialog.get(), RID_SVXSTR_QUERY_EXIT_RECOVERY) != DLG_RET_CANCEL)
+ {
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
+ execute();
+ }
+ break;
+ case RecoveryDialog::E_RECOVERY_CORE_DONE:
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
+ execute();
+ break;
+ }
+
+ if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
+ {
+ m_xDialog->response(RET_CANCEL);
+ }
+}
+
+OUString RecoveryDialog::impl_getStatusString( const TURLInfo& rInfo ) const
+{
+ OUString sStatus;
+ switch ( rInfo.RecoveryState )
+ {
+ case E_SUCCESSFULLY_RECOVERED :
+ sStatus = m_aSuccessRecovStr;
+ break;
+ case E_ORIGINAL_DOCUMENT_RECOVERED :
+ sStatus = m_aOrigDocRecovStr;
+ break;
+ case E_RECOVERY_FAILED :
+ sStatus = m_aRecovFailedStr;
+ break;
+ case E_RECOVERY_IS_IN_PROGRESS :
+ sStatus = m_aRecovInProgrStr;
+ break;
+ case E_NOT_RECOVERED_YET :
+ sStatus = m_aNotRecovYetStr;
+ break;
+ default:
+ break;
+ }
+ return sStatus;
+}
+
+OUString RecoveryDialog::impl_getStatusImage( const TURLInfo& rInfo )
+{
+ OUString sStatus;
+ switch ( rInfo.RecoveryState )
+ {
+ case E_SUCCESSFULLY_RECOVERED :
+ sStatus = RID_SVXBMP_GREENCHECK;
+ break;
+ case E_ORIGINAL_DOCUMENT_RECOVERED :
+ sStatus = RID_SVXBMP_YELLOWCHECK;
+ break;
+ case E_RECOVERY_FAILED :
+ sStatus = RID_SVXBMP_REDCROSS;
+ break;
+ default:
+ break;
+ }
+ return sStatus;
+}
+
+BrokenRecoveryDialog::BrokenRecoveryDialog(weld::Window* pParent,
+ RecoveryCore* pCore,
+ bool bBeforeRecovery)
+ : GenericDialogController(pParent, "svx/ui/docrecoverybrokendialog.ui", "DocRecoveryBrokenDialog")
+ , m_pCore(pCore)
+ , m_bBeforeRecovery(bBeforeRecovery)
+ , m_bExecutionNeeded(false)
+ , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
+ , m_xSaveDirED(m_xBuilder->weld_entry("savedir"))
+ , m_xSaveDirBtn(m_xBuilder->weld_button("change"))
+ , m_xOkBtn(m_xBuilder->weld_button("ok"))
+ , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
+{
+ m_xSaveDirBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, SaveButtonHdl ) );
+ m_xOkBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, OkButtonHdl ) );
+ m_xCancelBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, CancelButtonHdl ) );
+
+ m_sSavePath = SvtPathOptions().GetWorkPath();
+ INetURLObject aObj( m_sSavePath );
+ OUString sPath;
+ osl::FileBase::getSystemPathFromFileURL(aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), sPath);
+ m_xSaveDirED->set_text(sPath);
+
+ impl_refresh();
+}
+
+BrokenRecoveryDialog::~BrokenRecoveryDialog()
+{
+}
+
+void BrokenRecoveryDialog::impl_refresh()
+{
+ m_bExecutionNeeded = false;
+ TURLList& rURLList = m_pCore->getURLListAccess();
+ for (const TURLInfo& rInfo : rURLList)
+ {
+ if (m_bBeforeRecovery)
+ {
+ // "Cancel" before recovery ->
+ // search for any temp files!
+ if (rInfo.TempURL.isEmpty())
+ continue;
+ }
+ else
+ {
+ // "Cancel" after recovery ->
+ // search for broken temp files
+ if (!RecoveryCore::isBrokenTempEntry(rInfo))
+ continue;
+ }
+
+ m_bExecutionNeeded = true;
+
+ m_xFileListLB->append(weld::toId(&rInfo), rInfo.DisplayName, rInfo.StandardImageId);
+ }
+ m_sSavePath.clear();
+ m_xOkBtn->grab_focus();
+}
+
+bool BrokenRecoveryDialog::isExecutionNeeded() const
+{
+ return m_bExecutionNeeded;
+}
+
+const OUString& BrokenRecoveryDialog::getSaveDirURL() const
+{
+ return m_sSavePath;
+}
+
+IMPL_LINK_NOARG(BrokenRecoveryDialog, OkButtonHdl, weld::Button&, void)
+{
+ OUString sPhysicalPath = comphelper::string::strip(m_xSaveDirED->get_text(), ' ');
+ OUString sURL;
+ osl::FileBase::getFileURLFromSystemPath( sPhysicalPath, sURL );
+ m_sSavePath = sURL;
+ while (m_sSavePath.isEmpty())
+ impl_askForSavePath();
+
+ m_xDialog->response(DLG_RET_OK);
+}
+
+IMPL_LINK_NOARG(BrokenRecoveryDialog, CancelButtonHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_CANCEL);
+}
+
+IMPL_LINK_NOARG(BrokenRecoveryDialog, SaveButtonHdl, weld::Button&, void)
+{
+ impl_askForSavePath();
+}
+
+void BrokenRecoveryDialog::impl_askForSavePath()
+{
+ css::uno::Reference< css::ui::dialogs::XFolderPicker2 > xFolderPicker =
+ sfx2::createFolderPicker(m_pCore->getComponentContext(), m_xDialog.get());
+
+ INetURLObject aURL(m_sSavePath, INetProtocol::File);
+ xFolderPicker->setDisplayDirectory(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
+ short nRet = xFolderPicker->execute();
+ if (nRet == css::ui::dialogs::ExecutableDialogResults::OK)
+ {
+ m_sSavePath = xFolderPicker->getDirectory();
+ OUString sPath;
+ osl::FileBase::getSystemPathFromFileURL(m_sSavePath, sPath);
+ m_xSaveDirED->set_text(sPath);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/fntctrl.cxx b/svx/source/dialog/fntctrl.cxx
new file mode 100644
index 000000000..393fc4e68
--- /dev/null
+++ b/svx/source/dialog/fntctrl.cxx
@@ -0,0 +1,1089 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/dialoghelper.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/printer.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <unicode/uchar.h>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/i18n/BreakIterator.hpp>
+#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/i18n/ScriptType.hpp>
+
+#include <vector>
+#include <deque>
+#include <optional>
+#include <svtools/colorcfg.hxx>
+#include <svtools/sampletext.hxx>
+
+#include <svx/fntctrl.hxx>
+#include <svx/svxids.hrc>
+
+// Item set includes
+#include <svl/itemset.hxx>
+#include <svl/itempool.hxx>
+#include <svl/stritem.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+
+#include <editeng/colritem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/cmapitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <editeng/langitem.hxx>
+
+//TODO: remove this and calculate off the actual size of text, not
+//an arbitrary number of characters
+#define TEXT_WIDTH 80
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using ::com::sun::star::i18n::XBreakIterator;
+using ::com::sun::star::i18n::BreakIterator;
+
+
+// small helper functions to set fonts
+
+namespace
+{
+void scaleFontWidth(vcl::Font& rFont, vcl::RenderContext const & rRenderContext,tools::Long& n100PercentFont)
+{
+ rFont.SetAverageFontWidth(0);
+ n100PercentFont = rRenderContext.GetFontMetric(rFont).GetAverageFontWidth();
+}
+
+void initFont(vcl::Font& rFont)
+{
+ rFont.SetTransparent(true);
+ rFont.SetAlignment(ALIGN_BASELINE);
+}
+
+void setFontSize(vcl::Font& rFont)
+{
+ Size aSize(rFont.GetFontSize());
+ aSize.setHeight( (aSize.Height() * 3) / 5 );
+ aSize.setWidth( (aSize.Width() * 3) / 5 );
+ rFont.SetFontSize(aSize);
+}
+
+void calcFontHeightAnyAscent(vcl::RenderContext& rRenderContext, const vcl::Font& rFont, tools::Long& nHeight, tools::Long& nAscent)
+{
+ if (!nHeight)
+ {
+ rRenderContext.SetFont(rFont);
+ FontMetric aMetric(rRenderContext.GetFontMetric());
+ nHeight = aMetric.GetLineHeight();
+ nAscent = aMetric.GetAscent();
+ }
+}
+
+void setFont(const SvxFont& rNewFont, SvxFont& rImplFont)
+{
+ rImplFont = rNewFont;
+ rImplFont.SetTransparent(true);
+ rImplFont.SetAlignment(ALIGN_BASELINE);
+}
+
+/*
+ * removes line feeds and carriage returns from string
+ * returns if param is empty
+ */
+OUString removeCRLF(const OUString& rText)
+{
+ return rText.replace(0xa, ' ').replace(0xd, ' ').trim();
+}
+
+} // end anonymous namespace
+
+class FontPrevWin_Impl
+{
+ friend class SvxFontPrevWindow;
+
+ SvxFont maFont;
+ VclPtr<Printer> mpPrinter;
+ bool mbDelPrinter;
+
+ Reference <XBreakIterator> mxBreak;
+ std::vector<tools::Long> maTextWidth;
+ std::deque<sal_Int32> maScriptChg;
+ std::vector<sal_uInt16> maScriptType;
+ SvxFont maCJKFont;
+ SvxFont maCTLFont;
+ OUString maText;
+ OUString maScriptText;
+ std::optional<Color> mxColor;
+ std::optional<Color> mxBackColor;
+ std::optional<Color> mxTextLineColor;
+ std::optional<Color> mxOverlineColor;
+ tools::Long mnAscent;
+ sal_Unicode mcStartBracket;
+ sal_Unicode mcEndBracket;
+
+ tools::Long mn100PercentFontWidth; // initial -1 -> not set yet
+ tools::Long mn100PercentFontWidthCJK;
+ tools::Long mn100PercentFontWidthCTL;
+ sal_uInt16 mnFontWidthScale;
+
+ bool mbSelection : 1;
+ bool mbGetSelection : 1;
+ bool mbTwoLines : 1;
+ bool mbUseFontNameAsText : 1;
+ bool mbTextInited : 1;
+
+ bool m_bCJKEnabled;
+ bool m_bCTLEnabled;
+
+
+public:
+ FontPrevWin_Impl() :
+ mpPrinter(nullptr),
+ mbDelPrinter(false),
+ mnAscent(0),
+ mcStartBracket(0),
+ mcEndBracket(0),
+ mnFontWidthScale(100),
+ mbSelection(false),
+ mbGetSelection(false),
+ mbTwoLines(false),
+ mbUseFontNameAsText(false),
+ mbTextInited(false)
+ {
+ m_bCJKEnabled = SvtCJKOptions::IsAnyEnabled();
+ m_bCTLEnabled = SvtCTLOptions().IsCTLFontEnabled();
+ mxBackColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ Invalidate100PercentFontWidth();
+ }
+
+ ~FontPrevWin_Impl()
+ {
+ if (mbDelPrinter)
+ mpPrinter.disposeAndClear();
+ }
+
+ void CheckScript();
+ Size CalcTextSize(vcl::RenderContext& rRenderContext, OutputDevice const * pPrinter, const SvxFont& rFont);
+ void DrawPrev(vcl::RenderContext& rRenderContext, Printer* pPrinter, Point& rPt, const SvxFont& rFont);
+
+ bool SetFontWidthScale(sal_uInt16 nScaleInPercent);
+ inline void Invalidate100PercentFontWidth();
+ inline bool Is100PercentFontWidthValid() const;
+ void ScaleFontWidth(vcl::RenderContext const & rRenderContext);
+ // scales rNonCJKFont and aCJKFont depending on nFontWidthScale and
+ // sets the 100%-Font-Widths
+};
+
+inline void FontPrevWin_Impl::Invalidate100PercentFontWidth()
+{
+ mn100PercentFontWidth = mn100PercentFontWidthCJK = mn100PercentFontWidthCTL = -1;
+}
+
+inline bool FontPrevWin_Impl::Is100PercentFontWidthValid() const
+{
+ DBG_ASSERT( ( mn100PercentFontWidth == -1 && mn100PercentFontWidthCJK == -1 ) ||
+ ( mn100PercentFontWidth != -1 && mn100PercentFontWidthCJK != -1 ) ||
+ ( mn100PercentFontWidth == -1 && mn100PercentFontWidthCTL == -1 ) ||
+ ( mn100PercentFontWidth != -1 && mn100PercentFontWidthCTL != -1 ),
+ "*FontPrevWin_Impl::Is100PercentFontWidthValid(): 100PercentFontWidth's not synchronous" );
+ return mn100PercentFontWidth != -1;
+}
+
+/*
+ * evaluates the scripttypes of the actual string.
+ * Afterwards the positions of script change are notified in aScriptChg,
+ * the scripttypes in aScriptType.
+ * The aTextWidth array will be filled with zero.
+ */
+void FontPrevWin_Impl::CheckScript()
+{
+ assert(!maText.isEmpty()); // must have a preview text here!
+ if (maText == maScriptText)
+ {
+ return; // already initialized
+ }
+
+ maScriptText = maText;
+
+ maScriptChg.clear();
+ maScriptType.clear();
+ maTextWidth.clear();
+
+ if (!mxBreak.is())
+ {
+ Reference<XComponentContext> xContext = ::comphelper::getProcessComponentContext();
+ mxBreak = BreakIterator::create(xContext);
+ }
+
+ sal_uInt16 nScript = 0;
+ sal_Int32 nChg = 0;
+
+ while (nChg < maText.getLength())
+ {
+ nScript = mxBreak->getScriptType(maText, nChg);
+ nChg = mxBreak->endOfScript(maText, nChg, nScript);
+ if (nChg < maText.getLength() && nChg > 0 &&
+ (css::i18n::ScriptType::WEAK ==
+ mxBreak->getScriptType(maText, nChg - 1)))
+ {
+ int8_t nType = u_charType(maText[nChg]);
+ if (nType == U_NON_SPACING_MARK || nType == U_ENCLOSING_MARK ||
+ nType == U_COMBINING_SPACING_MARK)
+ {
+ maScriptChg.push_back(nChg - 1);
+ }
+ else
+ {
+ maScriptChg.push_back(nChg);
+ }
+ }
+ else
+ {
+ maScriptChg.push_back(nChg);
+ }
+ maScriptType.push_back(nScript);
+ maTextWidth.push_back(0);
+ }
+}
+
+/*
+ * Size FontPrevWin_Impl::CalcTextSize(..)
+ * fills the aTextWidth array with the text width of every part
+ * of the actual string without a script change inside.
+ * For Latin parts the given rFont will be used,
+ * for Asian parts the aCJKFont.
+ * The returned size contains the whole string.
+ * The member nAscent is calculated to the maximal ascent of all used fonts.
+ */
+
+Size FontPrevWin_Impl::CalcTextSize(vcl::RenderContext& rRenderContext, OutputDevice const * _pPrinter, const SvxFont& rInFont)
+{
+ sal_uInt16 nScript;
+ sal_uInt16 nIdx = 0;
+ sal_Int32 nStart = 0;
+ sal_Int32 nEnd;
+ size_t nCnt = maScriptChg.size();
+
+ if (nCnt)
+ {
+ nEnd = maScriptChg[nIdx];
+ nScript = maScriptType[nIdx];
+ }
+ else
+ {
+ nEnd = maText.getLength();
+ nScript = css::i18n::ScriptType::LATIN;
+ }
+ tools::Long nTxtWidth = 0;
+ tools::Long nCJKHeight = 0;
+ tools::Long nCTLHeight = 0;
+ tools::Long nHeight = 0;
+ mnAscent = 0;
+ tools::Long nCJKAscent = 0;
+ tools::Long nCTLAscent = 0;
+
+ do
+ {
+ const SvxFont& rFont = (nScript == css::i18n::ScriptType::ASIAN) ?
+ maCJKFont :
+ ((nScript == css::i18n::ScriptType::COMPLEX) ?
+ maCTLFont :
+ rInFont);
+ tools::Long nWidth = rFont.GetTextSize(*_pPrinter, maText, nStart, nEnd - nStart).Width();
+ if (nIdx >= maTextWidth.size())
+ break;
+
+ maTextWidth[nIdx++] = nWidth;
+ nTxtWidth += nWidth;
+
+ switch (nScript)
+ {
+ case css::i18n::ScriptType::ASIAN:
+ calcFontHeightAnyAscent(rRenderContext, maCJKFont, nCJKHeight, nCJKAscent);
+ break;
+ case css::i18n::ScriptType::COMPLEX:
+ calcFontHeightAnyAscent(rRenderContext, maCTLFont, nCTLHeight, nCTLAscent);
+ break;
+ default:
+ calcFontHeightAnyAscent(rRenderContext, rFont, nHeight, mnAscent);
+ }
+
+ if (nEnd < maText.getLength() && nIdx < nCnt)
+ {
+ nStart = nEnd;
+ nEnd = maScriptChg[nIdx];
+ nScript = maScriptType[nIdx];
+ }
+ else
+ break;
+ }
+ while(true);
+
+ nHeight -= mnAscent;
+ nCJKHeight -= nCJKAscent;
+ nCTLHeight -= nCTLAscent;
+
+ if (nHeight < nCJKHeight)
+ nHeight = nCJKHeight;
+
+ if (mnAscent < nCJKAscent)
+ mnAscent = nCJKAscent;
+
+ if (nHeight < nCTLHeight)
+ nHeight = nCTLHeight;
+
+ if (mnAscent < nCTLAscent)
+ mnAscent = nCTLAscent;
+
+ nHeight += mnAscent;
+
+ Size aTxtSize(nTxtWidth, nHeight);
+ return aTxtSize;
+}
+
+/*
+ * void FontPrevWin_Impl::DrawPrev(..)
+ * calls SvxFont::DrawPrev(..) for every part of the string without a script
+ * change inside, for Asian parts the aCJKFont will be used, otherwise the
+ * given rFont.
+ */
+
+void FontPrevWin_Impl::DrawPrev(vcl::RenderContext& rRenderContext, Printer* _pPrinter, Point &rPt, const SvxFont& rInFont)
+{
+ vcl::Font aOldFont = _pPrinter->GetFont();
+ sal_uInt16 nScript;
+ sal_uInt16 nIdx = 0;
+ sal_Int32 nStart = 0;
+ sal_Int32 nEnd;
+ size_t nCnt = maScriptChg.size();
+ if (nCnt)
+ {
+ nEnd = maScriptChg[nIdx];
+ nScript = maScriptType[nIdx];
+ }
+ else
+ {
+ nEnd = maText.getLength();
+ nScript = css::i18n::ScriptType::LATIN;
+ }
+ do
+ {
+ const SvxFont& rFont = (nScript == css::i18n::ScriptType::ASIAN)
+ ? maCJKFont
+ : ((nScript == css::i18n::ScriptType::COMPLEX)
+ ? maCTLFont
+ : rInFont);
+ _pPrinter->SetFont(rFont);
+
+ rFont.DrawPrev(&rRenderContext, _pPrinter, rPt, maText, nStart, nEnd - nStart);
+
+ rPt.AdjustX(maTextWidth[nIdx++] );
+ if (nEnd < maText.getLength() && nIdx < nCnt)
+ {
+ nStart = nEnd;
+ nEnd = maScriptChg[nIdx];
+ nScript = maScriptType[nIdx];
+ }
+ else
+ break;
+ }
+ while(true);
+ _pPrinter->SetFont(aOldFont);
+}
+
+
+bool FontPrevWin_Impl::SetFontWidthScale(sal_uInt16 nScale)
+{
+ if (mnFontWidthScale != nScale)
+ {
+ mnFontWidthScale = nScale;
+ return true;
+ }
+
+ return false;
+}
+
+void FontPrevWin_Impl::ScaleFontWidth(vcl::RenderContext const & rOutDev)
+{
+ if (!Is100PercentFontWidthValid())
+ {
+ scaleFontWidth(maFont, rOutDev, mn100PercentFontWidth);
+ scaleFontWidth(maCJKFont, rOutDev, mn100PercentFontWidthCJK);
+ scaleFontWidth(maCTLFont, rOutDev, mn100PercentFontWidthCTL);
+ }
+
+ maFont.SetAverageFontWidth(mn100PercentFontWidth * mnFontWidthScale / 100);
+ maCJKFont.SetAverageFontWidth(mn100PercentFontWidthCJK * mnFontWidthScale / 100);
+ maCTLFont.SetAverageFontWidth(mn100PercentFontWidthCTL * mnFontWidthScale / 100);
+}
+
+static bool GetWhich (const SfxItemSet& rSet, sal_uInt16 nSlot, sal_uInt16& rWhich)
+{
+ rWhich = rSet.GetPool()->GetWhich(nSlot);
+ return rSet.GetItemState(rWhich) >= SfxItemState::DEFAULT;
+}
+
+static void SetPrevFont(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
+{
+ sal_uInt16 nWhich;
+ if (GetWhich(rSet, nSlot, nWhich))
+ {
+ const SvxFontItem& rFontItem = static_cast<const SvxFontItem&>(rSet.Get(nWhich));
+ rFont.SetFamily(rFontItem.GetFamily());
+ rFont.SetFamilyName(rFontItem.GetFamilyName());
+ rFont.SetPitch(rFontItem.GetPitch());
+ rFont.SetCharSet(rFontItem.GetCharSet());
+ rFont.SetStyleName(rFontItem.GetStyleName());
+ }
+}
+
+static void SetPrevFontStyle( const SfxItemSet& rSet, sal_uInt16 nPosture, sal_uInt16 nWeight, SvxFont& rFont )
+{
+ sal_uInt16 nWhich;
+ if( GetWhich( rSet, nPosture, nWhich ) )
+ {
+ const SvxPostureItem& rItem = static_cast<const SvxPostureItem&>( rSet.Get( nWhich ) );
+ rFont.SetItalic( rItem.GetValue() != ITALIC_NONE ? ITALIC_NORMAL : ITALIC_NONE );
+ }
+
+ if( GetWhich( rSet, nWeight, nWhich ) )
+ {
+ const SvxWeightItem& rItem = static_cast<const SvxWeightItem&>( rSet.Get( nWhich ) );
+ rFont.SetWeight( rItem.GetValue() != WEIGHT_NORMAL ? WEIGHT_BOLD : WEIGHT_NORMAL );
+ }
+}
+
+static void SetPrevFontEscapement(SvxFont& rFont, sal_uInt8 nProp, sal_uInt8 nEscProp, short nEsc)
+{
+ rFont.SetPropr(nProp);
+ rFont.SetProprRel(nEscProp);
+ rFont.SetEscapement(nEsc);
+}
+
+void SvxFontPrevWindow::ApplySettings(vcl::RenderContext& rRenderContext)
+{
+ rRenderContext.SetTextColor( svtools::ColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
+ rRenderContext.SetBackground( svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
+}
+
+void SvxFontPrevWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aPrefSize(getPreviewStripSize(pDrawingArea->get_ref_device()));
+ pDrawingArea->set_size_request(aPrefSize.Width(), aPrefSize.Height());
+
+ pImpl.reset(new FontPrevWin_Impl);
+ SfxViewShell* pSh = SfxViewShell::Current();
+
+ if (pSh)
+ pImpl->mpPrinter = pSh->GetPrinter();
+
+ if (!pImpl->mpPrinter)
+ {
+ pImpl->mpPrinter = VclPtr<Printer>::Create();
+ pImpl->mbDelPrinter = true;
+ }
+ initFont(pImpl->maFont);
+ initFont(pImpl->maCJKFont);
+ initFont(pImpl->maCTLFont);
+
+ Invalidate();
+}
+
+SvxFontPrevWindow::SvxFontPrevWindow()
+{
+}
+
+SvxFontPrevWindow::~SvxFontPrevWindow()
+{
+}
+
+SvxFont& SvxFontPrevWindow::GetCTLFont()
+{
+ return pImpl->maCTLFont;
+}
+
+SvxFont& SvxFontPrevWindow::GetCJKFont()
+{
+ return pImpl->maCJKFont;
+}
+
+SvxFont& SvxFontPrevWindow::GetFont()
+{
+ pImpl->Invalidate100PercentFontWidth(); // because the user might change the size
+ return pImpl->maFont;
+}
+
+const SvxFont& SvxFontPrevWindow::GetFont() const
+{
+ return pImpl->maFont;
+}
+
+void SvxFontPrevWindow::SetPreviewText( const OUString& rString )
+{
+ pImpl->maText = rString;
+ pImpl->mbTextInited = true;
+}
+
+void SvxFontPrevWindow::SetFontNameAsPreviewText()
+{
+ pImpl->mbUseFontNameAsText = true;
+}
+
+void SvxFontPrevWindow::SetFont( const SvxFont& rNormalOutFont, const SvxFont& rCJKOutFont, const SvxFont& rCTLFont )
+{
+ setFont(rNormalOutFont, pImpl->maFont);
+ setFont(rCJKOutFont, pImpl->maCJKFont);
+ setFont(rCTLFont, pImpl->maCTLFont);
+
+ pImpl->Invalidate100PercentFontWidth();
+ Invalidate();
+}
+
+void SvxFontPrevWindow::SetColor(const Color &rColor)
+{
+ pImpl->mxColor = rColor;
+ Invalidate();
+}
+
+void SvxFontPrevWindow::ResetColor()
+{
+ pImpl->mxColor.reset();
+ Invalidate();
+}
+
+void SvxFontPrevWindow::SetTextLineColor(const Color &rColor)
+{
+ pImpl->mxTextLineColor = rColor;
+ Invalidate();
+}
+
+void SvxFontPrevWindow::SetOverlineColor(const Color &rColor)
+{
+ pImpl->mxOverlineColor = rColor;
+ Invalidate();
+}
+
+void SvxFontPrevWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::ALL);
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
+
+ ApplySettings(rRenderContext);
+
+ Printer* pPrinter = pImpl->mpPrinter;
+ const SvxFont& rFont = pImpl->maFont;
+ const SvxFont& rCJKFont = pImpl->maCJKFont;
+ const SvxFont& rCTLFont = pImpl->maCTLFont;
+
+ if (!IsEnabled())
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Size aLogSize(rRenderContext.GetOutputSize());
+
+ tools::Rectangle aRect(Point(0, 0), aLogSize);
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(rStyleSettings.GetWindowColor());
+ rRenderContext.DrawRect(aRect);
+ }
+ else
+ {
+ if (!pImpl->mbSelection && !pImpl->mbTextInited)
+ {
+ using namespace css::i18n::ScriptType;
+
+ SfxViewShell* pSh = SfxViewShell::Current();
+
+ if (pSh && !pImpl->mbGetSelection && !pImpl->mbUseFontNameAsText)
+ {
+ pImpl->maText = removeCRLF(pSh->GetSelectionText(/*bCompleteWords*/false, /*bOnlyASample*/true));
+ pImpl->mbGetSelection = true;
+ pImpl->mbSelection = !(pImpl->maText.isEmpty());
+ }
+
+ if (!pImpl->mbSelection || pImpl->mbUseFontNameAsText)
+ {
+ //If we're showing multiple sample texts, then they're all
+ //sample texts. If only showing Latin, continue to use
+ //the fontname as the preview
+ if ((pImpl->m_bCJKEnabled) || (pImpl->m_bCTLEnabled))
+ pImpl->maText = makeRepresentativeTextForFont(LATIN, rFont);
+ else
+ pImpl->maText = rFont.GetFamilyName();
+
+ if (pImpl->m_bCJKEnabled)
+ {
+ if (!pImpl->maText.isEmpty())
+ pImpl->maText += " ";
+ pImpl->maText += makeRepresentativeTextForFont(ASIAN, rCJKFont);
+
+ }
+ if (pImpl->m_bCTLEnabled)
+ {
+ if (!pImpl->maText.isEmpty())
+ pImpl->maText += " ";
+ pImpl->maText += makeRepresentativeTextForFont(COMPLEX, rCTLFont);
+ }
+ }
+
+ if (pImpl->maText.isEmpty())
+ { // fdo#58427: still no text? let's try that one...
+ pImpl->maText = makeRepresentativeTextForFont(LATIN, rFont);
+ }
+
+ pImpl->maText = removeCRLF(pImpl->maText);
+
+ if (pImpl->maText.getLength() > (TEXT_WIDTH - 1))
+ {
+ const sal_Int32 nSpaceIdx = pImpl->maText.indexOf(" ", TEXT_WIDTH);
+ if (nSpaceIdx != -1)
+ pImpl->maText = pImpl->maText.copy(0, nSpaceIdx);
+ else
+ pImpl->maText = pImpl->maText.copy(0, (TEXT_WIDTH - 1));
+ }
+ }
+
+ // calculate text width scaling
+ pImpl->ScaleFontWidth(rRenderContext);
+
+ pImpl->CheckScript();
+ Size aTxtSize = pImpl->CalcTextSize(rRenderContext, pPrinter, rFont);
+
+ const Size aLogSize(rRenderContext.GetOutputSize());
+
+ tools::Long nX = aLogSize.Width() / 2 - aTxtSize.Width() / 2;
+ tools::Long nY = aLogSize.Height() / 2 - aTxtSize.Height() / 2;
+
+ if (nY + pImpl->mnAscent > aLogSize.Height())
+ nY = aLogSize.Height() - pImpl->mnAscent;
+
+ if (pImpl->mxBackColor)
+ {
+ tools::Rectangle aRect(Point(0, 0), aLogSize);
+ Color aLineCol = rRenderContext.GetLineColor();
+ Color aFillCol = rRenderContext.GetFillColor();
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(*pImpl->mxBackColor);
+ rRenderContext.DrawRect(aRect);
+ rRenderContext.SetLineColor(aLineCol);
+ rRenderContext.SetFillColor(aFillCol);
+ }
+ if (pImpl->mxColor)
+ {
+ tools::Rectangle aRect(Point(nX, nY), aTxtSize);
+ Color aLineCol = rRenderContext.GetLineColor();
+ Color aFillCol = rRenderContext.GetFillColor();
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(*pImpl->mxColor);
+ rRenderContext.DrawRect(aRect);
+ rRenderContext.SetLineColor(aLineCol);
+ rRenderContext.SetFillColor(aFillCol);
+ }
+
+ if (pImpl->mxTextLineColor)
+ {
+ rRenderContext.SetTextLineColor(*pImpl->mxTextLineColor);
+ }
+
+ if (pImpl->mxOverlineColor)
+ {
+ rRenderContext.SetOverlineColor(*pImpl->mxOverlineColor);
+ }
+
+ tools::Long nStdAscent = pImpl->mnAscent;
+ nY += nStdAscent;
+
+ if (IsTwoLines())
+ {
+ SvxFont aSmallFont(rFont);
+ Size aOldSize = pImpl->maCJKFont.GetFontSize();
+ setFontSize(aSmallFont);
+ setFontSize(pImpl->maCJKFont);
+
+ tools::Long nStartBracketWidth = 0;
+ tools::Long nEndBracketWidth = 0;
+ tools::Long nTextWidth = 0;
+ if (pImpl->mcStartBracket)
+ {
+ OUString sBracket(pImpl->mcStartBracket);
+ nStartBracketWidth = rFont.GetTextSize(*pPrinter, sBracket).Width();
+ }
+ if (pImpl->mcEndBracket)
+ {
+ OUString sBracket(pImpl->mcEndBracket);
+ nEndBracketWidth = rFont.GetTextSize(*pPrinter, sBracket).Width();
+ }
+ nTextWidth = pImpl->CalcTextSize(rRenderContext, pPrinter, aSmallFont).Width();
+ tools::Long nResultWidth = nStartBracketWidth;
+ nResultWidth += nEndBracketWidth;
+ nResultWidth += nTextWidth;
+
+ tools::Long _nX = (aLogSize.Width() - nResultWidth) / 2;
+ rRenderContext.DrawLine(Point(0, nY), Point(_nX, nY));
+ rRenderContext.DrawLine(Point(_nX + nResultWidth, nY), Point(aLogSize.Width(), nY));
+
+ tools::Long nSmallAscent = pImpl->mnAscent;
+ tools::Long nOffset = (nStdAscent - nSmallAscent) / 2;
+
+ if (pImpl->mcStartBracket)
+ {
+ OUString sBracket(pImpl->mcStartBracket);
+ rFont.DrawPrev(&rRenderContext, pPrinter, Point(_nX, nY - nOffset - 4), sBracket);
+ _nX += nStartBracketWidth;
+ }
+
+ Point aTmpPoint1(_nX, nY - nSmallAscent - 2);
+ Point aTmpPoint2(_nX, nY);
+ pImpl->DrawPrev(rRenderContext, pPrinter, aTmpPoint1, aSmallFont);
+ pImpl->DrawPrev(rRenderContext, pPrinter, aTmpPoint2, aSmallFont);
+
+ _nX += nTextWidth;
+ if (pImpl->mcEndBracket)
+ {
+ Point aTmpPoint( _nX + 1, nY - nOffset - 4);
+ OUString sBracket(pImpl->mcEndBracket);
+ rFont.DrawPrev(&rRenderContext, pPrinter, aTmpPoint, sBracket);
+ }
+ pImpl->maCJKFont.SetFontSize(aOldSize);
+ }
+ else
+ {
+
+ Color aLineCol = rRenderContext.GetLineColor();
+
+ rRenderContext.SetLineColor(rFont.GetColor());
+ rRenderContext.DrawLine(Point(0, nY), Point(nX, nY));
+ rRenderContext.DrawLine(Point(nX + aTxtSize.Width(), nY), Point(aLogSize.Width(), nY));
+ rRenderContext.SetLineColor(aLineCol);
+
+ Point aTmpPoint(nX, nY);
+ pImpl->DrawPrev(rRenderContext, pPrinter, aTmpPoint, rFont);
+ }
+ }
+ rRenderContext.Pop();
+}
+
+bool SvxFontPrevWindow::IsTwoLines() const
+{
+ return pImpl->mbTwoLines;
+}
+
+void SvxFontPrevWindow::SetTwoLines(bool bSet)
+{
+ pImpl->mbTwoLines = bSet;
+}
+
+void SvxFontPrevWindow::SetBrackets(sal_Unicode cStart, sal_Unicode cEnd)
+{
+ pImpl->mcStartBracket = cStart;
+ pImpl->mcEndBracket = cEnd;
+}
+
+void SvxFontPrevWindow::SetFontWidthScale( sal_uInt16 n )
+{
+ if (pImpl->SetFontWidthScale(n))
+ Invalidate();
+}
+
+void SvxFontPrevWindow::AutoCorrectFontColor()
+{
+ Color aColor(COL_AUTO);
+ if ( pImpl->mxBackColor ) aColor = *pImpl->mxBackColor;
+ const bool bIsDark(aColor.IsDark());
+
+ aColor = pImpl->maFont.GetColor();
+ if (aColor == COL_AUTO)
+ pImpl->maFont.SetColor( bIsDark ? COL_WHITE : COL_BLACK );
+ aColor = pImpl->maCJKFont.GetColor();
+ if (aColor == COL_AUTO)
+ pImpl->maCJKFont.SetColor( bIsDark ? COL_WHITE : COL_BLACK );
+ aColor = pImpl->maCTLFont.GetColor();
+ if (aColor == COL_AUTO)
+ pImpl->maCTLFont.SetColor( bIsDark ? COL_WHITE : COL_BLACK );
+}
+
+void SvxFontPrevWindow::SetFontSize( const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont )
+{
+ sal_uInt16 nWhich;
+ tools::Long nH;
+ if (GetWhich(rSet, nSlot, nWhich))
+ {
+ nH = OutputDevice::LogicToLogic(static_cast<const SvxFontHeightItem&>(rSet.Get(nWhich)).GetHeight(),
+ rSet.GetPool()->GetMetric(nWhich),
+ MapUnit::MapTwip);
+ }
+ else
+ nH = 240;// as default 12pt
+
+ rFont.SetFontSize(Size(0, nH));
+}
+
+void SvxFontPrevWindow::SetFontLang(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
+{
+ sal_uInt16 nWhich;
+ LanguageType nLang;
+ if( GetWhich( rSet, nSlot, nWhich ) )
+ nLang = static_cast<const SvxLanguageItem&>(rSet.Get(nWhich)).GetLanguage();
+ else
+ nLang = LANGUAGE_NONE;
+ rFont.SetLanguage(nLang);
+}
+
+void SvxFontPrevWindow::SetFromItemSet(const SfxItemSet &rSet, bool bPreviewBackgroundToCharacter)
+{
+ sal_uInt16 nWhich;
+ SvxFont& rFont = GetFont();
+ SvxFont& rCJKFont = GetCJKFont();
+ SvxFont& rCTLFont = GetCTLFont();
+
+ // Preview string
+ if( GetWhich( rSet, SID_CHAR_DLG_PREVIEW_STRING, nWhich ) )
+ {
+ const SfxStringItem& rItem = static_cast<const SfxStringItem&>( rSet.Get( nWhich ) );
+ const OUString& aString = rItem.GetValue();
+ if( !aString.isEmpty() )
+ SetPreviewText( aString );
+ else
+ SetFontNameAsPreviewText();
+ }
+
+ // Underline
+ FontLineStyle eUnderline;
+ if( GetWhich( rSet, SID_ATTR_CHAR_UNDERLINE, nWhich ) )
+ {
+ const SvxUnderlineItem& rItem = static_cast<const SvxUnderlineItem&>( rSet.Get( nWhich ) );
+ eUnderline = rItem.GetValue();
+ }
+ else
+ eUnderline = LINESTYLE_NONE;
+
+ rFont.SetUnderline( eUnderline );
+ rCJKFont.SetUnderline( eUnderline );
+ rCTLFont.SetUnderline( eUnderline );
+
+ // Overline
+ FontLineStyle eOverline;
+ if( GetWhich( rSet, SID_ATTR_CHAR_OVERLINE, nWhich ) )
+ {
+ const SvxOverlineItem& rItem = static_cast<const SvxOverlineItem&>( rSet.Get( nWhich ) );
+ eOverline = rItem.GetValue();
+ }
+ else
+ eOverline = LINESTYLE_NONE;
+
+ rFont.SetOverline( eOverline );
+ rCJKFont.SetOverline( eOverline );
+ rCTLFont.SetOverline( eOverline );
+
+ // Strikeout
+ FontStrikeout eStrikeout;
+ if( GetWhich( rSet, SID_ATTR_CHAR_STRIKEOUT, nWhich ) )
+ {
+ const SvxCrossedOutItem& rItem = static_cast<const SvxCrossedOutItem&>( rSet.Get( nWhich ) );
+ eStrikeout = rItem.GetValue();
+ }
+ else
+ eStrikeout = STRIKEOUT_NONE;
+
+ rFont.SetStrikeout( eStrikeout );
+ rCJKFont.SetStrikeout( eStrikeout );
+ rCTLFont.SetStrikeout( eStrikeout );
+
+ // WordLineMode
+ if( GetWhich( rSet, SID_ATTR_CHAR_WORDLINEMODE, nWhich ) )
+ {
+ const SvxWordLineModeItem& rItem = static_cast<const SvxWordLineModeItem&>( rSet.Get( nWhich ) );
+ rFont.SetWordLineMode( rItem.GetValue() );
+ rCJKFont.SetWordLineMode( rItem.GetValue() );
+ rCTLFont.SetWordLineMode( rItem.GetValue() );
+ }
+
+ // Emphasis
+ if( GetWhich( rSet, SID_ATTR_CHAR_EMPHASISMARK, nWhich ) )
+ {
+ const SvxEmphasisMarkItem& rItem = static_cast<const SvxEmphasisMarkItem&>( rSet.Get( nWhich ) );
+ FontEmphasisMark eMark = rItem.GetEmphasisMark();
+ rFont.SetEmphasisMark( eMark );
+ rCJKFont.SetEmphasisMark( eMark );
+ rCTLFont.SetEmphasisMark( eMark );
+ }
+
+ // Relief
+ if( GetWhich( rSet, SID_ATTR_CHAR_RELIEF, nWhich ) )
+ {
+ const SvxCharReliefItem& rItem = static_cast<const SvxCharReliefItem&>( rSet.Get( nWhich ) );
+ FontRelief eFontRelief = rItem.GetValue();
+ rFont.SetRelief( eFontRelief );
+ rCJKFont.SetRelief( eFontRelief );
+ rCTLFont.SetRelief( eFontRelief );
+ }
+
+ // Effects
+ if( GetWhich( rSet, SID_ATTR_CHAR_CASEMAP, nWhich ) )
+ {
+ const SvxCaseMapItem& rItem = static_cast<const SvxCaseMapItem&>( rSet.Get( nWhich ) );
+ SvxCaseMap eCaseMap = rItem.GetValue();
+ rFont.SetCaseMap( eCaseMap );
+ rCJKFont.SetCaseMap( eCaseMap );
+ // #i78474# small caps do not exist in CTL fonts
+ rCTLFont.SetCaseMap( eCaseMap == SvxCaseMap::SmallCaps ? SvxCaseMap::NotMapped : eCaseMap );
+ }
+
+ // Outline
+ if( GetWhich( rSet, SID_ATTR_CHAR_CONTOUR, nWhich ) )
+ {
+ const SvxContourItem& rItem = static_cast<const SvxContourItem&>( rSet.Get( nWhich ) );
+ bool bOutline = rItem.GetValue();
+ rFont.SetOutline( bOutline );
+ rCJKFont.SetOutline( bOutline );
+ rCTLFont.SetOutline( bOutline );
+ }
+
+ // Shadow
+ if( GetWhich( rSet, SID_ATTR_CHAR_SHADOWED, nWhich ) )
+ {
+ const SvxShadowedItem& rItem = static_cast<const SvxShadowedItem&>( rSet.Get( nWhich ) );
+ bool bShadow = rItem.GetValue();
+ rFont.SetShadow( bShadow );
+ rCJKFont.SetShadow( bShadow );
+ rCTLFont.SetShadow( bShadow );
+ }
+
+ // Background
+ bool bTransparent;
+ if( GetWhich( rSet, bPreviewBackgroundToCharacter ? SID_ATTR_BRUSH : SID_ATTR_BRUSH_CHAR, nWhich ) )
+ {
+ const SvxBrushItem& rBrush = static_cast<const SvxBrushItem&>( rSet.Get( nWhich ) );
+ const Color& rColor = rBrush.GetColor();
+ bTransparent = rColor.IsTransparent();
+ rFont.SetFillColor( rColor );
+ rCJKFont.SetFillColor( rColor );
+ rCTLFont.SetFillColor( rColor );
+ }
+ else
+ bTransparent = true;
+
+ rFont.SetTransparent( bTransparent );
+ rCJKFont.SetTransparent( bTransparent );
+ rCTLFont.SetTransparent( bTransparent );
+
+ if( !bPreviewBackgroundToCharacter )
+ {
+ if( GetWhich( rSet, SID_ATTR_BRUSH, nWhich ) )
+ {
+ const SvxBrushItem& rBrush = static_cast<const SvxBrushItem&>( rSet.Get( nWhich ) );
+ if( GPOS_NONE == rBrush.GetGraphicPos() )
+ pImpl->mxBackColor = rBrush.GetColor();
+ }
+ }
+
+ // Font
+ SetPrevFont( rSet, SID_ATTR_CHAR_FONT, rFont );
+ SetPrevFont( rSet, SID_ATTR_CHAR_CJK_FONT, rCJKFont );
+ SetPrevFont( rSet, SID_ATTR_CHAR_CTL_FONT, rCTLFont );
+
+ // Style
+ SetPrevFontStyle( rSet, SID_ATTR_CHAR_POSTURE, SID_ATTR_CHAR_WEIGHT, rFont );
+ SetPrevFontStyle( rSet, SID_ATTR_CHAR_CJK_POSTURE, SID_ATTR_CHAR_CJK_WEIGHT, rCJKFont );
+ SetPrevFontStyle( rSet, SID_ATTR_CHAR_CTL_POSTURE, SID_ATTR_CHAR_CTL_WEIGHT, rCTLFont );
+
+ // Size
+ SetFontSize( rSet, SID_ATTR_CHAR_FONTHEIGHT, rFont );
+ SetFontSize( rSet, SID_ATTR_CHAR_CJK_FONTHEIGHT, rCJKFont );
+ SetFontSize( rSet, SID_ATTR_CHAR_CTL_FONTHEIGHT, rCTLFont );
+
+ // Language
+ SetFontLang( rSet, SID_ATTR_CHAR_LANGUAGE, rFont );
+ SetFontLang( rSet, SID_ATTR_CHAR_CJK_LANGUAGE, rCJKFont );
+ SetFontLang( rSet, SID_ATTR_CHAR_CTL_LANGUAGE, rCTLFont );
+
+ // Color
+ if( GetWhich( rSet, SID_ATTR_CHAR_COLOR, nWhich ) )
+ {
+ const SvxColorItem& rItem = static_cast<const SvxColorItem&>( rSet.Get( nWhich ) );
+ Color aCol( rItem.GetValue() );
+ rFont.SetColor( aCol );
+
+ rCJKFont.SetColor( aCol );
+ rCTLFont.SetColor( aCol );
+
+ AutoCorrectFontColor(); // handle color COL_AUTO
+ }
+
+ // Kerning
+ if( GetWhich( rSet, SID_ATTR_CHAR_KERNING, nWhich ) )
+ {
+ const SvxKerningItem& rItem = static_cast<const SvxKerningItem&>( rSet.Get( nWhich ) );
+ short nKern = static_cast<short>(OutputDevice::LogicToLogic(rItem.GetValue(), rSet.GetPool()->GetMetric(nWhich), MapUnit::MapTwip));
+ rFont.SetFixKerning( nKern );
+ rCJKFont.SetFixKerning( nKern );
+ rCTLFont.SetFixKerning( nKern );
+ }
+
+ // Escapement
+ const sal_uInt8 nProp = 100;
+ short nEsc;
+ sal_uInt8 nEscProp;
+ if( GetWhich( rSet, SID_ATTR_CHAR_ESCAPEMENT, nWhich ) )
+ {
+ const SvxEscapementItem& rItem = static_cast<const SvxEscapementItem&>( rSet.Get( nWhich ) );
+ nEsc = rItem.GetEsc();
+ nEscProp = rItem.GetProportionalHeight();
+
+ if( nEsc == DFLT_ESC_AUTO_SUPER )
+ nEsc = DFLT_ESC_SUPER;
+ else if( nEsc == DFLT_ESC_AUTO_SUB )
+ nEsc = DFLT_ESC_SUB;
+ }
+ else
+ {
+ nEsc = 0;
+ nEscProp = 100;
+ }
+ SetPrevFontEscapement( rFont, nProp, nEscProp, nEsc );
+ SetPrevFontEscapement( rCJKFont, nProp, nEscProp, nEsc );
+ SetPrevFontEscapement( rCTLFont, nProp, nEscProp, nEsc );
+
+ // Font width scale
+ if( GetWhich( rSet, SID_ATTR_CHAR_SCALEWIDTH, nWhich ) )
+ {
+ const SvxCharScaleWidthItem&rItem = static_cast<const SvxCharScaleWidthItem&>( rSet.Get( nWhich ) );
+ SetFontWidthScale( rItem.GetValue() );
+ }
+
+ Invalidate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/fontwork.cxx b/svx/source/dialog/fontwork.cxx
new file mode 100644
index 000000000..af1f25649
--- /dev/null
+++ b/svx/source/dialog/fontwork.cxx
@@ -0,0 +1,794 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/module.hxx>
+#include <sfx2/dispatch.hxx>
+
+#include <svx/colorbox.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/xftadit.hxx>
+#include <svx/xftdiit.hxx>
+#include <svx/xftstit.hxx>
+#include <svx/xftmrit.hxx>
+#include <svx/xftouit.hxx>
+#include <svx/xftshit.hxx>
+#include <svx/xftshcit.hxx>
+#include <svx/xftshxy.hxx>
+#include <svx/xtextit0.hxx>
+
+#include <svtools/unitconv.hxx>
+#include <svx/svxids.hrc>
+#include <bitmaps.hlst>
+#include <svx/fontwork.hxx>
+
+#define WIDTH_CHARS 10
+
+SFX_IMPL_DOCKINGWINDOW_WITHID( SvxFontWorkChildWindow, SID_FONTWORK );
+
+// ControllerItem for Fontwork
+
+SvxFontWorkControllerItem::SvxFontWorkControllerItem
+(
+ sal_uInt16 _nId,
+ SvxFontWorkDialog& rDlg,
+ SfxBindings& rBindings
+) :
+
+ SfxControllerItem( _nId, rBindings ),
+
+ rFontWorkDlg( rDlg )
+{
+}
+
+// StateChanged method for FontWork items
+
+void SvxFontWorkControllerItem::StateChangedAtToolBoxControl( sal_uInt16 /*nSID*/, SfxItemState /*eState*/,
+ const SfxPoolItem* pItem )
+{
+ switch ( GetId() )
+ {
+ case SID_FORMTEXT_STYLE:
+ {
+ const XFormTextStyleItem* pStateItem =
+ dynamic_cast<const XFormTextStyleItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextStyleItem expected");
+ rFontWorkDlg.SetStyle_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_ADJUST:
+ {
+ const XFormTextAdjustItem* pStateItem =
+ dynamic_cast<const XFormTextAdjustItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextAdjustItem expected");
+ rFontWorkDlg.SetAdjust_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_DISTANCE:
+ {
+ const XFormTextDistanceItem* pStateItem =
+ dynamic_cast<const XFormTextDistanceItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextDistanceItem expected");
+ rFontWorkDlg.SetDistance_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_START:
+ {
+ const XFormTextStartItem* pStateItem =
+ dynamic_cast<const XFormTextStartItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextStartItem expected");
+ rFontWorkDlg.SetStart_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_MIRROR:
+ {
+ const XFormTextMirrorItem* pStateItem =
+ dynamic_cast<const XFormTextMirrorItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextMirrorItem expected");
+ rFontWorkDlg.SetMirror_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_HIDEFORM:
+ {
+ const XFormTextHideFormItem* pStateItem =
+ dynamic_cast<const XFormTextHideFormItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextHideFormItem expected");
+ rFontWorkDlg.SetShowForm_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_OUTLINE:
+ {
+ const XFormTextOutlineItem* pStateItem =
+ dynamic_cast<const XFormTextOutlineItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextOutlineItem expected");
+ rFontWorkDlg.SetOutline_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_SHADOW:
+ {
+ const XFormTextShadowItem* pStateItem =
+ dynamic_cast<const XFormTextShadowItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowItem expected");
+ rFontWorkDlg.SetShadow_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_SHDWCOLOR:
+ {
+ const XFormTextShadowColorItem* pStateItem =
+ dynamic_cast<const XFormTextShadowColorItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowColorItem expected");
+ rFontWorkDlg.SetShadowColor_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_SHDWXVAL:
+ {
+ const XFormTextShadowXValItem* pStateItem =
+ dynamic_cast<const XFormTextShadowXValItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowXValItem expected");
+ rFontWorkDlg.SetShadowXVal_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_SHDWYVAL:
+ {
+ const XFormTextShadowYValItem* pStateItem =
+ dynamic_cast<const XFormTextShadowYValItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowYValItem expected");
+ rFontWorkDlg.SetShadowYVal_Impl(pStateItem);
+ break;
+ }
+ }
+}
+
+// Derivation from SfxChildWindow as "containers" for Fontwork dialog
+
+SvxFontWorkChildWindow::SvxFontWorkChildWindow
+(
+ vcl::Window* _pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo
+) :
+ SfxChildWindow( _pParent, nId )
+{
+ VclPtrInstance<SvxFontWorkDialog> pDlg(pBindings, this, _pParent);
+ SetWindow(pDlg);
+
+ pDlg->Initialize( pInfo );
+}
+
+// Floating Window to the attribution of text effects
+SvxFontWorkDialog::SvxFontWorkDialog(SfxBindings *pBindinx,
+ SfxChildWindow *pCW,
+ vcl::Window* _pParent)
+ : SfxDockingWindow(pBindinx, pCW, _pParent, "DockingFontwork", "svx/ui/dockingfontwork.ui")
+ , rBindings(*pBindinx)
+ , aInputIdle("SvxFontWorkDialog Input")
+ , nSaveShadowX(0)
+ , nSaveShadowY(0)
+ , nSaveShadowAngle(450)
+ , nSaveShadowSize (100)
+ , m_xTbxStyle(m_xBuilder->weld_toolbar("style"))
+ , m_xTbxAdjust(m_xBuilder->weld_toolbar("adjust"))
+ , m_xMtrFldDistance(m_xBuilder->weld_metric_spin_button("distance", FieldUnit::CM))
+ , m_xMtrFldTextStart(m_xBuilder->weld_metric_spin_button("indent", FieldUnit::CM))
+ , m_xTbxShadow(m_xBuilder->weld_toolbar("shadow"))
+ , m_xFbShadowX(m_xBuilder->weld_image("shadowx"))
+ , m_xMtrFldShadowX(m_xBuilder->weld_metric_spin_button("distancex", FieldUnit::CM))
+ , m_xFbShadowY(m_xBuilder->weld_image("shadowy"))
+ , m_xMtrFldShadowY(m_xBuilder->weld_metric_spin_button("distancey", FieldUnit::CM))
+ , m_xShadowColorLB(new ColorListBox(m_xBuilder->weld_menu_button("color"), [this]{ return GetFrameWeld(); } ))
+{
+ SetText(SvxResId(RID_SVXSTR_FONTWORK));
+
+ ApplyImageList();
+
+ pCtrlItems[0] = new SvxFontWorkControllerItem(SID_FORMTEXT_STYLE, *this, rBindings);
+ pCtrlItems[1] = new SvxFontWorkControllerItem(SID_FORMTEXT_ADJUST, *this, rBindings);
+ pCtrlItems[2] = new SvxFontWorkControllerItem(SID_FORMTEXT_DISTANCE, *this, rBindings);
+ pCtrlItems[3] = new SvxFontWorkControllerItem(SID_FORMTEXT_START, *this, rBindings);
+ pCtrlItems[4] = new SvxFontWorkControllerItem(SID_FORMTEXT_MIRROR, *this, rBindings);
+ pCtrlItems[5] = new SvxFontWorkControllerItem(SID_FORMTEXT_HIDEFORM, *this, rBindings);
+ pCtrlItems[6] = new SvxFontWorkControllerItem(SID_FORMTEXT_OUTLINE, *this, rBindings);
+ pCtrlItems[7] = new SvxFontWorkControllerItem(SID_FORMTEXT_SHADOW, *this, rBindings);
+ pCtrlItems[8] = new SvxFontWorkControllerItem(SID_FORMTEXT_SHDWCOLOR, *this, rBindings);
+ pCtrlItems[9] = new SvxFontWorkControllerItem(SID_FORMTEXT_SHDWXVAL, *this, rBindings);
+ pCtrlItems[10] = new SvxFontWorkControllerItem(SID_FORMTEXT_SHDWYVAL, *this, rBindings);
+
+ m_xTbxStyle->connect_clicked(LINK(this, SvxFontWorkDialog, SelectStyleHdl_Impl));
+ m_xTbxAdjust->connect_clicked(LINK(this, SvxFontWorkDialog, SelectAdjustHdl_Impl));
+ m_xTbxShadow->connect_clicked(LINK(this, SvxFontWorkDialog, SelectShadowHdl_Impl));
+
+ Link<weld::MetricSpinButton&,void> aLink = LINK(this, SvxFontWorkDialog, ModifyInputHdl_Impl);
+ m_xMtrFldDistance->connect_value_changed( aLink );
+ m_xMtrFldTextStart->connect_value_changed( aLink );
+ m_xMtrFldShadowX->connect_value_changed( aLink );
+ m_xMtrFldShadowY->connect_value_changed( aLink );
+
+ // Set System metric
+ const FieldUnit eDlgUnit = rBindings.GetDispatcher()->GetModule()->GetFieldUnit();
+ SetFieldUnit(*m_xMtrFldDistance, eDlgUnit, true);
+ SetFieldUnit(*m_xMtrFldTextStart, eDlgUnit, true);
+ SetFieldUnit(*m_xMtrFldShadowX, eDlgUnit, true);
+ SetFieldUnit(*m_xMtrFldShadowY, eDlgUnit, true);
+ if( eDlgUnit == FieldUnit::MM )
+ {
+ m_xMtrFldDistance->set_increments(50, 500, FieldUnit::NONE);
+ m_xMtrFldTextStart->set_increments(50, 500, FieldUnit::NONE);
+ m_xMtrFldShadowX->set_increments(50, 500, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_increments(50, 500, FieldUnit::NONE);
+ }
+ else
+ {
+ m_xMtrFldDistance->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldTextStart->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowX->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_increments(10, 100, FieldUnit::NONE);
+ }
+ m_xMtrFldShadowX->set_width_chars(WIDTH_CHARS);
+ m_xMtrFldShadowY->set_width_chars(WIDTH_CHARS);
+
+ m_xShadowColorLB->SetSelectHdl( LINK(this, SvxFontWorkDialog, ColorSelectHdl_Impl) );
+
+ aInputIdle.SetPriority(TaskPriority::LOWEST);
+ aInputIdle.SetInvokeHandler(LINK(this, SvxFontWorkDialog, InputTimeoutHdl_Impl));
+}
+
+SvxFontWorkDialog::~SvxFontWorkDialog()
+{
+ disposeOnce();
+}
+
+void SvxFontWorkDialog::dispose()
+{
+ for (SvxFontWorkControllerItem* pCtrlItem : pCtrlItems)
+ pCtrlItem->dispose();
+ m_xTbxStyle.reset();
+ m_xTbxAdjust.reset();
+ m_xMtrFldDistance.reset();
+ m_xMtrFldTextStart.reset();
+ m_xTbxShadow.reset();
+ m_xFbShadowX.reset();
+ m_xMtrFldShadowX.reset();
+ m_xFbShadowY.reset();
+ m_xMtrFldShadowY.reset();
+ m_xShadowColorLB.reset();
+ SfxDockingWindow::dispose();
+}
+
+SfxChildAlignment SvxFontWorkDialog::CheckAlignment( SfxChildAlignment eActAlign,
+ SfxChildAlignment eAlign )
+{
+ SfxChildAlignment eAlignment;
+
+ switch ( eAlign )
+ {
+ case SfxChildAlignment::TOP:
+ case SfxChildAlignment::HIGHESTTOP:
+ case SfxChildAlignment::LOWESTTOP:
+ case SfxChildAlignment::BOTTOM:
+ case SfxChildAlignment::LOWESTBOTTOM:
+ case SfxChildAlignment::HIGHESTBOTTOM:
+ {
+ eAlignment = eActAlign;
+ }
+ break;
+
+ case SfxChildAlignment::LEFT:
+ case SfxChildAlignment::RIGHT:
+ case SfxChildAlignment::FIRSTLEFT:
+ case SfxChildAlignment::LASTLEFT:
+ case SfxChildAlignment::FIRSTRIGHT:
+ case SfxChildAlignment::LASTRIGHT:
+ {
+ eAlignment = eAlign;
+ }
+ break;
+
+ default:
+ {
+ eAlignment = eAlign;
+ }
+ break;
+ }
+
+ return eAlignment;
+}
+
+// Set style buttons
+void SvxFontWorkDialog::SetStyle_Impl(const XFormTextStyleItem* pItem)
+{
+ if ( pItem )
+ {
+ OString sId = "off";
+
+ switch ( pItem->GetValue() )
+ {
+ case XFormTextStyle::Rotate : sId = "rotate"; break;
+ case XFormTextStyle::Upright: sId = "upright"; break;
+ case XFormTextStyle::SlantX : sId = "hori"; break;
+ case XFormTextStyle::SlantY : sId = "vert"; break;
+ default: ;//prevent warning
+ }
+ m_xTbxStyle->set_sensitive(true);
+
+ // Make sure that there is always exactly one checked toolbox item.
+ if ( pItem->GetValue() == XFormTextStyle::NONE )
+ {
+ m_xTbxStyle->set_item_active("rotate", false);
+ m_xTbxStyle->set_item_active("upright", false);
+ m_xTbxStyle->set_item_active("hori", false);
+ m_xTbxStyle->set_item_active("vert", false);
+
+ m_xTbxStyle->set_item_active("off", true);
+ }
+ else
+ {
+ m_xTbxStyle->set_item_active("off", false);
+ m_xTbxStyle->set_item_active(sId, true);
+ }
+
+ m_sLastStyleTbxId = sId;
+ }
+ else
+ m_xTbxStyle->set_sensitive(false);
+}
+
+// Set adjust buttons
+
+void SvxFontWorkDialog::SetAdjust_Impl(const XFormTextAdjustItem* pItem)
+{
+ if ( pItem )
+ {
+ OString sId;
+
+ m_xTbxAdjust->set_sensitive(true);
+ m_xMtrFldDistance->set_sensitive(true);
+
+ if ( pItem->GetValue() == XFormTextAdjust::Left || pItem->GetValue() == XFormTextAdjust::Right )
+ {
+ if (pItem->GetValue() == XFormTextAdjust::Left)
+ sId = "left";
+ else
+ sId = "right";
+ m_xMtrFldTextStart->set_sensitive(true);
+ }
+ else
+ {
+ if (pItem->GetValue() == XFormTextAdjust::Center)
+ sId = "center";
+ else
+ sId = "autosize";
+ m_xMtrFldTextStart->set_sensitive(false);
+ }
+
+ if (!m_xTbxAdjust->get_item_active(sId))
+ m_xTbxAdjust->set_item_active(sId, true);
+
+ m_sLastAdjustTbxId = sId;
+ }
+ else
+ {
+ m_xTbxAdjust->set_sensitive(false);
+ m_xMtrFldTextStart->set_sensitive(false);
+ m_xMtrFldDistance->set_sensitive(false);
+ }
+}
+
+// Enter Distance value in the edit field
+
+void SvxFontWorkDialog::SetDistance_Impl(const XFormTextDistanceItem* pItem)
+{
+ if (pItem && !m_xMtrFldDistance->has_focus())
+ {
+ SetMetricValue(*m_xMtrFldDistance, pItem->GetValue(), MapUnit::Map100thMM);
+ }
+}
+
+// Enter indent value in the edit field
+
+void SvxFontWorkDialog::SetStart_Impl(const XFormTextStartItem* pItem)
+{
+ if (pItem && !m_xMtrFldTextStart->has_focus())
+ {
+ SetMetricValue(*m_xMtrFldTextStart, pItem->GetValue(), MapUnit::Map100thMM);
+ }
+}
+
+// Set button for reversing the direction of text
+
+void SvxFontWorkDialog::SetMirror_Impl(const XFormTextMirrorItem* pItem)
+{
+ if ( pItem )
+ m_xTbxAdjust->set_item_active("orientation", pItem->GetValue());
+}
+
+// Set button for contour display
+
+void SvxFontWorkDialog::SetShowForm_Impl(const XFormTextHideFormItem* pItem)
+{
+ if ( pItem )
+ m_xTbxShadow->set_item_active("contour", !pItem->GetValue());
+}
+
+// Set button for text border
+
+void SvxFontWorkDialog::SetOutline_Impl(const XFormTextOutlineItem* pItem)
+{
+ if ( pItem )
+ m_xTbxShadow->set_item_active("textcontour", pItem->GetValue());
+}
+
+// Set shadow buttons
+
+void SvxFontWorkDialog::SetShadow_Impl(const XFormTextShadowItem* pItem,
+ bool bRestoreValues)
+{
+ if ( pItem )
+ {
+ OString sId;
+
+ m_xTbxShadow->set_sensitive(true);
+
+ if ( pItem->GetValue() == XFormTextShadow::NONE )
+ {
+ sId = "noshadow";
+ m_xFbShadowX->hide();
+ m_xFbShadowY->hide();
+ m_xMtrFldShadowX->set_sensitive(false);
+ m_xMtrFldShadowY->set_sensitive(false);
+ m_xShadowColorLB->set_sensitive(false);
+ }
+ else
+ {
+ m_xFbShadowX->show();
+ m_xFbShadowY->show();
+ m_xMtrFldShadowX->set_sensitive(true);
+ m_xMtrFldShadowY->set_sensitive(true);
+ m_xShadowColorLB->set_sensitive(true);
+
+ if ( pItem->GetValue() == XFormTextShadow::Normal )
+ {
+ sId = "vertical";
+ const FieldUnit eDlgUnit = rBindings.GetDispatcher()->GetModule()->GetFieldUnit();
+
+ m_xMtrFldShadowX->set_unit( eDlgUnit );
+ m_xMtrFldShadowX->set_digits(2);
+ m_xMtrFldShadowX->set_range(INT_MIN, INT_MAX, FieldUnit::NONE);
+ if( eDlgUnit == FieldUnit::MM )
+ m_xMtrFldShadowX->set_increments(50, 500, FieldUnit::NONE);
+ else
+ m_xMtrFldShadowX->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowX->set_width_chars(WIDTH_CHARS);
+
+ m_xMtrFldShadowY->set_unit( eDlgUnit );
+ m_xMtrFldShadowY->set_digits(2);
+ m_xMtrFldShadowY->set_range(INT_MIN, INT_MAX, FieldUnit::NONE);
+ if( eDlgUnit == FieldUnit::MM )
+ m_xMtrFldShadowY->set_increments(50, 500, FieldUnit::NONE);
+ else
+ m_xMtrFldShadowY->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_width_chars(WIDTH_CHARS);
+
+ if ( bRestoreValues )
+ {
+ SetMetricValue(*m_xMtrFldShadowX, nSaveShadowX, MapUnit::Map100thMM);
+ SetMetricValue(*m_xMtrFldShadowY, nSaveShadowY, MapUnit::Map100thMM);
+
+ XFormTextShadowXValItem aXItem( nSaveShadowX );
+ XFormTextShadowYValItem aYItem( nSaveShadowY );
+
+ GetBindings().GetDispatcher()->ExecuteList(
+ SID_FORMTEXT_SHDWXVAL, SfxCallMode::RECORD,
+ { &aXItem, &aYItem });
+ }
+ }
+ else
+ {
+ sId = "slant";
+
+ m_xMtrFldShadowX->set_unit(FieldUnit::DEGREE);
+ m_xMtrFldShadowX->set_digits(1);
+ m_xMtrFldShadowX->set_range(-1800, 1800, FieldUnit::NONE);
+ m_xMtrFldShadowX->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowX->set_width_chars(WIDTH_CHARS);
+
+ m_xMtrFldShadowY->set_unit(FieldUnit::PERCENT);
+ m_xMtrFldShadowY->set_digits(0);
+ m_xMtrFldShadowY->set_range(-999, 999, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_width_chars(WIDTH_CHARS);
+
+ if ( bRestoreValues )
+ {
+ m_xMtrFldShadowX->set_value(nSaveShadowAngle, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_value(nSaveShadowSize, FieldUnit::NONE);
+ XFormTextShadowXValItem aXItem(nSaveShadowAngle);
+ XFormTextShadowYValItem aYItem(nSaveShadowSize);
+ GetBindings().GetDispatcher()->ExecuteList(
+ SID_FORMTEXT_SHDWXVAL, SfxCallMode::RECORD,
+ { &aXItem, &aYItem });
+ }
+ }
+ }
+
+ if (!m_xTbxShadow->get_item_active(sId))
+ m_xTbxShadow->set_item_active(sId, true);
+ m_sLastShadowTbxId = sId;
+
+ ApplyImageList();
+ }
+ else
+ {
+ m_xTbxShadow->set_sensitive(false);
+ m_xMtrFldShadowX->set_sensitive(false);
+ m_xMtrFldShadowY->set_sensitive(false);
+ m_xShadowColorLB->set_sensitive(false);
+ }
+}
+
+// Insert shadow color in listbox
+
+void SvxFontWorkDialog::SetShadowColor_Impl(const XFormTextShadowColorItem* pItem)
+{
+ if ( pItem )
+ m_xShadowColorLB->SelectEntry(pItem->GetColorValue());
+}
+
+// Enter X-value for shadow in edit field
+void SvxFontWorkDialog::SetShadowXVal_Impl(const XFormTextShadowXValItem* pItem)
+{
+ if (!pItem || m_xMtrFldShadowX->has_focus())
+ return;
+
+ // #i19251#
+ // sal_Int32 nValue = pItem->GetValue();
+
+ // #i19251#
+ // The two involved fields/items are used double and contain/give different
+ // values regarding to the access method. Thus, here we need to separate the access
+ // methods regarding to the kind of value accessed.
+ if (m_xTbxShadow->get_item_active("slant"))
+ {
+ // #i19251#
+ // There is no value correction necessary at all, i think this
+ // was only tried to be done without understanding that the two
+ // involved fields/items are used double and contain/give different
+ // values regarding to the access method.
+ // nValue = nValue - ( int( float( nValue ) / 360.0 ) * 360 );
+ m_xMtrFldShadowX->set_value(pItem->GetValue(), FieldUnit::NONE);
+ }
+ else
+ {
+ SetMetricValue(*m_xMtrFldShadowX, pItem->GetValue(), MapUnit::Map100thMM);
+ }
+}
+
+// Enter Y-value for shadow in edit field
+void SvxFontWorkDialog::SetShadowYVal_Impl(const XFormTextShadowYValItem* pItem)
+{
+ if (!pItem || m_xMtrFldShadowY->has_focus())
+ return;
+
+ // #i19251#
+ // The two involved fields/items are used double and contain/give different
+ // values regarding to the access method. Thus, here we need to separate the access
+ // methods regarding to the kind of value accessed.
+ if (m_xTbxShadow->get_item_active("slant"))
+ {
+ m_xMtrFldShadowY->set_value(pItem->GetValue(), FieldUnit::NONE);
+ }
+ else
+ {
+ SetMetricValue(*m_xMtrFldShadowY, pItem->GetValue(), MapUnit::Map100thMM);
+ }
+}
+
+IMPL_LINK(SvxFontWorkDialog, SelectStyleHdl_Impl, const OString&, rId, void)
+{
+ // Execute this block when a different toolbox item has been clicked or
+ // when the off item has been clicked. The later is necessary to
+ // override the toolbox behaviour of unchecking the item after second
+ // click on it: One of the items has to be checked at all times (when
+ // enabled that is.)
+ if (rId != "off" && rId == m_sLastStyleTbxId)
+ return;
+
+ XFormTextStyle eStyle = XFormTextStyle::NONE;
+
+ if (rId == "rotate")
+ eStyle = XFormTextStyle::Rotate;
+ else if (rId == "upright")
+ eStyle = XFormTextStyle::Upright;
+ else if (rId == "hori")
+ eStyle = XFormTextStyle::SlantX;
+ else if (rId == "vert")
+ eStyle = XFormTextStyle::SlantY;
+
+ XFormTextStyleItem aItem( eStyle );
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_STYLE,
+ SfxCallMode::RECORD, { &aItem });
+ SetStyle_Impl( &aItem );
+ m_sLastStyleTbxId = rId;
+}
+
+IMPL_LINK(SvxFontWorkDialog, SelectAdjustHdl_Impl, const OString&, rId, void)
+{
+ if (rId == "orientation")
+ {
+ XFormTextMirrorItem aItem(m_xTbxAdjust->get_item_active(rId));
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_MIRROR,
+ SfxCallMode::SLOT, { &aItem });
+ }
+ else if (rId != m_sLastAdjustTbxId)
+ {
+ XFormTextAdjust eAdjust = XFormTextAdjust::AutoSize;
+
+ if (rId == "left")
+ eAdjust = XFormTextAdjust::Left;
+ else if (rId == "center")
+ eAdjust = XFormTextAdjust::Center;
+ else if (rId == "right")
+ eAdjust = XFormTextAdjust::Right;
+
+ XFormTextAdjustItem aItem(eAdjust);
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_ADJUST,
+ SfxCallMode::RECORD, { &aItem });
+ SetAdjust_Impl(&aItem);
+ m_sLastAdjustTbxId = rId;
+ }
+}
+
+IMPL_LINK(SvxFontWorkDialog, SelectShadowHdl_Impl, const OString&, rId, void)
+{
+ if (rId == "contour")
+ {
+ XFormTextHideFormItem aItem(!m_xTbxShadow->get_item_active(rId));
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_HIDEFORM,
+ SfxCallMode::RECORD, { &aItem });
+ }
+ else if (rId == "textcontour")
+ {
+ XFormTextOutlineItem aItem(m_xTbxShadow->get_item_active(rId));
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_OUTLINE,
+ SfxCallMode::RECORD, { &aItem });
+ }
+ else if (rId != m_sLastShadowTbxId)
+ {
+ XFormTextShadow eShadow = XFormTextShadow::NONE;
+
+ if (m_sLastShadowTbxId == "vertical")
+ {
+ nSaveShadowX = GetCoreValue(*m_xMtrFldShadowX, MapUnit::Map100thMM);
+ nSaveShadowY = GetCoreValue(*m_xMtrFldShadowY, MapUnit::Map100thMM);
+ }
+ else if (m_sLastShadowTbxId == "slant")
+ {
+ nSaveShadowAngle = m_xMtrFldShadowX->get_value(FieldUnit::NONE);
+ nSaveShadowSize = m_xMtrFldShadowY->get_value(FieldUnit::NONE);
+ }
+ m_sLastShadowTbxId = rId;
+
+ if ( rId == "vertical") eShadow = XFormTextShadow::Normal;
+ else if (rId == "slant") eShadow = XFormTextShadow::Slant;
+
+ XFormTextShadowItem aItem(eShadow);
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_SHADOW,
+ SfxCallMode::RECORD, { &aItem });
+ SetShadow_Impl(&aItem, true);
+ }
+}
+
+IMPL_LINK_NOARG(SvxFontWorkDialog, ModifyInputHdl_Impl, weld::MetricSpinButton&, void)
+{
+ aInputIdle.Start();
+}
+
+IMPL_LINK_NOARG(SvxFontWorkDialog, InputTimeoutHdl_Impl, Timer*, void)
+{
+ // Possibly set the Metric system again. This should be done with a
+ // listen, this is however not possible at the moment due to compatibility
+ // issues.
+ const FieldUnit eDlgUnit = rBindings.GetDispatcher()->GetModule()->GetFieldUnit();
+ if( eDlgUnit != m_xMtrFldDistance->get_unit() )
+ {
+ SetFieldUnit(*m_xMtrFldDistance, eDlgUnit, true);
+ SetFieldUnit(*m_xMtrFldTextStart, eDlgUnit, true);
+ if (eDlgUnit == FieldUnit::MM)
+ {
+ m_xMtrFldDistance->set_increments(50, 500, FieldUnit::NONE);
+ m_xMtrFldTextStart->set_increments(50, 500, FieldUnit::NONE);
+ }
+ else
+ {
+ m_xMtrFldDistance->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldTextStart->set_increments(10, 100, FieldUnit::NONE);
+ }
+ }
+ if( eDlgUnit != m_xMtrFldShadowX->get_unit() &&
+ m_xTbxShadow->get_item_active("vertical") )
+ {
+ SetFieldUnit(*m_xMtrFldShadowX, eDlgUnit, true);
+ SetFieldUnit(*m_xMtrFldShadowY, eDlgUnit, true);
+
+ if (eDlgUnit == FieldUnit::MM)
+ {
+ m_xMtrFldShadowX->set_increments(50, 500, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_increments(50, 500, FieldUnit::NONE);
+ }
+ else
+ {
+ m_xMtrFldShadowX->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_increments(10, 100, FieldUnit::NONE);
+ }
+ }
+
+ tools::Long nValue = GetCoreValue(*m_xMtrFldDistance, MapUnit::Map100thMM);
+ XFormTextDistanceItem aDistItem( nValue );
+ nValue = GetCoreValue(*m_xMtrFldTextStart, MapUnit::Map100thMM);
+ XFormTextStartItem aStartItem( nValue );
+
+ sal_Int32 nValueX(0);
+ sal_Int32 nValueY(0);
+
+ // #i19251#
+ // The two involved fields/items are used double and contain/give different
+ // values regarding to the access method. Thus, here we need to separate the access
+ // method regarding to the kind of value accessed.
+ if (m_sLastShadowTbxId == "vertical")
+ {
+ nValueX = GetCoreValue(*m_xMtrFldShadowX, MapUnit::Map100thMM);
+ nValueY = GetCoreValue(*m_xMtrFldShadowY, MapUnit::Map100thMM);
+ }
+ else if (m_sLastShadowTbxId == "slant")
+ {
+ nValueX = m_xMtrFldShadowX->get_value(FieldUnit::NONE);
+ nValueY = m_xMtrFldShadowY->get_value(FieldUnit::NONE);
+ }
+
+ XFormTextShadowXValItem aShadowXItem( nValueX );
+ XFormTextShadowYValItem aShadowYItem( nValueY );
+
+ // Slot-ID does not matter, the Exec method evaluates the entire item set
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_DISTANCE,
+ SfxCallMode::RECORD,
+ { &aDistItem, &aStartItem, &aShadowXItem, &aShadowYItem });
+}
+
+IMPL_LINK_NOARG(SvxFontWorkDialog, ColorSelectHdl_Impl, ColorListBox&, void)
+{
+ XFormTextShadowColorItem aItem( "", m_xShadowColorLB->GetSelectEntryColor() );
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_SHDWCOLOR,
+ SfxCallMode::RECORD, { &aItem });
+}
+
+void SvxFontWorkDialog::ApplyImageList()
+{
+ if (m_sLastShadowTbxId == "slant")
+ {
+ m_xFbShadowX->set_from_icon_name(RID_SVXBMP_SHADOW_ANGLE);
+ m_xFbShadowY->set_from_icon_name(RID_SVXBMP_SHADOW_SIZE);
+ }
+ else
+ {
+ m_xFbShadowX->set_from_icon_name(RID_SVXBMP_SHADOW_XDIST);
+ m_xFbShadowY->set_from_icon_name(RID_SVXBMP_SHADOW_YDIST);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
new file mode 100644
index 000000000..77098bd3e
--- /dev/null
+++ b/svx/source/dialog/framelink.cxx
@@ -0,0 +1,320 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <rtl/math.hxx>
+#include <svx/framelink.hxx>
+
+#include <editeng/borderline.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace editeng;
+
+namespace svx::frame
+{
+
+Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale )
+{
+ Clear();
+ mnType = nType;
+ mfPatternScale = fScale;
+ Set( nP, nD, nS );
+}
+
+Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale )
+{
+ Clear();
+ mnType = nType;
+ mfPatternScale = fScale;
+ Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS );
+}
+
+Style::Style( const editeng::SvxBorderLine* pBorder, double fScale )
+{
+ Clear();
+ if(nullptr != pBorder)
+ {
+ mfPatternScale = fScale;
+ Set( pBorder, fScale );
+ }
+}
+
+void Style::Clear()
+{
+ maColorPrim = Color();
+ maColorSecn = Color();
+ maColorGap = Color();
+ mbUseGapColor = false;
+ meRefMode = RefMode::Centered;
+ mfPrim = 0.0;
+ mfDist = 0.0;
+ mfSecn = 0.0;
+ mfPatternScale = 1.0;
+ mnType = SvxBorderLineStyle::SOLID;
+ mbWordTableCell = false;
+}
+
+void Style::Set( double nP, double nD, double nS )
+{
+ /* nP nD nS -> mfPrim mfDist mfSecn
+ --------------------------------------
+ any any 0 nP 0 0
+ 0 any >0 nS 0 0
+ >0 0 >0 nP 0 0
+ >0 >0 >0 nP nD nS
+ */
+ mfPrim = rtl::math::round(nP ? nP : nS, 2);
+ mfDist = rtl::math::round((nP && nS) ? nD : 0, 2);
+ mfSecn = rtl::math::round((nP && nD) ? nS : 0, 2);
+}
+
+void Style::Set( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS )
+{
+ maColorPrim = rColorPrim;
+ maColorSecn = rColorSecn;
+ maColorGap = rColorGap;
+ mbUseGapColor = bUseGapColor;
+ Set( nP, nD, nS );
+}
+
+void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth )
+{
+ if(nullptr == pBorder)
+ {
+ Clear();
+ return;
+ }
+
+ maColorPrim = pBorder->GetColorOut();
+ maColorSecn = pBorder->GetColorIn();
+ maColorGap = pBorder->GetColorGap();
+ mbUseGapColor = pBorder->HasGapColor();
+
+ const sal_uInt16 nPrim(pBorder->GetOutWidth());
+ const sal_uInt16 nDist(pBorder->GetDistance());
+ const sal_uInt16 nSecn(pBorder->GetInWidth());
+
+ mnType = pBorder->GetBorderLineStyle();
+ mfPatternScale = fScale;
+
+ if( !nSecn ) // no or single frame border
+ {
+ Set( std::min<double>(nPrim * fScale, nMaxWidth), 0, 0 );
+ }
+ else
+ {
+ Set(std::min<double>(nPrim * fScale, nMaxWidth), std::min<double>(nDist * fScale, nMaxWidth), std::min<double>(nSecn * fScale, nMaxWidth));
+ // Enlarge the style if distance is too small due to rounding losses.
+ double nPixWidth = std::min<double>((nPrim + nDist + nSecn) * fScale, nMaxWidth);
+
+ if( nPixWidth > GetWidth() )
+ {
+ mfDist = nPixWidth - mfPrim - mfSecn;
+ }
+
+ // Shrink the style if it is too thick for the control.
+ while( GetWidth() > nMaxWidth )
+ {
+ // First decrease space between lines.
+ if (mfDist)
+ {
+ --mfDist;
+ continue;
+ }
+
+ // Still too thick? Decrease the line widths.
+ if (mfPrim != 0.0 && rtl::math::approxEqual(mfPrim, mfSecn))
+ {
+ // Both lines equal - decrease both to keep symmetry.
+ --mfPrim;
+ --mfSecn;
+ continue;
+ }
+
+ // Decrease each line for itself
+ if (mfPrim)
+ --mfPrim;
+
+ if ((GetWidth() > nMaxWidth) && mfSecn != 0.0)
+ --mfSecn;
+ }
+ }
+}
+
+Style& Style::MirrorSelf()
+{
+ if (mfSecn)
+ {
+ std::swap( mfPrim, mfSecn );
+ // also need to swap colors
+ std::swap( maColorPrim, maColorSecn );
+ }
+
+ if( meRefMode != RefMode::Centered )
+ {
+ meRefMode = (meRefMode == RefMode::Begin) ? RefMode::End : RefMode::Begin;
+ }
+
+ return *this;
+}
+
+bool Style::operator==( const Style& rOther) const
+{
+ return (Prim() == rOther.Prim()
+ && Dist() == rOther.Dist()
+ && Secn() == rOther.Secn()
+ && GetColorPrim() == rOther.GetColorPrim()
+ && GetColorSecn() == rOther.GetColorSecn()
+ && GetColorGap() == rOther.GetColorGap()
+ && GetRefMode() == rOther.GetRefMode()
+ && UseGapColor() == rOther.UseGapColor()
+ && Type() == rOther.Type());
+}
+
+namespace
+{
+/**
+ * Gets the weight of rStyle, according to [MS-OI29500] v20171130, 2.1.168 Part 1 Section 17.4.66,
+ * tcBorders (Table Cell Borders).
+ */
+double GetWordTableCellBorderWeight(const Style& rStyle)
+{
+ double fWidth = rStyle.GetWidth();
+ int nBorderNumber = 0;
+
+ // See lcl_convertBorderStyleFromToken() in writerfilter/ and ConvertBorderStyleFromWord() in
+ // editeng/, this is the opposite of the combination of those functions.
+ switch (rStyle.Type())
+ {
+ case SvxBorderLineStyle::NONE:
+ return 0.0;
+ case SvxBorderLineStyle::DOTTED:
+ case SvxBorderLineStyle::DASHED:
+ return 1.0;
+ case SvxBorderLineStyle::SOLID:
+ // single = 1
+ // thick = 2
+ // wave = 20
+ nBorderNumber = 1;
+ break;
+ case SvxBorderLineStyle::DOUBLE:
+ case SvxBorderLineStyle::DOUBLE_THIN:
+ // double = 3
+ // triple = 10
+ // doubleWave = 21
+ // dashDotStroked = 23
+ nBorderNumber = 3;
+ break;
+ case SvxBorderLineStyle::DASH_DOT:
+ // dotDash = 8
+ nBorderNumber = 8;
+ break;
+ case SvxBorderLineStyle::DASH_DOT_DOT:
+ // dotDotDash = 9
+ nBorderNumber = 9;
+ break;
+ case SvxBorderLineStyle::THINTHICK_SMALLGAP:
+ // thinThickSmallGap = 11
+ nBorderNumber = 11;
+ break;
+ case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
+ // thickThinSmallGap = 12
+ // thinThickThinSmallGap = 13
+ nBorderNumber = 12;
+ break;
+ case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
+ // thinThickMediumGap = 14
+ nBorderNumber = 14;
+ break;
+ case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
+ // thickThinMediumGap = 15
+ // thinThickThinMediumGap = 16
+ nBorderNumber = 15;
+ break;
+ case SvxBorderLineStyle::THINTHICK_LARGEGAP:
+ // thinThickLargeGap = 17
+ nBorderNumber = 17;
+ break;
+ case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
+ // thickThinLargeGap = 18
+ // thinThickThinLargeGap = 19
+ nBorderNumber = 18;
+ break;
+ case SvxBorderLineStyle::FINE_DASHED:
+ // dashSmallGap = 22
+ nBorderNumber = 22;
+ break;
+ case SvxBorderLineStyle::EMBOSSED:
+ // threeDEmboss = 24
+ nBorderNumber = 24;
+ break;
+ case SvxBorderLineStyle::ENGRAVED:
+ // threeDEngrave = 25
+ nBorderNumber = 25;
+ break;
+ case SvxBorderLineStyle::OUTSET:
+ // outset = 26
+ nBorderNumber = 25;
+ break;
+ case SvxBorderLineStyle::INSET:
+ // inset = 27
+ nBorderNumber = 27;
+ break;
+ }
+
+ return nBorderNumber * fWidth;
+}
+}
+
+bool Style::operator<( const Style& rOther) const
+{
+ if (mbWordTableCell)
+ {
+ // The below code would first compare based on the border width, Word compares based on its
+ // calculated weight, do that in the compat case.
+ double fLW = GetWordTableCellBorderWeight(*this);
+ double fRW = GetWordTableCellBorderWeight(rOther);
+ if (!rtl::math::approxEqual(fLW, fRW))
+ {
+ return fLW < fRW;
+ }
+ }
+
+ // different total widths -> this<rOther, if this is thinner
+ double nLW = GetWidth();
+ double nRW = rOther.GetWidth();
+ if( !rtl::math::approxEqual(nLW, nRW) ) return nLW < nRW;
+
+ // one line double, the other single -> this<rOther, if this is single
+ if( (Secn() == 0) != (rOther.Secn() == 0) ) return Secn() == 0;
+
+ // both lines double with different distances -> this<rOther, if distance of this greater
+ if( (Secn() && rOther.Secn()) && !rtl::math::approxEqual(Dist(), rOther.Dist()) ) return Dist() > rOther.Dist();
+
+ // both lines single and 1 unit thick, only one is dotted -> this<rOther, if this is dotted
+ if ((nLW == 1) && !Secn() && !rOther.Secn() && (Type() != rOther.Type())) return Type() > rOther.Type();
+
+ // seem to be equal
+ return false;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
new file mode 100644
index 000000000..aabce64ba
--- /dev/null
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -0,0 +1,1530 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/framelinkarray.hxx>
+
+#include <math.h>
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <tools/debug.hxx>
+#include <tools/gen.hxx>
+#include <vcl/canvastools.hxx>
+#include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+
+//#define OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
+#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#endif
+
+namespace svx::frame {
+
+namespace {
+
+class Cell
+{
+private:
+ Style maLeft;
+ Style maRight;
+ Style maTop;
+ Style maBottom;
+ Style maTLBR;
+ Style maBLTR;
+
+ basegfx::B2DHomMatrix HelperCreateB2DHomMatrixFromB2DRange(
+ const basegfx::B2DRange& rRange ) const;
+
+public:
+ sal_Int32 mnAddLeft;
+ sal_Int32 mnAddRight;
+ sal_Int32 mnAddTop;
+ sal_Int32 mnAddBottom;
+
+ SvxRotateMode meRotMode;
+ double mfOrientation;
+
+ bool mbMergeOrig;
+ bool mbOverlapX;
+ bool mbOverlapY;
+
+public:
+ explicit Cell();
+
+ void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; }
+ void SetStyleRight(const Style& rStyle) { maRight = rStyle; }
+ void SetStyleTop(const Style& rStyle) { maTop = rStyle; }
+ void SetStyleBottom(const Style& rStyle) { maBottom = rStyle; }
+ void SetStyleTLBR(const Style& rStyle) { maTLBR = rStyle; }
+ void SetStyleBLTR(const Style& rStyle) { maBLTR = rStyle; }
+
+ const Style& GetStyleLeft() const { return maLeft; }
+ const Style& GetStyleRight() const { return maRight; }
+ const Style& GetStyleTop() const { return maTop; }
+ const Style& GetStyleBottom() const { return maBottom; }
+ const Style& GetStyleTLBR() const { return maTLBR; }
+ const Style& GetStyleBLTR() const { return maBLTR; }
+
+ bool IsMerged() const { return mbMergeOrig || mbOverlapX || mbOverlapY; }
+ bool IsRotated() const { return mfOrientation != 0.0; }
+
+ void MirrorSelfX();
+
+ basegfx::B2DHomMatrix CreateCoordinateSystemSingleCell(
+ const Array& rArray, sal_Int32 nCol, sal_Int32 nRow ) const;
+ basegfx::B2DHomMatrix CreateCoordinateSystemMergedCell(
+ const Array& rArray, sal_Int32 nColLeft, sal_Int32 nRowTop, sal_Int32 nColRight, sal_Int32 nRowBottom ) const;
+};
+
+}
+
+typedef std::vector< Cell > CellVec;
+
+basegfx::B2DHomMatrix Cell::HelperCreateB2DHomMatrixFromB2DRange(
+ const basegfx::B2DRange& rRange ) const
+{
+ if( rRange.isEmpty() )
+ return basegfx::B2DHomMatrix();
+
+ basegfx::B2DPoint aOrigin(rRange.getMinimum());
+ basegfx::B2DVector aX(rRange.getWidth(), 0.0);
+ basegfx::B2DVector aY(0.0, rRange.getHeight());
+
+ if (IsRotated() && SvxRotateMode::SVX_ROTATE_MODE_STANDARD != meRotMode )
+ {
+ // when rotated, adapt values. Get Skew (cos/sin == 1/tan)
+ const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation)));
+
+ switch (meRotMode)
+ {
+ case SvxRotateMode::SVX_ROTATE_MODE_TOP:
+ // shear Y-Axis
+ aY.setX(-fSkew);
+ break;
+ case SvxRotateMode::SVX_ROTATE_MODE_CENTER:
+ // shear origin half, Y full
+ aOrigin.setX(aOrigin.getX() + (fSkew * 0.5));
+ aY.setX(-fSkew);
+ break;
+ case SvxRotateMode::SVX_ROTATE_MODE_BOTTOM:
+ // shear origin full, Y full
+ aOrigin.setX(aOrigin.getX() + fSkew);
+ aY.setX(-fSkew);
+ break;
+ default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above
+ break;
+ }
+ }
+
+ // use column vectors as coordinate axes, homogen column for translation
+ return basegfx::utils::createCoordinateSystemTransform( aOrigin, aX, aY );
+}
+
+basegfx::B2DHomMatrix Cell::CreateCoordinateSystemSingleCell(
+ const Array& rArray, sal_Int32 nCol, sal_Int32 nRow) const
+{
+ const Point aPoint( rArray.GetColPosition( nCol ), rArray.GetRowPosition( nRow ) );
+ const Size aSize( rArray.GetColWidth( nCol, nCol ) + 1, rArray.GetRowHeight( nRow, nRow ) + 1 );
+ const basegfx::B2DRange aRange( vcl::unotools::b2DRectangleFromRectangle( tools::Rectangle( aPoint, aSize ) ) );
+
+ return HelperCreateB2DHomMatrixFromB2DRange( aRange );
+}
+
+basegfx::B2DHomMatrix Cell::CreateCoordinateSystemMergedCell(
+ const Array& rArray, sal_Int32 nColLeft, sal_Int32 nRowTop, sal_Int32 nColRight, sal_Int32 nRowBottom) const
+{
+ basegfx::B2DRange aRange( rArray.GetB2DRange(
+ nColLeft, nRowTop, nColRight, nRowBottom ) );
+
+ // adjust rectangle for partly visible merged cells
+ if( IsMerged() )
+ {
+ // not *sure* what exactly this is good for,
+ // it is just a hard set extension at merged cells,
+ // probably *should* be included in the above extended
+ // GetColPosition/GetColWidth already. This might be
+ // added due to GetColPosition/GetColWidth not working
+ // correctly over PageChanges (if used), but not sure.
+ aRange.expand(
+ basegfx::B2DRange(
+ aRange.getMinX() - mnAddLeft,
+ aRange.getMinY() - mnAddTop,
+ aRange.getMaxX() + mnAddRight,
+ aRange.getMaxY() + mnAddBottom ) );
+ }
+
+ return HelperCreateB2DHomMatrixFromB2DRange( aRange );
+}
+
+Cell::Cell() :
+ mnAddLeft( 0 ),
+ mnAddRight( 0 ),
+ mnAddTop( 0 ),
+ mnAddBottom( 0 ),
+ meRotMode(SvxRotateMode::SVX_ROTATE_MODE_STANDARD ),
+ mfOrientation( 0.0 ),
+ mbMergeOrig( false ),
+ mbOverlapX( false ),
+ mbOverlapY( false )
+{
+}
+
+void Cell::MirrorSelfX()
+{
+ std::swap( maLeft, maRight );
+ std::swap( mnAddLeft, mnAddRight );
+ maLeft.MirrorSelf();
+ maRight.MirrorSelf();
+ mfOrientation = -mfOrientation;
+}
+
+
+static void lclRecalcCoordVec( std::vector<sal_Int32>& rCoords, const std::vector<sal_Int32>& rSizes )
+{
+ DBG_ASSERT( rCoords.size() == rSizes.size() + 1, "lclRecalcCoordVec - inconsistent vectors" );
+ auto aCIt = rCoords.begin();
+ for( const auto& rSize : rSizes )
+ {
+ *(aCIt + 1) = *aCIt + rSize;
+ ++aCIt;
+ }
+}
+
+static void lclSetMergedRange( CellVec& rCells, sal_Int32 nWidth, sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
+{
+ for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
+ {
+ for( sal_Int32 nRow = nFirstRow; nRow <= nLastRow; ++nRow )
+ {
+ Cell& rCell = rCells[ nRow * nWidth + nCol ];
+ rCell.mbMergeOrig = false;
+ rCell.mbOverlapX = nCol > nFirstCol;
+ rCell.mbOverlapY = nRow > nFirstRow;
+ }
+ }
+ rCells[ nFirstRow * nWidth + nFirstCol ].mbMergeOrig = true;
+}
+
+
+const Style OBJ_STYLE_NONE;
+const Cell OBJ_CELL_NONE;
+
+struct ArrayImpl
+{
+ CellVec maCells;
+ std::vector<sal_Int32> maWidths;
+ std::vector<sal_Int32> maHeights;
+ mutable std::vector<sal_Int32> maXCoords;
+ mutable std::vector<sal_Int32> maYCoords;
+ sal_Int32 mnWidth;
+ sal_Int32 mnHeight;
+ sal_Int32 mnFirstClipCol;
+ sal_Int32 mnFirstClipRow;
+ sal_Int32 mnLastClipCol;
+ sal_Int32 mnLastClipRow;
+ mutable bool mbXCoordsDirty;
+ mutable bool mbYCoordsDirty;
+ bool mbMayHaveCellRotation;
+
+ explicit ArrayImpl( sal_Int32 nWidth, sal_Int32 nHeight );
+
+ bool IsValidPos( sal_Int32 nCol, sal_Int32 nRow ) const
+ { return (nCol < mnWidth) && (nRow < mnHeight); }
+ sal_Int32 GetIndex( sal_Int32 nCol, sal_Int32 nRow ) const
+ { return nRow * mnWidth + nCol; }
+
+ const Cell& GetCell( sal_Int32 nCol, sal_Int32 nRow ) const;
+ Cell& GetCellAcc( sal_Int32 nCol, sal_Int32 nRow );
+
+ sal_Int32 GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const;
+ sal_Int32 GetMergedFirstRow( sal_Int32 nCol, sal_Int32 nRow ) const;
+ sal_Int32 GetMergedLastCol( sal_Int32 nCol, sal_Int32 nRow ) const;
+ sal_Int32 GetMergedLastRow( sal_Int32 nCol, sal_Int32 nRow ) const;
+
+ const Cell& GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const;
+ const Cell& GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const;
+
+ bool IsMergedOverlappedLeft( sal_Int32 nCol, sal_Int32 nRow ) const;
+ bool IsMergedOverlappedRight( sal_Int32 nCol, sal_Int32 nRow ) const;
+ bool IsMergedOverlappedTop( sal_Int32 nCol, sal_Int32 nRow ) const;
+ bool IsMergedOverlappedBottom( sal_Int32 nCol, sal_Int32 nRow ) const;
+
+ bool IsInClipRange( sal_Int32 nCol, sal_Int32 nRow ) const;
+ bool IsColInClipRange( sal_Int32 nCol ) const;
+ bool IsRowInClipRange( sal_Int32 nRow ) const;
+
+ bool OverlapsClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow ) const;
+
+ sal_Int32 GetMirrorCol( sal_Int32 nCol ) const { return mnWidth - nCol - 1; }
+
+ sal_Int32 GetColPosition( sal_Int32 nCol ) const;
+ sal_Int32 GetRowPosition( sal_Int32 nRow ) const;
+
+ bool HasCellRotation() const;
+};
+
+ArrayImpl::ArrayImpl( sal_Int32 nWidth, sal_Int32 nHeight ) :
+ mnWidth( nWidth ),
+ mnHeight( nHeight ),
+ mnFirstClipCol( 0 ),
+ mnFirstClipRow( 0 ),
+ mnLastClipCol( nWidth - 1 ),
+ mnLastClipRow( nHeight - 1 ),
+ mbXCoordsDirty( false ),
+ mbYCoordsDirty( false ),
+ mbMayHaveCellRotation( false )
+{
+ // default-construct all vectors
+ maCells.resize( mnWidth * mnHeight );
+ maWidths.resize( mnWidth, 0 );
+ maHeights.resize( mnHeight, 0 );
+ maXCoords.resize( mnWidth + 1, 0 );
+ maYCoords.resize( mnHeight + 1, 0 );
+}
+
+const Cell& ArrayImpl::GetCell( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : OBJ_CELL_NONE;
+}
+
+Cell& ArrayImpl::GetCellAcc( sal_Int32 nCol, sal_Int32 nRow )
+{
+ static Cell aDummy;
+ return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : aDummy;
+}
+
+sal_Int32 ArrayImpl::GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ sal_Int32 nFirstCol = nCol;
+ while( (nFirstCol > 0) && GetCell( nFirstCol, nRow ).mbOverlapX ) --nFirstCol;
+ return nFirstCol;
+}
+
+sal_Int32 ArrayImpl::GetMergedFirstRow( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ sal_Int32 nFirstRow = nRow;
+ while( (nFirstRow > 0) && GetCell( nCol, nFirstRow ).mbOverlapY ) --nFirstRow;
+ return nFirstRow;
+}
+
+sal_Int32 ArrayImpl::GetMergedLastCol( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ sal_Int32 nLastCol = nCol + 1;
+ while( (nLastCol < mnWidth) && GetCell( nLastCol, nRow ).mbOverlapX ) ++nLastCol;
+ return nLastCol - 1;
+}
+
+sal_Int32 ArrayImpl::GetMergedLastRow( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ sal_Int32 nLastRow = nRow + 1;
+ while( (nLastRow < mnHeight) && GetCell( nCol, nLastRow ).mbOverlapY ) ++nLastRow;
+ return nLastRow - 1;
+}
+
+const Cell& ArrayImpl::GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return GetCell( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) );
+}
+
+const Cell& ArrayImpl::GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return GetCell( GetMergedLastCol( nCol, nRow ), GetMergedLastRow( nCol, nRow ) );
+}
+
+bool ArrayImpl::IsMergedOverlappedLeft( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ const Cell& rCell = GetCell( nCol, nRow );
+ return rCell.mbOverlapX || (rCell.mnAddLeft > 0);
+}
+
+bool ArrayImpl::IsMergedOverlappedRight( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return GetCell( nCol + 1, nRow ).mbOverlapX || (GetCell( nCol, nRow ).mnAddRight > 0);
+}
+
+bool ArrayImpl::IsMergedOverlappedTop( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ const Cell& rCell = GetCell( nCol, nRow );
+ return rCell.mbOverlapY || (rCell.mnAddTop > 0);
+}
+
+bool ArrayImpl::IsMergedOverlappedBottom( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return GetCell( nCol, nRow + 1 ).mbOverlapY || (GetCell( nCol, nRow ).mnAddBottom > 0);
+}
+
+bool ArrayImpl::IsColInClipRange( sal_Int32 nCol ) const
+{
+ return (mnFirstClipCol <= nCol) && (nCol <= mnLastClipCol);
+}
+
+bool ArrayImpl::IsRowInClipRange( sal_Int32 nRow ) const
+{
+ return (mnFirstClipRow <= nRow) && (nRow <= mnLastClipRow);
+}
+
+bool ArrayImpl::OverlapsClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow ) const
+{
+ if(nLastCol < mnFirstClipCol)
+ return false;
+
+ if(nFirstCol > mnLastClipCol)
+ return false;
+
+ if(nLastRow < mnFirstClipRow)
+ return false;
+
+ if(nFirstRow > mnLastClipRow)
+ return false;
+
+ return true;
+}
+
+bool ArrayImpl::IsInClipRange( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return IsColInClipRange( nCol ) && IsRowInClipRange( nRow );
+}
+
+sal_Int32 ArrayImpl::GetColPosition( sal_Int32 nCol ) const
+{
+ if( mbXCoordsDirty )
+ {
+ lclRecalcCoordVec( maXCoords, maWidths );
+ mbXCoordsDirty = false;
+ }
+ return maXCoords[ nCol ];
+}
+
+sal_Int32 ArrayImpl::GetRowPosition( sal_Int32 nRow ) const
+{
+ if( mbYCoordsDirty )
+ {
+ lclRecalcCoordVec( maYCoords, maHeights );
+ mbYCoordsDirty = false;
+ }
+ return maYCoords[ nRow ];
+}
+
+bool ArrayImpl::HasCellRotation() const
+{
+ // check cell array
+ for (const auto& aCell : maCells)
+ {
+ if (aCell.IsRotated())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+namespace {
+
+class MergedCellIterator
+{
+public:
+ explicit MergedCellIterator( const Array& rArray, sal_Int32 nCol, sal_Int32 nRow );
+
+ bool Is() const { return (mnCol <= mnLastCol) && (mnRow <= mnLastRow); }
+ sal_Int32 Col() const { return mnCol; }
+ sal_Int32 Row() const { return mnRow; }
+
+ MergedCellIterator& operator++();
+
+private:
+ sal_Int32 mnFirstCol;
+ sal_Int32 mnFirstRow;
+ sal_Int32 mnLastCol;
+ sal_Int32 mnLastRow;
+ sal_Int32 mnCol;
+ sal_Int32 mnRow;
+};
+
+}
+
+MergedCellIterator::MergedCellIterator( const Array& rArray, sal_Int32 nCol, sal_Int32 nRow )
+{
+ DBG_ASSERT( rArray.IsMerged( nCol, nRow ), "svx::frame::MergedCellIterator::MergedCellIterator - not in merged range" );
+ rArray.GetMergedRange( mnFirstCol, mnFirstRow, mnLastCol, mnLastRow, nCol, nRow );
+ mnCol = mnFirstCol;
+ mnRow = mnFirstRow;
+}
+
+MergedCellIterator& MergedCellIterator::operator++()
+{
+ DBG_ASSERT( Is(), "svx::frame::MergedCellIterator::operator++() - already invalid" );
+ if( ++mnCol > mnLastCol )
+ {
+ mnCol = mnFirstCol;
+ ++mnRow;
+ }
+ return *this;
+}
+
+
+#define DBG_FRAME_CHECK( cond, funcname, error ) DBG_ASSERT( cond, "svx::frame::Array::" funcname " - " error )
+#define DBG_FRAME_CHECK_COL( col, funcname ) DBG_FRAME_CHECK( (col) < GetColCount(), funcname, "invalid column index" )
+#define DBG_FRAME_CHECK_ROW( row, funcname ) DBG_FRAME_CHECK( (row) < GetRowCount(), funcname, "invalid row index" )
+#define DBG_FRAME_CHECK_COLROW( col, row, funcname ) DBG_FRAME_CHECK( ((col) < GetColCount()) && ((row) < GetRowCount()), funcname, "invalid cell index" )
+#define DBG_FRAME_CHECK_COL_1( col, funcname ) DBG_FRAME_CHECK( (col) <= GetColCount(), funcname, "invalid column index" )
+#define DBG_FRAME_CHECK_ROW_1( row, funcname ) DBG_FRAME_CHECK( (row) <= GetRowCount(), funcname, "invalid row index" )
+
+
+#define CELL( col, row ) mxImpl->GetCell( col, row )
+#define CELLACC( col, row ) mxImpl->GetCellAcc( col, row )
+#define ORIGCELL( col, row ) mxImpl->GetMergedOriginCell( col, row )
+#define LASTCELL( col, row ) mxImpl->GetMergedLastCell( col, row )
+
+
+Array::Array()
+{
+ Initialize( 0, 0 );
+}
+
+Array::~Array()
+{
+}
+
+// array size and column/row indexes
+void Array::Initialize( sal_Int32 nWidth, sal_Int32 nHeight )
+{
+ mxImpl.reset( new ArrayImpl( nWidth, nHeight ) );
+}
+
+sal_Int32 Array::GetColCount() const
+{
+ return mxImpl->mnWidth;
+}
+
+sal_Int32 Array::GetRowCount() const
+{
+ return mxImpl->mnHeight;
+}
+
+sal_Int32 Array::GetCellCount() const
+{
+ return mxImpl->maCells.size();
+}
+
+sal_Int32 Array::GetCellIndex( sal_Int32 nCol, sal_Int32 nRow, bool bRTL ) const
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetCellIndex" );
+ if (bRTL)
+ nCol = mxImpl->GetMirrorCol(nCol);
+ return mxImpl->GetIndex( nCol, nRow );
+}
+
+// cell border styles
+void Array::SetCellStyleLeft( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleLeft" );
+ CELLACC( nCol, nRow ).SetStyleLeft(rStyle);
+}
+
+void Array::SetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleRight" );
+ CELLACC( nCol, nRow ).SetStyleRight(rStyle);
+}
+
+void Array::SetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTop" );
+ CELLACC( nCol, nRow ).SetStyleTop(rStyle);
+}
+
+void Array::SetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBottom" );
+ CELLACC( nCol, nRow ).SetStyleBottom(rStyle);
+}
+
+void Array::SetCellStyleTLBR( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTLBR" );
+ CELLACC( nCol, nRow ).SetStyleTLBR(rStyle);
+}
+
+void Array::SetCellStyleBLTR( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBLTR" );
+ CELLACC( nCol, nRow ).SetStyleBLTR(rStyle);
+}
+
+void Array::SetCellStyleDiag( sal_Int32 nCol, sal_Int32 nRow, const Style& rTLBR, const Style& rBLTR )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleDiag" );
+ Cell& rCell = CELLACC( nCol, nRow );
+ rCell.SetStyleTLBR(rTLBR);
+ rCell.SetStyleBLTR(rBLTR);
+}
+
+void Array::SetColumnStyleLeft( sal_Int32 nCol, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleLeft" );
+ for( sal_Int32 nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
+ SetCellStyleLeft( nCol, nRow, rStyle );
+}
+
+void Array::SetColumnStyleRight( sal_Int32 nCol, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleRight" );
+ for( sal_Int32 nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
+ SetCellStyleRight( nCol, nRow, rStyle );
+}
+
+void Array::SetRowStyleTop( sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleTop" );
+ for( sal_Int32 nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
+ SetCellStyleTop( nCol, nRow, rStyle );
+}
+
+void Array::SetRowStyleBottom( sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleBottom" );
+ for( sal_Int32 nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
+ SetCellStyleBottom( nCol, nRow, rStyle );
+}
+
+void Array::SetCellRotation(sal_Int32 nCol, sal_Int32 nRow, SvxRotateMode eRotMode, double fOrientation)
+{
+ DBG_FRAME_CHECK_COLROW(nCol, nRow, "SetCellRotation");
+ Cell& rTarget = CELLACC(nCol, nRow);
+ rTarget.meRotMode = eRotMode;
+ rTarget.mfOrientation = fOrientation;
+
+ if (!mxImpl->mbMayHaveCellRotation)
+ {
+ // activate once when a cell gets actually rotated to allow fast
+ // answering HasCellRotation() calls
+ mxImpl->mbMayHaveCellRotation = rTarget.IsRotated();
+ }
+}
+
+bool Array::HasCellRotation() const
+{
+ if (!mxImpl->mbMayHaveCellRotation)
+ {
+ // never set, no need to check
+ return false;
+ }
+
+ return mxImpl->HasCellRotation();
+}
+
+const Style& Array::GetCellStyleLeft( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // outside clipping rows or overlapped in merged cells: invisible
+ if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedLeft( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // left clipping border: always own left style
+ if( nCol == mxImpl->mnFirstClipCol )
+ return ORIGCELL( nCol, nRow ).GetStyleLeft();
+ // right clipping border: always right style of left neighbor cell
+ if( nCol == mxImpl->mnLastClipCol + 1 )
+ return ORIGCELL( nCol - 1, nRow ).GetStyleRight();
+ // outside clipping columns: invisible
+ if( !mxImpl->IsColInClipRange( nCol ) )
+ return OBJ_STYLE_NONE;
+ // inside clipping range: maximum of own left style and right style of left neighbor cell
+ return std::max( ORIGCELL( nCol, nRow ).GetStyleLeft(), ORIGCELL( nCol - 1, nRow ).GetStyleRight() );
+}
+
+const Style& Array::GetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // outside clipping rows or overlapped in merged cells: invisible
+ if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedRight( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // left clipping border: always left style of right neighbor cell
+ if( nCol + 1 == mxImpl->mnFirstClipCol )
+ return ORIGCELL( nCol + 1, nRow ).GetStyleLeft();
+ // right clipping border: always own right style
+ if( nCol == mxImpl->mnLastClipCol )
+ return LASTCELL( nCol, nRow ).GetStyleRight();
+ // outside clipping columns: invisible
+ if( !mxImpl->IsColInClipRange( nCol ) )
+ return OBJ_STYLE_NONE;
+ // inside clipping range: maximum of own right style and left style of right neighbor cell
+ return std::max( ORIGCELL( nCol, nRow ).GetStyleRight(), ORIGCELL( nCol + 1, nRow ).GetStyleLeft() );
+}
+
+const Style& Array::GetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // outside clipping columns or overlapped in merged cells: invisible
+ if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedTop( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // top clipping border: always own top style
+ if( nRow == mxImpl->mnFirstClipRow )
+ return ORIGCELL( nCol, nRow ).GetStyleTop();
+ // bottom clipping border: always bottom style of top neighbor cell
+ if( nRow == mxImpl->mnLastClipRow + 1 )
+ return ORIGCELL( nCol, nRow - 1 ).GetStyleBottom();
+ // outside clipping rows: invisible
+ if( !mxImpl->IsRowInClipRange( nRow ) )
+ return OBJ_STYLE_NONE;
+ // inside clipping range: maximum of own top style and bottom style of top neighbor cell
+ return std::max( ORIGCELL( nCol, nRow ).GetStyleTop(), ORIGCELL( nCol, nRow - 1 ).GetStyleBottom() );
+}
+
+const Style& Array::GetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // outside clipping columns or overlapped in merged cells: invisible
+ if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedBottom( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // top clipping border: always top style of bottom neighbor cell
+ if( nRow + 1 == mxImpl->mnFirstClipRow )
+ return ORIGCELL( nCol, nRow + 1 ).GetStyleTop();
+ // bottom clipping border: always own bottom style
+ if( nRow == mxImpl->mnLastClipRow )
+ return LASTCELL( nCol, nRow ).GetStyleBottom();
+ // outside clipping rows: invisible
+ if( !mxImpl->IsRowInClipRange( nRow ) )
+ return OBJ_STYLE_NONE;
+ // inside clipping range: maximum of own bottom style and top style of bottom neighbor cell
+ return std::max( ORIGCELL( nCol, nRow ).GetStyleBottom(), ORIGCELL( nCol, nRow + 1 ).GetStyleTop() );
+}
+
+const Style& Array::GetCellStyleTLBR( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return CELL( nCol, nRow ).GetStyleTLBR();
+}
+
+const Style& Array::GetCellStyleBLTR( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return CELL( nCol, nRow ).GetStyleBLTR();
+}
+
+const Style& Array::GetCellStyleTL( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // not in clipping range: always invisible
+ if( !mxImpl->IsInClipRange( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // return style only for top-left cell
+ sal_Int32 nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
+ sal_Int32 nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
+ return ((nCol == nFirstCol) && (nRow == nFirstRow)) ?
+ CELL( nFirstCol, nFirstRow ).GetStyleTLBR() : OBJ_STYLE_NONE;
+}
+
+const Style& Array::GetCellStyleBR( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // not in clipping range: always invisible
+ if( !mxImpl->IsInClipRange( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // return style only for bottom-right cell
+ sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
+ sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
+ return ((nCol == nLastCol) && (nRow == nLastRow)) ?
+ CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleTLBR() : OBJ_STYLE_NONE;
+}
+
+const Style& Array::GetCellStyleBL( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // not in clipping range: always invisible
+ if( !mxImpl->IsInClipRange( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // return style only for bottom-left cell
+ sal_Int32 nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
+ sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
+ return ((nCol == nFirstCol) && (nRow == nLastRow)) ?
+ CELL( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleBLTR() : OBJ_STYLE_NONE;
+}
+
+const Style& Array::GetCellStyleTR( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // not in clipping range: always invisible
+ if( !mxImpl->IsInClipRange( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // return style only for top-right cell
+ sal_Int32 nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
+ sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
+ return ((nCol == nLastCol) && (nRow == nFirstRow)) ?
+ CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow ).GetStyleBLTR() : OBJ_STYLE_NONE;
+}
+
+// cell merging
+void Array::SetMergedRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
+{
+ DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetMergedRange" );
+ DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetMergedRange" );
+#if OSL_DEBUG_LEVEL >= 2
+ {
+ bool bFound = false;
+ for( sal_Int32 nCurrCol = nFirstCol; !bFound && (nCurrCol <= nLastCol); ++nCurrCol )
+ for( sal_Int32 nCurrRow = nFirstRow; !bFound && (nCurrRow <= nLastRow); ++nCurrRow )
+ bFound = CELL( nCurrCol, nCurrRow ).IsMerged();
+ DBG_FRAME_CHECK( !bFound, "SetMergedRange", "overlapping merged ranges" );
+ }
+#endif
+ if( mxImpl->IsValidPos( nFirstCol, nFirstRow ) && mxImpl->IsValidPos( nLastCol, nLastRow ) )
+ lclSetMergedRange( mxImpl->maCells, mxImpl->mnWidth, nFirstCol, nFirstRow, nLastCol, nLastRow );
+}
+
+void Array::SetAddMergedLeftSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedLeftSize" );
+ DBG_FRAME_CHECK( mxImpl->GetMergedFirstCol( nCol, nRow ) == 0, "SetAddMergedLeftSize", "additional border inside array" );
+ for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
+ CELLACC( aIt.Col(), aIt.Row() ).mnAddLeft = nAddSize;
+}
+
+void Array::SetAddMergedRightSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedRightSize" );
+ DBG_FRAME_CHECK( mxImpl->GetMergedLastCol( nCol, nRow ) + 1 == mxImpl->mnWidth, "SetAddMergedRightSize", "additional border inside array" );
+ for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
+ CELLACC( aIt.Col(), aIt.Row() ).mnAddRight = nAddSize;
+}
+
+void Array::SetAddMergedTopSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedTopSize" );
+ DBG_FRAME_CHECK( mxImpl->GetMergedFirstRow( nCol, nRow ) == 0, "SetAddMergedTopSize", "additional border inside array" );
+ for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
+ CELLACC( aIt.Col(), aIt.Row() ).mnAddTop = nAddSize;
+}
+
+void Array::SetAddMergedBottomSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedBottomSize" );
+ DBG_FRAME_CHECK( mxImpl->GetMergedLastRow( nCol, nRow ) + 1 == mxImpl->mnHeight, "SetAddMergedBottomSize", "additional border inside array" );
+ for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
+ CELLACC( aIt.Col(), aIt.Row() ).mnAddBottom = nAddSize;
+}
+
+bool Array::IsMerged( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMerged" );
+ return CELL( nCol, nRow ).IsMerged();
+}
+
+void Array::GetMergedOrigin( sal_Int32& rnFirstCol, sal_Int32& rnFirstRow, sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetMergedOrigin" );
+ rnFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
+ rnFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
+}
+
+void Array::GetMergedRange( sal_Int32& rnFirstCol, sal_Int32& rnFirstRow,
+ sal_Int32& rnLastCol, sal_Int32& rnLastRow, sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ GetMergedOrigin( rnFirstCol, rnFirstRow, nCol, nRow );
+ rnLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
+ rnLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
+}
+
+// clipping
+void Array::SetClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
+{
+ DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetClipRange" );
+ DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetClipRange" );
+ mxImpl->mnFirstClipCol = nFirstCol;
+ mxImpl->mnFirstClipRow = nFirstRow;
+ mxImpl->mnLastClipCol = nLastCol;
+ mxImpl->mnLastClipRow = nLastRow;
+}
+
+// cell coordinates
+void Array::SetXOffset( sal_Int32 nXOffset )
+{
+ mxImpl->maXCoords[ 0 ] = nXOffset;
+ mxImpl->mbXCoordsDirty = true;
+}
+
+void Array::SetYOffset( sal_Int32 nYOffset )
+{
+ mxImpl->maYCoords[ 0 ] = nYOffset;
+ mxImpl->mbYCoordsDirty = true;
+}
+
+void Array::SetColWidth( sal_Int32 nCol, sal_Int32 nWidth )
+{
+ DBG_FRAME_CHECK_COL( nCol, "SetColWidth" );
+ mxImpl->maWidths[ nCol ] = nWidth;
+ mxImpl->mbXCoordsDirty = true;
+}
+
+void Array::SetRowHeight( sal_Int32 nRow, sal_Int32 nHeight )
+{
+ DBG_FRAME_CHECK_ROW( nRow, "SetRowHeight" );
+ mxImpl->maHeights[ nRow ] = nHeight;
+ mxImpl->mbYCoordsDirty = true;
+}
+
+void Array::SetAllColWidths( sal_Int32 nWidth )
+{
+ std::fill( mxImpl->maWidths.begin(), mxImpl->maWidths.end(), nWidth );
+ mxImpl->mbXCoordsDirty = true;
+}
+
+void Array::SetAllRowHeights( sal_Int32 nHeight )
+{
+ std::fill( mxImpl->maHeights.begin(), mxImpl->maHeights.end(), nHeight );
+ mxImpl->mbYCoordsDirty = true;
+}
+
+sal_Int32 Array::GetColPosition( sal_Int32 nCol ) const
+{
+ DBG_FRAME_CHECK_COL_1( nCol, "GetColPosition" );
+ return mxImpl->GetColPosition( nCol );
+}
+
+sal_Int32 Array::GetRowPosition( sal_Int32 nRow ) const
+{
+ DBG_FRAME_CHECK_ROW_1( nRow, "GetRowPosition" );
+ return mxImpl->GetRowPosition( nRow );
+}
+
+sal_Int32 Array::GetColWidth( sal_Int32 nFirstCol, sal_Int32 nLastCol ) const
+{
+ DBG_FRAME_CHECK_COL( nFirstCol, "GetColWidth" );
+ DBG_FRAME_CHECK_COL( nLastCol, "GetColWidth" );
+ return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol );
+}
+
+sal_Int32 Array::GetRowHeight( sal_Int32 nFirstRow, sal_Int32 nLastRow ) const
+{
+ DBG_FRAME_CHECK_ROW( nFirstRow, "GetRowHeight" );
+ DBG_FRAME_CHECK_ROW( nLastRow, "GetRowHeight" );
+ return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow );
+}
+
+sal_Int32 Array::GetWidth() const
+{
+ return GetColPosition( mxImpl->mnWidth ) - GetColPosition( 0 );
+}
+
+sal_Int32 Array::GetHeight() const
+{
+ return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 );
+}
+
+basegfx::B2DRange Array::GetCellRange( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // get the Range of the fully expanded cell (if merged)
+ const sal_Int32 nFirstCol(mxImpl->GetMergedFirstCol( nCol, nRow ));
+ const sal_Int32 nFirstRow(mxImpl->GetMergedFirstRow( nCol, nRow ));
+ const sal_Int32 nLastCol(mxImpl->GetMergedLastCol( nCol, nRow ));
+ const sal_Int32 nLastRow(mxImpl->GetMergedLastRow( nCol, nRow ));
+ const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) );
+ const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 );
+ tools::Rectangle aRect(aPoint, aSize);
+
+ // adjust rectangle for partly visible merged cells
+ const Cell& rCell = CELL( nCol, nRow );
+
+ if( rCell.IsMerged() )
+ {
+ // not *sure* what exactly this is good for,
+ // it is just a hard set extension at merged cells,
+ // probably *should* be included in the above extended
+ // GetColPosition/GetColWidth already. This might be
+ // added due to GetColPosition/GetColWidth not working
+ // correctly over PageChanges (if used), but not sure.
+ aRect.AdjustLeft( -(rCell.mnAddLeft) );
+ aRect.AdjustRight(rCell.mnAddRight );
+ aRect.AdjustTop( -(rCell.mnAddTop) );
+ aRect.AdjustBottom(rCell.mnAddBottom );
+ }
+
+ return vcl::unotools::b2DRectangleFromRectangle(aRect);
+}
+
+// return output range of given row/col range in logical coordinates
+basegfx::B2DRange Array::GetB2DRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow) const
+{
+ const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) );
+ const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 );
+
+ return vcl::unotools::b2DRectangleFromRectangle(tools::Rectangle(aPoint, aSize));
+}
+
+// mirroring
+void Array::MirrorSelfX()
+{
+ CellVec aNewCells;
+ aNewCells.reserve( GetCellCount() );
+
+ sal_Int32 nCol, nRow;
+ for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
+ {
+ for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
+ {
+ aNewCells.push_back( CELL( mxImpl->GetMirrorCol( nCol ), nRow ) );
+ aNewCells.back().MirrorSelfX();
+ }
+ }
+ for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
+ {
+ for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
+ {
+ if( CELL( nCol, nRow ).mbMergeOrig )
+ {
+ sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
+ sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
+ lclSetMergedRange( aNewCells, mxImpl->mnWidth,
+ mxImpl->GetMirrorCol( nLastCol ), nRow,
+ mxImpl->GetMirrorCol( nCol ), nLastRow );
+ }
+ }
+ }
+ mxImpl->maCells.swap( aNewCells );
+
+ std::reverse( mxImpl->maWidths.begin(), mxImpl->maWidths.end() );
+ mxImpl->mbXCoordsDirty = true;
+}
+
+// drawing
+static void HelperCreateHorizontalEntry(
+ const Array& rArray,
+ const Style& rStyle,
+ sal_Int32 col,
+ sal_Int32 row,
+ const basegfx::B2DPoint& rOrigin,
+ const basegfx::B2DVector& rX,
+ const basegfx::B2DVector& rY,
+ drawinglayer::primitive2d::SdrFrameBorderDataVector& rData,
+ bool bUpper,
+ const Color* pForceColor)
+{
+ // prepare SdrFrameBorderData
+ rData.emplace_back(
+ bUpper ? rOrigin : basegfx::B2DPoint(rOrigin + rY),
+ rX,
+ rStyle,
+ pForceColor);
+ drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
+
+ // get involved styles at start
+ const Style& rStartFromTR(rArray.GetCellStyleBL( col, row - 1 ));
+ const Style& rStartLFromT(rArray.GetCellStyleLeft( col, row - 1 ));
+ const Style& rStartLFromL(rArray.GetCellStyleTop( col - 1, row ));
+ const Style& rStartLFromB(rArray.GetCellStyleLeft( col, row ));
+ const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
+
+ rInstance.addSdrConnectStyleData(true, rStartFromTR, rX - rY, false);
+ rInstance.addSdrConnectStyleData(true, rStartLFromT, -rY, true);
+ rInstance.addSdrConnectStyleData(true, rStartLFromL, -rX, true);
+ rInstance.addSdrConnectStyleData(true, rStartLFromB, rY, false);
+ rInstance.addSdrConnectStyleData(true, rStartFromBR, rX + rY, false);
+
+ // get involved styles at end
+ const Style& rEndFromTL(rArray.GetCellStyleBR( col, row - 1 ));
+ const Style& rEndRFromT(rArray.GetCellStyleRight( col, row - 1 ));
+ const Style& rEndRFromR(rArray.GetCellStyleTop( col + 1, row ));
+ const Style& rEndRFromB(rArray.GetCellStyleRight( col, row ));
+ const Style& rEndFromBL(rArray.GetCellStyleTR( col, row ));
+
+ rInstance.addSdrConnectStyleData(false, rEndFromTL, -rX - rY, true);
+ rInstance.addSdrConnectStyleData(false, rEndRFromT, -rY, true);
+ rInstance.addSdrConnectStyleData(false, rEndRFromR, rX, false);
+ rInstance.addSdrConnectStyleData(false, rEndRFromB, rY, false);
+ rInstance.addSdrConnectStyleData(false, rEndFromBL, rY - rX, true);
+}
+
+static void HelperCreateVerticalEntry(
+ const Array& rArray,
+ const Style& rStyle,
+ sal_Int32 col,
+ sal_Int32 row,
+ const basegfx::B2DPoint& rOrigin,
+ const basegfx::B2DVector& rX,
+ const basegfx::B2DVector& rY,
+ drawinglayer::primitive2d::SdrFrameBorderDataVector& rData,
+ bool bLeft,
+ const Color* pForceColor)
+{
+ // prepare SdrFrameBorderData
+ rData.emplace_back(
+ bLeft ? rOrigin : basegfx::B2DPoint(rOrigin + rX),
+ rY,
+ rStyle,
+ pForceColor);
+ drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
+
+ // get involved styles at start
+ const Style& rStartFromBL(rArray.GetCellStyleTR( col - 1, row ));
+ const Style& rStartTFromL(rArray.GetCellStyleTop( col - 1, row ));
+ const Style& rStartTFromT(rArray.GetCellStyleLeft( col, row - 1 ));
+ const Style& rStartTFromR(rArray.GetCellStyleTop( col, row ));
+ const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
+
+ rInstance.addSdrConnectStyleData(true, rStartFromBR, rX + rY, false);
+ rInstance.addSdrConnectStyleData(true, rStartTFromR, rX, false);
+ rInstance.addSdrConnectStyleData(true, rStartTFromT, -rY, true);
+ rInstance.addSdrConnectStyleData(true, rStartTFromL, -rX, true);
+ rInstance.addSdrConnectStyleData(true, rStartFromBL, rY - rX, true);
+
+ // get involved styles at end
+ const Style& rEndFromTL(rArray.GetCellStyleBR( col - 1, row ));
+ const Style& rEndBFromL(rArray.GetCellStyleBottom( col - 1, row ));
+ const Style& rEndBFromB(rArray.GetCellStyleLeft( col, row + 1 ));
+ const Style& rEndBFromR(rArray.GetCellStyleBottom( col, row ));
+ const Style& rEndFromTR(rArray.GetCellStyleBL( col, row ));
+
+ rInstance.addSdrConnectStyleData(false, rEndFromTR, rX - rY, false);
+ rInstance.addSdrConnectStyleData(false, rEndBFromR, rX, false);
+ rInstance.addSdrConnectStyleData(false, rEndBFromB, rY, false);
+ rInstance.addSdrConnectStyleData(false, rEndBFromL, -rX, true);
+ rInstance.addSdrConnectStyleData(false, rEndFromTL, -rY - rX, true);
+}
+
+static void HelperClipLine(
+ basegfx::B2DPoint& rStart,
+ basegfx::B2DVector& rDirection,
+ const basegfx::B2DRange& rClipRange)
+{
+ basegfx::B2DPolygon aLine({rStart, rStart + rDirection});
+ const basegfx::B2DPolyPolygon aResultPP(
+ basegfx::utils::clipPolygonOnRange(
+ aLine,
+ rClipRange,
+ true, // bInside
+ true)); // bStroke
+
+ if(aResultPP.count() > 0)
+ {
+ const basegfx::B2DPolygon aResultP(aResultPP.getB2DPolygon(0));
+
+ if(aResultP.count() > 0)
+ {
+ const basegfx::B2DPoint aResultStart(aResultP.getB2DPoint(0));
+ const basegfx::B2DPoint aResultEnd(aResultP.getB2DPoint(aResultP.count() - 1));
+
+ if(aResultStart != aResultEnd)
+ {
+ rStart = aResultStart;
+ rDirection = aResultEnd - aResultStart;
+ }
+ }
+ }
+}
+
+static void HelperCreateTLBREntry(
+ const Array& rArray,
+ const Style& rStyle,
+ drawinglayer::primitive2d::SdrFrameBorderDataVector& rData,
+ const basegfx::B2DPoint& rOrigin,
+ const basegfx::B2DVector& rX,
+ const basegfx::B2DVector& rY,
+ sal_Int32 nColLeft,
+ sal_Int32 nColRight,
+ sal_Int32 nRowTop,
+ sal_Int32 nRowBottom,
+ const Color* pForceColor,
+ const basegfx::B2DRange* pClipRange)
+{
+ if(rStyle.IsUsed())
+ {
+ /// prepare geometry line data
+ basegfx::B2DPoint aStart(rOrigin);
+ basegfx::B2DVector aDirection(rX + rY);
+
+ /// check if we need to clip geometry line data and do it
+ if(nullptr != pClipRange)
+ {
+ HelperClipLine(aStart, aDirection, *pClipRange);
+ }
+
+ /// top-left and bottom-right Style Tables
+ rData.emplace_back(
+ aStart,
+ aDirection,
+ rStyle,
+ pForceColor);
+ drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
+
+ /// Fill top-left Style Table
+ const Style& rTLFromRight(rArray.GetCellStyleTop(nColLeft, nRowTop));
+ const Style& rTLFromBottom(rArray.GetCellStyleLeft(nColLeft, nRowTop));
+
+ rInstance.addSdrConnectStyleData(true, rTLFromRight, rX, false);
+ rInstance.addSdrConnectStyleData(true, rTLFromBottom, rY, false);
+
+ /// Fill bottom-right Style Table
+ const Style& rBRFromBottom(rArray.GetCellStyleRight(nColRight, nRowBottom));
+ const Style& rBRFromLeft(rArray.GetCellStyleBottom(nColRight, nRowBottom));
+
+ rInstance.addSdrConnectStyleData(false, rBRFromBottom, -rY, true);
+ rInstance.addSdrConnectStyleData(false, rBRFromLeft, -rX, true);
+ }
+}
+
+static void HelperCreateBLTREntry(
+ const Array& rArray,
+ const Style& rStyle,
+ drawinglayer::primitive2d::SdrFrameBorderDataVector& rData,
+ const basegfx::B2DPoint& rOrigin,
+ const basegfx::B2DVector& rX,
+ const basegfx::B2DVector& rY,
+ sal_Int32 nColLeft,
+ sal_Int32 nColRight,
+ sal_Int32 nRowTop,
+ sal_Int32 nRowBottom,
+ const Color* pForceColor,
+ const basegfx::B2DRange* pClipRange)
+{
+ if(rStyle.IsUsed())
+ {
+ /// prepare geometry line data
+ basegfx::B2DPoint aStart(rOrigin + rY);
+ basegfx::B2DVector aDirection(rX - rY);
+
+ /// check if we need to clip geometry line data and do it
+ if(nullptr != pClipRange)
+ {
+ HelperClipLine(aStart, aDirection, *pClipRange);
+ }
+
+ /// bottom-left and top-right Style Tables
+ rData.emplace_back(
+ aStart,
+ aDirection,
+ rStyle,
+ pForceColor);
+ drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
+
+ /// Fill bottom-left Style Table
+ const Style& rBLFromTop(rArray.GetCellStyleLeft(nColLeft, nRowBottom));
+ const Style& rBLFromBottom(rArray.GetCellStyleBottom(nColLeft, nRowBottom));
+
+ rInstance.addSdrConnectStyleData(true, rBLFromTop, -rY, true);
+ rInstance.addSdrConnectStyleData(true, rBLFromBottom, rX, false);
+
+ /// Fill top-right Style Table
+ const Style& rTRFromLeft(rArray.GetCellStyleTop(nColRight, nRowTop));
+ const Style& rTRFromBottom(rArray.GetCellStyleRight(nColRight, nRowTop));
+
+ rInstance.addSdrConnectStyleData(false, rTRFromLeft, -rX, true);
+ rInstance.addSdrConnectStyleData(false, rTRFromBottom, rY, false);
+ }
+}
+
+drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
+ sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow,
+ const Color* pForceColor ) const
+{
+ DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "CreateB2DPrimitiveRange" );
+ DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "CreateB2DPrimitiveRange" );
+
+#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
+ std::vector<basegfx::B2DRange> aClipRanges;
+#endif
+
+ // It may be necessary to extend the loop ranges by one cell to the outside,
+ // when possible. This is needed e.g. when there is in Calc a Cell with an
+ // upper CellBorder using DoubleLine and that is right/left connected upwards
+ // to also DoubleLine. These upper DoubleLines will be extended to meet the
+ // lower of the upper CellBorder and thus have graphical parts that are
+ // displayed one cell below and right/left of the target cell - analog to
+ // other examples in all other directions.
+ // It would be possible to explicitly test this (if possible by indices at all)
+ // looping and testing the styles in the outer cells to detect this, but since
+ // for other usages (e.g. UI) usually nFirstRow==0 and nLastRow==GetRowCount()-1
+ // (and analog for Col) it is okay to just expand the range when available.
+ // Do *not* change nFirstRow/nLastRow due to these needed to the boolean tests
+ // below (!)
+ // Checked usages, this method is used in Calc EditView/Print/Export stuff and
+ // in UI (Dialog), not for Writer Tables and Draw/Impress tables. All usages
+ // seem okay with this change, so I will add it.
+ const sal_Int32 nStartRow(nFirstRow > 0 ? nFirstRow - 1 : nFirstRow);
+ const sal_Int32 nEndRow(nLastRow < GetRowCount() - 1 ? nLastRow + 1 : nLastRow);
+ const sal_Int32 nStartCol(nFirstCol > 0 ? nFirstCol - 1 : nFirstCol);
+ const sal_Int32 nEndCol(nLastCol < GetColCount() - 1 ? nLastCol + 1 : nLastCol);
+
+ // prepare SdrFrameBorderDataVector
+ std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData(
+ std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>());
+
+ // remember for which merged cells crossed lines were already created. To
+ // do so, hold the sal_Int32 cell index in a set for fast check
+ std::set< sal_Int32 > aMergedCells;
+
+ for (sal_Int32 nRow(nStartRow); nRow <= nEndRow; ++nRow)
+ {
+ for (sal_Int32 nCol(nStartCol); nCol <= nEndCol; ++nCol)
+ {
+ // get Cell and CoordinateSystem (*only* for this Cell, do *not* expand for
+ // merged cells (!)), check if used (non-empty vectors)
+ const Cell& rCell(CELL(nCol, nRow));
+ basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystemSingleCell(*this, nCol, nRow));
+ basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0));
+ basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1));
+
+ // get needed local values
+ basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2));
+ const bool bOverlapX(rCell.mbOverlapX);
+ const bool bFirstCol(nCol == nFirstCol);
+
+ // handle rotation: If cell is rotated, handle lower/right edge inside
+ // this local geometry due to the created CoordinateSystem already representing
+ // the needed transformations.
+ const bool bRotated(rCell.IsRotated());
+
+ // Additionally avoid double-handling by suppressing handling when self not rotated,
+ // but above/left is rotated and thus already handled. Two directly connected
+ // rotated will paint/create both edges, they might be rotated differently.
+ const bool bSuppressLeft(!bRotated && nCol > nFirstCol && CELL(nCol - 1, nRow).IsRotated());
+ const bool bSuppressAbove(!bRotated && nRow > nFirstRow && CELL(nCol, nRow - 1).IsRotated());
+
+ if(!aX.equalZero() && !aY.equalZero())
+ {
+ // additionally needed local values
+ const bool bOverlapY(rCell.mbOverlapY);
+ const bool bLastCol(nCol == nLastCol);
+ const bool bFirstRow(nRow == nFirstRow);
+ const bool bLastRow(nRow == nLastRow);
+
+ // create upper line for this Cell
+ if ((!bOverlapY // true for first line in merged cells or cells
+ || bFirstRow) // true for non_Calc usages of this tooling
+ && !bSuppressAbove) // true when above is not rotated, so edge is already handled (see bRotated)
+ {
+ // get CellStyle - method will take care to get the correct one, e.g.
+ // for merged cells (it uses ORIGCELL that works with topLeft's of these)
+ const Style& rTop(GetCellStyleTop(nCol, nRow));
+
+ if(rTop.IsUsed())
+ {
+ HelperCreateHorizontalEntry(*this, rTop, nCol, nRow, aOrigin, aX, aY, *aData, true, pForceColor);
+ }
+ }
+
+ // create lower line for this Cell
+ if (bLastRow // true for non_Calc usages of this tooling
+ || bRotated) // true if cell is rotated, handle lower edge in local geometry
+ {
+ const Style& rBottom(GetCellStyleBottom(nCol, nRow));
+
+ if(rBottom.IsUsed())
+ {
+ HelperCreateHorizontalEntry(*this, rBottom, nCol, nRow + 1, aOrigin, aX, aY, *aData, false, pForceColor);
+ }
+ }
+
+ // create left line for this Cell
+ if ((!bOverlapX // true for first column in merged cells or cells
+ || bFirstCol) // true for non_Calc usages of this tooling
+ && !bSuppressLeft) // true when left is not rotated, so edge is already handled (see bRotated)
+ {
+ const Style& rLeft(GetCellStyleLeft(nCol, nRow));
+
+ if(rLeft.IsUsed())
+ {
+ HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, *aData, true, pForceColor);
+ }
+ }
+
+ // create right line for this Cell
+ if (bLastCol // true for non_Calc usages of this tooling
+ || bRotated) // true if cell is rotated, handle right edge in local geometry
+ {
+ const Style& rRight(GetCellStyleRight(nCol, nRow));
+
+ if(rRight.IsUsed())
+ {
+ HelperCreateVerticalEntry(*this, rRight, nCol + 1, nRow, aOrigin, aX, aY, *aData, false, pForceColor);
+ }
+ }
+
+ // tdf#126269 check for crossed lines, these need special treatment, especially
+ // for merged cells (see comments in task). Separate treatment of merged and
+ // non-merged cells to allow better handling of both types
+ if(rCell.IsMerged())
+ {
+ // first check if this merged cell was already handled. To do so,
+ // calculate and use the index of the TopLeft cell
+ sal_Int32 nColLeft(nCol), nRowTop(nRow), nColRight(nCol), nRowBottom(nRow);
+ GetMergedRange(nColLeft, nRowTop, nColRight, nRowBottom, nCol, nRow);
+ const sal_Int32 nIndexOfMergedCell(mxImpl->GetIndex(nColLeft, nRowTop));
+
+ if(aMergedCells.end() == aMergedCells.find(nIndexOfMergedCell))
+ {
+ // not found, so not yet handled. Add now to mark as handled
+ aMergedCells.insert(nIndexOfMergedCell);
+
+ // Get and check if diagonal styles are used
+ // Note: For GetCellStyleBLTR below I tried to use nRowBottom
+ // as Y-value what seemed more logical, but that
+ // is wrong. Despite defining a line starting at
+ // bottom-left, the Style is defined in the cell at top-left
+ const Style& rTLBR(GetCellStyleTLBR(nColLeft, nRowTop));
+ const Style& rBLTR(GetCellStyleBLTR(nColLeft, nRowTop));
+
+ if(rTLBR.IsUsed() || rBLTR.IsUsed())
+ {
+ // test if merged cell overlaps ClipRange at all (needs visualization)
+ if(mxImpl->OverlapsClipRange(nColLeft, nRowTop, nColRight, nRowBottom))
+ {
+ // when merged, get extended coordinate system and derived values
+ // for the full range of this merged cell. Only work with rMergedCell
+ // (which is the top-left single cell of the merged cell) from here on
+ const Cell& rMergedCell(CELL(nColLeft, nRowTop));
+ aCoordinateSystem = rMergedCell.CreateCoordinateSystemMergedCell(
+ *this, nColLeft, nRowTop, nColRight, nRowBottom);
+ aX = basegfx::utils::getColumn(aCoordinateSystem, 0);
+ aY = basegfx::utils::getColumn(aCoordinateSystem, 1);
+ aOrigin = basegfx::utils::getColumn(aCoordinateSystem, 2);
+
+ // check if clip is needed
+ basegfx::B2DRange aClipRange;
+
+ // first use row/col ClipTest for raw check
+ bool bNeedToClip(
+ !mxImpl->IsColInClipRange(nColLeft) ||
+ !mxImpl->IsRowInClipRange(nRowTop) ||
+ !mxImpl->IsColInClipRange(nColRight) ||
+ !mxImpl->IsRowInClipRange(nRowBottom));
+
+ if(bNeedToClip)
+ {
+ // now get ClipRange and CellRange in logical coordinates
+ aClipRange = GetB2DRange(
+ mxImpl->mnFirstClipCol, mxImpl->mnFirstClipRow,
+ mxImpl->mnLastClipCol, mxImpl->mnLastClipRow);
+
+ basegfx::B2DRange aCellRange(
+ GetB2DRange(
+ nColLeft, nRowTop,
+ nColRight, nRowBottom));
+
+ // intersect these to get the target ClipRange, ensure
+ // that clip is needed
+ aClipRange.intersect(aCellRange);
+ bNeedToClip = !aClipRange.isEmpty();
+
+#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
+ aClipRanges.push_back(aClipRange);
+#endif
+ }
+
+ // create top-left to bottom-right geometry
+ HelperCreateTLBREntry(*this, rTLBR, *aData, aOrigin, aX, aY,
+ nColLeft, nRowTop, nColRight, nRowBottom, pForceColor,
+ bNeedToClip ? &aClipRange : nullptr);
+
+ // create bottom-left to top-right geometry
+ HelperCreateBLTREntry(*this, rBLTR, *aData, aOrigin, aX, aY,
+ nColLeft, nRowTop, nColRight, nRowBottom, pForceColor,
+ bNeedToClip ? &aClipRange : nullptr);
+ }
+ }
+ }
+ }
+ else
+ {
+ // must be in clipping range: else not visible. This
+ // already clips completely for non-merged cells
+ if( mxImpl->IsInClipRange( nCol, nRow ) )
+ {
+ // get and check if diagonal styles are used
+ const Style& rTLBR(GetCellStyleTLBR(nCol, nRow));
+ const Style& rBLTR(GetCellStyleBLTR(nCol, nRow));
+
+ if(rTLBR.IsUsed() || rBLTR.IsUsed())
+ {
+ HelperCreateTLBREntry(*this, rTLBR, *aData, aOrigin, aX, aY,
+ nCol, nRow, nCol, nRow, pForceColor, nullptr);
+
+ HelperCreateBLTREntry(*this, rBLTR, *aData, aOrigin, aX, aY,
+ nCol, nRow, nCol, nRow, pForceColor, nullptr);
+ }
+ }
+ }
+ }
+ else if(!aY.equalZero())
+ {
+ // cell has height, but no width. Create left vertical line for this Cell
+ if ((!bOverlapX // true for first column in merged cells or cells
+ || bFirstCol) // true for non_Calc usages of this tooling
+ && !bSuppressLeft) // true when left is not rotated, so edge is already handled (see bRotated)
+ {
+ const Style& rLeft(GetCellStyleLeft(nCol, nRow));
+
+ if (rLeft.IsUsed())
+ {
+ HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, *aData, true, pForceColor);
+ }
+ }
+ }
+ else
+ {
+ // Cell has *no* size, thus no visualization
+ }
+ }
+ }
+
+ // create instance of SdrFrameBorderPrimitive2D if
+ // SdrFrameBorderDataVector is used
+ drawinglayer::primitive2d::Primitive2DContainer aSequence;
+
+ if(!aData->empty())
+ {
+ aSequence.append(
+ drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
+ aData,
+ true))); // force visualization to minimal one discrete unit (pixel)
+ }
+
+#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
+ for(auto const& rClipRange : aClipRanges)
+ {
+ // draw ClipRange in yellow to allow simple interactive optical control in office
+ aSequence.append(
+ drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ basegfx::utils::createPolygonFromRect(rClipRange),
+ basegfx::BColor(1.0, 1.0, 0.0))));
+ }
+#endif
+
+ return aSequence;
+}
+
+drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveArray() const
+{
+ drawinglayer::primitive2d::Primitive2DContainer aPrimitives;
+
+ if (mxImpl->mnWidth && mxImpl->mnHeight)
+ {
+ aPrimitives = CreateB2DPrimitiveRange(0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1, nullptr);
+ }
+
+ return aPrimitives;
+}
+
+#undef ORIGCELL
+#undef LASTCELL
+#undef CELLACC
+#undef CELL
+#undef DBG_FRAME_CHECK_ROW_1
+#undef DBG_FRAME_CHECK_COL_1
+#undef DBG_FRAME_CHECK_COLROW
+#undef DBG_FRAME_CHECK_ROW
+#undef DBG_FRAME_CHECK_COL
+#undef DBG_FRAME_CHECK
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/frmdirlbox.cxx b/svx/source/dialog/frmdirlbox.cxx
new file mode 100644
index 000000000..375a41867
--- /dev/null
+++ b/svx/source/dialog/frmdirlbox.cxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/frmdirlbox.hxx>
+
+namespace svx
+{
+FrameDirectionListBox::FrameDirectionListBox(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+{
+}
+
+FrameDirectionListBox::~FrameDirectionListBox() {}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/frmsel.cxx b/svx/source/dialog/frmsel.cxx
new file mode 100644
index 000000000..fed0d59d0
--- /dev/null
+++ b/svx/source/dialog/frmsel.cxx
@@ -0,0 +1,1303 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_wasm_strip.h>
+
+#include <sal/config.h>
+
+#include <o3tl/safeint.hxx>
+#include <svx/frmsel.hxx>
+#include <vcl/event.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <svtools/colorcfg.hxx>
+
+#include <algorithm>
+#include <math.h>
+
+#include <frmselimpl.hxx>
+#include <AccessibleFrameSelector.hxx>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+
+#include <bitmaps.hlst>
+
+using namespace ::com::sun::star;
+using namespace ::editeng;
+
+namespace svx {
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::accessibility::XAccessible;
+using namespace ::com::sun::star::accessibility;
+
+// global functions from framebordertype.hxx
+
+FrameBorderType GetFrameBorderTypeFromIndex( size_t nIndex )
+{
+ DBG_ASSERT( nIndex < o3tl::make_unsigned(FRAMEBORDERTYPE_COUNT),
+ "svx::GetFrameBorderTypeFromIndex - invalid index" );
+ return static_cast< FrameBorderType >( nIndex + 1 );
+}
+
+size_t GetIndexFromFrameBorderType( FrameBorderType eBorder )
+{
+ DBG_ASSERT( eBorder != FrameBorderType::NONE,
+ "svx::GetIndexFromFrameBorderType - invalid frame border type" );
+ return static_cast< size_t >( eBorder ) - 1;
+}
+
+namespace
+{
+
+/** Space between outer control border and any graphical element of the control. */
+const tools::Long FRAMESEL_GEOM_OUTER = 2;
+
+/** Space between arrows and usable inner area. */
+const tools::Long FRAMESEL_GEOM_INNER = 3;
+
+/** Maximum width to draw a frame border style. */
+const tools::Long FRAMESEL_GEOM_WIDTH = 9;
+
+/** Additional margin for click area of outer lines. */
+const tools::Long FRAMESEL_GEOM_ADD_CLICK_OUTER = 5;
+
+/** Additional margin for click area of inner lines. */
+const tools::Long FRAMESEL_GEOM_ADD_CLICK_INNER = 2;
+
+
+/** Returns the corresponding flag for a frame border. */
+FrameSelFlags lclGetFlagFromType( FrameBorderType eBorder )
+{
+ switch( eBorder )
+ {
+ case FrameBorderType::Left: return FrameSelFlags::Left;
+ case FrameBorderType::Right: return FrameSelFlags::Right;
+ case FrameBorderType::Top: return FrameSelFlags::Top;
+ case FrameBorderType::Bottom: return FrameSelFlags::Bottom;
+ case FrameBorderType::Horizontal: return FrameSelFlags::InnerHorizontal;
+ case FrameBorderType::Vertical: return FrameSelFlags::InnerVertical;
+ case FrameBorderType::TLBR: return FrameSelFlags::DiagonalTLBR;
+ case FrameBorderType::BLTR: return FrameSelFlags::DiagonalBLTR;
+ case FrameBorderType::NONE : break;
+ }
+ return FrameSelFlags::NONE;
+}
+
+/** Merges the rSource polypolygon into the rDest polypolygon. */
+void lclPolyPolyUnion( tools::PolyPolygon& rDest, const tools::PolyPolygon& rSource )
+{
+ const tools::PolyPolygon aTmp( rDest );
+ aTmp.GetUnion( rSource, rDest );
+}
+
+} // namespace
+
+FrameBorder::FrameBorder( FrameBorderType eType ) :
+ meType( eType ),
+ meState( FrameBorderState::Hide ),
+ meKeyLeft( FrameBorderType::NONE ),
+ meKeyRight( FrameBorderType::NONE ),
+ meKeyTop( FrameBorderType::NONE ),
+ meKeyBottom( FrameBorderType::NONE ),
+ mbEnabled( false ),
+ mbSelected( false )
+{
+}
+
+void FrameBorder::Enable( FrameSelFlags nFlags )
+{
+ mbEnabled = bool(nFlags & lclGetFlagFromType( meType ));
+ if( !mbEnabled )
+ SetState( FrameBorderState::Hide );
+}
+
+void FrameBorder::SetCoreStyle( const SvxBorderLine* pStyle )
+{
+ if( pStyle )
+ maCoreStyle = *pStyle;
+ else
+ maCoreStyle = SvxBorderLine();
+
+ // from twips to points
+ maUIStyle.Set( &maCoreStyle, FrameBorder::GetDefaultPatternScale(), FRAMESEL_GEOM_WIDTH );
+ meState = maUIStyle.IsUsed() ? FrameBorderState::Show : FrameBorderState::Hide;
+}
+
+void FrameBorder::SetState( FrameBorderState eState )
+{
+ meState = eState;
+ switch( meState )
+ {
+ case FrameBorderState::Show:
+ SAL_WARN( "svx.dialog", "svx::FrameBorder::SetState - use SetCoreStyle to make border visible" );
+ break;
+ case FrameBorderState::Hide:
+ maCoreStyle = SvxBorderLine();
+ maUIStyle.Clear();
+ break;
+ case FrameBorderState::DontCare:
+ maCoreStyle = SvxBorderLine();
+ maUIStyle = frame::Style(3, 0, 0, SvxBorderLineStyle::SOLID, FrameBorder::GetDefaultPatternScale()); //OBJ_FRAMESTYLE_DONTCARE
+ break;
+ }
+}
+
+void FrameBorder::AddFocusPolygon( const tools::Polygon& rFocus )
+{
+ lclPolyPolyUnion( maFocusArea, rFocus );
+}
+
+void FrameBorder::MergeFocusToPolyPolygon( tools::PolyPolygon& rPPoly ) const
+{
+ lclPolyPolyUnion( rPPoly, maFocusArea );
+}
+
+void FrameBorder::AddClickRect( const tools::Rectangle& rRect )
+{
+ lclPolyPolyUnion( maClickArea, tools::Polygon( rRect ) );
+}
+
+bool FrameBorder::ContainsClickPoint( const Point& rPos ) const
+{
+ return vcl::Region( maClickArea ).Contains( rPos );
+}
+
+tools::Rectangle FrameBorder::GetClickBoundRect() const
+{
+ return maClickArea.GetBoundRect();
+}
+
+void FrameBorder::SetKeyboardNeighbors(
+ FrameBorderType eLeft, FrameBorderType eRight, FrameBorderType eTop, FrameBorderType eBottom )
+{
+ meKeyLeft = eLeft;
+ meKeyRight = eRight;
+ meKeyTop = eTop;
+ meKeyBottom = eBottom;
+}
+
+FrameBorderType FrameBorder::GetKeyboardNeighbor( sal_uInt16 nKeyCode ) const
+{
+ FrameBorderType eBorder = FrameBorderType::NONE;
+ switch( nKeyCode )
+ {
+ case KEY_LEFT: eBorder = meKeyLeft; break;
+ case KEY_RIGHT: eBorder = meKeyRight; break;
+ case KEY_UP: eBorder = meKeyTop; break;
+ case KEY_DOWN: eBorder = meKeyBottom; break;
+ default: SAL_WARN( "svx.dialog", "svx::FrameBorder::GetKeyboardNeighbor - unknown key code" );
+ }
+ return eBorder;
+}
+
+FrameSelectorImpl::FrameSelectorImpl( FrameSelector& rFrameSel ) :
+ mrFrameSel( rFrameSel ),
+ mpVirDev( VclPtr<VirtualDevice>::Create() ),
+ maLeft( FrameBorderType::Left ),
+ maRight( FrameBorderType::Right ),
+ maTop( FrameBorderType::Top ),
+ maBottom( FrameBorderType::Bottom ),
+ maHor( FrameBorderType::Horizontal ),
+ maVer( FrameBorderType::Vertical ),
+ maTLBR( FrameBorderType::TLBR ),
+ maBLTR( FrameBorderType::BLTR ),
+ mnFlags( FrameSelFlags::Outer ),
+ mnCtrlSize( 0 ),
+ mnArrowSize( 0 ),
+ mnLine1( 0 ),
+ mnLine2( 0 ),
+ mnLine3( 0 ),
+ mnFocusOffs( 0 ),
+ mbHor( false ),
+ mbVer( false ),
+ mbTLBR( false ),
+ mbBLTR( false ),
+ mbFullRepaint( true ),
+ mbAutoSelect( true ),
+ mbHCMode( false )
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ ,maChildVec( 8 )
+#endif
+{
+ maAllBorders.resize( FRAMEBORDERTYPE_COUNT, nullptr );
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Left ) ] = &maLeft;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Right ) ] = &maRight;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Top ) ] = &maTop;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Bottom ) ] = &maBottom;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Horizontal ) ] = &maHor;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Vertical ) ] = &maVer;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::TLBR ) ] = &maTLBR;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::BLTR ) ] = &maBLTR;
+#if OSL_DEBUG_LEVEL >= 2
+ {
+ bool bOk = true;
+ for( FrameBorderCIter aIt( maAllBorders ); bOk && aIt.Is(); bOk = (*aIt != 0), ++aIt );
+ DBG_ASSERT( bOk, "svx::FrameSelectorImpl::FrameSelectorImpl - missing entry in maAllBorders" );
+ }
+#endif
+ // left neighbor right neighbor upper neighbor lower neighbor
+ maLeft.SetKeyboardNeighbors( FrameBorderType::NONE, FrameBorderType::TLBR, FrameBorderType::Top, FrameBorderType::Bottom );
+ maRight.SetKeyboardNeighbors( FrameBorderType::BLTR, FrameBorderType::NONE, FrameBorderType::Top, FrameBorderType::Bottom );
+ maTop.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Right, FrameBorderType::NONE, FrameBorderType::TLBR );
+ maBottom.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Right, FrameBorderType::BLTR, FrameBorderType::NONE );
+ maHor.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Right, FrameBorderType::TLBR, FrameBorderType::BLTR );
+ maVer.SetKeyboardNeighbors( FrameBorderType::TLBR, FrameBorderType::BLTR, FrameBorderType::Top, FrameBorderType::Bottom );
+ maTLBR.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Vertical, FrameBorderType::Top, FrameBorderType::Horizontal );
+ maBLTR.SetKeyboardNeighbors( FrameBorderType::Vertical, FrameBorderType::Right, FrameBorderType::Horizontal, FrameBorderType::Bottom );
+
+ Initialize(mnFlags);
+}
+
+FrameSelectorImpl::~FrameSelectorImpl()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ for( auto& rpChild : maChildVec )
+ if( rpChild.is() )
+ rpChild->Invalidate();
+#endif
+}
+
+// initialization
+void FrameSelectorImpl::Initialize( FrameSelFlags nFlags )
+{
+ mnFlags = nFlags;
+
+ maEnabBorders.clear();
+ for( FrameBorderIter aIt( maAllBorders ); aIt.Is(); ++aIt )
+ {
+ (*aIt)->Enable( mnFlags );
+ if( (*aIt)->IsEnabled() )
+ maEnabBorders.push_back( *aIt );
+ }
+ mbHor = maHor.IsEnabled();
+ mbVer = maVer.IsEnabled();
+ mbTLBR = maTLBR.IsEnabled();
+ mbBLTR = maBLTR.IsEnabled();
+
+ InitVirtualDevice();
+}
+
+void FrameSelectorImpl::InitColors()
+{
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ svtools::ColorConfig aColorConfig;
+ maBackCol = aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
+ mbHCMode = rSettings.GetHighContrastMode();
+ maArrowCol = aColorConfig.GetColorValue(svtools::DOCBOUNDARIES).nColor;
+ maMarkCol = aColorConfig.GetColorValue(svtools::TABLEBOUNDARIES).nColor;
+ maHCLineCol = COL_BLACK;
+}
+
+constexpr rtl::OUStringConstExpr aImageIds[] =
+{
+ RID_SVXBMP_FRMSEL_ARROW1,
+ RID_SVXBMP_FRMSEL_ARROW2,
+ RID_SVXBMP_FRMSEL_ARROW3,
+ RID_SVXBMP_FRMSEL_ARROW4,
+ RID_SVXBMP_FRMSEL_ARROW5,
+ RID_SVXBMP_FRMSEL_ARROW6,
+ RID_SVXBMP_FRMSEL_ARROW7,
+ RID_SVXBMP_FRMSEL_ARROW8,
+ RID_SVXBMP_FRMSEL_ARROW9,
+ RID_SVXBMP_FRMSEL_ARROW10,
+ RID_SVXBMP_FRMSEL_ARROW11,
+ RID_SVXBMP_FRMSEL_ARROW12,
+ RID_SVXBMP_FRMSEL_ARROW13,
+ RID_SVXBMP_FRMSEL_ARROW14,
+ RID_SVXBMP_FRMSEL_ARROW15,
+ RID_SVXBMP_FRMSEL_ARROW16
+};
+
+void FrameSelectorImpl::InitArrowImageList()
+{
+ maArrows.clear();
+
+ /* Build the arrow images bitmap with current colors. */
+ Color pColorAry1[3];
+ Color pColorAry2[3];
+ pColorAry1[0] = Color( 0, 0, 0 );
+ pColorAry2[0] = maArrowCol; // black -> arrow color
+ pColorAry1[1] = Color( 0, 255, 0 );
+ pColorAry2[1] = maMarkCol; // green -> marker color
+ pColorAry1[2] = Color( 255, 0, 255 );
+ pColorAry2[2] = maBackCol; // magenta -> background
+
+ assert(SAL_N_ELEMENTS(aImageIds) == 16);
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aImageIds); ++i)
+ {
+ BitmapEx aBmpEx { OUString(aImageIds[i]) };
+ aBmpEx.Replace(pColorAry1, pColorAry2, 3);
+ maArrows.emplace_back(aBmpEx);
+ }
+ assert(maArrows.size() == 16);
+
+ mnArrowSize = maArrows[0].GetSizePixel().Height();
+}
+
+void FrameSelectorImpl::InitGlobalGeometry()
+{
+ Size aCtrlSize(mrFrameSel.GetOutputSizePixel());
+ /* nMinSize is the lower of width and height (control will always be squarish).
+ FRAMESEL_GEOM_OUTER is the minimal distance between inner control border
+ and any element. */
+ tools::Long nMinSize = std::min( aCtrlSize.Width(), aCtrlSize.Height() ) - 2 * FRAMESEL_GEOM_OUTER;
+ /* nFixedSize is the size all existing elements need in one direction:
+ the diag. arrow, space betw. arrow and frame border, outer frame border,
+ inner frame border, other outer frame border, space betw. frame border
+ and arrow, the other arrow. */
+ tools::Long nFixedSize = 2 * mnArrowSize + 2 * FRAMESEL_GEOM_INNER + 3 * FRAMESEL_GEOM_WIDTH;
+ /* nBetwBordersSize contains the size between an outer and inner frame border (made odd). */
+ tools::Long nBetwBordersSize = (((nMinSize - nFixedSize) / 2) - 1) | 1;
+
+ /* The final size of the usable area. At least do not get negative */
+ mnCtrlSize = 2 * nBetwBordersSize + nFixedSize;
+ mnCtrlSize = std::max(mnCtrlSize, static_cast<tools::Long>(0));
+ mpVirDev->SetOutputSizePixel( Size( mnCtrlSize, mnCtrlSize ) );
+
+ /* Center the virtual device in the control. */
+ maVirDevPos = Point( (aCtrlSize.Width() - mnCtrlSize) / 2, (aCtrlSize.Height() - mnCtrlSize) / 2 );
+}
+
+void FrameSelectorImpl::InitBorderGeometry()
+{
+ size_t nCol, nCols, nRow, nRows;
+
+ // Global border geometry values
+ /* mnLine* is the middle point inside a frame border (i.e. mnLine1 is mid X inside left border). */
+ mnLine1 = mnArrowSize + FRAMESEL_GEOM_INNER + FRAMESEL_GEOM_WIDTH / 2;
+ mnLine2 = mnCtrlSize / 2;
+ mnLine3 = 2 * mnLine2 - mnLine1;
+
+ // Frame helper array
+ maArray.Initialize( mbVer ? 2 : 1, mbHor ? 2 : 1 );
+
+ maArray.SetXOffset( mnLine1 );
+ maArray.SetAllColWidths( (mbVer ? mnLine2 : mnLine3) - mnLine1 );
+
+ maArray.SetYOffset( mnLine1 );
+ maArray.SetAllRowHeights( (mbHor ? mnLine2 : mnLine3) - mnLine1 );
+
+ // Focus polygons
+ /* Width for focus rectangles from center of frame borders. */
+ mnFocusOffs = FRAMESEL_GEOM_WIDTH / 2 + 1;
+
+ maLeft.ClearFocusArea();
+ maVer.ClearFocusArea();
+ maRight.ClearFocusArea();
+ maTop.ClearFocusArea();
+ maHor.ClearFocusArea();
+ maBottom.ClearFocusArea();
+
+ maLeft.AddFocusPolygon( tools::Rectangle( mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine1 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
+ maVer.AddFocusPolygon( tools::Rectangle( mnLine2 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine2 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
+ maRight.AddFocusPolygon( tools::Rectangle( mnLine3 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
+ maTop.AddFocusPolygon( tools::Rectangle( mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine1 + mnFocusOffs ) );
+ maHor.AddFocusPolygon( tools::Rectangle( mnLine1 - mnFocusOffs, mnLine2 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine2 + mnFocusOffs ) );
+ maBottom.AddFocusPolygon( tools::Rectangle( mnLine1 - mnFocusOffs, mnLine3 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
+
+ maTLBR.ClearFocusArea();
+ maBLTR.ClearFocusArea();
+
+ for( nCol = 0, nCols = maArray.GetColCount(); nCol < nCols; ++nCol )
+ {
+ for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow )
+ {
+ const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow ));
+ const tools::Rectangle aRect(
+ basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()),
+ basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY()));
+ const double fHorDiagAngle(atan2(fabs(aCellRange.getHeight()), fabs(aCellRange.getWidth())));
+ const double fVerDiagAngle(fHorDiagAngle > 0.0 ? M_PI_2 - fHorDiagAngle : 0.0);
+ const tools::Long nDiagFocusOffsX(basegfx::fround(-mnFocusOffs / tan(fHorDiagAngle) + mnFocusOffs / sin(fHorDiagAngle)));
+ const tools::Long nDiagFocusOffsY(basegfx::fround(-mnFocusOffs / tan(fVerDiagAngle) + mnFocusOffs / sin(fVerDiagAngle)));
+
+ std::vector< Point > aFocusVec;
+ aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Top() + nDiagFocusOffsY );
+ aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Top() - mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Left() + nDiagFocusOffsX, aRect.Top() - mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Bottom() - nDiagFocusOffsY );
+ aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Bottom() + mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Right() - nDiagFocusOffsX, aRect.Bottom() + mnFocusOffs );
+ maTLBR.AddFocusPolygon( tools::Polygon( static_cast< sal_uInt16 >( aFocusVec.size() ), aFocusVec.data() ) );
+
+ aFocusVec.clear();
+ aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Top() + nDiagFocusOffsY );
+ aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Top() - mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Right() - nDiagFocusOffsX, aRect.Top() - mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Bottom() - nDiagFocusOffsY );
+ aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Bottom() + mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Left() + nDiagFocusOffsX, aRect.Bottom() + mnFocusOffs );
+ maBLTR.AddFocusPolygon( tools::Polygon( static_cast< sal_uInt16 >( aFocusVec.size() ), aFocusVec.data() ) );
+ }
+ }
+
+ // Click areas
+ for( FrameBorderIter aIt( maAllBorders ); aIt.Is(); ++aIt )
+ (*aIt)->ClearClickArea();
+
+ /* Additional space for click area: is added to the space available to draw
+ the frame borders. For instance left frame border:
+ - To left, top, and bottom always big additional space (outer area).
+ - To right: Dependent on existence of inner vertical frame border
+ (if enabled, use less space).
+ */
+ tools::Long nClO = FRAMESEL_GEOM_WIDTH / 2 + FRAMESEL_GEOM_ADD_CLICK_OUTER;
+ tools::Long nClI = (mbTLBR && mbBLTR) ? (FRAMESEL_GEOM_WIDTH / 2 + FRAMESEL_GEOM_ADD_CLICK_INNER) : nClO;
+ tools::Long nClH = mbHor ? nClI : nClO; // additional space dependent of horizontal inner border
+ tools::Long nClV = mbVer ? nClI : nClO; // additional space dependent of vertical inner border
+
+ maLeft.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine1 - nClO, mnLine1 + nClV, mnLine3 + nClO ) );
+ maVer.AddClickRect( tools::Rectangle( mnLine2 - nClI, mnLine1 - nClO, mnLine2 + nClI, mnLine3 + nClO ) );
+ maRight.AddClickRect( tools::Rectangle( mnLine3 - nClV, mnLine1 - nClO, mnLine3 + nClO, mnLine3 + nClO ) );
+ maTop.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine1 - nClO, mnLine3 + nClO, mnLine1 + nClH ) );
+ maHor.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine2 - nClI, mnLine3 + nClO, mnLine2 + nClI ) );
+ maBottom.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine3 - nClH, mnLine3 + nClO, mnLine3 + nClO ) );
+
+ /* Diagonal frame borders use the remaining space between outer and inner frame borders. */
+ if( !(mbTLBR || mbBLTR) )
+ return;
+
+ for( nCol = 0, nCols = maArray.GetColCount(); nCol < nCols; ++nCol )
+ {
+ for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow )
+ {
+ // the usable area between horizontal/vertical frame borders of current quadrant
+ const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow ));
+ const tools::Rectangle aRect(
+ basegfx::fround(aCellRange.getMinX()) + nClV + 1, basegfx::fround(aCellRange.getMinY()) + nClH + 1,
+ basegfx::fround(aCellRange.getMaxX()) - nClV + 1, basegfx::fround(aCellRange.getMaxY()) - nClH + 1);
+
+ /* Both diagonal frame borders enabled. */
+ if( mbTLBR && mbBLTR )
+ {
+ // single areas
+ Point aMid( aRect.Center() );
+ maTLBR.AddClickRect( tools::Rectangle( aRect.TopLeft(), aMid ) );
+ maTLBR.AddClickRect( tools::Rectangle( aMid + Point( 1, 1 ), aRect.BottomRight() ) );
+ maBLTR.AddClickRect( tools::Rectangle( aRect.Left(), aMid.Y() + 1, aMid.X(), aRect.Bottom() ) );
+ maBLTR.AddClickRect( tools::Rectangle( aMid.X() + 1, aRect.Top(), aRect.Right(), aMid.Y() ) );
+ // centered rectangle for both frame borders
+ tools::Rectangle aMidRect( aRect.TopLeft(), Size( aRect.GetWidth() / 3, aRect.GetHeight() / 3 ) );
+ aMidRect.Move( (aRect.GetWidth() - aMidRect.GetWidth()) / 2, (aRect.GetHeight() - aMidRect.GetHeight()) / 2 );
+ maTLBR.AddClickRect( aMidRect );
+ maBLTR.AddClickRect( aMidRect );
+ }
+ /* One of the diagonal frame borders enabled - use entire rectangle. */
+ else if( mbTLBR && !mbBLTR ) // top-left to bottom-right only
+ maTLBR.AddClickRect( aRect );
+ else if( !mbTLBR && mbBLTR ) // bottom-left to top-right only
+ maBLTR.AddClickRect( aRect );
+ }
+ }
+}
+
+void FrameSelectorImpl::InitVirtualDevice()
+{
+ // initialize resources
+ InitColors();
+ InitArrowImageList();
+
+ sizeChanged();
+}
+
+void FrameSelectorImpl::sizeChanged()
+{
+ // initialize geometry
+ InitGlobalGeometry();
+ InitBorderGeometry();
+
+ DoInvalidate( true );
+}
+
+// frame border access
+const FrameBorder& FrameSelectorImpl::GetBorder( FrameBorderType eBorder ) const
+{
+ size_t nIndex = GetIndexFromFrameBorderType( eBorder );
+ if( nIndex < maAllBorders.size() )
+ return *maAllBorders[ nIndex ];
+ SAL_WARN( "svx.dialog", "svx::FrameSelectorImpl::GetBorder - unknown border type" );
+ return maTop;
+}
+
+FrameBorder& FrameSelectorImpl::GetBorderAccess( FrameBorderType eBorder )
+{
+ return const_cast< FrameBorder& >( GetBorder( eBorder ) );
+}
+
+// drawing
+void FrameSelectorImpl::DrawBackground()
+{
+ // clear the area
+ mpVirDev->SetLineColor();
+ mpVirDev->SetFillColor( maBackCol );
+ mpVirDev->DrawRect( tools::Rectangle( Point( 0, 0 ), mpVirDev->GetOutputSizePixel() ) );
+
+ // draw the inner gray (or whatever color) rectangle
+ mpVirDev->SetLineColor();
+ mpVirDev->SetFillColor( maMarkCol );
+ mpVirDev->DrawRect( tools::Rectangle(
+ mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
+
+ // draw the white space for enabled frame borders
+ tools::PolyPolygon aPPoly;
+ for( FrameBorderCIter aIt( maEnabBorders ); aIt.Is(); ++aIt )
+ (*aIt)->MergeFocusToPolyPolygon( aPPoly );
+ aPPoly.Optimize( PolyOptimizeFlags::CLOSE );
+ mpVirDev->SetLineColor( maBackCol );
+ mpVirDev->SetFillColor( maBackCol );
+ mpVirDev->DrawPolyPolygon( aPPoly );
+}
+
+void FrameSelectorImpl::DrawArrows( const FrameBorder& rBorder )
+{
+ DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::DrawArrows - access to disabled border" );
+
+ tools::Long nLinePos = 0;
+ switch( rBorder.GetType() )
+ {
+ case FrameBorderType::Left:
+ case FrameBorderType::Top: nLinePos = mnLine1; break;
+ case FrameBorderType::Vertical:
+ case FrameBorderType::Horizontal: nLinePos = mnLine2; break;
+ case FrameBorderType::Right:
+ case FrameBorderType::Bottom: nLinePos = mnLine3; break;
+ default: ; //prevent warning
+ }
+ nLinePos -= mnArrowSize / 2;
+
+ tools::Long nTLPos = 0;
+ tools::Long nBRPos = mnCtrlSize - mnArrowSize;
+ Point aPos1, aPos2;
+ int nImgIndex1 = -1, nImgIndex2 = -1;
+ switch( rBorder.GetType() )
+ {
+ case FrameBorderType::Left:
+ case FrameBorderType::Right:
+ case FrameBorderType::Vertical:
+ aPos1 = Point( nLinePos, nTLPos ); nImgIndex1 = 0;
+ aPos2 = Point( nLinePos, nBRPos ); nImgIndex2 = 1;
+ break;
+
+ case FrameBorderType::Top:
+ case FrameBorderType::Bottom:
+ case FrameBorderType::Horizontal:
+ aPos1 = Point( nTLPos, nLinePos ); nImgIndex1 = 2;
+ aPos2 = Point( nBRPos, nLinePos ); nImgIndex2 = 3;
+ break;
+
+ case FrameBorderType::TLBR:
+ aPos1 = Point( nTLPos, nTLPos ); nImgIndex1 = 4;
+ aPos2 = Point( nBRPos, nBRPos ); nImgIndex2 = 5;
+ break;
+ case FrameBorderType::BLTR:
+ aPos1 = Point( nTLPos, nBRPos ); nImgIndex1 = 6;
+ aPos2 = Point( nBRPos, nTLPos ); nImgIndex2 = 7;
+ break;
+ default: ; //prevent warning
+ }
+
+ // Arrow or marker? Do not draw arrows into disabled control.
+ sal_uInt16 nSelectAdd = (mrFrameSel.IsEnabled() && rBorder.IsSelected()) ? 0 : 8;
+ if (nImgIndex1 >= 0)
+ mpVirDev->DrawImage(aPos1, maArrows[nImgIndex1 + nSelectAdd]);
+ if (nImgIndex2 >= 0)
+ mpVirDev->DrawImage(aPos2, maArrows[nImgIndex2 + nSelectAdd]);
+}
+
+Color FrameSelectorImpl::GetDrawLineColor( const Color& rColor ) const
+{
+ Color aColor( mbHCMode ? maHCLineCol : rColor );
+ if( aColor == maBackCol )
+ aColor.Invert();
+ return aColor;
+}
+
+void FrameSelectorImpl::DrawAllFrameBorders()
+{
+ // Translate core colors to current UI colors (regards current background and HC mode).
+ for( FrameBorderIter aIt( maEnabBorders ); aIt.Is(); ++aIt )
+ {
+ Color aCoreColorPrim = ((*aIt)->GetState() == FrameBorderState::DontCare) ? maMarkCol : (*aIt)->GetCoreStyle().GetColorOut();
+ Color aCoreColorSecn = ((*aIt)->GetState() == FrameBorderState::DontCare) ? maMarkCol : (*aIt)->GetCoreStyle().GetColorIn();
+ (*aIt)->SetUIColorPrim( GetDrawLineColor( aCoreColorPrim ) );
+ (*aIt)->SetUIColorSecn( GetDrawLineColor( aCoreColorSecn ) );
+ }
+
+ // Copy all frame border styles to the helper array
+ maArray.SetColumnStyleLeft( 0, maLeft.GetUIStyle() );
+ if( mbVer ) maArray.SetColumnStyleLeft( 1, maVer.GetUIStyle() );
+
+ // Invert the style for the right line
+ const frame::Style rRightStyle = maRight.GetUIStyle( );
+ frame::Style rInvertedRight( rRightStyle.GetColorPrim(),
+ rRightStyle.GetColorSecn(), rRightStyle.GetColorGap(),
+ rRightStyle.UseGapColor(),
+ rRightStyle.Secn(), rRightStyle.Dist(), rRightStyle.Prim( ),
+ rRightStyle.Type( ), rRightStyle.PatternScale() );
+ maArray.SetColumnStyleRight( mbVer ? 1 : 0, rInvertedRight );
+
+ maArray.SetRowStyleTop( 0, maTop.GetUIStyle() );
+ if( mbHor )
+ {
+ // Invert the style for the hor line to match the real borders
+ const frame::Style rHorStyle = maHor.GetUIStyle();
+ frame::Style rInvertedHor( rHorStyle.GetColorPrim(),
+ rHorStyle.GetColorSecn(), rHorStyle.GetColorGap(),
+ rHorStyle.UseGapColor(),
+ rHorStyle.Secn(), rHorStyle.Dist(), rHorStyle.Prim( ),
+ rHorStyle.Type(), rHorStyle.PatternScale() );
+ maArray.SetRowStyleTop( 1, rInvertedHor );
+ }
+
+ // Invert the style for the bottom line
+ const frame::Style rBottomStyle = maBottom.GetUIStyle( );
+ frame::Style rInvertedBottom( rBottomStyle.GetColorPrim(),
+ rBottomStyle.GetColorSecn(), rBottomStyle.GetColorGap(),
+ rBottomStyle.UseGapColor(),
+ rBottomStyle.Secn(), rBottomStyle.Dist(), rBottomStyle.Prim( ),
+ rBottomStyle.Type(), rBottomStyle.PatternScale() );
+ maArray.SetRowStyleBottom( mbHor ? 1 : 0, rInvertedBottom );
+
+ for( sal_Int32 nCol = 0; nCol < maArray.GetColCount(); ++nCol )
+ for( sal_Int32 nRow = 0; nRow < maArray.GetRowCount(); ++nRow )
+ maArray.SetCellStyleDiag( nCol, nRow, maTLBR.GetUIStyle(), maBLTR.GetUIStyle() );
+
+ // This is used in the dialog/control for 'Border' attributes. When using
+ // the original paint below instead of primitives, the advantage currently
+ // is the correct visualization of diagonal line(s) including overlaying,
+ // but the rest is bad. Since the edit views use primitives and the preview
+ // should be 'real' I opt for also changing this to primitives. I will
+ // keep the old solution and add a switch (above) based on a static bool so
+ // that interested people may test this out in the debugger.
+ // This is one more hint to enhance the primitive visualization further to
+ // support diagonals better - that's the way to go.
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
+ drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
+ *mpVirDev,
+ aNewViewInformation2D));
+
+ pProcessor2D->process(maArray.CreateB2DPrimitiveArray());
+ pProcessor2D.reset();
+}
+
+void FrameSelectorImpl::DrawVirtualDevice()
+{
+ DrawBackground();
+ for(FrameBorderCIter aIt(maEnabBorders); aIt.Is(); ++aIt)
+ DrawArrows(**aIt);
+ DrawAllFrameBorders();
+ mbFullRepaint = false;
+}
+
+void FrameSelectorImpl::CopyVirDevToControl(vcl::RenderContext& rRenderContext)
+{
+ if (mbFullRepaint)
+ DrawVirtualDevice();
+ rRenderContext.DrawBitmapEx(maVirDevPos, mpVirDev->GetBitmapEx(Point(0, 0), mpVirDev->GetOutputSizePixel()));
+}
+
+void FrameSelectorImpl::DrawAllTrackingRects(vcl::RenderContext& rRenderContext)
+{
+ tools::PolyPolygon aPPoly;
+ if (mrFrameSel.IsAnyBorderSelected())
+ {
+ for(SelFrameBorderCIter aIt( maEnabBorders ); aIt.Is(); ++aIt)
+ (*aIt)->MergeFocusToPolyPolygon(aPPoly);
+ aPPoly.Move(maVirDevPos.X(), maVirDevPos.Y());
+ }
+ else
+ // no frame border selected -> draw tracking rectangle around entire control
+ aPPoly.Insert( tools::Polygon(tools::Rectangle(maVirDevPos, mpVirDev->GetOutputSizePixel())));
+
+ aPPoly.Optimize(PolyOptimizeFlags::CLOSE);
+
+ for(sal_uInt16 nIdx = 0, nCount = aPPoly.Count(); nIdx < nCount; ++nIdx)
+ rRenderContext.Invert(aPPoly.GetObject(nIdx), InvertFlags::TrackFrame);
+}
+
+Point FrameSelectorImpl::GetDevPosFromMousePos( const Point& rMousePos ) const
+{
+ return rMousePos - maVirDevPos;
+}
+
+void FrameSelectorImpl::DoInvalidate( bool bFullRepaint )
+{
+ mbFullRepaint |= bFullRepaint;
+ mrFrameSel.Invalidate();
+}
+
+// frame border state and style
+void FrameSelectorImpl::SetBorderState( FrameBorder& rBorder, FrameBorderState eState )
+{
+ DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SetBorderState - access to disabled border" );
+ Any aOld;
+ Any aNew;
+ Any& rMod = eState == FrameBorderState::Show ? aNew : aOld;
+ rMod <<= AccessibleStateType::CHECKED;
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ rtl::Reference< a11y::AccFrameSelectorChild > xRet;
+ size_t nVecIdx = static_cast< size_t >( rBorder.GetType() );
+ if( GetBorder(rBorder.GetType()).IsEnabled() && (1 <= nVecIdx) && (nVecIdx <= maChildVec.size()) )
+ xRet = maChildVec[ --nVecIdx ].get();
+#endif
+
+ if( eState == FrameBorderState::Show )
+ SetBorderCoreStyle( rBorder, &maCurrStyle );
+ else
+ rBorder.SetState( eState );
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (xRet.is())
+ xRet->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOld, aNew );
+#endif
+
+ DoInvalidate( true );
+}
+
+void FrameSelectorImpl::SetBorderCoreStyle( FrameBorder& rBorder, const SvxBorderLine* pStyle )
+{
+ DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SetBorderCoreStyle - access to disabled border" );
+ rBorder.SetCoreStyle( pStyle );
+ DoInvalidate( true );
+}
+
+void FrameSelectorImpl::ToggleBorderState( FrameBorder& rBorder )
+{
+ bool bDontCare = mrFrameSel.SupportsDontCareState();
+ switch( rBorder.GetState() )
+ {
+ // same order as tristate check box: visible -> don't care -> hidden
+ case FrameBorderState::Show:
+ SetBorderState( rBorder, bDontCare ? FrameBorderState::DontCare : FrameBorderState::Hide );
+ break;
+ case FrameBorderState::Hide:
+ SetBorderState( rBorder, FrameBorderState::Show );
+ break;
+ case FrameBorderState::DontCare:
+ SetBorderState( rBorder, FrameBorderState::Hide );
+ break;
+ }
+}
+
+// frame border selection
+void FrameSelectorImpl::SelectBorder( FrameBorder& rBorder, bool bSelect )
+{
+ DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SelectBorder - access to disabled border" );
+ rBorder.Select( bSelect );
+ DrawArrows( rBorder );
+ DoInvalidate( false );
+}
+
+void FrameSelectorImpl::SilentGrabFocus()
+{
+ bool bOldAuto = mbAutoSelect;
+ mbAutoSelect = false;
+ mrFrameSel.GrabFocus();
+ mbAutoSelect = bOldAuto;
+}
+
+bool FrameSelectorImpl::SelectedBordersEqual() const
+{
+ bool bEqual = true;
+ SelFrameBorderCIter aIt( maEnabBorders );
+ if( aIt.Is() )
+ {
+ const SvxBorderLine& rFirstStyle = (*aIt)->GetCoreStyle();
+ for( ++aIt; bEqual && aIt.Is(); ++aIt )
+ bEqual = ((*aIt)->GetCoreStyle() == rFirstStyle);
+ }
+ return bEqual;
+}
+
+FrameSelector::FrameSelector()
+{
+}
+
+void FrameSelector::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ mxImpl.reset( new FrameSelectorImpl( *this ) );
+ Size aPrefSize = pDrawingArea->get_ref_device().LogicToPixel(Size(61, 65), MapMode(MapUnit::MapAppFont));
+ pDrawingArea->set_size_request(aPrefSize.Width(), aPrefSize.Height());
+ EnableRTL( false ); // #107808# don't mirror the mouse handling
+}
+
+FrameSelector::~FrameSelector()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( mxAccess.is() )
+ mxAccess->Invalidate();
+#endif
+}
+
+void FrameSelector::Initialize( FrameSelFlags nFlags )
+{
+ mxImpl->Initialize( nFlags );
+ Show();
+}
+
+// enabled frame borders
+bool FrameSelector::IsBorderEnabled( FrameBorderType eBorder ) const
+{
+ return mxImpl->GetBorder( eBorder ).IsEnabled();
+}
+
+sal_Int32 FrameSelector::GetEnabledBorderCount() const
+{
+ return static_cast< sal_Int32 >( mxImpl->maEnabBorders.size() );
+}
+
+FrameBorderType FrameSelector::GetEnabledBorderType( sal_Int32 nIndex ) const
+{
+ FrameBorderType eBorder = FrameBorderType::NONE;
+ if( nIndex >= 0 )
+ {
+ size_t nVecIdx = static_cast< size_t >( nIndex );
+ if( nVecIdx < mxImpl->maEnabBorders.size() )
+ eBorder = mxImpl->maEnabBorders[ nVecIdx ]->GetType();
+ }
+ return eBorder;
+}
+
+// frame border state and style
+bool FrameSelector::SupportsDontCareState() const
+{
+ return bool(mxImpl->mnFlags & FrameSelFlags::DontCare);
+}
+
+FrameBorderState FrameSelector::GetFrameBorderState( FrameBorderType eBorder ) const
+{
+ return mxImpl->GetBorder( eBorder ).GetState();
+}
+
+const SvxBorderLine* FrameSelector::GetFrameBorderStyle( FrameBorderType eBorder ) const
+{
+ const SvxBorderLine& rStyle = mxImpl->GetBorder( eBorder ).GetCoreStyle();
+ // rest of the world uses null pointer for invisible frame border
+ return rStyle.GetOutWidth() ? &rStyle : nullptr;
+}
+
+void FrameSelector::ShowBorder( FrameBorderType eBorder, const SvxBorderLine* pStyle )
+{
+ mxImpl->SetBorderCoreStyle( mxImpl->GetBorderAccess( eBorder ), pStyle );
+}
+
+void FrameSelector::SetBorderDontCare( FrameBorderType eBorder )
+{
+ mxImpl->SetBorderState( mxImpl->GetBorderAccess( eBorder ), FrameBorderState::DontCare );
+}
+
+bool FrameSelector::IsAnyBorderVisible() const
+{
+ bool bIsSet = false;
+ for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !bIsSet && aIt.Is(); ++aIt )
+ bIsSet = ((*aIt)->GetState() == FrameBorderState::Show);
+ return bIsSet;
+}
+
+void FrameSelector::HideAllBorders()
+{
+ for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Hide );
+}
+
+bool FrameSelector::GetVisibleWidth( tools::Long& rnWidth, SvxBorderLineStyle& rnStyle ) const
+{
+ VisFrameBorderCIter aIt( mxImpl->maEnabBorders );
+ if( !aIt.Is() )
+ return false;
+
+ const SvxBorderLine& rStyle = (*aIt)->GetCoreStyle();
+ bool bFound = true;
+ for( ++aIt; bFound && aIt.Is(); ++aIt )
+ {
+ bFound =
+ (rStyle.GetWidth() == (*aIt)->GetCoreStyle().GetWidth()) &&
+ (rStyle.GetBorderLineStyle() ==
+ (*aIt)->GetCoreStyle().GetBorderLineStyle());
+ }
+
+ if( bFound )
+ {
+ rnWidth = rStyle.GetWidth();
+ rnStyle = rStyle.GetBorderLineStyle();
+ }
+ return bFound;
+}
+
+bool FrameSelector::GetVisibleColor( Color& rColor ) const
+{
+ VisFrameBorderCIter aIt( mxImpl->maEnabBorders );
+ if( !aIt.Is() )
+ return false;
+
+ const SvxBorderLine& rStyle = (*aIt)->GetCoreStyle();
+ bool bFound = true;
+ for( ++aIt; bFound && aIt.Is(); ++aIt )
+ bFound = (rStyle.GetColor() == (*aIt)->GetCoreStyle().GetColor());
+
+ if( bFound )
+ rColor = rStyle.GetColor();
+ return bFound;
+}
+
+// frame border selection
+const Link<LinkParamNone*,void>& FrameSelector::GetSelectHdl() const
+{
+ return mxImpl->maSelectHdl;
+}
+
+void FrameSelector::SetSelectHdl( const Link<LinkParamNone*,void>& rHdl )
+{
+ mxImpl->maSelectHdl = rHdl;
+}
+
+bool FrameSelector::IsBorderSelected( FrameBorderType eBorder ) const
+{
+ return mxImpl->GetBorder( eBorder ).IsSelected();
+}
+
+void FrameSelector::SelectBorder( FrameBorderType eBorder )
+{
+ mxImpl->SelectBorder( mxImpl->GetBorderAccess( eBorder ), true/*bSelect*/ );
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ // MT: bFireFox as API parameter is ugly...
+ // if (bFocus)
+ {
+ rtl::Reference< a11y::AccFrameSelectorChild > xRet = GetChildAccessible(eBorder);
+ if (xRet.is())
+ {
+ Any aOldValue, aNewValue;
+ aNewValue <<= AccessibleStateType::FOCUSED;
+ xRet->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+ }
+#endif
+}
+
+bool FrameSelector::IsAnyBorderSelected() const
+{
+ // Construct an iterator for selected borders. If it is valid, there is a selected border.
+ return SelFrameBorderCIter( mxImpl->maEnabBorders ).Is();
+}
+
+void FrameSelector::SelectAllBorders( bool bSelect )
+{
+ for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SelectBorder( **aIt, bSelect );
+}
+
+void FrameSelector::SelectAllVisibleBorders()
+{
+ for( VisFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SelectBorder( **aIt, true/*bSelect*/ );
+}
+
+void FrameSelector::SetStyleToSelection( tools::Long nWidth, SvxBorderLineStyle nStyle )
+{
+ mxImpl->maCurrStyle.SetBorderLineStyle( nStyle );
+ mxImpl->maCurrStyle.SetWidth( nWidth );
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
+}
+
+void FrameSelector::SetColorToSelection( const Color& rColor )
+{
+ mxImpl->maCurrStyle.SetColor( rColor );
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
+}
+
+SvxBorderLineStyle FrameSelector::getCurrentStyleLineStyle() const
+{
+ return mxImpl->maCurrStyle.GetBorderLineStyle();
+}
+
+// accessibility
+Reference< XAccessible > FrameSelector::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( !mxAccess.is() )
+ mxAccess = new a11y::AccFrameSelector(*this);
+#endif
+ return mxAccess;
+}
+
+rtl::Reference< a11y::AccFrameSelectorChild > FrameSelector::GetChildAccessible( FrameBorderType eBorder )
+{
+ rtl::Reference< a11y::AccFrameSelectorChild > xRet;
+ size_t nVecIdx = static_cast< size_t >( eBorder );
+ if( IsBorderEnabled( eBorder ) && (1 <= nVecIdx) && (nVecIdx <= mxImpl->maChildVec.size()) )
+ {
+ --nVecIdx;
+ if( !mxImpl->maChildVec[ nVecIdx ].is() )
+ mxImpl->maChildVec[ nVecIdx ] = new a11y::AccFrameSelectorChild( *this, eBorder );
+ xRet = mxImpl->maChildVec[ nVecIdx ].get();
+ }
+ return xRet;
+}
+
+Reference< XAccessible > FrameSelector::GetChildAccessible( sal_Int32 nIndex )
+{
+ return GetChildAccessible( GetEnabledBorderType( nIndex ) );
+}
+
+Reference< XAccessible > FrameSelector::GetChildAccessible( const Point& rPos )
+{
+ Reference< XAccessible > xRet;
+ for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !xRet.is() && aIt.Is(); ++aIt )
+ if( (*aIt)->ContainsClickPoint( rPos ) )
+ xRet = GetChildAccessible( (*aIt)->GetType() ).get();
+ return xRet;
+}
+
+tools::Rectangle FrameSelector::GetClickBoundRect( FrameBorderType eBorder ) const
+{
+ tools::Rectangle aRect;
+ const FrameBorder& rBorder = mxImpl->GetBorder( eBorder );
+ if( rBorder.IsEnabled() )
+ aRect = rBorder.GetClickBoundRect();
+ return aRect;
+}
+
+// virtual functions from base class
+void FrameSelector::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ mxImpl->CopyVirDevToControl(rRenderContext);
+ if (HasFocus())
+ mxImpl->DrawAllTrackingRects(rRenderContext);
+}
+
+bool FrameSelector::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ /* Mouse handling:
+ * Click on an unselected frame border:
+ Set current style/color, make frame border visible, deselect all
+ other frame borders.
+ * Click on a selected frame border:
+ Toggle state of the frame border (visible -> don't care -> hidden),
+ deselect all other frame borders.
+ * SHIFT+Click or CTRL+Click on an unselected frame border:
+ Extend selection, set current style/color to all selected frame
+ borders independent of the state/style/color of the borders.
+ * SHIFT+Click or CTRL+Click on a selected frame border:
+ If all frame borders have same style/color, toggle state of all
+ borders (see above), otherwise set current style/color to all
+ borders.
+ * Click on unused area: Do not modify selection and selected frame
+ borders.
+ */
+
+ // #107394# do not auto-select a frame border
+ mxImpl->SilentGrabFocus();
+
+ if( rMEvt.IsLeft() )
+ {
+ Point aPos( mxImpl->GetDevPosFromMousePos( rMEvt.GetPosPixel() ) );
+ FrameBorderPtrVec aDeselectBorders;
+
+ bool bAnyClicked = false; // Any frame border clicked?
+ bool bNewSelected = false; // Any unselected frame border selected?
+
+ /* If frame borders are set to "don't care" and the control does not
+ support this state, hide them on first mouse click.
+ DR 2004-01-30: Why are the borders set to "don't care" then?!? */
+ bool bHideDontCare = !SupportsDontCareState();
+
+ for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ {
+ if( (*aIt)->ContainsClickPoint( aPos ) )
+ {
+ // frame border is clicked
+ bAnyClicked = true;
+ if( !(*aIt)->IsSelected() )
+ {
+ bNewSelected = true;
+ //mxImpl->SelectBorder( **aIt, true );
+ SelectBorder((**aIt).GetType());
+ }
+ }
+ else
+ {
+ // hide a "don't care" frame border only if it is not clicked
+ if( bHideDontCare && ((*aIt)->GetState() == FrameBorderState::DontCare) )
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Hide );
+
+ // deselect frame borders not clicked (if SHIFT or CTRL are not pressed)
+ if( !rMEvt.IsShift() && !rMEvt.IsMod1() )
+ aDeselectBorders.push_back( *aIt );
+ }
+ }
+
+ if( bAnyClicked )
+ {
+ // any valid frame border clicked? -> deselect other frame borders
+ for( FrameBorderIter aIt( aDeselectBorders ); aIt.Is(); ++aIt )
+ mxImpl->SelectBorder( **aIt, false );
+
+ if( bNewSelected || !mxImpl->SelectedBordersEqual() )
+ {
+ // new frame border selected, selection extended, or selected borders different? -> show
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ // SetBorderState() sets current style and color to the frame border
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
+ }
+ else
+ {
+ // all selected frame borders are equal -> toggle state
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->ToggleBorderState( **aIt );
+ }
+
+ GetSelectHdl().Call( nullptr );
+ }
+ }
+
+ return true;
+}
+
+bool FrameSelector::KeyInput( const KeyEvent& rKEvt )
+{
+ bool bHandled = false;
+ vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
+ if( !aKeyCode.GetModifier() )
+ {
+ sal_uInt16 nCode = aKeyCode.GetCode();
+ switch( nCode )
+ {
+ case KEY_SPACE:
+ {
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->ToggleBorderState( **aIt );
+ bHandled = true;
+ }
+ break;
+
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ {
+ if( !mxImpl->maEnabBorders.empty() )
+ {
+ // start from first selected frame border
+ SelFrameBorderCIter aIt( mxImpl->maEnabBorders );
+ FrameBorderType eBorder = aIt.Is() ? (*aIt)->GetType() : mxImpl->maEnabBorders.front()->GetType();
+
+ // search for next enabled frame border
+ do
+ {
+ eBorder = mxImpl->GetBorder( eBorder ).GetKeyboardNeighbor( nCode );
+ }
+ while( (eBorder != FrameBorderType::NONE) && !IsBorderEnabled( eBorder ) );
+
+ // select the frame border
+ if( eBorder != FrameBorderType::NONE )
+ {
+ DeselectAllBorders();
+ SelectBorder( eBorder );
+ }
+ bHandled = true;
+ }
+ }
+ break;
+ }
+ }
+ if (bHandled)
+ return true;
+ return CustomWidgetController::KeyInput(rKEvt);
+}
+
+void FrameSelector::GetFocus()
+{
+ // auto-selection of a frame border, if focus reaches control, and nothing is selected
+ if( mxImpl->mbAutoSelect && !IsAnyBorderSelected() && !mxImpl->maEnabBorders.empty() )
+ mxImpl->SelectBorder( *mxImpl->maEnabBorders.front(), true );
+
+ mxImpl->DoInvalidate( false );
+ if (IsAnyBorderSelected())
+ {
+ FrameBorderType borderType = FrameBorderType::NONE;
+ if (mxImpl->maLeft.IsSelected())
+ borderType = FrameBorderType::Left;
+ else if (mxImpl->maRight.IsSelected())
+ borderType = FrameBorderType::Right;
+ else if (mxImpl->maTop.IsSelected())
+ borderType = FrameBorderType::Top;
+ else if (mxImpl->maBottom.IsSelected())
+ borderType = FrameBorderType::Bottom;
+ else if (mxImpl->maHor.IsSelected())
+ borderType = FrameBorderType::Horizontal;
+ else if (mxImpl->maVer.IsSelected())
+ borderType = FrameBorderType::Vertical;
+ else if (mxImpl->maTLBR.IsSelected())
+ borderType = FrameBorderType::TLBR;
+ else if (mxImpl->maBLTR.IsSelected())
+ borderType = FrameBorderType::BLTR;
+ SelectBorder(borderType);
+ }
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
+ CustomWidgetController::GetFocus();
+}
+
+void FrameSelector::LoseFocus()
+{
+ mxImpl->DoInvalidate( false );
+ CustomWidgetController::LoseFocus();
+}
+
+void FrameSelector::StyleUpdated()
+{
+ mxImpl->InitVirtualDevice();
+ CustomWidgetController::StyleUpdated();
+}
+
+void FrameSelector::Resize()
+{
+ CustomWidgetController::Resize();
+ mxImpl->sizeChanged();
+}
+
+template< typename Cont, typename Iter, typename Pred >
+FrameBorderIterBase< Cont, Iter, Pred >::FrameBorderIterBase( container_type& rCont ) :
+ maIt( rCont.begin() ),
+ maEnd( rCont.end() )
+{
+ while( Is() && !maPred( *maIt ) ) ++maIt;
+}
+
+template< typename Cont, typename Iter, typename Pred >
+FrameBorderIterBase< Cont, Iter, Pred >& FrameBorderIterBase< Cont, Iter, Pred >::operator++()
+{
+ do { ++maIt; } while( Is() && !maPred( *maIt ) );
+ return *this;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/graphctl.cxx b/svx/source/dialog/graphctl.cxx
new file mode 100644
index 000000000..136eae27b
--- /dev/null
+++ b/svx/source/dialog/graphctl.cxx
@@ -0,0 +1,850 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_wasm_strip.h>
+
+#include <svl/itempool.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/svapp.hxx>
+
+#include <svx/graphctl.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <GraphCtlAccessibleContext.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svdpage.hxx>
+#include <svx/sdrpaintwindow.hxx>
+
+void GraphCtrlUserCall::Changed( const SdrObject& rObj, SdrUserCallType eType, const tools::Rectangle& /*rOldBoundRect*/ )
+{
+ switch( eType )
+ {
+ case SdrUserCallType::MoveOnly:
+ case SdrUserCallType::Resize:
+ rWin.SdrObjChanged( rObj );
+ break;
+
+ case SdrUserCallType::Inserted:
+ rWin.SdrObjCreated( rObj );
+ break;
+
+ default:
+ break;
+ }
+ rWin.QueueIdleUpdate();
+}
+
+GraphCtrl::GraphCtrl(weld::Dialog* pDialog)
+ : aUpdateIdle("svx GraphCtrl Update")
+ , aMap100(MapUnit::Map100thMM)
+ , eObjKind(SdrObjKind::NONE)
+ , nPolyEdit(0)
+ , bEditMode(false)
+ , mbSdrMode(false)
+ , mbInIdleUpdate(false)
+ , mpDialog(pDialog)
+{
+ pUserCall.reset(new GraphCtrlUserCall( *this ));
+ aUpdateIdle.SetPriority( TaskPriority::LOWEST );
+ aUpdateIdle.SetInvokeHandler( LINK( this, GraphCtrl, UpdateHdl ) );
+ aUpdateIdle.Start();
+}
+
+void GraphCtrl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+ EnableRTL(false);
+}
+
+GraphCtrl::~GraphCtrl()
+{
+ aUpdateIdle.Stop();
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( mpAccContext.is() )
+ {
+ mpAccContext->disposing();
+ mpAccContext.clear();
+ }
+#endif
+
+ pView.reset();
+ pModel.reset();
+ pUserCall.reset();
+}
+
+void GraphCtrl::SetSdrMode(bool bSdrMode)
+{
+ mbSdrMode = bSdrMode;
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ rDevice.SetBackground( Wallpaper( rStyleSettings.GetWindowColor() ) );
+ xVD->SetBackground( Wallpaper( rStyleSettings.GetWindowColor() ) );
+ rDevice.SetMapMode( aMap100 );
+ xVD->SetMapMode( aMap100 );
+
+ pView.reset();
+ pModel.reset();
+
+ if ( mbSdrMode )
+ InitSdrModel();
+
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::InitSdrModel()
+{
+ SolarMutexGuard aGuard;
+
+ rtl::Reference<SdrPage> pPage;
+
+ // destroy old junk
+ pView.reset();
+ pModel.reset();
+
+ // Creating a Model
+ pModel.reset(new SdrModel(nullptr, nullptr, true));
+ pModel->GetItemPool().FreezeIdRanges();
+ pModel->SetScaleUnit( aMap100.GetMapUnit() );
+ pModel->SetScaleFraction( Fraction( 1, 1 ) );
+ pModel->SetDefaultFontHeight( 500 );
+
+ pPage = new SdrPage( *pModel );
+
+ pPage->SetSize( aGraphSize );
+ pPage->SetBorder( 0, 0, 0, 0 );
+ pModel->InsertPage( pPage.get() );
+ pModel->SetChanged( false );
+
+ // Creating a View
+ pView.reset(new GraphCtrlView(*pModel, this));
+ pView->SetWorkArea( tools::Rectangle( Point(), aGraphSize ) );
+ pView->EnableExtendedMouseEventDispatcher( true );
+ pView->ShowSdrPage(pView->GetModel()->GetPage(0));
+ pView->SetFrameDragSingles();
+ pView->SetMarkedPointsSmooth( SdrPathSmoothKind::Symmetric );
+ pView->SetEditMode();
+
+ // #i72889# set needed flags
+ pView->SetPagePaintingAllowed(false);
+ pView->SetBufferedOutputAllowed(true);
+ pView->SetBufferedOverlayAllowed(true);
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ // Tell the accessibility object about the changes.
+ if (mpAccContext.is())
+ mpAccContext->setModelAndView (pModel.get(), pView.get());
+#endif
+}
+
+void GraphCtrl::SetGraphic( const Graphic& rGraphic, bool bNewModel )
+{
+ aGraphic = rGraphic;
+ xVD->SetOutputSizePixel(Size(0, 0)); //force redraw
+
+ if ( aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
+ aGraphSize = Application::GetDefaultDevice()->PixelToLogic( aGraphic.GetPrefSize(), aMap100 );
+ else
+ aGraphSize = OutputDevice::LogicToLogic( aGraphic.GetPrefSize(), aGraphic.GetPrefMapMode(), aMap100 );
+
+ if ( mbSdrMode && bNewModel )
+ InitSdrModel();
+
+ aGraphSizeLink.Call( this );
+
+ Resize();
+
+ Invalidate();
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::GraphicToVD()
+{
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ xVD->SetOutputSizePixel(GetOutputSizePixel());
+ xVD->SetBackground(rDevice.GetBackground());
+ xVD->Erase();
+ const bool bGraphicValid(GraphicType::NONE != aGraphic.GetType());
+ if (bGraphicValid)
+ aGraphic.Draw(*xVD, Point(), aGraphSize);
+}
+
+void GraphCtrl::Resize()
+{
+ weld::CustomWidgetController::Resize();
+
+ if (aGraphSize.Width() && aGraphSize.Height())
+ {
+ MapMode aDisplayMap( aMap100 );
+ Point aNewPos;
+ Size aNewSize;
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ const Size aWinSize = rDevice.PixelToLogic( GetOutputSizePixel(), aDisplayMap );
+ const tools::Long nWidth = aWinSize.Width();
+ const tools::Long nHeight = aWinSize.Height();
+ double fGrfWH = static_cast<double>(aGraphSize.Width()) / aGraphSize.Height();
+ double fWinWH = static_cast<double>(nWidth) / nHeight;
+
+ // Adapt Bitmap to Thumb size
+ if ( fGrfWH < fWinWH)
+ {
+ aNewSize.setWidth( static_cast<tools::Long>( static_cast<double>(nHeight) * fGrfWH ) );
+ aNewSize.setHeight( nHeight );
+ }
+ else
+ {
+ aNewSize.setWidth( nWidth );
+ aNewSize.setHeight( static_cast<tools::Long>( static_cast<double>(nWidth) / fGrfWH ) );
+ }
+
+ aNewPos.setX( ( nWidth - aNewSize.Width() ) >> 1 );
+ aNewPos.setY( ( nHeight - aNewSize.Height() ) >> 1 );
+
+ // Implementing MapMode for Engine
+ aDisplayMap.SetScaleX( Fraction( aNewSize.Width(), aGraphSize.Width() ) );
+ aDisplayMap.SetScaleY( Fraction( aNewSize.Height(), aGraphSize.Height() ) );
+
+ aDisplayMap.SetOrigin( OutputDevice::LogicToLogic( aNewPos, aMap100, aDisplayMap ) );
+ rDevice.SetMapMode( aDisplayMap );
+ xVD->SetMapMode( aDisplayMap );
+ }
+
+ Invalidate();
+}
+
+void GraphCtrl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ // #i72889# used split repaint to be able to paint an own background
+ // even to the buffered view
+ const bool bGraphicValid(GraphicType::NONE != aGraphic.GetType());
+
+ if (GetOutputSizePixel() != xVD->GetOutputSizePixel())
+ GraphicToVD();
+
+ if (mbSdrMode)
+ {
+ SdrPaintWindow* pPaintWindow = pView->BeginCompleteRedraw(&rRenderContext);
+ pPaintWindow->SetOutputToWindow(true);
+
+ if (bGraphicValid)
+ {
+ vcl::RenderContext& rTarget = pPaintWindow->GetTargetOutputDevice();
+
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ rTarget.SetBackground(rDevice.GetBackground());
+ rTarget.Erase();
+
+ rTarget.DrawOutDev(Point(), xVD->GetOutputSize(), Point(), xVD->GetOutputSize(), *xVD);
+ }
+
+ const vcl::Region aRepaintRegion(rRect);
+ pView->DoCompleteRedraw(*pPaintWindow, aRepaintRegion);
+ pView->EndCompleteRedraw(*pPaintWindow, true);
+ }
+ else
+ {
+ // #i73381# in non-SdrMode, paint to local directly
+ rRenderContext.DrawOutDev(rRect.TopLeft(), rRect.GetSize(),
+ rRect.TopLeft(), rRect.GetSize(),
+ *xVD);
+ }
+}
+
+void GraphCtrl::SdrObjChanged( const SdrObject& )
+{
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::SdrObjCreated( const SdrObject& )
+{
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::MarkListHasChanged()
+{
+ QueueIdleUpdate();
+}
+
+bool GraphCtrl::KeyInput( const KeyEvent& rKEvt )
+{
+ vcl::KeyCode aCode( rKEvt.GetKeyCode() );
+ bool bProc = false;
+
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+
+ switch ( aCode.GetCode() )
+ {
+ case KEY_DELETE:
+ case KEY_BACKSPACE:
+ {
+ if ( mbSdrMode )
+ {
+ pView->DeleteMarked();
+ bProc = true;
+ }
+ }
+ break;
+
+ case KEY_ESCAPE:
+ {
+ if ( mbSdrMode )
+ {
+ if ( pView->IsAction() )
+ {
+ pView->BrkAction();
+ bProc = true;
+ }
+ else if ( pView->AreObjectsMarked() )
+ {
+ pView->UnmarkAllObj();
+ bProc = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_F11:
+ case KEY_TAB:
+ {
+ if( mbSdrMode )
+ {
+ if( !aCode.IsMod1() && !aCode.IsMod2() )
+ {
+ bool bForward = !aCode.IsShift();
+ // select next object
+ if ( ! pView->MarkNextObj( bForward ))
+ {
+ // At first or last object. Cycle to the other end
+ // of the list.
+ pView->UnmarkAllObj();
+ pView->MarkNextObj (bForward);
+ }
+ bProc = true;
+ }
+ else if(aCode.IsMod1())
+ {
+ // select next handle
+ const SdrHdlList& rHdlList = pView->GetHdlList();
+ bool bForward(!aCode.IsShift());
+
+ const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward);
+
+ bProc = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_END:
+ {
+
+ if ( aCode.IsMod1() )
+ {
+ // mark last object
+ pView->UnmarkAllObj();
+ pView->MarkNextObj();
+
+ bProc = true;
+ }
+ }
+ break;
+
+ case KEY_HOME:
+ {
+ if ( aCode.IsMod1() )
+ {
+ pView->UnmarkAllObj();
+ pView->MarkNextObj(true);
+
+ bProc = true;
+ }
+ }
+ break;
+
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ {
+ tools::Long nX = 0;
+ tools::Long nY = 0;
+
+ if (aCode.GetCode() == KEY_UP)
+ {
+ // Scroll up
+ nX = 0;
+ nY =-1;
+ }
+ else if (aCode.GetCode() == KEY_DOWN)
+ {
+ // Scroll down
+ nX = 0;
+ nY = 1;
+ }
+ else if (aCode.GetCode() == KEY_LEFT)
+ {
+ // Scroll left
+ nX =-1;
+ nY = 0;
+ }
+ else if (aCode.GetCode() == KEY_RIGHT)
+ {
+ // Scroll right
+ nX = 1;
+ nY = 0;
+ }
+
+ if (pView->AreObjectsMarked() && !aCode.IsMod1() )
+ {
+ if(aCode.IsMod2())
+ {
+ // move in 1 pixel distance
+ Size aLogicSizeOnePixel = rDevice.PixelToLogic(Size(1,1));
+ nX *= aLogicSizeOnePixel.Width();
+ nY *= aLogicSizeOnePixel.Height();
+ }
+ else
+ {
+ // old, fixed move distance
+ nX *= 100;
+ nY *= 100;
+ }
+
+ // II
+ const SdrHdlList& rHdlList = pView->GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(nullptr == pHdl)
+ {
+ // restrict movement to WorkArea
+ const tools::Rectangle& rWorkArea = pView->GetWorkArea();
+
+ if(!rWorkArea.IsEmpty())
+ {
+ tools::Rectangle aMarkRect(pView->GetMarkedObjRect());
+ aMarkRect.Move(nX, nY);
+
+ if(!aMarkRect.Contains(rWorkArea))
+ {
+ if(aMarkRect.Left() < rWorkArea.Left())
+ {
+ nX += rWorkArea.Left() - aMarkRect.Left();
+ }
+
+ if(aMarkRect.Right() > rWorkArea.Right())
+ {
+ nX -= aMarkRect.Right() - rWorkArea.Right();
+ }
+
+ if(aMarkRect.Top() < rWorkArea.Top())
+ {
+ nY += rWorkArea.Top() - aMarkRect.Top();
+ }
+
+ if(aMarkRect.Bottom() > rWorkArea.Bottom())
+ {
+ nY -= aMarkRect.Bottom() - rWorkArea.Bottom();
+ }
+ }
+ }
+
+ // no handle selected
+ if(0 != nX || 0 != nY)
+ {
+ pView->MoveAllMarked(Size(nX, nY));
+ }
+ }
+ else
+ {
+ // move handle with index nHandleIndex
+ if (nX || nY)
+ {
+ // now move the Handle (nX, nY)
+ Point aStartPoint(pHdl->GetPos());
+ Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
+ const SdrDragStat& rDragStat = pView->GetDragStat();
+
+ // start dragging
+ pView->BegDragObj(aStartPoint, nullptr, pHdl, 0);
+
+ if(pView->IsDragObj())
+ {
+ bool bWasNoSnap = rDragStat.IsNoSnap();
+ bool bWasSnapEnabled = pView->IsSnapEnabled();
+
+ // switch snapping off
+ if(!bWasNoSnap)
+ const_cast<SdrDragStat&>(rDragStat).SetNoSnap();
+ if(bWasSnapEnabled)
+ pView->SetSnapEnabled(false);
+
+ pView->MovAction(aEndPoint);
+ pView->EndDragObj();
+
+ // restore snap
+ if(!bWasNoSnap)
+ const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap);
+ if(bWasSnapEnabled)
+ pView->SetSnapEnabled(bWasSnapEnabled);
+ }
+ }
+ }
+
+ bProc = true;
+ }
+ }
+ break;
+
+ case KEY_SPACE:
+ {
+ const SdrHdlList& rHdlList = pView->GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(pHdl)
+ {
+ if(pHdl->GetKind() == SdrHdlKind::Poly)
+ {
+ // rescue ID of point with focus
+ sal_uInt32 nPol(pHdl->GetPolyNum());
+ sal_uInt32 nPnt(pHdl->GetPointNum());
+
+ if(pView->IsPointMarked(*pHdl))
+ {
+ if(rKEvt.GetKeyCode().IsShift())
+ {
+ pView->UnmarkPoint(*pHdl);
+ }
+ }
+ else
+ {
+ if(!rKEvt.GetKeyCode().IsShift())
+ {
+ pView->UnmarkAllPoints();
+ }
+
+ pView->MarkPoint(*pHdl);
+ }
+
+ if(nullptr == rHdlList.GetFocusHdl())
+ {
+ // restore point with focus
+ SdrHdl* pNewOne = nullptr;
+
+ for(size_t a = 0; !pNewOne && a < rHdlList.GetHdlCount(); ++a)
+ {
+ SdrHdl* pAct = rHdlList.GetHdl(a);
+
+ if(pAct
+ && pAct->GetKind() == SdrHdlKind::Poly
+ && pAct->GetPolyNum() == nPol
+ && pAct->GetPointNum() == nPnt)
+ {
+ pNewOne = pAct;
+ }
+ }
+
+ if(pNewOne)
+ {
+ const_cast<SdrHdlList&>(rHdlList).SetFocusHdl(pNewOne);
+ }
+ }
+
+ bProc = true;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (bProc)
+ ReleaseMouse();
+
+ QueueIdleUpdate();
+
+ return bProc;
+}
+
+bool GraphCtrl::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( mbSdrMode && ( rMEvt.GetClicks() < 2 ) )
+ {
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+
+ const Point aLogPt( rDevice.PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ if ( !tools::Rectangle( Point(), aGraphSize ).Contains( aLogPt ) && !pView->IsEditMode() )
+ weld::CustomWidgetController::MouseButtonDown( rMEvt );
+ else
+ {
+ // Get Focus for key inputs
+ GrabFocus();
+
+ if ( nPolyEdit )
+ {
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = pView->PickAnything( rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt );
+
+ if ( nPolyEdit == SID_BEZIER_INSERT && eHit == SdrHitKind::MarkedObject )
+ pView->BegInsObjPoint( aLogPt, rMEvt.IsMod1());
+ else
+ pView->MouseButtonDown( rMEvt, &rDevice );
+ }
+ else
+ pView->MouseButtonDown( rMEvt, &rDevice );
+ }
+
+ SdrObject* pCreateObj = pView->GetCreateObj();
+
+ // We want to realize the insert
+ if ( pCreateObj && !pCreateObj->GetUserCall() )
+ pCreateObj->SetUserCall( pUserCall.get() );
+
+ SetPointer( pView->GetPreferredPointer( aLogPt, &rDevice ) );
+ }
+ else
+ weld::CustomWidgetController::MouseButtonDown( rMEvt );
+
+ QueueIdleUpdate();
+
+ return false;
+}
+
+bool GraphCtrl::MouseMove(const MouseEvent& rMEvt)
+{
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ const Point aLogPos( rDevice.PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ if ( mbSdrMode )
+ {
+ pView->MouseMove( rMEvt, &rDevice );
+
+ if( ( SID_BEZIER_INSERT == nPolyEdit ) &&
+ !pView->PickHandle( aLogPos ) &&
+ !pView->IsInsObjPoint() )
+ {
+ SetPointer( PointerStyle::Cross );
+ }
+ else
+ SetPointer( pView->GetPreferredPointer( aLogPos, &rDevice ) );
+ }
+ else
+ weld::CustomWidgetController::MouseButtonUp( rMEvt );
+
+ if ( aMousePosLink.IsSet() )
+ {
+ if ( tools::Rectangle( Point(), aGraphSize ).Contains( aLogPos ) )
+ aMousePos = aLogPos;
+ else
+ aMousePos = Point();
+
+ aMousePosLink.Call( this );
+ }
+
+ QueueIdleUpdate();
+
+ return false;
+}
+
+bool GraphCtrl::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if ( mbSdrMode )
+ {
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+
+ if ( pView->IsInsObjPoint() )
+ pView->EndInsObjPoint( SdrCreateCmd::ForceEnd );
+ else
+ pView->MouseButtonUp( rMEvt, &rDevice );
+
+ ReleaseMouse();
+ SetPointer( pView->GetPreferredPointer( rDevice.PixelToLogic( rMEvt.GetPosPixel() ), &rDevice ) );
+ }
+ else
+ weld::CustomWidgetController::MouseButtonUp( rMEvt );
+
+ QueueIdleUpdate();
+
+ return false;
+}
+
+SdrObject* GraphCtrl::GetSelectedSdrObject() const
+{
+ SdrObject* pSdrObj = nullptr;
+
+ if ( mbSdrMode )
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ if ( rMarkList.GetMarkCount() == 1 )
+ pSdrObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ }
+
+ return pSdrObj;
+}
+
+void GraphCtrl::SetEditMode( const bool _bEditMode )
+{
+ if ( mbSdrMode )
+ {
+ bEditMode = _bEditMode;
+ pView->SetEditMode( bEditMode );
+ eObjKind = SdrObjKind::NONE;
+ pView->SetCurrentObj(eObjKind);
+ }
+ else
+ bEditMode = false;
+
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::SetPolyEditMode( const sal_uInt16 _nPolyEdit )
+{
+ if ( mbSdrMode && ( _nPolyEdit != nPolyEdit ) )
+ {
+ nPolyEdit = _nPolyEdit;
+ pView->SetFrameDragSingles( nPolyEdit == 0 );
+ }
+ else
+ nPolyEdit = 0;
+
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::SetObjKind( const SdrObjKind _eObjKind )
+{
+ if ( mbSdrMode )
+ {
+ bEditMode = false;
+ pView->SetEditMode( bEditMode );
+ eObjKind = _eObjKind;
+ pView->SetCurrentObj(eObjKind);
+ }
+ else
+ eObjKind = SdrObjKind::NONE;
+
+ QueueIdleUpdate();
+}
+
+IMPL_LINK_NOARG(GraphCtrl, UpdateHdl, Timer *, void)
+{
+ mbInIdleUpdate = true;
+ aUpdateLink.Call( this );
+ mbInIdleUpdate = false;
+}
+
+void GraphCtrl::QueueIdleUpdate()
+{
+ if (!mbInIdleUpdate)
+ aUpdateIdle.Start();
+}
+
+namespace
+{
+ class WeldOverlayManager final : public sdr::overlay::OverlayManager
+ {
+ weld::CustomWidgetController& m_rGraphCtrl;
+
+ public:
+ WeldOverlayManager(weld::CustomWidgetController& rGraphCtrl, OutputDevice& rDevice)
+ : OverlayManager(rDevice)
+ , m_rGraphCtrl(rGraphCtrl)
+ {
+ }
+
+ // invalidate the given range at local OutputDevice
+ virtual void invalidateRange(const basegfx::B2DRange& rRange) override
+ {
+ tools::Rectangle aInvalidateRectangle(RangeToInvalidateRectangle(rRange));
+ m_rGraphCtrl.Invalidate(aInvalidateRectangle);
+ }
+ };
+}
+
+rtl::Reference<sdr::overlay::OverlayManager> GraphCtrlView::CreateOverlayManager(OutputDevice& rDevice) const
+{
+ assert(&rDevice == &rGraphCtrl.GetDrawingArea()->get_ref_device());
+ if (rDevice.GetOutDevType() == OUTDEV_VIRDEV)
+ {
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager(new WeldOverlayManager(rGraphCtrl, rDevice));
+ InitOverlayManager(xOverlayManager);
+ return xOverlayManager;
+ }
+ return SdrView::CreateOverlayManager(rDevice);
+}
+
+void GraphCtrlView::InvalidateOneWin(OutputDevice& rDevice)
+{
+ assert(&rDevice == &rGraphCtrl.GetDrawingArea()->get_ref_device());
+ if (rDevice.GetOutDevType() == OUTDEV_VIRDEV)
+ {
+ rGraphCtrl.Invalidate();
+ return;
+ }
+ SdrView::InvalidateOneWin(rDevice);
+}
+
+void GraphCtrlView::InvalidateOneWin(OutputDevice& rDevice, const tools::Rectangle& rArea)
+{
+ assert(&rDevice == &rGraphCtrl.GetDrawingArea()->get_ref_device());
+ if (rDevice.GetOutDevType() == OUTDEV_VIRDEV)
+ {
+ rGraphCtrl.Invalidate(rArea);
+ return;
+ }
+ SdrView::InvalidateOneWin(rDevice, rArea);
+}
+
+GraphCtrlView::~GraphCtrlView()
+{
+ // turn SetOutputToWindow back off again before
+ // turning back into our baseclass during dtoring
+ const sal_uInt32 nWindowCount(PaintWindowCount());
+ for (sal_uInt32 nWinNum(0); nWinNum < nWindowCount; nWinNum++)
+ {
+ SdrPaintWindow* pPaintWindow = GetPaintWindow(nWinNum);
+ pPaintWindow->SetOutputToWindow(false);
+ }
+}
+
+Point GraphCtrl::GetPositionInDialog() const
+{
+ int x, y, width, height;
+ if (GetDrawingArea()->get_extents_relative_to(*mpDialog, x, y, width, height))
+ return Point(x, y);
+ return Point();
+}
+
+css::uno::Reference< css::accessibility::XAccessible > GraphCtrl::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if(mpAccContext == nullptr )
+ {
+ // Disable accessibility if no model/view data available
+ if (pView && pModel)
+ mpAccContext = new SvxGraphCtrlAccessibleContext(*this);
+ }
+#endif
+ return mpAccContext;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/grfflt.cxx b/svx/source/dialog/grfflt.cxx
new file mode 100644
index 000000000..81b928900
--- /dev/null
+++ b/svx/source/dialog/grfflt.cxx
@@ -0,0 +1,294 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/BitmapSharpenFilter.hxx>
+#include <vcl/BitmapMedianFilter.hxx>
+#include <vcl/BitmapSobelGreyFilter.hxx>
+#include <vcl/BitmapPopArtFilter.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+
+#include <osl/diagnose.h>
+#include <svx/grfflt.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svxdlg.hxx>
+
+
+SvxGraphicFilterResult SvxGraphicFilter::ExecuteGrfFilterSlot( SfxRequest const & rReq, GraphicObject& rFilterObject )
+{
+ const Graphic& rGraphic = rFilterObject.GetGraphic();
+ SvxGraphicFilterResult nRet = SvxGraphicFilterResult::UnsupportedGraphicType;
+
+ if( rGraphic.GetType() == GraphicType::Bitmap )
+ {
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ SfxObjectShell* pShell = pViewFrame ? pViewFrame->GetObjectShell() : nullptr;
+ weld::Window* pFrameWeld = (pViewFrame && pViewFrame->GetViewShell()) ? pViewFrame->GetViewShell()->GetFrameWeld() : nullptr;
+ Graphic aGraphic;
+
+ switch( rReq.GetSlot() )
+ {
+ case SID_GRFFILTER_INVERT:
+ {
+ if( pShell )
+ pShell->SetWaitCursor( true );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnimation( rGraphic.GetAnimation() );
+
+ if( aAnimation.Invert() )
+ aGraphic = aAnimation;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if( aBmpEx.Invert() )
+ aGraphic = aBmpEx;
+ }
+
+ if( pShell )
+ pShell->SetWaitCursor( false );
+ }
+ break;
+
+ case SID_GRFFILTER_SMOOTH:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterSmooth(pFrameWeld, rGraphic, 0.7));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER_SHARPEN:
+ {
+ if( pShell )
+ pShell->SetWaitCursor( true );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnimation( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnimation, BitmapSharpenFilter()))
+ aGraphic = aAnimation;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapSharpenFilter()))
+ aGraphic = aBmpEx;
+ }
+
+ if( pShell )
+ pShell->SetWaitCursor( false );
+ }
+ break;
+
+ case SID_GRFFILTER_REMOVENOISE:
+ {
+ if( pShell )
+ pShell->SetWaitCursor( true );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnimation( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnimation, BitmapMedianFilter()))
+ aGraphic = aAnimation;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapMedianFilter()))
+ aGraphic = aBmpEx;
+ }
+
+ if( pShell )
+ pShell->SetWaitCursor( false );
+ }
+ break;
+
+ case SID_GRFFILTER_SOBEL:
+ {
+ if( pShell )
+ pShell->SetWaitCursor( true );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnimation( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnimation, BitmapSobelGreyFilter()))
+ aGraphic = aAnimation;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapSobelGreyFilter()))
+ aGraphic = aBmpEx;
+ }
+
+ if( pShell )
+ pShell->SetWaitCursor( false );
+ }
+ break;
+
+ case SID_GRFFILTER_MOSAIC:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterMosaic(pFrameWeld, rGraphic));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER_EMBOSS:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterEmboss(pFrameWeld, rGraphic));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER_POSTER:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterPoster(pFrameWeld, rGraphic));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER_POPART:
+ {
+ if( pShell )
+ pShell->SetWaitCursor( true );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnimation( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnimation, BitmapPopArtFilter()))
+ aGraphic = aAnimation;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapPopArtFilter()))
+ aGraphic = aBmpEx;
+ }
+
+ if( pShell )
+ pShell->SetWaitCursor( false );
+ }
+ break;
+
+ case SID_GRFFILTER_SEPIA:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterSepia(pFrameWeld, rGraphic));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER_SOLARIZE:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterSolarize(pFrameWeld, rGraphic));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER :
+ {
+ // do nothing; no error
+ nRet = SvxGraphicFilterResult::NONE;
+ break;
+ }
+
+ default:
+ {
+ OSL_FAIL( "SvxGraphicFilter: selected filter slot not yet implemented" );
+ nRet = SvxGraphicFilterResult::UnsupportedSlot;
+ }
+ break;
+ }
+
+ if( aGraphic.GetType() != GraphicType::NONE )
+ {
+ rFilterObject.SetGraphic( aGraphic );
+ nRet = SvxGraphicFilterResult::NONE;
+ }
+ }
+
+ return nRet;
+}
+
+
+void SvxGraphicFilter::DisableGraphicFilterSlots( SfxItemSet& rSet )
+{
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER ) )
+ rSet.DisableItem( SID_GRFFILTER );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_INVERT ) )
+ rSet.DisableItem( SID_GRFFILTER_INVERT );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_SMOOTH ) )
+ rSet.DisableItem( SID_GRFFILTER_SMOOTH );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_SHARPEN ) )
+ rSet.DisableItem( SID_GRFFILTER_SHARPEN );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_REMOVENOISE ) )
+ rSet.DisableItem( SID_GRFFILTER_REMOVENOISE );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_SOBEL ) )
+ rSet.DisableItem( SID_GRFFILTER_SOBEL );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_MOSAIC ) )
+ rSet.DisableItem( SID_GRFFILTER_MOSAIC );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_EMBOSS ) )
+ rSet.DisableItem( SID_GRFFILTER_EMBOSS );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_POSTER ) )
+ rSet.DisableItem( SID_GRFFILTER_POSTER );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_POPART ) )
+ rSet.DisableItem( SID_GRFFILTER_POPART );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_SEPIA ) )
+ rSet.DisableItem( SID_GRFFILTER_SEPIA );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_SOLARIZE ) )
+ rSet.DisableItem( SID_GRFFILTER_SOLARIZE );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/hdft.cxx b/svx/source/dialog/hdft.cxx
new file mode 100644
index 000000000..9f0985ad1
--- /dev/null
+++ b/svx/source/dialog/hdft.cxx
@@ -0,0 +1,1052 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/unit_conversion.hxx>
+#include <svl/itemiter.hxx>
+#include <sfx2/objsh.hxx>
+#include <svx/svxids.hrc>
+
+#include <svl/intitem.hxx>
+#include <svtools/unitconv.hxx>
+
+#include <svx/hdft.hxx>
+#include <svx/pageitem.hxx>
+
+#include <svx/dlgutil.hxx>
+#include <sfx2/htmlmode.hxx>
+#include <osl/diagnose.h>
+
+#include <editeng/brushitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/boxitem.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <memory>
+
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/unobrushitemhelper.hxx>
+
+using namespace com::sun::star;
+
+// Word 97 incompatibility (#i19922#)
+// #i19922# - tdf#126051 see cui/source/tabpages/page.cxx and sw/source/uibase/sidebar/PageMarginControl.hxx
+constexpr tools::Long MINBODY = o3tl::toTwips(1, o3tl::Length::mm); // 1mm in twips rounded
+
+// default distance to Header or footer
+const tools::Long DEF_DIST_WRITER = 500; // 5mm (Writer)
+const tools::Long DEF_DIST_CALC = 250; // 2.5mm (Calc)
+
+const WhichRangesContainer SvxHFPage::pRanges(svl::Items<
+ // Support DrawingLayer FillStyles (no real call to below GetRanges()
+ // detected, still do the complete transition)
+ XATTR_FILL_FIRST, XATTR_FILL_LAST,
+
+ SID_ATTR_BRUSH, SID_ATTR_BRUSH,
+ SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER,
+ SID_ATTR_BORDER_OUTER, SID_ATTR_BORDER_OUTER,
+ SID_ATTR_BORDER_SHADOW, SID_ATTR_BORDER_SHADOW,
+ SID_ATTR_LRSPACE, SID_ATTR_LRSPACE,
+ SID_ATTR_ULSPACE, SID_ATTR_ULSPACE,
+ SID_ATTR_PAGE_SIZE, SID_ATTR_PAGE_SIZE,
+ SID_ATTR_PAGE_HEADERSET, SID_ATTR_PAGE_HEADERSET,
+ SID_ATTR_PAGE_FOOTERSET, SID_ATTR_PAGE_FOOTERSET,
+ SID_ATTR_PAGE_ON, SID_ATTR_PAGE_ON,
+ SID_ATTR_PAGE_DYNAMIC, SID_ATTR_PAGE_DYNAMIC,
+ SID_ATTR_PAGE_SHARED, SID_ATTR_PAGE_SHARED,
+ SID_ATTR_HDFT_DYNAMIC_SPACING, SID_ATTR_HDFT_DYNAMIC_SPACING,
+ SID_ATTR_PAGE_SHARED_FIRST, SID_ATTR_PAGE_SHARED_FIRST
+>);
+
+namespace svx {
+
+ bool ShowBorderBackgroundDlg(weld::Window* pParent, SfxItemSet* pBBSet)
+ {
+ bool bRes = false;
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSvxBorderBackgroundDlg(pParent, *pBBSet, true /*bEnableDrawingLayerFillStyles*/));
+ if ( pDlg->Execute() == RET_OK && pDlg->GetOutputItemSet() )
+ {
+ SfxItemIter aIter( *pDlg->GetOutputItemSet() );
+
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
+ {
+ if ( !IsInvalidItem( pItem ) )
+ pBBSet->Put( *pItem );
+ }
+ bRes = true;
+ }
+ return bRes;
+ }
+}
+
+std::unique_ptr<SfxTabPage> SvxHeaderPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
+{
+ return std::make_unique<SvxHeaderPage>( pPage, pController, *rSet );
+}
+
+std::unique_ptr<SfxTabPage> SvxFooterPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
+{
+ return std::make_unique<SvxFooterPage>( pPage, pController, *rSet );
+}
+
+SvxHeaderPage::SvxHeaderPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttr)
+ : SvxHFPage( pPage, pController, rAttr, SID_ATTR_PAGE_HEADERSET )
+{
+}
+
+SvxFooterPage::SvxFooterPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttr)
+ : SvxHFPage( pPage, pController, rAttr, SID_ATTR_PAGE_FOOTERSET )
+{
+}
+
+SvxHFPage::SvxHFPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet, sal_uInt16 nSetId)
+ : SfxTabPage(pPage, pController, "svx/ui/headfootformatpage.ui", "HFFormatPage", &rSet)
+ , nId(nSetId)
+ , mbDisableQueryBox(false)
+ , mbEnableDrawingLayerFillStyles(false)
+ , m_xCntSharedBox(m_xBuilder->weld_check_button("checkSameLR"))
+ , m_xCntSharedFirstBox(m_xBuilder->weld_check_button("checkSameFP"))
+ , m_xLMLbl(m_xBuilder->weld_label("labelLeftMarg"))
+ , m_xLMEdit(m_xBuilder->weld_metric_spin_button("spinMargLeft", FieldUnit::CM))
+ , m_xRMLbl(m_xBuilder->weld_label("labelRightMarg"))
+ , m_xRMEdit(m_xBuilder->weld_metric_spin_button("spinMargRight", FieldUnit::CM))
+ , m_xDistFT(m_xBuilder->weld_label("labelSpacing"))
+ , m_xDistEdit(m_xBuilder->weld_metric_spin_button("spinSpacing", FieldUnit::CM))
+ , m_xDynSpacingCB(m_xBuilder->weld_check_button("checkDynSpacing"))
+ , m_xHeightFT(m_xBuilder->weld_label("labelHeight"))
+ , m_xHeightEdit(m_xBuilder->weld_metric_spin_button("spinHeight", FieldUnit::CM))
+ , m_xHeightDynBtn(m_xBuilder->weld_check_button("checkAutofit"))
+ , m_xBackgroundBtn(m_xBuilder->weld_button("buttonMore"))
+ , m_xBspWin(new weld::CustomWeld(*m_xBuilder, "drawingareaPageHF", m_aBspWin))
+{
+ //swap header <-> footer in UI
+ if (nId == SID_ATTR_PAGE_FOOTERSET)
+ {
+ m_xContainer->set_help_id("svx/ui/headfootformatpage/FFormatPage");
+ m_xPageLbl = m_xBuilder->weld_label("labelFooterFormat");
+ m_xTurnOnBox = m_xBuilder->weld_check_button("checkFooterOn");
+
+ /* Set custom HIDs for the Footer help page (shared/01/05040400.xhp)
+ otherwise it would display the same extended help
+ on both the Header and Footer tabs */
+ m_xCntSharedBox->set_help_id( "SVX_HID_FOOTER_CHECKSAMELR" );
+ m_xCntSharedFirstBox->set_help_id( "SVX_HID_FOOTER_CHECKSAMEFP" );
+ m_xLMEdit->set_help_id( "SVX_HID_FOOTER_SPINMARGLEFT" );
+ m_xRMEdit->set_help_id( "SVX_HID_FOOTER_SPINMARGRIGHT" );
+ m_xDistEdit->set_help_id( "SVX_HID_FOOTER_SPINSPACING" );
+ m_xDynSpacingCB->set_help_id( "SVX_HID_FOOTER_CHECKDYNSPACING" );
+ m_xHeightEdit->set_help_id( "SVX_HID_FOOTER_SPINHEIGHT" );
+ m_xHeightDynBtn->set_help_id( "SVX_HID_FOOTER_CHECKAUTOFIT" );
+ m_xBackgroundBtn->set_help_id( "SVX_HID_FOOTER_BUTTONMORE" );
+ }
+ else //Header
+ {
+ m_xContainer->set_help_id("svx/ui/headfootformatpage/HFormatPage");
+ m_xPageLbl = m_xBuilder->weld_label("labelHeaderFormat");
+ m_xTurnOnBox = m_xBuilder->weld_check_button("checkHeaderOn");
+ }
+ m_xTurnOnBox->show();
+ m_xPageLbl->show();
+
+ InitHandler();
+ m_aBspWin.EnableRTL(false);
+
+ // This Page needs ExchangeSupport
+ SetExchangeSupport();
+
+ // Set metrics
+ FieldUnit eFUnit = GetModuleFieldUnit( rSet );
+ SetFieldUnit( *m_xDistEdit, eFUnit );
+ SetFieldUnit( *m_xHeightEdit, eFUnit );
+ SetFieldUnit( *m_xLMEdit, eFUnit );
+ SetFieldUnit( *m_xRMEdit, eFUnit );
+}
+
+SvxHFPage::~SvxHFPage()
+{
+}
+
+bool SvxHFPage::FillItemSet( SfxItemSet* rSet )
+{
+ const sal_uInt16 nWSize = GetWhich(SID_ATTR_PAGE_SIZE);
+ const sal_uInt16 nWLRSpace = GetWhich(SID_ATTR_LRSPACE);
+ const sal_uInt16 nWULSpace = GetWhich(SID_ATTR_ULSPACE);
+ const sal_uInt16 nWOn = GetWhich(SID_ATTR_PAGE_ON);
+ const sal_uInt16 nWDynamic = GetWhich(SID_ATTR_PAGE_DYNAMIC);
+ const sal_uInt16 nWDynSpacing = GetWhich(SID_ATTR_HDFT_DYNAMIC_SPACING);
+ const sal_uInt16 nWShared = GetWhich(SID_ATTR_PAGE_SHARED);
+ const sal_uInt16 nWSharedFirst = GetWhich( SID_ATTR_PAGE_SHARED_FIRST );
+ const sal_uInt16 nWBrush = GetWhich(SID_ATTR_BRUSH);
+ const sal_uInt16 nWBox = GetWhich(SID_ATTR_BORDER_OUTER);
+ const sal_uInt16 nWBoxInfo = GetWhich(SID_ATTR_BORDER_INNER);
+ const sal_uInt16 nWShadow = GetWhich(SID_ATTR_BORDER_SHADOW);
+
+ const SfxItemSet& rOldSet = GetItemSet();
+ SfxItemPool* pPool = rOldSet.GetPool();
+ DBG_ASSERT(pPool,"no pool :-(");
+ MapUnit eUnit = pPool->GetMetric(nWSize);
+ // take over DrawingLayer FillStyles
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aSet(*pPool);
+ // Keep it valid
+ aSet.MergeRange(nWSize, nWSize);
+ aSet.MergeRange(nWLRSpace, nWLRSpace);
+ aSet.MergeRange(nWULSpace, nWULSpace);
+ aSet.MergeRange(nWOn, nWOn);
+ aSet.MergeRange(nWDynamic, nWDynamic);
+ aSet.MergeRange(nWShared, nWShared);
+ aSet.MergeRange(nWSharedFirst, nWSharedFirst);
+ aSet.MergeRange(nWBrush, nWBrush);
+ aSet.MergeRange(nWBoxInfo, nWBoxInfo);
+ aSet.MergeRange(nWBox, nWBox);
+ aSet.MergeRange(nWShadow, nWShadow);
+ aSet.MergeRange(nWDynSpacing, nWDynSpacing);
+
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ // When using the XATTR_FILLSTYLE DrawingLayer FillStyle definition
+ // extra action has to be done here since the pool default is drawing::FillStyle_SOLID
+ // instead of drawing::FillStyle_NONE (to have the default blue fill color at start).
+ aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+
+ aSet.Put( SfxBoolItem( nWOn, m_xTurnOnBox->get_active() ) );
+ aSet.Put( SfxBoolItem( nWDynamic, m_xHeightDynBtn->get_active() ) );
+ aSet.Put( SfxBoolItem( nWShared, m_xCntSharedBox->get_active() ) );
+ if(m_xCntSharedFirstBox->get_visible())
+ aSet.Put(SfxBoolItem(nWSharedFirst, m_xCntSharedFirstBox->get_active()));
+ if (m_xDynSpacingCB->get_visible() && SfxItemPool::IsWhich(nWDynSpacing))
+ {
+ std::unique_ptr<SfxBoolItem> pBoolItem(static_cast<SfxBoolItem*>(pPool->GetDefaultItem(nWDynSpacing).Clone()));
+ pBoolItem->SetValue(m_xDynSpacingCB->get_active());
+ aSet.Put(std::move(pBoolItem));
+ }
+
+ // Size
+ SvxSizeItem aSizeItem( static_cast<const SvxSizeItem&>(rOldSet.Get( nWSize )) );
+ Size aSize( aSizeItem.GetSize() );
+ tools::Long nDist = GetCoreValue( *m_xDistEdit, eUnit );
+ tools::Long nH = GetCoreValue( *m_xHeightEdit, eUnit );
+
+ nH += nDist; // add distance
+ aSize.setHeight( nH );
+ aSizeItem.SetSize( aSize );
+ aSet.Put( aSizeItem );
+
+ // Margins
+ SvxLRSpaceItem aLR( nWLRSpace );
+ aLR.SetLeft( static_cast<sal_uInt16>(GetCoreValue( *m_xLMEdit, eUnit )) );
+ aLR.SetRight( static_cast<sal_uInt16>(GetCoreValue( *m_xRMEdit, eUnit )) );
+ aSet.Put( aLR );
+
+ SvxULSpaceItem aUL( nWULSpace );
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ aUL.SetLower( static_cast<sal_uInt16>(nDist) );
+ else
+ aUL.SetUpper( static_cast<sal_uInt16>(nDist) );
+ aSet.Put( aUL );
+
+ // Background and border?
+ if (pBBSet)
+ {
+ aSet.Put(*pBBSet);
+ }
+ else
+ {
+ const SfxPoolItem* pItem;
+
+ if(SfxItemState::SET == GetItemSet().GetItemState(GetWhich(nId), false, &pItem))
+ {
+ const SfxItemSet* _pSet = &(static_cast< const SvxSetItem* >(pItem)->GetItemSet());
+
+ if(_pSet->GetItemState(nWBrush) == SfxItemState::SET)
+ {
+ aSet.Put(_pSet->Get(nWBrush));
+ }
+
+ if(_pSet->GetItemState(nWBoxInfo) == SfxItemState::SET)
+ {
+ aSet.Put(_pSet->Get(nWBoxInfo));
+ }
+
+ if(_pSet->GetItemState(nWBox) == SfxItemState::SET)
+ {
+ aSet.Put(_pSet->Get(nWBox));
+ }
+
+ if(_pSet->GetItemState(nWShadow) == SfxItemState::SET)
+ {
+ aSet.Put(_pSet->Get(nWShadow));
+ }
+
+ // take care of [XATTR_XATTR_FILL_FIRST .. XATTR_FILL_LAST]
+ for(sal_uInt16 nFillStyleId(XATTR_FILL_FIRST); nFillStyleId <= XATTR_FILL_LAST; nFillStyleId++)
+ {
+ if(_pSet->GetItemState(nFillStyleId) == SfxItemState::SET)
+ {
+ aSet.Put(_pSet->Get(nFillStyleId));
+ }
+ }
+ }
+ }
+
+ // Flush the SetItem
+ SvxSetItem aSetItem( TypedWhichId<SvxSetItem>(GetWhich( nId )), aSet );
+ rSet->Put( aSetItem );
+
+ return true;
+}
+
+
+void SvxHFPage::Reset( const SfxItemSet* rSet )
+{
+ ActivatePage( *rSet );
+ ResetBackground_Impl( *rSet );
+
+ SfxItemPool* pPool = GetItemSet().GetPool();
+ DBG_ASSERT( pPool, "Where is the pool" );
+ MapUnit eUnit = pPool->GetMetric( GetWhich( SID_ATTR_PAGE_SIZE ) );
+
+ // Evaluate header-/footer- attributes
+ const SvxSetItem* pSetItem = nullptr;
+
+ if ( SfxItemState::SET == rSet->GetItemState( GetWhich(nId), false,
+ reinterpret_cast<const SfxPoolItem**>(&pSetItem) ) )
+ {
+ const SfxItemSet& rHeaderSet = pSetItem->GetItemSet();
+ const SfxBoolItem& rHeaderOn =
+ rHeaderSet.Get(GetWhich(SID_ATTR_PAGE_ON));
+
+ m_xTurnOnBox->set_active(rHeaderOn.GetValue());
+
+ if ( rHeaderOn.GetValue() )
+ {
+ const SfxBoolItem& rDynamic =
+ rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_DYNAMIC ) );
+ const SfxBoolItem& rShared =
+ rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SHARED ) );
+ const SfxBoolItem* pSharedFirst = nullptr;
+ if (rHeaderSet.HasItem(GetWhich(SID_ATTR_PAGE_SHARED_FIRST)))
+ pSharedFirst = static_cast<const SfxBoolItem*>(&rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SHARED_FIRST ) ));
+ const SvxSizeItem& rSize =
+ rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SIZE ) );
+ const SvxULSpaceItem& rUL =
+ static_cast<const SvxULSpaceItem&>(rHeaderSet.Get( GetWhich( SID_ATTR_ULSPACE ) ));
+ const SvxLRSpaceItem& rLR =
+ static_cast<const SvxLRSpaceItem&>(rHeaderSet.Get( GetWhich( SID_ATTR_LRSPACE ) ));
+ if (m_xDynSpacingCB->get_visible())
+ {
+ const SfxBoolItem& rDynSpacing =
+ static_cast<const SfxBoolItem&>(rHeaderSet.Get(GetWhich(SID_ATTR_HDFT_DYNAMIC_SPACING)));
+ m_xDynSpacingCB->set_active(rDynSpacing.GetValue());
+ }
+
+
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ { // Header
+ SetMetricValue( *m_xDistEdit, rUL.GetLower(), eUnit );
+ SetMetricValue( *m_xHeightEdit, rSize.GetSize().Height() - rUL.GetLower(), eUnit );
+ }
+ else
+ { // Footer
+ SetMetricValue( *m_xDistEdit, rUL.GetUpper(), eUnit );
+ SetMetricValue( *m_xHeightEdit, rSize.GetSize().Height() - rUL.GetUpper(), eUnit );
+ }
+
+ m_xHeightDynBtn->set_active(rDynamic.GetValue());
+ SetMetricValue( *m_xLMEdit, rLR.GetLeft(), eUnit );
+ SetMetricValue( *m_xRMEdit, rLR.GetRight(), eUnit );
+ m_xCntSharedBox->set_active(rShared.GetValue());
+ if (pSharedFirst)
+ m_xCntSharedFirstBox->set_active(pSharedFirst->GetValue());
+ }
+ else
+ pSetItem = nullptr;
+ }
+ else
+ {
+ bool bIsCalc = false;
+ const SfxPoolItem* pExt1 = GetItem(*rSet, SID_ATTR_PAGE_EXT1);
+ const SfxPoolItem* pExt2 = GetItem(*rSet, SID_ATTR_PAGE_EXT2);
+ if (dynamic_cast<const SfxBoolItem*>(pExt1) && dynamic_cast<const SfxBoolItem*>(pExt2) )
+ bIsCalc = true;
+
+ // defaults for distance and height
+ tools::Long nDefaultDist = bIsCalc ? DEF_DIST_CALC : DEF_DIST_WRITER;
+ SetMetricValue( *m_xDistEdit, nDefaultDist, MapUnit::Map100thMM );
+ SetMetricValue( *m_xHeightEdit, 500, MapUnit::Map100thMM );
+ }
+
+ if ( !pSetItem )
+ {
+ m_xTurnOnBox->set_active(false);
+ m_xHeightDynBtn->set_active(true);
+ m_xCntSharedBox->set_active(true);
+ m_xCntSharedFirstBox->set_active(true);
+ }
+
+ TurnOn(nullptr);
+
+ m_xTurnOnBox->save_state();
+ m_xDistEdit->save_value();
+ m_xHeightEdit->save_value();
+ m_xHeightDynBtn->save_state();
+ m_xLMEdit->save_value();
+ m_xRMEdit->save_value();
+ m_xCntSharedBox->save_state();
+ RangeHdl();
+
+ SfxObjectShell* pShell;
+ const SfxUInt16Item* pItem = rSet->GetItemIfSet(SID_HTML_MODE, false);
+ if(pItem ||
+ ( nullptr != (pShell = SfxObjectShell::Current()) &&
+ nullptr != (pItem = pShell->GetItem(SID_HTML_MODE))))
+ {
+ sal_uInt16 nHtmlMode = pItem->GetValue();
+ if (nHtmlMode & HTMLMODE_ON)
+ {
+ m_xCntSharedBox->hide();
+ m_xBackgroundBtn->hide();
+ }
+ }
+
+}
+
+void SvxHFPage::InitHandler()
+{
+ m_xTurnOnBox->connect_toggled(LINK(this, SvxHFPage, TurnOnHdl));
+ m_xDistEdit->connect_value_changed(LINK(this, SvxHFPage, ValueChangeHdl));
+ m_xHeightEdit->connect_value_changed(LINK(this,SvxHFPage,ValueChangeHdl));
+
+ m_xLMEdit->connect_value_changed(LINK(this, SvxHFPage, ValueChangeHdl));
+ m_xRMEdit->connect_value_changed(LINK(this, SvxHFPage, ValueChangeHdl));
+ m_xBackgroundBtn->connect_clicked(LINK(this,SvxHFPage, BackgroundHdl));
+}
+
+void SvxHFPage::TurnOn(const weld::Toggleable* pBox)
+{
+ if (m_xTurnOnBox->get_active())
+ {
+ m_xDistFT->set_sensitive(true);
+ m_xDistEdit->set_sensitive(true);
+ m_xDynSpacingCB->set_sensitive(true);
+ m_xHeightFT->set_sensitive(true);
+ m_xHeightEdit->set_sensitive(true);
+ m_xHeightDynBtn->set_sensitive(true);
+ m_xLMLbl->set_sensitive(true);
+ m_xLMEdit->set_sensitive(true);
+ m_xRMLbl->set_sensitive(true);
+ m_xRMEdit->set_sensitive(true);
+
+ SvxPageUsage nUsage = m_aBspWin.GetUsage();
+
+ if( nUsage == SvxPageUsage::Right || nUsage == SvxPageUsage::Left )
+ m_xCntSharedBox->set_sensitive(false);
+ else
+ {
+ m_xCntSharedBox->set_sensitive(true);
+ m_xCntSharedFirstBox->set_sensitive(true);
+ }
+ m_xBackgroundBtn->set_sensitive(true);
+ }
+ else
+ {
+ bool bDelete = true;
+
+ if (!mbDisableQueryBox && pBox && m_xTurnOnBox->get_saved_state() == TRISTATE_TRUE)
+ {
+ short nResult;
+ if (nId == SID_ATTR_PAGE_HEADERSET)
+ {
+ DeleteHeaderDialog aDlg(GetFrameWeld());
+ nResult = aDlg.run();
+ }
+ else
+ {
+ DeleteFooterDialog aDlg(GetFrameWeld());
+ nResult = aDlg.run();
+ }
+ bDelete = nResult == RET_YES;
+ }
+
+ if ( bDelete )
+ {
+ m_xDistFT->set_sensitive(false);
+ m_xDistEdit->set_sensitive(false);
+ m_xDynSpacingCB->set_sensitive(false);
+ m_xHeightFT->set_sensitive(false);
+ m_xHeightEdit->set_sensitive(false);
+ m_xHeightDynBtn->set_sensitive(false);
+
+ m_xLMLbl->set_sensitive(false);
+ m_xLMEdit->set_sensitive(false);
+ m_xRMLbl->set_sensitive(false);
+ m_xRMEdit->set_sensitive(false);
+
+ m_xCntSharedBox->set_sensitive(false);
+ m_xBackgroundBtn->set_sensitive(false);
+ m_xCntSharedFirstBox->set_sensitive(false);
+ }
+ else
+ m_xTurnOnBox->set_active(true);
+ }
+ UpdateExample();
+}
+
+IMPL_LINK(SvxHFPage, TurnOnHdl, weld::Toggleable&, rBox, void)
+{
+ TurnOn(&rBox);
+}
+
+IMPL_LINK_NOARG(SvxHFPage, BackgroundHdl, weld::Button&, void)
+{
+ if(!pBBSet)
+ {
+ // Use only the necessary items for border and background
+ const sal_uInt16 nOuter(GetWhich(SID_ATTR_BORDER_OUTER));
+ const sal_uInt16 nInner(GetWhich(SID_ATTR_BORDER_INNER, false));
+ const sal_uInt16 nShadow(GetWhich(SID_ATTR_BORDER_SHADOW));
+
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ pBBSet.reset(new SfxItemSetFixed
+ <XATTR_FILL_FIRST, XATTR_FILL_LAST, // DrawingLayer FillStyle definitions
+ SID_COLOR_TABLE, SID_PATTERN_LIST> // XPropertyLists for Color, Gradient, Hatch and Graphic fills
+ (*GetItemSet().GetPool()));
+ // Keep it valid
+ pBBSet->MergeRange(nOuter, nOuter);
+ pBBSet->MergeRange(nInner, nInner);
+ pBBSet->MergeRange(nShadow, nShadow);
+
+ // copy items for XPropertyList entries from the DrawModel so that
+ // the Area TabPage can access them
+ static const sal_uInt16 nCopyFlags[] = {
+ SID_COLOR_TABLE,
+ SID_GRADIENT_LIST,
+ SID_HATCH_LIST,
+ SID_BITMAP_LIST,
+ SID_PATTERN_LIST,
+ 0
+ };
+
+ for(sal_uInt16 a(0); nCopyFlags[a]; a++)
+ {
+ const SfxPoolItem* pItem = GetItemSet().GetItem(nCopyFlags[a]);
+
+ if(pItem)
+ {
+ pBBSet->Put(*pItem);
+ }
+ else
+ {
+ OSL_ENSURE(false, "XPropertyList missing (!)");
+ }
+ }
+ }
+ else
+ {
+ const sal_uInt16 nBrush(GetWhich(SID_ATTR_BRUSH));
+
+ pBBSet.reset( new SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>
+ (*GetItemSet().GetPool()) );
+ // Keep it valid
+ pBBSet->MergeRange(nBrush, nBrush);
+ pBBSet->MergeRange(nOuter, nOuter);
+ pBBSet->MergeRange(nInner, nInner);
+ pBBSet->MergeRange(nShadow, nShadow);
+ }
+
+ const SfxPoolItem* pItem;
+
+ if(SfxItemState::SET == GetItemSet().GetItemState(GetWhich(nId), false, &pItem))
+ {
+ // If a SfxItemSet from the SetItem for SID_ATTR_PAGE_HEADERSET or
+ // SID_ATTR_PAGE_FOOTERSET exists, use its content
+ pBBSet->Put(static_cast<const SvxSetItem*>(pItem)->GetItemSet());
+ }
+ else
+ {
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ // The style for header/footer is not yet created, need to reset
+ // XFillStyleItem to drawing::FillStyle_NONE which is the same as in the style
+ // initialization. This needs to be done since the pool default for
+ // XFillStyleItem is drawing::FillStyle_SOLID
+ pBBSet->Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ }
+
+ if(SfxItemState::SET == GetItemSet().GetItemState(nInner, false, &pItem))
+ {
+ // The set InfoItem is always required
+ pBBSet->Put(*pItem);
+ }
+ }
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+
+ VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSvxBorderBackgroundDlg(
+ GetFrameWeld(),
+ *pBBSet,
+ mbEnableDrawingLayerFillStyles));
+
+ pDlg->StartExecuteAsync([pDlg, this](sal_Int32 nResult) {
+ if (nResult == RET_OK && pDlg->GetOutputItemSet())
+ {
+ SfxItemIter aIter(*pDlg->GetOutputItemSet());
+
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
+ {
+ if(!IsInvalidItem(pItem))
+ {
+ pBBSet->Put(*pItem);
+ }
+ }
+
+ {
+ drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
+
+ if (mbEnableDrawingLayerFillStyles)
+ {
+ // create FillAttributes directly from DrawingLayer FillStyle entries
+ aFillAttributes =
+ std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(*pBBSet);
+ }
+ else
+ {
+ const sal_uInt16 nWhich = GetWhich(SID_ATTR_BRUSH);
+
+ if (pBBSet->GetItemState(nWhich) == SfxItemState::SET)
+ {
+ // create FillAttributes from SvxBrushItem
+ const SvxBrushItem& rItem
+ = static_cast<const SvxBrushItem&>(pBBSet->Get(nWhich));
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aTempSet(*pBBSet->GetPool());
+
+ setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet);
+ aFillAttributes =
+ std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(aTempSet);
+ }
+ }
+
+ if (SID_ATTR_PAGE_HEADERSET == nId)
+ {
+ //m_aBspWin.SetHdColor(rItem.GetColor());
+ m_aBspWin.setHeaderFillAttributes(aFillAttributes);
+ }
+ else
+ {
+ //m_aBspWin.SetFtColor(rItem.GetColor());
+ m_aBspWin.setFooterFillAttributes(aFillAttributes);
+ }
+ }
+ }
+ pDlg->disposeOnce();
+ });
+
+ UpdateExample();
+}
+
+void SvxHFPage::UpdateExample()
+{
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ {
+ m_aBspWin.SetHeader( m_xTurnOnBox->get_active() );
+ m_aBspWin.SetHdHeight( GetCoreValue( *m_xHeightEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetHdDist( GetCoreValue( *m_xDistEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetHdLeft( GetCoreValue( *m_xLMEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetHdRight( GetCoreValue( *m_xRMEdit, MapUnit::MapTwip ) );
+ }
+ else
+ {
+ m_aBspWin.SetFooter( m_xTurnOnBox->get_active() );
+ m_aBspWin.SetFtHeight( GetCoreValue( *m_xHeightEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetFtDist( GetCoreValue( *m_xDistEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetFtLeft( GetCoreValue( *m_xLMEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetFtRight( GetCoreValue( *m_xRMEdit, MapUnit::MapTwip ) );
+ }
+ m_aBspWin.Invalidate();
+}
+
+void SvxHFPage::ResetBackground_Impl( const SfxItemSet& rSet )
+{
+ sal_uInt16 nWhich(GetWhich(SID_ATTR_PAGE_HEADERSET));
+
+ if (SfxItemState::SET == rSet.GetItemState(nWhich, false))
+ {
+ const SvxSetItem& rSetItem = static_cast< const SvxSetItem& >(rSet.Get(nWhich, false));
+ const SfxItemSet& rTmpSet = rSetItem.GetItemSet();
+ const SfxBoolItem& rOn = rTmpSet.Get(GetWhich(SID_ATTR_PAGE_ON));
+
+ if(rOn.GetValue())
+ {
+ drawinglayer::attribute::SdrAllFillAttributesHelperPtr aHeaderFillAttributes;
+
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ // create FillAttributes directly from DrawingLayer FillStyle entries
+ aHeaderFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(rTmpSet);
+ }
+ else
+ {
+ nWhich = GetWhich(SID_ATTR_BRUSH);
+
+ if(SfxItemState::SET == rTmpSet.GetItemState(nWhich))
+ {
+ // create FillAttributes from SvxBrushItem
+ const SvxBrushItem& rItem = static_cast< const SvxBrushItem& >(rTmpSet.Get(nWhich));
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aTempSet(*rTmpSet.GetPool());
+
+ setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet);
+ aHeaderFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(aTempSet);
+ }
+ }
+
+ m_aBspWin.setHeaderFillAttributes(aHeaderFillAttributes);
+ }
+ }
+
+ nWhich = GetWhich(SID_ATTR_PAGE_FOOTERSET);
+
+ if (SfxItemState::SET == rSet.GetItemState(nWhich, false))
+ {
+ const SvxSetItem& rSetItem = static_cast< const SvxSetItem& >(rSet.Get(nWhich, false));
+ const SfxItemSet& rTmpSet = rSetItem.GetItemSet();
+ const SfxBoolItem& rOn = rTmpSet.Get(GetWhich(SID_ATTR_PAGE_ON));
+
+ if(rOn.GetValue())
+ {
+ drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFooterFillAttributes;
+
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ // create FillAttributes directly from DrawingLayer FillStyle entries
+ aFooterFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(rTmpSet);
+ }
+ else
+ {
+ nWhich = GetWhich(SID_ATTR_BRUSH);
+
+ if(SfxItemState::SET == rTmpSet.GetItemState(nWhich))
+ {
+ // create FillAttributes from SvxBrushItem
+ const SvxBrushItem& rItem = static_cast< const SvxBrushItem& >(rTmpSet.Get(nWhich));
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aTempSet(*rTmpSet.GetPool());
+
+ setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet);
+ aFooterFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(aTempSet);
+ }
+ }
+
+ m_aBspWin.setFooterFillAttributes(aFooterFillAttributes);
+ }
+ }
+
+ drawinglayer::attribute::SdrAllFillAttributesHelperPtr aPageFillAttributes;
+
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ // create FillAttributes directly from DrawingLayer FillStyle entries
+ aPageFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(rSet);
+ }
+ else
+ {
+ nWhich = GetWhich(SID_ATTR_BRUSH);
+
+ if(rSet.GetItemState(nWhich) >= SfxItemState::DEFAULT)
+ {
+ // create FillAttributes from SvxBrushItem
+ const SvxBrushItem& rItem = static_cast< const SvxBrushItem& >(rSet.Get(nWhich));
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aTempSet(*rSet.GetPool());
+
+ setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet);
+ aPageFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(aTempSet);
+ }
+ }
+
+ m_aBspWin.setPageFillAttributes(aPageFillAttributes);
+}
+
+void SvxHFPage::ActivatePage( const SfxItemSet& rSet )
+{
+ const SfxPoolItem* pItem = GetItem( rSet, SID_ATTR_LRSPACE );
+
+ if ( pItem )
+ {
+ // Set left and right margins
+ const SvxLRSpaceItem& rLRSpace = static_cast<const SvxLRSpaceItem&>(*pItem);
+
+ m_aBspWin.SetLeft( rLRSpace.GetLeft() );
+ m_aBspWin.SetRight( rLRSpace.GetRight() );
+ }
+ else
+ {
+ m_aBspWin.SetLeft( 0 );
+ m_aBspWin.SetRight( 0 );
+ }
+
+ pItem = GetItem( rSet, SID_ATTR_ULSPACE );
+
+ if ( pItem )
+ {
+ // Set top and bottom margins
+ const SvxULSpaceItem& rULSpace = static_cast<const SvxULSpaceItem&>(*pItem);
+
+ m_aBspWin.SetTop( rULSpace.GetUpper() );
+ m_aBspWin.SetBottom( rULSpace.GetLower() );
+ }
+ else
+ {
+ m_aBspWin.SetTop( 0 );
+ m_aBspWin.SetBottom( 0 );
+ }
+
+ SvxPageUsage nUsage = SvxPageUsage::All;
+ pItem = GetItem( rSet, SID_ATTR_PAGE );
+
+ if ( pItem )
+ nUsage = static_cast<const SvxPageItem*>(pItem)->GetPageUsage();
+
+ m_aBspWin.SetUsage( nUsage );
+
+ if ( SvxPageUsage::Right == nUsage || SvxPageUsage::Left == nUsage )
+ m_xCntSharedBox->set_sensitive(false);
+ else
+ {
+ m_xCntSharedBox->set_sensitive(true);
+ m_xCntSharedFirstBox->set_sensitive(true);
+ }
+ pItem = GetItem( rSet, SID_ATTR_PAGE_SIZE );
+
+ if ( pItem )
+ {
+ // Orientation and Size from the PageItem
+ const SvxSizeItem& rSize = static_cast<const SvxSizeItem&>(*pItem);
+ // if the size is already swapped (Landscape)
+ m_aBspWin.SetSize( rSize.GetSize() );
+ }
+
+ // Evaluate Header attribute
+ const SvxSetItem* pSetItem = nullptr;
+
+ if ( SfxItemState::SET == rSet.GetItemState( GetWhich( SID_ATTR_PAGE_HEADERSET ),
+ false,
+ reinterpret_cast<const SfxPoolItem**>(&pSetItem) ) )
+ {
+ const SfxItemSet& rHeaderSet = pSetItem->GetItemSet();
+ const SfxBoolItem& rHeaderOn =
+ rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_ON ) );
+
+ if ( rHeaderOn.GetValue() )
+ {
+ const SvxSizeItem& rSize =
+ rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SIZE ) );
+ const SvxULSpaceItem& rUL = static_cast<const SvxULSpaceItem&>(
+ rHeaderSet.Get( GetWhich(SID_ATTR_ULSPACE ) ));
+ const SvxLRSpaceItem& rLR = static_cast<const SvxLRSpaceItem&>(
+ rHeaderSet.Get( GetWhich( SID_ATTR_LRSPACE ) ));
+ tools::Long nDist = rUL.GetLower();
+
+ m_aBspWin.SetHdHeight( rSize.GetSize().Height() - nDist );
+ m_aBspWin.SetHdDist( nDist );
+ m_aBspWin.SetHdLeft( rLR.GetLeft() );
+ m_aBspWin.SetHdRight( rLR.GetRight() );
+ m_aBspWin.SetHeader( true );
+ }
+ else
+ pSetItem = nullptr;
+ }
+
+ if ( !pSetItem )
+ {
+ m_aBspWin.SetHeader( false );
+
+ if ( SID_ATTR_PAGE_HEADERSET == nId )
+ {
+ m_xCntSharedBox->set_sensitive(false);
+ m_xCntSharedFirstBox->set_sensitive(false);
+ }
+ }
+ pSetItem = nullptr;
+
+ if ( SfxItemState::SET == rSet.GetItemState( GetWhich( SID_ATTR_PAGE_FOOTERSET ),
+ false,
+ reinterpret_cast<const SfxPoolItem**>(&pSetItem) ) )
+ {
+ const SfxItemSet& rFooterSet = pSetItem->GetItemSet();
+ const SfxBoolItem& rFooterOn =
+ rFooterSet.Get( GetWhich( SID_ATTR_PAGE_ON ) );
+
+ if ( rFooterOn.GetValue() )
+ {
+ const SvxSizeItem& rSize =
+ rFooterSet.Get( GetWhich( SID_ATTR_PAGE_SIZE ) );
+ const SvxULSpaceItem& rUL = static_cast<const SvxULSpaceItem&>(
+ rFooterSet.Get( GetWhich( SID_ATTR_ULSPACE ) ));
+ const SvxLRSpaceItem& rLR = static_cast<const SvxLRSpaceItem&>(
+ rFooterSet.Get( GetWhich( SID_ATTR_LRSPACE ) ));
+ tools::Long nDist = rUL.GetUpper();
+
+ m_aBspWin.SetFtHeight( rSize.GetSize().Height() - nDist );
+ m_aBspWin.SetFtDist( nDist );
+ m_aBspWin.SetFtLeft( rLR.GetLeft() );
+ m_aBspWin.SetFtRight( rLR.GetRight() );
+ m_aBspWin.SetFooter( true );
+ }
+ else
+ pSetItem = nullptr;
+ }
+
+ if ( !pSetItem )
+ {
+ m_aBspWin.SetFooter( false );
+
+ if ( SID_ATTR_PAGE_FOOTERSET == nId )
+ {
+ m_xCntSharedBox->set_sensitive(false);
+ m_xCntSharedFirstBox->set_sensitive(false);
+ }
+ }
+
+ pItem = GetItem( rSet, SID_ATTR_PAGE_EXT1 );
+
+ if ( auto pBoolItem = dynamic_cast<const SfxBoolItem*>( pItem) )
+ {
+ m_aBspWin.SetTable( true );
+ m_aBspWin.SetHorz( pBoolItem->GetValue() );
+ }
+
+ pItem = GetItem( rSet, SID_ATTR_PAGE_EXT2 );
+
+ if ( auto pBoolItem = dynamic_cast<const SfxBoolItem*>( pItem) )
+ {
+ m_aBspWin.SetTable( true );
+ m_aBspWin.SetVert( pBoolItem->GetValue() );
+ }
+ ResetBackground_Impl( rSet );
+ RangeHdl();
+}
+
+DeactivateRC SvxHFPage::DeactivatePage( SfxItemSet* _pSet )
+{
+ if ( _pSet )
+ FillItemSet( _pSet );
+ return DeactivateRC::LeavePage;
+}
+
+IMPL_LINK_NOARG(SvxHFPage, ValueChangeHdl, weld::MetricSpinButton&, void)
+{
+ UpdateExample();
+ RangeHdl();
+}
+
+void SvxHFPage::RangeHdl()
+{
+ tools::Long nHHeight = m_aBspWin.GetHdHeight();
+ tools::Long nHDist = m_aBspWin.GetHdDist();
+
+ tools::Long nFHeight = m_aBspWin.GetFtHeight();
+ tools::Long nFDist = m_aBspWin.GetFtDist();
+
+ tools::Long nHeight = std::max(tools::Long(MINBODY),
+ static_cast<tools::Long>(m_xHeightEdit->denormalize(m_xHeightEdit->get_value(FieldUnit::TWIP))));
+ tools::Long nDist = m_xTurnOnBox->get_active() ?
+ static_cast<tools::Long>(m_xDistEdit->denormalize(m_xDistEdit->get_value(FieldUnit::TWIP))) : 0;
+
+ tools::Long nMin;
+ tools::Long nMax;
+
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ {
+ nHHeight = nHeight;
+ nHDist = nDist;
+ }
+ else
+ {
+ nFHeight = nHeight;
+ nFDist = nDist;
+ }
+
+ // Current values of the side edges
+ tools::Long nBT = m_aBspWin.GetTop();
+ tools::Long nBB = m_aBspWin.GetBottom();
+ tools::Long nBL = m_aBspWin.GetLeft();
+ tools::Long nBR = m_aBspWin.GetRight();
+
+ tools::Long nH = m_aBspWin.GetSize().Height();
+ tools::Long nW = m_aBspWin.GetSize().Width();
+
+ // Borders
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ {
+ // Header
+ nMin = ( nH - nBB - nBT ) / 5; // 20%
+ nMax = std::max( nH - nMin - nHDist - nFDist - nFHeight - nBB - nBT,
+ nMin );
+ m_xHeightEdit->set_max(m_xHeightEdit->normalize(nMax), FieldUnit::TWIP);
+ nMin = ( nH - nBB - nBT ) / 5; // 20%
+ nDist = std::max( nH - nMin - nHHeight - nFDist - nFHeight - nBB - nBT,
+ tools::Long(0) );
+ m_xDistEdit->set_max(m_xDistEdit->normalize(nDist), FieldUnit::TWIP);
+ }
+ else
+ {
+ // Footer
+ nMin = ( nH - nBT - nBB ) / 5; // 20%
+ nMax = std::max( nH - nMin - nFDist - nHDist - nHHeight - nBT - nBB,
+ nMin );
+ m_xHeightEdit->set_max(m_xHeightEdit->normalize(nMax), FieldUnit::TWIP);
+ nMin = ( nH - nBT - nBB ) / 5; // 20%
+ nDist = std::max( nH - nMin - nFHeight - nHDist - nHHeight - nBT - nBB,
+ tools::Long(0) );
+ m_xDistEdit->set_max(m_xDistEdit->normalize(nDist), FieldUnit::TWIP);
+ }
+
+ // Limit Indentation
+ nMax = nW - nBL - nBR -
+ static_cast<tools::Long>(m_xRMEdit->denormalize(m_xRMEdit->get_value(FieldUnit::TWIP))) - MINBODY;
+ m_xLMEdit->set_max(m_xLMEdit->normalize(nMax), FieldUnit::TWIP);
+
+ nMax = nW - nBL - nBR -
+ static_cast<tools::Long>(m_xLMEdit->denormalize(m_xLMEdit->get_value(FieldUnit::TWIP))) - MINBODY;
+ m_xRMEdit->set_max(m_xLMEdit->normalize(nMax), FieldUnit::TWIP);
+}
+
+void SvxHFPage::EnableDynamicSpacing()
+{
+ m_xDynSpacingCB->show();
+}
+
+void SvxHFPage::PageCreated(const SfxAllItemSet &rSet)
+{
+ const SfxBoolItem* pSupportDrawingLayerFillStyleItem = rSet.GetItem<SfxBoolItem>(SID_DRAWINGLAYER_FILLSTYLES, false);
+
+ if (pSupportDrawingLayerFillStyleItem)
+ {
+ const bool bNew(pSupportDrawingLayerFillStyleItem->GetValue());
+
+ mbEnableDrawingLayerFillStyles = bNew;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/hexcolorcontrol.cxx b/svx/source/dialog/hexcolorcontrol.cxx
new file mode 100644
index 000000000..fbf6b9ea6
--- /dev/null
+++ b/svx/source/dialog/hexcolorcontrol.cxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sax/tools/converter.hxx>
+#include <svx/hexcolorcontrol.hxx>
+#include <rtl/character.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+namespace weld
+{
+HexColorControl::HexColorControl(std::unique_ptr<weld::Entry> pEntry)
+ : m_xEntry(std::move(pEntry))
+ , m_nAsyncModifyEvent(nullptr)
+{
+ m_xEntry->set_max_length(6);
+ m_xEntry->set_width_chars(6);
+ m_xEntry->connect_insert_text(LINK(this, HexColorControl, ImplProcessInputHdl));
+ m_xEntry->connect_changed(LINK(this, HexColorControl, ImplProcessModifyHdl));
+}
+
+HexColorControl::~HexColorControl()
+{
+ if (m_nAsyncModifyEvent)
+ Application::RemoveUserEvent(m_nAsyncModifyEvent);
+}
+
+IMPL_LINK_NOARG(HexColorControl, OnAsyncModifyHdl, void*, void)
+{
+ m_nAsyncModifyEvent = nullptr;
+ m_aModifyHdl.Call(*m_xEntry);
+}
+
+// tdf#123291 resend it async so it arrives after ImplProcessInputHdl has been
+// processed
+IMPL_LINK_NOARG(HexColorControl, ImplProcessModifyHdl, weld::Entry&, void)
+{
+ if (m_nAsyncModifyEvent)
+ Application::RemoveUserEvent(m_nAsyncModifyEvent);
+ m_nAsyncModifyEvent = Application::PostUserEvent(LINK(this, HexColorControl, OnAsyncModifyHdl));
+}
+
+void HexColorControl::SetColor(Color nColor)
+{
+ OUStringBuffer aBuffer;
+ sax::Converter::convertColor(aBuffer, nColor);
+ OUString sColor = aBuffer.makeStringAndClear().copy(1);
+ if (sColor == m_xEntry->get_text())
+ return;
+ int nStartPos, nEndPos;
+ m_xEntry->get_selection_bounds(nStartPos, nEndPos);
+ m_xEntry->set_text(sColor);
+ m_xEntry->select_region(nStartPos, nEndPos);
+}
+
+Color HexColorControl::GetColor() const
+{
+ sal_Int32 nColor = -1;
+
+ OUString aStr = "#" + m_xEntry->get_text();
+ sal_Int32 nLen = aStr.getLength();
+
+ if (nLen < 7)
+ {
+ static const char* const pNullStr = "000000";
+ aStr += OUString::createFromAscii(&pNullStr[nLen - 1]);
+ }
+
+ sax::Converter::convertColor(nColor, aStr);
+
+ m_xEntry->set_message_type(nColor != -1 ? weld::EntryMessageType::Normal
+ : weld::EntryMessageType::Error);
+
+ return Color(ColorTransparency, nColor);
+}
+
+IMPL_STATIC_LINK(HexColorControl, ImplProcessInputHdl, OUString&, rTest, bool)
+{
+ const sal_Unicode* pTest = rTest.getStr();
+ sal_Int32 nLen = rTest.getLength();
+
+ OUStringBuffer aFilter(nLen);
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ if (rtl::isAsciiHexDigit(*pTest))
+ aFilter.append(*pTest);
+ ++pTest;
+ }
+
+ rTest = aFilter.makeStringAndClear();
+ return true;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/hyperdlg.cxx b/svx/source/dialog/hyperdlg.cxx
new file mode 100644
index 000000000..6d94d8add
--- /dev/null
+++ b/svx/source/dialog/hyperdlg.cxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/hyperdlg.hxx>
+#include <svx/svxdlg.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/sfxsids.hrc>
+
+//# #
+//# Childwindow-Wrapper-Class #
+//# #
+SFX_IMPL_CHILDWINDOW_WITHID(SvxHlinkDlgWrapper, SID_HYPERLINK_DIALOG)
+
+SvxHlinkDlgWrapper::SvxHlinkDlgWrapper( vcl::Window* _pParent, sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo ) :
+ SfxChildWindow( _pParent, nId ),
+
+ mpDlg( nullptr )
+
+{
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ mpDlg = pFact->CreateSvxHpLinkDlg(this, pBindings, _pParent->GetFrameWeld());
+ SetController( mpDlg->GetController() );
+ SetVisible_Impl(false);
+
+ if ( !pInfo->aSize.IsEmpty() )
+ {
+ weld::Window* pTopWindow = SfxGetpApp()->GetTopWindow();
+ if (pTopWindow)
+ {
+ weld::Dialog* pDialog = GetController()->getDialog();
+
+ Size aParentSize(pTopWindow->get_size());
+ Size aDlgSize(pDialog->get_size());
+
+ if( aParentSize.Width() < pInfo->aPos.X() )
+ pInfo->aPos.setX( aParentSize.Width()-aDlgSize.Width() < tools::Long(0.1*aParentSize.Width()) ?
+ tools::Long(0.1*aParentSize.Width()) : aParentSize.Width()-aDlgSize.Width() );
+ if( aParentSize.Height() < pInfo->aPos. Y() )
+ pInfo->aPos.setY( aParentSize.Height()-aDlgSize.Height() < tools::Long(0.1*aParentSize.Height()) ?
+ tools::Long(0.1*aParentSize.Height()) : aParentSize.Height()-aDlgSize.Height() );
+
+ pDialog->window_move(pInfo->aPos.X(), pInfo->aPos.Y());
+ }
+ }
+ SetHideNotDelete( true );
+}
+
+SfxChildWinInfo SvxHlinkDlgWrapper::GetInfo() const
+{
+ return SfxChildWindow::GetInfo();
+}
+
+bool SvxHlinkDlgWrapper::QueryClose()
+{
+ return !mpDlg || mpDlg->QueryClose();
+}
+
+SvxHlinkDlgWrapper::~SvxHlinkDlgWrapper()
+{
+ mpDlg.disposeAndClear();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/imapdlg.cxx b/svx/source/dialog/imapdlg.cxx
new file mode 100644
index 000000000..2eda3129b
--- /dev/null
+++ b/svx/source/dialog/imapdlg.cxx
@@ -0,0 +1,727 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/errinf.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <svl/eitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <svl/urihelper.hxx>
+#include <svtools/ehdl.hxx>
+#include <svtools/inettbc.hxx>
+#include <svtools/sfxecode.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/weld.hxx>
+#include <svx/imapdlg.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include "imapwnd.hxx"
+#include "imapimp.hxx"
+#include <svx/svdopath.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <osl/diagnose.h>
+#include "dlgunit.hxx"
+#include <memory>
+
+constexpr OUStringLiteral SELF_TARGET = u"_self";
+constexpr OUStringLiteral IMAP_CERN_FILTER = u"MAP - CERN";
+constexpr OUStringLiteral IMAP_NCSA_FILTER = u"MAP - NCSA";
+constexpr OUStringLiteral IMAP_BINARY_FILTER = u"SIP - StarView ImageMap";
+constexpr OUStringLiteral IMAP_ALL_TYPE = u"*.*";
+constexpr OUStringLiteral IMAP_BINARY_TYPE = u"*.sip";
+constexpr OUStringLiteral IMAP_CERN_TYPE = u"*.map";
+constexpr OUStringLiteral IMAP_NCSA_TYPE = u"*.map";
+
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID( SvxIMapDlgChildWindow, SID_IMAP );
+
+// ControllerItem
+
+SvxIMapDlgItem::SvxIMapDlgItem( SvxIMapDlg& rIMapDlg, SfxBindings& rBindings ) :
+ SfxControllerItem ( SID_IMAP_EXEC, rBindings ),
+ rIMap ( rIMapDlg )
+{
+}
+
+void SvxIMapDlgItem::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState /*eState*/,
+ const SfxPoolItem* pItem )
+{
+ if ( ( nSID == SID_IMAP_EXEC ) && pItem )
+ {
+ const SfxBoolItem* pStateItem = dynamic_cast<const SfxBoolItem*>( pItem );
+ assert(pStateItem); //SfxBoolItem expected
+ if (pStateItem)
+ {
+ // Disable Float if possible
+ rIMap.SetExecState( !pStateItem->GetValue() );
+ }
+ }
+}
+
+SvxIMapDlgChildWindow::SvxIMapDlgChildWindow(vcl::Window* _pParent, sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo const * pInfo)
+ : SfxChildWindow( _pParent, nId )
+{
+ SetController(std::make_shared<SvxIMapDlg>(pBindings, this, _pParent->GetFrameWeld()));
+ SvxIMapDlg* pDlg = static_cast<SvxIMapDlg*>(GetController().get());
+ pDlg->Initialize( pInfo );
+}
+
+void SvxIMapDlgChildWindow::UpdateIMapDlg( const Graphic& rGraphic, const ImageMap* pImageMap,
+ const TargetList* pTargetList, void* pEditingObj )
+{
+ SvxIMapDlg* pDlg = GetIMapDlg();
+ if (pDlg)
+ pDlg->UpdateLink(rGraphic, pImageMap, pTargetList, pEditingObj);
+}
+
+SvxIMapDlg::SvxIMapDlg(SfxBindings *_pBindings, SfxChildWindow *pCW, weld::Window* _pParent)
+ : SfxModelessDialogController(_pBindings, pCW, _pParent, "svx/ui/imapdialog.ui", "ImapDialog")
+ , pCheckObj(nullptr)
+ , aIMapItem(*this, *_pBindings)
+ , m_xIMapWnd(new IMapWindow(_pBindings->GetActiveFrame(), m_xDialog.get()))
+ , m_xTbxIMapDlg1(m_xBuilder->weld_toolbar("toolbar"))
+ , m_xFtURL(m_xBuilder->weld_label("urlft"))
+ , m_xURLBox(new SvtURLBox(m_xBuilder->weld_combo_box("url")))
+ , m_xFtText(m_xBuilder->weld_label("textft"))
+ , m_xEdtText(m_xBuilder->weld_entry("text"))
+ , m_xFtTarget(m_xBuilder->weld_label("targetft"))
+ , m_xCbbTarget(m_xBuilder->weld_combo_box("target"))
+ , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
+ , m_xStbStatus1(m_xBuilder->weld_label("statusurl"))
+ , m_xStbStatus2(m_xBuilder->weld_label("statuspos"))
+ , m_xStbStatus3(m_xBuilder->weld_label("statussize"))
+ , m_xIMapWndWeld(new weld::CustomWeld(*m_xBuilder, "container", *m_xIMapWnd))
+
+{
+ m_xTbxIMapDlg1->insert_separator(4, "sep1");
+ m_xTbxIMapDlg1->insert_separator(10, "sep2");
+ m_xTbxIMapDlg1->insert_separator(15, "sep3");
+ m_xTbxIMapDlg1->insert_separator(18, "sel4");
+
+ //lock this down so it doesn't jump around in size
+ //as entries are added later on
+ TargetList aTmpList;
+ SfxFrame::GetDefaultTargetList(aTmpList);
+ for (const OUString & s : aTmpList)
+ m_xCbbTarget->append_text(s);
+ Size aPrefSize(m_xCbbTarget->get_preferred_size());
+ m_xCbbTarget->set_size_request(aPrefSize.Width(), -1);
+ m_xCbbTarget->clear();
+
+ m_xIMapWnd->Show();
+
+ pOwnData.reset(new IMapOwnData);
+
+ m_xIMapWnd->SetInfoLink( LINK( this, SvxIMapDlg, InfoHdl ) );
+ m_xIMapWnd->SetMousePosLink( LINK( this, SvxIMapDlg, MousePosHdl ) );
+ m_xIMapWnd->SetGraphSizeLink( LINK( this, SvxIMapDlg, GraphSizeHdl ) );
+ m_xIMapWnd->SetUpdateLink( LINK( this, SvxIMapDlg, StateHdl ) );
+
+ m_xURLBox->connect_changed( LINK( this, SvxIMapDlg, URLModifyHdl ) );
+ m_xURLBox->connect_focus_out( LINK( this, SvxIMapDlg, URLLoseFocusHdl ) );
+ m_xEdtText->connect_changed( LINK( this, SvxIMapDlg, EntryModifyHdl ) );
+ m_xCbbTarget->connect_focus_out( LINK( this, SvxIMapDlg, URLLoseFocusHdl ) );
+
+ m_xTbxIMapDlg1->connect_clicked( LINK( this, SvxIMapDlg, TbxClickHdl ) );
+ OString sSelect("TBI_SELECT");
+ m_xTbxIMapDlg1->set_item_active(sSelect, true);
+ TbxClickHdl(sSelect);
+
+ m_xStbStatus1->set_size_request(120, -1);
+ const int nWidth = m_xStbStatus1->get_pixel_size(" 9999,99 cm / 9999,99 cm ").Width();
+ m_xStbStatus2->set_size_request(nWidth, -1);
+ m_xStbStatus3->set_size_request(nWidth, -1);
+
+ m_xFtURL->set_sensitive(false);
+ m_xURLBox->set_sensitive(false);
+ m_xFtText->set_sensitive(false);
+ m_xEdtText->set_sensitive(false);
+ m_xFtTarget->set_sensitive(false);
+ m_xCbbTarget->set_sensitive(false);
+ pOwnData->bExecState = false;
+
+ pOwnData->aIdle.SetInvokeHandler( LINK( this, SvxIMapDlg, UpdateHdl ) );
+
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_ACTIVE", false);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_MACRO", false );
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_PROPERTY", false );
+
+ m_xCancelBtn->connect_clicked(LINK(this, SvxIMapDlg, CancelHdl));
+}
+
+SvxIMapDlg::~SvxIMapDlg()
+{
+ m_xIMapWnd->SetUpdateLink( Link<GraphCtrl*,void>() );
+ m_xIMapWnd.reset();
+}
+
+IMPL_LINK_NOARG(SvxIMapDlg, CancelHdl, weld::Button&, void)
+{
+ bool bRet = true;
+
+ if ( m_xTbxIMapDlg1->get_item_sensitive("TBI_APPLY") )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "svx/ui/querymodifyimagemapchangesdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QueryModifyImageMapChangesDialog"));
+ const tools::Long nRet = xQBox->run();
+
+ if( nRet == RET_YES )
+ {
+ SfxBoolItem aBoolItem( SID_IMAP_EXEC, true );
+ GetBindings().GetDispatcher()->ExecuteList(SID_IMAP_EXEC,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aBoolItem });
+ }
+ else if( nRet == RET_CANCEL )
+ bRet = false;
+ }
+ else if( m_xIMapWnd->IsChanged() )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "svx/ui/querysaveimagemapchangesdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QuerySaveImageMapChangesDialog"));
+ const tools::Long nRet = xQBox->run();
+
+ if( nRet == RET_YES )
+ bRet = DoSave();
+ else if( nRet == RET_CANCEL )
+ bRet = false;
+ }
+
+ if (bRet)
+ m_xDialog->response(RET_CANCEL);
+}
+
+// Enabled or disable all Controls
+
+void SvxIMapDlg::SetExecState( bool bEnable )
+{
+ pOwnData->bExecState = bEnable;
+}
+
+const ImageMap& SvxIMapDlg::GetImageMap() const
+{
+ return m_xIMapWnd->GetImageMap();
+}
+
+void SvxIMapDlg::SetTargetList( const TargetList& rTargetList )
+{
+ m_xIMapWnd->SetTargetList( rTargetList );
+
+ m_xCbbTarget->clear();
+
+ for (const OUString & s : rTargetList)
+ m_xCbbTarget->append_text(s);
+}
+
+void SvxIMapDlg::UpdateLink( const Graphic& rGraphic, const ImageMap* pImageMap,
+ const TargetList* pTargetList, void* pEditingObj )
+{
+ pOwnData->aUpdateGraphic = rGraphic;
+
+ if ( pImageMap )
+ pOwnData->aUpdateImageMap = *pImageMap;
+ else
+ pOwnData->aUpdateImageMap.ClearImageMap();
+
+ pOwnData->pUpdateEditingObject = pEditingObj;
+
+ // Delete UpdateTargetList, because this method can still be called several
+ // times before the update timer is turned on
+
+ // TargetList must be copied, since it is owned by the caller and can be
+ // deleted immediately after this call the copied list will be deleted
+ // again in the handler
+ if( pTargetList )
+ pOwnData->aUpdateTargetList = *pTargetList;
+ else
+ pOwnData->aUpdateTargetList.clear();
+
+ pOwnData->aIdle.Start();
+}
+
+
+// Click-handler for ToolBox
+
+IMPL_LINK(SvxIMapDlg, TbxClickHdl, const OString&, rNewItemId, void)
+{
+ if (rNewItemId == "TBI_APPLY")
+ {
+ URLLoseFocusHdl(*m_xCbbTarget);
+ SfxBoolItem aBoolItem( SID_IMAP_EXEC, true );
+ GetBindings().GetDispatcher()->ExecuteList(SID_IMAP_EXEC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aBoolItem });
+ }
+ else if (rNewItemId == "TBI_OPEN")
+ DoOpen();
+ else if (rNewItemId == "TBI_SAVEAS")
+ DoSave();
+ else if (rNewItemId == "TBI_CLOSE")
+ CancelHdl(*m_xCancelBtn);
+ else if (rNewItemId == "TBI_SELECT")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetEditMode( true );
+ }
+ else if (rNewItemId == "TBI_RECT")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetObjKind( SdrObjKind::Rectangle );
+ }
+ else if (rNewItemId == "TBI_CIRCLE")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetObjKind( SdrObjKind::CircleOrEllipse );
+ }
+ else if (rNewItemId == "TBI_POLY")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetObjKind( SdrObjKind::Polygon );
+ }
+ else if (rNewItemId == "TBI_FREEPOLY")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetObjKind( SdrObjKind::FreehandFill );
+ }
+ else if (rNewItemId == "TBI_ACTIVE")
+ {
+ URLLoseFocusHdl(*m_xCbbTarget);
+ bool bNewState = !m_xTbxIMapDlg1->get_item_active(rNewItemId);
+ m_xTbxIMapDlg1->set_item_active(rNewItemId, bNewState);
+ m_xIMapWnd->SetCurrentObjState( !bNewState );
+ }
+ else if (rNewItemId == "TBI_MACRO")
+ m_xIMapWnd->DoMacroAssign();
+ else if (rNewItemId == "TBI_PROPERTY")
+ m_xIMapWnd->DoPropertyDialog();
+ else if (rNewItemId == "TBI_POLYEDIT")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetPolyEditMode( m_xTbxIMapDlg1->get_item_active(rNewItemId) ? SID_BEZIER_MOVE : 0 );
+ }
+ else if (rNewItemId == "TBI_POLYMOVE")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetPolyEditMode( SID_BEZIER_MOVE );
+ }
+ else if (rNewItemId == "TBI_POLYINSERT")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetPolyEditMode( SID_BEZIER_INSERT );
+ }
+ else if (rNewItemId == "TBI_POLYDELETE")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->GetSdrView()->DeleteMarkedPoints();
+ }
+ else if (rNewItemId == "TBI_UNDO")
+ {
+ URLLoseFocusHdl(*m_xCbbTarget);
+ m_xIMapWnd->GetSdrModel()->Undo();
+ }
+ else if (rNewItemId == "TBI_REDO")
+ {
+ URLLoseFocusHdl(*m_xCbbTarget);
+ m_xIMapWnd->GetSdrModel()->Redo();
+ }
+}
+
+void SvxIMapDlg::DoOpen()
+{
+ ::sfx2::FileDialogHelper aDlg(
+ css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::NONE, m_xDialog.get());
+
+ ImageMap aLoadIMap;
+ const OUString aFilter(SvxResId(RID_SVXSTR_IMAP_ALL_FILTER));
+
+ aDlg.AddFilter( aFilter, IMAP_ALL_TYPE );
+ aDlg.AddFilter( IMAP_CERN_FILTER, IMAP_CERN_TYPE );
+ aDlg.AddFilter( IMAP_NCSA_FILTER, IMAP_NCSA_TYPE );
+ aDlg.AddFilter( IMAP_BINARY_FILTER, IMAP_BINARY_TYPE );
+
+ aDlg.SetCurrentFilter( aFilter );
+ aDlg.SetContext(sfx2::FileDialogHelper::ImageMap);
+
+ if( aDlg.Execute() != ERRCODE_NONE )
+ return;
+
+ INetURLObject aURL( aDlg.GetPath() );
+ DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));
+
+ if( pIStm )
+ {
+ aLoadIMap.Read( *pIStm, IMapFormat::Detect );
+
+ if( pIStm->GetError() )
+ {
+ SfxErrorContext eEC(ERRCTX_ERROR, m_xDialog.get());
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+ else
+ m_xIMapWnd->SetImageMap( aLoadIMap );
+ }
+
+ m_xIMapWnd->Invalidate();
+}
+
+bool SvxIMapDlg::DoSave()
+{
+ ::sfx2::FileDialogHelper aDlg(
+ css::ui::dialogs::TemplateDescription::FILESAVE_SIMPLE,
+ FileDialogFlags::NONE, m_xDialog.get());
+
+ const OUString aBinFilter( IMAP_BINARY_FILTER );
+ const OUString aCERNFilter( IMAP_CERN_FILTER );
+ const OUString aNCSAFilter( IMAP_NCSA_FILTER );
+ SdrModel* pModel = m_xIMapWnd->GetSdrModel();
+ const bool bChanged = pModel->IsChanged();
+ bool bRet = false;
+
+ aDlg.AddFilter( aCERNFilter, IMAP_CERN_TYPE );
+ aDlg.AddFilter( aNCSAFilter, IMAP_NCSA_TYPE );
+ aDlg.AddFilter( aBinFilter, IMAP_BINARY_TYPE );
+
+ aDlg.SetCurrentFilter( aCERNFilter );
+ aDlg.SetContext(sfx2::FileDialogHelper::ImageMap);
+
+ if( aDlg.Execute() == ERRCODE_NONE )
+ {
+ const OUString aFilter( aDlg.GetCurrentFilter() );
+ OUString aExt;
+ IMapFormat nFormat;
+
+ if ( aFilter == aBinFilter )
+ {
+ nFormat = IMapFormat::Binary;
+ aExt = "sip";
+ }
+ else if ( aFilter == aCERNFilter )
+ {
+ nFormat = IMapFormat::CERN;
+ aExt = "map";
+ }
+ else if ( aFilter == aNCSAFilter )
+ {
+ nFormat = IMapFormat::NCSA;
+ aExt = "map";
+ }
+ else
+ {
+ return false;
+ }
+
+ INetURLObject aURL( aDlg.GetPath() );
+
+ if( aURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ OSL_FAIL( "invalid URL" );
+ }
+ else
+ {
+ if( aURL.getExtension().isEmpty() )
+ aURL.setExtension( aExt );
+
+ std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::TRUNC ));
+ if( pOStm )
+ {
+ m_xIMapWnd->GetImageMap().Write( *pOStm, nFormat );
+
+ if( pOStm->GetError() )
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+
+ pOStm.reset();
+ pModel->SetChanged( bChanged );
+ bRet = true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void SvxIMapDlg::SetActiveTool(std::string_view rId)
+{
+ m_xTbxIMapDlg1->set_item_active("TBI_SELECT", rId == "TBI_SELECT");
+ m_xTbxIMapDlg1->set_item_active("TBI_RECT", rId == "TBI_RECT");
+ m_xTbxIMapDlg1->set_item_active("TBI_CIRCLE", rId == "TBI_CIRCLE");
+ m_xTbxIMapDlg1->set_item_active("TBI_POLY", rId == "TBI_POLY");
+ m_xTbxIMapDlg1->set_item_active("TBI_FREEPOLY", rId == "TBI_FREEPOLY");
+
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYINSERT", rId == "TBI_POLYINSERT");
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYDELETE", false);
+
+ bool bMove = rId == "TBI_POLYMOVE"
+ || ( rId == "TBI_POLYEDIT"
+ && !m_xTbxIMapDlg1->get_item_active("TBI_POLYINSERT")
+ && !m_xTbxIMapDlg1->get_item_active("TBI_POLYDELETE") );
+
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYMOVE", bMove );
+
+ bool bEditMode = ( rId == "TBI_POLYEDIT" )
+ || ( rId == "TBI_POLYMOVE")
+ || ( rId == "TBI_POLYINSERT")
+ || ( rId == "TBI_POLYDELETE" );
+
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYEDIT", bEditMode);
+}
+
+IMPL_LINK( SvxIMapDlg, InfoHdl, IMapWindow&, rWnd, void )
+{
+ const NotifyInfo& rInfo = rWnd.GetInfo();
+
+ if ( rInfo.bNewObj )
+ {
+ if (!rInfo.aMarkURL.isEmpty() && ( m_xURLBox->find_text(rInfo.aMarkURL) == -1))
+ m_xURLBox->append_text(rInfo.aMarkURL);
+
+ m_xURLBox->set_entry_text(rInfo.aMarkURL);
+ m_xEdtText->set_text(rInfo.aMarkAltText);
+
+ if ( rInfo.aMarkTarget.isEmpty() )
+ m_xCbbTarget->set_entry_text( SELF_TARGET );
+ else
+ m_xCbbTarget->set_entry_text( rInfo.aMarkTarget );
+ }
+
+ if ( !rInfo.bOneMarked )
+ {
+ m_xTbxIMapDlg1->set_item_active("TBI_ACTIVE", false);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_ACTIVE", false);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_MACRO", false);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_PROPERTY", false);
+ m_xStbStatus1->set_label(OUString());
+
+ m_xFtURL->set_sensitive(false);
+ m_xURLBox->set_sensitive(false);
+ m_xFtText->set_sensitive(false);
+ m_xEdtText->set_sensitive(false);
+ m_xFtTarget->set_sensitive(false);
+ m_xCbbTarget->set_sensitive(false);
+
+ m_xURLBox->set_entry_text( "" );
+ m_xEdtText->set_text( "" );
+ }
+ else
+ {
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_ACTIVE", true);
+ m_xTbxIMapDlg1->set_item_active("TBI_ACTIVE", !rInfo.bActivated );
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_MACRO", true);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_PROPERTY", true);
+
+ m_xFtURL->set_sensitive(true);
+ m_xURLBox->set_sensitive(true);
+ m_xFtText->set_sensitive(true);
+ m_xEdtText->set_sensitive(true);
+ m_xFtTarget->set_sensitive(true);
+ m_xCbbTarget->set_sensitive(true);
+
+ m_xStbStatus1->set_label(rInfo.aMarkURL);
+
+ if ( m_xURLBox->get_active_text() != rInfo.aMarkURL )
+ m_xURLBox->set_entry_text( rInfo.aMarkURL );
+
+ if ( m_xEdtText->get_text() != rInfo.aMarkAltText )
+ m_xEdtText->set_text( rInfo.aMarkAltText );
+
+ if ( rInfo.aMarkTarget.isEmpty() )
+ m_xCbbTarget->set_entry_text( SELF_TARGET );
+ else
+ m_xCbbTarget->set_entry_text( rInfo.aMarkTarget );
+ }
+}
+
+IMPL_LINK( SvxIMapDlg, MousePosHdl, GraphCtrl*, pWnd, void )
+{
+ const FieldUnit eFieldUnit = GetBindings().GetDispatcher()->GetModule()->GetFieldUnit();
+ const Point& rMousePos = pWnd->GetMousePos();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ const sal_Unicode cSep = rLocaleWrapper.getNumDecimalSep()[0];
+
+ OUString aStr = GetUnitString( rMousePos.X(), eFieldUnit, cSep ) +
+ " / " + GetUnitString( rMousePos.Y(), eFieldUnit, cSep );
+
+ m_xStbStatus2->set_label(aStr);
+}
+
+IMPL_LINK( SvxIMapDlg, GraphSizeHdl, GraphCtrl*, pWnd, void )
+{
+ const FieldUnit eFieldUnit = GetBindings().GetDispatcher()->GetModule()->GetFieldUnit();
+ const Size& rSize = pWnd->GetGraphicSize();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ const sal_Unicode cSep = rLocaleWrapper.getNumDecimalSep()[0];
+
+ OUString aStr = GetUnitString( rSize.Width(), eFieldUnit, cSep ) +
+ " x " + GetUnitString( rSize.Height(), eFieldUnit, cSep );
+
+ m_xStbStatus3->set_label(aStr);
+}
+
+void SvxIMapDlg::URLModify()
+{
+ NotifyInfo aNewInfo;
+
+ aNewInfo.aMarkURL = m_xURLBox->get_active_text();
+ aNewInfo.aMarkAltText = m_xEdtText->get_text();
+ aNewInfo.aMarkTarget = m_xCbbTarget->get_active_text();
+
+ m_xIMapWnd->ReplaceActualIMapInfo( aNewInfo );
+}
+
+IMPL_LINK_NOARG(SvxIMapDlg, URLModifyHdl, weld::ComboBox&, void)
+{
+ URLModify();
+}
+
+IMPL_LINK_NOARG(SvxIMapDlg, EntryModifyHdl, weld::Entry&, void)
+{
+ URLModify();
+}
+
+IMPL_LINK_NOARG(SvxIMapDlg, URLLoseFocusHdl, weld::Widget&, void)
+{
+ NotifyInfo aNewInfo;
+ const OUString aURLText( m_xURLBox->get_active_text() );
+ const OUString aTargetText( m_xCbbTarget->get_active_text() );
+
+ if ( !aURLText.isEmpty() )
+ {
+ OUString aBase = GetBindings().GetDispatcher()->GetFrame()->GetObjectShell()->GetMedium()->GetBaseURL();
+ aNewInfo.aMarkURL = ::URIHelper::SmartRel2Abs( INetURLObject(aBase), aURLText, URIHelper::GetMaybeFileHdl(), true, false,
+ INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::Unambiguous );
+ }
+ else
+ aNewInfo.aMarkURL = aURLText;
+
+ aNewInfo.aMarkAltText = m_xEdtText->get_text();
+
+ if ( aTargetText.isEmpty() )
+ aNewInfo.aMarkTarget = SELF_TARGET;
+ else
+ aNewInfo.aMarkTarget = aTargetText;
+
+ m_xIMapWnd->ReplaceActualIMapInfo( aNewInfo );
+}
+
+IMPL_LINK_NOARG(SvxIMapDlg, UpdateHdl, Timer *, void)
+{
+ pOwnData->aIdle.Stop();
+
+ if ( pOwnData->pUpdateEditingObject != pCheckObj )
+ {
+ if (m_xIMapWnd->IsChanged())
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "svx/ui/querysaveimagemapchangesdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QuerySaveImageMapChangesDialog"));
+ if (xQBox->run() == RET_YES)
+ {
+ DoSave();
+ }
+ }
+
+ m_xIMapWnd->SetGraphic( pOwnData->aUpdateGraphic );
+ m_xIMapWnd->SetImageMap( pOwnData->aUpdateImageMap );
+ SetTargetList( pOwnData->aUpdateTargetList );
+ pCheckObj = pOwnData->pUpdateEditingObject;
+
+ // After changes => default selection
+ m_xTbxIMapDlg1->set_item_active("TBI_SELECT", true);
+ m_xIMapWnd->SetEditMode( true );
+ }
+
+ // Delete the copied list again in the Update method
+ pOwnData->aUpdateTargetList.clear();
+
+ GetBindings().Invalidate( SID_IMAP_EXEC );
+ m_xIMapWnd->QueueIdleUpdate();
+}
+
+IMPL_LINK( SvxIMapDlg, StateHdl, GraphCtrl*, pWnd, void )
+{
+ const SdrObject* pObj = pWnd->GetSelectedSdrObject();
+ const SdrModel* pModel = pWnd->GetSdrModel();
+ const SdrView* pView = pWnd->GetSdrView();
+ const bool bPolyEdit = ( pObj != nullptr ) && dynamic_cast<const SdrPathObj*>( pObj) != nullptr;
+ const bool bDrawEnabled = !( bPolyEdit && m_xTbxIMapDlg1->get_item_active("TBI_POLYEDIT") );
+
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_APPLY", pOwnData->bExecState && pWnd->IsChanged() );
+
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_SELECT", bDrawEnabled);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_RECT", bDrawEnabled);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_CIRCLE", bDrawEnabled);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_POLY", bDrawEnabled);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_FREEPOLY", bDrawEnabled);
+
+ // BezierEditor State
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_POLYEDIT", bPolyEdit );
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_POLYMOVE", !bDrawEnabled );
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_POLYINSERT", !bDrawEnabled );
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_POLYDELETE", !bDrawEnabled && pView->IsDeleteMarkedPointsPossible() );
+
+ // Undo/Redo
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_UNDO", pModel->HasUndoActions() );
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_REDO", pModel->HasRedoActions() );
+
+ if ( bPolyEdit )
+ {
+ switch( pWnd->GetPolyEditMode() )
+ {
+ case SID_BEZIER_MOVE:
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYMOVE", true);
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYINSERT", false);
+ break;
+ case SID_BEZIER_INSERT:
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYINSERT", true);
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYMOVE", false);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ m_xTbxIMapDlg1->set_item_active( "TBI_POLYEDIT", false );
+ m_xTbxIMapDlg1->set_item_active( "TBI_POLYMOVE", true);
+ m_xTbxIMapDlg1->set_item_active( "TBI_POLYINSERT", false );
+ pWnd->SetPolyEditMode( 0 );
+ }
+
+ m_xIMapWnd->QueueIdleUpdate();
+}
+
+SvxIMapDlg* GetIMapDlg()
+{
+ SfxChildWindow* pWnd = nullptr;
+ if (SfxViewFrame::Current() && SfxViewFrame::Current()->HasChildWindow(SvxIMapDlgChildWindow::GetChildWindowId()))
+ pWnd = SfxViewFrame::Current()->GetChildWindow(SvxIMapDlgChildWindow::GetChildWindowId());
+ return pWnd ? static_cast<SvxIMapDlg*>(pWnd->GetController().get()) : nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/imapimp.hxx b/svx/source/dialog/imapimp.hxx
new file mode 100644
index 000000000..50862f625
--- /dev/null
+++ b/svx/source/dialog/imapimp.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_IMAPIMP_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_IMAPIMP_HXX
+
+#include <svx/imapdlg.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/imap.hxx>
+
+class IMapOwnData
+{
+public:
+
+ Idle aIdle;
+ Graphic aUpdateGraphic;
+ ImageMap aUpdateImageMap;
+ TargetList aUpdateTargetList;
+ void* pUpdateEditingObject;
+ bool bExecState;
+
+ IMapOwnData()
+ : aIdle("svx IMapOwnData")
+ , pUpdateEditingObject(nullptr)
+ , bExecState(false)
+ {
+ }
+};
+
+
+#endif // _IMAPIMP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/imapwnd.cxx b/svx/source/dialog/imapwnd.cxx
new file mode 100644
index 000000000..0e7b85131
--- /dev/null
+++ b/svx/source/dialog/imapwnd.cxx
@@ -0,0 +1,743 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/urlobj.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/imaprect.hxx>
+#include <vcl/imapcirc.hxx>
+#include <vcl/imappoly.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/urlbmk.hxx>
+
+#include <svx/svxids.hrc>
+#include "imapwnd.hxx"
+#include <svx/svdpage.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlnclit.hxx>
+
+#include <sfx2/evntconf.hxx>
+
+#include <sot/formats.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+using ::com::sun::star::frame::XFrame;
+using ::com::sun::star::uno::Reference;
+
+#define TRANSCOL COL_WHITE
+
+IMapWindow::IMapWindow(const Reference< XFrame >& rxDocumentFrame, weld::Dialog* pDialog)
+ : GraphCtrl(pDialog)
+ , mxDocumentFrame(rxDocumentFrame)
+{
+ pIMapPool = new SfxItemPool( "IMapItemPool",
+ SID_ATTR_MACROITEM, SID_ATTR_MACROITEM, maItemInfos );
+ pIMapPool->FreezeIdRanges();
+}
+
+IMapWindow::~IMapWindow()
+{
+}
+
+void IMapWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(270, 170), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+
+ SetSdrMode(true);
+
+ mxDropTargetHelper.reset(new IMapDropTargetHelper(*this));
+}
+
+void IMapWindow::SetImageMap( const ImageMap& rImageMap )
+{
+ ReplaceImageMap( rImageMap );
+}
+
+void IMapWindow::ReplaceImageMap( const ImageMap& rImageMap )
+{
+ SdrPage* pPage = nullptr;
+ aIMap = rImageMap;
+
+ if(GetSdrModel())
+ {
+ // try to access page
+ pPage = GetSdrModel()->GetPage(0);
+ }
+
+ if(pPage)
+ {
+ // clear SdrObjects with broadcasting
+ pPage->ClearSdrObjList();
+ }
+
+ if(GetSdrView())
+ {
+ // #i63762# reset selection at view
+ GetSdrView()->UnmarkAllObj();
+ }
+
+ // create new drawing objects
+ const sal_uInt16 nCount(rImageMap.GetIMapObjectCount());
+
+ for ( sal_uInt16 i(nCount); i > 0; i-- )
+ {
+ SdrObject* pNewObj = CreateObj( rImageMap.GetIMapObject( i - 1 ) );
+
+ if (pNewObj && pPage)
+ {
+ pPage->InsertObject( pNewObj );
+ }
+ }
+}
+
+void IMapWindow::ReplaceActualIMapInfo( const NotifyInfo& rNewInfo )
+{
+ const SdrObject* pSdrObj = GetSelectedSdrObject();
+
+ if ( pSdrObj )
+ {
+ IMapObject* pIMapObj = GetIMapObj( pSdrObj );
+ if (pIMapObj)
+ {
+ pIMapObj->SetURL( rNewInfo.aMarkURL );
+ pIMapObj->SetAltText( rNewInfo.aMarkAltText );
+ pIMapObj->SetTarget( rNewInfo.aMarkTarget );
+ pModel->SetChanged();
+ UpdateInfo( false );
+ }
+ }
+}
+
+const ImageMap& IMapWindow::GetImageMap()
+{
+ if ( pModel->IsChanged() )
+ {
+ SdrPage* pPage = pModel->GetPage( 0 );
+
+ if ( pPage )
+ {
+ const size_t nCount = pPage->GetObjCount();
+
+ aIMap.ClearImageMap();
+
+ for ( size_t i = nCount; i; )
+ {
+ --i;
+ aIMap.InsertIMapObject( *( static_cast<IMapUserData*>( pPage->GetObj( i )->GetUserData( 0 ) )->GetObject() ) );
+ }
+ }
+
+ pModel->SetChanged( false );
+ }
+
+ return aIMap;
+}
+
+void IMapWindow::SetTargetList( const TargetList& rTargetList )
+{
+ // Delete old List
+ // Fill with the provided list
+ aTargetList = rTargetList;
+
+ pModel->SetChanged( false );
+}
+
+SdrObject* IMapWindow::CreateObj( const IMapObject* pIMapObj )
+{
+ tools::Rectangle aClipRect( Point(), GetGraphicSize() );
+ SdrObject* pSdrObj = nullptr;
+ IMapObjectPtr pCloneIMapObj;
+
+ switch( pIMapObj->GetType() )
+ {
+ case IMapObjectType::Rectangle:
+ {
+ const IMapRectangleObject* pIMapRectObj = static_cast<const IMapRectangleObject*>(pIMapObj);
+ tools::Rectangle aDrawRect( pIMapRectObj->GetRectangle( false ) );
+
+ // clipped on CanvasPane
+ aDrawRect.Intersection( aClipRect );
+
+ pSdrObj = new SdrRectObj(*pModel, aDrawRect);
+ pCloneIMapObj.reset(static_cast<IMapObject*>(new IMapRectangleObject( *pIMapRectObj )));
+ }
+ break;
+
+ case IMapObjectType::Circle:
+ {
+ const IMapCircleObject* pIMapCircleObj = static_cast<const IMapCircleObject*>(pIMapObj);
+ const Point aCenter( pIMapCircleObj->GetCenter( false ) );
+ const tools::Long nRadius = pIMapCircleObj->GetRadius( false );
+ const Point aOffset( nRadius, nRadius );
+ tools::Rectangle aCircle( aCenter - aOffset, aCenter + aOffset );
+
+ // limited to CanvasPane
+ aCircle.Intersection( aClipRect );
+
+ pSdrObj = new SdrCircObj(
+ *pModel,
+ SdrCircKind::Full,
+ aCircle,
+ 0_deg100,
+ 36000_deg100);
+ pCloneIMapObj.reset(static_cast<IMapObject*>(new IMapCircleObject( *pIMapCircleObj )));
+ }
+ break;
+
+ case IMapObjectType::Polygon:
+ {
+ const IMapPolygonObject* pIMapPolyObj = static_cast<const IMapPolygonObject*>(pIMapObj);
+
+ // If it actually is an ellipse, then another ellipse is created again
+ if ( pIMapPolyObj->HasExtraEllipse() )
+ {
+ tools::Rectangle aDrawRect( pIMapPolyObj->GetExtraEllipse() );
+
+ // clipped on CanvasPane
+ aDrawRect.Intersection( aClipRect );
+
+ pSdrObj = new SdrCircObj(
+ *pModel,
+ SdrCircKind::Full,
+ aDrawRect,
+ 0_deg100,
+ 36000_deg100);
+ }
+ else
+ {
+ const tools::Polygon& rPoly = pIMapPolyObj->GetPolygon( false );
+ tools::Polygon aDrawPoly( rPoly );
+
+ // clipped on CanvasPane
+ aDrawPoly.Clip( aClipRect );
+
+ basegfx::B2DPolygon aPolygon;
+ aPolygon.append(aDrawPoly.getB2DPolygon());
+ pSdrObj = new SdrPathObj(
+ *pModel,
+ SdrObjKind::Polygon,
+ basegfx::B2DPolyPolygon(aPolygon));
+ }
+
+ pCloneIMapObj.reset(static_cast<IMapObject*>(new IMapPolygonObject( *pIMapPolyObj )));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ( pSdrObj )
+ {
+ SfxItemSet aSet( pModel->GetItemPool() );
+
+ aSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ aSet.Put( XFillColorItem( "", TRANSCOL ) );
+
+ if ( !pIMapObj->IsActive() )
+ {
+ aSet.Put( XFillTransparenceItem( 100 ) );
+ aSet.Put( XLineColorItem( "", COL_RED ) );
+ }
+ else
+ {
+ aSet.Put( XFillTransparenceItem( 50 ) );
+ aSet.Put( XLineColorItem( "", COL_BLACK ) );
+ }
+
+ pSdrObj->SetMergedItemSetAndBroadcast(aSet);
+
+ pSdrObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new IMapUserData( pCloneIMapObj )) );
+ pSdrObj->SetUserCall( GetSdrUserCall() );
+ }
+
+ return pSdrObj;
+}
+
+void IMapWindow::InitSdrModel()
+{
+ GraphCtrl::InitSdrModel();
+
+ SfxItemSet aSet( pModel->GetItemPool() );
+
+ aSet.Put( XFillColorItem( "", TRANSCOL ) );
+ aSet.Put( XFillTransparenceItem( 50 ) );
+ pView->SetAttributes( aSet );
+ pView->SetFrameDragSingles();
+}
+
+void IMapWindow::SdrObjCreated( const SdrObject& rObj )
+{
+ switch( rObj.GetObjIdentifier() )
+ {
+ case SdrObjKind::Rectangle:
+ {
+ SdrRectObj* pRectObj = const_cast<SdrRectObj*>(static_cast<const SdrRectObj*>(&rObj));
+ auto pObj = std::make_shared<IMapRectangleObject>( pRectObj->GetLogicRect(), "", "", "", "", "", true, false );
+
+ pRectObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new IMapUserData( pObj )) );
+ }
+ break;
+
+ case SdrObjKind::CircleOrEllipse:
+ {
+ SdrCircObj* pCircObj = const_cast<SdrCircObj*>( static_cast<const SdrCircObj*>(&rObj) );
+ SdrPathObj* pPathObj = static_cast<SdrPathObj*>( pCircObj->ConvertToPolyObj( false, false ).release() );
+ tools::Polygon aPoly(pPathObj->GetPathPoly().getB2DPolygon(0));
+
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pPathObj);
+ SdrObject::Free(pTemp);
+
+ auto pObj = std::make_shared<IMapPolygonObject>( aPoly, "", "", "", "", "", true, false );
+ pObj->SetExtraEllipse( aPoly.GetBoundRect() );
+ pCircObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new IMapUserData( pObj )) );
+ }
+ break;
+
+ case SdrObjKind::Polygon:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathPoly:
+ case SdrObjKind::PathFill:
+ {
+ SdrPathObj* pPathObj = const_cast<SdrPathObj*>( static_cast<const SdrPathObj*>(&rObj) );
+ const basegfx::B2DPolyPolygon& rXPolyPoly = pPathObj->GetPathPoly();
+
+ if ( rXPolyPoly.count() )
+ {
+ tools::Polygon aPoly(rXPolyPoly.getB2DPolygon(0));
+ auto pObj = std::make_shared<IMapPolygonObject>( aPoly, "", "", "", "", "", true, false );
+ pPathObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new IMapUserData( pObj )) );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void IMapWindow::SdrObjChanged( const SdrObject& rObj )
+{
+ IMapUserData* pUserData = static_cast<IMapUserData*>( rObj.GetUserData( 0 ) );
+
+ if ( !pUserData )
+ return;
+
+ OUString aURL;
+ OUString aAltText;
+ OUString aDesc;
+ OUString aTarget;
+ IMapObjectPtr pIMapObj = pUserData->GetObject();
+ bool bActive = true;
+
+ if ( pIMapObj )
+ {
+ aURL = pIMapObj->GetURL();
+ aAltText = pIMapObj->GetAltText();
+ aDesc = pIMapObj->GetDesc();
+ aTarget = pIMapObj->GetTarget();
+ bActive = pIMapObj->IsActive();
+ }
+
+ switch( rObj.GetObjIdentifier() )
+ {
+ case SdrObjKind::Rectangle:
+ {
+ pUserData->ReplaceObject( std::make_shared<IMapRectangleObject>( static_cast<const SdrRectObj&>(rObj).GetLogicRect(),
+ aURL, aAltText, aDesc, aTarget, "", bActive, false ) );
+ }
+ break;
+
+ case SdrObjKind::CircleOrEllipse:
+ {
+ const SdrCircObj& rCircObj = static_cast<const SdrCircObj&>(rObj);
+ SdrPathObj* pPathObj = static_cast<SdrPathObj*>( rCircObj.ConvertToPolyObj( false, false ).release() );
+ tools::Polygon aPoly(pPathObj->GetPathPoly().getB2DPolygon(0));
+
+ auto pObj = std::make_shared<IMapPolygonObject>( aPoly, aURL, aAltText, aDesc, aTarget, "", bActive, false );
+ pObj->SetExtraEllipse( aPoly.GetBoundRect() );
+
+ // was only created by us temporarily
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pPathObj);
+ SdrObject::Free(pTemp);
+
+ pUserData->ReplaceObject( pObj );
+ }
+ break;
+
+ case SdrObjKind::Polygon:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathPoly:
+ case SdrObjKind::PathFill:
+ {
+ const SdrPathObj& rPathObj = static_cast<const SdrPathObj&>(rObj);
+ const basegfx::B2DPolyPolygon& rXPolyPoly = rPathObj.GetPathPoly();
+
+ if ( rXPolyPoly.count() )
+ {
+ tools::Polygon aPoly(rPathObj.GetPathPoly().getB2DPolygon(0));
+ auto pObj = std::make_shared<IMapPolygonObject>( aPoly, aURL, aAltText, aDesc, aTarget, "", bActive, false );
+ pUserData->ReplaceObject( pObj );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool IMapWindow::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bRet = GraphCtrl::MouseButtonUp( rMEvt );
+ UpdateInfo( true );
+ return bRet;
+}
+
+void IMapWindow::MarkListHasChanged()
+{
+ GraphCtrl::MarkListHasChanged();
+ UpdateInfo( false );
+}
+
+SdrObject* IMapWindow::GetHitSdrObj( const Point& rPosPixel ) const
+{
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+
+ SdrObject* pObj = nullptr;
+ Point aPt = rDevice.PixelToLogic( rPosPixel );
+
+ if ( tools::Rectangle( Point(), GetGraphicSize() ).Contains( aPt ) )
+ {
+ SdrPage* pPage = pModel->GetPage( 0 );
+ if ( pPage )
+ {
+ for ( size_t i = pPage->GetObjCount(); i > 0; )
+ {
+ --i;
+ SdrObject* pTestObj = pPage->GetObj( i );
+ IMapObject* pIMapObj = GetIMapObj( pTestObj );
+
+ if ( pIMapObj && pIMapObj->IsHit( aPt ) )
+ {
+ pObj = pTestObj;
+ break;
+ }
+ }
+ }
+ }
+
+ return pObj;
+}
+
+IMapObject* IMapWindow::GetIMapObj( const SdrObject* pSdrObj )
+{
+ IMapObject* pIMapObj = nullptr;
+
+ if ( pSdrObj )
+ {
+ IMapUserData* pUserData = static_cast<IMapUserData*>( pSdrObj->GetUserData( 0 ) );
+
+ if ( pUserData )
+ pIMapObj = pUserData->GetObject().get();
+ }
+
+ return pIMapObj;
+}
+
+bool IMapWindow::Command(const CommandEvent& rCEvt)
+{
+ if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetDrawingArea(), "svx/ui/imapmenu.ui"));
+ mxPopupMenu = xBuilder->weld_menu("menu");
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ const size_t nMarked = rMarkList.GetMarkCount();
+
+ mxPopupMenu->set_sensitive("url", false);
+ mxPopupMenu->set_sensitive("active", false);
+ mxPopupMenu->set_sensitive("macro", false);
+ mxPopupMenu->set_sensitive("selectall", pModel->GetPage(0)->GetObjCount() != pView->GetMarkedObjectCount());
+
+ if ( !nMarked )
+ {
+ mxPopupMenu->set_sensitive("arrange", false);
+ mxPopupMenu->set_sensitive("delete", false);
+ }
+ else
+ {
+ if ( nMarked == 1 )
+ {
+ SdrObject* pSdrObj = GetSelectedSdrObject();
+
+ mxPopupMenu->set_sensitive("url", true);
+ mxPopupMenu->set_sensitive("active", true);
+ mxPopupMenu->set_sensitive("macro", true);
+ mxPopupMenu->set_active("active", GetIMapObj(pSdrObj)->IsActive());
+ }
+
+ mxPopupMenu->set_sensitive("arrange", true);
+ mxPopupMenu->set_sensitive("delete", true);
+ }
+
+ MenuSelectHdl(mxPopupMenu->popup_at_rect(GetDrawingArea(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
+
+ mxPopupMenu.reset();
+
+ return true;
+ }
+ return CustomWidgetController::Command(rCEvt);
+}
+
+IMapDropTargetHelper::IMapDropTargetHelper(IMapWindow& rImapWindow)
+ : DropTargetHelper(rImapWindow.GetDrawingArea()->get_drop_target())
+ , m_rImapWindow(rImapWindow)
+{
+}
+
+sal_Int8 IMapDropTargetHelper::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ return m_rImapWindow.AcceptDrop(rEvt);
+}
+
+sal_Int8 IMapDropTargetHelper::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ return m_rImapWindow.ExecuteDrop(rEvt);
+}
+
+sal_Int8 IMapWindow::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ return( ( GetHitSdrObj( rEvt.maPosPixel ) != nullptr ) ? rEvt.mnAction : DND_ACTION_NONE );
+}
+
+sal_Int8 IMapWindow::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if (mxDropTargetHelper->IsDropFormatSupported(SotClipboardFormatId::NETSCAPE_BOOKMARK))
+ {
+ INetBookmark aBookMark( "", "" );
+ SdrObject* pSdrObj = GetHitSdrObj( rEvt.maPosPixel );
+
+ if( pSdrObj && TransferableDataHelper( rEvt.maDropEvent.Transferable ).GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aBookMark ) )
+ {
+ IMapObject* pIMapObj = GetIMapObj( pSdrObj );
+
+ pIMapObj->SetURL( aBookMark.GetURL() );
+ pIMapObj->SetAltText( aBookMark.GetDescription() );
+ pModel->SetChanged();
+ pView->UnmarkAll();
+ pView->MarkObj( pSdrObj, pView->GetSdrPageView() );
+ UpdateInfo( true );
+ nRet = rEvt.mnAction;
+ }
+ }
+
+ return nRet;
+}
+
+OUString IMapWindow::RequestHelp(tools::Rectangle& rHelpArea)
+{
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+
+ Point aPos = rDevice.PixelToLogic(rHelpArea.TopLeft());
+
+ SdrPageView* pPageView = nullptr;
+ SdrObject* pSdrObj = pView->PickObj(aPos, pView->getHitTolLog(), pPageView);
+ if (pSdrObj)
+ {
+ const IMapObject* pIMapObj = GetIMapObj( pSdrObj );
+ if ( pIMapObj )
+ {
+ OUString aStr = pIMapObj->GetURL();
+ if ( !aStr.isEmpty() )
+ {
+ rHelpArea = rDevice.LogicToPixel(tools::Rectangle( Point(), GetGraphicSize()));
+ return aStr;
+ }
+ }
+ }
+
+ return OUString();
+}
+
+void IMapWindow::SetCurrentObjState( bool bActive )
+{
+ SdrObject* pObj = GetSelectedSdrObject();
+
+ if ( !pObj )
+ return;
+
+ SfxItemSet aSet( pModel->GetItemPool() );
+
+ GetIMapObj( pObj )->SetActive( bActive );
+
+ aSet.Put( XFillColorItem( "", TRANSCOL ) );
+
+ if ( !bActive )
+ {
+ aSet.Put( XFillTransparenceItem( 100 ) );
+ aSet.Put( XLineColorItem( "", COL_RED ) );
+ }
+ else
+ {
+ aSet.Put( XFillTransparenceItem( 50 ) );
+ aSet.Put( XLineColorItem( "", COL_BLACK ) );
+ }
+
+ pView->SetAttributes( aSet );
+}
+
+void IMapWindow::UpdateInfo( bool bNewObj )
+{
+ if ( !aInfoLink.IsSet() )
+ return;
+
+ const SdrObject* pSdrObj = GetSelectedSdrObject();
+ const IMapObject* pIMapObj = pSdrObj ? GetIMapObj( pSdrObj ) : nullptr;
+
+ aInfo.bNewObj = bNewObj;
+
+ if ( pIMapObj )
+ {
+ aInfo.bOneMarked = true;
+ aInfo.aMarkURL = pIMapObj->GetURL();
+ aInfo.aMarkAltText = pIMapObj->GetAltText();
+ aInfo.aMarkTarget = pIMapObj->GetTarget();
+ aInfo.bActivated = pIMapObj->IsActive();
+ aInfoLink.Call( *this );
+ }
+ else
+ {
+ aInfo.aMarkURL.clear();
+ aInfo.aMarkAltText.clear();
+ aInfo.aMarkTarget.clear();
+ aInfo.bOneMarked = false;
+ aInfo.bActivated = false;
+ }
+
+ aInfoLink.Call( *this );
+}
+
+void IMapWindow::DoMacroAssign()
+{
+ SdrObject* pSdrObj = GetSelectedSdrObject();
+
+ if ( !pSdrObj )
+ return;
+
+ SfxItemSetFixed<SID_ATTR_MACROITEM, SID_ATTR_MACROITEM, SID_EVENTCONFIG, SID_EVENTCONFIG>
+ aSet(*pIMapPool);
+
+ SfxEventNamesItem aNamesItem(SID_EVENTCONFIG);
+ aNamesItem.AddEvent( "MouseOver", "", SvMacroItemId::OnMouseOver );
+ aNamesItem.AddEvent( "MouseOut", "", SvMacroItemId::OnMouseOut );
+ aSet.Put( aNamesItem );
+
+ SvxMacroItem aMacroItem(SID_ATTR_MACROITEM);
+ IMapObject* pIMapObj = GetIMapObj( pSdrObj );
+ aMacroItem.SetMacroTable( pIMapObj->GetMacroTable() );
+ aSet.Put( aMacroItem );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractDialog> pMacroDlg(pFact->CreateEventConfigDialog(GetDrawingArea(), aSet, mxDocumentFrame));
+
+ if ( pMacroDlg->Execute() == RET_OK )
+ {
+ const SfxItemSet* pOutSet = pMacroDlg->GetOutputItemSet();
+ pIMapObj->SetMacroTable( pOutSet->Get( SID_ATTR_MACROITEM ).GetMacroTable() );
+ pModel->SetChanged();
+ UpdateInfo( false );
+ }
+}
+
+void IMapWindow::DoPropertyDialog()
+{
+ SdrObject* pSdrObj = GetSelectedSdrObject();
+
+ if ( !pSdrObj )
+ return;
+
+ IMapObject* pIMapObj = GetIMapObj( pSdrObj );
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractURLDlg> aDlg(pFact->CreateURLDialog(GetDrawingArea(), pIMapObj->GetURL(), pIMapObj->GetAltText(), pIMapObj->GetDesc(),
+ pIMapObj->GetTarget(), pIMapObj->GetName(), aTargetList));
+ if ( aDlg->Execute() != RET_OK )
+ return;
+
+ const OUString aURLText( aDlg->GetURL() );
+
+ if ( !aURLText.isEmpty() )
+ {
+ INetURLObject aObj( aURLText, INetProtocol::File );
+ DBG_ASSERT( aObj.GetProtocol() != INetProtocol::NotValid, "Invalid URL" );
+ pIMapObj->SetURL( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ }
+ else
+ pIMapObj->SetURL( aURLText );
+
+ pIMapObj->SetAltText( aDlg->GetAltText() );
+ pIMapObj->SetDesc( aDlg->GetDesc() );
+ pIMapObj->SetTarget( aDlg->GetTarget() );
+ pIMapObj->SetName( aDlg->GetName() );
+ pModel->SetChanged();
+ UpdateInfo( true );
+}
+
+void IMapWindow::MenuSelectHdl(const OString& rId)
+{
+ if (rId == "url")
+ DoPropertyDialog();
+ else if (rId == "macro")
+ DoMacroAssign();
+ else if (rId == "active")
+ {
+ const bool bNewState = !mxPopupMenu->get_active(rId);
+ SetCurrentObjState(bNewState);
+ UpdateInfo( false );
+ }
+ else if (rId == "front")
+ pView->PutMarkedToTop();
+ else if (rId == "forward")
+ pView->MovMarkedToTop();
+ else if (rId == "backward")
+ pView->MovMarkedToBtm();
+ else if (rId == "back")
+ pView->PutMarkedToBtm();
+ else if (rId == "selectall")
+ pView->MarkAll();
+ else if (rId == "delete")
+ pView->DeleteMarked();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/imapwnd.hxx b/svx/source/dialog/imapwnd.hxx
new file mode 100644
index 000000000..4ef2c9277
--- /dev/null
+++ b/svx/source/dialog/imapwnd.hxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_IMAPWND_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_IMAPWND_HXX
+
+#include <vcl/imapobj.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/imap.hxx>
+#include <sfx2/frame.hxx>
+#include <svx/graphctl.hxx>
+#include <svl/itempool.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+
+struct NotifyInfo
+{
+ OUString aMarkURL;
+ OUString aMarkAltText;
+ OUString aMarkTarget;
+ bool bNewObj;
+ bool bOneMarked;
+ bool bActivated;
+};
+
+
+#define SVD_IMAP_USERDATA 0x0001
+
+typedef std::shared_ptr< IMapObject > IMapObjectPtr;
+
+class IMapUserData : public SdrObjUserData
+{
+ // #i98386# use std::shared_ptr here due to cloning possibilities
+ IMapObjectPtr mpObj;
+
+public:
+
+ explicit IMapUserData( const IMapObjectPtr& rIMapObj ) :
+ SdrObjUserData ( SdrInventor::IMap, SVD_IMAP_USERDATA ),
+ mpObj ( rIMapObj ) {}
+
+ IMapUserData( const IMapUserData& rIMapUserData ) :
+ SdrObjUserData ( SdrInventor::IMap, SVD_IMAP_USERDATA ),
+ mpObj ( rIMapUserData.mpObj ) {}
+
+ virtual std::unique_ptr<SdrObjUserData> Clone( SdrObject * ) const override { return std::unique_ptr<SdrObjUserData>(new IMapUserData( *this )); }
+
+ const IMapObjectPtr& GetObject() const { return mpObj; }
+ void ReplaceObject( const IMapObjectPtr& pNewIMapObject ) { mpObj = pNewIMapObject; }
+};
+
+class IMapWindow;
+
+class IMapDropTargetHelper final : public DropTargetHelper
+{
+ IMapWindow& m_rImapWindow;
+public:
+ IMapDropTargetHelper(IMapWindow& rImapWindow);
+
+ // DropTargetHelper
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+};
+
+class IMapWindow final : public GraphCtrl
+{
+ NotifyInfo aInfo;
+ ImageMap aIMap;
+ TargetList aTargetList;
+ Link<IMapWindow&,void> aInfoLink;
+ rtl::Reference<SfxItemPool> pIMapPool;
+ SfxItemInfo maItemInfos[1] = {};
+ css::uno::Reference< css::frame::XFrame >
+ mxDocumentFrame;
+ std::unique_ptr<IMapDropTargetHelper> mxDropTargetHelper;
+ std::unique_ptr<weld::Menu> mxPopupMenu;
+
+ void MenuSelectHdl(const OString& rId);
+
+ // GraphCtrl
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ virtual bool Command(const CommandEvent& rCEvt) override;
+ virtual OUString RequestHelp(tools::Rectangle& rHelpArea) override;
+ virtual void SdrObjCreated( const SdrObject& rObj ) override;
+ virtual void SdrObjChanged( const SdrObject& rObj ) override;
+ virtual void MarkListHasChanged() override;
+ virtual void InitSdrModel() override;
+
+ void ReplaceImageMap( const ImageMap& rNewImageMap );
+
+ SdrObject* CreateObj( const IMapObject* pIMapObj );
+ static IMapObject* GetIMapObj( const SdrObject* pSdrObj );
+ SdrObject* GetHitSdrObj( const Point& rPosPixel ) const;
+
+ void UpdateInfo( bool bNewObj );
+
+public:
+
+ IMapWindow(const css::uno::Reference< css::frame::XFrame >& rxDocumentFrame,
+ weld::Dialog* pDialog);
+ virtual ~IMapWindow() override;
+
+ sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt );
+ sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt );
+
+ void ReplaceActualIMapInfo( const NotifyInfo& rNewInfo );
+
+ void SetImageMap( const ImageMap& rImageMap );
+ const ImageMap& GetImageMap();
+
+ void SetCurrentObjState( bool bActive );
+ void DoMacroAssign();
+ void DoPropertyDialog();
+
+ void SetInfoLink( const Link<IMapWindow&,void>& rLink ) { aInfoLink = rLink; }
+
+ void SetTargetList( const TargetList& rTargetList );
+
+ const NotifyInfo& GetInfo() const { return aInfo; }
+};
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/langbox.cxx b/svx/source/dialog/langbox.cxx
new file mode 100644
index 000000000..43d123b1e
--- /dev/null
+++ b/svx/source/dialog/langbox.cxx
@@ -0,0 +1,502 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/linguistic2/XAvailableLocales.hpp>
+#include <com/sun/star/linguistic2/XLinguServiceManager2.hpp>
+#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
+#include <linguistic/misc.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <tools/urlobj.hxx>
+#include <svtools/langtab.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/lang.h>
+#include <editeng/unolingu.hxx>
+#include <svl/languageoptions.hxx>
+#include <svx/langbox.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <bitmaps.hlst>
+
+#include <comphelper/string.hxx>
+#include <comphelper/processfactory.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::linguistic2;
+using namespace ::com::sun::star::uno;
+
+OUString GetDicInfoStr( std::u16string_view rName, const LanguageType nLang, bool bNeg )
+{
+ INetURLObject aURLObj;
+ aURLObj.SetSmartProtocol( INetProtocol::File );
+ aURLObj.SetSmartURL( rName, INetURLObject::EncodeMechanism::All );
+ OUString aTmp( aURLObj.GetBase() + " " );
+
+ if ( bNeg )
+ {
+ aTmp += " (-) ";
+ }
+
+ if ( LANGUAGE_NONE == nLang )
+ aTmp += SvxResId(RID_SVXSTR_LANGUAGE_ALL);
+ else
+ {
+ aTmp += "[" + SvtLanguageTable::GetLanguageString( nLang ) + "]";
+ }
+
+ return aTmp;
+}
+
+// misc local helper functions
+static std::vector< LanguageType > lcl_LocaleSeqToLangSeq( Sequence< css::lang::Locale > const &rSeq )
+{
+ sal_Int32 nCount = rSeq.getLength();
+
+ std::vector< LanguageType > aLangs;
+ aLangs.reserve(nCount);
+
+ std::transform(rSeq.begin(), rSeq.end(), std::back_inserter(aLangs),
+ [](const css::lang::Locale& rLocale) -> LanguageType {
+ return LanguageTag::convertToLanguageType(rLocale); });
+
+ return aLangs;
+}
+
+static bool lcl_SeqHasLang( const Sequence< sal_Int16 > & rLangSeq, sal_Int16 nLang )
+{
+ return rLangSeq.hasElements()
+ && std::find(rLangSeq.begin(), rLangSeq.end(), nLang) != rLangSeq.end();
+}
+
+namespace {
+
+bool lcl_isPrerequisite( LanguageType nLangType )
+{
+ return
+ nLangType != LANGUAGE_DONTKNOW &&
+ nLangType != LANGUAGE_SYSTEM &&
+ nLangType != LANGUAGE_NONE &&
+ nLangType != LANGUAGE_USER_KEYID &&
+ !MsLangId::isLegacy( nLangType) &&
+ MsLangId::getSubLanguage( nLangType);
+}
+
+bool lcl_isScriptTypeRequested( LanguageType nLangType, SvxLanguageListFlags nLangList )
+{
+ return
+ bool(nLangList & SvxLanguageListFlags::ALL) ||
+ (bool(nLangList & SvxLanguageListFlags::WESTERN) &&
+ (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType) == SvtScriptType::LATIN)) ||
+ (bool(nLangList & SvxLanguageListFlags::CTL) &&
+ (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType) == SvtScriptType::COMPLEX)) ||
+ (bool(nLangList & SvxLanguageListFlags::CJK) &&
+ (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType) == SvtScriptType::ASIAN));
+}
+
+}
+
+
+LanguageType SvxLanguageBox::get_active_id() const
+{
+ OUString sLang = m_xControl->get_active_id();
+ if (!sLang.isEmpty())
+ return LanguageType(sLang.toInt32());
+ else
+ return LANGUAGE_DONTKNOW;
+}
+
+int SvxLanguageBox::find_id(const LanguageType eLangType) const
+{
+ return m_xControl->find_id(OUString::number(static_cast<sal_uInt16>(eLangType)));
+}
+
+void SvxLanguageBox::set_id(int pos, const LanguageType eLangType)
+{
+ m_xControl->set_id(pos, OUString::number(static_cast<sal_uInt16>(eLangType)));
+}
+
+LanguageType SvxLanguageBox::get_id(int pos) const
+{
+ return LanguageType(m_xControl->get_id(pos).toInt32());
+}
+
+void SvxLanguageBox::remove_id(const LanguageType eLangType)
+{
+ m_xControl->remove_id(OUString::number(static_cast<sal_uInt16>(eLangType)));
+}
+
+void SvxLanguageBox::append(const LanguageType eLangType, const OUString& rStr)
+{
+ m_xControl->append(OUString::number(static_cast<sal_uInt16>(eLangType)), rStr);
+}
+
+void SvxLanguageBox::set_active_id(const LanguageType eLangType)
+{
+ // If the core uses a LangID of an imported MS document and wants to select
+ // a language that is replaced, we need to select the replacement instead.
+ LanguageType nLang = MsLangId::getReplacementForObsoleteLanguage( eLangType);
+
+ sal_Int32 nAt = ImplTypeToPos( nLang );
+
+ if (nAt == -1)
+ {
+ InsertLanguage( nLang ); // on-the-fly-ID
+ nAt = ImplTypeToPos( nLang );
+ }
+
+ if (nAt != -1)
+ m_xControl->set_active(nAt);
+}
+
+void SvxLanguageBox::AddLanguages(const std::vector< LanguageType >& rLanguageTypes,
+ SvxLanguageListFlags nLangList, std::vector<weld::ComboBoxEntry>& rEntries)
+{
+ for ( auto const & nLangType : rLanguageTypes )
+ {
+ if (lcl_isPrerequisite( nLangType ))
+ {
+ LanguageType nLang = MsLangId::getReplacementForObsoleteLanguage( nLangType );
+ if (lcl_isScriptTypeRequested( nLang, nLangList))
+ {
+ int nAt = ImplTypeToPos(nLang);
+ if (nAt != -1)
+ continue;
+ weld::ComboBoxEntry aNewEntry(BuildEntry(nLang));
+ if (aNewEntry.sString.isEmpty())
+ continue;
+ if (std::find_if(rEntries.begin(), rEntries.end(),
+ [=](const weld::ComboBoxEntry& rEntry){ return rEntry.sId == aNewEntry.sId; }) != rEntries.end())
+ continue;
+ rEntries.push_back(aNewEntry);
+ }
+ }
+ }
+}
+
+void SvxLanguageBox::SetLanguageList(SvxLanguageListFlags nLangList, bool bHasLangNone,
+ bool bLangNoneIsLangAll, bool bCheckSpellAvail,
+ bool bDefaultLangExist, LanguageType eDefaultLangType,
+ sal_Int16 nDefaultType)
+{
+ m_bHasLangNone = bHasLangNone;
+ m_bLangNoneIsLangAll = bLangNoneIsLangAll;
+ m_bWithCheckmark = bCheckSpellAvail;
+
+ if (SvxLanguageListFlags::EMPTY == nLangList)
+ {
+ m_xControl->clear();
+ return;
+ }
+
+ bool bAddAvailable = (!(nLangList & SvxLanguageListFlags::ONLY_KNOWN) &&
+ ((nLangList & SvxLanguageListFlags::ALL) ||
+ (nLangList & SvxLanguageListFlags::WESTERN) ||
+ (nLangList & SvxLanguageListFlags::CTL) ||
+ (nLangList & SvxLanguageListFlags::CJK)));
+ std::vector< LanguageType > aSpellAvailLang;
+ std::vector< LanguageType > aHyphAvailLang;
+ std::vector< LanguageType > aThesAvailLang;
+ Sequence< sal_Int16 > aSpellUsedLang;
+ Reference< XAvailableLocales > xAvail( LinguMgr::GetLngSvcMgr() );
+ if (xAvail.is())
+ {
+ Sequence< css::lang::Locale > aTmp;
+
+ if (bAddAvailable)
+ {
+ aTmp = xAvail->getAvailableLocales( SN_SPELLCHECKER );
+ aSpellAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
+
+ aTmp = xAvail->getAvailableLocales( SN_HYPHENATOR );
+ aHyphAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
+
+ aTmp = xAvail->getAvailableLocales( SN_THESAURUS );
+ aThesAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
+ }
+ }
+ if (SvxLanguageListFlags::SPELL_USED & nLangList)
+ {
+ Reference< XSpellChecker1 > xTmp1 = LinguMgr::GetSpellChecker();
+ if (xTmp1.is())
+ aSpellUsedLang = xTmp1->getLanguages();
+ }
+
+ std::vector<LanguageType> aKnown;
+ sal_uInt32 nCount;
+ if ( nLangList & SvxLanguageListFlags::ONLY_KNOWN )
+ {
+ aKnown = LocaleDataWrapper::getInstalledLanguageTypes();
+ nCount = aKnown.size();
+ }
+ else
+ {
+ nCount = SvtLanguageTable::GetLanguageEntryCount();
+ }
+
+ std::vector<weld::ComboBoxEntry> aEntries;
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ LanguageType nLangType;
+ if ( nLangList & SvxLanguageListFlags::ONLY_KNOWN )
+ nLangType = aKnown[i];
+ else
+ nLangType = SvtLanguageTable::GetLanguageTypeAtIndex( i );
+ if ( lcl_isPrerequisite( nLangType ) &&
+ (lcl_isScriptTypeRequested( nLangType, nLangList) ||
+ (bool(nLangList & SvxLanguageListFlags::FBD_CHARS) &&
+ MsLangId::hasForbiddenCharacters(nLangType)) ||
+ (bool(nLangList & SvxLanguageListFlags::SPELL_USED) &&
+ lcl_SeqHasLang(aSpellUsedLang, static_cast<sal_uInt16>(nLangType)))
+ ) )
+ {
+ aEntries.push_back(BuildEntry(nLangType));
+ if (aEntries.back().sString.isEmpty())
+ aEntries.pop_back();
+ }
+ }
+
+ if (bAddAvailable)
+ {
+ // Spell checkers, hyphenators and thesauri may add language tags
+ // unknown so far.
+ AddLanguages(aSpellAvailLang, nLangList, aEntries);
+ AddLanguages(aHyphAvailLang, nLangList, aEntries);
+ AddLanguages(aThesAvailLang, nLangList, aEntries);
+ }
+
+ std::sort(aEntries.begin(), aEntries.end(),
+ [](const weld::ComboBoxEntry e1, const weld::ComboBoxEntry e2) {
+ static const auto aSorter = comphelper::string::NaturalStringSorter(
+ ::comphelper::getProcessComponentContext(),
+ Application::GetSettings().GetLanguageTag().getLocale());
+ return aSorter.compare(e1.sString, e2.sString) < 0;
+ });
+
+ int nSeparatorPosition = 0;
+ if (bDefaultLangExist)
+ {
+ aEntries.insert(aEntries.begin(), BuildEntry(eDefaultLangType, nDefaultType));
+ nSeparatorPosition++;
+ }
+
+ if (bHasLangNone)
+ {
+ aEntries.insert(aEntries.begin(), BuildEntry(LANGUAGE_NONE));
+ nSeparatorPosition++;
+ }
+
+ m_xControl->insert_vector(aEntries, false);
+ if (nSeparatorPosition > 0)
+ m_xControl->insert_separator(nSeparatorPosition, "");
+}
+
+int SvxLanguageBox::ImplTypeToPos(LanguageType eType) const
+{
+ return m_xControl->find_id(OUString::number(static_cast<sal_uInt16>(eType)));
+}
+
+void SvxLanguageBox::InsertLanguage(const LanguageType nLangType, sal_Int16 nType)
+{
+ weld::ComboBoxEntry aEntry = BuildEntry(nLangType, nType);
+ if (aEntry.sString.isEmpty())
+ return;
+ if (aEntry.sImage.isEmpty())
+ m_xControl->append(aEntry.sId, aEntry.sString);
+ else
+ m_xControl->append(aEntry.sId, aEntry.sString, aEntry.sImage);
+}
+
+void SvxLanguageBox::InsertLanguage(const LanguageType nLangType)
+{
+ InsertLanguage(nLangType, css::i18n::ScriptType::WEAK);
+}
+
+weld::ComboBoxEntry SvxLanguageBox::BuildEntry(const LanguageType nLangType, sal_Int16 nType)
+{
+ LanguageType nLang = MsLangId::getReplacementForObsoleteLanguage(nLangType);
+ // For obsolete and to be replaced languages check whether an entry of the
+ // replacement already exists and if so don't add an entry with identical
+ // string as would be returned by SvtLanguageTable::GetString().
+ if (nLang != nLangType)
+ {
+ int nAt = ImplTypeToPos( nLang );
+ if (nAt != -1)
+ return weld::ComboBoxEntry("");
+ }
+
+ OUString aStrEntry = SvtLanguageTable::GetLanguageString( nLang );
+ if (LANGUAGE_NONE == nLang && m_bHasLangNone && m_bLangNoneIsLangAll)
+ aStrEntry = m_aAllString;
+
+ LanguageType nRealLang = nLang;
+ if (nRealLang == LANGUAGE_SYSTEM)
+ {
+ nRealLang = MsLangId::resolveSystemLanguageByScriptType(nRealLang, nType);
+ aStrEntry += " - " + SvtLanguageTable::GetLanguageString( nRealLang );
+ }
+ else if (nRealLang == LANGUAGE_USER_SYSTEM_CONFIG)
+ {
+ nRealLang = MsLangId::getSystemLanguage();
+ // Whatever we obtained, ensure a known supported locale.
+ nRealLang = LanguageTag(nRealLang).makeFallback().getLanguageType();
+ aStrEntry += " - " + SvtLanguageTable::GetLanguageString( nRealLang );
+ }
+
+ if (m_bWithCheckmark)
+ {
+ if (!m_xSpellUsedLang)
+ {
+ Reference<XSpellChecker1> xSpell = LinguMgr::GetSpellChecker();
+ if (xSpell.is())
+ m_xSpellUsedLang.reset(new Sequence<sal_Int16>(xSpell->getLanguages()));
+ }
+
+ bool bFound = m_xSpellUsedLang && lcl_SeqHasLang(*m_xSpellUsedLang, static_cast<sal_uInt16>(nRealLang));
+
+ return weld::ComboBoxEntry(aStrEntry, OUString::number(static_cast<sal_uInt16>(nLangType)), bFound ? OUString(RID_SVXBMP_CHECKED) : OUString(RID_SVXBMP_NOTCHECKED));
+ }
+ else
+ return weld::ComboBoxEntry(aStrEntry, OUString::number(static_cast<sal_uInt16>(nLangType)));
+}
+
+IMPL_LINK(SvxLanguageBox, ChangeHdl, weld::ComboBox&, rControl, void)
+{
+ if (rControl.has_entry())
+ {
+ EditedAndValid eOldState = m_eEditedAndValid;
+ OUString aStr(rControl.get_active_text());
+ if (aStr.isEmpty())
+ m_eEditedAndValid = EditedAndValid::Invalid;
+ else
+ {
+ const int nPos = rControl.find_text(aStr);
+ if (nPos != -1)
+ {
+ int nStartSelectPos, nEndSelectPos;
+ rControl.get_entry_selection_bounds(nStartSelectPos, nEndSelectPos);
+
+ // Select the corresponding listbox entry if not current. This
+ // invalidates the Edit Selection thus has to happen between
+ // obtaining the Selection and setting the new Selection.
+ int nSelPos = m_xControl->get_active();
+ bool bSetEditSelection;
+ if (nSelPos == nPos)
+ bSetEditSelection = false;
+ else
+ {
+ m_xControl->set_active(nPos);
+ bSetEditSelection = true;
+ }
+
+ // If typing into the Edit control led us here, advance start of a
+ // full selection by one so the next character will already
+ // continue the string instead of having to type the same character
+ // again to start a new string. The selection is in reverse
+ // when obtained from the Edit control.
+ if (nEndSelectPos == 0)
+ {
+ OUString aText(m_xControl->get_active_text());
+ if (nStartSelectPos == aText.getLength())
+ {
+ ++nEndSelectPos;
+ bSetEditSelection = true;
+ }
+ }
+
+ if (bSetEditSelection)
+ rControl.select_entry_region(nStartSelectPos, nEndSelectPos);
+
+ m_eEditedAndValid = EditedAndValid::No;
+ }
+ else
+ {
+ OUString aCanonicalized;
+ bool bValid = LanguageTag::isValidBcp47( aStr, &aCanonicalized, true);
+ m_eEditedAndValid = (bValid ? EditedAndValid::Valid : EditedAndValid::Invalid);
+ if (bValid && aCanonicalized != aStr)
+ {
+ m_xControl->set_entry_text(aCanonicalized);
+ const auto nCursorPos = aCanonicalized.getLength();
+ m_xControl->select_entry_region(nCursorPos, nCursorPos);
+ }
+ }
+ }
+ if (eOldState != m_eEditedAndValid)
+ {
+ if (m_eEditedAndValid == EditedAndValid::Invalid)
+ rControl.set_entry_message_type(weld::EntryMessageType::Error);
+ else
+ rControl.set_entry_message_type(weld::EntryMessageType::Normal);
+ }
+ }
+ m_aChangeHdl.Call(rControl);
+}
+
+SvxLanguageBox::SvxLanguageBox(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+ , m_aAllString(SvxResId(RID_SVXSTR_LANGUAGE_ALL))
+ , m_eSavedLanguage(LANGUAGE_DONTKNOW)
+ , m_eEditedAndValid(EditedAndValid::No)
+ , m_bHasLangNone(false)
+ , m_bLangNoneIsLangAll(false)
+ , m_bWithCheckmark(false)
+{
+ m_xControl->connect_changed(LINK(this, SvxLanguageBox, ChangeHdl));
+}
+
+sal_Int32 SvxLanguageBox::SaveEditedAsEntry()
+{
+ if (m_eEditedAndValid != EditedAndValid::Valid)
+ return -1;
+
+ LanguageTag aLanguageTag(m_xControl->get_active_text());
+ LanguageType nLang = aLanguageTag.getLanguageType();
+ if (nLang == LANGUAGE_DONTKNOW)
+ {
+ SAL_WARN( "svx.dialog", "SvxLanguageComboBox::SaveEditedAsEntry: unknown tag");
+ return -1;
+ }
+
+ int nPos = ImplTypeToPos( nLang);
+ if (nPos != -1)
+ return nPos; // Already present but with a different string.
+
+ if (SvtLanguageTable::HasLanguageType( nLang))
+ {
+ // In SvtLanguageTable but not in SvxLanguageComboBox. On purpose? This
+ // may be an entry with different settings or CTL instead of Western or
+ // ... all things we don't handle yet.
+ SAL_WARN( "svx.dialog", "SvxLanguageComboBox::SaveEditedAsEntry: already in SvtLanguageTable: " <<
+ SvtLanguageTable::GetLanguageString( nLang) << ", " << nLang);
+ }
+ else
+ {
+ // Add to both, SvtLanguageTable and SvxLanguageComboBox.
+ /* TODO: a descriptive user comment would be a nice to have here. */
+ SvtLanguageTable::AddLanguageTag( aLanguageTag );
+ }
+
+ InsertLanguage(nLang);
+ return ImplTypeToPos(nLang);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/linkwarn.cxx b/svx/source/dialog/linkwarn.cxx
new file mode 100644
index 000000000..852c92af1
--- /dev/null
+++ b/svx/source/dialog/linkwarn.cxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/file.hxx>
+#include <svx/linkwarn.hxx>
+#include <officecfg/Office/Common.hxx>
+
+SvxLinkWarningDialog::SvxLinkWarningDialog(weld::Widget* pParent, const OUString& _rFileName)
+ : MessageDialogController(pParent, "svx/ui/linkwarndialog.ui", "LinkWarnDialog", "ask")
+ , m_xWarningOnBox(m_xBuilder->weld_check_button("ask"))
+{
+ // replace filename
+ OUString sInfoText = m_xDialog->get_primary_text();
+ OUString aPath;
+ if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(_rFileName, aPath))
+ aPath = _rFileName;
+ sInfoText = sInfoText.replaceAll("%FILENAME", aPath);
+ m_xDialog->set_primary_text(sInfoText);
+
+ // load state of "warning on" checkbox from misc options
+ m_xWarningOnBox->set_active(officecfg::Office::Common::Misc::ShowLinkWarningDialog::get());
+ m_xWarningOnBox->set_sensitive(
+ !officecfg::Office::Common::Misc::ShowLinkWarningDialog::isReadOnly());
+}
+
+SvxLinkWarningDialog::~SvxLinkWarningDialog()
+{
+ try
+ {
+ // save value of "warning off" checkbox, if necessary
+ bool bChecked = m_xWarningOnBox->get_active();
+ if (officecfg::Office::Common::Misc::ShowLinkWarningDialog::get() != bChecked)
+ {
+ std::shared_ptr<comphelper::ConfigurationChanges> xChanges(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::ShowLinkWarningDialog::set(bChecked, xChanges);
+ xChanges->commit();
+ }
+ }
+ catch (...)
+ {
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/measctrl.cxx b/svx/source/dialog/measctrl.cxx
new file mode 100644
index 000000000..ac1303db2
--- /dev/null
+++ b/svx/source/dialog/measctrl.cxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/dialoghelper.hxx>
+#include <svx/svdomeas.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/measctrl.hxx>
+#include <svx/dlgutil.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <memory>
+
+SvxXMeasurePreview::SvxXMeasurePreview()
+ : m_aMapMode(MapUnit::Map100thMM)
+{
+ // Scale: 1:2
+ m_aMapMode.SetScaleX(Fraction(1, 2));
+ m_aMapMode.SetScaleY(Fraction(1, 2));
+}
+
+void SvxXMeasurePreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(getPreviewStripSize(pDrawingArea->get_ref_device()));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+
+ pModel.reset(new SdrModel(nullptr, nullptr, true));
+ pMeasureObj.reset(new SdrMeasureObj(*pModel, Point(), Point()));
+
+ ResizeImpl(aSize);
+ Invalidate();
+}
+
+void SvxXMeasurePreview::ResizeImpl(const Size& rSize)
+{
+ OutputDevice& rRefDevice = GetDrawingArea()->get_ref_device();
+ rRefDevice.Push(vcl::PushFlags::MAPMODE);
+
+ rRefDevice.SetMapMode(m_aMapMode);
+
+ Size aSize = rRefDevice.PixelToLogic(rSize);
+ Point aPt1(aSize.Width() / 5, static_cast<tools::Long>(aSize.Height() / 2));
+ pMeasureObj->SetPoint(aPt1, 0);
+ Point aPt2(aSize.Width() * 4 / 5, static_cast<tools::Long>(aSize.Height() / 2));
+ pMeasureObj->SetPoint(aPt2, 1);
+
+ rRefDevice.Pop();
+}
+
+void SvxXMeasurePreview::Resize()
+{
+ CustomWidgetController::Resize();
+ ResizeImpl(GetOutputSizePixel());
+ Invalidate();
+}
+
+SvxXMeasurePreview::~SvxXMeasurePreview() {}
+
+void SvxXMeasurePreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.SetBackground(rRenderContext.GetSettings().GetStyleSettings().GetWindowColor());
+ rRenderContext.Erase();
+
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+ rRenderContext.SetMapMode(m_aMapMode);
+
+ bool bHighContrast = Application::GetSettings().GetStyleSettings().GetHighContrastMode();
+ rRenderContext.SetDrawMode(bHighContrast ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR);
+ pMeasureObj->SingleObjectPainter(rRenderContext);
+
+ rRenderContext.Pop();
+}
+
+void SvxXMeasurePreview::SetAttributes(const SfxItemSet& rInAttrs)
+{
+ pMeasureObj->SetMergedItemSetAndBroadcast(rInAttrs);
+
+ Invalidate();
+}
+
+bool SvxXMeasurePreview::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bZoomIn = rMEvt.IsLeft() && !rMEvt.IsShift();
+ bool bZoomOut = rMEvt.IsRight() || rMEvt.IsShift();
+ bool bCtrl = rMEvt.IsMod1();
+
+ if (bZoomIn || bZoomOut)
+ {
+ Fraction aXFrac = m_aMapMode.GetScaleX();
+ Fraction aYFrac = m_aMapMode.GetScaleY();
+ std::unique_ptr<Fraction> pMultFrac;
+
+ if (bZoomIn)
+ {
+ if (bCtrl)
+ pMultFrac.reset(new Fraction(3, 2));
+ else
+ pMultFrac.reset(new Fraction(11, 10));
+ }
+ else
+ {
+ if (bCtrl)
+ pMultFrac.reset(new Fraction(2, 3));
+ else
+ pMultFrac.reset(new Fraction(10, 11));
+ }
+
+ aXFrac *= *pMultFrac;
+ aYFrac *= *pMultFrac;
+
+ if (double(aXFrac) > 0.001 && double(aXFrac) < 1000.0 && double(aYFrac) > 0.001
+ && double(aYFrac) < 1000.0)
+ {
+ m_aMapMode.SetScaleX(aXFrac);
+ m_aMapMode.SetScaleY(aYFrac);
+
+ OutputDevice& rRefDevice = GetDrawingArea()->get_ref_device();
+ rRefDevice.Push(vcl::PushFlags::MAPMODE);
+ rRefDevice.SetMapMode(m_aMapMode);
+ Size aOutSize(rRefDevice.PixelToLogic(GetOutputSizePixel()));
+ rRefDevice.Pop();
+
+ Point aPt(m_aMapMode.GetOrigin());
+ tools::Long nX = tools::Long(
+ (double(aOutSize.Width()) - (double(aOutSize.Width()) * double(*pMultFrac))) / 2.0
+ + 0.5);
+ tools::Long nY = tools::Long(
+ (double(aOutSize.Height()) - (double(aOutSize.Height()) * double(*pMultFrac))) / 2.0
+ + 0.5);
+ aPt.AdjustX(nX);
+ aPt.AdjustY(nY);
+
+ m_aMapMode.SetOrigin(aPt);
+
+ Invalidate();
+ }
+ }
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/optgrid.cxx b/svx/source/dialog/optgrid.cxx
new file mode 100644
index 000000000..3cd12b48d
--- /dev/null
+++ b/svx/source/dialog/optgrid.cxx
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/intitem.hxx>
+#include <svtools/unitconv.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/optgrid.hxx>
+#include <svx/dlgutil.hxx>
+
+// local functions
+static void lcl_GetMinMax(weld::MetricSpinButton const& rField, sal_Int64& nMin, sal_Int64& nMax)
+{
+ rField.get_range(nMin, nMax, FieldUnit::TWIP);
+ nMin = rField.denormalize(nMin);
+ nMax = rField.denormalize(nMax);
+}
+
+static void lcl_SetMinMax(weld::MetricSpinButton& rField, sal_Int64 nMin, sal_Int64 nMax)
+{
+ rField.set_range(rField.normalize(nMin), rField.normalize(nMax), FieldUnit::TWIP);
+}
+
+SvxOptionsGrid::SvxOptionsGrid() :
+ nFldDrawX ( 100 ),
+ nFldDivisionX ( 0 ),
+ nFldDrawY ( 100 ),
+ nFldDivisionY ( 0 ),
+ nFldSnapX ( 100 ),
+ nFldSnapY ( 100 ),
+ bUseGridsnap ( false ),
+ bSynchronize ( true ),
+ bGridVisible ( false ),
+ bEqualGrid ( true )
+{
+}
+
+SvxGridItem* SvxGridItem::Clone( SfxItemPool* ) const
+{
+ return new SvxGridItem( *this );
+}
+
+bool SvxGridItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+
+ const SvxGridItem& rItem = static_cast<const SvxGridItem&>(rAttr);
+
+ return ( bUseGridsnap == rItem.bUseGridsnap &&
+ bSynchronize == rItem.bSynchronize &&
+ bGridVisible == rItem.bGridVisible &&
+ bEqualGrid == rItem.bEqualGrid &&
+ nFldDrawX == rItem.nFldDrawX &&
+ nFldDivisionX== rItem.nFldDivisionX&&
+ nFldDrawY == rItem.nFldDrawY &&
+ nFldDivisionY== rItem.nFldDivisionY&&
+ nFldSnapX == rItem.nFldSnapX &&
+ nFldSnapY == rItem.nFldSnapY );
+}
+
+bool SvxGridItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = "SvxGridItem";
+ return true;
+}
+
+// TabPage Screen Settings
+SvxGridTabPage::SvxGridTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet)
+ : SfxTabPage(pPage, pController, "svx/ui/optgridpage.ui", "OptGridPage", &rCoreSet)
+ , bAttrModified(false)
+ , m_xCbxUseGridsnap(m_xBuilder->weld_check_button("usegridsnap"))
+ , m_xCbxGridVisible(m_xBuilder->weld_check_button("gridvisible"))
+ , m_xMtrFldDrawX(m_xBuilder->weld_metric_spin_button("mtrflddrawx", FieldUnit::CM))
+ , m_xMtrFldDrawY(m_xBuilder->weld_metric_spin_button("mtrflddrawy", FieldUnit::CM))
+ , m_xNumFldDivisionX(m_xBuilder->weld_spin_button("numflddivisionx"))
+ , m_xNumFldDivisionY(m_xBuilder->weld_spin_button("numflddivisiony"))
+ , m_xCbxSynchronize(m_xBuilder->weld_check_button("synchronize"))
+ , m_xSnapFrames(m_xBuilder->weld_widget("snapframes"))
+ , m_xCbxSnapHelplines(m_xBuilder->weld_check_button("snaphelplines"))
+ , m_xCbxSnapBorder(m_xBuilder->weld_check_button("snapborder"))
+ , m_xCbxSnapFrame(m_xBuilder->weld_check_button("snapframe"))
+ , m_xCbxSnapPoints(m_xBuilder->weld_check_button("snappoints"))
+ , m_xMtrFldSnapArea(m_xBuilder->weld_metric_spin_button("mtrfldsnaparea", FieldUnit::PIXEL))
+ , m_xCbxOrtho(m_xBuilder->weld_check_button("ortho"))
+ , m_xCbxBigOrtho(m_xBuilder->weld_check_button("bigortho"))
+ , m_xCbxRotate(m_xBuilder->weld_check_button("rotate"))
+ , m_xMtrFldAngle(m_xBuilder->weld_metric_spin_button("mtrfldangle", FieldUnit::DEGREE))
+ , m_xMtrFldBezAngle(m_xBuilder->weld_metric_spin_button("mtrfldbezangle", FieldUnit::DEGREE))
+{
+ // This page requires exchange Support
+ SetExchangeSupport();
+
+ // Set Metrics
+ FieldUnit eFUnit = GetModuleFieldUnit( rCoreSet );
+ sal_Int64 nMin, nMax;
+
+ lcl_GetMinMax(*m_xMtrFldDrawX, nMin, nMax);
+ SetFieldUnit( *m_xMtrFldDrawX, eFUnit, true );
+ lcl_SetMinMax(*m_xMtrFldDrawX, nMin, nMax);
+
+ lcl_GetMinMax(*m_xMtrFldDrawY, nMin, nMax);
+ SetFieldUnit( *m_xMtrFldDrawY, eFUnit, true );
+ lcl_SetMinMax(*m_xMtrFldDrawY, nMin, nMax);
+
+
+ m_xCbxRotate->connect_toggled(LINK(this, SvxGridTabPage, ClickRotateHdl_Impl));
+ Link<weld::Toggleable&,void> aLink = LINK(this, SvxGridTabPage, ChangeGridsnapHdl_Impl);
+ m_xCbxUseGridsnap->connect_toggled(aLink);
+ m_xCbxSynchronize->connect_toggled(aLink);
+ m_xCbxGridVisible->connect_toggled(aLink);
+ m_xMtrFldDrawX->connect_value_changed(
+ LINK( this, SvxGridTabPage, ChangeDrawHdl_Impl ) );
+ m_xMtrFldDrawY->connect_value_changed(
+ LINK( this, SvxGridTabPage, ChangeDrawHdl_Impl ) );
+ m_xNumFldDivisionX->connect_value_changed(
+ LINK( this, SvxGridTabPage, ChangeDivisionHdl_Impl ) );
+ m_xNumFldDivisionY->connect_value_changed(
+ LINK( this, SvxGridTabPage, ChangeDivisionHdl_Impl ) );
+}
+
+SvxGridTabPage::~SvxGridTabPage()
+{
+}
+
+std::unique_ptr<SfxTabPage> SvxGridTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet)
+{
+ return std::make_unique<SvxGridTabPage>(pPage, pController, rAttrSet);
+}
+
+bool SvxGridTabPage::FillItemSet( SfxItemSet* rCoreSet )
+{
+ if ( bAttrModified )
+ {
+ SvxGridItem aGridItem( SID_ATTR_GRID_OPTIONS );
+
+ aGridItem.bUseGridsnap = m_xCbxUseGridsnap->get_active();
+ aGridItem.bSynchronize = m_xCbxSynchronize->get_active();
+ aGridItem.bGridVisible = m_xCbxGridVisible->get_active();
+
+ MapUnit eUnit = rCoreSet->GetPool()->GetMetric( SID_ATTR_GRID_OPTIONS );
+ tools::Long nX = GetCoreValue( *m_xMtrFldDrawX, eUnit );
+ tools::Long nY = GetCoreValue( *m_xMtrFldDrawY, eUnit );
+
+ aGridItem.nFldDrawX = static_cast<sal_uInt32>(nX);
+ aGridItem.nFldDrawY = static_cast<sal_uInt32>(nY);
+ aGridItem.nFldDivisionX = static_cast<tools::Long>(m_xNumFldDivisionX->get_value() - 1);
+ aGridItem.nFldDivisionY = static_cast<tools::Long>(m_xNumFldDivisionY->get_value() - 1);
+
+ rCoreSet->Put( aGridItem );
+ }
+ return bAttrModified;
+}
+
+void SvxGridTabPage::Reset( const SfxItemSet* rSet )
+{
+ const SvxGridItem* pGridAttr = nullptr;
+
+ if( (pGridAttr = rSet->GetItemIfSet( SID_ATTR_GRID_OPTIONS , false )) )
+ {
+ m_xCbxUseGridsnap->set_active(pGridAttr->bUseGridsnap);
+ m_xCbxSynchronize->set_active(pGridAttr->bSynchronize);
+ m_xCbxGridVisible->set_active(pGridAttr->bGridVisible);
+
+ MapUnit eUnit = rSet->GetPool()->GetMetric( SID_ATTR_GRID_OPTIONS );
+ SetMetricValue( *m_xMtrFldDrawX , pGridAttr->nFldDrawX, eUnit );
+ SetMetricValue( *m_xMtrFldDrawY , pGridAttr->nFldDrawY, eUnit );
+
+ m_xNumFldDivisionX->set_value(pGridAttr->nFldDivisionX + 1);
+ m_xNumFldDivisionY->set_value(pGridAttr->nFldDivisionY + 1);
+ }
+
+ ChangeGridsnapHdl_Impl(*m_xCbxUseGridsnap);
+ bAttrModified = false;
+}
+
+void SvxGridTabPage::ActivatePage( const SfxItemSet& rSet )
+{
+ const SvxGridItem* pGridAttr = nullptr;
+ if( (pGridAttr = rSet.GetItemIfSet( SID_ATTR_GRID_OPTIONS , false )) )
+ {
+ m_xCbxUseGridsnap->set_active(pGridAttr->bUseGridsnap);
+
+ ChangeGridsnapHdl_Impl(*m_xCbxUseGridsnap);
+ }
+
+ // Metric Change if necessary (as TabPage is in the dialog, where the
+ // metric can be set
+ const SfxUInt16Item* pItem = rSet.GetItemIfSet( SID_ATTR_METRIC , false );
+ if( !pItem )
+ return;
+
+
+ FieldUnit eFUnit = static_cast<FieldUnit>(static_cast<tools::Long>(pItem->GetValue()));
+
+ if (eFUnit == m_xMtrFldDrawX->get_unit())
+ return;
+
+ // Set Metrics
+ sal_Int64 nMin, nMax;
+ int nVal = m_xMtrFldDrawX->denormalize(m_xMtrFldDrawX->get_value(FieldUnit::TWIP));
+
+ lcl_GetMinMax(*m_xMtrFldDrawX, nMin, nMax);
+ SetFieldUnit(*m_xMtrFldDrawX, eFUnit, true);
+ lcl_SetMinMax(*m_xMtrFldDrawX, nMin, nMax);
+
+ m_xMtrFldDrawX->set_value(m_xMtrFldDrawX->normalize(nVal), FieldUnit::TWIP);
+
+ nVal = m_xMtrFldDrawY->denormalize(m_xMtrFldDrawY->get_value(FieldUnit::TWIP));
+ lcl_GetMinMax(*m_xMtrFldDrawY, nMin, nMax);
+ SetFieldUnit(*m_xMtrFldDrawY, eFUnit, true);
+ lcl_SetMinMax(*m_xMtrFldDrawY, nMin, nMax);
+ m_xMtrFldDrawY->set_value(m_xMtrFldDrawY->normalize(nVal), FieldUnit::TWIP);
+}
+
+DeactivateRC SvxGridTabPage::DeactivatePage( SfxItemSet* _pSet )
+{
+ if ( _pSet )
+ FillItemSet( _pSet );
+ return DeactivateRC::LeavePage;
+}
+
+IMPL_LINK(SvxGridTabPage, ChangeDrawHdl_Impl, weld::MetricSpinButton&, rField, void)
+{
+ bAttrModified = true;
+ if (m_xCbxSynchronize->get_active())
+ {
+ if (&rField == m_xMtrFldDrawX.get())
+ m_xMtrFldDrawY->set_value(m_xMtrFldDrawX->get_value(FieldUnit::NONE), FieldUnit::NONE);
+ else
+ m_xMtrFldDrawX->set_value(m_xMtrFldDrawY->get_value(FieldUnit::NONE), FieldUnit::NONE);
+ }
+}
+
+IMPL_LINK_NOARG(SvxGridTabPage, ClickRotateHdl_Impl, weld::Toggleable&, void)
+{
+ if (m_xCbxRotate->get_active())
+ m_xMtrFldAngle->set_sensitive(true);
+ else
+ m_xMtrFldAngle->set_sensitive(false);
+}
+
+IMPL_LINK(SvxGridTabPage, ChangeDivisionHdl_Impl, weld::SpinButton&, rField, void)
+{
+ bAttrModified = true;
+ if (m_xCbxSynchronize->get_active())
+ {
+ if (m_xNumFldDivisionX.get() == &rField)
+ m_xNumFldDivisionY->set_value(m_xNumFldDivisionX->get_value());
+ else
+ m_xNumFldDivisionX->set_value(m_xNumFldDivisionY->get_value());
+ }
+}
+
+IMPL_LINK_NOARG(SvxGridTabPage, ChangeGridsnapHdl_Impl, weld::Toggleable&, void)
+{
+ bAttrModified = true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/page.hrc b/svx/source/dialog/page.hrc
new file mode 100644
index 000000000..52e8a0dab
--- /dev/null
+++ b/svx/source/dialog/page.hrc
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_PAGE_HRC
+#define INCLUDED_SVX_SOURCE_DIALOG_PAGE_HRC
+
+#include <i18nutil/paper.hxx>
+#include <unotools/resmgr.hxx>
+#include <utility>
+
+#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String))
+
+const std::pair<TranslateId, int> RID_SVXSTRARY_PAPERSIZE_STD[] =
+{
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "A6") , PAPER_A6 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "A5") , PAPER_A5 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "A4") , PAPER_A4 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "A3") , PAPER_A3 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B6 (ISO)") , PAPER_B6_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B5 (ISO)") , PAPER_B5_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B4 (ISO)") , PAPER_B4_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Letter") , PAPER_LETTER },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Legal") , PAPER_LEGAL },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Long Bond") , PAPER_FANFOLD_LEGAL_DE },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Tabloid") , PAPER_TABLOID },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B6 (JIS)") , PAPER_B6_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B5 (JIS)") , PAPER_B5_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B4 (JIS)") , PAPER_B4_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "16 Kai") , PAPER_KAI16},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "32 Kai") , PAPER_KAI32},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Big 32 Kai") , PAPER_KAI32BIG},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "User") , PAPER_USER },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "DL Envelope") , PAPER_ENV_DL },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "C6 Envelope") , PAPER_ENV_C6 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "C6/5 Envelope") , PAPER_ENV_C65 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "C5 Envelope") , PAPER_ENV_C5 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "C4 Envelope") , PAPER_ENV_C4 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#6¾ Envelope") , PAPER_ENV_PERSONAL},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#7¾ (Monarch) Envelope") , PAPER_ENV_MONARCH},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#9 Envelope") , PAPER_ENV_9},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#10 Envelope") , PAPER_ENV_10},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#11 Envelope") , PAPER_ENV_11},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#12 Envelope") , PAPER_ENV_12},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Japanese Postcard") , PAPER_POSTCARD_JP}
+};
+
+const std::pair<TranslateId, int> RID_SVXSTRARY_PAPERSIZE_DRAW[] =
+{
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A6") , PAPER_A6 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A5") , PAPER_A5 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A4") , PAPER_A4 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A3") , PAPER_A3 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A2") , PAPER_A2 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A1") , PAPER_A1 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A0") , PAPER_A0 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B6 (ISO)") , PAPER_B6_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B5 (ISO)") , PAPER_B5_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B4 (ISO)") , PAPER_B4_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Letter") , PAPER_LETTER },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Legal") , PAPER_LEGAL },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Long Bond") , PAPER_FANFOLD_LEGAL_DE },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Tabloid") , PAPER_TABLOID },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B6 (JIS)") , PAPER_B6_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B5 (JIS)") , PAPER_B5_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B4 (JIS)") , PAPER_B4_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "16 Kai") , PAPER_KAI16},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "32 Kai") , PAPER_KAI32},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Big 32 Kai") , PAPER_KAI32BIG},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "User") , PAPER_USER },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "DL Envelope") , PAPER_ENV_DL },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "C6 Envelope") , PAPER_ENV_C6 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "C6/5 Envelope") , PAPER_ENV_C65 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "C5 Envelope") , PAPER_ENV_C5 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "C4 Envelope") , PAPER_ENV_C4 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Dia Slide") , PAPER_SLIDE_DIA },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Screen 4:3") , PAPER_SCREEN_4_3 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Screen 16:9") , PAPER_SCREEN_16_9 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Screen 16:10") , PAPER_SCREEN_16_10 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Widescreen") , PAPER_WIDESCREEN },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "On-screen Show (4:3)") , PAPER_ONSCREENSHOW_4_3 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "On-screen Show (16:9)") , PAPER_ONSCREENSHOW_16_9 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "On-screen Show (16:10)") , PAPER_ONSCREENSHOW_16_10 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Japanese Postcard") , PAPER_POSTCARD_JP}
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/pagectrl.cxx b/svx/source/dialog/pagectrl.cxx
new file mode 100644
index 000000000..a55f6a257
--- /dev/null
+++ b/svx/source/dialog/pagectrl.cxx
@@ -0,0 +1,396 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <editeng/frmdir.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+#include <tools/fract.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/pagectrl.hxx>
+#include <algorithm>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+#define CELL_WIDTH 1600L
+#define CELL_HEIGHT 800L
+
+SvxPageWindow::SvxPageWindow() :
+ nTop(0),
+ nBottom(0),
+ nLeft(0),
+ nRight(0),
+ bResetBackground(false),
+ bFrameDirection(false),
+ nFrameDirection(SvxFrameDirection::Horizontal_LR_TB),
+ nHdLeft(0),
+ nHdRight(0),
+ nHdDist(0),
+ nHdHeight(0),
+ nFtLeft(0),
+ nFtRight(0),
+ nFtDist(0),
+ nFtHeight(0),
+ bFooter(false),
+ bHeader(false),
+ bTable(false),
+ bHorz(false),
+ bVert(false),
+ eUsage(SvxPageUsage::All)
+{
+}
+
+SvxPageWindow::~SvxPageWindow()
+{
+}
+
+void SvxPageWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
+
+ Fraction aXScale(aWinSize.Width(), std::max(aSize.Width() * 2 + aSize.Width() / 8, tools::Long(1)));
+ Fraction aYScale(aWinSize.Height(), std::max(aSize.Height(), tools::Long(1)));
+ MapMode aMapMode(rRenderContext.GetMapMode());
+
+ if(aYScale < aXScale)
+ {
+ aMapMode.SetScaleX(aYScale);
+ aMapMode.SetScaleY(aYScale);
+ }
+ else
+ {
+ aMapMode.SetScaleX(aXScale);
+ aMapMode.SetScaleY(aXScale);
+ }
+ rRenderContext.SetMapMode(aMapMode);
+ Size aSz(rRenderContext.PixelToLogic(GetOutputSizePixel()));
+ tools::Long nYPos = (aSz.Height() - aSize.Height()) / 2;
+
+ if (eUsage == SvxPageUsage::All)
+ {
+ // all pages are equal -> draw one page
+ if (aSize.Width() > aSize.Height())
+ {
+ // Draw Landscape page of the same size
+ Fraction aX = aMapMode.GetScaleX();
+ Fraction aY = aMapMode.GetScaleY();
+ Fraction a2(1.5);
+ aX *= a2;
+ aY *= a2;
+ aMapMode.SetScaleX(aX);
+ aMapMode.SetScaleY(aY);
+ rRenderContext.SetMapMode(aMapMode);
+ aSz = rRenderContext.PixelToLogic(GetOutputSizePixel());
+ nYPos = (aSz.Height() - aSize.Height()) / 2;
+ tools::Long nXPos = (aSz.Width() - aSize.Width()) / 2;
+ DrawPage(rRenderContext, Point(nXPos,nYPos),true,true);
+ }
+ else
+ // Portrait
+ DrawPage(rRenderContext, Point((aSz.Width() - aSize.Width()) / 2,nYPos),true,true);
+ }
+ else
+ {
+ // Left and right page are different -> draw two pages if possible
+ DrawPage(rRenderContext, Point(0, nYPos), false,
+ eUsage == SvxPageUsage::Left || eUsage == SvxPageUsage::All || eUsage == SvxPageUsage::Mirror);
+ DrawPage(rRenderContext, Point(aSize.Width() + aSize.Width() / 8, nYPos), true,
+ eUsage == SvxPageUsage::Right || eUsage == SvxPageUsage::All || eUsage == SvxPageUsage::Mirror);
+ }
+ rRenderContext.Pop();
+}
+
+void SvxPageWindow::DrawPage(vcl::RenderContext& rRenderContext, const Point& rOrg, const bool bSecond, const bool bEnabled)
+{
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+ const Color& rFieldColor = rStyleSettings.GetFieldColor();
+ const Color& rFieldTextColor = rStyleSettings.GetFieldTextColor();
+ const Color& rDisableColor = rStyleSettings.GetDisableColor();
+ const Color& rDlgColor = rStyleSettings.GetDialogColor();
+
+ // background
+ if (!bSecond || bResetBackground)
+ {
+ rRenderContext.SetLineColor(COL_TRANSPARENT);
+ rRenderContext.SetFillColor(rDlgColor);
+ Size winSize(rRenderContext.GetOutputSize());
+ rRenderContext.DrawRect(tools::Rectangle(Point(0,0), winSize));
+
+ if (bResetBackground)
+ bResetBackground = false;
+ }
+ rRenderContext.SetLineColor(rFieldTextColor);
+
+ // Shadow
+ Size aTempSize = aSize;
+
+ // Page
+ if (!bEnabled)
+ {
+ rRenderContext.SetFillColor(rDisableColor);
+ rRenderContext.DrawRect(tools::Rectangle(rOrg, aTempSize));
+ return;
+ }
+ rRenderContext.SetFillColor(rFieldColor);
+ rRenderContext.DrawRect(tools::Rectangle(rOrg, aTempSize));
+
+ tools::Long nL = nLeft;
+ tools::Long nR = nRight;
+
+ if (eUsage == SvxPageUsage::Mirror && !bSecond)
+ {
+ // turn for mirrored
+ nL = nRight;
+ nR = nLeft;
+ }
+
+ tools::Rectangle aRect;
+
+ aRect.SetLeft( rOrg.X() + nL );
+ aRect.SetRight( rOrg.X() + aTempSize.Width() - nR );
+ aRect.SetTop( rOrg.Y() + nTop );
+ aRect.SetBottom( rOrg.Y() + aTempSize.Height() - nBottom );
+
+ tools::Rectangle aHdRect(aRect);
+ tools::Rectangle aFtRect(aRect);
+
+ if (bHeader || bFooter)
+ {
+ // Header and/or footer used
+ const Color aLineColor(rRenderContext.GetLineColor());
+
+ // draw PageFill first and on the whole page, no outline
+ rRenderContext.SetLineColor();
+ drawFillAttributes(rRenderContext, maPageFillAttributes, aRect, aRect);
+ rRenderContext.SetLineColor(aLineColor);
+
+ if (bHeader)
+ {
+ // show headers if possible
+ aHdRect.AdjustLeft(nHdLeft );
+ aHdRect.AdjustRight( -nHdRight );
+ aHdRect.SetBottom( aRect.Top() + nHdHeight );
+ aRect.AdjustTop(nHdHeight + nHdDist );
+
+ // draw header over PageFill, plus outline
+ drawFillAttributes(rRenderContext, maHeaderFillAttributes, aHdRect, aHdRect);
+ }
+
+ if (bFooter)
+ {
+ // show footer if possible
+ aFtRect.AdjustLeft(nFtLeft );
+ aFtRect.AdjustRight( -nFtRight );
+ aFtRect.SetTop( aRect.Bottom() - nFtHeight );
+ aRect.AdjustBottom( -(nFtHeight + nFtDist) );
+
+ // draw footer over PageFill, plus outline
+ drawFillAttributes(rRenderContext, maFooterFillAttributes, aFtRect, aFtRect);
+ }
+
+ // draw page's reduced outline, only outline
+ drawFillAttributes(rRenderContext, drawinglayer::attribute::SdrAllFillAttributesHelperPtr(), aRect, aRect);
+ }
+ else
+ {
+ // draw PageFill and outline
+ drawFillAttributes(rRenderContext, maPageFillAttributes, aRect, aRect);
+ }
+
+ if (bFrameDirection && !bTable)
+ {
+ Point aPos;
+ vcl::Font aFont(rRenderContext.GetFont());
+ const Size aSaveSize = aFont.GetFontSize();
+ Size aDrawSize(0,aRect.GetHeight() / 6);
+ aFont.SetFontSize(aDrawSize);
+ rRenderContext.SetFont(aFont);
+ OUString sText("ABC");
+ Point aMove(1, rRenderContext.GetTextHeight());
+ sal_Unicode cArrow = 0x2193;
+ tools::Long nAWidth = rRenderContext.GetTextWidth(sText.copy(0,1));
+ switch (nFrameDirection)
+ {
+ case SvxFrameDirection::Horizontal_LR_TB:
+ aPos = aRect.TopLeft();
+ aPos.AdjustX(rRenderContext.PixelToLogic(Point(1,1)).X() );
+ aMove.setY( 0 );
+ cArrow = 0x2192;
+ break;
+ case SvxFrameDirection::Horizontal_RL_TB:
+ aPos = aRect.TopRight();
+ aPos.AdjustX( -nAWidth );
+ aMove.setY( 0 );
+ aMove.setX( aMove.X() * -1 );
+ cArrow = 0x2190;
+ break;
+ case SvxFrameDirection::Vertical_LR_TB:
+ aPos = aRect.TopLeft();
+ aPos.AdjustX(rRenderContext.PixelToLogic(Point(1,1)).X() );
+ aMove.setX( 0 );
+ break;
+ case SvxFrameDirection::Vertical_RL_TB:
+ aPos = aRect.TopRight();
+ aPos.AdjustX( -nAWidth );
+ aMove.setX( 0 );
+ break;
+ default: break;
+ }
+ sText += OUStringChar(cArrow);
+ for (sal_Int32 i = 0; i < sText.getLength(); i++)
+ {
+ OUString sDraw(sText.copy(i,1));
+ tools::Long nHDiff = 0;
+ tools::Long nCharWidth = rRenderContext.GetTextWidth(sDraw);
+ bool bHorizontal = 0 == aMove.Y();
+ if (!bHorizontal)
+ {
+ nHDiff = (nAWidth - nCharWidth) / 2;
+ aPos.AdjustX(nHDiff );
+ }
+ rRenderContext.DrawText(aPos,sDraw);
+ if (bHorizontal)
+ {
+ aPos.AdjustX(aMove.X() < 0 ? -nCharWidth : nCharWidth );
+ }
+ else
+ {
+ aPos.AdjustX( -nHDiff );
+ aPos.AdjustY(aMove.Y() );
+ }
+ }
+ aFont.SetFontSize(aSaveSize);
+ rRenderContext.SetFont(aFont);
+
+ }
+ if (!bTable)
+ return;
+
+ // Paint Table, if necessary center it
+ rRenderContext.SetLineColor(COL_LIGHTGRAY);
+
+ tools::Long nW = aRect.GetWidth();
+ tools::Long nH = aRect.GetHeight();
+ tools::Long const nTW = CELL_WIDTH * 3;
+ tools::Long const nTH = CELL_HEIGHT * 3;
+ tools::Long _nLeft = bHorz ? aRect.Left() + ((nW - nTW) / 2) : aRect.Left();
+ tools::Long _nTop = bVert ? aRect.Top() + ((nH - nTH) / 2) : aRect.Top();
+ tools::Rectangle aCellRect(Point(_nLeft, _nTop),Size(CELL_WIDTH, CELL_HEIGHT));
+
+ for (sal_uInt16 i = 0; i < 3; ++i)
+ {
+ aCellRect.SetLeft( _nLeft );
+ aCellRect.SetRight( _nLeft + CELL_WIDTH );
+ if(i > 0)
+ aCellRect.Move(0,CELL_HEIGHT);
+
+ for (sal_uInt16 j = 0; j < 3; ++j)
+ {
+ if (j > 0)
+ aCellRect.Move(CELL_WIDTH,0);
+ rRenderContext.DrawRect(aCellRect);
+ }
+ }
+}
+
+void SvxPageWindow::drawFillAttributes(vcl::RenderContext& rRenderContext,
+ const drawinglayer::attribute::SdrAllFillAttributesHelperPtr& rFillAttributes,
+ const tools::Rectangle& rPaintRange,
+ const tools::Rectangle& rDefineRange)
+{
+ const basegfx::B2DRange aPaintRange = vcl::unotools::b2DRectangleFromRectangle(rPaintRange);
+
+ if(aPaintRange.isEmpty() ||
+ basegfx::fTools::equalZero(aPaintRange.getWidth()) ||
+ basegfx::fTools::equalZero(aPaintRange.getHeight()))
+ return;
+
+ const basegfx::B2DRange aDefineRange = vcl::unotools::b2DRectangleFromRectangle(rDefineRange);
+
+ // prepare primitive sequence
+ drawinglayer::primitive2d::Primitive2DContainer aSequence;
+
+ // create fill geometry if there is something to fill
+ if (rFillAttributes && rFillAttributes->isUsed())
+ {
+ aSequence = rFillAttributes->getPrimitive2DSequence(aPaintRange, aDefineRange);
+ }
+
+ // create line geometry if a LineColor is set at the target device
+ if (rRenderContext.IsLineColor())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xOutline(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ basegfx::utils::createPolygonFromRect(aPaintRange), rRenderContext.GetLineColor().getBColor()));
+
+ aSequence.push_back(xOutline);
+ }
+
+ // draw that if we have something to draw
+ if (aSequence.empty())
+ return;
+
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D(
+ basegfx::B2DHomMatrix(), rRenderContext.GetViewTransformation(), aPaintRange, nullptr, 0.0);
+
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
+ drawinglayer::processor2d::createProcessor2DFromOutputDevice(rRenderContext, aViewInformation2D));
+ pProcessor->process(aSequence);
+}
+
+void SvxPageWindow::EnableFrameDirection(bool bEnable)
+{
+ bFrameDirection = bEnable;
+}
+
+void SvxPageWindow::SetFrameDirection(SvxFrameDirection nDirection)
+{
+ nFrameDirection = nDirection;
+}
+
+void SvxPageWindow::ResetBackground()
+{
+ bResetBackground = true;
+}
+
+void SvxPageWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+
+ OutputDevice& rRefDevice = pDrawingArea->get_ref_device();
+ // Count in Twips by default
+ rRefDevice.Push(vcl::PushFlags::MAPMODE);
+ rRefDevice.SetMapMode(MapMode(MapUnit::MapTwip));
+ aWinSize = rRefDevice.LogicToPixel(Size(75, 46), MapMode(MapUnit::MapAppFont));
+ pDrawingArea->set_size_request(aWinSize.Width(), aWinSize.Height());
+
+ aWinSize.AdjustHeight( -4 );
+ aWinSize.AdjustWidth( -4 );
+
+ aWinSize = rRefDevice.PixelToLogic(aWinSize);
+ rRefDevice.Pop();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/pagenumberlistbox.cxx b/svx/source/dialog/pagenumberlistbox.cxx
new file mode 100644
index 000000000..076da12e1
--- /dev/null
+++ b/svx/source/dialog/pagenumberlistbox.cxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/pagenumberlistbox.hxx>
+#include <editeng/numitem.hxx>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <numberingtype.hrc>
+
+SvxPageNumberListBox::SvxPageNumberListBox(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+{
+ m_xControl->set_size_request(150, -1);
+
+ for (size_t i = 0; i < SAL_N_ELEMENTS(RID_SVXSTRARY_NUMBERINGTYPE); ++i)
+ {
+ sal_uInt16 nData = RID_SVXSTRARY_NUMBERINGTYPE[i].second;
+ switch (nData)
+ {
+ // String list array is also used in Writer and contains strings
+ // for Bullet and Graphics, ignore those here.
+ case css::style::NumberingType::CHAR_SPECIAL:
+ case css::style::NumberingType::BITMAP:
+ case css::style::NumberingType::BITMAP | LINK_TOKEN:
+ break;
+ default:
+ {
+ OUString aStr = SvxResId(RID_SVXSTRARY_NUMBERINGTYPE[i].first);
+ m_xControl->append(OUString::number(nData), aStr);
+ break;
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/papersizelistbox.cxx b/svx/source/dialog/papersizelistbox.cxx
new file mode 100644
index 000000000..fc0211a8b
--- /dev/null
+++ b/svx/source/dialog/papersizelistbox.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/papersizelistbox.hxx>
+#include "page.hrc"
+
+SvxPaperSizeListBox::SvxPaperSizeListBox(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+{
+ m_xControl->set_size_request(150, -1);
+}
+
+void SvxPaperSizeListBox::FillPaperSizeEntries( PaperSizeApp eApp )
+{
+ const std::pair<TranslateId, int>* pPaperAry = eApp == PaperSizeApp::Std ?
+ RID_SVXSTRARY_PAPERSIZE_STD : RID_SVXSTRARY_PAPERSIZE_DRAW;
+ sal_uInt32 nCnt = eApp == PaperSizeApp::Std ?
+ SAL_N_ELEMENTS(RID_SVXSTRARY_PAPERSIZE_STD) : SAL_N_ELEMENTS(RID_SVXSTRARY_PAPERSIZE_DRAW);
+
+ for ( sal_uInt32 i = 0; i < nCnt; ++i )
+ {
+ OUString aStr = SvxResId(pPaperAry[i].first);
+ Paper eSize = static_cast<Paper>(pPaperAry[i].second);
+ m_xControl->append(OUString::number(static_cast<sal_Int32>(eSize)), aStr);
+ }
+}
+
+void SvxPaperSizeListBox::set_active_id( Paper ePreselectPaper )
+{
+ int nEntryCount = m_xControl->get_count();
+ int nSelPos = -1;
+ int nUserPos = -1;
+
+ for (int i = 0; i < nEntryCount; ++i)
+ {
+ Paper eTmp = static_cast<Paper>(m_xControl->get_id(i).toInt32());
+ if (eTmp == ePreselectPaper)
+ {
+ nSelPos = i;
+ break;
+ }
+
+ if (eTmp == PAPER_USER)
+ nUserPos = i;
+ }
+
+ // preselect current paper format - #115915#: ePaper might not be in aPaperSizeBox so use PAPER_USER instead
+ m_xControl->set_active((nSelPos != -1) ? nSelPos : nUserPos);
+}
+
+Paper SvxPaperSizeListBox::get_active_id() const
+{
+ return static_cast<Paper>(m_xControl->get_active_id().toInt32());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/svx/source/dialog/paraprev.cxx b/svx/source/dialog/paraprev.cxx
new file mode 100644
index 000000000..27dccbfd9
--- /dev/null
+++ b/svx/source/dialog/paraprev.cxx
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/dialoghelper.hxx>
+#include <svx/paraprev.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+
+SvxParaPrevWindow::SvxParaPrevWindow() :
+ nLeftMargin ( 0 ),
+ nRightMargin ( 0 ),
+ nFirstLineOffset ( 0 ),
+ nUpper ( 0 ),
+ nLower ( 0 ),
+ eAdjust ( SvxAdjust::Left ),
+ eLastLine ( SvxAdjust::Left ),
+ eLine ( SvxPrevLineSpace::N1 )
+{
+ aSize = Size(11905, 16837);
+}
+
+void SvxParaPrevWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aOptimalSize(getParagraphPreviewOptimalSize(pDrawingArea->get_ref_device()));
+ pDrawingArea->set_size_request(aOptimalSize.Width(), aOptimalSize.Height());
+}
+
+void SvxParaPrevWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ DrawParagraph(rRenderContext);
+}
+
+#define DEF_MARGIN 120
+
+void SvxParaPrevWindow::DrawParagraph(vcl::RenderContext& rRenderContext)
+{
+ // Count in Twips by default
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
+
+ Size aWinSize(GetOutputSizePixel());
+ aWinSize = rRenderContext.PixelToLogic(aWinSize);
+ Size aTmp(1, 1);
+ aTmp = rRenderContext.PixelToLogic(aTmp);
+ aWinSize.AdjustWidth( -(aTmp.Width() /2) );
+ aWinSize.AdjustHeight( -(aTmp.Height() /2) );
+
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+ const Color& rWinColor = rStyleSettings.GetWindowColor();
+ Color aGrayColor(COL_LIGHTGRAY);
+
+ rRenderContext.SetFillColor(rWinColor);
+ rRenderContext.DrawRect(tools::Rectangle(Point(), aWinSize));
+
+ rRenderContext.SetLineColor();
+
+ tools::Long nH = aWinSize.Height() / 19;
+ Size aLineSiz(aWinSize.Width() - DEF_MARGIN, nH);
+ Size aSiz = aLineSiz;
+ Point aPnt;
+ aPnt.setX( DEF_MARGIN / 2 );
+ rRenderContext.SetFillColor(aGrayColor);
+
+ for (sal_uInt16 i = 0; i < 9; ++i)
+ {
+ if (i == 3)
+ {
+ rRenderContext.SetFillColor(COL_GRAY);
+ auto nTop = nUpper * aLineSiz.Height() / aSize.Height();
+ aPnt.AdjustY(nTop * 2 );
+ }
+
+ if (i == 6 )
+ rRenderContext.SetFillColor(aGrayColor);
+
+ if (3 <= i && 6 > i)
+ {
+ tools::Long nLeft = nLeftMargin * aLineSiz.Width() / aSize.Width();
+ tools::Long nFirst = nFirstLineOffset * aLineSiz.Width() / aSize.Width();
+ tools::Long nTmp = nLeft + nFirst;
+
+ if (i == 3)
+ {
+ aPnt.AdjustX(nTmp );
+ aSiz.AdjustWidth( -nTmp );
+ }
+ else
+ {
+ aPnt.AdjustX(nLeft );
+ aSiz.AdjustWidth( -nLeft );
+ }
+ tools::Long nRight = nRightMargin * aLineSiz.Width() / aSize.Width();
+ aSiz.AdjustWidth( -nRight );
+ }
+
+ if (4 == i || 5 == i || 6 == i)
+ {
+ switch (eLine)
+ {
+ case SvxPrevLineSpace::N1:
+ break;
+ case SvxPrevLineSpace::N115:
+ aPnt.AdjustY(nH / 6.67 ); // 1/.15 = 6.(6)
+ break;
+ case SvxPrevLineSpace::N15:
+ aPnt.AdjustY(nH / 2 );
+ break;
+ case SvxPrevLineSpace::N2:
+ aPnt.AdjustY(nH );
+ break;
+ case SvxPrevLineSpace::Prop:
+ case SvxPrevLineSpace::Min:
+ case SvxPrevLineSpace::Leading:
+ break;
+ }
+ }
+
+ aPnt.AdjustY(nH );
+
+ if (3 <= i && 5 >= i)
+ {
+ tools::Long nLW = tools::Long();
+ switch (i)
+ {
+ case 3:
+ nLW = aLineSiz.Width() * 8 / 10;
+ break;
+ case 4:
+ nLW = aLineSiz.Width() * 9 / 10;
+ break;
+ case 5:
+ nLW = aLineSiz.Width() / 2;
+ break;
+ }
+
+ if (nLW > aSiz.Width())
+ nLW = aSiz.Width();
+
+ switch (eAdjust)
+ {
+ case SvxAdjust::Left:
+ break;
+ case SvxAdjust::Right:
+ aPnt.AdjustX( aSiz.Width() - nLW );
+ break;
+ case SvxAdjust::Center:
+ aPnt.AdjustX(( aSiz.Width() - nLW ) / 2 );
+ break;
+ default: ; //prevent warning
+ }
+ if (SvxAdjust::Block == eAdjust)
+ {
+ if(5 == i)
+ {
+ switch( eLastLine )
+ {
+ case SvxAdjust::Left:
+ break;
+ case SvxAdjust::Right:
+ aPnt.AdjustX( aSiz.Width() - nLW );
+ break;
+ case SvxAdjust::Center:
+ aPnt.AdjustX(( aSiz.Width() - nLW ) / 2 );
+ break;
+ case SvxAdjust::Block:
+ nLW = aSiz.Width();
+ break;
+ default: ; //prevent warning
+ }
+ }
+ else
+ nLW = aSiz.Width();
+ }
+ aSiz.setWidth( nLW );
+ }
+
+ tools::Rectangle aRect(aPnt, aSiz);
+
+ rRenderContext.DrawRect( aRect );
+
+ if (5 == i)
+ {
+ auto nBottom = nLower * aLineSiz.Height() / aSize.Height();
+ aPnt.AdjustY(nBottom * 2 );
+ }
+
+ aPnt.AdjustY(nH );
+ // Reset, recalculate for each line
+ aPnt.setX( DEF_MARGIN / 2 );
+ aSiz = aLineSiz;
+ }
+ rRenderContext.Pop();
+}
+
+#undef DEF_MARGIN
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/passwd.cxx b/svx/source/dialog/passwd.cxx
new file mode 100644
index 000000000..cb7793c3d
--- /dev/null
+++ b/svx/source/dialog/passwd.cxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svx/passwd.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+IMPL_LINK_NOARG(SvxPasswordDialog, ButtonHdl, weld::Button&, void)
+{
+ bool bOK = true;
+
+ if (m_xNewPasswdED->get_text() != m_xRepeatPasswdED->get_text())
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ m_aRepeatPasswdErrStr));
+ xBox->run();
+ m_xNewPasswdED->set_text("");
+ m_xRepeatPasswdED->set_text("");
+ m_xNewPasswdED->grab_focus();
+ bOK = false;
+ }
+
+ if (bOK && m_aCheckPasswordHdl.IsSet() && !m_aCheckPasswordHdl.Call(this))
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ m_aOldPasswdErrStr));
+ xBox->run();
+ m_xOldPasswdED->set_text("");
+ m_xOldPasswdED->grab_focus();
+ bOK = false;
+ }
+
+ if (bOK)
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(SvxPasswordDialog, EditModifyHdl, weld::Entry&, void)
+{
+ if (!m_xOKBtn->get_sensitive())
+ m_xOKBtn->set_sensitive(true);
+}
+
+SvxPasswordDialog::SvxPasswordDialog(weld::Window* pParent, bool bDisableOldPassword)
+ : SfxDialogController(pParent, "svx/ui/passwd.ui", "PasswordDialog")
+ , m_aOldPasswdErrStr(SvxResId(RID_SVXSTR_ERR_OLD_PASSWD))
+ , m_aRepeatPasswdErrStr(SvxResId(RID_SVXSTR_ERR_REPEAT_PASSWD ))
+ , m_xOldFL(m_xBuilder->weld_label("oldpass"))
+ , m_xOldPasswdFT(m_xBuilder->weld_label("oldpassL"))
+ , m_xOldPasswdED(m_xBuilder->weld_entry("oldpassEntry"))
+ , m_xNewPasswdED(m_xBuilder->weld_entry("newpassEntry"))
+ , m_xRepeatPasswdED(m_xBuilder->weld_entry("confirmpassEntry"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+{
+ m_xOKBtn->connect_clicked(LINK(this, SvxPasswordDialog, ButtonHdl));
+ m_xRepeatPasswdED->connect_changed(LINK(this, SvxPasswordDialog, EditModifyHdl));
+ EditModifyHdl(*m_xRepeatPasswdED);
+
+ if (bDisableOldPassword)
+ {
+ m_xOldFL->set_sensitive(false);
+ m_xOldPasswdFT->set_sensitive(false);
+ m_xOldPasswdED->set_sensitive(false);
+ m_xNewPasswdED->grab_focus();
+ }
+}
+
+SvxPasswordDialog::~SvxPasswordDialog()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/relfld.cxx b/svx/source/dialog/relfld.cxx
new file mode 100644
index 000000000..3929e4fcf
--- /dev/null
+++ b/svx/source/dialog/relfld.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/relfld.hxx>
+
+SvxRelativeField::SvxRelativeField(std::unique_ptr<weld::MetricSpinButton> pControl)
+ : m_xSpinButton(std::move(pControl))
+ , nRelMin(0)
+ , nRelMax(0)
+ , bRelativeMode(false)
+ , bRelative(false)
+ , bNegativeEnabled(false)
+
+{
+ weld::SpinButton& rSpinButton = m_xSpinButton->get_widget();
+ rSpinButton.connect_changed(LINK(this, SvxRelativeField, ModifyHdl));
+}
+
+IMPL_LINK_NOARG(SvxRelativeField, ModifyHdl, weld::Entry&, void)
+{
+ if (!bRelativeMode)
+ return;
+
+ OUString aStr = m_xSpinButton->get_text();
+ bool bNewMode = bRelative;
+
+ if ( bRelative )
+ {
+ const sal_Unicode* pStr = aStr.getStr();
+
+ while ( *pStr )
+ {
+ if( ( ( *pStr < '0' ) || ( *pStr > '9' ) ) &&
+ ( *pStr != '%' ) )
+ {
+ bNewMode = false;
+ break;
+ }
+ pStr++;
+ }
+ }
+ else
+ {
+ if ( aStr.indexOf( "%" ) != -1 )
+ bNewMode = true;
+ }
+
+ if ( bNewMode != bRelative )
+ SetRelative( bNewMode );
+}
+
+void SvxRelativeField::EnableRelativeMode(sal_uInt16 nMin, sal_uInt16 nMax)
+{
+ bRelativeMode = true;
+ nRelMin = nMin;
+ nRelMax = nMax;
+ m_xSpinButton->set_unit(FieldUnit::CM);
+}
+
+void SvxRelativeField::SetRelative( bool bNewRelative )
+{
+ weld::SpinButton& rSpinButton = m_xSpinButton->get_widget();
+
+ int nStartPos, nEndPos;
+ rSpinButton.get_selection_bounds(nStartPos, nEndPos);
+ OUString aStr = rSpinButton.get_text();
+
+ if ( bNewRelative )
+ {
+ bRelative = true;
+ m_xSpinButton->set_digits(0);
+ m_xSpinButton->set_range(nRelMin, nRelMax, FieldUnit::NONE);
+ m_xSpinButton->set_unit(FieldUnit::PERCENT);
+ }
+ else
+ {
+ bRelative = false;
+ m_xSpinButton->set_digits(2);
+ m_xSpinButton->set_range(bNegativeEnabled ? -9999 : 0, 9999, FieldUnit::NONE);
+ m_xSpinButton->set_unit(FieldUnit::CM);
+ }
+
+ rSpinButton.set_text(aStr);
+ rSpinButton.select_region(nStartPos, nEndPos);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/rlrcitem.cxx b/svx/source/dialog/rlrcitem.cxx
new file mode 100644
index 000000000..a73cd00bd
--- /dev/null
+++ b/svx/source/dialog/rlrcitem.cxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/rectitem.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+#include <svx/svxids.hrc>
+
+#include <svx/ruler.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/tstpitem.hxx>
+#include <editeng/protitem.hxx>
+#include "rlrcitem.hxx"
+#include <svx/rulritem.hxx>
+#include <svl/eitem.hxx>
+
+SvxRulerItem::SvxRulerItem(sal_uInt16 _nId, SvxRuler &rRul, SfxBindings &rBindings)
+: SfxControllerItem(_nId, rBindings),
+ rRuler(rRul)
+{
+}
+
+
+void SvxRulerItem::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ // SfxItemState::DONTCARE => pState == -1 => PTR_CAST buff
+ if ( eState != SfxItemState::DEFAULT )
+ pState = nullptr;
+
+ switch(nSID)
+ {
+ // Left / right margin
+ case SID_RULER_LR_MIN_MAX:
+ {
+ const SfxRectangleItem *pItem = dynamic_cast<const SfxRectangleItem*>( pState );
+ rRuler.UpdateFrameMinMax(pItem);
+ break;
+ }
+ case SID_ATTR_LONG_LRSPACE:
+ {
+ const SvxLongLRSpaceItem *pItem = dynamic_cast<const SvxLongLRSpaceItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxLRSpaceItem expected");
+ rRuler.UpdateFrame(pItem);
+ break;
+ }
+ case SID_ATTR_LONG_ULSPACE:
+ {
+ const SvxLongULSpaceItem *pItem = dynamic_cast<const SvxLongULSpaceItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxULSpaceItem expected");
+ rRuler.UpdateFrame(pItem);
+ break;
+ }
+ case SID_ATTR_TABSTOP_VERTICAL:
+ case SID_ATTR_TABSTOP:
+ {
+ const SvxTabStopItem *pItem = dynamic_cast<const SvxTabStopItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxTabStopItem expected");
+ rRuler.Update(pItem);
+ break;
+ }
+ case SID_ATTR_PARA_LRSPACE_VERTICAL:
+ case SID_ATTR_PARA_LRSPACE:
+ {
+ const SvxLRSpaceItem *pItem = dynamic_cast<const SvxLRSpaceItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxLRSpaceItem expected");
+ rRuler.UpdatePara(pItem);
+ break;
+ }
+ case SID_RULER_BORDERS_VERTICAL:
+ case SID_RULER_BORDERS:
+ case SID_RULER_ROWS:
+ case SID_RULER_ROWS_VERTICAL:
+ {
+ const SvxColumnItem *pItem = dynamic_cast<const SvxColumnItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxColumnItem expected");
+#ifdef DBG_UTIL
+ if(pItem)
+ {
+ if(pItem->IsConsistent())
+ rRuler.Update(pItem, nSID);
+ else
+ OSL_FAIL("Column item corrupted");
+ }
+ else
+ rRuler.Update(pItem, nSID);
+#else
+ rRuler.Update(pItem, nSID);
+#endif
+ break;
+ }
+ case SID_RULER_PAGE_POS:
+ { // Position page, page width
+ const SvxPagePosSizeItem *pItem = dynamic_cast<const SvxPagePosSizeItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxPagePosSizeItem expected");
+ rRuler.Update(pItem);
+ break;
+ }
+ case SID_RULER_OBJECT:
+ { // Object selection
+ const SvxObjectItem *pItem = dynamic_cast<const SvxObjectItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxObjectItem expected");
+ rRuler.Update(pItem);
+ break;
+ }
+ case SID_RULER_PROTECT:
+ {
+ const SvxProtectItem *pItem = dynamic_cast<const SvxProtectItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxProtectItem expected");
+ rRuler.Update(pItem);
+ break;
+ }
+ case SID_RULER_BORDER_DISTANCE:
+ {
+ const SvxLRSpaceItem *pItem = dynamic_cast<const SvxLRSpaceItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxLRSpaceItem expected");
+ rRuler.UpdateBorder(pItem);
+ }
+ break;
+ case SID_RULER_TEXT_RIGHT_TO_LEFT :
+ {
+ const SfxBoolItem *pItem = dynamic_cast<const SfxBoolItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SfxBoolItem expected");
+ rRuler.UpdateTextRTL(pItem);
+ }
+ break;
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/rlrcitem.hxx b/svx/source/dialog/rlrcitem.hxx
new file mode 100644
index 000000000..0fde86f0c
--- /dev/null
+++ b/svx/source/dialog/rlrcitem.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_RLRCITEM_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_RLRCITEM_HXX
+
+#include <sfx2/ctrlitem.hxx>
+
+class SvxRuler;
+
+class SvxRulerItem : public SfxControllerItem
+{
+private:
+ SvxRuler& rRuler;
+
+protected:
+ virtual void StateChangedAtToolBoxControl( sal_uInt16,
+ SfxItemState, const SfxPoolItem* pState ) override;
+
+public:
+ SvxRulerItem( sal_uInt16 nId, SvxRuler&, SfxBindings& );
+};
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/rubydialog.cxx b/svx/source/dialog/rubydialog.cxx
new file mode 100644
index 000000000..c2d396901
--- /dev/null
+++ b/svx/source/dialog/rubydialog.cxx
@@ -0,0 +1,878 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <svx/rubydialog.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svl/eitem.hxx>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/text/XRubySelection.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/text/RubyAdjust.hpp>
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <svtools/colorcfg.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace css::uno;
+using namespace css::frame;
+using namespace css::text;
+using namespace css::beans;
+using namespace css::style;
+using namespace css::view;
+using namespace css::lang;
+using namespace css::container;
+
+SFX_IMPL_CHILDWINDOW(SvxRubyChildWindow, SID_RUBY_DIALOG);
+
+namespace
+{
+constexpr OUStringLiteral cRubyBaseText = u"RubyBaseText";
+constexpr OUStringLiteral cRubyText = u"RubyText";
+constexpr OUStringLiteral cRubyAdjust = u"RubyAdjust";
+constexpr OUStringLiteral cRubyPosition = u"RubyPosition";
+constexpr OUStringLiteral cRubyCharStyleName = u"RubyCharStyleName";
+
+} // end anonymous namespace
+
+SvxRubyChildWindow::SvxRubyChildWindow(vcl::Window* _pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo const* pInfo)
+ : SfxChildWindow(_pParent, nId)
+{
+ auto xDlg = std::make_shared<SvxRubyDialog>(pBindings, this, _pParent->GetFrameWeld());
+ SetController(xDlg);
+ xDlg->Initialize(pInfo);
+}
+
+SfxChildWinInfo SvxRubyChildWindow::GetInfo() const { return SfxChildWindow::GetInfo(); }
+
+class SvxRubyData_Impl : public cppu::WeakImplHelper<css::view::XSelectionChangeListener>
+{
+ Reference<XModel> xModel;
+ Reference<XRubySelection> xSelection;
+ Sequence<PropertyValues> aRubyValues;
+ Reference<XController> xController;
+ bool bHasSelectionChanged;
+ bool bDisposing;
+
+public:
+ SvxRubyData_Impl();
+ virtual ~SvxRubyData_Impl() override;
+
+ void SetController(const Reference<XController>& xCtrl);
+ Reference<XModel> const& GetModel()
+ {
+ if (!xController.is())
+ xModel = nullptr;
+ else
+ xModel = xController->getModel();
+ return xModel;
+ }
+ bool HasSelectionChanged() const { return bHasSelectionChanged; }
+ bool IsDisposing() const { return bDisposing; }
+ Reference<XRubySelection> const& GetRubySelection()
+ {
+ xSelection.set(xController, UNO_QUERY);
+ return xSelection;
+ }
+ void UpdateRubyValues()
+ {
+ if (!xSelection.is())
+ aRubyValues.realloc(0);
+ else
+ aRubyValues = xSelection->getRubyList(false);
+ bHasSelectionChanged = false;
+ }
+ Sequence<PropertyValues>& GetRubyValues() { return aRubyValues; }
+ void AssertOneEntry();
+
+ virtual void SAL_CALL selectionChanged(const css::lang::EventObject& aEvent) override;
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+};
+
+SvxRubyData_Impl::SvxRubyData_Impl()
+ : bHasSelectionChanged(false)
+ , bDisposing(false)
+{
+}
+
+SvxRubyData_Impl::~SvxRubyData_Impl() {}
+
+void SvxRubyData_Impl::SetController(const Reference<XController>& xCtrl)
+{
+ if (xCtrl.get() == xController.get())
+ return;
+
+ try
+ {
+ Reference<XSelectionSupplier> xSelSupp(xController, UNO_QUERY);
+ if (xSelSupp.is())
+ xSelSupp->removeSelectionChangeListener(this);
+
+ bHasSelectionChanged = true;
+ xController = xCtrl;
+ xSelSupp.set(xController, UNO_QUERY);
+ if (xSelSupp.is())
+ xSelSupp->addSelectionChangeListener(this);
+ }
+ catch (const Exception&)
+ {
+ }
+}
+
+void SvxRubyData_Impl::selectionChanged(const EventObject&) { bHasSelectionChanged = true; }
+
+void SvxRubyData_Impl::disposing(const EventObject&)
+{
+ try
+ {
+ Reference<XSelectionSupplier> xSelSupp(xController, UNO_QUERY);
+ if (xSelSupp.is())
+ xSelSupp->removeSelectionChangeListener(this);
+ }
+ catch (const Exception&)
+ {
+ }
+ xController = nullptr;
+ bDisposing = true;
+}
+
+void SvxRubyData_Impl::AssertOneEntry()
+{
+ //create one entry
+ if (!aRubyValues.hasElements())
+ {
+ aRubyValues.realloc(1);
+ Sequence<PropertyValue>& rValues = aRubyValues.getArray()[0];
+ rValues.realloc(5);
+ PropertyValue* pValues = rValues.getArray();
+ pValues[0].Name = cRubyBaseText;
+ pValues[1].Name = cRubyText;
+ pValues[2].Name = cRubyAdjust;
+ pValues[3].Name = cRubyPosition;
+ pValues[4].Name = cRubyCharStyleName;
+ }
+}
+
+SvxRubyDialog::SvxRubyDialog(SfxBindings* pBind, SfxChildWindow* pCW, weld::Window* pParent)
+ : SfxModelessDialogController(pBind, pCW, pParent, "svx/ui/asianphoneticguidedialog.ui",
+ "AsianPhoneticGuideDialog")
+ , nLastPos(0)
+ , nCurrentEdit(0)
+ , bModified(false)
+ , pBindings(pBind)
+ , m_pImpl(new SvxRubyData_Impl)
+ , m_xLeftFT(m_xBuilder->weld_label("basetextft"))
+ , m_xRightFT(m_xBuilder->weld_label("rubytextft"))
+ , m_xLeft1ED(m_xBuilder->weld_entry("Left1ED"))
+ , m_xRight1ED(m_xBuilder->weld_entry("Right1ED"))
+ , m_xLeft2ED(m_xBuilder->weld_entry("Left2ED"))
+ , m_xRight2ED(m_xBuilder->weld_entry("Right2ED"))
+ , m_xLeft3ED(m_xBuilder->weld_entry("Left3ED"))
+ , m_xRight3ED(m_xBuilder->weld_entry("Right3ED"))
+ , m_xLeft4ED(m_xBuilder->weld_entry("Left4ED"))
+ , m_xRight4ED(m_xBuilder->weld_entry("Right4ED"))
+ , m_xScrolledWindow(m_xBuilder->weld_scrolled_window("scrolledwindow", true))
+ , m_xAdjustLB(m_xBuilder->weld_combo_box("adjustlb"))
+ , m_xPositionLB(m_xBuilder->weld_combo_box("positionlb"))
+ , m_xCharStyleFT(m_xBuilder->weld_label("styleft"))
+ , m_xCharStyleLB(m_xBuilder->weld_combo_box("stylelb"))
+ , m_xStylistPB(m_xBuilder->weld_button("styles"))
+ , m_xApplyPB(m_xBuilder->weld_button("ok"))
+ , m_xClosePB(m_xBuilder->weld_button("close"))
+ , m_xContentArea(m_xDialog->weld_content_area())
+ , m_xGrid(m_xBuilder->weld_widget("grid"))
+ , m_xPreviewWin(new RubyPreview)
+ , m_xPreview(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreviewWin))
+{
+ m_xCharStyleLB->make_sorted();
+ m_xPreviewWin->setRubyDialog(this);
+ m_xScrolledWindow->set_size_request(-1, m_xGrid->get_preferred_size().Height());
+ m_xScrolledWindow->set_vpolicy(VclPolicyType::NEVER);
+
+ aEditArr[0] = m_xLeft1ED.get();
+ aEditArr[1] = m_xRight1ED.get();
+ aEditArr[2] = m_xLeft2ED.get();
+ aEditArr[3] = m_xRight2ED.get();
+ aEditArr[4] = m_xLeft3ED.get();
+ aEditArr[5] = m_xRight3ED.get();
+ aEditArr[6] = m_xLeft4ED.get();
+ aEditArr[7] = m_xRight4ED.get();
+
+ m_xApplyPB->connect_clicked(LINK(this, SvxRubyDialog, ApplyHdl_Impl));
+ m_xClosePB->connect_clicked(LINK(this, SvxRubyDialog, CloseHdl_Impl));
+ m_xStylistPB->connect_clicked(LINK(this, SvxRubyDialog, StylistHdl_Impl));
+ m_xAdjustLB->connect_changed(LINK(this, SvxRubyDialog, AdjustHdl_Impl));
+ m_xPositionLB->connect_changed(LINK(this, SvxRubyDialog, PositionHdl_Impl));
+ m_xCharStyleLB->connect_changed(LINK(this, SvxRubyDialog, CharStyleHdl_Impl));
+
+ Link<weld::ScrolledWindow&, void> aScrLk(LINK(this, SvxRubyDialog, ScrollHdl_Impl));
+ m_xScrolledWindow->connect_vadjustment_changed(aScrLk);
+
+ Link<weld::Entry&, void> aEditLk(LINK(this, SvxRubyDialog, EditModifyHdl_Impl));
+ Link<weld::Widget&, void> aFocusLk(LINK(this, SvxRubyDialog, EditFocusHdl_Impl));
+ Link<const KeyEvent&, bool> aKeyUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownHdl_Impl));
+ Link<const KeyEvent&, bool> aKeyTabUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownTabHdl_Impl));
+ for (sal_uInt16 i = 0; i < 8; i++)
+ {
+ aEditArr[i]->connect_changed(aEditLk);
+ aEditArr[i]->connect_focus_in(aFocusLk);
+ if (!i || 7 == i)
+ aEditArr[i]->connect_key_press(aKeyTabUpDownLk);
+ else
+ aEditArr[i]->connect_key_press(aKeyUpDownLk);
+ }
+}
+
+SvxRubyDialog::~SvxRubyDialog()
+{
+ ClearCharStyleList();
+ EventObject aEvent;
+ m_pImpl->disposing(aEvent);
+}
+
+void SvxRubyDialog::ClearCharStyleList() { m_xCharStyleLB->clear(); }
+
+void SvxRubyDialog::Close()
+{
+ if (IsClosing())
+ return;
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (pViewFrame)
+ pViewFrame->ToggleChildWindow(SID_RUBY_DIALOG);
+}
+
+void SvxRubyDialog::Activate()
+{
+ SfxModelessDialogController::Activate();
+ if (m_pImpl->IsDisposing())
+ {
+ // tdf#141967/tdf#152495 if Activate is called during tear down bail early
+ return;
+ }
+
+ //get selection from current view frame
+ SfxViewFrame* pCurFrm = SfxViewFrame::Current();
+ Reference<XController> xCtrl(pCurFrm ? pCurFrm->GetFrame().GetController() : nullptr);
+ m_pImpl->SetController(xCtrl);
+ if (!m_pImpl->HasSelectionChanged())
+ return;
+
+ Reference<XRubySelection> xRubySel = m_pImpl->GetRubySelection();
+ m_pImpl->UpdateRubyValues();
+ EnableControls(xRubySel.is());
+ if (xRubySel.is())
+ {
+ Reference<XModel> xModel = m_pImpl->GetModel();
+ const OUString sCharStyleSelect = m_xCharStyleLB->get_active_text();
+ ClearCharStyleList();
+ Reference<XStyleFamiliesSupplier> xSupplier(xModel, UNO_QUERY);
+ if (xSupplier.is())
+ {
+ try
+ {
+ Reference<XNameAccess> xFam = xSupplier->getStyleFamilies();
+ Any aChar = xFam->getByName("CharacterStyles");
+ Reference<XNameContainer> xChar;
+ aChar >>= xChar;
+ Reference<XIndexAccess> xCharIdx(xChar, UNO_QUERY);
+ if (xCharIdx.is())
+ {
+ OUString sUIName("DisplayName");
+ for (sal_Int32 nStyle = 0; nStyle < xCharIdx->getCount(); nStyle++)
+ {
+ Any aStyle = xCharIdx->getByIndex(nStyle);
+ Reference<XStyle> xStyle;
+ aStyle >>= xStyle;
+ Reference<XPropertySet> xPrSet(xStyle, UNO_QUERY);
+ OUString sName, sCoreName;
+ if (xPrSet.is())
+ {
+ Reference<XPropertySetInfo> xInfo = xPrSet->getPropertySetInfo();
+ if (xInfo->hasPropertyByName(sUIName))
+ {
+ Any aName = xPrSet->getPropertyValue(sUIName);
+ aName >>= sName;
+ }
+ }
+ if (xStyle.is())
+ {
+ sCoreName = xStyle->getName();
+ if (sName.isEmpty())
+ sName = sCoreName;
+ }
+ if (!sName.isEmpty())
+ {
+ m_xCharStyleLB->append(sCoreName, sName);
+ }
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "exception in style access");
+ }
+ if (!sCharStyleSelect.isEmpty())
+ m_xCharStyleLB->set_active_text(sCharStyleSelect);
+ }
+ m_xCharStyleLB->set_sensitive(xSupplier.is());
+ m_xCharStyleFT->set_sensitive(xSupplier.is());
+ }
+ Update();
+ m_xPreviewWin->Invalidate();
+}
+
+void SvxRubyDialog::SetRubyText(sal_Int32 nPos, weld::Entry& rLeft, weld::Entry& rRight)
+{
+ OUString sLeft, sRight;
+ const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
+ bool bEnable = aRubyValues.getLength() > nPos;
+ if (bEnable)
+ {
+ const Sequence<PropertyValue> aProps = aRubyValues.getConstArray()[nPos];
+ for (const PropertyValue& rProp : aProps)
+ {
+ if (rProp.Name == cRubyBaseText)
+ rProp.Value >>= sLeft;
+ else if (rProp.Name == cRubyText)
+ rProp.Value >>= sRight;
+ }
+ }
+ else if (!nPos)
+ {
+ bEnable = true;
+ }
+ rLeft.set_sensitive(bEnable);
+ rRight.set_sensitive(bEnable);
+ rLeft.set_text(sLeft);
+ rRight.set_text(sRight);
+ rLeft.save_value();
+ rRight.save_value();
+}
+
+void SvxRubyDialog::GetRubyText()
+{
+ tools::Long nTempLastPos = GetLastPos();
+ Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
+ auto aRubyValuesRange = asNonConstRange(aRubyValues);
+ for (int i = 0; i < 8; i += 2)
+ {
+ if (aEditArr[i]->get_sensitive()
+ && (aEditArr[i]->get_value_changed_from_saved()
+ || aEditArr[i + 1]->get_value_changed_from_saved()))
+ {
+ DBG_ASSERT(aRubyValues.getLength() > (i / 2 + nTempLastPos), "wrong index");
+ SetModified(true);
+ for (PropertyValue& propVal : asNonConstRange(aRubyValuesRange[i / 2 + nTempLastPos]))
+ {
+ if (propVal.Name == cRubyBaseText)
+ propVal.Value <<= aEditArr[i]->get_text();
+ else if (propVal.Name == cRubyText)
+ propVal.Value <<= aEditArr[i + 1]->get_text();
+ }
+ }
+ }
+}
+
+void SvxRubyDialog::Update()
+{
+ const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
+ sal_Int32 nLen = aRubyValues.getLength();
+ m_xScrolledWindow->vadjustment_configure(0, 0, !nLen ? 1 : nLen, 1, 4, 4);
+ if (nLen > 4)
+ m_xScrolledWindow->set_vpolicy(VclPolicyType::ALWAYS);
+ else
+ m_xScrolledWindow->set_vpolicy(VclPolicyType::NEVER);
+ SetLastPos(0);
+ SetModified(false);
+
+ sal_Int16 nAdjust = -1;
+ sal_Int16 nPosition = -1;
+ OUString sCharStyleName, sTmp;
+ bool bCharStyleEqual = true;
+ for (sal_Int32 nRuby = 0; nRuby < nLen; nRuby++)
+ {
+ const Sequence<PropertyValue>& rProps = aRubyValues.getConstArray()[nRuby];
+ for (const PropertyValue& rProp : rProps)
+ {
+ if (nAdjust > -2 && rProp.Name == cRubyAdjust)
+ {
+ sal_Int16 nTmp = sal_Int16();
+ rProp.Value >>= nTmp;
+ if (!nRuby)
+ nAdjust = nTmp;
+ else if (nAdjust != nTmp)
+ nAdjust = -2;
+ }
+ if (nPosition > -2 && rProp.Name == cRubyPosition)
+ {
+ sal_Int16 nTmp = sal_Int16();
+ rProp.Value >>= nTmp;
+ if (!nRuby)
+ nPosition = nTmp;
+ else if (nPosition != nTmp)
+ nPosition = -2;
+ }
+ if (bCharStyleEqual && rProp.Name == cRubyCharStyleName)
+ {
+ rProp.Value >>= sTmp;
+ if (!nRuby)
+ sCharStyleName = sTmp;
+ else if (sCharStyleName != sTmp)
+ bCharStyleEqual = false;
+ }
+ }
+ }
+ if (!nLen)
+ {
+ //enable selection if the ruby list is empty
+ nAdjust = 0;
+ nPosition = 0;
+ }
+ if (nAdjust > -1)
+ m_xAdjustLB->set_active(nAdjust);
+ else
+ m_xAdjustLB->set_active(-1);
+ if (nPosition > -1)
+ m_xPositionLB->set_active(nPosition);
+ if (!nLen || (bCharStyleEqual && sCharStyleName.isEmpty()))
+ sCharStyleName = "Rubies";
+ if (!sCharStyleName.isEmpty())
+ {
+ for (int i = 0, nEntryCount = m_xCharStyleLB->get_count(); i < nEntryCount; i++)
+ {
+ OUString sCoreName = m_xCharStyleLB->get_id(i);
+ if (sCharStyleName == sCoreName)
+ {
+ m_xCharStyleLB->set_active(i);
+ break;
+ }
+ }
+ }
+ else
+ m_xCharStyleLB->set_active(-1);
+
+ ScrollHdl_Impl(*m_xScrolledWindow);
+}
+
+void SvxRubyDialog::GetCurrentText(OUString& rBase, OUString& rRuby)
+{
+ rBase = aEditArr[nCurrentEdit * 2]->get_text();
+ rRuby = aEditArr[nCurrentEdit * 2 + 1]->get_text();
+}
+
+IMPL_LINK(SvxRubyDialog, ScrollHdl_Impl, weld::ScrolledWindow&, rScroll, void)
+{
+ int nPos = rScroll.vadjustment_get_value();
+ if (GetLastPos() != nPos)
+ {
+ GetRubyText();
+ }
+ SetRubyText(nPos++, *m_xLeft1ED, *m_xRight1ED);
+ SetRubyText(nPos++, *m_xLeft2ED, *m_xRight2ED);
+ SetRubyText(nPos++, *m_xLeft3ED, *m_xRight3ED);
+ SetRubyText(nPos, *m_xLeft4ED, *m_xRight4ED);
+ SetLastPos(nPos - 3);
+ m_xPreviewWin->Invalidate();
+}
+
+IMPL_LINK_NOARG(SvxRubyDialog, ApplyHdl_Impl, weld::Button&, void)
+{
+ const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
+ if (!aRubyValues.hasElements())
+ {
+ AssertOneEntry();
+ PositionHdl_Impl(*m_xPositionLB);
+ AdjustHdl_Impl(*m_xAdjustLB);
+ CharStyleHdl_Impl(*m_xCharStyleLB);
+ }
+ GetRubyText();
+ //reset all edit fields - SaveValue is called
+ ScrollHdl_Impl(*m_xScrolledWindow);
+
+ Reference<XRubySelection> xSelection = m_pImpl->GetRubySelection();
+ if (IsModified() && xSelection.is())
+ {
+ try
+ {
+ xSelection->setRubyList(aRubyValues, false);
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "");
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SvxRubyDialog, CloseHdl_Impl, weld::Button&, void) { Close(); }
+
+IMPL_LINK_NOARG(SvxRubyDialog, StylistHdl_Impl, weld::Button&, void)
+{
+ std::unique_ptr<SfxBoolItem> pState;
+ SfxItemState eState = pBindings->QueryState(SID_STYLE_DESIGNER, pState);
+ if (eState <= SfxItemState::SET || !pState || !pState->GetValue())
+ {
+ pBindings->GetDispatcher()->Execute(SID_STYLE_DESIGNER,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+}
+
+IMPL_LINK(SvxRubyDialog, AdjustHdl_Impl, weld::ComboBox&, rBox, void)
+{
+ AssertOneEntry();
+ sal_Int16 nAdjust = rBox.get_active();
+ for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues()))
+ {
+ for (PropertyValue& propVal : asNonConstRange(rProps))
+ {
+ if (propVal.Name == cRubyAdjust)
+ propVal.Value <<= nAdjust;
+ }
+ SetModified(true);
+ }
+ m_xPreviewWin->Invalidate();
+}
+
+IMPL_LINK(SvxRubyDialog, PositionHdl_Impl, weld::ComboBox&, rBox, void)
+{
+ AssertOneEntry();
+ sal_Int16 nPosition = rBox.get_active();
+ for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues()))
+ {
+ for (PropertyValue& propVal : asNonConstRange(rProps))
+ {
+ if (propVal.Name == cRubyPosition)
+ propVal.Value <<= nPosition;
+ }
+ SetModified(true);
+ }
+ m_xPreviewWin->Invalidate();
+}
+
+IMPL_LINK_NOARG(SvxRubyDialog, CharStyleHdl_Impl, weld::ComboBox&, void)
+{
+ AssertOneEntry();
+ OUString sStyleName;
+ if (m_xCharStyleLB->get_active() != -1)
+ sStyleName = m_xCharStyleLB->get_active_id();
+ for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues()))
+ {
+ for (PropertyValue& propVal : asNonConstRange(rProps))
+ {
+ if (propVal.Name == cRubyCharStyleName)
+ {
+ propVal.Value <<= sStyleName;
+ }
+ }
+ SetModified(true);
+ }
+}
+
+IMPL_LINK(SvxRubyDialog, EditFocusHdl_Impl, weld::Widget&, rEdit, void)
+{
+ for (sal_uInt16 i = 0; i < 8; i++)
+ {
+ if (&rEdit == aEditArr[i])
+ {
+ nCurrentEdit = i / 2;
+ break;
+ }
+ }
+ m_xPreviewWin->Invalidate();
+}
+
+IMPL_LINK(SvxRubyDialog, EditModifyHdl_Impl, weld::Entry&, rEdit, void)
+{
+ EditFocusHdl_Impl(rEdit);
+}
+
+bool SvxRubyDialog::EditScrollHdl_Impl(sal_Int32 nParam)
+{
+ bool bRet = false;
+ //scroll forward
+ if (nParam > 0 && (aEditArr[7]->has_focus() || aEditArr[6]->has_focus()))
+ {
+ if (m_xScrolledWindow->vadjustment_get_upper()
+ > m_xScrolledWindow->vadjustment_get_value()
+ + m_xScrolledWindow->vadjustment_get_page_size())
+ {
+ m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_value()
+ + 1);
+ aEditArr[6]->grab_focus();
+ bRet = true;
+ }
+ }
+ //scroll backward
+ else if (m_xScrolledWindow->vadjustment_get_value()
+ && (aEditArr[0]->has_focus() || aEditArr[1]->has_focus()))
+ {
+ m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_value() - 1);
+ aEditArr[1]->grab_focus();
+ bRet = true;
+ }
+ if (bRet)
+ ScrollHdl_Impl(*m_xScrolledWindow);
+ return bRet;
+}
+
+bool SvxRubyDialog::EditJumpHdl_Impl(sal_Int32 nParam)
+{
+ bool bHandled = false;
+ sal_uInt16 nIndex = USHRT_MAX;
+ for (sal_uInt16 i = 0; i < 8; i++)
+ {
+ if (aEditArr[i]->has_focus())
+ nIndex = i;
+ }
+ if (nIndex < 8)
+ {
+ if (nParam > 0)
+ {
+ if (nIndex < 6)
+ aEditArr[nIndex + 2]->grab_focus();
+ else if (EditScrollHdl_Impl(nParam))
+ aEditArr[nIndex]->grab_focus();
+ }
+ else
+ {
+ if (nIndex > 1)
+ aEditArr[nIndex - 2]->grab_focus();
+ else if (EditScrollHdl_Impl(nParam))
+ aEditArr[nIndex]->grab_focus();
+ }
+ bHandled = true;
+ }
+ return bHandled;
+}
+
+void SvxRubyDialog::AssertOneEntry() { m_pImpl->AssertOneEntry(); }
+
+void SvxRubyDialog::EnableControls(bool bEnable)
+{
+ m_xContentArea->set_sensitive(bEnable);
+ m_xApplyPB->set_sensitive(bEnable);
+}
+
+RubyPreview::RubyPreview()
+ : m_pParentDlg(nullptr)
+{
+}
+
+RubyPreview::~RubyPreview() {}
+
+void RubyPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
+{
+ rRenderContext.Push(vcl::PushFlags::ALL);
+
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
+
+ Size aWinSize = rRenderContext.GetOutputSize();
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ svtools::ColorConfig aColorConfig;
+
+ Color aNewTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
+ Color aNewFillColor(rStyleSettings.GetWindowColor());
+
+ vcl::Font aFont = rRenderContext.GetFont();
+ aFont.SetFontHeight(aWinSize.Height() / 4);
+ aFont.SetFillColor(aNewFillColor);
+ aFont.SetColor(aNewTextColor);
+ rRenderContext.SetFont(aFont);
+
+ tools::Rectangle aRect(Point(0, 0), aWinSize);
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(aFont.GetFillColor());
+ rRenderContext.DrawRect(aRect);
+
+ OUString sBaseText, sRubyText;
+ m_pParentDlg->GetCurrentText(sBaseText, sRubyText);
+
+ tools::Long nTextHeight = rRenderContext.GetTextHeight();
+ tools::Long nBaseWidth = rRenderContext.GetTextWidth(sBaseText);
+
+ vcl::Font aRubyFont(aFont);
+ aRubyFont.SetFontHeight(aRubyFont.GetFontHeight() * 70 / 100);
+ rRenderContext.SetFont(aRubyFont);
+ tools::Long nRubyWidth = rRenderContext.GetTextWidth(sRubyText);
+ rRenderContext.SetFont(aFont);
+
+ RubyAdjust nAdjust = static_cast<RubyAdjust>(m_pParentDlg->m_xAdjustLB->get_active());
+ //use center if no adjustment is available
+ if (nAdjust > RubyAdjust_INDENT_BLOCK)
+ nAdjust = RubyAdjust_CENTER;
+
+ //which part is stretched ?
+ bool bRubyStretch = nBaseWidth >= nRubyWidth;
+
+ tools::Long nCenter = aWinSize.Width() / 2;
+ tools::Long nHalfWidth = std::max(nBaseWidth, nRubyWidth) / 2;
+ tools::Long nLeftStart = nCenter - nHalfWidth;
+ tools::Long nRightEnd = nCenter + nHalfWidth;
+
+ // Default values for TOP or no selection
+ tools::Long nYRuby = aWinSize.Height() / 4 - nTextHeight / 2;
+ tools::Long nYBase = aWinSize.Height() * 3 / 4 - nTextHeight / 2;
+
+ sal_Int16 nRubyPos = m_pParentDlg->m_xPositionLB->get_active();
+ if (nRubyPos == 1) // BOTTOM
+ {
+ tools::Long nTmp = nYRuby;
+ nYRuby = nYBase;
+ nYBase = nTmp;
+ }
+ else if (nRubyPos == 2) // RIGHT ( vertically )
+ {
+ // Align the ruby text and base text to the vertical center.
+ nYBase = (aWinSize.Height() - nTextHeight) / 2;
+ nYRuby = (aWinSize.Height() - nRubyWidth) / 2;
+
+ // Align the ruby text at the right side of the base text
+ nAdjust = RubyAdjust_RIGHT;
+ nHalfWidth = nBaseWidth / 2;
+ nLeftStart = nCenter - nHalfWidth;
+ nRightEnd = nCenter + nHalfWidth + nRubyWidth + nTextHeight;
+ // Render base text first, then render ruby text on the right.
+ bRubyStretch = true;
+
+ aRubyFont.SetVertical(true);
+ aRubyFont.SetOrientation(2700_deg10);
+ }
+
+ tools::Long nYOutput;
+ tools::Long nOutTextWidth;
+ OUString sOutputText;
+
+ if (bRubyStretch)
+ {
+ rRenderContext.DrawText(Point(nLeftStart, nYBase), sBaseText);
+ nYOutput = nYRuby;
+ sOutputText = sRubyText;
+ nOutTextWidth = nRubyWidth;
+ rRenderContext.SetFont(aRubyFont);
+ }
+ else
+ {
+ rRenderContext.SetFont(aRubyFont);
+ rRenderContext.DrawText(Point(nLeftStart, nYRuby), sRubyText);
+ nYOutput = nYBase;
+ sOutputText = sBaseText;
+ nOutTextWidth = nBaseWidth;
+ rRenderContext.SetFont(aFont);
+ }
+
+ switch (nAdjust)
+ {
+ case RubyAdjust_LEFT:
+ rRenderContext.DrawText(Point(nLeftStart, nYOutput), sOutputText);
+ break;
+ case RubyAdjust_RIGHT:
+ rRenderContext.DrawText(Point(nRightEnd - nOutTextWidth, nYOutput), sOutputText);
+ break;
+ case RubyAdjust_INDENT_BLOCK:
+ {
+ tools::Long nCharWidth = rRenderContext.GetTextWidth("X");
+ if (nOutTextWidth < (nRightEnd - nLeftStart - nCharWidth))
+ {
+ nCharWidth /= 2;
+ nLeftStart += nCharWidth;
+ nRightEnd -= nCharWidth;
+ }
+ [[fallthrough]];
+ }
+ case RubyAdjust_BLOCK:
+ {
+ if (sOutputText.getLength() > 1)
+ {
+ sal_Int32 nCount = sOutputText.getLength();
+ tools::Long nSpace
+ = ((nRightEnd - nLeftStart) - rRenderContext.GetTextWidth(sOutputText))
+ / (nCount - 1);
+ for (sal_Int32 i = 0; i < nCount; i++)
+ {
+ OUString sChar(sOutputText[i]);
+ rRenderContext.DrawText(Point(nLeftStart, nYOutput), sChar);
+ tools::Long nCharWidth = rRenderContext.GetTextWidth(sChar);
+ nLeftStart += nCharWidth + nSpace;
+ }
+ break;
+ }
+ [[fallthrough]];
+ }
+ case RubyAdjust_CENTER:
+ rRenderContext.DrawText(Point(nCenter - nOutTextWidth / 2, nYOutput), sOutputText);
+ break;
+ default:
+ break;
+ }
+ rRenderContext.Pop();
+}
+
+void RubyPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 40,
+ pDrawingArea->get_text_height() * 7);
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+}
+
+IMPL_LINK(SvxRubyDialog, KeyUpDownHdl_Impl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ sal_uInt16 nCode = rKeyCode.GetCode();
+ if (KEY_UP == nCode || KEY_DOWN == nCode)
+ {
+ sal_Int32 nParam = KEY_UP == nCode ? -1 : 1;
+ bHandled = EditJumpHdl_Impl(nParam);
+ }
+ return bHandled;
+}
+
+IMPL_LINK(SvxRubyDialog, KeyUpDownTabHdl_Impl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ sal_uInt16 nMod = rKeyCode.GetModifier();
+ sal_uInt16 nCode = rKeyCode.GetCode();
+ if (nCode == KEY_TAB && (!nMod || KEY_SHIFT == nMod))
+ {
+ sal_Int32 nParam = KEY_SHIFT == nMod ? -1 : 1;
+ if (EditScrollHdl_Impl(nParam))
+ bHandled = true;
+ }
+ if (!bHandled)
+ bHandled = KeyUpDownHdl_Impl(rKEvt);
+ return bHandled;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/rulritem.cxx b/svx/source/dialog/rulritem.cxx
new file mode 100644
index 000000000..2e1dac984
--- /dev/null
+++ b/svx/source/dialog/rulritem.cxx
@@ -0,0 +1,732 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svxids.hrc>
+#include <svx/rulritem.hxx>
+#include <svx/unomid.hxx>
+#include <tools/debug.hxx>
+#include <tools/mapunit.hxx>
+#include <tools/UnitConversion.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/frame/status/LeftRightMargin.hpp>
+#include <com/sun/star/frame/status/UpperLowerMargin.hpp>
+
+SfxPoolItem* SvxPagePosSizeItem::CreateDefault() { return new SvxPagePosSizeItem; }
+SfxPoolItem* SvxLongLRSpaceItem::CreateDefault() { return new SvxLongLRSpaceItem; }
+SfxPoolItem* SvxLongULSpaceItem::CreateDefault() { return new SvxLongULSpaceItem; }
+SfxPoolItem* SvxColumnItem::CreateDefault() { return new SvxColumnItem; }
+SfxPoolItem* SvxObjectItem::CreateDefault() { SAL_WARN( "svx", "No SvxObjectItem factory available"); return nullptr; }
+
+/* SvxLongLRSpaceItem */
+
+bool SvxLongLRSpaceItem::operator==( const SfxPoolItem& rCmp) const
+{
+ return SfxPoolItem::operator==(rCmp) &&
+ mlLeft == static_cast<const SvxLongLRSpaceItem &>(rCmp).mlLeft &&
+ mlRight == static_cast<const SvxLongLRSpaceItem &>(rCmp).mlRight;
+}
+
+bool SvxLongLRSpaceItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal;
+ switch( nMemberId )
+ {
+ case 0:
+ {
+ css::frame::status::LeftRightMargin aLeftRightMargin;
+ aLeftRightMargin.Left = bConvert ? convertTwipToMm100( mlLeft ) : mlLeft;
+ aLeftRightMargin.Right = bConvert ? convertTwipToMm100( mlRight ) : mlRight;
+ rVal <<= aLeftRightMargin;
+ return true;
+ }
+
+ case MID_LEFT:
+ nVal = mlLeft;
+ break;
+ case MID_RIGHT:
+ nVal = mlRight;
+ break;
+ default:
+ OSL_FAIL("Wrong MemberId!");
+ return false;
+ }
+
+ if ( bConvert )
+ nVal = convertTwipToMm100( nVal );
+
+ rVal <<= nVal;
+ return true;
+}
+
+bool SvxLongLRSpaceItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal = 0;
+ if ( nMemberId == 0 )
+ {
+ css::frame::status::LeftRightMargin aLeftRightMargin;
+ if ( rVal >>= aLeftRightMargin )
+ {
+ mlLeft = bConvert ? o3tl::toTwips(aLeftRightMargin.Left, o3tl::Length::mm100) : aLeftRightMargin.Left;
+ mlRight = bConvert ? o3tl::toTwips(aLeftRightMargin.Right, o3tl::Length::mm100) : aLeftRightMargin.Right;
+ return true;
+ }
+ }
+ else if ( rVal >>= nVal )
+ {
+ if ( bConvert )
+ nVal = o3tl::toTwips(nVal, o3tl::Length::mm100);
+
+ switch( nMemberId )
+ {
+ case MID_LEFT:
+ mlLeft = nVal;
+ break;
+ case MID_RIGHT:
+ mlRight = nVal;
+ break;
+ default:
+ OSL_FAIL("Wrong MemberId!");
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool SvxLongLRSpaceItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rWrapper*/) const
+{
+ return false;
+}
+
+SvxLongLRSpaceItem* SvxLongLRSpaceItem::Clone(SfxItemPool *) const
+{
+ return new SvxLongLRSpaceItem(*this);
+}
+
+SvxLongLRSpaceItem::SvxLongLRSpaceItem(tools::Long lLeft, tools::Long lRight, TypedWhichId<SvxLongLRSpaceItem> nId) :
+ SfxPoolItem (nId),
+ mlLeft (lLeft),
+ mlRight (lRight)
+{}
+
+SvxLongLRSpaceItem::SvxLongLRSpaceItem() :
+ SfxPoolItem (0),
+ mlLeft (0),
+ mlRight (0)
+{}
+
+void SvxLongLRSpaceItem::SetLeft(tools::Long lArgLeft)
+{
+ mlLeft = lArgLeft;
+}
+
+void SvxLongLRSpaceItem::SetRight(tools::Long lArgRight)
+{
+ mlRight = lArgRight;
+}
+
+/* SvxLongULSpaceItem */
+
+bool SvxLongULSpaceItem::operator==( const SfxPoolItem& rCmp) const
+{
+ return SfxPoolItem::operator==(rCmp) &&
+ mlLeft == static_cast<const SvxLongULSpaceItem&>(rCmp).mlLeft &&
+ mlRight == static_cast<const SvxLongULSpaceItem&>(rCmp).mlRight;
+}
+
+bool SvxLongULSpaceItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal;
+ switch( nMemberId )
+ {
+ case 0:
+ {
+ css::frame::status::UpperLowerMargin aUpperLowerMargin;
+ aUpperLowerMargin.Upper = bConvert ? convertTwipToMm100( mlLeft ) : mlLeft;
+ aUpperLowerMargin.Lower = bConvert ? convertTwipToMm100( mlRight ) : mlRight;
+ rVal <<= aUpperLowerMargin;
+ return true;
+ }
+
+ case MID_UPPER:
+ nVal = mlLeft;
+ break;
+ case MID_LOWER:
+ nVal = mlRight;
+ break;
+ default: OSL_FAIL("Wrong MemberId!"); return false;
+ }
+
+ if ( bConvert )
+ nVal = convertTwipToMm100( nVal );
+
+ rVal <<= nVal;
+ return true;
+}
+
+bool SvxLongULSpaceItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal = 0;
+ if ( nMemberId == 0 )
+ {
+ css::frame::status::UpperLowerMargin aUpperLowerMargin;
+ if ( rVal >>= aUpperLowerMargin )
+ {
+ mlLeft = bConvert ? o3tl::toTwips(aUpperLowerMargin.Upper, o3tl::Length::mm100) : aUpperLowerMargin.Upper;
+ mlRight = bConvert ? o3tl::toTwips(aUpperLowerMargin.Lower, o3tl::Length::mm100) : aUpperLowerMargin.Lower;
+ return true;
+ }
+ }
+ else if ( rVal >>= nVal )
+ {
+ if ( bConvert )
+ nVal = o3tl::toTwips(nVal, o3tl::Length::mm100);
+
+ switch( nMemberId )
+ {
+ case MID_UPPER:
+ mlLeft = nVal;
+ break;
+ case MID_LOWER:
+ mlRight = nVal;
+ break;
+ default:
+ OSL_FAIL("Wrong MemberId!");
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool SvxLongULSpaceItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rWrapper*/ ) const
+{
+ return false;
+}
+
+SvxLongULSpaceItem* SvxLongULSpaceItem::Clone(SfxItemPool *) const
+{
+ return new SvxLongULSpaceItem(*this);
+}
+
+SvxLongULSpaceItem::SvxLongULSpaceItem(tools::Long lLeft, tools::Long lRight, TypedWhichId<SvxLongULSpaceItem> nId) :
+ SfxPoolItem (nId),
+ mlLeft (lLeft),
+ mlRight (lRight)
+{}
+
+SvxLongULSpaceItem::SvxLongULSpaceItem() :
+ SfxPoolItem (0),
+ mlLeft (0),
+ mlRight (0)
+{}
+
+
+void SvxLongULSpaceItem::SetUpper(tools::Long lArgLeft)
+{
+ mlLeft = lArgLeft;
+}
+
+void SvxLongULSpaceItem::SetLower(tools::Long lArgRight)
+{
+ mlRight = lArgRight;
+}
+
+/* SvxPagePosSizeItem */
+
+bool SvxPagePosSizeItem::operator==( const SfxPoolItem& rCmp) const
+{
+ return SfxPoolItem::operator==(rCmp) &&
+ aPos == static_cast<const SvxPagePosSizeItem &>(rCmp).aPos &&
+ lWidth == static_cast<const SvxPagePosSizeItem &>(rCmp).lWidth &&
+ lHeight == static_cast<const SvxPagePosSizeItem &>(rCmp).lHeight;
+}
+
+bool SvxPagePosSizeItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal;
+ switch ( nMemberId )
+ {
+ case 0 :
+ {
+ css::awt::Rectangle aPagePosSize;
+ aPagePosSize.X = aPos.X();
+ aPagePosSize.Y = aPos.Y();
+ aPagePosSize.Width = lWidth;
+ aPagePosSize.Height = lHeight;
+ rVal <<= aPagePosSize;
+ return true;
+ }
+
+ case MID_X: nVal = aPos.X(); break;
+ case MID_Y: nVal = aPos.Y(); break;
+ case MID_WIDTH: nVal = lWidth; break;
+ case MID_HEIGHT: nVal = lHeight; break;
+
+ default: OSL_FAIL("Wrong MemberId!"); return false;
+ }
+
+ rVal <<= nVal;
+ return true;
+}
+
+bool SvxPagePosSizeItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal = 0;
+ if ( nMemberId == 0 )
+ {
+ css::awt::Rectangle aPagePosSize;
+ if ( rVal >>= aPagePosSize )
+ {
+ aPos.setX( aPagePosSize.X );
+ aPos.setY( aPagePosSize.Y );
+ lWidth = aPagePosSize.Width;
+ lHeight = aPagePosSize.Height;
+ return true;
+ }
+ else
+ return false;
+ }
+ else if ( rVal >>= nVal )
+ {
+ switch ( nMemberId )
+ {
+ case MID_X: aPos.setX( nVal ); break;
+ case MID_Y: aPos.setY( nVal ); break;
+ case MID_WIDTH: lWidth = nVal; break;
+ case MID_HEIGHT: lHeight = nVal; break;
+
+ default: OSL_FAIL("Wrong MemberId!"); return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool SvxPagePosSizeItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rWrapper*/ ) const
+{
+ return false;
+}
+
+SvxPagePosSizeItem* SvxPagePosSizeItem::Clone(SfxItemPool *) const
+{
+ return new SvxPagePosSizeItem(*this);
+}
+
+SvxPagePosSizeItem::SvxPagePosSizeItem(const Point &rP, tools::Long lW, tools::Long lH) :
+ SfxPoolItem (SID_RULER_PAGE_POS),
+ aPos (rP),
+ lWidth (lW),
+ lHeight (lH)
+{}
+
+SvxPagePosSizeItem::SvxPagePosSizeItem() :
+ SfxPoolItem (0),
+ aPos (0, 0),
+ lWidth (0),
+ lHeight (0)
+{}
+
+/* SvxColumnItem */
+
+bool SvxColumnItem::operator==(const SfxPoolItem& rCmp) const
+{
+ if(!SfxPoolItem::operator==(rCmp) ||
+ nActColumn != static_cast<const SvxColumnItem&>(rCmp).nActColumn ||
+ nLeft != static_cast<const SvxColumnItem&>(rCmp).nLeft ||
+ nRight != static_cast<const SvxColumnItem&>(rCmp).nRight ||
+ bTable != static_cast<const SvxColumnItem&>(rCmp).bTable ||
+ Count() != static_cast<const SvxColumnItem&>(rCmp).Count())
+ return false;
+
+ const sal_uInt16 nCount = static_cast<const SvxColumnItem&>(rCmp).Count();
+ for(sal_uInt16 i = 0; i < nCount;++i)
+ {
+ if( (*this)[i] != static_cast<const SvxColumnItem&>(rCmp)[i] )
+ return false;
+ }
+ return true;
+}
+
+SvxColumnItem::SvxColumnItem( sal_uInt16 nAct ) :
+ SfxPoolItem (SID_RULER_BORDERS),
+ nLeft (0),
+ nRight (0),
+ nActColumn (nAct),
+ bTable (false),
+ bOrtho (true)
+
+{}
+
+SvxColumnItem::SvxColumnItem( sal_uInt16 nActCol, sal_uInt16 left, sal_uInt16 right ) :
+ SfxPoolItem (SID_RULER_BORDERS),
+ nLeft (left),
+ nRight (right),
+ nActColumn (nActCol),
+ bTable (true),
+ bOrtho (true)
+{}
+
+bool SvxColumnItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rWrapper*/ ) const
+{
+ return false;
+}
+
+SvxColumnItem* SvxColumnItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SvxColumnItem(*this);
+}
+
+bool SvxColumnItem::CalcOrtho() const
+{
+ const sal_uInt16 nCount = Count();
+ DBG_ASSERT(nCount >= 2, "no columns");
+ if(nCount < 2)
+ return false;
+
+ tools::Long nColWidth = (*this)[0].GetWidth();
+ for(sal_uInt16 i = 1; i < nCount; ++i) {
+ if( (*this)[i].GetWidth() != nColWidth)
+ return false;
+ }
+ //!! Wide divider
+ return true;
+}
+
+bool SvxColumnItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch ( nMemberId )
+ {
+ case MID_COLUMNARRAY:
+ return false;
+ case MID_RIGHT:
+ rVal <<= nRight;
+ break;
+ case MID_LEFT:
+ rVal <<= nLeft;
+ break;
+ case MID_ORTHO:
+ rVal <<= bOrtho;
+ break;
+ case MID_ACTUAL:
+ rVal <<= static_cast<sal_Int32>(nActColumn);
+ break;
+ case MID_TABLE:
+ rVal <<= bTable;
+ break;
+ default:
+ // SfxDispatchController_Impl::StateChanged calls this with hardcoded 0 triggering this;
+ OSL_FAIL("Wrong MemberId!");
+ return false;
+ }
+
+ return true;
+}
+
+bool SvxColumnItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ sal_Int32 nVal = 0;
+ switch ( nMemberId )
+ {
+ case MID_COLUMNARRAY:
+ {
+ return false;
+ }
+ case MID_RIGHT:
+ rVal >>= nRight;
+ break;
+ case MID_LEFT:
+ rVal >>= nLeft;
+ break;
+ case MID_ORTHO:
+ rVal >>= nVal;
+ bOrtho = static_cast<bool>(nVal);
+ break;
+ case MID_ACTUAL:
+ rVal >>= nVal;
+ nActColumn = static_cast<sal_uInt16>(nVal);
+ break;
+ case MID_TABLE:
+ rVal >>= nVal;
+ bTable = static_cast<bool>(nVal);
+ break;
+ default:
+ OSL_FAIL("Wrong MemberId!");
+ return false;
+ }
+
+ return true;
+}
+
+sal_uInt16 SvxColumnItem::Count() const
+{
+ return aColumns.size();
+}
+
+SvxColumnDescription& SvxColumnItem::At(sal_uInt16 index)
+{
+ return aColumns[index];
+}
+
+SvxColumnDescription& SvxColumnItem::GetActiveColumnDescription()
+{
+ return aColumns[GetActColumn()];
+}
+
+SvxColumnDescription& SvxColumnItem::operator[](sal_uInt16 index)
+{
+ return aColumns[index];
+}
+
+const SvxColumnDescription& SvxColumnItem::operator[](sal_uInt16 index) const
+{
+ return aColumns[index];
+}
+
+void SvxColumnItem::Append(const SvxColumnDescription &rDesc)
+{
+ aColumns.push_back(rDesc);
+}
+
+void SvxColumnItem::SetLeft(tools::Long left)
+{
+ nLeft = left;
+}
+
+void SvxColumnItem::SetRight(tools::Long right)
+{
+ nRight = right;
+}
+
+
+bool SvxColumnItem::IsFirstAct() const
+{
+ return nActColumn == 0;
+}
+
+bool SvxColumnItem::IsLastAct() const
+{
+ return nActColumn == Count() - 1;
+}
+
+SvxColumnDescription::SvxColumnDescription(tools::Long start, tools::Long end, bool bVis) :
+ nStart (start),
+ nEnd (end),
+ bVisible (bVis),
+ nEndMin (0),
+ nEndMax (0)
+{}
+
+SvxColumnDescription::SvxColumnDescription(tools::Long start, tools::Long end, tools::Long endMin, tools::Long endMax, bool bVis) :
+ nStart (start),
+ nEnd (end),
+ bVisible (bVis),
+ // fdo#85858 hack: clamp these to smaller value to prevent overflow
+ nEndMin(std::min<tools::Long>(endMin, std::numeric_limits<unsigned short>::max())),
+ nEndMax(std::min<tools::Long>(endMax, std::numeric_limits<unsigned short>::max()))
+{}
+
+bool SvxColumnDescription::operator==(const SvxColumnDescription& rCmp) const
+{
+ return nStart == rCmp.nStart
+ && bVisible == rCmp.bVisible
+ && nEnd == rCmp.nEnd
+ && nEndMin == rCmp.nEndMin
+ && nEndMax == rCmp.nEndMax;
+}
+
+bool SvxColumnDescription::operator!=(const SvxColumnDescription& rCmp) const
+{
+ return !operator==(rCmp);
+}
+
+tools::Long SvxColumnDescription::GetWidth() const
+{
+ return nEnd - nStart;
+}
+
+/* SvxColumnItem */
+void SvxColumnItem::SetOrtho(bool bVal)
+{
+ bOrtho = bVal;
+}
+
+bool SvxColumnItem::IsConsistent() const
+{
+ return nActColumn < aColumns.size();
+}
+
+bool SvxObjectItem::operator==( const SfxPoolItem& rCmp ) const
+{
+ return SfxPoolItem::operator==(rCmp) &&
+ nStartX == static_cast<const SvxObjectItem&>(rCmp).nStartX &&
+ nEndX == static_cast<const SvxObjectItem&>(rCmp).nEndX &&
+ nStartY == static_cast<const SvxObjectItem&>(rCmp).nStartY &&
+ nEndY == static_cast<const SvxObjectItem&>(rCmp).nEndY &&
+ bLimits == static_cast<const SvxObjectItem&>(rCmp).bLimits;
+}
+
+bool SvxObjectItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rWrapper*/ ) const
+{
+ return false;
+}
+
+SvxObjectItem* SvxObjectItem::Clone(SfxItemPool *) const
+{
+ return new SvxObjectItem(*this);
+}
+
+SvxObjectItem::SvxObjectItem( tools::Long nSX, tools::Long nEX,
+ tools::Long nSY, tools::Long nEY ) :
+ SfxPoolItem (SID_RULER_OBJECT),
+ nStartX (nSX),
+ nEndX (nEX),
+ nStartY (nSY),
+ nEndY (nEY),
+ bLimits (false)
+{}
+
+bool SvxObjectItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch (nMemberId)
+ {
+ case MID_START_X:
+ rVal <<= nStartX;
+ break;
+ case MID_START_Y:
+ rVal <<= nStartY;
+ break;
+ case MID_END_X:
+ rVal <<= nEndX;
+ break;
+ case MID_END_Y:
+ rVal <<= nEndY;
+ break;
+ case MID_LIMIT:
+ rVal <<= bLimits;
+ break;
+ default:
+ OSL_FAIL( "Wrong MemberId" );
+ return false;
+ }
+
+ return true;
+}
+
+bool SvxObjectItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ bool bRet = false;
+ switch (nMemberId)
+ {
+ case MID_START_X:
+ bRet = (rVal >>= nStartX);
+ break;
+ case MID_START_Y:
+ bRet = (rVal >>= nStartY);
+ break;
+ case MID_END_X:
+ bRet = (rVal >>= nEndX);
+ break;
+ case MID_END_Y:
+ bRet = (rVal >>= nEndY);
+ break;
+ case MID_LIMIT:
+ bRet = (rVal >>= bLimits);
+ break;
+ default: OSL_FAIL( "Wrong MemberId" );
+ }
+
+ return bRet;
+}
+
+
+void SvxObjectItem::SetStartX(tools::Long lValue)
+{
+ nStartX = lValue;
+}
+
+void SvxObjectItem::SetEndX(tools::Long lValue)
+{
+ nEndX = lValue;
+}
+
+void SvxObjectItem::SetStartY(tools::Long lValue)
+{
+ nStartY = lValue;
+}
+
+void SvxObjectItem::SetEndY(tools::Long lValue)
+{
+ nEndY = lValue;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/samecontentlistbox.cxx b/svx/source/dialog/samecontentlistbox.cxx
new file mode 100644
index 000000000..66c628a1e
--- /dev/null
+++ b/svx/source/dialog/samecontentlistbox.cxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/samecontentlistbox.hxx>
+#include <samecontent.hrc>
+
+namespace SameContentListBox
+{
+ void Fill(weld::ComboBox& rComboBox)
+ {
+ rComboBox.clear();
+ for (size_t i = 0; i < SAL_N_ELEMENTS(RID_SVXSTRARY_SAMECONTENT); ++i)
+ {
+ OUString aStr = SvxResId(RID_SVXSTRARY_SAMECONTENT[i].first);
+ sal_uInt32 nData = RID_SVXSTRARY_SAMECONTENT[i].second;
+ rComboBox.append(OUString::number(nData), aStr);
+ }
+ rComboBox.set_active(0);
+ rComboBox.set_size_request(150, -1);
+ }
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/searchcharmap.cxx b/svx/source/dialog/searchcharmap.cxx
new file mode 100644
index 000000000..2d8eeaab8
--- /dev/null
+++ b/svx/source/dialog/searchcharmap.cxx
@@ -0,0 +1,441 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_wasm_strip.h>
+
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+
+#include <svx/ucsubset.hxx>
+#include <unordered_map>
+
+#include <svx/searchcharmap.hxx>
+
+#include <charmapacc.hxx>
+
+#include <rtl/ustrbuf.hxx>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+
+SvxSearchCharSet::SvxSearchCharSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow, const VclPtr<VirtualDevice>& rVirDev)
+ : SvxShowCharSet(std::move(pScrolledWindow), rVirDev)
+ , nCount(0)
+{
+}
+
+int SvxSearchCharSet::LastInView() const
+{
+ int nIndex = FirstInView();
+ nIndex += ROW_COUNT * COLUMN_COUNT - 1;
+ int nCompare = nCount - 1;
+ if (nIndex > nCompare)
+ nIndex = nCompare;
+ return nIndex;
+}
+
+bool SvxSearchCharSet::KeyInput(const KeyEvent& rKEvt)
+{
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ if (aCode.GetModifier())
+ return false;
+
+ int tmpSelected = nSelectedIndex;
+
+ bool bRet = true;
+
+ switch (aCode.GetCode())
+ {
+ case KEY_SPACE:
+ aSelectHdl.Call( this );
+ break;
+ case KEY_LEFT:
+ --tmpSelected;
+ break;
+ case KEY_RIGHT:
+ ++tmpSelected;
+ break;
+ case KEY_UP:
+ tmpSelected -= COLUMN_COUNT;
+ break;
+ case KEY_DOWN:
+ tmpSelected += COLUMN_COUNT;
+ break;
+ case KEY_PAGEUP:
+ tmpSelected -= ROW_COUNT * COLUMN_COUNT;
+ break;
+ case KEY_PAGEDOWN:
+ tmpSelected += ROW_COUNT * COLUMN_COUNT;
+ break;
+ case KEY_HOME:
+ tmpSelected = 0;
+ break;
+ case KEY_END:
+ tmpSelected = nCount - 1;
+ break;
+ case KEY_TAB: // some fonts have a character at these unicode control codes
+ case KEY_ESCAPE:
+ case KEY_RETURN:
+ bRet = false;
+ tmpSelected = - 1; // mark as invalid
+ break;
+ default:
+ tmpSelected = -1;
+ bRet = false;
+ break;
+ }
+
+ if ( tmpSelected >= 0 )
+ {
+ SelectIndex( tmpSelected, true );
+ aPreSelectHdl.Call( this );
+ }
+
+ return bRet;
+}
+
+void SvxSearchCharSet::SelectCharacter( const Subset* sub )
+{
+ if (!mxFontCharMap.is())
+ RecalculateFont(*mxVirDev);
+
+ // get next available char of current font
+ sal_UCS4 cChar = sub->GetRangeMin();
+ int nMapIndex = 0;
+
+ while(cChar <= sub->GetRangeMax() && nMapIndex == 0)
+ {
+ auto it = std::find_if(m_aItemList.begin(), m_aItemList.end(),
+ [&cChar](const std::pair<const sal_Int32, sal_UCS4>& rItem) { return rItem.second == cChar; });
+ if (it != m_aItemList.end())
+ nMapIndex = it->first;
+ cChar++;
+ }
+
+ if(nMapIndex == 0)
+ SelectIndex( 0 );
+ else
+ SelectIndex( nMapIndex );
+ aHighHdl.Call(this);
+ // move selected item to top row if not in focus
+ //TO.DO aVscrollSB->SetThumbPos( nMapIndex / COLUMN_COUNT );
+ Invalidate();
+}
+
+void SvxSearchCharSet::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ InitSettings(rRenderContext);
+ RecalculateFont(rRenderContext);
+ DrawChars_Impl(rRenderContext, FirstInView(), LastInView());
+}
+
+void SvxSearchCharSet::DrawChars_Impl(vcl::RenderContext& rRenderContext, int n1, int n2)
+{
+ if (n1 > LastInView() || n2 < FirstInView())
+ return;
+
+ Size aOutputSize(GetOutputSizePixel());
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Color aWindowTextColor(rStyleSettings.GetFieldTextColor());
+ Color aHighlightColor(rStyleSettings.GetHighlightColor());
+ Color aHighlightTextColor(rStyleSettings.GetHighlightTextColor());
+ Color aFaceColor(rStyleSettings.GetFaceColor());
+ Color aLightColor(rStyleSettings.GetLightColor());
+ Color aShadowColor(rStyleSettings.GetShadowColor());
+
+ int i;
+ rRenderContext.SetLineColor(aShadowColor);
+ for (i = 1; i < COLUMN_COUNT; ++i)
+ {
+ rRenderContext.DrawLine(Point(nX * i + m_nXGap, 0),
+ Point(nX * i + m_nXGap, aOutputSize.Height()));
+ }
+ for (i = 1; i < ROW_COUNT; ++i)
+ {
+ rRenderContext.DrawLine(Point(0, nY * i + m_nYGap),
+ Point(aOutputSize.Width(), nY * i + m_nYGap));
+ }
+
+ int nTextHeight = rRenderContext.GetTextHeight();
+ tools::Rectangle aBoundRect;
+ for (i = n1; i <= n2; ++i)
+ {
+ Point pix = MapIndexToPixel(i);
+ int x = pix.X();
+ int y = pix.Y();
+
+ OUStringBuffer buf;
+ std::unordered_map<sal_Int32, sal_UCS4>::const_iterator got = m_aItemList.find (i);
+ sal_UCS4 sName;
+
+ if(got == m_aItemList.end())
+ continue;
+ else
+ sName = got->second;
+
+ buf.appendUtf32(sName);
+ OUString aCharStr(buf.makeStringAndClear());
+ int nTextWidth = rRenderContext.GetTextWidth(aCharStr);
+ int tx = x + (nX - nTextWidth + 1) / 2;
+ int ty = y + (nY - nTextHeight + 1) / 2;
+ Point aPointTxTy(tx, ty);
+
+ // adjust position before it gets out of bounds
+ if (rRenderContext.GetTextBoundRect(aBoundRect, aCharStr) && !aBoundRect.IsEmpty())
+ {
+ // zero advance width => use ink width to center glyph
+ if (!nTextWidth)
+ {
+ aPointTxTy.setX( x - aBoundRect.Left() + (nX - aBoundRect.GetWidth() + 1) / 2 );
+ }
+
+ aBoundRect += aPointTxTy;
+
+ // shift back vertically if needed
+ int nYLDelta = aBoundRect.Top() - y;
+ int nYHDelta = (y + nY) - aBoundRect.Bottom();
+ if (nYLDelta <= 0)
+ aPointTxTy.AdjustY( -(nYLDelta - 1) );
+ else if (nYHDelta <= 0)
+ aPointTxTy.AdjustY(nYHDelta - 1 );
+
+ // shift back horizontally if needed
+ int nXLDelta = aBoundRect.Left() - x;
+ int nXHDelta = (x + nX) - aBoundRect.Right();
+ if (nXLDelta <= 0)
+ aPointTxTy.AdjustX( -(nXLDelta - 1) );
+ else if (nXHDelta <= 0)
+ aPointTxTy.AdjustX(nXHDelta - 1 );
+ }
+
+ Color aTextCol = rRenderContext.GetTextColor();
+ if (i != nSelectedIndex)
+ {
+ rRenderContext.SetTextColor(aWindowTextColor);
+ rRenderContext.DrawText(aPointTxTy, aCharStr);
+ }
+ else
+ {
+ Color aLineCol = rRenderContext.GetLineColor();
+ Color aFillCol = rRenderContext.GetFillColor();
+ rRenderContext.SetLineColor();
+ Point aPointUL(x + 1, y + 1);
+ if (HasFocus())
+ {
+ rRenderContext.SetFillColor(aHighlightColor);
+ rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
+
+ rRenderContext.SetTextColor(aHighlightTextColor);
+ rRenderContext.DrawText(aPointTxTy, aCharStr);
+ }
+ else
+ {
+ rRenderContext.SetFillColor(aFaceColor);
+ rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
+
+ rRenderContext.SetLineColor(aLightColor);
+ rRenderContext.DrawLine(aPointUL, Point(x + nX - 1, y + 1));
+ rRenderContext.DrawLine(aPointUL, Point(x + 1, y + nY - 1));
+
+ rRenderContext.SetLineColor(aShadowColor);
+ rRenderContext.DrawLine(Point(x + 1, y + nY - 1), Point(x + nX - 1, y + nY - 1));
+ rRenderContext.DrawLine(Point(x + nX - 1, y + nY - 1), Point(x + nX - 1, y + 1));
+
+ rRenderContext.DrawText(aPointTxTy, aCharStr);
+ }
+ rRenderContext.SetLineColor(aLineCol);
+ rRenderContext.SetFillColor(aFillCol);
+ }
+ rRenderContext.SetTextColor(aTextCol);
+ }
+}
+
+sal_UCS4 SvxSearchCharSet::GetSelectCharacter() const
+{
+ if( nSelectedIndex >= 0 )
+ {
+ std::unordered_map<sal_Int32,sal_UCS4>::const_iterator got = m_aItemList.find (nSelectedIndex);
+
+ if(got == m_aItemList.end())
+ return 1;
+ else
+ return got->second;
+ }
+ return 1;
+}
+
+void SvxSearchCharSet::RecalculateFont(vcl::RenderContext& rRenderContext)
+{
+ if (!mbRecalculateFont)
+ return;
+
+ Size aSize(GetOutputSizePixel());
+
+ vcl::Font aFont = rRenderContext.GetFont();
+ aFont.SetWeight(WEIGHT_LIGHT);
+ aFont.SetAlignment(ALIGN_TOP);
+ int nFontHeight = (aSize.Height() - 5) * 2 / (3 * ROW_COUNT);
+ maFontSize = rRenderContext.PixelToLogic(Size(0, nFontHeight));
+ aFont.SetFontSize(maFontSize);
+ aFont.SetTransparent(true);
+ rRenderContext.SetFont(aFont);
+ rRenderContext.GetFontCharMap(mxFontCharMap);
+ getFavCharacterList();
+
+ nX = aSize.Width() / COLUMN_COUNT;
+ nY = aSize.Height() / ROW_COUNT;
+
+ UpdateScrollRange();
+
+ // rearrange CharSet element in sync with nX- and nY-multiples
+ Size aDrawSize(nX * COLUMN_COUNT, nY * ROW_COUNT);
+ m_nXGap = (aSize.Width() - aDrawSize.Width()) / 2;
+ m_nYGap = (aSize.Height() - aDrawSize.Height()) / 2;
+
+ mbRecalculateFont = false;
+}
+
+void SvxSearchCharSet::UpdateScrollRange()
+{
+ //scrollbar settings
+ int nLastRow = (nCount - 1 + COLUMN_COUNT) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_configure(mxScrollArea->vadjustment_get_value(), 0, nLastRow, 1, ROW_COUNT - 1, ROW_COUNT);
+}
+
+void SvxSearchCharSet::SelectIndex(int nNewIndex, bool bFocus)
+{
+ if (!mxFontCharMap.is())
+ RecalculateFont(*mxVirDev);
+
+ if( nNewIndex < 0 )
+ {
+ mxScrollArea->vadjustment_set_value(0);
+ nSelectedIndex = bFocus ? 0 : -1;
+ Invalidate();
+ }
+ else if( nNewIndex < FirstInView() )
+ {
+ // need to scroll up to see selected item
+ int nOldPos = mxScrollArea->vadjustment_get_value();
+ int nDelta = (FirstInView() - nNewIndex + COLUMN_COUNT-1) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_set_value(nOldPos - nDelta);
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+ else if( nNewIndex > LastInView() )
+ {
+ // need to scroll down to see selected item
+ int nOldPos = mxScrollArea->vadjustment_get_value();
+ int nDelta = (nNewIndex - LastInView() + COLUMN_COUNT) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_set_value(nOldPos + nDelta);
+
+ if( nNewIndex < nCount )
+ {
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+ else if (nOldPos != mxScrollArea->vadjustment_get_value())
+ {
+ Invalidate();
+ }
+ }
+ else
+ {
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+
+ if( nSelectedIndex >= 0 )
+ {
+#if 0
+ if( m_xAccessible.is() )
+ {
+ svx::SvxShowCharSetItem* pItem = ImplGetItem(nSelectedIndex);
+ // Don't fire the focus event.
+ if ( bFocus )
+ m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), makeAny(pItem->GetAccessible()) ); // this call assures that m_pItem is set
+ else
+ m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS, Any(), makeAny(pItem->GetAccessible()) ); // this call assures that m_pItem is set
+
+ assert(pItem->m_xItem.is() && "No accessible created!");
+ Any aOldAny, aNewAny;
+ aNewAny <<= AccessibleStateType::FOCUSED;
+ // Don't fire the focus event.
+ if ( bFocus )
+ pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
+
+ aNewAny <<= AccessibleStateType::SELECTED;
+ pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
+ }
+#endif
+ }
+ aHighHdl.Call( this );
+}
+
+SvxSearchCharSet::~SvxSearchCharSet()
+{
+}
+
+svx::SvxShowCharSetItem* SvxSearchCharSet::ImplGetItem( int _nPos )
+{
+ ItemsMap::iterator aFind = m_aItems.find(_nPos);
+ if ( aFind == m_aItems.end() )
+ {
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ OSL_ENSURE(m_xAccessible.is(), "Who wants to create a child of my table without a parent?");
+#endif
+ auto xItem = std::make_shared<svx::SvxShowCharSetItem>(*this,
+ m_xAccessible.get(), sal::static_int_cast< sal_uInt16 >(_nPos));
+ aFind = m_aItems.emplace(_nPos, xItem).first;
+ OUStringBuffer buf;
+ std::unordered_map<sal_Int32,sal_UCS4>::const_iterator got = m_aItemList.find (_nPos);
+ if (got != m_aItemList.end())
+ buf.appendUtf32(got->second);
+ aFind->second->maText = buf.makeStringAndClear();
+ Point pix = MapIndexToPixel( _nPos );
+ aFind->second->maRect = tools::Rectangle( Point( pix.X() + 1, pix.Y() + 1 ), Size(nX-1,nY-1) );
+ }
+
+ return aFind->second.get();
+}
+
+sal_Int32 SvxSearchCharSet::getMaxCharCount() const
+{
+ return nCount;
+}
+
+void SvxSearchCharSet::ClearPreviousData()
+{
+ m_aItemList.clear();
+ nCount = 0;
+ Invalidate();
+}
+
+void SvxSearchCharSet::AppendCharToList(sal_UCS4 sChar)
+{
+ m_aItemList.insert(std::make_pair(nCount++, sChar));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/signaturelinehelper.cxx b/svx/source/dialog/signaturelinehelper.cxx
new file mode 100644
index 000000000..2c055e84d
--- /dev/null
+++ b/svx/source/dialog/signaturelinehelper.cxx
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <svx/signaturelinehelper.hxx>
+
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/xmlsechelper.hxx>
+#include <config_folders.h>
+#include <rtl/bootstrap.hxx>
+#include <sal/log.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/objsh.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdmark.hxx>
+#include <svx/svdview.hxx>
+#include <tools/stream.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/syslocale.hxx>
+#include <vcl/weld.hxx>
+
+using namespace com::sun::star;
+
+namespace svx::SignatureLineHelper
+{
+OUString getSignatureImage(const OUString& rType)
+{
+ OUString aType = rType;
+ if (aType.isEmpty())
+ {
+ aType = "signature-line.svg";
+ }
+ OUString aPath("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/filter/" + aType);
+ rtl::Bootstrap::expandMacros(aPath);
+ SvFileStream aStream(aPath, StreamMode::READ);
+ if (aStream.GetError() != ERRCODE_NONE)
+ {
+ SAL_WARN("cui.dialogs", "failed to open " << aType);
+ }
+
+ OString const svg = read_uInt8s_ToOString(aStream, aStream.remainingSize());
+ return OUString::fromUtf8(svg);
+}
+
+uno::Reference<security::XCertificate> getSignatureCertificate(SfxObjectShell* pShell,
+ weld::Window* pParent)
+{
+ if (!pShell)
+ {
+ return {};
+ }
+
+ if (!pParent)
+ {
+ return {};
+ }
+
+ uno::Reference<security::XDocumentDigitalSignatures> xSigner;
+ if (pShell->GetMedium()->GetFilter()->IsAlienFormat())
+ {
+ xSigner = security::DocumentDigitalSignatures::createDefault(
+ comphelper::getProcessComponentContext());
+ }
+ else
+ {
+ OUString const aODFVersion(
+ comphelper::OStorageHelper::GetODFVersionFromStorage(pShell->GetStorage()));
+ xSigner = security::DocumentDigitalSignatures::createWithVersion(
+ comphelper::getProcessComponentContext(), aODFVersion);
+ }
+ xSigner->setParentWindow(pParent->GetXWindow());
+ OUString aDescription;
+ security::CertificateKind certificateKind = security::CertificateKind_NONE;
+ // When signing ooxml, we only want X.509 certificates
+ if (pShell->GetMedium()->GetFilter()->IsAlienFormat())
+ {
+ certificateKind = security::CertificateKind_X509;
+ }
+ uno::Reference<security::XCertificate> xSignCertificate
+ = xSigner->selectSigningCertificateWithType(certificateKind, aDescription);
+ return xSignCertificate;
+}
+
+OUString getSignerName(const css::uno::Reference<css::security::XCertificate>& xCertificate)
+{
+ return comphelper::xmlsec::GetContentPart(xCertificate->getSubjectName(),
+ xCertificate->getCertificateKind());
+}
+
+OUString getLocalizedDate()
+{
+ const SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
+ Date aDateTime(Date::SYSTEM);
+ return rLocaleData.getDate(aDateTime);
+}
+
+uno::Reference<graphic::XGraphic> importSVG(std::u16string_view rSVG)
+{
+ SvMemoryStream aSvgStream(4096, 4096);
+ aSvgStream.WriteOString(OUStringToOString(rSVG, RTL_TEXTENCODING_UTF8));
+ uno::Reference<io::XInputStream> xInputStream(new utl::OSeekableInputStreamWrapper(aSvgStream));
+ uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
+ uno::Reference<graphic::XGraphicProvider> xProvider
+ = graphic::GraphicProvider::create(xContext);
+
+ uno::Sequence<beans::PropertyValue> aMediaProperties{ comphelper::makePropertyValue(
+ "InputStream", xInputStream) };
+ uno::Reference<graphic::XGraphic> xGraphic(xProvider->queryGraphic(aMediaProperties));
+ return xGraphic;
+}
+
+void setShapeCertificate(const SdrView* pView,
+ const css::uno::Reference<css::security::XCertificate>& xCertificate)
+{
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() < 1)
+ {
+ return;
+ }
+
+ const SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pSignatureLine = pMark->GetMarkedSdrObj();
+ if (!pSignatureLine)
+ {
+ return;
+ }
+
+ // Remember the selected certificate.
+ uno::Reference<drawing::XShape> xShape = pSignatureLine->getUnoShape();
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ comphelper::SequenceAsHashMap aMap(xShapeProps->getPropertyValue("InteropGrabBag"));
+ aMap["SignatureCertificate"] <<= xCertificate;
+ xShapeProps->setPropertyValue("InteropGrabBag", uno::Any(aMap.getAsConstPropertyValueList()));
+
+ // Read svg and replace placeholder texts.
+ OUString aSvgImage(svx::SignatureLineHelper::getSignatureImage("signature-line-draw.svg"));
+ aSvgImage = aSvgImage.replaceAll("[SIGNED_BY]", SvxResId(RID_SVXSTR_SIGNATURELINE_DSIGNED_BY));
+ OUString aSignerName = svx::SignatureLineHelper::getSignerName(xCertificate);
+ aSvgImage = aSvgImage.replaceAll("[SIGNER_NAME]", aSignerName);
+ OUString aDate = svx::SignatureLineHelper::getLocalizedDate();
+ aDate = SvxResId(RID_SVXSTR_SIGNATURELINE_DATE).replaceFirst("%1", aDate);
+ aSvgImage = aSvgImage.replaceAll("[DATE]", aDate);
+
+ uno::Reference<graphic::XGraphic> xGraphic = svx::SignatureLineHelper::importSVG(aSvgImage);
+ xShapeProps->setPropertyValue("Graphic", uno::Any(xGraphic));
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/spacinglistbox.cxx b/svx/source/dialog/spacinglistbox.cxx
new file mode 100644
index 000000000..90cc689cc
--- /dev/null
+++ b/svx/source/dialog/spacinglistbox.cxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/spacinglistbox.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <spacing.hrc>
+
+namespace SpacingListBox
+{
+ void Fill(SpacingType eType, weld::ComboBox& rComboBox)
+ {
+ auto nSelected = rComboBox.get_active();
+ if (nSelected == -1)
+ nSelected = 0;
+ rComboBox.clear();
+
+ const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
+ OUString sSuffix;
+
+ const measurement* pResources;
+ switch (eType)
+ {
+ case SpacingType::SPACING_INCH:
+ pResources = RID_SVXSTRARY_SPACING_INCH;
+ sSuffix = weld::MetricSpinButton::MetricToString(FieldUnit::INCH);
+ break;
+ case SpacingType::MARGINS_INCH:
+ pResources = RID_SVXSTRARY_MARGINS_INCH;
+ sSuffix = weld::MetricSpinButton::MetricToString(FieldUnit::INCH);
+ break;
+ case SpacingType::SPACING_CM:
+ pResources = RID_SVXSTRARY_SPACING_CM;
+ sSuffix = " " + weld::MetricSpinButton::MetricToString(FieldUnit::CM);
+ break;
+ default:
+ case SpacingType::MARGINS_CM:
+ sSuffix = " " + weld::MetricSpinButton::MetricToString(FieldUnit::CM);
+ pResources = RID_SVXSTRARY_MARGINS_CM;
+ break;
+ }
+
+ while (pResources->key)
+ {
+ OUString sMeasurement = rLocaleData.getNum(pResources->human, 2, true, false) + sSuffix;
+ OUString aStr = SvxResId(pResources->key).replaceFirst("%1", sMeasurement);
+ sal_uInt32 nData = pResources->twips;
+ rComboBox.append(OUString::number(nData), aStr);
+ ++pResources;
+ }
+
+ rComboBox.set_active(nSelected);
+
+ rComboBox.set_size_request(150, -1);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/srchctrl.cxx b/svx/source/dialog/srchctrl.cxx
new file mode 100644
index 000000000..51c8d0333
--- /dev/null
+++ b/svx/source/dialog/srchctrl.cxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/intitem.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <svx/svxids.hrc>
+
+#include "srchctrl.hxx"
+#include <svx/srchdlg.hxx>
+#include <svl/srchitem.hxx>
+
+SvxSearchController::SvxSearchController
+(
+ sal_uInt16 _nId,
+ SfxBindings& rBind,
+ SvxSearchDialog& rDlg
+) :
+ SfxControllerItem( _nId, rBind ),
+
+ rSrchDlg( rDlg )
+{
+}
+
+
+void SvxSearchController::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ if ( SfxItemState::DEFAULT == eState )
+ {
+ if ( SID_STYLE_FAMILY1 <= nSID && nSID <= SID_STYLE_FAMILY4 )
+ {
+ SfxObjectShell* pShell = SfxObjectShell::Current();
+
+ if ( pShell && pShell->GetStyleSheetPool() )
+ rSrchDlg.TemplatesChanged_Impl( *pShell->GetStyleSheetPool() );
+ }
+ else if ( SID_SEARCH_OPTIONS == nSID )
+ {
+ DBG_ASSERT( dynamic_cast<const SfxUInt16Item* >(pState) != nullptr, "wrong item type" );
+ SearchOptionFlags nFlags = static_cast<SearchOptionFlags>(static_cast<const SfxUInt16Item*>(pState)->GetValue());
+ rSrchDlg.EnableControls_Impl( nFlags );
+ }
+ else if ( SID_SEARCH_ITEM == nSID )
+ {
+ DBG_ASSERT( dynamic_cast<const SvxSearchItem*>( pState) != nullptr, "wrong item type" );
+ rSrchDlg.SetItem_Impl( static_cast<const SvxSearchItem*>(pState) );
+ }
+ }
+ else if ( SID_SEARCH_OPTIONS == nSID || SID_SEARCH_ITEM == nSID )
+ rSrchDlg.EnableControls_Impl( SearchOptionFlags::NONE );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/srchctrl.hxx b/svx/source/dialog/srchctrl.hxx
new file mode 100644
index 000000000..042757537
--- /dev/null
+++ b/svx/source/dialog/srchctrl.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_SRCHCTRL_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_SRCHCTRL_HXX
+
+#include <sfx2/ctrlitem.hxx>
+class SvxSearchDialog;
+
+class SvxSearchController : public SfxControllerItem
+{
+ SvxSearchDialog& rSrchDlg;
+
+protected:
+ virtual void StateChangedAtToolBoxControl(sal_uInt16, SfxItemState,
+ const SfxPoolItem* pState) override;
+
+public:
+ SvxSearchController(sal_uInt16 nId, SfxBindings& rBnd, SvxSearchDialog& rDlg);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/srchdlg.cxx b/svx/source/dialog/srchdlg.cxx
new file mode 100644
index 000000000..b047ef27d
--- /dev/null
+++ b/svx/source/dialog/srchdlg.cxx
@@ -0,0 +1,2466 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+#include <vcl/timer.hxx>
+#include <svl/slstitm.hxx>
+#include <svl/itemiter.hxx>
+#include <svl/style.hxx>
+#include <unotools/intlwrapper.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <unotools/searchopt.hxx>
+#include <unotools/syslocale.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/ui/XUIElement.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <svl/itempool.hxx>
+
+#include <sfx2/app.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <svx/srchdlg.hxx>
+#include <svx/strarray.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+
+#include <svl/srchitem.hxx>
+#include <svx/pageitem.hxx>
+#include "srchctrl.hxx"
+#include <svx/dialmgr.hxx>
+#include <editeng/brushitem.hxx>
+#include <tools/resary.hxx>
+#include <svx/svxdlg.hxx>
+#include <vcl/toolbox.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <comphelper/lok.hxx>
+
+#include <cstdlib>
+#include <memory>
+
+#include <findtextfield.hxx>
+
+#include <svx/labelitemwindow.hxx>
+#include <svx/xdef.hxx>
+#include <officecfg/Office/Common.hxx>
+
+using namespace com::sun::star::i18n;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::accessibility;
+using namespace com::sun::star;
+using namespace comphelper;
+
+
+#define IS_MOBILE (comphelper::LibreOfficeKit::isActive() && SfxViewShell::Current() && SfxViewShell::Current()->isLOKMobilePhone())
+
+enum class ModifyFlags {
+ NONE = 0x000000,
+ Search = 0x000001,
+ Replace = 0x000002,
+ Word = 0x000004,
+ Exact = 0x000008,
+ Backwards = 0x000010,
+ Selection = 0x000020,
+ Regexp = 0x000040,
+ Layout = 0x000080,
+ Similarity = 0x000100,
+ Formulas = 0x000200,
+ Values = 0x000400,
+ CalcNotes = 0x000800,
+ Rows = 0x001000,
+ Columns = 0x002000,
+ AllTables = 0x004000,
+ Notes = 0x008000,
+ Wildcard = 0x010000
+};
+namespace o3tl {
+ template<> struct typed_flags<ModifyFlags> : is_typed_flags<ModifyFlags, 0x01ffff> {};
+}
+
+namespace
+{
+ bool GetCheckBoxValue(const weld::CheckButton& rBox)
+ {
+ return rBox.get_sensitive() && rBox.get_active();
+ }
+
+ bool GetNegatedCheckBoxValue(const weld::CheckButton& rBox)
+ {
+ return rBox.get_sensitive() && !rBox.get_active();
+ }
+}
+
+struct SearchDlg_Impl
+{
+ bool bSaveToModule : 1,
+ bFocusOnSearch : 1;
+ WhichRangesContainer pRanges;
+ Timer aSelectionTimer { "svx SearchDlg_Impl aSelectionTimer" };
+
+ uno::Reference< frame::XDispatch > xCommand1Dispatch;
+ uno::Reference< frame::XDispatch > xCommand2Dispatch;
+ util::URL aCommand1URL;
+ util::URL aCommand2URL;
+
+ SearchDlg_Impl()
+ : bSaveToModule(true)
+ , bFocusOnSearch(true)
+ {
+ aCommand1URL.Complete = aCommand1URL.Main = "vnd.sun.search:SearchViaComponent1";
+ aCommand1URL.Protocol = "vnd.sun.search:";
+ aCommand1URL.Path = "SearchViaComponent1";
+ aCommand2URL.Complete = aCommand2URL.Main = "vnd.sun.search:SearchViaComponent2";
+ aCommand2URL.Protocol = "vnd.sun.search:";
+ aCommand2URL.Path = "SearchViaComponent2";
+ }
+};
+
+static void ListToStrArr_Impl(sal_uInt16 nId, std::vector<OUString>& rStrLst, weld::ComboBox& rCBox, sal_uInt16 nRememberSize)
+{
+ const SfxStringListItem* pSrchItem =
+ static_cast<const SfxStringListItem*>(SfxGetpApp()->GetItem( nId ));
+
+ if (!pSrchItem)
+ return;
+
+ std::vector<OUString> aLst = pSrchItem->GetList();
+
+ if (aLst.size() > nRememberSize)
+ aLst.resize(nRememberSize);
+
+ for (const OUString & s : aLst)
+ {
+ rStrLst.push_back(s);
+ rCBox.append_text(s);
+ }
+}
+
+static void StrArrToList_Impl( sal_uInt16 nId, const std::vector<OUString>& rStrLst )
+{
+ DBG_ASSERT( !rStrLst.empty(), "check in advance");
+ SfxGetpApp()->PutItem( SfxStringListItem( nId, &rStrLst ) );
+}
+
+SearchAttrItemList::SearchAttrItemList( SearchAttrItemList&& rList ) :
+ SrchAttrItemList(std::move(rList))
+{
+ for ( size_t i = 0; i < size(); ++i )
+ if ( !IsInvalidItem( (*this)[i].pItem ) )
+ (*this)[i].pItem = (*this)[i].pItem->Clone();
+}
+
+SearchAttrItemList::SearchAttrItemList( const SearchAttrItemList& rList ) :
+ SrchAttrItemList(rList)
+{
+ for ( size_t i = 0; i < size(); ++i )
+ if ( !IsInvalidItem( (*this)[i].pItem ) )
+ (*this)[i].pItem = (*this)[i].pItem->Clone();
+}
+
+SearchAttrItemList::~SearchAttrItemList()
+{
+ Clear();
+}
+
+void SearchAttrItemList::Put( const SfxItemSet& rSet )
+{
+ if ( !rSet.Count() )
+ return;
+
+ SfxItemPool* pPool = rSet.GetPool();
+ SfxItemIter aIter( rSet );
+ SearchAttrItem aItem;
+ const SfxPoolItem* pItem = aIter.GetCurItem();
+ sal_uInt16 nWhich;
+
+ do
+ {
+ // only test that it is available?
+ if( IsInvalidItem( pItem ) )
+ {
+ nWhich = rSet.GetWhichByPos( aIter.GetCurPos() );
+ aItem.pItem = const_cast<SfxPoolItem*>(pItem);
+ }
+ else
+ {
+ nWhich = pItem->Which();
+ aItem.pItem = pItem->Clone();
+ }
+
+ aItem.nSlot = pPool->GetSlotId( nWhich );
+ Insert( aItem );
+
+ pItem = aIter.NextItem();
+ } while (pItem);
+}
+
+
+SfxItemSet& SearchAttrItemList::Get( SfxItemSet& rSet )
+{
+ SfxItemPool* pPool = rSet.GetPool();
+
+ for ( size_t i = 0; i < size(); ++i )
+ if ( IsInvalidItem( (*this)[i].pItem ) )
+ rSet.InvalidateItem( pPool->GetWhich( (*this)[i].nSlot ) );
+ else
+ rSet.Put( *(*this)[i].pItem );
+ return rSet;
+}
+
+
+void SearchAttrItemList::Clear()
+{
+ for ( size_t i = 0; i < size(); ++i )
+ if ( !IsInvalidItem( (*this)[i].pItem ) )
+ delete (*this)[i].pItem;
+ SrchAttrItemList::clear();
+}
+
+
+// Deletes the pointer to the items
+void SearchAttrItemList::Remove(size_t nPos)
+{
+ size_t nLen = 1;
+ if ( nPos + nLen > size() )
+ nLen = size() - nPos;
+
+ for ( size_t i = nPos; i < nPos + nLen; ++i )
+ if ( !IsInvalidItem( (*this)[i].pItem ) )
+ delete (*this)[i].pItem;
+
+ SrchAttrItemList::erase( begin() + nPos, begin() + nPos + nLen );
+}
+
+SvxSearchDialog::SvxSearchDialog(weld::Window* pParent, SfxChildWindow* pChildWin, SfxBindings& rBind)
+ : SfxModelessDialogController(&rBind, pChildWin, pParent,
+ IS_MOBILE ? OUString("svx/ui/findreplacedialog-mobile.ui") : OUString("svx/ui/findreplacedialog.ui"),
+ "FindReplaceDialog")
+ , rBindings(rBind)
+ , m_aPresentIdle("Bring SvxSearchDialog to Foreground")
+ , bWriter(false)
+ , bSearch(true)
+ , bFormat(false)
+ , bReplaceBackwards(false)
+ , nOptions(SearchOptionFlags::ALL)
+ , bSet(false)
+ , bConstruct(true)
+ , nModifyFlag(ModifyFlags::NONE)
+ , pReplaceList(new SearchAttrItemList)
+ , nTransliterationFlags(TransliterationFlags::NONE)
+ , m_xSearchFrame(m_xBuilder->weld_frame("searchframe"))
+ , m_xSearchLB(m_xBuilder->weld_combo_box("searchterm"))
+ , m_xSearchTmplLB(m_xBuilder->weld_combo_box("searchlist"))
+ , m_xSearchAttrText(m_xBuilder->weld_label("searchdesc"))
+ , m_xSearchLabel(m_xBuilder->weld_label("searchlabel"))
+ , m_xReplaceFrame(m_xBuilder->weld_frame("replaceframe"))
+ , m_xReplaceLB(m_xBuilder->weld_combo_box("replaceterm"))
+ , m_xReplaceTmplLB(m_xBuilder->weld_combo_box("replacelist"))
+ , m_xReplaceAttrText(m_xBuilder->weld_label("replacedesc"))
+ , m_xSearchBtn(m_xBuilder->weld_button("search"))
+ , m_xBackSearchBtn(m_xBuilder->weld_button("backsearch"))
+ , m_xSearchAllBtn(m_xBuilder->weld_button("searchall"))
+ , m_xReplaceBtn(m_xBuilder->weld_button("replace"))
+ , m_xReplaceAllBtn(m_xBuilder->weld_button("replaceall"))
+ , m_xComponentFrame(m_xBuilder->weld_frame("componentframe"))
+ , m_xSearchComponent1PB(m_xBuilder->weld_button("component1"))
+ , m_xSearchComponent2PB(m_xBuilder->weld_button("component2"))
+ , m_xMatchCaseCB(m_xBuilder->weld_check_button("matchcase"))
+ , m_xSearchFormattedCB(m_xBuilder->weld_check_button("searchformatted"))
+ , m_xWordBtn(m_xBuilder->weld_check_button("wholewords"))
+ , m_xCloseBtn(m_xBuilder->weld_button("close"))
+ , m_xIncludeDiacritics(m_xBuilder->weld_check_button("includediacritics"))
+ , m_xIncludeKashida(m_xBuilder->weld_check_button("includekashida"))
+ , m_xOtherOptionsExpander(m_xBuilder->weld_expander("OptionsExpander"))
+ , m_xSelectionBtn(m_xBuilder->weld_check_button("selection"))
+ , m_xRegExpBtn(m_xBuilder->weld_check_button("regexp"))
+ , m_xWildcardBtn(m_xBuilder->weld_check_button("wildcard"))
+ , m_xSimilarityBox(m_xBuilder->weld_check_button("similarity"))
+ , m_xSimilarityBtn(m_xBuilder->weld_button("similaritybtn"))
+ , m_xLayoutBtn(m_xBuilder->weld_check_button("layout"))
+ , m_xNotesBtn(m_xBuilder->weld_check_button("notes"))
+ , m_xJapMatchFullHalfWidthCB(m_xBuilder->weld_check_button("matchcharwidth"))
+ , m_xJapOptionsCB(m_xBuilder->weld_check_button("soundslike"))
+ , m_xReplaceBackwardsCB(m_xBuilder->weld_check_button("replace_backwards"))
+ , m_xJapOptionsBtn(m_xBuilder->weld_button("soundslikebtn"))
+ , m_xAttributeBtn(m_xBuilder->weld_button("attributes"))
+ , m_xFormatBtn(m_xBuilder->weld_button("format"))
+ , m_xNoFormatBtn(m_xBuilder->weld_button("noformat"))
+ , m_xCalcGrid(m_xBuilder->weld_widget("calcgrid"))
+ , m_xCalcSearchInFT(m_xBuilder->weld_label("searchinlabel"))
+ , m_xCalcSearchInLB(m_xBuilder->weld_combo_box("calcsearchin"))
+ , m_xCalcSearchDirFT(m_xBuilder->weld_label("searchdir"))
+ , m_xRowsBtn(m_xBuilder->weld_radio_button("rows"))
+ , m_xColumnsBtn(m_xBuilder->weld_radio_button("cols"))
+ , m_xAllSheetsCB(m_xBuilder->weld_check_button("allsheets"))
+ , m_xCalcStrFT(m_xBuilder->weld_label("entirecells"))
+{
+ m_aPresentIdle.SetTimeout(50);
+ m_aPresentIdle.SetInvokeHandler(LINK(this, SvxSearchDialog, PresentTimeoutHdl_Impl));
+
+ m_xSearchTmplLB->make_sorted();
+ m_xSearchAttrText->hide();
+ m_xSearchLabel->show();
+
+ m_xReplaceTmplLB->make_sorted();
+ m_xReplaceAttrText->hide();
+
+ aCalcStr = m_xCalcStrFT->get_label();
+
+ // m_xSimilarityBtn->set_height_request(m_xSimilarityBox->get_preferred_size().Height());
+ // m_xJapOptionsBtn->set_height_request(m_xJapOptionsCB->get_preferred_size().Height());
+
+ //tdf#122322
+ nRememberSize = officecfg::Office::Common::Misc::FindReplaceRememberedSearches::get();
+ if (nRememberSize<1)
+ nRememberSize = 1; //0 crashes with no results found
+
+ auto nTermWidth = m_xSearchLB->get_approximate_digit_width() * 28;
+ m_xSearchLB->set_size_request(nTermWidth, -1);
+ m_xSearchTmplLB->set_size_request(nTermWidth, -1);
+ m_xReplaceLB->set_size_request(nTermWidth, -1);
+ m_xReplaceTmplLB->set_size_request(nTermWidth, -1);
+
+ Construct_Impl();
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, PresentTimeoutHdl_Impl, Timer*, void)
+{
+ getDialog()->present();
+}
+
+void SvxSearchDialog::Present()
+{
+ PresentTimeoutHdl_Impl(nullptr);
+ // tdf#133807 try again in a short timeout
+ m_aPresentIdle.Start();
+}
+
+void SvxSearchDialog::ChildWinDispose()
+{
+ rBindings.EnterRegistrations();
+ pSearchController.reset();
+ pOptionsController.reset();
+ pFamilyController.reset();
+ rBindings.LeaveRegistrations();
+ SfxModelessDialogController::ChildWinDispose();
+}
+
+SvxSearchDialog::~SvxSearchDialog()
+{
+ m_aPresentIdle.Stop();
+ pSearchItem.reset();
+ pImpl.reset();
+}
+
+void SvxSearchDialog::Construct_Impl()
+{
+ pImpl.reset( new SearchDlg_Impl() );
+ pImpl->aSelectionTimer.SetTimeout( 500 );
+ pImpl->aSelectionTimer.SetInvokeHandler(
+ LINK( this, SvxSearchDialog, TimeoutHdl_Impl ) );
+ EnableControls_Impl( SearchOptionFlags::NONE );
+
+ // Store old Text from m_xWordBtn
+ aCalcStr += "#";
+ aCalcStr += m_xWordBtn->get_label();
+
+ aLayoutStr = SvxResId( RID_SVXSTR_SEARCH_STYLES );
+ aLayoutWriterStr = SvxResId( RID_SVXSTR_WRITER_STYLES );
+ aLayoutCalcStr = SvxResId( RID_SVXSTR_CALC_STYLES );
+ aStylesStr = m_xLayoutBtn->get_label();
+
+ // Get stored search-strings from the application
+ ListToStrArr_Impl(SID_SEARCHDLG_SEARCHSTRINGS,
+ aSearchStrings, *m_xSearchLB, nRememberSize);
+ ListToStrArr_Impl(SID_SEARCHDLG_REPLACESTRINGS,
+ aReplaceStrings, *m_xReplaceLB, nRememberSize);
+
+ InitControls_Impl();
+
+ // Get attribute sets only once in constructor()
+ const SfxPoolItem* ppArgs[] = { pSearchItem.get(), nullptr };
+ const SvxSetItem* pSrchSetItem =
+ static_cast<const SvxSetItem*>( rBindings.GetDispatcher()->Execute( FID_SEARCH_SEARCHSET, SfxCallMode::SLOT, ppArgs ) );
+
+ if ( pSrchSetItem )
+ InitAttrList_Impl( &pSrchSetItem->GetItemSet(), nullptr );
+
+ const SvxSetItem* pReplSetItem =
+ static_cast<const SvxSetItem*>( rBindings.GetDispatcher()->Execute( FID_SEARCH_REPLACESET, SfxCallMode::SLOT, ppArgs ) );
+
+ if ( pReplSetItem )
+ InitAttrList_Impl( nullptr, &pReplSetItem->GetItemSet() );
+
+ // Create controller and update at once
+ rBindings.EnterRegistrations();
+ pSearchController.reset(
+ new SvxSearchController( SID_SEARCH_ITEM, rBindings, *this ) );
+ pOptionsController.reset(
+ new SvxSearchController( SID_SEARCH_OPTIONS, rBindings, *this ) );
+ rBindings.LeaveRegistrations();
+ rBindings.GetDispatcher()->Execute( FID_SEARCH_ON, SfxCallMode::SLOT, ppArgs );
+ pImpl->aSelectionTimer.Start();
+
+
+ if(!SvtCJKOptions::IsJapaneseFindEnabled())
+ {
+ m_xJapOptionsCB->set_active( false );
+ m_xJapOptionsCB->hide();
+ m_xJapOptionsBtn->hide();
+ }
+ if(!SvtCJKOptions::IsCJKFontEnabled())
+ {
+ m_xJapMatchFullHalfWidthCB->hide();
+ }
+ SvtCTLOptions aCTLOptions;
+ // Do not disable and hide the m_xIncludeDiacritics button.
+ // Include Diacritics == Not Ignore Diacritics => A does not match A-Umlaut (Diaeresis).
+ // Confusingly these have negated names (following the UI) but the actual
+ // transliteration is to *ignore* diacritics if "included" (sensitive) is
+ // _not_ checked.
+ if(!aCTLOptions.IsCTLFontEnabled())
+ {
+ m_xIncludeDiacritics->set_active( true );
+ m_xIncludeKashida->set_active( true );
+ m_xIncludeKashida->hide();
+ }
+ //component extension - show component search buttons if the commands
+ // vnd.sun.star::SearchViaComponent1 and 2 are supported
+ const uno::Reference< frame::XFrame >xFrame = rBindings.GetActiveFrame();
+ const uno::Reference< frame::XDispatchProvider > xDispatchProv(xFrame, uno::UNO_QUERY);
+
+ bool bSearchComponent1 = false;
+ bool bSearchComponent2 = false;
+ if(xDispatchProv.is())
+ {
+ OUString sTarget("_self");
+ pImpl->xCommand1Dispatch = xDispatchProv->queryDispatch(pImpl->aCommand1URL, sTarget, 0);
+ if (pImpl->xCommand1Dispatch.is())
+ bSearchComponent1 = true;
+ pImpl->xCommand2Dispatch = xDispatchProv->queryDispatch(pImpl->aCommand2URL, sTarget, 0);
+ if (pImpl->xCommand2Dispatch.is())
+ bSearchComponent2 = true;
+ }
+
+ if( !(bSearchComponent1 || bSearchComponent2) )
+ return;
+
+ try
+ {
+ uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider =
+ configuration::theDefaultProvider::get( comphelper::getProcessComponentContext() );
+ uno::Sequence< uno::Any > aArgs {
+ Any(OUString( "/org.openoffice.Office.Common/SearchOptions/")) };
+
+ uno::Reference< uno::XInterface > xIFace = xConfigurationProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationUpdateAccess",
+ aArgs);
+ uno::Reference< container::XNameAccess> xDirectAccess(xIFace, uno::UNO_QUERY);
+ if(xDirectAccess.is())
+ {
+ OUString sTemp;
+ uno::Any aRet = xDirectAccess->getByName("ComponentSearchGroupLabel");
+ aRet >>= sTemp;
+ m_xComponentFrame->set_label(sTemp);
+ aRet = xDirectAccess->getByName("ComponentSearchCommandLabel1");
+ aRet >>= sTemp;
+ m_xSearchComponent1PB->set_label( sTemp );
+ aRet = xDirectAccess->getByName("ComponentSearchCommandLabel2");
+ aRet >>= sTemp;
+ m_xSearchComponent2PB->set_label( sTemp );
+ }
+ }
+ catch(uno::Exception&){}
+
+ if(!m_xSearchComponent1PB->get_label().isEmpty() && bSearchComponent1 )
+ {
+ m_xComponentFrame->show();
+ m_xSearchComponent1PB->show();
+ }
+ if( !m_xSearchComponent2PB->get_label().isEmpty() )
+ {
+ m_xComponentFrame->show();
+ m_xSearchComponent2PB->show();
+ }
+}
+
+void SvxSearchDialog::Close()
+{
+ // remember strings
+ if (!aSearchStrings.empty())
+ StrArrToList_Impl( SID_SEARCHDLG_SEARCHSTRINGS, aSearchStrings );
+
+ if (!aReplaceStrings.empty())
+ StrArrToList_Impl( SID_SEARCHDLG_REPLACESTRINGS, aReplaceStrings );
+
+ // save settings to configuration
+ SvtSearchOptions aOpt;
+ aOpt.SetWholeWordsOnly ( m_xWordBtn->get_active() );
+ aOpt.SetBackwards ( m_xReplaceBackwardsCB->get_active() );
+ aOpt.SetUseRegularExpression ( m_xRegExpBtn->get_active() );
+ aOpt.SetUseWildcard ( m_xWildcardBtn->get_active() );
+ aOpt.SetSearchForStyles ( m_xLayoutBtn->get_active() );
+ aOpt.SetSimilaritySearch ( m_xSimilarityBox->get_active() );
+ aOpt.SetUseAsianOptions ( m_xJapOptionsCB->get_active() );
+ aOpt.SetNotes ( m_xNotesBtn->get_active() );
+ aOpt.SetIgnoreDiacritics_CTL ( !m_xIncludeDiacritics->get_active() );
+ aOpt.SetIgnoreKashida_CTL ( !m_xIncludeKashida->get_active() );
+ aOpt.SetSearchFormatted ( m_xSearchFormattedCB->get_active() );
+ aOpt.Commit();
+
+ if (IsClosing())
+ return;
+
+ const SfxPoolItem* ppArgs[] = { pSearchItem.get(), nullptr };
+ rBindings.GetDispatcher()->Execute( FID_SEARCH_OFF, SfxCallMode::SLOT, ppArgs );
+ rBindings.Invalidate(SID_SEARCH_DLG);
+
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (pViewFrame)
+ pViewFrame->ToggleChildWindow(SID_SEARCH_DLG);
+}
+
+TransliterationFlags SvxSearchDialog::GetTransliterationFlags() const
+{
+ if (!m_xMatchCaseCB->get_active())
+ nTransliterationFlags |= TransliterationFlags::IGNORE_CASE;
+ else
+ nTransliterationFlags &= ~TransliterationFlags::IGNORE_CASE;
+ if ( !m_xJapMatchFullHalfWidthCB->get_active())
+ nTransliterationFlags |= TransliterationFlags::IGNORE_WIDTH;
+ else
+ nTransliterationFlags &= ~TransliterationFlags::IGNORE_WIDTH;
+ return nTransliterationFlags;
+}
+
+void SvxSearchDialog::SetSaveToModule(bool b)
+{
+ pImpl->bSaveToModule = b;
+}
+
+void SvxSearchDialog::SetSearchLabel(const OUString& rStr)
+{
+ m_xSearchLabel->set_label(rStr);
+
+ if (rStr == SvxResId(RID_SVXSTR_SEARCH_NOT_FOUND))
+ m_xSearchLB->set_entry_message_type(weld::EntryMessageType::Error);
+}
+
+void SvxSearchDialog::ApplyTransliterationFlags_Impl( TransliterationFlags nSettings )
+{
+ nTransliterationFlags = nSettings;
+ bool bVal(nSettings & TransliterationFlags::IGNORE_CASE);
+ m_xMatchCaseCB->set_active( !bVal );
+ bVal = bool(nSettings & TransliterationFlags::IGNORE_WIDTH);
+ m_xJapMatchFullHalfWidthCB->set_active( !bVal );
+}
+
+
+bool SvxSearchDialog::IsOtherOptionsExpanded() const
+{
+ return m_xReplaceBackwardsCB->get_active() ||
+ m_xSelectionBtn->get_active() ||
+ m_xRegExpBtn->get_active() ||
+ m_xLayoutBtn->get_active() ||
+ m_xSimilarityBox->get_active() ||
+ m_xJapMatchFullHalfWidthCB->get_active() ||
+ m_xJapOptionsCB->get_active() ||
+ m_xWildcardBtn->get_active() ||
+ m_xNotesBtn->get_active() ||
+ m_xIncludeKashida->get_active() ||
+ !m_xIncludeDiacritics->get_active();//tdf#138173
+}
+
+void SvxSearchDialog::Activate()
+{
+ // apply possible transliteration changes of the SvxSearchItem member
+ if (pSearchItem)
+ {
+ m_xMatchCaseCB->set_active( pSearchItem->GetExact() );
+ m_xJapMatchFullHalfWidthCB->set_active( !pSearchItem->IsMatchFullHalfWidthForms() );
+ }
+
+ SfxModelessDialogController::Activate();
+}
+
+void SvxSearchDialog::InitControls_Impl()
+{
+ // CaseSensitives AutoComplete
+ m_xSearchLB->set_entry_completion( true, true );
+ m_xSearchLB->show();
+ m_xReplaceLB->set_entry_completion( true, true );
+ m_xReplaceLB->show();
+
+ m_xFormatBtn->set_sensitive(false);
+ m_xAttributeBtn->set_sensitive(false);
+
+ m_xSearchLB->connect_changed( LINK( this, SvxSearchDialog, ModifyHdl_Impl ) );
+ m_xReplaceLB->connect_changed( LINK( this, SvxSearchDialog, ModifyHdl_Impl ) );
+
+ Link<weld::Widget&,void> aLink = LINK( this, SvxSearchDialog, FocusHdl_Impl );
+ m_xSearchLB->connect_focus_in( aLink );
+ m_xReplaceLB->connect_focus_in( aLink );
+
+ aLink = LINK( this, SvxSearchDialog, LoseFocusHdl_Impl );
+ m_xSearchLB->connect_focus_out( aLink );
+ m_xReplaceLB->connect_focus_out( aLink );
+
+ m_xSearchTmplLB->connect_focus_out( aLink );
+ m_xReplaceTmplLB->connect_focus_out( aLink );
+
+ Link<weld::Button&,void> aLink2 = LINK( this, SvxSearchDialog, CommandHdl_Impl );
+ m_xSearchBtn->connect_clicked( aLink2 );
+ m_xBackSearchBtn->connect_clicked( aLink2 );
+ m_xSearchAllBtn->connect_clicked( aLink2 );
+ m_xReplaceBtn->connect_clicked( aLink2 );
+ m_xReplaceAllBtn->connect_clicked( aLink2 );
+ m_xCloseBtn->connect_clicked( aLink2 );
+ m_xSimilarityBtn->connect_clicked( aLink2 );
+ m_xJapOptionsBtn->connect_clicked( aLink2 );
+ m_xSearchComponent1PB->connect_clicked( aLink2 );
+ m_xSearchComponent2PB->connect_clicked( aLink2 );
+
+ Link<weld::Toggleable&,void> aLink3 = LINK( this, SvxSearchDialog, FlagHdl_Impl );
+ m_xReplaceBackwardsCB->connect_toggled( aLink3 );
+ m_xWordBtn->connect_toggled( aLink3 );
+ m_xSelectionBtn->connect_toggled( aLink3 );
+ m_xMatchCaseCB->connect_toggled( aLink3 );
+ m_xRegExpBtn->connect_toggled( aLink3 );
+ m_xWildcardBtn->connect_toggled( aLink3 );
+ m_xNotesBtn->connect_toggled( aLink3 );
+ m_xSimilarityBox->connect_toggled( aLink3 );
+ m_xJapOptionsCB->connect_toggled( aLink3 );
+ m_xJapMatchFullHalfWidthCB->connect_toggled( aLink3 );
+ m_xIncludeDiacritics->connect_toggled( aLink3 );
+ m_xIncludeKashida->connect_toggled( aLink3 );
+ m_xLayoutBtn->connect_toggled( LINK( this, SvxSearchDialog, TemplateHdl_Impl ) );
+ m_xFormatBtn->connect_clicked( LINK( this, SvxSearchDialog, FormatHdl_Impl ) );
+ m_xNoFormatBtn->connect_clicked(
+ LINK( this, SvxSearchDialog, NoFormatHdl_Impl ) );
+ m_xAttributeBtn->connect_clicked(
+ LINK( this, SvxSearchDialog, AttributeHdl_Impl ) );
+}
+
+namespace
+{
+ SvtModuleOptions::EFactory getModule(SfxBindings const & rBindings)
+ {
+ SvtModuleOptions::EFactory eFactory(SvtModuleOptions::EFactory::UNKNOWN_FACTORY);
+ try
+ {
+ const uno::Reference< frame::XFrame > xFrame =
+ rBindings.GetActiveFrame();
+ uno::Reference< frame::XModuleManager2 > xModuleManager(
+ frame::ModuleManager::create(::comphelper::getProcessComponentContext()));
+
+ OUString aModuleIdentifier = xModuleManager->identify( xFrame );
+ eFactory = SvtModuleOptions::ClassifyFactoryByServiceName(aModuleIdentifier);
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ return eFactory;
+ }
+}
+
+void SvxSearchDialog::ShowOptionalControls_Impl()
+{
+ DBG_ASSERT( pSearchItem, "no search item" );
+
+ SvtCTLOptions aCTLOptions;
+ SvtModuleOptions::EFactory eFactory = getModule(rBindings);
+ bool bDrawApp = eFactory == SvtModuleOptions::EFactory::DRAW;
+ bool bWriterApp =
+ eFactory == SvtModuleOptions::EFactory::WRITER ||
+ eFactory == SvtModuleOptions::EFactory::WRITERWEB ||
+ eFactory == SvtModuleOptions::EFactory::WRITERGLOBAL;
+ bool bCalcApp = eFactory == SvtModuleOptions::EFactory::CALC;
+
+ m_xLayoutBtn->set_visible(!bDrawApp);
+ m_xNotesBtn->set_visible(bWriterApp);
+ m_xRegExpBtn->set_visible(!bDrawApp);
+ m_xWildcardBtn->set_visible(bCalcApp); /* TODO:WILDCARD enable for other apps if hey handle it */
+ m_xReplaceBackwardsCB->show();
+ m_xSimilarityBox->show();
+ m_xSimilarityBtn->show();
+ m_xSelectionBtn->show();
+ m_xIncludeDiacritics->show();
+ m_xIncludeKashida->set_visible(aCTLOptions.IsCTLFontEnabled());
+ m_xJapMatchFullHalfWidthCB->set_visible(SvtCJKOptions::IsCJKFontEnabled());
+ m_xJapOptionsCB->set_visible(SvtCJKOptions::IsJapaneseFindEnabled());
+ m_xJapOptionsBtn->set_visible(SvtCJKOptions::IsJapaneseFindEnabled());
+
+ if (bWriter)
+ {
+ m_xAttributeBtn->show();
+ m_xFormatBtn->show();
+ m_xNoFormatBtn->show();
+ }
+
+ if (bCalcApp)
+ {
+ m_xCalcSearchInFT->show();
+ m_xCalcSearchInLB->show();
+ m_xCalcSearchDirFT->show();
+ m_xRowsBtn->show();
+ m_xColumnsBtn->show();
+ m_xAllSheetsCB->show();
+ m_xSearchFormattedCB->show();
+ }
+}
+
+
+namespace {
+
+class ToggleSaveToModule
+{
+public:
+ ToggleSaveToModule(SvxSearchDialog& rDialog, bool bValue) :
+ mrDialog(rDialog), mbValue(bValue)
+ {
+ mrDialog.SetSaveToModule(mbValue);
+ }
+
+ ~ToggleSaveToModule()
+ {
+ mrDialog.SetSaveToModule(!mbValue);
+ }
+private:
+ SvxSearchDialog& mrDialog;
+ bool mbValue;
+};
+
+}
+
+void SvxSearchDialog::Init_Impl( bool bSearchPattern )
+{
+ DBG_ASSERT( pSearchItem, "SearchItem == 0" );
+
+ // We don't want to save any intermediate state to the module while the
+ // dialog is being initialized.
+ ToggleSaveToModule aNoModuleSave(*this, false);
+ SvtSearchOptions aOpt;
+
+ bWriter = ( pSearchItem->GetAppFlag() == SvxSearchApp::WRITER );
+
+ if ( !( nModifyFlag & ModifyFlags::Word ) )
+ m_xWordBtn->set_active( pSearchItem->GetWordOnly() );
+ if ( !( nModifyFlag & ModifyFlags::Exact ) )
+ m_xMatchCaseCB->set_active( pSearchItem->GetExact() );
+ if ( !( nModifyFlag & ModifyFlags::Backwards ) )
+ m_xReplaceBackwardsCB->set_active( bReplaceBackwards ); //adjustment to replace backwards
+ if ( !( nModifyFlag & ModifyFlags::Notes ) )
+ m_xNotesBtn->set_active( pSearchItem->GetNotes() );
+ if ( !( nModifyFlag & ModifyFlags::Selection ) )
+ m_xSelectionBtn->set_active( pSearchItem->GetSelection() );
+ if ( !( nModifyFlag & ModifyFlags::Regexp ) )
+ m_xRegExpBtn->set_active( pSearchItem->GetRegExp() );
+ if ( !( nModifyFlag & ModifyFlags::Wildcard ) )
+ m_xWildcardBtn->set_active( pSearchItem->GetWildcard() );
+ if ( !( nModifyFlag & ModifyFlags::Layout ) )
+ m_xLayoutBtn->set_active( pSearchItem->GetPattern() );
+ if (m_xNotesBtn->get_active())
+ m_xLayoutBtn->set_sensitive(false);
+ m_xSimilarityBox->set_active( pSearchItem->IsLevenshtein() );
+ if ( m_xJapOptionsCB->get_visible() )
+ m_xJapOptionsCB->set_active( pSearchItem->IsUseAsianOptions() );
+ m_xIncludeDiacritics->set_active( !aOpt.IsIgnoreDiacritics_CTL() );
+ if ( m_xIncludeKashida->get_visible() )
+ m_xIncludeKashida->set_active( !aOpt.IsIgnoreKashida_CTL() );
+ ApplyTransliterationFlags_Impl( pSearchItem->GetTransliterationFlags() );
+
+ ShowOptionalControls_Impl();
+
+ if ( pSearchItem->GetAppFlag() == SvxSearchApp::CALC )
+ {
+ m_xCalcGrid->show();
+ m_xSearchFormattedCB->set_active( aOpt.IsSearchFormatted() );
+ Link<weld::Toggleable&,void> aLink = LINK( this, SvxSearchDialog, FlagHdl_Impl );
+ m_xCalcSearchInLB->connect_changed( LINK( this, SvxSearchDialog, LBSelectHdl_Impl ) );
+ m_xRowsBtn->connect_toggled( aLink );
+ m_xColumnsBtn->connect_toggled( aLink );
+ m_xAllSheetsCB->connect_toggled( aLink );
+ m_xSearchFormattedCB->connect_toggled( aLink );
+
+ ModifyFlags nModifyFlagCheck;
+ switch ( pSearchItem->GetCellType() )
+ {
+ case SvxSearchCellType::FORMULA:
+ nModifyFlagCheck = ModifyFlags::Formulas;
+ break;
+
+ case SvxSearchCellType::VALUE:
+ nModifyFlagCheck = ModifyFlags::Values;
+ break;
+
+ case SvxSearchCellType::NOTE:
+ nModifyFlagCheck = ModifyFlags::CalcNotes;
+ break;
+
+ default:
+ std::abort(); // cannot happen
+ }
+ if ( !(nModifyFlag & nModifyFlagCheck) )
+ m_xCalcSearchInLB->set_active( static_cast<sal_Int32>(pSearchItem->GetCellType()) );
+
+ m_xWordBtn->set_label( aCalcStr.getToken( 0, '#' ) );
+
+ if ( pSearchItem->GetRowDirection() &&
+ !( nModifyFlag & ModifyFlags::Rows ) )
+ m_xRowsBtn->set_active(true);
+ else if ( !pSearchItem->GetRowDirection() &&
+ !( nModifyFlag & ModifyFlags::Columns ) )
+ m_xColumnsBtn->set_active(true);
+
+ if ( !( nModifyFlag & ModifyFlags::AllTables ) )
+ m_xAllSheetsCB->set_active( pSearchItem->IsAllTables() );
+
+ // only look for formatting in Writer
+ m_xFormatBtn->hide();
+ m_xNoFormatBtn->hide();
+ m_xAttributeBtn->hide();
+ }
+ else
+ {
+ m_xSearchFormattedCB->hide();
+ m_xWordBtn->set_label( aCalcStr.getToken( 1, '#' ) );
+
+ if ( pSearchItem->GetAppFlag() == SvxSearchApp::DRAW )
+ {
+ m_xSearchAllBtn->hide();
+
+ m_xRegExpBtn->hide();
+ m_xWildcardBtn->hide();
+ m_xLayoutBtn->hide();
+
+ // only look for formatting in Writer
+ m_xFormatBtn->hide();
+ m_xNoFormatBtn->hide();
+ m_xAttributeBtn->hide();
+ }
+ else
+ {
+ m_xWildcardBtn->hide(); /* TODO:WILDCARD do not hide for other apps if they handle it */
+
+ if ( !pSearchList )
+ {
+ // Get attribute sets, if it not has been done already
+ const SfxPoolItem* ppArgs[] = { pSearchItem.get(), nullptr };
+ const SvxSetItem* pSrchSetItem =
+ static_cast<const SvxSetItem*>(rBindings.GetDispatcher()->Execute( FID_SEARCH_SEARCHSET, SfxCallMode::SLOT, ppArgs ));
+
+ if ( pSrchSetItem )
+ InitAttrList_Impl( &pSrchSetItem->GetItemSet(), nullptr );
+
+ const SvxSetItem* pReplSetItem =
+ static_cast<const SvxSetItem*>( rBindings.GetDispatcher()->Execute( FID_SEARCH_REPLACESET, SfxCallMode::SLOT, ppArgs ) );
+
+ if ( pReplSetItem )
+ InitAttrList_Impl( nullptr, &pReplSetItem->GetItemSet() );
+ }
+ }
+ }
+
+ // similarity search?
+ if ( !( nModifyFlag & ModifyFlags::Similarity ) )
+ m_xSimilarityBox->set_active( pSearchItem->IsLevenshtein() );
+ bSet = true;
+
+ FlagHdl_Impl(*m_xSimilarityBox);
+ FlagHdl_Impl(*m_xJapOptionsCB);
+
+ bool bDisableSearch = false;
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+
+ if ( pViewShell )
+ {
+ bool bText = !bSearchPattern;
+
+ if ( pViewShell->HasSelection( bText ) )
+ EnableControl_Impl(*m_xSelectionBtn);
+ else
+ {
+ m_xSelectionBtn->set_active( false );
+ m_xSelectionBtn->set_sensitive(false);
+ }
+ }
+
+ // Pattern Search and there were no AttrSets given
+ if ( bSearchPattern )
+ {
+ SfxObjectShell* pShell = SfxObjectShell::Current();
+
+ if ( pShell && pShell->GetStyleSheetPool() )
+ {
+ // Templates designed
+ m_xSearchTmplLB->clear();
+ m_xReplaceTmplLB->clear();
+ SfxStyleSheetBasePool* pStylePool = pShell->GetStyleSheetPool();
+ SfxStyleSheetBase* pBase = pStylePool->First(pSearchItem->GetFamily());
+
+ while ( pBase )
+ {
+ if ( pBase->IsUsed() )
+ m_xSearchTmplLB->append_text( pBase->GetName() );
+ m_xReplaceTmplLB->append_text( pBase->GetName() );
+ pBase = pStylePool->Next();
+ }
+ m_xSearchTmplLB->set_active_text( pSearchItem->GetSearchString() );
+ m_xReplaceTmplLB->set_active_text( pSearchItem->GetReplaceString() );
+
+ }
+ m_xSearchTmplLB->show();
+
+ if ( bConstruct )
+ // Grab focus only after creating
+ m_xSearchTmplLB->grab_focus();
+ m_xReplaceTmplLB->show();
+ m_xSearchLB->hide();
+ m_xReplaceLB->hide();
+
+ m_xWordBtn->set_sensitive(false);
+ m_xRegExpBtn->set_sensitive(false);
+ m_xWildcardBtn->set_sensitive(false);
+ m_xMatchCaseCB->set_sensitive(false);
+
+ bDisableSearch = !m_xSearchTmplLB->get_count();
+ }
+ else
+ {
+ bool bSetSearch = !( nModifyFlag & ModifyFlags::Search );
+ bool bSetReplace = !( nModifyFlag & ModifyFlags::Replace );
+
+ if ( !(pSearchItem->GetSearchString().isEmpty()) && bSetSearch )
+ m_xSearchLB->set_entry_text( pSearchItem->GetSearchString() );
+ else if (!aSearchStrings.empty())
+ {
+ bool bAttributes =
+ ( ( pSearchList && pSearchList->Count() ) ||
+ ( pReplaceList && pReplaceList->Count() ) );
+
+ if ( bSetSearch && !bAttributes )
+ m_xSearchLB->set_entry_text(aSearchStrings[0]);
+
+ OUString aReplaceTxt = pSearchItem->GetReplaceString();
+
+ if (!aReplaceStrings.empty())
+ aReplaceTxt = aReplaceStrings[0];
+
+ if ( bSetReplace && !bAttributes )
+ m_xReplaceLB->set_entry_text( aReplaceTxt );
+ }
+ m_xSearchLB->show();
+
+ if ( bConstruct )
+ // Grab focus only after creating
+ m_xSearchLB->grab_focus();
+ m_xReplaceLB->show();
+ m_xSearchTmplLB->hide();
+ m_xReplaceTmplLB->hide();
+
+ EnableControl_Impl(*m_xRegExpBtn);
+ EnableControl_Impl(*m_xWildcardBtn);
+ EnableControl_Impl(*m_xMatchCaseCB);
+
+ if ( m_xRegExpBtn->get_active() )
+ m_xWordBtn->set_sensitive(false);
+ else
+ EnableControl_Impl(*m_xWordBtn);
+
+ bDisableSearch = m_xSearchLB->get_active_text().isEmpty() &&
+ m_xSearchAttrText->get_label().isEmpty();
+ }
+ FocusHdl_Impl(*m_xSearchLB);
+
+ if ( bDisableSearch )
+ {
+ m_xSearchBtn->set_sensitive(false);
+ m_xBackSearchBtn->set_sensitive(false);
+ m_xSearchAllBtn->set_sensitive(false);
+ m_xReplaceBtn->set_sensitive(false);
+ m_xReplaceAllBtn->set_sensitive(false);
+ m_xComponentFrame->set_sensitive(false);
+ }
+ else
+ {
+ EnableControl_Impl(*m_xSearchBtn);
+ EnableControl_Impl(*m_xBackSearchBtn);
+ EnableControl_Impl(*m_xReplaceBtn);
+ if (!bWriter || !m_xNotesBtn->get_active())
+ {
+ EnableControl_Impl(*m_xSearchAllBtn);
+ EnableControl_Impl(*m_xReplaceAllBtn);
+ }
+ if (bWriter && pSearchItem->GetNotes())
+ {
+ m_xSearchAllBtn->set_sensitive(false);
+ m_xReplaceAllBtn->set_sensitive(false);
+ }
+ }
+
+ if (!m_xSearchAttrText->get_label().isEmpty())
+ EnableControl_Impl(*m_xNoFormatBtn);
+ else
+ m_xNoFormatBtn->set_sensitive(false);
+
+ if ( !pSearchList )
+ {
+ m_xAttributeBtn->set_sensitive(false);
+ m_xFormatBtn->set_sensitive(false);
+ }
+
+ if ( m_xLayoutBtn->get_active() )
+ {
+ pImpl->bSaveToModule = false;
+ TemplateHdl_Impl(*m_xLayoutBtn);
+ pImpl->bSaveToModule = true;
+ }
+}
+
+
+void SvxSearchDialog::InitAttrList_Impl( const SfxItemSet* pSSet,
+ const SfxItemSet* pRSet )
+{
+ if ( !pSSet && !pRSet )
+ return;
+
+ if ( pImpl->pRanges.empty() && pSSet )
+ pImpl->pRanges = pSSet->GetRanges();
+
+ bool bSetOptimalLayoutSize = false;
+
+ // See to it that are the texts of the attributes are correct
+ OUString aDesc;
+
+ if ( pSSet )
+ {
+ pSearchList.reset(new SearchAttrItemList);
+
+ if ( pSSet->Count() )
+ {
+ pSearchList->Put( *pSSet );
+
+ m_xSearchAttrText->set_label( BuildAttrText_Impl( aDesc, true ) );
+
+ if ( !aDesc.isEmpty() )
+ {
+ if (!m_xSearchAttrText->get_visible())
+ {
+ m_xSearchAttrText->show();
+ bSetOptimalLayoutSize = true;
+ }
+ bFormat |= true;
+ }
+ }
+ }
+
+ if ( pRSet )
+ {
+ pReplaceList.reset(new SearchAttrItemList);
+
+ if ( pRSet->Count() )
+ {
+ pReplaceList->Put( *pRSet );
+
+ m_xReplaceAttrText->set_label( BuildAttrText_Impl( aDesc, false ) );
+
+ if ( !aDesc.isEmpty() )
+ {
+ if (!m_xReplaceAttrText->get_visible())
+ {
+ m_xReplaceAttrText->show();
+ bSetOptimalLayoutSize = true;
+ }
+ bFormat |= true;
+ }
+ }
+ }
+
+ if (bSetOptimalLayoutSize)
+ m_xDialog->resize_to_request();
+}
+
+IMPL_LINK( SvxSearchDialog, LBSelectHdl_Impl, weld::ComboBox&, rCtrl, void )
+{
+ ClickHdl_Impl(&rCtrl);
+}
+
+IMPL_LINK( SvxSearchDialog, FlagHdl_Impl, weld::Toggleable&, rCtrl, void )
+{
+ ClickHdl_Impl(&rCtrl);
+}
+
+void SvxSearchDialog::ClickHdl_Impl(const weld::Widget* pCtrl)
+{
+ if ( pCtrl && !bSet )
+ SetModifyFlag_Impl(pCtrl);
+ else
+ bSet = false;
+
+ if (pCtrl == m_xSimilarityBox.get())
+ {
+ bool bIsChecked = m_xSimilarityBox->get_active();
+
+ if ( bIsChecked )
+ {
+ m_xSimilarityBtn->set_sensitive(true);
+ m_xRegExpBtn->set_active( false );
+ m_xRegExpBtn->set_sensitive(false);
+ m_xWildcardBtn->set_active( false );
+ m_xWildcardBtn->set_sensitive(false);
+ EnableControl_Impl(*m_xWordBtn);
+
+ if ( m_xLayoutBtn->get_active() )
+ {
+ EnableControl_Impl(*m_xMatchCaseCB);
+ m_xLayoutBtn->set_active( false );
+ }
+ m_xRegExpBtn->set_sensitive(false);
+ m_xWildcardBtn->set_sensitive(false);
+ m_xLayoutBtn->set_sensitive(false);
+ m_xFormatBtn->set_sensitive(false);
+ m_xNoFormatBtn->set_sensitive(false);
+ m_xAttributeBtn->set_sensitive(false);
+ }
+ else
+ {
+ EnableControl_Impl(*m_xRegExpBtn);
+ EnableControl_Impl(*m_xWildcardBtn);
+ if (!m_xNotesBtn->get_active())
+ EnableControl_Impl(*m_xLayoutBtn);
+ EnableControl_Impl(*m_xFormatBtn);
+ EnableControl_Impl(*m_xAttributeBtn);
+ m_xSimilarityBtn->set_sensitive(false);
+ }
+ pSearchItem->SetLevenshtein( bIsChecked );
+ }
+ else if (pCtrl == m_xNotesBtn.get())
+ {
+ if (m_xNotesBtn->get_active())
+ {
+ m_xLayoutBtn->set_sensitive(false);
+ m_xSearchAllBtn->set_sensitive(false);
+ m_xReplaceAllBtn->set_sensitive(false);
+ }
+ else
+ {
+ EnableControl_Impl(*m_xLayoutBtn);
+ ModifyHdl_Impl(*m_xSearchLB);
+ }
+ }
+ else
+ {
+ if ( m_xLayoutBtn->get_active() && !bFormat )
+ {
+ m_xWordBtn->set_active( false );
+ m_xWordBtn->set_sensitive(false);
+ m_xRegExpBtn->set_active( false );
+ m_xRegExpBtn->set_sensitive(false);
+ m_xWildcardBtn->set_active( false );
+ m_xWildcardBtn->set_sensitive(false);
+ m_xMatchCaseCB->set_active( false );
+ m_xMatchCaseCB->set_sensitive(false);
+ m_xNotesBtn->set_sensitive(false);
+
+ if ( m_xSearchTmplLB->get_count() )
+ {
+ EnableControl_Impl(*m_xSearchBtn);
+ EnableControl_Impl(*m_xBackSearchBtn);
+ EnableControl_Impl(*m_xSearchAllBtn);
+ EnableControl_Impl(*m_xReplaceBtn);
+ EnableControl_Impl(*m_xReplaceAllBtn);
+ }
+ }
+ else
+ {
+ EnableControl_Impl(*m_xRegExpBtn);
+ EnableControl_Impl(*m_xWildcardBtn);
+ EnableControl_Impl(*m_xMatchCaseCB);
+ EnableControl_Impl(*m_xNotesBtn);
+
+ if ( m_xRegExpBtn->get_active() )
+ {
+ m_xWordBtn->set_active( false );
+ m_xWordBtn->set_sensitive(false);
+ m_xWildcardBtn->set_active( false );
+ m_xWildcardBtn->set_sensitive(false);
+ m_xSimilarityBox->set_active( false );
+ m_xSimilarityBox->set_sensitive(false);
+ m_xSimilarityBtn->set_sensitive(false);
+ }
+ else if ( m_xWildcardBtn->get_active() )
+ {
+ m_xRegExpBtn->set_active( false );
+ m_xRegExpBtn->set_sensitive(false);
+ m_xSimilarityBox->set_active( false );
+ m_xSimilarityBox->set_sensitive(false);
+ m_xSimilarityBtn->set_sensitive(false);
+ }
+ else
+ {
+ EnableControl_Impl(*m_xWordBtn);
+ EnableControl_Impl(*m_xSimilarityBox);
+ }
+
+ // Search-string in place? then enable Buttons
+ bSet = true;
+ ModifyHdl_Impl(*m_xSearchLB);
+ }
+ }
+
+ if (pCtrl == m_xAllSheetsCB.get())
+ {
+ bSet = true;
+ ModifyHdl_Impl(*m_xSearchLB);
+ }
+
+ if (pCtrl == m_xJapOptionsCB.get())
+ {
+ bool bEnableJapOpt = m_xJapOptionsCB->get_active();
+ m_xMatchCaseCB->set_sensitive(!bEnableJapOpt );
+ m_xJapMatchFullHalfWidthCB->set_sensitive(!bEnableJapOpt );
+ m_xJapOptionsBtn->set_sensitive( bEnableJapOpt );
+ }
+
+ if ( pImpl->bSaveToModule )
+ SaveToModule_Impl();
+}
+
+IMPL_LINK(SvxSearchDialog, CommandHdl_Impl, weld::Button&, rBtn, void)
+{
+ bool bInclusive = ( m_xLayoutBtn->get_label() == aLayoutStr );
+
+ if ( ( &rBtn == m_xSearchBtn.get() ) ||
+ (&rBtn == m_xBackSearchBtn.get()) ||
+ ( &rBtn == m_xSearchAllBtn.get() )||
+ ( &rBtn == m_xReplaceBtn.get() ) ||
+ ( &rBtn == m_xReplaceAllBtn.get() ) )
+ {
+ if ( m_xLayoutBtn->get_active() && !bInclusive )
+ {
+ pSearchItem->SetSearchString ( m_xSearchTmplLB->get_active_text() );
+ pSearchItem->SetReplaceString( m_xReplaceTmplLB->get_active_text() );
+ }
+ else
+ {
+ pSearchItem->SetSearchString ( m_xSearchLB->get_active_text() );
+ pSearchItem->SetReplaceString( m_xReplaceLB->get_active_text() );
+
+ if ( &rBtn == m_xReplaceBtn.get() )
+ Remember_Impl( m_xReplaceLB->get_active_text(), false );
+ else
+ {
+ Remember_Impl( m_xSearchLB->get_active_text(), true );
+
+ if ( &rBtn == m_xReplaceAllBtn.get() )
+ Remember_Impl( m_xReplaceLB->get_active_text(), false );
+ }
+ }
+
+ pSearchItem->SetRegExp( false );
+ pSearchItem->SetWildcard( false );
+ pSearchItem->SetLevenshtein( false );
+ if (GetCheckBoxValue(*m_xRegExpBtn))
+ pSearchItem->SetRegExp( true );
+ else if (GetCheckBoxValue(*m_xWildcardBtn))
+ pSearchItem->SetWildcard( true );
+ else if (GetCheckBoxValue(*m_xSimilarityBox))
+ pSearchItem->SetLevenshtein( true );
+
+ pSearchItem->SetWordOnly(GetCheckBoxValue(*m_xWordBtn));
+
+ bool bSetBackwards = false;
+ if( &rBtn == m_xBackSearchBtn.get())
+ {
+ bSetBackwards = true;
+ }
+ else if( &rBtn == m_xReplaceBtn.get())
+ {
+ bSetBackwards = GetCheckBoxValue(*m_xReplaceBackwardsCB);
+ bReplaceBackwards = GetCheckBoxValue(*m_xReplaceBackwardsCB);
+ }
+
+ pSearchItem->SetBackward(bSetBackwards);
+
+ pSearchItem->SetNotes(GetCheckBoxValue(*m_xNotesBtn));
+ pSearchItem->SetPattern(GetCheckBoxValue(*m_xLayoutBtn));
+ pSearchItem->SetSelection(GetCheckBoxValue(*m_xSelectionBtn));
+ pSearchItem->SetUseAsianOptions(GetCheckBoxValue(*m_xJapOptionsCB));
+ TransliterationFlags nFlags = GetTransliterationFlags();
+ if( !pSearchItem->IsUseAsianOptions())
+ nFlags &= TransliterationFlags::IGNORE_CASE |
+ TransliterationFlags::IGNORE_WIDTH;
+ if (GetNegatedCheckBoxValue(*m_xIncludeDiacritics))
+ nFlags |= TransliterationFlags::IGNORE_DIACRITICS_CTL;
+ if (GetNegatedCheckBoxValue(*m_xIncludeKashida))
+ nFlags |= TransliterationFlags::IGNORE_KASHIDA_CTL;
+ pSearchItem->SetTransliterationFlags( nFlags );
+
+ if ( !bWriter )
+ {
+ if ( m_xCalcSearchInLB->get_active() != -1)
+ pSearchItem->SetCellType( static_cast<SvxSearchCellType>(m_xCalcSearchInLB->get_active()) );
+
+ pSearchItem->SetRowDirection( m_xRowsBtn->get_active() );
+ pSearchItem->SetAllTables( m_xAllSheetsCB->get_active() );
+ pSearchItem->SetSearchFormatted( m_xSearchFormattedCB->get_active() );
+ }
+
+ if ((&rBtn == m_xSearchBtn.get()) || (&rBtn == m_xBackSearchBtn.get()))
+ pSearchItem->SetCommand( SvxSearchCmd::FIND );
+ else if ( &rBtn == m_xSearchAllBtn.get() )
+ pSearchItem->SetCommand( SvxSearchCmd::FIND_ALL );
+ else if ( &rBtn == m_xReplaceBtn.get() )
+ pSearchItem->SetCommand( SvxSearchCmd::REPLACE );
+ else if ( &rBtn == m_xReplaceAllBtn.get() )
+ pSearchItem->SetCommand( SvxSearchCmd::REPLACE_ALL );
+
+ // when looking for templates, delete format lists
+ if ( !bFormat && pSearchItem->GetPattern() )
+ {
+ if ( pSearchList )
+ pSearchList->Clear();
+
+ if ( pReplaceList )
+ pReplaceList->Clear();
+ }
+ nModifyFlag = ModifyFlags::NONE;
+ const SfxPoolItem* ppArgs[] = { pSearchItem.get(), nullptr };
+ rBindings.ExecuteSynchron( FID_SEARCH_NOW, ppArgs );
+ }
+ else if ( &rBtn == m_xCloseBtn.get() )
+ {
+ if ( !m_xLayoutBtn->get_active() || bInclusive )
+ {
+ OUString aStr( m_xSearchLB->get_active_text() );
+
+ if ( !aStr.isEmpty() )
+ Remember_Impl( aStr, true );
+ aStr = m_xReplaceLB->get_active_text();
+
+ if ( !aStr.isEmpty() )
+ Remember_Impl( aStr, false );
+ }
+ SaveToModule_Impl();
+ Close();
+ }
+ else if (&rBtn == m_xSimilarityBtn.get())
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxSearchSimilarityDialog> pDlg(pFact->CreateSvxSearchSimilarityDialog(m_xDialog.get(),
+ pSearchItem->IsLEVRelaxed(),
+ pSearchItem->GetLEVOther(),
+ pSearchItem->GetLEVShorter(),
+ pSearchItem->GetLEVLonger() ));
+ if ( executeSubDialog(pDlg.get()) == RET_OK )
+ {
+ pSearchItem->SetLEVRelaxed( pDlg->IsRelaxed() );
+ pSearchItem->SetLEVOther( pDlg->GetOther() );
+ pSearchItem->SetLEVShorter( pDlg->GetShorter() );
+ pSearchItem->SetLEVLonger( pDlg->GetLonger() );
+ SaveToModule_Impl();
+ }
+ }
+ else if (&rBtn == m_xJapOptionsBtn.get())
+ {
+ SfxItemSet aSet( SfxGetpApp()->GetPool() );
+ pSearchItem->SetTransliterationFlags( GetTransliterationFlags() );
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxJSearchOptionsDialog> aDlg(pFact->CreateSvxJSearchOptionsDialog(m_xDialog.get(), aSet,
+ pSearchItem->GetTransliterationFlags() ));
+ int nRet = executeSubDialog(aDlg.get());
+ if (RET_OK == nRet) //! true only if FillItemSet of SvxJSearchOptionsPage returns true
+ {
+ TransliterationFlags nFlags = aDlg->GetTransliterationFlags();
+ pSearchItem->SetTransliterationFlags( nFlags );
+ ApplyTransliterationFlags_Impl( nFlags );
+ }
+ }
+ else if (&rBtn == m_xSearchComponent1PB.get() || &rBtn == m_xSearchComponent2PB.get())
+ {
+ uno::Sequence < beans::PropertyValue > aArgs(2);
+ beans::PropertyValue* pArgs = aArgs.getArray();
+ pArgs[0].Name = "SearchString";
+ pArgs[0].Value <<= m_xSearchLB->get_active_text();
+ pArgs[1].Name = "ParentWindow";
+ pArgs[1].Value <<= m_xDialog->GetXWindow();
+ if (&rBtn == m_xSearchComponent1PB.get())
+ {
+ if ( pImpl->xCommand1Dispatch.is() )
+ pImpl->xCommand1Dispatch->dispatch(pImpl->aCommand1URL, aArgs);
+ }
+ else
+ {
+ if ( pImpl->xCommand2Dispatch.is() )
+ pImpl->xCommand2Dispatch->dispatch(pImpl->aCommand2URL, aArgs);
+ }
+ }
+}
+
+
+IMPL_LINK( SvxSearchDialog, ModifyHdl_Impl, weld::ComboBox&, rEd, void )
+{
+ if ( !bSet )
+ SetModifyFlag_Impl( &rEd );
+ else
+ bSet = false;
+
+ // Calc allows searching for empty cells.
+ bool bAllowEmptySearch = (pSearchItem->GetAppFlag() == SvxSearchApp::CALC);
+
+ if (&rEd != m_xSearchLB.get() && &rEd != m_xReplaceLB.get())
+ return;
+
+ sal_Int32 nSrchTxtLen = m_xSearchLB->get_active_text().getLength();
+ sal_Int32 nReplTxtLen = 0;
+ if (bAllowEmptySearch)
+ nReplTxtLen = m_xReplaceLB->get_active_text().getLength();
+ sal_Int32 nAttrTxtLen = m_xSearchAttrText->get_label().getLength();
+
+ if (nSrchTxtLen || nReplTxtLen || nAttrTxtLen)
+ {
+ EnableControl_Impl(*m_xSearchBtn);
+ EnableControl_Impl(*m_xBackSearchBtn);
+ EnableControl_Impl(*m_xReplaceBtn);
+ if (!bWriter || !m_xNotesBtn->get_active())
+ {
+ EnableControl_Impl(*m_xSearchAllBtn);
+ EnableControl_Impl(*m_xReplaceAllBtn);
+ }
+ }
+ else
+ {
+ m_xComponentFrame->set_sensitive(false);
+ m_xSearchBtn->set_sensitive(false);
+ m_xBackSearchBtn->set_sensitive(false);
+ m_xSearchAllBtn->set_sensitive(false);
+ m_xReplaceBtn->set_sensitive(false);
+ m_xReplaceAllBtn->set_sensitive(false);
+ }
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, TemplateHdl_Impl, weld::Toggleable&, void)
+{
+ if ( pImpl->bSaveToModule )
+ SaveToModule_Impl();
+
+ if ( bFormat )
+ return;
+ OUString sDesc;
+
+ if ( m_xLayoutBtn->get_active() )
+ {
+ if ( !pFamilyController )
+ {
+ sal_uInt16 nId = 0;
+
+ // Enable templates controller
+ switch ( pSearchItem->GetFamily() )
+ {
+ case SfxStyleFamily::Char:
+ nId = SID_STYLE_FAMILY1; break;
+
+ case SfxStyleFamily::Para:
+ nId = SID_STYLE_FAMILY2; break;
+
+ case SfxStyleFamily::Frame:
+ nId = SID_STYLE_FAMILY3; break;
+
+ case SfxStyleFamily::Page:
+ nId = SID_STYLE_FAMILY4; break;
+
+ case SfxStyleFamily::All:
+ break;
+
+ default:
+ OSL_FAIL( "StyleSheetFamily was changed?" );
+ }
+
+ rBindings.EnterRegistrations();
+ pFamilyController.reset(
+ new SvxSearchController( nId, rBindings, *this ) );
+ rBindings.LeaveRegistrations();
+ m_xSearchTmplLB->clear();
+ m_xReplaceTmplLB->clear();
+
+ m_xSearchTmplLB->show();
+ m_xReplaceTmplLB->show();
+ m_xSearchLB->hide();
+ m_xReplaceLB->hide();
+
+ m_xSearchAttrText->set_label( sDesc );
+ m_xReplaceAttrText->set_label( sDesc );
+
+ if(!sDesc.isEmpty())
+ {
+ if (!m_xReplaceAttrText->get_visible() || !m_xReplaceAttrText->get_visible())
+ {
+ m_xSearchAttrText->show();
+ m_xReplaceAttrText->show();
+ m_xDialog->resize_to_request();
+ }
+ }
+ }
+ m_xFormatBtn->set_sensitive(false);
+ m_xNoFormatBtn->set_sensitive(false);
+ m_xAttributeBtn->set_sensitive(false);
+ m_xSimilarityBox->set_sensitive(false);
+ m_xSimilarityBtn->set_sensitive(false);
+ }
+ else
+ {
+ // Disable templates controller
+ rBindings.EnterRegistrations();
+ pFamilyController.reset();
+ rBindings.LeaveRegistrations();
+
+ m_xSearchLB->show();
+ m_xReplaceLB->show();
+ m_xSearchTmplLB->hide();
+ m_xReplaceTmplLB->hide();
+
+ m_xSearchAttrText->set_label( BuildAttrText_Impl( sDesc, true ) );
+ m_xReplaceAttrText->set_label( BuildAttrText_Impl( sDesc, false ) );
+
+ if(!sDesc.isEmpty())
+ {
+ if (!m_xReplaceAttrText->get_visible() || !m_xReplaceAttrText->get_visible())
+ {
+ m_xSearchAttrText->show();
+ m_xReplaceAttrText->show();
+ m_xDialog->resize_to_request();
+ }
+ }
+
+ EnableControl_Impl(*m_xFormatBtn);
+ EnableControl_Impl(*m_xAttributeBtn);
+ EnableControl_Impl(*m_xSimilarityBox);
+
+ FocusHdl_Impl( bSearch ? *m_xSearchLB : *m_xReplaceLB );
+ }
+ bSet = true;
+ pImpl->bSaveToModule = false;
+ FlagHdl_Impl(*m_xLayoutBtn);
+ pImpl->bSaveToModule = true;
+}
+
+void SvxSearchDialog::Remember_Impl( const OUString &rStr, bool _bSearch )
+{
+ if ( rStr.isEmpty() )
+ return;
+
+ std::vector<OUString>* pArr = _bSearch ? &aSearchStrings : &aReplaceStrings;
+ weld::ComboBox* pListBox = _bSearch ? m_xSearchLB.get() : m_xReplaceLB.get();
+
+ // ignore identical strings
+ if (std::find(pArr->begin(), pArr->end(), rStr) != pArr->end())
+ return;
+
+ pArr->insert(pArr->begin(), rStr);
+ pListBox->insert_text(0, rStr);
+
+ // delete oldest entry at maximum occupancy (ListBox and Array)
+ size_t nArrSize = pArr->size();
+ if (nArrSize > nRememberSize)
+ {
+ pListBox->remove(nArrSize - 1);
+ pArr->erase(pArr->begin() + nArrSize - 1);
+ }
+}
+
+void SvxSearchDialog::TemplatesChanged_Impl( SfxStyleSheetBasePool& rPool )
+{
+ OUString aOldSrch( m_xSearchTmplLB->get_active_text() );
+ OUString aOldRepl( m_xReplaceTmplLB->get_active_text() );
+ m_xSearchTmplLB->clear();
+ m_xReplaceTmplLB->clear();
+ m_xSearchTmplLB->freeze();
+ m_xReplaceTmplLB->freeze();
+ SfxStyleSheetBase* pBase = rPool.First(pSearchItem->GetFamily());
+
+ while ( pBase )
+ {
+ if ( pBase->IsUsed() )
+ m_xSearchTmplLB->append_text( pBase->GetName() );
+ m_xReplaceTmplLB->append_text( pBase->GetName() );
+ pBase = rPool.Next();
+ }
+ m_xSearchTmplLB->thaw();
+ m_xReplaceTmplLB->thaw();
+ m_xSearchTmplLB->set_active(0);
+
+ if ( !aOldSrch.isEmpty() )
+ m_xSearchTmplLB->set_active_text( aOldSrch );
+ m_xReplaceTmplLB->set_active(0);
+
+ if ( !aOldRepl.isEmpty() )
+ m_xReplaceTmplLB->set_active_text( aOldRepl );
+
+ if ( m_xSearchTmplLB->get_count() )
+ {
+ EnableControl_Impl(*m_xSearchBtn);
+ EnableControl_Impl(*m_xBackSearchBtn);
+ EnableControl_Impl(*m_xSearchAllBtn);
+ EnableControl_Impl(*m_xReplaceBtn);
+ EnableControl_Impl(*m_xReplaceAllBtn);
+ }
+}
+
+
+void SvxSearchDialog::EnableControls_Impl( const SearchOptionFlags nFlags )
+{
+ if ( nFlags == nOptions )
+ return;
+ else
+ nOptions = nFlags;
+
+ bool bNoSearch = true;
+
+ bool bEnableSearch = bool( SearchOptionFlags::SEARCH & nOptions );
+ m_xSearchBtn->set_sensitive(bEnableSearch);
+ m_xBackSearchBtn->set_sensitive(bEnableSearch);
+
+ if( bEnableSearch )
+ bNoSearch = false;
+
+
+ if ( SearchOptionFlags::SEARCHALL & nOptions )
+ {
+ m_xSearchAllBtn->set_sensitive(true);
+ bNoSearch = false;
+ }
+ else
+ m_xSearchAllBtn->set_sensitive(false);
+ if ( SearchOptionFlags::REPLACE & nOptions )
+ {
+ m_xReplaceBtn->set_sensitive(true);
+ m_xReplaceFrame->set_sensitive(true);
+ m_xReplaceLB->set_sensitive(true);
+ m_xReplaceTmplLB->set_sensitive(true);
+ bNoSearch = false;
+ }
+ else
+ {
+ m_xReplaceBtn->set_sensitive(false);
+ m_xReplaceFrame->set_sensitive(false);
+ m_xReplaceLB->set_sensitive(false);
+ m_xReplaceTmplLB->set_sensitive(false);
+ }
+ if ( SearchOptionFlags::REPLACE_ALL & nOptions )
+ {
+ m_xReplaceAllBtn->set_sensitive(true);
+ bNoSearch = false;
+ }
+ else
+ m_xReplaceAllBtn->set_sensitive(false);
+ m_xComponentFrame->set_sensitive(!bNoSearch);
+ m_xSearchBtn->set_sensitive( !bNoSearch );
+ m_xBackSearchBtn->set_sensitive( !bNoSearch );
+ m_xSearchFrame->set_sensitive( !bNoSearch );
+ m_xSearchLB->set_sensitive( !bNoSearch );
+ m_xNotesBtn->set_sensitive(true);
+
+ if ( SearchOptionFlags::WHOLE_WORDS & nOptions )
+ m_xWordBtn->set_sensitive(true);
+ else
+ m_xWordBtn->set_sensitive(false);
+ if ( SearchOptionFlags::BACKWARDS & nOptions )
+ {
+ m_xBackSearchBtn->set_sensitive(true);
+ m_xReplaceBackwardsCB->set_sensitive(true);
+ }
+ else
+ {
+ m_xBackSearchBtn->set_sensitive(false);
+ m_xReplaceBackwardsCB->set_sensitive(false);
+ }
+ if ( SearchOptionFlags::REG_EXP & nOptions )
+ m_xRegExpBtn->set_sensitive(true);
+ else
+ m_xRegExpBtn->set_sensitive(false);
+ if ( SearchOptionFlags::WILDCARD & nOptions )
+ m_xWildcardBtn->set_sensitive(true);
+ else
+ m_xWildcardBtn->set_sensitive(false);
+ if ( SearchOptionFlags::EXACT & nOptions )
+ m_xMatchCaseCB->set_sensitive(true);
+ else
+ m_xMatchCaseCB->set_sensitive(false);
+ if ( SearchOptionFlags::SELECTION & nOptions )
+ m_xSelectionBtn->set_sensitive(true);
+ else
+ m_xSelectionBtn->set_sensitive(false);
+ if ( SearchOptionFlags::FAMILIES & nOptions )
+ m_xLayoutBtn->set_sensitive(true);
+ else
+ m_xLayoutBtn->set_sensitive(false);
+ if ( SearchOptionFlags::FORMAT & nOptions )
+ {
+ m_xAttributeBtn->set_sensitive(true);
+ m_xFormatBtn->set_sensitive(true);
+ m_xNoFormatBtn->set_sensitive(true);
+ }
+ else
+ {
+ m_xAttributeBtn->set_sensitive(false);
+ m_xFormatBtn->set_sensitive(false);
+ m_xNoFormatBtn->set_sensitive(false);
+ }
+
+ if ( SearchOptionFlags::SIMILARITY & nOptions )
+ {
+ m_xSimilarityBox->set_sensitive(true);
+ m_xSimilarityBtn->set_sensitive(true);
+ }
+ else
+ {
+ m_xSimilarityBox->set_sensitive(false);
+ m_xSimilarityBtn->set_sensitive(false);
+ }
+
+ if ( pSearchItem )
+ {
+ Init_Impl( pSearchItem->GetPattern() &&
+ ( !pSearchList || !pSearchList->Count() ) );
+ if (SvxSearchDialog::IsOtherOptionsExpanded())
+ m_xOtherOptionsExpander->set_expanded(true);
+ }
+}
+
+void SvxSearchDialog::EnableControl_Impl(const weld::Widget& rCtrl)
+{
+ if (m_xSearchBtn.get() == &rCtrl && ( SearchOptionFlags::SEARCH & nOptions ) )
+ {
+ m_xComponentFrame->set_sensitive(true);
+ m_xSearchBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xSearchAllBtn.get() == &rCtrl &&
+ ( SearchOptionFlags::SEARCHALL & nOptions ) )
+ {
+ m_xSearchAllBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xReplaceBtn.get() == &rCtrl && ( SearchOptionFlags::REPLACE & nOptions ) )
+ {
+ m_xReplaceBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xReplaceAllBtn.get() == &rCtrl &&
+ ( SearchOptionFlags::REPLACE_ALL & nOptions ) )
+ {
+ m_xReplaceAllBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xWordBtn.get() == &rCtrl && ( SearchOptionFlags::WHOLE_WORDS & nOptions ) )
+ {
+ m_xWordBtn->set_sensitive(true);
+ return;
+ }
+ if ( SearchOptionFlags::BACKWARDS & nOptions )
+ {
+ if( m_xBackSearchBtn.get() == &rCtrl )
+ {
+ m_xBackSearchBtn->set_sensitive(true);
+ return;
+ }
+ else if ( m_xReplaceBackwardsCB.get() == &rCtrl )
+ {
+ m_xReplaceBackwardsCB->set_sensitive(true);
+ return;
+ }
+ }
+ if (m_xNotesBtn.get() == &rCtrl)
+ {
+ m_xNotesBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xRegExpBtn.get() == &rCtrl && ( SearchOptionFlags::REG_EXP & nOptions )
+ && !m_xSimilarityBox->get_active() && !m_xWildcardBtn->get_active())
+ {
+ m_xRegExpBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xWildcardBtn.get() == &rCtrl && ( SearchOptionFlags::WILDCARD & nOptions )
+ && !m_xSimilarityBox->get_active() && !m_xRegExpBtn->get_active())
+ {
+ m_xWildcardBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xMatchCaseCB.get() == &rCtrl && ( SearchOptionFlags::EXACT & nOptions ) )
+ {
+ if (!m_xJapOptionsCB->get_active())
+ m_xMatchCaseCB->set_sensitive(true);
+ return;
+ }
+ if ( m_xSelectionBtn.get() == &rCtrl && ( SearchOptionFlags::SELECTION & nOptions ) )
+ {
+ m_xSelectionBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xLayoutBtn.get() == &rCtrl && ( SearchOptionFlags::FAMILIES & nOptions ) )
+ {
+ m_xLayoutBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xAttributeBtn.get() == &rCtrl
+ && ( SearchOptionFlags::FORMAT & nOptions )
+ && pSearchList )
+ {
+ m_xAttributeBtn->set_sensitive( pImpl->bFocusOnSearch );
+ }
+ if ( m_xFormatBtn.get() == &rCtrl && ( SearchOptionFlags::FORMAT & nOptions ) )
+ {
+ m_xFormatBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xNoFormatBtn.get() == &rCtrl && ( SearchOptionFlags::FORMAT & nOptions ) )
+ {
+ m_xNoFormatBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xSimilarityBox.get() == &rCtrl && ( SearchOptionFlags::SIMILARITY & nOptions )
+ && !m_xRegExpBtn->get_active() && !m_xWildcardBtn->get_active())
+ {
+ m_xSimilarityBox->set_sensitive(true);
+
+ if ( m_xSimilarityBox->get_active() )
+ m_xSimilarityBtn->set_sensitive(true);
+ }
+}
+
+void SvxSearchDialog::SetItem_Impl( const SvxSearchItem* pItem )
+{
+ //TODO: save pItem and process later if m_executingSubDialog?
+ if ( pItem && !m_executingSubDialog )
+ {
+ pSearchItem.reset(pItem->Clone());
+ Init_Impl( pSearchItem->GetPattern() &&
+ ( !pSearchList || !pSearchList->Count() ) );
+ }
+}
+
+IMPL_LINK(SvxSearchDialog, FocusHdl_Impl, weld::Widget&, rControl, void)
+{
+ sal_Int32 nTxtLen = m_xSearchAttrText->get_label().getLength();
+ weld::Widget* pCtrl = &rControl;
+ if (pCtrl == m_xSearchLB.get())
+ {
+ if (pCtrl->has_focus())
+ pImpl->bFocusOnSearch = true;
+ pCtrl = m_xSearchLB.get();
+ bSearch = true;
+
+ if( nTxtLen )
+ EnableControl_Impl(*m_xNoFormatBtn);
+ else
+ m_xNoFormatBtn->set_sensitive(false);
+ EnableControl_Impl(*m_xAttributeBtn);
+ }
+ else
+ {
+ pImpl->bFocusOnSearch = false;
+ pCtrl = m_xReplaceLB.get();
+ bSearch = false;
+
+ if (!m_xReplaceAttrText->get_label().isEmpty())
+ EnableControl_Impl(*m_xNoFormatBtn);
+ else
+ m_xNoFormatBtn->set_sensitive(false);
+ m_xAttributeBtn->set_sensitive(false);
+ }
+ bSet = true;
+
+ weld::ComboBox &rComboBox = dynamic_cast<weld::ComboBox&>(*pCtrl);
+ rComboBox.select_entry_region(0, -1);
+ ModifyHdl_Impl(rComboBox);
+
+ if (bFormat && nTxtLen)
+ m_xLayoutBtn->set_label(aLayoutStr);
+ else
+ {
+ SvtModuleOptions::EFactory eFactory = getModule(rBindings);
+ bool bWriterApp =
+ eFactory == SvtModuleOptions::EFactory::WRITER ||
+ eFactory == SvtModuleOptions::EFactory::WRITERWEB ||
+ eFactory == SvtModuleOptions::EFactory::WRITERGLOBAL;
+ bool bCalcApp = eFactory == SvtModuleOptions::EFactory::CALC;
+
+ if (bWriterApp)
+ m_xLayoutBtn->set_label(aLayoutWriterStr);
+ else
+ {
+ if (bCalcApp)
+ m_xLayoutBtn->set_label(aLayoutCalcStr);
+ else
+ m_xLayoutBtn->set_label(aStylesStr);
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, LoseFocusHdl_Impl, weld::Widget&, void)
+{
+ SaveToModule_Impl();
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, FormatHdl_Impl, weld::Button&, void)
+{
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+
+ DBG_ASSERT( pSh, "no DocShell" );
+
+ if ( !pSh || pImpl->pRanges.empty() )
+ return;
+
+ SfxItemPool& rPool = pSh->GetPool();
+ SfxItemSet aSet(rPool, pImpl->pRanges);
+
+ aSet.MergeRange(SID_ATTR_PARA_MODEL, SID_ATTR_PARA_MODEL);
+
+ sal_uInt16 nBrushWhich = pSh->GetPool().GetWhich(SID_ATTR_BRUSH);
+ aSet.MergeRange(nBrushWhich, nBrushWhich);
+
+ aSet.MergeRange(XATTR_FILL_FIRST, XATTR_FILL_LAST);
+
+ OUString aTxt;
+
+ aSet.InvalidateAllItems();
+ aSet.Put(SvxBrushItem(nBrushWhich));
+
+ if ( bSearch )
+ {
+ aTxt = SvxResId( RID_SVXSTR_SEARCH );
+ pSearchList->Get( aSet );
+ }
+ else
+ {
+ aTxt = SvxResId( RID_SVXSTR_REPLACE );
+ pReplaceList->Get( aSet );
+ }
+ aSet.DisableItem(SID_ATTR_PARA_MODEL);
+ aSet.DisableItem(rPool.GetWhich(SID_ATTR_PARA_PAGEBREAK));
+ aSet.DisableItem(rPool.GetWhich(SID_ATTR_PARA_KEEP));
+
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateTabItemDialog(m_xDialog.get(), aSet));
+ pDlg->SetText( aTxt );
+
+ if ( executeSubDialog(pDlg.get()) != RET_OK )
+ return;
+
+ DBG_ASSERT( pDlg->GetOutputItemSet(), "invalid Output-Set" );
+ SfxItemSet aOutSet( *pDlg->GetOutputItemSet() );
+
+ SearchAttrItemList* pList = bSearch ? pSearchList.get() : pReplaceList.get();
+
+ const SfxPoolItem* pItem;
+ for( sal_uInt16 n = 0; n < pList->Count(); ++n )
+ {
+ SearchAttrItem* pAItem = &pList->GetObject(n);
+ if( !IsInvalidItem( pAItem->pItem ) &&
+ SfxItemState::SET == aOutSet.GetItemState(
+ pAItem->pItem->Which(), false, &pItem ) )
+ {
+ delete pAItem->pItem;
+ pAItem->pItem = pItem->Clone();
+ aOutSet.ClearItem( pAItem->pItem->Which() );
+ }
+ }
+
+ if( aOutSet.Count() )
+ pList->Put( aOutSet );
+
+ PaintAttrText_Impl(); // Set AttributeText in GroupBox
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, NoFormatHdl_Impl, weld::Button&, void)
+{
+ SvtModuleOptions::EFactory eFactory = getModule(rBindings);
+ bool bWriterApp =
+ eFactory == SvtModuleOptions::EFactory::WRITER ||
+ eFactory == SvtModuleOptions::EFactory::WRITERWEB ||
+ eFactory == SvtModuleOptions::EFactory::WRITERGLOBAL;
+ bool bCalcApp = eFactory == SvtModuleOptions::EFactory::CALC;
+
+ if (bCalcApp)
+ m_xLayoutBtn->set_label( aLayoutCalcStr );
+ else
+ {
+ if (bWriterApp)
+ m_xLayoutBtn->set_label( aLayoutWriterStr);
+ else
+ m_xLayoutBtn->set_label( aStylesStr );
+ }
+
+ bFormat = false;
+ m_xLayoutBtn->set_active( false );
+
+ bool bSetOptimalLayoutSize = false;
+
+ if ( bSearch )
+ {
+ pSearchList->Clear();
+ m_xSearchAttrText->set_label( "" );
+ if (m_xSearchAttrText->get_visible())
+ {
+ m_xSearchAttrText->hide();
+ bSetOptimalLayoutSize = true;
+ }
+ }
+ else
+ {
+ pReplaceList->Clear();
+ m_xReplaceAttrText->set_label( "" );
+ if (m_xReplaceAttrText->get_visible())
+ {
+ m_xReplaceAttrText->hide();
+ bSetOptimalLayoutSize = true;
+ }
+ }
+
+ if (bSetOptimalLayoutSize)
+ m_xDialog->resize_to_request();
+
+ pImpl->bSaveToModule = false;
+ TemplateHdl_Impl(*m_xLayoutBtn);
+ pImpl->bSaveToModule = true;
+ m_xNoFormatBtn->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, AttributeHdl_Impl, weld::Button&, void)
+{
+ if ( !pSearchList || pImpl->pRanges.empty() )
+ return;
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateSvxSearchAttributeDialog(m_xDialog.get(), *pSearchList, pImpl->pRanges));
+ executeSubDialog(pDlg.get());
+ PaintAttrText_Impl();
+}
+
+IMPL_LINK( SvxSearchDialog, TimeoutHdl_Impl, Timer *, pTimer, void )
+{
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+
+ if ( pViewShell )
+ {
+ if ( pViewShell->HasSelection( m_xSearchLB->get_visible() ) )
+ EnableControl_Impl(*m_xSelectionBtn);
+ else
+ {
+ m_xSelectionBtn->set_active( false );
+ m_xSelectionBtn->set_sensitive(false);
+ }
+ }
+
+ pTimer->Start();
+}
+
+OUString& SvxSearchDialog::BuildAttrText_Impl( OUString& rStr,
+ bool bSrchFlag ) const
+{
+ rStr.clear();
+
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ DBG_ASSERT( pSh, "no DocShell" );
+
+ if ( !pSh )
+ return rStr;
+
+ SfxItemPool& rPool = pSh->GetPool();
+ SearchAttrItemList* pList = bSrchFlag ? pSearchList.get() : pReplaceList.get();
+
+ if ( !pList )
+ return rStr;
+
+ // Metric query
+ MapUnit eMapUnit = MapUnit::MapCM;
+ FieldUnit eFieldUnit = pSh->GetModule()->GetFieldUnit();
+ switch ( eFieldUnit )
+ {
+ case FieldUnit::MM: eMapUnit = MapUnit::MapMM; break;
+ case FieldUnit::CM:
+ case FieldUnit::M:
+ case FieldUnit::KM: eMapUnit = MapUnit::MapCM; break;
+ case FieldUnit::TWIP: eMapUnit = MapUnit::MapTwip; break;
+ case FieldUnit::POINT:
+ case FieldUnit::PICA: eMapUnit = MapUnit::MapPoint; break;
+ case FieldUnit::INCH:
+ case FieldUnit::FOOT:
+ case FieldUnit::MILE: eMapUnit = MapUnit::MapInch; break;
+ case FieldUnit::MM_100TH: eMapUnit = MapUnit::Map100thMM; break;
+ default: ;//prevent warning
+ }
+
+ IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag());
+ for ( sal_uInt16 i = 0; i < pList->Count(); ++i )
+ {
+ const SearchAttrItem& rItem = pList->GetObject(i);
+
+ if ( !rStr.isEmpty() )
+ rStr += ", ";
+
+ if ( !IsInvalidItem( rItem.pItem ) )
+ {
+ OUString aStr;
+ rPool.GetPresentation(*rItem.pItem, eMapUnit, aStr, aIntlWrapper);
+ if (aStr.isEmpty())
+ {
+ if (rStr.endsWith(", "))
+ rStr = rStr.copy(0, rStr.lastIndexOf(","));
+ }
+ else
+ rStr += aStr;
+ }
+ else if ( rItem.nSlot == SID_ATTR_BRUSH_CHAR )
+ {
+ // Special treatment for text background
+ rStr += SvxResId( RID_SVXITEMS_BRUSH_CHAR );
+ }
+ else
+ {
+ sal_uInt32 nId = SvxAttrNameTable::FindIndex(rItem.nSlot);
+ if ( RESARRAY_INDEX_NOTFOUND != nId )
+ rStr += SvxAttrNameTable::GetString(nId);
+ }
+ }
+ return rStr;
+}
+
+
+void SvxSearchDialog::PaintAttrText_Impl()
+{
+ OUString aDesc;
+ BuildAttrText_Impl( aDesc, bSearch );
+
+ if ( !bFormat && !aDesc.isEmpty() )
+ bFormat = true;
+
+ bool bSetOptimalLayoutSize = false;
+
+ if ( bSearch )
+ {
+ m_xSearchAttrText->set_label( aDesc );
+ if (!aDesc.isEmpty() && !m_xSearchAttrText->get_visible())
+ {
+ m_xSearchAttrText->show();
+ bSetOptimalLayoutSize = true;
+ }
+
+ FocusHdl_Impl(*m_xSearchLB);
+ }
+ else
+ {
+ m_xReplaceAttrText->set_label( aDesc );
+ if (!aDesc.isEmpty() && !m_xReplaceAttrText->get_visible())
+ {
+ m_xReplaceAttrText->show();
+ bSetOptimalLayoutSize = true;
+ }
+
+ FocusHdl_Impl(*m_xReplaceLB);
+ }
+
+ if (bSetOptimalLayoutSize)
+ m_xDialog->resize_to_request();
+}
+
+void SvxSearchDialog::SetModifyFlag_Impl( const weld::Widget* pCtrl )
+{
+ if (m_xSearchLB.get() == pCtrl)
+ {
+ nModifyFlag |= ModifyFlags::Search;
+ m_xSearchLB->set_entry_message_type(weld::EntryMessageType::Normal);
+ SvxSearchDialogWrapper::SetSearchLabel("");
+ }
+ else if ( m_xReplaceLB.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Replace;
+ else if ( m_xWordBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Word;
+ else if ( m_xMatchCaseCB.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Exact;
+ else if ( m_xReplaceBackwardsCB.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Backwards;
+ else if ( m_xNotesBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Notes;
+ else if ( m_xSelectionBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Selection;
+ else if ( m_xRegExpBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Regexp;
+ else if ( m_xWildcardBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Wildcard;
+ else if ( m_xLayoutBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Layout;
+ else if ( m_xSimilarityBox.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Similarity;
+ else if ( m_xCalcSearchInLB.get() == pCtrl )
+ {
+ nModifyFlag |= ModifyFlags::Formulas;
+ nModifyFlag |= ModifyFlags::Values;
+ nModifyFlag |= ModifyFlags::CalcNotes;
+ }
+ else if ( m_xRowsBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Rows;
+ else if ( m_xColumnsBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Columns;
+ else if ( m_xAllSheetsCB.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::AllTables;
+}
+
+void SvxSearchDialog::SaveToModule_Impl()
+{
+ if ( !pSearchItem )
+ return;
+
+ if ( m_xLayoutBtn->get_active() )
+ {
+ pSearchItem->SetSearchString ( m_xSearchTmplLB->get_active_text() );
+ pSearchItem->SetReplaceString( m_xReplaceTmplLB->get_active_text() );
+ }
+ else
+ {
+ pSearchItem->SetSearchString ( m_xSearchLB->get_active_text() );
+ pSearchItem->SetReplaceString( m_xReplaceLB->get_active_text() );
+ Remember_Impl( m_xSearchLB->get_active_text(), true );
+ }
+
+ pSearchItem->SetRegExp( false );
+ pSearchItem->SetWildcard( false );
+ pSearchItem->SetLevenshtein( false );
+ if (GetCheckBoxValue(*m_xRegExpBtn))
+ pSearchItem->SetRegExp( true );
+ else if (GetCheckBoxValue(*m_xWildcardBtn))
+ pSearchItem->SetWildcard( true );
+ else if (GetCheckBoxValue(*m_xSimilarityBox))
+ pSearchItem->SetLevenshtein( true );
+
+ pSearchItem->SetWordOnly(GetCheckBoxValue(*m_xWordBtn));
+ pSearchItem->SetBackward(GetCheckBoxValue(*m_xReplaceBackwardsCB));
+ pSearchItem->SetNotes(GetCheckBoxValue(*m_xNotesBtn));
+ pSearchItem->SetPattern(GetCheckBoxValue(*m_xLayoutBtn));
+ pSearchItem->SetSelection(GetCheckBoxValue(*m_xSelectionBtn));
+ pSearchItem->SetUseAsianOptions(GetCheckBoxValue(*m_xJapOptionsCB));
+
+ SvtSearchOptions aOpt;
+ aOpt.SetIgnoreDiacritics_CTL(GetNegatedCheckBoxValue(*m_xIncludeDiacritics));
+ aOpt.SetIgnoreKashida_CTL(GetNegatedCheckBoxValue(*m_xIncludeKashida));
+ aOpt.Commit();
+
+ TransliterationFlags nFlags = GetTransliterationFlags();
+ if( !pSearchItem->IsUseAsianOptions())
+ nFlags &= TransliterationFlags::IGNORE_CASE |
+ TransliterationFlags::IGNORE_WIDTH;
+ if (GetNegatedCheckBoxValue(*m_xIncludeDiacritics))
+ nFlags |= TransliterationFlags::IGNORE_DIACRITICS_CTL;
+ if (GetNegatedCheckBoxValue(*m_xIncludeKashida))
+ nFlags |= TransliterationFlags::IGNORE_KASHIDA_CTL;
+ pSearchItem->SetTransliterationFlags( nFlags );
+
+ if ( !bWriter )
+ {
+ if (m_xCalcSearchInLB->get_active() != -1)
+ pSearchItem->SetCellType( static_cast<SvxSearchCellType>(m_xCalcSearchInLB->get_active()) );
+
+ pSearchItem->SetRowDirection( m_xRowsBtn->get_active() );
+ pSearchItem->SetAllTables( m_xAllSheetsCB->get_active() );
+ pSearchItem->SetSearchFormatted( m_xSearchFormattedCB->get_active() );
+ }
+
+ pSearchItem->SetCommand( SvxSearchCmd::FIND );
+ nModifyFlag = ModifyFlags::NONE;
+ const SfxPoolItem* ppArgs[] = { pSearchItem.get(), nullptr };
+ rBindings.GetDispatcher()->Execute( SID_SEARCH_ITEM, SfxCallMode::SLOT, ppArgs );
+}
+
+short SvxSearchDialog::executeSubDialog(VclAbstractDialog * dialog) {
+ assert(!m_executingSubDialog);
+ comphelper::ScopeGuard g([this] { m_executingSubDialog = false; });
+ m_executingSubDialog = true;
+ return dialog->Execute();
+}
+
+SFX_IMPL_CHILDWINDOW_WITHID(SvxSearchDialogWrapper, SID_SEARCH_DLG);
+
+
+SvxSearchDialogWrapper::SvxSearchDialogWrapper( vcl::Window* _pParent, sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo const * pInfo )
+ : SfxChildWindow( _pParent, nId )
+ , dialog(std::make_shared<SvxSearchDialog>(_pParent->GetFrameWeld(), this, *pBindings))
+{
+ SetController(dialog);
+ dialog->Initialize( pInfo );
+
+ pBindings->Update( SID_SEARCH_ITEM );
+ pBindings->Update( SID_SEARCH_OPTIONS );
+ pBindings->Update( SID_SEARCH_SEARCHSET );
+ pBindings->Update( SID_SEARCH_REPLACESET );
+ dialog->bConstruct = false;
+}
+
+SvxSearchDialogWrapper::~SvxSearchDialogWrapper ()
+{
+}
+
+
+SfxChildWinInfo SvxSearchDialogWrapper::GetInfo() const
+{
+ SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
+ aInfo.bVisible = false;
+ return aInfo;
+}
+
+static void lcl_SetSearchLabelWindow(const OUString& rStr, SfxViewFrame& rViewFrame)
+{
+ bool bNotFound = rStr == SvxResId(RID_SVXSTR_SEARCH_NOT_FOUND);
+
+ css::uno::Reference< css::beans::XPropertySet > xPropSet(
+ rViewFrame.GetFrame().GetFrameInterface(), css::uno::UNO_QUERY_THROW);
+ css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ xPropSet->getPropertyValue("LayoutManager") >>= xLayoutManager;
+ css::uno::Reference< css::ui::XUIElement > xUIElement =
+ xLayoutManager->getElement("private:resource/toolbar/findbar");
+ if (!xUIElement.is())
+ return;
+ css::uno::Reference< css::awt::XWindow > xWindow(
+ xUIElement->getRealInterface(), css::uno::UNO_QUERY_THROW);
+ VclPtr< ToolBox > pToolBox = static_cast<ToolBox*>( VCLUnoHelper::GetWindow(xWindow) );
+ for (ToolBox::ImplToolItems::size_type i = 0; pToolBox && i < pToolBox->GetItemCount(); ++i)
+ {
+ ToolBoxItemId id = pToolBox->GetItemId(i);
+ if (pToolBox->GetItemCommand(id) == ".uno:SearchLabel")
+ {
+ LabelItemWindow* pSearchLabel = dynamic_cast<LabelItemWindow*>(pToolBox->GetItemWindow(id));
+ assert(pSearchLabel);
+ pSearchLabel->set_label(rStr);
+ if (rStr.isEmpty())
+ pSearchLabel->SetSizePixel(Size(16, pSearchLabel->GetSizePixel().Height()));
+ else
+ pSearchLabel->SetOptimalSize();
+ }
+
+ if (pToolBox->GetItemCommand(id) == ".uno:FindText")
+ {
+ FindTextFieldControl* pFindText = dynamic_cast<FindTextFieldControl*>(pToolBox->GetItemWindow(id));
+ assert(pFindText);
+ if (bNotFound)
+ pFindText->set_entry_message_type(weld::EntryMessageType::Error);
+ else
+ pFindText->set_entry_message_type(weld::EntryMessageType::Normal);
+ }
+ }
+ xLayoutManager->doLayout();
+ pToolBox->Resize();
+}
+
+OUString SvxSearchDialogWrapper::GetSearchLabel()
+{
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (!pViewFrame)
+ return OUString();
+
+ css::uno::Reference< css::beans::XPropertySet > xPropSet(
+ pViewFrame->GetFrame().GetFrameInterface(), css::uno::UNO_QUERY_THROW);
+ css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ xPropSet->getPropertyValue("LayoutManager") >>= xLayoutManager;
+ if (!xLayoutManager.is())
+ return OUString();
+ css::uno::Reference< css::ui::XUIElement > xUIElement =
+ xLayoutManager->getElement("private:resource/toolbar/findbar");
+ if (!xUIElement.is())
+ return OUString();
+ css::uno::Reference< css::awt::XWindow > xWindow(
+ xUIElement->getRealInterface(), css::uno::UNO_QUERY_THROW);
+ VclPtr< ToolBox > pToolBox = static_cast<ToolBox*>( VCLUnoHelper::GetWindow(xWindow) );
+ for (ToolBox::ImplToolItems::size_type i = 0; pToolBox && i < pToolBox->GetItemCount(); ++i)
+ {
+ ToolBoxItemId id = pToolBox->GetItemId(i);
+ if (pToolBox->GetItemCommand(id) == ".uno:SearchLabel")
+ {
+ LabelItemWindow* pSearchLabel = dynamic_cast<LabelItemWindow*>(pToolBox->GetItemWindow(id));
+ return pSearchLabel ? pSearchLabel->get_label() : OUString();
+ }
+ }
+ return OUString();
+}
+
+void SvxSearchDialogWrapper::SetSearchLabel(const SearchLabel& rSL)
+{
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (!pViewFrame)
+ return;
+
+ OUString sStr;
+ if (rSL == SearchLabel::End)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_END);
+ else if (rSL == SearchLabel::Start)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_START);
+ else if (rSL == SearchLabel::EndWrapped)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_END_WRAPPED);
+ else if (rSL == SearchLabel::StartWrapped)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_START_WRAPPED);
+ else if (rSL == SearchLabel::EndSheet)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_END_SHEET);
+ else if (rSL == SearchLabel::NotFound)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_NOT_FOUND);
+ else if (rSL == SearchLabel::NavElementNotFound)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_NAV_ELEMENT_NOT_FOUND);
+ else if (rSL == SearchLabel::ReminderEndWrapped)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_REMINDER_END_WRAPPED);
+ else if (rSL == SearchLabel::ReminderStartWrapped)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_REMINDER_START_WRAPPED);
+
+ lcl_SetSearchLabelWindow(sStr, *pViewFrame);
+
+ if (SvxSearchDialogWrapper *pWrp = static_cast<SvxSearchDialogWrapper*>( pViewFrame->
+ GetChildWindow( SvxSearchDialogWrapper::GetChildWindowId() )))
+ pWrp->getDialog()->SetSearchLabel(sStr);
+}
+
+void SvxSearchDialogWrapper::SetSearchLabel(const OUString& sStr)
+{
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (!pViewFrame)
+ return;
+
+ lcl_SetSearchLabelWindow(sStr, *pViewFrame);
+ if (SvxSearchDialogWrapper *pWrp = static_cast<SvxSearchDialogWrapper*>( pViewFrame->
+ GetChildWindow( SvxSearchDialogWrapper::GetChildWindowId() )))
+ pWrp->getDialog()->SetSearchLabel(sStr);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/strarray.cxx b/svx/source/dialog/strarray.cxx
new file mode 100644
index 000000000..335642452
--- /dev/null
+++ b/svx/source/dialog/strarray.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/strarray.hxx>
+#include <tools/resary.hxx>
+#include <svx/svxitems.hrc>
+#include <fieldunit.hrc>
+#include <numberingtype.hrc>
+
+sal_uInt32 SvxFieldUnitTable::Count() { return SAL_N_ELEMENTS(RID_SVXSTR_FIELDUNIT_TABLE); }
+
+OUString SvxFieldUnitTable::GetString(sal_uInt32 nPos)
+{
+ if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count())
+ return SvxResId(RID_SVXSTR_FIELDUNIT_TABLE[nPos].first);
+ return OUString();
+}
+
+FieldUnit SvxFieldUnitTable::GetValue(sal_uInt32 nPos)
+{
+ if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count())
+ return RID_SVXSTR_FIELDUNIT_TABLE[nPos].second;
+ return FieldUnit::NONE;
+}
+
+OUString SvxAttrNameTable::GetString(sal_uInt32 nPos)
+{
+ if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count())
+ return SvxResId(RID_ATTR_NAMES[nPos].first);
+ return OUString();
+}
+
+sal_uInt32 SvxAttrNameTable::Count() { return SAL_N_ELEMENTS(RID_ATTR_NAMES); }
+
+sal_uInt32 SvxAttrNameTable::FindIndex(int nValue)
+{
+ for (size_t i = 0; i < SAL_N_ELEMENTS(RID_ATTR_NAMES); ++i)
+ {
+ if (nValue == RID_ATTR_NAMES[i].second)
+ return i;
+ }
+ return RESARRAY_INDEX_NOTFOUND;
+}
+
+OUString SvxNumberingTypeTable::GetString(sal_uInt32 nPos)
+{
+ if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count())
+ return SvxResId(RID_SVXSTRARY_NUMBERINGTYPE[nPos].first);
+ return OUString();
+}
+
+sal_uInt32 SvxNumberingTypeTable::Count() { return SAL_N_ELEMENTS(RID_SVXSTRARY_NUMBERINGTYPE); }
+
+int SvxNumberingTypeTable::GetValue(sal_uInt32 nPos)
+{
+ if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count())
+ return RID_SVXSTRARY_NUMBERINGTYPE[nPos].second;
+ return 0;
+}
+
+sal_uInt32 SvxNumberingTypeTable::FindIndex(int nValue)
+{
+ for (size_t i = 0; i < SAL_N_ELEMENTS(RID_SVXSTRARY_NUMBERINGTYPE); ++i)
+ {
+ if (nValue == RID_SVXSTRARY_NUMBERINGTYPE[i].second)
+ return i;
+ }
+ return RESARRAY_INDEX_NOTFOUND;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/svxbmpnumvalueset.cxx b/svx/source/dialog/svxbmpnumvalueset.cxx
new file mode 100644
index 000000000..50b9efb3c
--- /dev/null
+++ b/svx/source/dialog/svxbmpnumvalueset.cxx
@@ -0,0 +1,533 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <tools/diagnose_ex.h>
+#include <i18nlangtag/mslangid.hxx>
+#include <svtools/valueset.hxx>
+#include <editeng/numitem.hxx>
+#include <svx/gallery.hxx>
+#include <vcl/event.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/numvset.hxx>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/text/XNumberingFormatter.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <algorithm>
+
+#include <uiobject.hxx>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::text;
+using namespace com::sun::star::container;
+using namespace com::sun::star::style;
+
+
+// The selection of bullets from the star symbol
+const sal_Unicode aBulletTypes[] =
+{
+ 0x2022,
+ 0x25cf,
+ 0xe00c,
+ 0xe00a,
+ 0x2794,
+ 0x27a2,
+ 0x2717,
+ 0x2714
+};
+
+static vcl::Font& lcl_GetDefaultBulletFont()
+{
+ static vcl::Font aDefBulletFont = []()
+ {
+ static vcl::Font tmp("OpenSymbol", "", Size(0, 14));
+ tmp.SetCharSet( RTL_TEXTENCODING_SYMBOL );
+ tmp.SetFamily( FAMILY_DONTKNOW );
+ tmp.SetPitch( PITCH_DONTKNOW );
+ tmp.SetWeight( WEIGHT_DONTKNOW );
+ tmp.SetTransparent( true );
+ return tmp;
+ }();
+ return aDefBulletFont;
+}
+
+static void lcl_PaintLevel(OutputDevice* pVDev, sal_Int16 nNumberingType,
+ const OUString& rBulletChar, const OUString& rText, const OUString& rFontName,
+ Point& rLeft, vcl::Font& rRuleFont, const vcl::Font& rTextFont)
+{
+
+ if(NumberingType::CHAR_SPECIAL == nNumberingType )
+ {
+ rRuleFont.SetStyleName(rFontName);
+ pVDev->SetFont(rRuleFont);
+ pVDev->DrawText(rLeft, rBulletChar);
+ rLeft.AdjustX(pVDev->GetTextWidth(rBulletChar) );
+ }
+ else
+ {
+ pVDev->SetFont(rTextFont);
+ pVDev->DrawText(rLeft, rText);
+ rLeft.AdjustX(pVDev->GetTextWidth(rText) );
+ }
+}
+
+ const TranslateId RID_SVXSTR_BULLET_DESCRIPTIONS[] =
+{
+ RID_SVXSTR_BULLET_DESCRIPTION_0,
+ RID_SVXSTR_BULLET_DESCRIPTION_1,
+ RID_SVXSTR_BULLET_DESCRIPTION_2,
+ RID_SVXSTR_BULLET_DESCRIPTION_3,
+ RID_SVXSTR_BULLET_DESCRIPTION_4,
+ RID_SVXSTR_BULLET_DESCRIPTION_5,
+ RID_SVXSTR_BULLET_DESCRIPTION_6,
+ RID_SVXSTR_BULLET_DESCRIPTION_7
+};
+
+const TranslateId RID_SVXSTR_SINGLENUM_DESCRIPTIONS[] =
+{
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_0,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_1,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_2,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_3,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_4,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_5,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_6,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_7
+};
+
+const TranslateId RID_SVXSTR_OUTLINENUM_DESCRIPTIONS[] =
+{
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_0,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_1,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_2,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_3,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_4,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_5,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_6,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_7
+};
+
+void SvxNumValueSet::UserDraw( const UserDrawEvent& rUDEvt )
+{
+ static const sal_uInt16 aLinesArr[] =
+ {
+ 15, 10,
+ 20, 30,
+ 25, 50,
+ 30, 70,
+ 35, 90, // up to here line positions
+ 5, 10, // character positions
+ 10, 30,
+ 15, 50,
+ 20, 70,
+ 25, 90,
+ };
+
+ const Color aBackColor(COL_WHITE);
+ const Color aTextColor(COL_BLACK);
+
+ vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
+ tools::Rectangle aRect = rUDEvt.GetRect();
+ sal_uInt16 nItemId = rUDEvt.GetItemId();
+
+ tools::Long nRectWidth = aRect.GetWidth();
+ tools::Long nRectHeight = aRect.GetHeight();
+ Size aRectSize(nRectWidth, aRect.GetHeight());
+ Point aBLPos = aRect.TopLeft();
+ vcl::Font aOldFont = pDev->GetFont();
+ Color aOldColor = pDev->GetLineColor();
+ pDev->SetLineColor(aTextColor);
+ vcl::Font aFont(OutputDevice::GetDefaultFont(
+ DefaultFontType::UI_SANS, MsLangId::getConfiguredSystemLanguage(), GetDefaultFontFlags::OnlyOne));
+
+ Size aSize = aFont.GetFontSize();
+
+ vcl::Font aRuleFont( lcl_GetDefaultBulletFont() );
+ aSize.setHeight( nRectHeight/6 );
+ aRuleFont.SetFontSize(aSize);
+ aRuleFont.SetColor(aTextColor);
+ aRuleFont.SetFillColor(aBackColor);
+ if(ePageType == NumberingPageType::BULLET)
+ aFont = aRuleFont;
+ else if(ePageType == NumberingPageType::OUTLINE)
+ {
+ aSize.setHeight( nRectHeight/8 );
+ }
+ aFont.SetColor(aTextColor);
+ aFont.SetFillColor(aBackColor);
+ aFont.SetFontSize( aSize );
+ pDev->SetFont(aFont);
+
+ if(!pVDev)
+ {
+ // The lines are only one time in the virtual device, only the outline
+ // page is currently done
+ pVDev = VclPtr<VirtualDevice>::Create(*pDev);
+ pVDev->SetMapMode(pDev->GetMapMode());
+ pVDev->EnableRTL( IsRTLEnabled() );
+ pVDev->SetOutputSize( aRectSize );
+ aOrgRect = aRect;
+ pVDev->SetFillColor( aBackColor );
+ pVDev->SetLineColor(COL_LIGHTGRAY);
+ // Draw line only once
+ if(ePageType != NumberingPageType::OUTLINE)
+ {
+ Point aStart(aBLPos.X() + nRectWidth *25 / 100,0);
+ Point aEnd(aBLPos.X() + nRectWidth * 9 / 10,0);
+ for( sal_uInt16 i = 11; i < 100; i += 33)
+ {
+ aStart.setY( aBLPos.Y() + nRectHeight * i / 100 );
+ aEnd.setY( aStart.Y() );
+ pVDev->DrawLine(aStart, aEnd);
+ aStart.setY( aBLPos.Y() + nRectHeight * (i + 11) / 100 );
+ aEnd.setY( aStart.Y() );
+ pVDev->DrawLine(aStart, aEnd);
+ }
+ }
+ }
+ pDev->DrawOutDev( aRect.TopLeft(), aRectSize,
+ aOrgRect.TopLeft(), aRectSize,
+ *pVDev );
+ // Now comes the text
+ static const OUStringLiteral sValue(u"Value");
+ if( NumberingPageType::SINGLENUM == ePageType ||
+ NumberingPageType::BULLET == ePageType )
+ {
+ Point aStart(aBLPos.X() + nRectWidth / 9,0);
+ for( sal_uInt16 i = 0; i < 3; i++ )
+ {
+ sal_uInt16 nY = 11 + i * 33;
+ aStart.setY( aBLPos.Y() + nRectHeight * nY / 100 );
+ OUString sText;
+ if(ePageType == NumberingPageType::BULLET)
+ {
+ sText = OUString( aBulletTypes[nItemId - 1] );
+ aStart.AdjustY( -(pDev->GetTextHeight()/2) );
+ aStart.setX( aBLPos.X() + 5 );
+ }
+ else
+ {
+ if(xFormatter.is() && aNumSettings.getLength() > nItemId - 1)
+ {
+ Sequence<PropertyValue> aLevel = aNumSettings.getConstArray()[nItemId - 1];
+ try
+ {
+ aLevel.realloc(aLevel.getLength() + 1);
+ PropertyValue& rValue = aLevel.getArray()[aLevel.getLength() - 1];
+ rValue.Name = sValue;
+ rValue.Value <<= static_cast<sal_Int32>(i + 1);
+ sText = xFormatter->makeNumberingString( aLevel, aLocale );
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "");
+ }
+ }
+ // start just next to the left edge
+ aStart.setX( aBLPos.X() + 2 );
+ aStart.AdjustY( -(pDev->GetTextHeight()/2) );
+ }
+ pDev->DrawText(aStart, sText);
+ }
+ }
+ else if(NumberingPageType::OUTLINE == ePageType )
+ {
+ // Outline numbering has to be painted into the virtual device
+ // to get correct lines
+ // has to be made again
+ pVDev->SetLineColor(aBackColor);
+ pVDev->DrawRect(aOrgRect);
+ tools::Long nStartX = aOrgRect.Left();
+ tools::Long nStartY = aOrgRect.Top();
+
+ if(xFormatter.is() && aOutlineSettings.getLength() > nItemId - 1)
+ {
+ Reference<XIndexAccess> xLevel = aOutlineSettings.getArray()[nItemId - 1];
+ try
+ {
+ OUString sLevelTexts[5];
+ OUString sFontNames[5];
+ OUString sBulletChars[5];
+ sal_Int16 aNumberingTypes[5];
+ OUString sPrefixes[5];
+ OUString sSuffixes[5];
+ sal_Int16 aParentNumberings[5];
+
+ sal_Int32 nLevelCount = xLevel->getCount();
+ if(nLevelCount > 5)
+ nLevelCount = 5;
+ for( sal_Int32 i = 0; i < nLevelCount; i++)
+ {
+ tools::Long nTop = nStartY + nRectHeight * (aLinesArr[2 * i + 11])/100 ;
+ Point aLeft(nStartX + nRectWidth * (aLinesArr[2 * i + 10])/ 100, nTop );
+
+ Any aLevelAny = xLevel->getByIndex(i);
+ Sequence<PropertyValue> aLevel;
+ aLevelAny >>= aLevel;
+ aNumberingTypes[i] = 0;
+ aParentNumberings[i] = 0;
+ for(const PropertyValue& rProp : std::as_const(aLevel))
+ {
+ if ( rProp.Name == "NumberingType" )
+ rProp.Value >>= aNumberingTypes[i];
+ else if ( rProp.Name == "BulletFontName" )
+ rProp.Value >>= sFontNames[i];
+ else if ( rProp.Name == "BulletChar" )
+ rProp.Value >>= sBulletChars[i];
+ else if ( rProp.Name == "Prefix" )
+ rProp.Value >>= sPrefixes[i];
+ else if ( rProp.Name == "Suffix" )
+ rProp.Value >>= sSuffixes[i];
+ else if ( rProp.Name == "ParentNumbering" )
+ rProp.Value >>= aParentNumberings[i];
+ }
+ Sequence< PropertyValue > aProperties(2);
+ PropertyValue* pProperties = aProperties.getArray();
+ pProperties[0].Name = "NumberingType";
+ pProperties[0].Value <<= aNumberingTypes[i];
+ pProperties[1].Name = "Value";
+ pProperties[1].Value <<= sal_Int32(1);
+ try
+ {
+ sLevelTexts[i] = xFormatter->makeNumberingString( aProperties, aLocale );
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "");
+ }
+
+ aLeft.AdjustY( -(pDev->GetTextHeight()/2) );
+ if(!sPrefixes[i].isEmpty() &&
+ sPrefixes[i] != " ")
+ {
+ pVDev->SetFont(aFont);
+ pVDev->DrawText(aLeft, sPrefixes[i]);
+ aLeft.AdjustX(pDev->GetTextWidth(sPrefixes[i]) );
+ }
+ if(aParentNumberings[i])
+ {
+ //insert old numberings here
+ sal_Int32 nStartLevel = std::min(static_cast<sal_Int32>(aParentNumberings[i]), i);
+ for(sal_Int32 nParentLevel = i - nStartLevel; nParentLevel < i; nParentLevel++)
+ {
+ OUString sTmp = sLevelTexts[nParentLevel] + ".";
+ lcl_PaintLevel(pVDev,
+ aNumberingTypes[nParentLevel],
+ sBulletChars[nParentLevel],
+ sTmp,
+ sFontNames[nParentLevel],
+ aLeft,
+ aRuleFont,
+ aFont);
+ }
+ }
+ lcl_PaintLevel(pVDev,
+ aNumberingTypes[i],
+ sBulletChars[i],
+ sLevelTexts[i],
+ sFontNames[i],
+ aLeft,
+ aRuleFont,
+ aFont);
+ if(!sSuffixes[i].isEmpty() &&
+ !sSuffixes[i].startsWith(" "))
+ {
+ pVDev->SetFont(aFont);
+ pVDev->DrawText(aLeft, sSuffixes[i]);
+ aLeft.AdjustX(pDev->GetTextWidth(sSuffixes[i]) );
+ }
+
+ tools::Long nLineTop = nStartY + nRectHeight * aLinesArr[2 * i + 1]/100 ;
+ Point aLineLeft(aLeft.X(), nLineTop );
+ Point aLineRight(nStartX + nRectWidth * 90 /100, nLineTop );
+ pVDev->SetLineColor(COL_LIGHTGRAY);
+ pVDev->DrawLine(aLineLeft, aLineRight);
+ }
+
+ }
+#ifdef DBG_UTIL
+ catch(Exception&)
+ {
+ static bool bAssert = false;
+ if(!bAssert)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "");
+ bAssert = true;
+ }
+ }
+#else
+ catch(Exception&)
+ {
+ }
+#endif
+ }
+ pDev->DrawOutDev( aRect.TopLeft(), aRectSize,
+ aOrgRect.TopLeft(), aRectSize,
+ *pVDev );
+ }
+
+ pDev->SetFont(aOldFont);
+ pDev->SetLineColor(aOldColor);
+}
+
+SvxNumValueSet::SvxNumValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
+ : ValueSet(std::move(pScrolledWindow))
+ , ePageType(NumberingPageType::BULLET)
+ , pVDev(nullptr)
+{
+}
+
+FactoryFunction SvxNumValueSet::GetUITestFactory() const
+{
+ return SvxNumValueSetUIObject::create;
+}
+
+void SvxNumValueSet::init(NumberingPageType eType)
+{
+ ePageType = eType;
+ pVDev = nullptr;
+
+ SetColCount( 4 );
+ SetLineCount( 2 );
+ SetStyle( GetStyle() | WB_ITEMBORDER | WB_DOUBLEBORDER );
+ if(NumberingPageType::BULLET == eType)
+ {
+ for ( sal_uInt16 i = 0; i < 8; i++ )
+ {
+ InsertItem( i + 1, i );
+ SetItemText(i + 1, SvxResId(RID_SVXSTR_BULLET_DESCRIPTIONS[i]));
+ }
+ }
+}
+
+SvxNumValueSet::~SvxNumValueSet()
+{
+}
+
+void SvxNumValueSet::SetNumberingSettings(
+ const Sequence<Sequence<PropertyValue> >& aNum,
+ Reference<XNumberingFormatter> const & xFormat,
+ const Locale& rLocale )
+{
+ aNumSettings = aNum;
+ xFormatter = xFormat;
+ aLocale = rLocale;
+ if(aNum.getLength() > 8)
+ SetStyle( GetStyle()|WB_VSCROLL);
+ for ( sal_Int32 i = 0; i < aNum.getLength(); i++ )
+ {
+ InsertItem( i + 1, i );
+ if( i < 8 )
+ SetItemText(i + 1, SvxResId(RID_SVXSTR_SINGLENUM_DESCRIPTIONS[i]));
+ }
+}
+
+void SvxNumValueSet::SetOutlineNumberingSettings(
+ Sequence<Reference<XIndexAccess> > const & rOutline,
+ Reference<XNumberingFormatter> const & xFormat,
+ const Locale& rLocale)
+{
+ aOutlineSettings = rOutline;
+ xFormatter = xFormat;
+ aLocale = rLocale;
+ if(aOutlineSettings.getLength() > 8)
+ SetStyle( GetStyle() | WB_VSCROLL );
+ for ( sal_Int32 i = 0; i < aOutlineSettings.getLength(); i++ )
+ {
+ InsertItem( i + 1, i );
+ if( i < 8 )
+ SetItemText(i + 1, SvxResId(RID_SVXSTR_OUTLINENUM_DESCRIPTIONS[i]));
+ }
+}
+
+SvxBmpNumValueSet::SvxBmpNumValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
+ : SvxNumValueSet(std::move(pScrolledWindow))
+ , aFormatIdle("SvxBmpNumValueSet FormatIdle")
+ , bGrfNotFound(false)
+{
+}
+
+void SvxBmpNumValueSet::init()
+{
+ SvxNumValueSet::init(NumberingPageType::BITMAP);
+ bGrfNotFound = false;
+ GalleryExplorer::BeginLocking(GALLERY_THEME_BULLETS);
+ SetStyle( GetStyle() | WB_VSCROLL );
+ SetLineCount( 3 );
+ aFormatIdle.SetPriority(TaskPriority::LOWEST);
+ aFormatIdle.SetInvokeHandler(LINK(this, SvxBmpNumValueSet, FormatHdl_Impl));
+}
+
+
+SvxBmpNumValueSet::~SvxBmpNumValueSet()
+{
+ GalleryExplorer::EndLocking(GALLERY_THEME_BULLETS);
+ aFormatIdle.Stop();
+}
+
+void SvxBmpNumValueSet::UserDraw(const UserDrawEvent& rUDEvt)
+{
+ SvxNumValueSet::UserDraw(rUDEvt);
+
+ tools::Rectangle aRect = rUDEvt.GetRect();
+ vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
+ sal_uInt16 nItemId = rUDEvt.GetItemId();
+ Point aBLPos = aRect.TopLeft();
+
+ tools::Long nRectHeight = aRect.GetHeight();
+ Size aSize(nRectHeight/8, nRectHeight/8);
+
+ Graphic aGraphic;
+ if(!GalleryExplorer::GetGraphicObj( GALLERY_THEME_BULLETS, nItemId - 1,
+ &aGraphic))
+ {
+ bGrfNotFound = true;
+ }
+ else
+ {
+ Point aPos(aBLPos.X() + 5, 0);
+ for( sal_uInt16 i = 0; i < 3; i++ )
+ {
+ sal_uInt16 nY = 11 + i * 33;
+ aPos.setY( aBLPos.Y() + nRectHeight * nY / 100 );
+ aGraphic.Draw(*pDev, aPos, aSize);
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SvxBmpNumValueSet, FormatHdl_Impl, Timer *, void)
+{
+ // only when a graphics was not there, it needs to be formatted
+ if (bGrfNotFound)
+ {
+ SetFormat();
+ bGrfNotFound = false;
+ }
+ Invalidate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/svxdlg.cxx b/svx/source/dialog/svxdlg.cxx
new file mode 100644
index 000000000..c073fb241
--- /dev/null
+++ b/svx/source/dialog/svxdlg.cxx
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svxdlg.hxx>
+
+SvxAbstractDialogFactory* SvxAbstractDialogFactory::Create()
+{
+ return dynamic_cast<SvxAbstractDialogFactory*>(VclAbstractDialogFactory::Create());
+}
+
+SvxAbstractDialogFactory::~SvxAbstractDialogFactory() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/svxgraphicitem.cxx b/svx/source/dialog/svxgraphicitem.cxx
new file mode 100644
index 000000000..9550e79e4
--- /dev/null
+++ b/svx/source/dialog/svxgraphicitem.cxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svxgraphicitem.hxx>
+#include <svx/svxids.hrc>
+
+SvxGraphicItem::SvxGraphicItem( const Graphic& rGraphic )
+ : SfxPoolItem( SID_GRAPHIC ), aGraphic( rGraphic )
+{
+
+}
+
+bool SvxGraphicItem::operator==( const SfxPoolItem& rItem) const
+{
+ return SfxPoolItem::operator==(rItem) && static_cast<const SvxGraphicItem&>(rItem).aGraphic == aGraphic;
+}
+
+SvxGraphicItem* SvxGraphicItem::Clone( SfxItemPool * ) const
+{
+ return new SvxGraphicItem( *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/svxruler.cxx b/svx/source/dialog/svxruler.cxx
new file mode 100644
index 000000000..b3d5e293e
--- /dev/null
+++ b/svx/source/dialog/svxruler.cxx
@@ -0,0 +1,3577 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cstring>
+#include <climits>
+
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/fieldvalues.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weldutils.hxx>
+#include <svl/eitem.hxx>
+#include <svl/rectitem.hxx>
+#include <svl/hint.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/ruler.hxx>
+#include <svx/rulritem.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/tstpitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/protitem.hxx>
+#include <osl/diagnose.h>
+#include <rtl/math.hxx>
+#include <o3tl/string_view.hxx>
+
+#include "rlrcitem.hxx"
+#include <memory>
+
+#define CTRL_ITEM_COUNT 14
+#define GAP 10
+#define OBJECT_BORDER_COUNT 4
+#define TAB_GAP 1
+#define INDENT_GAP 2
+#define INDENT_FIRST_LINE 2
+#define INDENT_LEFT_MARGIN 3
+#define INDENT_RIGHT_MARGIN 4
+#define INDENT_COUNT 3 //without the first two old values
+
+struct SvxRuler_Impl {
+ std::unique_ptr<sal_uInt16[]> pPercBuf;
+ std::unique_ptr<sal_uInt16[]> pBlockBuf;
+ sal_uInt16 nPercSize;
+ tools::Long nTotalDist;
+ tools::Long lOldWinPos;
+ tools::Long lMaxLeftLogic;
+ tools::Long lMaxRightLogic;
+ tools::Long lLastLMargin;
+ tools::Long lLastRMargin;
+ std::unique_ptr<SvxProtectItem> aProtectItem;
+ std::unique_ptr<SfxBoolItem> pTextRTLItem;
+ sal_uInt16 nControllerItems;
+ sal_uInt16 nIdx;
+ sal_uInt16 nColLeftPix;
+ sal_uInt16 nColRightPix; // Pixel values for left / right edge
+ // For columns; buffered to prevent
+ // recalculation errors
+ // May be has to be widen for future values
+ bool bIsTableRows : 1; // mxColumnItem contains table rows instead of columns
+ //#i24363# tab stops relative to indent
+ bool bIsTabsRelativeToIndent : 1; // Tab stops relative to paragraph indent?
+ // false means relative to SvxRuler::GetLeftFrameMargin()
+
+ SvxRuler_Impl() :
+ nPercSize(0), nTotalDist(0),
+ lOldWinPos(0), lMaxLeftLogic(0), lMaxRightLogic(0),
+ lLastLMargin(0), lLastRMargin(0),
+ aProtectItem(std::make_unique<SvxProtectItem>(SID_RULER_PROTECT)),
+ nControllerItems(0), nIdx(0),
+ nColLeftPix(0), nColRightPix(0),
+ bIsTableRows(false),
+ bIsTabsRelativeToIndent(true)
+ {
+ }
+
+ void SetPercSize(sal_uInt16 nSize);
+
+};
+
+static RulerTabData ruler_tab_svx =
+{
+ 0, // DPIScaleFactor to be set
+ 7, // ruler_tab_width
+ 6, // ruler_tab_height
+ 0, // ruler_tab_height2
+ 0, // ruler_tab_width2
+ 0, // ruler_tab_cwidth
+ 0, // ruler_tab_cwidth2
+ 0, // ruler_tab_cwidth3
+ 0, // ruler_tab_cwidth4
+ 0, // ruler_tab_dheight
+ 0, // ruler_tab_dheight2
+ 0, // ruler_tab_dwidth
+ 0, // ruler_tab_dwidth2
+ 0, // ruler_tab_dwidth3
+ 0, // ruler_tab_dwidth4
+ 0 // ruler_tab_textoff
+};
+
+void SvxRuler_Impl::SetPercSize(sal_uInt16 nSize)
+{
+ if(nSize > nPercSize)
+ {
+ nPercSize = nSize;
+ pPercBuf.reset( new sal_uInt16[nPercSize] );
+ pBlockBuf.reset( new sal_uInt16[nPercSize] );
+ }
+ size_t nSize2 = sizeof(sal_uInt16) * nPercSize;
+ memset(pPercBuf.get(), 0, nSize2);
+ memset(pBlockBuf.get(), 0, nSize2);
+}
+
+// Constructor of the ruler
+
+// SID_ATTR_ULSPACE, SID_ATTR_LRSPACE
+// expects as parameter SvxULSpaceItem for page edge
+// (either left/right or top/bottom)
+// Ruler: SetMargin1, SetMargin2
+
+// SID_RULER_PAGE_POS
+// expects as parameter the initial value of the page and page width
+// Ruler: SetPagePos
+
+// SID_ATTR_TABSTOP
+// expects: SvxTabStopItem
+// Ruler: SetTabs
+
+// SID_ATTR_PARA_LRSPACE
+// left, right paragraph edge in H-ruler
+// Ruler: SetIndents
+
+// SID_RULER_BORDERS
+// Table borders, columns
+// expects: something like SwTabCols
+// Ruler: SetBorders
+
+constexpr tools::Long glMinFrame = 5; // minimal frame width in pixels
+
+SvxRuler::SvxRuler(
+ vcl::Window* pParent, // StarView Parent
+ vcl::Window* pWin, // Output window: is used for conversion
+ // logical units <-> pixels
+ SvxRulerSupportFlags flags, // Display flags, see ruler.hxx
+ SfxBindings &rBindings, // associated Bindings
+ WinBits nWinStyle) : // StarView WinBits
+ Ruler(pParent, nWinStyle),
+ pCtrlItems(CTRL_ITEM_COUNT),
+ pEditWin(pWin),
+ mxRulerImpl(new SvxRuler_Impl),
+ bAppSetNullOffset(false), // Is the 0-offset of the ruler set by the application?
+ lLogicNullOffset(0),
+ lAppNullOffset(LONG_MAX),
+ lInitialDragPos(0),
+ nFlags(flags),
+ nDragType(SvxRulerDragFlags::NONE),
+ nDefTabType(RULER_TAB_LEFT),
+ nTabCount(0),
+ nTabBufSize(0),
+ lDefTabDist(50),
+ lTabPos(-1),
+ mpBorders(1), // due to one column tables
+ pBindings(&rBindings),
+ nDragOffset(0),
+ nMaxLeft(0),
+ nMaxRight(0),
+ bValid(false),
+ bListening(false),
+ bActive(true),
+ mbCoarseSnapping(false),
+ mbSnapping(true)
+
+{
+ /* Constructor; Initialize data buffer; controller items are created */
+
+ rBindings.EnterRegistrations();
+
+ // Create Supported Items
+ sal_uInt16 i = 0;
+
+ // Page edges
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_LR_MIN_MAX, *this, rBindings));
+ if((nWinStyle & WB_VSCROLL) == WB_VSCROLL)
+ {
+ bHorz = false;
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_ULSPACE, *this, rBindings));
+ }
+ else
+ {
+ bHorz = true;
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_LRSPACE, *this, rBindings));
+ }
+
+ // Page Position
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PAGE_POS, *this, rBindings));
+
+ if(nFlags & SvxRulerSupportFlags::TABS)
+ {
+ sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
+ pCtrlItems[i++].reset(new SvxRulerItem(nTabStopId, *this, rBindings));
+ SetExtraType(RulerExtra::Tab, nDefTabType);
+ }
+
+ if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS |SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
+ {
+ if(bHorz)
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE, *this, rBindings));
+ else
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE_VERTICAL, *this, rBindings));
+
+ mpIndents.resize(5 + INDENT_GAP);
+
+ for(RulerIndent & rIndent : mpIndents)
+ {
+ rIndent.nPos = 0;
+ rIndent.nStyle = RulerIndentStyle::Top;
+ }
+
+ mpIndents[0].nStyle = RulerIndentStyle::Top;
+ mpIndents[1].nStyle = RulerIndentStyle::Top;
+ mpIndents[INDENT_FIRST_LINE].nStyle = RulerIndentStyle::Top;
+ mpIndents[INDENT_LEFT_MARGIN].nStyle = RulerIndentStyle::Bottom;
+ mpIndents[INDENT_RIGHT_MARGIN].nStyle = RulerIndentStyle::Bottom;
+ }
+
+ if( (nFlags & SvxRulerSupportFlags::BORDERS) == SvxRulerSupportFlags::BORDERS )
+ {
+ pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL, *this, rBindings));
+ pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL, *this, rBindings));
+ }
+
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_TEXT_RIGHT_TO_LEFT, *this, rBindings));
+
+ if( (nFlags & SvxRulerSupportFlags::OBJECT) == SvxRulerSupportFlags::OBJECT )
+ {
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_OBJECT, *this, rBindings));
+ mpObjectBorders.resize(OBJECT_BORDER_COUNT);
+ for(sal_uInt16 nBorder = 0; nBorder < OBJECT_BORDER_COUNT; ++nBorder)
+ {
+ mpObjectBorders[nBorder].nPos = 0;
+ mpObjectBorders[nBorder].nWidth = 0;
+ mpObjectBorders[nBorder].nStyle = RulerBorderStyle::Moveable;
+ }
+ }
+
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PROTECT, *this, rBindings));
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_BORDER_DISTANCE, *this, rBindings));
+ mxRulerImpl->nControllerItems=i;
+
+ if( (nFlags & SvxRulerSupportFlags::SET_NULLOFFSET) == SvxRulerSupportFlags::SET_NULLOFFSET )
+ SetExtraType(RulerExtra::NullOffset);
+
+ rBindings.LeaveRegistrations();
+
+ ruler_tab_svx.DPIScaleFactor = pParent->GetDPIScaleFactor();
+ ruler_tab_svx.height *= ruler_tab_svx.DPIScaleFactor;
+ ruler_tab_svx.width *= ruler_tab_svx.DPIScaleFactor;
+
+}
+
+SvxRuler::~SvxRuler()
+{
+ disposeOnce();
+}
+
+void SvxRuler::dispose()
+{
+ /* Destructor ruler; release internal buffer */
+ if(bListening)
+ EndListening(*pBindings);
+
+ pBindings->EnterRegistrations();
+
+ pCtrlItems.clear();
+
+ pBindings->LeaveRegistrations();
+
+ pEditWin.clear();
+ Ruler::dispose();
+}
+
+tools::Long SvxRuler::MakePositionSticky(tools::Long aPosition, tools::Long aPointOfReference, bool aSnapToFrameMargin) const
+{
+ tools::Long aPointOfReferencePixel = ConvertHPosPixel(aPointOfReference);
+ tools::Long aLeftFramePosition = ConvertHPosPixel(GetLeftFrameMargin());
+ tools::Long aRightFramePosition = ConvertHPosPixel(GetRightFrameMargin());
+
+ double aTick = GetCurrentRulerUnit().nTick1;
+
+ if (mbCoarseSnapping)
+ aTick = GetCurrentRulerUnit().nTick2;
+
+ tools::Long aTickPixel = pEditWin->LogicToPixel(Size(aTick, 0), GetCurrentMapMode()).Width();
+
+ double aHalfTick = aTick / 2.0;
+ double aHalfTickPixel = aTickPixel / 2.0;
+
+ if (aSnapToFrameMargin)
+ {
+ if (aPosition > aLeftFramePosition - aHalfTickPixel && aPosition < aLeftFramePosition + aHalfTickPixel)
+ return aLeftFramePosition;
+
+ if (aPosition > aRightFramePosition - aHalfTickPixel && aPosition < aRightFramePosition + aHalfTickPixel)
+ return aRightFramePosition;
+ }
+
+ if (!mbSnapping)
+ return aPosition;
+
+ // Move "coordinate system" to frame position so ticks are calculated correctly
+ tools::Long aTranslatedPosition = aPosition - aPointOfReferencePixel;
+ // Convert position to current selected map mode
+ tools::Long aPositionLogic = pEditWin->PixelToLogic(Size(aTranslatedPosition, 0), GetCurrentMapMode()).Width();
+ // Normalize -- snap to nearest tick
+ aPositionLogic = rtl::math::round((aPositionLogic + aHalfTick) / aTick) * aTick;
+ // Convert back to pixels
+ aPosition = pEditWin->LogicToPixel(Size(aPositionLogic, 0), GetCurrentMapMode()).Width();
+ // Move "coordinate system" back to original position
+ return aPosition + aPointOfReferencePixel;
+}
+
+tools::Long SvxRuler::ConvertHPosPixel(tools::Long nVal) const
+{
+ return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
+}
+
+tools::Long SvxRuler::ConvertVPosPixel(tools::Long nVal) const
+{
+ return pEditWin->LogicToPixel(Size(0, nVal)).Height();
+}
+
+tools::Long SvxRuler::ConvertHSizePixel(tools::Long nVal) const
+{
+ return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
+}
+
+tools::Long SvxRuler::ConvertVSizePixel(tools::Long nVal) const
+{
+ return pEditWin->LogicToPixel(Size(0, nVal)).Height();
+}
+
+tools::Long SvxRuler::ConvertPosPixel(tools::Long nVal) const
+{
+ return bHorz ? ConvertHPosPixel(nVal): ConvertVPosPixel(nVal);
+}
+
+tools::Long SvxRuler::ConvertSizePixel(tools::Long nVal) const
+{
+ return bHorz? ConvertHSizePixel(nVal): ConvertVSizePixel(nVal);
+}
+
+inline tools::Long SvxRuler::ConvertHPosLogic(tools::Long nVal) const
+{
+ return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
+}
+
+inline tools::Long SvxRuler::ConvertVPosLogic(tools::Long nVal) const
+{
+ return pEditWin->PixelToLogic(Size(0, nVal)).Height();
+}
+
+inline tools::Long SvxRuler::ConvertHSizeLogic(tools::Long nVal) const
+{
+ return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
+}
+
+inline tools::Long SvxRuler::ConvertVSizeLogic(tools::Long nVal) const
+{
+ return pEditWin->PixelToLogic(Size(0, nVal)).Height();
+}
+
+inline tools::Long SvxRuler::ConvertPosLogic(tools::Long nVal) const
+{
+ return bHorz? ConvertHPosLogic(nVal): ConvertVPosLogic(nVal);
+}
+
+inline tools::Long SvxRuler::ConvertSizeLogic(tools::Long nVal) const
+{
+ return bHorz? ConvertHSizeLogic(nVal): ConvertVSizeLogic(nVal);
+}
+
+tools::Long SvxRuler::PixelHAdjust(tools::Long nVal, tools::Long nValOld) const
+{
+ if(ConvertHSizePixel(nVal) != ConvertHSizePixel(nValOld))
+ return nVal;
+ else
+ return nValOld;
+}
+
+tools::Long SvxRuler::PixelVAdjust(tools::Long nVal, tools::Long nValOld) const
+{
+ if(ConvertVSizePixel(nVal) != ConvertVSizePixel(nValOld))
+ return nVal;
+ else
+ return nValOld;
+}
+
+tools::Long SvxRuler::PixelAdjust(tools::Long nVal, tools::Long nValOld) const
+{
+ if(ConvertSizePixel(nVal) != ConvertSizePixel(nValOld))
+ return nVal;
+ else
+ return nValOld;
+}
+
+inline sal_uInt16 SvxRuler::GetObjectBordersOff(sal_uInt16 nIdx) const
+{
+ return bHorz ? nIdx : nIdx + 2;
+}
+
+/*
+ Update Upper Left edge.
+ Items are translated into the representation of the ruler.
+*/
+void SvxRuler::UpdateFrame()
+{
+ const RulerMarginStyle nMarginStyle =
+ ( mxRulerImpl->aProtectItem->IsSizeProtected() ||
+ mxRulerImpl->aProtectItem->IsPosProtected() ) ?
+ RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
+
+ if(mxLRSpaceItem && mxPagePosItem)
+ {
+ // if no initialization by default app behavior
+ const tools::Long nOld = lLogicNullOffset;
+ lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxLRSpaceItem->GetLeft();
+
+ if(bAppSetNullOffset)
+ {
+ lAppNullOffset += lLogicNullOffset - nOld;
+ }
+
+ if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
+ {
+ Ruler::SetNullOffset(ConvertHPosPixel(lLogicNullOffset));
+ SetMargin1(0, nMarginStyle);
+ lAppNullOffset = 0;
+ }
+ else
+ {
+ SetMargin1(ConvertHPosPixel(lAppNullOffset), nMarginStyle);
+ }
+
+ tools::Long lRight = 0;
+
+ // evaluate the table right edge of the table
+ if(mxColumnItem && mxColumnItem->IsTable())
+ lRight = mxColumnItem->GetRight();
+ else
+ lRight = mxLRSpaceItem->GetRight();
+
+ tools::Long aWidth = mxPagePosItem->GetWidth() - lRight - lLogicNullOffset + lAppNullOffset;
+ tools::Long aWidthPixel = ConvertHPosPixel(aWidth);
+
+ SetMargin2(aWidthPixel, nMarginStyle);
+ }
+ else if(mxULSpaceItem && mxPagePosItem)
+ {
+ // relative the upper edge of the surrounding frame
+ const tools::Long nOld = lLogicNullOffset;
+ lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxULSpaceItem->GetUpper();
+
+ if(bAppSetNullOffset)
+ {
+ lAppNullOffset += lLogicNullOffset - nOld;
+ }
+
+ if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
+ {
+ Ruler::SetNullOffset(ConvertVPosPixel(lLogicNullOffset));
+ lAppNullOffset = 0;
+ SetMargin1(0, nMarginStyle);
+ }
+ else
+ {
+ SetMargin1(ConvertVPosPixel(lAppNullOffset), nMarginStyle);
+ }
+
+ tools::Long lLower = mxColumnItem ? mxColumnItem->GetRight() : mxULSpaceItem->GetLower();
+ tools::Long nMargin2 = mxPagePosItem->GetHeight() - lLower - lLogicNullOffset + lAppNullOffset;
+ tools::Long nMargin2Pixel = ConvertVPosPixel(nMargin2);
+
+ SetMargin2(nMargin2Pixel, nMarginStyle);
+ }
+ else
+ {
+ // turns off the view
+ SetMargin1();
+ SetMargin2();
+ }
+
+ if (mxColumnItem)
+ {
+ mxRulerImpl->nColLeftPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetLeft()));
+ mxRulerImpl->nColRightPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetRight()));
+ }
+}
+
+void SvxRuler::MouseMove( const MouseEvent& rMEvt )
+{
+ if( bActive )
+ {
+ pBindings->Update( SID_RULER_LR_MIN_MAX );
+ pBindings->Update( SID_ATTR_LONG_ULSPACE );
+ pBindings->Update( SID_ATTR_LONG_LRSPACE );
+ pBindings->Update( SID_RULER_PAGE_POS );
+ pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
+ pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
+ pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
+ pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
+ pBindings->Update( SID_RULER_OBJECT );
+ pBindings->Update( SID_RULER_PROTECT );
+ }
+
+ Ruler::MouseMove( rMEvt );
+
+ RulerSelection aSelection = GetHoverSelection();
+
+ if (aSelection.eType == RulerType::DontKnow)
+ {
+ SetQuickHelpText("");
+ return;
+ }
+
+ RulerUnitData aUnitData = GetCurrentRulerUnit();
+ double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
+ sal_Int32 aNoDecimalPlaces = 1 + std::ceil(std::log10(aRoundingFactor));
+ OUString sUnit = OUString::createFromAscii(aUnitData.aUnitStr);
+
+ switch (aSelection.eType)
+ {
+ case RulerType::Indent:
+ {
+ if (!mxParaItem)
+ break;
+
+ tools::Long nIndex = aSelection.nAryPos + INDENT_GAP;
+
+ tools::Long nIndentValue = 0.0;
+ if (nIndex == INDENT_LEFT_MARGIN)
+ nIndentValue = mxParaItem->GetTextLeft();
+ else if (nIndex == INDENT_FIRST_LINE)
+ nIndentValue = mxParaItem->GetTextFirstLineOffset();
+ else if (nIndex == INDENT_RIGHT_MARGIN)
+ nIndentValue = mxParaItem->GetRight();
+
+ double fValue = OutputDevice::LogicToLogic(Size(nIndentValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
+
+ SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
+ break;
+ }
+ case RulerType::Border:
+ {
+ if (mxColumnItem == nullptr)
+ break;
+
+ SvxColumnItem& aColumnItem = *mxColumnItem;
+
+ if (aSelection.nAryPos + 1 >= aColumnItem.Count())
+ break;
+
+ double fStart = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos].nEnd, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ fStart = rtl::math::round(fStart / aUnitData.nTickUnit, aNoDecimalPlaces);
+ double fEnd = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos + 1].nStart, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ fEnd = rtl::math::round(fEnd / aUnitData.nTickUnit, aNoDecimalPlaces);
+
+ SetQuickHelpText(
+ OUString::number(fStart) + " " + sUnit + " - " +
+ OUString::number(fEnd) + " " + sUnit );
+ break;
+ }
+ case RulerType::Margin1:
+ {
+ tools::Long nLeft = 0.0;
+ if (mxLRSpaceItem)
+ nLeft = mxLRSpaceItem->GetLeft();
+ else if (mxULSpaceItem)
+ nLeft = mxULSpaceItem->GetUpper();
+ else
+ break;
+
+ double fValue = OutputDevice::LogicToLogic(Size(nLeft, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
+ SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
+
+ break;
+ }
+ case RulerType::Margin2:
+ {
+ tools::Long nRight = 0.0;
+ if (mxLRSpaceItem)
+ nRight = mxLRSpaceItem->GetRight();
+ else if (mxULSpaceItem)
+ nRight = mxULSpaceItem->GetLower();
+ else
+ break;
+
+ double fValue = OutputDevice::LogicToLogic(Size(nRight, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
+ SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
+
+ break;
+ }
+ default:
+ {
+ SetQuickHelpText("");
+ break;
+ }
+ }
+}
+
+void SvxRuler::StartListening_Impl()
+{
+ if(!bListening)
+ {
+ bValid = false;
+ StartListening(*pBindings);
+ bListening = true;
+ }
+}
+
+void SvxRuler::UpdateFrame(const SvxLongLRSpaceItem *pItem) // new value LRSpace
+{
+ /* Store new value LRSpace; delete old ones if possible */
+ if(bActive)
+ {
+ if(pItem)
+ mxLRSpaceItem.reset(new SvxLongLRSpaceItem(*pItem));
+ else
+ mxLRSpaceItem.reset();
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::UpdateFrameMinMax(const SfxRectangleItem *pItem) // value for MinMax
+{
+ /* Set new value for MinMax; delete old ones if possible */
+ if(bActive)
+ {
+ if(pItem)
+ mxMinMaxItem.reset(new SfxRectangleItem(*pItem));
+ else
+ mxMinMaxItem.reset();
+ }
+}
+
+
+void SvxRuler::UpdateFrame(const SvxLongULSpaceItem *pItem) // new value
+{
+ /* Update Right/bottom margin */
+ if(bActive && !bHorz)
+ {
+ if(pItem)
+ mxULSpaceItem.reset(new SvxLongULSpaceItem(*pItem));
+ else
+ mxULSpaceItem.reset();
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::Update( const SvxProtectItem* pItem )
+{
+ if( pItem )
+ mxRulerImpl->aProtectItem.reset(pItem->Clone());
+}
+
+void SvxRuler::UpdateTextRTL(const SfxBoolItem* pItem)
+{
+ if(bActive && bHorz)
+ {
+ mxRulerImpl->pTextRTLItem.reset();
+ if(pItem)
+ mxRulerImpl->pTextRTLItem.reset(new SfxBoolItem(*pItem));
+ SetTextRTL(mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue());
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::Update(
+ const SvxColumnItem *pItem, // new value
+ sal_uInt16 nSID) //Slot Id to identify NULL items
+{
+ /* Set new value for column view */
+ if(!bActive)
+ return;
+
+ if(pItem)
+ {
+ mxColumnItem.reset(new SvxColumnItem(*pItem));
+ mxRulerImpl->bIsTableRows = (pItem->Which() == SID_RULER_ROWS || pItem->Which() == SID_RULER_ROWS_VERTICAL);
+ if(!bHorz && !mxRulerImpl->bIsTableRows)
+ mxColumnItem->SetWhich(SID_RULER_BORDERS_VERTICAL);
+ }
+ else if(mxColumnItem && mxColumnItem->Which() == nSID)
+ //there are two groups of column items table/frame columns and table rows
+ //both can occur in vertical or horizontal mode
+ //the horizontal ruler handles the SID_RULER_BORDERS and SID_RULER_ROWS_VERTICAL
+ //and the vertical handles SID_RULER_BORDERS_VERTICAL and SID_RULER_ROWS
+ //if mxColumnItem is already set with one of the ids then a NULL pItem argument
+ //must not delete it
+ {
+ mxColumnItem.reset();
+ mxRulerImpl->bIsTableRows = false;
+ }
+ StartListening_Impl();
+}
+
+
+void SvxRuler::UpdateColumns()
+{
+ /* Update column view */
+ if(mxColumnItem && mxColumnItem->Count() > 1)
+ {
+ mpBorders.resize(mxColumnItem->Count());
+
+ RulerBorderStyle nStyleFlags = RulerBorderStyle::Variable;
+
+ bool bProtectColumns =
+ mxRulerImpl->aProtectItem->IsSizeProtected() ||
+ mxRulerImpl->aProtectItem->IsPosProtected();
+
+ if( !bProtectColumns )
+ {
+ nStyleFlags |= RulerBorderStyle::Moveable;
+ if( !mxColumnItem->IsTable() )
+ nStyleFlags |= RulerBorderStyle::Sizeable;
+ }
+
+ sal_uInt16 nBorders = mxColumnItem->Count();
+
+ if(!mxRulerImpl->bIsTableRows)
+ --nBorders;
+
+ for(sal_uInt16 i = 0; i < nBorders; ++i)
+ {
+ mpBorders[i].nStyle = nStyleFlags;
+ if(!mxColumnItem->At(i).bVisible)
+ mpBorders[i].nStyle |= RulerBorderStyle::Invisible;
+
+ mpBorders[i].nPos = ConvertPosPixel(mxColumnItem->At(i).nEnd + lAppNullOffset);
+
+ if(mxColumnItem->Count() == i + 1)
+ {
+ //with table rows the end of the table is contained in the
+ //column item but it has no width!
+ mpBorders[i].nWidth = 0;
+ }
+ else
+ {
+ mpBorders[i].nWidth = ConvertSizePixel(mxColumnItem->At(i + 1).nStart - mxColumnItem->At(i).nEnd);
+ }
+ mpBorders[i].nMinPos = ConvertPosPixel(mxColumnItem->At(i).nEndMin + lAppNullOffset);
+ mpBorders[i].nMaxPos = ConvertPosPixel(mxColumnItem->At(i).nEndMax + lAppNullOffset);
+ }
+ SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
+ }
+ else
+ {
+ SetBorders();
+ }
+}
+
+void SvxRuler::UpdateObject()
+{
+ /* Update view of object representation */
+ if (mxObjectItem)
+ {
+ DBG_ASSERT(!mpObjectBorders.empty(), "no Buffer");
+ // !! to the page margin
+ tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
+ mpObjectBorders[0].nPos =
+ ConvertPosPixel(mxObjectItem->GetStartX() -
+ nMargin + lAppNullOffset);
+ mpObjectBorders[1].nPos =
+ ConvertPosPixel(mxObjectItem->GetEndX() - nMargin + lAppNullOffset);
+ nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
+ mpObjectBorders[2].nPos =
+ ConvertPosPixel(mxObjectItem->GetStartY() -
+ nMargin + lAppNullOffset);
+ mpObjectBorders[3].nPos =
+ ConvertPosPixel(mxObjectItem->GetEndY() - nMargin + lAppNullOffset);
+
+ const sal_uInt16 nOffset = GetObjectBordersOff(0);
+ SetBorders(2, mpObjectBorders.data() + nOffset);
+ }
+ else
+ {
+ SetBorders();
+ }
+}
+
+void SvxRuler::UpdatePara()
+{
+
+ /* Update the view for paragraph indents:
+ Left margin, first line indent, right margin paragraph update
+ mpIndents[0] = Buffer for old intent
+ mpIndents[1] = Buffer for old intent
+ mpIndents[INDENT_FIRST_LINE] = first line indent
+ mpIndents[INDENT_LEFT_MARGIN] = left margin
+ mpIndents[INDENT_RIGHT_MARGIN] = right margin
+ */
+
+ // Dependence on PagePosItem
+ if (mxParaItem && mxPagePosItem && !mxObjectItem)
+ {
+ bool bRTLText = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+ // First-line indent is negative to the left paragraph margin
+ tools::Long nLeftFrameMargin = GetLeftFrameMargin();
+ tools::Long nRightFrameMargin = GetRightFrameMargin();
+ SetLeftFrameMargin(ConvertHPosPixel(nLeftFrameMargin));
+ SetRightFrameMargin(ConvertHPosPixel(nRightFrameMargin));
+
+ tools::Long leftMargin;
+ tools::Long leftFirstLine;
+ tools::Long rightMargin;
+
+ if(bRTLText)
+ {
+ leftMargin = nRightFrameMargin - mxParaItem->GetTextLeft() + lAppNullOffset;
+ leftFirstLine = leftMargin - mxParaItem->GetTextFirstLineOffset();
+ rightMargin = nLeftFrameMargin + mxParaItem->GetRight() + lAppNullOffset;
+ }
+ else
+ {
+ leftMargin = nLeftFrameMargin + mxParaItem->GetTextLeft() + lAppNullOffset;
+ leftFirstLine = leftMargin + mxParaItem->GetTextFirstLineOffset();
+ rightMargin = nRightFrameMargin - mxParaItem->GetRight() + lAppNullOffset;
+ }
+
+ mpIndents[INDENT_LEFT_MARGIN].nPos = ConvertHPosPixel(leftMargin);
+ mpIndents[INDENT_FIRST_LINE].nPos = ConvertHPosPixel(leftFirstLine);
+ mpIndents[INDENT_RIGHT_MARGIN].nPos = ConvertHPosPixel(rightMargin);
+
+ mpIndents[INDENT_FIRST_LINE].bInvisible = mxParaItem->IsAutoFirst();
+
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ else
+ {
+ if(!mpIndents.empty())
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos = 0;
+ mpIndents[INDENT_LEFT_MARGIN].nPos = 0;
+ mpIndents[INDENT_RIGHT_MARGIN].nPos = 0;
+ }
+ SetIndents(); // turn off
+ }
+}
+
+void SvxRuler::UpdatePara(const SvxLRSpaceItem *pItem) // new value of paragraph indents
+{
+ /* Store new value of paragraph indents */
+ if(bActive)
+ {
+ if(pItem)
+ mxParaItem.reset(new SvxLRSpaceItem(*pItem));
+ else
+ mxParaItem.reset();
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::UpdateBorder(const SvxLRSpaceItem * pItem)
+{
+ /* Border distance */
+ if(bActive)
+ {
+ if (pItem)
+ mxBorderItem.reset(new SvxLRSpaceItem(*pItem));
+ else
+ mxBorderItem.reset();
+
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::UpdatePage()
+{
+ /* Update view of position and width of page */
+ if (mxPagePosItem)
+ {
+ // all objects are automatically adjusted
+ if(bHorz)
+ {
+ SetPagePos(
+ pEditWin->LogicToPixel(mxPagePosItem->GetPos()).X(),
+ pEditWin->LogicToPixel(Size(mxPagePosItem->GetWidth(), 0)).
+ Width());
+ }
+ else
+ {
+ SetPagePos(
+ pEditWin->LogicToPixel(mxPagePosItem->GetPos()).Y(),
+ pEditWin->LogicToPixel(Size(0, mxPagePosItem->GetHeight())).
+ Height());
+ }
+ if(bAppSetNullOffset)
+ SetNullOffset(ConvertSizePixel(-lAppNullOffset + lLogicNullOffset));
+ }
+ else
+ {
+ SetPagePos();
+ }
+
+ tools::Long lPos = 0;
+ Point aOwnPos = GetPosPixel();
+ Point aEdtWinPos = pEditWin->GetPosPixel();
+ if( AllSettings::GetLayoutRTL() && bHorz )
+ {
+ //#i73321# in RTL the window and the ruler is not mirrored but the
+ // influence of the vertical ruler is inverted
+ Size aOwnSize = GetSizePixel();
+ Size aEdtWinSize = pEditWin->GetSizePixel();
+ lPos = aOwnSize.Width() - aEdtWinSize.Width();
+ lPos -= (aEdtWinPos - aOwnPos).X();
+ }
+ else
+ {
+ Point aPos(aEdtWinPos - aOwnPos);
+ lPos = bHorz ? aPos.X() : aPos.Y();
+ }
+
+ // Unfortunately, we get the offset of the edit window to the ruler never
+ // through a status message. So we set it ourselves if necessary.
+ if(lPos != mxRulerImpl->lOldWinPos)
+ {
+ mxRulerImpl->lOldWinPos=lPos;
+ SetWinPos(lPos);
+ }
+}
+
+void SvxRuler::Update(const SvxPagePosSizeItem *pItem) // new value of page attributes
+{
+ /* Store new value of page attributes */
+ if(bActive)
+ {
+ if(pItem)
+ mxPagePosItem.reset(new SvxPagePosSizeItem(*pItem));
+ else
+ mxPagePosItem.reset();
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::SetDefTabDist(tools::Long inDefTabDist) // New distance for DefaultTabs in App-Metrics
+{
+ if (lAppNullOffset == LONG_MAX)
+ UpdateFrame(); // hack: try to get lAppNullOffset initialized
+ /* New distance is set for DefaultTabs */
+ lDefTabDist = inDefTabDist;
+ if( !lDefTabDist )
+ lDefTabDist = 1;
+
+ UpdateTabs();
+}
+
+static sal_uInt16 ToSvTab_Impl(SvxTabAdjust eAdj)
+{
+ /* Internal conversion routine between SV-Tab.-Enum and Svx */
+ switch(eAdj) {
+ case SvxTabAdjust::Left: return RULER_TAB_LEFT;
+ case SvxTabAdjust::Right: return RULER_TAB_RIGHT;
+ case SvxTabAdjust::Decimal: return RULER_TAB_DECIMAL;
+ case SvxTabAdjust::Center: return RULER_TAB_CENTER;
+ case SvxTabAdjust::Default: return RULER_TAB_DEFAULT;
+ default: ; //prevent warning
+ }
+ return 0;
+}
+
+static SvxTabAdjust ToAttrTab_Impl(sal_uInt16 eAdj)
+{
+ switch(eAdj) {
+ case RULER_TAB_LEFT: return SvxTabAdjust::Left ;
+ case RULER_TAB_RIGHT: return SvxTabAdjust::Right ;
+ case RULER_TAB_DECIMAL: return SvxTabAdjust::Decimal ;
+ case RULER_TAB_CENTER: return SvxTabAdjust::Center ;
+ case RULER_TAB_DEFAULT: return SvxTabAdjust::Default ;
+ }
+ return SvxTabAdjust::Left;
+}
+
+void SvxRuler::UpdateTabs()
+{
+ if(IsDrag())
+ return;
+
+ if (mxPagePosItem && mxParaItem && mxTabStopItem && !mxObjectItem)
+ {
+ // buffer for DefaultTabStop
+ // Distance last Tab <-> Right paragraph margin / DefaultTabDist
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+
+ const tools::Long nLeftFrameMargin = GetLeftFrameMargin();
+ const tools::Long nRightFrameMargin = GetRightFrameMargin();
+
+ //#i24363# tab stops relative to indent
+ const tools::Long nParaItemTxtLeft = mxParaItem->GetTextLeft();
+
+ const tools::Long lParaIndent = nLeftFrameMargin + nParaItemTxtLeft;
+ const tools::Long lRightMargin = nRightFrameMargin - nParaItemTxtLeft;
+
+ const tools::Long lLastTab = mxTabStopItem->Count()
+ ? ConvertHPosPixel(mxTabStopItem->At(mxTabStopItem->Count() - 1).GetTabPos())
+ : 0;
+ const tools::Long lPosPixel = ConvertHPosPixel(lParaIndent) + lLastTab;
+ const tools::Long lRightIndent = ConvertHPosPixel(nRightFrameMargin - mxParaItem->GetRight());
+
+ tools::Long nDefTabDist = ConvertHPosPixel(lDefTabDist);
+
+ const sal_uInt16 nDefTabBuf = lPosPixel > lRightIndent || lLastTab > lRightIndent
+ ? 0
+ : static_cast<sal_uInt16>( (lRightIndent - lPosPixel) / nDefTabDist );
+
+ if(mxTabStopItem->Count() + TAB_GAP + nDefTabBuf > nTabBufSize)
+ {
+ // 10 (GAP) in stock
+ nTabBufSize = mxTabStopItem->Count() + TAB_GAP + nDefTabBuf + GAP;
+ mpTabs.resize(nTabBufSize);
+ }
+
+ nTabCount = 0;
+ sal_uInt16 j;
+
+ const tools::Long lParaIndentPix = ConvertSizePixel(lParaIndent);
+
+ tools::Long lTabStartLogic = (mxRulerImpl->bIsTabsRelativeToIndent ? lParaIndent : nLeftFrameMargin)
+ + lAppNullOffset;
+ if (bRTL)
+ {
+ lTabStartLogic = lParaIndent + lRightMargin - lTabStartLogic;
+ }
+ tools::Long lLastTabOffsetLogic = 0;
+ for(j = 0; j < mxTabStopItem->Count(); ++j)
+ {
+ const SvxTabStop* pTab = &mxTabStopItem->At(j);
+ lLastTabOffsetLogic = pTab->GetTabPos();
+ tools::Long lPos = lTabStartLogic + (bRTL ? -lLastTabOffsetLogic : lLastTabOffsetLogic);
+ mpTabs[nTabCount + TAB_GAP].nPos = ConvertHPosPixel(lPos);
+ mpTabs[nTabCount + TAB_GAP].nStyle = ToSvTab_Impl(pTab->GetAdjustment());
+ ++nTabCount;
+ }
+
+ // Adjust to previous-to-first default tab stop
+ lLastTabOffsetLogic -= lLastTabOffsetLogic % lDefTabDist;
+
+ // fill the rest with default Tabs
+ for (j = 0; j < nDefTabBuf; ++j)
+ {
+ //simply add the default distance to the last position
+ lLastTabOffsetLogic += lDefTabDist;
+ if (bRTL)
+ {
+ mpTabs[nTabCount + TAB_GAP].nPos =
+ ConvertHPosPixel(lTabStartLogic - lLastTabOffsetLogic);
+ if (mpTabs[nTabCount + TAB_GAP].nPos <= lParaIndentPix)
+ break;
+ }
+ else
+ {
+ mpTabs[nTabCount + TAB_GAP].nPos =
+ ConvertHPosPixel(lTabStartLogic + lLastTabOffsetLogic);
+ if (mpTabs[nTabCount + TAB_GAP].nPos >= lRightIndent)
+ break;
+ }
+
+ mpTabs[nTabCount + TAB_GAP].nStyle = RULER_TAB_DEFAULT;
+ ++nTabCount;
+ }
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+ DBG_ASSERT(nTabCount + TAB_GAP <= nTabBufSize, "BufferSize too small");
+ }
+ else
+ {
+ SetTabs();
+ }
+}
+
+void SvxRuler::Update(const SvxTabStopItem *pItem) // new value for tabs
+{
+ /* Store new value for tabs; delete old ones if possible */
+ if(!bActive)
+ return;
+
+ if(pItem)
+ {
+ mxTabStopItem.reset(new SvxTabStopItem(*pItem));
+ if(!bHorz)
+ mxTabStopItem->SetWhich(SID_ATTR_TABSTOP_VERTICAL);
+ }
+ else
+ {
+ mxTabStopItem.reset();
+ }
+ StartListening_Impl();
+}
+
+void SvxRuler::Update(const SvxObjectItem *pItem) // new value for objects
+{
+ /* Store new value for objects */
+ if(bActive)
+ {
+ if(pItem)
+ mxObjectItem.reset(new SvxObjectItem(*pItem));
+ else
+ mxObjectItem.reset();
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::SetNullOffsetLogic(tools::Long lVal) // Setting of the logic NullOffsets
+{
+ lAppNullOffset = lLogicNullOffset - lVal;
+ bAppSetNullOffset = true;
+ Ruler::SetNullOffset(ConvertSizePixel(lVal));
+ Update();
+}
+
+void SvxRuler::Update()
+{
+ /* Perform update of view */
+ if(IsDrag())
+ return;
+
+ UpdatePage();
+ UpdateFrame();
+ if(nFlags & SvxRulerSupportFlags::OBJECT)
+ UpdateObject();
+ else
+ UpdateColumns();
+
+ if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS | SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
+ UpdatePara();
+
+ if(nFlags & SvxRulerSupportFlags::TABS)
+ UpdateTabs();
+}
+
+tools::Long SvxRuler::GetPageWidth() const
+{
+ if (!mxPagePosItem)
+ return 0;
+ return bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
+}
+
+inline tools::Long SvxRuler::GetFrameLeft() const
+{
+ /* Get Left margin in Pixels */
+ return bAppSetNullOffset ?
+ GetMargin1() + ConvertSizePixel(lLogicNullOffset) :
+ Ruler::GetNullOffset();
+}
+
+tools::Long SvxRuler::GetFirstLineIndent() const
+{
+ /* Get First-line indent in pixels */
+ return mxParaItem ? mpIndents[INDENT_FIRST_LINE].nPos : GetMargin1();
+}
+
+tools::Long SvxRuler::GetLeftIndent() const
+{
+ /* Get Left paragraph margin in Pixels */
+ return mxParaItem ? mpIndents[INDENT_LEFT_MARGIN].nPos : GetMargin1();
+}
+
+tools::Long SvxRuler::GetRightIndent() const
+{
+ /* Get Right paragraph margin in Pixels */
+ return mxParaItem ? mpIndents[INDENT_RIGHT_MARGIN].nPos : GetMargin2();
+}
+
+tools::Long SvxRuler::GetLogicRightIndent() const
+{
+ /* Get Right paragraph margin in Logic */
+ return mxParaItem ? GetRightFrameMargin() - mxParaItem->GetRight() : GetRightFrameMargin();
+}
+
+// Left margin in App values, is either the margin (= 0) or the left edge of
+// the column that is set in the column attribute as current column.
+tools::Long SvxRuler::GetLeftFrameMargin() const
+{
+ // #126721# for some unknown reason the current column is set to 0xffff
+ DBG_ASSERT(!mxColumnItem || mxColumnItem->GetActColumn() < mxColumnItem->Count(),
+ "issue #126721# - invalid current column!");
+ tools::Long nLeft = 0;
+ if (mxColumnItem &&
+ mxColumnItem->Count() &&
+ mxColumnItem->IsConsistent())
+ {
+ nLeft = mxColumnItem->GetActiveColumnDescription().nStart;
+ }
+
+ if (mxBorderItem && (!mxColumnItem || mxColumnItem->IsTable()))
+ nLeft += mxBorderItem->GetLeft();
+
+ return nLeft;
+}
+
+inline tools::Long SvxRuler::GetLeftMin() const
+{
+ DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
+ if (mxMinMaxItem)
+ {
+ if (bHorz)
+ return mxMinMaxItem->GetValue().Left();
+ else
+ return mxMinMaxItem->GetValue().Top();
+ }
+ return 0;
+}
+
+inline tools::Long SvxRuler::GetRightMax() const
+{
+ DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
+ if (mxMinMaxItem)
+ {
+ if (bHorz)
+ return mxMinMaxItem->GetValue().Right();
+ else
+ return mxMinMaxItem->GetValue().Bottom();
+ }
+ return 0;
+}
+
+
+tools::Long SvxRuler::GetRightFrameMargin() const
+{
+ /* Get right frame margin (in logical units) */
+ if (mxColumnItem)
+ {
+ if (!IsActLastColumn(true))
+ {
+ return mxColumnItem->At(GetActRightColumn(true)).nEnd;
+ }
+ }
+
+ tools::Long lResult = lLogicNullOffset;
+
+ // If possible deduct right table entry
+ if(mxColumnItem && mxColumnItem->IsTable())
+ lResult += mxColumnItem->GetRight();
+ else if(bHorz && mxLRSpaceItem)
+ lResult += mxLRSpaceItem->GetRight();
+ else if(!bHorz && mxULSpaceItem)
+ lResult += mxULSpaceItem->GetLower();
+
+ if (bHorz && mxBorderItem && (!mxColumnItem || mxColumnItem->IsTable()))
+ lResult += mxBorderItem->GetRight();
+
+ if(bHorz)
+ lResult = mxPagePosItem->GetWidth() - lResult;
+ else
+ lResult = mxPagePosItem->GetHeight() - lResult;
+
+ return lResult;
+}
+
+#define NEG_FLAG ( (nFlags & SvxRulerSupportFlags::NEGATIVE_MARGINS) == \
+ SvxRulerSupportFlags::NEGATIVE_MARGINS )
+#define TAB_FLAG ( mxColumnItem && mxColumnItem->IsTable() )
+
+tools::Long SvxRuler::GetCorrectedDragPos( bool bLeft, bool bRight )
+{
+ /*
+ Corrects the position within the calculated limits. The limit values are in
+ pixels relative to the page edge.
+ */
+
+ const tools::Long lNullPix = Ruler::GetNullOffset();
+ tools::Long lDragPos = GetDragPos() + lNullPix;
+ bool bHoriRows = bHorz && mxRulerImpl->bIsTableRows;
+ if((bLeft || bHoriRows) && lDragPos < nMaxLeft)
+ lDragPos = nMaxLeft;
+ else if((bRight||bHoriRows) && lDragPos > nMaxRight)
+ lDragPos = nMaxRight;
+ return lDragPos - lNullPix;
+}
+
+static void ModifyTabs_Impl( sal_uInt16 nCount, // Number of Tabs
+ RulerTab* pTabs, // Tab buffer
+ tools::Long lDiff) // difference to be added
+{
+ /* Helper function, move all the tabs by a fixed value */
+ if( pTabs )
+ {
+ for(sal_uInt16 i = 0; i < nCount; ++i)
+ {
+ pTabs[i].nPos += lDiff;
+ }
+ }
+}
+
+void SvxRuler::DragMargin1()
+{
+ /* Dragging the left edge of frame */
+ tools::Long aDragPosition = GetCorrectedDragPos( !TAB_FLAG || !NEG_FLAG );
+
+ aDragPosition = MakePositionSticky(aDragPosition, GetRightFrameMargin(), false);
+
+ // Check if position changed
+ if (aDragPosition == 0)
+ return;
+
+ DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 3 : 7, bHorz);
+ if (mxColumnItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
+ DragBorders();
+ AdjustMargin1(aDragPosition);
+}
+
+void SvxRuler::AdjustMargin1(tools::Long lInputDiff)
+{
+ const tools::Long nOld = bAppSetNullOffset? GetMargin1(): GetNullOffset();
+ const tools::Long lDragPos = lInputDiff;
+
+ bool bProtectColumns =
+ mxRulerImpl->aProtectItem->IsSizeProtected() ||
+ mxRulerImpl->aProtectItem->IsPosProtected();
+
+ const RulerMarginStyle nMarginStyle =
+ bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
+
+ if(!bAppSetNullOffset)
+ {
+ tools::Long lDiff = lDragPos;
+ SetNullOffset(nOld + lDiff);
+ if (!mxColumnItem || !(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
+ {
+ SetMargin2( GetMargin2() - lDiff, nMarginStyle );
+
+ if (!mxColumnItem && !mxObjectItem && mxParaItem)
+ {
+ // Right indent of the old position
+ mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ if (mxObjectItem)
+ {
+ mpObjectBorders[GetObjectBordersOff(0)].nPos -= lDiff;
+ mpObjectBorders[GetObjectBordersOff(1)].nPos -= lDiff;
+ SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
+ }
+ if (mxColumnItem)
+ {
+ for(sal_uInt16 i = 0; i < mxColumnItem->Count()-1; ++i)
+ mpBorders[i].nPos -= lDiff;
+ SetBorders(mxColumnItem->Count()-1, mpBorders.data());
+ if(mxColumnItem->IsFirstAct())
+ {
+ // Right indent of the old position
+ if (mxParaItem)
+ {
+ mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ }
+ else
+ {
+ if (mxParaItem)
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
+ mpIndents[INDENT_LEFT_MARGIN].nPos -= lDiff;
+ mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ }
+ if(mxTabStopItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ &&!IsActFirstColumn())
+ {
+ ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), -lDiff);
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+ }
+ }
+ }
+ }
+ else
+ {
+ tools::Long lDiff = lDragPos - nOld;
+ SetMargin1(nOld + lDiff, nMarginStyle);
+
+ if (!mxColumnItem
+ || !(nDragType
+ & (SvxRulerDragFlags::OBJECT_SIZE_LINEAR
+ | SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
+ {
+ if (!mxColumnItem && !mxObjectItem && mxParaItem)
+ {
+ // Left indent of the old position
+ mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
+ mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+
+ if (mxColumnItem)
+ {
+ for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
+ mpBorders[i].nPos += lDiff;
+ SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
+ if (mxColumnItem->IsFirstAct())
+ {
+ // Left indent of the old position
+ if (mxParaItem)
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
+ mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ }
+ else
+ {
+ if (mxParaItem)
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
+ mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
+ mpIndents[INDENT_RIGHT_MARGIN].nPos += lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ }
+ }
+ if (mxTabStopItem)
+ {
+ ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), lDiff);
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+ }
+ }
+ }
+}
+
+void SvxRuler::DragMargin2()
+{
+ /* Dragging the right edge of frame */
+ tools::Long aDragPosition = GetCorrectedDragPos( true, !TAB_FLAG || !NEG_FLAG);
+ aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin(), false);
+ tools::Long lDiff = aDragPosition - GetMargin2();
+
+ // Check if position changed
+ if (lDiff == 0)
+ return;
+
+ if( mxRulerImpl->bIsTableRows &&
+ !bHorz &&
+ mxColumnItem &&
+ (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
+ {
+ DragBorders();
+ }
+
+ bool bProtectColumns =
+ mxRulerImpl->aProtectItem->IsSizeProtected() ||
+ mxRulerImpl->aProtectItem->IsPosProtected();
+
+ const RulerMarginStyle nMarginStyle = bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
+
+ SetMargin2( aDragPosition, nMarginStyle );
+
+ // Right indent of the old position
+ if ((!mxColumnItem || IsActLastColumn()) && mxParaItem)
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+
+ DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 5 : 7, bHorz);
+}
+
+void SvxRuler::DragIndents()
+{
+ /* Dragging the paragraph indents */
+ tools::Long aDragPosition = NEG_FLAG ? GetDragPos() : GetCorrectedDragPos();
+ const sal_uInt16 nIndex = GetDragAryPos() + INDENT_GAP;
+
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+
+ if(nIndex == INDENT_RIGHT_MARGIN)
+ aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetLeftFrameMargin() : GetRightFrameMargin());
+ else
+ aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
+
+ const tools::Long lDiff = mpIndents[nIndex].nPos - aDragPosition;
+
+ // Check if position changed
+ if (lDiff == 0)
+ return;
+
+ if((nIndex == INDENT_FIRST_LINE || nIndex == INDENT_LEFT_MARGIN ) &&
+ !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
+ }
+
+ mpIndents[nIndex].nPos = aDragPosition;
+
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ DrawLine_Impl(lTabPos, 1, bHorz);
+}
+
+void SvxRuler::DrawLine_Impl(tools::Long& lTabPosition, int nNew, bool bHorizontal)
+{
+ /*
+ Output routine for the ledger line when moving tabs, tables and other
+ columns
+ */
+ if(bHorizontal)
+ {
+ const tools::Long nHeight = pEditWin->GetOutDev()->GetOutputSize().Height();
+ Point aZero = pEditWin->GetMapMode().GetOrigin();
+ if(lTabPosition != -1)
+ {
+ pEditWin->InvertTracking(
+ tools::Rectangle( Point(lTabPosition, -aZero.Y()),
+ Point(lTabPosition, -aZero.Y() + nHeight)),
+ ShowTrackFlags::Split | ShowTrackFlags::Clip );
+ }
+ if( nNew & 1 )
+ {
+ tools::Long nDrapPosition = GetCorrectedDragPos( ( nNew & 4 ) != 0, ( nNew & 2 ) != 0 );
+ nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
+ lTabPosition = ConvertHSizeLogic( nDrapPosition + GetNullOffset() );
+ if (mxPagePosItem)
+ lTabPosition += mxPagePosItem->GetPos().X();
+ pEditWin->InvertTracking(
+ tools::Rectangle( Point(lTabPosition, -aZero.Y()),
+ Point(lTabPosition, -aZero.Y() + nHeight) ),
+ ShowTrackFlags::Clip | ShowTrackFlags::Split );
+ }
+ }
+ else
+ {
+ const tools::Long nWidth = pEditWin->GetOutDev()->GetOutputSize().Width();
+ Point aZero = pEditWin->GetMapMode().GetOrigin();
+ if(lTabPosition != -1)
+ {
+ pEditWin->InvertTracking(
+ tools::Rectangle( Point(-aZero.X(), lTabPosition),
+ Point(-aZero.X() + nWidth, lTabPosition)),
+ ShowTrackFlags::Split | ShowTrackFlags::Clip );
+ }
+
+ if(nNew & 1)
+ {
+ tools::Long nDrapPosition = GetCorrectedDragPos();
+ nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
+ lTabPosition = ConvertVSizeLogic(nDrapPosition + GetNullOffset());
+ if (mxPagePosItem)
+ lTabPosition += mxPagePosItem->GetPos().Y();
+ pEditWin->InvertTracking(
+ tools::Rectangle( Point(-aZero.X(), lTabPosition),
+ Point(-aZero.X()+nWidth, lTabPosition)),
+ ShowTrackFlags::Clip | ShowTrackFlags::Split );
+ }
+ }
+}
+
+void SvxRuler::DragTabs()
+{
+ /* Dragging of Tabs */
+ tools::Long aDragPosition = GetCorrectedDragPos(true, false);
+ aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin());
+
+ sal_uInt16 nIdx = GetDragAryPos() + TAB_GAP;
+ tools::Long nDiff = aDragPosition - mpTabs[nIdx].nPos;
+ if (nDiff == 0)
+ return;
+
+ DrawLine_Impl(lTabPos, 7, bHorz);
+
+ if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
+ {
+
+ for(sal_uInt16 i = nIdx; i < nTabCount; ++i)
+ {
+ mpTabs[i].nPos += nDiff;
+ // limit on maximum
+ if(mpTabs[i].nPos > GetMargin2())
+ mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
+ else
+ mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
+ }
+ }
+ else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ {
+ mxRulerImpl->nTotalDist -= nDiff;
+ mpTabs[nIdx].nPos = aDragPosition;
+ for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
+ {
+ if(mpTabs[i].nStyle & RULER_TAB_DEFAULT)
+ // can be canceled at the DefaultTabs
+ break;
+ tools::Long nDelta = mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i];
+ nDelta /= 1000;
+ mpTabs[i].nPos = mpTabs[nIdx].nPos + nDelta;
+ if(mpTabs[i].nPos + GetNullOffset() > nMaxRight)
+ mpTabs[i].nStyle |= RULER_STYLE_INVISIBLE;
+ else
+ mpTabs[i].nStyle &= ~RULER_STYLE_INVISIBLE;
+ }
+ }
+ else
+ {
+ mpTabs[nIdx].nPos = aDragPosition;
+ }
+
+ if(IsDragDelete())
+ mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
+ else
+ mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+}
+
+void SvxRuler::SetActive(bool bOn)
+{
+ if(bOn)
+ {
+ Activate();
+ }
+ else
+ Deactivate();
+ if(bActive!=bOn)
+ {
+ pBindings->EnterRegistrations();
+ if(bOn)
+ for(sal_uInt16 i=0;i<mxRulerImpl->nControllerItems;i++)
+ pCtrlItems[i]->ReBind();
+ else
+ for(sal_uInt16 j=0;j<mxRulerImpl->nControllerItems;j++)
+ pCtrlItems[j]->UnBind();
+ pBindings->LeaveRegistrations();
+ }
+ bActive = bOn;
+}
+
+void SvxRuler::UpdateParaContents_Impl(
+ tools::Long lDifference,
+ UpdateType eType) // Art (all, left or right)
+{
+ /* Helper function; carry Tabs and Paragraph Margins */
+ switch(eType)
+ {
+ case UpdateType::MoveRight:
+ mpIndents[INDENT_RIGHT_MARGIN].nPos += lDifference;
+ break;
+ case UpdateType::MoveLeft:
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos += lDifference;
+ mpIndents[INDENT_LEFT_MARGIN].nPos += lDifference;
+ if (!mpTabs.empty())
+ {
+ for(sal_uInt16 i = 0; i < nTabCount+TAB_GAP; ++i)
+ {
+ mpTabs[i].nPos += lDifference;
+ }
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+ }
+ break;
+ }
+ }
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+}
+
+void SvxRuler::DragBorders()
+{
+ /* Dragging of Borders (Tables and other columns) */
+ bool bLeftIndentsCorrected = false;
+ bool bRightIndentsCorrected = false;
+ int nIndex;
+
+ if(GetDragType() == RulerType::Border)
+ {
+ DrawLine_Impl(lTabPos, 7, bHorz);
+ nIndex = GetDragAryPos();
+ }
+ else
+ {
+ nIndex = 0;
+ }
+
+ RulerDragSize nDragSize = GetDragSize();
+ tools::Long lDiff = 0;
+
+ // the drag position has to be corrected to be able to prevent borders from passing each other
+ tools::Long lPos = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
+
+ switch(nDragSize)
+ {
+ case RulerDragSize::Move:
+ {
+ if(GetDragType() == RulerType::Border)
+ lDiff = lPos - nDragOffset - mpBorders[nIndex].nPos;
+ else
+ lDiff = GetDragType() == RulerType::Margin1 ? lPos - mxRulerImpl->lLastLMargin : lPos - mxRulerImpl->lLastRMargin;
+
+ if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
+ {
+ tools::Long nRight = GetMargin2() - glMinFrame; // Right limiters
+ for(int i = mpBorders.size() - 2; i >= nIndex; --i)
+ {
+ tools::Long l = mpBorders[i].nPos;
+ mpBorders[i].nPos += lDiff;
+ mpBorders[i].nPos = std::min(mpBorders[i].nPos, nRight - mpBorders[i].nWidth);
+ nRight = mpBorders[i].nPos - glMinFrame;
+ // RR update the column
+ if(i == GetActRightColumn())
+ {
+ UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
+ bRightIndentsCorrected = true;
+ }
+ // LAR, EZE update the column
+ else if(i == GetActLeftColumn())
+ {
+ UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
+ bLeftIndentsCorrected = true;
+ }
+ }
+ }
+ else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ {
+ int nLimit;
+ tools::Long lLeft;
+ int nStartLimit = mpBorders.size() - 2;
+ switch(GetDragType())
+ {
+ default: ;//prevent warning
+ OSL_FAIL("svx::SvxRuler::DragBorders(), unknown drag type!" );
+ [[fallthrough]];
+ case RulerType::Border:
+ if(mxRulerImpl->bIsTableRows)
+ {
+ mpBorders[nIndex].nPos += lDiff;
+ if(bHorz)
+ {
+ lLeft = mpBorders[nIndex].nPos;
+ mxRulerImpl->nTotalDist -= lDiff;
+ nLimit = nIndex + 1;
+ }
+ else
+ {
+ lLeft = 0;
+ nStartLimit = nIndex - 1;
+ mxRulerImpl->nTotalDist += lDiff;
+ nLimit = 0;
+ }
+ }
+ else
+ {
+ nLimit = nIndex + 1;
+ mpBorders[nIndex].nPos += lDiff;
+ lLeft = mpBorders[nIndex].nPos;
+ mxRulerImpl->nTotalDist -= lDiff;
+ }
+ break;
+ case RulerType::Margin1:
+ nLimit = 0;
+ lLeft = mxRulerImpl->lLastLMargin + lDiff;
+ mxRulerImpl->nTotalDist -= lDiff;
+ break;
+ case RulerType::Margin2:
+ nLimit = 0;
+ lLeft= 0;
+ nStartLimit = mpBorders.size() - 2;
+ mxRulerImpl->nTotalDist += lDiff;
+ break;
+ }
+
+ for(int i = nStartLimit; i >= nLimit; --i)
+ {
+
+ tools::Long l = mpBorders[i].nPos;
+ mpBorders[i].nPos =
+ lLeft +
+ (mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i]) / 1000 +
+ mxRulerImpl->pBlockBuf[i];
+
+ // RR update the column
+ if(!mxRulerImpl->bIsTableRows)
+ {
+ if(i == GetActRightColumn())
+ {
+ UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
+ bRightIndentsCorrected = true;
+ }
+ // LAR, EZE update the column
+ else if(i == GetActLeftColumn())
+ {
+ UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
+ bLeftIndentsCorrected = true;
+ }
+ }
+ }
+ if(mxRulerImpl->bIsTableRows)
+ {
+ //in vertical tables the left borders have to be moved
+ if(bHorz)
+ {
+ for(int i = 0; i < nIndex; ++i)
+ mpBorders[i].nPos += lDiff;
+ AdjustMargin1(lDiff);
+ }
+ else
+ {
+ //otherwise the right borders are moved
+ for(int i = mxColumnItem->Count() - 1; i > nIndex; --i)
+ mpBorders[i].nPos += lDiff;
+ SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
+ }
+ }
+ }
+ else if(mxRulerImpl->bIsTableRows)
+ {
+ //moving rows: if a row is resized all following rows
+ //have to be moved by the same amount.
+ //This includes the left border when the table is not limited
+ //to a lower frame border.
+ int nLimit;
+ if(GetDragType()==RulerType::Border)
+ {
+ nLimit = nIndex + 1;
+ mpBorders[nIndex].nPos += lDiff;
+ }
+ else
+ {
+ nLimit=0;
+ }
+ //in vertical tables the left borders have to be moved
+ if(bHorz)
+ {
+ for(int i = 0; i < nIndex; ++i)
+ {
+ mpBorders[i].nPos += lDiff;
+ }
+ AdjustMargin1(lDiff);
+ }
+ else
+ {
+ //otherwise the right borders are moved
+ for(int i = mpBorders.size() - 2; i >= nLimit; --i)
+ {
+ mpBorders[i].nPos += lDiff;
+ }
+ SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
+ }
+ }
+ else
+ mpBorders[nIndex].nPos += lDiff;
+ break;
+ }
+ case RulerDragSize::N1:
+ {
+ lDiff = lPos - mpBorders[nIndex].nPos;
+ mpBorders[nIndex].nWidth += mpBorders[nIndex].nPos - lPos;
+ mpBorders[nIndex].nPos = lPos;
+ break;
+ }
+ case RulerDragSize::N2:
+ {
+ const tools::Long nOld = mpBorders[nIndex].nWidth;
+ mpBorders[nIndex].nWidth = lPos - mpBorders[nIndex].nPos;
+ lDiff = mpBorders[nIndex].nWidth - nOld;
+ break;
+ }
+ }
+ if(!bRightIndentsCorrected &&
+ GetActRightColumn() == nIndex &&
+ nDragSize != RulerDragSize::N2 &&
+ !mpIndents.empty() &&
+ !mxRulerImpl->bIsTableRows)
+ {
+ UpdateParaContents_Impl(lDiff, UpdateType::MoveRight);
+ }
+ else if(!bLeftIndentsCorrected &&
+ GetActLeftColumn() == nIndex &&
+ nDragSize != RulerDragSize::N1 &&
+ !mpIndents.empty())
+ {
+ UpdateParaContents_Impl(lDiff, UpdateType::MoveLeft);
+ }
+ SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
+}
+
+void SvxRuler::DragObjectBorder()
+{
+ /* Dragging of object edges */
+ if(RulerDragSize::Move == GetDragSize())
+ {
+ const tools::Long lPosition = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
+
+ const sal_uInt16 nIdx = GetDragAryPos();
+ mpObjectBorders[GetObjectBordersOff(nIdx)].nPos = lPosition;
+ SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
+ DrawLine_Impl(lTabPos, 7, bHorz);
+
+ }
+}
+
+void SvxRuler::ApplyMargins()
+{
+ /* Applying margins; changed by dragging. */
+ const SfxPoolItem* pItem = nullptr;
+ sal_uInt16 nId = SID_ATTR_LONG_LRSPACE;
+
+ if(bHorz)
+ {
+ const tools::Long lOldNull = lLogicNullOffset;
+ if(mxRulerImpl->lMaxLeftLogic != -1 && nMaxLeft == GetMargin1() + Ruler::GetNullOffset())
+ {
+ lLogicNullOffset = mxRulerImpl->lMaxLeftLogic;
+ mxLRSpaceItem->SetLeft(lLogicNullOffset);
+ }
+ else
+ {
+ lLogicNullOffset = ConvertHPosLogic(GetFrameLeft()) - lAppNullOffset;
+ mxLRSpaceItem->SetLeft(PixelHAdjust(lLogicNullOffset, mxLRSpaceItem->GetLeft()));
+ }
+
+ if(bAppSetNullOffset)
+ {
+ lAppNullOffset += lLogicNullOffset - lOldNull;
+ }
+
+ tools::Long nRight;
+ if(mxRulerImpl->lMaxRightLogic != -1
+ && nMaxRight == GetMargin2() + Ruler::GetNullOffset())
+ {
+ nRight = GetPageWidth() - mxRulerImpl->lMaxRightLogic;
+ }
+ else
+ {
+ nRight = std::max(tools::Long(0),
+ mxPagePosItem->GetWidth() - mxLRSpaceItem->GetLeft() -
+ (ConvertHPosLogic(GetMargin2()) - lAppNullOffset));
+
+ nRight = PixelHAdjust( nRight, mxLRSpaceItem->GetRight());
+ }
+ mxLRSpaceItem->SetRight(nRight);
+
+ pItem = mxLRSpaceItem.get();
+
+#ifdef DEBUGLIN
+ Debug_Impl(pEditWin, *mxLRSpaceItem);
+#endif // DEBUGLIN
+
+ }
+ else
+ {
+ const tools::Long lOldNull = lLogicNullOffset;
+ lLogicNullOffset =
+ ConvertVPosLogic(GetFrameLeft()) -
+ lAppNullOffset;
+ mxULSpaceItem->SetUpper(
+ PixelVAdjust(lLogicNullOffset, mxULSpaceItem->GetUpper()));
+ if(bAppSetNullOffset)
+ {
+ lAppNullOffset += lLogicNullOffset - lOldNull;
+ }
+ mxULSpaceItem->SetLower(
+ PixelVAdjust(
+ std::max(tools::Long(0), mxPagePosItem->GetHeight() -
+ mxULSpaceItem->GetUpper() -
+ (ConvertVPosLogic(GetMargin2()) -
+ lAppNullOffset)), mxULSpaceItem->GetLower()));
+ pItem = mxULSpaceItem.get();
+ nId = SID_ATTR_LONG_ULSPACE;
+
+#ifdef DEBUGLIN
+ Debug_Impl(pEditWin,*mxULSpaceItem);
+#endif // DEBUGLIN
+
+ }
+ pBindings->GetDispatcher()->ExecuteList(nId, SfxCallMode::RECORD, { pItem });
+ if (mxTabStopItem)
+ UpdateTabs();
+}
+
+tools::Long SvxRuler::RoundToCurrentMapMode(tools::Long lValue) const
+{
+ RulerUnitData aUnitData = GetCurrentRulerUnit();
+ double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
+
+ tools::Long lNewValue = OutputDevice::LogicToLogic(Size(lValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ lNewValue = (rtl::math::round(lNewValue / static_cast<double>(aUnitData.nTickUnit) * aRoundingFactor) / aRoundingFactor) * aUnitData.nTickUnit;
+ return OutputDevice::LogicToLogic(Size(lNewValue, 0), GetCurrentMapMode(), pEditWin->GetMapMode()).Width();
+}
+
+void SvxRuler::ApplyIndents()
+{
+ /* Applying paragraph settings; changed by dragging. */
+
+ tools::Long nLeftFrameMargin = GetLeftFrameMargin();
+
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+
+ tools::Long nNewTxtLeft;
+ tools::Long nNewFirstLineOffset;
+ tools::Long nNewRight;
+
+ tools::Long nFirstLine = ConvertPosLogic(mpIndents[INDENT_FIRST_LINE].nPos);
+ tools::Long nLeftMargin = ConvertPosLogic(mpIndents[INDENT_LEFT_MARGIN].nPos);
+ tools::Long nRightMargin = ConvertPosLogic(mpIndents[INDENT_RIGHT_MARGIN].nPos);
+
+ if(mxColumnItem && ((bRTL && !IsActLastColumn(true)) || (!bRTL && !IsActFirstColumn(true))))
+ {
+ if(bRTL)
+ {
+ tools::Long nRightColumn = GetActRightColumn(true);
+ tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos);
+ nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
+ }
+ else
+ {
+ tools::Long nLeftColumn = GetActLeftColumn(true);
+ tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
+ nNewTxtLeft = nLeftMargin - nLeftBorder - lAppNullOffset;
+ }
+ }
+ else
+ {
+ if(bRTL)
+ {
+ tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
+ nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
+ }
+ else
+ {
+ tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
+ nNewTxtLeft = nLeftBorder + nLeftMargin - nLeftFrameMargin - lAppNullOffset;
+ }
+ }
+
+ if(bRTL)
+ nNewFirstLineOffset = nLeftMargin - nFirstLine - lAppNullOffset;
+ else
+ nNewFirstLineOffset = nFirstLine - nLeftMargin - lAppNullOffset;
+
+ if(mxColumnItem && ((!bRTL && !IsActLastColumn(true)) || (bRTL && !IsActFirstColumn(true))))
+ {
+ if(bRTL)
+ {
+ tools::Long nLeftColumn = GetActLeftColumn(true);
+ tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
+ nNewRight = nRightMargin - nLeftBorder - lAppNullOffset;
+ }
+ else
+ {
+ tools::Long nRightColumn = GetActRightColumn(true);
+ tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos);
+ nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
+ }
+ }
+ else
+ {
+ if(bRTL)
+ {
+ tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
+ nNewRight = nLeftBorder + nRightMargin - nLeftFrameMargin - lAppNullOffset;
+ }
+ else
+ {
+ tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
+ nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
+ }
+ }
+
+ if (mbSnapping)
+ {
+ nNewTxtLeft = RoundToCurrentMapMode(nNewTxtLeft);
+ nNewFirstLineOffset = RoundToCurrentMapMode(nNewFirstLineOffset);
+ nNewRight = RoundToCurrentMapMode(nNewRight);
+ }
+
+ mxParaItem->SetTextFirstLineOffset(sal::static_int_cast<short>(nNewFirstLineOffset));
+ mxParaItem->SetTextLeft(nNewTxtLeft);
+ mxParaItem->SetRight(nNewRight);
+
+ sal_uInt16 nParagraphId = bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL;
+ pBindings->GetDispatcher()->ExecuteList(nParagraphId, SfxCallMode::RECORD,
+ { mxParaItem.get() });
+ UpdateTabs();
+}
+
+void SvxRuler::ApplyTabs()
+{
+ /* Apply tab settings, changed by dragging. */
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+ const sal_uInt16 nCoreIdx = GetDragAryPos();
+ if(IsDragDelete())
+ {
+ mxTabStopItem->Remove(nCoreIdx);
+ }
+ else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType ||
+ SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType)
+ {
+ SvxTabStopItem *pItem = new SvxTabStopItem(mxTabStopItem->Which());
+ //remove default tab stops
+ for ( sal_uInt16 i = 0; i < pItem->Count(); )
+ {
+ if ( SvxTabAdjust::Default == (*pItem)[i].GetAdjustment() )
+ {
+ pItem->Remove(i);
+ continue;
+ }
+ ++i;
+ }
+
+ sal_uInt16 j;
+ for(j = 0; j < nCoreIdx; ++j)
+ {
+ pItem->Insert(mxTabStopItem->At(j));
+ }
+ for(; j < mxTabStopItem->Count(); ++j)
+ {
+ SvxTabStop aTabStop = mxTabStopItem->At(j);
+ aTabStop.GetTabPos() = PixelHAdjust(
+ ConvertHPosLogic(
+ mpTabs[j + TAB_GAP].nPos - GetLeftIndent()) - lAppNullOffset,
+ aTabStop.GetTabPos());
+ pItem->Insert(aTabStop);
+ }
+ mxTabStopItem.reset(pItem);
+ }
+ else if( mxTabStopItem->Count() == 0 )
+ return;
+ else
+ {
+ SvxTabStop aTabStop = mxTabStopItem->At(nCoreIdx);
+ if( mxRulerImpl->lMaxRightLogic != -1 &&
+ mpTabs[nCoreIdx + TAB_GAP].nPos + Ruler::GetNullOffset() == nMaxRight )
+ {
+ // Set tab pos exactly at the right indent
+ tools::Long nTmpLeftIndentLogic
+ = lAppNullOffset + (bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
+ if (mxRulerImpl->bIsTabsRelativeToIndent && mxParaItem)
+ {
+ nTmpLeftIndentLogic += bRTL ? mxParaItem->GetRight() : mxParaItem->GetLeft();
+ }
+ aTabStop.GetTabPos()
+ = mxRulerImpl->lMaxRightLogic - lLogicNullOffset - nTmpLeftIndentLogic;
+ }
+ else
+ {
+ if(bRTL)
+ {
+ //#i24363# tab stops relative to indent
+ const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
+ GetLeftIndent() :
+ ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset );
+
+ tools::Long nNewPosition = ConvertHPosLogic(nTmpLeftIndent - mpTabs[nCoreIdx + TAB_GAP].nPos);
+ aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
+ }
+ else
+ {
+ //#i24363# tab stops relative to indent
+ const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
+ GetLeftIndent() :
+ ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset );
+
+ tools::Long nNewPosition = ConvertHPosLogic(mpTabs[nCoreIdx + TAB_GAP].nPos - nTmpLeftIndent);
+ aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
+ }
+ }
+ mxTabStopItem->Remove(nCoreIdx);
+ mxTabStopItem->Insert(aTabStop);
+ }
+ sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
+ pBindings->GetDispatcher()->ExecuteList(nTabStopId, SfxCallMode::RECORD,
+ { mxTabStopItem.get() });
+ UpdateTabs();
+}
+
+void SvxRuler::ApplyBorders()
+{
+ /* Applying (table) column settings; changed by dragging. */
+ if(mxColumnItem->IsTable())
+ {
+ tools::Long lValue = GetFrameLeft();
+ if(lValue != mxRulerImpl->nColLeftPix)
+ {
+ tools::Long nLeft = PixelHAdjust(
+ ConvertHPosLogic(lValue) -
+ lAppNullOffset,
+ mxColumnItem->GetLeft());
+ mxColumnItem->SetLeft(nLeft);
+ }
+
+ lValue = GetMargin2();
+
+ if(lValue != mxRulerImpl->nColRightPix)
+ {
+ tools::Long nWidthOrHeight = bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
+ tools::Long nRight = PixelHAdjust(
+ nWidthOrHeight -
+ mxColumnItem->GetLeft() -
+ ConvertHPosLogic(lValue) -
+ lAppNullOffset,
+ mxColumnItem->GetRight() );
+ mxColumnItem->SetRight(nRight);
+ }
+ }
+
+ for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
+ {
+ tools::Long& nEnd = mxColumnItem->At(i).nEnd;
+ nEnd = PixelHAdjust(
+ ConvertPosLogic(mpBorders[i].nPos),
+ mxColumnItem->At(i).nEnd);
+ tools::Long& nStart = mxColumnItem->At(i + 1).nStart;
+ nStart = PixelHAdjust(
+ ConvertSizeLogic(mpBorders[i].nPos +
+ mpBorders[i].nWidth) -
+ lAppNullOffset,
+ mxColumnItem->At(i + 1).nStart);
+ // It may be that, due to the PixelHAdjust readjustment to old values,
+ // the width becomes < 0. This we readjust.
+ if( nEnd > nStart )
+ nStart = nEnd;
+ }
+
+#ifdef DEBUGLIN
+ Debug_Impl(pEditWin,*mxColumnItem);
+#endif // DEBUGLIN
+
+ SfxBoolItem aFlag(SID_RULER_ACT_LINE_ONLY,
+ bool(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY));
+
+ sal_uInt16 nColId = mxRulerImpl->bIsTableRows ? (bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL) :
+ (bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
+
+ pBindings->GetDispatcher()->ExecuteList(nColId, SfxCallMode::RECORD,
+ { mxColumnItem.get(), &aFlag });
+}
+
+void SvxRuler::ApplyObject()
+{
+ /* Applying object settings, changed by dragging. */
+
+ // to the page margin
+ tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
+ tools::Long nStartX = PixelAdjust(
+ ConvertPosLogic(mpObjectBorders[0].nPos) +
+ nMargin -
+ lAppNullOffset,
+ mxObjectItem->GetStartX());
+ mxObjectItem->SetStartX(nStartX);
+
+ tools::Long nEndX = PixelAdjust(
+ ConvertPosLogic(mpObjectBorders[1].nPos) +
+ nMargin -
+ lAppNullOffset,
+ mxObjectItem->GetEndX());
+ mxObjectItem->SetEndX(nEndX);
+
+ nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
+ tools::Long nStartY = PixelAdjust(
+ ConvertPosLogic(mpObjectBorders[2].nPos) +
+ nMargin -
+ lAppNullOffset,
+ mxObjectItem->GetStartY());
+ mxObjectItem->SetStartY(nStartY);
+
+ tools::Long nEndY = PixelAdjust(
+ ConvertPosLogic(mpObjectBorders[3].nPos) +
+ nMargin -
+ lAppNullOffset,
+ mxObjectItem->GetEndY());
+ mxObjectItem->SetEndY(nEndY);
+
+ pBindings->GetDispatcher()->ExecuteList(SID_RULER_OBJECT,
+ SfxCallMode::RECORD, { mxObjectItem.get() });
+}
+
+void SvxRuler::PrepareProportional_Impl(RulerType eType)
+{
+ /*
+ Preparation proportional dragging, and it is calculated based on the
+ proportional share of the total width in parts per thousand.
+ */
+ mxRulerImpl->nTotalDist = GetMargin2();
+ switch(eType)
+ {
+ case RulerType::Margin2:
+ case RulerType::Margin1:
+ case RulerType::Border:
+ {
+ DBG_ASSERT(mxColumnItem, "no ColumnItem");
+
+ mxRulerImpl->SetPercSize(mxColumnItem->Count());
+
+ tools::Long lPos;
+ tools::Long lWidth=0;
+ sal_uInt16 nStart;
+ sal_uInt16 nIdx=GetDragAryPos();
+ tools::Long lActWidth=0;
+ tools::Long lActBorderSum;
+ tools::Long lOrigLPos;
+
+ if(eType != RulerType::Border)
+ {
+ lOrigLPos = GetMargin1();
+ nStart = 0;
+ lActBorderSum = 0;
+ }
+ else
+ {
+ if(mxRulerImpl->bIsTableRows &&!bHorz)
+ {
+ lOrigLPos = GetMargin1();
+ nStart = 0;
+ }
+ else
+ {
+ lOrigLPos = mpBorders[nIdx].nPos + mpBorders[nIdx].nWidth;
+ nStart = 1;
+ }
+ lActBorderSum = mpBorders[nIdx].nWidth;
+ }
+
+ //in horizontal mode the percentage value has to be
+ //calculated on a "current change" position base
+ //because the height of the table changes while dragging
+ if(mxRulerImpl->bIsTableRows && RulerType::Border == eType)
+ {
+ sal_uInt16 nStartBorder;
+ sal_uInt16 nEndBorder;
+ if(bHorz)
+ {
+ nStartBorder = nIdx + 1;
+ nEndBorder = mxColumnItem->Count() - 1;
+ }
+ else
+ {
+ nStartBorder = 0;
+ nEndBorder = nIdx;
+ }
+
+ lWidth = mpBorders[nIdx].nPos;
+ if(bHorz)
+ lWidth = GetMargin2() - lWidth;
+ mxRulerImpl->nTotalDist = lWidth;
+ lPos = mpBorders[nIdx].nPos;
+
+ for(sal_uInt16 i = nStartBorder; i < nEndBorder; ++i)
+ {
+ if(bHorz)
+ {
+ lActWidth += mpBorders[i].nPos - lPos;
+ lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
+ }
+ else
+ lActWidth = mpBorders[i].nPos;
+ mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
+ / mxRulerImpl->nTotalDist);
+ mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
+ lActBorderSum += mpBorders[i].nWidth;
+ }
+ }
+ else
+ {
+ lPos = lOrigLPos;
+ for(sal_uInt16 ii = nStart; ii < mxColumnItem->Count() - 1; ++ii)
+ {
+ lWidth += mpBorders[ii].nPos - lPos;
+ lPos = mpBorders[ii].nPos + mpBorders[ii].nWidth;
+ }
+
+ lWidth += GetMargin2() - lPos;
+ mxRulerImpl->nTotalDist = lWidth;
+ lPos = lOrigLPos;
+
+ for(sal_uInt16 i = nStart; i < mxColumnItem->Count() - 1; ++i)
+ {
+ lActWidth += mpBorders[i].nPos - lPos;
+ lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
+ mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
+ / mxRulerImpl->nTotalDist);
+ mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
+ lActBorderSum += mpBorders[i].nWidth;
+ }
+ }
+ }
+ break;
+ case RulerType::Tab:
+ {
+ const sal_uInt16 nIdx = GetDragAryPos()+TAB_GAP;
+ mxRulerImpl->nTotalDist -= mpTabs[nIdx].nPos;
+ mxRulerImpl->SetPercSize(nTabCount);
+ for(sal_uInt16 n=0;n<=nIdx;mxRulerImpl->pPercBuf[n++]=0) ;
+ for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
+ {
+ const tools::Long nDelta = mpTabs[i].nPos - mpTabs[nIdx].nPos;
+ mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((nDelta * 1000) / mxRulerImpl->nTotalDist);
+ }
+ break;
+ }
+ default: break;
+ }
+}
+
+void SvxRuler::EvalModifier()
+{
+ /*
+ Eval Drag Modifier
+ Shift: move linear
+ Control: move proportional
+ Shift + Control: Table: only current line
+ Alt: disable snapping
+ Alt + Shift: coarse snapping
+ */
+
+ sal_uInt16 nModifier = GetDragModifier();
+ if(mxRulerImpl->bIsTableRows)
+ {
+ //rows can only be moved in one way, additionally current column is possible
+ if(nModifier == KEY_SHIFT)
+ nModifier = 0;
+ }
+
+ switch(nModifier)
+ {
+ case KEY_SHIFT:
+ nDragType = SvxRulerDragFlags::OBJECT_SIZE_LINEAR;
+ break;
+ case KEY_MOD2 | KEY_SHIFT:
+ mbCoarseSnapping = true;
+ break;
+ case KEY_MOD2:
+ mbSnapping = false;
+ break;
+ case KEY_MOD1:
+ {
+ const RulerType eType = GetDragType();
+ nDragType = SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL;
+ if( RulerType::Tab == eType ||
+ ( ( RulerType::Border == eType ||
+ RulerType::Margin1 == eType ||
+ RulerType::Margin2 == eType ) &&
+ mxColumnItem ) )
+ {
+ PrepareProportional_Impl(eType);
+ }
+ }
+ break;
+ case KEY_MOD1 | KEY_SHIFT:
+ if( GetDragType() != RulerType::Margin1 &&
+ GetDragType() != RulerType::Margin2 )
+ {
+ nDragType = SvxRulerDragFlags::OBJECT_ACTLINE_ONLY;
+ }
+ break;
+ }
+}
+
+void SvxRuler::Click()
+{
+ /* Override handler SV; sets Tab per dispatcher call */
+ Ruler::Click();
+ if( bActive )
+ {
+ pBindings->Update( SID_RULER_LR_MIN_MAX );
+ pBindings->Update( SID_ATTR_LONG_ULSPACE );
+ pBindings->Update( SID_ATTR_LONG_LRSPACE );
+ pBindings->Update( SID_RULER_PAGE_POS );
+ pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
+ pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
+ pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
+ pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
+ pBindings->Update( SID_RULER_OBJECT );
+ pBindings->Update( SID_RULER_PROTECT );
+ pBindings->Update( SID_ATTR_PARA_LRSPACE_VERTICAL );
+ }
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+ if(!(mxTabStopItem &&
+ (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS))
+ return;
+
+ bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
+ if( bContentProtected ) return;
+ const tools::Long lPos = GetClickPos();
+ if(!((bRTL && lPos < std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos > GetRightIndent()) ||
+ (!bRTL && lPos > std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos < GetRightIndent())))
+ return;
+
+ //convert position in left-to-right text
+ tools::Long nTabPos;
+//#i24363# tab stops relative to indent
+ if(bRTL)
+ nTabPos = ( mxRulerImpl->bIsTabsRelativeToIndent ?
+ GetLeftIndent() :
+ ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset ) ) -
+ lPos;
+ else
+ nTabPos = lPos -
+ ( mxRulerImpl->bIsTabsRelativeToIndent ?
+ GetLeftIndent() :
+ ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset ));
+
+ SvxTabStop aTabStop(ConvertHPosLogic(nTabPos),
+ ToAttrTab_Impl(nDefTabType));
+ mxTabStopItem->Insert(aTabStop);
+ UpdateTabs();
+}
+
+void SvxRuler::CalcMinMax()
+{
+ /*
+ Calculates the limits for dragging; which are in pixels relative to the
+ page edge
+ */
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+ const tools::Long lNullPix = ConvertPosPixel(lLogicNullOffset);
+ mxRulerImpl->lMaxLeftLogic=mxRulerImpl->lMaxRightLogic=-1;
+ switch(GetDragType())
+ {
+ case RulerType::Margin1:
+ { // left edge of the surrounding Frame
+ // DragPos - NOf between left - right
+ mxRulerImpl->lMaxLeftLogic = GetLeftMin();
+ nMaxLeft=ConvertSizePixel(mxRulerImpl->lMaxLeftLogic);
+
+ if (!mxColumnItem || mxColumnItem->Count() == 1)
+ {
+ if(bRTL)
+ {
+ nMaxRight = lNullPix - GetRightIndent() +
+ std::max(GetFirstLineIndent(), GetLeftIndent()) -
+ glMinFrame;
+ }
+ else
+ {
+ nMaxRight = lNullPix + GetRightIndent() -
+ std::max(GetFirstLineIndent(), GetLeftIndent()) -
+ glMinFrame;
+ }
+ }
+ else if(mxRulerImpl->bIsTableRows)
+ {
+ //top border is not moveable when table rows are displayed
+ // protection of content means the margin is not moveable
+ if(bHorz && !mxRulerImpl->aProtectItem->IsContentProtected())
+ {
+ nMaxLeft = mpBorders[0].nMinPos + lNullPix;
+ if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ nMaxRight = GetRightIndent() + lNullPix -
+ (mxColumnItem->Count() - 1 ) * glMinFrame;
+ else
+ nMaxRight = mpBorders[0].nPos - glMinFrame + lNullPix;
+ }
+ else
+ nMaxLeft = nMaxRight = lNullPix;
+ }
+ else
+ {
+ if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ {
+ nMaxRight=lNullPix+CalcPropMaxRight();
+ }
+ else if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
+ {
+ nMaxRight = ConvertPosPixel(
+ GetPageWidth() - (
+ (mxColumnItem->IsTable() && mxLRSpaceItem)
+ ? mxLRSpaceItem->GetRight() : 0))
+ - GetMargin2() + GetMargin1();
+ }
+ else
+ {
+ nMaxRight = lNullPix - glMinFrame;
+ if (mxColumnItem->IsFirstAct())
+ {
+ if(bRTL)
+ {
+ nMaxRight += std::min(
+ mpBorders[0].nPos,
+ std::max(GetFirstLineIndent(), GetLeftIndent()) - GetRightIndent());
+ }
+ else
+ {
+ nMaxRight += std::min(
+ mpBorders[0].nPos, GetRightIndent() -
+ std::max(GetFirstLineIndent(), GetLeftIndent()));
+ }
+ }
+ else if ( mxColumnItem->Count() > 1 )
+ {
+ nMaxRight += mpBorders[0].nPos;
+ }
+ else
+ {
+ nMaxRight += GetRightIndent() - std::max(GetFirstLineIndent(), GetLeftIndent());
+ }
+ // Do not drag the left table edge over the edge of the page
+ if(mxLRSpaceItem && mxColumnItem->IsTable())
+ {
+ tools::Long nTmp=ConvertSizePixel(mxLRSpaceItem->GetLeft());
+ if(nTmp>nMaxLeft)
+ nMaxLeft=nTmp;
+ }
+ }
+ }
+ break;
+ }
+ case RulerType::Margin2:
+ { // right edge of the surrounding Frame
+ mxRulerImpl->lMaxRightLogic
+ = mxMinMaxItem ? GetPageWidth() - GetRightMax() : GetPageWidth();
+ nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
+
+ if (!mxColumnItem)
+ {
+ if(bRTL)
+ {
+ nMaxLeft = GetMargin2() + GetRightIndent() -
+ std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+
+ glMinFrame + lNullPix;
+ }
+ else
+ {
+ nMaxLeft = GetMargin2() - GetRightIndent() +
+ std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+
+ glMinFrame + lNullPix;
+ }
+ }
+ else if(mxRulerImpl->bIsTableRows)
+ {
+ // get the bottom move range from the last border position - only available for rows!
+ // protection of content means the margin is not moveable
+ if(bHorz || mxRulerImpl->aProtectItem->IsContentProtected())
+ {
+ nMaxLeft = nMaxRight = mpBorders[mxColumnItem->Count() - 1].nMaxPos + lNullPix;
+ }
+ else
+ {
+ if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ {
+ nMaxLeft = (mxColumnItem->Count()) * glMinFrame + lNullPix;
+ }
+ else
+ {
+ if(mxColumnItem->Count() > 1)
+ nMaxLeft = mpBorders[mxColumnItem->Count() - 2].nPos + glMinFrame + lNullPix;
+ else
+ nMaxLeft = glMinFrame + lNullPix;
+ }
+ if(mxColumnItem->Count() > 1)
+ nMaxRight = mpBorders[mxColumnItem->Count() - 2].nMaxPos + lNullPix;
+ else
+ nMaxRight -= GetRightIndent() - lNullPix;
+ }
+ }
+ else
+ {
+ nMaxLeft = glMinFrame + lNullPix;
+ if(IsActLastColumn() || mxColumnItem->Count() < 2 ) //If last active column
+ {
+ if(bRTL)
+ {
+ nMaxLeft = glMinFrame + lNullPix + GetMargin2() +
+ GetRightIndent() - std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ else
+ {
+ nMaxLeft = glMinFrame + lNullPix + GetMargin2() -
+ GetRightIndent() + std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ }
+ if( mxColumnItem->Count() >= 2 )
+ {
+ tools::Long nNewMaxLeft =
+ glMinFrame + lNullPix +
+ mpBorders[mxColumnItem->Count() - 2].nPos +
+ mpBorders[mxColumnItem->Count() - 2].nWidth;
+ nMaxLeft = std::max(nMaxLeft, nNewMaxLeft);
+ }
+
+ }
+ break;
+ }
+ case RulerType::Border:
+ { // Table, column (Modifier)
+ const sal_uInt16 nIdx = GetDragAryPos();
+ switch(GetDragSize())
+ {
+ case RulerDragSize::N1 :
+ {
+ nMaxRight = mpBorders[nIdx].nPos +
+ mpBorders[nIdx].nWidth + lNullPix;
+
+ if(0 == nIdx)
+ nMaxLeft = lNullPix;
+ else
+ nMaxLeft = mpBorders[nIdx - 1].nPos + mpBorders[nIdx - 1].nWidth + lNullPix;
+ if(nIdx == mxColumnItem->GetActColumn())
+ {
+ if(bRTL)
+ {
+ nMaxLeft += mpBorders[nIdx].nPos +
+ GetRightIndent() - std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ else
+ {
+ nMaxLeft += mpBorders[nIdx].nPos -
+ GetRightIndent() + std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ if(0 != nIdx)
+ nMaxLeft -= mpBorders[nIdx-1].nPos +
+ mpBorders[nIdx-1].nWidth;
+ }
+ nMaxLeft += glMinFrame;
+ nMaxLeft += nDragOffset;
+ break;
+ }
+ case RulerDragSize::Move:
+ {
+ if (mxColumnItem)
+ {
+ //nIdx contains the position of the currently moved item
+ //next visible separator on the left
+ sal_uInt16 nLeftCol=GetActLeftColumn(false, nIdx);
+ //next visible separator on the right
+ sal_uInt16 nRightCol=GetActRightColumn(false, nIdx);
+ //next separator on the left - regardless if visible or not
+ sal_uInt16 nActLeftCol=GetActLeftColumn();
+ //next separator on the right - regardless if visible or not
+ sal_uInt16 nActRightCol=GetActRightColumn();
+ if(mxColumnItem->IsTable())
+ {
+ if(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY)
+ {
+ //the current row/column should be modified only
+ //then the next/previous visible border position
+ //marks the min/max positions
+ nMaxLeft = nLeftCol == USHRT_MAX ?
+ 0 :
+ mpBorders[nLeftCol].nPos;
+ //rows can always be increased without a limit
+ if(mxRulerImpl->bIsTableRows)
+ nMaxRight = mpBorders[nIdx].nMaxPos;
+ else
+ nMaxRight = nRightCol == USHRT_MAX ?
+ GetMargin2():
+ mpBorders[nRightCol].nPos;
+ nMaxLeft += lNullPix;
+ nMaxRight += lNullPix;
+ }
+ else
+ {
+ if(SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType && !bHorz && mxRulerImpl->bIsTableRows)
+ nMaxLeft = (nIdx + 1) * glMinFrame + lNullPix;
+ else
+ nMaxLeft = mpBorders[nIdx].nMinPos + lNullPix;
+ if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
+ (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
+ {
+ if(mxRulerImpl->bIsTableRows)
+ {
+ if(bHorz)
+ nMaxRight = GetRightIndent() + lNullPix -
+ (mxColumnItem->Count() - nIdx - 1) * glMinFrame;
+ else
+ nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
+ }
+ else
+ nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
+ }
+ else
+ nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
+ }
+ nMaxLeft += glMinFrame;
+ nMaxRight -= glMinFrame;
+
+ }
+ else
+ {
+ if(nLeftCol==USHRT_MAX)
+ nMaxLeft=lNullPix;
+ else
+ nMaxLeft = mpBorders[nLeftCol].nPos +
+ mpBorders[nLeftCol].nWidth + lNullPix;
+
+ if(nActRightCol == nIdx)
+ {
+ if(bRTL)
+ {
+ nMaxLeft += mpBorders[nIdx].nPos +
+ GetRightIndent() - std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ if(nActLeftCol!=USHRT_MAX)
+ nMaxLeft -= mpBorders[nActLeftCol].nPos +
+ mpBorders[nActLeftCol].nWidth;
+ }
+ else
+ {
+ nMaxLeft += mpBorders[nIdx].nPos -
+ GetRightIndent() + std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ if(nActLeftCol!=USHRT_MAX)
+ nMaxLeft -= mpBorders[nActLeftCol].nPos +
+ mpBorders[nActLeftCol].nWidth;
+ }
+ }
+ nMaxLeft += glMinFrame;
+ nMaxLeft += nDragOffset;
+
+ // nMaxRight
+ // linear / proportional move
+ if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
+ (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
+ {
+ nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
+ }
+ else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType)
+ {
+ nMaxRight = lNullPix + GetMargin2() - GetMargin1() +
+ (mpBorders.size() - nIdx - 1) * glMinFrame;
+ }
+ else
+ {
+ if(nRightCol==USHRT_MAX)
+ { // last column
+ nMaxRight = GetMargin2() + lNullPix;
+ if(IsActLastColumn())
+ {
+ if(bRTL)
+ {
+ nMaxRight -=
+ GetMargin2() + GetRightIndent() -
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ else
+ {
+ nMaxRight -=
+ GetMargin2() - GetRightIndent() +
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ nMaxRight += mpBorders[nIdx].nPos +
+ mpBorders[nIdx].nWidth;
+ }
+ }
+ else
+ {
+ nMaxRight = lNullPix + mpBorders[nRightCol].nPos;
+ sal_uInt16 nNotHiddenRightCol =
+ GetActRightColumn(true, nIdx);
+
+ if( nActLeftCol == nIdx )
+ {
+ tools::Long nBorder = nNotHiddenRightCol ==
+ USHRT_MAX ?
+ GetMargin2() :
+ mpBorders[nNotHiddenRightCol].nPos;
+ if(bRTL)
+ {
+ nMaxRight -= nBorder + GetRightIndent() -
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ else
+ {
+ nMaxRight -= nBorder - GetRightIndent() +
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ nMaxRight += mpBorders[nIdx].nPos +
+ mpBorders[nIdx].nWidth;
+ }
+ }
+ nMaxRight -= glMinFrame;
+ nMaxRight -= mpBorders[nIdx].nWidth;
+ }
+ }
+ }
+ // ObjectItem
+ else
+ {
+ nMaxLeft = LONG_MIN;
+ nMaxRight = LONG_MAX;
+ }
+ break;
+ }
+ case RulerDragSize::N2:
+ {
+ nMaxLeft = lNullPix + mpBorders[nIdx].nPos;
+ if(nIdx == mxColumnItem->Count()-2) { // last column
+ nMaxRight = GetMargin2() + lNullPix;
+ if(mxColumnItem->IsLastAct()) {
+ nMaxRight -=
+ GetMargin2() - GetRightIndent() +
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ nMaxRight += mpBorders[nIdx].nPos +
+ mpBorders[nIdx].nWidth;
+ }
+ }
+ else {
+ nMaxRight = lNullPix + mpBorders[nIdx+1].nPos;
+ if(mxColumnItem->GetActColumn()-1 == nIdx) {
+ nMaxRight -= mpBorders[nIdx+1].nPos - GetRightIndent() +
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ nMaxRight += mpBorders[nIdx].nPos +
+ mpBorders[nIdx].nWidth;
+ }
+ }
+ nMaxRight -= glMinFrame;
+ nMaxRight -= mpBorders[nIdx].nWidth;
+ break;
+ }
+ }
+ nMaxRight += nDragOffset;
+ break;
+ }
+ case RulerType::Indent:
+ {
+ const sal_uInt16 nIdx = GetDragAryPos();
+ switch(nIdx) {
+ case INDENT_FIRST_LINE - INDENT_GAP:
+ case INDENT_LEFT_MARGIN - INDENT_GAP:
+ {
+ if(bRTL)
+ {
+ nMaxLeft = lNullPix + GetRightIndent();
+
+ if(mxColumnItem && !mxColumnItem->IsFirstAct())
+ nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
+ mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
+ nMaxRight = lNullPix + GetMargin2();
+
+ // Dragging along
+ if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
+ !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
+ {
+ if(GetLeftIndent() > GetFirstLineIndent())
+ nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
+ else
+ nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
+ }
+ }
+ else
+ {
+ nMaxLeft = lNullPix;
+
+ if(mxColumnItem && !mxColumnItem->IsFirstAct())
+ nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
+ mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
+ nMaxRight = lNullPix + GetRightIndent() - glMinFrame;
+
+ // Dragging along
+ if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
+ !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
+ {
+ if(GetLeftIndent() > GetFirstLineIndent())
+ nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
+ else
+ nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
+ }
+ }
+ }
+ break;
+ case INDENT_RIGHT_MARGIN - INDENT_GAP:
+ {
+ if(bRTL)
+ {
+ nMaxLeft = lNullPix;
+ nMaxRight = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent()) - glMinFrame;
+ if (mxColumnItem)
+ {
+ sal_uInt16 nRightCol=GetActRightColumn( true );
+ if(!IsActLastColumn( true ))
+ nMaxRight += mpBorders[nRightCol].nPos;
+ else
+ nMaxRight += GetMargin2();
+ }
+ else
+ {
+ nMaxLeft += GetMargin1();
+ }
+ nMaxLeft += glMinFrame;
+ }
+ else
+ {
+ nMaxLeft = lNullPix +
+ std::max(GetFirstLineIndent(), GetLeftIndent());
+ nMaxRight = lNullPix;
+ if (mxColumnItem)
+ {
+ sal_uInt16 nRightCol=GetActRightColumn( true );
+ if(!IsActLastColumn( true ))
+ nMaxRight += mpBorders[nRightCol].nPos;
+ else
+ nMaxRight += GetMargin2();
+ }
+ else
+ nMaxRight += GetMargin2();
+ nMaxLeft += glMinFrame;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ case RulerType::Tab: // Tabs (Modifier)
+ /* left = NOf + Max(LAR, EZ)
+ right = NOf + RAR */
+
+ if (bRTL)
+ nMaxLeft = lNullPix + GetRightIndent();
+ else
+ nMaxLeft = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent());
+
+ mxRulerImpl->lMaxRightLogic = GetLogicRightIndent() + lLogicNullOffset;
+ nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
+ break;
+ default: ; //prevent warning
+ }
+}
+
+bool SvxRuler::StartDrag()
+{
+ /*
+ Beginning of a drag operation (SV-handler) evaluates modifier and
+ calculated values
+
+ [Cross-reference]
+
+ <SvxRuler::EvalModifier()>
+ <SvxRuler::CalcMinMax()>
+ <SvxRuler::EndDrag()>
+ */
+ bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
+
+ if(!bValid)
+ return false;
+
+ mxRulerImpl->lLastLMargin = GetMargin1();
+ mxRulerImpl->lLastRMargin = GetMargin2();
+
+ bool bOk = true;
+
+ lInitialDragPos = GetDragPos();
+ switch(GetDragType())
+ {
+ case RulerType::Margin1: // left edge of the surrounding Frame
+ case RulerType::Margin2: // right edge of the surrounding Frame
+ if((bHorz && mxLRSpaceItem) || (!bHorz && mxULSpaceItem))
+ {
+ if (!mxColumnItem)
+ EvalModifier();
+ else
+ nDragType = SvxRulerDragFlags::OBJECT;
+ }
+ else
+ {
+ bOk = false;
+ }
+ break;
+ case RulerType::Border: // Table, column (Modifier)
+ if (mxColumnItem)
+ {
+ nDragOffset = 0;
+ if (!mxColumnItem->IsTable())
+ nDragOffset = GetDragPos() - mpBorders[GetDragAryPos()].nPos;
+ EvalModifier();
+ }
+ else
+ nDragOffset = 0;
+ break;
+ case RulerType::Indent: // Paragraph indents (Modifier)
+ {
+ if( bContentProtected )
+ return false;
+ if(INDENT_LEFT_MARGIN == GetDragAryPos() + INDENT_GAP) { // Left paragraph indent
+ mpIndents[0] = mpIndents[INDENT_FIRST_LINE];
+ EvalModifier();
+ }
+ else
+ {
+ nDragType = SvxRulerDragFlags::OBJECT;
+ }
+ mpIndents[1] = mpIndents[GetDragAryPos() + INDENT_GAP];
+ break;
+ }
+ case RulerType::Tab: // Tabs (Modifier)
+ if( bContentProtected )
+ return false;
+ EvalModifier();
+ mpTabs[0] = mpTabs[GetDragAryPos() + 1];
+ mpTabs[0].nStyle |= RULER_STYLE_DONTKNOW;
+ break;
+ default:
+ nDragType = SvxRulerDragFlags::NONE;
+ }
+
+ if(bOk)
+ CalcMinMax();
+
+ return bOk;
+}
+
+void SvxRuler::Drag()
+{
+ /* SV-Draghandler */
+ if(IsDragCanceled())
+ {
+ Ruler::Drag();
+ return;
+ }
+ switch(GetDragType()) {
+ case RulerType::Margin1: // left edge of the surrounding Frame
+ DragMargin1();
+ mxRulerImpl->lLastLMargin = GetMargin1();
+ break;
+ case RulerType::Margin2: // right edge of the surrounding Frame
+ DragMargin2();
+ mxRulerImpl->lLastRMargin = GetMargin2();
+ break;
+ case RulerType::Indent: // Paragraph indents
+ DragIndents();
+ break;
+ case RulerType::Border: // Table, columns
+ if (mxColumnItem)
+ DragBorders();
+ else if (mxObjectItem)
+ DragObjectBorder();
+ break;
+ case RulerType::Tab: // Tabs
+ DragTabs();
+ break;
+ default:
+ break; //prevent warning
+ }
+ Ruler::Drag();
+}
+
+void SvxRuler::EndDrag()
+{
+ /*
+ SV-handler; is called when ending the dragging. Triggers the updating of data
+ on the application, by calling the respective Apply...() methods to send the
+ data to the application.
+ */
+ const bool bUndo = IsDragCanceled();
+ const tools::Long lPos = GetDragPos();
+ DrawLine_Impl(lTabPos, 6, bHorz);
+ lTabPos = -1;
+
+ if(!bUndo)
+ {
+ switch(GetDragType())
+ {
+ case RulerType::Margin1: // upper left edge of the surrounding Frame
+ case RulerType::Margin2: // lower right edge of the surrounding Frame
+ {
+ if (!mxColumnItem || !mxColumnItem->IsTable())
+ ApplyMargins();
+
+ if(mxColumnItem &&
+ (mxColumnItem->IsTable() ||
+ (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
+ ApplyBorders();
+
+ }
+ break;
+ case RulerType::Border: // Table, columns
+ if(lInitialDragPos != lPos ||
+ (mxRulerImpl->bIsTableRows && bHorz)) //special case - the null offset is changed here
+ {
+ if (mxColumnItem)
+ {
+ ApplyBorders();
+ if(bHorz)
+ UpdateTabs();
+ }
+ else if (mxObjectItem)
+ ApplyObject();
+ }
+ break;
+ case RulerType::Indent: // Paragraph indents
+ if(lInitialDragPos != lPos)
+ ApplyIndents();
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ break;
+ case RulerType::Tab: // Tabs
+ {
+ ApplyTabs();
+ mpTabs[GetDragAryPos()].nStyle &= ~RULER_STYLE_INVISIBLE;
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+ }
+ break;
+ default:
+ break; //prevent warning
+ }
+ }
+ nDragType = SvxRulerDragFlags::NONE;
+
+ mbCoarseSnapping = false;
+ mbSnapping = true;
+
+ Ruler::EndDrag();
+ if(bUndo)
+ {
+ for(sal_uInt16 i = 0; i < mxRulerImpl->nControllerItems; i++)
+ {
+ pCtrlItems[i]->ClearCache();
+ pCtrlItems[i]->GetBindings().Invalidate(pCtrlItems[i]->GetId());
+ }
+ }
+}
+
+void SvxRuler::ExtraDown()
+{
+ /* Override SV method, sets the new type for the Default tab. */
+
+ // Switch Tab Type
+ if(mxTabStopItem &&
+ (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS)
+ {
+ ++nDefTabType;
+ if(RULER_TAB_DEFAULT == nDefTabType)
+ nDefTabType = RULER_TAB_LEFT;
+ SetExtraType(RulerExtra::Tab, nDefTabType);
+ }
+ Ruler::ExtraDown();
+}
+
+void SvxRuler::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ /*
+ Report through the bindings that the status update is completed. The ruler
+ updates its appearance and gets registered again in the bindings.
+ */
+
+ // start update
+ if (bActive && rHint.GetId() == SfxHintId::UpdateDone)
+ {
+ Update();
+ EndListening(*pBindings);
+ bValid = true;
+ bListening = false;
+ }
+}
+
+void SvxRuler::MenuSelect(std::string_view ident)
+{
+ if (ident.empty())
+ return;
+ /* Handler of the context menus for switching the unit of measurement */
+ SetUnit(vcl::EnglishStringToMetric(ident));
+}
+
+void SvxRuler::TabMenuSelect(std::string_view rIdent)
+{
+ if (rIdent.empty())
+ return;
+ sal_Int32 nId = o3tl::toInt32(rIdent);
+ /* Handler of the tab menu for setting the type */
+ if (mxTabStopItem && mxTabStopItem->Count() > mxRulerImpl->nIdx)
+ {
+ SvxTabStop aTabStop = mxTabStopItem->At(mxRulerImpl->nIdx);
+ aTabStop.GetAdjustment() = ToAttrTab_Impl(nId - 1);
+ mxTabStopItem->Remove(mxRulerImpl->nIdx);
+ mxTabStopItem->Insert(aTabStop);
+ sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
+ pBindings->GetDispatcher()->ExecuteList(nTabStopId,
+ SfxCallMode::RECORD, { mxTabStopItem.get() });
+ UpdateTabs();
+ mxRulerImpl->nIdx = 0;
+ }
+}
+
+const TranslateId RID_SVXSTR_RULER_TAB[] =
+{
+ RID_SVXSTR_RULER_TAB_LEFT,
+ RID_SVXSTR_RULER_TAB_RIGHT,
+ RID_SVXSTR_RULER_TAB_CENTER,
+ RID_SVXSTR_RULER_TAB_DECIMAL
+};
+
+void SvxRuler::Command( const CommandEvent& rCommandEvent )
+{
+ /* Mouse context menu for switching the unit of measurement */
+ if ( CommandEventId::ContextMenu == rCommandEvent.GetCommand() )
+ {
+ CancelDrag();
+
+ tools::Rectangle aRect(rCommandEvent.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "svx/ui/rulermenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+ if ( !mpTabs.empty() &&
+ RulerType::Tab ==
+ GetRulerType( rCommandEvent.GetMousePosPixel(), &mxRulerImpl->nIdx ) &&
+ mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle < RULER_TAB_DEFAULT )
+ {
+ xMenu->clear();
+
+ const Size aSz(ruler_tab_svx.width + 2, ruler_tab_svx.height + 2);
+ const Point aPt(aSz.Width() / 2, aSz.Height() / 2);
+
+ for ( sal_uInt16 i = RULER_TAB_LEFT; i < RULER_TAB_DEFAULT; ++i )
+ {
+ ScopedVclPtr<VirtualDevice> xDev(pPopupParent->create_virtual_device());
+ xDev->SetOutputSize(aSz);
+
+ sal_uInt16 nStyle = bRTL ? i|RULER_TAB_RTL : i;
+ nStyle |= static_cast<sal_uInt16>(bHorz ? WB_HORZ : WB_VERT);
+
+ Color aFillColor(xDev->GetSettings().GetStyleSettings().GetShadowColor());
+ DrawTab(*xDev, aFillColor, aPt, nStyle);
+
+ OString sId(OString::number(i + 1));
+ xMenu->insert(-1, OUString::fromUtf8(sId), SvxResId(RID_SVXSTR_RULER_TAB[i]),
+ nullptr, xDev.get(), nullptr, TRISTATE_TRUE);
+ xMenu->set_active(sId, i == mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle);
+ }
+ TabMenuSelect(xMenu->popup_at_rect(pPopupParent, aRect));
+ }
+ else
+ {
+ FieldUnit eUnit = GetUnit();
+ const int nCount = xMenu->n_children();
+
+ bool bReduceMetric = bool(nFlags & SvxRulerSupportFlags::REDUCED_METRIC);
+ for ( sal_uInt16 i = nCount; i; --i )
+ {
+ OString sIdent = xMenu->get_id(i - 1);
+ FieldUnit eMenuUnit = vcl::EnglishStringToMetric(sIdent);
+ xMenu->set_active(sIdent, eMenuUnit == eUnit);
+ if( bReduceMetric )
+ {
+ if (eMenuUnit == FieldUnit::M ||
+ eMenuUnit == FieldUnit::KM ||
+ eMenuUnit == FieldUnit::FOOT ||
+ eMenuUnit == FieldUnit::MILE)
+ {
+ xMenu->remove(sIdent);
+ }
+ else if (( eMenuUnit == FieldUnit::CHAR ) && !bHorz )
+ {
+ xMenu->remove(sIdent);
+ }
+ else if (( eMenuUnit == FieldUnit::LINE ) && bHorz )
+ {
+ xMenu->remove(sIdent);
+ }
+ }
+ }
+ MenuSelect(xMenu->popup_at_rect(pPopupParent, aRect));
+ }
+ }
+ else
+ {
+ Ruler::Command( rCommandEvent );
+ }
+}
+
+sal_uInt16 SvxRuler::GetActRightColumn(
+ bool bForceDontConsiderHidden,
+ sal_uInt16 nAct ) const
+{
+ if( nAct == USHRT_MAX )
+ nAct = mxColumnItem->GetActColumn();
+ else
+ nAct++; //To be able to pass on the ActDrag
+
+ bool bConsiderHidden = !bForceDontConsiderHidden &&
+ !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
+
+ while( nAct < mxColumnItem->Count() - 1 )
+ {
+ if (mxColumnItem->At(nAct).bVisible || bConsiderHidden)
+ return nAct;
+ else
+ nAct++;
+ }
+ return USHRT_MAX;
+}
+
+sal_uInt16 SvxRuler::GetActLeftColumn(
+ bool bForceDontConsiderHidden,
+ sal_uInt16 nAct ) const
+{
+ if(nAct == USHRT_MAX)
+ nAct = mxColumnItem->GetActColumn();
+
+ sal_uInt16 nLeftOffset = 1;
+
+ bool bConsiderHidden = !bForceDontConsiderHidden &&
+ !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
+
+ while(nAct >= nLeftOffset)
+ {
+ if (mxColumnItem->At(nAct - nLeftOffset).bVisible || bConsiderHidden)
+ return nAct - nLeftOffset;
+ else
+ nLeftOffset++;
+ }
+ return USHRT_MAX;
+}
+
+bool SvxRuler::IsActLastColumn(
+ bool bForceDontConsiderHidden,
+ sal_uInt16 nAct) const
+{
+ return GetActRightColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
+}
+
+bool SvxRuler::IsActFirstColumn(
+ bool bForceDontConsiderHidden,
+ sal_uInt16 nAct) const
+{
+ return GetActLeftColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
+}
+
+tools::Long SvxRuler::CalcPropMaxRight(sal_uInt16 nCol) const
+{
+
+ if(!(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
+ {
+ // Remove the minimum width for all affected columns
+ // starting from the right edge
+ tools::Long _nMaxRight = GetMargin2() - GetMargin1();
+
+ tools::Long lFences = 0;
+ tools::Long lMinSpace = USHRT_MAX;
+ tools::Long lOldPos;
+ tools::Long lColumns = 0;
+
+ sal_uInt16 nStart;
+ if(!mxColumnItem->IsTable())
+ {
+ if(nCol == USHRT_MAX)
+ {
+ lOldPos = GetMargin1();
+ nStart = 0;
+ }
+ else
+ {
+ lOldPos = mpBorders[nCol].nPos + mpBorders[nCol].nWidth;
+ nStart = nCol + 1;
+ lFences = mpBorders[nCol].nWidth;
+ }
+
+ for(size_t i = nStart; i < mpBorders.size() - 1; ++i)
+ {
+ tools::Long lWidth = mpBorders[i].nPos - lOldPos;
+ lColumns += lWidth;
+ if(lWidth < lMinSpace)
+ lMinSpace = lWidth;
+ lOldPos = mpBorders[i].nPos + mpBorders[i].nWidth;
+ lFences += mpBorders[i].nWidth;
+ }
+ tools::Long lWidth = GetMargin2() - lOldPos;
+ lColumns += lWidth;
+ if(lWidth < lMinSpace)
+ lMinSpace = lWidth;
+ }
+ else
+ {
+ sal_uInt16 nActCol;
+ if(nCol == USHRT_MAX) //CalcMinMax for LeftMargin
+ {
+ lOldPos = GetMargin1();
+ }
+ else
+ {
+ lOldPos = mpBorders[nCol].nPos;
+ }
+ lColumns = GetMargin2()-lOldPos;
+ nActCol = nCol;
+ lFences = 0;
+ while(nActCol < mpBorders.size() || nActCol == USHRT_MAX)
+ {
+ sal_uInt16 nRight;
+ if(nActCol == USHRT_MAX)
+ {
+ nRight = 0;
+ while (!(*mxColumnItem)[nRight].bVisible)
+ {
+ nRight++;
+ }
+ }
+ else
+ {
+ nRight = GetActRightColumn(false, nActCol);
+ }
+
+ tools::Long lWidth;
+ if(nRight != USHRT_MAX)
+ {
+ lWidth = mpBorders[nRight].nPos - lOldPos;
+ lOldPos = mpBorders[nRight].nPos;
+ }
+ else
+ {
+ lWidth=GetMargin2() - lOldPos;
+ }
+ nActCol = nRight;
+ if(lWidth < lMinSpace)
+ lMinSpace = lWidth;
+ if(nActCol == USHRT_MAX)
+ break;
+ }
+ }
+
+ _nMaxRight -= static_cast<tools::Long>(lFences + glMinFrame / static_cast<float>(lMinSpace) * lColumns);
+ return _nMaxRight;
+ }
+ else
+ {
+ if(mxColumnItem->IsTable())
+ {
+ sal_uInt16 nVisCols = 0;
+ for(size_t i = GetActRightColumn(false, nCol); i < mpBorders.size();)
+ {
+ if ((*mxColumnItem)[i].bVisible)
+ nVisCols++;
+ i = GetActRightColumn(false, i);
+ }
+ return GetMargin2() - GetMargin1() - (nVisCols + 1) * glMinFrame;
+ }
+ else
+ {
+ tools::Long lWidth = 0;
+ for(size_t i = nCol; i < mpBorders.size() - 1; i++)
+ {
+ lWidth += glMinFrame + mpBorders[i].nWidth;
+ }
+ return GetMargin2() - GetMargin1() - lWidth;
+ }
+ }
+}
+
+// Tab stops relative to indent (#i24363#)
+void SvxRuler::SetTabsRelativeToIndent( bool bRel )
+{
+ mxRulerImpl->bIsTabsRelativeToIndent = bRel;
+}
+
+void SvxRuler::SetValues(RulerChangeType type, tools::Long diffValue)
+{
+ if (diffValue == 0)
+ return;
+
+ if (type == RulerChangeType::MARGIN1)
+ AdjustMargin1(diffValue);
+ else if (type == RulerChangeType::MARGIN2)
+ SetMargin2( GetMargin2() - diffValue);
+ ApplyMargins();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/dialog/swframeexample.cxx b/svx/source/dialog/swframeexample.cxx
new file mode 100644
index 000000000..a90780a5b
--- /dev/null
+++ b/svx/source/dialog/swframeexample.cxx
@@ -0,0 +1,714 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/metric.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svx/swframeexample.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+
+using namespace ::com::sun::star::text;
+
+#define FLYINFLY_BORDER 3
+constexpr OUStringLiteral DEMOTEXT = u"Ij";
+
+namespace {
+
+void DrawRect_Impl(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect,
+ const Color &rFillColor, const Color &rLineColor)
+{
+ rRenderContext.SetFillColor(rFillColor);
+ rRenderContext.SetLineColor(rLineColor);
+ rRenderContext.DrawRect(rRect);
+}
+
+}
+
+SwFrameExample::SwFrameExample()
+ : nHAlign(HoriOrientation::CENTER)
+ , nHRel(RelOrientation::FRAME)
+ , nVAlign(VertOrientation::TOP)
+ , nVRel(RelOrientation::PRINT_AREA)
+ , nWrap(WrapTextMode_NONE)
+ , nAnchor(RndStdIds::FLY_AT_PAGE)
+ , bTrans(false)
+ , aRelPos(Point(0,0))
+{
+ InitColors_Impl();
+}
+
+void SwFrameExample::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 16,
+ pDrawingArea->get_text_height() * 12);
+}
+
+void SwFrameExample::InitColors_Impl()
+{
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ m_aBgCol = rSettings.GetWindowColor();
+
+ bool bHC = rSettings.GetHighContrastMode();
+
+ m_aFrameColor = COL_LIGHTGREEN;
+ m_aAlignColor = COL_LIGHTRED;
+ m_aTransColor = COL_TRANSPARENT;
+
+ m_aTxtCol = bHC?
+ svtools::ColorConfig().GetColorValue(svtools::FONTCOLOR).nColor :
+ COL_GRAY;
+ m_aPrintAreaCol = bHC? m_aTxtCol : COL_GRAY;
+ m_aBorderCol = m_aTxtCol;
+ m_aBlankCol = bHC? m_aTxtCol : COL_LIGHTGRAY;
+ m_aBlankFrameCol = bHC? m_aTxtCol : COL_GRAY;
+}
+
+void SwFrameExample::StyleUpdated()
+{
+ InitColors_Impl();
+ CustomWidgetController::StyleUpdated();
+}
+
+void SwFrameExample::InitAllRects_Impl(vcl::RenderContext& rRenderContext)
+{
+ aPage.SetSize(GetOutputSizePixel());
+
+ sal_uInt32 nOutWPix = aPage.GetWidth();
+ sal_uInt32 nOutHPix = aPage.GetHeight();
+
+ // PrintArea
+ sal_uInt32 nLBorder;
+ sal_uInt32 nRBorder;
+ sal_uInt32 nTBorder;
+ sal_uInt32 nBBorder;
+
+ sal_uInt32 nLTxtBorder;
+ sal_uInt32 nRTxtBorder;
+ sal_uInt32 nTTxtBorder;
+ sal_uInt32 nBTxtBorder;
+
+ if (nAnchor != RndStdIds::FLY_AS_CHAR)
+ {
+ nLBorder = 14;
+ nRBorder = 10;
+ nTBorder = 10;
+ nBBorder = 15;
+
+ nLTxtBorder = 8;
+ nRTxtBorder = 4;
+ nTTxtBorder = 2;
+ nBTxtBorder = 2;
+ }
+ else
+ {
+ nLBorder = 2;
+ nRBorder = 2;
+ nTBorder = 2;
+ nBBorder = 2;
+
+ nLTxtBorder = 2;
+ nRTxtBorder = 2;
+ nTTxtBorder = 2;
+ nBTxtBorder = 2;
+ }
+ aPagePrtArea = tools::Rectangle(Point(nLBorder, nTBorder), Point((nOutWPix - 1) - nRBorder, (nOutHPix - 1) - nBBorder));
+
+ // Example text: Preparing for the text output
+ // A line of text
+ aTextLine = aPagePrtArea;
+ aTextLine.SetSize(Size(aTextLine.GetWidth(), 2));
+ aTextLine.AdjustLeft(nLTxtBorder );
+ aTextLine.AdjustRight( -sal_Int32(nRTxtBorder) );
+ aTextLine.Move(0, nTTxtBorder);
+
+ // Rectangle to edges including paragraph
+ sal_uInt16 nLines = static_cast<sal_uInt16>((aPagePrtArea.GetHeight() / 2 - nTTxtBorder - nBTxtBorder)
+ / (aTextLine.GetHeight() + 2));
+ aPara = aPagePrtArea;
+ aPara.SetSize(Size(aPara.GetWidth(),
+ (aTextLine.GetHeight() + 2) * nLines + nTTxtBorder + nBTxtBorder));
+
+ // Rectangle around paragraph without borders
+ aParaPrtArea = aPara;
+ aParaPrtArea.AdjustLeft(nLTxtBorder );
+ aParaPrtArea.AdjustRight( -sal_Int32(nRTxtBorder) );
+ aParaPrtArea.AdjustTop(nTTxtBorder );
+ aParaPrtArea.AdjustBottom( -sal_Int32(nBTxtBorder) );
+
+ if (nAnchor == RndStdIds::FLY_AS_CHAR || nAnchor == RndStdIds::FLY_AT_CHAR)
+ {
+ vcl::Font aFont = OutputDevice::GetDefaultFont(
+ DefaultFontType::LATIN_TEXT, Application::GetSettings().GetLanguageTag().getLanguageType(),
+ GetDefaultFontFlags::OnlyOne, &rRenderContext );
+ aFont.SetColor( m_aTxtCol );
+ aFont.SetFillColor( m_aBgCol );
+ aFont.SetWeight(WEIGHT_NORMAL);
+
+ if (nAnchor == RndStdIds::FLY_AS_CHAR)
+ {
+ aFont.SetFontSize(Size(0, aParaPrtArea.GetHeight() - 2));
+ rRenderContext.SetFont(aFont);
+ aParaPrtArea.SetSize(Size(rRenderContext.GetTextWidth(DEMOTEXT), rRenderContext.GetTextHeight()));
+ }
+ else
+ {
+ aFont.SetFontSize(Size(0, aParaPrtArea.GetHeight() / 2));
+ rRenderContext.SetFont(aFont);
+ aAutoCharFrame.SetSize(Size(rRenderContext.GetTextWidth(OUString('A')), GetTextHeight()));
+ aAutoCharFrame.SetPos(Point(aParaPrtArea.Left() + (aParaPrtArea.GetWidth() - aAutoCharFrame.GetWidth()) / 2,
+ aParaPrtArea.Top() + (aParaPrtArea.GetHeight() - aAutoCharFrame.GetHeight()) / 2));
+ }
+ }
+
+ // Inner Frame anchored at the Frame
+ aFrameAtFrame = aPara;
+ aFrameAtFrame.AdjustLeft(9 );
+ aFrameAtFrame.AdjustRight( -5 );
+ aFrameAtFrame.AdjustBottom(5 );
+ aFrameAtFrame.SetPos(Point(aFrameAtFrame.Left() + 2, (aPagePrtArea.Bottom() - aFrameAtFrame.GetHeight()) / 2 + 5));
+
+ // Size of the frame to be positioned
+ if (nAnchor != RndStdIds::FLY_AS_CHAR)
+ {
+ sal_uInt32 nLFBorder = nAnchor == RndStdIds::FLY_AT_PAGE ? nLBorder : nLTxtBorder;
+ sal_uInt32 nRFBorder = nAnchor == RndStdIds::FLY_AT_PAGE ? nRBorder : nRTxtBorder;
+
+ switch (nHRel)
+ {
+ case RelOrientation::PAGE_LEFT:
+ case RelOrientation::FRAME_LEFT:
+ aFrmSize = Size(nLFBorder - 4, (aTextLine.GetHeight() + 2) * 3);
+ break;
+
+ case RelOrientation::PAGE_RIGHT:
+ case RelOrientation::FRAME_RIGHT:
+ aFrmSize = Size(nRFBorder - 4, (aTextLine.GetHeight() + 2) * 3);
+ break;
+
+ default:
+ aFrmSize = Size(nLBorder - 3, (aTextLine.GetHeight() + 2) * 3);
+ break;
+ }
+ aFrmSize.setWidth( std::max(tools::Long(5), aFrmSize.Width()) );
+ aFrmSize.setHeight( std::max(tools::Long(5), aFrmSize.Height()) );
+ }
+ else
+ {
+ sal_uInt32 nFreeWidth = aPagePrtArea.GetWidth() - rRenderContext.GetTextWidth(DEMOTEXT);
+
+ aFrmSize = Size(nFreeWidth / 2, (aTextLine.GetHeight() + 2) * 3);
+ aDrawObj.SetSize(Size(std::max(tools::Long(5), tools::Long(nFreeWidth / 3)), std::max(tools::Long(5), aFrmSize.Height() * 3)));
+ aDrawObj.SetPos(Point(aParaPrtArea.Right() + 1, aParaPrtArea.Bottom() / 2));
+ aParaPrtArea.SetRight( aDrawObj.Right() );
+ }
+}
+
+void SwFrameExample::CalcBoundRect_Impl(const vcl::RenderContext& rRenderContext, tools::Rectangle &rRect)
+{
+ switch (nAnchor)
+ {
+ case RndStdIds::FLY_AT_PAGE:
+ {
+ switch (nHRel)
+ {
+ case RelOrientation::FRAME:
+ case RelOrientation::PAGE_FRAME:
+ rRect.SetLeft( aPage.Left() );
+ rRect.SetRight( aPage.Right() );
+ break;
+
+ case RelOrientation::PRINT_AREA:
+ case RelOrientation::PAGE_PRINT_AREA:
+ rRect.SetLeft( aPagePrtArea.Left() );
+ rRect.SetRight( aPagePrtArea.Right() );
+ break;
+
+ case RelOrientation::PAGE_LEFT:
+ rRect.SetLeft( aPage.Left() );
+ rRect.SetRight( aPagePrtArea.Left() );
+ break;
+
+ case RelOrientation::PAGE_RIGHT:
+ rRect.SetLeft( aPagePrtArea.Right() );
+ rRect.SetRight( aPage.Right() );
+ break;
+ }
+
+ switch (nVRel)
+ {
+ case RelOrientation::PRINT_AREA:
+ case RelOrientation::PAGE_PRINT_AREA:
+ rRect.SetTop( aPagePrtArea.Top() );
+ rRect.SetBottom( aPagePrtArea.Bottom() );
+ break;
+
+ case RelOrientation::FRAME:
+ case RelOrientation::PAGE_FRAME:
+ rRect.SetTop( aPage.Top() );
+ rRect.SetBottom( aPage.Bottom() );
+ break;
+ }
+ }
+ break;
+
+ case RndStdIds::FLY_AT_FLY:
+ {
+ switch (nHRel)
+ {
+ case RelOrientation::FRAME:
+ case RelOrientation::PAGE_FRAME:
+ rRect.SetLeft( aFrameAtFrame.Left() );
+ rRect.SetRight( aFrameAtFrame.Right() );
+ break;
+
+ case RelOrientation::PRINT_AREA:
+ case RelOrientation::PAGE_PRINT_AREA:
+ rRect.SetLeft( aFrameAtFrame.Left() + FLYINFLY_BORDER );
+ rRect.SetRight( aFrameAtFrame.Right() - FLYINFLY_BORDER );
+ break;
+
+ case RelOrientation::PAGE_LEFT:
+ rRect.SetLeft( aFrameAtFrame.Left() );
+ rRect.SetRight( aFrameAtFrame.Left() + FLYINFLY_BORDER );
+ break;
+
+ case RelOrientation::PAGE_RIGHT:
+ rRect.SetLeft( aFrameAtFrame.Right() );
+ rRect.SetRight( aFrameAtFrame.Right() - FLYINFLY_BORDER );
+ break;
+ }
+
+ switch (nVRel)
+ {
+ case RelOrientation::FRAME:
+ case RelOrientation::PAGE_FRAME:
+ rRect.SetTop( aFrameAtFrame.Top() );
+ rRect.SetBottom( aFrameAtFrame.Bottom() );
+ break;
+
+ case RelOrientation::PRINT_AREA:
+ case RelOrientation::PAGE_PRINT_AREA:
+ rRect.SetTop( aFrameAtFrame.Top() + FLYINFLY_BORDER );
+ rRect.SetBottom( aFrameAtFrame.Bottom() - FLYINFLY_BORDER );
+ break;
+ }
+ }
+ break;
+ case RndStdIds::FLY_AT_PARA:
+ case RndStdIds::FLY_AT_CHAR:
+ {
+ switch (nHRel)
+ {
+ case RelOrientation::FRAME:
+ rRect.SetLeft( aPara.Left() );
+ rRect.SetRight( aPara.Right() );
+ break;
+
+ case RelOrientation::PRINT_AREA:
+ rRect.SetLeft( aParaPrtArea.Left() );
+ rRect.SetRight( aParaPrtArea.Right() );
+ break;
+
+ case RelOrientation::PAGE_LEFT:
+ rRect.SetLeft( aPage.Left() );
+ rRect.SetRight( aPagePrtArea.Left() );
+ break;
+
+ case RelOrientation::PAGE_RIGHT:
+ rRect.SetLeft( aPagePrtArea.Right() );
+ rRect.SetRight( aPage.Right() );
+ break;
+
+ case RelOrientation::PAGE_FRAME:
+ rRect.SetLeft( aPage.Left() );
+ rRect.SetRight( aPage.Right() );
+ break;
+
+ case RelOrientation::PAGE_PRINT_AREA:
+ rRect.SetLeft( aPagePrtArea.Left() );
+ rRect.SetRight( aPagePrtArea.Right() );
+ break;
+
+ case RelOrientation::FRAME_LEFT:
+ rRect.SetLeft( aPara.Left() );
+ rRect.SetRight( aParaPrtArea.Left() );
+ break;
+
+ case RelOrientation::FRAME_RIGHT:
+ rRect.SetLeft( aParaPrtArea.Right() );
+ rRect.SetRight( aPara.Right() );
+ break;
+
+ case RelOrientation::CHAR:
+ rRect.SetLeft( aAutoCharFrame.Left() );
+ rRect.SetRight( aAutoCharFrame.Left() );
+ break;
+ }
+
+ switch (nVRel)
+ {
+ case RelOrientation::FRAME:
+ rRect.SetTop( aPara.Top() );
+ rRect.SetBottom( aPara.Bottom() );
+ break;
+
+ case RelOrientation::PRINT_AREA:
+ rRect.SetTop( aParaPrtArea.Top() );
+ rRect.SetBottom( aParaPrtArea.Bottom() );
+ break;
+
+ case RelOrientation::CHAR:
+ if (nVAlign != VertOrientation::NONE &&
+ nVAlign != VertOrientation::CHAR_BOTTOM)
+ rRect.SetTop( aAutoCharFrame.Top() );
+ else
+ rRect.SetTop( aAutoCharFrame.Bottom() );
+ rRect.SetBottom( aAutoCharFrame.Bottom() );
+ break;
+ // OD 12.11.2003 #i22341#
+ case RelOrientation::TEXT_LINE:
+ rRect.SetTop( aAutoCharFrame.Top() );
+ rRect.SetBottom( aAutoCharFrame.Top() );
+ break;
+ }
+ }
+ break;
+
+ case RndStdIds::FLY_AS_CHAR:
+ rRect.SetLeft( aParaPrtArea.Left() );
+ rRect.SetRight( aParaPrtArea.Right() );
+
+ switch (nVAlign)
+ {
+ case VertOrientation::NONE:
+ case VertOrientation::TOP:
+ case VertOrientation::CENTER:
+ case VertOrientation::BOTTOM:
+ {
+ FontMetric aMetric(rRenderContext.GetFontMetric());
+
+ rRect.SetTop( aParaPrtArea.Bottom() - aMetric.GetDescent() );
+ rRect.SetBottom( rRect.Top() );
+ }
+ break;
+
+ default:
+
+ case VertOrientation::LINE_TOP:
+ case VertOrientation::LINE_CENTER:
+ case VertOrientation::LINE_BOTTOM:
+ rRect.SetTop( aParaPrtArea.Top() );
+ rRect.SetBottom( aDrawObj.Bottom() );
+ break;
+
+ case VertOrientation::CHAR_TOP:
+ case VertOrientation::CHAR_CENTER:
+ case VertOrientation::CHAR_BOTTOM:
+ rRect.SetTop( aParaPrtArea.Top() );
+ rRect.SetBottom( aParaPrtArea.Bottom() );
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+tools::Rectangle SwFrameExample::DrawInnerFrame_Impl(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect,
+ const Color &rFillColor, const Color &rBorderColor)
+{
+ DrawRect_Impl(rRenderContext, rRect, rFillColor, rBorderColor);
+
+ // determine the area relative to which the positioning happens
+ tools::Rectangle aRect(rRect); // aPagePrtArea = Default
+ CalcBoundRect_Impl(rRenderContext, aRect);
+
+ if (nAnchor == RndStdIds::FLY_AT_FLY && &rRect == &aPagePrtArea)
+ {
+ // draw text paragraph
+ tools::Rectangle aTxt(aTextLine);
+ sal_Int32 nStep = aTxt.GetHeight() + 2;
+ sal_uInt16 nLines = static_cast<sal_uInt16>(aParaPrtArea.GetHeight() / (aTextLine.GetHeight() + 2));
+
+ for (sal_uInt16 i = 0; i < nLines; i++)
+ {
+ if (i == nLines - 1)
+ aTxt.SetSize(Size(aTxt.GetWidth() / 2, aTxt.GetHeight()));
+ DrawRect_Impl(rRenderContext, aTxt, m_aTxtCol, m_aTransColor);
+ aTxt.Move(0, nStep);
+ }
+ }
+
+ return aRect;
+}
+
+void SwFrameExample::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapPixel));
+
+ InitAllRects_Impl(rRenderContext);
+
+ // Draw page
+ DrawRect_Impl(rRenderContext, aPage, m_aBgCol, m_aBorderCol);
+
+ // Draw PrintArea
+ tools::Rectangle aRect = DrawInnerFrame_Impl(rRenderContext, aPagePrtArea, m_aTransColor, m_aPrintAreaCol);
+
+ if (nAnchor == RndStdIds::FLY_AT_FLY)
+ aRect = DrawInnerFrame_Impl(rRenderContext, aFrameAtFrame, m_aBgCol, m_aBorderCol);
+
+ tools::Long lXPos = 0;
+ tools::Long lYPos = 0;
+
+ // Horizontal alignment
+ if (nAnchor != RndStdIds::FLY_AS_CHAR)
+ {
+ switch (nHAlign)
+ {
+ case HoriOrientation::RIGHT:
+ {
+ lXPos = aRect.Right() - aFrmSize.Width() + 1;
+ break;
+ }
+ case HoriOrientation::CENTER:
+ {
+ lXPos = aRect.Left() + (aRect.GetWidth() - aFrmSize.Width()) / 2;
+ break;
+ }
+ case HoriOrientation::NONE:
+ {
+ lXPos = aRect.Left() + aRelPos.X();
+ break;
+ }
+
+ default: // HoriOrientation::LEFT
+ lXPos = aRect.Left();
+ break;
+ }
+ }
+ else
+ {
+ lXPos = aRect.Right() + 2;
+ }
+
+ // Vertical Alignment
+ if (nAnchor != RndStdIds::FLY_AS_CHAR)
+ {
+ switch (nVAlign)
+ {
+ case VertOrientation::BOTTOM:
+ case VertOrientation::LINE_BOTTOM:
+ {
+ // #i22341#
+ if ( nVRel != RelOrientation::TEXT_LINE )
+ {
+ lYPos = aRect.Bottom() - aFrmSize.Height() + 1;
+ }
+ else
+ {
+ lYPos = aRect.Top();
+ }
+ break;
+ }
+ case VertOrientation::CENTER:
+ case VertOrientation::LINE_CENTER:
+ {
+ lYPos = aRect.Top() + (aRect.GetHeight() - aFrmSize.Height()) / 2;
+ break;
+ }
+ case VertOrientation::NONE:
+ {
+ // #i22341#
+ if ( nVRel != RelOrientation::CHAR && nVRel != RelOrientation::TEXT_LINE )
+ lYPos = aRect.Top() + aRelPos.Y();
+ else
+ lYPos = aRect.Top() - aRelPos.Y();
+ break;
+ }
+ default:
+ // #i22341#
+ if ( nVRel != RelOrientation::TEXT_LINE )
+ {
+ lYPos = aRect.Top();
+ }
+ else
+ {
+ lYPos = aRect.Bottom() - aFrmSize.Height() + 1;
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch(nVAlign)
+ {
+ case VertOrientation::CENTER:
+ case VertOrientation::CHAR_CENTER:
+ case VertOrientation::LINE_CENTER:
+ lYPos = aRect.Top() + (aRect.GetHeight() - aFrmSize.Height()) / 2;
+ break;
+
+ case VertOrientation::TOP:
+ case VertOrientation::CHAR_BOTTOM:
+ case VertOrientation::LINE_BOTTOM:
+ lYPos = aRect.Bottom() - aFrmSize.Height() + 1;
+ break;
+
+ default:
+ lYPos = aRect.Top() - aRelPos.Y();
+ break;
+ }
+ }
+
+ tools::Rectangle aFrmRect(Point(lXPos, lYPos), aFrmSize);
+
+ tools::Rectangle* pOuterFrame = &aPage;
+
+ if (nAnchor == RndStdIds::FLY_AT_FLY)
+ pOuterFrame = &aFrameAtFrame;
+
+ if (aFrmRect.Left() < pOuterFrame->Left())
+ aFrmRect.Move(pOuterFrame->Left() - aFrmRect.Left(), 0);
+ if (aFrmRect.Right() > pOuterFrame->Right())
+ aFrmRect.Move(pOuterFrame->Right() - aFrmRect.Right(), 0);
+
+ if (aFrmRect.Top() < pOuterFrame->Top())
+ aFrmRect.Move(0, pOuterFrame->Top() - aFrmRect.Top());
+ if (aFrmRect.Bottom() > pOuterFrame->Bottom())
+ aFrmRect.Move(0, pOuterFrame->Bottom() - aFrmRect.Bottom());
+
+ // Draw Test paragraph
+ const tools::Long nTxtLineHeight = aTextLine.GetHeight();
+ tools::Rectangle aTxt(aTextLine);
+ sal_Int32 nStep;
+ sal_uInt16 nLines;
+
+ if (nAnchor == RndStdIds::FLY_AT_FLY)
+ {
+ aTxt.SetLeft( aFrameAtFrame.Left() + FLYINFLY_BORDER );
+ aTxt.SetRight( aFrameAtFrame.Right() - FLYINFLY_BORDER );
+ aTxt.SetTop( aFrameAtFrame.Top() + FLYINFLY_BORDER );
+ aTxt.SetBottom( aTxt.Top() + aTextLine.GetHeight() - 1 );
+
+ nStep = aTxt.GetHeight() + 2;
+ nLines = static_cast<sal_uInt16>(((aFrameAtFrame.GetHeight() - 2 * FLYINFLY_BORDER) * 2 / 3)
+ / (aTxt.GetHeight() + 2));
+ }
+ else
+ {
+ nStep = aTxt.GetHeight() + 2;
+ nLines = static_cast<sal_uInt16>(aParaPrtArea.GetHeight() / (aTextLine.GetHeight() + 2));
+ }
+
+ if (nAnchor != RndStdIds::FLY_AS_CHAR)
+ {
+ // Simulate text
+ const tools::Long nOldR = aTxt.Right();
+ const tools::Long nOldL = aTxt.Left();
+
+ // #i22341#
+ const bool bIgnoreWrap = nAnchor == RndStdIds::FLY_AT_CHAR &&
+ ( nHRel == RelOrientation::CHAR || nVRel == RelOrientation::CHAR ||
+ nVRel == RelOrientation::TEXT_LINE );
+
+ for (sal_uInt16 i = 0; i < nLines; ++i)
+ {
+ if (i == (nLines - 1))
+ aTxt.SetSize(Size(aTxt.GetWidth() / 2, aTxt.GetHeight()));
+
+ if (aTxt.Overlaps(aFrmRect) && nAnchor != RndStdIds::FLY_AS_CHAR && !bIgnoreWrap)
+ {
+ switch(nWrap)
+ {
+ case WrapTextMode_NONE:
+ aTxt.SetTop( aFrmRect.Bottom() + nTxtLineHeight );
+ aTxt.SetBottom( aTxt.Top() + nTxtLineHeight - 1 );
+ break;
+
+ case WrapTextMode_LEFT:
+ aTxt.SetRight( aFrmRect.Left() );
+ break;
+
+ case WrapTextMode_RIGHT:
+ aTxt.SetLeft( aFrmRect.Right() );
+ break;
+ default: break;
+ }
+ }
+ if (pOuterFrame->Contains(aTxt))
+ DrawRect_Impl(rRenderContext, aTxt, m_aTxtCol, m_aTransColor );
+
+ aTxt.Move(0, nStep);
+ aTxt.SetRight( nOldR );
+ aTxt.SetLeft( nOldL );
+ }
+ aTxt.Move(0, -nStep);
+
+ if (nAnchor != RndStdIds::FLY_AT_FLY && aTxt.Bottom() > aParaPrtArea.Bottom())
+ {
+ // Text has been replaced by frame, so adjust parameters height
+ sal_Int32 nDiff = aTxt.Bottom() - aParaPrtArea.Bottom();
+ aParaPrtArea.AdjustBottom(nDiff );
+ aPara.AdjustBottom(nDiff );
+
+ CalcBoundRect_Impl(rRenderContext, aRect);
+
+ aParaPrtArea.AdjustBottom( -nDiff );
+ aPara.AdjustBottom( -nDiff );
+ }
+ if (nAnchor == RndStdIds::FLY_AT_CHAR && bIgnoreWrap)
+ rRenderContext.DrawText(aAutoCharFrame, OUString('A'));
+ }
+ else
+ {
+ rRenderContext.DrawText(aParaPrtArea, OUString(DEMOTEXT));
+ DrawRect_Impl(rRenderContext, aDrawObj, m_aBlankCol, m_aBlankFrameCol );
+ }
+
+ // Draw rectangle on which the frame is aligned:
+ DrawRect_Impl(rRenderContext, aRect, m_aTransColor, m_aAlignColor);
+
+ // Frame View
+ bool bDontFill = (nAnchor == RndStdIds::FLY_AT_CHAR && aFrmRect.Overlaps(aAutoCharFrame)) || bTrans;
+ DrawRect_Impl(rRenderContext, aFrmRect, bDontFill? m_aTransColor : m_aBgCol, m_aFrameColor);
+}
+
+void SwFrameExample::SetRelPos(const Point& rP)
+{
+ aRelPos = rP;
+
+ if (aRelPos.X() > 0)
+ aRelPos.setX( 5 );
+ if (aRelPos.X() < 0)
+ aRelPos.setX( -5 );
+
+ if (aRelPos.Y() > 0)
+ aRelPos.setY( 5 );
+ if (aRelPos.Y() < 0)
+ aRelPos.setY( -5 );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/swframeposstrings.cxx b/svx/source/dialog/swframeposstrings.cxx
new file mode 100644
index 000000000..29b9243f8
--- /dev/null
+++ b/svx/source/dialog/swframeposstrings.cxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <svx/swframeposstrings.hxx>
+#include <svx/dialmgr.hxx>
+#include <swframeposstrings.hrc>
+
+OUString SvxSwFramePosString::GetString(StringId eId)
+{
+ static_assert(
+ (SAL_N_ELEMENTS(RID_SVXSW_FRAMEPOSITIONS)
+ == SvxSwFramePosString::STR_MAX),
+ "RID_SVXSW_FRAMEPOSITIONS too small");
+ assert(eId >= 0 && eId < STR_MAX);
+ return SvxResId(RID_SVXSW_FRAMEPOSITIONS[eId]);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/txencbox.cxx b/svx/source/dialog/txencbox.cxx
new file mode 100644
index 000000000..0aff6781d
--- /dev/null
+++ b/svx/source/dialog/txencbox.cxx
@@ -0,0 +1,267 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <svx/txencbox.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/txenctab.hxx>
+#if HAVE_FEATURE_DBCONNECTIVITY
+#include <dbcharsethelper.hxx>
+#endif
+#include <unotools/syslocale.hxx>
+#include <rtl/tencinfo.h>
+#include <sal/log.hxx>
+#include <txenctab.hrc>
+
+namespace
+{
+ std::vector<rtl_TextEncoding> FillFromDbTextEncodingMap(bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags)
+ {
+ std::vector<rtl_TextEncoding> aRet;
+#if !HAVE_FEATURE_DBCONNECTIVITY
+ (void)bExcludeImportSubsets;
+ (void)nExcludeInfoFlags;
+#else
+ rtl_TextEncodingInfo aInfo;
+ aInfo.StructSize = sizeof(rtl_TextEncodingInfo);
+ ::std::vector< rtl_TextEncoding > aEncs;
+ sal_Int32 nCount = svxform::charset_helper::getSupportedTextEncodings( aEncs );
+ for ( sal_Int32 j=0; j<nCount; j++ )
+ {
+ bool bInsert = true;
+ rtl_TextEncoding nEnc = rtl_TextEncoding( aEncs[j] );
+ if ( nExcludeInfoFlags )
+ {
+ if ( !rtl_getTextEncodingInfo( nEnc, &aInfo ) )
+ bInsert = false;
+ else
+ {
+ if ( (aInfo.Flags & nExcludeInfoFlags) == 0 )
+ {
+ if ( (nExcludeInfoFlags & RTL_TEXTENCODING_INFO_UNICODE) &&
+ ((nEnc == RTL_TEXTENCODING_UCS2) ||
+ nEnc == RTL_TEXTENCODING_UCS4) )
+ bInsert = false; // InfoFlags don't work for Unicode :-(
+ }
+ else
+ bInsert = false;
+ }
+ }
+ if ( bInsert )
+ {
+ if ( bExcludeImportSubsets )
+ {
+ switch ( nEnc )
+ {
+ // subsets of RTL_TEXTENCODING_GB_18030
+ case RTL_TEXTENCODING_GB_2312 :
+ case RTL_TEXTENCODING_GBK :
+ case RTL_TEXTENCODING_MS_936 :
+ bInsert = false;
+ break;
+ }
+ }
+ // CharsetMap offers a RTL_TEXTENCODING_DONTKNOW for internal use,
+ // makes no sense here and would result in an empty string as list
+ // entry.
+ if ( bInsert && nEnc != RTL_TEXTENCODING_DONTKNOW )
+ aRet.push_back(nEnc);
+ }
+ }
+#endif
+ return aRet;
+ }
+}
+
+void SvxTextEncodingBox::FillFromDbTextEncodingMap(
+ bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags )
+{
+ m_xControl->freeze();
+ auto aEncs = ::FillFromDbTextEncodingMap(bExcludeImportSubsets, nExcludeInfoFlags);
+ for (auto nEnc : aEncs)
+ InsertTextEncoding(nEnc);
+ m_xControl->thaw();
+}
+
+void SvxTextEncodingTreeView::FillFromDbTextEncodingMap(
+ bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags )
+{
+ m_xControl->freeze();
+ auto aEncs = ::FillFromDbTextEncodingMap(bExcludeImportSubsets, nExcludeInfoFlags);
+ for (auto nEnc : aEncs)
+ InsertTextEncoding(nEnc);
+ m_xControl->thaw();
+}
+
+SvxTextEncodingBox::SvxTextEncodingBox(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+{
+ m_xControl->make_sorted();
+}
+
+SvxTextEncodingTreeView::SvxTextEncodingTreeView(std::unique_ptr<weld::TreeView> pControl)
+ : m_xControl(std::move(pControl))
+{
+ m_xControl->make_sorted();
+}
+
+SvxTextEncodingBox::~SvxTextEncodingBox()
+{
+}
+
+SvxTextEncodingTreeView::~SvxTextEncodingTreeView()
+{
+}
+
+namespace
+{
+ std::vector<int> FillFromTextEncodingTable(bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags, sal_uInt32 nButIncludeInfoFlags)
+ {
+ std::vector<int> aRet;
+
+ rtl_TextEncodingInfo aInfo;
+ aInfo.StructSize = sizeof(rtl_TextEncodingInfo);
+ const sal_uInt32 nCount = SAL_N_ELEMENTS(RID_SVXSTR_TEXTENCODING_TABLE);
+ for (sal_uInt32 j = 0; j < nCount; ++j)
+ {
+ bool bInsert = true;
+ rtl_TextEncoding nEnc = RID_SVXSTR_TEXTENCODING_TABLE[j].second;
+ if ( nExcludeInfoFlags )
+ {
+ if ( !rtl_getTextEncodingInfo( nEnc, &aInfo ) )
+ bInsert = false;
+ else
+ {
+ if ( (aInfo.Flags & nExcludeInfoFlags) == 0 )
+ {
+ if ( (nExcludeInfoFlags & RTL_TEXTENCODING_INFO_UNICODE) &&
+ ((nEnc == RTL_TEXTENCODING_UCS2) ||
+ nEnc == RTL_TEXTENCODING_UCS4) )
+ bInsert = false; // InfoFlags don't work for Unicode :-(
+ }
+ else if ( (aInfo.Flags & nButIncludeInfoFlags) == 0 )
+ bInsert = false;
+ }
+ }
+ if ( bExcludeImportSubsets )
+ {
+ switch ( nEnc )
+ {
+ // subsets of RTL_TEXTENCODING_GB_18030
+ case RTL_TEXTENCODING_GB_2312 :
+ case RTL_TEXTENCODING_GBK :
+ case RTL_TEXTENCODING_MS_936 :
+ bInsert = false;
+ break;
+ }
+ }
+ if ( bInsert )
+ aRet.push_back(j);
+ }
+ return aRet;
+ }
+}
+
+void SvxTextEncodingBox::FillFromTextEncodingTable(
+ bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags,
+ sal_uInt32 nButIncludeInfoFlags )
+{
+ std::vector<int> aRet(::FillFromTextEncodingTable(bExcludeImportSubsets, nExcludeInfoFlags, nButIncludeInfoFlags));
+ m_xControl->freeze();
+ for (auto j : aRet)
+ {
+ rtl_TextEncoding nEnc = RID_SVXSTR_TEXTENCODING_TABLE[j].second;
+ InsertTextEncoding(nEnc, SvxResId(RID_SVXSTR_TEXTENCODING_TABLE[j].first));
+ }
+ m_xControl->thaw();
+}
+
+void SvxTextEncodingTreeView::FillFromTextEncodingTable(
+ bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags )
+{
+ std::vector<int> aRet(::FillFromTextEncodingTable(bExcludeImportSubsets, nExcludeInfoFlags, /*nButIncludeInfoFlags*/0));
+ m_xControl->freeze();
+ for (auto j : aRet)
+ {
+ rtl_TextEncoding nEnc = RID_SVXSTR_TEXTENCODING_TABLE[j].second;
+ InsertTextEncoding(nEnc, SvxResId(RID_SVXSTR_TEXTENCODING_TABLE[j].first));
+ }
+ m_xControl->thaw();
+}
+
+void SvxTextEncodingBox::InsertTextEncoding( const rtl_TextEncoding nEnc,
+ const OUString& rEntry )
+{
+ m_xControl->append(OUString::number(nEnc), rEntry);
+}
+
+void SvxTextEncodingTreeView::InsertTextEncoding( const rtl_TextEncoding nEnc,
+ const OUString& rEntry )
+{
+ m_xControl->append(OUString::number(nEnc), rEntry);
+}
+
+void SvxTextEncodingBox::InsertTextEncoding( const rtl_TextEncoding nEnc )
+{
+ const OUString& rEntry = SvxTextEncodingTable::GetTextString(nEnc);
+ if (!rEntry.isEmpty())
+ InsertTextEncoding( nEnc, rEntry );
+ else
+ SAL_WARN( "svx.dialog", "SvxTextEncodingBox::InsertTextEncoding: no resource string for text encoding: " << static_cast<sal_Int32>( nEnc ) );
+}
+
+void SvxTextEncodingTreeView::InsertTextEncoding( const rtl_TextEncoding nEnc )
+{
+ const OUString& rEntry = SvxTextEncodingTable::GetTextString(nEnc);
+ if (!rEntry.isEmpty())
+ InsertTextEncoding( nEnc, rEntry );
+ else
+ SAL_WARN( "svx.dialog", "SvxTextEncodingTreeView::InsertTextEncoding: no resource string for text encoding: " << static_cast<sal_Int32>( nEnc ) );
+}
+
+rtl_TextEncoding SvxTextEncodingBox::GetSelectTextEncoding() const
+{
+ OUString sId(m_xControl->get_active_id());
+ if (!sId.isEmpty())
+ return rtl_TextEncoding(sId.toInt32());
+ else
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+rtl_TextEncoding SvxTextEncodingTreeView::GetSelectTextEncoding() const
+{
+ OUString sId(m_xControl->get_selected_id());
+ if (!sId.isEmpty())
+ return rtl_TextEncoding(sId.toInt32());
+ else
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+void SvxTextEncodingBox::SelectTextEncoding( const rtl_TextEncoding nEnc )
+{
+ m_xControl->set_active_id(OUString::number(nEnc));
+}
+
+void SvxTextEncodingTreeView::SelectTextEncoding( const rtl_TextEncoding nEnc )
+{
+ m_xControl->select_id(OUString::number(nEnc));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/txenctab.cxx b/svx/source/dialog/txenctab.cxx
new file mode 100644
index 000000000..791b8f735
--- /dev/null
+++ b/svx/source/dialog/txenctab.cxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/txenctab.hxx>
+#include <txenctab.hrc>
+
+OUString SvxTextEncodingTable::GetTextString(const rtl_TextEncoding nEnc)
+{
+ const size_t nCount = SAL_N_ELEMENTS(RID_SVXSTR_TEXTENCODING_TABLE);
+
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ if (RID_SVXSTR_TEXTENCODING_TABLE[i].second == nEnc)
+ return SvxResId(RID_SVXSTR_TEXTENCODING_TABLE[i].first);
+ }
+
+ return OUString();
+}
+
+rtl_TextEncoding SvxTextEncodingTable::GetTextEncoding(const OUString& rStr)
+{
+ const size_t nCount = SAL_N_ELEMENTS(RID_SVXSTR_TEXTENCODING_TABLE);
+
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ if (SvxResId(RID_SVXSTR_TEXTENCODING_TABLE[i].first).equals(rStr))
+ return RID_SVXSTR_TEXTENCODING_TABLE[i].second;
+ }
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/weldeditview.cxx b/svx/source/dialog/weldeditview.cxx
new file mode 100644
index 000000000..dfae0f308
--- /dev/null
+++ b/svx/source/dialog/weldeditview.cxx
@@ -0,0 +1,1682 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_wasm_strip.h>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/unoedhlp.hxx>
+#include <editeng/unoedsrc.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <osl/diagnose.h>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <sal/log.hxx>
+#include <svx/sdr/overlay/overlayselection.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <svx/AccessibleTextHelper.hxx>
+#include <svx/weldeditview.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/event.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <vcl/uitest/uiobject.hxx>
+
+void WeldEditView::SetText(const OUString& rStr) { GetEditEngine()->SetText(rStr); }
+
+OUString WeldEditView::GetText() const { return GetEditEngine()->GetText(); }
+
+void WeldEditView::SetModifyHdl(const Link<LinkParamNone*, void>& rLink)
+{
+ GetEditEngine()->SetModifyHdl(rLink);
+}
+
+EditView* WeldEditView::GetEditView() const { return m_xEditView.get(); }
+
+EditEngine* WeldEditView::GetEditEngine() const { return m_xEditEngine.get(); }
+
+bool WeldEditView::HasSelection() const
+{
+ EditView* pEditView = GetEditView();
+ return pEditView && pEditView->HasSelection();
+}
+
+void WeldEditView::Delete()
+{
+ if (EditView* pEditView = GetEditView())
+ pEditView->DeleteSelected();
+}
+
+void WeldEditView::Cut()
+{
+ if (EditView* pEditView = GetEditView())
+ pEditView->Cut();
+}
+
+void WeldEditView::Copy()
+{
+ if (EditView* pEditView = GetEditView())
+ pEditView->Copy();
+}
+
+void WeldEditView::Paste()
+{
+ if (EditView* pEditView = GetEditView())
+ pEditView->Paste();
+}
+
+WeldEditView::WeldEditView()
+ : m_bAcceptsTab(false)
+{
+}
+
+// tdf#127033 want to use UI font so override makeEditEngine to enable that
+void WeldEditView::makeEditEngine()
+{
+ rtl::Reference<SfxItemPool> pItemPool = EditEngine::CreatePool();
+
+ vcl::Font aAppFont(Application::GetSettings().GetStyleSettings().GetAppFont());
+
+ pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(),
+ "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW,
+ EE_CHAR_FONTINFO));
+ pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(),
+ "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW,
+ EE_CHAR_FONTINFO_CJK));
+ pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(),
+ "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW,
+ EE_CHAR_FONTINFO_CTL));
+
+ pItemPool->SetPoolDefaultItem(
+ SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT));
+ pItemPool->SetPoolDefaultItem(
+ SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CJK));
+ pItemPool->SetPoolDefaultItem(
+ SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CTL));
+
+ m_xEditEngine.reset(new EditEngine(pItemPool.get()));
+}
+
+void WeldEditView::Resize()
+{
+ if (EditView* pEditView = GetEditView())
+ {
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ Size aOutputSize(rDevice.PixelToLogic(GetOutputSizePixel()));
+ // Resizes the edit engine to adjust to the size of the output area
+ pEditView->SetOutputArea(tools::Rectangle(Point(0, 0), aOutputSize));
+ GetEditEngine()->SetPaperSize(aOutputSize);
+ pEditView->ShowCursor();
+
+ const tools::Long nMaxVisAreaStart
+ = pEditView->GetEditEngine()->GetTextHeight() - aOutputSize.Height();
+ tools::Rectangle aVisArea(pEditView->GetVisArea());
+ if (aVisArea.Top() > nMaxVisAreaStart)
+ {
+ aVisArea.SetTop(std::max<tools::Long>(nMaxVisAreaStart, 0));
+ aVisArea.SetSize(aOutputSize);
+ pEditView->SetVisArea(aVisArea);
+ pEditView->ShowCursor();
+ }
+
+ EditViewScrollStateChange();
+ }
+ weld::CustomWidgetController::Resize();
+}
+
+void WeldEditView::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ DoPaint(rRenderContext, rRect);
+}
+
+void WeldEditView::DoPaint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ rRenderContext.Push(vcl::PushFlags::ALL);
+ rRenderContext.SetClipRegion();
+
+ std::vector<tools::Rectangle> aLogicRects;
+
+ if (EditView* pEditView = GetEditView())
+ {
+ pEditView->Paint(rRect, &rRenderContext);
+
+ if (HasFocus())
+ {
+ pEditView->ShowCursor(false);
+ vcl::Cursor* pCursor = pEditView->GetCursor();
+ pCursor->DrawToDevice(rRenderContext);
+ }
+
+ // get logic selection
+ pEditView->GetSelectionRectangles(aLogicRects);
+ }
+
+ if (!aLogicRects.empty())
+ {
+ std::vector<basegfx::B2DRange> aLogicRanges;
+ aLogicRanges.reserve(aLogicRects.size());
+
+ tools::Long nMinX(LONG_MAX), nMaxX(0), nMinY(LONG_MAX), nMaxY(0);
+ for (const auto& aRect : aLogicRects)
+ {
+ nMinX = std::min(nMinX, aRect.Left());
+ nMinY = std::min(nMinY, aRect.Top());
+ nMaxX = std::max(nMaxX, aRect.Right());
+ nMaxY = std::max(nMaxY, aRect.Bottom());
+ }
+
+ const Size aLogicPixel(rRenderContext.PixelToLogic(Size(1, 1)));
+ for (const auto& aRect : aLogicRects)
+ {
+ // Extend each range by one pixel so multiple lines touch each
+ // other if adjacent, so the whole set is drawn with a single
+ // border around the lot. But keep the selection within the
+ // original max extents.
+ auto nTop = aRect.Top();
+ if (nTop > nMinY)
+ nTop -= aLogicPixel.Height();
+ auto nBottom = aRect.Bottom();
+ if (nBottom < nMaxY)
+ nBottom += aLogicPixel.Height();
+ auto nLeft = aRect.Left();
+ if (nLeft > nMinX)
+ nLeft -= aLogicPixel.Width();
+ auto nRight = aRect.Right();
+ if (nRight < nMaxX)
+ nRight += aLogicPixel.Width();
+
+ aLogicRanges.emplace_back(nLeft, nTop, nRight, nBottom);
+ }
+
+ // get the system's highlight color
+ const Color aHighlight(SvtOptionsDrawinglayer::getHilightColor());
+
+ sdr::overlay::OverlaySelection aCursorOverlay(sdr::overlay::OverlayType::Transparent,
+ aHighlight, std::move(aLogicRanges), true);
+
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D(
+ basegfx::B2DHomMatrix(), rRenderContext.GetViewTransformation(),
+ vcl::unotools::b2DRectangleFromRectangle(rRect), nullptr, 0.0);
+
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor(
+ drawinglayer::processor2d::createProcessor2DFromOutputDevice(rRenderContext,
+ aViewInformation2D));
+
+ xProcessor->process(aCursorOverlay.getOverlayObjectPrimitive2DSequence());
+ }
+
+ rRenderContext.Pop();
+}
+
+bool WeldEditView::MouseMove(const MouseEvent& rMEvt)
+{
+ EditView* pEditView = GetEditView();
+ return pEditView && pEditView->MouseMove(rMEvt);
+}
+
+bool WeldEditView::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if (!IsMouseCaptured())
+ CaptureMouse();
+
+ if (!HasFocus() && CanFocus())
+ GrabFocus();
+
+ EditView* pEditView = GetEditView();
+ return pEditView && pEditView->MouseButtonDown(rMEvt);
+}
+
+bool WeldEditView::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if (IsMouseCaptured())
+ ReleaseMouse();
+ EditView* pEditView = GetEditView();
+ return pEditView && pEditView->MouseButtonUp(rMEvt);
+}
+
+bool WeldEditView::KeyInput(const KeyEvent& rKEvt)
+{
+ EditView* pEditView = GetEditView();
+
+ sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
+
+ if (nKey == KEY_TAB && !GetAcceptsTab())
+ {
+ return false;
+ }
+ else if (pEditView && !pEditView->PostKeyEvent(rKEvt))
+ {
+ if (rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2())
+ {
+ if (nKey == KEY_A)
+ {
+ EditEngine* pEditEngine = GetEditEngine();
+ sal_Int32 nPar = pEditEngine->GetParagraphCount();
+ if (nPar)
+ {
+ sal_Int32 nLen = pEditEngine->GetTextLen(nPar - 1);
+ pEditView->SetSelection(ESelection(0, 0, nPar - 1, nLen));
+ }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+bool WeldEditView::Command(const CommandEvent& rCEvt)
+{
+ EditView* pEditView = GetEditView();
+ if (!pEditView)
+ return false;
+ return pEditView->Command(rCEvt);
+}
+
+Point WeldEditView::EditViewPointerPosPixel() const
+{
+ return GetDrawingArea()->get_pointer_position();
+}
+
+class WeldEditAccessible;
+
+namespace
+{
+class WeldViewForwarder : public SvxViewForwarder
+{
+ WeldEditAccessible& m_rEditAcc;
+
+ WeldViewForwarder(const WeldViewForwarder&) = delete;
+ WeldViewForwarder& operator=(const WeldViewForwarder&) = delete;
+
+public:
+ explicit WeldViewForwarder(WeldEditAccessible& rAcc)
+ : m_rEditAcc(rAcc)
+ {
+ }
+
+ virtual bool IsValid() const override;
+ virtual Point LogicToPixel(const Point& rPoint, const MapMode& rMapMode) const override;
+ virtual Point PixelToLogic(const Point& rPoint, const MapMode& rMapMode) const override;
+};
+}
+
+class WeldEditAccessible;
+
+namespace
+{
+class WeldEditSource;
+
+/* analog to SvxEditEngineForwarder */
+class WeldTextForwarder : public SvxTextForwarder
+{
+ WeldEditAccessible& m_rEditAcc;
+ WeldEditSource& m_rEditSource;
+
+ DECL_LINK(NotifyHdl, EENotify&, void);
+
+ WeldTextForwarder(const WeldTextForwarder&) = delete;
+ WeldTextForwarder& operator=(const WeldTextForwarder&) = delete;
+
+public:
+ WeldTextForwarder(WeldEditAccessible& rAcc, WeldEditSource& rSource);
+ virtual ~WeldTextForwarder() override;
+
+ virtual sal_Int32 GetParagraphCount() const override;
+ virtual sal_Int32 GetTextLen(sal_Int32 nParagraph) const override;
+ virtual OUString GetText(const ESelection& rSel) const override;
+ virtual SfxItemSet GetAttribs(const ESelection& rSel, EditEngineAttribs nOnlyHardAttrib
+ = EditEngineAttribs::All) const override;
+ virtual SfxItemSet GetParaAttribs(sal_Int32 nPara) const override;
+ virtual void SetParaAttribs(sal_Int32 nPara, const SfxItemSet& rSet) override;
+ virtual void RemoveAttribs(const ESelection& rSelection) override;
+ virtual void GetPortions(sal_Int32 nPara, std::vector<sal_Int32>& rList) const override;
+
+ virtual SfxItemState GetItemState(const ESelection& rSel, sal_uInt16 nWhich) const override;
+ virtual SfxItemState GetItemState(sal_Int32 nPara, sal_uInt16 nWhich) const override;
+
+ virtual void QuickInsertText(const OUString& rText, const ESelection& rSel) override;
+ virtual void QuickInsertField(const SvxFieldItem& rFld, const ESelection& rSel) override;
+ virtual void QuickSetAttribs(const SfxItemSet& rSet, const ESelection& rSel) override;
+ virtual void QuickInsertLineBreak(const ESelection& rSel) override;
+
+ virtual SfxItemPool* GetPool() const override;
+
+ virtual OUString CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos,
+ std::optional<Color>& rpTxtColor,
+ std::optional<Color>& rpFldColor) override;
+ virtual void FieldClicked(const SvxFieldItem&) override;
+ virtual bool IsValid() const override;
+
+ virtual LanguageType GetLanguage(sal_Int32, sal_Int32) const override;
+ virtual sal_Int32 GetFieldCount(sal_Int32 nPara) const override;
+ virtual EFieldInfo GetFieldInfo(sal_Int32 nPara, sal_uInt16 nField) const override;
+ virtual EBulletInfo GetBulletInfo(sal_Int32 nPara) const override;
+ virtual tools::Rectangle GetCharBounds(sal_Int32 nPara, sal_Int32 nIndex) const override;
+ virtual tools::Rectangle GetParaBounds(sal_Int32 nPara) const override;
+ virtual MapMode GetMapMode() const override;
+ virtual OutputDevice* GetRefDevice() const override;
+ virtual bool GetIndexAtPoint(const Point&, sal_Int32& nPara, sal_Int32& nIndex) const override;
+ virtual bool GetWordIndices(sal_Int32 nPara, sal_Int32 nIndex, sal_Int32& nStart,
+ sal_Int32& nEnd) const override;
+ virtual bool GetAttributeRun(sal_Int32& nStartIndex, sal_Int32& nEndIndex, sal_Int32 nPara,
+ sal_Int32 nIndex, bool bInCell = false) const override;
+ virtual sal_Int32 GetLineCount(sal_Int32 nPara) const override;
+ virtual sal_Int32 GetLineLen(sal_Int32 nPara, sal_Int32 nLine) const override;
+ virtual void GetLineBoundaries(/*out*/ sal_Int32& rStart, /*out*/ sal_Int32& rEnd,
+ sal_Int32 nParagraph, sal_Int32 nLine) const override;
+ virtual sal_Int32 GetLineNumberAtIndex(sal_Int32 nPara, sal_Int32 nLine) const override;
+ virtual bool Delete(const ESelection&) override;
+ virtual bool InsertText(const OUString&, const ESelection&) override;
+ virtual bool QuickFormatDoc(bool bFull = false) override;
+
+ virtual sal_Int16 GetDepth(sal_Int32 nPara) const override;
+ virtual bool SetDepth(sal_Int32 nPara, sal_Int16 nNewDepth) override;
+
+ virtual const SfxItemSet* GetEmptyItemSetPtr() override;
+ // implementation functions for XParagraphAppend and XTextPortionAppend
+ virtual void AppendParagraph() override;
+ virtual sal_Int32 AppendTextPortion(sal_Int32 nPara, const OUString& rText,
+ const SfxItemSet& rSet) override;
+
+ virtual void CopyText(const SvxTextForwarder& rSource) override;
+};
+
+/* analog to SvxEditEngineViewForwarder */
+class WeldEditViewForwarder : public SvxEditViewForwarder
+{
+ WeldEditAccessible& m_rEditAcc;
+
+ WeldEditViewForwarder(const WeldEditViewForwarder&) = delete;
+ WeldEditViewForwarder& operator=(const WeldEditViewForwarder&) = delete;
+
+public:
+ explicit WeldEditViewForwarder(WeldEditAccessible& rAcc);
+
+ virtual bool IsValid() const override;
+
+ virtual Point LogicToPixel(const Point& rPoint, const MapMode& rMapMode) const override;
+ virtual Point PixelToLogic(const Point& rPoint, const MapMode& rMapMode) const override;
+
+ virtual bool GetSelection(ESelection& rSelection) const override;
+ virtual bool SetSelection(const ESelection& rSelection) override;
+ virtual bool Copy() override;
+ virtual bool Cut() override;
+ virtual bool Paste() override;
+};
+
+class WeldEditSource : public SvxEditSource
+{
+ SfxBroadcaster m_aBroadCaster;
+ WeldViewForwarder m_aViewFwd;
+ WeldTextForwarder m_aTextFwd;
+ WeldEditViewForwarder m_aEditViewFwd;
+ WeldEditAccessible& m_rEditAcc;
+
+ WeldEditSource(const WeldEditSource& rSrc)
+ : SvxEditSource()
+ , m_aViewFwd(rSrc.m_rEditAcc)
+ , m_aTextFwd(rSrc.m_rEditAcc, *this)
+ , m_aEditViewFwd(rSrc.m_rEditAcc)
+ , m_rEditAcc(rSrc.m_rEditAcc)
+ {
+ }
+
+ WeldEditSource& operator=(const WeldEditSource&) = delete;
+
+public:
+ WeldEditSource(WeldEditAccessible& rAcc)
+ : m_aViewFwd(rAcc)
+ , m_aTextFwd(rAcc, *this)
+ , m_aEditViewFwd(rAcc)
+ , m_rEditAcc(rAcc)
+ {
+ }
+
+ virtual std::unique_ptr<SvxEditSource> Clone() const override
+ {
+ return std::unique_ptr<SvxEditSource>(new WeldEditSource(*this));
+ }
+
+ virtual SvxTextForwarder* GetTextForwarder() override { return &m_aTextFwd; }
+
+ virtual SvxViewForwarder* GetViewForwarder() override { return &m_aViewFwd; }
+
+ virtual SvxEditViewForwarder* GetEditViewForwarder(bool /*bCreate*/) override
+ {
+ return &m_aEditViewFwd;
+ }
+
+ virtual void UpdateData() override
+ {
+ // would possibly only by needed if the XText interface is implemented
+ // and its text needs to be updated.
+ }
+ virtual SfxBroadcaster& GetBroadcaster() const override
+ {
+ return const_cast<WeldEditSource*>(this)->m_aBroadCaster;
+ }
+};
+}
+
+typedef cppu::WeakImplHelper<css::lang::XServiceInfo, css::accessibility::XAccessible,
+ css::accessibility::XAccessibleComponent,
+ css::accessibility::XAccessibleContext,
+ css::accessibility::XAccessibleEventBroadcaster>
+ WeldEditAccessibleBaseClass;
+
+class WeldEditAccessible : public WeldEditAccessibleBaseClass
+{
+ weld::CustomWidgetController* m_pController;
+ EditEngine* m_pEditEngine;
+ EditView* m_pEditView;
+ std::unique_ptr<::accessibility::AccessibleTextHelper> m_xTextHelper;
+
+public:
+ WeldEditAccessible(weld::CustomWidgetController* pController)
+ : m_pController(pController)
+ , m_pEditEngine(nullptr)
+ , m_pEditView(nullptr)
+ {
+ }
+
+ ::accessibility::AccessibleTextHelper* GetTextHelper() { return m_xTextHelper.get(); }
+
+ void Init(EditEngine* pEditEngine, EditView* pEditView)
+ {
+ m_pEditEngine = pEditEngine;
+ m_pEditView = pEditView;
+ m_xTextHelper.reset(
+ new ::accessibility::AccessibleTextHelper(std::make_unique<WeldEditSource>(*this)));
+ m_xTextHelper->SetEventSource(this);
+ }
+
+ EditEngine* GetEditEngine() { return m_pEditEngine; }
+ EditView* GetEditView() { return m_pEditView; }
+
+ void ClearWin()
+ {
+ // remove handler before current object gets destroyed
+ // (avoid handler being called for already dead object)
+ m_pEditEngine->SetNotifyHdl(Link<EENotify&, void>());
+
+ m_pEditEngine = nullptr;
+ m_pEditView = nullptr;
+ m_pController = nullptr; // implicitly results in AccessibleStateType::DEFUNC set
+
+ //! make TextHelper implicitly release C++ references to some core objects
+ m_xTextHelper->SetEditSource(::std::unique_ptr<SvxEditSource>());
+
+ //! make TextHelper release references
+ //! (e.g. the one set by the 'SetEventSource' call)
+ m_xTextHelper->Dispose();
+ m_xTextHelper.reset();
+ }
+
+ // XAccessible
+ virtual css::uno::Reference<css::accessibility::XAccessibleContext>
+ SAL_CALL getAccessibleContext() override
+ {
+ return this;
+ }
+
+ // XAccessibleComponent
+ virtual sal_Bool SAL_CALL containsPoint(const css::awt::Point& rPoint) override
+ {
+ //! the arguments coordinates are relative to the current window !
+ //! Thus the top left-point is (0, 0)
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ Size aSz(m_pController->GetOutputSizePixel());
+ return rPoint.X >= 0 && rPoint.Y >= 0 && rPoint.X < aSz.Width() && rPoint.Y < aSz.Height();
+ }
+
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getAccessibleAtPoint(const css::awt::Point& rPoint) override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_xTextHelper)
+ throw css::uno::RuntimeException();
+
+ return m_xTextHelper->GetAt(rPoint);
+ }
+
+ virtual css::awt::Rectangle SAL_CALL getBounds() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ const Point aOutPos;
+ const Size aOutSize(m_pController->GetOutputSizePixel());
+ css::awt::Rectangle aRet;
+
+ aRet.X = aOutPos.X();
+ aRet.Y = aOutPos.Y();
+ aRet.Width = aOutSize.Width();
+ aRet.Height = aOutSize.Height();
+
+ return aRet;
+ }
+
+ virtual css::awt::Point SAL_CALL getLocation() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ const css::awt::Rectangle aRect(getBounds());
+ css::awt::Point aRet;
+
+ aRet.X = aRect.X;
+ aRet.Y = aRect.Y;
+
+ return aRet;
+ }
+
+ virtual css::awt::Point SAL_CALL getLocationOnScreen() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ css::awt::Point aScreenLoc(0, 0);
+
+ if (weld::DrawingArea* pDrawingArea = m_pController->GetDrawingArea())
+ {
+ Point aPos = pDrawingArea->get_accessible_location_on_screen();
+ aScreenLoc.X = aPos.X();
+ aScreenLoc.Y = aPos.Y();
+ }
+
+ return aScreenLoc;
+ }
+
+ virtual css::awt::Size SAL_CALL getSize() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ Size aSz(m_pController->GetOutputSizePixel());
+ return css::awt::Size(aSz.Width(), aSz.Height());
+ }
+
+ virtual void SAL_CALL grabFocus() override { m_pController->GrabFocus(); }
+
+ virtual sal_Int32 SAL_CALL getForeground() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ Color nCol = m_pEditEngine->GetAutoColor();
+ return static_cast<sal_Int32>(nCol);
+ }
+
+ virtual sal_Int32 SAL_CALL getBackground() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ Color nCol = m_pEditEngine->GetBackgroundColor();
+ return static_cast<sal_Int32>(nCol);
+ }
+
+ // XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override
+ {
+ if (m_xTextHelper)
+ return m_xTextHelper->GetChildCount();
+ return 0;
+ }
+
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getAccessibleChild(sal_Int32 i) override
+ {
+ if (m_xTextHelper)
+ return m_xTextHelper->GetChild(i);
+ throw css::lang::IndexOutOfBoundsException(); // there is no child...
+ }
+
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getAccessibleParent() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ return m_pController->GetDrawingArea()->get_accessible_parent();
+ }
+
+ virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ // -1 for child not found/no parent (according to specification)
+ sal_Int32 nRet = -1;
+
+ css::uno::Reference<css::accessibility::XAccessible> xParent(getAccessibleParent());
+ if (!xParent)
+ return nRet;
+
+ try
+ {
+ css::uno::Reference<css::accessibility::XAccessibleContext> xParentContext(
+ xParent->getAccessibleContext());
+
+ // iterate over parent's children and search for this object
+ if (xParentContext.is())
+ {
+ sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
+ for (sal_Int32 nChild = 0; (nChild < nChildCount) && (-1 == nRet); ++nChild)
+ {
+ css::uno::Reference<css::accessibility::XAccessible> xChild(
+ xParentContext->getAccessibleChild(nChild));
+ if (xChild.get() == this)
+ nRet = nChild;
+ }
+ }
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "WeldEditAccessible::getAccessibleIndexInParent");
+ }
+
+ return nRet;
+ }
+
+ virtual sal_Int16 SAL_CALL getAccessibleRole() override
+ {
+ return css::accessibility::AccessibleRole::TEXT_FRAME;
+ }
+
+ virtual OUString SAL_CALL getAccessibleDescription() override
+ {
+ SolarMutexGuard aGuard;
+
+ OUString aRet;
+
+ if (m_pController)
+ {
+ aRet = m_pController->GetAccessibleDescription();
+ }
+
+ return aRet;
+ }
+
+ virtual OUString SAL_CALL getAccessibleName() override
+ {
+ SolarMutexGuard aGuard;
+
+ OUString aRet;
+
+ if (m_pController)
+ {
+ aRet = m_pController->GetAccessibleName();
+ }
+
+ return aRet;
+ }
+
+ virtual css::uno::Reference<css::accessibility::XAccessibleRelationSet>
+ SAL_CALL getAccessibleRelationSet() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ return m_pController->GetDrawingArea()->get_accessible_relation_set();
+ }
+
+ virtual css::uno::Reference<css::accessibility::XAccessibleStateSet>
+ SAL_CALL getAccessibleStateSet() override
+ {
+ SolarMutexGuard aGuard;
+ rtl::Reference<::utl::AccessibleStateSetHelper> pStateSet
+ = new ::utl::AccessibleStateSetHelper;
+
+ if (!m_pController || !m_xTextHelper)
+ pStateSet->AddState(css::accessibility::AccessibleStateType::DEFUNC);
+ else
+ {
+ pStateSet->AddState(css::accessibility::AccessibleStateType::MULTI_LINE);
+ pStateSet->AddState(css::accessibility::AccessibleStateType::ENABLED);
+ pStateSet->AddState(css::accessibility::AccessibleStateType::EDITABLE);
+ pStateSet->AddState(css::accessibility::AccessibleStateType::FOCUSABLE);
+ pStateSet->AddState(css::accessibility::AccessibleStateType::SELECTABLE);
+ if (m_pController->HasFocus())
+ pStateSet->AddState(css::accessibility::AccessibleStateType::FOCUSED);
+ if (m_pController->IsActive())
+ pStateSet->AddState(css::accessibility::AccessibleStateType::ACTIVE);
+ if (m_pController->IsVisible())
+ pStateSet->AddState(css::accessibility::AccessibleStateType::SHOWING);
+ if (m_pController->IsReallyVisible())
+ pStateSet->AddState(css::accessibility::AccessibleStateType::VISIBLE);
+ if (COL_TRANSPARENT != m_pEditEngine->GetBackgroundColor())
+ pStateSet->AddState(css::accessibility::AccessibleStateType::OPAQUE);
+ }
+
+ return pStateSet;
+ }
+
+ virtual css::lang::Locale SAL_CALL getLocale() override
+ {
+ SolarMutexGuard aGuard;
+ return LanguageTag(m_pEditEngine->GetDefaultLanguage()).getLocale();
+ }
+
+ // XAccessibleEventBroadcaster
+ virtual void SAL_CALL addAccessibleEventListener(
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener>& rListener) override
+ {
+ if (!m_xTextHelper) // not disposing (about to destroy view shell)
+ return;
+ m_xTextHelper->AddEventListener(rListener);
+ }
+
+ virtual void SAL_CALL removeAccessibleEventListener(
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener>& rListener) override
+ {
+ if (!m_xTextHelper) // not disposing (about to destroy view shell)
+ return;
+ m_xTextHelper->RemoveEventListener(rListener);
+ }
+
+ virtual OUString SAL_CALL getImplementationName() override { return "WeldEditAccessible"; }
+
+ virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override
+ {
+ return cppu::supportsService(this, rServiceName);
+ }
+
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
+ {
+ return { "css::accessibility::Accessible", "css::accessibility::AccessibleComponent",
+ "css::accessibility::AccessibleContext" };
+ }
+};
+
+css::uno::Reference<css::accessibility::XAccessible> WeldEditView::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (!m_xAccessible.is())
+ m_xAccessible.set(new WeldEditAccessible(this));
+#endif
+ return m_xAccessible;
+}
+
+WeldEditView::~WeldEditView()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccessible.is())
+ {
+ m_xAccessible->ClearWin(); // make Accessible nonfunctional
+ m_xAccessible.clear();
+ }
+#endif
+}
+
+bool WeldViewForwarder::IsValid() const { return m_rEditAcc.GetEditView() != nullptr; }
+
+Point WeldViewForwarder::LogicToPixel(const Point& rPoint, const MapMode& rMapMode) const
+{
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (!pEditView)
+ return Point();
+ OutputDevice& rOutDev = pEditView->GetOutputDevice();
+ MapMode aMapMode(rOutDev.GetMapMode());
+ Point aPoint(OutputDevice::LogicToLogic(rPoint, rMapMode, MapMode(aMapMode.GetMapUnit())));
+ aMapMode.SetOrigin(Point());
+ return rOutDev.LogicToPixel(aPoint, aMapMode);
+}
+
+Point WeldViewForwarder::PixelToLogic(const Point& rPoint, const MapMode& rMapMode) const
+{
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (!pEditView)
+ return Point();
+ OutputDevice& rOutDev = pEditView->GetOutputDevice();
+ MapMode aMapMode(rOutDev.GetMapMode());
+ aMapMode.SetOrigin(Point());
+ Point aPoint(rOutDev.PixelToLogic(rPoint, aMapMode));
+ return OutputDevice::LogicToLogic(aPoint, MapMode(aMapMode.GetMapUnit()), rMapMode);
+}
+
+WeldTextForwarder::WeldTextForwarder(WeldEditAccessible& rAcc, WeldEditSource& rSource)
+ : m_rEditAcc(rAcc)
+ , m_rEditSource(rSource)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->SetNotifyHdl(LINK(this, WeldTextForwarder, NotifyHdl));
+}
+
+WeldTextForwarder::~WeldTextForwarder()
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->SetNotifyHdl(Link<EENotify&, void>());
+}
+
+IMPL_LINK(WeldTextForwarder, NotifyHdl, EENotify&, rNotify, void)
+{
+ if (EditEngine* pEditEngine = m_rEditAcc.GetEditEngine())
+ {
+ if (rNotify.eNotificationType == EE_NOTIFY_PROCESSNOTIFICATIONS
+ && !pEditEngine->IsUpdateLayout())
+ {
+ // tdf#143088 an UpdateMode of false will just to on to cause
+ // AccessibleTextHelper_Impl::GetTextForwarder to throw an
+ // exception as a Frozen EditEngine is considered Invalid so return
+ // early instead
+ return;
+ }
+ }
+
+ ::std::unique_ptr<SfxHint> aHint = SvxEditSourceHelper::EENotification2Hint(&rNotify);
+ if (aHint)
+ m_rEditSource.GetBroadcaster().Broadcast(*aHint);
+}
+
+sal_Int32 WeldTextForwarder::GetParagraphCount() const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetParagraphCount() : 0;
+}
+
+sal_Int32 WeldTextForwarder::GetTextLen(sal_Int32 nParagraph) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetTextLen(nParagraph) : 0;
+}
+
+OUString WeldTextForwarder::GetText(const ESelection& rSel) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ OUString aRet;
+ if (pEditEngine)
+ aRet = pEditEngine->GetText(rSel);
+ return convertLineEnd(aRet, GetSystemLineEnd());
+}
+
+SfxItemSet WeldTextForwarder::GetAttribs(const ESelection& rSel,
+ EditEngineAttribs nOnlyHardAttrib) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ assert(pEditEngine && "EditEngine missing");
+ if (rSel.nStartPara == rSel.nEndPara)
+ {
+ GetAttribsFlags nFlags = GetAttribsFlags::NONE;
+ switch (nOnlyHardAttrib)
+ {
+ case EditEngineAttribs::All:
+ nFlags = GetAttribsFlags::ALL;
+ break;
+ case EditEngineAttribs::OnlyHard:
+ nFlags = GetAttribsFlags::CHARATTRIBS;
+ break;
+ default:
+ SAL_WARN("svx", "unknown flags for WeldTextForwarder::GetAttribs");
+ }
+
+ return pEditEngine->GetAttribs(rSel.nStartPara, rSel.nStartPos, rSel.nEndPos, nFlags);
+ }
+ else
+ {
+ return pEditEngine->GetAttribs(rSel, nOnlyHardAttrib);
+ }
+}
+
+SfxItemSet WeldTextForwarder::GetParaAttribs(sal_Int32 nPara) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ assert(pEditEngine && "EditEngine missing");
+
+ SfxItemSet aSet(pEditEngine->GetParaAttribs(nPara));
+
+ sal_uInt16 nWhich = EE_PARA_START;
+ while (nWhich <= EE_PARA_END)
+ {
+ if (aSet.GetItemState(nWhich) != SfxItemState::SET)
+ {
+ if (pEditEngine->HasParaAttrib(nPara, nWhich))
+ aSet.Put(pEditEngine->GetParaAttrib(nPara, nWhich));
+ }
+ nWhich++;
+ }
+
+ return aSet;
+}
+
+void WeldTextForwarder::SetParaAttribs(sal_Int32 nPara, const SfxItemSet& rSet)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->SetParaAttribs(nPara, rSet);
+}
+
+SfxItemPool* WeldTextForwarder::GetPool() const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetEmptyItemSet().GetPool() : nullptr;
+}
+
+void WeldTextForwarder::RemoveAttribs(const ESelection& rSelection)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->RemoveAttribs(rSelection, false /*bRemoveParaAttribs*/, 0);
+}
+
+void WeldTextForwarder::GetPortions(sal_Int32 nPara, std::vector<sal_Int32>& rList) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->GetPortions(nPara, rList);
+}
+
+void WeldTextForwarder::QuickInsertText(const OUString& rText, const ESelection& rSel)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->QuickInsertText(rText, rSel);
+}
+
+void WeldTextForwarder::QuickInsertLineBreak(const ESelection& rSel)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->QuickInsertLineBreak(rSel);
+}
+
+void WeldTextForwarder::QuickInsertField(const SvxFieldItem& rFld, const ESelection& rSel)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->QuickInsertField(rFld, rSel);
+}
+
+void WeldTextForwarder::QuickSetAttribs(const SfxItemSet& rSet, const ESelection& rSel)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->QuickSetAttribs(rSet, rSel);
+}
+
+bool WeldTextForwarder::IsValid() const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ // cannot reliably query EditEngine state
+ // while in the middle of an update
+ return pEditEngine && pEditEngine->IsUpdateLayout();
+}
+
+OUString WeldTextForwarder::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara,
+ sal_Int32 nPos, std::optional<Color>& rpTxtColor,
+ std::optional<Color>& rpFldColor)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->CalcFieldValue(rField, nPara, nPos, rpTxtColor, rpFldColor)
+ : OUString();
+}
+
+void WeldTextForwarder::FieldClicked(const SvxFieldItem&) {}
+
+static SfxItemState GetSvxEditEngineItemState(EditEngine const& rEditEngine, const ESelection& rSel,
+ sal_uInt16 nWhich)
+{
+ std::vector<EECharAttrib> aAttribs;
+
+ const SfxPoolItem* pLastItem = nullptr;
+
+ SfxItemState eState = SfxItemState::DEFAULT;
+
+ // check all paragraphs inside the selection
+ for (sal_Int32 nPara = rSel.nStartPara; nPara <= rSel.nEndPara; nPara++)
+ {
+ SfxItemState eParaState = SfxItemState::DEFAULT;
+
+ // calculate start and endpos for this paragraph
+ sal_Int32 nPos = 0;
+ if (rSel.nStartPara == nPara)
+ nPos = rSel.nStartPos;
+
+ sal_Int32 nEndPos = rSel.nEndPos;
+ if (rSel.nEndPara != nPara)
+ nEndPos = rEditEngine.GetTextLen(nPara);
+
+ // get list of char attribs
+ rEditEngine.GetCharAttribs(nPara, aAttribs);
+
+ bool bEmpty = true; // we found no item inside the selection of this paragraph
+ bool bGaps = false; // we found items but there are gaps between them
+ sal_Int32 nLastEnd = nPos;
+
+ const SfxPoolItem* pParaItem = nullptr;
+
+ for (const auto& rAttrib : aAttribs)
+ {
+ OSL_ENSURE(rAttrib.pAttr, "GetCharAttribs gives corrupt data");
+
+ const bool bEmptyPortion = (rAttrib.nStart == rAttrib.nEnd);
+ if ((!bEmptyPortion && (rAttrib.nStart >= nEndPos))
+ || (bEmptyPortion && (rAttrib.nStart > nEndPos)))
+ break; // break if we are already behind our selection
+
+ if ((!bEmptyPortion && (rAttrib.nEnd <= nPos))
+ || (bEmptyPortion && (rAttrib.nEnd < nPos)))
+ continue; // or if the attribute ends before our selection
+
+ if (rAttrib.pAttr->Which() != nWhich)
+ continue; // skip if is not the searched item
+
+ // if we already found an item
+ if (pParaItem)
+ {
+ // ... and its different to this one than the state is don't care
+ if (*pParaItem != *(rAttrib.pAttr))
+ return SfxItemState::DONTCARE;
+ }
+ else
+ {
+ pParaItem = rAttrib.pAttr;
+ }
+
+ if (bEmpty)
+ bEmpty = false;
+
+ if (!bGaps && rAttrib.nStart > nLastEnd)
+ bGaps = true;
+
+ nLastEnd = rAttrib.nEnd;
+ }
+
+ if (!bEmpty && !bGaps && nLastEnd < (nEndPos - 1))
+ bGaps = true;
+ if (bEmpty)
+ eParaState = SfxItemState::DEFAULT;
+ else if (bGaps)
+ eParaState = SfxItemState::DONTCARE;
+ else
+ eParaState = SfxItemState::SET;
+
+ // if we already found an item check if we found the same
+ if (pLastItem)
+ {
+ if ((pParaItem == nullptr) || (*pLastItem != *pParaItem))
+ return SfxItemState::DONTCARE;
+ }
+ else
+ {
+ pLastItem = pParaItem;
+ eState = eParaState;
+ }
+ }
+
+ return eState;
+}
+
+SfxItemState WeldTextForwarder::GetItemState(const ESelection& rSel, sal_uInt16 nWhich) const
+{
+ SfxItemState nState = SfxItemState::DISABLED;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ nState = GetSvxEditEngineItemState(*pEditEngine, rSel, nWhich);
+ return nState;
+}
+
+SfxItemState WeldTextForwarder::GetItemState(sal_Int32 nPara, sal_uInt16 nWhich) const
+{
+ SfxItemState nState = SfxItemState::DISABLED;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ const SfxItemSet& rSet = pEditEngine->GetParaAttribs(nPara);
+ nState = rSet.GetItemState(nWhich);
+ }
+ return nState;
+}
+
+LanguageType WeldTextForwarder::GetLanguage(sal_Int32 nPara, sal_Int32 nIndex) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetLanguage(nPara, nIndex).nLang : LANGUAGE_NONE;
+}
+
+sal_Int32 WeldTextForwarder::GetFieldCount(sal_Int32 nPara) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetFieldCount(nPara) : 0;
+}
+
+EFieldInfo WeldTextForwarder::GetFieldInfo(sal_Int32 nPara, sal_uInt16 nField) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetFieldInfo(nPara, nField) : EFieldInfo();
+}
+
+EBulletInfo WeldTextForwarder::GetBulletInfo(sal_Int32 /*nPara*/) const { return EBulletInfo(); }
+
+tools::Rectangle WeldTextForwarder::GetCharBounds(sal_Int32 nPara, sal_Int32 nIndex) const
+{
+ tools::Rectangle aRect(0, 0, 0, 0);
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+
+ if (pEditEngine)
+ {
+ // Handle virtual position one-past-the end of the string
+ if (nIndex >= pEditEngine->GetTextLen(nPara))
+ {
+ if (nIndex)
+ aRect = pEditEngine->GetCharacterBounds(EPosition(nPara, nIndex - 1));
+
+ aRect.Move(aRect.Right() - aRect.Left(), 0);
+ aRect.SetSize(Size(1, pEditEngine->GetTextHeight()));
+ }
+ else
+ {
+ aRect = pEditEngine->GetCharacterBounds(EPosition(nPara, nIndex));
+ }
+ }
+ return aRect;
+}
+
+tools::Rectangle WeldTextForwarder::GetParaBounds(sal_Int32 nPara) const
+{
+ tools::Rectangle aRect(0, 0, 0, 0);
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+
+ if (pEditEngine)
+ {
+ const Point aPnt = pEditEngine->GetDocPosTopLeft(nPara);
+ const sal_Int32 nWidth = pEditEngine->CalcTextWidth();
+ const sal_Int32 nHeight = pEditEngine->GetTextHeight(nPara);
+ aRect = tools::Rectangle(aPnt.X(), aPnt.Y(), aPnt.X() + nWidth, aPnt.Y() + nHeight);
+ }
+
+ return aRect;
+}
+
+MapMode WeldTextForwarder::GetMapMode() const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetRefMapMode() : MapMode(MapUnit::Map100thMM);
+}
+
+OutputDevice* WeldTextForwarder::GetRefDevice() const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetRefDevice() : nullptr;
+}
+
+bool WeldTextForwarder::GetIndexAtPoint(const Point& rPos, sal_Int32& nPara,
+ sal_Int32& nIndex) const
+{
+ bool bRes = false;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ EPosition aDocPos = pEditEngine->FindDocPosition(rPos);
+ nPara = aDocPos.nPara;
+ nIndex = aDocPos.nIndex;
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldTextForwarder::GetWordIndices(sal_Int32 nPara, sal_Int32 nIndex, sal_Int32& nStart,
+ sal_Int32& nEnd) const
+{
+ bool bRes = false;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ ESelection aRes = pEditEngine->GetWord(ESelection(nPara, nIndex, nPara, nIndex),
+ css::i18n::WordType::DICTIONARY_WORD);
+
+ if (aRes.nStartPara == nPara && aRes.nStartPara == aRes.nEndPara)
+ {
+ nStart = aRes.nStartPos;
+ nEnd = aRes.nEndPos;
+
+ bRes = true;
+ }
+ }
+
+ return bRes;
+}
+
+bool WeldTextForwarder::GetAttributeRun(sal_Int32& nStartIndex, sal_Int32& nEndIndex,
+ sal_Int32 nPara, sal_Int32 nIndex, bool bInCell) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (!pEditEngine)
+ return false;
+ SvxEditSourceHelper::GetAttributeRun(nStartIndex, nEndIndex, *pEditEngine, nPara, nIndex,
+ bInCell);
+ return true;
+}
+
+sal_Int32 WeldTextForwarder::GetLineCount(sal_Int32 nPara) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetLineCount(nPara) : 0;
+}
+
+sal_Int32 WeldTextForwarder::GetLineLen(sal_Int32 nPara, sal_Int32 nLine) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetLineLen(nPara, nLine) : 0;
+}
+
+void WeldTextForwarder::GetLineBoundaries(/*out*/ sal_Int32& rStart, /*out*/ sal_Int32& rEnd,
+ sal_Int32 nPara, sal_Int32 nLine) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->GetLineBoundaries(rStart, rEnd, nPara, nLine);
+ else
+ rStart = rEnd = 0;
+}
+
+sal_Int32 WeldTextForwarder::GetLineNumberAtIndex(sal_Int32 nPara, sal_Int32 nIndex) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetLineNumberAtIndex(nPara, nIndex) : 0;
+}
+
+bool WeldTextForwarder::QuickFormatDoc(bool /*bFull*/)
+{
+ bool bRes = false;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ pEditEngine->QuickFormatDoc();
+ bRes = true;
+ }
+ return bRes;
+}
+
+sal_Int16 WeldTextForwarder::GetDepth(sal_Int32 /*nPara*/) const
+{
+ // math has no outliner...
+ return -1;
+}
+
+bool WeldTextForwarder::SetDepth(sal_Int32 /*nPara*/, sal_Int16 nNewDepth)
+{
+ // math has no outliner...
+ return -1 == nNewDepth; // is it the value from 'GetDepth' ?
+}
+
+bool WeldTextForwarder::Delete(const ESelection& rSelection)
+{
+ bool bRes = false;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ pEditEngine->QuickDelete(rSelection);
+ pEditEngine->QuickFormatDoc();
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldTextForwarder::InsertText(const OUString& rStr, const ESelection& rSelection)
+{
+ bool bRes = false;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ pEditEngine->QuickInsertText(rStr, rSelection);
+ pEditEngine->QuickFormatDoc();
+ bRes = true;
+ }
+ return bRes;
+}
+
+const SfxItemSet* WeldTextForwarder::GetEmptyItemSetPtr()
+{
+ const SfxItemSet* pItemSet = nullptr;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ pItemSet = &pEditEngine->GetEmptyItemSet();
+ }
+ return pItemSet;
+}
+
+void WeldTextForwarder::AppendParagraph()
+{
+ // append an empty paragraph
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ sal_Int32 nParaCount = pEditEngine->GetParagraphCount();
+ pEditEngine->InsertParagraph(nParaCount, OUString());
+ }
+}
+
+sal_Int32 WeldTextForwarder::AppendTextPortion(sal_Int32 nPara, const OUString& rText,
+ const SfxItemSet& rSet)
+{
+ sal_uInt16 nRes = 0;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine && nPara < pEditEngine->GetParagraphCount())
+ {
+ // append text
+ ESelection aSel(nPara, pEditEngine->GetTextLen(nPara));
+ pEditEngine->QuickInsertText(rText, aSel);
+
+ // set attributes for new appended text
+ nRes = aSel.nEndPos = pEditEngine->GetTextLen(nPara);
+ pEditEngine->QuickSetAttribs(rSet, aSel);
+ }
+ return nRes;
+}
+
+void WeldTextForwarder::CopyText(const SvxTextForwarder& rSource)
+{
+ const WeldTextForwarder* pSourceForwarder = dynamic_cast<const WeldTextForwarder*>(&rSource);
+ if (!pSourceForwarder)
+ return;
+ EditEngine* pSourceEditEngine = pSourceForwarder->m_rEditAcc.GetEditEngine();
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine && pSourceEditEngine)
+ {
+ std::unique_ptr<EditTextObject> pNewTextObject = pSourceEditEngine->CreateTextObject();
+ pEditEngine->SetText(*pNewTextObject);
+ }
+}
+
+WeldEditViewForwarder::WeldEditViewForwarder(WeldEditAccessible& rAcc)
+ : m_rEditAcc(rAcc)
+{
+}
+
+bool WeldEditViewForwarder::IsValid() const { return m_rEditAcc.GetEditView() != nullptr; }
+
+Point WeldEditViewForwarder::LogicToPixel(const Point& rPoint, const MapMode& rMapMode) const
+{
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (!pEditView)
+ return Point();
+ OutputDevice& rOutDev = pEditView->GetOutputDevice();
+ MapMode aMapMode(rOutDev.GetMapMode());
+ Point aPoint(OutputDevice::LogicToLogic(rPoint, rMapMode, MapMode(aMapMode.GetMapUnit())));
+ aMapMode.SetOrigin(Point());
+ return rOutDev.LogicToPixel(aPoint, aMapMode);
+}
+
+Point WeldEditViewForwarder::PixelToLogic(const Point& rPoint, const MapMode& rMapMode) const
+{
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (!pEditView)
+ return Point();
+ OutputDevice& rOutDev = pEditView->GetOutputDevice();
+ MapMode aMapMode(rOutDev.GetMapMode());
+ aMapMode.SetOrigin(Point());
+ Point aPoint(rOutDev.PixelToLogic(rPoint, aMapMode));
+ return OutputDevice::LogicToLogic(aPoint, MapMode(aMapMode.GetMapUnit()), rMapMode);
+}
+
+bool WeldEditViewForwarder::GetSelection(ESelection& rSelection) const
+{
+ bool bRes = false;
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (pEditView)
+ {
+ rSelection = pEditView->GetSelection();
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldEditViewForwarder::SetSelection(const ESelection& rSelection)
+{
+ bool bRes = false;
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (pEditView)
+ {
+ pEditView->SetSelection(rSelection);
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldEditViewForwarder::Copy()
+{
+ bool bRes = false;
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (pEditView)
+ {
+ pEditView->Copy();
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldEditViewForwarder::Cut()
+{
+ bool bRes = false;
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (pEditView)
+ {
+ pEditView->Cut();
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldEditViewForwarder::Paste()
+{
+ bool bRes = false;
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (pEditView)
+ {
+ pEditView->Paste();
+ bRes = true;
+ }
+ return bRes;
+}
+
+void WeldEditView::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Size aSize(pDrawingArea->get_size_request());
+ if (aSize.Width() == -1)
+ aSize.setWidth(500);
+ if (aSize.Height() == -1)
+ aSize.setHeight(100);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+
+ SetOutputSizePixel(aSize);
+
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+
+ EnableRTL(false);
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Color aBgColor = rStyleSettings.GetWindowColor();
+
+ OutputDevice& rDevice = pDrawingArea->get_ref_device();
+
+ rDevice.SetMapMode(MapMode(MapUnit::MapTwip));
+ rDevice.SetBackground(aBgColor);
+
+ Size aOutputSize(rDevice.PixelToLogic(aSize));
+
+ makeEditEngine();
+ m_xEditEngine->SetPaperSize(aOutputSize);
+ m_xEditEngine->SetRefDevice(&rDevice);
+
+ m_xEditEngine->SetControlWord(m_xEditEngine->GetControlWord() | EEControlBits::MARKFIELDS);
+
+ m_xEditView.reset(new EditView(m_xEditEngine.get(), nullptr));
+ m_xEditView->setEditViewCallbacks(this);
+ m_xEditView->SetOutputArea(tools::Rectangle(Point(0, 0), aOutputSize));
+
+ m_xEditView->SetBackgroundColor(aBgColor);
+ m_xEditEngine->SetBackgroundColor(aBgColor);
+ m_xEditEngine->InsertView(m_xEditView.get());
+
+ pDrawingArea->set_cursor(PointerStyle::Text);
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ InitAccessible();
+#endif
+}
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+void WeldEditView::InitAccessible()
+{
+ if (m_xAccessible.is())
+ m_xAccessible->Init(GetEditEngine(), GetEditView());
+}
+#endif
+
+int WeldEditView::GetSurroundingText(OUString& rSurrounding)
+{
+ EditView* pEditView = GetEditView();
+ if (!pEditView)
+ return -1;
+ rSurrounding = pEditView->GetSurroundingText();
+ return pEditView->GetSurroundingTextSelection().Min();
+}
+
+bool WeldEditView::DeleteSurroundingText(const Selection& rRange)
+{
+ EditView* pEditView = GetEditView();
+ if (!pEditView)
+ return false;
+ return pEditView->DeleteSurroundingText(rRange);
+}
+
+void WeldEditView::GetFocus()
+{
+ EditView* pEditView = GetEditView();
+ if (pEditView)
+ {
+ pEditView->ShowCursor(false);
+ Invalidate(); // redraw with cursor
+ }
+
+ weld::CustomWidgetController::GetFocus();
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccessible.is())
+ {
+ // Note: will implicitly send the AccessibleStateType::FOCUSED event
+ ::accessibility::AccessibleTextHelper* pHelper = m_xAccessible->GetTextHelper();
+ if (pHelper)
+ pHelper->SetFocus();
+ }
+#endif
+}
+
+void WeldEditView::LoseFocus()
+{
+ weld::CustomWidgetController::LoseFocus();
+ Invalidate(); // redraw without cursor
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccessible.is())
+ {
+ // Note: will implicitly send the AccessibleStateType::FOCUSED event
+ ::accessibility::AccessibleTextHelper* pHelper = m_xAccessible->GetTextHelper();
+ if (pHelper)
+ pHelper->SetFocus(false);
+ }
+#endif
+}
+
+bool WeldEditView::CanFocus() const { return true; }
+
+css::uno::Reference<css::datatransfer::dnd::XDropTarget> WeldEditView::GetDropTarget()
+{
+ if (!m_xDropTarget)
+ m_xDropTarget = weld::CustomWidgetController::GetDropTarget();
+ return m_xDropTarget;
+}
+
+css::uno::Reference<css::datatransfer::clipboard::XClipboard> WeldEditView::GetClipboard() const
+{
+ return weld::CustomWidgetController::GetClipboard();
+}
+
+namespace
+{
+class WeldEditViewUIObject final : public DrawingAreaUIObject
+{
+private:
+ WeldEditView* mpEditView;
+
+public:
+ WeldEditViewUIObject(const VclPtr<vcl::Window>& rDrawingArea)
+ : DrawingAreaUIObject(rDrawingArea)
+ , mpEditView(static_cast<WeldEditView*>(mpController))
+ {
+ }
+
+ static std::unique_ptr<UIObject> create(vcl::Window* pWindow)
+ {
+ return std::unique_ptr<UIObject>(new WeldEditViewUIObject(pWindow));
+ }
+
+ virtual StringMap get_state() override
+ {
+ StringMap aMap = WindowUIObject::get_state();
+ aMap["Text"] = mpEditView->GetText();
+ return aMap;
+ }
+
+private:
+ virtual OUString get_name() const override { return "WeldEditViewUIObject"; }
+};
+}
+
+FactoryFunction WeldEditView::GetUITestFactory() const { return WeldEditViewUIObject::create; }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/camera3d.cxx b/svx/source/engine3d/camera3d.cxx
new file mode 100644
index 000000000..30a1b09fb
--- /dev/null
+++ b/svx/source/engine3d/camera3d.cxx
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/camera3d.hxx>
+
+Camera3D::Camera3D(const basegfx::B3DPoint& rPos, const basegfx::B3DPoint& rLookAt,
+ double fFocalLen)
+ : fBankAngle(0)
+ , bAutoAdjustProjection(true)
+{
+ SetPosition(rPos);
+ SetLookAt(rLookAt);
+ SetFocalLength(fFocalLen);
+}
+
+Camera3D::Camera3D()
+ : fFocalLength(35.0)
+ , fBankAngle(0.0)
+ , bAutoAdjustProjection(false)
+{
+}
+
+// Set ViewWindow and adjust PRP
+
+void Camera3D::SetViewWindow(double fX, double fY, double fW, double fH)
+{
+ Viewport3D::SetViewWindow(fX, fY, fW, fH);
+ if (bAutoAdjustProjection)
+ SetFocalLength(fFocalLength);
+}
+
+void Camera3D::SetPosition(const basegfx::B3DPoint& rNewPos)
+{
+ if (rNewPos != aPosition)
+ {
+ aPosition = rNewPos;
+ SetVRP(aPosition);
+ SetVPN(aPosition - aLookAt);
+ SetBankAngle(fBankAngle);
+ }
+}
+
+void Camera3D::SetLookAt(const basegfx::B3DPoint& rNewLookAt)
+{
+ if (rNewLookAt != aLookAt)
+ {
+ aLookAt = rNewLookAt;
+ SetVPN(aPosition - aLookAt);
+ SetBankAngle(fBankAngle);
+ }
+}
+
+void Camera3D::SetPosAndLookAt(const basegfx::B3DPoint& rNewPos,
+ const basegfx::B3DPoint& rNewLookAt)
+{
+ if (rNewPos != aPosition || rNewLookAt != aLookAt)
+ {
+ aPosition = rNewPos;
+ aLookAt = rNewLookAt;
+
+ SetVRP(aPosition);
+ SetVPN(aPosition - aLookAt);
+ SetBankAngle(fBankAngle);
+ }
+}
+
+void Camera3D::SetBankAngle(double fAngle)
+{
+ basegfx::B3DVector aDiff(aPosition - aLookAt);
+ basegfx::B3DVector aPrj(aDiff);
+ fBankAngle = fAngle;
+
+ if (aDiff.getY() == 0)
+ {
+ aPrj.setY(-1.0);
+ }
+ else
+ { // aPrj = Projection from aDiff on the XZ-plane
+ aPrj.setY(0.0);
+
+ if (aDiff.getY() < 0.0)
+ {
+ aPrj = -aPrj;
+ }
+ }
+
+ // Calculate from aDiff to upwards pointing View-Up-Vector
+ // duplicated line is intentional!
+ aPrj = aPrj.getPerpendicular(aDiff);
+ aPrj = aPrj.getPerpendicular(aDiff);
+ aDiff.normalize();
+
+ // Rotate on Z axis, to rotate the BankAngle and back
+ basegfx::B3DHomMatrix aTf;
+ const double fV(sqrt(aDiff.getY() * aDiff.getY() + aDiff.getZ() * aDiff.getZ()));
+
+ if (fV != 0.0)
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(aDiff.getY() / fV);
+ const double fCos(aDiff.getZ() / fV);
+
+ aTemp.set(1, 1, fCos);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(2, 1, fSin);
+ aTemp.set(1, 2, -fSin);
+
+ aTf *= aTemp;
+ }
+
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(-aDiff.getX());
+ const double fCos(fV);
+
+ aTemp.set(0, 0, fCos);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(0, 2, fSin);
+ aTemp.set(2, 0, -fSin);
+
+ aTf *= aTemp;
+ }
+
+ aTf.rotate(0.0, 0.0, fBankAngle);
+
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(aDiff.getX());
+ const double fCos(fV);
+
+ aTemp.set(0, 0, fCos);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(0, 2, fSin);
+ aTemp.set(2, 0, -fSin);
+
+ aTf *= aTemp;
+ }
+
+ if (fV != 0.0)
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(-aDiff.getY() / fV);
+ const double fCos(aDiff.getZ() / fV);
+
+ aTemp.set(1, 1, fCos);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(2, 1, fSin);
+ aTemp.set(1, 2, -fSin);
+
+ aTf *= aTemp;
+ }
+
+ SetVUV(aTf * aPrj);
+}
+
+void Camera3D::SetFocalLength(double fLen)
+{
+ if (fLen < 5)
+ fLen = 5;
+ SetPRP(basegfx::B3DPoint(0.0, 0.0, fLen / 35.0 * aViewWin.W));
+ fFocalLength = fLen;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/cube3d.cxx b/svx/source/engine3d/cube3d.cxx
new file mode 100644
index 000000000..020d4c85e
--- /dev/null
+++ b/svx/source/engine3d/cube3d.cxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/strings.hrc>
+#include <svx/deflt3d.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/cube3d.hxx>
+#include <svx/svdobjkind.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <sdr/contact/viewcontactofe3dcube.hxx>
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> E3dCubeObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dCube>(*this);
+}
+
+
+E3dCubeObj::E3dCubeObj(
+ SdrModel& rSdrModel,
+ const E3dDefaultAttributes& rDefault,
+ const basegfx::B3DPoint& aPos,
+ const basegfx::B3DVector& r3DSize)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set Defaults
+ SetDefaultAttributes(rDefault);
+
+ // position centre or left, bottom, back (dependent on bPosIsCenter)
+ aCubePos = aPos;
+ aCubeSize = r3DSize;
+}
+
+E3dCubeObj::E3dCubeObj(SdrModel& rSdrModel)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set Defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+}
+
+E3dCubeObj::E3dCubeObj(SdrModel& rSdrModel, E3dCubeObj const & rSource)
+: E3dCompoundObject(rSdrModel, rSource)
+{
+ // Set Defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+
+ aCubePos = rSource.aCubePos;
+ aCubeSize = rSource.aCubeSize;
+ bPosIsCenter = rSource.bPosIsCenter;
+}
+
+E3dCubeObj::~E3dCubeObj()
+{
+}
+
+void E3dCubeObj::SetDefaultAttributes(const E3dDefaultAttributes& rDefault)
+{
+ aCubePos = rDefault.GetDefaultCubePos();
+ aCubeSize = rDefault.GetDefaultCubeSize();
+ bPosIsCenter = rDefault.GetDefaultCubePosIsCenter();
+}
+
+SdrObjKind E3dCubeObj::GetObjIdentifier() const
+{
+ return SdrObjKind::E3D_Cube;
+}
+
+// Convert the object into a group object consisting of 6 polygons
+
+SdrObjectUniquePtr E3dCubeObj::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
+{
+ return nullptr;
+}
+
+E3dCubeObj* E3dCubeObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new E3dCubeObj(rTargetModel, *this);
+}
+
+// Set local parameters with geometry re-creating
+
+void E3dCubeObj::SetCubePos(const basegfx::B3DPoint& rNew)
+{
+ if(aCubePos != rNew)
+ {
+ aCubePos = rNew;
+ ActionChanged();
+ }
+}
+
+void E3dCubeObj::SetCubeSize(const basegfx::B3DVector& rNew)
+{
+ if(aCubeSize != rNew)
+ {
+ aCubeSize = rNew;
+ ActionChanged();
+ }
+}
+
+void E3dCubeObj::SetPosIsCenter(bool bNew)
+{
+ if(bPosIsCenter != bNew)
+ {
+ bPosIsCenter = bNew;
+ ActionChanged();
+ }
+}
+
+// Get the name of the object (singular)
+
+OUString E3dCubeObj::TakeObjNameSingul() const
+{
+ OUString sName = SvxResId(STR_ObjNameSingulCube3d);
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName += " \'" + aName + "'";
+ }
+ return sName;
+}
+
+// Get the name of the object (plural)
+
+OUString E3dCubeObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralCube3d);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/deflt3d.cxx b/svx/source/engine3d/deflt3d.cxx
new file mode 100644
index 000000000..89342e676
--- /dev/null
+++ b/svx/source/engine3d/deflt3d.cxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/deflt3d.hxx>
+
+// Class to manage the 3D default attributes
+
+E3dDefaultAttributes::E3dDefaultAttributes() { Reset(); }
+
+void E3dDefaultAttributes::Reset()
+{
+ // Cube object
+ aDefaultCubePos = basegfx::B3DPoint(-500.0, -500.0, -500.0);
+ aDefaultCubeSize = basegfx::B3DVector(1000.0, 1000.0, 1000.0);
+ bDefaultCubePosIsCenter = false;
+
+ // Sphere object
+ aDefaultSphereCenter = basegfx::B3DPoint(0.0, 0.0, 0.0);
+ aDefaultSphereSize = basegfx::B3DPoint(1000.0, 1000.0, 1000.0);
+
+ // Lathe object
+ bDefaultLatheSmoothed = true;
+ bDefaultLatheSmoothFrontBack = false;
+ bDefaultLatheCharacterMode = false;
+ bDefaultLatheCloseFront = true;
+ bDefaultLatheCloseBack = true;
+
+ // Extrude object
+ bDefaultExtrudeSmoothed = true;
+ bDefaultExtrudeSmoothFrontBack = false;
+ bDefaultExtrudeCharacterMode = false;
+ bDefaultExtrudeCloseFront = true;
+ bDefaultExtrudeCloseBack = true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/dragmt3d.cxx b/svx/source/engine3d/dragmt3d.cxx
new file mode 100644
index 000000000..c27d95598
--- /dev/null
+++ b/svx/source/engine3d/dragmt3d.cxx
@@ -0,0 +1,732 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <dragmt3d.hxx>
+#include <o3tl/numeric.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svddrgmt.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/e3dundo.hxx>
+#include <svx/strings.hrc>
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+#include <svx/e3dsceneupdater.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <comphelper/lok.hxx>
+
+
+E3dDragMethod::E3dDragMethod (
+ SdrDragView &_rView,
+ const SdrMarkList& rMark,
+ E3dDragConstraint eConstr,
+ bool bFull)
+: SdrDragMethod(_rView),
+ meConstraint(eConstr),
+ mbMoveFull(bFull),
+ mbMovedAtAll(false)
+{
+ // Create a unit for all the 3D objects present in the selection
+ const size_t nCnt(rMark.GetMarkCount());
+
+ if(mbMoveFull)
+ {
+ // for non-visible 3D objects fallback to wireframe interaction
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ E3dObject* pE3dObj = dynamic_cast< E3dObject* >(rMark.GetMark(nObjs)->GetMarkedSdrObj());
+
+ if(pE3dObj)
+ {
+ if(!pE3dObj->HasFillStyle() && !pE3dObj->HasLineStyle())
+ {
+ mbMoveFull = false;
+ break;
+ }
+ }
+ }
+ }
+
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ E3dObject* pE3dObj = dynamic_cast< E3dObject* >(rMark.GetMark(nObjs)->GetMarkedSdrObj());
+
+ if(pE3dObj)
+ {
+ // fill new interaction unit
+ E3dDragMethodUnit aNewUnit(*pE3dObj);
+
+ // get transformations
+ aNewUnit.maInitTransform = aNewUnit.maTransform = pE3dObj->GetTransform();
+
+ if(nullptr != pE3dObj->getParentE3dSceneFromE3dObject())
+ {
+ // get transform between object and world, normally scene transform
+ aNewUnit.maInvDisplayTransform = aNewUnit.maDisplayTransform = pE3dObj->getParentE3dSceneFromE3dObject()->GetFullTransform();
+ aNewUnit.maInvDisplayTransform.invert();
+ }
+
+ if(!mbMoveFull)
+ {
+ // create wireframe visualisation for parent coordinate system
+ aNewUnit.maWireframePoly.clear();
+ aNewUnit.maWireframePoly = pE3dObj->CreateWireframe();
+ aNewUnit.maWireframePoly.transform(aNewUnit.maTransform);
+ }
+
+ // Determine FullBound
+ maFullBound.Union(pE3dObj->GetSnapRect());
+
+ // Insert Unit
+ maGrp.push_back(aNewUnit);
+ }
+ }
+}
+
+OUString E3dDragMethod::GetSdrDragComment() const
+{
+ return OUString();
+}
+
+// Create the wireframe model for all actions
+
+bool E3dDragMethod::BeginSdrDrag()
+{
+ if(E3dDragConstraint::Z == meConstraint)
+ {
+ const sal_uInt32 nCnt(maGrp.size());
+ DragStat().SetRef1( maFullBound.Center() );
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ rCandidate.mnStartAngle = GetAngle(DragStat().GetStart() - DragStat().GetRef1());
+ rCandidate.mnLastAngle = 0_deg100;
+ }
+ }
+ else
+ {
+ maLastPos = DragStat().GetStart();
+ }
+
+ if(!mbMoveFull)
+ {
+ Show();
+ }
+
+ return true;
+}
+
+bool E3dDragMethod::EndSdrDrag(bool /*bCopy*/)
+{
+ const sal_uInt32 nCnt(maGrp.size());
+
+ if(!mbMoveFull)
+ {
+ // Hide wireframe
+ Hide();
+ }
+
+ // Apply all transformations and create undo's
+ if(mbMovedAtAll)
+ {
+ const bool bUndo = getSdrDragView().IsUndoEnabled();
+ if( bUndo )
+ getSdrDragView().BegUndo(SvxResId(RID_SVX_3D_UNDO_ROTATE));
+ sal_uInt32 nOb(0);
+
+ for(nOb=0;nOb<nCnt;nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
+ rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
+ if( bUndo )
+ {
+ getSdrDragView().AddUndo(
+ std::make_unique<E3dRotateUndoAction>(
+ rCandidate.mr3DObj,
+ rCandidate.maInitTransform,
+ rCandidate.maTransform));
+ }
+ }
+ if( bUndo )
+ getSdrDragView().EndUndo();
+ }
+
+ return true;
+}
+
+void E3dDragMethod::CancelSdrDrag()
+{
+ if(mbMoveFull)
+ {
+ if(mbMovedAtAll)
+ {
+ const sal_uInt32 nCnt(maGrp.size());
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ // Restore transformation
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
+ rCandidate.mr3DObj.SetTransform(rCandidate.maInitTransform);
+ }
+ }
+ }
+ else
+ {
+ // Hide WireFrame
+ Hide();
+ }
+}
+
+// Common MoveSdrDrag()
+
+void E3dDragMethod::MoveSdrDrag(const Point& /*rPnt*/)
+{
+ mbMovedAtAll = true;
+}
+
+// Draw the wire frame model
+
+// for migration from XOR to overlay
+void E3dDragMethod::CreateOverlayGeometry(
+ sdr::overlay::OverlayManager& rOverlayManager,
+ const sdr::contact::ObjectContact& rObjectContact)
+{
+ // We do client-side object manipulation with the Kit API
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+
+ const sal_uInt32 nCnt(maGrp.size());
+ basegfx::B2DPolyPolygon aResult;
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ SdrPageView* pPV = getSdrDragView().GetSdrPageView();
+
+ if(pPV && pPV->HasMarkedObjPageView())
+ {
+ const basegfx::B3DPolyPolygon aCandidate(rCandidate.maWireframePoly);
+ const sal_uInt32 nPlyCnt(aCandidate.count());
+
+ if(nPlyCnt)
+ {
+ const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ const basegfx::B3DHomMatrix aWorldToView(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection() * aViewInfo3D.getOrientation());
+ const basegfx::B3DHomMatrix aTransform(aWorldToView * rCandidate.maDisplayTransform);
+
+ // transform to relative scene coordinates
+ basegfx::B2DPolyPolygon aPolyPolygon(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aCandidate, aTransform));
+
+ // transform to 2D view coordinates
+ aPolyPolygon.transform(rVCScene.getObjectTransformation());
+
+ aResult.append(aPolyPolygon);
+ }
+ }
+ }
+ }
+
+ if(aResult.count())
+ {
+ std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(
+ new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
+ aResult));
+
+ insertNewlyCreatedOverlayObjectForSdrDragMethod(
+ std::move(pNew),
+ rObjectContact,
+ rOverlayManager);
+ }
+}
+
+
+E3dDragRotate::E3dDragRotate(SdrDragView &_rView,
+ const SdrMarkList& rMark,
+ E3dDragConstraint eConstr,
+ bool bFull)
+: E3dDragMethod(_rView, rMark, eConstr, bFull)
+{
+ // Get center of all selected objects in eye coordinates
+ const sal_uInt32 nCnt(maGrp.size());
+
+ if(!nCnt)
+ return;
+
+ const E3dScene* pScene(maGrp[0].mr3DObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr == pScene)
+ return;
+
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ basegfx::B3DPoint aObjCenter = rCandidate.mr3DObj.GetBoundVolume().getCenter();
+ const basegfx::B3DHomMatrix aTransform(aViewInfo3D.getOrientation() * rCandidate.maDisplayTransform * rCandidate.maInitTransform);
+
+ aObjCenter = aTransform * aObjCenter;
+ maGlobalCenter += aObjCenter;
+ }
+
+ // Divide by the number
+ if(nCnt > 1)
+ {
+ maGlobalCenter /= static_cast<double>(nCnt);
+ }
+
+ // get rotate center and transform to 3D eye coordinates
+ basegfx::B2DPoint aRotCenter2D(Ref1().X(), Ref1().Y());
+
+ // from world to relative scene using inverse getObjectTransformation()
+ basegfx::B2DHomMatrix aInverseObjectTransform(rVCScene.getObjectTransformation());
+ aInverseObjectTransform.invert();
+ aRotCenter2D = aInverseObjectTransform * aRotCenter2D;
+
+ // from 3D view to 3D eye
+ basegfx::B3DPoint aRotCenter3D(aRotCenter2D.getX(), aRotCenter2D.getY(), 0.0);
+ basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
+ aInverseViewToEye.invert();
+ aRotCenter3D = aInverseViewToEye * aRotCenter3D;
+
+// Use X,Y of the RotCenter and depth of the common object centre
+// as rotation point in the space
+ maGlobalCenter.setX(aRotCenter3D.getX());
+ maGlobalCenter.setY(aRotCenter3D.getY());
+}
+
+
+//The object is moved, determine the angle
+
+void E3dDragRotate::MoveSdrDrag(const Point& rPnt)
+{
+ // call parent
+ E3dDragMethod::MoveSdrDrag(rPnt);
+
+ if(!DragStat().CheckMinMoved(rPnt))
+ return;
+
+ // Get modifier
+ sal_uInt16 nModifier = 0;
+ if(auto pDragView = dynamic_cast<const E3dView*>(&getSdrDragView()))
+ {
+ const MouseEvent& rLastMouse = pDragView->GetMouseEvent();
+ nModifier = rLastMouse.GetModifier();
+ }
+
+ // Rotate all objects
+ const sal_uInt32 nCnt(maGrp.size());
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ // Determine rotation angle
+ double fWAngle, fHAngle;
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+
+ if(E3dDragConstraint::Z == meConstraint)
+ {
+ Degree100 lastAngle = NormAngle36000(GetAngle(rPnt - DragStat().GetRef1()) -
+ rCandidate.mnStartAngle) - rCandidate.mnLastAngle;
+ rCandidate.mnLastAngle = lastAngle + rCandidate.mnLastAngle;
+ fWAngle = toDegrees(lastAngle);
+ fHAngle = 0.0;
+ }
+ else
+ {
+ if ((maFullBound.GetWidth() == 0) || (maFullBound.GetHeight() == 0))
+ throw o3tl::divide_by_zero();
+ fWAngle = 90.0 * static_cast<double>(rPnt.X() - maLastPos.X())
+ / static_cast<double>(maFullBound.GetWidth());
+ fHAngle = 90.0 * static_cast<double>(rPnt.Y() - maLastPos.Y())
+ / static_cast<double>(maFullBound.GetHeight());
+ }
+ tools::Long nSnap = 0;
+
+ if(!getSdrDragView().IsRotateAllowed())
+ nSnap = 90;
+
+ if(nSnap != 0)
+ {
+ fWAngle = static_cast<double>((static_cast<tools::Long>(fWAngle) + nSnap/2) / nSnap * nSnap);
+ fHAngle = static_cast<double>((static_cast<tools::Long>(fHAngle) + nSnap/2) / nSnap * nSnap);
+ }
+
+ // to radians
+ fWAngle = basegfx::deg2rad(fWAngle);
+ fHAngle = basegfx::deg2rad(fHAngle);
+
+ // Determine transformation
+ basegfx::B3DHomMatrix aRotMat;
+ if(E3dDragConstraint::Y & meConstraint)
+ {
+ if(nModifier & KEY_MOD2)
+ aRotMat.rotate(0.0, 0.0, fWAngle);
+ else
+ aRotMat.rotate(0.0, fWAngle, 0.0);
+ }
+ else if(E3dDragConstraint::Z & meConstraint)
+ {
+ if(nModifier & KEY_MOD2)
+ aRotMat.rotate(0.0, fWAngle, 0.0);
+ else
+ aRotMat.rotate(0.0, 0.0, fWAngle);
+ }
+ if(E3dDragConstraint::X & meConstraint)
+ {
+ aRotMat.rotate(fHAngle, 0.0, 0.0);
+ }
+
+ const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ // Transformation in eye coordinates, there rotate then and back
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
+ aInverseOrientation.invert();
+
+ basegfx::B3DHomMatrix aTransMat(rCandidate.maDisplayTransform);
+ aTransMat *= aViewInfo3D.getOrientation();
+ aTransMat.translate(-maGlobalCenter.getX(), -maGlobalCenter.getY(), -maGlobalCenter.getZ());
+ aTransMat *= aRotMat;
+ aTransMat.translate(maGlobalCenter.getX(), maGlobalCenter.getY(), maGlobalCenter.getZ());
+ aTransMat *= aInverseOrientation;
+ aTransMat *= rCandidate.maInvDisplayTransform;
+
+ // ...and apply
+ rCandidate.maTransform *= aTransMat;
+
+ if(mbMoveFull)
+ {
+ E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
+ rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
+ }
+ else
+ {
+ Hide();
+ rCandidate.maWireframePoly.transform(aTransMat);
+ Show();
+ }
+ }
+ }
+ maLastPos = rPnt;
+ DragStat().NextMove(rPnt);
+}
+
+PointerStyle E3dDragRotate::GetSdrDragPointer() const
+{
+ return PointerStyle::Rotate;
+}
+
+// E3dDragMove. This drag method is only required for translations inside
+// 3D scenes. If a 3D-scene itself moved, then this drag method will drag
+// not be used.
+
+
+E3dDragMove::E3dDragMove(SdrDragView &_rView,
+ const SdrMarkList& rMark,
+ SdrHdlKind eDrgHdl,
+ E3dDragConstraint eConstr,
+ bool bFull)
+: E3dDragMethod(_rView, rMark, eConstr, bFull),
+ meWhatDragHdl(eDrgHdl)
+{
+ switch(meWhatDragHdl)
+ {
+ case SdrHdlKind::Left:
+ maScaleFixPos = maFullBound.RightCenter();
+ break;
+ case SdrHdlKind::Right:
+ maScaleFixPos = maFullBound.LeftCenter();
+ break;
+ case SdrHdlKind::Upper:
+ maScaleFixPos = maFullBound.BottomCenter();
+ break;
+ case SdrHdlKind::Lower:
+ maScaleFixPos = maFullBound.TopCenter();
+ break;
+ case SdrHdlKind::UpperLeft:
+ maScaleFixPos = maFullBound.BottomRight();
+ break;
+ case SdrHdlKind::UpperRight:
+ maScaleFixPos = maFullBound.BottomLeft();
+ break;
+ case SdrHdlKind::LowerLeft:
+ maScaleFixPos = maFullBound.TopRight();
+ break;
+ case SdrHdlKind::LowerRight:
+ maScaleFixPos = maFullBound.TopLeft();
+ break;
+ default:
+ // Moving the object, SdrHdlKind::Move
+ break;
+ }
+
+ // Override when IsResizeAtCenter()
+ if(getSdrDragView().IsResizeAtCenter())
+ {
+ meWhatDragHdl = SdrHdlKind::User;
+ maScaleFixPos = maFullBound.Center();
+ }
+}
+
+// The object is moved, determine the translations
+
+void E3dDragMove::MoveSdrDrag(const Point& rPnt)
+{
+ // call parent
+ E3dDragMethod::MoveSdrDrag(rPnt);
+
+ if(!DragStat().CheckMinMoved(rPnt))
+ return;
+
+ if(SdrHdlKind::Move == meWhatDragHdl)
+ {
+ // Translation
+ // Determine the motion vector
+ const sal_uInt32 nCnt(maGrp.size());
+
+ // Get modifier
+ sal_uInt16 nModifier(0);
+
+ if(auto pDragView = dynamic_cast<const E3dView*>(&getSdrDragView()))
+ {
+ const MouseEvent& rLastMouse = pDragView->GetMouseEvent();
+ nModifier = rLastMouse.GetModifier();
+ }
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+
+ // move coor from 2d world to 3d Eye
+ basegfx::B2DPoint aGlobalMoveHead2D(static_cast<double>(rPnt.X() - maLastPos.X()), static_cast<double>(rPnt.Y() - maLastPos.Y()));
+ basegfx::B2DPoint aGlobalMoveTail2D(0.0, 0.0);
+ basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
+
+ aInverseSceneTransform.invert();
+ aGlobalMoveHead2D = aInverseSceneTransform * aGlobalMoveHead2D;
+ aGlobalMoveTail2D = aInverseSceneTransform * aGlobalMoveTail2D;
+
+ basegfx::B3DPoint aMoveHead3D(aGlobalMoveHead2D.getX(), aGlobalMoveHead2D.getY(), 0.5);
+ basegfx::B3DPoint aMoveTail3D(aGlobalMoveTail2D.getX(), aGlobalMoveTail2D.getY(), 0.5);
+ basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
+ aInverseViewToEye.invert();
+
+ aMoveHead3D = aInverseViewToEye * aMoveHead3D;
+ aMoveTail3D = aInverseViewToEye * aMoveTail3D;
+
+ // eventually switch movement from XY to XZ plane
+ if(nModifier & KEY_MOD2)
+ {
+ double fZwi = aMoveHead3D.getY();
+ aMoveHead3D.setY(aMoveHead3D.getZ());
+ aMoveHead3D.setZ(fZwi);
+
+ fZwi = aMoveTail3D.getY();
+ aMoveTail3D.setY(aMoveTail3D.getZ());
+ aMoveTail3D.setZ(fZwi);
+ }
+
+ // Motion vector from eye coordinates to parent coordinates
+ basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
+ aInverseOrientation.invert();
+ basegfx::B3DHomMatrix aCompleteTrans(rCandidate.maInvDisplayTransform * aInverseOrientation);
+
+ aMoveHead3D = aCompleteTrans * aMoveHead3D;
+ aMoveTail3D = aCompleteTrans* aMoveTail3D;
+
+ // build transformation
+ basegfx::B3DHomMatrix aTransMat;
+ basegfx::B3DPoint aTranslate(aMoveHead3D - aMoveTail3D);
+ aTransMat.translate(aTranslate.getX(), aTranslate.getY(), aTranslate.getZ());
+
+ // ...and apply
+ rCandidate.maTransform *= aTransMat;
+
+ if(mbMoveFull)
+ {
+ E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
+ rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
+ }
+ else
+ {
+ Hide();
+ rCandidate.maWireframePoly.transform(aTransMat);
+ Show();
+ }
+ }
+ }
+ }
+ else
+ {
+ // Scaling
+ // Determine scaling vector
+ Point aStartPos = DragStat().GetStart();
+ const sal_uInt32 nCnt(maGrp.size());
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ const basegfx::B3DPoint aObjectCenter(rCandidate.mr3DObj.GetBoundVolume().getCenter());
+ const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ // transform from 2D world view to 3D eye
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+
+ basegfx::B2DPoint aGlobalScaleStart2D(static_cast<double>(aStartPos.X()), static_cast<double>(aStartPos.Y()));
+ basegfx::B2DPoint aGlobalScaleNext2D(static_cast<double>(rPnt.X()), static_cast<double>(rPnt.Y()));
+ basegfx::B2DPoint aGlobalScaleFixPos2D(static_cast<double>(maScaleFixPos.X()), static_cast<double>(maScaleFixPos.Y()));
+ basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
+
+ aInverseSceneTransform.invert();
+ aGlobalScaleStart2D = aInverseSceneTransform * aGlobalScaleStart2D;
+ aGlobalScaleNext2D = aInverseSceneTransform * aGlobalScaleNext2D;
+ aGlobalScaleFixPos2D = aInverseSceneTransform * aGlobalScaleFixPos2D;
+
+ basegfx::B3DPoint aGlobalScaleStart3D(aGlobalScaleStart2D.getX(), aGlobalScaleStart2D.getY(), aObjectCenter.getZ());
+ basegfx::B3DPoint aGlobalScaleNext3D(aGlobalScaleNext2D.getX(), aGlobalScaleNext2D.getY(), aObjectCenter.getZ());
+ basegfx::B3DPoint aGlobalScaleFixPos3D(aGlobalScaleFixPos2D.getX(), aGlobalScaleFixPos2D.getY(), aObjectCenter.getZ());
+ basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
+
+ aInverseViewToEye.invert();
+ basegfx::B3DPoint aScStart(aInverseViewToEye * aGlobalScaleStart3D);
+ basegfx::B3DPoint aScNext(aInverseViewToEye * aGlobalScaleNext3D);
+ basegfx::B3DPoint aScFixPos(aInverseViewToEye * aGlobalScaleFixPos3D);
+
+ // constraints?
+ switch(meWhatDragHdl)
+ {
+ case SdrHdlKind::Left:
+ case SdrHdlKind::Right:
+ // to constrain on X -> Y equal
+ aScNext.setY(aScFixPos.getY());
+ break;
+ case SdrHdlKind::Upper:
+ case SdrHdlKind::Lower:
+ // constrain to Y -> X equal
+ aScNext.setX(aScFixPos.getX());
+ break;
+ default:
+ break;
+ }
+
+ // get scale vector in eye coordinates
+ basegfx::B3DPoint aScaleVec(aScStart - aScFixPos);
+ aScaleVec.setZ(1.0);
+
+ if(aScaleVec.getX() != 0.0)
+ {
+ aScaleVec.setX((aScNext.getX() - aScFixPos.getX()) / aScaleVec.getX());
+ }
+ else
+ {
+ aScaleVec.setX(1.0);
+ }
+
+ if(aScaleVec.getY() != 0.0)
+ {
+ aScaleVec.setY((aScNext.getY() - aScFixPos.getY()) / aScaleVec.getY());
+ }
+ else
+ {
+ aScaleVec.setY(1.0);
+ }
+
+ // SHIFT-key used?
+ if(getSdrDragView().IsOrtho())
+ {
+ if(fabs(aScaleVec.getX()) > fabs(aScaleVec.getY()))
+ {
+ // X is biggest
+ aScaleVec.setY(aScaleVec.getX());
+ }
+ else
+ {
+ // Y is biggest
+ aScaleVec.setX(aScaleVec.getY());
+ }
+ }
+
+ // build transformation
+ basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
+ aInverseOrientation.invert();
+
+ basegfx::B3DHomMatrix aNewTrans = rCandidate.maInitTransform;
+ aNewTrans *= rCandidate.maDisplayTransform;
+ aNewTrans *= aViewInfo3D.getOrientation();
+ aNewTrans.translate(-aScFixPos.getX(), -aScFixPos.getY(), -aScFixPos.getZ());
+ aNewTrans.scale(aScaleVec.getX(), aScaleVec.getY(), aScaleVec.getZ());
+ aNewTrans.translate(aScFixPos.getX(), aScFixPos.getY(), aScFixPos.getZ());
+ aNewTrans *= aInverseOrientation;
+ aNewTrans *= rCandidate.maInvDisplayTransform;
+
+ // ...and apply
+ rCandidate.maTransform = aNewTrans;
+
+ if(mbMoveFull)
+ {
+ E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
+ rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
+ }
+ else
+ {
+ Hide();
+ rCandidate.maWireframePoly.clear();
+ rCandidate.maWireframePoly = rCandidate.mr3DObj.CreateWireframe();
+ rCandidate.maWireframePoly.transform(rCandidate.maTransform);
+ Show();
+ }
+ }
+ }
+ }
+ maLastPos = rPnt;
+ DragStat().NextMove(rPnt);
+}
+
+PointerStyle E3dDragMove::GetSdrDragPointer() const
+{
+ return PointerStyle::Move;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/e3dsceneupdater.cxx b/svx/source/engine3d/e3dsceneupdater.cxx
new file mode 100644
index 000000000..a72b4126d
--- /dev/null
+++ b/svx/source/engine3d/e3dsceneupdater.cxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/e3dsceneupdater.hxx>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+
+
+E3DModifySceneSnapRectUpdater::E3DModifySceneSnapRectUpdater(const SdrObject* pObject)
+: mpScene(nullptr)
+{
+ // Secure old 3D transformation stack before modification
+ const E3dObject* pE3dObject = dynamic_cast< const E3dObject* >(pObject);
+ if(!pE3dObject)
+ return;
+
+ mpScene = pE3dObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr == mpScene || mpScene->getRootE3dSceneFromE3dObject() != mpScene)
+ return;
+
+ // if there is a scene and it's the outmost scene, get current 3D range
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(mpScene->GetViewContact());
+ const basegfx::B3DRange aAllContentRange(rVCScene.getAllContentRange3D());
+
+ if(aAllContentRange.isEmpty())
+ {
+ // no content, nothing to do
+ mpScene = nullptr;
+ }
+ else
+ {
+ // secure current 3D transformation stack
+ mpViewInformation3D = rVCScene.getViewInformation3D(aAllContentRange);
+ }
+}
+
+E3DModifySceneSnapRectUpdater::~E3DModifySceneSnapRectUpdater()
+{
+ if(!(mpScene && mpViewInformation3D))
+ return;
+
+ // after changing parts of the scene, use the secured last 3d transformation stack and the new content
+ // range to calculate a new, eventually expanded or shrunk, 2D geometry for the scene and apply it.
+ // Get new content range
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(mpScene->GetViewContact());
+ basegfx::B3DRange aAllContentRange(rVCScene.getAllContentRange3D());
+
+ // only change when there is still content; else let scene stay at old SnapRect
+ if(aAllContentRange.isEmpty())
+ return;
+
+ // check if object transform of scene has changed
+ if(mpViewInformation3D->getObjectTransformation() != mpScene->GetTransform())
+ {
+ // If Yes, it needs to be updated since it's - for historical reasons -
+ // part of the basic 3d transformation stack of the scene
+ mpViewInformation3D = drawinglayer::geometry::ViewInformation3D(
+ mpScene->GetTransform(), // replace object transformation with new local transform
+ mpViewInformation3D->getOrientation(),
+ mpViewInformation3D->getProjection(),
+ mpViewInformation3D->getDeviceToView(),
+ mpViewInformation3D->getViewTime(),
+ mpViewInformation3D->getExtendedInformationSequence());
+ }
+
+ // transform content range to scene-relative coordinates using old 3d transformation stack
+ aAllContentRange.transform(mpViewInformation3D->getObjectToView());
+
+ // build 2d relative content range
+ basegfx::B2DRange aSnapRange(
+ aAllContentRange.getMinX(), aAllContentRange.getMinY(),
+ aAllContentRange.getMaxX(), aAllContentRange.getMaxY());
+
+ // transform to 2D world coordinates using scene's 2D transformation
+ aSnapRange.transform(rVCScene.getObjectTransformation());
+
+ // snap to (old) integer
+ const tools::Rectangle aNewSnapRect(
+ sal_Int32(floor(aSnapRange.getMinX())), sal_Int32(floor(aSnapRange.getMinY())),
+ sal_Int32(ceil(aSnapRange.getMaxX())), sal_Int32(ceil(aSnapRange.getMaxY())));
+
+ // set as new SnapRect and invalidate bound volume
+ if(mpScene->GetSnapRect() != aNewSnapRect)
+ {
+ mpScene->SetSnapRect(aNewSnapRect);
+ mpScene->InvalidateBoundVolume();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/e3dundo.cxx b/svx/source/engine3d/e3dundo.cxx
new file mode 100644
index 000000000..b1d99ddfd
--- /dev/null
+++ b/svx/source/engine3d/e3dundo.cxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/e3dundo.hxx>
+#include <svx/e3dsceneupdater.hxx>
+
+
+E3dUndoAction::~E3dUndoAction ()
+{
+}
+
+// Repeat does not exist
+
+bool E3dUndoAction::CanRepeat(SfxRepeatTarget&) const
+{
+ return false;
+}
+
+
+// Undo destructor for 3D-Rotation
+E3dRotateUndoAction::~E3dRotateUndoAction()
+{
+}
+
+// Undo for 3D-Rotation on the Rotation matrix
+void E3dRotateUndoAction::Undo()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(&mrMy3DObj);
+ mrMy3DObj.SetTransform(maMyOldRotation);
+}
+
+// Redo for 3D-Rotation on the Rotation matrix
+void E3dRotateUndoAction::Redo()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(&mrMy3DObj);
+ mrMy3DObj.SetTransform(maMyNewRotation);
+}
+
+E3dAttributesUndoAction::E3dAttributesUndoAction(
+ E3dObject& rInObject,
+ const SfxItemSet& rNewSet,
+ const SfxItemSet& rOldSet)
+: SdrUndoAction(rInObject.getSdrModelFromSdrObject())
+ ,mrObject(rInObject)
+ ,maNewSet(rNewSet)
+ ,maOldSet(rOldSet)
+{
+}
+
+E3dAttributesUndoAction::~E3dAttributesUndoAction()
+{
+}
+
+// Undo() implemented through Set3DAttributes() to only maintain the attributes
+// in one place
+
+void E3dAttributesUndoAction::Undo()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(&mrObject);
+ mrObject.SetMergedItemSetAndBroadcast(maOldSet);
+}
+
+void E3dAttributesUndoAction::Redo()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(&mrObject);
+ mrObject.SetMergedItemSetAndBroadcast(maNewSet);
+}
+
+// Multiple Undo is not possible
+bool E3dAttributesUndoAction::CanRepeat(SfxRepeatTarget& /*rView*/) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/extrud3d.cxx b/svx/source/engine3d/extrud3d.cxx
new file mode 100644
index 000000000..a74479b60
--- /dev/null
+++ b/svx/source/engine3d/extrud3d.cxx
@@ -0,0 +1,219 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/strings.hrc>
+#include <svx/deflt3d.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdobjkind.hxx>
+#include <extrud3d.hxx>
+
+#include <svx/svdopath.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svx3ditems.hxx>
+#include <svx/xlineit0.hxx>
+#include <sdr/properties/e3dextrudeproperties.hxx>
+#include <sdr/contact/viewcontactofe3dextrude.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b3dpolypolygontools.hxx>
+
+
+// DrawContact section
+std::unique_ptr<sdr::contact::ViewContact> E3dExtrudeObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dExtrude>(*this);
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dExtrudeObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dExtrudeProperties>(*this);
+}
+
+// Constructor creates a two cover surface tools::PolyPolygon and (point-count 1) side
+// surfaces rectangles from the passed PolyPolygon
+E3dExtrudeObj::E3dExtrudeObj(
+ SdrModel& rSdrModel,
+ const E3dDefaultAttributes& rDefault,
+ const basegfx::B2DPolyPolygon& rPP,
+ double fDepth)
+: E3dCompoundObject(rSdrModel),
+ maExtrudePolygon(rPP)
+{
+ // since the old class PolyPolygon3D did mirror the given PolyPolygons in Y, do the same here
+ basegfx::B2DHomMatrix aMirrorY;
+ aMirrorY.scale(1.0, -1.0);
+ maExtrudePolygon.transform(aMirrorY);
+
+ // Set Defaults
+ SetDefaultAttributes(rDefault);
+
+ // set extrude depth
+ GetProperties().SetObjectItemDirect(makeSvx3DDepthItem(static_cast<sal_uInt32>(fDepth + 0.5)));
+}
+
+E3dExtrudeObj::E3dExtrudeObj(SdrModel& rSdrModel)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set Defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+}
+
+E3dExtrudeObj::E3dExtrudeObj(SdrModel& rSdrModel, E3dExtrudeObj const & rSource)
+: E3dCompoundObject(rSdrModel, rSource)
+{
+ // Set Defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+
+ maExtrudePolygon = rSource.maExtrudePolygon;
+}
+
+E3dExtrudeObj::~E3dExtrudeObj()
+{
+}
+
+void E3dExtrudeObj::SetDefaultAttributes(const E3dDefaultAttributes& rDefault)
+{
+ GetProperties().SetObjectItemDirect(Svx3DSmoothNormalsItem(rDefault.GetDefaultExtrudeSmoothed()));
+ GetProperties().SetObjectItemDirect(Svx3DSmoothLidsItem(rDefault.GetDefaultExtrudeSmoothFrontBack()));
+ GetProperties().SetObjectItemDirect(Svx3DCharacterModeItem(rDefault.GetDefaultExtrudeCharacterMode()));
+ GetProperties().SetObjectItemDirect(Svx3DCloseFrontItem(rDefault.GetDefaultExtrudeCloseFront()));
+ GetProperties().SetObjectItemDirect(Svx3DCloseBackItem(rDefault.GetDefaultExtrudeCloseBack()));
+
+ // For extrudes use StdTexture in X and Y by default
+ GetProperties().SetObjectItemDirect(Svx3DTextureProjectionXItem(1));
+ GetProperties().SetObjectItemDirect(Svx3DTextureProjectionYItem(1));
+}
+
+SdrObjKind E3dExtrudeObj::GetObjIdentifier() const
+{
+ return SdrObjKind::E3D_Extrusion;
+}
+
+E3dExtrudeObj* E3dExtrudeObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new E3dExtrudeObj(rTargetModel, *this);
+}
+
+// Set local parameters with geometry re-creating
+
+void E3dExtrudeObj::SetExtrudePolygon(const basegfx::B2DPolyPolygon &rNew)
+{
+ if(maExtrudePolygon != rNew)
+ {
+ maExtrudePolygon = rNew;
+ ActionChanged();
+ }
+}
+
+// Get the name of the object (singular)
+
+OUString E3dExtrudeObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulExtrude3d));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName += " '" + aName + "'";
+ }
+ return sName;
+}
+
+// Get the name of the object (plural)
+
+OUString E3dExtrudeObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralExtrude3d);
+}
+
+bool E3dExtrudeObj::IsBreakObjPossible()
+{
+ return true;
+}
+
+std::unique_ptr<SdrAttrObj,SdrObjectFreeOp> E3dExtrudeObj::GetBreakObj()
+{
+ basegfx::B3DPolyPolygon aFrontSide;
+ basegfx::B3DPolyPolygon aBackSide;
+
+ if(maExtrudePolygon.count())
+ {
+ basegfx::B2DPolyPolygon aTemp(maExtrudePolygon);
+ aTemp.removeDoublePoints();
+ aTemp = basegfx::utils::correctOrientations(aTemp);
+ const basegfx::B2VectorOrientation aOrient = basegfx::utils::getOrientation(aTemp.getB2DPolygon(0));
+
+ if(basegfx::B2VectorOrientation::Positive == aOrient)
+ {
+ aTemp.flip();
+ }
+
+ aFrontSide = basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon(aTemp);
+ }
+
+ if(aFrontSide.count())
+ {
+ aBackSide = aFrontSide;
+
+ if(GetExtrudeDepth())
+ {
+ basegfx::B3DHomMatrix aTransform;
+
+ if(100 != GetPercentBackScale())
+ {
+ // scale polygon from center
+ const double fScaleFactor(GetPercentBackScale() / 100.0);
+ const basegfx::B3DRange aPolyPolyRange(basegfx::utils::getRange(aBackSide));
+ const basegfx::B3DPoint aCenter(aPolyPolyRange.getCenter());
+
+ aTransform.translate(-aCenter.getX(), -aCenter.getY(), -aCenter.getZ());
+ aTransform.scale(fScaleFactor, fScaleFactor, fScaleFactor);
+ aTransform.translate(aCenter.getX(), aCenter.getY(), aCenter.getZ());
+ }
+
+ // translate by extrude depth
+ aTransform.translate(0.0, 0.0, static_cast<double>(GetExtrudeDepth()));
+
+ aBackSide.transform(aTransform);
+ }
+ }
+
+ if(aBackSide.count())
+ {
+ // create PathObj
+ basegfx::B2DPolyPolygon aPoly = TransformToScreenCoor(aBackSide);
+ std::unique_ptr<SdrPathObj,SdrObjectFreeOp> pPathObj(new SdrPathObj(getSdrModelFromSdrObject(), SdrObjKind::PolyLine, aPoly));
+
+ SfxItemSet aSet(GetObjectItemSet());
+ aSet.Put(XLineStyleItem(css::drawing::LineStyle_SOLID));
+ pPathObj->SetMergedItemSet(aSet);
+
+ return std::unique_ptr<SdrAttrObj,SdrObjectFreeOp>(pPathObj.release());
+ }
+
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/float3d.cxx b/svx/source/engine3d/float3d.cxx
new file mode 100644
index 000000000..0c0b8eeb8
--- /dev/null
+++ b/svx/source/engine3d/float3d.cxx
@@ -0,0 +1,2944 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+#include <svtools/colrdlg.hxx>
+#include <svx/colorbox.hxx>
+#include <svx/f3dchild.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/dlgutil.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/svx3ditems.hxx>
+
+#include <svx/dialmgr.hxx>
+#include <svx/viewpt3d.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/strings.hrc>
+
+#include <editeng/colritem.hxx>
+#include <osl/diagnose.h>
+#include <svx/e3ditem.hxx>
+#include <svl/whiter.hxx>
+#include <svtools/unitconv.hxx>
+
+#include <svx/float3d.hxx>
+
+#include <bitmaps.hlst>
+
+using namespace com::sun::star;
+
+SFX_IMPL_DOCKINGWINDOW_WITHID( Svx3DChildWindow, SID_3D_WIN )
+
+struct Svx3DWinImpl
+{
+ SfxItemPool* pPool;
+};
+
+namespace {
+ /** Get the dispatcher from the current view frame, or, if that is not
+ available, from the given bindings.
+ @param pBindings
+ May be NULL.
+ @returns NULL when both the current view frame is NULL and the given
+ bindings are NULL.
+ */
+ SfxDispatcher* LocalGetDispatcher (const SfxBindings* pBindings)
+ {
+ SfxDispatcher* pDispatcher = nullptr;
+
+ if (SfxViewFrame::Current() != nullptr)
+ pDispatcher = SfxViewFrame::Current()->GetDispatcher();
+ else if (pBindings != nullptr)
+ pDispatcher = pBindings->GetDispatcher();
+
+ return pDispatcher;
+ }
+}
+
+Svx3DWin::Svx3DWin(SfxBindings* pInBindings, SfxChildWindow *pCW, vcl::Window* pParent)
+ : SfxDockingWindow(pInBindings, pCW, pParent,
+ "Docking3DEffects", "svx/ui/docking3deffects.ui")
+
+ , m_xBtnGeo(m_xBuilder->weld_toggle_button("geometry"))
+ , m_xBtnRepresentation(m_xBuilder->weld_toggle_button("representation"))
+ , m_xBtnLight(m_xBuilder->weld_toggle_button("light"))
+ , m_xBtnTexture(m_xBuilder->weld_toggle_button("texture"))
+ , m_xBtnMaterial(m_xBuilder->weld_toggle_button("material"))
+ , m_xBtnUpdate(m_xBuilder->weld_toggle_button("update"))
+ , m_xBtnAssign(m_xBuilder->weld_button("assign"))
+
+ , m_xFLGeometrie(m_xBuilder->weld_container("geoframe"))
+ , m_xFtPercentDiagonal(m_xBuilder->weld_label("diagonalft"))
+ , m_xMtrPercentDiagonal(m_xBuilder->weld_metric_spin_button("diagonal", FieldUnit::PERCENT))
+ , m_xFtBackscale(m_xBuilder->weld_label("scaleddepthft"))
+ , m_xMtrBackscale(m_xBuilder->weld_metric_spin_button("scaleddepth", FieldUnit::PERCENT))
+ , m_xFtEndAngle(m_xBuilder->weld_label("angleft"))
+ , m_xMtrEndAngle(m_xBuilder->weld_metric_spin_button("angle", FieldUnit::DEGREE))
+ , m_xFtDepth(m_xBuilder->weld_label("depthft"))
+ , m_xMtrDepth(m_xBuilder->weld_metric_spin_button("depth", FieldUnit::CM))
+
+ , m_xFLSegments(m_xBuilder->weld_container("segmentsframe"))
+ , m_xNumHorizontal(m_xBuilder->weld_spin_button("hori"))
+ , m_xNumVertical(m_xBuilder->weld_spin_button("veri"))
+
+ , m_xFLNormals(m_xBuilder->weld_container("normals"))
+ , m_xBtnNormalsObj(m_xBuilder->weld_toggle_button("objspecific"))
+ , m_xBtnNormalsFlat(m_xBuilder->weld_toggle_button("flat"))
+ , m_xBtnNormalsSphere(m_xBuilder->weld_toggle_button("spherical"))
+ , m_xBtnNormalsInvert(m_xBuilder->weld_toggle_button("invertnormals"))
+ , m_xBtnTwoSidedLighting(m_xBuilder->weld_toggle_button("doublesidedillum"))
+ , m_xBtnDoubleSided(m_xBuilder->weld_toggle_button("doublesided"))
+
+ , m_xFLRepresentation(m_xBuilder->weld_container("shadingframe"))
+ , m_xLbShademode(m_xBuilder->weld_combo_box("mode"))
+
+ , m_xFLShadow(m_xBuilder->weld_container("shadowframe"))
+ , m_xBtnShadow3d(m_xBuilder->weld_toggle_button("shadow"))
+ , m_xFtSlant(m_xBuilder->weld_label("slantft"))
+ , m_xMtrSlant(m_xBuilder->weld_metric_spin_button("slant", FieldUnit::DEGREE))
+
+ , m_xFLCamera(m_xBuilder->weld_container("cameraframe"))
+ , m_xMtrDistance(m_xBuilder->weld_metric_spin_button("distance", FieldUnit::CM))
+ , m_xMtrFocalLength(m_xBuilder->weld_metric_spin_button("focal", FieldUnit::CM))
+
+ , m_xFLLight(m_xBuilder->weld_container("illumframe"))
+ , m_xBtnLight1(new LightButton(m_xBuilder->weld_toggle_button("light1")))
+ , m_xBtnLight2(new LightButton(m_xBuilder->weld_toggle_button("light2")))
+ , m_xBtnLight3(new LightButton(m_xBuilder->weld_toggle_button("light3")))
+ , m_xBtnLight4(new LightButton(m_xBuilder->weld_toggle_button("light4")))
+ , m_xBtnLight5(new LightButton(m_xBuilder->weld_toggle_button("light5")))
+ , m_xBtnLight6(new LightButton(m_xBuilder->weld_toggle_button("light6")))
+ , m_xBtnLight7(new LightButton(m_xBuilder->weld_toggle_button("light7")))
+ , m_xBtnLight8(new LightButton(m_xBuilder->weld_toggle_button("light8")))
+ , m_xLbLight1(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor1"), [this]{ return GetFrameWeld(); }))
+ , m_xLbLight2(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor2"), [this]{ return GetFrameWeld(); }))
+ , m_xLbLight3(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor3"), [this]{ return GetFrameWeld(); }))
+ , m_xLbLight4(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor4"), [this]{ return GetFrameWeld(); }))
+ , m_xLbLight5(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor5"), [this]{ return GetFrameWeld(); }))
+ , m_xLbLight6(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor6"), [this]{ return GetFrameWeld(); }))
+ , m_xLbLight7(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor7"), [this]{ return GetFrameWeld(); }))
+ , m_xLbLight8(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor8"), [this]{ return GetFrameWeld(); }))
+ , m_xBtnLightColor(m_xBuilder->weld_button("colorbutton1"))
+ , m_xLbAmbientlight(new ColorListBox(m_xBuilder->weld_menu_button("ambientcolor"), [this]{ return GetFrameWeld(); }))
+ , m_xBtnAmbientColor(m_xBuilder->weld_button("colorbutton2"))
+
+ , m_xFLTexture(m_xBuilder->weld_container("textureframe"))
+ , m_xBtnTexLuminance(m_xBuilder->weld_toggle_button("textype"))
+ , m_xBtnTexColor(m_xBuilder->weld_toggle_button("texcolor"))
+ , m_xBtnTexReplace(m_xBuilder->weld_toggle_button("texreplace"))
+ , m_xBtnTexModulate(m_xBuilder->weld_toggle_button("texmodulate"))
+ , m_xBtnTexObjectX(m_xBuilder->weld_toggle_button("texobjx"))
+ , m_xBtnTexParallelX(m_xBuilder->weld_toggle_button("texparallelx"))
+ , m_xBtnTexCircleX(m_xBuilder->weld_toggle_button("texcirclex"))
+ , m_xBtnTexObjectY(m_xBuilder->weld_toggle_button("texobjy"))
+ , m_xBtnTexParallelY(m_xBuilder->weld_toggle_button("texparallely"))
+ , m_xBtnTexCircleY(m_xBuilder->weld_toggle_button("texcircley"))
+ , m_xBtnTexFilter(m_xBuilder->weld_toggle_button("texfilter"))
+
+ , m_xFLMaterial(m_xBuilder->weld_container("materialframe"))
+ , m_xLbMatFavorites(m_xBuilder->weld_combo_box("favorites"))
+ , m_xLbMatColor(new ColorListBox(m_xBuilder->weld_menu_button("objcolor"), [this]{ return GetFrameWeld(); }))
+ , m_xBtnMatColor(m_xBuilder->weld_button("colorbutton3"))
+ , m_xLbMatEmission(new ColorListBox(m_xBuilder->weld_menu_button("illumcolor"), [this]{ return GetFrameWeld(); }))
+ , m_xBtnEmissionColor(m_xBuilder->weld_button("colorbutton4"))
+
+ , m_xFLMatSpecular(m_xBuilder->weld_container("specframe"))
+ , m_xLbMatSpecular(new ColorListBox(m_xBuilder->weld_menu_button("speccolor"), [this]{ return GetFrameWeld(); }))
+ , m_xBtnSpecularColor(m_xBuilder->weld_button("colorbutton5"))
+ , m_xMtrMatSpecularIntensity(m_xBuilder->weld_metric_spin_button("intensity", FieldUnit::PERCENT))
+
+ , m_xCtlPreview(new Svx3DPreviewControl)
+ , m_xCtlPreviewWin(new weld::CustomWeld(*m_xBuilder, "preview", *m_xCtlPreview))
+
+ , m_xLightPreviewGrid(m_xBuilder->weld_container("lightpreviewgrid"))
+ , m_xHoriScale(m_xBuilder->weld_scale("horiscale"))
+ , m_xVertScale(m_xBuilder->weld_scale("vertscale"))
+ , m_xBtn_Corner(m_xBuilder->weld_button("corner"))
+ , m_xLightPreview(new Svx3DLightControl)
+ , m_xCtlLightPreviewWin(new weld::CustomWeld(*m_xBuilder, "lightpreview", *m_xLightPreview))
+ , m_xCtlLightPreview(new SvxLightCtl3D(*m_xLightPreview, *m_xHoriScale, *m_xVertScale, *m_xBtn_Corner)) // TODO might be other body widget as arg 1
+
+ , m_xBtnConvertTo3D(m_xBuilder->weld_button("to3d"))
+ , m_xBtnLatheObject(m_xBuilder->weld_button("tolathe"))
+ , m_xBtnPerspective(m_xBuilder->weld_toggle_button("perspective"))
+
+ , bUpdate(false)
+ , eViewType(ViewType3D::Geo)
+ , pBindings(pInBindings)
+ , mpImpl(new Svx3DWinImpl)
+ , ePoolUnit(MapUnit::MapMM)
+{
+ SetText(SvxResId(RID_SVXDLG_FLOAT3D_STR_TITLE));
+
+ weld::DrawingArea* pDrawingArea = m_xCtlPreview->GetDrawingArea();
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(83, 76), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ m_xCtlPreview->SetOutputSizePixel(aSize);
+
+ m_xLightPreviewGrid->set_size_request(aSize.Width(), aSize.Height());
+ pDrawingArea = m_xLightPreview->GetDrawingArea();
+ pDrawingArea->set_size_request(42, 42); // small to fit to m_xLightPreviewGrid
+
+ mpImpl->pPool = nullptr;
+
+ // Set Metric
+ eFUnit = pInBindings->GetDispatcher()->GetModule()->GetFieldUnit();
+
+ m_xMtrDepth->set_unit( eFUnit );
+ m_xMtrDistance->set_unit( eFUnit );
+ m_xMtrFocalLength->set_unit( eFUnit );
+
+ pControllerItem.reset( new Svx3DCtrlItem(SID_3D_STATE, pBindings) );
+ pConvertTo3DItem.reset( new SvxConvertTo3DItem(SID_CONVERT_TO_3D, pBindings) );
+ pConvertTo3DLatheItem.reset( new SvxConvertTo3DItem(SID_CONVERT_TO_3D_LATHE_FAST, pBindings) );
+
+ m_xBtnAssign->connect_clicked( LINK( this, Svx3DWin, ClickAssignHdl ) );
+ m_xBtnUpdate->connect_toggled( LINK( this, Svx3DWin, ClickUpdateHdl ) );
+
+ Link<weld::Button&,void> aLink( LINK( this, Svx3DWin, ClickViewTypeHdl ) );
+ m_xBtnGeo->connect_clicked( aLink );
+ m_xBtnRepresentation->connect_clicked( aLink );
+ m_xBtnLight->connect_clicked( aLink );
+ m_xBtnTexture->connect_clicked( aLink );
+ m_xBtnMaterial->connect_clicked( aLink );
+
+ aLink = LINK( this, Svx3DWin, ClickHdl );
+ m_xBtnPerspective->connect_clicked( aLink );
+ m_xBtnConvertTo3D->connect_clicked( aLink );
+ m_xBtnLatheObject->connect_clicked( aLink );
+
+ // Geometry
+ m_xBtnNormalsObj->connect_clicked( aLink );
+ m_xBtnNormalsFlat->connect_clicked( aLink );
+ m_xBtnNormalsSphere->connect_clicked( aLink );
+ m_xBtnTwoSidedLighting->connect_clicked( aLink );
+ m_xBtnNormalsInvert->connect_clicked( aLink );
+ m_xBtnDoubleSided->connect_clicked( aLink );
+
+ // Representation
+ m_xBtnShadow3d->connect_clicked( aLink );
+
+ // Lighting
+ m_xBtnLight1->connect_clicked( aLink );
+ m_xBtnLight2->connect_clicked( aLink );
+ m_xBtnLight3->connect_clicked( aLink );
+ m_xBtnLight4->connect_clicked( aLink );
+ m_xBtnLight5->connect_clicked( aLink );
+ m_xBtnLight6->connect_clicked( aLink );
+ m_xBtnLight7->connect_clicked( aLink );
+ m_xBtnLight8->connect_clicked( aLink );
+
+ // Textures
+ m_xBtnTexLuminance->connect_clicked( aLink );
+ m_xBtnTexColor->connect_clicked( aLink );
+ m_xBtnTexReplace->connect_clicked( aLink );
+ m_xBtnTexModulate->connect_clicked( aLink );
+ m_xBtnTexParallelX->connect_clicked( aLink );
+ m_xBtnTexCircleX->connect_clicked( aLink );
+ m_xBtnTexObjectX->connect_clicked( aLink );
+ m_xBtnTexParallelY->connect_clicked( aLink );
+ m_xBtnTexCircleY->connect_clicked( aLink );
+ m_xBtnTexObjectY->connect_clicked( aLink );
+ m_xBtnTexFilter->connect_clicked( aLink );
+
+ // Material
+ aLink = LINK( this, Svx3DWin, ClickColorHdl );
+ m_xBtnLightColor->connect_clicked( aLink );
+ m_xBtnAmbientColor->connect_clicked( aLink );
+ m_xBtnMatColor->connect_clicked( aLink );
+ m_xBtnEmissionColor->connect_clicked( aLink );
+ m_xBtnSpecularColor->connect_clicked( aLink );
+
+
+ Link<weld::ComboBox&,void> aLink2 = LINK( this, Svx3DWin, SelectHdl );
+ Link<ColorListBox&,void> aLink4 = LINK( this, Svx3DWin, SelectColorHdl );
+ m_xLbMatFavorites->connect_changed( aLink2 );
+ m_xLbMatColor->SetSelectHdl( aLink4 );
+ m_xLbMatEmission->SetSelectHdl( aLink4 );
+ m_xLbMatSpecular->SetSelectHdl( aLink4 );
+ m_xLbLight1->SetSelectHdl( aLink4 );
+ m_xLbLight2->SetSelectHdl( aLink4 );
+ m_xLbLight3->SetSelectHdl( aLink4 );
+ m_xLbLight4->SetSelectHdl( aLink4 );
+ m_xLbLight5->SetSelectHdl( aLink4 );
+ m_xLbLight6->SetSelectHdl( aLink4 );
+ m_xLbLight7->SetSelectHdl( aLink4 );
+ m_xLbLight8->SetSelectHdl( aLink4 );
+ m_xLbAmbientlight->SetSelectHdl( aLink4 );
+ m_xLbShademode->connect_changed( aLink2 );
+
+ Link<weld::MetricSpinButton&,void> aLink3 = LINK( this, Svx3DWin, ModifyMetricHdl );
+ Link<weld::SpinButton&,void> aLink5 = LINK( this, Svx3DWin, ModifySpinHdl );
+ m_xMtrMatSpecularIntensity->connect_value_changed( aLink3 );
+ m_xNumHorizontal->connect_value_changed( aLink5 );
+ m_xNumVertical->connect_value_changed( aLink5 );
+ m_xMtrSlant->connect_value_changed( aLink3 );
+
+ // Preview callback
+ m_xCtlLightPreview->SetUserSelectionChangeCallback(LINK( this, Svx3DWin, ChangeSelectionCallbackHdl ));
+
+ aSize = GetOutputSizePixel();
+ SetMinOutputSizePixel( aSize );
+
+ Construct();
+
+ // Initiation of the initialization of the ColorLBs
+ SfxDispatcher* pDispatcher = LocalGetDispatcher(pBindings);
+ if (pDispatcher != nullptr)
+ {
+ SfxBoolItem aItem( SID_3D_INIT, true );
+ pDispatcher->ExecuteList(SID_3D_INIT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+ }
+
+ Reset();
+
+ //lock down the size of the initial largest default mode as the permanent size
+ aSize = get_preferred_size();
+ set_width_request(aSize.Width());
+ set_height_request(aSize.Height());
+}
+
+Svx3DWin::~Svx3DWin()
+{
+ disposeOnce();
+}
+
+void Svx3DWin::dispose()
+{
+ pModel.reset();
+
+ pControllerItem.reset();
+ pConvertTo3DItem.reset();
+ pConvertTo3DLatheItem.reset();
+
+ mpImpl.reset();
+
+ m_xBtnGeo.reset();
+ m_xBtnRepresentation.reset();
+ m_xBtnLight.reset();
+ m_xBtnTexture.reset();
+ m_xBtnMaterial.reset();
+ m_xBtnUpdate.reset();
+ m_xBtnAssign.reset();
+ m_xFLGeometrie.reset();
+ m_xFtPercentDiagonal.reset();
+ m_xMtrPercentDiagonal.reset();
+ m_xFtBackscale.reset();
+ m_xMtrBackscale.reset();
+ m_xFtEndAngle.reset();
+ m_xMtrEndAngle.reset();
+ m_xFtDepth.reset();
+ m_xMtrDepth.reset();
+ m_xFLSegments.reset();
+ m_xNumHorizontal.reset();
+ m_xNumVertical.reset();
+ m_xFLNormals.reset();
+ m_xBtnNormalsObj.reset();
+ m_xBtnNormalsFlat.reset();
+ m_xBtnNormalsSphere.reset();
+ m_xBtnNormalsInvert.reset();
+ m_xBtnTwoSidedLighting.reset();
+ m_xBtnDoubleSided.reset();
+ m_xFLRepresentation.reset();
+ m_xLbShademode.reset();
+ m_xFLShadow.reset();
+ m_xBtnShadow3d.reset();
+ m_xFtSlant.reset();
+ m_xMtrSlant.reset();
+ m_xFLCamera.reset();
+ m_xMtrDistance.reset();
+ m_xMtrFocalLength.reset();
+ m_xFLLight.reset();
+ m_xBtnLight1.reset();
+ m_xBtnLight2.reset();
+ m_xBtnLight3.reset();
+ m_xBtnLight4.reset();
+ m_xBtnLight5.reset();
+ m_xBtnLight6.reset();
+ m_xBtnLight7.reset();
+ m_xBtnLight8.reset();
+ m_xLbLight1.reset();
+ m_xLbLight2.reset();
+ m_xLbLight3.reset();
+ m_xLbLight4.reset();
+ m_xLbLight5.reset();
+ m_xLbLight6.reset();
+ m_xLbLight7.reset();
+ m_xLbLight8.reset();
+ m_xBtnLightColor.reset();
+ m_xLbAmbientlight.reset();
+ m_xBtnAmbientColor.reset();
+ m_xFLTexture.reset();
+ m_xBtnTexLuminance.reset();
+ m_xBtnTexColor.reset();
+ m_xBtnTexReplace.reset();
+ m_xBtnTexModulate.reset();
+ m_xBtnTexObjectX.reset();
+ m_xBtnTexParallelX.reset();
+ m_xBtnTexCircleX.reset();
+ m_xBtnTexObjectY.reset();
+ m_xBtnTexParallelY.reset();
+ m_xBtnTexCircleY.reset();
+ m_xBtnTexFilter.reset();
+ m_xFLMaterial.reset();
+ m_xLbMatFavorites.reset();
+ m_xLbMatColor.reset();
+ m_xBtnMatColor.reset();
+ m_xLbMatEmission.reset();
+ m_xBtnEmissionColor.reset();
+ m_xFLMatSpecular.reset();
+ m_xLbMatSpecular.reset();
+ m_xBtnSpecularColor.reset();
+ m_xMtrMatSpecularIntensity.reset();
+ m_xCtlPreviewWin.reset();
+ m_xCtlPreview.reset();
+
+ m_xCtlLightPreview.reset();
+ m_xCtlLightPreviewWin.reset();
+ m_xLightPreview.reset();
+ m_xBtn_Corner.reset();
+ m_xVertScale.reset();
+ m_xHoriScale.reset();
+ m_xLightPreviewGrid.reset();
+
+ m_xBtnConvertTo3D.reset();
+ m_xBtnLatheObject.reset();
+ m_xBtnPerspective.reset();
+
+ SfxDockingWindow::dispose();
+}
+
+void Svx3DWin::Construct()
+{
+ m_xBtnGeo->set_active(true);
+ ClickViewTypeHdl(*m_xBtnGeo);
+ m_xLightPreviewGrid->hide();
+}
+
+void Svx3DWin::Reset()
+{
+ // Various initializations, default is AllAttributes
+ m_xLbShademode->set_active( 0 );
+ m_xMtrMatSpecularIntensity->set_value( 50, FieldUnit::PERCENT );
+
+ m_xBtnLight1->set_active(true);
+ m_xBtnUpdate->set_active(true);
+ ClickUpdateHdl(*m_xBtnUpdate);
+
+ // Select nothing, to avoid errors when selecting the first
+ m_xCtlLightPreview->GetSvx3DLightControl().SelectLight(0);
+ m_xCtlLightPreview->CheckSelection();
+}
+
+void Svx3DWin::Update( SfxItemSet const & rAttrs )
+{
+ // remember 2d attributes
+ if(mpRemember2DAttributes)
+ mpRemember2DAttributes->ClearItem();
+ else
+ mpRemember2DAttributes = std::make_unique<SfxItemSetFixed
+ <SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_3D_FIRST, SDRATTR_3D_LAST>>(*rAttrs.GetPool());
+
+ SfxWhichIter aIter(*mpRemember2DAttributes);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ SfxItemState eState = rAttrs.GetItemState(nWhich, false);
+ if(SfxItemState::DONTCARE == eState)
+ mpRemember2DAttributes->InvalidateItem(nWhich);
+ else if(SfxItemState::SET == eState)
+ mpRemember2DAttributes->Put(rAttrs.Get(nWhich, false));
+
+ nWhich = aIter.NextWhich();
+ }
+
+ // construct field values
+ const SfxPoolItem* pItem;
+
+ // Possible determine PoolUnit
+ if( !mpImpl->pPool )
+ {
+ mpImpl->pPool = rAttrs.GetPool();
+ DBG_ASSERT( mpImpl->pPool, "Where is the Pool? ");
+ ePoolUnit = mpImpl->pPool->GetMetric( SID_ATTR_LINE_WIDTH );
+ }
+ eFUnit = GetModuleFieldUnit( rAttrs );
+
+
+ // Segment Number Can be changed? and other states
+ SfxItemState eState = rAttrs.GetItemState( SID_ATTR_3D_INTERN, false, &pItem );
+ if( SfxItemState::SET == eState )
+ {
+ sal_uInt32 nState = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
+ bool bExtrude = ( nState & 2 );
+ bool bSphere = ( nState & 4 );
+ bool bCube = ( nState & 8 );
+
+ bool bChart = ( nState & 32 ); // Chart
+
+ if( !bChart )
+ {
+ // For cube objects are no segments set
+ m_xFLSegments->set_sensitive(!bCube);
+
+ m_xFtPercentDiagonal->set_sensitive( !bCube && !bSphere );
+ m_xMtrPercentDiagonal->set_sensitive( !bCube && !bSphere );
+ m_xFtBackscale->set_sensitive( !bCube && !bSphere );
+ m_xMtrBackscale->set_sensitive( !bCube && !bSphere );
+ m_xFtDepth->set_sensitive( !bCube && !bSphere );
+ m_xMtrDepth->set_sensitive( !bCube && !bSphere );
+ if( bCube )
+ {
+ m_xNumHorizontal->set_text("");
+ m_xNumVertical->set_text("");
+ }
+ if( bCube || bSphere )
+ {
+ m_xMtrPercentDiagonal->set_text("");
+ m_xMtrBackscale->set_text("");
+ m_xMtrDepth->set_text("");
+ }
+
+ // There is a final angle only for Lathe objects.
+ m_xFtEndAngle->set_sensitive( !bExtrude && !bCube && !bSphere );
+ m_xMtrEndAngle->set_sensitive( !bExtrude && !bCube && !bSphere );
+ if( bExtrude || bCube || bSphere )
+ m_xMtrEndAngle->set_text("");
+ }
+ else
+ {
+ // Geometry
+ m_xNumHorizontal->set_text("");
+ m_xNumVertical->set_text("");
+ m_xFLSegments->set_sensitive( false );
+ m_xFtEndAngle->set_sensitive( false );
+ m_xMtrEndAngle->set_sensitive( false );
+ m_xMtrEndAngle->set_text("");
+ m_xFtDepth->set_sensitive( false );
+ m_xMtrDepth->set_sensitive( false );
+ m_xMtrDepth->set_text("");
+
+ // Representation
+ m_xFLShadow->set_sensitive(false);
+
+ m_xMtrDistance->set_text("");
+ m_xMtrFocalLength->set_text("");
+ m_xFLCamera->set_sensitive( false );
+
+ //Lower Range
+ m_xBtnConvertTo3D->set_sensitive( false );
+ m_xBtnLatheObject->set_sensitive( false );
+ }
+ }
+ // Bitmap fill ? -> Status
+ bool bBitmap(false);
+ eState = rAttrs.GetItemState(XATTR_FILLSTYLE);
+ if(eState != SfxItemState::DONTCARE)
+ {
+ drawing::FillStyle eXFS = rAttrs.Get(XATTR_FILLSTYLE).GetValue();
+ bBitmap = (eXFS == drawing::FillStyle_BITMAP || eXFS == drawing::FillStyle_GRADIENT || eXFS == drawing::FillStyle_HATCH);
+ }
+
+ m_xFLTexture->set_sensitive(bBitmap);
+
+ // Geometry
+ // Number of segments (horizontal)
+ if( m_xNumHorizontal->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_HORZ_SEGS);
+ if(eState != SfxItemState::DONTCARE)
+ {
+ sal_uInt32 nValue = rAttrs.Get(SDRATTR_3DOBJ_HORZ_SEGS).GetValue();
+ if (nValue != static_cast<sal_uInt32>(m_xNumHorizontal->get_value()))
+ {
+ m_xNumHorizontal->set_value( nValue );
+ bUpdate = true;
+ }
+ else if( m_xNumHorizontal->get_text().isEmpty() )
+ m_xNumHorizontal->set_value( nValue );
+ }
+ else
+ {
+ if( !m_xNumHorizontal->get_text().isEmpty() )
+ {
+ m_xNumHorizontal->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ //Number of segments (vertical)
+ if( m_xNumVertical->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_VERT_SEGS);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt32 nValue = rAttrs.Get(SDRATTR_3DOBJ_VERT_SEGS).GetValue();
+ if( nValue != static_cast<sal_uInt32>(m_xNumVertical->get_value()) )
+ {
+ m_xNumVertical->set_value( nValue );
+ bUpdate = true;
+ }
+ else if( m_xNumVertical->get_text().isEmpty() )
+ m_xNumVertical->set_value( nValue );
+ }
+ else
+ {
+ if( !m_xNumVertical->get_text().isEmpty() )
+ {
+ m_xNumVertical->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ // Depth
+ if( m_xMtrDepth->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_DEPTH);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt32 nValue = rAttrs.Get(SDRATTR_3DOBJ_DEPTH).GetValue();
+ sal_uInt32 nValue2 = GetCoreValue(*m_xMtrDepth, ePoolUnit);
+ if( nValue != nValue2 )
+ {
+ if( eFUnit != m_xMtrDepth->get_unit() )
+ SetFieldUnit(*m_xMtrDepth, eFUnit);
+
+ SetMetricValue(*m_xMtrDepth, nValue, ePoolUnit);
+ bUpdate = true;
+ }
+ else if( m_xMtrDepth->get_text().isEmpty() )
+ m_xMtrDepth->set_value(m_xMtrDepth->get_value(FieldUnit::NONE), FieldUnit::NONE);
+ }
+ else
+ {
+ if( !m_xMtrDepth->get_text().isEmpty() )
+ {
+ m_xMtrDepth->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ // Double walled / Double sided
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_DOUBLE_SIDED);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bValue = rAttrs.Get(SDRATTR_3DOBJ_DOUBLE_SIDED).GetValue();
+ if( bValue != m_xBtnDoubleSided->get_active() )
+ {
+ m_xBtnDoubleSided->set_active( bValue );
+ bUpdate = true;
+ }
+ else if( m_xBtnDoubleSided->get_state() == TRISTATE_INDET )
+ m_xBtnDoubleSided->set_active( bValue );
+ }
+ else
+ {
+ if( m_xBtnDoubleSided->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnDoubleSided->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+
+ // Edge rounding
+ if( m_xMtrPercentDiagonal->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_PERCENT_DIAGONAL);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_PERCENT_DIAGONAL).GetValue();
+ if( nValue != m_xMtrPercentDiagonal->get_value(FieldUnit::PERCENT) )
+ {
+ m_xMtrPercentDiagonal->set_value(nValue, FieldUnit::PERCENT);
+ bUpdate = true;
+ }
+ else if( m_xMtrPercentDiagonal->get_text().isEmpty() )
+ m_xMtrPercentDiagonal->set_value(nValue, FieldUnit::PERCENT);
+ }
+ else
+ {
+ if( !m_xMtrPercentDiagonal->get_text().isEmpty() )
+ {
+ m_xMtrPercentDiagonal->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ // Depth scaling
+ if( m_xMtrBackscale->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_BACKSCALE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_BACKSCALE).GetValue();
+ if( nValue != m_xMtrBackscale->get_value(FieldUnit::PERCENT) )
+ {
+ m_xMtrBackscale->set_value(nValue, FieldUnit::PERCENT);
+ bUpdate = true;
+ }
+ else if( m_xMtrBackscale->get_text().isEmpty() )
+ m_xMtrBackscale->set_value(nValue, FieldUnit::PERCENT);
+ }
+ else
+ {
+ if( !m_xMtrBackscale->get_text().isEmpty() )
+ {
+ m_xMtrBackscale->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ // End angle
+ if( m_xMtrEndAngle->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_END_ANGLE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_Int32 nValue = rAttrs.Get(SDRATTR_3DOBJ_END_ANGLE).GetValue();
+ if( nValue != m_xMtrEndAngle->get_value(FieldUnit::DEGREE) )
+ {
+ m_xMtrEndAngle->set_value(nValue, FieldUnit::DEGREE);
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( !m_xMtrEndAngle->get_text().isEmpty() )
+ {
+ m_xMtrEndAngle->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ // Normal type
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_NORMALS_KIND);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_NORMALS_KIND).GetValue();
+
+ if( ( !m_xBtnNormalsObj->get_active() && nValue == 0 ) ||
+ ( !m_xBtnNormalsFlat->get_active() && nValue == 1 ) ||
+ ( !m_xBtnNormalsSphere->get_active() && nValue == 2 ) )
+ {
+ m_xBtnNormalsObj->set_active( nValue == 0 );
+ m_xBtnNormalsFlat->set_active( nValue == 1 );
+ m_xBtnNormalsSphere->set_active( nValue == 2 );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xBtnNormalsObj->get_active() ||
+ m_xBtnNormalsFlat->get_active() ||
+ m_xBtnNormalsSphere->get_active() )
+ {
+ m_xBtnNormalsObj->set_active( false );
+ m_xBtnNormalsFlat->set_active( false );
+ m_xBtnNormalsSphere->set_active( false );
+ bUpdate = true;
+ }
+ }
+
+ // Normal inverted
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_NORMALS_INVERT);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bValue = rAttrs.Get(SDRATTR_3DOBJ_NORMALS_INVERT).GetValue();
+ if( bValue != m_xBtnNormalsInvert->get_active() )
+ {
+ m_xBtnNormalsInvert->set_active( bValue );
+ bUpdate = true;
+ }
+ else if( m_xBtnNormalsInvert->get_state() == TRISTATE_INDET )
+ m_xBtnNormalsInvert->set_active( bValue );
+ }
+ else
+ {
+ if( m_xBtnNormalsInvert->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnNormalsInvert->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+
+ // 2-sided lighting
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_TWO_SIDED_LIGHTING);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bValue = rAttrs.Get(SDRATTR_3DSCENE_TWO_SIDED_LIGHTING).GetValue();
+ if( bValue != m_xBtnTwoSidedLighting->get_active() )
+ {
+ m_xBtnTwoSidedLighting->set_active( bValue );
+ bUpdate = true;
+ }
+ else if( m_xBtnTwoSidedLighting->get_state() == TRISTATE_INDET )
+ m_xBtnTwoSidedLighting->set_active( bValue );
+ }
+ else
+ {
+ if( m_xBtnTwoSidedLighting->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnTwoSidedLighting->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+
+ // Representation
+ // Shademode
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_SHADE_MODE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DSCENE_SHADE_MODE).GetValue();
+ if( nValue != m_xLbShademode->get_active() )
+ {
+ m_xLbShademode->set_active( nValue );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xLbShademode->get_active() != 0 )
+ {
+ m_xLbShademode->set_active(-1);
+ bUpdate = true;
+ }
+ }
+
+ // 3D-Shadow
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_SHADOW_3D);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bValue = rAttrs.Get(SDRATTR_3DOBJ_SHADOW_3D).GetValue();
+ if( bValue != m_xBtnShadow3d->get_active() )
+ {
+ m_xBtnShadow3d->set_active( bValue );
+ m_xFtSlant->set_sensitive( bValue );
+ m_xMtrSlant->set_sensitive( bValue );
+ bUpdate = true;
+ }
+ else if( m_xBtnShadow3d->get_state() == TRISTATE_INDET )
+ m_xBtnShadow3d->set_active( bValue );
+ }
+ else
+ {
+ if( m_xBtnShadow3d->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnShadow3d->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+
+ // Inclination (Shadow)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_SHADOW_SLANT);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DSCENE_SHADOW_SLANT).GetValue();
+ if( nValue != m_xMtrSlant->get_value(FieldUnit::DEGREE) )
+ {
+ m_xMtrSlant->set_value(nValue, FieldUnit::DEGREE);
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( !m_xMtrSlant->get_text().isEmpty() )
+ {
+ m_xMtrSlant->set_text("");
+ bUpdate = true;
+ }
+ }
+
+ // Distance
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_DISTANCE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt32 nValue = rAttrs.Get(SDRATTR_3DSCENE_DISTANCE).GetValue();
+ sal_uInt32 nValue2 = GetCoreValue(*m_xMtrDistance, ePoolUnit);
+ if( nValue != nValue2 )
+ {
+ if( eFUnit != m_xMtrDistance->get_unit() )
+ SetFieldUnit(*m_xMtrDistance, eFUnit);
+
+ SetMetricValue(*m_xMtrDistance, nValue, ePoolUnit);
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( !m_xMtrDepth->get_text().isEmpty() )
+ {
+ m_xMtrDepth->set_text("");
+ bUpdate = true;
+ }
+ }
+
+ // Focal length
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_FOCAL_LENGTH);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt32 nValue = rAttrs.Get(SDRATTR_3DSCENE_FOCAL_LENGTH).GetValue();
+ sal_uInt32 nValue2 = GetCoreValue(*m_xMtrFocalLength, ePoolUnit);
+ if( nValue != nValue2 )
+ {
+ if( eFUnit != m_xMtrFocalLength->get_unit() )
+ SetFieldUnit(*m_xMtrFocalLength, eFUnit);
+
+ SetMetricValue(*m_xMtrFocalLength, nValue, ePoolUnit);
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( !m_xMtrFocalLength->get_text().isEmpty() )
+ {
+ m_xMtrFocalLength->set_text("");
+ bUpdate = true;
+ }
+ }
+
+// Lighting
+ Color aColor;
+ // Light 1 (Color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_1);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_1).GetValue();
+ ColorListBox* pLb = m_xLbLight1.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight1->IsNoSelection())
+ {
+ m_xLbLight1->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 1 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_1);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_1).GetValue();
+ if (bOn != m_xBtnLight1->isLightOn())
+ {
+ m_xBtnLight1->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight1->get_state() == TRISTATE_INDET )
+ m_xBtnLight1->set_active( m_xBtnLight1->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight1->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight1->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 1 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_1);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ //Light 2 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_2);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_2).GetValue();
+ ColorListBox* pLb = m_xLbLight2.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight2->IsNoSelection())
+ {
+ m_xLbLight2->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 2 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_2);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_2).GetValue();
+ if (bOn != m_xBtnLight2->isLightOn())
+ {
+ m_xBtnLight2->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight2->get_state() == TRISTATE_INDET )
+ m_xBtnLight2->set_active( m_xBtnLight2->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight2->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight2->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ //Light 2 (Direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_2);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ //Light 3 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_3);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_3).GetValue();
+ ColorListBox* pLb = m_xLbLight3.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight3->IsNoSelection())
+ {
+ m_xLbLight3->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 3 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_3);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_3).GetValue();
+ if (bOn != m_xBtnLight3->isLightOn())
+ {
+ m_xBtnLight3->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight3->get_state() == TRISTATE_INDET )
+ m_xBtnLight3->set_active( m_xBtnLight3->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight3->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight3->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 3 (Direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_3);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Light 4 (Color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_4);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_4).GetValue();
+ ColorListBox* pLb = m_xLbLight4.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight4->IsNoSelection())
+ {
+ m_xLbLight4->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 4 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_4);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_4).GetValue();
+ if (bOn != m_xBtnLight4->isLightOn())
+ {
+ m_xBtnLight4->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight4->get_state() == TRISTATE_INDET )
+ m_xBtnLight4->set_active( m_xBtnLight4->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight4->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight4->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 4 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_4);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Light 5 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_5);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_5).GetValue();
+ ColorListBox* pLb = m_xLbLight5.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight5->IsNoSelection())
+ {
+ m_xLbLight5->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 5 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_5);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_5).GetValue();
+ if (bOn != m_xBtnLight5->isLightOn())
+ {
+ m_xBtnLight5->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight5->get_state() == TRISTATE_INDET )
+ m_xBtnLight5->set_active( m_xBtnLight5->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight5->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight5->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 5 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_5);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Light 6 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_6);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_6).GetValue();
+ ColorListBox* pLb = m_xLbLight6.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight6->IsNoSelection())
+ {
+ m_xLbLight6->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 6 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_6);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_6).GetValue();
+ if (bOn != m_xBtnLight6->isLightOn())
+ {
+ m_xBtnLight6->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight6->get_state() == TRISTATE_INDET )
+ m_xBtnLight6->set_active( m_xBtnLight6->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight6->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight6->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 6 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_6);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Light 7 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_7);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_7).GetValue();
+ ColorListBox* pLb = m_xLbLight7.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight7->IsNoSelection())
+ {
+ m_xLbLight7->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 7 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_7);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_7).GetValue();
+ if (bOn != m_xBtnLight7->isLightOn())
+ {
+ m_xBtnLight7->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight7->get_state() == TRISTATE_INDET )
+ m_xBtnLight7->set_active( m_xBtnLight7->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight7->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight7->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 7 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_7);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Light 8 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_8);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_8).GetValue();
+ ColorListBox* pLb = m_xLbLight8.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight8->IsNoSelection())
+ {
+ m_xLbLight8->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 8 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_8);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_8).GetValue();
+ if (bOn != m_xBtnLight8->isLightOn())
+ {
+ m_xBtnLight8->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight8->get_state() == TRISTATE_INDET )
+ m_xBtnLight8->set_active( m_xBtnLight8->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight8->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight8->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 8 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_8);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Ambient light
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_AMBIENTCOLOR);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_AMBIENTCOLOR).GetValue();
+ ColorListBox* pLb = m_xLbAmbientlight.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbAmbientlight->IsNoSelection())
+ {
+ m_xLbAmbientlight->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+
+
+// Textures
+ // Art
+ if( bBitmap )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_TEXTURE_KIND);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_TEXTURE_KIND).GetValue();
+
+ if( ( !m_xBtnTexLuminance->get_active() && nValue == 1 ) ||
+ ( !m_xBtnTexColor->get_active() && nValue == 3 ) )
+ {
+ m_xBtnTexLuminance->set_active( nValue == 1 );
+ m_xBtnTexColor->set_active( nValue == 3 );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xBtnTexLuminance->get_active() ||
+ m_xBtnTexColor->get_active() )
+ {
+ m_xBtnTexLuminance->set_active( false );
+ m_xBtnTexColor->set_active( false );
+ bUpdate = true;
+ }
+ }
+
+ // Mode
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_TEXTURE_MODE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_TEXTURE_MODE).GetValue();
+
+ if( ( !m_xBtnTexReplace->get_active() && nValue == 1 ) ||
+ ( !m_xBtnTexModulate->get_active() && nValue == 2 ) )
+ {
+ m_xBtnTexReplace->set_active( nValue == 1 );
+ m_xBtnTexModulate->set_active( nValue == 2 );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xBtnTexReplace->get_active() ||
+ m_xBtnTexModulate->get_active() )
+ {
+ m_xBtnTexReplace->set_active( false );
+ m_xBtnTexModulate->set_active( false );
+ bUpdate = true;
+ }
+ }
+
+ // Projection X
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_TEXTURE_PROJ_X);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_TEXTURE_PROJ_X).GetValue();
+
+ if( ( !m_xBtnTexObjectX->get_active() && nValue == 0 ) ||
+ ( !m_xBtnTexParallelX->get_active() && nValue == 1 ) ||
+ ( !m_xBtnTexCircleX->get_active() && nValue == 2 ) )
+ {
+ m_xBtnTexObjectX->set_active( nValue == 0 );
+ m_xBtnTexParallelX->set_active( nValue == 1 );
+ m_xBtnTexCircleX->set_active( nValue == 2 );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xBtnTexObjectX->get_active() ||
+ m_xBtnTexParallelX->get_active() ||
+ m_xBtnTexCircleX->get_active() )
+ {
+ m_xBtnTexObjectX->set_active( false );
+ m_xBtnTexParallelX->set_active( false );
+ m_xBtnTexCircleX->set_active( false );
+ bUpdate = true;
+ }
+ }
+
+ // Projection Y
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_TEXTURE_PROJ_Y);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_TEXTURE_PROJ_Y).GetValue();
+
+ if( ( !m_xBtnTexObjectY->get_active() && nValue == 0 ) ||
+ ( !m_xBtnTexParallelY->get_active() && nValue == 1 ) ||
+ ( !m_xBtnTexCircleY->get_active() && nValue == 2 ) )
+ {
+ m_xBtnTexObjectY->set_active( nValue == 0 );
+ m_xBtnTexParallelY->set_active( nValue == 1 );
+ m_xBtnTexCircleY->set_active( nValue == 2 );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xBtnTexObjectY->get_active() ||
+ m_xBtnTexParallelY->get_active() ||
+ m_xBtnTexCircleY->get_active() )
+ {
+ m_xBtnTexObjectY->set_active( false );
+ m_xBtnTexParallelY->set_active( false );
+ m_xBtnTexCircleY->set_active( false );
+ bUpdate = true;
+ }
+ }
+
+ // Filter
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_TEXTURE_FILTER);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bValue = rAttrs.Get(SDRATTR_3DOBJ_TEXTURE_FILTER).GetValue();
+ if( bValue != m_xBtnTexFilter->get_active() )
+ {
+ m_xBtnTexFilter->set_active( bValue );
+ bUpdate = true;
+ }
+ if( m_xBtnTexFilter->get_state() == TRISTATE_INDET )
+ m_xBtnTexFilter->set_active( bValue );
+ }
+ else
+ {
+ if( m_xBtnTexFilter->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnTexFilter->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ }
+
+
+ // Material Favorites
+ m_xLbMatFavorites->set_active( 0 );
+
+ // Object color
+ eState = rAttrs.GetItemState(XATTR_FILLCOLOR);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(XATTR_FILLCOLOR).GetColorValue();
+ ColorListBox* pLb = m_xLbMatColor.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbMatColor->IsNoSelection())
+ {
+ m_xLbMatColor->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+
+ // Self-luminous color
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_MAT_EMISSION);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DOBJ_MAT_EMISSION).GetValue();
+ ColorListBox* pLb = m_xLbMatEmission.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbMatEmission->IsNoSelection())
+ {
+ m_xLbMatEmission->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+
+ // Specular
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_MAT_SPECULAR);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DOBJ_MAT_SPECULAR).GetValue();
+ ColorListBox* pLb = m_xLbMatSpecular.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbMatSpecular->IsNoSelection())
+ {
+ m_xLbMatSpecular->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+
+ // Specular Intensity
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY).GetValue();
+ if( nValue != m_xMtrMatSpecularIntensity->get_value(FieldUnit::PERCENT) )
+ {
+ m_xMtrMatSpecularIntensity->set_value(nValue, FieldUnit::PERCENT);
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( !m_xMtrMatSpecularIntensity->get_text().isEmpty() )
+ {
+ m_xMtrMatSpecularIntensity->set_text("");
+ bUpdate = true;
+ }
+ }
+
+
+// Other
+ // Perspective
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_PERSPECTIVE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ ProjectionType ePT = static_cast<ProjectionType>(rAttrs.Get(SDRATTR_3DSCENE_PERSPECTIVE).GetValue());
+ if( ( !m_xBtnPerspective->get_active() && ePT == ProjectionType::Perspective ) ||
+ ( m_xBtnPerspective->get_active() && ePT == ProjectionType::Parallel ) )
+ {
+ m_xBtnPerspective->set_active( ePT == ProjectionType::Perspective );
+ bUpdate = true;
+ }
+ if( m_xBtnPerspective->get_state() == TRISTATE_INDET )
+ m_xBtnPerspective->set_active( ePT == ProjectionType::Perspective );
+ }
+ else
+ {
+ if( m_xBtnPerspective->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnPerspective->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+
+ if( !bUpdate )
+ {
+ // however the 2D attributes may be different. Compare these and decide
+
+ bUpdate = true;
+ }
+
+ // Update preview
+ SfxItemSet aSet(rAttrs);
+
+ // set LineStyle hard to drawing::LineStyle_NONE when it's not set so that
+ // the default (drawing::LineStyle_SOLID) is not used for 3d preview
+ if(SfxItemState::SET != aSet.GetItemState(XATTR_LINESTYLE, false))
+ aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+
+ // set FillColor hard to WHITE when it's SfxItemState::DONTCARE so that
+ // the default (Blue7) is not used for 3d preview
+ if(SfxItemState::DONTCARE == aSet.GetItemState(XATTR_FILLCOLOR, false))
+ aSet.Put(XFillColorItem(OUString(), COL_WHITE));
+
+ m_xCtlPreview->Set3DAttributes(aSet);
+ m_xCtlLightPreview->GetSvx3DLightControl().Set3DAttributes(aSet);
+
+ // try to select light corresponding to active button
+ sal_uInt32 nNumber(0xffffffff);
+
+ if(m_xBtnLight1->get_active())
+ nNumber = 0;
+ else if(m_xBtnLight2->get_active())
+ nNumber = 1;
+ else if(m_xBtnLight3->get_active())
+ nNumber = 2;
+ else if(m_xBtnLight4->get_active())
+ nNumber = 3;
+ else if(m_xBtnLight5->get_active())
+ nNumber = 4;
+ else if(m_xBtnLight6->get_active())
+ nNumber = 5;
+ else if(m_xBtnLight7->get_active())
+ nNumber = 6;
+ else if(m_xBtnLight8->get_active())
+ nNumber = 7;
+
+ if(nNumber != 0xffffffff)
+ {
+ m_xCtlLightPreview->GetSvx3DLightControl().SelectLight(nNumber);
+ }
+
+ // handle state of converts possible
+ m_xBtnConvertTo3D->set_sensitive(pConvertTo3DItem->GetState());
+ m_xBtnLatheObject->set_sensitive(pConvertTo3DLatheItem->GetState());
+}
+
+
+void Svx3DWin::GetAttr( SfxItemSet& rAttrs )
+{
+ // get remembered 2d attributes from the dialog
+ if(mpRemember2DAttributes)
+ {
+ SfxWhichIter aIter(*mpRemember2DAttributes);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ SfxItemState eState = aIter.GetItemState(false);
+ if(SfxItemState::DONTCARE == eState)
+ rAttrs.InvalidateItem(nWhich);
+ else if(SfxItemState::SET == eState)
+ rAttrs.Put(mpRemember2DAttributes->Get(nWhich, false));
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+
+//Others must stand as the front on all sides
+ // Perspective
+ if( m_xBtnPerspective->get_state() != TRISTATE_INDET )
+ {
+ ProjectionType nValue;
+ if( m_xBtnPerspective->get_active() )
+ nValue = ProjectionType::Perspective;
+ else
+ nValue = ProjectionType::Parallel;
+ rAttrs.Put(Svx3DPerspectiveItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_PERSPECTIVE);
+
+// Geometry
+ // Possible determine PoolUnit (in this case this has not happened in Update() )
+ if( !mpImpl->pPool )
+ {
+ OSL_FAIL( "No Pool in GetAttr()! May be incompatible to drviewsi.cxx ?" );
+ mpImpl->pPool = rAttrs.GetPool();
+ DBG_ASSERT( mpImpl->pPool, "Where is the Pool?" );
+ ePoolUnit = mpImpl->pPool->GetMetric( SID_ATTR_LINE_WIDTH );
+
+ eFUnit = GetModuleFieldUnit( rAttrs );
+ }
+
+ // Number of segments (horizontal)
+ if( !m_xNumHorizontal->get_text().isEmpty() )
+ {
+ sal_uInt32 nValue = static_cast<sal_uInt32>(m_xNumHorizontal->get_value());
+ rAttrs.Put(makeSvx3DHorizontalSegmentsItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_HORZ_SEGS);
+
+ // Number of segments (vertical)
+ if( !m_xNumVertical->get_text().isEmpty() )
+ {
+ sal_uInt32 nValue = static_cast<sal_uInt32>(m_xNumVertical->get_value());
+ rAttrs.Put(makeSvx3DVerticalSegmentsItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_VERT_SEGS);
+
+ // Depth
+ if( !m_xMtrDepth->get_text().isEmpty() )
+ {
+ sal_uInt32 nValue = GetCoreValue(*m_xMtrDepth, ePoolUnit);
+ rAttrs.Put(makeSvx3DDepthItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_DEPTH);
+
+ // Double-sided
+ TriState eState = m_xBtnDoubleSided->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = TRISTATE_TRUE == eState;
+ rAttrs.Put(makeSvx3DDoubleSidedItem(bValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_DOUBLE_SIDED);
+
+ // Edge rounding
+ if( !m_xMtrPercentDiagonal->get_text().isEmpty() )
+ {
+ sal_uInt16 nValue = static_cast<sal_uInt16>(m_xMtrPercentDiagonal->get_value(FieldUnit::PERCENT));
+ rAttrs.Put(makeSvx3DPercentDiagonalItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_PERCENT_DIAGONAL);
+
+ // Depth scale
+ if( !m_xMtrBackscale->get_text().isEmpty() )
+ {
+ sal_uInt16 nValue = static_cast<sal_uInt16>(m_xMtrBackscale->get_value(FieldUnit::PERCENT));
+ rAttrs.Put(makeSvx3DBackscaleItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_BACKSCALE);
+
+ // End angle
+ if( !m_xMtrEndAngle->get_text().isEmpty() )
+ {
+ sal_uInt16 nValue = static_cast<sal_uInt16>(m_xMtrEndAngle->get_value(FieldUnit::DEGREE));
+ rAttrs.Put(makeSvx3DEndAngleItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_END_ANGLE);
+
+ // Normal type
+ sal_uInt16 nValue = 99;
+ if( m_xBtnNormalsObj->get_active() )
+ nValue = 0;
+ else if( m_xBtnNormalsFlat->get_active() )
+ nValue = 1;
+ else if( m_xBtnNormalsSphere->get_active() )
+ nValue = 2;
+
+ if( nValue <= 2 )
+ rAttrs.Put(Svx3DNormalsKindItem(nValue));
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_NORMALS_KIND);
+
+ // Normal inverted
+ eState = m_xBtnNormalsInvert->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = TRISTATE_TRUE == eState;
+ rAttrs.Put(makeSvx3DNormalsInvertItem(bValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_NORMALS_INVERT);
+
+ // 2-sided lighting
+ eState = m_xBtnTwoSidedLighting->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = TRISTATE_TRUE == eState;
+ rAttrs.Put(makeSvx3DTwoSidedLightingItem(bValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_TWO_SIDED_LIGHTING);
+
+// Representation
+ // Shade mode
+ if( m_xLbShademode->get_active() != -1 )
+ {
+ nValue = m_xLbShademode->get_active();
+ rAttrs.Put(Svx3DShadeModeItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_SHADE_MODE);
+
+ // 3D-Shadow
+ eState = m_xBtnShadow3d->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = TRISTATE_TRUE == eState;
+ rAttrs.Put(makeSvx3DShadow3DItem(bValue));
+ rAttrs.Put(makeSdrShadowItem(bValue));
+ }
+ else
+ {
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_SHADOW_3D);
+ rAttrs.InvalidateItem(SDRATTR_SHADOW);
+ }
+
+ // Slant (Shadow)
+ if( !m_xMtrSlant->get_text().isEmpty() )
+ {
+ sal_uInt16 nValue2 = static_cast<sal_uInt16>(m_xMtrSlant->get_value(FieldUnit::DEGREE));
+ rAttrs.Put(makeSvx3DShadowSlantItem(nValue2));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_SHADOW_SLANT);
+
+ // Distance
+ if( !m_xMtrDistance->get_text().isEmpty() )
+ {
+ sal_uInt32 nValue2 = GetCoreValue(*m_xMtrDistance, ePoolUnit);
+ rAttrs.Put(makeSvx3DDistanceItem(nValue2));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_DISTANCE);
+
+ // Focal length
+ if( !m_xMtrFocalLength->get_text().isEmpty() )
+ {
+ sal_uInt32 nValue2 = GetCoreValue(*m_xMtrFocalLength, ePoolUnit);
+ rAttrs.Put(makeSvx3DFocalLengthItem(nValue2));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_FOCAL_LENGTH);
+
+ // Lighting
+ Color aColor;
+ const SfxItemSet aLightItemSet(m_xCtlLightPreview->GetSvx3DLightControl().Get3DAttributes());
+
+ // Light 1 color
+ if (!m_xLbLight1->IsNoSelection())
+ {
+ aColor = m_xLbLight1->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor1Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_1);
+ // Light 1 (on/off)
+ eState = m_xBtnLight1->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight1->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff1Item(bValue));
+
+ // Light 1 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_1));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_1);
+
+
+ // Light 2 color
+ if (!m_xLbLight2->IsNoSelection())
+ {
+ aColor = m_xLbLight2->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor2Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_2);
+ // Light 2 (on/off)
+ eState = m_xBtnLight2->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight2->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff2Item(bValue));
+
+ // Light 2 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_2));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_2);
+
+ // Light 3 color
+ if (!m_xLbLight3->IsNoSelection())
+ {
+ aColor = m_xLbLight3->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor3Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_3);
+ // Light 3 (on/off)
+ eState = m_xBtnLight3->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight3->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff3Item(bValue));
+
+ // Light 3 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_3));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_3);
+
+ // Light 4 color
+ if (!m_xLbLight4->IsNoSelection())
+ {
+ aColor = m_xLbLight4->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor4Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_4);
+ // Light 4 (on/off)
+ eState = m_xBtnLight4->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight4->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff4Item(bValue));
+
+ // Light 4 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_4));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_4);
+
+ // Light 5 color
+ if (!m_xLbLight5->IsNoSelection())
+ {
+ aColor = m_xLbLight5->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor5Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_5);
+ // Light 5 (on/off)
+ eState = m_xBtnLight5->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight5->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff5Item(bValue));
+
+ // Light 5 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_5));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_5);
+
+ // Light 6 color
+ if (!m_xLbLight6->IsNoSelection())
+ {
+ aColor = m_xLbLight6->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor6Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_6);
+ // Light 6 (on/off)
+ eState = m_xBtnLight6->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight6->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff6Item(bValue));
+
+ // Light 6 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_6));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_6);
+
+ // Light 7 color
+ if (!m_xLbLight7->IsNoSelection())
+ {
+ aColor = m_xLbLight7->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor7Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_7);
+ // Light 7 (on/off)
+ eState = m_xBtnLight7->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight7->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff7Item(bValue));
+
+ // Light 7 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_7));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_7);
+
+ // Light 8 color
+ if (!m_xLbLight8->IsNoSelection())
+ {
+ aColor = m_xLbLight8->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor8Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_8);
+ // Light 8 (on/off)
+ eState = m_xBtnLight8->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight8->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff8Item(bValue));
+
+ // Light 8 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_8));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_8);
+
+ // Ambient light
+ if (!m_xLbAmbientlight->IsNoSelection())
+ {
+ aColor = m_xLbAmbientlight->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DAmbientcolorItem(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_AMBIENTCOLOR);
+
+// Textures
+ // Art
+ nValue = 99;
+ if( m_xBtnTexLuminance->get_active() )
+ nValue = 1;
+ else if( m_xBtnTexColor->get_active() )
+ nValue = 3;
+
+ if( nValue == 1 || nValue == 3 )
+ rAttrs.Put(Svx3DTextureKindItem(nValue));
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_TEXTURE_KIND);
+
+
+ // Mode
+ nValue = 99;
+ if( m_xBtnTexReplace->get_active() )
+ nValue = 1;
+ else if( m_xBtnTexModulate->get_active() )
+ nValue = 2;
+
+ if( nValue == 1 || nValue == 2 )
+ rAttrs.Put(Svx3DTextureModeItem(nValue));
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_TEXTURE_MODE);
+
+ // X projection
+ nValue = 99;
+ if( m_xBtnTexObjectX->get_active() )
+ nValue = 0;
+ else if( m_xBtnTexParallelX->get_active() )
+ nValue = 1;
+ else if( m_xBtnTexCircleX->get_active() )
+ nValue = 2;
+
+ if( nValue <= 2 )
+ rAttrs.Put(Svx3DTextureProjectionXItem(nValue));
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_TEXTURE_PROJ_X);
+
+ // Y projection
+ nValue = 99;
+ if( m_xBtnTexObjectY->get_active() )
+ nValue = 0;
+ else if( m_xBtnTexParallelY->get_active() )
+ nValue = 1;
+ else if( m_xBtnTexCircleY->get_active() )
+ nValue = 2;
+
+ if( nValue <= 2 )
+ rAttrs.Put(Svx3DTextureProjectionYItem(nValue));
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_TEXTURE_PROJ_Y);
+
+
+ // Filter
+ eState = m_xBtnTexFilter->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = TRISTATE_TRUE == eState;
+ rAttrs.Put(makeSvx3DTextureFilterItem(bValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_TEXTURE_FILTER);
+
+
+// Material
+ // Object color
+ if (!m_xLbMatColor->IsNoSelection())
+ {
+ aColor = m_xLbMatColor->GetSelectEntryColor();
+ rAttrs.Put( XFillColorItem( "", aColor) );
+ }
+ else
+ {
+ rAttrs.InvalidateItem( XATTR_FILLCOLOR );
+ }
+
+ // luminous color
+ if (!m_xLbMatEmission->IsNoSelection())
+ {
+ aColor = m_xLbMatEmission->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DMaterialEmissionItem(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_MAT_EMISSION);
+
+ // Specular
+ if (!m_xLbMatSpecular->IsNoSelection())
+ {
+ aColor = m_xLbMatSpecular->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DMaterialSpecularItem(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_MAT_SPECULAR);
+
+ // Specular intensity
+ if( !m_xMtrMatSpecularIntensity->get_text().isEmpty() )
+ {
+ sal_uInt16 nValue2 = static_cast<sal_uInt16>(m_xMtrMatSpecularIntensity->get_value(FieldUnit::PERCENT));
+ rAttrs.Put(makeSvx3DMaterialSpecularIntensityItem(nValue2));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY);
+}
+
+void Svx3DWin::Resize()
+{
+ Size aWinSize( GetOutputSizePixel() ); // why rSize in Resizing()?
+
+ if( aWinSize.Height() >= GetMinOutputSizePixel().Height() &&
+ aWinSize.Width() >= GetMinOutputSizePixel().Width() )
+ {
+ // Hide
+ m_xBtnUpdate->hide();
+ m_xBtnAssign->hide();
+
+ m_xBtnConvertTo3D->hide();
+ m_xBtnLatheObject->hide();
+ m_xBtnPerspective->hide();
+
+ m_xCtlPreview->Hide();
+ m_xLightPreviewGrid->hide();
+
+ m_xFLGeometrie->hide();
+ m_xFLRepresentation->hide();
+ m_xFLLight->hide();
+ m_xFLTexture->hide();
+ m_xFLMaterial->hide();
+
+ // Show
+ m_xBtnUpdate->show();
+ m_xBtnAssign->show();
+
+ m_xBtnConvertTo3D->show();
+ m_xBtnLatheObject->show();
+ m_xBtnPerspective->show();
+
+ if( m_xBtnGeo->get_active() )
+ ClickViewTypeHdl(*m_xBtnGeo);
+ if( m_xBtnRepresentation->get_active() )
+ ClickViewTypeHdl(*m_xBtnRepresentation);
+ if( m_xBtnLight->get_active() )
+ ClickViewTypeHdl(*m_xBtnLight);
+ if( m_xBtnTexture->get_active() )
+ ClickViewTypeHdl(*m_xBtnTexture);
+ if( m_xBtnMaterial->get_active() )
+ ClickViewTypeHdl(*m_xBtnMaterial);
+ }
+
+ SfxDockingWindow::Resize();
+}
+
+IMPL_LINK_NOARG(Svx3DWin, ClickUpdateHdl, weld::Toggleable&, void)
+{
+ bUpdate = m_xBtnUpdate->get_active();
+
+ if( bUpdate )
+ {
+ SfxDispatcher* pDispatcher = LocalGetDispatcher(pBindings);
+ if (pDispatcher != nullptr)
+ {
+ SfxBoolItem aItem( SID_3D_STATE, true );
+ pDispatcher->ExecuteList(SID_3D_STATE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+ }
+ }
+ else
+ {
+ // Controls can be disabled during certain circumstances
+ }
+}
+
+IMPL_LINK_NOARG(Svx3DWin, ClickAssignHdl, weld::Button&, void)
+{
+ SfxDispatcher* pDispatcher = LocalGetDispatcher(pBindings);
+ if (pDispatcher != nullptr)
+ {
+ SfxBoolItem aItem( SID_3D_ASSIGN, true );
+ pDispatcher->ExecuteList(SID_3D_ASSIGN,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+ }
+}
+
+IMPL_LINK( Svx3DWin, ClickViewTypeHdl, weld::Button&, rBtn, void )
+{
+ // Since the permanent updating of the preview would be too expensive
+ bool bUpdatePreview = m_xBtnLight->get_active();
+
+ m_xBtnGeo->set_active(m_xBtnGeo.get() == &rBtn);
+ m_xBtnRepresentation->set_active(m_xBtnRepresentation.get() == &rBtn);
+ m_xBtnLight->set_active(m_xBtnLight.get() == &rBtn);
+ m_xBtnTexture->set_active(m_xBtnTexture.get() == &rBtn);
+ m_xBtnMaterial->set_active(m_xBtnMaterial.get() == &rBtn);
+
+ if( m_xBtnGeo->get_active() )
+ eViewType = ViewType3D::Geo;
+ if( m_xBtnRepresentation->get_active() )
+ eViewType = ViewType3D::Representation;
+ if( m_xBtnLight->get_active() )
+ eViewType = ViewType3D::Light;
+ if( m_xBtnTexture->get_active() )
+ eViewType = ViewType3D::Texture;
+ if( m_xBtnMaterial->get_active() )
+ eViewType = ViewType3D::Material;
+
+ // Geometry
+ if( eViewType == ViewType3D::Geo )
+ {
+ m_xFLSegments->show();
+ m_xFLGeometrie->show();
+ m_xFLNormals->show();
+ }
+ else
+ {
+ m_xFLSegments->hide();
+ m_xFLGeometrie->hide();
+ m_xFLNormals->hide();
+ }
+
+ // Representation
+ if( eViewType == ViewType3D::Representation )
+ {
+ m_xFLShadow->show();
+ m_xFLCamera->show();
+ m_xFLRepresentation->show();
+ }
+ else
+ {
+ m_xFLShadow->hide();
+ m_xFLCamera->hide();
+ m_xFLRepresentation->hide();
+ }
+
+ // Lighting
+ if( eViewType == ViewType3D::Light )
+ {
+ m_xFLLight->show();
+
+ ColorListBox* pLb = GetCLbByButton();
+ if( pLb )
+ pLb->show();
+
+ m_xLightPreviewGrid->show();
+ m_xCtlPreview->Hide();
+ }
+ else
+ {
+ m_xFLLight->hide();
+
+ if( !m_xCtlPreview->IsVisible() )
+ {
+ m_xCtlPreview->Show();
+ m_xLightPreviewGrid->hide();
+ }
+ }
+
+ // Textures
+ if (eViewType == ViewType3D::Texture)
+ m_xFLTexture->show();
+ else
+ m_xFLTexture->hide();
+
+ // Material
+ if( eViewType == ViewType3D::Material )
+ {
+ m_xFLMatSpecular->show();
+ m_xFLMaterial->show();
+ }
+ else
+ {
+ m_xFLMatSpecular->hide();
+ m_xFLMaterial->hide();
+ }
+ if( bUpdatePreview && !m_xBtnLight->get_active() )
+ UpdatePreview();
+}
+
+IMPL_LINK( Svx3DWin, ClickHdl, weld::Button&, rBtn, void )
+{
+ bool bUpdatePreview = false;
+ sal_uInt16 nSId = 0;
+
+ if( &rBtn == m_xBtnConvertTo3D.get() )
+ {
+ nSId = SID_CONVERT_TO_3D;
+ }
+ else if( &rBtn == m_xBtnLatheObject.get() )
+ {
+ nSId = SID_CONVERT_TO_3D_LATHE_FAST;
+ }
+ // Geometry
+ else if( &rBtn == m_xBtnNormalsObj.get() ||
+ &rBtn == m_xBtnNormalsFlat.get() ||
+ &rBtn == m_xBtnNormalsSphere.get() )
+ {
+ m_xBtnNormalsObj->set_active( &rBtn == m_xBtnNormalsObj.get() );
+ m_xBtnNormalsFlat->set_active( &rBtn == m_xBtnNormalsFlat.get() );
+ m_xBtnNormalsSphere->set_active( &rBtn == m_xBtnNormalsSphere.get() );
+ bUpdatePreview = true;
+ }
+ else if( &rBtn == m_xBtnLight1->get_widget() ||
+ &rBtn == m_xBtnLight2->get_widget() ||
+ &rBtn == m_xBtnLight3->get_widget() ||
+ &rBtn == m_xBtnLight4->get_widget() ||
+ &rBtn == m_xBtnLight5->get_widget() ||
+ &rBtn == m_xBtnLight6->get_widget() ||
+ &rBtn == m_xBtnLight7->get_widget() ||
+ &rBtn == m_xBtnLight8->get_widget() )
+ {
+ // Lighting
+ LightButton* pToggleBtn = GetLbByButton(&rBtn);
+
+ ColorListBox* pLb = GetCLbByButton(pToggleBtn);
+ pLb->show();
+
+ bool bIsChecked = pToggleBtn->get_prev_active();
+
+ if (pToggleBtn != m_xBtnLight1.get() && m_xBtnLight1->get_active())
+ {
+ m_xBtnLight1->set_active( false );
+ m_xBtnLight1->set_prev_active(false);
+ m_xLbLight1->hide();
+ }
+ if (pToggleBtn != m_xBtnLight2.get() && m_xBtnLight2->get_active())
+ {
+ m_xBtnLight2->set_active( false );
+ m_xBtnLight2->set_prev_active(false);
+ m_xLbLight2->hide();
+ }
+ if( pToggleBtn != m_xBtnLight3.get() && m_xBtnLight3->get_active() )
+ {
+ m_xBtnLight3->set_active( false );
+ m_xBtnLight3->set_prev_active(false);
+ m_xLbLight3->hide();
+ }
+ if( pToggleBtn != m_xBtnLight4.get() && m_xBtnLight4->get_active() )
+ {
+ m_xBtnLight4->set_active( false );
+ m_xBtnLight4->set_prev_active(false);
+ m_xLbLight4->hide();
+ }
+ if( pToggleBtn != m_xBtnLight5.get() && m_xBtnLight5->get_active() )
+ {
+ m_xBtnLight5->set_active( false );
+ m_xBtnLight5->set_prev_active(false);
+ m_xLbLight5->hide();
+ }
+ if( pToggleBtn != m_xBtnLight6.get() && m_xBtnLight6->get_active() )
+ {
+ m_xBtnLight6->set_active( false );
+ m_xBtnLight6->set_prev_active(false);
+ m_xLbLight6->hide();
+ }
+ if( pToggleBtn != m_xBtnLight7.get() && m_xBtnLight7->get_active() )
+ {
+ m_xBtnLight7->set_active( false );
+ m_xBtnLight7->set_prev_active(false);
+ m_xLbLight7->hide();
+ }
+ if( pToggleBtn != m_xBtnLight8.get() && m_xBtnLight8->get_active() )
+ {
+ m_xBtnLight8->set_active( false );
+ m_xBtnLight8->set_prev_active(false);
+ m_xLbLight8->hide();
+ }
+
+ //update light button
+ pToggleBtn->set_active(true);
+ pToggleBtn->set_prev_active(true);
+ if (bIsChecked)
+ pToggleBtn->switchLightOn(!pToggleBtn->isLightOn());
+
+ bool bEnable = pToggleBtn->isLightOn();
+ m_xBtnLightColor->set_sensitive( bEnable );
+ pLb->set_sensitive( bEnable );
+
+ ClickLight(*pToggleBtn);
+ bUpdatePreview = true;
+ }
+ // Textures
+ else if( &rBtn == m_xBtnTexLuminance.get() ||
+ &rBtn == m_xBtnTexColor.get() )
+ {
+ m_xBtnTexLuminance->set_active( &rBtn == m_xBtnTexLuminance.get() );
+ m_xBtnTexColor->set_active( &rBtn == m_xBtnTexColor.get() );
+ bUpdatePreview = true;
+ }
+ else if( &rBtn == m_xBtnTexReplace.get() ||
+ &rBtn == m_xBtnTexModulate.get() )
+ {
+ m_xBtnTexReplace->set_active( &rBtn == m_xBtnTexReplace.get() );
+ m_xBtnTexModulate->set_active( &rBtn == m_xBtnTexModulate.get() );
+ bUpdatePreview = true;
+ }
+ else if( &rBtn == m_xBtnTexParallelX.get() ||
+ &rBtn == m_xBtnTexCircleX.get() ||
+ &rBtn == m_xBtnTexObjectX.get() )
+ {
+ m_xBtnTexParallelX->set_active( &rBtn == m_xBtnTexParallelX.get() );
+ m_xBtnTexCircleX->set_active( &rBtn == m_xBtnTexCircleX.get() );
+ m_xBtnTexObjectX->set_active( &rBtn == m_xBtnTexObjectX.get() );
+ bUpdatePreview = true;
+ }
+ else if( &rBtn == m_xBtnTexParallelY.get() ||
+ &rBtn == m_xBtnTexCircleY.get() ||
+ &rBtn == m_xBtnTexObjectY.get() )
+ {
+ m_xBtnTexParallelY->set_active( &rBtn == m_xBtnTexParallelY.get() );
+ m_xBtnTexCircleY->set_active( &rBtn == m_xBtnTexCircleY.get() );
+ m_xBtnTexObjectY->set_active( &rBtn == m_xBtnTexObjectY.get() );
+ bUpdatePreview = true;
+ }
+ else if (&rBtn == m_xBtnShadow3d.get())
+ {
+ m_xFtSlant->set_sensitive( m_xBtnShadow3d->get_active() );
+ m_xMtrSlant->set_sensitive( m_xBtnShadow3d->get_active() );
+ bUpdatePreview = true;
+ }
+ // Other (no groups)
+ else
+ {
+ bUpdatePreview = true;
+ }
+
+ if( nSId > 0 )
+ {
+ SfxDispatcher* pDispatcher = LocalGetDispatcher(pBindings);
+ if (pDispatcher != nullptr)
+ {
+ SfxBoolItem aItem( nSId, true );
+ pDispatcher->ExecuteList(nSId,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+ }
+ }
+ else if( bUpdatePreview )
+ UpdatePreview();
+}
+
+IMPL_LINK( Svx3DWin, ClickColorHdl, weld::Button&, rBtn, void)
+{
+ SvColorDialog aColorDlg;
+ ColorListBox* pLb;
+
+ if( &rBtn == m_xBtnLightColor.get() )
+ pLb = GetCLbByButton();
+ else if( &rBtn == m_xBtnAmbientColor.get() )
+ pLb = m_xLbAmbientlight.get();
+ else if( &rBtn == m_xBtnMatColor.get() )
+ pLb = m_xLbMatColor.get();
+ else if( &rBtn == m_xBtnEmissionColor.get() )
+ pLb = m_xLbMatEmission.get();
+ else // if( &rBtn == m_xBtnSpecularColor.get() )
+ pLb = m_xLbMatSpecular.get();
+
+ Color aColor = pLb->GetSelectEntryColor();
+
+ aColorDlg.SetColor( aColor );
+ if( aColorDlg.Execute(GetFrameWeld()) == RET_OK )
+ {
+ aColor = aColorDlg.GetColor();
+ LBSelectColor(pLb, aColor);
+ SelectColorHdl(*pLb);
+ }
+}
+
+IMPL_LINK( Svx3DWin, SelectHdl, weld::ComboBox&, rListBox, void )
+{
+ bool bUpdatePreview = false;
+
+ // Material
+ if (&rListBox == m_xLbMatFavorites.get())
+ {
+ Color aColObj( COL_WHITE );
+ Color aColEmis( COL_BLACK );
+ Color aColSpec( COL_WHITE );
+ sal_uInt16 nSpecIntens = 20;
+
+ switch( m_xLbMatFavorites->get_active() )
+ {
+ case 1: // Metall
+ {
+ aColObj = Color(230,230,255);
+ aColEmis = Color(10,10,30);
+ aColSpec = Color(200,200,200);
+ nSpecIntens = 20;
+ }
+ break;
+
+ case 2: // Gold
+ {
+ aColObj = Color(230,255,0);
+ aColEmis = Color(51,0,0);
+ aColSpec = Color(255,255,240);
+ nSpecIntens = 20;
+ }
+ break;
+
+ case 3: // Chrome
+ {
+ aColObj = Color(36,117,153);
+ aColEmis = Color(18,30,51);
+ aColSpec = Color(230,230,255);
+ nSpecIntens = 2;
+ }
+ break;
+
+ case 4: // Plastic
+ {
+ aColObj = Color(255,48,57);
+ aColEmis = Color(35,0,0);
+ aColSpec = Color(179,202,204);
+ nSpecIntens = 60;
+ }
+ break;
+
+ case 5: // Wood
+ {
+ aColObj = Color(153,71,1);
+ aColEmis = Color(21,22,0);
+ aColSpec = Color(255,255,153);
+ nSpecIntens = 75;
+ }
+ break;
+ }
+ LBSelectColor( m_xLbMatColor.get(), aColObj );
+ LBSelectColor( m_xLbMatEmission.get(), aColEmis );
+ LBSelectColor( m_xLbMatSpecular.get(), aColSpec );
+ m_xMtrMatSpecularIntensity->set_value(nSpecIntens, FieldUnit::PERCENT);
+
+ bUpdatePreview = true;
+ }
+ else if (&rListBox == m_xLbShademode.get())
+ bUpdatePreview = true;
+
+ if( bUpdatePreview )
+ UpdatePreview();
+}
+
+IMPL_LINK( Svx3DWin, SelectColorHdl, ColorListBox&, rListBox, void )
+{
+ bool bUpdatePreview = false;
+
+ if( &rListBox == m_xLbMatColor.get() ||
+ &rListBox == m_xLbMatEmission.get() ||
+ &rListBox == m_xLbMatSpecular.get() )
+ {
+ m_xLbMatFavorites->set_active( 0 );
+ bUpdatePreview = true;
+ }
+ // Lighting
+ else if( &rListBox == m_xLbAmbientlight.get() )
+ {
+ bUpdatePreview = true;
+ }
+ else if( &rListBox == m_xLbLight1.get() ||
+ &rListBox == m_xLbLight2.get() ||
+ &rListBox == m_xLbLight3.get() ||
+ &rListBox == m_xLbLight4.get() ||
+ &rListBox == m_xLbLight5.get() ||
+ &rListBox == m_xLbLight6.get() ||
+ &rListBox == m_xLbLight7.get() ||
+ &rListBox == m_xLbLight8.get() )
+ {
+ bUpdatePreview = true;
+ }
+
+ if( bUpdatePreview )
+ UpdatePreview();
+}
+
+IMPL_LINK_NOARG( Svx3DWin, ModifyMetricHdl, weld::MetricSpinButton&, void )
+{
+ UpdatePreview();
+}
+
+IMPL_LINK_NOARG( Svx3DWin, ModifySpinHdl, weld::SpinButton&, void )
+{
+ UpdatePreview();
+}
+
+void Svx3DWin::ClickLight(const LightButton& rBtn)
+{
+ sal_uInt16 nLightSource = GetLightSource( &rBtn );
+ ColorListBox* pLb = GetCLbByButton( &rBtn );
+ Color aColor( pLb->GetSelectEntryColor() );
+ SfxItemSet aLightItemSet(m_xCtlLightPreview->GetSvx3DLightControl().Get3DAttributes());
+ const bool bOnOff(rBtn.isLightOn());
+
+ switch(nLightSource)
+ {
+ case 0: aLightItemSet.Put(makeSvx3DLightcolor1Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff1Item(bOnOff)); break;
+ case 1: aLightItemSet.Put(makeSvx3DLightcolor2Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff2Item(bOnOff)); break;
+ case 2: aLightItemSet.Put(makeSvx3DLightcolor3Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff3Item(bOnOff)); break;
+ case 3: aLightItemSet.Put(makeSvx3DLightcolor4Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff4Item(bOnOff)); break;
+ case 4: aLightItemSet.Put(makeSvx3DLightcolor5Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff5Item(bOnOff)); break;
+ case 5: aLightItemSet.Put(makeSvx3DLightcolor6Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff6Item(bOnOff)); break;
+ case 6: aLightItemSet.Put(makeSvx3DLightcolor7Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff7Item(bOnOff)); break;
+ default:
+ case 7: aLightItemSet.Put(makeSvx3DLightcolor8Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff8Item(bOnOff)); break;
+ }
+
+ m_xCtlLightPreview->GetSvx3DLightControl().Set3DAttributes(aLightItemSet);
+ m_xCtlLightPreview->GetSvx3DLightControl().SelectLight(nLightSource);
+ m_xCtlLightPreview->CheckSelection();
+}
+
+IMPL_LINK_NOARG(Svx3DWin, ChangeSelectionCallbackHdl, SvxLightCtl3D*, void)
+{
+ const sal_uInt32 nLight(m_xCtlLightPreview->GetSvx3DLightControl().GetSelectedLight());
+ weld::Button* pBtn = nullptr;
+
+ switch( nLight )
+ {
+ case 0: pBtn = m_xBtnLight1->get_widget(); break;
+ case 1: pBtn = m_xBtnLight2->get_widget(); break;
+ case 2: pBtn = m_xBtnLight3->get_widget(); break;
+ case 3: pBtn = m_xBtnLight4->get_widget(); break;
+ case 4: pBtn = m_xBtnLight5->get_widget(); break;
+ case 5: pBtn = m_xBtnLight6->get_widget(); break;
+ case 6: pBtn = m_xBtnLight7->get_widget(); break;
+ case 7: pBtn = m_xBtnLight8->get_widget(); break;
+ default: break;
+ }
+
+ if (pBtn)
+ ClickHdl(*pBtn);
+ else
+ {
+ // Status: No lamp selected
+ if( m_xBtnLight1->get_active() )
+ {
+ m_xBtnLight1->set_active( false );
+ m_xLbLight1->set_sensitive( false );
+ }
+ else if( m_xBtnLight2->get_active() )
+ {
+ m_xBtnLight2->set_active( false );
+ m_xLbLight2->set_sensitive( false );
+ }
+ else if( m_xBtnLight3->get_active() )
+ {
+ m_xBtnLight3->set_active( false );
+ m_xLbLight3->set_sensitive( false );
+ }
+ else if( m_xBtnLight4->get_active() )
+ {
+ m_xBtnLight4->set_active( false );
+ m_xLbLight4->set_sensitive( false );
+ }
+ else if( m_xBtnLight5->get_active() )
+ {
+ m_xBtnLight5->set_active( false );
+ m_xLbLight5->set_sensitive( false );
+ }
+ else if( m_xBtnLight6->get_active() )
+ {
+ m_xBtnLight6->set_active( false );
+ m_xLbLight6->set_sensitive( false );
+ }
+ else if( m_xBtnLight7->get_active() )
+ {
+ m_xBtnLight7->set_active( false );
+ m_xLbLight7->set_sensitive( false );
+ }
+ else if( m_xBtnLight8->get_active() )
+ {
+ m_xBtnLight8->set_active( false );
+ m_xLbLight8->set_sensitive( false );
+ }
+ m_xBtnLightColor->set_sensitive( false );
+ }
+}
+
+namespace
+{
+ OUString lcl_makeColorName(const Color& rColor)
+ {
+ OUString aStr = SvxResId(RID_SVXFLOAT3D_FIX_R) +
+ OUString::number(rColor.GetRed()) +
+ " " +
+ SvxResId(RID_SVXFLOAT3D_FIX_G) +
+ OUString::number(rColor.GetGreen()) +
+ " " +
+ SvxResId(RID_SVXFLOAT3D_FIX_B) +
+ OUString::number(rColor.GetBlue());
+ return aStr;
+ }
+}
+
+// Method to ensure that the LB is also associated with a color
+void Svx3DWin::LBSelectColor( ColorListBox* pLb, const Color& rColor )
+{
+ pLb->SetNoSelection();
+ pLb->SelectEntry(std::make_pair(rColor, lcl_makeColorName(rColor)));
+}
+
+void Svx3DWin::UpdatePreview()
+{
+ if(!pModel)
+ {
+ pModel.reset(new FmFormModel());
+ }
+
+ // Get Itemset
+ SfxItemSetFixed<SDRATTR_START, SDRATTR_END> aSet( pModel->GetItemPool() );
+
+ // Get Attributes and set the preview
+ GetAttr( aSet );
+ m_xCtlPreview->Set3DAttributes( aSet );
+ m_xCtlLightPreview->GetSvx3DLightControl().Set3DAttributes( aSet );
+}
+
+
+// document is to be reloaded, destroy remembered ItemSet
+void Svx3DWin::DocumentReload()
+{
+ mpRemember2DAttributes.reset();
+}
+
+void Svx3DWin::InitColorLB()
+{
+ // First...
+ Color aColWhite( COL_WHITE );
+ Color aColBlack( COL_BLACK );
+ m_xLbLight1->SelectEntry( aColWhite );
+ m_xLbLight2->SelectEntry( aColWhite );
+ m_xLbLight3->SelectEntry( aColWhite );
+ m_xLbLight4->SelectEntry( aColWhite );
+ m_xLbLight5->SelectEntry( aColWhite );
+ m_xLbLight6->SelectEntry( aColWhite );
+ m_xLbLight7->SelectEntry( aColWhite );
+ m_xLbLight8->SelectEntry( aColWhite );
+ m_xLbAmbientlight->SelectEntry( aColBlack );
+ m_xLbMatColor->SelectEntry( aColWhite );
+ m_xLbMatEmission->SelectEntry( aColBlack );
+ m_xLbMatSpecular->SelectEntry( aColWhite );
+}
+
+sal_uInt16 Svx3DWin::GetLightSource( const LightButton* pBtn ) const
+{
+ sal_uInt16 nLight = 8;
+
+ if (pBtn == m_xBtnLight1.get())
+ nLight = 0;
+ else if (pBtn == m_xBtnLight2.get())
+ nLight = 1;
+ else if( pBtn == m_xBtnLight3.get() )
+ nLight = 2;
+ else if( pBtn == m_xBtnLight4.get() )
+ nLight = 3;
+ else if( pBtn == m_xBtnLight5.get() )
+ nLight = 4;
+ else if( pBtn == m_xBtnLight6.get() )
+ nLight = 5;
+ else if( pBtn == m_xBtnLight7.get() )
+ nLight = 6;
+ else if( pBtn == m_xBtnLight8.get() )
+ nLight = 7;
+
+ return nLight;
+};
+
+ColorListBox* Svx3DWin::GetCLbByButton( const LightButton* pBtn )
+{
+ ColorListBox* pLb = nullptr;
+
+ if( pBtn == nullptr )
+ {
+ if( m_xBtnLight1->get_active() )
+ pLb = m_xLbLight1.get();
+ else if( m_xBtnLight2->get_active() )
+ pLb = m_xLbLight2.get();
+ else if( m_xBtnLight3->get_active() )
+ pLb = m_xLbLight3.get();
+ else if( m_xBtnLight4->get_active() )
+ pLb = m_xLbLight4.get();
+ else if( m_xBtnLight5->get_active() )
+ pLb = m_xLbLight5.get();
+ else if( m_xBtnLight6->get_active() )
+ pLb = m_xLbLight6.get();
+ else if( m_xBtnLight7->get_active() )
+ pLb = m_xLbLight7.get();
+ else if( m_xBtnLight8->get_active() )
+ pLb = m_xLbLight8.get();
+ }
+ else
+ {
+ if( pBtn == m_xBtnLight1.get() )
+ pLb = m_xLbLight1.get();
+ else if (pBtn == m_xBtnLight2.get())
+ pLb = m_xLbLight2.get();
+ else if( pBtn == m_xBtnLight3.get() )
+ pLb = m_xLbLight3.get();
+ else if( pBtn == m_xBtnLight4.get() )
+ pLb = m_xLbLight4.get();
+ else if( pBtn == m_xBtnLight5.get() )
+ pLb = m_xLbLight5.get();
+ else if( pBtn == m_xBtnLight6.get() )
+ pLb = m_xLbLight6.get();
+ else if( pBtn == m_xBtnLight7.get() )
+ pLb = m_xLbLight7.get();
+ else if( pBtn == m_xBtnLight8.get() )
+ pLb = m_xLbLight8.get();
+ }
+ return pLb;
+};
+
+LightButton* Svx3DWin::GetLbByButton( const weld::Button* pBtn )
+{
+ LightButton* pLb = nullptr;
+
+ if( pBtn == m_xBtnLight1->get_widget() )
+ pLb = m_xBtnLight1.get();
+ else if (pBtn == m_xBtnLight2->get_widget() )
+ pLb = m_xBtnLight2.get();
+ else if( pBtn == m_xBtnLight3->get_widget() )
+ pLb = m_xBtnLight3.get();
+ else if( pBtn == m_xBtnLight4->get_widget() )
+ pLb = m_xBtnLight4.get();
+ else if( pBtn == m_xBtnLight5->get_widget() )
+ pLb = m_xBtnLight5.get();
+ else if( pBtn == m_xBtnLight6->get_widget() )
+ pLb = m_xBtnLight6.get();
+ else if( pBtn == m_xBtnLight7->get_widget() )
+ pLb = m_xBtnLight7.get();
+ else if( pBtn == m_xBtnLight8->get_widget() )
+ pLb = m_xBtnLight8.get();
+
+ return pLb;
+};
+
+// Derivation from SfxChildWindow as "containers" for effects
+Svx3DChildWindow::Svx3DChildWindow( vcl::Window* _pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo ) :
+ SfxChildWindow( _pParent, nId )
+{
+ VclPtr<Svx3DWin> pWin = VclPtr<Svx3DWin>::Create( pBindings, this, _pParent );
+ SetWindow(pWin);
+
+ pWin->Initialize( pInfo );
+}
+
+Svx3DCtrlItem::Svx3DCtrlItem( sal_uInt16 _nId,
+ SfxBindings* _pBindings) :
+ SfxControllerItem( _nId, *_pBindings )
+{
+}
+
+
+void Svx3DCtrlItem::StateChangedAtToolBoxControl( sal_uInt16 /*nSId*/,
+ SfxItemState /*eState*/, const SfxPoolItem* /*pItem*/ )
+{
+}
+
+// ControllerItem for Status Slot SID_CONVERT_TO_3D
+
+SvxConvertTo3DItem::SvxConvertTo3DItem(sal_uInt16 _nId, SfxBindings* _pBindings)
+: SfxControllerItem(_nId, *_pBindings),
+ bState(false)
+{
+}
+
+void SvxConvertTo3DItem::StateChangedAtToolBoxControl(sal_uInt16 /*_nId*/, SfxItemState eState, const SfxPoolItem* /*pState*/)
+{
+ bool bNewState = (eState != SfxItemState::DISABLED);
+ if(bNewState != bState)
+ {
+ bState = bNewState;
+ SfxDispatcher* pDispatcher = LocalGetDispatcher(&GetBindings());
+ if (pDispatcher != nullptr)
+ {
+ SfxBoolItem aItem( SID_3D_STATE, true );
+ pDispatcher->ExecuteList(SID_3D_STATE,
+ SfxCallMode::ASYNCHRON|SfxCallMode::RECORD, { &aItem });
+ }
+ }
+}
+
+LightButton::LightButton(std::unique_ptr<weld::ToggleButton> xButton)
+ : m_xButton(std::move(xButton))
+ , m_bLightOn(false)
+ , m_bButtonPrevActive(false)
+{
+ m_xButton->set_from_icon_name(RID_SVXBMP_LAMP_OFF);
+}
+
+void LightButton::switchLightOn(bool bOn)
+{
+ if (m_bLightOn == bOn)
+ return;
+ m_bLightOn = bOn;
+ if (m_bLightOn)
+ m_xButton->set_from_icon_name(RID_SVXBMP_LAMP_ON);
+ else
+ m_xButton->set_from_icon_name(RID_SVXBMP_LAMP_OFF);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/helperhittest3d.cxx b/svx/source/engine3d/helperhittest3d.cxx
new file mode 100644
index 000000000..65ed16af7
--- /dev/null
+++ b/svx/source/engine3d/helperhittest3d.cxx
@@ -0,0 +1,277 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/helperhittest3d.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/svditer.hxx>
+#include <drawinglayer/processor3d/cutfindprocessor3d.hxx>
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <com/sun/star/uno/Sequence.h>
+
+
+using namespace com::sun::star;
+
+namespace {
+
+class ImplPairDephAndObject
+{
+private:
+ const E3dCompoundObject* mpObject;
+ double mfDepth;
+
+public:
+ ImplPairDephAndObject(const E3dCompoundObject* pObject, double fDepth)
+ : mpObject(pObject),
+ mfDepth(fDepth)
+ {}
+
+ // for ::std::sort
+ bool operator<(const ImplPairDephAndObject& rComp) const
+ {
+ return (mfDepth < rComp.mfDepth);
+ }
+
+ // data read access
+ const E3dCompoundObject* getObject() const { return mpObject; }
+};
+
+}
+
+static void getAllHit3DObjectWithRelativePoint(
+ const basegfx::B3DPoint& rFront,
+ const basegfx::B3DPoint& rBack,
+ const E3dCompoundObject& rObject,
+ const drawinglayer::geometry::ViewInformation3D& rObjectViewInformation3D,
+ ::std::vector< basegfx::B3DPoint >& o_rResult,
+ bool bAnyHit)
+{
+ o_rResult.clear();
+
+ if(rFront.equal(rBack))
+ return;
+
+ // rObject is an E3dCompoundObject, so it cannot be a scene (which is an E3dObject)
+ const sdr::contact::ViewContactOfE3d& rVCObject = static_cast< sdr::contact::ViewContactOfE3d& >(rObject.GetViewContact());
+ const drawinglayer::primitive3d::Primitive3DContainer aPrimitives(rVCObject.getViewIndependentPrimitive3DContainer());
+
+ if(aPrimitives.empty())
+ return;
+
+ // make BoundVolume empty and overlapping test for speedup
+ const basegfx::B3DRange aObjectRange(aPrimitives.getB3DRange(rObjectViewInformation3D));
+
+ if(!aObjectRange.isEmpty())
+ {
+ const basegfx::B3DRange aFrontBackRange(rFront, rBack);
+
+ if(aObjectRange.overlaps(aFrontBackRange))
+ {
+ // bound volumes hit, geometric cut tests needed
+ drawinglayer::processor3d::CutFindProcessor aCutFindProcessor(rObjectViewInformation3D, rFront, rBack, bAnyHit);
+ aCutFindProcessor.process(aPrimitives);
+ o_rResult = aCutFindProcessor.getCutPoints();
+ }
+ }
+}
+
+
+E3dScene* fillViewInformation3DForCompoundObject(drawinglayer::geometry::ViewInformation3D& o_rViewInformation3D, const E3dCompoundObject& rCandidate)
+{
+ // Search for root scene (outmost scene) of the 3d object since e.g. in chart, multiple scenes may
+ // be placed between object and outmost scene. On that search, remember the in-between scene's
+ // transformation for the correct complete ObjectTransformation. For historical reasons, the
+ // root scene's own object transformation is part of the scene's ViewTransformation, o do not
+ // add it. For more details, see ViewContactOfE3dScene::createViewInformation3D.
+ E3dScene* pParentScene(rCandidate.getParentE3dSceneFromE3dObject());
+ E3dScene* pRootScene(nullptr);
+ basegfx::B3DHomMatrix aInBetweenSceneMatrix;
+
+ while(pParentScene)
+ {
+ E3dScene* pParentParentScene(pParentScene->getParentE3dSceneFromE3dObject());
+
+ if(pParentParentScene)
+ {
+ // pParentScene is an in-between scene
+ aInBetweenSceneMatrix = pParentScene->GetTransform() * aInBetweenSceneMatrix;
+ }
+ else
+ {
+ // pParentScene is the root scene
+ pRootScene = pParentScene;
+ }
+
+ pParentScene = pParentParentScene;
+ }
+
+ if(pRootScene)
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+
+ if(aInBetweenSceneMatrix.isIdentity())
+ {
+ o_rViewInformation3D = rVCScene.getViewInformation3D();
+ }
+ else
+ {
+ // build new ViewInformation containing all transforms for the candidate
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+
+ o_rViewInformation3D = drawinglayer::geometry::ViewInformation3D(
+ aViewInfo3D.getObjectTransformation() * aInBetweenSceneMatrix,
+ aViewInfo3D.getOrientation(),
+ aViewInfo3D.getProjection(),
+ aViewInfo3D.getDeviceToView(),
+ aViewInfo3D.getViewTime(),
+ aViewInfo3D.getExtendedInformationSequence());
+ }
+ }
+ else
+ {
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ o_rViewInformation3D = drawinglayer::geometry::ViewInformation3D(aEmptyParameters);
+ }
+
+ return pRootScene;
+}
+
+
+void getAllHit3DObjectsSortedFrontToBack(
+ const basegfx::B2DPoint& rPoint,
+ const E3dScene& rScene,
+ ::std::vector< const E3dCompoundObject* >& o_rResult)
+{
+ o_rResult.clear();
+ SdrObjList* pList = rScene.GetSubList();
+
+ if(nullptr == pList || 0 == pList->GetObjCount())
+ return;
+
+ // prepare relative HitPoint. To do so, get the VC of the 3DScene and from there
+ // the Scene's 2D transformation. Multiplying with the inverse transformation
+ // will create a point relative to the 3D scene as unit-2d-object
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(rScene.GetViewContact());
+ basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
+ aInverseSceneTransform.invert();
+ const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * rPoint);
+
+ // check if test point is inside scene's area at all
+ if(!(aRelativePoint.getX() >= 0.0 && aRelativePoint.getX() <= 1.0 && aRelativePoint.getY() >= 0.0 && aRelativePoint.getY() <= 1.0))
+ return;
+
+ SdrObjListIter aIterator(pList, SdrIterMode::DeepNoGroups);
+ ::std::vector< ImplPairDephAndObject > aDepthAndObjectResults;
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+
+ while(aIterator.IsMore())
+ {
+ const E3dCompoundObject* pCandidate = dynamic_cast< const E3dCompoundObject* >(aIterator.Next());
+
+ if(pCandidate)
+ {
+ fillViewInformation3DForCompoundObject(aViewInfo3D, *pCandidate);
+
+ // create HitPoint Front and Back, transform to object coordinates
+ basegfx::B3DHomMatrix aViewToObject(aViewInfo3D.getObjectToView());
+ aViewToObject.invert();
+ const basegfx::B3DPoint aFront(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 0.0));
+ const basegfx::B3DPoint aBack(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 1.0));
+
+ if(!aFront.equal(aBack))
+ {
+ // get all hit points with object
+ ::std::vector< basegfx::B3DPoint > aHitsWithObject;
+ getAllHit3DObjectWithRelativePoint(aFront, aBack, *pCandidate, aViewInfo3D, aHitsWithObject, false);
+
+ for(const basegfx::B3DPoint & a : aHitsWithObject)
+ {
+ const basegfx::B3DPoint aPointInViewCoordinates(aViewInfo3D.getObjectToView() * a);
+ aDepthAndObjectResults.emplace_back(pCandidate, aPointInViewCoordinates.getZ());
+ }
+ }
+ }
+ }
+
+ // fill nRetval
+ const sal_uInt32 nCount(aDepthAndObjectResults.size());
+
+ if(nCount)
+ {
+ // sort aDepthAndObjectResults by depth
+ ::std::sort(aDepthAndObjectResults.begin(), aDepthAndObjectResults.end());
+
+ // copy SdrObject pointers to return result set
+ for(const auto& rResult : aDepthAndObjectResults)
+ {
+ o_rResult.push_back(rResult.getObject());
+ }
+ }
+}
+
+
+bool checkHitSingle3DObject(
+ const basegfx::B2DPoint& rPoint,
+ const E3dCompoundObject& rCandidate)
+{
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+ E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, rCandidate);
+
+ if(pRootScene)
+ {
+ // prepare relative HitPoint. To do so, get the VC of the 3DScene and from there
+ // the Scene's 2D transformation. Multiplying with the inverse transformation
+ // will create a point relative to the 3D scene as unit-2d-object
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+ basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
+ aInverseSceneTransform.invert();
+ const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * rPoint);
+
+ // check if test point is inside scene's area at all
+ if(aRelativePoint.getX() >= 0.0 && aRelativePoint.getX() <= 1.0 && aRelativePoint.getY() >= 0.0 && aRelativePoint.getY() <= 1.0)
+ {
+ // create HitPoint Front and Back, transform to object coordinates
+ basegfx::B3DHomMatrix aViewToObject(aViewInfo3D.getObjectToView());
+ aViewToObject.invert();
+ const basegfx::B3DPoint aFront(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 0.0));
+ const basegfx::B3DPoint aBack(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 1.0));
+
+ if(!aFront.equal(aBack))
+ {
+ // get all hit points with object
+ ::std::vector< basegfx::B3DPoint > aHitsWithObject;
+ getAllHit3DObjectWithRelativePoint(aFront, aBack, rCandidate, aViewInfo3D, aHitsWithObject, true);
+
+ if(!aHitsWithObject.empty())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/helperminimaldepth3d.cxx b/svx/source/engine3d/helperminimaldepth3d.cxx
new file mode 100644
index 000000000..cfcc2c7d1
--- /dev/null
+++ b/svx/source/engine3d/helperminimaldepth3d.cxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "helperminimaldepth3d.hxx"
+#include <drawinglayer/processor3d/baseprocessor3d.hxx>
+#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
+#include <drawinglayer/primitive3d/transformprimitive3d.hxx>
+#include <drawinglayer/primitive3d/polygonprimitive3d.hxx>
+#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx>
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+
+
+namespace drawinglayer::processor3d
+{
+ namespace {
+
+ class MinimalDephInViewExtractor : public BaseProcessor3D
+ {
+ private:
+ // the value which will be fetched as result
+ double mfMinimalDepth;
+
+ // as tooling, the process() implementation takes over API handling and calls this
+ // virtual render method when the primitive implementation is BasePrimitive3D-based.
+ virtual void processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate) override;
+
+ public:
+ explicit MinimalDephInViewExtractor(const geometry::ViewInformation3D& rViewInformation)
+ : BaseProcessor3D(rViewInformation),
+ mfMinimalDepth(DBL_MAX)
+ {}
+
+ // data access
+ double getMinimalDepth() const { return mfMinimalDepth; }
+ };
+
+ }
+
+ void MinimalDephInViewExtractor::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate)
+ {
+ // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch
+ switch(rCandidate.getPrimitive3DID())
+ {
+ case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D :
+ {
+ // transform group. Remember current transformations
+ const primitive3d::TransformPrimitive3D& rPrimitive = static_cast< const primitive3d::TransformPrimitive3D& >(rCandidate);
+ const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D());
+
+ // create new transformation; add new object transform from right side
+ const geometry::ViewInformation3D aNewViewInformation3D(
+ aLastViewInformation3D.getObjectTransformation() * rPrimitive.getTransformation(),
+ aLastViewInformation3D.getOrientation(),
+ aLastViewInformation3D.getProjection(),
+ aLastViewInformation3D.getDeviceToView(),
+ aLastViewInformation3D.getViewTime(),
+ aLastViewInformation3D.getExtendedInformationSequence());
+ updateViewInformation(aNewViewInformation3D);
+
+ // let break down
+ process(rPrimitive.getChildren());
+
+ // restore transformations
+ updateViewInformation(aLastViewInformation3D);
+ break;
+ }
+ case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D :
+ {
+ // PolygonHairlinePrimitive3D
+ const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rCandidate);
+ const basegfx::B3DPolygon& rPolygon = rPrimitive.getB3DPolygon();
+ const sal_uInt32 nCount(rPolygon.count());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const basegfx::B3DPoint aPointInView(getViewInformation3D().getObjectToView() * rPolygon.getB3DPoint(a));
+
+ if(aPointInView.getZ() < mfMinimalDepth)
+ {
+ mfMinimalDepth = aPointInView.getZ();
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D :
+ {
+ // PolyPolygonMaterialPrimitive3D
+ const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rCandidate);
+ const basegfx::B3DPolyPolygon& rPolyPolygon = rPrimitive.getB3DPolyPolygon();
+ const sal_uInt32 nPolyCount(rPolyPolygon.count());
+
+ for(sal_uInt32 a(0); a < nPolyCount; a++)
+ {
+ const basegfx::B3DPolygon& aPolygon(rPolyPolygon.getB3DPolygon(a));
+ const sal_uInt32 nCount(aPolygon.count());
+
+ for(sal_uInt32 b(0); b < nCount; b++)
+ {
+ const basegfx::B3DPoint aPointInView(getViewInformation3D().getObjectToView() * aPolygon.getB3DPoint(b));
+
+ if(aPointInView.getZ() < mfMinimalDepth)
+ {
+ mfMinimalDepth = aPointInView.getZ();
+ }
+ }
+ }
+
+ break;
+ }
+ default :
+ {
+ // process recursively
+ process(rCandidate.get3DDecomposition(getViewInformation3D()));
+ break;
+ }
+ }
+ }
+} // end of namespace
+
+
+// changed to create values using VCs, Primitive3DContainer and ViewInformation3D to allow
+// removal of old 3D bucket geometry. There is one slight difference in the result, it's
+// in [0.0 .. 1.0] for Z-Depth since the scaling of the scene as 2D object is no longer
+// part of the 3D transformations. This could be added since the ViewContactOfE3dScene is
+// given, but is not needed since the permutation of the depth values needs only be correct
+// relative to each other
+
+double getMinimalDepthInViewCoordinates(const E3dCompoundObject& rObject)
+{
+ // this is an E3dCompoundObject, so it cannot be a scene (which is an E3dObject).
+ // Get primitive sequence using VC
+ const sdr::contact::ViewContactOfE3d& rVCObject = static_cast< sdr::contact::ViewContactOfE3d& >(rObject.GetViewContact());
+ const drawinglayer::primitive3d::Primitive3DContainer aPrimitives = rVCObject.getViewIndependentPrimitive3DContainer();
+ double fRetval(DBL_MAX);
+
+ if(!aPrimitives.empty())
+ {
+ const E3dScene* pScene(rObject.getRootE3dSceneFromE3dObject());
+
+ if(pScene)
+ {
+ // get ViewInformation3D from scene using VC
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+
+ // the scene's object transformation is already part of aViewInfo3D.getObjectTransformation()
+ // for historical reasons (see ViewContactOfE3dScene::createViewInformation3D for more info)
+ // and the object's transform is part of aPrimitives (and taken into account when decomposing
+ // to PolygonHairlinePrimitive3D and PolyPolygonMaterialPrimitive3D). The missing part may be
+ // some Scene SdrObjects lying in-between which may need to be added. This is e.g. used in chart,
+ // and generally allowed in 3d scenes and their 3d object hierarchy
+ basegfx::B3DHomMatrix aInBetweenSceneMatrix;
+ E3dScene* pParentScene(rObject.getParentE3dSceneFromE3dObject());
+
+ while(pParentScene && pParentScene != pScene)
+ {
+ aInBetweenSceneMatrix = pParentScene->GetTransform() * aInBetweenSceneMatrix;
+ pParentScene = pParentScene->getParentE3dSceneFromE3dObject();
+ }
+
+ // build new ViewInformation containing all transforms
+ const drawinglayer::geometry::ViewInformation3D aNewViewInformation3D(
+ aViewInfo3D.getObjectTransformation() * aInBetweenSceneMatrix,
+ aViewInfo3D.getOrientation(),
+ aViewInfo3D.getProjection(),
+ aViewInfo3D.getDeviceToView(),
+ aViewInfo3D.getViewTime(),
+ aViewInfo3D.getExtendedInformationSequence());
+
+ // create extractor helper, process geometry and get return value
+ drawinglayer::processor3d::MinimalDephInViewExtractor aExtractor(aNewViewInformation3D);
+ aExtractor.process(aPrimitives);
+ fRetval = aExtractor.getMinimalDepth();
+ }
+ }
+
+ return fRetval;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/helperminimaldepth3d.hxx b/svx/source/engine3d/helperminimaldepth3d.hxx
new file mode 100644
index 000000000..392ba49f6
--- /dev/null
+++ b/svx/source/engine3d/helperminimaldepth3d.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_ENGINE3D_HELPERMINIMALDEPTH3D_HXX
+#define INCLUDED_SVX_SOURCE_ENGINE3D_HELPERMINIMALDEPTH3D_HXX
+
+// predefines
+
+class E3dCompoundObject;
+
+/** support extracting the minimal depth of a 3d object in its scene
+
+ @param rObject
+ The 3D Object from which the minimal depth needs to be calculated. The scene
+ is defined by the object already
+
+ @return
+ The minimal depth of this object in unified ViewCoordinates. This is the
+ Z-Coordinate of one object point in the range of [0.0 .. 1.0]. ViewCoordinates
+ means the transformations (esp. rotation) of the scene are taken into account
+
+*/
+// support extracting the minimal depth of a 3d object in its scene
+
+double getMinimalDepthInViewCoordinates(const E3dCompoundObject& rObject);
+
+#endif // INCLUDED_SVX_SOURCE_ENGINE3D_HELPERMINIMALDEPTH3D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/lathe3d.cxx b/svx/source/engine3d/lathe3d.cxx
new file mode 100644
index 000000000..70a6b7ab0
--- /dev/null
+++ b/svx/source/engine3d/lathe3d.cxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/deflt3d.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svdobjkind.hxx>
+#include <svx/lathe3d.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svx3ditems.hxx>
+#include <svx/xlineit0.hxx>
+#include <sdr/properties/e3dlatheproperties.hxx>
+#include <sdr/contact/viewcontactofe3dlathe.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+
+// DrawContact section
+std::unique_ptr<sdr::contact::ViewContact> E3dLatheObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dLathe>(*this);
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dLatheObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dLatheProperties>(*this);
+}
+
+// Constructor from 3D polygon, scale is the conversion factor for the coordinates
+E3dLatheObj::E3dLatheObj(
+ SdrModel& rSdrModel,
+ const E3dDefaultAttributes& rDefault,
+ const basegfx::B2DPolyPolygon& rPoly2D)
+: E3dCompoundObject(rSdrModel),
+ maPolyPoly2D(rPoly2D)
+{
+ // since the old class PolyPolygon3D did mirror the given PolyPolygons in Y, do the same here
+ basegfx::B2DHomMatrix aMirrorY;
+ aMirrorY.scale(1.0, -1.0);
+ maPolyPoly2D.transform(aMirrorY);
+
+ // Set Defaults
+ SetDefaultAttributes(rDefault);
+
+ // Superfluous items removed, in particular to prevent duplicate
+ // start and end points
+ maPolyPoly2D.removeDoublePoints();
+
+ if(maPolyPoly2D.count())
+ {
+ const basegfx::B2DPolygon rPoly(maPolyPoly2D.getB2DPolygon(0));
+ sal_uInt32 nSegCnt(rPoly.count());
+
+ if(nSegCnt && !rPoly.isClosed())
+ {
+ nSegCnt -= 1;
+ }
+
+ GetProperties().SetObjectItemDirect(makeSvx3DVerticalSegmentsItem(nSegCnt));
+ }
+}
+
+E3dLatheObj::E3dLatheObj(SdrModel& rSdrModel)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set Defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+}
+
+E3dLatheObj::E3dLatheObj(SdrModel& rSdrModel, E3dLatheObj const & rSource)
+: E3dCompoundObject(rSdrModel, rSource)
+{
+ // Set Defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+
+ maPolyPoly2D = rSource.maPolyPoly2D;
+}
+
+E3dLatheObj::~E3dLatheObj()
+{
+}
+
+void E3dLatheObj::SetDefaultAttributes(const E3dDefaultAttributes& rDefault)
+{
+ GetProperties().SetObjectItemDirect(Svx3DSmoothNormalsItem(rDefault.GetDefaultLatheSmoothed()));
+ GetProperties().SetObjectItemDirect(Svx3DSmoothLidsItem(rDefault.GetDefaultLatheSmoothFrontBack()));
+ GetProperties().SetObjectItemDirect(Svx3DCharacterModeItem(rDefault.GetDefaultLatheCharacterMode()));
+ GetProperties().SetObjectItemDirect(Svx3DCloseFrontItem(rDefault.GetDefaultLatheCloseFront()));
+ GetProperties().SetObjectItemDirect(Svx3DCloseBackItem(rDefault.GetDefaultLatheCloseBack()));
+}
+
+SdrObjKind E3dLatheObj::GetObjIdentifier() const
+{
+ return SdrObjKind::E3D_Lathe;
+}
+
+E3dLatheObj* E3dLatheObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new E3dLatheObj(rTargetModel, *this);
+}
+
+// Convert the object to group object consisting of n polygons
+
+SdrObjectUniquePtr E3dLatheObj::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
+{
+ return nullptr;
+}
+
+// Set Local parameters set to re-create geometry
+
+void E3dLatheObj::SetPolyPoly2D(const basegfx::B2DPolyPolygon& rNew)
+{
+ if(maPolyPoly2D == rNew)
+ return;
+
+ maPolyPoly2D = rNew;
+ maPolyPoly2D.removeDoublePoints();
+
+ if(maPolyPoly2D.count())
+ {
+ const basegfx::B2DPolygon rPoly(maPolyPoly2D.getB2DPolygon(0));
+ sal_uInt32 nSegCnt(rPoly.count());
+
+ if(nSegCnt && !rPoly.isClosed())
+ {
+ nSegCnt -= 1;
+ }
+
+ GetProperties().SetObjectItemDirect(makeSvx3DVerticalSegmentsItem(nSegCnt));
+ }
+
+ ActionChanged();
+}
+
+// Get the name of the object (singular)
+
+OUString E3dLatheObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulLathe3d));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName += " '" + aName + "'";
+ }
+ return sName;
+}
+
+// Get the name of the object (plural)
+
+OUString E3dLatheObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralLathe3d);
+}
+
+bool E3dLatheObj::IsBreakObjPossible()
+{
+ return true;
+}
+
+std::unique_ptr<SdrAttrObj,SdrObjectFreeOp> E3dLatheObj::GetBreakObj()
+{
+ // create PathObj
+ basegfx::B3DPolyPolygon aLathePoly3D(basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon(maPolyPoly2D));
+ basegfx::B2DPolyPolygon aTransPoly(TransformToScreenCoor(aLathePoly3D));
+ std::unique_ptr<SdrPathObj,SdrObjectFreeOp> pPathObj(new SdrPathObj(getSdrModelFromSdrObject(), SdrObjKind::PolyLine, aTransPoly));
+
+ // Set Attribute
+ SfxItemSet aSet(GetObjectItemSet());
+
+ // Enable lines to guarantee that the object becomes visible
+ aSet.Put(XLineStyleItem(css::drawing::LineStyle_SOLID));
+
+ pPathObj->SetMergedItemSet(aSet);
+
+ return std::unique_ptr<SdrAttrObj,SdrObjectFreeOp>(pPathObj.release());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/obj3d.cxx b/svx/source/engine3d/obj3d.cxx
new file mode 100644
index 000000000..692e3d757
--- /dev/null
+++ b/svx/source/engine3d/obj3d.cxx
@@ -0,0 +1,617 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <o3tl/numeric.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdobjkind.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/obj3d.hxx>
+#include <sdr/properties/e3dproperties.hxx>
+#include <sdr/properties/e3dcompoundproperties.hxx>
+#include <basegfx/polygon/b3dpolypolygontools.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/helperhittest3d.hxx>
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+#include <com/sun/star/uno/Sequence.h>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/e3dsceneupdater.hxx>
+#include <unotools/configmgr.hxx>
+
+using namespace com::sun::star;
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dObject::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dProperties>(*this);
+}
+
+E3dObject::E3dObject(SdrModel& rSdrModel)
+: SdrAttrObj(rSdrModel),
+ mbTfHasChanged(true),
+ mbIsSelected(false)
+{
+ m_bIs3DObj = true;
+ m_bClosedObj = true;
+}
+
+E3dObject::E3dObject(SdrModel& rSdrModel, E3dObject const & rSource)
+: SdrAttrObj(rSdrModel, rSource),
+ mbTfHasChanged(true),
+ mbIsSelected(false)
+{
+ m_bIs3DObj = true;
+ m_bClosedObj = true;
+
+ // BoundVol can be copied since also the children are copied
+ maLocalBoundVol = rSource.maLocalBoundVol;
+ maTransformation = rSource.maTransformation;
+
+ // Because the parent may have changed, definitely redefine the total
+ // transformation next time
+ SetTransformChanged();
+
+ // Copy selection status
+ mbIsSelected = rSource.mbIsSelected;
+}
+
+E3dObject::~E3dObject()
+{
+}
+
+void E3dObject::SetSelected(bool bNew)
+{
+ if(mbIsSelected != bNew)
+ {
+ mbIsSelected = bNew;
+ }
+}
+
+// Break, default implementations
+bool E3dObject::IsBreakObjPossible()
+{
+ return false;
+}
+
+std::unique_ptr<SdrAttrObj,SdrObjectFreeOp> E3dObject::GetBreakObj()
+{
+ return nullptr;
+}
+
+SdrInventor E3dObject::GetObjInventor() const
+{
+ return SdrInventor::E3d;
+}
+
+SdrObjKind E3dObject::GetObjIdentifier() const
+{
+ return SdrObjKind::E3D_Object;
+}
+
+// Determine the capabilities of the object
+void E3dObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bResizeFreeAllowed = true;
+ rInfo.bResizePropAllowed = true;
+ rInfo.bRotateFreeAllowed = true;
+ rInfo.bRotate90Allowed = true;
+ rInfo.bMirrorFreeAllowed = false;
+ rInfo.bMirror45Allowed = false;
+ rInfo.bMirror90Allowed = false;
+ rInfo.bShearAllowed = false;
+ rInfo.bEdgeRadiusAllowed = false;
+ rInfo.bCanConvToPath = false;
+
+ // no transparence for 3d objects
+ rInfo.bTransparenceAllowed = false;
+
+ // Convert 3D objects in a group of polygons:
+ // At first not only possible, because the creation of a group of
+ // 2D polygons would be required which need to be sorted by depth,
+ // ie at intersections be cut relative to each other. Also the texture
+ // coordinates were an unsolved problem.
+ rInfo.bCanConvToPoly = false;
+ rInfo.bCanConvToContour = false;
+ rInfo.bCanConvToPathLineToArea = false;
+ rInfo.bCanConvToPolyLineToArea = false;
+}
+
+// resize object, used from old 2d interfaces, e.g. in Move/Scale dialog (F4)
+void E3dObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ // Movement in X, Y in the eye coordinate system
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr == pScene)
+ {
+ return;
+ }
+
+ // transform pos from 2D world to 3D eye
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ basegfx::B2DPoint aScaleCenter2D(static_cast<double>(rRef.X()), static_cast<double>(rRef.Y()));
+ basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
+
+ aInverseSceneTransform.invert();
+ aScaleCenter2D = aInverseSceneTransform * aScaleCenter2D;
+
+ basegfx::B3DPoint aScaleCenter3D(aScaleCenter2D.getX(), aScaleCenter2D.getY(), 0.5);
+ basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
+
+ aInverseViewToEye.invert();
+ aScaleCenter3D = aInverseViewToEye * aScaleCenter3D;
+
+ // Get scale factors
+ double fScaleX(xFact);
+ double fScaleY(yFact);
+
+ // build transform
+ basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
+ aInverseOrientation.invert();
+ basegfx::B3DHomMatrix aFullTransform(GetFullTransform());
+ basegfx::B3DHomMatrix aTrans(aFullTransform);
+
+ aTrans *= aViewInfo3D.getOrientation();
+ aTrans.translate(-aScaleCenter3D.getX(), -aScaleCenter3D.getY(), -aScaleCenter3D.getZ());
+ aTrans.scale(fScaleX, fScaleY, 1.0);
+ aTrans.translate(aScaleCenter3D.getX(), aScaleCenter3D.getY(), aScaleCenter3D.getZ());
+ aTrans *= aInverseOrientation;
+ aFullTransform.invert();
+ aTrans *= aFullTransform;
+
+ // Apply
+ basegfx::B3DHomMatrix aObjTrans(GetTransform());
+ aObjTrans *= aTrans;
+
+ E3DModifySceneSnapRectUpdater aUpdater(this);
+ SetTransform(aObjTrans);
+}
+
+// Move object in 2D is needed when using cursor keys
+void E3dObject::NbcMove(const Size& rSize)
+{
+ // Movement in X, Y in the eye coordinate system
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr == pScene)
+ {
+ return;
+ }
+
+ //Dimensions of the scene in 3D and 2D for comparison
+ tools::Rectangle aRect = pScene->GetSnapRect();
+ basegfx::B3DHomMatrix aInvDispTransform;
+ E3dScene* pParent(getParentE3dSceneFromE3dObject());
+
+ if(nullptr != pParent)
+ {
+ aInvDispTransform = pParent->GetFullTransform();
+ aInvDispTransform.invert();
+ }
+
+ // BoundVolume from 3d world to 3d eye
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ basegfx::B3DRange aEyeVol(pScene->GetBoundVolume());
+ aEyeVol.transform(aViewInfo3D.getOrientation());
+
+ if ((aRect.GetWidth() == 0) || (aRect.GetHeight() == 0))
+ throw o3tl::divide_by_zero();
+
+ // build relative movement vector in eye coordinates
+ basegfx::B3DPoint aMove(
+ static_cast<double>(rSize.Width()) * aEyeVol.getWidth() / static_cast<double>(aRect.GetWidth()),
+ static_cast<double>(-rSize.Height()) * aEyeVol.getHeight() / static_cast<double>(aRect.GetHeight()),
+ 0.0);
+ basegfx::B3DPoint aPos(0.0, 0.0, 0.0);
+
+ // movement vector to local coordinates of objects' parent
+ basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
+ aInverseOrientation.invert();
+ basegfx::B3DHomMatrix aCompleteTrans(aInvDispTransform * aInverseOrientation);
+
+ aMove = aCompleteTrans * aMove;
+ aPos = aCompleteTrans * aPos;
+
+ // build transformation and apply
+ basegfx::B3DHomMatrix aTranslate;
+ aTranslate.translate(aMove.getX() - aPos.getX(), aMove.getY() - aPos.getY(), aMove.getZ() - aPos.getZ());
+
+ E3DModifySceneSnapRectUpdater aUpdater(pScene);
+ SetTransform(aTranslate * GetTransform());
+}
+
+void E3dObject::RecalcSnapRect()
+{
+ maSnapRect = tools::Rectangle();
+}
+
+// Inform parent of changes in the structure (eg by transformation), in this
+// process the object in which the change has occurred is returned.
+void E3dObject::StructureChanged()
+{
+ E3dScene* pParent(getParentE3dSceneFromE3dObject());
+
+ if(nullptr != pParent)
+ {
+ pParent->InvalidateBoundVolume();
+ pParent->StructureChanged();
+ }
+}
+
+E3dScene* E3dObject::getParentE3dSceneFromE3dObject() const
+{
+ return dynamic_cast< E3dScene* >(getParentSdrObjectFromSdrObject());
+}
+
+// Determine the top-level scene object
+E3dScene* E3dObject::getRootE3dSceneFromE3dObject() const
+{
+ E3dScene* pParent(getParentE3dSceneFromE3dObject());
+
+ if(nullptr != pParent)
+ {
+ return pParent->getRootE3dSceneFromE3dObject();
+ }
+
+ return nullptr;
+}
+
+// Calculate enclosed volume, including all child objects
+basegfx::B3DRange E3dObject::RecalcBoundVolume() const
+{
+ basegfx::B3DRange aRetval;
+ if (utl::ConfigManager::IsFuzzing()) // skip slow path for fuzzing
+ return aRetval;
+
+ const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
+
+ if(pVCOfE3D)
+ {
+ // BoundVolume is without 3D object transformation, use correct sequence
+ const drawinglayer::primitive3d::Primitive3DContainer& xLocalSequence(pVCOfE3D->getVIP3DSWithoutObjectTransform());
+
+ if(!xLocalSequence.empty())
+ {
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ const drawinglayer::geometry::ViewInformation3D aLocalViewInformation3D(aEmptyParameters);
+
+ aRetval = xLocalSequence.getB3DRange(aLocalViewInformation3D);
+ }
+ }
+
+ return aRetval;
+}
+
+// Get enclosed volume and possibly recalculate it
+const basegfx::B3DRange& E3dObject::GetBoundVolume() const
+{
+ if(maLocalBoundVol.isEmpty())
+ {
+ const_cast< E3dObject* >(this)->maLocalBoundVol = RecalcBoundVolume();
+ }
+
+ return maLocalBoundVol;
+}
+
+void E3dObject::InvalidateBoundVolume()
+{
+ maLocalBoundVol.reset();
+}
+
+// Pass on the changes in transformation to all child objects
+void E3dObject::SetTransformChanged()
+{
+ InvalidateBoundVolume();
+ mbTfHasChanged = true;
+}
+
+// Define the hierarchical transformation over all Parents, store in
+// maFullTransform and return them
+const basegfx::B3DHomMatrix& E3dObject::GetFullTransform() const
+{
+ if(mbTfHasChanged)
+ {
+ basegfx::B3DHomMatrix aNewFullTransformation(maTransformation);
+ E3dScene* pParent(getParentE3dSceneFromE3dObject());
+
+ if(nullptr != pParent)
+ {
+ aNewFullTransformation = pParent->GetFullTransform() * aNewFullTransformation;
+ }
+
+ const_cast< E3dObject* >(this)->maFullTransform = aNewFullTransformation;
+ const_cast< E3dObject* >(this)->mbTfHasChanged = false;
+ }
+
+ return maFullTransform;
+}
+
+void E3dObject::NbcSetTransform(const basegfx::B3DHomMatrix& rMatrix)
+{
+ if(maTransformation != rMatrix)
+ {
+ maTransformation = rMatrix;
+ SetTransformChanged();
+ StructureChanged();
+ }
+}
+
+// Set transformation matrix with repaint broadcast
+void E3dObject::SetTransform(const basegfx::B3DHomMatrix& rMatrix)
+{
+ if(rMatrix != maTransformation)
+ {
+ NbcSetTransform(rMatrix);
+ SetChanged();
+ BroadcastObjectChange();
+ if (m_pUserCall != nullptr) m_pUserCall->Changed(*this, SdrUserCallType::Resize, tools::Rectangle());
+ }
+}
+
+basegfx::B3DPolyPolygon E3dObject::CreateWireframe() const
+{
+ const basegfx::B3DRange aBoundVolume(GetBoundVolume());
+ return basegfx::utils::createCubePolyPolygonFromB3DRange(aBoundVolume);
+}
+
+// Get the name of the object (singular)
+OUString E3dObject::TakeObjNameSingul() const
+{
+ OUString sName = SvxResId(STR_ObjNameSingulObj3d);
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName += " '" + aName + "'";
+ }
+ return sName;
+}
+
+// Get the name of the object (plural)
+OUString E3dObject::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralObj3d);
+}
+
+E3dObject* E3dObject::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new E3dObject(rTargetModel, *this);
+}
+
+std::unique_ptr<SdrObjGeoData> E3dObject::NewGeoData() const
+{
+ return std::make_unique<E3DObjGeoData>();
+}
+
+void E3dObject::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrAttrObj::SaveGeoData (rGeo);
+
+ static_cast<E3DObjGeoData &>(rGeo).maLocalBoundVol = maLocalBoundVol;
+ static_cast<E3DObjGeoData &>(rGeo).maTransformation = maTransformation;
+}
+
+void E3dObject::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ maLocalBoundVol = static_cast<const E3DObjGeoData &>(rGeo).maLocalBoundVol;
+ E3DModifySceneSnapRectUpdater aUpdater(this);
+ NbcSetTransform(static_cast<const E3DObjGeoData &>(rGeo).maTransformation);
+ SdrAttrObj::RestoreGeoData (rGeo);
+}
+
+// 2D-rotation of a 3D-body, normally this is done by the scene itself.
+// This is however a correct implementation, because everything that has
+// happened is a rotation around the axis perpendicular to the screen and that
+// is regardless of how the scene has been rotated up until now.
+void E3dObject::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ // So currently the gluepoints are defined relative to the scene aOutRect.
+ // Before turning the gluepoints are defined relative to the page. They
+ // take no part in the rotation of the scene. To ensure this, there is the
+ // SetGlueReallyAbsolute(sal_True);
+ double fAngleInRad = toRadians(nAngle);
+
+ basegfx::B3DHomMatrix aRotateZ;
+ aRotateZ.rotate(0.0, 0.0, fAngleInRad);
+ NbcSetTransform(aRotateZ * GetTransform());
+
+ SetBoundAndSnapRectsDirty(); // This forces a recalculation of all BoundRects
+ NbcRotateGluePoints(rRef,nAngle,sn,cs); // Rotate the gluepoints (who still
+ // have coordinates relative to the
+ // original page)
+ SetGlueReallyAbsolute(false); // from now they are again relative to BoundRect (that is defined as aOutRect)
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dCompoundObject::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dCompoundProperties>(*this);
+}
+
+E3dCompoundObject::E3dCompoundObject(SdrModel& rSdrModel)
+: E3dObject(rSdrModel)
+{
+}
+
+E3dCompoundObject::E3dCompoundObject(SdrModel& rSdrModel, E3dCompoundObject const & rSource)
+: E3dObject(rSdrModel, rSource)
+{
+}
+
+E3dCompoundObject::~E3dCompoundObject ()
+{
+}
+
+basegfx::B2DPolyPolygon E3dCompoundObject::TakeXorPoly() const
+{
+ basegfx::B2DPolyPolygon aRetval;
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+ E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
+
+ if(pRootScene)
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+ const basegfx::B3DPolyPolygon aCubePolyPolygon(CreateWireframe());
+ aRetval = basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aCubePolyPolygon,
+ aViewInfo3D.getObjectToView() * GetTransform());
+ aRetval.transform(rVCScene.getObjectTransformation());
+ }
+
+ return aRetval;
+}
+
+sal_uInt32 E3dCompoundObject::GetHdlCount() const
+{
+ // 8 corners + 1 E3dVolumeMarker (= Wireframe representation)
+ return 9;
+}
+
+void E3dCompoundObject::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+ E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
+
+ if(pRootScene)
+ {
+ const basegfx::B3DRange aBoundVolume(GetBoundVolume());
+
+ if(!aBoundVolume.isEmpty())
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+
+ for(sal_uInt32 a(0); a < 8; a++)
+ {
+ basegfx::B3DPoint aPos3D;
+
+ switch(a)
+ {
+ case 0 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
+ case 1 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
+ case 2 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
+ case 3 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
+ case 4 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
+ case 5 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
+ case 6 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
+ case 7 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
+ }
+
+ // to 3d view coor
+ aPos3D *= aViewInfo3D.getObjectToView() * GetTransform();
+
+ // create 2d relative scene
+ basegfx::B2DPoint aPos2D(aPos3D.getX(), aPos3D.getY());
+
+ // to 2d world coor
+ aPos2D *= rVCScene.getObjectTransformation();
+
+ rHdlList.AddHdl(std::make_unique<SdrHdl>(Point(basegfx::fround(aPos2D.getX()), basegfx::fround(aPos2D.getY())), SdrHdlKind::BezierWeight));
+ }
+ }
+ }
+
+ const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());
+
+ if(aPolyPolygon.count())
+ {
+ rHdlList.AddHdl(std::make_unique<E3dVolumeMarker>(aPolyPolygon));
+ }
+}
+
+SdrObjKind E3dCompoundObject::GetObjIdentifier() const
+{
+ return SdrObjKind::E3D_CompoundObject;
+}
+
+void E3dCompoundObject::RecalcSnapRect()
+{
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+ E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
+ maSnapRect = tools::Rectangle();
+
+ if(!pRootScene)
+ return;
+
+ // get VC of 3D candidate
+ const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
+
+ if(!pVCOfE3D)
+ return;
+
+ // get 3D primitive sequence
+ const drawinglayer::primitive3d::Primitive3DContainer xLocalSequence(pVCOfE3D->getViewIndependentPrimitive3DContainer());
+
+ if(xLocalSequence.empty())
+ return;
+
+ // get BoundVolume
+ basegfx::B3DRange aBoundVolume(xLocalSequence.getB3DRange(aViewInfo3D));
+
+ // transform bound volume to relative scene coordinates
+ aBoundVolume.transform(aViewInfo3D.getObjectToView());
+
+ // build 2d relative scene range
+ basegfx::B2DRange aSnapRange(
+ aBoundVolume.getMinX(), aBoundVolume.getMinY(),
+ aBoundVolume.getMaxX(), aBoundVolume.getMaxY());
+
+ // transform to 2D world coordinates
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+ aSnapRange.transform(rVCScene.getObjectTransformation());
+
+ // snap to integer
+ maSnapRect = tools::Rectangle(
+ sal_Int32(floor(aSnapRange.getMinX())), sal_Int32(floor(aSnapRange.getMinY())),
+ sal_Int32(ceil(aSnapRange.getMaxX())), sal_Int32(ceil(aSnapRange.getMaxY())));
+}
+
+E3dCompoundObject* E3dCompoundObject::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new E3dCompoundObject(rTargetModel, *this);
+}
+
+// convert given basegfx::B3DPolyPolygon to screen coor
+basegfx::B2DPolyPolygon E3dCompoundObject::TransformToScreenCoor(const basegfx::B3DPolyPolygon& rCandidate) const
+{
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+ E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
+ basegfx::B2DPolyPolygon aRetval;
+
+ if(pRootScene)
+ {
+ aRetval = basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(rCandidate,
+ aViewInfo3D.getObjectToView() * GetTransform());
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+ aRetval.transform(rVCScene.getObjectTransformation());
+ }
+
+ return aRetval;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/objfac3d.cxx b/svx/source/engine3d/objfac3d.cxx
new file mode 100644
index 000000000..4153ffab5
--- /dev/null
+++ b/svx/source/engine3d/objfac3d.cxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdobjkind.hxx>
+#include <svx/cube3d.hxx>
+#include <svx/sphere3d.hxx>
+#include <extrud3d.hxx>
+#include <svx/lathe3d.hxx>
+#include <polygn3d.hxx>
+#include <svx/objfac3d.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/scene3d.hxx>
+
+static bool bInit = false;
+
+E3dObjFactory::E3dObjFactory()
+{
+ if ( !bInit )
+ {
+ SdrObjFactory::InsertMakeObjectHdl(LINK(this, E3dObjFactory, MakeObject));
+ bInit = true;
+ }
+}
+
+// Generate chart internal objects
+
+IMPL_STATIC_LINK( E3dObjFactory, MakeObject, SdrObjCreatorParams, aParams, SdrObject* )
+{
+ if ( aParams.nInventor == SdrInventor::E3d )
+ {
+ switch ( aParams.nObjIdentifier )
+ {
+ case SdrObjKind::E3D_Scene:
+ return new E3dScene(aParams.rSdrModel);
+ case SdrObjKind::E3D_Polygon :
+ return new E3dPolygonObj(aParams.rSdrModel);
+ case SdrObjKind::E3D_Cube :
+ return new E3dCubeObj(aParams.rSdrModel);
+ case SdrObjKind::E3D_Sphere:
+ return new E3dSphereObj(aParams.rSdrModel);
+ case SdrObjKind::E3D_Extrusion:
+ return new E3dExtrudeObj(aParams.rSdrModel);
+ case SdrObjKind::E3D_Lathe:
+ return new E3dLatheObj(aParams.rSdrModel);
+ case SdrObjKind::E3D_CompoundObject:
+ return new E3dCompoundObject(aParams.rSdrModel);
+ default:
+ break;
+ }
+ }
+ return nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/polygn3d.cxx b/svx/source/engine3d/polygn3d.cxx
new file mode 100644
index 000000000..e7a5623bf
--- /dev/null
+++ b/svx/source/engine3d/polygn3d.cxx
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <polygn3d.hxx>
+#include <svx/svdobjkind.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <sdr/contact/viewcontactofe3dpolygon.hxx>
+#include <basegfx/polygon/b3dpolygon.hxx>
+#include <basegfx/polygon/b3dpolygontools.hxx>
+
+// DrawContact section
+std::unique_ptr<sdr::contact::ViewContact> E3dPolygonObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dPolygon>(*this);
+}
+
+E3dPolygonObj::E3dPolygonObj(SdrModel& rSdrModel, const basegfx::B3DPolyPolygon& rPolyPoly3D)
+ : E3dCompoundObject(rSdrModel)
+ , bLineOnly(true)
+{
+ // Set geometry
+ SetPolyPolygon3D(rPolyPoly3D);
+
+ // Create default normals
+ CreateDefaultNormals();
+
+ // Create default texture coordinates
+ CreateDefaultTexture();
+}
+
+E3dPolygonObj::E3dPolygonObj(SdrModel& rSdrModel)
+ : E3dCompoundObject(rSdrModel)
+ , bLineOnly(false)
+{
+ // Create no geometry
+}
+
+E3dPolygonObj::E3dPolygonObj(SdrModel& rSdrModel, E3dPolygonObj const& rSource)
+ : E3dCompoundObject(rSdrModel, rSource)
+ , bLineOnly(false)
+{
+ // Create no geometry
+
+ aPolyPoly3D = rSource.aPolyPoly3D;
+ aPolyNormals3D = rSource.aPolyNormals3D;
+ aPolyTexture2D = rSource.aPolyTexture2D;
+ bLineOnly = rSource.bLineOnly;
+}
+
+void E3dPolygonObj::CreateDefaultNormals()
+{
+ basegfx::B3DPolyPolygon aPolyNormals;
+
+ // Create a complete tools::PolyPolygon with the plane normal
+ for (sal_uInt32 a(0); a < aPolyPoly3D.count(); a++)
+ {
+ // Find source polygon
+ const basegfx::B3DPolygon aPolygon(aPolyPoly3D.getB3DPolygon(a));
+
+ // Creating a new polygon for the normal
+ basegfx::B3DPolygon aNormals;
+
+ // Get normal (and invert)
+ basegfx::B3DVector aNormal(-aPolygon.getNormal());
+
+ // Fill new polygon
+ for (sal_uInt32 b(0); b < aPolygon.count(); b++)
+ {
+ aNormals.append(aNormal);
+ }
+
+ // Insert new polygon into the PolyPolygon
+ aPolyNormals.append(aNormals);
+ }
+
+ // Set default normal
+ SetPolyNormals3D(aPolyNormals);
+}
+
+void E3dPolygonObj::CreateDefaultTexture()
+{
+ basegfx::B2DPolyPolygon aPolyTexture;
+ // Create a complete tools::PolyPolygon with the texture coordinates
+ // The texture coordinates extend over X,Y and Z
+ // on the whole extreme values in the range 0.0 .. 1.0
+ for (sal_uInt32 a(0); a < aPolyPoly3D.count(); a++)
+ {
+ // Find source polygon
+ const basegfx::B3DPolygon& aPolygon(aPolyPoly3D.getB3DPolygon(a));
+
+ // Determine the total size of the object
+ basegfx::B3DRange aVolume(basegfx::utils::getRange(aPolygon));
+
+ // Get normal
+ basegfx::B3DVector aNormal(aPolygon.getNormal());
+ aNormal.setX(fabs(aNormal.getX()));
+ aNormal.setY(fabs(aNormal.getY()));
+ aNormal.setZ(fabs(aNormal.getZ()));
+
+ // Decide which coordinates should be used as a source for the mapping
+ sal_uInt16 nSourceMode = 0;
+
+ // Determine the greatest degree of freedom
+ if (aNormal.getX() <= aNormal.getY() || aNormal.getX() <= aNormal.getZ())
+ {
+ if (aNormal.getY() > aNormal.getZ())
+ {
+ // Y is the largest, use X,Z as mapping
+ nSourceMode = 1;
+ }
+ else
+ {
+ // Z is the largest, use X,Y as mapping
+ nSourceMode = 2;
+ }
+ }
+
+ // Create new polygon for texture coordinates
+ basegfx::B2DPolygon aTexture;
+
+ // Fill new polygon
+ for (sal_uInt32 b(0); b < aPolygon.count(); b++)
+ {
+ basegfx::B2DPoint aTex;
+ const basegfx::B3DPoint aCandidate(aPolygon.getB3DPoint(b));
+
+ switch (nSourceMode)
+ {
+ case 0: //Source is Y,Z
+ if (aVolume.getHeight())
+ aTex.setX((aCandidate.getY() - aVolume.getMinY()) / aVolume.getHeight());
+ if (aVolume.getDepth())
+ aTex.setY((aCandidate.getZ() - aVolume.getMinZ()) / aVolume.getDepth());
+ break;
+
+ case 1: // Source is X,Z
+ if (aVolume.getWidth())
+ aTex.setX((aCandidate.getX() - aVolume.getMinX()) / aVolume.getWidth());
+ if (aVolume.getDepth())
+ aTex.setY((aCandidate.getZ() - aVolume.getMinZ()) / aVolume.getDepth());
+ break;
+
+ case 2: // Source is X,Y
+ if (aVolume.getWidth())
+ aTex.setX((aCandidate.getX() - aVolume.getMinX()) / aVolume.getWidth());
+ if (aVolume.getHeight())
+ aTex.setY((aCandidate.getY() - aVolume.getMinY()) / aVolume.getHeight());
+ break;
+ }
+
+ aTexture.append(aTex);
+ }
+
+ // Insert new polygon into the PolyPolygon
+ aPolyTexture.append(aTexture);
+ }
+
+ // Set default Texture coordinates
+ SetPolyTexture2D(aPolyTexture);
+}
+
+E3dPolygonObj::~E3dPolygonObj() {}
+
+SdrObjKind E3dPolygonObj::GetObjIdentifier() const { return SdrObjKind::E3D_Polygon; }
+
+void E3dPolygonObj::SetPolyPolygon3D(const basegfx::B3DPolyPolygon& rNewPolyPoly3D)
+{
+ if (aPolyPoly3D != rNewPolyPoly3D)
+ {
+ // New PolyPolygon; copying
+ aPolyPoly3D = rNewPolyPoly3D;
+
+ // Create new geometry
+ ActionChanged();
+ }
+}
+
+void E3dPolygonObj::SetPolyNormals3D(const basegfx::B3DPolyPolygon& rNewPolyNormals3D)
+{
+ if (aPolyNormals3D != rNewPolyNormals3D)
+ {
+ // New PolyPolygon; copying
+ aPolyNormals3D = rNewPolyNormals3D;
+
+ // Create new geometry
+ ActionChanged();
+ }
+}
+
+void E3dPolygonObj::SetPolyTexture2D(const basegfx::B2DPolyPolygon& rNewPolyTexture2D)
+{
+ if (aPolyTexture2D != rNewPolyTexture2D)
+ {
+ // New PolyPolygon; copying
+ aPolyTexture2D = rNewPolyTexture2D;
+
+ // Create new geometry
+ ActionChanged();
+ }
+}
+
+// Convert the object into a group object consisting of 6 polygons
+
+SdrObjectUniquePtr E3dPolygonObj::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
+{
+ return nullptr;
+}
+
+E3dPolygonObj* E3dPolygonObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new E3dPolygonObj(rTargetModel, *this);
+}
+
+void E3dPolygonObj::SetLineOnly(bool bNew)
+{
+ if (bNew != bLineOnly)
+ {
+ bLineOnly = bNew;
+ ActionChanged();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/scene3d.cxx b/svx/source/engine3d/scene3d.cxx
new file mode 100644
index 000000000..07aa9c718
--- /dev/null
+++ b/svx/source/engine3d/scene3d.cxx
@@ -0,0 +1,898 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstdlib>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svditer.hxx>
+
+#include <svx/svdobjkind.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/svdtrans.hxx>
+#include <sdr/properties/e3dsceneproperties.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/svddrag.hxx>
+#include "helperminimaldepth3d.hxx"
+#include <algorithm>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/e3dsceneupdater.hxx>
+#include <svx/svdmodel.hxx>
+
+namespace {
+
+class ImpRemap3DDepth
+{
+ sal_uInt32 mnOrdNum;
+ double mfMinimalDepth;
+
+ // bit field
+ bool mbIsScene : 1;
+
+public:
+ ImpRemap3DDepth(sal_uInt32 nOrdNum, double fMinimalDepth);
+ explicit ImpRemap3DDepth(sal_uInt32 nOrdNum);
+
+ // for ::std::sort
+ bool operator<(const ImpRemap3DDepth& rComp) const;
+
+ sal_uInt32 GetOrdNum() const { return mnOrdNum; }
+ bool IsScene() const { return mbIsScene; }
+};
+
+}
+
+ImpRemap3DDepth::ImpRemap3DDepth(sal_uInt32 nOrdNum, double fMinimalDepth)
+: mnOrdNum(nOrdNum),
+ mfMinimalDepth(fMinimalDepth),
+ mbIsScene(false)
+{
+}
+
+ImpRemap3DDepth::ImpRemap3DDepth(sal_uInt32 nOrdNum)
+: mnOrdNum(nOrdNum),
+ mfMinimalDepth(0.0),
+ mbIsScene(true)
+{
+}
+
+bool ImpRemap3DDepth::operator<(const ImpRemap3DDepth& rComp) const
+{
+ if(IsScene())
+ {
+ return false;
+ }
+ else
+ {
+ if(rComp.IsScene())
+ {
+ return true;
+ }
+ else
+ {
+ return mfMinimalDepth < rComp.mfMinimalDepth;
+ }
+ }
+}
+
+class Imp3DDepthRemapper
+{
+ std::vector< ImpRemap3DDepth > maVector;
+
+public:
+ explicit Imp3DDepthRemapper(E3dScene const & rScene);
+
+ sal_uInt32 RemapOrdNum(sal_uInt32 nOrdNum) const;
+};
+
+Imp3DDepthRemapper::Imp3DDepthRemapper(E3dScene const & rScene)
+{
+ // only called when rScene.GetSubList() and nObjCount > 1
+ SdrObjList* pList = rScene.GetSubList();
+ const size_t nObjCount(pList->GetObjCount());
+
+ for(size_t a = 0; a < nObjCount; ++a)
+ {
+ SdrObject* pCandidate = pList->GetObj(a);
+
+ if(pCandidate)
+ {
+ if(auto pCompoundObj = dynamic_cast< const E3dCompoundObject*>(pCandidate))
+ {
+ // single 3d object, calc depth
+ const double fMinimalDepth(getMinimalDepthInViewCoordinates(*pCompoundObj));
+ ImpRemap3DDepth aEntry(a, fMinimalDepth);
+ maVector.push_back(aEntry);
+ }
+ else
+ {
+ // scene, use standard entry for scene
+ ImpRemap3DDepth aEntry(a);
+ maVector.push_back(aEntry);
+ }
+ }
+ }
+
+ // now, we need to sort the maVector by its members minimal depth. The
+ // smaller, the nearer to the viewer.
+ ::std::sort(maVector.begin(), maVector.end());
+}
+
+sal_uInt32 Imp3DDepthRemapper::RemapOrdNum(sal_uInt32 nOrdNum) const
+{
+ if(nOrdNum < maVector.size())
+ {
+ nOrdNum = maVector[(maVector.size() - 1) - nOrdNum].GetOrdNum();
+ }
+
+ return nOrdNum;
+}
+
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dScene::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dSceneProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> E3dScene::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dScene>(*this);
+}
+
+
+E3dScene::E3dScene(SdrModel& rSdrModel)
+: E3dObject(rSdrModel),
+ aCamera(basegfx::B3DPoint(0.0, 0.0, 4.0), basegfx::B3DPoint()),
+ bDrawOnlySelected(false),
+ mbSkipSettingDirty(false)
+{
+ // Set defaults
+ SetDefaultAttributes();
+}
+
+E3dScene::E3dScene(SdrModel& rSdrModel, E3dScene const & rSource)
+: E3dObject(rSdrModel, rSource),
+ aCamera(basegfx::B3DPoint(0.0, 0.0, 4.0), basegfx::B3DPoint()),
+ bDrawOnlySelected(false),
+ mbSkipSettingDirty(false)
+{
+ // Set defaults
+ SetDefaultAttributes();
+
+ // copy child SdrObjects
+ if (rSource.GetSubList())
+ {
+ CopyObjects(*rSource.GetSubList());
+
+ // tdf#116979: needed here, we need bSnapRectDirty to be true
+ // which it is after using SdrObject::operator= (see above),
+ // but set to false again using CopyObjects
+ SetBoundAndSnapRectsDirty();
+ }
+
+ // copy local data
+ aCamera = rSource.aCamera;
+ aCameraSet = rSource.aCameraSet;
+ static_cast<sdr::properties::E3dSceneProperties&>(GetProperties()).SetSceneItemsFromCamera();
+ InvalidateBoundVolume();
+ RebuildLists();
+ ImpCleanup3DDepthMapper();
+ GetViewContact().ActionChanged();
+}
+
+void E3dScene::SetDefaultAttributes()
+{
+ // For WIN95/NT turn off the FP-Exceptions
+#if defined(_WIN32)
+ _control87( _MCW_EM, _MCW_EM );
+#endif
+
+ // Set defaults
+ aCamera.SetViewWindow(-2, -2, 4, 4);
+ aCameraSet.SetDeviceRectangle(-2, 2, -2, 2);
+ aCamera.SetDeviceWindow(tools::Rectangle(0, 0, 10, 10));
+ tools::Rectangle aRect(0, 0, 10, 10);
+ aCameraSet.SetViewportRectangle(aRect);
+
+ // set defaults for Camera from ItemPool
+ aCamera.SetProjection(GetPerspective());
+ basegfx::B3DPoint aActualPosition(aCamera.GetPosition());
+ double fNew = GetDistance();
+
+ if(fabs(fNew - aActualPosition.getZ()) > 1.0)
+ {
+ aCamera.SetPosition( basegfx::B3DPoint( aActualPosition.getX(), aActualPosition.getY(), fNew) );
+ }
+
+ fNew = GetFocalLength() / 100.0;
+ aCamera.SetFocalLength(fNew);
+}
+
+E3dScene::~E3dScene()
+{
+ ImpCleanup3DDepthMapper();
+}
+
+SdrPage* E3dScene::getSdrPageFromSdrObjList() const
+{
+ return getSdrPageFromSdrObject();
+}
+
+SdrObject* E3dScene::getSdrObjectFromSdrObjList() const
+{
+ return const_cast< E3dScene* >(this);
+}
+
+SdrObjList* E3dScene::getChildrenOfSdrObject() const
+{
+ return const_cast< E3dScene* >(this);
+}
+
+basegfx::B2DPolyPolygon E3dScene::TakeXorPoly() const
+{
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ const basegfx::B3DPolyPolygon aCubePolyPolygon(CreateWireframe());
+
+ basegfx::B2DPolyPolygon aRetval(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aCubePolyPolygon,
+ aViewInfo3D.getObjectToView()));
+ aRetval.transform(rVCScene.getObjectTransformation());
+
+ return aRetval;
+}
+
+void E3dScene::ImpCleanup3DDepthMapper()
+{
+ mp3DDepthRemapper.reset();
+}
+
+sal_uInt32 E3dScene::RemapOrdNum(sal_uInt32 nNewOrdNum) const
+{
+ if(!mp3DDepthRemapper)
+ {
+ const size_t nObjCount(GetSubList() ? GetSubList()->GetObjCount() : 0);
+
+ if(nObjCount > 1)
+ {
+ mp3DDepthRemapper.reset(new Imp3DDepthRemapper(*this));
+ }
+ }
+
+ if(mp3DDepthRemapper)
+ {
+ return mp3DDepthRemapper->RemapOrdNum(nNewOrdNum);
+ }
+
+ return nNewOrdNum;
+}
+
+SdrObjKind E3dScene::GetObjIdentifier() const
+{
+ return SdrObjKind::E3D_Scene;
+}
+
+void E3dScene::SetBoundRectDirty()
+{
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(pScene == this)
+ {
+ // avoid resetting aOutRect which in case of a 3D scene used as 2d object
+ // is model data,not re-creatable view data
+ }
+ else
+ {
+ // if not the outmost scene it is used as group in 3d, call parent
+ E3dObject::SetBoundRectDirty();
+ }
+}
+
+void E3dScene::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ SetBoundAndSnapRectsDirty();
+ E3dObject::NbcSetSnapRect(rRect);
+ aCamera.SetDeviceWindow(rRect);
+ aCameraSet.SetViewportRectangle(rRect);
+
+ ImpCleanup3DDepthMapper();
+}
+
+void E3dScene::NbcMove(const Size& rSize)
+{
+ tools::Rectangle aNewSnapRect = GetSnapRect();
+ aNewSnapRect.Move(rSize);
+ NbcSetSnapRect(aNewSnapRect);
+}
+
+void E3dScene::NbcResize(const Point& rRef, const Fraction& rXFact,
+ const Fraction& rYFact)
+{
+ tools::Rectangle aNewSnapRect = GetSnapRect();
+ ResizeRect(aNewSnapRect, rRef, rXFact, rYFact);
+ NbcSetSnapRect(aNewSnapRect);
+}
+
+// Set new camera, and thus mark the scene and if possible the bound volume
+// as changed
+
+void E3dScene::SetCamera(const Camera3D& rNewCamera)
+{
+ aCamera = rNewCamera;
+ static_cast<sdr::properties::E3dSceneProperties&>(GetProperties()).SetSceneItemsFromCamera();
+
+ SetBoundAndSnapRectsDirty();
+
+ // Turn off ratio
+ GetCameraSet().SetRatio(0.0);
+
+ // Set Imaging geometry
+ basegfx::B3DPoint aVRP(aCamera.GetViewPoint());
+ basegfx::B3DVector aVPN(aVRP - aCamera.GetVRP());
+ basegfx::B3DVector aVUV(aCamera.GetVUV());
+
+ // use SetViewportValues() to set VRP, VPN and VUV as vectors, too.
+ // Else these values would not be exported/imported correctly.
+ GetCameraSet().SetViewportValues(aVRP, aVPN, aVUV);
+
+ // Set perspective
+ GetCameraSet().SetPerspective(aCamera.GetProjection() == ProjectionType::Perspective);
+ GetCameraSet().SetViewportRectangle(aCamera.GetDeviceWindow());
+
+ ImpCleanup3DDepthMapper();
+}
+
+// Inform parent of changes of a child
+
+void E3dScene::StructureChanged()
+{
+ E3dObject::StructureChanged();
+
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene && !pScene->mbSkipSettingDirty)
+ {
+ SetBoundAndSnapRectsDirty();
+ }
+
+ ImpCleanup3DDepthMapper();
+}
+
+// Determine the overall scene object
+
+E3dScene* E3dScene::getRootE3dSceneFromE3dObject() const
+{
+ E3dScene* pParent(getParentE3dSceneFromE3dObject());
+
+ if(nullptr != pParent)
+ {
+ return pParent->getRootE3dSceneFromE3dObject();
+ }
+
+ return const_cast< E3dScene* >(this);
+}
+
+void E3dScene::removeAllNonSelectedObjects()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(this);
+
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ SdrObject* pObj = GetObj(a);
+
+ if(pObj)
+ {
+ bool bRemoveObject(false);
+
+ if(auto pScene = dynamic_cast<E3dScene*>(pObj))
+ {
+ // iterate over this sub-scene
+ pScene->removeAllNonSelectedObjects();
+
+ // check object count. Empty scenes can be deleted
+ const size_t nObjCount(pScene->GetSubList() ? pScene->GetSubList()->GetObjCount() : 0);
+
+ if(!nObjCount)
+ {
+ // all objects removed, scene can be removed, too
+ bRemoveObject = true;
+ }
+ }
+ else if(auto pCompound = dynamic_cast<E3dCompoundObject*>(pObj))
+ {
+ if(!pCompound->GetSelected())
+ {
+ bRemoveObject = true;
+ }
+ }
+
+ if(bRemoveObject)
+ {
+ NbcRemoveObject(pObj->GetOrdNum());
+ a--;
+ SdrObject::Free(pObj);
+ }
+ }
+ }
+}
+
+E3dScene* E3dScene::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new E3dScene(rTargetModel, *this);
+}
+
+void E3dScene::SuspendReportingDirtyRects()
+{
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ pScene->mbSkipSettingDirty = true;
+ }
+}
+
+void E3dScene::ResumeReportingDirtyRects()
+{
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ pScene->mbSkipSettingDirty = false;
+ }
+}
+
+void E3dScene::SetAllSceneRectsDirty()
+{
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ pScene->SetBoundAndSnapRectsDirty();
+ }
+}
+
+// Rebuild Light- and label- object lists rebuild (after loading, allocation)
+
+void E3dScene::RebuildLists()
+{
+ // first delete
+ const SdrLayerID nCurrLayerID(GetLayer());
+ SdrObjListIter a3DIterator(GetSubList(), SdrIterMode::Flat);
+
+ // then examine all the objects in the scene
+ while(a3DIterator.IsMore())
+ {
+ E3dObject* p3DObj(static_cast< E3dObject* >(a3DIterator.Next()));
+ p3DObj->NbcSetLayer(nCurrLayerID);
+ }
+
+ ImpCleanup3DDepthMapper();
+}
+
+std::unique_ptr<SdrObjGeoData> E3dScene::NewGeoData() const
+{
+ return std::make_unique<E3DSceneGeoData>();
+}
+
+void E3dScene::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ E3dObject::SaveGeoData (rGeo);
+
+ static_cast<E3DSceneGeoData &>(rGeo).aCamera = aCamera;
+}
+
+void E3dScene::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ // #i94832# removed E3DModifySceneSnapRectUpdater here.
+ // It should not be needed, is already part of E3dObject::RestoreGeoData
+ E3dObject::RestoreGeoData (rGeo);
+ SetCamera (static_cast<const E3DSceneGeoData &>(rGeo).aCamera);
+}
+
+// Something was changed in the style sheet, so change scene
+
+void E3dScene::Notify(SfxBroadcaster &rBC, const SfxHint &rHint)
+{
+ SetBoundAndSnapRectsDirty();
+ E3dObject::Notify(rBC, rHint);
+}
+
+void E3dScene::RotateScene (const Point& rRef, double sn, double cs)
+{
+ Point UpperLeft, LowerRight, Center, NewCenter;
+
+ UpperLeft = m_aOutRect.TopLeft();
+ LowerRight = m_aOutRect.BottomRight();
+
+ tools::Long dxOutRectHalf = std::abs(UpperLeft.X() - LowerRight.X());
+ dxOutRectHalf /= 2;
+ tools::Long dyOutRectHalf = std::abs(UpperLeft.Y() - LowerRight.Y());
+ dyOutRectHalf /= 2;
+
+ // Only the center is moved. The corners are moved by NbcMove. For the
+ // rotation a cartesian coordinate system is used in which the pivot
+ // point is the origin, and the y-axis increases upward, the X-axis to
+ // the right. This must be especially noted for the Y-values.
+ // (When considering a flat piece of paper the Y-axis pointing downwards
+ Center.setX( (UpperLeft.X() + dxOutRectHalf) - rRef.X() );
+ Center.setY( -((UpperLeft.Y() + dyOutRectHalf) - rRef.Y()) );
+ // A few special cases has to be dealt with first (n * 90 degrees n integer)
+ if (sn==1.0 && cs==0.0) { // 90deg
+ NewCenter.setX( -Center.Y() );
+ NewCenter.setY( -Center.X() );
+ } else if (sn==0.0 && cs==-1.0) { // 180deg
+ NewCenter.setX( -Center.X() );
+ NewCenter.setY( -Center.Y() );
+ } else if (sn==-1.0 && cs==0.0) { // 270deg
+ NewCenter.setX( Center.Y() );
+ NewCenter.setY( -Center.X() );
+ }
+ else // Here it is rotated to any angle in the mathematically
+ // positive direction!
+ { // xnew = x * cos(alpha) - y * sin(alpha)
+ // ynew = x * sin(alpha) + y * cos(alpha)
+ // Bottom Right is not rotated: the pages of aOutRect must
+ // remain parallel to the coordinate axes.
+ NewCenter.setX( static_cast<tools::Long>(Center.X() * cs - Center.Y() * sn) );
+ NewCenter.setY( static_cast<tools::Long>(Center.X() * sn + Center.Y() * cs) );
+ }
+
+ Size Differenz;
+ Point DiffPoint = NewCenter - Center;
+ Differenz.setWidth( DiffPoint.X() );
+ Differenz.setHeight( -DiffPoint.Y() ); // Note that the Y-axis is counted ad positive downward.
+ NbcMove (Differenz); // Actually executes the coordinate transformation.
+}
+
+OUString E3dScene::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulScene3d));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+ return sName;
+}
+
+OUString E3dScene::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralScene3d);
+}
+
+// The NbcRotate routine overrides the one of the SdrObject. The idea is
+// to be able to rotate the scene relative to the position of the scene
+// and then the objects in the scene
+
+void E3dScene::NbcSetTransform(const basegfx::B3DHomMatrix& rMatrix)
+{
+ if(maTransformation != rMatrix)
+ {
+ // call parent
+ E3dObject::NbcSetTransform(rMatrix);
+ }
+}
+
+void E3dScene::SetTransform(const basegfx::B3DHomMatrix& rMatrix)
+{
+ if(rMatrix != maTransformation)
+ {
+ // call parent
+ E3dObject::SetTransform(rMatrix);
+ }
+}
+
+void E3dScene::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ // So currently the gluepoints are defined relative to the scene aOutRect.
+ // Before turning the gluepoints are defined relative to the page. They
+ // take no part in the rotation of the scene. To ensure this, there is the
+ // SetGlueReallyAbsolute(sal_True);
+
+ // So that was the scene, now the objects used in the scene
+ // 3D objects, if there is only one it can still have multiple surfaces but
+ // the surfaces do not have to be connected. This allows you to access child
+ // objects. So going through the entire list and rotate around the Z axis
+ // through the enter of aOutRect's (Steiner's theorem), so RotateZ
+
+ RotateScene (rRef, sn, cs); // Rotates the scene
+ double fAngleInRad = toRadians(nAngle);
+
+ basegfx::B3DHomMatrix aRotation;
+ aRotation.rotate(0.0, 0.0, fAngleInRad);
+ NbcSetTransform(aRotation * GetTransform());
+
+ SetBoundAndSnapRectsDirty(); // This forces a recalculation of all BoundRects
+ NbcRotateGluePoints(rRef,nAngle,sn,cs); // Rotate the gluepoints (who still
+ // have coordinates relative to the
+ // original page)
+ SetGlueReallyAbsolute(false); // from now they are again relative to BoundRect (that is defined as aOutRect)
+ SetBoundAndSnapRectsDirty();
+}
+
+void E3dScene::RecalcSnapRect()
+{
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(pScene == this)
+ {
+ // The Scene is used as a 2D-Object, take the SnapRect from the
+ // 2D Display settings
+ maSnapRect = pScene->aCamera.GetDeviceWindow();
+ }
+ else
+ {
+ // The Scene itself is a member of another scene, get the SnapRect
+ // as a composite object
+ // call parent
+ E3dObject::RecalcSnapRect();
+
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ E3dObject* pCandidate(dynamic_cast< E3dObject* >(GetObj(a)));
+
+ if(pCandidate)
+ {
+ maSnapRect.Union(pCandidate->GetSnapRect());
+ }
+ }
+ }
+}
+
+bool E3dScene::IsBreakObjPossible()
+{
+ // Break scene, if all members are able to break
+ SdrObjListIter a3DIterator(GetSubList(), SdrIterMode::DeepWithGroups);
+
+ while ( a3DIterator.IsMore() )
+ {
+ E3dObject* pObj = static_cast<E3dObject*>(a3DIterator.Next());
+ if(!pObj->IsBreakObjPossible())
+ return false;
+ }
+
+ return true;
+}
+
+basegfx::B2DPolyPolygon E3dScene::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
+{
+ return TakeXorPoly();
+}
+
+bool E3dScene::BegCreate(SdrDragStat& rStat)
+{
+ rStat.SetOrtho4Possible();
+ tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
+ aRect1.Justify();
+ rStat.SetActionRect(aRect1);
+ NbcSetSnapRect(aRect1);
+ return true;
+}
+
+bool E3dScene::MovCreate(SdrDragStat& rStat)
+{
+ tools::Rectangle aRect1;
+ rStat.TakeCreateRect(aRect1);
+ aRect1.Justify();
+ rStat.SetActionRect(aRect1);
+ NbcSetSnapRect(aRect1);
+ SetBoundRectDirty();
+ m_bSnapRectDirty=true;
+ return true;
+}
+
+bool E3dScene::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ tools::Rectangle aRect1;
+ rStat.TakeCreateRect(aRect1);
+ aRect1.Justify();
+ NbcSetSnapRect(aRect1);
+ SetBoundAndSnapRectsDirty();
+ return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
+}
+
+bool E3dScene::BckCreate(SdrDragStat& /*rStat*/)
+{
+ return false;
+}
+
+void E3dScene::BrkCreate(SdrDragStat& /*rStat*/)
+{
+}
+
+void E3dScene::SetSelected(bool bNew)
+{
+ // call parent
+ E3dObject::SetSelected(bNew);
+
+ for(size_t a(0); a < GetObjCount(); a++)
+ {
+ E3dObject* pCandidate(dynamic_cast< E3dObject* >(GetObj(a)));
+
+ if(pCandidate)
+ {
+ pCandidate->SetSelected(bNew);
+ }
+ }
+}
+
+void E3dScene::NbcInsertObject(SdrObject* pObj, size_t nPos)
+{
+ // Is it even a 3D object?
+ if(nullptr != dynamic_cast< const E3dObject* >(pObj))
+ {
+ // Normal 3D object, insert means call parent
+ SdrObjList::NbcInsertObject(pObj, nPos);
+
+ // local needed stuff
+ InvalidateBoundVolume();
+ StructureChanged();
+ }
+ else
+ {
+ // No 3D object, inserted a page in place in a scene ...
+ getSdrObjectFromSdrObjList()->getSdrPageFromSdrObject()->InsertObject(pObj, nPos);
+ }
+}
+
+void E3dScene::InsertObject(SdrObject* pObj, size_t nPos)
+{
+ // Is it even a 3D object?
+ if(nullptr != dynamic_cast< const E3dObject* >(pObj))
+ {
+ // call parent
+ SdrObjList::InsertObject(pObj, nPos);
+
+ // local needed stuff
+ InvalidateBoundVolume();
+ StructureChanged();
+ }
+ else
+ {
+ // No 3D object, inserted a page in place in a scene ...
+ getSdrObjectFromSdrObjList()->getSdrPageFromSdrObject()->InsertObject(pObj, nPos);
+ }
+}
+
+SdrObject* E3dScene::NbcRemoveObject(size_t nObjNum)
+{
+ // call parent
+ SdrObject* pRetval = SdrObjList::NbcRemoveObject(nObjNum);
+
+ InvalidateBoundVolume();
+ StructureChanged();
+
+ return pRetval;
+}
+
+SdrObject* E3dScene::RemoveObject(size_t nObjNum)
+{
+ // call parent
+ SdrObject* pRetval(SdrObjList::RemoveObject(nObjNum));
+
+ InvalidateBoundVolume();
+ StructureChanged();
+
+ return pRetval;
+}
+
+void E3dScene::SetBoundAndSnapRectsDirty(bool bNotMyself, bool bRecursive)
+{
+ // call parent
+ E3dObject::SetBoundAndSnapRectsDirty(bNotMyself, bRecursive);
+
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ E3dObject* pCandidate = dynamic_cast< E3dObject* >(GetObj(a));
+
+ if(pCandidate)
+ {
+ pCandidate->SetBoundAndSnapRectsDirty(bNotMyself, false);
+ }
+ }
+}
+
+void E3dScene::NbcSetLayer(SdrLayerID nLayer)
+{
+ // call parent
+ E3dObject::NbcSetLayer(nLayer);
+
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ E3dObject* pCandidate = dynamic_cast< E3dObject* >(GetObj(a));
+
+ if(pCandidate)
+ {
+ pCandidate->NbcSetLayer(nLayer);
+ }
+ }
+}
+
+void E3dScene::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ if(pOldPage == pNewPage)
+ return;
+
+ // call parent
+ E3dObject::handlePageChange(pOldPage, pNewPage);
+
+ for(size_t a(0); a < GetObjCount(); a++)
+ {
+ E3dObject* pCandidate = dynamic_cast< E3dObject* >(GetObj(a));
+
+ if(pCandidate)
+ {
+ pCandidate->handlePageChange(pOldPage, pNewPage);
+ }
+ else
+ {
+ OSL_ENSURE(false, "E3dScene::handlePageChange invalid object list (!)");
+ }
+ }
+}
+
+SdrObjList* E3dScene::GetSubList() const
+{
+ return const_cast< E3dScene* >(this);
+}
+
+basegfx::B3DRange E3dScene::RecalcBoundVolume() const
+{
+ basegfx::B3DRange aRetval;
+ const size_t nObjCnt(GetObjCount());
+
+ for(size_t a = 0; a < nObjCnt; ++a)
+ {
+ const E3dObject* p3DObject = dynamic_cast< const E3dObject* >(GetObj(a));
+
+ if(p3DObject)
+ {
+ basegfx::B3DRange aLocalRange(p3DObject->GetBoundVolume());
+ aLocalRange.transform(p3DObject->GetTransform());
+ aRetval.expand(aLocalRange);
+ }
+ }
+
+ return aRetval;
+}
+
+void E3dScene::SetTransformChanged()
+{
+ // call parent
+ E3dObject::SetTransformChanged();
+
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ E3dObject* pCandidate = dynamic_cast< E3dObject* >(GetObj(a));
+
+ if(pCandidate)
+ {
+ pCandidate->SetTransformChanged();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/sphere3d.cxx b/svx/source/engine3d/sphere3d.cxx
new file mode 100644
index 000000000..cac250907
--- /dev/null
+++ b/svx/source/engine3d/sphere3d.cxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/strings.hrc>
+#include <svx/deflt3d.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdobjkind.hxx>
+#include <svx/sphere3d.hxx>
+
+#include <sdr/properties/e3dsphereproperties.hxx>
+#include <basegfx/vector/b3dvector.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <sdr/contact/viewcontactofe3dsphere.hxx>
+
+// DrawContact section
+std::unique_ptr<sdr::contact::ViewContact> E3dSphereObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dSphere>(*this);
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dSphereObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dSphereProperties>(*this);
+}
+
+// Build Sphere from polygon facets in latitude and longitude
+E3dSphereObj::E3dSphereObj(
+ SdrModel& rSdrModel,
+ const E3dDefaultAttributes& rDefault,
+ const basegfx::B3DPoint& rCenter,
+ const basegfx::B3DVector& r3DSize)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set defaults
+ SetDefaultAttributes(rDefault);
+
+ aCenter = rCenter;
+ aSize = r3DSize;
+}
+
+E3dSphereObj::E3dSphereObj(SdrModel& rSdrModel)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+}
+
+E3dSphereObj::E3dSphereObj(SdrModel& rSdrModel, E3dSphereObj const & rSource)
+: E3dCompoundObject(rSdrModel, rSource)
+{
+ // Set defaults
+ const E3dDefaultAttributes aDefault;
+ SetDefaultAttributes(aDefault);
+
+ aCenter = rSource.aCenter;
+ aSize = rSource.aSize;
+}
+
+E3dSphereObj::~E3dSphereObj()
+{
+}
+
+void E3dSphereObj::SetDefaultAttributes(const E3dDefaultAttributes& rDefault)
+{
+ // Set defaults
+ aCenter = rDefault.GetDefaultSphereCenter();
+ aSize = rDefault.GetDefaultSphereSize();
+}
+
+SdrObjKind E3dSphereObj::GetObjIdentifier() const
+{
+ return SdrObjKind::E3D_Sphere;
+}
+
+// Convert the object into a group object consisting of n polygons
+
+SdrObjectUniquePtr E3dSphereObj::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
+{
+ return nullptr;
+}
+
+E3dSphereObj* E3dSphereObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new E3dSphereObj(rTargetModel, *this);
+}
+
+// Set local parameters with geometry re-creating
+
+void E3dSphereObj::SetCenter(const basegfx::B3DPoint& rNew)
+{
+ if(aCenter != rNew)
+ {
+ aCenter = rNew;
+ ActionChanged();
+ }
+}
+
+void E3dSphereObj::SetSize(const basegfx::B3DVector& rNew)
+{
+ if(aSize != rNew)
+ {
+ aSize = rNew;
+ ActionChanged();
+ }
+}
+
+// Get the name of the object (singular)
+
+OUString E3dSphereObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulSphere3d));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName += " '" + aName + "'";
+ }
+ return sName;
+}
+
+// Get the name of the object (plural)
+
+OUString E3dSphereObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralSphere3d);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/svx3ditems.cxx b/svx/source/engine3d/svx3ditems.cxx
new file mode 100644
index 000000000..68f31b120
--- /dev/null
+++ b/svx/source/engine3d/svx3ditems.cxx
@@ -0,0 +1,277 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svx3ditems.hxx>
+#include <com/sun/star/drawing/NormalsKind.hpp>
+#include <com/sun/star/drawing/TextureProjectionMode.hpp>
+#include <com/sun/star/drawing/TextureKind.hpp>
+#include <com/sun/star/drawing/TextureMode.hpp>
+#include <com/sun/star/drawing/ProjectionMode.hpp>
+#include <com/sun/star/drawing/ShadeMode.hpp>
+
+using namespace ::com::sun::star;
+
+// #i28528#
+// Added extra Item (Bool) for chart2 to be able to show reduced line geometry
+
+Svx3DReducedLineGeometryItem::Svx3DReducedLineGeometryItem(bool bVal)
+ : SfxBoolItem(SDRATTR_3DOBJ_REDUCED_LINE_GEOMETRY, bVal)
+{
+}
+
+Svx3DReducedLineGeometryItem* Svx3DReducedLineGeometryItem::Clone(SfxItemPool*) const
+{
+ return new Svx3DReducedLineGeometryItem(*this);
+}
+
+Svx3DNormalsKindItem::Svx3DNormalsKindItem(sal_uInt16 nVal)
+ : SfxUInt16Item(SDRATTR_3DOBJ_NORMALS_KIND, nVal)
+{
+}
+
+Svx3DTextureProjectionXItem::Svx3DTextureProjectionXItem(sal_uInt16 nVal)
+ : SfxUInt16Item(SDRATTR_3DOBJ_TEXTURE_PROJ_X, nVal)
+{
+}
+
+Svx3DTextureProjectionYItem::Svx3DTextureProjectionYItem(sal_uInt16 nVal)
+ : SfxUInt16Item(SDRATTR_3DOBJ_TEXTURE_PROJ_Y, nVal)
+{
+}
+
+Svx3DTextureKindItem::Svx3DTextureKindItem(sal_uInt16 nVal)
+ : SfxUInt16Item(SDRATTR_3DOBJ_TEXTURE_KIND, nVal)
+{
+}
+
+Svx3DTextureModeItem::Svx3DTextureModeItem(sal_uInt16 nVal)
+ : SfxUInt16Item(SDRATTR_3DOBJ_TEXTURE_MODE, nVal)
+{
+}
+
+Svx3DPerspectiveItem::Svx3DPerspectiveItem(ProjectionType nVal)
+ : SfxUInt16Item(SDRATTR_3DSCENE_PERSPECTIVE, static_cast<sal_uInt16>(nVal))
+{
+}
+
+Svx3DShadeModeItem::Svx3DShadeModeItem(sal_uInt16 nVal)
+ : SfxUInt16Item(SDRATTR_3DSCENE_SHADE_MODE, nVal)
+{
+}
+
+Svx3DSmoothNormalsItem::Svx3DSmoothNormalsItem(bool bVal)
+ : SfxBoolItem(SDRATTR_3DOBJ_SMOOTH_NORMALS, bVal)
+{
+}
+
+Svx3DSmoothNormalsItem* Svx3DSmoothNormalsItem::Clone(SfxItemPool*) const
+{
+ return new Svx3DSmoothNormalsItem(*this);
+}
+
+Svx3DSmoothLidsItem::Svx3DSmoothLidsItem(bool bVal)
+ : SfxBoolItem(SDRATTR_3DOBJ_SMOOTH_LIDS, bVal)
+{
+}
+
+Svx3DSmoothLidsItem* Svx3DSmoothLidsItem::Clone(SfxItemPool*) const
+{
+ return new Svx3DSmoothLidsItem(*this);
+}
+
+Svx3DCharacterModeItem::Svx3DCharacterModeItem(bool bVal)
+ : SfxBoolItem(SDRATTR_3DOBJ_CHARACTER_MODE, bVal)
+{
+}
+
+Svx3DCharacterModeItem* Svx3DCharacterModeItem::Clone(SfxItemPool*) const
+{
+ return new Svx3DCharacterModeItem(*this);
+}
+
+Svx3DCloseFrontItem::Svx3DCloseFrontItem(bool bVal)
+ : SfxBoolItem(SDRATTR_3DOBJ_CLOSE_FRONT, bVal)
+{
+}
+
+Svx3DCloseFrontItem* Svx3DCloseFrontItem::Clone(SfxItemPool*) const
+{
+ return new Svx3DCloseFrontItem(*this);
+}
+
+Svx3DCloseBackItem::Svx3DCloseBackItem(bool bVal)
+ : SfxBoolItem(SDRATTR_3DOBJ_CLOSE_BACK, bVal)
+{
+}
+
+Svx3DCloseBackItem* Svx3DCloseBackItem::Clone(SfxItemPool*) const
+{
+ return new Svx3DCloseBackItem(*this);
+}
+
+// Svx3DNormalsKindItem: use drawing::NormalsKind
+bool Svx3DNormalsKindItem::QueryValue(uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::NormalsKind>(GetValue());
+ return true;
+}
+
+bool Svx3DNormalsKindItem::PutValue(const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::NormalsKind eVar;
+ if (!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DNormalsKindItem* Svx3DNormalsKindItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DNormalsKindItem(*this);
+}
+
+// Svx3DTextureProjectionXItem: use drawing::TextureProjectionMode
+bool Svx3DTextureProjectionXItem::QueryValue(uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextureProjectionMode>(GetValue());
+ return true;
+}
+
+bool Svx3DTextureProjectionXItem::PutValue(const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextureProjectionMode eVar;
+ if (!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DTextureProjectionXItem* Svx3DTextureProjectionXItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DTextureProjectionXItem(*this);
+}
+
+// Svx3DTextureProjectionYItem: use drawing::TextureProjectionMode
+bool Svx3DTextureProjectionYItem::QueryValue(uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextureProjectionMode>(GetValue());
+ return true;
+}
+
+bool Svx3DTextureProjectionYItem::PutValue(const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextureProjectionMode eVar;
+ if (!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DTextureProjectionYItem* Svx3DTextureProjectionYItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DTextureProjectionYItem(*this);
+}
+
+// Svx3DTextureKindItem: use drawing::TextureKind
+bool Svx3DTextureKindItem::QueryValue(uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextureKind>(GetValue());
+ return true;
+}
+
+bool Svx3DTextureKindItem::PutValue(const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextureKind eVar;
+ if (!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DTextureKindItem* Svx3DTextureKindItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DTextureKindItem(*this);
+}
+
+// Svx3DTextureModeItem: use drawing:TextureMode
+bool Svx3DTextureModeItem::QueryValue(uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextureMode>(GetValue());
+ return true;
+}
+
+bool Svx3DTextureModeItem::PutValue(const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextureMode eVar;
+ if (!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DTextureModeItem* Svx3DTextureModeItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DTextureModeItem(*this);
+}
+
+// Svx3DPerspectiveItem: use drawing::ProjectionMode
+bool Svx3DPerspectiveItem::QueryValue(uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::ProjectionMode>(GetValue());
+ return true;
+}
+
+bool Svx3DPerspectiveItem::PutValue(const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::ProjectionMode eVar;
+ if (!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DPerspectiveItem* Svx3DPerspectiveItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DPerspectiveItem(*this);
+}
+
+// Svx3DShadeModeItem: use drawing::ShadeMode
+bool Svx3DShadeModeItem::QueryValue(uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::ShadeMode>(GetValue());
+ return true;
+}
+
+bool Svx3DShadeModeItem::PutValue(const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::ShadeMode eVar;
+ if (!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DShadeModeItem* Svx3DShadeModeItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DShadeModeItem(*this);
+}
+
+// EOF
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/view3d.cxx b/svx/source/engine3d/view3d.cxx
new file mode 100644
index 000000000..e5caf5355
--- /dev/null
+++ b/svx/source/engine3d/view3d.cxx
@@ -0,0 +1,1593 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdopath.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpagv.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdview.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/lathe3d.hxx>
+#include <extrud3d.hxx>
+#include <dragmt3d.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/view3d.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <svx/e3dsceneupdater.hxx>
+
+using namespace com::sun::star;
+
+
+// Migrate Marking
+
+class Impl3DMirrorConstructOverlay
+{
+ // The OverlayObjects
+ sdr::overlay::OverlayObjectList maObjects;
+
+ // the view
+ const E3dView& mrView;
+
+ // the object count
+ size_t mnCount;
+
+ // the unmirrored polygons
+ basegfx::B2DPolyPolygon* mpPolygons;
+
+ // the overlay geometry from selected objects
+ drawinglayer::primitive2d::Primitive2DContainer maFullOverlay;
+
+ // Copy assignment is forbidden and not implemented.
+ Impl3DMirrorConstructOverlay (const Impl3DMirrorConstructOverlay &) = delete;
+ Impl3DMirrorConstructOverlay & operator= (const Impl3DMirrorConstructOverlay &) = delete;
+
+public:
+ explicit Impl3DMirrorConstructOverlay(const E3dView& rView);
+ ~Impl3DMirrorConstructOverlay();
+
+ void SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB);
+};
+
+Impl3DMirrorConstructOverlay::Impl3DMirrorConstructOverlay(const E3dView& rView)
+: mrView(rView),
+ mnCount(rView.GetMarkedObjectCount()),
+ mpPolygons(nullptr)
+{
+ if(!mnCount)
+ return;
+
+ if(mrView.IsSolidDragging())
+ {
+ SdrPageView* pPV = rView.GetSdrPageView();
+
+ if(pPV && pPV->PageWindowCount())
+ {
+ for(size_t a = 0; a < mnCount; ++a)
+ {
+ SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
+
+ if(pObject)
+ {
+ // use the view-independent primitive representation (without
+ // evtl. GridOffset, that may be applied to the DragEntry individually)
+ pObject->GetViewContact().getViewIndependentPrimitive2DContainer(maFullOverlay);
+ }
+ }
+ }
+ }
+ else
+ {
+ mpPolygons = new basegfx::B2DPolyPolygon[mnCount];
+
+ for(size_t a = 0; a < mnCount; ++a)
+ {
+ SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
+ mpPolygons[mnCount - (a + 1)] = pObject->TakeXorPoly();
+ }
+ }
+}
+
+Impl3DMirrorConstructOverlay::~Impl3DMirrorConstructOverlay()
+{
+ // The OverlayObjects are cleared using the destructor of OverlayObjectList.
+ // That destructor calls clear() at the list which removes all objects from the
+ // OverlayManager and deletes them.
+ delete[] mpPolygons;
+}
+
+void Impl3DMirrorConstructOverlay::SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB)
+{
+ // get rid of old overlay objects
+ maObjects.clear();
+
+ // create new ones
+ for(sal_uInt32 a(0); a < mrView.PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = mrView.GetPaintWindow(a);
+ const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
+
+ if(xTargetOverlay.is())
+ {
+ // build transformation: translate and rotate so that given edge is
+ // on x axis, them mirror in y and translate back
+ const basegfx::B2DVector aEdge(aMirrorAxisB.X() - aMirrorAxisA.X(), aMirrorAxisB.Y() - aMirrorAxisA.Y());
+ basegfx::B2DHomMatrix aMatrixTransform(basegfx::utils::createTranslateB2DHomMatrix(
+ -aMirrorAxisA.X(), -aMirrorAxisA.Y()));
+ aMatrixTransform.rotate(-atan2(aEdge.getY(), aEdge.getX()));
+ aMatrixTransform.scale(1.0, -1.0);
+ aMatrixTransform.rotate(atan2(aEdge.getY(), aEdge.getX()));
+ aMatrixTransform.translate(aMirrorAxisA.X(), aMirrorAxisA.Y());
+
+ if(mrView.IsSolidDragging())
+ {
+ if(!maFullOverlay.empty())
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aContent(maFullOverlay);
+
+ if(!aMatrixTransform.isIdentity())
+ {
+ // embed in transformation group
+ drawinglayer::primitive2d::Primitive2DReference aTransformPrimitive2D(new drawinglayer::primitive2d::TransformPrimitive2D(aMatrixTransform, std::move(aContent)));
+ aContent = drawinglayer::primitive2d::Primitive2DContainer { aTransformPrimitive2D };
+ }
+
+ // if we have full overlay from selected objects, embed with 50% transparence, the
+ // transformation is added to the OverlayPrimitive2DSequenceObject
+ drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aContent), 0.5));
+ aContent = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparencePrimitive2D };
+
+ std::unique_ptr<sdr::overlay::OverlayPrimitive2DSequenceObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(std::move(aContent)));
+
+ xTargetOverlay->add(*pNew);
+ maObjects.append(std::move(pNew));
+ }
+ }
+ else
+ {
+ for(size_t b = 0; b < mnCount; ++b)
+ {
+ // apply to polygon
+ basegfx::B2DPolyPolygon aPolyPolygon(mpPolygons[b]);
+ aPolyPolygon.transform(aMatrixTransform);
+
+ std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
+ aPolyPolygon));
+ xTargetOverlay->add(*pNew);
+ maObjects.append(std::move(pNew));
+ }
+ }
+ }
+ }
+}
+
+E3dView::E3dView(
+ SdrModel& rSdrModel,
+ OutputDevice* pOut)
+: SdrView(rSdrModel, pOut)
+{
+ InitView();
+}
+
+// DrawMarkedObj override, since possibly only a single 3D object is to be
+// drawn
+
+void E3dView::DrawMarkedObj(OutputDevice& rOut) const
+{
+ // Does 3D objects exist which scenes are not selected?
+ bool bSpecialHandling = false;
+ E3dScene *pScene = nullptr;
+
+ const size_t nCnt = GetMarkedObjectCount();
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(auto pCompoundObject = dynamic_cast<E3dCompoundObject*>(pObj))
+ {
+ // related scene
+ pScene = pCompoundObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene && !IsObjMarked(pScene))
+ {
+ bSpecialHandling = true;
+ }
+ }
+ // Reset all selection flags
+ if(auto p3dObject = dynamic_cast< const E3dObject*>(pObj))
+ {
+ pScene = p3dObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene)
+ {
+ pScene->SetSelected(false);
+ }
+ }
+ }
+
+ if(bSpecialHandling)
+ {
+ // Set selection flag to "not selected" for scenes related to all 3D
+ // objects
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(auto pCompoundObject = dynamic_cast<E3dCompoundObject*>(pObj))
+ {
+ // related scene
+ pScene = pCompoundObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene)
+ {
+ pScene->SetSelected(false);
+ }
+ }
+ }
+
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(auto p3DObj = dynamic_cast<E3dObject*>(pObj))
+ {
+ // Select object
+ p3DObj->SetSelected(true);
+ pScene = p3DObj->getRootE3dSceneFromE3dObject();
+ }
+ }
+
+ if(nullptr != pScene)
+ {
+ // code from parent
+ SortMarkedObjects();
+
+ pScene->SetDrawOnlySelected(true);
+ pScene->SingleObjectPainter(rOut);
+ pScene->SetDrawOnlySelected(false);
+ }
+
+ // Reset selection flag
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(auto pCompoundObject = dynamic_cast<E3dCompoundObject*>(pObj))
+ {
+ // related scene
+ pScene = pCompoundObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene)
+ {
+ pScene->SetSelected(false);
+ }
+ }
+ }
+ }
+ else
+ {
+ // call parent
+ SdrExchangeView::DrawMarkedObj(rOut);
+ }
+}
+
+// override get model, since in some 3D objects an additional scene
+// must be pushed in
+
+std::unique_ptr<SdrModel> E3dView::CreateMarkedObjModel() const
+{
+ // Does 3D objects exist which scenes are not selected?
+ bool bSpecialHandling(false);
+ const size_t nCount(GetMarkedObjectCount());
+ E3dScene *pScene = nullptr;
+
+ for(size_t nObjs = 0; nObjs < nCount; ++nObjs)
+ {
+ const SdrObject* pObj = GetMarkedObjectByIndex(nObjs);
+
+ if(!bSpecialHandling)
+ if(auto pCompoundObj = dynamic_cast< const E3dCompoundObject*>(pObj))
+ {
+ // if the object is selected, but it's scene not,
+ // we need special handling
+ pScene = pCompoundObj->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene && !IsObjMarked(pScene))
+ {
+ bSpecialHandling = true;
+ }
+ }
+
+ if(auto p3dObject = dynamic_cast< const E3dObject*>(pObj))
+ {
+ // reset all selection flags at 3D objects
+ pScene = p3dObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene)
+ {
+ pScene->SetSelected(false);
+ }
+ }
+ }
+
+ if(!bSpecialHandling)
+ {
+ // call parent
+ return SdrView::CreateMarkedObjModel();
+ }
+
+ std::unique_ptr<SdrModel> pNewModel;
+ tools::Rectangle aSelectedSnapRect;
+
+ // set 3d selection flags at all directly selected objects
+ // and collect SnapRect of selected objects
+ for(size_t nObjs = 0; nObjs < nCount; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+
+ if(auto p3DObj = dynamic_cast<E3dCompoundObject*>(pObj))
+ {
+ // mark object, but not scenes
+ p3DObj->SetSelected(true);
+ aSelectedSnapRect.Union(p3DObj->GetSnapRect());
+ }
+ }
+
+ // create new mark list which contains all indirectly selected3d
+ // scenes as selected objects
+ SdrMarkList aOldML(GetMarkedObjectList());
+ SdrMarkList aNewML;
+ SdrMarkList& rCurrentMarkList = const_cast<E3dView*>(this)->GetMarkedObjectListWriteAccess();
+ rCurrentMarkList = aNewML;
+
+ for(size_t nObjs = 0; nObjs < nCount; ++nObjs)
+ {
+ SdrObject *pObj = aOldML.GetMark(nObjs)->GetMarkedSdrObj();
+
+ if(auto p3dObject = dynamic_cast< E3dObject* >(pObj))
+ {
+ pScene = p3dObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene && !IsObjMarked(pScene) && GetSdrPageView())
+ {
+ const_cast<E3dView*>(this)->MarkObj(pScene, GetSdrPageView(), false, true);
+ }
+ }
+ }
+
+ // call parent. This will copy all scenes and the selection flags at the 3D objects. So
+ // it will be possible to delete all non-selected 3d objects from the cloned 3d scenes
+ pNewModel = SdrView::CreateMarkedObjModel();
+
+ if(pNewModel)
+ {
+ for(sal_uInt16 nPg(0); nPg < pNewModel->GetPageCount(); nPg++)
+ {
+ const SdrPage* pSrcPg=pNewModel->GetPage(nPg);
+ const size_t nObjCount(pSrcPg->GetObjCount());
+
+ for(size_t nOb = 0; nOb < nObjCount; ++nOb)
+ {
+ const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
+
+ if(auto p3dscene = dynamic_cast< const E3dScene* >( pSrcOb))
+ {
+ pScene = const_cast<E3dScene*>(p3dscene);
+
+ // delete all not intentionally cloned 3d objects
+ pScene->removeAllNonSelectedObjects();
+
+ // reset select flags and set SnapRect of all selected objects
+ pScene->SetSelected(false);
+ pScene->SetSnapRect(aSelectedSnapRect);
+ }
+ }
+ }
+ }
+
+ // restore old selection
+ rCurrentMarkList = aOldML;
+
+ return pNewModel;
+}
+
+// When pasting objects have to integrated if a scene is inserted, but
+// not the scene itself
+
+bool E3dView::Paste(
+ const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
+{
+ bool bRetval = false;
+
+ // Get list
+ Point aPos(rPos);
+ SdrObjList* pDstList = pLst;
+ ImpGetPasteObjList(aPos, pDstList);
+
+ if(!pDstList)
+ return false;
+
+ // Get owner of the list
+ E3dScene* pDstScene(dynamic_cast< E3dScene* >(pDstList->getSdrObjectFromSdrObjList()));
+
+ if(nullptr != pDstScene)
+ {
+ BegUndo(SvxResId(RID_SVX_3D_UNDO_EXCHANGE_PASTE));
+
+ // Copy all objects from E3dScenes and insert them directly
+ for(sal_uInt16 nPg(0); nPg < rMod.GetPageCount(); nPg++)
+ {
+ const SdrPage* pSrcPg=rMod.GetPage(nPg);
+ const size_t nObjCount(pSrcPg->GetObjCount());
+
+ // calculate offset for paste
+ tools::Rectangle aR = pSrcPg->GetAllObjBoundRect();
+ Point aDist(aPos - aR.Center());
+
+ // Insert sub-objects for scenes
+ for(size_t nOb = 0; nOb < nObjCount; ++nOb)
+ {
+ const SdrObject* pSrcOb = pSrcPg->GetObj(nOb);
+ if(auto p3dscene = dynamic_cast< const E3dScene* >(pSrcOb))
+ {
+ E3dScene* pSrcScene = const_cast<E3dScene*>(p3dscene);
+ ImpCloneAll3DObjectsToDestScene(pSrcScene, pDstScene, aDist);
+ }
+ }
+ }
+ EndUndo();
+ }
+ else
+ {
+ // call parent
+ bRetval = SdrView::Paste(rMod, rPos, pLst, nOptions);
+ }
+
+ return bRetval;
+}
+
+// Service routine used from local Clone() and from SdrCreateView::EndCreateObj(...)
+bool E3dView::ImpCloneAll3DObjectsToDestScene(E3dScene const * pSrcScene, E3dScene* pDstScene, Point /*aOffset*/)
+{
+ bool bRetval(false);
+
+ if(pSrcScene && pDstScene)
+ {
+ for(size_t i = 0; i < pSrcScene->GetSubList()->GetObjCount(); ++i)
+ {
+ E3dCompoundObject* pCompoundObj = dynamic_cast< E3dCompoundObject* >(pSrcScene->GetSubList()->GetObj(i));
+
+ if(pCompoundObj)
+ {
+ E3dCompoundObject* pNewCompoundObj(pCompoundObj->CloneSdrObject(pDstScene->getSdrModelFromSdrObject()));
+
+ if(pNewCompoundObj)
+ {
+ // get dest scene's current range in 3D world coordinates
+ const basegfx::B3DHomMatrix aSceneToWorldTrans(pDstScene->GetFullTransform());
+ basegfx::B3DRange aSceneRange(pDstScene->GetBoundVolume());
+ aSceneRange.transform(aSceneToWorldTrans);
+
+ // get new object's implied object transformation
+ const basegfx::B3DHomMatrix aNewObjectTrans(pNewCompoundObj->GetTransform());
+
+ // get new object's range in 3D world coordinates in dest scene
+ // as if it were already added
+ const basegfx::B3DHomMatrix aObjectToWorldTrans(aSceneToWorldTrans * aNewObjectTrans);
+ basegfx::B3DRange aObjectRange(pNewCompoundObj->GetBoundVolume());
+ aObjectRange.transform(aObjectToWorldTrans);
+
+ // get scale adaptation
+ const basegfx::B3DVector aSceneScale(aSceneRange.getRange());
+ const basegfx::B3DVector aObjectScale(aObjectRange.getRange());
+ double fScale(1.0);
+
+ // if new object's size in X,Y or Z is bigger that 80% of dest scene, adapt scale
+ // to not change the scene by the inserted object
+ const double fSizeFactor(0.5);
+
+ if(aObjectScale.getX() * fScale > aSceneScale.getX() * fSizeFactor)
+ {
+ const double fObjSize(aObjectScale.getX() * fScale);
+ const double fFactor((aSceneScale.getX() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
+ fScale *= fFactor;
+ }
+
+ if(aObjectScale.getY() * fScale > aSceneScale.getY() * fSizeFactor)
+ {
+ const double fObjSize(aObjectScale.getY() * fScale);
+ const double fFactor((aSceneScale.getY() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
+ fScale *= fFactor;
+ }
+
+ if(aObjectScale.getZ() * fScale > aSceneScale.getZ() * fSizeFactor)
+ {
+ const double fObjSize(aObjectScale.getZ() * fScale);
+ const double fFactor((aSceneScale.getZ() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
+ fScale *= fFactor;
+ }
+
+ // get translation adaptation
+ const basegfx::B3DPoint aSceneCenter(aSceneRange.getCenter());
+ const basegfx::B3DPoint aObjectCenter(aObjectRange.getCenter());
+
+ // build full modification transform. The object's transformation
+ // shall be modified, so start at object coordinates; transform to 3d world coor
+ basegfx::B3DHomMatrix aModifyingTransform(aObjectToWorldTrans);
+
+ // translate to absolute center in 3d world coor
+ aModifyingTransform.translate(-aObjectCenter.getX(), -aObjectCenter.getY(), -aObjectCenter.getZ());
+
+ // scale to dest size in 3d world coor
+ aModifyingTransform.scale(fScale, fScale, fScale);
+
+ // translate to dest scene center in 3d world coor
+ aModifyingTransform.translate(aSceneCenter.getX(), aSceneCenter.getY(), aSceneCenter.getZ());
+
+ // transform from 3d world to dest object coordinates
+ basegfx::B3DHomMatrix aWorldToObject(aObjectToWorldTrans);
+ aWorldToObject.invert();
+ aModifyingTransform = aWorldToObject * aModifyingTransform;
+
+ // correct implied object transform by applying changing one in object coor
+ pNewCompoundObj->SetTransform(aModifyingTransform * aNewObjectTrans);
+
+ // fill and insert new object
+ pNewCompoundObj->NbcSetLayer(pCompoundObj->GetLayer());
+ pNewCompoundObj->NbcSetStyleSheet(pCompoundObj->GetStyleSheet(), true);
+ pDstScene->InsertObject(pNewCompoundObj);
+ bRetval = true;
+
+ // Create undo
+ if( GetModel()->IsUndoEnabled() )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewCompoundObj));
+ }
+ }
+ }
+ }
+
+ return bRetval;
+}
+
+bool E3dView::IsConvertTo3DObjPossible() const
+{
+ bool bAny3D(false);
+ bool bGroupSelected(false);
+ bool bRetval(true);
+
+ for(size_t a=0; !bAny3D && a<GetMarkedObjectCount(); ++a)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(a);
+ if(pObj)
+ {
+ ImpIsConvertTo3DPossible(pObj, bAny3D, bGroupSelected);
+ }
+ }
+
+ bRetval = !bAny3D
+ && (
+ IsConvertToPolyObjPossible()
+ || IsConvertToPathObjPossible()
+ || IsImportMtfPossible());
+ return bRetval;
+}
+
+void E3dView::ImpIsConvertTo3DPossible(SdrObject const * pObj, bool& rAny3D,
+ bool& rGroupSelected) const
+{
+ if(!pObj)
+ return;
+
+ if(dynamic_cast< const E3dObject* >(pObj) != nullptr)
+ {
+ rAny3D = true;
+ }
+ else
+ {
+ if(pObj->IsGroupObject())
+ {
+ SdrObjListIter aIter(*pObj, SdrIterMode::DeepNoGroups);
+ while(aIter.IsMore())
+ {
+ SdrObject* pNewObj = aIter.Next();
+ ImpIsConvertTo3DPossible(pNewObj, rAny3D, rGroupSelected);
+ }
+ rGroupSelected = true;
+ }
+ }
+}
+
+void E3dView::ImpChangeSomeAttributesFor3DConversion(SdrObject* pObj)
+{
+ if(dynamic_cast<const SdrTextObj*>( pObj) == nullptr)
+ return;
+
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+ const SvxColorItem& rTextColorItem = rSet.Get(EE_CHAR_COLOR);
+ if(rTextColorItem.GetValue() != COL_BLACK)
+ return;
+
+ //For black text objects, the color set to gray
+ if(pObj->getSdrPageFromSdrObject())
+ {
+ // if black is only default attribute from
+ // pattern set it hard so that it is used in undo.
+ pObj->SetMergedItem(SvxColorItem(COL_BLACK, EE_CHAR_COLOR));
+
+ // add undo now
+ if( GetModel()->IsUndoEnabled() )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
+ }
+
+ pObj->SetMergedItem(SvxColorItem(COL_GRAY, EE_CHAR_COLOR));
+}
+
+void E3dView::ImpChangeSomeAttributesFor3DConversion2(SdrObject* pObj)
+{
+ auto pPathObj = dynamic_cast<const SdrPathObj*>( pObj);
+ if(!pPathObj)
+ return;
+
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+ sal_Int32 nLineWidth = rSet.Get(XATTR_LINEWIDTH).GetValue();
+ drawing::LineStyle eLineStyle = rSet.Get(XATTR_LINESTYLE).GetValue();
+ drawing::FillStyle eFillStyle = rSet.Get(XATTR_FILLSTYLE).GetValue();
+
+ if(pPathObj->IsClosed()
+ && eLineStyle == drawing::LineStyle_SOLID
+ && !nLineWidth
+ && eFillStyle != drawing::FillStyle_NONE)
+ {
+ if(pObj->getSdrPageFromSdrObject() && GetModel()->IsUndoEnabled() )
+ {
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
+ }
+
+ pObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pObj->SetMergedItem(XLineWidthItem(0));
+ }
+}
+
+void E3dView::ImpCreateSingle3DObjectFlat(E3dScene* pScene, SdrObject* pObj, bool bExtrude, double fDepth, basegfx::B2DHomMatrix const & rLatheMat)
+{
+ // Single PathObject, transform this
+ SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pObj );
+
+ if(!pPath)
+ return;
+
+ E3dDefaultAttributes aDefault = Get3DDefaultAttributes();
+
+ if(bExtrude)
+ {
+ aDefault.SetDefaultExtrudeCharacterMode(true);
+ }
+ else
+ {
+ aDefault.SetDefaultLatheCharacterMode(true);
+ }
+
+ // Get Itemset of the original object
+ SfxItemSet aSet(pObj->GetMergedItemSet());
+
+ drawing::FillStyle eFillStyle = aSet.Get(XATTR_FILLSTYLE).GetValue();
+
+ // line style turned off
+ aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+
+ //Determining if FILL_Attribute is set.
+ if(!pPath->IsClosed() || eFillStyle == drawing::FillStyle_NONE)
+ {
+ // This SdrPathObj is not filled, leave the front and rear face out.
+ // Moreover, a two-sided representation necessary.
+ aDefault.SetDefaultExtrudeCloseFront(false);
+ aDefault.SetDefaultExtrudeCloseBack(false);
+
+ aSet.Put(makeSvx3DDoubleSidedItem(true));
+
+ // Set fill attribute
+ aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+
+ // Fill color must be the color line, because the object was
+ // previously just a line
+ Color aColorLine = aSet.Get(XATTR_LINECOLOR).GetColorValue();
+ aSet.Put(XFillColorItem(OUString(), aColorLine));
+ }
+
+ // Create a new extrude object
+ E3dObject* p3DObj = nullptr;
+ if(bExtrude)
+ {
+ p3DObj = new E3dExtrudeObj(pObj->getSdrModelFromSdrObject(), aDefault, pPath->GetPathPoly(), fDepth);
+ }
+ else
+ {
+ // rLatheMat expects coordinates with y-axis up, pPath uses y-axis down
+ basegfx::B2DHomMatrix aFlipVerticalMat(1.0, 0.0, 0.0, 0.0, -1.0, 0.0);
+ basegfx::B2DPolyPolygon aPolyPoly2D(pPath->GetPathPoly());
+ aPolyPoly2D.transform(aFlipVerticalMat);
+ aPolyPoly2D.transform(rLatheMat);
+ // ctor E3dLatheObj expects coordinates with y-axis down
+ aPolyPoly2D.transform(aFlipVerticalMat);
+ p3DObj = new E3dLatheObj(pObj->getSdrModelFromSdrObject(), aDefault, aPolyPoly2D);
+ }
+
+ // Set attribute
+ p3DObj->NbcSetLayer(pObj->GetLayer());
+
+ p3DObj->SetMergedItemSet(aSet);
+
+ p3DObj->NbcSetStyleSheet(pObj->GetStyleSheet(), true);
+
+ // Insert a new extrude object
+ pScene->InsertObject(p3DObj);
+}
+
+void E3dView::ImpCreate3DObject(E3dScene* pScene, SdrObject* pObj, bool bExtrude, double fDepth, basegfx::B2DHomMatrix const & rLatheMat)
+{
+ if(!pObj)
+ return;
+
+ // change text color attribute for not so dark colors
+ if(pObj->IsGroupObject())
+ {
+ SdrObjListIter aIter(*pObj, SdrIterMode::DeepWithGroups);
+ while(aIter.IsMore())
+ {
+ SdrObject* pGroupMember = aIter.Next();
+ ImpChangeSomeAttributesFor3DConversion(pGroupMember);
+ }
+ }
+ else
+ ImpChangeSomeAttributesFor3DConversion(pObj);
+
+ // convert completely to path objects
+ SdrObject* pNewObj1 = pObj->ConvertToPolyObj(false, false).release();
+
+ if(!pNewObj1)
+ return;
+
+ // change text color attribute for not so dark colors
+ if(pNewObj1->IsGroupObject())
+ {
+ SdrObjListIter aIter(*pNewObj1, SdrIterMode::DeepWithGroups);
+ while(aIter.IsMore())
+ {
+ SdrObject* pGroupMember = aIter.Next();
+ ImpChangeSomeAttributesFor3DConversion2(pGroupMember);
+ }
+ }
+ else
+ ImpChangeSomeAttributesFor3DConversion2(pNewObj1);
+
+ // convert completely to path objects
+ SdrObject* pNewObj2 = pObj->ConvertToContourObj(pNewObj1, true);
+
+ if(pNewObj2)
+ {
+ // add all to flat scene
+ if(pNewObj2->IsGroupObject())
+ {
+ SdrObjListIter aIter(*pNewObj2, SdrIterMode::DeepWithGroups);
+ while(aIter.IsMore())
+ {
+ SdrObject* pGroupMember = aIter.Next();
+ ImpCreateSingle3DObjectFlat(pScene, pGroupMember, bExtrude, fDepth, rLatheMat);
+ }
+ }
+ else
+ ImpCreateSingle3DObjectFlat(pScene, pNewObj2, bExtrude, fDepth, rLatheMat);
+
+ // delete object in between
+ if (pNewObj2 != pObj && pNewObj2 != pNewObj1)
+ SdrObject::Free( pNewObj2 );
+ }
+
+ // delete object in between
+ if (pNewObj1 != pObj)
+ SdrObject::Free( pNewObj1 );
+}
+
+void E3dView::ConvertMarkedObjTo3D(bool bExtrude, const basegfx::B2DPoint& rPnt1, const basegfx::B2DPoint& rPnt2)
+{
+ if(!AreObjectsMarked())
+ return;
+
+ // Create undo
+ if(bExtrude)
+ BegUndo(SvxResId(RID_SVX_3D_UNDO_EXTRUDE));
+ else
+ BegUndo(SvxResId(RID_SVX_3D_UNDO_LATHE));
+
+ SdrModel& rSdrModel(GetSdrMarkByIndex(0)->GetMarkedSdrObj()->getSdrModelFromSdrObject());
+
+ // Create a new scene for the created 3D object
+ E3dScene* pScene = new E3dScene(rSdrModel);
+
+ // Determine rectangle and possibly correct it
+ tools::Rectangle aRect = GetAllMarkedRect();
+ if(aRect.GetWidth() <= 1)
+ aRect.SetSize(Size(500, aRect.GetHeight()));
+ if(aRect.GetHeight() <= 1)
+ aRect.SetSize(Size(aRect.GetWidth(), 500));
+
+ // Determine the depth relative to the size of the selection
+ double fDepth = 0.0;
+ double fRot3D = 0.0;
+ basegfx::B2DHomMatrix aLatheMat;
+
+ if(bExtrude)
+ {
+ double fW = static_cast<double>(aRect.GetWidth());
+ double fH = static_cast<double>(aRect.GetHeight());
+ fDepth = sqrt(fW*fW + fH*fH) / 6.0;
+ }
+ if(!bExtrude)
+ {
+ // Create transformation for the polygons rotating body
+ if (rPnt1 != rPnt2)
+ {
+ // Rotation around control point #1 with set angle
+ // for 3D coordinates
+ basegfx::B2DPoint aDiff(rPnt1 - rPnt2);
+ fRot3D = atan2(aDiff.getY(), aDiff.getX()) - M_PI_2;
+
+ if(basegfx::fTools::equalZero(fabs(fRot3D)))
+ fRot3D = 0.0;
+
+ if(fRot3D != 0.0)
+ {
+ aLatheMat = basegfx::utils::createRotateAroundPoint(rPnt2, -fRot3D)
+ * aLatheMat;
+ }
+ }
+
+ if (rPnt2.getX() != 0.0)
+ {
+ // Translation to Y=0 - axis
+ aLatheMat.translate(-rPnt2.getX(), 0.0);
+ }
+ else
+ {
+ aLatheMat.translate(static_cast<double>(-aRect.Left()), 0.0);
+ }
+
+ // Form the inverse matrix to determine the target expansion
+ basegfx::B2DHomMatrix aInvLatheMat(aLatheMat);
+ aInvLatheMat.invert();
+
+ // SnapRect extension enables mirroring in the axis of rotation
+ for(size_t a=0; a<GetMarkedObjectCount(); ++a)
+ {
+ SdrMark* pMark = GetSdrMarkByIndex(a);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+ tools::Rectangle aTurnRect = pObj->GetSnapRect();
+ basegfx::B2DPoint aRot;
+ Point aRotPnt;
+
+ aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Top());
+ aRot *= aLatheMat;
+ aRot.setX(-aRot.getX());
+ aRot *= aInvLatheMat;
+ aRotPnt = Point(static_cast<tools::Long>(aRot.getX() + 0.5), static_cast<tools::Long>(-aRot.getY() - 0.5));
+ aRect.Union(tools::Rectangle(aRotPnt, aRotPnt));
+
+ aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Bottom());
+ aRot *= aLatheMat;
+ aRot.setX(-aRot.getX());
+ aRot *= aInvLatheMat;
+ aRotPnt = Point(static_cast<tools::Long>(aRot.getX() + 0.5), static_cast<tools::Long>(-aRot.getY() - 0.5));
+ aRect.Union(tools::Rectangle(aRotPnt, aRotPnt));
+
+ aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Top());
+ aRot *= aLatheMat;
+ aRot.setX(-aRot.getX());
+ aRot *= aInvLatheMat;
+ aRotPnt = Point(static_cast<tools::Long>(aRot.getX() + 0.5), static_cast<tools::Long>(-aRot.getY() - 0.5));
+ aRect.Union(tools::Rectangle(aRotPnt, aRotPnt));
+
+ aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Bottom());
+ aRot *= aLatheMat;
+ aRot.setX(-aRot.getX());
+ aRot *= aInvLatheMat;
+ aRotPnt = Point(static_cast<tools::Long>(aRot.getX() + 0.5), static_cast<tools::Long>(-aRot.getY() - 0.5));
+ aRect.Union(tools::Rectangle(aRotPnt, aRotPnt));
+ }
+ }
+
+ // Walk through the selection and convert it into 3D, complete with
+ // Conversion to SdrPathObject, also fonts
+ for(size_t a=0; a<GetMarkedObjectCount(); ++a)
+ {
+ SdrMark* pMark = GetSdrMarkByIndex(a);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ ImpCreate3DObject(pScene, pObj, bExtrude, fDepth, aLatheMat);
+ }
+
+ if(pScene->GetSubList() && pScene->GetSubList()->GetObjCount() != 0)
+ {
+ // Arrange all created objects by depth
+ if(bExtrude)
+ DoDepthArrange(pScene, fDepth);
+
+ // Center 3D objects in the middle of the overall rectangle
+ basegfx::B3DPoint aCenter(pScene->GetBoundVolume().getCenter());
+ basegfx::B3DHomMatrix aMatrix;
+
+ aMatrix.translate(-aCenter.getX(), -aCenter.getY(), -aCenter.getZ());
+ pScene->SetTransform(aMatrix * pScene->GetTransform());
+
+ // Initialize scene
+ pScene->NbcSetSnapRect(aRect);
+ basegfx::B3DRange aBoundVol = pScene->GetBoundVolume();
+ InitScene(pScene, static_cast<double>(aRect.GetWidth()), static_cast<double>(aRect.GetHeight()), aBoundVol.getDepth());
+
+ // Insert scene instead of the first selected object and throw away
+ // all the old objects
+ SdrObject* pRepObj = GetMarkedObjectByIndex(0);
+ SdrPageView* pPV = GetSdrPageViewOfMarkedByIndex(0);
+ MarkObj(pRepObj, pPV, true);
+ ReplaceObjectAtView(pRepObj, *pPV, pScene, false);
+ DeleteMarked();
+ MarkObj(pScene, pPV);
+
+ // Rotate Rotation body around the axis of rotation
+ if(!bExtrude && fRot3D != 0.0)
+ {
+ basegfx::B3DHomMatrix aRotate;
+ aRotate.rotate(0.0, 0.0, fRot3D);
+ pScene->SetTransform(aRotate * pScene->GetTransform());
+ }
+
+ // Set default rotation
+ {
+ basegfx::B3DHomMatrix aRotate;
+ aRotate.rotate(basegfx::deg2rad(20.0), 0.0, 0.0);
+ // E3DModifySceneSnapRectUpdater updates the 2D representation of the scene.
+ // It prepares things in ctor and acts in dtor.
+ E3DModifySceneSnapRectUpdater aUpdater(pScene->getSdrObjectFromSdrObjList());
+ pScene->SetTransform(aRotate * pScene->GetTransform());
+ }
+ }
+ else
+ {
+ // No 3D object was created, throw away everything
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pScene);
+ SdrObject::Free(pTemp);
+ }
+
+ EndUndo();
+}
+
+//Arrange all created extrude objects by depth
+
+namespace {
+
+struct E3dDepthNeighbour
+{
+ E3dExtrudeObj* mpObj;
+ basegfx::B2DPolyPolygon maPreparedPolyPolygon;
+
+ E3dDepthNeighbour(E3dExtrudeObj* pObj, basegfx::B2DPolyPolygon const & rPreparedPolyPolygon)
+ : mpObj(pObj),
+ maPreparedPolyPolygon(rPreparedPolyPolygon)
+ {
+ }
+};
+
+struct E3dDepthLayer
+{
+ E3dDepthLayer* mpDown;
+ std::vector<E3dDepthNeighbour> mvNeighbours;
+
+ E3dDepthLayer()
+ : mpDown(nullptr)
+ {
+ }
+};
+
+}
+
+void E3dView::DoDepthArrange(E3dScene const * pScene, double fDepth)
+{
+ if(!(pScene && pScene->GetSubList() && pScene->GetSubList()->GetObjCount() > 1))
+ return;
+
+ SdrObjList* pSubList = pScene->GetSubList();
+ SdrObjListIter aIter(pSubList, SdrIterMode::Flat);
+ E3dDepthLayer* pBaseLayer = nullptr;
+ E3dDepthLayer* pLayer = nullptr;
+ sal_Int32 nNumLayers = 0;
+
+ while(aIter.IsMore())
+ {
+ E3dExtrudeObj* pExtrudeObj = dynamic_cast< E3dExtrudeObj* >(aIter.Next());
+
+ if(pExtrudeObj)
+ {
+ const basegfx::B2DPolyPolygon aExtrudePoly(
+ basegfx::utils::prepareForPolygonOperation(pExtrudeObj->GetExtrudePolygon()));
+ const SfxItemSet& rLocalSet = pExtrudeObj->GetMergedItemSet();
+ const drawing::FillStyle eLocalFillStyle = rLocalSet.Get(XATTR_FILLSTYLE).GetValue();
+ const Color aLocalColor = rLocalSet.Get(XATTR_FILLCOLOR).GetColorValue();
+
+ // sort in ExtrudeObj
+ if(pLayer)
+ {
+ // do we have overlap with an object of this layer?
+ bool bOverlap(false);
+
+ for(const auto& rAct : pLayer->mvNeighbours)
+ {
+ // do rAct.mpObj and pExtrudeObj overlap? Check by
+ // using logical AND clipping
+ const basegfx::B2DPolyPolygon aAndPolyPolygon(
+ basegfx::utils::solvePolygonOperationAnd(
+ aExtrudePoly,
+ rAct.maPreparedPolyPolygon));
+
+ if(aAndPolyPolygon.count() != 0)
+ {
+ // second criteria: is another fillstyle or color used?
+ const SfxItemSet& rCompareSet = rAct.mpObj->GetMergedItemSet();
+
+ drawing::FillStyle eCompareFillStyle = rCompareSet.Get(XATTR_FILLSTYLE).GetValue();
+
+ if(eLocalFillStyle == eCompareFillStyle)
+ {
+ if(eLocalFillStyle == drawing::FillStyle_SOLID)
+ {
+ Color aCompareColor = rCompareSet.Get(XATTR_FILLCOLOR).GetColorValue();
+
+ if(aCompareColor == aLocalColor)
+ {
+ continue;
+ }
+ }
+ else if(eLocalFillStyle == drawing::FillStyle_NONE)
+ {
+ continue;
+ }
+ }
+
+ bOverlap = true;
+ break;
+ }
+ }
+
+ if(bOverlap)
+ {
+ // yes, start a new layer
+ pLayer->mpDown = new E3dDepthLayer;
+ pLayer = pLayer->mpDown;
+ nNumLayers++;
+ pLayer->mvNeighbours.emplace_back(pExtrudeObj, aExtrudePoly);
+ }
+ else
+ {
+ // no, add to current layer
+ pLayer->mvNeighbours.emplace(pLayer->mvNeighbours.begin(), pExtrudeObj, aExtrudePoly);
+ }
+ }
+ else
+ {
+ // first layer ever
+ pBaseLayer = new E3dDepthLayer;
+ pLayer = pBaseLayer;
+ nNumLayers++;
+ pLayer->mvNeighbours.emplace_back(pExtrudeObj, aExtrudePoly);
+ }
+ }
+ }
+
+ // number of layers is done
+ if(nNumLayers > 1)
+ {
+ // need to be arranged
+ double fMinDepth = fDepth * 0.8;
+ double fStep = (fDepth - fMinDepth) / static_cast<double>(nNumLayers);
+ pLayer = pBaseLayer;
+
+ while(pLayer)
+ {
+ // move along layer
+ for(auto& rAct : pLayer->mvNeighbours)
+ {
+ // adapt extrude value
+ rAct.mpObj->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH, sal_uInt32(fMinDepth + 0.5)));
+ }
+
+ // next layer
+ pLayer = pLayer->mpDown;
+ fMinDepth += fStep;
+ }
+ }
+
+ // cleanup
+ while(pBaseLayer)
+ {
+ pLayer = pBaseLayer->mpDown;
+ delete pBaseLayer;
+ pBaseLayer = pLayer;
+ }
+}
+
+// Start drag, create for 3D objects before possibly drag method
+
+bool E3dView::BegDragObj(const Point& rPnt, OutputDevice* pOut,
+ SdrHdl* pHdl, short nMinMov,
+ SdrDragMethod* pForcedMeth)
+{
+ if(Is3DRotationCreationActive() && GetMarkedObjectCount())
+ {
+ // Determine all selected polygons and return the mirrored helper overlay
+ mpMirrorOverlay->SetMirrorAxis(maRef1, maRef2);
+ }
+ else
+ {
+ bool bOwnActionNecessary;
+ if (pHdl == nullptr)
+ {
+ bOwnActionNecessary = true;
+ }
+ else if (pHdl->IsVertexHdl() || pHdl->IsCornerHdl())
+ {
+ bOwnActionNecessary = true;
+ }
+ else
+ {
+ bOwnActionNecessary = false;
+ }
+
+ if(bOwnActionNecessary && GetMarkedObjectCount() > 0)
+ {
+ E3dDragConstraint eConstraint = E3dDragConstraint::XYZ;
+ bool bThereAreRootScenes = false;
+ bool bThereAre3DObjects = false;
+ const size_t nCnt = GetMarkedObjectCount();
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(pObj)
+ {
+ if( auto pScene = dynamic_cast< const E3dScene* >(pObj) )
+ if( pScene->getRootE3dSceneFromE3dObject() == pObj )
+ bThereAreRootScenes = true;
+
+ if(dynamic_cast< const E3dObject* >(pObj) != nullptr)
+ {
+ bThereAre3DObjects = true;
+ }
+ }
+ }
+ if( bThereAre3DObjects )
+ {
+ meDragHdl = ( pHdl == nullptr ? SdrHdlKind::Move : pHdl->GetKind() );
+ switch ( meDragMode )
+ {
+ case SdrDragMode::Rotate:
+ case SdrDragMode::Shear:
+ {
+ switch ( meDragHdl )
+ {
+ case SdrHdlKind::Left:
+ case SdrHdlKind::Right:
+ {
+ eConstraint = E3dDragConstraint::X;
+ }
+ break;
+
+ case SdrHdlKind::Upper:
+ case SdrHdlKind::Lower:
+ {
+ eConstraint = E3dDragConstraint::Y;
+ }
+ break;
+
+ case SdrHdlKind::UpperLeft:
+ case SdrHdlKind::UpperRight:
+ case SdrHdlKind::LowerLeft:
+ case SdrHdlKind::LowerRight:
+ {
+ eConstraint = E3dDragConstraint::Z;
+ }
+ break;
+ default: break;
+ }
+
+ // do not mask the allowed rotations
+ eConstraint &= E3dDragConstraint::XYZ;
+ pForcedMeth = new E3dDragRotate(*this, GetMarkedObjectList(), eConstraint, IsSolidDragging());
+ }
+ break;
+
+ case SdrDragMode::Move:
+ {
+ if(!bThereAreRootScenes)
+ {
+ pForcedMeth = new E3dDragMove(*this, GetMarkedObjectList(), meDragHdl, eConstraint, IsSolidDragging());
+ }
+ }
+ break;
+
+ // later on
+ case SdrDragMode::Mirror:
+ case SdrDragMode::Crook:
+ case SdrDragMode::Transparence:
+ case SdrDragMode::Gradient:
+ default:
+ {
+ }
+ break;
+ }
+ }
+ }
+ }
+ return SdrView::BegDragObj(rPnt, pOut, pHdl, nMinMov, pForcedMeth);
+}
+
+// Set current 3D drawing object, create the scene for this
+E3dScene* E3dView::SetCurrent3DObj(E3dObject* p3DObj)
+{
+ DBG_ASSERT(p3DObj != nullptr, "Who puts in a NULL-pointer here");
+
+ // get transformed BoundVolume of the object
+ basegfx::B3DRange aVolume(p3DObj->GetBoundVolume());
+ aVolume.transform(p3DObj->GetTransform());
+ double fW(aVolume.getWidth());
+ double fH(aVolume.getHeight());
+
+ tools::Rectangle aRect(0,0, static_cast<tools::Long>(fW), static_cast<tools::Long>(fH));
+
+ E3dScene* pScene = new E3dScene(p3DObj->getSdrModelFromSdrObject());
+
+ InitScene(pScene, fW, fH, aVolume.getMaxZ() + ((fW + fH) / 4.0));
+
+ pScene->InsertObject(p3DObj);
+ pScene->NbcSetSnapRect(aRect);
+
+ return pScene;
+}
+
+void E3dView::InitScene(E3dScene* pScene, double fW, double fH, double fCamZ)
+{
+ Camera3D aCam(pScene->GetCamera());
+
+ aCam.SetAutoAdjustProjection(false);
+ aCam.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
+ basegfx::B3DPoint aLookAt;
+
+ double fDefaultCamPosZ = GetDefaultCamPosZ();
+ basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
+
+ aCam.SetPosAndLookAt(aCamPos, aLookAt);
+ aCam.SetFocalLength(GetDefaultCamFocal());
+ pScene->SetCamera(aCam);
+}
+
+void E3dView::Start3DCreation()
+{
+ if (!GetMarkedObjectCount())
+ return;
+
+ //positioned
+ tools::Long nOutMin = 0;
+ tools::Long nOutMax = 0;
+ tools::Long nMinLen = 0;
+ tools::Long nObjDst = 0;
+ tools::Long nOutHgt = 0;
+ OutputDevice* pOut = GetFirstOutputDevice();
+
+ // first determine representation boundaries
+ if (pOut != nullptr)
+ {
+ nMinLen = pOut->PixelToLogic(Size(0,50)).Height();
+ nObjDst = pOut->PixelToLogic(Size(0,20)).Height();
+
+ tools::Long nDst = pOut->PixelToLogic(Size(0,10)).Height();
+
+ nOutMin = -pOut->GetMapMode().GetOrigin().Y();
+ nOutMax = pOut->GetOutputSize().Height() - 1 + nOutMin;
+ nOutMin += nDst;
+ nOutMax -= nDst;
+
+ if (nOutMax - nOutMin < nDst)
+ {
+ nOutMin += nOutMax + 1;
+ nOutMin /= 2;
+ nOutMin -= (nDst + 1) / 2;
+ nOutMax = nOutMin + nDst;
+ }
+
+ nOutHgt = nOutMax - nOutMin;
+
+ tools::Long nTemp = nOutHgt / 4;
+ if (nTemp > nMinLen) nMinLen = nTemp;
+ }
+
+ // and then attach the marks at the top and bottom of the object
+ basegfx::B2DRange aR;
+ for(size_t nMark = 0; nMark < GetMarkedObjectCount(); ++nMark)
+ {
+ SdrObject* pMark = GetMarkedObjectByIndex(nMark);
+ basegfx::B2DPolyPolygon aXPP(pMark->TakeXorPoly());
+ aR.expand(basegfx::utils::getRange(aXPP));
+ }
+
+ basegfx::B2DPoint aCenter(aR.getCenter());
+ tools::Long nMarkHgt = basegfx::fround(aR.getHeight()) - 1;
+ tools::Long nHgt = nMarkHgt + nObjDst * 2;
+
+ if (nHgt < nMinLen) nHgt = nMinLen;
+
+ tools::Long nY1 = basegfx::fround(aCenter.getY()) - (nHgt + 1) / 2;
+ tools::Long nY2 = nY1 + nHgt;
+
+ if (pOut && (nMinLen > nOutHgt)) nMinLen = nOutHgt;
+ if (pOut)
+ {
+ if (nY1 < nOutMin)
+ {
+ nY1 = nOutMin;
+ if (nY2 < nY1 + nMinLen) nY2 = nY1 + nMinLen;
+ }
+ if (nY2 > nOutMax)
+ {
+ nY2 = nOutMax;
+ if (nY1 > nY2 - nMinLen) nY1 = nY2 - nMinLen;
+ }
+ }
+
+ maRef1.setX( basegfx::fround(aR.getMinX()) ); // Initial move axis 2/100mm to the left
+ maRef1.setY( nY1 );
+ maRef2.setX( maRef1.X() );
+ maRef2.setY( nY2 );
+
+ // Turn on marks
+ SetMarkHandles(nullptr);
+
+ //HMHif (bVis) ShowMarkHdl();
+ if (AreObjectsMarked()) MarkListHasChanged();
+
+ // Show mirror polygon IMMEDIATELY
+ const SdrHdlList &aHdlList = GetHdlList();
+ mpMirrorOverlay.reset(new Impl3DMirrorConstructOverlay(*this));
+ mpMirrorOverlay->SetMirrorAxis(aHdlList.GetHdl(SdrHdlKind::Ref1)->GetPos(), aHdlList.GetHdl(SdrHdlKind::Ref2)->GetPos());
+}
+
+// what happens with a mouse movement when the object is created?
+
+void E3dView::MovAction(const Point& rPnt)
+{
+ if(Is3DRotationCreationActive())
+ {
+ SdrHdl* pHdl = GetDragHdl();
+
+ if (pHdl)
+ {
+ SdrHdlKind eHdlKind = pHdl->GetKind();
+
+ // reacts only due to a mirror axis
+ if ((eHdlKind == SdrHdlKind::Ref1) ||
+ (eHdlKind == SdrHdlKind::Ref2) ||
+ (eHdlKind == SdrHdlKind::MirrorAxis))
+ {
+ const SdrHdlList &aHdlList = GetHdlList ();
+
+ // delete the mirrored polygon, mirrors the original and draws
+ // it anew
+ SdrView::MovAction (rPnt);
+ mpMirrorOverlay->SetMirrorAxis(
+ aHdlList.GetHdl (SdrHdlKind::Ref1)->GetPos(),
+ aHdlList.GetHdl (SdrHdlKind::Ref2)->GetPos());
+ }
+ }
+ else
+ {
+ SdrView::MovAction (rPnt);
+ }
+ }
+ else
+ {
+ SdrView::MovAction (rPnt);
+ }
+}
+
+// The End. Create object and any child objects through ImpCreate3DLathe.
+// With the parameter value sal_True (SDefault: sal_False) is simply a
+// rotation body created, without letting the user set the position of the
+// axis. It is sufficient with this call, if an object is selected.
+// (No initialization necessary)
+
+void E3dView::End3DCreation(bool bUseDefaultValuesForMirrorAxes)
+{
+ ResetCreationActive();
+
+ if(!AreObjectsMarked())
+ return;
+
+ if(bUseDefaultValuesForMirrorAxes)
+ {
+ tools::Rectangle aRect = GetAllMarkedRect();
+ if(aRect.GetWidth() <= 1)
+ aRect.SetSize(Size(500, aRect.GetHeight()));
+ if(aRect.GetHeight() <= 1)
+ aRect.SetSize(Size(aRect.GetWidth(), 500));
+
+ basegfx::B2DPoint aPnt1(aRect.Left(), -aRect.Top());
+ basegfx::B2DPoint aPnt2(aRect.Left(), -aRect.Bottom());
+
+ ConvertMarkedObjTo3D(false, aPnt1, aPnt2);
+ }
+ else
+ {
+ // Turn off helper overlay
+ // Determine from the handle positions and the displacement of
+ // the points
+ const SdrHdlList &aHdlList = GetHdlList();
+ Point aMirrorRef1 = aHdlList.GetHdl(SdrHdlKind::Ref1)->GetPos();
+ Point aMirrorRef2 = aHdlList.GetHdl(SdrHdlKind::Ref2)->GetPos();
+
+ basegfx::B2DPoint aPnt1(aMirrorRef1.X(), -aMirrorRef1.Y());
+ basegfx::B2DPoint aPnt2(aMirrorRef2.X(), -aMirrorRef2.Y());
+
+ ConvertMarkedObjTo3D(false, aPnt1, aPnt2);
+ }
+}
+
+E3dView::~E3dView ()
+{
+}
+
+void E3dView::ResetCreationActive ()
+{
+ mpMirrorOverlay.reset();
+}
+
+void E3dView::InitView ()
+{
+ mpMirrorOverlay = nullptr;
+}
+
+bool E3dView::IsBreak3DObjPossible() const
+{
+ const size_t nCount = GetMarkedObjectCount();
+
+ if (nCount > 0)
+ {
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(i);
+
+ if (auto p3dObject = dynamic_cast< E3dObject* >(pObj))
+ {
+ if(!p3dObject->IsBreakObjPossible())
+ return false;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void E3dView::Break3DObj()
+{
+ if(!IsBreak3DObjPossible())
+ return;
+
+ // ALL selected objects are changed
+ const size_t nCount = GetMarkedObjectCount();
+
+ BegUndo(SvxResId(RID_SVX_3D_UNDO_BREAK_LATHE));
+ for(size_t a=0; a<nCount; ++a)
+ {
+ E3dObject* pObj = static_cast<E3dObject*>(GetMarkedObjectByIndex(a));
+ BreakSingle3DObj(pObj);
+ }
+ DeleteMarked();
+ EndUndo();
+}
+
+void E3dView::BreakSingle3DObj(E3dObject* pObj)
+{
+ if(dynamic_cast< const E3dScene* >(pObj) != nullptr)
+ {
+ SdrObjList* pSubList = pObj->GetSubList();
+ SdrObjListIter aIter(pSubList, SdrIterMode::Flat);
+
+ while(aIter.IsMore())
+ {
+ E3dObject* pSubObj = static_cast<E3dObject*>(aIter.Next());
+ BreakSingle3DObj(pSubObj);
+ }
+ }
+ else
+ {
+ SdrAttrObj* pNewObj = pObj->GetBreakObj().release();
+ if (pNewObj)
+ {
+ if (InsertObjectAtView(pNewObj, *GetSdrPageView(), SdrInsertFlags::DONTMARK))
+ {
+ pNewObj->SetChanged();
+ pNewObj->BroadcastObjectChange();
+ }
+ }
+ }
+}
+
+void E3dView::CheckPossibilities()
+{
+ // call parent
+ SdrView::CheckPossibilities();
+
+ // Set other flags
+ if(!(m_bGroupPossible || m_bUnGroupPossible || m_bGrpEnterPossible))
+ return;
+
+ const size_t nMarkCnt = GetMarkedObjectCount();
+ bool bCompound = false;
+ bool b3DObject = false;
+ for(size_t nObjs = 0; (nObjs < nMarkCnt) && !bCompound; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(dynamic_cast< const E3dCompoundObject* >(pObj))
+ bCompound = true;
+ if(dynamic_cast< const E3dObject* >(pObj))
+ b3DObject = true;
+ }
+
+ // So far: there are two or more of any objects selected. See if
+ // compound objects are involved. If yes, ban grouping.
+ if(m_bGroupPossible && bCompound)
+ m_bGroupPossible = false;
+
+ if(m_bUnGroupPossible && b3DObject)
+ m_bUnGroupPossible = false;
+
+ if(m_bGrpEnterPossible && bCompound)
+ m_bGrpEnterPossible = false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/view3d1.cxx b/svx/source/engine3d/view3d1.cxx
new file mode 100644
index 000000000..22ec229bf
--- /dev/null
+++ b/svx/source/engine3d/view3d1.cxx
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svl/itempool.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svxids.hrc>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/lathe3d.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/sphere3d.hxx>
+#include <extrud3d.hxx>
+#include <svx/view3d.hxx>
+#include <svx/cube3d.hxx>
+#include <svx/xlineit0.hxx>
+#include <com/sun/star/drawing/LineStyle.hpp>
+
+void E3dView::ConvertMarkedToPolyObj()
+{
+ SdrObject* pNewObj = nullptr;
+
+ if (GetMarkedObjectCount() == 1)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(0);
+
+ if (pObj)
+ {
+ auto pScene = dynamic_cast< const E3dScene* >(pObj);
+ if (pScene)
+ {
+ pNewObj = pScene->ConvertToPolyObj(false/*bBezier*/, false/*bLineToArea*/).release();
+ if (pNewObj)
+ {
+ BegUndo(SvxResId(RID_SVX_3D_UNDO_EXTRUDE));
+ ReplaceObjectAtView(pObj, *GetSdrPageView(), pNewObj);
+ EndUndo();
+ }
+ }
+ }
+ }
+
+ if (!pNewObj)
+ {
+ SdrView::ConvertMarkedToPolyObj();
+ }
+}
+
+static void Imp_E3dView_InorderRun3DObjects(const SdrObject* pObj, sal_uInt32& rMask)
+{
+ if(dynamic_cast< const E3dLatheObj* >(pObj) != nullptr)
+ {
+ rMask |= 0x0001;
+ }
+ else if(dynamic_cast< const E3dExtrudeObj* >(pObj) != nullptr)
+ {
+ rMask |= 0x0002;
+ }
+ else if(dynamic_cast< const E3dSphereObj* >(pObj) != nullptr)
+ {
+ rMask |= 0x0004;
+ }
+ else if(dynamic_cast< const E3dCubeObj* >(pObj) != nullptr)
+ {
+ rMask |= 0x0008;
+ }
+ else if(pObj->IsGroupObject())
+ {
+ SdrObjList* pList = pObj->GetSubList();
+ for(size_t a = 0; a < pList->GetObjCount(); ++a)
+ Imp_E3dView_InorderRun3DObjects(pList->GetObj(a), rMask);
+ }
+}
+
+SfxItemSet E3dView::Get3DAttributes() const
+{
+ // Creating itemset with corresponding field
+ SfxItemSet aSet(
+ mpModel->GetItemPool(),
+ svl::Items<SDRATTR_START, SDRATTR_END,
+ SID_ATTR_3D_INTERN, SID_ATTR_3D_INTERN>);
+
+ sal_uInt32 nSelectedItems(0);
+
+ // get attributes from all selected objects
+ MergeAttrFromMarked(aSet, false);
+
+ // calc flags for SID_ATTR_3D_INTERN
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ const size_t nMarkCnt(rMarkList.GetMarkCount());
+
+ for(size_t a = 0; a < nMarkCnt; ++a)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(a);
+ Imp_E3dView_InorderRun3DObjects(pObj, nSelectedItems);
+ }
+
+ // Set SID_ATTR_3D_INTERN on the status of the selected objects
+ aSet.Put(SfxUInt32Item(SID_ATTR_3D_INTERN, nSelectedItems));
+
+ // maintain default values
+ if(!nSelectedItems)
+ {
+ // Get defaults and apply
+ SfxItemSetFixed<SDRATTR_3D_FIRST, SDRATTR_3D_LAST> aDefaultSet(mpModel->GetItemPool());
+ GetAttributes(aDefaultSet);
+ aSet.Put(aDefaultSet);
+
+ // ... but no lines for 3D
+ aSet.Put(XLineStyleItem (css::drawing::LineStyle_NONE));
+
+ // new defaults for distance and focal length
+ aSet.Put(makeSvx3DDistanceItem(100));
+ aSet.Put(makeSvx3DFocalLengthItem(10000));
+ }
+
+ // return ItemSet
+ return aSet;
+}
+
+void E3dView::Set3DAttributes( const SfxItemSet& rAttr)
+{
+ sal_uInt32 nSelectedItems(0);
+
+ // #i94832# removed usage of E3DModifySceneSnapRectUpdater here.
+ // They are not needed here, they are already handled in SetAttrToMarked
+
+ // set at selected objects
+ SetAttrToMarked(rAttr, false/*bReplaceAll*/);
+
+ // old run
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ const size_t nMarkCnt(rMarkList.GetMarkCount());
+
+ for(size_t a = 0; a < nMarkCnt; ++a)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(a);
+ Imp_E3dView_InorderRun3DObjects(pObj, nSelectedItems);
+ }
+
+ // Maintain default values
+ if(!nSelectedItems)
+ {
+ // Set defaults
+ SfxItemSetFixed<SDRATTR_3D_FIRST, SDRATTR_3D_LAST> aDefaultSet(mpModel->GetItemPool());
+ aDefaultSet.Put(rAttr);
+ SetAttributes(aDefaultSet);
+ }
+}
+
+double E3dView::GetDefaultCamPosZ()
+{
+ return static_cast<double>(mpModel->GetItemPool().GetDefaultItem(SDRATTR_3DSCENE_DISTANCE).GetValue());
+}
+
+double E3dView::GetDefaultCamFocal()
+{
+ return static_cast<double>(mpModel->GetItemPool().GetDefaultItem(SDRATTR_3DSCENE_FOCAL_LENGTH).GetValue());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/viewpt3d2.cxx b/svx/source/engine3d/viewpt3d2.cxx
new file mode 100644
index 000000000..c2e55a085
--- /dev/null
+++ b/svx/source/engine3d/viewpt3d2.cxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/viewpt3d.hxx>
+
+Viewport3D::Viewport3D() :
+ aVRP(0, 0, 5),
+ aVPN(0, 0, 1),
+ aVUV(0, 1, 1),
+ aPRP(0, 0, 2),
+ eProjection(ProjectionType::Perspective),
+ aDeviceRect(Point(0,0), Size(-1,-1)),
+ aViewPoint (0, 0, 5000),
+ bTfValid(false)
+{
+ aViewWin.X = -1; aViewWin.Y = -1;
+ aViewWin.W = 2; aViewWin.H = 2;
+}
+
+// Set ViewWindow (in View coordinates)
+
+void Viewport3D::SetViewWindow(double fX, double fY, double fW, double fH)
+{
+ aViewWin.X = fX;
+ aViewWin.Y = fY;
+ if ( fW > 0 ) aViewWin.W = fW;
+ else aViewWin.W = 1.0;
+ if ( fH > 0 ) aViewWin.H = fH;
+ else aViewWin.H = 1.0;
+}
+
+// Returns observer position (PRP) in world coordinates
+
+const basegfx::B3DPoint& Viewport3D::GetViewPoint()
+{
+ // Calculate View transformations matrix
+ if ( !bTfValid )
+ {
+ double fV, fXupVp, fYupVp;
+ aViewPoint = aVRP + aVPN * aPRP.getZ();
+
+ // Reset to Identity matrix
+ aViewTf.identity();
+
+ // shift in the origin
+ aViewTf.translate(-aVRP.getX(), -aVRP.getY(), -aVRP.getZ());
+
+ // fV = Length of the projection of aVPN on the yz plane:
+ fV = aVPN.getYZLength();
+
+ if ( fV != 0 )
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(aVPN.getY() / fV);
+ const double fCos(aVPN.getZ() / fV);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(1, 1, fCos);
+ aTemp.set(2, 1, fSin);
+ aTemp.set(1, 2, -fSin);
+ aViewTf *= aTemp;
+ }
+
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(-aVPN.getX());
+ const double fCos(fV);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(0, 0, fCos);
+ aTemp.set(0, 2, fSin);
+ aTemp.set(2, 0, -fSin);
+ aViewTf *= aTemp;
+ }
+
+ // Convert X- and Y- coordinates of the view up vector to the
+ // (preliminary) view coordinate system.
+ fXupVp = aViewTf.get(0, 0) * aVUV.getX() + aViewTf.get(0, 1) * aVUV.getY() + aViewTf.get(0, 2) * aVUV.getZ();
+ fYupVp = aViewTf.get(1, 0) * aVUV.getX() + aViewTf.get(1, 1) * aVUV.getY() + aViewTf.get(1, 2) * aVUV.getZ();
+ fV = std::hypot(fXupVp, fYupVp);
+
+ if ( fV != 0 )
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(fXupVp / fV);
+ const double fCos(fYupVp / fV);
+ aTemp.set(1, 1, fCos);
+ aTemp.set(0, 0, fCos);
+ aTemp.set(1, 0, fSin);
+ aTemp.set(0, 1, -fSin);
+ aViewTf *= aTemp;
+ }
+
+ bTfValid = true;
+ }
+ return aViewPoint;
+}
+
+void Viewport3D::SetDeviceWindow(const tools::Rectangle& rRect)
+{
+ aDeviceRect = rRect;
+}
+
+// Set View Reference Point
+
+void Viewport3D::SetVRP(const basegfx::B3DPoint& rNewVRP)
+{
+ aVRP = rNewVRP;
+ bTfValid = false;
+}
+
+// Set View Plane Normal
+
+void Viewport3D::SetVPN(const basegfx::B3DVector& rNewVPN)
+{
+ aVPN = rNewVPN;
+ aVPN.normalize();
+ bTfValid = false;
+}
+
+// Set View Up Vector
+
+void Viewport3D::SetVUV(const basegfx::B3DVector& rNewVUV)
+{
+ aVUV = rNewVUV;
+ bTfValid = false;
+}
+
+// Set Center Of Projection
+
+void Viewport3D::SetPRP(const basegfx::B3DPoint& rNewPRP)
+{
+ aPRP = rNewPRP;
+ aPRP.setX(0.0);
+ aPRP.setY(0.0);
+ bTfValid = false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/fmcomp/dbaexchange.cxx b/svx/source/fmcomp/dbaexchange.cxx
new file mode 100644
index 000000000..904740e38
--- /dev/null
+++ b/svx/source/fmcomp/dbaexchange.cxx
@@ -0,0 +1,630 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dbaexchange.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <fmprop.hxx>
+#include <comphelper/extract.hxx>
+#include <sot/formats.hxx>
+#include <sot/exchange.hxx>
+#include <o3tl/string_view.hxx>
+
+
+namespace svx
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::datatransfer;
+
+ OColumnTransferable::OColumnTransferable(ColumnTransferFormatFlags nFormats)
+ : m_nFormatFlags(nFormats)
+ {
+ }
+
+ void OColumnTransferable::setDescriptor(const ODataAccessDescriptor& rDescriptor)
+ {
+ ClearFormats();
+
+ OUString sDataSource, sDatabaseLocation, sConnectionResource, sCommand, sFieldName;
+ if ( rDescriptor.has( DataAccessDescriptorProperty::DataSource ) ) rDescriptor[ DataAccessDescriptorProperty::DataSource ] >>= sDataSource;
+ if ( rDescriptor.has( DataAccessDescriptorProperty::DatabaseLocation ) ) rDescriptor[ DataAccessDescriptorProperty::DatabaseLocation ] >>= sDatabaseLocation;
+ if ( rDescriptor.has( DataAccessDescriptorProperty::ConnectionResource ) ) rDescriptor[ DataAccessDescriptorProperty::ConnectionResource ] >>= sConnectionResource;
+ if ( rDescriptor.has( DataAccessDescriptorProperty::Command ) ) rDescriptor[ DataAccessDescriptorProperty::Command ] >>= sCommand;
+ if ( rDescriptor.has( DataAccessDescriptorProperty::ColumnName ) ) rDescriptor[ DataAccessDescriptorProperty::ColumnName ] >>= sFieldName;
+
+ sal_Int32 nCommandType = CommandType::TABLE;
+ OSL_VERIFY( rDescriptor[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType );
+
+ implConstruct(
+ sDataSource.isEmpty() ? sDatabaseLocation : sDataSource,
+ sConnectionResource, nCommandType, sCommand, sFieldName );
+
+ if ( m_nFormatFlags & ColumnTransferFormatFlags::COLUMN_DESCRIPTOR )
+ {
+ if ( rDescriptor.has( DataAccessDescriptorProperty::Connection ) )
+ m_aDescriptor[ DataAccessDescriptorProperty::Connection ] = rDescriptor[ DataAccessDescriptorProperty::Connection ];
+ if ( rDescriptor.has( DataAccessDescriptorProperty::ColumnObject ) )
+ m_aDescriptor[ DataAccessDescriptorProperty::ColumnObject ] = rDescriptor[ DataAccessDescriptorProperty::ColumnObject ];
+ }
+ }
+
+ OColumnTransferable::OColumnTransferable(const Reference< XPropertySet >& _rxForm,
+ const OUString& _rFieldName, const Reference< XPropertySet >& _rxColumn,
+ const Reference< XConnection >& _rxConnection, ColumnTransferFormatFlags _nFormats)
+ :m_nFormatFlags(_nFormats)
+ {
+ OSL_ENSURE(_rxForm.is(), "OColumnTransferable::OColumnTransferable: invalid form!");
+ // collect the necessary information from the form
+ OUString sCommand;
+ sal_Int32 nCommandType = CommandType::TABLE;
+ OUString sDatasource,sURL;
+
+ bool bTryToParse = true;
+ try
+ {
+ _rxForm->getPropertyValue(FM_PROP_COMMANDTYPE) >>= nCommandType;
+ _rxForm->getPropertyValue(FM_PROP_COMMAND) >>= sCommand;
+ _rxForm->getPropertyValue(FM_PROP_DATASOURCE) >>= sDatasource;
+ _rxForm->getPropertyValue(FM_PROP_URL) >>= sURL;
+ bTryToParse = ::cppu::any2bool(_rxForm->getPropertyValue(FM_PROP_ESCAPE_PROCESSING));
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("OColumnTransferable::OColumnTransferable: could not collect essential data source attributes !");
+ }
+
+ // If the data source is an SQL-statement and simple enough (means "select <field list> from <table> where...")
+ // we are able to fake the drag information we are about to create.
+ if (bTryToParse && (CommandType::COMMAND == nCommandType))
+ {
+ try
+ {
+ Reference< XTablesSupplier > xSupTab;
+ _rxForm->getPropertyValue("SingleSelectQueryComposer") >>= xSupTab;
+
+ if(xSupTab.is())
+ {
+ Reference< XNameAccess > xNames = xSupTab->getTables();
+ if (xNames.is())
+ {
+ Sequence< OUString > aTables = xNames->getElementNames();
+ if (1 == aTables.getLength())
+ {
+ sCommand = aTables[0];
+ nCommandType = CommandType::TABLE;
+ }
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("OColumnTransferable::OColumnTransferable: could not collect essential data source attributes (part two) !");
+ }
+ }
+
+ implConstruct(sDatasource, sURL,nCommandType, sCommand, _rFieldName);
+
+ if ((m_nFormatFlags & ColumnTransferFormatFlags::COLUMN_DESCRIPTOR) == ColumnTransferFormatFlags::COLUMN_DESCRIPTOR)
+ {
+ if (_rxColumn.is())
+ m_aDescriptor[DataAccessDescriptorProperty::ColumnObject] <<= _rxColumn;
+ if (_rxConnection.is())
+ m_aDescriptor[DataAccessDescriptorProperty::Connection] <<= _rxConnection;
+ }
+ }
+
+
+ SotClipboardFormatId OColumnTransferable::getDescriptorFormatId()
+ {
+ static SotClipboardFormatId s_nFormat = static_cast<SotClipboardFormatId>(-1);
+ if (static_cast<SotClipboardFormatId>(-1) == s_nFormat)
+ {
+ s_nFormat = SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"dbaccess.ColumnDescriptorTransfer\"");
+ OSL_ENSURE(static_cast<SotClipboardFormatId>(-1) != s_nFormat, "OColumnTransferable::getDescriptorFormatId: bad exchange id!");
+ }
+ return s_nFormat;
+ }
+
+
+ void OColumnTransferable::implConstruct( const OUString& _rDatasource
+ ,const OUString& _rConnectionResource
+ ,const sal_Int32 _nCommandType
+ ,const OUString& _rCommand
+ , const OUString& _rFieldName)
+ {
+ const sal_Unicode cSeparator = u'\x000B';
+ const OUString sSeparator(&cSeparator, 1);
+
+ m_sCompatibleFormat.clear();
+ m_sCompatibleFormat += _rDatasource;
+ m_sCompatibleFormat += sSeparator;
+ m_sCompatibleFormat += _rCommand;
+ m_sCompatibleFormat += sSeparator;
+
+ sal_Unicode cCommandType;
+ switch (_nCommandType)
+ {
+ case CommandType::TABLE:
+ cCommandType = '0';
+ break;
+ case CommandType::QUERY:
+ cCommandType = '1';
+ break;
+ default:
+ cCommandType = '2';
+ break;
+ }
+ m_sCompatibleFormat += OUStringChar(cCommandType);
+ m_sCompatibleFormat += sSeparator;
+ m_sCompatibleFormat += _rFieldName;
+
+ m_aDescriptor.clear();
+ if ((m_nFormatFlags & ColumnTransferFormatFlags::COLUMN_DESCRIPTOR) == ColumnTransferFormatFlags::COLUMN_DESCRIPTOR)
+ {
+ m_aDescriptor.setDataSource(_rDatasource);
+ if ( !_rConnectionResource.isEmpty() )
+ m_aDescriptor[DataAccessDescriptorProperty::ConnectionResource] <<= _rConnectionResource;
+
+ m_aDescriptor[DataAccessDescriptorProperty::Command] <<= _rCommand;
+ m_aDescriptor[DataAccessDescriptorProperty::CommandType] <<= _nCommandType;
+ m_aDescriptor[DataAccessDescriptorProperty::ColumnName] <<= _rFieldName;
+ }
+ }
+
+
+ void OColumnTransferable::AddSupportedFormats()
+ {
+ if (ColumnTransferFormatFlags::CONTROL_EXCHANGE & m_nFormatFlags)
+ AddFormat(SotClipboardFormatId::SBA_CTRLDATAEXCHANGE);
+
+ if (ColumnTransferFormatFlags::FIELD_DESCRIPTOR & m_nFormatFlags)
+ AddFormat(SotClipboardFormatId::SBA_FIELDDATAEXCHANGE);
+
+ if (ColumnTransferFormatFlags::COLUMN_DESCRIPTOR & m_nFormatFlags)
+ AddFormat(getDescriptorFormatId());
+ }
+
+
+ bool OColumnTransferable::GetData( const DataFlavor& _rFlavor, const OUString& /*rDestDoc*/ )
+ {
+ const SotClipboardFormatId nFormatId = SotExchange::GetFormat(_rFlavor);
+ switch (nFormatId)
+ {
+ case SotClipboardFormatId::SBA_FIELDDATAEXCHANGE:
+ case SotClipboardFormatId::SBA_CTRLDATAEXCHANGE:
+ return SetString(m_sCompatibleFormat);
+ default: break;
+ }
+ if (nFormatId == getDescriptorFormatId())
+ return SetAny( Any( m_aDescriptor.createPropertyValueSequence() ) );
+
+ return false;
+ }
+
+
+ bool OColumnTransferable::canExtractColumnDescriptor(const DataFlavorExVector& _rFlavors, ColumnTransferFormatFlags _nFormats)
+ {
+ bool bFieldFormat = bool(_nFormats & ColumnTransferFormatFlags::FIELD_DESCRIPTOR);
+ bool bControlFormat = bool(_nFormats & ColumnTransferFormatFlags::CONTROL_EXCHANGE);
+ bool bDescriptorFormat = bool(_nFormats & ColumnTransferFormatFlags::COLUMN_DESCRIPTOR);
+ SotClipboardFormatId nFormatId = getDescriptorFormatId();
+ return std::any_of(_rFlavors.begin(), _rFlavors.end(),
+ [&](const DataFlavorEx& rCheck) {
+ return (bFieldFormat && (SotClipboardFormatId::SBA_FIELDDATAEXCHANGE == rCheck.mnSotId))
+ || (bControlFormat && (SotClipboardFormatId::SBA_CTRLDATAEXCHANGE == rCheck.mnSotId))
+ || (bDescriptorFormat && (nFormatId == rCheck.mnSotId));
+ });
+ }
+
+
+ ODataAccessDescriptor OColumnTransferable::extractColumnDescriptor(const TransferableDataHelper& _rData)
+ {
+ if (_rData.HasFormat(getDescriptorFormatId()))
+ {
+ // the object has a real descriptor object (not just the old compatible format)
+
+ // extract the any from the transferable
+ DataFlavor aFlavor;
+ bool bSuccess =
+ SotExchange::GetFormatDataFlavor(getDescriptorFormatId(), aFlavor);
+ OSL_ENSURE(bSuccess, "OColumnTransferable::extractColumnDescriptor: invalid data format (no flavor)!");
+
+ Any aDescriptor = _rData.GetAny(aFlavor, OUString());
+
+ // extract the property value sequence
+ Sequence< PropertyValue > aDescriptorProps;
+ bSuccess = aDescriptor >>= aDescriptorProps;
+ OSL_ENSURE(bSuccess, "OColumnTransferable::extractColumnDescriptor: invalid clipboard format!");
+
+ // build the real descriptor
+ return ODataAccessDescriptor(aDescriptorProps);
+ }
+
+ // only the old (compatible) format exists -> use the other extract method ...
+ OUString sDatasource, sCommand, sFieldName,sDatabaseLocation,sConnectionResource;
+ sal_Int32 nCommandType = CommandType::COMMAND;
+
+ ODataAccessDescriptor aDescriptor;
+ if (extractColumnDescriptor(_rData, sDatasource, sDatabaseLocation,sConnectionResource,nCommandType, sCommand, sFieldName))
+ {
+ // and build an own descriptor
+ if ( !sDatasource.isEmpty() )
+ aDescriptor[DataAccessDescriptorProperty::DataSource] <<= sDatasource;
+ if ( !sDatabaseLocation.isEmpty() )
+ aDescriptor[DataAccessDescriptorProperty::DatabaseLocation] <<= sDatabaseLocation;
+ if ( !sConnectionResource.isEmpty() )
+ aDescriptor[DataAccessDescriptorProperty::ConnectionResource] <<= sConnectionResource;
+
+ aDescriptor[DataAccessDescriptorProperty::Command] <<= sCommand;
+ aDescriptor[DataAccessDescriptorProperty::CommandType] <<= nCommandType;
+ aDescriptor[DataAccessDescriptorProperty::ColumnName] <<= sFieldName;
+ }
+ return aDescriptor;
+ }
+
+
+ bool OColumnTransferable::extractColumnDescriptor(const TransferableDataHelper& _rData
+ ,OUString& _rDatasource
+ ,OUString& _rDatabaseLocation
+ ,OUString& _rConnectionResource
+ ,sal_Int32& _nCommandType
+ ,OUString& _rCommand
+ ,OUString& _rFieldName)
+ {
+ if ( _rData.HasFormat(getDescriptorFormatId()) )
+ {
+ ODataAccessDescriptor aDescriptor = extractColumnDescriptor(_rData);
+ if ( aDescriptor.has(DataAccessDescriptorProperty::DataSource) )
+ aDescriptor[DataAccessDescriptorProperty::DataSource] >>= _rDatasource;
+ if ( aDescriptor.has(DataAccessDescriptorProperty::DatabaseLocation) )
+ aDescriptor[DataAccessDescriptorProperty::DatabaseLocation] >>= _rDatabaseLocation;
+ if ( aDescriptor.has(DataAccessDescriptorProperty::ConnectionResource) )
+ aDescriptor[DataAccessDescriptorProperty::ConnectionResource] >>= _rConnectionResource;
+
+ aDescriptor[DataAccessDescriptorProperty::Command] >>= _rCommand;
+ aDescriptor[DataAccessDescriptorProperty::CommandType] >>= _nCommandType;
+ aDescriptor[DataAccessDescriptorProperty::ColumnName] >>= _rFieldName;
+ return true;
+ }
+
+ // check if we have a (string) format we can use...
+ SotClipboardFormatId nRecognizedFormat = SotClipboardFormatId::NONE;
+ if (_rData.HasFormat(SotClipboardFormatId::SBA_FIELDDATAEXCHANGE))
+ nRecognizedFormat = SotClipboardFormatId::SBA_FIELDDATAEXCHANGE;
+ if (_rData.HasFormat(SotClipboardFormatId::SBA_CTRLDATAEXCHANGE))
+ nRecognizedFormat = SotClipboardFormatId::SBA_CTRLDATAEXCHANGE;
+ if (nRecognizedFormat == SotClipboardFormatId::NONE)
+ return false;
+
+ OUString sFieldDescription;
+ (void)_rData.GetString(nRecognizedFormat, sFieldDescription);
+
+ const sal_Unicode cSeparator = u'\x000B';
+ sal_Int32 nIdx{ 0 };
+ _rDatasource = sFieldDescription.getToken(0, cSeparator, nIdx);
+ _rCommand = sFieldDescription.getToken(0, cSeparator, nIdx);
+ _nCommandType = o3tl::toInt32(o3tl::getToken(sFieldDescription, 0, cSeparator, nIdx));
+ _rFieldName = sFieldDescription.getToken(0, cSeparator, nIdx);
+
+ return true;
+ }
+
+ ODataAccessObjectTransferable::ODataAccessObjectTransferable()
+ {
+ }
+
+ void ODataAccessObjectTransferable::Update(
+ const OUString& _rDatasource,
+ const sal_Int32 _nCommandType,
+ const OUString& _rCommand)
+ {
+ construct(_rDatasource,OUString(),_nCommandType,_rCommand,nullptr,(CommandType::COMMAND == _nCommandType),_rCommand);
+ }
+
+ void ODataAccessObjectTransferable::Update(
+ const OUString& _rDatasource,
+ const sal_Int32 _nCommandType,
+ const OUString& _rCommand,
+ const Reference< XConnection >& _rxConnection)
+ {
+ OSL_ENSURE(_rxConnection.is(), "Wrong Update used.!");
+ construct(_rDatasource,OUString(),_nCommandType,_rCommand,_rxConnection,(CommandType::COMMAND == _nCommandType),_rCommand);
+ }
+
+ ODataAccessObjectTransferable::ODataAccessObjectTransferable(const Reference< XPropertySet >& _rxLivingForm)
+ {
+ // collect some properties of the form
+ OUString sDatasourceName,sConnectionResource;
+ sal_Int32 nObjectType = CommandType::COMMAND;
+ OUString sObjectName;
+ Reference< XConnection > xConnection;
+ try
+ {
+ _rxLivingForm->getPropertyValue(FM_PROP_COMMANDTYPE) >>= nObjectType;
+ _rxLivingForm->getPropertyValue(FM_PROP_COMMAND) >>= sObjectName;
+ _rxLivingForm->getPropertyValue(FM_PROP_DATASOURCE) >>= sDatasourceName;
+ _rxLivingForm->getPropertyValue(FM_PROP_URL) >>= sConnectionResource;
+ _rxLivingForm->getPropertyValue(FM_PROP_ACTIVE_CONNECTION) >>= xConnection;
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("ODataAccessObjectTransferable::ODataAccessObjectTransferable: could not collect essential form attributes !");
+ return;
+ }
+
+ // check if the SQL-statement is modified
+ OUString sCompleteStatement;
+ try
+ {
+ _rxLivingForm->getPropertyValue(FM_PROP_ACTIVECOMMAND) >>= sCompleteStatement;
+ }
+ catch (const Exception&)
+ {
+ OSL_FAIL("ODataAccessObjectTransferable::ODataAccessObjectTransferable: could not collect essential form attributes (part two) !");
+ return;
+ }
+
+ construct( sDatasourceName
+ ,sConnectionResource
+ ,nObjectType
+ ,sObjectName,xConnection
+ ,CommandType::QUERY != nObjectType
+ ,sCompleteStatement);
+ }
+
+
+ void ODataAccessObjectTransferable::AddSupportedFormats()
+ {
+ sal_Int32 nObjectType = CommandType::COMMAND;
+ m_aDescriptor[DataAccessDescriptorProperty::CommandType] >>= nObjectType;
+ switch (nObjectType)
+ {
+ case CommandType::TABLE:
+ AddFormat(SotClipboardFormatId::DBACCESS_TABLE);
+ break;
+ case CommandType::QUERY:
+ AddFormat(SotClipboardFormatId::DBACCESS_QUERY);
+ break;
+ case CommandType::COMMAND:
+ AddFormat(SotClipboardFormatId::DBACCESS_COMMAND);
+ break;
+ }
+
+ if (!m_sCompatibleObjectDescription.isEmpty())
+ AddFormat(SotClipboardFormatId::SBA_DATAEXCHANGE);
+ }
+
+
+ bool ODataAccessObjectTransferable::GetData( const DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+ {
+ SotClipboardFormatId nFormat = SotExchange::GetFormat(rFlavor);
+ switch (nFormat)
+ {
+ case SotClipboardFormatId::DBACCESS_TABLE:
+ case SotClipboardFormatId::DBACCESS_QUERY:
+ case SotClipboardFormatId::DBACCESS_COMMAND:
+ return SetAny( Any(m_aDescriptor.createPropertyValueSequence()) );
+
+ case SotClipboardFormatId::SBA_DATAEXCHANGE:
+ return SetString(m_sCompatibleObjectDescription);
+ default: break;
+ }
+ return false;
+ }
+
+
+ bool ODataAccessObjectTransferable::canExtractObjectDescriptor(const DataFlavorExVector& _rFlavors)
+ {
+ return std::any_of(_rFlavors.begin(), _rFlavors.end(),
+ [](const DataFlavorEx& rCheck) {
+ return SotClipboardFormatId::DBACCESS_TABLE == rCheck.mnSotId
+ || SotClipboardFormatId::DBACCESS_QUERY == rCheck.mnSotId
+ || SotClipboardFormatId::DBACCESS_COMMAND == rCheck.mnSotId;
+ });
+ }
+
+
+ ODataAccessDescriptor ODataAccessObjectTransferable::extractObjectDescriptor(const TransferableDataHelper& _rData)
+ {
+ SotClipboardFormatId nKnownFormatId = SotClipboardFormatId::NONE;
+ if ( _rData.HasFormat( SotClipboardFormatId::DBACCESS_TABLE ) )
+ nKnownFormatId = SotClipboardFormatId::DBACCESS_TABLE;
+ if ( _rData.HasFormat( SotClipboardFormatId::DBACCESS_QUERY ) )
+ nKnownFormatId = SotClipboardFormatId::DBACCESS_QUERY;
+ if ( _rData.HasFormat( SotClipboardFormatId::DBACCESS_COMMAND ) )
+ nKnownFormatId = SotClipboardFormatId::DBACCESS_COMMAND;
+
+ if (SotClipboardFormatId::NONE != nKnownFormatId)
+ {
+ // extract the any from the transferable
+ DataFlavor aFlavor;
+ bool bSuccess =
+ SotExchange::GetFormatDataFlavor(nKnownFormatId, aFlavor);
+ OSL_ENSURE(bSuccess, "OColumnTransferable::extractColumnDescriptor: invalid data format (no flavor)!");
+
+ Any aDescriptor = _rData.GetAny(aFlavor, OUString());
+
+ // extract the property value sequence
+ Sequence< PropertyValue > aDescriptorProps;
+ bSuccess = aDescriptor >>= aDescriptorProps;
+ OSL_ENSURE(bSuccess, "OColumnTransferable::extractColumnDescriptor: invalid clipboard format!");
+
+ // build the real descriptor
+ return ODataAccessDescriptor(aDescriptorProps);
+ }
+
+ OSL_FAIL( "OColumnTransferable::extractColumnDescriptor: unsupported formats only!" );
+ return ODataAccessDescriptor();
+ }
+
+
+ void ODataAccessObjectTransferable::addCompatibleSelectionDescription( const Sequence< Any >& _rSelRows )
+ {
+ const sal_Unicode cSeparator(11);
+ const OUString sSeparator(&cSeparator, 1);
+
+ for ( const Any& rSelRow : _rSelRows )
+ {
+ sal_Int32 nSelectedRow( 0 );
+ OSL_VERIFY( rSelRow >>= nSelectedRow );
+
+ m_sCompatibleObjectDescription += OUString::number(nSelectedRow);
+ m_sCompatibleObjectDescription += sSeparator;
+ }
+ }
+
+
+ void ODataAccessObjectTransferable::ObjectReleased()
+ {
+ m_aDescriptor.clear();
+ }
+
+ void ODataAccessObjectTransferable::construct( const OUString& _rDatasource
+ ,const OUString& _rConnectionResource
+ ,const sal_Int32 _nCommandType
+ ,const OUString& _rCommand
+ ,const Reference< XConnection >& _rxConnection
+ ,bool _bAddCommand
+ ,const OUString& _sActiveCommand)
+ {
+ m_aDescriptor.setDataSource(_rDatasource);
+ // build the descriptor (the property sequence)
+ if ( !_rConnectionResource.isEmpty() )
+ m_aDescriptor[DataAccessDescriptorProperty::ConnectionResource] <<= _rConnectionResource;
+ if ( _rxConnection.is() )
+ m_aDescriptor[DataAccessDescriptorProperty::Connection] <<= _rxConnection;
+ m_aDescriptor[DataAccessDescriptorProperty::Command] <<= _rCommand;
+ m_aDescriptor[DataAccessDescriptorProperty::CommandType] <<= _nCommandType;
+
+ // extract the single values from the sequence
+
+ OUString sObjectName = _rCommand;
+
+ // for compatibility: create a string which can be used for the SotClipboardFormatId::SBA_DATAEXCHANGE format
+
+ bool bTreatAsStatement = (CommandType::COMMAND == _nCommandType);
+ // statements are - in this old and ugly format - described as queries
+
+ const sal_Unicode cSeparator = u'\x000B';
+ const OUString sSeparator(&cSeparator, 1);
+
+ const sal_Unicode cTableMark = '1';
+ const sal_Unicode cQueryMark = '0';
+
+ // build the descriptor string
+ m_sCompatibleObjectDescription += _rDatasource;
+ m_sCompatibleObjectDescription += sSeparator;
+ m_sCompatibleObjectDescription += bTreatAsStatement ? OUString() : sObjectName;
+ m_sCompatibleObjectDescription += sSeparator;
+ switch (_nCommandType)
+ {
+ case CommandType::TABLE:
+ m_sCompatibleObjectDescription += OUStringChar(cTableMark);
+ break;
+ case CommandType::QUERY:
+ m_sCompatibleObjectDescription += OUStringChar(cQueryMark);
+ break;
+ case CommandType::COMMAND:
+ m_sCompatibleObjectDescription += OUStringChar(cQueryMark);
+ // think of it as a query
+ break;
+ }
+ m_sCompatibleObjectDescription += sSeparator;
+ m_sCompatibleObjectDescription += _bAddCommand ? _sActiveCommand : OUString();
+ m_sCompatibleObjectDescription += sSeparator;
+ }
+
+ OMultiColumnTransferable::OMultiColumnTransferable()
+ {
+ }
+
+ void OMultiColumnTransferable::setDescriptors(const Sequence< PropertyValue >& rDescriptors)
+ {
+ ClearFormats();
+ m_aDescriptors = rDescriptors;
+ }
+
+ SotClipboardFormatId OMultiColumnTransferable::getDescriptorFormatId()
+ {
+ static SotClipboardFormatId s_nFormat = static_cast<SotClipboardFormatId>(-1);
+ if (static_cast<SotClipboardFormatId>(-1) == s_nFormat)
+ {
+ s_nFormat = SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"dbaccess.MultipleColumnDescriptorTransfer\"");
+ OSL_ENSURE(static_cast<SotClipboardFormatId>(-1) != s_nFormat, "OColumnTransferable::getDescriptorFormatId: bad exchange id!");
+ }
+ return s_nFormat;
+ }
+
+ void OMultiColumnTransferable::AddSupportedFormats()
+ {
+ AddFormat(getDescriptorFormatId());
+ }
+
+ bool OMultiColumnTransferable::GetData( const DataFlavor& _rFlavor, const OUString& /*rDestDoc*/ )
+ {
+ const SotClipboardFormatId nFormatId = SotExchange::GetFormat(_rFlavor);
+ if (nFormatId == getDescriptorFormatId())
+ {
+ return SetAny( Any( m_aDescriptors ) );
+ }
+
+ return false;
+ }
+
+ bool OMultiColumnTransferable::canExtractDescriptor(const DataFlavorExVector& _rFlavors)
+ {
+ const SotClipboardFormatId nFormatId = getDescriptorFormatId();
+ return std::all_of(_rFlavors.begin(), _rFlavors.end(),
+ [&nFormatId](const DataFlavorEx& rCheck) { return nFormatId == rCheck.mnSotId; });
+ }
+
+ Sequence< PropertyValue > OMultiColumnTransferable::extractDescriptor(const TransferableDataHelper& _rData)
+ {
+ Sequence< PropertyValue > aList;
+ if (_rData.HasFormat(getDescriptorFormatId()))
+ {
+ // extract the any from the transferable
+ DataFlavor aFlavor;
+ bool bSuccess =
+ SotExchange::GetFormatDataFlavor(getDescriptorFormatId(), aFlavor);
+ OSL_ENSURE(bSuccess, "OColumnTransferable::extractColumnDescriptor: invalid data format (no flavor)!");
+
+ _rData.GetAny(aFlavor, OUString()) >>= aList;
+ } // if (_rData.HasFormat(getDescriptorFormatId()))
+ return aList;
+ }
+
+ void OMultiColumnTransferable::ObjectReleased()
+ {
+ m_aDescriptors.realloc(0);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/fmcomp/dbaobjectex.cxx b/svx/source/fmcomp/dbaobjectex.cxx
new file mode 100644
index 000000000..e3d22d2c3
--- /dev/null
+++ b/svx/source/fmcomp/dbaobjectex.cxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dbaobjectex.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <sot/formats.hxx>
+#include <sot/exchange.hxx>
+
+
+namespace svx
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::ucb;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::datatransfer;
+
+ OComponentTransferable::OComponentTransferable()
+ {
+ }
+
+ void OComponentTransferable::Update(const OUString& rDatasourceOrLocation
+ ,const Reference< XContent>& xContent)
+ {
+ ClearFormats();
+
+ m_aDescriptor.setDataSource(rDatasourceOrLocation);
+ m_aDescriptor[DataAccessDescriptorProperty::Component] <<= xContent;
+
+ AddSupportedFormats();
+ }
+
+ SotClipboardFormatId OComponentTransferable::getDescriptorFormatId(bool _bExtractForm)
+ {
+ static SotClipboardFormatId s_nReportFormat = static_cast<SotClipboardFormatId>(-1);
+ static SotClipboardFormatId s_nFormFormat = static_cast<SotClipboardFormatId>(-1);
+ if ( _bExtractForm && static_cast<SotClipboardFormatId>(-1) == s_nFormFormat )
+ {
+ s_nFormFormat = SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"dbaccess.FormComponentDescriptorTransfer\"");
+ OSL_ENSURE(static_cast<SotClipboardFormatId>(-1) != s_nFormFormat, "OComponentTransferable::getDescriptorFormatId: bad exchange id!");
+ }
+ else if ( !_bExtractForm && static_cast<SotClipboardFormatId>(-1) == s_nReportFormat)
+ {
+ s_nReportFormat = SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"dbaccess.ReportComponentDescriptorTransfer\"");
+ OSL_ENSURE(static_cast<SotClipboardFormatId>(-1) != s_nReportFormat, "OComponentTransferable::getDescriptorFormatId: bad exchange id!");
+ }
+ return _bExtractForm ? s_nFormFormat : s_nReportFormat;
+ }
+
+
+ void OComponentTransferable::AddSupportedFormats()
+ {
+ bool bForm = true;
+ try
+ {
+ Reference<XPropertySet> xProp;
+ m_aDescriptor[DataAccessDescriptorProperty::Component] >>= xProp;
+ if ( xProp.is() )
+ xProp->getPropertyValue("IsForm") >>= bForm;
+ }
+ catch(const Exception&)
+ {}
+ AddFormat(getDescriptorFormatId(bForm));
+ }
+
+
+ bool OComponentTransferable::GetData( const DataFlavor& _rFlavor, const OUString& /*rDestDoc*/ )
+ {
+ const SotClipboardFormatId nFormatId = SotExchange::GetFormat(_rFlavor);
+ if ( nFormatId == getDescriptorFormatId(true) || nFormatId == getDescriptorFormatId(false) )
+ return SetAny( Any( m_aDescriptor.createPropertyValueSequence() ) );
+
+ return false;
+ }
+
+
+ bool OComponentTransferable::canExtractComponentDescriptor(const DataFlavorExVector& _rFlavors, bool _bForm )
+ {
+ SotClipboardFormatId nFormatId = getDescriptorFormatId(_bForm);
+ return std::any_of(_rFlavors.begin(), _rFlavors.end(),
+ [&nFormatId](const DataFlavorEx& rCheck) { return nFormatId == rCheck.mnSotId; });
+ }
+
+
+ ODataAccessDescriptor OComponentTransferable::extractComponentDescriptor(const TransferableDataHelper& _rData)
+ {
+ bool bForm = _rData.HasFormat(getDescriptorFormatId(true));
+ if ( bForm || _rData.HasFormat(getDescriptorFormatId(false)) )
+ {
+ // the object has a real descriptor object (not just the old compatible format)
+
+ // extract the any from the transferable
+ DataFlavor aFlavor;
+ bool bSuccess =
+ SotExchange::GetFormatDataFlavor(getDescriptorFormatId(bForm), aFlavor);
+ OSL_ENSURE(bSuccess, "OComponentTransferable::extractColumnDescriptor: invalid data format (no flavor)!");
+
+ Any aDescriptor = _rData.GetAny(aFlavor, OUString());
+
+ // extract the property value sequence
+ Sequence< PropertyValue > aDescriptorProps;
+ bSuccess = aDescriptor >>= aDescriptorProps;
+ OSL_ENSURE(bSuccess, "OComponentTransferable::extractColumnDescriptor: invalid clipboard format!");
+
+ // build the real descriptor
+ return ODataAccessDescriptor(aDescriptorProps);
+ }
+
+ return ODataAccessDescriptor();
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/fmcomp/fmgridcl.cxx b/svx/source/fmcomp/fmgridcl.cxx
new file mode 100644
index 000000000..aacac128e
--- /dev/null
+++ b/svx/source/fmcomp/fmgridcl.cxx
@@ -0,0 +1,2096 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/fmgridif.hxx>
+#include <fmprop.hxx>
+#include <svx/fmtools.hxx>
+#include <fmservs.hxx>
+#include <fmurl.hxx>
+#include <formcontrolfactory.hxx>
+#include <gridcell.hxx>
+#include <gridcols.hxx>
+#include <svx/dbaexchange.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/fmgridcl.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/svxids.hrc>
+#include <bitmaps.hlst>
+
+#include <com/sun/star/form/XConfirmDeleteListener.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/form/XGridColumnFactory.hpp>
+#include <com/sun/star/io/XPersistObject.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/RowChangeAction.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/eitem.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/debug.hxx>
+#include <tools/multisel.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/help.hxx>
+#include <vcl/settings.hxx>
+#include <sal/log.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <memory>
+#include <string_view>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::container;
+using namespace ::cppu;
+using namespace ::svxform;
+using namespace ::svx;
+using namespace ::dbtools;
+
+struct FmGridHeaderData
+{
+ ODataAccessDescriptor aDropData;
+ Point aDropPosPixel;
+ sal_Int8 nDropAction;
+ Reference< XInterface > xDroppedStatement;
+ Reference< XInterface > xDroppedResultSet;
+};
+
+static void InsertMenuItem(weld::Menu& rMenu, int nMenuPos, std::string_view id, const OUString& rText, const OUString& rImgId)
+{
+ rMenu.insert(nMenuPos, OUString::fromUtf8(id), rText, &rImgId, nullptr, nullptr, TRISTATE_INDET);
+}
+
+FmGridHeader::FmGridHeader( BrowseBox* pParent, WinBits nWinBits)
+ :EditBrowserHeader(pParent, nWinBits)
+ ,DropTargetHelper(this)
+ ,m_pImpl(new FmGridHeaderData)
+{
+}
+
+FmGridHeader::~FmGridHeader()
+{
+ disposeOnce();
+}
+
+void FmGridHeader::dispose()
+{
+ m_pImpl.reset();
+ DropTargetHelper::dispose();
+ svt::EditBrowserHeader::dispose();
+}
+
+sal_uInt16 FmGridHeader::GetModelColumnPos(sal_uInt16 nId) const
+{
+ return static_cast<FmGridControl*>(GetParent())->GetModelColumnPos(nId);
+}
+
+void FmGridHeader::notifyColumnSelect(sal_uInt16 nColumnId)
+{
+ sal_uInt16 nPos = GetModelColumnPos(nColumnId);
+ Reference< XIndexAccess > xColumns = static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns();
+ if ( nPos < xColumns->getCount() )
+ {
+ Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
+ if ( xSelSupplier.is() )
+ {
+ Reference< XPropertySet > xColumn;
+ xColumns->getByIndex(nPos) >>= xColumn;
+ xSelSupplier->select(Any(xColumn));
+ }
+ }
+}
+
+void FmGridHeader::Select()
+{
+ EditBrowserHeader::Select();
+ notifyColumnSelect(GetCurItemId());
+}
+
+void FmGridHeader::RequestHelp( const HelpEvent& rHEvt )
+{
+ sal_uInt16 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
+ if ( nItemId )
+ {
+ if ( rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON) )
+ {
+ tools::Rectangle aItemRect = GetItemRect( nItemId );
+ Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
+ aItemRect.SetLeft( aPt.X() );
+ aItemRect.SetTop( aPt.Y() );
+ aPt = OutputToScreenPixel( aItemRect.BottomRight() );
+ aItemRect.SetRight( aPt.X() );
+ aItemRect.SetBottom( aPt.Y() );
+
+ sal_uInt16 nPos = GetModelColumnPos(nItemId);
+ Reference< css::container::XIndexContainer > xColumns(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
+ try
+ {
+ Reference< css::beans::XPropertySet > xColumn(xColumns->getByIndex(nPos),UNO_QUERY);
+ OUString aHelpText;
+ xColumn->getPropertyValue(FM_PROP_HELPTEXT) >>= aHelpText;
+ if ( aHelpText.isEmpty() )
+ xColumn->getPropertyValue(FM_PROP_DESCRIPTION) >>= aHelpText;
+ if ( !aHelpText.isEmpty() )
+ {
+ if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
+ Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aHelpText );
+ else
+ Help::ShowQuickHelp( this, aItemRect, aHelpText );
+ return;
+ }
+ }
+ catch(Exception&)
+ {
+ return;
+ }
+ }
+ }
+ EditBrowserHeader::RequestHelp( rHEvt );
+}
+
+sal_Int8 FmGridHeader::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ // drop allowed in design mode only
+ if (!static_cast<FmGridControl*>(GetParent())->IsDesignMode())
+ return DND_ACTION_NONE;
+
+ // search for recognized formats
+ const DataFlavorExVector& rFlavors = GetDataFlavorExVector();
+ if (OColumnTransferable::canExtractColumnDescriptor(rFlavors, ColumnTransferFormatFlags::COLUMN_DESCRIPTOR | ColumnTransferFormatFlags::FIELD_DESCRIPTOR))
+ return rEvt.mnAction;
+
+ return DND_ACTION_NONE;
+}
+
+sal_Int8 FmGridHeader::ExecuteDrop( const ExecuteDropEvent& _rEvt )
+{
+ if (!static_cast<FmGridControl*>(GetParent())->IsDesignMode())
+ return DND_ACTION_NONE;
+
+ TransferableDataHelper aDroppedData(_rEvt.maDropEvent.Transferable);
+
+ // check the formats
+ bool bColumnDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), ColumnTransferFormatFlags::COLUMN_DESCRIPTOR);
+ bool bFieldDescriptor = OColumnTransferable::canExtractColumnDescriptor(aDroppedData.GetDataFlavorExVector(), ColumnTransferFormatFlags::FIELD_DESCRIPTOR);
+ if (!bColumnDescriptor && !bFieldDescriptor)
+ {
+ OSL_FAIL("FmGridHeader::ExecuteDrop: should never have reached this (no extractable format)!");
+ return DND_ACTION_NONE;
+ }
+
+ // extract the descriptor
+ OUString sDatasource, sCommand, sFieldName,sDatabaseLocation;
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ Reference< XPreparedStatement > xStatement;
+ Reference< XResultSet > xResultSet;
+ Reference< XPropertySet > xField;
+ Reference< XConnection > xConnection;
+
+ ODataAccessDescriptor aColumn = OColumnTransferable::extractColumnDescriptor(aDroppedData);
+ if (aColumn.has(DataAccessDescriptorProperty::DataSource)) aColumn[DataAccessDescriptorProperty::DataSource] >>= sDatasource;
+ if (aColumn.has(DataAccessDescriptorProperty::DatabaseLocation)) aColumn[DataAccessDescriptorProperty::DatabaseLocation] >>= sDatabaseLocation;
+ if (aColumn.has(DataAccessDescriptorProperty::Command)) aColumn[DataAccessDescriptorProperty::Command] >>= sCommand;
+ if (aColumn.has(DataAccessDescriptorProperty::CommandType)) aColumn[DataAccessDescriptorProperty::CommandType] >>= nCommandType;
+ if (aColumn.has(DataAccessDescriptorProperty::ColumnName)) aColumn[DataAccessDescriptorProperty::ColumnName] >>= sFieldName;
+ if (aColumn.has(DataAccessDescriptorProperty::ColumnObject))aColumn[DataAccessDescriptorProperty::ColumnObject] >>= xField;
+ if (aColumn.has(DataAccessDescriptorProperty::Connection)) aColumn[DataAccessDescriptorProperty::Connection] >>= xConnection;
+
+ if ( sFieldName.isEmpty()
+ || sCommand.isEmpty()
+ || ( sDatasource.isEmpty()
+ && sDatabaseLocation.isEmpty()
+ && !xConnection.is()
+ )
+ )
+ {
+ OSL_FAIL( "FmGridHeader::ExecuteDrop: somebody started a nonsense drag operation!!" );
+ return DND_ACTION_NONE;
+ }
+
+ try
+ {
+ // need a connection
+ if (!xConnection.is())
+ { // the transferable did not contain the connection -> build an own one
+ try
+ {
+ OUString sSignificantSource( sDatasource.isEmpty() ? sDatabaseLocation : sDatasource );
+ xConnection = getConnection_withFeedback(sSignificantSource, OUString(), OUString(),
+ static_cast<FmGridControl*>(GetParent())->getContext(), nullptr );
+ }
+ catch(NoSuchElementException&)
+ { // allowed, means sDatasource isn't a valid data source name...
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("FmGridHeader::ExecuteDrop: could not retrieve the database access object !");
+ }
+
+ if (!xConnection.is())
+ {
+ OSL_FAIL("FmGridHeader::ExecuteDrop: could not retrieve the database access object !");
+ return DND_ACTION_NONE;
+ }
+ }
+
+ // try to obtain the column object
+ if (!xField.is())
+ {
+#ifdef DBG_UTIL
+ Reference< XServiceInfo > xServiceInfo(xConnection, UNO_QUERY);
+ DBG_ASSERT(xServiceInfo.is() && xServiceInfo->supportsService(SRV_SDB_CONNECTION), "FmGridHeader::ExecuteDrop: invalid connection (no database access connection !)");
+#endif
+
+ Reference< XNameAccess > xFields;
+ switch (nCommandType)
+ {
+ case CommandType::TABLE:
+ {
+ Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY);
+ Reference< XColumnsSupplier > xSupplyColumns;
+ xSupplyTables->getTables()->getByName(sCommand) >>= xSupplyColumns;
+ xFields = xSupplyColumns->getColumns();
+ }
+ break;
+ case CommandType::QUERY:
+ {
+ Reference< XQueriesSupplier > xSupplyQueries(xConnection, UNO_QUERY);
+ Reference< XColumnsSupplier > xSupplyColumns;
+ xSupplyQueries->getQueries()->getByName(sCommand) >>= xSupplyColumns;
+ xFields = xSupplyColumns->getColumns();
+ }
+ break;
+ default:
+ {
+ xStatement = xConnection->prepareStatement(sCommand);
+ // not interested in any results
+
+ Reference< XPropertySet > xStatProps(xStatement,UNO_QUERY);
+ xStatProps->setPropertyValue("MaxRows", Any(sal_Int32(0)));
+
+ xResultSet = xStatement->executeQuery();
+ Reference< XColumnsSupplier > xSupplyCols(xResultSet, UNO_QUERY);
+ if (xSupplyCols.is())
+ xFields = xSupplyCols->getColumns();
+ }
+ }
+
+ if (xFields.is() && xFields->hasByName(sFieldName))
+ xFields->getByName(sFieldName) >>= xField;
+
+ if (!xField.is())
+ {
+ ::comphelper::disposeComponent(xStatement);
+ return DND_ACTION_NONE;
+ }
+ }
+
+ // do the drop asynchronously
+ // (85957 - UI actions within the drop are not allowed, but we want to open a popup menu)
+ m_pImpl->aDropData = aColumn;
+ m_pImpl->aDropData[DataAccessDescriptorProperty::Connection] <<= xConnection;
+ m_pImpl->aDropData[DataAccessDescriptorProperty::ColumnObject] <<= xField;
+
+ m_pImpl->nDropAction = _rEvt.mnAction;
+ m_pImpl->aDropPosPixel = _rEvt.maPosPixel;
+ m_pImpl->xDroppedStatement = xStatement;
+ m_pImpl->xDroppedResultSet = xResultSet;
+
+ PostUserEvent(LINK(this, FmGridHeader, OnAsyncExecuteDrop), nullptr, true);
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "caught an exception while creatin' the column !");
+ ::comphelper::disposeComponent(xStatement);
+ return DND_ACTION_NONE;
+ }
+
+ return DND_ACTION_LINK;
+}
+
+IMPL_LINK_NOARG( FmGridHeader, OnAsyncExecuteDrop, void*, void )
+{
+ OUString sCommand, sFieldName,sURL;
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ Reference< XPropertySet > xField;
+ Reference< XConnection > xConnection;
+
+ OUString sDatasource = m_pImpl->aDropData.getDataSource();
+ if ( sDatasource.isEmpty() && m_pImpl->aDropData.has(DataAccessDescriptorProperty::ConnectionResource) )
+ m_pImpl->aDropData[DataAccessDescriptorProperty::ConnectionResource] >>= sURL;
+ m_pImpl->aDropData[DataAccessDescriptorProperty::Command] >>= sCommand;
+ m_pImpl->aDropData[DataAccessDescriptorProperty::CommandType] >>= nCommandType;
+ m_pImpl->aDropData[DataAccessDescriptorProperty::ColumnName] >>= sFieldName;
+ m_pImpl->aDropData[DataAccessDescriptorProperty::Connection] >>= xConnection;
+ m_pImpl->aDropData[DataAccessDescriptorProperty::ColumnObject] >>= xField;
+
+ try
+ {
+ // need number formats
+ Reference< XNumberFormatsSupplier > xSupplier = getNumberFormats(xConnection, true);
+ Reference< XNumberFormats > xNumberFormats;
+ if (xSupplier.is())
+ xNumberFormats = xSupplier->getNumberFormats();
+ if (!xNumberFormats.is())
+ {
+ ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
+ ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
+ return;
+ }
+
+ // The field now needs two pieces of information:
+ // a.) Name of the field for label and ControlSource
+ // b.) FormatKey, to determine which field is to be created
+ sal_Int32 nDataType = 0;
+ xField->getPropertyValue(FM_PROP_FIELDTYPE) >>= nDataType;
+ // these datatypes can not be processed in Gridcontrol
+ switch (nDataType)
+ {
+ case DataType::BLOB:
+ case DataType::LONGVARBINARY:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::OTHER:
+ ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
+ ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
+ return;
+ }
+
+ // Creating the column
+ Reference< XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
+ Reference< XGridColumnFactory > xFactory(xCols, UNO_QUERY);
+
+ sal_uInt16 nColId = GetItemId(m_pImpl->aDropPosPixel);
+ // insert position, always before the current column
+ sal_uInt16 nPos = GetModelColumnPos(nColId);
+ Reference< XPropertySet > xCol, xSecondCol;
+
+ // Create Column based on type, default textfield
+ std::vector<OString> aPossibleTypes;
+ std::vector<OUString> aImgResId;
+ std::vector<TranslateId> aStrResId;
+
+ switch (nDataType)
+ {
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ aPossibleTypes.emplace_back(FM_COL_CHECKBOX);
+ aImgResId.emplace_back(RID_SVXBMP_CHECKBOX);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_CHECKBOX);
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ aPossibleTypes.emplace_back(FM_COL_NUMERICFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_NUMERICFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_NUMERICFIELD);
+ aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_FORMATTED);
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_FORMATTED);
+ aPossibleTypes.emplace_back(FM_COL_NUMERICFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_NUMERICFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_NUMERICFIELD);
+ break;
+ case DataType::TIMESTAMP:
+ aPossibleTypes.emplace_back("dateandtimefield");
+ aImgResId.emplace_back(RID_SVXBMP_DATE_N_TIME_FIELDS);
+ aStrResId.emplace_back(RID_STR_DATE_AND_TIME);
+ aPossibleTypes.emplace_back(FM_COL_DATEFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_DATEFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_DATEFIELD);
+ aPossibleTypes.emplace_back(FM_COL_TIMEFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_TIMEFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_TIMEFIELD);
+ aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_FORMATTED);
+ break;
+ case DataType::DATE:
+ aPossibleTypes.emplace_back(FM_COL_DATEFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_DATEFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_DATEFIELD);
+ aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_FORMATTED);
+ break;
+ case DataType::TIME:
+ aPossibleTypes.emplace_back(FM_COL_TIMEFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_TIMEFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_TIMEFIELD);
+ aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_FORMATTED);
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ default:
+ aPossibleTypes.emplace_back(FM_COL_TEXTFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_EDITBOX);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_EDIT);
+ aPossibleTypes.emplace_back(FM_COL_FORMATTEDFIELD);
+ aImgResId.emplace_back(RID_SVXBMP_FORMATTEDFIELD);
+ aStrResId.emplace_back(RID_STR_PROPTITLE_FORMATTED);
+ break;
+ }
+ // if it's a currency field, a "currency field" option
+ try
+ {
+ if ( ::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField)
+ && ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY)))
+ {
+ aPossibleTypes.insert(aPossibleTypes.begin(), FM_COL_CURRENCYFIELD);
+ aImgResId.insert(aImgResId.begin(), RID_SVXBMP_CURRENCYFIELD);
+ aStrResId.insert(aStrResId.begin(), RID_STR_PROPTITLE_CURRENCYFIELD);
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+
+ assert(aPossibleTypes.size() == aImgResId.size());
+
+ bool bDateNTimeCol = false;
+ if (!aPossibleTypes.empty())
+ {
+ OString sPreferredType = aPossibleTypes[0];
+ if ((m_pImpl->nDropAction == DND_ACTION_LINK) && (aPossibleTypes.size() > 1))
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "svx/ui/colsmenu.ui"));
+ std::unique_ptr<weld::Menu> xTypeMenu(xBuilder->weld_menu("insertmenu"));
+
+ int nMenuPos = 0;
+ std::vector<OString>::const_iterator iter;
+ std::vector<TranslateId>::const_iterator striter;
+ std::vector<OUString>::const_iterator imgiter;
+ for (iter = aPossibleTypes.begin(), imgiter = aImgResId.begin(), striter = aStrResId.begin();
+ iter != aPossibleTypes.end(); ++iter, ++striter, ++imgiter)
+ {
+ InsertMenuItem(*xTypeMenu, nMenuPos++, *iter, SvxResId(*striter), *imgiter);
+ }
+
+ ::tools::Rectangle aRect(m_pImpl->aDropPosPixel, Size(1,1));
+ weld::Window* pParent = weld::GetPopupParent(*this, aRect);
+ OString sResult = xTypeMenu->popup_at_rect(pParent, aRect);
+ if (!sResult.isEmpty())
+ sPreferredType = sResult;
+ }
+
+ bDateNTimeCol = sPreferredType == "dateandtimefield";
+ sal_uInt16 nColCount = bDateNTimeCol ? 2 : 1;
+ OUString sFieldService;
+ while (nColCount--)
+ {
+ if (bDateNTimeCol)
+ sPreferredType = nColCount ? FM_COL_DATEFIELD : FM_COL_TIMEFIELD;
+
+ sFieldService = OUString::fromUtf8(sPreferredType);
+ Reference< XPropertySet > xThisRoundCol;
+ if ( !sFieldService.isEmpty() )
+ xThisRoundCol = xFactory->createColumn(sFieldService);
+ if (nColCount)
+ xSecondCol = xThisRoundCol;
+ else
+ xCol = xThisRoundCol;
+ }
+ }
+
+ if (!xCol.is() || (bDateNTimeCol && !xSecondCol.is()))
+ {
+ ::comphelper::disposeComponent(xCol); // in case only the creation of the second column failed
+ ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
+ ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
+ return;
+ }
+
+ if (bDateNTimeCol)
+ {
+ OUString sTimePostfix(SvxResId(RID_STR_POSTFIX_TIME));
+ xCol->setPropertyValue(FM_PROP_LABEL, Any( OUString( sFieldName + sTimePostfix ) ) );
+
+ OUString sDatePostfix(SvxResId( RID_STR_POSTFIX_DATE));
+ xSecondCol->setPropertyValue(FM_PROP_LABEL, Any( OUString( sFieldName + sDatePostfix ) ) );
+ }
+ else
+ xCol->setPropertyValue(FM_PROP_LABEL, Any(sFieldName));
+
+ // insert now
+ Any aElement;
+ aElement <<= xCol;
+
+ xCols->insertByIndex(nPos, aElement);
+
+ FormControlFactory aControlFactory;
+ aControlFactory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xCol );
+ FormControlFactory::initializeFieldDependentProperties( xField, xCol, xNumberFormats );
+
+ xCol->setPropertyValue(FM_PROP_CONTROLSOURCE, Any(sFieldName));
+ if ( xSecondCol.is() )
+ xSecondCol->setPropertyValue(FM_PROP_CONTROLSOURCE, Any(sFieldName));
+
+ if (bDateNTimeCol)
+ {
+ OUString aPostfix[] = {
+ SvxResId(RID_STR_POSTFIX_DATE),
+ SvxResId(RID_STR_POSTFIX_TIME)
+ };
+
+ for ( size_t i=0; i<2; ++i )
+ {
+ OUString sPurePostfix = comphelper::string::stripStart(aPostfix[i], ' ');
+ sPurePostfix = comphelper::string::stripStart(sPurePostfix, '(');
+ sPurePostfix = comphelper::string::stripEnd(sPurePostfix, ')');
+ OUString sRealName = sFieldName + "_" + sPurePostfix;
+ if (i)
+ xSecondCol->setPropertyValue(FM_PROP_NAME, Any(sRealName));
+ else
+ xCol->setPropertyValue(FM_PROP_NAME, Any(sRealName));
+ }
+ }
+ else
+ xCol->setPropertyValue(FM_PROP_NAME, Any(sFieldName));
+
+ if (bDateNTimeCol)
+ {
+ aElement <<= xSecondCol;
+ xCols->insertByIndex(nPos == sal_uInt16(-1) ? nPos : ++nPos, aElement);
+ }
+
+ // is the component::Form tied to the database?
+ Reference< XFormComponent > xFormCp(xCols, UNO_QUERY);
+ Reference< XPropertySet > xForm(xFormCp->getParent(), UNO_QUERY);
+ if (xForm.is())
+ {
+ if (::comphelper::getString(xForm->getPropertyValue(FM_PROP_DATASOURCE)).isEmpty())
+ {
+ if ( !sDatasource.isEmpty() )
+ xForm->setPropertyValue(FM_PROP_DATASOURCE, Any(sDatasource));
+ else
+ xForm->setPropertyValue(FM_PROP_URL, Any(sURL));
+ }
+
+ if (::comphelper::getString(xForm->getPropertyValue(FM_PROP_COMMAND)).isEmpty())
+ {
+ xForm->setPropertyValue(FM_PROP_COMMAND, Any(sCommand));
+ Any aCommandType;
+ switch (nCommandType)
+ {
+ case CommandType::TABLE:
+ aCommandType <<= sal_Int32(CommandType::TABLE);
+ break;
+ case CommandType::QUERY:
+ aCommandType <<= sal_Int32(CommandType::QUERY);
+ break;
+ default:
+ aCommandType <<= sal_Int32(CommandType::COMMAND);
+ xForm->setPropertyValue(FM_PROP_ESCAPE_PROCESSING, css::uno::Any(2 == nCommandType));
+ break;
+ }
+ xForm->setPropertyValue(FM_PROP_COMMANDTYPE, aCommandType);
+ }
+ }
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "caught an exception while creatin' the column !");
+ ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
+ ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
+ return;
+ }
+
+ ::comphelper::disposeComponent(m_pImpl->xDroppedResultSet);
+ ::comphelper::disposeComponent(m_pImpl->xDroppedStatement);
+}
+
+void FmGridHeader::PreExecuteColumnContextMenu(sal_uInt16 nColId, weld::Menu& rMenu,
+ weld::Menu& rInsertMenu, weld::Menu& rChangeMenu,
+ weld::Menu& rShowMenu)
+{
+ bool bDesignMode = static_cast<FmGridControl*>(GetParent())->IsDesignMode();
+
+ Reference< css::container::XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
+ // Building of the Insert Menu
+ // mark the column if nColId != HEADERBAR_ITEM_NOTFOUND
+ if(nColId > 0)
+ {
+ sal_uInt16 nPos2 = GetModelColumnPos(nColId);
+
+ Reference< css::container::XIndexContainer > xColumns(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
+ Reference< css::beans::XPropertySet> xColumn( xColumns->getByIndex(nPos2), css::uno::UNO_QUERY);
+ Reference< css::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
+ if (xSelSupplier.is())
+ xSelSupplier->select(Any(xColumn));
+ }
+
+ // insert position, always before the current column
+ sal_uInt16 nPos = GetModelColumnPos(nColId);
+ bool bMarked = nColId && static_cast<FmGridControl*>(GetParent())->isColumnMarked(nColId);
+
+ if (bDesignMode)
+ {
+ int nMenuPos = 0;
+ InsertMenuItem(rInsertMenu, nMenuPos++, FM_COL_TEXTFIELD, SvxResId(RID_STR_PROPTITLE_EDIT), RID_SVXBMP_EDITBOX);
+ InsertMenuItem(rInsertMenu, nMenuPos++, FM_COL_CHECKBOX, SvxResId(RID_STR_PROPTITLE_CHECKBOX), RID_SVXBMP_CHECKBOX);
+ InsertMenuItem(rInsertMenu, nMenuPos++, FM_COL_COMBOBOX, SvxResId(RID_STR_PROPTITLE_COMBOBOX), RID_SVXBMP_COMBOBOX);
+ InsertMenuItem(rInsertMenu, nMenuPos++, FM_COL_LISTBOX, SvxResId(RID_STR_PROPTITLE_LISTBOX), RID_SVXBMP_LISTBOX);
+ InsertMenuItem(rInsertMenu, nMenuPos++, FM_COL_DATEFIELD, SvxResId(RID_STR_PROPTITLE_DATEFIELD), RID_SVXBMP_DATEFIELD);
+ InsertMenuItem(rInsertMenu, nMenuPos++, FM_COL_TIMEFIELD, SvxResId(RID_STR_PROPTITLE_TIMEFIELD), RID_SVXBMP_TIMEFIELD);
+ InsertMenuItem(rInsertMenu, nMenuPos++, FM_COL_NUMERICFIELD, SvxResId(RID_STR_PROPTITLE_NUMERICFIELD), RID_SVXBMP_NUMERICFIELD);
+ InsertMenuItem(rInsertMenu, nMenuPos++, FM_COL_CURRENCYFIELD, SvxResId(RID_STR_PROPTITLE_CURRENCYFIELD), RID_SVXBMP_CURRENCYFIELD);
+ InsertMenuItem(rInsertMenu, nMenuPos++, FM_COL_PATTERNFIELD, SvxResId(RID_STR_PROPTITLE_PATTERNFIELD), RID_SVXBMP_PATTERNFIELD);
+ InsertMenuItem(rInsertMenu, nMenuPos++, FM_COL_FORMATTEDFIELD, SvxResId(RID_STR_PROPTITLE_FORMATTED), RID_SVXBMP_FORMATTEDFIELD);
+ }
+
+ if (xCols.is() && nColId)
+ {
+ Reference< css::beans::XPropertySet > xPropSet( xCols->getByIndex(nPos), css::uno::UNO_QUERY);
+
+ Reference< css::io::XPersistObject > xServiceQuestion(xPropSet, UNO_QUERY);
+ sal_Int32 nColType = xServiceQuestion.is() ? getColumnTypeByModelName(xServiceQuestion->getServiceName()) : 0;
+ if (nColType == TYPE_TEXTFIELD)
+ { // edit fields and formatted fields have the same service name, thus getColumnTypeByModelName returns TYPE_TEXTFIELD
+ // in both cases. And as columns don't have a css::lang::XServiceInfo interface, we have to distinguish both
+ // types via the existence of special properties
+ if (xPropSet.is())
+ {
+ Reference< css::beans::XPropertySetInfo > xPropsInfo = xPropSet->getPropertySetInfo();
+ if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(FM_PROP_FORMATSSUPPLIER))
+ nColType = TYPE_FORMATTEDFIELD;
+ }
+ }
+
+ if (bDesignMode)
+ {
+ int nMenuPos = 0;
+ if (nColType != TYPE_TEXTFIELD)
+ InsertMenuItem(rChangeMenu, nMenuPos++, FM_COL_TEXTFIELD"1", SvxResId(RID_STR_PROPTITLE_EDIT), RID_SVXBMP_EDITBOX);
+ if (nColType != TYPE_CHECKBOX)
+ InsertMenuItem(rChangeMenu, nMenuPos++, FM_COL_CHECKBOX"1", SvxResId(RID_STR_PROPTITLE_CHECKBOX), RID_SVXBMP_CHECKBOX);
+ if (nColType != TYPE_COMBOBOX)
+ InsertMenuItem(rChangeMenu, nMenuPos++, FM_COL_COMBOBOX"1", SvxResId(RID_STR_PROPTITLE_COMBOBOX), RID_SVXBMP_COMBOBOX);
+ if (nColType != TYPE_LISTBOX)
+ InsertMenuItem(rChangeMenu, nMenuPos++, FM_COL_LISTBOX"1", SvxResId(RID_STR_PROPTITLE_LISTBOX), RID_SVXBMP_LISTBOX);
+ if (nColType != TYPE_DATEFIELD)
+ InsertMenuItem(rChangeMenu, nMenuPos++, FM_COL_DATEFIELD"1", SvxResId(RID_STR_PROPTITLE_DATEFIELD), RID_SVXBMP_DATEFIELD);
+ if (nColType != TYPE_TIMEFIELD)
+ InsertMenuItem(rChangeMenu, nMenuPos++, FM_COL_TIMEFIELD"1", SvxResId(RID_STR_PROPTITLE_TIMEFIELD), RID_SVXBMP_TIMEFIELD);
+ if (nColType != TYPE_NUMERICFIELD)
+ InsertMenuItem(rChangeMenu, nMenuPos++, FM_COL_NUMERICFIELD"1", SvxResId(RID_STR_PROPTITLE_NUMERICFIELD), RID_SVXBMP_NUMERICFIELD);
+ if (nColType != TYPE_CURRENCYFIELD)
+ InsertMenuItem(rChangeMenu, nMenuPos++, FM_COL_CURRENCYFIELD"1", SvxResId(RID_STR_PROPTITLE_CURRENCYFIELD), RID_SVXBMP_CURRENCYFIELD);
+ if (nColType != TYPE_PATTERNFIELD)
+ InsertMenuItem(rChangeMenu, nMenuPos++, FM_COL_PATTERNFIELD"1", SvxResId(RID_STR_PROPTITLE_PATTERNFIELD), RID_SVXBMP_PATTERNFIELD);
+ if (nColType != TYPE_FORMATTEDFIELD)
+ InsertMenuItem(rChangeMenu, nMenuPos++, FM_COL_FORMATTEDFIELD"1", SvxResId(RID_STR_PROPTITLE_FORMATTED), RID_SVXBMP_FORMATTEDFIELD);
+ }
+
+
+ rMenu.set_visible("change", bDesignMode && bMarked && xCols.is());
+ rMenu.set_sensitive("change", bDesignMode && bMarked && xCols.is());
+ }
+ else
+ {
+ rMenu.set_visible("change", false);
+ rMenu.set_sensitive("change", false);
+ }
+
+ rMenu.set_visible("insert", bDesignMode && xCols.is());
+ rMenu.set_sensitive("insert", bDesignMode && xCols.is());
+ rMenu.set_visible("delete", bDesignMode && bMarked && xCols.is());
+ rMenu.set_sensitive("delete", bDesignMode && bMarked && xCols.is());
+ rMenu.set_visible("column", bDesignMode && bMarked && xCols.is());
+ rMenu.set_sensitive("column", bDesignMode && bMarked && xCols.is());
+
+ sal_uInt16 nHiddenCols = 0;
+ if (xCols.is())
+ {
+ // check for hidden cols
+ Reference< css::beans::XPropertySet > xCurCol;
+ Any aHidden,aName;
+ for (sal_Int32 i=0; i<xCols->getCount(); ++i)
+ {
+ xCurCol.set(xCols->getByIndex(i), css::uno::UNO_QUERY);
+ DBG_ASSERT(xCurCol.is(), "FmGridHeader::PreExecuteColumnContextMenu : the Peer has invalid columns !");
+ aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN);
+ DBG_ASSERT(aHidden.getValueType().getTypeClass() == TypeClass_BOOLEAN,
+ "FmGridHeader::PreExecuteColumnContextMenu : the property 'hidden' should be boolean !");
+ if (::comphelper::getBOOL(aHidden))
+ {
+ // put the column name into the 'show col' menu
+ if (nHiddenCols < 16)
+ {
+ // (only the first 16 items to keep the menu rather small)
+ aName = xCurCol->getPropertyValue(FM_PROP_LABEL);
+ // the ID is arbitrary, but should be unique within the whole menu
+ rMenu.insert(nHiddenCols, OUString::number(nHiddenCols + 1), ::comphelper::getString(aName),
+ nullptr, nullptr, nullptr, TRISTATE_INDET);
+ }
+ ++nHiddenCols;
+ }
+ }
+ }
+ rShowMenu.set_visible("more", xCols.is() && (nHiddenCols > 16));
+ rMenu.set_visible("show", xCols.is() && (nHiddenCols > 0));
+ rMenu.set_sensitive("show", xCols.is() && (nHiddenCols > 0));
+
+ // allow the 'hide column' item ?
+ bool bAllowHide = bMarked; // a column is marked
+ bAllowHide = bAllowHide || (!bDesignMode && (nPos != sal_uInt16(-1))); // OR we are in alive mode and have hit a column
+ bAllowHide = bAllowHide && xCols.is(); // AND we have a column container
+ bAllowHide = bAllowHide && (xCols->getCount()-nHiddenCols > 1); // AND there are at least two visible columns
+ rMenu.set_visible("hide", bAllowHide);
+ rMenu.set_sensitive("hide", bAllowHide);
+
+ if (!bMarked)
+ return;
+
+ SfxViewFrame* pCurrentFrame = SfxViewFrame::Current();
+ // ask the bindings of the current view frame (which should be the one we're residing in) for the state
+ if (pCurrentFrame)
+ {
+ std::unique_ptr<SfxBoolItem> pItem;
+ SfxItemState eState = pCurrentFrame->GetBindings().QueryState(SID_FM_CTL_PROPERTIES, pItem);
+
+ if (eState >= SfxItemState::DEFAULT && pItem != nullptr)
+ {
+ bool bChecked = pItem && pItem->GetValue();
+ rMenu.set_active("column", bChecked);
+ }
+ }
+}
+
+namespace {
+
+enum InspectorAction { eOpenInspector, eCloseInspector, eUpdateInspector, eNone };
+
+}
+
+void FmGridHeader::PostExecuteColumnContextMenu(sal_uInt16 nColId, const weld::Menu& rMenu, const OString& rExecutionResult)
+{
+ Reference< css::container::XIndexContainer > xCols(static_cast<FmGridControl*>(GetParent())->GetPeer()->getColumns());
+ sal_uInt16 nPos = GetModelColumnPos(nColId);
+
+ OUString aFieldType;
+ bool bReplace = false;
+ InspectorAction eInspectorAction = eNone;
+
+ if (rExecutionResult == "delete")
+ {
+ Reference< XInterface > xCol(
+ xCols->getByIndex(nPos), css::uno::UNO_QUERY);
+ xCols->removeByIndex(nPos);
+ ::comphelper::disposeComponent(xCol);
+ }
+ else if (rExecutionResult == "hide")
+ {
+ Reference< css::beans::XPropertySet > xCurCol( xCols->getByIndex(nPos), css::uno::UNO_QUERY);
+ xCurCol->setPropertyValue(FM_PROP_HIDDEN, Any(true));
+ }
+ else if (rExecutionResult == "column")
+ {
+ eInspectorAction = rMenu.get_active("column") ? eOpenInspector : eCloseInspector;
+ }
+ else if (rExecutionResult.startsWith(FM_COL_TEXTFIELD))
+ {
+ if (rExecutionResult != FM_COL_TEXTFIELD)
+ bReplace = true;
+ aFieldType = FM_COL_TEXTFIELD;
+ }
+ else if (rExecutionResult.startsWith(FM_COL_COMBOBOX))
+ {
+ if (rExecutionResult != FM_COL_COMBOBOX)
+ bReplace = true;
+ aFieldType = FM_COL_COMBOBOX;
+ }
+ else if (rExecutionResult.startsWith(FM_COL_LISTBOX))
+ {
+ if (rExecutionResult != FM_COL_LISTBOX)
+ bReplace = true;
+ aFieldType = FM_COL_LISTBOX;
+ }
+ else if (rExecutionResult.startsWith(FM_COL_CHECKBOX))
+ {
+ if (rExecutionResult != FM_COL_CHECKBOX)
+ bReplace = true;
+ aFieldType = FM_COL_CHECKBOX;
+ }
+ else if (rExecutionResult.startsWith(FM_COL_DATEFIELD))
+ {
+ if (rExecutionResult != FM_COL_DATEFIELD)
+ bReplace = true;
+ aFieldType = FM_COL_DATEFIELD;
+ }
+ else if (rExecutionResult.startsWith(FM_COL_TIMEFIELD))
+ {
+ if (rExecutionResult != FM_COL_TIMEFIELD)
+ bReplace = true;
+ aFieldType = FM_COL_TIMEFIELD;
+ }
+ else if (rExecutionResult.startsWith(FM_COL_NUMERICFIELD))
+ {
+ if (rExecutionResult != FM_COL_NUMERICFIELD)
+ bReplace = true;
+ aFieldType = FM_COL_NUMERICFIELD;
+ }
+ else if (rExecutionResult.startsWith(FM_COL_CURRENCYFIELD))
+ {
+ if (rExecutionResult != FM_COL_CURRENCYFIELD)
+ bReplace = true;
+ aFieldType = FM_COL_CURRENCYFIELD;
+ }
+ else if (rExecutionResult.startsWith(FM_COL_PATTERNFIELD))
+ {
+ if (rExecutionResult != FM_COL_PATTERNFIELD)
+ bReplace = true;
+ aFieldType = FM_COL_PATTERNFIELD;
+ }
+ else if (rExecutionResult.startsWith(FM_COL_FORMATTEDFIELD))
+ {
+ if (rExecutionResult != FM_COL_FORMATTEDFIELD)
+ bReplace = true;
+ aFieldType = FM_COL_FORMATTEDFIELD;
+ }
+ else if (rExecutionResult == "more")
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractFmShowColsDialog> pDlg(pFact->CreateFmShowColsDialog(GetFrameWeld()));
+ pDlg->SetColumns(xCols);
+ pDlg->Execute();
+ }
+ else if (rExecutionResult == "all")
+ {
+ // just iterate through all the cols ...
+ Reference< css::beans::XPropertySet > xCurCol;
+ for (sal_Int32 i=0; i<xCols->getCount(); ++i)
+ {
+ xCurCol.set(xCols->getByIndex(i), css::uno::UNO_QUERY);
+ xCurCol->setPropertyValue(FM_PROP_HIDDEN, Any(false));
+ }
+ // TODO : there must be a more clever way to do this...
+ // with the above the view is updated after every single model update ...
+ }
+ else if (!rExecutionResult.isEmpty())
+ {
+ sal_Int32 nExecutionResult = rExecutionResult.toInt32();
+ if (nExecutionResult>0 && nExecutionResult<=16)
+ {
+ // it was a "show column/<colname>" command (there are at most 16 such items)
+ // search the nExecutionResult'th hidden col
+ Reference< css::beans::XPropertySet > xCurCol;
+ for (sal_Int32 i=0; i<xCols->getCount() && nExecutionResult; ++i)
+ {
+ xCurCol.set(xCols->getByIndex(i), css::uno::UNO_QUERY);
+ Any aHidden = xCurCol->getPropertyValue(FM_PROP_HIDDEN);
+ if (::comphelper::getBOOL(aHidden))
+ if (!--nExecutionResult)
+ {
+ xCurCol->setPropertyValue(FM_PROP_HIDDEN, Any(false));
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !aFieldType.isEmpty() )
+ {
+ try
+ {
+ Reference< XGridColumnFactory > xFactory( xCols, UNO_QUERY_THROW );
+ Reference< XPropertySet > xNewCol( xFactory->createColumn( aFieldType ), UNO_SET_THROW );
+
+ if ( bReplace )
+ {
+ // rescue over a few properties
+ Reference< XPropertySet > xReplaced( xCols->getByIndex( nPos ), UNO_QUERY );
+
+ TransferFormComponentProperties(
+ xReplaced, xNewCol, Application::GetSettings().GetUILanguageTag().getLocale() );
+
+ xCols->replaceByIndex( nPos, Any( xNewCol ) );
+ ::comphelper::disposeComponent( xReplaced );
+
+ eInspectorAction = eUpdateInspector;
+ }
+ else
+ {
+ FormControlFactory factory;
+
+ OUString sLabel = FormControlFactory::getDefaultUniqueName_ByComponentType(
+ Reference< XNameAccess >( xCols, UNO_QUERY_THROW ), xNewCol );
+ xNewCol->setPropertyValue( FM_PROP_LABEL, Any( sLabel ) );
+ xNewCol->setPropertyValue( FM_PROP_NAME, Any( sLabel ) );
+
+ factory.initializeControlModel( DocumentClassification::classifyHostDocument( xCols ), xNewCol );
+
+ xCols->insertByIndex( nPos, Any( xNewCol ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+ SfxViewFrame* pCurrentFrame = SfxViewFrame::Current();
+ OSL_ENSURE( pCurrentFrame, "FmGridHeader::PostExecuteColumnContextMenu: no view frame -> no bindings -> no property browser!" );
+ if ( !pCurrentFrame )
+ return;
+
+ if ( eInspectorAction == eUpdateInspector )
+ {
+ if ( !pCurrentFrame->HasChildWindow( SID_FM_SHOW_PROPERTIES ) )
+ eInspectorAction = eNone;
+ }
+
+ if ( eInspectorAction != eNone )
+ {
+ SfxBoolItem aShowItem( SID_FM_SHOW_PROPERTIES, eInspectorAction != eCloseInspector );
+
+ pCurrentFrame->GetBindings().GetDispatcher()->ExecuteList(
+ SID_FM_SHOW_PROPERTY_BROWSER, SfxCallMode::ASYNCHRON,
+ { &aShowItem });
+ }
+}
+
+void FmGridHeader::triggerColumnContextMenu( const ::Point& _rPreferredPos )
+{
+ // the affected col
+ sal_uInt16 nColId = GetItemId( _rPreferredPos );
+
+ // the menu
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "svx/ui/colsmenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+ std::unique_ptr<weld::Menu> xInsertMenu(xBuilder->weld_menu("insertmenu"));
+ std::unique_ptr<weld::Menu> xChangeMenu(xBuilder->weld_menu("changemenu"));
+ std::unique_ptr<weld::Menu> xShowMenu(xBuilder->weld_menu("showmenu"));
+
+ // let derivatives modify the menu
+ PreExecuteColumnContextMenu(nColId, *xContextMenu, *xInsertMenu, *xChangeMenu, *xShowMenu);
+
+ bool bEmpty = true;
+ for (int i = 0, nCount = xContextMenu->n_children(); i < nCount; ++i)
+ {
+ bEmpty = !xContextMenu->get_sensitive(xContextMenu->get_id(i));
+ if (!bEmpty)
+ break;
+ }
+ if (bEmpty)
+ return;
+
+ // execute the menu
+ ::tools::Rectangle aRect(_rPreferredPos, Size(1,1));
+ weld::Window* pParent = weld::GetPopupParent(*this, aRect);
+ OString sResult = xContextMenu->popup_at_rect(pParent, aRect);
+
+ // let derivatives handle the result
+ PostExecuteColumnContextMenu(nColId, *xContextMenu, sResult);
+}
+
+void FmGridHeader::Command(const CommandEvent& rEvt)
+{
+ switch (rEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ if (!rEvt.IsMouseEvent())
+ return;
+
+ triggerColumnContextMenu( rEvt.GetMousePosPixel() );
+ }
+ break;
+ default:
+ EditBrowserHeader::Command(rEvt);
+ }
+}
+
+FmGridControl::FmGridControl(
+ const Reference< css::uno::XComponentContext >& _rxContext,
+ vcl::Window* pParent,
+ FmXGridPeer* _pPeer,
+ WinBits nBits)
+ :DbGridControl(_rxContext, pParent, nBits)
+ ,m_pPeer(_pPeer)
+ ,m_nCurrentSelectedColumn(-1)
+ ,m_nMarkedColumnId(BROWSER_INVALIDID)
+ ,m_bSelecting(false)
+ ,m_bInColumnMove(false)
+{
+ EnableInteractiveRowHeight( );
+}
+
+void FmGridControl::Command(const CommandEvent& _rEvt)
+{
+ if ( CommandEventId::ContextMenu == _rEvt.GetCommand() )
+ {
+ FmGridHeader* pMyHeader = static_cast< FmGridHeader* >( GetHeaderBar() );
+ if ( pMyHeader && !_rEvt.IsMouseEvent() )
+ { // context menu requested by keyboard
+ if ( 1 == GetSelectColumnCount() || IsDesignMode() )
+ {
+ sal_uInt16 nSelId = GetColumnId(
+ sal::static_int_cast< sal_uInt16 >( FirstSelectedColumn() ) );
+ ::tools::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, false ) );
+
+ Point aRelativePos( pMyHeader->ScreenToOutputPixel( OutputToScreenPixel( aColRect.TopCenter() ) ) );
+ pMyHeader->triggerColumnContextMenu(aRelativePos);
+
+ // handled
+ return;
+ }
+ }
+ }
+
+ DbGridControl::Command( _rEvt );
+}
+
+// css::beans::XPropertyChangeListener
+void FmGridControl::propertyChange(const css::beans::PropertyChangeEvent& evt)
+{
+ if (evt.PropertyName == FM_PROP_ROWCOUNT)
+ {
+ // if we're not in the main thread call AdjustRows asynchronously
+ implAdjustInSolarThread(true);
+ return;
+ }
+
+ const DbGridRowRef& xRow = GetCurrentRow();
+ // no adjustment of the properties is carried out during positioning
+ Reference<XPropertySet> xSet(evt.Source,UNO_QUERY);
+ if (!(xRow.is() && (::cppu::any2bool(xSet->getPropertyValue(FM_PROP_ISNEW))|| CompareBookmark(getDataSource()->getBookmark(), xRow->GetBookmark()))))
+ return;
+
+ if (evt.PropertyName == FM_PROP_ISMODIFIED)
+ {
+ // modified or clean ?
+ GridRowStatus eStatus = ::comphelper::getBOOL(evt.NewValue) ? GridRowStatus::Modified : GridRowStatus::Clean;
+ if (eStatus != xRow->GetStatus())
+ {
+ xRow->SetStatus(eStatus);
+ SolarMutexGuard aGuard;
+ RowModified(GetCurrentPos());
+ }
+ }
+}
+
+void FmGridControl::SetDesignMode(bool bMode)
+{
+ bool bOldMode = IsDesignMode();
+ DbGridControl::SetDesignMode(bMode);
+ if (bOldMode == bMode)
+ return;
+
+ if (!bMode)
+ {
+ // cancel selection
+ markColumn(USHRT_MAX);
+ }
+ else
+ {
+ Reference< css::container::XIndexContainer > xColumns(GetPeer()->getColumns());
+ Reference< css::view::XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
+ if (xSelSupplier.is())
+ {
+ Any aSelection = xSelSupplier->getSelection();
+ Reference< css::beans::XPropertySet > xColumn;
+ if (aSelection.getValueType().getTypeClass() == TypeClass_INTERFACE)
+ xColumn.set(aSelection, css::uno::UNO_QUERY);
+ Reference< XInterface > xCurrent;
+ for (sal_Int32 i=0; i<xColumns->getCount(); ++i)
+ {
+ xCurrent.set(xColumns->getByIndex(i), css::uno::UNO_QUERY);
+ if (xCurrent == xColumn)
+ {
+ markColumn(GetColumnIdFromModelPos(i));
+ break;
+ }
+ }
+ }
+ }
+}
+
+void FmGridControl::DeleteSelectedRows()
+{
+ if (!m_pSeekCursor)
+ return;
+
+ // how many rows are selected?
+ sal_Int32 nSelectedRows = GetSelectRowCount();
+
+ // the current line should be deleted but it is currently in edit mode
+ if ( IsCurrentAppending() )
+ return;
+ // is the insert row selected
+ if (GetEmptyRow().is() && IsRowSelected(GetRowCount() - 1))
+ nSelectedRows -= 1;
+
+ // nothing to do
+ if (nSelectedRows <= 0)
+ return;
+
+ // try to confirm the delete
+ Reference< css::frame::XDispatchProvider > xDispatcher = static_cast<css::frame::XDispatchProvider*>(GetPeer());
+ if (xDispatcher.is())
+ {
+ css::util::URL aUrl;
+ aUrl.Complete = FMURL_CONFIRM_DELETION;
+ Reference< css::util::XURLTransformer > xTransformer(
+ css::util::URLTransformer::create(::comphelper::getProcessComponentContext()) );
+ xTransformer->parseStrict( aUrl );
+
+ Reference< css::frame::XDispatch > xDispatch = xDispatcher->queryDispatch(aUrl, OUString(), 0);
+ Reference< css::form::XConfirmDeleteListener > xConfirm(xDispatch, UNO_QUERY);
+ if (xConfirm.is())
+ {
+ css::sdb::RowChangeEvent aEvent;
+ aEvent.Source = Reference< XInterface >(*getDataSource());
+ aEvent.Rows = nSelectedRows;
+ aEvent.Action = css::sdb::RowChangeAction::DELETE;
+ if (!xConfirm->confirmDelete(aEvent))
+ return;
+ }
+ }
+
+ const MultiSelection* pRowSelection = GetSelection();
+ if ( pRowSelection && pRowSelection->IsAllSelected() )
+ {
+ BeginCursorAction();
+ CursorWrapper* pCursor = getDataSource();
+ Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*pCursor), UNO_QUERY);
+ try
+ {
+ pCursor->beforeFirst();
+ while( pCursor->next() )
+ xUpdateCursor->deleteRow();
+
+ SetUpdateMode(false);
+ SetNoSelection();
+
+ xUpdateCursor->moveToInsertRow();
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "Exception caught while deleting rows!");
+ }
+ // adapt to the data cursor
+ AdjustDataSource(true);
+ EndCursorAction();
+ SetUpdateMode(true);
+ }
+ else
+ {
+ Reference< css::sdbcx::XDeleteRows > xDeleteThem(Reference< XInterface >(*getDataSource()), UNO_QUERY);
+
+ // collect the bookmarks of the selected rows
+ Sequence < Any> aBookmarks = getSelectionBookmarks();
+
+ // determine the next row to position after deletion
+ Any aBookmark;
+ bool bNewPos = false;
+ // if the current row isn't selected we take the row as row after deletion
+ OSL_ENSURE( GetCurrentRow().is(), "FmGridControl::DeleteSelectedRows: no current row here?" );
+ // crash reports suggest it can happen we don't have a current row - how?
+ // #154303# / 2008-04-23 / frank.schoenheit@sun.com
+ if ( !IsRowSelected( GetCurrentPos() ) && !IsCurrentAppending() && GetCurrentRow().is() )
+ {
+ aBookmark = GetCurrentRow()->GetBookmark();
+ bNewPos = true;
+ }
+ else
+ {
+ // we look for the first row after the selected block for selection
+ tools::Long nIdx = LastSelectedRow() + 1;
+ if (nIdx < GetRowCount() - 1)
+ {
+ // there is a next row to position on
+ if (SeekCursor(nIdx))
+ {
+ GetSeekRow()->SetState(m_pSeekCursor.get(), true);
+
+ bNewPos = true;
+ // if it's not the row for inserting we keep the bookmark
+ if (!IsInsertionRow(nIdx))
+ aBookmark = m_pSeekCursor->getBookmark();
+ }
+ }
+ else
+ {
+ // we look for the first row before the selected block for selection after deletion
+ nIdx = FirstSelectedRow() - 1;
+ if (nIdx >= 0 && SeekCursor(nIdx))
+ {
+ GetSeekRow()->SetState(m_pSeekCursor.get(), true);
+
+ bNewPos = true;
+ aBookmark = m_pSeekCursor->getBookmark();
+ }
+ }
+ }
+
+ // Are all rows selected?
+ // Second condition if no insertion line exists
+ bool bAllSelected = GetTotalCount() == nSelectedRows || GetRowCount() == nSelectedRows;
+
+ BeginCursorAction();
+
+ // now delete the row
+ Sequence<sal_Int32> aDeletedRows;
+ SetUpdateMode( false );
+ try
+ {
+ aDeletedRows = xDeleteThem->deleteRows(aBookmarks);
+ }
+ catch(SQLException&)
+ {
+ }
+ SetUpdateMode( true );
+
+ // how many rows are deleted?
+ sal_Int32 nDeletedRows = static_cast<sal_Int32>(std::count_if(std::cbegin(aDeletedRows), std::cend(aDeletedRows),
+ [](const sal_Int32 nRow) { return nRow != 0; }));
+
+ // have rows been deleted?
+ if (nDeletedRows)
+ {
+ SetUpdateMode(false);
+ SetNoSelection();
+ try
+ {
+ // did we delete all the rows than try to move to the next possible row
+ if (nDeletedRows == aDeletedRows.getLength())
+ {
+ // there exists a new position to move on
+ if (bNewPos)
+ {
+ if (aBookmark.hasValue())
+ getDataSource()->moveToBookmark(aBookmark);
+ // no valid bookmark so move to the insert row
+ else
+ {
+ Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
+ xUpdateCursor->moveToInsertRow();
+ }
+ }
+ else
+ {
+ Reference< css::beans::XPropertySet > xSet(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
+
+ sal_Int32 nRecordCount(0);
+ xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
+ if ( m_pDataCursor->rowDeleted() )
+ --nRecordCount;
+
+ // there are no rows left and we have an insert row
+ if (!nRecordCount && GetEmptyRow().is())
+ {
+ Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
+ xUpdateCursor->moveToInsertRow();
+ }
+ else if (nRecordCount)
+ // move to the first row
+ getDataSource()->first();
+ }
+ }
+ // not all the rows where deleted, so move to the first row which remained in the resultset
+ else
+ {
+ auto pRow = std::find(std::cbegin(aDeletedRows), std::cend(aDeletedRows), 0);
+ if (pRow != std::cend(aDeletedRows))
+ {
+ auto i = static_cast<sal_Int32>(std::distance(std::cbegin(aDeletedRows), pRow));
+ getDataSource()->moveToBookmark(aBookmarks[i]);
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ try
+ {
+ // positioning went wrong so try to move to the first row
+ getDataSource()->first();
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+
+ // adapt to the data cursor
+ AdjustDataSource(true);
+
+ // not all rows could be deleted;
+ // never select again there the ones that could not be deleted
+ if (nDeletedRows < nSelectedRows)
+ {
+ // were all selected
+ if (bAllSelected)
+ {
+ SelectAll();
+ if (IsInsertionRow(GetRowCount() - 1)) // not the insertion row
+ SelectRow(GetRowCount() - 1, false);
+ }
+ else
+ {
+ // select the remaining rows
+ for (const sal_Int32 nSuccess : std::as_const(aDeletedRows))
+ {
+ try
+ {
+ if (!nSuccess)
+ {
+ m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
+ SetSeekPos(m_pSeekCursor->getRow() - 1);
+ SelectRow(GetSeekPos());
+ }
+ }
+ catch(const Exception&)
+ {
+ // keep the seekpos in all cases
+ SetSeekPos(m_pSeekCursor->getRow() - 1);
+ }
+ }
+ }
+ }
+
+ EndCursorAction();
+ SetUpdateMode(true);
+ }
+ else // row could not be deleted
+ {
+ EndCursorAction();
+ try
+ {
+ // currentrow is the insert row?
+ if (!IsCurrentAppending())
+ getDataSource()->refreshRow();
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ }
+
+ // if there is no selection anymore we can start editing
+ if (!GetSelectRowCount())
+ ActivateCell();
+}
+
+// XCurrentRecordListener
+void FmGridControl::positioned()
+{
+ SAL_INFO("svx.fmcomp", "FmGridControl::positioned");
+ // position on the data source (force it to be done in the main thread)
+ implAdjustInSolarThread(false);
+}
+
+bool FmGridControl::commit()
+{
+ // execute commit only if an update is not already executed by the
+ // css::form::component::GridControl
+ if (!IsUpdating())
+ {
+ if (Controller().is() && Controller()->IsValueChangedFromSaved())
+ {
+ if (!SaveModified())
+ return false;
+ }
+ }
+ return true;
+}
+
+void FmGridControl::inserted()
+{
+ const DbGridRowRef& xRow = GetCurrentRow();
+ if (!xRow.is())
+ return;
+
+ // line has been inserted, then reset the status and mode
+ xRow->SetState(m_pDataCursor.get(), false);
+ xRow->SetNew(false);
+
+}
+
+VclPtr<BrowserHeader> FmGridControl::imp_CreateHeaderBar(BrowseBox* pParent)
+{
+ DBG_ASSERT( pParent == this, "FmGridControl::imp_CreateHeaderBar: parent?" );
+ return VclPtr<FmGridHeader>::Create( pParent );
+}
+
+void FmGridControl::markColumn(sal_uInt16 nId)
+{
+ if (!(GetHeaderBar() && m_nMarkedColumnId != nId))
+ return;
+
+ // deselect
+ if (m_nMarkedColumnId != BROWSER_INVALIDID)
+ {
+ HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(m_nMarkedColumnId) & ~HeaderBarItemBits::FLAT;
+ GetHeaderBar()->SetItemBits(m_nMarkedColumnId, aBits);
+ }
+
+
+ if (nId != BROWSER_INVALIDID)
+ {
+ HeaderBarItemBits aBits = GetHeaderBar()->GetItemBits(nId) | HeaderBarItemBits::FLAT;
+ GetHeaderBar()->SetItemBits(nId, aBits);
+ }
+ m_nMarkedColumnId = nId;
+}
+
+bool FmGridControl::isColumnMarked(sal_uInt16 nId) const
+{
+ return m_nMarkedColumnId == nId;
+}
+
+tools::Long FmGridControl::QueryMinimumRowHeight()
+{
+ tools::Long const nMinimalLogicHeight = 20; // 0.2 cm
+ tools::Long nMinimalPixelHeight = LogicToPixel(Point(0, nMinimalLogicHeight), MapMode(MapUnit::Map10thMM)).Y();
+ return CalcZoom( nMinimalPixelHeight );
+}
+
+void FmGridControl::RowHeightChanged()
+{
+ DbGridControl::RowHeightChanged();
+
+ Reference< XPropertySet > xModel( GetPeer()->getColumns(), UNO_QUERY );
+ DBG_ASSERT( xModel.is(), "FmGridControl::RowHeightChanged: no model!" );
+ if ( !xModel.is() )
+ return;
+
+ try
+ {
+ sal_Int32 nUnzoomedPixelHeight = CalcReverseZoom( GetDataRowHeight() );
+ Any aProperty( static_cast<sal_Int32>(PixelToLogic( Point(0, nUnzoomedPixelHeight), MapMode(MapUnit::Map10thMM)).Y()) );
+ xModel->setPropertyValue( FM_PROP_ROWHEIGHT, aProperty );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmGridControl::RowHeightChanged" );
+ }
+}
+
+void FmGridControl::ColumnResized(sal_uInt16 nId)
+{
+ DbGridControl::ColumnResized(nId);
+
+ // transfer value to the model
+ DbGridColumn* pCol = DbGridControl::GetColumns()[ GetModelColumnPos(nId) ].get();
+ const Reference< css::beans::XPropertySet >& xColModel(pCol->getModel());
+ if (xColModel.is())
+ {
+ Any aWidth;
+ sal_Int32 nColumnWidth = GetColumnWidth(nId);
+ nColumnWidth = CalcReverseZoom(nColumnWidth);
+ // convert to 10THMM
+ aWidth <<= static_cast<sal_Int32>(PixelToLogic(Point(nColumnWidth, 0), MapMode(MapUnit::Map10thMM)).X());
+ xColModel->setPropertyValue(FM_PROP_WIDTH, aWidth);
+ }
+}
+
+void FmGridControl::CellModified()
+{
+ DbGridControl::CellModified();
+ GetPeer()->CellModified();
+}
+
+void FmGridControl::BeginCursorAction()
+{
+ DbGridControl::BeginCursorAction();
+ m_pPeer->stopCursorListening();
+}
+
+void FmGridControl::EndCursorAction()
+{
+ m_pPeer->startCursorListening();
+ DbGridControl::EndCursorAction();
+}
+
+void FmGridControl::ColumnMoved(sal_uInt16 nId)
+{
+ m_bInColumnMove = true;
+
+ DbGridControl::ColumnMoved(nId);
+ Reference< css::container::XIndexContainer > xColumns(GetPeer()->getColumns());
+
+ if (xColumns.is())
+ {
+ // locate the column and move in the model;
+ // get ColumnPos
+ DbGridColumn* pCol = DbGridControl::GetColumns()[ GetModelColumnPos(nId) ].get();
+ Reference< css::beans::XPropertySet > xCol;
+
+ // inserting must be based on the column positions
+ sal_Int32 i;
+ Reference< XInterface > xCurrent;
+ for (i = 0; !xCol.is() && i < xColumns->getCount(); i++)
+ {
+ xCurrent.set(xColumns->getByIndex(i), css::uno::UNO_QUERY);
+ if (xCurrent == pCol->getModel())
+ {
+ xCol = pCol->getModel();
+ break;
+ }
+ }
+
+ DBG_ASSERT(i < xColumns->getCount(), "Wrong css::sdbcx::Index");
+ xColumns->removeByIndex(i);
+ Any aElement;
+ aElement <<= xCol;
+ xColumns->insertByIndex(GetModelColumnPos(nId), aElement);
+ pCol->setModel(xCol);
+ // if the column which is shown here is selected ...
+ if ( isColumnSelected(pCol) )
+ markColumn(nId); // ... -> mark it
+ }
+
+ m_bInColumnMove = false;
+}
+
+void FmGridControl::InitColumnsByModels(const Reference< css::container::XIndexContainer >& xColumns)
+{
+ // reset columns;
+ // if there is only one HandleColumn, then don't
+ if (GetModelColCount())
+ {
+ RemoveColumns();
+ InsertHandleColumn();
+ }
+
+ if (!xColumns.is())
+ return;
+
+ SetUpdateMode(false);
+
+ // inserting must be based on the column positions
+ sal_Int32 i;
+ Any aWidth;
+ for (i = 0; i < xColumns->getCount(); ++i)
+ {
+ Reference< css::beans::XPropertySet > xCol(
+ xColumns->getByIndex(i), css::uno::UNO_QUERY);
+
+ OUString aName(
+ comphelper::getString(xCol->getPropertyValue(FM_PROP_LABEL)));
+
+ aWidth = xCol->getPropertyValue(FM_PROP_WIDTH);
+ sal_Int32 nWidth = 0;
+ if (aWidth >>= nWidth)
+ nWidth = LogicToPixel(Point(nWidth, 0), MapMode(MapUnit::Map10thMM)).X();
+
+ AppendColumn(aName, static_cast<sal_uInt16>(nWidth));
+ DbGridColumn* pCol = DbGridControl::GetColumns()[ i ].get();
+ pCol->setModel(xCol);
+ }
+
+ // and now remove the hidden columns as well
+ // (we did not already make it in the upper loop, since we would then have gotten
+ // problems with the IDs of the columns: AppendColumn allocates them automatically,
+ // but the column _after_ a hidden one needs an ID increased by one ...)
+ Any aHidden;
+ for (i = 0; i < xColumns->getCount(); ++i)
+ {
+ Reference< css::beans::XPropertySet > xCol( xColumns->getByIndex(i), css::uno::UNO_QUERY);
+ aHidden = xCol->getPropertyValue(FM_PROP_HIDDEN);
+ if (::comphelper::getBOOL(aHidden))
+ HideColumn(GetColumnIdFromModelPos(static_cast<sal_uInt16>(i)));
+ }
+
+ SetUpdateMode(true);
+}
+
+void FmGridControl::InitColumnByField(
+ DbGridColumn* _pColumn, const Reference< XPropertySet >& _rxColumnModel,
+ const Reference< XNameAccess >& _rxFieldsByNames, const Reference< XIndexAccess >& _rxFieldsByIndex )
+{
+ DBG_ASSERT( _rxFieldsByNames == _rxFieldsByIndex, "FmGridControl::InitColumnByField: invalid container interfaces!" );
+
+ // lookup the column which belongs to the control source
+ OUString sFieldName;
+ _rxColumnModel->getPropertyValue( FM_PROP_CONTROLSOURCE ) >>= sFieldName;
+ Reference< XPropertySet > xField;
+ _rxColumnModel->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
+
+
+ if ( !xField.is() && /*sFieldName.getLength() && */_rxFieldsByNames->hasByName( sFieldName ) ) // #i93452# do not check for name length
+ _rxFieldsByNames->getByName( sFieldName ) >>= xField;
+
+ // determine the position of this column
+ sal_Int32 nFieldPos = -1;
+ if ( xField.is() )
+ {
+ Reference< XPropertySet > xCheck;
+ sal_Int32 nFieldCount = _rxFieldsByIndex->getCount();
+ for ( sal_Int32 i = 0; i < nFieldCount; ++i)
+ {
+ _rxFieldsByIndex->getByIndex( i ) >>= xCheck;
+ if ( xField.get() == xCheck.get() )
+ {
+ nFieldPos = i;
+ break;
+ }
+ }
+ }
+
+ if ( xField.is() && ( nFieldPos >= 0 ) )
+ {
+ // some data types are not allowed
+ sal_Int32 nDataType = DataType::OTHER;
+ xField->getPropertyValue( FM_PROP_FIELDTYPE ) >>= nDataType;
+
+ bool bIllegalType = false;
+ switch ( nDataType )
+ {
+ case DataType::BLOB:
+ case DataType::LONGVARBINARY:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::OTHER:
+ bIllegalType = true;
+ break;
+ }
+
+ if ( bIllegalType )
+ {
+ _pColumn->SetObject( static_cast<sal_Int16>(nFieldPos) );
+ return;
+ }
+ }
+
+ // the control type is determined by the ColumnServiceName
+ static constexpr OUStringLiteral s_sPropColumnServiceName = u"ColumnServiceName";
+ if ( !::comphelper::hasProperty( s_sPropColumnServiceName, _rxColumnModel ) )
+ return;
+
+ _pColumn->setModel( _rxColumnModel );
+
+ OUString sColumnServiceName;
+ _rxColumnModel->getPropertyValue( s_sPropColumnServiceName ) >>= sColumnServiceName;
+
+ sal_Int32 nTypeId = getColumnTypeByModelName( sColumnServiceName );
+ _pColumn->CreateControl( nFieldPos, xField, nTypeId );
+}
+
+void FmGridControl::InitColumnsByFields(const Reference< css::container::XIndexAccess >& _rxFields)
+{
+ if ( !_rxFields.is() )
+ return;
+
+ // initialize columns
+ Reference< XIndexContainer > xColumns( GetPeer()->getColumns() );
+ Reference< XNameAccess > xFieldsAsNames( _rxFields, UNO_QUERY );
+
+ // inserting must be based on the column positions
+ for (sal_Int32 i = 0; i < xColumns->getCount(); i++)
+ {
+ DbGridColumn* pCol = GetColumns()[ i ].get();
+ OSL_ENSURE(pCol,"No grid column!");
+ if ( pCol )
+ {
+ Reference< XPropertySet > xColumnModel(
+ xColumns->getByIndex( i ), css::uno::UNO_QUERY);
+
+ InitColumnByField( pCol, xColumnModel, xFieldsAsNames, _rxFields );
+ }
+ }
+}
+
+void FmGridControl::HideColumn(sal_uInt16 nId)
+{
+ DbGridControl::HideColumn(nId);
+
+ sal_uInt16 nPos = GetModelColumnPos(nId);
+ if (nPos == sal_uInt16(-1))
+ return;
+
+ DbGridColumn* pColumn = GetColumns()[ nPos ].get();
+ if (pColumn->IsHidden())
+ GetPeer()->columnHidden(pColumn);
+
+ if (nId == m_nMarkedColumnId)
+ m_nMarkedColumnId = sal_uInt16(-1);
+}
+
+bool FmGridControl::isColumnSelected(DbGridColumn const * _pColumn) const
+{
+ OSL_ENSURE(_pColumn,"Column can not be null!");
+ bool bSelected = false;
+ // if the column which is shown here is selected ...
+ Reference< css::view::XSelectionSupplier > xSelSupplier(GetPeer()->getColumns(), UNO_QUERY);
+ if ( xSelSupplier.is() )
+ {
+ Reference< css::beans::XPropertySet > xColumn;
+ xSelSupplier->getSelection() >>= xColumn;
+ bSelected = (xColumn.get() == _pColumn->getModel().get());
+ }
+ return bSelected;
+}
+
+void FmGridControl::ShowColumn(sal_uInt16 nId)
+{
+ DbGridControl::ShowColumn(nId);
+
+ sal_uInt16 nPos = GetModelColumnPos(nId);
+ if (nPos == sal_uInt16(-1))
+ return;
+
+ DbGridColumn* pColumn = GetColumns()[ nPos ].get();
+ if (!pColumn->IsHidden())
+ GetPeer()->columnVisible(pColumn);
+
+ // if the column which is shown here is selected ...
+ if ( isColumnSelected(pColumn) )
+ markColumn(nId); // ... -> mark it
+}
+
+bool FmGridControl::selectBookmarks(const Sequence< Any >& _rBookmarks)
+{
+ SolarMutexGuard aGuard;
+ // need to lock the SolarMutex so that no paint call disturbs us ...
+
+ if ( !m_pSeekCursor )
+ {
+ OSL_FAIL( "FmGridControl::selectBookmarks: no seek cursor!" );
+ return false;
+ }
+
+ SetNoSelection();
+
+ bool bAllSuccessful = true;
+ try
+ {
+ for (const Any& rBookmark : _rBookmarks)
+ {
+ // move the seek cursor to the row given
+ if (m_pSeekCursor->moveToBookmark(rBookmark))
+ SelectRow( m_pSeekCursor->getRow() - 1);
+ else
+ bAllSuccessful = false;
+ }
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("FmGridControl::selectBookmarks: could not move to one of the bookmarks!");
+ return false;
+ }
+
+ return bAllSuccessful;
+}
+
+Sequence< Any> FmGridControl::getSelectionBookmarks()
+{
+ // lock our update so no paint-triggered seeks interfere ...
+ SetUpdateMode(false);
+
+ sal_Int32 nSelectedRows = GetSelectRowCount(), i = 0;
+ Sequence< Any> aBookmarks(nSelectedRows);
+ if ( nSelectedRows )
+ {
+ Any* pBookmarks = aBookmarks.getArray();
+
+ // (I'm not sure if the problem isn't deeper: The scenario: a large table displayed by a grid with a
+ // thread-safe cursor (dBase). On loading the sdb-cursor started a counting thread. While this counting progress
+ // was running, I tried do delete 3 records from within the grid. Deletion caused a SeekCursor, which made a
+ // m_pSeekCursor->moveRelative and a m_pSeekCursor->getPosition.
+ // Unfortunately the first call caused a propertyChanged(RECORDCOUNT) which resulted in a repaint of the
+ // navigation bar and the grid. The latter itself will result in SeekRow calls. So after (successfully) returning
+ // from the moveRelative the getPosition returns an invalid value. And so the SeekCursor fails.
+ // In the consequence ALL parts of code where two calls to the seek cursor are done, while the second call _relies_ on
+ // the first one, should be secured against recursion, with a broad-minded interpretation of "recursion": if any of these
+ // code parts is executed, no other should be accessible. But this sounds very difficult to achieve...
+ // )
+
+ // The next problem caused by the same behavior (SeekCursor causes a propertyChanged): when adjusting rows we implicitly
+ // change our selection. So a "FirstSelected(); SeekCursor(); NextSelected();" may produce unpredictable results.
+ // That's why we _first_ collect the indices of the selected rows and _then_ their bookmarks.
+ tools::Long nIdx = FirstSelectedRow();
+ while (nIdx != BROWSER_ENDOFSELECTION)
+ {
+ // (we misuse the bookmarks array for this ...)
+ pBookmarks[i++] <<= static_cast<sal_Int32>(nIdx);
+ nIdx = NextSelectedRow();
+ }
+ DBG_ASSERT(i == nSelectedRows, "FmGridControl::DeleteSelectedRows : could not collect the row indices !");
+
+ for (i=0; i<nSelectedRows; ++i)
+ {
+ nIdx = ::comphelper::getINT32(pBookmarks[i]);
+ if (IsInsertionRow(nIdx))
+ {
+ // do not delete empty row
+ aBookmarks.realloc(--nSelectedRows);
+ SelectRow(nIdx, false); // cancel selection for empty row
+ break;
+ }
+
+ // first, position the data cursor on the selected block
+ if (SeekCursor(nIdx))
+ {
+ GetSeekRow()->SetState(m_pSeekCursor.get(), true);
+
+ pBookmarks[i] = m_pSeekCursor->getBookmark();
+ }
+ #ifdef DBG_UTIL
+ else
+ OSL_FAIL("FmGridControl::DeleteSelectedRows : a bookmark could not be determined !");
+ #endif
+ }
+ }
+ SetUpdateMode(true);
+
+ // if one of the SeekCursor-calls failed...
+ aBookmarks.realloc(i);
+
+ // (the alternative : while collecting the bookmarks lock our propertyChanged, this should resolve both our problems.
+ // but this would be incompatible as we need a locking flag, then...)
+
+ return aBookmarks;
+}
+
+namespace
+{
+ OUString getColumnPropertyFromPeer(FmXGridPeer* _pPeer,sal_Int32 _nPosition,const OUString& _sPropName)
+ {
+ OUString sRetText;
+ if ( _pPeer && _nPosition != -1)
+ {
+ Reference<XIndexContainer> xIndex = _pPeer->getColumns();
+ if ( xIndex.is() && xIndex->getCount() > _nPosition )
+ {
+ Reference<XPropertySet> xProp;
+ xIndex->getByIndex( _nPosition ) >>= xProp;
+ if ( xProp.is() )
+ {
+ try {
+ xProp->getPropertyValue( _sPropName ) >>= sRetText;
+ } catch (UnknownPropertyException const&) {
+ TOOLS_WARN_EXCEPTION("svx.fmcomp", "");
+ }
+ }
+ }
+ }
+ return sRetText;
+ }
+}
+
+// Object data and state
+OUString FmGridControl::GetAccessibleObjectName( AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const
+{
+ OUString sRetText;
+ switch( _eObjType )
+ {
+ case AccessibleBrowseBoxObjType::BrowseBox:
+ if ( GetPeer() )
+ {
+ Reference<XPropertySet> xProp(GetPeer()->getColumns(),UNO_QUERY);
+ if ( xProp.is() )
+ xProp->getPropertyValue(FM_PROP_NAME) >>= sRetText;
+ }
+ break;
+ case AccessibleBrowseBoxObjType::ColumnHeaderCell:
+ sRetText = getColumnPropertyFromPeer(
+ GetPeer(),
+ GetModelColumnPos(
+ sal::static_int_cast< sal_uInt16 >(_nPosition)),
+ FM_PROP_LABEL);
+ break;
+ default:
+ sRetText = DbGridControl::GetAccessibleObjectName(_eObjType,_nPosition);
+ }
+ return sRetText;
+}
+
+OUString FmGridControl::GetAccessibleObjectDescription( AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition ) const
+{
+ OUString sRetText;
+ switch( _eObjType )
+ {
+ case AccessibleBrowseBoxObjType::BrowseBox:
+ if ( GetPeer() )
+ {
+ Reference<XPropertySet> xProp(GetPeer()->getColumns(),UNO_QUERY);
+ if ( xProp.is() )
+ {
+ xProp->getPropertyValue(FM_PROP_HELPTEXT) >>= sRetText;
+ if ( sRetText.isEmpty() )
+ xProp->getPropertyValue(FM_PROP_DESCRIPTION) >>= sRetText;
+ }
+ }
+ break;
+ case AccessibleBrowseBoxObjType::ColumnHeaderCell:
+ sRetText = getColumnPropertyFromPeer(
+ GetPeer(),
+ GetModelColumnPos(
+ sal::static_int_cast< sal_uInt16 >(_nPosition)),
+ FM_PROP_HELPTEXT);
+ if ( sRetText.isEmpty() )
+ sRetText = getColumnPropertyFromPeer(
+ GetPeer(),
+ GetModelColumnPos(
+ sal::static_int_cast< sal_uInt16 >(_nPosition)),
+ FM_PROP_DESCRIPTION);
+
+ break;
+ default:
+ sRetText = DbGridControl::GetAccessibleObjectDescription(_eObjType,_nPosition);
+ }
+ return sRetText;
+}
+
+void FmGridControl::Select()
+{
+ DbGridControl::Select();
+ // ... does it affect our columns?
+ const MultiSelection* pColumnSelection = GetColumnSelection();
+
+ sal_uInt16 nSelectedColumn =
+ pColumnSelection && pColumnSelection->GetSelectCount()
+ ? sal::static_int_cast< sal_uInt16 >(
+ const_cast<MultiSelection*>(pColumnSelection)->FirstSelected())
+ : SAL_MAX_UINT16;
+ // the HandleColumn is not selected
+ switch (nSelectedColumn)
+ {
+ case SAL_MAX_UINT16: break; // no selection
+ case 0 : nSelectedColumn = SAL_MAX_UINT16; break;
+ // handle col can't be selected
+ default :
+ // get the model col pos instead of the view col pos
+ nSelectedColumn = GetModelColumnPos(GetColumnIdFromViewPos(nSelectedColumn - 1));
+ break;
+ }
+
+ if (nSelectedColumn == m_nCurrentSelectedColumn)
+ return;
+
+ // BEFORE calling the select at the SelectionSupplier!
+ m_nCurrentSelectedColumn = nSelectedColumn;
+
+ if (m_bSelecting)
+ return;
+
+ m_bSelecting = true;
+
+ try
+ {
+ Reference< XIndexAccess > xColumns = GetPeer()->getColumns();
+ Reference< XSelectionSupplier > xSelSupplier(xColumns, UNO_QUERY);
+ if (xSelSupplier.is())
+ {
+ if (nSelectedColumn != SAL_MAX_UINT16)
+ {
+ Reference< XPropertySet > xColumn(
+ xColumns->getByIndex(nSelectedColumn),
+ css::uno::UNO_QUERY);
+ xSelSupplier->select(Any(xColumn));
+ }
+ else
+ {
+ xSelSupplier->select(Any());
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ }
+
+
+ m_bSelecting = false;
+}
+
+
+void FmGridControl::KeyInput( const KeyEvent& rKEvt )
+{
+ bool bDone = false;
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ if ( IsDesignMode()
+ && !rKeyCode.IsShift()
+ && !rKeyCode.IsMod1()
+ && !rKeyCode.IsMod2()
+ && GetParent() )
+ {
+ switch ( rKeyCode.GetCode() )
+ {
+ case KEY_ESCAPE:
+ GetParent()->GrabFocus();
+ bDone = true;
+ break;
+ case KEY_DELETE:
+ if ( GetSelectColumnCount() && GetPeer() && m_nCurrentSelectedColumn >= 0 )
+ {
+ Reference< css::container::XIndexContainer > xCols(GetPeer()->getColumns());
+ if ( xCols.is() )
+ {
+ try
+ {
+ if ( m_nCurrentSelectedColumn < xCols->getCount() )
+ {
+ Reference< XInterface > xCol;
+ xCols->getByIndex(m_nCurrentSelectedColumn) >>= xCol;
+ xCols->removeByIndex(m_nCurrentSelectedColumn);
+ ::comphelper::disposeComponent(xCol);
+ }
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "exception occurred while deleting a column");
+ }
+ }
+ }
+ bDone = true;
+ break;
+ }
+ }
+ if ( !bDone )
+ DbGridControl::KeyInput( rKEvt );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/fmcomp/fmgridif.cxx b/svx/source/fmcomp/fmgridif.cxx
new file mode 100644
index 000000000..bce6303d2
--- /dev/null
+++ b/svx/source/fmcomp/fmgridif.cxx
@@ -0,0 +1,2808 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <svx/fmgridif.hxx>
+#include <fmprop.hxx>
+#include <fmservs.hxx>
+#include <svx/fmtools.hxx>
+#include <fmurl.hxx>
+#include <formcontrolfactory.hxx>
+#include <gridcell.hxx>
+#include <sdbdatacolumn.hxx>
+#include <svx/fmgridcl.hxx>
+#include <tools/urlobj.hxx>
+
+#include <com/sun/star/awt/PosSize.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/form/XReset.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <o3tl/safeint.hxx>
+#include <vcl/unohelp.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/macros.h>
+
+using namespace ::svxform;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star;
+
+using ::com::sun::star::sdbcx::XColumnsSupplier;
+using ::com::sun::star::frame::XDispatchProviderInterceptor;
+using ::com::sun::star::frame::XDispatchProvider;
+using ::com::sun::star::accessibility::XAccessible;
+using ::com::sun::star::accessibility::XAccessibleContext;
+using ::com::sun::star::sdb::XRowSetSupplier;
+using ::com::sun::star::awt::XVclWindowPeer;
+
+
+static css::awt::FontDescriptor ImplCreateFontDescriptor( const vcl::Font& rFont )
+{
+ css::awt::FontDescriptor aFD;
+ aFD.Name = rFont.GetFamilyName();
+ aFD.StyleName = rFont.GetStyleName();
+ aFD.Height = static_cast<sal_Int16>(rFont.GetFontSize().Height());
+ aFD.Width = static_cast<sal_Int16>(rFont.GetFontSize().Width());
+ aFD.Family = static_cast<sal_Int16>(rFont.GetFamilyType());
+ aFD.CharSet = rFont.GetCharSet();
+ aFD.Pitch = static_cast<sal_Int16>(rFont.GetPitch());
+ aFD.CharacterWidth = vcl::unohelper::ConvertFontWidth( rFont.GetWidthType() );
+ aFD.Weight= vcl::unohelper::ConvertFontWeight( rFont.GetWeight() );
+ aFD.Slant = vcl::unohelper::ConvertFontSlant( rFont.GetItalic() );
+ aFD.Underline = static_cast<sal_Int16>(rFont.GetUnderline());
+ aFD.Strikeout = static_cast<sal_Int16>(rFont.GetStrikeout());
+ aFD.Orientation = toDegrees(rFont.GetOrientation());
+ aFD.Kerning = rFont.IsKerning();
+ aFD.WordLineMode = rFont.IsWordLineMode();
+ aFD.Type = 0; // ??? => only to metric...
+ return aFD;
+}
+
+
+static vcl::Font ImplCreateFont( const css::awt::FontDescriptor& rDescr )
+{
+ vcl::Font aFont;
+ aFont.SetFamilyName( rDescr.Name );
+ aFont.SetStyleName( rDescr.StyleName );
+ aFont.SetFontSize( ::Size( rDescr.Width, rDescr.Height ) );
+ aFont.SetFamily( static_cast<FontFamily>(rDescr.Family) );
+ aFont.SetCharSet( static_cast<rtl_TextEncoding>(rDescr.CharSet) );
+ aFont.SetPitch( static_cast<FontPitch>(rDescr.Pitch) );
+ aFont.SetWidthType( vcl::unohelper::ConvertFontWidth( rDescr.CharacterWidth ) );
+ aFont.SetWeight( vcl::unohelper::ConvertFontWeight( rDescr.Weight ) );
+ aFont.SetItalic( static_cast<FontItalic>(rDescr.Slant) );
+ aFont.SetUnderline( static_cast<::FontLineStyle>(rDescr.Underline) );
+ aFont.SetStrikeout( static_cast<::FontStrikeout>(rDescr.Strikeout) );
+ aFont.SetOrientation( Degree10(static_cast<sal_Int16>(rDescr.Orientation * 10)) );
+ aFont.SetKerning( static_cast<FontKerning>(rDescr.Kerning) );
+ aFont.SetWordLineMode( rDescr.WordLineMode );
+ return aFont;
+}
+
+FmXModifyMultiplexer::FmXModifyMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex )
+ :OWeakSubObject( rSource )
+ ,OInterfaceContainerHelper3( _rMutex )
+{
+}
+
+
+Any SAL_CALL FmXModifyMultiplexer::queryInterface(const Type& _rType)
+{
+ Any aReturn = ::cppu::queryInterface(_rType,
+ static_cast< css::util::XModifyListener*>(this),
+ static_cast< XEventListener*>(this)
+ );
+
+ if (!aReturn.hasValue())
+ aReturn = OWeakSubObject::queryInterface( _rType );
+
+ return aReturn;
+}
+
+
+void FmXModifyMultiplexer::disposing(const EventObject& )
+{
+}
+
+
+void FmXModifyMultiplexer::modified(const EventObject& e)
+{
+ EventObject aMulti( e);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XModifyListener::modified, aMulti );
+}
+
+FmXUpdateMultiplexer::FmXUpdateMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex )
+ :OWeakSubObject( rSource )
+ ,OInterfaceContainerHelper3( _rMutex )
+{
+}
+
+
+Any SAL_CALL FmXUpdateMultiplexer::queryInterface(const Type& _rType)
+{
+ Any aReturn = ::cppu::queryInterface(_rType,
+ static_cast< XUpdateListener*>(this),
+ static_cast< XEventListener*>(this)
+ );
+
+ if (!aReturn.hasValue())
+ aReturn = OWeakSubObject::queryInterface( _rType );
+
+ return aReturn;
+}
+
+
+void FmXUpdateMultiplexer::disposing(const EventObject& )
+{
+}
+
+
+sal_Bool FmXUpdateMultiplexer::approveUpdate(const EventObject &e)
+{
+ EventObject aMulti( e );
+ aMulti.Source = &m_rParent;
+
+ bool bResult = true;
+ if (getLength())
+ {
+ ::comphelper::OInterfaceIteratorHelper3 aIter(*this);
+ while ( bResult && aIter.hasMoreElements() )
+ bResult = aIter.next()->approveUpdate( aMulti );
+ }
+
+ return bResult;
+}
+
+
+void FmXUpdateMultiplexer::updated(const EventObject &e)
+{
+ EventObject aMulti( e );
+ aMulti.Source = &m_rParent;
+ notifyEach( &XUpdateListener::updated, aMulti );
+}
+
+FmXSelectionMultiplexer::FmXSelectionMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex )
+ :OWeakSubObject( rSource )
+ ,OInterfaceContainerHelper3( _rMutex )
+{
+}
+
+
+Any SAL_CALL FmXSelectionMultiplexer::queryInterface(const Type& _rType)
+{
+ Any aReturn = ::cppu::queryInterface(_rType,
+ static_cast< XSelectionChangeListener*>(this),
+ static_cast< XEventListener*>(this)
+ );
+
+ if (!aReturn.hasValue())
+ aReturn = OWeakSubObject::queryInterface( _rType );
+
+ return aReturn;
+}
+
+
+void FmXSelectionMultiplexer::disposing(const EventObject& )
+{
+}
+
+
+void SAL_CALL FmXSelectionMultiplexer::selectionChanged( const EventObject& _rEvent )
+{
+ EventObject aMulti(_rEvent);
+ aMulti.Source = &m_rParent;
+ notifyEach( &XSelectionChangeListener::selectionChanged, aMulti );
+}
+
+FmXContainerMultiplexer::FmXContainerMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex )
+ :OWeakSubObject( rSource )
+ ,OInterfaceContainerHelper3( _rMutex )
+{
+}
+
+
+Any SAL_CALL FmXContainerMultiplexer::queryInterface(const Type& _rType)
+{
+ Any aReturn = ::cppu::queryInterface(_rType,
+ static_cast< XContainerListener*>(this),
+ static_cast< XEventListener*>(this)
+ );
+
+ if (!aReturn.hasValue())
+ aReturn = OWeakSubObject::queryInterface( _rType );
+
+ return aReturn;
+}
+
+
+void FmXContainerMultiplexer::disposing(const EventObject& )
+{
+}
+
+void FmXContainerMultiplexer::elementInserted(const ContainerEvent& e)
+{
+ ContainerEvent aMulti( e );
+ aMulti.Source = &m_rParent;
+ notifyEach( &XContainerListener::elementInserted, aMulti );
+}
+
+
+void FmXContainerMultiplexer::elementRemoved(const ContainerEvent& e)
+{
+ ContainerEvent aMulti( e );
+ aMulti.Source = &m_rParent;
+ notifyEach( &XContainerListener::elementRemoved, aMulti );
+}
+
+
+void FmXContainerMultiplexer::elementReplaced(const ContainerEvent& e)
+{
+ ContainerEvent aMulti( e );
+ aMulti.Source = &m_rParent;
+ notifyEach( &XContainerListener::elementReplaced, aMulti );
+}
+
+FmXGridControlMultiplexer::FmXGridControlMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex )
+ :OWeakSubObject( rSource )
+ ,OInterfaceContainerHelper3( _rMutex )
+{
+}
+
+
+Any SAL_CALL FmXGridControlMultiplexer::queryInterface(const Type& _rType)
+{
+ Any aReturn = ::cppu::queryInterface( _rType,
+ static_cast< XGridControlListener*>(this)
+ );
+
+ if (!aReturn.hasValue())
+ aReturn = OWeakSubObject::queryInterface( _rType );
+
+ return aReturn;
+}
+
+
+void FmXGridControlMultiplexer::disposing( const EventObject& )
+{
+}
+
+
+void SAL_CALL FmXGridControlMultiplexer::columnChanged( const EventObject& _event )
+{
+ EventObject aForwardedEvent( _event );
+ aForwardedEvent.Source = &m_rParent;
+ notifyEach( &XGridControlListener::columnChanged, aForwardedEvent );
+}
+
+
+//= FmXGridControl
+
+
+Reference< XInterface > FmXGridControl_NewInstance_Impl(const Reference< XMultiServiceFactory>& _rxFactory)
+{
+ return *(new FmXGridControl( comphelper::getComponentContext(_rxFactory) ));
+}
+
+FmXGridControl::FmXGridControl(const Reference< XComponentContext >& _rxContext)
+ :m_aModifyListeners(*this, GetMutex())
+ ,m_aUpdateListeners(*this, GetMutex())
+ ,m_aContainerListeners(*this, GetMutex())
+ ,m_aSelectionListeners(*this, GetMutex())
+ ,m_aGridControlListeners(*this, GetMutex())
+ ,m_bInDraw(false)
+ ,m_xContext(_rxContext)
+{
+}
+
+
+FmXGridControl::~FmXGridControl()
+{
+}
+
+
+Any SAL_CALL FmXGridControl::queryAggregation(const Type& _rType)
+{
+ Any aReturn = FmXGridControl_BASE::queryInterface(_rType);
+
+ if (!aReturn.hasValue())
+ aReturn = UnoControl::queryAggregation( _rType );
+ return aReturn;
+}
+
+
+Sequence< Type> SAL_CALL FmXGridControl::getTypes( )
+{
+ return comphelper::concatSequences(UnoControl::getTypes(),FmXGridControl_BASE::getTypes());
+}
+
+
+Sequence<sal_Int8> SAL_CALL FmXGridControl::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL FmXGridControl::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+OUString SAL_CALL FmXGridControl::getImplementationName()
+{
+ return "com.sun.star.form.FmXGridControl";
+}
+
+css::uno::Sequence<OUString> SAL_CALL FmXGridControl::getSupportedServiceNames()
+{
+ return { FM_SUN_CONTROL_GRIDCONTROL, "com.sun.star.awt.UnoControl" };
+}
+
+
+void SAL_CALL FmXGridControl::dispose()
+{
+ SolarMutexGuard aGuard;
+
+ EventObject aEvt;
+ aEvt.Source = static_cast< ::cppu::OWeakObject* >(this);
+ m_aModifyListeners.disposeAndClear(aEvt);
+ m_aUpdateListeners.disposeAndClear(aEvt);
+ m_aContainerListeners.disposeAndClear(aEvt);
+
+ UnoControl::dispose();
+}
+
+
+OUString FmXGridControl::GetComponentServiceName() const
+{
+ return "DBGrid";
+}
+
+
+sal_Bool SAL_CALL FmXGridControl::setModel(const Reference< css::awt::XControlModel >& rModel)
+{
+ SolarMutexGuard aGuard;
+
+ if (!UnoControl::setModel(rModel))
+ return false;
+
+ Reference< XGridPeer > xGridPeer(getPeer(), UNO_QUERY);
+ if (xGridPeer.is())
+ {
+ Reference< XIndexContainer > xCols(mxModel, UNO_QUERY);
+ xGridPeer->setColumns(xCols);
+ }
+ return true;
+}
+
+
+rtl::Reference<FmXGridPeer> FmXGridControl::imp_CreatePeer(vcl::Window* pParent)
+{
+ rtl::Reference<FmXGridPeer> pReturn = new FmXGridPeer(m_xContext);
+
+ // translate properties into WinBits
+ WinBits nStyle = WB_TABSTOP;
+ Reference< XPropertySet > xModelSet(getModel(), UNO_QUERY);
+ if (xModelSet.is())
+ {
+ try
+ {
+ if (::comphelper::getINT16(xModelSet->getPropertyValue(FM_PROP_BORDER)))
+ nStyle |= WB_BORDER;
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("Can not get style");
+ }
+ }
+
+ pReturn->Create(pParent, nStyle);
+ return pReturn;
+}
+
+
+void SAL_CALL FmXGridControl::createPeer(const Reference< css::awt::XToolkit >& /*rToolkit*/, const Reference< css::awt::XWindowPeer >& rParentPeer)
+{
+ if ( !mxModel.is() )
+ throw DisposedException( OUString(), *this );
+
+ DBG_ASSERT(/*(0 == m_nPeerCreationLevel) && */!mbCreatingPeer, "FmXGridControl::createPeer : recursion!");
+ // I think this should never assert, now that we're using the base class' mbCreatingPeer in addition to
+ // our own m_nPeerCreationLevel
+ // But I'm not sure as I don't _fully_ understand the underlying toolkit implementations...
+ // (if this asserts, we still need m_nPeerCreationLevel. If not, we could omit it...)
+ // 14.05.2001 - 86836 - frank.schoenheit@germany.sun.com
+
+ // TODO: why the hell this whole class does not use any mutex?
+
+ if (getPeer().is())
+ return;
+
+ mbCreatingPeer = true;
+ // mbCreatingPeer is virtually the same as m_nPeerCreationLevel, but it's the base class' method
+ // to prevent recursion.
+
+ vcl::Window* pParentWin = nullptr;
+ if (rParentPeer.is())
+ {
+ VCLXWindow* pParent = comphelper::getFromUnoTunnel<VCLXWindow>(rParentPeer);
+ if (pParent)
+ pParentWin = pParent->GetWindow();
+ }
+
+ rtl::Reference<FmXGridPeer> pPeer = imp_CreatePeer(pParentWin);
+ DBG_ASSERT(pPeer != nullptr, "FmXGridControl::createPeer : imp_CreatePeer didn't return a peer !");
+ setPeer( pPeer );
+
+ // reading the properties from the model
+// ++m_nPeerCreationLevel;
+ updateFromModel();
+
+ // consider the following ugly scenario: updateFromModel leads to a propertiesChanges on the Control,
+ // which determines, dat a "critical" property has changed (e.g. "Border") and therefore starts a new
+ // Peer, which lands again here in createPeer we also start a second FmXGridPeer and initialise it.
+ // Then we exit from the first incarnation's updateFromModel and continue working with the pPeer,
+ // that is in fact now already obsolete (as another peer is being started in the second incarnation).
+ // Therefore the effort with the PeerCreationLevel, which ensures that we really use the Peer
+ // created at the deepest level, but first initialise it in the top-level.
+// if (--m_nPeerCreationLevel == 0)
+ {
+ DBG_ASSERT(getPeer().is(), "FmXGridControl::createPeer : something went wrong ... no top level peer !");
+ pPeer = comphelper::getFromUnoTunnel<FmXGridPeer>(getPeer());
+
+ setPosSize( maComponentInfos.nX, maComponentInfos.nY, maComponentInfos.nWidth, maComponentInfos.nHeight, css::awt::PosSize::POSSIZE );
+
+ Reference< XIndexContainer > xColumns(getModel(), UNO_QUERY);
+ if (xColumns.is())
+ pPeer->setColumns(xColumns);
+
+ if (maComponentInfos.bVisible)
+ pPeer->setVisible(true);
+
+ if (!maComponentInfos.bEnable)
+ pPeer->setEnable(false);
+
+ if (maWindowListeners.getLength())
+ pPeer->addWindowListener( &maWindowListeners );
+
+ if (maFocusListeners.getLength())
+ pPeer->addFocusListener( &maFocusListeners );
+
+ if (maKeyListeners.getLength())
+ pPeer->addKeyListener( &maKeyListeners );
+
+ if (maMouseListeners.getLength())
+ pPeer->addMouseListener( &maMouseListeners );
+
+ if (maMouseMotionListeners.getLength())
+ pPeer->addMouseMotionListener( &maMouseMotionListeners );
+
+ if (maPaintListeners.getLength())
+ pPeer->addPaintListener( &maPaintListeners );
+
+ if (m_aModifyListeners.getLength())
+ pPeer->addModifyListener( &m_aModifyListeners );
+
+ if (m_aUpdateListeners.getLength())
+ pPeer->addUpdateListener( &m_aUpdateListeners );
+
+ if (m_aContainerListeners.getLength())
+ pPeer->addContainerListener( &m_aContainerListeners );
+
+ // forward the design mode
+ bool bForceAlivePeer = m_bInDraw && !maComponentInfos.bVisible;
+ // (we force an alive-mode peer if we're in "draw", cause in this case the peer will be used for drawing in
+ // foreign devices. We ensure this with the visibility check as a living peer is assumed to be noncritical
+ // only if invisible)
+ Any aOldCursorBookmark;
+ if (!mbDesignMode || bForceAlivePeer)
+ {
+ Reference< XFormComponent > xComp(getModel(), UNO_QUERY);
+ if (xComp.is())
+ {
+ Reference< XRowSet > xForm(xComp->getParent(), UNO_QUERY);
+ // is the form alive?
+ // we can see that if the form contains columns
+ Reference< css::sdbcx::XColumnsSupplier > xColumnsSupplier(xForm, UNO_QUERY);
+ if (xColumnsSupplier.is())
+ {
+ if (Reference< XIndexAccess > (xColumnsSupplier->getColumns(),UNO_QUERY_THROW)->getCount())
+ {
+ // we get only a new bookmark if the resultset is not forwardonly
+ if (::comphelper::getINT32(Reference< XPropertySet > (xForm, UNO_QUERY_THROW)->getPropertyValue(FM_PROP_RESULTSET_TYPE)) != ResultSetType::FORWARD_ONLY)
+ {
+ // as the FmGridControl touches the data source it is connected to we have to remember the current
+ // cursor position (and restore afterwards)
+ // OJ: but only when we stand on a valid row
+ if ( !xForm->isBeforeFirst() && !xForm->isAfterLast() )
+ {
+ try
+ {
+ aOldCursorBookmark = Reference< css::sdbcx::XRowLocate > (xForm, UNO_QUERY_THROW)->getBookmark();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+ }
+ }
+ pPeer->setRowSet(xForm);
+ }
+ }
+ pPeer->setDesignMode(mbDesignMode && !bForceAlivePeer);
+
+ try
+ {
+ if (aOldCursorBookmark.hasValue())
+ { // we have a valid bookmark, so we have to restore the cursor's position
+ Reference< XFormComponent > xComp(getModel(), UNO_QUERY);
+ Reference< css::sdbcx::XRowLocate > xLocate(xComp->getParent(), UNO_QUERY);
+ xLocate->moveToBookmark(aOldCursorBookmark);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ Reference< css::awt::XView > xPeerView(getPeer(), UNO_QUERY);
+ xPeerView->setZoom( maComponentInfos.nZoomX, maComponentInfos.nZoomY );
+ xPeerView->setGraphics( mxGraphics );
+ }
+ mbCreatingPeer = false;
+}
+
+
+void FmXGridControl::addModifyListener(const Reference< css::util::XModifyListener >& l)
+{
+ m_aModifyListeners.addInterface( l );
+ if( getPeer().is() && m_aModifyListeners.getLength() == 1 )
+ {
+ Reference< css::util::XModifyBroadcaster > xGrid(getPeer(), UNO_QUERY);
+ xGrid->addModifyListener( &m_aModifyListeners);
+ }
+}
+
+
+sal_Bool SAL_CALL FmXGridControl::select( const Any& _rSelection )
+{
+ SolarMutexGuard aGuard;
+ Reference< XSelectionSupplier > xPeer(getPeer(), UNO_QUERY);
+ return xPeer->select(_rSelection);
+}
+
+
+Any SAL_CALL FmXGridControl::getSelection( )
+{
+ SolarMutexGuard aGuard;
+ Reference< XSelectionSupplier > xPeer(getPeer(), UNO_QUERY);
+ return xPeer->getSelection();
+}
+
+
+void SAL_CALL FmXGridControl::addSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
+{
+ m_aSelectionListeners.addInterface( _rxListener );
+ if( getPeer().is() && 1 == m_aSelectionListeners.getLength() )
+ {
+ Reference< XSelectionSupplier > xGrid(getPeer(), UNO_QUERY);
+ xGrid->addSelectionChangeListener( &m_aSelectionListeners);
+ }
+}
+
+
+void SAL_CALL FmXGridControl::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
+{
+ if( getPeer().is() && 1 == m_aSelectionListeners.getLength() )
+ {
+ Reference< XSelectionSupplier > xGrid(getPeer(), UNO_QUERY);
+ xGrid->removeSelectionChangeListener( &m_aSelectionListeners);
+ }
+ m_aSelectionListeners.removeInterface( _rxListener );
+}
+
+
+Sequence< sal_Bool > SAL_CALL FmXGridControl::queryFieldDataType( const Type& xType )
+{
+ if (getPeer().is())
+ {
+ Reference< XGridFieldDataSupplier > xPeerSupplier(getPeer(), UNO_QUERY);
+ if (xPeerSupplier.is())
+ return xPeerSupplier->queryFieldDataType(xType);
+ }
+
+ return Sequence<sal_Bool>();
+}
+
+
+Sequence< Any > SAL_CALL FmXGridControl::queryFieldData( sal_Int32 nRow, const Type& xType )
+{
+ if (getPeer().is())
+ {
+ Reference< XGridFieldDataSupplier > xPeerSupplier(getPeer(), UNO_QUERY);
+ if (xPeerSupplier.is())
+ return xPeerSupplier->queryFieldData(nRow, xType);
+ }
+
+ return Sequence< Any>();
+}
+
+
+void SAL_CALL FmXGridControl::removeModifyListener(const Reference< css::util::XModifyListener >& l)
+{
+ if( getPeer().is() && m_aModifyListeners.getLength() == 1 )
+ {
+ Reference< css::util::XModifyBroadcaster > xGrid(getPeer(), UNO_QUERY);
+ xGrid->removeModifyListener( &m_aModifyListeners);
+ }
+ m_aModifyListeners.removeInterface( l );
+}
+
+
+void SAL_CALL FmXGridControl::draw( sal_Int32 x, sal_Int32 y )
+{
+ SolarMutexGuard aGuard;
+ m_bInDraw = true;
+ UnoControl::draw(x, y);
+ m_bInDraw = false;
+}
+
+
+void SAL_CALL FmXGridControl::setDesignMode(sal_Bool bOn)
+{
+ css::util::ModeChangeEvent aModeChangeEvent;
+
+ // --- <mutex_lock> ---
+ {
+ SolarMutexGuard aGuard;
+
+ Reference< XRowSetSupplier > xGrid(getPeer(), UNO_QUERY);
+
+ if (xGrid.is() && (bool(bOn) != mbDesignMode || (!bOn && !xGrid->getRowSet().is())))
+ {
+ if (bOn)
+ {
+ xGrid->setRowSet(Reference< XRowSet > ());
+ }
+ else
+ {
+ Reference< XFormComponent > xComp(getModel(), UNO_QUERY);
+ if (xComp.is())
+ {
+ Reference< XRowSet > xForm(xComp->getParent(), UNO_QUERY);
+ xGrid->setRowSet(xForm);
+ }
+ }
+
+ // Avoid infinite recursion when calling XVclWindowPeer::setDesignMode below
+ mbDesignMode = bOn;
+
+ Reference< XVclWindowPeer > xVclWindowPeer( getPeer(), UNO_QUERY );
+ if (xVclWindowPeer.is())
+ xVclWindowPeer->setDesignMode(bOn);
+ }
+ else
+ {
+ mbDesignMode = bOn;
+ }
+
+ // dispose our current AccessibleContext, if we have one
+ // (changing the design mode implies having a new implementation for this context,
+ // so the old one must be declared DEFUNC)
+ DisposeAccessibleContext(
+ Reference<XComponent>(maAccessibleContext, UNO_QUERY));
+ maAccessibleContext.clear();
+
+ // prepare firing an event
+ aModeChangeEvent.Source = *this;
+ aModeChangeEvent.NewMode = mbDesignMode ? std::u16string_view( u"design" ) : std::u16string_view( u"alive" );
+ }
+
+ // --- </mutex_lock> ---
+ maModeChangeListeners.notifyEach( &XModeChangeListener::modeChanged, aModeChangeEvent );
+}
+
+// XBoundComponent
+
+void SAL_CALL FmXGridControl::addUpdateListener(const Reference< XUpdateListener >& l)
+{
+ m_aUpdateListeners.addInterface( l );
+ if( getPeer().is() && m_aUpdateListeners.getLength() == 1 )
+ {
+ Reference< XBoundComponent > xBound(getPeer(), UNO_QUERY);
+ xBound->addUpdateListener( &m_aUpdateListeners);
+ }
+}
+
+
+void SAL_CALL FmXGridControl::removeUpdateListener(const Reference< XUpdateListener >& l)
+{
+ if( getPeer().is() && m_aUpdateListeners.getLength() == 1 )
+ {
+ Reference< XBoundComponent > xBound(getPeer(), UNO_QUERY);
+ xBound->removeUpdateListener( &m_aUpdateListeners);
+ }
+ m_aUpdateListeners.removeInterface( l );
+}
+
+
+sal_Bool SAL_CALL FmXGridControl::commit()
+{
+ Reference< XBoundComponent > xBound(getPeer(), UNO_QUERY);
+ if (xBound.is())
+ return xBound->commit();
+ else
+ return true;
+}
+
+// XContainer
+
+void SAL_CALL FmXGridControl::addContainerListener(const Reference< XContainerListener >& l)
+{
+ m_aContainerListeners.addInterface( l );
+ if( getPeer().is() && m_aContainerListeners.getLength() == 1 )
+ {
+ Reference< XContainer > xContainer(getPeer(), UNO_QUERY);
+ xContainer->addContainerListener( &m_aContainerListeners);
+ }
+}
+
+
+void SAL_CALL FmXGridControl::removeContainerListener(const Reference< XContainerListener >& l)
+{
+ if( getPeer().is() && m_aContainerListeners.getLength() == 1 )
+ {
+ Reference< XContainer > xContainer(getPeer(), UNO_QUERY);
+ xContainer->removeContainerListener( &m_aContainerListeners);
+ }
+ m_aContainerListeners.removeInterface( l );
+}
+
+
+Reference< css::frame::XDispatch > SAL_CALL FmXGridControl::queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags)
+{
+ Reference< css::frame::XDispatchProvider > xPeerProvider(getPeer(), UNO_QUERY);
+ if (xPeerProvider.is())
+ return xPeerProvider->queryDispatch(aURL, aTargetFrameName, nSearchFlags);
+ else
+ return Reference< css::frame::XDispatch > ();
+}
+
+
+Sequence< Reference< css::frame::XDispatch > > SAL_CALL FmXGridControl::queryDispatches(const Sequence< css::frame::DispatchDescriptor>& aDescripts)
+{
+ Reference< css::frame::XDispatchProvider > xPeerProvider(getPeer(), UNO_QUERY);
+ if (xPeerProvider.is())
+ return xPeerProvider->queryDispatches(aDescripts);
+ else
+ return Sequence< Reference< css::frame::XDispatch > >();
+}
+
+
+void SAL_CALL FmXGridControl::registerDispatchProviderInterceptor(const Reference< css::frame::XDispatchProviderInterceptor >& _xInterceptor)
+{
+ Reference< css::frame::XDispatchProviderInterception > xPeerInterception(getPeer(), UNO_QUERY);
+ if (xPeerInterception.is())
+ xPeerInterception->registerDispatchProviderInterceptor(_xInterceptor);
+}
+
+
+void SAL_CALL FmXGridControl::releaseDispatchProviderInterceptor(const Reference< css::frame::XDispatchProviderInterceptor >& _xInterceptor)
+{
+ Reference< css::frame::XDispatchProviderInterception > xPeerInterception(getPeer(), UNO_QUERY);
+ if (xPeerInterception.is())
+ xPeerInterception->releaseDispatchProviderInterceptor(_xInterceptor);
+}
+
+
+void SAL_CALL FmXGridControl::addGridControlListener( const Reference< XGridControlListener >& _listener )
+{
+ ::osl::MutexGuard aGuard( GetMutex() );
+
+ m_aGridControlListeners.addInterface( _listener );
+ if ( getPeer().is() && 1 == m_aGridControlListeners.getLength() )
+ {
+ Reference< XGridControl > xPeerGrid( getPeer(), UNO_QUERY );
+ if ( xPeerGrid.is() )
+ xPeerGrid->addGridControlListener( &m_aGridControlListeners );
+ }
+}
+
+
+void SAL_CALL FmXGridControl::removeGridControlListener( const Reference< XGridControlListener >& _listener )
+{
+ ::osl::MutexGuard aGuard( GetMutex() );
+
+ if( getPeer().is() && 1 == m_aGridControlListeners.getLength() )
+ {
+ Reference< XGridControl > xPeerGrid( getPeer(), UNO_QUERY );
+ if ( xPeerGrid.is() )
+ xPeerGrid->removeGridControlListener( &m_aGridControlListeners );
+ }
+
+ m_aGridControlListeners.removeInterface( _listener );
+}
+
+
+sal_Int16 SAL_CALL FmXGridControl::getCurrentColumnPosition()
+{
+ Reference< XGridControl > xGrid( getPeer(), UNO_QUERY );
+ return xGrid.is() ? xGrid->getCurrentColumnPosition() : -1;
+}
+
+
+void SAL_CALL FmXGridControl::setCurrentColumnPosition(sal_Int16 nPos)
+{
+ Reference< XGridControl > xGrid( getPeer(), UNO_QUERY );
+ if ( xGrid.is() )
+ {
+ SolarMutexGuard aGuard;
+ xGrid->setCurrentColumnPosition( nPos );
+ }
+}
+
+// XElementAccess
+
+sal_Bool SAL_CALL FmXGridControl::hasElements()
+{
+ Reference< XElementAccess > xPeer(getPeer(), UNO_QUERY);
+ return xPeer.is() && xPeer->hasElements();
+}
+
+
+Type SAL_CALL FmXGridControl::getElementType( )
+{
+ return cppu::UnoType<css::awt::XTextComponent>::get();
+}
+
+// XEnumerationAccess
+
+Reference< XEnumeration > SAL_CALL FmXGridControl::createEnumeration()
+{
+ Reference< XEnumerationAccess > xPeer(getPeer(), UNO_QUERY);
+ if (xPeer.is())
+ return xPeer->createEnumeration();
+ else
+ return new ::comphelper::OEnumerationByIndex(this);
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL FmXGridControl::getCount()
+{
+ Reference< XIndexAccess > xPeer(getPeer(), UNO_QUERY);
+ return xPeer.is() ? xPeer->getCount() : 0;
+}
+
+
+Any SAL_CALL FmXGridControl::getByIndex(sal_Int32 _nIndex)
+{
+ Reference< XIndexAccess > xPeer(getPeer(), UNO_QUERY);
+ if (!xPeer.is())
+ throw IndexOutOfBoundsException();
+
+ return xPeer->getByIndex(_nIndex);
+}
+
+// css::util::XModeSelector
+
+void SAL_CALL FmXGridControl::setMode(const OUString& Mode)
+{
+ Reference< css::util::XModeSelector > xPeer(getPeer(), UNO_QUERY);
+ if (!xPeer.is())
+ throw NoSupportException();
+
+ xPeer->setMode(Mode);
+}
+
+
+OUString SAL_CALL FmXGridControl::getMode()
+{
+ Reference< css::util::XModeSelector > xPeer(getPeer(), UNO_QUERY);
+ return xPeer.is() ? xPeer->getMode() : OUString();
+}
+
+
+css::uno::Sequence<OUString> SAL_CALL FmXGridControl::getSupportedModes()
+{
+ Reference< css::util::XModeSelector > xPeer(getPeer(), UNO_QUERY);
+ return xPeer.is() ? xPeer->getSupportedModes() : css::uno::Sequence<OUString>();
+}
+
+
+sal_Bool SAL_CALL FmXGridControl::supportsMode(const OUString& Mode)
+{
+ Reference< css::util::XModeSelector > xPeer(getPeer(), UNO_QUERY);
+ return xPeer.is() && xPeer->supportsMode(Mode);
+}
+
+void SAL_CALL FmXGridControl::setFocus()
+{
+ FmXGridPeer* pPeer = comphelper::getFromUnoTunnel<FmXGridPeer>(getPeer());
+ if (pPeer)
+ {
+ VclPtr<FmGridControl> xGrid = pPeer->GetAs<FmGridControl>();
+ bool bAlreadyHasFocus = xGrid->HasChildPathFocus() || xGrid->ControlHasFocus();
+ // if the focus is already in the control don't grab focus again which
+ // would grab focus away from any native widgets hosted in the control
+ if (bAlreadyHasFocus)
+ return;
+ }
+ UnoControl::setFocus();
+}
+
+// helper class which prevents that in the peer's header the FmGridListener must be known
+class FmXGridPeer::GridListenerDelegator : public FmGridListener
+{
+protected:
+ FmXGridPeer* m_pPeer;
+
+public:
+ explicit GridListenerDelegator( FmXGridPeer* _pPeer );
+ virtual ~GridListenerDelegator();
+
+protected:
+ virtual void selectionChanged() override;
+ virtual void columnChanged() override;
+};
+
+
+FmXGridPeer::GridListenerDelegator::GridListenerDelegator(FmXGridPeer* _pPeer)
+ :m_pPeer(_pPeer)
+{
+ DBG_ASSERT(m_pPeer, "GridListenerDelegator::GridListenerDelegator");
+}
+
+FmXGridPeer::GridListenerDelegator::~GridListenerDelegator()
+{
+}
+
+
+void FmXGridPeer::GridListenerDelegator::selectionChanged()
+{
+ m_pPeer->selectionChanged();
+}
+
+
+void FmXGridPeer::GridListenerDelegator::columnChanged()
+{
+ m_pPeer->columnChanged();
+}
+
+void FmXGridPeer::selectionChanged()
+{
+ EventObject aSource;
+ aSource.Source = static_cast< ::cppu::OWeakObject* >(this);
+ m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aSource);
+}
+
+
+void FmXGridPeer::columnChanged()
+{
+ EventObject aEvent( *this );
+ m_aGridControlListeners.notifyEach( &XGridControlListener::columnChanged, aEvent );
+}
+
+
+FmXGridPeer::FmXGridPeer(const Reference< XComponentContext >& _rxContext)
+ :m_xContext(_rxContext)
+ ,m_aModifyListeners(m_aMutex)
+ ,m_aUpdateListeners(m_aMutex)
+ ,m_aContainerListeners(m_aMutex)
+ ,m_aSelectionListeners(m_aMutex)
+ ,m_aGridControlListeners(m_aMutex)
+ ,m_aMode("DataMode")
+ ,m_nCursorListening(0)
+ ,m_bInterceptingDispatch(false)
+{
+ // Create must be called after this constructor
+ m_pGridListener.reset( new GridListenerDelegator( this ) );
+}
+
+
+VclPtr<FmGridControl> FmXGridPeer::imp_CreateControl(vcl::Window* pParent, WinBits nStyle)
+{
+ return VclPtr<FmGridControl>::Create(m_xContext, pParent, this, nStyle);
+}
+
+
+void FmXGridPeer::Create(vcl::Window* pParent, WinBits nStyle)
+{
+ VclPtr<FmGridControl> pWin = imp_CreateControl(pParent, nStyle);
+ DBG_ASSERT(pWin != nullptr, "FmXGridPeer::Create : imp_CreateControl didn't return a control !");
+
+ pWin->SetStateProvider(LINK(this, FmXGridPeer, OnQueryGridSlotState));
+ pWin->SetSlotExecutor(LINK(this, FmXGridPeer, OnExecuteGridSlot));
+
+ // want to hear about row selections
+ pWin->setGridListener( m_pGridListener.get() );
+
+ // Init must always be called
+ pWin->Init();
+ pWin->SetComponentInterface(this);
+
+ getSupportedURLs();
+}
+
+FmXGridPeer::~FmXGridPeer()
+{
+ setRowSet(Reference< XRowSet > ());
+ setColumns(Reference< XIndexContainer > ());
+}
+
+UNO3_GETIMPLEMENTATION2_IMPL(FmXGridPeer, VCLXWindow);
+
+// XEventListener
+
+void FmXGridPeer::disposing(const EventObject& e)
+{
+ bool bKnownSender = false;
+
+ Reference< XIndexContainer > xCols( e.Source, UNO_QUERY );
+ if ( xCols.is() )
+ {
+ setColumns(Reference< XIndexContainer > ());
+ bKnownSender = true;
+ }
+
+ Reference< XRowSet > xCursor(e.Source, UNO_QUERY);
+ if (xCursor.is())
+ {
+ setRowSet( m_xCursor );
+ m_xCursor = nullptr;
+ bKnownSender = true;
+ }
+
+
+ if ( !bKnownSender && m_pDispatchers )
+ {
+ const Sequence< URL>& aSupportedURLs = getSupportedURLs();
+ const URL* pSupportedURLs = aSupportedURLs.getConstArray();
+ for ( sal_Int32 i=0; i < ( aSupportedURLs.getLength() ) && !bKnownSender; ++i, ++pSupportedURLs )
+ {
+ if ( m_pDispatchers[i] == e.Source )
+ {
+ m_pDispatchers[i]->removeStatusListener( static_cast< css::frame::XStatusListener* >( this ), *pSupportedURLs );
+ m_pDispatchers[i] = nullptr;
+ m_pStateCache[i] = false;
+ bKnownSender = true;
+ }
+ }
+ }
+
+ if ( !bKnownSender )
+ VCLXWindow::disposing(e);
+}
+
+
+void FmXGridPeer::addModifyListener(const Reference< css::util::XModifyListener >& l)
+{
+ m_aModifyListeners.addInterface( l );
+}
+
+
+void FmXGridPeer::removeModifyListener(const Reference< css::util::XModifyListener >& l)
+{
+ m_aModifyListeners.removeInterface( l );
+}
+
+
+#define LAST_KNOWN_TYPE FormComponentType::PATTERNFIELD
+Sequence< sal_Bool > SAL_CALL FmXGridPeer::queryFieldDataType( const Type& xType )
+{
+ // a 'conversion table'
+ static const bool bCanConvert[LAST_KNOWN_TYPE][4] =
+ {
+ { false, false, false, false }, // FormComponentType::CONTROL
+ { false, false, false, false }, // FormComponentType::COMMANDBUTTON
+ { false, false, false, false }, // FormComponentType::RADIOBUTTON
+ { false, false, false, false }, // FormComponentType::IMAGEBUTTON
+ { false, false, false, true }, // FormComponentType::CHECKBOX
+ { false, false, false, false }, // FormComponentType::LISTBOX
+ { false, false, false, false }, // FormComponentType::COMBOBOX
+ { false, false, false, false }, // FormComponentType::GROUPBOX
+ { true , false, false, false }, // FormComponentType::TEXTFIELD
+ { false, false, false, false }, // FormComponentType::FIXEDTEXT
+ { false, false, false, false }, // FormComponentType::GRIDCONTROL
+ { false, false, false, false }, // FormComponentType::FILECONTROL
+ { false, false, false, false }, // FormComponentType::HIDDENCONTROL
+ { false, false, false, false }, // FormComponentType::IMAGECONTROL
+ { true , true , true , false }, // FormComponentType::DATEFIELD
+ { true , true , false, false }, // FormComponentType::TIMEFIELD
+ { true , true , false, false }, // FormComponentType::NUMERICFIELD
+ { true , true , false, false }, // FormComponentType::CURRENCYFIELD
+ { true , false, false, false } // FormComponentType::PATTERNFIELD
+ };
+
+
+ sal_Int16 nMapColumn = -1;
+ switch (xType.getTypeClass())
+ {
+ case TypeClass_STRING : nMapColumn = 0; break;
+ case TypeClass_FLOAT:
+ case TypeClass_DOUBLE : nMapColumn = 1; break;
+ case TypeClass_SHORT:
+ case TypeClass_LONG:
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_UNSIGNED_SHORT : nMapColumn = 2; break;
+ case TypeClass_BOOLEAN : nMapColumn = 3; break;
+ default:
+ break;
+ }
+
+ Reference< XIndexContainer > xColumns = getColumns();
+
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ sal_Int32 nColumns = pGrid->GetViewColCount();
+
+ std::vector< std::unique_ptr<DbGridColumn> > const & aColumns = pGrid->GetColumns();
+
+ Sequence<sal_Bool> aReturnSequence(nColumns);
+ sal_Bool* pReturnArray = aReturnSequence.getArray();
+
+ bool bRequestedAsAny = (xType.getTypeClass() == TypeClass_ANY);
+
+ DbGridColumn* pCol;
+ Reference< css::sdb::XColumn > xFieldContent;
+ Reference< XPropertySet > xCurrentColumn;
+ for (sal_Int32 i=0; i<nColumns; ++i)
+ {
+ if (bRequestedAsAny)
+ {
+ pReturnArray[i] = true;
+ continue;
+ }
+
+ pReturnArray[i] = false;
+
+ sal_uInt16 nModelPos = pGrid->GetModelColumnPos(pGrid->GetColumnIdFromViewPos(static_cast<sal_uInt16>(i)));
+ DBG_ASSERT(nModelPos != sal_uInt16(-1), "FmXGridPeer::queryFieldDataType : no model pos !");
+
+ pCol = aColumns[ nModelPos ].get();
+ const DbGridRowRef xRow = pGrid->GetSeekRow();
+ xFieldContent = (xRow.is() && xRow->HasField(pCol->GetFieldPos())) ? xRow->GetField(pCol->GetFieldPos()).getColumn() : Reference< css::sdb::XColumn > ();
+ if (!xFieldContent.is())
+ // can't supply anything without a field content
+ // FS - 07.12.99 - 54391
+ continue;
+
+ xColumns->getByIndex(nModelPos) >>= xCurrentColumn;
+ if (!::comphelper::hasProperty(FM_PROP_CLASSID, xCurrentColumn))
+ continue;
+
+ sal_Int16 nClassId = sal_Int16();
+ xCurrentColumn->getPropertyValue(FM_PROP_CLASSID) >>= nClassId;
+ if (nClassId>LAST_KNOWN_TYPE)
+ continue;
+ DBG_ASSERT(nClassId>0, "FmXGridPeer::queryFieldDataType : somebody changed the definition of the FormComponentType enum !");
+
+ if (nMapColumn != -1)
+ pReturnArray[i] = bCanConvert[nClassId-1][nMapColumn];
+ }
+
+ return aReturnSequence;
+}
+
+
+Sequence< Any > SAL_CALL FmXGridPeer::queryFieldData( sal_Int32 nRow, const Type& xType )
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ DBG_ASSERT(pGrid && pGrid->IsOpen(), "FmXGridPeer::queryFieldData : have no valid grid window !");
+ if (!pGrid || !pGrid->IsOpen())
+ return Sequence< Any>();
+
+ // move the control to the specified row
+ if (!pGrid->SeekRow(nRow))
+ {
+ throw IllegalArgumentException();
+ }
+
+ // don't use GetCurrentRow as this isn't affected by the above SeekRow
+ // FS - 30.09.99 - 68644
+ DbGridRowRef xPaintRow = pGrid->GetPaintRow();
+ ENSURE_OR_THROW( xPaintRow.is(), "invalid paint row" );
+
+ // I need the columns of the control for GetFieldText
+ std::vector< std::unique_ptr<DbGridColumn> > const & aColumns = pGrid->GetColumns();
+
+ // and through all the columns
+ sal_Int32 nColumnCount = pGrid->GetViewColCount();
+
+ Sequence< Any> aReturnSequence(nColumnCount);
+ Any* pReturnArray = aReturnSequence.getArray();
+
+ bool bRequestedAsAny = (xType.getTypeClass() == TypeClass_ANY);
+ Reference< css::sdb::XColumn > xFieldContent;
+ for (sal_Int32 i=0; i < nColumnCount; ++i)
+ {
+ sal_uInt16 nModelPos = pGrid->GetModelColumnPos(pGrid->GetColumnIdFromViewPos(static_cast<sal_uInt16>(i)));
+ DBG_ASSERT(nModelPos != sal_uInt16(-1), "FmXGridPeer::queryFieldData : invalid model pos !");
+
+ // don't use GetCurrentFieldValue to determine the field content as this isn't affected by the above SeekRow
+ // FS - 30.09.99 - 68644
+ DbGridColumn* pCol = aColumns[ nModelPos ].get();
+ xFieldContent = xPaintRow->HasField( pCol->GetFieldPos() )
+ ? xPaintRow->GetField( pCol->GetFieldPos() ).getColumn()
+ : Reference< XColumn > ();
+
+ if ( !xFieldContent.is() )
+ continue;
+
+ if (bRequestedAsAny)
+ {
+ Reference< XPropertySet > xFieldSet(xFieldContent, UNO_QUERY);
+ pReturnArray[i] = xFieldSet->getPropertyValue(FM_PROP_VALUE);
+ }
+ else
+ {
+ switch (xType.getTypeClass())
+ {
+ // Strings are dealt with directly by the GetFieldText
+ case TypeClass_STRING :
+ {
+ OUString sText = aColumns[ nModelPos ]->GetCellText( xPaintRow.get(), pGrid->getNumberFormatter() );
+ pReturnArray[i] <<= sText;
+ }
+ break;
+ // everything else is requested in the DatabaseVariant
+ case TypeClass_FLOAT : pReturnArray[i] <<= xFieldContent->getFloat(); break;
+ case TypeClass_DOUBLE : pReturnArray[i] <<= xFieldContent->getDouble(); break;
+ case TypeClass_SHORT : pReturnArray[i] <<= xFieldContent->getShort(); break;
+ case TypeClass_LONG : pReturnArray[i] <<= static_cast<sal_Int32>(xFieldContent->getLong()); break;
+ case TypeClass_UNSIGNED_SHORT : pReturnArray[i] <<= static_cast<sal_uInt16>(xFieldContent->getShort()); break;
+ case TypeClass_UNSIGNED_LONG : pReturnArray[i] <<= static_cast<sal_uInt32>(xFieldContent->getLong()); break;
+ case TypeClass_BOOLEAN : pReturnArray[i] <<= xFieldContent->getBoolean(); break;
+ default:
+ {
+ throw IllegalArgumentException();
+ }
+ }
+ }
+ }
+ return aReturnSequence;
+}
+
+
+void FmXGridPeer::CellModified()
+{
+ EventObject aEvt;
+ aEvt.Source = static_cast< ::cppu::OWeakObject* >(this);
+ m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvt );
+}
+
+// XPropertyChangeListener
+
+void FmXGridPeer::propertyChange(const PropertyChangeEvent& evt)
+{
+ SolarMutexGuard aGuard;
+ // want to do a lot of VCL stuff here ...
+ // this should not be (deadlock) critical, as by definition, every component should release
+ // any own mutexes before notifying
+
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (!pGrid)
+ return;
+
+ // Database event
+ if (evt.PropertyName == FM_PROP_VALUE || m_xCursor == evt.Source)
+ pGrid->propertyChange(evt);
+ else if (pGrid && m_xColumns.is() && m_xColumns->hasElements())
+ {
+ // next find which column has changed
+ css::uno::Reference<css::uno::XInterface> xCurrent;
+ sal_Int32 i;
+
+ for ( i = 0; i < m_xColumns->getCount(); i++)
+ {
+ xCurrent.set(m_xColumns->getByIndex(i), css::uno::UNO_QUERY);
+ if (evt.Source == xCurrent)
+ break;
+ }
+
+ if (i >= m_xColumns->getCount())
+ // this is valid because we are listening at the cursor, too (RecordCount, -status, edit mode)
+ return;
+
+ sal_uInt16 nId = pGrid->GetColumnIdFromModelPos(static_cast<sal_uInt16>(i));
+ bool bInvalidateColumn = false;
+
+ if (evt.PropertyName == FM_PROP_LABEL)
+ {
+ OUString aName = ::comphelper::getString(evt.NewValue);
+ if (aName != pGrid->GetColumnTitle(nId))
+ pGrid->SetColumnTitle(nId, aName);
+ }
+ else if (evt.PropertyName == FM_PROP_WIDTH)
+ {
+ sal_Int32 nWidth = 0;
+ if (evt.NewValue.getValueType().getTypeClass() == TypeClass_VOID)
+ nWidth = pGrid->GetDefaultColumnWidth(pGrid->GetColumnTitle(nId));
+ // GetDefaultColumnWidth already considered the zoom factor
+ else
+ {
+ sal_Int32 nTest = 0;
+ if (evt.NewValue >>= nTest)
+ {
+ nWidth = pGrid->LogicToPixel(Point(nTest, 0), MapMode(MapUnit::Map10thMM)).X();
+ // take the zoom factor into account
+ nWidth = pGrid->CalcZoom(nWidth);
+ }
+ }
+ if (nWidth != (sal_Int32(pGrid->GetColumnWidth(nId))))
+ {
+ if (pGrid->IsEditing())
+ {
+ pGrid->DeactivateCell();
+ pGrid->ActivateCell();
+ }
+ pGrid->SetColumnWidth(nId, nWidth);
+ }
+ }
+ else if (evt.PropertyName == FM_PROP_HIDDEN)
+ {
+ DBG_ASSERT(evt.NewValue.getValueType().getTypeClass() == TypeClass_BOOLEAN,
+ "FmXGridPeer::propertyChange : the property 'hidden' should be of type boolean !");
+ if (::comphelper::getBOOL(evt.NewValue))
+ pGrid->HideColumn(nId);
+ else
+ pGrid->ShowColumn(nId);
+ }
+ else if (evt.PropertyName == FM_PROP_ALIGN)
+ {
+ // in design mode it doesn't matter
+ if (!isDesignMode())
+ {
+ DbGridColumn* pCol = pGrid->GetColumns()[i].get();
+
+ pCol->SetAlignmentFromModel(-1);
+ bInvalidateColumn = true;
+ }
+ }
+ else if (evt.PropertyName == FM_PROP_FORMATKEY)
+ {
+ if (!isDesignMode())
+ bInvalidateColumn = true;
+ }
+
+ // need to invalidate the affected column ?
+ if (bInvalidateColumn)
+ {
+ bool bWasEditing = pGrid->IsEditing();
+ if (bWasEditing)
+ pGrid->DeactivateCell();
+
+ ::tools::Rectangle aColRect = pGrid->GetFieldRect(nId);
+ aColRect.SetTop( 0 );
+ aColRect.SetBottom( pGrid->GetSizePixel().Height() );
+ pGrid->Invalidate(aColRect);
+
+ if (bWasEditing)
+ pGrid->ActivateCell();
+ }
+ }
+}
+
+// XBoundComponent
+
+void FmXGridPeer::addUpdateListener(const Reference< XUpdateListener >& l)
+{
+ m_aUpdateListeners.addInterface(l);
+}
+
+
+void FmXGridPeer::removeUpdateListener(const Reference< XUpdateListener >& l)
+{
+ m_aUpdateListeners.removeInterface(l);
+}
+
+
+sal_Bool FmXGridPeer::commit()
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (!m_xCursor.is() || !pGrid)
+ return true;
+
+ EventObject aEvt(static_cast< ::cppu::OWeakObject* >(this));
+ ::comphelper::OInterfaceIteratorHelper3 aIter(m_aUpdateListeners);
+ bool bCancel = false;
+ while (aIter.hasMoreElements() && !bCancel)
+ if ( !aIter.next()->approveUpdate( aEvt ) )
+ bCancel = true;
+
+ if (!bCancel)
+ bCancel = !pGrid->commit();
+
+ if (!bCancel)
+ m_aUpdateListeners.notifyEach( &XUpdateListener::updated, aEvt );
+ return !bCancel;
+}
+
+
+void FmXGridPeer::cursorMoved(const EventObject& _rEvent)
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ // we are not interested in moving to insert row only in the reset event
+ // which is fired after positioning and the insert row
+ if (pGrid && pGrid->IsOpen() && !::comphelper::getBOOL(Reference< XPropertySet > (_rEvent.Source, UNO_QUERY_THROW)->getPropertyValue(FM_PROP_ISNEW)))
+ pGrid->positioned();
+}
+
+
+void FmXGridPeer::rowChanged(const EventObject& /*_rEvent*/)
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (pGrid && pGrid->IsOpen())
+ {
+ if (m_xCursor->rowUpdated() && !pGrid->IsCurrentAppending())
+ pGrid->RowModified(pGrid->GetCurrentPos());
+ else if (m_xCursor->rowInserted())
+ pGrid->inserted();
+ }
+}
+
+
+void FmXGridPeer::rowSetChanged(const EventObject& /*event*/)
+{
+ // not interested in ...
+ // (our parent is a form which means we get a loaded or reloaded after this rowSetChanged)
+}
+
+// XLoadListener
+
+void FmXGridPeer::loaded(const EventObject& /*rEvent*/)
+{
+ updateGrid(m_xCursor);
+}
+
+
+void FmXGridPeer::unloaded(const EventObject& /*rEvent*/)
+{
+ updateGrid( Reference< XRowSet > (nullptr) );
+}
+
+
+void FmXGridPeer::reloading(const EventObject& /*aEvent*/)
+{
+ // empty the grid
+ updateGrid( Reference< XRowSet > (nullptr) );
+}
+
+
+void FmXGridPeer::unloading(const EventObject& /*aEvent*/)
+{
+ // empty the grid
+ updateGrid( Reference< XRowSet > (nullptr) );
+}
+
+
+void FmXGridPeer::reloaded(const EventObject& aEvent)
+{
+ {
+ const sal_Int32 cnt = m_xColumns->getCount();
+ for(sal_Int32 i=0; i<cnt; ++i)
+ {
+ Reference< XLoadListener> xll(m_xColumns->getByIndex(i), UNO_QUERY);
+ if(xll.is())
+ {
+ xll->reloaded(aEvent);
+ }
+ }
+ }
+ updateGrid(m_xCursor);
+}
+
+// XGridPeer
+
+Reference< XIndexContainer > FmXGridPeer::getColumns()
+{
+ return m_xColumns;
+}
+
+
+void FmXGridPeer::addColumnListeners(const Reference< XPropertySet >& xCol)
+{
+ static const rtl::OUStringConstExpr aPropsListenedTo[] =
+ {
+ FM_PROP_LABEL, FM_PROP_WIDTH, FM_PROP_HIDDEN, FM_PROP_ALIGN,
+ FM_PROP_FORMATKEY
+ };
+
+ // as not all properties have to be supported by all columns we have to check this
+ // before adding a listener
+ Reference< XPropertySetInfo > xInfo = xCol->getPropertySetInfo();
+ for (size_t i=0; i<SAL_N_ELEMENTS(aPropsListenedTo); ++i)
+ {
+ if ( xInfo->hasPropertyByName( aPropsListenedTo[i] ) )
+ {
+ Property aPropDesc = xInfo->getPropertyByName( aPropsListenedTo[i] );
+ if ( 0 != ( aPropDesc.Attributes & PropertyAttribute::BOUND ) )
+ xCol->addPropertyChangeListener( aPropsListenedTo[i], this );
+ }
+ }
+}
+
+
+void FmXGridPeer::removeColumnListeners(const Reference< XPropertySet >& xCol)
+{
+ // the same props as in addColumnListeners... linux has problems with global static UStrings, so
+ // we have to do it this way...
+ static const rtl::OUStringConstExpr aPropsListenedTo[] =
+ {
+ FM_PROP_LABEL, FM_PROP_WIDTH, FM_PROP_HIDDEN, FM_PROP_ALIGN,
+ FM_PROP_FORMATKEY
+ };
+
+ Reference< XPropertySetInfo > xInfo = xCol->getPropertySetInfo();
+ for (const auto & i : aPropsListenedTo)
+ if (xInfo->hasPropertyByName(i))
+ xCol->removePropertyChangeListener(i, this);
+}
+
+
+void FmXGridPeer::setColumns(const Reference< XIndexContainer >& Columns)
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+
+ if (m_xColumns.is())
+ {
+ Reference< XPropertySet > xCol;
+ for (sal_Int32 i = 0; i < m_xColumns->getCount(); i++)
+ {
+ xCol.set(m_xColumns->getByIndex(i), css::uno::UNO_QUERY);
+ removeColumnListeners(xCol);
+ }
+ Reference< XContainer > xContainer(m_xColumns, UNO_QUERY);
+ xContainer->removeContainerListener(this);
+
+ Reference< XSelectionSupplier > xSelSupplier(m_xColumns, UNO_QUERY);
+ xSelSupplier->removeSelectionChangeListener(this);
+
+ Reference< XReset > xColumnReset(m_xColumns, UNO_QUERY);
+ if (xColumnReset.is())
+ xColumnReset->removeResetListener(static_cast<XResetListener*>(this));
+ }
+ if (Columns.is())
+ {
+ Reference< XContainer > xContainer(Columns, UNO_QUERY);
+ xContainer->addContainerListener(this);
+
+ Reference< XSelectionSupplier > xSelSupplier(Columns, UNO_QUERY);
+ xSelSupplier->addSelectionChangeListener(this);
+
+ Reference< XPropertySet > xCol;
+ for (sal_Int32 i = 0; i < Columns->getCount(); i++)
+ {
+ xCol.set(Columns->getByIndex(i), css::uno::UNO_QUERY);
+ addColumnListeners(xCol);
+ }
+
+ Reference< XReset > xColumnReset(Columns, UNO_QUERY);
+ if (xColumnReset.is())
+ xColumnReset->addResetListener(static_cast<XResetListener*>(this));
+ }
+ m_xColumns = Columns;
+ if (pGrid)
+ {
+ pGrid->InitColumnsByModels(m_xColumns);
+
+ if (m_xColumns.is())
+ {
+ EventObject aEvt(m_xColumns);
+ selectionChanged(aEvt);
+ }
+ }
+}
+
+
+void FmXGridPeer::setDesignMode(sal_Bool bOn)
+{
+ if (bOn != isDesignMode())
+ {
+ VclPtr<vcl::Window> pWin = GetWindow();
+ if (pWin)
+ static_cast<FmGridControl*>(pWin.get())->SetDesignMode(bOn);
+ }
+
+ if (bOn)
+ DisConnectFromDispatcher();
+ else
+ UpdateDispatches(); // will connect if not already connected and just update else
+}
+
+
+sal_Bool FmXGridPeer::isDesignMode()
+{
+ VclPtr<vcl::Window> pWin = GetWindow();
+ if (pWin)
+ return static_cast<FmGridControl*>(pWin.get())->IsDesignMode();
+ else
+ return false;
+}
+
+
+void FmXGridPeer::elementInserted(const ContainerEvent& evt)
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ // take handle column into account
+ if (!pGrid || !m_xColumns.is() || pGrid->IsInColumnMove() || m_xColumns->getCount() == static_cast<sal_Int32>(pGrid->GetModelColCount()))
+ return;
+
+ Reference< XPropertySet > xNewColumn(evt.Element, css::uno::UNO_QUERY);
+ addColumnListeners(xNewColumn);
+
+ OUString aName = ::comphelper::getString(xNewColumn->getPropertyValue(FM_PROP_LABEL));
+ Any aWidth = xNewColumn->getPropertyValue(FM_PROP_WIDTH);
+ sal_Int32 nWidth = 0;
+ if (aWidth >>= nWidth)
+ nWidth = pGrid->LogicToPixel(Point(nWidth, 0), MapMode(MapUnit::Map10thMM)).X();
+
+ pGrid->AppendColumn(aName, static_cast<sal_uInt16>(nWidth), static_cast<sal_Int16>(::comphelper::getINT32(evt.Accessor)));
+
+ // now set the column
+ DbGridColumn* pCol = pGrid->GetColumns()[ ::comphelper::getINT32(evt.Accessor) ].get();
+ pCol->setModel(xNewColumn);
+
+ Any aHidden = xNewColumn->getPropertyValue(FM_PROP_HIDDEN);
+ if (::comphelper::getBOOL(aHidden))
+ pGrid->HideColumn(pCol->GetId());
+
+ FormControlFactory( m_xContext ).initializeTextFieldLineEnds( xNewColumn );
+}
+
+
+void FmXGridPeer::elementReplaced(const ContainerEvent& evt)
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+
+ // take handle column into account
+ if (!pGrid || !m_xColumns.is() || pGrid->IsInColumnMove())
+ return;
+
+ Reference< XPropertySet > xNewColumn(evt.Element, css::uno::UNO_QUERY);
+ Reference< XPropertySet > xOldColumn(
+ evt.ReplacedElement, css::uno::UNO_QUERY);
+
+ bool bWasEditing = pGrid->IsEditing();
+ if (bWasEditing)
+ pGrid->DeactivateCell();
+
+ pGrid->RemoveColumn(pGrid->GetColumnIdFromModelPos(static_cast<sal_uInt16>(::comphelper::getINT32(evt.Accessor))));
+
+ removeColumnListeners(xOldColumn);
+ addColumnListeners(xNewColumn);
+
+ OUString aName = ::comphelper::getString(xNewColumn->getPropertyValue(FM_PROP_LABEL));
+ Any aWidth = xNewColumn->getPropertyValue(FM_PROP_WIDTH);
+ sal_Int32 nWidth = 0;
+ if (aWidth >>= nWidth)
+ nWidth = pGrid->LogicToPixel(Point(nWidth, 0), MapMode(MapUnit::Map10thMM)).X();
+ sal_uInt16 nNewId = pGrid->AppendColumn(aName, static_cast<sal_uInt16>(nWidth), static_cast<sal_Int16>(::comphelper::getINT32(evt.Accessor)));
+ sal_uInt16 nNewPos = pGrid->GetModelColumnPos(nNewId);
+
+ // set the model of the new column
+ DbGridColumn* pCol = pGrid->GetColumns()[ nNewPos ].get();
+
+ // for initializing this grid column, we need the fields of the grid's data source
+ Reference< XColumnsSupplier > xSuppColumns;
+ CursorWrapper* pGridDataSource = pGrid->getDataSource();
+ if ( pGridDataSource )
+ xSuppColumns.set(Reference< XInterface >( *pGridDataSource ), css::uno::UNO_QUERY);
+ Reference< XNameAccess > xColumnsByName;
+ if ( xSuppColumns.is() )
+ xColumnsByName = xSuppColumns->getColumns();
+ Reference< XIndexAccess > xColumnsByIndex( xColumnsByName, UNO_QUERY );
+
+ if ( xColumnsByIndex.is() )
+ FmGridControl::InitColumnByField( pCol, xNewColumn, xColumnsByName, xColumnsByIndex );
+ else
+ // the simple version, applies when the grid is not yet connected to a data source
+ pCol->setModel(xNewColumn);
+
+ if (bWasEditing)
+ pGrid->ActivateCell();
+}
+
+
+void FmXGridPeer::elementRemoved(const ContainerEvent& evt)
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+
+ // take handle column into account
+ if (!pGrid || !m_xColumns.is() || pGrid->IsInColumnMove() || m_xColumns->getCount() == static_cast<sal_Int32>(pGrid->GetModelColCount()))
+ return;
+
+ pGrid->RemoveColumn(pGrid->GetColumnIdFromModelPos(static_cast<sal_uInt16>(::comphelper::getINT32(evt.Accessor))));
+
+ Reference< XPropertySet > xOldColumn(evt.Element, css::uno::UNO_QUERY);
+ removeColumnListeners(xOldColumn);
+}
+
+
+void FmXGridPeer::setProperty( const OUString& PropertyName, const Any& Value)
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+
+ bool bVoid = !Value.hasValue();
+
+ if ( PropertyName == FM_PROP_TEXTLINECOLOR )
+ {
+ ::Color aTextLineColor( bVoid ? COL_TRANSPARENT : ::Color(ColorTransparency, ::comphelper::getINT32( Value )) );
+ if (bVoid)
+ {
+ pGrid->SetTextLineColor();
+ pGrid->GetDataWindow().SetTextLineColor();
+ }
+ else
+ {
+ pGrid->SetTextLineColor(aTextLineColor);
+ pGrid->GetDataWindow().SetTextLineColor(aTextLineColor);
+ }
+
+ // need to forward this to the columns
+ std::vector< std::unique_ptr<DbGridColumn> > const & rColumns = pGrid->GetColumns();
+ for (auto const & pLoop : rColumns)
+ {
+ FmXGridCell* pXCell = pLoop->GetCell();
+ if (pXCell)
+ {
+ if (bVoid)
+ pXCell->SetTextLineColor();
+ else
+ pXCell->SetTextLineColor(aTextLineColor);
+ }
+ }
+
+ if (isDesignMode())
+ pGrid->Invalidate();
+ }
+ else if ( PropertyName == FM_PROP_FONTEMPHASISMARK )
+ {
+ vcl::Font aGridFont = pGrid->GetControlFont();
+ sal_Int16 nValue = ::comphelper::getINT16(Value);
+ aGridFont.SetEmphasisMark( static_cast<FontEmphasisMark>(nValue) );
+ pGrid->SetControlFont( aGridFont );
+ }
+ else if ( PropertyName == FM_PROP_FONTRELIEF )
+ {
+ vcl::Font aGridFont = pGrid->GetControlFont();
+ sal_Int16 nValue = ::comphelper::getINT16(Value);
+ aGridFont.SetRelief( static_cast<FontRelief>(nValue) );
+ pGrid->SetControlFont( aGridFont );
+ }
+ else if ( PropertyName == FM_PROP_HELPURL )
+ {
+ OUString sHelpURL;
+ OSL_VERIFY( Value >>= sHelpURL );
+ INetURLObject aHID( sHelpURL );
+ if ( aHID.GetProtocol() == INetProtocol::Hid )
+ sHelpURL = aHID.GetURLPath();
+ pGrid->SetHelpId( OUStringToOString( sHelpURL, RTL_TEXTENCODING_UTF8 ) );
+ }
+ else if ( PropertyName == FM_PROP_DISPLAYSYNCHRON )
+ {
+ pGrid->setDisplaySynchron(::comphelper::getBOOL(Value));
+ }
+ else if ( PropertyName == FM_PROP_CURSORCOLOR )
+ {
+ if (bVoid)
+ pGrid->SetCursorColor(COL_TRANSPARENT);
+ else
+ pGrid->SetCursorColor( ::Color(ColorTransparency, ::comphelper::getINT32(Value)));
+ if (isDesignMode())
+ pGrid->Invalidate();
+ }
+ else if ( PropertyName == FM_PROP_ALWAYSSHOWCURSOR )
+ {
+ pGrid->EnablePermanentCursor(::comphelper::getBOOL(Value));
+ if (isDesignMode())
+ pGrid->Invalidate();
+ }
+ else if ( PropertyName == FM_PROP_FONT )
+ {
+ if ( bVoid )
+ pGrid->SetControlFont( vcl::Font() );
+ else
+ {
+ css::awt::FontDescriptor aFont;
+ if (Value >>= aFont)
+ {
+ vcl::Font aNewVclFont;
+ if (aFont != ::comphelper::getDefaultFont()) // is this the default
+ aNewVclFont = ImplCreateFont( aFont );
+
+ // need to add relief and emphasis (they're stored in a VCL-Font, but not in a FontDescriptor
+ vcl::Font aOldVclFont = pGrid->GetControlFont();
+ aNewVclFont.SetRelief( aOldVclFont.GetRelief() );
+ aNewVclFont.SetEmphasisMark( aOldVclFont.GetEmphasisMark() );
+
+ // now set it ...
+ pGrid->SetControlFont( aNewVclFont );
+
+ // if our row-height property is void (which means "calculate it font-dependent") we have
+ // to adjust the control's row height
+ Reference< XPropertySet > xModelSet(getColumns(), UNO_QUERY);
+ if (xModelSet.is() && ::comphelper::hasProperty(FM_PROP_ROWHEIGHT, xModelSet))
+ {
+ Any aHeight = xModelSet->getPropertyValue(FM_PROP_ROWHEIGHT);
+ if (!aHeight.hasValue())
+ pGrid->SetDataRowHeight(0);
+ }
+
+ }
+ }
+ }
+ else if ( PropertyName == FM_PROP_BACKGROUNDCOLOR )
+ {
+ if ( bVoid )
+ {
+ pGrid->SetControlBackground();
+ }
+ else
+ {
+ ::Color aColor( ColorTransparency, ::comphelper::getINT32(Value) );
+ pGrid->SetBackground( aColor );
+ pGrid->SetControlBackground( aColor );
+ }
+ }
+ else if ( PropertyName == FM_PROP_TEXTCOLOR )
+ {
+ if ( bVoid )
+ {
+ pGrid->SetControlForeground();
+ }
+ else
+ {
+ ::Color aColor( ColorTransparency, ::comphelper::getINT32(Value) );
+ pGrid->SetTextColor( aColor );
+ pGrid->SetControlForeground( aColor );
+ }
+ }
+ else if ( PropertyName == FM_PROP_ROWHEIGHT )
+ {
+ sal_Int32 nLogHeight(0);
+ if (Value >>= nLogHeight)
+ {
+ sal_Int32 nHeight = pGrid->LogicToPixel(Point(0, nLogHeight), MapMode(MapUnit::Map10thMM)).Y();
+ // take the zoom factor into account
+ nHeight = pGrid->CalcZoom(nHeight);
+ pGrid->SetDataRowHeight(nHeight);
+ }
+ else if (bVoid)
+ pGrid->SetDataRowHeight(0);
+ }
+ else if ( PropertyName == FM_PROP_HASNAVIGATION )
+ {
+ bool bValue( true );
+ OSL_VERIFY( Value >>= bValue );
+ pGrid->EnableNavigationBar( bValue );
+ }
+ else if ( PropertyName == FM_PROP_RECORDMARKER )
+ {
+ bool bValue( true );
+ OSL_VERIFY( Value >>= bValue );
+ pGrid->EnableHandle( bValue );
+ }
+ else if ( PropertyName == FM_PROP_ENABLED )
+ {
+ bool bValue( true );
+ OSL_VERIFY( Value >>= bValue );
+
+ // In design mode, disable only the data window.
+ // Else the control cannot be configured anymore.
+ if (isDesignMode())
+ pGrid->GetDataWindow().Enable( bValue );
+ else
+ pGrid->Enable( bValue );
+ }
+ else
+ VCLXWindow::setProperty( PropertyName, Value );
+}
+
+
+Reference< XAccessibleContext > FmXGridPeer::CreateAccessibleContext()
+{
+ Reference< XAccessibleContext > xContext;
+
+ // use the AccessibleContext provided by the VCL window
+ VclPtr<vcl::Window> pGrid = GetWindow();
+ if ( pGrid )
+ {
+ Reference< XAccessible > xAcc( pGrid->GetAccessible() );
+ if ( xAcc.is() )
+ xContext = xAcc->getAccessibleContext();
+ // TODO: this has a slight conceptual problem:
+
+ // We know that the XAccessible and XAccessibleContext implementation of the browse
+ // box is the same (the class implements both interfaces), which, speaking strictly,
+ // is bad here (means when a browse box acts as UnoControl): We (the FmXGridPeer) are
+ // the XAccessible here, and the browse box should be able to provide us an XAccessibleContext,
+ // but it should _not_ be the XAccessible itself.
+ // However, as long as no client implementation uses dirty hacks such as querying an
+ // XAccessibleContext for XAccessible, this should not be a problem.
+ }
+
+ if ( !xContext.is() )
+ xContext = VCLXWindow::CreateAccessibleContext( );
+
+ return xContext;
+}
+
+
+Any FmXGridPeer::getProperty( const OUString& _rPropertyName )
+{
+ Any aProp;
+ if (GetWindow())
+ {
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ vcl::Window* pDataWindow = &pGrid->GetDataWindow();
+
+ if ( _rPropertyName == FM_PROP_NAME )
+ {
+ vcl::Font aFont = pDataWindow->GetControlFont();
+ aProp <<= ImplCreateFontDescriptor( aFont );
+ }
+ else if ( _rPropertyName == FM_PROP_TEXTCOLOR )
+ {
+ aProp <<= pDataWindow->GetControlForeground();
+ }
+ else if ( _rPropertyName == FM_PROP_BACKGROUNDCOLOR )
+ {
+ aProp <<= pDataWindow->GetControlBackground();
+ }
+ else if ( _rPropertyName == FM_PROP_ROWHEIGHT )
+ {
+ sal_Int32 nPixelHeight = pGrid->GetDataRowHeight();
+ // take the zoom factor into account
+ nPixelHeight = pGrid->CalcReverseZoom(nPixelHeight);
+ aProp <<= static_cast<sal_Int32>(pGrid->PixelToLogic(Point(0, nPixelHeight), MapMode(MapUnit::Map10thMM)).Y());
+ }
+ else if ( _rPropertyName == FM_PROP_HASNAVIGATION )
+ {
+ bool bHasNavBar = pGrid->HasNavigationBar();
+ aProp <<= bHasNavBar;
+ }
+ else if ( _rPropertyName == FM_PROP_RECORDMARKER )
+ {
+ bool bHasHandle = pGrid->HasHandle();
+ aProp <<= bHasHandle;
+ }
+ else if ( _rPropertyName == FM_PROP_ENABLED )
+ {
+ aProp <<= pDataWindow->IsEnabled();
+ }
+ else
+ aProp = VCLXWindow::getProperty( _rPropertyName );
+ }
+ return aProp;
+}
+
+
+void FmXGridPeer::dispose()
+{
+ EventObject aEvt;
+ aEvt.Source = static_cast< ::cppu::OWeakObject* >(this);
+ m_aModifyListeners.disposeAndClear(aEvt);
+ m_aUpdateListeners.disposeAndClear(aEvt);
+ m_aContainerListeners.disposeAndClear(aEvt);
+
+ // release all interceptors
+ Reference< XDispatchProviderInterceptor > xInterceptor( m_xFirstDispatchInterceptor );
+ m_xFirstDispatchInterceptor.clear();
+ while ( xInterceptor.is() )
+ {
+ // tell the interceptor it has a new (means no) predecessor
+ xInterceptor->setMasterDispatchProvider( nullptr );
+
+ // ask for its successor
+ Reference< XDispatchProvider > xSlave = xInterceptor->getSlaveDispatchProvider();
+ // and give it the new (means no) successoert
+ xInterceptor->setSlaveDispatchProvider( nullptr );
+
+ // start over with the next chain element
+ xInterceptor.set(xSlave, css::uno::UNO_QUERY);
+ }
+
+ DisConnectFromDispatcher();
+
+ // unregister all listeners
+ if (m_xCursor.is())
+ {
+ m_xCursor->removeRowSetListener(this);
+
+ Reference< XReset > xReset(m_xCursor, UNO_QUERY);
+ if (xReset.is())
+ xReset->removeResetListener(this);
+ Reference< XLoadable > xLoadable(m_xCursor, UNO_QUERY);
+ if (xLoadable.is())
+ xLoadable->removeLoadListener(this);
+ Reference< XPropertySet > xSet(m_xCursor, UNO_QUERY);
+ if (xSet.is())
+ {
+ xSet->removePropertyChangeListener(FM_PROP_ISMODIFIED, this);
+ xSet->removePropertyChangeListener(FM_PROP_ROWCOUNT, this);
+ }
+ m_xCursor.clear();
+ }
+
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (pGrid)
+ {
+ pGrid->setDataSource(Reference< XRowSet > ());
+ pGrid->DisposeAccessible();
+ }
+
+ VCLXWindow::dispose();
+}
+
+// XContainer
+
+void FmXGridPeer::addContainerListener(const Reference< XContainerListener >& l)
+{
+ m_aContainerListeners.addInterface( l );
+}
+
+void FmXGridPeer::removeContainerListener(const Reference< XContainerListener >& l)
+{
+ m_aContainerListeners.removeInterface( l );
+}
+
+// css::data::XDatabaseCursorSupplier
+
+void FmXGridPeer::startCursorListening()
+{
+ if (!m_nCursorListening)
+ {
+ if (m_xCursor.is())
+ m_xCursor->addRowSetListener(this);
+
+ Reference< XReset > xReset(m_xCursor, UNO_QUERY);
+ if (xReset.is())
+ xReset->addResetListener(this);
+
+ // register all listeners
+ Reference< XPropertySet > xSet(m_xCursor, UNO_QUERY);
+ if (xSet.is())
+ {
+ xSet->addPropertyChangeListener(FM_PROP_ISMODIFIED, this);
+ xSet->addPropertyChangeListener(FM_PROP_ROWCOUNT, this);
+ }
+ }
+ m_nCursorListening++;
+}
+
+
+void FmXGridPeer::stopCursorListening()
+{
+ if (--m_nCursorListening)
+ return;
+
+ if (m_xCursor.is())
+ m_xCursor->removeRowSetListener(this);
+
+ Reference< XReset > xReset(m_xCursor, UNO_QUERY);
+ if (xReset.is())
+ xReset->removeResetListener(this);
+
+ Reference< XPropertySet > xSet(m_xCursor, UNO_QUERY);
+ if (xSet.is())
+ {
+ xSet->removePropertyChangeListener(FM_PROP_ISMODIFIED, this);
+ xSet->removePropertyChangeListener(FM_PROP_ROWCOUNT, this);
+ }
+}
+
+
+void FmXGridPeer::updateGrid(const Reference< XRowSet >& _rxCursor)
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (pGrid)
+ pGrid->setDataSource(_rxCursor);
+}
+
+
+Reference< XRowSet > FmXGridPeer::getRowSet()
+{
+ return m_xCursor;
+}
+
+
+void FmXGridPeer::setRowSet(const Reference< XRowSet >& _rDatabaseCursor)
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (!pGrid || !m_xColumns.is() || !m_xColumns->getCount())
+ return;
+ // unregister all listeners
+ if (m_xCursor.is())
+ {
+ Reference< XLoadable > xLoadable(m_xCursor, UNO_QUERY);
+ // only if the form is loaded we set the rowset
+ if (xLoadable.is())
+ {
+ stopCursorListening();
+ xLoadable->removeLoadListener(this);
+ }
+ }
+
+ m_xCursor = _rDatabaseCursor;
+
+ if (!pGrid)
+ return;
+
+ Reference< XLoadable > xLoadable(m_xCursor, UNO_QUERY);
+ // only if the form is loaded we set the rowset
+ if (xLoadable.is() && xLoadable->isLoaded())
+ pGrid->setDataSource(m_xCursor);
+ else
+ pGrid->setDataSource(Reference< XRowSet > ());
+
+ if (xLoadable.is())
+ {
+ startCursorListening();
+ xLoadable->addLoadListener(this);
+ }
+}
+
+
+void SAL_CALL FmXGridPeer::addGridControlListener( const Reference< XGridControlListener >& _listener )
+{
+ m_aGridControlListeners.addInterface( _listener );
+}
+
+
+void SAL_CALL FmXGridPeer::removeGridControlListener( const Reference< XGridControlListener >& _listener )
+{
+ m_aGridControlListeners.removeInterface( _listener );
+}
+
+
+sal_Int16 FmXGridPeer::getCurrentColumnPosition()
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ return pGrid ? pGrid->GetViewColumnPos(pGrid->GetCurColumnId()) : -1;
+}
+
+
+void FmXGridPeer::setCurrentColumnPosition(sal_Int16 nPos)
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (pGrid)
+ pGrid->GoToColumnId(pGrid->GetColumnIdFromViewPos(nPos));
+}
+
+
+void FmXGridPeer::selectionChanged(const EventObject& evt)
+{
+ SolarMutexGuard aGuard;
+
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (!pGrid)
+ return;
+
+ Reference< css::view::XSelectionSupplier > xSelSupplier(evt.Source, UNO_QUERY);
+ Any aSelection = xSelSupplier->getSelection();
+ DBG_ASSERT(aSelection.getValueType().getTypeClass() == TypeClass_INTERFACE, "FmXGridPeer::selectionChanged : invalid selection !");
+ Reference< XPropertySet > xSelection;
+ aSelection >>= xSelection;
+ if (xSelection.is())
+ {
+ Reference< XPropertySet > xCol;
+ sal_Int32 i = 0;
+ sal_Int32 nColCount = m_xColumns->getCount();
+
+ for (; i < nColCount; ++i)
+ {
+ m_xColumns->getByIndex(i) >>= xCol;
+ if ( xCol == xSelection )
+ {
+ pGrid->markColumn(pGrid->GetColumnIdFromModelPos(static_cast<sal_uInt16>(i)));
+ break;
+ }
+ }
+ // The columns have to be 1-based for the VCL control.
+ // If necessary, pass on the selection to the VCL control
+ if ( i != pGrid->GetSelectedColumn() )
+ { // (if this does not take effect, the selectionChanged was implicitly triggered by the control itself)
+ if ( i < nColCount )
+ {
+ pGrid->SelectColumnPos(pGrid->GetViewColumnPos(pGrid->GetColumnIdFromModelPos( static_cast<sal_uInt16>(i) )) + 1);
+ // SelectColumnPos has led to an implicit ActivateCell again
+ if (pGrid->IsEditing())
+ pGrid->DeactivateCell();
+ }
+ else
+ pGrid->SetNoSelection();
+ }
+ }
+ else
+ pGrid->markColumn(USHRT_MAX);
+}
+
+// XElementAccess
+
+sal_Bool FmXGridPeer::hasElements()
+{
+ return getCount() != 0;
+}
+
+
+Type SAL_CALL FmXGridPeer::getElementType( )
+{
+ return cppu::UnoType<css::awt::XControl>::get();
+}
+
+// XEnumerationAccess
+
+Reference< XEnumeration > FmXGridPeer::createEnumeration()
+{
+ return new ::comphelper::OEnumerationByIndex(this);
+}
+
+// XIndexAccess
+
+sal_Int32 FmXGridPeer::getCount()
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (pGrid)
+ return pGrid->GetViewColCount();
+ else
+ return 0;
+}
+
+
+Any FmXGridPeer::getByIndex(sal_Int32 _nIndex)
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (_nIndex < 0 ||
+ _nIndex >= getCount() || !pGrid)
+ throw IndexOutOfBoundsException();
+
+ Any aElement;
+ // get the columnid
+ sal_uInt16 nId = pGrid->GetColumnIdFromViewPos(static_cast<sal_uInt16>(_nIndex));
+ // get the list position
+ sal_uInt16 nPos = pGrid->GetModelColumnPos(nId);
+
+ if ( nPos == GRID_COLUMN_NOT_FOUND )
+ return aElement;
+
+ DbGridColumn* pCol = pGrid->GetColumns()[ nPos ].get();
+ Reference< css::awt::XControl > xControl(pCol->GetCell());
+ aElement <<= xControl;
+
+ return aElement;
+}
+
+// css::util::XModeSelector
+
+void FmXGridPeer::setMode(const OUString& Mode)
+{
+ if (!supportsMode(Mode))
+ throw NoSupportException();
+
+ if (Mode == m_aMode)
+ return;
+
+ m_aMode = Mode;
+
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if ( Mode == "FilterMode" )
+ pGrid->SetFilterMode(true);
+ else
+ {
+ pGrid->SetFilterMode(false);
+ pGrid->setDataSource(m_xCursor);
+ }
+}
+
+
+OUString FmXGridPeer::getMode()
+{
+ return m_aMode;
+}
+
+
+css::uno::Sequence<OUString> FmXGridPeer::getSupportedModes()
+{
+ static css::uno::Sequence<OUString> const aModes
+ {
+ "DataMode",
+ "FilterMode"
+ };
+ return aModes;
+}
+
+
+sal_Bool FmXGridPeer::supportsMode(const OUString& Mode)
+{
+ css::uno::Sequence<OUString> aModes(getSupportedModes());
+ return comphelper::findValue(aModes, Mode) != -1;
+}
+
+
+void FmXGridPeer::columnVisible(DbGridColumn const * pColumn)
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+
+ sal_Int32 _nIndex = pGrid->GetModelColumnPos(pColumn->GetId());
+ Reference< css::awt::XControl > xControl(pColumn->GetCell());
+ ContainerEvent aEvt;
+ aEvt.Source = static_cast<XContainer*>(this);
+ aEvt.Accessor <<= _nIndex;
+ aEvt.Element <<= xControl;
+
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvt );
+}
+
+
+void FmXGridPeer::columnHidden(DbGridColumn const * pColumn)
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+
+ sal_Int32 _nIndex = pGrid->GetModelColumnPos(pColumn->GetId());
+ Reference< css::awt::XControl > xControl(pColumn->GetCell());
+ ContainerEvent aEvt;
+ aEvt.Source = static_cast<XContainer*>(this);
+ aEvt.Accessor <<= _nIndex;
+ aEvt.Element <<= xControl;
+
+ m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvt );
+}
+
+
+void FmXGridPeer::draw( sal_Int32 x, sal_Int32 y )
+{
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ EditBrowseBoxFlags nOldFlags = pGrid->GetBrowserFlags();
+ pGrid->SetBrowserFlags(nOldFlags | EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT);
+
+ VCLXWindow::draw(x, y);
+
+ pGrid->SetBrowserFlags(nOldFlags);
+}
+
+
+Reference< css::frame::XDispatch > FmXGridPeer::queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags)
+{
+ Reference< css::frame::XDispatch > xResult;
+
+ // first ask our interceptor chain
+ if (m_xFirstDispatchInterceptor.is() && !m_bInterceptingDispatch)
+ {
+ m_bInterceptingDispatch = true;
+ // safety against recursion : as we are master of the first chain element and slave of the last one we would
+ // have an infinite loop without this if no dispatcher can fulfill the request
+ xResult = m_xFirstDispatchInterceptor->queryDispatch(aURL, aTargetFrameName, nSearchFlags);
+ m_bInterceptingDispatch = false;
+ }
+
+ // then ask ourself : we don't have any dispatches
+ return xResult;
+}
+
+
+Sequence< Reference< css::frame::XDispatch > > FmXGridPeer::queryDispatches(const Sequence< css::frame::DispatchDescriptor>& aDescripts)
+{
+ if (m_xFirstDispatchInterceptor.is())
+ return m_xFirstDispatchInterceptor->queryDispatches(aDescripts);
+
+ // then ask ourself : we don't have any dispatches
+ return Sequence< Reference< css::frame::XDispatch > >();
+}
+
+
+void FmXGridPeer::registerDispatchProviderInterceptor(const Reference< css::frame::XDispatchProviderInterceptor >& _xInterceptor)
+{
+ if (!_xInterceptor.is())
+ return;
+
+ if (m_xFirstDispatchInterceptor.is())
+ {
+ // there is already an interceptor; the new one will become its master
+ _xInterceptor->setSlaveDispatchProvider(m_xFirstDispatchInterceptor);
+ m_xFirstDispatchInterceptor->setMasterDispatchProvider(m_xFirstDispatchInterceptor);
+ }
+ else
+ {
+ // it is the first interceptor; set ourself as slave
+ _xInterceptor->setSlaveDispatchProvider(static_cast<css::frame::XDispatchProvider*>(this));
+ }
+
+ // we are the master of the chain's first interceptor
+ m_xFirstDispatchInterceptor = _xInterceptor;
+ m_xFirstDispatchInterceptor->setMasterDispatchProvider(static_cast<css::frame::XDispatchProvider*>(this));
+
+ // we have a new interceptor and we're alive ?
+ if (!isDesignMode())
+ // -> check for new dispatchers
+ UpdateDispatches();
+}
+
+
+void FmXGridPeer::releaseDispatchProviderInterceptor(const Reference< css::frame::XDispatchProviderInterceptor >& _xInterceptor)
+{
+ if (!_xInterceptor.is())
+ return;
+
+ Reference< css::frame::XDispatchProviderInterceptor > xChainWalk(m_xFirstDispatchInterceptor);
+
+ if (m_xFirstDispatchInterceptor == _xInterceptor)
+ { // our chain will have a new first element
+ Reference< css::frame::XDispatchProviderInterceptor > xSlave(m_xFirstDispatchInterceptor->getSlaveDispatchProvider(), UNO_QUERY);
+ m_xFirstDispatchInterceptor = xSlave;
+ }
+ // do this before removing the interceptor from the chain as we won't know it's slave afterwards)
+
+ while (xChainWalk.is())
+ {
+ // walk along the chain of interceptors and look for the interceptor that has to be removed
+ Reference< css::frame::XDispatchProviderInterceptor > xSlave(xChainWalk->getSlaveDispatchProvider(), UNO_QUERY);
+
+ if (xChainWalk == _xInterceptor)
+ {
+ // old master may be an interceptor too
+ Reference< css::frame::XDispatchProviderInterceptor > xMaster(xChainWalk->getMasterDispatchProvider(), UNO_QUERY);
+
+ // unchain the interceptor that has to be removed
+ xChainWalk->setSlaveDispatchProvider(Reference< css::frame::XDispatchProvider > ());
+ xChainWalk->setMasterDispatchProvider(Reference< css::frame::XDispatchProvider > ());
+
+ // reconnect the chain
+ if (xMaster.is())
+ {
+ if (xSlave.is())
+ xMaster->setSlaveDispatchProvider(xSlave);
+ else
+ // it's the first interceptor of the chain, set ourself as slave
+ xMaster->setSlaveDispatchProvider(static_cast<css::frame::XDispatchProvider*>(this));
+ }
+ else
+ {
+ // the chain's first element was removed, set ourself as new master of the second one
+ if (xSlave.is())
+ xSlave->setMasterDispatchProvider(static_cast<css::frame::XDispatchProvider*>(this));
+ }
+ }
+
+ xChainWalk = xSlave;
+ }
+ // our interceptor chain has changed and we're alive ?
+ if (!isDesignMode())
+ // -> check the dispatchers
+ UpdateDispatches();
+}
+
+
+void FmXGridPeer::statusChanged(const css::frame::FeatureStateEvent& Event)
+{
+ DBG_ASSERT(m_pStateCache, "FmXGridPeer::statusChanged : invalid call !");
+ DBG_ASSERT(m_pDispatchers, "FmXGridPeer::statusChanged : invalid call !");
+
+ const Sequence< css::util::URL>& aUrls = getSupportedURLs();
+
+ const std::vector<DbGridControlNavigationBarState>& aSlots = getSupportedGridSlots();
+
+ auto pUrl = std::find_if(aUrls.begin(), aUrls.end(),
+ [&Event](const css::util::URL& rUrl) { return rUrl.Main == Event.FeatureURL.Main; });
+ if (pUrl != aUrls.end())
+ {
+ auto i = static_cast<sal_uInt32>(std::distance(aUrls.begin(), pUrl));
+ DBG_ASSERT(m_pDispatchers[i] == Event.Source, "FmXGridPeer::statusChanged : the event source is a little bit suspect !");
+ m_pStateCache[i] = Event.IsEnabled;
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (aSlots[i] != DbGridControlNavigationBarState::Undo)
+ pGrid->GetNavigationBar().InvalidateState(aSlots[i]);
+ }
+ DBG_ASSERT(pUrl != aUrls.end(), "FmXGridPeer::statusChanged : got a call for an unknown url !");
+}
+
+
+sal_Bool FmXGridPeer::approveReset(const EventObject& /*rEvent*/)
+{
+ return true;
+}
+
+
+sal_Bool SAL_CALL FmXGridPeer::select( const Any& _rSelection )
+{
+ Sequence< Any > aBookmarks;
+ if ( !( _rSelection >>= aBookmarks ) )
+ throw IllegalArgumentException();
+
+ return GetAs< FmGridControl >()->selectBookmarks(aBookmarks);
+
+ // TODO:
+ // speaking strictly, we would have to adjust our model, as our ColumnSelection may have changed.
+ // Our model is a XSelectionSupplier, too, it handles the selection of single columns.
+ // This is somewhat strange, as selection should be a view (not a model) aspect.
+ // So for a clean solution, we should handle column selection ourself, and the model shouldn't
+ // deal with selection at all.
+}
+
+
+Any SAL_CALL FmXGridPeer::getSelection( )
+{
+ VclPtr< FmGridControl > pVclControl = GetAs< FmGridControl >();
+ Sequence< Any > aSelectionBookmarks = pVclControl->getSelectionBookmarks();
+ return Any(aSelectionBookmarks);
+}
+
+
+void SAL_CALL FmXGridPeer::addSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
+{
+ m_aSelectionListeners.addInterface( _rxListener );
+}
+
+
+void SAL_CALL FmXGridPeer::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener )
+{
+ m_aSelectionListeners.removeInterface( _rxListener );
+}
+
+
+void FmXGridPeer::resetted(const EventObject& rEvent)
+{
+ if (m_xColumns == rEvent.Source)
+ { // my model was reset -> refresh the grid content
+ SolarMutexGuard aGuard;
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (!pGrid)
+ return;
+ pGrid->resetCurrentRow();
+ }
+ // if the cursor fired a reset event we seem to be on the insert row
+ else if (m_xCursor == rEvent.Source)
+ {
+ SolarMutexGuard aGuard;
+ VclPtr< FmGridControl > pGrid = GetAs< FmGridControl >();
+ if (pGrid && pGrid->IsOpen())
+ pGrid->positioned();
+ }
+}
+
+
+const std::vector<DbGridControlNavigationBarState>& FmXGridPeer::getSupportedGridSlots()
+{
+ static const std::vector<DbGridControlNavigationBarState> aSupported {
+ DbGridControlNavigationBarState::First,
+ DbGridControlNavigationBarState::Prev,
+ DbGridControlNavigationBarState::Next,
+ DbGridControlNavigationBarState::Last,
+ DbGridControlNavigationBarState::New,
+ DbGridControlNavigationBarState::Undo
+ };
+ return aSupported;
+}
+
+
+Sequence< css::util::URL>& FmXGridPeer::getSupportedURLs()
+{
+ static Sequence< css::util::URL> aSupported = []()
+ {
+ static const rtl::OUStringConstExpr sSupported[] = {
+ FMURL_RECORD_MOVEFIRST,
+ FMURL_RECORD_MOVEPREV,
+ FMURL_RECORD_MOVENEXT,
+ FMURL_RECORD_MOVELAST,
+ FMURL_RECORD_MOVETONEW,
+ FMURL_RECORD_UNDO
+ };
+ Sequence< css::util::URL> tmp(SAL_N_ELEMENTS(sSupported));
+ css::util::URL* pSupported = tmp.getArray();
+
+ for ( sal_Int32 i = 0; i < tmp.getLength(); ++i, ++pSupported)
+ pSupported->Complete = sSupported[i];
+
+ // let a css::util::URL-transformer normalize the URLs
+ Reference< css::util::XURLTransformer > xTransformer(
+ util::URLTransformer::create(::comphelper::getProcessComponentContext()) );
+ for (css::util::URL & rURL : asNonConstRange(tmp))
+ xTransformer->parseStrict(rURL);
+ return tmp;
+ }();
+
+ return aSupported;
+}
+
+
+void FmXGridPeer::UpdateDispatches()
+{
+ if (!m_pStateCache)
+ { // we don't have any dispatchers yet -> do the initial connect
+ ConnectToDispatcher();
+ return;
+ }
+
+ sal_uInt16 nDispatchersGot = 0;
+ const Sequence< css::util::URL>& aSupportedURLs = getSupportedURLs();
+ const css::util::URL* pSupportedURLs = aSupportedURLs.getConstArray();
+ Reference< css::frame::XDispatch > xNewDispatch;
+ for (sal_Int32 i=0; i<aSupportedURLs.getLength(); ++i, ++pSupportedURLs)
+ {
+ xNewDispatch = queryDispatch(*pSupportedURLs, OUString(), 0);
+ if (xNewDispatch != m_pDispatchers[i])
+ {
+ if (m_pDispatchers[i].is())
+ m_pDispatchers[i]->removeStatusListener(static_cast<css::frame::XStatusListener*>(this), *pSupportedURLs);
+ m_pDispatchers[i] = xNewDispatch;
+ if (m_pDispatchers[i].is())
+ m_pDispatchers[i]->addStatusListener(static_cast<css::frame::XStatusListener*>(this), *pSupportedURLs);
+ }
+ if (m_pDispatchers[i].is())
+ ++nDispatchersGot;
+ }
+
+ if (!nDispatchersGot)
+ {
+ m_pStateCache.reset();
+ m_pDispatchers.reset();
+ }
+}
+
+
+void FmXGridPeer::ConnectToDispatcher()
+{
+ DBG_ASSERT((m_pStateCache != nullptr) == (m_pDispatchers != nullptr), "FmXGridPeer::ConnectToDispatcher : inconsistent !");
+ if (m_pStateCache)
+ { // already connected -> just do an update
+ UpdateDispatches();
+ return;
+ }
+
+ const Sequence< css::util::URL>& aSupportedURLs = getSupportedURLs();
+
+ // _before_ adding the status listeners (as the add should result in a statusChanged-call) !
+ m_pStateCache.reset(new bool[aSupportedURLs.getLength()]);
+ m_pDispatchers.reset(new Reference< css::frame::XDispatch > [aSupportedURLs.getLength()]);
+
+ sal_uInt16 nDispatchersGot = 0;
+ const css::util::URL* pSupportedURLs = aSupportedURLs.getConstArray();
+ for (sal_Int32 i=0; i<aSupportedURLs.getLength(); ++i, ++pSupportedURLs)
+ {
+ m_pStateCache[i] = false;
+ m_pDispatchers[i] = queryDispatch(*pSupportedURLs, OUString(), 0);
+ if (m_pDispatchers[i].is())
+ {
+ m_pDispatchers[i]->addStatusListener(static_cast<css::frame::XStatusListener*>(this), *pSupportedURLs);
+ ++nDispatchersGot;
+ }
+ }
+
+ if (!nDispatchersGot)
+ {
+ m_pStateCache.reset();
+ m_pDispatchers.reset();
+ }
+}
+
+
+void FmXGridPeer::DisConnectFromDispatcher()
+{
+ if (!m_pStateCache || !m_pDispatchers)
+ return;
+ // we're not connected
+
+ const Sequence< css::util::URL>& aSupportedURLs = getSupportedURLs();
+ const css::util::URL* pSupportedURLs = aSupportedURLs.getConstArray();
+ for (sal_Int32 i=0; i<aSupportedURLs.getLength(); ++i, ++pSupportedURLs)
+ {
+ if (m_pDispatchers[i].is())
+ m_pDispatchers[i]->removeStatusListener(static_cast<css::frame::XStatusListener*>(this), *pSupportedURLs);
+ }
+
+ m_pStateCache.reset();
+ m_pDispatchers.reset();
+}
+
+
+IMPL_LINK(FmXGridPeer, OnQueryGridSlotState, DbGridControlNavigationBarState, nSlot, int)
+{
+ if (!m_pStateCache)
+ return -1; // unspecified
+
+ // search the given slot with our supported sequence
+ const std::vector<DbGridControlNavigationBarState>& aSupported = getSupportedGridSlots();
+ for (size_t i=0; i<aSupported.size(); ++i)
+ {
+ if (aSupported[i] == nSlot)
+ {
+ if (!m_pDispatchers[i].is())
+ return -1; // nothing known about this slot
+ else
+ return m_pStateCache[i] ? 1 : 0;
+ }
+ }
+
+ return -1;
+}
+
+
+IMPL_LINK(FmXGridPeer, OnExecuteGridSlot, DbGridControlNavigationBarState, nSlot, bool)
+{
+ if (!m_pDispatchers)
+ return false; // not handled
+
+ Sequence< css::util::URL>& aUrls = getSupportedURLs();
+ const css::util::URL* pUrls = aUrls.getConstArray();
+
+ const std::vector<DbGridControlNavigationBarState>& aSlots = getSupportedGridSlots();
+
+ DBG_ASSERT(aSlots.size() == o3tl::make_unsigned(aUrls.getLength()), "FmXGridPeer::OnExecuteGridSlot : inconsistent data returned by getSupportedURLs/getSupportedGridSlots!");
+
+ for (size_t i=0; i<aSlots.size(); ++i, ++pUrls)
+ {
+ if (aSlots[i] == nSlot)
+ {
+ if (m_pDispatchers[i].is())
+ {
+ // commit any changes done so far, if it's not the undoRecord URL
+ if ( pUrls->Complete == FMURL_RECORD_UNDO || commit() )
+ m_pDispatchers[i]->dispatch(*pUrls, Sequence< PropertyValue>());
+
+ return true; // handled
+ }
+ }
+ }
+
+ return false; // not handled
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/fmcomp/gridcell.cxx b/svx/source/fmcomp/gridcell.cxx
new file mode 100644
index 000000000..67e5d0040
--- /dev/null
+++ b/svx/source/fmcomp/gridcell.cxx
@@ -0,0 +1,4615 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <memory>
+#include <sal/log.hxx>
+#include <fmprop.hxx>
+#include <svx/strings.hrc>
+#include <svx/fmtools.hxx>
+#include <gridcell.hxx>
+#include <gridcols.hxx>
+#include <sdbdatacolumn.hxx>
+
+#include <com/sun/star/awt/LineEndFormat.hpp>
+#include <com/sun/star/awt/MouseWheelBehavior.hpp>
+#include <com/sun/star/awt/VisualEffect.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/form/XBoundComponent.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/Date.hpp>
+
+#include <comphelper/numbers.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/formattedcolumnvalue.hxx>
+#include <i18nlangtag/lang.h>
+#include <o3tl/safeint.hxx>
+#include <svl/numformat.hxx>
+#include <svl/numuno.hxx>
+#include <svx/dialmgr.hxx>
+#include <toolkit/helper/listenermultiplexer.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/debug.hxx>
+#include <tools/fract.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/sqlnode.hxx>
+
+using namespace ::connectivity;
+using namespace ::svxform;
+using namespace ::comphelper;
+using namespace ::svt;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::form;
+using namespace ::dbtools::DBTypeConversion;
+using namespace ::dbtools;
+
+using ::com::sun::star::util::XNumberFormatter;
+
+constexpr OUStringLiteral INVALIDTEXT = u"###";
+constexpr OUStringLiteral OBJECTTEXT = u"<OBJECT>";
+
+
+//= helper
+
+namespace
+{
+ LineEnd getModelLineEndSetting( const Reference< XPropertySet >& _rxModel )
+ {
+ LineEnd eFormat = LINEEND_LF;
+
+ try
+ {
+ sal_Int16 nLineEndFormat = awt::LineEndFormat::LINE_FEED;
+
+ Reference< XPropertySetInfo > xPSI;
+ if ( _rxModel.is() )
+ xPSI = _rxModel->getPropertySetInfo();
+
+ OSL_ENSURE( xPSI.is(), "getModelLineEndSetting: invalid column model!" );
+ if ( xPSI.is() && xPSI->hasPropertyByName( FM_PROP_LINEENDFORMAT ) )
+ {
+ OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_LINEENDFORMAT ) >>= nLineEndFormat );
+
+ switch ( nLineEndFormat )
+ {
+ case awt::LineEndFormat::CARRIAGE_RETURN: eFormat = LINEEND_CR; break;
+ case awt::LineEndFormat::LINE_FEED: eFormat = LINEEND_LF; break;
+ case awt::LineEndFormat::CARRIAGE_RETURN_LINE_FEED: eFormat = LINEEND_CRLF; break;
+ default:
+ OSL_FAIL( "getModelLineEndSetting: what's this?" );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "getModelLineEndSetting" );
+ }
+ return eFormat;
+ }
+}
+
+
+//= DbGridColumn
+
+
+CellControllerRef DbGridColumn::s_xEmptyController;
+
+
+void DbGridColumn::CreateControl(sal_Int32 _nFieldPos, const Reference< css::beans::XPropertySet >& xField, sal_Int32 nTypeId)
+{
+ Clear();
+
+ m_nTypeId = static_cast<sal_Int16>(nTypeId);
+ if (xField != m_xField)
+ {
+ // initial setting
+ m_xField = xField;
+ xField->getPropertyValue(FM_PROP_FORMATKEY) >>= m_nFormatKey;
+ m_nFieldPos = static_cast<sal_Int16>(_nFieldPos);
+ m_bReadOnly = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISREADONLY));
+ m_bAutoValue = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_AUTOINCREMENT));
+ m_nFieldType = static_cast<sal_Int16>(::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE)));
+
+ switch (m_nFieldType)
+ {
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ case DataType::FLOAT:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ m_nAlign = css::awt::TextAlign::RIGHT;
+ m_bNumeric = true;
+ break;
+ default:
+ m_nAlign = css::awt::TextAlign::LEFT;
+ break;
+ }
+ }
+
+ std::unique_ptr<DbCellControl> pCellControl;
+ if (m_rParent.IsFilterMode())
+ {
+ pCellControl.reset(new DbFilterField(m_rParent.getContext(),*this));
+ }
+ else
+ {
+
+ switch (nTypeId)
+ {
+ case TYPE_CHECKBOX: pCellControl.reset(new DbCheckBox(*this)); break;
+ case TYPE_COMBOBOX: pCellControl.reset(new DbComboBox(*this)); break;
+ case TYPE_CURRENCYFIELD: pCellControl.reset(new DbCurrencyField(*this)); break;
+ case TYPE_DATEFIELD: pCellControl.reset(new DbDateField(*this)); break;
+ case TYPE_LISTBOX: pCellControl.reset(new DbListBox(*this)); break;
+ case TYPE_NUMERICFIELD: pCellControl.reset(new DbNumericField(*this)); break;
+ case TYPE_PATTERNFIELD: pCellControl.reset(new DbPatternField( *this, m_rParent.getContext() )); break;
+ case TYPE_TEXTFIELD: pCellControl.reset(new DbTextField(*this)); break;
+ case TYPE_TIMEFIELD: pCellControl.reset(new DbTimeField(*this)); break;
+ case TYPE_FORMATTEDFIELD: pCellControl.reset(new DbFormattedField(*this)); break;
+ default:
+ OSL_FAIL("DbGridColumn::CreateControl: Unknown Column");
+ return;
+ }
+
+ }
+ Reference< XRowSet > xCur;
+ if (m_rParent.getDataSource())
+ xCur.set(Reference< XInterface >(*m_rParent.getDataSource()), UNO_QUERY);
+ // TODO : the cursor wrapper should use an XRowSet interface, too
+
+ pCellControl->Init( m_rParent.GetDataWindow(), xCur );
+
+ // now create the control wrapper
+ auto pTempCellControl = pCellControl.get();
+ if (m_rParent.IsFilterMode())
+ m_pCell = new FmXFilterCell(this, std::unique_ptr<DbFilterField>(static_cast<DbFilterField*>(pCellControl.release())));
+ else
+ {
+ switch (nTypeId)
+ {
+ case TYPE_CHECKBOX: m_pCell = new FmXCheckBoxCell( this, std::move(pCellControl) ); break;
+ case TYPE_LISTBOX: m_pCell = new FmXListBoxCell( this, std::move(pCellControl) ); break;
+ case TYPE_COMBOBOX: m_pCell = new FmXComboBoxCell( this, std::move(pCellControl) ); break;
+ default:
+ m_pCell = new FmXEditCell( this, std::move(pCellControl) );
+ }
+ }
+ m_pCell->init();
+
+ impl_toggleScriptManager_nothrow( true );
+
+ // only if we use have a bound field, we use a controller for displaying the
+ // window in the grid
+ if (m_xField.is())
+ m_xController = pTempCellControl->CreateController();
+}
+
+
+void DbGridColumn::impl_toggleScriptManager_nothrow( bool _bAttach )
+{
+ try
+ {
+ Reference< container::XChild > xChild( m_xModel, UNO_QUERY_THROW );
+ Reference< script::XEventAttacherManager > xManager( xChild->getParent(), UNO_QUERY_THROW );
+ Reference< container::XIndexAccess > xContainer( xChild->getParent(), UNO_QUERY_THROW );
+
+ sal_Int32 nIndexInParent( getElementPos( xContainer, m_xModel ) );
+
+ Reference< XInterface > xCellInterface( *m_pCell, UNO_QUERY );
+ if ( _bAttach )
+ xManager->attach( nIndexInParent, xCellInterface, Any( xCellInterface ) );
+ else
+ xManager->detach( nIndexInParent, xCellInterface );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+void DbGridColumn::UpdateFromField(const DbGridRow* pRow, const Reference< XNumberFormatter >& xFormatter)
+{
+ if (FmXFilterCell* pCell = dynamic_cast<FmXFilterCell*>(m_pCell.get()))
+ pCell->Update();
+ else if (pRow && pRow->IsValid() && m_nFieldPos >= 0 && m_pCell.is() && pRow->HasField(m_nFieldPos))
+ {
+ dynamic_cast<FmXDataCell&>(*m_pCell).UpdateFromField( pRow->GetField( m_nFieldPos ).getColumn(), xFormatter );
+ }
+}
+
+bool DbGridColumn::Commit()
+{
+ bool bResult = true;
+ if (!m_bInSave && m_pCell.is())
+ {
+ m_bInSave = true;
+ bResult = m_pCell->Commit();
+
+ // store the data into the model
+ FmXDataCell* pDataCell = dynamic_cast<FmXDataCell*>( m_pCell.get() );
+ if (bResult && pDataCell)
+ {
+ Reference< css::form::XBoundComponent > xComp(m_xModel, UNO_QUERY);
+ if (xComp.is())
+ bResult = xComp->commit();
+ }
+ m_bInSave = false;
+ }
+ return bResult;
+}
+
+DbGridColumn::~DbGridColumn()
+{
+ Clear();
+}
+
+void DbGridColumn::setModel(const css::uno::Reference< css::beans::XPropertySet >& _xModel)
+{
+ if ( m_pCell.is() )
+ impl_toggleScriptManager_nothrow( false );
+
+ m_xModel = _xModel;
+
+ if ( m_pCell.is() )
+ impl_toggleScriptManager_nothrow( true );
+}
+
+
+void DbGridColumn::Clear()
+{
+ if ( m_pCell.is() )
+ {
+ impl_toggleScriptManager_nothrow( false );
+
+ m_pCell->dispose();
+ m_pCell.clear();
+ }
+
+ m_xController = nullptr;
+ m_xField = nullptr;
+
+ m_nFormatKey = 0;
+ m_nFieldPos = -1;
+ m_bReadOnly = true;
+ m_bAutoValue = false;
+ m_nFieldType = DataType::OTHER;
+}
+
+
+sal_Int16 DbGridColumn::SetAlignment(sal_Int16 _nAlign)
+{
+ if (_nAlign == -1)
+ { // 'Standard'
+ if (m_xField.is())
+ {
+ sal_Int32 nType = 0;
+ m_xField->getPropertyValue(FM_PROP_FIELDTYPE) >>= nType;
+
+ switch (nType)
+ {
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ case DataType::BIGINT:
+ case DataType::INTEGER:
+ case DataType::SMALLINT:
+ case DataType::TINYINT:
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ _nAlign = css::awt::TextAlign::RIGHT;
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ _nAlign = css::awt::TextAlign::CENTER;
+ break;
+ default:
+ _nAlign = css::awt::TextAlign::LEFT;
+ break;
+ }
+ }
+ else
+ _nAlign = css::awt::TextAlign::LEFT;
+ }
+
+ m_nAlign = _nAlign;
+ if (m_pCell.is() && m_pCell->isAlignedController())
+ m_pCell->AlignControl(m_nAlign);
+
+ return m_nAlign;
+}
+
+
+sal_Int16 DbGridColumn::SetAlignmentFromModel(sal_Int16 nStandardAlign)
+{
+ Any aAlign( m_xModel->getPropertyValue(FM_PROP_ALIGN));
+ if (aAlign.hasValue())
+ {
+ sal_Int16 nTest = sal_Int16();
+ if (aAlign >>= nTest)
+ nStandardAlign = nTest;
+ }
+ return SetAlignment(nStandardAlign);
+}
+
+
+void DbGridColumn::setLock(bool _bLock)
+{
+ if (m_bLocked == _bLock)
+ return;
+ m_bLocked = _bLock;
+
+ // is the column we represent active ?
+ if (m_bHidden)
+ return; // no, it isn't (or at least it shouldn't be ...)
+
+ if (m_rParent.GetCurColumnId() == m_nId)
+ {
+ m_rParent.DeactivateCell();
+ m_rParent.ActivateCell(m_rParent.GetCurRow(), m_rParent.GetCurColumnId());
+ }
+}
+
+
+OUString DbGridColumn::GetCellText(const DbGridRow* pRow, const Reference< XNumberFormatter >& xFormatter) const
+{
+ OUString aText;
+ if (m_pCell.is() && dynamic_cast<const FmXFilterCell*>( m_pCell.get() ) != nullptr)
+ return aText;
+
+ if (!pRow || !pRow->IsValid())
+ aText = INVALIDTEXT;
+ else if (pRow->HasField(m_nFieldPos))
+ {
+ aText = GetCellText( pRow->GetField( m_nFieldPos ).getColumn(), xFormatter );
+ }
+ return aText;
+}
+
+OUString DbGridColumn::GetCellText(const Reference< css::sdb::XColumn >& xField, const Reference< XNumberFormatter >& xFormatter) const
+{
+ OUString aText;
+ if (xField.is())
+ {
+ FmXTextCell* pTextCell = dynamic_cast<FmXTextCell*>( m_pCell.get() );
+ if (pTextCell)
+ aText = pTextCell->GetText(xField, xFormatter);
+ else if (m_bObject)
+ aText = OBJECTTEXT;
+ }
+ return aText;
+}
+
+Reference< css::sdb::XColumn > DbGridColumn::GetCurrentFieldValue() const
+{
+ Reference< css::sdb::XColumn > xField;
+ const DbGridRowRef xRow = m_rParent.GetCurrentRow();
+ if (xRow.is() && xRow->HasField(m_nFieldPos))
+ {
+ xField = xRow->GetField(m_nFieldPos).getColumn();
+ }
+ return xField;
+}
+
+
+void DbGridColumn::Paint(OutputDevice& rDev,
+ const tools::Rectangle& rRect,
+ const DbGridRow* pRow,
+ const Reference< XNumberFormatter >& xFormatter)
+{
+ bool bEnabled = ( rDev.GetOutDevType() != OUTDEV_WINDOW )
+ || ( rDev.GetOwnerWindow()->IsEnabled() );
+
+ FmXDataCell* pDataCell = dynamic_cast<FmXDataCell*>( m_pCell.get() );
+ if (pDataCell)
+ {
+ if (!pRow || !pRow->IsValid())
+ {
+ DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::Center;
+ if ( !bEnabled )
+ nStyle |= DrawTextFlags::Disable;
+
+ rDev.DrawText(rRect, OUString(INVALIDTEXT), nStyle);
+ }
+ else if (m_bAutoValue && pRow->IsNew())
+ {
+ DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::VCenter;
+ if ( !bEnabled )
+ nStyle |= DrawTextFlags::Disable;
+
+ switch (GetAlignment())
+ {
+ case css::awt::TextAlign::RIGHT:
+ nStyle |= DrawTextFlags::Right;
+ break;
+ case css::awt::TextAlign::CENTER:
+ nStyle |= DrawTextFlags::Center;
+ break;
+ default:
+ nStyle |= DrawTextFlags::Left;
+ }
+
+ rDev.DrawText(rRect, SvxResId(RID_STR_AUTOFIELD), nStyle);
+ }
+ else if (pRow->HasField(m_nFieldPos))
+ {
+ pDataCell->PaintFieldToCell(rDev, rRect, pRow->GetField( m_nFieldPos ).getColumn(), xFormatter);
+ }
+ }
+ else if (!m_pCell.is())
+ {
+ if (!pRow || !pRow->IsValid())
+ {
+ DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::Center;
+ if ( !bEnabled )
+ nStyle |= DrawTextFlags::Disable;
+
+ rDev.DrawText(rRect, OUString(INVALIDTEXT), nStyle);
+ }
+ else if (pRow->HasField(m_nFieldPos) && m_bObject)
+ {
+ DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::Center;
+ if ( !bEnabled )
+ nStyle |= DrawTextFlags::Disable;
+ rDev.DrawText(rRect, OUString(OBJECTTEXT), nStyle);
+ }
+ }
+ else if ( auto pFilterCell = dynamic_cast<FmXFilterCell*>( m_pCell.get() ) )
+ pFilterCell->PaintCell( rDev, rRect );
+}
+
+
+void DbGridColumn::ImplInitWindow( vcl::Window const & rParent, const InitWindowFacet _eInitWhat )
+{
+ if ( m_pCell.is() )
+ m_pCell->ImplInitWindow( rParent, _eInitWhat );
+}
+
+
+//= cell controls
+
+
+DbCellControl::DbCellControl( DbGridColumn& _rColumn )
+ :OPropertyChangeListener(m_aMutex)
+ ,m_bTransparent( false )
+ ,m_bAlignedController( true )
+ ,m_bAccessingValueProperty( false )
+ ,m_rColumn( _rColumn )
+ ,m_pPainter( nullptr )
+ ,m_pWindow( nullptr )
+{
+ Reference< XPropertySet > xColModelProps = _rColumn.getModel();
+ if ( !xColModelProps.is() )
+ return;
+
+ // if our model's format key changes we want to propagate the new value to our windows
+ m_pModelChangeBroadcaster = new ::comphelper::OPropertyChangeMultiplexer(this, _rColumn.getModel());
+
+ // be listener for some common properties
+ implDoPropertyListening( FM_PROP_READONLY, false );
+ implDoPropertyListening( FM_PROP_ENABLED, false );
+
+ // add as listener for all known "value" properties
+ implDoPropertyListening( FM_PROP_VALUE, false );
+ implDoPropertyListening( FM_PROP_STATE, false );
+ implDoPropertyListening( FM_PROP_TEXT, false );
+ implDoPropertyListening( FM_PROP_EFFECTIVE_VALUE, false );
+ implDoPropertyListening( FM_PROP_SELECT_SEQ, false );
+ implDoPropertyListening( FM_PROP_DATE, false );
+ implDoPropertyListening( FM_PROP_TIME, false );
+
+ // be listener at the bound field as well
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( xColModelProps->getPropertySetInfo(), UNO_SET_THROW );
+ if ( xPSI->hasPropertyByName( FM_PROP_BOUNDFIELD ) )
+ {
+ Reference< XPropertySet > xField;
+ xColModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
+ if ( xField.is() )
+ {
+ m_pFieldChangeBroadcaster = new ::comphelper::OPropertyChangeMultiplexer(this, xField);
+ m_pFieldChangeBroadcaster->addProperty( FM_PROP_ISREADONLY );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "DbCellControl::doPropertyListening" );
+ }
+}
+
+
+void DbCellControl::implDoPropertyListening(const OUString& _rPropertyName, bool _bWarnIfNotExistent)
+{
+ try
+ {
+ Reference< XPropertySet > xColModelProps = m_rColumn.getModel();
+ Reference< XPropertySetInfo > xPSI;
+ if ( xColModelProps.is() )
+ xPSI = xColModelProps->getPropertySetInfo();
+
+ DBG_ASSERT( !_bWarnIfNotExistent || ( xPSI.is() && xPSI->hasPropertyByName( _rPropertyName ) ),
+ "DbCellControl::doPropertyListening: no property set info or non-existent property!" );
+
+ if ( xPSI.is() && xPSI->hasPropertyByName( _rPropertyName ) )
+ m_pModelChangeBroadcaster->addProperty( _rPropertyName );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "DbCellControl::doPropertyListening" );
+ }
+}
+
+
+void DbCellControl::doPropertyListening(const OUString& _rPropertyName)
+{
+ implDoPropertyListening( _rPropertyName, true );
+}
+
+static void lcl_clearBroadCaster(rtl::Reference<::comphelper::OPropertyChangeMultiplexer>& _pBroadcaster)
+{
+ if ( _pBroadcaster.is() )
+ {
+ _pBroadcaster->dispose();
+ _pBroadcaster.clear();
+ // no delete, this is done implicitly
+ }
+}
+
+DbCellControl::~DbCellControl()
+{
+ lcl_clearBroadCaster(m_pModelChangeBroadcaster);
+ lcl_clearBroadCaster(m_pFieldChangeBroadcaster);
+
+ m_pWindow.disposeAndClear();
+ m_pPainter.disposeAndClear();
+}
+
+void DbCellControl::implValuePropertyChanged( )
+{
+ OSL_ENSURE( !isValuePropertyLocked(),
+ "DbCellControl::implValuePropertyChanged: not to be called with the value property locked!" );
+
+ if ( m_pWindow )
+ {
+ if ( m_rColumn.getModel().is() )
+ updateFromModel( m_rColumn.getModel() );
+ }
+}
+
+
+void DbCellControl::implAdjustGenericFieldSetting( const Reference< XPropertySet >& /*_rxModel*/ )
+{
+ // nothing to do here
+}
+
+
+void DbCellControl::_propertyChanged(const PropertyChangeEvent& _rEvent)
+{
+ SolarMutexGuard aGuard;
+
+ Reference< XPropertySet > xSourceProps( _rEvent.Source, UNO_QUERY );
+
+ if ( _rEvent.PropertyName == FM_PROP_VALUE
+ || _rEvent.PropertyName == FM_PROP_STATE
+ || _rEvent.PropertyName == FM_PROP_TEXT
+ || _rEvent.PropertyName == FM_PROP_EFFECTIVE_VALUE
+ || _rEvent.PropertyName == FM_PROP_SELECT_SEQ
+ || _rEvent.PropertyName == FM_PROP_DATE
+ || _rEvent.PropertyName == FM_PROP_TIME
+ )
+ { // it was one of the known "value" properties
+ if ( !isValuePropertyLocked() )
+ {
+ implValuePropertyChanged( );
+ }
+ }
+ else if ( _rEvent.PropertyName == FM_PROP_READONLY )
+ {
+ implAdjustReadOnly( xSourceProps, true);
+ }
+ else if ( _rEvent.PropertyName == FM_PROP_ISREADONLY )
+ {
+ bool bReadOnly = true;
+ _rEvent.NewValue >>= bReadOnly;
+ m_rColumn.SetReadOnly(bReadOnly);
+ implAdjustReadOnly( xSourceProps, false);
+ }
+ else if ( _rEvent.PropertyName == FM_PROP_ENABLED )
+ {
+ implAdjustEnabled( xSourceProps );
+ }
+ else
+ implAdjustGenericFieldSetting( xSourceProps );
+}
+
+bool DbCellControl::Commit()
+{
+ // lock the listening for value property changes
+ lockValueProperty();
+ // commit the content of the control into the model's value property
+ bool bReturn = false;
+ try
+ {
+ bReturn = commitControl();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ // unlock the listening for value property changes
+ unlockValueProperty();
+ // outta here
+ return bReturn;
+}
+
+void DbCellControl::ImplInitWindow( vcl::Window const & rParent, const InitWindowFacet _eInitWhat )
+{
+ svt::ControlBase* pWindows[] = { m_pPainter, m_pWindow };
+
+ if (_eInitWhat & InitWindowFacet::WritingMode)
+ {
+ for (svt::ControlBase* pWindow : pWindows)
+ {
+ if (pWindow)
+ pWindow->EnableRTL(rParent.IsRTLEnabled());
+ }
+ }
+
+ if (_eInitWhat & InitWindowFacet::Font)
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Fraction& rZoom = rParent.GetZoom();
+
+ for (svt::ControlBase* pWindow : pWindows)
+ {
+ if (!pWindow)
+ continue;
+
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ aFont.SetTransparent(isTransparent());
+
+ if (rParent.IsControlFont())
+ aFont.Merge(rParent.GetControlFont());
+
+ if (rZoom.GetNumerator() != rZoom.GetDenominator())
+ {
+ Size aSize = aFont.GetFontSize();
+ aSize.setWidth(std::round(double(aSize.Width() * rZoom)));
+ aSize.setHeight(std::round(double(aSize.Height() * rZoom)));
+ aFont.SetFontSize(aSize);
+ }
+
+ pWindow->SetPointFont(aFont);
+ }
+ }
+
+ if ((_eInitWhat & InitWindowFacet::Font) || (_eInitWhat & InitWindowFacet::Foreground))
+ {
+ Color aTextColor(rParent.IsControlForeground() ? rParent.GetControlForeground() : rParent.GetTextColor());
+
+ bool bTextLineColor = rParent.IsTextLineColor();
+ Color aTextLineColor(rParent.GetTextLineColor());
+
+ for (svt::ControlBase* pWindow : pWindows)
+ {
+ if (pWindow)
+ {
+ pWindow->SetTextColor(aTextColor);
+ if (rParent.IsControlForeground())
+ pWindow->SetControlForeground(aTextColor);
+
+ if (bTextLineColor)
+ pWindow->SetTextLineColor();
+ else
+ pWindow->SetTextLineColor(aTextLineColor);
+ }
+ }
+ }
+
+ if (!(_eInitWhat & InitWindowFacet::Background))
+ return;
+
+ if (rParent.IsControlBackground())
+ {
+ Color aColor(rParent.GetControlBackground());
+ for (svt::ControlBase* pWindow : pWindows)
+ {
+ if (pWindow)
+ {
+ if (isTransparent())
+ pWindow->SetBackground();
+ else
+ {
+ pWindow->SetBackground(aColor);
+ pWindow->SetControlBackground(aColor);
+ }
+ pWindow->GetOutDev()->SetFillColor(aColor);
+ }
+ }
+ }
+ else
+ {
+ if (m_pPainter)
+ {
+ if (isTransparent())
+ m_pPainter->SetBackground();
+ else
+ m_pPainter->SetBackground(rParent.GetBackground());
+ m_pPainter->GetOutDev()->SetFillColor(rParent.GetOutDev()->GetFillColor());
+ }
+
+ if (m_pWindow)
+ {
+ if (isTransparent())
+ m_pWindow->SetBackground(rParent.GetBackground());
+ else
+ m_pWindow->GetOutDev()->SetFillColor(rParent.GetOutDev()->GetFillColor());
+ }
+ }
+}
+
+void DbCellControl::implAdjustReadOnly( const Reference< XPropertySet >& _rxModel,bool i_bReadOnly )
+{
+ DBG_ASSERT( m_pWindow, "DbCellControl::implAdjustReadOnly: not to be called without window!" );
+ DBG_ASSERT( _rxModel.is(), "DbCellControl::implAdjustReadOnly: invalid model!" );
+ if ( !(m_pWindow && _rxModel.is()) )
+ return;
+
+ bool bReadOnly = m_rColumn.IsReadOnly();
+ if ( !bReadOnly )
+ {
+ _rxModel->getPropertyValue( i_bReadOnly ? OUString(FM_PROP_READONLY) : OUString(FM_PROP_ISREADONLY)) >>= bReadOnly;
+ }
+ m_pWindow->SetEditableReadOnly(bReadOnly);
+}
+
+void DbCellControl::implAdjustEnabled( const Reference< XPropertySet >& _rxModel )
+{
+ DBG_ASSERT( m_pWindow, "DbCellControl::implAdjustEnabled: not to be called without window!" );
+ DBG_ASSERT( _rxModel.is(), "DbCellControl::implAdjustEnabled: invalid model!" );
+ if ( m_pWindow && _rxModel.is() )
+ {
+ bool bEnable = true;
+ _rxModel->getPropertyValue( FM_PROP_ENABLED ) >>= bEnable;
+ m_pWindow->Enable( bEnable );
+ }
+}
+
+void DbCellControl::Init(BrowserDataWin& rParent, const Reference< XRowSet >& _rxCursor)
+{
+ ImplInitWindow( rParent, InitWindowFacet::All );
+
+ if ( m_pWindow )
+ {
+ // align the control
+ if ( isAlignedController() )
+ AlignControl( m_rColumn.GetAlignment() );
+
+ try
+ {
+ // some other common properties
+ Reference< XPropertySet > xModel( m_rColumn.getModel(), UNO_SET_THROW );
+ Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW );
+
+ if ( xModelPSI->hasPropertyByName( FM_PROP_READONLY ) )
+ {
+ implAdjustReadOnly( xModel,true );
+ }
+
+ if ( xModelPSI->hasPropertyByName( FM_PROP_ENABLED ) )
+ {
+ implAdjustEnabled( xModel );
+ }
+
+ if ( xModelPSI->hasPropertyByName( FM_PROP_MOUSE_WHEEL_BEHAVIOR ) )
+ {
+ sal_Int16 nWheelBehavior = css::awt::MouseWheelBehavior::SCROLL_FOCUS_ONLY;
+ OSL_VERIFY( xModel->getPropertyValue( FM_PROP_MOUSE_WHEEL_BEHAVIOR ) >>= nWheelBehavior );
+ MouseWheelBehaviour nVclSetting = MouseWheelBehaviour::FocusOnly;
+ switch ( nWheelBehavior )
+ {
+ case css::awt::MouseWheelBehavior::SCROLL_DISABLED: nVclSetting = MouseWheelBehaviour::Disable; break;
+ case css::awt::MouseWheelBehavior::SCROLL_FOCUS_ONLY: nVclSetting = MouseWheelBehaviour::FocusOnly; break;
+ case css::awt::MouseWheelBehavior::SCROLL_ALWAYS: nVclSetting = MouseWheelBehaviour::ALWAYS; break;
+ default:
+ OSL_FAIL( "DbCellControl::Init: invalid MouseWheelBehavior!" );
+ break;
+ }
+
+ AllSettings aSettings = m_pWindow->GetSettings();
+ MouseSettings aMouseSettings = aSettings.GetMouseSettings();
+ aMouseSettings.SetWheelBehavior( nVclSetting );
+ aSettings.SetMouseSettings( aMouseSettings );
+ m_pWindow->SetSettings( aSettings, true );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ m_xCursor = _rxCursor;
+ if ( m_rColumn.getModel().is() )
+ updateFromModel( m_rColumn.getModel() );
+}
+
+
+void DbCellControl::SetTextLineColor()
+{
+ if (m_pWindow)
+ m_pWindow->SetTextLineColor();
+ if (m_pPainter)
+ m_pPainter->SetTextLineColor();
+}
+
+
+void DbCellControl::SetTextLineColor(const Color& _rColor)
+{
+ if (m_pWindow)
+ m_pWindow->SetTextLineColor(_rColor);
+ if (m_pPainter)
+ m_pPainter->SetTextLineColor(_rColor);
+}
+
+namespace
+{
+ void lcl_implAlign( vcl::Window* _pWindow, WinBits _nAlignmentBit )
+ {
+ if (EditControlBase* pControl = dynamic_cast<EditControlBase*>(_pWindow))
+ {
+ switch (_nAlignmentBit)
+ {
+ case WB_LEFT:
+ pControl->get_widget().set_alignment(TxtAlign::Left);
+ break;
+ case WB_CENTER:
+ pControl->get_widget().set_alignment(TxtAlign::Center);
+ break;
+ case WB_RIGHT:
+ pControl->get_widget().set_alignment(TxtAlign::Right);
+ break;
+ }
+ return;
+ }
+
+ WinBits nStyle = _pWindow->GetStyle();
+ nStyle &= ~(WB_LEFT | WB_RIGHT | WB_CENTER);
+ _pWindow->SetStyle( nStyle | _nAlignmentBit );
+ }
+}
+
+void DbCellControl::AlignControl(sal_Int16 nAlignment)
+{
+ WinBits nAlignmentBit = 0;
+ switch (nAlignment)
+ {
+ case css::awt::TextAlign::RIGHT:
+ nAlignmentBit = WB_RIGHT;
+ break;
+ case css::awt::TextAlign::CENTER:
+ nAlignmentBit = WB_CENTER;
+ break;
+ default:
+ nAlignmentBit = WB_LEFT;
+ break;
+ }
+ lcl_implAlign( m_pWindow, nAlignmentBit );
+ if ( m_pPainter )
+ lcl_implAlign( m_pPainter, nAlignmentBit );
+}
+
+void DbCellControl::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect)
+{
+ m_pPainter->SetSizePixel(rRect.GetSize());
+ m_pPainter->Draw(&rDev, rRect.TopLeft(), SystemTextColorFlags::NONE);
+}
+
+void DbCellControl::PaintFieldToCell( OutputDevice& _rDev, const tools::Rectangle& _rRect, const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& _rxFormatter )
+{
+ m_pPainter->SetText( GetFormatText( _rxField, _rxFormatter ) );
+ PaintCell( _rDev, _rRect );
+}
+
+double DbCellControl::GetValue(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter) const
+{
+ double fValue = 0;
+ if (m_rColumn.IsNumeric())
+ {
+ try
+ {
+ fValue = _rxField->getDouble();
+ }
+ catch(const Exception&) { }
+ }
+ else
+ {
+ bool bSuccess = false;
+ try
+ {
+ fValue = _rxField->getDouble();
+ bSuccess = true;
+ }
+ catch(const Exception&) { }
+ if (!bSuccess)
+ {
+ try
+ {
+ fValue = xFormatter->convertStringToNumber(m_rColumn.GetKey(), _rxField->getString());
+ }
+ catch(const Exception&) { }
+ }
+ }
+ return fValue;
+}
+
+void DbCellControl::invalidatedController()
+{
+ m_rColumn.GetParent().refreshController(m_rColumn.GetId(), DbGridControl::GrantControlAccess());
+}
+
+// CellModels
+
+DbLimitedLengthField::DbLimitedLengthField( DbGridColumn& _rColumn )
+ :DbCellControl( _rColumn )
+{
+ doPropertyListening( FM_PROP_MAXTEXTLEN );
+}
+
+
+void DbLimitedLengthField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& _rxModel )
+{
+ DBG_ASSERT( m_pWindow, "DbLimitedLengthField::implAdjustGenericFieldSetting: not to be called without window!" );
+ DBG_ASSERT( _rxModel.is(), "DbLimitedLengthField::implAdjustGenericFieldSetting: invalid model!" );
+ if ( m_pWindow && _rxModel.is() )
+ {
+ sal_Int16 nMaxLen = 0;
+ _rxModel->getPropertyValue( FM_PROP_MAXTEXTLEN ) >>= nMaxLen;
+ implSetMaxTextLen( nMaxLen );
+ }
+}
+
+void DbLimitedLengthField::implSetEffectiveMaxTextLen(sal_Int32 nMaxLen)
+{
+ dynamic_cast<EditControlBase&>(*m_pWindow).get_widget().set_max_length(nMaxLen);
+ if (m_pPainter)
+ dynamic_cast<EditControlBase&>(*m_pPainter).get_widget().set_max_length(nMaxLen);
+}
+
+DbTextField::DbTextField(DbGridColumn& _rColumn)
+ :DbLimitedLengthField(_rColumn)
+ ,m_bIsMultiLineEdit(false)
+{
+}
+
+DbTextField::~DbTextField( )
+{
+ m_pPainterImplementation.reset();
+ m_pEdit.reset();
+}
+
+void DbTextField::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
+{
+ sal_Int16 nAlignment = m_rColumn.SetAlignmentFromModel(-1);
+
+ Reference< XPropertySet > xModel( m_rColumn.getModel() );
+
+ bool bLeftAlign = true;
+
+ // is this a multi-line field?
+ bool bIsMultiLine = false;
+ try
+ {
+ if ( xModel.is() )
+ {
+ OSL_VERIFY( xModel->getPropertyValue( FM_PROP_MULTILINE ) >>= bIsMultiLine );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx",
+ "caught an exception while determining the multi-line capabilities!");
+ }
+
+ m_bIsMultiLineEdit = bIsMultiLine;
+ if ( bIsMultiLine )
+ {
+ auto xEditControl = VclPtr<MultiLineTextCell>::Create(&rParent);
+ auto xEditPainter = VclPtr<MultiLineTextCell>::Create(&rParent);
+
+ switch (nAlignment)
+ {
+ case awt::TextAlign::RIGHT:
+ xEditControl->get_widget().set_alignment(TxtAlign::Right);
+ xEditPainter->get_widget().set_alignment(TxtAlign::Right);
+ bLeftAlign = false;
+ break;
+ case awt::TextAlign::CENTER:
+ xEditControl->get_widget().set_alignment(TxtAlign::Center);
+ xEditPainter->get_widget().set_alignment(TxtAlign::Center);
+ bLeftAlign = false;
+ break;
+ }
+
+ m_pWindow = xEditControl;
+ m_pEdit.reset(new MultiLineEditImplementation(*xEditControl));
+
+ m_pPainter = xEditPainter;
+ m_pPainterImplementation.reset(new MultiLineEditImplementation(*xEditPainter));
+ }
+ else
+ {
+ auto xEditControl = VclPtr<EditControl>::Create(&rParent);
+ auto xEditPainter = VclPtr<EditControl>::Create(&rParent);
+
+ switch (nAlignment)
+ {
+ case awt::TextAlign::RIGHT:
+ xEditControl->get_widget().set_alignment(TxtAlign::Right);
+ xEditPainter->get_widget().set_alignment(TxtAlign::Right);
+ bLeftAlign = false;
+ break;
+ case awt::TextAlign::CENTER:
+ xEditControl->get_widget().set_alignment(TxtAlign::Center);
+ xEditPainter->get_widget().set_alignment(TxtAlign::Center);
+ bLeftAlign = false;
+ break;
+ }
+
+ m_pWindow = xEditControl;
+ m_pEdit.reset(new EntryImplementation(*xEditControl));
+
+ m_pPainter = xEditPainter;
+ m_pPainterImplementation.reset(new EntryImplementation(*xEditPainter));
+ }
+
+ if (bLeftAlign)
+ {
+ // this is so that when getting the focus, the selection is oriented left-to-right
+ AllSettings aSettings = m_pWindow->GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ aStyleSettings.SetSelectionOptions(
+ aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst);
+ aSettings.SetStyleSettings(aStyleSettings);
+ m_pWindow->SetSettings(aSettings);
+ }
+
+ implAdjustGenericFieldSetting( xModel );
+
+ DbLimitedLengthField::Init( rParent, xCursor );
+}
+
+CellControllerRef DbTextField::CreateController() const
+{
+ return new EditCellController( m_pEdit.get() );
+}
+
+void DbTextField::PaintFieldToCell( OutputDevice& _rDev, const tools::Rectangle& _rRect, const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& _rxFormatter )
+{
+ if ( m_pPainterImplementation )
+ m_pPainterImplementation->SetText( GetFormatText( _rxField, _rxFormatter ) );
+
+ DbLimitedLengthField::PaintFieldToCell( _rDev, _rRect, _rxField, _rxFormatter );
+}
+
+OUString DbTextField::GetFormatText(const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter, const Color** /*ppColor*/)
+{
+ if (!_rxField.is())
+ return OUString();
+
+ const css::uno::Reference<css::beans::XPropertySet> xPS(_rxField, UNO_QUERY);
+ FormattedColumnValue fmter( xFormatter, xPS );
+
+ try
+ {
+ return fmter.getFormattedValue();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return OUString();
+
+}
+
+void DbTextField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter)
+{
+ m_pEdit->SetText( GetFormatText( _rxField, xFormatter ) );
+ m_pEdit->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) );
+}
+
+void DbTextField::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbTextField::updateFromModel: invalid call!" );
+
+ OUString sText;
+ _rxModel->getPropertyValue( FM_PROP_TEXT ) >>= sText;
+
+ sal_Int32 nMaxTextLen = m_pEdit->GetMaxTextLen();
+ if (nMaxTextLen > 0 && sText.getLength() > nMaxTextLen)
+ {
+ sal_Int32 nDiff = sText.getLength() - nMaxTextLen;
+ sText = sText.replaceAt(sText.getLength() - nDiff,nDiff, u"");
+ }
+
+ m_pEdit->SetText( sText );
+ m_pEdit->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) );
+}
+
+bool DbTextField::commitControl()
+{
+ OUString aText( m_pEdit->GetText( getModelLineEndSetting( m_rColumn.getModel() ) ) );
+ // we have to check if the length before we can decide if the value was modified
+ sal_Int32 nMaxTextLen = m_pEdit->GetMaxTextLen();
+ if (nMaxTextLen > 0)
+ {
+ OUString sOldValue;
+ m_rColumn.getModel()->getPropertyValue( FM_PROP_TEXT ) >>= sOldValue;
+ // if the new value didn't change we must set the old long value again
+ if ( sOldValue.getLength() > nMaxTextLen && sOldValue.compareTo(aText,nMaxTextLen) == 0 )
+ aText = sOldValue;
+ }
+ m_rColumn.getModel()->setPropertyValue( FM_PROP_TEXT, Any( aText ) );
+ return true;
+}
+
+void DbTextField::implSetEffectiveMaxTextLen( sal_Int32 _nMaxLen )
+{
+ if ( m_pEdit )
+ m_pEdit->SetMaxTextLen( _nMaxLen );
+ if ( m_pPainterImplementation )
+ m_pPainterImplementation->SetMaxTextLen( _nMaxLen );
+}
+
+DbFormattedField::DbFormattedField(DbGridColumn& _rColumn)
+ :DbLimitedLengthField(_rColumn)
+{
+ // if our model's format key changes we want to propagate the new value to our windows
+ doPropertyListening( FM_PROP_FORMATKEY );
+}
+
+DbFormattedField::~DbFormattedField()
+{
+}
+
+void DbFormattedField::Init( BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
+{
+ sal_Int16 nAlignment = m_rColumn.SetAlignmentFromModel(-1);
+
+ Reference< css::beans::XPropertySet > xUnoModel = m_rColumn.getModel();
+
+ auto xEditControl = VclPtr<FormattedControl>::Create(&rParent, false);
+ auto xEditPainter = VclPtr<FormattedControl>::Create(&rParent, false);
+
+ weld::EntryFormatter& rControlFormatter = xEditControl->get_formatter();
+ weld::EntryFormatter& rPainterFormatter = xEditPainter->get_formatter();
+
+ m_pWindow = xEditControl.get();
+ m_pPainter = xEditPainter.get();
+
+ switch (nAlignment)
+ {
+ case awt::TextAlign::RIGHT:
+ xEditControl->get_widget().set_alignment(TxtAlign::Right);
+ xEditPainter->get_widget().set_alignment(TxtAlign::Right);
+ break;
+ case awt::TextAlign::CENTER:
+ xEditControl->get_widget().set_alignment(TxtAlign::Center);
+ xEditPainter->get_widget().set_alignment(TxtAlign::Center);
+ break;
+ default:
+ {
+ // Everything just so that the selection goes from right to left when getting focus
+ SelectionOptions eOptions = rControlFormatter.GetEntrySelectionOptions();
+ rControlFormatter.SetEntrySelectionOptions(eOptions | SelectionOptions::ShowFirst);
+ break;
+ }
+ }
+
+ implAdjustGenericFieldSetting( xUnoModel );
+
+ rControlFormatter.SetStrictFormat(false);
+ rPainterFormatter.SetStrictFormat(false);
+ // if one allows any formatting, one cannot make an entry check anyway
+ // (the FormattedField does not support that anyway, only derived classes)
+
+ // get the formatter from the uno model
+ // (I could theoretically also go via the css::util::NumberFormatter, which the cursor would
+ // surely give me. The problem is that I can not really rely on the fact that the two
+ // formatters are the same. Clean is the whole thing if I go via the UNO model.)
+ sal_Int32 nFormatKey = -1;
+
+ // let's see if the model has one ...
+ DBG_ASSERT(::comphelper::hasProperty(FM_PROP_FORMATSSUPPLIER, xUnoModel), "DbFormattedField::Init : invalid UNO model !");
+ Any aSupplier( xUnoModel->getPropertyValue(FM_PROP_FORMATSSUPPLIER));
+ if (aSupplier.hasValue())
+ {
+ m_xSupplier.set(aSupplier, css::uno::UNO_QUERY);
+ if (m_xSupplier.is())
+ {
+ // if we take the supplier from the model, then also the key
+ Any aFmtKey( xUnoModel->getPropertyValue(FM_PROP_FORMATKEY));
+ if (aFmtKey.hasValue())
+ {
+ DBG_ASSERT(aFmtKey.getValueType().getTypeClass() == TypeClass_LONG, "DbFormattedField::Init : invalid format key property (no sal_Int32) !");
+ nFormatKey = ::comphelper::getINT32(aFmtKey);
+ }
+ else
+ {
+ SAL_INFO("svx.fmcomp", "DbFormattedField::Init : my uno-model has no format-key, but a formats supplier !");
+ // the OFormattedModel which we usually are working with ensures that the model has a format key
+ // as soon as the form is loaded. Unfortunally this method here is called from within loaded, too.
+ // So if our LoadListener is called before the LoadListener of the model, this "else case" is
+ // allowed.
+ // Of course our property listener for the FormatKey property will notify us if the prop is changed,
+ // so this here isn't really bad...
+ nFormatKey = 0;
+ }
+ }
+ }
+
+ // No? Maybe the css::form::component::Form behind the cursor?
+ if (!m_xSupplier.is())
+ {
+ if (xCursor.is())
+ { // If we take the formatter from the cursor, then also the key from the field to which we are bound
+ m_xSupplier = getNumberFormats(getConnection(xCursor));
+
+ if (m_rColumn.GetField().is())
+ nFormatKey = ::comphelper::getINT32(m_rColumn.GetField()->getPropertyValue(FM_PROP_FORMATKEY));
+ }
+ }
+
+ SvNumberFormatter* pFormatterUsed = nullptr;
+ if (m_xSupplier.is())
+ {
+ SvNumberFormatsSupplierObj* pImplementation = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(m_xSupplier);
+ if (pImplementation)
+ pFormatterUsed = pImplementation->GetNumberFormatter();
+ else
+ // Everything is invalid: the supplier is of the wrong type, then we can not
+ // rely on a standard formatter to know the (possibly non-standard) key.
+ nFormatKey = -1;
+ }
+
+ // a standard formatter ...
+ if (pFormatterUsed == nullptr)
+ {
+ pFormatterUsed = rControlFormatter.StandardFormatter();
+ DBG_ASSERT(pFormatterUsed != nullptr, "DbFormattedField::Init : no standard formatter given by the numeric field !");
+ }
+ // ... and a standard key
+ if (nFormatKey == -1)
+ nFormatKey = 0;
+
+ rControlFormatter.SetFormatter(pFormatterUsed);
+ rPainterFormatter.SetFormatter(pFormatterUsed);
+
+ rControlFormatter.SetFormatKey(nFormatKey);
+ rPainterFormatter.SetFormatKey(nFormatKey);
+
+ rControlFormatter.TreatAsNumber(m_rColumn.IsNumeric());
+ rPainterFormatter.TreatAsNumber(m_rColumn.IsNumeric());
+
+ // min and max values
+ if (m_rColumn.IsNumeric())
+ {
+ bool bClearMin = true;
+ if (::comphelper::hasProperty(FM_PROP_EFFECTIVE_MIN, xUnoModel))
+ {
+ Any aMin( xUnoModel->getPropertyValue(FM_PROP_EFFECTIVE_MIN));
+ if (aMin.getValueType().getTypeClass() != TypeClass_VOID)
+ {
+ DBG_ASSERT(aMin.getValueType().getTypeClass() == TypeClass_DOUBLE, "DbFormattedField::Init : the model has an invalid min value !");
+ double dMin = ::comphelper::getDouble(aMin);
+ rControlFormatter.SetMinValue(dMin);
+ rPainterFormatter.SetMinValue(dMin);
+ bClearMin = false;
+ }
+ }
+ if (bClearMin)
+ {
+ rControlFormatter.ClearMinValue();
+ rPainterFormatter.ClearMinValue();
+ }
+ bool bClearMax = true;
+ if (::comphelper::hasProperty(FM_PROP_EFFECTIVE_MAX, xUnoModel))
+ {
+ Any aMax(xUnoModel->getPropertyValue(FM_PROP_EFFECTIVE_MAX));
+ if (aMax.getValueType().getTypeClass() != TypeClass_VOID)
+ {
+ DBG_ASSERT(aMax.getValueType().getTypeClass() == TypeClass_DOUBLE, "DbFormattedField::Init : the model has an invalid max value !");
+ double dMax = ::comphelper::getDouble(aMax);
+ rControlFormatter.SetMaxValue(dMax);
+ rPainterFormatter.SetMaxValue(dMax);
+ bClearMax = false;
+ }
+ }
+ if (bClearMax)
+ {
+ rControlFormatter.ClearMaxValue();
+ rPainterFormatter.ClearMaxValue();
+ }
+ }
+
+ // the default value
+ Any aDefault( xUnoModel->getPropertyValue(FM_PROP_EFFECTIVE_DEFAULT));
+ if (aDefault.hasValue())
+ { // the thing can be a double or a string
+ switch (aDefault.getValueType().getTypeClass())
+ {
+ case TypeClass_DOUBLE:
+ if (m_rColumn.IsNumeric())
+ {
+ rControlFormatter.SetDefaultValue(::comphelper::getDouble(aDefault));
+ rPainterFormatter.SetDefaultValue(::comphelper::getDouble(aDefault));
+ }
+ else
+ {
+ OUString sConverted;
+ const Color* pDummy;
+ pFormatterUsed->GetOutputString(::comphelper::getDouble(aDefault), 0, sConverted, &pDummy);
+ rControlFormatter.SetDefaultText(sConverted);
+ rPainterFormatter.SetDefaultText(sConverted);
+ }
+ break;
+ case TypeClass_STRING:
+ {
+ OUString sDefault( ::comphelper::getString(aDefault) );
+ if (m_rColumn.IsNumeric())
+ {
+ double dVal;
+ sal_uInt32 nTestFormat(0);
+ if (pFormatterUsed->IsNumberFormat(sDefault, nTestFormat, dVal))
+ {
+ rControlFormatter.SetDefaultValue(dVal);
+ rPainterFormatter.SetDefaultValue(dVal);
+ }
+ }
+ else
+ {
+ rControlFormatter.SetDefaultText(sDefault);
+ rPainterFormatter.SetDefaultText(sDefault);
+ }
+ }
+ break;
+ default:
+ OSL_FAIL( "DbFormattedField::Init: unexpected value type!" );
+ break;
+ }
+ }
+ DbLimitedLengthField::Init( rParent, xCursor );
+}
+
+CellControllerRef DbFormattedField::CreateController() const
+{
+ return new ::svt::FormattedFieldCellController(static_cast<FormattedControlBase*>(m_pWindow.get()));
+}
+
+void DbFormattedField::_propertyChanged( const PropertyChangeEvent& _rEvent )
+{
+ if (_rEvent.PropertyName == FM_PROP_FORMATKEY )
+ {
+ sal_Int32 nNewKey = _rEvent.NewValue.hasValue() ? ::comphelper::getINT32(_rEvent.NewValue) : 0;
+
+ DBG_ASSERT(m_pWindow && m_pPainter, "DbFormattedField::_propertyChanged : where are my windows ?");
+ if (m_pWindow)
+ static_cast<FormattedControlBase*>(m_pWindow.get())->get_formatter().SetFormatKey(nNewKey);
+ if (m_pPainter)
+ static_cast<FormattedControlBase*>(m_pPainter.get())->get_formatter().SetFormatKey(nNewKey);
+ }
+ else
+ {
+ DbLimitedLengthField::_propertyChanged( _rEvent );
+ }
+}
+
+OUString DbFormattedField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** ppColor)
+{
+ // no color specification by default
+ if (ppColor != nullptr)
+ *ppColor = nullptr;
+
+ // NULL value -> empty text
+ if (!_rxField.is())
+ return OUString();
+
+ FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pPainter.get());
+ weld::EntryFormatter& rPainterFormatter = pControl->get_formatter();
+
+ OUString aText;
+ try
+ {
+ if (m_rColumn.IsNumeric())
+ {
+ // The IsNumeric at the column says nothing about the class of the used format, but
+ // about the class of the field bound to the column. So when you bind a FormattedField
+ // column to a double field and format it as text, m_rColumn.IsNumeric() returns
+ // sal_True. So that simply means that I can query the contents of the variant using
+ // getDouble, and then I can leave the rest (the formatting) to the FormattedField.
+ double dValue = getValue( _rxField, m_rColumn.GetParent().getNullDate() );
+ if (_rxField->wasNull())
+ return aText;
+ rPainterFormatter.SetValue(dValue);
+ }
+ else
+ {
+ // Here I can not work with a double, since the field can not provide it to me.
+ // So simply bind the text from the css::util::NumberFormatter to the correct css::form::component::Form.
+ aText = _rxField->getString();
+ if (_rxField->wasNull())
+ return aText;
+ rPainterFormatter.SetTextFormatted(aText);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ aText = pControl->get_widget().get_text();
+ if (ppColor != nullptr)
+ *ppColor = rPainterFormatter.GetLastOutputColor();
+
+ return aText;
+}
+
+void DbFormattedField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/)
+{
+ try
+ {
+ FormattedControlBase* pEditControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+ weld::Entry& rEntry = pEditControl->get_widget();
+ weld::EntryFormatter& rEditFormatter = pEditControl->get_formatter();
+
+ if (!_rxField.is())
+ {
+ // NULL value -> empty text
+ rEntry.set_text(OUString());
+ }
+ else if (m_rColumn.IsNumeric())
+ {
+ // The IsNumeric at the column says nothing about the class of the used format, but
+ // about the class of the field bound to the column. So when you bind a FormattedField
+ // column to a double field and format it as text, m_rColumn.IsNumeric() returns
+ // sal_True. So that simply means that I can query the contents of the variant using
+ // getDouble, and then I can leave the rest (the formatting) to the FormattedField.
+ double dValue = getValue( _rxField, m_rColumn.GetParent().getNullDate() );
+ if (_rxField->wasNull())
+ rEntry.set_text(OUString());
+ else
+ rEditFormatter.SetValue(dValue);
+ }
+ else
+ {
+ // Here I can not work with a double, since the field can not provide it to me.
+ // So simply bind the text from the css::util::NumberFormatter to the correct css::form::component::Form.
+ OUString sText( _rxField->getString());
+
+ rEditFormatter.SetTextFormatted( sText );
+ rEntry.select_region(0, -1);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+void DbFormattedField::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbFormattedField::updateFromModel: invalid call!" );
+
+ FormattedControlBase* pEditControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+ weld::Entry& rEntry = pEditControl->get_widget();
+ weld::EntryFormatter& rEditFormatter = pEditControl->get_formatter();
+
+ OUString sText;
+ Any aValue = _rxModel->getPropertyValue( FM_PROP_EFFECTIVE_VALUE );
+ if ( !aValue.hasValue() || (aValue >>= sText) )
+ {
+ // our effective value is transferred as string
+ rEditFormatter.SetTextFormatted( sText );
+ rEntry.select_region(0, -1);
+ }
+ else
+ {
+ double dValue = 0;
+ aValue >>= dValue;
+ rEditFormatter.SetValue(dValue);
+ }
+}
+
+bool DbFormattedField::commitControl()
+{
+ Any aNewVal;
+
+ FormattedControlBase* pEditControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+ weld::Entry& rEntry = pEditControl->get_widget();
+ weld::EntryFormatter& rEditFormatter = pEditControl->get_formatter();
+
+ if (m_rColumn.IsNumeric())
+ {
+ if (!rEntry.get_text().isEmpty())
+ aNewVal <<= rEditFormatter.GetValue();
+ // an empty string is passed on as void by default, to start with
+ }
+ else
+ aNewVal <<= rEditFormatter.GetTextValue();
+
+ m_rColumn.getModel()->setPropertyValue(FM_PROP_EFFECTIVE_VALUE, aNewVal);
+ return true;
+}
+
+DbCheckBox::DbCheckBox( DbGridColumn& _rColumn )
+ :DbCellControl( _rColumn )
+{
+ setAlignedController( false );
+}
+
+namespace
+{
+ void setCheckBoxStyle( vcl::Window* _pWindow, bool bMono )
+ {
+ AllSettings aSettings = _pWindow->GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ if( bMono )
+ aStyleSettings.SetOptions( aStyleSettings.GetOptions() | StyleSettingsOptions::Mono );
+ else
+ aStyleSettings.SetOptions( aStyleSettings.GetOptions() & (~StyleSettingsOptions::Mono) );
+ aSettings.SetStyleSettings( aStyleSettings );
+ _pWindow->SetSettings( aSettings );
+ }
+}
+
+void DbCheckBox::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
+{
+ setTransparent( true );
+
+ m_pWindow = VclPtr<CheckBoxControl>::Create( &rParent );
+ m_pPainter = VclPtr<CheckBoxControl>::Create( &rParent );
+
+ m_pWindow->SetPaintTransparent( true );
+ m_pPainter->SetPaintTransparent( true );
+
+ m_pPainter->SetBackground();
+
+ try
+ {
+ Reference< XPropertySet > xModel( m_rColumn.getModel(), UNO_SET_THROW );
+
+ sal_Int16 nStyle = awt::VisualEffect::LOOK3D;
+ OSL_VERIFY( xModel->getPropertyValue( FM_PROP_VISUALEFFECT ) >>= nStyle );
+
+ setCheckBoxStyle( m_pWindow, nStyle == awt::VisualEffect::FLAT );
+ setCheckBoxStyle( m_pPainter, nStyle == awt::VisualEffect::FLAT );
+
+ bool bTristate = true;
+ OSL_VERIFY( xModel->getPropertyValue( FM_PROP_TRISTATE ) >>= bTristate );
+ static_cast< CheckBoxControl* >( m_pWindow.get() )->EnableTriState( bTristate );
+ static_cast< CheckBoxControl* >( m_pPainter.get() )->EnableTriState( bTristate );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ DbCellControl::Init( rParent, xCursor );
+}
+
+CellControllerRef DbCheckBox::CreateController() const
+{
+ return new CheckBoxCellController(static_cast<CheckBoxControl*>(m_pWindow.get()));
+}
+
+static void lcl_setCheckBoxState( const Reference< css::sdb::XColumn >& _rxField,
+ CheckBoxControl* _pCheckBoxControl )
+{
+ TriState eState = TRISTATE_INDET;
+ if (_rxField.is())
+ {
+ try
+ {
+ bool bValue = _rxField->getBoolean();
+ if (!_rxField->wasNull())
+ eState = bValue ? TRISTATE_TRUE : TRISTATE_FALSE;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ _pCheckBoxControl->SetState(eState);
+}
+
+void DbCheckBox::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/)
+{
+ lcl_setCheckBoxState( _rxField, static_cast<CheckBoxControl*>(m_pWindow.get()) );
+}
+
+void DbCheckBox::PaintFieldToCell(OutputDevice& rDev, const tools::Rectangle& rRect,
+ const Reference< css::sdb::XColumn >& _rxField,
+ const Reference< XNumberFormatter >& xFormatter)
+{
+ CheckBoxControl* pControl = static_cast<CheckBoxControl*>(m_pPainter.get());
+ lcl_setCheckBoxState( _rxField, pControl );
+
+ Size aBoxSize;
+
+ switch (rDev.GetOutDevType())
+ {
+ case OUTDEV_WINDOW:
+ case OUTDEV_VIRDEV:
+ aBoxSize = pControl->GetBox().get_preferred_size();
+ break;
+ case OUTDEV_PRINTER:
+ case OUTDEV_PDF:
+ {
+ auto nSize = std::min(rRect.GetWidth(), rRect.GetHeight());
+ aBoxSize = Size(nSize, nSize);
+ break;
+ }
+ }
+
+ tools::Rectangle aRect(Point(rRect.Left() + ((rRect.GetWidth() - aBoxSize.Width()) / 2),
+ rRect.Top() + ((rRect.GetHeight() - aBoxSize.Height()) / 2)),
+ aBoxSize);
+
+ DbCellControl::PaintFieldToCell(rDev, aRect, _rxField, xFormatter);
+}
+
+void DbCheckBox::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect)
+{
+ switch (rDev.GetOutDevType())
+ {
+ case OUTDEV_WINDOW:
+ case OUTDEV_VIRDEV:
+ DbCellControl::PaintCell(rDev, rRect);
+ break;
+ case OUTDEV_PRINTER:
+ case OUTDEV_PDF:
+ {
+ TriState eState = static_cast<CheckBoxControl*>(m_pWindow.get())->GetState();
+
+ MapMode aResMapMode(MapUnit::Map100thMM);
+ Size aImageSize = rDev.LogicToPixel(Size(300, 300), aResMapMode);
+ Size aBrd1Size = rDev.LogicToPixel(Size(20, 20), aResMapMode);
+ Size aBrd2Size = rDev.LogicToPixel(Size(30, 30), aResMapMode);
+ int nCheckWidth = rDev.LogicToPixel(Size(20, 20), aResMapMode).Width();
+
+ tools::Rectangle aStateRect;
+ aStateRect.SetLeft(rRect.Left() + ((rRect.GetWidth() - aImageSize.Width()) / 2));
+ aStateRect.SetTop(rRect.Top() + ((rRect.GetHeight() - aImageSize.Height()) / 2));
+ aStateRect.SetRight(aStateRect.Left() + aImageSize.Width() - 1);
+ aStateRect.SetBottom(aStateRect.Top() + aImageSize.Height() - 1);
+
+ rDev.Push();
+ rDev.SetMapMode();
+
+ rDev.SetLineColor();
+ rDev.SetFillColor(COL_BLACK);
+ rDev.DrawRect(aStateRect);
+ aStateRect.AdjustLeft(aBrd1Size.Width());
+ aStateRect.AdjustTop(aBrd1Size.Height());
+ aStateRect.AdjustRight(-aBrd1Size.Width());
+ aStateRect.AdjustBottom(-aBrd1Size.Height());
+ if (eState == TRISTATE_INDET)
+ rDev.SetFillColor(COL_LIGHTGRAY);
+ else
+ rDev.SetFillColor(COL_WHITE);
+ rDev.DrawRect(aStateRect);
+
+ if (eState == TRISTATE_TRUE)
+ {
+ aStateRect.AdjustLeft(aBrd2Size.Width());
+ aStateRect.AdjustTop(aBrd2Size.Height());
+ aStateRect.AdjustRight(-aBrd2Size.Width());
+ aStateRect.AdjustBottom(-aBrd2Size.Height());
+ Point aPos11(aStateRect.TopLeft());
+ Point aPos12(aStateRect.BottomRight());
+ Point aPos21(aStateRect.TopRight());
+ Point aPos22(aStateRect.BottomLeft());
+ Point aTempPos11(aPos11);
+ Point aTempPos12(aPos12);
+ Point aTempPos21(aPos21);
+ Point aTempPos22(aPos22);
+ rDev.SetLineColor(COL_BLACK);
+ int nDX = 0;
+ for (int i = 0; i < nCheckWidth; i++)
+ {
+ if ( !(i % 2) )
+ {
+ aTempPos11.setX(aPos11.X() + nDX);
+ aTempPos12.setX(aPos12.X() + nDX);
+ aTempPos21.setX(aPos21.X() + nDX);
+ aTempPos22.setX(aPos22.X() + nDX);
+ }
+ else
+ {
+ nDX++;
+ aTempPos11.setX(aPos11.X() - nDX);
+ aTempPos12.setX(aPos12.X() - nDX);
+ aTempPos21.setX(aPos21.X() - nDX);
+ aTempPos22.setX(aPos22.X() - nDX);
+ }
+ rDev.DrawLine(aTempPos11, aTempPos12);
+ rDev.DrawLine(aTempPos21, aTempPos22);
+ }
+ }
+
+ rDev.Pop();
+ break;
+ }
+ }
+}
+
+void DbCheckBox::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbCheckBox::updateFromModel: invalid call!" );
+
+ sal_Int16 nState = TRISTATE_INDET;
+ _rxModel->getPropertyValue( FM_PROP_STATE ) >>= nState;
+ static_cast< CheckBoxControl* >( m_pWindow.get() )->SetState( static_cast< TriState >( nState ) );
+}
+
+bool DbCheckBox::commitControl()
+{
+ m_rColumn.getModel()->setPropertyValue( FM_PROP_STATE,
+ Any( static_cast<sal_Int16>( static_cast< CheckBoxControl* >( m_pWindow.get() )->GetState() ) ) );
+ return true;
+}
+
+OUString DbCheckBox::GetFormatText(const Reference< XColumn >& /*_rxField*/, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
+{
+ return OUString();
+}
+
+DbPatternField::DbPatternField( DbGridColumn& _rColumn, const Reference<XComponentContext>& _rContext )
+ :DbCellControl( _rColumn )
+ ,m_xContext( _rContext )
+{
+ doPropertyListening( FM_PROP_LITERALMASK );
+ doPropertyListening( FM_PROP_EDITMASK );
+ doPropertyListening( FM_PROP_STRICTFORMAT );
+}
+
+void DbPatternField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& _rxModel )
+{
+ DBG_ASSERT( m_pWindow, "DbPatternField::implAdjustGenericFieldSetting: not to be called without window!" );
+ DBG_ASSERT( _rxModel.is(), "DbPatternField::implAdjustGenericFieldSetting: invalid model!" );
+ if ( !m_pWindow || !_rxModel.is() )
+ return;
+
+ OUString aLitMask;
+ OUString aEditMask;
+ bool bStrict = false;
+
+ _rxModel->getPropertyValue( FM_PROP_LITERALMASK ) >>= aLitMask;
+ _rxModel->getPropertyValue( FM_PROP_EDITMASK ) >>= aEditMask;
+ _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) >>= bStrict;
+
+ OString aAsciiEditMask(OUStringToOString(aEditMask, RTL_TEXTENCODING_ASCII_US));
+
+ weld::PatternFormatter& rEditFormatter = static_cast<PatternControl*>(m_pWindow.get())->get_formatter();
+ rEditFormatter.SetMask(aAsciiEditMask, aLitMask);
+ rEditFormatter.SetStrictFormat(bStrict);
+
+ weld::PatternFormatter& rPaintFormatter = static_cast<PatternControl*>(m_pPainter.get())->get_formatter();
+ rPaintFormatter.SetMask(aAsciiEditMask, aLitMask);
+ rPaintFormatter.SetStrictFormat(bStrict);
+}
+
+void DbPatternField::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
+{
+ m_rColumn.SetAlignmentFromModel(-1);
+
+ m_pWindow = VclPtr<PatternControl>::Create(&rParent);
+ m_pPainter= VclPtr<PatternControl>::Create(&rParent);
+
+ Reference< XPropertySet > xModel( m_rColumn.getModel() );
+ implAdjustGenericFieldSetting( xModel );
+
+ DbCellControl::Init( rParent, xCursor );
+}
+
+CellControllerRef DbPatternField::CreateController() const
+{
+ return new EditCellController(static_cast<PatternControl*>(m_pWindow.get()));
+}
+
+OUString DbPatternField::impl_formatText( const OUString& _rText )
+{
+ weld::PatternFormatter& rPaintFormatter = static_cast<PatternControl*>(m_pPainter.get())->get_formatter();
+ rPaintFormatter.get_widget().set_text(_rText);
+ rPaintFormatter.ReformatAll();
+ return rPaintFormatter.get_widget().get_text();
+}
+
+OUString DbPatternField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
+{
+ bool bIsForPaint = _rxField != m_rColumn.GetField();
+ ::std::unique_ptr< FormattedColumnValue >& rpFormatter = bIsForPaint ? m_pPaintFormatter : m_pValueFormatter;
+
+ if (!rpFormatter)
+ {
+ rpFormatter = std::make_unique< FormattedColumnValue> (
+ m_xContext, getCursor(), Reference< XPropertySet >( _rxField, UNO_QUERY ) );
+ OSL_ENSURE(rpFormatter, "DbPatternField::Init: no value formatter!");
+ }
+ else
+ OSL_ENSURE( rpFormatter->getColumn() == _rxField, "DbPatternField::GetFormatText: my value formatter is working for another field ...!" );
+ // re-creating the value formatter here every time would be quite expensive ...
+
+ OUString sText;
+ if (rpFormatter)
+ sText = rpFormatter->getFormattedValue();
+
+ return impl_formatText( sText );
+}
+
+void DbPatternField::UpdateFromField( const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& _rxFormatter )
+{
+ weld::Entry& rEntry = static_cast<PatternControl*>(m_pWindow.get())->get_widget();
+ rEntry.set_text(GetFormatText(_rxField, _rxFormatter));
+ rEntry.select_region(-1, 0);
+}
+
+void DbPatternField::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbPatternField::updateFromModel: invalid call!" );
+
+ OUString sText;
+ _rxModel->getPropertyValue( FM_PROP_TEXT ) >>= sText;
+
+ weld::Entry& rEntry = static_cast<PatternControl*>(m_pWindow.get())->get_widget();
+ rEntry.set_text(impl_formatText(sText));
+ rEntry.select_region(-1, 0);
+}
+
+bool DbPatternField::commitControl()
+{
+ weld::Entry& rEntry = static_cast<PatternControl*>(m_pWindow.get())->get_widget();
+ m_rColumn.getModel()->setPropertyValue(FM_PROP_TEXT, Any(rEntry.get_text()));
+ return true;
+}
+
+DbSpinField::DbSpinField( DbGridColumn& _rColumn, sal_Int16 _nStandardAlign )
+ :DbCellControl( _rColumn )
+ ,m_nStandardAlign( _nStandardAlign )
+{
+}
+
+void DbSpinField::Init(BrowserDataWin& _rParent, const Reference< XRowSet >& _rxCursor)
+{
+ m_rColumn.SetAlignmentFromModel( m_nStandardAlign );
+
+ Reference< XPropertySet > xModel( m_rColumn.getModel() );
+
+ // determine if we need a spinbutton version
+ bool bSpinButton(false);
+ if ( ::comphelper::getBOOL( xModel->getPropertyValue( FM_PROP_SPIN ) ) )
+ bSpinButton = true;
+ // create the fields
+ m_pWindow = createField( &_rParent, bSpinButton, xModel );
+ m_pPainter = createField( &_rParent, bSpinButton, xModel );
+
+ // adjust all other settings which depend on the property values
+ implAdjustGenericFieldSetting( xModel );
+
+ // call the base class
+ DbCellControl::Init( _rParent, _rxCursor );
+}
+
+CellControllerRef DbSpinField::CreateController() const
+{
+ return new ::svt::FormattedFieldCellController(static_cast<FormattedControlBase*>(m_pWindow.get()));
+}
+
+DbNumericField::DbNumericField( DbGridColumn& _rColumn )
+ :DbSpinField( _rColumn )
+{
+ doPropertyListening( FM_PROP_DECIMAL_ACCURACY );
+ doPropertyListening( FM_PROP_VALUEMIN );
+ doPropertyListening( FM_PROP_VALUEMAX );
+ doPropertyListening( FM_PROP_VALUESTEP );
+ doPropertyListening( FM_PROP_STRICTFORMAT );
+ doPropertyListening( FM_PROP_SHOWTHOUSANDSEP );
+}
+
+void DbNumericField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& _rxModel )
+{
+ DBG_ASSERT( m_pWindow, "DbNumericField::implAdjustGenericFieldSetting: not to be called without window!" );
+ DBG_ASSERT( _rxModel.is(), "DbNumericField::implAdjustGenericFieldSetting: invalid model!" );
+ if ( !m_pWindow || !_rxModel.is() )
+ return;
+
+ sal_Int32 nMin = static_cast<sal_Int32>(getDouble( _rxModel->getPropertyValue( FM_PROP_VALUEMIN ) ));
+ sal_Int32 nMax = static_cast<sal_Int32>(getDouble( _rxModel->getPropertyValue( FM_PROP_VALUEMAX ) ));
+ sal_Int32 nStep = static_cast<sal_Int32>(getDouble( _rxModel->getPropertyValue( FM_PROP_VALUESTEP ) ));
+ bool bStrict = getBOOL( _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) );
+ sal_Int16 nScale = getINT16( _rxModel->getPropertyValue( FM_PROP_DECIMAL_ACCURACY ) );
+ bool bThousand = getBOOL( _rxModel->getPropertyValue( FM_PROP_SHOWTHOUSANDSEP ) );
+
+ Formatter& rEditFormatter = static_cast<FormattedControlBase*>(m_pWindow.get())->get_formatter();
+ rEditFormatter.SetMinValue(nMin);
+ rEditFormatter.SetMaxValue(nMax);
+ rEditFormatter.SetSpinSize(nStep);
+ rEditFormatter.SetStrictFormat(bStrict);
+
+ Formatter& rPaintFormatter = static_cast<FormattedControlBase*>(m_pPainter.get())->get_formatter();
+ rPaintFormatter.SetMinValue(nMin);
+ rPaintFormatter.SetMaxValue(nMax);
+ rPaintFormatter.SetStrictFormat(bStrict);
+
+ // give a formatter to the field and the painter;
+ // test first if I can get from the service behind a connection
+ Reference< css::util::XNumberFormatsSupplier > xSupplier;
+ Reference< XRowSet > xForm;
+ if ( m_rColumn.GetParent().getDataSource() )
+ xForm.set( Reference< XInterface >(*m_rColumn.GetParent().getDataSource()), UNO_QUERY );
+ if ( xForm.is() )
+ xSupplier = getNumberFormats( getConnection( xForm ), true );
+ SvNumberFormatter* pFormatterUsed = nullptr;
+ if ( xSupplier.is() )
+ {
+ SvNumberFormatsSupplierObj* pImplementation = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xSupplier );
+ pFormatterUsed = pImplementation ? pImplementation->GetNumberFormatter() : nullptr;
+ }
+ if ( nullptr == pFormatterUsed )
+ { // the cursor didn't lead to success -> standard
+ pFormatterUsed = rEditFormatter.StandardFormatter();
+ DBG_ASSERT( pFormatterUsed != nullptr, "DbNumericField::implAdjustGenericFieldSetting: no standard formatter given by the numeric field !" );
+ }
+ rEditFormatter.SetFormatter( pFormatterUsed );
+ rPaintFormatter.SetFormatter( pFormatterUsed );
+
+ // and then generate a format which has the desired length after the decimal point, etc.
+ LanguageType aAppLanguage = Application::GetSettings().GetUILanguageTag().getLanguageType();
+ OUString sFormatString = pFormatterUsed->GenerateFormat(0, aAppLanguage, bThousand, false, nScale);
+
+ rEditFormatter.SetFormat( sFormatString, aAppLanguage );
+ rPaintFormatter.SetFormat( sFormatString, aAppLanguage );
+}
+
+VclPtr<svt::ControlBase> DbNumericField::createField(BrowserDataWin* pParent, bool bSpinButton, const Reference<XPropertySet>& /*rxModel*/)
+{
+ return VclPtr<DoubleNumericControl>::Create(pParent, bSpinButton);
+}
+
+namespace
+{
+ OUString lcl_setFormattedNumeric_nothrow( FormattedControlBase& _rField, const DbCellControl& _rControl,
+ const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& _rxFormatter )
+ {
+ OUString sValue;
+ if ( _rxField.is() )
+ {
+ try
+ {
+ double fValue = _rControl.GetValue( _rxField, _rxFormatter );
+ if ( !_rxField->wasNull() )
+ {
+ _rField.get_formatter().SetValue(fValue);
+ sValue = _rField.get_widget().get_text();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ return sValue;
+ }
+}
+
+OUString DbNumericField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& _rxFormatter, const Color** /*ppColor*/)
+{
+ return lcl_setFormattedNumeric_nothrow(dynamic_cast<FormattedControlBase&>(*m_pPainter), *this, _rxField, _rxFormatter);
+}
+
+void DbNumericField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& _rxFormatter)
+{
+ lcl_setFormattedNumeric_nothrow(dynamic_cast<FormattedControlBase&>(*m_pWindow), *this, _rxField, _rxFormatter);
+}
+
+void DbNumericField::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbNumericField::updateFromModel: invalid call!" );
+
+ FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+
+ double dValue = 0;
+ if ( _rxModel->getPropertyValue( FM_PROP_VALUE ) >>= dValue )
+ {
+ Formatter& rFormatter = pControl->get_formatter();
+ rFormatter.SetValue(dValue);
+ }
+ else
+ pControl->get_widget().set_text(OUString());
+}
+
+bool DbNumericField::commitControl()
+{
+ FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+ OUString aText(pControl->get_widget().get_text());
+ Any aVal;
+
+ if (!aText.isEmpty()) // not empty
+ {
+ Formatter& rFormatter = pControl->get_formatter();
+ double fValue = rFormatter.GetValue();
+ aVal <<= fValue;
+ }
+ m_rColumn.getModel()->setPropertyValue(FM_PROP_VALUE, aVal);
+ return true;
+}
+
+DbCurrencyField::DbCurrencyField(DbGridColumn& _rColumn)
+ :DbSpinField( _rColumn )
+{
+ doPropertyListening( FM_PROP_DECIMAL_ACCURACY );
+ doPropertyListening( FM_PROP_VALUEMIN );
+ doPropertyListening( FM_PROP_VALUEMAX );
+ doPropertyListening( FM_PROP_VALUESTEP );
+ doPropertyListening( FM_PROP_STRICTFORMAT );
+ doPropertyListening( FM_PROP_SHOWTHOUSANDSEP );
+ doPropertyListening( FM_PROP_CURRENCYSYMBOL );
+}
+
+void DbCurrencyField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& _rxModel )
+{
+ DBG_ASSERT( m_pWindow, "DbCurrencyField::implAdjustGenericFieldSetting: not to be called without window!" );
+ DBG_ASSERT( _rxModel.is(), "DbCurrencyField::implAdjustGenericFieldSetting: invalid model!" );
+ if ( !m_pWindow || !_rxModel.is() )
+ return;
+
+ sal_Int16 nScale = getINT16( _rxModel->getPropertyValue( FM_PROP_DECIMAL_ACCURACY ) );
+ double nMin = getDouble( _rxModel->getPropertyValue( FM_PROP_VALUEMIN ) );
+ double nMax = getDouble( _rxModel->getPropertyValue( FM_PROP_VALUEMAX ) );
+ double nStep = getDouble( _rxModel->getPropertyValue( FM_PROP_VALUESTEP ) );
+ bool bStrict = getBOOL( _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) );
+ bool bThousand = getBOOL( _rxModel->getPropertyValue( FM_PROP_SHOWTHOUSANDSEP ) );
+ OUString aStr( getString( _rxModel->getPropertyValue(FM_PROP_CURRENCYSYMBOL ) ) );
+
+ Formatter& rEditFormatter = static_cast<FormattedControlBase*>(m_pWindow.get())->get_formatter();
+ rEditFormatter.SetDecimalDigits(nScale);
+ rEditFormatter.SetMinValue(nMin);
+ rEditFormatter.SetMaxValue(nMax);
+ rEditFormatter.SetSpinSize(nStep);
+ rEditFormatter.SetStrictFormat(bStrict);
+ weld::LongCurrencyFormatter& rCurrencyEditFormatter = static_cast<weld::LongCurrencyFormatter&>(rEditFormatter);
+ rCurrencyEditFormatter.SetUseThousandSep(bThousand);
+ rCurrencyEditFormatter.SetCurrencySymbol(aStr);
+
+ Formatter& rPaintFormatter = static_cast<FormattedControlBase*>(m_pPainter.get())->get_formatter();
+ rPaintFormatter.SetDecimalDigits(nScale);
+ rPaintFormatter.SetMinValue(nMin);
+ rPaintFormatter.SetMaxValue(nMax);
+ rPaintFormatter.SetStrictFormat(bStrict);
+ weld::LongCurrencyFormatter& rPaintCurrencyFormatter = static_cast<weld::LongCurrencyFormatter&>(rPaintFormatter);
+ rPaintCurrencyFormatter.SetUseThousandSep(bThousand);
+ rPaintCurrencyFormatter.SetCurrencySymbol(aStr);
+}
+
+VclPtr<svt::ControlBase> DbCurrencyField::createField(BrowserDataWin* pParent, bool bSpinButton, const Reference< XPropertySet >& /*rxModel*/)
+{
+ return VclPtr<LongCurrencyControl>::Create(pParent, bSpinButton);
+}
+
+namespace
+{
+ OUString lcl_setFormattedCurrency_nothrow( FormattedControlBase& _rField, const DbCurrencyField& _rControl,
+ const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& _rxFormatter )
+ {
+ OUString sValue;
+ if ( _rxField.is() )
+ {
+ try
+ {
+ double fValue = _rControl.GetValue( _rxField, _rxFormatter );
+ if ( !_rxField->wasNull() )
+ {
+ _rField.get_formatter().SetValue(fValue);
+ sValue = _rField.get_widget().get_text();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ return sValue;
+ }
+}
+
+OUString DbCurrencyField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& _rxFormatter, const Color** /*ppColor*/)
+{
+ return lcl_setFormattedCurrency_nothrow(dynamic_cast<FormattedControlBase&>(*m_pPainter), *this, _rxField, _rxFormatter);
+}
+
+void DbCurrencyField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& _rxFormatter)
+{
+ lcl_setFormattedCurrency_nothrow(dynamic_cast<FormattedControlBase&>(*m_pWindow), *this, _rxField, _rxFormatter);
+}
+
+void DbCurrencyField::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbCurrencyField::updateFromModel: invalid call!" );
+
+ FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+
+ double dValue = 0;
+ if ( _rxModel->getPropertyValue( FM_PROP_VALUE ) >>= dValue )
+ {
+ Formatter& rFormatter = pControl->get_formatter();
+ rFormatter.SetValue(dValue);
+ }
+ else
+ pControl->get_widget().set_text(OUString());
+}
+
+bool DbCurrencyField::commitControl()
+{
+ FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+ OUString aText(pControl->get_widget().get_text());
+ Any aVal;
+
+ if (!aText.isEmpty()) // not empty
+ {
+ Formatter& rFormatter = pControl->get_formatter();
+ double fValue = rFormatter.GetValue();
+ aVal <<= fValue;
+ }
+ m_rColumn.getModel()->setPropertyValue(FM_PROP_VALUE, aVal);
+ return true;
+}
+
+DbDateField::DbDateField( DbGridColumn& _rColumn )
+ :DbSpinField( _rColumn )
+{
+ doPropertyListening( FM_PROP_DATEFORMAT );
+ doPropertyListening( FM_PROP_DATEMIN );
+ doPropertyListening( FM_PROP_DATEMAX );
+ doPropertyListening( FM_PROP_STRICTFORMAT );
+ doPropertyListening( FM_PROP_DATE_SHOW_CENTURY );
+}
+
+VclPtr<svt::ControlBase> DbDateField::createField(BrowserDataWin* pParent, bool bSpinButton, const Reference< XPropertySet >& rxModel)
+{
+ // check if there is a DropDown property set to TRUE
+ bool bDropDown = !hasProperty( FM_PROP_DROPDOWN, rxModel )
+ || getBOOL( rxModel->getPropertyValue( FM_PROP_DROPDOWN ) );
+ // given the apparent inability to set a custom up/down action for a gtk
+ // spinbutton to have different up/down dates depending on the zone the
+ // mouse is in, show the dropdown calendar for both the spin or dropdown case
+ return VclPtr<DateControl>::Create(pParent, bSpinButton || bDropDown);
+}
+
+void DbDateField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& _rxModel )
+{
+ DBG_ASSERT( m_pWindow, "DbDateField::implAdjustGenericFieldSetting: not to be called without window!" );
+ DBG_ASSERT( _rxModel.is(), "DbDateField::implAdjustGenericFieldSetting: invalid model!" );
+ if ( !m_pWindow || !_rxModel.is() )
+ return;
+
+ sal_Int16 nFormat = getINT16( _rxModel->getPropertyValue( FM_PROP_DATEFORMAT ) );
+ util::Date aMin;
+ OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_DATEMIN ) >>= aMin );
+ util::Date aMax;
+ OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_DATEMAX ) >>= aMax );
+ bool bStrict = getBOOL( _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) );
+
+ FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+ weld::DateFormatter& rControlFormatter = static_cast<weld::DateFormatter&>(pControl->get_formatter());
+
+ FormattedControlBase* pPainter = static_cast<FormattedControlBase*>(m_pPainter.get());
+ weld::DateFormatter& rPainterFormatter = static_cast<weld::DateFormatter&>(pPainter->get_formatter());
+
+ Any aCentury = _rxModel->getPropertyValue( FM_PROP_DATE_SHOW_CENTURY );
+ if ( aCentury.getValueType().getTypeClass() != TypeClass_VOID )
+ {
+ bool bShowDateCentury = getBOOL( aCentury );
+
+ rControlFormatter.SetShowDateCentury(bShowDateCentury);
+ rPainterFormatter.SetShowDateCentury(bShowDateCentury);
+ }
+
+ rControlFormatter.SetExtDateFormat( static_cast<ExtDateFieldFormat>(nFormat) );
+ rControlFormatter.SetMin( aMin );
+ rControlFormatter.SetMax( aMax );
+ rControlFormatter.SetStrictFormat( bStrict );
+ rControlFormatter.EnableEmptyField( true );
+
+ rPainterFormatter.SetExtDateFormat( static_cast<ExtDateFieldFormat>(nFormat) );
+ rPainterFormatter.SetMin( aMin );
+ rPainterFormatter.SetMax( aMax );
+ rPainterFormatter.SetStrictFormat( bStrict );
+ rPainterFormatter.EnableEmptyField( true );
+}
+
+namespace
+{
+ OUString lcl_setFormattedDate_nothrow(DateControl& _rField, const Reference<XColumn>& _rxField)
+ {
+ OUString sDate;
+ if ( _rxField.is() )
+ {
+ try
+ {
+ css::util::Date aValue = _rxField->getDate();
+ if (!_rxField->wasNull())
+ {
+ _rField.SetDate(::Date(aValue.Day, aValue.Month, aValue.Year));
+ sDate = _rField.get_widget().get_text();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ return sDate;
+ }
+}
+
+OUString DbDateField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
+{
+ return lcl_setFormattedDate_nothrow(*static_cast<DateControl*>(m_pPainter.get()), _rxField);
+}
+
+void DbDateField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/)
+{
+ lcl_setFormattedDate_nothrow(*static_cast<DateControl*>(m_pWindow.get()), _rxField);
+}
+
+void DbDateField::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbDateField::updateFromModel: invalid call!" );
+
+ DateControl* pControl = static_cast<DateControl*>(m_pWindow.get());
+
+ util::Date aDate;
+ if ( _rxModel->getPropertyValue( FM_PROP_DATE ) >>= aDate )
+ pControl->SetDate(::Date(aDate));
+ else
+ pControl->get_widget().set_text(OUString());
+}
+
+bool DbDateField::commitControl()
+{
+ FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+ OUString aText(pControl->get_widget().get_text());
+ Any aVal;
+
+ if (!aText.isEmpty()) // not empty
+ {
+ weld::DateFormatter& rControlFormatter = static_cast<weld::DateFormatter&>(pControl->get_formatter());
+ aVal <<= rControlFormatter.GetDate().GetUNODate();
+ }
+
+ m_rColumn.getModel()->setPropertyValue(FM_PROP_DATE, aVal);
+ return true;
+}
+
+DbTimeField::DbTimeField( DbGridColumn& _rColumn )
+ :DbSpinField( _rColumn, css::awt::TextAlign::LEFT )
+{
+ doPropertyListening( FM_PROP_TIMEFORMAT );
+ doPropertyListening( FM_PROP_TIMEMIN );
+ doPropertyListening( FM_PROP_TIMEMAX );
+ doPropertyListening( FM_PROP_STRICTFORMAT );
+}
+
+VclPtr<svt::ControlBase> DbTimeField::createField(BrowserDataWin* pParent, bool bSpinButton, const Reference< XPropertySet >& /*rxModel*/ )
+{
+ return VclPtr<TimeControl>::Create(pParent, bSpinButton);
+}
+
+void DbTimeField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& _rxModel )
+{
+ DBG_ASSERT( m_pWindow, "DbTimeField::implAdjustGenericFieldSetting: not to be called without window!" );
+ DBG_ASSERT( _rxModel.is(), "DbTimeField::implAdjustGenericFieldSetting: invalid model!" );
+ if ( !m_pWindow || !_rxModel.is() )
+ return;
+
+ sal_Int16 nFormat = getINT16( _rxModel->getPropertyValue( FM_PROP_TIMEFORMAT ) );
+ util::Time aMin;
+ OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_TIMEMIN ) >>= aMin );
+ util::Time aMax;
+ OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_TIMEMAX ) >>= aMax );
+ bool bStrict = getBOOL( _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) );
+
+ FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+ weld::TimeFormatter& rControlFormatter = static_cast<weld::TimeFormatter&>(pControl->get_formatter());
+
+ rControlFormatter.SetExtFormat(static_cast<ExtTimeFieldFormat>(nFormat));
+ rControlFormatter.SetMin(aMin);
+ rControlFormatter.SetMax(aMax);
+ rControlFormatter.SetStrictFormat(bStrict);
+ rControlFormatter.EnableEmptyField(true);
+
+ FormattedControlBase* pPainter = static_cast<FormattedControlBase*>(m_pPainter.get());
+ weld::TimeFormatter& rPainterFormatter = static_cast<weld::TimeFormatter&>(pPainter->get_formatter());
+
+ rPainterFormatter.SetExtFormat(static_cast<ExtTimeFieldFormat>(nFormat));
+ rPainterFormatter.SetMin(aMin);
+ rPainterFormatter.SetMax(aMax);
+ rPainterFormatter.SetStrictFormat(bStrict);
+ rPainterFormatter.EnableEmptyField(true);
+}
+
+namespace
+{
+ OUString lcl_setFormattedTime_nothrow(TimeControl& _rField, const Reference<XColumn>& _rxField)
+ {
+ OUString sTime;
+ if ( _rxField.is() )
+ {
+ try
+ {
+ css::util::Time aValue = _rxField->getTime();
+ if (!_rxField->wasNull())
+ {
+ static_cast<weld::TimeFormatter&>(_rField.get_formatter()).SetTime( ::tools::Time( aValue ) );
+ sTime = _rField.get_widget().get_text();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ return sTime;
+ }
+}
+
+OUString DbTimeField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
+{
+ return lcl_setFormattedTime_nothrow(*static_cast<TimeControl*>(m_pPainter.get()), _rxField);
+}
+
+void DbTimeField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/)
+{
+ lcl_setFormattedTime_nothrow(*static_cast<TimeControl*>(m_pWindow.get()), _rxField);
+}
+
+void DbTimeField::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbTimeField::updateFromModel: invalid call!" );
+
+ FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+ weld::TimeFormatter& rControlFormatter = static_cast<weld::TimeFormatter&>(pControl->get_formatter());
+
+ util::Time aTime;
+ if ( _rxModel->getPropertyValue( FM_PROP_TIME ) >>= aTime )
+ rControlFormatter.SetTime(::tools::Time(aTime));
+ else
+ pControl->get_widget().set_text(OUString());
+}
+
+bool DbTimeField::commitControl()
+{
+ FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
+ OUString aText(pControl->get_widget().get_text());
+ Any aVal;
+
+ if (!aText.isEmpty()) // not empty
+ {
+ weld::TimeFormatter& rControlFormatter = static_cast<weld::TimeFormatter&>(pControl->get_formatter());
+ aVal <<= rControlFormatter.GetTime().GetUNOTime();
+ }
+
+ m_rColumn.getModel()->setPropertyValue(FM_PROP_TIME, aVal);
+ return true;
+}
+
+DbComboBox::DbComboBox(DbGridColumn& _rColumn)
+ :DbCellControl(_rColumn)
+{
+ setAlignedController( false );
+
+ doPropertyListening( FM_PROP_STRINGITEMLIST );
+ doPropertyListening( FM_PROP_LINECOUNT );
+}
+
+void DbComboBox::_propertyChanged( const PropertyChangeEvent& _rEvent )
+{
+ if ( _rEvent.PropertyName == FM_PROP_STRINGITEMLIST )
+ {
+ SetList(_rEvent.NewValue);
+ }
+ else
+ {
+ DbCellControl::_propertyChanged( _rEvent ) ;
+ }
+}
+
+void DbComboBox::SetList(const Any& rItems)
+{
+ ComboBoxControl* pField = static_cast<ComboBoxControl*>(m_pWindow.get());
+ weld::ComboBox& rComboBox = pField->get_widget();
+ rComboBox.clear();
+
+ css::uno::Sequence<OUString> aTest;
+ if (rItems >>= aTest)
+ {
+ for (const OUString& rString : std::as_const(aTest))
+ rComboBox.append_text(rString);
+
+ // tell the grid control that this controller is invalid and has to be re-initialized
+ invalidatedController();
+ }
+}
+
+void DbComboBox::implAdjustGenericFieldSetting(const Reference<XPropertySet>&)
+{
+ // we no longer pay attention to FM_PROP_LINECOUNT
+}
+
+void DbComboBox::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
+{
+ m_rColumn.SetAlignmentFromModel(css::awt::TextAlign::LEFT);
+
+ m_pWindow = VclPtr<ComboBoxControl>::Create( &rParent );
+
+ // selection from right to left
+ AllSettings aSettings = m_pWindow->GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ aStyleSettings.SetSelectionOptions(
+ aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst);
+ aSettings.SetStyleSettings(aStyleSettings);
+ m_pWindow->SetSettings(aSettings, true);
+
+ // some initial properties
+ Reference< XPropertySet > xModel(m_rColumn.getModel());
+ SetList( xModel->getPropertyValue( FM_PROP_STRINGITEMLIST ) );
+ implAdjustGenericFieldSetting( xModel );
+
+ DbCellControl::Init( rParent, xCursor );
+}
+
+CellControllerRef DbComboBox::CreateController() const
+{
+ return new ComboBoxCellController(static_cast<ComboBoxControl*>(m_pWindow.get()));
+}
+
+OUString DbComboBox::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter, const Color** /*ppColor*/)
+{
+ const css::uno::Reference<css::beans::XPropertySet> xPS(_rxField, UNO_QUERY);
+ ::dbtools::FormattedColumnValue fmter( xFormatter, xPS );
+
+ return fmter.getFormattedValue();
+}
+
+void DbComboBox::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter)
+{
+ ComboBoxControl* pControl = static_cast<ComboBoxControl*>(m_pWindow.get());
+ pControl->get_widget().set_entry_text(GetFormatText(_rxField, xFormatter));
+}
+
+void DbComboBox::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbComboBox::updateFromModel: invalid call!" );
+
+ OUString sText;
+ _rxModel->getPropertyValue( FM_PROP_TEXT ) >>= sText;
+
+ ComboBoxControl* pControl = static_cast<ComboBoxControl*>(m_pWindow.get());
+ weld::ComboBox& rComboBox = pControl->get_widget();
+
+ OUString sOldActive = rComboBox.get_active_text();
+ rComboBox.set_entry_text(sText);
+ rComboBox.select_entry_region(0, -1);
+
+ if (sOldActive != rComboBox.get_active_text())
+ pControl->TriggerAuxModify();
+}
+
+bool DbComboBox::commitControl()
+{
+ ComboBoxControl* pControl = static_cast<ComboBoxControl*>(m_pWindow.get());
+ weld::ComboBox& rComboBox = pControl->get_widget();
+ OUString aText(rComboBox.get_active_text());
+ m_rColumn.getModel()->setPropertyValue(FM_PROP_TEXT, Any(aText));
+ return true;
+}
+
+
+DbListBox::DbListBox(DbGridColumn& _rColumn)
+ :DbCellControl(_rColumn)
+ ,m_bBound(false)
+{
+ setAlignedController( false );
+
+ doPropertyListening( FM_PROP_STRINGITEMLIST );
+ doPropertyListening( FM_PROP_LINECOUNT );
+}
+
+void DbListBox::_propertyChanged( const css::beans::PropertyChangeEvent& _rEvent )
+{
+ if ( _rEvent.PropertyName == FM_PROP_STRINGITEMLIST )
+ {
+ SetList(_rEvent.NewValue);
+ }
+ else
+ {
+ DbCellControl::_propertyChanged( _rEvent ) ;
+ }
+}
+
+void DbListBox::SetList(const Any& rItems)
+{
+ ListBoxControl* pField = static_cast<ListBoxControl*>(m_pWindow.get());
+
+ weld::ComboBox& rFieldList = pField->get_widget();
+
+ rFieldList.clear();
+ m_bBound = false;
+
+ css::uno::Sequence<OUString> aTest;
+ if (!(rItems >>= aTest))
+ return;
+
+ if (aTest.hasElements())
+ {
+ for (const OUString& rString : std::as_const(aTest))
+ rFieldList.append_text(rString);
+
+ m_rColumn.getModel()->getPropertyValue(FM_PROP_VALUE_SEQ) >>= m_aValueList;
+ m_bBound = m_aValueList.hasElements();
+
+ // tell the grid control that this controller is invalid and has to be re-initialized
+ invalidatedController();
+ }
+}
+
+void DbListBox::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
+{
+ m_rColumn.SetAlignment(css::awt::TextAlign::LEFT);
+
+ m_pWindow = VclPtr<ListBoxControl>::Create( &rParent );
+
+ // some initial properties
+ Reference< XPropertySet > xModel( m_rColumn.getModel() );
+ SetList( xModel->getPropertyValue( FM_PROP_STRINGITEMLIST ) );
+ implAdjustGenericFieldSetting( xModel );
+
+ DbCellControl::Init( rParent, xCursor );
+}
+
+void DbListBox::implAdjustGenericFieldSetting( const Reference< XPropertySet >& /*rxModel*/ )
+{
+ // ignore FM_PROP_LINECOUNT
+}
+
+CellControllerRef DbListBox::CreateController() const
+{
+ return new ListBoxCellController(static_cast<ListBoxControl*>(m_pWindow.get()));
+}
+
+OUString DbListBox::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
+{
+ OUString sText;
+ if ( _rxField.is() )
+ {
+ try
+ {
+ sText = _rxField->getString();
+ if ( m_bBound )
+ {
+ sal_Int32 nPos = ::comphelper::findValue( m_aValueList, sText );
+ if ( nPos != -1 )
+ sText = static_cast<svt::ListBoxControl*>(m_pWindow.get())->get_widget().get_text(nPos);
+ else
+ sText.clear();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ return sText;
+}
+
+void DbListBox::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter)
+{
+ OUString sFormattedText( GetFormatText( _rxField, xFormatter ) );
+ weld::ComboBox& rComboBox = static_cast<ListBoxControl*>(m_pWindow.get())->get_widget();
+ if (!sFormattedText.isEmpty())
+ rComboBox.set_active_text(sFormattedText);
+ else
+ rComboBox.set_active(-1);
+}
+
+void DbListBox::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbListBox::updateFromModel: invalid call!" );
+
+ Sequence< sal_Int16 > aSelection;
+ _rxModel->getPropertyValue( FM_PROP_SELECT_SEQ ) >>= aSelection;
+
+ sal_Int16 nSelection = -1;
+ if ( aSelection.hasElements() )
+ nSelection = aSelection[ 0 ];
+
+ ListBoxControl* pControl = static_cast<ListBoxControl*>(m_pWindow.get());
+ weld::ComboBox& rComboBox = pControl->get_widget();
+
+ int nOldActive = rComboBox.get_active();
+ if (nSelection >= 0 && nSelection < rComboBox.get_count())
+ rComboBox.set_active(nSelection);
+ else
+ rComboBox.set_active(-1);
+
+ if (nOldActive != rComboBox.get_active())
+ pControl->TriggerAuxModify();
+}
+
+bool DbListBox::commitControl()
+{
+ Any aVal;
+ Sequence<sal_Int16> aSelectSeq;
+ weld::ComboBox& rComboBox = static_cast<ListBoxControl*>(m_pWindow.get())->get_widget();
+ auto nActive = rComboBox.get_active();
+ if (nActive != -1)
+ {
+ aSelectSeq.realloc(1);
+ *aSelectSeq.getArray() = static_cast<sal_Int16>(nActive);
+ }
+ aVal <<= aSelectSeq;
+ m_rColumn.getModel()->setPropertyValue(FM_PROP_SELECT_SEQ, aVal);
+ return true;
+}
+
+DbFilterField::DbFilterField(const Reference< XComponentContext >& rxContext,DbGridColumn& _rColumn)
+ :DbCellControl(_rColumn)
+ ,OSQLParserClient(rxContext)
+ ,m_nControlClass(css::form::FormComponentType::TEXTFIELD)
+ ,m_bFilterList(false)
+ ,m_bFilterListFilled(false)
+{
+
+ setAlignedController( false );
+}
+
+DbFilterField::~DbFilterField()
+{
+ if (m_nControlClass == css::form::FormComponentType::CHECKBOX)
+ static_cast<CheckBoxControl*>(m_pWindow.get())->SetToggleHdl(Link<weld::CheckButton&,void>());
+
+}
+
+void DbFilterField::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect)
+{
+ static const DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::VCenter | DrawTextFlags::Left;
+ switch (m_nControlClass)
+ {
+ case FormComponentType::CHECKBOX:
+ {
+ // center the checkbox within the space available
+ CheckBoxControl* pControl = static_cast<CheckBoxControl*>(m_pPainter.get());
+ Size aBoxSize = pControl->GetBox().get_preferred_size();
+ tools::Rectangle aRect(Point(rRect.Left() + ((rRect.GetWidth() - aBoxSize.Width()) / 2),
+ rRect.Top() + ((rRect.GetHeight() - aBoxSize.Height()) / 2)),
+ aBoxSize);
+
+ DbCellControl::PaintCell(rDev, aRect);
+ break;
+ }
+ case FormComponentType::LISTBOX:
+ rDev.DrawText(rRect, static_cast<ListBoxControl*>(m_pWindow.get())->get_widget().get_active_text(), nStyle);
+ break;
+ default:
+ rDev.DrawText(rRect, m_aText, nStyle);
+ }
+}
+
+void DbFilterField::SetList(const Any& rItems, bool bComboBox)
+{
+ css::uno::Sequence<OUString> aTest;
+ rItems >>= aTest;
+ if (!aTest.hasElements())
+ return;
+
+ if (bComboBox)
+ {
+ ComboBoxControl* pField = static_cast<ComboBoxControl*>(m_pWindow.get());
+ weld::ComboBox& rComboBox = pField->get_widget();
+ for (const OUString& rString : std::as_const(aTest))
+ rComboBox.append_text(rString);
+ }
+ else
+ {
+ ListBoxControl* pField = static_cast<ListBoxControl*>(m_pWindow.get());
+ weld::ComboBox& rFieldBox = pField->get_widget();
+ for (const OUString& rString : std::as_const(aTest))
+ rFieldBox.append_text(rString);
+
+ m_rColumn.getModel()->getPropertyValue(FM_PROP_VALUE_SEQ) >>= m_aValueList;
+ }
+}
+
+void DbFilterField::CreateControl(BrowserDataWin* pParent, const Reference< css::beans::XPropertySet >& xModel)
+{
+ switch (m_nControlClass)
+ {
+ case css::form::FormComponentType::CHECKBOX:
+ m_pWindow = VclPtr<CheckBoxControl>::Create(pParent);
+ m_pWindow->SetPaintTransparent( true );
+ static_cast<CheckBoxControl*>(m_pWindow.get())->SetToggleHdl(LINK(this, DbFilterField, OnToggle));
+
+ m_pPainter = VclPtr<CheckBoxControl>::Create(pParent);
+ m_pPainter->SetPaintTransparent( true );
+ m_pPainter->SetBackground();
+ break;
+ case css::form::FormComponentType::LISTBOX:
+ {
+ m_pWindow = VclPtr<ListBoxControl>::Create(pParent);
+ Any aItems = xModel->getPropertyValue(FM_PROP_STRINGITEMLIST);
+ SetList(aItems, false);
+ } break;
+ case css::form::FormComponentType::COMBOBOX:
+ {
+ m_pWindow = VclPtr<ComboBoxControl>::Create(pParent);
+
+ AllSettings aSettings = m_pWindow->GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ aStyleSettings.SetSelectionOptions(
+ aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst);
+ aSettings.SetStyleSettings(aStyleSettings);
+ m_pWindow->SetSettings(aSettings, true);
+
+ if (!m_bFilterList)
+ {
+ Any aItems = xModel->getPropertyValue(FM_PROP_STRINGITEMLIST);
+ SetList(aItems, true);
+ }
+
+ } break;
+ default:
+ {
+ m_pWindow = VclPtr<EditControl>::Create(pParent);
+ AllSettings aSettings = m_pWindow->GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ aStyleSettings.SetSelectionOptions(
+ aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst);
+ aSettings.SetStyleSettings(aStyleSettings);
+ m_pWindow->SetSettings(aSettings, true);
+ }
+ }
+}
+
+void DbFilterField::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
+{
+ Reference< css::beans::XPropertySet > xModel(m_rColumn.getModel());
+ m_rColumn.SetAlignment(css::awt::TextAlign::LEFT);
+
+ if (xModel.is())
+ {
+ m_bFilterList = ::comphelper::hasProperty(FM_PROP_FILTERPROPOSAL, xModel) && ::comphelper::getBOOL(xModel->getPropertyValue(FM_PROP_FILTERPROPOSAL));
+ if (m_bFilterList)
+ m_nControlClass = css::form::FormComponentType::COMBOBOX;
+ else
+ {
+ sal_Int16 nClassId = ::comphelper::getINT16(xModel->getPropertyValue(FM_PROP_CLASSID));
+ switch (nClassId)
+ {
+ case FormComponentType::CHECKBOX:
+ case FormComponentType::LISTBOX:
+ case FormComponentType::COMBOBOX:
+ m_nControlClass = nClassId;
+ break;
+ default:
+ if (m_bFilterList)
+ m_nControlClass = FormComponentType::COMBOBOX;
+ else
+ m_nControlClass = FormComponentType::TEXTFIELD;
+ }
+ }
+ }
+
+ CreateControl( &rParent, xModel );
+ DbCellControl::Init( rParent, xCursor );
+
+ // filter cells are never readonly
+ m_pWindow->SetEditableReadOnly(false);
+}
+
+CellControllerRef DbFilterField::CreateController() const
+{
+ CellControllerRef xController;
+ switch (m_nControlClass)
+ {
+ case css::form::FormComponentType::CHECKBOX:
+ xController = new CheckBoxCellController(static_cast<CheckBoxControl*>(m_pWindow.get()));
+ break;
+ case css::form::FormComponentType::LISTBOX:
+ xController = new ListBoxCellController(static_cast<ListBoxControl*>(m_pWindow.get()));
+ break;
+ case css::form::FormComponentType::COMBOBOX:
+ xController = new ComboBoxCellController(static_cast<ComboBoxControl*>(m_pWindow.get()));
+ break;
+ default:
+ if (m_bFilterList)
+ xController = new ComboBoxCellController(static_cast<ComboBoxControl*>(m_pWindow.get()));
+ else
+ xController = new EditCellController(static_cast<EditControlBase*>(m_pWindow.get()));
+ }
+ return xController;
+}
+
+void DbFilterField::updateFromModel( Reference< XPropertySet > _rxModel )
+{
+ OSL_ENSURE( _rxModel.is() && m_pWindow, "DbFilterField::updateFromModel: invalid call!" );
+
+ OSL_FAIL( "DbFilterField::updateFromModel: not implemented yet (how the hell did you reach this?)!" );
+ // TODO: implement this.
+ // remember: updateFromModel should be some kind of opposite of commitControl
+}
+
+bool DbFilterField::commitControl()
+{
+ OUString aText(m_aText);
+ switch (m_nControlClass)
+ {
+ case css::form::FormComponentType::CHECKBOX:
+ return true;
+ case css::form::FormComponentType::LISTBOX:
+ {
+ aText.clear();
+ weld::ComboBox& rComboBox = static_cast<svt::ListBoxControl*>(m_pWindow.get())->get_widget();
+ auto nActive = rComboBox.get_active();
+ if (nActive != -1)
+ {
+ sal_Int16 nPos = static_cast<sal_Int16>(nActive);
+ if ( ( nPos >= 0 ) && ( nPos < m_aValueList.getLength() ) )
+ aText = m_aValueList.getConstArray()[nPos];
+ }
+
+ if (m_aText != aText)
+ {
+ m_aText = aText;
+ m_aCommitLink.Call(*this);
+ }
+ return true;
+ }
+ case css::form::FormComponentType::COMBOBOX:
+ {
+ aText = static_cast<ComboBoxControl*>(m_pWindow.get())->get_widget().get_active_text();
+ break;
+ }
+ default:
+ {
+ aText = static_cast<EditControlBase*>(m_pWindow.get())->get_widget().get_text();
+ break;
+ }
+ }
+
+ if (m_aText != aText)
+ {
+ // check the text with the SQL-Parser
+ OUString aNewText(comphelper::string::stripEnd(aText, ' '));
+ if (!aNewText.isEmpty())
+ {
+ OUString aErrorMsg;
+ Reference< XNumberFormatter > xNumberFormatter(m_rColumn.GetParent().getNumberFormatter());
+
+ std::unique_ptr< OSQLParseNode > pParseNode = predicateTree(aErrorMsg, aNewText,xNumberFormatter, m_rColumn.GetField());
+ if (pParseNode != nullptr)
+ {
+ OUString aPreparedText;
+
+ css::lang::Locale aAppLocale = Application::GetSettings().GetUILanguageTag().getLocale();
+
+ Reference< XRowSet > xDataSourceRowSet(
+ Reference< XInterface >(*m_rColumn.GetParent().getDataSource()), UNO_QUERY);
+ Reference< XConnection > xConnection(getConnection(xDataSourceRowSet));
+
+ pParseNode->parseNodeToPredicateStr(aPreparedText,
+ xConnection,
+ xNumberFormatter,
+ m_rColumn.GetField(),
+ OUString(),
+ aAppLocale,
+ OUString("."),
+ getParseContext());
+ m_aText = aPreparedText;
+ }
+ else
+ {
+
+ SQLException aError;
+ aError.Message = aErrorMsg;
+ displayException(aError, VCLUnoHelper::GetInterface(m_pWindow->GetParent()));
+ // TODO: transport the title
+
+ return false;
+ }
+ }
+ else
+ m_aText = aText;
+
+ m_pWindow->SetText(m_aText);
+ m_aCommitLink.Call(*this);
+ }
+ return true;
+}
+
+
+void DbFilterField::SetText(const OUString& rText)
+{
+ m_aText = rText;
+ switch (m_nControlClass)
+ {
+ case css::form::FormComponentType::CHECKBOX:
+ {
+ TriState eState;
+ if (rText == "1")
+ eState = TRISTATE_TRUE;
+ else if (rText == "0")
+ eState = TRISTATE_FALSE;
+ else
+ eState = TRISTATE_INDET;
+
+ static_cast<CheckBoxControl*>(m_pWindow.get())->SetState(eState);
+ static_cast<CheckBoxControl*>(m_pPainter.get())->SetState(eState);
+ } break;
+ case css::form::FormComponentType::LISTBOX:
+ {
+ sal_Int32 nPos = ::comphelper::findValue(m_aValueList, m_aText);
+ static_cast<ListBoxControl*>(m_pWindow.get())->get_widget().set_active(nPos);
+ } break;
+ case css::form::FormComponentType::COMBOBOX:
+ {
+ static_cast<ComboBoxControl*>(m_pWindow.get())->get_widget().set_entry_text(m_aText);
+ break;
+ }
+ default:
+ {
+ static_cast<EditControlBase*>(m_pWindow.get())->get_widget().set_text(m_aText);
+ break;
+ }
+ }
+
+ // now force a repaint on the window
+ m_rColumn.GetParent().RowModified(0);
+}
+
+
+void DbFilterField::Update()
+{
+ // should we fill the combobox with a filter proposal?
+ if (!m_bFilterList || m_bFilterListFilled)
+ return;
+
+ m_bFilterListFilled = true;
+ Reference< css::beans::XPropertySet > xField = m_rColumn.GetField();
+ if (!xField.is())
+ return;
+
+ OUString aName;
+ xField->getPropertyValue(FM_PROP_NAME) >>= aName;
+
+ // the columnmodel
+ Reference< css::container::XChild > xModelAsChild(m_rColumn.getModel(), UNO_QUERY);
+ // the grid model
+ xModelAsChild.set(xModelAsChild->getParent(),UNO_QUERY);
+ Reference< XRowSet > xForm(xModelAsChild->getParent(), UNO_QUERY);
+ if (!xForm.is())
+ return;
+
+ Reference<XPropertySet> xFormProp(xForm,UNO_QUERY);
+ Reference< XTablesSupplier > xSupTab;
+ xFormProp->getPropertyValue("SingleSelectQueryComposer") >>= xSupTab;
+
+ Reference< XConnection > xConnection(getConnection(xForm));
+ if (!xSupTab.is())
+ return;
+
+ // search the field
+ Reference< XColumnsSupplier > xSupCol(xSupTab,UNO_QUERY);
+ Reference< css::container::XNameAccess > xFieldNames = xSupCol->getColumns();
+ if (!xFieldNames->hasByName(aName))
+ return;
+
+ Reference< css::container::XNameAccess > xTablesNames = xSupTab->getTables();
+ Reference< css::beans::XPropertySet > xComposerFieldAsSet(xFieldNames->getByName(aName),UNO_QUERY);
+
+ if (!xComposerFieldAsSet.is() ||
+ !::comphelper::hasProperty(FM_PROP_TABLENAME, xComposerFieldAsSet) ||
+ !::comphelper::hasProperty(FM_PROP_FIELDSOURCE, xComposerFieldAsSet))
+ return;
+
+ OUString aFieldName;
+ OUString aTableName;
+ xComposerFieldAsSet->getPropertyValue(FM_PROP_FIELDSOURCE) >>= aFieldName;
+ xComposerFieldAsSet->getPropertyValue(FM_PROP_TABLENAME) >>= aTableName;
+
+ // no possibility to create a select statement
+ // looking for the complete table name
+ if (!xTablesNames->hasByName(aTableName))
+ return;
+
+ // build a statement and send as query;
+ // Access to the connection
+ Reference< XStatement > xStatement;
+ Reference< XResultSet > xListCursor;
+ Reference< css::sdb::XColumn > xDataField;
+
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta = xConnection->getMetaData();
+
+ OUString aQuote(xMeta->getIdentifierQuoteString());
+ OUStringBuffer aStatement("SELECT DISTINCT ");
+ aStatement.append(quoteName(aQuote, aName));
+ if (!aFieldName.isEmpty() && aName != aFieldName)
+ {
+ aStatement.append(" AS ");
+ aStatement.append(quoteName(aQuote, aFieldName));
+ }
+
+ aStatement.append(" FROM ");
+
+ Reference< XPropertySet > xTableNameAccess(xTablesNames->getByName(aTableName), UNO_QUERY_THROW);
+ aStatement.append(composeTableNameForSelect(xConnection, xTableNameAccess));
+
+ xStatement = xConnection->createStatement();
+ Reference< css::beans::XPropertySet > xStatementProps(xStatement, UNO_QUERY);
+ xStatementProps->setPropertyValue(FM_PROP_ESCAPE_PROCESSING, Any(true));
+
+ xListCursor = xStatement->executeQuery(aStatement.makeStringAndClear());
+
+ Reference< css::sdbcx::XColumnsSupplier > xSupplyCols(xListCursor, UNO_QUERY);
+ Reference< css::container::XIndexAccess > xFields(xSupplyCols->getColumns(), UNO_QUERY);
+ xDataField.set(xFields->getByIndex(0), css::uno::UNO_QUERY);
+ if (!xDataField.is())
+ return;
+ }
+ catch(const Exception&)
+ {
+ ::comphelper::disposeComponent(xStatement);
+ return;
+ }
+
+ sal_Int16 i = 0;
+ ::std::vector< OUString > aStringList;
+ aStringList.reserve(16);
+ OUString aStr;
+ css::util::Date aNullDate = m_rColumn.GetParent().getNullDate();
+ sal_Int32 nFormatKey = m_rColumn.GetKey();
+ Reference< XNumberFormatter > xFormatter = m_rColumn.GetParent().getNumberFormatter();
+ sal_Int16 nKeyType = ::comphelper::getNumberFormatType(xFormatter->getNumberFormatsSupplier()->getNumberFormats(), nFormatKey);
+
+ while (!xListCursor->isAfterLast() && i++ < SHRT_MAX) // max number of entries
+ {
+ aStr = getFormattedValue(xDataField, xFormatter, aNullDate, nFormatKey, nKeyType);
+ aStringList.push_back(aStr);
+ (void)xListCursor->next();
+ }
+
+ ComboBoxControl* pField = static_cast<ComboBoxControl*>(m_pWindow.get());
+ weld::ComboBox& rComboBox = pField->get_widget();
+ // filling the entries for the combobox
+ for (const auto& rString : aStringList)
+ rComboBox.append_text(rString);
+}
+
+OUString DbFilterField::GetFormatText(const Reference< XColumn >& /*_rxField*/, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
+{
+ return OUString();
+}
+
+void DbFilterField::UpdateFromField(const Reference< XColumn >& /*_rxField*/, const Reference< XNumberFormatter >& /*xFormatter*/)
+{
+ OSL_FAIL( "DbFilterField::UpdateFromField: cannot update a filter control from a field!" );
+}
+
+IMPL_LINK_NOARG(DbFilterField, OnToggle, weld::CheckButton&, void)
+{
+ TriState eState = static_cast<CheckBoxControl*>(m_pWindow.get())->GetState();
+ OUStringBuffer aTextBuf;
+
+ Reference< XRowSet > xDataSourceRowSet(
+ Reference< XInterface >(*m_rColumn.GetParent().getDataSource()), UNO_QUERY);
+ Reference< XConnection > xConnection(getConnection(xDataSourceRowSet));
+ const sal_Int32 nBooleanComparisonMode = ::dbtools::DatabaseMetaData( xConnection ).getBooleanComparisonMode();
+
+ switch (eState)
+ {
+ case TRISTATE_TRUE:
+ ::dbtools::getBooleanComparisonPredicate(u"", true, nBooleanComparisonMode, aTextBuf);
+ break;
+ case TRISTATE_FALSE:
+ ::dbtools::getBooleanComparisonPredicate(u"", false, nBooleanComparisonMode, aTextBuf);
+ break;
+ case TRISTATE_INDET:
+ break;
+ }
+
+ const OUString aText(aTextBuf.makeStringAndClear());
+
+ if (m_aText != aText)
+ {
+ m_aText = aText;
+ m_aCommitLink.Call(*this);
+ }
+}
+
+FmXGridCell::FmXGridCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> _pControl )
+ :OComponentHelper(m_aMutex)
+ ,m_pColumn(pColumn)
+ ,m_pCellControl( std::move(_pControl) )
+ ,m_aWindowListeners( m_aMutex )
+ ,m_aFocusListeners( m_aMutex )
+ ,m_aKeyListeners( m_aMutex )
+ ,m_aMouseListeners( m_aMutex )
+ ,m_aMouseMotionListeners( m_aMutex )
+{
+}
+
+void FmXGridCell::init()
+{
+ svt::ControlBase* pEventWindow( getEventWindow() );
+ if ( pEventWindow )
+ {
+ pEventWindow->SetFocusInHdl(LINK( this, FmXGridCell, OnFocusGained));
+ pEventWindow->SetFocusOutHdl(LINK( this, FmXGridCell, OnFocusLost));
+ pEventWindow->SetMousePressHdl(LINK( this, FmXGridCell, OnMousePress));
+ pEventWindow->SetMouseReleaseHdl(LINK( this, FmXGridCell, OnMouseRelease));
+ pEventWindow->SetMouseMoveHdl(LINK( this, FmXGridCell, OnMouseMove));
+ pEventWindow->SetKeyInputHdl( LINK( this, FmXGridCell, OnKeyInput) );
+ pEventWindow->SetKeyReleaseHdl( LINK( this, FmXGridCell, OnKeyRelease) );
+ }
+}
+
+svt::ControlBase* FmXGridCell::getEventWindow() const
+{
+ if ( m_pCellControl )
+ return &m_pCellControl->GetWindow();
+ return nullptr;
+}
+
+FmXGridCell::~FmXGridCell()
+{
+ if (!OComponentHelper::rBHelper.bDisposed)
+ {
+ acquire();
+ dispose();
+ }
+
+}
+
+void FmXGridCell::SetTextLineColor()
+{
+ if (m_pCellControl)
+ m_pCellControl->SetTextLineColor();
+}
+
+void FmXGridCell::SetTextLineColor(const Color& _rColor)
+{
+ if (m_pCellControl)
+ m_pCellControl->SetTextLineColor(_rColor);
+}
+
+// XTypeProvider
+
+Sequence< Type > SAL_CALL FmXGridCell::getTypes( )
+{
+ Sequence< uno::Type > aTypes = ::comphelper::concatSequences(
+ ::cppu::OComponentHelper::getTypes(),
+ FmXGridCell_Base::getTypes()
+ );
+ if ( m_pCellControl )
+ aTypes = ::comphelper::concatSequences(
+ aTypes,
+ FmXGridCell_WindowBase::getTypes()
+ );
+ return aTypes;
+}
+
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( FmXGridCell )
+
+// OComponentHelper
+
+void FmXGridCell::disposing()
+{
+ lang::EventObject aEvent( *this );
+ m_aWindowListeners.disposeAndClear( aEvent );
+ m_aFocusListeners.disposeAndClear( aEvent );
+ m_aKeyListeners.disposeAndClear( aEvent );
+ m_aMouseListeners.disposeAndClear( aEvent );
+ m_aMouseMotionListeners.disposeAndClear( aEvent );
+
+ OComponentHelper::disposing();
+ m_pColumn = nullptr;
+ m_pCellControl.reset();
+}
+
+
+Any SAL_CALL FmXGridCell::queryAggregation( const css::uno::Type& _rType )
+{
+ Any aReturn = OComponentHelper::queryAggregation( _rType );
+
+ if ( !aReturn.hasValue() )
+ aReturn = FmXGridCell_Base::queryInterface( _rType );
+
+ if ( !aReturn.hasValue() && ( m_pCellControl != nullptr ) )
+ aReturn = FmXGridCell_WindowBase::queryInterface( _rType );
+
+ return aReturn;
+}
+
+// css::awt::XControl
+
+Reference< XInterface > FmXGridCell::getContext()
+{
+ return Reference< XInterface > ();
+}
+
+
+Reference< css::awt::XControlModel > FmXGridCell::getModel()
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< css::awt::XControlModel > (m_pColumn->getModel(), UNO_QUERY);
+}
+
+// css::form::XBoundControl
+
+sal_Bool FmXGridCell::getLock()
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return m_pColumn->isLocked();
+}
+
+
+void FmXGridCell::setLock(sal_Bool _bLock)
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ if (getLock() == _bLock)
+ return;
+ else
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_pColumn->setLock(_bLock);
+ }
+}
+
+
+void SAL_CALL FmXGridCell::setPosSize( ::sal_Int32, ::sal_Int32, ::sal_Int32, ::sal_Int32, ::sal_Int16 )
+{
+ OSL_FAIL( "FmXGridCell::setPosSize: not implemented" );
+ // not allowed to tamper with this for a grid cell
+}
+
+
+awt::Rectangle SAL_CALL FmXGridCell::getPosSize( )
+{
+ OSL_FAIL( "FmXGridCell::getPosSize: not implemented" );
+ return awt::Rectangle();
+}
+
+
+void SAL_CALL FmXGridCell::setVisible( sal_Bool )
+{
+ OSL_FAIL( "FmXGridCell::setVisible: not implemented" );
+ // not allowed to tamper with this for a grid cell
+}
+
+
+void SAL_CALL FmXGridCell::setEnable( sal_Bool )
+{
+ OSL_FAIL( "FmXGridCell::setEnable: not implemented" );
+ // not allowed to tamper with this for a grid cell
+}
+
+
+void SAL_CALL FmXGridCell::setFocus( )
+{
+ OSL_FAIL( "FmXGridCell::setFocus: not implemented" );
+ // not allowed to tamper with this for a grid cell
+}
+
+
+void SAL_CALL FmXGridCell::addWindowListener( const Reference< awt::XWindowListener >& _rxListener )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aWindowListeners.addInterface( _rxListener );
+}
+
+
+void SAL_CALL FmXGridCell::removeWindowListener( const Reference< awt::XWindowListener >& _rxListener )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aWindowListeners.removeInterface( _rxListener );
+}
+
+
+void SAL_CALL FmXGridCell::addFocusListener( const Reference< awt::XFocusListener >& _rxListener )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aFocusListeners.addInterface( _rxListener );
+}
+
+
+void SAL_CALL FmXGridCell::removeFocusListener( const Reference< awt::XFocusListener >& _rxListener )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aFocusListeners.removeInterface( _rxListener );
+}
+
+
+void SAL_CALL FmXGridCell::addKeyListener( const Reference< awt::XKeyListener >& _rxListener )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aKeyListeners.addInterface( _rxListener );
+}
+
+
+void SAL_CALL FmXGridCell::removeKeyListener( const Reference< awt::XKeyListener >& _rxListener )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aKeyListeners.removeInterface( _rxListener );
+}
+
+
+void SAL_CALL FmXGridCell::addMouseListener( const Reference< awt::XMouseListener >& _rxListener )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aMouseListeners.addInterface( _rxListener );
+}
+
+
+void SAL_CALL FmXGridCell::removeMouseListener( const Reference< awt::XMouseListener >& _rxListener )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aMouseListeners.removeInterface( _rxListener );
+}
+
+
+void SAL_CALL FmXGridCell::addMouseMotionListener( const Reference< awt::XMouseMotionListener >& _rxListener )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aMouseMotionListeners.addInterface( _rxListener );
+}
+
+
+void SAL_CALL FmXGridCell::removeMouseMotionListener( const Reference< awt::XMouseMotionListener >& _rxListener )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aMouseMotionListeners.removeInterface( _rxListener );
+}
+
+void SAL_CALL FmXGridCell::addPaintListener( const Reference< awt::XPaintListener >& )
+{
+ OSL_FAIL( "FmXGridCell::addPaintListener: not implemented" );
+}
+
+void SAL_CALL FmXGridCell::removePaintListener( const Reference< awt::XPaintListener >& )
+{
+ OSL_FAIL( "FmXGridCell::removePaintListener: not implemented" );
+}
+
+void FmXGridCell::onFocusGained( const awt::FocusEvent& _rEvent )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aFocusListeners.notifyEach( &awt::XFocusListener::focusGained, _rEvent );
+}
+
+void FmXGridCell::onFocusLost( const awt::FocusEvent& _rEvent )
+{
+ checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ m_aFocusListeners.notifyEach( &awt::XFocusListener::focusLost, _rEvent );
+}
+
+IMPL_LINK_NOARG(FmXGridCell, OnFocusGained, LinkParamNone*, void)
+{
+ if (!m_aFocusListeners.getLength())
+ return;
+
+ awt::FocusEvent aEvent;
+ aEvent.Source = *this;
+ aEvent.Temporary = false;
+
+ onFocusGained(aEvent);
+}
+
+IMPL_LINK_NOARG(FmXGridCell, OnFocusLost, LinkParamNone*, void)
+{
+ if (!m_aFocusListeners.getLength())
+ return;
+
+ awt::FocusEvent aEvent;
+ aEvent.Source = *this;
+ aEvent.Temporary = false;
+
+ onFocusLost(aEvent);
+}
+
+IMPL_LINK(FmXGridCell, OnMousePress, const MouseEvent&, rEventData, void)
+{
+ if (!m_aMouseListeners.getLength())
+ return;
+
+ awt::MouseEvent aEvent(VCLUnoHelper::createMouseEvent(rEventData, *this));
+ m_aMouseListeners.notifyEach(&awt::XMouseListener::mousePressed, aEvent);
+}
+
+IMPL_LINK(FmXGridCell, OnMouseRelease, const MouseEvent&, rEventData, void)
+{
+ if (!m_aMouseListeners.getLength())
+ return;
+
+ awt::MouseEvent aEvent(VCLUnoHelper::createMouseEvent(rEventData, *this));
+ m_aMouseListeners.notifyEach(&awt::XMouseListener::mouseReleased, aEvent);
+}
+
+IMPL_LINK(FmXGridCell, OnMouseMove, const MouseEvent&, rMouseEvent, void)
+{
+ if ( rMouseEvent.IsEnterWindow() || rMouseEvent.IsLeaveWindow() )
+ {
+ if ( m_aMouseListeners.getLength() != 0 )
+ {
+ awt::MouseEvent aEvent( VCLUnoHelper::createMouseEvent( rMouseEvent, *this ) );
+ m_aMouseListeners.notifyEach( rMouseEvent.IsEnterWindow() ? &awt::XMouseListener::mouseEntered: &awt::XMouseListener::mouseExited, aEvent );
+ }
+ }
+ else if ( !rMouseEvent.IsEnterWindow() && !rMouseEvent.IsLeaveWindow() )
+ {
+ if ( m_aMouseMotionListeners.getLength() != 0 )
+ {
+ awt::MouseEvent aEvent( VCLUnoHelper::createMouseEvent( rMouseEvent, *this ) );
+ aEvent.ClickCount = 0;
+ const bool bSimpleMove = bool( rMouseEvent.GetMode() & MouseEventModifiers::SIMPLEMOVE );
+ m_aMouseMotionListeners.notifyEach( bSimpleMove ? &awt::XMouseMotionListener::mouseMoved: &awt::XMouseMotionListener::mouseDragged, aEvent );
+ }
+ }
+}
+
+IMPL_LINK(FmXGridCell, OnKeyInput, const KeyEvent&, rEventData, void)
+{
+ if (!m_aKeyListeners.getLength())
+ return;
+
+ awt::KeyEvent aEvent(VCLUnoHelper::createKeyEvent(rEventData, *this));
+ m_aKeyListeners.notifyEach(&awt::XKeyListener::keyPressed, aEvent);
+}
+
+IMPL_LINK(FmXGridCell, OnKeyRelease, const KeyEvent&, rEventData, void)
+{
+ if (!m_aKeyListeners.getLength())
+ return;
+
+ awt::KeyEvent aEvent(VCLUnoHelper::createKeyEvent(rEventData, *this));
+ m_aKeyListeners.notifyEach(&awt::XKeyListener::keyReleased, aEvent);
+}
+
+void FmXDataCell::PaintFieldToCell(OutputDevice& rDev, const tools::Rectangle& rRect,
+ const Reference< css::sdb::XColumn >& _rxField,
+ const Reference< XNumberFormatter >& xFormatter)
+{
+ m_pCellControl->PaintFieldToCell( rDev, rRect, _rxField, xFormatter );
+}
+
+void FmXDataCell::UpdateFromColumn()
+{
+ Reference< css::sdb::XColumn > xField(m_pColumn->GetCurrentFieldValue());
+ if (xField.is())
+ m_pCellControl->UpdateFromField(xField, m_pColumn->GetParent().getNumberFormatter());
+}
+
+FmXTextCell::FmXTextCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl )
+ :FmXDataCell( pColumn, std::move(pControl) )
+ ,m_bIsMultiLineText(false)
+{
+}
+
+void FmXTextCell::PaintFieldToCell(OutputDevice& rDev,
+ const tools::Rectangle& rRect,
+ const Reference< css::sdb::XColumn >& _rxField,
+ const Reference< XNumberFormatter >& xFormatter)
+{
+ DrawTextFlags nStyle = DrawTextFlags::Clip;
+ if ( ( rDev.GetOutDevType() == OUTDEV_WINDOW ) && !rDev.GetOwnerWindow()->IsEnabled() )
+ nStyle |= DrawTextFlags::Disable;
+
+ switch (m_pColumn->GetAlignment())
+ {
+ case css::awt::TextAlign::RIGHT:
+ nStyle |= DrawTextFlags::Right;
+ break;
+ case css::awt::TextAlign::CENTER:
+ nStyle |= DrawTextFlags::Center;
+ break;
+ default:
+ nStyle |= DrawTextFlags::Left;
+ }
+
+ if (!m_bIsMultiLineText)
+ nStyle |= DrawTextFlags::VCenter;
+ else
+ nStyle |= DrawTextFlags::Top | DrawTextFlags::MultiLine | DrawTextFlags::WordBreak;
+
+ try
+ {
+ const Color* pColor = nullptr;
+ OUString aText = GetText(_rxField, xFormatter, &pColor);
+ if (pColor != nullptr)
+ {
+ Color aOldTextColor( rDev.GetTextColor() );
+ rDev.SetTextColor( *pColor );
+ rDev.DrawText(rRect, aText, nStyle);
+ rDev.SetTextColor( aOldTextColor );
+ }
+ else
+ rDev.DrawText(rRect, aText, nStyle);
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.fmcomp", "PaintFieldToCell");
+ }
+}
+
+FmXEditCell::FmXEditCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl )
+ :FmXTextCell( pColumn, std::move(pControl) )
+ ,m_aTextListeners(m_aMutex)
+ ,m_aChangeListeners( m_aMutex )
+ ,m_pEditImplementation( nullptr )
+ ,m_bOwnEditImplementation( false )
+{
+
+ DbTextField* pTextField = dynamic_cast<DbTextField*>( m_pCellControl.get() );
+ if ( pTextField )
+ {
+
+ m_pEditImplementation = pTextField->GetEditImplementation();
+ m_bIsMultiLineText = pTextField->IsMultiLineEdit();
+ }
+ else
+ {
+ m_pEditImplementation = new EntryImplementation(static_cast<EditControlBase&>(m_pCellControl->GetWindow()));
+ m_bOwnEditImplementation = true;
+ }
+ m_pEditImplementation->SetAuxModifyHdl(LINK(this, FmXEditCell, ModifyHdl));
+}
+
+FmXEditCell::~FmXEditCell()
+{
+ if (!OComponentHelper::rBHelper.bDisposed)
+ {
+ acquire();
+ dispose();
+ }
+}
+
+// OComponentHelper
+void FmXEditCell::disposing()
+{
+ css::lang::EventObject aEvt(*this);
+ m_aTextListeners.disposeAndClear(aEvt);
+ m_aChangeListeners.disposeAndClear(aEvt);
+
+ if ( m_bOwnEditImplementation )
+ delete m_pEditImplementation;
+ m_pEditImplementation = nullptr;
+
+ FmXDataCell::disposing();
+}
+
+Any SAL_CALL FmXEditCell::queryAggregation( const css::uno::Type& _rType )
+{
+ Any aReturn = FmXTextCell::queryAggregation( _rType );
+
+ if ( !aReturn.hasValue() )
+ aReturn = FmXEditCell_Base::queryInterface( _rType );
+
+ return aReturn;
+}
+
+Sequence< css::uno::Type > SAL_CALL FmXEditCell::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ FmXTextCell::getTypes(),
+ FmXEditCell_Base::getTypes()
+ );
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( FmXEditCell )
+
+// css::awt::XTextComponent
+void SAL_CALL FmXEditCell::addTextListener(const Reference< css::awt::XTextListener >& l)
+{
+ m_aTextListeners.addInterface( l );
+}
+
+
+void SAL_CALL FmXEditCell::removeTextListener(const Reference< css::awt::XTextListener >& l)
+{
+ m_aTextListeners.removeInterface( l );
+}
+
+void SAL_CALL FmXEditCell::setText( const OUString& aText )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pEditImplementation )
+ {
+ m_pEditImplementation->SetText( aText );
+
+ // In Java, a textChanged is fired as well; not in VCL.
+ // css::awt::Toolkit must be Java-compliant...
+ onTextChanged();
+ }
+}
+
+void SAL_CALL FmXEditCell::insertText(const css::awt::Selection& rSel, const OUString& aText)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pEditImplementation )
+ {
+ m_pEditImplementation->SetSelection( Selection( rSel.Min, rSel.Max ) );
+ m_pEditImplementation->ReplaceSelected( aText );
+ }
+}
+
+OUString SAL_CALL FmXEditCell::getText()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OUString aText;
+ if ( m_pEditImplementation )
+ {
+ if ( m_pEditImplementation->GetControl().IsVisible() && m_pColumn->GetParent().getDisplaySynchron())
+ {
+ // if the display isn't sync with the cursor we can't ask the edit field
+ LineEnd eLineEndFormat = getModelLineEndSetting( m_pColumn->getModel() );
+ aText = m_pEditImplementation->GetText( eLineEndFormat );
+ }
+ else
+ {
+ Reference< css::sdb::XColumn > xField(m_pColumn->GetCurrentFieldValue());
+ if (xField.is())
+ aText = GetText(xField, m_pColumn->GetParent().getNumberFormatter());
+ }
+ }
+ return aText;
+}
+
+OUString SAL_CALL FmXEditCell::getSelectedText()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OUString aText;
+ if ( m_pEditImplementation )
+ {
+ LineEnd eLineEndFormat = m_pColumn ? getModelLineEndSetting( m_pColumn->getModel() ) : LINEEND_LF;
+ aText = m_pEditImplementation->GetSelected( eLineEndFormat );
+ }
+ return aText;
+}
+
+void SAL_CALL FmXEditCell::setSelection( const css::awt::Selection& aSelection )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pEditImplementation )
+ m_pEditImplementation->SetSelection( Selection( aSelection.Min, aSelection.Max ) );
+}
+
+css::awt::Selection SAL_CALL FmXEditCell::getSelection()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Selection aSel;
+ if ( m_pEditImplementation )
+ aSel = m_pEditImplementation->GetSelection();
+
+ return css::awt::Selection(aSel.Min(), aSel.Max());
+}
+
+sal_Bool SAL_CALL FmXEditCell::isEditable()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return m_pEditImplementation && !m_pEditImplementation->IsReadOnly() && m_pEditImplementation->GetControl().IsEnabled();
+}
+
+void SAL_CALL FmXEditCell::setEditable( sal_Bool bEditable )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pEditImplementation )
+ m_pEditImplementation->SetReadOnly( !bEditable );
+}
+
+sal_Int16 SAL_CALL FmXEditCell::getMaxTextLen()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return m_pEditImplementation ? m_pEditImplementation->GetMaxTextLen() : 0;
+}
+
+void SAL_CALL FmXEditCell::setMaxTextLen( sal_Int16 nLen )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pEditImplementation )
+ m_pEditImplementation->SetMaxTextLen( nLen );
+}
+
+void SAL_CALL FmXEditCell::addChangeListener( const Reference< form::XChangeListener >& Listener )
+{
+ m_aChangeListeners.addInterface( Listener );
+}
+
+void SAL_CALL FmXEditCell::removeChangeListener( const Reference< form::XChangeListener >& Listener )
+{
+ m_aChangeListeners.removeInterface( Listener );
+}
+
+void FmXEditCell::onTextChanged()
+{
+ css::awt::TextEvent aEvent;
+ aEvent.Source = *this;
+ m_aTextListeners.notifyEach( &awt::XTextListener::textChanged, aEvent );
+}
+
+void FmXEditCell::onFocusGained( const awt::FocusEvent& _rEvent )
+{
+ FmXTextCell::onFocusGained( _rEvent );
+ m_sValueOnEnter = getText();
+}
+
+void FmXEditCell::onFocusLost( const awt::FocusEvent& _rEvent )
+{
+ FmXTextCell::onFocusLost( _rEvent );
+
+ if ( getText() != m_sValueOnEnter )
+ {
+ lang::EventObject aEvent( *this );
+ m_aChangeListeners.notifyEach( &XChangeListener::changed, aEvent );
+ }
+}
+
+IMPL_LINK_NOARG(FmXEditCell, ModifyHdl, LinkParamNone*, void)
+{
+ if (m_aTextListeners.getLength())
+ onTextChanged();
+}
+
+FmXCheckBoxCell::FmXCheckBoxCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl )
+ :FmXDataCell( pColumn, std::move(pControl) )
+ ,m_aItemListeners(m_aMutex)
+ ,m_aActionListeners( m_aMutex )
+ ,m_pBox( & static_cast< CheckBoxControl& >( m_pCellControl->GetWindow() ) )
+{
+ m_pBox->SetAuxModifyHdl(LINK(this, FmXCheckBoxCell, ModifyHdl));
+}
+
+FmXCheckBoxCell::~FmXCheckBoxCell()
+{
+ if (!OComponentHelper::rBHelper.bDisposed)
+ {
+ acquire();
+ dispose();
+ }
+}
+
+// OComponentHelper
+void FmXCheckBoxCell::disposing()
+{
+ css::lang::EventObject aEvt(*this);
+ m_aItemListeners.disposeAndClear(aEvt);
+ m_aActionListeners.disposeAndClear(aEvt);
+
+ m_pBox->SetToggleHdl(Link<weld::CheckButton&,void>());
+ m_pBox = nullptr;
+
+ FmXDataCell::disposing();
+}
+
+
+Any SAL_CALL FmXCheckBoxCell::queryAggregation( const css::uno::Type& _rType )
+{
+ Any aReturn = FmXDataCell::queryAggregation( _rType );
+
+ if ( !aReturn.hasValue() )
+ aReturn = FmXCheckBoxCell_Base::queryInterface( _rType );
+
+ return aReturn;
+}
+
+
+Sequence< css::uno::Type > SAL_CALL FmXCheckBoxCell::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ FmXDataCell::getTypes(),
+ FmXCheckBoxCell_Base::getTypes()
+ );
+}
+
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( FmXCheckBoxCell )
+
+void SAL_CALL FmXCheckBoxCell::addItemListener( const Reference< css::awt::XItemListener >& l )
+{
+ m_aItemListeners.addInterface( l );
+}
+
+void SAL_CALL FmXCheckBoxCell::removeItemListener( const Reference< css::awt::XItemListener >& l )
+{
+ m_aItemListeners.removeInterface( l );
+}
+
+void SAL_CALL FmXCheckBoxCell::setState( sal_Int16 n )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (m_pBox)
+ {
+ UpdateFromColumn();
+ m_pBox->SetState( static_cast<TriState>(n) );
+ }
+}
+
+sal_Int16 SAL_CALL FmXCheckBoxCell::getState()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (m_pBox)
+ {
+ UpdateFromColumn();
+ return static_cast<sal_Int16>(m_pBox->GetState());
+ }
+ return TRISTATE_INDET;
+}
+
+void SAL_CALL FmXCheckBoxCell::enableTriState(sal_Bool b)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (m_pBox)
+ m_pBox->EnableTriState( b );
+}
+
+void SAL_CALL FmXCheckBoxCell::addActionListener( const Reference< awt::XActionListener >& Listener )
+{
+ m_aActionListeners.addInterface( Listener );
+}
+
+
+void SAL_CALL FmXCheckBoxCell::removeActionListener( const Reference< awt::XActionListener >& Listener )
+{
+ m_aActionListeners.removeInterface( Listener );
+}
+
+void SAL_CALL FmXCheckBoxCell::setLabel( const OUString& Label )
+{
+ SolarMutexGuard aGuard;
+ if ( m_pColumn )
+ {
+ DbGridControl& rGrid( m_pColumn->GetParent() );
+ rGrid.SetColumnTitle( rGrid.GetColumnId( m_pColumn->GetFieldPos() ), Label );
+ }
+}
+
+void SAL_CALL FmXCheckBoxCell::setActionCommand( const OUString& Command )
+{
+ m_aActionCommand = Command;
+}
+
+IMPL_LINK_NOARG(FmXCheckBoxCell, ModifyHdl, LinkParamNone*, void)
+{
+ // check boxes are to be committed immediately (this holds for ordinary check box controls in
+ // documents, and this must hold for check boxes in grid columns, too
+ // 91210 - 22.08.2001 - frank.schoenheit@sun.com
+ m_pCellControl->Commit();
+
+ Reference< XWindow > xKeepAlive( this );
+ if ( m_aItemListeners.getLength() && m_pBox )
+ {
+ awt::ItemEvent aEvent;
+ aEvent.Source = *this;
+ aEvent.Highlighted = 0;
+ aEvent.Selected = m_pBox->GetState();
+ m_aItemListeners.notifyEach( &awt::XItemListener::itemStateChanged, aEvent );
+ }
+ if ( m_aActionListeners.getLength() )
+ {
+ awt::ActionEvent aEvent;
+ aEvent.Source = *this;
+ aEvent.ActionCommand = m_aActionCommand;
+ m_aActionListeners.notifyEach( &awt::XActionListener::actionPerformed, aEvent );
+ }
+}
+
+FmXListBoxCell::FmXListBoxCell(DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl)
+ : FmXTextCell(pColumn, std::move(pControl))
+ , m_aItemListeners(m_aMutex)
+ , m_aActionListeners(m_aMutex)
+ , m_pBox(&static_cast<svt::ListBoxControl&>(m_pCellControl->GetWindow()))
+ , m_nLines(Application::GetSettings().GetStyleSettings().GetListBoxMaximumLineCount())
+ , m_bMulti(false)
+{
+ m_pBox->SetAuxModifyHdl(LINK(this, FmXListBoxCell, ChangedHdl));
+}
+
+FmXListBoxCell::~FmXListBoxCell()
+{
+ if (!OComponentHelper::rBHelper.bDisposed)
+ {
+ acquire();
+ dispose();
+ }
+}
+
+// OComponentHelper
+void FmXListBoxCell::disposing()
+{
+ css::lang::EventObject aEvt(*this);
+ m_aItemListeners.disposeAndClear(aEvt);
+ m_aActionListeners.disposeAndClear(aEvt);
+
+ m_pBox->SetAuxModifyHdl(Link<bool,void>());
+ m_pBox = nullptr;
+
+ FmXTextCell::disposing();
+}
+
+Any SAL_CALL FmXListBoxCell::queryAggregation( const css::uno::Type& _rType )
+{
+ Any aReturn = FmXTextCell::queryAggregation(_rType);
+
+ if ( !aReturn.hasValue() )
+ aReturn = FmXListBoxCell_Base::queryInterface( _rType );
+
+ return aReturn;
+}
+
+Sequence< css::uno::Type > SAL_CALL FmXListBoxCell::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ FmXTextCell::getTypes(),
+ FmXListBoxCell_Base::getTypes()
+ );
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( FmXListBoxCell )
+
+void SAL_CALL FmXListBoxCell::addItemListener(const Reference< css::awt::XItemListener >& l)
+{
+ m_aItemListeners.addInterface( l );
+}
+
+void SAL_CALL FmXListBoxCell::removeItemListener(const Reference< css::awt::XItemListener >& l)
+{
+ m_aItemListeners.removeInterface( l );
+}
+
+void SAL_CALL FmXListBoxCell::addActionListener(const Reference< css::awt::XActionListener >& l)
+{
+ m_aActionListeners.addInterface( l );
+}
+
+void SAL_CALL FmXListBoxCell::removeActionListener(const Reference< css::awt::XActionListener >& l)
+{
+ m_aActionListeners.removeInterface( l );
+}
+
+void SAL_CALL FmXListBoxCell::addItem(const OUString& aItem, sal_Int16 nPos)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (m_pBox)
+ {
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ rBox.insert_text(nPos, aItem);
+ }
+}
+
+void SAL_CALL FmXListBoxCell::addItems(const css::uno::Sequence<OUString>& aItems, sal_Int16 nPos)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (m_pBox)
+ {
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ sal_uInt16 nP = nPos;
+ for ( const auto& rItem : aItems )
+ {
+ rBox.insert_text(nP, rItem);
+ if ( nPos != -1 ) // Not if 0xFFFF, because LIST_APPEND
+ nP++;
+ }
+ }
+}
+
+void SAL_CALL FmXListBoxCell::removeItems(sal_Int16 nPos, sal_Int16 nCount)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_pBox )
+ {
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ for ( sal_uInt16 n = nCount; n; )
+ rBox.remove( nPos + (--n) );
+ }
+}
+
+sal_Int16 SAL_CALL FmXListBoxCell::getItemCount()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pBox)
+ return 0;
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ return rBox.get_count();
+}
+
+OUString SAL_CALL FmXListBoxCell::getItem(sal_Int16 nPos)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pBox)
+ return OUString();
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ return rBox.get_text(nPos);
+}
+
+css::uno::Sequence<OUString> SAL_CALL FmXListBoxCell::getItems()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ css::uno::Sequence<OUString> aSeq;
+ if (m_pBox)
+ {
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ const sal_Int32 nEntries = rBox.get_count();
+ aSeq = css::uno::Sequence<OUString>( nEntries );
+ for ( sal_Int32 n = nEntries; n; )
+ {
+ --n;
+ aSeq.getArray()[n] = rBox.get_text( n );
+ }
+ }
+ return aSeq;
+}
+
+sal_Int16 SAL_CALL FmXListBoxCell::getSelectedItemPos()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (m_pBox)
+ {
+ UpdateFromColumn();
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ sal_Int32 nPos = rBox.get_active();
+ if (nPos > SHRT_MAX || nPos < SHRT_MIN)
+ throw std::out_of_range("awt::XListBox::getSelectedItemPos can only return a short");
+ return nPos;
+ }
+ return 0;
+}
+
+Sequence< sal_Int16 > SAL_CALL FmXListBoxCell::getSelectedItemsPos()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (m_pBox)
+ {
+ UpdateFromColumn();
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ auto nActive = rBox.get_active();
+ if (nActive != -1)
+ {
+ return { o3tl::narrowing<short>(nActive) };
+ }
+ }
+ return {};
+}
+
+OUString SAL_CALL FmXListBoxCell::getSelectedItem()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OUString aItem;
+
+ if (m_pBox)
+ {
+ UpdateFromColumn();
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ aItem = rBox.get_active_text();
+ }
+
+ return aItem;
+}
+
+css::uno::Sequence<OUString> SAL_CALL FmXListBoxCell::getSelectedItems()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (m_pBox)
+ {
+ UpdateFromColumn();
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ auto nActive = rBox.get_active();
+ if (nActive != -1)
+ {
+ return { rBox.get_text(nActive) };
+ }
+ }
+ return {};
+}
+
+void SAL_CALL FmXListBoxCell::selectItemPos(sal_Int16 nPos, sal_Bool bSelect)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (m_pBox)
+ {
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ if (bSelect)
+ rBox.set_active(nPos);
+ else if (nPos == rBox.get_active())
+ rBox.set_active(-1);
+ }
+}
+
+void SAL_CALL FmXListBoxCell::selectItemsPos(const Sequence< sal_Int16 >& aPositions, sal_Bool bSelect)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (m_pBox)
+ {
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ for ( sal_uInt16 n = static_cast<sal_uInt16>(aPositions.getLength()); n; )
+ {
+ auto nPos = static_cast<sal_uInt16>(aPositions.getConstArray()[--n]);
+ if (bSelect)
+ rBox.set_active(nPos);
+ else if (nPos == rBox.get_active())
+ rBox.set_active(-1);
+ }
+ }
+}
+
+void SAL_CALL FmXListBoxCell::selectItem(const OUString& aItem, sal_Bool bSelect)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if (m_pBox)
+ {
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ auto nPos = rBox.find_text(aItem);
+ if (bSelect)
+ rBox.set_active(nPos);
+ else if (nPos == rBox.get_active())
+ rBox.set_active(-1);
+ }
+}
+
+sal_Bool SAL_CALL FmXListBoxCell::isMutipleMode()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return m_bMulti;
+}
+
+void SAL_CALL FmXListBoxCell::setMultipleMode(sal_Bool bMulti)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_bMulti = bMulti;
+}
+
+sal_Int16 SAL_CALL FmXListBoxCell::getDropDownLineCount()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return m_nLines;
+}
+
+void SAL_CALL FmXListBoxCell::setDropDownLineCount(sal_Int16 nLines)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_nLines = nLines; // just store it to return it
+}
+
+void SAL_CALL FmXListBoxCell::makeVisible(sal_Int16 /*nEntry*/)
+{
+}
+
+IMPL_LINK(FmXListBoxCell, ChangedHdl, bool, bInteractive, void)
+{
+ if (!m_pBox)
+ return;
+
+ weld::ComboBox& rBox = m_pBox->get_widget();
+
+ if (bInteractive && !rBox.changed_by_direct_pick())
+ return;
+
+ OnDoubleClick();
+
+ css::awt::ItemEvent aEvent;
+ aEvent.Source = *this;
+ aEvent.Highlighted = 0;
+
+ // with multiple selection 0xFFFF, otherwise the ID
+ aEvent.Selected = (rBox.get_active() != -1 )
+ ? rBox.get_active() : 0xFFFF;
+
+ m_aItemListeners.notifyEach( &awt::XItemListener::itemStateChanged, aEvent );
+}
+
+void FmXListBoxCell::OnDoubleClick()
+{
+ css::awt::ActionEvent aEvent;
+ aEvent.Source = *this;
+ weld::ComboBox& rBox = m_pBox->get_widget();
+ aEvent.ActionCommand = rBox.get_active_text();
+
+ m_aActionListeners.notifyEach( &css::awt::XActionListener::actionPerformed, aEvent );
+}
+
+FmXComboBoxCell::FmXComboBoxCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl )
+ :FmXTextCell( pColumn, std::move(pControl) )
+ ,m_aItemListeners( m_aMutex )
+ ,m_aActionListeners( m_aMutex )
+ ,m_pComboBox(&static_cast<ComboBoxControl&>(m_pCellControl->GetWindow()))
+ ,m_nLines(Application::GetSettings().GetStyleSettings().GetListBoxMaximumLineCount())
+{
+ m_pComboBox->SetAuxModifyHdl(LINK(this, FmXComboBoxCell, ChangedHdl));
+}
+
+FmXComboBoxCell::~FmXComboBoxCell()
+{
+ if ( !OComponentHelper::rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+
+}
+
+void FmXComboBoxCell::disposing()
+{
+ css::lang::EventObject aEvt(*this);
+ m_aItemListeners.disposeAndClear(aEvt);
+ m_aActionListeners.disposeAndClear(aEvt);
+
+ m_pComboBox->SetAuxModifyHdl(Link<bool,void>());
+ m_pComboBox = nullptr;
+
+ FmXTextCell::disposing();
+}
+
+Any SAL_CALL FmXComboBoxCell::queryAggregation( const css::uno::Type& _rType )
+{
+ Any aReturn = FmXTextCell::queryAggregation(_rType);
+
+ if ( !aReturn.hasValue() )
+ aReturn = FmXComboBoxCell_Base::queryInterface( _rType );
+
+ return aReturn;
+}
+
+Sequence< Type > SAL_CALL FmXComboBoxCell::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ FmXTextCell::getTypes(),
+ FmXComboBoxCell_Base::getTypes()
+ );
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( FmXComboBoxCell )
+
+void SAL_CALL FmXComboBoxCell::addItemListener(const Reference< awt::XItemListener >& l)
+{
+ m_aItemListeners.addInterface( l );
+}
+
+void SAL_CALL FmXComboBoxCell::removeItemListener(const Reference< awt::XItemListener >& l)
+{
+ m_aItemListeners.removeInterface( l );
+}
+
+void SAL_CALL FmXComboBoxCell::addActionListener(const Reference< awt::XActionListener >& l)
+{
+ m_aActionListeners.addInterface( l );
+}
+
+
+void SAL_CALL FmXComboBoxCell::removeActionListener(const Reference< awt::XActionListener >& l)
+{
+ m_aActionListeners.removeInterface( l );
+}
+
+void SAL_CALL FmXComboBoxCell::addItem( const OUString& Item, sal_Int16 Pos )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pComboBox)
+ return;
+ weld::ComboBox& rBox = m_pComboBox->get_widget();
+ rBox.insert_text(Pos, Item);
+}
+
+void SAL_CALL FmXComboBoxCell::addItems( const Sequence< OUString >& Items, sal_Int16 Pos )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pComboBox)
+ return;
+ weld::ComboBox& rBox = m_pComboBox->get_widget();
+ sal_uInt16 nP = Pos;
+ for ( const auto& rItem : Items )
+ {
+ rBox.insert_text(nP, rItem);
+ if ( Pos != -1 )
+ nP++;
+ }
+}
+
+void SAL_CALL FmXComboBoxCell::removeItems( sal_Int16 Pos, sal_Int16 Count )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pComboBox)
+ return;
+ weld::ComboBox& rBox = m_pComboBox->get_widget();
+ for ( sal_uInt16 n = Count; n; )
+ rBox.remove( Pos + (--n) );
+}
+
+sal_Int16 SAL_CALL FmXComboBoxCell::getItemCount()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pComboBox)
+ return 0;
+ weld::ComboBox& rBox = m_pComboBox->get_widget();
+ return rBox.get_count();
+}
+
+OUString SAL_CALL FmXComboBoxCell::getItem( sal_Int16 Pos )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (!m_pComboBox)
+ return OUString();
+ weld::ComboBox& rBox = m_pComboBox->get_widget();
+ return rBox.get_text(Pos);
+}
+
+Sequence< OUString > SAL_CALL FmXComboBoxCell::getItems()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Sequence< OUString > aItems;
+ if (m_pComboBox)
+ {
+ weld::ComboBox& rBox = m_pComboBox->get_widget();
+ const sal_Int32 nEntries = rBox.get_count();
+ aItems.realloc( nEntries );
+ OUString* pItem = aItems.getArray();
+ for ( sal_Int32 n=0; n<nEntries; ++n, ++pItem )
+ *pItem = rBox.get_text(n);
+ }
+ return aItems;
+}
+
+sal_Int16 SAL_CALL FmXComboBoxCell::getDropDownLineCount()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return m_nLines;
+}
+
+void SAL_CALL FmXComboBoxCell::setDropDownLineCount(sal_Int16 nLines)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_nLines = nLines; // just store it to return it
+}
+
+IMPL_LINK(FmXComboBoxCell, ChangedHdl, bool, bInteractive, void)
+{
+ if (!m_pComboBox)
+ return;
+
+ weld::ComboBox& rComboBox = m_pComboBox->get_widget();
+
+ if (bInteractive && !rComboBox.changed_by_direct_pick())
+ return;
+
+ awt::ItemEvent aEvent;
+ aEvent.Source = *this;
+ aEvent.Highlighted = 0;
+
+ // with invalid selection 0xFFFF, otherwise the position
+ aEvent.Selected = ( rComboBox.get_active() != -1 )
+ ? rComboBox.get_active()
+ : 0xFFFF;
+ m_aItemListeners.notifyEach( &awt::XItemListener::itemStateChanged, aEvent );
+}
+
+FmXFilterCell::FmXFilterCell(DbGridColumn* pColumn, std::unique_ptr<DbFilterField> pControl )
+ :FmXGridCell( pColumn, std::move(pControl) )
+ ,m_aTextListeners(m_aMutex)
+{
+ static_cast<DbFilterField*>(m_pCellControl.get())->SetCommitHdl( LINK( this, FmXFilterCell, OnCommit ) );
+}
+
+FmXFilterCell::~FmXFilterCell()
+{
+ if (!OComponentHelper::rBHelper.bDisposed)
+ {
+ acquire();
+ dispose();
+ }
+
+}
+
+// XUnoTunnel
+sal_Int64 SAL_CALL FmXFilterCell::getSomething( const Sequence< sal_Int8 >& _rIdentifier )
+{
+ return comphelper::getSomethingImpl(_rIdentifier, this);
+}
+
+const Sequence<sal_Int8>& FmXFilterCell::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theFmXFilterCellUnoTunnelId;
+ return theFmXFilterCellUnoTunnelId.getSeq();
+}
+
+
+void FmXFilterCell::PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect )
+{
+ static_cast< DbFilterField* >( m_pCellControl.get() )->PaintCell( rDev, rRect );
+}
+
+// OComponentHelper
+
+void FmXFilterCell::disposing()
+{
+ css::lang::EventObject aEvt(*this);
+ m_aTextListeners.disposeAndClear(aEvt);
+
+ static_cast<DbFilterField*>(m_pCellControl.get())->SetCommitHdl(Link<DbFilterField&,void>());
+
+ FmXGridCell::disposing();
+}
+
+
+Any SAL_CALL FmXFilterCell::queryAggregation( const css::uno::Type& _rType )
+{
+ Any aReturn = FmXGridCell::queryAggregation(_rType);
+
+ if ( !aReturn.hasValue() )
+ aReturn = FmXFilterCell_Base::queryInterface( _rType );
+
+ return aReturn;
+}
+
+
+Sequence< css::uno::Type > SAL_CALL FmXFilterCell::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ FmXGridCell::getTypes(),
+ FmXFilterCell_Base::getTypes()
+ );
+}
+
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( FmXFilterCell )
+
+// css::awt::XTextComponent
+
+void SAL_CALL FmXFilterCell::addTextListener(const Reference< css::awt::XTextListener >& l)
+{
+ m_aTextListeners.addInterface( l );
+}
+
+
+void SAL_CALL FmXFilterCell::removeTextListener(const Reference< css::awt::XTextListener >& l)
+{
+ m_aTextListeners.removeInterface( l );
+}
+
+void SAL_CALL FmXFilterCell::setText( const OUString& aText )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ static_cast<DbFilterField*>(m_pCellControl.get())->SetText(aText);
+}
+
+void SAL_CALL FmXFilterCell::insertText( const css::awt::Selection& /*rSel*/, const OUString& /*aText*/ )
+{
+}
+
+OUString SAL_CALL FmXFilterCell::getText()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return static_cast<DbFilterField*>(m_pCellControl.get())->GetText();
+}
+
+OUString SAL_CALL FmXFilterCell::getSelectedText()
+{
+ return getText();
+}
+
+void SAL_CALL FmXFilterCell::setSelection( const css::awt::Selection& /*aSelection*/ )
+{
+}
+
+css::awt::Selection SAL_CALL FmXFilterCell::getSelection()
+{
+ return css::awt::Selection();
+}
+
+sal_Bool SAL_CALL FmXFilterCell::isEditable()
+{
+ return true;
+}
+
+void SAL_CALL FmXFilterCell::setEditable( sal_Bool /*bEditable*/ )
+{
+}
+
+sal_Int16 SAL_CALL FmXFilterCell::getMaxTextLen()
+{
+ return 0;
+}
+
+void SAL_CALL FmXFilterCell::setMaxTextLen( sal_Int16 /*nLen*/ )
+{
+}
+
+IMPL_LINK_NOARG(FmXFilterCell, OnCommit, DbFilterField&, void)
+{
+ css::awt::TextEvent aEvt;
+ aEvt.Source = *this;
+ m_aTextListeners.notifyEach( &css::awt::XTextListener::textChanged, aEvt );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/fmcomp/gridcols.cxx b/svx/source/fmcomp/gridcols.cxx
new file mode 100644
index 000000000..92546d155
--- /dev/null
+++ b/svx/source/fmcomp/gridcols.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <gridcols.hxx>
+#include <tools/debug.hxx>
+#include <fmservs.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+using namespace ::com::sun::star::uno;
+
+
+static const css::uno::Sequence<OUString>& getColumnTypes()
+{
+ static css::uno::Sequence<OUString> aColumnTypes = []()
+ {
+ css::uno::Sequence<OUString> tmp(10);
+ OUString* pNames = tmp.getArray();
+ pNames[TYPE_CHECKBOX] = FM_COL_CHECKBOX;
+ pNames[TYPE_COMBOBOX] = FM_COL_COMBOBOX;
+ pNames[TYPE_CURRENCYFIELD] = FM_COL_CURRENCYFIELD;
+ pNames[TYPE_DATEFIELD] = FM_COL_DATEFIELD;
+ pNames[TYPE_FORMATTEDFIELD] = FM_COL_FORMATTEDFIELD;
+ pNames[TYPE_LISTBOX] = FM_COL_LISTBOX;
+ pNames[TYPE_NUMERICFIELD] = FM_COL_NUMERICFIELD;
+ pNames[TYPE_PATTERNFIELD] = FM_COL_PATTERNFIELD;
+ pNames[TYPE_TEXTFIELD] = FM_COL_TEXTFIELD;
+ pNames[TYPE_TIMEFIELD] = FM_COL_TIMEFIELD;
+ return tmp;
+ }();
+ return aColumnTypes;
+}
+
+
+extern "C" {
+
+// comparison of PropertyInfo
+static int NameCompare(const void* pFirst, const void* pSecond)
+{
+ return static_cast<OUString const *>(pFirst)->compareTo(*static_cast<OUString const *>(pSecond));
+}
+
+}
+
+namespace
+{
+
+ sal_Int32 lcl_findPos(const OUString& aStr, const Sequence< OUString>& rList)
+ {
+ const OUString* pStrList = rList.getConstArray();
+ OUString* pResult = static_cast<OUString*>(bsearch(&aStr, static_cast<void const *>(pStrList), rList.getLength(), sizeof(OUString),
+ &NameCompare));
+
+ if (pResult)
+ return (pResult - pStrList);
+ else
+ return -1;
+ }
+}
+
+
+sal_Int32 getColumnTypeByModelName(const OUString& aModelName)
+{
+ static const OUStringLiteral aModelPrefix(u"com.sun.star.form.component.");
+ static const OUStringLiteral aCompatibleModelPrefix(u"stardiv.one.form.component.");
+
+ sal_Int32 nTypeId = -1;
+ if (aModelName == FM_COMPONENT_EDIT)
+ nTypeId = TYPE_TEXTFIELD;
+ else
+ {
+ sal_Int32 nPrefixPos = aModelName.indexOf(aModelPrefix);
+#ifdef DBG_UTIL
+ sal_Int32 nCompatiblePrefixPos = aModelName.indexOf(aCompatibleModelPrefix);
+ DBG_ASSERT( (nPrefixPos != -1) || (nCompatiblePrefixPos != -1), "::getColumnTypeByModelName() : wrong service!");
+#endif
+
+ OUString aColumnType = (nPrefixPos != -1)
+ ? aModelName.copy(aModelPrefix.getLength())
+ : aModelName.copy(aCompatibleModelPrefix.getLength());
+
+ const css::uno::Sequence<OUString>& rColumnTypes = getColumnTypes();
+ nTypeId = lcl_findPos(aColumnType, rColumnTypes);
+ }
+ return nTypeId;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/fmcomp/gridctrl.cxx b/svx/source/fmcomp/gridctrl.cxx
new file mode 100644
index 000000000..ab8f128a7
--- /dev/null
+++ b/svx/source/fmcomp/gridctrl.cxx
@@ -0,0 +1,3396 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/log.hxx>
+#include <helpids.h>
+#include <svx/gridctrl.hxx>
+#include <gridcell.hxx>
+#include <svx/fmtools.hxx>
+#include <svtools/stringtransfer.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbconversion.hxx>
+
+#include <fmprop.hxx>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/sdb/XResultSetAccess.hpp>
+#include <com/sun/star/sdb/RowChangeAction.hpp>
+#include <com/sun/star/sdb/XRowsChangeBroadcaster.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyChangeEvent.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <tools/diagnose_ex.h>
+#include <tools/debug.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+
+#include <svx/strings.hrc>
+
+#include <svx/dialmgr.hxx>
+#include <sdbdatacolumn.hxx>
+
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <algorithm>
+#include <cstdlib>
+#include <map>
+#include <memory>
+
+using namespace ::dbtools;
+using namespace ::dbtools::DBTypeConversion;
+using namespace ::svxform;
+using namespace ::svt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::container;
+using namespace com::sun::star::accessibility;
+
+#define ROWSTATUS(row) (!row.is() ? "NULL" : row->GetStatus() == GridRowStatus::Clean ? "CLEAN" : row->GetStatus() == GridRowStatus::Modified ? "MODIFIED" : row->GetStatus() == GridRowStatus::Deleted ? "DELETED" : "INVALID")
+
+constexpr auto DEFAULT_BROWSE_MODE =
+ BrowserMode::COLUMNSELECTION
+ | BrowserMode::MULTISELECTION
+ | BrowserMode::KEEPHIGHLIGHT
+ | BrowserMode::TRACKING_TIPS
+ | BrowserMode::HLINES
+ | BrowserMode::VLINES
+ | BrowserMode::HEADERBAR_NEW;
+
+class RowSetEventListener : public ::cppu::WeakImplHelper<XRowsChangeListener>
+{
+ VclPtr<DbGridControl> m_pControl;
+public:
+ explicit RowSetEventListener(DbGridControl* i_pControl) : m_pControl(i_pControl)
+ {
+ }
+
+private:
+ // XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& /*i_aEvt*/) override
+ {
+ }
+ virtual void SAL_CALL rowsChanged(const css::sdb::RowsChangeEvent& i_aEvt) override
+ {
+ if ( i_aEvt.Action != RowChangeAction::UPDATE )
+ return;
+
+ ::DbGridControl::GrantControlAccess aAccess;
+ CursorWrapper* pSeek = m_pControl->GetSeekCursor(aAccess);
+ const DbGridRowRef& rSeekRow = m_pControl->GetSeekRow(aAccess);
+ for(const Any& rBookmark : i_aEvt.Bookmarks)
+ {
+ pSeek->moveToBookmark(rBookmark);
+ // get the data
+ rSeekRow->SetState(pSeek, true);
+ sal_Int32 nSeekPos = pSeek->getRow() - 1;
+ m_pControl->SetSeekPos(nSeekPos,aAccess);
+ m_pControl->RowModified(nSeekPos);
+ }
+ }
+};
+
+class GridFieldValueListener;
+typedef std::map<sal_uInt16, GridFieldValueListener*> ColumnFieldValueListeners;
+
+class GridFieldValueListener : protected ::comphelper::OPropertyChangeListener
+{
+ osl::Mutex m_aMutex;
+ DbGridControl& m_rParent;
+ rtl::Reference<::comphelper::OPropertyChangeMultiplexer> m_pRealListener;
+ sal_uInt16 m_nId;
+ sal_Int16 m_nSuspended;
+ bool m_bDisposed : 1;
+
+public:
+ GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& xField, sal_uInt16 _nId);
+ virtual ~GridFieldValueListener() override;
+
+ virtual void _propertyChanged(const PropertyChangeEvent& evt) override;
+
+ void suspend() { ++m_nSuspended; }
+ void resume() { --m_nSuspended; }
+
+ void dispose();
+};
+
+GridFieldValueListener::GridFieldValueListener(DbGridControl& _rParent, const Reference< XPropertySet >& _rField, sal_uInt16 _nId)
+ :OPropertyChangeListener(m_aMutex)
+ ,m_rParent(_rParent)
+ ,m_nId(_nId)
+ ,m_nSuspended(0)
+ ,m_bDisposed(false)
+{
+ if (_rField.is())
+ {
+ m_pRealListener = new ::comphelper::OPropertyChangeMultiplexer(this, _rField);
+ m_pRealListener->addProperty(FM_PROP_VALUE);
+ }
+}
+
+GridFieldValueListener::~GridFieldValueListener()
+{
+ dispose();
+}
+
+void GridFieldValueListener::_propertyChanged(const PropertyChangeEvent& /*_evt*/)
+{
+ DBG_ASSERT(m_nSuspended>=0, "GridFieldValueListener::_propertyChanged : resume > suspend !");
+ if (m_nSuspended <= 0)
+ m_rParent.FieldValueChanged(m_nId);
+}
+
+void GridFieldValueListener::dispose()
+{
+ if (m_bDisposed)
+ {
+ DBG_ASSERT(!m_pRealListener, "GridFieldValueListener::dispose : inconsistent !");
+ return;
+ }
+
+ if (m_pRealListener.is())
+ {
+ m_pRealListener->dispose();
+ m_pRealListener.clear();
+ }
+
+ m_bDisposed = true;
+ m_rParent.FieldListenerDisposing(m_nId);
+}
+
+class DisposeListenerGridBridge : public FmXDisposeListener
+{
+ DbGridControl& m_rParent;
+ rtl::Reference<FmXDisposeMultiplexer> m_xRealListener;
+
+public:
+ DisposeListenerGridBridge( DbGridControl& _rParent, const Reference< XComponent >& _rxObject);
+ virtual ~DisposeListenerGridBridge() override;
+
+ virtual void disposing(sal_Int16 _nId) override { m_rParent.disposing(_nId); }
+};
+
+DisposeListenerGridBridge::DisposeListenerGridBridge(DbGridControl& _rParent, const Reference< XComponent >& _rxObject)
+ :FmXDisposeListener()
+ ,m_rParent(_rParent)
+{
+
+ if (_rxObject.is())
+ {
+ m_xRealListener = new FmXDisposeMultiplexer(this, _rxObject);
+ }
+}
+
+DisposeListenerGridBridge::~DisposeListenerGridBridge()
+{
+ if (m_xRealListener.is())
+ {
+ m_xRealListener->dispose();
+ }
+}
+
+const DbGridControlNavigationBarState ControlMap[] =
+ {
+ DbGridControlNavigationBarState::Text,
+ DbGridControlNavigationBarState::Absolute,
+ DbGridControlNavigationBarState::Of,
+ DbGridControlNavigationBarState::Count,
+ DbGridControlNavigationBarState::First,
+ DbGridControlNavigationBarState::Next,
+ DbGridControlNavigationBarState::Prev,
+ DbGridControlNavigationBarState::Last,
+ DbGridControlNavigationBarState::New,
+ DbGridControlNavigationBarState::NONE
+ };
+
+bool CompareBookmark(const Any& aLeft, const Any& aRight)
+{
+ return aLeft == aRight;
+}
+
+class FmXGridSourcePropListener : public ::comphelper::OPropertyChangeListener
+{
+ VclPtr<DbGridControl> m_pParent;
+
+ // a DbGridControl has no mutex, so we use our own as the base class expects one
+ osl::Mutex m_aMutex;
+ sal_Int16 m_nSuspended;
+
+public:
+ explicit FmXGridSourcePropListener(DbGridControl* _pParent);
+
+ void suspend() { ++m_nSuspended; }
+ void resume() { --m_nSuspended; }
+
+ virtual void _propertyChanged(const PropertyChangeEvent& evt) override;
+};
+
+FmXGridSourcePropListener::FmXGridSourcePropListener(DbGridControl* _pParent)
+ :OPropertyChangeListener(m_aMutex)
+ ,m_pParent(_pParent)
+ ,m_nSuspended(0)
+{
+ DBG_ASSERT(m_pParent, "FmXGridSourcePropListener::FmXGridSourcePropListener : invalid parent !");
+}
+
+void FmXGridSourcePropListener::_propertyChanged(const PropertyChangeEvent& evt)
+{
+ DBG_ASSERT(m_nSuspended>=0, "FmXGridSourcePropListener::_propertyChanged : resume > suspend !");
+ if (m_nSuspended <= 0)
+ m_pParent->DataSourcePropertyChanged(evt);
+}
+
+const int nReserveNumDigits = 7;
+
+NavigationBar::AbsolutePos::AbsolutePos(std::unique_ptr<weld::Entry> xEntry, NavigationBar* pBar)
+ : RecordItemWindowBase(std::move(xEntry))
+ , m_xParent(pBar)
+{
+}
+
+bool NavigationBar::AbsolutePos::DoKeyInput(const KeyEvent& rEvt)
+{
+ if (rEvt.GetKeyCode() == KEY_TAB)
+ {
+ m_xParent->GetParent()->GrabFocus();
+ return true;
+ }
+ return RecordItemWindowBase::DoKeyInput(rEvt);
+}
+
+void NavigationBar::AbsolutePos::PositionFired(sal_Int64 nRecord)
+{
+ m_xParent->PositionDataSource(nRecord);
+ m_xParent->InvalidateState(DbGridControlNavigationBarState::Absolute);
+}
+
+void NavigationBar::PositionDataSource(sal_Int32 nRecord)
+{
+ if (m_bPositioning)
+ return;
+ // the MoveToPosition may cause a LoseFocus which would lead to a second MoveToPosition,
+ // so protect against this recursion
+ m_bPositioning = true;
+ static_cast<DbGridControl*>(GetParent())->MoveToPosition(nRecord - 1);
+ m_bPositioning = false;
+}
+
+NavigationBar::NavigationBar(vcl::Window* pParent)
+ : InterimItemWindow(pParent, "svx/ui/navigationbar.ui", "NavigationBar")
+ , m_xRecordText(m_xBuilder->weld_label("recordtext"))
+ , m_xAbsolute(new NavigationBar::AbsolutePos(m_xBuilder->weld_entry("entry-noframe"), this))
+ , m_xRecordOf(m_xBuilder->weld_label("recordof"))
+ , m_xRecordCount(m_xBuilder->weld_label("recordcount"))
+ , m_xFirstBtn(m_xBuilder->weld_button("first"))
+ , m_xPrevBtn(m_xBuilder->weld_button("prev"))
+ , m_xNextBtn(m_xBuilder->weld_button("next"))
+ , m_xLastBtn(m_xBuilder->weld_button("last"))
+ , m_xNewBtn(m_xBuilder->weld_button("new"))
+ , m_xPrevRepeater(std::make_shared<weld::ButtonPressRepeater>(*m_xPrevBtn, LINK(this,NavigationBar,OnClick)))
+ , m_xNextRepeater(std::make_shared<weld::ButtonPressRepeater>(*m_xNextBtn, LINK(this,NavigationBar,OnClick)))
+ , m_nCurrentPos(-1)
+ , m_bPositioning(false)
+{
+ vcl::Font aApplFont(Application::GetSettings().GetStyleSettings().GetToolFont());
+ m_xAbsolute->set_font(aApplFont);
+ aApplFont.SetTransparent(true);
+ m_xRecordText->set_font(aApplFont);
+ m_xRecordOf->set_font(aApplFont);
+ m_xRecordCount->set_font(aApplFont);
+
+ m_xFirstBtn->set_help_id(HID_GRID_TRAVEL_FIRST);
+ m_xPrevBtn->set_help_id(HID_GRID_TRAVEL_PREV);
+ m_xNextBtn->set_help_id(HID_GRID_TRAVEL_NEXT);
+ m_xLastBtn->set_help_id(HID_GRID_TRAVEL_LAST);
+ m_xNewBtn->set_help_id(HID_GRID_TRAVEL_NEW);
+ m_xAbsolute->set_help_id(HID_GRID_TRAVEL_ABSOLUTE);
+ m_xRecordCount->set_help_id(HID_GRID_NUMBEROFRECORDS);
+
+ // set handlers for buttons
+ m_xFirstBtn->connect_clicked(LINK(this,NavigationBar,OnClick));
+ m_xLastBtn->connect_clicked(LINK(this,NavigationBar,OnClick));
+ m_xNewBtn->connect_clicked(LINK(this,NavigationBar,OnClick));
+
+ m_xRecordText->set_label(SvxResId(RID_STR_REC_TEXT));
+ m_xRecordOf->set_label(SvxResId(RID_STR_REC_FROM_TEXT));
+ m_xRecordCount->set_label(OUString('?'));
+
+ auto nReserveWidth = m_xRecordCount->get_approximate_digit_width() * nReserveNumDigits;
+ m_xAbsolute->GetWidget()->set_size_request(nReserveWidth, -1);
+ m_xRecordCount->set_size_request(nReserveWidth, -1);
+}
+
+NavigationBar::~NavigationBar()
+{
+ disposeOnce();
+}
+
+void NavigationBar::dispose()
+{
+ m_xRecordText.reset();
+ m_xAbsolute.reset();
+ m_xRecordOf.reset();
+ m_xRecordCount.reset();
+ m_xFirstBtn.reset();
+ m_xPrevBtn.reset();
+ m_xNextBtn.reset();
+ m_xLastBtn.reset();
+ m_xNewBtn.reset();
+ InterimItemWindow::dispose();
+}
+
+sal_uInt16 NavigationBar::ArrangeControls()
+{
+ return m_xContainer->get_preferred_size().Width();
+}
+
+IMPL_LINK(NavigationBar, OnClick, weld::Button&, rButton, void)
+{
+ DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
+
+ if (pParent->m_aMasterSlotExecutor.IsSet())
+ {
+ bool lResult = false;
+ if (&rButton == m_xFirstBtn.get())
+ lResult = pParent->m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::First);
+ else if( &rButton == m_xPrevBtn.get() )
+ lResult = pParent->m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::Prev);
+ else if( &rButton == m_xNextBtn.get() )
+ lResult = pParent->m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::Next);
+ else if( &rButton == m_xLastBtn.get() )
+ lResult = pParent->m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::Last);
+ else if( &rButton == m_xNewBtn.get() )
+ lResult = pParent->m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::New);
+
+ if (lResult)
+ // the link already handled it
+ return;
+ }
+
+ if (&rButton == m_xFirstBtn.get())
+ pParent->MoveToFirst();
+ else if( &rButton == m_xPrevBtn.get() )
+ pParent->MoveToPrev();
+ else if( &rButton == m_xNextBtn.get() )
+ pParent->MoveToNext();
+ else if( &rButton == m_xLastBtn.get() )
+ pParent->MoveToLast();
+ else if( &rButton == m_xNewBtn.get() )
+ pParent->AppendNew();
+}
+
+void NavigationBar::InvalidateAll(sal_Int32 nCurrentPos, bool bAll)
+{
+ if (!(m_nCurrentPos != nCurrentPos || nCurrentPos < 0 || bAll))
+ return;
+
+ DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
+
+ sal_Int32 nAdjustedRowCount = pParent->GetRowCount() - ((pParent->GetOptions() & DbGridControlOptions::Insert) ? 2 : 1);
+
+ // check if everything needs to be invalidated
+ bAll = bAll || m_nCurrentPos <= 0;
+ bAll = bAll || nCurrentPos <= 0;
+ bAll = bAll || m_nCurrentPos >= nAdjustedRowCount;
+ bAll = bAll || nCurrentPos >= nAdjustedRowCount;
+
+ if ( bAll )
+ {
+ m_nCurrentPos = nCurrentPos;
+ int i = 0;
+ while (ControlMap[i] != DbGridControlNavigationBarState::NONE)
+ SetState(ControlMap[i++]);
+ }
+ else // is in the center
+ {
+ m_nCurrentPos = nCurrentPos;
+ SetState(DbGridControlNavigationBarState::Count);
+ SetState(DbGridControlNavigationBarState::Absolute);
+ }
+}
+
+bool NavigationBar::GetState(DbGridControlNavigationBarState nWhich) const
+{
+ DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
+
+ if (!pParent->IsOpen() || pParent->IsDesignMode() || !pParent->IsEnabled()
+ || pParent->IsFilterMode() )
+ return false;
+ else
+ {
+ // check if we have a master state provider
+ if (pParent->m_aMasterStateProvider.IsSet())
+ {
+ tools::Long nState = pParent->m_aMasterStateProvider.Call( nWhich );
+ if (nState>=0)
+ return (nState>0);
+ }
+
+ bool bAvailable = true;
+
+ switch (nWhich)
+ {
+ case DbGridControlNavigationBarState::First:
+ case DbGridControlNavigationBarState::Prev:
+ bAvailable = m_nCurrentPos > 0;
+ break;
+ case DbGridControlNavigationBarState::Next:
+ if(pParent->m_bRecordCountFinal)
+ {
+ bAvailable = m_nCurrentPos < pParent->GetRowCount() - 1;
+ if (!bAvailable && pParent->GetOptions() & DbGridControlOptions::Insert)
+ bAvailable = (m_nCurrentPos == pParent->GetRowCount() - 2) && pParent->IsModified();
+ }
+ break;
+ case DbGridControlNavigationBarState::Last:
+ if(pParent->m_bRecordCountFinal)
+ {
+ if (pParent->GetOptions() & DbGridControlOptions::Insert)
+ bAvailable = pParent->IsCurrentAppending() ? pParent->GetRowCount() > 1 :
+ m_nCurrentPos != pParent->GetRowCount() - 2;
+ else
+ bAvailable = m_nCurrentPos != pParent->GetRowCount() - 1;
+ }
+ break;
+ case DbGridControlNavigationBarState::New:
+ bAvailable = (pParent->GetOptions() & DbGridControlOptions::Insert) && pParent->GetRowCount() && m_nCurrentPos < pParent->GetRowCount() - 1;
+ break;
+ case DbGridControlNavigationBarState::Absolute:
+ bAvailable = pParent->GetRowCount() > 0;
+ break;
+ default: break;
+ }
+ return bAvailable;
+ }
+}
+
+void NavigationBar::SetState(DbGridControlNavigationBarState nWhich)
+{
+ bool bAvailable = GetState(nWhich);
+ DbGridControl* pParent = static_cast<DbGridControl*>(GetParent());
+ weld::Widget* pWnd = nullptr;
+ switch (nWhich)
+ {
+ case DbGridControlNavigationBarState::First:
+ pWnd = m_xFirstBtn.get();
+ break;
+ case DbGridControlNavigationBarState::Prev:
+ pWnd = m_xPrevBtn.get();
+ break;
+ case DbGridControlNavigationBarState::Next:
+ pWnd = m_xNextBtn.get();
+ break;
+ case DbGridControlNavigationBarState::Last:
+ pWnd = m_xLastBtn.get();
+ break;
+ case DbGridControlNavigationBarState::New:
+ pWnd = m_xNewBtn.get();
+ break;
+ case DbGridControlNavigationBarState::Absolute:
+ pWnd = m_xAbsolute->GetWidget();
+ if (bAvailable)
+ m_xAbsolute->set_text(OUString::number(m_nCurrentPos + 1));
+ else
+ m_xAbsolute->set_text(OUString());
+ break;
+ case DbGridControlNavigationBarState::Text:
+ pWnd = m_xRecordText.get();
+ break;
+ case DbGridControlNavigationBarState::Of:
+ pWnd = m_xRecordOf.get();
+ break;
+ case DbGridControlNavigationBarState::Count:
+ {
+ pWnd = m_xRecordCount.get();
+ OUString aText;
+ if (bAvailable)
+ {
+ if (pParent->GetOptions() & DbGridControlOptions::Insert)
+ {
+ if (pParent->IsCurrentAppending() && !pParent->IsModified())
+ aText = OUString::number(pParent->GetRowCount());
+ else
+ aText = OUString::number(pParent->GetRowCount() - 1);
+ }
+ else
+ aText = OUString::number(pParent->GetRowCount());
+ if(!pParent->m_bRecordCountFinal)
+ aText += " *";
+ }
+ else
+ aText.clear();
+
+ // add the number of selected rows, if applicable
+ if (pParent->GetSelectRowCount())
+ {
+ OUString aExtendedInfo = aText + " (" +
+ OUString::number(pParent->GetSelectRowCount()) + ")";
+ m_xRecordCount->set_label(aExtendedInfo);
+ }
+ else
+ m_xRecordCount->set_label(aText);
+
+ pParent->SetRealRowCount(aText);
+ } break;
+ default: break;
+ }
+ DBG_ASSERT(pWnd, "no window");
+ if (!(pWnd && (pWnd->get_sensitive() != bAvailable)))
+ return;
+
+ // this "pWnd->IsEnabled() != bAvailable" is a little hack : Window::Enable always generates a user
+ // event (ImplGenerateMouseMove) even if nothing happened. This may lead to some unwanted effects, so we
+ // do this check.
+ // For further explanation see Bug 69900.
+ pWnd->set_sensitive(bAvailable);
+ if (!bAvailable)
+ {
+ if (pWnd == m_xNextBtn.get())
+ m_xNextRepeater->Stop();
+ else if (pWnd == m_xPrevBtn.get())
+ m_xPrevRepeater->Stop();
+ }
+}
+
+DbGridRow::DbGridRow():m_eStatus(GridRowStatus::Clean), m_bIsNew(true)
+{}
+
+DbGridRow::DbGridRow(CursorWrapper* pCur, bool bPaintCursor)
+ :m_bIsNew(false)
+{
+
+ if (pCur && pCur->Is())
+ {
+ Reference< XIndexAccess > xColumns(pCur->getColumns(), UNO_QUERY);
+ for (sal_Int32 i = 0; i < xColumns->getCount(); ++i)
+ {
+ Reference< XPropertySet > xColSet(
+ xColumns->getByIndex(i), css::uno::UNO_QUERY);
+ m_aVariants.emplace_back( new DataColumn(xColSet) );
+ }
+
+ if (pCur->rowDeleted())
+ m_eStatus = GridRowStatus::Deleted;
+ else
+ {
+ if (bPaintCursor)
+ m_eStatus = (pCur->isAfterLast() || pCur->isBeforeFirst()) ? GridRowStatus::Invalid : GridRowStatus::Clean;
+ else
+ {
+ const Reference< XPropertySet >& xSet = pCur->getPropertySet();
+ if (xSet.is())
+ {
+ m_bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
+ if (!m_bIsNew && (pCur->isAfterLast() || pCur->isBeforeFirst()))
+ m_eStatus = GridRowStatus::Invalid;
+ else if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)))
+ m_eStatus = GridRowStatus::Modified;
+ else
+ m_eStatus = GridRowStatus::Clean;
+ }
+ else
+ m_eStatus = GridRowStatus::Invalid;
+ }
+ }
+ if (!m_bIsNew && IsValid())
+ m_aBookmark = pCur->getBookmark();
+ else
+ m_aBookmark = Any();
+ }
+ else
+ m_eStatus = GridRowStatus::Invalid;
+}
+
+DbGridRow::~DbGridRow()
+{
+}
+
+void DbGridRow::SetState(CursorWrapper* pCur, bool bPaintCursor)
+{
+ if (pCur && pCur->Is())
+ {
+ if (pCur->rowDeleted())
+ {
+ m_eStatus = GridRowStatus::Deleted;
+ m_bIsNew = false;
+ }
+ else
+ {
+ m_eStatus = GridRowStatus::Clean;
+ if (!bPaintCursor)
+ {
+ const Reference< XPropertySet >& xSet = pCur->getPropertySet();
+ DBG_ASSERT(xSet.is(), "DbGridRow::SetState : invalid cursor !");
+
+ if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)))
+ m_eStatus = GridRowStatus::Modified;
+ m_bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
+ }
+ else
+ m_bIsNew = false;
+ }
+
+ try
+ {
+ if (!m_bIsNew && IsValid())
+ m_aBookmark = pCur->getBookmark();
+ else
+ m_aBookmark = Any();
+ }
+ catch(SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ m_aBookmark = Any();
+ m_eStatus = GridRowStatus::Invalid;
+ m_bIsNew = false;
+ }
+ }
+ else
+ {
+ m_aBookmark = Any();
+ m_eStatus = GridRowStatus::Invalid;
+ m_bIsNew = false;
+ }
+}
+
+DbGridControl::DbGridControl(
+ Reference< XComponentContext > const & _rxContext,
+ vcl::Window* pParent,
+ WinBits nBits)
+ :EditBrowseBox(pParent, EditBrowseBoxFlags::NONE, nBits, DEFAULT_BROWSE_MODE )
+ ,m_xContext(_rxContext)
+ ,m_aBar(VclPtr<NavigationBar>::Create(this))
+ ,m_nAsynAdjustEvent(nullptr)
+ ,m_pDataSourcePropListener(nullptr)
+ ,m_pFieldListeners(nullptr)
+ ,m_pGridListener(nullptr)
+ ,m_nSeekPos(-1)
+ ,m_nTotalCount(-1)
+ ,m_aNullDate(::dbtools::DBTypeConversion::getStandardDate())
+ ,m_nMode(DEFAULT_BROWSE_MODE)
+ ,m_nCurrentPos(-1)
+ ,m_nDeleteEvent(nullptr)
+ ,m_nOptions(DbGridControlOptions::Readonly)
+ ,m_nOptionMask(DbGridControlOptions::Insert | DbGridControlOptions::Update | DbGridControlOptions::Delete)
+ ,m_nLastColId(sal_uInt16(-1))
+ ,m_nLastRowId(-1)
+ ,m_bDesignMode(false)
+ ,m_bRecordCountFinal(false)
+ ,m_bNavigationBar(true)
+ ,m_bSynchDisplay(true)
+ ,m_bHandle(true)
+ ,m_bFilterMode(false)
+ ,m_bWantDestruction(false)
+ ,m_bPendingAdjustRows(false)
+ ,m_bHideScrollbars( false )
+ ,m_bUpdating(false)
+{
+
+ OUString sName(SvxResId(RID_STR_NAVIGATIONBAR));
+ m_aBar->SetAccessibleName(sName);
+ m_aBar->Show();
+ ImplInitWindow( InitWindowFacet::All );
+}
+
+void DbGridControl::InsertHandleColumn()
+{
+ // BrowseBox has problems when painting without a handleColumn (hide it here)
+ if (HasHandle())
+ BrowseBox::InsertHandleColumn(GetDefaultColumnWidth(OUString()));
+ else
+ BrowseBox::InsertHandleColumn(0);
+}
+
+void DbGridControl::Init()
+{
+ VclPtr<BrowserHeader> pNewHeader = CreateHeaderBar(this);
+ pHeader->SetMouseTransparent(false);
+
+ SetHeaderBar(pNewHeader);
+ SetMode(m_nMode);
+ SetCursorColor(Color(0xFF, 0, 0));
+
+ InsertHandleColumn();
+}
+
+DbGridControl::~DbGridControl()
+{
+ disposeOnce();
+}
+
+void DbGridControl::dispose()
+{
+ RemoveColumns();
+
+ m_bWantDestruction = true;
+ osl::MutexGuard aGuard(m_aDestructionSafety);
+ if (m_pFieldListeners)
+ DisconnectFromFields();
+ m_pCursorDisposeListener.reset();
+
+ if (m_nDeleteEvent)
+ Application::RemoveUserEvent(m_nDeleteEvent);
+
+ if (m_pDataSourcePropMultiplexer.is())
+ {
+ m_pDataSourcePropMultiplexer->dispose();
+ m_pDataSourcePropMultiplexer.clear(); // this should delete the multiplexer
+ delete m_pDataSourcePropListener;
+ m_pDataSourcePropListener = nullptr;
+ }
+ m_xRowSetListener.clear();
+
+ m_pDataCursor.reset();
+ m_pSeekCursor.reset();
+
+ m_aBar.disposeAndClear();
+
+ EditBrowseBox::dispose();
+}
+
+void DbGridControl::StateChanged( StateChangedType nType )
+{
+ EditBrowseBox::StateChanged( nType );
+
+ switch (nType)
+ {
+ case StateChangedType::Mirroring:
+ ImplInitWindow( InitWindowFacet::WritingMode );
+ Invalidate();
+ break;
+
+ case StateChangedType::Zoom:
+ {
+ ImplInitWindow( InitWindowFacet::Font );
+
+ // and give it a chance to rearrange
+ Point aPoint = GetControlArea().TopLeft();
+ sal_uInt16 nX = static_cast<sal_uInt16>(aPoint.X());
+ ArrangeControls(nX, static_cast<sal_uInt16>(aPoint.Y()));
+ ReserveControlArea(nX);
+ }
+ break;
+ case StateChangedType::ControlFont:
+ ImplInitWindow( InitWindowFacet::Font );
+ Invalidate();
+ break;
+ case StateChangedType::ControlForeground:
+ ImplInitWindow( InitWindowFacet::Foreground );
+ Invalidate();
+ break;
+ case StateChangedType::ControlBackground:
+ ImplInitWindow( InitWindowFacet::Background );
+ Invalidate();
+ break;
+ default:;
+ }
+}
+
+void DbGridControl::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ EditBrowseBox::DataChanged( rDCEvt );
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS ) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ ImplInitWindow( InitWindowFacet::All );
+ Invalidate();
+ }
+}
+
+void DbGridControl::Select()
+{
+ EditBrowseBox::Select();
+
+ // as the selected rows may have changed, update the according display in our navigation bar
+ m_aBar->InvalidateState(DbGridControlNavigationBarState::Count);
+
+ if (m_pGridListener)
+ m_pGridListener->selectionChanged();
+}
+
+void DbGridControl::ImplInitWindow( const InitWindowFacet _eInitWhat )
+{
+ for (auto const & pCol : m_aColumns)
+ {
+ pCol->ImplInitWindow( GetDataWindow(), _eInitWhat );
+ }
+
+ if ( _eInitWhat & InitWindowFacet::WritingMode )
+ {
+ if ( m_bNavigationBar )
+ {
+ m_aBar->EnableRTL( IsRTLEnabled() );
+ }
+ }
+
+ if ( _eInitWhat & InitWindowFacet::Font )
+ {
+ if ( m_bNavigationBar )
+ {
+ if ( IsControlFont() )
+ m_aBar->SetControlFont( GetControlFont() );
+ else
+ m_aBar->SetControlFont();
+
+ m_aBar->SetZoom( GetZoom() );
+ }
+ }
+
+ if ( !(_eInitWhat & InitWindowFacet::Background) )
+ return;
+
+ if (IsControlBackground())
+ {
+ GetDataWindow().SetBackground(GetControlBackground());
+ GetDataWindow().SetControlBackground(GetControlBackground());
+ GetDataWindow().GetOutDev()->SetFillColor(GetControlBackground());
+ }
+ else
+ {
+ GetDataWindow().SetControlBackground();
+ GetDataWindow().GetOutDev()->SetFillColor(GetOutDev()->GetFillColor());
+ }
+}
+
+void DbGridControl::RemoveRows(bool bNewCursor)
+{
+ // Did the data cursor change?
+ if (!bNewCursor)
+ {
+ m_pSeekCursor.reset();
+ m_xPaintRow = m_xDataRow = m_xEmptyRow = m_xCurrentRow = m_xSeekRow = nullptr;
+ m_nCurrentPos = m_nSeekPos = -1;
+ m_nOptions = DbGridControlOptions::Readonly;
+
+ RowRemoved(0, GetRowCount(), false);
+ m_nTotalCount = -1;
+ }
+ else
+ {
+ RemoveRows();
+ }
+}
+
+void DbGridControl::RemoveRows()
+{
+ // we're going to remove all columns and all row, so deactivate the current cell
+ if (IsEditing())
+ DeactivateCell();
+
+ // de-initialize all columns
+ // if there are columns, free all controllers
+ for (auto const & pColumn : m_aColumns)
+ pColumn->Clear();
+
+ m_pSeekCursor.reset();
+ m_pDataCursor.reset();
+
+ m_xPaintRow = m_xDataRow = m_xEmptyRow = m_xCurrentRow = m_xSeekRow = nullptr;
+ m_nCurrentPos = m_nSeekPos = m_nTotalCount = -1;
+ m_nOptions = DbGridControlOptions::Readonly;
+
+ // reset number of sentences to zero in the browser
+ EditBrowseBox::RemoveRows();
+ m_aBar->InvalidateAll(m_nCurrentPos, true);
+}
+
+void DbGridControl::ArrangeControls(sal_uInt16& nX, sal_uInt16 nY)
+{
+ // positioning of the controls
+ if (m_bNavigationBar)
+ {
+ tools::Rectangle aRect(GetControlArea());
+ m_aBar->SetPosSizePixel(Point(0, nY + 1), Size(aRect.GetSize().Width(), aRect.GetSize().Height() - 1));
+ nX = m_aBar->ArrangeControls();
+ }
+}
+
+void DbGridControl::EnableHandle(bool bEnable)
+{
+ if (m_bHandle == bEnable)
+ return;
+
+ // HandleColumn is only hidden because there are a lot of problems while painting otherwise
+ RemoveColumn( HandleColumnId );
+ m_bHandle = bEnable;
+ InsertHandleColumn();
+}
+
+namespace
+{
+ bool adjustModeForScrollbars( BrowserMode& _rMode, bool _bNavigationBar, bool _bHideScrollbars )
+ {
+ BrowserMode nOldMode = _rMode;
+
+ if ( !_bNavigationBar )
+ {
+ _rMode &= ~BrowserMode::AUTO_HSCROLL;
+ }
+
+ if ( _bHideScrollbars )
+ {
+ _rMode |= BrowserMode::NO_HSCROLL | BrowserMode::NO_VSCROLL;
+ _rMode &= ~BrowserMode( BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL );
+ }
+ else
+ {
+ _rMode |= BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL;
+ _rMode &= ~BrowserMode( BrowserMode::NO_HSCROLL | BrowserMode::NO_VSCROLL );
+ }
+
+ // note: if we have a navigation bar, we always have an AUTO_HSCROLL. In particular,
+ // _bHideScrollbars is ignored then
+ if ( _bNavigationBar )
+ {
+ _rMode |= BrowserMode::AUTO_HSCROLL;
+ _rMode &= ~BrowserMode::NO_HSCROLL;
+ }
+
+ return nOldMode != _rMode;
+ }
+}
+
+void DbGridControl::EnableNavigationBar(bool bEnable)
+{
+ if (m_bNavigationBar == bEnable)
+ return;
+
+ m_bNavigationBar = bEnable;
+
+ if (bEnable)
+ {
+ m_aBar->Show();
+ m_aBar->Enable();
+ m_aBar->InvalidateAll(m_nCurrentPos, true);
+
+ if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
+ SetMode( m_nMode );
+
+ // get size of the reserved ControlArea
+ Point aPoint = GetControlArea().TopLeft();
+ sal_uInt16 nX = static_cast<sal_uInt16>(aPoint.X());
+
+ ArrangeControls(nX, static_cast<sal_uInt16>(aPoint.Y()));
+ ReserveControlArea(nX);
+ }
+ else
+ {
+ m_aBar->Hide();
+ m_aBar->Disable();
+
+ if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
+ SetMode( m_nMode );
+
+ ReserveControlArea();
+ }
+}
+
+DbGridControlOptions DbGridControl::SetOptions(DbGridControlOptions nOpt)
+{
+ DBG_ASSERT(!m_xCurrentRow.is() || !m_xCurrentRow->IsModified(),
+ "DbGridControl::SetOptions : please do not call when editing a record (things are much easier this way ;) !");
+
+ // for the next setDataSource (which is triggered by a refresh, for instance)
+ m_nOptionMask = nOpt;
+
+ // normalize the new options
+ Reference< XPropertySet > xDataSourceSet = m_pDataCursor->getPropertySet();
+ if (xDataSourceSet.is())
+ {
+ // check what kind of options are available
+ sal_Int32 nPrivileges = 0;
+ xDataSourceSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
+ if ((nPrivileges & Privilege::INSERT) == 0)
+ nOpt &= ~DbGridControlOptions::Insert;
+ if ((nPrivileges & Privilege::UPDATE) == 0)
+ nOpt &= ~DbGridControlOptions::Update;
+ if ((nPrivileges & Privilege::DELETE) == 0)
+ nOpt &= ~DbGridControlOptions::Delete;
+ }
+ else
+ nOpt = DbGridControlOptions::Readonly;
+
+ // need to do something after that ?
+ if (nOpt == m_nOptions)
+ return m_nOptions;
+
+ // the 'update' option only affects our BrowserMode (with or w/o focus rect)
+ BrowserMode nNewMode = m_nMode;
+ if (!(m_nMode & BrowserMode::CURSOR_WO_FOCUS))
+ {
+ if (nOpt & DbGridControlOptions::Update)
+ nNewMode |= BrowserMode::HIDECURSOR;
+ else
+ nNewMode &= ~BrowserMode::HIDECURSOR;
+ }
+ else
+ nNewMode &= ~BrowserMode::HIDECURSOR;
+ // should not be necessary if EnablePermanentCursor is used to change the cursor behaviour, but to be sure ...
+
+ if (nNewMode != m_nMode)
+ {
+ SetMode(nNewMode);
+ m_nMode = nNewMode;
+ }
+
+ // _after_ setting the mode because this results in an ActivateCell
+ DeactivateCell();
+
+ bool bInsertChanged = (nOpt & DbGridControlOptions::Insert) != (m_nOptions & DbGridControlOptions::Insert);
+ m_nOptions = nOpt;
+ // we need to set this before the code below because it indirectly uses m_nOptions
+
+ // the 'insert' option affects our empty row
+ if (bInsertChanged)
+ {
+ if (m_nOptions & DbGridControlOptions::Insert)
+ { // the insert option is to be set
+ m_xEmptyRow = new DbGridRow();
+ RowInserted(GetRowCount());
+ }
+ else
+ { // the insert option is to be reset
+ m_xEmptyRow = nullptr;
+ if ((GetCurRow() == GetRowCount() - 1) && (GetCurRow() > 0))
+ GoToRowColumnId(GetCurRow() - 1, GetCurColumnId());
+ RowRemoved(GetRowCount());
+ }
+ }
+
+ // the 'delete' options has no immediate consequences
+
+ ActivateCell();
+ Invalidate();
+ return m_nOptions;
+}
+
+void DbGridControl::ForceHideScrollbars()
+{
+ if ( m_bHideScrollbars )
+ return;
+
+ m_bHideScrollbars = true;
+
+ if ( adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars ) )
+ SetMode( m_nMode );
+}
+
+void DbGridControl::EnablePermanentCursor(bool bEnable)
+{
+ if (IsPermanentCursorEnabled() == bEnable)
+ return;
+
+ if (bEnable)
+ {
+ m_nMode &= ~BrowserMode::HIDECURSOR; // without this BrowserMode::CURSOR_WO_FOCUS won't have any affect
+ m_nMode |= BrowserMode::CURSOR_WO_FOCUS;
+ }
+ else
+ {
+ if (m_nOptions & DbGridControlOptions::Update)
+ m_nMode |= BrowserMode::HIDECURSOR; // no cursor at all
+ else
+ m_nMode &= ~BrowserMode::HIDECURSOR; // at least the "non-permanent" cursor
+
+ m_nMode &= ~BrowserMode::CURSOR_WO_FOCUS;
+ }
+ SetMode(m_nMode);
+
+ bool bWasEditing = IsEditing();
+ DeactivateCell();
+ if (bWasEditing)
+ ActivateCell();
+}
+
+bool DbGridControl::IsPermanentCursorEnabled() const
+{
+ return (m_nMode & BrowserMode::CURSOR_WO_FOCUS) && !(m_nMode & BrowserMode::HIDECURSOR);
+}
+
+void DbGridControl::refreshController(sal_uInt16 _nColId, GrantControlAccess /*_aAccess*/)
+{
+ if ((GetCurColumnId() == _nColId) && IsEditing())
+ { // the controller which is currently active needs to be refreshed
+ DeactivateCell();
+ ActivateCell();
+ }
+}
+
+void DbGridControl::setDataSource(const Reference< XRowSet >& _xCursor, DbGridControlOptions nOpts)
+{
+ if (!_xCursor.is() && !m_pDataCursor)
+ return;
+
+ if (m_pDataSourcePropMultiplexer.is())
+ {
+ m_pDataSourcePropMultiplexer->dispose();
+ m_pDataSourcePropMultiplexer.clear(); // this should delete the multiplexer
+ delete m_pDataSourcePropListener;
+ m_pDataSourcePropListener = nullptr;
+ }
+ m_xRowSetListener.clear();
+
+ // is the new cursor valid ?
+ // the cursor is only valid if it contains some columns
+ // if there is no cursor or the cursor is not valid we have to clean up and leave
+ if (!_xCursor.is() || !Reference< XColumnsSupplier > (_xCursor, UNO_QUERY_THROW)->getColumns()->hasElements())
+ {
+ RemoveRows();
+ return;
+ }
+
+ // did the data cursor change?
+ sal_uInt16 nCurPos = GetColumnPos(GetCurColumnId());
+
+ SetUpdateMode(false);
+ RemoveRows();
+ DisconnectFromFields();
+
+ m_pCursorDisposeListener.reset();
+
+ {
+ ::osl::MutexGuard aGuard(m_aAdjustSafety);
+ if (m_nAsynAdjustEvent)
+ {
+ // the adjust was thought to work with the old cursor which we don't have anymore
+ RemoveUserEvent(m_nAsynAdjustEvent);
+ m_nAsynAdjustEvent = nullptr;
+ }
+ }
+
+ // get a new formatter and data cursor
+ m_xFormatter = nullptr;
+ Reference< css::util::XNumberFormatsSupplier > xSupplier = getNumberFormats(getConnection(_xCursor), true);
+ if (xSupplier.is())
+ {
+ m_xFormatter = css::util::NumberFormatter::create(m_xContext);
+ m_xFormatter->attachNumberFormatsSupplier(xSupplier);
+
+ // retrieve the datebase of the Numberformatter
+ try
+ {
+ xSupplier->getNumberFormatSettings()->getPropertyValue("NullDate") >>= m_aNullDate;
+ }
+ catch(Exception&)
+ {
+ }
+ }
+
+ m_pDataCursor.reset(new CursorWrapper(_xCursor));
+
+ // now create a cursor for painting rows
+ // we need that cursor only if we are not in insert only mode
+ Reference< XResultSet > xClone;
+ Reference< XResultSetAccess > xAccess( _xCursor, UNO_QUERY );
+ try
+ {
+ xClone = xAccess.is() ? xAccess->createResultSet() : Reference< XResultSet > ();
+ }
+ catch(Exception&)
+ {
+ }
+ if (xClone.is())
+ m_pSeekCursor.reset(new CursorWrapper(xClone));
+
+ // property listening on the data source
+ // (Normally one class would be sufficient : the multiplexer which could forward the property change to us.
+ // But for that we would have been derived from ::comphelper::OPropertyChangeListener, which isn't exported.
+ // So we introduce a second class, which is a ::comphelper::OPropertyChangeListener (in the implementation file we know this class)
+ // and forwards the property changes to our special method "DataSourcePropertyChanged".)
+ if (m_pDataCursor)
+ {
+ m_pDataSourcePropListener = new FmXGridSourcePropListener(this);
+ m_pDataSourcePropMultiplexer = new ::comphelper::OPropertyChangeMultiplexer(m_pDataSourcePropListener, m_pDataCursor->getPropertySet() );
+ m_pDataSourcePropMultiplexer->addProperty(FM_PROP_ISMODIFIED);
+ m_pDataSourcePropMultiplexer->addProperty(FM_PROP_ISNEW);
+ }
+
+ BrowserMode nOldMode = m_nMode;
+ if (m_pSeekCursor)
+ {
+ try
+ {
+ Reference< XPropertySet > xSet(_xCursor, UNO_QUERY);
+ if (xSet.is())
+ {
+ // check what kind of options are available
+ sal_Int32 nConcurrency = ResultSetConcurrency::READ_ONLY;
+ xSet->getPropertyValue(FM_PROP_RESULTSET_CONCURRENCY) >>= nConcurrency;
+
+ if ( ResultSetConcurrency::UPDATABLE == nConcurrency )
+ {
+ sal_Int32 nPrivileges = 0;
+ xSet->getPropertyValue(FM_PROP_PRIVILEGES) >>= nPrivileges;
+
+ // Insert Option should be set if insert only otherwise you won't see any rows
+ // and no insertion is possible
+ if ((m_nOptionMask & DbGridControlOptions::Insert)
+ && ((nPrivileges & Privilege::INSERT) == Privilege::INSERT) && (nOpts & DbGridControlOptions::Insert))
+ m_nOptions |= DbGridControlOptions::Insert;
+ if ((m_nOptionMask & DbGridControlOptions::Update)
+ && ((nPrivileges & Privilege::UPDATE) == Privilege::UPDATE) && (nOpts & DbGridControlOptions::Update))
+ m_nOptions |= DbGridControlOptions::Update;
+ if ((m_nOptionMask & DbGridControlOptions::Delete)
+ && ((nPrivileges & Privilege::DELETE) == Privilege::DELETE) && (nOpts & DbGridControlOptions::Delete))
+ m_nOptions |= DbGridControlOptions::Delete;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ bool bPermanentCursor = IsPermanentCursorEnabled();
+ m_nMode = DEFAULT_BROWSE_MODE;
+
+ if ( bPermanentCursor )
+ {
+ m_nMode |= BrowserMode::CURSOR_WO_FOCUS;
+ m_nMode &= ~BrowserMode::HIDECURSOR;
+ }
+ else
+ {
+ // updates are allowed -> no focus rectangle
+ if ( m_nOptions & DbGridControlOptions::Update )
+ m_nMode |= BrowserMode::HIDECURSOR;
+ }
+
+ m_nMode |= BrowserMode::MULTISELECTION;
+
+ adjustModeForScrollbars( m_nMode, m_bNavigationBar, m_bHideScrollbars );
+
+ Reference< XColumnsSupplier > xSupplyColumns(_xCursor, UNO_QUERY);
+ if (xSupplyColumns.is())
+ InitColumnsByFields(Reference< XIndexAccess > (xSupplyColumns->getColumns(), UNO_QUERY));
+
+ ConnectToFields();
+ }
+
+ sal_uInt32 nRecordCount(0);
+
+ if (m_pSeekCursor)
+ {
+ Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
+ xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
+ m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
+
+ m_xRowSetListener = new RowSetEventListener(this);
+ Reference< XRowsChangeBroadcaster> xChangeBroad(xSet,UNO_QUERY);
+ if ( xChangeBroad.is( ) )
+ xChangeBroad->addRowsChangeListener(m_xRowSetListener);
+
+
+ // insert the currently known rows
+ // and one row if we are able to insert rows
+ if (m_nOptions & DbGridControlOptions::Insert)
+ {
+ // insert the empty row for insertion
+ m_xEmptyRow = new DbGridRow();
+ ++nRecordCount;
+ }
+ if (nRecordCount)
+ {
+ m_xPaintRow = m_xSeekRow = new DbGridRow(m_pSeekCursor.get(), true);
+ m_xDataRow = new DbGridRow(m_pDataCursor.get(), false);
+ RowInserted(0, nRecordCount, false);
+
+ if (m_xSeekRow->IsValid())
+ try
+ {
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ m_nSeekPos = -1;
+ }
+ }
+ else
+ {
+ // no rows so we don't need a seekcursor
+ m_pSeekCursor.reset();
+ }
+ }
+
+ // go to the old column
+ if (nCurPos == BROWSER_INVALIDID || nCurPos >= ColCount())
+ nCurPos = 0;
+
+ // Column zero is a valid choice and guaranteed to exist,
+ // but invisible to the user; if we have at least one
+ // user-visible column, go to that one.
+ if (nCurPos == 0 && ColCount() > 1)
+ nCurPos = 1;
+
+ // there are rows so go to the selected current column
+ if (nRecordCount)
+ GoToRowColumnId(0, GetColumnId(nCurPos));
+ // else stop the editing if necessary
+ else if (IsEditing())
+ DeactivateCell();
+
+ // now reset the mode
+ if (m_nMode != nOldMode)
+ SetMode(m_nMode);
+
+ // RecalcRows was already called while resizing
+ if (!IsResizing() && GetRowCount())
+ RecalcRows(GetTopRow(), GetVisibleRows(), true);
+
+ m_aBar->InvalidateAll(m_nCurrentPos, true);
+ SetUpdateMode(true);
+
+ // start listening on the seek cursor
+ if (m_pSeekCursor)
+ m_pCursorDisposeListener.reset(new DisposeListenerGridBridge(*this, Reference< XComponent > (Reference< XInterface >(*m_pSeekCursor), UNO_QUERY)));
+}
+
+void DbGridControl::RemoveColumns()
+{
+ if ( !isDisposed() && IsEditing() )
+ DeactivateCell();
+
+ m_aColumns.clear();
+
+ EditBrowseBox::RemoveColumns();
+}
+
+std::unique_ptr<DbGridColumn> DbGridControl::CreateColumn(sal_uInt16 nId)
+{
+ return std::unique_ptr<DbGridColumn>(new DbGridColumn(nId, *this));
+}
+
+sal_uInt16 DbGridControl::AppendColumn(const OUString& rName, sal_uInt16 nWidth, sal_uInt16 nModelPos, sal_uInt16 nId)
+{
+ DBG_ASSERT(nId == BROWSER_INVALIDID, "DbGridControl::AppendColumn : I want to set the ID myself ...");
+ sal_uInt16 nRealPos = nModelPos;
+ if (nModelPos != HEADERBAR_APPEND)
+ {
+ // calc the view pos. we can't use our converting functions because the new column
+ // has no VCL-representation, yet.
+ sal_Int16 nViewPos = nModelPos;
+ while (nModelPos--)
+ {
+ if ( m_aColumns[ nModelPos ]->IsHidden() )
+ --nViewPos;
+ }
+ // restore nModelPos, we need it later
+ nModelPos = nRealPos;
+ // the position the base class gets is the view pos + 1 (because of the handle column)
+ nRealPos = nViewPos + 1;
+ }
+
+ // calculate the new id
+ for (nId=1; (GetModelColumnPos(nId) != GRID_COLUMN_NOT_FOUND) && size_t(nId) <= m_aColumns.size(); ++nId)
+ ;
+ DBG_ASSERT(GetViewColumnPos(nId) == GRID_COLUMN_NOT_FOUND, "DbGridControl::AppendColumn : inconsistent internal state !");
+ // my column's models say "there is no column with id nId", but the view (the base class) says "there is a column ..."
+
+ EditBrowseBox::AppendColumn(rName, nWidth, nRealPos, nId);
+ if (nModelPos == HEADERBAR_APPEND)
+ m_aColumns.push_back( CreateColumn(nId) );
+ else
+ m_aColumns.insert( m_aColumns.begin() + nModelPos, CreateColumn(nId) );
+
+ return nId;
+}
+
+void DbGridControl::RemoveColumn(sal_uInt16 nId)
+{
+ EditBrowseBox::RemoveColumn(nId);
+
+ const sal_uInt16 nIndex = GetModelColumnPos(nId);
+ if(nIndex != GRID_COLUMN_NOT_FOUND)
+ {
+ m_aColumns.erase( m_aColumns.begin()+nIndex );
+ }
+}
+
+void DbGridControl::ColumnMoved(sal_uInt16 nId)
+{
+ EditBrowseBox::ColumnMoved(nId);
+
+ // remove the col from the model
+ sal_uInt16 nOldModelPos = GetModelColumnPos(nId);
+#ifdef DBG_UTIL
+ DbGridColumn* pCol = m_aColumns[ nOldModelPos ].get();
+ DBG_ASSERT(!pCol->IsHidden(), "DbGridControl::ColumnMoved : moved a hidden col ? how this ?");
+#endif
+
+ // for the new model pos we can't use GetModelColumnPos because we are altering the model at the moment
+ // so the method won't work (in fact it would return the old model pos)
+
+ // the new view pos is calculated easily
+ sal_uInt16 nNewViewPos = GetViewColumnPos(nId);
+
+ // from that we can compute the new model pos
+ size_t nNewModelPos;
+ for (nNewModelPos = 0; nNewModelPos < m_aColumns.size(); ++nNewModelPos)
+ {
+ if (!m_aColumns[ nNewModelPos ]->IsHidden())
+ {
+ if (!nNewViewPos)
+ break;
+ else
+ --nNewViewPos;
+ }
+ }
+ DBG_ASSERT( nNewModelPos < m_aColumns.size(), "DbGridControl::ColumnMoved : could not find the new model position !");
+
+ // this will work. of course the model isn't fully consistent with our view right now, but let's
+ // look at the situation : a column has been moved with in the VIEW from pos m to n, say m<n (in the
+ // other case we can use analogue arguments).
+ // All cols k with m<k<=n have been shifted left on pos, the former col m now has pos n.
+ // In the model this affects a range of cols x to y, where x<=m and y<=n. And the number of hidden cols
+ // within this range is constant, so we may calculate the view pos from the model pos in the above way.
+
+ // for instance, let's look at a grid with six columns where the third one is hidden. this will
+ // initially look like this :
+
+ // +---+---+---+---+---+---+
+ // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
+ // +---+---+---+---+---+---+
+ // ID | 1 | 2 | 3 | 4 | 5 | 6 |
+ // +---+---+---+---+---+---+
+ // view pos | 0 | 1 | - | 2 | 3 | 4 |
+ // +---+---+---+---+---+---+
+
+ // if we move the column at (view) pos 1 to (view) pos 3 we have :
+
+ // +---+---+---+---+---+---+
+ // model pos | 0 | 3 |*2*| 4 | 1 | 5 | // not reflecting the changes, yet
+ // +---+---+---+---+---+---+
+ // ID | 1 | 4 | 3 | 5 | 2 | 6 | // already reflecting the changes
+ // +---+---+---+---+---+---+
+ // view pos | 0 | 1 | - | 2 | 3 | 4 |
+ // +---+---+---+---+---+---+
+
+ // or, sorted by the out-of-date model positions :
+
+ // +---+---+---+---+---+---+
+ // model pos | 0 | 1 |*2*| 3 | 4 | 5 |
+ // +---+---+---+---+---+---+
+ // ID | 1 | 2 | 3 | 4 | 5 | 6 |
+ // +---+---+---+---+---+---+
+ // view pos | 0 | 3 | - | 1 | 2 | 4 |
+ // +---+---+---+---+---+---+
+
+ // We know the new view pos (3) of the moved column because our base class tells us. So we look at our
+ // model for the 4th (the pos is zero-based) visible column, it is at (model) position 4. And this is
+ // exactly the pos where we have to re-insert our column's model, so it looks ike this :
+
+ // +---+---+---+---+---+---+
+ // model pos | 0 |*1*| 2 | 3 | 4 | 5 |
+ // +---+---+---+---+---+---+
+ // ID | 1 | 3 | 4 | 5 | 2 | 6 |
+ // +---+---+---+---+---+---+
+ // view pos | 0 | - | 1 | 2 | 3 | 4 |
+ // +---+---+---+---+---+---+
+
+ // Now, all is consistent again.
+ // (except of the hidden column : The cycling of the cols occurred on the model, not on the view. maybe
+ // the user expected the latter but there really is no good argument against our method ;) ...)
+
+ // And no, this large explanation isn't just because I wanted to play a board game or something like
+ // that. It's because it took me a while to see it myself, and the whole theme (hidden cols, model col
+ // positions, view col positions) is really painful (at least for me) so the above pictures helped me a lot ;)
+
+ auto temp = std::move(m_aColumns[ nOldModelPos ]);
+ m_aColumns.erase( m_aColumns.begin() + nOldModelPos );
+ m_aColumns.insert( m_aColumns.begin() + nNewModelPos, std::move(temp) );
+}
+
+bool DbGridControl::SeekRow(sal_Int32 nRow)
+{
+ // in filter mode or in insert only mode we don't have any cursor!
+ if ( !SeekCursor( nRow ) )
+ return false;
+
+ if ( IsFilterMode() )
+ {
+ DBG_ASSERT( IsFilterRow( nRow ), "DbGridControl::SeekRow(): No filter row, wrong mode" );
+ m_xPaintRow = m_xEmptyRow;
+ }
+ else
+ {
+ // on the current position we have to take the current row for display as we want
+ // to have the most recent values for display
+ if ( ( nRow == m_nCurrentPos ) && getDisplaySynchron() )
+ m_xPaintRow = m_xCurrentRow;
+ // seek to the empty insert row
+ else if ( IsInsertionRow( nRow ) )
+ m_xPaintRow = m_xEmptyRow;
+ else
+ {
+ m_xSeekRow->SetState( m_pSeekCursor.get(), true );
+ m_xPaintRow = m_xSeekRow;
+ }
+ }
+
+ EditBrowseBox::SeekRow(nRow);
+
+ return m_nSeekPos >= 0;
+}
+
+// Is called whenever the visible amount of data changes
+void DbGridControl::VisibleRowsChanged( sal_Int32 nNewTopRow, sal_uInt16 nLinesOnScreen )
+{
+ RecalcRows(nNewTopRow, nLinesOnScreen, false);
+}
+
+void DbGridControl::RecalcRows(sal_Int32 nNewTopRow, sal_uInt16 nLinesOnScreen, bool bUpdateCursor)
+{
+ // If no cursor -> no rows in the browser.
+ if (!m_pSeekCursor)
+ {
+ DBG_ASSERT(GetRowCount() == 0,"DbGridControl: without cursor no rows are allowed to be there");
+ return;
+ }
+
+ // ignore any implicitly made updates
+ bool bDisablePaint = !bUpdateCursor && IsPaintEnabled();
+ if (bDisablePaint)
+ EnablePaint(false);
+
+ // adjust cache to the visible area
+ Reference< XPropertySet > xSet = m_pSeekCursor->getPropertySet();
+ sal_Int32 nCacheSize = 0;
+ xSet->getPropertyValue(FM_PROP_FETCHSIZE) >>= nCacheSize;
+ bool bCacheAligned = false;
+ // no further cursor movements after initializing (m_nSeekPos < 0) because it is already
+ // positioned on the first sentence
+ tools::Long nDelta = nNewTopRow - GetTopRow();
+ // limit for relative positioning
+ tools::Long nLimit = nCacheSize ? nCacheSize / 2 : 0;
+
+ // more lines on screen than in cache
+ if (nLimit < nLinesOnScreen)
+ {
+ Any aCacheSize;
+ aCacheSize <<= sal_Int32(nLinesOnScreen*2);
+ xSet->setPropertyValue(FM_PROP_FETCHSIZE, aCacheSize);
+ // here we need to update the cursor for sure
+ bUpdateCursor = true;
+ bCacheAligned = true;
+ nLimit = nLinesOnScreen;
+ }
+
+ // In the following, all positionings are done as it is
+ // ensured that there are enough lines in the data cache
+
+ // window goes downwards with less than two windows difference or
+ // the cache was updated and no rowcount yet
+ if (nDelta < nLimit && (nDelta > 0
+ || (bCacheAligned && m_nTotalCount < 0)) )
+ SeekCursor(nNewTopRow + nLinesOnScreen - 1);
+ else if (nDelta < 0 && std::abs(nDelta) < nLimit)
+ SeekCursor(nNewTopRow);
+ else if (nDelta != 0 || bUpdateCursor)
+ SeekCursor(nNewTopRow, true);
+
+ AdjustRows();
+
+ // ignore any updates implicit made
+ EnablePaint(true);
+}
+
+void DbGridControl::RowInserted(sal_Int32 nRow, sal_Int32 nNumRows, bool bDoPaint)
+{
+ if (!nNumRows)
+ return;
+
+ if (m_bRecordCountFinal && m_nTotalCount < 0)
+ {
+ // if we have an insert row we have to reduce to count by 1
+ // as the total count reflects only the existing rows in database
+ m_nTotalCount = GetRowCount() + nNumRows;
+ if (m_xEmptyRow.is())
+ --m_nTotalCount;
+ }
+ else if (m_nTotalCount >= 0)
+ m_nTotalCount += nNumRows;
+
+ EditBrowseBox::RowInserted(nRow, nNumRows, bDoPaint);
+ m_aBar->InvalidateState(DbGridControlNavigationBarState::Count);
+}
+
+void DbGridControl::RowRemoved(sal_Int32 nRow, sal_Int32 nNumRows, bool bDoPaint)
+{
+ if (!nNumRows)
+ return;
+
+ if (m_bRecordCountFinal && m_nTotalCount < 0)
+ {
+ m_nTotalCount = GetRowCount() - nNumRows;
+ // if we have an insert row reduce by 1
+ if (m_xEmptyRow.is())
+ --m_nTotalCount;
+ }
+ else if (m_nTotalCount >= 0)
+ m_nTotalCount -= nNumRows;
+
+ EditBrowseBox::RowRemoved(nRow, nNumRows, bDoPaint);
+ m_aBar->InvalidateState(DbGridControlNavigationBarState::Count);
+}
+
+void DbGridControl::AdjustRows()
+{
+ if (!m_pSeekCursor)
+ return;
+
+ Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
+
+ // refresh RecordCount
+ sal_Int32 nRecordCount = 0;
+ xSet->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
+ if (!m_bRecordCountFinal)
+ m_bRecordCountFinal = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ROWCOUNTFINAL));
+
+ // Did the number of rows change?
+ // Here we need to consider that there might be an additional row for adding new data sets
+
+ // add additional AppendRow for insertion
+ if (m_nOptions & DbGridControlOptions::Insert)
+ ++nRecordCount;
+
+ // If there is currently an insertion, so do not consider this added row in RecordCount or Appendrow
+ if (!IsUpdating() && m_bRecordCountFinal && IsModified() && m_xCurrentRow != m_xEmptyRow &&
+ m_xCurrentRow->IsNew())
+ ++nRecordCount;
+ // ensured with !m_bUpdating: otherwise the edited data set (that SaveRow added and why this
+ // method was called) would be called twice (if m_bUpdating == sal_True): once in RecordCount
+ // and a second time here (60787 - FS)
+
+ if (nRecordCount != GetRowCount())
+ {
+ tools::Long nDelta = GetRowCount() - static_cast<tools::Long>(nRecordCount);
+ if (nDelta > 0) // too many
+ {
+ RowRemoved(GetRowCount() - nDelta, nDelta, false);
+ // some rows are gone, thus, repaint starting at the current position
+ Invalidate();
+
+ sal_Int32 nNewPos = AlignSeekCursor();
+ if (m_bSynchDisplay)
+ EditBrowseBox::GoToRow(nNewPos);
+
+ SetCurrent(nNewPos);
+ // there are rows so go to the selected current column
+ if (nRecordCount)
+ GoToRowColumnId(nNewPos, GetColumnId(GetCurColumnId()));
+ if (!IsResizing() && GetRowCount())
+ RecalcRows(GetTopRow(), GetVisibleRows(), true);
+ m_aBar->InvalidateAll(m_nCurrentPos, true);
+ }
+ else // too few
+ RowInserted(GetRowCount(), -nDelta);
+ }
+
+ if (m_bRecordCountFinal && m_nTotalCount < 0)
+ {
+ if (m_nOptions & DbGridControlOptions::Insert)
+ m_nTotalCount = GetRowCount() - 1;
+ else
+ m_nTotalCount = GetRowCount();
+ }
+ m_aBar->InvalidateState(DbGridControlNavigationBarState::Count);
+}
+
+svt::EditBrowseBox::RowStatus DbGridControl::GetRowStatus(sal_Int32 nRow) const
+{
+ if (IsFilterRow(nRow))
+ return EditBrowseBox::FILTER;
+ else if (m_nCurrentPos >= 0 && nRow == m_nCurrentPos)
+ {
+ // new row
+ if (!IsValid(m_xCurrentRow))
+ return EditBrowseBox::DELETED;
+ else if (IsModified())
+ return EditBrowseBox::MODIFIED;
+ else if (m_xCurrentRow->IsNew())
+ return EditBrowseBox::CURRENTNEW;
+ else
+ return EditBrowseBox::CURRENT;
+ }
+ else if (IsInsertionRow(nRow))
+ return EditBrowseBox::NEW;
+ else if (!IsValid(m_xSeekRow))
+ return EditBrowseBox::DELETED;
+ else
+ return EditBrowseBox::CLEAN;
+}
+
+void DbGridControl::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId) const
+{
+ if (!IsValid(m_xPaintRow))
+ return;
+
+ size_t Location = GetModelColumnPos(nColumnId);
+ DbGridColumn* pColumn = (Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
+ if (pColumn)
+ {
+ tools::Rectangle aArea(rRect);
+ if ((GetMode() & BrowserMode::CURSOR_WO_FOCUS) == BrowserMode::CURSOR_WO_FOCUS)
+ {
+ aArea.AdjustTop(1 );
+ aArea.AdjustBottom( -1 );
+ }
+ pColumn->Paint(rDev, aArea, m_xPaintRow.get(), getNumberFormatter());
+ }
+}
+
+bool DbGridControl::CursorMoving(sal_Int32 nNewRow, sal_uInt16 nNewCol)
+{
+
+ DeactivateCell( false );
+
+ if ( m_pDataCursor
+ && ( m_nCurrentPos != nNewRow )
+ && !SetCurrent( nNewRow )
+ )
+ {
+ ActivateCell();
+ return false;
+ }
+
+ return EditBrowseBox::CursorMoving( nNewRow, nNewCol );
+}
+
+bool DbGridControl::SetCurrent(sal_Int32 nNewRow)
+{
+ // Each movement of the datacursor must start with BeginCursorAction and end with
+ // EndCursorAction to block all notifications during the movement
+ BeginCursorAction();
+
+ try
+ {
+ // compare positions
+ if (SeekCursor(nNewRow))
+ {
+ if (IsFilterRow(nNewRow)) // special mode for filtering
+ {
+ m_xCurrentRow = m_xDataRow = m_xPaintRow = m_xEmptyRow;
+ m_nCurrentPos = nNewRow;
+ }
+ else
+ {
+ bool bNewRowInserted = false;
+ // Should we go to the insertrow ?
+ if (IsInsertionRow(nNewRow))
+ {
+ // to we need to move the cursor to the insert row?
+ // we need to insert the if the current row isn't the insert row or if the
+ // cursor triggered the move by itself and we need a reinitialization of the row
+ Reference< XPropertySet > xCursorProps = m_pDataCursor->getPropertySet();
+ if ( !::comphelper::getBOOL(xCursorProps->getPropertyValue(FM_PROP_ISNEW)) )
+ {
+ Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
+ xUpdateCursor->moveToInsertRow();
+ }
+ bNewRowInserted = true;
+ }
+ else
+ {
+
+ if ( !m_pSeekCursor->isBeforeFirst() && !m_pSeekCursor->isAfterLast() )
+ {
+ Any aBookmark = m_pSeekCursor->getBookmark();
+ if (!m_xCurrentRow.is() || m_xCurrentRow->IsNew() || !CompareBookmark(aBookmark, m_pDataCursor->getBookmark()))
+ {
+ // adjust the cursor to the new desired row
+ if (!m_pDataCursor->moveToBookmark(aBookmark))
+ {
+ EndCursorAction();
+ return false;
+ }
+ }
+ }
+ }
+ m_xDataRow->SetState(m_pDataCursor.get(), false);
+ m_xCurrentRow = m_xDataRow;
+
+ tools::Long nPaintPos = -1;
+ // do we have to repaint the last regular row in case of setting defaults or autovalues
+ if (m_nCurrentPos >= 0 && m_nCurrentPos >= (GetRowCount() - 2))
+ nPaintPos = m_nCurrentPos;
+
+ m_nCurrentPos = nNewRow;
+
+ // repaint the new row to display all defaults
+ if (bNewRowInserted)
+ RowModified(m_nCurrentPos);
+ if (nPaintPos >= 0)
+ RowModified(nPaintPos);
+ }
+ }
+ else
+ {
+ OSL_FAIL("DbGridControl::SetCurrent : SeekRow failed !");
+ EndCursorAction();
+ return false;
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ EndCursorAction();
+ return false;
+ }
+
+ EndCursorAction();
+ return true;
+}
+
+void DbGridControl::CursorMoved()
+{
+
+ // cursor movement due to deletion or insertion of rows
+ if (m_pDataCursor && m_nCurrentPos != GetCurRow())
+ {
+ DeactivateCell();
+ SetCurrent(GetCurRow());
+ }
+
+ EditBrowseBox::CursorMoved();
+ m_aBar->InvalidateAll(m_nCurrentPos);
+
+ // select the new column when they moved
+ if ( IsDesignMode() && GetSelectedColumnCount() > 0 && GetCurColumnId() )
+ {
+ SelectColumnId( GetCurColumnId() );
+ }
+
+ if ( m_nLastColId != GetCurColumnId() )
+ onColumnChange();
+ m_nLastColId = GetCurColumnId();
+
+ if ( m_nLastRowId != GetCurRow() )
+ onRowChange();
+ m_nLastRowId = GetCurRow();
+}
+
+void DbGridControl::onRowChange()
+{
+ // not interested in
+}
+
+void DbGridControl::onColumnChange()
+{
+ if ( m_pGridListener )
+ m_pGridListener->columnChanged();
+}
+
+void DbGridControl::setDisplaySynchron(bool bSync)
+{
+ if (bSync != m_bSynchDisplay)
+ {
+ m_bSynchDisplay = bSync;
+ if (m_bSynchDisplay)
+ AdjustDataSource();
+ }
+}
+
+void DbGridControl::AdjustDataSource(bool bFull)
+{
+ SAL_INFO("svx.fmcomp", "DbGridControl::AdjustDataSource");
+ SolarMutexGuard aGuard;
+ // If the current row is recalculated at the moment, do not adjust
+
+ if (bFull)
+ m_xCurrentRow = nullptr;
+ // if we are on the same row only repaint
+ // but this is only possible for rows which are not inserted, in that case the comparison result
+ // may not be correct
+ else
+ if ( m_xCurrentRow.is()
+ && !m_xCurrentRow->IsNew()
+ && !m_pDataCursor->isBeforeFirst()
+ && !m_pDataCursor->isAfterLast()
+ && !m_pDataCursor->rowDeleted()
+ )
+ {
+ bool bEqualBookmarks = CompareBookmark( m_xCurrentRow->GetBookmark(), m_pDataCursor->getBookmark() );
+
+ bool bDataCursorIsOnNew = false;
+ m_pDataCursor->getPropertySet()->getPropertyValue( FM_PROP_ISNEW ) >>= bDataCursorIsOnNew;
+
+ if ( bEqualBookmarks && !bDataCursorIsOnNew )
+ {
+ // position of my data cursor is the same as the position our current row points tpo
+ // sync the status, repaint, done
+ DBG_ASSERT(m_xDataRow == m_xCurrentRow, "Errors in the data row");
+ SAL_INFO("svx.fmcomp", "same position, new state: " << ROWSTATUS(m_xCurrentRow));
+ RowModified(m_nCurrentPos);
+ return;
+ }
+ }
+
+ // away from the data cursor's row
+ if (m_xPaintRow == m_xCurrentRow)
+ m_xPaintRow = m_xSeekRow;
+
+ // not up-to-date row, thus, adjust completely
+ if (!m_xCurrentRow.is())
+ AdjustRows();
+
+ sal_Int32 nNewPos = AlignSeekCursor();
+ if (nNewPos < 0)// could not find any position
+ return;
+
+ if (nNewPos != m_nCurrentPos)
+ {
+ if (m_bSynchDisplay)
+ EditBrowseBox::GoToRow(nNewPos);
+
+ if (!m_xCurrentRow.is())
+ // Happens e.g. when deleting the n last datasets (n>1) while the cursor was positioned
+ // on the last one. In this case, AdjustRows deletes two rows from BrowseBox, by what
+ // CurrentRow is corrected to point two rows down, so that GoToRow will point into
+ // emptiness (since we are - purportedly - at the correct position)
+ SetCurrent(nNewPos);
+ }
+ else
+ {
+ SetCurrent(nNewPos);
+ RowModified(nNewPos);
+ }
+
+ // if the data cursor was moved from outside, this section is voided
+ SetNoSelection();
+ m_aBar->InvalidateAll(m_nCurrentPos, m_xCurrentRow.is());
+}
+
+sal_Int32 DbGridControl::AlignSeekCursor()
+{
+ // position SeekCursor onto the data cursor, no data transmission
+
+ if (!m_pSeekCursor)
+ return -1;
+
+ Reference< XPropertySet > xSet = m_pDataCursor->getPropertySet();
+
+ // now align the seek cursor and the data cursor
+ if (::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW)))
+ m_nSeekPos = GetRowCount() - 1;
+ else
+ {
+ try
+ {
+ if ( m_pDataCursor->isBeforeFirst() )
+ {
+ // this is somewhat strange, but can nevertheless happen
+ SAL_INFO( "svx.fmcomp", "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (before first)!" );
+ m_pSeekCursor->first();
+ m_pSeekCursor->previous();
+ m_nSeekPos = -1;
+ }
+ else if ( m_pDataCursor->isAfterLast() )
+ {
+ SAL_INFO( "svx.fmcomp", "DbGridControl::AlignSeekCursor: nobody should tamper with my cursor this way (after last)!" );
+ m_pSeekCursor->last();
+ m_pSeekCursor->next();
+ m_nSeekPos = -1;
+ }
+ else
+ {
+ m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
+ if (!CompareBookmark(m_pDataCursor->getBookmark(), m_pSeekCursor->getBookmark()))
+ // unfortunately, moveToBookmark might lead to a re-positioning of the seek
+ // cursor (if the complex moveToBookmark with all its events fires an update
+ // somewhere) -> retry
+ m_pSeekCursor->moveToBookmark(m_pDataCursor->getBookmark());
+ // Now there is still the chance of a failure but it is less likely.
+ // The alternative would be a loop until everything is fine - no good solution...
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ return m_nSeekPos;
+}
+
+bool DbGridControl::SeekCursor(sal_Int32 nRow, bool bAbsolute)
+{
+ // position SeekCursor onto the data cursor, no data transmission
+
+ // additions for the filtermode
+ if (IsFilterRow(nRow))
+ {
+ m_nSeekPos = 0;
+ return true;
+ }
+
+ if (!m_pSeekCursor)
+ return false;
+
+ // is this an insertion?
+ if (IsValid(m_xCurrentRow) && m_xCurrentRow->IsNew() &&
+ nRow >= m_nCurrentPos)
+ {
+ // if so, scrolling down must be prevented as this is already the last data set!
+ if (nRow == m_nCurrentPos)
+ {
+ // no adjustment necessary
+ m_nSeekPos = nRow;
+ }
+ else if (IsInsertionRow(nRow)) // blank row for data insertion
+ m_nSeekPos = nRow;
+ }
+ else if (IsInsertionRow(nRow)) // blank row for data insertion
+ m_nSeekPos = nRow;
+ else if ((-1 == nRow) && (GetRowCount() == ((m_nOptions & DbGridControlOptions::Insert) ? 1 : 0)) && m_pSeekCursor->isAfterLast())
+ m_nSeekPos = nRow;
+ else
+ {
+ bool bSuccess = false;
+ tools::Long nSteps = 0;
+ try
+ {
+ if ( m_pSeekCursor->rowDeleted() )
+ {
+ // somebody deleted the current row of the seek cursor. Move it away from this row.
+ m_pSeekCursor->next();
+ if ( m_pSeekCursor->isAfterLast() || m_pSeekCursor->isBeforeFirst() )
+ bAbsolute = true;
+ }
+
+ if ( !bAbsolute )
+ {
+ DBG_ASSERT( !m_pSeekCursor->isAfterLast() && !m_pSeekCursor->isBeforeFirst(),
+ "DbGridControl::SeekCursor: how did the seek cursor get to this position?!" );
+ nSteps = nRow - (m_pSeekCursor->getRow() - 1);
+ bAbsolute = std::abs(nSteps) > 100;
+ }
+
+ if ( bAbsolute )
+ {
+ bSuccess = m_pSeekCursor->absolute(nRow + 1);
+ if (bSuccess)
+ m_nSeekPos = nRow;
+ }
+ else
+ {
+ if (nSteps > 0) // position onto the last needed data set
+ {
+ if (m_pSeekCursor->isAfterLast())
+ bSuccess = false;
+ else if (m_pSeekCursor->isBeforeFirst())
+ bSuccess = m_pSeekCursor->absolute(nSteps);
+ else
+ bSuccess = m_pSeekCursor->relative(nSteps);
+ }
+ else if (nSteps < 0)
+ {
+ if (m_pSeekCursor->isBeforeFirst())
+ bSuccess = false;
+ else if (m_pSeekCursor->isAfterLast())
+ bSuccess = m_pSeekCursor->absolute(nSteps);
+ else
+ bSuccess = m_pSeekCursor->relative(nSteps);
+ }
+ else
+ {
+ m_nSeekPos = nRow;
+ return true;
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("DbGridControl::SeekCursor : failed ...");
+ }
+
+ try
+ {
+ if (!bSuccess)
+ {
+ if (bAbsolute || nSteps > 0)
+ {
+ if (m_pSeekCursor->isLast())
+ bSuccess = true;
+ else
+ bSuccess = m_pSeekCursor->last();
+ }
+ else
+ {
+ if (m_pSeekCursor->isFirst())
+ bSuccess = true;
+ else
+ bSuccess = m_pSeekCursor->first();
+ }
+ }
+
+ if (bSuccess)
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ else
+ m_nSeekPos = -1;
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ OSL_FAIL("DbGridControl::SeekCursor : failed ...");
+ m_nSeekPos = -1; // no further data set available
+ }
+ }
+ return m_nSeekPos == nRow;
+}
+
+void DbGridControl::MoveToFirst()
+{
+ if (m_pSeekCursor && (GetCurRow() != 0))
+ MoveToPosition(0);
+}
+
+void DbGridControl::MoveToLast()
+{
+ if (!m_pSeekCursor)
+ return;
+
+ if (m_nTotalCount < 0) // no RecordCount, yet
+ {
+ try
+ {
+ bool bRes = m_pSeekCursor->last();
+
+ if (bRes)
+ {
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ AdjustRows();
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ }
+
+ // position onto the last data set not on a blank row
+ if (m_nOptions & DbGridControlOptions::Insert)
+ {
+ if ((GetRowCount() - 1) > 0)
+ MoveToPosition(GetRowCount() - 2);
+ }
+ else if (GetRowCount())
+ MoveToPosition(GetRowCount() - 1);
+}
+
+void DbGridControl::MoveToPrev()
+{
+ sal_Int32 nNewRow = std::max(GetCurRow() - 1, sal_Int32(0));
+ if (GetCurRow() != nNewRow)
+ MoveToPosition(nNewRow);
+}
+
+void DbGridControl::MoveToNext()
+{
+ if (!m_pSeekCursor)
+ return;
+
+ if (m_nTotalCount > 0)
+ {
+ // move the data cursor to the right position
+ tools::Long nNewRow = std::min(GetRowCount() - 1, GetCurRow() + 1);
+ if (GetCurRow() != nNewRow)
+ MoveToPosition(nNewRow);
+ }
+ else
+ {
+ bool bOk = false;
+ try
+ {
+ // try to move to next row
+ // when not possible our paint cursor is already on the last row
+ // then we must be sure that the data cursor is on the position
+ // we call ourself again
+ bOk = m_pSeekCursor->next();
+ if (bOk)
+ {
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ MoveToPosition(GetCurRow() + 1);
+ }
+ }
+ catch(SQLException &)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ if(!bOk)
+ {
+ AdjustRows();
+ if (m_nTotalCount > 0) // only to avoid infinite recursion
+ MoveToNext();
+ }
+ }
+}
+
+void DbGridControl::MoveToPosition(sal_uInt32 nPos)
+{
+ if (!m_pSeekCursor)
+ return;
+
+ if (m_nTotalCount < 0 && static_cast<tools::Long>(nPos) >= GetRowCount())
+ {
+ try
+ {
+ if (!m_pSeekCursor->absolute(nPos + 1))
+ {
+ AdjustRows();
+ return;
+ }
+ else
+ {
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ AdjustRows();
+ }
+ }
+ catch(Exception&)
+ {
+ return;
+ }
+ }
+ EditBrowseBox::GoToRow(nPos);
+ m_aBar->InvalidateAll(m_nCurrentPos);
+}
+
+void DbGridControl::AppendNew()
+{
+ if (!m_pSeekCursor || !(m_nOptions & DbGridControlOptions::Insert))
+ return;
+
+ if (m_nTotalCount < 0) // no RecordCount, yet
+ {
+ try
+ {
+ bool bRes = m_pSeekCursor->last();
+
+ if (bRes)
+ {
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ AdjustRows();
+ }
+ }
+ catch(Exception&)
+ {
+ return;
+ }
+ }
+
+ tools::Long nNewRow = m_nTotalCount + 1;
+ if (nNewRow > 0 && GetCurRow() != nNewRow)
+ MoveToPosition(nNewRow - 1);
+}
+
+void DbGridControl::SetDesignMode(bool bMode)
+{
+ if (IsDesignMode() == bMode)
+ return;
+
+ // adjust Enable/Disable for design mode so that the headerbar remains configurable
+ if (bMode)
+ {
+ if (!IsEnabled())
+ {
+ Enable();
+ GetDataWindow().Disable();
+ }
+ }
+ else
+ {
+ // disable completely
+ if (!GetDataWindow().IsEnabled())
+ Disable();
+ }
+
+ m_bDesignMode = bMode;
+ GetDataWindow().SetMouseTransparent(bMode);
+ SetMouseTransparent(bMode);
+
+ m_aBar->InvalidateAll(m_nCurrentPos, true);
+}
+
+void DbGridControl::SetFilterMode(bool bMode)
+{
+ if (IsFilterMode() == bMode)
+ return;
+
+ m_bFilterMode = bMode;
+
+ if (bMode)
+ {
+ SetUpdateMode(false);
+
+ // there is no cursor anymore
+ if (IsEditing())
+ DeactivateCell();
+ RemoveRows(false);
+
+ m_xEmptyRow = new DbGridRow();
+
+ // setting the new filter controls
+ for (auto const & pCurCol : m_aColumns)
+ {
+ if (!pCurCol->IsHidden())
+ pCurCol->UpdateControl();
+ }
+
+ // one row for filtering
+ RowInserted(0);
+ SetUpdateMode(true);
+ }
+ else
+ setDataSource(Reference< XRowSet > ());
+}
+
+OUString DbGridControl::GetCellText(sal_Int32 _nRow, sal_uInt16 _nColId) const
+{
+ size_t Location = GetModelColumnPos( _nColId );
+ DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
+ OUString sRet;
+ if ( const_cast<DbGridControl*>(this)->SeekRow(_nRow) )
+ sRet = GetCurrentRowCellText(pColumn, m_xPaintRow);
+ return sRet;
+}
+
+OUString DbGridControl::GetCurrentRowCellText(DbGridColumn const * pColumn,const DbGridRowRef& _rRow) const
+{
+ // text output for a single row
+ OUString aText;
+ if ( pColumn && IsValid(_rRow) )
+ aText = pColumn->GetCellText(_rRow.get(), m_xFormatter);
+ return aText;
+}
+
+sal_uInt32 DbGridControl::GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId)
+{
+ if (SeekRow(nRow))
+ {
+ size_t Location = GetModelColumnPos( nColId );
+ DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
+ return GetDataWindow().GetTextWidth(GetCurrentRowCellText(pColumn,m_xPaintRow));
+ }
+ else
+ return 30; // FIXME magic number for default cell width
+}
+
+void DbGridControl::PreExecuteRowContextMenu(weld::Menu& rMenu)
+{
+ bool bDelete = (m_nOptions & DbGridControlOptions::Delete) && GetSelectRowCount() && !IsCurrentAppending();
+ // if only a blank row is selected then do not delete
+ bDelete = bDelete && !((m_nOptions & DbGridControlOptions::Insert) && GetSelectRowCount() == 1 && IsRowSelected(GetRowCount() - 1));
+
+ rMenu.set_visible("delete", bDelete);
+ rMenu.set_visible("save", IsModified());
+
+ // the undo is more difficult
+ bool bCanUndo = IsModified();
+ int nState = -1;
+ if (m_aMasterStateProvider.IsSet())
+ nState = m_aMasterStateProvider.Call(DbGridControlNavigationBarState::Undo);
+ bCanUndo &= ( 0 != nState );
+
+ rMenu.set_visible("undo", bCanUndo);
+}
+
+void DbGridControl::PostExecuteRowContextMenu(const OString& rExecutionResult)
+{
+ if (rExecutionResult == "delete")
+ {
+ // delete asynchronously
+ if (m_nDeleteEvent)
+ Application::RemoveUserEvent(m_nDeleteEvent);
+ m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete), nullptr, true);
+ }
+ else if (rExecutionResult == "undo")
+ Undo();
+ else if (rExecutionResult == "save")
+ SaveRow();
+}
+
+void DbGridControl::DataSourcePropertyChanged(const PropertyChangeEvent& evt)
+{
+ SAL_INFO("svx.fmcomp", "DbGridControl::DataSourcePropertyChanged");
+ SolarMutexGuard aGuard;
+ // prop "IsModified" changed ?
+ // during update don't care about the modified state
+ if (IsUpdating() || evt.PropertyName != FM_PROP_ISMODIFIED)
+ return;
+
+ Reference< XPropertySet > xSource(evt.Source, UNO_QUERY);
+ DBG_ASSERT( xSource.is(), "DbGridControl::DataSourcePropertyChanged: invalid event source!" );
+ bool bIsNew = false;
+ if (xSource.is())
+ bIsNew = ::comphelper::getBOOL(xSource->getPropertyValue(FM_PROP_ISNEW));
+
+ if (bIsNew && m_xCurrentRow.is())
+ {
+ DBG_ASSERT(::comphelper::getBOOL(xSource->getPropertyValue(FM_PROP_ROWCOUNTFINAL)), "DbGridControl::DataSourcePropertyChanged : somebody moved the form to a new record before the row count was final !");
+ sal_Int32 nRecordCount = 0;
+ xSource->getPropertyValue(FM_PROP_ROWCOUNT) >>= nRecordCount;
+ if (::comphelper::getBOOL(evt.NewValue))
+ { // modified state changed from sal_False to sal_True and we're on an insert row
+ // -> we've to add a new grid row
+ if ((nRecordCount == GetRowCount() - 1) && m_xCurrentRow->IsNew())
+ {
+ RowInserted(GetRowCount());
+ InvalidateStatusCell(m_nCurrentPos);
+ m_aBar->InvalidateAll(m_nCurrentPos);
+ }
+ }
+ else
+ { // modified state changed from sal_True to sal_False and we're on an insert row
+ // we have two "new row"s at the moment : the one we're editing currently (where the current
+ // column is the only dirty element) and a "new new" row which is completely clean. As the first
+ // one is about to be cleaned, too, the second one is obsolete now.
+ if (m_xCurrentRow->IsNew() && nRecordCount == (GetRowCount() - 2))
+ {
+ RowRemoved(GetRowCount() - 1);
+ InvalidateStatusCell(m_nCurrentPos);
+ m_aBar->InvalidateAll(m_nCurrentPos);
+ }
+ }
+ }
+ if (m_xCurrentRow.is())
+ {
+ m_xCurrentRow->SetStatus(::comphelper::getBOOL(evt.NewValue) ? GridRowStatus::Modified : GridRowStatus::Clean);
+ m_xCurrentRow->SetNew( bIsNew );
+ InvalidateStatusCell(m_nCurrentPos);
+ SAL_INFO("svx.fmcomp", "modified flag changed, new state: " << ROWSTATUS(m_xCurrentRow));
+ }
+}
+
+void DbGridControl::StartDrag( sal_Int8 /*nAction*/, const Point& rPosPixel )
+{
+ if (!m_pSeekCursor || IsResizing())
+ return;
+
+ sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rPosPixel.X()));
+ tools::Long nRow = GetRowAtYPosPixel(rPosPixel.Y());
+ if (nColId != HandleColumnId && nRow >= 0)
+ {
+ if (GetDataWindow().IsMouseCaptured())
+ GetDataWindow().ReleaseMouse();
+
+ size_t Location = GetModelColumnPos( nColId );
+ DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
+ rtl::Reference<OStringTransferable> pTransferable = new OStringTransferable(GetCurrentRowCellText(pColumn,m_xPaintRow));
+ pTransferable->StartDrag(this, DND_ACTION_COPY);
+ }
+}
+
+bool DbGridControl::canCopyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
+{
+ return (_nRow >= 0)
+ && (_nRow < GetRowCount())
+ && (_nColId != HandleColumnId)
+ && (GetModelColumnPos(_nColId) != GRID_COLUMN_NOT_FOUND);
+}
+
+void DbGridControl::copyCellText(sal_Int32 _nRow, sal_uInt16 _nColId)
+{
+ DBG_ASSERT(canCopyCellText(_nRow, _nColId), "DbGridControl::copyCellText: invalid call!");
+ DbGridColumn* pColumn = m_aColumns[ GetModelColumnPos(_nColId) ].get();
+ SeekRow(_nRow);
+ OStringTransfer::CopyString( GetCurrentRowCellText( pColumn,m_xPaintRow ), this );
+}
+
+void DbGridControl::executeRowContextMenu(const Point& _rPreferredPos)
+{
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "svx/ui/rowsmenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+
+ tools::Rectangle aRect(_rPreferredPos, Size(1,1));
+ weld::Window* pParent = weld::GetPopupParent(*this, aRect);
+
+ PreExecuteRowContextMenu(*xContextMenu);
+ PostExecuteRowContextMenu(xContextMenu->popup_at_rect(pParent, aRect));
+}
+
+void DbGridControl::Command(const CommandEvent& rEvt)
+{
+ switch (rEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ if ( !m_pSeekCursor )
+ {
+ EditBrowseBox::Command(rEvt);
+ return;
+ }
+
+ if ( !rEvt.IsMouseEvent() )
+ { // context menu requested by keyboard
+ if ( GetSelectRowCount() )
+ {
+ tools::Long nRow = FirstSelectedRow( );
+
+ ::tools::Rectangle aRowRect( GetRowRectPixel( nRow ) );
+ executeRowContextMenu(aRowRect.LeftCenter());
+
+ // handled
+ return;
+ }
+ }
+
+ sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X()));
+ tools::Long nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y());
+
+ if (nColId == HandleColumnId)
+ {
+ executeRowContextMenu(rEvt.GetMousePosPixel());
+ }
+ else if (canCopyCellText(nRow, nColId))
+ {
+ ::tools::Rectangle aRect(rEvt.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "svx/ui/cellmenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+ if (!xContextMenu->popup_at_rect(pPopupParent, aRect).isEmpty())
+ copyCellText(nRow, nColId);
+ }
+ else
+ {
+ EditBrowseBox::Command(rEvt);
+ return;
+ }
+
+ [[fallthrough]];
+ }
+ default:
+ EditBrowseBox::Command(rEvt);
+ }
+}
+
+IMPL_LINK_NOARG(DbGridControl, OnDelete, void*, void)
+{
+ m_nDeleteEvent = nullptr;
+ DeleteSelectedRows();
+}
+
+void DbGridControl::DeleteSelectedRows()
+{
+ DBG_ASSERT(GetSelection(), "no selection!!!");
+
+ if (!m_pSeekCursor)
+ return;
+}
+
+CellController* DbGridControl::GetController(sal_Int32 /*nRow*/, sal_uInt16 nColumnId)
+{
+ if (!IsValid(m_xCurrentRow) || !IsEnabled())
+ return nullptr;
+
+ size_t Location = GetModelColumnPos(nColumnId);
+ DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
+ if (!pColumn)
+ return nullptr;
+
+ CellController* pReturn = nullptr;
+ if (IsFilterMode())
+ pReturn = pColumn->GetController().get();
+ else
+ {
+ if (::comphelper::hasProperty(FM_PROP_ENABLED, pColumn->getModel()))
+ {
+ if (!::comphelper::getBOOL(pColumn->getModel()->getPropertyValue(FM_PROP_ENABLED)))
+ return nullptr;
+ }
+
+ bool bInsert = (m_xCurrentRow->IsNew() && (m_nOptions & DbGridControlOptions::Insert));
+ bool bUpdate = (!m_xCurrentRow->IsNew() && (m_nOptions & DbGridControlOptions::Update));
+
+ if ((bInsert && !pColumn->IsAutoValue()) || bUpdate)
+ {
+ pReturn = pColumn->GetController().get();
+ }
+ }
+ return pReturn;
+}
+
+void DbGridControl::CellModified()
+{
+ SAL_INFO("svx.fmcomp", "DbGridControl::CellModified");
+
+ {
+ ::osl::MutexGuard aGuard(m_aAdjustSafety);
+ if (m_nAsynAdjustEvent)
+ {
+ SAL_INFO("svx.fmcomp", "forcing a synchron call to " << (m_bPendingAdjustRows ? "AdjustRows" : "AdustDataSource"));
+ RemoveUserEvent(m_nAsynAdjustEvent);
+ m_nAsynAdjustEvent = nullptr;
+
+ // force the call : this should be no problem as we're probably running in the solar thread here
+ // (cell modified is triggered by user actions)
+ if (m_bPendingAdjustRows)
+ AdjustRows();
+ else
+ AdjustDataSource();
+ }
+ }
+
+ if (IsFilterMode() || !IsValid(m_xCurrentRow) || m_xCurrentRow->IsModified())
+ return;
+
+ // enable edit mode
+ // a data set should be inserted
+ if (m_xCurrentRow->IsNew())
+ {
+ m_xCurrentRow->SetStatus(GridRowStatus::Modified);
+ SAL_INFO("svx.fmcomp", "current row is new, new state: MODIFIED");
+ // if no row was added yet, do it now
+ if (m_nCurrentPos == GetRowCount() - 1)
+ {
+ // increment RowCount
+ RowInserted(GetRowCount());
+ InvalidateStatusCell(m_nCurrentPos);
+ m_aBar->InvalidateAll(m_nCurrentPos);
+ }
+ }
+ else if (m_xCurrentRow->GetStatus() != GridRowStatus::Modified)
+ {
+ m_xCurrentRow->SetState(m_pDataCursor.get(), false);
+ SAL_INFO("svx.fmcomp", "current row is not new, after SetState, new state: " << ROWSTATUS(m_xCurrentRow));
+ m_xCurrentRow->SetStatus(GridRowStatus::Modified);
+ SAL_INFO("svx.fmcomp", "current row is not new, new state: MODIFIED");
+ InvalidateStatusCell(m_nCurrentPos);
+ }
+}
+
+void DbGridControl::Dispatch(sal_uInt16 nId)
+{
+ if (nId == BROWSER_CURSORENDOFFILE)
+ {
+ if (m_nOptions & DbGridControlOptions::Insert)
+ AppendNew();
+ else
+ MoveToLast();
+ }
+ else
+ EditBrowseBox::Dispatch(nId);
+}
+
+void DbGridControl::Undo()
+{
+ if (IsFilterMode() || !IsValid(m_xCurrentRow) || !IsModified())
+ return;
+
+ // check if we have somebody doin' the UNDO for us
+ int nState = -1;
+ if (m_aMasterStateProvider.IsSet())
+ nState = m_aMasterStateProvider.Call(DbGridControlNavigationBarState::Undo);
+ if (nState>0)
+ { // yes, we have, and the slot is enabled
+ DBG_ASSERT(m_aMasterSlotExecutor.IsSet(), "DbGridControl::Undo : a state, but no execute link ?");
+ bool lResult = m_aMasterSlotExecutor.Call(DbGridControlNavigationBarState::Undo);
+ if (lResult)
+ // handled
+ return;
+ }
+ else if (nState == 0)
+ // yes, we have, and the slot is disabled
+ return;
+
+ BeginCursorAction();
+
+ bool bAppending = m_xCurrentRow->IsNew();
+ bool bDirty = m_xCurrentRow->IsModified();
+
+ try
+ {
+ // cancel editing
+ Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
+ // no effects if we're not updating currently
+ if (bAppending)
+ // just refresh the row
+ xUpdateCursor->moveToInsertRow();
+ else
+ xUpdateCursor->cancelRowUpdates();
+
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ EndCursorAction();
+
+ m_xDataRow->SetState(m_pDataCursor.get(), false);
+ if (m_xPaintRow == m_xCurrentRow)
+ m_xPaintRow = m_xCurrentRow = m_xDataRow;
+ else
+ m_xCurrentRow = m_xDataRow;
+
+ if (bAppending && (EditBrowseBox::IsModified() || bDirty))
+ // remove the row
+ if (m_nCurrentPos == GetRowCount() - 2)
+ { // maybe we already removed it (in resetCurrentRow, called if the above moveToInsertRow
+ // caused our data source form to be reset - which should be the usual case...)
+ RowRemoved(GetRowCount() - 1);
+ m_aBar->InvalidateAll(m_nCurrentPos);
+ }
+
+ RowModified(m_nCurrentPos);
+}
+
+void DbGridControl::resetCurrentRow()
+{
+ if (IsModified())
+ {
+ // scenario : we're on the insert row, the row is dirty, and thus there exists a "second" insert row (which
+ // is clean). Normally in DataSourcePropertyChanged we would remove this second row if the modified state of
+ // the insert row changes from sal_True to sal_False. But if our current cell is the only modified element (means the
+ // data source isn't modified) and we're reset this DataSourcePropertyChanged would never be called, so we
+ // would never delete the obsolete "second insert row". Thus in this special case this method here
+ // is the only possibility to determine the redundance of the row (resetCurrentRow is called when the
+ // "first insert row" is about to be cleaned, so of course the "second insert row" is redundant now)
+ Reference< XPropertySet > xDataSource = getDataSource()->getPropertySet();
+ if (xDataSource.is() && !::comphelper::getBOOL(xDataSource->getPropertyValue(FM_PROP_ISMODIFIED)))
+ {
+ // are we on a new row currently ?
+ if (m_xCurrentRow->IsNew())
+ {
+ if (m_nCurrentPos == GetRowCount() - 2)
+ {
+ RowRemoved(GetRowCount() - 1);
+ m_aBar->InvalidateAll(m_nCurrentPos);
+ }
+ }
+ }
+
+ // update the rows
+ m_xDataRow->SetState(m_pDataCursor.get(), false);
+ if (m_xPaintRow == m_xCurrentRow)
+ m_xPaintRow = m_xCurrentRow = m_xDataRow;
+ else
+ m_xCurrentRow = m_xDataRow;
+ }
+
+ RowModified(GetCurRow()); // will update the current controller if affected
+}
+
+void DbGridControl::RowModified( sal_Int32 nRow )
+{
+ if (nRow == m_nCurrentPos && IsEditing())
+ {
+ CellControllerRef aTmpRef = Controller();
+ aTmpRef->SaveValue();
+ InitController(aTmpRef, m_nCurrentPos, GetCurColumnId());
+ }
+ EditBrowseBox::RowModified(nRow);
+}
+
+bool DbGridControl::IsModified() const
+{
+ return !IsFilterMode() && IsValid(m_xCurrentRow) && (m_xCurrentRow->IsModified() || EditBrowseBox::IsModified());
+}
+
+bool DbGridControl::IsCurrentAppending() const
+{
+ return m_xCurrentRow.is() && m_xCurrentRow->IsNew();
+}
+
+bool DbGridControl::IsInsertionRow(sal_Int32 nRow) const
+{
+ return (m_nOptions & DbGridControlOptions::Insert) && m_nTotalCount >= 0 && (nRow == GetRowCount() - 1);
+}
+
+bool DbGridControl::SaveModified()
+{
+ SAL_INFO("svx.fmcomp", "DbGridControl::SaveModified");
+ DBG_ASSERT(IsValid(m_xCurrentRow), "GridControl:: Invalid row");
+ if (!IsValid(m_xCurrentRow))
+ return true;
+
+ // accept input for this field
+ // Where there changes at the current input field?
+ if (!EditBrowseBox::IsModified())
+ return true;
+
+ size_t Location = GetModelColumnPos( GetCurColumnId() );
+ DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
+ bool bOK = pColumn && pColumn->Commit();
+ DBG_ASSERT( Controller().is(), "DbGridControl::SaveModified: was modified, by have no controller?!" );
+ if ( !Controller().is() )
+ // this might happen if the callbacks implicitly triggered by Commit
+ // fiddled with the form or the control ...
+ // (Note that this here is a workaround, at most. We need a general concept how
+ // to treat this, you can imagine an arbitrary number of scenarios where a callback
+ // triggers something which leaves us in an expected state.)
+ // #i67147# / 2006-07-17 / frank.schoenheit@sun.com
+ return bOK;
+
+ if (bOK)
+ {
+ Controller()->SaveValue();
+
+ if ( IsValid(m_xCurrentRow) )
+ {
+ m_xCurrentRow->SetState(m_pDataCursor.get(), false);
+ SAL_INFO("svx.fmcomp", "explicit SetState, new state: " << ROWSTATUS(m_xCurrentRow));
+ InvalidateStatusCell( m_nCurrentPos );
+ }
+ else
+ {
+ SAL_INFO("svx.fmcomp", "no SetState, new state: " << ROWSTATUS(m_xCurrentRow));
+ }
+ }
+
+ return bOK;
+}
+
+bool DbGridControl::SaveRow()
+{
+ SAL_INFO("svx.fmcomp", "DbGridControl::SaveRow");
+ // valid row
+ if (!IsValid(m_xCurrentRow) || !IsModified())
+ return true;
+ // value of the controller was not saved, yet
+ else if (Controller().is() && Controller()->IsValueChangedFromSaved())
+ {
+ if (!SaveModified())
+ return false;
+ }
+ m_bUpdating = true;
+
+ BeginCursorAction();
+ bool bAppending = m_xCurrentRow->IsNew();
+ bool bSuccess = false;
+ try
+ {
+ Reference< XResultSetUpdate > xUpdateCursor(Reference< XInterface >(*m_pDataCursor), UNO_QUERY);
+ if (bAppending)
+ xUpdateCursor->insertRow();
+ else
+ xUpdateCursor->updateRow();
+ bSuccess = true;
+ }
+ catch(SQLException&)
+ {
+ EndCursorAction();
+ m_bUpdating = false;
+ return false;
+ }
+
+ try
+ {
+ if (bSuccess)
+ {
+ // if we are appending we still sit on the insert row
+ // we don't move just clear the flags not to move on the current row
+ m_xCurrentRow->SetState(m_pDataCursor.get(), false);
+ SAL_INFO("svx.fmcomp", "explicit SetState after a successful update, new state: " << ROWSTATUS(m_xCurrentRow));
+ m_xCurrentRow->SetNew(false);
+
+ // adjust the seekcursor if it is on the same position as the datacursor
+ if (m_nSeekPos == m_nCurrentPos || bAppending)
+ {
+ // get the bookmark to refetch the data
+ // in insert mode we take the new bookmark of the data cursor
+ Any aBookmark = bAppending ? m_pDataCursor->getBookmark() : m_pSeekCursor->getBookmark();
+ m_pSeekCursor->moveToBookmark(aBookmark);
+ // get the data
+ m_xSeekRow->SetState(m_pSeekCursor.get(), true);
+ m_nSeekPos = m_pSeekCursor->getRow() - 1;
+ }
+ }
+ // and repaint the row
+ RowModified(m_nCurrentPos);
+ }
+ catch(Exception&)
+ {
+ }
+
+ m_bUpdating = false;
+ EndCursorAction();
+
+ // The old code returned (nRecords != 0) here.
+ // Me thinks this is wrong : If something goes wrong while update the record, an exception will be thrown,
+ // which results in a "return sal_False" (see above). If no exception is thrown, everything is fine. If nRecords
+ // is zero, this simply means all fields had their original values.
+ // FS - 06.12.99 - 70502
+ return true;
+}
+
+bool DbGridControl::PreNotify(NotifyEvent& rEvt)
+{
+ // do not handle events of the Navbar
+ if (m_aBar->IsWindowOrChild(rEvt.GetWindow()))
+ return BrowseBox::PreNotify(rEvt);
+
+ switch (rEvt.GetType())
+ {
+ case MouseNotifyEvent::KEYINPUT:
+ {
+ const KeyEvent* pKeyEvent = rEvt.GetKeyEvent();
+
+ sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
+ bool bShift = pKeyEvent->GetKeyCode().IsShift();
+ bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
+ bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
+ if ( ( KEY_TAB == nCode ) && bCtrl && !bAlt )
+ {
+ // Ctrl-Tab is used to step out of the control, without traveling to the
+ // remaining cells first
+ // -> build a new key event without the Ctrl-key, and let the very base class handle it
+ vcl::KeyCode aNewCode( KEY_TAB, bShift, false, false, false );
+ KeyEvent aNewEvent( pKeyEvent->GetCharCode(), aNewCode );
+
+ // call the Control - our direct base class will interpret this in a way we do not want (and do
+ // a cell traveling)
+ Control::KeyInput( aNewEvent );
+ return true;
+ }
+
+ if ( !bShift && !bCtrl && ( KEY_ESCAPE == nCode ) )
+ {
+ if (IsModified())
+ {
+ Undo();
+ return true;
+ }
+ }
+ else if ( ( KEY_DELETE == nCode ) && !bShift && !bCtrl ) // delete rows
+ {
+ if ((m_nOptions & DbGridControlOptions::Delete) && GetSelectRowCount())
+ {
+ // delete asynchronously
+ if (m_nDeleteEvent)
+ Application::RemoveUserEvent(m_nDeleteEvent);
+ m_nDeleteEvent = Application::PostUserEvent(LINK(this,DbGridControl,OnDelete), nullptr, true);
+ return true;
+ }
+ }
+
+ [[fallthrough]];
+ }
+ default:
+ return EditBrowseBox::PreNotify(rEvt);
+ }
+}
+
+bool DbGridControl::IsTabAllowed(bool bRight) const
+{
+ if (bRight)
+ // Tab only if not on the _last_ row
+ return GetCurRow() < (GetRowCount() - 1) || !m_bRecordCountFinal ||
+ GetViewColumnPos(GetCurColumnId()) < (GetViewColCount() - 1);
+ else
+ {
+ // Tab only if not on the _first_ row
+ return GetCurRow() > 0 || (GetCurColumnId() && GetViewColumnPos(GetCurColumnId()) > 0);
+ }
+}
+
+void DbGridControl::KeyInput( const KeyEvent& rEvt )
+{
+ if (rEvt.GetKeyCode().GetFunction() == KeyFuncType::COPY)
+ {
+ tools::Long nRow = GetCurRow();
+ sal_uInt16 nColId = GetCurColumnId();
+ if (nRow >= 0 && nRow < GetRowCount() && nColId < ColCount())
+ {
+ size_t Location = GetModelColumnPos( nColId );
+ DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
+ OStringTransfer::CopyString( GetCurrentRowCellText( pColumn, m_xCurrentRow ), this );
+ return;
+ }
+ }
+ EditBrowseBox::KeyInput(rEvt);
+}
+
+void DbGridControl::HideColumn(sal_uInt16 nId)
+{
+ DeactivateCell();
+
+ // determine the col for the focus to set to after removal
+ sal_uInt16 nPos = GetViewColumnPos(nId);
+ sal_uInt16 nNewColId = nPos == (ColCount()-1)
+ ? GetColumnIdFromViewPos(nPos-1) // last col is to be removed -> take the previous
+ : GetColumnIdFromViewPos(nPos+1); // take the next
+
+ tools::Long lCurrentWidth = GetColumnWidth(nId);
+ EditBrowseBox::RemoveColumn(nId);
+ // don't use my own RemoveColumn, this would remove it from m_aColumns, too
+
+ // update my model
+ size_t Location = GetModelColumnPos( nId );
+ DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
+ DBG_ASSERT(pColumn, "DbGridControl::HideColumn : somebody did hide a nonexistent column !");
+ if (pColumn)
+ {
+ pColumn->m_bHidden = true;
+ pColumn->m_nLastVisibleWidth = CalcReverseZoom(lCurrentWidth);
+ }
+
+ // and reset the focus
+ if ( nId == GetCurColumnId() )
+ GoToColumnId( nNewColId );
+}
+
+void DbGridControl::ShowColumn(sal_uInt16 nId)
+{
+ sal_uInt16 nPos = GetModelColumnPos(nId);
+ DBG_ASSERT(nPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : invalid argument !");
+ if (nPos == GRID_COLUMN_NOT_FOUND)
+ return;
+
+ DbGridColumn* pColumn = m_aColumns[ nPos ].get();
+ if (!pColumn->IsHidden())
+ {
+ DBG_ASSERT(GetViewColumnPos(nId) != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
+ // if the column isn't marked as hidden, it should be visible, shouldn't it ?
+ return;
+ }
+ DBG_ASSERT(GetViewColumnPos(nId) == GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
+ // the opposite situation ...
+
+ // to determine the new view position we need an adjacent non-hidden column
+ sal_uInt16 nNextNonHidden = BROWSER_INVALIDID;
+ // first search the cols to the right
+ for ( size_t i = nPos + 1; i < m_aColumns.size(); ++i )
+ {
+ DbGridColumn* pCurCol = m_aColumns[ i ].get();
+ if (!pCurCol->IsHidden())
+ {
+ nNextNonHidden = i;
+ break;
+ }
+ }
+ if ((nNextNonHidden == BROWSER_INVALIDID) && (nPos > 0))
+ {
+ // then to the left
+ for ( size_t i = nPos; i > 0; --i )
+ {
+ DbGridColumn* pCurCol = m_aColumns[ i-1 ].get();
+ if (!pCurCol->IsHidden())
+ {
+ nNextNonHidden = i-1;
+ break;
+ }
+ }
+ }
+ sal_uInt16 nNewViewPos = (nNextNonHidden == BROWSER_INVALIDID)
+ ? 1 // there is no visible column -> insert behind the handle col
+ : GetViewColumnPos( m_aColumns[ nNextNonHidden ]->GetId() ) + 1;
+ // the first non-handle col has "view pos" 0, but the pos arg for InsertDataColumn expects
+ // a position 1 for the first non-handle col -> +1
+ DBG_ASSERT(nNewViewPos != GRID_COLUMN_NOT_FOUND, "DbGridControl::ShowColumn : inconsistent internal state !");
+ // we found a col marked as visible but got no view pos for it ...
+
+ if ((nNextNonHidden<nPos) && (nNextNonHidden != BROWSER_INVALIDID))
+ // nNextNonHidden is a column to the left, so we want to insert the new col _right_ beside it's pos
+ ++nNewViewPos;
+
+ DeactivateCell();
+
+ OUString aName;
+ pColumn->getModel()->getPropertyValue(FM_PROP_LABEL) >>= aName;
+ InsertDataColumn(nId, aName, CalcZoom(pColumn->m_nLastVisibleWidth), HeaderBarItemBits::CENTER | HeaderBarItemBits::CLICKABLE, nNewViewPos);
+ pColumn->m_bHidden = false;
+
+ ActivateCell();
+ Invalidate();
+}
+
+sal_uInt16 DbGridControl::GetColumnIdFromModelPos( sal_uInt16 nPos ) const
+{
+ if (nPos >= m_aColumns.size())
+ {
+ OSL_FAIL("DbGridControl::GetColumnIdFromModelPos : invalid argument !");
+ return GRID_COLUMN_NOT_FOUND;
+ }
+
+ DbGridColumn* pCol = m_aColumns[ nPos ].get();
+#if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL
+ // in the debug version, we convert the ModelPos into a ViewPos and compare this with the
+ // value we will return (nId at the corresponding Col in m_aColumns)
+
+ if (!pCol->IsHidden())
+ { // makes sense only if the column is visible
+ sal_uInt16 nViewPos = nPos;
+ for ( size_t i = 0; i < m_aColumns.size() && i < nPos; ++i)
+ if ( m_aColumns[ i ]->IsHidden())
+ --nViewPos;
+
+ DBG_ASSERT(pCol && GetColumnIdFromViewPos(nViewPos) == pCol->GetId(),
+ "DbGridControl::GetColumnIdFromModelPos : this isn't consistent... did I misunderstand something ?");
+ }
+#endif
+ return pCol->GetId();
+}
+
+sal_uInt16 DbGridControl::GetModelColumnPos( sal_uInt16 nId ) const
+{
+ for ( size_t i = 0; i < m_aColumns.size(); ++i )
+ if ( m_aColumns[ i ]->GetId() == nId )
+ return i;
+
+ return GRID_COLUMN_NOT_FOUND;
+}
+
+void DbGridControl::implAdjustInSolarThread(bool _bRows)
+{
+ SAL_INFO("svx.fmcomp", "DbGridControl::implAdjustInSolarThread");
+ ::osl::MutexGuard aGuard(m_aAdjustSafety);
+ if (!Application::IsMainThread())
+ {
+ m_nAsynAdjustEvent = PostUserEvent(LINK(this, DbGridControl, OnAsyncAdjust), reinterpret_cast< void* >( _bRows ), true);
+ m_bPendingAdjustRows = _bRows;
+ if (_bRows)
+ SAL_INFO("svx.fmcomp", "posting an AdjustRows");
+ else
+ SAL_INFO("svx.fmcomp", "posting an AdjustDataSource");
+ }
+ else
+ {
+ if (_bRows)
+ SAL_INFO("svx.fmcomp", "doing an AdjustRows");
+ else
+ SAL_INFO("svx.fmcomp", "doing an AdjustDataSource");
+ // always adjust the rows before adjusting the data source
+ // If this is not necessary (because the row count did not change), nothing is done
+ // The problem is that we can't rely on the order of which the calls come in: If the cursor was moved
+ // to a position behind row count know 'til now, the cursorMoved notification may come before the
+ // RowCountChanged notification
+ // 94093 - 02.11.2001 - frank.schoenheit@sun.com
+ AdjustRows();
+
+ if ( !_bRows )
+ AdjustDataSource();
+ }
+}
+
+IMPL_LINK(DbGridControl, OnAsyncAdjust, void*, pAdjustWhat, void)
+{
+ m_nAsynAdjustEvent = nullptr;
+
+ AdjustRows();
+ // see implAdjustInSolarThread for a comment why we do this every time
+
+ if ( !pAdjustWhat )
+ AdjustDataSource();
+}
+
+void DbGridControl::BeginCursorAction()
+{
+ if (m_pFieldListeners)
+ {
+ ColumnFieldValueListeners* pListeners = static_cast<ColumnFieldValueListeners*>(m_pFieldListeners);
+ for (const auto& rListener : *pListeners)
+ {
+ GridFieldValueListener* pCurrent = rListener.second;
+ if (pCurrent)
+ pCurrent->suspend();
+ }
+ }
+
+ if (m_pDataSourcePropListener)
+ m_pDataSourcePropListener->suspend();
+}
+
+void DbGridControl::EndCursorAction()
+{
+ if (m_pFieldListeners)
+ {
+ ColumnFieldValueListeners* pListeners = static_cast<ColumnFieldValueListeners*>(m_pFieldListeners);
+ for (const auto& rListener : *pListeners)
+ {
+ GridFieldValueListener* pCurrent = rListener.second;
+ if (pCurrent)
+ pCurrent->resume();
+ }
+ }
+
+ if (m_pDataSourcePropListener)
+ m_pDataSourcePropListener->resume();
+}
+
+void DbGridControl::ConnectToFields()
+{
+ ColumnFieldValueListeners* pListeners = static_cast<ColumnFieldValueListeners*>(m_pFieldListeners);
+ DBG_ASSERT(!pListeners || pListeners->empty(), "DbGridControl::ConnectToFields : please call DisconnectFromFields first !");
+
+ if (!pListeners)
+ {
+ pListeners = new ColumnFieldValueListeners;
+ m_pFieldListeners = pListeners;
+ }
+
+ for (auto const & pCurrent : m_aColumns)
+ {
+ sal_uInt16 nViewPos = pCurrent ? GetViewColumnPos(pCurrent->GetId()) : GRID_COLUMN_NOT_FOUND;
+ if (GRID_COLUMN_NOT_FOUND == nViewPos)
+ continue;
+
+ Reference< XPropertySet > xField = pCurrent->GetField();
+ if (!xField.is())
+ continue;
+
+ // column is visible and bound here
+ GridFieldValueListener*& rpListener = (*pListeners)[pCurrent->GetId()];
+ DBG_ASSERT(!rpListener, "DbGridControl::ConnectToFields : already a listener for this column ?!");
+ rpListener = new GridFieldValueListener(*this, xField, pCurrent->GetId());
+ }
+}
+
+void DbGridControl::DisconnectFromFields()
+{
+ if (!m_pFieldListeners)
+ return;
+
+ ColumnFieldValueListeners* pListeners = static_cast<ColumnFieldValueListeners*>(m_pFieldListeners);
+ while (!pListeners->empty())
+ {
+ sal_Int32 nOldSize = pListeners->size();
+ pListeners->begin()->second->dispose();
+ DBG_ASSERT(nOldSize > static_cast<sal_Int32>(pListeners->size()), "DbGridControl::DisconnectFromFields : dispose on a listener should result in a removal from my list !");
+ }
+
+ delete pListeners;
+ m_pFieldListeners = nullptr;
+}
+
+void DbGridControl::FieldValueChanged(sal_uInt16 _nId)
+{
+ osl::MutexGuard aPreventDestruction(m_aDestructionSafety);
+ // needed as this may run in a thread other than the main one
+ if (GetRowStatus(GetCurRow()) != EditBrowseBox::MODIFIED)
+ // all other cases are handled elsewhere
+ return;
+
+ size_t Location = GetModelColumnPos( _nId );
+ DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
+ if (!pColumn)
+ return;
+
+ std::unique_ptr<vcl::SolarMutexTryAndBuyGuard> pGuard;
+ while (!m_bWantDestruction && (!pGuard || !pGuard->isAcquired()))
+ pGuard.reset(new vcl::SolarMutexTryAndBuyGuard);
+
+ if (m_bWantDestruction)
+ { // at this moment, within another thread, our destructor tries to destroy the listener which called this method
+ // => don't do anything
+ // 73365 - 23.02.00 - FS
+ return;
+ }
+
+ // and finally do the update ...
+ pColumn->UpdateFromField(m_xCurrentRow.get(), m_xFormatter);
+ RowModified(GetCurRow());
+}
+
+void DbGridControl::FieldListenerDisposing(sal_uInt16 _nId)
+{
+ ColumnFieldValueListeners* pListeners = static_cast<ColumnFieldValueListeners*>(m_pFieldListeners);
+ if (!pListeners)
+ {
+ OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (have no listener array) !");
+ return;
+ }
+
+ ColumnFieldValueListeners::const_iterator aPos = pListeners->find(_nId);
+ if (aPos == pListeners->end())
+ {
+ OSL_FAIL("DbGridControl::FieldListenerDisposing : invalid call (did not find the listener) !");
+ return;
+ }
+
+ delete aPos->second;
+
+ pListeners->erase(aPos);
+}
+
+void DbGridControl::disposing(sal_uInt16 _nId)
+{
+ if (_nId == 0)
+ { // the seek cursor is being disposed
+ ::osl::MutexGuard aGuard(m_aAdjustSafety);
+ setDataSource(nullptr, DbGridControlOptions::Readonly); // our clone was disposed so we set our datasource to null to avoid later access to it
+ if (m_nAsynAdjustEvent)
+ {
+ RemoveUserEvent(m_nAsynAdjustEvent);
+ m_nAsynAdjustEvent = nullptr;
+ }
+ }
+}
+
+sal_Int32 DbGridControl::GetAccessibleControlCount() const
+{
+ return EditBrowseBox::GetAccessibleControlCount() + 1; // the navigation control
+}
+
+Reference<XAccessible > DbGridControl::CreateAccessibleControl( sal_Int32 _nIndex )
+{
+ Reference<XAccessible > xRet;
+ if ( _nIndex == EditBrowseBox::GetAccessibleControlCount() )
+ {
+ xRet = m_aBar->GetAccessible();
+ }
+ else
+ xRet = EditBrowseBox::CreateAccessibleControl( _nIndex );
+ return xRet;
+}
+
+Reference< XAccessible > DbGridControl::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos )
+{
+ sal_uInt16 nColumnId = GetColumnId( _nColumnPos );
+ size_t Location = GetModelColumnPos(nColumnId);
+ DbGridColumn* pColumn = ( Location < m_aColumns.size() ) ? m_aColumns[ Location ].get() : nullptr;
+ if ( pColumn )
+ {
+ Reference< css::awt::XControl> xInt(pColumn->GetCell());
+ Reference< css::awt::XCheckBox> xBox(xInt,UNO_QUERY);
+ if ( xBox.is() )
+ {
+ TriState eValue = TRISTATE_FALSE;
+ switch( xBox->getState() )
+ {
+ case 0:
+ eValue = TRISTATE_FALSE;
+ break;
+ case 1:
+ eValue = TRISTATE_TRUE;
+ break;
+ case 2:
+ eValue = TRISTATE_INDET;
+ break;
+ }
+ return EditBrowseBox::CreateAccessibleCheckBoxCell( _nRow, _nColumnPos,eValue );
+ }
+ }
+ return EditBrowseBox::CreateAccessibleCell( _nRow, _nColumnPos );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/fmcomp/xmlexchg.cxx b/svx/source/fmcomp/xmlexchg.cxx
new file mode 100644
index 000000000..1f8d44ee7
--- /dev/null
+++ b/svx/source/fmcomp/xmlexchg.cxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/xmlexchg.hxx>
+#include <sot/formats.hxx>
+#include <sot/exchange.hxx>
+
+namespace svx
+{
+
+
+ using namespace ::com::sun::star::datatransfer;
+
+ OXFormsTransferable::OXFormsTransferable( const OXFormsDescriptor &rhs ) :
+ m_aDescriptor(rhs)
+ {
+ }
+
+ void OXFormsTransferable::AddSupportedFormats()
+ {
+ AddFormat( SotClipboardFormatId::XFORMS );
+ }
+
+ bool OXFormsTransferable::GetData( const DataFlavor& _rFlavor, const OUString& /*rDestDoc*/ )
+ {
+ const SotClipboardFormatId nFormatId = SotExchange::GetFormat( _rFlavor );
+ if ( SotClipboardFormatId::XFORMS == nFormatId )
+ {
+ return SetString("XForms-Transferable");
+ }
+ return false;
+ }
+
+ const OXFormsDescriptor &OXFormsTransferable::extractDescriptor( const TransferableDataHelper &_rData ) {
+
+ using namespace ::com::sun::star::uno;
+ Reference<XTransferable> &transfer = const_cast<Reference<XTransferable> &>(_rData.GetTransferable());
+ XTransferable *pInterface = transfer.get();
+ OXFormsTransferable& rThis = dynamic_cast<OXFormsTransferable&>(*pInterface);
+ return rThis.m_aDescriptor;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/ParseContext.cxx b/svx/source/form/ParseContext.cxx
new file mode 100644
index 000000000..636341791
--- /dev/null
+++ b/svx/source/form/ParseContext.cxx
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sal/macros.h>
+#include <svx/ParseContext.hxx>
+#include <svx/strings.hrc>
+
+#include <svx/dialmgr.hxx>
+
+#include <i18nlangtag/languagetag.hxx>
+#include <unotools/syslocale.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+#include <fmstring.hrc>
+#include <mutex>
+
+using namespace svxform;
+using namespace ::connectivity;
+
+OSystemParseContext::OSystemParseContext()
+ : IParseContext()
+{
+ for (size_t i = 0; i < SAL_N_ELEMENTS(RID_RSC_SQL_INTERNATIONAL); ++i)
+ m_aLocalizedKeywords.push_back(SvxResId(RID_RSC_SQL_INTERNATIONAL[i]));
+}
+
+OSystemParseContext::~OSystemParseContext()
+{
+}
+
+css::lang::Locale OSystemParseContext::getPreferredLocale( ) const
+{
+ return SvtSysLocale().GetLanguageTag().getLocale();
+}
+
+OUString OSystemParseContext::getErrorMessage(ErrorCode _eCode) const
+{
+ OUString aMsg;
+ SolarMutexGuard aGuard;
+ switch (_eCode)
+ {
+ case ErrorCode::General: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_ERROR); break;
+ case ErrorCode::ValueNoLike: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_VALUE_NO_LIKE); break;
+ case ErrorCode::FieldNoLike: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_FIELD_NO_LIKE); break;
+ case ErrorCode::InvalidCompare: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_CRIT_NO_COMPARE); break;
+ case ErrorCode::InvalidIntCompare: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_INT_NO_VALID); break;
+ case ErrorCode::InvalidDateCompare: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_ACCESS_DAT_NO_VALID); break;
+ case ErrorCode::InvalidRealCompare: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_REAL_NO_VALID); break;
+ case ErrorCode::InvalidTableNosuch: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_TABLE); break;
+ case ErrorCode::InvalidTableOrQuery: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_TABLE_OR_QUERY); break;
+ case ErrorCode::InvalidColumn: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_COLUMN); break;
+ case ErrorCode::InvalidTableExist: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_TABLE_EXISTS); break;
+ case ErrorCode::InvalidQueryExist: aMsg = SvxResId(RID_STR_SVT_SQL_SYNTAX_QUERY_EXISTS); break;
+ default: break;
+ }
+ return aMsg;
+}
+
+OString OSystemParseContext::getIntlKeywordAscii(InternationalKeyCode _eKey) const
+{
+ size_t nIndex = 0;
+ switch ( _eKey )
+ {
+ case InternationalKeyCode::Like: nIndex = 0; break;
+ case InternationalKeyCode::Not: nIndex = 1; break;
+ case InternationalKeyCode::Null: nIndex = 2; break;
+ case InternationalKeyCode::True: nIndex = 3; break;
+ case InternationalKeyCode::False: nIndex = 4; break;
+ case InternationalKeyCode::Is: nIndex = 5; break;
+ case InternationalKeyCode::Between: nIndex = 6; break;
+ case InternationalKeyCode::Or: nIndex = 7; break;
+ case InternationalKeyCode::And: nIndex = 8; break;
+ case InternationalKeyCode::Avg: nIndex = 9; break;
+ case InternationalKeyCode::Count: nIndex = 10; break;
+ case InternationalKeyCode::Max: nIndex = 11; break;
+ case InternationalKeyCode::Min: nIndex = 12; break;
+ case InternationalKeyCode::Sum: nIndex = 13; break;
+ case InternationalKeyCode::Every: nIndex = 14; break;
+ case InternationalKeyCode::Any: nIndex = 15; break;
+ case InternationalKeyCode::Some: nIndex = 16; break;
+ case InternationalKeyCode::StdDevPop: nIndex = 17; break;
+ case InternationalKeyCode::StdDevSamp: nIndex = 18; break;
+ case InternationalKeyCode::VarSamp: nIndex = 19; break;
+ case InternationalKeyCode::VarPop: nIndex = 20; break;
+ case InternationalKeyCode::Collect: nIndex = 21; break;
+ case InternationalKeyCode::Fusion: nIndex = 22; break;
+ case InternationalKeyCode::Intersection: nIndex = 23; break;
+ case InternationalKeyCode::None:
+ OSL_FAIL( "OSystemParseContext::getIntlKeywordAscii: illegal argument!" );
+ break;
+ }
+
+ OSL_ENSURE( nIndex < m_aLocalizedKeywords.size(), "OSystemParseContext::getIntlKeywordAscii: invalid index!" );
+
+ OString sKeyword;
+ if ( nIndex < m_aLocalizedKeywords.size() )
+ sKeyword = OUStringToOString(m_aLocalizedKeywords[nIndex], RTL_TEXTENCODING_UTF8);
+ return sKeyword;
+}
+
+
+IParseContext::InternationalKeyCode OSystemParseContext::getIntlKeyCode(const OString& rToken) const
+{
+ static const IParseContext::InternationalKeyCode Intl_TokenID[] =
+ {
+ InternationalKeyCode::Like, InternationalKeyCode::Not, InternationalKeyCode::Null, InternationalKeyCode::True,
+ InternationalKeyCode::False, InternationalKeyCode::Is, InternationalKeyCode::Between, InternationalKeyCode::Or,
+ InternationalKeyCode::And, InternationalKeyCode::Avg, InternationalKeyCode::Count, InternationalKeyCode::Max,
+ InternationalKeyCode::Min, InternationalKeyCode::Sum, InternationalKeyCode::Every,
+ InternationalKeyCode::Any, InternationalKeyCode::Some, InternationalKeyCode::StdDevPop,
+ InternationalKeyCode::StdDevSamp, InternationalKeyCode::VarSamp, InternationalKeyCode::VarPop,
+ InternationalKeyCode::Collect, InternationalKeyCode::Fusion, InternationalKeyCode::Intersection
+ };
+
+ sal_uInt32 const nCount = SAL_N_ELEMENTS(Intl_TokenID);
+ for (sal_uInt32 i = 0; i < nCount; i++)
+ {
+ OString aKey = getIntlKeywordAscii(Intl_TokenID[i]);
+ if (rToken.equalsIgnoreAsciiCase(aKey))
+ return Intl_TokenID[i];
+ }
+
+ return InternationalKeyCode::None;
+}
+
+
+namespace
+{
+
+ std::mutex& getSafetyMutex()
+ {
+ static ::std::mutex s_aSafety;
+ return s_aSafety;
+ }
+
+ int s_nCounter;
+
+ OSystemParseContext* getSharedContext(OSystemParseContext* _pContext, bool _bSet)
+ {
+ static OSystemParseContext* s_pSharedContext = nullptr;
+ if ( _pContext && !s_pSharedContext )
+ {
+ s_pSharedContext = _pContext;
+ return s_pSharedContext;
+ }
+ if ( _bSet )
+ {
+ OSystemParseContext* pReturn = _pContext ? _pContext : s_pSharedContext;
+ s_pSharedContext = _pContext;
+ return pReturn;
+ }
+ return s_pSharedContext;
+ }
+
+}
+
+OParseContextClient::OParseContextClient()
+{
+ std::scoped_lock aGuard( getSafetyMutex() );
+ ++s_nCounter;
+ if ( 1 == s_nCounter )
+ { // first instance
+ getSharedContext( new OSystemParseContext, false );
+ }
+}
+
+
+OParseContextClient::~OParseContextClient()
+{
+ std::scoped_lock aGuard( getSafetyMutex() );
+ --s_nCounter;
+ if ( 0 == s_nCounter )
+ delete getSharedContext(nullptr,true);
+}
+
+const OSystemParseContext* OParseContextClient::getParseContext() const
+{
+ return getSharedContext(nullptr, false);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/dataaccessdescriptor.cxx b/svx/source/form/dataaccessdescriptor.cxx
new file mode 100644
index 000000000..78538fbeb
--- /dev/null
+++ b/svx/source/form/dataaccessdescriptor.cxx
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dataaccessdescriptor.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <tools/urlobj.hxx>
+#include <map>
+
+namespace svx
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::ucb;
+
+ typedef std::pair<OUString const, DataAccessDescriptorProperty> PropertyMapEntry;
+
+ class ODADescriptorImpl
+ {
+ protected:
+ bool m_bSetOutOfDate : 1;
+ bool m_bSequenceOutOfDate : 1;
+
+ public:
+ typedef ::std::map< DataAccessDescriptorProperty, Any > DescriptorValues;
+ DescriptorValues m_aValues;
+ Sequence< PropertyValue > m_aAsSequence;
+
+ typedef ::std::map< OUString, DataAccessDescriptorProperty > MapString2PropertyEntry;
+
+ public:
+ ODADescriptorImpl();
+ ODADescriptorImpl(const ODADescriptorImpl& _rSource);
+
+ void invalidateExternRepresentations();
+
+ void updateSequence();
+
+ /** builds the descriptor from a property value sequence
+ @return <TRUE/>
+ if and only if the sequence contained valid properties only
+ */
+ bool buildFrom( const Sequence< PropertyValue >& _rValues );
+
+ /** builds the descriptor from a property set
+ @return <TRUE/>
+ if and only if the set contained valid properties only
+ */
+ bool buildFrom( const Reference< XPropertySet >& _rValues );
+
+ protected:
+ static PropertyValue buildPropertyValue( const DescriptorValues::const_iterator& _rPos );
+ static const MapString2PropertyEntry& getPropertyMap( );
+ static PropertyMapEntry const * getPropertyMapEntry( const DescriptorValues::const_iterator& _rPos );
+ };
+
+ ODADescriptorImpl::ODADescriptorImpl()
+ :m_bSetOutOfDate(true)
+ ,m_bSequenceOutOfDate(true)
+ {
+ }
+
+ ODADescriptorImpl::ODADescriptorImpl(const ODADescriptorImpl& _rSource)
+ :m_bSetOutOfDate( _rSource.m_bSetOutOfDate )
+ ,m_bSequenceOutOfDate( _rSource.m_bSequenceOutOfDate )
+ ,m_aValues( _rSource.m_aValues )
+ {
+ if (!m_bSequenceOutOfDate)
+ m_aAsSequence = _rSource.m_aAsSequence;
+ }
+
+ bool ODADescriptorImpl::buildFrom( const Sequence< PropertyValue >& _rValues )
+ {
+ const MapString2PropertyEntry& rProperties = getPropertyMap();
+
+ bool bValidPropsOnly = true;
+
+ // loop through the sequence, and fill our m_aValues
+ for (const PropertyValue& rValue : _rValues)
+ {
+ MapString2PropertyEntry::const_iterator aPropPos = rProperties.find( rValue.Name );
+ if ( aPropPos != rProperties.end() )
+ {
+ DataAccessDescriptorProperty eProperty = aPropPos->second;
+ m_aValues[eProperty] = rValue.Value;
+ }
+ else
+ // unknown property
+ bValidPropsOnly = false;
+ }
+
+ if (bValidPropsOnly)
+ {
+ m_aAsSequence = _rValues;
+ m_bSequenceOutOfDate = false;
+ }
+ else
+ m_bSequenceOutOfDate = true;
+
+ return bValidPropsOnly;
+ }
+
+ bool ODADescriptorImpl::buildFrom( const Reference< XPropertySet >& _rxValues )
+ {
+ Reference< XPropertySetInfo > xPropInfo;
+ if (_rxValues.is())
+ xPropInfo = _rxValues->getPropertySetInfo();
+ if (!xPropInfo.is())
+ {
+ OSL_FAIL("ODADescriptorImpl::buildFrom: invalid property set!");
+ return false;
+ }
+
+ // build a PropertyValue sequence with the current values
+ const Sequence< Property > aProperties = xPropInfo->getProperties();
+
+ Sequence< PropertyValue > aValues(aProperties.getLength());
+ PropertyValue* pValues = aValues.getArray();
+
+ for (const Property& rProperty : aProperties)
+ {
+ pValues->Name = rProperty.Name;
+ pValues->Value = _rxValues->getPropertyValue(rProperty.Name);
+ ++pValues;
+ }
+
+ bool bValidPropsOnly = buildFrom(aValues);
+ m_bSetOutOfDate = !bValidPropsOnly;
+
+ return bValidPropsOnly;
+ }
+
+ void ODADescriptorImpl::invalidateExternRepresentations()
+ {
+ m_bSetOutOfDate = true;
+ m_bSequenceOutOfDate = true;
+ }
+
+ const ODADescriptorImpl::MapString2PropertyEntry& ODADescriptorImpl::getPropertyMap( )
+ {
+ // the properties we know
+ static MapString2PropertyEntry s_aProperties
+ {
+ { OUString("ActiveConnection"), DataAccessDescriptorProperty::Connection, },
+ { OUString("BookmarkSelection"), DataAccessDescriptorProperty::BookmarkSelection, },
+ { OUString("Column"), DataAccessDescriptorProperty::ColumnObject, },
+ { OUString("ColumnName"), DataAccessDescriptorProperty::ColumnName, },
+ { OUString("Command"), DataAccessDescriptorProperty::Command, },
+ { OUString("CommandType"), DataAccessDescriptorProperty::CommandType, },
+ { OUString("Component"), DataAccessDescriptorProperty::Component, },
+ { OUString("ConnectionResource"), DataAccessDescriptorProperty::ConnectionResource, },
+ { OUString("Cursor"), DataAccessDescriptorProperty::Cursor, },
+ { OUString("DataSourceName"), DataAccessDescriptorProperty::DataSource, },
+ { OUString("DatabaseLocation"), DataAccessDescriptorProperty::DatabaseLocation, },
+ { OUString("EscapeProcessing"), DataAccessDescriptorProperty::EscapeProcessing, },
+ { OUString("Filter"), DataAccessDescriptorProperty::Filter, },
+ { OUString("Selection"), DataAccessDescriptorProperty::Selection, }
+ };
+
+ return s_aProperties;
+ }
+
+ PropertyMapEntry const * ODADescriptorImpl::getPropertyMapEntry( const DescriptorValues::const_iterator& _rPos )
+ {
+ const MapString2PropertyEntry& rProperties = getPropertyMap();
+
+ DataAccessDescriptorProperty nNeededHandle = _rPos->first;
+
+ auto loop = std::find_if(rProperties.begin(), rProperties.end(),
+ [&nNeededHandle](const MapString2PropertyEntry::value_type& rProp) { return nNeededHandle == rProp.second; });
+ if (loop != rProperties.end())
+ return &*loop;
+ throw RuntimeException();
+ }
+
+ PropertyValue ODADescriptorImpl::buildPropertyValue( const DescriptorValues::const_iterator& _rPos )
+ {
+ // the map entry
+ PropertyMapEntry const * pProperty = getPropertyMapEntry( _rPos );
+
+ // build the property value
+ PropertyValue aReturn;
+ aReturn.Name = pProperty->first;
+ aReturn.Handle = static_cast<sal_Int32>(pProperty->second);
+ aReturn.Value = _rPos->second;
+ aReturn.State = PropertyState_DIRECT_VALUE;
+
+ // outta here
+ return aReturn;
+ }
+
+ void ODADescriptorImpl::updateSequence()
+ {
+ if (!m_bSequenceOutOfDate)
+ return;
+
+ m_aAsSequence.realloc(m_aValues.size());
+ PropertyValue* pValue = m_aAsSequence.getArray();
+
+ // loop through all our values
+ for ( DescriptorValues::const_iterator aLoop = m_aValues.begin();
+ aLoop != m_aValues.end();
+ ++aLoop, ++pValue
+ )
+ {
+ *pValue = buildPropertyValue(aLoop);
+ }
+
+ // don't need to rebuild next time
+ m_bSequenceOutOfDate = false;
+ }
+
+ ODataAccessDescriptor::ODataAccessDescriptor()
+ :m_pImpl(new ODADescriptorImpl)
+ {
+ }
+
+ ODataAccessDescriptor::ODataAccessDescriptor( const ODataAccessDescriptor& _rSource )
+ :m_pImpl(new ODADescriptorImpl(*_rSource.m_pImpl))
+ {
+ }
+
+ ODataAccessDescriptor::ODataAccessDescriptor(ODataAccessDescriptor&& _rSource) noexcept
+ :m_pImpl(std::move(_rSource.m_pImpl))
+ {
+ }
+
+ ODataAccessDescriptor& ODataAccessDescriptor::operator=(const ODataAccessDescriptor& _rSource)
+ {
+ if (this != &_rSource)
+ m_pImpl.reset(new ODADescriptorImpl(*_rSource.m_pImpl));
+ return *this;
+ }
+
+ ODataAccessDescriptor& ODataAccessDescriptor::operator=(ODataAccessDescriptor&& _rSource) noexcept
+ {
+ m_pImpl = std::move(_rSource.m_pImpl);
+ return *this;
+ }
+
+ ODataAccessDescriptor::ODataAccessDescriptor( const Reference< XPropertySet >& _rValues )
+ :m_pImpl(new ODADescriptorImpl)
+ {
+ m_pImpl->buildFrom(_rValues);
+ }
+
+ ODataAccessDescriptor::ODataAccessDescriptor( const Any& _rValues )
+ :m_pImpl(new ODADescriptorImpl)
+ {
+ // check if we know the format in the Any
+ Sequence< PropertyValue > aValues;
+ Reference< XPropertySet > xValues;
+ if ( _rValues >>= aValues )
+ m_pImpl->buildFrom( aValues );
+ else if ( _rValues >>= xValues )
+ m_pImpl->buildFrom( xValues );
+ }
+
+ ODataAccessDescriptor::ODataAccessDescriptor( const Sequence< PropertyValue >& _rValues )
+ :m_pImpl(new ODADescriptorImpl)
+ {
+ m_pImpl->buildFrom(_rValues);
+ }
+
+ ODataAccessDescriptor::~ODataAccessDescriptor()
+ {
+ }
+
+ void ODataAccessDescriptor::clear()
+ {
+ m_pImpl->m_aValues.clear();
+ }
+
+ void ODataAccessDescriptor::erase(DataAccessDescriptorProperty _eWhich)
+ {
+ OSL_ENSURE(has(_eWhich), "ODataAccessDescriptor::erase: invalid call!");
+ if (has(_eWhich))
+ m_pImpl->m_aValues.erase(_eWhich);
+ }
+
+ bool ODataAccessDescriptor::has(DataAccessDescriptorProperty _eWhich) const
+ {
+ return m_pImpl->m_aValues.find(_eWhich) != m_pImpl->m_aValues.end();
+ }
+
+ const Any& ODataAccessDescriptor::operator [] ( DataAccessDescriptorProperty _eWhich ) const
+ {
+ if (!has(_eWhich))
+ {
+ OSL_FAIL("ODataAccessDescriptor::operator[]: invalid accessor!");
+ static const Any aDummy;
+ return aDummy;
+ }
+
+ return m_pImpl->m_aValues[_eWhich];
+ }
+
+ Any& ODataAccessDescriptor::operator[] ( DataAccessDescriptorProperty _eWhich )
+ {
+ m_pImpl->invalidateExternRepresentations();
+ return m_pImpl->m_aValues[_eWhich];
+ }
+
+ void ODataAccessDescriptor::initializeFrom(const Sequence< PropertyValue >& _rValues)
+ {
+ clear();
+ m_pImpl->buildFrom(_rValues);
+ }
+
+ Sequence< PropertyValue > const & ODataAccessDescriptor::createPropertyValueSequence()
+ {
+ m_pImpl->updateSequence();
+ return m_pImpl->m_aAsSequence;
+ }
+
+ OUString ODataAccessDescriptor::getDataSource() const
+ {
+ OUString sDataSourceName;
+ if ( has(DataAccessDescriptorProperty::DataSource) )
+ (*this)[DataAccessDescriptorProperty::DataSource] >>= sDataSourceName;
+ else if ( has(DataAccessDescriptorProperty::DatabaseLocation) )
+ (*this)[DataAccessDescriptorProperty::DatabaseLocation] >>= sDataSourceName;
+ return sDataSourceName;
+ }
+
+ void ODataAccessDescriptor::setDataSource(const OUString& _sDataSourceNameOrLocation)
+ {
+ if ( !_sDataSourceNameOrLocation.isEmpty() )
+ {
+ INetURLObject aURL(_sDataSourceNameOrLocation);
+ (*this)[ (( aURL.GetProtocol() == INetProtocol::File ) ? DataAccessDescriptorProperty::DatabaseLocation : DataAccessDescriptorProperty::DataSource)] <<= _sDataSourceNameOrLocation;
+ }
+ else
+ (*this)[ DataAccessDescriptorProperty::DataSource ] <<= OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/databaselocationinput.cxx b/svx/source/form/databaselocationinput.cxx
new file mode 100644
index 000000000..018fd3f5e
--- /dev/null
+++ b/svx/source/form/databaselocationinput.cxx
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/databaselocationinput.hxx>
+#include <svx/dialmgr.hxx>
+
+#include <svx/strings.hrc>
+
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <svl/filenotation.hxx>
+#include <svtools/inettbc.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/confignode.hxx>
+#include <unotools/ucbhelper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+namespace svx
+{
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Exception;
+
+ namespace TemplateDescription = ::com::sun::star::ui::dialogs::TemplateDescription;
+
+ class DatabaseLocationInputController_Impl
+ {
+ public:
+ DatabaseLocationInputController_Impl(
+ const Reference<XComponentContext>& _rContext,
+ SvtURLBox& _rLocationInput,
+ weld::Button& _rBrowseButton,
+ weld::Window& _rDialog
+ );
+
+ bool prepareCommit();
+ void setURL( const OUString& _rURL );
+ OUString getURL() const;
+
+ private:
+ void impl_initFilterProperties_nothrow();
+ void impl_onBrowseButtonClicked();
+ OUString impl_getCurrentURL() const;
+
+ DECL_LINK( OnButtonAction, weld::Button&, void );
+
+ private:
+ const Reference<XComponentContext> m_xContext;
+ SvtURLBox& m_rLocationInput;
+ weld::Window& m_rDialog;
+ Sequence< OUString > m_aFilterExtensions;
+ OUString m_sFilterUIName;
+ bool m_bNeedExistenceCheck;
+ };
+
+ DatabaseLocationInputController_Impl::DatabaseLocationInputController_Impl(const Reference<XComponentContext>& _rContext,
+ SvtURLBox& _rLocationInput, weld::Button& _rBrowseButton, weld::Window& _rDialog)
+ :m_xContext( _rContext )
+ ,m_rLocationInput( _rLocationInput )
+ ,m_rDialog( _rDialog )
+ ,m_bNeedExistenceCheck( true )
+ {
+ impl_initFilterProperties_nothrow();
+
+ // forward the allowed extensions to the input control
+ OUStringBuffer aExtensionList;
+ for ( auto const & extension : std::as_const(m_aFilterExtensions) )
+ {
+ aExtensionList.append( extension );
+ aExtensionList.append( ';' );
+ }
+ m_rLocationInput.SetFilter( aExtensionList.makeStringAndClear() );
+ _rBrowseButton.connect_clicked(LINK(this, DatabaseLocationInputController_Impl, OnButtonAction));
+ }
+
+ bool DatabaseLocationInputController_Impl::prepareCommit()
+ {
+ OUString sURL( impl_getCurrentURL() );
+ if ( sURL.isEmpty() )
+ return false;
+
+ // check if the name exists
+ if ( m_bNeedExistenceCheck )
+ {
+ if ( ::utl::UCBContentHelper::Exists( sURL ) )
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_rLocationInput.getWidget(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ SvxResId(RID_STR_ALREADYEXISTOVERWRITE)));
+ if (xQueryBox->run() != RET_YES)
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void DatabaseLocationInputController_Impl::setURL( const OUString& _rURL )
+ {
+ ::svt::OFileNotation aTransformer( _rURL );
+ m_rLocationInput.set_entry_text( aTransformer.get( ::svt::OFileNotation::N_SYSTEM ) );
+ }
+
+ OUString DatabaseLocationInputController_Impl::getURL() const
+ {
+ return impl_getCurrentURL();
+ }
+
+ void DatabaseLocationInputController_Impl::impl_initFilterProperties_nothrow()
+ {
+ try
+ {
+ // get the name of the default filter for database documents
+ ::utl::OConfigurationTreeRoot aConfig(
+ ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ m_xContext,
+ "/org.openoffice.Setup/Office/Factories/com.sun.star.sdb.OfficeDatabaseDocument"
+ ) );
+ OUString sDatabaseFilter;
+ OSL_VERIFY( aConfig.getNodeValue( "ooSetupFactoryActualFilter" ) >>= sDatabaseFilter );
+
+ // get the type this filter is responsible for
+ Reference< XNameAccess > xFilterFactory(
+ m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", m_xContext),
+ UNO_QUERY_THROW );
+ ::comphelper::NamedValueCollection aFilterProperties( xFilterFactory->getByName( sDatabaseFilter ) );
+ OUString sDocumentType = aFilterProperties.getOrDefault( "Type", OUString() );
+
+ // get the extension(s) for this type
+ Reference< XNameAccess > xTypeDetection(
+ m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", m_xContext),
+ UNO_QUERY_THROW );
+
+ ::comphelper::NamedValueCollection aTypeProperties( xTypeDetection->getByName( sDocumentType ) );
+ m_aFilterExtensions = aTypeProperties.getOrDefault( "Extensions", m_aFilterExtensions );
+ m_sFilterUIName = aTypeProperties.getOrDefault( "UIName", m_sFilterUIName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ // ensure we have at least one extension
+ OSL_ENSURE( m_aFilterExtensions.hasElements(),
+ "DatabaseLocationInputController_Impl::impl_initFilterProperties_nothrow: unable to determine the file extension(s)!" );
+ if ( !m_aFilterExtensions.hasElements() )
+ {
+ m_aFilterExtensions = { "*.odb" };
+ }
+ }
+
+ IMPL_LINK_NOARG(DatabaseLocationInputController_Impl, OnButtonAction, weld::Button&, void)
+ {
+ impl_onBrowseButtonClicked();
+ }
+
+ OUString DatabaseLocationInputController_Impl::impl_getCurrentURL() const
+ {
+ OUString sCurrentFile( m_rLocationInput.get_active_text() );
+ if ( !sCurrentFile.isEmpty() )
+ {
+ ::svt::OFileNotation aCurrentFile( sCurrentFile );
+ sCurrentFile = aCurrentFile.get( ::svt::OFileNotation::N_URL );
+ }
+ return sCurrentFile;
+ }
+
+ void DatabaseLocationInputController_Impl::impl_onBrowseButtonClicked()
+ {
+ ::sfx2::FileDialogHelper aFileDlg(
+ TemplateDescription::FILESAVE_AUTOEXTENSION,
+ FileDialogFlags::NONE,
+ &m_rDialog
+ );
+ aFileDlg.SetDisplayDirectory( impl_getCurrentURL() );
+
+ aFileDlg.AddFilter( m_sFilterUIName, "*." + m_aFilterExtensions[0] );
+ aFileDlg.SetCurrentFilter( m_sFilterUIName );
+
+ if ( aFileDlg.Execute() == ERRCODE_NONE )
+ {
+ INetURLObject aURL( aFileDlg.GetPath() );
+ if( aURL.GetProtocol() != INetProtocol::NotValid )
+ {
+ ::svt::OFileNotation aFileNotation( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ m_rLocationInput.set_entry_text(aFileNotation.get(::svt::OFileNotation::N_SYSTEM));
+ m_rLocationInput.trigger_changed();
+ // the dialog already checked for the file's existence, so we don't need to, again
+ m_bNeedExistenceCheck = false;
+ }
+ }
+ }
+
+ DatabaseLocationInputController::DatabaseLocationInputController( const Reference<XComponentContext>& _rContext,
+ SvtURLBox& _rLocationInput, weld::Button& _rBrowseButton, weld::Window& _rDialog )
+ :m_pImpl( new DatabaseLocationInputController_Impl( _rContext, _rLocationInput, _rBrowseButton, _rDialog ) )
+ {
+ }
+
+ DatabaseLocationInputController::~DatabaseLocationInputController()
+ {
+ }
+
+ bool DatabaseLocationInputController::prepareCommit()
+ {
+ return m_pImpl->prepareCommit();
+ }
+
+ void DatabaseLocationInputController::setURL( const OUString& _rURL )
+ {
+ m_pImpl->setURL( _rURL );
+ }
+
+ OUString DatabaseLocationInputController::getURL() const
+ {
+ return m_pImpl->getURL();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/datalistener.cxx b/svx/source/form/datalistener.cxx
new file mode 100644
index 000000000..fda74a92c
--- /dev/null
+++ b/svx/source/form/datalistener.cxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <datalistener.hxx>
+#include <datanavi.hxx>
+
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::xml::dom::events;
+
+
+namespace svxform
+{
+
+
+ DataListener::DataListener( DataNavigatorWindow* pNaviWin ) :
+
+ m_pNaviWin( pNaviWin )
+
+ {
+ DBG_ASSERT( m_pNaviWin, "DataListener::Ctor(): no navigator win" );
+ }
+
+ DataListener::~DataListener()
+ {
+ }
+
+ // XContainerListener
+ void SAL_CALL DataListener::elementInserted( const ContainerEvent& /*Event*/ )
+ {
+ m_pNaviWin->NotifyChanges();
+ }
+
+ void SAL_CALL DataListener::elementRemoved( const ContainerEvent& /*Event*/ )
+ {
+ m_pNaviWin->NotifyChanges();
+ }
+
+ void SAL_CALL DataListener::elementReplaced( const ContainerEvent& /*Event*/ )
+ {
+ m_pNaviWin->NotifyChanges();
+ }
+
+ // XFrameActionListener
+ void SAL_CALL DataListener::frameAction( const FrameActionEvent& rActionEvt )
+ {
+ if ( FrameAction_COMPONENT_ATTACHED == rActionEvt.Action ||
+ FrameAction_COMPONENT_REATTACHED == rActionEvt.Action )
+ {
+ m_pNaviWin->NotifyChanges( FrameAction_COMPONENT_REATTACHED == rActionEvt.Action );
+ }
+ }
+
+ // xml::dom::events::XEventListener
+ void SAL_CALL DataListener::handleEvent( const Reference< XEvent >& /*evt*/ )
+ {
+ m_pNaviWin->NotifyChanges();
+ }
+
+ // lang::XEventListener
+ void SAL_CALL DataListener::disposing( const EventObject& /*Source*/ )
+ {
+ SAL_WARN( "svx.form", "disposing" );
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/datanavi.cxx b/svx/source/form/datanavi.cxx
new file mode 100644
index 000000000..80b4dab1b
--- /dev/null
+++ b/svx/source/form/datanavi.cxx
@@ -0,0 +1,3090 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <sal/log.hxx>
+#include <datanavi.hxx>
+#include <fmservs.hxx>
+
+#include <bitmaps.hlst>
+#include <fpicker/strings.hrc>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <svx/svxids.hrc>
+#include <tools/diagnose_ex.h>
+#include <unotools/resmgr.hxx>
+#include <svx/xmlexchg.hxx>
+#include <unotools/viewoptions.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XSet.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/xforms/XFormsSupplier.hpp>
+#include <com/sun/star/xml/dom/XDocument.hpp>
+#include <comphelper/string.hxx>
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::xml::dom::events;
+using namespace ::svx;
+
+constexpr OUStringLiteral CFGNAME_DATANAVIGATOR = u"DataNavigator";
+constexpr OUStringLiteral CFGNAME_SHOWDETAILS = u"ShowDetails";
+constexpr OUStringLiteral MSG_VARIABLE = u"%1";
+constexpr OUStringLiteral MODELNAME = u"$MODELNAME";
+constexpr OUStringLiteral INSTANCENAME = u"$INSTANCENAME";
+constexpr OUStringLiteral ELEMENTNAME = u"$ELEMENTNAME";
+constexpr OUStringLiteral ATTRIBUTENAME = u"$ATTRIBUTENAME";
+constexpr OUStringLiteral SUBMISSIONNAME = u"$SUBMISSIONNAME";
+constexpr OUStringLiteral BINDINGNAME = u"$BINDINGNAME";
+
+
+namespace svxform
+{
+
+ // properties of instance
+ constexpr OUStringLiteral PN_INSTANCE_MODEL = u"Instance";
+ constexpr OUStringLiteral PN_INSTANCE_ID = u"ID";
+ constexpr OUStringLiteral PN_INSTANCE_URL = u"URL";
+
+ // properties of binding
+ constexpr OUStringLiteral PN_BINDING_ID = u"BindingID";
+ constexpr OUStringLiteral PN_BINDING_EXPR = u"BindingExpression";
+ constexpr OUStringLiteral PN_BINDING_MODEL = u"Model";
+ constexpr OUStringLiteral PN_BINDING_NAMESPACES = u"ModelNamespaces";
+ constexpr OUStringLiteral PN_READONLY_EXPR = u"ReadonlyExpression";
+ constexpr OUStringLiteral PN_RELEVANT_EXPR = u"RelevantExpression";
+ constexpr OUStringLiteral PN_REQUIRED_EXPR = u"RequiredExpression";
+ constexpr OUStringLiteral PN_CONSTRAINT_EXPR = u"ConstraintExpression";
+ constexpr OUStringLiteral PN_CALCULATE_EXPR = u"CalculateExpression";
+ constexpr OUStringLiteral PN_BINDING_TYPE = u"Type";
+
+ // properties of submission
+ constexpr OUStringLiteral PN_SUBMISSION_ID = u"ID";
+ constexpr OUStringLiteral PN_SUBMISSION_BIND = u"Bind";
+ constexpr OUStringLiteral PN_SUBMISSION_REF = u"Ref";
+ constexpr OUStringLiteral PN_SUBMISSION_ACTION = u"Action";
+ constexpr OUStringLiteral PN_SUBMISSION_METHOD = u"Method";
+ constexpr OUStringLiteral PN_SUBMISSION_REPLACE = u"Replace";
+
+ // other const strings
+ constexpr OUStringLiteral TRUE_VALUE = u"true()";
+ constexpr OUStringLiteral NEW_ELEMENT = u"newElement";
+ constexpr OUStringLiteral NEW_ATTRIBUTE = u"newAttribute";
+ constexpr OUStringLiteral EVENTTYPE_CHARDATA = u"DOMCharacterDataModified";
+ constexpr OUStringLiteral EVENTTYPE_ATTR = u"DOMAttrModified";
+
+ #define MIN_PAGE_COUNT 3 // at least one instance, one submission and one binding page
+
+ struct ItemNode
+ {
+ Reference< css::xml::dom::XNode > m_xNode;
+ Reference< XPropertySet > m_xPropSet;
+
+ explicit ItemNode( const Reference< css::xml::dom::XNode >& _rxNode ) :
+ m_xNode( _rxNode ) {}
+ explicit ItemNode( const Reference< XPropertySet >& _rxSet ) :
+ m_xPropSet( _rxSet ) {}
+ };
+
+ DataTreeDropTarget::DataTreeDropTarget(weld::TreeView& rWidget)
+ : DropTargetHelper(rWidget.get_drop_target())
+ {
+ }
+
+ sal_Int8 DataTreeDropTarget::AcceptDrop( const AcceptDropEvent& /*rEvt*/ )
+ {
+ return DND_ACTION_NONE;
+ }
+
+ sal_Int8 DataTreeDropTarget::ExecuteDrop( const ExecuteDropEvent& /*rEvt*/ )
+ {
+ return DND_ACTION_NONE;
+ }
+
+ IMPL_LINK(XFormsPage, PopupMenuHdl, const CommandEvent&, rCEvt, bool)
+ {
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ Point aPos(rCEvt.GetMousePosPixel());
+
+ if (m_xItemList->get_dest_row_at_pos(aPos, m_xScratchIter.get(), false) && !m_xItemList->is_selected(*m_xScratchIter))
+ {
+ m_xItemList->select(*m_xScratchIter);
+ ItemSelectHdl(*m_xItemList);
+ }
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xItemList.get(), "svx/ui/formdatamenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+
+ if (DGTInstance == m_eGroup)
+ xMenu->set_visible("additem", false);
+ else
+ {
+ xMenu->set_visible("addelement", false);
+ xMenu->set_visible("addattribute", false);
+
+ if (DGTSubmission == m_eGroup)
+ {
+ xMenu->set_label("additem", SvxResId(RID_STR_DATANAV_ADD_SUBMISSION));
+ xMenu->set_label("edit", SvxResId(RID_STR_DATANAV_EDIT_SUBMISSION));
+ xMenu->set_label("delete", SvxResId(RID_STR_DATANAV_REMOVE_SUBMISSION));
+ }
+ else
+ {
+ xMenu->set_label("additem", SvxResId(RID_STR_DATANAV_ADD_BINDING));
+ xMenu->set_label("edit", SvxResId(RID_STR_DATANAV_EDIT_BINDING));
+ xMenu->set_label("delete", SvxResId(RID_STR_DATANAV_REMOVE_BINDING));
+ }
+ }
+ EnableMenuItems(xMenu.get());
+ OString sCommand = xMenu->popup_at_rect(m_xItemList.get(), tools::Rectangle(aPos, Size(1,1)));
+ if (!sCommand.isEmpty())
+ DoMenuAction(sCommand);
+ return true;
+ }
+
+ void XFormsPage::DeleteAndClearTree()
+ {
+ m_xItemList->all_foreach([this](weld::TreeIter& rEntry) {
+ delete weld::fromId<ItemNode*>(m_xItemList->get_id(rEntry));
+ return false;
+ });
+ m_xItemList->clear();
+ }
+
+ XFormsPage::XFormsPage(weld::Container* pPage, DataNavigatorWindow* _pNaviWin, DataGroupType _eGroup)
+ : BuilderPage(pPage, nullptr, "svx/ui/xformspage.ui", "XFormsPage")
+ , m_pParent(pPage)
+ , m_xToolBox(m_xBuilder->weld_toolbar("toolbar"))
+ , m_xItemList(m_xBuilder->weld_tree_view("items"))
+ , m_xScratchIter(m_xItemList->make_iterator())
+ , m_aDropHelper(*m_xItemList)
+ , m_pNaviWin(_pNaviWin)
+ , m_bHasModel(false)
+ , m_eGroup(_eGroup)
+ , m_bLinkOnce(false)
+ {
+ m_xItemList->set_show_expanders(DGTInstance == m_eGroup || DGTSubmission == m_eGroup);
+
+ if ( DGTInstance == m_eGroup )
+ m_xToolBox->set_item_visible("additem", false);
+ else
+ {
+ m_xToolBox->set_item_visible("addelement", false);
+ m_xToolBox->set_item_visible("addattribute", false);
+
+ if ( DGTSubmission == m_eGroup )
+ {
+ m_xToolBox->set_item_label("additem", SvxResId(RID_STR_DATANAV_ADD_SUBMISSION));
+ m_xToolBox->set_item_label("edit", SvxResId(RID_STR_DATANAV_EDIT_SUBMISSION));
+ m_xToolBox->set_item_label("delete", SvxResId(RID_STR_DATANAV_REMOVE_SUBMISSION));
+ }
+ else
+ {
+ m_xToolBox->set_item_label("additem", SvxResId(RID_STR_DATANAV_ADD_BINDING));
+ m_xToolBox->set_item_label("edit", SvxResId(RID_STR_DATANAV_EDIT_BINDING));
+ m_xToolBox->set_item_label("delete", SvxResId(RID_STR_DATANAV_REMOVE_BINDING));
+ }
+ }
+
+ m_xToolBox->connect_clicked(LINK(this, XFormsPage, TbxSelectHdl));
+
+ m_xItemList->connect_changed(LINK(this, XFormsPage, ItemSelectHdl));
+ m_xItemList->connect_key_press(LINK(this, XFormsPage, KeyInputHdl));
+ m_xItemList->connect_popup_menu(LINK(this, XFormsPage, PopupMenuHdl));
+ ItemSelectHdl(*m_xItemList);
+ }
+
+ XFormsPage::~XFormsPage()
+ {
+ DeleteAndClearTree();
+ m_pNaviWin = nullptr;
+ m_pParent->move(m_xContainer.get(), nullptr);
+ }
+
+ IMPL_LINK(XFormsPage, TbxSelectHdl, const OString&, rIdent, void)
+ {
+ DoToolBoxAction(rIdent);
+ }
+
+ IMPL_LINK_NOARG(XFormsPage, ItemSelectHdl, weld::TreeView&, void)
+ {
+ EnableMenuItems(nullptr);
+ PrepDnD();
+ }
+
+ void XFormsPage::PrepDnD()
+ {
+ rtl::Reference<TransferDataContainer> xTransferable(new TransferDataContainer);
+ m_xItemList->enable_drag_source(xTransferable, DND_ACTION_NONE);
+
+ if (!m_xItemList->get_selected(m_xScratchIter.get()))
+ {
+ // no drag without an entry
+ return;
+ }
+
+ if ( m_eGroup == DGTBinding )
+ {
+ // for the moment, bindings cannot be dragged.
+ // #i59395# / 2005-12-15 / frank.schoenheit@sun.com
+ return;
+ }
+
+ // GetServiceNameForNode() requires a datatype repository which
+ // will be automatically build if requested???
+ Reference< css::xforms::XModel > xModel( GetXFormsHelper(), UNO_QUERY );
+ Reference< css::xforms::XDataTypeRepository > xDataTypes =
+ xModel->getDataTypeRepository();
+ if(!xDataTypes.is())
+ return;
+
+ ItemNode *pItemNode = weld::fromId<ItemNode*>(m_xItemList->get_id(*m_xScratchIter));
+ if (!pItemNode)
+ {
+ // the only known (and allowed?) case where this happens are sub-entries of a submission
+ // entry
+ DBG_ASSERT( DGTSubmission == m_eGroup, "DataTreeListBox::StartDrag: how this?" );
+ bool bSelected = m_xItemList->iter_parent(*m_xScratchIter);
+ DBG_ASSERT(bSelected && !m_xItemList->get_iter_depth(*m_xScratchIter), "DataTreeListBox::StartDrag: what kind of entry *is* this?");
+ // on the submission page, we have only top-level entries (the submission themself)
+ // plus direct children of those (facets of a submission)
+ pItemNode = bSelected ? weld::fromId<ItemNode*>(m_xItemList->get_id(*m_xScratchIter)) : nullptr;
+ if (!pItemNode)
+ return;
+ }
+
+ OXFormsDescriptor desc;
+ desc.szName = m_xItemList->get_text(*m_xScratchIter);
+ if(pItemNode->m_xNode.is()) {
+ // a valid node interface tells us that we need to create a control from a binding
+ desc.szServiceName = GetServiceNameForNode(pItemNode->m_xNode);
+ desc.xPropSet = GetBindingForNode(pItemNode->m_xNode);
+ DBG_ASSERT( desc.xPropSet.is(), "DataTreeListBox::StartDrag(): invalid node binding" );
+ }
+ else {
+ desc.szServiceName = FM_COMPONENT_COMMANDBUTTON;
+ desc.xPropSet = pItemNode->m_xPropSet;
+ }
+ xTransferable = rtl::Reference<TransferDataContainer>(new OXFormsTransferable(desc));
+ m_xItemList->enable_drag_source(xTransferable, DND_ACTION_COPY);
+ }
+
+ void XFormsPage::AddChildren(const weld::TreeIter* _pParent,
+ const Reference< css::xml::dom::XNode >& _xNode)
+ {
+ DBG_ASSERT( m_xUIHelper.is(), "XFormsPage::AddChildren(): invalid UIHelper" );
+
+ try
+ {
+ Reference< css::xml::dom::XNodeList > xNodeList = _xNode->getChildNodes();
+ if ( xNodeList.is() )
+ {
+ bool bShowDetails = m_pNaviWin->IsShowDetails();
+ sal_Int32 i, nNodeCount = xNodeList->getLength();
+ for ( i = 0; i < nNodeCount; ++i )
+ {
+ Reference< css::xml::dom::XNode > xChild = xNodeList->item(i);
+ css::xml::dom::NodeType eChildType = xChild->getNodeType();
+ OUString aExpImg;
+ switch ( eChildType )
+ {
+ case css::xml::dom::NodeType_ATTRIBUTE_NODE:
+ aExpImg = RID_SVXBMP_ATTRIBUTE;
+ break;
+ case css::xml::dom::NodeType_ELEMENT_NODE:
+ aExpImg = RID_SVXBMP_ELEMENT;
+ break;
+ case css::xml::dom::NodeType_TEXT_NODE:
+ aExpImg = RID_SVXBMP_TEXT;
+ break;
+ default:
+ aExpImg = RID_SVXBMP_OTHER;
+ }
+
+ OUString sName = m_xUIHelper->getNodeDisplayName( xChild, bShowDetails );
+ if ( !sName.isEmpty() )
+ {
+ ItemNode* pNode = new ItemNode( xChild );
+ OUString sId(weld::toId(pNode));
+ std::unique_ptr<weld::TreeIter> xEntry = m_xItemList->make_iterator();
+ m_xItemList->insert(_pParent, -1, &sName, &sId, nullptr, nullptr, false, xEntry.get());
+ m_xItemList->set_image(*xEntry, aExpImg);
+
+ if ( xChild->hasAttributes() )
+ {
+ Reference< css::xml::dom::XNamedNodeMap > xMap = xChild->getAttributes();
+ if ( xMap.is() )
+ {
+ aExpImg = RID_SVXBMP_ATTRIBUTE;
+ sal_Int32 j, nMapLen = xMap->getLength();
+ for ( j = 0; j < nMapLen; ++j )
+ {
+ Reference< css::xml::dom::XNode > xAttr = xMap->item(j);
+ pNode = new ItemNode( xAttr );
+ OUString sSubId(weld::toId(pNode));
+ OUString sAttrName = m_xUIHelper->getNodeDisplayName( xAttr, bShowDetails );
+ m_xItemList->insert(xEntry.get(), -1, &sAttrName, &sSubId, nullptr, nullptr, false, m_xScratchIter.get());
+ m_xItemList->set_image(*m_xScratchIter, aExpImg);
+ }
+ }
+ }
+ if ( xChild->hasChildNodes() )
+ AddChildren(xEntry.get(), xChild);
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+ bool XFormsPage::DoToolBoxAction(std::string_view rToolBoxID)
+ {
+ bool bHandled = false;
+ bool bIsDocModified = false;
+ m_pNaviWin->DisableNotify( true );
+
+ if (rToolBoxID == "additem" || rToolBoxID == "addelement" || rToolBoxID == "addattribute")
+ {
+ bHandled = true;
+ Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY );
+ DBG_ASSERT( xModel.is(), "XFormsPage::DoToolBoxAction(): Action without model" );
+ if ( DGTSubmission == m_eGroup )
+ {
+ AddSubmissionDialog aDlg(m_pNaviWin->GetFrameWeld(), nullptr, m_xUIHelper);
+ if ( aDlg.run() == RET_OK && aDlg.GetNewSubmission().is() )
+ {
+ try
+ {
+ Reference< css::xforms::XSubmission > xNewSubmission = aDlg.GetNewSubmission();
+ Reference< XSet > xSubmissions = xModel->getSubmissions();
+ xSubmissions->insert( Any( xNewSubmission ) );
+ AddEntry(xNewSubmission, m_xScratchIter.get());
+ m_xItemList->select(*m_xScratchIter);
+ bIsDocModified = true;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolBoxAction()" );
+ }
+ }
+ }
+ else
+ {
+ DataItemType eType = DITElement;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xItemList->make_iterator());
+ bool bEntry = m_xItemList->get_selected(xEntry.get());
+
+ std::unique_ptr<ItemNode> pNode;
+ Reference< css::xml::dom::XNode > xParentNode;
+ Reference< XPropertySet > xNewBinding;
+ TranslateId pResId;
+ bool bIsElement = true;
+ if ( DGTInstance == m_eGroup )
+ {
+ if ( !m_sInstanceURL.isEmpty() )
+ {
+ LinkedInstanceWarningBox aMsgBox(m_pNaviWin->GetFrameWeld());
+ if (aMsgBox.run() != RET_OK)
+ return bHandled;
+ }
+
+ DBG_ASSERT( bEntry, "XFormsPage::DoToolBoxAction(): no entry" );
+ ItemNode* pParentNode = weld::fromId<ItemNode*>(m_xItemList->get_id(*xEntry));
+ DBG_ASSERT( pParentNode, "XFormsPage::DoToolBoxAction(): no parent node" );
+ xParentNode = pParentNode->m_xNode;
+ Reference< css::xml::dom::XNode > xNewNode;
+ if (rToolBoxID == "addelement")
+ {
+ try
+ {
+ pResId = RID_STR_DATANAV_ADD_ELEMENT;
+ xNewNode = m_xUIHelper->createElement( xParentNode, NEW_ELEMENT );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolBoxAction(): exception while create element" );
+ }
+ }
+ else
+ {
+ pResId = RID_STR_DATANAV_ADD_ATTRIBUTE;
+ bIsElement = false;
+ eType = DITAttribute;
+ try
+ {
+ xNewNode = m_xUIHelper->createAttribute( xParentNode, NEW_ATTRIBUTE );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolBoxAction(): exception while create attribute" );
+ }
+ }
+
+ try
+ {
+ xNewNode = xParentNode->appendChild( xNewNode );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolBoxAction(): exception while append child" );
+ }
+
+ try
+ {
+ Reference< css::xml::dom::XNode > xPNode;
+ if ( xNewNode.is() )
+ xPNode = xNewNode->getParentNode();
+ // attributes don't have parents in the DOM model
+ DBG_ASSERT( rToolBoxID == "addattribute"
+ || xPNode.is(), "XFormsPage::DoToolboxAction(): node not added" );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolboxAction()" );
+ }
+
+ try
+ {
+ m_xUIHelper->getBindingForNode( xNewNode, true );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolBoxAction(): exception while get binding for node" );
+ }
+ pNode.reset(new ItemNode( xNewNode ));
+ }
+ else
+ {
+ try
+ {
+ pResId = RID_STR_DATANAV_ADD_BINDING;
+ xNewBinding = xModel->createBinding();
+ Reference< XSet > xBindings = xModel->getBindings();
+ xBindings->insert( Any( xNewBinding ) );
+ pNode.reset(new ItemNode( xNewBinding ));
+ eType = DITBinding;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolBoxAction(): exception while adding binding" );
+ }
+ }
+
+ AddDataItemDialog aDlg(m_pNaviWin->GetFrameWeld(), pNode.get(), m_xUIHelper);
+ aDlg.set_title(SvxResId(pResId));
+ aDlg.InitText( eType );
+ short nReturn = aDlg.run();
+ if ( DGTInstance == m_eGroup )
+ {
+ if ( RET_OK == nReturn )
+ {
+ AddEntry( std::move(pNode), bIsElement, m_xScratchIter.get());
+ m_xItemList->scroll_to_row(*m_xScratchIter);
+ m_xItemList->select(*m_xScratchIter);
+ bIsDocModified = true;
+ }
+ else
+ {
+ try
+ {
+ Reference< css::xml::dom::XNode > xPNode;
+ Reference< css::xml::dom::XNode > xNode =
+ xParentNode->removeChild( pNode->m_xNode );
+ if ( xNode.is() )
+ xPNode = xNode->getParentNode();
+ DBG_ASSERT( !xPNode.is(), "XFormsPage::RemoveEntry(): node not removed" );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolboxAction()" );
+ }
+ }
+ }
+ else
+ {
+ if ( RET_OK == nReturn )
+ {
+ AddEntry(xNewBinding, m_xScratchIter.get());
+ m_xItemList->select(*m_xScratchIter);
+ bIsDocModified = true;
+ }
+ else
+ {
+ try
+ {
+ Reference< XSet > xBindings = xModel->getBindings();
+ xBindings->remove( Any( xNewBinding ) );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolboxAction()" );
+ }
+ }
+ }
+ }
+ }
+ else if (rToolBoxID == "edit")
+ {
+ bHandled = true;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xItemList->make_iterator());
+ bool bEntry = m_xItemList->get_selected(xEntry.get());
+ if ( bEntry )
+ {
+ if ( DGTSubmission == m_eGroup && m_xItemList->get_iter_depth(*xEntry) )
+ {
+ m_xItemList->iter_parent(*xEntry);
+ }
+ ItemNode* pNode = weld::fromId<ItemNode*>(m_xItemList->get_id(*xEntry));
+ if ( DGTInstance == m_eGroup || DGTBinding == m_eGroup )
+ {
+ if ( DGTInstance == m_eGroup && !m_sInstanceURL.isEmpty() )
+ {
+ LinkedInstanceWarningBox aMsgBox(m_pNaviWin->GetFrameWeld());
+ if (aMsgBox.run() != RET_OK)
+ return bHandled;
+ }
+
+ AddDataItemDialog aDlg(m_pNaviWin->GetFrameWeld(), pNode, m_xUIHelper);
+ DataItemType eType = DITElement;
+ TranslateId pResId = RID_STR_DATANAV_EDIT_ELEMENT;
+ if ( pNode && pNode->m_xNode.is() )
+ {
+ try
+ {
+ css::xml::dom::NodeType eChildType = pNode->m_xNode->getNodeType();
+ if ( eChildType == css::xml::dom::NodeType_ATTRIBUTE_NODE )
+ {
+ pResId = RID_STR_DATANAV_EDIT_ATTRIBUTE;
+ eType = DITAttribute;
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolboxAction()" );
+ }
+ }
+ else if ( DGTBinding == m_eGroup )
+ {
+ pResId = RID_STR_DATANAV_EDIT_BINDING;
+ eType = DITBinding;
+ }
+ aDlg.set_title(SvxResId(pResId));
+ aDlg.InitText( eType );
+ if (aDlg.run() == RET_OK)
+ {
+ // Set the new name
+ OUString sNewName;
+ if ( DGTInstance == m_eGroup )
+ {
+ try
+ {
+ sNewName = m_xUIHelper->getNodeDisplayName(
+ pNode->m_xNode, m_pNaviWin->IsShowDetails() );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolboxAction()" );
+ }
+ }
+ else if (pNode)
+ {
+ try
+ {
+ OUString sTemp;
+ pNode->m_xPropSet->getPropertyValue( PN_BINDING_ID ) >>= sTemp;
+ sNewName += sTemp + ": ";
+ pNode->m_xPropSet->getPropertyValue( PN_BINDING_EXPR ) >>= sTemp;
+ sNewName += sTemp;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::DoToolboxAction()" );
+ }
+ }
+
+ m_xItemList->set_text(*xEntry, sNewName);
+ bIsDocModified = true;
+ }
+ }
+ else
+ {
+ AddSubmissionDialog aDlg(m_pNaviWin->GetFrameWeld(), pNode, m_xUIHelper);
+ aDlg.set_title(SvxResId(RID_STR_DATANAV_EDIT_SUBMISSION));
+ if (aDlg.run() == RET_OK)
+ {
+ EditEntry( pNode->m_xPropSet );
+ bIsDocModified = true;
+ }
+ }
+ }
+ }
+ else if (rToolBoxID == "delete")
+ {
+ bHandled = true;
+ if ( DGTInstance == m_eGroup && !m_sInstanceURL.isEmpty() )
+ {
+ LinkedInstanceWarningBox aMsgBox(m_pNaviWin->GetFrameWeld());
+ if (aMsgBox.run() != RET_OK)
+ return bHandled;
+ }
+ bIsDocModified = RemoveEntry();
+ }
+ else
+ {
+ OSL_FAIL( "XFormsPage::DoToolboxAction: unknown ID!" );
+ }
+
+ m_pNaviWin->DisableNotify( false );
+ EnableMenuItems( nullptr );
+ if ( bIsDocModified )
+ svxform::DataNavigatorWindow::SetDocModified();
+ return bHandled;
+ }
+
+ void XFormsPage::AddEntry(std::unique_ptr<ItemNode> _pNewNode, bool _bIsElement, weld::TreeIter* pRet)
+ {
+ if (!pRet)
+ pRet = m_xScratchIter.get();
+
+ std::unique_ptr<weld::TreeIter> xParent(m_xItemList->make_iterator());
+ if (!m_xItemList->get_selected(xParent.get()))
+ xParent.reset();
+ OUString aImage(_bIsElement ? OUString(RID_SVXBMP_ELEMENT) : OUString(RID_SVXBMP_ATTRIBUTE));
+ OUString sName;
+ try
+ {
+ sName = m_xUIHelper->getNodeDisplayName(
+ _pNewNode->m_xNode, m_pNaviWin->IsShowDetails() );
+ }
+ catch ( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ OUString sId(weld::toId(_pNewNode.release()));
+ m_xItemList->insert(xParent.get(), -1, &sName, &sId, nullptr, nullptr, false, pRet);
+ m_xItemList->set_image(*pRet, aImage);
+ if (xParent && !m_xItemList->get_row_expanded(*xParent) && m_xItemList->iter_has_child(*xParent))
+ m_xItemList->expand_row(*xParent);
+ }
+
+ void XFormsPage::AddEntry(const Reference< XPropertySet >& _rEntry, weld::TreeIter* pRet)
+ {
+ if (!pRet)
+ pRet = m_xScratchIter.get();
+
+ OUString aImage(RID_SVXBMP_ELEMENT);
+
+ ItemNode* pNode = new ItemNode( _rEntry );
+ OUString sTemp;
+
+ if ( DGTSubmission == m_eGroup )
+ {
+ try
+ {
+ // ID
+ _rEntry->getPropertyValue( PN_SUBMISSION_ID ) >>= sTemp;
+ OUString sId(weld::toId(pNode));
+ m_xItemList->insert(nullptr, -1, &sTemp, &sId, nullptr, nullptr, false, pRet);
+ m_xItemList->set_image(*pRet, aImage);
+ std::unique_ptr<weld::TreeIter> xRes(m_xItemList->make_iterator());
+ // Action
+ _rEntry->getPropertyValue( PN_SUBMISSION_ACTION ) >>= sTemp;
+ OUString sEntry = SvxResId( RID_STR_DATANAV_SUBM_ACTION ) + sTemp;
+ m_xItemList->insert(pRet, -1, &sEntry, nullptr, nullptr, nullptr, false, xRes.get());
+ m_xItemList->set_image(*xRes, aImage);
+ // Method
+ _rEntry->getPropertyValue( PN_SUBMISSION_METHOD ) >>= sTemp;
+ sEntry = SvxResId( RID_STR_DATANAV_SUBM_METHOD ) +
+ m_aMethodString.toUI( sTemp );
+ m_xItemList->insert(pRet, -1, &sEntry, nullptr, nullptr, nullptr, false, xRes.get());
+ m_xItemList->set_image(*xRes, aImage);
+ // Ref
+ _rEntry->getPropertyValue( PN_SUBMISSION_REF ) >>= sTemp;
+ sEntry = SvxResId( RID_STR_DATANAV_SUBM_REF ) + sTemp;
+ m_xItemList->insert(pRet, -1, &sEntry, nullptr, nullptr, nullptr, false, xRes.get());
+ m_xItemList->set_image(*xRes, aImage);
+ // Bind
+ _rEntry->getPropertyValue( PN_SUBMISSION_BIND ) >>= sTemp;
+ sEntry = SvxResId( RID_STR_DATANAV_SUBM_BIND ) + sTemp;
+ m_xItemList->insert(pRet, -1, &sEntry, nullptr, nullptr, nullptr, false, xRes.get());
+ m_xItemList->set_image(*xRes, aImage);
+ // Replace
+ _rEntry->getPropertyValue( PN_SUBMISSION_REPLACE ) >>= sTemp;
+ sEntry = SvxResId( RID_STR_DATANAV_SUBM_REPLACE ) +
+ m_aReplaceString.toUI( sTemp );
+ m_xItemList->insert(pRet, -1, &sEntry, nullptr, nullptr, nullptr, false, xRes.get());
+ m_xItemList->set_image(*xRes, aImage);
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::AddEntry(Ref)" );
+ }
+ }
+ else // then Binding Page
+ {
+ try
+ {
+ OUString sName;
+ _rEntry->getPropertyValue( PN_BINDING_ID ) >>= sTemp;
+ sName += sTemp + ": ";
+ _rEntry->getPropertyValue( PN_BINDING_EXPR ) >>= sTemp;
+ sName += sTemp;
+
+ OUString sId(weld::toId(pNode));
+ m_xItemList->insert(nullptr, -1, &sName, &sId, nullptr, nullptr, false, pRet);
+ m_xItemList->set_image(*pRet, aImage);
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::AddEntry(Ref)" );
+ }
+ }
+ }
+
+ void XFormsPage::EditEntry( const Reference< XPropertySet >& _rEntry )
+ {
+ if ( DGTSubmission != m_eGroup )
+ return;
+
+ try
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(m_xItemList->make_iterator());
+ if (!m_xItemList->get_selected(xEntry.get()))
+ {
+ SAL_WARN( "svx.form", "corrupt tree" );
+ return;
+ }
+
+ // #i36262# may be called for submission entry *or* for
+ // submission children. If we don't have any children, we
+ // assume the latter case and use the parent
+ if (!m_xItemList->iter_has_child(*xEntry))
+ m_xItemList->iter_parent(*xEntry);
+
+ OUString sTemp;
+ _rEntry->getPropertyValue( PN_SUBMISSION_ID ) >>= sTemp;
+ m_xItemList->set_text(*xEntry, sTemp);
+
+ _rEntry->getPropertyValue( PN_SUBMISSION_BIND ) >>= sTemp;
+ OUString sEntry = SvxResId( RID_STR_DATANAV_SUBM_BIND ) + sTemp;
+ if (!m_xItemList->iter_children(*xEntry))
+ {
+ SAL_WARN( "svx.form", "corrupt tree" );
+ return;
+ }
+ m_xItemList->set_text(*xEntry, sEntry);
+ _rEntry->getPropertyValue( PN_SUBMISSION_REF ) >>= sTemp;
+ sEntry = SvxResId( RID_STR_DATANAV_SUBM_REF ) + sTemp;
+ if (!m_xItemList->iter_next_sibling(*xEntry))
+ {
+ SAL_WARN( "svx.form", "corrupt tree" );
+ return;
+ }
+ m_xItemList->set_text(*xEntry, sEntry);
+ _rEntry->getPropertyValue( PN_SUBMISSION_ACTION ) >>= sTemp;
+ sEntry = SvxResId( RID_STR_DATANAV_SUBM_ACTION ) + sTemp;
+ if (!m_xItemList->iter_next_sibling(*xEntry))
+ {
+ SAL_WARN( "svx.form", "corrupt tree" );
+ return;
+ }
+ _rEntry->getPropertyValue( PN_SUBMISSION_METHOD ) >>= sTemp;
+ sEntry = SvxResId( RID_STR_DATANAV_SUBM_METHOD ) +
+ m_aMethodString.toUI( sTemp );
+ if (!m_xItemList->iter_next_sibling(*xEntry))
+ {
+ SAL_WARN( "svx.form", "corrupt tree" );
+ return;
+ }
+ m_xItemList->set_text(*xEntry, sEntry);
+ _rEntry->getPropertyValue( PN_SUBMISSION_REPLACE ) >>= sTemp;
+ sEntry = SvxResId( RID_STR_DATANAV_SUBM_REPLACE ) +
+ m_aReplaceString.toUI( sTemp );
+ if (!m_xItemList->iter_next_sibling(*xEntry))
+ {
+ SAL_WARN( "svx.form", "corrupt tree" );
+ return;
+ }
+ m_xItemList->set_text(*xEntry, sEntry);
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::EditEntry()" );
+ }
+ }
+
+ bool XFormsPage::RemoveEntry()
+ {
+ bool bRet = false;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xItemList->make_iterator());
+ bool bEntry = m_xItemList->get_selected(xEntry.get());
+ if ( bEntry &&
+ ( DGTInstance != m_eGroup || m_xItemList->get_iter_depth(*xEntry) ) )
+ {
+ Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY );
+ DBG_ASSERT( xModel.is(), "XFormsPage::RemoveEntry(): no model" );
+ ItemNode* pNode = weld::fromId<ItemNode*>(m_xItemList->get_id(*xEntry));
+ DBG_ASSERT( pNode, "XFormsPage::RemoveEntry(): no node" );
+
+ if ( DGTInstance == m_eGroup )
+ {
+ try
+ {
+ DBG_ASSERT( pNode->m_xNode.is(), "XFormsPage::RemoveEntry(): no XNode" );
+ css::xml::dom::NodeType eChildType = pNode->m_xNode->getNodeType();
+ bool bIsElement = ( eChildType == css::xml::dom::NodeType_ELEMENT_NODE );
+ TranslateId pResId = bIsElement ? RID_STR_QRY_REMOVE_ELEMENT : RID_STR_QRY_REMOVE_ATTRIBUTE;
+ OUString sVar = bIsElement ? OUString(ELEMENTNAME) : OUString(ATTRIBUTENAME);
+ std::unique_ptr<weld::MessageDialog> xQBox(Application::CreateMessageDialog(m_pNaviWin->GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ SvxResId(pResId)));
+ OUString sMessText = xQBox->get_primary_text();
+ sMessText = sMessText.replaceFirst(
+ sVar, m_xUIHelper->getNodeDisplayName( pNode->m_xNode, false ) );
+ xQBox->set_primary_text(sMessText);
+ if (xQBox->run() == RET_YES)
+ {
+ std::unique_ptr<weld::TreeIter> xParent(m_xItemList->make_iterator(xEntry.get()));
+ bool bParent = m_xItemList->iter_parent(*xParent); (void)bParent;
+ assert(bParent && "XFormsPage::RemoveEntry(): no parent entry");
+ ItemNode* pParentNode = weld::fromId<ItemNode*>(m_xItemList->get_id(*xParent));
+ DBG_ASSERT( pParentNode && pParentNode->m_xNode.is(), "XFormsPage::RemoveEntry(): no parent XNode" );
+
+ Reference< css::xml::dom::XNode > xPNode;
+ Reference< css::xml::dom::XNode > xNode =
+ pParentNode->m_xNode->removeChild( pNode->m_xNode );
+ if ( xNode.is() )
+ xPNode = xNode->getParentNode();
+ DBG_ASSERT( !xPNode.is(), "XFormsPage::RemoveEntry(): node not removed" );
+ bRet = true;
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::RemoveEntry()" );
+ }
+ }
+ else
+ {
+ DBG_ASSERT( pNode->m_xPropSet.is(), "XFormsPage::RemoveEntry(): no propset" );
+ bool bSubmission = ( DGTSubmission == m_eGroup );
+ TranslateId pResId = bSubmission ? RID_STR_QRY_REMOVE_SUBMISSION : RID_STR_QRY_REMOVE_BINDING;
+ OUString sProperty = bSubmission ? OUString(PN_SUBMISSION_ID) : OUString(PN_BINDING_ID);
+ OUString sSearch = bSubmission ? OUString(SUBMISSIONNAME) : OUString(BINDINGNAME);
+ OUString sName;
+ try
+ {
+ pNode->m_xPropSet->getPropertyValue( sProperty ) >>= sName;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::RemoveEntry()" );
+ }
+ std::unique_ptr<weld::MessageDialog> xQBox(Application::CreateMessageDialog(m_pNaviWin->GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ SvxResId(pResId)));
+ OUString sMessText = xQBox->get_primary_text();
+ sMessText = sMessText.replaceFirst( sSearch, sName);
+ xQBox->set_primary_text(sMessText);
+ if (xQBox->run() == RET_YES)
+ {
+ try
+ {
+ if ( bSubmission )
+ xModel->getSubmissions()->remove( Any( pNode->m_xPropSet ) );
+ else // then Binding Page
+ xModel->getBindings()->remove( Any( pNode->m_xPropSet ) );
+ bRet = true;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::RemoveEntry()" );
+ }
+ }
+ }
+
+ if (bRet)
+ {
+ m_xItemList->remove(*xEntry);
+ delete pNode;
+ }
+ }
+
+ return bRet;
+ }
+
+ IMPL_LINK(XFormsPage, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+ {
+ bool bHandled = false;
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+ if (nCode == KEY_DELETE)
+ bHandled = DoMenuAction("delete");
+
+ return bHandled;
+ }
+
+ OUString XFormsPage::SetModel( const Reference< css::xforms::XModel >& _xModel, int _nPagePos )
+ {
+ DBG_ASSERT( _xModel.is(), "XFormsPage::SetModel(): invalid model" );
+
+ m_xUIHelper.set( _xModel, UNO_QUERY );
+ OUString sRet;
+ m_bHasModel = true;
+
+ switch ( m_eGroup )
+ {
+ case DGTInstance :
+ {
+ DBG_ASSERT( _nPagePos != -1, "XFormsPage::SetModel(): invalid page position" );
+ try
+ {
+ Reference< XContainer > xContainer( _xModel->getInstances(), UNO_QUERY );
+ if ( xContainer.is() )
+ m_pNaviWin->AddContainerBroadcaster( xContainer );
+
+ Reference< XEnumerationAccess > xNumAccess = _xModel->getInstances();
+ if ( xNumAccess.is() )
+ {
+ Reference < XEnumeration > xNum = xNumAccess->createEnumeration();
+ if ( xNum.is() && xNum->hasMoreElements() )
+ {
+ int nIter = 0;
+ while ( xNum->hasMoreElements() )
+ {
+ if ( nIter == _nPagePos )
+ {
+ Sequence< PropertyValue > xPropSeq;
+ Any aAny = xNum->nextElement();
+ if ( aAny >>= xPropSeq )
+ sRet = LoadInstance(xPropSeq);
+ else
+ {
+ SAL_WARN( "svx.form", "XFormsPage::SetModel(): invalid instance" );
+ }
+ break;
+ }
+ else
+ {
+ xNum->nextElement();
+ ++nIter;
+ }
+ }
+ }
+ }
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::SetModel()" );
+ }
+ break;
+ }
+
+ case DGTSubmission :
+ {
+ DBG_ASSERT( _nPagePos == -1, "XFormsPage::SetModel(): invalid page position" );
+ try
+ {
+ Reference< XContainer > xContainer( _xModel->getSubmissions(), UNO_QUERY );
+ if ( xContainer.is() )
+ m_pNaviWin->AddContainerBroadcaster( xContainer );
+
+ Reference< XEnumerationAccess > xNumAccess = _xModel->getSubmissions();
+ if ( xNumAccess.is() )
+ {
+ Reference < XEnumeration > xNum = xNumAccess->createEnumeration();
+ if ( xNum.is() && xNum->hasMoreElements() )
+ {
+ while ( xNum->hasMoreElements() )
+ {
+ Reference< XPropertySet > xPropSet;
+ Any aAny = xNum->nextElement();
+ if ( aAny >>= xPropSet )
+ AddEntry( xPropSet );
+ }
+ }
+ }
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::SetModel()" );
+ }
+ break;
+ }
+
+ case DGTBinding :
+ {
+ DBG_ASSERT( _nPagePos == -1, "XFormsPage::SetModel(): invalid page position" );
+ try
+ {
+ Reference< XContainer > xContainer( _xModel->getBindings(), UNO_QUERY );
+ if ( xContainer.is() )
+ m_pNaviWin->AddContainerBroadcaster( xContainer );
+
+ Reference< XEnumerationAccess > xNumAccess = _xModel->getBindings();
+ if ( xNumAccess.is() )
+ {
+ Reference < XEnumeration > xNum = xNumAccess->createEnumeration();
+ if ( xNum.is() && xNum->hasMoreElements() )
+ {
+ OUString aImage(RID_SVXBMP_ELEMENT);
+ std::unique_ptr<weld::TreeIter> xRes(m_xItemList->make_iterator());
+ while ( xNum->hasMoreElements() )
+ {
+ Reference< XPropertySet > xPropSet;
+ Any aAny = xNum->nextElement();
+ if ( aAny >>= xPropSet )
+ {
+ OUString sEntry;
+ OUString sTemp;
+ xPropSet->getPropertyValue( PN_BINDING_ID ) >>= sTemp;
+ sEntry += sTemp + ": ";
+ xPropSet->getPropertyValue( PN_BINDING_EXPR ) >>= sTemp;
+ sEntry += sTemp;
+
+ ItemNode* pNode = new ItemNode( xPropSet );
+
+ OUString sId(weld::toId(pNode));
+ m_xItemList->insert(nullptr, -1, &sEntry, &sId, nullptr, nullptr, false, xRes.get());
+ m_xItemList->set_image(*xRes, aImage);
+ }
+ }
+ }
+ }
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::SetModel()" );
+ }
+ break;
+ }
+ default:
+ OSL_FAIL( "XFormsPage::SetModel: unknown group!" );
+ break;
+ }
+
+ EnableMenuItems( nullptr );
+
+ return sRet;
+ }
+
+ void XFormsPage::ClearModel()
+ {
+ m_bHasModel = false;
+ DeleteAndClearTree();
+ }
+
+ OUString XFormsPage::LoadInstance(const Sequence< PropertyValue >& _xPropSeq)
+ {
+ OUString sRet;
+ OUString sTemp;
+ OUString sInstModel = PN_INSTANCE_MODEL;
+ OUString sInstName = PN_INSTANCE_ID;
+ OUString sInstURL = PN_INSTANCE_URL;
+ for ( const PropertyValue& rProp : _xPropSeq )
+ {
+ if ( sInstModel == rProp.Name )
+ {
+ Reference< css::xml::dom::XNode > xRoot;
+ if ( rProp.Value >>= xRoot )
+ {
+ try
+ {
+ Reference< XEventTarget > xTarget( xRoot, UNO_QUERY );
+ if ( xTarget.is() )
+ m_pNaviWin->AddEventBroadcaster( xTarget );
+
+ OUString sNodeName =
+ m_xUIHelper->getNodeDisplayName( xRoot, m_pNaviWin->IsShowDetails() );
+ if ( sNodeName.isEmpty() )
+ sNodeName = xRoot->getNodeName();
+ if ( xRoot->hasChildNodes() )
+ AddChildren(nullptr, xRoot);
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::LoadInstance()" );
+ }
+ }
+ }
+ else if ( sInstName == rProp.Name && ( rProp.Value >>= sTemp ) )
+ m_sInstanceName = sRet = sTemp;
+ else if ( sInstURL == rProp.Name && ( rProp.Value >>= sTemp ) )
+ m_sInstanceURL = sTemp;
+ }
+
+ return sRet;
+ }
+
+ bool XFormsPage::DoMenuAction(std::string_view rMenuID)
+ {
+ return DoToolBoxAction(rMenuID);
+ }
+
+ void XFormsPage::EnableMenuItems(weld::Menu* pMenu)
+ {
+ bool bEnableAdd = false;
+ bool bEnableEdit = false;
+ bool bEnableRemove = false;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xItemList->make_iterator());
+ bool bEntry = m_xItemList->get_selected(xEntry.get());
+ if (bEntry)
+ {
+ bEnableAdd = true;
+ bool bSubmitChild = false;
+ if (DGTSubmission == m_eGroup && m_xItemList->get_iter_depth(*xEntry))
+ {
+ m_xItemList->iter_parent(*xEntry);
+ bSubmitChild = true;
+ }
+ ItemNode* pNode = weld::fromId<ItemNode*>(m_xItemList->get_id(*xEntry));
+ if ( pNode && ( pNode->m_xNode.is() || pNode->m_xPropSet.is() ) )
+ {
+ bEnableEdit = true;
+ bEnableRemove = !bSubmitChild;
+ if ( DGTInstance == m_eGroup && !m_xItemList->get_iter_depth(*xEntry) )
+ bEnableRemove = false;
+ if ( pNode->m_xNode.is() )
+ {
+ try
+ {
+ css::xml::dom::NodeType eChildType = pNode->m_xNode->getNodeType();
+ if ( eChildType != css::xml::dom::NodeType_ELEMENT_NODE
+ && eChildType != css::xml::dom::NodeType_DOCUMENT_NODE )
+ {
+ bEnableAdd = false;
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::EnableMenuItems()" );
+ }
+ }
+ }
+ }
+ else if ( m_eGroup != DGTInstance )
+ bEnableAdd = true;
+
+ m_xToolBox->set_item_sensitive("additem", bEnableAdd);
+ m_xToolBox->set_item_sensitive("addelement", bEnableAdd);
+ m_xToolBox->set_item_sensitive("addattribute", bEnableAdd);
+ m_xToolBox->set_item_sensitive("edit", bEnableEdit);
+ m_xToolBox->set_item_sensitive("delete", bEnableRemove);
+
+ if (pMenu)
+ {
+ pMenu->set_sensitive("additem", bEnableAdd);
+ pMenu->set_sensitive("addelement", bEnableAdd);
+ pMenu->set_sensitive("addattribute", bEnableAdd);
+ pMenu->set_sensitive("edit", bEnableEdit);
+ pMenu->set_sensitive("delete", bEnableRemove);
+ }
+ if ( DGTInstance != m_eGroup )
+ return;
+
+ TranslateId pResId1 = RID_STR_DATANAV_EDIT_ELEMENT;
+ TranslateId pResId2 = RID_STR_DATANAV_REMOVE_ELEMENT;
+ if (bEntry)
+ {
+ ItemNode* pNode = weld::fromId<ItemNode*>(m_xItemList->get_id(*xEntry));
+ if ( pNode && pNode->m_xNode.is() )
+ {
+ try
+ {
+ css::xml::dom::NodeType eChildType = pNode->m_xNode->getNodeType();
+ if ( eChildType == css::xml::dom::NodeType_ATTRIBUTE_NODE )
+ {
+ pResId1 = RID_STR_DATANAV_EDIT_ATTRIBUTE;
+ pResId2 = RID_STR_DATANAV_REMOVE_ATTRIBUTE;
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "XFormsPage::EnableMenuItems()" );
+ }
+ }
+ }
+ m_xToolBox->set_item_label("edit", SvxResId(pResId1));
+ m_xToolBox->set_item_label("delete", SvxResId(pResId2));
+ if (pMenu)
+ {
+ pMenu->set_label("edit", SvxResId( pResId1 ) );
+ pMenu->set_label("delete", SvxResId( pResId2 ) );
+ }
+ }
+
+ DataNavigatorWindow::DataNavigatorWindow(vcl::Window* pParent, weld::Builder& rBuilder, SfxBindings const * pBindings)
+ : m_xParent(pParent)
+ , m_xModelsBox(rBuilder.weld_combo_box("modelslist"))
+ , m_xModelBtn(rBuilder.weld_menu_button("modelsbutton"))
+ , m_xTabCtrl(rBuilder.weld_notebook("tabcontrol"))
+ , m_xInstanceBtn(rBuilder.weld_menu_button("instances"))
+ , m_nLastSelectedPos(-1)
+ , m_bShowDetails(false)
+ , m_bIsNotifyDisabled(false)
+ , m_aUpdateTimer("svx DataNavigatorWindow m_aUpdateTimer")
+ , m_xDataListener(new DataListener(this))
+ {
+ // handler
+ m_xModelsBox->connect_changed( LINK( this, DataNavigatorWindow, ModelSelectListBoxHdl ) );
+ Link<const OString&, void> aLink1 = LINK( this, DataNavigatorWindow, MenuSelectHdl );
+ m_xModelBtn->connect_selected(aLink1);
+ m_xInstanceBtn->connect_selected(aLink1);
+ Link<weld::Toggleable&,void> aLink2 = LINK( this, DataNavigatorWindow, MenuActivateHdl );
+ m_xModelBtn->connect_toggled( aLink2 );
+ m_xInstanceBtn->connect_toggled( aLink2 );
+ m_xTabCtrl->connect_enter_page( LINK( this, DataNavigatorWindow, ActivatePageHdl ) );
+ m_aUpdateTimer.SetTimeout( 2000 );
+ m_aUpdateTimer.SetInvokeHandler( LINK( this, DataNavigatorWindow, UpdateHdl ) );
+
+ // init tabcontrol
+ OString sPageId("instance");
+ SvtViewOptions aViewOpt( EViewType::TabDialog, CFGNAME_DATANAVIGATOR );
+ if ( aViewOpt.Exists() )
+ {
+ OString sNewPageId = aViewOpt.GetPageID();
+ if (m_xTabCtrl->get_page_index(sNewPageId) != -1)
+ sPageId = sNewPageId;
+ aViewOpt.GetUserItem(CFGNAME_SHOWDETAILS) >>= m_bShowDetails;
+ }
+
+ m_xInstanceBtn->set_item_active("instancesdetails", m_bShowDetails);
+
+ m_xTabCtrl->set_current_page(sPageId);
+ ActivatePageHdl(sPageId);
+
+ // get our frame
+ DBG_ASSERT( pBindings != nullptr,
+ "DataNavigatorWindow::LoadModels(): no SfxBindings; can't get frame" );
+ m_xFrame = pBindings->GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface();
+ DBG_ASSERT( m_xFrame.is(), "DataNavigatorWindow::LoadModels(): no frame" );
+ // add frameaction listener
+ Reference< XFrameActionListener > xListener = m_xDataListener;
+ m_xFrame->addFrameActionListener( xListener );
+
+ // load xforms models of the current document
+ LoadModels();
+ }
+
+ DataNavigatorWindow::~DataNavigatorWindow()
+ {
+ Reference< XFrameActionListener > xListener = m_xDataListener;
+ m_xFrame->removeFrameActionListener( xListener );
+
+ SvtViewOptions aViewOpt( EViewType::TabDialog, CFGNAME_DATANAVIGATOR );
+ aViewOpt.SetPageID(m_xTabCtrl->get_current_page_ident());
+ aViewOpt.SetUserItem(CFGNAME_SHOWDETAILS, Any(m_bShowDetails));
+
+ m_xInstPage.reset();
+ m_xSubmissionPage.reset();
+ m_xBindingPage.reset();
+
+ sal_Int32 i, nCount = m_aPageList.size();
+ for ( i = 0; i < nCount; ++i )
+ m_aPageList[i].reset();
+ m_aPageList.clear();
+
+ RemoveBroadcaster();
+ m_xDataListener.clear();
+ }
+
+ IMPL_LINK( DataNavigatorWindow, ModelSelectListBoxHdl, weld::ComboBox&, rBox, void )
+ {
+ ModelSelectHdl(&rBox);
+ }
+
+ void DataNavigatorWindow::ModelSelectHdl(const weld::ComboBox* pBox)
+ {
+ sal_Int32 nPos = m_xModelsBox->get_active();
+ // pBox == NULL, if you want to force a new fill.
+ if ( nPos != m_nLastSelectedPos || !pBox )
+ {
+ m_nLastSelectedPos = nPos;
+ ClearAllPageModels( pBox != nullptr );
+ InitPages();
+ SetPageModel(GetCurrentPage());
+ }
+ }
+
+ IMPL_LINK(DataNavigatorWindow, MenuSelectHdl, const OString&, rIdent, void)
+ {
+ bool bIsDocModified = false;
+ Reference< css::xforms::XFormsUIHelper1 > xUIHelper;
+ sal_Int32 nSelectedPos = m_xModelsBox->get_active();
+ OUString sSelectedModel(m_xModelsBox->get_text(nSelectedPos));
+ Reference< css::xforms::XModel > xModel;
+ try
+ {
+ Any aAny = m_xDataContainer->getByName( sSelectedModel );
+ if ( aAny >>= xModel )
+ xUIHelper.set( xModel, UNO_QUERY );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::MenuSelectHdl()" );
+ }
+ DBG_ASSERT( xUIHelper.is(), "DataNavigatorWindow::MenuSelectHdl(): no UIHelper" );
+
+ m_bIsNotifyDisabled = true;
+
+ if (rIdent == "modelsadd")
+ {
+ AddModelDialog aDlg(GetFrameWeld(), false);
+ bool bShowDialog = true;
+ while ( bShowDialog )
+ {
+ bShowDialog = false;
+ if (aDlg.run() == RET_OK)
+ {
+ OUString sNewName = aDlg.GetName();
+ bool bDocumentData = aDlg.GetModifyDoc();
+
+ if (m_xModelsBox->find_text(sNewName) != -1)
+ {
+ // error: model name already exists
+ std::unique_ptr<weld::MessageDialog> xErrBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SvxResId(RID_STR_DOUBLE_MODELNAME)));
+ xErrBox->set_primary_text(xErrBox->get_primary_text().replaceFirst(MSG_VARIABLE, sNewName));
+ xErrBox->run();
+ bShowDialog = true;
+ }
+ else
+ {
+ try
+ {
+ // add new model to frame model
+ Reference< css::xforms::XModel > xNewModel(
+ xUIHelper->newModel( m_xFrameModel, sNewName ), UNO_SET_THROW );
+
+ Reference< XPropertySet > xModelProps( xNewModel, UNO_QUERY_THROW );
+ xModelProps->setPropertyValue("ExternalData", Any( !bDocumentData ) );
+
+ m_xModelsBox->append_text(sNewName);
+ m_xModelsBox->set_active(m_xModelsBox->get_count() - 1);
+ ModelSelectHdl(m_xModelsBox.get());
+ bIsDocModified = true;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::MenuSelectHdl()" );
+ }
+ }
+ }
+ }
+ }
+ else if (rIdent == "modelsedit")
+ {
+ AddModelDialog aDlg(GetFrameWeld(), true);
+ aDlg.SetName( sSelectedModel );
+
+ bool bDocumentData( false );
+ try
+ {
+ Reference< css::xforms::XFormsSupplier > xFormsSupp( m_xFrameModel, UNO_QUERY_THROW );
+ Reference< XNameContainer > xXForms( xFormsSupp->getXForms(), UNO_SET_THROW );
+ Reference< XPropertySet > xModelProps( xXForms->getByName( sSelectedModel ), UNO_QUERY_THROW );
+ bool bExternalData = false;
+ OSL_VERIFY( xModelProps->getPropertyValue( "ExternalData" ) >>= bExternalData );
+ bDocumentData = !bExternalData;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ aDlg.SetModifyDoc( bDocumentData );
+
+ if (aDlg.run() == RET_OK)
+ {
+ if ( aDlg.GetModifyDoc() != bDocumentData )
+ {
+ bDocumentData = aDlg.GetModifyDoc();
+ try
+ {
+ Reference< css::xforms::XFormsSupplier > xFormsSupp( m_xFrameModel, UNO_QUERY_THROW );
+ Reference< XNameContainer > xXForms( xFormsSupp->getXForms(), UNO_SET_THROW );
+ Reference< XPropertySet > xModelProps( xXForms->getByName( sSelectedModel ), UNO_QUERY_THROW );
+ xModelProps->setPropertyValue( "ExternalData", Any( !bDocumentData ) );
+ bIsDocModified = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+ OUString sNewName = aDlg.GetName();
+ if ( !sNewName.isEmpty() && ( sNewName != sSelectedModel ) )
+ {
+ try
+ {
+ xUIHelper->renameModel( m_xFrameModel, sSelectedModel, sNewName );
+
+ m_xModelsBox->remove(nSelectedPos);
+ m_xModelsBox->append_text(sNewName);
+ m_xModelsBox->set_active(m_xModelsBox->get_count() - 1);
+ bIsDocModified = true;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::MenuSelectHdl()" );
+ }
+ }
+ }
+ }
+ else if (rIdent == "modelsremove")
+ {
+ std::unique_ptr<weld::MessageDialog> xQBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ SvxResId( RID_STR_QRY_REMOVE_MODEL)));
+ OUString sText = xQBox->get_primary_text();
+ sText = sText.replaceFirst( MODELNAME, sSelectedModel );
+ xQBox->set_primary_text(sText);
+ if (xQBox->run() == RET_YES)
+ {
+ try
+ {
+ xUIHelper->removeModel( m_xFrameModel, sSelectedModel );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::MenuSelectHdl()" );
+ }
+ m_xModelsBox->remove(nSelectedPos);
+ if (m_xModelsBox->get_count() <= nSelectedPos)
+ nSelectedPos = m_xModelsBox->get_count() - 1;
+ m_xModelsBox->set_active(nSelectedPos);
+ ModelSelectHdl(m_xModelsBox.get());
+ bIsDocModified = true;
+ }
+ }
+ else if (rIdent == "instancesadd")
+ {
+ AddInstanceDialog aDlg(GetFrameWeld(), false);
+ if (aDlg.run() == RET_OK)
+ {
+ OString sPageId = GetNewPageId(); // ModelSelectHdl will cause a page of this id to be created
+
+ OUString sName = aDlg.GetName();
+ if (sName.isEmpty())
+ {
+ SAL_WARN( "svx.form", "DataNavigatorWindow::CreateInstancePage(): instance without name" );
+ sName = "untitled";
+ }
+
+ OUString sURL = aDlg.GetURL();
+ bool bLinkOnce = aDlg.IsLinkInstance();
+ try
+ {
+ xUIHelper->newInstance( sName, sURL, !bLinkOnce );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::MenuSelectHdl()" );
+ }
+ ModelSelectHdl( nullptr );
+
+ XFormsPage* pPage = GetPage(sPageId);
+ pPage->SetInstanceName(sName);
+ pPage->SetInstanceURL(sURL);
+ pPage->SetLinkOnce(bLinkOnce);
+ ActivatePageHdl(sPageId);
+
+ bIsDocModified = true;
+ }
+ }
+ else if (rIdent == "instancesedit")
+ {
+ OString sIdent = GetCurrentPage();
+ XFormsPage* pPage = GetPage(sIdent);
+ if ( pPage )
+ {
+ AddInstanceDialog aDlg(GetFrameWeld(), true);
+ aDlg.SetName( pPage->GetInstanceName() );
+ aDlg.SetURL( pPage->GetInstanceURL() );
+ aDlg.SetLinkInstance( pPage->GetLinkOnce() );
+ OUString sOldName = aDlg.GetName();
+ if (aDlg.run() == RET_OK)
+ {
+ OUString sNewName = aDlg.GetName();
+ OUString sURL = aDlg.GetURL();
+ bool bLinkOnce = aDlg.IsLinkInstance();
+ try
+ {
+ xUIHelper->renameInstance( sOldName,
+ sNewName,
+ sURL,
+ !bLinkOnce );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::MenuSelectHdl()" );
+ }
+ pPage->SetInstanceName(sNewName);
+ pPage->SetInstanceURL(sURL);
+ pPage->SetLinkOnce(bLinkOnce);
+ m_xTabCtrl->set_tab_label_text(sIdent, sNewName);
+ bIsDocModified = true;
+ }
+ }
+ }
+ else if (rIdent == "instancesremove")
+ {
+ OString sIdent = GetCurrentPage();
+ XFormsPage* pPage = GetPage(sIdent);
+ if (pPage)
+ {
+ OUString sInstName = pPage->GetInstanceName();
+ std::unique_ptr<weld::MessageDialog> xQBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ SvxResId(RID_STR_QRY_REMOVE_INSTANCE)));
+ OUString sMessText = xQBox->get_primary_text();
+ sMessText = sMessText.replaceFirst( INSTANCENAME, sInstName );
+ xQBox->set_primary_text(sMessText);
+ if (xQBox->run() == RET_YES)
+ {
+ bool bDoRemove = false;
+ if (IsAdditionalPage(sIdent))
+ {
+ auto aPageListEnd = m_aPageList.end();
+ auto aFoundPage = std::find_if(m_aPageList.begin(), aPageListEnd,
+ [pPage](const auto&elem) { return elem.get() == pPage; });
+ if ( aFoundPage != aPageListEnd )
+ {
+ m_aPageList.erase( aFoundPage );
+ bDoRemove = true;
+ }
+ }
+ else
+ {
+ m_xInstPage.reset();
+ bDoRemove = true;
+ }
+
+ if ( bDoRemove )
+ {
+ try
+ {
+ xUIHelper->removeInstance( sInstName );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::MenuSelectHdl()" );
+ }
+ m_xTabCtrl->remove_page(sIdent);
+ m_xTabCtrl->set_current_page("instance");
+ ModelSelectHdl( nullptr );
+ bIsDocModified = true;
+ }
+ }
+ }
+ }
+ else if (rIdent == "instancesdetails")
+ {
+ m_bShowDetails = !m_bShowDetails;
+ m_xInstanceBtn->set_item_active("instancesdetails", m_bShowDetails);
+ ModelSelectHdl(m_xModelsBox.get());
+ }
+ else
+ {
+ SAL_WARN( "svx.form", "DataNavigatorWindow::MenuSelectHdl(): wrong menu item" );
+ }
+
+ m_bIsNotifyDisabled = false;
+
+ if ( bIsDocModified )
+ SetDocModified();
+ }
+
+ bool DataNavigatorWindow::IsAdditionalPage(std::string_view rIdent)
+ {
+ return o3tl::starts_with(rIdent, "additional");
+ }
+
+ IMPL_LINK( DataNavigatorWindow, MenuActivateHdl, weld::Toggleable&, rBtn, void )
+ {
+ if (m_xInstanceBtn.get() == &rBtn)
+ {
+ OString sIdent(m_xTabCtrl->get_current_page_ident());
+ bool bIsInstPage = (IsAdditionalPage(sIdent) || sIdent == "instance");
+ m_xInstanceBtn->set_item_sensitive( "instancesedit", bIsInstPage );
+ m_xInstanceBtn->set_item_sensitive( "instancesremove",
+ bIsInstPage && m_xTabCtrl->get_n_pages() > MIN_PAGE_COUNT );
+ m_xInstanceBtn->set_item_sensitive( "instancesdetails", bIsInstPage );
+ }
+ else if (m_xModelBtn.get() == &rBtn)
+ {
+ // we need at least one model!
+ m_xModelBtn->set_item_sensitive("modelsremove", m_xModelsBox->get_count() > 1 );
+ }
+ else
+ {
+ SAL_WARN( "svx.form", "DataNavigatorWindow::MenuActivateHdl(): wrong button" );
+ }
+ }
+
+ IMPL_LINK(DataNavigatorWindow, ActivatePageHdl, const OString&, rIdent, void)
+ {
+ XFormsPage* pPage = GetPage(rIdent);
+ if (!pPage)
+ return;
+ if (m_xDataContainer.is() && !pPage->HasModel())
+ SetPageModel(rIdent);
+ }
+
+ IMPL_LINK_NOARG(DataNavigatorWindow, UpdateHdl, Timer *, void)
+ {
+ ModelSelectHdl( nullptr );
+ }
+
+ XFormsPage* DataNavigatorWindow::GetPage(const OString& rCurId)
+ {
+ XFormsPage* pPage = nullptr;
+ if (rCurId == "submissions")
+ {
+ if (!m_xSubmissionPage)
+ m_xSubmissionPage.reset(new XFormsPage(m_xTabCtrl->get_page(rCurId), this, DGTSubmission));
+ pPage = m_xSubmissionPage.get();
+ }
+ else if (rCurId == "bindings")
+ {
+ if (!m_xBindingPage)
+ m_xBindingPage.reset(new XFormsPage(m_xTabCtrl->get_page(rCurId), this, DGTBinding));
+ pPage = m_xBindingPage.get();
+ }
+ else if (rCurId == "instance")
+ {
+ if (!m_xInstPage)
+ m_xInstPage.reset(new XFormsPage(m_xTabCtrl->get_page(rCurId), this, DGTInstance));
+ pPage = m_xInstPage.get();
+ }
+ else
+ {
+ sal_uInt16 nPos = m_xTabCtrl->get_page_index(rCurId);
+ if (HasFirstInstancePage() && nPos > 0)
+ nPos--;
+ if (m_aPageList.size() > nPos)
+ pPage = m_aPageList[nPos].get();
+ else
+ {
+ m_aPageList.emplace_back(std::make_unique<XFormsPage>(m_xTabCtrl->get_page(rCurId), this, DGTInstance));
+ pPage = m_aPageList.back().get();
+ }
+ }
+ return pPage;
+ }
+
+ OString DataNavigatorWindow::GetCurrentPage() const
+ {
+ return m_xTabCtrl->get_current_page_ident();
+ }
+
+ void DataNavigatorWindow::LoadModels()
+ {
+ if ( !m_xFrameModel.is() )
+ {
+ // get model of active frame
+ Reference< XController > xCtrl = m_xFrame->getController();
+ if ( xCtrl.is() )
+ {
+ try
+ {
+ m_xFrameModel = xCtrl->getModel();
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::LoadModels()" );
+ }
+ }
+ }
+
+ if ( m_xFrameModel.is() )
+ {
+ try
+ {
+ Reference< css::xforms::XFormsSupplier > xFormsSupp( m_xFrameModel, UNO_QUERY );
+ if ( xFormsSupp.is() )
+ {
+ Reference< XNameContainer > xContainer = xFormsSupp->getXForms();
+ if ( xContainer.is() )
+ {
+ m_xDataContainer = xContainer;
+ const Sequence< OUString > aNameList = m_xDataContainer->getElementNames();
+ for ( const OUString& rName : aNameList )
+ {
+ Any aAny = m_xDataContainer->getByName( rName );
+ Reference< css::xforms::XModel > xFormsModel;
+ if ( aAny >>= xFormsModel )
+ m_xModelsBox->append_text(xFormsModel->getID());
+ }
+ }
+ }
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::LoadModels()" );
+ }
+ }
+
+ if (m_xModelsBox->get_count() > 0)
+ {
+ m_xModelsBox->set_active(0);
+ ModelSelectHdl(m_xModelsBox.get());
+ }
+ }
+
+ void DataNavigatorWindow::SetPageModel(const OString& rIdent)
+ {
+ OUString sModel(m_xModelsBox->get_active_text());
+ try
+ {
+ Any aAny = m_xDataContainer->getByName( sModel );
+ Reference< css::xforms::XModel > xFormsModel;
+ if ( aAny >>= xFormsModel )
+ {
+ int nPagePos = -1;
+ XFormsPage* pPage = GetPage(rIdent);
+ DBG_ASSERT( pPage, "DataNavigatorWindow::SetPageModel(): no page" );
+ if (IsAdditionalPage(rIdent) || rIdent == "instance")
+ {
+ // instance page
+ nPagePos = m_xTabCtrl->get_page_index(rIdent);
+ }
+ m_bIsNotifyDisabled = true;
+ OUString sText = pPage->SetModel( xFormsModel, nPagePos );
+ m_bIsNotifyDisabled = false;
+ if (!sText.isEmpty())
+ m_xTabCtrl->set_tab_label_text(rIdent, sText);
+ }
+ }
+ catch (const NoSuchElementException& )
+ {
+ SAL_WARN( "svx.form", "DataNavigatorWindow::SetPageModel(): no such element" );
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::SetPageModel()" );
+ }
+ }
+
+ void DataNavigatorWindow::InitPages()
+ {
+ OUString sModel(m_xModelsBox->get_active_text());
+ try
+ {
+ Any aAny = m_xDataContainer->getByName( sModel );
+ Reference< css::xforms::XModel > xModel;
+ if ( aAny >>= xModel )
+ {
+ Reference< XEnumerationAccess > xNumAccess = xModel->getInstances();
+ if ( xNumAccess.is() )
+ {
+ Reference < XEnumeration > xNum = xNumAccess->createEnumeration();
+ if ( xNum.is() && xNum->hasMoreElements() )
+ {
+ sal_Int32 nAlreadyLoadedCount = m_aPageList.size();
+ if ( !HasFirstInstancePage() && nAlreadyLoadedCount > 0 )
+ nAlreadyLoadedCount--;
+ sal_Int32 nIdx = 0;
+ while ( xNum->hasMoreElements() )
+ {
+ if ( nIdx > nAlreadyLoadedCount )
+ {
+ Sequence< PropertyValue > xPropSeq;
+ if ( xNum->nextElement() >>= xPropSeq )
+ CreateInstancePage( xPropSeq );
+ else
+ {
+ SAL_WARN( "svx.form", "DataNavigator::InitPages(): invalid instance" );
+ }
+ }
+ else
+ xNum->nextElement();
+ nIdx++;
+ }
+ }
+ }
+ }
+ }
+ catch ( NoSuchElementException& )
+ {
+ SAL_WARN( "svx.form", "DataNavigatorWindow::SetPageModel(): no such element" );
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "DataNavigatorWindow::SetPageModel()" );
+ }
+ }
+
+ void DataNavigatorWindow::ClearAllPageModels( bool bClearPages )
+ {
+ if ( m_xInstPage )
+ m_xInstPage->ClearModel();
+ if ( m_xSubmissionPage )
+ m_xSubmissionPage->ClearModel();
+ if ( m_xBindingPage )
+ m_xBindingPage->ClearModel();
+
+ sal_Int32 nCount = m_aPageList.size();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ XFormsPage* pPage = m_aPageList[i].get();
+ pPage->ClearModel();
+ }
+
+ if ( bClearPages )
+ {
+ m_aPageList.clear();
+ while ( m_xTabCtrl->get_n_pages() > MIN_PAGE_COUNT )
+ m_xTabCtrl->remove_page(m_xTabCtrl->get_page_ident(1));
+ }
+ }
+
+ void DataNavigatorWindow::CreateInstancePage( const Sequence< PropertyValue >& _xPropSeq )
+ {
+ OUString sInstName;
+ auto pProp = std::find_if(_xPropSeq.begin(), _xPropSeq.end(),
+ [](const PropertyValue& rProp) { return PN_INSTANCE_ID == rProp.Name; });
+ if (pProp != _xPropSeq.end())
+ pProp->Value >>= sInstName;
+
+ OString sPageId = GetNewPageId();
+ if ( sInstName.isEmpty() )
+ {
+ SAL_WARN( "svx.form", "DataNavigatorWindow::CreateInstancePage(): instance without name" );
+ sInstName = "untitled";
+ }
+ m_xTabCtrl->insert_page(sPageId, sInstName, m_xTabCtrl->get_n_pages() - 2);
+ }
+
+ bool DataNavigatorWindow::HasFirstInstancePage() const
+ {
+ return m_xTabCtrl->get_page_ident(0) == "instance";
+ }
+
+ OString DataNavigatorWindow::GetNewPageId() const
+ {
+ int nMax = 0;
+
+ int nCount = m_xTabCtrl->get_n_pages();
+ for (int i = 0; i < nCount; ++i)
+ {
+ OString sIdent = m_xTabCtrl->get_page_ident(i);
+ OString sNumber;
+ if (!sIdent.startsWith("additional", &sNumber))
+ continue;
+ int nPageId = sNumber.toInt32();
+ if (nMax < nPageId)
+ nMax = nPageId;
+ }
+
+ return "additional" + OString::number(nMax + 1);
+ }
+
+ void DataNavigatorWindow::SetDocModified()
+ {
+ SfxObjectShell* pCurrentDoc = SfxObjectShell::Current();
+ DBG_ASSERT( pCurrentDoc, "DataNavigatorWindow::SetDocModified(): no objectshell" );
+ if (pCurrentDoc && !pCurrentDoc->IsModified() && pCurrentDoc->IsEnableSetModified())
+ pCurrentDoc->SetModified();
+ }
+
+ void DataNavigatorWindow::NotifyChanges( bool _bLoadAll )
+ {
+ if ( m_bIsNotifyDisabled )
+ return;
+
+ if ( _bLoadAll )
+ {
+ // reset all members
+ RemoveBroadcaster();
+ m_xDataContainer.clear();
+ m_xFrameModel.clear();
+ m_xModelsBox->clear();
+ m_nLastSelectedPos = -1;
+ // for a reload
+ LoadModels();
+ }
+ else
+ m_aUpdateTimer.Start();
+ }
+
+ void DataNavigatorWindow::AddContainerBroadcaster( const css::uno::Reference< css::container::XContainer >& xContainer )
+ {
+ Reference< XContainerListener > xListener = m_xDataListener;
+ xContainer->addContainerListener( xListener );
+ m_aContainerList.push_back( xContainer );
+ }
+
+
+ void DataNavigatorWindow::AddEventBroadcaster( const css::uno::Reference< css::xml::dom::events::XEventTarget >& xTarget )
+ {
+ Reference< XEventListener > xListener = m_xDataListener;
+ xTarget->addEventListener( EVENTTYPE_CHARDATA, xListener, true );
+ xTarget->addEventListener( EVENTTYPE_CHARDATA, xListener, false );
+ xTarget->addEventListener( EVENTTYPE_ATTR, xListener, true );
+ xTarget->addEventListener( EVENTTYPE_ATTR, xListener, false );
+ m_aEventTargetList.push_back( xTarget );
+ }
+
+ void DataNavigatorWindow::RemoveBroadcaster()
+ {
+ Reference< XContainerListener > xContainerListener = m_xDataListener;
+ sal_Int32 i, nCount = m_aContainerList.size();
+ for ( i = 0; i < nCount; ++i )
+ m_aContainerList[i]->removeContainerListener( xContainerListener );
+ Reference< XEventListener > xEventListener = m_xDataListener;
+ nCount = m_aEventTargetList.size();
+ for ( i = 0; i < nCount; ++i )
+ {
+ m_aEventTargetList[i]->removeEventListener( EVENTTYPE_CHARDATA, xEventListener, true );
+ m_aEventTargetList[i]->removeEventListener( EVENTTYPE_CHARDATA, xEventListener, false );
+ m_aEventTargetList[i]->removeEventListener( EVENTTYPE_ATTR, xEventListener, true );
+ m_aEventTargetList[i]->removeEventListener( EVENTTYPE_ATTR, xEventListener, false );
+ }
+ }
+
+ DataNavigator::DataNavigator(SfxBindings* _pBindings, SfxChildWindow* _pMgr, vcl::Window* _pParent)
+ : SfxDockingWindow(_pBindings, _pMgr, _pParent, "DataNavigator", "svx/ui/datanavigator.ui")
+ , SfxControllerItem(SID_FM_DATANAVIGATOR_CONTROL, *_pBindings)
+ , m_xDataWin(new DataNavigatorWindow(this, *m_xBuilder, _pBindings))
+ {
+ SetText( SvxResId( RID_STR_DATANAVIGATOR ) );
+
+ Size aSize = GetOptimalSize();
+ Size aLogSize = PixelToLogic(aSize, MapMode(MapUnit::MapAppFont));
+ SfxDockingWindow::SetFloatingSize( aLogSize );
+ }
+
+ DataNavigator::~DataNavigator()
+ {
+ disposeOnce();
+ }
+
+ void DataNavigator::dispose()
+ {
+ m_xDataWin.reset();
+ ::SfxControllerItem::dispose();
+ SfxDockingWindow::dispose();
+ }
+
+ void DataNavigator::StateChangedAtToolBoxControl( sal_uInt16 , SfxItemState , const SfxPoolItem* )
+ {
+ }
+
+ Size DataNavigator::CalcDockingSize( SfxChildAlignment eAlign )
+ {
+ if ( ( eAlign == SfxChildAlignment::TOP ) || ( eAlign == SfxChildAlignment::BOTTOM ) )
+ return Size();
+
+ return SfxDockingWindow::CalcDockingSize( eAlign );
+ }
+
+ SfxChildAlignment DataNavigator::CheckAlignment( SfxChildAlignment eActAlign, SfxChildAlignment eAlign )
+ {
+ switch ( eAlign )
+ {
+ case SfxChildAlignment::LEFT:
+ case SfxChildAlignment::RIGHT:
+ case SfxChildAlignment::NOALIGNMENT:
+ return eAlign;
+ default:
+ break;
+ }
+ return eActAlign;
+ }
+
+ SFX_IMPL_DOCKINGWINDOW( DataNavigatorManager, SID_FM_SHOW_DATANAVIGATOR )
+
+ DataNavigatorManager::DataNavigatorManager(
+ vcl::Window* _pParent, sal_uInt16 _nId, SfxBindings* _pBindings, SfxChildWinInfo* _pInfo ) :
+
+ SfxChildWindow( _pParent, _nId )
+
+ {
+ SetWindow( VclPtr<DataNavigator>::Create( _pBindings, this, _pParent ) );
+ SetAlignment(SfxChildAlignment::RIGHT);
+ GetWindow()->SetSizePixel( Size( 250, 400 ) );
+ static_cast<SfxDockingWindow*>(GetWindow())->Initialize( _pInfo );
+ }
+
+ AddDataItemDialog::AddDataItemDialog(weld::Window* pParent, ItemNode* _pNode,
+ const Reference< css::xforms::XFormsUIHelper1 >& _rUIHelper)
+ : GenericDialogController(pParent, "svx/ui/adddataitemdialog.ui", "AddDataItemDialog")
+ , m_xUIHelper(_rUIHelper)
+ , m_pItemNode(_pNode)
+ , m_eItemType(DITNone)
+ , m_sFL_Element(SvxResId(RID_STR_ELEMENT))
+ , m_sFL_Attribute(SvxResId(RID_STR_ATTRIBUTE))
+ , m_sFL_Binding(SvxResId(RID_STR_BINDING))
+ , m_sFT_BindingExp(SvxResId(RID_STR_BINDING_EXPR))
+ , m_xItemFrame(m_xBuilder->weld_frame("itemframe"))
+ , m_xNameFT(m_xBuilder->weld_label("nameft"))
+ , m_xNameED(m_xBuilder->weld_entry("name"))
+ , m_xDefaultFT(m_xBuilder->weld_label("valueft"))
+ , m_xDefaultED(m_xBuilder->weld_entry("value"))
+ , m_xDefaultBtn(m_xBuilder->weld_button("browse"))
+ , m_xSettingsFrame(m_xBuilder->weld_widget("settingsframe"))
+ , m_xDataTypeFT(m_xBuilder->weld_label("datatypeft"))
+ , m_xDataTypeLB(m_xBuilder->weld_combo_box("datatype"))
+ , m_xRequiredCB(m_xBuilder->weld_check_button("required"))
+ , m_xRequiredBtn(m_xBuilder->weld_button("requiredcond"))
+ , m_xRelevantCB(m_xBuilder->weld_check_button("relevant"))
+ , m_xRelevantBtn(m_xBuilder->weld_button("relevantcond"))
+ , m_xConstraintCB(m_xBuilder->weld_check_button("constraint"))
+ , m_xConstraintBtn(m_xBuilder->weld_button("constraintcond"))
+ , m_xReadonlyCB(m_xBuilder->weld_check_button("readonly"))
+ , m_xReadonlyBtn(m_xBuilder->weld_button("readonlycond"))
+ , m_xCalculateCB(m_xBuilder->weld_check_button("calculate"))
+ , m_xCalculateBtn(m_xBuilder->weld_button("calculatecond"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+ {
+ InitDialog();
+ InitFromNode();
+ InitDataTypeBox();
+ Check(nullptr);
+ }
+
+ AddDataItemDialog::~AddDataItemDialog()
+ {
+ if ( m_xTempBinding.is() )
+ {
+ Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY );
+ if ( xModel.is() )
+ {
+ try
+ {
+ Reference < XSet > xBindings = xModel->getBindings();
+ if ( xBindings.is() )
+ xBindings->remove( Any( m_xTempBinding ) );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddDataItemDialog::Dtor()" );
+ }
+ }
+ }
+ if( m_xUIHelper.is() && m_xBinding.is() )
+ {
+ // remove binding, if it does not convey 'useful' information
+ m_xUIHelper->removeBindingIfUseless( m_xBinding );
+ }
+ }
+
+ IMPL_LINK(AddDataItemDialog, CheckHdl, weld::Toggleable&, rBox, void)
+ {
+ Check(&rBox);
+ }
+
+ void AddDataItemDialog::Check(const weld::Toggleable* pBox)
+ {
+ // Condition buttons are only enable if their check box is checked
+ m_xReadonlyBtn->set_sensitive( m_xReadonlyCB->get_active() );
+ m_xRequiredBtn->set_sensitive( m_xRequiredCB->get_active() );
+ m_xRelevantBtn->set_sensitive( m_xRelevantCB->get_active() );
+ m_xConstraintBtn->set_sensitive( m_xConstraintCB->get_active() );
+ m_xCalculateBtn->set_sensitive( m_xCalculateCB->get_active() );
+
+ if ( !(pBox && m_xTempBinding.is()) )
+ return;
+
+ OUString sTemp, sPropName;
+ if ( m_xRequiredCB.get() == pBox )
+ sPropName = PN_REQUIRED_EXPR;
+ else if ( m_xRelevantCB.get() == pBox )
+ sPropName = PN_RELEVANT_EXPR;
+ else if ( m_xConstraintCB.get() == pBox )
+ sPropName = PN_CONSTRAINT_EXPR;
+ else if ( m_xReadonlyCB.get() == pBox )
+ sPropName = PN_READONLY_EXPR;
+ else if ( m_xCalculateCB.get() == pBox )
+ sPropName = PN_CALCULATE_EXPR;
+ bool bIsChecked = pBox->get_active();
+ m_xTempBinding->getPropertyValue( sPropName ) >>= sTemp;
+ if ( bIsChecked && sTemp.isEmpty() )
+ sTemp = TRUE_VALUE;
+ else if ( !bIsChecked && !sTemp.isEmpty() )
+ sTemp.clear();
+ m_xTempBinding->setPropertyValue( sPropName, Any( sTemp ) );
+ }
+
+ IMPL_LINK(AddDataItemDialog, ConditionHdl, weld::Button&, rBtn, void)
+ {
+ OUString sPropName;
+ if ( m_xDefaultBtn.get() == &rBtn )
+ sPropName = PN_BINDING_EXPR;
+ else if ( m_xRequiredBtn.get() == &rBtn )
+ sPropName = PN_REQUIRED_EXPR;
+ else if ( m_xRelevantBtn.get() == &rBtn )
+ sPropName = PN_RELEVANT_EXPR;
+ else if ( m_xConstraintBtn.get() == &rBtn )
+ sPropName = PN_CONSTRAINT_EXPR;
+ else if (m_xReadonlyBtn.get() == &rBtn)
+ sPropName = PN_READONLY_EXPR;
+ else if (m_xCalculateBtn.get() == &rBtn)
+ sPropName = PN_CALCULATE_EXPR;
+ AddConditionDialog aDlg(m_xDialog.get(), sPropName, m_xTempBinding);
+ bool bIsDefBtn = ( m_xDefaultBtn.get() == &rBtn );
+ OUString sCondition;
+ if ( bIsDefBtn )
+ sCondition = m_xDefaultED->get_text();
+ else
+ {
+ OUString sTemp;
+ m_xTempBinding->getPropertyValue( sPropName ) >>= sTemp;
+ if ( sTemp.isEmpty() )
+ sTemp = TRUE_VALUE;
+ sCondition = sTemp;
+ }
+ aDlg.SetCondition( sCondition );
+
+ if (aDlg.run() == RET_OK)
+ {
+ OUString sNewCondition = aDlg.GetCondition();
+ if ( bIsDefBtn )
+ m_xDefaultED->set_text(sNewCondition);
+ else
+ {
+
+ m_xTempBinding->setPropertyValue(
+ sPropName, Any( sNewCondition ) );
+ }
+ }
+ }
+
+ static void copyPropSet( const Reference< XPropertySet >& xFrom, Reference< XPropertySet > const & xTo )
+ {
+ DBG_ASSERT( xFrom.is(), "copyPropSet(): no source" );
+ DBG_ASSERT( xTo.is(), "copyPropSet(): no target" );
+
+ try
+ {
+ // get property names & infos, and iterate over target properties
+ const Sequence< Property > aProperties = xTo->getPropertySetInfo()->getProperties();
+ Reference< XPropertySetInfo > xFromInfo = xFrom->getPropertySetInfo();
+ for ( const Property& rProperty : aProperties )
+ {
+ const OUString& rName = rProperty.Name;
+
+ // if both set have the property, copy the value
+ // (catch and ignore exceptions, if any)
+ if ( xFromInfo->hasPropertyByName( rName ) )
+ {
+ // don't set readonly properties
+ Property aProperty = xFromInfo->getPropertyByName( rName );
+ if ( ( aProperty.Attributes & PropertyAttribute::READONLY ) == 0 )
+ xTo->setPropertyValue(rName, xFrom->getPropertyValue( rName ));
+ }
+ // else: no property? then ignore.
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "copyPropSet()" );
+ }
+ }
+
+ IMPL_LINK_NOARG(AddDataItemDialog, OKHdl, weld::Button&, void)
+ {
+ bool bIsHandleBinding = ( DITBinding == m_eItemType );
+ bool bIsHandleText = ( DITText == m_eItemType );
+ OUString sNewName( m_xNameED->get_text() );
+
+ if ( ( !bIsHandleBinding && !bIsHandleText && !m_xUIHelper->isValidXMLName( sNewName ) ) ||
+ ( bIsHandleBinding && sNewName.isEmpty() ) )
+ {
+ // Error and don't close the dialog
+ std::unique_ptr<weld::MessageDialog> xErrBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SvxResId(RID_STR_INVALID_XMLNAME)));
+ xErrBox->set_primary_text(xErrBox->get_primary_text().replaceFirst(MSG_VARIABLE, sNewName));
+ xErrBox->run();
+ return;
+ }
+
+ OUString sDataType( m_xDataTypeLB->get_active_text() );
+ m_xTempBinding->setPropertyValue( PN_BINDING_TYPE, Any( sDataType ) );
+
+ if ( bIsHandleBinding )
+ {
+ // copy properties from temp binding to original binding
+ copyPropSet( m_xTempBinding, m_pItemNode->m_xPropSet );
+ try
+ {
+ OUString sValue = m_xNameED->get_text();
+ m_pItemNode->m_xPropSet->setPropertyValue( PN_BINDING_ID, Any( sValue ) );
+ sValue = m_xDefaultED->get_text();
+ m_pItemNode->m_xPropSet->setPropertyValue( PN_BINDING_EXPR, Any( sValue ) );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddDataDialog::OKHdl()" );
+ }
+ }
+ else
+ {
+ // copy properties from temp binding to original binding
+ copyPropSet( m_xTempBinding, m_xBinding );
+ try
+ {
+ if ( bIsHandleText )
+ m_xUIHelper->setNodeValue( m_pItemNode->m_xNode, m_xDefaultED->get_text() );
+ else
+ {
+ Reference< css::xml::dom::XNode > xNewNode =
+ m_xUIHelper->renameNode( m_pItemNode->m_xNode, m_xNameED->get_text() );
+ m_xUIHelper->setNodeValue( xNewNode, m_xDefaultED->get_text() );
+ m_pItemNode->m_xNode = xNewNode;
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddDataDialog::OKHdl()" );
+ }
+ }
+ // then close the dialog
+ m_xDialog->response(RET_OK);
+ }
+
+ void AddDataItemDialog::InitDialog()
+ {
+ // set handler
+ Link<weld::Toggleable&,void> aLink = LINK( this, AddDataItemDialog, CheckHdl );
+ m_xRequiredCB->connect_toggled( aLink );
+ m_xRelevantCB->connect_toggled( aLink );
+ m_xConstraintCB->connect_toggled( aLink );
+ m_xReadonlyCB->connect_toggled( aLink );
+ m_xCalculateCB->connect_toggled( aLink );
+
+ Link<weld::Button&,void> aLink2 = LINK( this, AddDataItemDialog, ConditionHdl );
+ m_xDefaultBtn->connect_clicked( aLink2 );
+ m_xRequiredBtn->connect_clicked( aLink2 );
+ m_xRelevantBtn->connect_clicked( aLink2 );
+ m_xConstraintBtn->connect_clicked( aLink2 );
+ m_xReadonlyBtn->connect_clicked( aLink2 );
+ m_xCalculateBtn->connect_clicked( aLink2 );
+
+ m_xOKBtn->connect_clicked( LINK( this, AddDataItemDialog, OKHdl ) );
+ }
+
+ void AddDataItemDialog::InitFromNode()
+ {
+ if ( m_pItemNode )
+ {
+ if ( m_pItemNode->m_xNode.is() )
+ {
+ try
+ {
+ // detect type of the node
+ css::xml::dom::NodeType eChildType = m_pItemNode->m_xNode->getNodeType();
+ switch ( eChildType )
+ {
+ case css::xml::dom::NodeType_ATTRIBUTE_NODE:
+ m_eItemType = DITAttribute;
+ break;
+ case css::xml::dom::NodeType_ELEMENT_NODE:
+ m_eItemType = DITElement;
+ break;
+ case css::xml::dom::NodeType_TEXT_NODE:
+ m_eItemType = DITText;
+ break;
+ default:
+ OSL_FAIL( "AddDataItemDialog::InitFronNode: cannot handle this node type!" );
+ break;
+ }
+
+ /** Get binding of the node and clone it
+ Then use this temporary binding in the dialog.
+ When the user click OK the temporary binding will be copied
+ into the original binding.
+ */
+
+ Reference< css::xml::dom::XNode > xNode = m_pItemNode->m_xNode;
+ m_xBinding = m_xUIHelper->getBindingForNode( xNode, true );
+ if ( m_xBinding.is() )
+ {
+ Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY );
+ if ( xModel.is() )
+ {
+ m_xTempBinding = m_xUIHelper->cloneBindingAsGhost( m_xBinding );
+ Reference < XSet > xBindings = xModel->getBindings();
+ if ( xBindings.is() )
+ xBindings->insert( Any( m_xTempBinding ) );
+ }
+ }
+
+ if ( m_eItemType != DITText )
+ {
+ OUString sName( m_xUIHelper->getNodeName( m_pItemNode->m_xNode ) );
+ m_xNameED->set_text( sName );
+ }
+ m_xDefaultED->set_text( m_pItemNode->m_xNode->getNodeValue() );
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddDataItemDialog::InitFromNode()" );
+ }
+ }
+ else if ( m_pItemNode->m_xPropSet.is() )
+ {
+ m_eItemType = DITBinding;
+ Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY );
+ if ( xModel.is() )
+ {
+ try
+ {
+ m_xTempBinding = m_xUIHelper->cloneBindingAsGhost( m_pItemNode->m_xPropSet );
+ Reference < XSet > xBindings = xModel->getBindings();
+ if ( xBindings.is() )
+ xBindings->insert( Any( m_xTempBinding ) );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddDataItemDialog::InitFromNode()" );
+ }
+ }
+ try
+ {
+ Reference< XPropertySetInfo > xInfo = m_pItemNode->m_xPropSet->getPropertySetInfo();
+ OUString sTemp;
+ if ( xInfo->hasPropertyByName( PN_BINDING_ID ) )
+ {
+ m_pItemNode->m_xPropSet->getPropertyValue( PN_BINDING_ID ) >>= sTemp;
+ m_xNameED->set_text( sTemp );
+ m_pItemNode->m_xPropSet->getPropertyValue( PN_BINDING_EXPR ) >>= sTemp;
+ m_xDefaultED->set_text( sTemp );
+ }
+ else if ( xInfo->hasPropertyByName( PN_SUBMISSION_BIND ) )
+ {
+ m_pItemNode->m_xPropSet->getPropertyValue( PN_SUBMISSION_ID ) >>= sTemp;
+ m_xNameED->set_text( sTemp );
+ }
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddDataItemDialog::InitFromNode()" );
+ }
+
+ m_xDefaultBtn->show();
+ }
+
+ if ( m_xTempBinding.is() )
+ {
+ try
+ {
+ OUString sTemp;
+ if ( ( m_xTempBinding->getPropertyValue( PN_REQUIRED_EXPR ) >>= sTemp )
+ && !sTemp.isEmpty() )
+ m_xRequiredCB->set_active(true);
+ if ( ( m_xTempBinding->getPropertyValue( PN_RELEVANT_EXPR ) >>= sTemp )
+ && !sTemp.isEmpty() )
+ m_xRelevantCB->set_active(true);
+ if ( ( m_xTempBinding->getPropertyValue( PN_CONSTRAINT_EXPR ) >>= sTemp )
+ && !sTemp.isEmpty() )
+ m_xConstraintCB->set_active(true);
+ if ( ( m_xTempBinding->getPropertyValue( PN_READONLY_EXPR ) >>= sTemp )
+ && !sTemp.isEmpty() )
+ m_xReadonlyCB->set_active(true);
+ if ( ( m_xTempBinding->getPropertyValue( PN_CALCULATE_EXPR ) >>= sTemp )
+ && !sTemp.isEmpty() )
+ m_xCalculateCB->set_active(true);
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddDataItemDialog::InitFromNode()" );
+ }
+ }
+ }
+
+ if ( DITText == m_eItemType )
+ {
+ m_xSettingsFrame->hide();
+ m_xNameFT->set_sensitive(false);
+ m_xNameED->set_sensitive(false);
+ }
+ }
+
+ void AddDataItemDialog::InitDataTypeBox()
+ {
+ if ( m_eItemType == DITText )
+ return;
+
+ Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY );
+ if ( !xModel.is() )
+ return;
+
+ try
+ {
+ Reference< css::xforms::XDataTypeRepository > xDataTypes =
+ xModel->getDataTypeRepository();
+ if ( xDataTypes.is() )
+ {
+ const Sequence< OUString > aNameList = xDataTypes->getElementNames();
+ for ( const OUString& rName : aNameList )
+ m_xDataTypeLB->append_text(rName);
+ }
+
+ if ( m_xTempBinding.is() )
+ {
+ OUString sTemp;
+ if ( m_xTempBinding->getPropertyValue( PN_BINDING_TYPE ) >>= sTemp )
+ {
+ int nPos = m_xDataTypeLB->find_text(sTemp);
+ if (nPos == -1)
+ {
+ m_xDataTypeLB->append_text(sTemp);
+ nPos = m_xDataTypeLB->get_count() - 1;
+ }
+ m_xDataTypeLB->set_active(nPos);
+ }
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddDataItemDialog::InitDataTypeBox()" );
+ }
+ }
+
+ void AddDataItemDialog::InitText( DataItemType _eType )
+ {
+ OUString sText;
+
+ switch ( _eType )
+ {
+ case DITAttribute :
+ {
+ sText = m_sFL_Attribute;
+ break;
+ }
+
+ case DITBinding :
+ {
+ sText = m_sFL_Binding;
+ m_xDefaultFT->set_label(m_sFT_BindingExp);
+ break;
+ }
+
+ default:
+ {
+ sText = m_sFL_Element;
+ }
+ }
+
+ m_xItemFrame->set_label(sText);
+ }
+
+ AddConditionDialog::AddConditionDialog(weld::Window* pParent,
+ const OUString& _rPropertyName,
+ const Reference< XPropertySet >& _rPropSet)
+ : GenericDialogController(pParent, "svx/ui/addconditiondialog.ui", "AddConditionDialog")
+ , m_aResultIdle("svx AddConditionDialog m_aResultIdle")
+ , m_sPropertyName(_rPropertyName)
+ , m_xBinding(_rPropSet)
+ , m_xConditionED(m_xBuilder->weld_text_view("condition"))
+ , m_xResultWin(m_xBuilder->weld_text_view("result"))
+ , m_xEditNamespacesBtn(m_xBuilder->weld_button("edit"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+ {
+ DBG_ASSERT( m_xBinding.is(), "AddConditionDialog::Ctor(): no Binding" );
+
+ m_xConditionED->set_size_request(m_xConditionED->get_approximate_digit_width() * 52,
+ m_xConditionED->get_height_rows(4));
+ m_xResultWin->set_size_request(m_xResultWin->get_approximate_digit_width() * 52,
+ m_xResultWin->get_height_rows(4));
+
+ m_xConditionED->connect_changed( LINK( this, AddConditionDialog, ModifyHdl ) );
+ m_xEditNamespacesBtn->connect_clicked( LINK( this, AddConditionDialog, EditHdl ) );
+ m_xOKBtn->connect_clicked( LINK( this, AddConditionDialog, OKHdl ) );
+ m_aResultIdle.SetPriority( TaskPriority::LOWEST );
+ m_aResultIdle.SetInvokeHandler( LINK( this, AddConditionDialog, ResultHdl ) );
+
+ if ( !m_sPropertyName.isEmpty() )
+ {
+ try
+ {
+ OUString sTemp;
+ if ( ( m_xBinding->getPropertyValue( m_sPropertyName ) >>= sTemp )
+ && !sTemp.isEmpty() )
+ {
+ m_xConditionED->set_text( sTemp );
+ }
+ else
+ {
+//! m_xBinding->setPropertyValue( m_sPropertyName, makeAny( TRUE_VALUE ) );
+ m_xConditionED->set_text( TRUE_VALUE );
+ }
+
+ Reference< css::xforms::XModel > xModel;
+ if ( ( m_xBinding->getPropertyValue( PN_BINDING_MODEL ) >>= xModel ) && xModel.is() )
+ m_xUIHelper.set( xModel, UNO_QUERY );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddConditionDialog::Ctor()" );
+ }
+ }
+
+ DBG_ASSERT( m_xUIHelper.is(), "AddConditionDialog::Ctor(): no UIHelper" );
+ ResultHdl( &m_aResultIdle );
+ }
+
+ AddConditionDialog::~AddConditionDialog()
+ {
+ }
+
+ IMPL_LINK_NOARG(AddConditionDialog, EditHdl, weld::Button&, void)
+ {
+ Reference< XNameContainer > xNameContnr;
+ try
+ {
+ m_xBinding->getPropertyValue( PN_BINDING_NAMESPACES ) >>= xNameContnr;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddDataItemDialog::EditHdl()" );
+ }
+ NamespaceItemDialog aDlg(this, xNameContnr);
+ aDlg.run();
+ try
+ {
+ m_xBinding->setPropertyValue( PN_BINDING_NAMESPACES, Any( xNameContnr ) );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddDataItemDialog::EditHdl()" );
+ }
+ }
+
+ IMPL_LINK_NOARG(AddConditionDialog, OKHdl, weld::Button&, void)
+ {
+ m_xDialog->response(RET_OK);
+ }
+
+ IMPL_LINK_NOARG(AddConditionDialog, ModifyHdl, weld::TextView&, void)
+ {
+ m_aResultIdle.Start();
+ }
+
+ IMPL_LINK_NOARG(AddConditionDialog, ResultHdl, Timer *, void)
+ {
+ OUString sCondition = comphelper::string::strip(m_xConditionED->get_text(), ' ');
+ OUString sResult;
+ if ( !sCondition.isEmpty() )
+ {
+ try
+ {
+ sResult = m_xUIHelper->getResultForExpression( m_xBinding, ( m_sPropertyName == PN_BINDING_EXPR ), sCondition );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddConditionDialog::ResultHdl()" );
+ }
+ }
+ m_xResultWin->set_text(sResult);
+ }
+
+ NamespaceItemDialog::NamespaceItemDialog(AddConditionDialog* pCondDlg, Reference<XNameContainer>& rContainer)
+ : GenericDialogController(pCondDlg->getDialog(), "svx/ui/namespacedialog.ui", "NamespaceDialog")
+ , m_pConditionDlg(pCondDlg)
+ , m_rNamespaces(rContainer)
+ , m_xNamespacesList(m_xBuilder->weld_tree_view("namespaces"))
+ , m_xAddNamespaceBtn(m_xBuilder->weld_button("add"))
+ , m_xEditNamespaceBtn(m_xBuilder->weld_button("edit"))
+ , m_xDeleteNamespaceBtn(m_xBuilder->weld_button("delete"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+ {
+ m_xNamespacesList->set_size_request(m_xNamespacesList->get_approximate_digit_width() * 80,
+ m_xNamespacesList->get_height_rows(8));
+
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(m_xNamespacesList->get_approximate_digit_width() * 20)
+ };
+ m_xNamespacesList->set_column_fixed_widths(aWidths);
+
+ m_xNamespacesList->connect_changed( LINK( this, NamespaceItemDialog, SelectHdl ) );
+ Link<weld::Button&,void> aLink = LINK( this, NamespaceItemDialog, ClickHdl );
+ m_xAddNamespaceBtn->connect_clicked( aLink );
+ m_xEditNamespaceBtn->connect_clicked( aLink );
+ m_xDeleteNamespaceBtn->connect_clicked( aLink );
+ m_xOKBtn->connect_clicked( LINK( this, NamespaceItemDialog, OKHdl ) );
+
+ LoadNamespaces();
+ SelectHdl(*m_xNamespacesList);
+ }
+
+ NamespaceItemDialog::~NamespaceItemDialog()
+ {
+ }
+
+ IMPL_LINK_NOARG( NamespaceItemDialog, SelectHdl, weld::TreeView&, void)
+ {
+ bool bEnable = m_xNamespacesList->get_selected_index() != -1;
+ m_xEditNamespaceBtn->set_sensitive( bEnable );
+ m_xDeleteNamespaceBtn->set_sensitive( bEnable );
+ }
+
+ IMPL_LINK( NamespaceItemDialog, ClickHdl, weld::Button&, rButton, void )
+ {
+ if (m_xAddNamespaceBtn.get() == &rButton)
+ {
+ ManageNamespaceDialog aDlg(m_xDialog.get(), m_pConditionDlg, false);
+ if (aDlg.run() == RET_OK)
+ {
+ m_xNamespacesList->append_text(aDlg.GetPrefix());
+ int nRow = m_xNamespacesList->n_children();
+ m_xNamespacesList->set_text(nRow - 1, aDlg.GetURL(), 1);
+ }
+ }
+ else if (m_xEditNamespaceBtn.get() == &rButton)
+ {
+ ManageNamespaceDialog aDlg(m_xDialog.get(), m_pConditionDlg, true);
+ int nEntry = m_xNamespacesList->get_selected_index();
+ DBG_ASSERT( nEntry != -1, "NamespaceItemDialog::ClickHdl(): no entry" );
+ OUString sPrefix(m_xNamespacesList->get_text(nEntry, 0));
+ aDlg.SetNamespace(sPrefix, m_xNamespacesList->get_text(nEntry, 1));
+ if (aDlg.run() == RET_OK)
+ {
+ // if a prefix was changed, mark the old prefix as 'removed'
+ if( sPrefix != aDlg.GetPrefix() )
+ m_aRemovedList.push_back( sPrefix );
+
+ m_xNamespacesList->set_text(nEntry, aDlg.GetPrefix(), 0);
+ m_xNamespacesList->set_text(nEntry, aDlg.GetURL(), 1);
+ }
+ }
+ else if (m_xDeleteNamespaceBtn.get() == &rButton)
+ {
+ int nEntry = m_xNamespacesList->get_selected_index();
+ DBG_ASSERT( nEntry != -1, "NamespaceItemDialog::ClickHdl(): no entry" );
+ OUString sPrefix(m_xNamespacesList->get_text(nEntry, 0));
+ m_aRemovedList.push_back( sPrefix );
+ m_xNamespacesList->remove(nEntry);
+ }
+ else
+ {
+ SAL_WARN( "svx.form", "NamespaceItemDialog::ClickHdl(): invalid button" );
+ }
+
+ SelectHdl(*m_xNamespacesList);
+ }
+
+ IMPL_LINK_NOARG(NamespaceItemDialog, OKHdl, weld::Button&, void)
+ {
+ try
+ {
+ // update namespace container
+ sal_Int32 i, nRemovedCount = m_aRemovedList.size();
+ for( i = 0; i < nRemovedCount; ++i )
+ m_rNamespaces->removeByName( m_aRemovedList[i] );
+
+ sal_Int32 nEntryCount = m_xNamespacesList->n_children();
+ for( i = 0; i < nEntryCount; ++i )
+ {
+ OUString sPrefix(m_xNamespacesList->get_text(i, 0));
+ OUString sURL(m_xNamespacesList->get_text(i, 1));
+
+ if ( m_rNamespaces->hasByName( sPrefix ) )
+ m_rNamespaces->replaceByName( sPrefix, Any( sURL ) );
+ else
+ m_rNamespaces->insertByName( sPrefix, Any( sURL ) );
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "NamespaceItemDialog::OKHdl()" );
+ }
+ // and close the dialog
+ m_xDialog->response(RET_OK);
+ }
+
+ void NamespaceItemDialog::LoadNamespaces()
+ {
+ try
+ {
+ int nRow = 0;
+ const Sequence< OUString > aAllNames = m_rNamespaces->getElementNames();
+ for ( const OUString& sPrefix : aAllNames )
+ {
+ if ( m_rNamespaces->hasByName( sPrefix ) )
+ {
+ OUString sURL;
+ Any aAny = m_rNamespaces->getByName( sPrefix );
+ if (aAny >>= sURL)
+ {
+ m_xNamespacesList->append_text(sPrefix);
+ m_xNamespacesList->set_text(nRow, sURL, 1);
+ ++nRow;
+ }
+ }
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "NamespaceItemDialog::LoadNamespaces()" );
+ }
+ }
+
+ ManageNamespaceDialog::ManageNamespaceDialog(weld::Window* pParent, AddConditionDialog* pCondDlg, bool bIsEdit)
+ : GenericDialogController(pParent, "svx/ui/addnamespacedialog.ui", "AddNamespaceDialog")
+ , m_pConditionDlg(pCondDlg)
+ , m_xPrefixED(m_xBuilder->weld_entry("prefix"))
+ , m_xUrlED(m_xBuilder->weld_entry("url"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+ , m_xAltTitle(m_xBuilder->weld_label("alttitle"))
+ {
+ if (bIsEdit)
+ m_xDialog->set_title(m_xAltTitle->get_label());
+
+ m_xOKBtn->connect_clicked(LINK(this, ManageNamespaceDialog, OKHdl));
+ }
+
+ ManageNamespaceDialog::~ManageNamespaceDialog()
+ {
+ }
+
+ IMPL_LINK_NOARG(ManageNamespaceDialog, OKHdl, weld::Button&, void)
+ {
+ OUString sPrefix = m_xPrefixED->get_text();
+
+ try
+ {
+ if (!m_pConditionDlg->GetUIHelper()->isValidPrefixName(sPrefix))
+ {
+ std::unique_ptr<weld::MessageDialog> xErrBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SvxResId(RID_STR_INVALID_XMLPREFIX)));
+ xErrBox->set_primary_text(xErrBox->get_primary_text().replaceFirst(MSG_VARIABLE, sPrefix));
+ xErrBox->run();
+ return;
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "ManageNamespacesDialog::OKHdl()" );
+ }
+
+ // no error so close the dialog
+ m_xDialog->response(RET_OK);
+ }
+
+ AddSubmissionDialog::AddSubmissionDialog(
+ weld::Window* pParent, ItemNode* _pNode,
+ const Reference< css::xforms::XFormsUIHelper1 >& _rUIHelper)
+ : GenericDialogController(pParent, "svx/ui/addsubmissiondialog.ui", "AddSubmissionDialog")
+ , m_pItemNode(_pNode)
+ , m_xUIHelper(_rUIHelper)
+ , m_xNameED(m_xBuilder->weld_entry("name"))
+ , m_xActionED(m_xBuilder->weld_entry("action"))
+ , m_xMethodLB(m_xBuilder->weld_combo_box("method"))
+ , m_xRefED(m_xBuilder->weld_entry("expression"))
+ , m_xRefBtn(m_xBuilder->weld_button("browse"))
+ , m_xBindLB(m_xBuilder->weld_combo_box("binding"))
+ , m_xReplaceLB(m_xBuilder->weld_combo_box("replace"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+ {
+ FillAllBoxes();
+
+ m_xRefBtn->connect_clicked( LINK( this, AddSubmissionDialog, RefHdl ) );
+ m_xOKBtn->connect_clicked( LINK( this, AddSubmissionDialog, OKHdl ) );
+ }
+
+ AddSubmissionDialog::~AddSubmissionDialog()
+ {
+ // #i38991# if we have added a binding, we need to remove it as well.
+ if( m_xCreatedBinding.is() && m_xUIHelper.is() )
+ m_xUIHelper->removeBindingIfUseless( m_xCreatedBinding );
+ }
+
+ IMPL_LINK_NOARG(AddSubmissionDialog, RefHdl, weld::Button&, void)
+ {
+ AddConditionDialog aDlg(m_xDialog.get(), PN_BINDING_EXPR, m_xTempBinding );
+ aDlg.SetCondition( m_xRefED->get_text() );
+ if ( aDlg.run() == RET_OK )
+ m_xRefED->set_text(aDlg.GetCondition());
+ }
+
+ IMPL_LINK_NOARG(AddSubmissionDialog, OKHdl, weld::Button&, void)
+ {
+ OUString sName(m_xNameED->get_text());
+ if(sName.isEmpty())
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SvxResId(RID_STR_EMPTY_SUBMISSIONNAME)));
+ xErrorBox->run();
+ return;
+ }
+
+ if ( !m_xSubmission.is() )
+ {
+ DBG_ASSERT( !m_xNewSubmission.is(),
+ "AddSubmissionDialog::OKHdl(): new submission already exists" );
+
+ // add a new submission
+ Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY );
+ if ( xModel.is() )
+ {
+ try
+ {
+ m_xNewSubmission = xModel->createSubmission();
+ m_xSubmission = m_xNewSubmission;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddSubmissionDialog::OKHdl()" );
+ }
+ }
+ }
+
+ if ( m_xSubmission.is() )
+ {
+ OUString sTemp = m_xNameED->get_text();
+ try
+ {
+ m_xSubmission->setPropertyValue( PN_SUBMISSION_ID, Any( sTemp ) );
+ sTemp = m_xActionED->get_text();
+ m_xSubmission->setPropertyValue( PN_SUBMISSION_ACTION, Any( sTemp ) );
+ sTemp = m_aMethodString.toAPI( m_xMethodLB->get_active_text() );
+ m_xSubmission->setPropertyValue( PN_SUBMISSION_METHOD, Any( sTemp ) );
+ sTemp = m_xRefED->get_text();
+ m_xSubmission->setPropertyValue( PN_SUBMISSION_REF, Any( sTemp ) );
+ OUString sEntry = m_xBindLB->get_active_text();
+ sal_Int32 nColonIdx = sEntry.indexOf(':');
+ if (nColonIdx != -1)
+ sEntry = sEntry.copy(0, nColonIdx);
+ sTemp = sEntry;
+ m_xSubmission->setPropertyValue( PN_SUBMISSION_BIND, Any( sTemp ) );
+ sTemp = m_aReplaceString.toAPI( m_xReplaceLB->get_active_text() );
+ m_xSubmission->setPropertyValue( PN_SUBMISSION_REPLACE, Any( sTemp ) );
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddSubmissionDialog::OKHdl()" );
+ }
+ }
+
+ m_xDialog->response(RET_OK);
+ }
+
+ void AddSubmissionDialog::FillAllBoxes()
+ {
+ // method box
+ m_xMethodLB->append_text(SvxResId(RID_STR_METHOD_POST));
+ m_xMethodLB->append_text(SvxResId(RID_STR_METHOD_PUT));
+ m_xMethodLB->append_text(SvxResId(RID_STR_METHOD_GET));
+ m_xMethodLB->set_active(0);
+
+ // binding box
+ Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY );
+ if ( xModel.is() )
+ {
+ try
+ {
+ Reference< XEnumerationAccess > xNumAccess = xModel->getBindings();
+ if ( xNumAccess.is() )
+ {
+ Reference < XEnumeration > xNum = xNumAccess->createEnumeration();
+ if ( xNum.is() && xNum->hasMoreElements() )
+ {
+ while ( xNum->hasMoreElements() )
+ {
+ Reference< XPropertySet > xPropSet;
+ Any aAny = xNum->nextElement();
+ if ( aAny >>= xPropSet )
+ {
+ OUString sEntry;
+ OUString sTemp;
+ xPropSet->getPropertyValue( PN_BINDING_ID ) >>= sTemp;
+ sEntry += sTemp + ": ";
+ xPropSet->getPropertyValue( PN_BINDING_EXPR ) >>= sTemp;
+ sEntry += sTemp;
+ m_xBindLB->append_text(sEntry);
+
+ if ( !m_xTempBinding.is() )
+ m_xTempBinding = xPropSet;
+ }
+ }
+ }
+ }
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddSubmissionDialog::FillAllBoxes()" );
+ }
+ }
+
+ // #i36342# we need a temporary binding; create one if no existing binding
+ // is found
+ if( !m_xTempBinding.is() )
+ {
+ m_xCreatedBinding = m_xUIHelper->getBindingForNode(
+ Reference<css::xml::dom::XNode>(
+ xModel->getDefaultInstance()->getDocumentElement(),
+ UNO_QUERY_THROW ),
+ true );
+ m_xTempBinding = m_xCreatedBinding;
+ }
+
+ // replace box
+ m_xReplaceLB->append_text(SvxResId(RID_STR_REPLACE_NONE));
+ m_xReplaceLB->append_text(SvxResId(RID_STR_REPLACE_INST));
+ m_xReplaceLB->append_text(SvxResId(RID_STR_REPLACE_DOC));
+
+
+ // init the controls with the values of the submission
+ if ( m_pItemNode && m_pItemNode->m_xPropSet.is() )
+ {
+ m_xSubmission = m_pItemNode->m_xPropSet;
+ try
+ {
+ OUString sTemp;
+ m_xSubmission->getPropertyValue( PN_SUBMISSION_ID ) >>= sTemp;
+ m_xNameED->set_text( sTemp );
+ m_xSubmission->getPropertyValue( PN_SUBMISSION_ACTION ) >>= sTemp;
+ m_xActionED->set_text( sTemp );
+ m_xSubmission->getPropertyValue( PN_SUBMISSION_REF ) >>= sTemp;
+ m_xRefED->set_text(sTemp);
+
+ m_xSubmission->getPropertyValue( PN_SUBMISSION_METHOD ) >>= sTemp;
+ sTemp = m_aMethodString.toUI( sTemp );
+ sal_Int32 nPos = m_xMethodLB->find_text( sTemp );
+ if (nPos == -1)
+ {
+ m_xMethodLB->append_text( sTemp );
+ nPos = m_xMethodLB->get_count() - 1;
+ }
+ m_xMethodLB->set_active( nPos );
+
+ m_xSubmission->getPropertyValue( PN_SUBMISSION_BIND ) >>= sTemp;
+ nPos = m_xBindLB->find_text(sTemp);
+ if (nPos == -1)
+ {
+ m_xBindLB->append_text(sTemp);
+ nPos = m_xBindLB->get_count() - 1;
+ }
+ m_xBindLB->set_active(nPos);
+
+ m_xSubmission->getPropertyValue( PN_SUBMISSION_REPLACE ) >>= sTemp;
+ sTemp = m_aReplaceString.toUI( sTemp );
+ if ( sTemp.isEmpty() )
+ sTemp = m_xReplaceLB->get_text(0); // first entry == "none"
+ nPos = m_xReplaceLB->find_text(sTemp);
+ if (nPos == -1)
+ {
+ m_xReplaceLB->append_text(sTemp);
+ nPos = m_xReplaceLB->get_count() - 1;
+ }
+ m_xReplaceLB->set_active(nPos);
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.form", "AddSubmissionDialog::FillAllBoxes()" );
+ }
+ }
+
+ m_xRefBtn->set_sensitive(m_xTempBinding.is());
+ }
+
+ AddModelDialog::AddModelDialog(weld::Window* pParent, bool bIsEdit)
+ : GenericDialogController(pParent, "svx/ui/addmodeldialog.ui", "AddModelDialog")
+ , m_xNameED(m_xBuilder->weld_entry("name"))
+ , m_xModifyCB(m_xBuilder->weld_check_button("modify"))
+ , m_xAltTitle(m_xBuilder->weld_label("alttitle"))
+ {
+ if (bIsEdit)
+ m_xDialog->set_title(m_xAltTitle->get_label());
+ }
+
+ AddModelDialog::~AddModelDialog()
+ {
+ }
+
+ AddInstanceDialog::AddInstanceDialog(weld::Window* pParent, bool _bEdit)
+ : GenericDialogController(pParent, "svx/ui/addinstancedialog.ui", "AddInstanceDialog")
+ , m_xNameED(m_xBuilder->weld_entry("name"))
+ , m_xURLFT(m_xBuilder->weld_label("urlft"))
+ , m_xURLED(new SvtURLBox(m_xBuilder->weld_combo_box("url")))
+ , m_xFilePickerBtn(m_xBuilder->weld_button("browse"))
+ , m_xLinkInstanceCB(m_xBuilder->weld_check_button("link"))
+ , m_xAltTitle(m_xBuilder->weld_label("alttitle"))
+ {
+ if (_bEdit)
+ m_xDialog->set_title(m_xAltTitle->get_label());
+
+ m_xURLED->DisableHistory();
+ m_xFilePickerBtn->connect_clicked(LINK(this, AddInstanceDialog, FilePickerHdl));
+
+ // load the filter name from fps resource
+ m_sAllFilterName = Translate::get(STR_FILTERNAME_ALL, Translate::Create("fps"));
+ }
+
+ AddInstanceDialog::~AddInstanceDialog()
+ {
+ }
+
+ IMPL_LINK_NOARG(AddInstanceDialog, FilePickerHdl, weld::Button&, void)
+ {
+ ::sfx2::FileDialogHelper aDlg(
+ css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::NONE, m_xDialog.get());
+ aDlg.SetContext(sfx2::FileDialogHelper::FormsAddInstance);
+
+ aDlg.AddFilter( m_sAllFilterName, FILEDIALOG_FILTER_ALL );
+ OUString sFilterName( "XML" );
+ aDlg.AddFilter( sFilterName, "*.xml" );
+ aDlg.SetCurrentFilter( sFilterName );
+
+ if (aDlg.Execute() == ERRCODE_NONE)
+ m_xURLED->set_entry_text(aDlg.GetPath());
+ }
+
+ LinkedInstanceWarningBox::LinkedInstanceWarningBox(weld::Widget* pParent)
+ : MessageDialogController(pParent, "svx/ui/formlinkwarndialog.ui",
+ "FormLinkWarnDialog")
+ {
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/dbcharsethelper.cxx b/svx/source/form/dbcharsethelper.cxx
new file mode 100644
index 000000000..a20ffa7c1
--- /dev/null
+++ b/svx/source/form/dbcharsethelper.cxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbcharsethelper.hxx>
+
+#include <connectivity/dbcharset.hxx>
+
+using namespace ::dbtools;
+
+namespace svxform::charset_helper
+{
+
+ sal_Int32 getSupportedTextEncodings( ::std::vector< rtl_TextEncoding >& _rEncs )
+ {
+ OCharsetMap aCharsetInfo;
+ _rEncs.clear();
+
+ OCharsetMap::const_iterator aLoop = aCharsetInfo.begin();
+ OCharsetMap::const_iterator aLoopEnd = aCharsetInfo.end();
+ while (aLoop != aLoopEnd)
+ {
+ _rEncs.push_back( (*aLoop).getEncoding() );
+ ++aLoop;
+ }
+
+ return _rEncs.size();
+ }
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/delayedevent.cxx b/svx/source/form/delayedevent.cxx
new file mode 100644
index 000000000..8a9cb218d
--- /dev/null
+++ b/svx/source/form/delayedevent.cxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <delayedevent.hxx>
+#include <vcl/svapp.hxx>
+#include <sal/log.hxx>
+
+namespace svxform
+{
+ void DelayedEvent::Call()
+ {
+ CancelPendingCall();
+ SAL_WARN_IF( m_nEventId != nullptr, "svx.form", "DelayedEvent::Call: CancelPendingCall did not work!" );
+
+ m_nEventId = Application::PostUserEvent( LINK( this, DelayedEvent, OnCall ) );
+ }
+
+ void DelayedEvent::CancelPendingCall()
+ {
+ if ( m_nEventId )
+ Application::RemoveUserEvent( m_nEventId );
+ m_nEventId = nullptr;
+ }
+
+ IMPL_LINK( DelayedEvent, OnCall, void*, _pArg, void )
+ {
+ m_nEventId = nullptr;
+ m_aHandler.Call( _pArg );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/filtnav.cxx b/svx/source/form/filtnav.cxx
new file mode 100644
index 000000000..9b1703f6a
--- /dev/null
+++ b/svx/source/form/filtnav.cxx
@@ -0,0 +1,1850 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <filtnav.hxx>
+#include <fmexch.hxx>
+#include <helpids.h>
+#include <fmprop.hxx>
+#include <svx/strings.hrc>
+
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/form/runtime/XFormController.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqlnode.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <fmshimp.hxx>
+#include <o3tl/safeint.hxx>
+#include <sfx2/objitem.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/fmtools.hxx>
+#include <svx/svxids.hrc>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+#include <bitmaps.hlst>
+
+#include <functional>
+
+using namespace ::svxform;
+using namespace ::connectivity;
+using namespace ::dbtools;
+
+namespace svxform
+{
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::container::XIndexAccess;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::form::runtime::XFormController;
+ using ::com::sun::star::form::runtime::XFilterController;
+ using ::com::sun::star::form::runtime::XFilterControllerListener;
+ using ::com::sun::star::form::runtime::FilterEvent;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::form::XForm;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::awt::XControl;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::util::XNumberFormatsSupplier;
+ using ::com::sun::star::util::XNumberFormatter;
+ using ::com::sun::star::util::NumberFormatter;
+ using ::com::sun::star::sdbc::XRowSet;
+ using ::com::sun::star::lang::Locale;
+ using ::com::sun::star::sdb::SQLContext;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Sequence;
+
+
+OFilterItemExchange::OFilterItemExchange()
+ : m_pFormItem(nullptr)
+{
+}
+
+void OFilterItemExchange::AddSupportedFormats()
+{
+ AddFormat(getFormatId());
+}
+
+SotClipboardFormatId OFilterItemExchange::getFormatId()
+{
+ static SotClipboardFormatId s_nFormat =
+ SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"form.FilterControlExchange\"");
+ DBG_ASSERT(static_cast<SotClipboardFormatId>(-1) != s_nFormat, "OFilterExchangeHelper::getFormatId: bad exchange id!");
+ return s_nFormat;
+}
+
+rtl::Reference<OLocalExchange> OFilterExchangeHelper::createExchange() const
+{
+ return new OFilterItemExchange;
+}
+
+OUString FmFilterData::GetImage() const
+{
+ return OUString();
+}
+
+FmParentData::~FmParentData()
+{
+}
+
+OUString FmFormItem::GetImage() const
+{
+ return RID_SVXBMP_FORM;
+}
+
+FmFilterItem* FmFilterItems::Find( const ::sal_Int32 _nFilterComponentIndex ) const
+{
+ for ( auto & pData : m_aChildren )
+ {
+ FmFilterItem& rCondition = dynamic_cast<FmFilterItem&>(*pData);
+ if ( _nFilterComponentIndex == rCondition.GetComponentIndex() )
+ return &rCondition;
+ }
+ return nullptr;
+}
+
+OUString FmFilterItems::GetImage() const
+{
+ return RID_SVXBMP_FILTER;
+}
+
+FmFilterItem::FmFilterItem( FmFilterItems* pParent,
+ const OUString& aFieldName,
+ const OUString& aText,
+ const sal_Int32 _nComponentIndex )
+ :FmFilterData(pParent, aText)
+ ,m_aFieldName(aFieldName)
+ ,m_nComponentIndex( _nComponentIndex )
+{
+}
+
+OUString FmFilterItem::GetImage() const
+{
+ return RID_SVXBMP_FIELD;
+}
+
+// Hints for communication between model and view
+
+namespace {
+
+class FmFilterHint : public SfxHint
+{
+ FmFilterData* m_pData;
+
+public:
+ explicit FmFilterHint(FmFilterData* pData):m_pData(pData){}
+ FmFilterData* GetData() const { return m_pData; }
+};
+
+class FmFilterInsertedHint : public FmFilterHint
+{
+ size_t m_nPos; // Position relative to the parent of the data
+
+public:
+ FmFilterInsertedHint(FmFilterData* pData, size_t nRelPos)
+ :FmFilterHint(pData)
+ ,m_nPos(nRelPos){}
+
+ size_t GetPos() const { return m_nPos; }
+};
+
+class FmFilterRemovedHint : public FmFilterHint
+{
+public:
+ explicit FmFilterRemovedHint(FmFilterData* pData)
+ :FmFilterHint(pData){}
+};
+
+
+class FmFilterTextChangedHint : public FmFilterHint
+{
+public:
+ explicit FmFilterTextChangedHint(FmFilterData* pData)
+ :FmFilterHint(pData){}
+};
+
+class FilterClearingHint : public SfxHint
+{
+public:
+ FilterClearingHint(){}
+};
+
+class FmFilterCurrentChangedHint : public SfxHint
+{
+public:
+ FmFilterCurrentChangedHint(){}
+};
+
+}
+
+// class FmFilterAdapter, listener at the FilterControls
+class FmFilterAdapter : public ::cppu::WeakImplHelper< XFilterControllerListener >
+{
+ FmFilterModel* m_pModel;
+ Reference< XIndexAccess > m_xControllers;
+
+public:
+ FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers);
+
+// XEventListener
+ virtual void SAL_CALL disposing(const EventObject& Source) override;
+
+// XFilterControllerListener
+ virtual void SAL_CALL predicateExpressionChanged( const FilterEvent& Event ) override;
+ virtual void SAL_CALL disjunctiveTermRemoved( const FilterEvent& Event ) override;
+ virtual void SAL_CALL disjunctiveTermAdded( const FilterEvent& Event ) override;
+
+// helpers
+ /// @throws RuntimeException
+ void dispose();
+
+ void AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd );
+
+ static void setText(sal_Int32 nPos,
+ const FmFilterItem* pFilterItem,
+ const OUString& rText);
+};
+
+
+FmFilterAdapter::FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers)
+ :m_pModel( pModel )
+ ,m_xControllers( xControllers )
+{
+ AddOrRemoveListener( m_xControllers, true );
+}
+
+
+void FmFilterAdapter::dispose()
+{
+ AddOrRemoveListener( m_xControllers, false );
+}
+
+
+void FmFilterAdapter::AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd )
+{
+ for (sal_Int32 i = 0, nLen = _rxControllers->getCount(); i < nLen; ++i)
+ {
+ Reference< XIndexAccess > xElement( _rxControllers->getByIndex(i), UNO_QUERY );
+
+ // step down
+ AddOrRemoveListener( xElement, _bAdd );
+
+ // handle this particular controller
+ Reference< XFilterController > xController( xElement, UNO_QUERY );
+ OSL_ENSURE( xController.is(), "FmFilterAdapter::InsertElements: no XFilterController, cannot sync data!" );
+ if ( xController.is() )
+ {
+ if ( _bAdd )
+ xController->addFilterControllerListener( this );
+ else
+ xController->removeFilterControllerListener( this );
+ }
+ }
+}
+
+
+void FmFilterAdapter::setText(sal_Int32 nRowPos,
+ const FmFilterItem* pFilterItem,
+ const OUString& rText)
+{
+ FmFormItem* pFormItem = dynamic_cast<FmFormItem*>( pFilterItem->GetParent()->GetParent() );
+ assert(pFormItem);
+ try
+ {
+ Reference< XFilterController > xController( pFormItem->GetController(), UNO_QUERY_THROW );
+ xController->setPredicateExpression( pFilterItem->GetComponentIndex(), nRowPos, rText );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+// XEventListener
+
+void SAL_CALL FmFilterAdapter::disposing(const EventObject& /*e*/)
+{
+}
+
+
+namespace
+{
+ OUString lcl_getLabelName_nothrow( const Reference< XControl >& _rxControl )
+ {
+ OUString sLabelName;
+ try
+ {
+ Reference< XPropertySet > xModel( _rxControl->getModel(), UNO_QUERY_THROW );
+ sLabelName = getLabelName( xModel );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return sLabelName;
+ }
+
+ Reference< XPropertySet > lcl_getBoundField_nothrow( const Reference< XControl >& _rxControl )
+ {
+ Reference< XPropertySet > xField;
+ try
+ {
+ Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY_THROW );
+ xField.set( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return xField;
+ }
+}
+
+// XFilterControllerListener
+void FmFilterAdapter::predicateExpressionChanged( const FilterEvent& Event )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !m_pModel )
+ return;
+
+ // the controller which sent the event
+ Reference< XFormController > xController( Event.Source, UNO_QUERY_THROW );
+ Reference< XFilterController > xFilterController( Event.Source, UNO_QUERY_THROW );
+ Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
+
+ FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
+ OSL_ENSURE( pFormItem, "FmFilterAdapter::predicateExpressionChanged: don't know this form!" );
+ if ( !pFormItem )
+ return;
+
+ const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() );
+
+ FmFilterData* pData = pFormItem->GetChildren()[nActiveTerm].get();
+ FmFilterItems& rFilter = dynamic_cast<FmFilterItems&>(*pData);
+ FmFilterItem* pFilterItem = rFilter.Find( Event.FilterComponent );
+ if ( pFilterItem )
+ {
+ if ( !Event.PredicateExpression.isEmpty())
+ {
+ pFilterItem->SetText( Event.PredicateExpression );
+ // notify the UI
+ FmFilterTextChangedHint aChangeHint(pFilterItem);
+ m_pModel->Broadcast( aChangeHint );
+ }
+ else
+ {
+ // no text anymore so remove the condition
+ m_pModel->Remove(pFilterItem);
+ }
+ }
+ else
+ {
+ // searching the component by field name
+ OUString aFieldName( lcl_getLabelName_nothrow( xFilterController->getFilterComponent( Event.FilterComponent ) ) );
+
+ std::unique_ptr<FmFilterItem> pNewFilterItem(new FmFilterItem(&rFilter, aFieldName, Event.PredicateExpression, Event.FilterComponent));
+ m_pModel->Insert(rFilter.GetChildren().end(), std::move(pNewFilterItem));
+ }
+
+ // ensure there's one empty term in the filter, just in case the active term was previously empty
+ m_pModel->EnsureEmptyFilterRows( *pFormItem );
+}
+
+
+void SAL_CALL FmFilterAdapter::disjunctiveTermRemoved( const FilterEvent& Event )
+{
+ SolarMutexGuard aGuard;
+
+ Reference< XFormController > xController( Event.Source, UNO_QUERY_THROW );
+ Reference< XFilterController > xFilterController( Event.Source, UNO_QUERY_THROW );
+ Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
+
+ FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
+ OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermRemoved: don't know this form!" );
+ if ( !pFormItem )
+ return;
+
+ auto& rTermItems = pFormItem->GetChildren();
+ const bool bValidIndex = ( Event.DisjunctiveTerm >= 0 ) && ( o3tl::make_unsigned(Event.DisjunctiveTerm) < rTermItems.size() );
+ OSL_ENSURE( bValidIndex, "FmFilterAdapter::disjunctiveTermRemoved: invalid term index!" );
+ if ( !bValidIndex )
+ return;
+
+ // if the first term was removed, then the to-be first term needs its text updated
+ if ( Event.DisjunctiveTerm == 0 )
+ {
+ rTermItems[1]->SetText( SvxResId(RID_STR_FILTER_FILTER_FOR));
+ FmFilterTextChangedHint aChangeHint( rTermItems[1].get() );
+ m_pModel->Broadcast( aChangeHint );
+ }
+
+ // finally remove the entry from the model
+ m_pModel->Remove( rTermItems.begin() + Event.DisjunctiveTerm );
+
+ // ensure there's one empty term in the filter, just in case the currently removed one was the last empty one
+ m_pModel->EnsureEmptyFilterRows( *pFormItem );
+}
+
+
+void SAL_CALL FmFilterAdapter::disjunctiveTermAdded( const FilterEvent& Event )
+{
+ SolarMutexGuard aGuard;
+
+ Reference< XFormController > xController( Event.Source, UNO_QUERY_THROW );
+ Reference< XFilterController > xFilterController( Event.Source, UNO_QUERY_THROW );
+ Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW );
+
+ FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm );
+ OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermAdded: don't know this form!" );
+ if ( !pFormItem )
+ return;
+
+ const sal_Int32 nInsertPos = Event.DisjunctiveTerm;
+ bool bValidIndex = ( nInsertPos >= 0 ) && ( o3tl::make_unsigned(nInsertPos) <= pFormItem->GetChildren().size() );
+ if ( !bValidIndex )
+ {
+ OSL_FAIL( "FmFilterAdapter::disjunctiveTermAdded: invalid index!" );
+ return;
+ }
+
+ auto insertPos = pFormItem->GetChildren().begin() + nInsertPos;
+
+ // "Filter for" for first position, "Or" for the other positions
+ std::unique_ptr<FmFilterItems> pFilterItems(new FmFilterItems(pFormItem, (nInsertPos?SvxResId(RID_STR_FILTER_FILTER_OR):SvxResId(RID_STR_FILTER_FILTER_FOR))));
+ m_pModel->Insert( insertPos, std::move(pFilterItems) );
+}
+
+
+FmFilterModel::FmFilterModel()
+ :FmParentData(nullptr, OUString())
+ ,OSQLParserClient(comphelper::getProcessComponentContext())
+ ,m_pCurrentItems(nullptr)
+{
+}
+
+
+FmFilterModel::~FmFilterModel()
+{
+ Clear();
+}
+
+
+void FmFilterModel::Clear()
+{
+ // notify
+ FilterClearingHint aClearedHint;
+ Broadcast( aClearedHint );
+
+ // lose endings
+ if (m_pAdapter.is())
+ {
+ m_pAdapter->dispose();
+ m_pAdapter.clear();
+ }
+
+ m_pCurrentItems = nullptr;
+ m_xController = nullptr;
+ m_xControllers = nullptr;
+
+ m_aChildren.clear();
+}
+
+
+void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent)
+{
+ if ( xCurrent == m_xController )
+ return;
+
+ if (!xControllers.is())
+ {
+ Clear();
+ return;
+ }
+
+ // there is only a new current controller
+ if ( m_xControllers != xControllers )
+ {
+ Clear();
+
+ m_xControllers = xControllers;
+ Update(m_xControllers, this);
+
+ DBG_ASSERT(xCurrent.is(), "FmFilterModel::Update(...) no current controller");
+
+ // Listening for TextChanges
+ m_pAdapter = new FmFilterAdapter(this, xControllers);
+
+ SetCurrentController(xCurrent);
+ EnsureEmptyFilterRows( *this );
+ }
+ else
+ SetCurrentController(xCurrent);
+}
+
+
+void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, FmParentData* pParent)
+{
+ try
+ {
+ sal_Int32 nCount = xControllers->getCount();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ Reference< XFormController > xController( xControllers->getByIndex(i), UNO_QUERY_THROW );
+
+ Reference< XPropertySet > xFormProperties( xController->getModel(), UNO_QUERY_THROW );
+ OUString aName;
+ OSL_VERIFY( xFormProperties->getPropertyValue( FM_PROP_NAME ) >>= aName );
+
+ // Insert a new item for the form
+ FmFormItem* pFormItem = new FmFormItem( pParent, xController, aName );
+ Insert( pParent->GetChildren().end(), std::unique_ptr<FmFilterData>(pFormItem) );
+
+ Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
+
+ // insert the existing filters for the form
+ OUString aTitle(SvxResId(RID_STR_FILTER_FILTER_FOR));
+
+ const Sequence< Sequence< OUString > > aExpressions = xFilterController->getPredicateExpressions();
+ for ( auto const & conjunctionTerm : aExpressions )
+ {
+ // we always display one row, even if there's no term to be displayed
+ FmFilterItems* pFilterItems = new FmFilterItems( pFormItem, aTitle );
+ Insert( pFormItem->GetChildren().end(), std::unique_ptr<FmFilterData>(pFilterItems) );
+
+ const Sequence< OUString >& rDisjunction( conjunctionTerm );
+ sal_Int32 nComponentIndex = -1;
+ for ( const OUString& rDisjunctiveTerm : rDisjunction )
+ {
+ ++nComponentIndex;
+
+ if ( rDisjunctiveTerm.isEmpty() )
+ // no condition for this particular component in this particular conjunction term
+ continue;
+
+ // determine the display name of the control
+ const Reference< XControl > xFilterControl( xFilterController->getFilterComponent( nComponentIndex ) );
+ const OUString sDisplayName( lcl_getLabelName_nothrow( xFilterControl ) );
+
+ // insert a new entry
+ std::unique_ptr<FmFilterItem> pANDCondition(new FmFilterItem( pFilterItems, sDisplayName, rDisjunctiveTerm, nComponentIndex ));
+ Insert( pFilterItems->GetChildren().end(), std::move(pANDCondition) );
+ }
+
+ // title for the next conditions
+ aTitle = SvxResId( RID_STR_FILTER_FILTER_OR );
+ }
+
+ // now add dependent controllers
+ Update( xController, pFormItem );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+FmFormItem* FmFilterModel::Find(const ::std::vector<std::unique_ptr<FmFilterData>>& rItems, const Reference< XFormController > & xController) const
+{
+ for (const auto& rItem : rItems)
+ {
+ FmFormItem* pForm = dynamic_cast<FmFormItem*>( rItem.get() );
+ if (pForm)
+ {
+ if ( xController == pForm->GetController() )
+ return pForm;
+ else
+ {
+ pForm = Find(pForm->GetChildren(), xController);
+ if (pForm)
+ return pForm;
+ }
+ }
+ }
+ return nullptr;
+}
+
+
+FmFormItem* FmFilterModel::Find(const ::std::vector<std::unique_ptr<FmFilterData>>& rItems, const Reference< XForm >& xForm) const
+{
+ for (const auto& rItem : rItems)
+ {
+ FmFormItem* pForm = dynamic_cast<FmFormItem*>( rItem.get() );
+ if (pForm)
+ {
+ if (xForm == pForm->GetController()->getModel())
+ return pForm;
+ else
+ {
+ pForm = Find(pForm->GetChildren(), xForm);
+ if (pForm)
+ return pForm;
+ }
+ }
+ }
+ return nullptr;
+}
+
+void FmFilterModel::SetCurrentController(const Reference< XFormController > & xCurrent)
+{
+ if ( xCurrent == m_xController )
+ return;
+
+ m_xController = xCurrent;
+
+ FmFormItem* pItem = Find( m_aChildren, xCurrent );
+ if ( !pItem )
+ return;
+
+ try
+ {
+ Reference< XFilterController > xFilterController( m_xController, UNO_QUERY_THROW );
+ const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() );
+ if (nActiveTerm != -1 && pItem->GetChildren().size() > o3tl::make_unsigned(nActiveTerm))
+ {
+ SetCurrentItems( static_cast< FmFilterItems* >( pItem->GetChildren()[ nActiveTerm ].get() ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+void FmFilterModel::AppendFilterItems( FmFormItem& _rFormItem )
+{
+ // insert the condition behind the last filter items
+ auto iter = std::find_if(_rFormItem.GetChildren().rbegin(), _rFormItem.GetChildren().rend(),
+ [](const std::unique_ptr<FmFilterData>& rChild) { return dynamic_cast<const FmFilterItems*>(rChild.get()) != nullptr; });
+
+ sal_Int32 nInsertPos = iter.base() - _rFormItem.GetChildren().begin();
+ // delegate this to the FilterController, it will notify us, which will let us update our model
+ try
+ {
+ Reference< XFilterController > xFilterController( _rFormItem.GetFilterController(), UNO_SET_THROW );
+ if ( nInsertPos >= xFilterController->getDisjunctiveTerms() )
+ xFilterController->appendEmptyDisjunctiveTerm();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+void FmFilterModel::Insert(const ::std::vector<std::unique_ptr<FmFilterData>>::iterator& rPos, std::unique_ptr<FmFilterData> pData)
+{
+ auto pTemp = pData.get();
+ size_t nPos;
+ ::std::vector<std::unique_ptr<FmFilterData>>& rItems = pData->GetParent()->GetChildren();
+ if (rPos == rItems.end())
+ {
+ nPos = rItems.size();
+ rItems.push_back(std::move(pData));
+ }
+ else
+ {
+ nPos = rPos - rItems.begin();
+ rItems.insert(rPos, std::move(pData));
+ }
+
+ // notify the UI
+ FmFilterInsertedHint aInsertedHint(pTemp, nPos);
+ Broadcast( aInsertedHint );
+}
+
+void FmFilterModel::Remove(FmFilterData* pData)
+{
+ FmParentData* pParent = pData->GetParent();
+ ::std::vector<std::unique_ptr<FmFilterData>>& rItems = pParent->GetChildren();
+
+ // erase the item from the model
+ auto i = ::std::find_if(rItems.begin(), rItems.end(),
+ [&](const std::unique_ptr<FmFilterData>& p) { return p.get() == pData; } );
+ DBG_ASSERT(i != rItems.end(), "FmFilterModel::Remove(): unknown Item");
+ // position within the parent
+ sal_Int32 nPos = i - rItems.begin();
+ if (auto pFilterItems = dynamic_cast<FmFilterItems*>( pData))
+ {
+ FmFormItem* pFormItem = static_cast<FmFormItem*>(pParent);
+
+ try
+ {
+ Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
+
+ bool bEmptyLastTerm = ( ( nPos == 0 ) && xFilterController->getDisjunctiveTerms() == 1 );
+ if ( bEmptyLastTerm )
+ {
+ // remove all children (by setting an empty predicate expression)
+ ::std::vector< std::unique_ptr<FmFilterData> >& rChildren = pFilterItems->GetChildren();
+ while ( !rChildren.empty() )
+ {
+ auto removePos = rChildren.end() - 1;
+ if (FmFilterItem* pFilterItem = dynamic_cast<FmFilterItem*>( removePos->get() ))
+ {
+ FmFilterAdapter::setText( nPos, pFilterItem, OUString() );
+ }
+ Remove( removePos );
+ }
+ }
+ else
+ {
+ xFilterController->removeDisjunctiveTerm( nPos );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ else // FormItems can not be deleted
+ {
+ FmFilterItem& rFilterItem = dynamic_cast<FmFilterItem&>(*pData);
+
+ // if it's the last condition remove the parent
+ if (rItems.size() == 1)
+ Remove(rFilterItem.GetParent());
+ else
+ {
+ // find the position of the father within his father
+ ::std::vector<std::unique_ptr<FmFilterData>>& rParentParentItems = pData->GetParent()->GetParent()->GetChildren();
+ auto j = ::std::find_if(rParentParentItems.begin(), rParentParentItems.end(),
+ [&](const std::unique_ptr<FmFilterData>& p) { return p.get() == rFilterItem.GetParent(); });
+ DBG_ASSERT(j != rParentParentItems.end(), "FmFilterModel::Remove(): unknown Item");
+ sal_Int32 nParentPos = j - rParentParentItems.begin();
+
+ // EmptyText removes the filter
+ FmFilterAdapter::setText(nParentPos, &rFilterItem, OUString());
+ Remove( i );
+ }
+ }
+}
+
+void FmFilterModel::Remove( const ::std::vector<std::unique_ptr<FmFilterData>>::iterator& rPos )
+{
+ // remove from parent's child list
+ std::unique_ptr<FmFilterData> pData = std::move(*rPos);
+ pData->GetParent()->GetChildren().erase( rPos );
+
+ // notify the view, this will remove the actual SvTreeListEntry
+ FmFilterRemovedHint aRemoveHint( pData.get() );
+ Broadcast( aRemoveHint );
+}
+
+
+bool FmFilterModel::ValidateText(FmFilterItem const * pItem, OUString& rText, OUString& rErrorMsg) const
+{
+ FmFormItem* pFormItem = dynamic_cast<FmFormItem*>( pItem->GetParent()->GetParent() );
+ assert(pFormItem);
+ try
+ {
+ Reference< XFormController > xFormController( pFormItem->GetController() );
+ // obtain the connection of the form belonging to the controller
+ Reference< XRowSet > xRowSet( xFormController->getModel(), UNO_QUERY_THROW );
+ Reference< XConnection > xConnection( getConnection( xRowSet ) );
+
+ // obtain a number formatter for this connection
+ // TODO: shouldn't this be cached?
+ Reference< XNumberFormatsSupplier > xFormatSupplier = getNumberFormats( xConnection, true );
+ Reference< XNumberFormatter > xFormatter( NumberFormatter::create( comphelper::getProcessComponentContext() ), UNO_QUERY_THROW );
+ xFormatter->attachNumberFormatsSupplier( xFormatSupplier );
+
+ // get the field (database column) which the item is responsible for
+ Reference< XFilterController > xFilterController( xFormController, UNO_QUERY_THROW );
+ Reference< XPropertySet > xField( lcl_getBoundField_nothrow( xFilterController->getFilterComponent( pItem->GetComponentIndex() ) ), UNO_SET_THROW );
+
+ // parse the given text as filter predicate
+ OUString aErr, aTxt( rText );
+ std::unique_ptr< OSQLParseNode > pParseNode = predicateTree( aErr, aTxt, xFormatter, xField );
+ rErrorMsg = aErr;
+ rText = aTxt;
+ if ( pParseNode != nullptr )
+ {
+ OUString aPreparedText;
+ Locale aAppLocale = Application::GetSettings().GetUILanguageTag().getLocale();
+ pParseNode->parseNodeToPredicateStr(
+ aPreparedText, xConnection, xFormatter, xField, OUString(), aAppLocale, OUString("."), getParseContext() );
+ rText = aPreparedText;
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ return false;
+}
+
+
+void FmFilterModel::Append(FmFilterItems* pItems, std::unique_ptr<FmFilterItem> pFilterItem)
+{
+ Insert(pItems->GetChildren().end(), std::move(pFilterItem));
+}
+
+
+void FmFilterModel::SetTextForItem(FmFilterItem* pItem, const OUString& rText)
+{
+ ::std::vector<std::unique_ptr<FmFilterData>>& rItems = pItem->GetParent()->GetParent()->GetChildren();
+ auto i = ::std::find_if(rItems.begin(), rItems.end(),
+ [&](const std::unique_ptr<FmFilterData>& p) { return p.get() == pItem->GetParent(); });
+ sal_Int32 nParentPos = i - rItems.begin();
+
+ FmFilterAdapter::setText(nParentPos, pItem, rText);
+
+ if (rText.isEmpty())
+ Remove(pItem);
+ else
+ {
+ // Change the text
+ pItem->SetText(rText);
+ FmFilterTextChangedHint aChangeHint(pItem);
+ Broadcast( aChangeHint );
+ }
+}
+
+
+void FmFilterModel::SetCurrentItems(FmFilterItems* pCurrent)
+{
+ if (m_pCurrentItems == pCurrent)
+ return;
+
+ // search for the condition
+ if (pCurrent)
+ {
+ FmFormItem* pFormItem = static_cast<FmFormItem*>(pCurrent->GetParent());
+ ::std::vector<std::unique_ptr<FmFilterData>>& rItems = pFormItem->GetChildren();
+ auto i = ::std::find_if(rItems.begin(), rItems.end(),
+ [&](const std::unique_ptr<FmFilterData>& p) { return p.get() == pCurrent; });
+
+ if (i != rItems.end())
+ {
+ // determine the filter position
+ sal_Int32 nPos = i - rItems.begin();
+ try
+ {
+ Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW );
+ xFilterController->setActiveTerm( nPos );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ if ( m_xController != pFormItem->GetController() )
+ // calls SetCurrentItems again
+ SetCurrentController( pFormItem->GetController() );
+ else
+ m_pCurrentItems = pCurrent;
+ }
+ else
+ m_pCurrentItems = nullptr;
+ }
+ else
+ m_pCurrentItems = nullptr;
+
+
+ // notify the UI
+ FmFilterCurrentChangedHint aHint;
+ Broadcast( aHint );
+}
+
+
+void FmFilterModel::EnsureEmptyFilterRows( FmParentData& _rItem )
+{
+ // checks whether for each form there's one free level for input
+ ::std::vector< std::unique_ptr<FmFilterData> >& rChildren = _rItem.GetChildren();
+ bool bAppendLevel = dynamic_cast<const FmFormItem*>(&_rItem) != nullptr;
+
+ for ( const auto& rpChild : rChildren )
+ {
+ FmFilterItems* pItems = dynamic_cast<FmFilterItems*>( rpChild.get() );
+ if ( pItems && pItems->GetChildren().empty() )
+ {
+ bAppendLevel = false;
+ break;
+ }
+
+ FmFormItem* pFormItem = dynamic_cast<FmFormItem*>( rpChild.get() );
+ if (pFormItem)
+ {
+ EnsureEmptyFilterRows( *pFormItem );
+ continue;
+ }
+ }
+
+ if ( bAppendLevel )
+ {
+ FmFormItem* pFormItem = dynamic_cast<FmFormItem*>( &_rItem );
+ OSL_ENSURE( pFormItem, "FmFilterModel::EnsureEmptyFilterRows: no FmFormItem, but a FmFilterItems child?" );
+ if ( pFormItem )
+ AppendFilterItems( *pFormItem );
+ }
+}
+
+const int nxD = 4;
+const int nxDBmp = 12;
+
+IMPL_STATIC_LINK(FmFilterNavigator, CustomGetSizeHdl, weld::TreeView::get_size_args, aPayload, Size)
+{
+ vcl::RenderContext& rRenderContext = aPayload.first;
+ const OUString& rId = aPayload.second;
+
+ Size aSize;
+
+ FmFilterData* pData = weld::fromId<FmFilterData*>(rId);
+ OUString sText = pData->GetText();
+
+ if (FmFilterItem* pItem = dynamic_cast<FmFilterItem*>(pData))
+ {
+ rRenderContext.Push(vcl::PushFlags::FONT);
+ vcl::Font aFont(rRenderContext.GetFont());
+ aFont.SetWeight(WEIGHT_BOLD);
+ rRenderContext.SetFont(aFont);
+
+ OUString sName = pItem->GetFieldName() + ": ";
+ aSize = Size(rRenderContext.GetTextWidth(sName), rRenderContext.GetTextHeight());
+
+ rRenderContext.Pop();
+
+ aSize.AdjustWidth(rRenderContext.GetTextWidth(sText) + nxD);
+ }
+ else
+ {
+ aSize = Size(rRenderContext.GetTextWidth(sText), rRenderContext.GetTextHeight());
+ if (dynamic_cast<FmFilterItems*>(pData))
+ aSize.AdjustWidth(nxDBmp);
+ }
+
+ return aSize;
+}
+
+IMPL_STATIC_LINK(FmFilterNavigator, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
+{
+ vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
+ const ::tools::Rectangle& rRect = std::get<1>(aPayload);
+ ::tools::Rectangle aRect(rRect.TopLeft(), Size(rRenderContext.GetOutputSize().Width() - rRect.Left(), rRect.GetHeight()));
+ bool bSelected = std::get<2>(aPayload);
+ const OUString& rId = std::get<3>(aPayload);
+
+ rRenderContext.Push(vcl::PushFlags::TEXTCOLOR);
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ if (bSelected)
+ rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
+ else
+ rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
+
+ FmFilterData* pData = weld::fromId<FmFilterData*>(rId);
+ OUString sText = pData->GetText();
+ Point aPos(aRect.TopLeft());
+
+ if (FmFilterItem* pFilter = dynamic_cast<FmFilterItem*>(pData))
+ {
+ vcl::Font aFont(rRenderContext.GetFont());
+ aFont.SetWeight(WEIGHT_BOLD);
+
+ rRenderContext.Push(vcl::PushFlags::FONT);
+ rRenderContext.SetFont(aFont);
+
+ OUString sName = pFilter->GetFieldName() + ": ";
+ rRenderContext.DrawText(aPos, sName);
+
+ // position for the second text
+ aPos.AdjustX(rRenderContext.GetTextWidth(sName) + nxD);
+ rRenderContext.Pop();
+
+ rRenderContext.DrawText(aPos, sText);
+ }
+ else if (FmFilterItems* pRow = dynamic_cast<FmFilterItems*>(pData))
+ {
+ FmFormItem* pForm = static_cast<FmFormItem*>(pRow->GetParent());
+
+ // current filter is significant painted
+ const bool bIsCurrentFilter = pForm->GetChildren()[ pForm->GetFilterController()->getActiveTerm() ].get() == pRow;
+ if (bIsCurrentFilter)
+ {
+ rRenderContext.Push(vcl::PushFlags::LINECOLOR);
+ rRenderContext.SetLineColor(rRenderContext.GetTextColor());
+
+ Point aFirst(aPos.X(), aRect.Bottom() - 6);
+ Point aSecond(aFirst .X() + 2, aFirst.Y() + 3);
+
+ rRenderContext.DrawLine(aFirst, aSecond);
+
+ aFirst = aSecond;
+ aFirst.AdjustX(1);
+ aSecond.AdjustX(6);
+ aSecond.AdjustY(-5);
+
+ rRenderContext.DrawLine(aFirst, aSecond);
+ rRenderContext.Pop();
+ }
+
+ rRenderContext.DrawText(Point(aPos.X() + nxDBmp, aPos.Y()), sText);
+ }
+ else
+ rRenderContext.DrawText(aPos, sText);
+
+ rRenderContext.Pop();
+}
+
+FmFilterNavigatorDropTarget::FmFilterNavigatorDropTarget(FmFilterNavigator& rTreeView)
+ : DropTargetHelper(rTreeView.get_widget().get_drop_target())
+ , m_rTreeView(rTreeView)
+{
+}
+
+sal_Int8 FmFilterNavigatorDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt);
+
+ if (nAccept != DND_ACTION_NONE)
+ {
+ // to enable the autoscroll when we're close to the edges
+ weld::TreeView& rWidget = m_rTreeView.get_widget();
+ rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
+ }
+
+ return nAccept;
+}
+
+sal_Int8 FmFilterNavigatorDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
+{
+ return m_rTreeView.ExecuteDrop(rEvt);
+}
+
+FmFilterNavigator::FmFilterNavigator(vcl::Window* pTopLevel, std::unique_ptr<weld::TreeView> xTreeView)
+ : m_xTopLevel(pTopLevel)
+ , m_xTreeView(std::move(xTreeView))
+ , m_aDropTargetHelper(*this)
+ , m_nAsyncRemoveEvent(nullptr)
+{
+ m_xTreeView->set_help_id(HID_FILTER_NAVIGATOR);
+
+ m_xTreeView->set_selection_mode(SelectionMode::Multiple);
+
+ m_pModel.reset( new FmFilterModel() );
+ StartListening( *m_pModel );
+
+ m_xTreeView->connect_custom_get_size(LINK(this, FmFilterNavigator, CustomGetSizeHdl));
+ m_xTreeView->connect_custom_render(LINK(this, FmFilterNavigator, CustomRenderHdl));
+ m_xTreeView->set_column_custom_renderer(0, true);
+
+ m_xTreeView->connect_changed(LINK(this, FmFilterNavigator, SelectHdl));
+ m_xTreeView->connect_key_press(LINK(this, FmFilterNavigator, KeyInputHdl));
+ m_xTreeView->connect_popup_menu(LINK(this, FmFilterNavigator, PopupMenuHdl));
+ m_xTreeView->connect_editing(LINK(this, FmFilterNavigator, EditingEntryHdl),
+ LINK(this, FmFilterNavigator, EditedEntryHdl));
+ m_xTreeView->connect_drag_begin(LINK(this, FmFilterNavigator, DragBeginHdl));
+}
+
+FmFilterNavigator::~FmFilterNavigator()
+{
+ if (m_nAsyncRemoveEvent)
+ Application::RemoveUserEvent(m_nAsyncRemoveEvent);
+ EndListening(*m_pModel);
+ m_pModel.reset();
+}
+
+void FmFilterNavigator::UpdateContent(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent)
+{
+ if (xCurrent == m_pModel->GetCurrentController())
+ return;
+
+ m_pModel->Update(xControllers, xCurrent);
+
+ // expand the filters for the current controller
+ std::unique_ptr<weld::TreeIter> xEntry = FindEntry(m_pModel->GetCurrentForm());
+ if (!xEntry || m_xTreeView->get_row_expanded(*xEntry))
+ return;
+
+ m_xTreeView->unselect_all();
+
+ m_xTreeView->expand_row(*xEntry);
+
+ xEntry = FindEntry(m_pModel->GetCurrentItems());
+ if (xEntry)
+ {
+ if (!m_xTreeView->get_row_expanded(*xEntry))
+ m_xTreeView->expand_row(*xEntry);
+ m_xTreeView->select(*xEntry);
+ SelectHdl(*m_xTreeView);
+ }
+}
+
+IMPL_LINK(FmFilterNavigator, EditingEntryHdl, const weld::TreeIter&, rIter, bool)
+{
+ // returns true to allow editing
+ if (dynamic_cast<const FmFilterItem*>(weld::fromId<FmFilterData*>(m_xTreeView->get_id(rIter))))
+ {
+ m_xEditingCurrently = m_xTreeView->make_iterator(&rIter);
+ return true;
+ }
+ m_xEditingCurrently.reset();
+ return false;
+}
+
+IMPL_LINK(FmFilterNavigator, EditedEntryHdl, const IterString&, rIterString, bool)
+{
+ const weld::TreeIter& rIter = rIterString.first;
+ const OUString& rNewText = rIterString.second;
+
+ assert(m_xEditingCurrently && m_xTreeView->iter_compare(rIter, *m_xEditingCurrently) == 0 &&
+ "FmFilterNavigator::EditedEntry: suspicious entry!");
+ m_xEditingCurrently.reset();
+
+ FmFilterData* pData = weld::fromId<FmFilterData*>(m_xTreeView->get_id(rIter));
+
+ DBG_ASSERT(dynamic_cast<const FmFilterItem*>(pData) != nullptr,
+ "FmFilterNavigator::EditedEntry() wrong entry");
+
+ OUString aText(comphelper::string::strip(rNewText, ' '));
+ if (aText.isEmpty())
+ {
+ // deleting the entry asynchron
+ m_nAsyncRemoveEvent = Application::PostUserEvent(LINK(this, FmFilterNavigator, OnRemove), pData);
+ }
+ else
+ {
+ OUString aErrorMsg;
+
+ if (m_pModel->ValidateText(static_cast<FmFilterItem*>(pData), aText, aErrorMsg))
+ {
+ // this will set the text at the FmFilterItem, as well as update any filter controls
+ // which are connected to this particular entry
+ m_pModel->SetTextForItem(static_cast<FmFilterItem*>(pData), aText);
+ m_xTreeView->set_text(rIter, aText);
+ }
+ else
+ {
+ // display the error and return sal_False
+ SQLContext aError;
+ aError.Message = SvxResId(RID_STR_SYNTAXERROR);
+ aError.Details = aErrorMsg;
+ displayException(aError, VCLUnoHelper::GetInterface(m_xTopLevel));
+
+ return false;
+ }
+ }
+ return true;
+}
+
+IMPL_LINK( FmFilterNavigator, OnRemove, void*, p, void )
+{
+ m_nAsyncRemoveEvent = nullptr;
+ // now remove the entry
+ m_pModel->Remove(static_cast<FmFilterData*>(p));
+}
+
+sal_Int8 FmFilterNavigator::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ if (!m_aControlExchange.isDragSource())
+ return DND_ACTION_NONE;
+
+ if (!OFilterItemExchange::hasFormat(m_aDropTargetHelper.GetDataFlavorExVector()))
+ return DND_ACTION_NONE;
+
+ // do we contain the formitem?
+ if (!FindEntry(m_aControlExchange->getFormItem()))
+ return DND_ACTION_NONE;
+
+ Point aDropPos = rEvt.maPosPixel;
+ std::unique_ptr<weld::TreeIter> xDropTarget(m_xTreeView->make_iterator());
+ // get_dest_row_at_pos with false cause we must drop exactly "on" a node to paste a condition into it
+ if (!m_xTreeView->get_dest_row_at_pos(aDropPos, xDropTarget.get(), false))
+ xDropTarget.reset();
+
+ if (!xDropTarget)
+ return DND_ACTION_NONE;
+
+ FmFilterData* pData = weld::fromId<FmFilterData*>(m_xTreeView->get_id(*xDropTarget));
+ FmFormItem* pForm = nullptr;
+ if (dynamic_cast<const FmFilterItem*>(pData) != nullptr)
+ {
+ pForm = dynamic_cast<FmFormItem*>( pData->GetParent()->GetParent() );
+ if (pForm != m_aControlExchange->getFormItem())
+ return DND_ACTION_NONE;
+ }
+ else if (dynamic_cast<const FmFilterItems*>( pData) != nullptr)
+ {
+ pForm = dynamic_cast<FmFormItem*>( pData->GetParent() );
+ if (pForm != m_aControlExchange->getFormItem())
+ return DND_ACTION_NONE;
+ }
+ else
+ return DND_ACTION_NONE;
+
+ return rEvt.mnAction;
+}
+
+namespace
+{
+ FmFilterItems* getTargetItems(const weld::TreeView& rTreeView, const weld::TreeIter& rTarget)
+ {
+ FmFilterData* pData = weld::fromId<FmFilterData*>(rTreeView.get_id(rTarget));
+ FmFilterItems* pTargetItems = dynamic_cast<FmFilterItems*>(pData);
+ if (!pTargetItems)
+ pTargetItems = dynamic_cast<FmFilterItems*>(pData->GetParent());
+ return pTargetItems;
+ }
+}
+
+sal_Int8 FmFilterNavigator::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ if (!m_aControlExchange.isDragSource())
+ return DND_ACTION_NONE;
+
+ Point aDropPos = rEvt.maPosPixel;
+ std::unique_ptr<weld::TreeIter> xDropTarget(m_xTreeView->make_iterator());
+ // get_dest_row_at_pos with false cause we must drop exactly "on" a node to paste a condition into it
+ if (!m_xTreeView->get_dest_row_at_pos(aDropPos, xDropTarget.get(), false))
+ xDropTarget.reset();
+ if (!xDropTarget)
+ return DND_ACTION_NONE;
+
+ // search the container where to add the items
+ FmFilterItems* pTargetItems = getTargetItems(*m_xTreeView, *xDropTarget);
+ m_xTreeView->unselect_all();
+ std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pTargetItems);
+ if (xEntry)
+ {
+ m_xTreeView->select(*xEntry);
+ m_xTreeView->set_cursor(*xEntry);
+ }
+
+ insertFilterItem(m_aControlExchange->getDraggedEntries(),pTargetItems,DND_ACTION_COPY == rEvt.mnAction);
+
+ return DND_ACTION_COPY;
+}
+
+IMPL_LINK_NOARG(FmFilterNavigator, SelectHdl, weld::TreeView&, void)
+{
+ std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_selected(xIter.get()))
+ return;
+
+ FmFilterData* pData = weld::fromId<FmFilterData*>(m_xTreeView->get_id(*xIter));
+
+ FmFormItem* pFormItem = nullptr;
+ if (FmFilterItem* pItem = dynamic_cast<FmFilterItem*>(pData))
+ pFormItem = static_cast<FmFormItem*>(pItem->GetParent()->GetParent());
+ else if (FmFilterItems* pItems = dynamic_cast<FmFilterItems*>(pData))
+ pFormItem = static_cast<FmFormItem*>(pItems->GetParent()->GetParent());
+ else
+ pFormItem = dynamic_cast<FmFormItem*>(pData);
+
+ if (pFormItem)
+ {
+ // will the controller be exchanged?
+ if (FmFilterItem* pItem = dynamic_cast<FmFilterItem*>(pData))
+ m_pModel->SetCurrentItems(static_cast<FmFilterItems*>(pItem->GetParent()));
+ else if (FmFilterItems* pItems = dynamic_cast<FmFilterItems*>(pData))
+ m_pModel->SetCurrentItems(pItems);
+ else
+ m_pModel->SetCurrentController(pFormItem->GetController());
+ }
+}
+
+void FmFilterNavigator::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+{
+ if (const FmFilterInsertedHint* pInsertHint = dynamic_cast<const FmFilterInsertedHint*>(&rHint))
+ {
+ Insert(pInsertHint->GetData(), pInsertHint->GetPos());
+ }
+ else if( dynamic_cast<const FilterClearingHint*>(&rHint) )
+ {
+ m_xTreeView->clear();
+ }
+ else if (const FmFilterRemovedHint* pRemoveHint = dynamic_cast<const FmFilterRemovedHint*>(&rHint))
+ {
+ Remove(pRemoveHint->GetData());
+ }
+ else if (const FmFilterTextChangedHint *pChangeHint = dynamic_cast<const FmFilterTextChangedHint*>(&rHint))
+ {
+ std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pChangeHint->GetData());
+ if (xEntry)
+ m_xTreeView->set_text(*xEntry, pChangeHint->GetData()->GetText());
+ }
+ else if( dynamic_cast<const FmFilterCurrentChangedHint*>(&rHint) )
+ {
+ m_xTreeView->queue_draw();
+ }
+}
+
+std::unique_ptr<weld::TreeIter> FmFilterNavigator::FindEntry(const FmFilterData* pItem) const
+{
+ if (!pItem)
+ return nullptr;
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ if (!m_xTreeView->get_iter_first(*xEntry))
+ return nullptr;
+ do
+ {
+ FmFilterData* pEntryItem = weld::fromId<FmFilterData*>(m_xTreeView->get_id(*xEntry));
+ if (pEntryItem == pItem)
+ return xEntry;
+ }
+ while (m_xTreeView->iter_next(*xEntry));
+
+ return nullptr;
+}
+
+void FmFilterNavigator::Insert(const FmFilterData* pItem, int nPos)
+{
+ const FmParentData* pParent = pItem->GetParent() ? pItem->GetParent() : m_pModel.get();
+
+ // insert the item
+ std::unique_ptr<weld::TreeIter> xParentEntry = FindEntry(pParent);
+
+ OUString sId(weld::toId(pItem));
+ std::unique_ptr<weld::TreeIter> xRet(m_xTreeView->make_iterator());
+ m_xTreeView->insert(xParentEntry.get(), nPos, &pItem->GetText(), &sId,
+ nullptr, nullptr, false, xRet.get());
+ m_xTreeView->set_image(*xRet, pItem->GetImage());
+
+ if (!xParentEntry)
+ return;
+ m_xTreeView->expand_row(*xParentEntry);
+}
+
+void FmFilterNavigator::EndEditing()
+{
+ if (m_xEditingCurrently)
+ {
+ // end editing
+ m_xTreeView->end_editing();
+ m_xEditingCurrently.reset();
+ }
+}
+
+void FmFilterNavigator::Remove(FmFilterData const * pItem)
+{
+ // the entry for the data
+ std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pItem);
+ if (!xEntry)
+ return;
+
+ if (m_xEditingCurrently && m_xTreeView->iter_compare(*xEntry, *m_xEditingCurrently) == 0)
+ EndEditing();
+
+ m_xTreeView->remove(*xEntry);
+}
+
+FmFormItem* FmFilterNavigator::getSelectedFilterItems(::std::vector<FmFilterItem*>& _rItemList)
+{
+ // be sure that the data is only used within only one form!
+ FmFormItem* pFirstItem = nullptr;
+
+ bool bHandled = true;
+ bool bFoundSomething = false;
+
+ m_xTreeView->selected_foreach([this, &bHandled, &bFoundSomething, &pFirstItem, &_rItemList](weld::TreeIter& rEntry) {
+ FmFilterData* pFilterEntry = weld::fromId<FmFilterData*>(m_xTreeView->get_id(rEntry));
+ FmFilterItem* pFilter = dynamic_cast<FmFilterItem*>(pFilterEntry);
+ if (pFilter)
+ {
+ FmFormItem* pForm = dynamic_cast<FmFormItem*>( pFilter->GetParent()->GetParent() );
+ if (!pForm)
+ bHandled = false;
+ else if (!pFirstItem)
+ pFirstItem = pForm;
+ else if (pFirstItem != pForm)
+ bHandled = false;
+
+ if (bHandled)
+ {
+ _rItemList.push_back(pFilter);
+ bFoundSomething = true;
+ }
+ }
+ return !bHandled;
+ });
+
+ if ( !bHandled || !bFoundSomething )
+ pFirstItem = nullptr;
+ return pFirstItem;
+}
+
+void FmFilterNavigator::insertFilterItem(const ::std::vector<FmFilterItem*>& _rFilterList,FmFilterItems* _pTargetItems,bool _bCopy)
+{
+ for (FmFilterItem* pLookupItem : _rFilterList)
+ {
+ if ( pLookupItem->GetParent() == _pTargetItems )
+ continue;
+
+ FmFilterItem* pFilterItem = _pTargetItems->Find( pLookupItem->GetComponentIndex() );
+ OUString aText = pLookupItem->GetText();
+ if ( !pFilterItem )
+ {
+ pFilterItem = new FmFilterItem( _pTargetItems, pLookupItem->GetFieldName(), aText, pLookupItem->GetComponentIndex() );
+ m_pModel->Append( _pTargetItems, std::unique_ptr<FmFilterItem>(pFilterItem) );
+ }
+
+ if ( !_bCopy )
+ m_pModel->Remove( pLookupItem );
+
+ // now set the text for the new dragged item
+ m_pModel->SetTextForItem( pFilterItem, aText );
+ }
+
+ m_pModel->EnsureEmptyFilterRows( *_pTargetItems->GetParent() );
+}
+
+IMPL_LINK(FmFilterNavigator, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+{
+ rUnsetDragIcon = false;
+
+ // be sure that the data is only used within an only one form!
+ m_aControlExchange.prepareDrag();
+
+ ::std::vector<FmFilterItem*> aItemList;
+ if (FmFormItem* pFirstItem = getSelectedFilterItems(aItemList))
+ {
+ m_aControlExchange->setDraggedEntries(std::move(aItemList));
+ m_aControlExchange->setFormItem(pFirstItem);
+
+ OFilterItemExchange& rExchange = *m_aControlExchange;
+ rtl::Reference<TransferDataContainer> xHelper(&rExchange);
+ m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPYMOVE);
+ rExchange.setDragging(true);
+
+ return false;
+ }
+ return true;
+}
+
+IMPL_LINK(FmFilterNavigator, PopupMenuHdl, const CommandEvent&, rEvt, bool)
+{
+ bool bHandled = false;
+ switch (rEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ // the place where it was clicked
+ Point aWhere;
+ std::unique_ptr<weld::TreeIter> xClicked(m_xTreeView->make_iterator());
+ if (rEvt.IsMouseEvent())
+ {
+ aWhere = rEvt.GetMousePosPixel();
+ if (!m_xTreeView->get_dest_row_at_pos(aWhere, xClicked.get(), false))
+ break;
+
+ if (!m_xTreeView->is_selected(*xClicked))
+ {
+ m_xTreeView->unselect_all();
+ m_xTreeView->select(*xClicked);
+ m_xTreeView->set_cursor(*xClicked);
+ }
+ }
+ else
+ {
+ if (!m_xTreeView->get_cursor(xClicked.get()))
+ break;
+ aWhere = m_xTreeView->get_row_area(*xClicked).Center();
+ }
+
+ ::std::vector<FmFilterData*> aSelectList;
+ m_xTreeView->selected_foreach([this, &aSelectList](weld::TreeIter& rEntry) {
+ FmFilterData* pFilterEntry = weld::fromId<FmFilterData*>(m_xTreeView->get_id(rEntry));
+
+ // don't delete forms
+ FmFormItem* pForm = dynamic_cast<FmFormItem*>(pFilterEntry);
+ if (!pForm)
+ aSelectList.push_back(pFilterEntry);
+
+ return false;
+ });
+
+ if (aSelectList.size() == 1)
+ {
+ // don't delete the only empty row of a form
+ FmFilterItems* pFilterItems = dynamic_cast<FmFilterItems*>( aSelectList[0] );
+ if (pFilterItems && pFilterItems->GetChildren().empty()
+ && pFilterItems->GetParent()->GetChildren().size() == 1)
+ aSelectList.clear();
+ }
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "svx/ui/filtermenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+
+ // every condition could be deleted except the first one if it's the only one
+ bool bNoDelete = false;
+ if (aSelectList.empty())
+ {
+ bNoDelete = true;
+ xContextMenu->remove("delete");
+ }
+
+ FmFilterData* pFilterEntry = weld::fromId<FmFilterData*>(m_xTreeView->get_id(*xClicked));
+ auto pFilterItem = dynamic_cast<FmFilterItem*>(pFilterEntry);
+ bool bEdit = pFilterItem &&
+ m_xTreeView->is_selected(*xClicked) && m_xTreeView->count_selected_rows() == 1;
+
+ if (bNoDelete && !bEdit)
+ {
+ // nothing is in the menu, don't bother
+ return true;
+ }
+
+ if (!bEdit)
+ {
+ xContextMenu->remove("edit");
+ xContextMenu->remove("isnull");
+ xContextMenu->remove("isnotnull");
+ }
+
+ OString sIdent = xContextMenu->popup_at_rect(m_xTreeView.get(), tools::Rectangle(aWhere, ::Size(1, 1)));
+ if (sIdent == "edit")
+ {
+ m_xTreeView->start_editing(*xClicked);
+ }
+ else if (sIdent == "isnull")
+ {
+ OUString aErrorMsg;
+ OUString aText = "IS NULL";
+ assert(pFilterItem && "if item is null this menu entry was removed and unavailable");
+ m_pModel->ValidateText(pFilterItem, aText, aErrorMsg);
+ m_pModel->SetTextForItem(pFilterItem, aText);
+ }
+ else if (sIdent == "isnotnull")
+ {
+ OUString aErrorMsg;
+ OUString aText = "IS NOT NULL";
+
+ assert(pFilterItem && "if item is null this menu entry was removed and unavailable");
+ m_pModel->ValidateText(pFilterItem, aText, aErrorMsg);
+ m_pModel->SetTextForItem(pFilterItem, aText);
+ }
+ else if (sIdent == "delete")
+ {
+ DeleteSelection();
+ }
+ bHandled = true;
+ }
+ break;
+ default: break;
+ }
+
+ return bHandled;
+}
+
+bool FmFilterNavigator::getNextEntry(weld::TreeIter& rEntry)
+{
+ bool bEntry = m_xTreeView->iter_next(rEntry);
+ // we need the next filter entry
+ if (bEntry)
+ {
+ while (!m_xTreeView->iter_has_child(rEntry))
+ {
+ std::unique_ptr<weld::TreeIter> xNext = m_xTreeView->make_iterator(&rEntry);
+ if (!m_xTreeView->iter_next(*xNext))
+ break;
+ m_xTreeView->copy_iterator(*xNext, rEntry);
+ }
+ }
+ return bEntry;
+}
+
+bool FmFilterNavigator::getPrevEntry(weld::TreeIter& rEntry)
+{
+ bool bEntry = m_xTreeView->iter_previous(rEntry);
+ // check if the previous entry is a filter, if so get the next prev
+ if (bEntry && m_xTreeView->iter_has_child(rEntry))
+ {
+ bEntry = m_xTreeView->iter_previous(rEntry);
+ // if the entry is still no leaf return
+ if (bEntry && m_xTreeView->iter_has_child(rEntry))
+ bEntry = false;
+ }
+ return bEntry;
+}
+IMPL_LINK(FmFilterNavigator, KeyInputHdl, const ::KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+
+ switch ( rKeyCode.GetCode() )
+ {
+ case KEY_UP:
+ case KEY_DOWN:
+ {
+ if ( !rKeyCode.IsMod1() || !rKeyCode.IsMod2() || rKeyCode.IsShift() )
+ break;
+
+ ::std::vector<FmFilterItem*> aItemList;
+ if ( !getSelectedFilterItems( aItemList ) )
+ break;
+
+
+ std::vector<std::unique_ptr<weld::TreeIter>> aSelected;
+ m_xTreeView->selected_foreach([this, &aSelected](weld::TreeIter& rEntry){
+ aSelected.emplace_back(m_xTreeView->make_iterator(&rEntry));
+ return false;
+ });
+
+ std::unique_ptr<weld::TreeIter> xTarget;
+ ::std::function<bool(FmFilterNavigator*, weld::TreeIter&)> getter;
+
+ if (rKeyCode.GetCode() == KEY_UP)
+ {
+ xTarget = m_xTreeView->make_iterator(aSelected.front().get());
+ getter = ::std::mem_fn(&FmFilterNavigator::getPrevEntry);
+ }
+ else
+ {
+ xTarget = m_xTreeView->make_iterator(aSelected.back().get());
+ getter = ::std::mem_fn(&FmFilterNavigator::getNextEntry);
+ }
+
+ bool bTarget = getter(this, *xTarget);
+ if (!bTarget)
+ break;
+
+ FmFilterItems* pTargetItems = getTargetItems(*m_xTreeView, *xTarget);
+ if (!pTargetItems)
+ break;
+
+ ::std::vector<FmFilterItem*>::const_iterator aEnd = aItemList.end();
+ bool bNextTargetItem = true;
+ while ( bNextTargetItem )
+ {
+ ::std::vector<FmFilterItem*>::const_iterator i = aItemList.begin();
+ for (; i != aEnd; ++i)
+ {
+ if ( (*i)->GetParent() == pTargetItems )
+ {
+ bTarget = getter(this, *xTarget);
+ if (!bTarget)
+ return true;
+ pTargetItems = getTargetItems(*m_xTreeView, *xTarget);
+ break;
+ }
+ else
+ {
+ FmFilterItem* pFilterItem = pTargetItems->Find( (*i)->GetComponentIndex() );
+ // we found the text component so jump above
+ if ( pFilterItem )
+ {
+ bTarget = getter(this, *xTarget);
+ if (!bTarget)
+ return true;
+
+ pTargetItems = getTargetItems(*m_xTreeView, *xTarget);
+ break;
+ }
+ }
+ }
+ bNextTargetItem = i != aEnd && pTargetItems;
+ }
+
+ if ( pTargetItems )
+ {
+ insertFilterItem( aItemList, pTargetItems, false );
+ return true;
+ }
+ }
+ break;
+
+ case KEY_DELETE:
+ {
+ if ( rKeyCode.GetModifier() )
+ break;
+
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ if (m_xTreeView->get_iter_first(*xEntry) && !m_xTreeView->is_selected(*xEntry))
+ DeleteSelection();
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void FmFilterNavigator::DeleteSelection()
+{
+ // to avoid the deletion of an entry twice (e.g. deletion of a parent and afterward
+ // the deletion of its child, I have to shrink the selection list
+ std::vector<FmFilterData*> aEntryList;
+
+ m_xTreeView->selected_foreach([this, &aEntryList](weld::TreeIter& rEntry) {
+ FmFilterData* pFilterEntry = weld::fromId<FmFilterData*>(m_xTreeView->get_id(rEntry));
+
+ if (dynamic_cast<FmFilterItem*>(pFilterEntry))
+ {
+ std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
+ if (m_xTreeView->iter_parent(*xParent) && m_xTreeView->is_selected(*xParent))
+ return false;
+ }
+
+ FmFormItem* pForm = dynamic_cast<FmFormItem*>(pFilterEntry);
+ if (!pForm)
+ aEntryList.emplace_back(pFilterEntry);
+
+ return false;
+ });
+
+ // Remove the selection
+ m_xTreeView->unselect_all();
+
+ for (auto i = aEntryList.rbegin(); i != aEntryList.rend(); ++i)
+ m_pModel->Remove(*i);
+}
+
+FmFilterNavigatorWin::FmFilterNavigatorWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr,
+ vcl::Window* _pParent)
+ : SfxDockingWindow(_pBindings, _pMgr, _pParent, "FilterNavigator", "svx/ui/filternavigator.ui")
+ , SfxControllerItem( SID_FM_FILTER_NAVIGATOR_CONTROL, *_pBindings )
+ , m_xNavigatorTree(new FmFilterNavigator(this, m_xBuilder->weld_tree_view("treeview")))
+{
+ SetHelpId( HID_FILTER_NAVIGATOR_WIN );
+
+ SetText( SvxResId(RID_STR_FILTER_NAVIGATOR) );
+ SfxDockingWindow::SetFloatingSize( Size(200,200) );
+}
+
+FmFilterNavigatorWin::~FmFilterNavigatorWin()
+{
+ disposeOnce();
+}
+
+void FmFilterNavigatorWin::dispose()
+{
+ m_xNavigatorTree.reset();
+ ::SfxControllerItem::dispose();
+ SfxDockingWindow::dispose();
+}
+
+void FmFilterNavigatorWin::UpdateContent(FmFormShell const * pFormShell)
+{
+ if (!m_xNavigatorTree)
+ return;
+
+ if (!pFormShell)
+ m_xNavigatorTree->UpdateContent( nullptr, nullptr );
+ else
+ {
+ Reference<XFormController> const xController(pFormShell->GetImpl()->getActiveInternalController_Lock());
+ Reference< XIndexAccess > xContainer;
+ if (xController.is())
+ {
+ Reference< XChild > xChild = xController;
+ for (Reference< XInterface > xParent(xChild->getParent());
+ xParent.is();
+ xParent = xChild.is() ? xChild->getParent() : Reference< XInterface > ())
+ {
+ xContainer.set(xParent, UNO_QUERY);
+ xChild.set(xParent, UNO_QUERY);
+ }
+ }
+ m_xNavigatorTree->UpdateContent(xContainer, xController);
+ }
+}
+
+void FmFilterNavigatorWin::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
+{
+ if( !pState || SID_FM_FILTER_NAVIGATOR_CONTROL != nSID )
+ return;
+
+ if( eState >= SfxItemState::DEFAULT )
+ {
+ FmFormShell* pShell = dynamic_cast<FmFormShell*>( static_cast<const SfxObjectItem*>(pState)->GetShell() );
+ UpdateContent( pShell );
+ }
+ else
+ UpdateContent( nullptr );
+}
+
+bool FmFilterNavigatorWin::Close()
+{
+ if (m_xNavigatorTree)
+ m_xNavigatorTree->EndEditing();
+
+ UpdateContent( nullptr );
+ return SfxDockingWindow::Close();
+}
+
+void FmFilterNavigatorWin::FillInfo( SfxChildWinInfo& rInfo ) const
+{
+ SfxDockingWindow::FillInfo( rInfo );
+ rInfo.bVisible = false;
+}
+
+Size FmFilterNavigatorWin::CalcDockingSize( SfxChildAlignment eAlign )
+{
+ if ( ( eAlign == SfxChildAlignment::TOP ) || ( eAlign == SfxChildAlignment::BOTTOM ) )
+ return Size();
+
+ return SfxDockingWindow::CalcDockingSize( eAlign );
+}
+
+SfxChildAlignment FmFilterNavigatorWin::CheckAlignment( SfxChildAlignment eActAlign, SfxChildAlignment eAlign )
+{
+ switch (eAlign)
+ {
+ case SfxChildAlignment::LEFT:
+ case SfxChildAlignment::RIGHT:
+ case SfxChildAlignment::NOALIGNMENT:
+ return eAlign;
+ default:
+ break;
+ }
+
+ return eActAlign;
+}
+
+void FmFilterNavigatorWin::GetFocus()
+{
+ // oj #97405#
+ if (m_xNavigatorTree)
+ m_xNavigatorTree->GrabFocus();
+ else
+ SfxDockingWindow::GetFocus();
+}
+
+SFX_IMPL_DOCKINGWINDOW( FmFilterNavigatorWinMgr, SID_FM_FILTER_NAVIGATOR )
+
+
+FmFilterNavigatorWinMgr::FmFilterNavigatorWinMgr( vcl::Window *_pParent, sal_uInt16 _nId,
+ SfxBindings *_pBindings, SfxChildWinInfo* _pInfo )
+ :SfxChildWindow( _pParent, _nId )
+{
+ SetWindow( VclPtr<FmFilterNavigatorWin>::Create( _pBindings, this, _pParent ) );
+ static_cast<SfxDockingWindow*>(GetWindow())->Initialize( _pInfo );
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmPropBrw.cxx b/svx/source/form/fmPropBrw.cxx
new file mode 100644
index 000000000..1b24f9703
--- /dev/null
+++ b/svx/source/form/fmPropBrw.cxx
@@ -0,0 +1,581 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sal/macros.h>
+
+#include <fmprop.hxx>
+#include <fmPropBrw.hxx>
+#include <svx/strings.hrc>
+#include <fmservs.hxx>
+#include <fmshimp.hxx>
+#include <fmpgeimp.hxx>
+
+#include <svx/dialmgr.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/fmview.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svxids.hrc>
+
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/form/inspection/DefaultFormComponentInspectorModel.hpp>
+#include <com/sun/star/frame/Frame.hpp>
+#include <com/sun/star/inspection/ObjectInspector.hpp>
+#include <com/sun/star/inspection/XObjectInspectorUI.hpp>
+#include <com/sun/star/inspection/DefaultHelpProvider.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/util/VetoException.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/component_context.hxx>
+#include <o3tl/deleter.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/objitem.hxx>
+#include <sfx2/objsh.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/confignode.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::form::inspection;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::inspection;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::svxform;
+using ::com::sun::star::awt::XWindow;
+
+//= FmPropBrwMgr
+SFX_IMPL_MODELESSDIALOGCONTOLLER(FmPropBrwMgr, SID_FM_SHOW_PROPERTIES)
+
+FmPropBrwMgr::FmPropBrwMgr( vcl::Window* _pParent, sal_uInt16 _nId,
+ SfxBindings* _pBindings, const SfxChildWinInfo* _pInfo)
+ :SfxChildWindow(_pParent, _nId)
+{
+ std::shared_ptr<FmPropBrw> xControl(new FmPropBrw(::comphelper::getProcessComponentContext(), _pBindings,
+ this, _pParent->GetFrameWeld(), _pInfo), o3tl::default_delete<FmPropBrw>());
+ SetController(std::move(xControl));
+ static_cast<FmPropBrw*>(GetController().get())->Initialize( _pInfo );
+}
+
+static OUString GetUIHeadlineName(sal_Int16 nClassId, const Any& aUnoObj)
+{
+ TranslateId pClassNameResourceId;
+
+ switch ( nClassId )
+ {
+ case FormComponentType::TEXTFIELD:
+ {
+ Reference< XInterface > xIFace;
+ aUnoObj >>= xIFace;
+ pClassNameResourceId = RID_STR_PROPTITLE_EDIT;
+ if (xIFace.is())
+ { // we have a chance to check if it's a formatted field model
+ Reference< XServiceInfo > xInfo(xIFace, UNO_QUERY);
+ if (xInfo.is() && (xInfo->supportsService(FM_SUN_COMPONENT_FORMATTEDFIELD)))
+ pClassNameResourceId = RID_STR_PROPTITLE_FORMATTED;
+ else if (!xInfo.is())
+ {
+ // couldn't distinguish between formatted and edit with the service name, so try with the properties
+ Reference< XPropertySet > xProps(xIFace, UNO_QUERY);
+ if (xProps.is())
+ {
+ Reference< XPropertySetInfo > xPropsInfo = xProps->getPropertySetInfo();
+ if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(FM_PROP_FORMATSSUPPLIER))
+ pClassNameResourceId = RID_STR_PROPTITLE_FORMATTED;
+ }
+ }
+ }
+ }
+ break;
+
+ case FormComponentType::COMMANDBUTTON:
+ pClassNameResourceId = RID_STR_PROPTITLE_PUSHBUTTON; break;
+ case FormComponentType::RADIOBUTTON:
+ pClassNameResourceId = RID_STR_PROPTITLE_RADIOBUTTON; break;
+ case FormComponentType::CHECKBOX:
+ pClassNameResourceId = RID_STR_PROPTITLE_CHECKBOX; break;
+ case FormComponentType::LISTBOX:
+ pClassNameResourceId = RID_STR_PROPTITLE_LISTBOX; break;
+ case FormComponentType::COMBOBOX:
+ pClassNameResourceId = RID_STR_PROPTITLE_COMBOBOX; break;
+ case FormComponentType::GROUPBOX:
+ pClassNameResourceId = RID_STR_PROPTITLE_GROUPBOX; break;
+ case FormComponentType::IMAGEBUTTON:
+ pClassNameResourceId = RID_STR_PROPTITLE_IMAGEBUTTON; break;
+ case FormComponentType::FIXEDTEXT:
+ pClassNameResourceId = RID_STR_PROPTITLE_FIXEDTEXT; break;
+ case FormComponentType::GRIDCONTROL:
+ pClassNameResourceId = RID_STR_PROPTITLE_DBGRID; break;
+ case FormComponentType::FILECONTROL:
+ pClassNameResourceId = RID_STR_PROPTITLE_FILECONTROL; break;
+ case FormComponentType::DATEFIELD:
+ pClassNameResourceId = RID_STR_PROPTITLE_DATEFIELD; break;
+ case FormComponentType::TIMEFIELD:
+ pClassNameResourceId = RID_STR_PROPTITLE_TIMEFIELD; break;
+ case FormComponentType::NUMERICFIELD:
+ pClassNameResourceId = RID_STR_PROPTITLE_NUMERICFIELD; break;
+ case FormComponentType::CURRENCYFIELD:
+ pClassNameResourceId = RID_STR_PROPTITLE_CURRENCYFIELD; break;
+ case FormComponentType::PATTERNFIELD:
+ pClassNameResourceId = RID_STR_PROPTITLE_PATTERNFIELD; break;
+ case FormComponentType::IMAGECONTROL:
+ pClassNameResourceId = RID_STR_PROPTITLE_IMAGECONTROL; break;
+ case FormComponentType::HIDDENCONTROL:
+ pClassNameResourceId = RID_STR_PROPTITLE_HIDDEN; break;
+ case FormComponentType::SCROLLBAR:
+ pClassNameResourceId = RID_STR_PROPTITLE_SCROLLBAR; break;
+ case FormComponentType::SPINBUTTON:
+ pClassNameResourceId = RID_STR_PROPTITLE_SPINBUTTON; break;
+ case FormComponentType::NAVIGATIONBAR:
+ pClassNameResourceId = RID_STR_PROPTITLE_NAVBAR; break;
+ case FormComponentType::CONTROL:
+ default:
+ pClassNameResourceId = RID_STR_CONTROL; break;
+ }
+
+ return SvxResId(pClassNameResourceId);
+}
+
+FmPropBrw::FmPropBrw(const Reference< XComponentContext >& _xORB, SfxBindings* _pBindings,
+ SfxChildWindow* _pMgr, weld::Window* _pParent, const SfxChildWinInfo* _pInfo)
+ : SfxModelessDialogController(_pBindings, _pMgr, _pParent, "svx/ui/formpropertydialog.ui", "FormPropertyDialog")
+ , SfxControllerItem(SID_FM_PROPERTY_CONTROL, *_pBindings)
+ , m_bInitialStateChange(true)
+ , m_pParent(_pParent)
+ , m_nAsyncGetFocusId(nullptr)
+ , m_xContainer(m_xBuilder->weld_container("container"))
+ , m_xORB(_xORB)
+{
+ m_xContainer->set_size_request(m_xContainer->get_approximate_digit_width() * 72, m_xContainer->get_text_height() * 20);
+
+ try
+ {
+ // create a frame wrapper for myself
+ m_xMeAsFrame = Frame::create(m_xORB);
+
+ // transport the container area of this dialog to be the container window of the frame
+ css::uno::Reference<css::awt::XWindow> xFrameContainerWindow(new weld::TransportAsXWindow(m_xContainer.get()));
+ m_xMeAsFrame->initialize(xFrameContainerWindow);
+ m_xMeAsFrame->setName("form property browser");
+ }
+ catch (const Exception&)
+ {
+ OSL_FAIL("FmPropBrw::FmPropBrw: could not create/initialize my frame!");
+ m_xMeAsFrame.clear();
+ }
+
+ if ( _pInfo )
+ m_sLastActivePage = _pInfo->aExtraString;
+}
+
+FmPropBrw::~FmPropBrw()
+{
+ if (m_nAsyncGetFocusId)
+ {
+ Application::RemoveUserEvent(m_nAsyncGetFocusId);
+ m_nAsyncGetFocusId = nullptr;
+ }
+
+ if (m_xBrowserController.is())
+ implDetachController();
+ try
+ {
+ // remove our own properties from the component context. We cannot ensure that the component context
+ // is freed (there might be refcount problems :-\), so at least ensure the context itself
+ // does hold the objects anymore
+ Reference<XNameContainer> xName(m_xInspectorContext,uno::UNO_QUERY);
+ if ( xName.is() )
+ {
+ const OUString pProps[] = { OUString( "ContextDocument" )
+ , OUString( "DialogParentWindow" )
+ , OUString( "ControlContext" )
+ , OUString( "ControlShapeAccess" ) };
+ for (const auto & i : pProps)
+ xName->removeByName( i );
+ }
+ }
+ catch (const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ ::SfxControllerItem::dispose();
+}
+
+OUString FmPropBrw::getCurrentPage() const
+{
+ OUString sCurrentPage;
+ try
+ {
+ if ( m_xBrowserController.is() )
+ {
+ OSL_VERIFY( m_xBrowserController->getViewData() >>= sCurrentPage );
+ }
+
+ if ( sCurrentPage.isEmpty() )
+ sCurrentPage = m_sLastActivePage;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while retrieving the current page!");
+ }
+ return sCurrentPage;
+}
+
+void FmPropBrw::implDetachController()
+{
+ m_sLastActivePage = getCurrentPage();
+
+ implSetNewSelection( InterfaceBag() );
+
+ if ( m_xMeAsFrame.is() )
+ {
+ try
+ {
+ m_xMeAsFrame->setComponent(nullptr, nullptr);
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while resetting the component!");
+ }
+ }
+
+ // we attached a frame to the controller manually, so we need to manually tell it that it's detached, too
+ if ( m_xBrowserController.is() )
+ {
+ m_xBrowserController->attachFrame( nullptr );
+ }
+
+ m_xBrowserController.clear();
+ m_xInspectorModel.clear();
+ m_xMeAsFrame.clear();
+}
+
+void FmPropBrw::Close()
+{
+ // suspend the controller (it is allowed to veto)
+ if ( m_xMeAsFrame.is() )
+ {
+ try
+ {
+ Reference< XController > xController( m_xMeAsFrame->getController() );
+ if ( xController.is() && !xController->suspend( true ) )
+ return;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while asking the controller!");
+ }
+ }
+
+ implDetachController();
+
+ // remember our bindings: while we're closed, we're deleted, too, so accessing the bindings after this
+ // would be deadly
+ // 10/19/00 - 79321 - FS
+ SfxBindings& rBindings = SfxControllerItem::GetBindings();
+
+ SfxModelessDialogController::Close();
+
+ rBindings.Invalidate(SID_FM_CTL_PROPERTIES);
+ rBindings.Invalidate(SID_FM_PROPERTIES);
+}
+
+bool FmPropBrw::implIsReadOnlyModel() const
+{
+ try
+ {
+ if ( m_xInspectorModel.is() )
+ return m_xInspectorModel->getIsReadOnly();
+ return false;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return true;
+}
+
+
+void FmPropBrw::implSetNewSelection( const InterfaceBag& _rSelection )
+{
+ if ( !m_xBrowserController.is() )
+ return;
+
+ try
+ {
+ Reference< XObjectInspector > xInspector( m_xBrowserController, UNO_QUERY_THROW );
+
+ // tell it the objects to inspect
+ xInspector->inspect( comphelper::containerToSequence(_rSelection) );
+ }
+ catch( const VetoException& )
+ {
+ return;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "");
+ return;
+ }
+
+ // set the new title according to the selected object
+ OUString sTitle;
+
+ if ( _rSelection.empty() )
+ {
+ sTitle = SvxResId(RID_STR_NO_PROPERTIES);
+ }
+ else if ( _rSelection.size() > 1 )
+ {
+ // no form component and (no form or no name) -> Multiselection
+ sTitle = SvxResId(RID_STR_PROPERTIES_CONTROL) +
+ SvxResId(RID_STR_PROPTITLE_MULTISELECT);
+ }
+ else
+ {
+ Reference< XPropertySet > xSingleSelection( *_rSelection.begin(), UNO_QUERY);
+ if ( ::comphelper::hasProperty( FM_PROP_CLASSID, xSingleSelection ) )
+ {
+ sal_Int16 nClassID = FormComponentType::CONTROL;
+ xSingleSelection->getPropertyValue( FM_PROP_CLASSID ) >>= nClassID;
+
+ sTitle = SvxResId(RID_STR_PROPERTIES_CONTROL) +
+ GetUIHeadlineName(nClassID, Any(xSingleSelection));
+ }
+ else if ( Reference< XForm >( xSingleSelection, UNO_QUERY ).is() )
+ sTitle = SvxResId(RID_STR_PROPERTIES_FORM);
+ }
+
+ if ( implIsReadOnlyModel() )
+ sTitle += SvxResId(RID_STR_READONLY_VIEW);
+
+ m_xDialog->set_title(sTitle);
+}
+
+void FmPropBrw::FillInfo( SfxChildWinInfo& rInfo ) const
+{
+ rInfo.bVisible = false;
+ rInfo.aExtraString = getCurrentPage();
+}
+
+IMPL_LINK_NOARG( FmPropBrw, OnAsyncGetFocus, void*, void )
+{
+ m_nAsyncGetFocusId = nullptr;
+}
+
+namespace
+{
+ bool lcl_shouldEnableHelpSection( const Reference< XComponentContext >& _rxContext )
+ {
+ ::utl::OConfigurationTreeRoot aConfiguration(
+ ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ _rxContext,
+ "/org.openoffice.Office.Common/Forms/PropertyBrowser/" ) );
+
+ bool bEnabled = false;
+ OSL_VERIFY( aConfiguration.getNodeValue( "DirectHelp" ) >>= bEnabled );
+ return bEnabled;
+ }
+}
+
+void FmPropBrw::impl_createPropertyBrowser_throw( FmFormShell* _pFormShell )
+{
+ // the document in which we live
+ Reference< XInterface > xDocument;
+ if ( _pFormShell && _pFormShell->GetObjectShell() )
+ xDocument = _pFormShell->GetObjectShell()->GetModel();
+
+ // the context of the controls in our document
+ Reference< awt::XControlContainer > xControlContext;
+ if ( _pFormShell && _pFormShell->GetFormView() )
+ {
+ SdrPageView* pPageView = _pFormShell->GetFormView()->GetSdrPageView();
+
+ if(pPageView)
+ {
+ SdrPageWindow* pPageWindow = pPageView->GetPageWindow(0);
+
+ if(pPageWindow)
+ {
+ xControlContext = pPageWindow->GetControlContainer();
+ }
+ }
+ }
+
+ // the default parent window for message boxes
+ Reference< XWindow > xParentWindow(m_xDialog->GetXWindow());
+
+ // the mapping from control models to control shapes
+ Reference< XMap > xControlMap;
+ FmFormPage* pFormPage = _pFormShell ? _pFormShell->GetCurPage() : nullptr;
+ if ( pFormPage )
+ xControlMap = pFormPage->GetImpl().getControlToShapeMap();
+
+ // our own component context
+
+ // a ComponentContext for the
+ ::cppu::ContextEntry_Init aHandlerContextInfo[] =
+ {
+ ::cppu::ContextEntry_Init( "ContextDocument", Any( xDocument ) ),
+ ::cppu::ContextEntry_Init( "DialogParentWindow", Any( xParentWindow ) ),
+ ::cppu::ContextEntry_Init( "ControlContext", Any( xControlContext ) ),
+ ::cppu::ContextEntry_Init( "ControlShapeAccess", Any( xControlMap ) )
+ };
+ m_xInspectorContext.set(
+ ::cppu::createComponentContext( aHandlerContextInfo, SAL_N_ELEMENTS( aHandlerContextInfo ),
+ m_xORB ) );
+
+ bool bEnableHelpSection = lcl_shouldEnableHelpSection( m_xORB );
+
+ // an object inspector model
+ m_xInspectorModel =
+ bEnableHelpSection
+ ? DefaultFormComponentInspectorModel::createWithHelpSection( m_xInspectorContext, 3, 5 )
+ : DefaultFormComponentInspectorModel::createDefault( m_xInspectorContext );
+
+ // an object inspector
+ m_xBrowserController =
+ ObjectInspector::createWithModel(
+ m_xInspectorContext, m_xInspectorModel
+ );
+
+ if ( !m_xBrowserController.is() )
+ {
+ ShowServiceNotAvailableError(m_pParent, u"com.sun.star.inspection.ObjectInspector", true);
+ }
+ else
+ {
+ m_xBrowserController->attachFrame( Reference<XFrame>(m_xMeAsFrame,UNO_QUERY_THROW) );
+ }
+
+ if ( bEnableHelpSection )
+ {
+ Reference< XObjectInspector > xInspector( m_xBrowserController, UNO_QUERY_THROW );
+ Reference< XObjectInspectorUI > xInspectorUI( xInspector->getInspectorUI() );
+ DefaultHelpProvider::create( m_xInspectorContext, xInspectorUI );
+ }
+}
+
+
+void FmPropBrw::impl_ensurePropertyBrowser_nothrow( FmFormShell* _pFormShell )
+{
+ // the document in which we live
+ Reference< XInterface > xDocument;
+ SfxObjectShell* pObjectShell = _pFormShell ? _pFormShell->GetObjectShell() : nullptr;
+ if ( pObjectShell )
+ xDocument = pObjectShell->GetModel();
+ if ( ( xDocument == m_xLastKnownDocument ) && m_xBrowserController.is() )
+ // nothing to do
+ return;
+
+ try
+ {
+ // clean up any previous instances of the object inspector
+ if ( m_xMeAsFrame.is() )
+ m_xMeAsFrame->setComponent( nullptr, nullptr );
+ else
+ ::comphelper::disposeComponent( m_xBrowserController );
+ m_xBrowserController.clear();
+ m_xInspectorModel.clear();
+
+ // and create a new one
+ impl_createPropertyBrowser_throw( _pFormShell );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ m_xLastKnownDocument = xDocument;
+}
+
+
+void FmPropBrw::StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
+{
+ if (!pState || SID_FM_PROPERTY_CONTROL != nSID)
+ return;
+
+ try
+ {
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ FmFormShell* pShell = dynamic_cast<FmFormShell*>( static_cast<const SfxObjectItem*>(pState)->GetShell() );
+ InterfaceBag aSelection;
+ if ( pShell )
+ pShell->GetImpl()->getCurrentSelection_Lock(aSelection);
+
+ impl_ensurePropertyBrowser_nothrow( pShell );
+
+ // set the new object to inspect
+ implSetNewSelection( aSelection );
+
+ // if this is the first time we're here, some additional things need to be done ...
+ if ( m_bInitialStateChange )
+ {
+ // if we're just newly created, we want to have the focus
+ m_nAsyncGetFocusId = Application::PostUserEvent(LINK(this, FmPropBrw, OnAsyncGetFocus));
+
+ // and additionally, we want to show the page which was active during
+ // our previous incarnation
+ if ( !m_sLastActivePage.isEmpty() )
+ {
+ try
+ {
+ if ( m_xBrowserController.is() )
+ m_xBrowserController->restoreViewData( Any( m_sLastActivePage ) );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.form",
+ "caught an exception while setting the initial page!");
+ }
+ }
+
+ m_bInitialStateChange = false;
+ }
+
+ }
+ else
+ {
+ implSetNewSelection( InterfaceBag() );
+ }
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "");
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmcontrolbordermanager.cxx b/svx/source/form/fmcontrolbordermanager.cxx
new file mode 100644
index 000000000..b46733995
--- /dev/null
+++ b/svx/source/form/fmcontrolbordermanager.cxx
@@ -0,0 +1,425 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <fmcontrolbordermanager.hxx>
+
+#include <fmprop.hxx>
+
+#include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
+#include <com/sun/star/awt/XTextComponent.hpp>
+#include <com/sun/star/awt/XListBox.hpp>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+
+
+namespace svxform
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::form::validation;
+
+
+ //= helper
+
+
+ static void setUnderline( const Reference< XVclWindowPeer >& _rxPeer, const UnderlineDescriptor& _rUnderline )
+ {
+ OSL_ENSURE( _rxPeer.is(), "setUnderline: invalid peer!" );
+
+ // the underline type is an aspect of the font
+ FontDescriptor aFont;
+ OSL_VERIFY( _rxPeer->getProperty( FM_PROP_FONT ) >>= aFont );
+ aFont.Underline = _rUnderline.nUnderlineType;
+ _rxPeer->setProperty( FM_PROP_FONT, Any( aFont ) );
+ // the underline color is a separate property
+ _rxPeer->setProperty( FM_PROP_TEXTLINECOLOR, Any( _rUnderline.nUnderlineColor ) );
+ }
+
+
+ static void getUnderline( const Reference< XVclWindowPeer >& _rxPeer, UnderlineDescriptor& _rUnderline )
+ {
+ OSL_ENSURE( _rxPeer.is(), "getUnderline: invalid peer!" );
+
+ FontDescriptor aFont;
+ OSL_VERIFY( _rxPeer->getProperty( FM_PROP_FONT ) >>= aFont );
+ _rUnderline.nUnderlineType = aFont.Underline;
+
+ OSL_VERIFY( _rxPeer->getProperty( FM_PROP_TEXTLINECOLOR ) >>= _rUnderline.nUnderlineColor );
+ }
+
+
+ static void getBorder( const Reference< XVclWindowPeer >& _rxPeer, BorderDescriptor& _rBorder )
+ {
+ OSL_ENSURE( _rxPeer.is(), "getBorder: invalid peer!" );
+
+ OSL_VERIFY( _rxPeer->getProperty( FM_PROP_BORDER ) >>= _rBorder.nBorderType );
+ OSL_VERIFY( _rxPeer->getProperty( FM_PROP_BORDERCOLOR ) >>= _rBorder.nBorderColor );
+ }
+
+
+ static void setBorder( const Reference< XVclWindowPeer >& _rxPeer, const BorderDescriptor& _rBorder )
+ {
+ OSL_ENSURE( _rxPeer.is(), "setBorder: invalid peer!" );
+
+ _rxPeer->setProperty( FM_PROP_BORDER, Any( _rBorder.nBorderType ) );
+ _rxPeer->setProperty( FM_PROP_BORDERCOLOR, Any( _rBorder.nBorderColor ) );
+ }
+
+ ControlBorderManager::ControlBorderManager()
+ :m_nFocusColor ( 0x000000FF )
+ ,m_nMouseHoveColor( 0x007098BE )
+ ,m_nInvalidColor ( 0x00FF0000 )
+ ,m_bDynamicBorderColors( false )
+ {
+ }
+
+
+ ControlBorderManager::~ControlBorderManager()
+ {
+ }
+
+
+ bool ControlBorderManager::canColorBorder( const Reference< XVclWindowPeer >& _rxPeer )
+ {
+ OSL_PRECOND( _rxPeer.is(), "ControlBorderManager::canColorBorder: invalid peer!" );
+
+ PeerBag::const_iterator aPos = m_aColorableControls.find( _rxPeer );
+ if ( aPos != m_aColorableControls.end() )
+ return true;
+
+ aPos = m_aNonColorableControls.find( _rxPeer );
+ if ( aPos != m_aNonColorableControls.end() )
+ return false;
+
+ // this peer is not yet known
+
+ // no border coloring for controls which are not for text input
+ // #i37434# / 2004-11-19 / frank.schoenheit@sun.com
+ Reference< XTextComponent > xText( _rxPeer, UNO_QUERY );
+ Reference< XListBox > xListBox( _rxPeer, UNO_QUERY );
+ if ( xText.is() || xListBox.is() )
+ {
+ sal_Int16 nBorderStyle = VisualEffect::NONE;
+ OSL_VERIFY( _rxPeer->getProperty( FM_PROP_BORDER ) >>= nBorderStyle );
+ if ( nBorderStyle == VisualEffect::FLAT )
+ // if you change this to also accept LOOK3D, then this would also work, but look ugly
+ {
+ m_aColorableControls.insert( _rxPeer );
+ return true;
+ }
+ }
+
+ m_aNonColorableControls.insert( _rxPeer );
+ return false;
+ }
+
+
+ ControlStatus ControlBorderManager::getControlStatus( const Reference< XControl >& _rxControl )
+ {
+ ControlStatus nStatus = ControlStatus::NONE;
+
+ if ( _rxControl.get() == m_aFocusControl.xControl.get() )
+ nStatus |= ControlStatus::Focused;
+
+ if ( _rxControl.get() == m_aMouseHoverControl.xControl.get() )
+ nStatus |= ControlStatus::MouseHover;
+
+ if ( m_aInvalidControls.find( ControlData( _rxControl ) ) != m_aInvalidControls.end() )
+ nStatus |= ControlStatus::Invalid;
+
+ return nStatus;
+ }
+
+
+ Color ControlBorderManager::getControlColorByStatus( ControlStatus _nStatus ) const
+ {
+ // "invalid" is ranked highest
+ if ( _nStatus & ControlStatus::Invalid )
+ return m_nInvalidColor;
+
+ // then, "focused" is more important than ...
+ if ( _nStatus & ControlStatus::Focused )
+ return m_nFocusColor;
+
+ // ... "mouse over"
+ if ( _nStatus & ControlStatus::MouseHover )
+ return m_nMouseHoveColor;
+
+ OSL_FAIL( "ControlBorderManager::getControlColorByStatus: invalid status!" );
+ return Color(0);
+ }
+
+
+ void ControlBorderManager::updateBorderStyle( const Reference< XControl >& _rxControl, const Reference< XVclWindowPeer >& _rxPeer, const BorderDescriptor& _rFallback )
+ {
+ OSL_PRECOND( _rxControl.is() && _rxPeer.is(), "ControlBorderManager::updateBorderStyle: invalid parameters!" );
+
+ ControlStatus nStatus = getControlStatus( _rxControl );
+ BorderDescriptor aBorder;
+ aBorder.nBorderType = ( nStatus == ControlStatus::NONE )
+ ? _rFallback.nBorderType
+ : VisualEffect::FLAT;
+ aBorder.nBorderColor = ( nStatus == ControlStatus::NONE )
+ ? _rFallback.nBorderColor
+ : getControlColorByStatus( nStatus );
+ setBorder( _rxPeer, aBorder );
+ }
+
+
+ void ControlBorderManager::determineOriginalBorderStyle( const Reference< XControl >& _rxControl, BorderDescriptor& _rData ) const
+ {
+ _rData = ControlData();
+ if ( m_aFocusControl.xControl.get() == _rxControl.get() )
+ {
+ _rData = m_aFocusControl;
+ }
+ else if ( m_aMouseHoverControl.xControl.get() == _rxControl.get() )
+ {
+ _rData = m_aMouseHoverControl;
+ }
+ else
+ {
+ ControlBag::const_iterator aPos = m_aInvalidControls.find( _rxControl );
+ if ( aPos != m_aInvalidControls.end() )
+ {
+ _rData = *aPos;
+ }
+ else
+ {
+ Reference< XVclWindowPeer > xPeer( _rxControl->getPeer(), UNO_QUERY );
+ getBorder( xPeer, _rData );
+ }
+ }
+ }
+
+
+ void ControlBorderManager::controlStatusGained( const Reference< XInterface >& _rxControl, ControlData& _rControlData )
+ {
+ if ( _rxControl == _rControlData.xControl )
+ // nothing to do - though suspicious
+ return;
+
+ Reference< XControl > xAsControl( _rxControl, UNO_QUERY );
+ DBG_ASSERT( xAsControl.is(), "ControlBorderManager::controlStatusGained: invalid control!" );
+ if ( !xAsControl.is() )
+ return;
+
+ try
+ {
+ Reference< XVclWindowPeer > xPeer( xAsControl->getPeer(), UNO_QUERY );
+ if ( xPeer.is() && canColorBorder( xPeer ) )
+ {
+ // remember the control and its current border color
+ _rControlData.xControl.clear(); // so determineOriginalBorderStyle doesn't get confused
+
+ determineOriginalBorderStyle( xAsControl, _rControlData );
+
+ _rControlData.xControl = xAsControl;
+
+ updateBorderStyle( xAsControl, xPeer, _rControlData );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "ControlBorderManager::controlStatusGained" );
+ }
+ }
+
+
+ void ControlBorderManager::controlStatusLost( const Reference< XInterface >& _rxControl, ControlData& _rControlData )
+ {
+ if ( _rxControl != _rControlData.xControl )
+ // nothing to do
+ return;
+
+ OSL_PRECOND( _rControlData.xControl.is(), "ControlBorderManager::controlStatusLost: invalid control data - this will crash!" );
+ try
+ {
+ Reference< XVclWindowPeer > xPeer( _rControlData.xControl->getPeer(), UNO_QUERY );
+ if ( xPeer.is() && canColorBorder( xPeer ) )
+ {
+ ControlData aPreviousStatus( _rControlData );
+ _rControlData = ControlData();
+ updateBorderStyle( aPreviousStatus.xControl, xPeer, aPreviousStatus );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "ControlBorderManager::controlStatusLost" );
+ }
+ }
+
+
+ void ControlBorderManager::enableDynamicBorderColor( )
+ {
+ m_bDynamicBorderColors = true;
+ }
+
+
+ void ControlBorderManager::disableDynamicBorderColor( )
+ {
+ m_bDynamicBorderColors = false;
+ restoreAll();
+ }
+
+
+ void ControlBorderManager::setStatusColor( ControlStatus _nStatus, Color _nColor )
+ {
+ switch ( _nStatus )
+ {
+ case ControlStatus::Focused:
+ m_nFocusColor = _nColor;
+ break;
+ case ControlStatus::MouseHover:
+ m_nMouseHoveColor = _nColor;
+ break;
+ case ControlStatus::Invalid:
+ m_nInvalidColor = _nColor;
+ break;
+ default:
+ OSL_FAIL( "ControlBorderManager::setStatusColor: invalid status!" );
+ }
+ }
+
+
+ void ControlBorderManager::restoreAll()
+ {
+ if ( m_aFocusControl.xControl.is() )
+ controlStatusLost( m_aFocusControl.xControl, m_aFocusControl );
+ if ( m_aMouseHoverControl.xControl.is() )
+ controlStatusLost( m_aMouseHoverControl.xControl, m_aMouseHoverControl );
+
+ ControlBag aInvalidControls;
+ m_aInvalidControls.swap( aInvalidControls );
+
+ for (const auto& rControl : aInvalidControls)
+ {
+ Reference< XVclWindowPeer > xPeer( rControl.xControl->getPeer(), UNO_QUERY );
+ if ( xPeer.is() )
+ {
+ updateBorderStyle( rControl.xControl, xPeer, rControl );
+ xPeer->setProperty( FM_PROP_HELPTEXT, Any( rControl.sOriginalHelpText ) );
+ setUnderline( xPeer, rControl );
+ }
+ }
+ }
+
+
+ void ControlBorderManager::focusGained( const Reference< XInterface >& _rxControl )
+ {
+ if ( m_bDynamicBorderColors )
+ controlStatusGained( _rxControl, m_aFocusControl );
+ }
+
+
+ void ControlBorderManager::focusLost( const Reference< XInterface >& _rxControl )
+ {
+ if ( m_bDynamicBorderColors )
+ controlStatusLost( _rxControl, m_aFocusControl );
+ }
+
+
+ void ControlBorderManager::mouseEntered( const Reference< XInterface >& _rxControl )
+ {
+ if ( m_bDynamicBorderColors )
+ controlStatusGained( _rxControl, m_aMouseHoverControl );
+ }
+
+
+ void ControlBorderManager::mouseExited( const Reference< XInterface >& _rxControl )
+ {
+ if ( m_bDynamicBorderColors )
+ controlStatusLost( _rxControl, m_aMouseHoverControl );
+ }
+
+
+ void ControlBorderManager::validityChanged( const Reference< XControl >& _rxControl, const Reference< XValidatableFormComponent >& _rxValidatable )
+ {
+ try
+ {
+ OSL_ENSURE( _rxControl.is(), "ControlBorderManager::validityChanged: invalid control!" );
+ OSL_ENSURE( _rxValidatable.is(), "ControlBorderManager::validityChanged: invalid validatable!" );
+
+ Reference< XVclWindowPeer > xPeer( _rxControl.is() ? _rxControl->getPeer() : Reference< XWindowPeer >(), UNO_QUERY );
+ if ( !xPeer.is() || !_rxValidatable.is() )
+ return;
+
+ ControlData aData( _rxControl );
+
+ if ( _rxValidatable->isValid() )
+ {
+ ControlBag::iterator aPos = m_aInvalidControls.find( aData );
+ if ( aPos != m_aInvalidControls.end() )
+ { // invalid before, valid now
+ ControlData aOriginalLayout( *aPos );
+ m_aInvalidControls.erase( aPos );
+
+ // restore all the things we used to indicate invalidity
+ if ( m_bDynamicBorderColors )
+ updateBorderStyle( _rxControl, xPeer, aOriginalLayout );
+ xPeer->setProperty( FM_PROP_HELPTEXT, Any( aOriginalLayout.sOriginalHelpText ) );
+ setUnderline( xPeer, aOriginalLayout );
+ }
+ return;
+ }
+
+ // we're here in the INVALID case
+ if ( m_aInvalidControls.find( _rxControl ) == m_aInvalidControls.end() )
+ { // valid before, invalid now
+
+ // remember the current border
+ determineOriginalBorderStyle( _rxControl, aData );
+ // and tool tip
+ xPeer->getProperty( FM_PROP_HELPTEXT ) >>= aData.sOriginalHelpText;
+ // and font
+ getUnderline( xPeer, aData );
+
+ m_aInvalidControls.insert( aData );
+
+ // update the border to the new invalidity
+ if ( m_bDynamicBorderColors && canColorBorder( xPeer ) )
+ updateBorderStyle( _rxControl, xPeer, aData );
+ else
+ {
+ // and also the new font
+ setUnderline( xPeer, UnderlineDescriptor( css::awt::FontUnderline::WAVE, m_nInvalidColor ) );
+ }
+ }
+
+ // update the explanation for invalidity (this is always done, even if the validity did not change)
+ Reference< XValidator > xValidator = _rxValidatable->getValidator();
+ OSL_ENSURE( xValidator.is(), "ControlBorderManager::validityChanged: invalid, but no validator?" );
+ OUString sExplainInvalidity = xValidator.is() ? xValidator->explainInvalid( _rxValidatable->getCurrentValue() ) : OUString();
+ xPeer->setProperty( FM_PROP_HELPTEXT, Any( sExplainInvalidity ) );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "ControlBorderManager::validityChanged" );
+ }
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmcontrollayout.cxx b/svx/source/form/fmcontrollayout.cxx
new file mode 100644
index 000000000..985fc6ef1
--- /dev/null
+++ b/svx/source/form/fmcontrollayout.cxx
@@ -0,0 +1,312 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <fmcontrollayout.hxx>
+#include <fmprop.hxx>
+
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/awt/VisualEffect.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XChild.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <unotools/confignode.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/localedatawrapper.hxx>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/outdev.hxx>
+
+
+namespace svxform
+{
+
+
+ using namespace ::utl;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::lang::Locale;
+ using ::com::sun::star::awt::FontDescriptor;
+ using ::com::sun::star::style::XStyleFamiliesSupplier;
+ using ::com::sun::star::lang::XServiceInfo;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::container::XChild;
+
+ namespace FormComponentType = ::com::sun::star::form::FormComponentType;
+ namespace VisualEffect = ::com::sun::star::awt::VisualEffect;
+ namespace ScriptType = ::com::sun::star::i18n::ScriptType;
+
+
+ namespace
+ {
+ ::utl::OConfigurationNode getLayoutSettings( DocumentType _eDocType )
+ {
+ OUString sConfigName = "/org.openoffice.Office.Common/Forms/ControlLayout/" +
+ DocumentClassification::getModuleIdentifierForDocumentType( _eDocType );
+ return OConfigurationTreeRoot::createWithComponentContext(
+ ::comphelper::getProcessComponentContext(), // TODO
+ sConfigName );
+ }
+
+ template< class INTERFACE_TYPE >
+ Reference< INTERFACE_TYPE > getTypedModelNode( const Reference< XInterface >& _rxModelNode )
+ {
+ Reference< INTERFACE_TYPE > xTypedNode( _rxModelNode, UNO_QUERY );
+ if ( xTypedNode.is() )
+ return xTypedNode;
+ else
+ {
+ Reference< XChild > xChild( _rxModelNode, UNO_QUERY );
+ if ( xChild.is() )
+ return getTypedModelNode< INTERFACE_TYPE >( xChild->getParent() );
+ else
+ return nullptr;
+ }
+ }
+
+
+ bool lcl_getDocumentDefaultStyleAndFamily( const Reference< XInterface >& _rxDocument, OUString& _rFamilyName, OUString& _rStyleName )
+ {
+ bool bSuccess = true;
+ Reference< XServiceInfo > xDocumentSI( _rxDocument, UNO_QUERY );
+ if ( xDocumentSI.is() )
+ {
+ if ( xDocumentSI->supportsService("com.sun.star.text.TextDocument")
+ || xDocumentSI->supportsService("com.sun.star.text.WebDocument")
+ )
+ {
+ _rFamilyName = "ParagraphStyles";
+ _rStyleName = "Standard";
+ }
+ else if ( xDocumentSI->supportsService("com.sun.star.sheet.SpreadsheetDocument") )
+ {
+ _rFamilyName = "CellStyles";
+ _rStyleName = "Default";
+ }
+ else if ( xDocumentSI->supportsService("com.sun.star.drawing.DrawingDocument")
+ || xDocumentSI->supportsService("com.sun.star.presentation.PresentationDocument")
+ )
+ {
+ _rFamilyName = "graphics";
+ _rStyleName = "standard";
+ }
+ else
+ bSuccess = false;
+ }
+ return bSuccess;
+ }
+
+
+ void lcl_initializeControlFont( const Reference< XPropertySet >& _rxModel )
+ {
+ try
+ {
+ Reference< XPropertySet > xStyle( ControlLayouter::getDefaultDocumentTextStyle( _rxModel ), UNO_SET_THROW );
+ Reference< XPropertySetInfo > xStylePSI( xStyle->getPropertySetInfo(), UNO_SET_THROW );
+
+ // determine the script type associated with the system locale
+ const SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& rSysLocaleData = aSysLocale.GetLocaleData();
+ const sal_Int16 eSysLocaleScriptType = MsLangId::getScriptType( rSysLocaleData.getLanguageTag().getLanguageType() );
+
+ // depending on this script type, use the right property from the document's style which controls the
+ // default locale for document content
+ const char* pCharLocalePropertyName = "CharLocale";
+ switch ( eSysLocaleScriptType )
+ {
+ case ScriptType::LATIN:
+ // already defaulted above
+ break;
+ case ScriptType::ASIAN:
+ pCharLocalePropertyName = "CharLocaleAsian";
+ break;
+ case ScriptType::COMPLEX:
+ pCharLocalePropertyName = "CharLocaleComplex";
+ break;
+ default:
+ OSL_FAIL( "lcl_initializeControlFont: unexpected script type for system locale!" );
+ break;
+ }
+
+ OUString sCharLocalePropertyName = OUString::createFromAscii( pCharLocalePropertyName );
+ Locale aDocumentCharLocale;
+ if ( xStylePSI->hasPropertyByName( sCharLocalePropertyName ) )
+ {
+ OSL_VERIFY( xStyle->getPropertyValue( sCharLocalePropertyName ) >>= aDocumentCharLocale );
+ }
+ // fall back to CharLocale property at the style
+ if ( aDocumentCharLocale.Language.isEmpty() )
+ {
+ sCharLocalePropertyName = "CharLocale";
+ if ( xStylePSI->hasPropertyByName( sCharLocalePropertyName ) )
+ {
+ OSL_VERIFY( xStyle->getPropertyValue( sCharLocalePropertyName ) >>= aDocumentCharLocale );
+ }
+ }
+ // fall back to the system locale
+ if ( aDocumentCharLocale.Language.isEmpty() )
+ {
+ aDocumentCharLocale = rSysLocaleData.getLanguageTag().getLocale();
+ }
+
+ // retrieve a default font for this locale, and set it at the control
+ vcl::Font aFont = OutputDevice::GetDefaultFont( DefaultFontType::SANS, LanguageTag::convertToLanguageType( aDocumentCharLocale ), GetDefaultFontFlags::OnlyOne );
+ FontDescriptor aFontDesc = VCLUnoHelper::CreateFontDescriptor( aFont );
+ _rxModel->setPropertyValue("FontDescriptor", Any( aFontDesc )
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+
+
+ //= ControlLayouter
+
+
+ Reference< XPropertySet > ControlLayouter::getDefaultDocumentTextStyle( const Reference< XPropertySet >& _rxModel )
+ {
+ // the style family collection
+ Reference< XStyleFamiliesSupplier > xSuppStyleFamilies( getTypedModelNode< XStyleFamiliesSupplier >( _rxModel ), UNO_SET_THROW );
+ Reference< XNameAccess > xStyleFamilies( xSuppStyleFamilies->getStyleFamilies(), UNO_SET_THROW );
+
+ // the names of the family, and the style - depends on the document type we live in
+ OUString sFamilyName, sStyleName;
+ if ( !lcl_getDocumentDefaultStyleAndFamily( xSuppStyleFamilies, sFamilyName, sStyleName ) )
+ throw RuntimeException("unknown document type!");
+
+ // the concrete style
+ Reference< XNameAccess > xStyleFamily( xStyleFamilies->getByName( sFamilyName ), UNO_QUERY_THROW );
+ return Reference< XPropertySet >( xStyleFamily->getByName( sStyleName ), UNO_QUERY_THROW );
+ }
+
+
+ void ControlLayouter::initializeControlLayout( const Reference< XPropertySet >& _rxControlModel, DocumentType _eDocType )
+ {
+ DBG_ASSERT( _rxControlModel.is(), "ControlLayouter::initializeControlLayout: invalid model!" );
+ if ( !_rxControlModel.is() )
+ return;
+
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( _rxControlModel->getPropertySetInfo(), UNO_SET_THROW );
+
+ // the control type
+ sal_Int16 nClassId = FormComponentType::CONTROL;
+ _rxControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId;
+
+ // the document type
+ if ( _eDocType == eUnknownDocumentType )
+ _eDocType = DocumentClassification::classifyHostDocument( _rxControlModel );
+
+ // let's see what the configuration says about the visual effect
+ OConfigurationNode aConfig = getLayoutSettings( _eDocType );
+ Any aVisualEffect = aConfig.getNodeValue( OUString( "VisualEffect" ) );
+ if ( aVisualEffect.hasValue() )
+ {
+ OUString sVisualEffect;
+ OSL_VERIFY( aVisualEffect >>= sVisualEffect );
+
+ sal_Int16 nVisualEffect = VisualEffect::NONE;
+ if ( sVisualEffect == "flat" )
+ nVisualEffect = VisualEffect::FLAT;
+ else if ( sVisualEffect == "3D" )
+ nVisualEffect = VisualEffect::LOOK3D;
+
+ if ( xPSI->hasPropertyByName( FM_PROP_BORDER ) )
+ {
+ if ( ( nClassId != FormComponentType::COMMANDBUTTON )
+ && ( nClassId != FormComponentType::RADIOBUTTON )
+ && ( nClassId != FormComponentType::CHECKBOX )
+ && ( nClassId != FormComponentType::GROUPBOX )
+ && ( nClassId != FormComponentType::FIXEDTEXT )
+ && ( nClassId != FormComponentType::SCROLLBAR )
+ && ( nClassId != FormComponentType::SPINBUTTON )
+ )
+ {
+ _rxControlModel->setPropertyValue( FM_PROP_BORDER, Any( nVisualEffect ) );
+ if ( ( nVisualEffect == VisualEffect::FLAT )
+ && ( xPSI->hasPropertyByName( FM_PROP_BORDERCOLOR ) )
+ )
+ // light gray flat border
+ _rxControlModel->setPropertyValue( FM_PROP_BORDERCOLOR, Any( sal_Int32(0x00C0C0C0) ) );
+ }
+ }
+ if ( xPSI->hasPropertyByName( FM_PROP_VISUALEFFECT ) )
+ _rxControlModel->setPropertyValue( FM_PROP_VISUALEFFECT, Any( nVisualEffect ) );
+ }
+
+ // the font (only if we use the document's ref devices for rendering control text, otherwise, the
+ // default font of VCL controls is assumed to be fine)
+ if ( useDocumentReferenceDevice( _eDocType )
+ && xPSI->hasPropertyByName( FM_PROP_FONT )
+ )
+ lcl_initializeControlFont( _rxControlModel );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "ControlLayouter::initializeControlLayout" );
+ }
+ }
+
+ bool ControlLayouter::useDynamicBorderColor( DocumentType _eDocType )
+ {
+ OConfigurationNode aConfig = getLayoutSettings( _eDocType );
+ Any aDynamicBorderColor = aConfig.getNodeValue( OUString( "DynamicBorderColors" ) );
+ bool bDynamicBorderColor = false;
+ OSL_VERIFY( aDynamicBorderColor >>= bDynamicBorderColor );
+ return bDynamicBorderColor;
+ }
+
+
+ bool ControlLayouter::useDocumentReferenceDevice( DocumentType _eDocType )
+ {
+ if ( _eDocType == eUnknownDocumentType )
+ return false;
+ OConfigurationNode aConfig = getLayoutSettings( _eDocType );
+ Any aUseRefDevice = aConfig.getNodeValue( OUString( "UseDocumentTextMetrics" ) );
+ bool bUseRefDevice = false;
+ OSL_VERIFY( aUseRefDevice >>= bUseRefDevice );
+ return bUseRefDevice;
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmdmod.cxx b/svx/source/form/fmdmod.cxx
new file mode 100644
index 000000000..e475cf8f8
--- /dev/null
+++ b/svx/source/form/fmdmod.cxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sal/macros.h>
+#include <svx/fmdmod.hxx>
+#include <fmservs.hxx>
+#include <fmobj.hxx>
+#include <svx/unoshape.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+using namespace ::svxform;
+
+
+::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL SvxFmMSFactory::createInstance(const OUString& rServiceSpecifier)
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xRet;
+
+ if ( rServiceSpecifier.startsWith( "com.sun.star.form.component." ) )
+ {
+ css::uno::Reference<css::uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
+ xRet = xContext->getServiceManager()->createInstanceWithContext(rServiceSpecifier, xContext);
+ }
+ else if ( rServiceSpecifier == "com.sun.star.drawing.ControlShape" )
+ {
+ SdrModel& rTargetModel(getSdrModelFromUnoModel());
+ SdrObject* pObj = new FmFormObj(rTargetModel);
+ xRet = static_cast<cppu::OWeakObject*>(static_cast<SvxShape_UnoImplHelper*>(new SvxShapeControl(pObj)));
+ }
+
+ if (!xRet.is())
+ {
+ xRet = SvxUnoDrawMSFactory::createInstance(rServiceSpecifier);
+ }
+
+ return xRet;
+}
+
+
+::com::sun::star::uno::Sequence< OUString > SAL_CALL SvxFmMSFactory::getAvailableServiceNames()
+{
+ static const rtl::OUStringConstExpr aSvxComponentServiceNameList[] =
+ {
+ FM_SUN_COMPONENT_TEXTFIELD,
+ FM_SUN_COMPONENT_FORM,
+ FM_SUN_COMPONENT_LISTBOX,
+ FM_SUN_COMPONENT_COMBOBOX,
+ FM_SUN_COMPONENT_RADIOBUTTON,
+ FM_SUN_COMPONENT_GROUPBOX,
+ FM_SUN_COMPONENT_FIXEDTEXT,
+ FM_SUN_COMPONENT_COMMANDBUTTON,
+ FM_SUN_COMPONENT_CHECKBOX,
+ FM_SUN_COMPONENT_GRIDCONTROL,
+ FM_SUN_COMPONENT_IMAGEBUTTON,
+ FM_SUN_COMPONENT_FILECONTROL,
+ FM_SUN_COMPONENT_TIMEFIELD,
+ FM_SUN_COMPONENT_DATEFIELD,
+ FM_SUN_COMPONENT_NUMERICFIELD,
+ FM_SUN_COMPONENT_CURRENCYFIELD,
+ FM_SUN_COMPONENT_PATTERNFIELD,
+ FM_SUN_COMPONENT_HIDDENCONTROL,
+ FM_SUN_COMPONENT_IMAGECONTROL
+ };
+
+ static const sal_uInt16 nSvxComponentServiceNameListCount = SAL_N_ELEMENTS(aSvxComponentServiceNameList);
+
+ auto aSeq( comphelper::arrayToSequence< OUString >(aSvxComponentServiceNameList, nSvxComponentServiceNameListCount) );
+
+ ::com::sun::star::uno::Sequence< OUString > aParentSeq( SvxUnoDrawMSFactory::getAvailableServiceNames() );
+ return comphelper::concatSequences( aParentSeq, aSeq );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmdocumentclassification.cxx b/svx/source/form/fmdocumentclassification.cxx
new file mode 100644
index 000000000..e624e23f5
--- /dev/null
+++ b/svx/source/form/fmdocumentclassification.cxx
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <fmdocumentclassification.hxx>
+
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/xforms/XFormsSupplier.hpp>
+#include <com/sun/star/frame/XModule.hpp>
+
+#include <o3tl/string_view.hxx>
+#include <tools/diagnose_ex.h>
+
+
+namespace svxform
+{
+
+
+ namespace
+ {
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::frame::XModule;
+
+
+ template< class TYPE >
+ Reference< TYPE > getTypedModelNode( const Reference< XInterface >& _rxModelNode )
+ {
+ Reference< TYPE > xTypedNode( _rxModelNode, UNO_QUERY );
+ if ( xTypedNode.is() )
+ return xTypedNode;
+ else
+ {
+ Reference< XChild > xChild( _rxModelNode, UNO_QUERY );
+ if ( xChild.is() )
+ return getTypedModelNode< TYPE >( xChild->getParent() );
+ else
+ return Reference< TYPE >();
+ }
+ }
+
+
+ Reference< XModel > getDocument( const Reference< XInterface >& _rxModelNode )
+ {
+ return getTypedModelNode< XModel >( _rxModelNode );
+ }
+ }
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::xforms;
+ using namespace ::com::sun::star::container;
+
+
+ namespace
+ {
+
+ struct ModuleInfo
+ {
+ const char* pAsciiModuleOrServiceName;
+ DocumentType eType;
+ };
+
+
+ const ModuleInfo* lcl_getModuleInfo()
+ {
+ static const ModuleInfo aModuleInfo[] =
+ {
+ { "com.sun.star.text.TextDocument", eTextDocument },
+ { "com.sun.star.text.WebDocument", eWebDocument },
+ { "com.sun.star.sheet.SpreadsheetDocument", eSpreadsheetDocument },
+ { "com.sun.star.drawing.DrawingDocument", eDrawingDocument },
+ { "com.sun.star.presentation.PresentationDocument", ePresentationDocument },
+ { "com.sun.star.xforms.XMLFormDocument", eEnhancedForm },
+ { "com.sun.star.sdb.FormDesign", eDatabaseForm },
+ { "com.sun.star.sdb.TextReportDesign", eDatabaseReport },
+ { "com.sun.star.text.GlobalDocument", eTextDocument },
+ { nullptr, eUnknownDocumentType }
+ };
+ return aModuleInfo;
+ }
+ }
+
+
+ //= DocumentClassification
+
+
+ DocumentType DocumentClassification::classifyDocument( const Reference< XModel >& _rxDocumentModel )
+ {
+ DocumentType eType( eUnknownDocumentType );
+
+ OSL_ENSURE( _rxDocumentModel.is(), "DocumentClassification::classifyDocument: invalid document!" );
+ if ( !_rxDocumentModel.is() )
+ return eType;
+
+ try
+ {
+ // first, check whether the document has a ModuleIdentifier which we know
+ Reference< XModule > xModule( _rxDocumentModel, UNO_QUERY );
+ if ( xModule.is() )
+ eType = getDocumentTypeForModuleIdentifier( xModule->getIdentifier() );
+ if ( eType != eUnknownDocumentType )
+ return eType;
+
+ // second, check whether it supports one of the services we know
+ Reference< XServiceInfo > xSI( _rxDocumentModel, UNO_QUERY_THROW );
+ const ModuleInfo* pModuleInfo = lcl_getModuleInfo();
+ while ( pModuleInfo->pAsciiModuleOrServiceName )
+ {
+ if ( xSI->supportsService( OUString::createFromAscii( pModuleInfo->pAsciiModuleOrServiceName ) ) )
+ return pModuleInfo->eType;
+ ++pModuleInfo;
+ }
+
+ // last: uhm, there is no last resort
+ OSL_FAIL( "DocumentClassification::classifyDocument: unknown document!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ return eType;
+ }
+
+
+ DocumentType DocumentClassification::classifyHostDocument( const Reference< XInterface >& _rxFormComponent )
+ {
+ DocumentType eType( eUnknownDocumentType );
+
+ try
+ {
+ Reference< XModel > xDocument( getDocument( _rxFormComponent ) );
+ if ( !xDocument.is() )
+ return eUnknownDocumentType;
+ eType = classifyDocument( xDocument );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "DocumentClassification::classifyHostDocument" );
+ }
+
+ return eType;
+ }
+
+
+ DocumentType DocumentClassification::getDocumentTypeForModuleIdentifier( std::u16string_view _rModuleIdentifier )
+ {
+ const ModuleInfo* pModuleInfo = lcl_getModuleInfo();
+ while ( pModuleInfo->pAsciiModuleOrServiceName )
+ {
+ if ( o3tl::equalsAscii(_rModuleIdentifier, pModuleInfo->pAsciiModuleOrServiceName ) )
+ return pModuleInfo->eType;
+ ++pModuleInfo;
+ }
+ return eUnknownDocumentType;
+ }
+
+
+ OUString DocumentClassification::getModuleIdentifierForDocumentType( DocumentType _eType )
+ {
+ const ModuleInfo* pModuleInfo = lcl_getModuleInfo();
+ while ( pModuleInfo->pAsciiModuleOrServiceName )
+ {
+ if ( pModuleInfo->eType == _eType )
+ return OUString::createFromAscii( pModuleInfo->pAsciiModuleOrServiceName );
+ ++pModuleInfo;
+ }
+ return OUString();
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmdpage.cxx b/svx/source/form/fmdpage.cxx
new file mode 100644
index 000000000..2351564e0
--- /dev/null
+++ b/svx/source/form/fmdpage.cxx
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/fmpage.hxx>
+#include <fmobj.hxx>
+#include <svx/fmdpage.hxx>
+#include <svx/unoshape.hxx>
+#include <vcl/svapp.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::form::XFormsSupplier2;
+
+SvxFmDrawPage::SvxFmDrawPage( SdrPage* pInPage ) :
+ SvxDrawPage( pInPage )
+{
+}
+
+SvxFmDrawPage::~SvxFmDrawPage() noexcept
+{
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL SvxFmDrawPage::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any SAL_CALL SvxFmDrawPage::queryAggregation( const css::uno::Type& _rType )
+{
+ Any aRet = ::cppu::queryInterface ( _rType
+ , static_cast< XFormsSupplier2* >( this )
+ , static_cast< XFormsSupplier* >( this )
+ );
+ if ( !aRet.hasValue() )
+ aRet = SvxDrawPage::queryAggregation( _rType );
+
+ return aRet;
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL SvxFmDrawPage::getTypes( )
+{
+ return comphelper::concatSequences(SvxDrawPage::getTypes(),
+ css::uno::Sequence { cppu::UnoType<css::form::XFormsSupplier>::get() });
+}
+
+SdrObject *SvxFmDrawPage::CreateSdrObject_( const css::uno::Reference< css::drawing::XShape > & xDescr )
+{
+ OUString aShapeType( xDescr->getShapeType() );
+
+ if ( aShapeType == "com.sun.star.drawing.ShapeControl" // compatibility
+ || aShapeType == "com.sun.star.drawing.ControlShape"
+ )
+ {
+ return new FmFormObj(GetSdrPage()->getSdrModelFromSdrPage());
+ }
+ else
+ {
+ return SvxDrawPage::CreateSdrObject_( xDescr );
+ }
+}
+
+css::uno::Reference< css::drawing::XShape > SvxFmDrawPage::CreateShape( SdrObject *pObj ) const
+{
+ if( SdrInventor::FmForm == pObj->GetObjInventor() )
+ {
+ css::uno::Reference< css::drawing::XShape > xShape = static_cast<SvxShape*>(new SvxShapeControl( pObj ));
+ return xShape;
+ }
+ else
+ return SvxDrawPage::CreateShape( pObj );
+}
+
+// XFormsSupplier
+css::uno::Reference< css::container::XNameContainer > SAL_CALL SvxFmDrawPage::getForms()
+{
+ SolarMutexGuard g;
+
+ css::uno::Reference< css::container::XNameContainer > xForms;
+
+ FmFormPage *pFmPage = dynamic_cast<FmFormPage*>( GetSdrPage() );
+ if( pFmPage )
+ xForms.set( pFmPage->GetForms(), css::uno::UNO_QUERY_THROW );
+
+ return xForms;
+}
+
+// XFormsSupplier2
+sal_Bool SAL_CALL SvxFmDrawPage::hasForms()
+{
+ SolarMutexGuard g;
+
+ bool bHas = false;
+ FmFormPage* pFormPage = dynamic_cast<FmFormPage*>( GetSdrPage() );
+ if ( pFormPage )
+ bHas = pFormPage->GetForms( false ).is();
+ return bHas;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmexch.cxx b/svx/source/form/fmexch.cxx
new file mode 100644
index 000000000..5a5429b10
--- /dev/null
+++ b/svx/source/form/fmexch.cxx
@@ -0,0 +1,347 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fmexch.hxx>
+
+#include <sot/formats.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace svxform
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::datatransfer;
+
+ OLocalExchange::OLocalExchange( )
+ :m_bDragging( false )
+ ,m_bClipboardOwner( false )
+ {
+ }
+
+ void OLocalExchange::copyToClipboard(const weld::Widget& rWidget, const GrantAccess&)
+ {
+ if ( m_bClipboardOwner )
+ { // simulate a lostOwnership to notify parties interested in
+ m_aClipboardListener.Call( *this );
+ }
+
+ m_bClipboardOwner = true;
+ CopyToClipboard(rWidget.get_clipboard());
+ }
+
+ void OLocalExchange::clear()
+ {
+ if ( !isClipboardOwner() )
+ return;
+
+ try
+ {
+ Reference< clipboard::XClipboard > xClipBoard( getOwnClipboard() );
+ if ( xClipBoard.is() )
+ xClipBoard->setContents( nullptr, nullptr );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ m_bClipboardOwner = false;
+ }
+
+ void SAL_CALL OLocalExchange::lostOwnership( const Reference< clipboard::XClipboard >& _rxClipboard, const Reference< XTransferable >& _rxTrans )
+ {
+ TransferDataContainer::implCallOwnLostOwnership( _rxClipboard, _rxTrans );
+ m_bClipboardOwner = false;
+
+ m_aClipboardListener.Call( *this );
+ }
+
+ void OLocalExchange::setDragging(bool bDragging)
+ {
+ m_bDragging = bDragging;
+ }
+
+ void OLocalExchange::DragFinished( sal_Int8 nDropAction )
+ {
+ TransferDataContainer::DragFinished( nDropAction );
+ setDragging(false);
+ }
+
+ bool OLocalExchange::hasFormat( const DataFlavorExVector& _rFormats, SotClipboardFormatId _nFormatId )
+ {
+ return std::any_of(_rFormats.begin(), _rFormats.end(),
+ [&_nFormatId](const DataFlavorEx& rFormat) { return rFormat.mnSotId == _nFormatId; });
+ }
+
+ bool OLocalExchange::GetData( const css::datatransfer::DataFlavor& /*_rFlavor*/, const OUString& /*rDestDoc*/ )
+ {
+ return false; // do not have any formats by default
+ }
+
+ OControlTransferData::OControlTransferData( )
+ : m_bFocusEntry(false)
+ {
+ }
+
+ OControlTransferData::OControlTransferData( const Reference< XTransferable >& _rxTransferable )
+ : m_bFocusEntry(false)
+ {
+ TransferableDataHelper aExchangedData( _rxTransferable );
+
+ // try the formats we know
+ if ( OControlExchange::hasControlPathFormat( aExchangedData.GetDataFlavorExVector() ) )
+ { // paths to the controls, relative to a root
+ Sequence< Any > aControlPathData;
+ if ( aExchangedData.GetAny(OControlExchange::getControlPathFormatId(), OUString()) >>= aControlPathData )
+ {
+ DBG_ASSERT( aControlPathData.getLength() >= 2, "OControlTransferData::OControlTransferData: invalid data for the control path format!" );
+ if ( aControlPathData.getLength() >= 2 )
+ {
+ aControlPathData[0] >>= m_xFormsRoot;
+ aControlPathData[1] >>= m_aControlPaths;
+ }
+ }
+ else
+ {
+ OSL_FAIL( "OControlTransferData::OControlTransferData: invalid data for the control path format (2)!" );
+ }
+ }
+ if ( OControlExchange::hasHiddenControlModelsFormat( aExchangedData.GetDataFlavorExVector() ) )
+ { // sequence of models of hidden controls
+ aExchangedData.GetAny(OControlExchange::getHiddenControlModelsFormatId(), OUString()) >>= m_aHiddenControlModels;
+ }
+
+ updateFormats( );
+ }
+
+
+ static bool lcl_fillDataFlavorEx( SotClipboardFormatId nId, DataFlavorEx& _rFlavor )
+ {
+ _rFlavor.mnSotId = nId;
+ return SotExchange::GetFormatDataFlavor( _rFlavor.mnSotId, _rFlavor );
+ }
+
+
+ void OControlTransferData::updateFormats( )
+ {
+ m_aCurrentFormats.clear();
+ m_aCurrentFormats.reserve( 3 );
+
+ DataFlavorEx aFlavor;
+
+ if ( m_aHiddenControlModels.hasElements() )
+ {
+ if ( lcl_fillDataFlavorEx( OControlExchange::getHiddenControlModelsFormatId(), aFlavor ) )
+ m_aCurrentFormats.push_back( aFlavor );
+ }
+
+ if ( m_xFormsRoot.is() && m_aControlPaths.hasElements() )
+ {
+ if ( lcl_fillDataFlavorEx( OControlExchange::getControlPathFormatId(), aFlavor ) )
+ m_aCurrentFormats.push_back( aFlavor );
+ }
+
+ if ( !m_aSelectedEntries.empty() )
+ {
+ if ( lcl_fillDataFlavorEx( OControlExchange::getFieldExchangeFormatId(), aFlavor ) )
+ m_aCurrentFormats.push_back( aFlavor );
+ }
+ }
+
+ size_t OControlTransferData::onEntryRemoved(const weld::TreeView* pView, const weld::TreeIter* _pEntry)
+ {
+ auto aIter = std::find_if(m_aSelectedEntries.begin(), m_aSelectedEntries.end(),
+ [pView, _pEntry](const auto& rElem) {
+ return pView->iter_compare(*rElem, *_pEntry) == 0;
+ });
+ if (aIter != m_aSelectedEntries.end())
+ m_aSelectedEntries.erase(aIter);
+
+ return m_aSelectedEntries.size();
+ }
+
+ void OControlTransferData::addSelectedEntry(std::unique_ptr<weld::TreeIter> xEntry)
+ {
+ m_aSelectedEntries.emplace(std::move(xEntry));
+ }
+
+ void OControlTransferData::setFocusEntry(bool _bFocusEntry)
+ {
+ m_bFocusEntry = _bFocusEntry;
+ }
+
+ void OControlTransferData::addHiddenControlsFormat(const css::uno::Sequence< css::uno::Reference< css::uno::XInterface > >& seqInterfaces)
+ {
+ m_aHiddenControlModels = seqInterfaces;
+ }
+
+ void OControlTransferData::buildPathFormat(const weld::TreeView* pTreeBox, const weld::TreeIter* pRoot)
+ {
+ m_aControlPaths.realloc(0);
+
+ sal_Int32 nEntryCount = m_aSelectedEntries.size();
+ if (nEntryCount == 0)
+ return;
+
+ m_aControlPaths.realloc(nEntryCount);
+ css::uno::Sequence<sal_uInt32>* pAllPaths = m_aControlPaths.getArray();
+ for (const auto& rCurrentEntry : m_aSelectedEntries)
+ {
+ // first we collect the path in an array
+ ::std::vector< sal_uInt32 > aCurrentPath;
+
+ std::unique_ptr<weld::TreeIter> xLoop(pTreeBox->make_iterator(rCurrentEntry.get()));
+ while (pTreeBox->iter_compare(*xLoop, *pRoot) != 0)
+ {
+ aCurrentPath.push_back(pTreeBox->get_iter_index_in_parent(*xLoop));
+ bool bLoop = pTreeBox->iter_parent(*xLoop);
+ assert(bLoop && "OControlTransferData::buildPathFormat: invalid root or entry !"); (void)bLoop;
+ }
+
+ // then we can transfer it into css::uno::Sequence
+ Sequence<sal_uInt32>& rCurrentPath = *pAllPaths;
+ sal_Int32 nDepth = aCurrentPath.size();
+
+ rCurrentPath.realloc(nDepth);
+ sal_uInt32* pSeq = rCurrentPath.getArray();
+ sal_Int32 j,k;
+ for (j = nDepth - 1, k = 0; k<nDepth; --j, ++k)
+ pSeq[j] = aCurrentPath[k];
+ ++pAllPaths;
+ }
+ }
+
+ void OControlTransferData::buildListFromPath(const weld::TreeView* pTreeBox, const weld::TreeIter* pRoot)
+ {
+ ListBoxEntrySet().swap(m_aSelectedEntries);
+
+ for (const css::uno::Sequence<sal_uInt32>& rPaths : std::as_const(m_aControlPaths))
+ {
+ std::unique_ptr<weld::TreeIter> xSearch(pTreeBox->make_iterator(pRoot));
+ for (const sal_uInt32 nThisPath : rPaths)
+ pTreeBox->iter_nth_child(*xSearch, nThisPath);
+ m_aSelectedEntries.emplace(std::move(xSearch));
+ }
+ }
+
+ OControlExchange::OControlExchange( )
+ {
+ }
+
+ bool OControlExchange::GetData( const DataFlavor& _rFlavor, const OUString& rDestDoc )
+ {
+ const SotClipboardFormatId nFormatId = SotExchange::GetFormat( _rFlavor );
+
+ if ( getControlPathFormatId( ) == nFormatId )
+ {
+ // ugly. We have to pack all the info into one object
+ Sequence< Any > aCompleteInfo( 2 );
+ OSL_ENSURE( m_xFormsRoot.is(), "OLocalExchange::GetData: invalid forms root for this format!" );
+ aCompleteInfo.getArray()[ 0 ] <<= m_xFormsRoot;
+ aCompleteInfo.getArray()[ 1 ] <<= m_aControlPaths;
+
+ SetAny( Any( aCompleteInfo ) );
+ }
+ else if ( getHiddenControlModelsFormatId() == nFormatId )
+ {
+ // just need to transfer the models
+ SetAny( Any( m_aHiddenControlModels ) );
+ }
+ else
+ return OLocalExchange::GetData(_rFlavor, rDestDoc);
+
+ return true;
+ }
+
+ void OControlExchange::AddSupportedFormats()
+ {
+ if (m_bFocusEntry && !m_aSelectedEntries.empty())
+ AddFormat(getFieldExchangeFormatId());
+
+ if (m_aControlPaths.hasElements())
+ AddFormat(getControlPathFormatId());
+
+ if (m_aHiddenControlModels.hasElements())
+ AddFormat(getHiddenControlModelsFormatId());
+ }
+
+ SotClipboardFormatId OControlExchange::getControlPathFormatId()
+ {
+ static SotClipboardFormatId s_nFormat =
+ SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"svxform.ControlPathExchange\"");
+ DBG_ASSERT(static_cast<SotClipboardFormatId>(-1) != s_nFormat, "OControlExchange::getControlPathFormatId: bad exchange id!");
+ return s_nFormat;
+ }
+
+ SotClipboardFormatId OControlExchange::getHiddenControlModelsFormatId()
+ {
+ static SotClipboardFormatId s_nFormat =
+ SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"svxform.HiddenControlModelsExchange\"");
+ DBG_ASSERT(static_cast<SotClipboardFormatId>(-1) != s_nFormat, "OControlExchange::getHiddenControlModelsFormatId: bad exchange id!");
+ return s_nFormat;
+ }
+
+
+ SotClipboardFormatId OControlExchange::getFieldExchangeFormatId()
+ {
+ static SotClipboardFormatId s_nFormat =
+ SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"svxform.FieldNameExchange\"");
+ DBG_ASSERT(static_cast<SotClipboardFormatId>(-1) != s_nFormat, "OControlExchange::getFieldExchangeFormatId: bad exchange id!");
+ return s_nFormat;
+ }
+
+ //= OControlExchangeHelper
+ rtl::Reference<OLocalExchange> OControlExchangeHelper::createExchange() const
+ {
+ return new OControlExchange;
+ }
+
+ OLocalExchangeHelper::OLocalExchangeHelper()
+ {
+ }
+
+ OLocalExchangeHelper::~OLocalExchangeHelper()
+ {
+ implReset();
+ }
+
+ void OLocalExchangeHelper::copyToClipboard(const weld::Widget& rWidget) const
+ {
+ DBG_ASSERT( m_xTransferable.is(), "OLocalExchangeHelper::copyToClipboard: not prepared!" );
+ m_xTransferable->copyToClipboard(rWidget, OLocalExchange::GrantAccess());
+ }
+
+ void OLocalExchangeHelper::implReset()
+ {
+ if (m_xTransferable.is())
+ {
+ m_xTransferable->setClipboardListener( Link<OLocalExchange&,void>() );
+ m_xTransferable.clear();
+ }
+ }
+
+ void OLocalExchangeHelper::prepareDrag( )
+ {
+ DBG_ASSERT(!m_xTransferable.is() || !m_xTransferable->isDragging(), "OLocalExchangeHelper::prepareDrag: recursive DnD?");
+
+ implReset();
+ m_xTransferable = createExchange();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmexpl.cxx b/svx/source/form/fmexpl.cxx
new file mode 100644
index 000000000..8ab6006bd
--- /dev/null
+++ b/svx/source/form/fmexpl.cxx
@@ -0,0 +1,527 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/strings.hrc>
+#include <fmexpl.hxx>
+
+#include <helpids.h>
+#include <svx/svdobjkind.hxx>
+#include <svx/fmtools.hxx>
+#include <fmexch.hxx>
+
+#include <svx/svxids.hrc>
+
+#include <fmprop.hxx>
+#include <bitmaps.hlst>
+#include <svx/dialmgr.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <sfx2/objitem.hxx>
+
+#include <svx/fmshell.hxx>
+#include <comphelper/types.hxx>
+
+using namespace ::svxform;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+
+FmNavInsertedHint::FmNavInsertedHint( FmEntryData* pInsertedEntryData, sal_uInt32 nRelPos )
+ :pEntryData( pInsertedEntryData )
+ ,nPos( nRelPos )
+
+{
+}
+
+
+FmNavInsertedHint::~FmNavInsertedHint()
+{
+}
+
+
+
+FmNavModelReplacedHint::FmNavModelReplacedHint( FmEntryData* pAffectedEntryData )
+ :pEntryData( pAffectedEntryData )
+{
+}
+
+
+FmNavModelReplacedHint::~FmNavModelReplacedHint()
+{
+}
+
+FmNavRemovedHint::FmNavRemovedHint( FmEntryData* pRemovedEntryData )
+ :pEntryData( pRemovedEntryData )
+{
+}
+
+
+FmNavRemovedHint::~FmNavRemovedHint()
+{
+}
+
+FmNavNameChangedHint::FmNavNameChangedHint( FmEntryData* pData, const OUString& rNewName )
+ :pEntryData( pData )
+ ,aNewName( rNewName )
+{
+}
+
+
+FmNavNameChangedHint::~FmNavNameChangedHint()
+{
+}
+
+FmNavClearedHint::FmNavClearedHint()
+{
+}
+
+
+FmNavClearedHint::~FmNavClearedHint()
+{
+}
+
+
+FmEntryDataList::FmEntryDataList()
+{
+}
+
+
+FmEntryDataList::~FmEntryDataList()
+{
+}
+
+
+void FmEntryDataList::removeNoDelete( FmEntryData* pItem )
+{
+ auto it = std::find_if(maEntryDataList.begin(), maEntryDataList.end(),
+ [&pItem](const std::unique_ptr<FmEntryData>& rEntryData) { return rEntryData.get() == pItem; });
+ if (it != maEntryDataList.end())
+ {
+ it->release();
+ maEntryDataList.erase( it );
+ return;
+ }
+ assert(false);
+}
+
+
+void FmEntryDataList::insert( std::unique_ptr<FmEntryData> pItem, size_t Index )
+{
+ if ( Index < maEntryDataList.size() )
+ {
+ maEntryDataList.insert( maEntryDataList.begin() + Index, std::move(pItem) );
+ }
+ else
+ maEntryDataList.push_back( std::move(pItem) );
+}
+
+
+void FmEntryDataList::clear()
+{
+ maEntryDataList.clear();
+}
+
+
+FmEntryData::FmEntryData( FmEntryData* pParentData, const Reference< XInterface >& _rxIFace )
+ :pParent( pParentData )
+{
+ pChildList.reset( new FmEntryDataList() );
+
+ newObject( _rxIFace );
+}
+
+
+FmEntryData::~FmEntryData()
+{
+ pChildList->clear();
+}
+
+
+void FmEntryData::newObject( const css::uno::Reference< css::uno::XInterface >& _rxIFace )
+{
+ // do not just copy, normalize it
+ m_xNormalizedIFace.set( _rxIFace, UNO_QUERY );
+ m_xProperties.set(m_xNormalizedIFace, css::uno::UNO_QUERY);
+ m_xChild.set(m_xNormalizedIFace, css::uno::UNO_QUERY);
+}
+
+
+FmEntryData::FmEntryData( const FmEntryData& rEntryData )
+{
+ pChildList.reset( new FmEntryDataList() );
+ aText = rEntryData.GetText();
+ m_aNormalImage = rEntryData.GetNormalImage();
+ pParent = rEntryData.GetParent();
+
+ FmEntryData* pChildData;
+ size_t nEntryCount = rEntryData.GetChildList()->size();
+ for( size_t i = 0; i < nEntryCount; i++ )
+ {
+ pChildData = rEntryData.GetChildList()->at( i );
+ std::unique_ptr<FmEntryData> pNewChildData = pChildData->Clone();
+ pChildList->insert( std::move(pNewChildData), size_t(-1) );
+ }
+
+ m_xNormalizedIFace = rEntryData.m_xNormalizedIFace;
+ m_xProperties = rEntryData.m_xProperties;
+ m_xChild = rEntryData.m_xChild;
+}
+
+
+
+bool FmEntryData::IsEqualWithoutChildren( FmEntryData* pEntryData )
+{
+ if(this == pEntryData)
+ return true;
+
+ if( !pEntryData )
+ return false;
+
+ if( aText != pEntryData->GetText() )
+ return false;
+
+ if( !pEntryData->GetParent() && pParent )
+ return false;
+
+ if( pEntryData->GetParent() && !pParent )
+ return false;
+
+ if( !pEntryData->GetParent() && !pParent )
+ return true;
+
+ if( !pParent->IsEqualWithoutChildren(pEntryData->GetParent()) )
+ return false;
+
+ return true;
+}
+
+FmFormData::FmFormData(const Reference< XForm >& _rxForm, FmFormData* _pParent)
+ : FmEntryData(_pParent, _rxForm)
+ , m_xForm(_rxForm)
+{
+ // set images
+ m_aNormalImage = RID_SVXBMP_FORM;
+
+ // set title
+ if (m_xForm.is())
+ {
+ Reference< XPropertySet > xSet(m_xForm, UNO_QUERY);
+ if (xSet.is())
+ {
+ OUString aEntryName(::comphelper::getString(xSet->getPropertyValue( FM_PROP_NAME )));
+ SetText(aEntryName);
+ }
+ }
+ else
+ SetText( OUString() );
+}
+
+FmFormData::~FmFormData()
+{
+}
+
+FmFormData::FmFormData( const FmFormData& rFormData )
+ :FmEntryData( rFormData )
+{
+ m_xForm = rFormData.GetFormIface();
+}
+
+
+std::unique_ptr<FmEntryData> FmFormData::Clone()
+{
+ return std::unique_ptr<FmEntryData>(new FmFormData( *this ));
+}
+
+
+bool FmFormData::IsEqualWithoutChildren( FmEntryData* pEntryData )
+{
+ if(this == pEntryData)
+ return true;
+ FmFormData* pFormData = dynamic_cast<FmFormData*>(pEntryData);
+ if( !pFormData )
+ return false;
+ if( m_xForm.get() != pFormData->GetFormIface().get() )
+ return false;
+
+ return FmEntryData::IsEqualWithoutChildren( pFormData );
+}
+
+FmControlData::FmControlData(const Reference< XFormComponent >& _rxComponent, FmFormData* _pParent)
+: FmEntryData( _pParent, _rxComponent ),
+ m_xFormComponent( _rxComponent )
+{
+
+ // set images
+ m_aNormalImage = GetImage();
+
+
+ // set title
+ Reference< XPropertySet > xSet(m_xFormComponent, UNO_QUERY);
+ if( xSet.is() )
+ {
+ SetText( ::comphelper::getString(xSet->getPropertyValue( FM_PROP_NAME )));
+ }
+}
+
+
+FmControlData::~FmControlData()
+{
+}
+
+
+FmControlData::FmControlData( const FmControlData& rControlData )
+ :FmEntryData( rControlData )
+{
+ m_xFormComponent = rControlData.GetFormComponent();
+}
+
+
+std::unique_ptr<FmEntryData> FmControlData::Clone()
+{
+ return std::unique_ptr<FmEntryData>(new FmControlData( *this ));
+}
+
+
+OUString FmControlData::GetImage() const
+{
+ // Default-Image
+ OUString aImage(RID_SVXBMP_CONTROL);
+
+ Reference< XServiceInfo > xInfo( m_xFormComponent, UNO_QUERY );
+ if (!m_xFormComponent.is())
+ return aImage;
+
+
+ // Spezielle Control-Images
+ SdrObjKind nObjectType = getControlTypeByObject(xInfo);
+ switch (nObjectType)
+ {
+ case SdrObjKind::FormButton:
+ aImage = RID_SVXBMP_BUTTON;
+ break;
+
+ case SdrObjKind::FormFixedText:
+ aImage = RID_SVXBMP_FIXEDTEXT;
+ break;
+
+ case SdrObjKind::FormEdit:
+ aImage = RID_SVXBMP_EDITBOX;
+ break;
+
+ case SdrObjKind::FormRadioButton:
+ aImage = RID_SVXBMP_RADIOBUTTON;
+ break;
+
+ case SdrObjKind::FormCheckbox:
+ aImage = RID_SVXBMP_CHECKBOX;
+ break;
+
+ case SdrObjKind::FormListbox:
+ aImage = RID_SVXBMP_LISTBOX;
+ break;
+
+ case SdrObjKind::FormCombobox:
+ aImage = RID_SVXBMP_COMBOBOX;
+ break;
+
+ case SdrObjKind::FormNavigationBar:
+ aImage = RID_SVXBMP_NAVIGATIONBAR;
+ break;
+
+ case SdrObjKind::FormGroupBox:
+ aImage = RID_SVXBMP_GROUPBOX;
+ break;
+
+ case SdrObjKind::FormImageButton:
+ aImage = RID_SVXBMP_IMAGEBUTTON;
+ break;
+
+ case SdrObjKind::FormFileControl:
+ aImage = RID_SVXBMP_FILECONTROL;
+ break;
+
+ case SdrObjKind::FormHidden:
+ aImage = RID_SVXBMP_HIDDEN;
+ break;
+
+ case SdrObjKind::FormDateField:
+ aImage = RID_SVXBMP_DATEFIELD;
+ break;
+
+ case SdrObjKind::FormTimeField:
+ aImage = RID_SVXBMP_TIMEFIELD;
+ break;
+
+ case SdrObjKind::FormNumericField:
+ aImage = RID_SVXBMP_NUMERICFIELD;
+ break;
+
+ case SdrObjKind::FormCurrencyField:
+ aImage = RID_SVXBMP_CURRENCYFIELD;
+ break;
+
+ case SdrObjKind::FormPatternField:
+ aImage = RID_SVXBMP_PATTERNFIELD;
+ break;
+
+ case SdrObjKind::FormImageControl:
+ aImage = RID_SVXBMP_IMAGECONTROL;
+ break;
+
+ case SdrObjKind::FormFormattedField:
+ aImage = RID_SVXBMP_FORMATTEDFIELD;
+ break;
+
+ case SdrObjKind::FormGrid:
+ aImage = RID_SVXBMP_GRID;
+ break;
+
+ case SdrObjKind::FormScrollbar:
+ aImage = RID_SVXBMP_SCROLLBAR;
+ break;
+
+ case SdrObjKind::FormSpinButton:
+ aImage = RID_SVXBMP_SPINBUTTON;
+ break;
+
+ default:;
+ }
+
+ return aImage;
+}
+
+bool FmControlData::IsEqualWithoutChildren( FmEntryData* pEntryData )
+{
+ if(this == pEntryData)
+ return true;
+
+ FmControlData* pControlData = dynamic_cast<FmControlData*>(pEntryData);
+ if( !pControlData )
+ return false;
+
+ if( m_xFormComponent.get() != pControlData->GetFormComponent().get() )
+ return false;
+
+ return FmEntryData::IsEqualWithoutChildren( pControlData );
+}
+
+void FmControlData::ModelReplaced(const Reference< XFormComponent >& _rxNew)
+{
+ m_xFormComponent = _rxNew;
+ newObject( m_xFormComponent );
+ // set images anew
+ m_aNormalImage = GetImage();
+}
+
+namespace svxform
+{
+
+ NavigatorFrame::NavigatorFrame( SfxBindings* _pBindings, SfxChildWindow* _pMgr,
+ vcl::Window* _pParent )
+ : SfxDockingWindow(_pBindings, _pMgr, _pParent, "FormNavigator", "svx/ui/formnavigator.ui")
+ , SfxControllerItem( SID_FM_FMEXPLORER_CONTROL, *_pBindings )
+ , m_xNavigatorTree(new NavigatorTree(m_xBuilder->weld_tree_view("treeview")))
+ {
+ SetHelpId( HID_FORM_NAVIGATOR_WIN );
+
+ SetText( SvxResId(RID_STR_FMEXPLORER) );
+ SfxDockingWindow::SetFloatingSize( Size(200,200) );
+ }
+
+ NavigatorFrame::~NavigatorFrame()
+ {
+ disposeOnce();
+ }
+
+ void NavigatorFrame::dispose()
+ {
+ m_xNavigatorTree.reset();
+ ::SfxControllerItem::dispose();
+ SfxDockingWindow::dispose();
+ }
+
+ void NavigatorFrame::UpdateContent( FmFormShell* pFormShell )
+ {
+ m_xNavigatorTree->UpdateContent(pFormShell);
+ }
+
+ void NavigatorFrame::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
+ {
+ if( !pState || SID_FM_FMEXPLORER_CONTROL != nSID )
+ return;
+
+ if( eState >= SfxItemState::DEFAULT )
+ {
+ FmFormShell* pShell = dynamic_cast<FmFormShell*>( static_cast<const SfxObjectItem*>(pState)->GetShell() );
+ UpdateContent( pShell );
+ }
+ else
+ UpdateContent( nullptr );
+ }
+
+ void NavigatorFrame::GetFocus()
+ {
+ if (m_xNavigatorTree )
+ m_xNavigatorTree->GrabFocus();
+ else
+ SfxDockingWindow::GetFocus();
+ }
+
+ bool NavigatorFrame::Close()
+ {
+ UpdateContent( nullptr );
+ return SfxDockingWindow::Close();
+ }
+
+ void NavigatorFrame::FillInfo( SfxChildWinInfo& rInfo ) const
+ {
+ SfxDockingWindow::FillInfo( rInfo );
+ rInfo.bVisible = false;
+ }
+
+ Size NavigatorFrame::CalcDockingSize( SfxChildAlignment eAlign )
+ {
+ if ( ( eAlign == SfxChildAlignment::TOP ) || ( eAlign == SfxChildAlignment::BOTTOM ) )
+ return Size();
+
+ return SfxDockingWindow::CalcDockingSize( eAlign );
+ }
+
+ SfxChildAlignment NavigatorFrame::CheckAlignment( SfxChildAlignment _eActAlign, SfxChildAlignment _eAlign )
+ {
+ if ( ( _eAlign == SfxChildAlignment::LEFT ) || ( _eAlign == SfxChildAlignment::RIGHT ) || ( _eAlign == SfxChildAlignment::NOALIGNMENT ) )
+ return _eAlign;
+ return _eActAlign;
+ }
+
+ SFX_IMPL_DOCKINGWINDOW( NavigatorFrameManager, SID_FM_SHOW_FMEXPLORER )
+
+ NavigatorFrameManager::NavigatorFrameManager( vcl::Window* _pParent, sal_uInt16 _nId,
+ SfxBindings* _pBindings, SfxChildWinInfo* _pInfo )
+ :SfxChildWindow( _pParent, _nId )
+ {
+ SetWindow( VclPtr<NavigatorFrame>::Create( _pBindings, this, _pParent ) );
+ static_cast<SfxDockingWindow*>(GetWindow())->Initialize( _pInfo );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmmodel.cxx b/svx/source/form/fmmodel.cxx
new file mode 100644
index 000000000..e518319aa
--- /dev/null
+++ b/svx/source/form/fmmodel.cxx
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <fmundo.hxx>
+#include <fmdocumentclassification.hxx>
+#include <fmcontrollayout.hxx>
+
+#include <com/sun/star/form/XForms.hpp>
+#include <svx/fmmodel.hxx>
+#include <svx/fmpage.hxx>
+
+#include <sfx2/objsh.hxx>
+#include <osl/diagnose.h>
+
+#include <optional>
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::container::XNameContainer;
+using namespace svxform;
+
+
+struct FmFormModelImplData
+{
+ rtl::Reference<FmXUndoEnvironment> mxUndoEnv;
+ bool bOpenInDesignIsDefaulted;
+ std::optional<bool> aControlsUseRefDevice;
+
+ FmFormModelImplData()
+ :bOpenInDesignIsDefaulted( true )
+ {
+ }
+};
+
+FmFormModel::FmFormModel(
+ SfxItemPool* pPool,
+ SfxObjectShell* pPers)
+: SdrModel(
+ pPool,
+ pPers)
+ , m_pObjShell(nullptr)
+ , m_bOpenInDesignMode(false)
+ , m_bAutoControlFocus(false)
+{
+ m_pImpl.reset( new FmFormModelImplData );
+ m_pImpl->mxUndoEnv = new FmXUndoEnvironment(*this);
+}
+
+FmFormModel::~FmFormModel()
+{
+ if (m_pObjShell && m_pImpl->mxUndoEnv->IsListening(*m_pObjShell))
+ SetObjectShell(nullptr);
+
+ ClearUndoBuffer();
+ // minimum limit for undos
+ SetMaxUndoActionCount(1);
+}
+
+rtl::Reference<SdrPage> FmFormModel::AllocPage(bool bMasterPage)
+{
+ return new FmFormPage(*this, bMasterPage);
+}
+
+void FmFormModel::InsertPage(SdrPage* pPage, sal_uInt16 nPos)
+{
+ // hack for as long as the method is internal
+ if (m_pObjShell && !m_pImpl->mxUndoEnv->IsListening( *m_pObjShell ))
+ SetObjectShell(m_pObjShell);
+
+ SdrModel::InsertPage( pPage, nPos );
+}
+
+rtl::Reference<SdrPage> FmFormModel::RemovePage(sal_uInt16 nPgNum)
+{
+ FmFormPage* pToBeRemovedPage = dynamic_cast< FmFormPage* >( GetPage( nPgNum ) );
+ OSL_ENSURE( pToBeRemovedPage, "FmFormModel::RemovePage: *which page*?" );
+
+ if ( pToBeRemovedPage )
+ {
+ Reference< XNameContainer > xForms( pToBeRemovedPage->GetForms( false ) );
+ if ( xForms.is() )
+ m_pImpl->mxUndoEnv->RemoveForms( xForms );
+ }
+
+ rtl::Reference<FmFormPage> pRemovedPage = static_cast<FmFormPage*>(SdrModel::RemovePage(nPgNum).get());
+ OSL_ENSURE( pRemovedPage == pToBeRemovedPage, "FmFormModel::RemovePage: inconsistency!" );
+ return pRemovedPage;
+}
+
+void FmFormModel::InsertMasterPage(SdrPage* pPage, sal_uInt16 nPos)
+{
+ // hack for as long as the method is internal
+ if (m_pObjShell && !m_pImpl->mxUndoEnv->IsListening( *m_pObjShell ))
+ SetObjectShell(m_pObjShell);
+
+ SdrModel::InsertMasterPage(pPage, nPos);
+}
+
+rtl::Reference<SdrPage> FmFormModel::RemoveMasterPage(sal_uInt16 nPgNum)
+{
+ rtl::Reference<FmFormPage> pPage = static_cast<FmFormPage*>(SdrModel::RemoveMasterPage(nPgNum).get());
+
+ if ( pPage )
+ {
+ Reference< XNameContainer > xForms( pPage->GetForms( false ) );
+ if ( xForms.is() )
+ m_pImpl->mxUndoEnv->RemoveForms( xForms );
+ }
+
+ return pPage;
+}
+
+
+void FmFormModel::implSetOpenInDesignMode( bool _bOpenDesignMode )
+{
+ if( _bOpenDesignMode != m_bOpenInDesignMode )
+ {
+ m_bOpenInDesignMode = _bOpenDesignMode;
+
+ if ( m_pObjShell )
+ m_pObjShell->SetModified();
+ }
+ // no matter if we really did it or not - from now on, it does not count as defaulted anymore
+ m_pImpl->bOpenInDesignIsDefaulted = false;
+}
+
+
+void FmFormModel::SetOpenInDesignMode( bool bOpenDesignMode )
+{
+ implSetOpenInDesignMode( bOpenDesignMode );
+}
+
+
+bool FmFormModel::OpenInDesignModeIsDefaulted( )
+{
+ return m_pImpl->bOpenInDesignIsDefaulted;
+}
+
+
+bool FmFormModel::ControlsUseRefDevice() const
+{
+ if ( !m_pImpl->aControlsUseRefDevice )
+ {
+ DocumentType eDocType = eUnknownDocumentType;
+ if ( m_pObjShell )
+ eDocType = DocumentClassification::classifyHostDocument( m_pObjShell->GetModel() );
+ m_pImpl->aControlsUseRefDevice = ControlLayouter::useDocumentReferenceDevice(eDocType);
+ }
+ return *m_pImpl->aControlsUseRefDevice;
+}
+
+
+void FmFormModel::SetAutoControlFocus( bool _bAutoControlFocus )
+{
+ if( _bAutoControlFocus != m_bAutoControlFocus )
+ {
+ m_bAutoControlFocus = _bAutoControlFocus;
+ m_pObjShell->SetModified();
+ }
+}
+
+
+void FmFormModel::SetObjectShell( SfxObjectShell* pShell )
+{
+ if (pShell == m_pObjShell)
+ return;
+
+ if (m_pObjShell)
+ {
+ m_pImpl->mxUndoEnv->EndListening( *this );
+ m_pImpl->mxUndoEnv->EndListening( *m_pObjShell );
+ }
+
+ m_pObjShell = pShell;
+
+ if (m_pObjShell)
+ {
+ m_pImpl->mxUndoEnv->SetReadOnly( m_pObjShell->IsReadOnly() || m_pObjShell->IsReadOnlyUI(), FmXUndoEnvironment::Accessor() );
+
+ if (!m_pImpl->mxUndoEnv->IsReadOnly())
+ m_pImpl->mxUndoEnv->StartListening(*this);
+
+ m_pImpl->mxUndoEnv->StartListening( *m_pObjShell );
+ }
+}
+
+
+FmXUndoEnvironment& FmFormModel::GetUndoEnv()
+{
+ return *m_pImpl->mxUndoEnv;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmobj.cxx b/svx/source/form/fmobj.cxx
new file mode 100644
index 000000000..e337f79d7
--- /dev/null
+++ b/svx/source/form/fmobj.cxx
@@ -0,0 +1,653 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fmobj.hxx>
+#include <fmprop.hxx>
+#include <fmvwimp.hxx>
+#include <fmpgeimp.hxx>
+#include <o3tl/string_view.hxx>
+#include <svx/fmview.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/svdovirt.hxx>
+#include <svx/fmmodel.hxx>
+
+#include <com/sun/star/awt/XDevice.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/form/Forms.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <svx/fmtools.hxx>
+
+#include <comphelper/property.hxx>
+#include <comphelper/processfactory.hxx>
+#include <toolkit/awt/vclxdevice.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::container;
+using namespace ::svxform;
+
+
+FmFormObj::FmFormObj(
+ SdrModel& rSdrModel,
+ const OUString& rModelName)
+: SdrUnoObj(rSdrModel, rModelName)
+ ,m_nPos(-1)
+ ,m_pLastKnownRefDevice(nullptr)
+{
+ // normally, this is done in SetUnoControlModel, but if the call happened in the base class ctor,
+ // then our incarnation of it was not called (since we were not constructed at this time).
+ impl_checkRefDevice_nothrow( true );
+}
+
+FmFormObj::FmFormObj(SdrModel& rSdrModel)
+: SdrUnoObj(rSdrModel, "")
+ ,m_nPos(-1)
+ ,m_pLastKnownRefDevice(nullptr)
+{
+ // Stuff that old SetModel also did:
+ impl_checkRefDevice_nothrow();
+}
+
+FmFormObj::FmFormObj(SdrModel& rSdrModel, FmFormObj const & rSource)
+: SdrUnoObj(rSdrModel, rSource)
+ ,m_nPos(-1)
+ ,m_pLastKnownRefDevice(nullptr)
+{
+ // Stuff that old SetModel also did:
+ impl_checkRefDevice_nothrow();
+
+ // If UnoControlModel is part of an event environment,
+ // events may assigned to it.
+ Reference< XFormComponent > xContent(rSource.xUnoControlModel, UNO_QUERY);
+ if (xContent.is())
+ {
+ Reference< XEventAttacherManager > xManager(xContent->getParent(), UNO_QUERY);
+ Reference< XIndexAccess > xManagerAsIndex(xManager, UNO_QUERY);
+ if (xManagerAsIndex.is())
+ {
+ sal_Int32 nPos = getElementPos( xManagerAsIndex, xContent );
+ if ( nPos >= 0 )
+ aEvts = xManager->getScriptEvents( nPos );
+ }
+ }
+ else
+ aEvts = rSource.aEvts;
+
+ Reference< XChild > xSourceAsChild(rSource.GetUnoControlModel(), UNO_QUERY);
+ if (!xSourceAsChild.is())
+ return;
+
+ Reference< XInterface > xSourceContainer = xSourceAsChild->getParent();
+
+ m_xEnvironmentHistory = css::form::Forms::create( comphelper::getProcessComponentContext() );
+
+ ensureModelEnv(xSourceContainer, m_xEnvironmentHistory);
+ m_aEventsHistory = aEvts;
+ // if we were clone there was a call to operator=, so aEvts are exactly the events we need here...
+}
+
+FmFormObj::~FmFormObj()
+{
+
+ if (m_xEnvironmentHistory.is())
+ m_xEnvironmentHistory->dispose();
+
+ m_xEnvironmentHistory = nullptr;
+ m_aEventsHistory.realloc(0);
+}
+
+
+void FmFormObj::SetObjEnv(const Reference< XIndexContainer > & xForm, const sal_Int32 nIdx,
+ const Sequence< ScriptEventDescriptor >& rEvts)
+{
+ m_xParent = xForm;
+ aEvts = rEvts;
+ m_nPos = nIdx;
+}
+
+
+void FmFormObj::ClearObjEnv()
+{
+ m_xParent.clear();
+ aEvts.realloc( 0 );
+ m_nPos = -1;
+}
+
+
+void FmFormObj::impl_checkRefDevice_nothrow( bool _force )
+{
+ const FmFormModel* pFormModel = dynamic_cast<FmFormModel*>(&getSdrModelFromSdrObject());
+ if ( !pFormModel || !pFormModel->ControlsUseRefDevice() )
+ return;
+
+ OutputDevice* pCurrentRefDevice = pFormModel->GetRefDevice();
+ if ( ( m_pLastKnownRefDevice.get() == pCurrentRefDevice ) && !_force )
+ return;
+
+ Reference< XControlModel > xControlModel( GetUnoControlModel() );
+ if ( !xControlModel.is() )
+ return;
+
+ m_pLastKnownRefDevice = pCurrentRefDevice;
+ if ( !m_pLastKnownRefDevice )
+ return;
+
+ try
+ {
+ Reference< XPropertySet > xModelProps( GetUnoControlModel(), UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xPropertyInfo( xModelProps->getPropertySetInfo(), UNO_SET_THROW );
+
+ static constexpr OUStringLiteral sRefDevicePropName = u"ReferenceDevice";
+ if ( xPropertyInfo->hasPropertyByName( sRefDevicePropName ) )
+ {
+ rtl::Reference<VCLXDevice> pUnoRefDevice = new VCLXDevice;
+ pUnoRefDevice->SetOutputDevice( m_pLastKnownRefDevice );
+ Reference< XDevice > xRefDevice( pUnoRefDevice );
+ xModelProps->setPropertyValue( sRefDevicePropName, Any( xRefDevice ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+void FmFormObj::impl_isolateControlModel_nothrow()
+{
+ try
+ {
+ Reference< XChild > xControlModel( GetUnoControlModel(), UNO_QUERY );
+ if ( xControlModel.is() )
+ {
+ Reference< XIndexContainer> xParent( xControlModel->getParent(), UNO_QUERY );
+ if ( xParent.is() )
+ {
+ sal_Int32 nPos = getElementPos( xParent, xControlModel );
+ xParent->removeByIndex( nPos );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+void FmFormObj::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ FmFormPage* pOldFormPage(dynamic_cast< FmFormPage* >(getSdrPageFromSdrObject()));
+ if ( pOldFormPage )
+ pOldFormPage->GetImpl().formObjectRemoved( *this );
+
+ FmFormPage* pNewFormPage = dynamic_cast<FmFormPage*>( pNewPage );
+ if ( !pNewFormPage )
+ {
+ // Maybe it makes sense to create an environment history here : if somebody set's our page to NULL, and we have a valid page before,
+ // me may want to remember our place within the old page. For this we could create a new m_xEnvironmentHistory to store it.
+ // So the next SetPage with a valid new page would restore that environment within the new page.
+ // But for the original Bug (#57300#) we don't need that, so I omit it here. Maybe this will be implemented later.
+ impl_isolateControlModel_nothrow();
+ SdrUnoObj::handlePageChange(pOldPage, pNewPage);
+ return;
+ }
+
+ Reference< css::form::XForms > xNewPageForms = pNewFormPage->GetForms();
+ Reference< XIndexContainer > xNewParent;
+ Sequence< ScriptEventDescriptor> aNewEvents;
+
+ // calc the new parent for my model (within the new page's forms hierarchy)
+ // do we have a history ? (from :Clone)
+ if ( m_xEnvironmentHistory.is() )
+ {
+ // the element in m_xEnvironmentHistory which is equivalent to my new parent (which (perhaps) has to be created within pNewPage->GetForms)
+ // is the right-most element in the tree.
+ Reference< XIndexContainer > xRightMostLeaf( m_xEnvironmentHistory, UNO_QUERY_THROW );
+ try
+ {
+ while ( xRightMostLeaf->getCount() )
+ {
+ xRightMostLeaf.set(
+ xRightMostLeaf->getByIndex( xRightMostLeaf->getCount() - 1 ),
+ UNO_QUERY_THROW
+ );
+ }
+
+ xNewParent.set( ensureModelEnv( xRightMostLeaf, xNewPageForms ), UNO_QUERY_THROW );
+
+ // we successfully cloned the environment in m_xEnvironmentHistory, so we can use m_aEventsHistory
+ // (which describes the events of our model at the moment m_xEnvironmentHistory was created)
+ aNewEvents = m_aEventsHistory;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+ if ( !xNewParent.is() )
+ {
+ // are we a valid part of our current page forms ?
+ Reference< XIndexContainer > xOldForms;
+ if ( pOldFormPage )
+ xOldForms.set( pOldFormPage->GetForms(), UNO_QUERY_THROW );
+
+ if ( xOldForms.is() )
+ {
+ // search (upward from our model) for xOldForms
+ Reference< XChild > xSearch( GetUnoControlModel(), UNO_QUERY );
+ while (xSearch.is())
+ {
+ if ( xSearch == xOldForms )
+ break;
+ xSearch.set( xSearch->getParent(), UNO_QUERY );
+ }
+ if ( xSearch.is() ) // implies xSearch == xOldForms, which means we're a valid part of our current page forms hierarchy
+ {
+ Reference< XChild > xMeAsChild( GetUnoControlModel(), UNO_QUERY );
+ xNewParent.set( ensureModelEnv( xMeAsChild->getParent(), xNewPageForms ), UNO_QUERY );
+
+ if ( xNewParent.is() )
+ {
+ try
+ {
+ // transfer the events from our (model's) parent to the new (model's) parent, too
+ Reference< XEventAttacherManager > xEventManager(xMeAsChild->getParent(), UNO_QUERY);
+ Reference< XIndexAccess > xManagerAsIndex(xEventManager, UNO_QUERY);
+ if (xManagerAsIndex.is())
+ {
+ sal_Int32 nPos = getElementPos(xManagerAsIndex, xMeAsChild);
+ if (nPos >= 0)
+ aNewEvents = xEventManager->getScriptEvents(nPos);
+ }
+ else
+ aNewEvents = aEvts;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+ }
+ }
+
+ // now set the page
+ SdrUnoObj::handlePageChange(pOldPage, pNewPage);
+
+ // place my model within the new parent container
+ if (xNewParent.is())
+ {
+ Reference< XFormComponent > xMeAsFormComp(GetUnoControlModel(), UNO_QUERY);
+ if (xMeAsFormComp.is())
+ {
+ // check if I have another parent (and remove me, if necessary)
+ Reference< XIndexContainer > xOldParent(xMeAsFormComp->getParent(), UNO_QUERY);
+ if (xOldParent.is())
+ {
+ sal_Int32 nPos = getElementPos(xOldParent, xMeAsFormComp);
+ if (nPos > -1)
+ xOldParent->removeByIndex(nPos);
+ }
+
+ // and insert into the new container
+ xNewParent->insertByIndex(xNewParent->getCount(), Any(xMeAsFormComp));
+
+ // transfer the events
+ if (aNewEvents.hasElements())
+ {
+ try
+ {
+ Reference< XEventAttacherManager > xEventManager(xNewParent, UNO_QUERY);
+ Reference< XIndexAccess > xManagerAsIndex(xEventManager, UNO_QUERY);
+ if (xManagerAsIndex.is())
+ {
+ sal_Int32 nPos = getElementPos(xManagerAsIndex, xMeAsFormComp);
+ DBG_ASSERT(nPos >= 0, "FmFormObj::SetPage : inserted but not present ?");
+ xEventManager->registerScriptEvents(nPos, aNewEvents);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ }
+ }
+ }
+
+ // delete my history
+ if (m_xEnvironmentHistory.is())
+ m_xEnvironmentHistory->dispose();
+
+ m_xEnvironmentHistory = nullptr;
+ m_aEventsHistory.realloc(0);
+
+ pNewFormPage->GetImpl().formObjectInserted( *this );
+}
+
+SdrInventor FmFormObj::GetObjInventor() const
+{
+ return SdrInventor::FmForm;
+}
+
+SdrObjKind FmFormObj::GetObjIdentifier() const
+{
+ return SdrObjKind::UNO;
+}
+
+FmFormObj* FmFormObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new FmFormObj(rTargetModel, *this);
+}
+
+void FmFormObj::NbcReformatText()
+{
+ impl_checkRefDevice_nothrow();
+ SdrUnoObj::NbcReformatText();
+}
+
+
+namespace
+{
+ OUString lcl_getFormComponentAccessPath(const Reference< XInterface >& _xElement, Reference< XInterface >& _rTopLevelElement)
+ {
+ Reference< css::form::XFormComponent> xChild(_xElement, UNO_QUERY);
+ Reference< css::container::XIndexAccess> xParent;
+ if (xChild.is())
+ xParent.set(xChild->getParent(), UNO_QUERY);
+
+ // while the current content is a form
+ OUString sReturn;
+ while (xChild.is())
+ {
+ // get the content's relative pos within its parent container
+ sal_Int32 nPos = getElementPos(xParent, xChild);
+
+ // prepend this current relative pos
+ OUString sCurrentIndex = OUString::number(nPos);
+ if (!sReturn.isEmpty())
+ {
+ sCurrentIndex += "\\" + sReturn;
+ }
+
+ sReturn = sCurrentIndex;
+
+ // travel up
+ xChild.set(xParent, css::uno::UNO_QUERY);
+ if (xChild.is())
+ xParent.set(xChild->getParent(), UNO_QUERY);
+ }
+
+ _rTopLevelElement = xParent;
+ return sReturn;
+ }
+}
+
+
+Reference< XInterface > FmFormObj::ensureModelEnv(const Reference< XInterface > & _rSourceContainer, const Reference<css::form::XForms>& _rTopLevelDestContainer)
+{
+ Reference< XInterface > xTopLevelSource;
+ OUString sAccessPath = lcl_getFormComponentAccessPath(_rSourceContainer, xTopLevelSource);
+ if (!xTopLevelSource.is())
+ // something went wrong, maybe _rSourceContainer isn't part of a valid forms hierarchy
+ return Reference< XInterface > ();
+
+ Reference< XIndexContainer > xDestContainer(_rTopLevelDestContainer, UNO_QUERY_THROW);
+ Reference< XIndexContainer > xSourceContainer(xTopLevelSource, UNO_QUERY);
+ DBG_ASSERT(xSourceContainer.is(), "FmFormObj::ensureModelEnv : the top level source is invalid !");
+
+ sal_Int32 nTokIndex = 0;
+ do
+ {
+ std::u16string_view aToken = o3tl::getToken(sAccessPath, 0, '\\', nTokIndex );
+ sal_uInt16 nIndex = static_cast<sal_uInt16>(o3tl::toInt32(aToken));
+
+ // get the DSS of the source form (we have to find an equivalent for)
+ DBG_ASSERT(nIndex<xSourceContainer->getCount(), "FmFormObj::ensureModelEnv : invalid access path !");
+ Reference< XPropertySet > xSourceForm;
+ xSourceContainer->getByIndex(nIndex) >>= xSourceForm;
+ DBG_ASSERT(xSourceForm.is(), "FmFormObj::ensureModelEnv : invalid source form !");
+
+ Any aSrcCursorSource, aSrcCursorSourceType, aSrcDataSource;
+ DBG_ASSERT(::comphelper::hasProperty(FM_PROP_COMMAND, xSourceForm) && ::comphelper::hasProperty(FM_PROP_COMMANDTYPE, xSourceForm)
+ && ::comphelper::hasProperty(FM_PROP_DATASOURCE, xSourceForm), "FmFormObj::ensureModelEnv : invalid access path or invalid form (missing props) !");
+ // the parent access path should refer to a row set
+ try
+ {
+ aSrcCursorSource = xSourceForm->getPropertyValue(FM_PROP_COMMAND);
+ aSrcCursorSourceType = xSourceForm->getPropertyValue(FM_PROP_COMMANDTYPE);
+ aSrcDataSource = xSourceForm->getPropertyValue(FM_PROP_DATASOURCE);
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("FmFormObj::ensureModelEnv : could not retrieve a source DSS !");
+ }
+
+
+ // calc the number of (source) form siblings with the same DSS
+ Reference< XPropertySet > xCurrentSourceForm, xCurrentDestForm;
+ sal_Int16 nCurrentSourceIndex = 0;
+ sal_Int32 nCurrentDestIndex = 0;
+ while (nCurrentSourceIndex <= nIndex)
+ {
+ bool bEqualDSS = false;
+ while (!bEqualDSS) // (we don't have to check nCurrentSourceIndex here : it's bound by nIndex)
+ {
+ xSourceContainer->getByIndex(nCurrentSourceIndex) >>= xCurrentSourceForm;
+ DBG_ASSERT(xCurrentSourceForm.is(), "FmFormObj::ensureModelEnv : invalid form ancestor (2) !");
+ bEqualDSS = false;
+ if (::comphelper::hasProperty(FM_PROP_DATASOURCE, xCurrentSourceForm))
+ { // it is a form
+ try
+ {
+ if ( xCurrentSourceForm->getPropertyValue(FM_PROP_COMMAND) == aSrcCursorSource
+ && xCurrentSourceForm->getPropertyValue(FM_PROP_COMMANDTYPE) == aSrcCursorSourceType
+ && xCurrentSourceForm->getPropertyValue(FM_PROP_DATASOURCE) == aSrcDataSource
+ )
+ {
+ bEqualDSS = true;
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.form",
+ "exception while getting a sibling's DSS !");
+ }
+
+ }
+ ++nCurrentSourceIndex;
+ }
+
+ DBG_ASSERT(bEqualDSS, "FmFormObj::ensureModelEnv : found no source form !");
+ // ??? at least the nIndex-th one should have been found ???
+
+ // now search the next one with the given DSS (within the destination container)
+ bEqualDSS = false;
+ while (!bEqualDSS && (nCurrentDestIndex < xDestContainer->getCount()))
+ {
+ xDestContainer->getByIndex(nCurrentDestIndex) >>= xCurrentDestForm;
+ DBG_ASSERT(xCurrentDestForm.is(), "FmFormObj::ensureModelEnv : invalid destination form !");
+ bEqualDSS = false;
+ if (::comphelper::hasProperty(FM_PROP_DATASOURCE, xCurrentDestForm))
+ { // it is a form
+ try
+ {
+ if ( xCurrentDestForm->getPropertyValue(FM_PROP_COMMAND) == aSrcCursorSource
+ && xCurrentDestForm->getPropertyValue(FM_PROP_COMMANDTYPE) == aSrcCursorSourceType
+ && xCurrentDestForm->getPropertyValue(FM_PROP_DATASOURCE) == aSrcDataSource
+ )
+ {
+ bEqualDSS = true;
+ }
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.form",
+ "exception while getting a destination DSS !");
+ }
+
+ }
+ ++nCurrentDestIndex;
+ }
+
+ if (!bEqualDSS)
+ { // There is at least one more source form with the given DSS than destination forms are.
+ // correct this ...
+ try
+ {
+ // create and insert (into the destination) a copy of the form
+ xCurrentDestForm.set(
+ ::comphelper::getProcessServiceFactory()->createInstance("com.sun.star.form.component.DataForm"),
+ UNO_QUERY_THROW );
+ ::comphelper::copyProperties( xCurrentSourceForm, xCurrentDestForm );
+
+ DBG_ASSERT(nCurrentDestIndex == xDestContainer->getCount(), "FmFormObj::ensureModelEnv : something went wrong with the numbers !");
+ xDestContainer->insertByIndex(nCurrentDestIndex, Any(xCurrentDestForm));
+
+ ++nCurrentDestIndex;
+ // like nCurrentSourceIndex, nCurrentDestIndex now points 'behind' the form it actually means
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("FmFormObj::ensureModelEnv : something went seriously wrong while creating a new form !");
+ // no more options anymore ...
+ return Reference< XInterface > ();
+ }
+
+ }
+ }
+
+ // now xCurrentDestForm is a form equivalent to xSourceForm (which means they have the same DSS and the same number
+ // of left siblings with the same DSS, which counts for all their ancestors, too)
+
+ // go down
+ xDestContainer.set(xCurrentDestForm, UNO_QUERY);
+ xSourceContainer.set(xSourceForm, UNO_QUERY);
+ DBG_ASSERT(xDestContainer.is() && xSourceContainer.is(), "FmFormObj::ensureModelEnv : invalid container !");
+ }
+ while ( nTokIndex >= 0 );
+
+ return Reference<XInterface>( xDestContainer, UNO_QUERY );
+}
+
+FmFormObj* FmFormObj::GetFormObject( SdrObject* _pSdrObject )
+{
+ FmFormObj* pFormObject = dynamic_cast< FmFormObj* >( _pSdrObject );
+ if ( !pFormObject )
+ {
+ SdrVirtObj* pVirtualObject = dynamic_cast< SdrVirtObj* >( _pSdrObject );
+ if ( pVirtualObject )
+ pFormObject = dynamic_cast< FmFormObj* >( &pVirtualObject->ReferencedObj() );
+ }
+ return pFormObject;
+}
+
+
+const FmFormObj* FmFormObj::GetFormObject( const SdrObject* _pSdrObject )
+{
+ const FmFormObj* pFormObject = dynamic_cast< const FmFormObj* >( _pSdrObject );
+ if ( !pFormObject )
+ {
+ const SdrVirtObj* pVirtualObject = dynamic_cast< const SdrVirtObj* >( _pSdrObject );
+ if ( pVirtualObject )
+ pFormObject = dynamic_cast< const FmFormObj* >( &pVirtualObject->GetReferencedObj() );
+ }
+ return pFormObject;
+}
+
+
+void FmFormObj::SetUnoControlModel( const Reference< css::awt::XControlModel >& _rxModel )
+{
+ SdrUnoObj::SetUnoControlModel( _rxModel );
+
+ FmFormPage* pFormPage(dynamic_cast< FmFormPage* >(getSdrPageFromSdrObject()));
+ if ( pFormPage )
+ pFormPage->GetImpl().formModelAssigned( *this );
+
+ impl_checkRefDevice_nothrow( true );
+}
+
+
+bool FmFormObj::EndCreate( SdrDragStat& rStat, SdrCreateCmd eCmd )
+{
+ bool bResult = SdrUnoObj::EndCreate(rStat, eCmd);
+ if ( bResult && SdrCreateCmd::ForceEnd == eCmd && rStat.GetView() )
+ {
+ FmFormPage* pFormPage(dynamic_cast< FmFormPage* >(getSdrPageFromSdrObject()));
+
+ if (nullptr != pFormPage)
+ {
+ try
+ {
+ Reference< XFormComponent > xContent( xUnoControlModel, UNO_QUERY_THROW );
+ Reference< XForm > xParentForm( xContent->getParent(), UNO_QUERY );
+
+ Reference< XIndexContainer > xFormToInsertInto;
+
+ if ( !xParentForm.is() )
+ { // model is not yet part of a form component hierarchy
+ xParentForm.set( pFormPage->GetImpl().findPlaceInFormComponentHierarchy( xContent ), UNO_SET_THROW );
+ xFormToInsertInto.set( xParentForm, UNO_QUERY_THROW );
+ }
+
+ FmFormPageImpl::setUniqueName( xContent, xParentForm );
+
+ if ( xFormToInsertInto.is() )
+ xFormToInsertInto->insertByIndex( xFormToInsertInto->getCount(), Any( xContent ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+ FmFormView* pView( dynamic_cast< FmFormView* >( rStat.GetView() ) );
+ FmXFormView* pViewImpl = pView ? pView->GetImpl() : nullptr;
+ OSL_ENSURE( pViewImpl, "FmFormObj::EndCreate: no view!?" );
+ if ( pViewImpl )
+ pViewImpl->onCreatedFormObject( *this );
+ }
+ return bResult;
+}
+
+
+void FmFormObj::BrkCreate( SdrDragStat& rStat )
+{
+ SdrUnoObj::BrkCreate( rStat );
+ impl_isolateControlModel_nothrow();
+
+ FmFormView* pView( dynamic_cast< FmFormView* >( rStat.GetView() ) );
+ FmXFormView* pViewImpl = pView ? pView->GetImpl() : nullptr;
+ OSL_ENSURE( pViewImpl, "FmFormObj::EndCreate: no view!?" );
+ if ( pViewImpl )
+ pViewImpl->breakCreateFormObject();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmobjfac.cxx b/svx/source/form/fmobjfac.cxx
new file mode 100644
index 000000000..7bdf2d4cc
--- /dev/null
+++ b/svx/source/form/fmobjfac.cxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+#include <config_fuzzers.h>
+
+#include <tools/diagnose_ex.h>
+#include <svx/svdobj.hxx>
+#include <svx/fmtools.hxx>
+#include <fmservs.hxx>
+
+#include <svx/fmobjfac.hxx>
+
+#include <svx/svdobjkind.hxx>
+
+#include <fmobj.hxx>
+
+#include <svx/fmshell.hxx>
+
+#include <svx/svxids.hrc>
+#include <tbxform.hxx>
+
+#include <tabwin.hxx>
+#include <fmexpl.hxx>
+#include <filtnav.hxx>
+
+#include <fmprop.hxx>
+#include <fmPropBrw.hxx>
+#include <datanavi.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::svxform;
+
+static bool bInit = false;
+
+FmFormObjFactory::FmFormObjFactory()
+{
+ if ( bInit )
+ return;
+
+ SdrObjFactory::InsertMakeObjectHdl(LINK(this, FmFormObjFactory, MakeObject));
+
+
+ // register the configuration css::frame::Controller and the NavigationBar
+ SvxFmTbxCtlAbsRec::RegisterControl( SID_FM_RECORD_ABSOLUTE );
+ SvxFmTbxCtlRecText::RegisterControl( SID_FM_RECORD_TEXT );
+ SvxFmTbxCtlRecFromText::RegisterControl( SID_FM_RECORD_FROM_TEXT );
+ SvxFmTbxCtlRecTotal::RegisterControl( SID_FM_RECORD_TOTAL );
+ SvxFmTbxPrevRec::RegisterControl( SID_FM_RECORD_PREV );
+ SvxFmTbxNextRec::RegisterControl( SID_FM_RECORD_NEXT );
+
+ // registering global windows
+ FmFieldWinMgr::RegisterChildWindow();
+ FmPropBrwMgr::RegisterChildWindow();
+ NavigatorFrameManager::RegisterChildWindow();
+ DataNavigatorManager::RegisterChildWindow();
+#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
+ FmFilterNavigatorWinMgr::RegisterChildWindow();
+#endif
+
+ // register the interface for the Formshell
+ FmFormShell::RegisterInterface();
+
+ ImplSmartRegisterUnoServices();
+ bInit = true;
+}
+
+// create css::form::Form objects
+namespace
+{
+ void lcl_initProperty( FmFormObj const * _pObject, const OUString& _rPropName, const Any& _rValue )
+ {
+ try
+ {
+ Reference< XPropertySet > xModelSet( _pObject->GetUnoControlModel(), UNO_QUERY );
+ if ( xModelSet.is() )
+ xModelSet->setPropertyValue( _rPropName, _rValue );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "lcl_initProperty" );
+ }
+ }
+}
+
+IMPL_STATIC_LINK(FmFormObjFactory, MakeObject, SdrObjCreatorParams, aParams, SdrObject*)
+{
+ SdrObject* pNewObj = nullptr;
+
+ if (aParams.nInventor == SdrInventor::FmForm)
+ {
+ OUString sServiceSpecifier;
+
+ typedef ::std::vector< ::std::pair< OUString, Any > > PropertyValueArray;
+ PropertyValueArray aInitialProperties;
+
+ switch ( aParams.nObjIdentifier )
+ {
+ case SdrObjKind::FormEdit:
+ sServiceSpecifier = FM_COMPONENT_EDIT;
+ break;
+
+ case SdrObjKind::FormButton:
+ sServiceSpecifier = FM_COMPONENT_COMMANDBUTTON;
+ break;
+
+ case SdrObjKind::FormFixedText:
+ sServiceSpecifier = FM_COMPONENT_FIXEDTEXT;
+ break;
+
+ case SdrObjKind::FormListbox:
+ sServiceSpecifier = FM_COMPONENT_LISTBOX;
+ break;
+
+ case SdrObjKind::FormCheckbox:
+ sServiceSpecifier = FM_COMPONENT_CHECKBOX;
+ break;
+
+ case SdrObjKind::FormRadioButton:
+ sServiceSpecifier = FM_COMPONENT_RADIOBUTTON;
+ break;
+
+ case SdrObjKind::FormGroupBox:
+ sServiceSpecifier = FM_COMPONENT_GROUPBOX;
+ break;
+
+ case SdrObjKind::FormCombobox:
+ sServiceSpecifier = FM_COMPONENT_COMBOBOX;
+ break;
+
+ case SdrObjKind::FormGrid:
+ sServiceSpecifier = FM_COMPONENT_GRID;
+ break;
+
+ case SdrObjKind::FormImageButton:
+ sServiceSpecifier = FM_COMPONENT_IMAGEBUTTON;
+ break;
+
+ case SdrObjKind::FormFileControl:
+ sServiceSpecifier = FM_COMPONENT_FILECONTROL;
+ break;
+
+ case SdrObjKind::FormDateField:
+ sServiceSpecifier = FM_COMPONENT_DATEFIELD;
+ break;
+
+ case SdrObjKind::FormTimeField:
+ sServiceSpecifier = FM_COMPONENT_TIMEFIELD;
+ aInitialProperties.emplace_back( FM_PROP_TIMEMAX, Any( tools::Time( 23, 59, 59, 999999999 ).GetUNOTime() ) );
+ break;
+
+ case SdrObjKind::FormNumericField:
+ sServiceSpecifier = FM_COMPONENT_NUMERICFIELD;
+ break;
+
+ case SdrObjKind::FormCurrencyField:
+ sServiceSpecifier = FM_COMPONENT_CURRENCYFIELD;
+ break;
+
+ case SdrObjKind::FormPatternField:
+ sServiceSpecifier = FM_COMPONENT_PATTERNFIELD;
+ break;
+
+ case SdrObjKind::FormHidden:
+ sServiceSpecifier = FM_COMPONENT_HIDDEN;
+ break;
+
+ case SdrObjKind::FormImageControl:
+ sServiceSpecifier = FM_COMPONENT_IMAGECONTROL;
+ break;
+
+ case SdrObjKind::FormFormattedField:
+ sServiceSpecifier = FM_COMPONENT_FORMATTEDFIELD;
+ break;
+
+ case SdrObjKind::FormNavigationBar:
+ sServiceSpecifier = FM_SUN_COMPONENT_NAVIGATIONBAR;
+ break;
+
+ case SdrObjKind::FormScrollbar:
+ sServiceSpecifier = FM_SUN_COMPONENT_SCROLLBAR;
+ aInitialProperties.emplace_back( FM_PROP_BORDER, Any( sal_Int16(0) ) );
+ break;
+
+ case SdrObjKind::FormSpinButton:
+ sServiceSpecifier = FM_SUN_COMPONENT_SPINBUTTON;
+ aInitialProperties.emplace_back( FM_PROP_BORDER, Any( sal_Int16(0) ) );
+ break;
+
+ default:
+ break;
+ }
+
+ // create the actual object
+ if ( !sServiceSpecifier.isEmpty() )
+ pNewObj = new FmFormObj(aParams.rSdrModel, sServiceSpecifier);
+ else
+ pNewObj = new FmFormObj(aParams.rSdrModel);
+
+ // initialize some properties which we want to differ from the defaults
+ for (const auto& rInitProp : aInitialProperties)
+ {
+ lcl_initProperty(
+ static_cast< FmFormObj* >( pNewObj ),
+ rInitProp.first,
+ rInitProp.second
+ );
+ }
+ }
+ return pNewObj;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmpage.cxx b/svx/source/form/fmpage.cxx
new file mode 100644
index 000000000..c4f0bcad5
--- /dev/null
+++ b/svx/source/form/fmpage.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/fmpage.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <svx/fmmodel.hxx>
+
+#include <fmobj.hxx>
+
+#include <fmpgeimp.hxx>
+
+#include <svx/svdview.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/help.hxx>
+#include <vcl/window.hxx>
+#include <osl/diagnose.h>
+
+
+#include <fmprop.hxx>
+#include <fmundo.hxx>
+using namespace ::svxform;
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::UNO_QUERY;
+
+
+FmFormPage::FmFormPage(FmFormModel& rModel, bool bMasterPage)
+: SdrPage(rModel, bMasterPage)
+ ,m_pImpl( new FmFormPageImpl( *this ) )
+{
+}
+
+void FmFormPage::lateInit(const FmFormPage& rPage)
+{
+ // call parent
+ SdrPage::lateInit( rPage );
+
+ // copy local variables (former stuff from copy constructor)
+ m_pImpl->initFrom( rPage.GetImpl() );
+ m_sPageName = rPage.m_sPageName;
+}
+
+
+FmFormPage::~FmFormPage()
+{
+}
+
+rtl::Reference<SdrPage> FmFormPage::CloneSdrPage(SdrModel& rTargetModel) const
+{
+ FmFormModel& rFmFormModel(static_cast< FmFormModel& >(rTargetModel));
+ rtl::Reference<FmFormPage> pClonedFmFormPage =
+ new FmFormPage(
+ rFmFormModel,
+ IsMasterPage());
+ pClonedFmFormPage->lateInit(*this);
+ return pClonedFmFormPage;
+}
+
+
+void FmFormPage::InsertObject(SdrObject* pObj, size_t nPos)
+{
+ SdrPage::InsertObject( pObj, nPos );
+ static_cast< FmFormModel& >(getSdrModelFromSdrPage()).GetUndoEnv().Inserted(pObj);
+}
+
+
+const Reference< css::form::XForms > & FmFormPage::GetForms( bool _bForceCreate ) const
+{
+ const SdrPage& rMasterPage( *this );
+ const FmFormPage* pFormPage = dynamic_cast< const FmFormPage* >( &rMasterPage );
+ OSL_ENSURE( pFormPage, "FmFormPage::GetForms: referenced page is no FmFormPage - is this allowed?!" );
+ if ( !pFormPage )
+ pFormPage = this;
+
+ return pFormPage->m_pImpl->getForms( _bForceCreate );
+}
+
+
+bool FmFormPage::RequestHelp( vcl::Window* pWindow, SdrView const * pView,
+ const HelpEvent& rEvt )
+{
+ if( pView->IsAction() )
+ return false;
+
+ Point aPos = rEvt.GetMousePosPixel();
+ aPos = pWindow->ScreenToOutputPixel( aPos );
+ aPos = pWindow->PixelToLogic( aPos );
+
+ SdrPageView* pPV = nullptr;
+ SdrObject* pObj = pView->PickObj(aPos, 0, pPV, SdrSearchOptions::DEEP);
+ if (!pObj)
+ return false;
+
+ FmFormObj* pFormObject = FmFormObj::GetFormObject( pObj );
+ if ( !pFormObject )
+ return false;
+
+ OUString aHelpText;
+ css::uno::Reference< css::beans::XPropertySet > xSet( pFormObject->GetUnoControlModel(), css::uno::UNO_QUERY );
+ if (xSet.is())
+ {
+ if (::comphelper::hasProperty(FM_PROP_HELPTEXT, xSet))
+ aHelpText = ::comphelper::getString(xSet->getPropertyValue(FM_PROP_HELPTEXT));
+
+ if (aHelpText.isEmpty() && ::comphelper::hasProperty(FM_PROP_TARGET_URL, xSet))
+ {
+ OUString aText = ::comphelper::getString(xSet->getPropertyValue(FM_PROP_TARGET_URL));
+ INetURLObject aUrl(aText);
+
+ // test if it is a protocol type that I want to display
+ INetProtocol aProtocol = aUrl.GetProtocol();
+ static const INetProtocol s_aQuickHelpSupported[] =
+ { INetProtocol::Ftp, INetProtocol::Http, INetProtocol::File, INetProtocol::Mailto,
+ INetProtocol::Https, INetProtocol::Javascript,
+ INetProtocol::Ldap
+ };
+ for (const INetProtocol& i : s_aQuickHelpSupported)
+ if (i == aProtocol)
+ {
+ aHelpText = aUrl.GetURLNoPass(INetURLObject::DecodeMechanism::Unambiguous);
+ break;
+ }
+ }
+ }
+ if ( !aHelpText.isEmpty() )
+ {
+ // display the help
+ tools::Rectangle aItemRect = pObj->GetCurrentBoundRect();
+ aItemRect = pWindow->LogicToPixel( aItemRect );
+ Point aPt = pWindow->OutputToScreenPixel( aItemRect.TopLeft() );
+ aItemRect.SetLeft( aPt.X() );
+ aItemRect.SetTop( aPt.Y() );
+ aPt = pWindow->OutputToScreenPixel( aItemRect.BottomRight() );
+ aItemRect.SetRight( aPt.X() );
+ aItemRect.SetBottom( aPt.Y() );
+ if( rEvt.GetMode() == HelpEventMode::BALLOON )
+ Help::ShowBalloon( pWindow, aItemRect.Center(), aItemRect, aHelpText);
+ else
+ Help::ShowQuickHelp( pWindow, aItemRect, aHelpText );
+ }
+ return true;
+}
+
+
+SdrObject* FmFormPage::RemoveObject(size_t nObjNum)
+{
+ SdrObject* pObj = SdrPage::RemoveObject(nObjNum);
+ if (pObj)
+ static_cast< FmFormModel& >(getSdrModelFromSdrPage()).GetUndoEnv().Removed(pObj);
+ return pObj;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmpgeimp.cxx b/svx/source/form/fmpgeimp.cxx
new file mode 100644
index 000000000..5e8c2027d
--- /dev/null
+++ b/svx/source/form/fmpgeimp.cxx
@@ -0,0 +1,713 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <fmpgeimp.hxx>
+#include <fmundo.hxx>
+#include <svx/fmtools.hxx>
+#include <fmprop.hxx>
+#include <fmservs.hxx>
+#include <fmobj.hxx>
+#include <formcontrolfactory.hxx>
+#include <svx/svditer.hxx>
+#include <svx/strings.hrc>
+#include <treevisitor.hxx>
+
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/container/EnumerableMap.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/form/Forms.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+
+#include <sal/log.hxx>
+#include <sfx2/objsh.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/fmmodel.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <svx/dialmgr.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::form;
+using ::com::sun::star::awt::XControlModel;
+using ::com::sun::star::container::XMap;
+using ::com::sun::star::container::EnumerableMap;
+using ::com::sun::star::drawing::XControlShape;
+using namespace ::svxform;
+using namespace ::dbtools;
+
+
+FmFormPageImpl::FmFormPageImpl( FmFormPage& _rPage )
+ :m_rPage( _rPage )
+ ,m_bFirstActivation( true )
+ ,m_bAttemptedFormCreation( false )
+{
+}
+
+
+namespace
+{
+ class FormComponentInfo
+ {
+ public:
+ static size_t childCount( const Reference< XInterface >& _component )
+ {
+ Reference< XIndexAccess > xContainer( _component, UNO_QUERY );
+ if ( xContainer.is() )
+ return xContainer->getCount();
+ return 0;
+ }
+
+ static Reference< XInterface > getChild( const Reference< XInterface >& _component, size_t _index )
+ {
+ Reference< XIndexAccess > xContainer( _component, UNO_QUERY_THROW );
+ return Reference< XInterface >( xContainer->getByIndex( _index ), UNO_QUERY );
+ }
+ };
+
+ typedef ::std::pair< Reference< XInterface >, Reference< XInterface > > FormComponentPair;
+
+ class FormHierarchyComparator
+ {
+ public:
+ FormHierarchyComparator()
+ {
+ }
+
+ static size_t childCount( const FormComponentPair& _components )
+ {
+ size_t lhsCount = FormComponentInfo::childCount( _components.first );
+ size_t rhsCount = FormComponentInfo::childCount( _components.second );
+ if ( lhsCount != rhsCount )
+ throw RuntimeException( "Found inconsistent form component hierarchies (1)!" );
+ return lhsCount;
+ }
+
+ static FormComponentPair getChild( const FormComponentPair& _components, size_t _index )
+ {
+ return FormComponentPair(
+ FormComponentInfo::getChild( _components.first, _index ),
+ FormComponentInfo::getChild( _components.second, _index )
+ );
+ }
+ };
+
+ typedef ::std::map< Reference< XControlModel >, Reference< XControlModel > > MapControlModels;
+
+ class FormComponentAssignment
+ {
+ public:
+ explicit FormComponentAssignment( MapControlModels& _out_controlModelMap )
+ :m_rControlModelMap( _out_controlModelMap )
+ {
+ }
+
+ void process( const FormComponentPair& _component )
+ {
+ Reference< XControlModel > lhsControlModel( _component.first, UNO_QUERY );
+ Reference< XControlModel > rhsControlModel( _component.second, UNO_QUERY );
+ if ( lhsControlModel.is() != rhsControlModel.is() )
+ throw RuntimeException( "Found inconsistent form component hierarchies (2)!" );
+
+ if ( lhsControlModel.is() )
+ m_rControlModelMap[ lhsControlModel ] = rhsControlModel;
+ }
+
+ private:
+ MapControlModels& m_rControlModelMap;
+ };
+}
+
+
+void FmFormPageImpl::initFrom( FmFormPageImpl& i_foreignImpl )
+{
+ // clone the Forms collection
+ const Reference< css::form::XForms > xForeignForms( i_foreignImpl.getForms( false ) );
+
+ if ( !xForeignForms.is() )
+ return;
+
+ try
+ {
+ m_xForms.set( xForeignForms->createClone(), UNO_QUERY_THROW );
+
+ // create a mapping between the original control models and their clones
+ MapControlModels aModelAssignment;
+
+ typedef TreeVisitor< FormComponentPair, FormHierarchyComparator, FormComponentAssignment > FormComponentVisitor;
+ FormComponentVisitor aVisitor{ FormHierarchyComparator() };
+
+ FormComponentAssignment aAssignmentProcessor( aModelAssignment );
+ aVisitor.process( FormComponentPair( xForeignForms, m_xForms ), aAssignmentProcessor );
+
+ // assign the cloned models to their SdrObjects
+ SdrObjListIter aForeignIter( &i_foreignImpl.m_rPage );
+ SdrObjListIter aOwnIter( &m_rPage );
+
+ OSL_ENSURE( aForeignIter.IsMore() == aOwnIter.IsMore(), "FmFormPageImpl::FmFormPageImpl: inconsistent number of objects (1)!" );
+ while ( aForeignIter.IsMore() && aOwnIter.IsMore() )
+ {
+ FmFormObj* pForeignObj = dynamic_cast< FmFormObj* >( aForeignIter.Next() );
+ FmFormObj* pOwnObj = dynamic_cast< FmFormObj* >( aOwnIter.Next() );
+
+ bool bForeignIsForm = pForeignObj && ( pForeignObj->GetObjInventor() == SdrInventor::FmForm );
+ bool bOwnIsForm = pOwnObj && ( pOwnObj->GetObjInventor() == SdrInventor::FmForm );
+
+ if ( bForeignIsForm != bOwnIsForm )
+ {
+ // if this fires, don't attempt to do further assignments, something's completely messed up
+ SAL_WARN( "svx.form", "FmFormPageImpl::FmFormPageImpl: inconsistent ordering of objects!" );
+ break;
+ }
+
+ if ( !bForeignIsForm )
+ // no form control -> next round
+ continue;
+
+ Reference< XControlModel > xForeignModel( pForeignObj->GetUnoControlModel() );
+ if ( !xForeignModel.is() )
+ {
+ // if this fires, the SdrObject does not have a UNO Control Model. This is pathological, but well ...
+ // So the cloned SdrObject will also not have a UNO Control Model.
+ SAL_WARN( "svx.form", "FmFormPageImpl::FmFormPageImpl: control shape without control!" );
+ continue;
+ }
+
+ MapControlModels::const_iterator assignment = aModelAssignment.find( xForeignModel );
+ if ( assignment == aModelAssignment.end() )
+ {
+ // if this fires, the source SdrObject has a model, but it is not part of the model hierarchy in
+ // i_foreignImpl.getForms().
+ // Pathological, too ...
+ SAL_WARN( "svx.form", "FmFormPageImpl::FmFormPageImpl: no clone found for this model!" );
+ continue;
+ }
+
+ pOwnObj->SetUnoControlModel( assignment->second );
+ }
+ OSL_ENSURE( aForeignIter.IsMore() == aOwnIter.IsMore(), "FmFormPageImpl::FmFormPageImpl: inconsistent number of objects (2)!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+Reference< XMap > FmFormPageImpl::getControlToShapeMap()
+{
+ Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY );
+ if ( xControlShapeMap.is() )
+ return xControlShapeMap;
+
+ xControlShapeMap = impl_createControlShapeMap_nothrow();
+ m_aControlShapeMap = xControlShapeMap;
+ return xControlShapeMap;
+}
+
+
+namespace
+{
+ void lcl_insertFormObject_throw( const FmFormObj& _object, const Reference< XMap >& _map )
+ {
+ // the control model
+ Reference< XControlModel > xControlModel = _object.GetUnoControlModel();
+ OSL_ENSURE( xControlModel.is(), "lcl_insertFormObject_throw: suspicious: no control model!" );
+ if ( !xControlModel.is() )
+ return;
+
+ Reference< XControlShape > xControlShape( const_cast< FmFormObj& >( _object ).getUnoShape(), UNO_QUERY );
+ OSL_ENSURE( xControlShape.is(), "lcl_insertFormObject_throw: suspicious: no control shape!" );
+ if ( !xControlShape.is() )
+ return;
+
+ _map->put( Any( xControlModel ), Any( xControlShape ) );
+ }
+
+ void lcl_removeFormObject_throw( const FmFormObj& _object, const Reference< XMap >& _map )
+ {
+ // the control model
+ Reference< XControlModel > xControlModel = _object.GetUnoControlModel();
+ OSL_ENSURE( xControlModel.is(), "lcl_removeFormObject: suspicious: no control model!" );
+ if ( !xControlModel.is() )
+ {
+ return;
+ }
+
+ Any aOldAssignment = _map->remove( Any( xControlModel ) );
+ OSL_ENSURE(
+ aOldAssignment == Any( Reference< XControlShape >( const_cast< FmFormObj& >( _object ).getUnoShape(), UNO_QUERY ) ),
+ "lcl_removeFormObject: map was inconsistent!" );
+ }
+}
+
+
+Reference< XMap > FmFormPageImpl::impl_createControlShapeMap_nothrow()
+{
+ Reference< XMap > xMap;
+
+ try
+ {
+ xMap = EnumerableMap::create( comphelper::getProcessComponentContext(),
+ ::cppu::UnoType< XControlModel >::get(),
+ ::cppu::UnoType< XControlShape >::get()
+ );
+
+ SdrObjListIter aPageIter( &m_rPage );
+ while ( aPageIter.IsMore() )
+ {
+ // only FmFormObjs are what we're interested in
+ FmFormObj* pCurrent = FmFormObj::GetFormObject( aPageIter.Next() );
+ if ( !pCurrent )
+ continue;
+
+ lcl_insertFormObject_throw( *pCurrent, xMap );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return xMap;
+}
+
+
+const Reference< css::form::XForms >& FmFormPageImpl::getForms( bool _bForceCreate )
+{
+ if ( m_xForms.is() || !_bForceCreate )
+ return m_xForms;
+
+ if ( !m_bAttemptedFormCreation )
+ {
+ m_bAttemptedFormCreation = true;
+
+ Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
+ m_xForms = css::form::Forms::create( xContext );
+
+ if ( m_aFormsCreationHdl.IsSet() )
+ {
+ m_aFormsCreationHdl.Call( *this );
+ }
+
+ FmFormModel& rFmFormModel(dynamic_cast< FmFormModel& >(m_rPage.getSdrModelFromSdrPage()));
+
+ // give the newly created collection a place in the universe
+ SfxObjectShell* pObjShell(rFmFormModel.GetObjectShell());
+ if ( pObjShell )
+ m_xForms->setParent( pObjShell->GetModel() );
+
+ // tell the UNDO environment that we have a new forms collection
+ rFmFormModel.GetUndoEnv().AddForms( Reference<XNameContainer>(m_xForms,UNO_QUERY_THROW) );
+ }
+ return m_xForms;
+}
+
+
+FmFormPageImpl::~FmFormPageImpl()
+{
+ xCurrentForm = nullptr;
+
+ ::comphelper::disposeComponent( m_xForms );
+}
+
+
+bool FmFormPageImpl::validateCurForm()
+{
+ if ( !xCurrentForm.is() )
+ return false;
+
+ if ( !xCurrentForm->getParent().is() )
+ xCurrentForm.clear();
+
+ return xCurrentForm.is();
+}
+
+
+void FmFormPageImpl::setCurForm(const Reference< css::form::XForm >& xForm)
+{
+ xCurrentForm = xForm;
+}
+
+
+Reference< XForm > FmFormPageImpl::getDefaultForm()
+{
+ Reference< XForm > xForm;
+
+ Reference< XForms > xForms( getForms() );
+
+ // by default, we use our "current form"
+ if ( !validateCurForm() )
+ {
+ // check whether there is a "standard" form
+ if ( Reference<XNameAccess>(xForms,UNO_QUERY_THROW)->hasElements() )
+ {
+ // find the standard form
+ OUString sStandardFormname = SvxResId(RID_STR_STDFORMNAME);
+
+ try
+ {
+ if ( xForms->hasByName( sStandardFormname ) )
+ xForm.set( xForms->getByName( sStandardFormname ), UNO_QUERY_THROW );
+ else
+ {
+ xForm.set( xForms->getByIndex(0), UNO_QUERY_THROW );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+ else
+ {
+ xForm = xCurrentForm;
+ }
+
+ // did not find an existing suitable form -> create a new one
+ if ( !xForm.is() )
+ {
+ SdrModel& rModel(m_rPage.getSdrModelFromSdrPage());
+
+ if( rModel.IsUndoEnabled() )
+ {
+ OUString aStr(SvxResId(RID_STR_FORM));
+ OUString aUndoStr(SvxResId(RID_STR_UNDO_CONTAINER_INSERT));
+ rModel.BegUndo(aUndoStr.replaceFirst("'#'", aStr));
+ }
+
+ try
+ {
+ xForm.set( ::comphelper::getProcessServiceFactory()->createInstance( FM_SUN_COMPONENT_FORM ), UNO_QUERY );
+
+ // a form should always have the command type table as default
+ Reference< XPropertySet > xFormProps( xForm, UNO_QUERY_THROW );
+ xFormProps->setPropertyValue( FM_PROP_COMMANDTYPE, Any( sal_Int32( CommandType::TABLE ) ) );
+
+ // and the "Standard" name
+ OUString sName = SvxResId(RID_STR_STDFORMNAME);
+ xFormProps->setPropertyValue( FM_PROP_NAME, Any( sName ) );
+
+ if( rModel.IsUndoEnabled() )
+ {
+ rModel.AddUndo(
+ std::make_unique<FmUndoContainerAction>(
+ static_cast< FmFormModel& >(rModel),
+ FmUndoContainerAction::Inserted,
+ xForms,
+ xForm,
+ xForms->getCount()));
+ }
+ xForms->insertByName( sName, Any( xForm ) );
+ xCurrentForm = xForm;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ xForm.clear();
+ }
+
+ if( rModel.IsUndoEnabled() )
+ rModel.EndUndo();
+ }
+
+ return xForm;
+}
+
+
+Reference< css::form::XForm > FmFormPageImpl::findPlaceInFormComponentHierarchy(
+ const Reference< XFormComponent > & rContent, const Reference< XDataSource > & rDatabase,
+ const OUString& rDBTitle, const OUString& rCursorSource, sal_Int32 nCommandType )
+{
+ // if the control already is child of a form, don't do anything
+ if (!rContent.is() || rContent->getParent().is())
+ return nullptr;
+
+ Reference< XForm > xForm;
+
+ // If database and CursorSource are set, the form is searched for using
+ // these criteria, otherwise only current and the DefaultForm.
+ if (rDatabase.is() && !rCursorSource.isEmpty())
+ {
+ validateCurForm();
+
+ // first search in the current form
+ xForm = findFormForDataSource( xCurrentForm, rDatabase, rCursorSource, nCommandType );
+
+ Reference< css::container::XIndexAccess > xFormsByIndex = getForms();
+ DBG_ASSERT(xFormsByIndex.is(), "FmFormPageImpl::findPlaceInFormComponentHierarchy : no index access for my forms collection !");
+ sal_Int32 nCount = xFormsByIndex->getCount();
+ for (sal_Int32 i = 0; !xForm.is() && i < nCount; i++)
+ {
+ Reference< css::form::XForm > xToSearch;
+ xFormsByIndex->getByIndex(i) >>= xToSearch;
+ xForm = findFormForDataSource( xToSearch, rDatabase, rCursorSource, nCommandType );
+ }
+
+ // If no css::form found, then create a new one
+ if (!xForm.is())
+ {
+ SdrModel& rModel(m_rPage.getSdrModelFromSdrPage());
+ const bool bUndo(rModel.IsUndoEnabled());
+
+ if( bUndo )
+ {
+ OUString aStr(SvxResId(RID_STR_FORM));
+ OUString aUndoStr(SvxResId(RID_STR_UNDO_CONTAINER_INSERT));
+ aUndoStr = aUndoStr.replaceFirst("#", aStr);
+ rModel.BegUndo(aUndoStr);
+ }
+
+ xForm.set(::comphelper::getProcessServiceFactory()->createInstance(FM_SUN_COMPONENT_FORM), UNO_QUERY);
+ // a form should always have the command type table as default
+ Reference< css::beans::XPropertySet > xFormProps(xForm, UNO_QUERY);
+ try { xFormProps->setPropertyValue(FM_PROP_COMMANDTYPE, Any(sal_Int32(CommandType::TABLE))); }
+ catch(Exception&) { }
+
+ if (!rDBTitle.isEmpty())
+ xFormProps->setPropertyValue(FM_PROP_DATASOURCE,Any(rDBTitle));
+ else
+ {
+ Reference< css::beans::XPropertySet > xDatabaseProps(rDatabase, UNO_QUERY);
+ Any aDatabaseUrl = xDatabaseProps->getPropertyValue(FM_PROP_URL);
+ xFormProps->setPropertyValue(FM_PROP_URL, aDatabaseUrl);
+ }
+
+ xFormProps->setPropertyValue(FM_PROP_COMMAND,Any(rCursorSource));
+ xFormProps->setPropertyValue(FM_PROP_COMMANDTYPE, Any(nCommandType));
+
+ Reference< css::container::XNameAccess > xNamedSet = getForms();
+
+ const bool bTableOrQuery = ( CommandType::TABLE == nCommandType ) || ( CommandType::QUERY == nCommandType );
+ OUString sName = FormControlFactory::getUniqueName( xNamedSet,
+ bTableOrQuery ? rCursorSource : SvxResId(RID_STR_STDFORMNAME) );
+
+ xFormProps->setPropertyValue( FM_PROP_NAME, Any( sName ) );
+
+ if( bUndo )
+ {
+ Reference< css::container::XIndexContainer > xContainer = getForms();
+ rModel.AddUndo(
+ std::make_unique<FmUndoContainerAction>(
+ static_cast< FmFormModel& >(rModel),
+ FmUndoContainerAction::Inserted,
+ xContainer,
+ xForm,
+ xContainer->getCount()));
+ }
+
+ getForms()->insertByName( sName, Any( xForm ) );
+
+ if( bUndo )
+ rModel.EndUndo();
+ }
+ xCurrentForm = xForm;
+ }
+
+ xForm = getDefaultForm();
+ return xForm;
+}
+
+
+Reference< XForm > FmFormPageImpl::findFormForDataSource(
+ const Reference< XForm > & rForm, const Reference< XDataSource > & _rxDatabase,
+ const OUString& _rCursorSource, sal_Int32 nCommandType)
+{
+ Reference< XForm > xResultForm;
+ Reference< XRowSet > xDBForm(rForm, UNO_QUERY);
+ Reference< XPropertySet > xFormProps(rForm, UNO_QUERY);
+ if (!xDBForm.is() || !xFormProps.is())
+ return xResultForm;
+
+ OSL_ENSURE(_rxDatabase.is(), "FmFormPageImpl::findFormForDataSource: invalid data source!");
+ OUString sLookupName; // the name of the data source we're looking for
+ OUString sFormDataSourceName; // the name of the data source the current connection in the form is based on
+ try
+ {
+ Reference< XPropertySet > xDSProps(_rxDatabase, UNO_QUERY);
+ if (xDSProps.is())
+ xDSProps->getPropertyValue(FM_PROP_NAME) >>= sLookupName;
+
+ xFormProps->getPropertyValue(FM_PROP_DATASOURCE) >>= sFormDataSourceName;
+ // if there's no DataSourceName set at the form, check whether we can deduce one from its
+ // ActiveConnection
+ if (sFormDataSourceName.isEmpty())
+ {
+ Reference< XConnection > xFormConnection;
+ xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xFormConnection;
+ if ( !xFormConnection.is() )
+ isEmbeddedInDatabase( xFormProps, xFormConnection );
+ if (xFormConnection.is())
+ {
+ Reference< XChild > xConnAsChild(xFormConnection, UNO_QUERY);
+ if (xConnAsChild.is())
+ {
+ Reference< XDataSource > xFormDS(xConnAsChild->getParent(), UNO_QUERY);
+ if (xFormDS.is())
+ {
+ xDSProps.set(xFormDS, css::uno::UNO_QUERY);
+ if (xDSProps.is())
+ xDSProps->getPropertyValue(FM_PROP_NAME) >>= sFormDataSourceName;
+ }
+ }
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "FmFormPageImpl::findFormForDataSource");
+ }
+
+ if (sLookupName == sFormDataSourceName)
+ {
+ // now check whether CursorSource and type match
+ OUString aCursorSource = ::comphelper::getString(xFormProps->getPropertyValue(FM_PROP_COMMAND));
+ sal_Int32 nType = ::comphelper::getINT32(xFormProps->getPropertyValue(FM_PROP_COMMANDTYPE));
+ if (aCursorSource.isEmpty() || ((nType == nCommandType) && (aCursorSource == _rCursorSource))) // found the form
+ {
+ xResultForm = rForm;
+ // if no data source is set yet, it is done here
+ if (aCursorSource.isEmpty())
+ {
+ xFormProps->setPropertyValue(FM_PROP_COMMAND, Any(_rCursorSource));
+ xFormProps->setPropertyValue(FM_PROP_COMMANDTYPE, Any(nCommandType));
+ }
+ }
+ }
+
+ // as long as xResultForm is NULL, search the child forms of rForm
+ Reference< XIndexAccess > xComponents(rForm, UNO_QUERY);
+ sal_Int32 nCount = xComponents->getCount();
+ for (sal_Int32 i = 0; !xResultForm.is() && i < nCount; ++i)
+ {
+ Reference< css::form::XForm > xSearchForm;
+ xComponents->getByIndex(i) >>= xSearchForm;
+ // continue searching in the sub form
+ if (xSearchForm.is())
+ xResultForm = findFormForDataSource( xSearchForm, _rxDatabase, _rCursorSource, nCommandType );
+ }
+ return xResultForm;
+}
+
+
+OUString FmFormPageImpl::setUniqueName(const Reference< XFormComponent > & xFormComponent, const Reference< XForm > & xControls)
+{
+#if OSL_DEBUG_LEVEL > 0
+ try
+ {
+ OSL_ENSURE( !xFormComponent->getParent().is(), "FmFormPageImpl::setUniqueName: to be called before insertion!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+#endif
+ OUString sName;
+ Reference< css::beans::XPropertySet > xSet(xFormComponent, UNO_QUERY);
+ if (xSet.is())
+ {
+ sName = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_NAME ) );
+ Reference< css::container::XNameAccess > xNameAcc(xControls, UNO_QUERY);
+
+ if (sName.isEmpty() || xNameAcc->hasByName(sName))
+ {
+ // set a default name via the ClassId
+ sal_Int16 nClassId( FormComponentType::CONTROL );
+ xSet->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId;
+
+ OUString sDefaultName = FormControlFactory::getDefaultUniqueName_ByComponentType(
+ Reference< XNameAccess >( xControls, UNO_QUERY ), xSet );
+
+ // do not overwrite the name of radio buttons that have it!
+ if (sName.isEmpty() || nClassId != css::form::FormComponentType::RADIOBUTTON)
+ {
+ xSet->setPropertyValue(FM_PROP_NAME, Any(sDefaultName));
+ }
+
+ sName = sDefaultName;
+ }
+ }
+ return sName;
+}
+
+
+void FmFormPageImpl::formModelAssigned( const FmFormObj& _object )
+{
+ Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY );
+ if ( !xControlShapeMap.is() )
+ // our map does not exist -> not interested in this event
+ return;
+
+ try
+ {
+ lcl_removeFormObject_throw( _object, xControlShapeMap );
+ lcl_insertFormObject_throw( _object, xControlShapeMap );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+void FmFormPageImpl::formObjectInserted( const FmFormObj& _object )
+{
+ Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY );
+ if ( !xControlShapeMap.is() )
+ // our map does not exist -> not interested in this event
+ return;
+
+ try
+ {
+ lcl_insertFormObject_throw( _object, xControlShapeMap );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+void FmFormPageImpl::formObjectRemoved( const FmFormObj& _object )
+{
+ Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY );
+ if ( !xControlShapeMap.is() )
+ // our map does not exist -> not interested in this event
+ return;
+
+ try
+ {
+ lcl_removeFormObject_throw( _object, xControlShapeMap );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmscriptingenv.cxx b/svx/source/form/fmscriptingenv.cxx
new file mode 100644
index 000000000..31de56304
--- /dev/null
+++ b/svx/source/form/fmscriptingenv.cxx
@@ -0,0 +1,928 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <fmscriptingenv.hxx>
+#include <svx/fmmodel.hxx>
+
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/EventObject.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/script/XScriptListener.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <tools/debug.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <vcl/svapp.hxx>
+#include <mutex>
+#include <o3tl/sorted_vector.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/app.hxx>
+#include <basic/basmgr.hxx>
+
+#include <memory>
+#include <utility>
+
+using std::pair;
+
+namespace svxform
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::script::XEventAttacherManager;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::script::XScriptListener;
+ using ::com::sun::star::script::ScriptEvent;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::awt::XControl;
+ using ::com::sun::star::beans::XPropertySet;
+
+ //= FormScriptListener
+
+ typedef ::cppu::WeakImplHelper < XScriptListener
+ > FormScriptListener_Base;
+
+ /** implements the XScriptListener interface, is used by FormScriptingEnvironment
+ */
+ class FormScriptListener :public FormScriptListener_Base
+ {
+ private:
+ std::mutex m_aMutex;
+ FormScriptingEnvironment *m_pScriptExecutor;
+
+ public:
+ explicit FormScriptListener( FormScriptingEnvironment * pScriptExecutor );
+
+ // XScriptListener
+ virtual void SAL_CALL firing( const ScriptEvent& aEvent ) override;
+ virtual Any SAL_CALL approveFiring( const ScriptEvent& aEvent ) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& Source ) override;
+
+ // lifetime control
+ void dispose();
+
+ protected:
+ virtual ~FormScriptListener() override;
+
+ private:
+ /** determines whether calling a given method at a given listener interface can be done asynchronously
+
+ @param _rListenerType
+ the name of the UNO type whose method is to be checked
+ @param _rMethodName
+ the name of the method at the interface determined by _rListenerType
+
+ @return
+ <TRUE/> if and only if the method is declared <code>oneway</code>, i.e. can be called asynchronously
+ */
+ static bool impl_allowAsynchronousCall_nothrow( const OUString& _rListenerType, const OUString& _rMethodName );
+
+ /** determines whether the instance is already disposed
+ */
+ bool impl_isDisposed_nothrow() const { return !m_pScriptExecutor; }
+
+ /** fires the given script event in a thread-safe manner
+
+ This methods calls our script executor's doFireScriptEvent, with previously releasing the given mutex guard,
+ but ensuring that our script executor is not deleted between this release and the actual call.
+
+ @param _rGuard
+ a clearable guard to our mutex. Must be the only active guard to our mutex.
+ @param _rEvent
+ the event to fire
+ @param _pSynchronousResult
+ a place to take a possible result of the script call.
+
+ @precond
+ m_pScriptExecutor is not <NULL/>.
+ */
+ void impl_doFireScriptEvent_nothrow( std::unique_lock<std::mutex>& _rGuard, const ScriptEvent& _rEvent, Any* _pSynchronousResult );
+
+ private:
+ DECL_LINK( OnAsyncScriptEvent, void*, void );
+ };
+
+ FormScriptListener::FormScriptListener( FormScriptingEnvironment* pScriptExecutor )
+ :m_pScriptExecutor( pScriptExecutor )
+ {
+ }
+
+
+ FormScriptListener::~FormScriptListener()
+ {
+ }
+
+
+ bool FormScriptListener::impl_allowAsynchronousCall_nothrow( const OUString& _rListenerType, const OUString& _rMethodName )
+ {
+ // This used to be implemented as:
+ // is (_rListenerType + "::" + _rMethodName) a oneway function?
+ // since we got rid of the notion of oneway, this is the list
+ // of oneway methods, autogenerated by postprocessing of
+ // commitdiff 90eac3e69749a9227c4b6902b1f3cef1e338c6d1
+ static const o3tl::sorted_vector<pair<OUString, OUString>> delayed_event_listeners{
+ pair<OUString,OUString>("com.sun.star.accessibility.XAccessibleComponent","grabFocus"),
+ pair<OUString,OUString>("com.sun.star.accessibility.XAccessibleEventBroadcaster","addAccessibleEventListener"),
+ pair<OUString,OUString>("com.sun.star.accessibility.XAccessibleEventBroadcaster","removeAccessibleEventListener"),
+ pair<OUString,OUString>("com.sun.star.accessibility.XAccessibleSelection","clearAccessibleSelection"),
+ pair<OUString,OUString>("com.sun.star.accessibility.XAccessibleSelection","selectAllAccessibleChildren"),
+ pair<OUString,OUString>("com.sun.star.awt.XActionListener","actionPerformed"),
+ pair<OUString,OUString>("com.sun.star.awt.XActivateListener","windowActivated"),
+ pair<OUString,OUString>("com.sun.star.awt.XActivateListener","windowDeactivated"),
+ pair<OUString,OUString>("com.sun.star.awt.XAdjustmentListener","adjustmentValueChanged"),
+ pair<OUString,OUString>("com.sun.star.awt.XButton","addActionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XButton","removeActionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XButton","setLabel"),
+ pair<OUString,OUString>("com.sun.star.awt.XButton","setActionCommand"),
+ pair<OUString,OUString>("com.sun.star.awt.XCheckBox","addItemListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XCheckBox","removeItemListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XCheckBox","setState"),
+ pair<OUString,OUString>("com.sun.star.awt.XCheckBox","setLabel"),
+ pair<OUString,OUString>("com.sun.star.awt.XCheckBox","enableTriState"),
+ pair<OUString,OUString>("com.sun.star.awt.XComboBox","addItemListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XComboBox","removeItemListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XComboBox","addActionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XComboBox","removeActionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XComboBox","addItem"),
+ pair<OUString,OUString>("com.sun.star.awt.XComboBox","addItems"),
+ pair<OUString,OUString>("com.sun.star.awt.XComboBox","removeItems"),
+ pair<OUString,OUString>("com.sun.star.awt.XComboBox","setDropDownLineCount"),
+ pair<OUString,OUString>("com.sun.star.awt.XControl","setContext"),
+ pair<OUString,OUString>("com.sun.star.awt.XControl","createPeer"),
+ pair<OUString,OUString>("com.sun.star.awt.XControl","setDesignMode"),
+ pair<OUString,OUString>("com.sun.star.awt.XControlContainer","setStatusText"),
+ pair<OUString,OUString>("com.sun.star.awt.XControlContainer","addControl"),
+ pair<OUString,OUString>("com.sun.star.awt.XControlContainer","removeControl"),
+ pair<OUString,OUString>("com.sun.star.awt.XCurrencyField","setValue"),
+ pair<OUString,OUString>("com.sun.star.awt.XCurrencyField","setMin"),
+ pair<OUString,OUString>("com.sun.star.awt.XCurrencyField","setMax"),
+ pair<OUString,OUString>("com.sun.star.awt.XCurrencyField","setFirst"),
+ pair<OUString,OUString>("com.sun.star.awt.XCurrencyField","setLast"),
+ pair<OUString,OUString>("com.sun.star.awt.XCurrencyField","setSpinSize"),
+ pair<OUString,OUString>("com.sun.star.awt.XCurrencyField","setDecimalDigits"),
+ pair<OUString,OUString>("com.sun.star.awt.XCurrencyField","setStrictFormat"),
+ pair<OUString,OUString>("com.sun.star.awt.XDateField","setDate"),
+ pair<OUString,OUString>("com.sun.star.awt.XDateField","setMin"),
+ pair<OUString,OUString>("com.sun.star.awt.XDateField","setMax"),
+ pair<OUString,OUString>("com.sun.star.awt.XDateField","setFirst"),
+ pair<OUString,OUString>("com.sun.star.awt.XDateField","setLast"),
+ pair<OUString,OUString>("com.sun.star.awt.XDateField","setLongFormat"),
+ pair<OUString,OUString>("com.sun.star.awt.XDateField","setStrictFormat"),
+ pair<OUString,OUString>("com.sun.star.awt.XDialog","setTitle"),
+ pair<OUString,OUString>("com.sun.star.awt.XDisplayConnection","addEventHandler"),
+ pair<OUString,OUString>("com.sun.star.awt.XDisplayConnection","removeEventHandler"),
+ pair<OUString,OUString>("com.sun.star.awt.XDisplayConnection","addErrorHandler"),
+ pair<OUString,OUString>("com.sun.star.awt.XDisplayConnection","removeErrorHandler"),
+ pair<OUString,OUString>("com.sun.star.awt.XExtendedToolkit","addTopWindowListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XExtendedToolkit","removeTopWindowListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XExtendedToolkit","addKeyHandler"),
+ pair<OUString,OUString>("com.sun.star.awt.XExtendedToolkit","removeKeyHandler"),
+ pair<OUString,OUString>("com.sun.star.awt.XExtendedToolkit","addFocusListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XExtendedToolkit","removeFocusListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XExtendedToolkit","fireFocusGained"),
+ pair<OUString,OUString>("com.sun.star.awt.XExtendedToolkit","fireFocusLost"),
+ pair<OUString,OUString>("com.sun.star.awt.XFileDialog","setPath"),
+ pair<OUString,OUString>("com.sun.star.awt.XFileDialog","setFilters"),
+ pair<OUString,OUString>("com.sun.star.awt.XFileDialog","setCurrentFilter"),
+ pair<OUString,OUString>("com.sun.star.awt.XFixedHyperlink","setText"),
+ pair<OUString,OUString>("com.sun.star.awt.XFixedHyperlink","setURL"),
+ pair<OUString,OUString>("com.sun.star.awt.XFixedHyperlink","setAlignment"),
+ pair<OUString,OUString>("com.sun.star.awt.XFixedHyperlink","addActionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XFixedHyperlink","removeActionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XFixedText","setText"),
+ pair<OUString,OUString>("com.sun.star.awt.XFixedText","setAlignment"),
+ pair<OUString,OUString>("com.sun.star.awt.XFocusListener","focusGained"),
+ pair<OUString,OUString>("com.sun.star.awt.XFocusListener","focusLost"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","setFont"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","selectFont"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","setTextColor"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","setTextFillColor"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","setLineColor"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","setFillColor"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","setRasterOp"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","setClipRegion"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","intersectClipRegion"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","push"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","pop"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","copy"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","draw"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawPixel"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawLine"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawRect"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawRoundedRect"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawPolyLine"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawPolygon"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawPolyPolygon"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawEllipse"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawArc"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawPie"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawChord"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawGradient"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawText"),
+ pair<OUString,OUString>("com.sun.star.awt.XGraphics","drawTextArray"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageButton","addActionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageButton","removeActionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageButton","setActionCommand"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageConsumer","init"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageConsumer","setColorModel"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageConsumer","setPixelsByBytes"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageConsumer","setPixelsByLongs"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageConsumer","complete"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageProducer","addConsumer"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageProducer","removeConsumer"),
+ pair<OUString,OUString>("com.sun.star.awt.XImageProducer","startProduction"),
+ pair<OUString,OUString>("com.sun.star.awt.XItemEventBroadcaster","addItemListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XItemEventBroadcaster","removeItemListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XItemListener","itemStateChanged"),
+ pair<OUString,OUString>("com.sun.star.awt.XKeyListener","keyPressed"),
+ pair<OUString,OUString>("com.sun.star.awt.XKeyListener","keyReleased"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","addItemListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","removeItemListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","addActionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","removeActionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","addItem"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","addItems"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","removeItems"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","selectItemPos"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","selectItemsPos"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","selectItem"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","setMultipleMode"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","setDropDownLineCount"),
+ pair<OUString,OUString>("com.sun.star.awt.XListBox","makeVisible"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenu","addMenuListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenu","removeMenuListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenu","insertItem"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenu","removeItem"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenu","enableItem"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenu","setItemText"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenu","setPopupMenu"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenuListener","highlight"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenuListener","select"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenuListener","activate"),
+ pair<OUString,OUString>("com.sun.star.awt.XMenuListener","deactivate"),
+ pair<OUString,OUString>("com.sun.star.awt.XMessageBox","setCaptionText"),
+ pair<OUString,OUString>("com.sun.star.awt.XMessageBox","setMessageText"),
+ pair<OUString,OUString>("com.sun.star.awt.XMouseListener","mousePressed"),
+ pair<OUString,OUString>("com.sun.star.awt.XMouseListener","mouseReleased"),
+ pair<OUString,OUString>("com.sun.star.awt.XMouseListener","mouseEntered"),
+ pair<OUString,OUString>("com.sun.star.awt.XMouseListener","mouseExited"),
+ pair<OUString,OUString>("com.sun.star.awt.XNumericField","setValue"),
+ pair<OUString,OUString>("com.sun.star.awt.XNumericField","setMin"),
+ pair<OUString,OUString>("com.sun.star.awt.XNumericField","setMax"),
+ pair<OUString,OUString>("com.sun.star.awt.XNumericField","setFirst"),
+ pair<OUString,OUString>("com.sun.star.awt.XNumericField","setLast"),
+ pair<OUString,OUString>("com.sun.star.awt.XNumericField","setSpinSize"),
+ pair<OUString,OUString>("com.sun.star.awt.XNumericField","setDecimalDigits"),
+ pair<OUString,OUString>("com.sun.star.awt.XNumericField","setStrictFormat"),
+ pair<OUString,OUString>("com.sun.star.awt.XPaintListener","windowPaint"),
+ pair<OUString,OUString>("com.sun.star.awt.XPatternField","setMasks"),
+ pair<OUString,OUString>("com.sun.star.awt.XPatternField","setString"),
+ pair<OUString,OUString>("com.sun.star.awt.XPatternField","setStrictFormat"),
+ pair<OUString,OUString>("com.sun.star.awt.XPointer","setType"),
+ pair<OUString,OUString>("com.sun.star.awt.XPopupMenu","insertSeparator"),
+ pair<OUString,OUString>("com.sun.star.awt.XPopupMenu","setDefaultItem"),
+ pair<OUString,OUString>("com.sun.star.awt.XPopupMenu","checkItem"),
+ pair<OUString,OUString>("com.sun.star.awt.XProgressBar","setForegroundColor"),
+ pair<OUString,OUString>("com.sun.star.awt.XProgressBar","setBackgroundColor"),
+ pair<OUString,OUString>("com.sun.star.awt.XProgressBar","setRange"),
+ pair<OUString,OUString>("com.sun.star.awt.XProgressBar","setValue"),
+ pair<OUString,OUString>("com.sun.star.awt.XProgressMonitor","addText"),
+ pair<OUString,OUString>("com.sun.star.awt.XProgressMonitor","removeText"),
+ pair<OUString,OUString>("com.sun.star.awt.XProgressMonitor","updateText"),
+ pair<OUString,OUString>("com.sun.star.awt.XRadioButton","addItemListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XRadioButton","removeItemListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XRadioButton","setState"),
+ pair<OUString,OUString>("com.sun.star.awt.XRadioButton","setLabel"),
+ pair<OUString,OUString>("com.sun.star.awt.XRegion","clear"),
+ pair<OUString,OUString>("com.sun.star.awt.XRegion","move"),
+ pair<OUString,OUString>("com.sun.star.awt.XRegion","unionRectangle"),
+ pair<OUString,OUString>("com.sun.star.awt.XRegion","intersectRectangle"),
+ pair<OUString,OUString>("com.sun.star.awt.XRegion","excludeRectangle"),
+ pair<OUString,OUString>("com.sun.star.awt.XRegion","xOrRectangle"),
+ pair<OUString,OUString>("com.sun.star.awt.XRegion","unionRegion"),
+ pair<OUString,OUString>("com.sun.star.awt.XRegion","intersectRegion"),
+ pair<OUString,OUString>("com.sun.star.awt.XRegion","excludeRegion"),
+ pair<OUString,OUString>("com.sun.star.awt.XRegion","xOrRegion"),
+ pair<OUString,OUString>("com.sun.star.awt.XScrollBar","addAdjustmentListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XScrollBar","removeAdjustmentListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XScrollBar","setValue"),
+ pair<OUString,OUString>("com.sun.star.awt.XScrollBar","setValues"),
+ pair<OUString,OUString>("com.sun.star.awt.XScrollBar","setMaximum"),
+ pair<OUString,OUString>("com.sun.star.awt.XScrollBar","setLineIncrement"),
+ pair<OUString,OUString>("com.sun.star.awt.XScrollBar","setBlockIncrement"),
+ pair<OUString,OUString>("com.sun.star.awt.XScrollBar","setVisibleSize"),
+ pair<OUString,OUString>("com.sun.star.awt.XScrollBar","setOrientation"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinField","addSpinListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinField","removeSpinListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinField","up"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinField","down"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinField","first"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinField","last"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinField","enableRepeat"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinListener","up"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinListener","down"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinListener","first"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinListener","last"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinValue","addAdjustmentListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinValue","removeAdjustmentListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinValue","setValue"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinValue","setValues"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinValue","setMinimum"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinValue","setMaximum"),
+ pair<OUString,OUString>("com.sun.star.awt.XSpinValue","setSpinIncrement"),
+ pair<OUString,OUString>("com.sun.star.awt.XTabController","setModel"),
+ pair<OUString,OUString>("com.sun.star.awt.XTabController","setContainer"),
+ pair<OUString,OUString>("com.sun.star.awt.XTabController","autoTabOrder"),
+ pair<OUString,OUString>("com.sun.star.awt.XTabController","activateTabOrder"),
+ pair<OUString,OUString>("com.sun.star.awt.XTabController","activateFirst"),
+ pair<OUString,OUString>("com.sun.star.awt.XTabController","activateLast"),
+ pair<OUString,OUString>("com.sun.star.awt.XTabControllerModel","setGroupControl"),
+ pair<OUString,OUString>("com.sun.star.awt.XTabControllerModel","setControlModels"),
+ pair<OUString,OUString>("com.sun.star.awt.XTabControllerModel","setGroup"),
+ pair<OUString,OUString>("com.sun.star.awt.XTextComponent","addTextListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XTextComponent","removeTextListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XTextComponent","setText"),
+ pair<OUString,OUString>("com.sun.star.awt.XTextComponent","insertText"),
+ pair<OUString,OUString>("com.sun.star.awt.XTextComponent","setSelection"),
+ pair<OUString,OUString>("com.sun.star.awt.XTextComponent","setEditable"),
+ pair<OUString,OUString>("com.sun.star.awt.XTextComponent","setMaxTextLen"),
+ pair<OUString,OUString>("com.sun.star.awt.XTextEditField","setEchoChar"),
+ pair<OUString,OUString>("com.sun.star.awt.XTextListener","textChanged"),
+ pair<OUString,OUString>("com.sun.star.awt.XTimeField","setTime"),
+ pair<OUString,OUString>("com.sun.star.awt.XTimeField","setMin"),
+ pair<OUString,OUString>("com.sun.star.awt.XTimeField","setMax"),
+ pair<OUString,OUString>("com.sun.star.awt.XTimeField","setFirst"),
+ pair<OUString,OUString>("com.sun.star.awt.XTimeField","setLast"),
+ pair<OUString,OUString>("com.sun.star.awt.XTimeField","setStrictFormat"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindow","addTopWindowListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindow","removeTopWindowListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindow","toFront"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindow","toBack"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindow","setMenuBar"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindowListener","windowOpened"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindowListener","windowClosing"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindowListener","windowClosed"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindowListener","windowMinimized"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindowListener","windowNormalized"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindowListener","windowActivated"),
+ pair<OUString,OUString>("com.sun.star.awt.XTopWindowListener","windowDeactivated"),
+ pair<OUString,OUString>("com.sun.star.awt.XUnoControlContainer","setTabControllers"),
+ pair<OUString,OUString>("com.sun.star.awt.XUnoControlContainer","addTabController"),
+ pair<OUString,OUString>("com.sun.star.awt.XUnoControlContainer","removeTabController"),
+ pair<OUString,OUString>("com.sun.star.awt.XUserInputInterception","addKeyHandler"),
+ pair<OUString,OUString>("com.sun.star.awt.XUserInputInterception","removeKeyHandler"),
+ pair<OUString,OUString>("com.sun.star.awt.XUserInputInterception","addMouseClickHandler"),
+ pair<OUString,OUString>("com.sun.star.awt.XUserInputInterception","removeMouseClickHandler"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclContainer","addVclContainerListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclContainer","removeVclContainerListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclContainerListener","windowAdded"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclContainerListener","windowRemoved"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclContainerPeer","enableDialogControl"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclContainerPeer","setTabOrder"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclContainerPeer","setGroup"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclWindowPeer","setDesignMode"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclWindowPeer","enableClipSiblings"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclWindowPeer","setForeground"),
+ pair<OUString,OUString>("com.sun.star.awt.XVclWindowPeer","setControlFont"),
+ pair<OUString,OUString>("com.sun.star.awt.XView","draw"),
+ pair<OUString,OUString>("com.sun.star.awt.XView","setZoom"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","setPosSize"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","setVisible"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","setEnable"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","setFocus"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","addWindowListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","removeWindowListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","addFocusListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","removeFocusListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","addKeyListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","removeKeyListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","addMouseListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","removeMouseListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","addMouseMotionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","removeMouseMotionListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","addPaintListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindow","removePaintListener"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindowListener","windowResized"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindowListener","windowMoved"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindowListener","windowShown"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindowListener","windowHidden"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindowListener2","windowEnabled"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindowListener2","windowDisabled"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindowPeer","setPointer"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindowPeer","setBackground"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindowPeer","invalidate"),
+ pair<OUString,OUString>("com.sun.star.awt.XWindowPeer","invalidateRect"),
+ pair<OUString,OUString>("com.sun.star.awt.grid.XGridSelectionListener","selectionChanged"),
+ pair<OUString,OUString>("com.sun.star.awt.tab.XTabPageContainer","addTabPageContainerListener"),
+ pair<OUString,OUString>("com.sun.star.awt.tab.XTabPageContainer","removeTabPageContainerListener"),
+ pair<OUString,OUString>("com.sun.star.awt.tab.XTabPageContainerListener","tabPageActivated"),
+ pair<OUString,OUString>("com.sun.star.configuration.backend.XBackendChangesNotifier","addChangesListener"),
+ pair<OUString,OUString>("com.sun.star.configuration.backend.XBackendChangesNotifier","removeChangesListener"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.clipboard.XClipboard","setContents"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.clipboard.XClipboardListener","changedContents"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.clipboard.XClipboardNotifier","addClipboardListener"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.clipboard.XClipboardNotifier","removeClipboardListener"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.clipboard.XClipboardOwner","lostOwnership"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XAutoscroll","autoscroll"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragGestureListener","dragGestureRecognized"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragGestureRecognizer","addDragGestureListener"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragGestureRecognizer","removeDragGestureListener"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragSource","startDrag"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragSourceContext","setCursor"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragSourceContext","setImage"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragSourceContext","transferablesFlavorsChanged"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragSourceListener","dragDropEnd"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragSourceListener","dragEnter"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragSourceListener","dragExit"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragSourceListener","dragOver"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDragSourceListener","dropActionChanged"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTarget","addDropTargetListener"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTarget","removeDropTargetListener"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTarget","setDefaultActions"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTargetDragContext","acceptDrag"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTargetDragContext","rejectDrag"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTargetDropContext","acceptDrop"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTargetDropContext","rejectDrop"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTargetDropContext","dropComplete"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTargetListener","dragEnter"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTargetListener","dragExit"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTargetListener","dragOver"),
+ pair<OUString,OUString>("com.sun.star.datatransfer.dnd.XDropTargetListener","dropActionChanged"),
+ pair<OUString,OUString>("com.sun.star.document.XEventBroadcaster","addEventListener"),
+ pair<OUString,OUString>("com.sun.star.document.XEventBroadcaster","removeEventListener"),
+ pair<OUString,OUString>("com.sun.star.document.XEventListener","notifyEvent"),
+ pair<OUString,OUString>("com.sun.star.document.XStorageChangeListener","notifyStorageChange"),
+ pair<OUString,OUString>("com.sun.star.drawing.XControlShape","setControl"),
+ pair<OUString,OUString>("com.sun.star.form.XApproveActionBroadcaster","addApproveActionListener"),
+ pair<OUString,OUString>("com.sun.star.form.XApproveActionBroadcaster","removeApproveActionListener"),
+ pair<OUString,OUString>("com.sun.star.form.XBoundControl","setLock"),
+ pair<OUString,OUString>("com.sun.star.form.XChangeBroadcaster","addChangeListener"),
+ pair<OUString,OUString>("com.sun.star.form.XChangeBroadcaster","removeChangeListener"),
+ pair<OUString,OUString>("com.sun.star.form.XChangeListener","changed"),
+ pair<OUString,OUString>("com.sun.star.form.XConfirmDeleteBroadcaster","addConfirmDeleteListener"),
+ pair<OUString,OUString>("com.sun.star.form.XConfirmDeleteBroadcaster","removeConfirmDeleteListener"),
+ pair<OUString,OUString>("com.sun.star.form.XDatabaseParameterBroadcaster","addParameterListener"),
+ pair<OUString,OUString>("com.sun.star.form.XDatabaseParameterBroadcaster","removeParameterListener"),
+ pair<OUString,OUString>("com.sun.star.form.XDatabaseParameterBroadcaster2","addDatabaseParameterListener"),
+ pair<OUString,OUString>("com.sun.star.form.XDatabaseParameterBroadcaster2","removeDatabaseParameterListener"),
+ pair<OUString,OUString>("com.sun.star.form.XErrorBroadcaster","addErrorListener"),
+ pair<OUString,OUString>("com.sun.star.form.XErrorBroadcaster","removeErrorListener"),
+ pair<OUString,OUString>("com.sun.star.form.XFormController","addActivateListener"),
+ pair<OUString,OUString>("com.sun.star.form.XFormController","removeActivateListener"),
+ pair<OUString,OUString>("com.sun.star.form.XFormControllerListener","formActivated"),
+ pair<OUString,OUString>("com.sun.star.form.XFormControllerListener","formDeactivated"),
+ pair<OUString,OUString>("com.sun.star.form.XGrid","setCurrentColumnPosition"),
+ pair<OUString,OUString>("com.sun.star.form.XGridPeer","setColumns"),
+ pair<OUString,OUString>("com.sun.star.form.XLoadListener","loaded"),
+ pair<OUString,OUString>("com.sun.star.form.XLoadListener","unloading"),
+ pair<OUString,OUString>("com.sun.star.form.XLoadListener","unloaded"),
+ pair<OUString,OUString>("com.sun.star.form.XLoadListener","reloading"),
+ pair<OUString,OUString>("com.sun.star.form.XLoadListener","reloaded"),
+ pair<OUString,OUString>("com.sun.star.form.XLoadable","load"),
+ pair<OUString,OUString>("com.sun.star.form.XLoadable","unload"),
+ pair<OUString,OUString>("com.sun.star.form.XLoadable","reload"),
+ pair<OUString,OUString>("com.sun.star.form.XLoadable","addLoadListener"),
+ pair<OUString,OUString>("com.sun.star.form.XLoadable","removeLoadListener"),
+ pair<OUString,OUString>("com.sun.star.form.XPositioningListener","positioned"),
+ pair<OUString,OUString>("com.sun.star.form.XReset","reset"),
+ pair<OUString,OUString>("com.sun.star.form.XReset","addResetListener"),
+ pair<OUString,OUString>("com.sun.star.form.XReset","removeResetListener"),
+ pair<OUString,OUString>("com.sun.star.form.XResetListener","resetted"),
+ pair<OUString,OUString>("com.sun.star.form.XSubmit","submit"),
+ pair<OUString,OUString>("com.sun.star.form.XSubmit","addSubmitListener"),
+ pair<OUString,OUString>("com.sun.star.form.XSubmit","removeSubmitListener"),
+ pair<OUString,OUString>("com.sun.star.form.XUpdateBroadcaster","addUpdateListener"),
+ pair<OUString,OUString>("com.sun.star.form.XUpdateBroadcaster","removeUpdateListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XBrowseHistoryRegistry","updateViewData"),
+ pair<OUString,OUString>("com.sun.star.frame.XBrowseHistoryRegistry","createNewEntry"),
+ pair<OUString,OUString>("com.sun.star.frame.XConfigManager","addPropertyChangeListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XConfigManager","removePropertyChangeListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XConfigManager","flush"),
+ pair<OUString,OUString>("com.sun.star.frame.XDesktop","addTerminateListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XDesktop","removeTerminateListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XDispatch","dispatch"),
+ pair<OUString,OUString>("com.sun.star.frame.XDispatch","addStatusListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XDispatch","removeStatusListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XDocumentTemplates","update"),
+ pair<OUString,OUString>("com.sun.star.frame.XFrame","setCreator"),
+ pair<OUString,OUString>("com.sun.star.frame.XFrame","setName"),
+ pair<OUString,OUString>("com.sun.star.frame.XFrame","activate"),
+ pair<OUString,OUString>("com.sun.star.frame.XFrame","deactivate"),
+ pair<OUString,OUString>("com.sun.star.frame.XFrame","addFrameActionListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XFrame","removeFrameActionListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XFrameActionListener","frameAction"),
+ pair<OUString,OUString>("com.sun.star.frame.XFrameLoader","load"),
+ pair<OUString,OUString>("com.sun.star.frame.XFrameLoader","cancel"),
+ pair<OUString,OUString>("com.sun.star.frame.XLoadEventListener","loadFinished"),
+ pair<OUString,OUString>("com.sun.star.frame.XLoadEventListener","loadCancelled"),
+ pair<OUString,OUString>("com.sun.star.frame.XModel","connectController"),
+ pair<OUString,OUString>("com.sun.star.frame.XModel","disconnectController"),
+ pair<OUString,OUString>("com.sun.star.frame.XModel","lockControllers"),
+ pair<OUString,OUString>("com.sun.star.frame.XModel","unlockControllers"),
+ pair<OUString,OUString>("com.sun.star.frame.XNotifyingDispatch","dispatchWithNotification"),
+ pair<OUString,OUString>("com.sun.star.frame.XRecordableDispatch","dispatchAndRecord"),
+ pair<OUString,OUString>("com.sun.star.frame.XSessionManagerClient","addSessionManagerListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XSessionManagerClient","removeSessionManagerListener"),
+ pair<OUString,OUString>("com.sun.star.frame.XSessionManagerClient","queryInteraction"),
+ pair<OUString,OUString>("com.sun.star.frame.XSessionManagerClient","interactionDone"),
+ pair<OUString,OUString>("com.sun.star.frame.XSessionManagerClient","saveDone"),
+ pair<OUString,OUString>("com.sun.star.frame.XSessionManagerListener","doSave"),
+ pair<OUString,OUString>("com.sun.star.frame.XSessionManagerListener","approveInteraction"),
+ pair<OUString,OUString>("com.sun.star.frame.XSessionManagerListener","shutdownCanceled"),
+ pair<OUString,OUString>("com.sun.star.frame.XSessionManagerListener2","doQuit"),
+ pair<OUString,OUString>("com.sun.star.frame.XStatusListener","statusChanged"),
+ pair<OUString,OUString>("com.sun.star.frame.XTask","tileWindows"),
+ pair<OUString,OUString>("com.sun.star.frame.XTask","arrangeWindowsVertical"),
+ pair<OUString,OUString>("com.sun.star.frame.XTask","arrangeWindowsHorizontal"),
+ pair<OUString,OUString>("com.sun.star.frame.XWindowArranger","arrange"),
+ pair<OUString,OUString>("com.sun.star.inspection.XPropertyControlContext","activateNextControl"),
+ pair<OUString,OUString>("com.sun.star.inspection.XPropertyControlObserver","focusGained"),
+ pair<OUString,OUString>("com.sun.star.inspection.XPropertyControlObserver","valueChanged"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XCloseSessionListener","sessionClosed"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XMenuProxy","addMenuProxyListener"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XMenuProxy","removeMenuProxyListener"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstance","start"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstance","stop"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstance","destroy"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstance","createWindow"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstance","newStream"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstance","newURL"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstanceNotifySink","notifyURL"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstancePeer","showStatusMessage"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstancePeer","enableScripting"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstancePeer","newStream"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstancePeer","getURL"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginInstancePeer","postURL"),
+ pair<OUString,OUString>("com.sun.star.mozilla.XPluginWindowPeer","setChildWindow"),
+ pair<OUString,OUString>("com.sun.star.script.vba.XVBACompatibility","addVBAScriptListener"),
+ pair<OUString,OUString>("com.sun.star.script.vba.XVBACompatibility","removeVBAScriptListener"),
+ pair<OUString,OUString>("com.sun.star.sdb.XDatabaseAccess","addDatabaseAccessListener"),
+ pair<OUString,OUString>("com.sun.star.sdb.XDatabaseAccess","removeDatabaseAccessListener"),
+ pair<OUString,OUString>("com.sun.star.sdb.XDatabaseAccessListener","connectionChanged"),
+ pair<OUString,OUString>("com.sun.star.sdb.XDatabaseAccessListener","connectionClosing"),
+ pair<OUString,OUString>("com.sun.star.sdb.XRowSetApproveBroadcaster","addRowSetApproveListener"),
+ pair<OUString,OUString>("com.sun.star.sdb.XRowSetApproveBroadcaster","removeRowSetApproveListener"),
+ pair<OUString,OUString>("com.sun.star.sdb.XRowSetChangeListener","onRowSetChanged"),
+ pair<OUString,OUString>("com.sun.star.sdb.XRowSetSupplier","setRowSet"),
+ pair<OUString,OUString>("com.sun.star.sdb.XRowsChangeListener","rowsChanged"),
+ pair<OUString,OUString>("com.sun.star.sdb.XSQLErrorBroadcaster","addSQLErrorListener"),
+ pair<OUString,OUString>("com.sun.star.sdb.XSQLErrorBroadcaster","removeSQLErrorListener"),
+ pair<OUString,OUString>("com.sun.star.sdbc.XRowSet","addRowSetListener"),
+ pair<OUString,OUString>("com.sun.star.sdbc.XRowSet","removeRowSetListener"),
+ pair<OUString,OUString>("com.sun.star.sdbc.XRowSetListener","cursorMoved"),
+ pair<OUString,OUString>("com.sun.star.sdbc.XRowSetListener","rowChanged"),
+ pair<OUString,OUString>("com.sun.star.sdbc.XRowSetListener","rowSetChanged"),
+ pair<OUString,OUString>("com.sun.star.sheet.XCalculatable","enableAutomaticCalculation"),
+ pair<OUString,OUString>("com.sun.star.sheet.XVolatileResult","addResultListener"),
+ pair<OUString,OUString>("com.sun.star.sheet.XVolatileResult","removeResultListener"),
+ pair<OUString,OUString>("com.sun.star.task.XJobExecutor","trigger"),
+ pair<OUString,OUString>("com.sun.star.task.XStatusIndicator","start"),
+ pair<OUString,OUString>("com.sun.star.task.XStatusIndicator","end"),
+ pair<OUString,OUString>("com.sun.star.task.XStatusIndicator","setText"),
+ pair<OUString,OUString>("com.sun.star.task.XStatusIndicator","setValue"),
+ pair<OUString,OUString>("com.sun.star.task.XStatusIndicator","reset"),
+ pair<OUString,OUString>("com.sun.star.text.XSimpleText","insertString"),
+ pair<OUString,OUString>("com.sun.star.text.XTextCursor","collapseToStart"),
+ pair<OUString,OUString>("com.sun.star.text.XTextCursor","collapseToEnd"),
+ pair<OUString,OUString>("com.sun.star.text.XTextRange","setString"),
+ pair<OUString,OUString>("com.sun.star.text.XTextViewCursor","setVisible"),
+ pair<OUString,OUString>("com.sun.star.ucb.XCommandProcessor","abort"),
+ pair<OUString,OUString>("com.sun.star.ucb.XCommandProcessor2","releaseCommandIdentifier"),
+ pair<OUString,OUString>("com.sun.star.ucb.XContent","addContentEventListener"),
+ pair<OUString,OUString>("com.sun.star.ucb.XContent","removeContentEventListener"),
+ pair<OUString,OUString>("com.sun.star.ucb.XContentProviderManager","deregisterContentProvider"),
+ pair<OUString,OUString>("com.sun.star.ucb.XContentTransmitter","transmit"),
+ pair<OUString,OUString>("com.sun.star.ucb.XPropertySetRegistry","removePropertySet"),
+ pair<OUString,OUString>("com.sun.star.ui.XUIConfigurationListener","elementInserted"),
+ pair<OUString,OUString>("com.sun.star.ui.XUIConfigurationListener","elementRemoved"),
+ pair<OUString,OUString>("com.sun.star.ui.XUIConfigurationListener","elementReplaced"),
+ pair<OUString,OUString>("com.sun.star.ui.dialogs.XFilePickerNotifier","addFilePickerListener"),
+ pair<OUString,OUString>("com.sun.star.ui.dialogs.XFilePickerNotifier","removeFilePickerListener"),
+ pair<OUString,OUString>("com.sun.star.util.XBroadcaster","lockBroadcasts"),
+ pair<OUString,OUString>("com.sun.star.util.XBroadcaster","unlockBroadcasts"),
+ pair<OUString,OUString>("com.sun.star.util.XChangesListener","changesOccurred"),
+ pair<OUString,OUString>("com.sun.star.util.XChangesNotifier","addChangesListener"),
+ pair<OUString,OUString>("com.sun.star.util.XChangesNotifier","removeChangesListener"),
+ pair<OUString,OUString>("com.sun.star.util.XCloseBroadcaster","addCloseListener"),
+ pair<OUString,OUString>("com.sun.star.util.XCloseBroadcaster","removeCloseListener"),
+ pair<OUString,OUString>("com.sun.star.util.XFlushable","addFlushListener"),
+ pair<OUString,OUString>("com.sun.star.util.XFlushable","removeFlushListener"),
+ pair<OUString,OUString>("com.sun.star.util.XModeChangeListener","modeChanged"),
+ pair<OUString,OUString>("com.sun.star.util.XModifyBroadcaster","addModifyListener"),
+ pair<OUString,OUString>("com.sun.star.util.XModifyBroadcaster","removeModifyListener"),
+ pair<OUString,OUString>("com.sun.star.util.XRefreshable","addRefreshListener"),
+ pair<OUString,OUString>("com.sun.star.util.XRefreshable","removeRefreshListener"),
+ pair<OUString,OUString>("com.sun.star.util.XSearchDescriptor","setSearchString"),
+ pair<OUString,OUString>("com.sun.star.view.XPrintJobBroadcaster","addPrintJobListener"),
+ pair<OUString,OUString>("com.sun.star.view.XPrintJobBroadcaster","removePrintJobListener"),
+ pair<OUString,OUString>("com.sun.star.view.XPrintJobListener","printJobEvent"),
+ pair<OUString,OUString>("com.sun.star.view.XPrintableBroadcaster","addPrintableListener"),
+ pair<OUString,OUString>("com.sun.star.view.XPrintableBroadcaster","removePrintableListener"),
+ pair<OUString,OUString>("com.sun.star.view.XPrintableListener","stateChanged"),
+ pair<OUString,OUString>("com.sun.star.view.XSelectionChangeListener","selectionChanged"),
+ pair<OUString,OUString>("com.sun.star.beans.XMultiPropertySet","addPropertiesChangeListener"),
+ pair<OUString,OUString>("com.sun.star.beans.XMultiPropertySet","removePropertiesChangeListener"),
+ pair<OUString,OUString>("com.sun.star.beans.XMultiPropertySet","firePropertiesChangeEvent"),
+ pair<OUString,OUString>("com.sun.star.beans.XPropertiesChangeNotifier","addPropertiesChangeListener"),
+ pair<OUString,OUString>("com.sun.star.beans.XPropertiesChangeNotifier","removePropertiesChangeListener"),
+ pair<OUString,OUString>("com.sun.star.container.XContainer","addContainerListener"),
+ pair<OUString,OUString>("com.sun.star.container.XContainer","removeContainerListener"),
+ pair<OUString,OUString>("com.sun.star.container.XContainerListener","elementInserted"),
+ pair<OUString,OUString>("com.sun.star.container.XContainerListener","elementRemoved"),
+ pair<OUString,OUString>("com.sun.star.container.XContainerListener","elementReplaced"),
+ pair<OUString,OUString>("com.sun.star.container.XNamed","setName"),
+ pair<OUString,OUString>("com.sun.star.io.XDataExporter","exportData"),
+ pair<OUString,OUString>("com.sun.star.io.XDataExporter","cancel"),
+ pair<OUString,OUString>("com.sun.star.io.XDataImporter","importData"),
+ pair<OUString,OUString>("com.sun.star.io.XDataImporter","cancel"),
+ pair<OUString,OUString>("com.sun.star.io.XDataTransferEventListener","finished"),
+ pair<OUString,OUString>("com.sun.star.io.XDataTransferEventListener","cancelled"),
+ pair<OUString,OUString>("com.sun.star.lang.XConnectionPointContainer","advise"),
+ pair<OUString,OUString>("com.sun.star.lang.XConnectionPointContainer","unadvise"),
+ pair<OUString,OUString>("com.sun.star.script.XAllListener","firing"),
+ pair<OUString,OUString>("com.sun.star.uno.XInterface","acquire"),
+ pair<OUString,OUString>("com.sun.star.uno.XInterface","release"),
+ pair<OUString,OUString>("com.sun.star.uno.XReference","dispose")};
+
+ pair<OUString,OUString> k(_rListenerType, _rMethodName);
+ return delayed_event_listeners.find(k) != delayed_event_listeners.end();
+ }
+
+
+ void FormScriptListener::impl_doFireScriptEvent_nothrow( std::unique_lock<std::mutex>& _rGuard, const ScriptEvent& _rEvent, Any* _pSynchronousResult )
+ {
+ OSL_PRECOND( m_pScriptExecutor, "FormScriptListener::impl_doFireScriptEvent_nothrow: this will crash!" );
+
+ _rGuard.unlock();
+ m_pScriptExecutor->doFireScriptEvent( _rEvent, _pSynchronousResult );
+ }
+
+
+ void SAL_CALL FormScriptListener::firing( const ScriptEvent& _rEvent )
+ {
+ if ( _rEvent.ScriptType == "VBAInterop" )
+ return; // not handled here
+
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( impl_isDisposed_nothrow() )
+ return;
+
+ if ( !impl_allowAsynchronousCall_nothrow( _rEvent.ListenerType.getTypeName(), _rEvent.MethodName ) )
+ {
+ impl_doFireScriptEvent_nothrow( aGuard, _rEvent, nullptr );
+ return;
+ }
+
+ acquire();
+ Application::PostUserEvent( LINK( this, FormScriptListener, OnAsyncScriptEvent ), new ScriptEvent( _rEvent ) );
+ }
+
+
+ Any SAL_CALL FormScriptListener::approveFiring( const ScriptEvent& _rEvent )
+ {
+ Any aResult;
+
+ std::unique_lock aGuard( m_aMutex );
+ if ( !impl_isDisposed_nothrow() )
+ impl_doFireScriptEvent_nothrow( aGuard, _rEvent, &aResult );
+
+ return aResult;
+ }
+
+
+ void SAL_CALL FormScriptListener::disposing( const EventObject& /*Source*/ )
+ {
+ // not interested in
+ }
+
+
+ void FormScriptListener::dispose()
+ {
+ std::unique_lock aGuard( m_aMutex );
+ m_pScriptExecutor = nullptr;
+ }
+
+ IMPL_LINK( FormScriptListener, OnAsyncScriptEvent, void*, p, void )
+ {
+ ScriptEvent* _pEvent = static_cast<ScriptEvent*>(p);
+ OSL_PRECOND( _pEvent != nullptr, "FormScriptListener::OnAsyncScriptEvent: invalid event!" );
+ if ( !_pEvent )
+ return;
+
+ {
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( !impl_isDisposed_nothrow() )
+ impl_doFireScriptEvent_nothrow( aGuard, *_pEvent, nullptr );
+ }
+
+ delete _pEvent;
+ // we acquired ourself immediately before posting the event
+ release();
+ }
+
+ FormScriptingEnvironment::FormScriptingEnvironment( FmFormModel& _rModel )
+ :m_rFormModel( _rModel )
+ ,m_bDisposed( false )
+ {
+ m_pScriptListener = new FormScriptListener( this );
+ // note that this is a cyclic reference between the FormScriptListener and the FormScriptingEnvironment
+ // This cycle is broken up when our instance is disposed.
+ }
+
+ void FormScriptingEnvironment::impl_registerOrRevoke_throw( const Reference< XEventAttacherManager >& _rxManager, bool _bRegister )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !_rxManager.is() )
+ throw IllegalArgumentException();
+ if ( m_bDisposed )
+ throw DisposedException();
+
+ try
+ {
+ if ( _bRegister )
+ _rxManager->addScriptListener( m_pScriptListener );
+ else
+ _rxManager->removeScriptListener( m_pScriptListener );
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void FormScriptingEnvironment::registerEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager )
+ {
+ impl_registerOrRevoke_throw( _rxManager, true );
+ }
+
+
+ void FormScriptingEnvironment::revokeEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager )
+ {
+ impl_registerOrRevoke_throw( _rxManager, false );
+ }
+
+#if HAVE_FEATURE_SCRIPTING
+ namespace
+ {
+ class NewStyleUNOScript
+ {
+ SfxObjectShell& m_rObjectShell;
+ const OUString m_sScriptCode;
+
+ public:
+ NewStyleUNOScript( SfxObjectShell& _rObjectShell, const OUString& _rScriptCode )
+ :m_rObjectShell( _rObjectShell )
+ ,m_sScriptCode( _rScriptCode )
+ {
+ }
+
+ void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult );
+ };
+
+
+ void NewStyleUNOScript::invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult )
+ {
+ Sequence< sal_Int16 > aOutArgsIndex;
+ Sequence< Any > aOutArgs;
+ EventObject aEvent;
+ Any aCaller;
+ if ( _rArguments.hasElements() && ( _rArguments[ 0 ] >>= aEvent ) )
+ {
+ try
+ {
+ Reference< XControl > xControl( aEvent.Source, UNO_QUERY_THROW );
+ Reference< XPropertySet > xProps( xControl->getModel(), UNO_QUERY_THROW );
+ aCaller = xProps->getPropertyValue("Name");
+ }
+ catch( Exception& ) {}
+ }
+ m_rObjectShell.CallXScript( m_sScriptCode, _rArguments, _rSynchronousResult, aOutArgsIndex, aOutArgs, true, aCaller.hasValue() ? &aCaller : nullptr );
+ }
+ }
+#endif
+
+ void FormScriptingEnvironment::doFireScriptEvent( const ScriptEvent& _rEvent, Any* _pSynchronousResult )
+ {
+#if !HAVE_FEATURE_SCRIPTING
+ (void) _rEvent;
+ (void) _pSynchronousResult;
+ (void) m_rFormModel;
+#else
+ SolarMutexClearableGuard aSolarGuard;
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ return;
+
+ // SfxObjectShellRef is good here since the model controls the lifetime of the object
+ SfxObjectShellRef xObjectShell = m_rFormModel.GetObjectShell();
+ if( !xObjectShell.is() )
+ return;
+
+ // the script to execute
+ std::shared_ptr< NewStyleUNOScript > pScript;
+
+ if ( _rEvent.ScriptType != "StarBasic" )
+ {
+ pScript = std::make_shared<NewStyleUNOScript>( *xObjectShell, _rEvent.ScriptCode );
+ }
+ else
+ {
+ OUString sScriptCode = _rEvent.ScriptCode;
+ OUString sMacroLocation;
+
+ // is there a location in the script name ("application" or "document")?
+ sal_Int32 nPrefixLen = sScriptCode.indexOf( ':' );
+ DBG_ASSERT( 0 <= nPrefixLen, "FormScriptingEnvironment::doFireScriptEvent: Basic script name in old format encountered!" );
+
+ if ( 0 <= nPrefixLen )
+ {
+ // and it has such a prefix
+ sMacroLocation = sScriptCode.copy( 0, nPrefixLen );
+ DBG_ASSERT( sMacroLocation == "document"
+ || sMacroLocation == "application",
+ "FormScriptingEnvironment::doFireScriptEvent: invalid (unknown) prefix!" );
+
+ // strip the prefix: the SfxObjectShell::CallScript knows nothing about such prefixes
+ sScriptCode = sScriptCode.copy( nPrefixLen + 1 );
+ }
+
+ if ( sMacroLocation.isEmpty() )
+ {
+ // legacy format: use the app-wide Basic, if it has a respective method, otherwise fall back to the doc's Basic
+ if ( SfxApplication::GetBasicManager()->HasMacro( sScriptCode ) )
+ sMacroLocation = "application";
+ else
+ sMacroLocation = "document";
+ }
+
+ OUString sScriptURI = "vnd.sun.star.script:" +
+ sScriptCode +
+ "?language=Basic&location=" +
+ sMacroLocation;
+
+ pScript = std::make_shared<NewStyleUNOScript>( *xObjectShell, sScriptURI );
+ }
+
+ assert(pScript && "FormScriptingEnvironment::doFireScriptEvent: no script to execute!");
+
+ aGuard.clear();
+ aSolarGuard.clear();
+
+ Any aIgnoreResult;
+ pScript->invoke( _rEvent.Arguments, _pSynchronousResult ? *_pSynchronousResult : aIgnoreResult );
+ pScript.reset();
+
+ {
+ // object shells are not thread safe, so guard the destruction
+ SolarMutexGuard aSolarGuarsReset;
+ xObjectShell = nullptr;
+ }
+#endif
+ }
+
+
+ void FormScriptingEnvironment::dispose()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_bDisposed = true;
+ m_pScriptListener->dispose();
+ m_pScriptListener.clear();
+ }
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmservs.cxx b/svx/source/form/fmservs.cxx
new file mode 100644
index 000000000..a6c0daf5d
--- /dev/null
+++ b/svx/source/form/fmservs.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/container/XSet.hpp>
+#include <cppuhelper/factory.hxx>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <fmservs.hxx>
+
+using namespace com::sun::star;
+
+#define REGISTER_SERVICE(ImplName, ServiceName) \
+ sString = (ServiceName); \
+ xSingleFactory = ::cppu::createSingleFactory(xServiceFactory, \
+ OUString(), ImplName##_NewInstance_Impl, \
+ uno::Sequence< OUString>(&sString, 1)); \
+ if (xSingleFactory.is()) \
+ xSet->insert(uno::Any(xSingleFactory));
+
+namespace svxform
+{
+ void ImplSmartRegisterUnoServices()
+ {
+ uno::Reference< lang::XMultiServiceFactory > xServiceFactory = ::comphelper::getProcessServiceFactory();
+ uno::Reference< container::XSet > xSet(xServiceFactory, uno::UNO_QUERY);
+ if (!xSet.is())
+ return;
+
+ uno::Reference< lang::XSingleServiceFactory > xSingleFactory;
+
+ OUString sString;
+
+
+ // FormController
+ REGISTER_SERVICE( FormController, "com.sun.star.form.runtime.FormController" );
+ REGISTER_SERVICE( LegacyFormController, "com.sun.star.form.FormController" );
+
+
+ // FormController - register selfaware service
+ xSingleFactory = ::cppu::createSingleFactory( xServiceFactory,
+ OAddConditionDialog_GetImplementationName(),
+ OAddConditionDialog_Create,
+ OAddConditionDialog_GetSupportedServiceNames()
+ );
+ if ( xSingleFactory.is() )
+ xSet->insert( uno::Any( xSingleFactory ) );
+
+
+ // DBGridControl
+ REGISTER_SERVICE(FmXGridControl, FM_CONTROL_GRID); // compatibility
+ REGISTER_SERVICE(FmXGridControl, FM_CONTROL_GRIDCONTROL);
+ REGISTER_SERVICE(FmXGridControl, FM_SUN_CONTROL_GRIDCONTROL);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmshell.cxx b/svx/source/form/fmshell.cxx
new file mode 100644
index 000000000..5ffa29917
--- /dev/null
+++ b/svx/source/form/fmshell.cxx
@@ -0,0 +1,1417 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fmvwimp.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/fmtools.hxx>
+#include <fmprop.hxx>
+#include <fmundo.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/XTabControllerModel.hpp>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svl/whiter.hxx>
+#include <sfx2/app.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/visitem.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/svditer.hxx>
+
+#include <svx/svxids.hrc>
+
+#include <svx/svdobjkind.hxx>
+#include <svl/eitem.hxx>
+#include <tools/diagnose_ex.h>
+#include <svx/svdpage.hxx>
+#include <svx/fmmodel.hxx>
+#include <fmshimp.hxx>
+#include <svx/svdpagv.hxx>
+#include <sfx2/objitem.hxx>
+#include <sfx2/viewsh.hxx>
+#include <fmexpl.hxx>
+#include <formcontrolling.hxx>
+#include <comphelper/types.hxx>
+#include <fmdocumentclassification.hxx>
+#include <formtoolbars.hxx>
+
+#include <svx/svxdlg.hxx>
+
+#include <svx/sdrobjectfilter.hxx>
+
+#define ShellClass_FmFormShell
+#include <svxslots.hxx>
+
+#include <memory>
+
+// is used for Invalidate -> maintain it as well
+// sort ascending !!!!!!
+sal_uInt16 const ControllerSlotMap[] = // slots of the controller
+{
+ SID_FM_CONFIG,
+ SID_FM_PUSHBUTTON,
+ SID_FM_RADIOBUTTON,
+ SID_FM_CHECKBOX,
+ SID_FM_FIXEDTEXT,
+ SID_FM_GROUPBOX,
+ SID_FM_EDIT,
+ SID_FM_LISTBOX,
+ SID_FM_COMBOBOX,
+ SID_FM_DBGRID,
+ SID_FM_IMAGEBUTTON,
+ SID_FM_FILECONTROL,
+ SID_FM_NAVIGATIONBAR,
+ SID_FM_CTL_PROPERTIES,
+ SID_FM_PROPERTIES,
+ SID_FM_TAB_DIALOG,
+ SID_FM_ADD_FIELD,
+ SID_FM_DESIGN_MODE,
+ SID_FM_SHOW_FMEXPLORER,
+ SID_FM_SHOW_PROPERTIES,
+ SID_FM_FMEXPLORER_CONTROL,
+ SID_FM_DATEFIELD,
+ SID_FM_TIMEFIELD,
+ SID_FM_NUMERICFIELD,
+ SID_FM_CURRENCYFIELD,
+ SID_FM_PATTERNFIELD,
+ SID_FM_OPEN_READONLY,
+ SID_FM_IMAGECONTROL,
+ SID_FM_USE_WIZARDS,
+ SID_FM_FORMATTEDFIELD,
+ SID_FM_FILTER_NAVIGATOR,
+ SID_FM_AUTOCONTROLFOCUS,
+ SID_FM_SCROLLBAR,
+ SID_FM_SPINBUTTON,
+ SID_FM_SHOW_DATANAVIGATOR,
+ SID_FM_DATANAVIGATOR_CONTROL,
+
+ 0
+};
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::form::runtime;
+using namespace ::svxform;
+
+FmDesignModeChangedHint::FmDesignModeChangedHint( bool bDesMode )
+ :m_bDesignMode( bDesMode )
+{
+}
+
+
+FmDesignModeChangedHint::~FmDesignModeChangedHint()
+{
+}
+
+SFX_IMPL_INTERFACE(FmFormShell, SfxShell)
+
+void FmFormShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_NAVIGATION, SfxVisibilityFlags::Standard|SfxVisibilityFlags::ReadonlyDoc,
+ ToolbarId::SvxTbx_Form_Navigation,
+ SfxShellFeature::FormShowDatabaseBar);
+
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_NAVIGATION, SfxVisibilityFlags::Standard|SfxVisibilityFlags::ReadonlyDoc,
+ ToolbarId::SvxTbx_Form_Filter,
+ SfxShellFeature::FormShowFilterBar);
+
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Standard | SfxVisibilityFlags::ReadonlyDoc,
+ ToolbarId::SvxTbx_Text_Control_Attributes,
+ SfxShellFeature::FormShowTextControlBar);
+
+ GetStaticInterface()->RegisterChildWindow(SID_FM_ADD_FIELD, false, SfxShellFeature::FormShowField);
+ GetStaticInterface()->RegisterChildWindow(SID_FM_SHOW_PROPERTIES, false, SfxShellFeature::FormShowProperties);
+ GetStaticInterface()->RegisterChildWindow(SID_FM_SHOW_FMEXPLORER, false, SfxShellFeature::FormShowExplorer);
+ GetStaticInterface()->RegisterChildWindow(SID_FM_FILTER_NAVIGATOR, false, SfxShellFeature::FormShowFilterNavigator);
+ GetStaticInterface()->RegisterChildWindow(SID_FM_SHOW_DATANAVIGATOR, false, SfxShellFeature::FormShowDataNavigator);
+
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Standard,
+ ToolbarId::SvxTbx_Controls,
+ SfxShellFeature::FormTBControls);
+
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Standard,
+ ToolbarId::SvxTbx_FormDesign,
+ SfxShellFeature::FormTBDesign);
+}
+
+
+FmFormShell::FmFormShell( SfxViewShell* _pParent, FmFormView* pView )
+ :SfxShell(_pParent)
+ ,m_pImpl(new FmXFormShell(*this, _pParent->GetViewFrame()))
+ ,m_pFormView( pView )
+ ,m_pFormModel( nullptr )
+ ,m_nLastSlot( 0 )
+ ,m_bDesignMode( true )
+ ,m_bHasForms(false)
+{
+ SetPool( &SfxGetpApp()->GetPool() );
+ SetName( "Form" );
+
+ SetView(m_pFormView);
+}
+
+
+FmFormShell::~FmFormShell()
+{
+ if ( m_pFormView )
+ SetView( nullptr );
+
+ m_pImpl->dispose();
+}
+
+
+void FmFormShell::NotifyMarkListChanged(FmFormView* pWhichView)
+{
+ FmNavViewMarksChanged aChangeNotification(pWhichView);
+ Broadcast(aChangeNotification);
+}
+
+
+bool FmFormShell::PrepareClose(bool bUI)
+{
+ if (GetImpl()->didPrepareClose_Lock())
+ // we already made a PrepareClose for the current modifications of the current form
+ return true;
+
+ bool bResult = true;
+ // Save the data records, not in DesignMode and FilterMode
+ if (!m_bDesignMode && !GetImpl()->isInFilterMode_Lock() &&
+ m_pFormView && m_pFormView->GetActualOutDev() &&
+ m_pFormView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
+ {
+ SdrPageView* pCurPageView = m_pFormView->GetSdrPageView();
+
+ // sal_uInt16 nPos = pCurPageView ? pCurPageView->GetWinList().Find((OutputDevice*)m_pFormView->GetActualOutDev()) : SDRPAGEVIEWWIN_NOTFOUND;
+ SdrPageWindow* pWindow = pCurPageView ? pCurPageView->FindPageWindow(*const_cast<OutputDevice*>(m_pFormView->GetActualOutDev())) : nullptr;
+
+ if(pWindow)
+ {
+ // First, the current contents of the controls are stored.
+ // If everything has gone smoothly, the modified records are stored.
+ if (GetImpl()->getActiveController_Lock().is())
+ {
+ const svx::ControllerFeatures& rController = GetImpl()->getActiveControllerFeatures_Lock();
+ if ( rController->commitCurrentControl() )
+ {
+ const bool bModified = rController->isModifiedRow();
+
+ if ( bModified && bUI )
+ {
+ SfxViewShell* pShell = GetViewShell();
+ vcl::Window* pShellWnd = pShell ? pShell->GetWindow() : nullptr;
+ weld::Widget* pFrameWeld = pShellWnd ? pShellWnd->GetFrameWeld() : nullptr;
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pFrameWeld, "svx/ui/savemodifieddialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQry(xBuilder->weld_message_dialog("SaveModifiedDialog"));
+ switch (xQry->run())
+ {
+ case RET_YES:
+ bResult = rController->commitCurrentRecord( );
+ [[fallthrough]];
+ case RET_NO:
+ GetImpl()->didPrepareClose_Lock(true);
+ break;
+
+ case RET_CANCEL:
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ return bResult;
+}
+
+
+void FmFormShell::impl_setDesignMode(bool bDesign)
+{
+ if (m_pFormView)
+ {
+ if (!bDesign)
+ m_nLastSlot = SID_FM_DESIGN_MODE;
+
+ GetImpl()->SetDesignMode_Lock(bDesign);
+ // my m_bDesignMode is also set by the Impl ...
+ }
+ else
+ {
+ m_bHasForms = false;
+ m_bDesignMode = bDesign;
+ UIFeatureChanged();
+ }
+
+ GetViewShell()->GetViewFrame()->GetBindings().Invalidate(ControllerSlotMap);
+}
+
+
+bool FmFormShell::HasUIFeature(SfxShellFeature nFeature) const
+{
+ assert((nFeature & ~SfxShellFeature::FormMask) == SfxShellFeature::NONE);
+ bool bResult = false;
+ if (nFeature & SfxShellFeature::FormShowDatabaseBar)
+ {
+ // only if forms are also available
+ bResult = !m_bDesignMode && GetImpl()->hasDatabaseBar_Lock() && !GetImpl()->isInFilterMode_Lock();
+ }
+ else if (nFeature & SfxShellFeature::FormShowFilterBar)
+ {
+ // only if forms are also available
+ bResult = !m_bDesignMode && GetImpl()->hasDatabaseBar_Lock() && GetImpl()->isInFilterMode_Lock();
+ }
+ else if (nFeature & SfxShellFeature::FormShowFilterNavigator)
+ {
+ bResult = !m_bDesignMode && GetImpl()->hasDatabaseBar_Lock() && GetImpl()->isInFilterMode_Lock();
+ }
+ else if (nFeature & SfxShellFeature::FormShowField)
+ {
+ bResult = m_bDesignMode && m_pFormView && m_bHasForms;
+ }
+ else if (nFeature & SfxShellFeature::FormShowProperties)
+ {
+ bResult = m_bDesignMode && m_pFormView && m_bHasForms;
+ }
+ else if (nFeature & SfxShellFeature::FormShowExplorer)
+ {
+ bResult = m_bDesignMode; // OJ #101593# && m_pFormView && m_bHasForms;
+ }
+ else if (nFeature & SfxShellFeature::FormShowTextControlBar)
+ {
+ bResult = !GetImpl()->IsReadonlyDoc_Lock() && m_pImpl->IsActiveControl_Lock(true);
+ }
+ else if (nFeature & SfxShellFeature::FormShowDataNavigator)
+ {
+ bResult = GetImpl()->isEnhancedForm_Lock();
+ }
+ else if ( (nFeature & SfxShellFeature::FormTBControls)
+ || (nFeature & SfxShellFeature::FormTBDesign)
+ )
+ {
+ bResult = true;
+ }
+
+ return bResult;
+}
+
+
+void FmFormShell::Execute(SfxRequest &rReq)
+{
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+
+ // set MasterSlot
+ switch( nSlot )
+ {
+ case SID_FM_PUSHBUTTON:
+ case SID_FM_RADIOBUTTON:
+ case SID_FM_CHECKBOX:
+ case SID_FM_FIXEDTEXT:
+ case SID_FM_GROUPBOX:
+ case SID_FM_LISTBOX:
+ case SID_FM_COMBOBOX:
+ case SID_FM_NAVIGATIONBAR:
+ case SID_FM_EDIT:
+ case SID_FM_DBGRID:
+ case SID_FM_IMAGEBUTTON:
+ case SID_FM_IMAGECONTROL:
+ case SID_FM_FILECONTROL:
+ case SID_FM_DATEFIELD:
+ case SID_FM_TIMEFIELD:
+ case SID_FM_NUMERICFIELD:
+ case SID_FM_CURRENCYFIELD:
+ case SID_FM_PATTERNFIELD:
+ case SID_FM_FORMATTEDFIELD:
+ case SID_FM_SCROLLBAR:
+ case SID_FM_SPINBUTTON:
+ m_nLastSlot = nSlot;
+ break;
+ }
+
+
+ // set the Identifier and Inventor of the Uno control
+ SdrObjKind nIdentifier = SdrObjKind::NONE;
+ switch( nSlot )
+ {
+ case SID_FM_CHECKBOX:
+ nIdentifier = SdrObjKind::FormCheckbox;
+ break;
+ case SID_FM_PUSHBUTTON:
+ nIdentifier = SdrObjKind::FormButton;
+ break;
+ case SID_FM_FIXEDTEXT:
+ nIdentifier = SdrObjKind::FormFixedText;
+ break;
+ case SID_FM_LISTBOX:
+ nIdentifier = SdrObjKind::FormListbox;
+ break;
+ case SID_FM_EDIT:
+ nIdentifier = SdrObjKind::FormEdit;
+ break;
+ case SID_FM_RADIOBUTTON:
+ nIdentifier = SdrObjKind::FormRadioButton;
+ break;
+ case SID_FM_GROUPBOX:
+ nIdentifier = SdrObjKind::FormGroupBox;
+ break;
+ case SID_FM_COMBOBOX:
+ nIdentifier = SdrObjKind::FormCombobox;
+ break;
+ case SID_FM_NAVIGATIONBAR:
+ nIdentifier = SdrObjKind::FormNavigationBar;
+ break;
+ case SID_FM_DBGRID:
+ nIdentifier = SdrObjKind::FormGrid;
+ break;
+ case SID_FM_IMAGEBUTTON:
+ nIdentifier = SdrObjKind::FormImageButton;
+ break;
+ case SID_FM_IMAGECONTROL:
+ nIdentifier = SdrObjKind::FormImageControl;
+ break;
+ case SID_FM_FILECONTROL:
+ nIdentifier = SdrObjKind::FormFileControl;
+ break;
+ case SID_FM_DATEFIELD:
+ nIdentifier = SdrObjKind::FormDateField;
+ break;
+ case SID_FM_TIMEFIELD:
+ nIdentifier = SdrObjKind::FormTimeField;
+ break;
+ case SID_FM_NUMERICFIELD:
+ nIdentifier = SdrObjKind::FormNumericField;
+ break;
+ case SID_FM_CURRENCYFIELD:
+ nIdentifier = SdrObjKind::FormCurrencyField;
+ break;
+ case SID_FM_PATTERNFIELD:
+ nIdentifier = SdrObjKind::FormPatternField;
+ break;
+ case SID_FM_FORMATTEDFIELD:
+ nIdentifier = SdrObjKind::FormFormattedField;
+ break;
+ case SID_FM_SCROLLBAR:
+ nIdentifier = SdrObjKind::FormScrollbar;
+ break;
+ case SID_FM_SPINBUTTON:
+ nIdentifier = SdrObjKind::FormSpinButton;
+ break;
+ }
+
+ switch ( nSlot )
+ {
+ case SID_FM_CHECKBOX:
+ case SID_FM_PUSHBUTTON:
+ case SID_FM_FIXEDTEXT:
+ case SID_FM_LISTBOX:
+ case SID_FM_EDIT:
+ case SID_FM_RADIOBUTTON:
+ case SID_FM_COMBOBOX:
+ case SID_FM_NAVIGATIONBAR:
+ case SID_FM_GROUPBOX:
+ case SID_FM_DBGRID:
+ case SID_FM_IMAGEBUTTON:
+ case SID_FM_IMAGECONTROL:
+ case SID_FM_FILECONTROL:
+ case SID_FM_DATEFIELD:
+ case SID_FM_TIMEFIELD:
+ case SID_FM_NUMERICFIELD:
+ case SID_FM_CURRENCYFIELD:
+ case SID_FM_PATTERNFIELD:
+ case SID_FM_FORMATTEDFIELD:
+ case SID_FM_SCROLLBAR:
+ case SID_FM_SPINBUTTON:
+ {
+ const SfxBoolItem* pGrabFocusItem = rReq.GetArg<SfxBoolItem>(SID_FM_TOGGLECONTROLFOCUS);
+ if ( pGrabFocusItem && pGrabFocusItem->GetValue() )
+ { // see below
+ SfxViewShell* pShell = GetViewShell();
+ vcl::Window* pShellWnd = pShell ? pShell->GetWindow() : nullptr;
+ if ( pShellWnd )
+ pShellWnd->GrabFocus();
+ break;
+ }
+
+ SfxUInt16Item aIdentifierItem( SID_FM_CONTROL_IDENTIFIER, static_cast<sal_uInt16>(nIdentifier) );
+ SfxUInt32Item aInventorItem( SID_FM_CONTROL_INVENTOR, sal_uInt32(SdrInventor::FmForm) );
+ const SfxPoolItem* pArgs[] =
+ {
+ &aIdentifierItem, &aInventorItem, nullptr
+ };
+ const SfxPoolItem* pInternalArgs[] =
+ {
+ nullptr
+ };
+
+ GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( SID_FM_CREATE_CONTROL, SfxCallMode::ASYNCHRON,
+ pArgs, rReq.GetModifier(), pInternalArgs );
+
+ if ( rReq.GetModifier() & KEY_MOD1 )
+ {
+ // #99013# if selected with control key, return focus to current view
+ // do this asynchron, so that the creation can be finished first
+ // reusing the SID_FM_TOGGLECONTROLFOCUS is somewhat hacky... which it wouldn't if it would have another
+ // name, so I do not really have a big problem with this...
+ SfxBoolItem aGrabFocusIndicatorItem( SID_FM_TOGGLECONTROLFOCUS, true );
+ GetViewShell()->GetViewFrame()->GetDispatcher()->ExecuteList(
+ nSlot, SfxCallMode::ASYNCHRON,
+ { &aGrabFocusIndicatorItem });
+ }
+
+ rReq.Done();
+ } break;
+ }
+
+ // individual actions
+ switch( nSlot )
+ {
+ case SID_FM_FORM_DESIGN_TOOLS:
+ {
+ FormToolboxes aToolboxAccess(GetImpl()->getHostFrame_Lock());
+ aToolboxAccess.toggleToolbox( nSlot );
+ rReq.Done();
+ }
+ break;
+
+ case SID_FM_TOGGLECONTROLFOCUS:
+ {
+ FmFormView* pFormView = GetFormView();
+ if ( !pFormView )
+ break;
+
+ // if we execute this ourself, then either the application does not implement an own handling for this,
+ // of we're on the top of the dispatcher stack, which means a control has the focus.
+ // In the latter case, we put the focus to the document window, otherwise, we focus the first control
+ const bool bHasControlFocus = GetImpl()->HasControlFocus_Lock();
+ if ( bHasControlFocus )
+ {
+ if (m_pFormView)
+ {
+ const OutputDevice* pDevice = m_pFormView->GetActualOutDev();
+ vcl::Window* pWindow = pDevice->GetOwnerWindow();
+ if ( pWindow )
+ pWindow->GrabFocus();
+ }
+ }
+ else
+ {
+ pFormView->GrabFirstControlFocus( );
+ }
+ }
+ break;
+
+ case SID_FM_VIEW_AS_GRID:
+ GetImpl()->CreateExternalView_Lock();
+ break;
+ case SID_FM_CONVERTTO_EDIT :
+ case SID_FM_CONVERTTO_BUTTON :
+ case SID_FM_CONVERTTO_FIXEDTEXT :
+ case SID_FM_CONVERTTO_LISTBOX :
+ case SID_FM_CONVERTTO_CHECKBOX :
+ case SID_FM_CONVERTTO_RADIOBUTTON :
+ case SID_FM_CONVERTTO_GROUPBOX :
+ case SID_FM_CONVERTTO_COMBOBOX :
+ case SID_FM_CONVERTTO_IMAGEBUTTON :
+ case SID_FM_CONVERTTO_FILECONTROL :
+ case SID_FM_CONVERTTO_DATE :
+ case SID_FM_CONVERTTO_TIME :
+ case SID_FM_CONVERTTO_NUMERIC :
+ case SID_FM_CONVERTTO_CURRENCY :
+ case SID_FM_CONVERTTO_PATTERN :
+ case SID_FM_CONVERTTO_IMAGECONTROL :
+ case SID_FM_CONVERTTO_FORMATTED :
+ case SID_FM_CONVERTTO_SCROLLBAR :
+ case SID_FM_CONVERTTO_SPINBUTTON :
+ case SID_FM_CONVERTTO_NAVIGATIONBAR :
+ GetImpl()->executeControlConversionSlot_Lock(FmXFormShell::SlotToIdent(nSlot));
+ // after the conversion, re-determine the selection, since the
+ // selected object has changed
+ GetImpl()->SetSelection_Lock(GetFormView()->GetMarkedObjectList());
+ break;
+ case SID_FM_LEAVE_CREATE:
+ m_nLastSlot = 0;
+ rReq.Done();
+ break;
+ case SID_FM_SHOW_PROPERTY_BROWSER:
+ {
+ const SfxBoolItem* pShowItem = rReq.GetArg<SfxBoolItem>(SID_FM_SHOW_PROPERTIES);
+ bool bShow = true;
+ if ( pShowItem )
+ bShow = pShowItem->GetValue();
+ GetImpl()->ShowSelectionProperties_Lock(bShow);
+
+ rReq.Done();
+ } break;
+
+ case SID_FM_PROPERTIES:
+ {
+ // display the PropertyBrowser
+ const SfxBoolItem* pShowItem = rReq.GetArg<SfxBoolItem>(nSlot);
+ bool bShow = pShowItem == nullptr || pShowItem->GetValue();
+
+ InterfaceBag aOnlyTheForm;
+ aOnlyTheForm.insert(Reference<XInterface>(GetImpl()->getCurrentForm_Lock(), UNO_QUERY));
+ GetImpl()->setCurrentSelection_Lock(std::move(aOnlyTheForm));
+
+ GetImpl()->ShowSelectionProperties_Lock(bShow);
+
+ rReq.Done();
+ } break;
+
+ case SID_FM_CTL_PROPERTIES:
+ {
+ const SfxBoolItem* pShowItem = rReq.GetArg<SfxBoolItem>(nSlot);
+ bool bShow = pShowItem == nullptr || pShowItem->GetValue();
+
+ OSL_ENSURE( GetImpl()->onlyControlsAreMarked_Lock(), "FmFormShell::Execute: ControlProperties should be disabled!" );
+ if ( bShow )
+ GetImpl()->selectLastMarkedControls_Lock();
+ GetImpl()->ShowSelectionProperties_Lock(bShow);
+
+ rReq.Done();
+ } break;
+ case SID_FM_SHOW_PROPERTIES:
+ case SID_FM_ADD_FIELD:
+ case SID_FM_FILTER_NAVIGATOR:
+ case SID_FM_SHOW_DATANAVIGATOR :
+ {
+ GetViewShell()->GetViewFrame()->ToggleChildWindow(nSlot);
+ rReq.Done();
+ } break;
+ case SID_FM_SHOW_FMEXPLORER:
+ {
+ if (!m_pFormView) // force setting the view
+ GetViewShell()->GetViewFrame()->GetDispatcher()->Execute(SID_CREATE_SW_DRAWVIEW);
+
+ GetViewShell()->GetViewFrame()->ChildWindowExecute(rReq);
+ rReq.Done();
+ }
+ break;
+
+ case SID_FM_TAB_DIALOG:
+ {
+ GetImpl()->ExecuteTabOrderDialog_Lock(
+ Reference<XTabControllerModel>(GetImpl()->getCurrentForm_Lock(), UNO_QUERY));
+ rReq.Done();
+ }
+ break;
+
+ case SID_FM_DESIGN_MODE:
+ {
+ const SfxBoolItem* pDesignItem = rReq.GetArg<SfxBoolItem>(nSlot);
+ bool bDesignMode = pDesignItem ? pDesignItem->GetValue() : !m_bDesignMode;
+ SetDesignMode( bDesignMode );
+ if ( m_bDesignMode == bDesignMode )
+ rReq.Done();
+
+ m_nLastSlot = SID_FM_DESIGN_MODE;
+ }
+ break;
+
+ case SID_FM_AUTOCONTROLFOCUS:
+ {
+ FmFormModel* pModel = GetFormModel();
+ DBG_ASSERT(pModel, "FmFormShell::Execute : invalid call !");
+ // should have been disabled in GetState if we don't have a FormModel
+ pModel->SetAutoControlFocus( !pModel->GetAutoControlFocus() );
+ GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_AUTOCONTROLFOCUS);
+ }
+ break;
+ case SID_FM_OPEN_READONLY:
+ {
+ FmFormModel* pModel = GetFormModel();
+ DBG_ASSERT(pModel, "FmFormShell::Execute : invalid call !");
+ // should have been disabled in GetState if we don't have a FormModel
+ pModel->SetOpenInDesignMode( !pModel->GetOpenInDesignMode() );
+ GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_OPEN_READONLY);
+ }
+ break;
+ case SID_FM_USE_WIZARDS:
+ {
+ GetImpl()->SetWizardUsing_Lock(!GetImpl()->GetWizardUsing_Lock());
+ GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_USE_WIZARDS);
+ }
+ break;
+ case SID_FM_SEARCH:
+ {
+ const svx::ControllerFeatures& rController = GetImpl()->getActiveControllerFeatures_Lock();
+ if ( rController->commitCurrentControl() && rController->commitCurrentRecord() )
+ GetImpl()->ExecuteSearch_Lock();
+ rReq.Done();
+ }
+ break;
+
+ case SID_FM_RECORD_FIRST:
+ case SID_FM_RECORD_PREV:
+ case SID_FM_RECORD_NEXT:
+ case SID_FM_RECORD_LAST:
+ case SID_FM_RECORD_NEW:
+ case SID_FM_REFRESH:
+ case SID_FM_REFRESH_FORM_CONTROL:
+ case SID_FM_RECORD_DELETE:
+ case SID_FM_RECORD_UNDO:
+ case SID_FM_RECORD_SAVE:
+ case SID_FM_REMOVE_FILTER_SORT:
+ case SID_FM_SORTDOWN:
+ case SID_FM_SORTUP:
+ case SID_FM_AUTOFILTER:
+ case SID_FM_ORDERCRIT:
+ case SID_FM_FORM_FILTERED:
+ {
+ GetImpl()->ExecuteFormSlot_Lock(nSlot);
+ rReq.Done();
+ }
+ break;
+
+ case SID_FM_RECORD_ABSOLUTE:
+ {
+ const svx::ControllerFeatures& rController = GetImpl()->getNavControllerFeatures_Lock();
+ sal_Int32 nRecord = -1;
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if ( pArgs )
+ {
+ const SfxPoolItem* pItem;
+ if ( ( pArgs->GetItemState( FN_PARAM_1, true, &pItem ) ) == SfxItemState::SET )
+ {
+ const SfxInt32Item* pTypedItem = dynamic_cast<const SfxInt32Item* >( pItem );
+ if ( pTypedItem )
+ nRecord = std::max( pTypedItem->GetValue(), sal_Int32(0) );
+ }
+ }
+ else
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractFmInputRecordNoDialog> dlg(pFact->CreateFmInputRecordNoDialog(rReq.GetFrameWeld()));
+ dlg->SetValue( rController->getCursor()->getRow() );
+ if ( dlg->Execute() == RET_OK )
+ nRecord = dlg->GetValue();
+
+ rReq.AppendItem( SfxInt32Item( FN_PARAM_1, nRecord ) );
+ }
+
+ if ( nRecord != -1 )
+ rController->execute( nSlot, "Position", Any( nRecord ) );
+
+ rReq.Done();
+ } break;
+ case SID_FM_FILTER_EXECUTE:
+ case SID_FM_FILTER_EXIT:
+ {
+ bool bCancelled = ( SID_FM_FILTER_EXIT == nSlot );
+ bool bReopenNavigator = false;
+
+ if ( !bCancelled )
+ {
+ // if the filter navigator is still open, we need to close it, so it can possibly
+ // commit it's most recent changes
+ if ( GetViewShell() && GetViewShell()->GetViewFrame() )
+ if ( GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_FILTER_NAVIGATOR ) )
+ {
+ GetViewShell()->GetViewFrame()->ToggleChildWindow( SID_FM_FILTER_NAVIGATOR );
+ bReopenNavigator = true;
+ }
+
+ Reference<runtime::XFormController> const xController(GetImpl()->getActiveController_Lock());
+
+ if ( GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_FILTER_NAVIGATOR )
+ // closing the window was denied, for instance because of an invalid criterion
+
+ || ( xController.is()
+ && !GetImpl()->getActiveControllerFeatures_Lock()->commitCurrentControl()
+ )
+ // committing the controller was denied
+ )
+ {
+ rReq.Done();
+ break;
+ }
+ }
+
+ GetImpl()->stopFiltering_Lock(!bCancelled);
+ rReq.Done();
+
+ if ( bReopenNavigator )
+ // we closed the navigator only to implicitly commit it (as we do not have another
+ // direct wire to it), but to the user, it should look as it was always open
+ GetViewShell()->GetViewFrame()->ToggleChildWindow( SID_FM_FILTER_NAVIGATOR );
+ }
+ break;
+
+ case SID_FM_FILTER_START:
+ {
+ GetImpl()->startFiltering_Lock();
+ rReq.Done();
+
+ // initially open the filter navigator, the whole form based filter is pretty useless without it
+ SfxBoolItem aIdentifierItem( SID_FM_FILTER_NAVIGATOR, true );
+ GetViewShell()->GetViewFrame()->GetDispatcher()->ExecuteList(
+ SID_FM_FILTER_NAVIGATOR, SfxCallMode::ASYNCHRON,
+ { &aIdentifierItem });
+ } break;
+ }
+}
+
+
+void FmFormShell::GetState(SfxItemSet &rSet)
+{
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ switch( nWhich )
+ {
+ case SID_FM_FORM_DESIGN_TOOLS:
+ {
+ FormToolboxes aToolboxAccess(GetImpl()->getHostFrame_Lock());
+ rSet.Put( SfxBoolItem( nWhich, aToolboxAccess.isToolboxVisible( nWhich ) ) );
+ }
+ break;
+
+ case SID_FM_FILTER_EXECUTE:
+ case SID_FM_FILTER_EXIT:
+ if (!GetImpl()->isInFilterMode_Lock())
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_FM_USE_WIZARDS:
+ if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
+ rSet.Put( SfxVisibilityItem( nWhich, false ) );
+ else if (!GetFormModel())
+ rSet.DisableItem( nWhich );
+ else
+ rSet.Put(SfxBoolItem(nWhich, GetImpl()->GetWizardUsing_Lock()));
+ break;
+ case SID_FM_AUTOCONTROLFOCUS:
+ if (!GetFormModel())
+ rSet.DisableItem( nWhich );
+ else
+ rSet.Put( SfxBoolItem(nWhich, GetFormModel()->GetAutoControlFocus() ) );
+ break;
+ case SID_FM_OPEN_READONLY:
+ if (!GetFormModel())
+ rSet.DisableItem( nWhich );
+ else
+ rSet.Put( SfxBoolItem(nWhich, GetFormModel()->GetOpenInDesignMode() ) );
+ break;
+
+ case SID_FM_NAVIGATIONBAR:
+ case SID_FM_DBGRID:
+ if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
+ {
+ rSet.Put( SfxVisibilityItem( nWhich, false ) );
+ break;
+ }
+ [[fallthrough]];
+
+ case SID_FM_SCROLLBAR:
+ case SID_FM_IMAGECONTROL:
+ case SID_FM_FILECONTROL:
+ case SID_FM_CURRENCYFIELD:
+ case SID_FM_PATTERNFIELD:
+ case SID_FM_IMAGEBUTTON:
+ case SID_FM_RADIOBUTTON:
+ case SID_FM_COMBOBOX:
+ case SID_FM_GROUPBOX:
+ case SID_FM_CHECKBOX:
+ case SID_FM_PUSHBUTTON:
+ case SID_FM_FIXEDTEXT:
+ case SID_FM_LISTBOX:
+ case SID_FM_EDIT:
+ case SID_FM_DATEFIELD:
+ case SID_FM_TIMEFIELD:
+ case SID_FM_NUMERICFIELD:
+ case SID_FM_FORMATTEDFIELD:
+ case SID_FM_SPINBUTTON:
+ if (!m_bDesignMode)
+ rSet.DisableItem( nWhich );
+ else
+ {
+ bool bLayerLocked = false;
+ if (m_pFormView)
+ {
+ // If the css::drawing::Layer is locked, the slots must be disabled. #36897
+ SdrPageView* pPV = m_pFormView->GetSdrPageView();
+ if (pPV != nullptr)
+ bLayerLocked = pPV->IsLayerLocked(m_pFormView->GetActiveLayer());
+ }
+ if (bLayerLocked)
+ rSet.DisableItem( nWhich );
+ else
+ rSet.Put( SfxBoolItem(nWhich, (nWhich==m_nLastSlot)) );
+ }
+ break;
+ case SID_FM_FILTER_NAVIGATOR_CONTROL:
+ {
+ if (GetImpl()->isInFilterMode_Lock())
+ rSet.Put(SfxObjectItem(nWhich, this));
+ else
+ rSet.Put(SfxObjectItem(nWhich));
+ } break;
+ case SID_FM_FIELDS_CONTROL:
+ case SID_FM_PROPERTY_CONTROL:
+ {
+ if (!m_bDesignMode || !m_pFormView || !m_bHasForms)
+ rSet.Put(SfxObjectItem(nWhich));
+ else
+ rSet.Put(SfxObjectItem(nWhich, this));
+
+ } break;
+ case SID_FM_FMEXPLORER_CONTROL:
+ case SID_FM_DATANAVIGATOR_CONTROL :
+ {
+ if (!m_bDesignMode || !m_pFormView)
+ rSet.Put(SfxObjectItem(nWhich));
+ else
+ rSet.Put(SfxObjectItem(nWhich, this));
+
+ } break;
+ case SID_FM_ADD_FIELD:
+ case SID_FM_SHOW_FMEXPLORER:
+ case SID_FM_SHOW_PROPERTIES:
+ case SID_FM_FILTER_NAVIGATOR:
+ case SID_FM_SHOW_DATANAVIGATOR:
+ {
+ if ( GetViewShell()->GetViewFrame()->KnowsChildWindow(nWhich) )
+ rSet.Put( SfxBoolItem( nWhich, GetViewShell()->GetViewFrame()->HasChildWindow(nWhich)) );
+ else
+ rSet.DisableItem(nWhich);
+ } break;
+
+ case SID_FM_SHOW_PROPERTY_BROWSER:
+ {
+ rSet.Put(SfxBoolItem(nWhich, GetImpl()->IsPropBrwOpen_Lock()));
+ }
+ break;
+
+ case SID_FM_CTL_PROPERTIES:
+ {
+ // potentially, give the Impl the opportunity to update its
+ // current objects which are aligned with the current MarkList
+ if (GetImpl()->IsSelectionUpdatePending_Lock())
+ GetImpl()->ForceUpdateSelection_Lock();
+
+ if (!m_pFormView || !m_bDesignMode || !GetImpl()->onlyControlsAreMarked_Lock())
+ rSet.DisableItem( nWhich );
+ else
+ {
+ bool const bChecked = GetImpl()->IsPropBrwOpen_Lock() && !GetImpl()->isSolelySelected_Lock(GetImpl()->getCurrentForm_Lock());
+ // if the property browser is open, and only controls are marked, and the current selection
+ // does not consist of only the current form, then the current selection is the (composition of)
+ // the currently marked controls
+ rSet.Put( SfxBoolItem( nWhich, bChecked ) );
+ }
+ } break;
+
+ case SID_FM_PROPERTIES:
+ {
+ // potentially, give the Impl the opportunity to update its
+ // current objects which are aligned with the current MarkList
+ if (GetImpl()->IsSelectionUpdatePending_Lock())
+ GetImpl()->ForceUpdateSelection_Lock();
+
+ if (!m_pFormView || !m_bDesignMode || !GetImpl()->getCurrentForm_Lock().is())
+ rSet.DisableItem( nWhich );
+ else
+ {
+ bool const bChecked = GetImpl()->IsPropBrwOpen_Lock() && GetImpl()->isSolelySelected_Lock(GetImpl()->getCurrentForm_Lock());
+ rSet.Put(SfxBoolItem(nWhich, bChecked));
+ }
+ } break;
+ case SID_FM_TAB_DIALOG:
+ // potentially, give the Impl the opportunity to update its
+ // current objects which are aligned with the current MarkList
+ if (GetImpl()->IsSelectionUpdatePending_Lock())
+ GetImpl()->ForceUpdateSelection_Lock();
+
+ if (!m_pFormView || !m_bDesignMode || !GetImpl()->getCurrentForm_Lock().is() )
+ rSet.DisableItem( nWhich );
+ break;
+ case SID_FM_DESIGN_MODE:
+ if (!m_pFormView || GetImpl()->IsReadonlyDoc_Lock())
+ rSet.DisableItem( nWhich );
+ else
+ rSet.Put( SfxBoolItem(nWhich, m_bDesignMode) );
+ break;
+ case SID_FM_SEARCH:
+ case SID_FM_RECORD_FIRST:
+ case SID_FM_RECORD_NEXT:
+ case SID_FM_RECORD_PREV:
+ case SID_FM_RECORD_LAST:
+ case SID_FM_RECORD_NEW:
+ case SID_FM_RECORD_DELETE:
+ case SID_FM_RECORD_ABSOLUTE:
+ case SID_FM_RECORD_TOTAL:
+ case SID_FM_RECORD_SAVE:
+ case SID_FM_RECORD_UNDO:
+ case SID_FM_FORM_FILTERED:
+ case SID_FM_REMOVE_FILTER_SORT:
+ case SID_FM_SORTUP:
+ case SID_FM_SORTDOWN:
+ case SID_FM_ORDERCRIT:
+ case SID_FM_FILTER_START:
+ case SID_FM_AUTOFILTER:
+ case SID_FM_REFRESH:
+ case SID_FM_REFRESH_FORM_CONTROL:
+ case SID_FM_VIEW_AS_GRID:
+ GetFormState(rSet,nWhich);
+ break;
+
+ case SID_FM_CHANGECONTROLTYPE:
+ {
+ if ( !m_pFormView || !m_bDesignMode )
+ rSet.DisableItem( nWhich );
+ else
+ {
+ if (!GetImpl()->canConvertCurrentSelectionToControl_Lock("ConvertToFixed"))
+ // if it cannot be converted to a fixed text, it is no single control
+ rSet.DisableItem( nWhich );
+ }
+ } break;
+
+ case SID_FM_CONVERTTO_FILECONTROL :
+ case SID_FM_CONVERTTO_CURRENCY :
+ case SID_FM_CONVERTTO_PATTERN :
+ case SID_FM_CONVERTTO_IMAGECONTROL :
+ case SID_FM_CONVERTTO_SCROLLBAR :
+ case SID_FM_CONVERTTO_NAVIGATIONBAR :
+ case SID_FM_CONVERTTO_IMAGEBUTTON :
+ case SID_FM_CONVERTTO_EDIT :
+ case SID_FM_CONVERTTO_BUTTON :
+ case SID_FM_CONVERTTO_FIXEDTEXT :
+ case SID_FM_CONVERTTO_LISTBOX :
+ case SID_FM_CONVERTTO_CHECKBOX :
+ case SID_FM_CONVERTTO_RADIOBUTTON :
+ case SID_FM_CONVERTTO_GROUPBOX :
+ case SID_FM_CONVERTTO_COMBOBOX :
+ case SID_FM_CONVERTTO_DATE :
+ case SID_FM_CONVERTTO_TIME :
+ case SID_FM_CONVERTTO_NUMERIC :
+ case SID_FM_CONVERTTO_FORMATTED :
+ case SID_FM_CONVERTTO_SPINBUTTON :
+ {
+ if (!m_pFormView || !m_bDesignMode || !GetImpl()->canConvertCurrentSelectionToControl_Lock(FmXFormShell::SlotToIdent(nWhich)))
+ rSet.DisableItem( nWhich );
+ else
+ {
+ rSet.Put( SfxBoolItem( nWhich, false ) );
+ // just to have a defined state (available and not checked)
+ }
+ }
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+
+void FmFormShell::GetFormState(SfxItemSet &rSet, sal_uInt16 nWhich)
+{
+ if ( !GetImpl()->getNavController_Lock().is()
+ || !isRowSetAlive(GetImpl()->getNavController_Lock()->getModel())
+ || !m_pFormView
+ || m_bDesignMode
+ || !GetImpl()->getActiveForm_Lock().is()
+ || GetImpl()->isInFilterMode_Lock()
+ )
+ rSet.DisableItem(nWhich);
+ else
+ {
+ bool bEnable = false;
+ try
+ {
+ switch (nWhich)
+ {
+ case SID_FM_VIEW_AS_GRID:
+ if (GetImpl()->getHostFrame_Lock().is() && GetImpl()->getNavController_Lock().is())
+ {
+ bEnable = true;
+ bool bDisplayingCurrent =
+ GetImpl()->getInternalForm_Lock(
+ Reference<XForm>(GetImpl()->getNavController_Lock()->getModel(), UNO_QUERY)
+ ) == GetImpl()->getExternallyDisplayedForm_Lock();
+ rSet.Put(SfxBoolItem(nWhich, bDisplayingCurrent));
+ }
+ break;
+
+ case SID_FM_SEARCH:
+ {
+ Reference<css::beans::XPropertySet> const xNavSet(GetImpl()->getActiveForm_Lock(), UNO_QUERY);
+ sal_Int32 nCount = ::comphelper::getINT32(xNavSet->getPropertyValue(FM_PROP_ROWCOUNT));
+ bEnable = nCount != 0;
+ } break;
+ case SID_FM_RECORD_ABSOLUTE:
+ case SID_FM_RECORD_TOTAL:
+ {
+ FeatureState aState;
+ GetImpl()->getNavControllerFeatures_Lock()->getState( nWhich, aState );
+ if ( SID_FM_RECORD_ABSOLUTE == nWhich )
+ {
+ sal_Int32 nPosition = 0;
+ aState.State >>= nPosition;
+ rSet.Put( SfxInt32Item( nWhich, nPosition ) );
+ }
+ else if ( SID_FM_RECORD_TOTAL == nWhich )
+ {
+ OUString sTotalCount;
+ aState.State >>= sTotalCount;
+ rSet.Put( SfxStringItem( nWhich, sTotalCount ) );
+ }
+ bEnable = aState.Enabled;
+ }
+ break;
+
+ // first, prev, next, last, and absolute affect the nav controller, not the
+ // active controller
+ case SID_FM_RECORD_FIRST:
+ case SID_FM_RECORD_PREV:
+ case SID_FM_RECORD_NEXT:
+ case SID_FM_RECORD_LAST:
+ case SID_FM_RECORD_NEW:
+ case SID_FM_RECORD_SAVE:
+ case SID_FM_RECORD_UNDO:
+ case SID_FM_RECORD_DELETE:
+ case SID_FM_REFRESH:
+ case SID_FM_REFRESH_FORM_CONTROL:
+ case SID_FM_REMOVE_FILTER_SORT:
+ case SID_FM_SORTUP:
+ case SID_FM_SORTDOWN:
+ case SID_FM_AUTOFILTER:
+ case SID_FM_ORDERCRIT:
+ bEnable = GetImpl()->IsFormSlotEnabled( nWhich, nullptr );
+ break;
+
+ case SID_FM_FORM_FILTERED:
+ {
+ FeatureState aState;
+ bEnable = GetImpl()->IsFormSlotEnabled( nWhich, &aState );
+
+ rSet.Put( SfxBoolItem( nWhich, ::comphelper::getBOOL( aState.State ) ) );
+ }
+ break;
+
+ case SID_FM_FILTER_START:
+ bEnable = GetImpl()->getActiveControllerFeatures_Lock()->canDoFormFilter();
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while determining the state!");
+ }
+ if (!bEnable)
+ rSet.DisableItem(nWhich);
+ }
+}
+
+
+FmFormPage* FmFormShell::GetCurPage() const
+{
+ FmFormPage* pP = nullptr;
+ if (m_pFormView && m_pFormView->GetSdrPageView())
+ pP = dynamic_cast<FmFormPage*>( m_pFormView->GetSdrPageView()->GetPage() );
+ return pP;
+}
+
+
+void FmFormShell::SetView( FmFormView* _pView )
+{
+ if ( m_pFormView )
+ {
+ if ( IsActive() )
+ GetImpl()->viewDeactivated_Lock(*m_pFormView);
+
+ m_pFormView->SetFormShell( nullptr, FmFormView::FormShellAccess() );
+ m_pFormView = nullptr;
+ m_pFormModel = nullptr;
+ }
+
+ if ( !_pView )
+ return;
+
+ m_pFormView = _pView;
+ m_pFormView->SetFormShell( this, FmFormView::FormShellAccess() );
+ m_pFormModel = static_cast<FmFormModel*>(m_pFormView->GetModel());
+
+ impl_setDesignMode( m_pFormView->IsDesignMode() );
+
+ // We activate our view if we are activated ourself, but sometimes the Activate precedes the SetView.
+ // But here we know both the view and our activation state so we at least are able to pass the latter
+ // to the former.
+ // FS - 30.06.99 - 67308
+ if ( IsActive() )
+ GetImpl()->viewActivated_Lock(*m_pFormView);
+}
+
+
+void FmFormShell::DetermineForms(bool bInvalidate)
+{
+ // are there forms on the current page
+ bool bForms = GetImpl()->hasForms_Lock();
+ if (bForms != m_bHasForms)
+ {
+ m_bHasForms = bForms;
+ if (bInvalidate)
+ UIFeatureChanged();
+ }
+}
+
+
+bool FmFormShell::GetY2KState(sal_uInt16& nReturn)
+{
+ return GetImpl()->GetY2KState_Lock(nReturn);
+}
+
+
+void FmFormShell::SetY2KState(sal_uInt16 n)
+{
+ GetImpl()->SetY2KState_Lock(n);
+}
+
+
+void FmFormShell::Activate(bool bMDI)
+{
+ SfxShell::Activate(bMDI);
+
+ if ( m_pFormView )
+ GetImpl()->viewActivated_Lock(*m_pFormView, true);
+}
+
+
+void FmFormShell::Deactivate(bool bMDI)
+{
+ SfxShell::Deactivate(bMDI);
+
+ if ( m_pFormView )
+ GetImpl()->viewDeactivated_Lock(*m_pFormView, false);
+}
+
+
+void FmFormShell::ExecuteTextAttribute( SfxRequest& _rReq )
+{
+ m_pImpl->ExecuteTextAttribute_Lock(_rReq);
+}
+
+
+void FmFormShell::GetTextAttributeState( SfxItemSet& _rSet )
+{
+ m_pImpl->GetTextAttributeState_Lock(_rSet);
+}
+
+
+bool FmFormShell::IsActiveControl() const
+{
+ return m_pImpl->IsActiveControl_Lock(false);
+}
+
+
+void FmFormShell::ForgetActiveControl()
+{
+ m_pImpl->ForgetActiveControl_Lock();
+}
+
+
+void FmFormShell::SetControlActivationHandler( const Link<LinkParamNone*,void>& _rHdl )
+{
+ m_pImpl->SetControlActivationHandler_Lock(_rHdl);
+}
+
+
+namespace
+{
+ SdrUnoObj* lcl_findUnoObject( const SdrObjList& _rObjList, const Reference< XControlModel >& _rxModel )
+ {
+ SdrObjListIter aIter( &_rObjList );
+ while ( aIter.IsMore() )
+ {
+ SdrObject* pObject = aIter.Next();
+ SdrUnoObj* pUnoObject = dynamic_cast<SdrUnoObj*>( pObject );
+ if ( !pUnoObject )
+ continue;
+
+ Reference< XControlModel > xControlModel = pUnoObject->GetUnoControlModel();
+ if ( !xControlModel.is() )
+ continue;
+
+ if ( _rxModel == xControlModel )
+ return pUnoObject;
+ }
+ return nullptr;
+ }
+}
+
+
+void FmFormShell::ToggleControlFocus( const SdrUnoObj& i_rUnoObject, const SdrView& i_rView, const OutputDevice& i_rDevice ) const
+{
+ try
+ {
+ // check if the focus currently is in a control
+ // Well, okay, do it the other way 'round: Check whether the current control of the active controller
+ // actually has the focus. This should be equivalent.
+ const bool bHasControlFocus = GetImpl()->HasControlFocus_Lock();
+
+ if ( bHasControlFocus )
+ {
+ vcl::Window* pWindow = i_rDevice.GetOwnerWindow();
+ OSL_ENSURE( pWindow, "FmFormShell::ToggleControlFocus: I need a Window, really!" );
+ if ( pWindow )
+ pWindow->GrabFocus();
+ }
+ else
+ {
+ Reference< XControl > xControl;
+ GetFormControl( i_rUnoObject.GetUnoControlModel(), i_rView, i_rDevice, xControl );
+ Reference< XWindow > xControlWindow( xControl, UNO_QUERY );
+ if ( xControlWindow.is() )
+ xControlWindow->setFocus();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+namespace
+{
+ class FocusableControlsFilter : public svx::ISdrObjectFilter
+ {
+ public:
+ FocusableControlsFilter( const SdrView& i_rView, const OutputDevice& i_rDevice )
+ :m_rView( i_rView )
+ ,m_rDevice( i_rDevice )
+ {
+ }
+
+ public:
+ virtual bool includeObject( const SdrObject& i_rObject ) const override
+ {
+ const SdrUnoObj* pUnoObj = dynamic_cast< const SdrUnoObj* >( &i_rObject );
+ if ( !pUnoObj )
+ return false;
+
+ Reference< XControl > xControl = pUnoObj->GetUnoControl( m_rView, m_rDevice );
+ return FmXFormView::isFocusable( xControl );
+ }
+
+ private:
+ const SdrView& m_rView;
+ const OutputDevice& m_rDevice;
+ };
+}
+
+
+::std::unique_ptr< svx::ISdrObjectFilter > FmFormShell::CreateFocusableControlFilter( const SdrView& i_rView, const OutputDevice& i_rDevice )
+{
+ ::std::unique_ptr< svx::ISdrObjectFilter > pFilter;
+
+ if ( !i_rView.IsDesignMode() )
+ pFilter.reset( new FocusableControlsFilter( i_rView, i_rDevice ) );
+
+ return pFilter;
+}
+
+
+SdrUnoObj* FmFormShell::GetFormControl( const Reference< XControlModel >& _rxModel, const SdrView& _rView, const OutputDevice& _rDevice, Reference< XControl >& _out_rxControl ) const
+{
+ if ( !_rxModel.is() )
+ return nullptr;
+
+ // we can only retrieve controls for SdrObjects which belong to page which is actually displayed in the given view
+ SdrPageView* pPageView = _rView.GetSdrPageView();
+ SdrPage* pPage = pPageView ? pPageView->GetPage() : nullptr;
+ OSL_ENSURE( pPage, "FmFormShell::GetFormControl: no page displayed in the given view!" );
+ if ( !pPage )
+ return nullptr;
+
+ SdrUnoObj* pUnoObject = lcl_findUnoObject( *pPage, _rxModel );
+ if ( pUnoObject )
+ {
+ _out_rxControl = pUnoObject->GetUnoControl( _rView, _rDevice );
+ return pUnoObject;
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ // perhaps we are fed with a control model which lives on a page other than the one displayed
+ // in the given view. This is worth being reported as error, in non-product builds.
+ FmFormModel* pModel = GetFormModel();
+ if ( pModel )
+ {
+ sal_uInt16 pageCount = pModel->GetPageCount();
+ for ( sal_uInt16 page = 0; page < pageCount; ++page )
+ {
+ pPage = pModel->GetPage( page );
+ OSL_ENSURE( pPage, "FmFormShell::GetFormControl: NULL page encountered!" );
+ if ( !pPage )
+ continue;
+
+ pUnoObject = lcl_findUnoObject( *pPage, _rxModel );
+ OSL_ENSURE( !pUnoObject, "FmFormShell::GetFormControl: the given control model belongs to a wrong page (displayed elsewhere)!" );
+ }
+ }
+#else
+ (void) this; // avoid loplugin:staticmethods
+#endif
+
+ return nullptr;
+}
+
+
+Reference< runtime::XFormController > FmFormShell::GetFormController( const Reference< XForm >& _rxForm, const SdrView& _rView, const OutputDevice& _rDevice )
+{
+ const FmFormView* pFormView = dynamic_cast< const FmFormView* >( &_rView );
+ if ( !pFormView )
+ return nullptr;
+
+ return pFormView->GetFormController( _rxForm, _rDevice );
+}
+
+
+void FmFormShell::SetDesignMode( bool _bDesignMode )
+{
+ if ( _bDesignMode == m_bDesignMode )
+ return;
+
+ FmFormModel* pModel = GetFormModel();
+ if (pModel)
+ // Switch off the undo environment for the time of the transition. This ensures that
+ // one can also change non-transient properties there. (It should be done with
+ // caution, however, and it should always be reversed when one switches the mode back.
+ // An example is the setting of the maximum text length by the OEditModel on its control.)
+ pModel->GetUndoEnv().Lock();
+
+ // then the actual switch
+ if ( m_bDesignMode || PrepareClose() )
+ impl_setDesignMode(!m_bDesignMode );
+
+ // and my undo environment back on
+ if ( pModel )
+ pModel->GetUndoEnv().UnLock();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmshimp.cxx b/svx/source/form/fmshimp.cxx
new file mode 100644
index 000000000..8eb83000b
--- /dev/null
+++ b/svx/source/form/fmshimp.cxx
@@ -0,0 +1,3960 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/safeint.hxx>
+#include <sal/macros.h>
+#include <sal/log.hxx>
+#include <fmobj.hxx>
+#include <fmpgeimp.hxx>
+#include <svx/fmtools.hxx>
+#include <fmprop.hxx>
+#include <fmservs.hxx>
+#include <fmshimp.hxx>
+#include <fmtextcontrolshell.hxx>
+#include <fmundo.hxx>
+#include <fmurl.hxx>
+#include <fmvwimp.hxx>
+#include <gridcols.hxx>
+#include <svx/svditer.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdobjkind.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/fmview.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/svxids.hrc>
+#include <bitmaps.hlst>
+#include <formnavi.hrc>
+
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <com/sun/star/awt/XCheckBox.hpp>
+#include <com/sun/star/awt/XListBox.hpp>
+#include <com/sun/star/awt/XTextComponent.hpp>
+#include <com/sun/star/beans/theIntrospection.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/form/ListSourceType.hpp>
+#include <com/sun/star/form/TabOrderDialog.hpp>
+#include <com/sun/star/form/XGrid.hpp>
+#include <com/sun/star/form/XGridPeer.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/form/XReset.hpp>
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XListEntrySink.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/util/XModeSelector.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+
+#include <comphelper/evtmethodhelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/solarmutex.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/window.hxx>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string_view>
+#include <vector>
+
+// is used for Invalidate -> maintain it as well
+const sal_uInt16 DatabaseSlotMap[] =
+{
+ SID_FM_RECORD_FIRST,
+ SID_FM_RECORD_NEXT,
+ SID_FM_RECORD_PREV,
+ SID_FM_RECORD_LAST,
+ SID_FM_RECORD_NEW,
+ SID_FM_RECORD_DELETE,
+ SID_FM_RECORD_ABSOLUTE,
+ SID_FM_RECORD_TOTAL,
+ SID_FM_RECORD_SAVE,
+ SID_FM_RECORD_UNDO,
+ SID_FM_REMOVE_FILTER_SORT,
+ SID_FM_SORTUP,
+ SID_FM_SORTDOWN,
+ SID_FM_ORDERCRIT,
+ SID_FM_AUTOFILTER,
+ SID_FM_FORM_FILTERED,
+ SID_FM_REFRESH,
+ SID_FM_REFRESH_FORM_CONTROL,
+ SID_FM_SEARCH,
+ SID_FM_FILTER_START,
+ SID_FM_VIEW_AS_GRID,
+ 0
+};
+
+// is used for Invalidate -> maintain it as well
+// sort ascending !!!!!!
+const sal_Int16 DlgSlotMap[] = // slots of the controller
+{
+ SID_FM_CTL_PROPERTIES,
+ SID_FM_PROPERTIES,
+ SID_FM_TAB_DIALOG,
+ SID_FM_ADD_FIELD,
+ SID_FM_SHOW_FMEXPLORER,
+ SID_FM_FIELDS_CONTROL,
+ SID_FM_SHOW_PROPERTIES,
+ SID_FM_PROPERTY_CONTROL,
+ SID_FM_FMEXPLORER_CONTROL,
+ SID_FM_SHOW_DATANAVIGATOR,
+ SID_FM_DATANAVIGATOR_CONTROL,
+ 0
+};
+
+const sal_Int16 SelObjectSlotMap[] = // slots depending on the SelObject
+{
+ SID_FM_CONVERTTO_EDIT,
+ SID_FM_CONVERTTO_BUTTON,
+ SID_FM_CONVERTTO_FIXEDTEXT,
+ SID_FM_CONVERTTO_LISTBOX,
+ SID_FM_CONVERTTO_CHECKBOX,
+ SID_FM_CONVERTTO_RADIOBUTTON,
+ SID_FM_CONVERTTO_GROUPBOX,
+ SID_FM_CONVERTTO_COMBOBOX,
+ SID_FM_CONVERTTO_IMAGEBUTTON,
+ SID_FM_CONVERTTO_FILECONTROL,
+ SID_FM_CONVERTTO_DATE,
+ SID_FM_CONVERTTO_TIME,
+ SID_FM_CONVERTTO_NUMERIC,
+ SID_FM_CONVERTTO_CURRENCY,
+ SID_FM_CONVERTTO_PATTERN,
+ SID_FM_CONVERTTO_IMAGECONTROL,
+ SID_FM_CONVERTTO_FORMATTED,
+ SID_FM_CONVERTTO_SCROLLBAR,
+ SID_FM_CONVERTTO_SPINBUTTON,
+ SID_FM_CONVERTTO_NAVIGATIONBAR,
+
+ SID_FM_FMEXPLORER_CONTROL,
+ SID_FM_DATANAVIGATOR_CONTROL,
+
+ 0
+};
+
+// the following arrays must be consistent, i.e., corresponding entries should
+// be at the same relative position within their respective arrays
+static const char* aConvertSlots[] =
+{
+ "ConvertToEdit",
+ "ConvertToButton",
+ "ConvertToFixed",
+ "ConvertToList",
+ "ConvertToCheckBox",
+ "ConvertToRadio",
+ "ConvertToGroup",
+ "ConvertToCombo",
+ "ConvertToImageBtn",
+ "ConvertToFileControl",
+ "ConvertToDate",
+ "ConvertToTime",
+ "ConvertToNumeric",
+ "ConvertToCurrency",
+ "ConvertToPattern",
+ "ConvertToImageControl",
+ "ConvertToFormatted",
+ "ConvertToScrollBar",
+ "ConvertToSpinButton",
+ "ConvertToNavigationBar"
+};
+
+constexpr rtl::OUStringConstExpr aImgIds[] =
+{
+ RID_SVXBMP_EDITBOX,
+ RID_SVXBMP_BUTTON,
+ RID_SVXBMP_FIXEDTEXT,
+ RID_SVXBMP_LISTBOX,
+ RID_SVXBMP_CHECKBOX,
+ RID_SVXBMP_RADIOBUTTON,
+ RID_SVXBMP_GROUPBOX,
+ RID_SVXBMP_COMBOBOX,
+ RID_SVXBMP_IMAGEBUTTON,
+ RID_SVXBMP_FILECONTROL,
+ RID_SVXBMP_DATEFIELD,
+ RID_SVXBMP_TIMEFIELD,
+ RID_SVXBMP_NUMERICFIELD,
+ RID_SVXBMP_CURRENCYFIELD,
+ RID_SVXBMP_PATTERNFIELD,
+ RID_SVXBMP_IMAGECONTROL,
+ RID_SVXBMP_FORMATTEDFIELD,
+ RID_SVXBMP_SCROLLBAR,
+ RID_SVXBMP_SPINBUTTON,
+ RID_SVXBMP_NAVIGATIONBAR
+};
+
+const SdrObjKind nObjectTypes[] =
+{
+ SdrObjKind::FormEdit,
+ SdrObjKind::FormButton,
+ SdrObjKind::FormFixedText,
+ SdrObjKind::FormListbox,
+ SdrObjKind::FormCheckbox,
+ SdrObjKind::FormRadioButton,
+ SdrObjKind::FormGroupBox,
+ SdrObjKind::FormCombobox,
+ SdrObjKind::FormImageButton,
+ SdrObjKind::FormFileControl,
+ SdrObjKind::FormDateField,
+ SdrObjKind::FormTimeField,
+ SdrObjKind::FormNumericField,
+ SdrObjKind::FormCurrencyField,
+ SdrObjKind::FormPatternField,
+ SdrObjKind::FormImageControl,
+ SdrObjKind::FormFormattedField,
+ SdrObjKind::FormScrollbar,
+ SdrObjKind::FormSpinButton,
+ SdrObjKind::FormNavigationBar
+};
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::ui;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::form::binding;
+using namespace ::com::sun::star::form::runtime;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::script;
+using namespace ::svxform;
+using namespace ::svx;
+using namespace ::dbtools;
+
+
+//= helper
+
+namespace
+{
+
+ void collectInterfacesFromMarkList( const SdrMarkList& _rMarkList, InterfaceBag& /* [out] */ _rInterfaces )
+ {
+ _rInterfaces.clear();
+
+ const size_t nMarkCount = _rMarkList.GetMarkCount();
+ for ( size_t i = 0; i < nMarkCount; ++i)
+ {
+ SdrObject* pCurrent = _rMarkList.GetMark( i )->GetMarkedSdrObj();
+
+ std::unique_ptr<SdrObjListIter> pGroupIterator;
+ if ( pCurrent->IsGroupObject() )
+ {
+ pGroupIterator.reset(new SdrObjListIter( pCurrent->GetSubList() ));
+ pCurrent = pGroupIterator->IsMore() ? pGroupIterator->Next() : nullptr;
+ }
+
+ while ( pCurrent )
+ {
+ FmFormObj* pAsFormObject = FmFormObj::GetFormObject( pCurrent );
+ // note this will de-reference virtual objects, if necessary/possible
+ if ( pAsFormObject )
+ {
+ Reference< XInterface > xControlModel( pAsFormObject->GetUnoControlModel(), UNO_QUERY );
+ // the UNO_QUERY is important for normalization
+ if ( xControlModel.is() )
+ _rInterfaces.insert( xControlModel );
+ }
+
+ // next element
+ pCurrent = pGroupIterator && pGroupIterator->IsMore() ? pGroupIterator->Next() : nullptr;
+ }
+ }
+ }
+
+
+ sal_Int32 GridView2ModelPos(const Reference< XIndexAccess>& rColumns, sal_Int16 nViewPos)
+ {
+ try
+ {
+ if (rColumns.is())
+ {
+ // loop through all columns
+ sal_Int32 i;
+ Reference< XPropertySet> xCur;
+ for (i=0; i<rColumns->getCount(); ++i)
+ {
+ rColumns->getByIndex(i) >>= xCur;
+ if (!::comphelper::getBOOL(xCur->getPropertyValue(FM_PROP_HIDDEN)))
+ {
+ // for every visible col : if nViewPos is greater zero, decrement it, else we
+ // have found the model position
+ if (!nViewPos)
+ break;
+ else
+ --nViewPos;
+ }
+ }
+ if (i<rColumns->getCount())
+ return i;
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return -1;
+ }
+
+
+ void TransferEventScripts(const Reference< XControlModel>& xModel, const Reference< XControl>& xControl,
+ const Sequence< ScriptEventDescriptor>& rTransferIfAvailable)
+ {
+ // first check if we have a XEventAttacherManager for the model
+ Reference< XChild> xModelChild(xModel, UNO_QUERY);
+ if (!xModelChild.is())
+ return; // nothing to do
+
+ Reference< XEventAttacherManager> xEventManager(xModelChild->getParent(), UNO_QUERY);
+ if (!xEventManager.is())
+ return; // nothing to do
+
+ if (!rTransferIfAvailable.hasElements())
+ return; // nothing to do
+
+ // check for the index of the model within its parent
+ Reference< XIndexAccess> xParentIndex(xModelChild->getParent(), UNO_QUERY);
+ if (!xParentIndex.is())
+ return; // nothing to do
+ sal_Int32 nIndex = getElementPos(xParentIndex, xModel);
+ if (nIndex<0 || nIndex>=xParentIndex->getCount())
+ return; // nothing to do
+
+ // then we need information about the listeners supported by the control and the model
+ Sequence< Type> aModelListeners;
+ Sequence< Type> aControlListeners;
+
+ Reference< XIntrospection> xIntrospection = theIntrospection::get(::comphelper::getProcessComponentContext());
+
+ if (xModel.is())
+ {
+ Any aModel(xModel);
+ aModelListeners = xIntrospection->inspect(aModel)->getSupportedListeners();
+ }
+
+ if (xControl.is())
+ {
+ Any aControl(xControl);
+ aControlListeners = xIntrospection->inspect(aControl)->getSupportedListeners();
+ }
+
+ sal_Int32 nMaxNewLen = aModelListeners.getLength() + aControlListeners.getLength();
+ if (!nMaxNewLen)
+ return; // the model and the listener don't support any listeners (or we were unable to retrieve these infos)
+
+ Sequence< ScriptEventDescriptor> aTransferable(nMaxNewLen);
+ ScriptEventDescriptor* pTransferable = aTransferable.getArray();
+
+ for (const ScriptEventDescriptor& rCurrent : rTransferIfAvailable)
+ {
+ // search the model/control idl classes for the event described by pCurrent
+ for (const Sequence< Type>* pCurrentArray : { &aModelListeners, &aControlListeners })
+ {
+ for (const Type& rCurrentListener : *pCurrentArray)
+ {
+ OUString aListener = rCurrentListener.getTypeName();
+ if (!aListener.isEmpty())
+ aListener = aListener.copy(aListener.lastIndexOf('.')+1);
+
+ if (aListener == rCurrent.ListenerType)
+ // the current ScriptEventDescriptor doesn't match the current listeners class
+ continue;
+
+ // now check the methods
+ Sequence< OUString> aMethodsNames = ::comphelper::getEventMethodsForType(rCurrentListener);
+
+ if (comphelper::findValue(aMethodsNames, rCurrent.EventMethod) != -1)
+ {
+ // we can transfer the script event : the model (control) supports it
+ *pTransferable = rCurrent;
+ ++pTransferable;
+ break;
+ }
+ }
+ }
+ }
+
+ sal_Int32 nRealNewLen = pTransferable - aTransferable.getArray();
+ aTransferable.realloc(nRealNewLen);
+
+ xEventManager->registerScriptEvents(nIndex, aTransferable);
+ }
+
+
+ OUString getServiceNameByControlType(SdrObjKind nType)
+ {
+ switch (nType)
+ {
+ case SdrObjKind::FormEdit : return FM_COMPONENT_TEXTFIELD;
+ case SdrObjKind::FormButton : return FM_COMPONENT_COMMANDBUTTON;
+ case SdrObjKind::FormFixedText : return FM_COMPONENT_FIXEDTEXT;
+ case SdrObjKind::FormListbox : return FM_COMPONENT_LISTBOX;
+ case SdrObjKind::FormCheckbox : return FM_COMPONENT_CHECKBOX;
+ case SdrObjKind::FormRadioButton : return FM_COMPONENT_RADIOBUTTON;
+ case SdrObjKind::FormGroupBox : return FM_COMPONENT_GROUPBOX;
+ case SdrObjKind::FormCombobox : return FM_COMPONENT_COMBOBOX;
+ case SdrObjKind::FormGrid : return FM_COMPONENT_GRIDCONTROL;
+ case SdrObjKind::FormImageButton : return FM_COMPONENT_IMAGEBUTTON;
+ case SdrObjKind::FormFileControl : return FM_COMPONENT_FILECONTROL;
+ case SdrObjKind::FormDateField : return FM_COMPONENT_DATEFIELD;
+ case SdrObjKind::FormTimeField : return FM_COMPONENT_TIMEFIELD;
+ case SdrObjKind::FormNumericField : return FM_COMPONENT_NUMERICFIELD;
+ case SdrObjKind::FormCurrencyField : return FM_COMPONENT_CURRENCYFIELD;
+ case SdrObjKind::FormPatternField : return FM_COMPONENT_PATTERNFIELD;
+ case SdrObjKind::FormHidden : return FM_COMPONENT_HIDDENCONTROL;
+ case SdrObjKind::FormImageControl : return FM_COMPONENT_IMAGECONTROL;
+ case SdrObjKind::FormFormattedField : return FM_COMPONENT_FORMATTEDFIELD;
+ case SdrObjKind::FormScrollbar : return FM_SUN_COMPONENT_SCROLLBAR;
+ case SdrObjKind::FormSpinButton : return FM_SUN_COMPONENT_SPINBUTTON;
+ case SdrObjKind::FormNavigationBar : return FM_SUN_COMPONENT_NAVIGATIONBAR;
+ default:;
+ }
+ return OUString();
+ }
+
+}
+
+
+// check if the control has one of the interfaces we can use for searching
+// *_pCurrentText will be filled with the current text of the control (as used when searching this control)
+bool IsSearchableControl( const css::uno::Reference< css::uno::XInterface>& _rxControl,
+ OUString* _pCurrentText )
+{
+ if ( !_rxControl.is() )
+ return false;
+
+ Reference< XTextComponent > xAsText( _rxControl, UNO_QUERY );
+ if ( xAsText.is() )
+ {
+ if ( _pCurrentText )
+ *_pCurrentText = xAsText->getText();
+ return true;
+ }
+
+ Reference< XListBox > xListBox( _rxControl, UNO_QUERY );
+ if ( xListBox.is() )
+ {
+ if ( _pCurrentText )
+ *_pCurrentText = xListBox->getSelectedItem();
+ return true;
+ }
+
+ Reference< XCheckBox > xCheckBox( _rxControl, UNO_QUERY );
+ if ( xCheckBox.is() )
+ {
+ if ( _pCurrentText )
+ {
+ switch ( static_cast<::TriState>(xCheckBox->getState()) )
+ {
+ case TRISTATE_FALSE: *_pCurrentText = "0"; break;
+ case TRISTATE_TRUE: *_pCurrentText = "1"; break;
+ default: _pCurrentText->clear(); break;
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+
+bool FmXBoundFormFieldIterator::ShouldStepInto(const Reference< XInterface>& _rContainer) const
+{
+ if (_rContainer == m_xStartingPoint)
+ // would be quite stupid to step over the root...
+ return true;
+
+ return Reference< XControlModel>(_rContainer, UNO_QUERY).is();
+}
+
+
+bool FmXBoundFormFieldIterator::ShouldHandleElement(const Reference< XInterface>& _rElement)
+{
+ if (!_rElement.is())
+ // NULL element
+ return false;
+
+ if (Reference< XForm>(_rElement, UNO_QUERY).is() || Reference< XGrid>(_rElement, UNO_QUERY).is())
+ // a forms or a grid
+ return false;
+
+ Reference< XPropertySet> xSet(_rElement, UNO_QUERY);
+ if (!xSet.is() || !::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
+ // no "BoundField" property
+ return false;
+
+ Any aVal( xSet->getPropertyValue(FM_PROP_BOUNDFIELD) );
+ if (aVal.getValueTypeClass() != TypeClass_INTERFACE)
+ // void or invalid property value
+ return false;
+
+ return aVal.hasValue();
+}
+
+
+static bool isControlList(const SdrMarkList& rMarkList)
+{
+ // the list contains only controls and at least one control
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+ bool bControlList = nMarkCount != 0;
+
+ bool bHadAnyLeafs = false;
+
+ for (size_t i = 0; i < nMarkCount && bControlList; ++i)
+ {
+ SdrObject *pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ E3dObject* pAs3DObject = dynamic_cast< E3dObject* >( pObj);
+ // E3dObject's do not contain any 2D-objects (by definition)
+ // we need this extra check here : an E3dObject->IsGroupObject says "YES", but an SdrObjListIter working
+ // with an E3dObject doesn't give me any Nodes (E3dObject has a sub list, but no members in that list,
+ // cause there implementation differs from the one of "normal" SdrObject's. Unfortunally SdrObject::IsGroupObject
+ // doesn't check the element count of the sub list, which is simply a bug in IsGroupObject we can't fix at the moment).
+ // So at the end of this function bControlList would have the same value it was initialized with above : sal_True
+ // And this would be wrong :)
+ // 03.02.00 - 72529 - FS
+ if (!pAs3DObject)
+ {
+ if (pObj->IsGroupObject())
+ {
+ SdrObjListIter aIter(pObj->GetSubList());
+ while (aIter.IsMore() && bControlList)
+ {
+ bControlList = SdrInventor::FmForm == aIter.Next()->GetObjInventor();
+ bHadAnyLeafs = true;
+ }
+ }
+ else
+ {
+ bHadAnyLeafs = true;
+ bControlList = SdrInventor::FmForm == pObj->GetObjInventor();
+ }
+ }
+ }
+
+ return bControlList && bHadAnyLeafs;
+}
+
+
+static Reference< XForm > GetForm(const Reference< XInterface>& _rxElement)
+{
+ Reference< XForm > xForm( _rxElement, UNO_QUERY );
+ if ( xForm.is() )
+ return xForm;
+
+ Reference< XChild > xChild( _rxElement, UNO_QUERY );
+ if ( xChild.is() )
+ return GetForm( xChild->getParent() );
+
+ return Reference< XForm >();
+}
+
+FmXFormShell_Base_Disambiguation::FmXFormShell_Base_Disambiguation( ::osl::Mutex& _rMutex )
+ :FmXFormShell_BD_BASE( _rMutex )
+{
+}
+
+FmXFormShell::FmXFormShell( FmFormShell& _rShell, SfxViewFrame* _pViewFrame )
+ :FmXFormShell_BASE(m_aMutex)
+ ,FmXFormShell_CFGBASE("Office.Common/Misc", ConfigItemMode::NONE)
+ ,m_aMarkTimer("svx::FmXFormShell m_aMarkTimer")
+ ,m_eNavigate( NavigationBarMode_NONE )
+ ,m_nInvalidationEvent( nullptr )
+ ,m_nActivationEvent( nullptr )
+ ,m_pShell( &_rShell )
+ ,m_pTextShell( new svx::FmTextControlShell( _pViewFrame ) )
+ ,m_aActiveControllerFeatures( this )
+ ,m_aNavControllerFeatures( this )
+ ,m_eDocumentType( eUnknownDocumentType )
+ ,m_nLockSlotInvalidation( 0 )
+ ,m_bHadPropertyBrowserInDesignMode( false )
+ ,m_bTrackProperties( true )
+ ,m_bUseWizards( true )
+ ,m_bDatabaseBar( false )
+ ,m_bInActivate( false )
+ ,m_bSetFocus( false )
+ ,m_bFilterMode( false )
+ ,m_bChangingDesignMode( false )
+ ,m_bPreparedClose( false )
+ ,m_bFirstActivation( true )
+{
+ m_aMarkTimer.SetTimeout(100);
+ m_aMarkTimer.SetInvokeHandler(LINK(this, FmXFormShell, OnTimeOut_Lock));
+
+ m_xAttachedFrame = _pViewFrame->GetFrame().GetFrameInterface();
+
+ // to prevent deletion of this we acquire our refcounter once
+ osl_atomic_increment(&m_refCount);
+
+ // correct the refcounter
+ osl_atomic_decrement(&m_refCount);
+
+ // cache the current configuration settings we're interested in
+ implAdjustConfigCache_Lock();
+ // and register for changes on this settings
+ Sequence< OUString > aNames { "FormControlPilotsEnabled" };
+ EnableNotification(aNames);
+}
+
+
+FmXFormShell::~FmXFormShell()
+{
+}
+
+
+Reference< css::frame::XModel > FmXFormShell::getContextDocument_Lock() const
+{
+ Reference< css::frame::XModel > xModel;
+
+ // determine the type of document we live in
+ try
+ {
+ Reference< css::frame::XController > xController;
+ if ( m_xAttachedFrame.is() )
+ xController = m_xAttachedFrame->getController();
+ if ( xController.is() )
+ xModel = xController->getModel();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return xModel;
+}
+
+
+bool FmXFormShell::isEnhancedForm_Lock() const
+{
+ return getDocumentType_Lock() == eEnhancedForm;
+}
+
+
+bool FmXFormShell::impl_checkDisposed_Lock() const
+{
+ DBG_TESTSOLARMUTEX();
+ if ( !m_pShell )
+ {
+ OSL_FAIL( "FmXFormShell::impl_checkDisposed: already disposed!" );
+ return true;
+ }
+ return false;
+}
+
+
+::svxform::DocumentType FmXFormShell::getDocumentType_Lock() const
+{
+ if ( m_eDocumentType != eUnknownDocumentType )
+ return m_eDocumentType;
+
+ // determine the type of document we live in
+ Reference<css::frame::XModel> xModel = getContextDocument_Lock();
+ if ( xModel.is() )
+ m_eDocumentType = DocumentClassification::classifyDocument( xModel );
+ else
+ {
+ OSL_FAIL( "FmXFormShell::getDocumentType: can't determine the document type!" );
+ m_eDocumentType = eTextDocument;
+ // fallback, just to have a defined state
+ }
+
+ return m_eDocumentType;
+}
+
+
+bool FmXFormShell::IsReadonlyDoc_Lock() const
+{
+ if (impl_checkDisposed_Lock())
+ return true;
+
+ FmFormModel* pModel = m_pShell->GetFormModel();
+ if ( pModel && pModel->GetObjectShell() )
+ return pModel->GetObjectShell()->IsReadOnly() || pModel->GetObjectShell()->IsReadOnlyUI();
+ return true;
+}
+
+// EventListener
+
+void SAL_CALL FmXFormShell::disposing(const lang::EventObject& e)
+{
+ SolarMutexGuard g;
+
+ if (m_xActiveController == e.Source)
+ {
+ // the controller will release, then release everything
+ stopListening_Lock();
+ m_xActiveForm = nullptr;
+ m_xActiveController = nullptr;
+ m_xNavigationController = nullptr;
+
+ m_aActiveControllerFeatures.dispose();
+ m_aNavControllerFeatures.dispose();
+
+ if ( m_pShell )
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
+ }
+
+ if (e.Source != m_xExternalViewController)
+ return;
+
+ Reference< runtime::XFormController > xFormController( m_xExternalViewController, UNO_QUERY );
+ OSL_ENSURE( xFormController.is(), "FmXFormShell::disposing: invalid external view controller!" );
+ if (xFormController.is())
+ xFormController->removeActivateListener(static_cast<XFormControllerListener*>(this));
+
+ if (m_xExternalViewController.is())
+ m_xExternalViewController->removeEventListener(static_cast<XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
+
+ m_xExternalViewController = nullptr;
+ m_xExternalDisplayedForm = nullptr;
+ m_xExtViewTriggerController = nullptr;
+
+ InvalidateSlot_Lock( SID_FM_VIEW_AS_GRID, false );
+}
+
+
+void SAL_CALL FmXFormShell::propertyChange(const PropertyChangeEvent& evt)
+{
+ SolarMutexGuard g;
+
+ if (impl_checkDisposed_Lock())
+ return;
+
+ if (evt.PropertyName == FM_PROP_ROWCOUNT)
+ {
+ // The update following this forces a re-painting of the corresponding
+ // slots. But if I am not in the MainThread of the application (because,
+ // for example, a cursor is counting data sets at the moment and always
+ // gives me this PropertyChanges), this can clash with normal paints in
+ // the MainThread of the application. (Such paints happen, for example,
+ // if one simply places another application over the office and switches
+ // back again).
+ // Therefore the use of the SolarMutex, which safeguards that.
+ comphelper::SolarMutex& rSolarSafety = Application::GetSolarMutex();
+ if (rSolarSafety.tryToAcquire())
+ {
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_RECORD_TOTAL, true);
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update(SID_FM_RECORD_TOTAL);
+ rSolarSafety.release();
+ }
+ else
+ {
+ // with the following the slot is invalidated asynchron
+ LockSlotInvalidation_Lock(true);
+ InvalidateSlot_Lock(SID_FM_RECORD_TOTAL, false);
+ LockSlotInvalidation_Lock(false);
+ }
+ }
+
+ // this may be called from a non-main-thread so invalidate the shell asynchronously
+ LockSlotInvalidation_Lock(true);
+ InvalidateSlot_Lock(0, false); // special meaning : invalidate m_pShell
+ LockSlotInvalidation_Lock(false);
+}
+
+
+void FmXFormShell::invalidateFeatures( const ::std::vector< sal_Int32 >& _rFeatures )
+{
+ SolarMutexGuard g;
+
+ if (impl_checkDisposed_Lock())
+ return;
+
+ OSL_ENSURE( !_rFeatures.empty(), "FmXFormShell::invalidateFeatures: invalid arguments!" );
+
+ if ( !(m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame()) )
+ return;
+
+ // unfortunately, SFX requires sal_uInt16
+ ::std::vector< sal_uInt16 > aSlotIds( _rFeatures.begin(), _rFeatures.end() );
+
+ // furthermore, SFX wants a terminating 0
+ aSlotIds.push_back( 0 );
+
+ // and, last but not least, SFX wants the ids to be sorted
+ ::std::sort( aSlotIds.begin(), aSlotIds.end() - 1 );
+
+ sal_uInt16 *pSlotIds = aSlotIds.data();
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate( pSlotIds );
+}
+
+
+void SAL_CALL FmXFormShell::formActivated(const lang::EventObject& rEvent)
+{
+ SolarMutexGuard g;
+
+ if (impl_checkDisposed_Lock())
+ return;
+
+ Reference< runtime::XFormController > xController( rEvent.Source, UNO_QUERY_THROW );
+ m_pTextShell->formActivated( xController );
+ setActiveController_Lock(xController);
+}
+
+
+void SAL_CALL FmXFormShell::formDeactivated(const lang::EventObject& rEvent)
+{
+ SolarMutexGuard g;
+
+ if (impl_checkDisposed_Lock())
+ return;
+
+ Reference< runtime::XFormController > xController( rEvent.Source, UNO_QUERY_THROW );
+ m_pTextShell->formDeactivated( xController );
+}
+
+
+void FmXFormShell::disposing()
+{
+ SolarMutexGuard g;
+
+ FmXFormShell_BASE::disposing();
+
+ if ( m_pShell && !m_pShell->IsDesignMode() )
+ setActiveController_Lock(nullptr, true);
+ // do NOT save the content of the old form (the second parameter tells this)
+ // if we're here, then we expect that PrepareClose has been called, and thus the user
+ // got a chance to commit or reject any changes. So in case we're here and there
+ // are still uncommitted changes, the user explicitly wanted this.
+
+ m_pTextShell->dispose();
+
+ m_xAttachedFrame = nullptr;
+
+ CloseExternalFormViewer_Lock();
+
+ while ( !m_aLoadingPages.empty() )
+ {
+ Application::RemoveUserEvent( m_aLoadingPages.front().nEventId );
+ m_aLoadingPages.pop();
+ }
+
+ {
+ if (m_nInvalidationEvent)
+ {
+ Application::RemoveUserEvent(m_nInvalidationEvent);
+ m_nInvalidationEvent = nullptr;
+ }
+ if ( m_nActivationEvent )
+ {
+ Application::RemoveUserEvent( m_nActivationEvent );
+ m_nActivationEvent = nullptr;
+ }
+ }
+
+ {
+ DBG_ASSERT(!m_nInvalidationEvent, "FmXFormShell::~FmXFormShell : still have an invalidation event !");
+ // should have been deleted while being disposed
+
+ m_aMarkTimer.Stop();
+ }
+
+ DisableNotification();
+
+ RemoveElement_Lock(m_xForms);
+ m_xForms.clear();
+
+ impl_switchActiveControllerListening_Lock(false);
+ m_xActiveController = nullptr;
+ m_xActiveForm = nullptr;
+
+ m_pShell = nullptr;
+ m_xNavigationController = nullptr;
+ m_xCurrentForm = nullptr;
+ m_xLastGridFound = nullptr;
+ m_xAttachedFrame = nullptr;
+ m_xExternalViewController = nullptr;
+ m_xExtViewTriggerController = nullptr;
+ m_xExternalDisplayedForm = nullptr;
+
+ InterfaceBag().swap(m_aCurrentSelection);
+
+ m_aActiveControllerFeatures.dispose();
+ m_aNavControllerFeatures.dispose();
+}
+
+
+void FmXFormShell::UpdateSlot_Lock(sal_Int16 _nId)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ if ( m_nLockSlotInvalidation )
+ {
+ OSL_FAIL( "FmXFormShell::UpdateSlot: cannot update if invalidation is currently locked!" );
+ InvalidateSlot_Lock(_nId, false);
+ }
+ else
+ {
+ OSL_ENSURE( _nId, "FmXFormShell::UpdateSlot: can't update the complete shell!" );
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate( _nId, true, true );
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update( _nId );
+ }
+}
+
+
+void FmXFormShell::InvalidateSlot_Lock(sal_Int16 nId, bool bWithId)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ if (m_nLockSlotInvalidation)
+ {
+ sal_uInt8 nFlags = ( bWithId ? 0x01 : 0 );
+ m_arrInvalidSlots.emplace_back(nId, nFlags );
+ }
+ else
+ if (nId)
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(nId, true, bWithId);
+ else
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
+}
+
+
+void FmXFormShell::LockSlotInvalidation_Lock(bool bLock)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ DBG_ASSERT(bLock || m_nLockSlotInvalidation>0, "FmXFormShell::LockSlotInvalidation : invalid call !");
+
+ if (bLock)
+ ++m_nLockSlotInvalidation;
+ else if (!--m_nLockSlotInvalidation)
+ {
+ // (asynchronously) invalidate everything accumulated during the locked phase
+ if (!m_nInvalidationEvent)
+ m_nInvalidationEvent = Application::PostUserEvent(LINK(this, FmXFormShell, OnInvalidateSlots_Lock));
+ }
+}
+
+
+IMPL_LINK_NOARG(FmXFormShell, OnInvalidateSlots_Lock, void*,void)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ m_nInvalidationEvent = nullptr;
+
+ for (const auto& rInvalidSlot : m_arrInvalidSlots)
+ {
+ if (rInvalidSlot.id)
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(rInvalidSlot.id, true, (rInvalidSlot.flags & 0x01));
+ else
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
+ }
+ m_arrInvalidSlots.clear();
+}
+
+
+void FmXFormShell::ForceUpdateSelection_Lock()
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ if (IsSelectionUpdatePending_Lock())
+ {
+ m_aMarkTimer.Stop();
+
+ // optionally turn off the invalidation of slots which is implicitly done by SetSelection
+ LockSlotInvalidation_Lock(true);
+
+ SetSelection_Lock(m_pShell->GetFormView()->GetMarkedObjectList());
+
+ LockSlotInvalidation_Lock(false);
+ }
+}
+
+void FmXFormShell::GetConversionMenu_Lock(weld::Menu& rNewMenu)
+{
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aConvertSlots); ++i)
+ {
+ // the corresponding image at it
+ rNewMenu.append(OUString::createFromAscii(aConvertSlots[i]), SvxResId(RID_SVXSW_CONVERTMENU[i]), aImgIds[i]);
+ }
+}
+
+OString FmXFormShell::SlotToIdent(sal_uInt16 nSlot)
+{
+ static_assert(SAL_N_ELEMENTS(SelObjectSlotMap) >= SAL_N_ELEMENTS(aConvertSlots));
+
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aConvertSlots); ++i)
+ {
+ if (nSlot == SelObjectSlotMap[i])
+ return aConvertSlots[i];
+ }
+
+ return OString();
+}
+
+bool FmXFormShell::isControlConversionSlot(std::string_view rIdent)
+{
+ for (const auto& rConvertSlot : aConvertSlots)
+ if (rIdent == rConvertSlot)
+ return true;
+ return false;
+}
+
+void FmXFormShell::executeControlConversionSlot_Lock(std::string_view rIdent)
+{
+ OSL_PRECOND( canConvertCurrentSelectionToControl_Lock(rIdent), "FmXFormShell::executeControlConversionSlot: illegal call!" );
+ InterfaceBag::const_iterator aSelectedElement = m_aCurrentSelection.begin();
+ if ( aSelectedElement == m_aCurrentSelection.end() )
+ return;
+
+ executeControlConversionSlot_Lock(Reference<XFormComponent>(*aSelectedElement, UNO_QUERY), rIdent);
+}
+
+bool FmXFormShell::executeControlConversionSlot_Lock(const Reference<XFormComponent>& _rxObject, std::string_view rIdent)
+{
+ if (impl_checkDisposed_Lock())
+ return false;
+
+ OSL_ENSURE( _rxObject.is(), "FmXFormShell::executeControlConversionSlot: invalid object!" );
+ if ( !_rxObject.is() )
+ return false;
+
+ SdrPage* pPage = m_pShell->GetCurPage();
+ FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( pPage );
+ OSL_ENSURE( pFormPage, "FmXFormShell::executeControlConversionSlot: no current (form) page!" );
+ if ( !pFormPage )
+ return false;
+
+ OSL_ENSURE( isSolelySelected_Lock(_rxObject),
+ "FmXFormShell::executeControlConversionSlot: hmm ... shouldn't this parameter be redundant?" );
+
+ for (size_t lookupSlot = 0; lookupSlot < SAL_N_ELEMENTS(aConvertSlots); ++lookupSlot)
+ {
+ if (rIdent == aConvertSlots[lookupSlot])
+ {
+ Reference< XInterface > xNormalizedObject( _rxObject, UNO_QUERY );
+
+ FmFormObj* pFormObject = nullptr;
+ SdrObjListIter aPageIter( pFormPage );
+ while ( aPageIter.IsMore() )
+ {
+ SdrObject* pCurrent = aPageIter.Next();
+ pFormObject = FmFormObj::GetFormObject( pCurrent );
+ if ( !pFormObject )
+ continue;
+
+ Reference< XInterface > xCurrentNormalized( pFormObject->GetUnoControlModel(), UNO_QUERY );
+ if ( xCurrentNormalized.get() == xNormalizedObject.get() )
+ break;
+
+ pFormObject = nullptr;
+ }
+
+ if ( !pFormObject )
+ return false;
+
+ OUString sNewName( getServiceNameByControlType( nObjectTypes[ lookupSlot ] ) );
+ Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
+ Reference< XControlModel> xNewModel( xContext->getServiceManager()->createInstanceWithContext(sNewName, xContext), UNO_QUERY );
+ if (!xNewModel.is())
+ return false;
+
+ Reference< XControlModel> xOldModel( pFormObject->GetUnoControlModel() );
+
+ // transfer properties
+ Reference< XPropertySet> xOldSet(xOldModel, UNO_QUERY);
+ Reference< XPropertySet> xNewSet(xNewModel, UNO_QUERY);
+
+
+ lang::Locale aNewLanguage = Application::GetSettings().GetUILanguageTag().getLocale();
+ TransferFormComponentProperties(xOldSet, xNewSet, aNewLanguage);
+
+ Sequence< css::script::ScriptEventDescriptor> aOldScripts;
+ Reference< XChild> xChild(xOldModel, UNO_QUERY);
+ if (xChild.is())
+ {
+ Reference< XIndexAccess> xParent(xChild->getParent(), UNO_QUERY);
+
+ // remember old script events
+ Reference< css::script::XEventAttacherManager> xEvManager(xChild->getParent(), UNO_QUERY);
+ if (xParent.is() && xEvManager.is())
+ {
+ sal_Int32 nIndex = getElementPos(xParent, xOldModel);
+ if (nIndex>=0 && nIndex<xParent->getCount())
+ aOldScripts = xEvManager->getScriptEvents(nIndex);
+ }
+
+ // replace the model within the parent container
+ Reference< XIndexContainer> xIndexParent(xChild->getParent(), UNO_QUERY);
+ if (xIndexParent.is())
+ {
+ // the form container works with FormComponents
+ Reference< XFormComponent> xComponent(xNewModel, UNO_QUERY);
+ DBG_ASSERT(xComponent.is(), "FmXFormShell::executeControlConversionSlot: the new model is no form component !");
+ Any aNewModel(xComponent);
+ try
+ {
+
+ sal_Int32 nIndex = getElementPos(xParent, xOldModel);
+ if (nIndex>=0 && nIndex<xParent->getCount())
+ xIndexParent->replaceByIndex(nIndex, aNewModel);
+ else
+ {
+ OSL_FAIL("FmXFormShell::executeControlConversionSlot: could not replace the model !");
+ Reference< css::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY);
+ if (xNewComponent.is())
+ xNewComponent->dispose();
+ return false;
+ }
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("FmXFormShell::executeControlConversionSlot: could not replace the model !");
+ Reference< css::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY);
+ if (xNewComponent.is())
+ xNewComponent->dispose();
+ return false;
+ }
+
+ }
+ }
+
+ // special handling for the LabelControl-property : can only be set when the model is placed
+ // within the forms hierarchy
+ if (::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xOldSet) && ::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xNewSet))
+ {
+ try
+ {
+ xNewSet->setPropertyValue(FM_PROP_CONTROLLABEL, xOldSet->getPropertyValue(FM_PROP_CONTROLLABEL));
+ }
+ catch(Exception&)
+ {
+ }
+
+ }
+
+ // set new model
+ pFormObject->SetChanged();
+ pFormObject->SetUnoControlModel(xNewModel);
+
+ // transfer script events
+ // (do this _after_ SetUnoControlModel as we need the new (implicitly created) control)
+ if (aOldScripts.hasElements())
+ {
+ // find the control for the model
+ Reference<XControlContainer> xControlContainer(getControlContainerForView_Lock());
+
+ const Sequence< Reference< XControl> > aControls( xControlContainer->getControls() );
+
+ Reference< XControl> xControl;
+ auto pControl = std::find_if(aControls.begin(), aControls.end(),
+ [&xNewModel](const Reference< XControl>& rControl) { return rControl->getModel() == xNewModel; });
+ if (pControl != aControls.end())
+ xControl = *pControl;
+ TransferEventScripts(xNewModel, xControl, aOldScripts);
+ }
+
+ // transfer value bindings, if possible
+ {
+ Reference< XBindableValue > xOldBindable( xOldModel, UNO_QUERY );
+ Reference< XBindableValue > xNewBindable( xNewModel, UNO_QUERY );
+ if ( xOldBindable.is() )
+ {
+ try
+ {
+ if ( xNewBindable.is() )
+ xNewBindable->setValueBinding( xOldBindable->getValueBinding() );
+ xOldBindable->setValueBinding( nullptr );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+ // same for list entry sources
+ {
+ Reference< XListEntrySink > xOldSink( xOldModel, UNO_QUERY );
+ Reference< XListEntrySink > xNewSink( xNewModel, UNO_QUERY );
+ if ( xOldSink.is() )
+ {
+ try
+ {
+ if ( xNewSink.is() )
+ xNewSink->setListEntrySource( xOldSink->getListEntrySource() );
+ xOldSink->setListEntrySource( nullptr );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+
+ // create an undo action
+ FmFormModel* pModel = m_pShell->GetFormModel();
+ DBG_ASSERT(pModel != nullptr, "FmXFormShell::executeControlConversionSlot: my shell has no model !");
+ if (pModel && pModel->IsUndoEnabled() )
+ {
+ pModel->AddUndo(std::make_unique<FmUndoModelReplaceAction>(*pModel, pFormObject, xOldModel));
+ }
+ else
+ {
+ FmUndoModelReplaceAction::DisposeElement( xOldModel );
+ }
+
+ return true;
+ }
+ }
+ return false;
+}
+
+bool FmXFormShell::canConvertCurrentSelectionToControl_Lock(std::string_view rIdent)
+{
+ if ( m_aCurrentSelection.empty() )
+ return false;
+
+ InterfaceBag::const_iterator aCheck = m_aCurrentSelection.begin();
+ Reference< lang::XServiceInfo > xElementInfo( *aCheck, UNO_QUERY );
+ if ( !xElementInfo.is() )
+ // no service info -> cannot determine this
+ return false;
+
+ if ( ++aCheck != m_aCurrentSelection.end() )
+ // more than one element
+ return false;
+
+ if ( Reference< XForm >::query( xElementInfo ).is() )
+ // it's a form
+ return false;
+
+ SdrObjKind nObjectType = getControlTypeByObject( xElementInfo );
+
+ if ( ( SdrObjKind::FormHidden == nObjectType )
+ || ( SdrObjKind::FormControl == nObjectType )
+ || ( SdrObjKind::FormGrid == nObjectType )
+ )
+ return false; // those types cannot be converted
+
+ DBG_ASSERT(SAL_N_ELEMENTS(aConvertSlots) == SAL_N_ELEMENTS(nObjectTypes),
+ "FmXFormShell::canConvertCurrentSelectionToControl: aConvertSlots & nObjectTypes must have the same size !");
+
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aConvertSlots); ++i)
+ if (rIdent == aConvertSlots[i])
+ return nObjectTypes[i] != nObjectType;
+
+ return true; // all other slots: assume "yes"
+}
+
+void FmXFormShell::checkControlConversionSlotsForCurrentSelection_Lock(weld::Menu& rMenu)
+{
+ for (int i = 0, nCount = rMenu.n_children(); i < nCount; ++i)
+ {
+ // the context is already of a type that corresponds to the entry -> disable
+ OString sIdent(aConvertSlots[i]);
+ rMenu.set_sensitive(sIdent, canConvertCurrentSelectionToControl_Lock(sIdent));
+ }
+}
+
+void FmXFormShell::LoopGrids_Lock(LoopGridsSync nSync, LoopGridsFlags nFlags)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ Reference< XIndexContainer> xControlModels(m_xActiveForm, UNO_QUERY);
+ if (!xControlModels.is())
+ return;
+
+ for (sal_Int32 i=0; i<xControlModels->getCount(); ++i)
+ {
+ Reference< XPropertySet> xModelSet;
+ xControlModels->getByIndex(i) >>= xModelSet;
+ if (!xModelSet.is())
+ continue;
+
+ if (!::comphelper::hasProperty(FM_PROP_CLASSID, xModelSet))
+ continue;
+ sal_Int16 nClassId = ::comphelper::getINT16(xModelSet->getPropertyValue(FM_PROP_CLASSID));
+ if (FormComponentType::GRIDCONTROL != nClassId)
+ continue;
+
+ if (!::comphelper::hasProperty(FM_PROP_CURSORCOLOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_ALWAYSSHOWCURSOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_DISPLAYSYNCHRON, xModelSet))
+ continue;
+
+ switch (nSync)
+ {
+ case LoopGridsSync::DISABLE_SYNC:
+ {
+ xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(false));
+ }
+ break;
+ case LoopGridsSync::FORCE_SYNC:
+ {
+ Any aOldVal( xModelSet->getPropertyValue(FM_PROP_DISPLAYSYNCHRON) );
+ xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(true));
+ xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, aOldVal);
+ }
+ break;
+ case LoopGridsSync::ENABLE_SYNC:
+ {
+ xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(true));
+ }
+ break;
+ }
+
+ if (nFlags & LoopGridsFlags::DISABLE_ROCTRLR)
+ {
+ xModelSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any(false));
+ Reference< XPropertyState> xModelPropState(xModelSet, UNO_QUERY);
+ if (xModelPropState.is())
+ xModelPropState->setPropertyToDefault(FM_PROP_CURSORCOLOR);
+ else
+ xModelSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any()); // this should be the default
+ }
+ }
+}
+
+
+Reference< XControlContainer > FmXFormShell::getControlContainerForView_Lock() const
+{
+ if (impl_checkDisposed_Lock())
+ return nullptr;
+
+ SdrPageView* pPageView = nullptr;
+ if ( m_pShell && m_pShell->GetFormView() )
+ pPageView = m_pShell->GetFormView()->GetSdrPageView();
+
+ Reference< XControlContainer> xControlContainer;
+ if ( pPageView )
+ xControlContainer = pPageView->GetPageWindow(0)->GetControlContainer();
+
+ return xControlContainer;
+}
+
+
+void FmXFormShell::ExecuteTabOrderDialog_Lock(const Reference<XTabControllerModel>& _rxForForm)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ OSL_PRECOND( _rxForForm.is(), "FmXFormShell::ExecuteTabOrderDialog: invalid tabbing model!" );
+ if ( !_rxForForm.is() )
+ return;
+
+ try
+ {
+ Reference< XWindow > xParentWindow;
+ if ( m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame() )
+ xParentWindow = VCLUnoHelper::GetInterface ( &m_pShell->GetViewShell()->GetViewFrame()->GetWindow() );
+
+ Reference< dialogs::XExecutableDialog > xDialog = form::TabOrderDialog::createWithModel(
+ comphelper::getProcessComponentContext(),
+ _rxForForm, getControlContainerForView_Lock(), xParentWindow
+ );
+
+ xDialog->execute();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmXFormShell::ExecuteTabOrderDialog" );
+ }
+}
+
+
+void FmXFormShell::ExecuteSearch_Lock()
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ // a collection of all (logical) forms
+ FmFormArray().swap(m_aSearchForms);
+ ::std::vector< OUString > aContextNames;
+ impl_collectFormSearchContexts_nothrow_Lock(
+ m_pShell->GetCurPage()->GetForms(), u"",
+ m_aSearchForms, aContextNames);
+
+ if ( m_aSearchForms.size() != aContextNames.size() )
+ {
+ SAL_WARN ( "svx.form", "FmXFormShell::ExecuteSearch: nonsense!" );
+ return;
+ }
+
+ // filter out the forms which do not contain valid controls at all
+ {
+ FmFormArray aValidForms;
+ ::std::vector< OUString > aValidContexts;
+ FmFormArray::const_iterator form = m_aSearchForms.begin();
+ ::std::vector< OUString >::const_iterator contextName = aContextNames.begin();
+ for ( ; form != m_aSearchForms.end(); ++form, ++contextName )
+ {
+ FmSearchContext aTestContext;
+ aTestContext.nContext = static_cast< sal_Int16 >( form - m_aSearchForms.begin() );
+ sal_uInt32 nValidControls = OnSearchContextRequest_Lock(aTestContext);
+ if ( nValidControls > 0 )
+ {
+ aValidForms.push_back( *form );
+ aValidContexts.push_back( *contextName );
+ }
+ }
+
+ m_aSearchForms.swap( aValidForms );
+ aContextNames.swap( aValidContexts );
+ }
+
+ if (m_aSearchForms.empty() )
+ {
+ // there are no controls that meet all the conditions for a search
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SvxResId(RID_STR_NODATACONTROLS)));
+ xBox->run();
+ return;
+ }
+
+ // now I need another 'initial context'
+ sal_Int16 nInitialContext = 0;
+ Reference<XForm> xActiveForm(getActiveForm_Lock());
+ for ( size_t i=0; i<m_aSearchForms.size(); ++i )
+ {
+ if (m_aSearchForms.at(i) == xActiveForm)
+ {
+ nInitialContext = static_cast<sal_Int16>(i);
+ break;
+ }
+ }
+
+ // If the dialog should initially offer the text of the active control,
+ // this must have an XTextComponent interface. An addition, this makes
+ // sense only if the current field is also bound to a table (or whatever) field.
+ OUString strActiveField;
+ OUString strInitialText;
+ // ... this I get from my FormController
+ DBG_ASSERT(m_xActiveController.is(), "FmXFormShell::ExecuteSearch : no active controller !");
+ Reference< XControl> xActiveControl( m_xActiveController->getCurrentControl());
+ if (xActiveControl.is())
+ {
+ // the control can tell me its model ...
+ Reference< XControlModel> xActiveModel( xActiveControl->getModel());
+ DBG_ASSERT(xActiveModel.is(), "FmXFormShell::ExecuteSearch : active control has no model !");
+
+ // I ask the model for the ControlSource property ...
+ Reference< XPropertySet> xProperties(xActiveControl->getModel(), UNO_QUERY);
+ if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties))
+ {
+ Reference< XPropertySet> xField;
+ xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
+ if (xField.is()) // (only when the thing is really bound)
+ {
+ // and the control itself for a TextComponent interface (so that I can pick up the text there)
+ Reference< XTextComponent> xText(xActiveControl, UNO_QUERY);
+ if (xText.is())
+ {
+ strActiveField = getLabelName(xProperties);
+ strInitialText = xText->getText();
+ }
+ }
+ }
+ else
+ {
+ // the control itself has no ControlSource, but maybe it is a GridControl
+ Reference< XGrid> xGrid(xActiveControl, UNO_QUERY);
+ if (xGrid.is())
+ {
+ // for strActiveField I need the ControlSource of the column,
+ // for that the columns container, for that the GridPeer
+ Reference< XGridPeer> xGridPeer(xActiveControl->getPeer(), UNO_QUERY);
+ Reference< XIndexAccess> xColumns;
+ if (xGridPeer.is())
+ xColumns = xGridPeer->getColumns();
+
+ sal_Int16 nViewCol = xGrid->getCurrentColumnPosition();
+ sal_Int32 nModelCol = GridView2ModelPos(xColumns, nViewCol);
+ Reference< XPropertySet> xCurrentCol;
+ if(xColumns.is())
+ xColumns->getByIndex(nModelCol) >>= xCurrentCol;
+ if (xCurrentCol.is())
+ strActiveField = ::comphelper::getString(xCurrentCol->getPropertyValue(FM_PROP_LABEL));
+
+ // the text of the current column
+ Reference< XIndexAccess> xColControls(xGridPeer, UNO_QUERY);
+ Reference< XInterface> xCurControl;
+ xColControls->getByIndex(nViewCol) >>= xCurControl;
+ OUString sInitialText;
+ if (IsSearchableControl(xCurControl, &sInitialText))
+ strInitialText = sInitialText;
+ }
+ }
+ }
+
+ // taking care of possible GridControls that I know
+ LoopGrids_Lock(LoopGridsSync::DISABLE_SYNC);
+
+ // Now I am ready for the dialogue.
+ // When the potential deadlocks caused by the use of the solar mutex in
+ // MTs VCLX... classes are eventually cleared, an SM_USETHREAD should be
+ // placed here, because the search in a separate thread is nevertheless
+ // somewhat more fluid. Should be, however, somehow made dependent of the
+ // underlying cursor. DAO for example is not thread-safe.
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractFmSearchDialog> pDialog(
+ pFact->CreateFmSearchDialog(
+ m_pShell->GetViewShell()->GetViewFrame()->GetFrameWeld(),
+ strInitialText, aContextNames, nInitialContext,
+ LINK(this, FmXFormShell, OnSearchContextRequest_Lock) ));
+ pDialog->SetActiveField( strActiveField );
+ pDialog->SetFoundHandler(LINK(this, FmXFormShell, OnFoundData_Lock));
+ pDialog->SetCanceledNotFoundHdl(LINK(this, FmXFormShell, OnCanceledNotFound_Lock));
+ pDialog->Execute();
+ pDialog.disposeAndClear();
+
+ // restore GridControls again
+ LoopGrids_Lock(LoopGridsSync::ENABLE_SYNC, LoopGridsFlags::DISABLE_ROCTRLR);
+
+ m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView());
+ // because I marked controls in OnFoundData (if I was there)
+}
+
+
+bool FmXFormShell::GetY2KState_Lock(sal_uInt16& n)
+{
+ if (impl_checkDisposed_Lock())
+ return false;
+
+ if (m_pShell->IsDesignMode())
+ // in the design mode (without active controls) the main document is to take care of it
+ return false;
+
+ Reference<XForm> xForm(getActiveForm_Lock());
+ if (!xForm.is())
+ // no current form (in particular no current control) -> the main document is to take care
+ return false;
+
+ Reference< XRowSet> xDB(xForm, UNO_QUERY);
+ DBG_ASSERT(xDB.is(), "FmXFormShell::GetY2KState : current form has no dbform-interface !");
+
+ Reference< XNumberFormatsSupplier> xSupplier( getNumberFormats(getConnection(xDB)));
+ if (xSupplier.is())
+ {
+ Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings());
+ if (xSet.is())
+ {
+ try
+ {
+ Any aVal( xSet->getPropertyValue("TwoDigitDateStart") );
+ aVal >>= n;
+ return true;
+ }
+ catch(Exception&)
+ {
+ }
+
+ }
+ }
+ return false;
+}
+
+
+void FmXFormShell::SetY2KState_Lock(sal_uInt16 n)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ Reference<XForm> xActiveForm(getActiveForm_Lock());
+ Reference< XRowSet > xActiveRowSet( xActiveForm, UNO_QUERY );
+ if ( xActiveRowSet.is() )
+ {
+ Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getConnection( xActiveRowSet ) ) );
+ if (xSupplier.is())
+ {
+ Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings());
+ if (xSet.is())
+ {
+ try
+ {
+ xSet->setPropertyValue("TwoDigitDateStart", Any(sal_uInt16(n)));
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "");
+ }
+
+ }
+ return;
+ }
+ }
+
+ // no active form found -> iterate through all current forms
+ Reference< XIndexAccess> xCurrentForms( m_xForms);
+ if (!xCurrentForms.is())
+ { // in the alive mode, my forms are not set, but the ones on the page are
+ if (m_pShell->GetCurPage())
+ xCurrentForms = m_pShell->GetCurPage()->GetForms( false );
+ }
+ if (!xCurrentForms.is())
+ return;
+
+ ::comphelper::IndexAccessIterator aIter(xCurrentForms);
+ Reference< XInterface> xCurrentElement( aIter.Next());
+ while (xCurrentElement.is())
+ {
+ // is the current element a DatabaseForm?
+ Reference< XRowSet> xElementAsRowSet( xCurrentElement, UNO_QUERY );
+ if ( xElementAsRowSet.is() )
+ {
+ Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getConnection( xElementAsRowSet ) ) );
+ if (!xSupplier.is())
+ continue;
+
+ Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings());
+ if (xSet.is())
+ {
+ try
+ {
+ xSet->setPropertyValue("TwoDigitDateStart", Any(sal_uInt16(n)));
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "");
+ }
+
+ }
+ }
+ xCurrentElement = aIter.Next();
+ }
+}
+
+
+void FmXFormShell::CloseExternalFormViewer_Lock()
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ if (!m_xExternalViewController.is())
+ return;
+
+ Reference< css::frame::XFrame> xExternalViewFrame( m_xExternalViewController->getFrame());
+ Reference< css::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY);
+ if (!xCommLink.is())
+ return;
+
+ xExternalViewFrame->setComponent(nullptr,nullptr);
+ ::comphelper::disposeComponent(xExternalViewFrame);
+ m_xExternalViewController = nullptr;
+ m_xExtViewTriggerController = nullptr;
+ m_xExternalDisplayedForm = nullptr;
+}
+
+
+Reference<XResultSet> FmXFormShell::getInternalForm_Lock(const Reference<XResultSet>& _xForm) const
+{
+ if (impl_checkDisposed_Lock())
+ return nullptr;
+
+ Reference< runtime::XFormController> xExternalCtrlr(m_xExternalViewController, UNO_QUERY);
+ if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel()))
+ {
+ DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !");
+ return m_xExternalDisplayedForm;
+ }
+ return _xForm;
+}
+
+
+Reference<XForm> FmXFormShell::getInternalForm_Lock(const Reference<XForm>& _xForm) const
+{
+ if (impl_checkDisposed_Lock())
+ return nullptr;
+
+ Reference< runtime::XFormController > xExternalCtrlr(m_xExternalViewController, UNO_QUERY);
+ if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel()))
+ {
+ DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !");
+ return Reference< XForm>(m_xExternalDisplayedForm, UNO_QUERY);
+ }
+ return _xForm;
+}
+
+
+namespace
+{
+ bool lcl_isNavigationRelevant( sal_Int32 _nWhich )
+ {
+ return ( _nWhich == SID_FM_RECORD_FIRST )
+ || ( _nWhich == SID_FM_RECORD_PREV )
+ || ( _nWhich == SID_FM_RECORD_NEXT )
+ || ( _nWhich == SID_FM_RECORD_LAST )
+ || ( _nWhich == SID_FM_RECORD_NEW );
+ }
+}
+
+
+bool FmXFormShell::IsFormSlotEnabled( sal_Int32 _nSlot, FeatureState* _pCompleteState ) const
+{
+ const svx::ControllerFeatures& rController =
+ lcl_isNavigationRelevant( _nSlot )
+ ? getNavControllerFeatures_Lock()
+ : getActiveControllerFeatures_Lock();
+
+ if ( !_pCompleteState )
+ return rController->isEnabled( _nSlot );
+
+ rController->getState( _nSlot, *_pCompleteState );
+ return _pCompleteState->Enabled;
+}
+
+
+void FmXFormShell::ExecuteFormSlot_Lock( sal_Int32 _nSlot )
+{
+ const svx::ControllerFeatures& rController =
+ lcl_isNavigationRelevant( _nSlot )
+ ? getNavControllerFeatures_Lock()
+ : getActiveControllerFeatures_Lock();
+
+ rController->execute( _nSlot );
+
+ if ( _nSlot != SID_FM_RECORD_UNDO )
+ return;
+
+ // if we're doing an UNDO, *and* if the affected form is the form which we also display
+ // as external view, then we need to reset the controls of the external form, too
+ if (getInternalForm_Lock(getActiveForm_Lock()) != m_xExternalDisplayedForm)
+ return;
+
+ Reference< XIndexAccess > xContainer( m_xExternalDisplayedForm, UNO_QUERY );
+ if ( !xContainer.is() )
+ return;
+
+ Reference< XReset > xReset;
+ for ( sal_Int32 i = 0; i < xContainer->getCount(); ++i )
+ {
+ if ( ( xContainer->getByIndex( i ) >>= xReset ) && xReset.is() )
+ {
+ // no resets on sub forms
+ Reference< XForm > xAsForm( xReset, UNO_QUERY );
+ if ( !xAsForm.is() )
+ xReset->reset();
+ }
+ }
+}
+
+
+void FmXFormShell::impl_switchActiveControllerListening_Lock(const bool _bListen)
+{
+ if ( !m_xActiveController.is() )
+ return;
+
+ if ( _bListen )
+ m_xActiveController->addEventListener( static_cast<XFormControllerListener*>(this) );
+ else
+ m_xActiveController->removeEventListener( static_cast<XFormControllerListener*>(this) );
+}
+
+
+void FmXFormShell::setActiveController_Lock(const Reference<runtime::XFormController>& xController, bool _bNoSaveOldContent)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ if (m_bChangingDesignMode)
+ return;
+ DBG_ASSERT(!m_pShell->IsDesignMode(), "only to be used in alive mode");
+
+ // if the routine has been called a second time,
+ // the focus should no longer be transferred
+ if (m_bInActivate)
+ {
+ m_bSetFocus = xController != m_xActiveController;
+ return;
+ }
+
+ if (xController == m_xActiveController)
+ return;
+
+ // switch all nav dispatchers belonging to the form of the current nav controller to 'non active'
+ Reference< XResultSet> xNavigationForm;
+ if (m_xNavigationController.is())
+ xNavigationForm.set(m_xNavigationController->getModel(), UNO_QUERY);
+
+ m_bInActivate = true;
+
+ // check if the 2 controllers serve different forms
+ Reference< XResultSet> xOldForm;
+ if (m_xActiveController.is())
+ xOldForm.set(m_xActiveController->getModel(), UNO_QUERY);
+ Reference< XResultSet> xNewForm;
+ if (xController.is())
+ xNewForm = Reference< XResultSet>(xController->getModel(), UNO_QUERY);
+ xOldForm = getInternalForm_Lock(xOldForm);
+ xNewForm = getInternalForm_Lock(xNewForm);
+
+ bool bDifferentForm = ( xOldForm.get() != xNewForm.get() );
+ bool bNeedSave = bDifferentForm && !_bNoSaveOldContent;
+ // we save the content of the old form if we move to a new form, and saving old content is allowed
+
+ if ( m_xActiveController.is() && bNeedSave )
+ {
+ // save content on change of the controller; a commit has already been executed
+ if ( m_aActiveControllerFeatures->commitCurrentControl() )
+ {
+ m_bSetFocus = true;
+ if ( m_aActiveControllerFeatures->isModifiedRow() )
+ {
+ bool bIsNew = m_aActiveControllerFeatures->isInsertionRow();
+ bool bResult = m_aActiveControllerFeatures->commitCurrentRecord();
+ if ( !bResult && m_bSetFocus )
+ {
+ // if we couldn't save the current record, set the focus back to the
+ // current control
+ Reference< XWindow > xWindow( m_xActiveController->getCurrentControl(), UNO_QUERY );
+ if ( xWindow.is() )
+ xWindow->setFocus();
+ m_bInActivate = false;
+ return;
+ }
+ else if ( bResult && bIsNew )
+ {
+ Reference< XResultSet > xCursor( m_aActiveControllerFeatures->getCursor() );
+ if ( xCursor.is() )
+ {
+ DO_SAFE( xCursor->last(); );
+ }
+ }
+ }
+ }
+ }
+
+ stopListening_Lock();
+
+ impl_switchActiveControllerListening_Lock(false);
+
+ m_aActiveControllerFeatures.dispose();
+ m_xActiveController = xController;
+ if ( m_xActiveController.is() )
+ m_aActiveControllerFeatures.assign( m_xActiveController );
+
+ impl_switchActiveControllerListening_Lock(true);
+
+ if ( m_xActiveController.is() )
+ m_xActiveForm = getInternalForm_Lock(Reference<XForm>(m_xActiveController->getModel(), UNO_QUERY));
+ else
+ m_xActiveForm = nullptr;
+
+ startListening_Lock();
+
+ // activate all dispatchers belonging to form of the new navigation controller
+ xNavigationForm = nullptr;
+ if (m_xNavigationController.is())
+ xNavigationForm.set(m_xNavigationController->getModel(), UNO_QUERY);
+
+ m_bInActivate = false;
+
+ m_pShell->UIFeatureChanged();
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
+
+ InvalidateSlot_Lock(SID_FM_FILTER_NAVIGATOR_CONTROL, true);
+}
+
+
+void FmXFormShell::getCurrentSelection_Lock(InterfaceBag& /* [out] */ _rSelection) const
+{
+ _rSelection = m_aCurrentSelection;
+}
+
+
+bool FmXFormShell::setCurrentSelectionFromMark_Lock(const SdrMarkList& _rMarkList)
+{
+ m_aLastKnownMarkedControls.clear();
+
+ if ( ( _rMarkList.GetMarkCount() > 0 ) && isControlList( _rMarkList ) )
+ collectInterfacesFromMarkList( _rMarkList, m_aLastKnownMarkedControls );
+
+ return setCurrentSelection_Lock(o3tl::sorted_vector(m_aLastKnownMarkedControls));
+}
+
+
+bool FmXFormShell::selectLastMarkedControls_Lock()
+{
+ return setCurrentSelection_Lock(o3tl::sorted_vector(m_aLastKnownMarkedControls));
+}
+
+
+bool FmXFormShell::setCurrentSelection_Lock( InterfaceBag&& _rSelection )
+{
+ if (impl_checkDisposed_Lock())
+ return false;
+
+ DBG_ASSERT( m_pShell->IsDesignMode(), "FmXFormShell::setCurrentSelection: only to be used in design mode!" );
+
+ if ( _rSelection.empty() && m_aCurrentSelection.empty() )
+ // nothing to do
+ return false;
+
+ if ( _rSelection.size() == m_aCurrentSelection.size() )
+ {
+ InterfaceBag::const_iterator aNew = _rSelection.begin();
+ InterfaceBag::const_iterator aOld = m_aCurrentSelection.begin();
+ for ( ; aNew != _rSelection.end(); ++aNew, ++aOld )
+ {
+ OSL_ENSURE( Reference< XInterface >( *aNew, UNO_QUERY ).get() == aNew->get(), "FmXFormShell::setCurrentSelection: new interface not normalized!" );
+ OSL_ENSURE( Reference< XInterface >( *aOld, UNO_QUERY ).get() == aOld->get(), "FmXFormShell::setCurrentSelection: old interface not normalized!" );
+
+ if ( aNew->get() != aOld->get() )
+ break;
+ }
+
+ if ( aNew == _rSelection.end() )
+ // both bags equal
+ return false;
+ }
+
+ // the following is some strange code to ensure that when you have two grid controls in a document,
+ // only one of them can have a selected column.
+ // TODO: this should happen elsewhere, but not here - shouldn't it?
+ if ( !m_aCurrentSelection.empty() )
+ {
+ Reference< XChild > xCur; if ( m_aCurrentSelection.size() == 1 ) xCur.set(*m_aCurrentSelection.begin(), css::uno::UNO_QUERY);
+ Reference< XChild > xNew; if ( _rSelection.size() == 1 ) xNew.set(*_rSelection.begin(), css::uno::UNO_QUERY);
+
+ // is there nothing to be selected, or the parents differ, and the parent of the current object
+ // is a selection supplier, then deselect
+ if ( xCur.is() && ( !xNew.is() || ( xCur->getParent() != xNew->getParent() ) ) )
+ {
+ Reference< XSelectionSupplier > xSel( xCur->getParent(), UNO_QUERY );
+ if ( xSel.is() )
+ xSel->select( Any() );
+ }
+ }
+
+ m_aCurrentSelection = _rSelection;
+
+ // determine the form which all the selected objects belong to, if any
+ Reference< XForm > xNewCurrentForm;
+ for (const auto& rpSelection : m_aCurrentSelection)
+ {
+ Reference< XForm > xThisRoundsForm( GetForm( rpSelection ) );
+ OSL_ENSURE( xThisRoundsForm.is(), "FmXFormShell::setCurrentSelection: *everything* should belong to a form!" );
+
+ if ( !xNewCurrentForm.is() )
+ { // the first form we encountered
+ xNewCurrentForm = xThisRoundsForm;
+ }
+ else if ( xNewCurrentForm != xThisRoundsForm )
+ { // different forms -> no "current form" at all
+ xNewCurrentForm.clear();
+ break;
+ }
+ }
+
+ if ( !m_aCurrentSelection.empty() )
+ impl_updateCurrentForm_Lock(xNewCurrentForm);
+
+ // ensure some slots are updated
+ for (sal_Int16 i : SelObjectSlotMap)
+ InvalidateSlot_Lock(i, false);
+
+ return true;
+}
+
+
+bool FmXFormShell::isSolelySelected_Lock(const Reference<XInterface>& _rxObject)
+{
+ return ( m_aCurrentSelection.size() == 1 ) && ( *m_aCurrentSelection.begin() == _rxObject );
+}
+
+
+void FmXFormShell::forgetCurrentForm_Lock()
+{
+ if ( !m_xCurrentForm.is() )
+ return;
+
+ // reset ...
+ impl_updateCurrentForm_Lock(nullptr);
+
+ // ... and try finding a new current form
+ // #i88186# / 2008-04-12 / frank.schoenheit@sun.com
+ impl_defaultCurrentForm_nothrow_Lock();
+}
+
+
+void FmXFormShell::impl_updateCurrentForm_Lock(const Reference<XForm>& _rxNewCurForm)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ m_xCurrentForm = _rxNewCurForm;
+
+ // propagate to the FormPage(Impl)
+ FmFormPage* pPage = m_pShell->GetCurPage();
+ if ( pPage )
+ pPage->GetImpl().setCurForm( m_xCurrentForm );
+
+ // ensure the UI which depends on the current form is up-to-date
+ for (sal_Int16 i : DlgSlotMap)
+ InvalidateSlot_Lock(i, false);
+}
+
+
+void FmXFormShell::startListening_Lock()
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY);
+ if (xDatabaseForm.is() && getConnection(xDatabaseForm).is())
+ {
+ Reference< XPropertySet> xActiveFormSet(m_xActiveForm, UNO_QUERY);
+ if (xActiveFormSet.is())
+ {
+ // if there is a data source, then build the listener
+ // TODO: this is strange - shouldn't this depend on a isLoaded instead of
+ // a "has command value"? Finally, the command value only means that it was
+ // intended to be loaded, not that it actually *is* loaded
+ OUString aSource = ::comphelper::getString(xActiveFormSet->getPropertyValue(FM_PROP_COMMAND));
+ if (!aSource.isEmpty())
+ {
+ m_bDatabaseBar = true;
+
+ xActiveFormSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate;
+
+ switch (m_eNavigate)
+ {
+ case NavigationBarMode_PARENT:
+ {
+ // search for the controller via which navigation is possible
+ Reference< XChild> xChild = m_xActiveController;
+ Reference< runtime::XFormController > xParent;
+ while (xChild.is())
+ {
+ xChild.set(xChild->getParent(), UNO_QUERY);
+ xParent.set(xChild, UNO_QUERY);
+ Reference< XPropertySet> xParentSet;
+ if (xParent.is())
+ xParentSet.set(xParent->getModel(), UNO_QUERY);
+ if (xParentSet.is())
+ {
+ xParentSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate;
+ if (m_eNavigate == NavigationBarMode_CURRENT)
+ break;
+ }
+ }
+ m_xNavigationController = xParent;
+ }
+ break;
+
+ case NavigationBarMode_CURRENT:
+ m_xNavigationController = m_xActiveController;
+ break;
+
+ default:
+ m_xNavigationController = nullptr;
+ m_bDatabaseBar = false;
+ }
+
+ m_aNavControllerFeatures.dispose();
+ if ( m_xNavigationController.is() && ( m_xNavigationController != m_xActiveController ) )
+ m_aNavControllerFeatures.assign( m_xNavigationController );
+
+ // because of RecordCount, listen at the controller which controls the navigation
+ Reference< XPropertySet> xNavigationSet;
+ if (m_xNavigationController.is())
+ {
+ xNavigationSet.set(m_xNavigationController->getModel(), UNO_QUERY);
+ if (xNavigationSet.is())
+ xNavigationSet->addPropertyChangeListener(FM_PROP_ROWCOUNT,this);
+ }
+ return;
+ }
+ }
+ }
+
+ m_eNavigate = NavigationBarMode_NONE;
+ m_bDatabaseBar = false;
+ m_xNavigationController = nullptr;
+}
+
+
+void FmXFormShell::stopListening_Lock()
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY);
+ if ( xDatabaseForm.is() )
+ {
+ if (m_xNavigationController.is())
+ {
+ Reference< XPropertySet> xSet(m_xNavigationController->getModel(), UNO_QUERY);
+ if (xSet.is())
+ xSet->removePropertyChangeListener(FM_PROP_ROWCOUNT, this);
+
+ }
+ }
+
+ m_bDatabaseBar = false;
+ m_eNavigate = NavigationBarMode_NONE;
+ m_xNavigationController = nullptr;
+}
+
+
+void FmXFormShell::ShowSelectionProperties_Lock(bool bShow)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ // if the window is already visible, only update the state
+ bool bHasChild = m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_SHOW_PROPERTIES );
+ if ( bHasChild && bShow )
+ UpdateSlot_Lock(SID_FM_PROPERTY_CONTROL);
+
+ // else toggle state
+ else
+ m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow(SID_FM_SHOW_PROPERTIES);
+
+ InvalidateSlot_Lock(SID_FM_PROPERTIES, false);
+ InvalidateSlot_Lock(SID_FM_CTL_PROPERTIES, false);
+}
+
+
+IMPL_LINK(FmXFormShell, OnFoundData_Lock, FmFoundRecordInformation&, rfriWhere, void)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ DBG_ASSERT((rfriWhere.nContext >= 0) && (o3tl::make_unsigned(rfriWhere.nContext) < m_aSearchForms.size()),
+ "FmXFormShell::OnFoundData : invalid context!");
+ Reference< XForm> xForm( m_aSearchForms.at(rfriWhere.nContext));
+ DBG_ASSERT(xForm.is(), "FmXFormShell::OnFoundData : invalid form!");
+
+ Reference< XRowLocate> xCursor(xForm, UNO_QUERY);
+ if (!xCursor.is())
+ return; // what should I do there?
+
+ // to the record
+ try
+ {
+ xCursor->moveToBookmark(rfriWhere.aPosition);
+ }
+ catch(const SQLException&)
+ {
+ OSL_FAIL("Can position on bookmark!");
+ }
+
+ LoopGrids_Lock(LoopGridsSync::FORCE_SYNC);
+
+ // and to the field (for that, I collected the XVclComponent interfaces before the start of the search)
+ SAL_WARN_IF(o3tl::make_unsigned(rfriWhere.nFieldPos) >=
+ m_arrSearchedControls.size(),
+ "svx.form", "FmXFormShell::OnFoundData : invalid index!");
+ SdrObject* pObject = m_arrSearchedControls.at(rfriWhere.nFieldPos);
+
+ m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView());
+ m_pShell->GetFormView()->MarkObj(pObject, m_pShell->GetFormView()->GetSdrPageView());
+
+ FmFormObj* pFormObject = FmFormObj::GetFormObject( pObject );
+ Reference< XControlModel > xControlModel( pFormObject ? pFormObject->GetUnoControlModel() : Reference< XControlModel >() );
+ DBG_ASSERT( xControlModel.is(), "FmXFormShell::OnFoundData: invalid control!" );
+ if ( !xControlModel.is() )
+ return;
+
+ // disable the permanent cursor for the last grid we found a record
+ if (m_xLastGridFound.is() && (m_xLastGridFound != xControlModel))
+ {
+ Reference< XPropertySet> xOldSet(m_xLastGridFound, UNO_QUERY);
+ xOldSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any( false ) );
+ Reference< XPropertyState> xOldSetState(xOldSet, UNO_QUERY);
+ if (xOldSetState.is())
+ xOldSetState->setPropertyToDefault(FM_PROP_CURSORCOLOR);
+ else
+ xOldSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any());
+ }
+
+ // if the field is in a GridControl, I have to additionally go into the corresponding column there
+ sal_Int32 nGridColumn = m_arrRelativeGridColumn[rfriWhere.nFieldPos];
+ if (nGridColumn != -1)
+ { // unfortunately, I have to first get the control again
+ Reference<XControl> xControl(pFormObject ? impl_getControl_Lock(xControlModel, *pFormObject) : Reference<XControl>());
+ Reference< XGrid> xGrid(xControl, UNO_QUERY);
+ DBG_ASSERT(xGrid.is(), "FmXFormShell::OnFoundData : invalid control!");
+ // if one of the asserts fires, I probably did something wrong on building of m_arrSearchedControls
+
+ // enable a permanent cursor for the grid so we can see the found text
+ Reference< XPropertySet> xModelSet(xControlModel, UNO_QUERY);
+ DBG_ASSERT(xModelSet.is(), "FmXFormShell::OnFoundData : invalid control model (no property set) !");
+ xModelSet->setPropertyValue( FM_PROP_ALWAYSSHOWCURSOR, Any( true ) );
+ xModelSet->setPropertyValue( FM_PROP_CURSORCOLOR, Any( COL_LIGHTRED ) );
+ m_xLastGridFound = xControlModel;
+
+ if ( xGrid.is() )
+ xGrid->setCurrentColumnPosition(static_cast<sal_Int16>(nGridColumn));
+ }
+
+ // As the cursor has been repositioned, I have (in positioned) invalidated
+ // my form bar slots. But that does not take effect here unfortunately, as
+ // generally the (modal) search dialog is of course at the top ... So, force ...
+ sal_uInt16 nPos = 0;
+ while (DatabaseSlotMap[nPos])
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update(DatabaseSlotMap[nPos++]);
+ // unfortunately the update goes against the invalidate with only individual slots
+}
+
+
+IMPL_LINK(FmXFormShell, OnCanceledNotFound_Lock, FmFoundRecordInformation&, rfriWhere, void)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ DBG_ASSERT((rfriWhere.nContext >= 0) && (o3tl::make_unsigned(rfriWhere.nContext) < m_aSearchForms.size()),
+ "FmXFormShell::OnCanceledNotFound : invalid context!");
+ Reference< XForm> xForm( m_aSearchForms.at(rfriWhere.nContext));
+ DBG_ASSERT(xForm.is(), "FmXFormShell::OnCanceledNotFound : invalid form!");
+
+ Reference< XRowLocate> xCursor(xForm, UNO_QUERY);
+ if (!xCursor.is())
+ return; // what should I do there?
+
+ // to the record
+ try
+ {
+ xCursor->moveToBookmark(rfriWhere.aPosition);
+ }
+ catch(const SQLException&)
+ {
+ OSL_FAIL("Can position on bookmark!");
+ }
+
+
+ m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView());
+}
+
+
+IMPL_LINK(FmXFormShell, OnSearchContextRequest_Lock, FmSearchContext&, rfmscContextInfo, sal_uInt32)
+{
+ if (impl_checkDisposed_Lock())
+ return 0;
+
+ DBG_ASSERT(rfmscContextInfo.nContext < static_cast<sal_Int16>(m_aSearchForms.size()), "FmXFormShell::OnSearchContextRequest : invalid parameter !");
+ Reference< XForm> xForm( m_aSearchForms.at(rfmscContextInfo.nContext));
+ DBG_ASSERT(xForm.is(), "FmXFormShell::OnSearchContextRequest : unexpected : invalid context !");
+
+ Reference< XResultSet> xIter(xForm, UNO_QUERY);
+ DBG_ASSERT(xIter.is(), "FmXFormShell::OnSearchContextRequest : unexpected : context has no iterator !");
+
+
+ // assemble the list of fields to involve (that is, the ControlSources of all fields that have such a property)
+ OUString strFieldList, sFieldDisplayNames;
+ m_arrSearchedControls.clear();
+ m_arrRelativeGridColumn.clear();
+
+ // small problem: To mark found fields, I need SdrObjects. To determine which controls
+ // to include in the search, I need Controls (that is, XControl interfaces). So I have
+ // to iterate over one of them and get the other in some way. Unfortunately, there is
+ // no direct connection between the two worlds (except from a GetUnoControl to a
+ // SdrUnoObject, but this requires an OutputDevice I can not do anything with.
+ // However I can get to the Model from the Control and also from the SdrObject, and in
+ // this way the assignment SdrObject<->Control is possible with a double loop.
+ // The alternative to this (ugly but certainly not entirely fixable) solution would be
+ // to renounce the caching of the SdrObjects, which would lead to significant extra
+ // work in OnFoundData (since there I'd have to get the SdrObject first thing every
+ // time). But since OnFoundData is usually called more often than ExecuteSearch, I'll
+ // do that here.
+
+ Reference< XNameAccess> xValidFormFields;
+ Reference< XColumnsSupplier> xSupplyCols(xIter, UNO_QUERY);
+ DBG_ASSERT(xSupplyCols.is(), "FmXFormShell::OnSearchContextRequest : invalid cursor : no columns supplier !");
+ if (xSupplyCols.is())
+ xValidFormFields = xSupplyCols->getColumns();
+ DBG_ASSERT(xValidFormFields.is(), "FmXFormShell::OnSearchContextRequest : form has no fields !");
+
+ // current Page/Controller
+ FmFormPage* pCurrentPage = m_pShell->GetCurPage();
+ assert(pCurrentPage && "FmXFormShell::OnSearchContextRequest : no page !");
+ // Search all SdrControls of this page...
+ OUString sControlSource, aName;
+
+ SdrObjListIter aPageIter( pCurrentPage );
+ while ( aPageIter.IsMore() )
+ {
+ SdrObject* pCurrent = aPageIter.Next();
+ FmFormObj* pFormObject = FmFormObj::GetFormObject( pCurrent );
+ // note that in case pCurrent is a virtual object, pFormObject points to the referenced object
+
+ if ( !pFormObject )
+ continue;
+
+ // the current object's model, in different tastes
+ Reference< XControlModel> xControlModel( pFormObject->GetUnoControlModel() );
+ Reference< XFormComponent > xCurrentFormComponent( xControlModel, UNO_QUERY );
+ DBG_ASSERT( xCurrentFormComponent.is(), "FmXFormShell::OnSearchContextRequest: invalid objects!" );
+ if ( !xCurrentFormComponent.is() )
+ continue;
+
+ // does the component belong to the form which we're interested in?
+ if ( xCurrentFormComponent->getParent() != xForm )
+ continue;
+
+ // ... ask for the ControlSource property
+ SearchableControlIterator iter( xCurrentFormComponent );
+ Reference< XControl> xControl;
+ // the control that has model xControlModel
+ // (the following while can be passed through several times, without the Control
+ // being modified, so I don't have to search every time from scratch)
+
+ Reference< XInterface > xSearchable( iter.Next() );
+ while ( xSearchable.is() )
+ {
+ sControlSource = iter.getCurrentValue();
+ if ( sControlSource.isEmpty() )
+ {
+ // the current element has no ControlSource, so it is a GridControl (that
+ // is the only thing that still permits the SearchableControlIteratore)
+ xControl = impl_getControl_Lock(xControlModel, *pFormObject);
+ DBG_ASSERT(xControl.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !");
+
+ Reference< XGridPeer> xGridPeer;
+ if ( xControl.is() )
+ xGridPeer.set( xControl->getPeer(), UNO_QUERY );
+ do
+ {
+ if (!xGridPeer.is())
+ break;
+
+ Reference< XIndexAccess> xPeerContainer(xGridPeer, UNO_QUERY);
+ if (!xPeerContainer.is())
+ break;
+
+ Reference< XIndexAccess> xModelColumns = xGridPeer->getColumns();
+ DBG_ASSERT(xModelColumns.is(), "FmXFormShell::OnSearchContextRequest : there is a grid control without columns !");
+ // the case 'no columns' should be indicated with an empty container, I think ...
+ DBG_ASSERT(xModelColumns->getCount() >= xPeerContainer->getCount(), "FmXFormShell::OnSearchContextRequest : impossible : have more view than model columns !");
+
+ Reference< XInterface> xCurrentColumn;
+ for (sal_Int32 nViewPos=0; nViewPos<xPeerContainer->getCount(); ++nViewPos)
+ {
+ xPeerContainer->getByIndex(nViewPos) >>= xCurrentColumn;
+ if (!xCurrentColumn.is())
+ continue;
+
+ // can we use this column control for searching ?
+ if (!IsSearchableControl(xCurrentColumn))
+ continue;
+
+ sal_Int32 nModelPos = GridView2ModelPos(xModelColumns, nViewPos);
+ Reference< XPropertySet> xCurrentColModel;
+ xModelColumns->getByIndex(nModelPos) >>= xCurrentColModel;
+ aName = ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_CONTROLSOURCE));
+ // the cursor has a field matching the control source ?
+ if (xValidFormFields->hasByName(aName))
+ {
+ strFieldList += aName + ";";
+
+ sFieldDisplayNames +=
+ ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_LABEL)) +
+ ";";
+
+ rfmscContextInfo.arrFields.push_back(xCurrentColumn);
+
+ // and the SdrOject to the Field
+ m_arrSearchedControls.push_back(pCurrent);
+ // the number of the column
+ m_arrRelativeGridColumn.push_back(nViewPos);
+ }
+ }
+ } while (false);
+ }
+ else
+ {
+ if (!sControlSource.isEmpty() && xValidFormFields->hasByName(sControlSource))
+ {
+ // now I need the Control to SdrObject
+ if (!xControl.is())
+ {
+ xControl = impl_getControl_Lock(xControlModel, *pFormObject);
+ DBG_ASSERT(xControl.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !");
+ }
+
+ if (IsSearchableControl(xControl))
+ {
+ // all tests passed -> take along in the list
+ strFieldList += sControlSource + ";";
+
+ // the label which should appear for the control :
+ sFieldDisplayNames +=
+ getLabelName(Reference< XPropertySet>(xControlModel, UNO_QUERY)) +
+ ";";
+
+ // mark the SdrObject (accelerates the treatment in OnFoundData)
+ m_arrSearchedControls.push_back(pCurrent);
+
+ // the number of the column (here a dummy, since it is only interesting for GridControls)
+ m_arrRelativeGridColumn.push_back(-1);
+
+ // and for the formatted search...
+ rfmscContextInfo.arrFields.emplace_back( xControl, UNO_QUERY );
+ }
+ }
+ }
+
+ xSearchable = iter.Next();
+ }
+ }
+
+ strFieldList = comphelper::string::stripEnd(strFieldList, ';');
+ sFieldDisplayNames = comphelper::string::stripEnd(sFieldDisplayNames, ';');
+
+ if (rfmscContextInfo.arrFields.empty())
+ {
+ rfmscContextInfo.arrFields.clear();
+ rfmscContextInfo.xCursor = nullptr;
+ rfmscContextInfo.strUsedFields.clear();
+ return 0;
+ }
+
+ rfmscContextInfo.xCursor = xIter;
+ rfmscContextInfo.strUsedFields = strFieldList;
+ rfmscContextInfo.sFieldDisplayNames = sFieldDisplayNames;
+
+ // 66463 - 31.05.99 - FS
+ // when the cursor is a non-STANDARD RecordMode, set it back
+ Reference< XPropertySet> xCursorSet(rfmscContextInfo.xCursor, UNO_QUERY);
+ Reference< XResultSetUpdate> xUpdateCursor(rfmscContextInfo.xCursor, UNO_QUERY);
+ if (xUpdateCursor.is() && xCursorSet.is())
+ {
+ if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISNEW)))
+ xUpdateCursor->moveToCurrentRow();
+ else if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISMODIFIED)))
+ xUpdateCursor->cancelRowUpdates();
+ }
+
+ return rfmscContextInfo.arrFields.size();
+}
+
+ // XContainerListener
+
+void SAL_CALL FmXFormShell::elementInserted(const ContainerEvent& evt)
+{
+ SolarMutexGuard g;
+
+ if (impl_checkDisposed_Lock())
+ return;
+
+ // new object to listen to
+ Reference< XInterface> xTemp;
+ evt.Element >>= xTemp;
+ AddElement_Lock(xTemp);
+
+ m_pShell->DetermineForms(true);
+}
+
+
+void SAL_CALL FmXFormShell::elementReplaced(const ContainerEvent& evt)
+{
+ SolarMutexGuard g;
+
+ if (impl_checkDisposed_Lock() )
+ return;
+
+ Reference< XInterface> xTemp;
+ evt.ReplacedElement >>= xTemp;
+ RemoveElement_Lock(xTemp);
+ evt.Element >>= xTemp;
+ AddElement_Lock(xTemp);
+}
+
+
+void SAL_CALL FmXFormShell::elementRemoved(const ContainerEvent& evt)
+{
+ SolarMutexGuard g;
+
+ if (impl_checkDisposed_Lock())
+ return;
+
+ Reference< XInterface> xTemp;
+ evt.Element >>= xTemp;
+ RemoveElement_Lock(xTemp);
+
+ m_pShell->DetermineForms(true);
+}
+
+
+void FmXFormShell::UpdateForms_Lock(bool _bInvalidate)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ Reference< XIndexAccess > xForms;
+
+ FmFormPage* pPage = m_pShell->GetCurPage();
+ if ( pPage && m_pShell->m_bDesignMode )
+ xForms = pPage->GetForms( false );
+
+ if ( m_xForms != xForms )
+ {
+ RemoveElement_Lock( m_xForms );
+ m_xForms = xForms;
+ AddElement_Lock(m_xForms);
+ }
+
+ SolarMutexGuard g;
+ m_pShell->DetermineForms( _bInvalidate );
+}
+
+
+void FmXFormShell::AddElement_Lock(const Reference<XInterface>& _xElement)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+ impl_AddElement_nothrow(_xElement);
+}
+
+void FmXFormShell::impl_AddElement_nothrow(const Reference< XInterface>& Element)
+{
+ // listen at the container
+ const Reference< XIndexContainer> xContainer(Element, UNO_QUERY);
+ if (xContainer.is())
+ {
+ const sal_uInt32 nCount = xContainer->getCount();
+ Reference< XInterface> xElement;
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ xElement.set(xContainer->getByIndex(i),UNO_QUERY);
+ impl_AddElement_nothrow(xElement);
+ }
+
+ const Reference< XContainer> xCont(Element, UNO_QUERY);
+ if (xCont.is())
+ xCont->addContainerListener(this);
+ }
+
+ const Reference< css::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY);
+ if (xSelSupplier.is())
+ xSelSupplier->addSelectionChangeListener(this);
+}
+
+
+void FmXFormShell::RemoveElement_Lock(const Reference<XInterface>& Element)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+ impl_RemoveElement_nothrow_Lock(Element);
+}
+
+void FmXFormShell::impl_RemoveElement_nothrow_Lock(const Reference<XInterface>& Element)
+{
+ const Reference< css::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY);
+ if (xSelSupplier.is())
+ xSelSupplier->removeSelectionChangeListener(this);
+
+ // remove connection to children
+ const Reference< XIndexContainer> xContainer(Element, UNO_QUERY);
+ if (xContainer.is())
+ {
+ const Reference< XContainer> xCont(Element, UNO_QUERY);
+ if (xCont.is())
+ xCont->removeContainerListener(this);
+
+ const sal_uInt32 nCount = xContainer->getCount();
+ Reference< XInterface> xElement;
+ for (sal_uInt32 i = 0; i < nCount; i++)
+ {
+ xElement.set(xContainer->getByIndex(i),UNO_QUERY);
+ impl_RemoveElement_nothrow_Lock(xElement);
+ }
+ }
+
+ auto wasSelectedPos = m_aCurrentSelection.find( Element );
+ if ( wasSelectedPos != m_aCurrentSelection.end() )
+ m_aCurrentSelection.erase( wasSelectedPos );
+}
+
+
+void SAL_CALL FmXFormShell::selectionChanged(const lang::EventObject& rEvent)
+{
+ SolarMutexGuard g;
+
+ if (impl_checkDisposed_Lock())
+ return;
+
+ Reference< XSelectionSupplier > xSupplier( rEvent.Source, UNO_QUERY );
+ Reference< XInterface > xSelObj( xSupplier->getSelection(), UNO_QUERY );
+ // a selection was removed, this can only be done by the shell
+ if ( !xSelObj.is() )
+ return;
+
+ EnableTrackProperties_Lock(false);
+
+ bool bMarkChanged = m_pShell->GetFormView()->checkUnMarkAll(rEvent.Source);
+
+ InterfaceBag aNewSelection;
+ aNewSelection.insert( Reference<XInterface>( xSelObj, UNO_QUERY ) );
+
+ if (setCurrentSelection_Lock(std::move(aNewSelection)) && IsPropBrwOpen_Lock())
+ ShowSelectionProperties_Lock(true);
+
+ EnableTrackProperties_Lock(true);
+
+ if ( bMarkChanged )
+ m_pShell->NotifyMarkListChanged( m_pShell->GetFormView() );
+}
+
+
+IMPL_LINK_NOARG(FmXFormShell, OnTimeOut_Lock, Timer*, void)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ if (m_pShell->IsDesignMode() && m_pShell->GetFormView())
+ SetSelection_Lock(m_pShell->GetFormView()->GetMarkedObjectList());
+}
+
+
+void FmXFormShell::SetSelectionDelayed_Lock()
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ if (m_pShell->IsDesignMode() && IsTrackPropertiesEnabled_Lock() && !m_aMarkTimer.IsActive())
+ m_aMarkTimer.Start();
+}
+
+
+void FmXFormShell::SetSelection_Lock(const SdrMarkList& rMarkList)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ DetermineSelection_Lock(rMarkList);
+ m_pShell->NotifyMarkListChanged(m_pShell->GetFormView());
+}
+
+
+void FmXFormShell::DetermineSelection_Lock(const SdrMarkList& rMarkList)
+{
+ if (setCurrentSelectionFromMark_Lock(rMarkList) && IsPropBrwOpen_Lock())
+ ShowSelectionProperties_Lock(true);
+}
+
+
+bool FmXFormShell::IsPropBrwOpen_Lock() const
+{
+ if (impl_checkDisposed_Lock())
+ return false;
+
+ return m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame()
+ && m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow(SID_FM_SHOW_PROPERTIES);
+}
+
+
+class FmXFormShell::SuspendPropertyTracking
+{
+private:
+ FmXFormShell& m_rShell;
+ bool m_bEnabled;
+
+public:
+ explicit SuspendPropertyTracking( FmXFormShell& _rShell )
+ :m_rShell( _rShell )
+ ,m_bEnabled( false )
+ {
+ if (m_rShell.IsTrackPropertiesEnabled_Lock())
+ {
+ m_rShell.EnableTrackProperties_Lock(false);
+ m_bEnabled = true;
+ }
+ }
+
+ ~SuspendPropertyTracking( )
+ {
+ if ( m_bEnabled ) // note that ( false != m_bEnabled ) implies ( NULL != m_pShell )
+ m_rShell.EnableTrackProperties_Lock(true);
+ }
+};
+
+
+void FmXFormShell::SetDesignMode_Lock(bool bDesign)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ DBG_ASSERT(m_pShell->GetFormView(), "FmXFormShell::SetDesignMode : invalid call (have no shell or no view) !");
+ m_bChangingDesignMode = true;
+
+ // 67506 - 15.07.99 - FS
+ // if we're switching off the design mode we have to force the property browser to be closed
+ // so it can commit it's changes _before_ we load the forms
+ if (!bDesign)
+ {
+ m_bHadPropertyBrowserInDesignMode = m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow(SID_FM_SHOW_PROPERTIES);
+ if (m_bHadPropertyBrowserInDesignMode)
+ m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow(SID_FM_SHOW_PROPERTIES);
+ }
+
+ FmFormView* pFormView = m_pShell->GetFormView();
+ if (bDesign)
+ {
+ // we are currently filtering, so stop filtering
+ if (m_bFilterMode)
+ stopFiltering_Lock(false);
+
+ // unsubscribe from the objects of my MarkList
+ pFormView->GetImpl()->stopMarkListWatching();
+ }
+ else
+ {
+ m_aMarkTimer.Stop();
+
+ SuspendPropertyTracking aSuspend( *this );
+ pFormView->GetImpl()->saveMarkList();
+ }
+
+ if (bDesign && m_xExternalViewController.is())
+ CloseExternalFormViewer_Lock();
+
+ pFormView->ChangeDesignMode(bDesign);
+
+ // notify listeners
+ FmDesignModeChangedHint aChangedHint( bDesign );
+ m_pShell->Broadcast(aChangedHint);
+
+ m_pShell->m_bDesignMode = bDesign;
+ UpdateForms_Lock(false);
+
+ m_pTextShell->designModeChanged();
+
+ if (bDesign)
+ {
+ SdrMarkList aList;
+ {
+ // during changing the mark list, don't track the selected objects in the property browser
+ SuspendPropertyTracking aSuspend( *this );
+ // restore the marks
+ pFormView->GetImpl()->restoreMarkList( aList );
+ }
+
+ // synchronize with the restored mark list
+ if ( aList.GetMarkCount() )
+ SetSelection_Lock(aList);
+ }
+ else
+ {
+ // subscribe to the model of the view (so that I'm informed when someone deletes
+ // during the alive mode controls that I had saved in the saveMarklist (60343)
+ pFormView->GetImpl()->startMarkListWatching();
+ }
+
+ m_pShell->UIFeatureChanged();
+
+ // 67506 - 15.07.99 - FS
+ if (bDesign && m_bHadPropertyBrowserInDesignMode)
+ {
+ // The UIFeatureChanged performs an update (a check of the available features) asynchronously.
+ // So we can't call ShowSelectionProperties directly as the according feature isn't enabled yet.
+ // That's why we use an asynchron execution on the dispatcher.
+ // (And that's why this has to be done AFTER the UIFeatureChanged.)
+ m_pShell->GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SfxCallMode::ASYNCHRON );
+ }
+ m_bChangingDesignMode = false;
+}
+
+
+Reference< XControl> FmXFormShell::impl_getControl_Lock(const Reference<XControlModel>& i_rxModel, const FmFormObj& i_rKnownFormObj)
+{
+ if (impl_checkDisposed_Lock())
+ return nullptr;
+
+ Reference< XControl > xControl;
+ try
+ {
+ Reference< XControlContainer> xControlContainer(getControlContainerForView_Lock(), UNO_SET_THROW);
+
+ const Sequence< Reference< XControl > > seqControls( xControlContainer->getControls() );
+ // ... that I can then search
+ for (Reference< XControl > const & control : seqControls)
+ {
+ xControl.set( control, UNO_SET_THROW );
+ Reference< XControlModel > xCurrentModel( xControl->getModel() );
+ if ( xCurrentModel == i_rxModel )
+ break;
+ xControl.clear();
+ }
+
+ if ( !xControl.is() )
+ {
+ // fallback (some controls might not have been created, yet, since they were never visible so far)
+ Reference< XControl > xContainerControl( xControlContainer, UNO_QUERY_THROW );
+ const vcl::Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerControl->getPeer() );
+ ENSURE_OR_THROW( pContainerWindow, "unexpected control container implementation" );
+
+ const SdrView* pSdrView = m_pShell ? m_pShell->GetFormView() : nullptr;
+ ENSURE_OR_THROW( pSdrView, "no current view" );
+
+ xControl.set( i_rKnownFormObj.GetUnoControl( *pSdrView, *pContainerWindow->GetOutDev() ), UNO_SET_THROW );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ OSL_ENSURE( xControl.is(), "FmXFormShell::impl_getControl: no control found!" );
+ return xControl;
+}
+
+// note: _out_rForms is a member so needs lock
+void FmXFormShell::impl_collectFormSearchContexts_nothrow_Lock( const Reference<XInterface>& _rxStartingPoint,
+ std::u16string_view _rCurrentLevelPrefix, FmFormArray& _out_rForms, ::std::vector< OUString >& _out_rNames )
+{
+ try
+ {
+ Reference< XIndexAccess> xContainer( _rxStartingPoint, UNO_QUERY );
+ if ( !xContainer.is() )
+ return;
+
+ sal_Int32 nCount( xContainer->getCount() );
+ if ( nCount == 0 )
+ return;
+
+ OUString sCurrentFormName;
+ OUStringBuffer aNextLevelPrefix;
+ for ( sal_Int32 i=0; i<nCount; ++i )
+ {
+ // is the current child a form?
+ Reference< XForm > xCurrentAsForm( xContainer->getByIndex(i), UNO_QUERY );
+ if ( !xCurrentAsForm.is() )
+ continue;
+
+ Reference< XNamed > xNamed( xCurrentAsForm, UNO_QUERY_THROW );
+ sCurrentFormName = xNamed->getName();
+
+ // the name of the current form
+ OUString sCompleteCurrentName( sCurrentFormName );
+ if ( !_rCurrentLevelPrefix.empty() )
+ {
+ sCompleteCurrentName += OUString::Concat(" (") + _rCurrentLevelPrefix + ")";
+ }
+
+ // the prefix for the next level
+ aNextLevelPrefix = _rCurrentLevelPrefix;
+ if ( !_rCurrentLevelPrefix.empty() )
+ aNextLevelPrefix.append( '/' );
+ aNextLevelPrefix.append( sCurrentFormName );
+
+ // remember both the form and its "display name"
+ _out_rForms.push_back( xCurrentAsForm );
+ _out_rNames.push_back( sCompleteCurrentName );
+
+ // and descend
+ impl_collectFormSearchContexts_nothrow_Lock(
+ xCurrentAsForm, aNextLevelPrefix,
+ _out_rForms, _out_rNames);
+ aNextLevelPrefix.setLength(0);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+void FmXFormShell::startFiltering_Lock()
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ // setting all forms in filter mode
+ FmXFormView* pXView = m_pShell->GetFormView()->GetImpl();
+
+ // if the active controller is our external one we have to use the trigger controller
+ Reference< XControlContainer> xContainer;
+ if (getActiveController_Lock() == m_xExternalViewController)
+ {
+ DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::startFiltering : inconsistent : active external controller, but no one triggered this !");
+ xContainer = m_xExtViewTriggerController->getContainer();
+ }
+ else
+ xContainer = getActiveController_Lock()->getContainer();
+
+ rtl::Reference< FormViewPageWindowAdapter > pAdapter = pXView->findWindow( xContainer );
+ if ( pAdapter.is() )
+ {
+ const ::std::vector< Reference< runtime::XFormController> >& rControllerList = pAdapter->GetList();
+ for (const auto& rpController : rControllerList)
+ {
+ Reference< XModeSelector> xModeSelector(rpController, UNO_QUERY);
+ if (xModeSelector.is())
+ xModeSelector->setMode( "FilterMode" );
+ }
+ }
+
+ m_bFilterMode = true;
+
+ m_pShell->UIFeatureChanged();
+ SfxViewFrame* pViewFrame = m_pShell->GetViewShell()->GetViewFrame();
+ pViewFrame->GetBindings().InvalidateShell( *m_pShell );
+
+ if ( pViewFrame->KnowsChildWindow( SID_FM_FILTER_NAVIGATOR )
+ && !pViewFrame->HasChildWindow( SID_FM_FILTER_NAVIGATOR )
+ )
+ {
+ pViewFrame->ToggleChildWindow( SID_FM_FILTER_NAVIGATOR );
+ }
+}
+
+
+static void saveFilter(const Reference< runtime::XFormController >& _rxController)
+{
+ Reference< XPropertySet> xFormAsSet(_rxController->getModel(), UNO_QUERY);
+ Reference< XPropertySet> xControllerAsSet(_rxController, UNO_QUERY);
+
+ // call the subcontroller
+ Reference< runtime::XFormController > xController;
+ for (sal_Int32 i = 0, nCount = _rxController->getCount(); i < nCount; ++i)
+ {
+ _rxController->getByIndex(i) >>= xController;
+ saveFilter(xController);
+ }
+
+ try
+ {
+
+ xFormAsSet->setPropertyValue(FM_PROP_FILTER, xControllerAsSet->getPropertyValue(FM_PROP_FILTER));
+ xFormAsSet->setPropertyValue(FM_PROP_APPLYFILTER, Any( true ) );
+ }
+ catch (const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+}
+
+
+void FmXFormShell::stopFiltering_Lock(bool bSave)
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ m_bFilterMode = false;
+
+ FmXFormView* pXView = m_pShell->GetFormView()->GetImpl();
+
+ // if the active controller is our external one we have to use the trigger controller
+ Reference< XControlContainer> xContainer;
+ if (getActiveController_Lock() == m_xExternalViewController)
+ {
+ DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::stopFiltering : inconsistent : active external controller, but no one triggered this !");
+ xContainer = m_xExtViewTriggerController->getContainer();
+ }
+ else
+ xContainer = getActiveController_Lock()->getContainer();
+
+ rtl::Reference< FormViewPageWindowAdapter > pAdapter = pXView->findWindow(xContainer);
+ if ( pAdapter.is() )
+ {
+ const ::std::vector< Reference< runtime::XFormController > >& rControllerList = pAdapter->GetList();
+ ::std::vector < OUString > aOriginalFilters;
+ ::std::vector < bool > aOriginalApplyFlags;
+
+ if (bSave)
+ {
+ for (const auto& rpController : rControllerList)
+ {
+ // remember the current filter settings in case we're going to reload the forms below (which may fail)
+ try
+ {
+ Reference< XPropertySet > xFormAsSet(rpController->getModel(), UNO_QUERY);
+ aOriginalFilters.push_back(::comphelper::getString(xFormAsSet->getPropertyValue(FM_PROP_FILTER)));
+ aOriginalApplyFlags.push_back(::comphelper::getBOOL(xFormAsSet->getPropertyValue(FM_PROP_APPLYFILTER)));
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("FmXFormShell::stopFiltering : could not get the original filter !");
+ // put dummies into the arrays so the they have the right size
+
+ if (aOriginalFilters.size() == aOriginalApplyFlags.size())
+ // the first getPropertyValue failed -> use two dummies
+ aOriginalFilters.emplace_back( );
+ aOriginalApplyFlags.push_back( false );
+ }
+ saveFilter(rpController);
+ }
+ }
+ for (const auto& rController : rControllerList)
+ {
+
+ Reference< XModeSelector> xModeSelector(rController, UNO_QUERY);
+ if (xModeSelector.is())
+ xModeSelector->setMode( "DataMode" );
+ }
+ if (bSave) // execute the filter
+ {
+ const ::std::vector< Reference< runtime::XFormController > > & rControllers = pAdapter->GetList();
+ for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllers.begin();
+ j != rControllers.end(); ++j)
+ {
+ Reference< XLoadable> xReload((*j)->getModel(), UNO_QUERY);
+ if (!xReload.is())
+ continue;
+ Reference< XPropertySet > xFormSet(xReload, UNO_QUERY);
+
+ try
+ {
+ xReload->reload();
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "");
+ }
+
+ if (!isRowSetAlive(xFormSet))
+ { // something went wrong -> restore the original state
+ OUString sOriginalFilter = aOriginalFilters[ j - rControllers.begin() ];
+ bool bOriginalApplyFlag = aOriginalApplyFlags[ j - rControllers.begin() ];
+ try
+ {
+ xFormSet->setPropertyValue(FM_PROP_FILTER, Any(sOriginalFilter));
+ xFormSet->setPropertyValue(FM_PROP_APPLYFILTER, Any(bOriginalApplyFlag));
+ xReload->reload();
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+ }
+ }
+
+ m_pShell->UIFeatureChanged();
+ m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
+}
+
+
+void FmXFormShell::CreateExternalView_Lock()
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ DBG_ASSERT(m_xAttachedFrame.is(), "FmXFormShell::CreateExternalView : no frame !");
+
+ // the frame the external view is displayed in
+ bool bAlreadyExistent = m_xExternalViewController.is();
+ Reference< css::frame::XFrame> xExternalViewFrame;
+
+ Reference<runtime::XFormController> xCurrentNavController(getNavController_Lock());
+ // the creation of the "partwindow" may cause a deactivate of the document which will result in our nav controller to be set to NULL
+
+ // _first_ check if we have any valid fields we can use for the grid view
+ // FS - 21.10.99 - 69219
+ {
+ FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel());
+ bool bHaveUsableControls = false;
+ for (;;)
+ {
+ Reference< XPropertySet> xCurrentModelSet(aModelIterator.Next(), UNO_QUERY);
+ if (!xCurrentModelSet.is())
+ break;
+ // the FmXBoundFormFieldIterator only supplies controls with a valid control source
+ // so we just have to check the field type
+ sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID));
+ switch (nClassId)
+ {
+ case FormComponentType::IMAGECONTROL:
+ case FormComponentType::CONTROL:
+ continue;
+ }
+ bHaveUsableControls = true;
+ break;
+ }
+
+ if (!bHaveUsableControls)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SvxResId(RID_STR_NOCONTROLS_FOR_EXTERNALDISPLAY)));
+ xBox->run();
+ return;
+ }
+ }
+
+ // load the component for external form views
+ if (!bAlreadyExistent)
+ {
+ OUString sFrameName("_beamer");
+ URL aWantToDispatch;
+ aWantToDispatch.Complete = FMURL_COMPONENT_FORMGRIDVIEW;
+
+ Reference< css::frame::XDispatchProvider> xProv(m_xAttachedFrame, UNO_QUERY);
+ Reference< css::frame::XDispatch> xDisp;
+ if (xProv.is())
+ xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName,
+ css::frame::FrameSearchFlag::CHILDREN | css::frame::FrameSearchFlag::CREATE);
+ if (xDisp.is())
+ {
+ xDisp->dispatch(aWantToDispatch, Sequence< PropertyValue>());
+ }
+
+ // with this the component should be loaded, now search the frame where it resides in
+ xExternalViewFrame = m_xAttachedFrame->findFrame(sFrameName, css::frame::FrameSearchFlag::CHILDREN);
+ if (xExternalViewFrame.is())
+ {
+ m_xExternalViewController = xExternalViewFrame->getController();
+ if (m_xExternalViewController.is())
+ m_xExternalViewController->addEventListener(static_cast<XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
+ }
+ }
+ else
+ {
+ xExternalViewFrame = m_xExternalViewController->getFrame();
+ Reference< css::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY);
+
+ // if we display the active form we interpret the slot as "remove it"
+ Reference< XForm> xCurrentModel(xCurrentNavController->getModel(), UNO_QUERY);
+ if ((xCurrentModel == m_xExternalDisplayedForm) || (getInternalForm_Lock(xCurrentModel) == m_xExternalDisplayedForm))
+ {
+ if (m_xExternalViewController == getActiveController_Lock())
+ {
+ Reference< runtime::XFormController > xAsFormController( m_xExternalViewController, UNO_QUERY );
+ ControllerFeatures aHelper( xAsFormController );
+ (void)aHelper->commitCurrentControl();
+ }
+
+ Reference< runtime::XFormController > xNewController(m_xExtViewTriggerController);
+ CloseExternalFormViewer_Lock();
+ setActiveController_Lock(xNewController);
+ return;
+ }
+
+ URL aClearURL;
+ aClearURL.Complete = FMURL_GRIDVIEW_CLEARVIEW;
+
+ Reference< css::frame::XDispatch> xClear( xCommLink->queryDispatch(aClearURL, OUString(), 0));
+ if (xClear.is())
+ xClear->dispatch(aClearURL, Sequence< PropertyValue>());
+ }
+
+ // TODO: We need an interceptor at the xSupplier, which forwards all queryDispatch requests to the FormController
+ // instance for which this "external view" was triggered
+
+ // get the dispatch interface of the frame so we can communicate (interceptable) with the controller
+ Reference< css::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY);
+
+ if (m_xExternalViewController.is())
+ {
+ DBG_ASSERT(xCommLink.is(), "FmXFormShell::CreateExternalView : the component doesn't have the necessary interfaces !");
+ // collect the dispatchers we will need
+ URL aAddColumnURL;
+ aAddColumnURL.Complete = FMURL_GRIDVIEW_ADDCOLUMN;
+ Reference< css::frame::XDispatch> xAddColumnDispatch( xCommLink->queryDispatch(aAddColumnURL, OUString(), 0));
+ URL aAttachURL;
+ aAttachURL.Complete = FMURL_GRIDVIEW_ATTACHTOFORM;
+ Reference< css::frame::XDispatch> xAttachDispatch( xCommLink->queryDispatch(aAttachURL, OUString(), 0));
+
+ if (xAddColumnDispatch.is() && xAttachDispatch.is())
+ {
+ DBG_ASSERT(xCurrentNavController.is(), "FmXFormShell::CreateExternalView : invalid call : have no nav controller !");
+ // first : dispatch the descriptions for the columns to add
+ sal_Int16 nAddedColumns = 0;
+
+ // for radio buttons we need some special structures
+ typedef std::map< OUString, Sequence< OUString> > MapUString2UstringSeq;
+ typedef std::map< OUString, OUString > FmMapUString2UString;
+ typedef std::map< OUString, sal_Int16 > FmMapUString2Int16;
+
+ MapUString2UstringSeq aRadioValueLists;
+ MapUString2UstringSeq aRadioListSources;
+ FmMapUString2UString aRadioControlSources;
+ FmMapUString2Int16 aRadioPositions;
+
+ FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel());
+ OUString sColumnType,aGroupName,sControlSource;
+ Sequence< Property> aProps;
+ for (;;)
+ {
+ Reference< XPropertySet> xCurrentModelSet(aModelIterator.Next(), UNO_QUERY);
+ if (!xCurrentModelSet.is())
+ break;
+ OSL_ENSURE(xCurrentModelSet.is(),"xCurrentModelSet is null!");
+ // create a description of the column to be created
+ // first : determine it's type
+
+ sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID));
+ switch (nClassId)
+ {
+ case FormComponentType::RADIOBUTTON:
+ {
+ // get the label of the button (this is the access key for our structures)
+ aGroupName = getLabelName(xCurrentModelSet);
+
+ // add the reference value of the radio button to the list source sequence
+ Sequence< OUString>& aThisGroupLabels = aRadioListSources[aGroupName];
+ sal_Int32 nNewSizeL = aThisGroupLabels.getLength() + 1;
+ aThisGroupLabels.realloc(nNewSizeL);
+ aThisGroupLabels.getArray()[nNewSizeL - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_REFVALUE));
+
+ // add the label to the value list sequence
+ Sequence< OUString>& aThisGroupControlSources = aRadioValueLists[aGroupName];
+ sal_Int32 nNewSizeC = aThisGroupControlSources.getLength() + 1;
+ aThisGroupControlSources.realloc(nNewSizeC);
+ aThisGroupControlSources.getArray()[nNewSizeC - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_LABEL));
+
+ // remember the controls source of the radio group
+ sControlSource = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_CONTROLSOURCE));
+ if (aRadioControlSources.find(aGroupName) == aRadioControlSources.end())
+ aRadioControlSources[aGroupName] = sControlSource;
+#ifdef DBG_UTIL
+ else
+ DBG_ASSERT(aRadioControlSources[aGroupName] == sControlSource,
+ "FmXFormShell::CreateExternalView : inconsistent radio buttons detected !");
+ // (radio buttons with the same name should have the same control source)
+#endif
+ // remember the position within the columns
+ if (aRadioPositions.find(aGroupName) == aRadioPositions.end())
+ aRadioPositions[aGroupName] = nAddedColumns;
+
+ // any further handling is done below
+ }
+ continue;
+
+ case FormComponentType::IMAGECONTROL:
+ case FormComponentType::CONTROL:
+ // no grid columns for these types (though they have a control source)
+ continue;
+ case FormComponentType::CHECKBOX:
+ sColumnType = FM_COL_CHECKBOX; break;
+ case FormComponentType::LISTBOX:
+ sColumnType = FM_COL_LISTBOX; break;
+ case FormComponentType::COMBOBOX:
+ sColumnType = FM_COL_COMBOBOX; break;
+ case FormComponentType::DATEFIELD:
+ sColumnType = FM_COL_DATEFIELD; break;
+ case FormComponentType::TIMEFIELD:
+ sColumnType = FM_COL_TIMEFIELD; break;
+ case FormComponentType::NUMERICFIELD:
+ sColumnType = FM_COL_NUMERICFIELD; break;
+ case FormComponentType::CURRENCYFIELD:
+ sColumnType = FM_COL_CURRENCYFIELD; break;
+ case FormComponentType::PATTERNFIELD:
+ sColumnType = FM_COL_PATTERNFIELD; break;
+
+ case FormComponentType::TEXTFIELD:
+ {
+ sColumnType = FM_COL_TEXTFIELD;
+ // we know at least two different controls which are TextFields : the basic edit field and the formatted
+ // field. we distinguish them by their service name
+ Reference< lang::XServiceInfo> xInfo(xCurrentModelSet, UNO_QUERY);
+ if (xInfo.is())
+ {
+ SdrObjKind nObjectType = getControlTypeByObject(xInfo);
+ if (SdrObjKind::FormFormattedField == nObjectType)
+ sColumnType = FM_COL_FORMATTEDFIELD;
+ }
+ }
+ break;
+ default:
+ sColumnType = FM_COL_TEXTFIELD; break;
+ }
+
+ const sal_Int16 nDispatchArgs = 3;
+ Sequence< PropertyValue> aDispatchArgs(nDispatchArgs);
+ PropertyValue* pDispatchArgs = aDispatchArgs.getArray();
+
+ // properties describing "meta data" about the column
+ // the type
+ pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE;
+ pDispatchArgs->Value <<= sColumnType;
+ ++pDispatchArgs;
+
+ // the pos : append the col
+ pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS;
+ pDispatchArgs->Value <<= nAddedColumns;
+ ++pDispatchArgs;
+
+ // the properties to forward to the new column
+ Sequence< PropertyValue> aColumnProps(1);
+ PropertyValue* pColumnProps = aColumnProps.getArray();
+
+ // the label
+ pColumnProps->Name = FM_PROP_LABEL;
+ pColumnProps->Value <<= getLabelName(xCurrentModelSet);
+ ++pColumnProps;
+
+ // for all other props : transfer them
+ Reference< XPropertySetInfo> xControlModelInfo( xCurrentModelSet->getPropertySetInfo());
+ DBG_ASSERT(xControlModelInfo.is(), "FmXFormShell::CreateExternalView : the control model has no property info ! This will crash !");
+ aProps = xControlModelInfo->getProperties();
+
+ // realloc the control description sequence
+ sal_Int32 nExistentDescs = pColumnProps - aColumnProps.getArray();
+ aColumnProps.realloc(nExistentDescs + aProps.getLength());
+ pColumnProps = aColumnProps.getArray() + nExistentDescs;
+
+ for (const Property& rProp : std::as_const(aProps))
+ {
+ if (rProp.Name == FM_PROP_LABEL)
+ // already set
+ continue;
+ if (rProp.Name == FM_PROP_DEFAULTCONTROL)
+ // allow the column's own "default control"
+ continue;
+ if (rProp.Attributes & PropertyAttribute::READONLY)
+ // assume that properties which are readonly for the control are ro for the column to be created, too
+ continue;
+
+ pColumnProps->Name = rProp.Name;
+ pColumnProps->Value = xCurrentModelSet->getPropertyValue(rProp.Name);
+ ++pColumnProps;
+ }
+ aColumnProps.realloc(pColumnProps - aColumnProps.getArray());
+
+ // columns props are a dispatch argument
+ pDispatchArgs->Name = "ColumnProperties"; // TODO : fmurl.*
+ pDispatchArgs->Value <<= aColumnProps;
+ ++pDispatchArgs;
+ DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()),
+ "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?");
+
+ // dispatch the "add column"
+ xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs);
+ ++nAddedColumns;
+ }
+
+ // now for the radio button handling
+ sal_Int16 nOffset(0);
+ // properties describing the "direct" column properties
+ const sal_Int16 nListBoxDescription = 6;
+ Sequence< PropertyValue> aListBoxDescription(nListBoxDescription);
+ for (const auto& rCtrlSource : aRadioControlSources)
+ {
+ PropertyValue* pListBoxDescription = aListBoxDescription.getArray();
+ // label
+ pListBoxDescription->Name = FM_PROP_LABEL;
+ pListBoxDescription->Value <<= rCtrlSource.first;
+ ++pListBoxDescription;
+
+ // control source
+ pListBoxDescription->Name = FM_PROP_CONTROLSOURCE;
+ pListBoxDescription->Value <<= rCtrlSource.second;
+ ++pListBoxDescription;
+
+ // bound column
+ pListBoxDescription->Name = FM_PROP_BOUNDCOLUMN;
+ pListBoxDescription->Value <<= sal_Int16(1);
+ ++pListBoxDescription;
+
+ // content type
+ pListBoxDescription->Name = FM_PROP_LISTSOURCETYPE;
+ pListBoxDescription->Value <<= ListSourceType_VALUELIST;
+ ++pListBoxDescription;
+
+ // list source
+ MapUString2UstringSeq::const_iterator aCurrentListSource = aRadioListSources.find(rCtrlSource.first);
+ DBG_ASSERT(aCurrentListSource != aRadioListSources.end(),
+ "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
+ pListBoxDescription->Name = FM_PROP_LISTSOURCE;
+ pListBoxDescription->Value <<= (*aCurrentListSource).second;
+ ++pListBoxDescription;
+
+ // value list
+ MapUString2UstringSeq::const_iterator aCurrentValueList = aRadioValueLists.find(rCtrlSource.first);
+ DBG_ASSERT(aCurrentValueList != aRadioValueLists.end(),
+ "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
+ pListBoxDescription->Name = FM_PROP_STRINGITEMLIST;
+ pListBoxDescription->Value <<= (*aCurrentValueList).second;
+ ++pListBoxDescription;
+
+ DBG_ASSERT(nListBoxDescription == (pListBoxDescription - aListBoxDescription.getConstArray()),
+ "FmXFormShell::CreateExternalView : forgot to adjust nListBoxDescription ?");
+
+ // properties describing the column "meta data"
+ const sal_Int16 nDispatchArgs = 3;
+ Sequence< PropertyValue> aDispatchArgs(nDispatchArgs);
+ PropertyValue* pDispatchArgs = aDispatchArgs.getArray();
+
+ // column type : listbox
+ pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE;
+ pDispatchArgs->Value <<= OUString(FM_COL_LISTBOX);
+// pDispatchArgs->Value <<= (OUString)FM_COL_LISTBOX;
+ ++pDispatchArgs;
+
+ // column position
+ pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS;
+ FmMapUString2Int16::const_iterator aOffset = aRadioPositions.find(rCtrlSource.first);
+ DBG_ASSERT(aOffset != aRadioPositions.end(),
+ "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
+ sal_Int16 nPosition = (*aOffset).second;
+ nPosition = nPosition + nOffset;
+ // we already inserted nOffset additional columns...
+ pDispatchArgs->Value <<= nPosition;
+ ++pDispatchArgs;
+
+ // the
+ pDispatchArgs->Name = "ColumnProperties"; // TODO : fmurl.*
+ pDispatchArgs->Value <<= aListBoxDescription;
+ ++pDispatchArgs;
+ DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()),
+ "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?");
+
+ // dispatch the "add column"
+ xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs);
+ ++nAddedColumns;
+ ++nOffset;
+ }
+
+
+ DBG_ASSERT(nAddedColumns > 0, "FmXFormShell::CreateExternalView : no controls (inconsistent) !");
+ // we should have checked if we have any usable controls (see above).
+
+ // "load" the "form" of the external view
+ PropertyValue aArg;
+ aArg.Name = FMARG_ATTACHTO_MASTERFORM;
+ Reference< XResultSet> xForm(xCurrentNavController->getModel(), UNO_QUERY);
+ aArg.Value <<= xForm;
+
+ m_xExternalDisplayedForm = xForm;
+ // do this before dispatching the "attach" command, as the attach may result in a call to our queryDispatch (for the FormSlots)
+ // which needs the m_xExternalDisplayedForm
+
+ xAttachDispatch->dispatch(aAttachURL, Sequence< PropertyValue>(&aArg, 1));
+
+ m_xExtViewTriggerController = xCurrentNavController;
+
+ // we want to know modifications done in the external view
+ // if the external controller is a XFormController we can use all our default handlings for it
+ Reference< runtime::XFormController > xFormController( m_xExternalViewController, UNO_QUERY );
+ OSL_ENSURE( xFormController.is(), "FmXFormShell::CreateExternalView:: invalid external view controller!" );
+ if (xFormController.is())
+ xFormController->addActivateListener(static_cast<XFormControllerListener*>(this));
+ }
+ }
+#ifdef DBG_UTIL
+ else
+ {
+ OSL_FAIL("FmXFormShell::CreateExternalView : could not create the external form view !");
+ }
+#endif
+ InvalidateSlot_Lock(SID_FM_VIEW_AS_GRID, false);
+}
+
+
+void FmXFormShell::implAdjustConfigCache_Lock()
+{
+ // get (cache) the wizard usage flag
+ Sequence< OUString > aNames { "FormControlPilotsEnabled" };
+ Sequence< Any > aFlags = GetProperties(aNames);
+ if (1 == aFlags.getLength())
+ m_bUseWizards = ::cppu::any2bool(aFlags[0]);
+}
+
+
+void FmXFormShell::Notify( const css::uno::Sequence< OUString >& _rPropertyNames)
+{
+ DBG_TESTSOLARMUTEX();
+ if (impl_checkDisposed_Lock())
+ return;
+
+ for (const OUString& rName : _rPropertyNames)
+ if (rName == "FormControlPilotsEnabled")
+ {
+ implAdjustConfigCache_Lock();
+ InvalidateSlot_Lock(SID_FM_USE_WIZARDS, true);
+ }
+}
+
+void FmXFormShell::ImplCommit()
+{
+}
+
+
+void FmXFormShell::SetWizardUsing_Lock(bool _bUseThem)
+{
+ m_bUseWizards = _bUseThem;
+
+ Sequence< OUString > aNames { "FormControlPilotsEnabled" };
+ Sequence< Any > aValues{ Any(m_bUseWizards) };
+ PutProperties(aNames, aValues);
+}
+
+
+void FmXFormShell::viewDeactivated_Lock(FmFormView& _rCurrentView, bool _bDeactivateController)
+{
+
+ if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() )
+ {
+ _rCurrentView.GetImpl()->Deactivate( _bDeactivateController );
+ }
+
+ // if we have an async load operation pending for the 0-th page for this view,
+ // we need to cancel this
+ if (FmFormPage* pPage = _rCurrentView.GetCurPage())
+ {
+ // move all events from our queue to a new one, omit the events for the deactivated
+ // page
+ ::std::queue< FmLoadAction > aNewEvents;
+ while ( !m_aLoadingPages.empty() )
+ {
+ FmLoadAction aAction = m_aLoadingPages.front();
+ m_aLoadingPages.pop();
+ if ( pPage != aAction.pPage )
+ {
+ aNewEvents.push( aAction );
+ }
+ else
+ {
+ Application::RemoveUserEvent( aAction.nEventId );
+ }
+ }
+ m_aLoadingPages = aNewEvents;
+
+ // remove callbacks at the page
+ pPage->GetImpl().SetFormsCreationHdl( Link<FmFormPageImpl&,void>() );
+ }
+ UpdateForms_Lock(true);
+}
+
+
+IMPL_LINK_NOARG( FmXFormShell, OnFirstTimeActivation_Lock, void*, void )
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ m_nActivationEvent = nullptr;
+ SfxObjectShell* pDocument = m_pShell->GetObjectShell();
+
+ if ( pDocument && !pDocument->HasName() )
+ {
+ if (isEnhancedForm_Lock())
+ {
+ // show the data navigator
+ if ( !m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_SHOW_DATANAVIGATOR ) )
+ m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow( SID_FM_SHOW_DATANAVIGATOR );
+ }
+ }
+}
+
+
+IMPL_LINK_NOARG( FmXFormShell, OnFormsCreated_Lock, FmFormPageImpl&, void )
+{
+ UpdateForms_Lock(true);
+}
+
+
+void FmXFormShell::viewActivated_Lock(FmFormView& _rCurrentView, bool _bSyncAction)
+{
+ FmFormPage* pPage = _rCurrentView.GetCurPage();
+
+ // activate our view if we are activated ourself
+ // FS - 30.06.99 - 67308
+ if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() )
+ {
+ // load forms for the page the current view belongs to
+ if ( pPage )
+ {
+ if ( !pPage->GetImpl().hasEverBeenActivated() )
+ loadForms_Lock(pPage, LoadFormsFlags::Load
+ | (_bSyncAction ? LoadFormsFlags::Sync
+ : LoadFormsFlags::Async));
+ pPage->GetImpl().setHasBeenActivated( );
+ }
+
+ // first-time initializations for the views
+ if ( !_rCurrentView.GetImpl()->hasEverBeenActivated( ) )
+ {
+ _rCurrentView.GetImpl()->onFirstViewActivation( dynamic_cast<FmFormModel*>( _rCurrentView.GetModel() ) );
+ _rCurrentView.GetImpl()->setHasBeenActivated( );
+ }
+
+ // activate the current view
+ _rCurrentView.GetImpl()->Activate( _bSyncAction );
+ }
+
+ // set callbacks at the page
+ if ( pPage )
+ {
+ pPage->GetImpl().SetFormsCreationHdl(LINK(this, FmXFormShell, OnFormsCreated_Lock));
+ }
+
+ UpdateForms_Lock(true);
+
+ if ( m_bFirstActivation )
+ {
+ m_nActivationEvent = Application::PostUserEvent(LINK(this, FmXFormShell, OnFirstTimeActivation_Lock));
+ m_bFirstActivation = false;
+ }
+
+ // find a default "current form", if there is none, yet
+ // #i88186# / 2008-04-12 / frank.schoenheit@sun.com
+ impl_defaultCurrentForm_nothrow_Lock();
+}
+
+
+void FmXFormShell::impl_defaultCurrentForm_nothrow_Lock()
+{
+ if (impl_checkDisposed_Lock())
+ return;
+
+ if ( m_xCurrentForm.is() )
+ // no action required
+ return;
+
+ FmFormView* pFormView = m_pShell->GetFormView();
+ FmFormPage* pPage = pFormView ? pFormView->GetCurPage() : nullptr;
+ if ( !pPage )
+ return;
+
+ try
+ {
+ Reference< XIndexAccess > xForms = pPage->GetForms( false );
+ if ( !xForms.is() || !xForms->hasElements() )
+ return;
+
+ Reference< XForm > xNewCurrentForm( xForms->getByIndex(0), UNO_QUERY_THROW );
+ impl_updateCurrentForm_Lock(xNewCurrentForm);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+void FmXFormShell::smartControlReset( const Reference< XIndexAccess >& _rxModels )
+{
+ if (!_rxModels.is())
+ {
+ OSL_FAIL("FmXFormShell::smartControlReset: invalid container!");
+ return;
+ }
+
+ sal_Int32 nCount = _rxModels->getCount();
+ Reference< XPropertySet > xCurrent;
+ Reference< XPropertySetInfo > xCurrentInfo;
+ Reference< XPropertySet > xBoundField;
+
+ for (sal_Int32 i=0; i<nCount; ++i)
+ {
+ _rxModels->getByIndex(i) >>= xCurrent;
+ if (xCurrent.is())
+ xCurrentInfo = xCurrent->getPropertySetInfo();
+ else
+ xCurrentInfo.clear();
+ if (!xCurrentInfo.is())
+ continue;
+
+ if (xCurrentInfo->hasPropertyByName(FM_PROP_CLASSID))
+ { // it's a control model
+
+ // check if this control is bound to a living database field
+ if (xCurrentInfo->hasPropertyByName(FM_PROP_BOUNDFIELD))
+ xCurrent->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xBoundField;
+ else
+ xBoundField.clear();
+
+ // reset only if it's *not* bound
+ bool bReset = !xBoundField.is();
+
+ // and additionally, check if it has an external value binding
+ Reference< XBindableValue > xBindable( xCurrent, UNO_QUERY );
+ if ( xBindable.is() && xBindable->getValueBinding().is() )
+ bReset = false;
+
+ if ( bReset )
+ {
+ Reference< XReset > xControlReset( xCurrent, UNO_QUERY );
+ if ( xControlReset.is() )
+ xControlReset->reset();
+ }
+ }
+ else
+ {
+ Reference< XIndexAccess > xContainer(xCurrent, UNO_QUERY);
+ if (xContainer.is())
+ smartControlReset(xContainer);
+ }
+ }
+}
+
+
+IMPL_LINK_NOARG( FmXFormShell, OnLoadForms_Lock, void*, void )
+{
+ FmLoadAction aAction = m_aLoadingPages.front();
+ m_aLoadingPages.pop();
+
+ loadForms_Lock(aAction.pPage, aAction.nFlags & ~LoadFormsFlags::Async);
+}
+
+
+namespace
+{
+ bool lcl_isLoadable( const Reference< XInterface >& _rxLoadable )
+ {
+ // determines whether a form should be loaded or not
+ // if there is no datasource or connection there is no reason to load a form
+ Reference< XPropertySet > xSet( _rxLoadable, UNO_QUERY );
+ if ( !xSet.is() )
+ return false;
+ try
+ {
+ Reference< XConnection > xConn;
+ if ( isEmbeddedInDatabase( _rxLoadable, xConn ) )
+ return true;
+
+ // is there already an active connection
+ xSet->getPropertyValue(FM_PROP_ACTIVE_CONNECTION) >>= xConn;
+ if ( xConn.is() )
+ return true;
+
+ OUString sPropertyValue;
+ OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DATASOURCE ) >>= sPropertyValue );
+ if ( !sPropertyValue.isEmpty() )
+ return true;
+
+ OSL_VERIFY( xSet->getPropertyValue( FM_PROP_URL ) >>= sPropertyValue );
+ if ( !sPropertyValue.isEmpty() )
+ return true;
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return false;
+ }
+}
+
+
+void FmXFormShell::loadForms_Lock(FmFormPage* _pPage, const LoadFormsFlags _nBehaviour /* LoadFormsFlags::Load | LoadFormsFlags::Sync */)
+{
+ DBG_ASSERT( ( _nBehaviour & ( LoadFormsFlags::Async | LoadFormsFlags::Unload ) ) != ( LoadFormsFlags::Async | LoadFormsFlags::Unload ),
+ "FmXFormShell::loadForms: async loading not supported - this will heavily fail!" );
+
+ if ( _nBehaviour & LoadFormsFlags::Async )
+ {
+ m_aLoadingPages.push( FmLoadAction(
+ _pPage,
+ _nBehaviour,
+ Application::PostUserEvent(LINK(this, FmXFormShell, OnLoadForms_Lock), _pPage)
+ ) );
+ return;
+ }
+
+ DBG_ASSERT( _pPage, "FmXFormShell::loadForms: invalid page!" );
+ if ( !_pPage )
+ return;
+
+ // lock the undo env so the forms can change non-transient properties while loading
+ // (without this my doc's modified flag would be set)
+ FmFormModel& rFmFormModel(dynamic_cast< FmFormModel& >(_pPage->getSdrModelFromSdrPage()));
+ rFmFormModel.GetUndoEnv().Lock();
+
+ // load all forms
+ Reference< XIndexAccess > xForms = _pPage->GetForms( false );
+
+ if ( xForms.is() )
+ {
+ Reference< XLoadable > xForm;
+ for ( sal_Int32 j = 0, nCount = xForms->getCount(); j < nCount; ++j )
+ {
+ xForms->getByIndex( j ) >>= xForm;
+ bool bFormWasLoaded = false;
+ // a database form must be loaded for
+ try
+ {
+ if ( !( _nBehaviour & LoadFormsFlags::Unload ) )
+ {
+ if ( lcl_isLoadable( xForm ) && !xForm->isLoaded() )
+ xForm->load();
+ }
+ else
+ {
+ if ( xForm->isLoaded() )
+ {
+ bFormWasLoaded = true;
+ xForm->unload();
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ // reset the form if it was loaded
+ if ( bFormWasLoaded )
+ {
+ Reference< XIndexAccess > xContainer( xForm, UNO_QUERY );
+ DBG_ASSERT( xContainer.is(), "FmXFormShell::loadForms: the form is no container!" );
+ if ( xContainer.is() )
+ smartControlReset( xContainer );
+ }
+ }
+ }
+
+ // unlock the environment
+ rFmFormModel.GetUndoEnv().UnLock();
+}
+
+
+void FmXFormShell::ExecuteTextAttribute_Lock(SfxRequest& _rReq)
+{
+ DBG_TESTSOLARMUTEX();
+ m_pTextShell->ExecuteTextAttribute( _rReq );
+}
+
+
+void FmXFormShell::GetTextAttributeState_Lock(SfxItemSet& _rSet)
+{
+ DBG_TESTSOLARMUTEX();
+ m_pTextShell->GetTextAttributeState( _rSet );
+}
+
+
+bool FmXFormShell::IsActiveControl_Lock(bool _bCountRichTextOnly ) const
+{
+ DBG_TESTSOLARMUTEX();
+ return m_pTextShell->IsActiveControl( _bCountRichTextOnly );
+}
+
+
+void FmXFormShell::ForgetActiveControl_Lock()
+{
+ DBG_TESTSOLARMUTEX();
+ m_pTextShell->ForgetActiveControl();
+}
+
+
+void FmXFormShell::SetControlActivationHandler_Lock(const Link<LinkParamNone*,void>& _rHdl)
+{
+ DBG_TESTSOLARMUTEX();
+ m_pTextShell->SetControlActivationHandler( _rHdl );
+}
+
+void FmXFormShell::handleShowPropertiesRequest_Lock()
+{
+ if (onlyControlsAreMarked_Lock())
+ ShowSelectionProperties_Lock( true );
+}
+
+
+void FmXFormShell::handleMouseButtonDown_Lock(const SdrViewEvent& _rViewEvent)
+{
+ // catch simple double clicks
+ if (_rViewEvent.mnMouseClicks == 2 && _rViewEvent.mnMouseCode == MOUSE_LEFT)
+ {
+ if ( _rViewEvent.meHit == SdrHitKind::MarkedObject )
+ {
+ if (onlyControlsAreMarked_Lock())
+ ShowSelectionProperties_Lock( true );
+ }
+ }
+}
+
+
+bool FmXFormShell::HasControlFocus_Lock() const
+{
+ bool bHasControlFocus = false;
+
+ try
+ {
+ Reference<runtime::XFormController> xController(getActiveController_Lock());
+ Reference< XControl > xCurrentControl;
+ if ( xController.is() )
+ xCurrentControl.set( xController->getCurrentControl() );
+ if ( xCurrentControl.is() )
+ {
+ Reference< XWindow2 > xPeerWindow( xCurrentControl->getPeer(), UNO_QUERY_THROW );
+ bHasControlFocus = xPeerWindow->hasFocus();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ return bHasControlFocus;
+}
+
+
+SearchableControlIterator::SearchableControlIterator(Reference< XInterface> const & xStartingPoint)
+ :IndexAccessIterator(xStartingPoint)
+{
+}
+
+
+bool SearchableControlIterator::ShouldHandleElement(const Reference< XInterface>& xElement)
+{
+ // if the thing has a ControlSource and a BoundField property
+ Reference< XPropertySet> xProperties(xElement, UNO_QUERY);
+ if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties))
+ {
+ // and the BoundField is valid
+ Reference< XPropertySet> xField;
+ xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
+ if (xField.is())
+ {
+ // we take it
+ m_sCurrentValue = ::comphelper::getString(xProperties->getPropertyValue(FM_PROP_CONTROLSOURCE));
+ return true;
+ }
+ }
+
+ // if it is a grid control
+ if (::comphelper::hasProperty(FM_PROP_CLASSID, xProperties))
+ {
+ Any aClassId( xProperties->getPropertyValue(FM_PROP_CLASSID) );
+ if (::comphelper::getINT16(aClassId) == FormComponentType::GRIDCONTROL)
+ {
+ m_sCurrentValue.clear();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool SearchableControlIterator::ShouldStepInto(const Reference< XInterface>& /*xContainer*/) const
+{
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmsrccfg.cxx b/svx/source/form/fmsrccfg.cxx
new file mode 100644
index 000000000..499d2cb16
--- /dev/null
+++ b/svx/source/form/fmsrccfg.cxx
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/fmsrccfg.hxx>
+
+#include <sal/log.hxx>
+#include <comphelper/processfactory.hxx>
+#include <i18nutil/transliteration.hxx>
+
+using namespace ::com::sun::star::uno;
+
+namespace svxform
+{
+ // search parameters
+
+ FmSearchParams::FmSearchParams()
+ :nTransliterationFlags( TransliterationFlags::NONE )
+ ,nSearchForType ( 0 )
+ ,nPosition ( MATCHING_ANYWHERE )
+ ,nLevOther ( 2 )
+ ,nLevShorter ( 2 )
+ ,nLevLonger ( 2 )
+ ,bLevRelaxed ( true )
+ ,bAllFields ( false )
+ ,bUseFormatter ( true )
+ ,bBackwards ( false )
+ ,bWildcard ( false )
+ ,bRegular ( false )
+ ,bApproxSearch ( false )
+ ,bSoundsLikeCJK ( false )
+ {
+ nTransliterationFlags =
+ TransliterationFlags::ignoreSpace_ja_JP
+ | TransliterationFlags::ignoreMiddleDot_ja_JP
+ | TransliterationFlags::ignoreProlongedSoundMark_ja_JP
+ | TransliterationFlags::ignoreSeparator_ja_JP
+ | TransliterationFlags::IGNORE_CASE;
+ }
+
+ bool FmSearchParams::isIgnoreWidthCJK( ) const
+ {
+ return bool(nTransliterationFlags & TransliterationFlags::IGNORE_WIDTH);
+ }
+
+ bool FmSearchParams::isCaseSensitive( ) const
+ {
+ return !(nTransliterationFlags & TransliterationFlags::IGNORE_CASE);
+ }
+
+ void FmSearchParams::setCaseSensitive( bool _bCase )
+ {
+ if ( _bCase )
+ nTransliterationFlags &= ~TransliterationFlags::IGNORE_CASE;
+ else
+ nTransliterationFlags |= TransliterationFlags::IGNORE_CASE;
+ }
+
+ // maps from ascii values to int values
+
+ namespace {
+
+ struct Ascii2Int16
+ {
+ const char* pAscii;
+ sal_Int16 nValue;
+ };
+
+ }
+
+ static const Ascii2Int16* lcl_getSearchForTypeValueMap()
+ {
+ static const Ascii2Int16 s_aSearchForTypeMap[] =
+ {
+ { "text", 0 },
+ { "null", 1 },
+ { "non-null", 2 },
+ { nullptr, -1 }
+ };
+ return s_aSearchForTypeMap;
+ }
+
+ static const Ascii2Int16* lcl_getSearchPositionValueMap()
+ {
+ static const Ascii2Int16 s_aSearchPositionMap[] =
+ {
+ { "anywhere-in-field", MATCHING_ANYWHERE },
+ { "beginning-of-field", MATCHING_BEGINNING },
+ { "end-of-field", MATCHING_END },
+ { "complete-field", MATCHING_WHOLETEXT },
+ { nullptr, -1 }
+ };
+ return s_aSearchPositionMap;
+ }
+
+ static sal_Int16 lcl_implMapAsciiValue( const OUString& _rAsciiValue, const Ascii2Int16* _pMap )
+ {
+ // search the map for the given ascii value
+ const Ascii2Int16* pSearch = _pMap;
+ while ( pSearch && pSearch->pAscii )
+ {
+ if ( _rAsciiValue.equalsAscii( pSearch->pAscii ) )
+ // found
+ return pSearch->nValue;
+ ++pSearch;
+ }
+
+ SAL_WARN(
+ "svx.form", "could not convert the ascii value " << _rAsciiValue);
+ return -1;
+ }
+
+ static const char* lcl_implMapIntValue( const sal_Int16 _nValue, const Ascii2Int16* _pMap )
+ {
+ // search the map for the given integer value
+ const Ascii2Int16* pSearch = _pMap;
+ while ( pSearch && pSearch->pAscii )
+ {
+ if ( _nValue == pSearch->nValue )
+ // found
+ return pSearch->pAscii;
+ ++pSearch;
+ }
+
+ SAL_WARN( "svx", "lcl_implMapIntValue: could not convert the integer value "
+ << _nValue << " !");
+ static const char* const s_pDummy = "";
+ // just as a fallback...
+ return s_pDummy;
+ }
+
+ // class FmSearchConfigItem - a config item that stores search parameters
+
+#define TA( c ) &c, cppu::UnoType<decltype(c)>::get()
+
+ FmSearchConfigItem::FmSearchConfigItem()
+ :OConfigurationValueContainer( ::comphelper::getProcessComponentContext(), m_aMutex, "/org.openoffice.Office.DataAccess/FormSearchOptions", 2 )
+ {
+ // register our members so the data exchange with the node values is done automatically
+
+ registerExchangeLocation( "SearchHistory", TA( aHistory ) );
+ registerExchangeLocation( "LevenshteinOther", TA( nLevOther ) );
+ registerExchangeLocation( "LevenshteinShorter", TA( nLevShorter ) );
+ registerExchangeLocation( "LevenshteinLonger", TA( nLevLonger ) );
+ registerExchangeLocation( "IsLevenshteinRelaxed", TA( bLevRelaxed ) );
+ registerExchangeLocation( "IsSearchAllFields", TA( bAllFields ) );
+ registerExchangeLocation( "IsUseFormatter", TA( bUseFormatter ) );
+ registerExchangeLocation( "IsBackwards", TA( bBackwards ) );
+ registerExchangeLocation( "IsWildcardSearch", TA( bWildcard ) );
+ registerExchangeLocation( "IsUseRegularExpression", TA( bRegular ) );
+ registerExchangeLocation( "IsSimilaritySearch", TA( bApproxSearch ) );
+ registerExchangeLocation( "IsUseAsianOptions", TA( bSoundsLikeCJK ) );
+
+ // the properties which need to be translated
+ registerExchangeLocation( "SearchType", TA( m_sSearchForType ) );
+ registerExchangeLocation( "SearchPosition", TA( m_sSearchPosition ) );
+
+ registerExchangeLocation( "IsMatchCase", TA( m_bIsMatchCase ) );
+ registerExchangeLocation( "Japanese/IsMatchFullHalfWidthForms", TA( m_bIsMatchFullHalfWidthForms ) );
+ registerExchangeLocation( "Japanese/IsMatchHiraganaKatakana", TA( m_bIsMatchHiraganaKatakana ) );
+ registerExchangeLocation( "Japanese/IsMatchContractions", TA( m_bIsMatchContractions ) );
+ registerExchangeLocation( "Japanese/IsMatchMinusDashCho-on", TA( m_bIsMatchMinusDashCho_on ) );
+ registerExchangeLocation( "Japanese/IsMatchRepeatCharMarks", TA( m_bIsMatchRepeatCharMarks ) );
+ registerExchangeLocation( "Japanese/IsMatchVariantFormKanji", TA( m_bIsMatchVariantFormKanji ) );
+ registerExchangeLocation( "Japanese/IsMatchOldKanaForms", TA( m_bIsMatchOldKanaForms ) );
+ registerExchangeLocation( "Japanese/IsMatch_DiZi_DuZu", TA( m_bIsMatch_DiZi_DuZu ) );
+ registerExchangeLocation( "Japanese/IsMatch_BaVa_HaFa", TA( m_bIsMatch_BaVa_HaFa ) );
+ registerExchangeLocation( "Japanese/IsMatch_TsiThiChi_DhiZi", TA( m_bIsMatch_TsiThiChi_DhiZi ) );
+ registerExchangeLocation( "Japanese/IsMatch_HyuIyu_ByuVyu", TA( m_bIsMatch_HyuIyu_ByuVyu ) );
+ registerExchangeLocation( "Japanese/IsMatch_SeShe_ZeJe", TA( m_bIsMatch_SeShe_ZeJe ) );
+ registerExchangeLocation( "Japanese/IsMatch_IaIya", TA( m_bIsMatch_IaIya ) );
+ registerExchangeLocation( "Japanese/IsMatch_KiKu", TA( m_bIsMatch_KiKu ) );
+ registerExchangeLocation( "Japanese/IsIgnorePunctuation", TA( m_bIsIgnorePunctuation ) );
+ registerExchangeLocation( "Japanese/IsIgnoreWhitespace", TA( m_bIsIgnoreWhitespace ) );
+ registerExchangeLocation( "Japanese/IsIgnoreProlongedSoundMark",TA( m_bIsIgnoreProlongedSoundMark ) );
+ registerExchangeLocation( "Japanese/IsIgnoreMiddleDot", TA( m_bIsIgnoreMiddleDot ) );
+
+ read( );
+ }
+
+ FmSearchConfigItem::~FmSearchConfigItem()
+ {
+ commit( );
+ }
+
+ void FmSearchConfigItem::implTranslateFromConfig( )
+ {
+ // the search-for string
+ nSearchForType = lcl_implMapAsciiValue( m_sSearchForType, lcl_getSearchForTypeValueMap() );
+
+ // the search position
+ nPosition = lcl_implMapAsciiValue( m_sSearchPosition, lcl_getSearchPositionValueMap() );
+
+ // the transliteration flags
+ nTransliterationFlags = TransliterationFlags::NONE;
+
+ if ( !m_bIsMatchCase ) nTransliterationFlags |= TransliterationFlags::IGNORE_CASE;
+ if ( m_bIsMatchFullHalfWidthForms ) nTransliterationFlags |= TransliterationFlags::IGNORE_WIDTH;
+ if ( m_bIsMatchHiraganaKatakana ) nTransliterationFlags |= TransliterationFlags::IGNORE_KANA;
+ if ( m_bIsMatchContractions ) nTransliterationFlags |= TransliterationFlags::ignoreSize_ja_JP;
+ if ( m_bIsMatchMinusDashCho_on ) nTransliterationFlags |= TransliterationFlags::ignoreMinusSign_ja_JP;
+ if ( m_bIsMatchRepeatCharMarks ) nTransliterationFlags |= TransliterationFlags::ignoreIterationMark_ja_JP;
+ if ( m_bIsMatchVariantFormKanji ) nTransliterationFlags |= TransliterationFlags::ignoreTraditionalKanji_ja_JP;
+ if ( m_bIsMatchOldKanaForms ) nTransliterationFlags |= TransliterationFlags::ignoreTraditionalKana_ja_JP;
+ if ( m_bIsMatch_DiZi_DuZu ) nTransliterationFlags |= TransliterationFlags::ignoreZiZu_ja_JP;
+ if ( m_bIsMatch_BaVa_HaFa ) nTransliterationFlags |= TransliterationFlags::ignoreBaFa_ja_JP;
+ if ( m_bIsMatch_TsiThiChi_DhiZi ) nTransliterationFlags |= TransliterationFlags::ignoreTiJi_ja_JP;
+ if ( m_bIsMatch_HyuIyu_ByuVyu ) nTransliterationFlags |= TransliterationFlags::ignoreHyuByu_ja_JP;
+ if ( m_bIsMatch_SeShe_ZeJe ) nTransliterationFlags |= TransliterationFlags::ignoreSeZe_ja_JP;
+ if ( m_bIsMatch_IaIya ) nTransliterationFlags |= TransliterationFlags::ignoreIandEfollowedByYa_ja_JP;
+ if ( m_bIsMatch_KiKu ) nTransliterationFlags |= TransliterationFlags::ignoreKiKuFollowedBySa_ja_JP;
+
+ if ( m_bIsIgnorePunctuation ) nTransliterationFlags |= TransliterationFlags::ignoreSeparator_ja_JP;
+ if ( m_bIsIgnoreWhitespace ) nTransliterationFlags |= TransliterationFlags::ignoreSpace_ja_JP;
+ if ( m_bIsIgnoreProlongedSoundMark ) nTransliterationFlags |= TransliterationFlags::ignoreProlongedSoundMark_ja_JP;
+ if ( m_bIsIgnoreMiddleDot ) nTransliterationFlags |= TransliterationFlags::ignoreMiddleDot_ja_JP;
+ }
+
+ void FmSearchConfigItem::implTranslateToConfig( )
+ {
+ // the search-for string
+ m_sSearchForType = OUString::createFromAscii( lcl_implMapIntValue( nSearchForType, lcl_getSearchForTypeValueMap() ) );
+
+ // the search position
+ m_sSearchPosition = OUString::createFromAscii( lcl_implMapIntValue( nPosition, lcl_getSearchPositionValueMap() ) );
+
+ // the transliteration flags
+
+ m_bIsMatchCase = !( nTransliterationFlags & TransliterationFlags::IGNORE_CASE );
+ m_bIsMatchFullHalfWidthForms = bool( nTransliterationFlags & TransliterationFlags::IGNORE_WIDTH );
+ m_bIsMatchHiraganaKatakana = bool( nTransliterationFlags & TransliterationFlags::IGNORE_KANA );
+ m_bIsMatchContractions = bool( nTransliterationFlags & TransliterationFlags::ignoreSize_ja_JP );
+ m_bIsMatchMinusDashCho_on = bool( nTransliterationFlags & TransliterationFlags::ignoreMinusSign_ja_JP );
+ m_bIsMatchRepeatCharMarks = bool( nTransliterationFlags & TransliterationFlags::ignoreIterationMark_ja_JP );
+ m_bIsMatchVariantFormKanji = bool( nTransliterationFlags & TransliterationFlags::ignoreTraditionalKanji_ja_JP );
+ m_bIsMatchOldKanaForms = bool( nTransliterationFlags & TransliterationFlags::ignoreTraditionalKana_ja_JP );
+ m_bIsMatch_DiZi_DuZu = bool( nTransliterationFlags & TransliterationFlags::ignoreZiZu_ja_JP );
+ m_bIsMatch_BaVa_HaFa = bool( nTransliterationFlags & TransliterationFlags::ignoreBaFa_ja_JP );
+ m_bIsMatch_TsiThiChi_DhiZi = bool( nTransliterationFlags & TransliterationFlags::ignoreTiJi_ja_JP );
+ m_bIsMatch_HyuIyu_ByuVyu = bool( nTransliterationFlags & TransliterationFlags::ignoreHyuByu_ja_JP );
+ m_bIsMatch_SeShe_ZeJe = bool( nTransliterationFlags & TransliterationFlags::ignoreSeZe_ja_JP );
+ m_bIsMatch_IaIya = bool( nTransliterationFlags & TransliterationFlags::ignoreIandEfollowedByYa_ja_JP );
+ m_bIsMatch_KiKu = bool( nTransliterationFlags & TransliterationFlags::ignoreKiKuFollowedBySa_ja_JP );
+
+ m_bIsIgnorePunctuation = bool( nTransliterationFlags & TransliterationFlags::ignoreSeparator_ja_JP );
+ m_bIsIgnoreWhitespace = bool( nTransliterationFlags & TransliterationFlags::ignoreSpace_ja_JP );
+ m_bIsIgnoreProlongedSoundMark = bool( nTransliterationFlags & TransliterationFlags::ignoreProlongedSoundMark_ja_JP );
+ m_bIsIgnoreMiddleDot = bool( nTransliterationFlags & TransliterationFlags::ignoreMiddleDot_ja_JP );
+ }
+
+ const FmSearchParams& FmSearchConfigItem::getParams() const
+ {
+ // ensure that the properties which are not stored directly are up-to-date
+ const_cast< FmSearchConfigItem* >( this )->implTranslateFromConfig( );
+
+ // and return our FmSearchParams part
+ return *this;
+ }
+
+ void FmSearchConfigItem::setParams( const FmSearchParams& _rParams )
+ {
+ // copy the FmSearchParams part
+ *static_cast< FmSearchParams* >( this ) = _rParams;
+
+ // translate the settings not represented by a direct config value
+ implTranslateToConfig();
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmsrcimp.cxx b/svx/source/form/fmsrcimp.cxx
new file mode 100644
index 000000000..6ebd99c93
--- /dev/null
+++ b/svx/source/form/fmsrcimp.cxx
@@ -0,0 +1,1058 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <svx/fmtools.hxx>
+#include <svx/fmsrccfg.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/wldcrd.hxx>
+#include <vcl/svapp.hxx>
+#include <unotools/textsearch.hxx>
+#include <com/sun/star/awt/XTextComponent.hpp>
+#include <com/sun/star/awt/XListBox.hpp>
+#include <com/sun/star/awt/XCheckBox.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/util/SearchAlgorithms2.hpp>
+#include <com/sun/star/util/SearchFlags.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/i18n/CollatorOptions.hpp>
+
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+
+#include <fmprop.hxx>
+#include <svx/fmsrcimp.hxx>
+
+#include <comphelper/types.hxx>
+#include <unotools/syslocale.hxx>
+#include <i18nutil/searchopt.hxx>
+
+#define EQUAL_BOOKMARKS(a, b) a == b
+
+#define IFACECAST(c) static_cast<const Reference< XInterface >&>(c)
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::beans;
+using namespace ::svxform;
+
+
+// = FmRecordCountListener
+
+// SMART_UNO_IMPLEMENTATION(FmRecordCountListener, UsrObject);
+
+
+FmRecordCountListener::FmRecordCountListener(const Reference< css::sdbc::XResultSet > & dbcCursor)
+{
+
+ m_xListening.set(dbcCursor, UNO_QUERY);
+ if (!m_xListening.is())
+ return;
+
+ if (::comphelper::getBOOL(m_xListening->getPropertyValue(FM_PROP_ROWCOUNTFINAL)))
+ {
+ m_xListening = nullptr;
+ // there's nothing to do as the record count is already known
+ return;
+ }
+
+ m_xListening->addPropertyChangeListener(FM_PROP_ROWCOUNT, static_cast<css::beans::XPropertyChangeListener*>(this));
+}
+
+
+void FmRecordCountListener::SetPropChangeHandler(const Link<sal_Int32,void>& lnk)
+{
+ m_lnkWhoWantsToKnow = lnk;
+
+ if (m_xListening.is())
+ NotifyCurrentCount();
+}
+
+
+FmRecordCountListener::~FmRecordCountListener()
+{
+
+}
+
+
+void FmRecordCountListener::DisConnect()
+{
+ if(m_xListening.is())
+ m_xListening->removePropertyChangeListener(FM_PROP_ROWCOUNT, static_cast<css::beans::XPropertyChangeListener*>(this));
+ m_xListening = nullptr;
+}
+
+
+void SAL_CALL FmRecordCountListener::disposing(const css::lang::EventObject& /*Source*/)
+{
+ DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::disposing should never have been called without a propset !");
+ DisConnect();
+}
+
+
+void FmRecordCountListener::NotifyCurrentCount()
+{
+ if (m_lnkWhoWantsToKnow.IsSet())
+ {
+ DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::NotifyCurrentCount : I have no propset ... !?");
+ sal_Int32 theCount = ::comphelper::getINT32(m_xListening->getPropertyValue(FM_PROP_ROWCOUNT));
+ m_lnkWhoWantsToKnow.Call(theCount);
+ }
+}
+
+
+void FmRecordCountListener::propertyChange(const css::beans::PropertyChangeEvent& /*evt*/)
+{
+ NotifyCurrentCount();
+}
+
+
+// FmSearchEngine - local classes
+
+SimpleTextWrapper::SimpleTextWrapper(const Reference< css::awt::XTextComponent > & _xText)
+ :ControlTextWrapper(_xText)
+ ,m_xText(_xText)
+{
+ DBG_ASSERT(m_xText.is(), "FmSearchEngine::SimpleTextWrapper::SimpleTextWrapper : invalid argument !");
+}
+
+
+OUString SimpleTextWrapper::getCurrentText() const
+{
+ return m_xText->getText();
+}
+
+
+ListBoxWrapper::ListBoxWrapper(const Reference< css::awt::XListBox > & _xBox)
+ :ControlTextWrapper(_xBox)
+ ,m_xBox(_xBox)
+{
+ DBG_ASSERT(m_xBox.is(), "FmSearchEngine::ListBoxWrapper::ListBoxWrapper : invalid argument !");
+}
+
+
+OUString ListBoxWrapper::getCurrentText() const
+{
+ return m_xBox->getSelectedItem();
+}
+
+
+CheckBoxWrapper::CheckBoxWrapper(const Reference< css::awt::XCheckBox > & _xBox)
+ :ControlTextWrapper(_xBox)
+ ,m_xBox(_xBox)
+{
+ DBG_ASSERT(m_xBox.is(), "FmSearchEngine::CheckBoxWrapper::CheckBoxWrapper : invalid argument !");
+}
+
+
+OUString CheckBoxWrapper::getCurrentText() const
+{
+ switch (static_cast<TriState>(m_xBox->getState()))
+ {
+ case TRISTATE_FALSE: return "0";
+ case TRISTATE_TRUE: return "1";
+ default: break;
+ }
+ return OUString();
+}
+
+
+// = FmSearchEngine
+
+bool FmSearchEngine::MoveCursor()
+{
+ bool bSuccess = true;
+ try
+ {
+ if (m_bForward)
+ if (m_xSearchCursor.isLast())
+ m_xSearchCursor.first();
+ else
+ m_xSearchCursor.next();
+ else
+ if (m_xSearchCursor.isFirst())
+ {
+ rtl::Reference<FmRecordCountListener> prclListener = new FmRecordCountListener(m_xSearchCursor);
+ prclListener->SetPropChangeHandler(LINK(this, FmSearchEngine, OnNewRecordCount));
+
+ m_xSearchCursor.last();
+
+ prclListener->DisConnect();
+ }
+ else
+ m_xSearchCursor.previous();
+ }
+ catch(Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmSearchEngine::MoveCursor");
+ bSuccess = false;
+ }
+ catch(...)
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmSearchEngine::MoveCursor : caught an unknown Exception !");
+ bSuccess = false;
+ }
+
+ return bSuccess;
+}
+
+
+bool FmSearchEngine::MoveField(sal_Int32& nPos, FieldCollection::iterator& iter, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
+{
+ bool bSuccess(true);
+ if (m_bForward)
+ {
+ ++iter;
+ ++nPos;
+ if (iter == iterEnd)
+ {
+ bSuccess = MoveCursor();
+ iter = iterBegin;
+ nPos = 0;
+ }
+ } else
+ {
+ if (iter == iterBegin)
+ {
+ bSuccess = MoveCursor();
+ iter = iterEnd;
+ nPos = iter-iterBegin;
+ }
+ --iter;
+ --nPos;
+ }
+ return bSuccess;
+}
+
+
+void FmSearchEngine::BuildAndInsertFieldInfo(const Reference< css::container::XIndexAccess > & xAllFields, sal_Int32 nField)
+{
+ DBG_ASSERT( xAllFields.is() && ( nField >= 0 ) && ( nField < xAllFields->getCount() ),
+ "FmSearchEngine::BuildAndInsertFieldInfo: invalid field descriptor!" );
+
+ // the field itself
+ Reference< XInterface > xCurrentField;
+ xAllFields->getByIndex(nField) >>= xCurrentField;
+
+ // From this I now know that it supports the DatabaseRecord service (I hope).
+ // For the FormatKey and the type I need the PropertySet.
+ Reference< css::beans::XPropertySet > xProperties(xCurrentField, UNO_QUERY_THROW);
+
+ // build the FieldInfo for that
+ FieldInfo fiCurrent;
+ fiCurrent.xContents.set(xCurrentField, UNO_QUERY);
+
+ // and memorize
+ m_arrUsedFields.insert(m_arrUsedFields.end(), fiCurrent);
+
+}
+
+OUString FmSearchEngine::FormatField(sal_Int32 nWhich)
+{
+ DBG_ASSERT(o3tl::make_unsigned(nWhich) < m_aControlTexts.size(), "FmSearchEngine::FormatField(sal_Int32) : invalid position !");
+ DBG_ASSERT(m_aControlTexts[nWhich], "FmSearchEngine::FormatField(sal_Int32) : invalid object in array !");
+ DBG_ASSERT(m_aControlTexts[nWhich]->getControl().is(), "FmSearchEngine::FormatField : invalid control !");
+
+ if (m_nCurrentFieldIndex != -1)
+ {
+ DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : parameter nWhich is invalid");
+ // analogous situation as below
+ nWhich = m_nCurrentFieldIndex;
+ }
+
+ DBG_ASSERT((nWhich >= 0) && (o3tl::make_unsigned(nWhich) < m_aControlTexts.size()),
+ "FmSearchEngine::FormatField : invalid argument nWhich !");
+ return m_aControlTexts[m_nCurrentFieldIndex == -1 ? nWhich : m_nCurrentFieldIndex]->getCurrentText();
+}
+
+
+FmSearchEngine::SearchResult FmSearchEngine::SearchSpecial(bool _bSearchForNull, sal_Int32& nFieldPos,
+ FieldCollection::iterator& iterFieldLoop, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
+{
+ // memorize the start position
+ Any aStartMark;
+ try { aStartMark = m_xSearchCursor.getBookmark(); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
+ FieldCollection::const_iterator iterInitialField = iterFieldLoop;
+
+
+ bool bFound(false);
+ bool bMovedAround(false);
+ do
+ {
+ Application::Reschedule( true );
+
+ // the content to be compared currently
+ iterFieldLoop->xContents->getString(); // needed for wasNull
+ bFound = _bSearchForNull == bool(iterFieldLoop->xContents->wasNull());
+ if (bFound)
+ break;
+
+ // next field (implicitly next record, if necessary)
+ if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
+ { // When moving to the next field, something went wrong...
+ // Continuing is not possible, since the next time exactly the same
+ // will definitely go wrong again, thus abort.
+ // Before, however, so that the search continues at the current position:
+ try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); }
+ m_iterPreviousLocField = iterFieldLoop;
+ // and leave
+ return SearchResult::Error;
+ }
+
+ Any aCurrentBookmark;
+ try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
+
+ bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
+
+ if (nFieldPos == 0)
+ // that is, I've moved to a new record
+ PropagateProgress(bMovedAround);
+ // if we moved to the starting position we don't have to propagate an 'overflow' message
+ // FS - 07.12.99 - 68530
+
+ // cancel requested?
+ if (CancelRequested())
+ return SearchResult::Cancelled;
+
+ } while (!bMovedAround);
+
+ return bFound ? SearchResult::Found : SearchResult::NotFound;
+}
+
+
+FmSearchEngine::SearchResult FmSearchEngine::SearchWildcard(std::u16string_view strExpression, sal_Int32& nFieldPos,
+ FieldCollection::iterator& iterFieldLoop, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
+{
+ // memorize the start position
+ Any aStartMark;
+ try { aStartMark = m_xSearchCursor.getBookmark(); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
+ FieldCollection::const_iterator iterInitialField = iterFieldLoop;
+
+ WildCard aSearchExpression(strExpression);
+
+
+ bool bFound(false);
+ bool bMovedAround(false);
+ do
+ {
+ Application::Reschedule( true );
+
+ // the content to be compared currently
+ OUString sCurrentCheck;
+ if (m_bFormatter)
+ sCurrentCheck = FormatField(nFieldPos);
+ else
+ sCurrentCheck = iterFieldLoop->xContents->getString();
+
+ if (!GetCaseSensitive())
+ // norm the string
+ sCurrentCheck = m_aCharacterClassficator.lowercase(sCurrentCheck);
+
+ // now the test is easy...
+ bFound = aSearchExpression.Matches(sCurrentCheck);
+
+ if (bFound)
+ break;
+
+ // next field (implicitly next record, if necessary)
+ if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
+ { // When moving to the next field, something went wrong...
+ // Continuing is not possible, since the next time exactly the same
+ // will definitely go wrong again, thus abort.
+ // Before, however, so that the search continues at the current position:
+ try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); }
+ m_iterPreviousLocField = iterFieldLoop;
+ // and leave
+ return SearchResult::Error;
+ }
+
+ Any aCurrentBookmark;
+ try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
+
+ bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
+
+ if (nFieldPos == 0)
+ // that is, I've moved to a new record
+ PropagateProgress(bMovedAround);
+ // if we moved to the starting position we don't have to propagate an 'overflow' message
+ // FS - 07.12.99 - 68530
+
+ // cancel requested?
+ if (CancelRequested())
+ return SearchResult::Cancelled;
+
+ } while (!bMovedAround);
+
+ return bFound ? SearchResult::Found : SearchResult::NotFound;
+}
+
+
+FmSearchEngine::SearchResult FmSearchEngine::SearchRegularApprox(const OUString& strExpression, sal_Int32& nFieldPos,
+ FieldCollection::iterator& iterFieldLoop, const FieldCollection::iterator& iterBegin, const FieldCollection::iterator& iterEnd)
+{
+ DBG_ASSERT(m_bLevenshtein || m_bRegular,
+ "FmSearchEngine::SearchRegularApprox : invalid search mode!");
+ DBG_ASSERT(!m_bLevenshtein || !m_bRegular,
+ "FmSearchEngine::SearchRegularApprox : cannot search for regular expressions and similarities at the same time!");
+
+ // memorize start position
+ Any aStartMark;
+ try { aStartMark = m_xSearchCursor.getBookmark(); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
+ FieldCollection::const_iterator iterInitialField = iterFieldLoop;
+
+ // collect parameters
+ i18nutil::SearchOptions2 aParam;
+ aParam.AlgorithmType2 = m_bRegular ? SearchAlgorithms2::REGEXP : SearchAlgorithms2::APPROXIMATE;
+ aParam.searchFlag = 0;
+ aParam.transliterateFlags = GetTransliterationFlags();
+ if ( !GetTransliteration() )
+ { // if transliteration is not enabled, the only flags which matter are IGNORE_CASE and IGNORE_WIDTH
+ aParam.transliterateFlags &= TransliterationFlags::IGNORE_CASE | TransliterationFlags::IGNORE_WIDTH;
+ }
+ if (m_bLevenshtein)
+ {
+ if (m_bLevRelaxed)
+ aParam.searchFlag |= SearchFlags::LEV_RELAXED;
+ aParam.changedChars = m_nLevOther;
+ aParam.deletedChars = m_nLevShorter;
+ aParam.insertedChars = m_nLevLonger;
+ }
+ aParam.searchString = strExpression;
+ aParam.Locale = SvtSysLocale().GetLanguageTag().getLocale();
+ ::utl::TextSearch aLocalEngine( aParam);
+
+
+ bool bFound = false;
+ bool bMovedAround(false);
+ do
+ {
+ Application::Reschedule( true );
+
+ // the content to be compared currently
+ OUString sCurrentCheck;
+ if (m_bFormatter)
+ sCurrentCheck = FormatField(nFieldPos);
+ else
+ sCurrentCheck = iterFieldLoop->xContents->getString();
+
+ // (don't care about case here, this is done by the TextSearch object, 'cause we passed our case parameter to it)
+
+ sal_Int32 nStart = 0, nEnd = sCurrentCheck.getLength();
+ bFound = aLocalEngine.SearchForward(sCurrentCheck, &nStart, &nEnd);
+ // it says 'forward' here, but that only refers to the search within
+ // sCurrentCheck, so it has nothing to do with the direction of my
+ // record migration (MoveField takes care of that)
+
+ // check if the position is correct
+ if (bFound)
+ {
+ switch (m_nPosition)
+ {
+ case MATCHING_WHOLETEXT :
+ if (nEnd != sCurrentCheck.getLength())
+ {
+ bFound = false;
+ break;
+ }
+ [[fallthrough]];
+ case MATCHING_BEGINNING :
+ if (nStart != 0)
+ bFound = false;
+ break;
+ case MATCHING_END :
+ if (nEnd != sCurrentCheck.getLength())
+ bFound = false;
+ break;
+ }
+ }
+
+ if (bFound) // still?
+ break;
+
+ // next field (implicitly next record, if necessary)
+ if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd))
+ { // When moving to the next field, something went wrong...
+ // Continuing is not possible, since the next time exactly the same
+ // will definitely go wrong again, thus abort (without error
+ // notification, I expect it to be displayed in the Move).
+ // Before, however, so that the search continues at the current position:
+ try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); }
+ m_iterPreviousLocField = iterFieldLoop;
+ // and leave
+ return SearchResult::Error;
+ }
+
+ Any aCurrentBookmark;
+ try { aCurrentBookmark = m_xSearchCursor.getBookmark(); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); return SearchResult::Error; }
+ bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField);
+
+ if (nFieldPos == 0)
+ // that is, I've moved to a new record
+ PropagateProgress(bMovedAround);
+ // if we moved to the starting position we don't have to propagate an 'overflow' message
+ // FS - 07.12.99 - 68530
+
+ // cancel requested?
+ if (CancelRequested())
+ return SearchResult::Cancelled;
+
+ } while (!bMovedAround);
+
+ return bFound ? SearchResult::Found : SearchResult::NotFound;
+}
+
+
+FmSearchEngine::FmSearchEngine(const Reference< XComponentContext >& _rxContext,
+ const Reference< XResultSet > & xCursor, std::u16string_view sVisibleFields,
+ const InterfaceArray& arrFields)
+ :m_xSearchCursor(xCursor)
+ ,m_aCharacterClassficator( _rxContext, SvtSysLocale().GetLanguageTag() )
+ ,m_aStringCompare( _rxContext )
+ ,m_nCurrentFieldIndex(-2) // -1 already has a meaning, so I take -2 for 'invalid'
+ ,m_xOriginalIterator(xCursor)
+ ,m_xClonedIterator(m_xOriginalIterator, true)
+ ,m_eSearchForType(SearchFor::String)
+ ,m_srResult(SearchResult::Found)
+ ,m_bCancelAsynchRequest(false)
+ ,m_bSearchingCurrently(false)
+ ,m_bFormatter(true) // this must be consistent with m_xSearchCursor, which is generally == m_xOriginalIterator
+ ,m_bForward(false)
+ ,m_bWildcard(false)
+ ,m_bRegular(false)
+ ,m_bLevenshtein(false)
+ ,m_bTransliteration(false)
+ ,m_bLevRelaxed(false)
+ ,m_nLevOther(0)
+ ,m_nLevShorter(0)
+ ,m_nLevLonger(0)
+ ,m_nPosition(MATCHING_ANYWHERE)
+ ,m_nTransliterationFlags(TransliterationFlags::NONE)
+{
+
+ fillControlTexts(arrFields);
+ Init(sVisibleFields);
+}
+
+
+void FmSearchEngine::SetIgnoreWidthCJK(bool bSet)
+{
+ if (bSet)
+ m_nTransliterationFlags |= TransliterationFlags::IGNORE_WIDTH;
+ else
+ m_nTransliterationFlags &= ~TransliterationFlags::IGNORE_WIDTH;
+}
+
+
+bool FmSearchEngine::GetIgnoreWidthCJK() const
+{
+ return bool(m_nTransliterationFlags & TransliterationFlags::IGNORE_WIDTH);
+}
+
+
+void FmSearchEngine::SetCaseSensitive(bool bSet)
+{
+ if (bSet)
+ m_nTransliterationFlags &= ~TransliterationFlags::IGNORE_CASE;
+ else
+ m_nTransliterationFlags |= TransliterationFlags::IGNORE_CASE;
+}
+
+
+bool FmSearchEngine::GetCaseSensitive() const
+{
+ return !(m_nTransliterationFlags & TransliterationFlags::IGNORE_CASE);
+}
+
+
+void FmSearchEngine::fillControlTexts(const InterfaceArray& arrFields)
+{
+ m_aControlTexts.clear();
+ Reference< XInterface > xCurrent;
+ for (const auto & rField : arrFields)
+ {
+ xCurrent = rField;
+ DBG_ASSERT(xCurrent.is(), "FmSearchEngine::fillControlTexts : invalid field interface !");
+ // check which type of control this is
+ Reference< css::awt::XTextComponent > xAsText(xCurrent, UNO_QUERY);
+ if (xAsText.is())
+ {
+ m_aControlTexts.emplace_back(new SimpleTextWrapper(xAsText));
+ continue;
+ }
+
+ Reference< css::awt::XListBox > xAsListBox(xCurrent, UNO_QUERY);
+ if (xAsListBox.is())
+ {
+ m_aControlTexts.emplace_back(new ListBoxWrapper(xAsListBox));
+ continue;
+ }
+
+ Reference< css::awt::XCheckBox > xAsCheckBox(xCurrent, UNO_QUERY);
+ DBG_ASSERT(xAsCheckBox.is(), "FmSearchEngine::fillControlTexts : invalid field interface (no supported type) !");
+ // we don't have any more options ...
+ m_aControlTexts.emplace_back(new CheckBoxWrapper(xAsCheckBox));
+ }
+}
+
+
+void FmSearchEngine::Init(std::u16string_view sVisibleFields)
+{
+ // analyze the fields
+ // additionally, create the mapping: because the list of used columns can be shorter than the list
+ // of columns of the cursor, we need a mapping: "used column number n" -> "cursor column m"
+ m_arrFieldMapping.clear();
+
+ // important: The case of the columns does not need to be exact - for instance:
+ // - a user created a form which works on a table, for which the driver returns a column name "COLUMN"
+ // - the driver itself works case-insensitive with column names
+ // - a control in the form is bound to "column" - not the different case
+ // In such a scenario, the form and the field would work okay, but we here need to case for the different case
+ // explicitly
+ // #i8755#
+
+ // so first of all, check if the database handles identifiers case sensitive
+ Reference< XConnection > xConn;
+ Reference< XDatabaseMetaData > xMeta;
+ Reference< XPropertySet > xCursorProps( IFACECAST( m_xSearchCursor ), UNO_QUERY );
+ if ( xCursorProps.is() )
+ {
+ try
+ {
+ xCursorProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xConn;
+ }
+ catch( const Exception& ) { /* silent this - will be asserted below */ }
+ }
+ if ( xConn.is() )
+ xMeta = xConn->getMetaData();
+ OSL_ENSURE( xMeta.is(), "FmSearchEngine::Init: very strange cursor (could not derive connection meta data from it)!" );
+
+ bool bCaseSensitiveIdentifiers = true; // assume case sensitivity
+ if ( xMeta.is() )
+ bCaseSensitiveIdentifiers = xMeta->supportsMixedCaseQuotedIdentifiers();
+
+ // now that we have this information, we need a collator which is able to case (in)sensitivity compare strings
+ m_aStringCompare.loadDefaultCollator( SvtSysLocale().GetLanguageTag().getLocale(),
+ bCaseSensitiveIdentifiers ? 0 : css::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE );
+
+ try
+ {
+ // the cursor can give me a record (as PropertySet), which supports the DatabaseRecord service
+ Reference< css::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
+ DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::Init : invalid cursor (no columns supplier) !");
+ Reference< css::container::XNameAccess > xAllFieldNames = xSupplyCols->getColumns();
+ const Sequence< OUString > seqFieldNames = xAllFieldNames->getElementNames();
+
+ OUString sCurrentField;
+ sal_Int32 nIndex = 0;
+ do
+ {
+ sCurrentField = o3tl::getToken(sVisibleFields, 0, ';' , nIndex);
+
+ // search in the field collection
+ sal_Int32 nFoundIndex = -1;
+ auto pFieldName = std::find_if(seqFieldNames.begin(), seqFieldNames.end(),
+ [this, &sCurrentField](const OUString& rFieldName) {
+ return 0 == m_aStringCompare.compareString( rFieldName, sCurrentField ); });
+ if (pFieldName != seqFieldNames.end())
+ nFoundIndex = static_cast<sal_Int32>(std::distance(seqFieldNames.begin(), pFieldName));
+ DBG_ASSERT(nFoundIndex != -1, "FmSearchEngine::Init : Invalid field name were given !");
+ m_arrFieldMapping.push_back(nFoundIndex);
+ }
+ while ( nIndex >= 0 );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "");
+ }
+
+}
+
+
+void FmSearchEngine::SetFormatterUsing(bool bSet)
+{
+ if (m_bFormatter == bSet)
+ return;
+ m_bFormatter = bSet;
+
+ // I did not use a formatter, but TextComponents -> the SearchIterator needs to be adjusted
+ try
+ {
+ if (m_bFormatter)
+ {
+ DBG_ASSERT(m_xSearchCursor == m_xClonedIterator, "FmSearchEngine::SetFormatterUsing : inconsistent state !");
+ m_xSearchCursor = m_xOriginalIterator;
+ m_xSearchCursor.moveToBookmark(m_xClonedIterator.getBookmark());
+ // so that I continue with the new iterator at the actual place where I previously stopped
+ }
+ else
+ {
+ DBG_ASSERT(m_xSearchCursor == m_xOriginalIterator, "FmSearchEngine::SetFormatterUsing : inconsistent state !");
+ m_xSearchCursor = m_xClonedIterator;
+ m_xSearchCursor.moveToBookmark(m_xOriginalIterator.getBookmark());
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ // I have to re-bind the fields, because the text exchange might take
+ // place over these fields and the underlying cursor has changed
+ RebuildUsedFields(m_nCurrentFieldIndex, true);
+}
+
+
+void FmSearchEngine::PropagateProgress(bool _bDontPropagateOverflow)
+{
+ if (!m_aProgressHandler.IsSet())
+ return;
+
+ FmSearchProgress aProgress;
+ try
+ {
+ aProgress.aSearchState = FmSearchProgress::State::Progress;
+ aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
+ if (m_bForward)
+ aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isFirst();
+ else
+ aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isLast();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ m_aProgressHandler.Call(&aProgress);
+}
+
+
+void FmSearchEngine::SearchNextImpl()
+{
+ DBG_ASSERT(!(m_bWildcard && m_bRegular) && !(m_bRegular && m_bLevenshtein) && !(m_bLevenshtein && m_bWildcard),
+ "FmSearchEngine::SearchNextImpl : search parameters are mutually exclusive!");
+
+ DBG_ASSERT(m_xSearchCursor.is(), "FmSearchEngine::SearchNextImpl : have invalid iterator!");
+
+ // the parameters of the search
+ OUString strSearchExpression(m_strSearchExpression); // I need non-const
+ if (!GetCaseSensitive())
+ // norm the string
+ strSearchExpression = m_aCharacterClassficator.lowercase(strSearchExpression);
+
+ if (!m_bRegular && !m_bLevenshtein)
+ { // 'normal' search I run through WildCards in any case, but must before adjust the OUString depending on the mode
+
+ if (!m_bWildcard)
+ { // since in all other cases * and ? in the search string are of course
+ // also allowed, but should not count as WildCards, I need to normalize
+ OUString aTmp(strSearchExpression);
+ aTmp = aTmp.replaceAll("*", "\\*");
+ aTmp = aTmp.replaceAll("?", "\\?");
+ strSearchExpression = aTmp;
+
+ switch (m_nPosition)
+ {
+ case MATCHING_ANYWHERE :
+ strSearchExpression = "*" + strSearchExpression + "*";
+ break;
+ case MATCHING_BEGINNING :
+ strSearchExpression += "*";
+ break;
+ case MATCHING_END :
+ strSearchExpression = "*" + strSearchExpression;
+ break;
+ case MATCHING_WHOLETEXT :
+ break;
+ default :
+ OSL_FAIL("FmSearchEngine::SearchNextImpl() : the methods listbox may contain only 4 entries ...");
+ }
+ }
+ }
+
+ // for work on field list
+ FieldCollection::iterator iterBegin = m_arrUsedFields.begin();
+ FieldCollection::iterator iterEnd = m_arrUsedFields.end();
+ FieldCollection::iterator iterFieldCheck;
+
+ sal_Int32 nFieldPos;
+
+ if (m_aPreviousLocBookmark.hasValue())
+ {
+ DBG_ASSERT(EQUAL_BOOKMARKS(m_aPreviousLocBookmark, m_xSearchCursor.getBookmark()),
+ "FmSearchEngine::SearchNextImpl : invalid position!");
+ iterFieldCheck = m_iterPreviousLocField;
+ // continue in the field after (or before) the last discovery
+ nFieldPos = iterFieldCheck - iterBegin;
+ MoveField(nFieldPos, iterFieldCheck, iterBegin, iterEnd);
+ }
+ else
+ {
+ if (m_bForward)
+ iterFieldCheck = iterBegin;
+ else
+ {
+ iterFieldCheck = iterEnd;
+ --iterFieldCheck;
+ }
+ nFieldPos = iterFieldCheck - iterBegin;
+ }
+
+ PropagateProgress(true);
+ SearchResult srResult;
+ if (m_eSearchForType != SearchFor::String)
+ srResult = SearchSpecial(m_eSearchForType == SearchFor::Null, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
+ else if (!m_bRegular && !m_bLevenshtein)
+ srResult = SearchWildcard(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
+ else
+ srResult = SearchRegularApprox(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd);
+
+ m_srResult = srResult;
+
+ if (SearchResult::Error == m_srResult)
+ return;
+
+ // found?
+ if (SearchResult::Found == m_srResult)
+ {
+ // memorize the position
+ try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("svx"); }
+ m_iterPreviousLocField = iterFieldCheck;
+ }
+ else
+ // invalidate the "last discovery"
+ InvalidatePreviousLoc();
+}
+
+
+void FmSearchEngine::OnSearchTerminated()
+{
+ if (!m_aProgressHandler.IsSet())
+ return;
+
+ FmSearchProgress aProgress;
+ try
+ {
+ switch (m_srResult)
+ {
+ case SearchResult::Error :
+ aProgress.aSearchState = FmSearchProgress::State::Error;
+ break;
+ case SearchResult::Found :
+ aProgress.aSearchState = FmSearchProgress::State::Successful;
+ aProgress.aBookmark = m_aPreviousLocBookmark;
+ aProgress.nFieldIndex = m_iterPreviousLocField - m_arrUsedFields.begin();
+ break;
+ case SearchResult::NotFound :
+ aProgress.aSearchState = FmSearchProgress::State::NothingFound;
+ aProgress.aBookmark = m_xSearchCursor.getBookmark();
+ break;
+ case SearchResult::Cancelled :
+ aProgress.aSearchState = FmSearchProgress::State::Canceled;
+ aProgress.aBookmark = m_xSearchCursor.getBookmark();
+ break;
+ }
+ aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ // by definition, the link must be thread-safe (I just require that),
+ // so that I do not have to worry about such things here
+ m_aProgressHandler.Call(&aProgress);
+
+ m_bSearchingCurrently = false;
+}
+
+
+IMPL_LINK(FmSearchEngine, OnNewRecordCount, sal_Int32, theCounter, void)
+{
+ if (!m_aProgressHandler.IsSet())
+ return;
+
+ FmSearchProgress aProgress;
+ aProgress.nCurrentRecord = theCounter;
+ aProgress.aSearchState = FmSearchProgress::State::ProgressCounting;
+ m_aProgressHandler.Call(&aProgress);
+}
+
+
+bool FmSearchEngine::CancelRequested()
+{
+ bool bReturn = m_bCancelAsynchRequest;
+ return bReturn;
+}
+
+
+void FmSearchEngine::CancelSearch()
+{
+ m_bCancelAsynchRequest = true;
+}
+
+
+void FmSearchEngine::SwitchToContext(const Reference< css::sdbc::XResultSet > & xCursor, std::u16string_view sVisibleFields, const InterfaceArray& arrFields,
+ sal_Int32 nFieldIndex)
+{
+ DBG_ASSERT(!m_bSearchingCurrently, "FmSearchEngine::SwitchToContext : please do not call while I'm searching !");
+ if (m_bSearchingCurrently)
+ return;
+
+ m_xSearchCursor = xCursor;
+ m_xOriginalIterator = xCursor;
+ m_xClonedIterator = CursorWrapper(m_xOriginalIterator, true);
+
+ fillControlTexts(arrFields);
+
+ Init(sVisibleFields);
+ RebuildUsedFields(nFieldIndex, true);
+}
+
+
+void FmSearchEngine::ImplStartNextSearch()
+{
+ m_bCancelAsynchRequest = false;
+ m_bSearchingCurrently = true;
+
+ SearchNextImpl();
+ OnSearchTerminated();
+}
+
+
+void FmSearchEngine::SearchNext(const OUString& strExpression)
+{
+ m_strSearchExpression = strExpression;
+ m_eSearchForType = SearchFor::String;
+ ImplStartNextSearch();
+}
+
+
+void FmSearchEngine::SearchNextSpecial(bool _bSearchForNull)
+{
+ m_eSearchForType = _bSearchForNull ? SearchFor::Null : SearchFor::NotNull;
+ ImplStartNextSearch();
+}
+
+
+void FmSearchEngine::StartOver(const OUString& strExpression)
+{
+ try
+ {
+ if (m_bForward)
+ m_xSearchCursor.first();
+ else
+ m_xSearchCursor.last();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ return;
+ }
+
+ InvalidatePreviousLoc();
+ SearchNext(strExpression);
+}
+
+
+void FmSearchEngine::StartOverSpecial(bool _bSearchForNull)
+{
+ try
+ {
+ if (m_bForward)
+ m_xSearchCursor.first();
+ else
+ m_xSearchCursor.last();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ return;
+ }
+
+ InvalidatePreviousLoc();
+ SearchNextSpecial(_bSearchForNull);
+}
+
+
+void FmSearchEngine::InvalidatePreviousLoc()
+{
+ m_aPreviousLocBookmark.clear();
+ m_iterPreviousLocField = m_arrUsedFields.end();
+}
+
+
+void FmSearchEngine::RebuildUsedFields(sal_Int32 nFieldIndex, bool bForce)
+{
+ if (!bForce && (nFieldIndex == m_nCurrentFieldIndex))
+ return;
+ // (since I allow no change of the iterator from the outside, the same css::sdbcx::Index
+ // also always means the same column, so I have nothing to do)
+
+ DBG_ASSERT((nFieldIndex == -1) ||
+ ((nFieldIndex >= 0) &&
+ (o3tl::make_unsigned(nFieldIndex) < m_arrFieldMapping.size())),
+ "FmSearchEngine::RebuildUsedFields : nFieldIndex is invalid!");
+ // collect all fields I need to search through
+ m_arrUsedFields.clear();
+ if (nFieldIndex == -1)
+ {
+ Reference< css::container::XIndexAccess > xFields;
+ for (sal_Int32 i : m_arrFieldMapping)
+ {
+ Reference< css::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
+ DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !");
+ xFields.set(xSupplyCols->getColumns(), UNO_QUERY);
+ BuildAndInsertFieldInfo(xFields, i);
+ }
+ }
+ else
+ {
+ Reference< css::container::XIndexAccess > xFields;
+ Reference< css::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY);
+ DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !");
+ xFields.set (xSupplyCols->getColumns(), UNO_QUERY);
+ BuildAndInsertFieldInfo(xFields, m_arrFieldMapping[static_cast< size_t >(nFieldIndex)]);
+ }
+
+ m_nCurrentFieldIndex = nFieldIndex;
+ // and of course I start the next search in a virgin state again
+ InvalidatePreviousLoc();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmtextcontroldialogs.cxx b/svx/source/form/fmtextcontroldialogs.cxx
new file mode 100644
index 000000000..c365becea
--- /dev/null
+++ b/svx/source/form/fmtextcontroldialogs.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fmtextcontroldialogs.hxx>
+#include <svx/dialogs.hrc>
+#include <svx/svxids.hrc>
+
+#include <svx/flagsdef.hxx>
+#include <svl/intitem.hxx>
+
+#include <svl/cjkoptions.hxx>
+
+
+namespace svx
+{
+
+ TextControlCharAttribDialog::TextControlCharAttribDialog(weld::Window* pParent, const SfxItemSet& rCoreSet, const SvxFontListItem& rFontList)
+ : SfxTabDialogController(pParent, "svx/ui/textcontrolchardialog.ui", "TextControlCharacterPropertiesDialog", &rCoreSet)
+ , m_aFontList(rFontList)
+ {
+ AddTabPage("font", RID_SVXPAGE_CHAR_NAME);
+ AddTabPage("fonteffects", RID_SVXPAGE_CHAR_EFFECTS);
+ AddTabPage("position", RID_SVXPAGE_CHAR_POSITION);
+ }
+
+ void TextControlCharAttribDialog::PageCreated(const OString& rId, SfxTabPage& rPage)
+ {
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+
+ if (rId == "font")
+ {
+ aSet.Put (m_aFontList);
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "fonteffects")
+ {
+ aSet.Put (SfxUInt16Item(SID_DISABLE_CTL,DISABLE_CASEMAP));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "position")
+ {
+ aSet.Put( SfxUInt32Item(SID_FLAG_TYPE, SVX_PREVIEW_CHARACTER) );
+ rPage.PageCreated(aSet);
+ }
+ }
+
+ TextControlParaAttribDialog::TextControlParaAttribDialog(weld::Window* pParent, const SfxItemSet& rCoreSet)
+ : SfxTabDialogController(pParent, "svx/ui/textcontrolparadialog.ui", "TextControlParagraphPropertiesDialog", &rCoreSet)
+ {
+ AddTabPage("labelTP_PARA_STD", RID_SVXPAGE_STD_PARAGRAPH);
+ AddTabPage("labelTP_PARA_ALIGN", RID_SVXPAGE_ALIGN_PARAGRAPH);
+
+ if( SvtCJKOptions::IsAsianTypographyEnabled() )
+ AddTabPage("labelTP_PARA_ASIAN", RID_SVXPAGE_PARA_ASIAN);
+ else
+ RemoveTabPage("labelTP_PARA_ASIAN");
+
+ AddTabPage("labelTP_TABULATOR", RID_SVXPAGE_TABULATOR);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmtextcontrolfeature.cxx b/svx/source/form/fmtextcontrolfeature.cxx
new file mode 100644
index 000000000..68bb8606a
--- /dev/null
+++ b/svx/source/form/fmtextcontrolfeature.cxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <fmtextcontrolfeature.hxx>
+#include <fmtextcontrolshell.hxx>
+
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+namespace svx
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::util;
+
+ FmTextControlFeature::FmTextControlFeature( const Reference< XDispatch >& _rxDispatcher, const URL& _rFeatureURL, SfxSlotId _nSlotId, FmTextControlShell* _pInvalidator )
+ :m_xDispatcher ( _rxDispatcher )
+ ,m_aFeatureURL ( _rFeatureURL )
+ ,m_nSlotId ( _nSlotId )
+ ,m_pInvalidator ( _pInvalidator )
+ ,m_bFeatureEnabled( false )
+ {
+ OSL_ENSURE( _rxDispatcher.is(), "FmTextControlFeature::FmTextControlFeature: invalid dispatcher!" );
+ OSL_ENSURE( m_nSlotId, "FmTextControlFeature::FmTextControlFeature: invalid slot id!" );
+ OSL_ENSURE( m_pInvalidator, "FmTextControlFeature::FmTextControlFeature: invalid invalidator!" );
+
+ osl_atomic_increment( &m_refCount );
+ try
+ {
+ m_xDispatcher->addStatusListener( this, m_aFeatureURL );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmTextControlFeature::FmTextControlFeature" );
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ FmTextControlFeature::~FmTextControlFeature( )
+ {
+ }
+
+
+ void FmTextControlFeature::dispatch() const
+ {
+ dispatch( Sequence< PropertyValue >( ) );
+ }
+
+
+ void FmTextControlFeature::dispatch( const Sequence< PropertyValue >& _rArgs ) const
+ {
+ try
+ {
+ if ( m_xDispatcher.is() )
+ m_xDispatcher->dispatch( m_aFeatureURL, _rArgs );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmTextControlFeature::dispatch" );
+ }
+ }
+
+
+ void SAL_CALL FmTextControlFeature::statusChanged( const FeatureStateEvent& _rState )
+ {
+ m_aFeatureState = _rState.State;
+ m_bFeatureEnabled = _rState.IsEnabled;
+
+ if ( m_pInvalidator )
+ m_pInvalidator->Invalidate( m_nSlotId );
+ }
+
+
+ void SAL_CALL FmTextControlFeature::disposing( const EventObject& /*Source*/ )
+ {
+ // nothing to do
+ }
+
+
+ void FmTextControlFeature::dispose()
+ {
+ try
+ {
+ m_xDispatcher->removeStatusListener( this, m_aFeatureURL );
+ m_xDispatcher.clear();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmTextControlFeature::dispose" );
+ }
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmtextcontrolshell.cxx b/svx/source/form/fmtextcontrolshell.cxx
new file mode 100644
index 000000000..d97dfeb85
--- /dev/null
+++ b/svx/source/form/fmtextcontrolshell.cxx
@@ -0,0 +1,1315 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <fmprop.hxx>
+#include <fmtextcontroldialogs.hxx>
+#include <fmtextcontrolfeature.hxx>
+#include <fmtextcontrolshell.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/scriptspaceitem.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/udlnitem.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/awt/XFocusListener.hpp>
+#include <com/sun/star/awt/XMouseListener.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/msgpool.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxuno.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/eitem.hxx>
+#include <svl/itempool.hxx>
+#include <svl/ctloptions.hxx>
+#include <svtools/stringtransfer.hxx>
+#include <svl/whiter.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+
+#include <memory>
+
+
+namespace svx
+{
+
+
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::form::runtime;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+
+
+ typedef sal_uInt16 WhichId;
+
+
+ static SfxSlotId pTextControlSlots[] =
+ {
+ SID_CLIPBOARD_FORMAT_ITEMS,
+ SID_CUT,
+ SID_COPY,
+ SID_PASTE,
+ SID_SELECTALL,
+// SID_ATTR_TABSTOP, /* 2 */
+ SID_ATTR_CHAR_FONT,
+ SID_ATTR_CHAR_POSTURE,
+ SID_ATTR_CHAR_WEIGHT,
+ SID_ATTR_CHAR_SHADOWED,
+ SID_ATTR_CHAR_WORDLINEMODE,
+ SID_ATTR_CHAR_CONTOUR,
+ SID_ATTR_CHAR_STRIKEOUT,
+ SID_ATTR_CHAR_UNDERLINE,
+ SID_ATTR_CHAR_FONTHEIGHT,
+ SID_ATTR_CHAR_COLOR,
+ SID_ATTR_CHAR_KERNING,
+ SID_ATTR_CHAR_LANGUAGE, /* 20 */
+ SID_ATTR_CHAR_ESCAPEMENT,
+ SID_ATTR_PARA_ADJUST, /* 28 */
+ SID_ATTR_PARA_ADJUST_LEFT,
+ SID_ATTR_PARA_ADJUST_RIGHT,
+ SID_ATTR_PARA_ADJUST_CENTER,
+ SID_ATTR_PARA_ADJUST_BLOCK,
+ SID_ATTR_PARA_LINESPACE, /* 33 */
+ SID_ATTR_PARA_LINESPACE_10,
+ SID_ATTR_PARA_LINESPACE_15,
+ SID_ATTR_PARA_LINESPACE_20,
+ SID_ATTR_LRSPACE, /* 48 */
+ SID_ATTR_ULSPACE, /* 49 */
+ SID_ATTR_CHAR_AUTOKERN,
+ SID_SET_SUPER_SCRIPT,
+ SID_SET_SUB_SCRIPT,
+ SID_CHAR_DLG,
+ SID_PARA_DLG,
+// SID_TEXTDIRECTION_LEFT_TO_RIGHT, /* 907 */
+// SID_TEXTDIRECTION_TOP_TO_BOTTOM,
+ SID_ATTR_CHAR_SCALEWIDTH, /* 911 */
+ SID_ATTR_CHAR_RELIEF,
+ SID_ATTR_PARA_LEFT_TO_RIGHT, /* 950 */
+ SID_ATTR_PARA_RIGHT_TO_LEFT,
+ SID_ATTR_CHAR_OVERLINE,
+ 0
+ };
+
+ // slots which we are not responsible for on the SfxShell level, but
+ // need to handle during the "paragraph attributes" and/or "character
+ // attributes" dialogs
+ static SfxSlotId pDialogSlots[] =
+ {
+ SID_ATTR_TABSTOP,
+ SID_ATTR_PARA_HANGPUNCTUATION,
+ SID_ATTR_PARA_FORBIDDEN_RULES,
+ SID_ATTR_PARA_SCRIPTSPACE,
+ SID_ATTR_CHAR_LATIN_LANGUAGE,
+ SID_ATTR_CHAR_CJK_LANGUAGE,
+ SID_ATTR_CHAR_CTL_LANGUAGE,
+ SID_ATTR_CHAR_LATIN_FONT,
+ SID_ATTR_CHAR_CJK_FONT,
+ SID_ATTR_CHAR_CTL_FONT,
+ SID_ATTR_CHAR_LATIN_FONTHEIGHT,
+ SID_ATTR_CHAR_CJK_FONTHEIGHT,
+ SID_ATTR_CHAR_CTL_FONTHEIGHT,
+ SID_ATTR_CHAR_LATIN_WEIGHT,
+ SID_ATTR_CHAR_CJK_WEIGHT,
+ SID_ATTR_CHAR_CTL_WEIGHT,
+ SID_ATTR_CHAR_LATIN_POSTURE,
+ SID_ATTR_CHAR_CJK_POSTURE,
+ SID_ATTR_CHAR_CTL_POSTURE,
+ SID_ATTR_CHAR_EMPHASISMARK,
+ 0
+ };
+
+ typedef ::cppu::WeakImplHelper < css::awt::XFocusListener
+ > FmFocusListenerAdapter_Base;
+ class FmFocusListenerAdapter : public FmFocusListenerAdapter_Base
+ {
+ private:
+ IFocusObserver* m_pObserver;
+ Reference< css::awt::XWindow > m_xWindow;
+
+ public:
+ FmFocusListenerAdapter( const Reference< css::awt::XControl >& _rxControl, IFocusObserver* _pObserver );
+
+ // clean up the instance
+ void dispose();
+
+ protected:
+ virtual ~FmFocusListenerAdapter() override;
+
+ protected:
+ virtual void SAL_CALL focusGained( const css::awt::FocusEvent& e ) override;
+ virtual void SAL_CALL focusLost( const css::awt::FocusEvent& e ) override;
+ virtual void SAL_CALL disposing( const EventObject& Source ) override;
+ };
+
+
+ FmFocusListenerAdapter::FmFocusListenerAdapter( const Reference< css::awt::XControl >& _rxControl, IFocusObserver* _pObserver )
+ :m_pObserver( _pObserver )
+ ,m_xWindow( _rxControl, UNO_QUERY )
+ {
+
+ DBG_ASSERT( m_xWindow.is(), "FmFocusListenerAdapter::FmFocusListenerAdapter: invalid control!" );
+ osl_atomic_increment( &m_refCount );
+ {
+ try
+ {
+ if ( m_xWindow.is() )
+ m_xWindow->addFocusListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ FmFocusListenerAdapter::~FmFocusListenerAdapter()
+ {
+ acquire();
+ dispose();
+
+ }
+
+
+ void FmFocusListenerAdapter::dispose()
+ {
+ if ( m_xWindow.is() )
+ {
+ m_xWindow->removeFocusListener( this );
+ m_xWindow.clear();
+ }
+ }
+
+
+ void SAL_CALL FmFocusListenerAdapter::focusGained( const css::awt::FocusEvent& e )
+ {
+ if ( m_pObserver )
+ m_pObserver->focusGained( e );
+ }
+
+
+ void SAL_CALL FmFocusListenerAdapter::focusLost( const css::awt::FocusEvent& e )
+ {
+ if ( m_pObserver )
+ m_pObserver->focusLost( e );
+ }
+
+
+ void SAL_CALL FmFocusListenerAdapter::disposing( const EventObject& Source )
+ {
+ DBG_ASSERT( Source.Source == m_xWindow, "FmFocusListenerAdapter::disposing: where did this come from?" );
+ m_xWindow.clear();
+ }
+
+ typedef ::cppu::WeakImplHelper < css::awt::XMouseListener
+ > FmMouseListenerAdapter_Base;
+ class FmMouseListenerAdapter : public FmMouseListenerAdapter_Base
+ {
+ private:
+ IContextRequestObserver* m_pObserver;
+ Reference< css::awt::XWindow > m_xWindow;
+
+ public:
+ FmMouseListenerAdapter( const Reference< css::awt::XControl >& _rxControl, IContextRequestObserver* _pObserver );
+
+ // clean up the instance
+ void dispose();
+
+ protected:
+ virtual ~FmMouseListenerAdapter() override;
+
+ protected:
+ virtual void SAL_CALL mousePressed( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseReleased( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseEntered( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseExited( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL disposing( const EventObject& Source ) override;
+ };
+
+ FmMouseListenerAdapter::FmMouseListenerAdapter( const Reference< css::awt::XControl >& _rxControl, IContextRequestObserver* _pObserver )
+ :m_pObserver( _pObserver )
+ ,m_xWindow( _rxControl, UNO_QUERY )
+ {
+
+ DBG_ASSERT( m_xWindow.is(), "FmMouseListenerAdapter::FmMouseListenerAdapter: invalid control!" );
+ osl_atomic_increment( &m_refCount );
+ {
+ try
+ {
+ if ( m_xWindow.is() )
+ m_xWindow->addMouseListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ FmMouseListenerAdapter::~FmMouseListenerAdapter()
+ {
+ acquire();
+ dispose();
+
+ }
+
+
+ void FmMouseListenerAdapter::dispose()
+ {
+ if ( m_xWindow.is() )
+ {
+ m_xWindow->removeMouseListener( this );
+ m_xWindow.clear();
+ }
+ }
+
+
+ void SAL_CALL FmMouseListenerAdapter::mousePressed( const css::awt::MouseEvent& _rEvent )
+ {
+ SolarMutexGuard aGuard;
+ // is this a request for a context menu?
+ if ( _rEvent.PopupTrigger )
+ {
+ if ( m_pObserver )
+ m_pObserver->contextMenuRequested();
+ }
+ }
+
+
+ void SAL_CALL FmMouseListenerAdapter::mouseReleased( const css::awt::MouseEvent& /*e*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL FmMouseListenerAdapter::mouseEntered( const css::awt::MouseEvent& /*e*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL FmMouseListenerAdapter::mouseExited( const css::awt::MouseEvent& /*e*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL FmMouseListenerAdapter::disposing( const EventObject& Source )
+ {
+ DBG_ASSERT( Source.Source == m_xWindow, "FmMouseListenerAdapter::disposing: where did this come from?" );
+ m_xWindow.clear();
+ }
+
+
+ //= FmTextControlShell
+
+
+ namespace
+ {
+
+ void lcl_translateUnoStateToItem( SfxSlotId _nSlot, const Any& _rUnoState, SfxItemSet& _rSet )
+ {
+ WhichId nWhich = _rSet.GetPool()->GetWhich( _nSlot );
+ if ( !_rUnoState.hasValue() )
+ {
+ if ( ( _nSlot != SID_CUT )
+ && ( _nSlot != SID_COPY )
+ && ( _nSlot != SID_PASTE )
+ )
+ {
+ _rSet.InvalidateItem( nWhich );
+ }
+ }
+ else
+ {
+ switch ( _rUnoState.getValueType().getTypeClass() )
+ {
+ case TypeClass_BOOLEAN:
+ {
+ bool bState = false;
+ _rUnoState >>= bState;
+ if ( _nSlot == SID_ATTR_PARA_SCRIPTSPACE )
+ _rSet.Put( SvxScriptSpaceItem( bState, nWhich ) );
+ else
+ _rSet.Put( SfxBoolItem( nWhich, bState ) );
+ }
+ break;
+
+ default:
+ {
+ Sequence< PropertyValue > aComplexState;
+ if ( _rUnoState >>= aComplexState )
+ {
+ if ( !aComplexState.hasElements() )
+ _rSet.InvalidateItem( nWhich );
+ else
+ {
+ SfxAllItemSet aAllItems( _rSet );
+ TransformParameters( _nSlot, aComplexState, aAllItems );
+ const SfxPoolItem* pTransformed = aAllItems.GetItem( nWhich );
+ OSL_ENSURE( pTransformed, "lcl_translateUnoStateToItem: non-empty parameter sequence leading to empty item?" );
+ if ( pTransformed )
+ _rSet.Put( *pTransformed );
+ else
+ _rSet.InvalidateItem( nWhich );
+ }
+ }
+ else
+ {
+ OSL_FAIL( "lcl_translateUnoStateToItem: invalid state!" );
+ }
+ }
+ }
+ }
+ }
+
+
+ OUString lcl_getUnoSlotName( SfxSlotId _nSlotId )
+ {
+ OUString sSlotUnoName;
+
+ SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool();
+ const SfxSlot* pSlot = rSlotPool.GetSlot( _nSlotId );
+
+ const char* pAsciiUnoName = nullptr;
+ if ( pSlot )
+ {
+ pAsciiUnoName = pSlot->GetUnoName();
+ }
+ else
+ {
+ // some hard-coded slots, which do not have a UNO name at SFX level, but which
+ // we nevertheless need to transport via UNO mechanisms, so we need a name
+ switch ( _nSlotId )
+ {
+ case SID_ATTR_PARA_HANGPUNCTUATION: pAsciiUnoName = "AllowHangingPunctuation"; break;
+ case SID_ATTR_PARA_FORBIDDEN_RULES: pAsciiUnoName = "ApplyForbiddenCharacterRules"; break;
+ case SID_ATTR_PARA_SCRIPTSPACE: pAsciiUnoName = "UseScriptSpacing"; break;
+ }
+ }
+
+ if ( pAsciiUnoName )
+ {
+ sSlotUnoName = ".uno:" + OUString::createFromAscii( pAsciiUnoName );
+ }
+ else
+ {
+ SAL_WARN( "svx", "lcl_getUnoSlotName: invalid slot id, or invalid slot, or no UNO name! "
+ "(slot id: " << _nSlotId << ")");
+ }
+ return sSlotUnoName;
+ }
+
+
+ bool lcl_determineReadOnly( const Reference< css::awt::XControl >& _rxControl )
+ {
+ bool bIsReadOnlyModel = true;
+ try
+ {
+ Reference< XPropertySet > xModelProps;
+ if ( _rxControl.is() )
+ xModelProps.set(_rxControl->getModel(), css::uno::UNO_QUERY);
+ Reference< XPropertySetInfo > xModelPropInfo;
+ if ( xModelProps.is() )
+ xModelPropInfo = xModelProps->getPropertySetInfo();
+
+ if ( !xModelPropInfo.is() || !xModelPropInfo->hasPropertyByName( FM_PROP_READONLY ) )
+ bIsReadOnlyModel = true;
+ else
+ {
+ bool bReadOnly = true;
+ xModelProps->getPropertyValue( FM_PROP_READONLY ) >>= bReadOnly;
+ bIsReadOnlyModel = bReadOnly;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return bIsReadOnlyModel;
+ }
+
+
+ vcl::Window* lcl_getWindow( const Reference< css::awt::XControl >& _rxControl )
+ {
+ vcl::Window* pWindow = nullptr;
+ try
+ {
+ Reference< css::awt::XWindowPeer > xControlPeer;
+ if ( _rxControl.is() )
+ xControlPeer = _rxControl->getPeer();
+ if ( xControlPeer.is() )
+ pWindow = VCLUnoHelper::GetWindow( xControlPeer );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ return pWindow;
+ }
+
+
+ bool lcl_isRichText( const Reference< css::awt::XControl >& _rxControl )
+ {
+ if ( !_rxControl.is() )
+ return false;
+
+ bool bIsRichText = false;
+ try
+ {
+ Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
+ Reference< XPropertySetInfo > xPSI;
+ if ( xModelProps.is() )
+ xPSI = xModelProps->getPropertySetInfo();
+ OUString sRichTextPropertyName = "RichText";
+ if ( xPSI.is() && xPSI->hasPropertyByName( sRichTextPropertyName ) )
+ {
+ OSL_VERIFY( xModelProps->getPropertyValue( sRichTextPropertyName ) >>= bIsRichText );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return bIsRichText;
+ }
+ }
+
+
+ FmTextControlShell::FmTextControlShell( SfxViewFrame* _pFrame )
+ :m_bActiveControl( false )
+ ,m_bActiveControlIsReadOnly( true )
+ ,m_bActiveControlIsRichText( false )
+ ,m_pViewFrame( _pFrame )
+ ,m_rBindings( _pFrame->GetBindings() )
+ ,m_aClipboardInvalidation("svx FmTextControlShell m_aClipboardInvalidation")
+ ,m_bNeedClipboardInvalidation( true )
+ {
+ m_aClipboardInvalidation.SetInvokeHandler( LINK( this, FmTextControlShell, OnInvalidateClipboard ) );
+ m_aClipboardInvalidation.SetTimeout( 200 );
+ }
+
+
+ FmTextControlShell::~FmTextControlShell()
+ {
+ dispose();
+ }
+
+
+ IMPL_LINK_NOARG( FmTextControlShell, OnInvalidateClipboard, Timer*, void )
+ {
+ if ( m_bNeedClipboardInvalidation )
+ {
+ SAL_INFO("svx.form", "invalidating clipboard slots" );
+ m_rBindings.Invalidate( SID_CUT );
+ m_rBindings.Invalidate( SID_COPY );
+ m_rBindings.Invalidate( SID_PASTE );
+ m_bNeedClipboardInvalidation = false;
+ }
+ }
+
+
+ void FmTextControlShell::transferFeatureStatesToItemSet( ControlFeatures& _rDispatchers, SfxAllItemSet& _rSet, bool _bTranslateLatin )
+ {
+ SfxItemPool& rPool = *_rSet.GetPool();
+
+ for (const auto& rFeature : _rDispatchers)
+ {
+ SfxSlotId nSlotId( rFeature.first );
+#if OSL_DEBUG_LEVEL > 0
+ OUString sUnoSlotName;
+ if ( SfxGetpApp() )
+ sUnoSlotName = lcl_getUnoSlotName( nSlotId );
+ else
+ sUnoSlotName = "<unknown>";
+ OString sUnoSlotNameAscii = "\"" +
+ OString( sUnoSlotName.getStr(), sUnoSlotName.getLength(), RTL_TEXTENCODING_ASCII_US ) +
+ "\"";
+#endif
+
+ if ( _bTranslateLatin )
+ {
+ // A rich text control offers a dispatcher for the "Font" slot/feature.
+ // Sadly, the semantics of the dispatches is that the feature "Font" depends
+ // on the current cursor position: If it's on latin text, it's the "latin font"
+ // which is set up at the control. If it's on CJK text, it's the "CJK font", and
+ // equivalent for "CTL font".
+ // The same holds for some other font related features/slots.
+ // Thus, we have separate dispatches for "Latin Font", "Latin Font Size", etc,
+ // which are only "virtual", in a sense that there exist no item with this id.
+ // So when we encounter such a dispatcher for, say, "Latin Font", we need to
+ // put an item into the set which has the "Font" id.
+
+ switch ( nSlotId )
+ {
+ case SID_ATTR_CHAR_LATIN_FONT: nSlotId = SID_ATTR_CHAR_FONT; break;
+ case SID_ATTR_CHAR_LATIN_FONTHEIGHT:nSlotId = SID_ATTR_CHAR_FONTHEIGHT; break;
+ case SID_ATTR_CHAR_LATIN_LANGUAGE: nSlotId = SID_ATTR_CHAR_LANGUAGE; break;
+ case SID_ATTR_CHAR_LATIN_POSTURE: nSlotId = SID_ATTR_CHAR_POSTURE; break;
+ case SID_ATTR_CHAR_LATIN_WEIGHT: nSlotId = SID_ATTR_CHAR_WEIGHT; break;
+ }
+ }
+
+ WhichId nWhich = rPool.GetWhich( nSlotId );
+ bool bIsInPool = rPool.IsInRange( nWhich );
+ if ( bIsInPool )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ bool bFeatureIsEnabled = rFeature.second->isFeatureEnabled();
+ OString sMessage = "found a feature state for " + sUnoSlotNameAscii;
+ if ( !bFeatureIsEnabled )
+ sMessage += " (disabled)";
+ SAL_INFO("svx.form", sMessage );
+#endif
+
+ lcl_translateUnoStateToItem( nSlotId, rFeature.second->getFeatureState(), _rSet );
+ }
+#if OSL_DEBUG_LEVEL > 0
+ else
+ {
+ SAL_WARN("svx.form", "found a feature state for " << sUnoSlotNameAscii << ", but could not translate it into an item!" );
+ }
+#endif
+ }
+ }
+
+
+ void FmTextControlShell::executeAttributeDialog( AttributeSet _eSet, SfxRequest& rReq )
+ {
+ const SvxFontListItem* pFontList = dynamic_cast<const SvxFontListItem*>( m_pViewFrame->GetObjectShell()->GetItem( SID_ATTR_CHAR_FONTLIST ) );
+ DBG_ASSERT( pFontList, "FmTextControlShell::executeAttributeDialog: no font list item!" );
+ if ( !pFontList )
+ return;
+
+ rtl::Reference<SfxItemPool> pPool(EditEngine::CreatePool());
+ pPool->FreezeIdRanges();
+ std::optional< SfxItemSet > xPureItems(( SfxItemSet( *pPool ) ));
+
+ // put the current states of the items into the set
+ std::optional<SfxAllItemSet> xCurrentItems(( SfxAllItemSet( *xPureItems ) ));
+ transferFeatureStatesToItemSet( m_aControlFeatures, *xCurrentItems, false );
+
+ // additional items, which we are not responsible for at the SfxShell level,
+ // but which need to be forwarded to the dialog, anyway
+ ControlFeatures aAdditionalFestures;
+ fillFeatureDispatchers( m_xActiveControl, pDialogSlots, aAdditionalFestures );
+ transferFeatureStatesToItemSet( aAdditionalFestures, *xCurrentItems, true );
+
+ std::unique_ptr<SfxTabDialogController> xDialog;
+ if (_eSet == eCharAttribs)
+ xDialog = std::make_unique<TextControlCharAttribDialog>(rReq.GetFrameWeld(), *xCurrentItems, *pFontList);
+ else
+ xDialog = std::make_unique<TextControlParaAttribDialog>(rReq.GetFrameWeld(), *xCurrentItems);
+ if ( RET_OK == xDialog->run() )
+ {
+ const SfxItemSet& rModifiedItems = *xDialog->GetOutputItemSet();
+ for ( WhichId nWhich = pPool->GetFirstWhich(); nWhich <= pPool->GetLastWhich(); ++nWhich )
+ {
+ if ( rModifiedItems.GetItemState( nWhich ) == SfxItemState::SET )
+ {
+ SfxSlotId nSlotForItemSet = pPool->GetSlotId( nWhich );
+ const SfxPoolItem* pModifiedItem = rModifiedItems.GetItem( nWhich );
+
+
+ SfxSlotId nSlotForDispatcher = nSlotForItemSet;
+ switch ( nSlotForDispatcher )
+ {
+ case SID_ATTR_CHAR_FONT: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_FONT; break;
+ case SID_ATTR_CHAR_FONTHEIGHT:nSlotForDispatcher = SID_ATTR_CHAR_LATIN_FONTHEIGHT; break;
+ case SID_ATTR_CHAR_LANGUAGE: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_LANGUAGE; break;
+ case SID_ATTR_CHAR_POSTURE: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_POSTURE; break;
+ case SID_ATTR_CHAR_WEIGHT: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_WEIGHT; break;
+ }
+
+ // do we already have a dispatcher for this slot/feature?
+ ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlotForDispatcher );
+ bool bFound = aFeaturePos != m_aControlFeatures.end( );
+
+ if ( !bFound )
+ {
+ aFeaturePos = aAdditionalFestures.find( nSlotForDispatcher );
+ bFound = aFeaturePos != aAdditionalFestures.end( );
+ }
+
+ if ( bFound )
+ {
+ Sequence< PropertyValue > aArgs;
+ // temporarily put the modified item into a "clean" set,
+ // and let TransformItems calc the respective UNO parameters
+ xPureItems->Put( *pModifiedItem );
+ TransformItems( nSlotForItemSet, *xPureItems, aArgs );
+ xPureItems->ClearItem( nWhich );
+
+ if ( ( nSlotForItemSet == SID_ATTR_PARA_HANGPUNCTUATION )
+ || ( nSlotForItemSet == SID_ATTR_PARA_FORBIDDEN_RULES )
+ || ( nSlotForItemSet == SID_ATTR_PARA_SCRIPTSPACE )
+ )
+ {
+ // these are no UNO slots, they need special handling since TransformItems cannot
+ // handle them
+ DBG_ASSERT( !aArgs.hasElements(), "FmTextControlShell::executeAttributeDialog: these are no UNO slots - are they?" );
+
+ const SfxBoolItem* pBoolItem = dynamic_cast<const SfxBoolItem*>( pModifiedItem );
+ DBG_ASSERT( pBoolItem, "FmTextControlShell::executeAttributeDialog: no bool item?!" );
+ if ( pBoolItem )
+ {
+ aArgs = { comphelper::makePropertyValue("Enable",
+ pBoolItem->GetValue()) };
+ }
+ }
+
+ // dispatch this
+ aFeaturePos->second->dispatch( aArgs );
+ }
+ #if OSL_DEBUG_LEVEL > 0
+ else
+ {
+ OUString sUnoSlotName = lcl_getUnoSlotName( nSlotForItemSet );
+ if ( sUnoSlotName.isEmpty() )
+ sUnoSlotName = "unknown (no SfxSlot)";
+ SAL_WARN( "svx", "FmTextControShell::executeAttributeDialog: Could not handle the following item:"
+ "\n SlotID: " << nSlotForItemSet
+ << "\n WhichID: " << nWhich
+ << "\n UNO name: " << sUnoSlotName );
+ }
+ #endif
+ }
+ }
+ rReq.Done( rModifiedItems );
+ }
+
+ xDialog.reset();
+ xCurrentItems.reset();
+ xPureItems.reset();
+ pPool.clear();
+ }
+
+
+ void FmTextControlShell::executeSelectAll( )
+ {
+ try
+ {
+ if ( m_xActiveTextComponent.is() )
+ {
+ sal_Int32 nTextLen = m_xActiveTextComponent->getText().getLength();
+ m_xActiveTextComponent->setSelection( css::awt::Selection( 0, nTextLen ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void FmTextControlShell::executeClipboardSlot( SfxSlotId _nSlot )
+ {
+ try
+ {
+ if ( m_xActiveTextComponent.is() )
+ {
+ switch ( _nSlot )
+ {
+ case SID_COPY:
+ case SID_CUT:
+ {
+ OUString sSelectedText( m_xActiveTextComponent->getSelectedText() );
+ ::svt::OStringTransfer::CopyString( sSelectedText, lcl_getWindow( m_xActiveControl ) );
+ if ( SID_CUT == _nSlot )
+ {
+ css::awt::Selection aSelection( m_xActiveTextComponent->getSelection() );
+ m_xActiveTextComponent->insertText( aSelection, OUString() );
+ }
+ }
+ break;
+ case SID_PASTE:
+ {
+ OUString sClipboardContent;
+ OSL_VERIFY( ::svt::OStringTransfer::PasteString( sClipboardContent, lcl_getWindow( m_xActiveControl ) ) );
+ css::awt::Selection aSelection( m_xActiveTextComponent->getSelection() );
+ m_xActiveTextComponent->insertText( aSelection, sClipboardContent );
+ }
+ break;
+ default:
+ OSL_FAIL( "FmTextControlShell::executeClipboardSlot: invalid slot!" );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void FmTextControlShell::ExecuteTextAttribute( SfxRequest& _rReq )
+ {
+ SfxSlotId nSlot = _rReq.GetSlot();
+
+ ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlot );
+ if ( aFeaturePos == m_aControlFeatures.end() )
+ {
+ // special slots
+ switch ( nSlot )
+ {
+ case SID_CHAR_DLG:
+ executeAttributeDialog( eCharAttribs, _rReq );
+ break;
+
+ case SID_PARA_DLG:
+ executeAttributeDialog( eParaAttribs, _rReq );
+ break;
+
+ case SID_SELECTALL:
+ executeSelectAll();
+ break;
+
+ case SID_CUT:
+ case SID_COPY:
+ case SID_PASTE:
+ executeClipboardSlot( nSlot );
+ break;
+
+ default:
+ DBG_ASSERT( aFeaturePos != m_aControlFeatures.end(), "FmTextControShell::ExecuteTextAttribute: I have no such dispatcher, and cannot handle it at all!" );
+ return;
+ }
+ }
+ else
+ {
+ // slots which are dispatched to the control
+
+ switch ( nSlot )
+ {
+ case SID_ATTR_CHAR_STRIKEOUT:
+ case SID_ATTR_CHAR_UNDERLINE:
+ case SID_ATTR_CHAR_OVERLINE:
+ {
+ SfxItemSet aToggled( *_rReq.GetArgs() );
+
+ lcl_translateUnoStateToItem( nSlot, aFeaturePos->second->getFeatureState(), aToggled );
+ WhichId nWhich = aToggled.GetPool()->GetWhich( nSlot );
+ const SfxPoolItem* pItem = aToggled.GetItem( nWhich );
+ if ( ( SID_ATTR_CHAR_UNDERLINE == nSlot ) || ( SID_ATTR_CHAR_OVERLINE == nSlot ) )
+ {
+ const SvxTextLineItem* pTextLine = dynamic_cast<const SvxTextLineItem*>( pItem );
+ DBG_ASSERT( pTextLine, "FmTextControlShell::ExecuteTextAttribute: ooops - no underline/overline item!" );
+ if ( pTextLine )
+ {
+ FontLineStyle eTL = pTextLine->GetLineStyle();
+ if ( SID_ATTR_CHAR_UNDERLINE == nSlot ) {
+ aToggled.Put( SvxUnderlineItem( eTL == LINESTYLE_SINGLE ? LINESTYLE_NONE : LINESTYLE_SINGLE, nWhich ) );
+ } else {
+ aToggled.Put( SvxOverlineItem( eTL == LINESTYLE_SINGLE ? LINESTYLE_NONE : LINESTYLE_SINGLE, nWhich ) );
+ }
+ }
+ }
+ else
+ {
+ const SvxCrossedOutItem* pCrossedOut = dynamic_cast<const SvxCrossedOutItem*>( pItem );
+ DBG_ASSERT( pCrossedOut, "FmTextControlShell::ExecuteTextAttribute: ooops - no CrossedOut item!" );
+ if ( pCrossedOut )
+ {
+ FontStrikeout eFS = pCrossedOut->GetStrikeout();
+ aToggled.Put( SvxCrossedOutItem( eFS == STRIKEOUT_SINGLE ? STRIKEOUT_NONE : STRIKEOUT_SINGLE, nWhich ) );
+ }
+ }
+
+ Sequence< PropertyValue > aArguments;
+ TransformItems( nSlot, aToggled, aArguments );
+ aFeaturePos->second->dispatch( aArguments );
+ }
+ break;
+
+ case SID_ATTR_CHAR_FONTHEIGHT:
+ case SID_ATTR_CHAR_FONT:
+ case SID_ATTR_CHAR_POSTURE:
+ case SID_ATTR_CHAR_WEIGHT:
+ case SID_ATTR_CHAR_SHADOWED:
+ case SID_ATTR_CHAR_CONTOUR:
+ case SID_SET_SUPER_SCRIPT:
+ case SID_SET_SUB_SCRIPT:
+ {
+ const SfxItemSet* pArgs = _rReq.GetArgs();
+ Sequence< PropertyValue > aArgs;
+ if ( pArgs )
+ TransformItems( nSlot, *pArgs, aArgs );
+ aFeaturePos->second->dispatch( aArgs );
+ }
+ break;
+
+ default:
+ if ( aFeaturePos->second->isFeatureEnabled() )
+ aFeaturePos->second->dispatch();
+ break;
+ }
+ }
+ _rReq.Done();
+ }
+
+
+ void FmTextControlShell::GetTextAttributeState( SfxItemSet& _rSet )
+ {
+ SfxWhichIter aIter( _rSet );
+ sal_uInt16 nSlot = aIter.FirstWhich();
+ while ( nSlot )
+ {
+ if ( ( nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT )
+ || ( nSlot == SID_ATTR_PARA_RIGHT_TO_LEFT )
+ )
+ {
+ if ( !SvtCTLOptions().IsCTLFontEnabled() )
+ {
+ _rSet.DisableItem( nSlot );
+ nSlot = aIter.NextWhich();
+ continue;
+ }
+ }
+
+ ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlot );
+ if ( aFeaturePos != m_aControlFeatures.end() )
+ {
+ if ( aFeaturePos->second->isFeatureEnabled() )
+ lcl_translateUnoStateToItem( nSlot, aFeaturePos->second->getFeatureState(), _rSet );
+ else
+ _rSet.DisableItem( nSlot );
+ }
+ else
+ {
+ bool bDisable = false;
+
+ bool bNeedWriteableControl = false;
+ bool bNeedTextComponent = false;
+ bool bNeedSelection = false;
+
+ switch ( nSlot )
+ {
+ case SID_CHAR_DLG:
+ case SID_PARA_DLG:
+ bDisable |= m_aControlFeatures.empty();
+ bNeedWriteableControl = true;
+ break;
+
+ case SID_CUT:
+ bNeedSelection = true;
+ bNeedTextComponent = true;
+ bNeedWriteableControl = true;
+ SAL_INFO("svx.form", "need to invalidate again" );
+ m_bNeedClipboardInvalidation = true;
+ break;
+
+ case SID_PASTE:
+ {
+ vcl::Window* pActiveControlVCLWindow = lcl_getWindow( m_xActiveControl );
+ if ( pActiveControlVCLWindow )
+ {
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pActiveControlVCLWindow) );
+ bDisable |= !aDataHelper.HasFormat( SotClipboardFormatId::STRING );
+ }
+ else
+ bDisable = true;
+
+ bNeedTextComponent = true;
+ bNeedWriteableControl = true;
+ }
+ break;
+
+ case SID_COPY:
+ bNeedTextComponent = true;
+ bNeedSelection = true;
+ break;
+
+ case SID_SELECTALL:
+ bNeedTextComponent = true;
+ break;
+
+ default:
+ // slot is unknown at all
+ bDisable = true;
+ break;
+ }
+ SAL_WARN_IF( bNeedSelection && !bNeedTextComponent, "svx.form", "FmTextControlShell::GetTextAttributeState: bNeedSelection should imply bNeedTextComponent!" );
+
+ if ( !bDisable && bNeedWriteableControl )
+ bDisable |= !IsActiveControl( ) || m_bActiveControlIsReadOnly;
+
+ if ( !bDisable && bNeedTextComponent )
+ bDisable |= !m_xActiveTextComponent.is();
+
+ if ( !bDisable && bNeedSelection )
+ {
+ css::awt::Selection aSelection = m_xActiveTextComponent->getSelection();
+ bDisable |= aSelection.Min == aSelection.Max;
+ }
+
+ if ( bDisable )
+ _rSet.DisableItem( nSlot );
+ }
+
+ nSlot = aIter.NextWhich();
+ }
+ }
+
+
+ bool FmTextControlShell::IsActiveControl( bool _bCountRichTextOnly ) const
+ {
+ if ( _bCountRichTextOnly && !m_bActiveControlIsRichText )
+ return false;
+
+ return m_bActiveControl;
+ }
+
+
+ void FmTextControlShell::dispose()
+ {
+ if ( IsActiveControl() )
+ controlDeactivated();
+ if ( isControllerListening() )
+ stopControllerListening();
+ }
+
+
+ void FmTextControlShell::designModeChanged()
+ {
+ m_rBindings.Invalidate( pTextControlSlots );
+ }
+
+
+ void FmTextControlShell::formActivated( const Reference< runtime::XFormController >& _rxController )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ SAL_INFO("svx.form", "0x" << OUString::number( reinterpret_cast<sal_IntPtr>(_rxController.get()), 16 ));
+#endif
+
+ DBG_ASSERT( _rxController.is(), "FmTextControlShell::formActivated: invalid controller!" );
+ if ( !_rxController.is() )
+ return;
+
+ // sometimes, a form controller notifies activations, even if it's already activated
+ if ( m_xActiveController == _rxController )
+ return;
+
+ try
+ {
+ startControllerListening( _rxController );
+ controlActivated( _rxController->getCurrentControl() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void FmTextControlShell::formDeactivated( const Reference< runtime::XFormController >& _rxController )
+ {
+ SAL_INFO("svx.form", "0x" << OUString::number( reinterpret_cast<sal_IntPtr>(_rxController.get()), 16 ));
+
+ if ( IsActiveControl() )
+ controlDeactivated();
+ if ( isControllerListening() )
+ stopControllerListening();
+ }
+
+
+ void FmTextControlShell::startControllerListening( const Reference< runtime::XFormController >& _rxController )
+ {
+ OSL_PRECOND( _rxController.is(), "FmTextControlShell::startControllerListening: invalid controller!" );
+ if ( !_rxController.is() )
+ return;
+
+ OSL_PRECOND( !isControllerListening(), "FmTextControlShell::startControllerListening: already listening!" );
+ if ( isControllerListening() )
+ stopControllerListening( );
+ DBG_ASSERT( !isControllerListening(), "FmTextControlShell::startControllerListening: inconsistence!" );
+
+ try
+ {
+ const Sequence< Reference< css::awt::XControl > > aControls( _rxController->getControls() );
+ m_aControlObservers.resize( 0 );
+ m_aControlObservers.reserve( aControls.getLength() );
+
+ std::transform(aControls.begin(), aControls.end(), std::back_inserter(m_aControlObservers),
+ [this](const Reference< css::awt::XControl >& rControl) -> FocusListenerAdapter {
+ return FocusListenerAdapter( new FmFocusListenerAdapter( rControl, this ) ); });
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ m_xActiveController = _rxController;
+ }
+
+
+ void FmTextControlShell::stopControllerListening( )
+ {
+ OSL_PRECOND( isControllerListening(), "FmTextControlShell::stopControllerListening: inconsistence!" );
+
+ // dispose all listeners associated with the controls of the active controller
+ for (auto& rpObserver : m_aControlObservers)
+ {
+ rpObserver->dispose();
+ }
+
+ FocusListenerAdapters().swap(m_aControlObservers);
+
+ m_xActiveController.clear();
+ }
+
+
+ void FmTextControlShell::implClearActiveControlRef()
+ {
+ // no more features for this control
+ for (auto& rFeature : m_aControlFeatures)
+ {
+ rFeature.second->dispose();
+ }
+
+ ControlFeatures().swap(m_aControlFeatures);
+
+ if ( m_aContextMenuObserver )
+ {
+ m_aContextMenuObserver->dispose();
+ m_aContextMenuObserver = MouseListenerAdapter();
+ }
+
+ if ( m_xActiveTextComponent.is() )
+ {
+ SAL_INFO("svx.form", "stopping timer for clipboard invalidation" );
+ m_aClipboardInvalidation.Stop();
+ }
+ // no more active control
+ m_xActiveControl.clear();
+ m_xActiveTextComponent.clear();
+ m_bActiveControlIsReadOnly = true;
+ m_bActiveControlIsRichText = false;
+ m_bActiveControl = false;
+ }
+
+
+ void FmTextControlShell::controlDeactivated( )
+ {
+ DBG_ASSERT( IsActiveControl(), "FmTextControlShell::controlDeactivated: no active control!" );
+
+ m_bActiveControl = false;
+
+ m_rBindings.Invalidate( pTextControlSlots );
+ }
+
+
+ void FmTextControlShell::controlActivated( const Reference< css::awt::XControl >& _rxControl )
+ {
+ // ensure that all knittings with the previously active control are lost
+ if ( m_xActiveControl.is() )
+ implClearActiveControlRef();
+ DBG_ASSERT( m_aControlFeatures.empty(), "FmTextControlShell::controlActivated: should have no dispatchers when I'm here!" );
+
+#if OSL_DEBUG_LEVEL > 0
+ {
+ Sequence< Reference< css::awt::XControl > > aActiveControls;
+ if ( m_xActiveController.is() )
+ aActiveControls = m_xActiveController->getControls();
+
+ bool bFoundThisControl = false;
+
+ const Reference< css::awt::XControl >* pControls = aActiveControls.getConstArray();
+ const Reference< css::awt::XControl >* pControlsEnd = pControls + aActiveControls.getLength();
+ for ( ; ( pControls != pControlsEnd ) && !bFoundThisControl; ++pControls )
+ {
+ if ( *pControls == _rxControl )
+ bFoundThisControl = true;
+ }
+ DBG_ASSERT( bFoundThisControl, "FmTextControlShell::controlActivated: only controls which belong to the active controller can be activated!" );
+ }
+#endif
+ // ask the control for dispatchers for our text-related slots
+ fillFeatureDispatchers( _rxControl, pTextControlSlots, m_aControlFeatures );
+
+ // remember this control
+ m_xActiveControl = _rxControl;
+ m_xActiveTextComponent.set(_rxControl, css::uno::UNO_QUERY);
+ m_bActiveControlIsReadOnly = lcl_determineReadOnly( m_xActiveControl );
+ m_bActiveControlIsRichText = lcl_isRichText( m_xActiveControl );
+
+ // if we found a rich text control, we need context menu support
+ if ( m_bActiveControlIsRichText )
+ {
+ DBG_ASSERT( !m_aContextMenuObserver, "FmTextControlShell::controlActivated: already have an observer!" );
+ m_aContextMenuObserver = MouseListenerAdapter( new FmMouseListenerAdapter( _rxControl, this ) );
+ }
+
+ if ( m_xActiveTextComponent.is() )
+ {
+ SAL_INFO("svx.form", "starting timer for clipboard invalidation" );
+ m_aClipboardInvalidation.Start();
+ }
+
+ m_bActiveControl = true;
+
+ m_rBindings.Invalidate( pTextControlSlots );
+
+ if ( m_pViewFrame )
+ m_pViewFrame->UIFeatureChanged();
+
+ // don't call the activation handler if we don't have any slots we can serve
+ // The activation handler is used to put the shell on the top of the dispatcher stack,
+ // so it's preferred when slots are distributed.
+ // Note that this is a slight hack, to prevent that we grab slots from the SfxDispatcher
+ // which should be served by other shells (e.g. Cut/Copy/Paste).
+ // A real solution would be a forwarding-mechanism for slots: We should be on the top
+ // if we're active, but if we cannot handle the slot, then we need to tell the dispatcher
+ // to skip our shell, and pass the slot to the next one. However, this mechanism is not
+ // not in place in SFX.
+ // Another possibility would be to have dedicated shells for the slots which we might
+ // or might not be able to serve. However, this could probably increase the number of
+ // shells too much (In theory, nearly every slot could have an own shell then).
+
+ // #i51621# / 2005-08-19 / frank.schoenheit@sun.com
+ // bool bHaveAnyServeableSlots = m_xActiveTextComponent.is() || !m_aControlFeatures.empty();
+ // LEM: not calling m_aControlActivatonHandler causes fdo#63695, so disable this hack for now.
+ m_aControlActivationHandler.Call( nullptr );
+
+ m_bNeedClipboardInvalidation = true;
+ }
+
+
+ void FmTextControlShell::fillFeatureDispatchers(const Reference< css::awt::XControl >& _rxControl, SfxSlotId* _pZeroTerminatedSlots,
+ ControlFeatures& _rDispatchers)
+ {
+ Reference< XDispatchProvider > xProvider( _rxControl, UNO_QUERY );
+ SfxApplication* pApplication = SfxGetpApp();
+ DBG_ASSERT( pApplication, "FmTextControlShell::fillFeatureDispatchers: no SfxApplication!" );
+ if ( xProvider.is() && pApplication )
+ {
+ SfxSlotId* pSlots = _pZeroTerminatedSlots;
+ while ( *pSlots )
+ {
+ rtl::Reference<FmTextControlFeature> pDispatcher = implGetFeatureDispatcher( xProvider, pApplication, *pSlots );
+ if ( pDispatcher )
+ _rDispatchers.emplace( *pSlots, pDispatcher );
+
+ ++pSlots;
+ }
+ }
+ }
+
+
+ rtl::Reference<FmTextControlFeature> FmTextControlShell::implGetFeatureDispatcher( const Reference< XDispatchProvider >& _rxProvider, SfxApplication const * _pApplication, SfxSlotId _nSlot )
+ {
+ OSL_PRECOND( _rxProvider.is() && _pApplication, "FmTextControlShell::implGetFeatureDispatcher: invalid arg(s)!" );
+ URL aFeatureURL;
+ aFeatureURL.Complete = lcl_getUnoSlotName( _nSlot );
+ try
+ {
+ if ( !m_xURLTransformer.is() )
+ {
+ m_xURLTransformer = util::URLTransformer::create( ::comphelper::getProcessComponentContext() );
+ }
+ if ( m_xURLTransformer.is() )
+ m_xURLTransformer->parseStrict( aFeatureURL );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ Reference< XDispatch > xDispatcher = _rxProvider->queryDispatch( aFeatureURL, OUString(), 0xFF );
+ if ( xDispatcher.is() )
+ return new FmTextControlFeature( xDispatcher, aFeatureURL, _nSlot, this );
+ return nullptr;
+ }
+
+
+ void FmTextControlShell::Invalidate( SfxSlotId _nSlot )
+ {
+ m_rBindings.Invalidate( _nSlot );
+ // despite this method being called "Invalidate", we also update here - this gives more immediate
+ // feedback in the UI
+ m_rBindings.Update( _nSlot );
+ }
+
+
+ void FmTextControlShell::focusGained( const css::awt::FocusEvent& _rEvent )
+ {
+ Reference< css::awt::XControl > xControl( _rEvent.Source, UNO_QUERY );
+
+#if OSL_DEBUG_LEVEL > 0
+ SAL_INFO("svx.form", "0x" << OUString::number( reinterpret_cast<sal_IntPtr>(xControl.get()), 16 ));
+#endif
+
+ DBG_ASSERT( xControl.is(), "FmTextControlShell::focusGained: suspicious focus event!" );
+ if ( xControl.is() )
+ controlActivated( xControl );
+ }
+
+
+ void FmTextControlShell::focusLost( const css::awt::FocusEvent& _rEvent )
+ {
+ Reference< css::awt::XControl > xControl( _rEvent.Source, UNO_QUERY );
+
+#if OSL_DEBUG_LEVEL > 0
+ SAL_INFO("svx.form", "0x" << OUString::number( reinterpret_cast<sal_IntPtr>(xControl.get()), 16 ));
+#endif
+
+ m_bActiveControl = false;
+ }
+
+
+ void FmTextControlShell::ForgetActiveControl()
+ {
+ implClearActiveControlRef();
+ }
+
+
+ void FmTextControlShell::contextMenuRequested()
+ {
+ m_rBindings.GetDispatcher()->ExecutePopup( "formrichtext" );
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmtools.cxx b/svx/source/form/fmtools.cxx
new file mode 100644
index 000000000..1089754d5
--- /dev/null
+++ b/svx/source/form/fmtools.cxx
@@ -0,0 +1,371 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <fmprop.hxx>
+#include <fmservs.hxx>
+#include <svx/fmtools.hxx>
+#include <svx/svdobjkind.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/io/XPersistObject.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/sdb/ErrorMessageDialog.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdb/SQLErrorEvent.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdb/XResultSetAccess.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/util/Language.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::form;
+using namespace ::svxform;
+
+
+namespace
+{
+ bool lcl_shouldDisplayError( const Any& _rError )
+ {
+ SQLException aError;
+ if ( !( _rError >>= aError ) )
+ return true;
+
+ if ( ! aError.Message.startsWith( "[OOoBase]" ) )
+ // it is an exception *not* thrown by an OOo Base core component
+ return true;
+
+ // the only exception we do not display ATM is a RowSetVetoException, which
+ // has been raised because an XRowSetApprovalListener vetoed a change
+ if ( aError.ErrorCode + ErrorCondition::ROW_SET_OPERATION_VETOED == 0 )
+ return false;
+
+ // everything else is to be displayed
+ return true;
+ }
+}
+
+void displayException(const Any& _rExcept, const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ // check whether we need to display it
+ if ( !lcl_shouldDisplayError( _rExcept ) )
+ return;
+
+ try
+ {
+ Reference< XExecutableDialog > xErrorDialog = ErrorMessageDialog::create(::comphelper::getProcessComponentContext(), "", rParent, _rExcept);
+ xErrorDialog->execute();
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "could not display the error message!");
+ }
+}
+
+void displayException(const css::sdbc::SQLException& _rExcept, const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ displayException(Any(_rExcept), rParent);
+}
+
+void displayException(const css::sdb::SQLContext& _rExcept, const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ displayException(Any(_rExcept), rParent);
+}
+
+void displayException(const css::sdb::SQLErrorEvent& _rEvent, const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ displayException(_rEvent.Reason, rParent);
+}
+
+sal_Int32 getElementPos(const Reference< css::container::XIndexAccess>& xCont, const Reference< XInterface >& xElement)
+{
+ sal_Int32 nIndex = -1;
+ if (!xCont.is())
+ return nIndex;
+
+
+ Reference< XInterface > xNormalized( xElement, UNO_QUERY );
+ DBG_ASSERT( xNormalized.is(), "getElementPos: invalid element!" );
+ if ( xNormalized.is() )
+ {
+ // find child position
+ nIndex = xCont->getCount();
+ while (nIndex--)
+ {
+ try
+ {
+ Reference< XInterface > xCurrent(xCont->getByIndex( nIndex ),UNO_QUERY);
+ DBG_ASSERT( xCurrent.get() == Reference< XInterface >( xCurrent, UNO_QUERY ).get(),
+ "getElementPos: container element not normalized!" );
+ if ( xNormalized.get() == xCurrent.get() )
+ break;
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "getElementPos" );
+ }
+
+ }
+ }
+ return nIndex;
+}
+
+
+OUString getLabelName(const Reference< css::beans::XPropertySet>& xControlModel)
+{
+ if (!xControlModel.is())
+ return OUString();
+
+ if (::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xControlModel))
+ {
+ Reference< css::beans::XPropertySet> xLabelSet;
+ xControlModel->getPropertyValue(FM_PROP_CONTROLLABEL) >>= xLabelSet;
+ if (xLabelSet.is() && ::comphelper::hasProperty(FM_PROP_LABEL, xLabelSet))
+ {
+ Any aLabel( xLabelSet->getPropertyValue(FM_PROP_LABEL) );
+ if ((aLabel.getValueTypeClass() == TypeClass_STRING) && !::comphelper::getString(aLabel).isEmpty())
+ return ::comphelper::getString(aLabel);
+ }
+ }
+
+ return ::comphelper::getString(xControlModel->getPropertyValue(FM_PROP_CONTROLSOURCE));
+}
+
+
+// = CursorWrapper
+
+CursorWrapper::CursorWrapper(const Reference< css::sdbc::XRowSet>& _rxCursor, bool bUseCloned)
+{
+ ImplConstruct(Reference< css::sdbc::XResultSet>(_rxCursor), bUseCloned);
+}
+
+
+CursorWrapper::CursorWrapper(const Reference< css::sdbc::XResultSet>& _rxCursor, bool bUseCloned)
+{
+ ImplConstruct(_rxCursor, bUseCloned);
+}
+
+
+void CursorWrapper::ImplConstruct(const Reference< css::sdbc::XResultSet>& _rxCursor, bool bUseCloned)
+{
+ if (bUseCloned)
+ {
+ Reference< css::sdb::XResultSetAccess> xAccess(_rxCursor, UNO_QUERY);
+ try
+ {
+ m_xMoveOperations = xAccess.is() ? xAccess->createResultSet() : Reference< css::sdbc::XResultSet>();
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ else
+ m_xMoveOperations = _rxCursor;
+
+ m_xBookmarkOperations.set(m_xMoveOperations, css::uno::UNO_QUERY);
+ m_xColumnsSupplier.set(m_xMoveOperations, css::uno::UNO_QUERY);
+ m_xPropertyAccess.set(m_xMoveOperations, css::uno::UNO_QUERY);
+
+ if ( !m_xMoveOperations.is() || !m_xBookmarkOperations.is() || !m_xColumnsSupplier.is() || !m_xPropertyAccess.is() )
+ { // all or nothing !!
+ m_xMoveOperations = nullptr;
+ m_xBookmarkOperations = nullptr;
+ m_xColumnsSupplier = nullptr;
+ }
+ else
+ m_xGeneric = m_xMoveOperations.get();
+}
+
+CursorWrapper& CursorWrapper::operator=(const Reference< css::sdbc::XRowSet>& _rxCursor)
+{
+ m_xMoveOperations.set(_rxCursor);
+ m_xBookmarkOperations.set(_rxCursor, UNO_QUERY);
+ m_xColumnsSupplier.set(_rxCursor, UNO_QUERY);
+ if (!m_xMoveOperations.is() || !m_xBookmarkOperations.is() || !m_xColumnsSupplier.is())
+ { // all or nothing !!
+ m_xMoveOperations = nullptr;
+ m_xBookmarkOperations = nullptr;
+ m_xColumnsSupplier = nullptr;
+ }
+ return *this;
+}
+
+FmXDisposeListener::~FmXDisposeListener()
+{
+ setAdapter(nullptr);
+}
+
+void FmXDisposeListener::setAdapter(FmXDisposeMultiplexer* pAdapter)
+{
+ std::scoped_lock aGuard(m_aMutex);
+ m_pAdapter = pAdapter;
+}
+
+FmXDisposeMultiplexer::FmXDisposeMultiplexer(FmXDisposeListener* _pListener, const Reference< css::lang::XComponent>& _rxObject)
+ :m_xObject(_rxObject)
+ ,m_pListener(_pListener)
+{
+ m_pListener->setAdapter(this);
+
+ if (m_xObject.is())
+ m_xObject->addEventListener(this);
+}
+
+FmXDisposeMultiplexer::~FmXDisposeMultiplexer()
+{
+}
+
+// css::lang::XEventListener
+
+void FmXDisposeMultiplexer::disposing(const css::lang::EventObject& /*Source*/)
+{
+ Reference< css::lang::XEventListener> xPreventDelete(this);
+
+ if (m_pListener)
+ {
+ m_pListener->disposing(0);
+ m_pListener->setAdapter(nullptr);
+ m_pListener = nullptr;
+ }
+ m_xObject = nullptr;
+}
+
+
+void FmXDisposeMultiplexer::dispose()
+{
+ if (m_xObject.is())
+ {
+ Reference< css::lang::XEventListener> xPreventDelete(this);
+
+ m_xObject->removeEventListener(this);
+ m_xObject = nullptr;
+
+ m_pListener->setAdapter(nullptr);
+ m_pListener = nullptr;
+ }
+}
+
+
+SdrObjKind getControlTypeByObject(const Reference< css::lang::XServiceInfo>& _rxObject)
+{
+ // ask for the persistent service name
+ Reference< css::io::XPersistObject> xPersistence(_rxObject, UNO_QUERY);
+ DBG_ASSERT(xPersistence.is(), "::getControlTypeByObject : argument should be a css::io::XPersistObject !");
+ if (!xPersistence.is())
+ return SdrObjKind::FormControl;
+
+ OUString sPersistentServiceName = xPersistence->getServiceName();
+ if (sPersistentServiceName == FM_COMPONENT_EDIT) // 5.0-Name
+ {
+ // may be a simple edit field or a formatted field, dependent of the supported services
+ if (_rxObject->supportsService(FM_SUN_COMPONENT_FORMATTEDFIELD))
+ return SdrObjKind::FormFormattedField;
+ return SdrObjKind::FormEdit;
+ }
+ if (sPersistentServiceName == FM_COMPONENT_TEXTFIELD)
+ return SdrObjKind::FormEdit;
+ if (sPersistentServiceName == FM_COMPONENT_COMMANDBUTTON)
+ return SdrObjKind::FormButton;
+ if (sPersistentServiceName == FM_COMPONENT_FIXEDTEXT)
+ return SdrObjKind::FormFixedText;
+ if (sPersistentServiceName == FM_COMPONENT_LISTBOX)
+ return SdrObjKind::FormListbox;
+ if (sPersistentServiceName == FM_COMPONENT_CHECKBOX)
+ return SdrObjKind::FormCheckbox;
+ if (sPersistentServiceName == FM_COMPONENT_RADIOBUTTON)
+ return SdrObjKind::FormRadioButton;
+ if (sPersistentServiceName == FM_COMPONENT_GROUPBOX)
+ return SdrObjKind::FormGroupBox;
+ if (sPersistentServiceName == FM_COMPONENT_COMBOBOX)
+ return SdrObjKind::FormCombobox;
+ if (sPersistentServiceName == FM_COMPONENT_GRID) // 5.0-Name
+ return SdrObjKind::FormGrid;
+ if (sPersistentServiceName == FM_COMPONENT_GRIDCONTROL)
+ return SdrObjKind::FormGrid;
+ if (sPersistentServiceName == FM_COMPONENT_IMAGEBUTTON)
+ return SdrObjKind::FormImageButton;
+ if (sPersistentServiceName == FM_COMPONENT_FILECONTROL)
+ return SdrObjKind::FormFileControl;
+ if (sPersistentServiceName == FM_COMPONENT_DATEFIELD)
+ return SdrObjKind::FormDateField;
+ if (sPersistentServiceName == FM_COMPONENT_TIMEFIELD)
+ return SdrObjKind::FormTimeField;
+ if (sPersistentServiceName == FM_COMPONENT_NUMERICFIELD)
+ return SdrObjKind::FormNumericField;
+ if (sPersistentServiceName == FM_COMPONENT_CURRENCYFIELD)
+ return SdrObjKind::FormCurrencyField;
+ if (sPersistentServiceName == FM_COMPONENT_PATTERNFIELD)
+ return SdrObjKind::FormPatternField;
+ if (sPersistentServiceName == FM_COMPONENT_HIDDEN) // 5.0-Name
+ return SdrObjKind::FormHidden;
+ if (sPersistentServiceName == FM_COMPONENT_HIDDENCONTROL)
+ return SdrObjKind::FormHidden;
+ if (sPersistentServiceName == FM_COMPONENT_IMAGECONTROL)
+ return SdrObjKind::FormImageControl;
+ if (sPersistentServiceName == FM_COMPONENT_FORMATTEDFIELD)
+ {
+ OSL_FAIL("::getControlTypeByObject : suspicious persistent service name (formatted field) !");
+ // objects with that service name should exist as they aren't compatible with older versions
+ return SdrObjKind::FormFormattedField;
+ }
+ if ( sPersistentServiceName == FM_SUN_COMPONENT_SCROLLBAR )
+ return SdrObjKind::FormScrollbar;
+ if ( sPersistentServiceName == FM_SUN_COMPONENT_SPINBUTTON )
+ return SdrObjKind::FormSpinButton;
+ if ( sPersistentServiceName == FM_SUN_COMPONENT_NAVIGATIONBAR )
+ return SdrObjKind::FormNavigationBar;
+
+ OSL_FAIL("::getControlTypeByObject : unknown object type !");
+ return SdrObjKind::FormControl;
+}
+
+
+bool isRowSetAlive(const Reference< XInterface >& _rxRowSet)
+{
+ bool bIsAlive = false;
+ Reference< css::sdbcx::XColumnsSupplier> xSupplyCols(_rxRowSet, UNO_QUERY);
+ Reference< css::container::XIndexAccess> xCols;
+ if (xSupplyCols.is())
+ xCols.set(xSupplyCols->getColumns(), UNO_QUERY);
+ if (xCols.is() && (xCols->getCount() > 0))
+ bIsAlive = true;
+
+ return bIsAlive;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmundo.cxx b/svx/source/form/fmundo.cxx
new file mode 100644
index 000000000..57593d36c
--- /dev/null
+++ b/svx/source/form/fmundo.cxx
@@ -0,0 +1,1263 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <map>
+
+#include <sal/macros.h>
+#include <fmundo.hxx>
+#include <fmpgeimp.hxx>
+#include <svx/svditer.hxx>
+#include <fmobj.hxx>
+#include <fmprop.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmpage.hxx>
+
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XListEntrySink.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <svx/fmtools.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <sfx2/objsh.hxx>
+#include <sfx2/event.hxx>
+#include <osl/mutex.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::form::binding;
+using namespace ::com::sun::star::sdbc;
+using namespace ::svxform;
+using namespace ::dbtools;
+
+
+#include <com/sun/star/script/XScriptListener.hpp>
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/implbase.hxx>
+
+namespace {
+
+class ScriptEventListenerWrapper : public cppu::WeakImplHelper< XScriptListener >
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScriptEventListenerWrapper( FmFormModel& _rModel)
+ :m_rModel( _rModel )
+ ,m_attemptedListenerCreation( false )
+ {
+
+ }
+ // XEventListener
+ virtual void SAL_CALL disposing(const EventObject& ) override {}
+
+ // XScriptListener
+ virtual void SAL_CALL firing(const ScriptEvent& evt) override
+ {
+ attemptListenerCreation();
+ if ( m_vbaListener.is() )
+ {
+ m_vbaListener->firing( evt );
+ }
+ }
+
+ virtual Any SAL_CALL approveFiring(const ScriptEvent& evt) override
+ {
+ attemptListenerCreation();
+ if ( m_vbaListener.is() )
+ {
+ return m_vbaListener->approveFiring( evt );
+ }
+ return Any();
+ }
+
+private:
+ void attemptListenerCreation()
+ {
+ if ( m_attemptedListenerCreation )
+ return;
+ m_attemptedListenerCreation = true;
+
+ try
+ {
+ css::uno::Reference<css::uno::XComponentContext> context(
+ comphelper::getProcessComponentContext());
+ Reference< XScriptListener > const xScriptListener(
+ context->getServiceManager()->createInstanceWithContext(
+ "ooo.vba.EventListener", context),
+ UNO_QUERY_THROW);
+ Reference< XPropertySet > const xListenerProps( xScriptListener, UNO_QUERY_THROW );
+ // SfxObjectShellRef is good here since the model controls the lifetime of the shell
+ SfxObjectShellRef const xObjectShell = m_rModel.GetObjectShell();
+ ENSURE_OR_THROW( xObjectShell.is(), "no object shell!" );
+ xListenerProps->setPropertyValue("Model", Any( xObjectShell->GetModel() ) );
+
+ m_vbaListener = xScriptListener;
+ }
+ catch( Exception const & )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ FmFormModel& m_rModel;
+ Reference< XScriptListener > m_vbaListener;
+ bool m_attemptedListenerCreation;
+
+
+};
+
+
+// some helper structs for caching property infos
+
+struct PropertyInfo
+{
+ bool bIsTransientOrReadOnly : 1; // the property is transient or read-only, thus we need no undo action for it
+ bool bIsValueProperty : 1; // the property is the special value property, thus it may be handled
+ // as if it's transient or persistent
+};
+
+struct PropertySetInfo
+{
+ typedef std::map<OUString, PropertyInfo> AllProperties;
+
+ AllProperties aProps; // all properties of this set which we know so far
+ bool bHasEmptyControlSource; // sal_True -> the set has a DataField property, and the current value is an empty string
+ // sal_False -> the set has _no_ such property or its value isn't empty
+};
+
+}
+
+typedef std::map<Reference< XPropertySet >, PropertySetInfo> PropertySetInfoCache;
+
+
+static OUString static_STR_UNDO_PROPERTY;
+
+
+FmXUndoEnvironment::FmXUndoEnvironment(FmFormModel& _rModel)
+ :rModel( _rModel )
+ ,m_pPropertySetCache( nullptr )
+ ,m_pScriptingEnv( new svxform::FormScriptingEnvironment( _rModel ) )
+ ,m_Locks( 0 )
+ ,bReadOnly( false )
+ ,m_bDisposed( false )
+{
+ try
+ {
+ m_vbaListener = new ScriptEventListenerWrapper( _rModel );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+FmXUndoEnvironment::~FmXUndoEnvironment()
+{
+ if ( !m_bDisposed ) // i120746, call FormScriptingEnvironment::dispose to avoid memory leak
+ m_pScriptingEnv->dispose();
+
+ if (m_pPropertySetCache)
+ delete static_cast<PropertySetInfoCache*>(m_pPropertySetCache);
+}
+
+void FmXUndoEnvironment::dispose()
+{
+ OSL_ENSURE( !m_bDisposed, "FmXUndoEnvironment::dispose: disposed twice?" );
+ if ( !m_bDisposed )
+ return;
+
+ Lock();
+
+ sal_uInt16 nCount = rModel.GetPageCount();
+ sal_uInt16 i;
+ for (i = 0; i < nCount; i++)
+ {
+ FmFormPage* pPage = dynamic_cast<FmFormPage*>( rModel.GetPage(i) );
+ if ( pPage )
+ {
+ Reference< css::form::XForms > xForms = pPage->GetForms( false );
+ if ( xForms.is() )
+ RemoveElement( xForms );
+ }
+ }
+
+ nCount = rModel.GetMasterPageCount();
+ for (i = 0; i < nCount; i++)
+ {
+ FmFormPage* pPage = dynamic_cast<FmFormPage*>( rModel.GetMasterPage(i) );
+ if ( pPage )
+ {
+ Reference< css::form::XForms > xForms = pPage->GetForms( false );
+ if ( xForms.is() )
+ RemoveElement( xForms );
+ }
+ }
+
+ UnLock();
+
+ OSL_PRECOND( rModel.GetObjectShell(), "FmXUndoEnvironment::dispose: no object shell anymore!" );
+ if ( rModel.GetObjectShell() )
+ EndListening( *rModel.GetObjectShell() );
+
+ if ( IsListening( rModel ) )
+ EndListening( rModel );
+
+ m_pScriptingEnv->dispose();
+
+ m_bDisposed = true;
+}
+
+
+void FmXUndoEnvironment::ModeChanged()
+{
+ OSL_PRECOND( rModel.GetObjectShell(), "FmXUndoEnvironment::ModeChanged: no object shell anymore!" );
+ if ( !rModel.GetObjectShell() )
+ return;
+
+ if (bReadOnly == (rModel.GetObjectShell()->IsReadOnly() || rModel.GetObjectShell()->IsReadOnlyUI()))
+ return;
+
+ bReadOnly = !bReadOnly;
+
+ sal_uInt16 nCount = rModel.GetPageCount();
+ sal_uInt16 i;
+ for (i = 0; i < nCount; i++)
+ {
+ FmFormPage* pPage = dynamic_cast<FmFormPage*>( rModel.GetPage(i) );
+ if ( pPage )
+ {
+ Reference< css::form::XForms > xForms = pPage->GetForms( false );
+ if ( xForms.is() )
+ TogglePropertyListening( xForms );
+ }
+ }
+
+ nCount = rModel.GetMasterPageCount();
+ for (i = 0; i < nCount; i++)
+ {
+ FmFormPage* pPage = dynamic_cast<FmFormPage*>( rModel.GetMasterPage(i) );
+ if ( pPage )
+ {
+ Reference< css::form::XForms > xForms = pPage->GetForms( false );
+ if ( xForms.is() )
+ TogglePropertyListening( xForms );
+ }
+ }
+
+ if (!bReadOnly)
+ StartListening(rModel);
+ else
+ EndListening(rModel);
+}
+
+
+void FmXUndoEnvironment::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+{
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ switch (pSdrHint->GetKind())
+ {
+ case SdrHintKind::ObjectInserted:
+ {
+ SdrObject* pSdrObj = const_cast<SdrObject*>(pSdrHint->GetObject());
+ Inserted( pSdrObj );
+ } break;
+ case SdrHintKind::ObjectRemoved:
+ {
+ SdrObject* pSdrObj = const_cast<SdrObject*>(pSdrHint->GetObject());
+ Removed( pSdrObj );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else if (rHint.GetId() != SfxHintId::NONE)
+ {
+ switch (rHint.GetId())
+ {
+ case SfxHintId::Dying:
+ dispose();
+ rModel.SetObjectShell( nullptr );
+ break;
+ case SfxHintId::ModeChanged:
+ ModeChanged();
+ break;
+ default: break;
+ }
+ }
+ else if (const SfxEventHint* pEventHint = dynamic_cast<const SfxEventHint*>(&rHint))
+ {
+ switch (pEventHint->GetEventId())
+ {
+ case SfxEventHintId::CreateDoc:
+ case SfxEventHintId::OpenDoc:
+ ModeChanged();
+ break;
+ default: break;
+ }
+ }
+}
+
+void FmXUndoEnvironment::Inserted(SdrObject* pObj)
+{
+ if (pObj->GetObjInventor() == SdrInventor::FmForm)
+ {
+ FmFormObj* pFormObj = dynamic_cast<FmFormObj*>( pObj );
+ Inserted( pFormObj );
+ }
+ else if (pObj->IsGroupObject())
+ {
+ SdrObjListIter aIter(pObj->GetSubList());
+ while ( aIter.IsMore() )
+ Inserted( aIter.Next() );
+ }
+}
+
+
+namespace
+{
+ bool lcl_searchElement(const Reference< XIndexAccess>& xCont, const Reference< XInterface >& xElement)
+ {
+ if (!xCont.is() || !xElement.is())
+ return false;
+
+ sal_Int32 nCount = xCont->getCount();
+ Reference< XInterface > xComp;
+ for (sal_Int32 i = 0; i < nCount; i++)
+ {
+ try
+ {
+ xCont->getByIndex(i) >>= xComp;
+ if (xComp.is())
+ {
+ if ( xElement == xComp )
+ return true;
+ else
+ {
+ Reference< XIndexAccess> xCont2(xComp, UNO_QUERY);
+ if (xCont2.is() && lcl_searchElement(xCont2, xElement))
+ return true;
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ return false;
+ }
+}
+
+
+void FmXUndoEnvironment::Inserted(FmFormObj* pObj)
+{
+ DBG_ASSERT( pObj, "FmXUndoEnvironment::Inserted: invalid object!" );
+ if ( !pObj )
+ return;
+
+ // is the control still assigned to a form
+ Reference< XInterface > xModel(pObj->GetUnoControlModel(), UNO_QUERY);
+ Reference< XFormComponent > xContent(xModel, UNO_QUERY);
+ if (!(xContent.is() && pObj->getSdrPageFromSdrObject()))
+ return;
+
+ // if the component doesn't belong to a form, yet, find one to insert into
+ if (!xContent->getParent().is())
+ {
+ try
+ {
+ const Reference< XIndexContainer >& xObjectParent = pObj->GetOriginalParent();
+
+ FmFormPage& rPage(dynamic_cast< FmFormPage& >( *pObj->getSdrPageFromSdrObject()));
+ Reference< XIndexAccess > xForms( rPage.GetForms(), UNO_QUERY_THROW );
+
+ Reference< XIndexContainer > xNewParent;
+ Reference< XForm > xForm;
+ sal_Int32 nPos = -1;
+ if ( lcl_searchElement( xForms, xObjectParent ) )
+ {
+ // the form which was the parent of the object when it was removed is still
+ // part of the form component hierarchy of the current page
+ xNewParent = xObjectParent;
+ xForm.set( xNewParent, UNO_QUERY_THROW );
+ nPos = ::std::min( pObj->GetOriginalIndex(), xNewParent->getCount() );
+ }
+ else
+ {
+ xForm.set( rPage.GetImpl().findPlaceInFormComponentHierarchy( xContent ), UNO_SET_THROW );
+ xNewParent.set( xForm, UNO_QUERY_THROW );
+ nPos = xNewParent->getCount();
+ }
+
+ FmFormPageImpl::setUniqueName( xContent, xForm );
+ xNewParent->insertByIndex( nPos, Any( xContent ) );
+
+ Reference< XEventAttacherManager > xManager( xNewParent, UNO_QUERY_THROW );
+ xManager->registerScriptEvents( nPos, pObj->GetOriginalEvents() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+ // reset FormObject
+ pObj->ClearObjEnv();
+}
+
+
+void FmXUndoEnvironment::Removed(SdrObject* pObj)
+{
+ if ( pObj->IsVirtualObj() )
+ // for virtual objects, we've already been notified of the removal of the master
+ // object, which is sufficient here
+ return;
+
+ if (pObj->GetObjInventor() == SdrInventor::FmForm)
+ {
+ FmFormObj* pFormObj = dynamic_cast<FmFormObj*>( pObj );
+ Removed(pFormObj);
+ }
+ else if (pObj->IsGroupObject())
+ {
+ SdrObjListIter aIter(pObj->GetSubList());
+ while ( aIter.IsMore() )
+ Removed( aIter.Next() );
+ }
+}
+
+
+void FmXUndoEnvironment::Removed(FmFormObj* pObj)
+{
+ DBG_ASSERT( pObj, "FmXUndoEnvironment::Removed: invalid object!" );
+ if ( !pObj )
+ return;
+
+ // is the control still assigned to a form
+ Reference< XFormComponent > xContent(pObj->GetUnoControlModel(), UNO_QUERY);
+ if (!xContent.is())
+ return;
+
+ // The object is taken out of a list.
+ // If a father exists, the object is removed at the father and
+ // noted at the FormObject!
+
+ // If the object is reinserted and a parent exists, this parent is set though.
+ Reference< XIndexContainer > xForm(xContent->getParent(), UNO_QUERY);
+ if (!xForm.is())
+ return;
+
+ // determine which position the child was at
+ const sal_Int32 nPos = getElementPos(xForm, xContent);
+ if (nPos < 0)
+ return;
+
+ Sequence< ScriptEventDescriptor > aEvts;
+ Reference< XEventAttacherManager > xManager(xForm, UNO_QUERY);
+ if (xManager.is())
+ aEvts = xManager->getScriptEvents(nPos);
+
+ try
+ {
+ pObj->SetObjEnv(xForm, nPos, aEvts);
+ xForm->removeByIndex(nPos);
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+// XEventListener
+
+void SAL_CALL FmXUndoEnvironment::disposing(const EventObject& e)
+{
+ // check if it's an object we have cached information about
+ if (m_pPropertySetCache)
+ {
+ Reference< XPropertySet > xSourceSet(e.Source, UNO_QUERY);
+ if (xSourceSet.is())
+ {
+ PropertySetInfoCache* pCache = static_cast<PropertySetInfoCache*>(m_pPropertySetCache);
+ PropertySetInfoCache::iterator aSetPos = pCache->find(xSourceSet);
+ if (aSetPos != pCache->end())
+ pCache->erase(aSetPos);
+ }
+ }
+}
+
+// XPropertyChangeListener
+
+void SAL_CALL FmXUndoEnvironment::propertyChange(const PropertyChangeEvent& evt)
+{
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ if (!IsLocked())
+ {
+ Reference< XPropertySet > xSet(evt.Source, UNO_QUERY);
+ if (!xSet.is())
+ return;
+
+ // if it's a "default value" property of a control model, set the according "value" property
+ static constexpr rtl::OUStringConstExpr pDefaultValueProperties[] = {
+ FM_PROP_DEFAULT_TEXT, FM_PROP_DEFAULTCHECKED, FM_PROP_DEFAULT_DATE, FM_PROP_DEFAULT_TIME,
+ FM_PROP_DEFAULT_VALUE, FM_PROP_DEFAULT_SELECT_SEQ, FM_PROP_EFFECTIVE_DEFAULT
+ };
+ static constexpr rtl::OUStringConstExpr aValueProperties[] = {
+ FM_PROP_TEXT, FM_PROP_STATE, FM_PROP_DATE, FM_PROP_TIME,
+ FM_PROP_VALUE, FM_PROP_SELECT_SEQ, FM_PROP_EFFECTIVE_VALUE
+ };
+ sal_Int32 nDefaultValueProps = SAL_N_ELEMENTS(pDefaultValueProperties);
+ OSL_ENSURE(SAL_N_ELEMENTS(aValueProperties) == nDefaultValueProps,
+ "FmXUndoEnvironment::propertyChange: inconsistence!");
+ for (sal_Int32 i=0; i<nDefaultValueProps; ++i)
+ {
+ if (evt.PropertyName == pDefaultValueProperties[i])
+ {
+ try
+ {
+ xSet->setPropertyValue(aValueProperties[i], evt.NewValue);
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("FmXUndoEnvironment::propertyChange: could not adjust the value property!");
+ }
+ }
+ }
+
+ // no Undo for transient and readonly props. But unfortunately "transient" is not only that the
+ // "transient" flag is set for the property in question, instead it is somewhat more complex
+ // Transience criterions are:
+ // - the "transient" flag is set for the property
+ // - OR the control has a non-empty COntrolSource property, i.e. is intended to be bound
+ // to a database column. Note that it doesn't matter here whether the control actually
+ // *is* bound to a column
+ // - OR the control is bound to an external value via XBindableValue/XValueBinding
+ // which does not have a "ExternalData" property being <TRUE/>
+
+ if (!m_pPropertySetCache)
+ m_pPropertySetCache = new PropertySetInfoCache;
+ PropertySetInfoCache* pCache = static_cast<PropertySetInfoCache*>(m_pPropertySetCache);
+
+ // let's see if we know something about the set
+ PropertySetInfoCache::iterator aSetPos = pCache->find(xSet);
+ if (aSetPos == pCache->end())
+ {
+ PropertySetInfo aNewEntry;
+ if (!::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xSet))
+ {
+ aNewEntry.bHasEmptyControlSource = false;
+ }
+ else
+ {
+ try
+ {
+ Any aCurrentControlSource = xSet->getPropertyValue(FM_PROP_CONTROLSOURCE);
+ aNewEntry.bHasEmptyControlSource = !aCurrentControlSource.hasValue() || ::comphelper::getString(aCurrentControlSource).isEmpty();
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ aSetPos = pCache->emplace(xSet,aNewEntry).first;
+ DBG_ASSERT(aSetPos != pCache->end(), "FmXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?");
+ }
+ else
+ { // is it the DataField property ?
+ if (evt.PropertyName == FM_PROP_CONTROLSOURCE)
+ {
+ aSetPos->second.bHasEmptyControlSource = !evt.NewValue.hasValue() || ::comphelper::getString(evt.NewValue).isEmpty();
+ }
+ }
+
+ // now we have access to the cached info about the set
+ // let's see what we know about the property
+ PropertySetInfo::AllProperties& rPropInfos = aSetPos->second.aProps;
+ PropertySetInfo::AllProperties::iterator aPropertyPos = rPropInfos.find(evt.PropertyName);
+ if (aPropertyPos == rPropInfos.end())
+ { // nothing 'til now ... have to change this...
+ PropertyInfo aNewEntry;
+
+ // the attributes
+ sal_Int32 nAttributes = xSet->getPropertySetInfo()->getPropertyByName(evt.PropertyName).Attributes;
+ aNewEntry.bIsTransientOrReadOnly = ((nAttributes & PropertyAttribute::READONLY) != 0) || ((nAttributes & PropertyAttribute::TRANSIENT) != 0);
+
+ // check if it is the special "DataFieldProperty"
+ aNewEntry.bIsValueProperty = false;
+ try
+ {
+ if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCEPROPERTY, xSet))
+ {
+ Any aControlSourceProperty = xSet->getPropertyValue(FM_PROP_CONTROLSOURCEPROPERTY);
+ OUString sControlSourceProperty;
+ aControlSourceProperty >>= sControlSourceProperty;
+
+ aNewEntry.bIsValueProperty = (sControlSourceProperty == evt.PropertyName);
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ // insert the new entry
+ aPropertyPos = rPropInfos.emplace(evt.PropertyName,aNewEntry).first;
+ DBG_ASSERT(aPropertyPos != rPropInfos.end(), "FmXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?");
+ }
+
+ // now we have access to the cached info about the property affected
+ // and are able to decide whether or not we need an undo action
+
+ bool bAddUndoAction = rModel.IsUndoEnabled();
+ // no UNDO for transient/readonly properties
+ if ( bAddUndoAction && aPropertyPos->second.bIsTransientOrReadOnly )
+ bAddUndoAction = false;
+
+ if ( bAddUndoAction && aPropertyPos->second.bIsValueProperty )
+ {
+ // no UNDO when the "value" property changes, but the ControlSource is non-empty
+ // (in this case the control is intended to be bound to a database column)
+ if ( !aSetPos->second.bHasEmptyControlSource )
+ bAddUndoAction = false;
+
+ // no UNDO if the control is currently bound to an external value
+ if ( bAddUndoAction )
+ {
+ Reference< XBindableValue > xBindable( evt.Source, UNO_QUERY );
+ Reference< XValueBinding > xBinding;
+ if ( xBindable.is() )
+ xBinding = xBindable->getValueBinding();
+
+ Reference< XPropertySet > xBindingProps;
+ Reference< XPropertySetInfo > xBindingPropsPSI;
+ if ( xBindable.is() )
+ xBindingProps.set( xBinding, UNO_QUERY );
+ if ( xBindingProps.is() )
+ xBindingPropsPSI = xBindingProps->getPropertySetInfo();
+ // TODO: we should cache all those things, else this might be too expensive.
+ // However, this requires we're notified of changes in the value binding
+
+ static constexpr OUStringLiteral s_sExternalData = u"ExternalData";
+ if ( xBindingPropsPSI.is() && xBindingPropsPSI->hasPropertyByName( s_sExternalData ) )
+ {
+ bool bExternalData = true;
+ OSL_VERIFY( xBindingProps->getPropertyValue( s_sExternalData ) >>= bExternalData );
+ bAddUndoAction = !bExternalData;
+ }
+ else
+ bAddUndoAction = !xBinding.is();
+ }
+ }
+
+ if ( bAddUndoAction && ( evt.PropertyName == FM_PROP_STRINGITEMLIST ) )
+ {
+ Reference< XListEntrySink > xSink( evt.Source, UNO_QUERY );
+ if ( xSink.is() && xSink->getListEntrySource().is() )
+ // #i41029# / 2005-01-31 / frank.schoenheit@sun.com
+ bAddUndoAction = false;
+ }
+
+ if ( bAddUndoAction )
+ {
+ aGuard.clear();
+ // TODO: this is a potential race condition: two threads here could in theory
+ // add their undo actions out-of-order
+
+ SolarMutexGuard aSolarGuard;
+ rModel.AddUndo(std::make_unique<FmUndoPropertyAction>(rModel, evt));
+ }
+ }
+ else
+ {
+ // if it's the DataField property we may have to adjust our cache
+ if (m_pPropertySetCache && evt.PropertyName == FM_PROP_CONTROLSOURCE)
+ {
+ Reference< XPropertySet > xSet(evt.Source, UNO_QUERY);
+ PropertySetInfoCache* pCache = static_cast<PropertySetInfoCache*>(m_pPropertySetCache);
+ PropertySetInfo& rSetInfo = (*pCache)[xSet];
+ rSetInfo.bHasEmptyControlSource = !evt.NewValue.hasValue() || ::comphelper::getString(evt.NewValue).isEmpty();
+ }
+ }
+}
+
+// XContainerListener
+
+void SAL_CALL FmXUndoEnvironment::elementInserted(const ContainerEvent& evt)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // new object for listening
+ Reference< XInterface > xIface;
+ evt.Element >>= xIface;
+ OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementInserted: invalid container notification!");
+ AddElement(xIface);
+
+ implSetModified();
+}
+
+
+void FmXUndoEnvironment::implSetModified()
+{
+ if ( !IsLocked() && rModel.GetObjectShell() )
+ {
+ rModel.GetObjectShell()->SetModified();
+ }
+}
+
+
+void SAL_CALL FmXUndoEnvironment::elementReplaced(const ContainerEvent& evt)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XInterface > xIface;
+ evt.ReplacedElement >>= xIface;
+ OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementReplaced: invalid container notification!");
+ RemoveElement(xIface);
+
+ evt.Element >>= xIface;
+ AddElement(xIface);
+
+ implSetModified();
+}
+
+
+void SAL_CALL FmXUndoEnvironment::elementRemoved(const ContainerEvent& evt)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference< XInterface > xIface( evt.Element, UNO_QUERY );
+ OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementRemoved: invalid container notification!");
+ RemoveElement(xIface);
+
+ implSetModified();
+}
+
+
+void SAL_CALL FmXUndoEnvironment::modified( const EventObject& /*aEvent*/ )
+{
+ implSetModified();
+}
+
+
+void FmXUndoEnvironment::AddForms(const Reference< XNameContainer > & rForms)
+{
+ Lock();
+ AddElement(Reference<XInterface>( rForms, UNO_QUERY ));
+ UnLock();
+}
+
+
+void FmXUndoEnvironment::RemoveForms(const Reference< XNameContainer > & rForms)
+{
+ Lock();
+ RemoveElement(Reference<XInterface>( rForms, UNO_QUERY ));
+ UnLock();
+}
+
+
+void FmXUndoEnvironment::TogglePropertyListening(const Reference< XInterface > & Element)
+{
+ // listen at the container
+ Reference< XIndexContainer > xContainer(Element, UNO_QUERY);
+ if (xContainer.is())
+ {
+ sal_uInt32 nCount = xContainer->getCount();
+ Reference< XInterface > xIface;
+ for (sal_uInt32 i = 0; i < nCount; i++)
+ {
+ xContainer->getByIndex(i) >>= xIface;
+ TogglePropertyListening(xIface);
+ }
+ }
+
+ Reference< XPropertySet > xSet(Element, UNO_QUERY);
+ if (xSet.is())
+ {
+ if (!bReadOnly)
+ xSet->addPropertyChangeListener( OUString(), this );
+ else
+ xSet->removePropertyChangeListener( OUString(), this );
+ }
+}
+
+
+void FmXUndoEnvironment::switchListening( const Reference< XIndexContainer >& _rxContainer, bool _bStartListening )
+{
+ OSL_PRECOND( _rxContainer.is(), "FmXUndoEnvironment::switchListening: invalid container!" );
+ if ( !_rxContainer.is() )
+ return;
+
+ try
+ {
+ // if it's an EventAttacherManager, then we need to listen for
+ // script events
+ Reference< XEventAttacherManager > xManager( _rxContainer, UNO_QUERY );
+ if ( xManager.is() )
+ {
+ if ( _bStartListening )
+ {
+ m_pScriptingEnv->registerEventAttacherManager( xManager );
+ if ( m_vbaListener.is() )
+ xManager->addScriptListener( m_vbaListener );
+ }
+ else
+ {
+ m_pScriptingEnv->revokeEventAttacherManager( xManager );
+ if ( m_vbaListener.is() )
+ xManager->removeScriptListener( m_vbaListener );
+ }
+ }
+
+ // also handle all children of this element
+ sal_uInt32 nCount = _rxContainer->getCount();
+ Reference< XInterface > xInterface;
+ for ( sal_uInt32 i = 0; i < nCount; ++i )
+ {
+ _rxContainer->getByIndex( i ) >>= xInterface;
+ if ( _bStartListening )
+ AddElement( xInterface );
+ else
+ RemoveElement( xInterface );
+ }
+
+ // be notified of any changes in the container elements
+ Reference< XContainer > xSimpleContainer( _rxContainer, UNO_QUERY );
+ OSL_ENSURE( xSimpleContainer.is(), "FmXUndoEnvironment::switchListening: how are we expected to be notified of changes in the container?" );
+ if ( xSimpleContainer.is() )
+ {
+ if ( _bStartListening )
+ xSimpleContainer->addContainerListener( this );
+ else
+ xSimpleContainer->removeContainerListener( this );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmXUndoEnvironment::switchListening" );
+ }
+}
+
+
+void FmXUndoEnvironment::switchListening( const Reference< XInterface >& _rxObject, bool _bStartListening )
+{
+ OSL_PRECOND( _rxObject.is(), "FmXUndoEnvironment::switchListening: how should I listen at a NULL object?" );
+
+ try
+ {
+ if ( !bReadOnly )
+ {
+ Reference< XPropertySet > xProps( _rxObject, UNO_QUERY );
+ if ( xProps.is() )
+ {
+ if ( _bStartListening )
+ xProps->addPropertyChangeListener( OUString(), this );
+ else
+ xProps->removePropertyChangeListener( OUString(), this );
+ }
+ }
+
+ Reference< XModifyBroadcaster > xBroadcaster( _rxObject, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ if ( _bStartListening )
+ xBroadcaster->addModifyListener( this );
+ else
+ xBroadcaster->removeModifyListener( this );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmXUndoEnvironment::switchListening" );
+ }
+}
+
+
+void FmXUndoEnvironment::AddElement(const Reference< XInterface >& _rxElement )
+{
+ OSL_ENSURE( !m_bDisposed, "FmXUndoEnvironment::AddElement: not when I'm already disposed!" );
+
+ // listen at the container
+ Reference< XIndexContainer > xContainer( _rxElement, UNO_QUERY );
+ if ( xContainer.is() )
+ switchListening( xContainer, true );
+
+ switchListening( _rxElement, true );
+}
+
+
+void FmXUndoEnvironment::RemoveElement(const Reference< XInterface >& _rxElement)
+{
+ if ( m_bDisposed )
+ return;
+
+ switchListening( _rxElement, false );
+
+ if (!bReadOnly)
+ {
+ // reset the ActiveConnection if the form is to be removed. This will (should) free the resources
+ // associated with this connection
+ // 86299 - 05/02/2001 - frank.schoenheit@germany.sun.com
+ Reference< XForm > xForm( _rxElement, UNO_QUERY );
+ Reference< XPropertySet > xFormProperties( xForm, UNO_QUERY );
+ if ( xFormProperties.is() )
+ {
+ Reference< XConnection > xDummy;
+ if ( !isEmbeddedInDatabase( _rxElement, xDummy ) )
+ // (if there is a connection in the context of the component, setting
+ // a new connection would be vetoed, anyway)
+ // #i34196#
+ xFormProperties->setPropertyValue( FM_PROP_ACTIVE_CONNECTION, Any() );
+ }
+ }
+
+ Reference< XIndexContainer > xContainer( _rxElement, UNO_QUERY );
+ if ( xContainer.is() )
+ switchListening( xContainer, false );
+}
+
+
+FmUndoPropertyAction::FmUndoPropertyAction(FmFormModel& rNewMod, const PropertyChangeEvent& evt)
+ :SdrUndoAction(rNewMod)
+ ,xObj(evt.Source, UNO_QUERY)
+ ,aPropertyName(evt.PropertyName)
+ ,aNewValue(evt.NewValue)
+ ,aOldValue(evt.OldValue)
+{
+ if (rNewMod.GetObjectShell())
+ rNewMod.GetObjectShell()->SetModified();
+ if(static_STR_UNDO_PROPERTY.isEmpty())
+ static_STR_UNDO_PROPERTY = SvxResId(RID_STR_UNDO_PROPERTY);
+}
+
+
+void FmUndoPropertyAction::Undo()
+{
+ FmXUndoEnvironment& rEnv = static_cast<FmFormModel&>(rMod).GetUndoEnv();
+
+ if (!xObj.is() || rEnv.IsLocked())
+ return;
+
+ rEnv.Lock();
+ try
+ {
+ xObj->setPropertyValue( aPropertyName, aOldValue );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmUndoPropertyAction::Undo" );
+ }
+ rEnv.UnLock();
+}
+
+
+void FmUndoPropertyAction::Redo()
+{
+ FmXUndoEnvironment& rEnv = static_cast<FmFormModel&>(rMod).GetUndoEnv();
+
+ if (!xObj.is() || rEnv.IsLocked())
+ return;
+
+ rEnv.Lock();
+ try
+ {
+ xObj->setPropertyValue( aPropertyName, aNewValue );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmUndoPropertyAction::Redo" );
+ }
+ rEnv.UnLock();
+}
+
+
+OUString FmUndoPropertyAction::GetComment() const
+{
+ OUString aStr = static_STR_UNDO_PROPERTY.replaceFirst( "#", aPropertyName );
+ return aStr;
+}
+
+
+FmUndoContainerAction::FmUndoContainerAction(FmFormModel& _rMod,
+ Action _eAction,
+ const Reference< XIndexContainer > & xCont,
+ const Reference< XInterface > & xElem,
+ sal_Int32 nIdx)
+ :SdrUndoAction( _rMod )
+ ,m_xContainer( xCont )
+ ,m_nIndex( nIdx )
+ ,m_eAction( _eAction )
+{
+ OSL_ENSURE( nIdx >= 0, "FmUndoContainerAction::FmUndoContainerAction: invalid index!" );
+ // some old code suggested this could be a valid argument. However, this code was
+ // buggy, and it *seemed* that nobody used it - so it was removed.
+
+ if ( !(xCont.is() && xElem.is()) )
+ return;
+
+ // normalize
+ m_xElement = xElem;
+ if ( m_eAction != Removed )
+ return;
+
+ if (m_nIndex >= 0)
+ {
+ Reference< XEventAttacherManager > xManager( xCont, UNO_QUERY );
+ if ( xManager.is() )
+ m_aEvents = xManager->getScriptEvents(m_nIndex);
+ }
+ else
+ m_xElement = nullptr;
+
+ // we now own the element
+ m_xOwnElement = m_xElement;
+}
+
+
+FmUndoContainerAction::~FmUndoContainerAction()
+{
+ // if we own the object...
+ DisposeElement( m_xOwnElement );
+}
+
+
+void FmUndoContainerAction::DisposeElement( const Reference< XInterface > & xElem )
+{
+ Reference< XComponent > xComp( xElem, UNO_QUERY );
+ if ( xComp.is() )
+ {
+ // and the object does not have a parent
+ Reference< XChild > xChild( xElem, UNO_QUERY );
+ if ( xChild.is() && !xChild->getParent().is() )
+ // -> dispose it
+ xComp->dispose();
+ }
+}
+
+
+void FmUndoContainerAction::implReInsert( )
+{
+ if ( m_xContainer->getCount() < m_nIndex )
+ return;
+
+ // insert the element
+ Any aVal;
+ if ( m_xContainer->getElementType() == cppu::UnoType<XFormComponent>::get() )
+ {
+ aVal <<= Reference< XFormComponent >( m_xElement, UNO_QUERY );
+ }
+ else
+ {
+ aVal <<= Reference< XForm >( m_xElement, UNO_QUERY );
+ }
+ m_xContainer->insertByIndex( m_nIndex, aVal );
+
+ OSL_ENSURE( getElementPos( m_xContainer, m_xElement ) == m_nIndex, "FmUndoContainerAction::implReInsert: insertion did not work!" );
+
+ // register the events
+ Reference< XEventAttacherManager > xManager( m_xContainer, UNO_QUERY );
+ if ( xManager.is() )
+ xManager->registerScriptEvents( m_nIndex, m_aEvents );
+
+ // we don't own the object anymore
+ m_xOwnElement = nullptr;
+}
+
+
+void FmUndoContainerAction::implReRemove( )
+{
+ Reference< XInterface > xElement;
+ if ( ( m_nIndex >= 0 ) && ( m_nIndex < m_xContainer->getCount() ) )
+ m_xContainer->getByIndex( m_nIndex ) >>= xElement;
+
+ if ( xElement != m_xElement )
+ {
+ // the indexes in the container changed. Okay, so go the long way and
+ // manually determine the index
+ m_nIndex = getElementPos( m_xContainer, m_xElement );
+ if ( m_nIndex != -1 )
+ xElement = m_xElement;
+ }
+
+ OSL_ENSURE( xElement == m_xElement, "FmUndoContainerAction::implReRemove: cannot find the element which I'm responsible for!" );
+ if ( xElement == m_xElement )
+ {
+ Reference< XEventAttacherManager > xManager( m_xContainer, UNO_QUERY );
+ if ( xManager.is() )
+ m_aEvents = xManager->getScriptEvents( m_nIndex );
+ m_xContainer->removeByIndex( m_nIndex );
+ // from now on, we own this object
+ m_xOwnElement = m_xElement;
+ }
+}
+
+
+void FmUndoContainerAction::Undo()
+{
+ FmXUndoEnvironment& rEnv = static_cast< FmFormModel& >( rMod ).GetUndoEnv();
+
+ if ( !(m_xContainer.is() && !rEnv.IsLocked() && m_xElement.is()) )
+ return;
+
+ rEnv.Lock();
+ try
+ {
+ switch ( m_eAction )
+ {
+ case Inserted:
+ implReRemove();
+ break;
+
+ case Removed:
+ implReInsert();
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmUndoContainerAction::Undo" );
+ }
+ rEnv.UnLock();
+}
+
+
+void FmUndoContainerAction::Redo()
+{
+ FmXUndoEnvironment& rEnv = static_cast< FmFormModel& >( rMod ).GetUndoEnv();
+ if ( !(m_xContainer.is() && !rEnv.IsLocked() && m_xElement.is()) )
+ return;
+
+ rEnv.Lock();
+ try
+ {
+ switch ( m_eAction )
+ {
+ case Inserted:
+ implReInsert();
+ break;
+
+ case Removed:
+ implReRemove();
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmUndoContainerAction::Redo" );
+ }
+ rEnv.UnLock();
+}
+
+
+FmUndoModelReplaceAction::FmUndoModelReplaceAction(FmFormModel& _rMod, SdrUnoObj* _pObject, const Reference< XControlModel > & _xReplaced)
+ :SdrUndoAction(_rMod)
+ ,m_xReplaced(_xReplaced)
+ ,m_pObject(_pObject)
+{
+}
+
+
+FmUndoModelReplaceAction::~FmUndoModelReplaceAction()
+{
+ // dispose our element if nobody else is responsible for
+ DisposeElement(m_xReplaced);
+}
+
+
+void FmUndoModelReplaceAction::DisposeElement( const css::uno::Reference< css::awt::XControlModel>& xReplaced )
+{
+ Reference< XComponent > xComp(xReplaced, UNO_QUERY);
+ if (xComp.is())
+ {
+ Reference< XChild > xChild(xReplaced, UNO_QUERY);
+ if (!xChild.is() || !xChild->getParent().is())
+ xComp->dispose();
+ }
+}
+
+
+void FmUndoModelReplaceAction::Undo()
+{
+ try
+ {
+ Reference< XControlModel > xCurrentModel( m_pObject->GetUnoControlModel() );
+
+ // replace the model within the parent
+ Reference< XChild > xCurrentAsChild( xCurrentModel, UNO_QUERY );
+ Reference< XNameContainer > xCurrentsParent;
+ if ( xCurrentAsChild.is() )
+ xCurrentsParent.set(xCurrentAsChild->getParent(), css::uno::UNO_QUERY);
+ DBG_ASSERT( xCurrentsParent.is(), "FmUndoModelReplaceAction::Undo: invalid current model!" );
+
+ if ( xCurrentsParent.is() )
+ {
+ // the form container works with FormComponents
+ Reference< XFormComponent > xComponent( m_xReplaced, UNO_QUERY );
+ DBG_ASSERT( xComponent.is(), "FmUndoModelReplaceAction::Undo: the new model is no form component !" );
+
+ Reference< XPropertySet > xCurrentAsSet( xCurrentModel, UNO_QUERY );
+ DBG_ASSERT( ::comphelper::hasProperty(FM_PROP_NAME, xCurrentAsSet ), "FmUndoModelReplaceAction::Undo : one of the models is invalid !");
+
+ OUString sName;
+ xCurrentAsSet->getPropertyValue( FM_PROP_NAME ) >>= sName;
+ xCurrentsParent->replaceByName( sName, Any( xComponent ) );
+
+ m_pObject->SetUnoControlModel(m_xReplaced);
+ m_pObject->SetChanged();
+
+ m_xReplaced = xCurrentModel;
+ }
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("FmUndoModelReplaceAction::Undo : could not replace the model !");
+ }
+}
+
+
+OUString FmUndoModelReplaceAction::GetComment() const
+{
+ return SvxResId(RID_STR_UNDO_MODEL_REPLACE);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmview.cxx b/svx/source/form/fmview.cxx
new file mode 100644
index 000000000..141bdc097
--- /dev/null
+++ b/svx/source/form/fmview.cxx
@@ -0,0 +1,599 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/docfile.hxx>
+#ifdef REFERENCE
+#undef REFERENCE
+#endif
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <fmvwimp.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <fmobj.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/fmview.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/fmshell.hxx>
+#include <fmshimp.hxx>
+#include <fmservs.hxx>
+#include <fmundo.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <o3tl/deleter.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <tools/debug.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svxids.hrc>
+#include <vcl/i18nhelp.hxx>
+#include <vcl/window.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::util;
+using namespace ::svxform;
+using namespace ::svx;
+
+FmFormView::FmFormView(
+ SdrModel& rSdrModel,
+ OutputDevice* pOut)
+: E3dView(rSdrModel, pOut)
+{
+ Init();
+}
+
+void FmFormView::Init()
+{
+ pFormShell = nullptr;
+ pImpl = new FmXFormView(this);
+
+ // set model
+ SdrModel* pModel = GetModel();
+
+ DBG_ASSERT( dynamic_cast<const FmFormModel*>( pModel) != nullptr, "Wrong model" );
+ FmFormModel* pFormModel = dynamic_cast<FmFormModel*>(pModel);
+ if( !pFormModel )
+ return;
+
+ // get DesignMode from model
+ bool bInitDesignMode = pFormModel->GetOpenInDesignMode();
+ if ( pFormModel->OpenInDesignModeIsDefaulted( ) )
+ { // this means that nobody ever explicitly set this on the model, and the model has never
+ // been loaded from a stream.
+ // This means this is a newly created document. This means, we want to have it in design
+ // mode by default (though a newly created model returns true for GetOpenInDesignMode).
+ // We _want_ to have this because it makes a lot of hacks following the original fix
+ DBG_ASSERT( !bInitDesignMode, "FmFormView::Init: doesn't the model default to FALSE anymore?" );
+ // if this asserts, either the on-construction default in the model has changed (then this here
+ // may not be necessary anymore), or we're not dealing with a new document...
+ bInitDesignMode = true;
+ }
+
+ SfxObjectShell* pObjShell = pFormModel->GetObjectShell();
+ if ( pObjShell && pObjShell->GetMedium() )
+ {
+ if ( const SfxUnoAnyItem *pItem = pObjShell->GetMedium()->GetItemSet()->GetItemIfSet( SID_COMPONENTDATA, false ) )
+ {
+ ::comphelper::NamedValueCollection aComponentData( pItem->GetValue() );
+ bInitDesignMode = aComponentData.getOrDefault( "ApplyFormDesignMode", bInitDesignMode );
+ }
+ }
+
+ // this will be done in the shell
+ // bDesignMode = !bInitDesignMode; // forces execution of SetDesignMode
+ SetDesignMode( bInitDesignMode );
+}
+
+FmFormView::~FmFormView()
+{
+ if (pFormShell)
+ suppress_fun_call_w_exception(pFormShell->SetView(nullptr));
+
+ pImpl->notifyViewDying();
+}
+
+FmFormPage* FmFormView::GetCurPage()
+{
+ SdrPageView* pPageView = GetSdrPageView();
+ FmFormPage* pCurPage = pPageView ? dynamic_cast<FmFormPage*>( pPageView->GetPage() ) : nullptr;
+ return pCurPage;
+}
+
+void FmFormView::MarkListHasChanged()
+{
+ E3dView::MarkListHasChanged();
+
+ if ( !(pFormShell && IsDesignMode()) )
+ return;
+
+ FmFormObj* pObj = getMarkedGrid();
+ if ( pImpl->m_pMarkedGrid && pImpl->m_pMarkedGrid != pObj )
+ {
+ pImpl->m_pMarkedGrid = nullptr;
+ if ( pImpl->m_xWindow.is() )
+ {
+ pImpl->m_xWindow->removeFocusListener(pImpl);
+ pImpl->m_xWindow = nullptr;
+ }
+ SetMoveOutside(false);
+ //OLMRefreshAllIAOManagers();
+ }
+
+ pFormShell->GetImpl()->SetSelectionDelayed_Lock();
+}
+
+namespace
+{
+ const SdrPageWindow* findPageWindow( const SdrPaintView* _pView, OutputDevice const * _pWindow )
+ {
+ SdrPageView* pPageView = _pView->GetSdrPageView();
+ if(pPageView)
+ {
+ for ( sal_uInt32 window = 0; window < pPageView->PageWindowCount(); ++window )
+ {
+ const SdrPageWindow* pPageWindow = pPageView->GetPageWindow( window );
+ if ( !pPageWindow || &pPageWindow->GetPaintWindow().GetOutputDevice() != _pWindow )
+ continue;
+
+ return pPageWindow;
+ }
+ }
+ return nullptr;
+ }
+}
+
+
+void FmFormView::AddWindowToPaintView(OutputDevice* pNewWin, vcl::Window* pWindow)
+{
+ E3dView::AddWindowToPaintView(pNewWin, pWindow);
+
+ if ( !pNewWin )
+ return;
+
+ // look up the PageViewWindow for the newly inserted window, and care for it
+ // #i39269# / 2004-12-20 / frank.schoenheit@sun.com
+ const SdrPageWindow* pPageWindow = findPageWindow( this, pNewWin );
+ if ( pPageWindow )
+ pImpl->addWindow( *pPageWindow );
+}
+
+
+void FmFormView::DeleteWindowFromPaintView(OutputDevice* pNewWin)
+{
+ const SdrPageWindow* pPageWindow = findPageWindow( this, pNewWin );
+ if ( pPageWindow )
+ pImpl->removeWindow( pPageWindow->GetControlContainer() );
+
+ E3dView::DeleteWindowFromPaintView(pNewWin);
+}
+
+
+void FmFormView::ChangeDesignMode(bool bDesign)
+{
+ if (bDesign == IsDesignMode())
+ return;
+
+ FmFormModel* pModel = dynamic_cast<FmFormModel*>( GetModel() );
+ if (pModel)
+ { // For the duration of the transition the Undo-Environment is disabled. This ensures that non-transient Properties can
+ // also be changed (this should be done with care and also reversed before switching the mode back. An example is the
+ // setting of the maximal length of the text by FmXEditModel on its control.)
+ pModel->GetUndoEnv().Lock();
+ }
+
+ // --- 1. deactivate all controls if we are switching to design mode
+ if ( bDesign )
+ DeactivateControls( GetSdrPageView() );
+
+ // --- 2. simulate a deactivation (the shell will handle some things there ...?)
+ if ( pFormShell && pFormShell->GetImpl() )
+ pFormShell->GetImpl()->viewDeactivated_Lock(*this);
+ else
+ pImpl->Deactivate();
+
+ // --- 3. activate all controls, if we're switching to alive mode
+ if ( !bDesign )
+ ActivateControls( GetSdrPageView() );
+
+ // --- 4. load resp. unload the forms
+ FmFormPage* pCurPage = GetCurPage();
+ if ( pCurPage )
+ {
+ if ( pFormShell && pFormShell->GetImpl() )
+ pFormShell->GetImpl()->loadForms_Lock(pCurPage, (bDesign ? LoadFormsFlags::Unload : LoadFormsFlags::Load));
+ }
+
+ // --- 5. base class functionality
+ SetDesignMode( bDesign );
+
+ // --- 6. simulate an activation (the shell will handle some things there ...?)
+ OSL_PRECOND( pFormShell && pFormShell->GetImpl(), "FmFormView::ChangeDesignMode: is this really allowed? No shell?" );
+ if ( pFormShell && pFormShell->GetImpl() )
+ pFormShell->GetImpl()->viewActivated_Lock(*this);
+ else
+ pImpl->Activate();
+
+ if ( pCurPage )
+ {
+ if ( bDesign )
+ {
+ if ( GetActualOutDev() && GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW )
+ {
+ const vcl::Window* pWindow = GetActualOutDev()->GetOwnerWindow();
+ const_cast< vcl::Window* >( pWindow )->GrabFocus();
+ }
+
+ // redraw UNO objects
+ if ( GetSdrPageView() )
+ {
+ SdrObjListIter aIter(pCurPage);
+ while( aIter.IsMore() )
+ {
+ SdrObject* pObj = aIter.Next();
+ if (pObj && pObj->IsUnoObj())
+ {
+ // For redraw just use ActionChanged()
+ // pObj->BroadcastObjectChange();
+ pObj->ActionChanged();
+ }
+ }
+ }
+ }
+ else
+ {
+ // set the auto focus to the first control (if indicated by the model to do so)
+ bool bForceControlFocus = pModel && pModel->GetAutoControlFocus();
+ if (bForceControlFocus)
+ pImpl->AutoFocus();
+ }
+ }
+
+ // Unlock Undo-Environment
+ if (pModel)
+ pModel->GetUndoEnv().UnLock();
+}
+
+
+void FmFormView::GrabFirstControlFocus()
+{
+ if ( !IsDesignMode() )
+ pImpl->AutoFocus();
+}
+
+
+SdrPageView* FmFormView::ShowSdrPage(SdrPage* pPage)
+{
+ SdrPageView* pPV = E3dView::ShowSdrPage(pPage);
+
+ if (pPage)
+ {
+ if (!IsDesignMode())
+ {
+ // creating the controllers
+ ActivateControls(pPV);
+
+ // Deselect all
+ UnmarkAll();
+ }
+ else if ( pFormShell && pFormShell->IsDesignMode() )
+ {
+ FmXFormShell* pFormShellImpl = pFormShell->GetImpl();
+ pFormShellImpl->UpdateForms_Lock(true);
+
+ // so that the form navigator can react to the pagechange
+ pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_FMEXPLORER_CONTROL, true);
+
+ pFormShellImpl->SetSelection_Lock(GetMarkedObjectList());
+ }
+ }
+
+ // notify our shell that we have been activated
+ if ( pFormShell && pFormShell->GetImpl() )
+ pFormShell->GetImpl()->viewActivated_Lock(*this);
+ else
+ pImpl->Activate();
+
+ return pPV;
+}
+
+
+void FmFormView::HideSdrPage()
+{
+ // --- 1. deactivate controls
+ if ( !IsDesignMode() )
+ DeactivateControls(GetSdrPageView());
+
+ // --- 2. tell the shell the view is (going to be) deactivated
+ if ( pFormShell && pFormShell->GetImpl() )
+ pFormShell->GetImpl()->viewDeactivated_Lock(*this);
+ else
+ pImpl->Deactivate();
+
+ // --- 3. base class behavior
+ E3dView::HideSdrPage();
+}
+
+
+void FmFormView::ActivateControls(SdrPageView const * pPageView)
+{
+ if (!pPageView)
+ return;
+
+ for (sal_uInt32 i = 0; i < pPageView->PageWindowCount(); ++i)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
+ pImpl->addWindow(rPageWindow);
+ }
+}
+
+
+void FmFormView::DeactivateControls(SdrPageView const * pPageView)
+{
+ if( !pPageView )
+ return;
+
+ for (sal_uInt32 i = 0; i < pPageView->PageWindowCount(); ++i)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
+ pImpl->removeWindow(rPageWindow.GetControlContainer() );
+ }
+}
+
+
+SdrObjectUniquePtr FmFormView::CreateFieldControl( const ODataAccessDescriptor& _rColumnDescriptor )
+{
+ return pImpl->implCreateFieldControl( _rColumnDescriptor );
+}
+
+
+SdrObjectUniquePtr FmFormView::CreateXFormsControl( const OXFormsDescriptor &_rDesc )
+{
+ return pImpl->implCreateXFormsControl(_rDesc);
+}
+
+
+SdrObjectUniquePtr FmFormView::CreateFieldControl(std::u16string_view rFieldDesc) const
+{
+ sal_Int32 nIdx{ 0 };
+ OUString sDataSource( o3tl::getToken(rFieldDesc, 0, u'\x000B', nIdx));
+ OUString sObjectName( o3tl::getToken(rFieldDesc, 0, u'\x000B', nIdx));
+ sal_uInt16 nObjectType = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(rFieldDesc, 0, u'\x000B', nIdx)));
+ OUString sFieldName( o3tl::getToken(rFieldDesc, 0, u'\x000B', nIdx));
+
+ if (sFieldName.isEmpty() || sObjectName.isEmpty() || sDataSource.isEmpty())
+ return nullptr;
+
+ ODataAccessDescriptor aColumnDescriptor;
+ aColumnDescriptor.setDataSource(sDataSource);
+ aColumnDescriptor[ DataAccessDescriptorProperty::Command ] <<= sObjectName;
+ aColumnDescriptor[ DataAccessDescriptorProperty::CommandType ] <<= nObjectType;
+ aColumnDescriptor[ DataAccessDescriptorProperty::ColumnName ] <<= sFieldName;
+
+ return pImpl->implCreateFieldControl( aColumnDescriptor );
+}
+
+
+void FmFormView::InsertControlContainer(const Reference< css::awt::XControlContainer > & xCC)
+{
+ if( IsDesignMode() )
+ return;
+
+ SdrPageView* pPageView = GetSdrPageView();
+ if( !pPageView )
+ return;
+
+ for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
+
+ if( rPageWindow.GetControlContainer( false ) == xCC )
+ {
+ pImpl->addWindow(rPageWindow);
+ break;
+ }
+ }
+}
+
+
+void FmFormView::RemoveControlContainer(const Reference< css::awt::XControlContainer > & xCC)
+{
+ if( !IsDesignMode() )
+ {
+ pImpl->removeWindow( xCC );
+ }
+}
+
+
+SdrPaintWindow* FmFormView::BeginCompleteRedraw(OutputDevice* pOut)
+{
+ SdrPaintWindow* pPaintWindow = E3dView::BeginCompleteRedraw( pOut );
+ pImpl->suspendTabOrderUpdate();
+ return pPaintWindow;
+}
+
+
+void FmFormView::EndCompleteRedraw( SdrPaintWindow& rPaintWindow, bool bPaintFormLayer )
+{
+ E3dView::EndCompleteRedraw( rPaintWindow, bPaintFormLayer );
+ pImpl->resumeTabOrderUpdate();
+}
+
+
+bool FmFormView::KeyInput(const KeyEvent& rKEvt, vcl::Window* pWin)
+{
+ bool bDone = false;
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ if ( IsDesignMode()
+ && rKeyCode.GetCode() == KEY_RETURN
+ )
+ {
+ // RETURN alone enters grid controls, for keyboard accessibility
+ if ( pWin
+ && !rKeyCode.IsShift()
+ && !rKeyCode.IsMod1()
+ && !rKeyCode.IsMod2()
+ )
+ {
+ FmFormObj* pObj = getMarkedGrid();
+ if ( pObj )
+ {
+ Reference< awt::XWindow > xWindow( pObj->GetUnoControl( *this, *pWin->GetOutDev() ), UNO_QUERY );
+ if ( xWindow.is() )
+ {
+ pImpl->m_pMarkedGrid = pObj;
+ pImpl->m_xWindow = xWindow;
+ // add as listener to get notified when ESC will be pressed inside the grid
+ pImpl->m_xWindow->addFocusListener(pImpl);
+ SetMoveOutside(true);
+ //OLMRefreshAllIAOManagers();
+ xWindow->setFocus();
+ bDone = true;
+ }
+ }
+ }
+ // Alt-RETURN alone shows the properties of the selection
+ if ( pFormShell
+ && pFormShell->GetImpl()
+ && !rKeyCode.IsShift()
+ && !rKeyCode.IsMod1()
+ && rKeyCode.IsMod2()
+ )
+ {
+ pFormShell->GetImpl()->handleShowPropertiesRequest_Lock();
+ }
+
+ }
+
+ // tdf#139804 Allow selecting form controls with Alt-<Mnemonic>
+ if (rKeyCode.IsMod2() && rKeyCode.GetCode())
+ {
+ if (FmFormPage* pCurPage = GetCurPage())
+ {
+ for (size_t a = 0; a < pCurPage->GetObjCount(); ++a)
+ {
+ SdrObject* pObj = pCurPage->GetObj(a);
+ FmFormObj* pFormObject = FmFormObj::GetFormObject(pObj);
+ if (!pFormObject)
+ continue;
+
+ Reference<awt::XControl> xControl = pFormObject->GetUnoControl(*this, *pWin->GetOutDev());
+ if (!xControl.is())
+ continue;
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xControl->getPeer());
+ if (rI18nHelper.MatchMnemonic(pWindow->GetText(), rKEvt.GetCharCode()))
+ {
+ pWindow->GrabFocus();
+ pWindow->KeyInput(rKEvt);
+ bDone = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !bDone )
+ bDone = E3dView::KeyInput(rKEvt,pWin);
+ return bDone;
+}
+
+bool FmFormView::checkUnMarkAll(const Reference< XInterface >& _xSource)
+{
+ Reference< css::awt::XControl> xControl(pImpl->m_xWindow,UNO_QUERY);
+ bool bRet = !xControl.is() || !_xSource.is() || _xSource != xControl->getModel();
+ if ( bRet )
+ UnmarkAll();
+
+ return bRet;
+}
+
+
+bool FmFormView::MouseButtonDown( const MouseEvent& _rMEvt, OutputDevice* _pWin )
+{
+ bool bReturn = E3dView::MouseButtonDown( _rMEvt, _pWin );
+
+ if ( pFormShell && pFormShell->GetImpl() )
+ {
+ SdrViewEvent aViewEvent;
+ PickAnything( _rMEvt, SdrMouseEventKind::BUTTONDOWN, aViewEvent );
+ pFormShell->GetImpl()->handleMouseButtonDown_Lock(aViewEvent);
+ }
+
+ return bReturn;
+}
+
+
+FmFormObj* FmFormView::getMarkedGrid() const
+{
+ FmFormObj* pFormObject = nullptr;
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ if ( 1 == rMarkList.GetMarkCount() )
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ if ( pMark )
+ {
+ pFormObject = FmFormObj::GetFormObject( pMark->GetMarkedSdrObj() );
+ if ( pFormObject )
+ {
+ Reference< XServiceInfo > xServInfo( pFormObject->GetUnoControlModel(), UNO_QUERY );
+ if ( !xServInfo.is() || !xServInfo->supportsService( FM_SUN_COMPONENT_GRIDCONTROL ) )
+ pFormObject = nullptr;
+ }
+ }
+ }
+ return pFormObject;
+}
+
+void FmFormView::createControlLabelPair( OutputDevice const * _pOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
+ const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats,
+ SdrObjKind _nControlObjectID, SdrInventor _nInventor, SdrObjKind _nLabelObjectID,
+ SdrModel& _rModel,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpControl )
+{
+ FmXFormView::createControlLabelPair(
+ *_pOutDev, _nXOffsetMM, _nYOffsetMM,
+ _rxField, _rxNumberFormats,
+ _nControlObjectID, u"", _nInventor, _nLabelObjectID,
+ _rModel,
+ _rpLabel, _rpControl
+ );
+}
+
+Reference< runtime::XFormController > FmFormView::GetFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const
+{
+ return pImpl->getFormController( _rxForm, _rDevice );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/fmvwimp.cxx b/svx/source/form/fmvwimp.cxx
new file mode 100644
index 000000000..c95c5d710
--- /dev/null
+++ b/svx/source/form/fmvwimp.cxx
@@ -0,0 +1,1918 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <memory>
+#include <fmdocumentclassification.hxx>
+#include <fmobj.hxx>
+#include <fmpgeimp.hxx>
+#include <fmprop.hxx>
+#include <svx/strings.hrc>
+#include <fmservs.hxx>
+#include <fmshimp.hxx>
+#include <svx/fmtools.hxx>
+#include <fmvwimp.hxx>
+#include <formcontrolfactory.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svditer.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdobjkind.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/fmview.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/xmlexchg.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XValueBinding.hpp>
+#include <com/sun/star/form/runtime/FormController.hpp>
+#include <com/sun/star/form/submission/XSubmissionSupplier.hpp>
+#include <com/sun/star/awt/XTabControllerModel.hpp>
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <com/sun/star/awt/XTabController.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/window.hxx>
+#include <connectivity/dbtools.hxx>
+
+#include <algorithm>
+
+using namespace ::comphelper;
+using namespace ::svx;
+using namespace ::svxform;
+using namespace ::dbtools;
+
+ using namespace ::com::sun::star;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::form::FormButtonType_SUBMIT;
+ using ::com::sun::star::form::binding::XValueBinding;
+ using ::com::sun::star::form::binding::XBindableValue;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::container::XIndexAccess;
+ using ::com::sun::star::form::runtime::FormController;
+ using ::com::sun::star::form::runtime::XFormController;
+ using ::com::sun::star::script::XEventAttacherManager;
+ using ::com::sun::star::awt::XTabControllerModel;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::task::XInteractionHandler;
+ using ::com::sun::star::awt::XTabController;
+ using ::com::sun::star::awt::XControlContainer;
+ using ::com::sun::star::awt::XControl;
+ using ::com::sun::star::form::XFormComponent;
+ using ::com::sun::star::form::XForm;
+ using ::com::sun::star::lang::IndexOutOfBoundsException;
+ using ::com::sun::star::container::XContainer;
+ using ::com::sun::star::container::ContainerEvent;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::sdb::SQLErrorEvent;
+ using ::com::sun::star::sdbc::XRowSet;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::container::XElementAccess;
+ using ::com::sun::star::awt::XWindow;
+ using ::com::sun::star::awt::FocusEvent;
+ using ::com::sun::star::ui::dialogs::XExecutableDialog;
+ using ::com::sun::star::sdbc::XDataSource;
+ using ::com::sun::star::container::XIndexContainer;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::util::XNumberFormatsSupplier;
+ using ::com::sun::star::util::XNumberFormats;
+ using ::com::sun::star::beans::XPropertySetInfo;
+
+ namespace FormComponentType = ::com::sun::star::form::FormComponentType;
+ namespace CommandType = ::com::sun::star::sdb::CommandType;
+ namespace DataType = ::com::sun::star::sdbc::DataType;
+
+
+class FmXFormView::ObjectRemoveListener : public SfxListener
+{
+ FmXFormView* m_pParent;
+public:
+ explicit ObjectRemoveListener( FmXFormView* pParent );
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+};
+
+FormViewPageWindowAdapter::FormViewPageWindowAdapter( const css::uno::Reference<css::uno::XComponentContext>& _rContext, const SdrPageWindow& _rWindow, FmXFormView* _pViewImpl )
+: m_xControlContainer( _rWindow.GetControlContainer() ),
+ m_xContext( _rContext ),
+ m_pViewImpl( _pViewImpl ),
+ m_pWindow( _rWindow.GetPaintWindow().GetOutputDevice().GetOwnerWindow() )
+{
+
+ // create an XFormController for every form
+ FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( _rWindow.GetPageView().GetPage() );
+ DBG_ASSERT( pFormPage, "FormViewPageWindowAdapter::FormViewPageWindowAdapter: no FmFormPage found!" );
+ if ( !pFormPage )
+ return;
+
+ try
+ {
+ Reference< XIndexAccess > xForms( pFormPage->GetForms(), UNO_QUERY_THROW );
+ sal_uInt32 nLength = xForms->getCount();
+ for (sal_uInt32 i = 0; i < nLength; i++)
+ {
+ Reference< XForm > xForm( xForms->getByIndex(i), UNO_QUERY );
+ if ( xForm.is() )
+ setController( xForm, nullptr );
+ }
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+FormViewPageWindowAdapter::~FormViewPageWindowAdapter()
+{
+}
+
+void FormViewPageWindowAdapter::dispose()
+{
+ for ( ::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin();
+ i != m_aControllerList.end();
+ ++i
+ )
+ {
+ try
+ {
+ Reference< XFormController > xController( *i, UNO_SET_THROW );
+
+ // detaching the events
+ Reference< XChild > xControllerModel( xController->getModel(), UNO_QUERY );
+ if ( xControllerModel.is() )
+ {
+ Reference< XEventAttacherManager > xEventManager( xControllerModel->getParent(), UNO_QUERY_THROW );
+ Reference< XInterface > xControllerNormalized( xController, UNO_QUERY_THROW );
+ xEventManager->detach( i - m_aControllerList.begin(), xControllerNormalized );
+ }
+
+ // dispose the formcontroller
+ xController->dispose();
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+ m_aControllerList.clear();
+}
+
+sal_Bool SAL_CALL FormViewPageWindowAdapter::hasElements()
+{
+ return getCount() != 0;
+}
+
+Type SAL_CALL FormViewPageWindowAdapter::getElementType()
+{
+ return cppu::UnoType<XFormController>::get();
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL FormViewPageWindowAdapter::getCount()
+{
+ return m_aControllerList.size();
+}
+
+Any SAL_CALL FormViewPageWindowAdapter::getByIndex(sal_Int32 nIndex)
+{
+ if (nIndex < 0 ||
+ nIndex >= getCount())
+ throw IndexOutOfBoundsException();
+
+ Any aElement;
+ aElement <<= m_aControllerList[nIndex];
+ return aElement;
+}
+
+void SAL_CALL FormViewPageWindowAdapter::makeVisible( const Reference< XControl >& Control )
+{
+ SolarMutexGuard aSolarGuard;
+
+ Reference< XWindow > xWindow( Control, UNO_QUERY );
+ if ( xWindow.is() && m_pViewImpl->getView() && m_pWindow )
+ {
+ awt::Rectangle aRect = xWindow->getPosSize();
+ ::tools::Rectangle aNewRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
+ aNewRect = m_pWindow->PixelToLogic( aNewRect );
+ m_pViewImpl->getView()->MakeVisible( aNewRect, *m_pWindow );
+ }
+}
+
+static Reference< XFormController > getControllerSearchChildren( const Reference< XIndexAccess > & xIndex, const Reference< XTabControllerModel > & xModel)
+{
+ if (xIndex.is() && xIndex->getCount())
+ {
+ Reference< XFormController > xController;
+
+ for (sal_Int32 n = xIndex->getCount(); n-- && !xController.is(); )
+ {
+ xIndex->getByIndex(n) >>= xController;
+ if (xModel.get() == xController->getModel().get())
+ return xController;
+ else
+ {
+ xController = getControllerSearchChildren(xController, xModel);
+ if ( xController.is() )
+ return xController;
+ }
+ }
+ }
+ return Reference< XFormController > ();
+}
+
+// Search the according controller
+Reference< XFormController > FormViewPageWindowAdapter::getController( const Reference< XForm > & xForm ) const
+{
+ Reference< XTabControllerModel > xModel(xForm, UNO_QUERY);
+ for (const auto& rpController : m_aControllerList)
+ {
+ if (rpController->getModel().get() == xModel.get())
+ return rpController;
+
+ // the current-round controller isn't the right one. perhaps one of its children ?
+ Reference< XFormController > xChildSearch = getControllerSearchChildren(Reference< XIndexAccess > (rpController, UNO_QUERY), xModel);
+ if (xChildSearch.is())
+ return xChildSearch;
+ }
+ return Reference< XFormController > ();
+}
+
+
+void FormViewPageWindowAdapter::setController(const Reference< XForm > & xForm, const Reference< XFormController >& _rxParentController )
+{
+ DBG_ASSERT( xForm.is(), "FormViewPageWindowAdapter::setController: there should be a form!" );
+ Reference< XIndexAccess > xFormCps(xForm, UNO_QUERY);
+ if (!xFormCps.is())
+ return;
+
+ Reference< XTabControllerModel > xTabOrder(xForm, UNO_QUERY);
+
+ // create a form controller
+ Reference< XFormController > xController( FormController::create(m_xContext) );
+
+ Reference< XInteractionHandler > xHandler;
+ if ( _rxParentController.is() )
+ xHandler = _rxParentController->getInteractionHandler();
+ else
+ {
+ // TODO: should we create a default handler? Not really necessary, since the
+ // FormController itself has a default fallback
+ }
+ if ( xHandler.is() )
+ xController->setInteractionHandler( xHandler );
+
+ xController->setContext( this );
+
+ xController->setModel( xTabOrder );
+ xController->setContainer( m_xControlContainer );
+ xController->activateTabOrder();
+ xController->addActivateListener( m_pViewImpl );
+
+ if ( _rxParentController.is() )
+ _rxParentController->addChildController( xController );
+ else
+ {
+ m_aControllerList.push_back(xController);
+
+ xController->setParent( *this );
+
+ // attaching the events
+ Reference< XEventAttacherManager > xEventManager( xForm->getParent(), UNO_QUERY );
+ xEventManager->attach(m_aControllerList.size() - 1, Reference<XInterface>( xController, UNO_QUERY ), Any(xController) );
+ }
+
+ // now go through the subforms
+ sal_uInt32 nLength = xFormCps->getCount();
+ Reference< XForm > xSubForm;
+ for (sal_uInt32 i = 0; i < nLength; i++)
+ {
+ if ( xFormCps->getByIndex(i) >>= xSubForm )
+ setController( xSubForm, xController );
+ }
+}
+
+
+void FormViewPageWindowAdapter::updateTabOrder( const Reference< XForm >& _rxForm )
+{
+ OSL_PRECOND( _rxForm.is(), "FormViewPageWindowAdapter::updateTabOrder: illegal argument!" );
+ if ( !_rxForm.is() )
+ return;
+
+ try
+ {
+ Reference< XTabController > xTabCtrl( getController( _rxForm ) );
+ if ( xTabCtrl.is() )
+ { // if there already is a TabController for this form, then delegate the "updateTabOrder" request
+ xTabCtrl->activateTabOrder();
+ }
+ else
+ { // otherwise, create a TabController
+
+ // if it's a sub form, then we must ensure there exist TabControllers
+ // for all its ancestors, too
+ Reference< XForm > xParentForm( _rxForm->getParent(), UNO_QUERY );
+ // there is a parent form -> look for the respective controller
+ Reference< XFormController > xParentController;
+ if ( xParentForm.is() )
+ xParentController = getController( xParentForm );
+
+ setController( _rxForm, xParentController );
+ }
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+FmXFormView::FmXFormView(FmFormView* _pView )
+ :m_pMarkedGrid(nullptr)
+ ,m_pView(_pView)
+ ,m_nActivationEvent(nullptr)
+ ,m_nErrorMessageEvent( nullptr )
+ ,m_nAutoFocusEvent( nullptr )
+ ,m_nControlWizardEvent( nullptr )
+ ,m_bFirstActivation( true )
+ ,m_isTabOrderUpdateSuspended( false )
+{
+}
+
+
+void FmXFormView::cancelEvents()
+{
+ if ( m_nActivationEvent )
+ {
+ Application::RemoveUserEvent( m_nActivationEvent );
+ m_nActivationEvent = nullptr;
+ }
+
+ if ( m_nErrorMessageEvent )
+ {
+ Application::RemoveUserEvent( m_nErrorMessageEvent );
+ m_nErrorMessageEvent = nullptr;
+ }
+
+ if ( m_nAutoFocusEvent )
+ {
+ Application::RemoveUserEvent( m_nAutoFocusEvent );
+ m_nAutoFocusEvent = nullptr;
+ }
+
+ if ( m_nControlWizardEvent )
+ {
+ Application::RemoveUserEvent( m_nControlWizardEvent );
+ m_nControlWizardEvent = nullptr;
+ }
+}
+
+
+void FmXFormView::notifyViewDying( )
+{
+ DBG_ASSERT( m_pView, "FmXFormView::notifyViewDying: my view already died!" );
+ m_pView = nullptr;
+ cancelEvents();
+}
+
+
+FmXFormView::~FmXFormView()
+{
+ DBG_ASSERT( m_aPageWindowAdapters.empty(), "FmXFormView::~FmXFormView: Window list not empty!" );
+ for (const auto& rpAdapter : m_aPageWindowAdapters)
+ {
+ rpAdapter->dispose();
+ }
+
+ cancelEvents();
+}
+
+// EventListener
+
+void SAL_CALL FmXFormView::disposing(const EventObject& Source)
+{
+ if ( m_xWindow.is() && Source.Source == m_xWindow )
+ {
+ m_xWindow->removeFocusListener(this);
+ if ( m_pView )
+ {
+ m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
+ }
+ m_xWindow = nullptr;
+ }
+}
+
+// XFormControllerListener
+
+void SAL_CALL FmXFormView::formActivated(const EventObject& rEvent)
+{
+ if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
+ m_pView->GetFormShell()->GetImpl()->formActivated( rEvent );
+}
+
+
+void SAL_CALL FmXFormView::formDeactivated(const EventObject& rEvent)
+{
+ if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
+ m_pView->GetFormShell()->GetImpl()->formDeactivated( rEvent );
+}
+
+// XContainerListener
+
+void SAL_CALL FmXFormView::elementInserted(const ContainerEvent& evt)
+{
+ try
+ {
+ Reference< XControlContainer > xControlContainer( evt.Source, UNO_QUERY_THROW );
+ Reference< XControl > xControl( evt.Element, UNO_QUERY_THROW );
+ Reference< XFormComponent > xControlModel( xControl->getModel(), UNO_QUERY_THROW );
+ Reference< XForm > xForm( xControlModel->getParent(), UNO_QUERY_THROW );
+
+ if ( m_isTabOrderUpdateSuspended )
+ {
+ // remember the container and the control, so we can update the tab order on resumeTabOrderUpdate
+ m_aNeedTabOrderUpdate[ xControlContainer ].insert( xForm );
+ }
+ else
+ {
+ rtl::Reference< FormViewPageWindowAdapter > pAdapter = findWindow( xControlContainer );
+ if ( pAdapter.is() )
+ pAdapter->updateTabOrder( xForm );
+ }
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+void SAL_CALL FmXFormView::elementReplaced(const ContainerEvent& evt)
+{
+ elementInserted(evt);
+}
+
+
+void SAL_CALL FmXFormView::elementRemoved(const ContainerEvent& /*evt*/)
+{
+}
+
+
+rtl::Reference< FormViewPageWindowAdapter > FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC ) const
+{
+ auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
+ [&_rxCC](const rtl::Reference< FormViewPageWindowAdapter >& rpAdapter) { return _rxCC == rpAdapter->getControlContainer(); });
+ if (i != m_aPageWindowAdapters.end())
+ return *i;
+ return nullptr;
+}
+
+
+void FmXFormView::addWindow(const SdrPageWindow& rWindow)
+{
+ FmFormPage* pFormPage = dynamic_cast<FmFormPage*>( rWindow.GetPageView().GetPage() );
+ if ( !pFormPage )
+ return;
+
+ const Reference< XControlContainer >& xCC = rWindow.GetControlContainer();
+ if ( xCC.is()
+ && ( !findWindow( xCC ).is() )
+ )
+ {
+ rtl::Reference< FormViewPageWindowAdapter > pAdapter = new FormViewPageWindowAdapter( comphelper::getProcessComponentContext(), rWindow, this );
+ m_aPageWindowAdapters.push_back( pAdapter );
+
+ // listen at the ControlContainer to notice changes
+ Reference< XContainer > xContainer( xCC, UNO_QUERY );
+ if ( xContainer.is() )
+ xContainer->addContainerListener( this );
+ }
+}
+
+
+void FmXFormView::removeWindow( const Reference< XControlContainer >& _rxCC )
+{
+ // Is called if
+ // - the design mode is being switched to
+ // - a window is deleted while in the design mode
+ // - the control container for a window is removed while the active mode is on
+
+ auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
+ [&_rxCC](const rtl::Reference< FormViewPageWindowAdapter >& rpAdapter) { return _rxCC == rpAdapter->getControlContainer(); });
+ if (i != m_aPageWindowAdapters.end())
+ {
+ Reference< XContainer > xContainer( _rxCC, UNO_QUERY );
+ if ( xContainer.is() )
+ xContainer->removeContainerListener( this );
+
+ (*i)->dispose();
+ m_aPageWindowAdapters.erase( i );
+ }
+}
+
+void FmXFormView::displayAsyncErrorMessage( const SQLErrorEvent& _rEvent )
+{
+ DBG_ASSERT( nullptr == m_nErrorMessageEvent, "FmXFormView::displayAsyncErrorMessage: not too fast, please!" );
+ // This should not happen - usually, the PostUserEvent is faster than any possible user
+ // interaction which could trigger a new error. If it happens, we need a queue for the events.
+ m_aAsyncError = _rEvent;
+ m_nErrorMessageEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnDelayedErrorMessage ) );
+}
+
+IMPL_LINK_NOARG(FmXFormView, OnDelayedErrorMessage, void*, void)
+{
+ m_nErrorMessageEvent = nullptr;
+ displayException(m_aAsyncError, GetParentWindow());
+}
+
+void FmXFormView::onFirstViewActivation( const FmFormModel* _pDocModel )
+{
+ if ( _pDocModel && _pDocModel->GetAutoControlFocus() )
+ m_nAutoFocusEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnAutoFocus ) );
+}
+
+void FmXFormView::suspendTabOrderUpdate()
+{
+ OSL_ENSURE( !m_isTabOrderUpdateSuspended, "FmXFormView::suspendTabOrderUpdate: nesting not allowed!" );
+ m_isTabOrderUpdateSuspended = true;
+}
+
+void FmXFormView::resumeTabOrderUpdate()
+{
+ OSL_ENSURE( m_isTabOrderUpdateSuspended, "FmXFormView::resumeTabOrderUpdate: not suspended!" );
+ m_isTabOrderUpdateSuspended = false;
+
+ // update the tab orders for all components which were collected since the suspendTabOrderUpdate call.
+ for (const auto& rContainer : m_aNeedTabOrderUpdate)
+ {
+ rtl::Reference< FormViewPageWindowAdapter > pAdapter = findWindow( rContainer.first );
+ if ( !pAdapter.is() )
+ continue;
+
+ for (const auto& rForm : rContainer.second)
+ {
+ pAdapter->updateTabOrder( rForm );
+ }
+ }
+ m_aNeedTabOrderUpdate.clear();
+}
+
+namespace
+{
+ bool isActivableDatabaseForm(const Reference< XFormController > &xController)
+ {
+ // only database forms are to be activated
+ Reference< XRowSet > xForm(xController->getModel(), UNO_QUERY);
+ if ( !xForm.is() || !getConnection( xForm ).is() )
+ return false;
+
+ Reference< XPropertySet > xFormSet( xForm, UNO_QUERY );
+ if ( !xFormSet.is() )
+ {
+ SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form which does not have properties?" );
+ return false;
+ }
+
+ const OUString aSource = ::comphelper::getString( xFormSet->getPropertyValue( FM_PROP_COMMAND ) );
+
+ return !aSource.isEmpty();
+ }
+
+ class find_active_databaseform
+ {
+ const Reference< XFormController > xActiveController;
+
+ public:
+
+ explicit find_active_databaseform( const Reference< XFormController >& _xActiveController )
+ : xActiveController(_xActiveController )
+ {}
+
+ Reference < XFormController > operator() (const Reference< XFormController > &xController)
+ {
+ if(xController == xActiveController && isActivableDatabaseForm(xController))
+ return xController;
+
+ if ( !xController.is() )
+ {
+ SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form controller which does not have children?" );
+ return nullptr;
+ }
+
+ for(sal_Int32 i = 0; i < xController->getCount(); ++i)
+ {
+ const Any a(xController->getByIndex(i));
+ Reference < XFormController > xI;
+ if ((a >>= xI) && xI.is())
+ {
+ Reference < XFormController > xRes(operator()(xI));
+ if (xRes.is())
+ return xRes;
+ }
+ }
+
+ return nullptr;
+ }
+ };
+}
+
+
+IMPL_LINK_NOARG(FmXFormView, OnActivate, void*, void)
+{
+ m_nActivationEvent = nullptr;
+
+ if ( !m_pView )
+ {
+ OSL_FAIL( "FmXFormView::OnActivate: well... seems we have a timing problem (the view already died)!" );
+ return;
+ }
+
+ // setting the controller to activate
+ if (!(m_pView->GetFormShell() && m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW))
+ return;
+
+ FmXFormShell* const pShImpl = m_pView->GetFormShell()->GetImpl();
+
+ if(!pShImpl)
+ return;
+
+ find_active_databaseform fad(pShImpl->getActiveController_Lock());
+
+ vcl::Window* pWindow = m_pView->GetActualOutDev()->GetOwnerWindow();
+ rtl::Reference< FormViewPageWindowAdapter > pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
+ for (const auto& rpPageWindowAdapter : m_aPageWindowAdapters)
+ {
+ if ( pWindow == rpPageWindowAdapter->getWindow() )
+ pAdapter = rpPageWindowAdapter;
+ }
+
+ if ( !pAdapter.is() )
+ return;
+
+ Reference< XFormController > xControllerToActivate;
+ for (const Reference< XFormController > & xController : pAdapter->GetList())
+ {
+ if ( !xController.is() )
+ continue;
+
+ {
+ Reference< XFormController > xActiveController(fad(xController));
+ if (xActiveController.is())
+ {
+ xControllerToActivate = xActiveController;
+ break;
+ }
+ }
+
+ if(xControllerToActivate.is() || !isActivableDatabaseForm(xController))
+ continue;
+
+ xControllerToActivate = xController;
+ }
+ pShImpl->setActiveController_Lock(xControllerToActivate);
+}
+
+
+void FmXFormView::Activate(bool bSync)
+{
+ if (m_nActivationEvent)
+ {
+ Application::RemoveUserEvent(m_nActivationEvent);
+ m_nActivationEvent = nullptr;
+ }
+
+ if (bSync)
+ {
+ LINK(this,FmXFormView,OnActivate).Call(nullptr);
+ }
+ else
+ m_nActivationEvent = Application::PostUserEvent(LINK(this,FmXFormView,OnActivate));
+}
+
+
+void FmXFormView::Deactivate(bool bDeactivateController)
+{
+ if (m_nActivationEvent)
+ {
+ Application::RemoveUserEvent(m_nActivationEvent);
+ m_nActivationEvent = nullptr;
+ }
+
+ FmXFormShell* pShImpl = m_pView->GetFormShell() ? m_pView->GetFormShell()->GetImpl() : nullptr;
+ if (pShImpl && bDeactivateController)
+ pShImpl->setActiveController_Lock(nullptr);
+}
+
+
+FmFormShell* FmXFormView::GetFormShell() const
+{
+ return m_pView ? m_pView->GetFormShell() : nullptr;
+}
+
+void FmXFormView::AutoFocus()
+{
+ if (m_nAutoFocusEvent)
+ Application::RemoveUserEvent(m_nAutoFocusEvent);
+
+ m_nAutoFocusEvent = Application::PostUserEvent(LINK(this, FmXFormView, OnAutoFocus));
+}
+
+
+bool FmXFormView::isFocusable( const Reference< XControl >& i_rControl )
+{
+ if ( !i_rControl.is() )
+ return false;
+
+ try
+ {
+ Reference< XPropertySet > xModelProps( i_rControl->getModel(), UNO_QUERY_THROW );
+
+ // only enabled controls are allowed to participate
+ bool bEnabled = false;
+ OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_ENABLED ) >>= bEnabled );
+ if ( !bEnabled )
+ return false;
+
+ // check the class id of the control model
+ sal_Int16 nClassId = FormComponentType::CONTROL;
+ OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
+
+ // controls which are not focussable
+ if ( ( FormComponentType::CONTROL != nClassId )
+ && ( FormComponentType::IMAGEBUTTON != nClassId )
+ && ( FormComponentType::GROUPBOX != nClassId )
+ && ( FormComponentType::FIXEDTEXT != nClassId )
+ && ( FormComponentType::HIDDENCONTROL != nClassId )
+ && ( FormComponentType::IMAGECONTROL != nClassId )
+ && ( FormComponentType::SCROLLBAR != nClassId )
+ && ( FormComponentType::SPINBUTTON!= nClassId )
+ )
+ {
+ return true;
+ }
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return false;
+}
+
+
+static Reference< XControl > lcl_firstFocussableControl( const Sequence< Reference< XControl > >& _rControls )
+{
+ Reference< XControl > xReturn;
+
+ // loop through all the controls
+ for ( auto const & control : _rControls )
+ {
+ if ( !control.is() )
+ continue;
+
+ if ( FmXFormView::isFocusable( control ) )
+ {
+ xReturn = control;
+ break;
+ }
+ }
+
+ if ( !xReturn.is() && _rControls.hasElements() )
+ xReturn = _rControls[0];
+
+ return xReturn;
+}
+
+
+namespace
+{
+
+ void lcl_ensureControlsOfFormExist_nothrow( const SdrPage& _rPage, const SdrView& _rView, const vcl::Window& _rWindow, const Reference< XForm >& _rxForm )
+ {
+ try
+ {
+ Reference< XInterface > xNormalizedForm( _rxForm, UNO_QUERY_THROW );
+
+ SdrObjListIter aSdrObjectLoop( &_rPage, SdrIterMode::DeepNoGroups );
+ while ( aSdrObjectLoop.IsMore() )
+ {
+ FmFormObj* pFormObject = FmFormObj::GetFormObject( aSdrObjectLoop.Next() );
+ if ( !pFormObject )
+ continue;
+
+ Reference< XChild > xModel( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
+ Reference< XInterface > xModelParent( xModel->getParent(), UNO_QUERY );
+
+ if ( xNormalizedForm.get() != xModelParent.get() )
+ continue;
+
+ pFormObject->GetUnoControl( _rView, *_rWindow.GetOutDev() );
+ }
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+}
+
+
+Reference< XFormController > FmXFormView::getFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const
+{
+ Reference< XFormController > xController;
+
+ for (const rtl::Reference< FormViewPageWindowAdapter >& pAdapter : m_aPageWindowAdapters)
+ {
+ if ( !pAdapter )
+ {
+ SAL_WARN( "svx.form", "FmXFormView::getFormController: invalid page window adapter!" );
+ continue;
+ }
+
+ if ( pAdapter->getWindow() != _rDevice.GetOwnerWindow() )
+ // wrong device
+ continue;
+
+ xController = pAdapter->getController( _rxForm );
+ if ( xController.is() )
+ break;
+ }
+ return xController;
+}
+
+
+IMPL_LINK_NOARG(FmXFormView, OnAutoFocus, void*, void)
+{
+ m_nAutoFocusEvent = nullptr;
+
+ // go to the first form of our page, examine it's TabController, go to its first (in terms of the tab order)
+ // control, give it the focus
+
+ SdrPageView *pPageView = m_pView ? m_pView->GetSdrPageView() : nullptr;
+ SdrPage *pSdrPage = pPageView ? pPageView->GetPage() : nullptr;
+ // get the forms collection of the page we belong to
+ FmFormPage* pPage = dynamic_cast<FmFormPage*>( pSdrPage );
+ Reference< XIndexAccess > xForms( pPage ? Reference< XIndexAccess >( pPage->GetForms() ) : Reference< XIndexAccess >() );
+
+ const rtl::Reference< FormViewPageWindowAdapter > pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
+ const vcl::Window* pWindow = pAdapter ? pAdapter->getWindow() : nullptr;
+
+ ENSURE_OR_RETURN_VOID( xForms.is() && pWindow, "FmXFormView::OnAutoFocus: could not collect all essentials!" );
+
+ try
+ {
+ // go for the tab controller of the first form
+ if ( !xForms->getCount() )
+ return;
+ Reference< XForm > xForm( xForms->getByIndex( 0 ), UNO_QUERY_THROW );
+ Reference< XTabController > xTabController( pAdapter->getController( xForm ), UNO_QUERY_THROW );
+
+ // go for the first control of the controller
+ Sequence< Reference< XControl > > aControls( xTabController->getControls() );
+ if ( !aControls.hasElements() )
+ {
+ Reference< XElementAccess > xFormElementAccess( xForm, UNO_QUERY_THROW );
+ if (xFormElementAccess->hasElements() && pPage && m_pView)
+ {
+ // there are control models in the form, but no controls, yet.
+ // Well, since some time controls are created on demand only. In particular,
+ // they're normally created when they're first painted.
+ // Unfortunately, the FormController does not have any way to
+ // trigger the creation itself, so we must hack this ...
+ lcl_ensureControlsOfFormExist_nothrow( *pPage, *m_pView, *pWindow, xForm );
+ aControls = xTabController->getControls();
+ OSL_ENSURE( aControls.hasElements(), "FmXFormView::OnAutoFocus: no controls at all!" );
+ }
+ }
+
+ // set the focus to this first control
+ Reference< XWindow > xControlWindow( lcl_firstFocussableControl( aControls ), UNO_QUERY );
+ if ( !xControlWindow.is() )
+ return;
+
+ xControlWindow->setFocus();
+
+ // ensure that the control is visible
+ // 80210 - 12/07/00 - FS
+ const OutputDevice* pOut = m_pView ? m_pView->GetActualOutDev() : nullptr;
+ const vcl::Window* pCurrentWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
+ if ( pCurrentWindow )
+ {
+ awt::Rectangle aRect = xControlWindow->getPosSize();
+ ::tools::Rectangle aNonUnoRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
+ m_pView->MakeVisible( pCurrentWindow->PixelToLogic( aNonUnoRect ), *const_cast< vcl::Window* >( pCurrentWindow ) );
+ }
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+void FmXFormView::onCreatedFormObject( FmFormObj const & _rFormObject )
+{
+ FmFormShell* pShell = m_pView ? m_pView->GetFormShell() : nullptr;
+ FmXFormShell* pShellImpl = pShell ? pShell->GetImpl() : nullptr;
+ OSL_ENSURE( pShellImpl, "FmXFormView::onCreatedFormObject: no form shell!" );
+ if ( !pShellImpl )
+ return;
+
+ // it is valid that the form shell's forms collection is not initialized, yet
+ pShellImpl->UpdateForms_Lock(true);
+
+ m_xLastCreatedControlModel.set( _rFormObject.GetUnoControlModel(), UNO_QUERY );
+ if ( !m_xLastCreatedControlModel.is() )
+ return;
+
+ // some initial property defaults
+ FormControlFactory aControlFactory;
+ aControlFactory.initializeControlModel(pShellImpl->getDocumentType_Lock(), _rFormObject);
+
+ if (!pShellImpl->GetWizardUsing_Lock())
+ return;
+
+ // #i31958# don't call wizards in XForms mode
+ if (pShellImpl->isEnhancedForm_Lock())
+ return;
+
+ // #i46898# no wizards if there is no Base installed - currently, all wizards are
+ // database related
+ if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
+ return;
+
+ if ( m_nControlWizardEvent )
+ Application::RemoveUserEvent( m_nControlWizardEvent );
+ m_nControlWizardEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnStartControlWizard ) );
+}
+
+void FmXFormView::breakCreateFormObject()
+{
+ if (m_nControlWizardEvent != nullptr)
+ {
+ Application::RemoveUserEvent(m_nControlWizardEvent);
+ m_nControlWizardEvent = nullptr;
+ }
+ m_xLastCreatedControlModel.clear();
+}
+
+Reference<XWindow> FmXFormView::GetParentWindow() const
+{
+ const OutputDevice* pOut = m_pView ? m_pView->GetActualOutDev() : nullptr;
+ const vcl::Window* pCurrentWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
+ return VCLUnoHelper::GetInterface(const_cast<vcl::Window*>(pCurrentWindow));
+}
+
+IMPL_LINK_NOARG( FmXFormView, OnStartControlWizard, void*, void )
+{
+ m_nControlWizardEvent = nullptr;
+ OSL_PRECOND( m_xLastCreatedControlModel.is(), "FmXFormView::OnStartControlWizard: illegal call!" );
+ if ( !m_xLastCreatedControlModel.is() )
+ return;
+
+ sal_Int16 nClassId = FormComponentType::CONTROL;
+ try
+ {
+ OSL_VERIFY( m_xLastCreatedControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ const char* pWizardAsciiName = nullptr;
+ switch ( nClassId )
+ {
+ case FormComponentType::GRIDCONTROL:
+ pWizardAsciiName = "com.sun.star.sdb.GridControlAutoPilot";
+ break;
+ case FormComponentType::LISTBOX:
+ case FormComponentType::COMBOBOX:
+ pWizardAsciiName = "com.sun.star.sdb.ListComboBoxAutoPilot";
+ break;
+ case FormComponentType::GROUPBOX:
+ pWizardAsciiName = "com.sun.star.sdb.GroupBoxAutoPilot";
+ break;
+ }
+
+ if ( pWizardAsciiName )
+ {
+ // build the argument list
+ ::comphelper::NamedValueCollection aWizardArgs;
+ aWizardArgs.put("ObjectModel", m_xLastCreatedControlModel);
+ aWizardArgs.put("ParentWindow", GetParentWindow());
+
+ // create the wizard object
+ Reference< XExecutableDialog > xWizard;
+ try
+ {
+ Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
+ xWizard.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii(pWizardAsciiName), aWizardArgs.getWrappedPropertyValues(), xContext ), UNO_QUERY);
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ if ( !xWizard.is() )
+ {
+ ShowServiceNotAvailableError( nullptr, OUString::createFromAscii(pWizardAsciiName), true );
+ }
+ else
+ {
+ // execute the wizard
+ try
+ {
+ xWizard->execute();
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+
+ m_xLastCreatedControlModel.clear();
+}
+
+
+namespace
+{
+ void lcl_insertIntoFormComponentHierarchy_throw( const FmFormView& _rView, const SdrUnoObj& _rSdrObj,
+ const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
+ const OUString& _rCommand, const sal_Int32 _nCommandType )
+ {
+ FmFormPage& rPage = static_cast< FmFormPage& >( *_rView.GetSdrPageView()->GetPage() );
+
+ Reference< XFormComponent > xFormComponent( _rSdrObj.GetUnoControlModel(), UNO_QUERY_THROW );
+ Reference< XForm > xTargetForm(
+ rPage.GetImpl().findPlaceInFormComponentHierarchy( xFormComponent, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ),
+ UNO_SET_THROW );
+
+ FmFormPageImpl::setUniqueName( xFormComponent, xTargetForm );
+
+ Reference< XIndexContainer > xFormAsContainer( xTargetForm, UNO_QUERY_THROW );
+ xFormAsContainer->insertByIndex( xFormAsContainer->getCount(), Any( xFormComponent ) );
+ }
+}
+
+
+SdrObjectUniquePtr FmXFormView::implCreateFieldControl( const svx::ODataAccessDescriptor& _rColumnDescriptor )
+{
+ // not if we're in design mode
+ if ( !m_pView->IsDesignMode() )
+ return nullptr;
+
+ OUString sCommand, sFieldName;
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ SharedConnection xConnection;
+
+ OUString sDataSource = _rColumnDescriptor.getDataSource();
+ _rColumnDescriptor[ DataAccessDescriptorProperty::Command ] >>= sCommand;
+ _rColumnDescriptor[ DataAccessDescriptorProperty::ColumnName ] >>= sFieldName;
+ _rColumnDescriptor[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType;
+ {
+ Reference< XConnection > xExternalConnection;
+ _rColumnDescriptor[ DataAccessDescriptorProperty::Connection ] >>= xExternalConnection;
+ xConnection.reset( xExternalConnection, SharedConnection::NoTakeOwnership );
+ }
+
+ if ( sCommand.isEmpty()
+ || sFieldName.isEmpty()
+ || ( sDataSource.isEmpty()
+ && !xConnection.is()
+ )
+ )
+ {
+ OSL_FAIL( "FmXFormView::implCreateFieldControl: nonsense!" );
+ }
+
+ Reference< XDataSource > xDataSource;
+ SQLErrorEvent aError;
+ try
+ {
+ if ( xConnection.is() && !xDataSource.is() && sDataSource.isEmpty() )
+ {
+ Reference< XChild > xChild( xConnection, UNO_QUERY );
+ if ( xChild.is() )
+ xDataSource.set(xChild->getParent(), css::uno::UNO_QUERY);
+ }
+
+ // obtain the data source
+ if ( !xDataSource.is() )
+ xDataSource = getDataSource( sDataSource, comphelper::getProcessComponentContext() );
+
+ // and the connection, if necessary
+ if ( !xConnection.is() )
+ xConnection.reset( getConnection_withFeedback(
+ sDataSource,
+ OUString(),
+ OUString(),
+ comphelper::getProcessComponentContext(),
+ nullptr
+ ) );
+ }
+ catch (const SQLException&)
+ {
+ aError.Reason = ::cppu::getCaughtException();
+ }
+ catch (const Exception& )
+ {
+ /* will be asserted below */
+ }
+ if (aError.Reason.hasValue())
+ {
+ displayAsyncErrorMessage( aError );
+ return nullptr;
+ }
+
+ // need a data source and a connection here
+ if (!xDataSource.is() || !xConnection.is())
+ {
+ OSL_FAIL("FmXFormView::implCreateFieldControl : could not retrieve the data source or the connection!");
+ return nullptr;
+ }
+
+ Reference< XComponent > xKeepFieldsAlive;
+ // go
+ try
+ {
+ // determine the table/query field which we should create a control for
+ Reference< XPropertySet > xField;
+
+ Reference< XNameAccess > xFields = getFieldsByCommandDescriptor(
+ xConnection, nCommandType, sCommand, xKeepFieldsAlive );
+
+ if (xFields.is() && xFields->hasByName(sFieldName))
+ xFields->getByName(sFieldName) >>= xField;
+ if ( !xField.is() )
+ return nullptr;
+
+ Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection ), UNO_SET_THROW );
+ Reference< XNumberFormats > xNumberFormats( xSupplier->getNumberFormats(), UNO_SET_THROW );
+
+ OUString sLabelPostfix;
+
+
+ // only for text size
+ OutputDevice* pOutDev = nullptr;
+ if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
+ pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
+ else
+ {// find OutDev
+ if (SdrPageView* pPageView = m_pView->GetSdrPageView())
+ {
+ // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
+ // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
+
+ for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
+
+ if( rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !pOutDev )
+ return nullptr;
+
+ sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE));
+ if ((DataType::BINARY == nDataType) || (DataType::VARBINARY == nDataType))
+ return nullptr;
+
+
+ // determine the control type by examining the data type of the bound column
+ SdrObjKind nOBJID = SdrObjKind::NONE;
+ bool bDateNTimeField = false;
+
+ bool bIsCurrency = false;
+ if (::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField))
+ bIsCurrency = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY));
+
+ if (bIsCurrency)
+ nOBJID = SdrObjKind::FormCurrencyField;
+ else
+ switch (nDataType)
+ {
+ case DataType::BLOB:
+ case DataType::LONGVARBINARY:
+ nOBJID = SdrObjKind::FormImageControl;
+ break;
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ nOBJID = SdrObjKind::FormEdit;
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ return nullptr;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nOBJID = SdrObjKind::FormCheckbox;
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ nOBJID = SdrObjKind::FormNumericField;
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ nOBJID = SdrObjKind::FormFormattedField;
+ break;
+ case DataType::TIMESTAMP:
+ bDateNTimeField = true;
+ sLabelPostfix = SvxResId(RID_STR_POSTFIX_DATE);
+ [[fallthrough]];
+ case DataType::DATE:
+ nOBJID = SdrObjKind::FormDateField;
+ break;
+ case DataType::TIME:
+ nOBJID = SdrObjKind::FormTimeField;
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ default:
+ nOBJID = SdrObjKind::FormEdit;
+ break;
+ }
+ if (nOBJID == SdrObjKind::NONE)
+ return nullptr;
+
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pLabel;
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pControl;
+ if ( !createControlLabelPair( *pOutDev, 0, 0, xField, xNumberFormats, nOBJID, sLabelPostfix,
+ pLabel, pControl, xDataSource, sDataSource, sCommand, nCommandType )
+ )
+ {
+ return nullptr;
+ }
+
+
+ // group objects
+ bool bCheckbox = ( SdrObjKind::FormCheckbox == nOBJID );
+ OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateFieldControl: why was there a label created for a check box?" );
+ if ( bCheckbox )
+ return SdrObjectUniquePtr(pControl.release());
+
+ SdrObjGroup* pGroup = new SdrObjGroup(getView()->getSdrModelFromSdrView());
+ SdrObjList* pObjList = pGroup->GetSubList();
+ pObjList->InsertObject( pLabel.release() );
+ pObjList->InsertObject( pControl.release() );
+
+ if ( bDateNTimeField )
+ { // so far we created a date field only, but we also need a time field
+ if ( createControlLabelPair( *pOutDev, 0, 1000, xField, xNumberFormats, SdrObjKind::FormTimeField,
+ SvxResId(RID_STR_POSTFIX_TIME), pLabel, pControl,
+ xDataSource, sDataSource, sCommand, nCommandType )
+ )
+ {
+ pObjList->InsertObject( pLabel.release() );
+ pObjList->InsertObject( pControl.release() );
+ }
+ }
+
+ return SdrObjectUniquePtr(pGroup); // and done
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+
+ return nullptr;
+}
+
+
+SdrObjectUniquePtr FmXFormView::implCreateXFormsControl( const svx::OXFormsDescriptor &_rDesc )
+{
+ // not if we're in design mode
+ if ( !m_pView->IsDesignMode() )
+ return nullptr;
+
+ // go
+ try
+ {
+ // determine the table/query field which we should create a control for
+ Reference< XNumberFormats > xNumberFormats;
+ OUString sLabelPostfix = _rDesc.szName;
+
+
+ // only for text size
+ OutputDevice* pOutDev = nullptr;
+ if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
+ pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
+ else
+ {// find OutDev
+ if (SdrPageView* pPageView = m_pView->GetSdrPageView())
+ {
+ // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
+ // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
+
+ for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
+
+ if( rPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType() == OUTDEV_WINDOW)
+ {
+ pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !pOutDev )
+ return nullptr;
+
+
+ // The service name decides which control should be created
+ SdrObjKind nOBJID = SdrObjKind::FormEdit;
+ if(_rDesc.szServiceName == FM_SUN_COMPONENT_NUMERICFIELD)
+ nOBJID = SdrObjKind::FormNumericField;
+ if(_rDesc.szServiceName == FM_SUN_COMPONENT_CHECKBOX)
+ nOBJID = SdrObjKind::FormCheckbox;
+ if(_rDesc.szServiceName == FM_COMPONENT_COMMANDBUTTON)
+ nOBJID = SdrObjKind::FormButton;
+
+ Reference< css::form::submission::XSubmission > xSubmission(_rDesc.xPropSet, UNO_QUERY);
+
+ // xform control or submission button?
+ if ( !xSubmission.is() )
+ {
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pLabel;
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pControl;
+ if ( !createControlLabelPair( *pOutDev, 0, 0, nullptr, xNumberFormats, nOBJID, sLabelPostfix,
+ pLabel, pControl, nullptr, "", "", -1 )
+ )
+ {
+ return nullptr;
+ }
+
+
+ // Now build the connection between the control and the data item.
+ Reference< XValueBinding > xValueBinding(_rDesc.xPropSet,UNO_QUERY);
+ Reference< XBindableValue > xBindableValue(pControl->GetUnoControlModel(),UNO_QUERY);
+
+ DBG_ASSERT( xBindableValue.is(), "FmXFormView::implCreateXFormsControl: control's not bindable!" );
+ if ( xBindableValue.is() )
+ xBindableValue->setValueBinding(xValueBinding);
+
+ bool bCheckbox = ( SdrObjKind::FormCheckbox == nOBJID );
+ OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateXFormsControl: why was there a label created for a check box?" );
+ if ( bCheckbox )
+ return SdrObjectUniquePtr(pControl.release());
+
+
+ // group objects
+ SdrObjGroup* pGroup = new SdrObjGroup(getView()->getSdrModelFromSdrView());
+ SdrObjList* pObjList = pGroup->GetSubList();
+ pObjList->InsertObject(pLabel.release());
+ pObjList->InsertObject(pControl.release());
+
+ return SdrObjectUniquePtr(pGroup);
+ }
+ else {
+
+ // create a button control
+ const MapMode& eTargetMode( pOutDev->GetMapMode() );
+ const MapMode eSourceMode(MapUnit::Map100thMM);
+ const SdrObjKind nObjID = SdrObjKind::FormButton;
+ ::Size controlSize(4000, 500);
+ FmFormObj *pControl = static_cast<FmFormObj*>(
+ SdrObjFactory::MakeNewObject(
+ getView()->getSdrModelFromSdrView(),
+ SdrInventor::FmForm,
+ nObjID));
+ controlSize.setWidth( tools::Long(controlSize.Width() * eTargetMode.GetScaleX()) );
+ controlSize.setHeight( tools::Long(controlSize.Height() * eTargetMode.GetScaleY()) );
+ ::Point controlPos( OutputDevice::LogicToLogic( ::Point( controlSize.Width(), 0 ), eSourceMode, eTargetMode ) );
+ ::tools::Rectangle controlRect( controlPos, OutputDevice::LogicToLogic( controlSize, eSourceMode, eTargetMode ) );
+ pControl->SetLogicRect(controlRect);
+
+ // set the button label
+ Reference< XPropertySet > xControlSet(pControl->GetUnoControlModel(), UNO_QUERY);
+ xControlSet->setPropertyValue(FM_PROP_LABEL, Any(_rDesc.szName));
+
+ // connect the submission with the submission supplier (aka the button)
+ xControlSet->setPropertyValue( FM_PROP_BUTTON_TYPE,
+ Any( FormButtonType_SUBMIT ) );
+ Reference< css::form::submission::XSubmissionSupplier > xSubmissionSupplier(pControl->GetUnoControlModel(), UNO_QUERY);
+ xSubmissionSupplier->setSubmission(xSubmission);
+
+ return SdrObjectUniquePtr(pControl);
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while creating the control !");
+ }
+
+
+ return nullptr;
+}
+
+bool FmXFormView::createControlLabelPair( OutputDevice const & _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
+ const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats,
+ SdrObjKind _nControlObjectID, std::u16string_view _rFieldPostfix,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpControl,
+ const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
+ const OUString& _rCommand, const sal_Int32 _nCommandType )
+{
+ if(!createControlLabelPair(
+ _rOutDev,
+ _nXOffsetMM,
+ _nYOffsetMM,
+ _rxField,
+ _rxNumberFormats,
+ _nControlObjectID,
+ _rFieldPostfix,
+ SdrInventor::FmForm,
+ SdrObjKind::FormFixedText,
+
+ // tdf#118963 Hand over a SdrModel to SdrObject-creation. It uses the local m_pView
+ // and already returning false when nullptr == getView() could be done, but m_pView
+ // is already dereferenced here in many places (see below), so just use it for now.
+ getView()->getSdrModelFromSdrView(),
+
+ _rpLabel,
+ _rpControl))
+ {
+ return false;
+ }
+
+ // insert the control model(s) into the form component hierarchy
+ if ( _rpLabel )
+ lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpLabel, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
+ lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpControl, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
+
+ // some context-dependent initializations
+ FormControlFactory aControlFactory;
+ if ( _rpLabel )
+ aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpLabel );
+ aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpControl );
+
+ return true;
+}
+
+
+bool FmXFormView::createControlLabelPair( OutputDevice const & _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
+ const Reference< XPropertySet >& _rxField,
+ const Reference< XNumberFormats >& _rxNumberFormats, SdrObjKind _nControlObjectID,
+ std::u16string_view _rFieldPostfix, SdrInventor _nInventor, SdrObjKind _nLabelObjectID,
+ SdrModel& _rModel,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel, std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpControl)
+{
+ sal_Int32 nDataType = 0;
+ OUString sFieldName;
+ Any aFieldName;
+ if ( _rxField.is() )
+ {
+ nDataType = ::comphelper::getINT32(_rxField->getPropertyValue(FM_PROP_FIELDTYPE));
+ aFieldName = _rxField->getPropertyValue(FM_PROP_NAME);
+ aFieldName >>= sFieldName;
+ }
+
+ // calculate the positions, respecting the settings of the target device
+ ::Size aTextSize( _rOutDev.GetTextWidth(sFieldName + _rFieldPostfix), _rOutDev.GetTextHeight() );
+
+ MapMode eTargetMode( _rOutDev.GetMapMode() ),
+ eSourceMode( MapUnit::Map100thMM );
+
+ // text width is at least 4 centimeters
+ // text height is always half a centimeter
+ ::Size aDefTxtSize(4000, 500);
+ ::Size aDefSize(4000, 500);
+ ::Size aDefImageSize(4000, 4000);
+
+ ::Size aRealSize = OutputDevice::LogicToLogic(aTextSize, eTargetMode, eSourceMode);
+ aRealSize.setWidth( std::max(aRealSize.Width(), aDefTxtSize.Width()) );
+ aRealSize.setHeight( aDefSize.Height() );
+
+ // adjust to scaling of the target device (#53523#)
+ aRealSize.setWidth( tools::Long(Fraction(aRealSize.Width(), 1) * eTargetMode.GetScaleX()) );
+ aRealSize.setHeight( tools::Long(Fraction(aRealSize.Height(), 1) * eTargetMode.GetScaleY()) );
+
+ // for boolean fields, we do not create a label, but just a checkbox
+ bool bNeedLabel = ( _nControlObjectID != SdrObjKind::FormCheckbox );
+
+ // the label
+ ::std::unique_ptr< SdrUnoObj, SdrObjectFreeOp > pLabel;
+ Reference< XPropertySet > xLabelModel;
+
+ if ( bNeedLabel )
+ {
+ pLabel.reset( dynamic_cast< SdrUnoObj* >(
+ SdrObjFactory::MakeNewObject(
+ _rModel,
+ _nInventor,
+ _nLabelObjectID)));
+
+ OSL_ENSURE(pLabel, "FmXFormView::createControlLabelPair: could not create the label!");
+
+ if (!pLabel)
+ return false;
+
+ xLabelModel.set( pLabel->GetUnoControlModel(), UNO_QUERY );
+ if ( xLabelModel.is() )
+ {
+ OUString sLabel;
+ if ( _rxField.is() && _rxField->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) )
+ _rxField->getPropertyValue(FM_PROP_LABEL) >>= sLabel;
+ if ( sLabel.isEmpty() )
+ sLabel = sFieldName;
+
+ xLabelModel->setPropertyValue( FM_PROP_LABEL, Any( sLabel + _rFieldPostfix ) );
+ OUString sObjectLabel(SvxResId(RID_STR_OBJECT_LABEL).replaceAll("#object#", sFieldName));
+ xLabelModel->setPropertyValue(FM_PROP_NAME, Any(sObjectLabel));
+ }
+
+ pLabel->SetLogicRect( ::tools::Rectangle(
+ OutputDevice::LogicToLogic( ::Point( _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
+ OutputDevice::LogicToLogic( aRealSize, eSourceMode, eTargetMode )
+ ) );
+ }
+
+ // the control
+ ::std::unique_ptr< SdrUnoObj, SdrObjectFreeOp > pControl( dynamic_cast< SdrUnoObj* >(
+ SdrObjFactory::MakeNewObject(
+ _rModel,
+ _nInventor,
+ _nControlObjectID)));
+
+ OSL_ENSURE(pControl, "FmXFormView::createControlLabelPair: could not create the control!");
+
+ if (!pControl)
+ return false;
+
+ Reference< XPropertySet > xControlSet( pControl->GetUnoControlModel(), UNO_QUERY );
+ if ( !xControlSet.is() )
+ return false;
+
+ // size of the control
+ ::Size aControlSize( aDefSize );
+ switch ( nDataType )
+ {
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ aControlSize = aDefSize;
+ break;
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ aControlSize = aDefImageSize;
+ break;
+ }
+
+ if ( SdrObjKind::FormImageControl == _nControlObjectID )
+ aControlSize = aDefImageSize;
+
+ aControlSize.setWidth( tools::Long(Fraction(aControlSize.Width(), 1) * eTargetMode.GetScaleX()) );
+ aControlSize.setHeight( tools::Long(Fraction(aControlSize.Height(), 1) * eTargetMode.GetScaleY()) );
+
+ pControl->SetLogicRect( ::tools::Rectangle(
+ OutputDevice::LogicToLogic( ::Point( aRealSize.Width() + _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
+ OutputDevice::LogicToLogic( aControlSize, eSourceMode, eTargetMode )
+ ) );
+
+ // some initializations
+ Reference< XPropertySetInfo > xControlPropInfo = xControlSet->getPropertySetInfo();
+
+ if ( aFieldName.hasValue() )
+ {
+ xControlSet->setPropertyValue( FM_PROP_CONTROLSOURCE, aFieldName );
+ xControlSet->setPropertyValue( FM_PROP_NAME, aFieldName );
+ if ( !bNeedLabel )
+ {
+ // no dedicated label control => use the label property
+ if ( xControlPropInfo->hasPropertyByName( FM_PROP_LABEL ) )
+ xControlSet->setPropertyValue( FM_PROP_LABEL, Any( sFieldName + _rFieldPostfix ) );
+ else
+ OSL_FAIL( "FmXFormView::createControlLabelPair: can't set a label for the control!" );
+ }
+ }
+
+ if ( (nDataType == DataType::LONGVARCHAR || nDataType == DataType::CLOB) && xControlPropInfo->hasPropertyByName( FM_PROP_MULTILINE ) )
+ {
+ xControlSet->setPropertyValue( FM_PROP_MULTILINE, Any( true ) );
+ }
+
+ // announce the label to the control
+ if ( xControlPropInfo->hasPropertyByName( FM_PROP_CONTROLLABEL ) && xLabelModel.is() )
+ {
+ try
+ {
+ xControlSet->setPropertyValue( FM_PROP_CONTROLLABEL, Any( xLabelModel ) );
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+ if ( _rxField.is() )
+ {
+ FormControlFactory::initializeFieldDependentProperties( _rxField, xControlSet, _rxNumberFormats );
+ }
+
+ _rpLabel = std::move(pLabel);
+ _rpControl = std::move(pControl);
+ return true;
+}
+
+
+FmXFormView::ObjectRemoveListener::ObjectRemoveListener( FmXFormView* pParent )
+ :m_pParent( pParent )
+{
+}
+
+
+void FmXFormView::ObjectRemoveListener::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+{
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ if (pSdrHint->GetKind() == SdrHintKind::ObjectRemoved)
+ m_pParent->ObjectRemovedInAliveMode(pSdrHint->GetObject());
+}
+
+
+void FmXFormView::ObjectRemovedInAliveMode( const SdrObject* pObject )
+{
+ // if the remote object in my MarkList, which I have memorized when switching to the
+ // Alive mode, I have to take it out now, because I otherwise try to set the mark
+ // again when switching back (interestingly, this fails only with grouped objects
+ // (when accessing their ObjList GPF), not with individual ones)
+
+ const size_t nCount = m_aMark.GetMarkCount();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ SdrMark* pMark = m_aMark.GetMark(i);
+ SdrObject* pCurrent = pMark->GetMarkedSdrObj();
+ if (pObject == pCurrent)
+ {
+ m_aMark.DeleteMark(i);
+ return;
+ }
+ // I do not need to descend into GroupObjects: if an object is deleted there,
+ // then the pointer, which I have, to the GroupObject still remains valid ...
+ }
+}
+
+
+void FmXFormView::stopMarkListWatching()
+{
+ if ( m_pWatchStoredList )
+ {
+ m_pWatchStoredList->EndListeningAll();
+ m_pWatchStoredList.reset();
+ }
+}
+
+
+void FmXFormView::startMarkListWatching()
+{
+ if ( !m_pWatchStoredList )
+ {
+ FmFormModel* pModel = GetFormShell() ? GetFormShell()->GetFormModel() : nullptr;
+ DBG_ASSERT( pModel != nullptr, "FmXFormView::startMarkListWatching: shell has no model!" );
+ if (pModel)
+ {
+ m_pWatchStoredList.reset(new ObjectRemoveListener( this ));
+ m_pWatchStoredList->StartListening( *static_cast< SfxBroadcaster* >( pModel ) );
+ }
+ }
+ else
+ {
+ OSL_FAIL( "FmXFormView::startMarkListWatching: already listening!" );
+ }
+}
+
+void FmXFormView::saveMarkList()
+{
+ if ( m_pView )
+ {
+ m_aMark = m_pView->GetMarkedObjectList();
+ const size_t nCount = m_aMark.GetMarkCount( );
+ for ( size_t i = 0; i < nCount; ++i )
+ {
+ SdrMark* pMark = m_aMark.GetMark(i);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ if ( m_pView->IsObjMarked( pObj ) )
+ {
+ if ( pObj->IsGroupObject() )
+ {
+ SdrObjListIter aIter( pObj->GetSubList() );
+ bool bMixed = false;
+ while ( aIter.IsMore() && !bMixed )
+ bMixed = ( aIter.Next()->GetObjInventor() != SdrInventor::FmForm );
+
+ if ( !bMixed )
+ {
+ // all objects in the group are form objects
+ m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
+ }
+ }
+ else
+ {
+ if ( pObj->GetObjInventor() == SdrInventor::FmForm )
+ { // this is a form layer object
+ m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL( "FmXFormView::saveMarkList: invalid view!" );
+ m_aMark.Clear();
+ }
+}
+
+static bool lcl_hasObject( SdrObjListIter& rIter, SdrObject const * pObj )
+{
+ bool bFound = false;
+ while (rIter.IsMore() && !bFound)
+ bFound = pObj == rIter.Next();
+
+ rIter.Reset();
+ return bFound;
+}
+
+
+void FmXFormView::restoreMarkList( SdrMarkList& _rRestoredMarkList )
+{
+ if ( !m_pView )
+ return;
+
+ _rRestoredMarkList.Clear();
+
+ const SdrMarkList& rCurrentList = m_pView->GetMarkedObjectList();
+ FmFormPage* pPage = GetFormShell() ? GetFormShell()->GetCurPage() : nullptr;
+ if (!pPage)
+ return;
+
+ if (rCurrentList.GetMarkCount())
+ { // there is a current mark ... hmm. Is it a subset of the mark we remembered in saveMarkList?
+ bool bMisMatch = false;
+
+ // loop through all current marks
+ const size_t nCurrentCount = rCurrentList.GetMarkCount();
+ for ( size_t i=0; i<nCurrentCount && !bMisMatch; ++i )
+ {
+ const SdrObject* pCurrentMarked = rCurrentList.GetMark( i )->GetMarkedSdrObj();
+
+ // loop through all saved marks, check for equality
+ bool bFound = false;
+ const size_t nSavedCount = m_aMark.GetMarkCount();
+ for ( size_t j=0; j<nSavedCount && !bFound; ++j )
+ {
+ if ( m_aMark.GetMark( j )->GetMarkedSdrObj() == pCurrentMarked )
+ bFound = true;
+ }
+
+ // did not find a current mark in the saved marks
+ if ( !bFound )
+ bMisMatch = true;
+ }
+
+ if ( bMisMatch )
+ {
+ m_aMark.Clear();
+ _rRestoredMarkList = rCurrentList;
+ return;
+ }
+ }
+ // it is important that the objects of the mark list are not accessed,
+ // because they can be already destroyed
+ SdrPageView* pCurPageView = m_pView->GetSdrPageView();
+ SdrObjListIter aPageIter( pPage );
+ bool bFound = true;
+
+ // do all objects still exist
+ const size_t nCount = m_aMark.GetMarkCount();
+ for (size_t i = 0; i < nCount && bFound; ++i)
+ {
+ SdrMark* pMark = m_aMark.GetMark(i);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+ if (pObj->IsGroupObject())
+ {
+ SdrObjListIter aIter(pObj->GetSubList());
+ while (aIter.IsMore() && bFound)
+ bFound = lcl_hasObject(aPageIter, aIter.Next());
+ }
+ else
+ bFound = lcl_hasObject(aPageIter, pObj);
+
+ bFound = bFound && pCurPageView == pMark->GetPageView();
+ }
+
+ if (bFound)
+ {
+ // evaluate the LastObject
+ if (nCount) // now mark the objects
+ {
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ SdrMark* pMark = m_aMark.GetMark(i);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+ if ( pObj->GetObjInventor() == SdrInventor::FmForm )
+ if ( !m_pView->IsObjMarked( pObj ) )
+ m_pView->MarkObj( pObj, pMark->GetPageView() );
+ }
+
+ _rRestoredMarkList = m_aMark;
+ }
+ }
+ m_aMark.Clear();
+}
+
+void SAL_CALL FmXFormView::focusGained( const FocusEvent& /*e*/ )
+{
+ if ( m_xWindow.is() && m_pView )
+ {
+ m_pView->SetMoveOutside( true, FmFormView::ImplAccess() );
+ }
+}
+
+void SAL_CALL FmXFormView::focusLost( const FocusEvent& /*e*/ )
+{
+ // when switch the focus outside the office the mark didn't change
+ // so we can not remove us as focus listener
+ if ( m_xWindow.is() && m_pView )
+ {
+ m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
+ }
+}
+
+DocumentType FmXFormView::impl_getDocumentType() const
+{
+ if ( GetFormShell() && GetFormShell()->GetImpl() )
+ return GetFormShell()->GetImpl()->getDocumentType_Lock();
+ return eUnknownDocumentType;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/formcontrolfactory.cxx b/svx/source/form/formcontrolfactory.cxx
new file mode 100644
index 000000000..61a28b21a
--- /dev/null
+++ b/svx/source/form/formcontrolfactory.cxx
@@ -0,0 +1,702 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <formcontrolfactory.hxx>
+#include <fmcontrollayout.hxx>
+#include <fmprop.hxx>
+#include <svx/strings.hrc>
+#include <fmservs.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdouno.hxx>
+
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/awt/ScrollBarOrientation.hpp>
+#include <com/sun/star/awt/MouseWheelBehavior.hpp>
+#include <com/sun/star/form/XGridColumnFactory.hpp>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+#include <com/sun/star/awt/LineEndFormat.hpp>
+#include <com/sun/star/awt/ImageScaleMode.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+
+#include <comphelper/numbers.hxx>
+#include <comphelper/processfactory.hxx>
+#include <unotools/syslocale.hxx>
+#include <tools/gen.hxx>
+#include <tools/diagnose_ex.h>
+#include <connectivity/dbtools.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+#include <set>
+
+using namespace ::dbtools;
+
+namespace svxform
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::form::XFormComponent;
+ using ::com::sun::star::container::XIndexAccess;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::form::XGridColumnFactory;
+ using ::com::sun::star::style::VerticalAlignment_MIDDLE;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::uno::TypeClass_DOUBLE;
+ using ::com::sun::star::uno::TypeClass_LONG;
+ using ::com::sun::star::util::XNumberFormats;
+ using ::com::sun::star::util::XNumberFormatTypes;
+ using ::com::sun::star::lang::XServiceInfo;
+ using ::com::sun::star::container::XNameAccess;
+
+ namespace FormComponentType = ::com::sun::star::form::FormComponentType;
+ namespace ScrollBarOrientation = ::com::sun::star::awt::ScrollBarOrientation;
+ namespace MouseWheelBehavior = ::com::sun::star::awt::MouseWheelBehavior;
+ namespace LineEndFormat = ::com::sun::star::awt::LineEndFormat;
+ namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode;
+ namespace DataType = ::com::sun::star::sdbc::DataType;
+ namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue;
+ namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
+
+ FormControlFactory::FormControlFactory( const Reference<XComponentContext>& _rContext )
+ :m_xContext( _rContext )
+ {
+ }
+
+ FormControlFactory::FormControlFactory( )
+ :m_xContext( comphelper::getProcessComponentContext() )
+ {
+ }
+
+
+ FormControlFactory::~FormControlFactory()
+ {
+ }
+
+
+ sal_Int16 FormControlFactory::initializeControlModel( const DocumentType _eDocType, const SdrUnoObj& _rObject )
+ {
+ return initializeControlModel(
+ _eDocType,
+ Reference< XPropertySet >( _rObject.GetUnoControlModel(), UNO_QUERY ),
+ _rObject.GetCurrentBoundRect()
+ );
+ }
+
+
+ void FormControlFactory::initializeControlModel( const DocumentType _eDocType, const Reference< XPropertySet >& _rxControlModel )
+ {
+ initializeControlModel(
+ _eDocType, _rxControlModel, tools::Rectangle()
+ );
+ }
+
+
+ namespace
+ {
+
+ OUString lcl_getUniqueLabel_nothrow( const Reference< XPropertySet >& _rxControlModel, const OUString& _rBaseLabel )
+ {
+ OUString sLabel( _rBaseLabel );
+ try
+ {
+ typedef ::std::set< OUString > StringBag;
+ StringBag aUsedLabels;
+
+ Reference< XFormComponent > xFormComponent( _rxControlModel, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xContainer( xFormComponent->getParent(), UNO_QUERY_THROW );
+ // loop through all siblings of the control model, and collect their labels
+ for ( sal_Int32 index=xContainer->getCount(); index>0; )
+ {
+ Reference< XPropertySet > xElement( xContainer->getByIndex( --index ), UNO_QUERY_THROW );
+ if ( xElement == _rxControlModel )
+ continue;
+
+ Reference< XPropertySetInfo > xPSI( xElement->getPropertySetInfo(), UNO_SET_THROW );
+ if ( !xPSI->hasPropertyByName( FM_PROP_LABEL ) )
+ continue;
+
+ OUString sElementLabel;
+ OSL_VERIFY( xElement->getPropertyValue( FM_PROP_LABEL ) >>= sElementLabel );
+ aUsedLabels.insert( sElementLabel );
+ }
+
+ // now find a free label
+ sal_Int32 i=2;
+ while ( aUsedLabels.find( sLabel ) != aUsedLabels.end() )
+ {
+ OUStringBuffer aBuffer( _rBaseLabel );
+ aBuffer.append( " " );
+ aBuffer.append( i++ );
+ sLabel = aBuffer.makeStringAndClear();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return sLabel;
+ }
+
+
+ Sequence< PropertyValue > lcl_getDataSourceIndirectProperties( const Reference< XPropertySet >& _rxControlModel,
+ const Reference<XComponentContext>& _rContext )
+ {
+ OSL_PRECOND( _rxControlModel.is(), "lcl_getDataSourceIndirectProperties: invalid model!" );
+
+ Sequence< PropertyValue > aInfo;
+ try
+ {
+ Reference< XChild > xChild( _rxControlModel, UNO_QUERY );
+ Reference< XPropertySet > xForm;
+ if ( xChild.is() )
+ xForm.set(xChild->getParent(), css::uno::UNO_QUERY);
+
+ if ( Reference< XGridColumnFactory >( xForm, UNO_QUERY ).is() )
+ { // hmm. the model is a grid column, in real
+ xChild.set(xForm, css::uno::UNO_QUERY);
+ xForm.set(xChild->getParent(), css::uno::UNO_QUERY);
+ }
+
+ OSL_ENSURE( xForm.is(), "lcl_getDataSourceIndirectProperties: could not determine the form!" );
+ if ( !xForm.is() )
+ return aInfo;
+ OUString sDataSourceName;
+ xForm->getPropertyValue( FM_PROP_DATASOURCE ) >>= sDataSourceName;
+
+ Reference< XPropertySet > xDsProperties;
+ if ( !sDataSourceName.isEmpty() )
+ xDsProperties.set(getDataSource( sDataSourceName, _rContext ), css::uno::UNO_QUERY);
+ if ( xDsProperties.is() )
+ xDsProperties->getPropertyValue("Info") >>= aInfo;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "lcl_getDataSourceIndirectProperties" );
+ }
+ return aInfo;
+ }
+
+
+ const char* aCharacterAndParagraphProperties[] =
+ {
+ "CharFontName",
+ "CharFontStyleName",
+ "CharFontFamily",
+ "CharFontCharSet",
+ "CharFontPitch",
+ "CharColor",
+ "CharEscapement",
+ "CharHeight",
+ "CharUnderline",
+ "CharWeight",
+ "CharPosture",
+ "CharAutoKerning",
+ "CharBackColor",
+ "CharBackTransparent",
+ "CharCaseMap",
+ "CharCrossedOut",
+ "CharFlash",
+ "CharStrikeout",
+ "CharWordMode",
+ "CharKerning",
+ "CharLocale",
+ "CharKeepTogether",
+ "CharNoLineBreak",
+ "CharShadowed",
+ "CharFontType",
+ "CharStyleName",
+ "CharContoured",
+ "CharCombineIsOn",
+ "CharCombinePrefix",
+ "CharCombineSuffix",
+ "CharEmphasize",
+ "CharRelief",
+ "RubyText",
+ "RubyAdjust",
+ "RubyCharStyleName",
+ "RubyIsAbove",
+ "CharRotation",
+ "CharRotationIsFitToLine",
+ "CharScaleWidth",
+ "HyperLinkURL",
+ "HyperLinkTarget",
+ "HyperLinkName",
+ "VisitedCharStyleName",
+ "UnvisitedCharStyleName",
+ "CharEscapementHeight",
+ "CharNoHyphenation",
+ "CharUnderlineColor",
+ "CharUnderlineHasColor",
+ "CharStyleNames",
+ "CharHeightAsian",
+ "CharWeightAsian",
+ "CharFontNameAsian",
+ "CharFontStyleNameAsian",
+ "CharFontFamilyAsian",
+ "CharFontCharSetAsian",
+ "CharFontPitchAsian",
+ "CharPostureAsian",
+ "CharLocaleAsian",
+ "ParaIsCharacterDistance",
+ "ParaIsForbiddenRules",
+ "ParaIsHangingPunctuation",
+ "CharHeightComplex",
+ "CharWeightComplex",
+ "CharFontNameComplex",
+ "CharFontStyleNameComplex",
+ "CharFontFamilyComplex",
+ "CharFontCharSetComplex",
+ "CharFontPitchComplex",
+ "CharPostureComplex",
+ "CharLocaleComplex",
+ "ParaAdjust",
+ "ParaLineSpacing",
+ "ParaBackColor",
+ "ParaBackTransparent",
+ "ParaBackGraphic",
+ "ParaBackGraphicURL",
+ "ParaBackGraphicFilter",
+ "ParaBackGraphicLocation",
+ "ParaLastLineAdjust",
+ "ParaExpandSingleWord",
+ "ParaLeftMargin",
+ "ParaRightMargin",
+ "ParaTopMargin",
+ "ParaBottomMargin",
+ "ParaLineNumberCount",
+ "ParaLineNumberStartValue",
+ "PageDescName",
+ "PageNumberOffset",
+ "ParaRegisterModeActive",
+ "ParaTabStops",
+ "ParaStyleName",
+ "DropCapFormat",
+ "DropCapWholeWord",
+ "ParaKeepTogether",
+ "Setting",
+ "ParaSplit",
+ "Setting",
+ "NumberingLevel",
+ "NumberingRules",
+ "NumberingStartValue",
+ "ParaIsNumberingRestart",
+ "NumberingStyleName",
+ "ParaOrphans",
+ "ParaWidows",
+ "ParaShadowFormat",
+ "LeftBorder",
+ "RightBorder",
+ "TopBorder",
+ "BottomBorder",
+ "BorderDistance",
+ "LeftBorderDistance",
+ "RightBorderDistance",
+ "TopBorderDistance",
+ "BottomBorderDistance",
+ "BreakType",
+ "DropCapCharStyleName",
+ "ParaFirstLineIndent",
+ "ParaIsAutoFirstLineIndent",
+ "ParaIsHyphenation",
+ "ParaHyphenationMaxHyphens",
+ "ParaHyphenationMaxLeadingChars",
+ "ParaHyphenationMaxTrailingChars",
+ "ParaVertAlignment",
+ "ParaUserDefinedAttributes",
+ "NumberingIsNumber",
+ "ParaIsConnectBorder",
+ nullptr
+ };
+
+
+ void lcl_initializeCharacterAttributes( const Reference< XPropertySet >& _rxModel )
+ {
+ try
+ {
+ Reference< XPropertySet > xStyle( ControlLayouter::getDefaultDocumentTextStyle( _rxModel ), UNO_SET_THROW );
+
+ // transfer all properties which are described by the style
+ Reference< XPropertySetInfo > xSourcePropInfo( xStyle->getPropertySetInfo(), UNO_SET_THROW );
+ Reference< XPropertySetInfo > xDestPropInfo( _rxModel->getPropertySetInfo(), UNO_SET_THROW );
+
+ OUString sPropertyName;
+ const char** pCharacterProperty = aCharacterAndParagraphProperties;
+ while ( *pCharacterProperty )
+ {
+ sPropertyName = OUString::createFromAscii( *pCharacterProperty );
+
+ if ( xSourcePropInfo->hasPropertyByName( sPropertyName ) && xDestPropInfo->hasPropertyByName( sPropertyName ) )
+ _rxModel->setPropertyValue( sPropertyName, xStyle->getPropertyValue( sPropertyName ) );
+
+ ++pCharacterProperty;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+
+
+ sal_Int16 FormControlFactory::initializeControlModel( const DocumentType _eDocType, const Reference< XPropertySet >& _rxControlModel,
+ const tools::Rectangle& _rControlBoundRect )
+ {
+ sal_Int16 nClassId = FormComponentType::CONTROL;
+
+ OSL_ENSURE( _rxControlModel.is(), "FormControlFactory::initializeControlModel: invalid model!" );
+ if ( !_rxControlModel.is() )
+ return nClassId;
+
+ try
+ {
+ ControlLayouter::initializeControlLayout( _rxControlModel, _eDocType );
+
+ _rxControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId;
+ Reference< XPropertySetInfo > xPSI( _rxControlModel->getPropertySetInfo(), UNO_SET_THROW );
+ switch ( nClassId )
+ {
+ case FormComponentType::SCROLLBAR:
+ _rxControlModel->setPropertyValue("LiveScroll", Any( true ) );
+ [[fallthrough]];
+ case FormComponentType::SPINBUTTON:
+ {
+ sal_Int32 eOrientation = ScrollBarOrientation::HORIZONTAL;
+ if ( !_rControlBoundRect.IsEmpty() && ( _rControlBoundRect.GetWidth() < _rControlBoundRect.GetHeight() ) )
+ eOrientation = ScrollBarOrientation::VERTICAL;
+ _rxControlModel->setPropertyValue( FM_PROP_ORIENTATION, Any( eOrientation ) );
+ }
+ break;
+
+ case FormComponentType::LISTBOX:
+ case FormComponentType::COMBOBOX:
+ {
+ bool bDropDown = !_rControlBoundRect.IsEmpty() && ( _rControlBoundRect.GetWidth() >= 3 * _rControlBoundRect.GetHeight() );
+ if ( xPSI->hasPropertyByName( FM_PROP_DROPDOWN ) )
+ _rxControlModel->setPropertyValue( FM_PROP_DROPDOWN, Any( bDropDown ) );
+ _rxControlModel->setPropertyValue( FM_PROP_LINECOUNT, Any( sal_Int16( 20 ) ) );
+ }
+ break;
+
+ case FormComponentType::TEXTFIELD:
+ {
+ initializeTextFieldLineEnds( _rxControlModel );
+ lcl_initializeCharacterAttributes( _rxControlModel );
+
+ if ( !_rControlBoundRect.IsEmpty()
+ && ( _rControlBoundRect.GetWidth() <= 4 * _rControlBoundRect.GetHeight() )
+ )
+ {
+ if ( xPSI->hasPropertyByName( FM_PROP_MULTILINE ) )
+ _rxControlModel->setPropertyValue( FM_PROP_MULTILINE, Any( true ) );
+ }
+ }
+ break;
+
+ case FormComponentType::RADIOBUTTON:
+ case FormComponentType::CHECKBOX:
+ case FormComponentType::FIXEDTEXT:
+ {
+ OUString sVertAlignPropertyName( "VerticalAlign" );
+ if ( xPSI->hasPropertyByName( sVertAlignPropertyName ) )
+ _rxControlModel->setPropertyValue( sVertAlignPropertyName, Any( VerticalAlignment_MIDDLE ) );
+ }
+ break;
+
+ case FormComponentType::IMAGEBUTTON:
+ case FormComponentType::IMAGECONTROL:
+ {
+ static const OUStringLiteral sScaleModeProperty( u"ScaleMode" );
+ if ( xPSI->hasPropertyByName( sScaleModeProperty ) )
+ _rxControlModel->setPropertyValue( sScaleModeProperty, Any( ImageScaleMode::ISOTROPIC ) );
+ }
+ break;
+ }
+
+ // initial default label for the control
+ if ( xPSI->hasPropertyByName( FM_PROP_LABEL ) )
+ {
+ OUString sExistingLabel;
+ OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_LABEL ) >>= sExistingLabel );
+ if ( sExistingLabel.isEmpty() )
+ {
+ OUString sInitialLabel;
+ OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_NAME ) >>= sInitialLabel );
+
+ TranslateId pTitleResId;
+ switch ( nClassId )
+ {
+ case FormComponentType::COMMANDBUTTON: pTitleResId = RID_STR_PROPTITLE_PUSHBUTTON; break;
+ case FormComponentType::RADIOBUTTON: pTitleResId = RID_STR_PROPTITLE_RADIOBUTTON; break;
+ case FormComponentType::CHECKBOX: pTitleResId = RID_STR_PROPTITLE_CHECKBOX; break;
+ case FormComponentType::GROUPBOX: pTitleResId = RID_STR_PROPTITLE_GROUPBOX; break;
+ case FormComponentType::FIXEDTEXT: pTitleResId = RID_STR_PROPTITLE_FIXEDTEXT; break;
+ }
+
+ if (pTitleResId)
+ sInitialLabel = SvxResId(pTitleResId);
+
+ _rxControlModel->setPropertyValue(
+ FM_PROP_LABEL,
+ Any( lcl_getUniqueLabel_nothrow( _rxControlModel, sInitialLabel ) )
+ );
+ }
+ }
+
+ // strict format = yes is the default (i93467)
+ if ( xPSI->hasPropertyByName( FM_PROP_STRICTFORMAT ) )
+ {
+ _rxControlModel->setPropertyValue( FM_PROP_STRICTFORMAT, Any( true ) );
+ }
+
+ // mouse wheel: don't use it for scrolling by default (i110036)
+ if ( xPSI->hasPropertyByName( FM_PROP_MOUSE_WHEEL_BEHAVIOR ) )
+ {
+ _rxControlModel->setPropertyValue( FM_PROP_MOUSE_WHEEL_BEHAVIOR, Any( MouseWheelBehavior::SCROLL_DISABLED ) );
+ }
+
+ if ( xPSI->hasPropertyByName( FM_PROP_WRITING_MODE ) )
+ _rxControlModel->setPropertyValue( FM_PROP_WRITING_MODE, Any( WritingMode2::CONTEXT ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return nClassId;
+ }
+
+
+ void FormControlFactory::initializeTextFieldLineEnds( const Reference< XPropertySet >& _rxModel )
+ {
+ OSL_PRECOND( _rxModel.is(), "initializeTextFieldLineEnds: invalid model!" );
+ if ( !_rxModel.is() )
+ return;
+
+ try
+ {
+ Reference< XPropertySetInfo > xInfo = _rxModel->getPropertySetInfo();
+ if ( !xInfo.is() || !xInfo->hasPropertyByName( FM_PROP_LINEENDFORMAT ) )
+ return;
+
+ // let's see if the data source which the form belongs to (if any)
+ // has a setting for the preferred line end format
+ bool bDosLineEnds = false;
+ const Sequence< PropertyValue > aInfo = lcl_getDataSourceIndirectProperties( _rxModel, m_xContext );
+ const PropertyValue* pInfo = std::find_if(aInfo.begin(), aInfo.end(),
+ [](const PropertyValue& rInfo) { return rInfo.Name == "PreferDosLikeLineEnds"; });
+ if (pInfo != aInfo.end())
+ pInfo->Value >>= bDosLineEnds;
+
+ sal_Int16 nLineEndFormat = bDosLineEnds ? LineEndFormat::CARRIAGE_RETURN_LINE_FEED : LineEndFormat::LINE_FEED;
+ _rxModel->setPropertyValue( FM_PROP_LINEENDFORMAT, Any( nLineEndFormat ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void FormControlFactory::initializeFieldDependentProperties( const Reference< XPropertySet >& _rxDatabaseField,
+ const Reference< XPropertySet >& _rxControlModel, const Reference< XNumberFormats >& _rxNumberFormats )
+ {
+ OSL_PRECOND( _rxDatabaseField.is() && _rxControlModel.is(),
+ "FormControlFactory::initializeFieldDependentProperties: illegal params!" );
+ if ( !_rxDatabaseField.is() || !_rxControlModel.is() )
+ return;
+
+ try
+ {
+
+ // if the field has a numeric format, and the model has a "Scale" property, sync it
+ Reference< XPropertySetInfo > xFieldPSI( _rxDatabaseField->getPropertySetInfo(), UNO_SET_THROW );
+ Reference< XPropertySetInfo > xModelPSI( _rxControlModel->getPropertySetInfo(), UNO_SET_THROW );
+
+ if ( xModelPSI->hasPropertyByName( FM_PROP_DECIMAL_ACCURACY ) )
+ {
+ sal_Int32 nFormatKey = 0;
+ if ( xFieldPSI->hasPropertyByName( FM_PROP_FORMATKEY ) )
+ {
+ _rxDatabaseField->getPropertyValue( FM_PROP_FORMATKEY ) >>= nFormatKey;
+ }
+ else
+ {
+ nFormatKey = getDefaultNumberFormat(
+ _rxDatabaseField,
+ Reference< XNumberFormatTypes >( _rxNumberFormats, UNO_QUERY ),
+ SvtSysLocale().GetLanguageTag().getLocale()
+ );
+ }
+
+ Any aScaleVal( ::comphelper::getNumberFormatDecimals( _rxNumberFormats, nFormatKey ) );
+ _rxControlModel->setPropertyValue( FM_PROP_DECIMAL_ACCURACY, aScaleVal );
+ }
+
+
+ // minimum and maximum of the control according to the type of the database field
+ sal_Int32 nDataType = DataType::OTHER;
+ OSL_VERIFY( _rxDatabaseField->getPropertyValue( FM_PROP_FIELDTYPE ) >>= nDataType );
+
+ if ( xModelPSI->hasPropertyByName( FM_PROP_VALUEMIN )
+ && xModelPSI->hasPropertyByName( FM_PROP_VALUEMAX )
+ )
+ {
+ sal_Int32 nMinValue = -1000000000, nMaxValue = 1000000000;
+ switch ( nDataType )
+ {
+ case DataType::TINYINT : nMinValue = 0; nMaxValue = 255; break;
+ case DataType::SMALLINT : nMinValue = -32768; nMaxValue = 32767; break;
+ case DataType::INTEGER : nMinValue = 0x80000000; nMaxValue = 0x7FFFFFFF; break;
+ // double and singles are ignored
+ }
+
+ Any aValue;
+
+ // both the minimum and the maximum value properties can be either Long or Double
+ Property aProperty = xModelPSI->getPropertyByName( FM_PROP_VALUEMIN );
+ if ( aProperty.Type.getTypeClass() == TypeClass_DOUBLE )
+ aValue <<= static_cast<double>(nMinValue);
+ else if ( aProperty.Type.getTypeClass() == TypeClass_LONG )
+ aValue <<= nMinValue;
+ else
+ {
+ OSL_FAIL( "FormControlFactory::initializeFieldDependentProperties: unexpected property type (MinValue)!" );
+ }
+ _rxControlModel->setPropertyValue( FM_PROP_VALUEMIN, aValue );
+
+ // both the minimum and the maximum value properties can be either Long or Double
+ aProperty = xModelPSI->getPropertyByName( FM_PROP_VALUEMAX );
+ if ( aProperty.Type.getTypeClass() == TypeClass_DOUBLE )
+ aValue <<= static_cast<double>(nMaxValue);
+ else if ( aProperty.Type.getTypeClass() == TypeClass_LONG )
+ aValue <<= nMaxValue;
+ else
+ {
+ OSL_FAIL( "FormControlFactory::initializeFieldDependentProperties: unexpected property type (MaxValue)!" );
+ }
+ _rxControlModel->setPropertyValue( FM_PROP_VALUEMAX, aValue );
+ }
+
+
+ // a check box can be tristate if and only if the column it is bound to is nullable
+ sal_Int16 nClassId = FormComponentType::CONTROL;
+ OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
+ if ( nClassId == FormComponentType::CHECKBOX )
+ {
+ sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
+ OSL_VERIFY( _rxDatabaseField->getPropertyValue( FM_PROP_ISNULLABLE ) >>= nNullable );
+ _rxControlModel->setPropertyValue( FM_PROP_TRISTATE, Any( ColumnValue::NO_NULLS != nNullable ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ OUString FormControlFactory::getDefaultName( sal_Int16 _nClassId, const Reference< XServiceInfo >& _rxObject )
+ {
+ TranslateId pResId;
+
+ switch ( _nClassId )
+ {
+ case FormComponentType::COMMANDBUTTON: pResId = RID_STR_PROPTITLE_PUSHBUTTON; break;
+ case FormComponentType::RADIOBUTTON: pResId = RID_STR_PROPTITLE_RADIOBUTTON; break;
+ case FormComponentType::CHECKBOX: pResId = RID_STR_PROPTITLE_CHECKBOX; break;
+ case FormComponentType::LISTBOX: pResId = RID_STR_PROPTITLE_LISTBOX; break;
+ case FormComponentType::COMBOBOX: pResId = RID_STR_PROPTITLE_COMBOBOX; break;
+ case FormComponentType::GROUPBOX: pResId = RID_STR_PROPTITLE_GROUPBOX; break;
+ case FormComponentType::IMAGEBUTTON: pResId = RID_STR_PROPTITLE_IMAGEBUTTON; break;
+ case FormComponentType::FIXEDTEXT: pResId = RID_STR_PROPTITLE_FIXEDTEXT; break;
+ case FormComponentType::GRIDCONTROL: pResId = RID_STR_PROPTITLE_DBGRID; break;
+ case FormComponentType::FILECONTROL: pResId = RID_STR_PROPTITLE_FILECONTROL; break;
+ case FormComponentType::DATEFIELD: pResId = RID_STR_PROPTITLE_DATEFIELD; break;
+ case FormComponentType::TIMEFIELD: pResId = RID_STR_PROPTITLE_TIMEFIELD; break;
+ case FormComponentType::NUMERICFIELD: pResId = RID_STR_PROPTITLE_NUMERICFIELD; break;
+ case FormComponentType::CURRENCYFIELD: pResId = RID_STR_PROPTITLE_CURRENCYFIELD; break;
+ case FormComponentType::PATTERNFIELD: pResId = RID_STR_PROPTITLE_PATTERNFIELD; break;
+ case FormComponentType::IMAGECONTROL: pResId = RID_STR_PROPTITLE_IMAGECONTROL; break;
+ case FormComponentType::HIDDENCONTROL: pResId = RID_STR_PROPTITLE_HIDDEN; break;
+ case FormComponentType::SCROLLBAR: pResId = RID_STR_PROPTITLE_SCROLLBAR; break;
+ case FormComponentType::SPINBUTTON: pResId = RID_STR_PROPTITLE_SPINBUTTON; break;
+ case FormComponentType::NAVIGATIONBAR: pResId = RID_STR_PROPTITLE_NAVBAR; break;
+
+ case FormComponentType::TEXTFIELD:
+ pResId = RID_STR_PROPTITLE_EDIT;
+ if ( _rxObject.is() && _rxObject->supportsService( FM_SUN_COMPONENT_FORMATTEDFIELD ) )
+ pResId = RID_STR_PROPTITLE_FORMATTED;
+ break;
+
+ default:
+ pResId = RID_STR_CONTROL; break;
+ }
+
+ return SvxResId(pResId);
+ }
+
+
+ OUString FormControlFactory::getDefaultUniqueName_ByComponentType( const Reference< XNameAccess >& _rxContainer,
+ const Reference< XPropertySet >& _rxObject )
+ {
+ sal_Int16 nClassId = FormComponentType::CONTROL;
+ OSL_VERIFY( _rxObject->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
+ OUString sBaseName = getDefaultName( nClassId, Reference< XServiceInfo >( _rxObject, UNO_QUERY ) );
+
+ return getUniqueName( _rxContainer, sBaseName );
+ }
+
+
+ OUString FormControlFactory::getUniqueName( const Reference< XNameAccess >& _rxContainer, std::u16string_view _rBaseName )
+ {
+ sal_Int32 n = 0;
+ OUString sName;
+ do
+ {
+ OUStringBuffer aBuf( _rBaseName );
+ aBuf.append( " " );
+ aBuf.append( ++n );
+ sName = aBuf.makeStringAndClear();
+ }
+ while ( _rxContainer->hasByName( sName ) );
+
+ return sName;
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/formcontroller.cxx b/svx/source/form/formcontroller.cxx
new file mode 100644
index 000000000..d53b58939
--- /dev/null
+++ b/svx/source/form/formcontroller.cxx
@@ -0,0 +1,4168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <fmcontrolbordermanager.hxx>
+#include <fmcontrollayout.hxx>
+#include <formcontroller.hxx>
+#include <formfeaturedispatcher.hxx>
+#include <fmdocumentclassification.hxx>
+#include <formcontrolling.hxx>
+#include <fmprop.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <fmservs.hxx>
+#include <svx/fmtools.hxx>
+#include <fmurl.hxx>
+
+#include <com/sun/star/awt/FocusChangeReason.hpp>
+#include <com/sun/star/awt/XCheckBox.hpp>
+#include <com/sun/star/awt/XComboBox.hpp>
+#include <com/sun/star/awt/XListBox.hpp>
+#include <com/sun/star/awt/XVclWindowPeer.hpp>
+#include <com/sun/star/awt/TabController.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XIdentifierReplace.hpp>
+#include <com/sun/star/form/TabulatorCycle.hpp>
+#include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
+#include <com/sun/star/form/XBoundComponent.hpp>
+#include <com/sun/star/form/XBoundControl.hpp>
+#include <com/sun/star/form/XGridControl.hpp>
+#include <com/sun/star/form/XLoadable.hpp>
+#include <com/sun/star/form/XReset.hpp>
+#include <com/sun/star/form/control/FilterControl.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/sdb/ParametersRequest.hpp>
+#include <com/sun/star/sdb/RowChangeAction.hpp>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/form/runtime/FormOperations.hpp>
+#include <com/sun/star/form/runtime/FormFeature.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/interaction.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/flagguard.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/IParseContext.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <toolkit/controls/unocontrol.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/mutex.hxx>
+#include <sal/log.hxx>
+
+#include <algorithm>
+#include <iterator>
+
+using namespace ::com::sun::star;
+using namespace ::comphelper;
+using namespace ::connectivity;
+using namespace ::dbtools;
+
+
+css::uno::Reference< css::uno::XInterface >
+ FormController_NewInstance_Impl( const css::uno::Reference< css::lang::XMultiServiceFactory > & _rxORB )
+{
+ return *( new ::svxform::FormController( comphelper::getComponentContext(_rxORB) ) );
+}
+
+namespace svxform
+{
+
+ using ::com::sun::star::sdb::XColumn;
+ using ::com::sun::star::awt::XControl;
+ using ::com::sun::star::awt::TabController;
+ using ::com::sun::star::awt::XToolkit;
+ using ::com::sun::star::awt::XWindowPeer;
+ using ::com::sun::star::form::XGrid;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::container::XIndexAccess;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::lang::IndexOutOfBoundsException;
+ using ::com::sun::star::sdb::XInteractionSupplyParameters;
+ using ::com::sun::star::awt::XTextComponent;
+ using ::com::sun::star::awt::XTextListener;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::frame::XDispatch;
+ using ::com::sun::star::lang::XMultiServiceFactory;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdbc::XRowSet;
+ using ::com::sun::star::sdbc::XDatabaseMetaData;
+ using ::com::sun::star::util::XNumberFormatsSupplier;
+ using ::com::sun::star::util::NumberFormatter;
+ using ::com::sun::star::util::XNumberFormatter;
+ using ::com::sun::star::sdbcx::XColumnsSupplier;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::container::XEnumeration;
+ using ::com::sun::star::form::XFormComponent;
+ using ::com::sun::star::form::runtime::XFormOperations;
+ using ::com::sun::star::form::runtime::FilterEvent;
+ using ::com::sun::star::form::runtime::XFilterControllerListener;
+ using ::com::sun::star::awt::XControlContainer;
+ using ::com::sun::star::container::XIdentifierReplace;
+ using ::com::sun::star::form::XFormControllerListener;
+ using ::com::sun::star::awt::XWindow;
+ using ::com::sun::star::sdbc::XResultSet;
+ using ::com::sun::star::awt::XControlModel;
+ using ::com::sun::star::awt::XTabControllerModel;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+ using ::com::sun::star::form::validation::XValidatableFormComponent;
+ using ::com::sun::star::form::XLoadable;
+ using ::com::sun::star::form::XBoundControl;
+ using ::com::sun::star::beans::XPropertyChangeListener;
+ using ::com::sun::star::awt::TextEvent;
+ using ::com::sun::star::form::XBoundComponent;
+ using ::com::sun::star::awt::XCheckBox;
+ using ::com::sun::star::awt::XComboBox;
+ using ::com::sun::star::awt::XListBox;
+ using ::com::sun::star::awt::ItemEvent;
+ using ::com::sun::star::util::XModifyListener;
+ using ::com::sun::star::form::XReset;
+ using ::com::sun::star::frame::XDispatchProviderInterception;
+ using ::com::sun::star::form::XGridControl;
+ using ::com::sun::star::awt::XVclWindowPeer;
+ using ::com::sun::star::form::validation::XValidator;
+ using ::com::sun::star::awt::FocusEvent;
+ using ::com::sun::star::sdb::SQLContext;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::form::TabulatorCycle_RECORDS;
+ using ::com::sun::star::container::ContainerEvent;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::lang::Locale;
+ using ::com::sun::star::lang::NoSupportException;
+ using ::com::sun::star::sdb::RowChangeEvent;
+ using ::com::sun::star::frame::XStatusListener;
+ using ::com::sun::star::frame::XDispatchProviderInterceptor;
+ using ::com::sun::star::sdb::SQLErrorEvent;
+ using ::com::sun::star::form::DatabaseParameterEvent;
+ using ::com::sun::star::sdb::ParametersRequest;
+ using ::com::sun::star::task::XInteractionRequest;
+ using ::com::sun::star::util::URL;
+ using ::com::sun::star::frame::FeatureStateEvent;
+ using ::com::sun::star::form::runtime::XFormControllerContext;
+ using ::com::sun::star::task::InteractionHandler;
+ using ::com::sun::star::task::XInteractionHandler;
+ using ::com::sun::star::form::runtime::FormOperations;
+ using ::com::sun::star::container::XContainer;
+ using ::com::sun::star::sdbc::SQLWarning;
+
+ namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue;
+ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
+ namespace FocusChangeReason = ::com::sun::star::awt::FocusChangeReason;
+ namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
+ namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
+
+namespace {
+
+struct ColumnInfo
+{
+ // information about the column itself
+ Reference< XColumn > xColumn;
+ sal_Int32 nNullable;
+ bool bAutoIncrement;
+ bool bReadOnly;
+ OUString sName;
+
+ // information about the control(s) bound to this column
+
+ /// the first control which is bound to the given column, and which requires input
+ Reference< XControl > xFirstControlWithInputRequired;
+ /** the first grid control which contains a column which is bound to the given database column, and requires
+ input
+ */
+ Reference< XGrid > xFirstGridWithInputRequiredColumn;
+ /** if xFirstControlWithInputRequired is a grid control, then nRequiredGridColumn specifies the position
+ of the grid column which is actually bound
+ */
+ sal_Int32 nRequiredGridColumn;
+
+ ColumnInfo()
+ :nNullable( ColumnValue::NULLABLE_UNKNOWN )
+ ,bAutoIncrement( false )
+ ,bReadOnly( false )
+ ,nRequiredGridColumn( -1 )
+ {
+ }
+};
+
+}
+
+class ColumnInfoCache
+{
+public:
+ explicit ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier );
+
+ size_t getColumnCount() const { return m_aColumns.size(); }
+ const ColumnInfo& getColumnInfo( size_t _pos );
+
+ bool controlsInitialized() const { return m_bControlsInitialized; }
+ void initializeControls( const Sequence< Reference< XControl > >& _rControls );
+ void deinitializeControls();
+
+private:
+ typedef ::std::vector< ColumnInfo > ColumnInfos;
+ ColumnInfos m_aColumns;
+ bool m_bControlsInitialized;
+};
+
+
+ColumnInfoCache::ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier )
+ :m_bControlsInitialized( false )
+{
+ try
+ {
+ m_aColumns.clear();
+
+ Reference< XIndexAccess > xColumns( _rxColSupplier->getColumns(), UNO_QUERY_THROW );
+ sal_Int32 nColumnCount = xColumns->getCount();
+ m_aColumns.reserve( nColumnCount );
+
+ Reference< XPropertySet > xColumnProps;
+ for ( sal_Int32 i = 0; i < nColumnCount; ++i )
+ {
+ ColumnInfo aColInfo;
+ aColInfo.xColumn.set( xColumns->getByIndex(i), UNO_QUERY_THROW );
+
+ xColumnProps.set( aColInfo.xColumn, UNO_QUERY_THROW );
+ OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISNULLABLE ) >>= aColInfo.nNullable );
+ OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_AUTOINCREMENT ) >>= aColInfo.bAutoIncrement );
+ OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_NAME ) >>= aColInfo.sName );
+ OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISREADONLY ) >>= aColInfo.bReadOnly );
+
+ m_aColumns.push_back( aColInfo );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+namespace
+{
+ bool lcl_isBoundTo( const Reference< XPropertySet >& _rxControlModel, const Reference< XInterface >& _rxNormDBField )
+ {
+ Reference< XInterface > xNormBoundField( _rxControlModel->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY );
+ return ( xNormBoundField == _rxNormDBField );
+ }
+
+ bool lcl_isInputRequired( const Reference< XPropertySet >& _rxControlModel )
+ {
+ bool bInputRequired = false;
+ OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_INPUT_REQUIRED ) >>= bInputRequired );
+ return bInputRequired;
+ }
+
+ void lcl_resetColumnControlInfo( ColumnInfo& _rColInfo )
+ {
+ _rColInfo.xFirstControlWithInputRequired.clear();
+ _rColInfo.xFirstGridWithInputRequiredColumn.clear();
+ _rColInfo.nRequiredGridColumn = -1;
+ }
+}
+
+
+void ColumnInfoCache::deinitializeControls()
+{
+ for (auto& rCol : m_aColumns)
+ {
+ lcl_resetColumnControlInfo( rCol );
+ }
+ m_bControlsInitialized = false;
+}
+
+
+void ColumnInfoCache::initializeControls( const Sequence< Reference< XControl > >& _rControls )
+{
+ try
+ {
+ // for every of our known columns, find the controls which are bound to this column
+ for (auto& rCol : m_aColumns)
+ {
+ OSL_ENSURE( !rCol.xFirstControlWithInputRequired.is() && !rCol.xFirstGridWithInputRequiredColumn.is()
+ && ( rCol.nRequiredGridColumn == -1 ), "ColumnInfoCache::initializeControls: called me twice?" );
+
+ lcl_resetColumnControlInfo( rCol );
+
+ Reference< XInterface > xNormColumn( rCol.xColumn, UNO_QUERY_THROW );
+
+ const Reference< XControl >* pControl( _rControls.getConstArray() );
+ const Reference< XControl >* pControlEnd( pControl + _rControls.getLength() );
+ for ( ; pControl != pControlEnd; ++pControl )
+ {
+ if ( !pControl->is() )
+ continue;
+
+ Reference< XPropertySet > xModel( (*pControl)->getModel(), UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW );
+
+ // special handling for grid controls
+ Reference< XGrid > xGrid( *pControl, UNO_QUERY );
+ if ( xGrid.is() )
+ {
+ Reference< XIndexAccess > xGridColAccess( xModel, UNO_QUERY_THROW );
+ sal_Int32 gridColCount = xGridColAccess->getCount();
+ sal_Int32 gridCol = 0;
+ for ( gridCol = 0; gridCol < gridColCount; ++gridCol )
+ {
+ Reference< XPropertySet > xGridColumnModel( xGridColAccess->getByIndex( gridCol ), UNO_QUERY_THROW );
+
+ if ( !lcl_isBoundTo( xGridColumnModel, xNormColumn )
+ || !lcl_isInputRequired( xGridColumnModel )
+ )
+ continue; // with next grid column
+
+ break;
+ }
+
+ if ( gridCol < gridColCount )
+ {
+ // found a grid column which is bound to the given
+ rCol.xFirstGridWithInputRequiredColumn = xGrid;
+ rCol.nRequiredGridColumn = gridCol;
+ break;
+ }
+
+ continue; // with next control
+ }
+
+ if ( !xModelPSI->hasPropertyByName( FM_PROP_BOUNDFIELD )
+ || !lcl_isBoundTo( xModel, xNormColumn )
+ || !lcl_isInputRequired( xModel )
+ )
+ continue; // with next control
+
+ break;
+ }
+
+ if ( pControl == pControlEnd )
+ // did not find a control which is bound to this particular column, and for which the input is required
+ continue; // with next DB column
+
+ rCol.xFirstControlWithInputRequired = *pControl;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ m_bControlsInitialized = true;
+}
+
+
+const ColumnInfo& ColumnInfoCache::getColumnInfo( size_t _pos )
+{
+ if ( _pos >= m_aColumns.size() )
+ throw IndexOutOfBoundsException();
+
+ return m_aColumns[ _pos ];
+}
+
+namespace {
+
+class OParameterContinuation : public OInteraction< XInteractionSupplyParameters >
+{
+ Sequence< PropertyValue > m_aValues;
+
+public:
+ OParameterContinuation() { }
+
+ const Sequence< PropertyValue >& getValues() const { return m_aValues; }
+
+// XInteractionSupplyParameters
+ virtual void SAL_CALL setParameters( const Sequence< PropertyValue >& _rValues ) override;
+};
+
+}
+
+void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues )
+{
+ m_aValues = _rValues;
+}
+
+
+// FmXAutoControl
+
+struct FmFieldInfo
+{
+ OUString aFieldName;
+ Reference< XPropertySet > xField;
+ Reference< XTextComponent > xText;
+
+ FmFieldInfo(const Reference< XPropertySet >& _xField, const Reference< XTextComponent >& _xText)
+ :xField(_xField)
+ ,xText(_xText)
+ {xField->getPropertyValue(FM_PROP_NAME) >>= aFieldName;}
+};
+
+namespace {
+
+class FmXAutoControl: public UnoControl
+
+{
+public:
+ FmXAutoControl()
+ {
+ }
+
+ virtual OUString GetComponentServiceName() const override {return "Edit";}
+ virtual void SAL_CALL createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) override;
+
+protected:
+ virtual void ImplSetPeerProperty( const OUString& rPropName, const Any& rVal ) override;
+};
+
+}
+
+void FmXAutoControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer )
+{
+ UnoControl::createPeer( rxToolkit, rParentPeer );
+
+ Reference< XTextComponent > xText(getPeer() , UNO_QUERY);
+ if (xText.is())
+ {
+ xText->setText(SvxResId(RID_STR_AUTOFIELD));
+ xText->setEditable(false);
+ }
+}
+
+
+void FmXAutoControl::ImplSetPeerProperty( const OUString& rPropName, const Any& rVal )
+{
+ // these properties are ignored
+ if (rPropName == FM_PROP_TEXT)
+ return;
+
+ UnoControl::ImplSetPeerProperty( rPropName, rVal );
+}
+
+
+IMPL_LINK_NOARG( FormController, OnActivateTabOrder, Timer*, void )
+{
+ activateTabOrder();
+}
+
+namespace {
+
+struct UpdateAllListeners
+{
+ bool operator()( const Reference< XDispatch >& _rxDispatcher ) const
+ {
+ static_cast< svx::OSingleFeatureDispatcher* >( _rxDispatcher.get() )->updateAllListeners();
+ // the return is a dummy only so we can use this struct in a lambda expression
+ return true;
+ }
+};
+
+}
+
+IMPL_LINK_NOARG( FormController, OnInvalidateFeatures, Timer*, void )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ for (const auto& rFeature : m_aInvalidFeatures)
+ {
+ DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( rFeature );
+ if ( aDispatcherPos != m_aFeatureDispatchers.end() )
+ {
+ // TODO: for the real and actual listener notifications, we should release
+ // our mutex
+ UpdateAllListeners( )( aDispatcherPos->second );
+ }
+ }
+}
+
+FormController::FormController(const Reference< css::uno::XComponentContext > & _rxORB )
+ :FormController_BASE( m_aMutex )
+ ,OPropertySetHelper( FormController_BASE::rBHelper )
+ ,OSQLParserClient( _rxORB )
+ ,m_xComponentContext( _rxORB )
+ ,m_aActivateListeners(m_aMutex)
+ ,m_aModifyListeners(m_aMutex)
+ ,m_aErrorListeners(m_aMutex)
+ ,m_aDeleteListeners(m_aMutex)
+ ,m_aRowSetApproveListeners(m_aMutex)
+ ,m_aParameterListeners(m_aMutex)
+ ,m_aFilterListeners(m_aMutex)
+ ,m_aTabActivationIdle("svx FormController m_aTabActivationIdle")
+ ,m_aFeatureInvalidationTimer("svx FormController m_aFeatureInvalidationTimer")
+ ,m_aMode( OUString( "DataMode" ) )
+ ,m_aLoadEvent( LINK( this, FormController, OnLoad ) )
+ ,m_aToggleEvent( LINK( this, FormController, OnToggleAutoFields ) )
+ ,m_aActivationEvent( LINK( this, FormController, OnActivated ) )
+ ,m_aDeactivationEvent( LINK( this, FormController, OnDeactivated ) )
+ ,m_nCurrentFilterPosition(-1)
+ ,m_bCurrentRecordModified(false)
+ ,m_bCurrentRecordNew(false)
+ ,m_bLocked(false)
+ ,m_bDBConnection(false)
+ ,m_bCycle(false)
+ ,m_bCanInsert(false)
+ ,m_bCanUpdate(false)
+ ,m_bCommitLock(false)
+ ,m_bModified(false)
+ ,m_bControlsSorted(false)
+ ,m_bFiltering(false)
+ ,m_bAttachEvents(true)
+ ,m_bDetachEvents(true)
+ ,m_bAttemptedHandlerCreation( false )
+ ,m_bSuspendFilterTextListening( false )
+{
+
+ osl_atomic_increment(&m_refCount);
+ {
+ m_xTabController = TabController::create( m_xComponentContext );
+ m_xAggregate.set( m_xTabController, UNO_QUERY_THROW );
+ m_xAggregate->setDelegator( *this );
+ }
+ osl_atomic_decrement(&m_refCount);
+
+ m_aTabActivationIdle.SetPriority( TaskPriority::LOWEST );
+ m_aTabActivationIdle.SetInvokeHandler( LINK( this, FormController, OnActivateTabOrder ) );
+
+ m_aFeatureInvalidationTimer.SetTimeout( 200 );
+ m_aFeatureInvalidationTimer.SetInvokeHandler( LINK( this, FormController, OnInvalidateFeatures ) );
+}
+
+
+FormController::~FormController()
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_aLoadEvent.CancelPendingCall();
+ m_aToggleEvent.CancelPendingCall();
+ m_aActivationEvent.CancelPendingCall();
+ m_aDeactivationEvent.CancelPendingCall();
+
+ if ( m_aTabActivationIdle.IsActive() )
+ m_aTabActivationIdle.Stop();
+ }
+
+ if ( m_aFeatureInvalidationTimer.IsActive() )
+ m_aFeatureInvalidationTimer.Stop();
+
+ disposeAllFeaturesAndDispatchers();
+
+ if ( m_xFormOperations.is() )
+ m_xFormOperations->dispose();
+ m_xFormOperations.clear();
+
+ // release of aggregation
+ if ( m_xAggregate.is() )
+ {
+ m_xAggregate->setDelegator( nullptr );
+ m_xAggregate.clear();
+ }
+}
+
+
+void SAL_CALL FormController::acquire() noexcept
+{
+ FormController_BASE::acquire();
+}
+
+
+void SAL_CALL FormController::release() noexcept
+{
+ FormController_BASE::release();
+}
+
+
+Any SAL_CALL FormController::queryInterface( const Type& _rType )
+{
+ Any aRet = FormController_BASE::queryInterface( _rType );
+ if ( !aRet.hasValue() )
+ aRet = OPropertySetHelper::queryInterface( _rType );
+ if ( !aRet.hasValue() )
+ aRet = m_xAggregate->queryAggregation( _rType );
+ return aRet;
+}
+
+
+Sequence< sal_Int8 > SAL_CALL FormController::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Sequence< Type > SAL_CALL FormController::getTypes( )
+{
+ return comphelper::concatSequences(
+ FormController_BASE::getTypes(),
+ ::cppu::OPropertySetHelper::getTypes()
+ );
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL FormController::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+OUString SAL_CALL FormController::getImplementationName()
+{
+ return "org.openoffice.comp.svx.FormController";
+}
+
+Sequence< OUString> SAL_CALL FormController::getSupportedServiceNames()
+{
+ // service names which are supported only, but cannot be used to created an
+ // instance at a service factory
+ Sequence<OUString> aNonCreatableServiceNames { "com.sun.star.form.FormControllerDispatcher" };
+
+ // services which can be used to created an instance at a service factory
+ Sequence< OUString > aCreatableServiceNames( getSupportedServiceNames_Static() );
+ return ::comphelper::concatSequences( aCreatableServiceNames, aNonCreatableServiceNames );
+}
+
+
+sal_Bool SAL_CALL FormController::approveReset(const EventObject& /*rEvent*/)
+{
+ return true;
+}
+
+
+void SAL_CALL FormController::resetted(const EventObject& rEvent)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if (getCurrentControl().is() && (getCurrentControl()->getModel() == rEvent.Source))
+ m_bModified = false;
+}
+
+
+Sequence< OUString> const & FormController::getSupportedServiceNames_Static()
+{
+ static Sequence< OUString> const aServices
+ {
+ "com.sun.star.form.runtime.FormController",
+ "com.sun.star.awt.control.TabController"
+ };
+ return aServices;
+}
+
+
+namespace
+{
+ struct ResetComponentText
+ {
+ void operator()( const Reference< XTextComponent >& _rxText )
+ {
+ _rxText->setText( OUString() );
+ }
+ };
+
+ struct RemoveComponentTextListener
+ {
+ explicit RemoveComponentTextListener( const Reference< XTextListener >& _rxListener )
+ :m_xListener( _rxListener )
+ {
+ }
+
+ void operator()( const Reference< XTextComponent >& _rxText )
+ {
+ _rxText->removeTextListener( m_xListener );
+ }
+
+ private:
+ Reference< XTextListener > m_xListener;
+ };
+}
+
+
+void FormController::impl_setTextOnAllFilter_throw()
+{
+ m_bSuspendFilterTextListening = true;
+ ::comphelper::FlagGuard aResetFlag( m_bSuspendFilterTextListening );
+
+ // reset the text for all controls
+ ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), ResetComponentText() );
+
+ if ( m_aFilterRows.empty() )
+ // nothing to do anymore
+ return;
+
+ if ( m_nCurrentFilterPosition < 0 )
+ return;
+
+ // set the text for all filters
+ OSL_ENSURE( m_aFilterRows.size() > o3tl::make_unsigned(m_nCurrentFilterPosition),
+ "FormController::impl_setTextOnAllFilter_throw: m_nCurrentFilterPosition too big" );
+
+ if ( o3tl::make_unsigned(m_nCurrentFilterPosition) < m_aFilterRows.size() )
+ {
+ FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
+ for (const auto& rEntry : rRow)
+ {
+ rEntry.first->setText( rEntry.second );
+ }
+ }
+}
+// OPropertySetHelper
+
+sal_Bool FormController::convertFastPropertyValue( Any & /*rConvertedValue*/, Any & /*rOldValue*/,
+ sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
+{
+ return false;
+}
+
+
+void FormController::setFastPropertyValue_NoBroadcast( sal_Int32 /*nHandle*/, const Any& /*rValue*/ )
+{
+}
+
+
+void FormController::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ switch (nHandle)
+ {
+ case FM_ATTR_FILTER:
+ {
+ OUStringBuffer aFilter;
+ Reference<XConnection> xConnection(getConnection(Reference< XRowSet>(m_xModelAsIndex, UNO_QUERY)));
+ if (xConnection.is())
+ {
+ Reference< XNumberFormatsSupplier> xFormatSupplier( getNumberFormats( xConnection, true ) );
+ Reference< XNumberFormatter> xFormatter = NumberFormatter::create(m_xComponentContext);
+ xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
+
+ // now add the filter rows
+ try
+ {
+ for (const FmFilterRow& rRow : m_aFilterRows)
+ {
+ if ( rRow.empty() )
+ continue;
+
+ OUStringBuffer aRowFilter;
+ for ( FmFilterRow::const_iterator condition = rRow.begin(); condition != rRow.end(); ++condition )
+ {
+ // get the field of the controls map
+ Reference< XControl > xControl( condition->first, UNO_QUERY_THROW );
+ Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW );
+ Reference< XPropertySet > xField( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW );
+
+ OUString sFilterValue( condition->second );
+
+ OUString sErrorMsg;
+ const std::unique_ptr< OSQLParseNode > pParseNode =
+ predicateTree( sErrorMsg, sFilterValue, xFormatter, xField );
+ OSL_ENSURE( pParseNode != nullptr, "FormController::getFastPropertyValue: could not parse the field value predicate!" );
+ if ( pParseNode != nullptr )
+ {
+ OUString sCriteria;
+ // don't use a parse context here, we need it unlocalized
+ pParseNode->parseNodeToStr( sCriteria, xConnection );
+ if ( condition != rRow.begin() )
+ aRowFilter.append( " AND " );
+ aRowFilter.append( sCriteria );
+ }
+ }
+ if ( !aRowFilter.isEmpty() )
+ {
+ if ( !aFilter.isEmpty() )
+ aFilter.append( " OR " );
+
+ aFilter.append( "( " );
+ aFilter.append( aRowFilter );
+ aFilter.append( " )" );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ aFilter.setLength(0);
+ }
+ }
+ rValue <<= aFilter.makeStringAndClear();
+ }
+ break;
+
+ case FM_ATTR_FORM_OPERATIONS:
+ rValue <<= m_xFormOperations;
+ break;
+ }
+}
+
+
+Reference< XPropertySetInfo > FormController::getPropertySetInfo()
+{
+ static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+
+void FormController::fillProperties(
+ Sequence< Property >& /* [out] */ _rProps,
+ Sequence< Property >& /* [out] */ /*_rAggregateProps*/
+ ) const
+{
+ _rProps.realloc(2);
+ sal_Int32 nPos = 0;
+ Property* pDesc = _rProps.getArray();
+
+ pDesc[nPos++] = Property(FM_PROP_FILTER, FM_ATTR_FILTER,
+ cppu::UnoType<OUString>::get(),
+ PropertyAttribute::READONLY);
+ pDesc[nPos++] = Property(FM_PROP_FORM_OPERATIONS, FM_ATTR_FORM_OPERATIONS,
+ cppu::UnoType<XFormOperations>::get(),
+ PropertyAttribute::READONLY);
+}
+
+
+::cppu::IPropertyArrayHelper& FormController::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+// XFilterController
+
+void SAL_CALL FormController::addFilterControllerListener( const Reference< XFilterControllerListener >& Listener )
+{
+ m_aFilterListeners.addInterface( Listener );
+}
+
+
+void SAL_CALL FormController::removeFilterControllerListener( const Reference< XFilterControllerListener >& Listener )
+{
+ m_aFilterListeners.removeInterface( Listener );
+}
+
+
+::sal_Int32 SAL_CALL FormController::getFilterComponents()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ return m_aFilterComponents.size();
+}
+
+
+::sal_Int32 SAL_CALL FormController::getDisjunctiveTerms()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ return m_aFilterRows.size();
+}
+
+
+void SAL_CALL FormController::setPredicateExpression( ::sal_Int32 Component, ::sal_Int32 Term, const OUString& PredicateExpression )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ if ( ( Component < 0 ) || ( Component >= getFilterComponents() ) || ( Term < 0 ) || ( Term >= getDisjunctiveTerms() ) )
+ throw IndexOutOfBoundsException( OUString(), *this );
+
+ Reference< XTextComponent > xText( m_aFilterComponents[ Component ] );
+ xText->setText( PredicateExpression );
+
+ FmFilterRow& rFilterRow = m_aFilterRows[ Term ];
+ if ( !PredicateExpression.isEmpty() )
+ rFilterRow[ xText ] = PredicateExpression;
+ else
+ rFilterRow.erase( xText );
+}
+
+
+Reference< XControl > FormController::getFilterComponent( ::sal_Int32 Component )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ if ( ( Component < 0 ) || ( Component >= getFilterComponents() ) )
+ throw IndexOutOfBoundsException( OUString(), *this );
+
+ return Reference< XControl >( m_aFilterComponents[ Component ], UNO_QUERY );
+}
+
+
+Sequence< Sequence< OUString > > FormController::getPredicateExpressions()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ Sequence< Sequence< OUString > > aExpressions( m_aFilterRows.size() );
+ auto aExpressionsRange = asNonConstRange(aExpressions);
+ sal_Int32 termIndex = 0;
+ for (const FmFilterRow& rRow : m_aFilterRows)
+ {
+ Sequence< OUString > aConjunction( m_aFilterComponents.size() );
+ auto aConjunctionRange = asNonConstRange(aConjunction);
+ sal_Int32 componentIndex = 0;
+ for (const auto& rComp : m_aFilterComponents)
+ {
+ FmFilterRow::const_iterator predicate = rRow.find( rComp );
+ if ( predicate != rRow.end() )
+ aConjunctionRange[ componentIndex ] = predicate->second;
+ ++componentIndex;
+ }
+
+ aExpressionsRange[ termIndex ] = aConjunction;
+ ++termIndex;
+ }
+
+ return aExpressions;
+}
+
+
+void SAL_CALL FormController::removeDisjunctiveTerm( ::sal_Int32 Term )
+{
+ // SYNCHRONIZED -->
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ if ( ( Term < 0 ) || ( Term >= getDisjunctiveTerms() ) )
+ throw IndexOutOfBoundsException( OUString(), *this );
+
+ // if the to-be-deleted row is our current row, we need to shift
+ if ( Term == m_nCurrentFilterPosition )
+ {
+ if ( m_nCurrentFilterPosition < sal_Int32( m_aFilterRows.size() - 1 ) )
+ ++m_nCurrentFilterPosition;
+ else
+ --m_nCurrentFilterPosition;
+ }
+
+ FmFilterRows::iterator pos = m_aFilterRows.begin() + Term;
+ m_aFilterRows.erase( pos );
+
+ // adjust m_nCurrentFilterPosition if the removed row preceded it
+ if ( Term < m_nCurrentFilterPosition )
+ --m_nCurrentFilterPosition;
+
+ SAL_WARN_IF( !( ( m_nCurrentFilterPosition < 0 ) != ( m_aFilterRows.empty() ) ),
+ "svx.form", "FormController::removeDisjunctiveTerm: inconsistency!" );
+
+ // update the texts in the filter controls
+ impl_setTextOnAllFilter_throw();
+
+ FilterEvent aEvent;
+ aEvent.Source = *this;
+ aEvent.DisjunctiveTerm = Term;
+ aGuard.clear();
+ // <-- SYNCHRONIZED
+
+ m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermRemoved, aEvent );
+}
+
+
+void SAL_CALL FormController::appendEmptyDisjunctiveTerm()
+{
+ // SYNCHRONIZED -->
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ impl_appendEmptyFilterRow( aGuard );
+ // <-- SYNCHRONIZED
+}
+
+
+::sal_Int32 SAL_CALL FormController::getActiveTerm()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ return m_nCurrentFilterPosition;
+}
+
+
+void SAL_CALL FormController::setActiveTerm( ::sal_Int32 ActiveTerm )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ if ( ( ActiveTerm < 0 ) || ( ActiveTerm >= getDisjunctiveTerms() ) )
+ throw IndexOutOfBoundsException( OUString(), *this );
+
+ if ( ActiveTerm == getActiveTerm() )
+ return;
+
+ m_nCurrentFilterPosition = ActiveTerm;
+ impl_setTextOnAllFilter_throw();
+}
+
+// XElementAccess
+
+sal_Bool SAL_CALL FormController::hasElements()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return !m_aChildren.empty();
+}
+
+
+Type SAL_CALL FormController::getElementType()
+{
+ return cppu::UnoType<XFormController>::get();
+
+}
+
+// XEnumerationAccess
+
+Reference< XEnumeration > SAL_CALL FormController::createEnumeration()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return new ::comphelper::OEnumerationByIndex(this);
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL FormController::getCount()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return m_aChildren.size();
+}
+
+
+Any SAL_CALL FormController::getByIndex(sal_Int32 Index)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (Index < 0 ||
+ o3tl::make_unsigned(Index) >= m_aChildren.size())
+ throw IndexOutOfBoundsException();
+
+ return Any( m_aChildren[ Index ] );
+}
+
+// EventListener
+
+void SAL_CALL FormController::disposing(const EventObject& e)
+{
+ // has the container been disposed
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XControlContainer > xContainer(e.Source, UNO_QUERY);
+ if (xContainer.is())
+ {
+ setContainer(Reference< XControlContainer > ());
+ }
+ else
+ {
+ // has a control been disposed
+ Reference< XControl > xControl(e.Source, UNO_QUERY);
+ if (xControl.is())
+ {
+ if (getContainer().is())
+ removeControl(xControl);
+ }
+ }
+}
+
+// OComponentHelper
+
+void FormController::disposeAllFeaturesAndDispatchers()
+{
+ for (auto& rDispatcher : m_aFeatureDispatchers)
+ {
+ try
+ {
+ ::comphelper::disposeComponent( rDispatcher.second );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ m_aFeatureDispatchers.clear();
+}
+
+
+void FormController::disposing()
+{
+ EventObject aEvt( *this );
+
+ // if we're still active, simulate a "deactivated" event
+ if ( m_xActiveControl.is() )
+ m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvt );
+
+ // notify all our listeners
+ m_aActivateListeners.disposeAndClear(aEvt);
+ m_aModifyListeners.disposeAndClear(aEvt);
+ m_aErrorListeners.disposeAndClear(aEvt);
+ m_aDeleteListeners.disposeAndClear(aEvt);
+ m_aRowSetApproveListeners.disposeAndClear(aEvt);
+ m_aParameterListeners.disposeAndClear(aEvt);
+ m_aFilterListeners.disposeAndClear(aEvt);
+
+ removeBoundFieldListener();
+ stopFiltering();
+
+ m_aControlBorderManager.restoreAll();
+
+ m_aFilterRows.clear();
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_xActiveControl = nullptr;
+ implSetCurrentControl( nullptr );
+
+ // clean up our children
+ for (const auto& rpChild : m_aChildren)
+ {
+ // search the position of the model within the form
+ Reference< XFormComponent > xForm(rpChild->getModel(), UNO_QUERY);
+ sal_uInt32 nPos = m_xModelAsIndex->getCount();
+ Reference< XFormComponent > xTemp;
+ for( ; nPos; )
+ {
+
+ m_xModelAsIndex->getByIndex( --nPos ) >>= xTemp;
+ if ( xForm.get() == xTemp.get() )
+ {
+ Reference< XInterface > xIfc( rpChild, UNO_QUERY );
+ m_xModelAsManager->detach( nPos, xIfc );
+ break;
+ }
+ }
+
+ Reference< XComponent > (rpChild, UNO_QUERY_THROW)->dispose();
+ }
+ m_aChildren.clear();
+
+ disposeAllFeaturesAndDispatchers();
+
+ if ( m_xFormOperations.is() )
+ m_xFormOperations->dispose();
+ m_xFormOperations.clear();
+
+ if (m_bDBConnection)
+ unload();
+
+ setContainer( nullptr );
+ setModel( nullptr );
+ setParent( nullptr );
+
+ ::comphelper::disposeComponent( m_xComposer );
+
+ m_bDBConnection = false;
+}
+
+
+namespace
+{
+ bool lcl_shouldUseDynamicControlBorder( const Reference< XInterface >& _rxForm, const Any& _rDynamicColorProp )
+ {
+ bool bDoUse = false;
+ if ( !( _rDynamicColorProp >>= bDoUse ) )
+ {
+ DocumentType eDocType = DocumentClassification::classifyHostDocument( _rxForm );
+ return ControlLayouter::useDynamicBorderColor( eDocType );
+ }
+ return bDoUse;
+ }
+}
+
+
+void SAL_CALL FormController::propertyChange(const PropertyChangeEvent& evt)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ if ( evt.PropertyName == FM_PROP_BOUNDFIELD )
+ {
+ Reference<XPropertySet> xOldBound;
+ evt.OldValue >>= xOldBound;
+ if ( !xOldBound.is() && evt.NewValue.hasValue() )
+ {
+ Reference< XControlModel > xControlModel(evt.Source,UNO_QUERY);
+ Reference< XControl > xControl = findControl(m_aControls,xControlModel,false,false);
+ if ( xControl.is() )
+ {
+ startControlModifyListening( xControl );
+ Reference<XPropertySet> xProp(xControlModel,UNO_QUERY);
+ if ( xProp.is() )
+ xProp->removePropertyChangeListener(FM_PROP_BOUNDFIELD, this);
+ }
+ }
+ }
+ else
+ {
+ bool bModifiedChanged = (evt.PropertyName == FM_PROP_ISMODIFIED);
+ bool bNewChanged = (evt.PropertyName == FM_PROP_ISNEW);
+ if (bModifiedChanged || bNewChanged)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if (bModifiedChanged)
+ m_bCurrentRecordModified = ::comphelper::getBOOL(evt.NewValue);
+ else
+ m_bCurrentRecordNew = ::comphelper::getBOOL(evt.NewValue);
+
+ // toggle the locking
+ if (m_bLocked != determineLockState())
+ {
+ m_bLocked = !m_bLocked;
+ setLocks();
+ if (isListeningForChanges())
+ startListening();
+ else
+ stopListening();
+ }
+
+ if ( bNewChanged )
+ m_aToggleEvent.Call();
+
+ if (!m_bCurrentRecordModified)
+ m_bModified = false;
+ }
+ else if ( evt.PropertyName == FM_PROP_DYNAMIC_CONTROL_BORDER )
+ {
+ bool bEnable = lcl_shouldUseDynamicControlBorder( evt.Source, evt.NewValue );
+ if ( bEnable )
+ {
+ m_aControlBorderManager.enableDynamicBorderColor();
+ if ( m_xActiveControl.is() )
+ m_aControlBorderManager.focusGained( m_xActiveControl );
+ }
+ else
+ {
+ m_aControlBorderManager.disableDynamicBorderColor();
+ }
+ }
+ }
+}
+
+
+bool FormController::replaceControl( const Reference< XControl >& _rxExistentControl, const Reference< XControl >& _rxNewControl )
+{
+ bool bSuccess = false;
+ try
+ {
+ Reference< XIdentifierReplace > xContainer( getContainer(), UNO_QUERY );
+ DBG_ASSERT( xContainer.is(), "FormController::replaceControl: yes, it's not required by the service description, but XIdentifierReplace would be nice!" );
+ if ( xContainer.is() )
+ {
+ // look up the ID of _rxExistentControl
+ const Sequence< sal_Int32 > aIdentifiers( xContainer->getIdentifiers() );
+ const sal_Int32* pIdentifiers = std::find_if(aIdentifiers.begin(), aIdentifiers.end(),
+ [&xContainer, &_rxExistentControl](const sal_Int32 nId) {
+ Reference< XControl > xCheck( xContainer->getByIdentifier( nId ), UNO_QUERY );
+ return xCheck == _rxExistentControl;
+ });
+ DBG_ASSERT( pIdentifiers != aIdentifiers.end(), "FormController::replaceControl: did not find the control in the container!" );
+ if ( pIdentifiers != aIdentifiers.end() )
+ {
+ bool bReplacedWasActive = ( m_xActiveControl.get() == _rxExistentControl.get() );
+ bool bReplacedWasCurrent = ( m_xCurrentControl.get() == _rxExistentControl.get() );
+
+ if ( bReplacedWasActive )
+ {
+ m_xActiveControl = nullptr;
+ implSetCurrentControl( nullptr );
+ }
+ else if ( bReplacedWasCurrent )
+ {
+ implSetCurrentControl( _rxNewControl );
+ }
+
+ // carry over the model
+ _rxNewControl->setModel( _rxExistentControl->getModel() );
+
+ xContainer->replaceByIdentifer( *pIdentifiers, Any( _rxNewControl ) );
+ bSuccess = true;
+
+ if ( bReplacedWasActive )
+ {
+ Reference< XWindow > xControlWindow( _rxNewControl, UNO_QUERY );
+ if ( xControlWindow.is() )
+ xControlWindow->setFocus();
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ Reference< XControl > xDisposeIt( bSuccess ? _rxExistentControl : _rxNewControl );
+ ::comphelper::disposeComponent( xDisposeIt );
+ return bSuccess;
+}
+
+
+void FormController::toggleAutoFields(bool bAutoFields)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+
+
+ Sequence< Reference< XControl > > aControlsCopy( m_aControls );
+ const Reference< XControl >* pControls = aControlsCopy.getConstArray();
+ sal_Int32 nControls = aControlsCopy.getLength();
+
+ if (bAutoFields)
+ {
+ // as we don't want new controls to be attached to the scripting environment
+ // we change attach flags
+ m_bAttachEvents = false;
+ for (sal_Int32 i = nControls; i > 0;)
+ {
+ Reference< XControl > xControl = pControls[--i];
+ if (xControl.is())
+ {
+ Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
+ if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
+ {
+ // does the model use a bound field ?
+ Reference< XPropertySet > xField;
+ xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
+
+ // is it an autofield?
+ if ( xField.is()
+ && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
+ && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_AUTOINCREMENT ) )
+ )
+ {
+ replaceControl( xControl, new FmXAutoControl() );
+ }
+ }
+ }
+ }
+ m_bAttachEvents = true;
+ }
+ else
+ {
+ m_bDetachEvents = false;
+ for (sal_Int32 i = nControls; i > 0;)
+ {
+ Reference< XControl > xControl = pControls[--i];
+ if (xControl.is())
+ {
+ Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
+ if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
+ {
+ // does the model use a bound field ?
+ Reference< XPropertySet > xField;
+ xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
+
+ // is it an autofield?
+ if ( xField.is()
+ && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField )
+ && ::comphelper::getBOOL( xField->getPropertyValue(FM_PROP_AUTOINCREMENT ) )
+ )
+ {
+ OUString sServiceName;
+ OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
+ Reference< XControl > xNewControl( m_xComponentContext->getServiceManager()->createInstanceWithContext( sServiceName, m_xComponentContext ), UNO_QUERY );
+ replaceControl( xControl, xNewControl );
+ }
+ }
+ }
+ }
+ m_bDetachEvents = true;
+ }
+}
+
+
+IMPL_LINK_NOARG(FormController, OnToggleAutoFields, void*, void)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+
+ toggleAutoFields(m_bCurrentRecordNew);
+}
+
+// XTextListener
+void SAL_CALL FormController::textChanged(const TextEvent& e)
+{
+ // SYNCHRONIZED -->
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ if ( !m_bFiltering )
+ {
+ impl_onModify();
+ return;
+ }
+
+ if ( m_bSuspendFilterTextListening )
+ return;
+
+ Reference< XTextComponent > xText(e.Source,UNO_QUERY);
+ OUString aText = xText->getText();
+
+ if ( m_aFilterRows.empty() )
+ appendEmptyDisjunctiveTerm();
+
+ // find the current row
+ if ( ( m_nCurrentFilterPosition < 0 ) || ( o3tl::make_unsigned(m_nCurrentFilterPosition) >= m_aFilterRows.size() ) )
+ {
+ OSL_ENSURE( false, "FormController::textChanged: m_nCurrentFilterPosition is wrong!" );
+ return;
+ }
+
+ FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ];
+
+ // do we have a new filter
+ if (!aText.isEmpty())
+ rRow[xText] = aText;
+ else
+ {
+ // do we have the control in the row
+ FmFilterRow::iterator iter = rRow.find(xText);
+ // erase the entry out of the row
+ if (iter != rRow.end())
+ rRow.erase(iter);
+ }
+
+ // multiplex the event to our FilterControllerListeners
+ FilterEvent aEvent;
+ aEvent.Source = *this;
+ aEvent.FilterComponent = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xText ) - m_aFilterComponents.begin();
+ aEvent.DisjunctiveTerm = getActiveTerm();
+ aEvent.PredicateExpression = aText;
+
+ aGuard.clear();
+ // <-- SYNCHRONIZED
+
+ // notify the changed filter expression
+ m_aFilterListeners.notifyEach( &XFilterControllerListener::predicateExpressionChanged, aEvent );
+}
+
+// XItemListener
+void SAL_CALL FormController::itemStateChanged(const ItemEvent& /*rEvent*/)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ impl_onModify();
+}
+
+// XModificationBroadcaster
+void SAL_CALL FormController::addModifyListener(const Reference< XModifyListener > & l)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ m_aModifyListeners.addInterface( l );
+}
+
+void FormController::removeModifyListener(const Reference< XModifyListener > & l)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ m_aModifyListeners.removeInterface( l );
+}
+
+// XModificationListener
+void FormController::modified( const EventObject& _rEvent )
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+
+ try
+ {
+ if ( _rEvent.Source != m_xActiveControl )
+ { // let this control grab the focus
+ // (this case may happen if somebody moves the scroll wheel of the mouse over a control
+ // which does not have the focus)
+ // 85511 - 29.05.2001 - frank.schoenheit@germany.sun.com
+
+ // also, it happens when an image control gets a new image by double-clicking it
+ // #i88458# / 2009-01-12 / frank.schoenheit@sun.com
+ Reference< XWindow > xControlWindow( _rEvent.Source, UNO_QUERY_THROW );
+ xControlWindow->setFocus();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ impl_onModify();
+}
+
+void FormController::impl_checkDisposed_throw() const
+{
+ if ( impl_isDisposed_nofail() )
+ throw DisposedException( OUString(), *const_cast< FormController* >( this ) );
+}
+
+void FormController::impl_onModify()
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_bModified )
+ m_bModified = true;
+ }
+
+ EventObject aEvt(static_cast<cppu::OWeakObject*>(this));
+ m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvt );
+}
+
+void FormController::impl_addFilterRow( const FmFilterRow& _row )
+{
+ m_aFilterRows.push_back( _row );
+
+ if ( m_aFilterRows.size() == 1 )
+ { // that's the first row ever
+ OSL_ENSURE( m_nCurrentFilterPosition == -1, "FormController::impl_addFilterRow: inconsistency!" );
+ m_nCurrentFilterPosition = 0;
+ }
+}
+
+void FormController::impl_appendEmptyFilterRow( ::osl::ClearableMutexGuard& _rClearBeforeNotify )
+{
+ // SYNCHRONIZED -->
+ impl_addFilterRow( FmFilterRow() );
+
+ // notify the listeners
+ FilterEvent aEvent;
+ aEvent.Source = *this;
+ aEvent.DisjunctiveTerm = static_cast<sal_Int32>(m_aFilterRows.size()) - 1;
+ _rClearBeforeNotify.clear();
+ // <-- SYNCHRONIZED
+ m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermAdded, aEvent );
+}
+
+bool FormController::determineLockState() const
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ // a.) in filter mode we are always locked
+ // b.) if we have no valid model or our model (a result set) is not alive -> we're locked
+ // c.) if we are inserting everything is OK and we are not locked
+ // d.) if are not updatable or on invalid position
+ Reference< XResultSet > xResultSet(m_xModelAsIndex, UNO_QUERY);
+ if (m_bFiltering || !xResultSet.is() || !isRowSetAlive(xResultSet))
+ return true;
+ else
+ return !(m_bCanInsert && m_bCurrentRecordNew)
+ && (xResultSet->isBeforeFirst() || xResultSet->isAfterLast() || xResultSet->rowDeleted() || !m_bCanUpdate);
+}
+
+// FocusListener
+void FormController::focusGained(const FocusEvent& e)
+{
+ // SYNCHRONIZED -->
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ m_aControlBorderManager.focusGained( e.Source );
+
+ Reference< XControl > xControl(e.Source, UNO_QUERY);
+ if (m_bDBConnection)
+ {
+ // do we need to keep the locking of the commit
+ // we hold the lock as long as the control differs from the current
+ // otherwise we disabled the lock
+ m_bCommitLock = m_bCommitLock && xControl.get() != m_xCurrentControl.get();
+ if (m_bCommitLock)
+ return;
+
+ // when do we have to commit a value to form or a filter
+ // a.) if the current value is modified
+ // b.) there must be a current control
+ // c.) and it must be different from the new focus owning control or
+ // d.) the focus is moving around (so we have only one control)
+
+ if ( ( m_bModified || m_bFiltering )
+ && m_xCurrentControl.is()
+ && ( ( xControl.get() != m_xCurrentControl.get() )
+ || ( ( e.FocusFlags & FocusChangeReason::AROUND )
+ && ( m_bCycle || m_bFiltering )
+ )
+ )
+ )
+ {
+ // check the old control if the content is ok
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+ Reference< XBoundControl > xLockingTest(m_xCurrentControl, UNO_QUERY);
+ bool bControlIsLocked = xLockingTest.is() && xLockingTest->getLock();
+ assert(!bControlIsLocked && "FormController::Gained: I'm modified and the current control is locked ? How this ?");
+ // normally, a locked control should not be modified, so probably my bModified must
+ // have been set from a different context, which I would not understand ...
+#endif
+ DBG_ASSERT(m_xCurrentControl.is(), "no CurrentControl set");
+ // first the control ask if it supports the IFace
+ Reference< XBoundComponent > xBound(m_xCurrentControl, UNO_QUERY);
+ if (!xBound.is() && m_xCurrentControl.is())
+ xBound.set(m_xCurrentControl->getModel(), UNO_QUERY);
+
+ // lock if we lose the focus during commit
+ m_bCommitLock = true;
+
+ // commit unsuccessful, reset focus
+ if (xBound.is() && !xBound->commit())
+ {
+ // the commit failed and we don't commit again until the current control
+ // which couldn't be commit gains the focus again
+ Reference< XWindow > xWindow(m_xCurrentControl, UNO_QUERY);
+ if (xWindow.is())
+ xWindow->setFocus();
+ return;
+ }
+ else
+ {
+ m_bModified = false;
+ m_bCommitLock = false;
+ }
+ }
+
+ if (!m_bFiltering && m_bCycle && (e.FocusFlags & FocusChangeReason::AROUND) && m_xCurrentControl.is())
+ {
+ OSL_ENSURE( m_xFormOperations.is(), "FormController::focusGained: hmm?" );
+ // should have been created in setModel
+ try
+ {
+ if ( e.FocusFlags & FocusChangeReason::FORWARD )
+ {
+ if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToNext ) )
+ m_xFormOperations->execute( FormFeature::MoveToNext );
+ }
+ else // backward
+ {
+ if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToPrevious ) )
+ m_xFormOperations->execute( FormFeature::MoveToPrevious );
+ }
+ }
+ catch ( const Exception& )
+ {
+ // don't handle this any further. That's an ... admissible error.
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+
+ // still one and the same control
+ if ( ( m_xActiveControl == xControl )
+ && ( xControl == m_xCurrentControl )
+ )
+ {
+ DBG_ASSERT(m_xCurrentControl.is(), "No CurrentControl selected");
+ return;
+ }
+
+ bool bActivated = !m_xActiveControl.is() && xControl.is();
+
+ m_xActiveControl = xControl;
+
+ implSetCurrentControl( xControl );
+ SAL_WARN_IF( !m_xCurrentControl.is(), "svx.form", "implSetCurrentControl did nonsense!" );
+
+ if ( bActivated )
+ {
+ // (asynchronously) call activation handlers
+ m_aActivationEvent.Call();
+
+ // call modify listeners
+ if ( m_bModified )
+ m_aModifyListeners.notifyEach( &XModifyListener::modified, EventObject( *this ) );
+ }
+
+ // invalidate all features which depend on the currently focused control
+ if ( m_bDBConnection && !m_bFiltering )
+ implInvalidateCurrentControlDependentFeatures();
+
+ if ( !m_xCurrentControl.is() )
+ return;
+
+ // control gets focus, then possibly in the visible range
+ Reference< XFormControllerContext > xContext( m_xFormControllerContext );
+ Reference< XControl > xCurrentControl( m_xCurrentControl );
+ aGuard.clear();
+ // <-- SYNCHRONIZED
+
+ if ( xContext.is() )
+ xContext->makeVisible( xCurrentControl );
+}
+
+IMPL_LINK_NOARG( FormController, OnActivated, void*, void )
+{
+ EventObject aEvent;
+ aEvent.Source = *this;
+ m_aActivateListeners.notifyEach( &XFormControllerListener::formActivated, aEvent );
+}
+
+IMPL_LINK_NOARG( FormController, OnDeactivated, void*, void )
+{
+ EventObject aEvent;
+ aEvent.Source = *this;
+ m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvent );
+}
+
+void FormController::focusLost(const FocusEvent& e)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+
+ m_aControlBorderManager.focusLost( e.Source );
+
+ Reference< XWindowPeer > xNext(e.NextFocus, UNO_QUERY);
+ // if focus hasn't passed to some other window, e.g. focus in a welded item, don't deactivate
+ if (!xNext)
+ return;
+ Reference< XControl > xNextControl = isInList(xNext);
+ if (!xNextControl.is())
+ {
+ m_xActiveControl = nullptr;
+ m_aDeactivationEvent.Call();
+ }
+}
+
+void SAL_CALL FormController::mousePressed( const awt::MouseEvent& /*_rEvent*/ )
+{
+ // not interested in
+}
+
+void SAL_CALL FormController::mouseReleased( const awt::MouseEvent& /*_rEvent*/ )
+{
+ // not interested in
+}
+
+void SAL_CALL FormController::mouseEntered( const awt::MouseEvent& _rEvent )
+{
+ m_aControlBorderManager.mouseEntered( _rEvent.Source );
+}
+
+void SAL_CALL FormController::mouseExited( const awt::MouseEvent& _rEvent )
+{
+ m_aControlBorderManager.mouseExited( _rEvent.Source );
+}
+
+void SAL_CALL FormController::componentValidityChanged( const EventObject& _rSource )
+{
+ Reference< XControl > xControl( findControl( m_aControls, Reference< XControlModel >( _rSource.Source, UNO_QUERY ), false, false ) );
+ Reference< XValidatableFormComponent > xValidatable( _rSource.Source, UNO_QUERY );
+
+ OSL_ENSURE( xControl.is() && xValidatable.is(), "FormController::componentValidityChanged: huh?" );
+
+ if ( xControl.is() && xValidatable.is() )
+ m_aControlBorderManager.validityChanged( xControl, xValidatable );
+}
+
+
+void FormController::setModel(const Reference< XTabControllerModel > & Model)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ DBG_ASSERT(m_xTabController.is(), "FormController::setModel : invalid aggregate !");
+
+ try
+ {
+ // disconnect from the old model
+ if (m_xModelAsIndex.is())
+ {
+ if (m_bDBConnection)
+ {
+ // we are currently working on the model
+ EventObject aEvt(m_xModelAsIndex);
+ unloaded(aEvt);
+ }
+
+ Reference< XLoadable > xForm(m_xModelAsIndex, UNO_QUERY);
+ if (xForm.is())
+ xForm->removeLoadListener(this);
+
+ Reference< XSQLErrorBroadcaster > xBroadcaster(m_xModelAsIndex, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeSQLErrorListener(this);
+
+ Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(m_xModelAsIndex, UNO_QUERY);
+ if (xParamBroadcaster.is())
+ xParamBroadcaster->removeParameterListener(this);
+
+ }
+
+ disposeAllFeaturesAndDispatchers();
+
+ if ( m_xFormOperations.is() )
+ m_xFormOperations->dispose();
+ m_xFormOperations.clear();
+
+ // set the new model wait for the load event
+ if (m_xTabController.is())
+ m_xTabController->setModel(Model);
+ m_xModelAsIndex.set(Model, UNO_QUERY);
+ m_xModelAsManager.set(Model, UNO_QUERY);
+
+ // only if both ifaces exit, the controller will work successful
+ if (!m_xModelAsIndex.is() || !m_xModelAsManager.is())
+ {
+ m_xModelAsManager = nullptr;
+ m_xModelAsIndex = nullptr;
+ }
+
+ if (m_xModelAsIndex.is())
+ {
+ // re-create m_xFormOperations
+ m_xFormOperations = FormOperations::createWithFormController( m_xComponentContext, this );
+ m_xFormOperations->setFeatureInvalidation( this );
+
+ // adding load and ui interaction listeners
+ Reference< XLoadable > xForm(Model, UNO_QUERY);
+ if (xForm.is())
+ xForm->addLoadListener(this);
+
+ Reference< XSQLErrorBroadcaster > xBroadcaster(Model, UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addSQLErrorListener(this);
+
+ Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(Model, UNO_QUERY);
+ if (xParamBroadcaster.is())
+ xParamBroadcaster->addParameterListener(this);
+
+ // well, is the database already loaded?
+ // then we have to simulate a load event
+ Reference< XLoadable > xCursor(m_xModelAsIndex, UNO_QUERY);
+ if (xCursor.is() && xCursor->isLoaded())
+ {
+ EventObject aEvt(xCursor);
+ loaded(aEvt);
+ }
+
+ Reference< XPropertySet > xModelProps( m_xModelAsIndex, UNO_QUERY );
+ Reference< XPropertySetInfo > xPropInfo( xModelProps->getPropertySetInfo() );
+ if ( xPropInfo.is()
+ && xPropInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER )
+ && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_FOCUS )
+ && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_MOUSE )
+ && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_INVALID )
+ )
+ {
+ bool bEnableDynamicControlBorder = lcl_shouldUseDynamicControlBorder(
+ xModelProps, xModelProps->getPropertyValue( FM_PROP_DYNAMIC_CONTROL_BORDER ) );
+ if ( bEnableDynamicControlBorder )
+ m_aControlBorderManager.enableDynamicBorderColor();
+ else
+ m_aControlBorderManager.disableDynamicBorderColor();
+
+ Color nColor;
+ if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_FOCUS ) >>= nColor )
+ m_aControlBorderManager.setStatusColor( ControlStatus::Focused, nColor );
+ if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_MOUSE ) >>= nColor )
+ m_aControlBorderManager.setStatusColor( ControlStatus::MouseHover, nColor );
+ if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_INVALID ) >>= nColor )
+ m_aControlBorderManager.setStatusColor( ControlStatus::Invalid, nColor );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+Reference< XTabControllerModel > FormController::getModel()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ DBG_ASSERT(m_xTabController.is(), "FormController::getModel : invalid aggregate !");
+ if (!m_xTabController.is())
+ return Reference< XTabControllerModel > ();
+ return m_xTabController->getModel();
+}
+
+
+void FormController::addToEventAttacher(const Reference< XControl > & xControl)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ OSL_ENSURE( xControl.is(), "FormController::addToEventAttacher: invalid control - how did you reach this?" );
+ if ( !xControl.is() )
+ return; /* throw IllegalArgumentException(); */
+
+ // register at the event attacher
+ Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
+ if (!(xComp.is() && m_xModelAsIndex.is()))
+ return;
+
+ // and look for the position of the ControlModel in it
+ sal_uInt32 nPos = m_xModelAsIndex->getCount();
+ Reference< XFormComponent > xTemp;
+ for( ; nPos; )
+ {
+ m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
+ if (xComp.get() == xTemp.get())
+ {
+ m_xModelAsManager->attach( nPos, Reference<XInterface>( xControl, UNO_QUERY ), Any(xControl) );
+ break;
+ }
+ }
+}
+
+
+void FormController::removeFromEventAttacher(const Reference< XControl > & xControl)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ OSL_ENSURE( xControl.is(), "FormController::removeFromEventAttacher: invalid control - how did you reach this?" );
+ if ( !xControl.is() )
+ return; /* throw IllegalArgumentException(); */
+
+ // register at the event attacher
+ Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY);
+ if ( !(xComp.is() && m_xModelAsIndex.is()) )
+ return;
+
+ // and look for the position of the ControlModel in it
+ sal_uInt32 nPos = m_xModelAsIndex->getCount();
+ Reference< XFormComponent > xTemp;
+ for( ; nPos; )
+ {
+ m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
+ if (xComp.get() == xTemp.get())
+ {
+ m_xModelAsManager->detach( nPos, Reference<XInterface>( xControl, UNO_QUERY ) );
+ break;
+ }
+ }
+}
+
+
+void FormController::setContainer(const Reference< XControlContainer > & xContainer)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ Reference< XTabControllerModel > xTabModel(getModel());
+ DBG_ASSERT(xTabModel.is() || !xContainer.is(), "No Model defined");
+ // if we have a new container we need a model
+ DBG_ASSERT(m_xTabController.is(), "FormController::setContainer : invalid aggregate !");
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XContainer > xCurrentContainer;
+ if (m_xTabController.is())
+ xCurrentContainer.set(m_xTabController->getContainer(), UNO_QUERY);
+ if (xCurrentContainer.is())
+ {
+ xCurrentContainer->removeContainerListener(this);
+
+ if ( m_aTabActivationIdle.IsActive() )
+ m_aTabActivationIdle.Stop();
+
+ // clear the filter map
+ ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
+ m_aFilterComponents.clear();
+
+ // collecting the controls
+ for ( const Reference< XControl >& rControl : std::as_const(m_aControls) )
+ implControlRemoved( rControl, true );
+
+ // make database-specific things
+ if (m_bDBConnection && isListeningForChanges())
+ stopListening();
+
+ m_aControls.realloc( 0 );
+ }
+
+ if (m_xTabController.is())
+ m_xTabController->setContainer(xContainer);
+
+ // What controls belong to the container?
+ if (xContainer.is() && xTabModel.is())
+ {
+ const Sequence< Reference< XControlModel > > aModels = xTabModel->getControlModels();
+ Sequence< Reference< XControl > > aAllControls = xContainer->getControls();
+
+ sal_Int32 nCount = aModels.getLength();
+ m_aControls = Sequence< Reference< XControl > >( nCount );
+ Reference< XControl > * pControls = m_aControls.getArray();
+
+ // collecting the controls
+ sal_Int32 j = 0;
+ for (const Reference< XControlModel >& rModel : aModels )
+ {
+ Reference< XControl > xControl = findControl( aAllControls, rModel, false, true );
+ if ( xControl.is() )
+ {
+ pControls[j++] = xControl;
+ implControlInserted( xControl, true );
+ }
+ }
+
+ // not every model had an associated control
+ if (j != nCount)
+ m_aControls.realloc(j);
+
+ // listen at the container
+ Reference< XContainer > xNewContainer(xContainer, UNO_QUERY);
+ if (xNewContainer.is())
+ xNewContainer->addContainerListener(this);
+
+ // make database-specific things
+ if (m_bDBConnection)
+ {
+ m_bLocked = determineLockState();
+ setLocks();
+ if (!isLocked())
+ startListening();
+ }
+ }
+ // the controls are in the right order
+ m_bControlsSorted = true;
+}
+
+
+Reference< XControlContainer > FormController::getContainer()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ DBG_ASSERT(m_xTabController.is(), "FormController::getContainer : invalid aggregate !");
+ if (!m_xTabController.is())
+ return Reference< XControlContainer > ();
+ return m_xTabController->getContainer();
+}
+
+
+Sequence< Reference< XControl > > FormController::getControls()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ if (!m_bControlsSorted)
+ {
+ Reference< XTabControllerModel > xModel = getModel();
+ if (!xModel.is())
+ return m_aControls;
+
+ const Sequence< Reference< XControlModel > > aControlModels = xModel->getControlModels();
+ sal_Int32 nModels = aControlModels.getLength();
+
+ Sequence< Reference< XControl > > aNewControls(nModels);
+
+ Reference< XControl > * pControls = aNewControls.getArray();
+ Reference< XControl > xControl;
+
+ // rearrange the controls according to the tab order sequence
+ sal_Int32 j = 0;
+ for ( const Reference< XControlModel >& rModel : aControlModels )
+ {
+ xControl = findControl( m_aControls, rModel, true, true );
+ if ( xControl.is() )
+ pControls[j++] = xControl;
+ }
+
+ // not every model had an associated control
+ if ( j != nModels )
+ aNewControls.realloc( j );
+
+ m_aControls = aNewControls;
+ m_bControlsSorted = true;
+ }
+ return m_aControls;
+}
+
+
+void FormController::autoTabOrder()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ DBG_ASSERT(m_xTabController.is(), "FormController::autoTabOrder : invalid aggregate !");
+ if (m_xTabController.is())
+ m_xTabController->autoTabOrder();
+}
+
+
+void FormController::activateTabOrder()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ DBG_ASSERT(m_xTabController.is(), "FormController::activateTabOrder : invalid aggregate !");
+ if (m_xTabController.is())
+ m_xTabController->activateTabOrder();
+}
+
+
+void FormController::setControlLock(const Reference< XControl > & xControl)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ bool bLocked = isLocked();
+
+ // It is locked
+ // a. if the entire record is locked
+ // b. if the associated field is locked
+ Reference< XBoundControl > xBound(xControl, UNO_QUERY);
+ if (!(xBound.is() &&
+ ( (bLocked && bLocked != bool(xBound->getLock())) ||
+ !bLocked))) // always uncheck individual fields when unlocking
+ return;
+
+ // there is a data source
+ Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
+ if (!(xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet)))
+ return;
+
+ // what about the ReadOnly and Enable properties
+ bool bTouch = true;
+ if (::comphelper::hasProperty(FM_PROP_ENABLED, xSet))
+ bTouch = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ENABLED));
+ if (::comphelper::hasProperty(FM_PROP_READONLY, xSet))
+ bTouch = !::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_READONLY));
+
+ if (!bTouch)
+ return;
+
+ Reference< XPropertySet > xField;
+ xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
+ if (!xField.is())
+ return;
+
+ if (bLocked)
+ xBound->setLock(bLocked);
+ else
+ {
+ try
+ {
+ Any aVal = xField->getPropertyValue(FM_PROP_ISREADONLY);
+ if (aVal.hasValue() && ::comphelper::getBOOL(aVal))
+ xBound->setLock(true);
+ else
+ xBound->setLock(bLocked);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ }
+}
+
+
+void FormController::setLocks()
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ // lock/unlock all controls connected to a data source
+ for ( const Reference< XControl >& rControl : std::as_const(m_aControls) )
+ setControlLock( rControl );
+}
+
+
+namespace
+{
+ bool lcl_shouldListenForModifications( const Reference< XControl >& _rxControl, const Reference< XPropertyChangeListener >& _rxBoundFieldListener )
+ {
+ bool bShould = false;
+
+ Reference< XBoundComponent > xBound( _rxControl, UNO_QUERY );
+ if ( xBound.is() )
+ {
+ bShould = true;
+ }
+ else if ( _rxControl.is() )
+ {
+ Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
+ if ( xModelProps.is() && ::comphelper::hasProperty( FM_PROP_BOUNDFIELD, xModelProps ) )
+ {
+ Reference< XPropertySet > xField;
+ xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
+ bShould = xField.is();
+
+ if ( !bShould && _rxBoundFieldListener.is() )
+ xModelProps->addPropertyChangeListener( FM_PROP_BOUNDFIELD, _rxBoundFieldListener );
+ }
+ }
+
+ return bShould;
+ }
+}
+
+
+void FormController::startControlModifyListening(const Reference< XControl > & xControl)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+
+ bool bModifyListening = lcl_shouldListenForModifications( xControl, this );
+
+ // artificial while
+ while ( bModifyListening )
+ {
+ Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
+ if (xMod.is())
+ {
+ xMod->addModifyListener(this);
+ break;
+ }
+
+ // all the text to prematurely recognize a modified
+ Reference< XTextComponent > xText(xControl, UNO_QUERY);
+ if (xText.is())
+ {
+ xText->addTextListener(this);
+ break;
+ }
+
+ Reference< XCheckBox > xBox(xControl, UNO_QUERY);
+ if (xBox.is())
+ {
+ xBox->addItemListener(this);
+ break;
+ }
+
+ Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
+ if (xCbBox.is())
+ {
+ xCbBox->addItemListener(this);
+ break;
+ }
+
+ Reference< XListBox > xListBox(xControl, UNO_QUERY);
+ if (xListBox.is())
+ {
+ xListBox->addItemListener(this);
+ break;
+ }
+ break;
+ }
+}
+
+
+void FormController::stopControlModifyListening(const Reference< XControl > & xControl)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+
+ bool bModifyListening = lcl_shouldListenForModifications( xControl, nullptr );
+
+ // artificial while
+ while (bModifyListening)
+ {
+ Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY);
+ if (xMod.is())
+ {
+ xMod->removeModifyListener(this);
+ break;
+ }
+ // all the text to prematurely recognize a modified
+ Reference< XTextComponent > xText(xControl, UNO_QUERY);
+ if (xText.is())
+ {
+ xText->removeTextListener(this);
+ break;
+ }
+
+ Reference< XCheckBox > xBox(xControl, UNO_QUERY);
+ if (xBox.is())
+ {
+ xBox->removeItemListener(this);
+ break;
+ }
+
+ Reference< XComboBox > xCbBox(xControl, UNO_QUERY);
+ if (xCbBox.is())
+ {
+ xCbBox->removeItemListener(this);
+ break;
+ }
+
+ Reference< XListBox > xListBox(xControl, UNO_QUERY);
+ if (xListBox.is())
+ {
+ xListBox->removeItemListener(this);
+ break;
+ }
+ break;
+ }
+}
+
+
+void FormController::startListening()
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ m_bModified = false;
+
+ // now register at bound fields
+ for ( const Reference< XControl >& rControl : std::as_const(m_aControls) )
+ startControlModifyListening( rControl );
+}
+
+
+void FormController::stopListening()
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ m_bModified = false;
+
+ // now register at bound fields
+ for ( const Reference< XControl >& rControl : std::as_const(m_aControls) )
+ stopControlModifyListening( rControl );
+}
+
+
+Reference< XControl > FormController::findControl(Sequence< Reference< XControl > >& _rControls, const Reference< XControlModel > & xCtrlModel ,bool _bRemove,bool _bOverWrite) const
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ DBG_ASSERT( xCtrlModel.is(), "findControl - which ?!" );
+
+ const Reference< XControl >* pControls = std::find_if(std::cbegin(_rControls), std::cend(_rControls),
+ [&xCtrlModel](const Reference< XControl >& rControl) {
+ return rControl.is() && rControl->getModel().get() == xCtrlModel.get(); });
+ if (pControls != std::cend(_rControls))
+ {
+ Reference< XControl > xControl( *pControls );
+ auto i = static_cast<sal_Int32>(std::distance(std::cbegin(_rControls), pControls));
+ if ( _bRemove )
+ ::comphelper::removeElementAt( _rControls, i );
+ else if ( _bOverWrite )
+ _rControls.getArray()[i].clear();
+ return xControl;
+ }
+ return Reference< XControl > ();
+}
+
+
+void FormController::implControlInserted( const Reference< XControl>& _rxControl, bool _bAddToEventAttacher )
+{
+ Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
+ if ( xWindow.is() )
+ {
+ xWindow->addFocusListener( this );
+ xWindow->addMouseListener( this );
+
+ if ( _bAddToEventAttacher )
+ addToEventAttacher( _rxControl );
+ }
+
+ // add a dispatch interceptor to the control (if supported)
+ Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY );
+ if ( xInterception.is() )
+ createInterceptor( xInterception );
+
+ if ( !_rxControl.is() )
+ return;
+
+ Reference< XControlModel > xModel( _rxControl->getModel() );
+
+ // we want to know about the reset of the model of our controls
+ // (for correctly resetting m_bModified)
+ Reference< XReset > xReset( xModel, UNO_QUERY );
+ if ( xReset.is() )
+ xReset->addResetListener( this );
+
+ // and we want to know about the validity, to visually indicate it
+ Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
+ if ( xValidatable.is() )
+ {
+ xValidatable->addFormComponentValidityListener( this );
+ m_aControlBorderManager.validityChanged( _rxControl, xValidatable );
+ }
+
+}
+
+
+void FormController::implControlRemoved( const Reference< XControl>& _rxControl, bool _bRemoveFromEventAttacher )
+{
+ Reference< XWindow > xWindow( _rxControl, UNO_QUERY );
+ if ( xWindow.is() )
+ {
+ xWindow->removeFocusListener( this );
+ xWindow->removeMouseListener( this );
+
+ if ( _bRemoveFromEventAttacher )
+ removeFromEventAttacher( _rxControl );
+ }
+
+ Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY);
+ if ( xInterception.is() )
+ deleteInterceptor( xInterception );
+
+ if ( _rxControl.is() )
+ {
+ Reference< XControlModel > xModel( _rxControl->getModel() );
+
+ Reference< XReset > xReset( xModel, UNO_QUERY );
+ if ( xReset.is() )
+ xReset->removeResetListener( this );
+
+ Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY );
+ if ( xValidatable.is() )
+ xValidatable->removeFormComponentValidityListener( this );
+ }
+}
+
+
+void FormController::implSetCurrentControl( const Reference< XControl >& _rxControl )
+{
+ if ( m_xCurrentControl.get() == _rxControl.get() )
+ return;
+
+ Reference< XGridControl > xGridControl( m_xCurrentControl, UNO_QUERY );
+ if ( xGridControl.is() )
+ xGridControl->removeGridControlListener( this );
+
+ m_xCurrentControl = _rxControl;
+
+ xGridControl.set( m_xCurrentControl, UNO_QUERY );
+ if ( xGridControl.is() )
+ xGridControl->addGridControlListener( this );
+}
+
+
+void FormController::insertControl(const Reference< XControl > & xControl)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ m_bControlsSorted = false;
+ m_aControls.realloc(m_aControls.getLength() + 1);
+ m_aControls.getArray()[m_aControls.getLength() - 1] = xControl;
+
+ if (m_pColumnInfoCache)
+ m_pColumnInfoCache->deinitializeControls();
+
+ implControlInserted( xControl, m_bAttachEvents );
+
+ if (m_bDBConnection && !m_bFiltering)
+ setControlLock(xControl);
+
+ if (isListeningForChanges() && m_bAttachEvents)
+ startControlModifyListening( xControl );
+}
+
+
+void FormController::removeControl(const Reference< XControl > & xControl)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ auto pControl = std::find_if(std::cbegin(m_aControls), std::cend(m_aControls),
+ [&xControl](const Reference< XControl >& rControl) { return xControl.get() == rControl.get(); });
+ if (pControl != std::cend(m_aControls))
+ {
+ auto nIndex = static_cast<sal_Int32>(std::distance(std::cbegin(m_aControls), pControl));
+ ::comphelper::removeElementAt( m_aControls, nIndex );
+ }
+
+ FilterComponents::iterator componentPos = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
+ if ( componentPos != m_aFilterComponents.end() )
+ m_aFilterComponents.erase( componentPos );
+
+ implControlRemoved( xControl, m_bDetachEvents );
+
+ if ( isListeningForChanges() && m_bDetachEvents )
+ stopControlModifyListening( xControl );
+}
+
+// XLoadListener
+
+void FormController::loaded(const EventObject& rEvent)
+{
+ OSL_ENSURE( rEvent.Source == m_xModelAsIndex, "FormController::loaded: where did this come from?" );
+
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XRowSet > xForm(rEvent.Source, UNO_QUERY);
+ // do we have a connected data source
+ if (xForm.is() && getConnection(xForm).is())
+ {
+ Reference< XPropertySet > xSet(xForm, UNO_QUERY);
+ if (xSet.is())
+ {
+ Any aVal = xSet->getPropertyValue(FM_PROP_CYCLE);
+ sal_Int32 aVal2 = 0;
+ ::cppu::enum2int(aVal2,aVal);
+ m_bCycle = !aVal.hasValue() || static_cast<form::TabulatorCycle>(aVal2) == TabulatorCycle_RECORDS;
+ m_bCanUpdate = canUpdate(xSet);
+ m_bCanInsert = canInsert(xSet);
+ m_bCurrentRecordModified = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED));
+ m_bCurrentRecordNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW));
+
+ startFormListening( xSet, false );
+
+ // set the locks for the current controls
+ if (getContainer().is())
+ {
+ m_aLoadEvent.Call();
+ }
+ }
+ else
+ {
+ m_bCanInsert = m_bCanUpdate = m_bCycle = false;
+ m_bCurrentRecordModified = false;
+ m_bCurrentRecordNew = false;
+ m_bLocked = false;
+ }
+ m_bDBConnection = true;
+ }
+ else
+ {
+ m_bDBConnection = false;
+ m_bCanInsert = m_bCanUpdate = m_bCycle = false;
+ m_bCurrentRecordModified = false;
+ m_bCurrentRecordNew = false;
+ m_bLocked = false;
+ }
+
+ Reference< XColumnsSupplier > xFormColumns( xForm, UNO_QUERY );
+ m_pColumnInfoCache.reset( xFormColumns.is() ? new ColumnInfoCache( xFormColumns ) : nullptr );
+
+ updateAllDispatchers();
+}
+
+
+void FormController::updateAllDispatchers() const
+{
+ ::std::for_each(
+ m_aFeatureDispatchers.begin(),
+ m_aFeatureDispatchers.end(),
+ [] (const DispatcherContainer::value_type& dispatcher) {
+ UpdateAllListeners()(dispatcher.second);
+ });
+}
+
+
+IMPL_LINK_NOARG(FormController, OnLoad, void*, void)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ m_bLocked = determineLockState();
+
+ setLocks();
+
+ if (!m_bLocked)
+ startListening();
+
+ // just one exception toggle the auto values
+ if (m_bCurrentRecordNew)
+ toggleAutoFields(true);
+}
+
+
+void FormController::unloaded(const EventObject& /*rEvent*/)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ updateAllDispatchers();
+}
+
+
+void FormController::reloading(const EventObject& /*aEvent*/)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ // do the same like in unloading
+ // just one exception toggle the auto values
+ m_aToggleEvent.CancelPendingCall();
+ unload();
+}
+
+
+void FormController::reloaded(const EventObject& aEvent)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ loaded(aEvent);
+}
+
+
+void FormController::unloading(const EventObject& /*aEvent*/)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ unload();
+}
+
+
+void FormController::unload()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ m_aLoadEvent.CancelPendingCall();
+
+ // be sure not to have autofields
+ if (m_bCurrentRecordNew)
+ toggleAutoFields(false);
+
+ // remove bound field listing again
+ removeBoundFieldListener();
+
+ if (m_bDBConnection && isListeningForChanges())
+ stopListening();
+
+ Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
+ if ( m_bDBConnection && xSet.is() )
+ stopFormListening( xSet, false );
+
+ m_bDBConnection = false;
+ m_bCanInsert = m_bCanUpdate = m_bCycle = false;
+ m_bCurrentRecordModified = m_bCurrentRecordNew = m_bLocked = false;
+
+ m_pColumnInfoCache.reset();
+}
+
+
+void FormController::removeBoundFieldListener()
+{
+ for ( const Reference< XControl >& rControl : std::as_const(m_aControls) )
+ {
+ Reference< XPropertySet > xProp( rControl, UNO_QUERY );
+ if ( xProp.is() )
+ xProp->removePropertyChangeListener( FM_PROP_BOUNDFIELD, this );
+ }
+}
+
+
+void FormController::startFormListening( const Reference< XPropertySet >& _rxForm, bool _bPropertiesOnly )
+{
+ try
+ {
+ if ( m_bCanInsert || m_bCanUpdate ) // form can be modified
+ {
+ _rxForm->addPropertyChangeListener( FM_PROP_ISNEW, this );
+ _rxForm->addPropertyChangeListener( FM_PROP_ISMODIFIED, this );
+
+ if ( !_bPropertiesOnly )
+ {
+ // set the Listener for UI interaction
+ Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
+ if ( xApprove.is() )
+ xApprove->addRowSetApproveListener( this );
+
+ // listener for row set changes
+ Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
+ if ( xRowSet.is() )
+ xRowSet->addRowSetListener( this );
+ }
+ }
+
+ Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
+ if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
+ _rxForm->addPropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+
+void FormController::stopFormListening( const Reference< XPropertySet >& _rxForm, bool _bPropertiesOnly )
+{
+ try
+ {
+ if ( m_bCanInsert || m_bCanUpdate )
+ {
+ _rxForm->removePropertyChangeListener( FM_PROP_ISNEW, this );
+ _rxForm->removePropertyChangeListener( FM_PROP_ISMODIFIED, this );
+
+ if ( !_bPropertiesOnly )
+ {
+ Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY );
+ if (xApprove.is())
+ xApprove->removeRowSetApproveListener(this);
+
+ Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY );
+ if ( xRowSet.is() )
+ xRowSet->removeRowSetListener( this );
+ }
+ }
+
+ Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo();
+ if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) )
+ _rxForm->removePropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+// css::sdbc::XRowSetListener
+
+void FormController::cursorMoved(const EventObject& /*event*/)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ // toggle the locking ?
+ if (m_bLocked != determineLockState())
+ {
+ m_bLocked = !m_bLocked;
+ setLocks();
+ if (isListeningForChanges())
+ startListening();
+ else
+ stopListening();
+ }
+
+ // neither the current control nor the current record are modified anymore
+ m_bCurrentRecordModified = m_bModified = false;
+}
+
+
+void FormController::rowChanged(const EventObject& /*event*/)
+{
+ // not interested in ...
+}
+
+void FormController::rowSetChanged(const EventObject& /*event*/)
+{
+ // not interested in ...
+}
+
+
+// XContainerListener
+
+void SAL_CALL FormController::elementInserted(const ContainerEvent& evt)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ Reference< XControl > xControl( evt.Element, UNO_QUERY );
+ if ( !xControl.is() )
+ return;
+
+ Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
+ if (xModel.is() && m_xModelAsIndex == xModel->getParent())
+ {
+ insertControl(xControl);
+
+ if ( m_aTabActivationIdle.IsActive() )
+ m_aTabActivationIdle.Stop();
+
+ m_aTabActivationIdle.Start();
+ }
+ // are we in filtermode and a XModeSelector has inserted an element
+ else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
+ {
+ xModel.set(evt.Source, UNO_QUERY);
+ if (xModel.is() && m_xModelAsIndex == xModel->getParent())
+ {
+ Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
+ if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
+ {
+ // does the model use a bound field ?
+ Reference< XPropertySet > xField;
+ xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
+
+ Reference< XTextComponent > xText(xControl, UNO_QUERY);
+ // may we filter the field?
+ if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
+ ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
+ {
+ m_aFilterComponents.push_back( xText );
+ xText->addTextListener( this );
+ }
+ }
+ }
+ }
+}
+
+
+void SAL_CALL FormController::elementReplaced(const ContainerEvent& evt)
+{
+ // simulate an elementRemoved
+ ContainerEvent aRemoveEvent( evt );
+ aRemoveEvent.Element = evt.ReplacedElement;
+ aRemoveEvent.ReplacedElement = Any();
+ elementRemoved( aRemoveEvent );
+
+ // simulate an elementInserted
+ ContainerEvent aInsertEvent( evt );
+ aInsertEvent.ReplacedElement = Any();
+ elementInserted( aInsertEvent );
+}
+
+
+void SAL_CALL FormController::elementRemoved(const ContainerEvent& evt)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ Reference< XControl > xControl;
+ evt.Element >>= xControl;
+ if (!xControl.is())
+ return;
+
+ Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY);
+ if (xModel.is() && m_xModelAsIndex == xModel->getParent())
+ {
+ removeControl(xControl);
+ // Do not recalculate TabOrder, because it must already work internally!
+ }
+ // are we in filtermode and a XModeSelector has inserted an element
+ else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is())
+ {
+ FilterComponents::iterator componentPos = ::std::find(
+ m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl );
+ if ( componentPos != m_aFilterComponents.end() )
+ m_aFilterComponents.erase( componentPos );
+ }
+}
+
+
+Reference< XControl > FormController::isInList(const Reference< XWindowPeer > & xPeer) const
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ const Reference< XControl >* pControls = m_aControls.getConstArray();
+
+ sal_uInt32 nCtrls = m_aControls.getLength();
+ for ( sal_uInt32 n = 0; n < nCtrls && xPeer.is(); ++n, ++pControls )
+ {
+ if ( pControls->is() )
+ {
+ Reference< XVclWindowPeer > xCtrlPeer( (*pControls)->getPeer(), UNO_QUERY);
+ if ( ( xCtrlPeer.get() == xPeer.get() ) || xCtrlPeer->isChild( xPeer ) )
+ return *pControls;
+ }
+ }
+ return Reference< XControl > ();
+}
+
+
+void FormController::activateFirst()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ DBG_ASSERT(m_xTabController.is(), "FormController::activateFirst : invalid aggregate !");
+ if (m_xTabController.is())
+ m_xTabController->activateFirst();
+}
+
+
+void FormController::activateLast()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ DBG_ASSERT(m_xTabController.is(), "FormController::activateLast : invalid aggregate !");
+ if (m_xTabController.is())
+ m_xTabController->activateLast();
+}
+
+// XFormController
+
+Reference< XFormOperations > SAL_CALL FormController::getFormOperations()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ return m_xFormOperations;
+}
+
+
+Reference< XControl> SAL_CALL FormController::getCurrentControl()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return m_xCurrentControl;
+}
+
+
+void SAL_CALL FormController::addActivateListener(const Reference< XFormControllerListener > & l)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ m_aActivateListeners.addInterface(l);
+}
+
+void SAL_CALL FormController::removeActivateListener(const Reference< XFormControllerListener > & l)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ m_aActivateListeners.removeInterface(l);
+}
+
+
+void SAL_CALL FormController::addChildController( const Reference< XFormController >& ChildController )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ if ( !ChildController.is() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+ // TODO: (localized) error message
+
+ // the parent of our (to-be-)child must be our own model
+ Reference< XFormComponent > xFormOfChild( ChildController->getModel(), UNO_QUERY );
+ if ( !xFormOfChild.is() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+ // TODO: (localized) error message
+
+ if ( xFormOfChild->getParent() != m_xModelAsIndex )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+ // TODO: (localized) error message
+
+ m_aChildren.push_back( ChildController );
+ ChildController->setParent( *this );
+
+ // search the position of the model within the form
+ sal_uInt32 nPos = m_xModelAsIndex->getCount();
+ Reference< XFormComponent > xTemp;
+ for( ; nPos; )
+ {
+ m_xModelAsIndex->getByIndex(--nPos) >>= xTemp;
+ if ( xFormOfChild == xTemp )
+ {
+ m_xModelAsManager->attach( nPos, Reference<XInterface>( ChildController, UNO_QUERY ), Any( ChildController) );
+ break;
+ }
+ }
+}
+
+
+Reference< XFormControllerContext > SAL_CALL FormController::getContext()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return m_xFormControllerContext;
+}
+
+
+void SAL_CALL FormController::setContext( const Reference< XFormControllerContext >& _context )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ m_xFormControllerContext = _context;
+}
+
+
+Reference< XInteractionHandler > SAL_CALL FormController::getInteractionHandler()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return m_xInteractionHandler;
+}
+
+
+void SAL_CALL FormController::setInteractionHandler( const Reference< XInteractionHandler >& _interactionHandler )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ m_xInteractionHandler = _interactionHandler;
+}
+
+
+void FormController::setFilter(::std::vector<FmFieldInfo>& rFieldInfos)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ // create the composer
+ Reference< XRowSet > xForm(m_xModelAsIndex, UNO_QUERY);
+ Reference< XConnection > xConnection(getConnection(xForm));
+ if (xForm.is())
+ {
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory( xConnection, UNO_QUERY_THROW );
+ m_xComposer.set(
+ xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),
+ UNO_QUERY_THROW );
+
+ Reference< XPropertySet > xSet( xForm, UNO_QUERY );
+ OUString sStatement = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_ACTIVECOMMAND ) );
+ OUString sFilter = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_FILTER ) );
+ m_xComposer->setElementaryQuery( sStatement );
+ m_xComposer->setFilter( sFilter );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+ if (m_xComposer.is())
+ {
+ const Sequence< Sequence < PropertyValue > > aFilterRows = m_xComposer->getStructuredFilter();
+
+ // ok, we receive the list of filters as sequence of fieldnames, value
+ // now we have to transform the fieldname into UI names, that could be a label of the field or
+ // an aliasname or the fieldname itself
+
+ // first adjust the field names if necessary
+ Reference< XNameAccess > xQueryColumns =
+ Reference< XColumnsSupplier >( m_xComposer, UNO_QUERY_THROW )->getColumns();
+
+ for (auto& rFieldInfo : rFieldInfos)
+ {
+ if ( xQueryColumns->hasByName(rFieldInfo.aFieldName) )
+ {
+ if ( (xQueryColumns->getByName(rFieldInfo.aFieldName) >>= rFieldInfo.xField) && rFieldInfo.xField.is() )
+ rFieldInfo.xField->getPropertyValue(FM_PROP_REALNAME) >>= rFieldInfo.aFieldName;
+ }
+ }
+
+ Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData());
+ // now transfer the filters into Value/TextComponent pairs
+ ::comphelper::UStringMixEqual aCompare(xMetaData->storesMixedCaseQuotedIdentifiers());
+
+ // need to parse criteria localized
+ Reference< XNumberFormatsSupplier> xFormatSupplier( getNumberFormats(xConnection, true));
+ Reference< XNumberFormatter> xFormatter = NumberFormatter::create(m_xComponentContext);
+ xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
+ Locale aAppLocale = Application::GetSettings().GetUILanguageTag().getLocale();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetUILocaleDataWrapper() );
+ OUString strDecimalSeparator = rLocaleWrapper.getNumDecimalSep();
+
+ // retrieving the filter
+ for (const Sequence < PropertyValue >& rRow : aFilterRows)
+ {
+ FmFilterRow aRow;
+
+ // search a field for the given name
+ for (const PropertyValue& rRefValue : rRow)
+ {
+ // look for the text component
+ Reference< XPropertySet > xField;
+ try
+ {
+ Reference< XPropertySet > xSet;
+ OUString aRealName;
+
+ // first look with the given name
+ if (xQueryColumns->hasByName(rRefValue.Name))
+ {
+ xQueryColumns->getByName(rRefValue.Name) >>= xSet;
+
+ // get the RealName
+ xSet->getPropertyValue("RealName") >>= aRealName;
+
+ // compare the condition field name and the RealName
+ if (aCompare(aRealName, rRefValue.Name))
+ xField = xSet;
+ }
+ if (!xField.is())
+ {
+ // no we have to check every column to find the realname
+ Reference< XIndexAccess > xColumnsByIndex(xQueryColumns, UNO_QUERY);
+ for (sal_Int32 n = 0, nCount = xColumnsByIndex->getCount(); n < nCount; n++)
+ {
+ xColumnsByIndex->getByIndex(n) >>= xSet;
+ xSet->getPropertyValue("RealName") >>= aRealName;
+ if (aCompare(aRealName, rRefValue.Name))
+ {
+ // get the column by its alias
+ xField = xSet;
+ break;
+ }
+ }
+ }
+ if (!xField.is())
+ continue;
+ }
+ catch (const Exception&)
+ {
+ continue;
+ }
+
+ // find the text component
+ for (const auto& rFieldInfo : rFieldInfos)
+ {
+ // we found the field so insert a new entry to the filter row
+ if (rFieldInfo.xField == xField)
+ {
+ // do we already have the control ?
+ if (aRow.find(rFieldInfo.xText) != aRow.end())
+ {
+ OString aVal = m_pParser->getContext().getIntlKeywordAscii(IParseContext::InternationalKeyCode::And);
+ OUString aCompText = aRow[rFieldInfo.xText] + " " +
+ OUString(aVal.getStr(),aVal.getLength(),RTL_TEXTENCODING_ASCII_US) + " " +
+ ::comphelper::getString(rRefValue.Value);
+ aRow[rFieldInfo.xText] = aCompText;
+ }
+ else
+ {
+ OUString sPredicate,sErrorMsg;
+ rRefValue.Value >>= sPredicate;
+ std::unique_ptr< OSQLParseNode > pParseNode = predicateTree(sErrorMsg, sPredicate, xFormatter, xField);
+ if ( pParseNode != nullptr )
+ {
+ OUString sCriteria;
+ switch (rRefValue.Handle)
+ {
+ case css::sdb::SQLFilterOperator::EQUAL:
+ sCriteria += "=";
+ break;
+ case css::sdb::SQLFilterOperator::NOT_EQUAL:
+ sCriteria += "!=";
+ break;
+ case css::sdb::SQLFilterOperator::LESS:
+ sCriteria += "<";
+ break;
+ case css::sdb::SQLFilterOperator::GREATER:
+ sCriteria += ">";
+ break;
+ case css::sdb::SQLFilterOperator::LESS_EQUAL:
+ sCriteria += "<=";
+ break;
+ case css::sdb::SQLFilterOperator::GREATER_EQUAL:
+ sCriteria += ">=";
+ break;
+ case css::sdb::SQLFilterOperator::LIKE:
+ sCriteria += "LIKE ";
+ break;
+ case css::sdb::SQLFilterOperator::NOT_LIKE:
+ sCriteria += "NOT LIKE ";
+ break;
+ case css::sdb::SQLFilterOperator::SQLNULL:
+ sCriteria += "IS NULL";
+ break;
+ case css::sdb::SQLFilterOperator::NOT_SQLNULL:
+ sCriteria += "IS NOT NULL";
+ break;
+ }
+ pParseNode->parseNodeToPredicateStr( sCriteria
+ ,xConnection
+ ,xFormatter
+ ,xField
+ ,OUString()
+ ,aAppLocale
+ ,strDecimalSeparator
+ ,getParseContext());
+ aRow[rFieldInfo.xText] = sCriteria;
+ }
+ }
+ }
+ }
+ }
+
+ if (aRow.empty())
+ continue;
+
+ impl_addFilterRow( aRow );
+ }
+ }
+
+ // now set the filter controls
+ for (const auto& rFieldInfo : rFieldInfos)
+ {
+ m_aFilterComponents.push_back( rFieldInfo.xText );
+ }
+}
+
+
+void FormController::startFiltering()
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+
+ Reference< XConnection > xConnection( getConnection( Reference< XRowSet >( m_xModelAsIndex, UNO_QUERY ) ) );
+ if ( !xConnection.is() )
+ // nothing to do - can't filter a form which is not connected
+ return;
+
+ // stop listening for controls
+ if (isListeningForChanges())
+ stopListening();
+
+ m_bFiltering = true;
+
+ // as we don't want new controls to be attached to the scripting environment
+ // we change attach flags
+ m_bAttachEvents = false;
+
+ // exchanging the controls for the current form
+ Sequence< Reference< XControl > > aControlsCopy( m_aControls );
+ const Reference< XControl >* pControls = aControlsCopy.getConstArray();
+ sal_Int32 nControlCount = aControlsCopy.getLength();
+
+ // the control we have to activate after replacement
+ Reference< XNumberFormatsSupplier > xFormatSupplier = getNumberFormats(xConnection, true);
+ Reference< XNumberFormatter > xFormatter = NumberFormatter::create(m_xComponentContext);
+ xFormatter->attachNumberFormatsSupplier(xFormatSupplier);
+
+ // structure for storing the field info
+ ::std::vector<FmFieldInfo> aFieldInfos;
+
+ for (sal_Int32 i = nControlCount; i > 0;)
+ {
+ Reference< XControl > xControl = pControls[--i];
+ if (xControl.is())
+ {
+ // no events for the control anymore
+ removeFromEventAttacher(xControl);
+
+ // do we have a mode selector
+ Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
+ if (xSelector.is())
+ {
+ xSelector->setMode( "FilterMode" );
+
+ // listening for new controls of the selector
+ Reference< XContainer > xContainer(xSelector, UNO_QUERY);
+ if (xContainer.is())
+ xContainer->addContainerListener(this);
+
+ Reference< XEnumerationAccess > xElementAccess(xSelector, UNO_QUERY);
+ if (xElementAccess.is())
+ {
+ Reference< XEnumeration > xEnumeration(xElementAccess->createEnumeration());
+ Reference< XControl > xSubControl;
+ while (xEnumeration->hasMoreElements())
+ {
+ xEnumeration->nextElement() >>= xSubControl;
+ if (xSubControl.is())
+ {
+ Reference< XPropertySet > xSet(xSubControl->getModel(), UNO_QUERY);
+ if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
+ {
+ // does the model use a bound field ?
+ Reference< XPropertySet > xField;
+ xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
+
+ Reference< XTextComponent > xText(xSubControl, UNO_QUERY);
+ // may we filter the field?
+ if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) &&
+ ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE)))
+ {
+ aFieldInfos.emplace_back(xField, xText);
+ xText->addTextListener(this);
+ }
+ }
+ }
+ }
+ }
+ continue;
+ }
+
+ Reference< XPropertySet > xModel( xControl->getModel(), UNO_QUERY );
+ if (xModel.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xModel))
+ {
+ // does the model use a bound field ?
+ Any aVal = xModel->getPropertyValue(FM_PROP_BOUNDFIELD);
+ Reference< XPropertySet > xField;
+ aVal >>= xField;
+
+ // may we filter the field?
+
+ if ( xField.is()
+ && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
+ && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
+ )
+ {
+ // create a filter control
+ Reference< XControl > xFilterControl = form::control::FilterControl::createWithFormat(
+ m_xComponentContext,
+ getDialogParentWindow(this),
+ xFormatter,
+ xModel);
+
+ if ( replaceControl( xControl, xFilterControl ) )
+ {
+ Reference< XTextComponent > xFilterText( xFilterControl, UNO_QUERY );
+ aFieldInfos.emplace_back( xField, xFilterText );
+ xFilterText->addTextListener(this);
+ }
+ }
+ }
+ else
+ {
+ // unsubscribe from EventManager
+ }
+ }
+ }
+
+ // we have all filter controls now, so the next step is to read the filters from the form
+ // resolve all aliases and set the current filter to the according structure
+ setFilter(aFieldInfos);
+
+ Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
+ if ( xSet.is() )
+ stopFormListening( xSet, true );
+
+ impl_setTextOnAllFilter_throw();
+
+ // lock all controls which are not used for filtering
+ m_bLocked = determineLockState();
+ setLocks();
+ m_bAttachEvents = true;
+}
+
+
+void FormController::stopFiltering()
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ if ( !m_bFiltering ) // #104693# OJ
+ { // nothing to do
+ return;
+ }
+
+ m_bFiltering = false;
+ m_bDetachEvents = false;
+
+ ::comphelper::disposeComponent(m_xComposer);
+
+ // exchanging the controls for the current form
+ Sequence< Reference< XControl > > aControlsCopy( m_aControls );
+ const Reference< XControl > * pControls = aControlsCopy.getConstArray();
+ sal_Int32 nControlCount = aControlsCopy.getLength();
+
+ // clear the filter control map
+ ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) );
+ m_aFilterComponents.clear();
+
+ for ( sal_Int32 i = nControlCount; i > 0; )
+ {
+ Reference< XControl > xControl = pControls[--i];
+ if (xControl.is())
+ {
+ // now enable event handling again
+ addToEventAttacher(xControl);
+
+ Reference< XModeSelector > xSelector(xControl, UNO_QUERY);
+ if (xSelector.is())
+ {
+ xSelector->setMode( "DataMode" );
+
+ // listening for new controls of the selector
+ Reference< XContainer > xContainer(xSelector, UNO_QUERY);
+ if (xContainer.is())
+ xContainer->removeContainerListener(this);
+ continue;
+ }
+
+ Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY);
+ if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
+ {
+ // does the model use a bound field ?
+ Reference< XPropertySet > xField;
+ xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
+
+ // may we filter the field?
+ if ( xField.is()
+ && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField )
+ && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) )
+ )
+ {
+ OUString sServiceName;
+ OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName );
+ Reference< XControl > xNewControl( m_xComponentContext->getServiceManager()->createInstanceWithContext( sServiceName, m_xComponentContext ), UNO_QUERY );
+ replaceControl( xControl, xNewControl );
+ }
+ }
+ }
+ }
+
+ Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY );
+ if ( xSet.is() )
+ startFormListening( xSet, true );
+
+ m_bDetachEvents = true;
+
+ m_aFilterRows.clear();
+ m_nCurrentFilterPosition = -1;
+
+ // release the locks if possible
+ // lock all controls which are not used for filtering
+ m_bLocked = determineLockState();
+ setLocks();
+
+ // restart listening for control modifications
+ if (isListeningForChanges())
+ startListening();
+}
+
+// XModeSelector
+
+void FormController::setMode(const OUString& Mode)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ if (!supportsMode(Mode))
+ throw NoSupportException();
+
+ if (Mode == m_aMode)
+ return;
+
+ m_aMode = Mode;
+
+ if ( Mode == "FilterMode" )
+ startFiltering();
+ else
+ stopFiltering();
+
+ for (const auto& rChild : m_aChildren)
+ {
+ Reference< XModeSelector > xMode(rChild, UNO_QUERY);
+ if ( xMode.is() )
+ xMode->setMode(Mode);
+ }
+}
+
+
+OUString SAL_CALL FormController::getMode()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ return m_aMode;
+}
+
+
+Sequence< OUString > SAL_CALL FormController::getSupportedModes()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ static Sequence< OUString > const aModes
+ {
+ "DataMode",
+ "FilterMode"
+ };
+ return aModes;
+}
+
+sal_Bool SAL_CALL FormController::supportsMode(const OUString& Mode)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ Sequence< OUString > aModes(getSupportedModes());
+ return comphelper::findValue(aModes, Mode) != -1;
+}
+
+css::uno::Reference<css::awt::XWindow> FormController::getDialogParentWindow(css::uno::Reference<css::form::runtime::XFormController> xFormController)
+{
+ try
+ {
+ Reference< XControl > xContainerControl( xFormController->getContainer(), UNO_QUERY_THROW );
+ Reference<XWindow> xContainerWindow(xContainerControl->getPeer(), UNO_QUERY_THROW);
+ return xContainerWindow;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return nullptr;
+}
+
+bool FormController::checkFormComponentValidity( OUString& /* [out] */ _rFirstInvalidityExplanation, Reference< XControlModel >& /* [out] */ _rxFirstInvalidModel )
+{
+ try
+ {
+ Reference< XEnumerationAccess > xControlEnumAcc( getModel(), UNO_QUERY );
+ Reference< XEnumeration > xControlEnumeration;
+ if ( xControlEnumAcc.is() )
+ xControlEnumeration = xControlEnumAcc->createEnumeration();
+ OSL_ENSURE( xControlEnumeration.is(), "FormController::checkFormComponentValidity: cannot enumerate the controls!" );
+ if ( !xControlEnumeration.is() )
+ // assume all valid
+ return true;
+
+ Reference< XValidatableFormComponent > xValidatable;
+ while ( xControlEnumeration->hasMoreElements() )
+ {
+ if ( !( xControlEnumeration->nextElement() >>= xValidatable ) )
+ // control does not support validation
+ continue;
+
+ if ( xValidatable->isValid() )
+ continue;
+
+ Reference< XValidator > xValidator( xValidatable->getValidator() );
+ OSL_ENSURE( xValidator.is(), "FormController::checkFormComponentValidity: invalid, but no validator?" );
+ if ( !xValidator.is() )
+ // this violates the interface definition of css.form.validation.XValidatableFormComponent ...
+ continue;
+
+ _rFirstInvalidityExplanation = xValidator->explainInvalid( xValidatable->getCurrentValue() );
+ _rxFirstInvalidModel.set(xValidatable, css::uno::UNO_QUERY);
+ return false;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return true;
+}
+
+
+Reference< XControl > FormController::locateControl( const Reference< XControlModel >& _rxModel )
+{
+ try
+ {
+ const Sequence< Reference< XControl > > aControls( getControls() );
+
+ for ( auto const & control : aControls )
+ {
+ OSL_ENSURE( control.is(), "FormController::locateControl: NULL-control?" );
+ if ( control.is() )
+ {
+ if ( control->getModel() == _rxModel )
+ return control;
+ }
+ }
+ OSL_FAIL( "FormController::locateControl: did not find a control for this model!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return nullptr;
+}
+
+
+namespace
+{
+ void displayErrorSetFocus(const OUString& _rMessage, const Reference<XControl>& _rxFocusControl,
+ const css::uno::Reference<css::awt::XWindow>& rDialogParent)
+ {
+ SQLContext aError;
+ aError.Message = SvxResId(RID_STR_WRITEERROR);
+ aError.Details = _rMessage;
+ displayException(aError, rDialogParent);
+
+ if ( _rxFocusControl.is() )
+ {
+ Reference< XWindow > xControlWindow( _rxFocusControl, UNO_QUERY );
+ OSL_ENSURE( xControlWindow.is(), "displayErrorSetFocus: invalid control!" );
+ if ( xControlWindow.is() )
+ xControlWindow->setFocus();
+ }
+ }
+
+ bool lcl_shouldValidateRequiredFields_nothrow( const Reference< XInterface >& _rxForm )
+ {
+ try
+ {
+ static constexpr OUStringLiteral s_sFormsCheckRequiredFields = u"FormsCheckRequiredFields";
+
+ // first, check whether the form has a property telling us the answer
+ // this allows people to use the XPropertyContainer interface of a form to control
+ // the behaviour on a per-form basis.
+ Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xPSI( xFormProps->getPropertySetInfo() );
+ if ( xPSI->hasPropertyByName( s_sFormsCheckRequiredFields ) )
+ {
+ bool bShouldValidate = true;
+ OSL_VERIFY( xFormProps->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
+ return bShouldValidate;
+ }
+
+ // next, check the data source which created the connection
+ Reference< XChild > xConnectionAsChild( xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ), UNO_QUERY_THROW );
+ Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY );
+ if ( !xDataSource.is() )
+ // seldom (but possible): this is not a connection created by a data source
+ return true;
+
+ Reference< XPropertySet > xDataSourceSettings(
+ xDataSource->getPropertyValue("Settings"),
+ UNO_QUERY_THROW );
+
+ bool bShouldValidate = true;
+ OSL_VERIFY( xDataSourceSettings->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate );
+ return bShouldValidate;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ return true;
+ }
+}
+
+// XRowSetApproveListener
+
+sal_Bool SAL_CALL FormController::approveRowChange(const RowChangeEvent& _rEvent)
+{
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter(m_aRowSetApproveListeners);
+ bool bValid = true;
+ if (aIter.hasMoreElements())
+ {
+ RowChangeEvent aEvt( _rEvent );
+ aEvt.Source = *this;
+ bValid = aIter.next()->approveRowChange(aEvt);
+ }
+
+ if ( !bValid )
+ return bValid;
+
+ if ( ( _rEvent.Action != RowChangeAction::INSERT )
+ && ( _rEvent.Action != RowChangeAction::UPDATE )
+ )
+ return bValid;
+
+ // if some of the control models are bound to validators, check them
+ OUString sInvalidityExplanation;
+ Reference< XControlModel > xInvalidModel;
+ if ( !checkFormComponentValidity( sInvalidityExplanation, xInvalidModel ) )
+ {
+ Reference< XControl > xControl( locateControl( xInvalidModel ) );
+ aGuard.clear();
+ displayErrorSetFocus( sInvalidityExplanation, xControl, getDialogParentWindow(this) );
+ return false;
+ }
+
+ // check values on NULL and required flag
+ if ( !lcl_shouldValidateRequiredFields_nothrow( _rEvent.Source ) )
+ return true;
+
+ OSL_ENSURE(m_pColumnInfoCache, "FormController::approveRowChange: no column infos!");
+ if (!m_pColumnInfoCache)
+ return true;
+
+ try
+ {
+ if ( !m_pColumnInfoCache->controlsInitialized() )
+ m_pColumnInfoCache->initializeControls( getControls() );
+
+ size_t colCount = m_pColumnInfoCache->getColumnCount();
+ for ( size_t col = 0; col < colCount; ++col )
+ {
+ const ColumnInfo& rColInfo = m_pColumnInfoCache->getColumnInfo( col );
+
+ if ( rColInfo.bAutoIncrement )
+ continue;
+
+ if ( rColInfo.bReadOnly )
+ continue;
+
+ if ( !rColInfo.xFirstControlWithInputRequired.is() && !rColInfo.xFirstGridWithInputRequiredColumn.is() )
+ {
+ continue;
+ }
+
+ // TODO: in case of binary fields, this "getString" below is extremely expensive
+ if ( !rColInfo.xColumn->getString().isEmpty() || !rColInfo.xColumn->wasNull() )
+ continue;
+
+ OUString sMessage( SvxResId( RID_ERR_FIELDREQUIRED ) );
+ sMessage = sMessage.replaceFirst( "#", rColInfo.sName );
+
+ // the control to focus
+ Reference< XControl > xControl( rColInfo.xFirstControlWithInputRequired );
+ if ( !xControl.is() )
+ xControl.set( rColInfo.xFirstGridWithInputRequiredColumn, UNO_QUERY );
+
+ aGuard.clear();
+ displayErrorSetFocus( sMessage, rColInfo.xFirstControlWithInputRequired, getDialogParentWindow(this) );
+ return false;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ return true;
+}
+
+
+sal_Bool SAL_CALL FormController::approveCursorMove(const EventObject& event)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter(m_aRowSetApproveListeners);
+ if (aIter.hasMoreElements())
+ {
+ EventObject aEvt(event);
+ aEvt.Source = *this;
+ return aIter.next()->approveCursorMove(aEvt);
+ }
+
+ return true;
+}
+
+
+sal_Bool SAL_CALL FormController::approveRowSetChange(const EventObject& event)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter(m_aRowSetApproveListeners);
+ if (aIter.hasMoreElements())
+ {
+ EventObject aEvt(event);
+ aEvt.Source = *this;
+ return aIter.next()->approveRowSetChange(aEvt);
+ }
+
+ return true;
+}
+
+// XRowSetApproveBroadcaster
+
+void SAL_CALL FormController::addRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ m_aRowSetApproveListeners.addInterface(_rxListener);
+}
+
+
+void SAL_CALL FormController::removeRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ m_aRowSetApproveListeners.removeInterface(_rxListener);
+}
+
+// XErrorListener
+
+void SAL_CALL FormController::errorOccured(const SQLErrorEvent& aEvent)
+{
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter(m_aErrorListeners);
+ if (aIter.hasMoreElements())
+ {
+ SQLErrorEvent aEvt(aEvent);
+ aEvt.Source = *this;
+ aIter.next()->errorOccured(aEvt);
+ }
+ else
+ {
+ aGuard.clear();
+ displayException(aEvent, getDialogParentWindow(this));
+ }
+}
+
+// XErrorBroadcaster
+
+void SAL_CALL FormController::addSQLErrorListener(const Reference< XSQLErrorListener > & aListener)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ m_aErrorListeners.addInterface(aListener);
+}
+
+
+void SAL_CALL FormController::removeSQLErrorListener(const Reference< XSQLErrorListener > & aListener)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ m_aErrorListeners.removeInterface(aListener);
+}
+
+// XDatabaseParameterBroadcaster2
+
+void SAL_CALL FormController::addDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ m_aParameterListeners.addInterface(aListener);
+}
+
+
+void SAL_CALL FormController::removeDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ m_aParameterListeners.removeInterface(aListener);
+}
+
+// XDatabaseParameterBroadcaster
+
+void SAL_CALL FormController::addParameterListener(const Reference< XDatabaseParameterListener > & aListener)
+{
+ FormController::addDatabaseParameterListener( aListener );
+}
+
+
+void SAL_CALL FormController::removeParameterListener(const Reference< XDatabaseParameterListener > & aListener)
+{
+ FormController::removeDatabaseParameterListener( aListener );
+}
+
+// XDatabaseParameterListener
+
+sal_Bool SAL_CALL FormController::approveParameter(const DatabaseParameterEvent& aEvent)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter(m_aParameterListeners);
+ if (aIter.hasMoreElements())
+ {
+ DatabaseParameterEvent aEvt(aEvent);
+ aEvt.Source = *this;
+ return aIter.next()->approveParameter(aEvt);
+ }
+ else
+ {
+ // default handling: instantiate an interaction handler and let it handle the parameter request
+ try
+ {
+ if ( !ensureInteractionHandler() )
+ return false;
+
+ // two continuations allowed: OK and Cancel
+ rtl::Reference<OParameterContinuation> pParamValues = new OParameterContinuation;
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ // the request
+ ParametersRequest aRequest;
+ aRequest.Parameters = aEvent.Parameters;
+ aRequest.Connection = getConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY));
+ rtl::Reference<OInteractionRequest> pParamRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ pParamRequest->addContinuation(pParamValues);
+ pParamRequest->addContinuation(pAbort);
+
+ // handle the request
+ m_xInteractionHandler->handle(pParamRequest);
+
+ if (!pParamValues->wasSelected())
+ // canceled
+ return false;
+
+ // transfer the values into the parameter supplier
+ Sequence< PropertyValue > aFinalValues = pParamValues->getValues();
+ if (aFinalValues.getLength() != aRequest.Parameters->getCount())
+ {
+ OSL_FAIL("FormController::approveParameter: the InteractionHandler returned nonsense!");
+ return false;
+ }
+ const PropertyValue* pFinalValues = aFinalValues.getConstArray();
+ for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
+ {
+ Reference< XPropertySet > xParam(
+ aRequest.Parameters->getByIndex(i), css::uno::UNO_QUERY);
+ if (xParam.is())
+ {
+#ifdef DBG_UTIL
+ OUString sName;
+ xParam->getPropertyValue(FM_PROP_NAME) >>= sName;
+ DBG_ASSERT(sName == pFinalValues->Name, "FormController::approveParameter: suspicious value names!");
+#endif
+ try { xParam->setPropertyValue(FM_PROP_VALUE, pFinalValues->Value); }
+ catch(Exception&)
+ {
+ OSL_FAIL("FormController::approveParameter: setting one of the properties failed!");
+ }
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ return true;
+}
+
+// XConfirmDeleteBroadcaster
+
+void SAL_CALL FormController::addConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ m_aDeleteListeners.addInterface(aListener);
+}
+
+
+void SAL_CALL FormController::removeConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ m_aDeleteListeners.removeInterface(aListener);
+}
+
+// XConfirmDeleteListener
+
+sal_Bool SAL_CALL FormController::confirmDelete(const RowChangeEvent& aEvent)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter(m_aDeleteListeners);
+ if (aIter.hasMoreElements())
+ {
+ RowChangeEvent aEvt(aEvent);
+ aEvt.Source = *this;
+ return aIter.next()->confirmDelete(aEvt);
+ }
+ // default handling: instantiate an interaction handler and let it handle the request
+
+ OUString sTitle;
+ sal_Int32 nLength = aEvent.Rows;
+ if ( nLength > 1 )
+ {
+ sTitle = SvxResId( RID_STR_DELETECONFIRM_RECORDS );
+ sTitle = sTitle.replaceFirst( "#", OUString::number(nLength) );
+ }
+ else
+ sTitle = SvxResId( RID_STR_DELETECONFIRM_RECORD );
+
+ try
+ {
+ if ( !ensureInteractionHandler() )
+ return false;
+
+ // two continuations allowed: Yes and No
+ rtl::Reference<OInteractionApprove> pApprove = new OInteractionApprove;
+ rtl::Reference<OInteractionDisapprove> pDisapprove = new OInteractionDisapprove;
+
+ // the request
+ SQLWarning aWarning;
+ aWarning.Message = sTitle;
+ SQLWarning aDetails;
+ aDetails.Message = SvxResId(RID_STR_DELETECONFIRM);
+ aWarning.NextException <<= aDetails;
+
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest( Any( aWarning ) );
+
+ // some knittings
+ pRequest->addContinuation( pApprove );
+ pRequest->addContinuation( pDisapprove );
+
+ // handle the request
+ m_xInteractionHandler->handle( pRequest );
+
+ if ( pApprove->wasSelected() )
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ return false;
+}
+
+
+void SAL_CALL FormController::invalidateFeatures( const Sequence< ::sal_Int16 >& Features )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ // for now, just copy the ids of the features, because...
+ m_aInvalidFeatures.insert( Features.begin(), Features.end() );
+
+ // ... we will do the real invalidation asynchronously
+ if ( !m_aFeatureInvalidationTimer.IsActive() )
+ m_aFeatureInvalidationTimer.Start();
+}
+
+
+void SAL_CALL FormController::invalidateAllFeatures( )
+{
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ Sequence< sal_Int16 > aInterceptedFeatures( comphelper::mapKeysToSequence(m_aFeatureDispatchers) );
+
+ aGuard.clear();
+ if ( aInterceptedFeatures.hasElements() )
+ invalidateFeatures( aInterceptedFeatures );
+}
+
+
+Reference< XDispatch >
+FormController::interceptedQueryDispatch( const URL& aURL,
+ const OUString& /*aTargetFrameName*/, sal_Int32 /*nSearchFlags*/)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ Reference< XDispatch > xReturn;
+ // dispatches handled by ourself
+ if ( ( aURL.Complete == FMURL_CONFIRM_DELETION )
+ || ( ( aURL.Complete == "private:/InteractionHandler" )
+ && ensureInteractionHandler()
+ )
+ )
+ xReturn = static_cast< XDispatch* >( this );
+
+ // dispatches of FormSlot-URLs we have to translate
+ if ( !xReturn.is() && m_xFormOperations.is() )
+ {
+ // find the slot id which corresponds to the URL
+ sal_Int32 nFeatureSlotId = svx::FeatureSlotTranslation::getControllerFeatureSlotIdForURL( aURL.Main );
+ sal_Int16 nFormFeature = ( nFeatureSlotId != -1 ) ? svx::FeatureSlotTranslation::getFormFeatureForSlotId( nFeatureSlotId ) : -1;
+ if ( nFormFeature > 0 )
+ {
+ // get the dispatcher for this feature, create if necessary
+ DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( nFormFeature );
+ if ( aDispatcherPos == m_aFeatureDispatchers.end() )
+ {
+ aDispatcherPos = m_aFeatureDispatchers.emplace(
+ nFormFeature, new svx::OSingleFeatureDispatcher( aURL, nFormFeature, m_xFormOperations, m_aMutex )
+ ).first;
+ }
+
+ OSL_ENSURE( aDispatcherPos->second.is(), "FormController::interceptedQueryDispatch: should have a dispatcher by now!" );
+ return aDispatcherPos->second;
+ }
+ }
+
+ // no more to offer
+ return xReturn;
+}
+
+
+void SAL_CALL FormController::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArgs )
+{
+ if ( _rArgs.getLength() != 1 )
+ {
+ OSL_FAIL( "FormController::dispatch: no arguments -> no dispatch!" );
+ return;
+ }
+
+ if ( _rURL.Complete == "private:/InteractionHandler" )
+ {
+ Reference< XInteractionRequest > xRequest;
+ OSL_VERIFY( _rArgs[0].Value >>= xRequest );
+ if ( xRequest.is() )
+ handle( xRequest );
+ return;
+ }
+
+ if ( _rURL.Complete == FMURL_CONFIRM_DELETION )
+ {
+ OSL_FAIL( "FormController::dispatch: How do you expect me to return something via this call?" );
+ // confirmDelete has a return value - dispatch hasn't
+ return;
+ }
+
+ OSL_FAIL( "FormController::dispatch: unknown URL!" );
+}
+
+
+void SAL_CALL FormController::addStatusListener( const Reference< XStatusListener >& _rxListener, const URL& _rURL )
+{
+ if (_rURL.Complete == FMURL_CONFIRM_DELETION)
+ {
+ if (_rxListener.is())
+ { // send an initial statusChanged event
+ FeatureStateEvent aEvent;
+ aEvent.FeatureURL = _rURL;
+ aEvent.IsEnabled = true;
+ _rxListener->statusChanged(aEvent);
+ // and don't add the listener at all (the status will never change)
+ }
+ }
+ else
+ OSL_FAIL("FormController::addStatusListener: invalid (unsupported) URL!");
+}
+
+
+Reference< XInterface > SAL_CALL FormController::getParent()
+{
+ return m_xParent;
+}
+
+
+void SAL_CALL FormController::setParent( const Reference< XInterface >& Parent)
+{
+ m_xParent = Parent;
+}
+
+
+void SAL_CALL FormController::removeStatusListener( const Reference< XStatusListener >& /*_rxListener*/, const URL& _rURL )
+{
+ OSL_ENSURE(_rURL.Complete == FMURL_CONFIRM_DELETION, "FormController::removeStatusListener: invalid (unsupported) URL!");
+ // we never really added the listener, so we don't need to remove it
+}
+
+
+Reference< XDispatchProviderInterceptor > FormController::createInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+#ifdef DBG_UTIL
+ // check if we already have an interceptor for the given object
+ for ( const auto & it : m_aControlDispatchInterceptors )
+ {
+ if (it->getIntercepted() == _xInterception)
+ OSL_FAIL("FormController::createInterceptor : we already do intercept this objects dispatches !");
+ }
+#endif
+
+ rtl::Reference<DispatchInterceptionMultiplexer> pInterceptor(new DispatchInterceptionMultiplexer( _xInterception, this ));
+ m_aControlDispatchInterceptors.push_back( pInterceptor );
+
+ return pInterceptor;
+}
+
+
+bool FormController::ensureInteractionHandler()
+{
+ if ( m_xInteractionHandler.is() )
+ return true;
+ if ( m_bAttemptedHandlerCreation )
+ return false;
+ m_bAttemptedHandlerCreation = true;
+
+ m_xInteractionHandler = InteractionHandler::createWithParent(m_xComponentContext,
+ getDialogParentWindow(this));
+ return m_xInteractionHandler.is();
+}
+
+
+void SAL_CALL FormController::handle( const Reference< XInteractionRequest >& _rRequest )
+{
+ if ( !ensureInteractionHandler() )
+ return;
+ m_xInteractionHandler->handle( _rRequest );
+}
+
+
+void FormController::deleteInterceptor(const Reference< XDispatchProviderInterception > & _xInterception)
+{
+ OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" );
+ // search the interceptor responsible for the given object
+ auto aIter = std::find_if(m_aControlDispatchInterceptors.begin(), m_aControlDispatchInterceptors.end(),
+ [&_xInterception](const rtl::Reference<DispatchInterceptionMultiplexer>& rpInterceptor) {
+ return rpInterceptor->getIntercepted() == _xInterception;
+ });
+ if (aIter != m_aControlDispatchInterceptors.end())
+ {
+ // log off the interception from its interception object
+ (*aIter)->dispose();
+ // remove the interceptor from our array
+ m_aControlDispatchInterceptors.erase(aIter);
+ }
+}
+
+
+void FormController::implInvalidateCurrentControlDependentFeatures()
+{
+ Sequence< sal_Int16 > aCurrentControlDependentFeatures
+ {
+ FormFeature::SortAscending,
+ FormFeature::SortDescending,
+ FormFeature::AutoFilter,
+ FormFeature::RefreshCurrentControl
+ };
+
+ invalidateFeatures( aCurrentControlDependentFeatures );
+}
+
+
+void SAL_CALL FormController::columnChanged( const EventObject& /*_event*/ )
+{
+ implInvalidateCurrentControlDependentFeatures();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/formcontrolling.cxx b/svx/source/form/formcontrolling.cxx
new file mode 100644
index 000000000..221ae3584
--- /dev/null
+++ b/svx/source/form/formcontrolling.cxx
@@ -0,0 +1,497 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sal/macros.h>
+#include <formcontrolling.hxx>
+#include <fmurl.hxx>
+#include <svx/svxids.hrc>
+#include <fmprop.hxx>
+#include <formcontroller.hxx>
+#include <svx/fmtools.hxx>
+
+#include <com/sun/star/form/runtime/FormOperations.hpp>
+#include <com/sun/star/form/runtime/FormFeature.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <comphelper/anytostring.hxx>
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <osl/diagnose.h>
+
+#include <algorithm>
+
+
+namespace svx
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::form::runtime::XFormController;
+ using ::com::sun::star::form::runtime::FormOperations;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::sdbc::XRowSet;
+ using ::com::sun::star::form::runtime::FeatureState;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::beans::NamedValue;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::sdb::SQLErrorEvent;
+ using ::com::sun::star::lang::EventObject;
+
+ namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
+
+
+ //= FeatureSlotTranslation
+
+ namespace
+ {
+ struct FeatureDescription
+ {
+ OUString sURL; // the URL
+ sal_Int32 nSlotId; // the SFX-compatible slot ID
+ sal_Int16 nFormFeature; // the css.form.runtime.FormFeature ID
+ };
+ typedef ::std::vector< FeatureDescription > FeatureDescriptions;
+
+
+ const FeatureDescriptions& getFeatureDescriptions()
+ {
+ static const FeatureDescriptions s_aFeatureDescriptions({
+ { OUString(FMURL_FORM_POSITION), SID_FM_RECORD_ABSOLUTE, FormFeature::MoveAbsolute },
+ { OUString(FMURL_FORM_RECORDCOUNT), SID_FM_RECORD_TOTAL, FormFeature::TotalRecords },
+ { OUString(FMURL_RECORD_MOVEFIRST), SID_FM_RECORD_FIRST, FormFeature::MoveToFirst },
+ { OUString(FMURL_RECORD_MOVEPREV), SID_FM_RECORD_PREV, FormFeature::MoveToPrevious },
+ { OUString(FMURL_RECORD_MOVENEXT), SID_FM_RECORD_NEXT, FormFeature::MoveToNext },
+ { OUString(FMURL_RECORD_MOVELAST), SID_FM_RECORD_LAST, FormFeature::MoveToLast },
+ { OUString(FMURL_RECORD_MOVETONEW), SID_FM_RECORD_NEW, FormFeature::MoveToInsertRow },
+ { OUString(FMURL_RECORD_SAVE), SID_FM_RECORD_SAVE, FormFeature::SaveRecordChanges },
+ { OUString(FMURL_RECORD_DELETE), SID_FM_RECORD_DELETE, FormFeature::DeleteRecord },
+ { OUString(FMURL_FORM_REFRESH), SID_FM_REFRESH, FormFeature::ReloadForm },
+ { OUString(FMURL_FORM_REFRESH_CURRENT_CONTROL),
+ SID_FM_REFRESH_FORM_CONTROL,FormFeature::RefreshCurrentControl },
+ { OUString(FMURL_RECORD_UNDO), SID_FM_RECORD_UNDO, FormFeature::UndoRecordChanges },
+ { OUString(FMURL_FORM_SORT_UP), SID_FM_SORTUP, FormFeature::SortAscending },
+ { OUString(FMURL_FORM_SORT_DOWN), SID_FM_SORTDOWN, FormFeature::SortDescending },
+ { OUString(FMURL_FORM_SORT), SID_FM_ORDERCRIT, FormFeature::InteractiveSort },
+ { OUString(FMURL_FORM_AUTO_FILTER), SID_FM_AUTOFILTER, FormFeature::AutoFilter },
+ { OUString(FMURL_FORM_FILTER), SID_FM_FILTERCRIT, FormFeature::InteractiveFilter },
+ { OUString(FMURL_FORM_APPLY_FILTER), SID_FM_FORM_FILTERED, FormFeature::ToggleApplyFilter },
+ { OUString(FMURL_FORM_REMOVE_FILTER), SID_FM_REMOVE_FILTER_SORT, FormFeature::RemoveFilterAndSort }
+ });
+ return s_aFeatureDescriptions;
+ }
+ }
+
+
+ namespace
+ {
+
+ struct MatchFeatureDescriptionByURL
+ {
+ const OUString& m_rURL;
+ explicit MatchFeatureDescriptionByURL( const OUString& _rURL ) :m_rURL( _rURL ) { }
+
+ bool operator()( const FeatureDescription& _compare )
+ {
+ return m_rURL == _compare.sURL;
+ }
+ };
+
+
+ struct MatchFeatureDescriptionBySlotId
+ {
+ sal_Int32 m_nSlotId;
+ explicit MatchFeatureDescriptionBySlotId( sal_Int32 _nSlotId ) :m_nSlotId( _nSlotId ) { }
+
+ bool operator()( const FeatureDescription& _compare )
+ {
+ return m_nSlotId == _compare.nSlotId;
+ }
+ };
+
+
+ struct MatchFeatureDescriptionByFormFeature
+ {
+ sal_Int32 m_nFormFeature;
+ explicit MatchFeatureDescriptionByFormFeature( sal_Int32 _nFormFeature ) :m_nFormFeature( _nFormFeature ) { }
+
+ bool operator()( const FeatureDescription& _compare )
+ {
+ return m_nFormFeature == _compare.nFormFeature;
+ }
+ };
+
+
+ struct FormFeatureToSlotId
+ {
+ sal_Int32 operator()( sal_Int16 FormFeature )
+ {
+ return FeatureSlotTranslation::getSlotIdForFormFeature( FormFeature );
+ }
+ };
+ }
+
+
+ sal_Int32 FeatureSlotTranslation::getControllerFeatureSlotIdForURL( const OUString& _rMainURL )
+ {
+ const FeatureDescriptions& rDescriptions( getFeatureDescriptions() );
+ FeatureDescriptions::const_iterator pos = ::std::find_if( rDescriptions.begin(), rDescriptions.end(), MatchFeatureDescriptionByURL( _rMainURL ) );
+ return ( pos != rDescriptions.end() ) ? pos->nSlotId : -1;
+ }
+
+
+ sal_Int16 FeatureSlotTranslation::getFormFeatureForSlotId( sal_Int32 _nSlotId )
+ {
+ const FeatureDescriptions& rDescriptions( getFeatureDescriptions() );
+ FeatureDescriptions::const_iterator pos = ::std::find_if( rDescriptions.begin(), rDescriptions.end(), MatchFeatureDescriptionBySlotId( _nSlotId ) );
+ OSL_ENSURE( pos != rDescriptions.end(), "FeatureSlotTranslation::getFormFeatureForSlotId: not found!" );
+ return ( pos != rDescriptions.end() ) ? pos->nFormFeature : -1;
+ }
+
+
+ sal_Int32 FeatureSlotTranslation::getSlotIdForFormFeature( sal_Int16 _nFormFeature )
+ {
+ const FeatureDescriptions& rDescriptions( getFeatureDescriptions() );
+ FeatureDescriptions::const_iterator pos = ::std::find_if( rDescriptions.begin(), rDescriptions.end(), MatchFeatureDescriptionByFormFeature( _nFormFeature ) );
+ OSL_ENSURE( pos != rDescriptions.end(), "FeatureSlotTranslation::getSlotIdForFormFeature: not found!" );
+ return ( pos != rDescriptions.end() ) ? pos->nSlotId : -1;
+ }
+
+ ControllerFeatures::ControllerFeatures( IControllerFeatureInvalidation* _pInvalidationCallback )
+ :m_pInvalidationCallback( _pInvalidationCallback )
+ {
+ }
+
+
+ ControllerFeatures::ControllerFeatures( const Reference< XFormController >& _rxController )
+ :m_pInvalidationCallback( nullptr )
+ {
+ assign( _rxController );
+ }
+
+
+ void ControllerFeatures::assign( const Reference< XFormController >& _rxController )
+ {
+ dispose();
+ m_pImpl = new FormControllerHelper( _rxController, m_pInvalidationCallback );
+ }
+
+
+ ControllerFeatures::~ControllerFeatures()
+ {
+ dispose();
+ }
+
+
+ void ControllerFeatures::dispose()
+ {
+ if ( m_pImpl.is() )
+ {
+ m_pImpl->dispose();
+ m_pImpl.clear();
+ }
+ }
+
+ FormControllerHelper::FormControllerHelper( const Reference< XFormController >& _rxController, IControllerFeatureInvalidation* _pInvalidationCallback )
+ :m_pInvalidationCallback( _pInvalidationCallback )
+ {
+ osl_atomic_increment( &m_refCount );
+ try
+ {
+ m_xFormOperations = FormOperations::createWithFormController( comphelper::getProcessComponentContext(), _rxController );
+ if ( m_xFormOperations.is() )
+ m_xFormOperations->setFeatureInvalidation( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ FormControllerHelper::~FormControllerHelper( )
+ {
+ try
+ {
+ acquire();
+ dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void FormControllerHelper::dispose()
+ {
+ if ( m_xFormOperations.is() )
+ m_xFormOperations->dispose();
+ m_xFormOperations.clear();
+ }
+
+
+ bool FormControllerHelper::isEnabled( sal_Int32 _nSlotId ) const
+ {
+ if ( !m_xFormOperations.is() )
+ return false;
+ return m_xFormOperations->isEnabled( FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ) );
+ }
+
+
+ Reference< XRowSet > FormControllerHelper::getCursor() const
+ {
+ Reference< XRowSet > xCursor;
+ if ( m_xFormOperations.is() )
+ xCursor = m_xFormOperations->getCursor();
+ return xCursor;
+ }
+
+
+ void FormControllerHelper::getState( sal_Int32 _nSlotId, FeatureState& _rState ) const
+ {
+ if ( m_xFormOperations.is() )
+ _rState = m_xFormOperations->getState( FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ) );
+ }
+
+
+ bool FormControllerHelper::commitCurrentControl( ) const
+ {
+ return impl_operateForm_nothrow( COMMIT_CONTROL );
+ }
+
+
+ bool FormControllerHelper::commitCurrentRecord() const
+ {
+ return impl_operateForm_nothrow( COMMIT_RECORD );
+ }
+
+
+ void FormControllerHelper::execute( sal_Int32 _nSlotId, const OUString& _rParamName, const Any& _rParamValue ) const
+ {
+ Sequence< NamedValue > aArguments { { _rParamName, _rParamValue } };
+ impl_operateForm_nothrow( EXECUTE_ARGS, FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ), aArguments );
+ }
+
+
+ bool FormControllerHelper::impl_operateForm_nothrow( const FormOperation _eWhat, const sal_Int16 _nFeature,
+ const Sequence< NamedValue >& _rArguments ) const
+ {
+ if ( !m_xFormOperations.is() )
+ return false;
+
+ Any aError;
+ bool bSuccess = false;
+ const_cast< FormControllerHelper* >( this )->m_aOperationError.clear();
+ try
+ {
+ // to prevent the controller from displaying any error messages which happen while we operate on it,
+ // we add ourself as XSQLErrorListener. By contract, a FormController displays errors if and only if
+ // no SQLErrorListeners are registered.
+ m_xFormOperations->getController()->addSQLErrorListener( const_cast< FormControllerHelper* >(this) );
+
+ switch ( _eWhat )
+ {
+ case COMMIT_CONTROL:
+ bSuccess = m_xFormOperations->commitCurrentControl();
+ break;
+
+ case COMMIT_RECORD:
+ {
+ sal_Bool bDummy( false );
+ bSuccess = m_xFormOperations->commitCurrentRecord( bDummy );
+ }
+ break;
+
+ case EXECUTE:
+ m_xFormOperations->execute( _nFeature );
+ bSuccess = true;
+ break;
+
+ case EXECUTE_ARGS:
+ m_xFormOperations->executeWithArguments( _nFeature, _rArguments );
+ bSuccess = true;
+ break;
+ }
+ }
+ catch ( const SQLException& )
+ {
+ m_xFormOperations->getController()->removeSQLErrorListener( const_cast< FormControllerHelper* >(this) );
+ aError = ::cppu::getCaughtException();
+ }
+ catch( const Exception& )
+ {
+ m_xFormOperations->getController()->removeSQLErrorListener( const_cast< FormControllerHelper* >(this) );
+ SQLException aFallbackError;
+ aFallbackError.Message = ::comphelper::anyToString( ::cppu::getCaughtException() );
+ aError <<= aFallbackError;
+ }
+
+ if ( bSuccess )
+ return true;
+
+ // display the error. Prefer the one reported in errorOccurred over the one caught.
+ if ( m_aOperationError.hasValue() )
+ displayException(m_aOperationError, svxform::FormController::getDialogParentWindow(m_xFormOperations->getController()));
+ else if ( aError.hasValue() )
+ displayException(aError, svxform::FormController::getDialogParentWindow(m_xFormOperations->getController()));
+ else
+ OSL_FAIL( "FormControllerHelper::impl_operateForm_nothrow: no success, but no error?" );
+
+ return false;
+ }
+
+
+ void FormControllerHelper::execute( sal_Int32 _nSlotId ) const
+ {
+ impl_operateForm_nothrow( EXECUTE, FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ),
+ Sequence< NamedValue >() );
+ }
+
+
+ void SAL_CALL FormControllerHelper::invalidateFeatures( const Sequence< ::sal_Int16 >& Features )
+ {
+ if ( !m_pInvalidationCallback )
+ // nobody's interested in ...
+ return;
+
+ ::std::vector< sal_Int32 > aFeatures( Features.getLength() );
+ ::std::transform(
+ Features.begin(),
+ Features.end(),
+ aFeatures.begin(),
+ FormFeatureToSlotId()
+ );
+
+ m_pInvalidationCallback->invalidateFeatures( aFeatures );
+ }
+
+
+ void SAL_CALL FormControllerHelper::invalidateAllFeatures()
+ {
+ if ( !m_pInvalidationCallback )
+ // nobody's interested in ...
+ return;
+
+ // actually, it's a little bit more than the supported features,
+ // but on the medium term, we are to support everything listed
+ // here
+ ::std::vector< sal_Int32 > aSupportedFeatures;
+ const sal_Int32 pSupportedFeatures[] =
+ {
+ SID_FM_RECORD_FIRST,
+ SID_FM_RECORD_NEXT,
+ SID_FM_RECORD_PREV,
+ SID_FM_RECORD_LAST,
+ SID_FM_RECORD_NEW,
+ SID_FM_RECORD_DELETE,
+ SID_FM_RECORD_ABSOLUTE,
+ SID_FM_RECORD_TOTAL,
+ SID_FM_RECORD_SAVE,
+ SID_FM_RECORD_UNDO,
+ SID_FM_REMOVE_FILTER_SORT,
+ SID_FM_SORTUP,
+ SID_FM_SORTDOWN,
+ SID_FM_ORDERCRIT,
+ SID_FM_AUTOFILTER,
+ SID_FM_FILTERCRIT,
+ SID_FM_FORM_FILTERED,
+ SID_FM_REFRESH,
+ SID_FM_REFRESH_FORM_CONTROL,
+ SID_FM_SEARCH,
+ SID_FM_FILTER_START,
+ SID_FM_VIEW_AS_GRID
+ };
+ sal_Int32 nFeatureCount = SAL_N_ELEMENTS( pSupportedFeatures );
+ aSupportedFeatures.reserve(nFeatureCount); // work around GCC12 spurious -Werror=stringop-overflow=
+ aSupportedFeatures.insert( aSupportedFeatures.begin(), pSupportedFeatures, pSupportedFeatures + nFeatureCount );
+
+ m_pInvalidationCallback->invalidateFeatures( aSupportedFeatures );
+ }
+
+
+ void SAL_CALL FormControllerHelper::errorOccured( const SQLErrorEvent& Event )
+ {
+ OSL_ENSURE( !m_aOperationError.hasValue(), "FormControllerHelper::errorOccurred: two errors during one operation?" );
+ m_aOperationError = Event.Reason;
+ }
+
+
+ void SAL_CALL FormControllerHelper::disposing( const EventObject& /*_Source*/ )
+ {
+ // not interested in
+ }
+
+
+ bool FormControllerHelper::isInsertionRow() const
+ {
+ bool bIs = false;
+ if ( m_xFormOperations.is() )
+ bIs = m_xFormOperations->isInsertionRow();
+ return bIs;
+ }
+
+
+ bool FormControllerHelper::isModifiedRow() const
+ {
+ bool bIs = false;
+ if ( m_xFormOperations.is() )
+ bIs = m_xFormOperations->isModifiedRow();
+ return bIs;
+ }
+
+ bool FormControllerHelper::canDoFormFilter() const
+ {
+ if ( !m_xFormOperations.is() )
+ return false;
+
+ bool bCanDo = false;
+ try
+ {
+ Reference< XPropertySet > xCursorProperties( m_xFormOperations->getCursor(), UNO_QUERY_THROW );
+
+ bool bEscapeProcessing( false );
+ OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_ESCAPE_PROCESSING ) >>= bEscapeProcessing );
+
+ OUString sActiveCommand;
+ OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_ACTIVECOMMAND ) >>= sActiveCommand );
+
+ bool bInsertOnlyForm( false );
+ OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_INSERTONLY ) >>= bInsertOnlyForm );
+
+ bCanDo = bEscapeProcessing && !sActiveCommand.isEmpty() && !bInsertOnlyForm;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return bCanDo;
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/formdispatchinterceptor.cxx b/svx/source/form/formdispatchinterceptor.cxx
new file mode 100644
index 000000000..cc75b0b01
--- /dev/null
+++ b/svx/source/form/formdispatchinterceptor.cxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <formdispatchinterceptor.hxx>
+
+namespace svxform
+{
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::frame::XDispatchProviderInterception;
+ using ::com::sun::star::frame::XDispatchProviderInterceptor;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::util::URL;
+ using ::com::sun::star::frame::XDispatch;
+ using ::com::sun::star::frame::DispatchDescriptor;
+ using ::com::sun::star::frame::XDispatchProvider;
+ using ::com::sun::star::lang::EventObject;
+
+ DispatchInterceptionMultiplexer::DispatchInterceptionMultiplexer(
+ const Reference< XDispatchProviderInterception >& _rxToIntercept, DispatchInterceptor* _pMaster )
+ :DispatchInterceptionMultiplexer_BASE(_pMaster && _pMaster->getInterceptorMutex() ? *_pMaster->getInterceptorMutex() : m_aFallback)
+ ,m_pMutex( _pMaster && _pMaster->getInterceptorMutex() ? _pMaster->getInterceptorMutex() : &m_aFallback )
+ ,m_xIntercepted(_rxToIntercept)
+ ,m_bListening(false)
+ ,m_pMaster(_pMaster)
+ {
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ osl_atomic_increment(&m_refCount);
+ if (_rxToIntercept.is())
+ {
+ _rxToIntercept->registerDispatchProviderInterceptor(static_cast<XDispatchProviderInterceptor*>(this));
+ // this should make us the top-level dispatch-provider for the component, via a call to our
+ // setDispatchProvider we should have got a fallback for requests we (i.e. our master) cannot fulfill
+ Reference< XComponent> xInterceptedComponent(_rxToIntercept, UNO_QUERY);
+ if (xInterceptedComponent.is())
+ {
+ xInterceptedComponent->addEventListener(this);
+ m_bListening = true;
+ }
+ }
+ osl_atomic_decrement(&m_refCount);
+ }
+
+
+ DispatchInterceptionMultiplexer::~DispatchInterceptionMultiplexer()
+ {
+ if (!rBHelper.bDisposed)
+ dispose();
+
+ }
+
+
+ Reference< XDispatch > SAL_CALL DispatchInterceptionMultiplexer::queryDispatch( const URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags )
+ {
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ Reference< XDispatch> xResult;
+ // ask our 'real' interceptor
+ if (m_pMaster)
+ xResult = m_pMaster->interceptedQueryDispatch( aURL, aTargetFrameName, nSearchFlags);
+
+ // ask our slave provider
+ if (!xResult.is() && m_xSlaveDispatcher.is())
+ xResult = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags);
+
+ return xResult;
+ }
+
+
+ Sequence< Reference< XDispatch > > SAL_CALL
+ DispatchInterceptionMultiplexer::queryDispatches( const Sequence< DispatchDescriptor >& aDescripts )
+ {
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ Sequence< Reference< XDispatch> > aReturn(aDescripts.getLength());
+ std::transform(aDescripts.begin(), aDescripts.end(), aReturn.getArray(),
+ [this](const DispatchDescriptor& rDescript) -> Reference< XDispatch> {
+ return queryDispatch(rDescript.FeatureURL, rDescript.FrameName, rDescript.SearchFlags); });
+ return aReturn;
+ }
+
+
+ Reference< XDispatchProvider > SAL_CALL DispatchInterceptionMultiplexer::getSlaveDispatchProvider( )
+ {
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return m_xSlaveDispatcher;
+ }
+
+
+ void SAL_CALL DispatchInterceptionMultiplexer::setSlaveDispatchProvider(const Reference< XDispatchProvider>& xNewDispatchProvider)
+ {
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ m_xSlaveDispatcher = xNewDispatchProvider;
+ }
+
+
+ Reference< XDispatchProvider> SAL_CALL DispatchInterceptionMultiplexer::getMasterDispatchProvider()
+ {
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return m_xMasterDispatcher;
+ }
+
+
+ void SAL_CALL DispatchInterceptionMultiplexer::setMasterDispatchProvider(const Reference< XDispatchProvider>& xNewSupplier)
+ {
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ m_xMasterDispatcher = xNewSupplier;
+ }
+
+
+ void SAL_CALL DispatchInterceptionMultiplexer::disposing(const EventObject& Source)
+ {
+ if (m_bListening)
+ {
+ Reference< XDispatchProviderInterception > xIntercepted(m_xIntercepted.get(), UNO_QUERY);
+ if (Source.Source == xIntercepted)
+ ImplDetach();
+ }
+ }
+
+
+ void DispatchInterceptionMultiplexer::ImplDetach()
+ {
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ OSL_ENSURE(m_bListening, "DispatchInterceptionMultiplexer::ImplDetach: invalid call!");
+
+ // deregister ourself from the interception component
+ Reference< XDispatchProviderInterception > xIntercepted(m_xIntercepted.get(), UNO_QUERY);
+ if (xIntercepted.is())
+ xIntercepted->releaseDispatchProviderInterceptor(static_cast<XDispatchProviderInterceptor*>(this));
+
+ // m_xIntercepted.clear();
+ // Don't reset m_xIntercepted: It may be needed by our owner to check for which object we were
+ // responsible. As we hold the object with a weak reference only, this should be no problem.
+ // 88936 - 23.07.2001 - frank.schoenheit@sun.com
+ m_pMaster = nullptr;
+ m_pMutex = &m_aFallback;
+ m_bListening = false;
+ }
+
+
+ void DispatchInterceptionMultiplexer::disposing()
+ {
+ // remove ourself as event listener from the interception component
+ if (m_bListening)
+ {
+ Reference< XComponent> xInterceptedComponent(m_xIntercepted.get(), UNO_QUERY);
+ if (xInterceptedComponent.is())
+ xInterceptedComponent->removeEventListener(static_cast<XEventListener*>(this));
+
+ // detach from the interception component
+ ImplDetach();
+ }
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/formfeaturedispatcher.cxx b/svx/source/form/formfeaturedispatcher.cxx
new file mode 100644
index 000000000..b90cd4c92
--- /dev/null
+++ b/svx/source/form/formfeaturedispatcher.cxx
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <formfeaturedispatcher.hxx>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <tools/diagnose_ex.h>
+
+
+namespace svx
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::form::runtime;
+
+ OSingleFeatureDispatcher::OSingleFeatureDispatcher( const URL& _rFeatureURL, const sal_Int16 _nFormFeature,
+ const Reference< XFormOperations >& _rxFormOperations, ::osl::Mutex& _rMutex )
+ :m_rMutex( _rMutex )
+ ,m_aStatusListeners( _rMutex )
+ ,m_xFormOperations( _rxFormOperations )
+ ,m_aFeatureURL( _rFeatureURL )
+ ,m_nFormFeature( _nFormFeature )
+ ,m_bLastKnownEnabled( false )
+ {
+ }
+
+
+ void OSingleFeatureDispatcher::getUnoState( FeatureStateEvent& /* [out] */ _rState ) const
+ {
+ _rState.Source = *const_cast< OSingleFeatureDispatcher* >( this );
+
+ FeatureState aState( m_xFormOperations->getState( m_nFormFeature ) );
+
+ _rState.FeatureURL = m_aFeatureURL;
+ _rState.IsEnabled = aState.Enabled;
+ _rState.Requery = false;
+ _rState.State = aState.State;
+ }
+
+
+ void OSingleFeatureDispatcher::updateAllListeners()
+ {
+ ::osl::ClearableMutexGuard aGuard( m_rMutex );
+
+ FeatureStateEvent aUnoState;
+ getUnoState( aUnoState );
+
+ if ( ( m_aLastKnownState == aUnoState.State ) && ( m_bLastKnownEnabled == bool(aUnoState.IsEnabled) ) )
+ return;
+
+ m_aLastKnownState = aUnoState.State;
+ m_bLastKnownEnabled = aUnoState.IsEnabled;
+
+ notifyStatus( nullptr, aGuard );
+ }
+
+
+ void OSingleFeatureDispatcher::notifyStatus( const Reference< XStatusListener >& _rxListener, ::osl::ClearableMutexGuard& _rFreeForNotification )
+ {
+ FeatureStateEvent aUnoState;
+ getUnoState( aUnoState );
+
+ if ( _rxListener.is() )
+ {
+ try
+ {
+ _rFreeForNotification.clear();
+ _rxListener->statusChanged( aUnoState );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "OSingleFeatureDispatcher::notifyStatus" );
+ }
+ }
+ else
+ {
+ ::comphelper::OInterfaceIteratorHelper3 aIter( m_aStatusListeners );
+ _rFreeForNotification.clear();
+
+ while ( aIter.hasMoreElements() )
+ {
+ try
+ {
+ aIter.next()->statusChanged( aUnoState );
+ }
+ catch( const DisposedException& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.form",
+ "caught a DisposedException - removing the listener!");
+ aIter.remove( );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION(
+ "svx.form",
+ "caught a generic exception while notifying a single listener!");
+ }
+ }
+ }
+ }
+
+
+ void SAL_CALL OSingleFeatureDispatcher::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArguments )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_rMutex );
+
+ OSL_ENSURE( _rURL.Complete == m_aFeatureURL.Complete, "OSingleFeatureDispatcher::dispatch: not responsible for this URL!" );
+
+ if ( !m_xFormOperations->isEnabled( m_nFormFeature ) )
+ return;
+
+ // release our mutex before executing the command
+ sal_Int16 nFormFeature( m_nFormFeature );
+ Reference< XFormOperations > xFormOperations( m_xFormOperations );
+ aGuard.clear();
+
+ try
+ {
+ if ( !_rArguments.hasElements() )
+ {
+ xFormOperations->execute( nFormFeature );
+ }
+ else
+ { // at the moment we only support one parameter
+ ::comphelper::NamedValueCollection aArgs( _rArguments );
+ xFormOperations->executeWithArguments( nFormFeature, aArgs.getNamedValues() );
+ }
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void SAL_CALL OSingleFeatureDispatcher::addStatusListener( const Reference< XStatusListener >& _rxControl, const URL& _rURL )
+ {
+ OSL_ENSURE( _rURL.Complete == m_aFeatureURL.Complete, "OSingleFeatureDispatcher::addStatusListener: unexpected URL!" );
+ OSL_ENSURE( _rxControl.is(), "OSingleFeatureDispatcher::addStatusListener: senseless call!" );
+ if ( !_rxControl.is() )
+ return;
+
+ ::osl::ClearableMutexGuard aGuard( m_rMutex );
+
+ m_aStatusListeners.addInterface( _rxControl );
+
+ // initially update the status
+ notifyStatus( _rxControl, aGuard );
+ }
+
+
+ void SAL_CALL OSingleFeatureDispatcher::removeStatusListener( const Reference< XStatusListener >& _rxControl, const URL& _rURL )
+ {
+ OSL_ENSURE( _rURL.Complete == m_aFeatureURL.Complete, "OSingleFeatureDispatcher::removeStatusListener: unexpected URL!" );
+ OSL_ENSURE( _rxControl.is(), "OSingleFeatureDispatcher::removeStatusListener: senseless call!" );
+ if ( !_rxControl.is() )
+ return;
+
+ ::osl::MutexGuard aGuard( m_rMutex );
+
+ m_aStatusListeners.removeInterface( _rxControl );
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/formtoolbars.cxx b/svx/source/form/formtoolbars.cxx
new file mode 100644
index 000000000..d46e7cc1b
--- /dev/null
+++ b/svx/source/form/formtoolbars.cxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <formtoolbars.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+#include <svx/svxids.hrc>
+
+
+namespace svxform
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::beans;
+
+ FormToolboxes::FormToolboxes( const Reference< XFrame >& _rxFrame )
+ {
+ // the layout manager
+ Reference< XPropertySet > xFrameProps( _rxFrame, UNO_QUERY );
+ if ( xFrameProps.is() )
+ xFrameProps->getPropertyValue("LayoutManager") >>= m_xLayouter;
+ }
+
+
+ void FormToolboxes::toggleToolbox( sal_uInt16 _nSlotId ) const
+ {
+ try
+ {
+ Reference< XLayoutManager > xManager( m_xLayouter );
+ OSL_ENSURE( xManager. is(), "FormToolboxes::toggleToolbox: couldn't obtain the layout manager!" );
+ if ( xManager. is() )
+ {
+ OUString sToolboxResource( getToolboxResourceName( _nSlotId ) );
+ if ( xManager->isElementVisible( sToolboxResource ) )
+ {
+ xManager->hideElement( sToolboxResource );
+ xManager->destroyElement( sToolboxResource );
+ }
+ else
+ {
+ xManager->createElement( sToolboxResource );
+ xManager->showElement( sToolboxResource );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FormToolboxes::toggleToolbox" );
+ }
+ }
+
+
+ bool FormToolboxes::isToolboxVisible( sal_uInt16 _nSlotId ) const
+ {
+ return m_xLayouter.is() && m_xLayouter->isElementVisible(
+ getToolboxResourceName( _nSlotId ) );
+ }
+
+
+ OUString FormToolboxes::getToolboxResourceName( sal_uInt16 _nSlotId )
+ {
+ OSL_ENSURE( _nSlotId == SID_FM_FORM_DESIGN_TOOLS ,
+ "FormToolboxes::getToolboxResourceName: unsupported slot!" );
+
+ return "private:resource/toolbar/formdesign";
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/labelitemwindow.cxx b/svx/source/form/labelitemwindow.cxx
new file mode 100644
index 000000000..77965cbd4
--- /dev/null
+++ b/svx/source/form/labelitemwindow.cxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <svx/labelitemwindow.hxx>
+
+LabelItemWindow::LabelItemWindow(vcl::Window* pParent, const OUString& rLabel)
+ : InterimItemWindow(pParent, "svx/ui/labelbox.ui", "LabelBox")
+ , m_xLabel(m_xBuilder->weld_label("label"))
+{
+ InitControlBase(m_xLabel.get());
+
+ m_xLabel->set_label(rLabel);
+
+ SetOptimalSize();
+
+ m_xLabel->set_toolbar_background();
+}
+
+void LabelItemWindow::SetOptimalSize()
+{
+ Size aSize(m_xLabel->get_preferred_size());
+ aSize.AdjustWidth(12);
+
+ SetSizePixel(aSize);
+}
+
+void LabelItemWindow::set_label(const OUString& rLabel) { m_xLabel->set_label(rLabel); }
+
+OUString LabelItemWindow::get_label() const { return m_xLabel->get_label(); }
+
+void LabelItemWindow::dispose()
+{
+ m_xLabel.reset();
+ InterimItemWindow::dispose();
+}
+
+LabelItemWindow::~LabelItemWindow() { disposeOnce(); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/form/legacyformcontroller.cxx b/svx/source/form/legacyformcontroller.cxx
new file mode 100644
index 000000000..94b2ae983
--- /dev/null
+++ b/svx/source/form/legacyformcontroller.cxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <fmservs.hxx>
+
+#include <com/sun/star/form/XFormController.hpp>
+#include <com/sun/star/form/runtime/FormController.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/processfactory.hxx>
+
+
+namespace svxform
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::lang::XMultiServiceFactory;
+ using ::com::sun::star::awt::XControl;
+ using ::com::sun::star::awt::XTabControllerModel;
+ using ::com::sun::star::awt::XControlContainer;
+ using ::com::sun::star::lang::XServiceInfo;
+ using ::com::sun::star::form::runtime::FormController;
+
+ using namespace ::com::sun::star;
+
+
+ //= LegacyFormController
+
+ typedef ::cppu::WeakImplHelper < form::XFormController
+ , XServiceInfo
+ > LegacyFormController_Base;
+
+ namespace {
+
+ /** is an implementation of the legacy form controller service, namely css.form.FormController, supporting the
+ css.form.XFormController interface.
+
+ This legacy API is superseded by css.form.runtime.(X)FormController, and though we migrated all OOo-internal
+ usage of this old API, their might be clients external to OOo still using it (though this is rather unlikely).
+ */
+ class LegacyFormController : public LegacyFormController_Base
+ {
+ public:
+ static Reference< XInterface > Create( const Reference< XMultiServiceFactory >& _rxFactory )
+ {
+ return *( new LegacyFormController( comphelper::getComponentContext(_rxFactory) ) );
+ }
+
+ protected:
+ explicit LegacyFormController( const Reference< XComponentContext >& _rxContext )
+ :m_xDelegator( FormController::create(_rxContext) )
+ {
+ }
+
+ // form::XFormController
+ virtual Reference< XControl > SAL_CALL getCurrentControl( ) override;
+ virtual void SAL_CALL addActivateListener( const Reference< form::XFormControllerListener >& l ) override;
+ virtual void SAL_CALL removeActivateListener( const Reference< form::XFormControllerListener >& l ) override;
+
+ // awt::XTabController
+ virtual void SAL_CALL setModel( const Reference< XTabControllerModel >& Model ) override;
+ virtual Reference< XTabControllerModel > SAL_CALL getModel( ) override;
+ virtual void SAL_CALL setContainer( const Reference< XControlContainer >& Container ) override;
+ virtual Reference< XControlContainer > SAL_CALL getContainer( ) override;
+ virtual Sequence< Reference< XControl > > SAL_CALL getControls( ) override;
+ virtual void SAL_CALL autoTabOrder( ) override;
+ virtual void SAL_CALL activateTabOrder( ) override;
+ virtual void SAL_CALL activateFirst( ) override;
+ virtual void SAL_CALL activateLast( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ private:
+ const Reference< form::runtime::XFormController > m_xDelegator;
+ };
+
+ }
+
+ Reference< XControl > SAL_CALL LegacyFormController::getCurrentControl( )
+ {
+ return m_xDelegator->getCurrentControl();
+ }
+
+
+ void SAL_CALL LegacyFormController::addActivateListener( const Reference< form::XFormControllerListener >& _listener )
+ {
+ m_xDelegator->addActivateListener( _listener );
+ }
+
+
+ void SAL_CALL LegacyFormController::removeActivateListener( const Reference< form::XFormControllerListener >& _listener )
+ {
+ m_xDelegator->removeActivateListener( _listener );
+ }
+
+
+ void SAL_CALL LegacyFormController::setModel( const Reference< XTabControllerModel >& _model )
+ {
+ m_xDelegator->setModel( _model );
+ }
+
+
+ Reference< XTabControllerModel > SAL_CALL LegacyFormController::getModel( )
+ {
+ return m_xDelegator->getModel();
+ }
+
+
+ void SAL_CALL LegacyFormController::setContainer( const Reference< XControlContainer >& _container )
+ {
+ m_xDelegator->setContainer( _container );
+ }
+
+
+ Reference< XControlContainer > SAL_CALL LegacyFormController::getContainer( )
+ {
+ return m_xDelegator->getContainer();
+ }
+
+
+ Sequence< Reference< XControl > > SAL_CALL LegacyFormController::getControls( )
+ {
+ return m_xDelegator->getControls();
+ }
+
+
+ void SAL_CALL LegacyFormController::autoTabOrder( )
+ {
+ m_xDelegator->autoTabOrder();
+ }
+
+
+ void SAL_CALL LegacyFormController::activateTabOrder( )
+ {
+ m_xDelegator->activateTabOrder();
+ }
+
+
+ void SAL_CALL LegacyFormController::activateFirst( )
+ {
+ m_xDelegator->activateFirst();
+ }
+
+
+ void SAL_CALL LegacyFormController::activateLast( )
+ {
+ m_xDelegator->activateLast();
+ }
+
+
+ OUString SAL_CALL LegacyFormController::getImplementationName( )
+ {
+ return "org.openoffice.comp.svx.LegacyFormController";
+ }
+
+ sal_Bool SAL_CALL LegacyFormController::supportsService( const OUString& _serviceName )
+ {
+ return cppu::supportsService(this, _serviceName);
+ }
+
+ Sequence< OUString > SAL_CALL LegacyFormController::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.form.FormController", "com.sun.star.awt.control.TabController" };
+ }
+
+}
+
+css::uno::Reference< css::uno::XInterface >
+ LegacyFormController_NewInstance_Impl( const css::uno::Reference< css::lang::XMultiServiceFactory > & _rxORB )
+{
+ return ::svxform::LegacyFormController::Create( _rxORB );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/navigatortree.cxx b/svx/source/form/navigatortree.cxx
new file mode 100644
index 000000000..9ac6e6a87
--- /dev/null
+++ b/svx/source/form/navigatortree.cxx
@@ -0,0 +1,2044 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <svx/dialmgr.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svditer.hxx>
+
+#include <helpids.h>
+#include <fmexpl.hxx>
+#include <fmshimp.hxx>
+#include <fmservs.hxx>
+#include <fmundo.hxx>
+#include <fmpgeimp.hxx>
+#include <fmobj.hxx>
+#include <fmprop.hxx>
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <svx/sdrpaintwindow.hxx>
+
+#include <svx/strings.hrc>
+#include <tools/diagnose_ex.h>
+#include <svx/svxids.hrc>
+#include <bitmaps.hlst>
+#include <vcl/commandevent.hxx>
+
+namespace svxform
+{
+ #define EXPLORER_SYNC_DELAY 200
+ // Time (in ms) until explorer synchronizes the view after select or deselect
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::datatransfer;
+ using namespace ::com::sun::star::datatransfer::clipboard;
+ using namespace ::com::sun::star::sdb;
+
+
+ // helper
+
+
+ typedef ::std::map< Reference< XInterface >, SdrObject* > MapModelToShape;
+
+
+ static void collectShapeModelMapping( SdrPage const * _pPage, MapModelToShape& _rMapping )
+ {
+ OSL_ENSURE( _pPage, "collectShapeModelMapping: invalid arg!" );
+
+ _rMapping.clear();
+
+ SdrObjListIter aIter( _pPage );
+ while ( aIter.IsMore() )
+ {
+ SdrObject* pSdrObject = aIter.Next();
+ FmFormObj* pFormObject = FmFormObj::GetFormObject( pSdrObject );
+ if ( !pFormObject )
+ continue;
+
+ Reference< XInterface > xNormalizedModel( pFormObject->GetUnoControlModel(), UNO_QUERY );
+ // note that this is normalized (i.e. queried for XInterface explicitly)
+
+ ::std::pair< MapModelToShape::iterator, bool > aPos =
+ _rMapping.emplace( xNormalizedModel, pSdrObject );
+ DBG_ASSERT( aPos.second, "collectShapeModelMapping: model was already existent!" );
+ // if this asserts, this would mean we have 2 shapes pointing to the same model
+ }
+ }
+
+ NavigatorTreeDropTarget::NavigatorTreeDropTarget(NavigatorTree& rTreeView)
+ : DropTargetHelper(rTreeView.get_widget().get_drop_target())
+ , m_rTreeView(rTreeView)
+ {
+ }
+
+ sal_Int8 NavigatorTreeDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
+ {
+ sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt);
+
+ if (nAccept != DND_ACTION_NONE)
+ {
+ // to enable the autoscroll when we're close to the edges
+ weld::TreeView& rWidget = m_rTreeView.get_widget();
+ rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
+ }
+
+ return nAccept;
+ }
+
+ sal_Int8 NavigatorTreeDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
+ {
+ return m_rTreeView.ExecuteDrop(rEvt);
+ }
+
+ NavigatorTree::NavigatorTree(std::unique_ptr<weld::TreeView> xTreeView)
+ :m_xTreeView(std::move(xTreeView))
+ ,m_aDropTargetHelper(*this)
+ ,m_aSynchronizeTimer("svx NavigatorTree m_aSynchronizeTimer")
+ ,nEditEvent(nullptr)
+ ,m_sdiState(SDI_DIRTY)
+ ,m_nSelectLock(0)
+ ,m_nFormsSelected(0)
+ ,m_nControlsSelected(0)
+ ,m_nHiddenControls(0)
+ ,m_bDragDataDirty(false)
+ ,m_bPrevSelectionMixed(false)
+ ,m_bRootSelected(false)
+ ,m_bInitialUpdate(true)
+ ,m_bKeyboardCut( false )
+ ,m_bEditing( false )
+ {
+ m_xTreeView->set_help_id(HID_FORM_NAVIGATOR);
+ m_xTreeView->set_size_request(200, 200);
+
+ m_xTreeView->set_selection_mode(SelectionMode::Multiple);
+
+ m_pNavModel.reset(new NavigatorTreeModel());
+ Clear();
+
+ StartListening( *m_pNavModel );
+
+ m_aSynchronizeTimer.SetInvokeHandler(LINK(this, NavigatorTree, OnSynchronizeTimer));
+ m_xTreeView->connect_changed(LINK(this, NavigatorTree, OnEntrySelDesel));
+ m_xTreeView->connect_key_press(LINK(this, NavigatorTree, KeyInputHdl));
+ m_xTreeView->connect_popup_menu(LINK(this, NavigatorTree, PopupMenuHdl));
+ m_xTreeView->connect_editing(LINK(this, NavigatorTree, EditingEntryHdl),
+ LINK(this, NavigatorTree, EditedEntryHdl));
+ m_xTreeView->connect_drag_begin(LINK(this, NavigatorTree, DragBeginHdl));
+ }
+
+ NavigatorTree::~NavigatorTree()
+ {
+ if( nEditEvent )
+ Application::RemoveUserEvent( nEditEvent );
+
+ if (m_aSynchronizeTimer.IsActive())
+ m_aSynchronizeTimer.Stop();
+
+ DBG_ASSERT(GetNavModel() != nullptr, "NavigatorTree::~NavigatorTree : unexpected : no ExplorerModel");
+ EndListening( *m_pNavModel );
+ Clear();
+ m_pNavModel.reset();
+ }
+
+ void NavigatorTree::Clear()
+ {
+ m_pNavModel->Clear();
+ }
+
+ void NavigatorTree::UpdateContent( FmFormShell* pFormShell )
+ {
+ if (m_bInitialUpdate)
+ {
+ GrabFocus();
+ m_bInitialUpdate = false;
+ }
+
+ FmFormShell* pOldShell = GetNavModel()->GetFormShell();
+ FmFormPage* pOldPage = GetNavModel()->GetFormPage();
+ FmFormPage* pNewPage = pFormShell ? pFormShell->GetCurPage() : nullptr;
+
+ if ((pOldShell != pFormShell) || (pOldPage != pNewPage))
+ {
+ // new shell during editing
+ if (IsEditingActive())
+ {
+ m_xTreeView->end_editing();
+ m_bEditing = false;
+ }
+
+ m_bDragDataDirty = true; // as a precaution, although I don't drag
+ }
+ GetNavModel()->UpdateContent( pFormShell );
+
+ // if there is a form, expand root
+ if (m_xRootEntry && !m_xTreeView->get_row_expanded(*m_xRootEntry))
+ m_xTreeView->expand_row(*m_xRootEntry);
+ // if there is EXACTLY ONE form, expand it too
+ if (m_xRootEntry)
+ {
+ std::unique_ptr<weld::TreeIter> xFirst(m_xTreeView->make_iterator(m_xRootEntry.get()));
+ bool bFirst = m_xTreeView->iter_children(*xFirst);
+ if (bFirst)
+ {
+ std::unique_ptr<weld::TreeIter> xSibling(m_xTreeView->make_iterator(xFirst.get()));
+ if (!m_xTreeView->iter_next_sibling(*xSibling))
+ m_xTreeView->expand_row(*xFirst);
+ }
+ }
+ }
+
+ bool NavigatorTree::implAllowExchange( sal_Int8 _nAction, bool* _pHasNonHidden )
+ {
+ bool bCurEntry = m_xTreeView->get_cursor(nullptr);
+ if (!bCurEntry)
+ return false;
+
+ // Information for AcceptDrop and Execute Drop
+ CollectSelectionData(SDI_ALL);
+ if (m_arrCurrentSelection.empty())
+ // nothing to do
+ return false;
+
+ // check whether there are only hidden controls
+ // I may add a format to pCtrlExch
+ bool bHasNonHidden = std::any_of(m_arrCurrentSelection.begin(), m_arrCurrentSelection.end(),
+ [this](const auto& rEntry) {
+ FmEntryData* pCurrent = weld::fromId<FmEntryData*>(m_xTreeView->get_id(*rEntry));
+ return !IsHiddenControl( pCurrent );
+ });
+
+ if ( bHasNonHidden && ( 0 == ( _nAction & DND_ACTION_MOVE ) ) )
+ // non-hidden controls need to be moved
+ return false;
+
+ if ( _pHasNonHidden )
+ *_pHasNonHidden = bHasNonHidden;
+
+ return true;
+ }
+
+ bool NavigatorTree::implPrepareExchange( sal_Int8 _nAction )
+ {
+ bool bHasNonHidden = false;
+ if ( !implAllowExchange( _nAction, &bHasNonHidden ) )
+ return false;
+
+ m_aControlExchange.prepareDrag();
+ m_aControlExchange->setFocusEntry(m_xTreeView->get_cursor(nullptr));
+
+ for (const auto& rpEntry : m_arrCurrentSelection)
+ m_aControlExchange->addSelectedEntry(m_xTreeView->make_iterator(rpEntry.get()));
+
+ m_aControlExchange->setFormsRoot( GetNavModel()->GetFormPage()->GetForms() );
+ m_aControlExchange->buildPathFormat(m_xTreeView.get(), m_xRootEntry.get());
+
+ if (!bHasNonHidden)
+ {
+ // create a sequence
+ Sequence< Reference< XInterface > > seqIFaces(m_arrCurrentSelection.size());
+ Reference< XInterface >* pArray = seqIFaces.getArray();
+ for (const auto& rpEntry : m_arrCurrentSelection)
+ {
+ *pArray = weld::fromId<FmEntryData*>(m_xTreeView->get_id(*rpEntry))->GetElement();
+ ++pArray;
+ }
+ // and the new format
+ m_aControlExchange->addHiddenControlsFormat(seqIFaces);
+ }
+
+ m_bDragDataDirty = false;
+ return true;
+ }
+
+ IMPL_LINK(NavigatorTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+ {
+ rUnsetDragIcon = false;
+
+ bool bSuccess = implPrepareExchange(DND_ACTION_COPYMOVE);
+ if (bSuccess)
+ {
+ OControlExchange& rExchange = *m_aControlExchange;
+ rtl::Reference<TransferDataContainer> xHelper(&rExchange);
+ m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPYMOVE);
+ rExchange.setDragging(true);
+ }
+ return !bSuccess;
+ }
+
+ IMPL_LINK(NavigatorTree, PopupMenuHdl, const CommandEvent&, rEvt, bool)
+ {
+ bool bHandled = false;
+ switch( rEvt.GetCommand() )
+ {
+ case CommandEventId::ContextMenu:
+ {
+ // Position of click
+ ::Point ptWhere;
+ if (rEvt.IsMouseEvent())
+ {
+ ptWhere = rEvt.GetMousePosPixel();
+ std::unique_ptr<weld::TreeIter> xClickedOn(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_dest_row_at_pos(ptWhere, xClickedOn.get(), false))
+ break;
+ if (!m_xTreeView->is_selected(*xClickedOn))
+ {
+ m_xTreeView->unselect_all();
+ m_xTreeView->select(*xClickedOn);
+ m_xTreeView->set_cursor(*xClickedOn);
+ }
+ }
+ else
+ {
+ if (m_arrCurrentSelection.empty()) // only happens with context menu via keyboard
+ break;
+
+ std::unique_ptr<weld::TreeIter> xCurrent(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xCurrent.get()))
+ break;
+ ptWhere = m_xTreeView->get_row_area(*xCurrent).Center();
+ }
+
+ // update my selection data
+ CollectSelectionData(SDI_ALL);
+
+ // if there is at least one no-root-entry and the root selected, I deselect root
+ if ( (m_arrCurrentSelection.size() > 1) && m_bRootSelected )
+ {
+ const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
+ m_xTreeView->set_cursor(*rIter);
+ m_xTreeView->unselect(*m_xRootEntry);
+ }
+ bool bSingleSelection = (m_arrCurrentSelection.size() == 1);
+
+
+ DBG_ASSERT( (!m_arrCurrentSelection.empty()) || m_bRootSelected, "no entries selected" );
+ // shouldn't happen, because I would have selected one during call to IsSelected,
+ // if there was none before
+
+
+ // create menu
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : nullptr;
+ if( pFormShell && pFormModel )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "svx/ui/formnavimenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+ std::unique_ptr<weld::Menu> xSubMenuNew(xBuilder->weld_menu("submenu"));
+
+ // menu 'New' only exists, if only the root or only one form is selected
+ bool bShowNew = bSingleSelection && (m_nFormsSelected || m_bRootSelected);
+ if (!bShowNew)
+ xContextMenu->remove("new");
+
+ // 'New'\'Form' under the same terms
+ bool bShowForm = bSingleSelection && (m_nFormsSelected || m_bRootSelected);
+ if (bShowForm)
+ xSubMenuNew->append("form", SvxResId(RID_STR_FORM), RID_SVXBMP_FORM);
+
+ // 'New'\'hidden...', if exactly one form is selected
+ bool bShowHidden = bSingleSelection && m_nFormsSelected;
+ if (bShowHidden)
+ xSubMenuNew->append("hidden", SvxResId(RID_STR_HIDDEN), RID_SVXBMP_HIDDEN);
+
+ // 'Delete': everything which is not root can be removed
+ if (m_bRootSelected)
+ xContextMenu->remove("delete");
+
+ // 'Cut', 'Copy' and 'Paste'
+ bool bShowCut = !m_bRootSelected && implAllowExchange(DND_ACTION_MOVE);
+ if (!bShowCut)
+ xContextMenu->remove("cut");
+ bool bShowCopy = !m_bRootSelected && implAllowExchange(DND_ACTION_COPY);
+ if (!bShowCopy)
+ xContextMenu->remove("copy");
+ if (!implAcceptPaste())
+ xContextMenu->remove("paste");
+
+ // TabDialog, if exactly one form
+ bool bShowTabOrder = bSingleSelection && m_nFormsSelected;
+ if (!bShowTabOrder)
+ xContextMenu->remove("taborder");
+
+ bool bShowProps = true;
+ // in XML forms, we don't allow for the properties of a form
+ // #i36484#
+ if (pFormShell->GetImpl()->isEnhancedForm_Lock() && !m_nControlsSelected)
+ bShowProps = false;
+ // if the property browser is already open, we don't allow for the properties, too
+ if (pFormShell->GetImpl()->IsPropBrwOpen_Lock())
+ bShowProps = false;
+
+ // and finally, if there's a mixed selection of forms and controls, disable the entry, too
+ if (bShowProps && !pFormShell->GetImpl()->IsPropBrwOpen_Lock())
+ bShowProps =
+ (m_nControlsSelected && !m_nFormsSelected) || (!m_nControlsSelected && m_nFormsSelected);
+
+ if (!bShowProps)
+ xContextMenu->remove("props");
+
+ // rename, if one element and no root
+ bool bShowRename = bSingleSelection && !m_bRootSelected;
+ if (!bShowRename)
+ xContextMenu->remove("rename");
+
+ if (!m_bRootSelected)
+ {
+ // Readonly-entry is only for root
+ xContextMenu->remove("designmode");
+ // the same for automatic control focus
+ xContextMenu->remove("controlfocus");
+ }
+
+ std::unique_ptr<weld::Menu> xConversionMenu(xBuilder->weld_menu("changemenu"));
+ // ConvertTo-Slots are enabled, if one control is selected
+ // the corresponding slot is disabled
+ if (!m_bRootSelected && !m_nFormsSelected && (m_nControlsSelected == 1))
+ {
+ FmXFormShell::GetConversionMenu_Lock(*xConversionMenu);
+#if OSL_DEBUG_LEVEL > 0
+ const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
+ FmControlData* pCurrent = weld::fromId<FmControlData*>(m_xTreeView->get_id(*rIter));
+ OSL_ENSURE( pFormShell->GetImpl()->isSolelySelected_Lock( pCurrent->GetFormComponent() ),
+ "NavigatorTree::Command: inconsistency between the navigator selection, and the selection as the shell knows it!" );
+#endif
+
+ pFormShell->GetImpl()->checkControlConversionSlotsForCurrentSelection_Lock(*xConversionMenu);
+ }
+ else
+ xContextMenu->remove("change");
+
+ if (m_bRootSelected)
+ {
+ // set OpenReadOnly
+ xContextMenu->set_active("designmode", pFormModel->GetOpenInDesignMode());
+ xContextMenu->set_active("controlfocus", pFormModel->GetAutoControlFocus());
+ }
+
+ OString sIdent = xContextMenu->popup_at_rect(m_xTreeView.get(), tools::Rectangle(ptWhere, ::Size(1, 1)));
+ if (sIdent == "form")
+ {
+ OUString aStr(SvxResId(RID_STR_FORM));
+ OUString aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_INSERT).replaceAll("#", aStr);
+
+ pFormModel->BegUndo(aUndoStr);
+ // slot was only available, if there is only one selected entry,
+ // which is a root or a form
+ const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
+ NewForm(*rIter);
+ pFormModel->EndUndo();
+ }
+ else if (sIdent == "hidden")
+ {
+ OUString aStr(SvxResId(RID_STR_CONTROL));
+ OUString aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_INSERT).replaceAll("#", aStr);
+
+ pFormModel->BegUndo(aUndoStr);
+ // slot was valid for (exactly) one selected form
+ const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
+ NewControl(FM_COMPONENT_HIDDEN, *rIter, true);
+ pFormModel->EndUndo();
+ }
+ else if (sIdent == "cut")
+ doCut();
+ else if (sIdent == "copy")
+ doCopy();
+ else if (sIdent == "paste")
+ doPaste();
+ else if (sIdent == "delete")
+ DeleteSelection();
+ else if (sIdent == "taborder")
+ {
+ // this slot was effective for exactly one selected form
+ const std::unique_ptr<weld::TreeIter>& rSelectedForm = *m_arrCurrentSelection.begin();
+ DBG_ASSERT( IsFormEntry(*rSelectedForm), "NavigatorTree::Command: This entry must be a FormEntry." );
+
+ FmFormData* pFormData = weld::fromId<FmFormData*>(m_xTreeView->get_id(*rSelectedForm));
+ const Reference< XForm >& xForm( pFormData->GetFormIface());
+
+ Reference< XTabControllerModel > xTabController(xForm, UNO_QUERY);
+ if( !xTabController.is() )
+ break;
+ GetNavModel()->GetFormShell()->GetImpl()->ExecuteTabOrderDialog_Lock(xTabController);
+ }
+ else if (sIdent == "props")
+ ShowSelectionProperties(true);
+ else if (sIdent == "rename")
+ {
+ // only allowed for one no-root-entry
+ const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
+ m_xTreeView->start_editing(*rIter);
+ m_bEditing = true;
+ }
+ else if (sIdent == "designmode")
+ {
+ pFormModel->SetOpenInDesignMode( !pFormModel->GetOpenInDesignMode() );
+ pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_OPEN_READONLY);
+ }
+ else if (sIdent == "controlfocus")
+ {
+ pFormModel->SetAutoControlFocus( !pFormModel->GetAutoControlFocus() );
+ pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_AUTOCONTROLFOCUS);
+ }
+ else if (FmXFormShell::isControlConversionSlot(sIdent))
+ {
+ const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
+ FmControlData* pCurrent = weld::fromId<FmControlData*>(m_xTreeView->get_id(*rIter));
+ if (pFormShell->GetImpl()->executeControlConversionSlot_Lock(pCurrent->GetFormComponent(), sIdent))
+ ShowSelectionProperties();
+ }
+ }
+ bHandled = true;
+ }
+ break;
+ default: break;
+ }
+
+ return bHandled;
+ }
+
+ std::unique_ptr<weld::TreeIter> NavigatorTree::FindEntry(FmEntryData* pEntryData)
+ {
+ std::unique_ptr<weld::TreeIter> xRet;
+ if(!pEntryData)
+ return xRet;
+
+ m_xTreeView->all_foreach([this, pEntryData, &xRet](weld::TreeIter& rEntry){
+ FmEntryData* pCurEntryData = weld::fromId<FmEntryData*>(m_xTreeView->get_id(rEntry));
+ if (pCurEntryData && pCurEntryData->IsEqualWithoutChildren(pEntryData))
+ {
+ xRet = m_xTreeView->make_iterator(&rEntry);
+ return true;
+ }
+ return false;
+ });
+
+ return xRet;
+ }
+
+ void NavigatorTree::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+ {
+ if( auto pRemovedHint = dynamic_cast<const FmNavRemovedHint*>(&rHint) )
+ {
+ FmEntryData* pEntryData = pRemovedHint->GetEntryData();
+ Remove( pEntryData );
+ }
+ else if( auto pInsertedHint = dynamic_cast<const FmNavInsertedHint*>(&rHint) )
+ {
+ FmEntryData* pEntryData = pInsertedHint->GetEntryData();
+ sal_uInt32 nRelPos = pInsertedHint->GetRelPos();
+ Insert( pEntryData, nRelPos );
+ }
+ else if( auto pReplacedHint = dynamic_cast<const FmNavModelReplacedHint*>(&rHint) )
+ {
+ FmEntryData* pData = pReplacedHint->GetEntryData();
+ std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pData);
+ if (xEntry)
+ {
+ // reset image
+ m_xTreeView->set_image(*xEntry, pData->GetNormalImage());
+ }
+ }
+ else if( auto pNameChangedHint = dynamic_cast<const FmNavNameChangedHint*>(&rHint) )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pNameChangedHint->GetEntryData());
+ m_xTreeView->set_text(*xEntry, pNameChangedHint->GetNewName());
+ }
+ else if( dynamic_cast<const FmNavClearedHint*>(&rHint) )
+ {
+ m_aCutEntries.clear();
+ if (m_aControlExchange.isDataExchangeActive())
+ m_aControlExchange.clear();
+ m_xTreeView->clear();
+
+ // default-entry "Forms"
+ OUString sText(SvxResId(RID_STR_FORMS));
+ m_xRootEntry = m_xTreeView->make_iterator();
+ m_xTreeView->insert(nullptr, -1, &sText, nullptr, nullptr, nullptr,
+ false, m_xRootEntry.get());
+ m_xTreeView->set_image(*m_xRootEntry, RID_SVXBMP_FORMS);
+ m_xTreeView->set_sensitive(*m_xRootEntry, true);
+ }
+ else if (auto pSelectHint = dynamic_cast<FmNavRequestSelectHint*>(const_cast<SfxHint*>(&rHint)))
+ {
+ FmEntryDataArray& arredToSelect = pSelectHint->GetItems();
+ SynchronizeSelection(arredToSelect);
+
+ if (pSelectHint->IsMixedSelection())
+ // in this case I deselect all, although the view had a mixed selection
+ // during next selection, I must adapt the navigator to the view
+ m_bPrevSelectionMixed = true;
+ }
+ }
+
+ std::unique_ptr<weld::TreeIter> NavigatorTree::Insert(const FmEntryData* pEntryData, int nRelPos)
+ {
+ // insert current entry
+ std::unique_ptr<weld::TreeIter> xParentEntry = FindEntry( pEntryData->GetParent() );
+ std::unique_ptr<weld::TreeIter> xNewEntry(m_xTreeView->make_iterator());
+ OUString sId(weld::toId(pEntryData));
+
+ if(!xParentEntry)
+ {
+ m_xTreeView->insert(m_xRootEntry.get(), nRelPos, &pEntryData->GetText(), &sId,
+ nullptr, nullptr, false, xNewEntry.get());
+ }
+ else
+ {
+ m_xTreeView->insert(xParentEntry.get(), nRelPos, &pEntryData->GetText(), &sId,
+ nullptr, nullptr, false, xNewEntry.get());
+ }
+
+ m_xTreeView->set_image(*xNewEntry, pEntryData->GetNormalImage());
+ m_xTreeView->set_sensitive(*xNewEntry, true);
+
+ // If root-entry, expand root
+ if (!xParentEntry)
+ m_xTreeView->expand_row(*m_xRootEntry);
+
+ // insert children
+ FmEntryDataList* pChildList = pEntryData->GetChildList();
+ size_t nChildCount = pChildList->size();
+ for( size_t i = 0; i < nChildCount; i++ )
+ {
+ FmEntryData* pChildData = pChildList->at( i );
+ Insert(pChildData, -1);
+ }
+
+ return xNewEntry;
+ }
+
+ void NavigatorTree::Remove( FmEntryData* pEntryData )
+ {
+ if( !pEntryData )
+ return;
+
+ // entry for the data
+ std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pEntryData);
+ if (!xEntry)
+ return;
+
+ // delete entry from TreeListBox
+ // I'm not allowed, to treat the selection, which I trigger:
+ // select changes the MarkList of the view, if somebody else does this at the same time
+ // and removes a selection, we get a problem
+ // e.g. Group controls with open navigator
+ LockSelectionHandling();
+
+ // little problem: I remember the selected data, but if somebody deletes one of these entries,
+ // I get inconsistent... this would be bad
+ m_xTreeView->unselect(*xEntry);
+
+ // selection can be modified during deletion,
+ // but because I disabled SelectionHandling, I have to do it later
+ auto nExpectedSelectionCount = m_xTreeView->count_selected_rows();
+
+ ModelHasRemoved(xEntry.get());
+ m_xTreeView->remove(*xEntry);
+
+ if (nExpectedSelectionCount != m_xTreeView->count_selected_rows())
+ SynchronizeSelection();
+
+ // by default I treat the selection of course
+ UnlockSelectionHandling();
+ }
+
+ bool NavigatorTree::IsFormEntry(const weld::TreeIter& rEntry)
+ {
+ FmEntryData* pEntryData = weld::fromId<FmEntryData*>(m_xTreeView->get_id(rEntry));
+ return !pEntryData || dynamic_cast<const FmFormData*>( pEntryData) != nullptr;
+ }
+
+ bool NavigatorTree::IsFormComponentEntry(const weld::TreeIter& rEntry)
+ {
+ FmEntryData* pEntryData = weld::fromId<FmEntryData*>(m_xTreeView->get_id(rEntry));
+ return dynamic_cast<const FmControlData*>( pEntryData) != nullptr;
+ }
+
+ bool NavigatorTree::implAcceptPaste( )
+ {
+ auto nSelectedEntries = m_xTreeView->count_selected_rows();
+ if (nSelectedEntries != 1)
+ // no selected entry, or at least two selected entries
+ return false;
+
+ // get the clipboard
+ TransferableDataHelper aClipboardContent(TransferableDataHelper::CreateFromClipboard(m_xTreeView->get_clipboard()));
+
+ sal_Int8 nAction = m_aControlExchange.isClipboardOwner() && doingKeyboardCut( ) ? DND_ACTION_MOVE : DND_ACTION_COPY;
+ std::unique_ptr<weld::TreeIter> xSelected(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_selected(xSelected.get()))
+ xSelected.reset();
+ return nAction == implAcceptDataTransfer(aClipboardContent.GetDataFlavorExVector(), nAction, xSelected.get(), false);
+ }
+
+ sal_Int8 NavigatorTree::implAcceptDataTransfer( const DataFlavorExVector& _rFlavors, sal_Int8 _nAction, const weld::TreeIter* _pTargetEntry, bool _bDnD )
+ {
+ // no target -> no drop
+ if (!_pTargetEntry)
+ return DND_ACTION_NONE;
+
+ // format check
+ bool bHasDefControlFormat = OControlExchange::hasFieldExchangeFormat( _rFlavors );
+ bool bHasControlPathFormat = OControlExchange::hasControlPathFormat( _rFlavors );
+ bool bHasHiddenControlsFormat = OControlExchange::hasHiddenControlModelsFormat( _rFlavors );
+ if (!bHasDefControlFormat && !bHasControlPathFormat && !bHasHiddenControlsFormat)
+ return DND_ACTION_NONE;
+
+ bool bSelfSource = _bDnD ? m_aControlExchange.isDragSource() : m_aControlExchange.isClipboardOwner();
+
+ if ( bHasHiddenControlsFormat )
+ { // bHasHiddenControlsFormat means that only hidden controls are part of the data
+
+ // hidden controls can be copied to a form only
+ if (m_xTreeView->iter_compare(*_pTargetEntry, *m_xRootEntry) == 0 || !IsFormEntry(*_pTargetEntry))
+ return DND_ACTION_NONE;
+
+ return bSelfSource ? ( DND_ACTION_COPYMOVE & _nAction ) : DND_ACTION_COPY;
+ }
+
+ if ( !bSelfSource )
+ {
+ // DnD or CnP crossing navigator boundaries
+ // The main problem here is that the current API does not allow us to sneak into the content which
+ // is to be inserted. So we have to allow it for the moment, but maybe reject later on (in the real drop).
+
+ // TODO: this smart behaviour later on ... at the moment, we disallow data transfer crossing navigator
+ // boundaries.
+
+ return DND_ACTION_NONE;
+ }
+
+ DBG_ASSERT( _bDnD ? m_aControlExchange.isDragSource() : m_aControlExchange.isClipboardOwner(),
+ "NavigatorTree::implAcceptDataTransfer: here only with source=dest!" );
+ // somebody changed the logic of this method ...
+
+ // from here on, I can work with m_aControlExchange instead of _rData!
+
+ bool bForeignCollection = m_aControlExchange->getFormsRoot().get() != GetNavModel()->GetFormPage()->GetForms().get();
+ if ( bForeignCollection )
+ {
+ // crossing shell/page boundaries, we can exchange hidden controls only
+ // But if we survived the checks above, we do not have hidden controls.
+ // -> no data transfer
+ DBG_ASSERT( !bHasHiddenControlsFormat, "NavigatorTree::implAcceptDataTransfer: still hidden controls format!" );
+ // somebody changed the logic of this method ...
+
+ return DND_ACTION_COPY;
+ }
+
+ if (DND_ACTION_MOVE != _nAction) // 'normal' controls within a shell are moved only (never copied)
+ return DND_ACTION_NONE;
+
+ if ( m_bDragDataDirty || !bHasDefControlFormat )
+ {
+ if (!bHasControlPathFormat)
+ // I am in the shell/page, which has the controls, but I have no format,
+ // which survived the shell change (SVX_FM_CONTROLS_AS_PATH)
+ return DND_ACTION_NONE;
+
+ // I must recreate the list of the ExchangeObjects, because the shell was changed during dragging
+ // (there are SvLBoxEntries in it, and we lost them during change)
+ m_aControlExchange->buildListFromPath(m_xTreeView.get(), m_xRootEntry.get());
+ m_bDragDataDirty = false;
+ }
+
+ // List of dropped entries from DragServer
+ const ListBoxEntrySet& rDropped = m_aControlExchange->selected();
+ DBG_ASSERT(!rDropped.empty(), "NavigatorTree::implAcceptDataTransfer: no entries !");
+
+ bool bDropTargetIsComponent = IsFormComponentEntry( *_pTargetEntry );
+
+ // conditions to disallow the drop
+ // 0) the root entry is part of the list (can't DnD the root!)
+ // 1) one of the dragged entries is to be dropped onto its own parent
+ // 2) - " - is to be dropped onto itself
+ // 3) - " - is a Form and to be dropped onto one of its descendants
+ // 4) one of the entries is a control and to be dropped onto the root
+ // 5) a control or form will be dropped onto a control which is _not_ a sibling (dropping onto a sibling
+ // means moving the control)
+
+ // collect the ancestors of the drop target (speeds up 3)
+ SvLBoxEntrySortedArray arrDropAncestors;
+ std::unique_ptr<weld::TreeIter> xLoop(m_xTreeView->make_iterator(_pTargetEntry));
+ do
+ {
+ arrDropAncestors.emplace(m_xTreeView->make_iterator(xLoop.get()));
+ }
+ while (m_xTreeView->iter_parent(*xLoop));
+
+ for (const auto& rCurrent : rDropped)
+ {
+ // test for 0)
+ if (m_xTreeView->iter_compare(*rCurrent, *m_xRootEntry) == 0)
+ return DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xCurrentParent(m_xTreeView->make_iterator(rCurrent.get()));
+ m_xTreeView->iter_parent(*xCurrentParent);
+
+ // test for 1)
+ if (m_xTreeView->iter_compare(*_pTargetEntry, *xCurrentParent) == 0)
+ return DND_ACTION_NONE;
+
+ // test for 2)
+ if (m_xTreeView->iter_compare(*rCurrent, *_pTargetEntry) == 0)
+ return DND_ACTION_NONE;
+
+ // test for 5)
+ if (bDropTargetIsComponent)
+ return DND_ACTION_NONE;
+
+ // test for 3)
+ if (IsFormEntry(*rCurrent))
+ {
+ auto aIter = std::find_if(arrDropAncestors.begin(), arrDropAncestors.end(),
+ [this, &rCurrent](const auto& rElem) {
+ return m_xTreeView->iter_compare(*rElem, *rCurrent) == 0;
+ });
+
+ if ( aIter != arrDropAncestors.end() )
+ return DND_ACTION_NONE;
+ }
+ else if (IsFormComponentEntry(*rCurrent))
+ {
+ // test for 4)
+ if (m_xTreeView->iter_compare(*_pTargetEntry, *m_xRootEntry) == 0)
+ return DND_ACTION_NONE;
+ }
+ }
+ return DND_ACTION_MOVE;
+ }
+
+ sal_Int8 NavigatorTree::AcceptDrop( const AcceptDropEvent& rEvt )
+ {
+ ::Point aDropPos = rEvt.maPosPixel;
+ std::unique_ptr<weld::TreeIter> xDropTarget(m_xTreeView->make_iterator());
+ // get_dest_row_at_pos with false cause we must drop exactly "on" a form to paste a control into it
+ if (!m_xTreeView->get_dest_row_at_pos(aDropPos, xDropTarget.get(), false))
+ xDropTarget.reset();
+ return implAcceptDataTransfer(m_aDropTargetHelper.GetDataFlavorExVector(), rEvt.mnAction, xDropTarget.get(), true);
+ }
+
+ sal_Int8 NavigatorTree::implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, const ::Point& _rDropPos, bool _bDnD )
+ {
+ std::unique_ptr<weld::TreeIter> xDrop(m_xTreeView->make_iterator());
+ // get_dest_row_at_pos with false cause we must drop exactly "on" a form to paste a control into it
+ if (!m_xTreeView->get_dest_row_at_pos(_rDropPos, xDrop.get(), false))
+ xDrop.reset();
+ return implExecuteDataTransfer( _rData, _nAction, xDrop.get(), _bDnD );
+ }
+
+ sal_Int8 NavigatorTree::implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, const weld::TreeIter* _pTargetEntry, bool _bDnD )
+ {
+ const DataFlavorExVector& rDataFlavors = _rData.GetDataFlavorExVector();
+
+ if ( DND_ACTION_NONE == implAcceptDataTransfer( rDataFlavors, _nAction, _pTargetEntry, _bDnD ) )
+ // under some platforms, it may happen that ExecuteDrop is called though AcceptDrop returned DND_ACTION_NONE
+ return DND_ACTION_NONE;
+
+ if (!_pTargetEntry)
+ // no target -> no drop
+ return DND_ACTION_NONE;
+
+ // format checks
+#ifdef DBG_UTIL
+ bool bHasHiddenControlsFormat = OControlExchange::hasHiddenControlModelsFormat( rDataFlavors );
+ bool bForeignCollection = _rData.getFormsRoot().get() != GetNavModel()->GetFormPage()->GetForms().get();
+ DBG_ASSERT(!bForeignCollection || bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: invalid format (AcceptDrop shouldn't have let this pass) !");
+ DBG_ASSERT(bForeignCollection || !m_bDragDataDirty, "NavigatorTree::implExecuteDataTransfer: invalid state (shell changed since last exchange resync) !");
+ // this should be done in AcceptDrop: the list of controls is created in _rData
+ // and m_bDragDataDirty is reset
+#endif
+
+ if ( DND_ACTION_COPY == _nAction )
+ { // bHasHiddenControlsFormat means that only hidden controls are part of the data
+#ifdef DBG_UTIL
+ DBG_ASSERT( bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: copy allowed for hidden controls only!" );
+#endif
+ DBG_ASSERT( _pTargetEntry && m_xTreeView->iter_compare(*_pTargetEntry, *m_xRootEntry) != 0 && IsFormEntry( *_pTargetEntry ),
+ "NavigatorTree::implExecuteDataTransfer: should not be here!" );
+ // implAcceptDataTransfer should have caught both cases
+
+#ifdef DBG_UTIL
+ DBG_ASSERT(bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: only copying of hidden controls is supported !");
+ // should be caught by AcceptDrop
+#endif
+
+ // because i want to select all targets (and only them)
+ m_xTreeView->unselect_all();
+
+ const Sequence< Reference< XInterface > >& aControls = _rData.hiddenControls();
+ sal_Int32 nCount = aControls.getLength();
+ const Reference< XInterface >* pControls = aControls.getConstArray();
+
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : nullptr;
+
+ // within undo
+ if (pFormModel)
+ {
+ OUString aStr(SvxResId(RID_STR_CONTROL));
+ OUString aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_INSERT).replaceAll("#", aStr);
+ pFormModel->BegUndo(aUndoStr);
+ }
+
+ // copy controls
+ for (sal_Int32 i=0; i<nCount; ++i)
+ {
+ // create new control
+ FmControlData* pNewControlData = NewControl( FM_COMPONENT_HIDDEN, *_pTargetEntry, false);
+ Reference< XPropertySet > xNewPropSet( pNewControlData->GetPropertySet() );
+
+ // copy properties form old control to new one
+ Reference< XPropertySet > xCurrent(pControls[i], UNO_QUERY);
+#if (OSL_DEBUG_LEVEL > 0)
+ // check whether it is a hidden control
+ sal_Int16 nClassId = ::comphelper::getINT16(xCurrent->getPropertyValue(FM_PROP_CLASSID));
+ OSL_ENSURE(nClassId == FormComponentType::HIDDENCONTROL, "NavigatorTree::implExecuteDataTransfer: invalid control in drop list !");
+ // if SVX_FM_HIDDEN_CONTROLS-format exists, the sequence
+ // should only contain hidden controls
+#endif // (OSL_DEBUG_LEVEL > 0)
+ Reference< XPropertySetInfo > xPropInfo( xCurrent->getPropertySetInfo());
+ const Sequence< Property> seqAllCurrentProps = xPropInfo->getProperties();
+ for (Property const & currentProp : seqAllCurrentProps)
+ {
+ if (((currentProp.Attributes & PropertyAttribute::READONLY) == 0) && (currentProp.Name != FM_PROP_NAME))
+ { // (read-only attribs aren't set, ditto name,
+ // NewControl defined it uniquely
+ xNewPropSet->setPropertyValue(currentProp.Name, xCurrent->getPropertyValue(currentProp.Name));
+ }
+ }
+
+ std::unique_ptr<weld::TreeIter> xToSelect = FindEntry(pNewControlData);
+ m_xTreeView->select(*xToSelect);
+ if (i == 0)
+ m_xTreeView->set_cursor(*xToSelect);
+ }
+
+ if (pFormModel)
+ pFormModel->EndUndo();
+
+ return _nAction;
+ }
+
+ if ( !OControlExchange::hasFieldExchangeFormat( _rData.GetDataFlavorExVector() ) )
+ {
+ // can't do anything without the internal format here ... usually happens when doing DnD or CnP
+ // over navigator boundaries
+ return DND_ACTION_NONE;
+ }
+
+ // some data for the target
+ bool bDropTargetIsForm = IsFormEntry(*_pTargetEntry);
+ FmFormData* pTargetData = bDropTargetIsForm ? weld::fromId<FmFormData*>(m_xTreeView->get_id(*_pTargetEntry)) : nullptr;
+
+ DBG_ASSERT( DND_ACTION_COPY != _nAction, "NavigatorTree::implExecuteDataTransfer: somebody changed the logics!" );
+
+ // list of dragged entries
+ const ListBoxEntrySet& rDropped = _rData.selected();
+ DBG_ASSERT(!rDropped.empty(), "NavigatorTree::implExecuteDataTransfer: no entries!");
+
+ // make a copy because rDropped is updated on deleting an entry which we do in the processing loop
+ ListBoxEntrySet aDropped;
+ for (const auto& rEntry : rDropped)
+ aDropped.emplace(m_xTreeView->make_iterator(rEntry.get()));
+
+ // shell and model
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : nullptr;
+ if (!pFormModel)
+ return DND_ACTION_NONE;
+
+ // for Undo
+ const bool bUndo = pFormModel->IsUndoEnabled();
+
+ if( bUndo )
+ {
+ OUString strUndoDescription(SvxResId(RID_STR_UNDO_CONTAINER_REPLACE));
+ pFormModel->BegUndo(strUndoDescription);
+ }
+
+ // remove selection before adding an entry, so the mark doesn't flicker
+ // -> lock action of selection
+ LockSelectionHandling();
+
+ // go through all dropped entries
+ for ( ListBoxEntrySet::const_iterator dropped = aDropped.begin();
+ dropped != aDropped.end();
+ ++dropped
+ )
+ {
+ bool bFirstEntry = aDropped.begin() == dropped;
+
+ // some data of the current element
+ const auto& rCurrent = *dropped;
+ DBG_ASSERT(rCurrent, "NavigatorTree::implExecuteDataTransfer: invalid entry");
+ DBG_ASSERT(m_xTreeView->get_iter_depth(*rCurrent) != 0, "NavigatorTree::implExecuteDataTransfer: invalid entry");
+ // don't drag root
+
+ FmEntryData* pCurrentUserData = weld::fromId<FmEntryData*>(m_xTreeView->get_id(*rCurrent));
+
+ Reference< XChild > xCurrentChild = pCurrentUserData->GetChildIFace();
+ Reference< XIndexContainer > xContainer(xCurrentChild->getParent(), UNO_QUERY);
+
+ FmFormData* pCurrentParentUserData = static_cast<FmFormData*>(pCurrentUserData->GetParent());
+ DBG_ASSERT(pCurrentParentUserData == nullptr || dynamic_cast<const FmFormData*>(pCurrentUserData->GetParent()) != nullptr, "NavigatorTree::implExecuteDataTransfer: invalid parent");
+
+ // remove from parent
+ if (pCurrentParentUserData)
+ pCurrentParentUserData->GetChildList()->removeNoDelete( pCurrentUserData );
+ else
+ GetNavModel()->GetRootList()->removeNoDelete( pCurrentUserData );
+
+ // remove from container
+ sal_Int32 nIndex = getElementPos(xContainer, xCurrentChild);
+ GetNavModel()->m_pPropChangeList->Lock();
+ // UndoAction for removal
+ if ( bUndo && GetNavModel()->m_pPropChangeList->CanUndo())
+ {
+ pFormModel->AddUndo(std::make_unique<FmUndoContainerAction>(*pFormModel, FmUndoContainerAction::Removed,
+ xContainer, xCurrentChild, nIndex));
+ }
+ else if( !GetNavModel()->m_pPropChangeList->CanUndo() )
+ {
+ FmUndoContainerAction::DisposeElement( xCurrentChild );
+ }
+
+ // copy events
+ Reference< XEventAttacherManager > xManager(xContainer, UNO_QUERY);
+ Sequence< ScriptEventDescriptor > aEvts;
+
+ if (xManager.is() && nIndex >= 0)
+ aEvts = xManager->getScriptEvents(nIndex);
+ xContainer->removeByIndex(nIndex);
+
+ // remove selection
+ m_xTreeView->unselect(*rCurrent);
+ // and delete it
+ Remove(pCurrentUserData);
+
+ // position in DropParents, where to insert dropped entries
+ if (pTargetData)
+ xContainer.set(pTargetData->GetElement(), UNO_QUERY);
+ else
+ xContainer = GetNavModel()->GetForms();
+
+ // always insert at the end
+ nIndex = xContainer->getCount();
+
+ // UndoAction for insertion
+ if ( bUndo && GetNavModel()->m_pPropChangeList->CanUndo())
+ pFormModel->AddUndo(std::make_unique<FmUndoContainerAction>(*pFormModel, FmUndoContainerAction::Inserted,
+ xContainer, xCurrentChild, nIndex));
+
+ // insert in new container
+ if (pTargetData)
+ {
+ // insert in a form needs a FormComponent
+ xContainer->insertByIndex( nIndex,
+ Any( Reference< XFormComponent >( xCurrentChild, UNO_QUERY ) ) );
+ }
+ else
+ {
+ xContainer->insertByIndex( nIndex,
+ Any( Reference< XForm >( xCurrentChild, UNO_QUERY ) ) );
+ }
+
+ if (aEvts.hasElements())
+ {
+ xManager.set(xContainer, UNO_QUERY);
+ if (xManager.is())
+ xManager->registerScriptEvents(nIndex, aEvts);
+ }
+
+ GetNavModel()->m_pPropChangeList->UnLock();
+
+ // give an entry the new parent
+ pCurrentUserData->SetParent(pTargetData);
+
+ // give parent the new child
+ if (pTargetData)
+ pTargetData->GetChildList()->insert( std::unique_ptr<FmEntryData>(pCurrentUserData), nIndex );
+ else
+ GetNavModel()->GetRootList()->insert( std::unique_ptr<FmEntryData>(pCurrentUserData), nIndex );
+
+ // announce to myself and reselect
+ std::unique_ptr<weld::TreeIter> xNew = Insert( pCurrentUserData, nIndex );
+ if (bFirstEntry && xNew)
+ {
+ if (m_xTreeView->iter_parent(*xNew))
+ m_xTreeView->expand_row(*xNew);
+ }
+ }
+
+ UnlockSelectionHandling();
+
+ if( bUndo )
+ pFormModel->EndUndo();
+
+ // During the move, the markings of the underlying view did not change (because the view is not affected by the logical
+ // hierarchy of the form/control models. But my selection changed - which means I have to adjust it according to the
+ // view marks, again.
+ SynchronizeSelection();
+
+ // in addition, with the move of controls such things as "the current form" may have changed - force the shell
+ // to update itself accordingly
+ if( pFormShell && pFormShell->GetImpl() && pFormShell->GetFormView() )
+ pFormShell->GetImpl()->DetermineSelection_Lock( pFormShell->GetFormView()->GetMarkedObjectList() );
+
+ if ( m_aControlExchange.isClipboardOwner() && ( DND_ACTION_MOVE == _nAction ) )
+ m_aControlExchange->clear();
+
+ return _nAction;
+ }
+
+ sal_Int8 NavigatorTree::ExecuteDrop( const ExecuteDropEvent& rEvt )
+ {
+ sal_Int8 nResult( DND_ACTION_NONE );
+ if ( m_aControlExchange.isDragSource() )
+ nResult = implExecuteDataTransfer( *m_aControlExchange, rEvt.mnAction, rEvt.maPosPixel, true );
+ else
+ {
+ OControlTransferData aDroppedData( rEvt.maDropEvent.Transferable );
+ nResult = implExecuteDataTransfer( aDroppedData, rEvt.mnAction, rEvt.maPosPixel, true );
+ }
+ return nResult;
+ }
+
+ void NavigatorTree::doPaste()
+ {
+ std::unique_ptr<weld::TreeIter> xSelected(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_selected(xSelected.get()))
+ xSelected.reset();
+
+ try
+ {
+ if ( m_aControlExchange.isClipboardOwner() )
+ {
+ implExecuteDataTransfer( *m_aControlExchange, doingKeyboardCut( ) ? DND_ACTION_MOVE : DND_ACTION_COPY, xSelected.get(), false );
+ }
+ else
+ {
+ // the clipboard content
+ Reference< XClipboard > xClipboard(m_xTreeView->get_clipboard());
+ Reference< XTransferable > xTransferable;
+ if ( xClipboard.is() )
+ xTransferable = xClipboard->getContents();
+
+ OControlTransferData aClipboardContent( xTransferable );
+ implExecuteDataTransfer( aClipboardContent, DND_ACTION_COPY, xSelected.get(), false );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "NavigatorTree::doPaste" );
+ }
+ }
+
+ void NavigatorTree::doCopy()
+ {
+ if ( implPrepareExchange( DND_ACTION_COPY ) )
+ {
+ m_aControlExchange.setClipboardListener( LINK( this, NavigatorTree, OnClipboardAction ) );
+ m_aControlExchange.copyToClipboard(*m_xTreeView);
+ }
+ }
+
+ void NavigatorTree::ModelHasRemoved(const weld::TreeIter* pTypedEntry)
+ {
+ if (doingKeyboardCut())
+ {
+ auto aIter = std::find_if(m_aCutEntries.begin(), m_aCutEntries.end(),
+ [this, pTypedEntry](const auto& rElem) {
+ return m_xTreeView->iter_compare(*rElem, *pTypedEntry) == 0;
+ });
+ if (aIter != m_aCutEntries.end())
+ m_aCutEntries.erase(aIter);
+ }
+
+ if (m_aControlExchange.isDataExchangeActive())
+ {
+ if (0 == m_aControlExchange->onEntryRemoved(m_xTreeView.get(), pTypedEntry))
+ {
+ // last of the entries which we put into the clipboard has been deleted from the tree.
+ // Give up the clipboard ownership.
+ m_aControlExchange.clear();
+ }
+ }
+ }
+
+ void NavigatorTree::doCut()
+ {
+ if ( !implPrepareExchange( DND_ACTION_MOVE ) )
+ return;
+
+ m_aControlExchange.setClipboardListener( LINK( this, NavigatorTree, OnClipboardAction ) );
+ m_aControlExchange.copyToClipboard(*m_xTreeView);
+ m_bKeyboardCut = true;
+
+ // mark all the entries we just "cut" into the clipboard as "nearly moved"
+ for (const auto& rEntry : m_arrCurrentSelection )
+ {
+ if (!rEntry)
+ continue;
+ m_aCutEntries.emplace(m_xTreeView->make_iterator(rEntry.get()));
+ m_xTreeView->set_sensitive(*rEntry, false);
+ }
+ }
+
+ IMPL_LINK(NavigatorTree, KeyInputHdl, const ::KeyEvent&, rKEvt, bool)
+ {
+ const vcl::KeyCode& rCode = rKEvt.GetKeyCode();
+
+ // delete?
+ if (rCode.GetCode() == KEY_DELETE && !rCode.GetModifier())
+ {
+ DeleteSelection();
+ return true;
+ }
+
+ // copy'n'paste?
+ switch ( rCode.GetFunction() )
+ {
+ case KeyFuncType::CUT:
+ doCut();
+ break;
+
+ case KeyFuncType::PASTE:
+ if ( implAcceptPaste() )
+ doPaste();
+ break;
+
+ case KeyFuncType::COPY:
+ doCopy();
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+ IMPL_LINK(NavigatorTree, EditingEntryHdl, const weld::TreeIter&, rIter, bool)
+ {
+ // root, which isn't allowed to be renamed, has UserData=NULL
+ m_bEditing = !m_xTreeView->get_id(rIter).isEmpty();
+ return m_bEditing;
+ }
+
+ void NavigatorTree::NewForm(const weld::TreeIter& rParentEntry)
+ {
+ // get ParentFormData
+ if (!IsFormEntry(rParentEntry))
+ return;
+
+ FmFormData* pParentFormData = weld::fromId<FmFormData*>(m_xTreeView->get_id(rParentEntry));
+
+
+ // create new form
+ Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
+ Reference< XForm > xNewForm(xContext->getServiceManager()->createInstanceWithContext(FM_SUN_COMPONENT_FORM, xContext), UNO_QUERY);
+ if (!xNewForm.is())
+ return;
+
+ Reference< XPropertySet > xPropertySet(xNewForm, UNO_QUERY);
+ if (!xPropertySet.is())
+ return;
+
+ FmFormData* pNewFormData = new FmFormData(xNewForm, pParentFormData);
+
+
+ // set name
+ OUString aName = GenerateName(pNewFormData);
+ pNewFormData->SetText(aName);
+
+ try
+ {
+ xPropertySet->setPropertyValue( FM_PROP_NAME, Any(aName) );
+ // a form should always have the command type table as default
+ xPropertySet->setPropertyValue( FM_PROP_COMMANDTYPE, Any(sal_Int32(CommandType::TABLE)));
+ }
+ catch ( const Exception& )
+ {
+ OSL_FAIL("NavigatorTree::NewForm : could not set essential properties!");
+ }
+
+
+ // insert form
+ GetNavModel()->Insert(pNewFormData, SAL_MAX_UINT32, true);
+
+
+ // set new form as active
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ if( pFormShell )
+ {
+ InterfaceBag aSelection;
+ aSelection.insert( Reference<XInterface>( xNewForm, UNO_QUERY ) );
+ pFormShell->GetImpl()->setCurrentSelection_Lock(std::move(aSelection));
+
+ pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_PROPERTIES, true, true);
+ }
+ GetNavModel()->SetModified();
+
+ // switch to EditMode
+ std::unique_ptr<weld::TreeIter> xNewEntry = FindEntry(pNewFormData);
+ m_xTreeView->start_editing(*xNewEntry);
+ m_bEditing = true;
+ }
+
+ FmControlData* NavigatorTree::NewControl(const OUString& rServiceName, const weld::TreeIter& rParentEntry, bool bEditName)
+ {
+ // get ParentForm
+ if (!GetNavModel()->GetFormShell())
+ return nullptr;
+ if (!IsFormEntry(rParentEntry))
+ return nullptr;
+
+ FmFormData* pParentFormData = weld::fromId<FmFormData*>(m_xTreeView->get_id(rParentEntry));
+ Reference<XForm> xParentForm(pParentFormData->GetFormIface());
+
+ // create new component
+ Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
+ Reference<XFormComponent> xNewComponent( xContext->getServiceManager()->createInstanceWithContext(rServiceName, xContext), UNO_QUERY);
+ if (!xNewComponent.is())
+ return nullptr;
+
+ FmControlData* pNewFormControlData = new FmControlData(xNewComponent, pParentFormData);
+
+ // set name
+ OUString sName = FmFormPageImpl::setUniqueName( xNewComponent, xParentForm );
+
+ pNewFormControlData->SetText( sName );
+
+ // insert FormComponent
+ GetNavModel()->Insert(pNewFormControlData, SAL_MAX_UINT32, true);
+ GetNavModel()->SetModified();
+
+ if (bEditName)
+ {
+ // switch to EditMode
+ std::unique_ptr<weld::TreeIter> xNewEntry = FindEntry( pNewFormControlData );
+ m_xTreeView->select(*xNewEntry);
+
+ m_xTreeView->start_editing(*xNewEntry);
+ m_bEditing = true;
+ }
+
+ return pNewFormControlData;
+ }
+
+ OUString NavigatorTree::GenerateName( FmEntryData const * pEntryData )
+ {
+ const sal_uInt16 nMaxCount = 99;
+ OUString aNewName;
+
+ // create base name
+ OUString aBaseName;
+ if( dynamic_cast<const FmFormData*>( pEntryData) != nullptr )
+ aBaseName = SvxResId( RID_STR_STDFORMNAME );
+ else if( dynamic_cast<const FmControlData*>( pEntryData) != nullptr )
+ aBaseName = SvxResId( RID_STR_CONTROL );
+
+
+ // create new name
+ FmFormData* pFormParentData = static_cast<FmFormData*>(pEntryData->GetParent());
+
+ for( sal_Int32 i=0; i<nMaxCount; i++ )
+ {
+ aNewName = aBaseName;
+ if( i>0 )
+ {
+ aNewName += " " + OUString::number(i);
+ }
+
+ if( GetNavModel()->FindData(aNewName, pFormParentData,false) == nullptr )
+ break;
+ }
+
+ return aNewName;
+ }
+
+ IMPL_LINK(NavigatorTree, EditedEntryHdl, const IterString&, rIterString, bool)
+ {
+ m_bEditing = false;
+
+ const weld::TreeIter& rIter = rIterString.first;
+
+ FmEntryData* pEntryData = weld::fromId<FmEntryData*>(m_xTreeView->get_id(rIter));
+ bool bRes = NavigatorTreeModel::Rename(pEntryData, rIterString.second);
+ if (!bRes)
+ {
+ m_xEditEntry = m_xTreeView->make_iterator(&rIter);
+ nEditEvent = Application::PostUserEvent(LINK(this, NavigatorTree, OnEdit));
+ }
+
+ return bRes;
+ }
+
+ IMPL_LINK_NOARG(NavigatorTree, OnEdit, void*, void)
+ {
+ nEditEvent = nullptr;
+ m_xTreeView->start_editing(*m_xEditEntry);
+ m_bEditing = true;
+ m_xEditEntry.reset();
+ }
+
+ IMPL_LINK_NOARG(NavigatorTree, OnEntrySelDesel, weld::TreeView&, void)
+ {
+ m_sdiState = SDI_DIRTY;
+
+ if (IsSelectionHandlingLocked())
+ return;
+
+ if (m_aSynchronizeTimer.IsActive())
+ m_aSynchronizeTimer.Stop();
+
+ m_aSynchronizeTimer.SetTimeout(EXPLORER_SYNC_DELAY);
+ m_aSynchronizeTimer.Start();
+ }
+
+ IMPL_LINK_NOARG(NavigatorTree, OnSynchronizeTimer, Timer *, void)
+ {
+ SynchronizeMarkList();
+ }
+
+ IMPL_LINK_NOARG(NavigatorTree, OnClipboardAction, OLocalExchange&, void)
+ {
+ if ( m_aControlExchange.isClipboardOwner() )
+ return;
+
+ if ( !doingKeyboardCut() )
+ return;
+
+ for (const auto& rEntry : m_aCutEntries)
+ {
+ if (!rEntry)
+ continue;
+ m_xTreeView->set_sensitive(*rEntry, true);
+ }
+ ListBoxEntrySet().swap(m_aCutEntries);
+
+ m_bKeyboardCut = false;
+ }
+
+ void NavigatorTree::ShowSelectionProperties(bool bForce)
+ {
+ // at first i need the FormShell
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ if (!pFormShell)
+ // no shell -> impossible to set curObject -> leave
+ return;
+
+ CollectSelectionData(SDI_ALL);
+ SAL_WARN_IF(static_cast<size_t>(m_nFormsSelected + m_nControlsSelected
+ + (m_bRootSelected ? 1 : 0)) != m_arrCurrentSelection.size(),
+ "svx.form",
+ "NavigatorTree::ShowSelectionProperties : selection meta data invalid !");
+
+
+ InterfaceBag aSelection;
+ bool bSetSelectionAsMarkList = false;
+
+ if (m_bRootSelected)
+ ; // no properties for the root, neither for single nor for multi selection
+ else if ( m_nFormsSelected + m_nControlsSelected == 0 ) // none of the two should be less 0
+ ; // no selection -> no properties
+ else if ( m_nFormsSelected * m_nControlsSelected != 0 )
+ ; // mixed selection -> no properties
+ else
+ { // either only forms, or only controls are selected
+ if (m_arrCurrentSelection.size() == 1)
+ {
+ const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
+ if (m_nFormsSelected > 0)
+ { // exactly one form is selected
+ FmFormData* pFormData = weld::fromId<FmFormData*>(m_xTreeView->get_id(*rIter));
+ aSelection.insert( Reference< XInterface >( pFormData->GetFormIface(), UNO_QUERY ) );
+ }
+ else
+ { // exactly one control is selected (whatever hidden or normal)
+ FmEntryData* pEntryData = weld::fromId<FmEntryData*>(m_xTreeView->get_id(*rIter));
+
+ aSelection.insert( Reference< XInterface >( pEntryData->GetElement(), UNO_QUERY ) );
+ }
+ }
+ else
+ { // it's a MultiSelection, so we must build a MultiSet
+ if (m_nFormsSelected > 0)
+ { // ... only forms
+ // first of all collect PropertySet-Interfaces of the forms
+ SvLBoxEntrySortedArray::const_iterator it = m_arrCurrentSelection.begin();
+ for ( sal_Int32 i = 0; i < m_nFormsSelected; ++i )
+ {
+ const std::unique_ptr<weld::TreeIter>& rIter = *it;
+ FmFormData* pFormData = weld::fromId<FmFormData*>(m_xTreeView->get_id(*rIter));
+ aSelection.insert( pFormData->GetPropertySet() );
+ ++it;
+ }
+ }
+ else
+ { // ... only controls
+ if (m_nHiddenControls == m_nControlsSelected)
+ { // a MultiSet for properties of hidden controls
+ SvLBoxEntrySortedArray::const_iterator it = m_arrCurrentSelection.begin();
+ for ( sal_Int32 i = 0; i < m_nHiddenControls; ++i )
+ {
+ const std::unique_ptr<weld::TreeIter>& rIter = *it;
+ FmEntryData* pEntryData = weld::fromId<FmEntryData*>(m_xTreeView->get_id(*rIter));
+ aSelection.insert( pEntryData->GetPropertySet() );
+ ++it;
+ }
+ }
+ else if (m_nHiddenControls == 0)
+ { // only normal controls
+ bSetSelectionAsMarkList = true;
+ }
+ }
+ }
+
+ }
+
+ // and now my form and my SelObject
+ if ( bSetSelectionAsMarkList )
+ pFormShell->GetImpl()->setCurrentSelectionFromMark_Lock(pFormShell->GetFormView()->GetMarkedObjectList());
+ else
+ pFormShell->GetImpl()->setCurrentSelection_Lock(std::move(aSelection));
+
+ if (pFormShell->GetImpl()->IsPropBrwOpen_Lock() || bForce)
+ {
+ // and now deliver all to the PropertyBrowser
+ pFormShell->GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SfxCallMode::ASYNCHRON );
+ }
+ }
+
+
+ void NavigatorTree::DeleteSelection()
+ {
+ // of course, i can't delete root
+ bool bRootSelected = m_xTreeView->is_selected(*m_xRootEntry);
+ auto nSelectedEntries = m_xTreeView->count_selected_rows();
+ if (bRootSelected && (nSelectedEntries > 1)) // root and other elements ?
+ m_xTreeView->unselect(*m_xRootEntry); // yes -> remove root from selection
+
+ if ((nSelectedEntries == 0) || bRootSelected) // still root ?
+ return; // -> only selected element -> leave
+
+ DBG_ASSERT(!m_bPrevSelectionMixed, "NavigatorTree::DeleteSelection() : delete permitted if mark and selection are inconsistent");
+
+ // i need the FormModel later
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ if (!pFormShell)
+ return;
+ FmFormModel* pFormModel = pFormShell->GetFormModel();
+ if (!pFormModel)
+ return;
+
+ // now I have to safeguard the DeleteList: if you delete a form and a dependent element
+ // - in this order - than the SvLBoxEntryPtr of the dependent element is already invalid,
+ // when it should be deleted... you have to prohibit this GPF, that of course would happen,
+ // so I take the 'normalized' list
+ CollectSelectionData( SDI_NORMALIZED );
+
+ // see below for why we need this mapping from models to shapes
+ FmFormView* pFormView = pFormShell->GetFormView();
+ SdrPageView* pPageView = pFormView ? pFormView->GetSdrPageView() : nullptr;
+ SdrPage* pPage = pPageView ? pPageView->GetPage() : nullptr;
+ DBG_ASSERT( pPage, "NavigatorTree::DeleteSelection: invalid form page!" );
+
+ MapModelToShape aModelShapes;
+ if ( pPage )
+ collectShapeModelMapping( pPage, aModelShapes );
+
+ // problem: we have to use ExplorerModel::Remove, since only this one properly deletes Form objects.
+ // But, the controls themself must be deleted via DeleteMarked (else, the Writer has some problems
+ // somewhere). In case I'd first delete the structure, then the controls, the UNDO would not work
+ // (since UNDO then would mean to first restore the controls, then the structure, means their parent
+ // form). The other way round, the EntryDatas would be invalid, if I'd first delete the controls and
+ // then go on to the structure. This means I have to delete the forms *after* the normal controls, so
+ // that during UNDO, they're restored in the proper order.
+ pFormShell->GetImpl()->EnableTrackProperties_Lock(false);
+ for (SvLBoxEntrySortedArray::reverse_iterator it = m_arrCurrentSelection.rbegin();
+ it != m_arrCurrentSelection.rend(); )
+ {
+ const std::unique_ptr<weld::TreeIter>& rIter = *it;
+ FmEntryData* pCurrent = weld::fromId<FmEntryData*>(m_xTreeView->get_id(*rIter));
+
+ // a form ?
+ auto pFormData = dynamic_cast<FmFormData*>(pCurrent);
+
+ // because deletion is done by the view, and i build on its MarkList,
+ // but normally only direct controls, no indirect ones, are marked in a marked form,
+ // I have to do it later
+ if (pFormData)
+ MarkViewObj(pFormData, true/*deep*/);
+
+ // a hidden control ?
+ bool bIsHidden = IsHiddenControl(pCurrent);
+
+ // keep forms and hidden controls, the rest not
+ if (!pFormData && !bIsHidden)
+ {
+ // well, no form and no hidden control -> we can remove it from m_arrCurrentSelection, as it will
+ // be deleted automatically. This is because for every model (except forms and hidden control models)
+ // there exist a shape, which is marked _if_and_only_if_ the model is selected in our tree.
+ if ( aModelShapes.find( pCurrent->GetElement() ) != aModelShapes.end() )
+ {
+ // if there's a shape for the current entry, then either it is marked or it is in a
+ // hidden layer (#i28502#), or something like this.
+ // In the first case, it will be deleted below, in the second case, we currently don't
+ // delete it, as there's no real (working!) API for this, neither in UNO nor in non-UNO.
+ m_arrCurrentSelection.erase( --(it.base()) );
+ }
+ else
+ ++it;
+ // In case there is no shape for the current entry, we keep the entry in m_arrCurrentSelection,
+ // since then we can definitely remove it.
+ }
+ else
+ ++it;
+ }
+ pFormShell->GetImpl()->EnableTrackProperties_Lock(true);
+
+ // let the view delete the marked controls
+ pFormShell->GetFormView()->DeleteMarked();
+
+ // start UNDO at this point. Unfortunately, this results in 2 UNDO actions, since DeleteMarked is
+ // creating an own one. However, if we'd move it before DeleteMarked, Writer does not really like
+ // this ... :(
+ // #i31038#
+ {
+
+ // initialize UNDO
+ OUString aUndoStr;
+ if ( m_arrCurrentSelection.size() == 1 )
+ {
+ aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_REMOVE);
+ if (m_nFormsSelected)
+ aUndoStr = aUndoStr.replaceFirst( "#", SvxResId( RID_STR_FORM ) );
+ else
+ // it must be a control (else the root would be selected, but it cannot be deleted)
+ aUndoStr = aUndoStr.replaceFirst( "#", SvxResId( RID_STR_CONTROL ) );
+ }
+ else
+ {
+ aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_REMOVE_MULTIPLE);
+ aUndoStr = aUndoStr.replaceFirst( "#", OUString::number( m_arrCurrentSelection.size() ) );
+ }
+ pFormModel->BegUndo(aUndoStr);
+ }
+
+ // remove remaining structure
+ for (const auto& rpSelection : m_arrCurrentSelection)
+ {
+ FmEntryData* pCurrent = weld::fromId<FmEntryData*>(m_xTreeView->get_id(*rpSelection));
+
+ // if the entry still has children, we skipped deletion of one of those children.
+ // This may for instance be because the shape is in a hidden layer, where we're unable
+ // to remove it
+ if ( pCurrent->GetChildList()->size() )
+ continue;
+
+ // one remaining subtile problem, before deleting it : if it's a form and the shell
+ // knows it as CurrentObject, I have to tell it something else
+ if (auto pFormData = dynamic_cast<FmFormData*>( pCurrent))
+ {
+ Reference< XForm > xCurrentForm( pFormData->GetFormIface() );
+ if (pFormShell->GetImpl()->getCurrentForm_Lock() == xCurrentForm) // shell knows form to be deleted ?
+ pFormShell->GetImpl()->forgetCurrentForm_Lock(); // -> take away ...
+ }
+ GetNavModel()->Remove(pCurrent, true);
+ }
+ pFormModel->EndUndo();
+ }
+
+
+ void NavigatorTree::CollectSelectionData(SELDATA_ITEMS sdiHow)
+ {
+ DBG_ASSERT(sdiHow != SDI_DIRTY, "NavigatorTree::CollectSelectionData : ever thought about your parameter ? DIRTY ?");
+ if (sdiHow == m_sdiState)
+ return;
+
+ m_arrCurrentSelection.clear();
+ m_nFormsSelected = m_nControlsSelected = m_nHiddenControls = 0;
+ m_bRootSelected = false;
+
+ m_xTreeView->selected_foreach([this, sdiHow](weld::TreeIter& rSelectionLoop){
+ // count different elements
+ if (m_xTreeView->iter_compare(rSelectionLoop, *m_xRootEntry) == 0)
+ m_bRootSelected = true;
+ else
+ {
+ if (IsFormEntry(rSelectionLoop))
+ ++m_nFormsSelected;
+ else
+ {
+ ++m_nControlsSelected;
+ if (IsHiddenControl(weld::fromId<FmEntryData*>(m_xTreeView->get_id(rSelectionLoop))))
+ ++m_nHiddenControls;
+ }
+ }
+
+ if (sdiHow == SDI_NORMALIZED)
+ {
+ // don't take something with a selected ancestor
+ if (m_xTreeView->iter_compare(rSelectionLoop, *m_xRootEntry) == 0)
+ m_arrCurrentSelection.emplace(m_xTreeView->make_iterator(&rSelectionLoop));
+ else
+ {
+ std::unique_ptr<weld::TreeIter> xParentLoop(m_xTreeView->make_iterator(&rSelectionLoop));
+ bool bParentLoop = m_xTreeView->iter_parent(*xParentLoop);
+ while (bParentLoop)
+ {
+ // actually i would have to test, if parent is part of m_arr_CurrentSelection ...
+ // but if it's selected, then it's in m_arrCurrentSelection
+ // or one of its ancestors, which was selected earlier.
+ // In both cases IsSelected is enough
+ if (m_xTreeView->is_selected(*xParentLoop))
+ break;
+ else
+ {
+ if (m_xTreeView->iter_compare(*xParentLoop, *m_xRootEntry) == 0)
+ {
+ // until root (exclusive), there was no selected parent -> entry belongs to normalized list
+ m_arrCurrentSelection.emplace(m_xTreeView->make_iterator(&rSelectionLoop));
+ break;
+ }
+ else
+ bParentLoop = m_xTreeView->iter_parent(*xParentLoop);
+ }
+ }
+ }
+ }
+ else if (sdiHow == SDI_NORMALIZED_FORMARK)
+ {
+ std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rSelectionLoop));
+ bool bParent = m_xTreeView->iter_parent(*xParent);
+ if (!bParent || !m_xTreeView->is_selected(*xParent) || IsFormEntry(rSelectionLoop))
+ m_arrCurrentSelection.emplace(m_xTreeView->make_iterator(&rSelectionLoop));
+ }
+ else
+ m_arrCurrentSelection.emplace(m_xTreeView->make_iterator(&rSelectionLoop));
+
+ return false;
+ });
+
+ m_sdiState = sdiHow;
+ }
+
+ void NavigatorTree::SynchronizeSelection(FmEntryDataArray& arredToSelect)
+ {
+ LockSelectionHandling();
+ if (arredToSelect.empty())
+ {
+ m_xTreeView->unselect_all();
+ }
+ else
+ {
+ // compare current selection with requested SelectList
+ m_xTreeView->selected_foreach([this, &arredToSelect](weld::TreeIter& rSelection) {
+ FmEntryData* pCurrent = weld::fromId<FmEntryData*>(m_xTreeView->get_id(rSelection));
+ if (pCurrent != nullptr)
+ {
+ FmEntryDataArray::iterator it = arredToSelect.find(pCurrent);
+ if ( it != arredToSelect.end() )
+ { // entry already selected, but also in SelectList
+ // remove it from there
+ arredToSelect.erase(it);
+ } else
+ { // entry selected, but not in SelectList -> remove selection
+ m_xTreeView->unselect(rSelection);
+ // make it visible (maybe it's the only modification i do in this handler
+ // so you should see it
+ m_xTreeView->scroll_to_row(rSelection);
+ }
+ }
+ else
+ m_xTreeView->unselect(rSelection);
+
+ return false;
+ });
+
+ // now SelectList contains only entries, which have to be selected
+ // two possibilities : 1) run through SelectList, get SvTreeListEntry for every entry and select it (is more intuitive)
+ // 2) run through my SvLBoxEntries and select those, i can find in the SelectList
+ // 1) needs =(k*n) (k=length of SelectList, n=number of entries),
+ // plus the fact, that FindEntry uses extensive IsEqualWithoutChilden instead of comparing pointer to UserData
+ // 2) needs =(n*log k), duplicates some code from FindEntry
+ // This may be a frequently used code ( at every change in mark of the view!),
+ // so i use latter one
+ m_xTreeView->all_foreach([this, &arredToSelect](weld::TreeIter& rLoop){
+ FmEntryData* pCurEntryData = weld::fromId<FmEntryData*>(m_xTreeView->get_id(rLoop));
+ FmEntryDataArray::iterator it = arredToSelect.find(pCurEntryData);
+ if (it != arredToSelect.end())
+ {
+ m_xTreeView->select(rLoop);
+ m_xTreeView->scroll_to_row(rLoop);
+ }
+
+ return false;
+ });
+ }
+ UnlockSelectionHandling();
+ }
+
+
+ void NavigatorTree::SynchronizeSelection()
+ {
+ // shell and view
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ if(!pFormShell) return;
+
+ FmFormView* pFormView = pFormShell->GetFormView();
+ if (!pFormView) return;
+
+ GetNavModel()->BroadcastMarkedObjects(pFormView->GetMarkedObjectList());
+ }
+
+
+ void NavigatorTree::SynchronizeMarkList()
+ {
+ // i'll need this shell
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ if (!pFormShell) return;
+
+ CollectSelectionData(SDI_NORMALIZED_FORMARK);
+
+ // the view shouldn't notify now if MarkList changed
+ pFormShell->GetImpl()->EnableTrackProperties_Lock(false);
+
+ UnmarkAllViewObj();
+
+ for (auto& rSelectionLoop : m_arrCurrentSelection)
+ {
+ // When form selection, mark all controls of form
+ if (IsFormEntry(*rSelectionLoop) && m_xTreeView->iter_compare(*rSelectionLoop, *m_xRootEntry) != 0)
+ MarkViewObj(weld::fromId<FmFormData*>(m_xTreeView->get_id(*rSelectionLoop)), false/*deep*/);
+
+ // When control selection, mark Control-SdrObjects
+ else if (IsFormComponentEntry(*rSelectionLoop))
+ {
+ FmControlData* pControlData = weld::fromId<FmControlData*>(m_xTreeView->get_id(*rSelectionLoop));
+ if (pControlData)
+ {
+
+ // When HiddenControl no object can be selected
+ Reference< XFormComponent > xFormComponent( pControlData->GetFormComponent());
+ if (!xFormComponent.is())
+ continue;
+ Reference< XPropertySet > xSet(xFormComponent, UNO_QUERY);
+ if (!xSet.is())
+ continue;
+
+ sal_uInt16 nClassId = ::comphelper::getINT16(xSet->getPropertyValue(FM_PROP_CLASSID));
+ if (nClassId != FormComponentType::HIDDENCONTROL)
+ MarkViewObj(pControlData);
+ }
+ }
+ }
+
+ // if PropertyBrowser is open, I have to adopt it according to my selection
+ // (Not as MarkList of view : if a form is selected, all belonging controls are selected in the view
+ // but of course i want to see the form-properties
+ ShowSelectionProperties();
+
+ // reset flag at view
+ pFormShell->GetImpl()->EnableTrackProperties_Lock(true);
+
+ // if exactly one form is selected now, shell should notice it as CurrentForm
+ // (if selection handling isn't locked, view cares about it in MarkListHasChanged
+ // but mechanism doesn't work, if form is empty for example
+ if ((m_arrCurrentSelection.size() != 1) || (m_nFormsSelected != 1))
+ return;
+
+ std::unique_ptr<weld::TreeIter> xSelected(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_selected(xSelected.get()))
+ xSelected.reset();
+ FmFormData* pSingleSelectionData = xSelected ? dynamic_cast<FmFormData*>(weld::fromId<FmEntryData*>(m_xTreeView->get_id(*xSelected)))
+ : nullptr;
+ DBG_ASSERT( pSingleSelectionData, "NavigatorTree::SynchronizeMarkList: invalid selected form!" );
+ if ( pSingleSelectionData )
+ {
+ InterfaceBag aSelection;
+ aSelection.insert( Reference< XInterface >( pSingleSelectionData->GetFormIface(), UNO_QUERY ) );
+ pFormShell->GetImpl()->setCurrentSelection_Lock(std::move(aSelection));
+ }
+ }
+
+ bool NavigatorTree::IsHiddenControl(FmEntryData const * pEntryData)
+ {
+ if (pEntryData == nullptr) return false;
+
+ Reference< XPropertySet > xProperties( pEntryData->GetPropertySet() );
+ if (::comphelper::hasProperty(FM_PROP_CLASSID, xProperties))
+ {
+ Any aClassID = xProperties->getPropertyValue( FM_PROP_CLASSID );
+ return (::comphelper::getINT16(aClassID) == FormComponentType::HIDDENCONTROL);
+ }
+ return false;
+ }
+
+ void NavigatorTree::UnmarkAllViewObj()
+ {
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ if( !pFormShell )
+ return;
+ FmFormView* pFormView = pFormShell->GetFormView();
+ pFormView->UnMarkAll();
+ }
+
+ void NavigatorTree::MarkViewObj(FmFormData const * pFormData, bool bDeep )
+ {
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ if( !pFormShell )
+ return;
+
+ // first collect all sdrobjects
+ ::std::set< Reference< XFormComponent > > aObjects;
+ CollectObjects(pFormData,bDeep,aObjects);
+
+
+ // find and select appropriate SdrObj in page
+ FmFormView* pFormView = pFormShell->GetFormView();
+ SdrPageView* pPageView = pFormView->GetSdrPageView();
+ SdrPage* pPage = pPageView->GetPage();
+ //FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( pPage );
+
+ SdrObjListIter aIter( pPage );
+ while ( aIter.IsMore() )
+ {
+ SdrObject* pSdrObject = aIter.Next();
+ FmFormObj* pFormObject = FmFormObj::GetFormObject( pSdrObject );
+ if ( !pFormObject )
+ continue;
+
+ Reference< XFormComponent > xControlModel( pFormObject->GetUnoControlModel(),UNO_QUERY );
+ if ( xControlModel.is() && aObjects.find(xControlModel) != aObjects.end() && !pFormView->IsObjMarked( pSdrObject ) )
+ {
+ // unfortunately, the writer doesn't like marking an already-marked object, again, so reset the mark first
+ pFormView->MarkObj( pSdrObject, pPageView );
+ }
+ } // while ( aIter.IsMore() )
+ // make the mark visible
+ ::tools::Rectangle aMarkRect( pFormView->GetAllMarkedRect());
+ for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i )
+ {
+ SdrPaintWindow* pPaintWindow = pFormView->GetPaintWindow( i );
+ OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
+ if ( ( OUTDEV_WINDOW == rOutDev.GetOutDevType() ) && !aMarkRect.IsEmpty() )
+ {
+ pFormView->MakeVisible( aMarkRect, *rOutDev.GetOwnerWindow() );
+ }
+ } // for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i )
+ }
+
+ void NavigatorTree::CollectObjects(FmFormData const * pFormData, bool bDeep, ::std::set< Reference< XFormComponent > >& _rObjects)
+ {
+ FmEntryDataList* pChildList = pFormData->GetChildList();
+ for( size_t i = 0; i < pChildList->size(); ++i )
+ {
+ FmEntryData* pEntryData = pChildList->at( i );
+ if( auto pControlData = dynamic_cast<FmControlData*>( pEntryData) )
+ {
+ _rObjects.insert(pControlData->GetFormComponent());
+ } // if( dynamic_cast<const FmControlData*>( pEntryData) != nullptr )
+ else if (bDeep)
+ if (auto pEntryFormData = dynamic_cast<FmFormData*>( pEntryData))
+ CollectObjects(pEntryFormData, bDeep, _rObjects);
+ } // for( sal_uInt32 i=0; i<pChildList->Count(); i++ )
+ }
+
+ void NavigatorTree::MarkViewObj( FmControlData const * pControlData)
+ {
+ if( !pControlData )
+ return;
+ FmFormShell* pFormShell = GetNavModel()->GetFormShell();
+ if( !pFormShell )
+ return;
+
+
+ // find and select appropriate SdrObj
+ FmFormView* pFormView = pFormShell->GetFormView();
+ Reference< XFormComponent > xFormComponent( pControlData->GetFormComponent());
+ SdrPageView* pPageView = pFormView->GetSdrPageView();
+ SdrPage* pPage = pPageView->GetPage();
+
+ bool bPaint = false;
+ SdrObjListIter aIter( pPage );
+ while ( aIter.IsMore() )
+ {
+ SdrObject* pSdrObject = aIter.Next();
+ FmFormObj* pFormObject = FmFormObj::GetFormObject( pSdrObject );
+ if ( !pFormObject )
+ continue;
+
+ Reference< XInterface > xControlModel( pFormObject->GetUnoControlModel() );
+ if ( xControlModel != xFormComponent )
+ continue;
+
+ // mark the object
+ if ( !pFormView->IsObjMarked( pSdrObject ) )
+ // unfortunately, the writer doesn't like marking an already-marked object, again, so reset the mark first
+ pFormView->MarkObj( pSdrObject, pPageView );
+
+ bPaint = true;
+
+ } // while ( aIter.IsMore() )
+ if ( !bPaint )
+ return;
+
+ // make the mark visible
+ ::tools::Rectangle aMarkRect( pFormView->GetAllMarkedRect());
+ for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i )
+ {
+ SdrPaintWindow* pPaintWindow = pFormView->GetPaintWindow( i );
+ OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
+ if ( OUTDEV_WINDOW == rOutDev.GetOutDevType() )
+ {
+ pFormView->MakeVisible( aMarkRect, *rOutDev.GetOwnerWindow() );
+ }
+ } // for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i )
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/navigatortreemodel.cxx b/svx/source/form/navigatortreemodel.cxx
new file mode 100644
index 000000000..218e2ba4a
--- /dev/null
+++ b/svx/source/form/navigatortreemodel.cxx
@@ -0,0 +1,907 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdogrp.hxx>
+
+#include <fmprop.hxx>
+
+#include <fmundo.hxx>
+#include <fmexpl.hxx>
+#include <svx/strings.hrc>
+#include <fmshimp.hxx>
+#include <fmobj.hxx>
+#include <o3tl/safeint.hxx>
+#include <sfx2/objsh.hxx>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/container/XContainer.hpp>
+#include <comphelper/types.hxx>
+
+
+namespace svxform
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::script;
+ using namespace ::com::sun::star::sdb;
+
+ OFormComponentObserver::OFormComponentObserver(NavigatorTreeModel* _pModel)
+ :m_pNavModel(_pModel)
+ ,m_nLocks(0)
+ ,m_bCanUndo(true)
+ {
+ }
+
+ // XPropertyChangeListener
+
+ void SAL_CALL OFormComponentObserver::disposing(const EventObject& Source)
+ {
+ Remove( Source.Source );
+ }
+
+
+ void SAL_CALL OFormComponentObserver::propertyChange(const PropertyChangeEvent& evt)
+ {
+ if( !m_pNavModel ) return;
+ if( evt.PropertyName != FM_PROP_NAME ) return;
+
+ Reference< XFormComponent > xFormComponent(evt.Source, UNO_QUERY);
+ Reference< XForm > xForm(evt.Source, UNO_QUERY);
+
+ FmEntryData* pEntryData( nullptr );
+ if( xForm.is() )
+ pEntryData = m_pNavModel->FindData( xForm, m_pNavModel->GetRootList() );
+ else if( xFormComponent.is() )
+ pEntryData = m_pNavModel->FindData( xFormComponent, m_pNavModel->GetRootList() );
+
+ if( pEntryData )
+ {
+ OUString aNewName = ::comphelper::getString(evt.NewValue);
+ pEntryData->SetText( aNewName );
+ FmNavNameChangedHint aNameChangedHint( pEntryData, aNewName );
+ m_pNavModel->Broadcast( aNameChangedHint );
+ }
+ }
+
+ // XContainerListener
+
+ void SAL_CALL OFormComponentObserver::elementInserted(const ContainerEvent& evt)
+ {
+ if (IsLocked() || !m_pNavModel)
+ return;
+
+ // insert no Undoaction
+ m_bCanUndo = false;
+
+ Reference< XInterface > xTemp;
+ evt.Element >>= xTemp;
+ Insert(xTemp, ::comphelper::getINT32(evt.Accessor));
+
+ m_bCanUndo = true;
+ }
+
+
+ void OFormComponentObserver::Insert(const Reference< XInterface > & xIface, sal_Int32 nIndex)
+ {
+ Reference< XForm > xForm(xIface, UNO_QUERY);
+ if (xForm.is())
+ {
+ m_pNavModel->InsertForm(xForm, sal_uInt32(nIndex));
+ Reference< XIndexContainer > xContainer(xForm, UNO_QUERY);
+ Reference< XInterface > xTemp;
+ for (sal_Int32 i = 0; i < xContainer->getCount(); i++)
+ {
+ xContainer->getByIndex(i) >>= xTemp;
+ Insert(xTemp, i);
+ }
+ }
+ else
+ {
+ Reference< XFormComponent > xFormComp(xIface, UNO_QUERY);
+ if (xFormComp.is())
+ m_pNavModel->InsertFormComponent(xFormComp, sal_uInt32(nIndex));
+ }
+ }
+
+
+ void SAL_CALL OFormComponentObserver::elementReplaced(const ContainerEvent& evt)
+ {
+ if (IsLocked() || !m_pNavModel)
+ return;
+
+ m_bCanUndo = false;
+
+ // delete EntryData
+ Reference< XFormComponent > xReplaced;
+ evt.ReplacedElement >>= xReplaced;
+ FmEntryData* pEntryData = m_pNavModel->FindData(xReplaced, m_pNavModel->GetRootList());
+ if (pEntryData)
+ {
+ if (dynamic_cast<const FmControlData*>( pEntryData) != nullptr)
+ {
+ Reference< XFormComponent > xComp;
+ evt.Element >>= xComp;
+ DBG_ASSERT(xComp.is(), "OFormComponentObserver::elementReplaced : invalid argument !");
+ // FmControlData should be coupled with XFormComponent
+ m_pNavModel->ReplaceFormComponent(xReplaced, xComp);
+ }
+ else if (dynamic_cast<const FmFormData*>( pEntryData) != nullptr)
+ {
+ OSL_FAIL("replacing forms not implemented yet !");
+ }
+ }
+
+ m_bCanUndo = true;
+ }
+
+
+ void OFormComponentObserver::Remove( const css::uno::Reference< css::uno::XInterface >& _rxElement )
+ {
+ if (IsLocked() || !m_pNavModel)
+ return;
+
+ m_bCanUndo = false;
+
+
+ // delete EntryData
+ FmEntryData* pEntryData = m_pNavModel->FindData( _rxElement, m_pNavModel->GetRootList() );
+ if (pEntryData)
+ m_pNavModel->Remove(pEntryData);
+
+ m_bCanUndo = true;
+ }
+
+
+ void SAL_CALL OFormComponentObserver::elementRemoved(const ContainerEvent& evt)
+ {
+ Reference< XInterface > xElement;
+ evt.Element >>= xElement;
+ Remove( xElement );
+ }
+
+ NavigatorTreeModel::NavigatorTreeModel()
+ :m_pFormShell(nullptr)
+ ,m_pFormPage(nullptr)
+ ,m_pFormModel(nullptr)
+ {
+ m_pPropChangeList = new OFormComponentObserver(this);
+ m_pRootList.reset( new FmEntryDataList() );
+ }
+
+ NavigatorTreeModel::~NavigatorTreeModel()
+ {
+
+ // unregister Listener
+ if( m_pFormShell)
+ {
+ FmFormModel* pFormModel = m_pFormShell->GetFormModel();
+ if( pFormModel && IsListening(*pFormModel))
+ EndListening( *pFormModel );
+
+ if (IsListening(*m_pFormShell))
+ EndListening(*m_pFormShell);
+ }
+
+ Clear();
+ m_pRootList.reset();
+ m_pPropChangeList->ReleaseModel();
+ }
+
+
+ void NavigatorTreeModel::SetModified()
+ {
+ if( !m_pFormShell ) return;
+ SfxObjectShell* pObjShell = m_pFormShell->GetFormModel()->GetObjectShell();
+ if( !pObjShell ) return;
+ pObjShell->SetModified();
+ }
+
+
+ void NavigatorTreeModel::Clear()
+ {
+ Reference< css::form::XForms > xForms( GetForms());
+ if(xForms.is())
+ xForms->removeContainerListener(m_pPropChangeList);
+
+
+ // delete RootList
+ GetRootList()->clear();
+
+
+ // notify UI
+ FmNavClearedHint aClearedHint;
+ Broadcast( aClearedHint );
+ }
+
+
+ Reference< css::form::XForms > NavigatorTreeModel::GetForms() const
+ {
+ if( !m_pFormShell || !m_pFormShell->GetCurPage())
+ return nullptr;
+ else
+ return m_pFormShell->GetCurPage()->GetForms();
+ }
+
+
+ void NavigatorTreeModel::Insert(FmEntryData* pEntry, sal_uInt32 nRelPos, bool bAlterModel)
+ {
+ if (IsListening(*m_pFormModel))
+ EndListening(*m_pFormModel);
+
+ m_pPropChangeList->Lock();
+ FmFormData* pFolder = static_cast<FmFormData*>( pEntry->GetParent() );
+ Reference< XChild > xElement( pEntry->GetChildIFace() );
+ if (bAlterModel)
+ {
+ OUString aStr;
+ if (dynamic_cast<const FmFormData*>( pEntry) != nullptr)
+ aStr = SvxResId(RID_STR_FORM);
+ else
+ aStr = SvxResId(RID_STR_CONTROL);
+
+ Reference< XIndexContainer > xContainer;
+ if (pFolder)
+ xContainer.set(pFolder->GetFormIface(), UNO_QUERY);
+ else
+ xContainer = GetForms();
+
+ bool bUndo = m_pFormModel->IsUndoEnabled();
+
+ if( bUndo )
+ {
+ OUString aUndoStr(SvxResId(RID_STR_UNDO_CONTAINER_INSERT));
+ aUndoStr = aUndoStr.replaceFirst("#", aStr);
+ m_pFormModel->BegUndo(aUndoStr);
+ }
+
+ if (nRelPos >= o3tl::make_unsigned(xContainer->getCount()))
+ nRelPos = static_cast<sal_uInt32>(xContainer->getCount());
+
+ // UndoAction
+ if ( bUndo && m_pPropChangeList->CanUndo())
+ {
+ m_pFormModel->AddUndo(std::make_unique<FmUndoContainerAction>(*m_pFormModel,
+ FmUndoContainerAction::Inserted,
+ xContainer,
+ xElement,
+ nRelPos));
+ }
+
+ // Element has to be of the expected type by the container
+ if (xContainer->getElementType() ==
+ cppu::UnoType<XForm>::get())
+
+ {
+ Reference< XForm > xElementAsForm(xElement, UNO_QUERY);
+ xContainer->insertByIndex(nRelPos, Any(xElementAsForm));
+ }
+ else if (xContainer->getElementType() ==
+ cppu::UnoType<XFormComponent>::get())
+
+ {
+ Reference< XFormComponent > xElementAsComponent(xElement, UNO_QUERY);
+ xContainer->insertByIndex(nRelPos, Any(xElementAsComponent));
+ }
+ else
+ {
+ OSL_FAIL("NavigatorTreeModel::Insert : the parent container needs an elementtype I don't know !");
+ }
+
+ if( bUndo )
+ m_pFormModel->EndUndo();
+ }
+
+ // register as PropertyChangeListener
+ Reference< XPropertySet > xSet(xElement, UNO_QUERY);
+ if( xSet.is() )
+ xSet->addPropertyChangeListener( FM_PROP_NAME, m_pPropChangeList );
+
+
+ // Remove data from model
+ if (dynamic_cast<const FmFormData*>( pEntry) != nullptr)
+ {
+ Reference< XContainer > xContainer(xElement, UNO_QUERY);
+ if (xContainer.is())
+ xContainer->addContainerListener(m_pPropChangeList);
+ }
+
+ if (pFolder)
+ pFolder->GetChildList()->insert( std::unique_ptr<FmEntryData>(pEntry), nRelPos );
+ else
+ GetRootList()->insert( std::unique_ptr<FmEntryData>(pEntry), nRelPos );
+
+
+ // notify UI
+ FmNavInsertedHint aInsertedHint( pEntry, nRelPos );
+ Broadcast( aInsertedHint );
+
+ m_pPropChangeList->UnLock();
+ if (IsListening(*m_pFormModel))
+ StartListening(*m_pFormModel);
+ }
+
+
+ void NavigatorTreeModel::Remove(FmEntryData* pEntry, bool bAlterModel)
+ {
+
+ // get form and parent
+ if (!pEntry || !m_pFormModel)
+ return;
+
+ if (IsListening(*m_pFormModel))
+ EndListening(*m_pFormModel);
+
+ const bool bUndo = m_pFormModel->IsUndoEnabled();
+
+ m_pPropChangeList->Lock();
+ FmFormData* pFolder = static_cast<FmFormData*>( pEntry->GetParent() );
+ Reference< XChild > xElement ( pEntry->GetChildIFace() );
+ if (bAlterModel)
+ {
+ OUString aStr;
+ if (dynamic_cast<const FmFormData*>( pEntry) != nullptr)
+ aStr = SvxResId(RID_STR_FORM);
+ else
+ aStr = SvxResId(RID_STR_CONTROL);
+
+ if( bUndo )
+ {
+ OUString aUndoStr(SvxResId(RID_STR_UNDO_CONTAINER_REMOVE));
+ aUndoStr = aUndoStr.replaceFirst("#", aStr);
+ m_pFormModel->BegUndo(aUndoStr);
+ }
+ }
+
+ // now real deletion of data form model
+ if (auto pFormData = dynamic_cast<FmFormData*>( pEntry))
+ RemoveForm(pFormData);
+ else
+ RemoveFormComponent(static_cast<FmControlData*>(pEntry));
+
+
+ if (bAlterModel)
+ {
+ Reference< XIndexContainer > xContainer(xElement->getParent(), UNO_QUERY);
+ // remove from Container
+ sal_Int32 nContainerIndex = getElementPos(xContainer, xElement);
+ // UndoAction
+ if (nContainerIndex >= 0)
+ {
+ if ( bUndo && m_pPropChangeList->CanUndo())
+ {
+ m_pFormModel->AddUndo(std::make_unique<FmUndoContainerAction>(*m_pFormModel,
+ FmUndoContainerAction::Removed,
+ xContainer,
+ xElement, nContainerIndex ));
+ }
+ else if( !m_pPropChangeList->CanUndo() )
+ {
+ FmUndoContainerAction::DisposeElement( xElement );
+ }
+
+ xContainer->removeByIndex(nContainerIndex );
+ }
+
+ if( bUndo )
+ m_pFormModel->EndUndo();
+ }
+
+ // remove from parent
+ if (pFolder)
+ pFolder->GetChildList()->removeNoDelete( pEntry );
+ else
+ {
+ GetRootList()->removeNoDelete( pEntry );
+
+ // If root has no more form, reset CurForm at shell
+ if ( !GetRootList()->size() )
+ m_pFormShell->GetImpl()->forgetCurrentForm_Lock();
+ }
+
+
+ // notify UI
+ FmNavRemovedHint aRemovedHint( pEntry );
+ Broadcast( aRemovedHint );
+
+ // delete entry
+ delete pEntry;
+
+ m_pPropChangeList->UnLock();
+ StartListening(*m_pFormModel);
+ }
+
+
+ void NavigatorTreeModel::RemoveForm(FmFormData const * pFormData)
+ {
+
+ // get form and parent
+ if (!pFormData || !m_pFormModel)
+ return;
+
+ FmEntryDataList* pChildList = pFormData->GetChildList();
+ for ( size_t i = pChildList->size(); i > 0; )
+ {
+ FmEntryData* pEntryData = pChildList->at( --i );
+
+
+ // Child is form -> recursive call
+ if( auto pChildFormData = dynamic_cast<FmFormData*>( pEntryData) )
+ RemoveForm(pChildFormData);
+ else if( auto pChildControlData = dynamic_cast<FmControlData*>( pEntryData) )
+ RemoveFormComponent(pChildControlData);
+ }
+
+
+ // unregister as PropertyChangeListener
+ Reference< XPropertySet > xSet( pFormData->GetPropertySet() );
+ if ( xSet.is() )
+ xSet->removePropertyChangeListener( FM_PROP_NAME, m_pPropChangeList );
+ }
+
+
+ void NavigatorTreeModel::RemoveFormComponent(FmControlData const * pControlData)
+ {
+
+ // get control and parent
+ if (!pControlData)
+ return;
+
+
+ // unregister as PropertyChangeListener
+ Reference< XPropertySet > xSet( pControlData->GetPropertySet() );
+ if (xSet.is())
+ xSet->removePropertyChangeListener( FM_PROP_NAME, m_pPropChangeList);
+ }
+
+
+ void NavigatorTreeModel::FillBranch( FmFormData* pFormData )
+ {
+
+ // insert forms from root
+ if( pFormData == nullptr )
+ {
+ Reference< XIndexContainer > xForms = GetForms();
+ if (!xForms.is())
+ return;
+
+ Reference< XForm > xSubForm;
+ for (sal_Int32 i=0; i<xForms->getCount(); ++i)
+ {
+ DBG_ASSERT( xForms->getByIndex(i).getValueType() == cppu::UnoType<XForm>::get(),
+ "NavigatorTreeModel::FillBranch : the root container should supply only elements of type XForm");
+
+ xForms->getByIndex(i) >>= xSubForm;
+ FmFormData* pSubFormData = new FmFormData(xSubForm, pFormData);
+ Insert( pSubFormData );
+
+ // new branch, if SubForm contains Subforms itself
+ FillBranch( pSubFormData );
+ }
+ }
+
+
+ // insert components
+ else
+ {
+ Reference< XIndexContainer > xComponents( GetFormComponents(pFormData));
+ if( !xComponents.is() ) return;
+
+ FmControlData* pNewControlData;
+ FmFormData* pSubFormData;
+
+ Reference< XFormComponent > xCurrentComponent;
+ for (sal_Int32 j=0; j<xComponents->getCount(); ++j)
+ {
+ xComponents->getByIndex(j) >>= xCurrentComponent;
+ Reference< XForm > xSubForm(xCurrentComponent, UNO_QUERY);
+
+ if (xSubForm.is())
+ { // actual component is a form
+ pSubFormData = new FmFormData(xSubForm, pFormData);
+ Insert(pSubFormData);
+
+
+ // new branch, if SubForm contains Subforms itself
+ FillBranch(pSubFormData);
+ }
+ else
+ {
+ pNewControlData = new FmControlData(xCurrentComponent, pFormData);
+ Insert(pNewControlData);
+ }
+ }
+ }
+ }
+
+
+ void NavigatorTreeModel::InsertForm(const Reference< XForm > & xForm, sal_uInt32 nRelPos)
+ {
+ FmFormData* pFormData = static_cast<FmFormData*>(FindData( xForm, GetRootList() ));
+ if (pFormData)
+ return;
+
+
+ // set ParentData
+ Reference< XInterface > xIFace( xForm->getParent());
+ Reference< XForm > xParentForm(xIFace, UNO_QUERY);
+ FmFormData* pParentData = nullptr;
+ if (xParentForm.is())
+ pParentData = static_cast<FmFormData*>(FindData( xParentForm, GetRootList() ));
+
+ pFormData = new FmFormData(xForm, pParentData);
+ Insert( pFormData, nRelPos );
+ }
+
+
+ void NavigatorTreeModel::InsertFormComponent(const Reference< XFormComponent > & xComp, sal_uInt32 nRelPos)
+ {
+
+ // set ParentData
+ Reference< XInterface > xIFace( xComp->getParent());
+ Reference< XForm > xForm(xIFace, UNO_QUERY);
+ if (!xForm.is())
+ return;
+
+ FmFormData* pParentData = static_cast<FmFormData*>(FindData( xForm, GetRootList() ));
+ if( !pParentData )
+ {
+ pParentData = new FmFormData(xForm, nullptr);
+ Insert( pParentData );
+ }
+
+ if (!FindData(xComp, pParentData->GetChildList(),false))
+ {
+
+ // set new EntryData
+ FmEntryData* pNewEntryData = new FmControlData(xComp, pParentData);
+
+
+ // insert new EntryData
+ Insert( pNewEntryData, nRelPos );
+ }
+ }
+
+ void NavigatorTreeModel::ReplaceFormComponent(
+ const Reference< XFormComponent > & xOld,
+ const Reference< XFormComponent > & xNew
+ )
+ {
+ FmEntryData* pData = FindData(xOld, GetRootList());
+ assert(dynamic_cast<const FmControlData*>( pData)); //NavigatorTreeModel::ReplaceFormComponent : invalid argument
+ auto pControlData = dynamic_cast<FmControlData*>( pData);
+ if (!pControlData)
+ return;
+ pControlData->ModelReplaced(xNew);
+
+ FmNavModelReplacedHint aReplacedHint( pData );
+ Broadcast( aReplacedHint );
+ }
+
+ FmEntryData* NavigatorTreeModel::FindData(const Reference< XInterface > & xElement, FmEntryDataList* pDataList, bool bRecurs)
+ {
+ // normalize
+ Reference< XInterface > xIFace( xElement, UNO_QUERY );
+
+ for ( size_t i = 0; i < pDataList->size(); i++ )
+ {
+ FmEntryData* pEntryData = pDataList->at( i );
+ if ( pEntryData->GetElement().get() == xIFace.get() )
+ return pEntryData;
+ else if (bRecurs)
+ {
+ pEntryData = FindData( xElement, pEntryData->GetChildList() );
+ if (pEntryData)
+ return pEntryData;
+ }
+ }
+ return nullptr;
+ }
+
+
+ FmEntryData* NavigatorTreeModel::FindData( const OUString& rText, FmFormData const * pParentData, bool bRecurs )
+ {
+ FmEntryDataList* pDataList;
+ if( !pParentData )
+ pDataList = GetRootList();
+ else
+ pDataList = pParentData->GetChildList();
+
+ OUString aEntryText;
+ FmEntryData* pEntryData;
+ FmEntryData* pChildData;
+
+ for( size_t i = 0; i < pDataList->size(); i++ )
+ {
+ pEntryData = pDataList->at( i );
+ aEntryText = pEntryData->GetText();
+
+ if (rText == aEntryText)
+ return pEntryData;
+
+ if (FmFormData* pFormData = bRecurs ? dynamic_cast<FmFormData*>(pEntryData) : nullptr)
+ {
+ pChildData = FindData(rText, pFormData, true);
+ if( pChildData )
+ return pChildData;
+ }
+ }
+
+ return nullptr;
+ }
+
+ void NavigatorTreeModel::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+ {
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ switch( pSdrHint->GetKind() )
+ {
+ case SdrHintKind::ObjectInserted:
+ InsertSdrObj(pSdrHint->GetObject());
+ break;
+ case SdrHintKind::ObjectRemoved:
+ RemoveSdrObj(pSdrHint->GetObject());
+ break;
+ default:
+ break;
+ }
+ }
+ // is shell gone?
+ else if (rHint.GetId() == SfxHintId::Dying)
+ {
+ UpdateContent(nullptr);
+ }
+ // changed mark of controls?
+ else if (const FmNavViewMarksChanged* pvmcHint = dynamic_cast<const FmNavViewMarksChanged*>(&rHint))
+ {
+ BroadcastMarkedObjects(pvmcHint->GetAffectedView()->GetMarkedObjectList());
+ }
+ }
+
+ void NavigatorTreeModel::InsertSdrObj( const SdrObject* pObj )
+ {
+ const FmFormObj* pFormObject = FmFormObj::GetFormObject( pObj );
+ if ( pFormObject )
+ {
+ try
+ {
+ Reference< XFormComponent > xFormComponent( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xContainer( xFormComponent->getParent(), UNO_QUERY_THROW );
+
+ sal_Int32 nPos = getElementPos( xContainer, xFormComponent );
+ InsertFormComponent( xFormComponent, nPos );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ else if ( pObj->IsGroupObject() )
+ {
+ SdrObjListIter aIter( pObj->GetSubList() );
+ while ( aIter.IsMore() )
+ InsertSdrObj( aIter.Next() );
+ }
+ }
+
+
+ void NavigatorTreeModel::RemoveSdrObj( const SdrObject* pObj )
+ {
+ const FmFormObj* pFormObject = FmFormObj::GetFormObject( pObj );
+ if ( pFormObject )
+ {
+ try
+ {
+ Reference< XFormComponent > xFormComponent( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
+ FmEntryData* pEntryData = FindData( xFormComponent, GetRootList() );
+ if ( pEntryData )
+ Remove( pEntryData );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ else if ( pObj->IsGroupObject() )
+ {
+ SdrObjListIter aIter( pObj->GetSubList() );
+ while ( aIter.IsMore() )
+ RemoveSdrObj( aIter.Next() );
+ }
+ }
+
+ bool NavigatorTreeModel::InsertFormComponent(FmNavRequestSelectHint& rHint, SdrObject* pObject)
+ {
+ if ( auto pObjGroup = dynamic_cast<const SdrObjGroup*>( pObject) )
+ { // descend recursively
+ const SdrObjList *pChildren = pObjGroup->GetSubList();
+ for ( size_t i=0; i<pChildren->GetObjCount(); ++i )
+ {
+ SdrObject* pCurrent = pChildren->GetObj(i);
+ if (!InsertFormComponent(rHint, pCurrent))
+ return false;
+ }
+ }
+ else
+ {
+ FmFormObj* pFormObject = FmFormObj::GetFormObject( pObject );
+ if ( !pFormObject )
+ return false;
+
+ try
+ {
+ Reference< XFormComponent > xFormViewControl( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
+ FmEntryData* pControlData = FindData( xFormViewControl, GetRootList() );
+ if ( !pControlData )
+ return false;
+
+ rHint.AddItem( pControlData );
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void NavigatorTreeModel::BroadcastMarkedObjects(const SdrMarkList& mlMarked)
+ {
+ // search all objects, which can be handled, out of marked objects
+ FmNavRequestSelectHint rshRequestSelection;
+ bool bIsMixedSelection = false;
+
+ for (size_t i=0; (i<mlMarked.GetMarkCount()) && !bIsMixedSelection; ++i)
+ {
+ SdrObject* pobjCurrent = mlMarked.GetMark(i)->GetMarkedSdrObj();
+ bIsMixedSelection |= !InsertFormComponent(rshRequestSelection, pobjCurrent);
+ // if Not-Form-Control, InsertFormComponent returns sal_False !
+ }
+
+ rshRequestSelection.SetMixedSelection(bIsMixedSelection);
+ if (bIsMixedSelection)
+ rshRequestSelection.ClearItems();
+
+ Broadcast(rshRequestSelection);
+ // an empty list causes NavigatorTree to remove his selection
+ }
+
+
+ void NavigatorTreeModel::UpdateContent( const Reference< css::form::XForms > & xForms )
+ {
+
+ // refill model form root upward
+ Clear();
+ if (!xForms.is())
+ return;
+
+ xForms->addContainerListener(m_pPropChangeList);
+
+ FillBranch(nullptr);
+
+ // select same control in tree as in view
+ // (or all of them), if there is one ...
+ if(!m_pFormShell) return; // no shell
+
+ FmFormView* pFormView = m_pFormShell->GetFormView();
+ DBG_ASSERT(pFormView != nullptr, "NavigatorTreeModel::UpdateContent : no FormView");
+ BroadcastMarkedObjects(pFormView->GetMarkedObjectList());
+ }
+
+
+ void NavigatorTreeModel::UpdateContent( FmFormShell* pShell )
+ {
+
+ // If shell is unchanged, do nothing
+ FmFormPage* pNewPage = pShell ? pShell->GetCurPage() : nullptr;
+ if ((pShell == m_pFormShell) && (m_pFormPage == pNewPage))
+ return;
+
+
+ // unregister as Listener
+ if( m_pFormShell )
+ {
+ if (m_pFormModel)
+ EndListening( *m_pFormModel );
+ m_pFormModel = nullptr;
+ EndListening( *m_pFormShell );
+ Clear();
+ }
+
+
+ // entire update
+ m_pFormShell = pShell;
+ if (m_pFormShell)
+ {
+ m_pFormPage = pNewPage;
+ UpdateContent(m_pFormPage->GetForms());
+ } else
+ m_pFormPage = nullptr;
+
+
+ // register as Listener again
+ if( m_pFormShell )
+ {
+ StartListening( *m_pFormShell );
+ m_pFormModel = m_pFormShell->GetFormModel();
+ if( m_pFormModel )
+ StartListening( *m_pFormModel );
+ }
+ }
+
+
+ Reference< XIndexContainer > NavigatorTreeModel::GetFormComponents( FmFormData const * pFormData )
+ {
+
+ // get components from form
+ if (pFormData)
+ return Reference< XIndexContainer > (pFormData->GetFormIface(), UNO_QUERY);
+
+ return Reference< XIndexContainer > ();
+ }
+
+
+ bool NavigatorTreeModel::Rename( FmEntryData* pEntryData, const OUString& rNewText )
+ {
+
+ // If name already exist, error message
+ pEntryData->SetText( rNewText );
+
+
+ // get PropertySet
+ Reference< XFormComponent > xFormComponent;
+
+ if( auto pFormData = dynamic_cast<FmFormData*>( pEntryData))
+ {
+ xFormComponent = pFormData->GetFormIface();
+ }
+
+ if( auto pControlData = dynamic_cast<FmControlData*>( pEntryData) )
+ {
+ xFormComponent = pControlData->GetFormComponent();
+ }
+
+ if( !xFormComponent.is() ) return false;
+ Reference< XPropertySet > xSet(xFormComponent, UNO_QUERY);
+ if( !xSet.is() ) return false;
+
+
+ // set name
+ xSet->setPropertyValue( FM_PROP_NAME, Any(rNewText) );
+
+ return true;
+ }
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/sdbdatacolumn.cxx b/svx/source/form/sdbdatacolumn.cxx
new file mode 100644
index 000000000..19a7fd016
--- /dev/null
+++ b/svx/source/form/sdbdatacolumn.cxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdbdatacolumn.hxx>
+
+
+namespace svxform
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::io;
+ using namespace ::com::sun::star::container;
+
+
+ //= DataColumn - a class wrapping an object implementing a sdb::DataColumn service
+
+ DataColumn::DataColumn(const Reference< css::beans::XPropertySet>& _rxIFace)
+ {
+ m_xPropertySet = _rxIFace;
+ m_xColumn.set(_rxIFace, UNO_QUERY);
+ m_xColumnUpdate.set(_rxIFace, UNO_QUERY);
+
+ if (!m_xPropertySet.is() || !m_xColumn.is())
+ {
+ m_xPropertySet = nullptr;
+ m_xColumn = nullptr;
+ m_xColumnUpdate = nullptr;
+ }
+ }
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/sqlparserclient.cxx b/svx/source/form/sqlparserclient.cxx
new file mode 100644
index 000000000..232f0418d
--- /dev/null
+++ b/svx/source/form/sqlparserclient.cxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sqlparserclient.hxx>
+
+#include <connectivity/sqlparse.hxx>
+
+using namespace ::dbtools;
+using namespace ::connectivity;
+
+namespace svxform
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+
+ OSQLParserClient::OSQLParserClient(const Reference< XComponentContext >& rxContext)
+ : m_pParser(std::make_shared<OSQLParser>(rxContext, getParseContext()))
+ {
+ }
+
+ std::unique_ptr< ::connectivity::OSQLParseNode > OSQLParserClient::predicateTree(
+ OUString& _rErrorMessage,
+ const OUString& _rStatement,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxFormatter,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxField
+ ) const
+ {
+ return m_pParser->predicateTree(_rErrorMessage, _rStatement, _rxFormatter, _rxField);
+ }
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/tabwin.cxx b/svx/source/form/tabwin.cxx
new file mode 100644
index 000000000..4aa65b56e
--- /dev/null
+++ b/svx/source/form/tabwin.cxx
@@ -0,0 +1,304 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <tabwin.hxx>
+#include <fmservs.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/types.hxx>
+
+#include <helpids.h>
+#include <svx/fmshell.hxx>
+#include <fmshimp.hxx>
+
+#include <fmprop.hxx>
+
+#include <svx/dialmgr.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/objitem.hxx>
+#include <sfx2/frame.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <tools/diagnose_ex.h>
+#include <tabwin.hrc>
+
+const tools::Long STD_WIN_SIZE_X = 120;
+const tools::Long STD_WIN_SIZE_Y = 150;
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::form;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star;
+using namespace ::svxform;
+using namespace ::svx;
+using namespace ::dbtools;
+
+struct ColumnInfo
+{
+ OUString sColumnName;
+ explicit ColumnInfo(const OUString& i_sColumnName)
+ : sColumnName(i_sColumnName)
+ {
+ }
+};
+
+void FmFieldWin::addToList(const uno::Reference< container::XNameAccess>& i_xColumns )
+{
+ const uno::Sequence< OUString > aEntries = i_xColumns->getElementNames();
+ for ( const OUString& rEntry : aEntries )
+ {
+ uno::Reference< beans::XPropertySet> xColumn(i_xColumns->getByName(rEntry),UNO_QUERY_THROW);
+ OUString sLabel;
+ if ( xColumn->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) )
+ xColumn->getPropertyValue(FM_PROP_LABEL) >>= sLabel;
+ m_aListBoxData.emplace_back(new ColumnInfo(rEntry));
+ OUString sId(weld::toId(m_aListBoxData.back().get()));
+ if ( !sLabel.isEmpty() )
+ m_xListBox->append(sId, sLabel);
+ else
+ m_xListBox->append(sId, rEntry);
+ }
+}
+
+IMPL_LINK(FmFieldWin, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+{
+ rUnsetDragIcon = false;
+
+ ColumnInfo* pSelected = weld::fromId<ColumnInfo*>(m_xListBox->get_selected_id());
+ if (!pSelected)
+ {
+ // no drag without a field
+ return true;
+ }
+
+ svx::ODataAccessDescriptor aDescriptor;
+ aDescriptor[ DataAccessDescriptorProperty::DataSource ] <<= GetDatabaseName();
+ aDescriptor[ DataAccessDescriptorProperty::Connection ] <<= GetConnection().getTyped();
+ aDescriptor[ DataAccessDescriptorProperty::Command ] <<= GetObjectName();
+ aDescriptor[ DataAccessDescriptorProperty::CommandType ]<<= GetObjectType();
+ aDescriptor[ DataAccessDescriptorProperty::ColumnName ] <<= pSelected->sColumnName;
+
+ m_xHelper->setDescriptor(aDescriptor);
+
+ return false;
+}
+
+FmFieldWin::FmFieldWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr, weld::Window* _pParent)
+ : SfxModelessDialogController(_pBindings, _pMgr, _pParent, "svx/ui/formfielddialog.ui", "FormFieldDialog")
+ , SfxControllerItem(SID_FM_FIELDS_CONTROL, *_pBindings)
+ , comphelper::OPropertyChangeListener(m_aMutex)
+ , m_xListBox(m_xBuilder->weld_tree_view("treeview"))
+ , m_nObjectType(0)
+{
+ m_xDialog->set_help_id(HID_FIELD_SEL_WIN);
+ m_xListBox->set_help_id(HID_FIELD_SEL);
+
+ m_xListBox->connect_row_activated(LINK(this, FmFieldWin, RowActivatedHdl));
+ m_xHelper.set(new OColumnTransferable(
+ ColumnTransferFormatFlags::FIELD_DESCRIPTOR | ColumnTransferFormatFlags::CONTROL_EXCHANGE | ColumnTransferFormatFlags::COLUMN_DESCRIPTOR
+ ));
+ rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
+ m_xListBox->enable_drag_source(xHelper, DND_ACTION_COPY);
+ m_xListBox->connect_drag_begin(LINK(this, FmFieldWin, DragBeginHdl));
+
+ UpdateContent(nullptr);
+ m_xDialog->set_size_request(STD_WIN_SIZE_X, STD_WIN_SIZE_Y);
+}
+
+FmFieldWin::~FmFieldWin()
+{
+ if (m_xChangeListener.is())
+ {
+ m_xChangeListener->dispose();
+ m_xChangeListener.clear();
+ }
+ ::SfxControllerItem::dispose();
+}
+
+IMPL_LINK_NOARG(FmFieldWin, RowActivatedHdl, weld::TreeView&, bool)
+{
+ return createSelectionControls();
+}
+
+bool FmFieldWin::createSelectionControls()
+{
+ ColumnInfo* pSelected = weld::fromId<ColumnInfo*>(m_xListBox->get_selected_id());
+ if (pSelected)
+ {
+ // build a descriptor for the currently selected field
+ ODataAccessDescriptor aDescr;
+ aDescr.setDataSource(GetDatabaseName());
+
+ aDescr[ DataAccessDescriptorProperty::Connection ] <<= GetConnection().getTyped();
+
+ aDescr[ DataAccessDescriptorProperty::Command ] <<= GetObjectName();
+ aDescr[ DataAccessDescriptorProperty::CommandType ] <<= GetObjectType();
+ aDescr[ DataAccessDescriptorProperty::ColumnName ] <<= pSelected->sColumnName;
+
+ // transfer this to the SFX world
+ SfxUnoAnyItem aDescriptorItem( SID_FM_DATACCESS_DESCRIPTOR, Any( aDescr.createPropertyValueSequence() ) );
+ const SfxPoolItem* pArgs[] =
+ {
+ &aDescriptorItem, nullptr
+ };
+
+ // execute the create slot
+ GetBindings().Execute( SID_FM_CREATE_FIELDCONTROL, pArgs );
+ }
+
+ return nullptr != pSelected;
+}
+
+void FmFieldWin::_propertyChanged(const css::beans::PropertyChangeEvent& evt)
+{
+ css::uno::Reference< css::form::XForm > xForm(evt.Source, css::uno::UNO_QUERY);
+ UpdateContent(xForm);
+}
+
+void FmFieldWin::StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
+{
+ if (!pState || SID_FM_FIELDS_CONTROL != nSID)
+ return;
+
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ FmFormShell* pShell = dynamic_cast<FmFormShell*>( static_cast<const SfxObjectItem*>(pState)->GetShell() );
+ UpdateContent(pShell);
+ }
+ else
+ UpdateContent(nullptr);
+}
+
+void FmFieldWin::UpdateContent(FmFormShell const * pShell)
+{
+ m_xListBox->clear();
+ m_aListBoxData.clear();
+ OUString aTitle(SvxResId(RID_STR_FIELDSELECTION));
+ m_xDialog->set_title(aTitle);
+
+ if (!pShell || !pShell->GetImpl())
+ return;
+
+ Reference<XForm> const xForm = pShell->GetImpl()->getCurrentForm_Lock();
+ if ( xForm.is() )
+ UpdateContent( xForm );
+}
+
+void FmFieldWin::UpdateContent(const css::uno::Reference< css::form::XForm > & xForm)
+{
+ try
+ {
+ // delete ListBox
+ m_xListBox->clear();
+ m_aListBoxData.clear();
+ OUString aTitle(SvxResId(RID_STR_FIELDSELECTION));
+ m_xDialog->set_title(aTitle);
+
+ if (!xForm.is())
+ return;
+
+ Reference< XPropertySet > xSet(xForm, UNO_QUERY);
+
+ m_aObjectName = ::comphelper::getString(xSet->getPropertyValue(FM_PROP_COMMAND));
+ m_aDatabaseName = ::comphelper::getString(xSet->getPropertyValue(FM_PROP_DATASOURCE));
+ m_nObjectType = ::comphelper::getINT32(xSet->getPropertyValue(FM_PROP_COMMANDTYPE));
+
+ // get the connection of the form
+ m_aConnection.reset(
+ connectRowset( Reference< XRowSet >( xForm, UNO_QUERY ), ::comphelper::getProcessComponentContext(), nullptr ),
+ SharedConnection::NoTakeOwnership
+ );
+ // TODO: When incompatible changes (such as extending the "virtualdbtools" interface by ensureRowSetConnection)
+ // are allowed, again, we should change this: dbtools should consistently use SharedConnection all over
+ // the place, and connectRowset should be replaced with ensureRowSetConnection
+
+ // get the fields of the object
+
+ if ( m_aConnection.is() && !m_aObjectName.isEmpty() )
+ {
+ Reference< XComponent > xKeepFieldsAlive;
+ Reference< XNameAccess > xColumns = getFieldsByCommandDescriptor( m_aConnection, m_nObjectType, m_aObjectName,xKeepFieldsAlive );
+ if ( xColumns.is() )
+ addToList(xColumns);
+ }
+
+ // set prefix
+ OUString aPrefix;
+
+ switch (m_nObjectType)
+ {
+ case CommandType::TABLE:
+ aPrefix = SvxResId(RID_RSC_TABWIN_PREFIX[0]);
+ break;
+ case CommandType::QUERY:
+ aPrefix = SvxResId(RID_RSC_TABWIN_PREFIX[1]);
+ break;
+ default:
+ aPrefix = SvxResId(RID_RSC_TABWIN_PREFIX[2]);
+ break;
+ }
+
+ // listen for changes at ControlSource in PropertySet
+ if (m_xChangeListener.is())
+ {
+ m_xChangeListener->dispose();
+ m_xChangeListener.clear();
+ }
+ m_xChangeListener = new ::comphelper::OPropertyChangeMultiplexer(this, xSet);
+ m_xChangeListener->addProperty(FM_PROP_DATASOURCE);
+ m_xChangeListener->addProperty(FM_PROP_COMMAND);
+ m_xChangeListener->addProperty(FM_PROP_COMMANDTYPE);
+
+ // set title
+ aTitle += " " + aPrefix + " " + m_aObjectName;
+ m_xDialog->set_title(aTitle);
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "FmTabWin::UpdateContent" );
+ }
+}
+
+void FmFieldWin::FillInfo( SfxChildWinInfo& rInfo ) const
+{
+ rInfo.bVisible = false;
+}
+
+SFX_IMPL_MODELESSDIALOGCONTOLLER(FmFieldWinMgr, SID_FM_ADD_FIELD)
+
+FmFieldWinMgr::FmFieldWinMgr(vcl::Window* _pParent, sal_uInt16 _nId,
+ SfxBindings* _pBindings, SfxChildWinInfo const * _pInfo)
+ :SfxChildWindow(_pParent, _nId)
+{
+ auto xDlg = std::make_shared<FmFieldWin>(_pBindings, this, _pParent->GetFrameWeld());
+ SetController(xDlg);
+ SetHideNotDelete(true);
+ xDlg->Initialize(_pInfo);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/tbxform.cxx b/svx/source/form/tbxform.cxx
new file mode 100644
index 000000000..05576133d
--- /dev/null
+++ b/svx/source/form/tbxform.cxx
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <svl/intitem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/settings.hxx>
+
+#include <svx/dialmgr.hxx>
+#include <svx/labelitemwindow.hxx>
+#include <svx/svxids.hrc>
+#include <svx/strings.hrc>
+#include <tbxform.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+
+SvxFmAbsRecWin::SvxFmAbsRecWin(vcl::Window* pParent, SfxToolBoxControl* pController)
+ : RecordItemWindow(pParent)
+ , m_pController(pController)
+{
+ m_xWidget->set_width_chars(6);
+ SetSizePixel(m_xWidget->get_preferred_size());
+}
+
+void SvxFmAbsRecWin::PositionFired(sal_Int64 nRecord)
+{
+ SfxInt32Item aPositionParam( FN_PARAM_1, static_cast<sal_Int32>(nRecord) );
+
+ Any a;
+ aPositionParam.QueryValue( a );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("Position", a) };
+ m_pController->Dispatch( ".uno:AbsoluteRecord",
+ aArgs );
+ m_pController->updateStatus();
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxCtlAbsRec, SfxInt32Item );
+
+SvxFmTbxCtlAbsRec::SvxFmTbxCtlAbsRec( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx )
+ :SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+
+SvxFmTbxCtlAbsRec::~SvxFmTbxCtlAbsRec()
+{
+}
+
+void SvxFmTbxCtlAbsRec::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
+{
+ ToolBoxItemId nId = GetId();
+ ToolBox* pToolBox = &GetToolBox();
+ SvxFmAbsRecWin* pWin = static_cast<SvxFmAbsRecWin*>( pToolBox->GetItemWindow(nId) );
+
+ assert(pWin && "Control not found!");
+
+ if (pState)
+ {
+ const SfxInt32Item* pItem = dynamic_cast< const SfxInt32Item* >( pState );
+ DBG_ASSERT( pItem, "SvxFmTbxCtlAbsRec::StateChanged: invalid item!" );
+ pWin->set_text(OUString::number(pItem ? pItem->GetValue() : -1));
+ }
+
+ bool bEnable = SfxItemState::DISABLED != eState && pState;
+ if (!bEnable)
+ pWin->set_text(OUString());
+
+
+ // enabling/disabling of the window
+ pToolBox->EnableItem(nId, bEnable);
+ SfxToolBoxControl::StateChangedAtToolBoxControl( nSID, eState,pState );
+}
+
+VclPtr<InterimItemWindow> SvxFmTbxCtlAbsRec::CreateItemWindow( vcl::Window* pParent )
+{
+ return VclPtrInstance<SvxFmAbsRecWin>(pParent, this);
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxCtlRecText, SfxBoolItem );
+
+SvxFmTbxCtlRecText::SvxFmTbxCtlRecText( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx )
+ :SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+ rTbx.SetItemWindowNonInteractive(nId, true);
+}
+
+SvxFmTbxCtlRecText::~SvxFmTbxCtlRecText()
+{
+}
+
+VclPtr<InterimItemWindow> SvxFmTbxCtlRecText::CreateItemWindow( vcl::Window* pParent )
+{
+ OUString aText(SvxResId(RID_STR_REC_TEXT));
+ VclPtrInstance<LabelItemWindow> xFixedText(pParent, aText);
+
+ xFixedText->Show();
+
+ return xFixedText;
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxCtlRecFromText, SfxBoolItem );
+
+SvxFmTbxCtlRecFromText::SvxFmTbxCtlRecFromText( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx )
+ :SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+ rTbx.SetItemWindowNonInteractive(nId, true);
+}
+
+SvxFmTbxCtlRecFromText::~SvxFmTbxCtlRecFromText()
+{
+}
+
+VclPtr<InterimItemWindow> SvxFmTbxCtlRecFromText::CreateItemWindow( vcl::Window* pParent )
+{
+ OUString aText(SvxResId(RID_STR_REC_FROM_TEXT));
+ VclPtrInstance<LabelItemWindow> xFixedText(pParent, aText);
+
+ xFixedText->Show();
+
+ return xFixedText;
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxCtlRecTotal, SfxStringItem );
+
+SvxFmTbxCtlRecTotal::SvxFmTbxCtlRecTotal( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx )
+ : SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+ rTbx.SetItemWindowNonInteractive(nId, true);
+}
+
+SvxFmTbxCtlRecTotal::~SvxFmTbxCtlRecTotal()
+{
+}
+
+VclPtr<InterimItemWindow> SvxFmTbxCtlRecTotal::CreateItemWindow( vcl::Window* pParent )
+{
+ m_xFixedText.reset(VclPtr<LabelItemWindow>::Create(pParent, "123456"));
+ m_xFixedText->set_label("");
+
+ m_xFixedText->Show();
+
+ return m_xFixedText;
+}
+
+void SvxFmTbxCtlRecTotal::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
+{
+ // setting the FixedText
+ if (GetSlotId() != SID_FM_RECORD_TOTAL)
+ return;
+
+ OUString aText;
+ if (pState)
+ aText = static_cast<const SfxStringItem*>(pState)->GetValue();
+ else
+ aText = "?";
+
+ m_xFixedText->set_label(aText);
+
+ SfxToolBoxControl::StateChangedAtToolBoxControl( nSID, eState,pState );
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxNextRec, SfxBoolItem );
+
+
+SvxFmTbxNextRec::SvxFmTbxNextRec( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx )
+ :SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+ rTbx.SetItemBits(nId, rTbx.GetItemBits(nId) | ToolBoxItemBits::REPEAT);
+
+ AllSettings aSettings = rTbx.GetSettings();
+ MouseSettings aMouseSettings = aSettings.GetMouseSettings();
+ aMouseSettings.SetButtonRepeat(aMouseSettings.GetButtonRepeat() / 4);
+ aSettings.SetMouseSettings(aMouseSettings);
+ rTbx.SetSettings(aSettings, true);
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxPrevRec, SfxBoolItem );
+
+
+SvxFmTbxPrevRec::SvxFmTbxPrevRec( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx )
+ :SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+ rTbx.SetItemBits(nId, rTbx.GetItemBits(nId) | ToolBoxItemBits::REPEAT);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/typemap.cxx b/svx/source/form/typemap.cxx
new file mode 100644
index 000000000..b169b745c
--- /dev/null
+++ b/svx/source/form/typemap.cxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_options.h>
+
+#include <sfx2/objitem.hxx>
+#include <sfx2/msg.hxx>
+#include <svl/memberid.h>
+#include <editeng/wghtitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/postitem.hxx>
+#include <svx/clipfmtitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <editeng/autokernitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/emphasismarkitem.hxx>
+
+#include <editeng/memberids.h>
+#define SFX_TYPEMAP
+#include <svxslots.hxx>
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/form/xfm_addcondition.cxx b/svx/source/form/xfm_addcondition.cxx
new file mode 100644
index 000000000..6c8d6ef35
--- /dev/null
+++ b/svx/source/form/xfm_addcondition.cxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <xfm_addcondition.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/processfactory.hxx>
+#include <vcl/svapp.hxx>
+#include <datanavi.hxx>
+#include <fmservs.hxx>
+
+namespace svxform
+{
+
+#define PROPERTY_ID_BINDING 5724
+#define PROPERTY_ID_FORM_MODEL 5725
+#define PROPERTY_ID_FACET_NAME 5726
+#define PROPERTY_ID_CONDITION_VALUE 5727
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::xforms;
+
+
+ //= OAddConditionDialog
+
+
+ Reference< XInterface > OAddConditionDialog_Create( const Reference< XMultiServiceFactory > & _rxORB )
+ {
+ return OAddConditionDialog::Create( _rxORB );
+ }
+
+
+ Sequence< OUString > OAddConditionDialog_GetSupportedServiceNames()
+ {
+ return { "com.sun.star.xforms.ui.dialogs.AddCondition" };
+ }
+
+
+ OUString OAddConditionDialog_GetImplementationName()
+ {
+ return "org.openoffice.comp.svx.OAddConditionDialog";
+ }
+
+ OAddConditionDialog::OAddConditionDialog( const Reference< XComponentContext >& _rxORB )
+ :OAddConditionDialogBase( _rxORB )
+ {
+ registerProperty(
+ "Binding",
+ PROPERTY_ID_BINDING,
+ PropertyAttribute::TRANSIENT,
+ &m_xBinding,
+ cppu::UnoType<decltype(m_xBinding)>::get()
+ );
+
+ registerProperty(
+ "FacetName",
+ PROPERTY_ID_FACET_NAME,
+ PropertyAttribute::TRANSIENT,
+ &m_sFacetName,
+ cppu::UnoType<decltype(m_sFacetName)>::get()
+ );
+
+ registerProperty(
+ "ConditionValue",
+ PROPERTY_ID_CONDITION_VALUE,
+ PropertyAttribute::TRANSIENT,
+ &m_sConditionValue,
+ cppu::UnoType<decltype(m_sConditionValue)>::get()
+ );
+
+ registerProperty(
+ "FormModel",
+ PROPERTY_ID_FORM_MODEL,
+ PropertyAttribute::TRANSIENT,
+ &m_xWorkModel,
+ cppu::UnoType<decltype(m_xWorkModel)>::get()
+ );
+ }
+
+
+ Sequence<sal_Int8> SAL_CALL OAddConditionDialog::getImplementationId( )
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+
+ Reference< XInterface > OAddConditionDialog::Create( const Reference< XMultiServiceFactory >& _rxFactory )
+ {
+ return *( new OAddConditionDialog( comphelper::getComponentContext(_rxFactory) ) );
+ }
+
+
+ OUString SAL_CALL OAddConditionDialog::getImplementationName()
+ {
+ return OAddConditionDialog_GetImplementationName();
+ }
+
+
+ Sequence< OUString > SAL_CALL OAddConditionDialog::getSupportedServiceNames()
+ {
+ return OAddConditionDialog_GetSupportedServiceNames();
+ }
+
+
+ Reference<XPropertySetInfo> SAL_CALL OAddConditionDialog::getPropertySetInfo()
+ {
+ return createPropertySetInfo( getInfoHelper() );
+ }
+
+ ::cppu::IPropertyArrayHelper& OAddConditionDialog::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* OAddConditionDialog::createArrayHelper( ) const
+ {
+ Sequence< Property > aProperties;
+ describeProperties( aProperties );
+ return new ::cppu::OPropertyArrayHelper( aProperties );
+ }
+
+ std::unique_ptr<weld::DialogController> OAddConditionDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
+ {
+ if ( !m_xBinding.is() || m_sFacetName.isEmpty() )
+ throw RuntimeException( OUString(), *this );
+
+ return std::make_unique<AddConditionDialog>(Application::GetFrameWeld(rParent), m_sFacetName, m_xBinding);
+ }
+
+ void OAddConditionDialog::executedDialog( sal_Int16 _nExecutionResult )
+ {
+ OAddConditionDialogBase::executedDialog( _nExecutionResult );
+ if ( _nExecutionResult == RET_OK )
+ m_sConditionValue = static_cast<AddConditionDialog*>(m_xDialog.get())->GetCondition();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/GalleryControl.cxx b/svx/source/gallery2/GalleryControl.cxx
new file mode 100644
index 000000000..d7b2a9693
--- /dev/null
+++ b/svx/source/gallery2/GalleryControl.cxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <GalleryControl.hxx>
+
+#include <svx/gallery1.hxx>
+#include "galbrws1.hxx"
+#include <galbrws2.hxx>
+
+namespace svx::sidebar {
+
+GalleryControl::GalleryControl(weld::Widget* pParent)
+ : PanelLayout(pParent, "GalleryPanel", "svx/ui/sidebargallery.ui")
+ , mpGallery(Gallery::GetGalleryInstance())
+ , mxBrowser1(new GalleryBrowser1(
+ *m_xBuilder,
+ mpGallery,
+ [this] ()
+ { return mxBrowser2->SelectTheme(mxBrowser1->GetSelectedTheme()); }))
+ , mxBrowser2(new GalleryBrowser2(*m_xBuilder, mpGallery))
+{
+ mxBrowser1->SelectTheme(0);
+}
+
+GalleryControl::~GalleryControl()
+{
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/codec.cxx b/svx/source/gallery2/codec.cxx
new file mode 100644
index 000000000..062c60dbe
--- /dev/null
+++ b/svx/source/gallery2/codec.cxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <tools/stream.hxx>
+#include <tools/zcodec.hxx>
+#include "codec.hxx"
+#include <memory>
+
+
+GalleryCodec::GalleryCodec( SvStream& rIOStm ) :
+ rStm( rIOStm )
+{
+}
+
+bool GalleryCodec::IsCoded( SvStream& rStm, sal_uInt32& rVersion )
+{
+ const sal_uInt64 nPos = rStm.Tell();
+ bool bRet;
+ sal_uInt8 cByte1, cByte2, cByte3, cByte4, cByte5, cByte6;
+
+ rStm.ReadUChar( cByte1 ).ReadUChar( cByte2 ).ReadUChar( cByte3 ).ReadUChar( cByte4 ).ReadUChar( cByte5 ).ReadUChar( cByte6 );
+
+ if ( cByte1 == 'S' && cByte2 == 'V' && cByte3 == 'R' && cByte4 == 'L' && cByte5 == 'E' && ( cByte6 == '1' || cByte6 == '2' ) )
+ {
+ rVersion = ( ( cByte6 == '1' ) ? 1 : 2 );
+ bRet = true;
+ }
+ else
+ {
+ rVersion = 0;
+ bRet = false;
+ }
+
+ rStm.Seek( nPos );
+
+ return bRet;
+}
+
+void GalleryCodec::Write( SvStream& rStmToWrite )
+{
+ sal_uInt32 nPos, nCompSize;
+
+ const sal_uInt32 nSize = rStmToWrite.TellEnd();
+ rStmToWrite.Seek( 0 );
+
+ rStm.WriteChar( 'S' ).WriteChar( 'V' ).WriteChar( 'R' ).WriteChar( 'L' ).WriteChar( 'E' ).WriteChar( '2' );
+ rStm.WriteUInt32( nSize );
+
+ nPos = rStm.Tell();
+ rStm.SeekRel( 4 );
+
+ ZCodec aCodec;
+ aCodec.BeginCompression();
+ aCodec.Compress( rStmToWrite, rStm );
+ aCodec.EndCompression();
+
+ nCompSize = rStm.Tell() - nPos - 4;
+ rStm.Seek( nPos );
+ rStm.WriteUInt32( nCompSize );
+ rStm.Seek( STREAM_SEEK_TO_END );
+}
+
+void GalleryCodec::Read( SvStream& rStmToRead )
+{
+ sal_uInt32 nVersion = 0;
+
+ if( !IsCoded( rStm, nVersion ) )
+ return;
+
+ sal_uInt32 nCompressedSize, nUnCompressedSize;
+
+ rStm.SeekRel( 6 );
+ rStm.ReadUInt32( nUnCompressedSize ).ReadUInt32( nCompressedSize );
+
+ // decompress
+ if( 1 == nVersion )
+ {
+ std::unique_ptr<sal_uInt8[]> pCompressedBuffer(new sal_uInt8[ nCompressedSize ]);
+ rStm.ReadBytes(pCompressedBuffer.get(), nCompressedSize);
+ sal_uInt8* pInBuf = pCompressedBuffer.get();
+ std::unique_ptr<sal_uInt8[]> pOutBuf(new sal_uInt8[ nUnCompressedSize ]);
+ sal_uInt8* pTmpBuf = pOutBuf.get();
+ sal_uInt8* pLast = pOutBuf.get() + nUnCompressedSize - 1;
+ sal_uIntPtr nIndex = 0, nCountByte, nRunByte;
+ bool bEndDecoding = false;
+
+ do
+ {
+ nCountByte = *pInBuf++;
+
+ if ( !nCountByte )
+ {
+ nRunByte = *pInBuf++;
+
+ if ( nRunByte > 2 )
+ {
+ // filling absolutely
+ memcpy( &pTmpBuf[ nIndex ], pInBuf, nRunByte );
+ pInBuf += nRunByte;
+ nIndex += nRunByte;
+
+ // note WORD alignment
+ if ( nRunByte & 1 )
+ pInBuf++;
+ }
+ else if ( nRunByte == 1 ) // End of the image
+ bEndDecoding = true;
+ }
+ else
+ {
+ const sal_uInt8 cVal = *pInBuf++;
+
+ memset( &pTmpBuf[ nIndex ], cVal, nCountByte );
+ nIndex += nCountByte;
+ }
+ }
+ while ( !bEndDecoding && ( pTmpBuf <= pLast ) );
+
+ rStmToRead.WriteBytes(pOutBuf.get(), nUnCompressedSize);
+ }
+ else if( 2 == nVersion )
+ {
+ ZCodec aCodec;
+
+ aCodec.BeginCompression();
+ aCodec.Decompress( rStm, rStmToRead );
+ aCodec.EndCompression();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/codec.hxx b/svx/source/gallery2/codec.hxx
new file mode 100644
index 000000000..726b80157
--- /dev/null
+++ b/svx/source/gallery2/codec.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+class SvStream;
+
+class GalleryCodec
+{
+private:
+ SvStream& rStm;
+
+public:
+ explicit GalleryCodec(SvStream& rIOStm);
+
+ void Write(SvStream& rStmToWrite);
+ void Read(SvStream& rStmToRead);
+
+ static bool IsCoded(SvStream& rStm, sal_uInt32& rVersion);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galbrws1.cxx b/svx/source/gallery2/galbrws1.cxx
new file mode 100644
index 000000000..e33e16974
--- /dev/null
+++ b/svx/source/gallery2/galbrws1.cxx
@@ -0,0 +1,485 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <tools/datetime.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <sfx2/app.hxx>
+#include <helpids.h>
+#include <svx/gallery1.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/galmisc.hxx>
+#include "galbrws1.hxx"
+#include <svx/strings.hrc>
+#include <algorithm>
+#include <svx/dialmgr.hxx>
+#include <comphelper/dispatchcommand.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <svx/svxdlg.hxx>
+#include <memory>
+#include <bitmaps.hlst>
+
+using namespace ::com::sun::star;
+
+GalleryBrowser1::GalleryBrowser1(
+ weld::Builder& rBuilder,
+ Gallery* pGallery,
+ const std::function<void ()>& rThemeSelectionHandler)
+ :
+ mxNewTheme(rBuilder.weld_button("insert")),
+ mxThemes(rBuilder.weld_tree_view("themelist")),
+ mxMoreGalleries(rBuilder.weld_button("btnMoreGalleries")),
+ mpGallery ( pGallery ),
+ mpExchangeData ( new ExchangeData ),
+ aImgNormal ( RID_SVXBMP_THEME_NORMAL ),
+ aImgDefault ( RID_SVXBMP_THEME_DEFAULT ),
+ aImgReadOnly ( RID_SVXBMP_THEME_READONLY ),
+ maThemeSelectionHandler(rThemeSelectionHandler)
+{
+ mxNewTheme->set_help_id(HID_GALLERY_NEWTHEME);
+ mxNewTheme->connect_clicked( LINK( this, GalleryBrowser1, ClickNewThemeHdl ) );
+
+ mxThemes->make_sorted();
+ mxThemes->set_help_id( HID_GALLERY_THEMELIST );
+ mxThemes->connect_changed( LINK( this, GalleryBrowser1, SelectThemeHdl ) );
+ mxThemes->connect_popup_menu(LINK(this, GalleryBrowser1, PopupMenuHdl));
+ mxThemes->connect_key_press(LINK(this, GalleryBrowser1, KeyInputHdl));
+ mxThemes->set_size_request(-1, mxThemes->get_height_rows(6));
+
+ mxMoreGalleries->set_from_icon_name("cmd/sc_additionsdialog.png");
+ mxMoreGalleries->connect_clicked(LINK(this, GalleryBrowser1, OnMoreGalleriesClick));
+
+ // disable creation of new themes if a writable directory is not available
+ if( mpGallery->GetUserURL().GetProtocol() == INetProtocol::NotValid )
+ mxNewTheme->set_sensitive(false);
+
+ StartListening( *mpGallery );
+
+ for (size_t i = 0, nCount = mpGallery->GetThemeCount(); i < nCount; ++i)
+ ImplInsertThemeEntry( mpGallery->GetThemeInfo( i ) );
+}
+
+GalleryBrowser1::~GalleryBrowser1()
+{
+ EndListening( *mpGallery );
+ mpExchangeData.reset();
+}
+
+void GalleryBrowser1::ImplInsertThemeEntry( const GalleryThemeEntry* pEntry )
+{
+ static const bool bShowHiddenThemes = ( getenv( "GALLERY_SHOW_HIDDEN_THEMES" ) != nullptr );
+
+ if( !(pEntry && ( !pEntry->IsHidden() || bShowHiddenThemes )) )
+ return;
+
+ const OUString* pImage;
+
+ if( pEntry->IsReadOnly() )
+ pImage = &aImgReadOnly;
+ else if( pEntry->IsDefault() )
+ pImage = &aImgDefault;
+ else
+ pImage = &aImgNormal;
+
+ mxThemes->append("", pEntry->GetThemeName(), *pImage);
+}
+
+void GalleryBrowser1::ImplFillExchangeData( const GalleryTheme* pThm, ExchangeData& rData )
+{
+ rData.pTheme = const_cast<GalleryTheme*>(pThm);
+ rData.aEditedTitle = pThm->GetName();
+
+ try
+ {
+ DateTime aDateTime(pThm->getModificationDate());
+
+ rData.aThemeChangeDate = aDateTime;
+ rData.aThemeChangeTime = aDateTime;
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+void GalleryBrowser1::ImplGetExecuteVector(std::vector<OString>& o_aExec)
+{
+ GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this );
+
+ if( !pTheme )
+ return;
+
+ bool bUpdateAllowed, bRenameAllowed, bRemoveAllowed;
+ static const bool bIdDialog = ( getenv( "GALLERY_ENABLE_ID_DIALOG" ) != nullptr );
+
+ if( pTheme->IsReadOnly() )
+ bUpdateAllowed = bRenameAllowed = bRemoveAllowed = false;
+ else if( pTheme->IsDefault() )
+ {
+ bUpdateAllowed = bRenameAllowed = true;
+ bRemoveAllowed = false;
+ }
+ else
+ bUpdateAllowed = bRenameAllowed = bRemoveAllowed = true;
+
+ if( bUpdateAllowed && pTheme->GetObjectCount() )
+ o_aExec.emplace_back("update");
+
+ if( bRenameAllowed )
+ o_aExec.emplace_back("rename");
+
+ if( bRemoveAllowed )
+ o_aExec.emplace_back("delete");
+
+ if( bIdDialog && !pTheme->IsReadOnly() )
+ o_aExec.emplace_back("assign");
+
+ o_aExec.emplace_back("properties");
+
+ mpGallery->ReleaseTheme( pTheme, *this );
+}
+
+void GalleryBrowser1::ImplGalleryThemeProperties( std::u16string_view rThemeName, bool bCreateNew )
+{
+ DBG_ASSERT(!mpThemePropsDlgItemSet, "mpThemePropsDlgItemSet already set!");
+ mpThemePropsDlgItemSet.reset(new SfxItemSet( SfxGetpApp()->GetPool() ));
+ GalleryTheme* pTheme = mpGallery->AcquireTheme( rThemeName, *this );
+
+ ImplFillExchangeData( pTheme, *mpExchangeData );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ VclPtr<VclAbstractDialog> xThemePropertiesDialog = pFact->CreateGalleryThemePropertiesDialog(mxThemes.get(), mpExchangeData.get(), mpThemePropsDlgItemSet.get());
+
+ if ( bCreateNew )
+ {
+ xThemePropertiesDialog->StartExecuteAsync([xThemePropertiesDialog, this](sal_Int32 nResult){
+ EndNewThemePropertiesDlgHdl(nResult);
+ xThemePropertiesDialog->disposeOnce();
+ });
+ }
+ else
+ {
+ xThemePropertiesDialog->StartExecuteAsync([xThemePropertiesDialog, this](sal_Int32 nResult){
+ EndThemePropertiesDlgHdl(nResult);
+ xThemePropertiesDialog->disposeOnce();
+ });
+ }
+}
+
+void GalleryBrowser1::ImplEndGalleryThemeProperties(bool bCreateNew, sal_Int32 nRet)
+{
+ if( nRet == RET_OK )
+ {
+ OUString aName( mpExchangeData->pTheme->GetName() );
+
+ if( !mpExchangeData->aEditedTitle.isEmpty() && aName != mpExchangeData->aEditedTitle )
+ {
+ OUString aTitle( mpExchangeData->aEditedTitle );
+ sal_uInt16 nCount = 0;
+
+ while( mpGallery->HasTheme( aTitle ) && ( nCount++ < 16000 ) )
+ {
+ aTitle = mpExchangeData->aEditedTitle + " " + OUString::number( nCount );
+ }
+
+ mpGallery->RenameTheme( aName, aTitle );
+ }
+
+ if ( bCreateNew )
+ {
+ mxThemes->select_text( mpExchangeData->pTheme->GetName() );
+ SelectThemeHdl( *mxThemes );
+ }
+ }
+
+ OUString aThemeName( mpExchangeData->pTheme->GetName() );
+ mpGallery->ReleaseTheme( mpExchangeData->pTheme, *this );
+
+ if ( bCreateNew && ( nRet != RET_OK ) )
+ {
+ mpGallery->RemoveTheme( aThemeName );
+ }
+}
+
+void GalleryBrowser1::EndNewThemePropertiesDlgHdl(sal_Int32 nResult)
+{
+ ImplEndGalleryThemeProperties(true, nResult);
+}
+
+void GalleryBrowser1::EndThemePropertiesDlgHdl(sal_Int32 nResult)
+{
+ ImplEndGalleryThemeProperties(false, nResult);
+}
+
+void GalleryBrowser1::ImplExecute(std::string_view rIdent)
+{
+ if (rIdent == "update")
+ {
+ GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> aActualizeProgress(pFact->CreateActualizeProgressDialog(mxThemes.get(), pTheme));
+
+ aActualizeProgress->Execute();
+ mpGallery->ReleaseTheme( pTheme, *this );
+ }
+ else if (rIdent == "delete")
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxThemes.get(), "svx/ui/querydeletethemedialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteThemeDialog"));
+ if (xQuery->run() == RET_YES)
+ mpGallery->RemoveTheme( mxThemes->get_selected_text() );
+ }
+ else if (rIdent == "rename")
+ {
+ GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this );
+ const OUString aOldName( pTheme->GetName() );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractTitleDialog> aDlg(pFact->CreateTitleDialog(mxThemes.get(), aOldName));
+
+ if( aDlg->Execute() == RET_OK )
+ {
+ const OUString aNewName( aDlg->GetTitle() );
+
+ if( !aNewName.isEmpty() && ( aNewName != aOldName ) )
+ {
+ OUString aName( aNewName );
+ sal_uInt16 nCount = 0;
+
+ while( mpGallery->HasTheme( aName ) && ( nCount++ < 16000 ) )
+ {
+ aName = aNewName + " " + OUString::number( nCount );
+ }
+
+ mpGallery->RenameTheme( aOldName, aName );
+ }
+ }
+ mpGallery->ReleaseTheme( pTheme, *this );
+ }
+ else if (rIdent == "assign")
+ {
+ GalleryTheme* pTheme = mpGallery->AcquireTheme( GetSelectedTheme(), *this );
+
+ if (pTheme && !pTheme->IsReadOnly())
+ {
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGalleryIdDialog> aDlg(pFact->CreateGalleryIdDialog(mxThemes.get(), pTheme));
+ if( aDlg->Execute() == RET_OK )
+ pTheme->SetId( aDlg->GetId(), true );
+ }
+
+ mpGallery->ReleaseTheme( pTheme, *this );
+ }
+ else if (rIdent == "properties")
+ {
+ ImplGalleryThemeProperties( GetSelectedTheme(), false );
+ }
+}
+
+void GalleryBrowser1::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const GalleryHint& rGalleryHint = static_cast<const GalleryHint&>(rHint);
+
+ switch( rGalleryHint.GetType() )
+ {
+ case GalleryHintType::THEME_CREATED:
+ ImplInsertThemeEntry( mpGallery->GetThemeInfo( rGalleryHint.GetThemeName() ) );
+ break;
+
+ case GalleryHintType::THEME_RENAMED:
+ {
+ const sal_Int32 nCurSelectPos = mxThemes->get_selected_index();
+ const sal_Int32 nRenameEntryPos = mxThemes->find_text( rGalleryHint.GetThemeName() );
+
+ mxThemes->remove_text( rGalleryHint.GetThemeName() );
+ ImplInsertThemeEntry( mpGallery->GetThemeInfo( rGalleryHint.GetStringData() ) );
+
+ if( nCurSelectPos == nRenameEntryPos )
+ {
+ mxThemes->select_text( rGalleryHint.GetStringData() );
+ SelectThemeHdl( *mxThemes );
+ }
+ }
+ break;
+
+ case GalleryHintType::THEME_REMOVED:
+ {
+ mxThemes->remove_text( rGalleryHint.GetThemeName() );
+ }
+ break;
+
+ case GalleryHintType::CLOSE_THEME:
+ {
+ const sal_Int32 nCurSelectPos = mxThemes->get_selected_index();
+ const sal_Int32 nCloseEntryPos = mxThemes->find_text( rGalleryHint.GetThemeName() );
+
+ if( nCurSelectPos == nCloseEntryPos )
+ {
+ if( nCurSelectPos < ( mxThemes->n_children() - 1 ) )
+ mxThemes->select( nCurSelectPos + 1 );
+ else if( nCurSelectPos )
+ mxThemes->select( nCurSelectPos - 1 );
+ else
+ mxThemes->select(-1);
+
+ SelectThemeHdl( *mxThemes );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+IMPL_STATIC_LINK_NOARG( GalleryBrowser1, OnMoreGalleriesClick, weld::Button&, void)
+{
+ css::uno::Sequence<css::beans::PropertyValue> aArgs{
+ comphelper::makePropertyValue("AdditionsTag", OUString("Gallery"))
+ };
+ comphelper::dispatchCommand(".uno:AdditionsDialog", aArgs);
+}
+
+IMPL_LINK(GalleryBrowser1, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bRet = false;
+
+ std::vector<OString> aExecVector;
+ ImplGetExecuteVector(aExecVector);
+ OString sExecuteIdent;
+ bool bMod1 = rKEvt.GetKeyCode().IsMod1();
+
+ switch( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_INSERT:
+ ClickNewThemeHdl(*mxNewTheme);
+ break;
+
+ case KEY_I:
+ {
+ if( bMod1 )
+ ClickNewThemeHdl(*mxNewTheme);
+ }
+ break;
+
+ case KEY_U:
+ {
+ if( bMod1 )
+ sExecuteIdent = "update";
+ }
+ break;
+
+ case KEY_DELETE:
+ sExecuteIdent = "delete";
+ break;
+
+ case KEY_D:
+ {
+ if( bMod1 )
+ sExecuteIdent = "delete";
+ }
+ break;
+
+ case KEY_R:
+ {
+ if( bMod1 )
+ sExecuteIdent = "rename";
+ }
+ break;
+
+ case KEY_RETURN:
+ {
+ if( bMod1 )
+ sExecuteIdent = "properties";
+ }
+ break;
+ }
+
+ if (!sExecuteIdent.isEmpty() && (std::find( aExecVector.begin(), aExecVector.end(), sExecuteIdent) != aExecVector.end()))
+ {
+ ImplExecute(sExecuteIdent);
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+IMPL_LINK(GalleryBrowser1, PopupMenuHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ std::vector<OString> aExecVector;
+ ImplGetExecuteVector(aExecVector);
+
+ if (aExecVector.empty())
+ return true;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxThemes.get(), "svx/ui/gallerymenu1.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+
+ xMenu->set_visible("update", std::find( aExecVector.begin(), aExecVector.end(), "update" ) != aExecVector.end());
+ xMenu->set_visible("rename", std::find( aExecVector.begin(), aExecVector.end(), "rename" ) != aExecVector.end());
+ xMenu->set_visible("delete", std::find( aExecVector.begin(), aExecVector.end(), "delete" ) != aExecVector.end());
+ xMenu->set_visible("assign", std::find( aExecVector.begin(), aExecVector.end(), "assign" ) != aExecVector.end());
+ xMenu->set_visible("properties", std::find( aExecVector.begin(), aExecVector.end(), "properties" ) != aExecVector.end());
+
+ OString sCommand(xMenu->popup_at_rect(mxThemes.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
+ ImplExecute(sCommand);
+
+ return true;
+}
+
+IMPL_LINK_NOARG(GalleryBrowser1, SelectThemeHdl, weld::TreeView&, void)
+{
+ if (maThemeSelectionHandler)
+ maThemeSelectionHandler();
+}
+
+IMPL_LINK_NOARG(GalleryBrowser1, ClickNewThemeHdl, weld::Button&, void)
+{
+ OUString aNewTheme( SvxResId(RID_SVXSTR_GALLERY_NEWTHEME) );
+ OUString aName( aNewTheme );
+ sal_uInt16 nCount = 0;
+
+ while( mpGallery->HasTheme( aName ) && ( nCount++ < 16000 ) )
+ {
+ aName = aNewTheme + " " + OUString::number( nCount );
+ }
+
+ if( !mpGallery->HasTheme( aName ) && mpGallery->CreateTheme( aName ) )
+ {
+ ImplGalleryThemeProperties( aName, true );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galbrws1.hxx b/svx/source/gallery2/galbrws1.hxx
new file mode 100644
index 000000000..ccbc7f24f
--- /dev/null
+++ b/svx/source/gallery2/galbrws1.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svl/lstner.hxx>
+#include <vcl/weld.hxx>
+#include <vector>
+
+#include <functional>
+
+class GalleryBrowser1;
+
+
+class Gallery;
+class GalleryThemeEntry;
+class GalleryTheme;
+class VclAbstractDialog;
+struct ExchangeData;
+class SfxItemSet;
+
+namespace svx::sidebar { class GalleryControl; }
+
+class GalleryBrowser1 final : public SfxListener
+{
+ friend class GalleryBrowser;
+ friend class svx::sidebar::GalleryControl;
+
+private:
+
+ std::unique_ptr<weld::Button> mxNewTheme;
+ std::unique_ptr<weld::TreeView> mxThemes;
+ std::unique_ptr<weld::Button> mxMoreGalleries;
+ Gallery* mpGallery;
+ std::unique_ptr<ExchangeData> mpExchangeData;
+ std::unique_ptr<SfxItemSet> mpThemePropsDlgItemSet;
+
+ OUString aImgNormal;
+ OUString aImgDefault;
+ OUString aImgReadOnly;
+
+ ::std::function<void ()> maThemeSelectionHandler;
+
+ void ImplInsertThemeEntry( const GalleryThemeEntry* pEntry );
+ static void ImplFillExchangeData( const GalleryTheme* pThm, ExchangeData& rData );
+ void ImplGetExecuteVector(std::vector<OString>& o_aExec);
+ void ImplExecute(std::string_view rIdent);
+ void ImplGalleryThemeProperties( std::u16string_view rThemeName, bool bCreateNew );
+ void EndNewThemePropertiesDlgHdl(sal_Int32 nResult);
+ void EndThemePropertiesDlgHdl(sal_Int32 nResult);
+ void ImplEndGalleryThemeProperties(bool bCreateNew, sal_Int32 nResult);
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ DECL_LINK( ClickNewThemeHdl, weld::Button&, void );
+ DECL_LINK( SelectThemeHdl, weld::TreeView&, void );
+ DECL_LINK( PopupMenuHdl, const CommandEvent&, bool );
+ DECL_LINK( KeyInputHdl, const KeyEvent&, bool );
+ DECL_STATIC_LINK( GalleryBrowser1, OnMoreGalleriesClick, weld::Button&, void );
+
+public:
+
+ GalleryBrowser1(
+ weld::Builder& rBuilder,
+ Gallery* pGallery,
+ const ::std::function<void ()>& rThemeSelectionHandler);
+
+ ~GalleryBrowser1();
+
+ void SelectTheme( sal_uInt16 nThemePos ) { mxThemes->select( nThemePos ); SelectThemeHdl( *mxThemes ); }
+ OUString GetSelectedTheme() const { return mxThemes->get_selected_text(); }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galbrws2.cxx b/svx/source/gallery2/galbrws2.cxx
new file mode 100644
index 000000000..27ba2634d
--- /dev/null
+++ b/svx/source/gallery2/galbrws2.cxx
@@ -0,0 +1,1242 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sot/formats.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/virdev.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <helpids.h>
+#include <svx/svxids.hrc>
+#include <galobj.hxx>
+#include <svx/gallery1.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/galctrl.hxx>
+#include <svx/galmisc.hxx>
+#include <galbrws2.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/galleryitem.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/gallery/GalleryItemType.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/style/GraphicLocation.hpp>
+
+#include <cassert>
+#include <map>
+#include <memory>
+#include <cppuhelper/implbase.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+
+GalleryBrowserMode GalleryBrowser2::meInitMode = GALLERYBROWSERMODE_ICON;
+
+struct DispatchInfo
+{
+ css::util::URL TargetURL;
+ css::uno::Sequence< css::beans::PropertyValue > Arguments;
+ css::uno::Reference< css::frame::XDispatch > Dispatch;
+};
+
+IMPL_STATIC_LINK( GalleryBrowser2, AsyncDispatch_Impl, void*, p, void )
+{
+ DispatchInfo* pDispatchInfo = static_cast<DispatchInfo*>(p);
+ if ( pDispatchInfo && pDispatchInfo->Dispatch.is() )
+ {
+ try
+ {
+ pDispatchInfo->Dispatch->dispatch( pDispatchInfo->TargetURL,
+ pDispatchInfo->Arguments );
+ }
+ catch ( const css::uno::Exception& )
+ {
+ }
+ }
+
+ delete pDispatchInfo;
+}
+
+namespace
+{
+
+struct CommandInfo
+{
+ css::util::URL URL;
+ css::uno::Reference< css::frame::XDispatch > Dispatch;
+
+ explicit CommandInfo( const OUString &rURL )
+ {
+ URL.Complete = rURL;
+ }
+};
+
+class GalleryThemePopup : public ::cppu::WeakImplHelper< css::frame::XStatusListener >
+{
+private:
+ const GalleryTheme* mpTheme;
+ sal_uInt32 mnObjectPos;
+ bool mbPreview;
+ std::unique_ptr<weld::Builder> mxBuilder;
+ std::unique_ptr<weld::Menu> mxPopupMenu;
+ std::unique_ptr<weld::Menu> mxBackgroundPopup;
+ GalleryBrowser2* mpBrowser;
+
+ typedef std::map< int, CommandInfo > CommandInfoMap;
+ CommandInfoMap m_aCommandInfo;
+
+ static void Execute( const CommandInfo &rCmdInfo,
+ const css::uno::Sequence< css::beans::PropertyValue > &rArguments );
+
+ void MenuSelectHdl(std::string_view rIdent);
+ void BackgroundMenuSelectHdl(sal_uInt16 nId);
+public:
+ GalleryThemePopup(weld::Widget* pParent,
+ const GalleryTheme* pTheme,
+ sal_uInt32 nObjectPos,
+ bool bPreview,
+ GalleryBrowser2* pBrowser);
+
+ void ExecutePopup(weld::Widget* pParent, const ::Point &rPos);
+
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent &rEvent) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject &rSource) override;
+};
+
+
+GalleryThemePopup::GalleryThemePopup(
+ weld::Widget* pParent,
+ const GalleryTheme* pTheme,
+ sal_uInt32 nObjectPos,
+ bool bPreview,
+ GalleryBrowser2* pBrowser )
+ : mpTheme( pTheme )
+ , mnObjectPos( nObjectPos )
+ , mbPreview( bPreview )
+ , mxBuilder(Application::CreateBuilder(pParent, "svx/ui/gallerymenu2.ui"))
+ , mxPopupMenu(mxBuilder->weld_menu("menu"))
+ , mxBackgroundPopup(mxBuilder->weld_menu("backgroundmenu"))
+ , mpBrowser( pBrowser )
+{
+ // SID_GALLERY_ENABLE_ADDCOPY
+ m_aCommandInfo.emplace(
+ SID_GALLERY_ENABLE_ADDCOPY,
+ CommandInfo( ".uno:GalleryEnableAddCopy" ));
+ // SID_GALLERY_BG_BRUSH
+ m_aCommandInfo.emplace(
+ SID_GALLERY_BG_BRUSH,
+ CommandInfo( ".uno:BackgroundImage" ));
+ // SID_GALLERY_FORMATS
+ m_aCommandInfo.emplace(
+ SID_GALLERY_FORMATS,
+ CommandInfo( ".uno:InsertGalleryPic" ));
+
+}
+
+void SAL_CALL GalleryThemePopup::statusChanged(
+ const css::frame::FeatureStateEvent &rEvent )
+{
+ const OUString &rURL = rEvent.FeatureURL.Complete;
+ if ( rURL == ".uno:GalleryEnableAddCopy" )
+ {
+ if ( !rEvent.IsEnabled )
+ {
+ mxPopupMenu->set_visible("add", false);
+ }
+ }
+ else if ( rURL == ".uno:BackgroundImage" )
+ {
+ mxBackgroundPopup->clear();
+ if ( rEvent.IsEnabled )
+ {
+ OUString sItem;
+ css::uno::Sequence< OUString > sItems;
+ if ( ( rEvent.State >>= sItem ) && sItem.getLength() )
+ {
+ mxBackgroundPopup->append(OUString::number(1), sItem);
+ }
+ else if ( ( rEvent.State >>= sItems ) && sItems.hasElements() )
+ {
+ sal_uInt16 nId = 1;
+ for ( const OUString& rStr : std::as_const(sItems) )
+ {
+ mxBackgroundPopup->append(OUString::number(nId), rStr);
+ nId++;
+ }
+ }
+ }
+ }
+}
+
+void SAL_CALL GalleryThemePopup::disposing(
+ const css::lang::EventObject &/*rSource*/)
+{
+}
+
+void GalleryThemePopup::Execute(
+ const CommandInfo &rCmdInfo,
+ const css::uno::Sequence< css::beans::PropertyValue > &rArguments )
+{
+ if ( rCmdInfo.Dispatch.is() )
+ {
+ std::unique_ptr<DispatchInfo> pInfo(new DispatchInfo);
+ pInfo->TargetURL = rCmdInfo.URL;
+ pInfo->Arguments = rArguments;
+ pInfo->Dispatch = rCmdInfo.Dispatch;
+
+ if ( Application::PostUserEvent(
+ LINK( nullptr, GalleryBrowser2, AsyncDispatch_Impl), pInfo.get() ) )
+ pInfo.release();
+ }
+}
+
+void GalleryThemePopup::ExecutePopup(weld::Widget* pParent, const ::Point &rPos)
+{
+ css::uno::Reference< css::frame::XStatusListener > xThis( this );
+
+ const SgaObjKind eObjKind = mpTheme->GetObjectKind( mnObjectPos );
+ INetURLObject aURL;
+
+ const_cast< GalleryTheme* >( mpTheme )->GetURL( mnObjectPos, aURL );
+ const bool bValidURL = ( aURL.GetProtocol() != INetProtocol::NotValid );
+
+ mxPopupMenu->set_visible("add", bValidURL && SgaObjKind::Sound != eObjKind);
+
+ mxPopupMenu->set_visible("preview", bValidURL);
+ mxPopupMenu->set_active("preview", mbPreview);
+
+ if( mpTheme->IsReadOnly() || !mpTheme->GetObjectCount() )
+ {
+ mxPopupMenu->set_visible("delete", false);
+ mxPopupMenu->set_visible("title", false);
+ if (mpTheme->IsReadOnly())
+ mxPopupMenu->set_visible("paste", false);
+
+ if (!mpTheme->GetObjectCount())
+ mxPopupMenu->set_visible("copy", false);
+ }
+ else
+ {
+ mxPopupMenu->set_visible("delete", !mbPreview);
+ mxPopupMenu->set_visible("title", true);
+ mxPopupMenu->set_visible("copy", true);
+ mxPopupMenu->set_visible("paste", true);
+ }
+
+ // update status
+ css::uno::Reference< css::frame::XDispatchProvider> xDispatchProvider(
+ GalleryBrowser2::GetFrame(), css::uno::UNO_QUERY );
+ css::uno::Reference< css::util::XURLTransformer > xTransformer(
+ mpBrowser->GetURLTransformer() );
+ for ( auto& rInfo : m_aCommandInfo )
+ {
+ try
+ {
+ CommandInfo &rCmdInfo = rInfo.second;
+ if ( xTransformer.is() )
+ xTransformer->parseStrict( rCmdInfo.URL );
+
+ if ( xDispatchProvider.is() )
+ {
+ rCmdInfo.Dispatch = xDispatchProvider->queryDispatch(
+ rCmdInfo.URL,
+ "_self",
+ css::frame::FrameSearchFlag::SELF );
+ }
+
+ if ( rCmdInfo.Dispatch.is() )
+ {
+ rCmdInfo.Dispatch->addStatusListener( this, rCmdInfo.URL );
+ rCmdInfo.Dispatch->removeStatusListener( this, rCmdInfo.URL );
+ }
+ }
+ catch ( ... )
+ {}
+ }
+
+ if( !mxBackgroundPopup->n_children() || ( eObjKind == SgaObjKind::SvDraw ) || ( eObjKind == SgaObjKind::Sound ) )
+ mxPopupMenu->set_visible("background", false);
+ else
+ mxPopupMenu->set_visible("background", true);
+
+ MenuSelectHdl(mxPopupMenu->popup_at_rect(pParent, tools::Rectangle(rPos, Size(1,1))));
+}
+
+void GalleryThemePopup::MenuSelectHdl(std::string_view rIdent)
+{
+ if (rIdent.empty())
+ return;
+
+ sal_uInt16 nSubMenuId = o3tl::toUInt32(rIdent);
+ if (nSubMenuId)
+ {
+ BackgroundMenuSelectHdl(nSubMenuId-1);
+ return;
+ }
+
+ if (rIdent == "add")
+ {
+ const CommandInfoMap::const_iterator it = m_aCommandInfo.find( SID_GALLERY_FORMATS );
+ if (it != m_aCommandInfo.end())
+ mpBrowser->DispatchAdd(it->second.Dispatch, it->second.URL);
+ }
+ else
+ mpBrowser->Execute(rIdent);
+}
+
+void GalleryThemePopup::BackgroundMenuSelectHdl(sal_uInt16 nPos)
+{
+ OUString aURL( mpBrowser->GetURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ OUString aFilterName( mpBrowser->GetFilterName() );
+
+ css::uno::Sequence< css::beans::PropertyValue > aArgs{
+ comphelper::makePropertyValue("Background.Transparent", sal_Int32( 0 )), // 0 - 100
+ comphelper::makePropertyValue("Background.BackColor", sal_Int32( - 1 )),
+ comphelper::makePropertyValue("Background.URL", aURL),
+ comphelper::makePropertyValue("Background.Filtername", aFilterName), // FIXME name should be FilterName
+ comphelper::makePropertyValue("Background.Position", css::style::GraphicLocation_TILED),
+ comphelper::makePropertyValue("Position", nPos)
+ };
+
+ const CommandInfoMap::const_iterator it = m_aCommandInfo.find( SID_GALLERY_BG_BRUSH );
+ if ( it != m_aCommandInfo.end() )
+ Execute( it->second, aArgs );
+}
+
+} // end anonymous namespace
+
+GalleryBrowser2::GalleryBrowser2(weld::Builder& rBuilder, Gallery* pGallery)
+ : mpGallery(pGallery)
+ , mpCurTheme(nullptr)
+ , mxIconView(new GalleryIconView(this, rBuilder.weld_scrolled_window("galleryscroll", true)))
+ , mxIconViewWin(new weld::CustomWeld(rBuilder, "gallery", *mxIconView))
+ , mxListView(rBuilder.weld_tree_view("gallerylist"))
+ , mxPreview(new GalleryPreview(this, rBuilder.weld_scrolled_window("previewscroll")))
+ , mxPreviewWin(new weld::CustomWeld(rBuilder, "preview", *mxPreview))
+ , mxIconButton(rBuilder.weld_toggle_button("icon"))
+ , mxListButton(rBuilder.weld_toggle_button("list"))
+ , mxInfoBar(rBuilder.weld_label("label"))
+ , maPreviewSize(28, 28)
+ , mnCurActionPos ( 0xffffffff )
+ , meMode ( GALLERYBROWSERMODE_NONE )
+ , meLastMode ( GALLERYBROWSERMODE_NONE )
+{
+ m_xContext.set( ::comphelper::getProcessComponentContext() );
+
+ int nHeight = mxListView->get_height_rows(10);
+ mxListView->set_size_request(-1, nHeight);
+ mxIconView->set_size_request(-1, nHeight);
+
+ m_xTransformer.set(
+ m_xContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.util.URLTransformer", m_xContext ),
+ css::uno::UNO_QUERY );
+
+ mxIconButton->set_help_id(HID_GALLERY_ICONVIEW);
+ mxListButton->set_help_id(HID_GALLERY_LISTVIEW);
+
+ mxIconButton->connect_toggled( LINK( this, GalleryBrowser2, SelectTbxHdl ) );
+ mxListButton->connect_toggled( LINK( this, GalleryBrowser2, SelectTbxHdl ) );
+
+ mxIconView->SetSelectHdl( LINK( this, GalleryBrowser2, SelectObjectValueSetHdl ) );
+ mxListView->connect_visible_range_changed(LINK(this, GalleryBrowser2, VisRowsScrolledHdl));
+ mxListView->connect_size_allocate(LINK(this, GalleryBrowser2, SizeAllocHdl));
+ mxListView->connect_changed( LINK( this, GalleryBrowser2, SelectObjectHdl ) );
+ mxListView->connect_popup_menu(LINK(this, GalleryBrowser2, PopupMenuHdl));
+ mxListView->connect_key_press(LINK(this, GalleryBrowser2, KeyInputHdl));
+ mxListView->connect_row_activated(LINK(this, GalleryBrowser2, RowActivatedHdl));
+ mxDragDropTargetHelper.reset(new GalleryDragDrop(this, mxListView->get_drop_target()));
+ mxListView->connect_drag_begin(LINK(this, GalleryBrowser2, DragBeginHdl));
+
+ mxListView->set_help_id(HID_GALLERY_WINDOW);
+
+ SetMode( ( GALLERYBROWSERMODE_PREVIEW != GalleryBrowser2::meInitMode ) ? GalleryBrowser2::meInitMode : GALLERYBROWSERMODE_ICON );
+}
+
+IMPL_LINK(GalleryBrowser2, PopupMenuHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+ ShowContextMenu(rCEvt);
+ return true;
+}
+
+IMPL_LINK(GalleryBrowser2, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return KeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(GalleryBrowser2, RowActivatedHdl, weld::TreeView&, bool)
+{
+ TogglePreview();
+ return true;
+}
+
+GalleryBrowser2::~GalleryBrowser2()
+{
+ if (mpCurTheme)
+ mpGallery->ReleaseTheme( mpCurTheme, *this );
+}
+
+void GalleryBrowser2::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const GalleryHint& rGalleryHint = static_cast<const GalleryHint&>(rHint);
+
+ switch( rGalleryHint.GetType() )
+ {
+ case GalleryHintType::THEME_UPDATEVIEW:
+ {
+ if( GALLERYBROWSERMODE_PREVIEW == GetMode() )
+ SetMode( meLastMode );
+
+ ImplUpdateViews( reinterpret_cast<size_t>(rGalleryHint.GetData1()) + 1 );
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+sal_Int8 GalleryBrowser2::AcceptDrop( const DropTargetHelper& rTarget )
+{
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( mpCurTheme && !mpCurTheme->IsReadOnly() )
+ {
+ if( !mpCurTheme->IsDragging() )
+ {
+ if( rTarget.IsDropFormatSupported( SotClipboardFormatId::DRAWING ) ||
+ rTarget.IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) ||
+ rTarget.IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
+ rTarget.IsDropFormatSupported( SotClipboardFormatId::SVXB ) ||
+ rTarget.IsDropFormatSupported( SotClipboardFormatId::GDIMETAFILE ) ||
+ rTarget.IsDropFormatSupported( SotClipboardFormatId::BITMAP ) )
+ {
+ nRet = DND_ACTION_COPY;
+ }
+ }
+ else
+ nRet = DND_ACTION_COPY;
+ }
+
+ return nRet;
+}
+
+sal_Int8 GalleryBrowser2::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( mpCurTheme )
+ {
+ Point aSelPos;
+ const sal_uInt32 nItemId = ImplGetSelectedItemId( &rEvt.maPosPixel, aSelPos );
+ const sal_uInt32 nInsertPos = (nItemId ? (nItemId - 1) : mpCurTheme->GetObjectCount());
+
+ if( mpCurTheme->IsDragging() )
+ mpCurTheme->ChangeObjectPos( mpCurTheme->GetDragPos(), nInsertPos );
+ else
+ nRet = mpCurTheme->InsertTransferable( rEvt.maDropEvent.Transferable, nInsertPos ) ? 1 : 0;
+ }
+
+ return nRet;
+}
+
+bool GalleryBrowser2::StartDrag()
+{
+ if (!mpCurTheme)
+ return true;
+ return m_xHelper->StartDrag();
+}
+
+IMPL_LINK(GalleryBrowser2, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+{
+ rUnsetDragIcon = false;
+ return StartDrag();
+}
+
+void GalleryBrowser2::TogglePreview()
+{
+ SetMode( ( GALLERYBROWSERMODE_PREVIEW != GetMode() ) ? GALLERYBROWSERMODE_PREVIEW : meLastMode );
+ GetViewWindow()->grab_focus();
+}
+
+void GalleryBrowser2::ShowContextMenu(const CommandEvent& rCEvt)
+{
+ Point aMousePos = rCEvt.GetMousePosPixel();
+ Point aSelPos;
+ const sal_uInt32 nItemId = ImplGetSelectedItemId( rCEvt.IsMouseEvent() ? &aMousePos : nullptr, aSelPos );
+
+ if( !(mpCurTheme && nItemId && ( nItemId <= mpCurTheme->GetObjectCount() )) )
+ return;
+
+ ImplSelectItemId( nItemId );
+
+ css::uno::Reference< css::frame::XFrame > xFrame( GetFrame() );
+ if ( !xFrame.is() )
+ return;
+
+ weld::Widget* pParent = GetViewWindow();
+ mnCurActionPos = nItemId - 1;
+ rtl::Reference< GalleryThemePopup > xPopup(
+ new GalleryThemePopup(
+ pParent,
+ mpCurTheme,
+ mnCurActionPos,
+ GALLERYBROWSERMODE_PREVIEW == GetMode(),
+ this ) );
+ xPopup->ExecutePopup(pParent, aSelPos);
+}
+
+bool GalleryBrowser2::ViewBoxHasFocus() const
+{
+ return mxIconButton->has_focus() || mxListButton->has_focus();
+}
+
+bool GalleryBrowser2::KeyInput(const KeyEvent& rKEvt)
+{
+ Point aSelPos;
+ const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos );
+ bool bRet = false;
+
+ if (!ViewBoxHasFocus() && nItemId && mpCurTheme)
+ {
+ OString sExecuteIdent;
+ INetURLObject aURL;
+
+ mpCurTheme->GetURL( nItemId - 1, aURL );
+
+ const bool bValidURL = ( aURL.GetProtocol() != INetProtocol::NotValid );
+ bool bPreview = bValidURL;
+ bool bDelete = false;
+ bool bTitle = false;
+
+ if( !mpCurTheme->IsReadOnly() && mpCurTheme->GetObjectCount() )
+ {
+ bDelete = ( GALLERYBROWSERMODE_PREVIEW != GetMode() );
+ bTitle = true;
+ }
+
+ switch( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_SPACE:
+ case KEY_RETURN:
+ case KEY_P:
+ {
+ if( bPreview )
+ {
+ TogglePreview();
+ bRet = true;
+ }
+ }
+ break;
+
+ case KEY_INSERT:
+ case KEY_I:
+ {
+ // Inserting a gallery item in the document must be dispatched
+ if( bValidURL )
+ {
+ DispatchAdd(css::uno::Reference<css::frame::XDispatch>(), css::util::URL());
+ return true;
+ }
+ }
+ break;
+
+ case KEY_DELETE:
+ case KEY_D:
+ {
+ if( bDelete )
+ sExecuteIdent = "delete";
+ }
+ break;
+
+ case KEY_T:
+ {
+ if( bTitle )
+ sExecuteIdent = "title";
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!sExecuteIdent.isEmpty())
+ {
+ Execute(sExecuteIdent);
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+void GalleryBrowser2::SelectTheme( std::u16string_view rThemeName )
+{
+ if( mpCurTheme )
+ mpGallery->ReleaseTheme( mpCurTheme, *this );
+
+ mpCurTheme = mpGallery->AcquireTheme( rThemeName, *this );
+
+ m_xHelper.set(new GalleryTransferable(mpCurTheme, 0, true));
+ rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
+ mxListView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+ mxIconView->SetDragDataTransferrable(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+ mxPreview->SetDragDataTransferrable(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+
+ mxIconView->SetTheme(mpCurTheme);
+ mxPreview->SetTheme(mpCurTheme);
+
+ if( GALLERYBROWSERMODE_PREVIEW == GetMode() )
+ meMode = meLastMode;
+
+ ImplUpdateViews( 1 );
+
+ bool bIconMode = (GALLERYBROWSERMODE_ICON == GetMode());
+ mxIconButton->set_sensitive(true);
+ mxListButton->set_sensitive(true);
+ mxIconButton->set_active(bIconMode);
+ mxListButton->set_active(!bIconMode);
+}
+
+void GalleryBrowser2::SetMode( GalleryBrowserMode eMode )
+{
+ if( GetMode() == eMode )
+ return;
+
+ meLastMode = GetMode();
+
+ switch( eMode )
+ {
+ case GALLERYBROWSERMODE_ICON:
+ {
+ mxListView->hide();
+
+ mxPreview->Hide();
+ mxPreview->SetGraphic( Graphic() );
+ GalleryPreview::PreviewMedia( INetURLObject() );
+
+ mxIconView->Show();
+
+ mxIconButton->set_sensitive(true);
+ mxListButton->set_sensitive(true);
+
+ mxIconButton->set_active(true);
+ mxListButton->set_active(false);
+ }
+ break;
+
+ case GALLERYBROWSERMODE_LIST:
+ {
+ mxIconView->Hide();
+
+ mxPreview->Hide();
+ mxPreview->SetGraphic( Graphic() );
+ GalleryPreview::PreviewMedia( INetURLObject() );
+
+ mxListView->show();
+ UpdateRows(true);
+
+ mxIconButton->set_sensitive(true);
+ mxListButton->set_sensitive(true);
+
+ mxIconButton->set_active(false);
+ mxListButton->set_active(true);
+ }
+ break;
+
+ case GALLERYBROWSERMODE_PREVIEW:
+ {
+ Graphic aGraphic;
+ Point aSelPos;
+ const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos );
+
+ if( nItemId )
+ {
+ const sal_uInt32 nPos = nItemId - 1;
+
+ mxIconView->Hide();
+ mxListView->hide();
+
+ if( mpCurTheme )
+ mpCurTheme->GetGraphic( nPos, aGraphic );
+
+ mxPreview->SetGraphic( aGraphic );
+ mxPreview->Show();
+
+ if( mpCurTheme && mpCurTheme->GetObjectKind( nPos ) == SgaObjKind::Sound )
+ GalleryPreview::PreviewMedia( mpCurTheme->GetObjectURL( nPos ) );
+
+ mxIconButton->set_sensitive(false);
+ mxListButton->set_sensitive(false);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ GalleryBrowser2::meInitMode = meMode = eMode;
+}
+
+weld::Widget* GalleryBrowser2::GetViewWindow() const
+{
+ weld::Widget* pRet;
+
+ switch( GetMode() )
+ {
+ case GALLERYBROWSERMODE_LIST: pRet = mxListView.get(); break;
+ case GALLERYBROWSERMODE_PREVIEW: pRet = mxPreview->GetDrawingArea(); break;
+
+ default:
+ pRet = mxIconView->GetDrawingArea();
+ break;
+ }
+
+ return pRet;
+}
+
+void GalleryBrowser2::Travel( GalleryBrowserTravel eTravel )
+{
+ if( !mpCurTheme )
+ return;
+
+ Point aSelPos;
+ const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos );
+
+ if( !nItemId )
+ return;
+
+ sal_uInt32 nNewItemId = nItemId;
+
+ switch( eTravel )
+ {
+ case GalleryBrowserTravel::First: nNewItemId = 1; break;
+ case GalleryBrowserTravel::Last: nNewItemId = mpCurTheme->GetObjectCount(); break;
+ case GalleryBrowserTravel::Previous: nNewItemId--; break;
+ case GalleryBrowserTravel::Next: nNewItemId++; break;
+ default:
+ break;
+ }
+
+ if( nNewItemId < 1 )
+ nNewItemId = 1;
+ else if( nNewItemId > mpCurTheme->GetObjectCount() )
+ nNewItemId = mpCurTheme->GetObjectCount();
+
+ if( nNewItemId == nItemId )
+ return;
+
+ ImplSelectItemId( nNewItemId );
+ ImplUpdateInfoBar();
+
+ if( GALLERYBROWSERMODE_PREVIEW != GetMode() )
+ return;
+
+ Graphic aGraphic;
+ const sal_uInt32 nPos = nNewItemId - 1;
+
+ mpCurTheme->GetGraphic( nPos, aGraphic );
+ mxPreview->SetGraphic( aGraphic );
+
+ if( SgaObjKind::Sound == mpCurTheme->GetObjectKind( nPos ) )
+ GalleryPreview::PreviewMedia( mpCurTheme->GetObjectURL( nPos ) );
+
+ mxPreview->Invalidate();
+}
+
+void GalleryBrowser2::ImplUpdateViews( sal_uInt16 nSelectionId )
+{
+ mxIconView->Hide();
+ mxListView->hide();
+ mxPreview->Hide();
+
+ mxIconView->Clear();
+ mxListView->clear();
+
+ if( mpCurTheme )
+ {
+ const int nAlwaysUpToDate = 15;
+
+ mxListView->freeze();
+
+ sal_uInt32 nCount = mpCurTheme->GetObjectCount();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ mxIconView->InsertItem(i + 1); // skip reserved id 0
+ mxListView->append(OUString::number(i), ""); // create on-demand in VisRowsScrolledHdl
+
+ if (i == nAlwaysUpToDate) // fill in the first block
+ UpdateRows(false);
+ }
+
+ if (nCount < nAlwaysUpToDate) // if less than block size, fill in all of them
+ UpdateRows(false);
+
+ mxListView->thaw();
+
+ ImplSelectItemId( std::min<sal_uInt16>( nSelectionId, mpCurTheme->GetObjectCount() ) );
+ }
+
+ switch( GetMode() )
+ {
+ case GALLERYBROWSERMODE_ICON: mxIconView->Show(); break;
+ case GALLERYBROWSERMODE_LIST:
+ mxListView->show();
+ UpdateRows(true);
+ break;
+ case GALLERYBROWSERMODE_PREVIEW: mxPreview->Show(); break;
+
+ default:
+ break;
+ }
+
+ ImplUpdateInfoBar();
+}
+
+void GalleryBrowser2::UpdateRows(bool bVisibleOnly)
+{
+ auto lambda = [this](weld::TreeIter& rEntry){
+ // id is non-null if the preview is pending creation
+ OUString sId(mxListView->get_id(rEntry));
+ if (sId.isEmpty())
+ return false;
+
+ // get the icon for the listview
+ BitmapEx aBitmapEx;
+ Size aPreparedSize;
+
+ OUString sItemTextTitle;
+ OUString sItemTextPath;
+
+ sal_Int32 i = sId.toUInt32();
+ mpCurTheme->GetPreviewBitmapExAndStrings(i, aBitmapEx, aPreparedSize, sItemTextTitle, sItemTextPath);
+
+ bool bNeedToCreate(aBitmapEx.IsEmpty());
+ if (!bNeedToCreate && (sItemTextTitle.isEmpty() || aPreparedSize != maPreviewSize))
+ bNeedToCreate = true;
+
+ if (bNeedToCreate)
+ {
+ std::unique_ptr<SgaObject> xObj = mpCurTheme->AcquireObject(i);
+ if (xObj)
+ {
+ aBitmapEx = xObj->createPreviewBitmapEx(maPreviewSize);
+ sItemTextTitle = GalleryBrowser2::GetItemText(*xObj, GalleryItemFlags::Title);
+ sItemTextPath = GalleryBrowser2::GetItemText(*xObj, GalleryItemFlags::Path);
+
+ mpCurTheme->SetPreviewBitmapExAndStrings(i, aBitmapEx, maPreviewSize, sItemTextTitle, sItemTextPath);
+ }
+ }
+
+ ScopedVclPtr<VirtualDevice> xDev(mxListView->create_virtual_device());
+ xDev->SetOutputSizePixel(maPreviewSize);
+
+ if (!aBitmapEx.IsEmpty())
+ {
+ const Size aBitmapExSizePixel(aBitmapEx.GetSizePixel());
+ const Point aPos(
+ ((maPreviewSize.Width() - aBitmapExSizePixel.Width()) >> 1),
+ ((maPreviewSize.Height() - aBitmapExSizePixel.Height()) >> 1));
+
+ if (aBitmapEx.IsAlpha())
+ {
+ // draw checkered background
+ GalleryIconView::drawTransparenceBackground(*xDev, aPos, aBitmapExSizePixel);
+ }
+
+ xDev->DrawBitmapEx(aPos, aBitmapEx);
+ }
+
+ mxListView->set_text(rEntry, sItemTextTitle);
+ mxListView->set_image(rEntry, *xDev);
+ mxListView->set_id(rEntry, OUString());
+
+ return false;
+ };
+
+ if (bVisibleOnly)
+ {
+ // ensure all visible entries are up to date
+ mxListView->visible_foreach(lambda);
+ // and ensure all selected entries are up to date
+ mxListView->selected_foreach(lambda);
+ return;
+ }
+
+ mxListView->all_foreach(lambda);
+}
+
+IMPL_LINK_NOARG(GalleryBrowser2, VisRowsScrolledHdl, weld::TreeView&, void)
+{
+ UpdateRows(true);
+}
+
+IMPL_LINK_NOARG(GalleryBrowser2, SizeAllocHdl, const Size&, void)
+{
+ UpdateRows(true);
+}
+
+void GalleryBrowser2::ImplUpdateInfoBar()
+{
+ if (!mpCurTheme)
+ return;
+ mxInfoBar->set_label( mpCurTheme->GetName() );
+}
+
+void GalleryBrowser2::ImplUpdateSelection()
+{
+ if (!mpCurTheme)
+ return;
+ auto nSelectedObject = (GALLERYBROWSERMODE_ICON == GetMode()) ? (mxIconView->GetSelectedItemId() - 1) : mxListView->get_selected_index();
+ m_xHelper->SelectObject(nSelectedObject);
+}
+
+sal_uInt32 GalleryBrowser2::ImplGetSelectedItemId( const Point* pSelPos, Point& rSelPos )
+{
+ sal_uInt32 nRet = 0;
+
+ if( GALLERYBROWSERMODE_PREVIEW == GetMode() )
+ {
+ nRet = ( ( GALLERYBROWSERMODE_ICON == meLastMode ) ? mxIconView->GetSelectedItemId() : ( mxListView->get_selected_index() + 1 ) );
+
+ if( pSelPos )
+ rSelPos = *pSelPos;
+ else
+ {
+ Size aOutputSizePixel(mxPreview->GetOutputSizePixel());
+ rSelPos = Point( aOutputSizePixel.Width() >> 1, aOutputSizePixel.Height() >> 1 );
+ }
+ }
+ else if (GALLERYBROWSERMODE_ICON == GetMode())
+ {
+ if (pSelPos)
+ {
+ nRet = mxIconView->GetItemId( *pSelPos );
+ rSelPos = *pSelPos;
+ }
+ else
+ {
+ nRet = mxIconView->GetSelectedItemId();
+ rSelPos = mxIconView->GetItemRect(nRet).Center();
+ }
+ }
+ else
+ {
+ std::unique_ptr<weld::TreeIter> xIter = mxListView->make_iterator();
+ if( pSelPos )
+ {
+ if (mxListView->get_dest_row_at_pos(*pSelPos, xIter.get(), false))
+ nRet = mxListView->get_iter_index_in_parent(*xIter) + 1;
+ rSelPos = *pSelPos;
+ }
+ else
+ {
+ if (mxListView->get_selected(xIter.get()))
+ {
+ nRet = mxListView->get_iter_index_in_parent(*xIter) + 1;
+ rSelPos = mxListView->get_row_area(*xIter).Center();
+ }
+ }
+ }
+
+ if( nRet && ( !mpCurTheme || ( nRet > mpCurTheme->GetObjectCount() ) ) )
+ {
+ nRet = 0;
+ }
+
+ return nRet;
+}
+
+void GalleryBrowser2::ImplSelectItemId(sal_uInt32 nItemId)
+{
+ if( nItemId )
+ {
+ mxIconView->SelectItem(nItemId);
+ mxListView->select( nItemId - 1 );
+ ImplUpdateSelection();
+ }
+}
+
+css::uno::Reference< css::frame::XFrame >
+GalleryBrowser2::GetFrame()
+{
+ css::uno::Reference< css::frame::XFrame > xFrame;
+ SfxViewFrame* pCurrentViewFrame = SfxViewFrame::Current();
+ if ( pCurrentViewFrame )
+ {
+ SfxBindings& rBindings = pCurrentViewFrame->GetBindings();
+ xFrame.set( rBindings.GetActiveFrame() );
+ }
+
+ return xFrame;
+}
+
+void GalleryBrowser2::DispatchAdd(
+ const css::uno::Reference< css::frame::XDispatch > &rxDispatch,
+ const css::util::URL &rURL)
+{
+ Point aSelPos;
+ const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos );
+
+ if( !mpCurTheme || !nItemId )
+ return;
+
+ mnCurActionPos = nItemId - 1;
+
+ css::uno::Reference< css::frame::XDispatch > xDispatch( rxDispatch );
+ css::util::URL aURL = rURL;
+
+ if ( !xDispatch.is() )
+ {
+ css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider(
+ GetFrame(), css::uno::UNO_QUERY );
+ if ( !xDispatchProvider.is() || !m_xTransformer.is() )
+ return;
+
+ aURL.Complete = ".uno:InsertGalleryPic";
+ m_xTransformer->parseStrict( aURL );
+ xDispatch = xDispatchProvider->queryDispatch(
+ aURL,
+ "_self",
+ css::frame::FrameSearchFlag::SELF );
+ }
+
+ if ( !xDispatch.is() )
+ return;
+
+ sal_Int8 nType = 0;
+ OUString aFilterName;
+ css::uno::Reference< css::lang::XComponent > xDrawing;
+ css::uno::Reference< css::graphic::XGraphic > xGraphic;
+
+ aFilterName = GetFilterName();
+
+ switch( mpCurTheme->GetObjectKind( mnCurActionPos ) )
+ {
+ case SgaObjKind::Bitmap:
+ case SgaObjKind::Animation:
+ case SgaObjKind::Inet:
+ // TODO drawing objects are inserted as drawings only via drag&drop
+ case SgaObjKind::SvDraw:
+ nType = css::gallery::GalleryItemType::GRAPHIC;
+ break;
+
+ case SgaObjKind::Sound :
+ nType = css::gallery::GalleryItemType::MEDIA;
+ break;
+
+ default:
+ nType = css::gallery::GalleryItemType::EMPTY;
+ break;
+ }
+
+ Graphic aGraphic;
+ bool bGraphic = mpCurTheme->GetGraphic( mnCurActionPos, aGraphic );
+ if ( bGraphic && !aGraphic.IsNone() )
+ xGraphic.set( aGraphic.GetXGraphic() );
+ OSL_ENSURE( xGraphic.is(), "gallery item is graphic, but the reference is invalid!" );
+
+ css::uno::Sequence< css::beans::PropertyValue > aSeq{
+ comphelper::makePropertyValue(SVXGALLERYITEM_TYPE, nType),
+ comphelper::makePropertyValue(SVXGALLERYITEM_URL, OUString()),
+ comphelper::makePropertyValue(SVXGALLERYITEM_FILTER, aFilterName),
+ comphelper::makePropertyValue(SVXGALLERYITEM_DRAWING, xDrawing),
+ comphelper::makePropertyValue(SVXGALLERYITEM_GRAPHIC, xGraphic)
+ };
+ assert(aSeq.getLength() == SVXGALLERYITEM_PARAMS);
+
+ css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
+ SVXGALLERYITEM_ARGNAME, aSeq) };
+
+ std::unique_ptr<DispatchInfo> pInfo(new DispatchInfo);
+ pInfo->TargetURL = aURL;
+ pInfo->Arguments = aArgs;
+ pInfo->Dispatch = xDispatch;
+
+ if ( Application::PostUserEvent(
+ LINK( nullptr, GalleryBrowser2, AsyncDispatch_Impl), pInfo.get() ) )
+ pInfo.release();
+}
+
+void GalleryBrowser2::Execute(std::string_view rIdent)
+{
+ Point aSelPos;
+ const sal_uInt32 nItemId = ImplGetSelectedItemId( nullptr, aSelPos );
+
+ if( !(mpCurTheme && nItemId) )
+ return;
+
+ mnCurActionPos = nItemId - 1;
+
+ if (rIdent == "preview")
+ SetMode( ( GALLERYBROWSERMODE_PREVIEW != GetMode() ) ? GALLERYBROWSERMODE_PREVIEW : meLastMode );
+ else if (rIdent == "delete")
+ {
+ if (!mpCurTheme->IsReadOnly())
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetViewWindow(), "svx/ui/querydeleteobjectdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteObjectDialog"));
+ if (xQuery->run() == RET_YES)
+ {
+ mpCurTheme->RemoveObject( mnCurActionPos );
+ }
+ }
+ }
+ else if (rIdent == "title")
+ {
+ std::unique_ptr<SgaObject> pObj = mpCurTheme->AcquireObject( mnCurActionPos );
+
+ if( pObj )
+ {
+ const OUString aOldTitle( GetItemText( *pObj, GalleryItemFlags::Title ) );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractTitleDialog> aDlg(pFact->CreateTitleDialog(GetViewWindow(), aOldTitle));
+ if( aDlg->Execute() == RET_OK )
+ {
+ OUString aNewTitle( aDlg->GetTitle() );
+
+ if( ( aNewTitle.isEmpty() && !pObj->GetTitle().isEmpty() ) || ( aNewTitle != aOldTitle ) )
+ {
+ if( aNewTitle.isEmpty() )
+ aNewTitle = "__<empty>__";
+
+ pObj->SetTitle( aNewTitle );
+ mpCurTheme->InsertObject( *pObj );
+ }
+ }
+ }
+ }
+ else if (rIdent == "copy")
+ {
+ mpCurTheme->CopyToClipboard(*GetViewWindow(), mnCurActionPos);
+ }
+ else if (rIdent == "paste")
+ {
+ if( !mpCurTheme->IsReadOnly() )
+ {
+ weld::Widget* pParent = GetViewWindow();
+ TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromClipboard(pParent->get_clipboard()));
+ mpCurTheme->InsertTransferable( aDataHelper.GetTransferable(), mnCurActionPos );
+ }
+ }
+}
+
+OUString GalleryBrowser2::GetItemText( const SgaObject& rObj, GalleryItemFlags nItemTextFlags )
+{
+ OUString aRet;
+
+ const INetURLObject& aURL(rObj.GetURL());
+
+ if( nItemTextFlags & GalleryItemFlags::Title )
+ {
+ OUString aTitle( rObj.GetTitle() );
+
+ if( aTitle.isEmpty() )
+ aTitle = aURL.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous );
+
+ if( aTitle.isEmpty() )
+ {
+ aTitle = aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+ aTitle = aTitle.copy( aTitle.lastIndexOf('/')+1 );
+ }
+
+ aRet += aTitle;
+ }
+
+ if( nItemTextFlags & GalleryItemFlags::Path )
+ {
+ const OUString aPath( aURL.getFSysPath( FSysStyle::Detect ) );
+
+ if( !aPath.isEmpty() && ( nItemTextFlags & GalleryItemFlags::Title ) )
+ aRet += " (";
+
+ aRet += aURL.getFSysPath( FSysStyle::Detect );
+
+ if( !aPath.isEmpty() && ( nItemTextFlags & GalleryItemFlags::Title ) )
+ aRet += ")";
+ }
+
+ return aRet;
+}
+
+INetURLObject GalleryBrowser2::GetURL() const
+{
+ INetURLObject aURL;
+
+ if( mpCurTheme && mnCurActionPos != 0xffffffff )
+ aURL = mpCurTheme->GetObjectURL( mnCurActionPos );
+
+ return aURL;
+}
+
+OUString GalleryBrowser2::GetFilterName() const
+{
+ OUString aFilterName;
+
+ if( mpCurTheme && mnCurActionPos != 0xffffffff )
+ {
+ const SgaObjKind eObjKind = mpCurTheme->GetObjectKind( mnCurActionPos );
+
+ if( ( SgaObjKind::Bitmap == eObjKind ) || ( SgaObjKind::Animation == eObjKind ) )
+ {
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ INetURLObject aURL;
+ mpCurTheme->GetURL( mnCurActionPos, aURL );
+ sal_uInt16 nFilter = rFilter.GetImportFormatNumberForShortName(aURL.GetFileExtension());
+
+ if( GRFILTER_FORMAT_DONTKNOW != nFilter )
+ aFilterName = rFilter.GetImportFormatName( nFilter );
+ }
+ }
+
+ return aFilterName;
+}
+
+IMPL_LINK_NOARG(GalleryBrowser2, SelectObjectValueSetHdl, ValueSet*, void)
+{
+ ImplUpdateSelection();
+}
+
+IMPL_LINK_NOARG(GalleryBrowser2, SelectObjectHdl, weld::TreeView&, void)
+{
+ ImplUpdateSelection();
+}
+
+IMPL_LINK(GalleryBrowser2, SelectTbxHdl, weld::Toggleable&, rBox, void)
+{
+ if (&rBox == mxIconButton.get())
+ SetMode(rBox.get_active() ? GALLERYBROWSERMODE_ICON : GALLERYBROWSERMODE_LIST);
+ else if (&rBox == mxListButton.get())
+ SetMode(rBox.get_active() ? GALLERYBROWSERMODE_LIST : GALLERYBROWSERMODE_ICON);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galctrl.cxx b/svx/source/gallery2/galctrl.cxx
new file mode 100644
index 000000000..ae9de1ce7
--- /dev/null
+++ b/svx/source/gallery2/galctrl.cxx
@@ -0,0 +1,408 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <avmedia/mediaplayer.hxx>
+#include <helpids.h>
+#include <galbrws2.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/galctrl.hxx>
+#include <galobj.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <vcl/event.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <bitmaps.hlst>
+
+GalleryPreview::GalleryPreview(GalleryBrowser2* pParent, std::unique_ptr<weld::ScrolledWindow> xScrolledWindow)
+ : mxScrolledWindow(std::move(xScrolledWindow))
+ , mpParent(pParent)
+ , mpTheme(nullptr)
+{
+}
+
+void GalleryPreview::Show()
+{
+ mxScrolledWindow->show();
+ weld::CustomWidgetController::Show();
+}
+
+void GalleryPreview::Hide()
+{
+ weld::CustomWidgetController::Hide();
+ mxScrolledWindow->hide();
+}
+
+GalleryPreview::~GalleryPreview()
+{
+}
+
+void GalleryPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize = pDrawingArea->get_ref_device().LogicToPixel(Size(70, 88), MapMode(MapUnit::MapAppFont));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+
+ pDrawingArea->set_help_id(HID_GALLERY_WINDOW);
+
+ mxDragDropTargetHelper.reset(new GalleryDragDrop(mpParent, pDrawingArea->get_drop_target()));
+}
+
+namespace
+{
+ bool ImplGetGraphicCenterRect(const weld::CustomWidgetController& rWidget, const Graphic& rGraphic, tools::Rectangle& rResultRect)
+ {
+ const Size aWinSize(rWidget.GetOutputSizePixel());
+ Size aNewSize(rWidget.GetDrawingArea()->get_ref_device().LogicToPixel(rGraphic.GetPrefSize(), rGraphic.GetPrefMapMode()));
+ bool bRet = false;
+
+ if( aNewSize.Width() && aNewSize.Height() )
+ {
+ // scale to fit window
+ const double fGrfWH = static_cast<double>(aNewSize.Width()) / aNewSize.Height();
+ const double fWinWH = static_cast<double>(aWinSize.Width()) / aWinSize.Height();
+
+ if ( fGrfWH < fWinWH )
+ {
+ aNewSize.setWidth( static_cast<tools::Long>( aWinSize.Height() * fGrfWH ) );
+ aNewSize.setHeight( aWinSize.Height() );
+ }
+ else
+ {
+ aNewSize.setWidth( aWinSize.Width() );
+ aNewSize.setHeight( static_cast<tools::Long>( aWinSize.Width() / fGrfWH) );
+ }
+
+ const Point aNewPos( ( aWinSize.Width() - aNewSize.Width() ) >> 1,
+ ( aWinSize.Height() - aNewSize.Height() ) >> 1 );
+
+ rResultRect = tools::Rectangle( aNewPos, aNewSize );
+ bRet = true;
+ }
+
+ return bRet;
+ }
+}
+
+bool GalleryPreview::ImplGetGraphicCenterRect( const Graphic& rGraphic, tools::Rectangle& rResultRect ) const
+{
+ return ::ImplGetGraphicCenterRect(*this, rGraphic, rResultRect);
+}
+
+void GalleryPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
+{
+ rRenderContext.SetBackground(Wallpaper(GALLERY_BG_COLOR));
+ rRenderContext.Erase();
+
+ if (ImplGetGraphicCenterRect(aGraphicObj.GetGraphic(), aPreviewRect))
+ {
+ const Point aPos( aPreviewRect.TopLeft() );
+ const Size aSize( aPreviewRect.GetSize() );
+
+ if( aGraphicObj.IsAnimated() )
+ aGraphicObj.StartAnimation(rRenderContext, aPos, aSize);
+ else
+ aGraphicObj.Draw(rRenderContext, aPos, aSize);
+ }
+}
+
+bool GalleryPreview::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if (mpTheme && (rMEvt.GetClicks() == 2))
+ mpParent->TogglePreview();
+ return true;
+}
+
+bool GalleryPreview::Command(const CommandEvent& rCEvt)
+{
+ if (mpTheme && (rCEvt.GetCommand() == CommandEventId::ContextMenu))
+ {
+ mpParent->ShowContextMenu(rCEvt);
+ return true;
+ }
+ return false;
+}
+
+bool GalleryPreview::KeyInput(const KeyEvent& rKEvt)
+{
+ if(mpTheme)
+ {
+ GalleryBrowser2* pBrowser = mpParent;
+
+ switch( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_BACKSPACE:
+ pBrowser->TogglePreview();
+ break;
+
+ case KEY_HOME:
+ pBrowser->Travel( GalleryBrowserTravel::First );
+ break;
+
+ case KEY_END:
+ pBrowser->Travel( GalleryBrowserTravel::Last );
+ break;
+
+ case KEY_LEFT:
+ case KEY_UP:
+ pBrowser->Travel( GalleryBrowserTravel::Previous );
+ break;
+
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ pBrowser->Travel( GalleryBrowserTravel::Next );
+ break;
+
+ default:
+ {
+ if (!pBrowser->KeyInput(rKEvt))
+ return false;
+ }
+ break;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool GalleryPreview::StartDrag()
+{
+ if (mpTheme)
+ return mpParent->StartDrag();
+ return true;
+}
+
+void GalleryPreview::PreviewMedia( const INetURLObject& rURL )
+{
+#if HAVE_FEATURE_AVMEDIA
+ if (rURL.GetProtocol() == INetProtocol::NotValid)
+ return;
+
+ ::avmedia::MediaFloater* pFloater = avmedia::getMediaFloater();
+
+ if (!pFloater)
+ {
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ pViewFrm->GetBindings().GetDispatcher()->Execute( SID_AVMEDIA_PLAYER, SfxCallMode::SYNCHRON );
+ pFloater = avmedia::getMediaFloater();
+ }
+
+ if (pFloater)
+ pFloater->setURL( rURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ), "", true );
+#else
+ (void) rURL;
+#endif
+}
+
+DialogGalleryPreview::DialogGalleryPreview()
+{
+}
+
+void DialogGalleryPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(70, 88), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ pDrawingArea->set_help_id(HID_GALLERY_WINDOW);
+}
+
+bool DialogGalleryPreview::SetGraphic( const INetURLObject& _aURL )
+{
+ bool bRet = true;
+ Graphic aGraphic;
+#if HAVE_FEATURE_AVMEDIA
+ if( ::avmedia::MediaWindow::isMediaURL( _aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ), "" ) )
+ {
+ aGraphic = BitmapEx(RID_SVXBMP_GALLERY_MEDIA);
+ }
+ else
+#endif
+ {
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ GalleryProgress aProgress( &rFilter );
+ if( rFilter.ImportGraphic( aGraphic, _aURL ) )
+ bRet = false;
+ }
+
+ SetGraphic( aGraphic );
+ Invalidate();
+ return bRet;
+}
+
+bool DialogGalleryPreview::ImplGetGraphicCenterRect( const Graphic& rGraphic, tools::Rectangle& rResultRect ) const
+{
+ return ::ImplGetGraphicCenterRect(*this, rGraphic, rResultRect);
+}
+
+void DialogGalleryPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.SetBackground(Wallpaper(GALLERY_BG_COLOR));
+
+ if (ImplGetGraphicCenterRect(aGraphicObj.GetGraphic(), aPreviewRect))
+ {
+ const Point aPos( aPreviewRect.TopLeft() );
+ const Size aSize( aPreviewRect.GetSize() );
+
+ if( aGraphicObj.IsAnimated() )
+ aGraphicObj.StartAnimation(rRenderContext, aPos, aSize);
+ else
+ aGraphicObj.Draw(rRenderContext, aPos, aSize);
+ }
+}
+
+void GalleryIconView::drawTransparenceBackground(vcl::RenderContext& rOut, const Point& rPos, const Size& rSize)
+{
+ // draw checkered background
+ static const sal_uInt32 nLen(8);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+
+ rOut.DrawCheckered(rPos, rSize, nLen, aW, aG);
+}
+
+GalleryIconView::GalleryIconView(GalleryBrowser2* pParent, std::unique_ptr<weld::ScrolledWindow> xScrolledWindow)
+ : ValueSet(std::move(xScrolledWindow))
+ , mpParent(pParent)
+ , mpTheme(nullptr)
+{
+}
+
+GalleryIconView::~GalleryIconView()
+{
+}
+
+void GalleryIconView::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ValueSet::SetDrawingArea(pDrawingArea);
+
+ SetStyle(GetStyle() | WB_TABSTOP | WB_3DLOOK | WB_BORDER | WB_ITEMBORDER | WB_DOUBLEBORDER | WB_VSCROLL | WB_FLATVALUESET);
+ EnableFullItemMode( false );
+
+ SetHelpId( HID_GALLERY_WINDOW );
+ SetExtraSpacing( 2 );
+ SetItemWidth( S_THUMB + 6 );
+ SetItemHeight( S_THUMB + 6 );
+
+ mxDragDropTargetHelper.reset(new GalleryDragDrop(mpParent, pDrawingArea->get_drop_target()));
+}
+
+void GalleryIconView::UserDraw(const UserDrawEvent& rUDEvt)
+{
+ const sal_uInt16 nId = rUDEvt.GetItemId();
+
+ if (!nId || !mpTheme)
+ return;
+
+ const tools::Rectangle& rRect = rUDEvt.GetRect();
+ const Size aSize(rRect.GetWidth(), rRect.GetHeight());
+ BitmapEx aBitmapEx;
+ Size aPreparedSize;
+ OUString aItemTextTitle;
+ OUString aItemTextPath;
+
+ mpTheme->GetPreviewBitmapExAndStrings(nId - 1, aBitmapEx, aPreparedSize, aItemTextTitle, aItemTextPath);
+
+ bool bNeedToCreate(aBitmapEx.IsEmpty());
+
+ if (!bNeedToCreate && aItemTextTitle.isEmpty())
+ {
+ bNeedToCreate = true;
+ }
+
+ if (!bNeedToCreate && aPreparedSize != aSize)
+ {
+ bNeedToCreate = true;
+ }
+
+ if (bNeedToCreate)
+ {
+ std::unique_ptr<SgaObject> pObj = mpTheme->AcquireObject(nId - 1);
+
+ if(pObj)
+ {
+ aBitmapEx = pObj->createPreviewBitmapEx(aSize);
+ aItemTextTitle = GalleryBrowser2::GetItemText(*pObj, GalleryItemFlags::Title);
+
+ mpTheme->SetPreviewBitmapExAndStrings(nId - 1, aBitmapEx, aSize, aItemTextTitle, aItemTextPath);
+ }
+ }
+
+ if (!aBitmapEx.IsEmpty())
+ {
+ const Size aBitmapExSizePixel(aBitmapEx.GetSizePixel());
+ const Point aPos(
+ ((aSize.Width() - aBitmapExSizePixel.Width()) >> 1) + rRect.Left(),
+ ((aSize.Height() - aBitmapExSizePixel.Height()) >> 1) + rRect.Top());
+ OutputDevice* pDev = rUDEvt.GetRenderContext();
+
+ if(aBitmapEx.IsAlpha())
+ {
+ // draw checkered background for full rectangle.
+ GalleryIconView::drawTransparenceBackground(*pDev, rRect.TopLeft(), rRect.GetSize());
+ }
+
+ pDev->DrawBitmapEx(aPos, aBitmapEx);
+ }
+
+ SetItemText(nId, aItemTextTitle);
+}
+
+bool GalleryIconView::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bRet = ValueSet::MouseButtonDown(rMEvt);
+
+ if (rMEvt.GetClicks() == 2)
+ mpParent->TogglePreview();
+
+ return bRet;
+}
+
+bool GalleryIconView::Command(const CommandEvent& rCEvt)
+{
+ bool bRet = ValueSet::Command(rCEvt);
+
+ if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
+ {
+ mpParent->ShowContextMenu(rCEvt);
+ }
+
+ return bRet;
+}
+
+bool GalleryIconView::KeyInput(const KeyEvent& rKEvt)
+{
+ if (!mpTheme || !mpParent->KeyInput(rKEvt))
+ return ValueSet::KeyInput(rKEvt);
+ return true;
+}
+
+bool GalleryIconView::StartDrag()
+{
+ Select();
+ return mpParent->StartDrag();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galexpl.cxx b/svx/source/gallery2/galexpl.cxx
new file mode 100644
index 000000000..b1e70919c
--- /dev/null
+++ b/svx/source/gallery2/galexpl.cxx
@@ -0,0 +1,299 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/gallery1.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/gallery.hxx>
+#include <galobj.hxx>
+
+namespace
+{
+ SfxListener& theLockListener()
+ {
+ static SfxListener SINGLETON;
+ return SINGLETON;
+ }
+}
+
+
+bool GalleryExplorer::FillThemeList( std::vector<OUString>& rThemeList )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+
+ if( pGal )
+ {
+ for( sal_uInt32 i = 0, nCount = pGal->GetThemeCount(); i < nCount; i++ )
+ {
+ const GalleryThemeEntry* pEntry = pGal->GetThemeInfo( i );
+
+ if( pEntry && !pEntry->IsReadOnly() && !pEntry->IsHidden() )
+ rThemeList.push_back(pEntry->GetThemeName());
+ }
+ }
+
+ return !rThemeList.empty();
+}
+
+bool GalleryExplorer::FillObjList( std::u16string_view rThemeName, std::vector<OUString> &rObjList )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ for( sal_uInt32 i = 0, nCount = pTheme->GetObjectCount(); i < nCount; i++ )
+ rObjList.push_back( pTheme->GetObjectURL( i ).GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+
+ return !rObjList.empty();
+}
+
+bool GalleryExplorer::FillObjList( const sal_uInt32 nThemeId, std::vector<OUString> &rObjList )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+
+ if (!pGal)
+ return false;
+
+ return FillObjList( pGal->GetThemeName( nThemeId ), rObjList );
+}
+
+bool GalleryExplorer::FillObjListTitle( const sal_uInt32 nThemeId, std::vector< OUString >& rList )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( pGal->GetThemeName( nThemeId ), aListener );
+
+ if( pTheme )
+ {
+ for( sal_uInt32 i = 0, nCount = pTheme->GetObjectCount(); i < nCount; i++ )
+ {
+ std::unique_ptr<SgaObject> pObj = pTheme->AcquireObject( i );
+ if ( pObj )
+ {
+ OUString aTitle( pObj->GetTitle() );
+ rList.push_back( aTitle );
+ }
+ }
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+ return !rList.empty();
+}
+
+bool GalleryExplorer::InsertURL( std::u16string_view rThemeName, std::u16string_view rURL )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ bool bRet = false;
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ INetURLObject aURL( rURL );
+ DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+ bRet = pTheme->InsertURL( aURL );
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryExplorer::InsertURL( sal_uInt32 nThemeId, std::u16string_view rURL )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return pGal && InsertURL( pGal->GetThemeName( nThemeId ), rURL );
+}
+
+bool GalleryExplorer::GetGraphicObj( std::u16string_view rThemeName, sal_uInt32 nPos,
+ Graphic* pGraphic )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ bool bRet = false;
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ if( pGraphic )
+ bRet = bRet || pTheme->GetGraphic( nPos, *pGraphic );
+
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryExplorer::GetGraphicObj( sal_uInt32 nThemeId, sal_uInt32 nPos,
+ Graphic* pGraphic )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return pGal && GetGraphicObj( pGal->GetThemeName( nThemeId ), nPos, pGraphic );
+}
+
+sal_uInt32 GalleryExplorer::GetSdrObjCount( std::u16string_view rThemeName )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ sal_uInt32 nRet = 0;
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ for( sal_uInt32 i = 0, nCount = pTheme->GetObjectCount(); i < nCount; i++ )
+ if( SgaObjKind::SvDraw == pTheme->GetObjectKind( i ) )
+ nRet++;
+
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+
+ return nRet;
+}
+
+sal_uInt32 GalleryExplorer::GetSdrObjCount( sal_uInt32 nThemeId )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return( pGal ? GetSdrObjCount( pGal->GetThemeName( nThemeId ) ) : 0 );
+}
+
+bool GalleryExplorer::GetSdrObj( std::u16string_view rThemeName, sal_uInt32 nSdrModelPos,
+ SdrModel* pModel, BitmapEx* pThumb )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ bool bRet = false;
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ for( sal_uInt32 i = 0, nCount = pTheme->GetObjectCount(), nActPos = 0; ( i < nCount ) && !bRet; i++ )
+ {
+ if( SgaObjKind::SvDraw == pTheme->GetObjectKind( i ) )
+ {
+ if( nActPos++ == nSdrModelPos )
+ {
+ if( pModel )
+ bRet = pTheme->GetModel(i, *pModel);
+
+ if( pThumb )
+ bRet = bRet || pTheme->GetThumb( i, *pThumb );
+ }
+ }
+ }
+
+ pGal->ReleaseTheme( pTheme, aListener );
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryExplorer::GetSdrObj( sal_uInt32 nThemeId, sal_uInt32 nSdrModelPos,
+ SdrModel* pModel, BitmapEx* pThumb )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return pGal && GetSdrObj( pGal->GetThemeName( nThemeId ), nSdrModelPos, pModel, pThumb );
+}
+
+bool GalleryExplorer::BeginLocking( std::u16string_view rThemeName )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ bool bRet = false;
+
+ if( pGal )
+ {
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, theLockListener() );
+
+ if( pTheme )
+ {
+ pTheme->LockTheme();
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryExplorer::BeginLocking( sal_uInt32 nThemeId )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return pGal && BeginLocking( pGal->GetThemeName( nThemeId ) );
+}
+
+bool GalleryExplorer::EndLocking( std::u16string_view rThemeName )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ bool bRet = false;
+
+ if( pGal )
+ {
+ SfxListener aListener;
+ GalleryTheme* pTheme = pGal->AcquireTheme( rThemeName, aListener );
+
+ if( pTheme )
+ {
+ const bool bReleaseLockedTheme = pTheme->UnlockTheme();
+
+ // release acquired theme
+ pGal->ReleaseTheme( pTheme, aListener );
+
+ if( bReleaseLockedTheme )
+ {
+ // release locked theme
+ pGal->ReleaseTheme( pTheme, theLockListener() );
+ bRet = true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryExplorer::EndLocking( sal_uInt32 nThemeId )
+{
+ Gallery* pGal = ::Gallery::GetGalleryInstance();
+ return pGal && EndLocking( pGal->GetThemeName( nThemeId ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galini.cxx b/svx/source/gallery2/galini.cxx
new file mode 100644
index 000000000..8cdfb23ae
--- /dev/null
+++ b/svx/source/gallery2/galini.cxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ * The world's quickest and lamest .desktop / .ini file parser.
+ * Ideally the .thm file would move to a .desktop file in
+ * future.
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <unotools/ucbstreamhelper.hxx>
+#include <svx/gallerybinaryengineentry.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <o3tl/string_view.hxx>
+#include <memory>
+
+OUString GalleryBinaryEngineEntry::ReadStrFromIni(std::u16string_view aKeyName ) const
+{
+ std::unique_ptr<SvStream> pStrm(::utl::UcbStreamHelper::CreateStream(
+ GetStrURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ StreamMode::READ ));
+
+ const LanguageTag &rLangTag = Application::GetSettings().GetUILanguageTag();
+
+ ::std::vector< OUString > aFallbacks = rLangTag.getFallbackStrings( true);
+
+ OUString aResult;
+ sal_Int32 nRank = 42;
+
+ if( pStrm )
+ {
+ OString aLine;
+ while( pStrm->ReadLine( aLine ) )
+ {
+ OUString aKey;
+ OUString aLocale;
+ OUString aValue;
+ sal_Int32 n;
+
+ // comments
+ if( aLine.startsWith( "#" ) )
+ continue;
+
+ // a[en_US] = Bob
+ if( ( n = aLine.indexOf( '=' ) ) >= 1)
+ {
+ aKey = OStringToOUString(
+ o3tl::trim(aLine.subView( 0, n )), RTL_TEXTENCODING_ASCII_US );
+ aValue = OStringToOUString(
+ o3tl::trim(aLine.subView( n + 1 )), RTL_TEXTENCODING_UTF8 );
+
+ if( ( n = aKey.indexOf( '[' ) ) >= 1 )
+ {
+ aLocale = o3tl::trim(aKey.subView( n + 1 ));
+ aKey = o3tl::trim(aKey.subView( 0, n ));
+ if( (n = aLocale.indexOf( ']' ) ) >= 1 )
+ aLocale = o3tl::trim(aLocale.subView( 0, n ));
+ }
+ }
+ SAL_INFO("svx", "ini file has '" << aKey << "' [ '" << aLocale << "' ] = '" << aValue << "'");
+
+ // grisly language matching, is this not available somewhere else?
+ if( aKey == aKeyName )
+ {
+ /* FIXME-BCP47: what is this supposed to do? */
+ n = 0;
+ OUString aLang = aLocale.replace('_','-');
+ for( const auto& rFallback : aFallbacks )
+ {
+ SAL_INFO( "svx", "compare '" << aLang << "' with '" << rFallback << "' rank " << nRank << " vs. " << n );
+ if( rFallback == aLang && n < nRank ) {
+ nRank = n; // try to get the most accurate match
+ aResult = aValue;
+ }
+ ++n;
+ }
+ }
+ }
+ }
+
+ SAL_INFO( "svx", "readStrFromIni returns '" << aResult << "'");
+ return aResult;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallery1.cxx b/svx/source/gallery2/gallery1.cxx
new file mode 100644
index 000000000..3d412eacb
--- /dev/null
+++ b/svx/source/gallery2/gallery1.cxx
@@ -0,0 +1,724 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#if defined(MACOSX) && HAVE_FEATURE_READONLY_INSTALLSET
+#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
+#include <premac.h>
+#include <Foundation/Foundation.h>
+#include <postmac.h>
+#endif
+
+#include <sal/config.h>
+
+#include <comphelper/processfactory.hxx>
+#include <ucbhelper/content.hxx>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <o3tl/string_view.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/gallery.hxx>
+#include <svx/galleryobjectcollection.hxx>
+#include <svx/strings.hrc>
+#include <strings.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/gallery1.hxx>
+#include <svx/gallerybinaryengineentry.hxx>
+#include <vcl/weld.hxx>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <memory>
+
+
+using namespace ::com::sun::star;
+
+
+const std::pair<sal_uInt16, rtl::OUStringConstExpr> aUnlocalized[] =
+{
+ { GALLERY_THEME_HOMEPAGE, RID_GALLERYSTR_THEME_HTMLBUTTONS },
+ { GALLERY_THEME_POWERPOINT, RID_GALLERYSTR_THEME_POWERPOINT },
+ { GALLERY_THEME_USERSOUNDS, RID_GALLERYSTR_THEME_USERSOUNDS },
+ { GALLERY_THEME_DUMMY5, RID_GALLERYSTR_THEME_DUMMY5 },
+ { GALLERY_THEME_RULERS, RID_GALLERYSTR_THEME_RULERS },
+ { GALLERY_THEME_FONTWORK, RID_GALLERYSTR_THEME_FONTWORK },
+ { GALLERY_THEME_FONTWORK_VERTICAL, RID_GALLERYSTR_THEME_FONTWORK_VERTICAL }
+};
+
+const std::pair<sal_uInt16, TranslateId> aLocalized[] =
+{
+ { RID_GALLERY_THEME_3D, RID_GALLERYSTR_THEME_3D },
+ { RID_GALLERY_THEME_ANIMATIONS, RID_GALLERYSTR_THEME_ANIMATIONS },
+ { RID_GALLERY_THEME_BULLETS, RID_GALLERYSTR_THEME_BULLETS },
+ { RID_GALLERY_THEME_OFFICE, RID_GALLERYSTR_THEME_OFFICE },
+ { RID_GALLERY_THEME_FLAGS, RID_GALLERYSTR_THEME_FLAGS },
+ { RID_GALLERY_THEME_FLOWCHARTS, RID_GALLERYSTR_THEME_FLOWCHARTS },
+ { RID_GALLERY_THEME_EMOTICONS, RID_GALLERYSTR_THEME_EMOTICONS },
+ { RID_GALLERY_THEME_PHOTOS, RID_GALLERYSTR_THEME_PHOTOS },
+ { RID_GALLERY_THEME_BACKGROUNDS, RID_GALLERYSTR_THEME_BACKGROUNDS },
+ { RID_GALLERY_THEME_HOMEPAGE, RID_GALLERYSTR_THEME_HOMEPAGE },
+ { RID_GALLERY_THEME_INTERACTION, RID_GALLERYSTR_THEME_INTERACTION },
+ { RID_GALLERY_THEME_MAPS, RID_GALLERYSTR_THEME_MAPS },
+ { RID_GALLERY_THEME_PEOPLE, RID_GALLERYSTR_THEME_PEOPLE },
+ { RID_GALLERY_THEME_SURFACES, RID_GALLERYSTR_THEME_SURFACES },
+ { RID_GALLERY_THEME_SOUNDS, RID_GALLERYSTR_THEME_SOUNDS },
+ { RID_GALLERY_THEME_SYMBOLS, RID_GALLERYSTR_THEME_SYMBOLS },
+ { RID_GALLERY_THEME_MYTHEME, RID_GALLERYSTR_THEME_MYTHEME },
+
+ { RID_GALLERY_THEME_ARROWS, RID_GALLERYSTR_THEME_ARROWS },
+ { RID_GALLERY_THEME_BALLOONS, RID_GALLERYSTR_THEME_BALLOONS },
+ { RID_GALLERY_THEME_KEYBOARD, RID_GALLERYSTR_THEME_KEYBOARD },
+ { RID_GALLERY_THEME_TIME, RID_GALLERYSTR_THEME_TIME },
+ { RID_GALLERY_THEME_PRESENTATION, RID_GALLERYSTR_THEME_PRESENTATION },
+ { RID_GALLERY_THEME_CALENDAR, RID_GALLERYSTR_THEME_CALENDAR },
+ { RID_GALLERY_THEME_NAVIGATION, RID_GALLERYSTR_THEME_NAVIGATION },
+ { RID_GALLERY_THEME_COMMUNICATION, RID_GALLERYSTR_THEME_COMMUNICATION },
+ { RID_GALLERY_THEME_FINANCES, RID_GALLERYSTR_THEME_FINANCES },
+ { RID_GALLERY_THEME_COMPUTER, RID_GALLERYSTR_THEME_COMPUTER },
+
+ { RID_GALLERY_THEME_CLIMA, RID_GALLERYSTR_THEME_CLIMA },
+ { RID_GALLERY_THEME_EDUCATION, RID_GALLERYSTR_THEME_EDUCATION },
+ { RID_GALLERY_THEME_TROUBLE, RID_GALLERYSTR_THEME_TROUBLE },
+ { RID_GALLERY_THEME_SCREENBEANS, RID_GALLERYSTR_THEME_SCREENBEANS },
+
+ { RID_GALLERY_THEME_COMPUTERS, RID_GALLERYSTR_THEME_COMPUTERS },
+ { RID_GALLERY_THEME_DIAGRAMS, RID_GALLERYSTR_THEME_DIAGRAMS },
+ { RID_GALLERY_THEME_ENVIRONMENT, RID_GALLERYSTR_THEME_ENVIRONMENT },
+ { RID_GALLERY_THEME_FINANCE, RID_GALLERYSTR_THEME_FINANCE },
+ { RID_GALLERY_THEME_TRANSPORT, RID_GALLERYSTR_THEME_TRANSPORT },
+ { RID_GALLERY_THEME_TXTSHAPES, RID_GALLERYSTR_THEME_TXTSHAPES }
+};
+
+GalleryThemeEntry::GalleryThemeEntry( bool bCreateUniqueURL,
+ const INetURLObject& rBaseURL, const OUString& rName,
+ bool _bReadOnly, bool _bNewFile,
+ sal_uInt32 _nId, bool _bThemeNameFromResource ) :
+ nId ( _nId ),
+ bReadOnly ( _bReadOnly ),
+ bThemeNameFromResource ( _bThemeNameFromResource )
+{
+ INetURLObject aURL( rBaseURL );
+ DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+
+ if (bCreateUniqueURL)
+ {
+ GalleryBinaryEngineEntry::CreateUniqueURL(rBaseURL,aURL);
+ }
+
+ mpGalleryStorageEngineEntry = std::make_unique<GalleryBinaryEngineEntry>();
+ setStorageLocations(aURL);
+
+ SetModified( _bNewFile );
+
+ aName = mpGalleryStorageEngineEntry->ReadStrFromIni( u"name" );
+
+ // This is awful - we shouldn't use these resources if we
+ // possibly can avoid them
+ if( aName.isEmpty() && nId && bThemeNameFromResource )
+ {
+ //some of these are supposed to *not* be localized
+ //so catch them before looking up the resource
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aUnlocalized); ++i)
+ {
+ if (aUnlocalized[i].first == nId)
+ {
+ aName = aUnlocalized[i].second;
+ break;
+ }
+ }
+ //look up the rest of the ids in string resources
+ if (aName.isEmpty())
+ {
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aLocalized); ++i)
+ {
+ if (aLocalized[i].first == nId)
+ {
+ aName = SvxResId(aLocalized[i].second);
+ break;
+ }
+ }
+ }
+ }
+
+ if( aName.isEmpty() )
+ aName = rName;
+}
+
+void GalleryThemeEntry::setStorageLocations(INetURLObject & rURL)
+{
+ mpGalleryStorageEngineEntry->setStorageLocations(rURL);
+}
+
+GalleryTheme* GalleryThemeEntry::createGalleryTheme(Gallery* pGallery)
+{
+ return new GalleryTheme(pGallery,this);
+}
+
+std::unique_ptr<GalleryBinaryEngine> GalleryThemeEntry::createGalleryStorageEngine(GalleryObjectCollection& mrGalleryObjectCollection)
+{
+ return mpGalleryStorageEngineEntry->createGalleryStorageEngine(mrGalleryObjectCollection, bReadOnly);
+}
+
+void GalleryTheme::InsertAllThemes(weld::ComboBox& rListBox)
+{
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aUnlocalized); ++i)
+ rListBox.append_text(aUnlocalized[i].second);
+
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aLocalized); ++i)
+ rListBox.append_text(SvxResId(aLocalized[i].second));
+}
+
+void GalleryThemeEntry::SetName( const OUString& rNewName )
+{
+ if( aName != rNewName )
+ {
+ aName = rNewName;
+ SetModified( true );
+ bThemeNameFromResource = false;
+ }
+}
+
+void GalleryThemeEntry::SetId( sal_uInt32 nNewId, bool bResetThemeName )
+{
+ nId = nNewId;
+ SetModified( true );
+ bThemeNameFromResource = ( nId && bResetThemeName );
+}
+
+void GalleryThemeEntry::removeTheme()
+{
+ mpGalleryStorageEngineEntry->removeTheme();
+}
+
+class GalleryThemeCacheEntry
+{
+private:
+
+ const GalleryThemeEntry* mpThemeEntry;
+ std::unique_ptr<GalleryTheme> mpTheme;
+
+public:
+
+ GalleryThemeCacheEntry( const GalleryThemeEntry* pThemeEntry, std::unique_ptr<GalleryTheme> pTheme ) :
+ mpThemeEntry( pThemeEntry ), mpTheme( std::move(pTheme) ) {}
+
+ const GalleryThemeEntry* GetThemeEntry() const { return mpThemeEntry; }
+ GalleryTheme* GetTheme() const { return mpTheme.get(); }
+};
+
+
+Gallery::Gallery( std::u16string_view rMultiPath )
+: bMultiPath ( false )
+{
+ ImplLoad( rMultiPath );
+}
+
+Gallery::~Gallery()
+{
+}
+
+Gallery* Gallery::GetGalleryInstance()
+{
+ // note: this would deadlock if it used osl::Mutex::getGlobalMutex()
+ static Gallery *const s_pGallery(
+ utl::ConfigManager::IsFuzzing() ? nullptr :
+ new Gallery(SvtPathOptions().GetGalleryPath()));
+
+ return s_pGallery;
+}
+
+void Gallery::ImplLoad( std::u16string_view rMultiPath )
+{
+ bool bIsReadOnlyDir {false};
+
+ bMultiPath = !rMultiPath.empty();
+
+ INetURLObject aCurURL(SvtPathOptions().GetConfigPath());
+ ImplLoadSubDirs( aCurURL, bIsReadOnlyDir );
+
+ if( !bIsReadOnlyDir )
+ aUserURL = aCurURL;
+
+ if( bMultiPath )
+ {
+ bool bIsRelURL {true};
+ sal_Int32 nIdx {0};
+ do
+ {
+ aCurURL = INetURLObject(o3tl::getToken(rMultiPath, 0, ';', nIdx));
+ if (bIsRelURL)
+ {
+ aRelURL = aCurURL;
+ bIsRelURL = false;
+ }
+
+ ImplLoadSubDirs( aCurURL, bIsReadOnlyDir );
+
+ if( !bIsReadOnlyDir )
+ aUserURL = aCurURL;
+ }
+ while (nIdx>0);
+ }
+ else
+ aRelURL = INetURLObject( rMultiPath );
+
+ DBG_ASSERT( aUserURL.GetProtocol() != INetProtocol::NotValid, "no writable Gallery user directory available" );
+ DBG_ASSERT( aRelURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+}
+
+void Gallery::ImplLoadSubDirs( const INetURLObject& rBaseURL, bool& rbDirIsReadOnly )
+{
+ rbDirIsReadOnly = false;
+
+ try
+ {
+ uno::Reference< ucb::XCommandEnvironment > xEnv;
+ ::ucbhelper::Content aCnt( rBaseURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext() );
+
+ uno::Sequence<OUString> aProps { "Url" };
+
+ uno::Reference< sdbc::XResultSet > xResultSet( aCnt.createCursor( aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ) );
+
+#if defined(MACOSX) && HAVE_FEATURE_READONLY_INSTALLSET
+ if( rBaseURL.GetProtocol() == INetProtocol::File )
+ {
+ const char *appBundle = [[[NSBundle mainBundle] bundlePath] UTF8String];
+ OUString path = rBaseURL.GetURLPath();
+ if( path.startsWith( OUStringConcatenation(OUString( appBundle, strlen( appBundle ), RTL_TEXTENCODING_UTF8 ) + "/") ) )
+ rbDirIsReadOnly = true;
+ }
+#else
+ try
+ {
+ // check readonlyness the very hard way
+ INetURLObject aTestURL( rBaseURL );
+
+ aTestURL.Append( u"cdefghij.klm" );
+ std::unique_ptr<SvStream> pTestStm(::utl::UcbStreamHelper::CreateStream( aTestURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE ));
+
+ if( pTestStm )
+ {
+ pTestStm->WriteInt32( sal_Int32(1) );
+
+ if( pTestStm->GetError() )
+ rbDirIsReadOnly = true;
+
+ pTestStm.reset();
+ KillFile( aTestURL );
+ }
+ else
+ rbDirIsReadOnly = true;
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+#endif
+ if( xResultSet.is() )
+ {
+ uno::Reference< ucb::XContentAccess > xContentAccess( xResultSet, uno::UNO_QUERY );
+
+ if( xContentAccess.is() )
+ {
+ static constexpr OUStringLiteral s_sTitle = u"Title";
+ static constexpr OUStringLiteral s_sIsReadOnly = u"IsReadOnly";
+
+ while( xResultSet->next() )
+ {
+ INetURLObject aThmURL( xContentAccess->queryContentIdentifierString() );
+
+ if (aThmURL.GetFileExtension().equalsIgnoreAsciiCase("thm"))
+ {
+ INetURLObject aSdgURL( aThmURL); aSdgURL.SetExtension( u"sdg" );
+ INetURLObject aSdvURL( aThmURL ); aSdvURL.SetExtension( u"sdv" );
+
+ try
+ {
+ ::ucbhelper::Content aThmCnt( aThmURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext() );
+ ::ucbhelper::Content aSdgCnt( aSdgURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext() );
+ ::ucbhelper::Content aSdvCnt( aSdvURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext() );
+
+ OUString aTitle;
+ try
+ {
+ aThmCnt.getPropertyValue( s_sTitle ) >>= aTitle;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ if( !aTitle.isEmpty() )
+ {
+ bool bReadOnly = false;
+
+ try
+ {
+ aThmCnt.getPropertyValue( s_sIsReadOnly ) >>= bReadOnly;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ if( !bReadOnly )
+ {
+ try
+ {
+ aSdgCnt.getPropertyValue( s_sTitle ) >>= aTitle;
+ }
+ catch( const css::uno::RuntimeException& )
+ {
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+
+ if( !aTitle.isEmpty() )
+ {
+ try
+ {
+ aSdgCnt.getPropertyValue( s_sIsReadOnly ) >>= bReadOnly;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ }
+
+ if( !bReadOnly )
+ {
+ try
+ {
+ aSdvCnt.getPropertyValue( s_sTitle ) >>= aTitle;
+ }
+ catch( const css::uno::RuntimeException& )
+ {
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+
+ if( !aTitle.isEmpty() )
+ {
+ try
+ {
+ aSdvCnt.getPropertyValue( s_sIsReadOnly ) >>= bReadOnly;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ }
+
+ GalleryThemeEntry* pEntry = GalleryBinaryEngineEntry::CreateThemeEntry( aThmURL, rbDirIsReadOnly || bReadOnly );
+
+ if( pEntry )
+ aThemeList.emplace_back( pEntry );
+ }
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+GalleryThemeEntry* Gallery::ImplGetThemeEntry( std::u16string_view rThemeName )
+{
+ if( !rThemeName.empty() )
+ {
+ for ( size_t i = 0, n = aThemeList.size(); i < n; ++i )
+ if( rThemeName == aThemeList[ i ]->GetThemeName() )
+ return aThemeList[ i ].get();
+ }
+
+ return nullptr;
+}
+
+OUString Gallery::GetThemeName( sal_uInt32 nThemeId ) const
+{
+ GalleryThemeEntry* pFound = nullptr;
+
+ for ( size_t i = 0, n = aThemeList.size(); i < n && !pFound; ++i )
+ {
+ GalleryThemeEntry* pEntry = aThemeList[ i ].get();
+ if( nThemeId == pEntry->GetId() )
+ pFound = pEntry;
+ }
+
+ // try fallback, if no entry was found
+ if( !pFound )
+ {
+ OUString aFallback;
+
+ switch( nThemeId )
+ {
+ case GALLERY_THEME_3D:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_3D);
+ break;
+ case GALLERY_THEME_BULLETS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_BULLETS);
+ break;
+ case GALLERY_THEME_HOMEPAGE:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_HOMEPAGE);
+ break;
+ case GALLERY_THEME_POWERPOINT:
+ aFallback = RID_GALLERYSTR_THEME_POWERPOINT;
+ break;
+ case GALLERY_THEME_FONTWORK:
+ aFallback = RID_GALLERYSTR_THEME_FONTWORK;
+ break;
+ case GALLERY_THEME_FONTWORK_VERTICAL:
+ aFallback = RID_GALLERYSTR_THEME_FONTWORK_VERTICAL;
+ break;
+ case GALLERY_THEME_SOUNDS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_SOUNDS);
+ break;
+ case RID_GALLERY_THEME_ARROWS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_ARROWS);
+ break;
+ case RID_GALLERY_THEME_COMPUTERS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_COMPUTERS);
+ break;
+ case RID_GALLERY_THEME_DIAGRAMS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_DIAGRAMS);
+ break;
+ case RID_GALLERY_THEME_EDUCATION:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_EDUCATION);
+ break;
+ case RID_GALLERY_THEME_ENVIRONMENT:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_ENVIRONMENT);
+ break;
+ case RID_GALLERY_THEME_FINANCE:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_FINANCE);
+ break;
+ case RID_GALLERY_THEME_PEOPLE:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_PEOPLE);
+ break;
+ case RID_GALLERY_THEME_SYMBOLS:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_SYMBOLS);
+ break;
+ case RID_GALLERY_THEME_TRANSPORT:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_TRANSPORT);
+ break;
+ case RID_GALLERY_THEME_TXTSHAPES:
+ aFallback = SvxResId(RID_GALLERYSTR_THEME_TXTSHAPES);
+ break;
+ default:
+ break;
+ }
+
+ pFound = const_cast<Gallery*>(this)->ImplGetThemeEntry(aFallback);
+ }
+
+ return( pFound ? pFound->GetThemeName() : OUString() );
+}
+
+bool Gallery::HasTheme( std::u16string_view rThemeName )
+{
+ return( ImplGetThemeEntry( rThemeName ) != nullptr );
+}
+
+bool Gallery::CreateTheme( const OUString& rThemeName )
+{
+ bool bRet = false;
+
+ if( !HasTheme( rThemeName ) && ( GetUserURL().GetProtocol() != INetProtocol::NotValid ) )
+ {
+ INetURLObject aURL( GetUserURL() );
+ aURL.Append( rThemeName );
+ GalleryThemeEntry* pNewEntry = new GalleryThemeEntry(
+ true, aURL, rThemeName,
+ false, true, 0, false );
+
+ aThemeList.emplace_back( pNewEntry );
+ delete pNewEntry->createGalleryTheme( this );
+ Broadcast( GalleryHint( GalleryHintType::THEME_CREATED, rThemeName ) );
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+void Gallery::RenameTheme( const OUString& rOldName, const OUString& rNewName )
+{
+ GalleryThemeEntry* pThemeEntry = ImplGetThemeEntry( rOldName );
+
+ // check if the new theme name is already present
+ if( !pThemeEntry || HasTheme( rNewName ) || pThemeEntry->IsReadOnly() )
+ return;
+
+ SfxListener aListener;
+ GalleryTheme* pThm = AcquireTheme( rOldName, aListener );
+
+ if( pThm )
+ {
+ pThemeEntry->SetName( rNewName );
+ if (pThm->pThm->IsModified())
+ if (!pThm->mpGalleryStorageEngine->implWrite(*pThm, pThm->pThm))
+ pThm->ImplSetModified(false);
+
+ Broadcast( GalleryHint( GalleryHintType::THEME_RENAMED, rOldName, pThm->GetName() ) );
+ ReleaseTheme( pThm, aListener );
+ }
+}
+
+bool Gallery::RemoveTheme( const OUString& rThemeName )
+{
+ GalleryThemeEntry* pThemeEntry = ImplGetThemeEntry( rThemeName );
+ bool bRet = false;
+
+ if( pThemeEntry && !pThemeEntry->IsReadOnly() )
+ {
+ Broadcast( GalleryHint( GalleryHintType::CLOSE_THEME, rThemeName ) );
+
+ SfxListener aListener;
+ GalleryTheme* pThm = AcquireTheme( rThemeName, aListener );
+
+ if( pThm )
+ {
+ ReleaseTheme(pThm, aListener);
+ pThemeEntry->removeTheme();
+ }
+
+ auto it = std::find_if(aThemeList.begin(), aThemeList.end(),
+ [&pThemeEntry](const std::unique_ptr<GalleryThemeEntry>& rpEntry) { return pThemeEntry == rpEntry.get(); });
+ if (it != aThemeList.end())
+ aThemeList.erase( it );
+
+ Broadcast( GalleryHint( GalleryHintType::THEME_REMOVED, rThemeName ) );
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+std::unique_ptr<GalleryTheme> GalleryThemeEntry::getCachedTheme(Gallery* pGallery)
+{
+ std::unique_ptr<GalleryTheme> pNewTheme;
+ pNewTheme.reset(createGalleryTheme(pGallery));
+ mpGalleryStorageEngineEntry->getCachedTheme(pNewTheme);
+ return pNewTheme;
+}
+
+GalleryTheme* Gallery::ImplGetCachedTheme(GalleryThemeEntry* pThemeEntry)
+{
+ GalleryTheme* pTheme = nullptr;
+
+ if( pThemeEntry )
+ {
+ auto it = std::find_if(aThemeCache.begin(), aThemeCache.end(),
+ [&pThemeEntry](const GalleryThemeCacheEntry* pEntry) { return pThemeEntry == pEntry->GetThemeEntry(); });
+ if (it != aThemeCache.end())
+ pTheme = (*it)->GetTheme();
+
+ if( !pTheme )
+ {
+ std::unique_ptr<GalleryTheme> pNewTheme = pThemeEntry->getCachedTheme(this);
+ if (pNewTheme)
+ {
+ aThemeCache.push_back( new GalleryThemeCacheEntry( pThemeEntry, std::move(pNewTheme) ));
+ pTheme = aThemeCache.back()->GetTheme();
+ }
+ }
+ }
+
+ return pTheme;
+}
+
+void Gallery::ImplDeleteCachedTheme( GalleryTheme const * pTheme )
+{
+ auto it = std::find_if(aThemeCache.begin(), aThemeCache.end(),
+ [&pTheme](const GalleryThemeCacheEntry* pEntry) { return pTheme == pEntry->GetTheme(); });
+ if (it != aThemeCache.end())
+ {
+ delete *it;
+ aThemeCache.erase(it);
+ }
+}
+
+GalleryTheme* Gallery::AcquireTheme( std::u16string_view rThemeName, SfxListener& rListener )
+{
+ GalleryTheme* pTheme = nullptr;
+ GalleryThemeEntry* pThemeEntry = ImplGetThemeEntry( rThemeName );
+
+ if( pThemeEntry )
+ {
+ pTheme = ImplGetCachedTheme( pThemeEntry );
+ if (pTheme)
+ rListener.StartListening(*pTheme, DuplicateHandling::Prevent);
+ }
+ return pTheme;
+}
+
+void Gallery::ReleaseTheme( GalleryTheme* pTheme, SfxListener& rListener )
+{
+ if( pTheme )
+ {
+ rListener.EndListening( *pTheme );
+
+ if( !pTheme->HasListeners() )
+ ImplDeleteCachedTheme( pTheme );
+ }
+}
+
+bool GalleryThemeEntry::IsDefault() const
+{
+ return nId > 0 && nId != GALLERY_THEME_MYTHEME;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallerybinaryengine.cxx b/svx/source/gallery2/gallerybinaryengine.cxx
new file mode 100644
index 000000000..c86ffa6f5
--- /dev/null
+++ b/svx/source/gallery2/gallerybinaryengine.cxx
@@ -0,0 +1,810 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/unomodel.hxx>
+#include <svx/fmmodel.hxx>
+#include <galobj.hxx>
+#include <svx/gallerybinaryengine.hxx>
+#include <svx/galleryobjectcollection.hxx>
+#include <svx/gallery1.hxx>
+#include <galleryobjectbinarystorage.hxx>
+#include <osl/thread.hxx>
+#include "codec.hxx"
+#include "gallerydrawmodel.hxx"
+#include <vcl/cvtgrf.hxx>
+#include <vcl/filter/SvmWriter.hxx>
+
+#include <sal/log.hxx>
+
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <comphelper/fileformat.h>
+#include <comphelper/graphicmimetype.hxx>
+#include <comphelper/processfactory.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/datetime.hxx>
+#include <unotools/datetime.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/tempfile.hxx>
+#include <ucbhelper/content.hxx>
+#include <tools/vcompat.hxx>
+
+using namespace ::com::sun::star;
+
+GalleryBinaryEngine::GalleryBinaryEngine(
+ const GalleryBinaryStorageLocations& rGalleryBinaryStorageLocations,
+ GalleryObjectCollection& rGalleryObjectCollection, bool bReadOnly)
+ : maGalleryStorageLocations(rGalleryBinaryStorageLocations)
+ , mrGalleryObjectCollection(rGalleryObjectCollection)
+ , mbReadOnly(bReadOnly)
+ , m_bDestDirRelative(false)
+{
+ ImplCreateSvDrawStorage();
+}
+
+GalleryBinaryEngine::~GalleryBinaryEngine() { clearSotStorage(); }
+
+void GalleryBinaryEngine::setDestDir(const OUString& rDestDir, bool bRelative)
+{
+ m_aDestDir = rDestDir;
+ m_bDestDirRelative = bRelative;
+}
+
+void GalleryBinaryEngine::clearSotStorage() { m_aSvDrawStorageRef.clear(); }
+
+void GalleryBinaryEngine::ImplCreateSvDrawStorage()
+{
+ try
+ {
+ m_aSvDrawStorageRef
+ = new SotStorage(false, GetSdvURL().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ mbReadOnly ? StreamMode::READ : StreamMode::STD_READWRITE);
+ // #i50423# ReadOnly may not been set though the file can't be written (because of security reasons)
+ if ((m_aSvDrawStorageRef->GetError() != ERRCODE_NONE) && !mbReadOnly)
+ m_aSvDrawStorageRef = new SotStorage(
+ false, GetSdvURL().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::READ);
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "failed to open: " << GetSdvURL().GetMainURL(
+ INetURLObject::DecodeMechanism::NONE)
+ << "due to");
+ }
+}
+
+const tools::SvRef<SotStorage>& GalleryBinaryEngine::GetSvDrawStorage() const
+{
+ return m_aSvDrawStorageRef;
+}
+
+bool GalleryBinaryEngine::implWrite(const GalleryTheme& rTheme, const GalleryThemeEntry* pThm)
+{
+ INetURLObject aPathURL(GetThmURL());
+
+ aPathURL.removeSegment();
+ aPathURL.removeFinalSlash();
+
+ DBG_ASSERT(aPathURL.GetProtocol() != INetProtocol::NotValid, "invalid URL");
+
+ if (FileExists(aPathURL) || CreateDir(aPathURL))
+ {
+#ifdef UNX
+ std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream(
+ GetThmURL().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::WRITE | StreamMode::COPY_ON_SYMLINK | StreamMode::TRUNC));
+#else
+ std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream(
+ GetThmURL().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::WRITE | StreamMode::TRUNC));
+#endif
+
+ if (pOStm)
+ {
+ writeGalleryTheme(*pOStm, rTheme, pThm);
+ pOStm.reset();
+ return true;
+ }
+
+ return false;
+ }
+ return true;
+}
+
+void GalleryBinaryEngine::insertObject(const SgaObject& rObj, GalleryObject* pFoundEntry,
+ sal_uInt32 nInsertPos)
+{
+ if (pFoundEntry)
+ {
+ GalleryObject aNewEntry;
+
+ // update title of new object if necessary
+ if (rObj.GetTitle().isEmpty())
+ {
+ std::unique_ptr<SgaObject> pOldObj(implReadSgaObject(pFoundEntry));
+
+ if (pOldObj)
+ {
+ const_cast<SgaObject&>(rObj).SetTitle(pOldObj->GetTitle());
+ }
+ }
+ else if (rObj.GetTitle() == "__<empty>__")
+ const_cast<SgaObject&>(rObj).SetTitle("");
+
+ implWriteSgaObject(rObj, nInsertPos, &aNewEntry);
+ pFoundEntry->nOffset = aNewEntry.nOffset;
+ }
+ else
+ implWriteSgaObject(rObj, nInsertPos, nullptr);
+}
+
+void GalleryBinaryEngine::removeObject(const std::unique_ptr<GalleryObject>& pEntry)
+{
+ if (mrGalleryObjectCollection.getObjectList().empty())
+ KillFile(GetSdgURL());
+
+ if (SgaObjKind::SvDraw == pEntry->eObjKind)
+ GetSvDrawStorage()->Remove(
+ pEntry->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE));
+}
+
+std::unique_ptr<SgaObject> GalleryBinaryEngine::implReadSgaObject(GalleryObject const* pEntry)
+{
+ std::unique_ptr<SgaObject> pSgaObj;
+
+ if (pEntry)
+ {
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream(
+ GetSdgURL().GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+
+ if (pIStm)
+ {
+ sal_uInt32 nInventor;
+
+ // Check to ensure that the file is a valid SGA file
+ pIStm->Seek(pEntry->nOffset);
+ pIStm->ReadUInt32(nInventor);
+
+ if (nInventor == COMPAT_FORMAT('S', 'G', 'A', '3'))
+ {
+ pIStm->Seek(pEntry->nOffset);
+
+ switch (pEntry->eObjKind)
+ {
+ case SgaObjKind::Bitmap:
+ pSgaObj.reset(new SgaObjectBmp());
+ break;
+ case SgaObjKind::Animation:
+ pSgaObj.reset(new SgaObjectAnim());
+ break;
+ case SgaObjKind::Inet:
+ pSgaObj.reset(new SgaObjectINet());
+ break;
+ case SgaObjKind::SvDraw:
+ pSgaObj.reset(new SgaObjectSvDraw());
+ break;
+ case SgaObjKind::Sound:
+ pSgaObj.reset(new SgaObjectSound());
+ break;
+
+ default:
+ break;
+ }
+
+ if (pSgaObj)
+ {
+ ReadSgaObject(*pIStm, *pSgaObj);
+ pSgaObj->ImplUpdateURL(pEntry->getURL());
+ }
+ }
+ }
+ }
+
+ return pSgaObj;
+}
+
+bool GalleryBinaryEngine::implWriteSgaObject(const SgaObject& rObj, sal_uInt32 nPos,
+ GalleryObject* pExistentEntry)
+{
+ std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream(
+ GetSdgURL().GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::WRITE));
+ bool bRet = false;
+
+ if (pOStm)
+ {
+ const sal_uInt32 nOffset = pOStm->Seek(STREAM_SEEK_TO_END);
+
+ rObj.WriteData(*pOStm, m_aDestDir);
+
+ if (!pOStm->GetError())
+ {
+ GalleryObject* pEntry;
+
+ if (!pExistentEntry)
+ {
+ pEntry = new GalleryObject;
+ if (nPos < mrGalleryObjectCollection.size())
+ {
+ mrGalleryObjectCollection.getObjectList().emplace(
+ mrGalleryObjectCollection.getObjectList().begin() + nPos, pEntry);
+ }
+ else
+ mrGalleryObjectCollection.getObjectList().emplace_back(pEntry);
+ }
+ else
+ pEntry = pExistentEntry;
+
+ pEntry->m_pGalleryObjectStorage = std::make_unique<GalleryObjectBinaryStorage>();
+ pEntry->m_pGalleryObjectStorage->setURL(rObj.GetURL());
+
+ pEntry->nOffset = nOffset;
+ pEntry->eObjKind = rObj.GetObjKind();
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryBinaryEngine::readModel(const GalleryObject* pObject, SdrModel& rModel)
+{
+ tools::SvRef<SotStorage> xSotStorage(GetSvDrawStorage());
+ bool bRet = false;
+ const INetURLObject aURL(ImplGetURL(pObject));
+
+ if (xSotStorage.is())
+ {
+ const OUString aStreamName(GetSvDrawStreamNameFromURL(aURL));
+ tools::SvRef<SotStorageStream> xInputStream(
+ xSotStorage->OpenSotStream(aStreamName, StreamMode::READ));
+
+ if (xInputStream.is() && !xInputStream->GetError())
+ {
+ xInputStream->SetBufferSize(STREAMBUF_SIZE);
+ bRet = GallerySvDrawImport(*xInputStream, rModel);
+ xInputStream->SetBufferSize(0);
+ }
+ }
+ return bRet;
+}
+
+SgaObjectSvDraw GalleryBinaryEngine::insertModel(const FmFormModel& rModel,
+ const INetURLObject& rUserURL)
+{
+ INetURLObject aURL(implCreateUniqueURL(SgaObjKind::SvDraw, rUserURL));
+ tools::SvRef<SotStorage> xSotStorage(GetSvDrawStorage());
+ bool bRet = false;
+
+ if (xSotStorage.is())
+ {
+ const OUString aStreamName(GetSvDrawStreamNameFromURL(aURL));
+ tools::SvRef<SotStorageStream> xOutputStream(
+ xSotStorage->OpenSotStream(aStreamName, StreamMode::WRITE | StreamMode::TRUNC));
+
+ if (xOutputStream.is() && !xOutputStream->GetError())
+ {
+ SvMemoryStream aMemoryStream(65535, 65535);
+ FmFormModel* pFormModel = const_cast<FmFormModel*>(&rModel);
+
+ pFormModel->BurnInStyleSheetAttributes();
+
+ {
+ uno::Reference<io::XOutputStream> xDocOut(
+ new utl::OOutputStreamWrapper(aMemoryStream));
+
+ if (xDocOut.is())
+ (void)SvxDrawingLayerExport(pFormModel, xDocOut);
+ }
+
+ aMemoryStream.Seek(0);
+
+ xOutputStream->SetBufferSize(16348);
+ GalleryCodec aCodec(*xOutputStream);
+ aCodec.Write(aMemoryStream);
+
+ xOutputStream->SetBufferSize(0);
+ xOutputStream->Commit();
+ bRet = !xOutputStream->GetError();
+ }
+ }
+ if (bRet)
+ {
+ SgaObjectSvDraw aObjSvDraw(rModel, aURL);
+ return aObjSvDraw;
+ }
+ return SgaObjectSvDraw();
+}
+
+bool GalleryBinaryEngine::readModelStream(const GalleryObject* pObject,
+ tools::SvRef<SotTempStream> const& rxModelStream)
+{
+ const INetURLObject aURL(ImplGetURL(pObject));
+ tools::SvRef<SotStorage> xSotStorage(GetSvDrawStorage());
+ bool bRet = false;
+
+ if (xSotStorage.is())
+ {
+ const OUString aStreamName(GetSvDrawStreamNameFromURL(aURL));
+ tools::SvRef<SotStorageStream> xInputStream(
+ xSotStorage->OpenSotStream(aStreamName, StreamMode::READ));
+
+ if (xInputStream.is() && !xInputStream->GetError())
+ {
+ sal_uInt32 nVersion = 0;
+
+ xInputStream->SetBufferSize(16348);
+
+ if (GalleryCodec::IsCoded(*xInputStream, nVersion))
+ {
+ SvxGalleryDrawModel aModel;
+
+ if (aModel.GetModel())
+ {
+ if (GallerySvDrawImport(*xInputStream, *aModel.GetModel()))
+ {
+ aModel.GetModel()->BurnInStyleSheetAttributes();
+
+ {
+ uno::Reference<io::XOutputStream> xDocOut(
+ new utl::OOutputStreamWrapper(*rxModelStream));
+
+ SvxDrawingLayerExport(aModel.GetModel(), xDocOut);
+ }
+ }
+
+ bRet = (rxModelStream->GetError() == ERRCODE_NONE);
+ }
+ }
+
+ xInputStream->SetBufferSize(0);
+ }
+ }
+ return bRet;
+}
+
+SgaObjectSvDraw
+GalleryBinaryEngine::insertModelStream(const tools::SvRef<SotTempStream>& rxModelStream,
+ const INetURLObject& rUserURL)
+{
+ INetURLObject aURL(implCreateUniqueURL(SgaObjKind::SvDraw, rUserURL));
+ tools::SvRef<SotStorage> xSotStorage(GetSvDrawStorage());
+
+ if (xSotStorage.is())
+ {
+ const OUString aStreamName(GetSvDrawStreamNameFromURL(aURL));
+ tools::SvRef<SotStorageStream> xOutputStream(
+ xSotStorage->OpenSotStream(aStreamName, StreamMode::WRITE | StreamMode::TRUNC));
+
+ if (xOutputStream.is() && !xOutputStream->GetError())
+ {
+ GalleryCodec aCodec(*xOutputStream);
+
+ xOutputStream->SetBufferSize(16348);
+ aCodec.Write(*rxModelStream);
+
+ if (!xOutputStream->GetError())
+ {
+ xOutputStream->Seek(0);
+ SgaObjectSvDraw aObjSvDraw(*xOutputStream, aURL);
+ return aObjSvDraw;
+ }
+ }
+ }
+ return SgaObjectSvDraw();
+}
+
+INetURLObject GalleryBinaryEngine::implCreateUniqueURL(SgaObjKind eObjKind,
+ const INetURLObject& rUserURL,
+ ConvertDataFormat nFormat)
+{
+ INetURLObject aDir(rUserURL);
+ INetURLObject aInfoFileURL(rUserURL);
+ INetURLObject aNewURL;
+ sal_uInt32 nNextNumber = 1999;
+ char const* pExt = nullptr;
+ bool bExists;
+
+ aDir.Append(u"dragdrop");
+ CreateDir(aDir);
+
+ aInfoFileURL.Append(u"sdddndx1");
+
+ // read next possible number
+ if (FileExists(aInfoFileURL))
+ {
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream(
+ aInfoFileURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+
+ if (pIStm)
+ {
+ pIStm->ReadUInt32(nNextNumber);
+ }
+ }
+
+ pExt = comphelper::GraphicMimeTypeHelper::GetExtensionForConvertDataFormat(nFormat);
+
+ do
+ {
+ // get URL
+ if (SgaObjKind::SvDraw == eObjKind)
+ {
+ OUString aFileName = "gallery/svdraw/dd" + OUString::number(++nNextNumber % 99999999);
+ aNewURL = INetURLObject(aFileName, INetProtocol::PrivSoffice);
+
+ bExists = false;
+
+ for (auto const& pObject : mrGalleryObjectCollection.getObjectList())
+ {
+ if (pObject->getURL() == aNewURL)
+ {
+ bExists = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ OUString aFileName = "dd" + OUString::number(++nNextNumber % 999999);
+
+ if (pExt)
+ aFileName += OUString(pExt, strlen(pExt), RTL_TEXTENCODING_ASCII_US);
+
+ aNewURL = aDir;
+ aNewURL.Append(aFileName);
+
+ bExists = FileExists(aNewURL);
+ }
+ } while (bExists);
+
+ // write updated number
+ std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream(
+ aInfoFileURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::WRITE));
+
+ if (pOStm)
+ {
+ pOStm->WriteUInt32(nNextNumber);
+ }
+
+ return aNewURL;
+}
+
+SgaObjectBmp GalleryBinaryEngine::insertGraphic(const Graphic& rGraphic, const GfxLink& aGfxLink,
+ const ConvertDataFormat& nExportFormat,
+ const INetURLObject& rUserURL)
+{
+ const INetURLObject aURL(implCreateUniqueURL(SgaObjKind::Bitmap, rUserURL, nExportFormat));
+ std::unique_ptr<SvStream> pOStm(
+ ::utl::UcbStreamHelper::CreateStream(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::WRITE | StreamMode::TRUNC));
+ bool bRet = false;
+
+ if (pOStm)
+ {
+ pOStm->SetVersion(SOFFICE_FILEFORMAT_50);
+
+ if (ConvertDataFormat::SVM == nExportFormat)
+ {
+ GDIMetaFile aMtf(rGraphic.GetGDIMetaFile());
+
+ SvmWriter aWriter(*pOStm);
+ aWriter.Write(aMtf);
+ bRet = (pOStm->GetError() == ERRCODE_NONE);
+ }
+ else
+ {
+ if (aGfxLink.GetDataSize() && aGfxLink.GetData())
+ {
+ pOStm->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
+ bRet = (pOStm->GetError() == ERRCODE_NONE);
+ }
+ else
+ bRet = (GraphicConverter::Export(*pOStm, rGraphic, nExportFormat) == ERRCODE_NONE);
+ }
+
+ pOStm.reset();
+ }
+ if (bRet)
+ {
+ const SgaObjectBmp aObjBmp(aURL);
+ return aObjBmp;
+ }
+ return SgaObjectBmp();
+}
+
+SgaObjectSvDraw GalleryBinaryEngine::updateSvDrawObject(const GalleryObject* pEntry)
+{
+ if (GetSvDrawStorage().is())
+ {
+ const OUString aStmName(GetSvDrawStreamNameFromURL(pEntry->getURL()));
+ tools::SvRef<SotStorageStream> pIStm
+ = GetSvDrawStorage()->OpenSotStream(aStmName, StreamMode::READ);
+
+ if (pIStm.is() && !pIStm->GetError())
+ {
+ pIStm->SetBufferSize(16384);
+
+ SgaObjectSvDraw aNewObj(*pIStm, pEntry->getURL());
+
+ pIStm->SetBufferSize(0);
+
+ return aNewObj;
+ }
+ }
+ return SgaObjectSvDraw();
+}
+
+void GalleryBinaryEngine::updateTheme()
+{
+ ::utl::TempFile aTmp;
+ INetURLObject aInURL(GetSdgURL());
+ INetURLObject aTmpURL(aTmp.GetURL());
+
+ DBG_ASSERT(aInURL.GetProtocol() != INetProtocol::NotValid, "invalid URL");
+ DBG_ASSERT(aTmpURL.GetProtocol() != INetProtocol::NotValid, "invalid URL");
+
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream(
+ aInURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+ std::unique_ptr<SvStream> pTmpStm(::utl::UcbStreamHelper::CreateStream(
+ aTmpURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::WRITE | StreamMode::TRUNC));
+
+ if (pIStm && pTmpStm)
+ {
+ for (const auto& i : mrGalleryObjectCollection.getObjectList())
+ {
+ GalleryObject* pEntry = i.get();
+ std::unique_ptr<SgaObject> pObj;
+
+ switch (pEntry->eObjKind)
+ {
+ case SgaObjKind::Bitmap:
+ pObj.reset(new SgaObjectBmp());
+ break;
+ case SgaObjKind::Animation:
+ pObj.reset(new SgaObjectAnim());
+ break;
+ case SgaObjKind::Inet:
+ pObj.reset(new SgaObjectINet());
+ break;
+ case SgaObjKind::SvDraw:
+ pObj.reset(new SgaObjectSvDraw());
+ break;
+ case SgaObjKind::Sound:
+ pObj.reset(new SgaObjectSound());
+ break;
+
+ default:
+ break;
+ }
+
+ if (pObj)
+ {
+ pIStm->Seek(pEntry->nOffset);
+ ReadSgaObject(*pIStm, *pObj);
+ pEntry->nOffset = pTmpStm->Tell();
+ WriteSgaObject(*pTmpStm, *pObj);
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("File(s) could not be opened");
+ }
+
+ pIStm.reset();
+ pTmpStm.reset();
+
+ CopyFile(aTmpURL, aInURL);
+ KillFile(aTmpURL);
+
+ ErrCode nStorErr = ERRCODE_NONE;
+
+ try
+ {
+ tools::SvRef<SotStorage> aTempStorageRef(
+ new SotStorage(false, aTmpURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ StreamMode::STD_READWRITE));
+ GetSvDrawStorage()->CopyTo(aTempStorageRef.get());
+ nStorErr = GetSvDrawStorage()->GetError();
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "failed to open: "
+ << aTmpURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)
+ << "due to");
+ nStorErr = ERRCODE_IO_GENERAL;
+ }
+
+ if (nStorErr == ERRCODE_NONE)
+ {
+ clearSotStorage();
+ CopyFile(aTmpURL, GetSdvURL());
+ ImplCreateSvDrawStorage();
+ }
+
+ KillFile(aTmpURL);
+}
+
+void GalleryBinaryEngine::insertFileOrDirURL(const INetURLObject& rFileOrDirURL,
+ std::vector<INetURLObject>& rURLVector)
+{
+ INetURLObject aURL;
+ try
+ {
+ ::ucbhelper::Content aCnt(rFileOrDirURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ uno::Reference<ucb::XCommandEnvironment>(),
+ comphelper::getProcessComponentContext());
+ bool bFolder = false;
+
+ aCnt.getPropertyValue("IsFolder") >>= bFolder;
+
+ if (bFolder)
+ {
+ uno::Sequence<OUString> aProps{ "Url" };
+ uno::Reference<sdbc::XResultSet> xResultSet(
+ aCnt.createCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY));
+ uno::Reference<ucb::XContentAccess> xContentAccess(xResultSet, uno::UNO_QUERY);
+ if (xContentAccess.is())
+ {
+ while (xResultSet->next())
+ {
+ aURL.SetSmartURL(xContentAccess->queryContentIdentifierString());
+ rURLVector.push_back(aURL);
+ }
+ }
+ }
+ else
+ rURLVector.push_back(rFileOrDirURL);
+ }
+ catch (const ucb::ContentCreationException&)
+ {
+ }
+ catch (const uno::RuntimeException&)
+ {
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+SvStream& GalleryBinaryEngine::writeGalleryTheme(SvStream& rOStm, const GalleryTheme& rTheme,
+ const GalleryThemeEntry* pThm)
+{
+ const INetURLObject rRelURL1 = rTheme.GetParent()->GetRelativeURL();
+ const INetURLObject rRelURL2 = rTheme.GetParent()->GetUserURL();
+ const sal_uInt32 rId = rTheme.GetId();
+ sal_uInt32 nCount = mrGalleryObjectCollection.size();
+ bool bRel;
+
+ rOStm.WriteUInt16(0x0004);
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, pThm->GetThemeName(),
+ RTL_TEXTENCODING_UTF8);
+ rOStm.WriteUInt32(nCount).WriteUInt16(osl_getThreadTextEncoding());
+
+ for (sal_uInt32 i = 0; i < nCount; i++)
+ {
+ const GalleryObject* pObj = mrGalleryObjectCollection.getForPosition(i);
+ OUString aPath;
+
+ if (SgaObjKind::SvDraw == pObj->eObjKind)
+ {
+ aPath = GetSvDrawStreamNameFromURL(pObj->getURL());
+ bRel = false;
+ }
+ else
+ {
+ aPath = pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ aPath = aPath.copy(
+ 0, std::min(rRelURL1.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength(),
+ aPath.getLength()));
+ bRel = aPath == rRelURL1.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+
+ if (bRel
+ && (pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength()
+ > (rRelURL1.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength() + 1)))
+ {
+ aPath = pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ aPath = aPath.copy(
+ std::min(rRelURL1.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength(),
+ aPath.getLength()));
+ }
+ else
+ {
+ aPath = pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ aPath = aPath.copy(
+ 0,
+ std::min(rRelURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength(),
+ aPath.getLength()));
+ bRel = aPath == rRelURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+
+ if (bRel
+ && (pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength()
+ > (rRelURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength()
+ + 1)))
+ {
+ aPath = pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ aPath = aPath.copy(std::min(
+ rRelURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE).getLength(),
+ aPath.getLength()));
+ }
+ else
+ aPath = pObj->getURL().GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ }
+ }
+
+ if (!m_aDestDir.isEmpty())
+ {
+ bool aFound = aPath.indexOf(m_aDestDir) != -1;
+ aPath = aPath.replaceFirst(m_aDestDir, "");
+ if (aFound)
+ bRel = m_bDestDirRelative;
+ else
+ SAL_WARN("svx", "failed to replace destdir of '" << m_aDestDir << "' in '" << aPath
+ << "'");
+ }
+
+ rOStm.WriteBool(bRel);
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, aPath, RTL_TEXTENCODING_UTF8);
+ rOStm.WriteUInt32(pObj->nOffset).WriteUInt16(static_cast<sal_uInt16>(pObj->eObjKind));
+ }
+
+ // more recently, a 512-byte reserve buffer is written,
+ // to recognize them two sal_uInt32-Ids will be written.
+ rOStm.WriteUInt32(COMPAT_FORMAT('G', 'A', 'L', 'R'))
+ .WriteUInt32(COMPAT_FORMAT('E', 'S', 'R', 'V'));
+
+ const sal_uInt64 nReservePos = rOStm.Tell();
+ std::unique_ptr<VersionCompatWrite> pCompat(new VersionCompatWrite(rOStm, 2));
+
+ rOStm.WriteUInt32(rId).WriteBool(pThm->IsNameFromResource()); // From version 2 and up
+
+ pCompat.reset();
+
+ // Fill the rest of the buffer.
+ const tools::Long nRest
+ = std::max(tools::Long(512 - (rOStm.Tell() - nReservePos)), tools::Long(0));
+
+ if (nRest)
+ {
+ std::unique_ptr<char[]> pReserve(new char[nRest]);
+ memset(pReserve.get(), 0, nRest);
+ rOStm.WriteBytes(pReserve.get(), nRest);
+ }
+
+ return rOStm;
+}
+
+DateTime GalleryBinaryEngine::getModificationDate() const
+{
+ ::ucbhelper::Content aCnt(GetThmURL().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ uno::Reference<ucb::XCommandEnvironment>(),
+ comphelper::getProcessComponentContext());
+ util::DateTime aDateTimeModified;
+ DateTime aDateTime(DateTime::EMPTY);
+
+ aCnt.getPropertyValue("DateModified") >>= aDateTimeModified;
+ ::utl::typeConvert(aDateTimeModified, aDateTime);
+
+ return aDateTime;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallerybinaryengineentry.cxx b/svx/source/gallery2/gallerybinaryengineentry.cxx
new file mode 100644
index 000000000..f892788ae
--- /dev/null
+++ b/svx/source/gallery2/gallerybinaryengineentry.cxx
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/gallerybinaryengineentry.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/gallery1.hxx>
+
+#include <unotools/ucbstreamhelper.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/vcompat.hxx>
+
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+
+static bool FileExists(const INetURLObject& rURL, std::u16string_view rExt)
+{
+ INetURLObject aURL(rURL);
+ aURL.setExtension(rExt);
+ return FileExists(aURL);
+}
+
+GalleryBinaryEngineEntry::GalleryBinaryEngineEntry()
+{
+ mpGalleryStorageLocations = std::make_unique<GalleryBinaryStorageLocations>();
+}
+
+void GalleryBinaryEngineEntry::setStorageLocations(INetURLObject& rURL)
+{
+ mpGalleryStorageLocations->SetStorageLocations(rURL);
+}
+
+std::unique_ptr<GalleryBinaryEngine> GalleryBinaryEngineEntry::createGalleryStorageEngine(
+ GalleryObjectCollection& mrGalleryObjectCollection, bool& bReadOnly)
+{
+ return std::make_unique<GalleryBinaryEngine>(*mpGalleryStorageLocations,
+ mrGalleryObjectCollection, bReadOnly);
+}
+
+void GalleryBinaryEngineEntry::CreateUniqueURL(const INetURLObject& rBaseURL, INetURLObject& aURL)
+{
+ INetURLObject aBaseNoCase(GalleryBinaryStorageLocations::ImplGetURLIgnoreCase(rBaseURL));
+ aURL = aBaseNoCase;
+ static sal_Int32 nIdx = 0;
+ while (FileExists(aURL, u"thm"))
+ { // create new URLs
+ nIdx++;
+ aURL = aBaseNoCase;
+ aURL.setName(OUStringConcatenation(aURL.getName() + OUString::number(nIdx)));
+ }
+}
+
+GalleryThemeEntry* GalleryBinaryEngineEntry::CreateThemeEntry(const INetURLObject& rURL,
+ bool bReadOnly)
+{
+ DBG_ASSERT(rURL.GetProtocol() != INetProtocol::NotValid, "invalid URL");
+
+ GalleryThemeEntry* pRet = nullptr;
+
+ if (FileExists(rURL))
+ {
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream(
+ rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+
+ if (pIStm)
+ {
+ sal_uInt16 nVersion;
+
+ pIStm->ReadUInt16(nVersion);
+
+ if (nVersion <= 0x00ff)
+ {
+ bool bThemeNameFromResource = false;
+ sal_uInt32 nThemeId = 0;
+
+ OString aTmpStr = read_uInt16_lenPrefixed_uInt8s_ToOString(*pIStm);
+ OUString aThemeName = OStringToOUString(aTmpStr, RTL_TEXTENCODING_UTF8);
+
+ // execute a character conversion
+ if (nVersion >= 0x0004)
+ {
+ sal_uInt32 nCount;
+ sal_uInt16 nTemp16;
+
+ pIStm->ReadUInt32(nCount).ReadUInt16(nTemp16);
+ pIStm->Seek(STREAM_SEEK_TO_END);
+
+ // check whether there is a newer version;
+ // therefore jump back by 520Bytes (8 bytes ID + 512Bytes reserve buffer)
+ // if this is at all possible.
+ if (pIStm->Tell() >= 520)
+ {
+ sal_uInt32 nId1, nId2;
+
+ pIStm->SeekRel(-520);
+ pIStm->ReadUInt32(nId1).ReadUInt32(nId2);
+
+ if (nId1 == COMPAT_FORMAT('G', 'A', 'L', 'R')
+ && nId2 == COMPAT_FORMAT('E', 'S', 'R', 'V'))
+ {
+ VersionCompatRead aCompat(*pIStm);
+
+ pIStm->ReadUInt32(nThemeId);
+
+ if (aCompat.GetVersion() >= 2)
+ {
+ pIStm->ReadCharAsBool(bThemeNameFromResource);
+ }
+ }
+ }
+ }
+
+ pRet = new GalleryThemeEntry(false, rURL, aThemeName, bReadOnly, false, nThemeId,
+ bThemeNameFromResource);
+ }
+ }
+ }
+
+ return pRet;
+}
+
+void GalleryBinaryEngineEntry::removeTheme()
+{
+ INetURLObject aThmURL(GetThmURL());
+ INetURLObject aSdgURL(GetSdgURL());
+ INetURLObject aSdvURL(GetSdvURL());
+ INetURLObject aStrURL(GetStrURL());
+
+ KillFile(aThmURL);
+ KillFile(aSdgURL);
+ KillFile(aSdvURL);
+ KillFile(aStrURL);
+}
+
+std::unique_ptr<GalleryTheme>&
+GalleryBinaryEngineEntry::getCachedTheme(std::unique_ptr<GalleryTheme>& pNewTheme)
+{
+ INetURLObject aURL = GetThmURL();
+
+ DBG_ASSERT(aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL");
+
+ if (FileExists(aURL))
+ {
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream(
+ aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ));
+
+ if (pIStm)
+ {
+ try
+ {
+ ReadGalleryTheme(*pIStm, *pNewTheme);
+
+ if (pIStm->GetError())
+ pNewTheme.reset();
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ }
+ }
+ }
+ return pNewTheme;
+}
+
+SvStream& ReadGalleryTheme(SvStream& rIn, GalleryTheme& rTheme) { return rTheme.ReadData(rIn); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallerybinarystoragelocations.cxx b/svx/source/gallery2/gallerybinarystoragelocations.cxx
new file mode 100644
index 000000000..dc896f6c3
--- /dev/null
+++ b/svx/source/gallery2/gallerybinarystoragelocations.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/gallerybinarystoragelocations.hxx>
+#include <svx/galmisc.hxx>
+
+INetURLObject GalleryBinaryStorageLocations::ImplGetURLIgnoreCase(const INetURLObject& rURL)
+{
+ INetURLObject aURL(rURL);
+
+ // check original file name
+ if (!FileExists(aURL))
+ {
+ // check upper case file name
+ aURL.setName(aURL.getName().toAsciiUpperCase());
+
+ if (!FileExists(aURL))
+ {
+ // check lower case file name
+ aURL.setName(aURL.getName().toAsciiLowerCase());
+ }
+ }
+
+ return aURL;
+}
+
+void GalleryBinaryStorageLocations::SetThmExtension(INetURLObject& aURL)
+{
+ aURL.setExtension(u"thm");
+ maThmURL = ImplGetURLIgnoreCase(aURL);
+}
+
+void GalleryBinaryStorageLocations::SetSdgExtension(INetURLObject& aURL)
+{
+ aURL.setExtension(u"sdg");
+ maSdgURL = ImplGetURLIgnoreCase(aURL);
+}
+
+void GalleryBinaryStorageLocations::SetSdvExtension(INetURLObject& aURL)
+{
+ aURL.setExtension(u"sdv");
+ maSdvURL = ImplGetURLIgnoreCase(aURL);
+}
+
+void GalleryBinaryStorageLocations::SetStrExtension(INetURLObject& aURL)
+{
+ aURL.setExtension(u"str");
+ maStrURL = ImplGetURLIgnoreCase(aURL);
+}
+
+void GalleryBinaryStorageLocations::SetStorageLocations(INetURLObject& rURL)
+{
+ SetThmExtension(rURL);
+ SetSdgExtension(rURL);
+ SetSdvExtension(rURL);
+ SetStrExtension(rURL);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallerydrawmodel.hxx b/svx/source/gallery2/gallerydrawmodel.hxx
new file mode 100644
index 000000000..0b2ef2582
--- /dev/null
+++ b/svx/source/gallery2/gallerydrawmodel.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/objsh.hxx>
+
+class FmFormModel;
+
+class SvxGalleryDrawModel
+{
+public:
+ SvxGalleryDrawModel();
+ ~SvxGalleryDrawModel();
+
+ FmFormModel* GetModel() const { return mpFormModel; }
+
+private:
+ SfxObjectShellLock mxDoc;
+ FmFormModel* mpFormModel;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryfilestorage.cxx b/svx/source/gallery2/galleryfilestorage.cxx
new file mode 100644
index 000000000..dd8e74cd3
--- /dev/null
+++ b/svx/source/gallery2/galleryfilestorage.cxx
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/galleryfilestorage.hxx>
+
+GalleryFileStorage::~GalleryFileStorage(){};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryfilestorageentry.cxx b/svx/source/gallery2/galleryfilestorageentry.cxx
new file mode 100644
index 000000000..d04f49bf8
--- /dev/null
+++ b/svx/source/gallery2/galleryfilestorageentry.cxx
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/galleryfilestorageentry.hxx>
+
+GalleryFileStorageEntry::~GalleryFileStorageEntry(){};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryobjectbinarystorage.cxx b/svx/source/gallery2/galleryobjectbinarystorage.cxx
new file mode 100644
index 000000000..14bdc8b08
--- /dev/null
+++ b/svx/source/gallery2/galleryobjectbinarystorage.cxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <galleryobjectbinarystorage.hxx>
+#include <tools/urlobj.hxx>
+
+void GalleryObjectBinaryStorage::setURL(INetURLObject aURL) { m_aURL = aURL; }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryobjectcollection.cxx b/svx/source/gallery2/galleryobjectcollection.cxx
new file mode 100644
index 000000000..515f52759
--- /dev/null
+++ b/svx/source/gallery2/galleryobjectcollection.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/galleryobjectcollection.hxx>
+
+GalleryObjectCollection::GalleryObjectCollection() {}
+
+void GalleryObjectCollection::clear() { m_aObjectList.clear(); }
+
+const GalleryObject* GalleryObjectCollection::searchObjectWithURL(const INetURLObject& rURL)
+{
+ for (auto const& pObject : m_aObjectList)
+ {
+ if (pObject->getURL() == rURL)
+ return pObject.get();
+ }
+ return nullptr;
+}
+
+sal_uInt32 GalleryObjectCollection::searchPosWithObject(const GalleryObject* pObj)
+{
+ for (sal_uInt32 i = 0, n = size(); i < n; ++i)
+ if (pObj == get(i).get())
+ return i;
+ return SAL_MAX_UINT32;
+}
+
+const GalleryObject* GalleryObjectCollection::getForPosition(sal_uInt32 nPos) const
+{
+ if (nPos < size())
+ return get(nPos).get();
+ return nullptr;
+}
+
+const INetURLObject g_aInvalidURL;
+
+const INetURLObject& GalleryObjectCollection::getURLForPosition(sal_uInt32 nPos) const
+{
+ if (nPos < size())
+ return get(nPos)->getURL();
+ return g_aInvalidURL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryobjectstorage.cxx b/svx/source/gallery2/galleryobjectstorage.cxx
new file mode 100644
index 000000000..2d324b3d0
--- /dev/null
+++ b/svx/source/gallery2/galleryobjectstorage.cxx
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/galleryobjectstorage.hxx>
+
+GalleryObjectStorage::~GalleryObjectStorage() = default;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galleryobjectxmlstorage.cxx b/svx/source/gallery2/galleryobjectxmlstorage.cxx
new file mode 100644
index 000000000..f07b7b869
--- /dev/null
+++ b/svx/source/gallery2/galleryobjectxmlstorage.cxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <galleryobjectxmlstorage.hxx>
+#include <tools/urlobj.hxx>
+
+void GalleryObjectXMLStorage::setURL(INetURLObject aURL) { m_aURL = aURL; }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/gallerystoragelocations.cxx b/svx/source/gallery2/gallerystoragelocations.cxx
new file mode 100644
index 000000000..d71ae452f
--- /dev/null
+++ b/svx/source/gallery2/gallerystoragelocations.cxx
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/gallerystoragelocations.hxx>
+
+GalleryStorageLocations::~GalleryStorageLocations(){};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galmisc.cxx b/svx/source/gallery2/galmisc.cxx
new file mode 100644
index 000000000..3422f5e29
--- /dev/null
+++ b/svx/source/gallery2/galmisc.cxx
@@ -0,0 +1,563 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sot/storage.hxx>
+#include <unotools/streamwrap.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <ucbhelper/content.hxx>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <tools/urlobj.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <svl/itempool.hxx>
+#include <sfx2/docfile.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/unomodel.hxx>
+#include "codec.hxx"
+#include <svx/strings.hrc>
+#include <svx/galtheme.hxx>
+#include <svx/galmisc.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/awt/XProgressMonitor.hpp>
+#include <com/sun/star/ucb/TransferInfo.hpp>
+#include <com/sun/star/ucb/NameClash.hpp>
+#include <memory>
+
+using namespace ::com::sun::star;
+
+GalleryGraphicImportRet GalleryGraphicImport( const INetURLObject& rURL, Graphic& rGraphic,
+ OUString& rFilterName )
+{
+ GalleryGraphicImportRet nRet = GalleryGraphicImportRet::IMPORT_NONE;
+ SfxMedium aMedium( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ );
+
+ aMedium.Download();
+
+ SvStream* pIStm = aMedium.GetInStream();
+
+ if( pIStm )
+ {
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ sal_uInt16 nFormat;
+
+ if( !rGraphicFilter.ImportGraphic( rGraphic, rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), *pIStm, GRFILTER_FORMAT_DONTKNOW, &nFormat ) )
+ {
+ rFilterName = rGraphicFilter.GetImportFormatName( nFormat );
+ nRet = GalleryGraphicImportRet::IMPORT_FILE;
+ }
+ }
+
+ return nRet;
+}
+
+bool GallerySvDrawImport( SvStream& rIStm, SdrModel& rModel )
+{
+ sal_uInt32 nVersion;
+ bool bRet = false;
+
+ if( GalleryCodec::IsCoded( rIStm, nVersion ) )
+ {
+ SvMemoryStream aMemStm( 65535, 65535 );
+ GalleryCodec aCodec( rIStm );
+
+ aCodec.Read( aMemStm );
+ aMemStm.Seek( 0 );
+
+ if( 1 == nVersion )
+ {
+ OSL_FAIL( "staroffice binary file formats are no longer supported inside the gallery!" );
+ bRet = false;
+ }
+ else if( 2 == nVersion )
+ {
+ // recall to read as XML
+ bRet = GallerySvDrawImport( aMemStm, rModel );
+ }
+ }
+ else
+ {
+ // read as XML
+ uno::Reference< io::XInputStream > xInputStream( new utl::OInputStreamWrapper( rIStm ) );
+
+ rModel.GetItemPool().SetDefaultMetric( MapUnit::Map100thMM );
+ uno::Reference< lang::XComponent > xComponent;
+
+ bRet = SvxDrawingLayerImport( &rModel, xInputStream, xComponent, "com.sun.star.comp.Draw.XMLOasisImporter" );
+ if( !bRet || (rModel.GetPageCount() == 0) )
+ {
+ rIStm.Seek(0);
+ bRet = SvxDrawingLayerImport( &rModel, xInputStream, xComponent, "com.sun.star.comp.Draw.XMLImporter" );
+ }
+
+ }
+
+ return bRet;
+}
+
+bool CreateIMapGraphic( const FmFormModel& rModel, Graphic& rGraphic, ImageMap& rImageMap )
+{
+ if (! rModel.GetPageCount() )
+ return false;
+
+ const SdrPage* pPage = rModel.GetPage( 0 );
+ const SdrObject* pObj = pPage->GetObj( 0 );
+
+ if ( pPage->GetObjCount() != 1 )
+ return false;
+ auto pGrafObj = dynamic_cast<const SdrGrafObj*>( pObj);
+ if (!pGrafObj)
+ return false;
+
+ bool bRet = false;
+ const sal_uInt16 nCount = pObj->GetUserDataCount();
+
+ // Exist in the user data an IMap information?
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ const SdrObjUserData* pUserData = pObj->GetUserData( i );
+
+ if ( ( pUserData->GetInventor() == SdrInventor::SgaImap ) && ( pUserData->GetId() == ID_IMAPINFO ) )
+ {
+ rGraphic = pGrafObj->GetGraphic();
+ rImageMap = static_cast<const SgaIMapInfo*>( pUserData )->GetImageMap();
+ bRet = true;
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+OUString GetReducedString( const INetURLObject& rURL, sal_Int32 nMaxLen )
+{
+ OUString aReduced( rURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) );
+
+ aReduced = aReduced.copy(aReduced.lastIndexOf('/')+1);
+
+ if( INetProtocol::PrivSoffice != rURL.GetProtocol() )
+ {
+ sal_Unicode aDelimiter;
+ const OUString aPath( rURL.getFSysPath( FSysStyle::Detect, &aDelimiter ) );
+ const OUString aName( aReduced );
+
+ if( aPath.getLength() > nMaxLen )
+ {
+ sal_Int32 nPathPrefixLen = nMaxLen - aName.getLength() - 4;
+
+ if (nPathPrefixLen >= 0)
+ {
+ aReduced = OUString::Concat(aPath.subView(0, nPathPrefixLen)) + "..."
+ + OUStringChar(aDelimiter) + aName;
+ }
+ else
+ {
+ aReduced += "..." + OUStringChar(aDelimiter) + "..."
+ + aName.subView( aName.getLength() - (nMaxLen - 7) );
+ }
+ }
+ else
+ aReduced = aPath;
+ }
+
+ return aReduced;
+}
+
+OUString GetSvDrawStreamNameFromURL( const INetURLObject& rSvDrawObjURL )
+{
+ OUString aRet;
+
+ if( rSvDrawObjURL.GetProtocol() == INetProtocol::PrivSoffice &&
+ comphelper::string::getTokenCount(rSvDrawObjURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), '/') == 3 )
+ {
+ aRet = rSvDrawObjURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getToken( 2, '/' );
+ }
+
+ return aRet;
+}
+
+bool FileExists( const INetURLObject& rURL )
+{
+ bool bRet = false;
+
+ if( rURL.GetProtocol() != INetProtocol::NotValid )
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ OUString aTitle;
+
+ aCnt.getPropertyValue("Title") >>= aTitle;
+ bRet = ( !aTitle.isEmpty() );
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ return bRet;
+}
+
+bool CreateDir( const INetURLObject& rURL )
+{
+ bool bRet = FileExists( rURL );
+
+ if( !bRet )
+ {
+ try
+ {
+ uno::Reference< ucb::XCommandEnvironment > aCmdEnv;
+ INetURLObject aParentURL( rURL );
+ aParentURL.removeSegment();
+ ::ucbhelper::Content aParent( aParentURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aCmdEnv, comphelper::getProcessComponentContext() );
+ uno::Sequence< OUString > aProps{ "Title" };
+ uno::Sequence< uno::Any > aValues{ uno::Any(rURL.GetLastName()) };
+
+ ::ucbhelper::Content aContent( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aCmdEnv, comphelper::getProcessComponentContext() );
+ bRet = aParent.insertNewContent( "application/vnd.sun.staroffice.fsys-folder", aProps, aValues, aContent );
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ return bRet;
+}
+
+bool CopyFile( const INetURLObject& rSrcURL, const INetURLObject& rDstURL )
+{
+ bool bRet = false;
+
+ try
+ {
+ ::ucbhelper::Content aDestPath( rDstURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+
+ aDestPath.executeCommand( "transfer",
+ uno::Any( ucb::TransferInfo( false, rSrcURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ rDstURL.GetLastName(), ucb::NameClash::OVERWRITE ) ) );
+ bRet = true;
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ return bRet;
+}
+
+bool KillFile( const INetURLObject& rURL )
+{
+ bool bRet = FileExists( rURL );
+
+ if( bRet )
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ aCnt.executeCommand( "delete", uno::Any( true ) );
+ }
+ catch( const ucb::ContentCreationException& )
+ {
+ bRet = false;
+ }
+ catch( const uno::RuntimeException& )
+ {
+ bRet = false;
+ }
+ catch( const uno::Exception& )
+ {
+ bRet = false;
+ }
+ }
+
+ return bRet;
+}
+
+
+GalleryProgress::GalleryProgress( const GraphicFilter* pFilter )
+{
+
+ uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
+
+ uno::Reference< awt::XProgressMonitor > xMonitor( xMgr->createInstance( "com.sun.star.awt.XProgressMonitor" ),
+ uno::UNO_QUERY );
+
+ if ( !xMonitor.is() )
+ return;
+
+ mxProgressBar = xMonitor;
+
+ OUString aProgressText;
+
+ if( pFilter )
+ {
+ aProgressText = SvxResId(RID_SVXSTR_GALLERY_FILTER);
+// pFilter->SetUpdatePercentHdl( LINK( this, GalleryProgress, Update ) ); // sj: progress wasn't working up from SO7 at all
+// // so I am removing this. The gallery progress should
+// // be changed to use the XStatusIndicator instead of XProgressMonitor
+ }
+ else
+ aProgressText = "Gallery";
+
+ xMonitor->addText( "Gallery", aProgressText, false ) ;
+ mxProgressBar->setRange( 0, GALLERY_PROGRESS_RANGE );
+}
+
+GalleryProgress::~GalleryProgress()
+{
+}
+
+void GalleryProgress::Update( sal_Int32 nVal, sal_Int32 nMaxVal )
+{
+ if( mxProgressBar.is() && nMaxVal )
+ mxProgressBar->setValue( std::min<sal_Int32>( static_cast<double>(nVal) / nMaxVal * GALLERY_PROGRESS_RANGE,
+ GALLERY_PROGRESS_RANGE ) );
+}
+
+
+GalleryTransferable::GalleryTransferable( GalleryTheme* pTheme, sal_uInt32 nObjectPos, bool bLazy ) :
+ mpTheme( pTheme ),
+ meObjectKind( pTheme ? mpTheme->GetObjectKind(nObjectPos) : SgaObjKind::NONE),
+ mnObjectPos( nObjectPos )
+{
+
+ InitData( bLazy );
+}
+
+void GalleryTransferable::SelectObject(sal_uInt32 nObjectPos)
+{
+ if (nObjectPos == mnObjectPos)
+ return;
+ ClearFormats();
+ mnObjectPos = nObjectPos;
+ meObjectKind = mpTheme ? mpTheme->GetObjectKind(mnObjectPos) : SgaObjKind::NONE;
+ ObjectReleased();
+ InitData(true);
+}
+
+GalleryTransferable::~GalleryTransferable()
+{
+}
+
+void GalleryTransferable::InitData( bool bLazy )
+{
+ switch( meObjectKind )
+ {
+ case SgaObjKind::SvDraw:
+ {
+ if( !bLazy )
+ {
+ if( !mpGraphicObject )
+ {
+ Graphic aGraphic;
+
+ if (mpTheme && mpTheme->GetGraphic(mnObjectPos, aGraphic))
+ mpGraphicObject.reset(new GraphicObject( aGraphic ));
+ }
+
+ if( !mxModelStream.is() )
+ {
+ mxModelStream = new SotTempStream( "" );
+ mxModelStream->SetBufferSize( 16348 );
+
+ if (!mpTheme || !mpTheme->GetModelStream(mnObjectPos, mxModelStream))
+ mxModelStream.clear();
+ else
+ mxModelStream->Seek( 0 );
+ }
+ }
+ }
+ break;
+
+ case SgaObjKind::Animation:
+ case SgaObjKind::Bitmap:
+ case SgaObjKind::Inet:
+ case SgaObjKind::Sound:
+ {
+ if( !mpURL )
+ {
+ mpURL.reset(new INetURLObject);
+
+ if (!mpTheme || !mpTheme->GetURL(mnObjectPos, *mpURL))
+ {
+ mpURL.reset();
+ }
+ }
+
+ if( ( SgaObjKind::Sound != meObjectKind ) && !mpGraphicObject )
+ {
+ Graphic aGraphic;
+
+ if (mpTheme && mpTheme->GetGraphic(mnObjectPos, aGraphic))
+ mpGraphicObject.reset(new GraphicObject( aGraphic ));
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL( "GalleryTransferable::GalleryTransferable: invalid object type" );
+ break;
+ }
+}
+
+void GalleryTransferable::AddSupportedFormats()
+{
+ if( SgaObjKind::SvDraw == meObjectKind )
+ {
+ AddFormat( SotClipboardFormatId::DRAWING );
+ AddFormat( SotClipboardFormatId::SVXB );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ }
+ else
+ {
+ if( mpURL )
+ AddFormat( SotClipboardFormatId::SIMPLE_FILE );
+
+ if( mpGraphicObject )
+ {
+ AddFormat( SotClipboardFormatId::SVXB );
+
+ if( mpGraphicObject->GetType() == GraphicType::GdiMetafile )
+ {
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ }
+ else
+ {
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ }
+ }
+ }
+}
+
+bool GalleryTransferable::GetData( const datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+{
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ bool bRet = false;
+
+ InitData( false );
+
+ if( ( SotClipboardFormatId::DRAWING == nFormat ) && ( SgaObjKind::SvDraw == meObjectKind ) )
+ {
+ bRet = ( mxModelStream.is() && SetObject( mxModelStream.get(), 0, rFlavor ) );
+ }
+ else if( ( SotClipboardFormatId::SIMPLE_FILE == nFormat ) && mpURL )
+ {
+ bRet = SetString( mpURL->GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ }
+ else if( ( SotClipboardFormatId::SVXB == nFormat ) && mpGraphicObject )
+ {
+ bRet = SetGraphic( mpGraphicObject->GetGraphic() );
+ }
+ else if( ( SotClipboardFormatId::GDIMETAFILE == nFormat ) && mpGraphicObject )
+ {
+ bRet = SetGDIMetaFile( mpGraphicObject->GetGraphic().GetGDIMetaFile() );
+ }
+ else if( ( SotClipboardFormatId::BITMAP == nFormat ) && mpGraphicObject )
+ {
+ bRet = SetBitmapEx( mpGraphicObject->GetGraphic().GetBitmapEx(), rFlavor );
+ }
+
+ return bRet;
+}
+
+bool GalleryTransferable::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject,
+ sal_uInt32, const datatransfer::DataFlavor& )
+{
+ bool bRet = false;
+
+ if( pUserObject )
+ {
+ rxOStm->WriteStream( *static_cast< SotStorageStream* >( pUserObject ) );
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+
+ return bRet;
+}
+
+void GalleryTransferable::DragFinished( sal_Int8 nDropAction )
+{
+ if (mpTheme)
+ {
+ mpTheme->SetDragging( false );
+ mpTheme->SetDragPos( 0 );
+ }
+ if ( nDropAction )
+ {
+ vcl::Window *pFocusWindow = Application::GetFocusWindow();
+ if ( pFocusWindow )
+ pFocusWindow->GrabFocusToDocument();
+ }
+}
+
+void GalleryTransferable::ObjectReleased()
+{
+ mxModelStream.clear();
+ mpGraphicObject.reset();
+ mpURL.reset();
+}
+
+bool GalleryTransferable::StartDrag()
+{
+ INetURLObject aURL;
+ if (mpTheme && mpTheme->GetURL(mnObjectPos, aURL) && aURL.GetProtocol() != INetProtocol::NotValid)
+ {
+ mpTheme->SetDragging( true );
+ mpTheme->SetDragPos( mnObjectPos );
+ return false;
+ }
+ return true;
+}
+
+INetURLObject ImplGetURL(const GalleryObject* pObject)
+{
+ INetURLObject aURL;
+
+ if (pObject)
+ aURL = pObject->getURL();
+
+ return aURL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galobj.cxx b/svx/source/gallery2/galobj.cxx
new file mode 100644
index 000000000..44362b9a7
--- /dev/null
+++ b/svx/source/gallery2/galobj.cxx
@@ -0,0 +1,493 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <sfx2/objsh.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/servicehelper.hxx>
+#include <tools/vcompat.hxx>
+#include <tools/helpers.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmview.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/galmisc.hxx>
+#include <galobj.hxx>
+#include <vcl/dibtools.hxx>
+#include <vcl/filter/SvmReader.hxx>
+#include <vcl/filter/SvmWriter.hxx>
+#include "gallerydrawmodel.hxx"
+#include <bitmaps.hlst>
+
+using namespace ::com::sun::star;
+
+SgaObject::SgaObject()
+: bIsValid ( false ),
+ bIsThumbBmp ( true )
+{
+}
+
+SgaObject::SgaObject(const SgaObject& aObject)
+ : aThumbBmp(aObject.aThumbBmp)
+ , aThumbMtf(aObject.aThumbMtf)
+ , aURL(aObject.aURL)
+ , aTitle(aObject.aTitle)
+ , bIsValid(aObject.bIsValid)
+ , bIsThumbBmp(aObject.bIsThumbBmp)
+{
+}
+
+BitmapEx SgaObject::createPreviewBitmapEx(const Size& rSizePixel) const
+{
+ BitmapEx aRetval;
+
+ if(rSizePixel.Width() && rSizePixel.Height())
+ {
+ if(SgaObjKind::Sound == GetObjKind())
+ {
+ aRetval = BitmapEx(RID_SVXBMP_GALLERY_MEDIA);
+ }
+ else if(IsThumbBitmap())
+ {
+ aRetval = GetThumbBmp();
+ }
+ else
+ {
+ const Graphic aGraphic(GetThumbMtf());
+
+ aRetval = aGraphic.GetBitmapEx();
+ }
+
+ if(!aRetval.IsEmpty())
+ {
+ const Size aCurrentSizePixel(aRetval.GetSizePixel());
+ const double fScaleX(static_cast<double>(rSizePixel.Width()) / static_cast<double>(aCurrentSizePixel.Width()));
+ const double fScaleY(static_cast<double>(rSizePixel.Height()) / static_cast<double>(aCurrentSizePixel.Height()));
+ const double fScale(std::min(fScaleX, fScaleY));
+
+ // only scale when need to decrease, no need to make bigger as original. Also
+ // prevent scaling close to 1.0 which is not needed for pixel graphics
+ if(fScale < 1.0 && fabs(1.0 - fScale) > 0.005)
+ {
+ aRetval.Scale(fScale, fScale, BmpScaleFlag::BestQuality);
+ }
+ }
+ }
+
+ return aRetval;
+}
+
+bool SgaObject::CreateThumb( const Graphic& rGraphic )
+{
+ bool bRet = false;
+
+ if( rGraphic.GetType() == GraphicType::Bitmap )
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+ Size aBmpSize( aBmpEx.GetSizePixel() );
+
+ if( aBmpSize.Width() && aBmpSize.Height() )
+ {
+ if( aBmpEx.GetPrefMapMode().GetMapUnit() != MapUnit::MapPixel &&
+ aBmpEx.GetPrefSize().Width() > 0 &&
+ aBmpEx.GetPrefSize().Height() > 0 )
+ {
+ Size aLogSize( OutputDevice::LogicToLogic(aBmpEx.GetPrefSize(), aBmpEx.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) );
+
+ if( !aLogSize.IsEmpty() )
+ {
+ double fFactorLog = static_cast< double >( aLogSize.Width() ) / aLogSize.Height();
+ double fFactorPix = static_cast< double >( aBmpSize.Width() ) / aBmpSize.Height();
+
+ if( fFactorPix > fFactorLog )
+ aBmpSize.setWidth( FRound( aBmpSize.Height() * fFactorLog ) );
+ else
+ aBmpSize.setHeight( FRound( aBmpSize.Width() / fFactorLog ) );
+
+ aBmpEx.Scale(aBmpSize, BmpScaleFlag::BestQuality);
+ }
+ }
+
+ // take over BitmapEx
+ aThumbBmp = aBmpEx;
+
+ if( ( aBmpSize.Width() <= S_THUMB ) && ( aBmpSize.Height() <= S_THUMB ) )
+ {
+ aThumbBmp.Convert( BmpConversion::N8BitColors );
+ bRet = true;
+ }
+ else
+ {
+ const float fFactor = static_cast<float>(aBmpSize.Width()) / aBmpSize.Height();
+ const Size aNewSize( std::max( tools::Long(fFactor < 1. ? S_THUMB * fFactor : S_THUMB), tools::Long(8) ),
+ std::max( tools::Long(fFactor < 1. ? S_THUMB : S_THUMB / fFactor), tools::Long(8) ) );
+ if(aThumbBmp.Scale(
+ static_cast<double>(aNewSize.Width()) / aBmpSize.Width(),
+ static_cast<double>(aNewSize.Height()) / aBmpSize.Height(),
+ BmpScaleFlag::BestQuality ) )
+ {
+ aThumbBmp.Convert( BmpConversion::N8BitColors );
+ bRet = true;
+ }
+ }
+ }
+ }
+ else if( rGraphic.GetType() == GraphicType::GdiMetafile )
+ {
+ const Size aPrefSize( rGraphic.GetPrefSize() );
+ const double fFactor = static_cast<double>(aPrefSize.Width()) / static_cast<double>(aPrefSize.Height());
+ Size aSize( S_THUMB, S_THUMB );
+ if ( fFactor < 1.0 )
+ aSize.setWidth( static_cast<sal_Int32>( S_THUMB * fFactor ) );
+ else
+ aSize.setHeight( static_cast<sal_Int32>( S_THUMB / fFactor ) );
+
+ const GraphicConversionParameters aParameters(aSize, false, true, true /*TODO: extra ", true" post-#i121194#*/);
+ aThumbBmp = rGraphic.GetBitmapEx(aParameters);
+
+ if( !aThumbBmp.IsEmpty() )
+ {
+ aThumbBmp.Convert( BmpConversion::N8BitColors );
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+void SgaObject::WriteData( SvStream& rOut, const OUString& rDestDir ) const
+{
+ static const sal_uInt32 nInventor = COMPAT_FORMAT( 'S', 'G', 'A', '3' );
+
+ rOut.WriteUInt32( nInventor ).WriteUInt16( 0x0004 ).WriteUInt16( GetVersion() ).WriteUInt16( static_cast<sal_uInt16>(GetObjKind()) );
+ rOut.WriteBool( bIsThumbBmp );
+
+ if( bIsThumbBmp )
+ {
+ const SvStreamCompressFlags nOldCompressMode = rOut.GetCompressMode();
+ const sal_Int32 nOldVersion = rOut.GetVersion();
+
+ rOut.SetCompressMode( SvStreamCompressFlags::ZBITMAP );
+ rOut.SetVersion( SOFFICE_FILEFORMAT_50 );
+
+ WriteDIBBitmapEx(aThumbBmp, rOut);
+
+ rOut.SetVersion( nOldVersion );
+ rOut.SetCompressMode( nOldCompressMode );
+ }
+ else
+ {
+ if(!rOut.GetError())
+ {
+ SvmWriter aWriter(rOut);
+ aWriter.Write(aThumbMtf);
+ }
+ }
+
+ OUString aURLWithoutDestDir = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ aURLWithoutDestDir = aURLWithoutDestDir.replaceFirst(rDestDir, "");
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aURLWithoutDestDir, RTL_TEXTENCODING_UTF8);
+}
+
+void SgaObject::ReadData(SvStream& rIn, sal_uInt16& rReadVersion )
+{
+ sal_uInt32 nTmp32;
+ sal_uInt16 nTmp16;
+
+ rIn.ReadUInt32( nTmp32 ).ReadUInt16( nTmp16 ).ReadUInt16( rReadVersion ).ReadUInt16( nTmp16 ).ReadCharAsBool( bIsThumbBmp );
+
+ if( bIsThumbBmp )
+ {
+ ReadDIBBitmapEx(aThumbBmp, rIn);
+ }
+ else
+ {
+ SvmReader aReader( rIn );
+ aReader.Read( aThumbMtf );
+ }
+
+ OUString aTmpStr = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
+ aURL = INetURLObject(aTmpStr);
+}
+
+OUString const & SgaObject::GetTitle() const
+{
+ return aTitle;
+}
+
+void SgaObject::SetTitle( const OUString& rTitle )
+{
+ aTitle = rTitle;
+}
+
+SvStream& WriteSgaObject( SvStream& rOut, const SgaObject& rObj )
+{
+ rObj.WriteData( rOut, "" );
+ return rOut;
+}
+
+SvStream& ReadSgaObject( SvStream& rIn, SgaObject& rObj )
+{
+ sal_uInt16 nReadVersion;
+
+ rObj.ReadData( rIn, nReadVersion );
+ rObj.bIsValid = ( rIn.GetError() == ERRCODE_NONE );
+
+ return rIn;
+}
+
+SgaObjectBmp::SgaObjectBmp()
+{
+}
+
+SgaObjectBmp::SgaObjectBmp( const INetURLObject& rURL )
+{
+ Graphic aGraphic;
+ OUString aFilter;
+
+ if ( GalleryGraphicImportRet::IMPORT_NONE != GalleryGraphicImport( rURL, aGraphic, aFilter ) )
+ Init( aGraphic, rURL );
+}
+
+SgaObjectBmp::SgaObjectBmp( const Graphic& rGraphic, const INetURLObject& rURL )
+{
+ if( FileExists( rURL ) )
+ Init( rGraphic, rURL );
+}
+
+void SgaObjectBmp::Init( const Graphic& rGraphic, const INetURLObject& rURL )
+{
+ aURL = rURL;
+ bIsValid = CreateThumb( rGraphic );
+}
+
+void SgaObjectBmp::WriteData( SvStream& rOut, const OUString& rDestDir ) const
+{
+ // Set version
+ SgaObject::WriteData( rOut, rDestDir );
+ char const aDummy[ 10 ] = { 0 };
+ rOut.WriteBytes(aDummy, 10);
+ write_uInt16_lenPrefixed_uInt8s_FromOString(rOut, ""); //dummy
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
+}
+
+void SgaObjectBmp::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
+{
+
+ SgaObject::ReadData( rIn, rReadVersion );
+ rIn.SeekRel( 10 ); // 16, 16, 32, 16
+ read_uInt16_lenPrefixed_uInt8s_ToOString(rIn); //dummy
+
+ if( rReadVersion >= 5 )
+ aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
+}
+
+
+SgaObjectSound::SgaObjectSound() :
+ eSoundType( SOUND_STANDARD )
+{
+}
+
+SgaObjectSound::SgaObjectSound( const INetURLObject& rURL ) :
+ eSoundType( SOUND_STANDARD )
+{
+
+ if( FileExists( rURL ) )
+ {
+ aURL = rURL;
+ aThumbBmp = Bitmap(Size(1, 1), vcl::PixelFormat::N1_BPP);
+ bIsValid = true;
+ }
+ else
+ bIsValid = false;
+}
+
+SgaObjectSound::~SgaObjectSound()
+{
+}
+
+BitmapEx SgaObjectSound::GetThumbBmp() const
+{
+ OUString sId;
+
+ switch( eSoundType )
+ {
+ case SOUND_COMPUTER: sId = RID_SVXBMP_GALLERY_SOUND_1; break;
+ case SOUND_MISC: sId = RID_SVXBMP_GALLERY_SOUND_2; break;
+ case SOUND_MUSIC: sId = RID_SVXBMP_GALLERY_SOUND_3; break;
+ case SOUND_NATURE: sId = RID_SVXBMP_GALLERY_SOUND_4; break;
+ case SOUND_SPEECH: sId = RID_SVXBMP_GALLERY_SOUND_5; break;
+ case SOUND_TECHNIC: sId = RID_SVXBMP_GALLERY_SOUND_6; break;
+ case SOUND_ANIMAL: sId = RID_SVXBMP_GALLERY_SOUND_7; break;
+
+ // standard
+ default:
+ sId = RID_SVXBMP_GALLERY_MEDIA;
+ break;
+ }
+
+ const BitmapEx aBmpEx(sId);
+
+ return aBmpEx;
+}
+
+void SgaObjectSound::WriteData( SvStream& rOut, const OUString& rDestDir ) const
+{
+ SgaObject::WriteData( rOut, rDestDir );
+ rOut.WriteUInt16( eSoundType );
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
+}
+
+void SgaObjectSound::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
+{
+ SgaObject::ReadData( rIn, rReadVersion );
+
+ if( rReadVersion >= 5 )
+ {
+ sal_uInt16 nTmp16;
+
+ rIn.ReadUInt16( nTmp16 ); eSoundType = static_cast<GalSoundType>(nTmp16);
+
+ if( rReadVersion >= 6 )
+ aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
+ }
+}
+
+SgaObjectAnim::SgaObjectAnim()
+{
+}
+
+SgaObjectAnim::SgaObjectAnim( const Graphic& rGraphic,
+ const INetURLObject& rURL )
+{
+ aURL = rURL;
+ bIsValid = CreateThumb( rGraphic );
+}
+
+SgaObjectINet::SgaObjectINet()
+{
+}
+
+SgaObjectINet::SgaObjectINet( const Graphic& rGraphic, const INetURLObject& rURL ) :
+ SgaObjectAnim ( rGraphic, rURL )
+{
+}
+
+SgaObjectSvDraw::SgaObjectSvDraw()
+{
+}
+
+SgaObjectSvDraw::SgaObjectSvDraw( const FmFormModel& rModel, const INetURLObject& rURL )
+{
+ aURL = rURL;
+ bIsValid = CreateThumb( rModel );
+}
+
+
+SvxGalleryDrawModel::SvxGalleryDrawModel()
+: mpFormModel( nullptr )
+{
+ mxDoc = SfxObjectShell::CreateObjectByFactoryName( "sdraw" );
+
+ if( !mxDoc.Is() )
+ return;
+
+ mxDoc->DoInitNew();
+
+ mpFormModel
+ = dynamic_cast<FmFormModel*>(comphelper::getFromUnoTunnel<SdrModel>(mxDoc->GetModel()));
+ if (mpFormModel)
+ {
+ mpFormModel->InsertPage(mpFormModel->AllocPage(false).get());
+ }
+}
+
+SvxGalleryDrawModel::~SvxGalleryDrawModel()
+{
+ if( mxDoc.Is() )
+ mxDoc->DoClose();
+
+}
+
+SgaObjectSvDraw::SgaObjectSvDraw( SvStream& rIStm, const INetURLObject& rURL )
+{
+ SvxGalleryDrawModel aModel;
+
+ if( aModel.GetModel() )
+ {
+ if( GallerySvDrawImport( rIStm, *aModel.GetModel() ) )
+ {
+ aURL = rURL;
+ bIsValid = CreateThumb( *aModel.GetModel() );
+ }
+ }
+}
+
+bool SgaObjectSvDraw::CreateThumb( const FmFormModel& rModel )
+{
+ Graphic aGraphic;
+ ImageMap aImageMap;
+ bool bRet = false;
+
+ if ( CreateIMapGraphic( rModel, aGraphic, aImageMap ) )
+ {
+ bRet = SgaObject::CreateThumb( aGraphic );
+ }
+ else
+ {
+ const FmFormPage* pPage = static_cast< const FmFormPage* >(rModel.GetPage(0));
+
+ if(pPage)
+ {
+ const tools::Rectangle aObjRect(pPage->GetAllObjBoundRect());
+
+ if(aObjRect.GetWidth() && aObjRect.GetHeight())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ FmFormView aView(const_cast< FmFormModel& >(rModel), pVDev);
+
+ aView.ShowSdrPage(const_cast< FmFormPage* >(pPage));
+ aView.MarkAllObj();
+ aThumbBmp = aView.GetMarkedObjBitmapEx(true);
+ aGraphic = Graphic(aThumbBmp);
+ bRet = SgaObject::CreateThumb(aGraphic);
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void SgaObjectSvDraw::WriteData( SvStream& rOut, const OUString& rDestDir ) const
+{
+ SgaObject::WriteData( rOut, rDestDir );
+ write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
+}
+
+void SgaObjectSvDraw::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
+{
+ SgaObject::ReadData( rIn, rReadVersion );
+
+ if( rReadVersion >= 5 )
+ aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gallery2/galtheme.cxx b/svx/source/gallery2/galtheme.cxx
new file mode 100644
index 000000000..4a9d10e60
--- /dev/null
+++ b/svx/source/gallery2/galtheme.cxx
@@ -0,0 +1,780 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <sal/config.h>
+
+#include <algorithm>
+
+#include <osl/file.hxx>
+#include <osl/thread.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/vcompat.hxx>
+#include <tools/datetime.hxx>
+#include <sot/storage.hxx>
+#include <sot/formats.hxx>
+#include <sot/filelist.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmview.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/galtheme.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/galleryobjectcollection.hxx>
+#include <galleryobjectbinarystorage.hxx>
+#include <galobj.hxx>
+#include <svx/gallery1.hxx>
+#include "gallerydrawmodel.hxx"
+#include <memory>
+
+using namespace ::com::sun::star;
+
+GalleryTheme::GalleryTheme( Gallery* pGallery, GalleryThemeEntry* pThemeEntry )
+ : pParent(pGallery)
+ , pThm(pThemeEntry)
+ , mnThemeLockCount(0)
+ , mnBroadcasterLockCount(0)
+ , nDragPos(0)
+ , bDragging(false)
+ , bAbortActualize(false)
+{
+ mpGalleryStorageEngine = pThm->createGalleryStorageEngine(maGalleryObjectCollection);
+}
+
+GalleryTheme::~GalleryTheme()
+{
+ if(pThm->IsModified())
+ if(!mpGalleryStorageEngine->implWrite(*this, pThm))
+ ImplSetModified(false);
+
+ for (auto & pEntry : maGalleryObjectCollection.getObjectList())
+ {
+ Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pEntry.get() ) );
+ pEntry.reset();
+ }
+ maGalleryObjectCollection.clear();
+ mpGalleryStorageEngine->clearSotStorage();
+}
+
+void GalleryTheme::SetDestDir(const OUString& rDestDir, bool bRelative)
+{
+ mpGalleryStorageEngine->setDestDir(rDestDir, bRelative);
+}
+
+void GalleryTheme::ImplBroadcast(sal_uInt32 nUpdatePos)
+{
+ if( !IsBroadcasterLocked() )
+ {
+ if( GetObjectCount() && ( nUpdatePos >= GetObjectCount() ) )
+ nUpdatePos = GetObjectCount() - 1;
+
+ Broadcast( GalleryHint( GalleryHintType::THEME_UPDATEVIEW, GetName(), reinterpret_cast<void*>(nUpdatePos) ) );
+ }
+}
+
+bool GalleryTheme::UnlockTheme()
+{
+ DBG_ASSERT( mnThemeLockCount, "Theme is not locked" );
+
+ bool bRet = false;
+
+ if( mnThemeLockCount )
+ {
+ --mnThemeLockCount;
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+void GalleryTheme::UnlockBroadcaster()
+{
+ DBG_ASSERT( mnBroadcasterLockCount, "Broadcaster is not locked" );
+
+ if( mnBroadcasterLockCount && !--mnBroadcasterLockCount )
+ ImplBroadcast( 0 );
+}
+
+bool GalleryTheme::InsertObject(const SgaObject& rObj, sal_uInt32 nInsertPos)
+{
+ if (!rObj.IsValid())
+ return false;
+
+ GalleryObject* pFoundEntry = nullptr;
+ sal_uInt32 iFoundPos = 0;
+ for (sal_uInt32 n = maGalleryObjectCollection.size(); iFoundPos < n; ++iFoundPos)
+ {
+ if (maGalleryObjectCollection.get(iFoundPos)->getURL() == rObj.GetURL())
+ {
+ pFoundEntry = maGalleryObjectCollection.get(iFoundPos).get();
+ break;
+ }
+ }
+
+ mpGalleryStorageEngine->insertObject(rObj, pFoundEntry, nInsertPos);
+
+ ImplSetModified(true);
+ ImplBroadcast(pFoundEntry? iFoundPos: nInsertPos);
+
+ return true;
+}
+
+std::unique_ptr<SgaObject> GalleryTheme::AcquireObject(sal_uInt32 nPos)
+{
+ return mpGalleryStorageEngine->implReadSgaObject(maGalleryObjectCollection.getForPosition(nPos));
+}
+
+void GalleryTheme::GetPreviewBitmapExAndStrings(sal_uInt32 nPos, BitmapEx& rBitmapEx, Size& rSize, OUString& rTitle, OUString& rPath)
+{
+ const GalleryObject* pGalleryObject = maGalleryObjectCollection.get(nPos).get();
+
+ rBitmapEx = pGalleryObject->maPreviewBitmapEx;
+ rSize = pGalleryObject->maPreparedSize;
+ rTitle = pGalleryObject->maTitle;
+ rPath = pGalleryObject->maPath;
+}
+
+void GalleryTheme::SetPreviewBitmapExAndStrings(sal_uInt32 nPos, const BitmapEx& rBitmapEx, const Size& rSize, const OUString& rTitle, const OUString& rPath)
+{
+ GalleryObject* pGalleryObject = maGalleryObjectCollection.get(nPos).get();
+
+ pGalleryObject->maPreviewBitmapEx = rBitmapEx;
+ pGalleryObject->maPreparedSize = rSize;
+ pGalleryObject->maTitle = rTitle;
+ pGalleryObject->maPath = rPath;
+}
+
+void GalleryTheme::RemoveObject(sal_uInt32 nPos)
+{
+ auto it = maGalleryObjectCollection.getObjectList().begin() + nPos;
+ std::unique_ptr<GalleryObject> pEntry = std::move(*it);
+ maGalleryObjectCollection.getObjectList().erase( it );
+
+ mpGalleryStorageEngine->removeObject(pEntry);
+
+ Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pEntry.get() ) );
+ pEntry.reset();
+
+ ImplSetModified( true );
+ ImplBroadcast( nPos );
+}
+
+bool GalleryTheme::ChangeObjectPos(sal_uInt32 nOldPos, sal_uInt32 nNewPos)
+{
+ if (nOldPos == nNewPos || nOldPos >= maGalleryObjectCollection.size())
+ return false;
+
+ std::unique_ptr<GalleryObject> pEntry = std::move(maGalleryObjectCollection.get(nOldPos));
+
+ maGalleryObjectCollection.getObjectList().insert(maGalleryObjectCollection.getObjectList().begin() + nNewPos, std::move(pEntry));
+
+ if (nNewPos < nOldPos)
+ nOldPos++;
+
+ auto it = maGalleryObjectCollection.getObjectList().begin() + nOldPos;
+ maGalleryObjectCollection.getObjectList().erase(it);
+
+ ImplSetModified(true);
+ ImplBroadcast((nNewPos < nOldPos)? nNewPos: (nNewPos - 1));
+
+ return true;
+}
+
+void GalleryTheme::Actualize( const Link<const INetURLObject&, void>& rActualizeLink, GalleryProgress* pProgress )
+{
+ if( IsReadOnly() )
+ return;
+
+ Graphic aGraphic;
+ OUString aFormat;
+ const sal_uInt32 nCount = maGalleryObjectCollection.size();
+
+ LockBroadcaster();
+ bAbortActualize = false;
+
+ // reset delete flag
+ for (sal_uInt32 i = 0; i < nCount; i++)
+ maGalleryObjectCollection.get(i)->mbDelete = false;
+
+ for (sal_uInt32 i = 0; ( i < nCount ) && !bAbortActualize; i++)
+ {
+ if( pProgress )
+ pProgress->Update( i, nCount - 1 );
+
+ GalleryObject* pEntry = maGalleryObjectCollection.get(i).get();
+
+ const INetURLObject aURL( pEntry->getURL());
+
+ rActualizeLink.Call( aURL );
+
+ // SvDraw objects will be updated later
+ if( pEntry->eObjKind != SgaObjKind::SvDraw )
+ {
+ // Still a function should be implemented,
+ // which assigns files to the relevant entry.
+ // insert graphics as graphic objects into the gallery
+ if( pEntry->eObjKind == SgaObjKind::Sound )
+ {
+ SgaObjectSound aObjSound( aURL );
+ if( !InsertObject( aObjSound ) )
+ pEntry->mbDelete = true;
+ }
+ else
+ {
+ aGraphic.Clear();
+
+ if ( GalleryGraphicImport( aURL, aGraphic, aFormat ) != GalleryGraphicImportRet::IMPORT_NONE )
+ {
+ std::unique_ptr<SgaObject> pNewObj;
+
+ if ( SgaObjKind::Inet == pEntry->eObjKind )
+ pNewObj.reset(new SgaObjectINet( aGraphic, aURL ));
+ else if ( aGraphic.IsAnimated() )
+ pNewObj.reset(new SgaObjectAnim( aGraphic, aURL ));
+ else
+ pNewObj.reset(new SgaObjectBmp( aGraphic, aURL ));
+
+ if( !InsertObject( *pNewObj ) )
+ pEntry->mbDelete = true;
+ }
+ else
+ pEntry->mbDelete = true; // set delete flag
+ }
+ }
+ else
+ {
+ //update SvDraw object
+ if ( mpGalleryStorageEngine->GetSvDrawStorage().is() )
+ {
+ SgaObjectSvDraw aNewObj = mpGalleryStorageEngine->updateSvDrawObject(pEntry);
+ if (aNewObj.IsValid() && !InsertObject(aNewObj))
+ pEntry->mbDelete = true;
+ }
+ }
+ }
+
+ // remove all entries with set flag
+ for ( auto it = maGalleryObjectCollection.getObjectList().begin(); it != maGalleryObjectCollection.getObjectList().end(); /* increment is in the body of loop */)
+ {
+ if( (*it)->mbDelete )
+ {
+ Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), it->get() ) );
+ it = maGalleryObjectCollection.getObjectList().erase( it );
+ }
+ else
+ ++it;
+ }
+
+ // update theme
+ mpGalleryStorageEngine->updateTheme();
+ ImplSetModified( true );
+ if (pThm->IsModified())
+ if (!mpGalleryStorageEngine->implWrite(*this, pThm))
+ ImplSetModified(false);
+ UnlockBroadcaster();
+}
+
+bool GalleryTheme::GetThumb(sal_uInt32 nPos, BitmapEx& rBmp)
+{
+ std::unique_ptr<SgaObject> pObj = AcquireObject( nPos );
+ bool bRet = false;
+
+ if( pObj )
+ {
+ rBmp = pObj->GetThumbBmp();
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::GetGraphic(sal_uInt32 nPos, Graphic& rGraphic)
+{
+ const GalleryObject* pObject = maGalleryObjectCollection.getForPosition( nPos );
+ bool bRet = false;
+
+ if( pObject )
+ {
+ const INetURLObject aURL( ImplGetURL( pObject ) );
+
+ switch( pObject->eObjKind )
+ {
+ case SgaObjKind::Bitmap:
+ case SgaObjKind::Animation:
+ case SgaObjKind::Inet:
+ {
+ OUString aFilterDummy;
+ bRet = ( GalleryGraphicImport( aURL, rGraphic, aFilterDummy ) != GalleryGraphicImportRet::IMPORT_NONE );
+ }
+ break;
+
+ case SgaObjKind::SvDraw:
+ {
+ SvxGalleryDrawModel aModel;
+
+ if( aModel.GetModel() )
+ {
+ if( GetModel( nPos, *aModel.GetModel() ) )
+ {
+ ImageMap aIMap;
+
+ if( CreateIMapGraphic( *aModel.GetModel(), rGraphic, aIMap ) )
+ bRet = true;
+ else
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ pVDev->SetMapMode( MapMode( MapUnit::Map100thMM ) );
+ FmFormView aView(*aModel.GetModel(), pVDev);
+
+ aView.hideMarkHandles();
+ aView.ShowSdrPage(aView.GetModel()->GetPage(0));
+ aView.MarkAll();
+ rGraphic = aView.GetAllMarkedGraphic();
+ bRet = true;
+ }
+ }
+ }
+ }
+ break;
+
+ case SgaObjKind::Sound:
+ {
+ std::unique_ptr<SgaObject> pObj = AcquireObject( nPos );
+
+ if( pObj )
+ {
+ rGraphic = pObj->GetThumbBmp();
+ //Bitmap aBmp( pObj->GetThumbBmp() );
+ //aBmp.Replace( COL_LIGHTMAGENTA, COL_WHITE );
+ //rGraphic = aBmp;
+ bRet = true;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertGraphic(const Graphic& rGraphic, sal_uInt32 nInsertPos)
+{
+ bool bRet = false;
+
+ if( rGraphic.GetType() != GraphicType::NONE )
+ {
+ ConvertDataFormat nExportFormat = ConvertDataFormat::Unknown;
+ const GfxLink aGfxLink( rGraphic.GetGfxLink() );
+
+ if( aGfxLink.GetDataSize() )
+ {
+ switch( aGfxLink.GetType() )
+ {
+ case GfxLinkType::EpsBuffer: nExportFormat = ConvertDataFormat::SVM; break;
+ case GfxLinkType::NativeGif: nExportFormat = ConvertDataFormat::GIF; break;
+
+ // #i15508# added BMP type
+ // could not find/trigger a call to this, but should do no harm
+ case GfxLinkType::NativeBmp: nExportFormat = ConvertDataFormat::BMP; break;
+
+ case GfxLinkType::NativeJpg: nExportFormat = ConvertDataFormat::JPG; break;
+ case GfxLinkType::NativePng: nExportFormat = ConvertDataFormat::PNG; break;
+ case GfxLinkType::NativeTif: nExportFormat = ConvertDataFormat::TIF; break;
+ case GfxLinkType::NativeWmf: nExportFormat = ConvertDataFormat::WMF; break;
+ case GfxLinkType::NativeMet: nExportFormat = ConvertDataFormat::MET; break;
+ case GfxLinkType::NativePct: nExportFormat = ConvertDataFormat::PCT; break;
+ case GfxLinkType::NativeSvg: nExportFormat = ConvertDataFormat::SVG; break;
+ case GfxLinkType::NativeWebp: nExportFormat = ConvertDataFormat::WEBP; break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ if( rGraphic.GetType() == GraphicType::Bitmap )
+ {
+ if( rGraphic.IsAnimated() )
+ nExportFormat = ConvertDataFormat::GIF;
+ else
+ nExportFormat = ConvertDataFormat::PNG;
+ }
+ else
+ nExportFormat = ConvertDataFormat::SVM;
+ }
+
+ const SgaObjectBmp aObjBmp = mpGalleryStorageEngine->insertGraphic(rGraphic, aGfxLink, nExportFormat, GetParent()->GetUserURL());
+
+ if (aObjBmp.IsValid())
+ bRet = InsertObject(aObjBmp, nInsertPos);
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::GetModel(sal_uInt32 nPos, SdrModel& rModel)
+{
+ const GalleryObject* pObject = maGalleryObjectCollection.getForPosition( nPos );
+ bool bRet = false;
+
+ if( pObject && ( SgaObjKind::SvDraw == pObject->eObjKind ) )
+ {
+ bRet = mpGalleryStorageEngine->readModel(pObject, rModel);
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertModel(const FmFormModel& rModel, sal_uInt32 nInsertPos)
+{
+ bool bRet = false;
+ SgaObjectSvDraw aObjSvDraw = mpGalleryStorageEngine->insertModel(rModel, GetParent()->GetUserURL());
+ if(aObjSvDraw.IsValid())
+ bRet = InsertObject( aObjSvDraw, nInsertPos );
+ return bRet;
+}
+
+bool GalleryTheme::GetModelStream(sal_uInt32 nPos, tools::SvRef<SotTempStream> const & rxModelStream)
+{
+ const GalleryObject* pObject = maGalleryObjectCollection.getForPosition( nPos );
+ bool bRet = false;
+
+ if( pObject && ( SgaObjKind::SvDraw == pObject->eObjKind ) )
+ {
+ bRet = mpGalleryStorageEngine->readModelStream(pObject, rxModelStream);
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertModelStream(const tools::SvRef<SotTempStream>& rxModelStream, sal_uInt32 nInsertPos)
+{
+ bool bRet = false;
+
+ const SgaObjectSvDraw aObjSvDraw = mpGalleryStorageEngine->insertModelStream(rxModelStream, GetParent()->GetUserURL());
+ if(aObjSvDraw.IsValid())
+ bRet = InsertObject( aObjSvDraw, nInsertPos );
+
+ return bRet;
+}
+
+bool GalleryTheme::GetURL(sal_uInt32 nPos, INetURLObject& rURL)
+{
+ const GalleryObject* pObject = maGalleryObjectCollection.getForPosition( nPos );
+ bool bRet = false;
+
+ if( pObject )
+ {
+ rURL = ImplGetURL( pObject );
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertURL(const INetURLObject& rURL, sal_uInt32 nInsertPos)
+{
+ Graphic aGraphic;
+ OUString aFormat;
+ std::unique_ptr<SgaObject> pNewObj;
+ const GalleryGraphicImportRet nImportRet = GalleryGraphicImport( rURL, aGraphic, aFormat );
+ bool bRet = false;
+
+ if( nImportRet != GalleryGraphicImportRet::IMPORT_NONE )
+ {
+ if ( aGraphic.IsAnimated() )
+ pNewObj.reset(new SgaObjectAnim( aGraphic, rURL ));
+ else
+ pNewObj.reset(new SgaObjectBmp( aGraphic, rURL ));
+ }
+#if HAVE_FEATURE_AVMEDIA
+ else if( ::avmedia::MediaWindow::isMediaURL( rURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ), ""/*TODO?*/ ) )
+ pNewObj.reset(new SgaObjectSound( rURL ));
+#endif
+ if( pNewObj && InsertObject( *pNewObj, nInsertPos ) )
+ bRet = true;
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertFileOrDirURL(const INetURLObject& rFileOrDirURL, sal_uInt32 nInsertPos)
+{
+ bool bRet = false;
+ std::vector< INetURLObject > aURLVector;
+ GalleryBinaryEngine::insertFileOrDirURL(rFileOrDirURL, aURLVector);
+
+ for( const auto& rURL : aURLVector )
+ bRet = bRet || InsertURL( rURL, nInsertPos );
+
+ return bRet;
+}
+
+bool GalleryTheme::InsertTransferable(const uno::Reference< datatransfer::XTransferable >& rxTransferable, sal_uInt32 nInsertPos)
+{
+ bool bRet = false;
+
+ if( rxTransferable.is() )
+ {
+ TransferableDataHelper aDataHelper( rxTransferable );
+ std::unique_ptr<Graphic> pGraphic;
+
+ if( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) )
+ {
+ tools::SvRef<SotTempStream> xModelStm;
+
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::DRAWING, xModelStm ) )
+ bRet = InsertModelStream( xModelStm, nInsertPos );
+ }
+ else if( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) ||
+ aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) )
+ {
+ FileList aFileList;
+
+ if( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
+ aDataHelper.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList );
+ else
+ {
+ OUString aFile;
+ if (aDataHelper.GetString(SotClipboardFormatId::SIMPLE_FILE, aFile) && !aFile.isEmpty())
+ aFileList.AppendFile( aFile );
+ }
+
+ for( sal_uInt32 i = 0, nCount = aFileList.Count(); i < nCount; ++i )
+ {
+ const OUString aFile( aFileList.GetFile( i ) );
+ INetURLObject aURL( aFile );
+
+ if( aURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ OUString aLocalURL;
+
+ if( osl::FileBase::getFileURLFromSystemPath( aFile, aLocalURL ) == osl::FileBase::E_None )
+ aURL = INetURLObject( aLocalURL );
+ }
+
+ if( aURL.GetProtocol() != INetProtocol::NotValid )
+ bRet = InsertFileOrDirURL( aURL, nInsertPos );
+ }
+ }
+ else
+ {
+ Graphic aGraphic;
+ SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
+
+ if( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
+ nFormat = SotClipboardFormatId::SVXB;
+ else if( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
+ nFormat = SotClipboardFormatId::GDIMETAFILE;
+ else if( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) )
+ nFormat = SotClipboardFormatId::BITMAP;
+
+ if( nFormat != SotClipboardFormatId::NONE && aDataHelper.GetGraphic( nFormat, aGraphic ) )
+ pGraphic.reset(new Graphic( aGraphic ));
+ }
+
+ if( pGraphic )
+ {
+ bRet = false;
+
+ if( aDataHelper.HasFormat( SotClipboardFormatId::SVIM ) )
+ {
+
+ ImageMap aImageMap;
+
+ // according to KA we don't need a BaseURL here
+ if( aDataHelper.GetImageMap( SotClipboardFormatId::SVIM, aImageMap ) )
+ {
+ SvxGalleryDrawModel aModel;
+
+ if( aModel.GetModel() )
+ {
+ SdrPage* pPage = aModel.GetModel()->GetPage(0);
+ SdrGrafObj* pGrafObj = new SdrGrafObj(*aModel.GetModel(), *pGraphic );
+
+ pGrafObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SgaIMapInfo( aImageMap )) );
+ pPage->InsertObject( pGrafObj );
+ bRet = InsertModel( *aModel.GetModel(), nInsertPos );
+ }
+ }
+ }
+
+ if( !bRet )
+ bRet = InsertGraphic( *pGraphic, nInsertPos );
+ }
+ }
+
+ return bRet;
+}
+
+void GalleryTheme::CopyToClipboard(const weld::Widget& rWidget, sal_uInt32 nPos)
+{
+ rtl::Reference<GalleryTransferable> pTransferable = new GalleryTransferable( this, nPos, false );
+ pTransferable->CopyToClipboard(rWidget.get_clipboard());
+}
+
+DateTime GalleryTheme::getModificationDate() const
+{
+ return mpGalleryStorageEngine->getModificationDate();
+}
+
+SvStream& GalleryTheme::ReadData( SvStream& rIStm )
+{
+ sal_uInt32 nCount;
+ sal_uInt16 nVersion;
+
+ rIStm.ReadUInt16( nVersion );
+ read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm);
+ rIStm.ReadUInt32( nCount );
+
+ if( nVersion >= 0x0004 )
+ {
+ sal_uInt16 nTmp16;
+ rIStm.ReadUInt16( nTmp16 );
+ }
+
+ if( nCount <= ( 1 << 14 ) )
+ {
+ INetURLObject aRelURL1( GetParent()->GetRelativeURL() );
+ INetURLObject aRelURL2( GetParent()->GetUserURL() );
+ sal_uInt32 nId1, nId2;
+ bool bRel;
+
+ for(auto & i : maGalleryObjectCollection.getObjectList())
+ {
+ GalleryObject* pObj = i.get();
+ Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pObj ) );
+ i.reset();
+ }
+ maGalleryObjectCollection.clear();
+
+ for( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ std::unique_ptr<GalleryObject> pObj(new GalleryObject);
+
+ OUString aFileName;
+ sal_uInt16 nTemp;
+
+ rIStm.ReadCharAsBool( bRel );
+ OString aTempFileName = read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm);
+ rIStm.ReadUInt32( pObj->nOffset );
+ rIStm.ReadUInt16( nTemp ); pObj->eObjKind = static_cast<SgaObjKind>(nTemp);
+
+ aFileName = OStringToOUString(aTempFileName, osl_getThreadTextEncoding());
+
+ pObj->m_pGalleryObjectStorage.reset();
+ pObj->m_pGalleryObjectStorage = std::make_unique<GalleryObjectBinaryStorage>();
+
+ if( bRel )
+ {
+ aFileName = aFileName.replaceAll( "\\", "/" );
+ OUString aPath = aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ if( aFileName[ 0 ] != '/' )
+ aPath += "/";
+
+ aPath += aFileName;
+
+ pObj->m_pGalleryObjectStorage->setURL(INetURLObject(aPath));
+
+ if (!FileExists(pObj->getURL()))
+ {
+ aPath = aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ if( aFileName[0] != '/' )
+ aPath += "/";
+
+ aPath += aFileName;
+
+ // assign this URL, even in the case it is not valid (#94482)
+ pObj->m_pGalleryObjectStorage->setURL(INetURLObject(aPath));
+ }
+ }
+ else
+ {
+ if( SgaObjKind::SvDraw == pObj->eObjKind )
+ {
+ OUString aDummyURL = "gallery/svdraw/" + aFileName;
+ pObj->m_pGalleryObjectStorage->setURL(INetURLObject(aDummyURL, INetProtocol::PrivSoffice));
+ }
+ else
+ {
+ OUString aLocalURL;
+
+ pObj->m_pGalleryObjectStorage->setURL(INetURLObject(aFileName));
+
+ if( ( pObj->getURL().GetProtocol() == INetProtocol::NotValid ) &&
+ osl::FileBase::getFileURLFromSystemPath( aFileName, aLocalURL ) == osl::FileBase::E_None )
+ {
+ pObj->m_pGalleryObjectStorage->setURL(INetURLObject(aLocalURL));
+ }
+ }
+ }
+ maGalleryObjectCollection.getObjectList().push_back( std::move(pObj) );
+ }
+
+ rIStm.ReadUInt32( nId1 ).ReadUInt32( nId2 );
+
+ // In newer versions a 512 byte reserve buffer is located at the end,
+ // the data is located at the beginning of this buffer and are clamped
+ // by a VersionCompatRead.
+ if( !rIStm.eof() &&
+ nId1 == COMPAT_FORMAT( 'G', 'A', 'L', 'R' ) &&
+ nId2 == COMPAT_FORMAT( 'E', 'S', 'R', 'V' ) )
+ {
+ VersionCompatRead aCompat(rIStm);
+ sal_uInt32 nTemp32;
+ bool bThemeNameFromResource = false;
+
+ rIStm.ReadUInt32( nTemp32 );
+
+ if( aCompat.GetVersion() >= 2 )
+ {
+ rIStm.ReadCharAsBool( bThemeNameFromResource );
+ }
+
+ SetId( nTemp32, bThemeNameFromResource );
+ }
+ }
+ else
+ rIStm.SetError( SVSTREAM_READ_ERROR );
+
+ ImplSetModified( false );
+
+ return rIStm;
+}
+
+void GalleryTheme::ImplSetModified( bool bModified )
+{
+ pThm->SetModified(bModified);
+}
+
+sal_uInt32 GalleryTheme::GetId() const { return pThm->GetId(); }
+void GalleryTheme::SetId( sal_uInt32 nNewId, bool bResetThemeName ) { pThm->SetId( nNewId, bResetThemeName ); }
+bool GalleryTheme::IsReadOnly() const { return pThm->IsReadOnly(); }
+bool GalleryTheme::IsDefault() const { return pThm->IsDefault(); }
+
+const OUString& GalleryTheme::GetName() const { return pThm->GetThemeName(); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gengal/gengal.cxx b/svx/source/gengal/gengal.cxx
new file mode 100644
index 000000000..95c415d60
--- /dev/null
+++ b/svx/source/gengal/gengal.cxx
@@ -0,0 +1,326 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <stdio.h>
+
+#include <vector>
+
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/bootstrap.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/ucb/UniversalContentBroker.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+
+#include <tools/urlobj.hxx>
+#include <vcl/vclmain.hxx>
+
+#include <osl/file.hxx>
+#include <osl/process.h>
+#include <sfx2/app.hxx>
+#include <sal/types.h>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+
+#include <svx/galtheme.hxx>
+#include <svx/gallery1.hxx>
+
+using namespace ::com::sun::star;
+
+namespace {
+
+class GalApp : public Application
+{
+ bool mbInBuildTree;
+ bool mbRelativeURLs;
+public:
+ GalApp() : mbInBuildTree( false ), mbRelativeURLs( false )
+ {
+ }
+ virtual int Main() override;
+
+protected:
+ uno::Reference<lang::XMultiServiceFactory> xMSF;
+ void Init() override;
+ void DeInit() override;
+};
+
+}
+
+static void createTheme( const OUString& aThemeName, std::u16string_view aGalleryURL,
+ const OUString& aDestDir, std::vector<INetURLObject> &rFiles,
+ bool bRelativeURLs )
+{
+ std::unique_ptr<Gallery> pGallery(new Gallery( aGalleryURL ));
+
+ fprintf( stderr, "Work on gallery '%s'\n",
+ OUStringToOString( aGalleryURL, RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ fprintf( stderr, "Existing themes: %" SAL_PRI_SIZET "u\n",
+ pGallery->GetThemeCount() );
+
+ GalleryTheme *pGalTheme;
+ if( !pGallery->HasTheme( aThemeName) ) {
+ if( !pGallery->CreateTheme( aThemeName ) ) {
+ fprintf( stderr, "Failed to create theme\n" );
+ exit( 1 );
+ }
+ }
+
+ fprintf( stderr, "Existing themes: %" SAL_PRI_SIZET "u\n",
+ pGallery->GetThemeCount() );
+
+ SfxListener aListener;
+
+ pGalTheme = pGallery->AcquireTheme( aThemeName, aListener );
+ if ( !pGalTheme ) {
+ fprintf( stderr, "Failed to acquire theme\n" );
+ exit( 1 );
+ }
+
+ fprintf( stderr, "Using DestDir: %s\n",
+ OUStringToOString( aDestDir, RTL_TEXTENCODING_UTF8 ).getStr() );
+ pGalTheme->SetDestDir( aDestDir, bRelativeURLs );
+
+ for( const auto& rFile : rFiles )
+ {
+// Should/could use:
+// if ( ! pGalTheme->InsertFileOrDirURL( aURL ) ) {
+// Requires a load more components ...
+
+ if ( ! pGalTheme->InsertURL( rFile ) )
+ fprintf( stderr, "Failed to import '%s'\n",
+ OUStringToOString( rFile.GetMainURL(INetURLObject::DecodeMechanism::NONE), RTL_TEXTENCODING_UTF8 ).getStr() );
+ else
+ fprintf( stderr, "Imported file '%s' (%" SAL_PRIuUINT32 ")\n",
+ OUStringToOString( rFile.GetMainURL(INetURLObject::DecodeMechanism::NONE), RTL_TEXTENCODING_UTF8 ).getStr(),
+ pGalTheme->GetObjectCount() );
+ }
+
+ pGallery->ReleaseTheme( pGalTheme, aListener );
+}
+
+static int PrintHelp()
+{
+ fprintf( stdout, "Utility to generate LibreOffice gallery files\n\n" );
+
+ fprintf( stdout, "using: gengal --name <name> --path <dir> [ --destdir <path> ]\n");
+ fprintf( stdout, " [ files ... ]\n\n" );
+
+ fprintf( stdout, "options:\n");
+ fprintf( stdout, " --name <theme>\t\tdefines the user visible name of the created or updated theme.\n");
+
+ fprintf( stdout, " --path <dir>\t\tdefines directory where the gallery files are created\n");
+ fprintf( stdout, "\t\t\tor updated.\n");
+
+ fprintf( stdout, " --destdir <dir>\tdefines a path prefix to be removed from the paths\n");
+ fprintf( stdout, "\t\t\tstored in the gallery files. It is useful to create\n");
+ fprintf( stdout, "\t\t\tRPM packages using the BuildRoot feature.\n");
+
+ fprintf( stdout, " --relative-urls\t\tflags that after removing the destdir, the URL should be a path relative to the gallery folder in the install\n");
+ fprintf( stdout, "\t\t\tprimarily used for internal gallery generation at compile time.\n");
+ fprintf( stdout, "\t\t\ttheme files.\n");
+ fprintf( stdout, " files\t\t\tlists files to be added to the gallery. Absolute paths\n");
+ fprintf( stdout, "\t\t\tare required.\n");
+ // --build-tree not documented - only useful during the build ...
+
+ return EXIT_SUCCESS;
+}
+
+static INetURLObject Smartify( std::u16string_view rPath )
+{
+ INetURLObject aURL;
+ aURL.SetSmartURL( rPath );
+ return aURL;
+}
+
+void GalApp::Init()
+{
+ try {
+ if( !mbInBuildTree && getenv( "OOO_INSTALL_PREFIX" ) == nullptr ) {
+ OUString fileName = GetAppFileName();
+ int lastSlash = fileName.lastIndexOf( '/' );
+#ifdef _WIN32
+ // Don't know which directory separators GetAppFileName() returns on Windows.
+ // Be safe and take into consideration they might be backslashes.
+ if( fileName.lastIndexOf( '\\' ) > lastSlash )
+ lastSlash = fileName.lastIndexOf( '\\' );
+#endif
+ OUString baseBinDir = fileName.copy( 0, lastSlash );
+ OUString installPrefix = baseBinDir + "/../..";
+
+ OUString envVar( "OOO_INSTALL_PREFIX");
+ osl_setEnvironment(envVar.pData, installPrefix.pData);
+ }
+ SAL_INFO("svx", "OOO_INSTALL_PREFIX=" << getenv( "OOO_INSTALL_PREFIX" ) );
+
+ uno::Reference<uno::XComponentContext> xComponentContext
+ = ::cppu::defaultBootstrap_InitialComponentContext();
+ xMSF.set( xComponentContext->getServiceManager(), uno::UNO_QUERY );
+ if( !xMSF.is() )
+ {
+ fprintf( stderr, "Failed to bootstrap\n" );
+ exit( 1 );
+ }
+ ::comphelper::setProcessServiceFactory( xMSF );
+
+ // For backwards compatibility, in case some code still uses plain
+ // createInstance w/o args directly to obtain an instance:
+ css::ucb::UniversalContentBroker::create(xComponentContext);
+ } catch (const uno::Exception &e) {
+ fprintf( stderr, "Bootstrap exception '%s'\n",
+ OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
+ exit( 1 );
+ }
+}
+
+static std::vector<OUString> ReadResponseFile_Impl(OUString const& rInput)
+{
+ osl::File file(rInput);
+ osl::FileBase::RC rc = file.open(osl_File_OpenFlag_Read);
+ OString const uInput(OUStringToOString(rInput, RTL_TEXTENCODING_UTF8));
+ if (osl::FileBase::E_None != rc)
+ {
+ fprintf(stderr, "error while opening response file: %s (%d)\n",
+ uInput.getStr(), rc);
+ exit(1);
+ }
+
+ std::vector<OUString> ret;
+ OUStringBuffer b(256);
+ char buf[1<<16];
+ while (true)
+ {
+ sal_uInt64 size(0);
+ rc = file.read(buf, sizeof(buf), size);
+ if (osl::FileBase::E_None != rc)
+ {
+ fprintf(stderr, "error while reading response file: %s (%d)\n",
+ uInput.getStr(), rc);
+ exit(1);
+ }
+ if (!size)
+ break;
+ for (sal_uInt64 i = 0; i < size; ++i)
+ {
+ if (static_cast<unsigned char>(buf[i]) >= 128)
+ {
+ fprintf(stderr, "non-ASCII character in response file: %s\n",
+ uInput.getStr());
+ exit(1);
+ }
+ switch (buf[i])
+ {
+ case ' ' :
+ case '\t':
+ case '\r':
+ case '\n':
+ if (!b.isEmpty())
+ ret.push_back(b.makeStringAndClear());
+ break;
+ default:
+ b.append(buf[i]);
+ break;
+ }
+ }
+ }
+ if (!b.isEmpty())
+ ret.push_back(b.makeStringAndClear());
+ return ret;
+}
+
+static void
+ReadResponseFile(std::vector<INetURLObject> & rFiles, OUString const& rInput)
+{
+ std::vector<OUString> files(ReadResponseFile_Impl(rInput));
+ for (size_t i = 0; i < files.size(); ++i)
+ {
+ rFiles.push_back(Smartify(files[i]));
+ }
+}
+
+int GalApp::Main()
+{
+ try
+ {
+ SfxApplication::GetOrCreate();
+
+ OUString aPath, aDestDir;
+ OUString aName( "Default name" );
+ std::vector<INetURLObject> aFiles;
+
+ for( sal_uInt16 i = 0; i < GetCommandLineParamCount(); ++i )
+ {
+ OUString aParam = GetCommandLineParam( i );
+
+ if ( aParam.startsWith( "-env:" ) )
+ continue;
+ else if ( aParam == "--help" || aParam == "-h" )
+ return PrintHelp();
+ else if ( aParam == "--build-tree" )
+ {
+ mbRelativeURLs = true;
+ mbInBuildTree = true;
+ }
+ else if ( aParam == "--name" )
+ aName = GetCommandLineParam( ++i );
+ else if ( aParam == "--path" )
+ aPath = Smartify( GetCommandLineParam( ++i ) ).
+ GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ else if ( aParam == "--destdir" )
+ aDestDir = GetCommandLineParam( ++i );
+ else if ( aParam == "--relative-urls" )
+ mbRelativeURLs = true;
+ else if ( aParam == "--number-from" )
+ fprintf ( stderr, "--number-from is deprecated, themes now "
+ "have filenames based on their names\n" );
+ else if ( aParam == "--filenames" )
+ ReadResponseFile(aFiles, GetCommandLineParam(++i));
+ else
+ aFiles.push_back( Smartify( aParam ) );
+ }
+
+ if( aFiles.empty() )
+ return PrintHelp();
+
+ createTheme( aName, aPath, aDestDir, aFiles, mbRelativeURLs );
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "Fatal");
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception &e)
+ {
+ SAL_WARN("svx", "Fatal: " << e.what());
+ return 1;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+void GalApp::DeInit()
+{
+ auto xDesktop = css::frame::Desktop::create(comphelper::getProcessComponentContext());
+ xDesktop->terminate();
+ uno::Reference< lang::XComponent >(
+ comphelper::getProcessComponentContext(),
+ uno::UNO_QUERY_THROW )-> dispose();
+ ::comphelper::setProcessServiceFactory( nullptr );
+}
+
+void vclmain::createApplication()
+{
+ Application::EnableConsoleOnly();
+ static GalApp aGalApp;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/gengal/gengal.sh b/svx/source/gengal/gengal.sh
new file mode 100755
index 000000000..245c171c3
--- /dev/null
+++ b/svx/source/gengal/gengal.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+# enable file locking
+SAL_ENABLE_FILE_LOCKING=1
+export SAL_ENABLE_FILE_LOCKING
+
+# resolve installation directory
+sd_cwd=$(pwd)
+sd_res=$0
+while [ -h "$sd_res" ] ; do
+ cd "$(dirname "$sd_res")"
+ sd_basename=$(basename "$sd_res")
+ sd_res=$(ls -l "$sd_basename" | sed "s/.*$sd_basename -> //g")
+done
+cd "$(dirname "$sd_res")"
+sd_prog=$(pwd)
+cd "$sd_cwd"
+
+# this is a temporary hack until we can live with the default search paths
+case "$(uname -s)" in
+OpenBSD)
+ LD_LIBRARY_PATH=$sd_prog${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
+ JAVA_HOME=$(javaPathHelper -h libreoffice-java 2> /dev/null)
+ export LD_LIBRARY_PATH
+ if [ -n "${JAVA_HOME}" ]; then
+ export JAVA_HOME
+ fi
+ ;;
+NetBSD|FreeBSD|DragonFly)
+ LD_LIBRARY_PATH=$sd_prog${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
+ export LD_LIBRARY_PATH
+ ;;
+AIX)
+ LIBPATH=$sd_prog${LIBPATH:+:${LIBPATH}}
+ export LIBPATH
+ ;;
+esac
+
+#collect all bootstrap variables specified on the command line
+#so that they can be passed as arguments to javaldx later on
+for arg in "$@"
+do
+ case "$arg" in
+ -env:*) BOOTSTRAPVARS=$BOOTSTRAPVARS" ""$arg";;
+ esac
+done
+
+# extend the ld_library_path for java: javaldx checks the sofficerc for us
+if [ -x "$sd_prog/javaldx" ] ; then
+ my_path=$("$sd_prog/javaldx" $BOOTSTRAPVARS \
+ "-env:INIFILENAME=vnd.sun.star.pathname:$sd_prog/redirectrc")
+ if [ -n "$my_path" ] ; then
+ sd_platform=$(uname -s)
+ case $sd_platform in
+ AIX)
+ LIBPATH=$my_path${LIBPATH:+:$LIBPATH}
+ export LIBPATH
+ ;;
+ *)
+ LD_LIBRARY_PATH=$my_path${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
+ export LD_LIBRARY_PATH
+ ;;
+ esac
+ fi
+fi
+
+unset XENVIRONMENT
+
+# uncomment line below to disable anti aliasing of fonts
+# SAL_ANTIALIAS_DISABLE=true; export SAL_ANTIALIAS_DISABLE
+
+# uncomment line below if you encounter problems starting soffice on your system
+# SAL_NO_XINITTHREADS=true; export SAL_NO_XINITTHREADS
+
+# execute binary
+exec "$sd_prog/gengal.bin" "$@" \
+ "-env:INIFILENAME=vnd.sun.star.pathname:$sd_prog/redirectrc"
+
diff --git a/svx/source/inc/AccessibleFrameSelector.hxx b/svx/source/inc/AccessibleFrameSelector.hxx
new file mode 100644
index 000000000..26f30aa67
--- /dev/null
+++ b/svx/source/inc/AccessibleFrameSelector.hxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_ACCESSIBLEFRAMESELECTOR_HXX
+#define INCLUDED_SVX_SOURCE_INC_ACCESSIBLEFRAMESELECTOR_HXX
+
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <cppuhelper/implbase1.hxx>
+#include<comphelper/accessiblecomponenthelper.hxx>
+#include <svx/framebordertype.hxx>
+
+namespace svx {
+
+class FrameSelector;
+
+namespace a11y {
+
+typedef ::cppu::ImplHelper1<css::accessibility::XAccessible> OAccessibleHelper_Base;
+
+class AccFrameSelector final : public ::comphelper::OAccessibleComponentHelper,
+ public OAccessibleHelper_Base
+{
+public:
+ explicit AccFrameSelector(FrameSelector& rFrameSel);
+ virtual ~AccFrameSelector() override;
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ //XAccessibleComponent
+ virtual void SAL_CALL grabFocus( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+
+ //XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) override;
+
+ //XAccessible
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ void Invalidate();
+
+private:
+ // OCommonAccessibleComponent
+ /// implements the calculation of the bounding rectangle
+ virtual css::awt::Rectangle implGetBounds( ) override;
+
+ /// @throws css::uno::RuntimeException
+ void IsValid();
+
+ FrameSelector* mpFrameSel;
+};
+
+class AccFrameSelectorChild final : public ::comphelper::OAccessibleComponentHelper,
+ public OAccessibleHelper_Base
+{
+public:
+ explicit AccFrameSelectorChild( FrameSelector& rFrameSel, FrameBorderType eBorder );
+
+ virtual ~AccFrameSelectorChild() override;
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ //XAccessibleComponent
+ virtual void SAL_CALL grabFocus( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+
+ //XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) override;
+
+ //XAccessible
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ void NotifyAccessibleEvent(const sal_Int16 _nEventId, const css::uno::Any& _rOldValue, const css::uno::Any& _rNewValue)
+ {
+ ::comphelper::OAccessibleComponentHelper::NotifyAccessibleEvent(_nEventId, _rOldValue, _rNewValue);
+ }
+
+ void Invalidate();
+
+private:
+ // OCommonAccessibleComponent
+ /// implements the calculation of the bounding rectangle
+ virtual css::awt::Rectangle implGetBounds( ) override;
+
+ /// @throws css::uno::RuntimeException
+ void IsValid();
+
+ FrameSelector* mpFrameSel;
+
+ FrameBorderType meBorder;
+};
+
+
+}
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/DefaultShapesPanel.hxx b/svx/source/inc/DefaultShapesPanel.hxx
new file mode 100644
index 000000000..71396c5ce
--- /dev/null
+++ b/svx/source/inc/DefaultShapesPanel.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_DEFAULTSHAPESPANEL_HXX
+#define INCLUDED_SVX_SOURCE_INC_DEFAULTSHAPESPANEL_HXX
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <svtools/valueset.hxx>
+#include <map>
+#include "ShapesUtil.hxx"
+
+using namespace css;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+
+namespace svx::sidebar {
+
+/** This panel provides buttons for inserting shapes into a document.
+*/
+class DefaultShapesPanel final
+ : public PanelLayout, public SvxShapeCommandsMap
+{
+public:
+ DefaultShapesPanel (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame);
+ static std::unique_ptr<PanelLayout> Create(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame);
+ virtual ~DefaultShapesPanel() override;
+
+private:
+ std::unique_ptr<ValueSet> mxLineArrowSet;
+ std::unique_ptr<weld::CustomWeld> mxLineArrowSetWin;
+ std::unique_ptr<ValueSet> mxCurveSet;
+ std::unique_ptr<weld::CustomWeld> mxCurveSetWin;
+ std::unique_ptr<ValueSet> mxConnectorSet;
+ std::unique_ptr<weld::CustomWeld> mxConnectorSetWin;
+ std::unique_ptr<ValueSet> mxBasicShapeSet;
+ std::unique_ptr<weld::CustomWeld> mxBasicShapeSetWin;
+ std::unique_ptr<ValueSet> mxSymbolShapeSet;
+ std::unique_ptr<weld::CustomWeld> mxSymbolShapeSetWin;
+ std::unique_ptr<ValueSet> mxBlockArrowSet;
+ std::unique_ptr<weld::CustomWeld> mxBlockArrowSetWin;
+ std::unique_ptr<ValueSet> mxFlowchartSet;
+ std::unique_ptr<weld::CustomWeld> mxFlowchartSetWin;
+ std::unique_ptr<ValueSet> mxCalloutSet;
+ std::unique_ptr<weld::CustomWeld> mxCalloutSetWin;
+ std::unique_ptr<ValueSet> mxStarSet;
+ std::unique_ptr<weld::CustomWeld> mxStarSetWin;
+ std::unique_ptr<ValueSet> mx3DObjectSet;
+ std::unique_ptr<weld::CustomWeld> mx3DObjectSetWin;
+
+ Reference< XFrame > mxFrame;
+ std::map<ValueSet*, std::map<sal_uInt16, OUString>> mpShapesSetMap;
+
+ void populateShapes();
+ void Initialize();
+ DECL_LINK( ShapeSelectHdl, ValueSet*, void );
+};
+
+} // end of namespace sd::sidebar
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/GraphCtlAccessibleContext.hxx b/svx/source/inc/GraphCtlAccessibleContext.hxx
new file mode 100644
index 000000000..5e77d3a11
--- /dev/null
+++ b/svx/source/inc/GraphCtlAccessibleContext.hxx
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#ifndef INCLUDED_SVX_SOURCE_INC_GRAPHCTLACCESSIBLECONTEXT_HXX
+#define INCLUDED_SVX_SOURCE_INC_GRAPHCTLACCESSIBLECONTEXT_HXX
+
+#include <cppuhelper/compbase7.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <svl/lstner.hxx>
+
+#include <map>
+
+#include <svx/AccessibleShapeTreeInfo.hxx>
+#include <svx/IAccessibleViewForwarder.hxx>
+#include <svx/AccessibleShape.hxx>
+
+namespace com::sun::star::awt {
+ struct Point;
+ struct Rectangle;
+ struct Size;
+ class XFocusListener;
+}
+namespace tools { class Rectangle; }
+class GraphCtrl;
+class SdrObject;
+class SdrModel;
+class SdrPage;
+class SdrView;
+
+/** @descr
+ This base class provides an implementation of the
+ <code>AccessibleContext</code> service.
+*/
+
+typedef ::cppu::WeakAggComponentImplHelper7<
+ css::accessibility::XAccessible,
+ css::accessibility::XAccessibleComponent,
+ css::accessibility::XAccessibleContext,
+ css::accessibility::XAccessibleEventBroadcaster,
+ css::accessibility::XAccessibleSelection,
+ css::lang::XServiceInfo,
+ css::lang::XServiceName >
+ SvxGraphCtrlAccessibleContext_Base;
+
+class SvxGraphCtrlAccessibleContext final :
+ private cppu::BaseMutex, public SvxGraphCtrlAccessibleContext_Base,
+ public SfxListener, public ::accessibility::IAccessibleViewForwarder
+{
+public:
+ friend class GraphCtrl;
+
+ // internal
+ SvxGraphCtrlAccessibleContext(GraphCtrl& rRepresentation);
+
+ void Notify( SfxBroadcaster& aBC, const SfxHint& aHint ) override;
+
+ // XAccessible
+ /// Return the XAccessibleContext.
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext> SAL_CALL
+ getAccessibleContext() override;
+
+ // XAccessibleComponent
+ virtual sal_Bool SAL_CALL containsPoint( const css::awt::Point& rPoint ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& rPoint ) override;
+ virtual css::awt::Rectangle SAL_CALL getBounds() override;
+ virtual css::awt::Point SAL_CALL getLocation() override;
+ virtual css::awt::Point SAL_CALL getLocationOnScreen() override;
+ virtual css::awt::Size SAL_CALL getSize() override;
+ virtual void SAL_CALL grabFocus() override;
+
+ virtual sal_Int32 SAL_CALL getForeground() override;
+
+ virtual sal_Int32 SAL_CALL getBackground() override;
+
+ // XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL getAccessibleChild (sal_Int32 nIndex) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL getAccessibleParent() override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole() override;
+ virtual OUString SAL_CALL getAccessibleDescription() override;
+ virtual OUString SAL_CALL getAccessibleName() override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet> SAL_CALL getAccessibleRelationSet() override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet> SAL_CALL getAccessibleStateSet() override;
+ virtual css::lang::Locale SAL_CALL getLocale() override;
+
+ // XAccessibleEventBroadcaster
+ virtual void SAL_CALL addAccessibleEventListener( const css::uno::Reference< css::accessibility::XAccessibleEventListener>& xListener) override;
+ virtual void SAL_CALL removeAccessibleEventListener( const css::uno::Reference< css::accessibility::XAccessibleEventListener>& xListener) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService (const OUString& sServiceName) override;
+ virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ // XServiceName
+ virtual OUString SAL_CALL getServiceName() override;
+
+ // XAccessibleSelection
+ virtual void SAL_CALL selectAccessibleChild( sal_Int32 nChildIndex ) override;
+ virtual sal_Bool SAL_CALL isAccessibleChildSelected( sal_Int32 nChildIndex ) override;
+ virtual void SAL_CALL clearAccessibleSelection() override;
+ virtual void SAL_CALL selectAllAccessibleChildren() override;
+ virtual sal_Int32 SAL_CALL getSelectedAccessibleChildCount() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) override;
+ virtual void SAL_CALL deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) override;
+
+ // IAccessibleViewforwarder
+ virtual tools::Rectangle GetVisibleArea() const override;
+ virtual Point LogicToPixel (const Point& rPoint) const override;
+ virtual Size LogicToPixel (const Size& rSize) const override;
+
+ /** This method is used by the graph control to tell the
+ accessibility object about a new model and view.
+ */
+ void setModelAndView (SdrModel* pModel, SdrView* pView);
+
+private:
+ virtual ~SvxGraphCtrlAccessibleContext() override;
+ /// @throws css::lang::IndexOutOfBoundsException
+ void checkChildIndexOnSelection( tools::Long nIndexOfChild );
+
+ virtual void SAL_CALL disposing() final override;
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::lang::IndexOutOfBoundsException
+ SdrObject* getSdrObject( sal_Int32 nIndex );
+
+ void CommitChange (sal_Int16 aEventId, const css::uno::Any& rNewValue, const css::uno::Any& rOldValue);
+
+ css::uno::Reference< css::accessibility::XAccessible > getAccessible( const SdrObject* pObj );
+
+ ::accessibility::AccessibleShapeTreeInfo maTreeInfo;
+
+ /** Description of this object. This is not a constant because it can
+ be set from the outside.
+ */
+ OUString msDescription;
+
+ /** Name of this object.
+ */
+ OUString msName;
+
+ /// map of accessible shapes
+ typedef ::std::map< const SdrObject*, rtl::Reference<::accessibility::AccessibleShape> > ShapesMapType;
+ ShapesMapType mxShapes;
+
+ GraphCtrl* mpControl;
+
+ SdrModel* mpModel;
+ SdrPage* mpPage;
+ SdrView* mpView;
+
+ /// client id in the AccessibleEventNotifier queue
+ sal_uInt32 mnClientId;
+
+ bool mbDisposed;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/ShapesUtil.hxx b/svx/source/inc/ShapesUtil.hxx
new file mode 100644
index 000000000..72d6e63dc
--- /dev/null
+++ b/svx/source/inc/ShapesUtil.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_SHAPESUTIL_HXX
+#define INCLUDED_SVX_SOURCE_INC_SHAPESUTIL_HXX
+#include <map>
+#include <rtl/ustring.hxx>
+
+namespace svx::sidebar {
+
+class SvxShapeCommandsMap
+{
+public:
+ SvxShapeCommandsMap();
+ std::map<sal_uInt16, OUString> mpLineShapes, mpCurveShapes,
+ mpConnectorShapes, mpBasicShapes, mpSymbolShapes,
+ mpBlockArrowShapes, mpFlowchartShapes,
+ mpCalloutShapes, mpStarShapes, mp3DShapes;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ \ No newline at end of file
diff --git a/svx/source/inc/StylesPreviewToolBoxControl.hxx b/svx/source/inc/StylesPreviewToolBoxControl.hxx
new file mode 100644
index 000000000..d8d12a0f2
--- /dev/null
+++ b/svx/source/inc/StylesPreviewToolBoxControl.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_STYLES_PREVIEW_TOOLBOX_CONTROL_HXX
+#define INCLUDED_SVX_SOURCE_INC_STYLES_PREVIEW_TOOLBOX_CONTROL_HXX
+
+#include <svtools/toolboxcontroller.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include "StylesPreviewWindow.hxx"
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+
+class StylesPreviewToolBoxControl final
+ : public cppu::ImplInheritanceHelper<svt::ToolboxController, css::lang::XServiceInfo>
+{
+ VclPtr<StylesPreviewWindow_Impl> m_xVclBox;
+ std::unique_ptr<StylesPreviewWindow_Base> m_xWeldBox;
+
+ css::uno::Reference<css::frame::XDispatchProvider> m_xDispatchProvider;
+
+ std::vector<std::pair<OUString, OUString>> m_aDefaultStyles;
+
+public:
+ StylesPreviewToolBoxControl();
+ virtual ~StylesPreviewToolBoxControl() override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& rEvent) override;
+
+ // XToolbarController
+ virtual css::uno::Reference<css::awt::XWindow>
+ SAL_CALL createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& aArguments) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XUpdatable
+ virtual void SAL_CALL update() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+private:
+ void InitializeStyles(const css::uno::Reference<css::frame::XModel>& xModel);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/inc/StylesPreviewWindow.hxx b/svx/source/inc/StylesPreviewWindow.hxx
new file mode 100644
index 000000000..3b652dcfb
--- /dev/null
+++ b/svx/source/inc/StylesPreviewWindow.hxx
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_STYLES_PREVIEW_WINDOW_HXX
+#define INCLUDED_SVX_SOURCE_INC_STYLES_PREVIEW_WINDOW_HXX
+
+#include <vcl/InterimItemWindow.hxx>
+#include <svl/style.hxx>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <sfx2/sfxstatuslistener.hxx>
+
+class StylesPreviewWindow_Base;
+
+/// Listener for style selection
+class StyleStatusListener final : public SfxStatusListener
+{
+ StylesPreviewWindow_Base* m_pPreviewControl;
+
+public:
+ StyleStatusListener(
+ StylesPreviewWindow_Base* pPreviewControl,
+ const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider);
+
+ void StateChangedAtStatusListener(SfxItemState eState, const SfxPoolItem* pState) override;
+};
+
+/// Listener for styles creation or modification
+class StylePoolChangeListener final : public SfxListener
+{
+ StylesPreviewWindow_Base* m_pPreviewControl;
+ SfxStyleSheetBasePool* m_pStyleSheetPool;
+
+public:
+ StylePoolChangeListener(StylesPreviewWindow_Base* pPreviewControl);
+ ~StylePoolChangeListener();
+
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+};
+
+class StyleItemController
+{
+ static constexpr unsigned LEFT_MARGIN = 8;
+
+ SfxStyleFamily m_eStyleFamily;
+ std::pair<OUString, OUString> m_aStyleName;
+
+public:
+ StyleItemController(const std::pair<OUString, OUString>& aStyleName);
+
+ void Paint(vcl::RenderContext& rRenderContext);
+
+private:
+ void DrawEntry(vcl::RenderContext& rRenderContext);
+ void DrawText(vcl::RenderContext& rRenderContext);
+ void DrawHighlight(vcl::RenderContext& rRenderContext, Color aFontBack);
+ static void DrawContentBackground(vcl::RenderContext& rRenderContext,
+ const tools::Rectangle& aContentRect, const Color& aColor);
+};
+
+class StylesListUpdateTask : public Idle
+{
+ StylesPreviewWindow_Base& m_rStylesList;
+
+public:
+ StylesListUpdateTask(StylesPreviewWindow_Base& rStylesList)
+ : Idle("StylesListUpdateTask")
+ , m_rStylesList(rStylesList)
+ {
+ SetPriority(TaskPriority::HIGH_IDLE);
+ }
+
+ virtual void Invoke() override;
+};
+
+class StylesPreviewWindow_Base
+{
+ friend class StylesListUpdateTask;
+
+protected:
+ static constexpr unsigned STYLES_COUNT = 6;
+
+ css::uno::Reference<css::frame::XDispatchProvider> m_xDispatchProvider;
+
+ std::unique_ptr<weld::IconView> m_xStylesView;
+
+ StylesListUpdateTask m_aUpdateTask;
+
+ rtl::Reference<StyleStatusListener> m_xStatusListener;
+ std::unique_ptr<StylePoolChangeListener> m_pStylePoolChangeListener;
+
+ std::vector<std::pair<OUString, OUString>> m_aDefaultStyles;
+ std::vector<std::pair<OUString, OUString>> m_aAllStyles;
+
+ OUString m_sSelectedStyle;
+
+ DECL_LINK(Selected, weld::IconView&, void);
+ DECL_LINK(DoubleClick, weld::IconView&, bool);
+ DECL_LINK(DoCommand, const CommandEvent&, bool);
+
+public:
+ StylesPreviewWindow_Base(
+ weld::Builder& xBuilder, std::vector<std::pair<OUString, OUString>>&& aDefaultStyles,
+ const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider);
+ ~StylesPreviewWindow_Base();
+
+ void Select(const OUString& rStyleName);
+ void RequestStylesListUpdate();
+
+private:
+ void UpdateStylesList();
+ void UpdateSelection();
+ bool Command(const CommandEvent& rEvent);
+};
+
+class StylesPreviewWindow_Impl final : public InterimItemWindow, public StylesPreviewWindow_Base
+{
+public:
+ StylesPreviewWindow_Impl(
+ vcl::Window* pParent, std::vector<std::pair<OUString, OUString>>&& aDefaultStyles,
+ const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider);
+ ~StylesPreviewWindow_Impl();
+
+ void dispose();
+
+ void SetOptimalSize();
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/inc/cell.hxx b/svx/source/inc/cell.hxx
new file mode 100644
index 000000000..36ce254d1
--- /dev/null
+++ b/svx/source/inc/cell.hxx
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_CELL_HXX
+#define INCLUDED_SVX_SOURCE_INC_CELL_HXX
+
+#include <config_options.h>
+#include <com/sun/star/table/XMergeableCell.hpp>
+#include <com/sun/star/awt/XLayoutConstrains.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+
+#include <rtl/ref.hxx>
+#include <svl/style.hxx>
+#include <svx/sdtaitm.hxx>
+#include "tablemodel.hxx"
+#include <editeng/unotext.hxx>
+#include <svx/svdtext.hxx>
+
+
+class SfxItemSet;
+class OutlinerParaObject;
+class SdrObject;
+namespace sdr::properties { class TextProperties; }
+
+
+namespace sdr::table {
+
+
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) Cell final : public SdrText,
+ public SvxUnoTextBase,
+ public css::table::XMergeableCell,
+ public css::awt::XLayoutConstrains,
+ public css::lang::XEventListener,
+ public ::cppu::OWeakObject
+{
+ friend class CellUndo;
+
+public:
+ SVX_DLLPRIVATE static rtl::Reference< Cell > create( SdrTableObj& rTableObj );
+
+ // private
+ SVX_DLLPRIVATE void dispose();
+
+ // SdrTextShape proxy
+ bool IsActiveCell() const;
+ bool IsTextEditActive() const;
+ SVX_DLLPRIVATE bool hasText() const;
+
+ SVX_DLLPRIVATE void cloneFrom( const CellRef& rCell );
+
+ SVX_DLLPRIVATE void setCellRect( ::tools::Rectangle const & rCellRect ) { maCellRect = rCellRect; }
+ SVX_DLLPRIVATE const ::tools::Rectangle& getCellRect() const { return maCellRect; }
+ SVX_DLLPRIVATE ::tools::Rectangle& getCellRect() { return maCellRect; }
+
+ bool CanCreateEditOutlinerParaObject() const;
+ std::optional<OutlinerParaObject> CreateEditOutlinerParaObject() const;
+ SVX_DLLPRIVATE void SetStyleSheet( SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr );
+ SVX_DLLPRIVATE virtual SfxStyleSheet* GetStyleSheet() const override;
+ SVX_DLLPRIVATE void TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const;
+
+ SVX_DLLPRIVATE void SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems);
+ void SetMergedItem(const SfxPoolItem& rItem);
+
+ SVX_DLLPRIVATE sal_Int32 calcPreferredWidth( const Size aSize );
+ SVX_DLLPRIVATE sal_Int32 getMinimumWidth() const;
+ SVX_DLLPRIVATE sal_Int32 getMinimumHeight();
+
+ SVX_DLLPRIVATE tools::Long GetTextLeftDistance() const;
+ SVX_DLLPRIVATE tools::Long GetTextRightDistance() const;
+ SVX_DLLPRIVATE tools::Long GetTextUpperDistance() const;
+ SVX_DLLPRIVATE tools::Long GetTextLowerDistance() const;
+
+ SVX_DLLPRIVATE SdrTextVertAdjust GetTextVerticalAdjust() const;
+ SdrTextHorzAdjust GetTextHorizontalAdjust() const;
+
+ SVX_DLLPRIVATE void merge( sal_Int32 nColumnSpan, sal_Int32 nRowSpan );
+ SVX_DLLPRIVATE void mergeContent( const CellRef& xSourceCell );
+ SVX_DLLPRIVATE void replaceContentAndFormatting( const CellRef& xSourceCell );
+
+ SVX_DLLPRIVATE void setMerged();
+
+ SVX_DLLPRIVATE void copyFormatFrom( const CellRef& xSourceCell );
+
+ // XInterface
+ SVX_DLLPRIVATE virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& Type ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ SVX_DLLPRIVATE virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ SVX_DLLPRIVATE virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // XLayoutConstrains
+ SVX_DLLPRIVATE virtual css::awt::Size SAL_CALL getMinimumSize() override;
+ SVX_DLLPRIVATE virtual css::awt::Size SAL_CALL getPreferredSize() override;
+ SVX_DLLPRIVATE virtual css::awt::Size SAL_CALL calcAdjustedSize( const css::awt::Size& aNewSize ) override;
+
+ // XMergeableCell
+ SVX_DLLPRIVATE virtual ::sal_Int32 SAL_CALL getRowSpan() override;
+ SVX_DLLPRIVATE virtual ::sal_Int32 SAL_CALL getColumnSpan() override;
+ virtual sal_Bool SAL_CALL isMerged() override;
+
+ // XCell
+ SVX_DLLPRIVATE virtual OUString SAL_CALL getFormula() override;
+ SVX_DLLPRIVATE virtual void SAL_CALL setFormula( const OUString& aFormula ) override;
+ SVX_DLLPRIVATE virtual double SAL_CALL getValue() override;
+ SVX_DLLPRIVATE virtual void SAL_CALL setValue( double nValue ) override;
+ SVX_DLLPRIVATE virtual css::table::CellContentType SAL_CALL getType() override;
+ SVX_DLLPRIVATE virtual sal_Int32 SAL_CALL getError() override;
+
+ // css::beans::XPropertySet
+ SVX_DLLPRIVATE virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ SVX_DLLPRIVATE virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ SVX_DLLPRIVATE virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // XMultiPropertySet
+ SVX_DLLPRIVATE virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override;
+ SVX_DLLPRIVATE virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+
+ // css::beans::XPropertyState
+ SVX_DLLPRIVATE virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override;
+ SVX_DLLPRIVATE virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( const css::uno::Sequence< OUString >& aPropertyName ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override;
+ SVX_DLLPRIVATE virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override;
+
+ // XMultiPropertyStates
+ SVX_DLLPRIVATE virtual void SAL_CALL setAllPropertiesToDefault() override;
+ SVX_DLLPRIVATE virtual void SAL_CALL setPropertiesToDefault( const css::uno::Sequence< OUString >& aPropertyNames ) override;
+ SVX_DLLPRIVATE virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyDefaults( const css::uno::Sequence< OUString >& aPropertyNames ) override;
+
+ // XText
+ SVX_DLLPRIVATE virtual void SAL_CALL insertTextContent( const css::uno::Reference< css::text::XTextRange >& xRange, const css::uno::Reference< css::text::XTextContent >& xContent, sal_Bool bAbsorb ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL removeTextContent( const css::uno::Reference< css::text::XTextContent >& xContent ) override;
+
+ // XSimpleText
+ SVX_DLLPRIVATE virtual void SAL_CALL insertString( const css::uno::Reference< css::text::XTextRange >& xRange, const OUString& aString, sal_Bool bAbsorb ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL insertControlCharacter( const css::uno::Reference< css::text::XTextRange >& xRange, ::sal_Int16 nControlCharacter, sal_Bool bAbsorb ) override;
+
+ // XTextRange
+ SVX_DLLPRIVATE virtual OUString SAL_CALL getString( ) override;
+ SVX_DLLPRIVATE virtual void SAL_CALL setString( const OUString& aString ) override;
+
+ // XEventListener
+ SVX_DLLPRIVATE virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ SVX_DLLPRIVATE virtual void SetOutlinerParaObject( std::optional<OutlinerParaObject> pTextObject ) override;
+
+ SVX_DLLPRIVATE void AddUndo();
+
+ using SvxUnoTextRangeBase::setPropertyValue;
+ using SvxUnoTextRangeBase::getPropertyValue;
+
+ SVX_DLLPRIVATE sdr::properties::TextProperties* CloneProperties( SdrObject& rNewObj, Cell& rNewCell );
+
+ SVX_DLLPRIVATE static sdr::properties::TextProperties* CloneProperties( sdr::properties::TextProperties const * pProperties, SdrObject& rNewObj, Cell& rNewCell );
+
+ SVX_DLLPRIVATE void notifyModified();
+
+ void dumpAsXml(xmlTextWriterPtr pWriter, sal_Int32 nRow, sal_Int32 nCol) const;
+
+private:
+ SVX_DLLPRIVATE virtual const SfxItemSet& GetObjectItemSet() override;
+ SVX_DLLPRIVATE void SetObjectItem(const SfxPoolItem& rItem);
+
+ SVX_DLLPRIVATE static css::uno::Any GetAnyForItem( SfxItemSet const & aSet, const SfxItemPropertyMapEntry* pMap );
+
+ /// @throws css::uno::RuntimeException
+ SVX_DLLPRIVATE Cell( SdrTableObj& rTableObj );
+ SVX_DLLPRIVATE virtual ~Cell() COVERITY_NOEXCEPT_FALSE override;
+
+ Cell(Cell const &) = delete;
+ void operator =(Cell const &) = delete;
+
+ const SvxItemPropertySet* mpPropSet;
+
+ std::unique_ptr<sdr::properties::TextProperties> mpProperties;
+
+ css::table::CellContentType mnCellContentType;
+
+ OUString msFormula;
+ double mfValue;
+ ::sal_Int32 mnError;
+ bool mbMerged;
+ ::sal_Int32 mnRowSpan;
+ ::sal_Int32 mnColSpan;
+
+ tools::Rectangle maCellRect;
+
+ css::uno::Reference< css::table::XTable > mxTable;
+};
+
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/celltypes.hxx b/svx/source/inc/celltypes.hxx
new file mode 100644
index 000000000..39edf2c5a
--- /dev/null
+++ b/svx/source/inc/celltypes.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_CELLTYPES_HXX
+#define INCLUDED_SVX_SOURCE_INC_CELLTYPES_HXX
+
+#include <rtl/ref.hxx>
+#include <vector>
+
+namespace sdr::table
+{
+class Cell;
+class TableModel;
+class TableRow;
+class TableColumn;
+class TableRows;
+class TableColumns;
+typedef rtl::Reference<Cell> CellRef;
+typedef rtl::Reference<TableModel> TableModelRef;
+typedef rtl::Reference<TableRow> TableRowRef;
+typedef rtl::Reference<TableColumn> TableColumnRef;
+typedef std::vector<CellRef> CellVector;
+typedef std::vector<TableRowRef> RowVector;
+typedef std::vector<TableColumnRef> ColumnVector;
+
+class TableDesignUser
+{
+public:
+ virtual bool isInUse() = 0;
+
+protected:
+ ~TableDesignUser() {}
+};
+
+template <typename T> class RangeIterator
+{
+public:
+ /** creates an iterator from rStart (including) to rEnd (excluding) if
+ bForward is true or from nEnd (excluding to nStart (including).
+ rStart must be <= rEnd.
+ */
+ RangeIterator(const T& rStart, const T& rEnd, bool bForward)
+ {
+ if (bForward)
+ {
+ maIter = rStart;
+ maEnd = rEnd;
+ }
+ else
+ {
+ maIter = rEnd - 1;
+ maEnd = rStart - 1;
+ }
+ }
+
+ /* iterates in the configured direction and returns true if rValue
+ now contains a valid position in the range of this iterator */
+ bool next(T& rValue)
+ {
+ if (maIter == maEnd)
+ return false;
+
+ rValue = maIter;
+ if (maIter < maEnd)
+ ++maIter;
+ else
+ --maIter;
+ return true;
+ }
+
+private:
+ T maEnd;
+ T maIter;
+};
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/charmapacc.hxx b/svx/source/inc/charmapacc.hxx
new file mode 100644
index 000000000..193314ba4
--- /dev/null
+++ b/svx/source/inc/charmapacc.hxx
@@ -0,0 +1,222 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_CHARMAPACC_HXX
+#define INCLUDED_SVX_SOURCE_INC_CHARMAPACC_HXX
+
+#include <comphelper/accessibleselectionhelper.hxx>
+#include <com/sun/star/accessibility/XAccessibleAction.hpp>
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+#include <tools/gen.hxx>
+#include <rtl/ref.hxx>
+
+#include <vector>
+class SvxShowCharSet;
+
+namespace svx
+{
+ typedef ::cppu::ImplHelper1 < css::accessibility::XAccessible
+ > OAccessibleHelper_Base_2;
+
+ class SvxShowCharSetAcc;
+
+ class SvxShowCharSetItemAcc;
+
+ // - SvxShowCharSetItem -
+
+ /** Simple struct to hold some information about the single items of the table.
+ */
+ struct SvxShowCharSetItem
+ {
+ SvxShowCharSet& mrParent;
+ sal_uInt16 mnId;
+ OUString maText;
+ tools::Rectangle maRect;
+ rtl::Reference<SvxShowCharSetItemAcc> m_xItem;
+ SvxShowCharSetAcc* m_pParent;
+
+ SvxShowCharSetItem( SvxShowCharSet& rParent, SvxShowCharSetAcc* _pParent, sal_uInt16 _nPos );
+ ~SvxShowCharSetItem();
+
+ css::uno::Reference< css::accessibility::XAccessible > GetAccessible();
+ };
+
+
+ typedef ::cppu::ImplHelper2 < css::accessibility::XAccessible,
+ css::accessibility::XAccessibleTable
+ > OAccessibleHelper_Base;
+
+ // - SvxShowCharSetAcc -
+
+ /** The table implementation of the vcl control.
+ */
+
+ class SvxShowCharSetAcc final : public ::comphelper::OAccessibleSelectionHelper,
+ public OAccessibleHelper_Base
+ {
+ ::std::vector< css::uno::Reference< css::accessibility::XAccessible > > m_aChildren;
+ SvxShowCharSet* m_pParent; // the vcl control
+ virtual void SAL_CALL disposing() override;
+ public:
+ SvxShowCharSetAcc(SvxShowCharSet* pParent);
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ // XAccessibleComponent
+ virtual void SAL_CALL grabFocus( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+
+ //OAccessibleContextHelper
+ // XAccessibleContext - still waiting to be overwritten
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override { return this; }
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ // XAccessibleTable
+ virtual sal_Int32 SAL_CALL getAccessibleRowCount( ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumnCount( ) override;
+ virtual OUString SAL_CALL getAccessibleRowDescription( sal_Int32 nRow ) override;
+ virtual OUString SAL_CALL getAccessibleColumnDescription( sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL getAccessibleRowHeaders( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL getAccessibleColumnHeaders( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getSelectedAccessibleRows( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getSelectedAccessibleColumns( ) override;
+ virtual sal_Bool SAL_CALL isAccessibleRowSelected( sal_Int32 nRow ) override;
+ virtual sal_Bool SAL_CALL isAccessibleColumnSelected( sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleCaption( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleSummary( ) override;
+ virtual sal_Bool SAL_CALL isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleRow( sal_Int32 nChildIndex ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumn( sal_Int32 nChildIndex ) override;
+
+
+ void fireEvent(
+ const sal_Int16 _nEventId,
+ const css::uno::Any& _rOldValue,
+ const css::uno::Any& _rNewValue
+ )
+ {
+ NotifyAccessibleEvent(_nEventId,_rOldValue,_rNewValue);
+ }
+
+ void clearCharSetControl() { m_pParent = nullptr; }
+ private:
+
+ virtual ~SvxShowCharSetAcc() override;
+
+ // OCommonAccessibleSelection
+ // return if the specified child is visible => watch for special ChildIndexes (ACCESSIBLE_SELECTION_CHILD_xxx)
+ virtual bool
+ implIsSelected( sal_Int32 nAccessibleChildIndex ) override;
+
+ // select the specified child => watch for special ChildIndexes (ACCESSIBLE_SELECTION_CHILD_xxx)
+ virtual void
+ implSelect( sal_Int32 nAccessibleChildIndex, bool bSelect ) override;
+
+ // OCommonAccessibleComponent
+ /// implements the calculation of the bounding rectangle - still waiting to be overwritten
+ virtual css::awt::Rectangle implGetBounds( ) override;
+ };
+
+
+ // - SvxShowCharSetItemAcc -
+
+ typedef ::cppu::ImplHelper2 < css::accessibility::XAccessible,
+ css::accessibility::XAccessibleAction
+ > OAccessibleHelper_Base_3;
+
+ /** The child implementation of the table.
+ */
+ class SvxShowCharSetItemAcc final : public ::comphelper::OAccessibleComponentHelper,
+ public OAccessibleHelper_Base_3
+ {
+ private:
+ SvxShowCharSetItem* mpParent;
+
+ virtual ~SvxShowCharSetItemAcc() override;
+
+ // OCommonAccessibleComponent
+ /// implements the calculation of the bounding rectangle - still waiting to be overwritten
+ virtual css::awt::Rectangle implGetBounds( ) override;
+ public:
+
+ // XInterface
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ SvxShowCharSetItemAcc( SvxShowCharSetItem* pParent );
+
+ void ParentDestroyed();
+
+ // XAccessibleComponent
+ virtual void SAL_CALL grabFocus( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+
+ //OAccessibleContextHelper
+ // XAccessibleContext - still waiting to be overwritten
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override { return this; }
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override { return mpParent->m_pParent->getForeground(); }
+ virtual sal_Int32 SAL_CALL getBackground( ) override { return mpParent->m_pParent->getBackground(); }
+
+ // XAccessibleAction
+ virtual sal_Int32 SAL_CALL getAccessibleActionCount( ) override;
+ virtual sal_Bool SAL_CALL doAccessibleAction ( sal_Int32 nIndex ) override;
+ virtual OUString SAL_CALL getAccessibleActionDescription ( sal_Int32 nIndex ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleKeyBinding > SAL_CALL getAccessibleActionKeyBinding( sal_Int32 nIndex ) override;
+
+
+ void fireEvent(
+ const sal_Int16 _nEventId,
+ const css::uno::Any& _rOldValue,
+ const css::uno::Any& _rNewValue
+ )
+ {
+ NotifyAccessibleEvent(_nEventId,_rOldValue,_rNewValue);
+ }
+ };
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_CHARMAPACC_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/clonelist.hxx b/svx/source/inc/clonelist.hxx
new file mode 100644
index 000000000..5ed3e4d8c
--- /dev/null
+++ b/svx/source/inc/clonelist.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_CLONELIST_HXX
+#define INCLUDED_SVX_SOURCE_INC_CLONELIST_HXX
+
+#include <vector>
+
+#include <sal/types.h>
+
+class SdrObject;
+
+// #i13033#
+// New mechanism to hold a list of all original and cloned objects for later
+// re-creating the connections for contained connectors
+class CloneList
+{
+ std::vector<const SdrObject*> maOriginalList;
+ std::vector<SdrObject*> maCloneList;
+
+public:
+ void AddPair(const SdrObject* pOriginal, SdrObject* pClone);
+
+ const SdrObject* GetOriginal(sal_uInt32 nIndex) const;
+ SdrObject* GetClone(sal_uInt32 nIndex) const;
+
+ void CopyConnections() const;
+};
+
+#endif // INCLUDED_SVX_SOURCE_INC_CLONELIST_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/datalistener.hxx b/svx/source/inc/datalistener.hxx
new file mode 100644
index 000000000..88f0a9f5a
--- /dev/null
+++ b/svx/source/inc/datalistener.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_DATALISTENER_HXX
+#define INCLUDED_SVX_SOURCE_INC_DATALISTENER_HXX
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/frame/XFrameActionListener.hpp>
+#include <com/sun/star/xml/dom/events/XEventListener.hpp>
+
+
+namespace svxform
+{
+
+
+ class DataNavigatorWindow;
+
+ typedef cppu::WeakImplHelper<
+ css::container::XContainerListener,
+ css::frame::XFrameActionListener,
+ css::xml::dom::events::XEventListener > DataListener_t;
+
+ class DataListener final : public DataListener_t
+ {
+ private:
+ DataNavigatorWindow* m_pNaviWin;
+
+ public:
+ DataListener( DataNavigatorWindow* pNaviWin );
+
+ private:
+ virtual ~DataListener() override;
+
+ public:
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+
+ // XFrameActionListener
+ virtual void SAL_CALL frameAction( const css::frame::FrameActionEvent& Action ) override;
+
+ // xml::dom::events::XEventListener
+ virtual void SAL_CALL handleEvent( const css::uno::Reference< css::xml::dom::events::XEvent >& evt ) override;
+
+ // lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_DATALISTENER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/datanavi.hxx b/svx/source/inc/datanavi.hxx
new file mode 100644
index 000000000..22f30e044
--- /dev/null
+++ b/svx/source/inc/datanavi.hxx
@@ -0,0 +1,580 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_DATANAVI_HXX
+#define INCLUDED_SVX_SOURCE_INC_DATANAVI_HXX
+
+#include <config_options.h>
+#include <vcl/builderpage.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/weld.hxx>
+#include <svtools/inettbc.hxx>
+#include <sfx2/dockwin.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/ctrlitem.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svxdllapi.h>
+#include <rtl/ref.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/xforms/XFormsUIHelper1.hpp>
+#include <com/sun/star/xforms/XModel.hpp>
+#include <com/sun/star/xforms/XSubmission.hpp>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/events/XEventTarget.hpp>
+
+#include "datalistener.hxx"
+
+#include <memory>
+#include <string_view>
+#include <vector>
+
+class FmFormShell;
+
+
+namespace svxform
+{
+
+
+ enum DataGroupType
+ {
+ DGTUnknown = 0,
+ DGTInstance,
+ DGTSubmission,
+ DGTBinding
+ };
+
+ enum DataItemType
+ {
+ DITNone = 0,
+ DITText,
+ DITAttribute,
+ DITElement,
+ DITBinding
+ };
+
+ struct ItemNode;
+ class XFormsPage;
+ class DataNavigatorWindow;
+ class AddInstanceDialog;
+
+ class ReplaceString
+ {
+ OUString m_sDoc_UI;
+ OUString m_sInstance_UI;
+ OUString m_sNone_UI;
+
+ static constexpr OUStringLiteral m_sDoc_API = u"all";
+ static constexpr OUStringLiteral m_sInstance_API = u"instance";
+ static constexpr OUStringLiteral m_sNone_API = u"none";
+
+ ReplaceString( const ReplaceString& ) = delete;
+
+ public:
+ ReplaceString()
+ {
+ m_sDoc_UI = SvxResId(RID_STR_REPLACE_DOC);
+ m_sInstance_UI = SvxResId(RID_STR_REPLACE_INST);
+ m_sNone_UI = SvxResId(RID_STR_REPLACE_NONE);
+ }
+
+ /** convert submission replace string from API value to UI value.
+ Use 'none' as default. */
+ OUString const & toUI( std::u16string_view rStr ) const
+ {
+ if( rStr == m_sDoc_API )
+ return m_sDoc_UI;
+ else if( rStr == m_sInstance_API )
+ return m_sInstance_UI;
+ else
+ return m_sNone_UI;
+ }
+
+ /** convert submission replace string from UI to API.
+ Use 'none' as default. */
+ OUString toAPI( std::u16string_view rStr ) const
+ {
+ if( rStr == m_sDoc_UI )
+ return m_sDoc_API;
+ else if( rStr == m_sInstance_UI )
+ return m_sInstance_API;
+ else
+ return m_sNone_API;
+ }
+ };
+
+ class MethodString
+ {
+ OUString m_sPost_UI;
+ OUString m_sPut_UI;
+ OUString m_sGet_UI;
+
+ static constexpr OUStringLiteral m_sPost_API = u"post";
+ static constexpr OUStringLiteral m_sPut_API = u"put";
+ static constexpr OUStringLiteral m_sGet_API = u"get";
+
+ MethodString( const MethodString& ) = delete;
+
+ public:
+
+ MethodString()
+ {
+ m_sPost_UI = SvxResId(RID_STR_METHOD_POST);
+ m_sPut_UI = SvxResId(RID_STR_METHOD_PUT);
+ m_sGet_UI = SvxResId(RID_STR_METHOD_GET);
+ }
+
+ /** convert from API to UI; put is default. */
+ OUString const & toUI( std::u16string_view rStr ) const
+ {
+ if( rStr == m_sGet_API )
+ return m_sGet_UI;
+ else if( rStr == m_sPost_API )
+ return m_sPost_UI;
+ else
+ return m_sPut_UI;
+ }
+
+ /** convert from UI to API; put is default */
+ OUString toAPI( std::u16string_view rStr ) const
+ {
+ if( rStr == m_sGet_UI )
+ return m_sGet_API;
+ else if( rStr == m_sPost_UI )
+ return m_sPost_API;
+ else
+ return m_sPut_API;
+ }
+ };
+
+ class DataTreeDropTarget final : public DropTargetHelper
+ {
+ private:
+ virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override;
+ virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override;
+
+ public:
+ DataTreeDropTarget(weld::TreeView& rWidget);
+ };
+
+ class XFormsPage final : public BuilderPage
+ {
+ private:
+ MethodString m_aMethodString;
+ ReplaceString m_aReplaceString;
+
+ weld::Container* m_pParent;
+ std::unique_ptr<weld::Toolbar> m_xToolBox;
+ std::unique_ptr<weld::TreeView> m_xItemList;
+ std::unique_ptr<weld::TreeIter> m_xScratchIter;
+
+ DataTreeDropTarget m_aDropHelper;
+
+ css::uno::Reference< css::xforms::XFormsUIHelper1 >
+ m_xUIHelper;
+
+ DataNavigatorWindow* m_pNaviWin;
+ bool m_bHasModel;
+ DataGroupType m_eGroup;
+ // these strings are not valid on the Submission and Binding Page
+ // mb: furthermore these are properties of an instance, thus
+ // it would be much better to get/set them through the UIHelper
+ // interface.
+ OUString m_sInstanceName;
+ OUString m_sInstanceURL;
+ bool m_bLinkOnce;
+
+ DECL_LINK(TbxSelectHdl, const OString&, void);
+ DECL_LINK(ItemSelectHdl, weld::TreeView&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(PopupMenuHdl, const CommandEvent&, bool);
+
+ void AddChildren(const weld::TreeIter* _pParent,
+ const css::uno::Reference< css::xml::dom::XNode >& _xNode);
+ bool DoToolBoxAction(std::string_view rToolBoxID);
+ void AddEntry(std::unique_ptr<ItemNode> _pNewNode, bool _bIsElement, weld::TreeIter* pRet = nullptr);
+ void AddEntry(const css::uno::Reference< css::beans::XPropertySet >& _rPropSet, weld::TreeIter* pRet = nullptr);
+ void EditEntry( const css::uno::Reference< css::beans::XPropertySet >& _rPropSet );
+ bool RemoveEntry();
+
+ void PrepDnD();
+
+ void DeleteAndClearTree();
+
+ public:
+ XFormsPage(weld::Container* pParent, DataNavigatorWindow* _pNaviWin, DataGroupType _eGroup);
+ virtual ~XFormsPage() override;
+
+ bool HasModel() const { return m_bHasModel; }
+ OUString SetModel( const css::uno::Reference< css::xforms::XModel > & _xModel, int _nPagePos );
+ void ClearModel();
+ OUString LoadInstance(const css::uno::Sequence< css::beans::PropertyValue >& _xPropSeq);
+
+ bool DoMenuAction(std::string_view rMenuID);
+ void EnableMenuItems(weld::Menu* pMenu);
+
+ const OUString& GetInstanceName() const { return m_sInstanceName; }
+ const OUString& GetInstanceURL() const { return m_sInstanceURL; }
+ bool GetLinkOnce() const { return m_bLinkOnce; }
+ void SetInstanceName( const OUString &name ) { m_sInstanceName=name; }
+ void SetInstanceURL( const OUString &url ) { m_sInstanceURL=url; }
+ void SetLinkOnce( bool bLinkOnce ) { m_bLinkOnce=bLinkOnce; }
+
+ css::uno::Reference<css::beans::XPropertySet>
+ GetBindingForNode( const css::uno::Reference<css::xml::dom::XNode> &xNode ) { return m_xUIHelper->getBindingForNode(xNode,true); }
+ OUString GetServiceNameForNode( const css::uno::Reference<css::xml::dom::XNode> &xNode ) { return m_xUIHelper->getDefaultServiceNameForNode(xNode); }
+ const css::uno::Reference< css::xforms::XFormsUIHelper1 >&
+ GetXFormsHelper() const { return m_xUIHelper; }
+ };
+
+ class DataNavigatorWindow final
+ {
+ private:
+ VclPtr<vcl::Window> m_xParent;
+ std::unique_ptr<weld::ComboBox> m_xModelsBox;
+ std::unique_ptr<weld::MenuButton> m_xModelBtn;
+ std::unique_ptr<weld::Notebook> m_xTabCtrl;
+ std::unique_ptr<weld::MenuButton> m_xInstanceBtn;
+
+ std::unique_ptr<XFormsPage> m_xInstPage;
+ std::unique_ptr<XFormsPage> m_xSubmissionPage;
+ std::unique_ptr<XFormsPage> m_xBindingPage;
+
+ sal_Int32 m_nLastSelectedPos;
+ bool m_bShowDetails;
+ bool m_bIsNotifyDisabled;
+ std::vector< std::unique_ptr<XFormsPage> >
+ m_aPageList;
+ std::vector< css::uno::Reference< css::container::XContainer > >
+ m_aContainerList;
+ std::vector< css::uno::Reference< css::xml::dom::events::XEventTarget > >
+ m_aEventTargetList;
+ Timer m_aUpdateTimer;
+
+ ::rtl::Reference < DataListener >
+ m_xDataListener;
+ css::uno::Reference< css::container::XNameContainer >
+ m_xDataContainer;
+ css::uno::Reference< css::frame::XFrame >
+ m_xFrame;
+ css::uno::Reference< css::frame::XModel >
+ m_xFrameModel;
+
+ DECL_LINK( ModelSelectListBoxHdl, weld::ComboBox&, void );
+ DECL_LINK( MenuSelectHdl, const OString&, void );
+ DECL_LINK( MenuActivateHdl, weld::Toggleable&, void );
+ DECL_LINK( ActivatePageHdl, const OString&, void);
+ DECL_LINK( UpdateHdl, Timer *, void);
+ void ModelSelectHdl(const weld::ComboBox*);
+ OString GetCurrentPage() const;
+ XFormsPage* GetPage(const OString& rCurId);
+ void LoadModels();
+ void SetPageModel(const OString& rCurId);
+ void ClearAllPageModels( bool bClearPages );
+ void InitPages();
+ void CreateInstancePage( const css::uno::Sequence< css::beans::PropertyValue >& _xPropSeq );
+ bool HasFirstInstancePage() const;
+ OString GetNewPageId() const;
+
+ static bool IsAdditionalPage(std::string_view rIdent);
+
+ public:
+ DataNavigatorWindow(vcl::Window* pParent, weld::Builder& rBuilder, SfxBindings const * pBindings);
+ ~DataNavigatorWindow();
+
+ static void SetDocModified();
+ void NotifyChanges( bool _bLoadAll = false );
+ void AddContainerBroadcaster( const css::uno::Reference< css::container::XContainer > & xContainer );
+ void AddEventBroadcaster( const css::uno::Reference< css::xml::dom::events::XEventTarget >& xTarget );
+ void RemoveBroadcaster();
+
+ weld::Window* GetFrameWeld() const { return m_xParent->GetFrameWeld(); }
+
+ bool IsShowDetails() const { return m_bShowDetails; }
+ void DisableNotify( bool _bDisable ) { m_bIsNotifyDisabled = _bDisable; }
+ };
+
+ class DataNavigator final : public SfxDockingWindow, public SfxControllerItem
+ {
+ private:
+ std::unique_ptr<DataNavigatorWindow> m_xDataWin;
+
+ virtual Size CalcDockingSize( SfxChildAlignment ) override;
+ virtual SfxChildAlignment CheckAlignment( SfxChildAlignment, SfxChildAlignment ) override;
+
+ public:
+ DataNavigator( SfxBindings* pBindings, SfxChildWindow* pMgr, vcl::Window* pParent );
+ virtual ~DataNavigator() override;
+ virtual void dispose() override;
+
+ using SfxDockingWindow::StateChanged;
+
+ void StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState ) override;
+ };
+
+ class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) DataNavigatorManager final : public SfxChildWindow
+ {
+ public:
+ SVX_DLLPRIVATE DataNavigatorManager( vcl::Window* pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo* pInfo );
+ SFX_DECL_CHILDWINDOW( DataNavigatorManager );
+ };
+
+ class AddDataItemDialog final : public weld::GenericDialogController
+ {
+ private:
+ css::uno::Reference< css::xforms::XFormsUIHelper1 >
+ m_xUIHelper;
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xBinding;
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xTempBinding;
+
+ ItemNode* m_pItemNode;
+ DataItemType m_eItemType;
+ OUString m_sFL_Element;
+ OUString m_sFL_Attribute;
+ OUString m_sFL_Binding;
+ OUString m_sFT_BindingExp;
+
+ std::unique_ptr<weld::Frame> m_xItemFrame;
+ std::unique_ptr<weld::Label> m_xNameFT;
+ std::unique_ptr<weld::Entry> m_xNameED;
+ std::unique_ptr<weld::Label> m_xDefaultFT;
+ std::unique_ptr<weld::Entry> m_xDefaultED;
+ std::unique_ptr<weld::Button> m_xDefaultBtn;
+ std::unique_ptr<weld::Widget> m_xSettingsFrame;
+ std::unique_ptr<weld::Label> m_xDataTypeFT;
+ std::unique_ptr<weld::ComboBox> m_xDataTypeLB;
+ std::unique_ptr<weld::CheckButton> m_xRequiredCB;
+ std::unique_ptr<weld::Button> m_xRequiredBtn;
+ std::unique_ptr<weld::CheckButton> m_xRelevantCB;
+ std::unique_ptr<weld::Button> m_xRelevantBtn;
+ std::unique_ptr<weld::CheckButton> m_xConstraintCB;
+ std::unique_ptr<weld::Button> m_xConstraintBtn;
+ std::unique_ptr<weld::CheckButton> m_xReadonlyCB;
+ std::unique_ptr<weld::Button> m_xReadonlyBtn;
+ std::unique_ptr<weld::CheckButton> m_xCalculateCB;
+ std::unique_ptr<weld::Button> m_xCalculateBtn;
+ std::unique_ptr<weld::Button> m_xOKBtn;
+
+ void Check(const weld::Toggleable* pBox);
+ DECL_LINK(CheckHdl, weld::Toggleable&, void);
+ DECL_LINK(ConditionHdl, weld::Button&, void);
+ DECL_LINK(OKHdl, weld::Button&, void);
+
+ void InitDialog();
+ void InitFromNode();
+ void InitDataTypeBox();
+
+ public:
+ AddDataItemDialog(
+ weld::Window* pParent, ItemNode* _pNode,
+ const css::uno::Reference< css::xforms::XFormsUIHelper1 >& _rUIHelper );
+ virtual ~AddDataItemDialog() override;
+
+ void InitText( DataItemType _eType );
+ };
+
+ class AddConditionDialog final : public weld::GenericDialogController
+ {
+ private:
+ Idle m_aResultIdle;
+ OUString m_sPropertyName;
+
+ css::uno::Reference< css::xforms::XFormsUIHelper1 >
+ m_xUIHelper;
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xBinding;
+
+ std::unique_ptr<weld::TextView> m_xConditionED;
+ std::unique_ptr<weld::TextView> m_xResultWin;
+ std::unique_ptr<weld::Button> m_xEditNamespacesBtn;
+ std::unique_ptr<weld::Button> m_xOKBtn;
+
+ DECL_LINK(ModifyHdl, weld::TextView&, void);
+ DECL_LINK(ResultHdl, Timer *, void);
+ DECL_LINK(EditHdl, weld::Button&, void);
+ DECL_LINK(OKHdl, weld::Button&, void);
+
+ public:
+ AddConditionDialog(weld::Window* pParent,
+ const OUString& _rPropertyName, const css::uno::Reference< css::beans::XPropertySet >& _rBinding);
+ virtual ~AddConditionDialog() override;
+
+ const css::uno::Reference< css::xforms::XFormsUIHelper1 >& GetUIHelper() const { return m_xUIHelper; }
+ OUString GetCondition() const { return m_xConditionED->get_text(); }
+ void SetCondition(const OUString& _rCondition)
+ {
+ m_xConditionED->set_text(_rCondition);
+ m_aResultIdle.Start();
+ }
+ };
+
+ class NamespaceItemDialog final : public weld::GenericDialogController
+ {
+ private:
+ AddConditionDialog* m_pConditionDlg;
+ std::vector< OUString > m_aRemovedList;
+
+ css::uno::Reference< css::container::XNameContainer >&
+ m_rNamespaces;
+
+ std::unique_ptr<weld::TreeView> m_xNamespacesList;
+ std::unique_ptr<weld::Button> m_xAddNamespaceBtn;
+ std::unique_ptr<weld::Button> m_xEditNamespaceBtn;
+ std::unique_ptr<weld::Button> m_xDeleteNamespaceBtn;
+ std::unique_ptr<weld::Button> m_xOKBtn;
+
+ DECL_LINK(SelectHdl, weld::TreeView&, void);
+ DECL_LINK(ClickHdl, weld::Button&, void);
+ DECL_LINK(OKHdl, weld::Button&, void);
+
+ void LoadNamespaces();
+
+ public:
+ NamespaceItemDialog(AddConditionDialog* pParent, css::uno::Reference< css::container::XNameContainer >& _rContainer);
+ virtual ~NamespaceItemDialog() override;
+ };
+
+ class ManageNamespaceDialog final : public weld::GenericDialogController
+ {
+ private:
+ AddConditionDialog* m_pConditionDlg;
+
+ std::unique_ptr<weld::Entry> m_xPrefixED;
+ std::unique_ptr<weld::Entry> m_xUrlED;
+ std::unique_ptr<weld::Button> m_xOKBtn;
+ std::unique_ptr<weld::Label> m_xAltTitle;
+
+ DECL_LINK(OKHdl, weld::Button&, void);
+
+ public:
+ ManageNamespaceDialog(weld::Window* pParent, AddConditionDialog* _pCondDlg, bool bIsEdit);
+ virtual ~ManageNamespaceDialog() override;
+
+ void SetNamespace(const OUString& _rPrefix, const OUString& _rURL)
+ {
+ m_xPrefixED->set_text(_rPrefix);
+ m_xUrlED->set_text(_rURL);
+ }
+ OUString GetPrefix() const { return m_xPrefixED->get_text(); }
+ OUString GetURL() const { return m_xUrlED->get_text(); }
+ };
+
+ class AddSubmissionDialog final : public weld::GenericDialogController
+ {
+ private:
+ MethodString m_aMethodString;
+ ReplaceString m_aReplaceString;
+
+ ItemNode* m_pItemNode;
+
+ css::uno::Reference< css::xforms::XFormsUIHelper1 >
+ m_xUIHelper;
+ css::uno::Reference< css::xforms::XSubmission >
+ m_xNewSubmission;
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xSubmission;
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xTempBinding;
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xCreatedBinding;
+
+ std::unique_ptr<weld::Entry> m_xNameED;
+ std::unique_ptr<weld::Entry> m_xActionED;
+ std::unique_ptr<weld::ComboBox> m_xMethodLB;
+ std::unique_ptr<weld::Entry> m_xRefED;
+ std::unique_ptr<weld::Button> m_xRefBtn;
+ std::unique_ptr<weld::ComboBox> m_xBindLB;
+ std::unique_ptr<weld::ComboBox> m_xReplaceLB;
+ std::unique_ptr<weld::Button> m_xOKBtn;
+
+ DECL_LINK(RefHdl, weld::Button&, void);
+ DECL_LINK(OKHdl, weld::Button&, void);
+
+ void FillAllBoxes();
+
+ public:
+ AddSubmissionDialog(weld::Window* pParent, ItemNode* pNode,
+ const css::uno::Reference< css::xforms::XFormsUIHelper1 >& rUIHelper);
+ virtual ~AddSubmissionDialog() override;
+
+ const css::uno::Reference< css::xforms::XSubmission >& GetNewSubmission() const { return m_xNewSubmission; }
+ };
+
+ class AddModelDialog final : public weld::GenericDialogController
+ {
+ private:
+ std::unique_ptr<weld::Entry> m_xNameED;
+ std::unique_ptr<weld::CheckButton> m_xModifyCB;
+ std::unique_ptr<weld::Label> m_xAltTitle;
+
+ public:
+ AddModelDialog(weld::Window* pParent, bool _bEdit);
+ virtual ~AddModelDialog() override;
+
+ OUString GetName() const { return m_xNameED->get_text(); }
+ void SetName( const OUString& _rName ) { m_xNameED->set_text( _rName );}
+
+ bool GetModifyDoc() const { return m_xModifyCB->get_active(); }
+ void SetModifyDoc( const bool bModify ) { m_xModifyCB->set_active(bModify); }
+ };
+
+ class AddInstanceDialog final : public weld::GenericDialogController
+ {
+ private:
+ OUString m_sAllFilterName;
+
+ std::unique_ptr<weld::Entry> m_xNameED;
+ std::unique_ptr<weld::Label> m_xURLFT;
+ std::unique_ptr<SvtURLBox> m_xURLED;
+ std::unique_ptr<weld::Button> m_xFilePickerBtn;
+ std::unique_ptr<weld::CheckButton> m_xLinkInstanceCB;
+ std::unique_ptr<weld::Label> m_xAltTitle;
+
+ DECL_LINK(FilePickerHdl, weld::Button&, void);
+
+ public:
+ AddInstanceDialog(weld::Window* pParent, bool _bEdit);
+ virtual ~AddInstanceDialog() override;
+
+ OUString GetName() const { return m_xNameED->get_text(); }
+ void SetName( const OUString& rName ) { m_xNameED->set_text( rName );}
+ OUString GetURL() const { return m_xURLED->get_active_text(); }
+ void SetURL( const OUString& rURL ) { m_xURLED->set_entry_text( rURL );}
+ bool IsLinkInstance() const { return m_xLinkInstanceCB->get_active(); }
+ void SetLinkInstance( bool bLink ) { m_xLinkInstanceCB->set_active(bLink); }
+ };
+
+ class LinkedInstanceWarningBox final : public weld::MessageDialogController
+ {
+ public:
+ LinkedInstanceWarningBox(weld::Widget* pParent);
+ };
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_DATANAVI_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/delayedevent.hxx b/svx/source/inc/delayedevent.hxx
new file mode 100644
index 000000000..4f7925c94
--- /dev/null
+++ b/svx/source/inc/delayedevent.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_DELAYEDEVENT_HXX
+#define INCLUDED_SVX_SOURCE_INC_DELAYEDEVENT_HXX
+
+#include <tools/link.hxx>
+
+struct ImplSVEvent;
+
+namespace svxform
+{
+
+
+ //= DelayedEvent
+
+ /** small class which encapsulates posting a Link instance as ApplicationUserEvent
+
+ No thread safety at all here, just a little saving of code to type multiple times
+ */
+ class DelayedEvent
+ {
+ public:
+ DelayedEvent( const Link<void*,void>& _rHandler )
+ :m_aHandler( _rHandler )
+ ,m_nEventId( nullptr )
+ {
+ }
+
+ ~DelayedEvent()
+ {
+ CancelPendingCall();
+ }
+
+ /** calls the handler asynchronously
+
+ If there's already a call pending, this previous call is cancelled.
+ */
+ void Call();
+
+ /** cancels a call which is currently pending
+
+ If no call is currently pending, then this is ignored.
+ */
+ void CancelPendingCall();
+
+ private:
+ Link<void*,void> m_aHandler;
+ ImplSVEvent * m_nEventId;
+
+ private:
+ DECL_LINK( OnCall, void*, void );
+
+ private:
+ DelayedEvent( const DelayedEvent& ) = delete;
+ DelayedEvent& operator=( const DelayedEvent& ) = delete;
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_DELAYEDEVENT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/docrecovery.hxx b/svx/source/inc/docrecovery.hxx
new file mode 100644
index 000000000..9b69342bc
--- /dev/null
+++ b/svx/source/inc/docrecovery.hxx
@@ -0,0 +1,503 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_DOCRECOVERY_HXX
+#define INCLUDED_SVX_SOURCE_INC_DOCRECOVERY_HXX
+
+#include <vcl/weld.hxx>
+#include <o3tl/typed_flags_set.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+
+#define RECOVERY_CMDPART_PROTOCOL "vnd.sun.star.autorecovery:"
+
+#define RECOVERY_CMDPART_DO_EMERGENCY_SAVE "/doEmergencySave"
+#define RECOVERY_CMDPART_DO_RECOVERY "/doAutoRecovery"
+#define RECOVERY_CMDPART_DO_BRINGTOFRONT "/doBringToFront"
+
+inline constexpr OUStringLiteral RECOVERY_CMD_DO_PREPARE_EMERGENCY_SAVE = u"vnd.sun.star.autorecovery:/doPrepareEmergencySave";
+inline constexpr OUStringLiteral RECOVERY_CMD_DO_EMERGENCY_SAVE = u"vnd.sun.star.autorecovery:/doEmergencySave";
+inline constexpr OUStringLiteral RECOVERY_CMD_DO_RECOVERY = u"vnd.sun.star.autorecovery:/doAutoRecovery";
+inline constexpr OUStringLiteral RECOVERY_CMD_DO_ENTRY_BACKUP = u"vnd.sun.star.autorecovery:/doEntryBackup";
+inline constexpr OUStringLiteral RECOVERY_CMD_DO_ENTRY_CLEANUP = u"vnd.sun.star.autorecovery:/doEntryCleanUp";
+
+inline constexpr OUStringLiteral PROP_STATUSINDICATOR = u"StatusIndicator";
+inline constexpr OUStringLiteral PROP_DISPATCHASYNCHRON = u"DispatchAsynchron";
+inline constexpr OUStringLiteral PROP_SAVEPATH = u"SavePath";
+inline constexpr OUStringLiteral PROP_ENTRYID = u"EntryID";
+
+inline constexpr OUStringLiteral STATEPROP_ID = u"ID";
+inline constexpr OUStringLiteral STATEPROP_STATE = u"DocumentState";
+inline constexpr OUStringLiteral STATEPROP_ORGURL = u"OriginalURL";
+inline constexpr OUStringLiteral STATEPROP_TEMPURL = u"TempURL";
+inline constexpr OUStringLiteral STATEPROP_FACTORYURL = u"FactoryURL";
+inline constexpr OUStringLiteral STATEPROP_TEMPLATEURL = u"TemplateURL";
+inline constexpr OUStringLiteral STATEPROP_TITLE = u"Title";
+inline constexpr OUStringLiteral STATEPROP_MODULE = u"Module";
+
+#define RECOVERY_OPERATIONSTATE_START "start"
+#define RECOVERY_OPERATIONSTATE_STOP "stop"
+#define RECOVERY_OPERATIONSTATE_UPDATE "update"
+
+#define DLG_RET_UNKNOWN -1
+#define DLG_RET_OK RET_OK
+#define DLG_RET_CANCEL RET_CANCEL
+#define DLG_RET_OK_AUTOLUNCH 101
+
+
+enum class EDocStates
+{
+ /* TEMP STATES */
+
+ /// default state, if a document was new created or loaded
+ Unknown = 0x000,
+ /** an action was started (saving/loading) ... Can be interesting later if the process may be was interrupted by an exception. */
+ TryLoadBackup = 0x010,
+ TryLoadOriginal = 0x020,
+
+ /* FINAL STATES */
+
+ /// the Auto/Emergency saved document isn't usable any longer
+ Damaged = 0x040,
+ /// the Auto/Emergency saved document is not really up-to-date (some changes can be missing)
+ Incomplete = 0x080,
+ /// the Auto/Emergency saved document was processed successfully
+ Succeeded = 0x200
+};
+namespace o3tl {
+ template<> struct typed_flags<EDocStates> : is_typed_flags<EDocStates, 0x2f0> {};
+}
+
+
+namespace svx{
+ namespace DocRecovery{
+
+
+enum ERecoveryState
+{
+ E_SUCCESSFULLY_RECOVERED,
+ E_ORIGINAL_DOCUMENT_RECOVERED,
+ E_RECOVERY_FAILED,
+ E_RECOVERY_IS_IN_PROGRESS,
+ E_NOT_RECOVERED_YET
+};
+
+
+struct TURLInfo
+{
+ public:
+
+ /// unique ID, which is specified by the underlying autorecovery core!
+ sal_Int32 ID;
+
+ /// the full qualified document URL
+ OUString OrgURL;
+
+ /// the full qualified URL of the temp. file (if it's exists)
+ OUString TempURL;
+
+ /// a may be existing factory URL (e.g. for untitled documents)
+ OUString FactoryURL;
+
+ /// may be the document base on a template file !?
+ OUString TemplateURL;
+
+ /// the pure file name, without path, disc etcpp.
+ OUString DisplayName;
+
+ /// the application module, where this document was loaded
+ OUString Module;
+
+ /// state info as e.g. VALID, CORRUPTED, NON EXISTING ...
+ EDocStates DocState;
+
+ /// ui representation for DocState!
+ ERecoveryState RecoveryState;
+
+ /// standard icon
+ OUString StandardImageId;
+
+ public:
+
+ TURLInfo()
+ : ID (-1 )
+ , DocState (EDocStates::Unknown)
+ , RecoveryState(E_NOT_RECOVERED_YET)
+ {}
+};
+
+
+typedef ::std::vector< TURLInfo > TURLList;
+
+
+class IRecoveryUpdateListener
+{
+ public:
+
+ // inform listener about changed items, which should be refreshed
+ virtual void updateItems() = 0;
+
+ // inform listener about ending of the asynchronous recovery operation
+ virtual void end() = 0;
+
+ // TODO
+ virtual void stepNext(TURLInfo* pItem) = 0;
+
+ protected:
+ ~IRecoveryUpdateListener() {}
+};
+
+
+class RecoveryCore final : public ::cppu::WeakImplHelper< css::frame::XStatusListener >
+{
+
+ // types, const
+ public:
+
+
+ // member
+ private:
+
+ /// TODO
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ /// TODO
+ css::uno::Reference< css::frame::XDispatch > m_xRealCore;
+
+ /// TODO
+ css::uno::Reference< css::task::XStatusIndicator > m_xProgress;
+
+ /// TODO
+ TURLList m_lURLs;
+
+ /// TODO
+ IRecoveryUpdateListener* m_pListener;
+
+ /** @short knows the reason, why we listen on our internal m_xRealCore
+ member.
+
+ @descr Because we listen for different operations
+ on the core dispatch implementation, we must know,
+ which URL we have to use for deregistration!
+ */
+ bool m_bListenForSaving;
+
+
+ // native interface
+ public:
+
+
+ /** @short TODO */
+ RecoveryCore(const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ bool bUsedForSaving);
+
+
+ /** @short TODO */
+ virtual ~RecoveryCore() override;
+
+
+ /** @short TODO */
+ const css::uno::Reference< css::uno::XComponentContext >& getComponentContext() const;
+
+
+ /** @short TODO */
+ TURLList& getURLListAccess();
+
+
+ /** @short TODO */
+ static bool isBrokenTempEntry(const TURLInfo& rInfo);
+ void saveBrokenTempEntries(const OUString& sSaveDir);
+ void saveAllTempEntries(const OUString& sSaveDir);
+ void forgetBrokenTempEntries();
+ void forgetAllRecoveryEntries();
+ void forgetBrokenRecoveryEntries();
+
+
+ /** @short TODO */
+ void setProgressHandler(const css::uno::Reference< css::task::XStatusIndicator >& xProgress);
+
+
+ /** @short TODO */
+ void setUpdateListener(IRecoveryUpdateListener* pListener);
+
+
+ /** @short TODO */
+ void doEmergencySavePrepare();
+ void doEmergencySave();
+ void doRecovery();
+
+
+ /** @short TODO */
+ static ERecoveryState mapDocState2RecoverState(EDocStates eDocState);
+
+
+ // uno interface
+ public:
+
+ // css.frame.XStatusListener
+ virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& aEvent) override;
+
+ // css.lang.XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override;
+
+
+ // helper
+ private:
+
+
+ /** @short starts listening on the internal EmergencySave/AutoRecovery core.
+ */
+ void impl_startListening();
+
+
+ /** @short stop listening on the internal EmergencySave/AutoRecovery core.
+ */
+ void impl_stopListening();
+
+
+ /** @short TODO */
+ css::util::URL impl_getParsedURL(const OUString& sURL);
+};
+
+class PluginProgress final : public ::cppu::WeakImplHelper<css::task::XStatusIndicator, css::lang::XComponent>
+{
+// member
+private:
+ weld::ProgressBar* m_pProgressBar;
+ int m_nRange;
+
+// native interface
+public:
+ PluginProgress(weld::ProgressBar* pProgressBar);
+ virtual ~PluginProgress() override;
+
+// uno interface
+public:
+ // XStatusIndicator
+ virtual void SAL_CALL start(const OUString& sText, sal_Int32 nRange) override;
+ virtual void SAL_CALL end() override;
+ virtual void SAL_CALL setText(const OUString& sText) override;
+ virtual void SAL_CALL setValue(sal_Int32 nValue) override;
+ virtual void SAL_CALL reset() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+ virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener >& xListener) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener) override;
+};
+
+class SaveDialog final : public weld::GenericDialogController
+{
+// member
+private:
+ RecoveryCore* m_pCore;
+ std::unique_ptr<weld::TreeView> m_xFileListLB;
+ std::unique_ptr<weld::Button> m_xOkBtn;
+
+// interface
+public:
+ /** @short create all child controls of this dialog.
+
+ @descr The dialog isn't shown nor it starts any
+ action by itself!
+
+ @param pParent
+ can point to a parent window.
+ If it's set to 0, the defmodal-dialog-parent
+ is used automatically.
+
+ @param pCore
+ provides access to the recovery core service
+ and the current list of open documents,
+ which should be shown inside this dialog.
+ */
+ SaveDialog(weld::Window* pParent, RecoveryCore* pCore);
+ virtual ~SaveDialog() override;
+
+ DECL_LINK(OKButtonHdl, weld::Button&, void);
+};
+
+class SaveProgressDialog final : public weld::GenericDialogController
+ , public IRecoveryUpdateListener
+{
+ // member
+ private:
+ // @short TODO
+ RecoveryCore* m_pCore;
+
+ std::unique_ptr<weld::ProgressBar> m_xProgressBar;
+
+ // @short TODO
+ css::uno::Reference< css::task::XStatusIndicator > m_xProgress;
+ // interface
+ public:
+ /** @short create all child controls of this dialog.
+
+ @descr The dialog isn't shown nor it starts any
+ action by itself!
+
+ @param pParent
+ can point to a parent window.
+ If it's set to 0, the defmodal-dialog-parent
+ is used automatically.
+
+ @param pCore
+ used to start emergency save.
+ */
+ SaveProgressDialog(weld::Window* pParent,
+ RecoveryCore* pCore);
+ virtual ~SaveProgressDialog() override;
+
+ /** @short start the emergency save operation. */
+ virtual short run() override;
+
+ // IRecoveryUpdateListener
+ virtual void updateItems() override;
+ virtual void stepNext(TURLInfo* pItem) override;
+ virtual void end() override;
+};
+
+class RecoveryDialog final : public weld::GenericDialogController
+ , public IRecoveryUpdateListener
+{
+ // member
+ private:
+ OUString m_aTitleRecoveryInProgress;
+ OUString m_aRecoveryOnlyFinish;
+ OUString m_aRecoveryOnlyFinishDescr;
+
+ RecoveryCore* m_pCore;
+ css::uno::Reference< css::task::XStatusIndicator > m_xProgress;
+ enum EInternalRecoveryState
+ {
+ E_RECOVERY_PREPARED, // dialog started... recovery prepared
+ E_RECOVERY_IN_PROGRESS, // recovery core still in progress
+ E_RECOVERY_CORE_DONE, // recovery core finished it's task
+ E_RECOVERY_DONE, // user clicked "next" button
+ E_RECOVERY_CANCELED, // user clicked "cancel" button
+ E_RECOVERY_CANCELED_BEFORE, // user clicked "cancel" button before recovery was started
+ E_RECOVERY_CANCELED_AFTERWARDS, // user clicked "cancel" button after recovery was finished
+ E_RECOVERY_HANDLED // the recovery wizard page was shown already... and will be shown now again...
+ };
+ sal_Int32 m_eRecoveryState;
+ bool m_bWaitForCore;
+ bool m_bWasRecoveryStarted;
+
+ OUString m_aSuccessRecovStr;
+ OUString m_aOrigDocRecovStr;
+ OUString m_aRecovFailedStr;
+ OUString m_aRecovInProgrStr;
+ OUString m_aNotRecovYetStr;
+
+ std::unique_ptr<weld::Label> m_xDescrFT;
+ std::unique_ptr<weld::ProgressBar> m_xProgressBar;
+ std::unique_ptr<weld::TreeView> m_xFileListLB;
+ std::unique_ptr<weld::Button> m_xNextBtn;
+ std::unique_ptr<weld::Button> m_xCancelBtn;
+
+ // member
+ public:
+ /** @short TODO */
+ RecoveryDialog(weld::Window* pParent,
+ RecoveryCore* pCore);
+
+ virtual ~RecoveryDialog() override;
+
+ // IRecoveryUpdateListener
+ virtual void updateItems() override;
+ virtual void stepNext(TURLInfo* pItem) override;
+ virtual void end() override;
+
+ short execute();
+
+ // helper
+ private:
+ DECL_LINK(NextButtonHdl, weld::Button&, void);
+ DECL_LINK(CancelButtonHdl, weld::Button&, void);
+
+ OUString impl_getStatusString( const TURLInfo& rInfo ) const;
+ static OUString impl_getStatusImage( const TURLInfo& rInfo );
+};
+
+
+class BrokenRecoveryDialog final : public weld::GenericDialogController
+{
+// member
+private:
+ OUString m_sSavePath;
+ RecoveryCore* m_pCore;
+ bool const m_bBeforeRecovery;
+ bool m_bExecutionNeeded;
+
+ std::unique_ptr<weld::TreeView> m_xFileListLB;
+ std::unique_ptr<weld::Entry> m_xSaveDirED;
+ std::unique_ptr<weld::Button> m_xSaveDirBtn;
+ std::unique_ptr<weld::Button> m_xOkBtn;
+ std::unique_ptr<weld::Button> m_xCancelBtn;
+
+// interface
+public:
+
+ /** @short TODO */
+ BrokenRecoveryDialog(weld::Window* pParent,
+ RecoveryCore* pCore,
+ bool bBeforeRecovery);
+ virtual ~BrokenRecoveryDialog() override;
+
+ /** @short TODO */
+ bool isExecutionNeeded() const;
+
+
+ /** @short TODO */
+ const OUString& getSaveDirURL() const;
+
+
+// helper
+private:
+ /** @short TODO */
+ void impl_refresh();
+
+
+ /** @short TODO */
+ DECL_LINK(SaveButtonHdl, weld::Button&, void);
+
+
+ /** @short TODO */
+ DECL_LINK(OkButtonHdl, weld::Button&, void);
+
+
+ /** @short TODO */
+ DECL_LINK(CancelButtonHdl, weld::Button&, void);
+
+
+ /** @short TODO */
+ void impl_askForSavePath();
+};
+ }
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/filtnav.hxx b/svx/source/inc/filtnav.hxx
new file mode 100644
index 000000000..47af4017a
--- /dev/null
+++ b/svx/source/inc/filtnav.hxx
@@ -0,0 +1,339 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FILTNAV_HXX
+#define INCLUDED_SVX_SOURCE_INC_FILTNAV_HXX
+
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/runtime/XFormController.hpp>
+#include <com/sun/star/form/runtime/XFilterController.hpp>
+#include <svl/lstner.hxx>
+#include <svl/SfxBroadcaster.hxx>
+
+#include <vcl/window.hxx>
+#include <sfx2/childwin.hxx>
+#include <svl/poolitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dockwin.hxx>
+#include <sfx2/ctrlitem.hxx>
+
+#include "fmexch.hxx"
+#include "sqlparserclient.hxx"
+
+class FmFormShell;
+
+namespace svxform
+{
+
+class FmFilterItem;
+class FmFilterItems;
+class FmParentData;
+class FmFilterAdapter;
+
+// data structure for the filter model
+class FmFilterData
+{
+ FmParentData* m_pParent;
+ OUString m_aText;
+
+public:
+ FmFilterData(FmParentData* pParent, const OUString& rText)
+ :m_pParent( pParent )
+ ,m_aText( rText )
+ {}
+ virtual ~FmFilterData(){}
+
+ void SetText( const OUString& rText ){ m_aText = rText; }
+ const OUString& GetText() const { return m_aText; }
+ FmParentData* GetParent() const {return m_pParent;}
+
+ virtual OUString GetImage() const;
+};
+
+class FmParentData : public FmFilterData
+{
+protected:
+ ::std::vector< std::unique_ptr<FmFilterData> > m_aChildren;
+
+public:
+ FmParentData(FmParentData* pParent, const OUString& rText)
+ : FmFilterData(pParent, rText)
+ {}
+ virtual ~FmParentData() override;
+
+ ::std::vector< std::unique_ptr<FmFilterData> >& GetChildren() { return m_aChildren; }
+};
+
+// Item representing the forms and subforms
+class FmFormItem final : public FmParentData
+{
+ css::uno::Reference< css::form::runtime::XFormController > m_xController;
+ css::uno::Reference< css::form::runtime::XFilterController > m_xFilterController;
+
+public:
+
+ FmFormItem( FmParentData* _pParent,
+ const css::uno::Reference< css::form::runtime::XFormController > & _xController,
+ const OUString& _rText)
+ :FmParentData( _pParent, _rText )
+ ,m_xController( _xController )
+ ,m_xFilterController( _xController, css::uno::UNO_QUERY_THROW )
+ {
+ }
+
+ const css::uno::Reference< css::form::runtime::XFormController >&
+ GetController() const { return m_xController; }
+
+ const css::uno::Reference< css::form::runtime::XFilterController >&
+ GetFilterController() const { return m_xFilterController; }
+
+ virtual OUString GetImage() const override;
+};
+
+class FmFilterItems final : public FmParentData
+{
+public:
+ FmFilterItems(FmFormItem* pParent, const OUString& rText ) : FmParentData(pParent, rText) {}
+
+ FmFilterItem* Find( const ::sal_Int32 _nFilterComponentIndex ) const;
+ virtual OUString GetImage() const override;
+};
+
+class FmFilterItem final : public FmFilterData
+{
+ OUString m_aFieldName;
+ sal_Int32 m_nComponentIndex;
+
+public:
+ FmFilterItem(
+ FmFilterItems* pParent,
+ const OUString& aFieldName,
+ const OUString& aCondition,
+ const sal_Int32 _nComponentIndex
+ );
+
+ const OUString& GetFieldName() const {return m_aFieldName;}
+ sal_Int32 GetComponentIndex() const { return m_nComponentIndex; }
+
+ virtual OUString GetImage() const override;
+};
+
+class FmFilterModel final : public FmParentData
+ ,public SfxBroadcaster
+ ,public ::svxform::OSQLParserClient
+{
+ friend class FmFilterAdapter;
+
+ css::uno::Reference< css::container::XIndexAccess > m_xControllers;
+ css::uno::Reference< css::form::runtime::XFormController > m_xController;
+ rtl::Reference<FmFilterAdapter> m_pAdapter;
+ FmFilterItems* m_pCurrentItems;
+
+public:
+ FmFilterModel();
+ virtual ~FmFilterModel() override;
+
+ void Update(const css::uno::Reference< css::container::XIndexAccess > & xControllers, const css::uno::Reference< css::form::runtime::XFormController > & xCurrent);
+ void Clear();
+ bool ValidateText(FmFilterItem const * pItem, OUString& rText, OUString& rErrorMsg) const;
+ void Append(FmFilterItems* pItems, std::unique_ptr<FmFilterItem> pFilterItem);
+ void SetTextForItem(FmFilterItem* pItem, const OUString& rText);
+
+ FmFormItem* GetCurrentForm() const {return m_pCurrentItems ? static_cast<FmFormItem*>(m_pCurrentItems->GetParent()) : nullptr;}
+ FmFilterItems* GetCurrentItems() const {return m_pCurrentItems;}
+ void SetCurrentItems(FmFilterItems* pCurrent);
+
+ const css::uno::Reference< css::form::runtime::XFormController > & GetCurrentController() const {return m_xController;}
+ void SetCurrentController(const css::uno::Reference< css::form::runtime::XFormController > & xController);
+
+ void Remove(FmFilterData* pFilterItem);
+ static void AppendFilterItems( FmFormItem& _rItem );
+ void EnsureEmptyFilterRows( FmParentData& _rItem );
+
+private:
+ void Insert(const ::std::vector<std::unique_ptr<FmFilterData>>::iterator& rPos, std::unique_ptr<FmFilterData> pFilterItem);
+ void Remove( const ::std::vector<std::unique_ptr<FmFilterData>>::iterator& rPos );
+ FmFormItem* Find(const ::std::vector<std::unique_ptr<FmFilterData>>& rItems, const css::uno::Reference< css::form::runtime::XFormController > & xController) const;
+ FmFormItem* Find(const ::std::vector<std::unique_ptr<FmFilterData>>& rItems, const css::uno::Reference< css::form::XForm >& xForm) const;
+ void Update(const css::uno::Reference< css::container::XIndexAccess > & xControllers, FmParentData* pParent);
+};
+
+
+class OFilterItemExchange final : public OLocalExchange
+{
+ ::std::vector<FmFilterItem*> m_aDraggedEntries;
+ FmFormItem* m_pFormItem; // ensure that we drop on the same form
+
+public:
+ OFilterItemExchange();
+
+ static SotClipboardFormatId getFormatId( );
+ inline static bool hasFormat( const DataFlavorExVector& _rFormats );
+
+ const ::std::vector<FmFilterItem*>& getDraggedEntries() const { return m_aDraggedEntries; }
+ void setDraggedEntries(::std::vector<FmFilterItem*>&& _rList) { m_aDraggedEntries = std::move(_rList); }
+ FmFormItem* getFormItem() const { return m_pFormItem; }
+
+ void setFormItem( FmFormItem* _pItem ) { m_pFormItem = _pItem; }
+
+private:
+ virtual void AddSupportedFormats() override;
+};
+
+inline bool OFilterItemExchange::hasFormat( const DataFlavorExVector& _rFormats )
+{
+ return OLocalExchange::hasFormat( _rFormats, getFormatId() );
+}
+
+class OFilterExchangeHelper final : public OLocalExchangeHelper
+{
+public:
+ OFilterExchangeHelper() : OLocalExchangeHelper() { }
+
+ OFilterItemExchange* operator->() const { return static_cast<OFilterItemExchange*>(m_xTransferable.get()); }
+ OFilterItemExchange& operator*() const { return *static_cast<OFilterItemExchange*>(m_xTransferable.get()); }
+
+private:
+ virtual rtl::Reference<OLocalExchange> createExchange() const override;
+};
+
+class FmFilterNavigator;
+
+class FmFilterNavigatorDropTarget final : public DropTargetHelper
+{
+private:
+ FmFilterNavigator& m_rTreeView;
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+public:
+ FmFilterNavigatorDropTarget(FmFilterNavigator& rTreeView);
+};
+
+class FmFilterNavigator final : public SfxListener
+{
+ VclPtr<vcl::Window> m_xTopLevel;
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+ FmFilterNavigatorDropTarget m_aDropTargetHelper;
+
+ std::unique_ptr<FmFilterModel> m_pModel;
+ std::unique_ptr<weld::TreeIter> m_xEditingCurrently;
+ OFilterExchangeHelper m_aControlExchange;
+
+ ImplSVEvent* m_nAsyncRemoveEvent;
+
+public:
+ FmFilterNavigator(vcl::Window* pTopLevel, std::unique_ptr<weld::TreeView> xTreeView);
+ virtual ~FmFilterNavigator() override;
+
+ void GrabFocus() { m_xTreeView->grab_focus(); }
+
+ void EndEditing();
+
+ void UpdateContent(
+ const css::uno::Reference< css::container::XIndexAccess > & xControllers,
+ const css::uno::Reference< css::form::runtime::XFormController > & xCurrent
+ );
+
+ weld::TreeView& get_widget() { return *m_xTreeView; }
+
+ sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt);
+ sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt);
+
+private:
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(PopupMenuHdl, const CommandEvent&, bool);
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ DECL_STATIC_LINK(FmFilterNavigator, CustomGetSizeHdl, weld::TreeView::get_size_args, Size);
+ DECL_STATIC_LINK(FmFilterNavigator, CustomRenderHdl, weld::TreeView::render_args, void);
+
+ DECL_LINK(SelectHdl, weld::TreeView&, void);
+ DECL_LINK(EditingEntryHdl, const weld::TreeIter&, bool);
+ typedef std::pair<const weld::TreeIter&, OUString> IterString;
+ DECL_LINK(EditedEntryHdl, const IterString&, bool);
+
+ DECL_LINK(DragBeginHdl, bool&, bool);
+
+ void DeleteSelection();
+ std::unique_ptr<weld::TreeIter> FindEntry(const FmFilterData* pItem) const;
+ void Insert(const FmFilterData* pItem, int nPos);
+ void Remove(FmFilterData const * pItem);
+
+ DECL_LINK(OnRemove, void*, void);
+
+ /** returns the first form item and the selected FilterItems in the vector
+ @param _rItemList
+ Is filled inside. <OUT/>
+ @return
+ The first form item.
+ */
+ FmFormItem* getSelectedFilterItems(::std::vector<FmFilterItem*>& _rItemList);
+
+ /**
+ * inserts the filter items into the tree model and creates new FilterItems if needed.
+ * @param _rFilterList
+ * The items which should be inserted.
+ * @param _pTargetItems
+ * The target where to insert the items.
+ * @param _bCopy
+ * If <TRUE/> the items will not be removed from the model, otherwise they will.
+ */
+ void insertFilterItem(const ::std::vector<FmFilterItem*>& _rFilterList,FmFilterItems* _pTargetItems, bool _bCopy);
+
+ bool getPrevEntry(weld::TreeIter& rEntry);
+ bool getNextEntry(weld::TreeIter& rEntry);
+};
+
+class FmFilterNavigatorWin final : public SfxDockingWindow, public SfxControllerItem
+{
+private:
+ std::unique_ptr<FmFilterNavigator> m_xNavigatorTree;
+
+ virtual bool Close() override;
+ virtual void GetFocus() override;
+ virtual Size CalcDockingSize( SfxChildAlignment ) override;
+ virtual SfxChildAlignment CheckAlignment( SfxChildAlignment, SfxChildAlignment ) override;
+
+ using SfxDockingWindow::StateChanged;
+
+public:
+ FmFilterNavigatorWin( SfxBindings *pBindings, SfxChildWindow *pMgr,
+ vcl::Window* pParent );
+ virtual ~FmFilterNavigatorWin() override;
+ virtual void dispose() override;
+
+ void UpdateContent( FmFormShell const * pFormShell );
+ void StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) override;
+ void FillInfo( SfxChildWinInfo& rInfo ) const override;
+};
+
+class FmFilterNavigatorWinMgr final : public SfxChildWindow
+{
+public:
+ FmFilterNavigatorWinMgr( vcl::Window *pParent, sal_uInt16 nId, SfxBindings *pBindings,
+ SfxChildWinInfo *pInfo );
+ SFX_DECL_CHILDWINDOW( FmFilterNavigatorWinMgr );
+};
+
+}
+
+#endif // INCLUDED_SVX_SOURCE_INC_FILTNAV_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/findtextfield.hxx b/svx/source/inc/findtextfield.hxx
new file mode 100644
index 000000000..bce8b5589
--- /dev/null
+++ b/svx/source/inc/findtextfield.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/InterimItemWindow.hxx>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace svt
+{
+class AcceleratorExecute;
+}
+
+class FindTextFieldControl final : public InterimItemWindow
+{
+public:
+ FindTextFieldControl(vcl::Window* pParent,
+ css::uno::Reference<css::frame::XFrame> const& xFrame,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext);
+
+ virtual void dispose() override;
+
+ virtual ~FindTextFieldControl() override;
+
+ void Remember_Impl(const OUString& rStr);
+ void SetTextToSelected_Impl();
+
+ void connect_changed(const Link<weld::ComboBox&, void>& rLink);
+
+ int get_count() const;
+ OUString get_text(int nIndex) const;
+ OUString get_active_text() const;
+ void append_text(const OUString& rText);
+ void set_entry_message_type(weld::EntryMessageType eType);
+
+private:
+ ImplSVEvent* m_nAsyncGetFocusId;
+ std::unique_ptr<weld::ComboBox> m_xWidget;
+ css::uno::Reference<css::frame::XFrame> m_xFrame;
+ css::uno::Reference<css::uno::XComponentContext> m_xContext;
+ std::unique_ptr<svt::AcceleratorExecute> m_pAcc;
+ Link<weld::ComboBox&, void> m_aChangeHdl;
+
+ DECL_LINK(FocusInHdl, weld::Widget&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+ DECL_LINK(OnAsyncGetFocus, void*, void);
+
+ void FocusIn();
+ void ActivateFind(bool bShift);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmPropBrw.hxx b/svx/source/inc/fmPropBrw.hxx
new file mode 100644
index 000000000..b33597b24
--- /dev/null
+++ b/svx/source/inc/fmPropBrw.hxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FMPROPBRW_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMPROPBRW_HXX
+
+#include <com/sun/star/frame/XFrame2.hpp>
+#include <com/sun/star/inspection/XObjectInspectorModel.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/ctrlitem.hxx>
+#include <sfx2/childwin.hxx>
+#include <svx/fmtools.hxx>
+
+
+class FmPropBrwMgr final : public SfxChildWindow
+{
+public:
+ FmPropBrwMgr(vcl::Window *pParent, sal_uInt16 nId, SfxBindings *pBindings, const SfxChildWinInfo *pInfo);
+ SFX_DECL_CHILDWINDOW(FmPropBrwMgr);
+};
+
+class SfxBindings;
+class FmFormShell;
+
+class FmPropBrw final : public SfxModelessDialogController, public SfxControllerItem
+{
+ bool m_bInitialStateChange;
+ weld::Window* m_pParent;
+ ImplSVEvent* m_nAsyncGetFocusId;
+ OUString m_sLastActivePage;
+ std::unique_ptr<weld::Container> m_xContainer;
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xInspectorContext;
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xORB;
+ css::uno::Reference< css::frame::XFrame2 >
+ m_xMeAsFrame;
+ css::uno::Reference< css::uno::XInterface >
+ m_xLastKnownDocument;
+ css::uno::Reference< css::inspection::XObjectInspectorModel >
+ m_xInspectorModel;
+ css::uno::Reference< css::frame::XController >
+ m_xBrowserController;
+
+ virtual void StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState) override;
+ virtual void FillInfo( SfxChildWinInfo& rInfo ) const override;
+ virtual void Close() override;
+
+ DECL_LINK( OnAsyncGetFocus, void*, void );
+
+ void implSetNewSelection( const InterfaceBag& _rSelection );
+ void implDetachController();
+ bool implIsReadOnlyModel() const;
+ OUString getCurrentPage() const;
+
+public:
+ FmPropBrw(
+ const css::uno::Reference< css::uno::XComponentContext >& _xORB,
+ SfxBindings* pBindings,
+ SfxChildWindow* pMgr,
+ weld::Window* pParent,
+ const SfxChildWinInfo* _pInfo
+ );
+ virtual ~FmPropBrw() override;
+
+private:
+
+ /** creates the PropertyBrowser (aka ObjectInspector) and plugs it into our frame
+
+ This method ensures that a new component is created every time the XModel which
+ we're working for changed. This is necessary since this model is part of the
+ ComponentContext we use to create the ObjectInspector.
+ */
+ void impl_ensurePropertyBrowser_nothrow( FmFormShell* _pFormShell );
+
+ /** creates a property browser
+
+ After this method returns, m_xBrowserController is not <NULL/>.
+
+ @precond
+ we don't have an ObjectInspector, yet, i.e. m_xBrowserController is <NULL/>.
+ */
+ void impl_createPropertyBrowser_throw( FmFormShell* _pFormShell );
+};
+#endif // INCLUDED_SVX_SOURCE_INC_FMPROPBRW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmcontrolbordermanager.hxx b/svx/source/inc/fmcontrolbordermanager.hxx
new file mode 100644
index 000000000..620d8b98d
--- /dev/null
+++ b/svx/source/inc/fmcontrolbordermanager.hxx
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FMCONTROLBORDERMANAGER_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMCONTROLBORDERMANAGER_HXX
+
+#include <com/sun/star/awt/VisualEffect.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/XVclWindowPeer.hpp>
+#include <o3tl/typed_flags_set.hxx>
+#include <tools/color.hxx>
+
+#include <set>
+
+namespace com::sun::star::form::validation { class XValidatableFormComponent; }
+
+enum class ControlStatus {
+ NONE = 0x00,
+ Focused = 0x01,
+ MouseHover = 0x02,
+ Invalid = 0x04
+};
+namespace o3tl {
+ template<> struct typed_flags<ControlStatus> : is_typed_flags<ControlStatus, 0x07> {};
+}
+
+
+namespace svxform
+{
+
+
+ struct BorderDescriptor
+ {
+ sal_Int16 nBorderType;
+ Color nBorderColor;
+
+ BorderDescriptor()
+ :nBorderType( css::awt::VisualEffect::FLAT )
+ {
+ }
+ };
+
+ struct UnderlineDescriptor
+ {
+ sal_Int16 nUnderlineType;
+ Color nUnderlineColor;
+
+ UnderlineDescriptor()
+ :nUnderlineType( css::awt::FontUnderline::NONE )
+ {
+ }
+
+ UnderlineDescriptor( sal_Int16 _nUnderlineType, Color _nUnderlineColor )
+ :nUnderlineType( _nUnderlineType )
+ ,nUnderlineColor( _nUnderlineColor )
+ {
+ }
+ };
+
+ struct ControlData : public BorderDescriptor, UnderlineDescriptor
+ {
+ css::uno::Reference< css::awt::XControl > xControl;
+ OUString sOriginalHelpText;
+
+ ControlData() : BorderDescriptor() { }
+ ControlData( const css::uno::Reference< css::awt::XControl >& _rxControl )
+ :xControl( _rxControl )
+ {
+ }
+ };
+
+
+ //= ControlBorderManager
+
+ /** manages the dynamic border color for form controls
+
+ Used by the <type>FormController</type>, this class manages the dynamic changes in the
+ border color of form controls. For this a set of events have to be forwarded to the manager
+ instance, which then will switch the border color depending on the mouse and focus status
+ of the controls.
+ */
+ class ControlBorderManager
+ {
+ private:
+ struct ControlDataCompare
+ {
+ bool operator()( const ControlData& _rLHS, const ControlData& _rRHS ) const
+ {
+ return _rLHS.xControl.get() < _rRHS.xControl.get();
+ }
+ };
+
+ typedef ::std::set< ControlData, ControlDataCompare > ControlBag;
+ typedef ::std::set< css::uno::Reference< css::awt::XVclWindowPeer > > PeerBag;
+
+ PeerBag m_aColorableControls;
+ PeerBag m_aNonColorableControls;
+
+ ControlData m_aFocusControl;
+ ControlData m_aMouseHoverControl;
+ ControlBag m_aInvalidControls;
+
+
+ // attributes
+ Color m_nFocusColor;
+ Color m_nMouseHoveColor;
+ Color m_nInvalidColor;
+ bool m_bDynamicBorderColors;
+
+ public:
+ ControlBorderManager();
+ ~ControlBorderManager();
+
+ public:
+ void focusGained( const css::uno::Reference< css::uno::XInterface >& _rxControl );
+ void focusLost( const css::uno::Reference< css::uno::XInterface >& _rxControl );
+ void mouseEntered( const css::uno::Reference< css::uno::XInterface >& _rxControl );
+ void mouseExited( const css::uno::Reference< css::uno::XInterface >& _rxControl );
+
+ void validityChanged(
+ const css::uno::Reference< css::awt::XControl >& _rxControl,
+ const css::uno::Reference< css::form::validation::XValidatableFormComponent >& _rxValidatable
+ );
+
+ /// enables dynamic border color for the controls
+ void enableDynamicBorderColor( );
+ /// disables dynamic border color for the controls
+ void disableDynamicBorderColor( );
+
+ /** sets a color to be used for a given status
+ @param _nStatus
+ the status which the color should be applied for. Must not be ControlStatus::NONE
+ @param _nColor
+ the color to apply for the given status
+ */
+ void setStatusColor( ControlStatus _nStatus, Color _nColor );
+
+ /** restores all colors of all controls where we possibly changed them
+ */
+ void restoreAll();
+
+ private:
+ /** called when a control got one of the two possible statuses (focused, and hovered with the mouse)
+ @param _rxControl
+ the control which gained the status
+ @param _rControlData
+ the control's status data, as a reference to our respective member
+ */
+ void controlStatusGained(
+ const css::uno::Reference< css::uno::XInterface >& _rxControl,
+ ControlData& _rControlData
+ );
+
+ /** called when a control lost one of the two possible statuses (focused, and hovered with the mouse)
+ @param _rxControl
+ the control which lost the status
+ @param _rControlData
+ the control's status data, as a reference to our respective member
+ */
+ void controlStatusLost( const css::uno::Reference< css::uno::XInterface >& _rxControl, ControlData& _rControlData );
+
+ /** determines whether the border of a given peer can be colored
+ @param _rxPeer
+ the peer to examine. Must not be <NULL/>
+ */
+ bool canColorBorder( const css::uno::Reference< css::awt::XVclWindowPeer >& _rxPeer );
+
+ /** determines the status of the given control
+ */
+ ControlStatus getControlStatus( const css::uno::Reference< css::awt::XControl >& _rxControl );
+
+ /** retrieves the color associated with a given ControlStatus
+ @param _eStatus
+ the status of the control. Must not be <member>ControlStatus::none</member>
+ */
+ Color getControlColorByStatus( ControlStatus _eStatus ) const;
+
+ /** sets the border color for a given control, depending on its status
+ @param _rxControl
+ the control to set the border color for. Must not be <NULL/>
+ @param _rxPeer
+ the peer of the control, to be passed herein for optimization the caller usually needs it, anyway).
+ Must not be <NULL/>
+ @param _rFallback
+ the color/type to use when the control has the status ControlStatus::NONE
+ */
+ void updateBorderStyle(
+ const css::uno::Reference< css::awt::XControl >& _rxControl,
+ const css::uno::Reference< css::awt::XVclWindowPeer >& _rxPeer,
+ const BorderDescriptor& _rFallback
+ );
+
+ /** determines the to-be-remembered original border color and type for a control
+
+ The method also takes into account that the control may currently have an overwritten
+ border style
+
+ @param _rxControl
+ the control to examine. Must not be <NULL/>, and have a non-<NULL/> peer
+ */
+ void determineOriginalBorderStyle(
+ const css::uno::Reference< css::awt::XControl >& _rxControl,
+ BorderDescriptor& _rData
+ ) const;
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMCONTROLBORDERMANAGER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmcontrollayout.hxx b/svx/source/inc/fmcontrollayout.hxx
new file mode 100644
index 000000000..f2494d83e
--- /dev/null
+++ b/svx/source/inc/fmcontrollayout.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FMCONTROLLAYOUT_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMCONTROLLAYOUT_HXX
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include "fmdocumentclassification.hxx"
+
+
+namespace svxform::ControlLayouter
+{
+ /** initializes the layout of a newly created form control (model)
+ */
+ void initializeControlLayout(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ DocumentType _eDocType
+ );
+
+ /** determines whether for the given document type, dynamic control border coloring is enabled
+ */
+ bool useDynamicBorderColor( DocumentType _eDocType );
+
+ /** determines whether for the given document type, form controls should use the document's reference device
+ for text rendering
+ */
+ bool useDocumentReferenceDevice( DocumentType _eDocType );
+
+ /** gets the "default" style in a document which can be used if some default text format is needed
+
+ It depends on the type document type which concrete kind of style is returned, but it is expected to support
+ the css.style.CharacterProperties service.
+
+ @param _rxModel
+ a form component.
+ */
+ css::uno::Reference< css::beans::XPropertySet >
+ getDefaultDocumentTextStyle( const css::uno::Reference< css::beans::XPropertySet >& _rxModel );
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMCONTROLLAYOUT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmdocumentclassification.hxx b/svx/source/inc/fmdocumentclassification.hxx
new file mode 100644
index 000000000..e50523348
--- /dev/null
+++ b/svx/source/inc/fmdocumentclassification.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FMDOCUMENTCLASSIFICATION_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMDOCUMENTCLASSIFICATION_HXX
+
+#include <com/sun/star/frame/XModel.hpp>
+
+
+namespace svxform
+{
+
+ enum DocumentType
+ {
+ eTextDocument,
+ eWebDocument,
+ eSpreadsheetDocument,
+ eDrawingDocument,
+ ePresentationDocument,
+ eEnhancedForm,
+ eDatabaseForm,
+ eDatabaseReport,
+
+ eUnknownDocumentType
+ };
+
+ class DocumentClassification
+ {
+ public:
+ /** classifies a document model
+ */
+ static DocumentType classifyDocument(
+ const css::uno::Reference< css::frame::XModel >& _rxDocumentModel
+ );
+
+ static DocumentType classifyHostDocument(
+ const css::uno::Reference< css::uno::XInterface >& _rxFormComponent
+ );
+
+ static DocumentType getDocumentTypeForModuleIdentifier(
+ std::u16string_view _rModuleIdentifier
+ );
+
+ static OUString getModuleIdentifierForDocumentType(
+ DocumentType _eType
+ );
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMDOCUMENTCLASSIFICATION_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmexch.hxx b/svx/source/inc/fmexch.hxx
new file mode 100644
index 000000000..b8878e76d
--- /dev/null
+++ b/svx/source/inc/fmexch.hxx
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FMEXCH_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMEXCH_HXX
+
+#include <config_options.h>
+#include <sal/config.h>
+
+#include <set>
+
+#include <sot/exchange.hxx>
+#include <vcl/transfer.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/form/XForms.hpp>
+#include <rtl/ref.hxx>
+#include <tools/link.hxx>
+#include <vcl/weld.hxx>
+#include <svx/svxdllapi.h>
+
+namespace svxform
+{
+ typedef ::std::set<std::unique_ptr<weld::TreeIter>> ListBoxEntrySet;
+
+ //= OLocalExchange
+ class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) OLocalExchange : public TransferDataContainer
+ {
+ private:
+ Link<OLocalExchange&,void> m_aClipboardListener;
+ bool m_bDragging : 1;
+ bool m_bClipboardOwner : 1;
+
+ public:
+ class GrantAccess
+ {
+ friend class OLocalExchangeHelper;
+ };
+
+ public:
+ OLocalExchange( );
+
+ bool isDragging() const { return m_bDragging; }
+ bool isClipboardOwner() const { return m_bClipboardOwner; }
+
+ void setDragging(bool bDragging);
+ SVXCORE_DLLPRIVATE void copyToClipboard(const weld::Widget& rWidget, const GrantAccess&);
+
+ void setClipboardListener( const Link<OLocalExchange&,void>& _rListener ) { m_aClipboardListener = _rListener; }
+
+ SVXCORE_DLLPRIVATE void clear();
+
+ static bool hasFormat( const DataFlavorExVector& _rFormats, SotClipboardFormatId _nFormatId );
+
+ protected:
+ // XClipboardOwner
+ virtual void SAL_CALL lostOwnership( const css::uno::Reference< css::datatransfer::clipboard::XClipboard >& _rxClipboard, const css::uno::Reference< css::datatransfer::XTransferable >& _rxTrans ) override;
+
+ // TransferableHelper
+ virtual void DragFinished( sal_Int8 nDropAction ) override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+
+ private:
+ // don't allow this base class method to be called from outside
+ using TransferDataContainer::StartDrag;
+ };
+
+
+ //= OLocalExchangeHelper
+
+ /// a helper for navigator windows (SvTreeListBox'es) which allow DnD within themself
+ class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) OLocalExchangeHelper
+ {
+ protected:
+ rtl::Reference<OLocalExchange> m_xTransferable;
+
+ public:
+ OLocalExchangeHelper();
+ virtual ~OLocalExchangeHelper();
+
+ void prepareDrag( );
+
+ SVXCORE_DLLPRIVATE void copyToClipboard(const weld::Widget& rWidget) const;
+
+ bool isDragSource() const { return m_xTransferable.is() && m_xTransferable->isDragging(); }
+ bool isClipboardOwner() const { return m_xTransferable.is() && m_xTransferable->isClipboardOwner(); }
+ bool isDataExchangeActive( ) const { return isDragSource() || isClipboardOwner(); }
+ void clear() { if ( isDataExchangeActive() ) m_xTransferable->clear(); }
+
+ SVX_DLLPRIVATE void setClipboardListener( const Link<OLocalExchange&,void>& _rListener ) { if ( m_xTransferable.is() ) m_xTransferable->setClipboardListener( _rListener ); }
+
+ protected:
+ SVX_DLLPRIVATE virtual rtl::Reference<OLocalExchange> createExchange() const = 0;
+
+ protected:
+ SVX_DLLPRIVATE void implReset();
+ };
+
+ class OControlTransferData
+ {
+ private:
+ DataFlavorExVector m_aCurrentFormats;
+
+ protected:
+ ListBoxEntrySet m_aSelectedEntries;
+ css::uno::Sequence< css::uno::Sequence< sal_uInt32 > >
+ m_aControlPaths;
+ css::uno::Sequence< css::uno::Reference< css::uno::XInterface > >
+ m_aHiddenControlModels;
+
+ css::uno::Reference< css::form::XForms >
+ m_xFormsRoot; // the root of the forms collection where the entries we represent reside
+ // this uniquely identifies the page and the document
+
+ bool m_bFocusEntry;
+
+ protected:
+ // updates m_aCurrentFormats with all formats we currently could supply
+ void updateFormats( );
+
+ public:
+ OControlTransferData( );
+
+ // ctor to construct the data from an arbitrary Transferable (usually clipboard data)
+ OControlTransferData(
+ const css::uno::Reference< css::datatransfer::XTransferable >& _rxTransferable
+ );
+
+ inline const DataFlavorExVector& GetDataFlavorExVector() const;
+
+ void addSelectedEntry(std::unique_ptr<weld::TreeIter> xEntry);
+ void setFocusEntry(bool _bFocusEntry);
+
+ /** notifies the data transfer object that a certain entry has been removed from the owning tree
+
+ In case the removed entry is part of the transfer object's selection, the entry is removed from
+ the selection.
+
+ @param _pEntry
+ @return the number of entries remaining in the selection.
+ */
+ size_t onEntryRemoved(const weld::TreeView* pView, const weld::TreeIter* _pEntry);
+
+ void setFormsRoot(
+ const css::uno::Reference< css::form::XForms >& _rxFormsRoot
+ ) { m_xFormsRoot = _rxFormsRoot; }
+
+ void buildPathFormat(const weld::TreeView* pTreeBox, const weld::TreeIter* pRoot);
+ // assembles m_aControlPaths from m_aSelectedEntries
+ // (it is assumed that the entries are sorted in m_aSelectedEntries with respect to the neighbor relationship)
+
+
+ void buildListFromPath(const weld::TreeView* pTreeBox, const weld::TreeIter* pRoot);
+ // The reverse way: throws everything out of m_aSelectedEntries and rebuilds it using m_aControlPaths
+
+ void addHiddenControlsFormat(const css::uno::Sequence< css::uno::Reference< css::uno::XInterface > >& seqInterfaces);
+ // adds an SVX_FML_HIDDEN_CONTROLS format and remembers the passed interfaces for it
+ // (it is NOT checked whether actually only hidden controls are denominated
+ // by this - the caller must ensure that)
+
+ const ListBoxEntrySet& selected() const { return m_aSelectedEntries; }
+ const css::uno::Sequence< css::uno::Reference< css::uno::XInterface > >&
+ hiddenControls() const { return m_aHiddenControlModels; }
+
+ const css::uno::Reference< css::form::XForms >&
+ getFormsRoot() const { return m_xFormsRoot; }
+ };
+
+
+ inline const DataFlavorExVector& OControlTransferData::GetDataFlavorExVector() const
+ {
+ const_cast< OControlTransferData* >( this )->updateFormats( );
+ return m_aCurrentFormats;
+ }
+
+ class OControlExchange final : public OLocalExchange, public OControlTransferData
+ {
+ public:
+ OControlExchange( );
+
+ public:
+ static SotClipboardFormatId getFieldExchangeFormatId( );
+ static SotClipboardFormatId getControlPathFormatId( );
+ static SotClipboardFormatId getHiddenControlModelsFormatId( );
+
+ inline static bool hasFieldExchangeFormat( const DataFlavorExVector& _rFormats );
+ inline static bool hasControlPathFormat( const DataFlavorExVector& _rFormats );
+ inline static bool hasHiddenControlModelsFormat( const DataFlavorExVector& _rFormats );
+
+ private:
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ virtual void AddSupportedFormats() override;
+ };
+
+ class OControlExchangeHelper final : public OLocalExchangeHelper
+ {
+ public:
+ OControlExchangeHelper() : OLocalExchangeHelper() { }
+
+ OControlExchange* operator->() const { return static_cast< OControlExchange* >( m_xTransferable.get() ); }
+ OControlExchange& operator*() const { return *static_cast< OControlExchange* >( m_xTransferable.get() ); }
+
+ private:
+ virtual rtl::Reference<OLocalExchange> createExchange() const override;
+ };
+
+
+ inline bool OControlExchange::hasFieldExchangeFormat( const DataFlavorExVector& _rFormats )
+ {
+ return hasFormat( _rFormats, getFieldExchangeFormatId() );
+ }
+
+ inline bool OControlExchange::hasControlPathFormat( const DataFlavorExVector& _rFormats )
+ {
+ return hasFormat( _rFormats, getControlPathFormatId() );
+ }
+
+ inline bool OControlExchange::hasHiddenControlModelsFormat( const DataFlavorExVector& _rFormats )
+ {
+ return hasFormat( _rFormats, getHiddenControlModelsFormatId() );
+ }
+
+
+}
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmexpl.hxx b/svx/source/inc/fmexpl.hxx
new file mode 100644
index 000000000..fc7823b69
--- /dev/null
+++ b/svx/source/inc/fmexpl.hxx
@@ -0,0 +1,551 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FMEXPL_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMEXPL_HXX
+
+#include <config_options.h>
+#include <svl/lstner.hxx>
+#include <svl/SfxBroadcaster.hxx>
+#include <vcl/window.hxx>
+#include <sfx2/childwin.hxx>
+#include <svl/poolitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dockwin.hxx>
+#include <sfx2/ctrlitem.hxx>
+
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/beans/PropertyChangeEvent.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+
+#include <svx/fmview.hxx>
+
+#include "fmexch.hxx"
+#include <vector>
+#include <set>
+#include <cppuhelper/implbase.hxx>
+
+class SdrObjListIter;
+class FmFormShell;
+class SdrObject;
+class FmFormModel;
+class FmFormView;
+class SdrMarkList;
+
+
+class FmEntryData;
+class FmNavInsertedHint final : public SfxHint
+{
+ FmEntryData* pEntryData;
+ sal_uInt32 nPos;
+
+public:
+ FmNavInsertedHint( FmEntryData* pInsertedEntryData, sal_uInt32 nRelPos );
+ virtual ~FmNavInsertedHint() override;
+
+ FmEntryData* GetEntryData() const { return pEntryData; }
+ sal_uInt32 GetRelPos() const { return nPos; }
+};
+
+
+class FmNavModelReplacedHint final : public SfxHint
+{
+ FmEntryData* pEntryData; // the data of the entry that has got a new model
+
+public:
+ FmNavModelReplacedHint( FmEntryData* pAffectedEntryData );
+ virtual ~FmNavModelReplacedHint() override;
+
+ FmEntryData* GetEntryData() const { return pEntryData; }
+};
+
+
+class FmNavRemovedHint final : public SfxHint
+{
+ FmEntryData* pEntryData;
+
+public:
+ FmNavRemovedHint( FmEntryData* pInsertedEntryData );
+ virtual ~FmNavRemovedHint() override;
+
+ FmEntryData* GetEntryData() const { return pEntryData; }
+};
+
+
+class FmNavNameChangedHint final : public SfxHint
+{
+ FmEntryData* pEntryData;
+ OUString aNewName;
+
+public:
+ FmNavNameChangedHint( FmEntryData* pData, const OUString& rNewName );
+ virtual ~FmNavNameChangedHint() override;
+
+ FmEntryData* GetEntryData() const { return pEntryData; }
+ const OUString& GetNewName() const { return aNewName; }
+};
+
+
+class FmNavClearedHint final : public SfxHint
+{
+public:
+ FmNavClearedHint();
+ virtual ~FmNavClearedHint() override;
+};
+
+
+class FmNavViewMarksChanged final : public SfxHint
+{
+ FmFormView* pView;
+public:
+ FmNavViewMarksChanged(FmFormView* pWhichView) { pView = pWhichView; }
+
+ const FmFormView* GetAffectedView() const { return pView; }
+};
+
+
+class FmEntryDataList;
+class FmEntryData
+{
+private:
+ css::uno::Reference< css::uno::XInterface > m_xNormalizedIFace;
+ css::uno::Reference< css::beans::XPropertySet > m_xProperties;
+ css::uno::Reference< css::container::XChild > m_xChild;
+
+protected:
+ OUString m_aNormalImage;
+ OUString aText;
+
+ std::unique_ptr<FmEntryDataList>
+ pChildList;
+ FmEntryData* pParent;
+
+protected:
+ void newObject( const css::uno::Reference< css::uno::XInterface >& _rxIFace );
+
+public:
+
+ FmEntryData( FmEntryData* pParentData, const css::uno::Reference< css::uno::XInterface >& _rIFace );
+ FmEntryData( const FmEntryData& rEntryData );
+ virtual ~FmEntryData();
+
+ void SetText( const OUString& rText ){ aText = rText; }
+ void SetParent( FmEntryData* pParentData ){ pParent = pParentData; }
+
+ const OUString& GetNormalImage() const { return m_aNormalImage; }
+
+ const OUString& GetText() const { return aText; }
+ FmEntryData* GetParent() const { return pParent; }
+ FmEntryDataList* GetChildList() const { return pChildList.get(); }
+
+ virtual bool IsEqualWithoutChildren( FmEntryData* pEntryData );
+ virtual std::unique_ptr<FmEntryData> Clone() = 0;
+
+ // note that the interface returned is normalized, i.e. querying the given XInterface of the object
+ // for XInterface must return the interface itself.
+ const css::uno::Reference< css::uno::XInterface >& GetElement() const
+ {
+ return m_xNormalizedIFace;
+ }
+
+ const css::uno::Reference< css::beans::XPropertySet >& GetPropertySet() const
+ {
+ return m_xProperties;
+ }
+
+ const css::uno::Reference< css::container::XChild >& GetChildIFace() const
+ {
+ return m_xChild;
+ }
+};
+
+
+class FmEntryDataList final
+{
+private:
+ std::vector< std::unique_ptr<FmEntryData> > maEntryDataList;
+
+public:
+ FmEntryDataList();
+ ~FmEntryDataList();
+
+ FmEntryData* at( size_t Index )
+ { return maEntryDataList.at(Index).get(); }
+
+ size_t size() const { return maEntryDataList.size(); }
+ void removeNoDelete( FmEntryData* pItem );
+ void insert( std::unique_ptr<FmEntryData> pItem, size_t Index );
+ void clear();
+};
+
+
+// FmNavRequestSelectHint - someone tells the NavigatorTree to select certain entries
+
+typedef std::set<FmEntryData*> FmEntryDataArray;
+
+class FmNavRequestSelectHint final : public SfxHint
+{
+ FmEntryDataArray m_arredToSelect;
+ bool m_bMixedSelection;
+public:
+ FmNavRequestSelectHint()
+ : m_bMixedSelection(false)
+ {
+ }
+
+ void SetMixedSelection(bool bMixedSelection) { m_bMixedSelection = bMixedSelection; }
+ bool IsMixedSelection() const { return m_bMixedSelection; }
+ void AddItem(FmEntryData* pEntry) { m_arredToSelect.insert(pEntry); }
+ void ClearItems() { m_arredToSelect.clear(); }
+ FmEntryDataArray& GetItems() { return m_arredToSelect; }
+};
+
+
+class FmFormData final : public FmEntryData
+{
+ css::uno::Reference< css::form::XForm > m_xForm;
+
+public:
+ FmFormData(const css::uno::Reference< css::form::XForm >& _rxForm, FmFormData* _pParent);
+ FmFormData( const FmFormData& rFormData );
+ virtual ~FmFormData() override;
+
+ const css::uno::Reference< css::form::XForm >& GetFormIface() const { return m_xForm; }
+
+ virtual bool IsEqualWithoutChildren( FmEntryData* pEntryData ) override;
+ virtual std::unique_ptr<FmEntryData> Clone() override;
+};
+
+
+class FmControlData final : public FmEntryData
+{
+ css::uno::Reference< css::form::XFormComponent > m_xFormComponent;
+
+ OUString GetImage() const;
+
+public:
+
+ FmControlData(
+ const css::uno::Reference< css::form::XFormComponent >& _rxComponent,
+ FmFormData* _pParent
+ );
+ FmControlData( const FmControlData& rControlData );
+ virtual ~FmControlData() override;
+
+ const css::uno::Reference< css::form::XFormComponent >& GetFormComponent() const { return m_xFormComponent; }
+ virtual bool IsEqualWithoutChildren( FmEntryData* pEntryData ) override;
+ virtual std::unique_ptr<FmEntryData> Clone() override;
+
+ void ModelReplaced(const css::uno::Reference< css::form::XFormComponent >& _rxNew);
+};
+
+
+namespace svxform
+{
+
+
+ class NavigatorTreeModel;
+
+ class OFormComponentObserver final
+ :public ::cppu::WeakImplHelper < css::beans::XPropertyChangeListener
+ , css::container::XContainerListener
+ >
+ {
+ ::svxform::NavigatorTreeModel* m_pNavModel;
+ sal_uInt32 m_nLocks;
+ bool m_bCanUndo;
+
+ public:
+ OFormComponentObserver( ::svxform::NavigatorTreeModel* pModel );
+
+ // XEventListenerListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // css::beans::XPropertyChangeListener
+ virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override;
+
+ // css::container::XContainerListener
+
+ virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& rEvent) override;
+ virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& rEvent) override;
+ virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& rEvent) override;
+
+ void Lock() { m_nLocks++; }
+ void UnLock() { m_nLocks--; }
+ bool IsLocked() const { return m_nLocks != 0; }
+ bool CanUndo() const { return m_bCanUndo; }
+ void ReleaseModel() { m_pNavModel = nullptr; }
+ private:
+ void Insert(const css::uno::Reference< css::uno::XInterface >& xIface, sal_Int32 nIndex);
+ void Remove( const css::uno::Reference< css::uno::XInterface >& _rxElement );
+ };
+
+ class NavigatorTreeModel final : public SfxBroadcaster
+ ,public SfxListener
+ {
+ friend class NavigatorTree;
+ friend class OFormComponentObserver;
+
+ std::unique_ptr<FmEntryDataList>
+ m_pRootList;
+ FmFormShell* m_pFormShell;
+ FmFormPage* m_pFormPage;
+ FmFormModel* m_pFormModel;
+ rtl::Reference<OFormComponentObserver> m_pPropChangeList;
+
+ void UpdateContent( const css::uno::Reference< css::form::XForms >& xForms );
+
+ void InsertForm(const css::uno::Reference< css::form::XForm >& xForm, sal_uInt32 nRelPos);
+ void RemoveForm(FmFormData const * pFormData);
+
+ void InsertFormComponent(const css::uno::Reference< css::form::XFormComponent >& xComp, sal_uInt32 nRelPos);
+ void RemoveFormComponent(FmControlData const * pControlData);
+ void InsertSdrObj(const SdrObject* pSdrObj);
+ void RemoveSdrObj(const SdrObject* pSdrObj);
+
+ void ReplaceFormComponent(const css::uno::Reference< css::form::XFormComponent >& xOld, const css::uno::Reference< css::form::XFormComponent >& xNew);
+
+ void BroadcastMarkedObjects(const SdrMarkList& mlMarked);
+ // send a RequestSelectHint with the currently selected objects
+ bool InsertFormComponent(FmNavRequestSelectHint& rHint, SdrObject* pObject);
+ // is a helper for previous, manages the ... in SdrObjGroups;
+ // returns sal_True if the object is a FormComponent (or recursively consists only of such)
+
+ public:
+ NavigatorTreeModel();
+ virtual ~NavigatorTreeModel() override;
+
+ void FillBranch( FmFormData* pParentData );
+ void UpdateContent( FmFormShell* pNewShell );
+
+ void Insert(FmEntryData* pEntryData, sal_uInt32 nRelPos = SAL_MAX_UINT32,
+ bool bAlterModel = false);
+ void Remove(FmEntryData* pEntryData, bool bAlterModel = false);
+
+ static bool Rename( FmEntryData* pEntryData, const OUString& rNewText );
+
+ void Clear();
+ void SetModified();
+
+ css::uno::Reference< css::form::XForms > GetForms() const;
+ FmFormShell* GetFormShell() const { return m_pFormShell; }
+ FmFormPage* GetFormPage() const { return m_pFormPage; }
+ FmEntryData* FindData( const css::uno::Reference< css::uno::XInterface >& xElement, FmEntryDataList* pDataList, bool bRecurs=true );
+ FmEntryData* FindData( const OUString& rText, FmFormData const * pParentData, bool bRecurs );
+ FmEntryDataList* GetRootList() const { return m_pRootList.get(); }
+ static css::uno::Reference< css::container::XIndexContainer > GetFormComponents( FmFormData const * pParentFormData );
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+ };
+
+ class NavigatorTree;
+
+ class NavigatorTreeDropTarget final : public DropTargetHelper
+ {
+ private:
+ NavigatorTree& m_rTreeView;
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+ public:
+ NavigatorTreeDropTarget(NavigatorTree& rTreeView);
+ };
+
+ typedef std::set<std::unique_ptr<weld::TreeIter>> SvLBoxEntrySortedArray;
+
+ class NavigatorTree final : public SfxListener
+ {
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+ NavigatorTreeDropTarget m_aDropTargetHelper;
+
+ enum SELDATA_ITEMS { SDI_DIRTY, SDI_ALL, SDI_NORMALIZED, SDI_NORMALIZED_FORMARK };
+
+ Timer m_aSynchronizeTimer;
+ // the meta-data about my current selection
+ SvLBoxEntrySortedArray m_arrCurrentSelection;
+ // the entries which, in the view, are currently marked as "cut" (painted semi-transparent)
+ ListBoxEntrySet m_aCutEntries;
+
+ ::svxform::OControlExchangeHelper m_aControlExchange;
+
+ std::unique_ptr<NavigatorTreeModel> m_pNavModel;
+ std::unique_ptr<weld::TreeIter> m_xRootEntry;
+ std::unique_ptr<weld::TreeIter> m_xEditEntry;
+
+ ImplSVEvent * nEditEvent;
+
+ SELDATA_ITEMS m_sdiState;
+
+ sal_uInt16 m_nSelectLock;
+ sal_uInt16 m_nFormsSelected;
+ sal_uInt16 m_nControlsSelected;
+ sal_uInt16 m_nHiddenControls; // (the number is included in m_nControlsSelected)
+
+ bool m_bDragDataDirty : 1; // ditto
+ bool m_bPrevSelectionMixed : 1;
+ bool m_bRootSelected : 1;
+ bool m_bInitialUpdate : 1; // am I the first time in the UpdateContent?
+ bool m_bKeyboardCut : 1;
+ bool m_bEditing : 1;
+
+ FmControlData* NewControl(const OUString& rServiceName, const weld::TreeIter& rParentEntry, bool bEditName);
+ void NewForm(const weld::TreeIter& rParentEntry);
+ std::unique_ptr<weld::TreeIter> Insert(const FmEntryData* pEntryData, int nRelPos);
+ void Remove( FmEntryData* pEntryData );
+
+
+ void CollectSelectionData(SELDATA_ITEMS sdiHow);
+ // Collects the currently selected entries in m_arrCurrentSelection, normalizes the list if requested.
+ // - SDI_NORMALIZED simply means that all entries that already have a selected ancestor are not collected.
+ // - SDI_NORMALIZED_FORMARK means that the procedure is the same as for SDI_NORMALIZED,
+ // but entries whose direct parent is not selected are collected (independent of the
+ // status of further ancestors). The same applies for forms that are selected,
+ // regardless of the status of any ancestors.
+ // For both normalized modes, the m_nFormsSelected, ... contain the correct number,
+ // even if not all of these entries end up in m_arrCurrentSelection.
+ // SDI_DIRTY is of course not allowed as a parameter.
+
+ // a single interface for all selected entries
+ void ShowSelectionProperties(bool bForce = false);
+ // delete all selected elements
+ void DeleteSelection();
+
+ void SynchronizeSelection(FmEntryDataArray& arredToSelect);
+ // after calling this method, exactly the entries marked in the array are selected
+ void SynchronizeSelection();
+ // makes the same, takes the MarkList of the View
+ void SynchronizeMarkList();
+ // reverse direction of SynchronizeMarkList: selects in the view all controls corresponding to the current selection
+
+ void CollectObjects(FmFormData const * pFormData, bool bDeep, ::std::set< css::uno::Reference< css::form::XFormComponent > >& _rObjects);
+
+ // in the Select I usually update the Marklist of the corresponding view,
+ // with the following functions I can control the locking of this behavior
+ void LockSelectionHandling() { ++m_nSelectLock; }
+ void UnlockSelectionHandling() { --m_nSelectLock; }
+ bool IsSelectionHandlingLocked() const { return m_nSelectLock>0; }
+
+ bool IsEditingActive() const { return m_bEditing; }
+
+ static bool IsHiddenControl(FmEntryData const * pEntryData);
+
+ DECL_LINK( KeyInputHdl, const KeyEvent&, bool );
+ DECL_LINK( PopupMenuHdl, const CommandEvent&, bool );
+
+ DECL_LINK(EditingEntryHdl, const weld::TreeIter&, bool);
+ typedef std::pair<const weld::TreeIter&, OUString> IterString;
+ DECL_LINK(EditedEntryHdl, const IterString&, bool);
+
+ DECL_LINK( OnEdit, void*, void );
+
+ DECL_LINK( OnEntrySelDesel, weld::TreeView&, void );
+ DECL_LINK( OnSynchronizeTimer, Timer*, void );
+
+ DECL_LINK( OnClipboardAction, OLocalExchange&, void );
+
+ DECL_LINK( DragBeginHdl, bool&, bool );
+
+ public:
+ NavigatorTree(std::unique_ptr<weld::TreeView> xTreeView);
+ virtual ~NavigatorTree() override;
+
+ void Clear();
+ void UpdateContent( FmFormShell* pFormShell );
+ void MarkViewObj( FmFormData const * pFormData, bool bDeep );
+ void MarkViewObj( FmControlData const * pControlData );
+ void UnmarkAllViewObj();
+
+ void GrabFocus() { m_xTreeView->grab_focus(); }
+
+ bool IsFormEntry(const weld::TreeIter& rEntry);
+ bool IsFormComponentEntry(const weld::TreeIter& rEntry);
+
+ OUString GenerateName( FmEntryData const * pEntryData );
+
+ NavigatorTreeModel* GetNavModel() const { return m_pNavModel.get(); }
+ std::unique_ptr<weld::TreeIter> FindEntry(FmEntryData* pEntryData);
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ weld::TreeView& get_widget() { return *m_xTreeView; }
+
+ sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt);
+ sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt);
+
+ private:
+ sal_Int8 implAcceptDataTransfer( const DataFlavorExVector& _rFlavors, sal_Int8 _nAction, const weld::TreeIter* _pTargetEntry, bool _bDnD );
+
+ sal_Int8 implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, const Point& _rDropPos, bool _bDnD );
+ sal_Int8 implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, const weld::TreeIter* _pTargetEntry, bool _bDnD );
+
+ // check if a cut, copy, or drag operation can be started in the current situation
+ bool implAllowExchange( sal_Int8 _nAction, bool* _pHasNonHidden = nullptr );
+ // check if a paste with the current clipboard content can be accepted
+ bool implAcceptPaste( );
+
+ // fills m_aControlExchange in preparation of a DnD or clipboard operation
+ bool implPrepareExchange( sal_Int8 _nAction );
+
+ void ModelHasRemoved(const weld::TreeIter* _pEntry);
+
+ void doPaste();
+ void doCopy();
+ void doCut();
+
+ bool doingKeyboardCut( ) const { return m_bKeyboardCut; }
+ };
+
+ class NavigatorFrame final : public SfxDockingWindow, public SfxControllerItem
+ {
+ private:
+ std::unique_ptr<NavigatorTree> m_xNavigatorTree;
+
+ virtual bool Close() override;
+ virtual void GetFocus() override;
+ virtual Size CalcDockingSize( SfxChildAlignment ) override;
+ virtual SfxChildAlignment CheckAlignment( SfxChildAlignment, SfxChildAlignment ) override;
+
+ using SfxDockingWindow::StateChanged;
+
+ public:
+ NavigatorFrame( SfxBindings *pBindings, SfxChildWindow *pMgr,
+ vcl::Window* pParent );
+ virtual ~NavigatorFrame() override;
+ virtual void dispose() override;
+
+ void UpdateContent( FmFormShell* pFormShell );
+ void StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) override;
+ void FillInfo( SfxChildWinInfo& rInfo ) const override;
+ };
+
+ class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) NavigatorFrameManager final : public SfxChildWindow
+ {
+ public:
+ SVX_DLLPRIVATE NavigatorFrameManager( vcl::Window *pParent, sal_uInt16 nId, SfxBindings *pBindings,
+ SfxChildWinInfo *pInfo );
+ SFX_DECL_CHILDWINDOW( NavigatorFrameManager );
+ };
+}
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMEXPL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmobj.hxx b/svx/source/inc/fmobj.hxx
new file mode 100644
index 000000000..d604cfd20
--- /dev/null
+++ b/svx/source/inc/fmobj.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FMOBJ_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMOBJ_HXX
+
+#include <config_options.h>
+#include <svx/svdouno.hxx>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/form/XForms.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+
+
+// FmFormObj
+
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) FmFormObj final : public SdrUnoObj
+{
+ FmFormObj( const FmFormObj& ) = delete;
+
+ css::uno::Sequence< css::script::ScriptEventDescriptor > aEvts; // events of the object
+ css::uno::Sequence< css::script::ScriptEventDescriptor> m_aEventsHistory;
+ // valid if and only if m_pEnvironmentHistory != NULL, this are the events which we're set when
+ // m_pEnvironmentHistory was created
+
+ // information for the control environment is only maintained if an object is not in an
+ // object list
+ css::uno::Reference< css::container::XIndexContainer> m_xParent;
+ css::uno::Reference< css::form::XForms > m_xEnvironmentHistory;
+ sal_Int32 m_nPos;
+
+ VclPtr<OutputDevice> m_pLastKnownRefDevice;
+ // the last ref device we know, as set at the model
+ // only to be used for comparison with the current ref device!
+
+ // protected destructor
+ SAL_DLLPRIVATE virtual ~FmFormObj() override;
+
+public:
+ FmFormObj(
+ SdrModel& rSdrModel,
+ const OUString& rModelName);
+ FmFormObj(SdrModel& rSdrModel);
+ // Copy constructor
+ FmFormObj(SdrModel& rSdrModel, FmFormObj const & rSource);
+
+ SAL_DLLPRIVATE const css::uno::Reference< css::container::XIndexContainer>&
+ GetOriginalParent() const { return m_xParent; }
+ SAL_DLLPRIVATE const css::uno::Sequence< css::script::ScriptEventDescriptor >&
+ GetOriginalEvents() const { return aEvts; }
+ SAL_DLLPRIVATE sal_Int32
+ GetOriginalIndex() const { return m_nPos; }
+
+ SAL_DLLPRIVATE void SetObjEnv(
+ const css::uno::Reference< css::container::XIndexContainer>& xForm,
+ const sal_Int32 nIdx,
+ const css::uno::Sequence< css::script::ScriptEventDescriptor >& rEvts );
+ SAL_DLLPRIVATE void ClearObjEnv();
+
+public:
+ // react on page change
+ virtual void handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage) override;
+
+ SAL_DLLPRIVATE virtual SdrInventor GetObjInventor() const override;
+ SAL_DLLPRIVATE virtual SdrObjKind GetObjIdentifier() const override;
+ SAL_DLLPRIVATE virtual void NbcReformatText() override;
+
+ SAL_DLLPRIVATE virtual FmFormObj* CloneSdrObject(SdrModel& rTargetModel) const override;
+
+ SAL_DLLPRIVATE static css::uno::Reference< css::uno::XInterface> ensureModelEnv(
+ const css::uno::Reference< css::uno::XInterface>& _rSourceContainer,
+ const css::uno::Reference< css::form::XForms>& _rTopLevelDestContainer);
+
+ /** returns the FmFormObj behind the given SdrObject
+
+ In case the SdrObject *is* a FmFormObject, this is a simple cast. In case the SdrObject
+ is a virtual object whose referenced object is a FmFormObj, then this referenced
+ object is returned. In all other cases, NULL is returned.
+ */
+ SAL_DLLPRIVATE static FmFormObj* GetFormObject( SdrObject* _pSdrObject );
+ SAL_DLLPRIVATE static const FmFormObj* GetFormObject( const SdrObject* _pSdrObject );
+
+ SAL_DLLPRIVATE virtual void SetUnoControlModel( const css::uno::Reference< css::awt::XControlModel >& _rxModel ) override;
+
+private:
+ SAL_DLLPRIVATE virtual bool EndCreate( SdrDragStat& rStat, SdrCreateCmd eCmd ) override;
+ SAL_DLLPRIVATE virtual void BrkCreate( SdrDragStat& rStat ) override;
+
+ /** isolates the control model from its form component hierarchy, i.e. removes it from
+ its parent.
+ */
+ SAL_DLLPRIVATE void impl_isolateControlModel_nothrow();
+
+ /** forwards the reference device of our SdrModel to the control model
+ */
+ SAL_DLLPRIVATE void impl_checkRefDevice_nothrow( bool _force = false );
+};
+
+
+#endif // _FM_FMOBJ_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmpgeimp.hxx b/svx/source/inc/fmpgeimp.hxx
new file mode 100644
index 000000000..1e2b63207
--- /dev/null
+++ b/svx/source/inc/fmpgeimp.hxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FMPGEIMP_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMPGEIMP_HXX
+
+#include <config_options.h>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/XForms.hpp>
+#include <com/sun/star/container/XMap.hpp>
+
+#include <tools/link.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <svx/svxdllapi.h>
+
+class FmFormObj;
+class FmFormPage;
+class SdrObject;
+
+
+// FmFormPageImpl
+// Listens to all containers to determine when objects have been inserted
+// and when they have been removed
+
+
+class FmFormPageImpl final
+{
+ css::uno::Reference< css::form::XForm > xCurrentForm;
+ css::uno::Reference< css::form::XForms > m_xForms;
+ css::uno::WeakReference< css::container::XMap > m_aControlShapeMap;
+
+ FmFormPage& m_rPage;
+ Link<FmFormPageImpl&,void> m_aFormsCreationHdl;
+
+ bool m_bFirstActivation;
+ bool m_bAttemptedFormCreation;
+
+public:
+ explicit FmFormPageImpl( FmFormPage& _rPage );
+ ~FmFormPageImpl();
+
+ void initFrom( FmFormPageImpl& i_foreignImpl );
+
+ // only important for the DesignMode
+ void setCurForm(const css::uno::Reference< css::form::XForm>& xForm);
+ css::uno::Reference< css::form::XForm> getDefaultForm();
+
+ /** finds a place in the form component hierarchy where to insert the given component
+
+ Note that no actual insertion happens, this is the responsibility of the caller (as
+ the caller might decide on a suitable place where in the returned container the insertion
+ should happen).
+ */
+ css::uno::Reference< css::form::XForm> findPlaceInFormComponentHierarchy(
+ const css::uno::Reference< css::form::XFormComponent>& rContent,
+ const css::uno::Reference< css::sdbc::XDataSource>& rDatabase = css::uno::Reference< css::sdbc::XDataSource>(),
+ const OUString& rDBTitle = OUString(),
+ const OUString& rCursorSource = OUString(),
+ sal_Int32 nCommandType = 0
+ );
+
+ // activation handling
+ bool hasEverBeenActivated( ) const { return !m_bFirstActivation; }
+ void setHasBeenActivated( ) { m_bFirstActivation = false; }
+
+ const css::uno::Reference< css::form::XForms>& getForms( bool _bForceCreate = true );
+
+ void SetFormsCreationHdl( const Link<FmFormPageImpl&,void>& _rFormsCreationHdl ) { m_aFormsCreationHdl = _rFormsCreationHdl; }
+
+private:
+ /** finds a form with a given data source signature
+ @param rForm
+ the form to start the search with. This form, including all possible sub forms,
+ will be examined
+ @param rDatabase
+ the data source which to which the found form must be bound
+ @param rCommand
+ the desired Command property value of the sought-after form
+ @param nCommandType
+ the desired CommandType property value of the sought-after form
+ */
+ css::uno::Reference< css::form::XForm> findFormForDataSource(
+ const css::uno::Reference< css::form::XForm>& rForm,
+ const css::uno::Reference< css::sdbc::XDataSource>& rDatabase,
+ const OUString& rCommand,
+ sal_Int32 nCommandType
+ );
+
+public:
+ static OUString setUniqueName(const css::uno::Reference< css::form::XFormComponent>& xFormComponent, const css::uno::Reference< css::form::XForm>& xControls);
+
+ void formObjectInserted( const FmFormObj& _object );
+ void formObjectRemoved( const FmFormObj& _object );
+ void formModelAssigned( const FmFormObj& _object );
+
+ /** returns an object mapping from control models to drawing shapes.
+ */
+ UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) css::uno::Reference< css::container::XMap > getControlToShapeMap();
+
+private:
+ /** validates whether <member>xCurrentForm</member> is still valid and to be used
+
+ There are situations where our current form becomes invalid, without us noticing this. Thus,
+ every method which accesses <member>xCurrentForm</member> should beforehand validate the current
+ form by calling this method.
+
+ If <member>xCurrentForm</member> is not valid anymore, it is reset to <NULL/>.
+
+ @return
+ <TRUE/> if and only if xCurrentForm is valid.
+
+ @since #i40086#
+ */
+ bool validateCurForm();
+
+ css::uno::Reference< css::container::XMap >
+ impl_createControlShapeMap_nothrow();
+
+ FmFormPageImpl( const FmFormPageImpl& ) = delete;
+ FmFormPageImpl& operator=( const FmFormPageImpl& ) = delete;
+};
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMPGEIMP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmprop.hxx b/svx/source/inc/fmprop.hxx
new file mode 100644
index 000000000..a6125f2ff
--- /dev/null
+++ b/svx/source/inc/fmprop.hxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FMPROP_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMPROP_HXX
+
+#include <rtl/ustring.hxx>
+
+// PropertyIds, which have an assignment to a PropertyName, could continue
+// to be WhichIds in the future -> Itemset
+#define FM_ATTR_START 0
+
+#define FM_ATTR_FILTER ( FM_ATTR_START + 1 )
+#define FM_ATTR_FORM_OPERATIONS ( FM_ATTR_START + 2 )
+
+inline constexpr OUStringLiteral FM_PROP_NAME = u"Name";
+inline constexpr OUStringLiteral FM_PROP_CLASSID = u"ClassId";
+inline constexpr OUStringLiteral FM_PROP_ALIGN = u"Align";
+inline constexpr OUStringLiteral FM_PROP_ROWCOUNT = u"RowCount";
+inline constexpr OUStringLiteral FM_PROP_ROWCOUNTFINAL = u"IsRowCountFinal";
+inline constexpr OUStringLiteral FM_PROP_FETCHSIZE = u"FetchSize";
+inline constexpr OUStringLiteral FM_PROP_VALUE = u"Value";
+inline constexpr OUStringLiteral FM_PROP_VALUEMIN = u"ValueMin";
+inline constexpr OUStringLiteral FM_PROP_VALUEMAX = u"ValueMax";
+inline constexpr OUStringLiteral FM_PROP_VALUESTEP = u"ValueStep";
+inline constexpr OUStringLiteral FM_PROP_TEXT = u"Text";
+inline constexpr OUStringLiteral FM_PROP_LABEL = u"Label";
+inline constexpr OUStringLiteral FM_PROP_NAVIGATION = u"NavigationBarMode";
+inline constexpr OUStringLiteral FM_PROP_CYCLE = u"Cycle";
+inline constexpr OUStringLiteral FM_PROP_CONTROLSOURCE = u"DataField";
+inline constexpr OUStringLiteral FM_PROP_ENABLED = u"Enabled";
+inline constexpr OUStringLiteral FM_PROP_SPIN = u"Spin";
+inline constexpr OUStringLiteral FM_PROP_READONLY = u"ReadOnly";
+inline constexpr OUStringLiteral FM_PROP_FILTER = u"Filter";
+inline constexpr OUStringLiteral FM_PROP_AUTOINCREMENT = u"IsAutoIncrement";
+inline constexpr OUStringLiteral FM_PROP_WIDTH = u"Width";
+inline constexpr OUStringLiteral FM_PROP_SEARCHABLE = u"IsSearchable";
+inline constexpr OUStringLiteral FM_PROP_MULTILINE = u"MultiLine";
+inline constexpr OUStringLiteral FM_PROP_TARGET_URL = u"TargetURL";
+inline constexpr OUStringLiteral FM_PROP_DEFAULTCONTROL = u"DefaultControl";
+inline constexpr OUStringLiteral FM_PROP_MAXTEXTLEN = u"MaxTextLen";
+inline constexpr OUStringLiteral FM_PROP_DATE = u"Date";
+inline constexpr OUStringLiteral FM_PROP_TIME = u"Time";
+inline constexpr OUStringLiteral FM_PROP_STATE = u"State";
+inline constexpr OUStringLiteral FM_PROP_TRISTATE = u"TriState";
+inline constexpr OUStringLiteral FM_PROP_STRINGITEMLIST = u"StringItemList";
+inline constexpr OUStringLiteral FM_PROP_DEFAULT_TEXT = u"DefaultText";
+inline constexpr OUStringLiteral FM_PROP_DEFAULTCHECKED = u"DefaultState";
+inline constexpr OUStringLiteral FM_PROP_DEFAULT_DATE = u"DefaultDate";
+inline constexpr OUStringLiteral FM_PROP_DEFAULT_TIME = u"DefaultTime";
+inline constexpr OUStringLiteral FM_PROP_DEFAULT_VALUE = u"DefaultValue";
+inline constexpr OUStringLiteral FM_PROP_FORMATKEY = u"FormatKey";
+inline constexpr OUStringLiteral FM_PROP_FORMATSSUPPLIER = u"FormatsSupplier";
+inline constexpr OUStringLiteral FM_PROP_LISTSOURCETYPE = u"ListSourceType";
+inline constexpr OUStringLiteral FM_PROP_LISTSOURCE = u"ListSource";
+inline constexpr OUStringLiteral FM_PROP_SELECT_SEQ = u"SelectedItems";
+inline constexpr OUStringLiteral FM_PROP_VALUE_SEQ = u"ValueItemList";
+inline constexpr OUStringLiteral FM_PROP_DEFAULT_SELECT_SEQ = u"DefaultSelection";
+inline constexpr OUStringLiteral FM_PROP_DECIMAL_ACCURACY = u"DecimalAccuracy";
+inline constexpr OUStringLiteral FM_PROP_EDITMASK = u"EditMask";
+inline constexpr OUStringLiteral FM_PROP_ISREADONLY = u"IsReadOnly";
+inline constexpr OUStringLiteral FM_PROP_FIELDTYPE = u"Type";
+inline constexpr OUStringLiteral FM_PROP_REFVALUE = u"RefValue";
+inline constexpr OUStringLiteral FM_PROP_STRICTFORMAT = u"StrictFormat";
+inline constexpr OUStringLiteral FM_PROP_DATASOURCE = u"DataSourceName";
+inline constexpr OUStringLiteral FM_PROP_LITERALMASK = u"LiteralMask";
+inline constexpr OUStringLiteral FM_PROP_SHOWTHOUSANDSEP = u"ShowThousandsSeparator";
+inline constexpr OUStringLiteral FM_PROP_CURRENCYSYMBOL = u"CurrencySymbol";
+inline constexpr OUStringLiteral FM_PROP_DATEFORMAT = u"DateFormat";
+inline constexpr OUStringLiteral FM_PROP_DATEMIN = u"DateMin";
+inline constexpr OUStringLiteral FM_PROP_DATEMAX = u"DateMax";
+inline constexpr OUStringLiteral FM_PROP_DATE_SHOW_CENTURY = u"DateShowCentury";
+inline constexpr OUStringLiteral FM_PROP_TIMEFORMAT = u"TimeFormat";
+inline constexpr OUStringLiteral FM_PROP_TIMEMIN = u"TimeMin";
+inline constexpr OUStringLiteral FM_PROP_TIMEMAX = u"TimeMax";
+inline constexpr OUStringLiteral FM_PROP_LINECOUNT = u"LineCount";
+inline constexpr OUStringLiteral FM_PROP_BOUNDCOLUMN = u"BoundColumn";
+#define FM_PROP_HASNAVIGATION "HasNavigationBar"
+inline constexpr OUStringLiteral FM_PROP_FONT = u"FontDescriptor";
+#define FM_PROP_BACKGROUNDCOLOR "BackgroundColor"
+#define FM_PROP_TEXTCOLOR "TextColor"
+inline constexpr OUStringLiteral FM_PROP_BORDER = u"Border";
+inline constexpr OUStringLiteral FM_PROP_DROPDOWN = u"Dropdown";
+inline constexpr OUStringLiteral FM_PROP_ROWHEIGHT = u"RowHeight";
+inline constexpr OUStringLiteral FM_PROP_HELPTEXT = u"HelpText";
+#define FM_PROP_HELPURL "HelpURL"
+#define FM_PROP_RECORDMARKER "HasRecordMarker"
+inline constexpr OUStringLiteral FM_PROP_BOUNDFIELD = u"BoundField";
+inline constexpr OUStringLiteral FM_PROP_EFFECTIVE_VALUE = u"EffectiveValue";
+inline constexpr OUStringLiteral FM_PROP_EFFECTIVE_DEFAULT = u"EffectiveDefault";
+inline constexpr OUStringLiteral FM_PROP_EFFECTIVE_MIN = u"EffectiveMin";
+inline constexpr OUStringLiteral FM_PROP_EFFECTIVE_MAX = u"EffectiveMax";
+inline constexpr OUStringLiteral FM_PROP_HIDDEN = u"Hidden";
+inline constexpr OUStringLiteral FM_PROP_FILTERPROPOSAL = u"UseFilterValueProposal";
+inline constexpr OUStringLiteral FM_PROP_FIELDSOURCE = u"FieldSource";
+inline constexpr OUStringLiteral FM_PROP_TABLENAME = u"TableName";
+inline constexpr OUStringLiteral FM_PROP_CONTROLLABEL = u"LabelControl";
+inline constexpr OUStringLiteral FM_PROP_CURSORCOLOR = u"CursorColor";
+inline constexpr OUStringLiteral FM_PROP_ALWAYSSHOWCURSOR = u"AlwaysShowCursor";
+inline constexpr OUStringLiteral FM_PROP_DISPLAYSYNCHRON = u"DisplayIsSynchron";
+inline constexpr OUStringLiteral FM_PROP_ISMODIFIED = u"IsModified";
+inline constexpr OUStringLiteral FM_PROP_ISNEW = u"IsNew";
+inline constexpr OUStringLiteral FM_PROP_PRIVILEGES = u"Privileges";
+inline constexpr OUStringLiteral FM_PROP_COMMAND = u"Command";
+inline constexpr OUStringLiteral FM_PROP_COMMANDTYPE = u"CommandType";
+inline constexpr OUStringLiteral FM_PROP_RESULTSET_CONCURRENCY = u"ResultSetConcurrency";
+inline constexpr OUStringLiteral FM_PROP_INSERTONLY = u"IgnoreResult";
+inline constexpr OUStringLiteral FM_PROP_RESULTSET_TYPE = u"ResultSetType";
+inline constexpr OUStringLiteral FM_PROP_ESCAPE_PROCESSING = u"EscapeProcessing";
+inline constexpr OUStringLiteral FM_PROP_APPLYFILTER = u"ApplyFilter";
+inline constexpr OUStringLiteral FM_PROP_ISNULLABLE = u"IsNullable";
+inline constexpr OUStringLiteral FM_PROP_ACTIVECOMMAND = u"ActiveCommand";
+inline constexpr OUStringLiteral FM_PROP_ISCURRENCY = u"IsCurrency";
+inline constexpr OUStringLiteral FM_PROP_URL = u"URL";
+inline constexpr OUStringLiteral FM_PROP_ACTIVE_CONNECTION = u"ActiveConnection";
+inline constexpr OUStringLiteral FM_PROP_CONTROLSOURCEPROPERTY = u"DataFieldProperty";
+inline constexpr OUStringLiteral FM_PROP_REALNAME = u"RealName";
+inline constexpr OUStringLiteral FM_PROP_TEXTLINECOLOR = u"TextLineColor";
+#define FM_PROP_FONTEMPHASISMARK "FontEmphasisMark"
+#define FM_PROP_FONTRELIEF "FontRelief"
+inline constexpr OUStringLiteral FM_PROP_ORIENTATION = u"Orientation";
+inline constexpr OUStringLiteral FM_PROP_LINEENDFORMAT = u"LineEndFormat";
+inline constexpr OUStringLiteral FM_PROP_VISUALEFFECT = u"VisualEffect";
+inline constexpr OUStringLiteral FM_PROP_BORDERCOLOR = u"BorderColor";
+inline constexpr OUStringLiteral FM_PROP_DYNAMIC_CONTROL_BORDER = u"DynamicControlBorder";
+inline constexpr OUStringLiteral FM_PROP_CONTROL_BORDER_COLOR_FOCUS = u"ControlBorderColorOnFocus";
+inline constexpr OUStringLiteral FM_PROP_CONTROL_BORDER_COLOR_MOUSE = u"ControlBorderColorOnHover";
+inline constexpr OUStringLiteral FM_PROP_CONTROL_BORDER_COLOR_INVALID = u"ControlBorderColorOnInvalid";
+inline constexpr OUStringLiteral FM_PROP_BUTTON_TYPE = u"ButtonType";
+inline constexpr OUStringLiteral FM_PROP_FORM_OPERATIONS = u"FormOperations";
+inline constexpr OUStringLiteral FM_PROP_INPUT_REQUIRED = u"InputRequired";
+inline constexpr OUStringLiteral FM_PROP_WRITING_MODE = u"WritingMode";
+inline constexpr OUStringLiteral FM_PROP_MOUSE_WHEEL_BEHAVIOR = u"MouseWheelBehavior";
+inline constexpr OUStringLiteral FM_PROP_DESCRIPTION = u"Description";
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmscriptingenv.hxx b/svx/source/inc/fmscriptingenv.hxx
new file mode 100644
index 000000000..18d8a5e44
--- /dev/null
+++ b/svx/source/inc/fmscriptingenv.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FMSCRIPTINGENV_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMSCRIPTINGENV_HXX
+
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <rtl/ref.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+class FmFormModel;
+
+namespace svxform
+{
+ class FormScriptListener;
+
+ //= IFormScriptingEnvironment
+
+ /** describes the interface implemented by a component which handles scripting requirements
+ in a form/control environment.
+ */
+ class FormScriptingEnvironment final : public ::salhelper::SimpleReferenceObject
+ {
+ friend class FormScriptListener;
+ public:
+ explicit FormScriptingEnvironment( FmFormModel& _rModel );
+ FormScriptingEnvironment(const FormScriptingEnvironment&) = delete;
+ FormScriptingEnvironment& operator=(const FormScriptingEnvironment&) = delete;
+
+ /** registers an XEventAttacherManager whose events should be monitored and handled
+
+ @param _rxManager
+ the XEventAttacherManager to monitor. Must not be <NULL/>.
+
+ @throws css::lang::IllegalArgumentException
+ if <arg>_rxManager</arg> is <NULL/>
+ @throws css::lang::DisposedException
+ if the instance is already disposed
+ @throws css::uno::RuntimeException
+ if attaching as script listener to the manager fails with a RuntimeException itself
+ */
+ void registerEventAttacherManager(
+ const css::uno::Reference< css::script::XEventAttacherManager >& _rxManager );
+
+ /** registers an XEventAttacherManager whose events should not be monitored and handled anymore
+
+ @param _rxManager
+ the XEventAttacherManager which was previously registered. Must not ne <NULL/>.
+
+ @throws css::lang::IllegalArgumentException
+ if <arg>_rxManager</arg> is <NULL/>
+ @throws css::lang::DisposedException
+ if the instance is already disposed
+ @throws css::uno::RuntimeException
+ if removing as script listener from the manager fails with a RuntimeException itself
+ */
+ void revokeEventAttacherManager(
+ const css::uno::Reference< css::script::XEventAttacherManager >& _rxManager );
+
+ /** disposes the scripting environment instance
+ */
+ void dispose();
+
+ private:
+ ::osl::Mutex m_aMutex;
+ rtl::Reference<FormScriptListener> m_pScriptListener;
+ FmFormModel& m_rFormModel;
+ bool m_bDisposed;
+
+ void impl_registerOrRevoke_throw( const css::uno::Reference< css::script::XEventAttacherManager >& _rxManager, bool _bRegister );
+ // callback for FormScriptListener
+ void doFireScriptEvent( const css::script::ScriptEvent& _rEvent, css::uno::Any* _pSynchronousResult );
+
+ };
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMSCRIPTINGENV_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmservs.hxx b/svx/source/inc/fmservs.hxx
new file mode 100644
index 000000000..2b8ee7a7d
--- /dev/null
+++ b/svx/source/inc/fmservs.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FMSERVS_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMSERVS_HXX
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <svx/svxdllapi.h>
+
+namespace com::sun::star::lang { class XMultiServiceFactory; }
+
+inline constexpr OUStringLiteral FM_COMPONENT_EDIT = u"stardiv.one.form.component.Edit";
+inline constexpr OUStringLiteral FM_COMPONENT_TEXTFIELD = u"stardiv.one.form.component.TextField";
+inline constexpr OUStringLiteral FM_COMPONENT_LISTBOX = u"stardiv.one.form.component.ListBox";
+inline constexpr OUStringLiteral FM_COMPONENT_COMBOBOX = u"stardiv.one.form.component.ComboBox";
+inline constexpr OUStringLiteral FM_COMPONENT_RADIOBUTTON = u"stardiv.one.form.component.RadioButton";
+inline constexpr OUStringLiteral FM_COMPONENT_GROUPBOX = u"stardiv.one.form.component.GroupBox";
+inline constexpr OUStringLiteral FM_COMPONENT_FIXEDTEXT = u"stardiv.one.form.component.FixedText";
+inline constexpr OUStringLiteral FM_COMPONENT_COMMANDBUTTON = u"stardiv.one.form.component.CommandButton";
+inline constexpr OUStringLiteral FM_COMPONENT_CHECKBOX = u"stardiv.one.form.component.CheckBox";
+inline constexpr OUStringLiteral FM_COMPONENT_GRID = u"stardiv.one.form.component.Grid";
+inline constexpr OUStringLiteral FM_COMPONENT_GRIDCONTROL = u"stardiv.one.form.component.GridControl";
+inline constexpr OUStringLiteral FM_COMPONENT_IMAGEBUTTON = u"stardiv.one.form.component.ImageButton";
+inline constexpr OUStringLiteral FM_COMPONENT_FILECONTROL = u"stardiv.one.form.component.FileControl";
+inline constexpr OUStringLiteral FM_COMPONENT_TIMEFIELD = u"stardiv.one.form.component.TimeField";
+inline constexpr OUStringLiteral FM_COMPONENT_DATEFIELD = u"stardiv.one.form.component.DateField";
+inline constexpr OUStringLiteral FM_COMPONENT_NUMERICFIELD = u"stardiv.one.form.component.NumericField";
+inline constexpr OUStringLiteral FM_COMPONENT_CURRENCYFIELD = u"stardiv.one.form.component.CurrencyField";
+inline constexpr OUStringLiteral FM_COMPONENT_PATTERNFIELD = u"stardiv.one.form.component.PatternField";
+inline constexpr OUStringLiteral FM_COMPONENT_FORMATTEDFIELD = u"stardiv.one.form.component.FormattedField";
+inline constexpr OUStringLiteral FM_COMPONENT_HIDDEN = u"stardiv.one.form.component.Hidden";
+inline constexpr OUStringLiteral FM_COMPONENT_HIDDENCONTROL = u"stardiv.one.form.component.HiddenControl";
+inline constexpr OUStringLiteral FM_COMPONENT_IMAGECONTROL = u"stardiv.one.form.component.ImageControl";
+inline constexpr OUStringLiteral FM_CONTROL_GRID = u"stardiv.one.form.control.Grid";
+inline constexpr OUStringLiteral FM_CONTROL_GRIDCONTROL = u"stardiv.one.form.control.GridControl";
+inline constexpr OUStringLiteral SRV_SDB_CONNECTION = u"com.sun.star.sdb.Connection";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_FORM = u"com.sun.star.form.component.Form";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_TEXTFIELD = u"com.sun.star.form.component.TextField";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_LISTBOX = u"com.sun.star.form.component.ListBox";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_COMBOBOX = u"com.sun.star.form.component.ComboBox";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_RADIOBUTTON = u"com.sun.star.form.component.RadioButton";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_GROUPBOX = u"com.sun.star.form.component.GroupBox";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_FIXEDTEXT = u"com.sun.star.form.component.FixedText";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_COMMANDBUTTON = u"com.sun.star.form.component.CommandButton";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_CHECKBOX = u"com.sun.star.form.component.CheckBox";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_GRIDCONTROL = u"com.sun.star.form.component.GridControl";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_IMAGEBUTTON = u"com.sun.star.form.component.ImageButton";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_FILECONTROL = u"com.sun.star.form.component.FileControl";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_TIMEFIELD = u"com.sun.star.form.component.TimeField";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_DATEFIELD = u"com.sun.star.form.component.DateField";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_NUMERICFIELD = u"com.sun.star.form.component.NumericField";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_CURRENCYFIELD = u"com.sun.star.form.component.CurrencyField";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_PATTERNFIELD = u"com.sun.star.form.component.PatternField";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_HIDDENCONTROL = u"com.sun.star.form.component.HiddenControl";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_IMAGECONTROL = u"com.sun.star.form.component.DatabaseImageControl";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_FORMATTEDFIELD = u"com.sun.star.form.component.FormattedField";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_SCROLLBAR = u"com.sun.star.form.component.ScrollBar";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_SPINBUTTON = u"com.sun.star.form.component.SpinButton";
+inline constexpr OUStringLiteral FM_SUN_COMPONENT_NAVIGATIONBAR = u"com.sun.star.form.component.NavigationToolBar";
+inline constexpr OUStringLiteral FM_SUN_CONTROL_GRIDCONTROL = u"com.sun.star.form.control.GridControl";
+
+namespace svxform
+{
+ SVXCORE_DLLPUBLIC void ImplSmartRegisterUnoServices();
+
+ css::uno::Reference<css::uno::XInterface>
+ OAddConditionDialog_Create(
+ css::uno::Reference<css::lang::XMultiServiceFactory> const &);
+
+ OUString OAddConditionDialog_GetImplementationName();
+
+ css::uno::Sequence<OUString>
+ OAddConditionDialog_GetSupportedServiceNames();
+}
+
+/// @throws css::uno::Exception
+css::uno::Reference<css::uno::XInterface>
+FmXGridControl_NewInstance_Impl(
+ css::uno::Reference<css::lang::XMultiServiceFactory> const &);
+
+/// @throws css::uno::Exception
+css::uno::Reference<css::uno::XInterface>
+FormController_NewInstance_Impl(
+ css::uno::Reference<css::lang::XMultiServiceFactory> const &);
+
+/// @throws css::uno::Exception
+css::uno::Reference<css::uno::XInterface>
+LegacyFormController_NewInstance_Impl(
+ css::uno::Reference<css::lang::XMultiServiceFactory> const &);
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMSERVS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmshimp.hxx b/svx/source/inc/fmshimp.hxx
new file mode 100644
index 000000000..a468bc030
--- /dev/null
+++ b/svx/source/inc/fmshimp.hxx
@@ -0,0 +1,562 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FMSHIMP_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMSHIMP_HXX
+
+#include <config_options.h>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/container/ContainerEvent.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/runtime/XFormController.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/form/NavigationBarMode.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/beans/PropertyChangeEvent.hpp>
+#include <com/sun/star/form/runtime/FeatureState.hpp>
+#include <tools/diagnose_ex.h>
+#include <vcl/timer.hxx>
+#include <sfx2/shell.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/fmsearch.hxx>
+
+#include <svx/fmtools.hxx>
+#include <osl/mutex.hxx>
+#include <comphelper/container.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <unotools/configitem.hxx>
+#include "formcontrolling.hxx"
+#include "fmdocumentclassification.hxx"
+#include <o3tl/typed_flags_set.hxx>
+
+#include <queue>
+#include <string_view>
+#include <vector>
+#include <memory>
+
+struct ImplSVEvent;
+
+typedef std::vector< css::uno::Reference< css::form::XForm > > FmFormArray;
+
+// catch database exceptions if they occur
+#define DO_SAFE(statement) try { statement; } catch( const Exception& ) { TOOLS_WARN_EXCEPTION("svx", "unhandled exception (I tried to move a cursor (or something like that).)"); }
+
+enum class LoopGridsSync {
+ DISABLE_SYNC = 1,
+ FORCE_SYNC = 2,
+ ENABLE_SYNC = 3
+};
+enum class LoopGridsFlags
+{
+ NONE = 0,
+ DISABLE_ROCTRLR = 4
+};
+namespace o3tl
+{
+ template<> struct typed_flags<LoopGridsFlags> : is_typed_flags<LoopGridsFlags, 0x04> {};
+}
+
+
+// flags for controlling the behaviour when calling loadForms
+enum class LoadFormsFlags {
+ Load = 0x0000, // default: simply load
+ Sync = 0x0000, // default: do in synchronous
+ Unload = 0x0001, // unload
+ Async = 0x0002 // do this async
+};
+namespace o3tl {
+ template<> struct typed_flags<LoadFormsFlags> : is_typed_flags<LoadFormsFlags, 0x0003> {};
+}
+
+namespace weld {
+ class Menu;
+}
+
+// a class iterating through all fields of a form which are bound to a field
+// sub forms are ignored, grid columns (where the grid is a direct child of the form) are included
+class FmXBoundFormFieldIterator final : public ::comphelper::IndexAccessIterator
+{
+public:
+ FmXBoundFormFieldIterator(const css::uno::Reference< css::uno::XInterface>& _rStartingPoint) : ::comphelper::IndexAccessIterator(_rStartingPoint) { }
+
+private:
+ virtual bool ShouldHandleElement(const css::uno::Reference< css::uno::XInterface>& _rElement) override;
+ virtual bool ShouldStepInto(const css::uno::Reference< css::uno::XInterface>& _rContainer) const override;
+};
+
+class FmFormPage;
+class FmFormPageImpl;
+
+struct FmLoadAction
+{
+ FmFormPage* pPage;
+ ImplSVEvent * nEventId;
+ LoadFormsFlags nFlags;
+
+ FmLoadAction( FmFormPage* _pPage, LoadFormsFlags _nFlags, ImplSVEvent * _nEventId )
+ :pPage( _pPage ), nEventId( _nEventId ), nFlags( _nFlags )
+ {
+ }
+};
+
+
+class SfxViewFrame;
+typedef ::cppu::WeakComponentImplHelper< css::beans::XPropertyChangeListener
+ , css::container::XContainerListener
+ , css::view::XSelectionChangeListener
+ , css::form::XFormControllerListener
+ > FmXFormShell_BD_BASE;
+
+
+class FmXFormShell_Base_Disambiguation : public FmXFormShell_BD_BASE
+{
+ using css::beans::XPropertyChangeListener::disposing;
+protected:
+ FmXFormShell_Base_Disambiguation( ::osl::Mutex& _rMutex );
+ using WeakComponentImplHelperBase::disposing;
+};
+
+
+namespace svx
+{
+ class FmTextControlShell;
+}
+
+
+typedef FmXFormShell_Base_Disambiguation FmXFormShell_BASE;
+typedef ::utl::ConfigItem FmXFormShell_CFGBASE;
+
+struct SdrViewEvent;
+class FmFormShell;
+class FmFormView;
+class FmFormObj;
+class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) FmXFormShell final : private cppu::BaseMutex
+ ,public FmXFormShell_BASE
+ ,public FmXFormShell_CFGBASE
+ ,public svx::IControllerFeatureInvalidation
+{
+ friend class FmFormView;
+ friend class FmXFormView;
+
+ class SuspendPropertyTracking;
+ friend class SuspendPropertyTracking;
+
+ // timer for delayed mark
+ Timer m_aMarkTimer;
+ std::vector<SdrObject*> m_arrSearchedControls;
+ // We enable a permanent cursor for the grid we found a searched text, it's disabled in the next "found" event.
+ FmFormArray m_aSearchForms;
+
+ struct SAL_DLLPRIVATE InvalidSlotInfo {
+ sal_uInt16 id;
+ sal_uInt8 flags;
+ InvalidSlotInfo(sal_uInt16 slotId, sal_uInt8 flgs) : id(slotId), flags(flgs) {};
+ };
+ std::vector<InvalidSlotInfo> m_arrInvalidSlots;
+ // we explicitly switch off the propbrw before leaving the design mode
+ // this flag tells us if we have to switch it on again when reentering
+
+ css::form::NavigationBarMode m_eNavigate; // kind of navigation
+
+ // since I want to mark an SdrObject when searching for the treatment of the "found",
+ // I get all relevant objects before yanking up of the search dialog
+ // (the array is thus only valid during the search process)
+ std::vector<sal_Int16> m_arrRelativeGridColumn;
+
+ ImplSVEvent * m_nInvalidationEvent;
+ ImplSVEvent * m_nActivationEvent;
+ ::std::queue< FmLoadAction >
+ m_aLoadingPages;
+
+ FmFormShell* m_pShell;
+ std::unique_ptr<svx::FmTextControlShell> m_pTextShell;
+
+ svx::ControllerFeatures m_aActiveControllerFeatures;
+ svx::ControllerFeatures m_aNavControllerFeatures;
+
+ // current form, controller
+ // only available in the alive mode
+ css::uno::Reference< css::form::runtime::XFormController > m_xActiveController;
+ css::uno::Reference< css::form::runtime::XFormController > m_xNavigationController;
+ css::uno::Reference< css::form::XForm > m_xActiveForm;
+
+ // current container of a page
+ // only available in the design mode
+ css::uno::Reference< css::container::XIndexAccess> m_xForms;
+
+ // the currently selected objects, as to be displayed in the property browser
+ InterfaceBag m_aCurrentSelection;
+ /// the currently selected form, or the form which all currently selected controls belong to, or <NULL/>
+ css::uno::Reference< css::form::XForm > m_xCurrentForm;
+ /// the last selection/marking of controls only. Necessary to implement the "Control properties" slot
+ InterfaceBag m_aLastKnownMarkedControls;
+
+
+ // And this is also for the 'found': When I find in GridControls, I need the column,
+ // but only get the number of the field corresponding to the number of the
+ // column + <offset>, where the offset depends on the position of the GridControl
+ // in the form. So here is a conversion.
+ css::uno::Reference< css::awt::XControlModel> m_xLastGridFound;
+ // the frame we live in
+ css::uno::Reference< css::frame::XFrame> m_xAttachedFrame;
+ // Administration of external form views (see the SID_FM_VIEW_AS_GRID-slot)
+ css::uno::Reference< css::frame::XController > m_xExternalViewController; // the controller for the external form view
+ css::uno::Reference< css::form::runtime::XFormController > m_xExtViewTriggerController; // the nav controller at the time the external display was triggered
+ css::uno::Reference< css::sdbc::XResultSet > m_xExternalDisplayedForm; // the form which the external view is based on
+
+ mutable ::svxform::DocumentType
+ m_eDocumentType; /// the type of document we're living in
+ sal_Int16 m_nLockSlotInvalidation;
+ bool m_bHadPropertyBrowserInDesignMode : 1;
+
+ bool m_bTrackProperties : 1;
+ // should I (or the owner of this impl class) take car of the update of the css::beans::Property-Browser?
+
+ bool m_bUseWizards : 1;
+
+ bool m_bDatabaseBar : 1; // is there a database bar
+ bool m_bInActivate : 1; // is a controller activated
+ bool m_bSetFocus : 1; // may the focus be changed over
+ bool m_bFilterMode : 1; // is a filter currently set to the controls
+ bool m_bChangingDesignMode:1; // sal_True within SetDesignMode
+ bool m_bPreparedClose : 1; // for the current modification state of the current form
+ // PrepareClose had been called and the user denied to save changes
+ bool m_bFirstActivation : 1; // has the shell ever been activated?
+
+public:
+ // attribute access
+ SAL_DLLPRIVATE const css::uno::Reference< css::frame::XFrame >&
+ getHostFrame_Lock() const { return m_xAttachedFrame; }
+ SAL_DLLPRIVATE const css::uno::Reference< css::sdbc::XResultSet >&
+ getExternallyDisplayedForm_Lock() const { return m_xExternalDisplayedForm; }
+
+ SAL_DLLPRIVATE bool
+ didPrepareClose_Lock() const { return m_bPreparedClose; }
+ SAL_DLLPRIVATE void
+ didPrepareClose_Lock(bool bDid) { m_bPreparedClose = bDid; }
+
+ SAL_DLLPRIVATE FmXFormShell(FmFormShell& _rShell, SfxViewFrame* _pViewFrame);
+
+private:
+ SAL_DLLPRIVATE virtual ~FmXFormShell() override;
+
+// EventListener
+ SAL_DLLPRIVATE virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+// css::container::XContainerListener
+ SAL_DLLPRIVATE virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& rEvent) override;
+ SAL_DLLPRIVATE virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& rEvent) override;
+ SAL_DLLPRIVATE virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& rEvent) override;
+
+// XSelectionChangeListener
+ SAL_DLLPRIVATE virtual void SAL_CALL selectionChanged(const css::lang::EventObject& rEvent) override;
+
+// css::beans::XPropertyChangeListener
+ SAL_DLLPRIVATE virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override;
+
+// css::form::XFormControllerListener
+ SAL_DLLPRIVATE virtual void SAL_CALL formActivated(const css::lang::EventObject& rEvent) override;
+ SAL_DLLPRIVATE virtual void SAL_CALL formDeactivated(const css::lang::EventObject& rEvent) override;
+
+// OComponentHelper
+ SAL_DLLPRIVATE virtual void SAL_CALL disposing() override;
+
+public:
+ SAL_DLLPRIVATE void EnableTrackProperties_Lock(bool bEnable) { m_bTrackProperties = bEnable; }
+ SAL_DLLPRIVATE bool IsTrackPropertiesEnabled_Lock() const { return m_bTrackProperties; }
+
+ // activation handling
+ SAL_DLLPRIVATE void viewActivated_Lock(FmFormView& _rCurrentView, bool _bSyncAction = false);
+ SAL_DLLPRIVATE void viewDeactivated_Lock(FmFormView& _rCurrentView, bool _bDeactivateController = true);
+
+ // IControllerFeatureInvalidation
+ SAL_DLLPRIVATE virtual void invalidateFeatures/*_NoLock*/( const ::std::vector< sal_Int32 >& _rFeatures ) override;
+
+ SAL_DLLPRIVATE void ExecuteTabOrderDialog_Lock( // execute SID_FM_TAB_DIALOG
+ const css::uno::Reference< css::awt::XTabControllerModel >& _rxForForm
+ );
+
+ // stuff
+ SAL_DLLPRIVATE void AddElement_Lock(const css::uno::Reference< css::uno::XInterface>& Element);
+ SAL_DLLPRIVATE void RemoveElement_Lock(const css::uno::Reference< css::uno::XInterface>& Element);
+
+ /** updates m_xForms, to be either <NULL/>, if we're in alive mode, or our current page's forms collection,
+ if in design mode
+ */
+ SAL_DLLPRIVATE void UpdateForms_Lock(bool bInvalidate);
+
+ SAL_DLLPRIVATE void ExecuteSearch_Lock(); // execute SID_FM_SEARCH
+ SAL_DLLPRIVATE void CreateExternalView_Lock(); // execute SID_FM_VIEW_AS_GRID
+
+ SAL_DLLPRIVATE bool GetY2KState_Lock(sal_uInt16 & n);
+ SAL_DLLPRIVATE void SetY2KState_Lock(sal_uInt16 n);
+
+private:
+ // form handling
+ /// load or unload the forms on a page
+ SAL_DLLPRIVATE void loadForms_Lock( FmFormPage* _pPage, const LoadFormsFlags _nBehaviour );
+ SAL_DLLPRIVATE void smartControlReset( const css::uno::Reference< css::container::XIndexAccess >& _rxModels );
+
+
+ SAL_DLLPRIVATE void startListening_Lock();
+ SAL_DLLPRIVATE void stopListening_Lock();
+
+ SAL_DLLPRIVATE css::uno::Reference< css::awt::XControl >
+ impl_getControl_Lock(
+ const css::uno::Reference< css::awt::XControlModel>& i_rxModel,
+ const FmFormObj& i_rKnownFormObj
+ );
+
+ // collects in strNames the names of all forms
+ SAL_DLLPRIVATE static void impl_collectFormSearchContexts_nothrow_Lock(
+ const css::uno::Reference< css::uno::XInterface>& _rxStartingPoint,
+ std::u16string_view _rCurrentLevelPrefix,
+ FmFormArray& _out_rForms,
+ ::std::vector< OUString >& _out_rNames );
+
+ /** checks whenever the instance is already disposed, if so, this is reported as assertion error (debug
+ builds only) and <TRUE/> is returned.
+ */
+ SAL_DLLPRIVATE bool impl_checkDisposed_Lock() const;
+
+public:
+ // method for non design mode (alive mode)
+ SAL_DLLPRIVATE void setActiveController_Lock(const css::uno::Reference< css::form::runtime::XFormController>& _xController, bool _bNoSaveOldContent = false);
+ SAL_DLLPRIVATE const css::uno::Reference< css::form::runtime::XFormController>& getActiveController_Lock() const { return m_xActiveController; }
+ SAL_DLLPRIVATE const css::uno::Reference< css::form::runtime::XFormController>& getActiveInternalController_Lock() const { return m_xActiveController == m_xExternalViewController ? m_xExtViewTriggerController : m_xActiveController; }
+ SAL_DLLPRIVATE const css::uno::Reference< css::form::XForm>& getActiveForm_Lock() const { return m_xActiveForm; }
+ SAL_DLLPRIVATE const css::uno::Reference< css::form::runtime::XFormController>& getNavController_Lock() const { return m_xNavigationController; }
+
+ SAL_DLLPRIVATE const svx::ControllerFeatures& getActiveControllerFeatures_Lock() const
+ { return m_aActiveControllerFeatures; }
+ SAL_DLLPRIVATE const svx::ControllerFeatures& getNavControllerFeatures_Lock() const
+ { return m_aNavControllerFeatures.isAssigned() ? m_aNavControllerFeatures : m_aActiveControllerFeatures; }
+
+ /** announces a new "current selection"
+ @return
+ <TRUE/> if and only if the to-bet-set selection was different from the previous selection
+ */
+ SAL_DLLPRIVATE bool setCurrentSelection_Lock(InterfaceBag&& rSelection);
+
+ /** sets the new selection to the last known marked controls
+ */
+ SAL_DLLPRIVATE bool selectLastMarkedControls_Lock();
+
+ /** retrieves the current selection
+ */
+ void getCurrentSelection_Lock(InterfaceBag& /* [out] */ _rSelection) const;
+
+ /** sets a new current selection as indicated by a mark list
+ @return
+ <TRUE/> if and only if the to-bet-set selection was different from the previous selection
+ */
+ SAL_DLLPRIVATE bool setCurrentSelectionFromMark_Lock(const SdrMarkList& rMarkList);
+
+ /// returns the currently selected form, or the form which all currently selected controls belong to, or <NULL/>
+ SAL_DLLPRIVATE const css::uno::Reference< css::form::XForm >&
+ getCurrentForm_Lock() const { return m_xCurrentForm; }
+ SAL_DLLPRIVATE void forgetCurrentForm_Lock();
+ /// returns whether the last known marking contained only controls
+ SAL_DLLPRIVATE bool onlyControlsAreMarked_Lock() const { return !m_aLastKnownMarkedControls.empty(); }
+
+ /// determines whether the current selection consists of exactly the given object
+ SAL_DLLPRIVATE bool isSolelySelected_Lock(
+ const css::uno::Reference< css::uno::XInterface >& _rxObject
+ );
+
+ /// handles a MouseButtonDown event of the FmFormView
+ SAL_DLLPRIVATE void handleMouseButtonDown_Lock( const SdrViewEvent& _rViewEvent );
+ /// handles the request for showing the "Properties"
+ SAL_DLLPRIVATE void handleShowPropertiesRequest_Lock();
+
+ SAL_DLLPRIVATE bool hasForms_Lock() const { return m_xForms.is() && m_xForms->getCount() != 0; }
+ SAL_DLLPRIVATE bool hasDatabaseBar_Lock() const { return m_bDatabaseBar; }
+
+ SAL_DLLPRIVATE void ShowSelectionProperties_Lock(bool bShow);
+ SAL_DLLPRIVATE bool IsPropBrwOpen_Lock() const;
+
+ SAL_DLLPRIVATE void DetermineSelection_Lock(const SdrMarkList& rMarkList);
+ SAL_DLLPRIVATE void SetSelection_Lock(const SdrMarkList& rMarkList);
+ SAL_DLLPRIVATE void SetSelectionDelayed_Lock();
+
+ SAL_DLLPRIVATE void SetDesignMode_Lock(bool bDesign);
+
+ SAL_DLLPRIVATE bool GetWizardUsing_Lock() const { return m_bUseWizards; }
+ SAL_DLLPRIVATE void SetWizardUsing_Lock(bool _bUseThem);
+
+ // setting the filter mode
+ SAL_DLLPRIVATE bool isInFilterMode_Lock() const { return m_bFilterMode; }
+ SAL_DLLPRIVATE void startFiltering_Lock();
+ SAL_DLLPRIVATE void stopFiltering_Lock(bool bSave);
+
+ // fills rMenu to be a menu that contains all ControlConversion entries
+ SAL_DLLPRIVATE static void GetConversionMenu_Lock(weld::Menu& rMenu);
+
+ /// checks whether a given control conversion slot can be applied to the current selection
+ SAL_DLLPRIVATE bool canConvertCurrentSelectionToControl_Lock(std::string_view rIdent);
+ /// enables or disables all conversion slots in a menu, according to the current selection
+ SAL_DLLPRIVATE void checkControlConversionSlotsForCurrentSelection_Lock(weld::Menu& rMenu);
+ /// executes a control conversion slot for a given object
+ SAL_DLLPRIVATE bool executeControlConversionSlot_Lock(const css::uno::Reference< css::form::XFormComponent >& _rxObject, std::string_view rIdent);
+ /** executes a control conversion slot for the current selection
+ @precond canConvertCurrentSelectionToControl( <arg>_nSlotId</arg> ) must return <TRUE/>
+ */
+ SAL_DLLPRIVATE void executeControlConversionSlot_Lock(std::string_view rIdent);
+ /// checks whether the given slot id denotes a control conversion slot
+ SAL_DLLPRIVATE static bool isControlConversionSlot(std::string_view rIdent);
+
+ SAL_DLLPRIVATE void ExecuteTextAttribute_Lock(SfxRequest& _rReq);
+ SAL_DLLPRIVATE void GetTextAttributeState_Lock(SfxItemSet& _rSet);
+ SAL_DLLPRIVATE bool IsActiveControl_Lock(bool _bCountRichTextOnly) const;
+ SAL_DLLPRIVATE void ForgetActiveControl_Lock();
+ SAL_DLLPRIVATE void SetControlActivationHandler_Lock(const Link<LinkParamNone*,void>& _rHdl);
+
+ /// classifies our host document
+ SAL_DLLPRIVATE ::svxform::DocumentType getDocumentType_Lock() const;
+ SAL_DLLPRIVATE bool isEnhancedForm_Lock() const;
+
+ /// determines whether our host document is currently read-only
+ SAL_DLLPRIVATE bool IsReadonlyDoc_Lock() const;
+
+ // Setting the curObject/selObject/curForm is delayed (SetSelectionDelayed). With the
+ // following functions this can be inquired/enforced.
+ SAL_DLLPRIVATE inline bool IsSelectionUpdatePending_Lock() const;
+ SAL_DLLPRIVATE void ForceUpdateSelection_Lock();
+
+ SAL_DLLPRIVATE css::uno::Reference< css::frame::XModel> getContextDocument_Lock() const;
+ SAL_DLLPRIVATE css::uno::Reference< css::form::XForm> getInternalForm_Lock(const css::uno::Reference< css::form::XForm>& _xForm) const;
+ SAL_DLLPRIVATE css::uno::Reference< css::sdbc::XResultSet> getInternalForm_Lock(const css::uno::Reference< css::sdbc::XResultSet>& _xForm) const;
+ // if the form belongs to the controller (extern) displaying a grid, the according internal form will
+ // be displayed, _xForm else
+
+ // check if the current control of the active controller has the focus
+ SAL_DLLPRIVATE bool HasControlFocus_Lock() const;
+
+private:
+ DECL_DLLPRIVATE_LINK(OnFoundData_Lock, FmFoundRecordInformation&, void);
+ DECL_DLLPRIVATE_LINK(OnCanceledNotFound_Lock, FmFoundRecordInformation&, void);
+ DECL_DLLPRIVATE_LINK(OnSearchContextRequest_Lock, FmSearchContext&, sal_uInt32);
+ DECL_DLLPRIVATE_LINK(OnTimeOut_Lock, Timer*, void);
+ DECL_DLLPRIVATE_LINK(OnFirstTimeActivation_Lock, void*, void);
+ DECL_DLLPRIVATE_LINK(OnFormsCreated_Lock, FmFormPageImpl&, void);
+
+ SAL_DLLPRIVATE void LoopGrids_Lock(LoopGridsSync nSync, LoopGridsFlags nWhat = LoopGridsFlags::NONE);
+
+ // invalidation of slots
+ SAL_DLLPRIVATE void InvalidateSlot_Lock(sal_Int16 nId, bool bWithId);
+ SAL_DLLPRIVATE void UpdateSlot_Lock(sal_Int16 nId);
+ // locking the invalidation - if the internal locking counter goes to 0, all accumulated slots
+ // are invalidated (asynchronously)
+ SAL_DLLPRIVATE void LockSlotInvalidation_Lock(bool bLock);
+
+ DECL_DLLPRIVATE_LINK(OnInvalidateSlots_Lock, void*, void);
+
+ SAL_DLLPRIVATE void CloseExternalFormViewer_Lock();
+ // closes the task-local beamer displaying a grid view for a form
+
+ // ConfigItem related stuff
+ SAL_DLLPRIVATE virtual void Notify( const css::uno::Sequence< OUString >& _rPropertyNames) override;
+ SAL_DLLPRIVATE void implAdjustConfigCache_Lock();
+
+ SAL_DLLPRIVATE css::uno::Reference< css::awt::XControlContainer >
+ getControlContainerForView_Lock() const;
+
+ /** finds and sets a default for m_xCurrentForm, if it is currently NULL
+ */
+ SAL_DLLPRIVATE void impl_defaultCurrentForm_nothrow_Lock();
+
+ /** sets m_xCurrentForm to the provided form, and updates everything which
+ depends on the current form
+ */
+ SAL_DLLPRIVATE void impl_updateCurrentForm_Lock( const css::uno::Reference< css::form::XForm >& _rxNewCurForm );
+
+ /** adds or removes ourself as XEventListener at m_xActiveController
+ */
+ SAL_DLLPRIVATE void impl_switchActiveControllerListening_Lock(const bool _bListen);
+
+ /** add an element
+ */
+ SAL_DLLPRIVATE void impl_AddElement_nothrow(const css::uno::Reference< css::uno::XInterface>& Element);
+
+ /** remove an element
+ */
+ SAL_DLLPRIVATE void impl_RemoveElement_nothrow_Lock(const css::uno::Reference< css::uno::XInterface>& Element);
+
+ SAL_DLLPRIVATE virtual void ImplCommit() override;
+
+ // asynchronous cursor actions/navigation slot handling
+
+public:
+ /** execute the given form slot
+ <p>Warning. Only a small set of slots implemented currently.</p>
+ @param _nSlot
+ the slot to execute
+ */
+ SAL_DLLPRIVATE void ExecuteFormSlot_Lock(sal_Int32 _nSlot);
+
+ /** determines whether the current form slot is currently enabled
+ */
+ SAL_DLLPRIVATE bool IsFormSlotEnabled( sal_Int32 _nSlot, css::form::runtime::FeatureState* _pCompleteState ) const;
+
+ SAL_DLLPRIVATE static OString SlotToIdent(sal_uInt16 nSlot);
+
+private:
+ DECL_DLLPRIVATE_LINK( OnLoadForms_Lock, void*, void );
+};
+
+
+inline bool FmXFormShell::IsSelectionUpdatePending_Lock() const
+{
+ return m_aMarkTimer.IsActive();
+}
+
+
+// = An iterator that, emanating from an interface, looks for an object whose
+// = css::beans::Property-Set has a ControlSource and a BoundField property, the
+// = latter having a non-NULL value. If the interface itself does not meet this
+// = condition, it is tested whether it is a container (that is, has a
+// = css::container::XIndexAccess), then it is descended there and the same tried
+// = for each element of the container (again possibly with descent). If any
+// = object thereby has the required property, the part with the container test
+// = for that object is omitted.
+// =
+
+class SearchableControlIterator final : public ::comphelper::IndexAccessIterator
+{
+ OUString m_sCurrentValue;
+ // the current value of the ControlSource css::beans::Property
+
+public:
+ const OUString& getCurrentValue() const { return m_sCurrentValue; }
+
+ SearchableControlIterator(css::uno::Reference< css::uno::XInterface> const & xStartingPoint);
+
+ virtual bool ShouldHandleElement(const css::uno::Reference< css::uno::XInterface>& rElement) override;
+ virtual bool ShouldStepInto(const css::uno::Reference< css::uno::XInterface>& xContainer) const override;
+ virtual void Invalidate() override { IndexAccessIterator::Invalidate(); m_sCurrentValue.clear(); }
+};
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMSHIMP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmslotinvalidator.hxx b/svx/source/inc/fmslotinvalidator.hxx
new file mode 100644
index 000000000..4027b63fa
--- /dev/null
+++ b/svx/source/inc/fmslotinvalidator.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FMSLOTINVALIDATOR_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMSLOTINVALIDATOR_HXX
+
+#include <sal/types.h>
+
+namespace svx
+{
+typedef sal_uInt16 SfxSlotId;
+}
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMSLOTINVALIDATOR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmtextcontroldialogs.hxx b/svx/source/inc/fmtextcontroldialogs.hxx
new file mode 100644
index 000000000..e915b06f1
--- /dev/null
+++ b/svx/source/inc/fmtextcontroldialogs.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FMTEXTCONTROLDIALOGS_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMTEXTCONTROLDIALOGS_HXX
+
+#include <sfx2/tabdlg.hxx>
+#include <editeng/flstitem.hxx>
+
+namespace svx
+{
+
+ class TextControlCharAttribDialog final : public SfxTabDialogController
+ {
+ private:
+ SvxFontListItem m_aFontList;
+
+ public:
+ TextControlCharAttribDialog(weld::Window* pParent, const SfxItemSet& rCoreSet, const SvxFontListItem& rFontList);
+
+ private:
+ virtual void PageCreated(const OString& rId, SfxTabPage& _rPage) override;
+ };
+
+ class TextControlParaAttribDialog final : public SfxTabDialogController
+ {
+ public:
+ TextControlParaAttribDialog(weld::Window* pParent, const SfxItemSet& rCoreSet);
+ };
+}
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMTEXTCONTROLDIALOGS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmtextcontrolfeature.hxx b/svx/source/inc/fmtextcontrolfeature.hxx
new file mode 100644
index 000000000..2414f2bbd
--- /dev/null
+++ b/svx/source/inc/fmtextcontrolfeature.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FMTEXTCONTROLFEATURE_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMTEXTCONTROLFEATURE_HXX
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <cppuhelper/implbase.hxx>
+#include "fmslotinvalidator.hxx"
+
+
+namespace svx
+{
+ class FmTextControlShell;
+
+ typedef ::cppu::WeakImplHelper < css::frame::XStatusListener
+ > FmTextControlFeature_Base;
+
+ class FmTextControlFeature final : public FmTextControlFeature_Base
+ {
+ private:
+ css::uno::Reference< css::frame::XDispatch >
+ m_xDispatcher;
+ css::util::URL m_aFeatureURL;
+ css::uno::Any m_aFeatureState;
+ SfxSlotId m_nSlotId;
+ FmTextControlShell* m_pInvalidator;
+ bool m_bFeatureEnabled;
+
+ public:
+ /** constructs a FmTextControlFeature object
+ @param _rxDispatcher
+ the dispatcher which the instance should work with
+ @param _rFeatureURL
+ the URL which the instance should be responsible for
+ */
+ FmTextControlFeature(
+ const css::uno::Reference< css::frame::XDispatch >& _rxDispatcher,
+ const css::util::URL& _rFeatureURL,
+ SfxSlotId _nId,
+ FmTextControlShell* _pInvalidator
+ );
+
+ /// determines whether the feature we're responsible for is currently enabled
+ bool isFeatureEnabled( ) const { return m_bFeatureEnabled; }
+ const css::uno::Any& getFeatureState( ) const { return m_aFeatureState; }
+
+ /** dispatches the feature URL to the dispatcher
+ */
+ void dispatch() const;
+
+ /** dispatches the feature URL to the dispatcher, with passing the given arguments
+ */
+ void dispatch( const css::uno::Sequence< css::beans::PropertyValue >& _rArgs ) const;
+
+ /// releases any resources associated with this instance
+ void dispose();
+
+ private:
+ virtual ~FmTextControlFeature() override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& State ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMTEXTCONTROLFEATURE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmtextcontrolshell.hxx b/svx/source/inc/fmtextcontrolshell.hxx
new file mode 100644
index 000000000..77ea5c5d2
--- /dev/null
+++ b/svx/source/inc/fmtextcontrolshell.hxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FMTEXTCONTROLSHELL_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMTEXTCONTROLSHELL_HXX
+
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/awt/FocusEvent.hpp>
+#include <com/sun/star/awt/XTextComponent.hpp>
+#include <com/sun/star/form/runtime/XFormController.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <rtl/ref.hxx>
+#include <tools/link.hxx>
+#include <vcl/timer.hxx>
+#include "fmslotinvalidator.hxx"
+
+#include <vector>
+#include <map>
+
+class SfxRequest;
+class SfxItemSet;
+class SfxAllItemSet;
+class SfxBindings;
+class SfxViewFrame;
+class SfxApplication;
+
+
+namespace svx
+{
+
+
+ class FmFocusListenerAdapter;
+ class FmTextControlFeature;
+ class FmMouseListenerAdapter;
+
+ class IFocusObserver
+ {
+ public:
+ virtual void focusGained( const css::awt::FocusEvent& _rEvent ) = 0;
+ virtual void focusLost( const css::awt::FocusEvent& _rEvent ) = 0;
+
+ protected:
+ ~IFocusObserver() {}
+ };
+
+
+ //= IFocusObserver
+
+ class IContextRequestObserver
+ {
+ public:
+ virtual void contextMenuRequested() = 0;
+
+ protected:
+ ~IContextRequestObserver() {}
+ };
+
+ class FmTextControlShell final : public IFocusObserver
+ ,public IContextRequestObserver
+ {
+ private:
+ css::uno::Reference< css::util::XURLTransformer > m_xURLTransformer;
+ css::uno::Reference< css::awt::XControl > m_xActiveControl;
+ css::uno::Reference< css::awt::XTextComponent > m_xActiveTextComponent;
+ css::uno::Reference< css::form::runtime::XFormController > m_xActiveController;
+#ifndef DONT_REMEMBER_LAST_CONTROL
+ // without this define, m_xActiveControl remembers the *last* active control, even
+ // if it, in the meantime, already lost the focus
+ bool m_bActiveControl;
+ // so we need an additional boolean flag telling whether the active control
+ // is really focused
+#endif
+ bool m_bActiveControlIsReadOnly;
+ bool m_bActiveControlIsRichText;
+
+ // listening at all controls of the active controller for focus changes
+ typedef rtl::Reference<FmFocusListenerAdapter> FocusListenerAdapter;
+ typedef ::std::vector< FocusListenerAdapter > FocusListenerAdapters;
+ FocusListenerAdapters m_aControlObservers;
+
+ typedef rtl::Reference<FmMouseListenerAdapter> MouseListenerAdapter;
+ MouseListenerAdapter m_aContextMenuObserver;
+
+ // translating between "slots" of the framework and "features" of the active control
+ typedef rtl::Reference<FmTextControlFeature> ControlFeature;
+ typedef ::std::map< SfxSlotId, ControlFeature > ControlFeatures;
+ ControlFeatures m_aControlFeatures;
+
+ SfxViewFrame* m_pViewFrame;
+ // invalidating slots
+ SfxBindings& m_rBindings;
+ Link<LinkParamNone*,void> m_aControlActivationHandler;
+ AutoTimer m_aClipboardInvalidation;
+ bool m_bNeedClipboardInvalidation;
+
+ public:
+ FmTextControlShell( SfxViewFrame* _pFrame );
+ virtual ~FmTextControlShell();
+
+ // clean up any resources associated with this instance
+ void dispose();
+
+ void ExecuteTextAttribute( SfxRequest& _rReq );
+ void GetTextAttributeState( SfxItemSet& _rSet );
+ bool IsActiveControl( bool _bCountRichTextOnly = false ) const;
+ void ForgetActiveControl();
+ void SetControlActivationHandler( const Link<LinkParamNone*,void>& _rHdl ) { m_aControlActivationHandler = _rHdl; }
+
+ /** to be called when a form in our document has been activated
+ */
+ void formActivated( const css::uno::Reference< css::form::runtime::XFormController >& _rxController );
+ /** to be called when a form in our document has been deactivated
+ */
+ void formDeactivated( const css::uno::Reference< css::form::runtime::XFormController >& _rxController );
+
+ /** notifies the instance that the design mode has changed
+ */
+ void designModeChanged();
+
+ void Invalidate( SfxSlotId _nSlot );
+
+ private:
+ // IFocusObserver
+ virtual void focusGained( const css::awt::FocusEvent& _rEvent ) override;
+ virtual void focusLost( const css::awt::FocusEvent& _rEvent ) override;
+
+ // IContextRequestObserver
+ virtual void contextMenuRequested() override;
+
+ enum AttributeSet { eCharAttribs, eParaAttribs };
+ void executeAttributeDialog( AttributeSet _eSet, SfxRequest& _rReq );
+ void executeSelectAll( );
+ void executeClipboardSlot( SfxSlotId _nSlot );
+
+ bool isControllerListening() const { return !m_aControlObservers.empty(); }
+
+ rtl::Reference<FmTextControlFeature>
+ implGetFeatureDispatcher(
+ const css::uno::Reference< css::frame::XDispatchProvider >& _rxProvider,
+ SfxApplication const * _pApplication,
+ SfxSlotId _nSlot
+ );
+
+ // fills the given structure with dispatchers for the given slots, for the given control
+ void fillFeatureDispatchers(
+ const css::uno::Reference< css::awt::XControl >& _rxControl,
+ SfxSlotId* _pZeroTerminatedSlots,
+ ControlFeatures& _rDispatchers
+ );
+
+ /// creates SfxPoolItes for all features in the given set, and puts them into the given SfxAllItemSet
+ static void transferFeatureStatesToItemSet(
+ ControlFeatures& _rDispatchers,
+ SfxAllItemSet& _rSet,
+ bool _bTranslateLatin
+ );
+
+ /// to be called when a control has been activated
+ void controlActivated( const css::uno::Reference< css::awt::XControl >& _rxControl );
+ /// to be called when the currently active control has been deactivated
+ void controlDeactivated( );
+
+ void implClearActiveControlRef();
+
+ /** starts listening at all controls of the given controller for focus events
+ @precond
+ we don't have an active controller currently
+ */
+ void startControllerListening( const css::uno::Reference< css::form::runtime::XFormController >& _rxController );
+ /** stops listening at the active controller
+ @precond
+ we have an active controller currently
+ */
+ void stopControllerListening( );
+
+ DECL_LINK( OnInvalidateClipboard, Timer*, void );
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMTEXTCONTROLSHELL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmundo.hxx b/svx/source/inc/fmundo.hxx
new file mode 100644
index 000000000..61792e1af
--- /dev/null
+++ b/svx/source/inc/fmundo.hxx
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FMUNDO_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMUNDO_HXX
+
+#include <svx/svdundo.hxx>
+#include <svx/svdouno.hxx>
+#include "fmscriptingenv.hxx"
+
+
+#include <com/sun/star/util/XModifyListener.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/beans/PropertyChangeEvent.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/ContainerEvent.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <cppuhelper/implbase.hxx>
+
+
+#include <svl/lstner.hxx>
+
+class FmFormModel;
+class FmFormObj;
+class SdrObject;
+
+class FmUndoPropertyAction final : public SdrUndoAction
+{
+ css::uno::Reference< css::beans::XPropertySet> xObj;
+ OUString aPropertyName;
+ css::uno::Any aNewValue;
+ css::uno::Any aOldValue;
+
+public:
+ FmUndoPropertyAction(FmFormModel& rMod, const css::beans::PropertyChangeEvent& evt);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+ virtual OUString GetComment() const override;
+
+};
+
+class FmUndoContainerAction final : public SdrUndoAction
+{
+public:
+ enum Action
+ {
+ Inserted = 1,
+ Removed = 2
+ };
+
+ FmUndoContainerAction(FmFormModel& rMod,
+ Action _eAction,
+ const css::uno::Reference< css::container::XIndexContainer >& xCont,
+ const css::uno::Reference< css::uno::XInterface >& xElem,
+ sal_Int32 nIdx);
+ virtual ~FmUndoContainerAction() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+ static void DisposeElement( const css::uno::Reference< css::uno::XInterface >& xElem );
+
+private:
+ void implReInsert( );
+ void implReRemove( );
+
+ css::uno::Reference< css::container::XIndexContainer >
+ m_xContainer; // container which the action applies to
+ css::uno::Reference< css::uno::XInterface >
+ m_xElement; // object not owned by the action
+ css::uno::Reference< css::uno::XInterface >
+ m_xOwnElement; // object owned by the action
+ sal_Int32 m_nIndex; // index of the object within its container
+ css::uno::Sequence< css::script::ScriptEventDescriptor >
+ m_aEvents; // events of the object
+ Action m_eAction;
+};
+
+class FmUndoModelReplaceAction final : public SdrUndoAction
+{
+ css::uno::Reference< css::awt::XControlModel> m_xReplaced;
+ SdrUnoObj* m_pObject;
+
+public:
+ FmUndoModelReplaceAction(FmFormModel& rMod, SdrUnoObj* pObject, const css::uno::Reference< css::awt::XControlModel>& xReplaced);
+ virtual ~FmUndoModelReplaceAction() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override { Undo(); }
+
+ virtual OUString GetComment() const override;
+
+ static void DisposeElement( const css::uno::Reference< css::awt::XControlModel>& xReplaced );
+};
+
+
+class FmXUndoEnvironment final
+ : public ::cppu::WeakImplHelper< css::beans::XPropertyChangeListener
+ , css::container::XContainerListener
+ , css::util::XModifyListener
+ >
+ , public SfxListener
+{
+public:
+ FmXUndoEnvironment(FmFormModel& _rModel);
+ virtual ~FmXUndoEnvironment() override;
+
+ // UNO binding
+ // SMART_UNO_DECLARATION(FmXUndoEnvironment, ::cppu::OWeakObject);
+ // virtual sal_Bool queryInterface(UsrUik, css::uno::Reference< css::uno::XInterface>&);
+ // virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass>> getIdlClasses();
+
+ void Lock() { osl_atomic_increment( &m_Locks ); }
+ void UnLock() { osl_atomic_decrement( &m_Locks ); }
+ bool IsLocked() const { return m_Locks != 0; }
+
+ // access control
+ struct Accessor { friend class FmFormModel; private: Accessor() { } };
+
+ // addition and removal of form collections
+ void AddForms( const css::uno::Reference< css::container::XNameContainer>& rForms );
+ void RemoveForms( const css::uno::Reference< css::container::XNameContainer>& rForms );
+
+ // readonly-ness
+ void SetReadOnly( bool bRead, const Accessor& ) { bReadOnly = bRead; }
+ bool IsReadOnly() const {return bReadOnly;}
+
+ // Methods for assigning controls to forms,
+ // used by the page and the undo environment
+ void Inserted(SdrObject* pObj);
+ void Removed(SdrObject* pObj);
+
+ static void Inserted(FmFormObj* pObj);
+ static void Removed(FmFormObj* pObj);
+
+private:
+ // XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override;
+
+ // XContainerListener
+ virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& rEvent) override;
+ virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& rEvent) override;
+ virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& rEvent) override;
+
+ // XModifyListener
+ virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
+
+ void ModeChanged();
+ void dispose();
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ void AddElement(const css::uno::Reference< css::uno::XInterface>& Element);
+ void RemoveElement(const css::uno::Reference< css::uno::XInterface>& Element);
+ void TogglePropertyListening(const css::uno::Reference< css::uno::XInterface>& Element);
+
+ void implSetModified();
+
+ void switchListening( const css::uno::Reference< css::container::XIndexContainer >& _rxContainer, bool _bStartListening );
+ void switchListening( const css::uno::Reference< css::uno::XInterface >& _rxObject, bool _bStartListening );
+
+ FmFormModel& rModel;
+ void* m_pPropertySetCache;
+ ::rtl::Reference<svxform::FormScriptingEnvironment> m_pScriptingEnv;
+ oslInterlockedCount m_Locks;
+ ::osl::Mutex m_aMutex;
+ bool bReadOnly;
+ bool m_bDisposed;
+ css::uno::Reference< css::script::XScriptListener > m_vbaListener;
+};
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMUNDO_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmurl.hxx b/svx/source/inc/fmurl.hxx
new file mode 100644
index 000000000..5386270ae
--- /dev/null
+++ b/svx/source/inc/fmurl.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FMURL_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMURL_HXX
+
+#include <rtl/ustring.hxx>
+
+inline constexpr OUStringLiteral FMURL_FORM_POSITION = u".uno:FormController/positionForm";
+inline constexpr OUStringLiteral FMURL_FORM_RECORDCOUNT = u".uno:FormController/RecordCount";
+inline constexpr OUStringLiteral FMURL_RECORD_MOVEFIRST = u".uno:FormController/moveToFirst";
+inline constexpr OUStringLiteral FMURL_RECORD_MOVEPREV = u".uno:FormController/moveToPrev";
+inline constexpr OUStringLiteral FMURL_RECORD_MOVENEXT = u".uno:FormController/moveToNext";
+inline constexpr OUStringLiteral FMURL_RECORD_MOVELAST = u".uno:FormController/moveToLast";
+inline constexpr OUStringLiteral FMURL_RECORD_MOVETONEW = u".uno:FormController/moveToNew";
+inline constexpr OUStringLiteral FMURL_RECORD_UNDO = u".uno:FormController/undoRecord";
+inline constexpr OUStringLiteral FMURL_RECORD_SAVE = u".uno:FormController/saveRecord";
+inline constexpr OUStringLiteral FMURL_RECORD_DELETE = u".uno:FormController/deleteRecord";
+inline constexpr OUStringLiteral FMURL_FORM_REFRESH = u".uno:FormController/refreshForm";
+inline constexpr OUStringLiteral FMURL_FORM_REFRESH_CURRENT_CONTROL = u".uno:FormController/refreshCurrentControl";
+inline constexpr OUStringLiteral FMURL_FORM_SORT_UP = u".uno:FormController/sortUp";
+inline constexpr OUStringLiteral FMURL_FORM_SORT_DOWN = u".uno:FormController/sortDown";
+inline constexpr OUStringLiteral FMURL_FORM_SORT = u".uno:FormController/sort";
+inline constexpr OUStringLiteral FMURL_FORM_AUTO_FILTER = u".uno:FormController/autoFilter";
+inline constexpr OUStringLiteral FMURL_FORM_FILTER = u".uno:FormController/filter";
+inline constexpr OUStringLiteral FMURL_FORM_APPLY_FILTER = u".uno:FormController/applyFilter";
+inline constexpr OUStringLiteral FMURL_FORM_REMOVE_FILTER = u".uno:FormController/removeFilterOrder";
+inline constexpr OUStringLiteral FMURL_CONFIRM_DELETION = u".uno:FormSlots/ConfirmDeletion";
+inline constexpr OUStringLiteral FMURL_COMPONENT_FORMGRIDVIEW = u".component:DB/FormGridView";
+inline constexpr OUStringLiteral FMURL_GRIDVIEW_CLEARVIEW = u".uno:FormSlots/ClearView";
+inline constexpr OUStringLiteral FMURL_GRIDVIEW_ADDCOLUMN = u".uno:FormSlots/AddGridColumn";
+inline constexpr OUStringLiteral FMURL_GRIDVIEW_ATTACHTOFORM = u".uno:FormSlots/AttachToForm";
+inline constexpr OUStringLiteral FMARG_ATTACHTO_MASTERFORM = u"MasterForm";
+inline constexpr OUStringLiteral FMARG_ADDCOL_COLUMNTYPE = u"ColumnType";
+inline constexpr OUStringLiteral FMARG_ADDCOL_COLUMNPOS = u"ColumnPosition";
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMURL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/fmvwimp.hxx b/svx/source/inc/fmvwimp.hxx
new file mode 100644
index 000000000..c7cb3681b
--- /dev/null
+++ b/svx/source/inc/fmvwimp.hxx
@@ -0,0 +1,302 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FMVWIMP_HXX
+#define INCLUDED_SVX_SOURCE_INC_FMVWIMP_HXX
+
+#include <sal/config.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string_view>
+
+#include <svx/svdmark.hxx>
+#include <svx/svdobj.hxx>
+#include "fmdocumentclassification.hxx"
+
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/form/runtime/XFormController.hpp>
+#include <com/sun/star/form/runtime/XFormControllerContext.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/ContainerEvent.hpp>
+#include <com/sun/star/awt/XFocusListener.hpp>
+#include <com/sun/star/sdb/SQLErrorEvent.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <tools/link.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+#include <vcl/vclptr.hxx>
+
+class SdrPageWindow;
+
+class SdrObject;
+class FmFormObj;
+class FmFormModel;
+class FmFormView;
+class FmFormShell;
+namespace vcl { class Window; }
+class OutputDevice;
+class SdrUnoObj;
+struct ImplSVEvent;
+enum class SdrInventor : sal_uInt32;
+
+namespace com::sun::star {
+ namespace awt {
+ class XControl;
+ class XWindow;
+ }
+ namespace beans {
+ class XPropertySet;
+ }
+ namespace util {
+ class XNumberFormats;
+ }
+}
+
+class FmXFormView;
+
+namespace svx {
+ class ODataAccessDescriptor;
+ struct OXFormsDescriptor;
+}
+
+
+// FormViewPageWindowAdapter
+
+typedef ::cppu::WeakImplHelper < css::container::XIndexAccess
+ , css::form::runtime::XFormControllerContext
+ > FormViewPageWindowAdapter_Base;
+
+class FormViewPageWindowAdapter final : public FormViewPageWindowAdapter_Base
+{
+ friend class FmXFormView;
+
+ ::std::vector< css::uno::Reference< css::form::runtime::XFormController > > m_aControllerList;
+ css::uno::Reference< css::awt::XControlContainer > m_xControlContainer;
+ css::uno::Reference<css::uno::XComponentContext> m_xContext;
+ FmXFormView* m_pViewImpl;
+ VclPtr<vcl::Window> m_pWindow;
+
+public:
+ FormViewPageWindowAdapter( const css::uno::Reference<css::uno::XComponentContext>& _rContext,
+ const SdrPageWindow&, FmXFormView* pView);
+ //const SdrPageViewWinRec*, FmXFormView* pView);
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual css::uno::Any SAL_CALL getByIndex(sal_Int32 Index) override;
+
+ // XFormControllerContext
+ virtual void SAL_CALL makeVisible( const css::uno::Reference< css::awt::XControl >& Control ) override;
+
+ const ::std::vector< css::uno::Reference< css::form::runtime::XFormController > >& GetList() const {return m_aControllerList;}
+
+private:
+ virtual ~FormViewPageWindowAdapter() override;
+
+ css::uno::Reference< css::form::runtime::XFormController > getController( const css::uno::Reference< css::form::XForm >& xForm ) const;
+ void setController(
+ const css::uno::Reference< css::form::XForm >& xForm,
+ const css::uno::Reference< css::form::runtime::XFormController >& _rxParentController );
+ const css::uno::Reference< css::awt::XControlContainer >& getControlContainer() const { return m_xControlContainer; }
+ void updateTabOrder( const css::uno::Reference< css::form::XForm >& _rxForm );
+ void dispose();
+ vcl::Window* getWindow() const {return m_pWindow;}
+};
+
+class SdrModel;
+
+class FmXFormView final : public ::cppu::WeakImplHelper<
+ css::form::XFormControllerListener,
+ css::awt::XFocusListener,
+ css::container::XContainerListener>
+{
+ friend class FmFormView;
+ friend class FmFormShell;
+ friend class FmXFormShell;
+ friend class FormViewPageWindowAdapter;
+ class ObjectRemoveListener;
+ friend class ObjectRemoveListener;
+
+ css::uno::Reference< css::awt::XWindow> m_xWindow;
+ css::uno::Reference< css::beans::XPropertySet > m_xLastCreatedControlModel;
+
+ FmFormObj* m_pMarkedGrid;
+ FmFormView* m_pView;
+ ImplSVEvent * m_nActivationEvent;
+ ImplSVEvent * m_nErrorMessageEvent; // event for an asynchronous error message. See also m_aAsyncError
+ ImplSVEvent * m_nAutoFocusEvent; // event for asynchronously setting the focus to a control
+ ImplSVEvent * m_nControlWizardEvent; // event for asynchronously setting the focus to a control
+
+ css::sdb::SQLErrorEvent
+ m_aAsyncError; // error event which is to be displayed asyn. See m_nErrorMessageEvent.
+
+ std::vector< rtl::Reference< FormViewPageWindowAdapter > >
+ m_aPageWindowAdapters; // to be filled in alive mode only
+ typedef ::std::set< css::uno::Reference< css::form::XForm > > SetOfForms;
+ std::map< css::uno::Reference< css::awt::XControlContainer >, SetOfForms >
+ m_aNeedTabOrderUpdate; // map control container to set of forms
+
+ // list of selected objects, used for restoration when switching from Alive to DesignMode
+ SdrMarkList m_aMark;
+ std::unique_ptr<ObjectRemoveListener>
+ m_pWatchStoredList;
+
+ bool m_bFirstActivation;
+ bool m_isTabOrderUpdateSuspended;
+
+ FmFormShell* GetFormShell() const;
+
+ css::uno::Reference<css::awt::XWindow> GetParentWindow() const;
+
+ FmXFormView( FmFormView* _pView );
+ virtual ~FmXFormView() override;
+
+ void saveMarkList();
+ void restoreMarkList( SdrMarkList& _rRestoredMarkList );
+ void stopMarkListWatching();
+ void startMarkListWatching();
+
+ void notifyViewDying( );
+ // notifies this impl class that the anti-impl instance (m_pView) is going to die
+
+public:
+ // UNO binding
+
+// css::lang::XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+// css::container::XContainerListener
+ virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& rEvent) override;
+ virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& rEvent) override;
+ virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& rEvent) override;
+
+// css::form::XFormControllerListener
+ virtual void SAL_CALL formActivated(const css::lang::EventObject& rEvent) override;
+ virtual void SAL_CALL formDeactivated(const css::lang::EventObject& rEvent) override;
+
+ // XFocusListener
+ virtual void SAL_CALL focusGained( const css::awt::FocusEvent& e ) override;
+ virtual void SAL_CALL focusLost( const css::awt::FocusEvent& e ) override;
+
+ FmFormView* getView() const {return m_pView;}
+ rtl::Reference< FormViewPageWindowAdapter > findWindow( const css::uno::Reference< css::awt::XControlContainer >& _rxCC ) const;
+
+ css::uno::Reference< css::form::runtime::XFormController >
+ getFormController( const css::uno::Reference< css::form::XForm >& _rxForm, const OutputDevice& _rDevice ) const;
+
+ // activation handling
+ bool hasEverBeenActivated( ) const { return !m_bFirstActivation; }
+ void setHasBeenActivated( ) { m_bFirstActivation = false; }
+
+ void onFirstViewActivation( const FmFormModel* _pDocModel );
+
+ /** suspends the calls to activateTabOrder, which normally happen whenever for any ControlContainer of the view,
+ new controls are inserted. Cannot be nested, i.e. you need to call resumeTabOrderUpdate before calling
+ suspendTabOrderUpdate, again.
+ */
+ void suspendTabOrderUpdate();
+
+ /** resumes calls to activateTabOrder, and also does all pending calls which were collected since the last
+ suspendTabOrderUpdate call.
+ */
+ void resumeTabOrderUpdate();
+
+ void onCreatedFormObject( FmFormObj const & _rFormObject );
+
+ void breakCreateFormObject();
+
+ static bool
+ isFocusable( const css::uno::Reference< css::awt::XControl >& i_rControl );
+
+private:
+ //void addWindow(const SdrPageViewWinRec*);
+ void addWindow(const SdrPageWindow&);
+ void removeWindow( const css::uno::Reference< css::awt::XControlContainer >& _rxCC );
+ void Activate(bool bSync = false);
+ void Deactivate(bool bDeactivateController = true);
+
+ SdrObjectUniquePtr implCreateFieldControl( const svx::ODataAccessDescriptor& _rColumnDescriptor );
+ SdrObjectUniquePtr implCreateXFormsControl( const svx::OXFormsDescriptor &_rDesc );
+
+ static bool createControlLabelPair(
+ OutputDevice const & _rOutDev,
+ sal_Int32 _nXOffsetMM,
+ sal_Int32 _nYOffsetMM,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxField,
+ const css::uno::Reference< css::util::XNumberFormats >& _rxNumberFormats,
+ SdrObjKind _nControlObjectID,
+ std::u16string_view _rFieldPostfix,
+ SdrInventor _nInventor,
+ SdrObjKind _nLabelObjectID,
+
+ // tdf#118963 Need a SdrModel for SdrObject creation. To make the
+ // demand clear, hand over a SdrMldel&
+ SdrModel& _rModel,
+
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpControl
+ );
+
+ bool createControlLabelPair(
+ OutputDevice const & _rOutDev,
+ sal_Int32 _nXOffsetMM,
+ sal_Int32 _nYOffsetMM,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxField,
+ const css::uno::Reference< css::util::XNumberFormats >& _rxNumberFormats,
+ SdrObjKind _nControlObjectID,
+ std::u16string_view _rFieldPostfix,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpControl,
+ const css::uno::Reference< css::sdbc::XDataSource >& _rxDataSource,
+ const OUString& _rDataSourceName,
+ const OUString& _rCommand,
+ const sal_Int32 _nCommandType
+ );
+
+ void ObjectRemovedInAliveMode(const SdrObject* pObject);
+
+ // asynchronously displays an error message. See also OnDelayedErrorMessage.
+ void displayAsyncErrorMessage( const css::sdb::SQLErrorEvent& _rEvent );
+
+ // cancels all pending async events
+ void cancelEvents();
+
+ /// the auto focus to the first (in terms of the tab order) control
+ void AutoFocus();
+ DECL_LINK( OnActivate, void*, void );
+ DECL_LINK( OnAutoFocus, void*, void );
+ DECL_LINK( OnDelayedErrorMessage, void*, void );
+ DECL_LINK( OnStartControlWizard, void*, void );
+
+private:
+ ::svxform::DocumentType impl_getDocumentType() const;
+};
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FMVWIMP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/formcontrolfactory.hxx b/svx/source/inc/formcontrolfactory.hxx
new file mode 100644
index 000000000..a95c51095
--- /dev/null
+++ b/svx/source/inc/formcontrolfactory.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FORMCONTROLFACTORY_HXX
+#define INCLUDED_SVX_SOURCE_INC_FORMCONTROLFACTORY_HXX
+
+#include "fmdocumentclassification.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+
+#include <string_view>
+
+class SdrUnoObj;
+namespace tools { class Rectangle; }
+
+namespace comphelper {
+ class ComponentContext;
+}
+
+
+namespace svxform
+{
+
+ class FormControlFactory
+ {
+ public:
+ FormControlFactory( const css::uno::Reference<css::uno::XComponentContext>& _rContext );
+ FormControlFactory();
+ ~FormControlFactory();
+
+ /** initializes the given control model which is to be newly inserted into a document
+
+ @param _eDocType
+ the type of the document which the control is to be inserted into
+ @param _rxControlModel
+ the control model to be inserted
+ @param _rControlBoundRect
+ the bound rect of the control, if applicable
+ @return
+ the class ID of the control
+ */
+ sal_Int16 initializeControlModel(
+ const DocumentType _eDocType,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const tools::Rectangle& _rControlBoundRect
+ );
+
+ sal_Int16 initializeControlModel( const DocumentType _eDocType, const SdrUnoObj& _rObject );
+ void initializeControlModel( const DocumentType _eDocType, const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel );
+
+ void initializeTextFieldLineEnds(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxModel
+ );
+
+ static void initializeFieldDependentProperties(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxDatabaseField,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel,
+ const css::uno::Reference< css::util::XNumberFormats >& _rxNumberFormats
+ );
+
+ static OUString getDefaultName(
+ const sal_Int16 nClassId,
+ const css::uno::Reference< css::lang::XServiceInfo >& _rxObject
+ );
+
+ static OUString getDefaultUniqueName_ByComponentType(
+ const css::uno::Reference< css::container::XNameAccess >& _rxContainer,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxObject
+ );
+
+ static OUString getUniqueName(
+ const css::uno::Reference< css::container::XNameAccess >& _rxContainer,
+ std::u16string_view _rBaseName
+ );
+
+ private:
+ css::uno::Reference<css::uno::XComponentContext> m_xContext;
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FORMCONTROLFACTORY_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/formcontroller.hxx b/svx/source/inc/formcontroller.hxx
new file mode 100644
index 000000000..22e3bcb43
--- /dev/null
+++ b/svx/source/inc/formcontroller.hxx
@@ -0,0 +1,570 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_FORMCONTROLLER_HXX
+#define INCLUDED_SVX_SOURCE_INC_FORMCONTROLLER_HXX
+
+#include <sal/config.h>
+
+#include <memory>
+#include <vector>
+
+#include "delayedevent.hxx"
+#include "fmcontrolbordermanager.hxx"
+#include "formdispatchinterceptor.hxx"
+#include "sqlparserclient.hxx"
+
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/awt/XFocusListener.hpp>
+#include <com/sun/star/awt/XItemListener.hpp>
+#include <com/sun/star/awt/XMouseListener.hpp>
+#include <com/sun/star/awt/XTabController.hpp>
+#include <com/sun/star/awt/XTextComponent.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/form/DatabaseParameterEvent.hpp>
+#include <com/sun/star/form/validation/XFormComponentValidityListener.hpp>
+#include <com/sun/star/form/XConfirmDeleteListener.hpp>
+#include <com/sun/star/form/XDatabaseParameterListener.hpp>
+#include <com/sun/star/form/runtime/XFormController.hpp>
+#include <com/sun/star/form/runtime/XFilterController.hpp>
+#include <com/sun/star/form/XFormControllerListener.hpp>
+#include <com/sun/star/form/XGridControlListener.hpp>
+#include <com/sun/star/form/XLoadListener.hpp>
+#include <com/sun/star/form/XResetListener.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProviderInterception.hpp>
+#include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <com/sun/star/sdb/XRowSetApproveListener.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdb/XSQLErrorListener.hpp>
+#include <com/sun/star/sdbc/XRowSetListener.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/propshlp.hxx>
+#include <rtl/ref.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/idle.hxx>
+
+#include <cppuhelper/compbase.hxx>
+
+struct FmXTextComponentLess
+{
+ bool operator() (const css::uno::Reference< css::awt::XTextComponent >& x, const css::uno::Reference< css::awt::XTextComponent >& y) const
+ {
+ return reinterpret_cast<sal_Int64>(x.get()) < reinterpret_cast<sal_Int64>(y.get());
+ }
+};
+
+typedef ::std::map< css::uno::Reference< css::awt::XTextComponent >, OUString, FmXTextComponentLess> FmFilterRow;
+typedef ::std::vector< FmFilterRow > FmFilterRows;
+
+namespace svxform
+{
+ typedef ::std::vector< css::uno::Reference< css::awt::XTextComponent > > FilterComponents;
+ class ControlBorderManager;
+ struct FmFieldInfo;
+
+ typedef cppu::WeakComponentImplHelper < css::form::runtime::XFormController
+ , css::form::runtime::XFilterController
+ , css::awt::XFocusListener
+ , css::form::XLoadListener
+ , css::beans::XPropertyChangeListener
+ , css::awt::XTextListener
+ , css::awt::XItemListener
+ , css::container::XContainerListener
+ , css::util::XModifyListener
+ , css::form::XConfirmDeleteListener
+ , css::sdb::XSQLErrorListener
+ , css::sdbc::XRowSetListener
+ , css::sdb::XRowSetApproveListener
+ , css::form::XDatabaseParameterListener
+ , css::lang::XServiceInfo
+ , css::form::XResetListener
+ , css::frame::XDispatch
+ , css::awt::XMouseListener
+ , css::form::validation::XFormComponentValidityListener
+ , css::task::XInteractionHandler
+ , css::form::XGridControlListener
+ , css::form::runtime::XFeatureInvalidation
+ > FormController_BASE;
+
+ class ColumnInfoCache;
+ class FormController final : public ::cppu::BaseMutex
+ ,public FormController_BASE
+ ,public ::cppu::OPropertySetHelper
+ ,public DispatchInterceptor
+ ,public ::comphelper::OAggregationArrayUsageHelper< FormController >
+ ,public ::svxform::OSQLParserClient
+ {
+ typedef ::std::map < sal_Int16,
+ css::uno::Reference< css::frame::XDispatch >
+ > DispatcherContainer;
+
+ css::uno::Reference< css::uno::XAggregation> m_xAggregate;
+ css::uno::Reference< css::awt::XTabController> m_xTabController;
+ css::uno::Reference< css::awt::XControl> m_xActiveControl, m_xCurrentControl;
+ css::uno::Reference< css::container::XIndexAccess> m_xModelAsIndex;
+ css::uno::Reference< css::script::XEventAttacherManager> m_xModelAsManager;
+ css::uno::Reference< css::uno::XInterface> m_xParent;
+ css::uno::Reference< css::uno::XComponentContext> m_xComponentContext;
+ // Composer used for checking filter conditions
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer > m_xComposer;
+ css::uno::Reference< css::task::XInteractionHandler > m_xInteractionHandler;
+ css::uno::Reference< css::form::runtime::XFormControllerContext > m_xFormControllerContext;
+
+ css::uno::Sequence< css::uno::Reference< css::awt::XControl> > m_aControls;
+ ::comphelper::OInterfaceContainerHelper3<css::form::XFormControllerListener>
+ m_aActivateListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener>
+ m_aModifyListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::sdb::XSQLErrorListener>
+ m_aErrorListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::form::XConfirmDeleteListener>
+ m_aDeleteListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::sdb::XRowSetApproveListener>
+ m_aRowSetApproveListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::form::XDatabaseParameterListener>
+ m_aParameterListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::form::runtime::XFilterControllerListener>
+ m_aFilterListeners;
+
+ std::vector< css::uno::Reference< css::form::runtime::XFormController > >
+ m_aChildren;
+ FilterComponents m_aFilterComponents;
+ FmFilterRows m_aFilterRows;
+
+ Idle m_aTabActivationIdle;
+ Timer m_aFeatureInvalidationTimer;
+
+ ::svxform::ControlBorderManager
+ m_aControlBorderManager;
+
+ css::uno::Reference< css::form::runtime::XFormOperations >
+ m_xFormOperations;
+ DispatcherContainer m_aFeatureDispatchers;
+ ::std::set< sal_Int16 > m_aInvalidFeatures; // for asynchronous feature invalidation
+
+ OUString m_aMode;
+
+ ::svxform::DelayedEvent m_aLoadEvent;
+ ::svxform::DelayedEvent m_aToggleEvent;
+ ::svxform::DelayedEvent m_aActivationEvent;
+ ::svxform::DelayedEvent m_aDeactivationEvent;
+
+ ::std::unique_ptr< ColumnInfoCache >
+ m_pColumnInfoCache;
+
+ sal_Int32 m_nCurrentFilterPosition; // current level for filtering (or-criteria)
+
+ bool m_bCurrentRecordModified : 1;
+ bool m_bCurrentRecordNew : 1;
+ bool m_bLocked : 1;
+ bool m_bDBConnection : 1; // focus listener only for database forms
+ bool m_bCycle : 1;
+ bool m_bCanInsert : 1;
+ bool m_bCanUpdate : 1;
+ bool m_bCommitLock : 1; // lock the committing of controls see focusGained
+ bool m_bModified : 1; // is the content of a control modified?
+ bool m_bControlsSorted : 1;
+ bool m_bFiltering : 1;
+ bool m_bAttachEvents : 1;
+ bool m_bDetachEvents : 1;
+ bool m_bAttemptedHandlerCreation : 1;
+ bool m_bSuspendFilterTextListening; // no bit field, passed around as reference
+
+ // as we want to intercept dispatches of _all_ controls we're responsible for, and an object implementing
+ // the css::frame::XDispatchProviderInterceptor interface can intercept only _one_ objects dispatches, we need a helper class
+ std::vector<rtl::Reference<DispatchInterceptionMultiplexer>> m_aControlDispatchInterceptors;
+
+ public:
+ FormController( const css::uno::Reference< css::uno::XComponentContext > & _rxORB );
+
+ // returns the window which should be used as parent window for dialogs
+ static css::uno::Reference<css::awt::XWindow> getDialogParentWindow(css::uno::Reference<css::form::runtime::XFormController> xFormController);
+
+ private:
+ virtual ~FormController() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& type) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& _rURL, const css::uno::Sequence< css::beans::PropertyValue >& _rArgs ) override;
+ virtual void SAL_CALL addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& _rxListener, const css::util::URL& _rURL ) override;
+ virtual void SAL_CALL removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& _rxListener, const css::util::URL& _rURL ) override;
+
+ // css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface> SAL_CALL getParent() override;
+ virtual void SAL_CALL setParent(const css::uno::Reference< css::uno::XInterface>& Parent) override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // OPropertySetHelper
+ virtual sal_Bool SAL_CALL convertFastPropertyValue( css::uno::Any & rConvertedValue, css::uno::Any & rOldValue,
+ sal_Int32 nHandle, const css::uno::Any& rValue ) override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ using OPropertySetHelper::getFastPropertyValue;
+
+ // XFilterController
+ virtual ::sal_Int32 SAL_CALL getFilterComponents() override;
+ virtual ::sal_Int32 SAL_CALL getDisjunctiveTerms() override;
+ virtual void SAL_CALL addFilterControllerListener( const css::uno::Reference< css::form::runtime::XFilterControllerListener >& Listener ) override;
+ virtual void SAL_CALL removeFilterControllerListener( const css::uno::Reference< css::form::runtime::XFilterControllerListener >& Listener ) override;
+ virtual void SAL_CALL setPredicateExpression( ::sal_Int32 Component, ::sal_Int32 Term, const OUString& PredicateExpression ) override;
+ virtual css::uno::Reference< css::awt::XControl > SAL_CALL getFilterComponent( ::sal_Int32 Component ) override;
+ virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL getPredicateExpressions() override;
+ virtual void SAL_CALL removeDisjunctiveTerm( ::sal_Int32 Term ) override;
+ virtual void SAL_CALL appendEmptyDisjunctiveTerm() override;
+ virtual ::sal_Int32 SAL_CALL getActiveTerm() override;
+ virtual void SAL_CALL setActiveTerm( ::sal_Int32 ActiveTerm ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // css::container::XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration> SAL_CALL createEnumeration() override;
+
+ // css::container::XContainerListener
+ virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& rEvent) override;
+ virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& rEvent) override;
+ virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& rEvent) override;
+
+ // XLoadListener
+ virtual void SAL_CALL loaded(const css::lang::EventObject& rEvent) override;
+ virtual void SAL_CALL unloaded(const css::lang::EventObject& rEvent) override;
+ virtual void SAL_CALL unloading(const css::lang::EventObject& aEvent) override;
+ virtual void SAL_CALL reloading(const css::lang::EventObject& aEvent) override;
+ virtual void SAL_CALL reloaded(const css::lang::EventObject& aEvent) override;
+
+ // XModeSelector
+ virtual void SAL_CALL setMode(const OUString& Mode) override;
+ virtual OUString SAL_CALL getMode() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedModes() override;
+ virtual sal_Bool SAL_CALL supportsMode(const OUString& Mode) override;
+
+ // css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual css::uno::Any SAL_CALL getByIndex(sal_Int32 Index) override;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener(const css::uno::Reference< css::util::XModifyListener>& l) override;
+ virtual void SAL_CALL removeModifyListener(const css::uno::Reference< css::util::XModifyListener>& l) override;
+
+ // XFocusListener
+ virtual void SAL_CALL focusGained(const css::awt::FocusEvent& e) override;
+ virtual void SAL_CALL focusLost(const css::awt::FocusEvent& e) override;
+
+ // XMouseListener
+ virtual void SAL_CALL mousePressed( const css::awt::MouseEvent& _rEvent ) override;
+ virtual void SAL_CALL mouseReleased( const css::awt::MouseEvent& _rEvent ) override;
+ virtual void SAL_CALL mouseEntered( const css::awt::MouseEvent& _rEvent ) override;
+ virtual void SAL_CALL mouseExited( const css::awt::MouseEvent& _rEvent ) override;
+
+ // XFormComponentValidityListener
+ virtual void SAL_CALL componentValidityChanged( const css::lang::EventObject& _rSource ) override;
+
+ // XInteractionHandler
+ virtual void SAL_CALL handle( const css::uno::Reference< css::task::XInteractionRequest >& Request ) override;
+
+ // XGridControlListener
+ virtual void SAL_CALL columnChanged( const css::lang::EventObject& _event ) override;
+
+ // css::beans::XPropertyChangeListener -> change of states
+ virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override;
+
+ // XTextListener -> set modify
+ virtual void SAL_CALL textChanged(const css::awt::TextEvent& rEvent) override;
+
+ // XItemListener -> set modify
+ virtual void SAL_CALL itemStateChanged(const css::awt::ItemEvent& rEvent) override;
+
+ // XModifyListener -> set modify
+ virtual void SAL_CALL modified(const css::lang::EventObject& rEvent) override;
+
+ // XFormController
+ virtual css::uno::Reference< css::form::runtime::XFormOperations > SAL_CALL getFormOperations() override;
+ virtual css::uno::Reference< css::awt::XControl> SAL_CALL getCurrentControl() override;
+ virtual void SAL_CALL addActivateListener(const css::uno::Reference< css::form::XFormControllerListener>& l) override;
+ virtual void SAL_CALL removeActivateListener(const css::uno::Reference< css::form::XFormControllerListener>& l) override;
+ virtual void SAL_CALL addChildController( const css::uno::Reference< css::form::runtime::XFormController >& ChildController ) override;
+
+ virtual css::uno::Reference< css::form::runtime::XFormControllerContext > SAL_CALL getContext() override;
+ virtual void SAL_CALL setContext( const css::uno::Reference< css::form::runtime::XFormControllerContext >& _context ) override;
+ virtual css::uno::Reference< css::task::XInteractionHandler > SAL_CALL getInteractionHandler() override;
+ virtual void SAL_CALL setInteractionHandler( const css::uno::Reference< css::task::XInteractionHandler >& _interactionHandler ) override;
+
+ // XTabController
+ virtual css::uno::Sequence< css::uno::Reference< css::awt::XControl> > SAL_CALL getControls() override;
+
+ virtual void SAL_CALL setModel(const css::uno::Reference< css::awt::XTabControllerModel>& Model) override;
+ virtual css::uno::Reference< css::awt::XTabControllerModel> SAL_CALL getModel() override;
+
+ virtual void SAL_CALL setContainer(const css::uno::Reference< css::awt::XControlContainer>& Container) override;
+ virtual css::uno::Reference< css::awt::XControlContainer> SAL_CALL getContainer() override;
+
+ virtual void SAL_CALL autoTabOrder() override;
+ virtual void SAL_CALL activateTabOrder() override;
+
+ virtual void SAL_CALL activateFirst() override;
+ virtual void SAL_CALL activateLast() override;
+
+ // css::sdbc::XRowSetListener
+ virtual void SAL_CALL cursorMoved(const css::lang::EventObject& event) override;
+ virtual void SAL_CALL rowChanged(const css::lang::EventObject& event) override;
+ virtual void SAL_CALL rowSetChanged(const css::lang::EventObject& event) override;
+
+ // XRowSetApproveListener
+ virtual sal_Bool SAL_CALL approveCursorMove(const css::lang::EventObject& event) override;
+ virtual sal_Bool SAL_CALL approveRowChange(const css::sdb::RowChangeEvent& event) override;
+ virtual sal_Bool SAL_CALL approveRowSetChange(const css::lang::EventObject& event) override;
+
+ // XRowSetApproveBroadcaster
+ virtual void SAL_CALL addRowSetApproveListener(const css::uno::Reference< css::sdb::XRowSetApproveListener>& listener) override;
+ virtual void SAL_CALL removeRowSetApproveListener(const css::uno::Reference< css::sdb::XRowSetApproveListener>& listener) override;
+
+ // XSQLErrorBroadcaster
+ virtual void SAL_CALL errorOccured(const css::sdb::SQLErrorEvent& aEvent) override;
+
+ // XSQLErrorListener
+ virtual void SAL_CALL addSQLErrorListener(const css::uno::Reference< css::sdb::XSQLErrorListener>& _rListener) override;
+ virtual void SAL_CALL removeSQLErrorListener(const css::uno::Reference< css::sdb::XSQLErrorListener>& _rListener) override;
+
+ // XDatabaseParameterBroadcaster2
+ virtual void SAL_CALL addDatabaseParameterListener(const css::uno::Reference< css::form::XDatabaseParameterListener>& aListener) override;
+ virtual void SAL_CALL removeDatabaseParameterListener(const css::uno::Reference< css::form::XDatabaseParameterListener>& aListener) override;
+
+ // XDatabaseParameterBroadcaster
+ virtual void SAL_CALL addParameterListener(const css::uno::Reference< css::form::XDatabaseParameterListener>& aListener) override;
+ virtual void SAL_CALL removeParameterListener(const css::uno::Reference< css::form::XDatabaseParameterListener>& aListener) override;
+
+ // XDatabaseParameterListener
+ virtual sal_Bool SAL_CALL approveParameter(const css::form::DatabaseParameterEvent& aEvent) override;
+
+ // XConfirmDeleteBroadcaster
+ virtual void SAL_CALL addConfirmDeleteListener(const css::uno::Reference< css::form::XConfirmDeleteListener>& aListener) override;
+ virtual void SAL_CALL removeConfirmDeleteListener(const css::uno::Reference< css::form::XConfirmDeleteListener>& aListener) override;
+
+ // XConfirmDeleteListener
+ virtual sal_Bool SAL_CALL confirmDelete(const css::sdb::RowChangeEvent& aEvent) override;
+
+ // XServiceInfo
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XResetListener
+ virtual sal_Bool SAL_CALL approveReset(const css::lang::EventObject& rEvent) override;
+ virtual void SAL_CALL resetted(const css::lang::EventObject& rEvent) override;
+
+ // XFeatureInvalidation
+ virtual void SAL_CALL invalidateFeatures( const css::uno::Sequence< ::sal_Int16 >& Features ) override;
+ virtual void SAL_CALL invalidateAllFeatures( ) override;
+
+// method for registration
+ static css::uno::Sequence< OUString > const & getSupportedServiceNames_Static();
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual void fillProperties(
+ css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps,
+ css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps
+ ) const override;
+
+ // DispatchInterceptor
+ virtual css::uno::Reference< css::frame::XDispatch>
+ interceptedQueryDispatch(
+ const css::util::URL& aURL,
+ const OUString& aTargetFrameName,
+ sal_Int32 nSearchFlags
+ ) override;
+
+ virtual ::osl::Mutex* getInterceptorMutex() override { return &m_aMutex; }
+
+ /// update all our dispatchers
+ void updateAllDispatchers() const;
+
+ /** disposes all dispatchers in m_aFeatureDispatchers, and empties m_aFeatureDispatchers
+ */
+ void disposeAllFeaturesAndDispatchers();
+
+ void startFiltering();
+ void stopFiltering();
+ void setFilter(::std::vector<FmFieldInfo>&);
+ void startListening();
+ void stopListening();
+
+ /** ensures that we have an interaction handler, if possible
+
+ If an interaction handler was provided at creation time (<member>initialize</member>), this
+ one will be used. Else, an attempt is made to create an <type scope="css::sdb">InteractionHandler</type>
+ is made.
+
+ @return <TRUE/>
+ if and only if <member>m_xInteractionHandler</member> is valid when the method returns
+ */
+ bool ensureInteractionHandler();
+
+ /** replaces one of our controls with another one
+
+ Upon successful replacing, the old control will be disposed. Also, internal members pointing
+ to the current or active control will be adjusted. Yet more, if the replaced control was
+ the active control, the new control will be made active.
+
+ @param _rxExistentControl
+ The control to replace. Must be one of the controls in our ControlContainer.
+ @param _rxNewControl
+ The control which should replace the existent control.
+ @return
+ <TRUE/> if and only if the control was successfully replaced
+ */
+ bool replaceControl(
+ const css::uno::Reference< css::awt::XControl >& _rxExistentControl,
+ const css::uno::Reference< css::awt::XControl >& _rxNewControl
+ );
+
+ // we're listening at all bound controls for modifications
+ void startControlModifyListening(const css::uno::Reference< css::awt::XControl>& xControl);
+ void stopControlModifyListening(const css::uno::Reference< css::awt::XControl>& xControl);
+
+ void setLocks();
+ void setControlLock(const css::uno::Reference< css::awt::XControl>& xControl);
+ void addToEventAttacher(const css::uno::Reference< css::awt::XControl>& xControl);
+ void removeFromEventAttacher(const css::uno::Reference< css::awt::XControl>& xControl);
+ void toggleAutoFields(bool bAutoFields);
+ /// @throws css::uno::RuntimeException
+ void unload();
+ void removeBoundFieldListener();
+
+ void startFormListening( const css::uno::Reference< css::beans::XPropertySet >& _rxForm, bool _bPropertiesOnly );
+ void stopFormListening( const css::uno::Reference< css::beans::XPropertySet >& _rxForm, bool _bPropertiesOnly );
+
+ css::uno::Reference< css::awt::XControl> findControl( css::uno::Sequence< css::uno::Reference< css::awt::XControl> >& rCtrls, const css::uno::Reference< css::awt::XControlModel>& rxCtrlModel, bool _bRemove, bool _bOverWrite ) const;
+
+ void insertControl(const css::uno::Reference< css::awt::XControl>& xControl);
+ void removeControl(const css::uno::Reference< css::awt::XControl>& xControl);
+
+ /// called when a new control is to be handled by the controller
+ void implControlInserted( const css::uno::Reference< css::awt::XControl>& _rxControl, bool _bAddToEventAttacher );
+ /// called when a control is not to be handled by the controller anymore
+ void implControlRemoved( const css::uno::Reference< css::awt::XControl>& _rxControl, bool _bRemoveFromEventAttacher );
+
+ /** sets m_xCurrentControl, plus does administrative tasks depending on it
+ */
+ void implSetCurrentControl( const css::uno::Reference< css::awt::XControl >& _rxControl );
+
+ /** invalidates the FormFeatures which depend on the current control
+ */
+ void implInvalidateCurrentControlDependentFeatures();
+
+ bool impl_isDisposed_nofail() const { return FormController_BASE::rBHelper.bDisposed; }
+ void impl_checkDisposed_throw() const;
+
+ void impl_onModify();
+
+ /** adds the given filter row to m_aFilterRows, setting m_nCurrentFilterPosition to 0 if the newly added
+ row is the first one.
+
+ @precond
+ our mutex is locked
+ */
+ void impl_addFilterRow( const FmFilterRow& _row );
+
+ /** adds an empty filter row to m_aFilterRows, and notifies our listeners
+ */
+ void impl_appendEmptyFilterRow( ::osl::ClearableMutexGuard& _rClearBeforeNotify );
+
+ bool isLocked() const {return m_bLocked;}
+ bool determineLockState() const;
+
+ css::uno::Reference< css::frame::XDispatchProviderInterceptor> createInterceptor(const css::uno::Reference< css::frame::XDispatchProviderInterception>& _xInterception);
+ // create a new interceptor, register it on the given object
+ void deleteInterceptor(const css::uno::Reference< css::frame::XDispatchProviderInterception>& _xInterception);
+ // if createInterceptor was called for the given object the according interceptor will be removed
+ // from the objects interceptor chain and released
+
+ /** checks all form controls belonging to our form for validity
+
+ If a form control supports the XValidatableFormComponent interface, this is used to determine
+ the validity of the control. If the interface is not supported, the control is supposed to be
+ valid.
+
+ @param _rFirstInvalidityExplanation
+ if the method returns <FALSE/> (i.e. if there is an invalid control), this string contains
+ the explanation for the invalidity, as obtained from the validator.
+
+ @param _rxFirstInvalidModel
+ if the method returns <FALSE/> (i.e. if there is an invalid control), this contains
+ the control model
+
+ @return
+ <TRUE/> if and only if all controls belonging to our form are valid
+ */
+ bool checkFormComponentValidity(
+ OUString& /* [out] */ _rFirstInvalidityExplanation,
+ css::uno::Reference< css::awt::XControlModel >& /* [out] */ _rxFirstInvalidModel
+ );
+
+ /** locates the control which belongs to a given model
+ */
+ css::uno::Reference< css::awt::XControl >
+ locateControl( const css::uno::Reference< css::awt::XControlModel >& _rxModel );
+
+ // set the text for all filters
+ void impl_setTextOnAllFilter_throw();
+
+ // in filter mode we do not listen for changes
+ bool isListeningForChanges() const {return m_bDBConnection && !m_bFiltering && !isLocked();}
+ css::uno::Reference< css::awt::XControl> isInList(const css::uno::Reference< css::awt::XWindowPeer>& xPeer) const;
+
+ DECL_LINK( OnActivateTabOrder, Timer*, void );
+ DECL_LINK( OnInvalidateFeatures, Timer*, void );
+ DECL_LINK( OnLoad, void*, void );
+ DECL_LINK( OnToggleAutoFields, void*, void );
+ DECL_LINK( OnActivated, void*, void );
+ DECL_LINK( OnDeactivated, void*, void );
+ };
+
+}
+
+#endif // INCLUDED_SVX_SOURCE_INC_FORMCONTROLLER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/formcontrolling.hxx b/svx/source/inc/formcontrolling.hxx
new file mode 100644
index 000000000..c9bd8f23f
--- /dev/null
+++ b/svx/source/inc/formcontrolling.hxx
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FORMCONTROLLING_HXX
+#define INCLUDED_SVX_SOURCE_INC_FORMCONTROLLING_HXX
+
+#include <com/sun/star/form/runtime/XFormController.hpp>
+#include <com/sun/star/form/runtime/FeatureState.hpp>
+#include <com/sun/star/form/runtime/XFormOperations.hpp>
+#include <com/sun/star/sdb/XSQLErrorListener.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+
+#include <vector>
+
+
+namespace svx
+{
+
+ class FeatureSlotTranslation
+ {
+ public:
+ /// retrieves the feature id for a given feature URL
+ static sal_Int32 getControllerFeatureSlotIdForURL( const OUString& _rMainURL );
+
+ /// retrieves the css.form.runtime.FormFeature ID for a given slot ID
+ static sal_Int16 getFormFeatureForSlotId( sal_Int32 _nSlotId );
+
+ /// retrieves the slot id for a given css.form.runtime.FormFeature ID
+ static sal_Int32 getSlotIdForFormFeature( sal_Int16 _nFormFeature );
+ };
+
+ class IControllerFeatureInvalidation
+ {
+ public:
+ /** invalidates the given features
+
+ Invalidation means that any user interface representation (such as toolbox buttons), or
+ any dispatches associated with the features in question are potentially out-of-date, and
+ need to be updated
+
+ @param _rFeatures
+ Ids of the features to be invalidated.
+ */
+ virtual void invalidateFeatures( const ::std::vector< sal_Int32 >& _rFeatures ) = 0;
+
+ protected:
+ ~IControllerFeatureInvalidation() {}
+ };
+
+ class FormControllerHelper;
+ /** easier access to a FormControllerHelper instance
+ */
+ class ControllerFeatures final
+ {
+ IControllerFeatureInvalidation* m_pInvalidationCallback; // necessary as long as m_pImpl is not yet constructed
+ rtl::Reference<FormControllerHelper> m_pImpl;
+
+ public:
+ /** standard ctor
+
+ The instance is not functional until <method>assign</method> is used.
+
+ @param _pInvalidationCallback
+ the callback for invalidating feature states
+ */
+ ControllerFeatures(
+ IControllerFeatureInvalidation* _pInvalidationCallback
+ );
+
+ /** constructs the instance from a <type scope="css::form::runtime">XFormController<type> instance
+
+ @param _rxController
+ The form controller which the helper should be responsible for. Must not
+ be <NULL/>, and must have a valid model (form).
+ */
+ ControllerFeatures(
+ const css::uno::Reference< css::form::runtime::XFormController >& _rxController
+ );
+
+ /// dtor
+ ~ControllerFeatures();
+
+ /// checks whether the instance is properly assigned to a form and/or controller
+ bool isAssigned( ) const { return m_pImpl != nullptr; }
+
+ /** assign to a controller
+ */
+ void assign(
+ const css::uno::Reference< css::form::runtime::XFormController >& _rxController
+ );
+
+ /// clears the instance so that it cannot be used afterwards
+ void dispose();
+
+ // access to the instance which implements the functionality. Not to be used when not assigned
+ const FormControllerHelper* operator->() const { return m_pImpl.get(); }
+ FormControllerHelper* operator->() { return m_pImpl.get(); }
+ };
+
+
+ //= FormControllerHelper
+
+ typedef ::cppu::WeakImplHelper < css::form::runtime::XFeatureInvalidation
+ , css::sdb::XSQLErrorListener
+ > FormControllerHelper_Base;
+ /** is a helper class which manages form controller functionality (such as moveNext etc.).
+
+ <p>The class helps implementing form controller functionality, by providing
+ methods to determine the state of, and execute, various common form features.<br/>
+ A <em>feature</em> is for instance moving the form associated with the controller
+ to a certain position, or reloading the form, and so on.</p>
+ */
+ class FormControllerHelper final : public FormControllerHelper_Base
+ {
+ IControllerFeatureInvalidation* m_pInvalidationCallback;
+ css::uno::Reference< css::form::runtime::XFormOperations >
+ m_xFormOperations;
+
+ css::uno::Any m_aOperationError;
+
+ public:
+ /** constructs the helper from a <type scope="css::form::runtime">XFormController<type> instance
+
+ @param _rxController
+ The form controller which the helper should be responsible for. Must not
+ be <NULL/>, and must have a valid model (form).
+ @param _pInvalidationCallback
+ the callback for invalidating feature states
+ */
+ FormControllerHelper(
+ const css::uno::Reference< css::form::runtime::XFormController >& _rxController,
+ IControllerFeatureInvalidation* _pInvalidationCallback
+ );
+
+ // forwards to the XFormOperations implementation
+ css::uno::Reference< css::sdbc::XRowSet >
+ getCursor() const;
+ void getState(
+ sal_Int32 _nSlotId,
+ css::form::runtime::FeatureState& _out_rState
+ ) const;
+ bool isEnabled( sal_Int32 _nSlotId ) const;
+ void execute( sal_Int32 _nSlotId ) const;
+ void execute( sal_Int32 _nSlotId, const OUString& _rParamName, const css::uno::Any& _rParamValue ) const;
+ bool commitCurrentRecord() const;
+ bool commitCurrentControl( ) const;
+ bool isInsertionRow() const;
+ bool isModifiedRow() const;
+
+ bool canDoFormFilter() const;
+
+ /** disposes this instance.
+
+ After this method has been called, the instance is not functional anymore
+ */
+ void dispose();
+
+ private:
+ /// dtor
+ virtual ~FormControllerHelper() override;
+
+ // XFeatureInvalidation
+ virtual void SAL_CALL invalidateFeatures( const css::uno::Sequence< ::sal_Int16 >& Features ) override;
+ virtual void SAL_CALL invalidateAllFeatures() override;
+
+ // XSQLErrorListener
+ virtual void SAL_CALL errorOccured( const css::sdb::SQLErrorEvent& Event ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ enum FormOperation { EXECUTE, EXECUTE_ARGS, COMMIT_CONTROL, COMMIT_RECORD };
+
+ bool impl_operateForm_nothrow(
+ const FormOperation _eWhat,
+ const sal_Int16 _nFeature, /* ignore for COMMIT_* */
+ const css::uno::Sequence< css::beans::NamedValue >& _rArguments /* ignore except for EXECUTE_ARGS */
+ ) const;
+ bool impl_operateForm_nothrow( const FormOperation _eWhat ) const
+ {
+ return impl_operateForm_nothrow( _eWhat, 0, css::uno::Sequence< css::beans::NamedValue >() );
+ }
+
+ private:
+ FormControllerHelper( const FormControllerHelper& ) = delete;
+ FormControllerHelper& operator=( const FormControllerHelper& ) = delete;
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FORMCONTROLLING_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/formdispatchinterceptor.hxx b/svx/source/inc/formdispatchinterceptor.hxx
new file mode 100644
index 000000000..d2947eec5
--- /dev/null
+++ b/svx/source/inc/formdispatchinterceptor.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FORMDISPATCHINTERCEPTOR_HXX
+#define INCLUDED_SVX_SOURCE_INC_FORMDISPATCHINTERCEPTOR_HXX
+
+#include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
+#include <com/sun/star/frame/XDispatchProviderInterception.hpp>
+
+#include <cppuhelper/compbase.hxx>
+
+
+namespace svxform
+{
+
+ class DispatchInterceptor
+ {
+ public:
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Reference< css::frame::XDispatch> interceptedQueryDispatch(
+ const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags) = 0;
+
+ virtual ::osl::Mutex* getInterceptorMutex() = 0;
+
+ protected:
+ DispatchInterceptor() {}
+
+ ~DispatchInterceptor() {}
+ };
+
+
+ //=
+
+ typedef ::cppu::WeakComponentImplHelper< css::frame::XDispatchProviderInterceptor
+ , css::lang::XEventListener
+ > DispatchInterceptionMultiplexer_BASE;
+
+ class DispatchInterceptionMultiplexer final : public DispatchInterceptionMultiplexer_BASE
+ {
+ public:
+ css::uno::Reference< css::frame::XDispatchProviderInterception> getIntercepted() const { return m_xIntercepted; }
+
+ DispatchInterceptionMultiplexer(
+ const css::uno::Reference< css::frame::XDispatchProviderInterception>& _rToIntercept,
+ DispatchInterceptor* _pMaster
+ );
+
+ // css::frame::XDispatchProvider
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch( const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& aDescripts ) override;
+
+ // css::frame::XDispatchProviderInterceptor
+ virtual css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL getSlaveDispatchProvider( ) override;
+ virtual void SAL_CALL setSlaveDispatchProvider( const css::uno::Reference< css::frame::XDispatchProvider >& xNewDispatchProvider ) override;
+ virtual css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL getMasterDispatchProvider( ) override;
+ virtual void SAL_CALL setMasterDispatchProvider( const css::uno::Reference< css::frame::XDispatchProvider >& xNewSupplier ) override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ private:
+ virtual ~DispatchInterceptionMultiplexer() override;
+
+ void ImplDetach();
+
+ ::osl::Mutex m_aFallback;
+ ::osl::Mutex* m_pMutex;
+
+ // the component which's dispatches we're intercepting
+ css::uno::WeakReference< css::frame::XDispatchProviderInterception >
+ m_xIntercepted;
+ bool m_bListening;
+
+ // the real interceptor
+ DispatchInterceptor* m_pMaster;
+
+ // chaining
+ css::uno::Reference< css::frame::XDispatchProvider> m_xSlaveDispatcher;
+ css::uno::Reference< css::frame::XDispatchProvider> m_xMasterDispatcher;
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_FORMDISPATCHINTERCEPTOR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/formfeaturedispatcher.hxx b/svx/source/inc/formfeaturedispatcher.hxx
new file mode 100644
index 000000000..a57453dc8
--- /dev/null
+++ b/svx/source/inc/formfeaturedispatcher.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FORMFEATUREDISPATCHER_HXX
+#define INCLUDED_SVX_SOURCE_INC_FORMFEATUREDISPATCHER_HXX
+
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/form/runtime/XFormOperations.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+
+
+namespace svx
+{
+
+ typedef ::cppu::WeakImplHelper < css::frame::XDispatch
+ > OSingleFeatureDispatcher_Base;
+
+ class OSingleFeatureDispatcher final : public OSingleFeatureDispatcher_Base
+ {
+ public:
+ /** constructs the dispatcher
+
+ @param _rFeatureURL
+ the URL of the feature which this instance is responsible for
+
+ @param _nFeatureId
+ the feature which this instance is responsible for
+
+ @param _rController
+ the controller which is responsible for providing the state of feature of this instance,
+ and for executing it. After disposing the dispatcher instance, the controller will
+ not be accessed anymore
+
+ @see dispose
+ */
+ OSingleFeatureDispatcher(
+ const css::util::URL& _rFeatureURL,
+ const sal_Int16 _nFormFeature,
+ const css::uno::Reference< css::form::runtime::XFormOperations >& _rxFormOperations,
+ ::osl::Mutex& _rMutex
+ );
+
+ /** notifies all our listeners of the current state
+ */
+ void updateAllListeners();
+
+ private:
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& _rURL, const css::uno::Sequence< css::beans::PropertyValue >& _rArguments ) override;
+ virtual void SAL_CALL addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& _rxControl, const css::util::URL& _rURL ) override;
+ virtual void SAL_CALL removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& _rxControl, const css::util::URL& _rURL ) override;
+
+ /** notifies our current state to one or all listeners
+
+ @param _rxListener
+ the listener to notify. May be NULL, in this case all our listeners will be
+ notified with the current state
+
+ @param _rFreeForNotification
+ a guard which currently locks our mutex, and which is to be cleared
+ for actually doing the notification(s)
+ */
+ void notifyStatus(
+ const css::uno::Reference< css::frame::XStatusListener >& _rxListener,
+ ::osl::ClearableMutexGuard& _rFreeForNotification
+ );
+
+ /** retrieves the current status of our feature, in a format which can be used
+ for UNO notifications
+
+ @precond
+ our mutex is locked
+ */
+ void getUnoState( css::frame::FeatureStateEvent& /* [out] */ _rState ) const;
+
+ ::osl::Mutex& m_rMutex;
+ ::comphelper::OInterfaceContainerHelper3<css::frame::XStatusListener> m_aStatusListeners;
+ css::uno::Reference< css::form::runtime::XFormOperations >
+ m_xFormOperations;
+ const css::util::URL m_aFeatureURL;
+ css::uno::Any m_aLastKnownState;
+ const sal_Int16 m_nFormFeature;
+ bool m_bLastKnownEnabled;
+
+ };
+
+
+}
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/formtoolbars.hxx b/svx/source/inc/formtoolbars.hxx
new file mode 100644
index 000000000..1a77613bf
--- /dev/null
+++ b/svx/source/inc/formtoolbars.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FORMTOOLBARS_HXX
+#define INCLUDED_SVX_SOURCE_INC_FORMTOOLBARS_HXX
+
+#include <com/sun/star/frame/XLayoutManager.hpp>
+
+namespace svxform
+{
+ class FormToolboxes
+ {
+ private:
+ css::uno::Reference< css::frame::XLayoutManager > m_xLayouter;
+
+ public:
+ /** constructs an instance
+ @param _rxFrame
+ the frame to analyze
+ */
+ FormToolboxes(
+ const css::uno::Reference< css::frame::XFrame >& _rxFrame
+ );
+
+ public:
+ /** retrieves the URI for the toolbox associated with the given slot, depending
+ on the type of our document
+ */
+ static OUString
+ getToolboxResourceName( sal_uInt16 _nSlotId );
+
+ /** toggles the toolbox associated with the given slot
+ */
+ void toggleToolbox( sal_uInt16 _nSlotId ) const;
+
+ /** determines whether the toolbox associated with the given slot is currently visible
+ */
+ bool isToolboxVisible( sal_uInt16 _nSlotId ) const;
+
+ };
+
+}
+
+#endif // INCLUDED_SVX_SOURCE_INC_FORMTOOLBARS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/frmselimpl.hxx b/svx/source/inc/frmselimpl.hxx
new file mode 100644
index 000000000..79df99cfb
--- /dev/null
+++ b/svx/source/inc/frmselimpl.hxx
@@ -0,0 +1,285 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_FRMSELIMPL_HXX
+#define INCLUDED_SVX_SOURCE_INC_FRMSELIMPL_HXX
+
+#include <vcl/virdev.hxx>
+#include <vcl/image.hxx>
+#include <svx/frmsel.hxx>
+#include <svx/framelink.hxx>
+#include <svx/framelinkarray.hxx>
+#include <editeng/borderline.hxx>
+
+namespace svx {
+
+namespace a11y {
+ class AccFrameSelector;
+ class AccFrameSelectorChild;
+}
+
+class FrameBorder
+{
+public:
+ explicit FrameBorder(FrameBorderType eType);
+ static double GetDefaultPatternScale() { return 0.05; }
+
+ FrameBorderType GetType() const
+ {
+ return meType;
+ }
+
+ bool IsEnabled() const
+ {
+ return mbEnabled;
+ }
+ void Enable(FrameSelFlags nFlags);
+
+ FrameBorderState GetState() const
+ {
+ return meState;
+ }
+ void SetState(FrameBorderState eState);
+
+ bool IsSelected() const { return mbSelected; }
+ void Select( bool bSelect ) { mbSelected = bSelect; }
+
+ const editeng::SvxBorderLine& GetCoreStyle() const { return maCoreStyle; }
+ void SetCoreStyle( const editeng::SvxBorderLine* pStyle );
+
+ void SetUIColorPrim( const Color& rColor ) {maUIStyle.SetColorPrim( rColor ); }
+ void SetUIColorSecn( const Color& rColor ) {maUIStyle.SetColorSecn( rColor ); }
+ const frame::Style& GetUIStyle() const { return maUIStyle; }
+
+ void ClearFocusArea() { maFocusArea.Clear(); }
+ void AddFocusPolygon( const tools::Polygon& rFocus );
+ void MergeFocusToPolyPolygon( tools::PolyPolygon& rPPoly ) const;
+
+ void ClearClickArea() { maClickArea.Clear(); }
+ void AddClickRect( const tools::Rectangle& rRect );
+ bool ContainsClickPoint( const Point& rPos ) const;
+ tools::Rectangle GetClickBoundRect() const;
+
+ void SetKeyboardNeighbors(FrameBorderType eLeft, FrameBorderType eRight,
+ FrameBorderType eTop, FrameBorderType eBottom);
+ FrameBorderType GetKeyboardNeighbor( sal_uInt16 nKeyCode ) const;
+
+private:
+ const FrameBorderType meType; /// Frame border type (position in control).
+ FrameBorderState meState; /// Frame border state (on/off/don't care).
+ editeng::SvxBorderLine maCoreStyle; /// Core style from application.
+ frame::Style maUIStyle; /// Internal style to draw lines.
+ FrameBorderType meKeyLeft; /// Left neighbor for keyboard control.
+ FrameBorderType meKeyRight; /// Right neighbor for keyboard control.
+ FrameBorderType meKeyTop; /// Upper neighbor for keyboard control.
+ FrameBorderType meKeyBottom; /// Lower neighbor for keyboard control.
+ tools::PolyPolygon maFocusArea; /// Focus drawing areas.
+ tools::PolyPolygon maClickArea; /// Mouse click areas.
+ bool mbEnabled : 1; /// true = Border enabled in control.
+ bool mbSelected : 1; /// true = Border selected in control.
+};
+
+
+typedef std::vector< FrameBorder* > FrameBorderPtrVec;
+
+struct FrameSelectorImpl
+{
+ FrameSelector& mrFrameSel; /// The control itself.
+ ScopedVclPtr<VirtualDevice> mpVirDev; /// For all buffered drawing operations.
+ std::vector<Image> maArrows; /// Arrows in current system colors.
+ Color maBackCol; /// Background color.
+ Color maArrowCol; /// Selection arrow color.
+ Color maMarkCol; /// Selection marker color.
+ Color maHCLineCol; /// High contrast line color.
+ Point maVirDevPos; /// Position of virtual device in the control.
+
+ FrameBorder maLeft; /// All data of left frame border.
+ FrameBorder maRight; /// All data of right frame border.
+ FrameBorder maTop; /// All data of top frame border.
+ FrameBorder maBottom; /// All data of bottom frame border.
+ FrameBorder maHor; /// All data of inner horizontal frame border.
+ FrameBorder maVer; /// All data of inner vertical frame border.
+ FrameBorder maTLBR; /// All data of top-left to bottom-right frame border.
+ FrameBorder maBLTR; /// All data of bottom-left to top-right frame border.
+ editeng::SvxBorderLine maCurrStyle; /// Current style and color for new borders.
+ frame::Array maArray; /// Frame link array to draw an array of frame borders.
+
+ FrameSelFlags mnFlags; /// Flags for enabled frame borders.
+ FrameBorderPtrVec maAllBorders; /// Pointers to all frame borders.
+ FrameBorderPtrVec maEnabBorders; /// Pointers to enables frame borders.
+ Link<LinkParamNone*,void> maSelectHdl; /// Selection handler.
+
+ tools::Long mnCtrlSize; /// Size of the control (always square).
+ tools::Long mnArrowSize; /// Size of an arrow image.
+ tools::Long mnLine1; /// Middle of left/top frame borders.
+ tools::Long mnLine2; /// Middle of inner frame borders.
+ tools::Long mnLine3; /// Middle of right/bottom frame borders.
+ tools::Long mnFocusOffs; /// Offset from frame border middle to draw focus.
+
+ bool mbHor; /// true = Inner horizontal frame border enabled.
+ bool mbVer; /// true = Inner vertical frame border enabled.
+ bool mbTLBR; /// true = Top-left to bottom-right frame border enabled.
+ bool mbBLTR; /// true = Bottom-left to top-right frame border enabled.
+ bool mbFullRepaint; /// Used for repainting (false = only copy virtual device).
+ bool mbAutoSelect; /// true = Auto select a frame border, if focus reaches control.
+ bool mbHCMode; /// true = High contrast mode.
+
+ std::vector<rtl::Reference<a11y::AccFrameSelectorChild>>
+ maChildVec; /// Pointers to accessibility objects for frame borders.
+ explicit FrameSelectorImpl( FrameSelector& rFrameSel );
+ ~FrameSelectorImpl();
+
+ // initialization
+ /** Initializes the control, enables/disables frame borders according to flags. */
+ void Initialize( FrameSelFlags nFlags );
+
+ /** Fills all color members from current style settings. */
+ void InitColors();
+ /** Creates the image list with selection arrows regarding current style settings. */
+ void InitArrowImageList();
+ /** Initializes global coordinates. */
+ void InitGlobalGeometry();
+ /** Initializes coordinates of all frame borders. */
+ void InitBorderGeometry();
+ /** Draws the entire control into the internal virtual device. */
+ void InitVirtualDevice();
+ /** call this to recalculate based on parent size */
+ void sizeChanged();
+
+ // frame border access
+ /** Returns the object representing the specified frame border. */
+ const FrameBorder& GetBorder( FrameBorderType eBorder ) const;
+ /** Returns the object representing the specified frame border (write access). */
+ FrameBorder& GetBorderAccess( FrameBorderType eBorder );
+
+ // drawing
+ /** Draws the background of the entire control (the gray areas between borders). */
+ void DrawBackground();
+
+ /** Draws selection arrows for the specified frame border. */
+ void DrawArrows( const FrameBorder& rBorder );
+
+ /** Returns the color that has to be used to draw a frame border. */
+ Color GetDrawLineColor( const Color& rColor ) const;
+ /** Draws all frame borders. */
+ void DrawAllFrameBorders();
+
+ /** Draws all contents of the control. */
+ void DrawVirtualDevice();
+ /** Copies contents of the virtual device to the control. */
+ void CopyVirDevToControl(vcl::RenderContext& rRenderContext);
+
+ /** Draws tracking rectangles for all selected frame borders. */
+ void DrawAllTrackingRects(vcl::RenderContext& rRenderContext);
+
+ /** Converts a mouse position to the virtual device position. */
+ Point GetDevPosFromMousePos( const Point& rMousePos ) const;
+
+ /** Invalidates the control.
+ @param bFullRepaint true = Full repaint; false = update selection only. */
+ void DoInvalidate( bool bFullRepaint );
+
+ // frame border state and style
+ /** Sets the state of the specified frame border. */
+ void SetBorderState( FrameBorder& rBorder, FrameBorderState eState );
+ /** Sets the core style of the specified frame border, or hides the frame border, if pStyle is 0. */
+ void SetBorderCoreStyle( FrameBorder& rBorder, const editeng::SvxBorderLine* pStyle );
+
+ /** Changes the state of a frame border after a control event (mouse/keyboard). */
+ void ToggleBorderState( FrameBorder& rBorder );
+
+ // frame border selection
+ /** Selects a frame border and schedules redraw. */
+ void SelectBorder( FrameBorder& rBorder, bool bSelect );
+ /** Grabs focus without auto-selection of a frame border, if no border selected. */
+ void SilentGrabFocus();
+
+ /** Returns true, if all selected frame borders are equal (or if nothing is selected). */
+ bool SelectedBordersEqual() const;
+};
+
+
+/** Dummy predicate for frame border iterators to use all borders in a container. */
+struct FrameBorderDummy_Pred
+{
+ bool operator()( const FrameBorder* ) const { return true; }
+};
+
+/** Predicate for frame border iterators to use only visible borders in a container. */
+struct FrameBorderVisible_Pred
+{
+ bool operator()( const FrameBorder* pBorder ) const { return pBorder->GetState() == FrameBorderState::Show; }
+};
+
+/** Predicate for frame border iterators to use only selected borders in a container. */
+struct FrameBorderSelected_Pred
+{
+ bool operator()( const FrameBorder* pBorder ) const { return pBorder->IsSelected(); }
+};
+
+/** Template class for all types of frame border iterators. */
+template< typename Cont, typename Iter, typename Pred >
+class FrameBorderIterBase
+{
+public:
+ typedef Cont container_type;
+ typedef Iter iterator_type;
+ typedef typename Cont::value_type value_type;
+ typedef FrameBorderIterBase<Cont, Iter, Pred> this_type;
+
+ explicit FrameBorderIterBase( container_type& rCont );
+ bool Is() const { return maIt != maEnd; }
+ this_type& operator++();
+ value_type operator*() const { return *maIt; }
+
+private:
+ iterator_type maIt;
+ iterator_type maEnd;
+ Pred maPred;
+};
+
+/** Iterator for constant svx::FrameBorder containers, iterates over all borders. */
+typedef FrameBorderIterBase< const FrameBorderPtrVec, FrameBorderPtrVec::const_iterator, FrameBorderDummy_Pred >
+ FrameBorderCIter;
+
+/** Iterator for mutable svx::FrameBorder containers, iterates over all borders. */
+typedef FrameBorderIterBase< FrameBorderPtrVec, FrameBorderPtrVec::iterator, FrameBorderDummy_Pred >
+ FrameBorderIter;
+
+/** Iterator for constant svx::FrameBorder containers, iterates over visible borders. */
+typedef FrameBorderIterBase< const FrameBorderPtrVec, FrameBorderPtrVec::const_iterator, FrameBorderVisible_Pred >
+ VisFrameBorderCIter;
+
+/** Iterator for mutable svx::FrameBorder containers, iterates over visible borders. */
+typedef FrameBorderIterBase< FrameBorderPtrVec, FrameBorderPtrVec::iterator, FrameBorderVisible_Pred >
+ VisFrameBorderIter;
+
+/** Iterator for constant svx::FrameBorder containers, iterates over selected borders. */
+typedef FrameBorderIterBase< const FrameBorderPtrVec, FrameBorderPtrVec::const_iterator, FrameBorderSelected_Pred >
+ SelFrameBorderCIter;
+
+/** Iterator for mutable svx::FrameBorder containers, iterates over selected borders. */
+typedef FrameBorderIterBase< FrameBorderPtrVec, FrameBorderPtrVec::iterator, FrameBorderSelected_Pred >
+ SelFrameBorderIter;
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/gridcell.hxx b/svx/source/inc/gridcell.hxx
new file mode 100644
index 000000000..9ee419ea1
--- /dev/null
+++ b/svx/source/inc/gridcell.hxx
@@ -0,0 +1,1067 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_GRIDCELL_HXX
+#define INCLUDED_SVX_SOURCE_INC_GRIDCELL_HXX
+
+#include <memory>
+#include <svx/gridctrl.hxx>
+
+#include "sqlparserclient.hxx"
+
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/form/XBoundControl.hpp>
+#include <com/sun/star/awt/XTextComponent.hpp>
+#include <com/sun/star/awt/XListBox.hpp>
+#include <com/sun/star/awt/XComboBox.hpp>
+#include <com/sun/star/awt/TextAlign.hpp>
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/XCheckBox.hpp>
+#include <com/sun/star/awt/XButton.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/form/XChangeBroadcaster.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+
+#include <comphelper/propmultiplex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/uno3.hxx>
+#include <connectivity/formattedcolumnvalue.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/component.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <cppuhelper/implbase2.hxx>
+#include <tools/diagnose_ex.h>
+
+class DbCellControl;
+class Edit;
+class FmXGridCell;
+namespace dbtools {
+ class FormattedColumnValue;
+}
+
+// DbGridColumn, column description
+
+class DbGridColumn
+{
+ friend class DbGridControl;
+
+ css::uno::Reference< css::beans::XPropertySet > m_xModel;
+ css::uno::Reference< css::beans::XPropertySet > m_xField; // connection to the database field
+ ::svt::CellControllerRef m_xController; // structure for managing the controls for a column
+ // this is positioned by the DbBrowseBox on the respective
+ // cells of a column
+ rtl::Reference<FmXGridCell> m_pCell;
+ DbGridControl& m_rParent;
+ sal_Int32 m_nLastVisibleWidth; // only valid if m_bHidden == sal_True
+ sal_Int32 m_nFormatKey;
+ sal_Int16 m_nFieldType;
+ sal_Int16 m_nTypeId;
+ sal_uInt16 m_nId;
+ sal_Int16 m_nFieldPos;
+ sal_Int16 m_nAlign; // specified with TXT_ALIGN_LEFT...
+ bool m_bReadOnly : 1;
+ bool m_bAutoValue : 1;
+ bool m_bInSave : 1;
+ bool m_bNumeric : 1;
+ bool m_bObject : 1; // does the column reference an object datatype?
+ bool m_bHidden : 1;
+ bool m_bLocked : 1;
+
+ static ::svt::CellControllerRef s_xEmptyController;
+ // used by locked columns
+public:
+ DbGridColumn(sal_uInt16 _nId, DbGridControl& rParent)
+ :m_rParent(rParent)
+ ,m_nLastVisibleWidth(-1)
+ ,m_nFormatKey(0)
+ ,m_nFieldType(0)
+ ,m_nTypeId(0)
+ ,m_nId(_nId)
+ ,m_nFieldPos(-1)
+ ,m_nAlign(css::awt::TextAlign::LEFT)
+ ,m_bReadOnly(false)
+ ,m_bAutoValue(false)
+ ,m_bInSave(false)
+ ,m_bNumeric(false)
+ ,m_bObject(false)
+ ,m_bHidden(false)
+ ,m_bLocked(false)
+ {
+ }
+
+ ~DbGridColumn();
+
+ const css::uno::Reference< css::beans::XPropertySet >& getModel() const { return m_xModel; }
+ void setModel(const css::uno::Reference< css::beans::XPropertySet >& _xModel);
+
+
+ sal_uInt16 GetId() const {return m_nId;}
+ bool IsReadOnly() const {return m_bReadOnly;}
+ bool IsAutoValue() const {return m_bAutoValue;}
+ sal_Int16 GetAlignment() const {return m_nAlign;}
+ sal_Int16 GetFieldPos() const {return m_nFieldPos; }
+ bool IsNumeric() const {return m_bNumeric;}
+ bool IsHidden() const {return m_bHidden;}
+ sal_Int32 GetKey() const {return m_nFormatKey;}
+ const ::svt::CellControllerRef& GetController() const {return m_bLocked ? s_xEmptyController : m_xController;}
+ const css::uno::Reference< css::beans::XPropertySet >& GetField() const {return m_xField;}
+ DbGridControl& GetParent() const {return m_rParent;}
+ FmXGridCell* GetCell() const {return m_pCell.get();}
+
+ css::uno::Reference< css::sdb::XColumn > GetCurrentFieldValue() const;
+
+ // Drawing a field at a position. If a view is set, it takes over the drawing,
+ // e.g., for checkboxes.
+ void Paint(OutputDevice& rDev,
+ const tools::Rectangle& rRect,
+ const DbGridRow* pRow,
+ const css::uno::Reference< css::util::XNumberFormatter >& xFormatter);
+
+
+ // Initializing in the alive mode.
+ // If no ColumnController is set, a default initialization is performed.
+ void CreateControl(sal_Int32 _nFieldPos, const css::uno::Reference< css::beans::XPropertySet >& xField, sal_Int32 nTypeId);
+ void UpdateControl()
+ {
+ css::uno::Reference< css::beans::XPropertySet > xField(m_xField);
+ CreateControl(m_nFieldPos, xField, m_nTypeId);
+ }
+
+ // Editing a Zelle
+ void UpdateFromField(const DbGridRow* pRow, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter);
+ bool Commit();
+
+ // releasing all the data required for the AliveMode
+ void Clear();
+
+ OUString GetCellText(const DbGridRow* pRow, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) const;
+ OUString GetCellText(const css::uno::Reference< css::sdb::XColumn >& xField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) const;
+
+ void SetReadOnly(bool bRead){m_bReadOnly = bRead;}
+ void SetObject(sal_Int16 nPos) {m_bObject = m_bReadOnly = true; m_nFieldPos = nPos;}
+
+ void ImplInitWindow( vcl::Window const & rParent, const InitWindowFacet _eInitWhat );
+
+ // properties that can bleed through onto the css::frame::Controller
+ sal_Int16 SetAlignment(sal_Int16 _nAlign);
+ // if _nAlign is -1, the alignment is calculated from the type of the field we are bound to
+ // the value really set is returned
+ sal_Int16 SetAlignmentFromModel(sal_Int16 nStandardAlign);
+ // set the alignment according to the "Align"-property of m_xModel, use the given standard
+ // alignment if the property if void, return the really set alignment
+
+ // column locking
+ bool isLocked() const { return m_bLocked; }
+ void setLock(bool _bLock);
+
+private:
+ /** attaches or detaches our cell object to the SctriptEventAttacherManager implemented
+ by our model's parent
+ */
+ void impl_toggleScriptManager_nothrow( bool _bAttach );
+};
+
+
+// DbCellControl, provides the data for a CellController.
+// Is usually only required for complex controls such as combo boxes.
+
+class DbCellControl
+ :public cppu::BaseMutex // _before_ the listener, so the listener is to be destroyed first!
+ ,public ::comphelper::OPropertyChangeListener
+{
+private:
+ rtl::Reference<::comphelper::OPropertyChangeMultiplexer> m_pModelChangeBroadcaster;
+ rtl::Reference<::comphelper::OPropertyChangeMultiplexer> m_pFieldChangeBroadcaster;
+
+private:
+ bool m_bTransparent : 1;
+ bool m_bAlignedController : 1;
+ bool m_bAccessingValueProperty : 1;
+
+ css::uno::Reference< css::sdbc::XRowSet >
+ m_xCursor;
+
+protected:
+ DbGridColumn& m_rColumn;
+ VclPtr<svt::ControlBase> m_pPainter;
+ VclPtr<svt::ControlBase> m_pWindow;
+
+protected:
+ // attribute access
+ const css::uno::Reference< css::sdbc::XRowSet >& getCursor() const { return m_xCursor; }
+
+ // control transparency
+ bool isTransparent( ) const { return m_bTransparent; }
+ void setTransparent( bool _bSet ) { m_bTransparent = _bSet; }
+
+ // control alignment
+ void setAlignedController( bool _bAlign ) { m_bAlignedController = _bAlign; }
+
+
+ /** determined whether or not the value property is locked
+ @see lockValueProperty
+ */
+ inline bool isValuePropertyLocked() const;
+
+ /** locks the listening at the value property.
+ <p>This means that every subsequent change now done on the value property of the model ("Text", or "Value",
+ or whatever) is then ignored.<br/>
+ This base class uses this setting in <method>Commit</method>.</p>
+ @precond
+ Value locking can't be nested
+ @see unlockValueProperty
+ */
+ inline void lockValueProperty();
+ /** unlocks the listening at the value property
+ @see lockValueProperty
+ */
+ inline void unlockValueProperty();
+
+protected:
+ // adds the given property to the list of properties which we listen for
+ void doPropertyListening( const OUString& _rPropertyName );
+
+ // called whenever a property which affects field settings in general is called
+ // you should overwrite this method for every property you add yourself as listener to
+ // with doPropertyListening
+ virtual void implAdjustGenericFieldSetting( const css::uno::Reference< css::beans::XPropertySet >& _rxModel );
+
+ // called by _propertyChanged if a property which denotes the column value has changed
+ void implValuePropertyChanged( );
+
+
+public:
+ DbCellControl(DbGridColumn& _rColumn);
+ virtual ~DbCellControl() override;
+
+ svt::ControlBase& GetWindow() const
+ {
+ ENSURE_OR_THROW( m_pWindow, "no window" );
+ return *m_pWindow;
+ }
+
+ // control alignment
+ bool isAlignedController() const { return m_bAlignedController; }
+ void AlignControl(sal_Int16 nAlignment);
+
+ void SetTextLineColor();
+ void SetTextLineColor(const Color& _rColor);
+
+ // initializing before a control is displayed
+ virtual void Init( BrowserDataWin& rParent, const css::uno::Reference< css::sdbc::XRowSet >& xCursor );
+ virtual ::svt::CellControllerRef CreateController() const = 0;
+
+ // writing the value into the model
+ bool Commit();
+
+ // Formatting the field data to output text
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) = 0;
+
+ virtual void Update(){}
+ // Refresh the control by the field data
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) = 0;
+
+ // painting a cell content in the specified rectangle
+ virtual void PaintFieldToCell( OutputDevice& rDev, const tools::Rectangle& rRect, const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter);
+ virtual void PaintCell( OutputDevice& _rDev, const tools::Rectangle& _rRect );
+
+ void ImplInitWindow( vcl::Window const & rParent, const InitWindowFacet _eInitWhat );
+
+ double GetValue(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) const;
+
+protected:
+ void invalidatedController();
+
+ /** commits the content of the control (e.g. the text of an edit field) into the column model
+ (e.g. the "Text" property of the model).
+ <p>To be overwritten in derived classes.</p>
+ @see updateFromModel
+ */
+ virtual bool commitControl( ) = 0;
+
+ /** updates the current content of the control (e.g. the text of an edit field) from the column model
+ (e.g. the "Text" property of the model).
+ <p>To be overwritten in derived classes.</p>
+ @precond
+ NULL != _rxModel
+ @precond
+ NULL != m_pWindow
+
+ @see commitControl
+ */
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) = 0;
+
+protected:
+// OPropertyChangeListener
+ virtual void _propertyChanged(const css::beans::PropertyChangeEvent& evt) override;
+
+private:
+ void implDoPropertyListening( const OUString& _rPropertyName, bool _bWarnIfNotExistent );
+
+ /// updates the "readonly" setting on m_pWindow, according to the respective property value in the given model
+ void implAdjustReadOnly( const css::uno::Reference< css::beans::XPropertySet >& _rxModel,bool i_bReadOnly );
+
+ /// updates the "enabled" setting on m_pWindow, according to the respective property value in the given model
+ void implAdjustEnabled( const css::uno::Reference< css::beans::XPropertySet >& _rxModel );
+};
+
+
+inline bool DbCellControl::isValuePropertyLocked() const
+{
+ return m_bAccessingValueProperty;
+}
+
+
+inline void DbCellControl::lockValueProperty()
+{
+ OSL_ENSURE( !isValuePropertyLocked(), "DbCellControl::lockValueProperty: not to be nested!" );
+ m_bAccessingValueProperty = true;
+}
+
+
+inline void DbCellControl::unlockValueProperty()
+{
+ OSL_ENSURE( isValuePropertyLocked(), "DbCellControl::lockValueProperty: not locked so far!" );
+ m_bAccessingValueProperty = false;
+}
+
+
+/** a field which is bound to a column which supports the MaxTextLen property
+*/
+class DbLimitedLengthField : public DbCellControl
+{
+public:
+
+protected:
+ DbLimitedLengthField( DbGridColumn& _rColumn );
+
+protected:
+ // DbCellControl
+ virtual void implAdjustGenericFieldSetting( const css::uno::Reference< css::beans::XPropertySet >& _rxModel ) override;
+
+protected:
+ void implSetMaxTextLen( sal_Int16 _nMaxLen )
+ {
+ implSetEffectiveMaxTextLen(_nMaxLen);
+ }
+ virtual void implSetEffectiveMaxTextLen( sal_Int32 _nMaxLen );
+};
+
+
+class DbTextField final : public DbLimitedLengthField
+{
+ std::unique_ptr<::svt::IEditImplementation> m_pEdit;
+ std::unique_ptr<::svt::IEditImplementation> m_pPainterImplementation;
+ bool m_bIsMultiLineEdit;
+
+ virtual ~DbTextField( ) override;
+
+public:
+ DbTextField(DbGridColumn& _rColumn);
+
+ ::svt::IEditImplementation* GetEditImplementation() { return m_pEdit.get(); }
+ bool IsMultiLineEdit() const { return m_bIsMultiLineEdit; }
+
+ virtual void Init( BrowserDataWin& rParent, const css::uno::Reference< css::sdbc::XRowSet >& xCursor ) override;
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+ virtual ::svt::CellControllerRef CreateController() const override;
+ virtual void PaintFieldToCell( OutputDevice& _rDev, const tools::Rectangle& _rRect,
+ const css::uno::Reference< css::sdb::XColumn >& _rxField,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxFormatter ) override;
+
+private:
+ // DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+ // DbLimitedLengthField
+ virtual void implSetEffectiveMaxTextLen( sal_Int32 _nMaxLen ) override;
+};
+
+
+class DbFormattedField final : public DbLimitedLengthField
+{
+public:
+ DbFormattedField(DbGridColumn& _rColumn);
+ virtual ~DbFormattedField() override;
+
+ virtual void Init( BrowserDataWin& rParent, const css::uno::Reference< css::sdbc::XRowSet >& xCursor ) override;
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+ virtual ::svt::CellControllerRef CreateController() const override;
+
+private:
+ // DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+
+ // OPropertyChangeListener
+ virtual void _propertyChanged(const css::beans::PropertyChangeEvent& evt) override;
+
+ css::uno::Reference< css::util::XNumberFormatsSupplier > m_xSupplier;
+};
+
+
+class DbCheckBox final : public DbCellControl
+{
+public:
+ DbCheckBox(DbGridColumn& _rColumn);
+
+ virtual void Init( BrowserDataWin& rParent, const css::uno::Reference< css::sdbc::XRowSet >& xCursor ) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+ virtual ::svt::CellControllerRef CreateController() const override;
+ virtual void PaintFieldToCell(OutputDevice& rDev, const tools::Rectangle& rRect,
+ const css::uno::Reference< css::sdb::XColumn >& _rxField,
+ const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+ virtual void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect) override;
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+
+private:
+ // DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+};
+
+
+class DbComboBox final : public DbCellControl
+{
+
+public:
+ DbComboBox(DbGridColumn& _rColumn);
+
+ virtual void Init( BrowserDataWin& rParent, const css::uno::Reference< css::sdbc::XRowSet >& xCursor ) override;
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+ virtual ::svt::CellControllerRef CreateController() const override;
+
+ void SetList(const css::uno::Any& rItems);
+
+private:
+ // DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+
+ virtual void implAdjustGenericFieldSetting( const css::uno::Reference< css::beans::XPropertySet >& _rxModel ) override;
+
+ // OPropertyChangeListener
+ virtual void _propertyChanged(const css::beans::PropertyChangeEvent& evt) override;
+};
+
+
+class DbListBox final : public DbCellControl
+{
+ bool m_bBound : 1;
+ css::uno::Sequence< OUString > m_aValueList;
+
+public:
+ DbListBox(DbGridColumn& _rColumn);
+
+ virtual void Init( BrowserDataWin& rParent, const css::uno::Reference< css::sdbc::XRowSet >& xCursor ) override;
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+ virtual ::svt::CellControllerRef CreateController() const override;
+
+ void SetList(const css::uno::Any& rItems);
+
+private:
+ // DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+
+ virtual void implAdjustGenericFieldSetting( const css::uno::Reference< css::beans::XPropertySet >& _rxModel ) override;
+
+ // OPropertyChangeListener
+ virtual void _propertyChanged(const css::beans::PropertyChangeEvent& evt) override;
+};
+
+
+class DbPatternField final : public DbCellControl
+{
+public:
+ DbPatternField( DbGridColumn& _rColumn, const css::uno::Reference<css::uno::XComponentContext>& _rContext );
+ virtual void Init( BrowserDataWin& rParent, const css::uno::Reference< css::sdbc::XRowSet >& xCursor ) override;
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+ virtual ::svt::CellControllerRef CreateController() const override;
+
+private:
+ /// DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+
+ virtual void implAdjustGenericFieldSetting( const css::uno::Reference< css::beans::XPropertySet >& _rxModel ) override;
+
+ OUString impl_formatText(const OUString& _rText);
+
+ ::std::unique_ptr< ::dbtools::FormattedColumnValue > m_pValueFormatter;
+ ::std::unique_ptr< ::dbtools::FormattedColumnValue > m_pPaintFormatter;
+ css::uno::Reference<css::uno::XComponentContext> m_xContext;
+};
+
+
+class DbSpinField : public DbCellControl
+{
+private:
+ sal_Int16 m_nStandardAlign;
+
+public:
+
+protected:
+ DbSpinField( DbGridColumn& _rColumn, sal_Int16 _nStandardAlign = css::awt::TextAlign::RIGHT );
+
+public:
+ virtual void Init( BrowserDataWin& rParent, const css::uno::Reference< css::sdbc::XRowSet >& _rxCursor ) override;
+ virtual ::svt::CellControllerRef CreateController() const override;
+
+protected:
+ virtual VclPtr<svt::ControlBase> createField(
+ BrowserDataWin* _pParent,
+ bool bSpinButton,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxModel
+ ) = 0;
+};
+
+class DbDateField final : public DbSpinField
+{
+public:
+ DbDateField(DbGridColumn& _rColumn);
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+
+private:
+ // DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+
+ // DbSpinField
+ virtual VclPtr<svt::ControlBase> createField(
+ BrowserDataWin* _pParent,
+ bool bSpinButton,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxModel
+ ) override;
+
+ /// initializes everything which relates to the properties describing the numeric behaviour
+ virtual void implAdjustGenericFieldSetting( const css::uno::Reference< css::beans::XPropertySet >& _rxModel ) override;
+};
+
+class DbTimeField final : public DbSpinField
+{
+public:
+ DbTimeField(DbGridColumn& _rColumn);
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+
+private:
+ // DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+
+ // DbSpinField
+ virtual VclPtr<svt::ControlBase> createField(
+ BrowserDataWin* _pParent,
+ bool bSpinButton,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxModel
+ ) override;
+
+ /// initializes everything which relates to the properties describing the numeric behaviour
+ virtual void implAdjustGenericFieldSetting( const css::uno::Reference< css::beans::XPropertySet >& _rxModel ) override;
+};
+
+class DbCurrencyField final : public DbSpinField
+{
+public:
+ DbCurrencyField(DbGridColumn& _rColumn);
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+
+private:
+ // DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+
+ // DbSpinField
+ virtual VclPtr<svt::ControlBase> createField(
+ BrowserDataWin* _pParent,
+ bool bSpinButton,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxModel
+ ) override;
+
+ /// initializes everything which relates to the properties describing the numeric behaviour
+ virtual void implAdjustGenericFieldSetting( const css::uno::Reference< css::beans::XPropertySet >& _rxModel ) override;
+};
+
+class DbNumericField final : public DbSpinField
+{
+public:
+ DbNumericField(DbGridColumn& _rColumn);
+
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+
+private:
+ // DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+
+ // DbSpinField
+ virtual VclPtr<svt::ControlBase> createField(
+ BrowserDataWin* _pParent,
+ bool bSpinButton,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxModel
+ ) override;
+
+ /// initializes everything which relates to the properties describing the numeric behaviour
+ void implAdjustGenericFieldSetting( const css::uno::Reference< css::beans::XPropertySet >& _rxModel ) override;
+};
+
+class DbFilterField final
+ :public DbCellControl
+ ,public ::svxform::OSQLParserClient
+{
+public:
+ DbFilterField(const css::uno::Reference< css::uno::XComponentContext >& rxContext, DbGridColumn& _rColumn);
+ virtual ~DbFilterField() override;
+
+ virtual void Init( BrowserDataWin& rParent, const css::uno::Reference< css::sdbc::XRowSet >& xCursor ) override;
+ virtual ::svt::CellControllerRef CreateController() const override;
+ virtual void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect) override;
+ virtual void Update() override;
+ virtual OUString GetFormatText(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter, const Color** ppColor = nullptr) override;
+ virtual void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& _rxField, const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+
+ const OUString& GetText() const {return m_aText;}
+ void SetText(const OUString& rText);
+
+ void SetCommitHdl( const Link<DbFilterField&,void>& rLink ) { m_aCommitLink = rLink; }
+
+private:
+ // DbCellControl
+ virtual bool commitControl( ) override;
+ virtual void updateFromModel( css::uno::Reference< css::beans::XPropertySet > _rxModel ) override;
+
+ void SetList(const css::uno::Any& rItems, bool bComboBox);
+ void CreateControl(BrowserDataWin* pParent, const css::uno::Reference< css::beans::XPropertySet >& xModel);
+ DECL_LINK(OnToggle, weld::CheckButton&, void);
+
+ css::uno::Sequence< OUString > m_aValueList;
+ OUString m_aText;
+ Link<DbFilterField&,void> m_aCommitLink;
+ sal_Int16 m_nControlClass;
+ bool m_bFilterList : 1;
+ bool m_bFilterListFilled : 1;
+};
+
+
+// Base class providing the access to a grid cell
+
+typedef ::cppu::ImplHelper2 < css::awt::XControl
+ , css::form::XBoundControl
+ > FmXGridCell_Base;
+typedef ::cppu::ImplHelper1 < css::awt::XWindow
+ > FmXGridCell_WindowBase;
+class FmXGridCell :public ::cppu::OComponentHelper
+ ,public FmXGridCell_Base
+ ,public FmXGridCell_WindowBase
+{
+protected:
+ ::osl::Mutex m_aMutex;
+ DbGridColumn* m_pColumn;
+ std::unique_ptr<DbCellControl> m_pCellControl;
+
+private:
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XWindowListener> m_aWindowListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XFocusListener> m_aFocusListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XKeyListener> m_aKeyListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XMouseListener> m_aMouseListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XMouseMotionListener> m_aMouseMotionListeners;
+
+protected:
+ virtual ~FmXGridCell() override;
+
+public:
+ FmXGridCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl );
+ void init();
+
+ DECLARE_UNO3_AGG_DEFAULTS(FmXGridCell, OComponentHelper)
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override;
+
+ void SetTextLineColor();
+ void SetTextLineColor(const Color& _rColor);
+
+// XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::lang::XComponent
+ virtual void SAL_CALL dispose() override {OComponentHelper::dispose();}
+ virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener >& aListener) override { OComponentHelper::addEventListener(aListener);}
+ virtual void SAL_CALL removeEventListener(const css::uno::Reference< css::lang::XEventListener >& aListener) override { OComponentHelper::removeEventListener(aListener);}
+
+// css::awt::XControl
+ virtual void SAL_CALL setContext(const css::uno::Reference< css::uno::XInterface >& /*Context*/) override {}
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getContext() override;
+ virtual void SAL_CALL createPeer(const css::uno::Reference< css::awt::XToolkit >& /*Toolkit*/, const css::uno::Reference< css::awt::XWindowPeer >& /*Parent*/) override {}
+
+ virtual css::uno::Reference< css::awt::XWindowPeer > SAL_CALL getPeer() override {return css::uno::Reference< css::awt::XWindowPeer > ();}
+ virtual sal_Bool SAL_CALL setModel(const css::uno::Reference< css::awt::XControlModel >& /*Model*/) override {return false;}
+ virtual css::uno::Reference< css::awt::XControlModel > SAL_CALL getModel() override;
+ virtual css::uno::Reference< css::awt::XView > SAL_CALL getView() override {return css::uno::Reference< css::awt::XView > ();}
+ virtual void SAL_CALL setDesignMode(sal_Bool /*bOn*/) override {}
+ virtual sal_Bool SAL_CALL isDesignMode() override {return false;}
+ virtual sal_Bool SAL_CALL isTransparent() override {return false;}
+
+// css::form::XBoundControl
+ virtual sal_Bool SAL_CALL getLock() override;
+ virtual void SAL_CALL setLock(sal_Bool _bLock) override;
+
+ // XWindow
+ virtual void SAL_CALL setPosSize( ::sal_Int32 X, ::sal_Int32 Y, ::sal_Int32 Width, ::sal_Int32 Height, ::sal_Int16 Flags ) override;
+ virtual css::awt::Rectangle SAL_CALL getPosSize( ) override;
+ virtual void SAL_CALL setVisible( sal_Bool Visible ) override;
+ virtual void SAL_CALL setEnable( sal_Bool Enable ) override;
+ virtual void SAL_CALL setFocus( ) override;
+ virtual void SAL_CALL addWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override;
+ virtual void SAL_CALL removeWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override;
+ virtual void SAL_CALL addFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override;
+ virtual void SAL_CALL removeFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override;
+ virtual void SAL_CALL addKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override;
+ virtual void SAL_CALL removeKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override;
+ virtual void SAL_CALL addMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override;
+ virtual void SAL_CALL addMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL removeMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override;
+ virtual void SAL_CALL addPaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+ virtual void SAL_CALL removePaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override;
+
+ bool Commit() {return m_pCellControl->Commit();}
+ void ImplInitWindow( vcl::Window const & rParent, const InitWindowFacet _eInitWhat )
+ { m_pCellControl->ImplInitWindow( rParent, _eInitWhat ); }
+
+ bool isAlignedController() const { return m_pCellControl->isAlignedController(); }
+ void AlignControl(sal_Int16 nAlignment)
+ { m_pCellControl->AlignControl(nAlignment);}
+
+protected:
+ // default implementations call our focus listeners, don't forget to call them if you override this
+ virtual void onFocusGained( const css::awt::FocusEvent& _rEvent );
+ virtual void onFocusLost( const css::awt::FocusEvent& _rEvent );
+
+private:
+ svt::ControlBase* getEventWindow() const;
+ DECL_LINK(OnFocusGained, LinkParamNone*, void);
+ DECL_LINK(OnFocusLost, LinkParamNone*, void);
+ DECL_LINK(OnMousePress, const MouseEvent&, void);
+ DECL_LINK(OnMouseRelease, const MouseEvent&, void);
+ DECL_LINK(OnMouseMove, const MouseEvent&, void);
+ DECL_LINK(OnKeyInput, const KeyEvent&, void);
+ DECL_LINK(OnKeyRelease, const KeyEvent&, void);
+};
+
+
+class FmXDataCell : public FmXGridCell
+{
+public:
+ FmXDataCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl )
+ :FmXGridCell( pColumn, std::move(pControl) )
+ {
+ }
+
+ virtual void PaintFieldToCell(OutputDevice& rDev,
+ const tools::Rectangle& rRect,
+ const css::uno::Reference< css::sdb::XColumn >& xField,
+ const css::uno::Reference< css::util::XNumberFormatter >& xFormatter);
+
+ void UpdateFromField(const css::uno::Reference< css::sdb::XColumn >& xField,
+ const css::uno::Reference< css::util::XNumberFormatter >& xFormatter)
+ { m_pCellControl->UpdateFromField(xField, xFormatter); }
+
+protected:
+ void UpdateFromColumn();
+};
+
+
+class FmXTextCell : public FmXDataCell
+{
+protected:
+ bool m_bIsMultiLineText;
+
+public:
+ FmXTextCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl );
+
+ virtual void PaintFieldToCell(OutputDevice& rDev,
+ const tools::Rectangle& rRect,
+ const css::uno::Reference< css::sdb::XColumn >& xField,
+ const css::uno::Reference< css::util::XNumberFormatter >& xFormatter) override;
+
+ OUString GetText(const css::uno::Reference< css::sdb::XColumn >& _rxField,
+ const css::uno::Reference< css::util::XNumberFormatter >& xFormatter,
+ const Color** ppColor = nullptr)
+ {return m_pCellControl->GetFormatText(_rxField, xFormatter, ppColor);}
+};
+
+
+typedef ::cppu::ImplHelper2 < css::awt::XTextComponent
+ , css::form::XChangeBroadcaster
+ > FmXEditCell_Base;
+class FmXEditCell final : public FmXTextCell,
+ public FmXEditCell_Base
+{
+public:
+ FmXEditCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl );
+
+ DECLARE_UNO3_AGG_DEFAULTS(FmXEditCell, FmXTextCell)
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override;
+
+// XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::awt::XTextComponent
+ virtual void SAL_CALL addTextListener(const css::uno::Reference< css::awt::XTextListener >& l) override;
+ virtual void SAL_CALL removeTextListener(const css::uno::Reference< css::awt::XTextListener >& l) override;
+ virtual void SAL_CALL setText(const OUString& aText) override;
+ virtual void SAL_CALL insertText(const css::awt::Selection& Sel, const OUString& Text) override;
+ virtual OUString SAL_CALL getText() override;
+ virtual OUString SAL_CALL getSelectedText() override;
+ virtual void SAL_CALL setSelection(const css::awt::Selection& aSelection) override;
+ virtual css::awt::Selection SAL_CALL getSelection() override;
+ virtual sal_Bool SAL_CALL isEditable() override;
+ virtual void SAL_CALL setEditable(sal_Bool bEditable) override;
+ virtual void SAL_CALL setMaxTextLen(sal_Int16 nLen) override;
+ virtual sal_Int16 SAL_CALL getMaxTextLen() override;
+
+ // XChangeBroadcaster
+ virtual void SAL_CALL addChangeListener( const css::uno::Reference< css::form::XChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeChangeListener( const css::uno::Reference< css::form::XChangeListener >& aListener ) override;
+
+private:
+ virtual ~FmXEditCell() override;
+
+ virtual void onFocusGained( const css::awt::FocusEvent& _rEvent ) override;
+ virtual void onFocusLost( const css::awt::FocusEvent& _rEvent ) override;
+
+ DECL_LINK(ModifyHdl, LinkParamNone*, void);
+
+ void onTextChanged();
+
+ OUString m_sValueOnEnter;
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XTextListener> m_aTextListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::form::XChangeListener> m_aChangeListeners;
+ ::svt::IEditImplementation* m_pEditImplementation;
+ bool m_bOwnEditImplementation;
+};
+
+typedef ::cppu::ImplHelper2 < css::awt::XCheckBox
+ , css::awt::XButton
+ > FmXCheckBoxCell_Base;
+class FmXCheckBoxCell final : public FmXDataCell,
+ public FmXCheckBoxCell_Base
+{
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XItemListener> m_aItemListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XActionListener> m_aActionListeners;
+ OUString m_aActionCommand;
+ VclPtr<::svt::CheckBoxControl> m_pBox;
+
+ DECL_LINK(ModifyHdl, LinkParamNone*, void);
+
+ virtual ~FmXCheckBoxCell() override;
+
+public:
+ FmXCheckBoxCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl );
+
+// UNO
+ DECLARE_UNO3_AGG_DEFAULTS(FmXCheckBoxCell, FmXDataCell)
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override;
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::awt::XCheckBox
+ virtual void SAL_CALL addItemListener(const css::uno::Reference< css::awt::XItemListener >& l) override;
+ virtual void SAL_CALL removeItemListener(const css::uno::Reference< css::awt::XItemListener >& l) override;
+ virtual sal_Int16 SAL_CALL getState() override;
+ virtual void SAL_CALL setState(sal_Int16 n) override;
+ virtual void SAL_CALL setLabel(const OUString& Label) override;
+ virtual void SAL_CALL enableTriState(sal_Bool b) override;
+
+ // XButton
+ virtual void SAL_CALL addActionListener( const css::uno::Reference< css::awt::XActionListener >& l ) override;
+ virtual void SAL_CALL removeActionListener( const css::uno::Reference< css::awt::XActionListener >& l ) override;
+ //virtual void SAL_CALL setLabel( const OUString& Label ) throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setActionCommand( const OUString& Command ) override;
+};
+
+typedef ::cppu::ImplHelper1 < css::awt::XListBox
+ > FmXListBoxCell_Base;
+class FmXListBoxCell final : public FmXTextCell
+ , public FmXListBoxCell_Base
+{
+public:
+ FmXListBoxCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl );
+
+ DECLARE_UNO3_AGG_DEFAULTS(FmXListBoxCell, FmXTextCell)
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override;
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::awt::XListBox
+ virtual void SAL_CALL addItemListener(const css::uno::Reference< css::awt::XItemListener >& l) override;
+ virtual void SAL_CALL removeItemListener(const css::uno::Reference< css::awt::XItemListener >& l) override;
+ virtual void SAL_CALL addActionListener(const css::uno::Reference< css::awt::XActionListener >& l) override;
+ virtual void SAL_CALL removeActionListener(const css::uno::Reference< css::awt::XActionListener >& l) override;
+ virtual void SAL_CALL addItem(const OUString& aItem, sal_Int16 nPos) override;
+ virtual void SAL_CALL addItems(const css::uno::Sequence< OUString >& aItems, sal_Int16 nPos) override;
+ virtual void SAL_CALL removeItems(sal_Int16 nPos, sal_Int16 nCount) override;
+ virtual sal_Int16 SAL_CALL getItemCount() override;
+ virtual OUString SAL_CALL getItem(sal_Int16 nPos) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getItems() override;
+ virtual sal_Int16 SAL_CALL getSelectedItemPos() override;
+ virtual css::uno::Sequence< sal_Int16 > SAL_CALL getSelectedItemsPos() override;
+ virtual OUString SAL_CALL getSelectedItem() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSelectedItems() override;
+ virtual void SAL_CALL selectItemPos(sal_Int16 nPos, sal_Bool bSelect) override;
+ virtual void SAL_CALL selectItemsPos(const css::uno::Sequence< sal_Int16 >& aPositions, sal_Bool bSelect) override;
+ virtual void SAL_CALL selectItem(const OUString& aItem, sal_Bool bSelect) override;
+ virtual sal_Bool SAL_CALL isMutipleMode() override;
+ virtual void SAL_CALL setMultipleMode(sal_Bool bMulti) override;
+ virtual sal_Int16 SAL_CALL getDropDownLineCount() override;
+ virtual void SAL_CALL setDropDownLineCount(sal_Int16 nLines) override;
+ virtual void SAL_CALL makeVisible(sal_Int16 nEntry) override;
+
+private:
+ virtual ~FmXListBoxCell() override;
+
+ DECL_LINK(ChangedHdl, bool, void);
+
+ void OnDoubleClick();
+
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XItemListener> m_aItemListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XActionListener> m_aActionListeners;
+ VclPtr<::svt::ListBoxControl> m_pBox;
+ sal_uInt16 m_nLines;
+ bool m_bMulti;
+};
+
+
+typedef ::cppu::ImplHelper1 < css::awt::XComboBox
+ > FmXComboBoxCell_Base;
+class FmXComboBoxCell final : public FmXTextCell
+ , public FmXComboBoxCell_Base
+{
+private:
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XItemListener> m_aItemListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XActionListener> m_aActionListeners;
+ VclPtr<::svt::ComboBoxControl> m_pComboBox;
+ sal_uInt16 m_nLines;
+
+ DECL_LINK(ChangedHdl, bool, void);
+
+ virtual ~FmXComboBoxCell() override;
+
+public:
+ FmXComboBoxCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl );
+
+ DECLARE_UNO3_AGG_DEFAULTS(FmXListBoxCell, FmXTextCell)
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override;
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XComboBox
+ virtual void SAL_CALL addItemListener( const css::uno::Reference< css::awt::XItemListener >& Listener ) override;
+ virtual void SAL_CALL removeItemListener( const css::uno::Reference< css::awt::XItemListener >& Listener ) override;
+ virtual void SAL_CALL addActionListener( const css::uno::Reference< css::awt::XActionListener >& Listener ) override;
+ virtual void SAL_CALL removeActionListener( const css::uno::Reference< css::awt::XActionListener >& Listener ) override;
+ virtual void SAL_CALL addItem( const OUString& Item, ::sal_Int16 Pos ) override;
+ virtual void SAL_CALL addItems( const css::uno::Sequence< OUString >& Items, ::sal_Int16 Pos ) override;
+ virtual void SAL_CALL removeItems( ::sal_Int16 nPos, ::sal_Int16 nCount ) override;
+ virtual ::sal_Int16 SAL_CALL getItemCount( ) override;
+ virtual OUString SAL_CALL getItem( ::sal_Int16 Pos ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getItems( ) override;
+ virtual ::sal_Int16 SAL_CALL getDropDownLineCount( ) override;
+ virtual void SAL_CALL setDropDownLineCount( ::sal_Int16 Lines ) override;
+};
+
+typedef ::cppu::ImplHelper2 < css::awt::XTextComponent
+ , css::lang::XUnoTunnel
+ > FmXFilterCell_Base;
+class FmXFilterCell final : public FmXGridCell
+ ,public FmXFilterCell_Base
+{
+public:
+ FmXFilterCell(DbGridColumn* pColumn, std::unique_ptr<DbFilterField> pControl);
+
+
+ DECLARE_UNO3_AGG_DEFAULTS(FmXFilterCell, FmXGridCell)
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override;
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+// XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+
+// helpers for XUnoTunnel
+ static const css::uno::Sequence<sal_Int8>& getUnoTunnelId();
+
+// painting the filter text
+ void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect);
+ void Update(){m_pCellControl->Update();}
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::awt::XTextComponent
+ virtual void SAL_CALL addTextListener(const css::uno::Reference< css::awt::XTextListener >& l) override;
+ virtual void SAL_CALL removeTextListener(const css::uno::Reference< css::awt::XTextListener >& l) override;
+ virtual void SAL_CALL setText(const OUString& aText) override;
+ virtual void SAL_CALL insertText(const css::awt::Selection& Sel, const OUString& Text) override;
+ virtual OUString SAL_CALL getText() override;
+ virtual OUString SAL_CALL getSelectedText() override;
+ virtual void SAL_CALL setSelection(const css::awt::Selection& aSelection) override;
+ virtual css::awt::Selection SAL_CALL getSelection() override;
+ virtual sal_Bool SAL_CALL isEditable() override;
+ virtual void SAL_CALL setEditable(sal_Bool bEditable) override;
+ virtual void SAL_CALL setMaxTextLen(sal_Int16 nLen) override;
+ virtual sal_Int16 SAL_CALL getMaxTextLen() override;
+
+private:
+ DECL_LINK( OnCommit, DbFilterField&, void );
+ virtual ~FmXFilterCell() override;
+
+ ::comphelper::OInterfaceContainerHelper3<css::awt::XTextListener> m_aTextListeners;
+};
+
+#endif // INCLUDED_SVX_SOURCE_INC_GRIDCELL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/gridcols.hxx b/svx/source/inc/gridcols.hxx
new file mode 100644
index 000000000..180337f7f
--- /dev/null
+++ b/svx/source/inc/gridcols.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_GRIDCOLS_HXX
+#define INCLUDED_SVX_SOURCE_INC_GRIDCOLS_HXX
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+
+#define FM_COL_TEXTFIELD "TextField"
+#define FM_COL_COMBOBOX "ComboBox"
+#define FM_COL_CHECKBOX "CheckBox"
+#define FM_COL_TIMEFIELD "TimeField"
+#define FM_COL_DATEFIELD "DateField"
+#define FM_COL_NUMERICFIELD "NumericField"
+#define FM_COL_CURRENCYFIELD "CurrencyField"
+#define FM_COL_PATTERNFIELD "PatternField"
+#define FM_COL_LISTBOX "ListBox"
+#define FM_COL_FORMATTEDFIELD "FormattedField"
+
+// column type ids
+#define TYPE_CHECKBOX 0
+#define TYPE_COMBOBOX 1
+#define TYPE_CURRENCYFIELD 2
+#define TYPE_DATEFIELD 3
+#define TYPE_FORMATTEDFIELD 4
+#define TYPE_LISTBOX 5
+#define TYPE_NUMERICFIELD 6
+#define TYPE_PATTERNFIELD 7
+#define TYPE_TEXTFIELD 8
+#define TYPE_TIMEFIELD 9
+
+
+sal_Int32 getColumnTypeByModelName(const OUString& aModelName);
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_GRIDCOLS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/sdbdatacolumn.hxx b/svx/source/inc/sdbdatacolumn.hxx
new file mode 100644
index 000000000..76d8039c8
--- /dev/null
+++ b/svx/source/inc/sdbdatacolumn.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_SDBDATACOLUMN_HXX
+#define INCLUDED_SVX_SOURCE_INC_SDBDATACOLUMN_HXX
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdb/XColumnUpdate.hpp>
+
+
+namespace svxform
+{
+
+
+ //= DataColumn - a class wrapping an object implementing a sdb::DataColumn service
+
+ class DataColumn
+ {
+ // interfaces needed for sddb::Column
+ css::uno::Reference< css::beans::XPropertySet> m_xPropertySet;
+ // interfaces needed for sdb::DataColumn
+ css::uno::Reference< css::sdb::XColumn> m_xColumn;
+ css::uno::Reference< css::sdb::XColumnUpdate> m_xColumnUpdate;
+
+ public:
+ DataColumn(const css::uno::Reference< css::beans::XPropertySet>& _rxIFace);
+ // if the object behind _rxIFace doesn't fully support the DataColumn service,
+ // (which is checked via the supported interfaces) _all_ members will be set to
+ // void !, even if the object has some of the needed interfaces.
+
+ // 'conversions'
+ const css::uno::Reference< css::sdb::XColumn>& getColumn() const
+ {
+ return m_xColumn;
+ }
+ };
+
+}
+
+#endif // INCLUDED_SVX_SOURCE_INC_SDBDATACOLUMN_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/sqlparserclient.hxx b/svx/source/inc/sqlparserclient.hxx
new file mode 100644
index 000000000..a14ea3671
--- /dev/null
+++ b/svx/source/inc/sqlparserclient.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_SQLPARSERCLIENT_HXX
+#define INCLUDED_SVX_SOURCE_INC_SQLPARSERCLIENT_HXX
+
+#include <config_options.h>
+#include <svx/ParseContext.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <memory>
+
+namespace com::sun::star {
+ namespace util {
+ class XNumberFormatter;
+ }
+ namespace beans {
+ class XPropertySet;
+ }
+}
+namespace connectivity {
+ class OSQLParser;
+ class OSQLParseNode;
+}
+
+namespace svxform
+{
+ //= OSQLParserClient
+
+ class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) OSQLParserClient : public ::svxform::OParseContextClient
+ {
+ protected:
+ mutable std::shared_ptr< ::connectivity::OSQLParser > m_pParser;
+
+ OSQLParserClient(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext);
+
+ std::unique_ptr< ::connectivity::OSQLParseNode > predicateTree(
+ OUString& _rErrorMessage,
+ const OUString& _rStatement,
+ const css::uno::Reference< css::util::XNumberFormatter >& _rxFormatter,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxField
+ ) const;
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_SQLPARSERCLIENT_HXX
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/svdobjplusdata.hxx b/svx/source/inc/svdobjplusdata.hxx
new file mode 100644
index 000000000..5e00a37c5
--- /dev/null
+++ b/svx/source/inc/svdobjplusdata.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+* This file is part of the LibreOffice project.
+*
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/.
+*/
+
+#ifndef INCLUDED_SVX_SVDOBJPLUSDATA_HXX
+#define INCLUDED_SVX_SVDOBJPLUSDATA_HXX
+
+#include <rtl/ustring.hxx>
+#include <memory>
+
+class SdrObject;
+class SfxBroadcaster;
+class SdrObjUserDataList;
+class SdrGluePointList;
+
+// Bitsack for DrawObjects
+class SdrObjPlusData final
+{
+ friend class SdrObject;
+
+ std::unique_ptr<SfxBroadcaster> pBroadcast; // broadcaster, if this object is referenced (bVirtObj=true). Also for connectors etc.
+ std::unique_ptr<SdrObjUserDataList> pUserDataList; // application specific data
+ std::unique_ptr<SdrGluePointList> pGluePoints; // gluepoints for glueing object connectors
+
+ // #i68101#
+ // object name, title and description
+ OUString aObjName;
+ OUString aObjTitle;
+ OUString aObjDescription;
+
+public:
+ SdrObjPlusData();
+ ~SdrObjPlusData();
+ SdrObjPlusData* Clone(SdrObject* pObj1) const;
+
+ void SetGluePoints(const SdrGluePointList& rPts);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/svdobjuserdatalist.hxx b/svx/source/inc/svdobjuserdatalist.hxx
new file mode 100644
index 000000000..d2cb0e16a
--- /dev/null
+++ b/svx/source/inc/svdobjuserdatalist.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+* This file is part of the LibreOffice project.
+*
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/.
+*/
+
+#ifndef INCLUDED_SVX_SVDOBJUSERDATALIST_HXX
+#define INCLUDED_SVX_SVDOBJUSERDATALIST_HXX
+
+#include <svx/svdobj.hxx>
+
+#include <vector>
+#include <memory>
+
+class SdrObjUserData;
+
+class SdrObjUserDataList
+{
+ typedef std::vector<std::unique_ptr<SdrObjUserData>> ListType;
+ ListType maList;
+
+public:
+ SdrObjUserDataList();
+ ~SdrObjUserDataList();
+
+ size_t GetUserDataCount() const;
+ SdrObjUserData& GetUserData(size_t nNum);
+ void AppendUserData(std::unique_ptr<SdrObjUserData> pData);
+ void DeleteUserData(size_t nNum);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/svdoutlinercache.hxx b/svx/source/inc/svdoutlinercache.hxx
new file mode 100644
index 000000000..01679f6b9
--- /dev/null
+++ b/svx/source/inc/svdoutlinercache.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_SVDOUTLINERCACHE_HXX
+#define INCLUDED_SVX_SOURCE_INC_SVDOUTLINERCACHE_HXX
+
+#include <memory>
+#include <vector>
+#include <o3tl/sorted_vector.hxx>
+
+class SdrModel;
+class SdrOutliner;
+enum class OutlinerMode;
+
+class SdrOutlinerCache
+{
+private:
+ SdrModel* mpModel;
+ std::vector< std::unique_ptr<SdrOutliner> > maModeOutline;
+ std::vector< std::unique_ptr<SdrOutliner> > maModeText;
+ o3tl::sorted_vector< SdrOutliner* > maActiveOutliners;
+
+public:
+ SdrOutlinerCache( SdrModel* pModel );
+ ~SdrOutlinerCache();
+
+ std::unique_ptr<SdrOutliner> createOutliner( OutlinerMode nOutlinerMode );
+ void disposeOutliner( std::unique_ptr<SdrOutliner> pOutliner );
+ std::vector< SdrOutliner* > GetActiveOutliners() const;
+};
+
+#endif
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/svdpdf.hxx b/svx/source/inc/svdpdf.hxx
new file mode 100644
index 000000000..f8736a7bc
--- /dev/null
+++ b/svx/source/inc/svdpdf.hxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_SVDRAW_SVDPDF_HXX
+#define INCLUDED_SVX_SOURCE_SVDRAW_SVDPDF_HXX
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <tools/fract.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/graph.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/xdash.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+#include <vcl/filter/PDFiumLibrary.hxx>
+
+// Forward Declarations
+
+class SfxItemSet;
+class SdrObjList;
+class SdrModel;
+class SdrPage;
+class SdrObject;
+class SvdProgressInfo;
+
+// Helper Class to import PDF
+class ImpSdrPdfImport final
+{
+ std::vector<SdrObject*> maTmpList;
+ ScopedVclPtr<VirtualDevice> mpVD;
+ tools::Rectangle maScaleRect;
+ size_t mnMapScalingOfs; // from here on, not edited with MapScaling
+ std::unique_ptr<SfxItemSet> mpLineAttr;
+ std::unique_ptr<SfxItemSet> mpFillAttr;
+ std::unique_ptr<SfxItemSet> mpTextAttr;
+ SdrModel* mpModel;
+ SdrLayerID mnLayer;
+ Color maOldLineColor;
+ sal_Int32 mnLineWidth;
+ static constexpr css::drawing::LineCap gaLineCap = css::drawing::LineCap_BUTT;
+ XDash maDash;
+
+ bool mbMov;
+ bool mbSize;
+ Point maOfs;
+ double mfScaleX;
+ double mfScaleY;
+ Fraction maScaleX;
+ Fraction maScaleY;
+
+ bool mbFntDirty;
+
+ // to optimize (PenNULL,Brush,DrawPoly),(Pen,BrushNULL,DrawPoly) -> two-in-one
+ bool mbLastObjWasPolyWithoutLine;
+ bool mbNoLine;
+ bool mbNoFill;
+
+ // clipregion
+ basegfx::B2DPolyPolygon maClip;
+
+ std::unique_ptr<vcl::pdf::PDFiumDocument> mpPdfDocument;
+ int mnPageCount;
+ double mdPageHeightPts;
+ /// The current transformation matrix, typically used with Form objects.
+ basegfx::B2DHomMatrix maCurrentMatrix;
+
+ /// Correct the vertical coordinate to start at the top.
+ /// PDF coordinate system has origin at the bottom right.
+ double correctVertOrigin(double offsetPts) const { return mdPageHeightPts - offsetPts; }
+ /// Convert PDF points to logic (twips).
+ tools::Rectangle PointsToLogic(double left, double right, double top, double bottom) const;
+ Point PointsToLogic(double x, double y) const;
+
+ std::shared_ptr<vcl::pdf::PDFium> mpPDFium;
+
+ // check for clip and evtl. fill maClip
+ void checkClip();
+ bool isClip() const;
+
+ void ImportPdfObject(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+ std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage,
+ int nPageObjectIndex);
+ void ImportForm(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+ std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage,
+ int nPageObjectIndex);
+ void ImportImage(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+ int nPageObjectIndex);
+ void ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+ int nPageObjectIndex);
+ void ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+ std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage,
+ int nPageObjectIndex);
+ void InsertTextObject(const Point& rPos, const Size& rSize, const OUString& rStr);
+
+ void SetupPageScale(const double dPageWidth, const double dPageHeight);
+ void SetAttributes(SdrObject* pObj, bool bForceTextAttr = false);
+ void InsertObj(SdrObject* pObj, bool bScale = true);
+ void MapScaling();
+
+ // #i73407# reformulation to use new B2DPolygon classes
+ bool CheckLastPolyLineAndFillMerge(const basegfx::B2DPolyPolygon& rPolyPolygon);
+
+ void DoObjects(SvdProgressInfo* pProgrInfo, sal_uInt32* pActionsToReport, int nPageIndex);
+
+ // Copy assignment is forbidden and not implemented.
+ ImpSdrPdfImport(const ImpSdrPdfImport&) = delete;
+ ImpSdrPdfImport& operator=(const ImpSdrPdfImport&) = delete;
+
+public:
+ ImpSdrPdfImport(SdrModel& rModel, SdrLayerID nLay, const tools::Rectangle& rRect,
+ Graphic const& rGraphic);
+
+ ~ImpSdrPdfImport();
+
+ int GetPageCount() const { return mnPageCount; }
+ size_t DoImport(SdrObjList& rDestList, size_t nInsPos, int nPageNumber,
+ SvdProgressInfo* pProgrInfo = nullptr);
+};
+
+#endif // INCLUDED_SVX_SOURCE_SVDRAW_SVDPDF_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/svxpixelctlaccessiblecontext.hxx b/svx/source/inc/svxpixelctlaccessiblecontext.hxx
new file mode 100644
index 000000000..2e0f0abcf
--- /dev/null
+++ b/svx/source/inc/svxpixelctlaccessiblecontext.hxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_SVXPIXELCTLACCESSIBLECONTEXT_HXX
+#define INCLUDED_SVX_SOURCE_INC_SVXPIXELCTLACCESSIBLECONTEXT_HXX
+
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <comphelper/accessibleselectionhelper.hxx>
+
+#include <rtl/ref.hxx>
+#include <tools/gen.hxx>
+
+
+namespace com::sun::star::awt {
+ struct Point;
+ struct Rectangle;
+ struct Size;
+ class XFocusListener;
+}
+class SvxPixelCtl;
+class SvxPixelCtlAccessible;
+
+typedef ::cppu::ImplHelper1<css::accessibility::XAccessible> OAccessibleHelper_Base;
+
+class SvxPixelCtlAccessibleChild final : public ::comphelper::OAccessibleComponentHelper,
+ public OAccessibleHelper_Base
+{
+public:
+ SvxPixelCtlAccessibleChild(
+ SvxPixelCtl& rWindow,
+ bool bPixelColorOrBG,
+ const tools::Rectangle& rBounds,
+ const rtl::Reference<SvxPixelCtlAccessible>& xParent,
+ tools::Long nIndexInParent );
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ //XAccessibleComponent
+ virtual void SAL_CALL grabFocus( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+
+ //XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) override;
+
+ //XAccessible
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ void CheckChild();
+ void SelectChild( bool bSelect);
+ void ChangePixelColorOrBG(bool bPixelColorOrBG){ m_bPixelColorOrBG = bPixelColorOrBG ;}
+ OUString GetName() const;
+
+private:
+ virtual ~SvxPixelCtlAccessibleChild() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ // OCommonAccessibleComponent
+ /// implements the calculation of the bounding rectangle
+ virtual css::awt::Rectangle implGetBounds( ) override;
+
+ SvxPixelCtl& mrParentWindow;
+ rtl::Reference<SvxPixelCtlAccessible> mxParent;
+ bool m_bPixelColorOrBG;//Pixel Color Or BackGround Color
+ tools::Rectangle maBoundingBox;
+ /// index of child in parent
+ tools::Long mnIndexInParent;
+};
+
+class SvxPixelCtlAccessible final : public ::comphelper::OAccessibleSelectionHelper,
+ public OAccessibleHelper_Base
+{
+public:
+ SvxPixelCtlAccessible(SvxPixelCtl* pPixelCtl);
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ //XAccessibleComponent
+ virtual void SAL_CALL grabFocus( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+
+ //XAccessible
+ //XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet( ) override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ css::uno::Reference< css::accessibility::XAccessible >
+ CreateChild (tools::Long nIndex, Point mPoint);
+
+private:
+ virtual ~SvxPixelCtlAccessible() override;
+
+ // OCommonAccessibleSelection
+ // return if the specified child is visible => watch for special ChildIndexes (ACCESSIBLE_SELECTION_CHILD_xxx)
+ virtual bool implIsSelected(sal_Int32 nAccessibleChildIndex) override;
+
+ // select the specified child => watch for special ChildIndexes (ACCESSIBLE_SELECTION_CHILD_xxx)
+ virtual void implSelect(sal_Int32 nAccessibleChildIndex, bool bSelect) override;
+
+ // OCommonAccessibleComponent
+ virtual css::awt::Rectangle implGetBounds() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ SvxPixelCtl* mpPixelCtl;
+ css::uno::Reference< css::accessibility::XAccessible> m_xCurChild;
+
+public:
+ void NotifyChild(tools::Long nIndex, bool bSelect, bool bCheck);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/svxrectctaccessiblecontext.hxx b/svx/source/inc/svxrectctaccessiblecontext.hxx
new file mode 100644
index 000000000..ef20985a4
--- /dev/null
+++ b/svx/source/inc/svxrectctaccessiblecontext.hxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#ifndef INCLUDED_SVX_SOURCE_INC_SVXRECTCTACCESSIBLECONTEXT_HXX
+#define INCLUDED_SVX_SOURCE_INC_SVXRECTCTACCESSIBLECONTEXT_HXX
+
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleAction.hpp>
+#include <com/sun/star/accessibility/XAccessibleValue.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <comphelper/accessibleselectionhelper.hxx>
+#include <rtl/ref.hxx>
+#include <svx/rectenum.hxx>
+#include <tools/gen.hxx>
+#include <vector>
+
+namespace com::sun::star::awt {
+ struct Point;
+ struct Rectangle;
+ struct Size;
+ class XFocusListener;
+}
+namespace tools { class Rectangle; }
+class SvxRectCtl;
+class SvxRectCtlChildAccessibleContext;
+
+typedef ::cppu::ImplHelper1<css::accessibility::XAccessible> OAccessibleHelper_Base;
+
+class SvxRectCtlAccessibleContext final : public ::comphelper::OAccessibleSelectionHelper,
+ public OAccessibleHelper_Base
+{
+public:
+ // internal
+ SvxRectCtlAccessibleContext(SvxRectCtl* pRepresentation);
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ // XAccessibleComponent
+ virtual void SAL_CALL grabFocus() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint(const css::awt::Point& rPoint) override;
+
+ // XAccessible
+ // XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL getAccessibleChild(sal_Int32 nIndex) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL getAccessibleParent() override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole() override;
+ virtual OUString SAL_CALL getAccessibleDescription() override;
+ virtual OUString SAL_CALL getAccessibleName() override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet() override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet() override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext> SAL_CALL getAccessibleContext() override { return this; }
+ virtual sal_Int32 SAL_CALL getForeground() override;
+ virtual sal_Int32 SAL_CALL getBackground() override;
+
+ /** Selects a new child by point.
+
+ <p>If the child was not selected before, the state of the child will
+ be updated. If the point is not invalid, the index will internally set to NOCHILDSELECTED</p>
+
+ @param eButton
+ Button which belongs to the child which should be selected.
+ */
+ void selectChild( RectPoint ePoint );
+ void FireChildFocus( RectPoint eButton );
+
+private:
+ virtual ~SvxRectCtlAccessibleContext() override;
+
+ // OCommonAccessibleSelection
+ // return if the specified child is visible => watch for special ChildIndexes (ACCESSIBLE_SELECTION_CHILD_xxx)
+ virtual bool implIsSelected(sal_Int32 nAccessibleChildIndex) override;
+
+ // select the specified child => watch for special ChildIndexes (ACCESSIBLE_SELECTION_CHILD_xxx)
+ virtual void implSelect(sal_Int32 nAccessibleChildIndex, bool bSelect) override;
+
+ // OCommonAccessibleComponent
+ virtual css::awt::Rectangle implGetBounds() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ void checkChildIndex(tools::Long nIndex);
+
+ /** Selects a new child by index.
+
+ <p>If the child was not selected before, the state of the child will
+ be updated. If the index is invalid, the index will internally set to NOCHILDSELECTED</p>
+
+ @param nIndexOfChild
+ Index of the new child which should be selected.
+ */
+ void selectChild( tools::Long nIndexOfChild );
+
+ /** Description of this object. This is not a constant because it can
+ be set from the outside.
+ */
+ OUString msDescription;
+
+ /** Name of this object.
+ */
+ OUString msName;
+
+ /// pointer to internal representation
+ SvxRectCtl* mpRepr;
+
+ /// array for all possible children
+ std::vector<rtl::Reference<SvxRectCtlChildAccessibleContext>> mvChildren;
+
+ /// actual selected child
+ tools::Long mnSelectedChild;
+};
+
+typedef ::cppu::ImplHelper3 < css::accessibility::XAccessible,
+ css::accessibility::XAccessibleValue,
+ css::accessibility::XAccessibleAction
+ > OAccessibleHelper_Base_3;
+
+class SvxRectCtlChildAccessibleContext final : public ::comphelper::OAccessibleComponentHelper,
+ public OAccessibleHelper_Base_3
+{
+public:
+ SvxRectCtlChildAccessibleContext(
+ const css::uno::Reference< css::accessibility::XAccessible>& rxParent,
+ const OUString& rName, const OUString& rDescription,
+ const tools::Rectangle& rBoundingBox,
+ tools::Long nIndexInParent );
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+
+ // XAccessibleComponent
+ virtual void SAL_CALL grabFocus() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& rPoint ) override;
+
+ // XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 nIndex ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole() override;
+ virtual OUString SAL_CALL getAccessibleDescription() override;
+ virtual OUString SAL_CALL getAccessibleName() override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet() override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet() override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext> SAL_CALL getAccessibleContext() override { return this; }
+
+ virtual sal_Int32 SAL_CALL getForeground() override;
+ virtual sal_Int32 SAL_CALL getBackground() override;
+
+ // XAccessibleValue
+ virtual css::uno::Any SAL_CALL
+ getCurrentValue() override;
+
+ virtual sal_Bool SAL_CALL
+ setCurrentValue( const css::uno::Any& aNumber ) override;
+
+ virtual css::uno::Any SAL_CALL
+ getMaximumValue() override;
+
+ virtual css::uno::Any SAL_CALL
+ getMinimumValue() override;
+
+ virtual css::uno::Any SAL_CALL
+ getMinimumIncrement() override;
+
+ // XAccessibleAction
+ virtual sal_Int32 SAL_CALL getAccessibleActionCount( ) override;
+ virtual sal_Bool SAL_CALL doAccessibleAction ( sal_Int32 nIndex ) override;
+ virtual OUString SAL_CALL getAccessibleActionDescription ( sal_Int32 nIndex ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleKeyBinding > SAL_CALL getAccessibleActionKeyBinding( sal_Int32 nIndex ) override;
+
+ // internal
+ /// Sets the checked status
+ void setStateChecked(bool bChecked);
+ void FireFocusEvent();
+
+private:
+ virtual ~SvxRectCtlChildAccessibleContext() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ // OCommonAccessibleComponent
+ /// implements the calculation of the bounding rectangle
+ virtual css::awt::Rectangle implGetBounds( ) override;
+
+ /** Description of this object. This is not a constant because it can
+ be set from the outside. Furthermore, it changes according to the
+ draw page's display mode.
+ */
+ OUString msDescription;
+
+ /** Name of this object. It changes according the draw page's
+ display mode.
+ */
+ OUString msName;
+
+ /// Reference to the parent object.
+ css::uno::Reference< css::accessibility::XAccessible >
+ mxParent;
+
+ /// Bounding box
+ tools::Rectangle maBoundingBox;
+
+ /// index of child in parent
+ tools::Long mnIndexInParent;
+
+ /// Indicates, if object is checked
+ bool mbIsChecked;
+};
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/tablemodel.hxx b/svx/source/inc/tablemodel.hxx
new file mode 100644
index 000000000..63c08a9b8
--- /dev/null
+++ b/svx/source/inc/tablemodel.hxx
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_TABLEMODEL_HXX
+#define INCLUDED_SVX_SOURCE_INC_TABLEMODEL_HXX
+
+#include <sal/types.h>
+#include <com/sun/star/util/XBroadcaster.hpp>
+#include <com/sun/star/table/XTable.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include "celltypes.hxx"
+
+struct _xmlTextWriter;
+typedef struct _xmlTextWriter* xmlTextWriterPtr;
+
+namespace sdr::table {
+
+class SdrTableObj;
+
+/** base class for each object implementing an XCellRange */
+class ICellRange
+{
+public:
+ virtual sal_Int32 getLeft() = 0;
+ virtual sal_Int32 getTop() = 0;
+ virtual sal_Int32 getRight() = 0;
+ virtual sal_Int32 getBottom() = 0;
+ virtual css::uno::Reference< css::table::XTable > getTable() = 0;
+
+protected:
+ ~ICellRange() {}
+};
+
+typedef ::cppu::WeakComponentImplHelper< css::table::XTable, css::util::XBroadcaster > TableModelBase;
+
+class TableModel final : public ::cppu::BaseMutex,
+ public TableModelBase,
+ public ICellRange
+{
+ friend class InsertRowUndo;
+ friend class RemoveRowUndo;
+ friend class InsertColUndo;
+ friend class RemoveColUndo;
+ friend class TableColumnUndo;
+ friend class TableRowUndo;
+ friend class TableColumn;
+ friend class TableRow;
+ friend class TableRows;
+ friend class TableColumns;
+ friend class TableModelNotifyGuard;
+
+public:
+ explicit TableModel( SdrTableObj* pTableObj );
+ TableModel( SdrTableObj* pTableObj, const TableModelRef& xSourceTable );
+ virtual ~TableModel() override;
+
+ void init( sal_Int32 nColumns, sal_Int32 nRows );
+
+ SdrTableObj* getSdrTableObj() const { return mpTableObj; }
+
+ /** deletes rows and columns that are completely merged. Must be called between BegUndo/EndUndo! */
+ void optimize();
+
+ /// merges the cell at the given position with the given span
+ void merge( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan );
+ /// Get the width of all columns in this table.
+ std::vector<sal_Int32> getColumnWidths();
+
+ void dumpAsXml(xmlTextWriterPtr pWriter) const;
+
+ // ICellRange
+ virtual sal_Int32 getLeft() override;
+ virtual sal_Int32 getTop() override;
+ virtual sal_Int32 getRight() override;
+ virtual sal_Int32 getBottom() override;
+ virtual css::uno::Reference< css::table::XTable > getTable() override;
+
+ // XTable
+ virtual css::uno::Reference< css::table::XCellCursor > SAL_CALL createCursor( ) override;
+ virtual css::uno::Reference< css::table::XCellCursor > SAL_CALL createCursorByRange( const css::uno::Reference< css::table::XCellRange >& rRange ) override;
+ virtual ::sal_Int32 SAL_CALL getRowCount() override;
+ virtual ::sal_Int32 SAL_CALL getColumnCount() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+
+ // XModifiable
+ virtual sal_Bool SAL_CALL isModified( ) override;
+ virtual void SAL_CALL setModified( sal_Bool bModified ) override;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // XColumnRowRange
+ virtual css::uno::Reference< css::table::XTableColumns > SAL_CALL getColumns() override;
+ virtual css::uno::Reference< css::table::XTableRows > SAL_CALL getRows() override;
+
+ // XCellRange
+ virtual css::uno::Reference< css::table::XCell > SAL_CALL getCellByPosition( ::sal_Int32 nColumn, ::sal_Int32 nRow ) override;
+ virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByPosition( ::sal_Int32 nLeft, ::sal_Int32 nTop, ::sal_Int32 nRight, ::sal_Int32 nBottom ) override;
+ virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByName( const OUString& aRange ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // XFastPropertySet
+ virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) override;
+
+ // XBroadcaster
+ virtual void SAL_CALL lockBroadcasts() override;
+ virtual void SAL_CALL unlockBroadcasts() override;
+
+private:
+ void notifyModification();
+
+ void insertColumns( sal_Int32 nIndex, sal_Int32 nCount );
+ void removeColumns( sal_Int32 nIndex, sal_Int32 nCount );
+ void insertRows( sal_Int32 nIndex, sal_Int32 nCount );
+ void removeRows( sal_Int32 nIndex, sal_Int32 nCount );
+
+ sal_Int32 getRowCountImpl() const;
+ sal_Int32 getColumnCountImpl() const;
+
+ CellRef createCell();
+ CellRef getCell( ::sal_Int32 nCol, ::sal_Int32 nRow ) const;
+
+ void UndoInsertRows( sal_Int32 nIndex, sal_Int32 nCount );
+ void UndoRemoveRows( sal_Int32 nIndex, RowVector& aNewRows );
+
+ void UndoInsertColumns( sal_Int32 nIndex, sal_Int32 nCount );
+ void UndoRemoveColumns( sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells );
+
+private:
+ /** this function is called upon disposing the component
+ */
+ virtual void SAL_CALL disposing() override;
+
+ /// @throws css::lang::IndexOutOfBoundsException
+ TableRowRef const & getRow( sal_Int32 nRow ) const;
+ /// @throws css::lang::IndexOutOfBoundsException
+ TableColumnRef const & getColumn( sal_Int32 nColumn ) const;
+
+ void updateRows();
+ void updateColumns();
+
+ RowVector maRows;
+ ColumnVector maColumns;
+
+ rtl::Reference< TableColumns > mxTableColumns;
+ rtl::Reference< TableRows > mxTableRows;
+
+ SdrTableObj* mpTableObj; // TTTT should be reference
+
+ bool mbModified;
+ bool mbNotifyPending;
+
+ sal_Int32 mnNotifyLock;
+};
+
+class TableModelNotifyGuard
+{
+public:
+ explicit TableModelNotifyGuard( TableModel* pModel )
+ : mxBroadcaster( static_cast< css::util::XBroadcaster* >( pModel ) )
+ {
+ if( mxBroadcaster.is() )
+ mxBroadcaster->lockBroadcasts();
+ }
+
+ ~TableModelNotifyGuard()
+ {
+ if( mxBroadcaster.is() )
+ mxBroadcaster->unlockBroadcasts();
+ }
+
+private:
+ css::uno::Reference< css::util::XBroadcaster > mxBroadcaster;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/tabwin.hxx b/svx/source/inc/tabwin.hxx
new file mode 100644
index 000000000..c1cf70664
--- /dev/null
+++ b/svx/source/inc/tabwin.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_TABWIN_HXX
+#define INCLUDED_SVX_SOURCE_INC_TABWIN_HXX
+
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/ctrlitem.hxx>
+#include <svx/dbaexchange.hxx>
+#include <com/sun/star/form/XForm.hpp>
+
+#include <comphelper/propmultiplex.hxx>
+#include <connectivity/dbtools.hxx>
+
+class FmFormShell;
+struct ColumnInfo;
+
+class FmFieldWin final : public SfxModelessDialogController
+ , public SfxControllerItem
+ , public ::comphelper::OPropertyChangeListener
+{
+ ::osl::Mutex m_aMutex;
+ std::unique_ptr<weld::TreeView> m_xListBox;
+ std::vector<std::unique_ptr<ColumnInfo>> m_aListBoxData;
+ ::dbtools::SharedConnection
+ m_aConnection;
+ OUString m_aDatabaseName,
+ m_aObjectName;
+ sal_Int32 m_nObjectType;
+
+ rtl::Reference<comphelper::OPropertyChangeMultiplexer> m_xChangeListener;
+ rtl::Reference<svx::OColumnTransferable> m_xHelper;
+
+ void addToList(const css::uno::Reference<css::container::XNameAccess>& i_xColumns);
+
+ DECL_LINK(RowActivatedHdl, weld::TreeView&, bool);
+ DECL_LINK(DragBeginHdl, bool&, bool);
+public:
+ FmFieldWin(SfxBindings *pBindings, SfxChildWindow *pMgr, weld::Window* pParent);
+
+ virtual ~FmFieldWin() override;
+
+ virtual void StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ void UpdateContent(FmFormShell const *);
+ void UpdateContent(const css::uno::Reference< css::form::XForm > &);
+ void FillInfo( SfxChildWinInfo& rInfo ) const override;
+
+ const OUString& GetDatabaseName() const { return m_aDatabaseName; }
+ const ::dbtools::SharedConnection& GetConnection() const { return m_aConnection; }
+ const OUString& GetObjectName() const { return m_aObjectName; }
+ sal_Int32 GetObjectType() const { return m_nObjectType; }
+
+ bool createSelectionControls( );
+
+private:
+ // FmXChangeListener
+ virtual void _propertyChanged(const css::beans::PropertyChangeEvent& evt) override;
+
+ using SfxControllerItem::GetBindings;
+};
+
+
+class FmFieldWinMgr final : public SfxChildWindow
+{
+public:
+ FmFieldWinMgr(vcl::Window *pParent, sal_uInt16 nId,
+ SfxBindings *pBindings, SfxChildWinInfo const *pInfo);
+ SFX_DECL_CHILDWINDOW(FmFieldWinMgr);
+};
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/tbxform.hxx b/svx/source/inc/tbxform.hxx
new file mode 100644
index 000000000..20c22a0b5
--- /dev/null
+++ b/svx/source/inc/tbxform.hxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_INC_TBXFORM_HXX
+#define INCLUDED_SVX_SOURCE_INC_TBXFORM_HXX
+
+#include <sfx2/tbxctrl.hxx>
+#include <svtools/recorditemwindow.hxx>
+
+class SvxFmAbsRecWin final : public RecordItemWindow
+{
+public:
+ SvxFmAbsRecWin(vcl::Window* _pParent, SfxToolBoxControl* _pController);
+
+private:
+ virtual void PositionFired(sal_Int64 nRecord) override;
+
+ SfxToolBoxControl* m_pController;
+};
+
+class SvxFmTbxCtlAbsRec final : public SfxToolBoxControl
+{
+public:
+ SFX_DECL_TOOLBOX_CONTROL();
+
+ SvxFmTbxCtlAbsRec(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx);
+ virtual ~SvxFmTbxCtlAbsRec() override;
+
+ virtual VclPtr<InterimItemWindow> CreateItemWindow(vcl::Window* pParent) override;
+
+ virtual void StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState) override;
+};
+
+class SvxFmTbxCtlRecText final : public SfxToolBoxControl
+{
+public:
+ SFX_DECL_TOOLBOX_CONTROL();
+
+ SvxFmTbxCtlRecText(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx);
+ virtual ~SvxFmTbxCtlRecText() override;
+
+ virtual VclPtr<InterimItemWindow> CreateItemWindow(vcl::Window* pParent) override;
+};
+
+class SvxFmTbxCtlRecFromText final : public SfxToolBoxControl
+{
+public:
+ SFX_DECL_TOOLBOX_CONTROL();
+
+ SvxFmTbxCtlRecFromText(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx);
+ virtual ~SvxFmTbxCtlRecFromText() override;
+
+ virtual VclPtr<InterimItemWindow> CreateItemWindow(vcl::Window* pParent) override;
+};
+
+class LabelItemWindow;
+
+class SvxFmTbxCtlRecTotal final : public SfxToolBoxControl
+{
+ VclPtr<LabelItemWindow> m_xFixedText;
+
+public:
+ SFX_DECL_TOOLBOX_CONTROL();
+
+ SvxFmTbxCtlRecTotal(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx);
+ virtual ~SvxFmTbxCtlRecTotal() override;
+
+ virtual VclPtr<InterimItemWindow> CreateItemWindow(vcl::Window* pParent) override;
+ virtual void StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState) override;
+};
+
+class SvxFmTbxNextRec final : public SfxToolBoxControl
+{
+public:
+ SFX_DECL_TOOLBOX_CONTROL();
+ SvxFmTbxNextRec(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx);
+};
+
+class SvxFmTbxPrevRec final : public SfxToolBoxControl
+{
+public:
+ SFX_DECL_TOOLBOX_CONTROL();
+ SvxFmTbxPrevRec(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/treevisitor.hxx b/svx/source/inc/treevisitor.hxx
new file mode 100644
index 000000000..50e7d7a35
--- /dev/null
+++ b/svx/source/inc/treevisitor.hxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_TREEVISITOR_HXX
+#define INCLUDED_SVX_SOURCE_INC_TREEVISITOR_HXX
+
+#include <stack>
+
+template< class ELEMENT, class NODEINFO, class PROCESSOR >
+class TreeVisitor
+{
+public:
+ TreeVisitor( NODEINFO _nodeInfo )
+ :m_visitedRoot( false )
+ ,m_root()
+ ,m_current()
+ ,m_nodeInfo( _nodeInfo )
+ {
+ }
+
+ void process( const ELEMENT& _root, PROCESSOR& _processor )
+ {
+ m_root = _root;
+ m_visitedRoot = false;
+
+ while ( do_step() )
+ _processor.process( m_current );
+ }
+
+private:
+ bool do_step();
+
+private:
+ bool m_visitedRoot;
+ ELEMENT m_root;
+ ELEMENT m_current;
+ const NODEINFO m_nodeInfo;
+
+ ::std::stack< size_t > m_pathToCurrent;
+ ::std::stack< ELEMENT > m_currentAncestors;
+};
+
+template< class ELEMENT, class NODEINFO, class PROCESSOR >
+bool TreeVisitor< ELEMENT, NODEINFO, PROCESSOR >::do_step()
+{
+ if ( !m_visitedRoot )
+ {
+ m_current = m_root;
+ m_visitedRoot = true;
+ return true;
+ }
+
+ // can we step down from the current node?
+ size_t childCount = m_nodeInfo.childCount( m_current );
+ if ( childCount )
+ {
+ m_currentAncestors.push( m_current );
+ m_current = m_nodeInfo.getChild( m_current, 0 );
+ m_pathToCurrent.push( 0 );
+ return true;
+ }
+
+ // is there a right sibling of the current node?
+ while ( !m_pathToCurrent.empty() )
+ {
+ const ELEMENT& currentParent = m_currentAncestors.top();
+ childCount = m_nodeInfo.childCount( currentParent );
+
+ size_t currentChildPos = m_pathToCurrent.top();
+ if ( ++currentChildPos < childCount )
+ {
+ // yes there is
+ m_pathToCurrent.top() = currentChildPos;
+ m_current = m_nodeInfo.getChild( currentParent, currentChildPos );
+ return true;
+ }
+
+ // no there isn't => step up
+ m_currentAncestors.pop();
+ m_pathToCurrent.pop();
+ }
+
+ return false;
+}
+
+#endif // INCLUDED_SVX_SOURCE_INC_TREEVISITOR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/xfm_addcondition.hxx b/svx/source/inc/xfm_addcondition.hxx
new file mode 100644
index 000000000..10d4674cb
--- /dev/null
+++ b/svx/source/inc/xfm_addcondition.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_XFM_ADDCONDITION_HXX
+#define INCLUDED_SVX_SOURCE_INC_XFM_ADDCONDITION_HXX
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/xforms/XModel.hpp>
+#include <svtools/genericunodialog.hxx>
+#include <comphelper/proparrhlp.hxx>
+
+
+namespace svxform
+{
+
+ typedef ::svt::OGenericUnoDialog OAddConditionDialogBase;
+ class OAddConditionDialog final
+ :public OAddConditionDialogBase
+ ,public ::comphelper::OPropertyArrayUsageHelper< OAddConditionDialog >
+ {
+ public:
+ static css::uno::Reference< css::uno::XInterface >
+ Create( const css::uno::Reference< css::lang::XMultiServiceFactory >& );
+
+ private:
+ OAddConditionDialog( const css::uno::Reference< css::uno::XComponentContext >& _rxORB );
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySet
+ virtual css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // OGenericUnoDialog overridables
+ virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+ virtual void executedDialog(sal_Int16 _nExecutionResult) override;
+
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xBinding;
+ OUString m_sFacetName;
+ OUString m_sConditionValue;
+ css::uno::Reference< css::xforms::XModel >
+ m_xWorkModel;
+ };
+
+
+}
+
+
+#endif // INCLUDED_SVX_SOURCE_INC_XFM_ADDCONDITION_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/xmlxtexp.hxx b/svx/source/inc/xmlxtexp.hxx
new file mode 100644
index 000000000..e47dbf1df
--- /dev/null
+++ b/svx/source/inc/xmlxtexp.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_XMLXTEXP_HXX
+#define INCLUDED_SVX_SOURCE_INC_XMLXTEXP_HXX
+
+#include <xmloff/xmlexp.hxx>
+
+namespace com::sun::star {
+ namespace frame { class XModel; }
+ namespace uno { template<class X> class Reference; }
+ namespace uno { class XInterface; }
+ namespace container { class XNameContainer; }
+ namespace document { class XGraphicStorageHandler; }
+ namespace xml::sax { class XDocumentHandler; }
+}
+
+class SvxXMLXTableExportComponent final : public SvXMLExport
+{
+public:
+ SvxXMLXTableExportComponent(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::xml::sax::XDocumentHandler > & xHandler,
+ const css::uno::Reference< css::container::XNameContainer > & xTable,
+ css::uno::Reference<css::document::XGraphicStorageHandler> const & xGraphicStorageHandler);
+
+ virtual ~SvxXMLXTableExportComponent() override;
+
+ /// @throws css::uno::RuntimeException
+ static bool save( const OUString& rURL,
+ const css::uno::Reference< css::container::XNameContainer >& xTable,
+ const css::uno::Reference< css::embed::XStorage > &xStorage,
+ OUString *pOptName );
+
+ // methods without content:
+ virtual void ExportAutoStyles_() override;
+ virtual void ExportMasterStyles_() override;
+ virtual void ExportContent_() override;
+
+private:
+ bool exportTable() noexcept;
+ const css::uno::Reference< css::container::XNameContainer > & mxTable;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/xmlxtimp.hxx b/svx/source/inc/xmlxtimp.hxx
new file mode 100644
index 000000000..ee442ac40
--- /dev/null
+++ b/svx/source/inc/xmlxtimp.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_INC_XMLXTIMP_HXX
+#define INCLUDED_SVX_SOURCE_INC_XMLXTIMP_HXX
+
+#include <xmloff/xmlimp.hxx>
+
+namespace com::sun::star {
+ namespace uno { template<class X> class Reference; }
+ namespace uno { class XInterface; }
+ namespace document { class XGraphicStorageHandler; }
+ namespace container { class XNameContainer; }
+}
+
+class SvxXMLXTableImport final : public SvXMLImport
+{
+public:
+ SvxXMLXTableImport(
+ const css::uno::Reference< css::uno::XComponentContext >& rContext,
+ const css::uno::Reference< css::container::XNameContainer > & rTable,
+ css::uno::Reference<css::document::XGraphicStorageHandler> const & rxGraphicStorageHandler);
+
+ virtual ~SvxXMLXTableImport() noexcept override;
+
+ static bool load( const OUString &rPath, const OUString &rReferer,
+ const css::uno::Reference < css::embed::XStorage > &xStorage,
+ const css::uno::Reference< css::container::XNameContainer >& xTable,
+ bool *bOptLoadedFromStorage ) noexcept;
+private:
+ virtual SvXMLImportContext *CreateFastContext( sal_Int32 Element,
+ const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& xAttrList ) override;
+
+ const css::uno::Reference< css::container::XNameContainer > & mrTable;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/SmartTagItem.cxx b/svx/source/items/SmartTagItem.cxx
new file mode 100644
index 000000000..fcec36315
--- /dev/null
+++ b/svx/source/items/SmartTagItem.cxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/propertysequence.hxx>
+#include <svx/SmartTagItem.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/container/XStringKeyMap.hpp>
+
+
+using namespace ::com::sun::star;
+
+
+SfxPoolItem* SvxSmartTagItem::CreateDefault() { SAL_WARN( "svx", "No SvxSmartTagItem factory available"); return nullptr; }
+
+SvxSmartTagItem::SvxSmartTagItem( const TypedWhichId<SvxSmartTagItem> nId,
+ const css::uno::Sequence < css::uno::Sequence< css::uno::Reference< css::smarttags::XSmartTagAction > > >& rActionComponentsSequence,
+ const css::uno::Sequence < css::uno::Sequence< sal_Int32 > >& rActionIndicesSequence,
+ const css::uno::Sequence< css::uno::Reference< css::container::XStringKeyMap > >& rStringKeyMaps,
+ const css::uno::Reference<css::text::XTextRange>& rRange,
+ const css::uno::Reference<css::frame::XController>& rController,
+ const css::lang::Locale& rLocale,
+ const OUString& rApplicationName,
+ const OUString& rRangeText ) :
+ SfxPoolItem( nId ),
+ maActionComponentsSequence( rActionComponentsSequence ),
+ maActionIndicesSequence( rActionIndicesSequence ),
+ maStringKeyMaps( rStringKeyMaps ),
+ mxRange( rRange ),
+ mxController( rController ),
+ maLocale( rLocale ),
+ maApplicationName( rApplicationName ),
+ maRangeText( rRangeText )
+{
+}
+
+
+bool SvxSmartTagItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ rVal <<= comphelper::InitPropertySequence( {
+ { "ActionComponents", css::uno::Any( maActionComponentsSequence ) },
+ { "ActionIndices", css::uno::Any( maActionIndicesSequence ) },
+ { "StringKeyMaps", css::uno::Any( maStringKeyMaps ) },
+ { "TextRange", css::uno::Any( mxRange ) },
+ { "Controller", css::uno::Any( mxController ) },
+ { "Locale", css::uno::Any( maLocale ) },
+ { "ApplicationName", css::uno::Any( maApplicationName ) },
+ { "RangeText", css::uno::Any( maRangeText ) },
+ } );
+ return true;
+}
+
+bool SvxSmartTagItem::PutValue( const uno::Any& /*rVal*/, sal_uInt8 /* nMemberId */)
+{
+ return false;
+}
+
+
+bool SvxSmartTagItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+
+ const SvxSmartTagItem& rItem = static_cast<const SvxSmartTagItem&>(rAttr);
+
+ return maActionComponentsSequence == rItem.maActionComponentsSequence &&
+ maActionIndicesSequence == rItem.maActionIndicesSequence &&
+ maStringKeyMaps == rItem.maStringKeyMaps &&
+ mxRange == rItem.mxRange &&
+ mxController == rItem.mxController &&
+ maApplicationName == rItem.maApplicationName &&
+ maRangeText == rItem.maRangeText;
+}
+
+
+SvxSmartTagItem* SvxSmartTagItem::Clone( SfxItemPool * ) const
+{
+ return new SvxSmartTagItem( *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/algitem.cxx b/svx/source/items/algitem.cxx
new file mode 100644
index 000000000..917edb1f6
--- /dev/null
+++ b/svx/source/items/algitem.cxx
@@ -0,0 +1,315 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/strings.hrc>
+#include <osl/diagnose.h>
+#include <tools/mapunit.hxx>
+#include <tools/UnitConversion.hxx>
+#include <com/sun/star/table/CellOrientation.hpp>
+
+#include <svx/algitem.hxx>
+#include <svx/dialmgr.hxx>
+#include <editeng/itemtype.hxx>
+#include <editeng/eerdll.hxx>
+#include <svx/unomid.hxx>
+
+#include <climits>
+
+using namespace ::com::sun::star;
+
+
+SfxPoolItem* SvxMarginItem::CreateDefault() { return new SvxMarginItem(TypedWhichId<SvxMarginItem>(0)) ;}
+
+SvxOrientationItem::SvxOrientationItem( const SvxCellOrientation eOrientation,
+ const TypedWhichId<SvxOrientationItem> nId):
+ SfxEnumItem( nId, eOrientation )
+{
+}
+
+SvxOrientationItem::SvxOrientationItem( Degree100 nRotation, bool bStacked, const TypedWhichId<SvxOrientationItem> nId ) :
+ SfxEnumItem( nId, SvxCellOrientation::Standard )
+{
+ if( bStacked )
+ {
+ SetValue( SvxCellOrientation::Stacked );
+ }
+ else switch( nRotation.get() )
+ {
+ case 9000: SetValue( SvxCellOrientation::BottomUp ); break;
+ case 27000: SetValue( SvxCellOrientation::TopBottom ); break;
+ default: SetValue( SvxCellOrientation::Standard );
+ }
+}
+
+
+bool SvxOrientationItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper& ) const
+{
+ rText = GetValueText( GetValue() );
+ return true;
+}
+
+
+bool SvxOrientationItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ table::CellOrientation eUno = table::CellOrientation_STANDARD;
+ switch ( GetValue() )
+ {
+ case SvxCellOrientation::Standard: eUno = table::CellOrientation_STANDARD; break;
+ case SvxCellOrientation::TopBottom: eUno = table::CellOrientation_TOPBOTTOM; break;
+ case SvxCellOrientation::BottomUp: eUno = table::CellOrientation_BOTTOMTOP; break;
+ case SvxCellOrientation::Stacked: eUno = table::CellOrientation_STACKED; break;
+ }
+ rVal <<= eUno;
+ return true;
+}
+
+bool SvxOrientationItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
+{
+ table::CellOrientation eOrient;
+ if(!(rVal >>= eOrient))
+ {
+ sal_Int32 nValue = 0;
+ if(!(rVal >>= nValue))
+ return false;
+ eOrient = static_cast<table::CellOrientation>(nValue);
+ }
+ SvxCellOrientation eSvx = SvxCellOrientation::Standard;
+ switch (eOrient)
+ {
+ case table::CellOrientation_STANDARD: eSvx = SvxCellOrientation::Standard; break;
+ case table::CellOrientation_TOPBOTTOM: eSvx = SvxCellOrientation::TopBottom; break;
+ case table::CellOrientation_BOTTOMTOP: eSvx = SvxCellOrientation::BottomUp; break;
+ case table::CellOrientation_STACKED: eSvx = SvxCellOrientation::Stacked; break;
+ default: ; //prevent warning
+ }
+ SetValue( eSvx );
+ return true;
+}
+
+OUString SvxOrientationItem::GetValueText( SvxCellOrientation nVal )
+{
+ OString id = OString::Concat(RID_SVXITEMS_ORI_STANDARD.mpId) + OString::number(static_cast<int>(nVal));
+ return SvxResId(TranslateId(RID_SVXITEMS_ORI_STANDARD.mpContext, id.getStr()));
+}
+
+SvxOrientationItem* SvxOrientationItem::Clone( SfxItemPool* ) const
+{
+ return new SvxOrientationItem( *this );
+}
+
+sal_uInt16 SvxOrientationItem::GetValueCount() const
+{
+ return static_cast<sal_uInt16>(SvxCellOrientation::Stacked) + 1; // last enum value + 1
+}
+
+bool SvxOrientationItem::IsStacked() const
+{
+ return GetValue() == SvxCellOrientation::Stacked;
+}
+
+Degree100 SvxOrientationItem::GetRotation( Degree100 nStdAngle ) const
+{
+ Degree100 nAngle = nStdAngle;
+ switch( GetValue() )
+ {
+ case SvxCellOrientation::BottomUp: nAngle = 9000_deg100; break;
+ case SvxCellOrientation::TopBottom: nAngle = 27000_deg100; break;
+ default: ; //prevent warning
+ }
+ return nAngle;
+}
+
+SvxMarginItem::SvxMarginItem( const TypedWhichId<SvxMarginItem> nId ) :
+
+ SfxPoolItem( nId ),
+
+ nLeftMargin ( 20 ),
+ nTopMargin ( 20 ),
+ nRightMargin ( 20 ),
+ nBottomMargin( 20 )
+{
+}
+
+
+SvxMarginItem::SvxMarginItem( sal_Int16 nLeft,
+ sal_Int16 nTop,
+ sal_Int16 nRight,
+ sal_Int16 nBottom,
+ const TypedWhichId<SvxMarginItem> nId ) :
+ SfxPoolItem( nId ),
+
+ nLeftMargin ( nLeft ),
+ nTopMargin ( nTop ),
+ nRightMargin ( nRight ),
+ nBottomMargin( nBottom )
+{
+}
+
+
+bool SvxMarginItem::GetPresentation
+(
+ SfxItemPresentation ePres,
+ MapUnit eCoreUnit,
+ MapUnit ePresUnit,
+ OUString& rText, const IntlWrapper& rIntl
+) const
+{
+ OUString cpDelimTmp(cpDelim);
+
+ switch ( ePres )
+ {
+ case SfxItemPresentation::Nameless:
+ {
+ rText = GetMetricText( static_cast<tools::Long>(nLeftMargin), eCoreUnit, ePresUnit, &rIntl ) +
+ cpDelimTmp +
+ GetMetricText( static_cast<tools::Long>(nTopMargin), eCoreUnit, ePresUnit, &rIntl ) +
+ cpDelimTmp +
+ GetMetricText( static_cast<tools::Long>(nRightMargin), eCoreUnit, ePresUnit, &rIntl ) +
+ cpDelimTmp +
+ GetMetricText( static_cast<tools::Long>(nBottomMargin), eCoreUnit, ePresUnit, &rIntl );
+ return true;
+ }
+ case SfxItemPresentation::Complete:
+ {
+ rText = SvxResId(RID_SVXITEMS_MARGIN_LEFT) +
+ GetMetricText( static_cast<tools::Long>(nLeftMargin), eCoreUnit, ePresUnit, &rIntl ) +
+ " " + EditResId(GetMetricId(ePresUnit)) +
+ cpDelimTmp +
+ SvxResId(RID_SVXITEMS_MARGIN_TOP) +
+ GetMetricText( static_cast<tools::Long>(nTopMargin), eCoreUnit, ePresUnit, &rIntl ) +
+ " " + EditResId(GetMetricId(ePresUnit)) +
+ cpDelimTmp +
+ SvxResId(RID_SVXITEMS_MARGIN_RIGHT) +
+ GetMetricText( static_cast<tools::Long>(nRightMargin), eCoreUnit, ePresUnit, &rIntl ) +
+ " " + EditResId(GetMetricId(ePresUnit)) +
+ cpDelimTmp +
+ SvxResId(RID_SVXITEMS_MARGIN_BOTTOM) +
+ GetMetricText( static_cast<tools::Long>(nBottomMargin), eCoreUnit, ePresUnit, &rIntl ) +
+ " " + EditResId(GetMetricId(ePresUnit));
+ return true;
+ }
+ default: ; //prevent warning
+ }
+ return false;
+}
+
+
+bool SvxMarginItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ return ( ( nLeftMargin == static_cast<const SvxMarginItem&>(rItem).nLeftMargin ) &&
+ ( nTopMargin == static_cast<const SvxMarginItem&>(rItem).nTopMargin ) &&
+ ( nRightMargin == static_cast<const SvxMarginItem&>(rItem).nRightMargin ) &&
+ ( nBottomMargin == static_cast<const SvxMarginItem&>(rItem).nBottomMargin ) );
+}
+
+SvxMarginItem* SvxMarginItem::Clone( SfxItemPool* ) const
+{
+ return new SvxMarginItem(*this);
+}
+
+bool SvxMarginItem::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+ switch ( nMemberId )
+ {
+ // now sign everything
+ case MID_MARGIN_L_MARGIN:
+ rVal <<= static_cast<sal_Int32>( bConvert ? convertTwipToMm100(nLeftMargin) : nLeftMargin );
+ break;
+ case MID_MARGIN_R_MARGIN:
+ rVal <<= static_cast<sal_Int32>( bConvert ? convertTwipToMm100(nRightMargin) : nRightMargin );
+ break;
+ case MID_MARGIN_UP_MARGIN:
+ rVal <<= static_cast<sal_Int32>( bConvert ? convertTwipToMm100(nTopMargin) : nTopMargin );
+ break;
+ case MID_MARGIN_LO_MARGIN:
+ rVal <<= static_cast<sal_Int32>( bConvert ? convertTwipToMm100(nBottomMargin) : nBottomMargin );
+ break;
+ default:
+ OSL_FAIL("unknown MemberId");
+ return false;
+ }
+ return true;
+}
+
+
+bool SvxMarginItem::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ bool bConvert = ( ( nMemberId & CONVERT_TWIPS ) != 0 );
+ tools::Long nMaxVal = bConvert ? convertTwipToMm100(SHRT_MAX) : SHRT_MAX; // members are sal_Int16
+ sal_Int32 nVal = 0;
+ if(!(rVal >>= nVal) || (nVal > nMaxVal))
+ return false;
+
+ switch ( nMemberId & ~CONVERT_TWIPS )
+ {
+ case MID_MARGIN_L_MARGIN:
+ nLeftMargin = static_cast<sal_Int16>( bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : nVal );
+ break;
+ case MID_MARGIN_R_MARGIN:
+ nRightMargin = static_cast<sal_Int16>( bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : nVal );
+ break;
+ case MID_MARGIN_UP_MARGIN:
+ nTopMargin = static_cast<sal_Int16>( bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : nVal );
+ break;
+ case MID_MARGIN_LO_MARGIN:
+ nBottomMargin = static_cast<sal_Int16>( bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : nVal );
+ break;
+ default:
+ OSL_FAIL("unknown MemberId");
+ return false;
+ }
+ return true;
+}
+
+
+void SvxMarginItem::SetLeftMargin( sal_Int16 nLeft )
+{
+ nLeftMargin = nLeft;
+}
+
+
+void SvxMarginItem::SetTopMargin( sal_Int16 nTop )
+{
+ nTopMargin = nTop;
+}
+
+
+void SvxMarginItem::SetRightMargin( sal_Int16 nRight )
+{
+ nRightMargin = nRight;
+}
+
+
+void SvxMarginItem::SetBottomMargin( sal_Int16 nBottom )
+{
+ nBottomMargin = nBottom;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/autoformathelper.cxx b/svx/source/items/autoformathelper.cxx
new file mode 100644
index 000000000..0ae522fbd
--- /dev/null
+++ b/svx/source/items/autoformathelper.cxx
@@ -0,0 +1,393 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/autoformathelper.hxx>
+#include <tools/stream.hxx>
+#include <svl/legacyitem.hxx>
+#include <editeng/legacyitem.hxx>
+#include <svx/legacyitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <svl/eitem.hxx>
+#include <svx/algitem.hxx>
+#include <svl/intitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <osl/thread.h>
+
+//////////////////////////////////////////////////////////////////////////////
+
+AutoFormatVersions::AutoFormatVersions()
+: nFontVersion(0),
+ nFontHeightVersion(0),
+ nWeightVersion(0),
+ nPostureVersion(0),
+ nUnderlineVersion(0),
+ nOverlineVersion(0),
+ nCrossedOutVersion(0),
+ nContourVersion(0),
+ nShadowedVersion(0),
+ nColorVersion(0),
+ nBoxVersion(0),
+ nLineVersion(0),
+ nBrushVersion(0),
+ nAdjustVersion(0),
+ nHorJustifyVersion(0),
+ nVerJustifyVersion(0),
+ nOrientationVersion(0),
+ nMarginVersion(0),
+ nBoolVersion(0),
+ nInt32Version(0),
+ nRotateModeVersion(0),
+ nNumFormatVersion(0)
+{
+}
+
+const sal_uInt16 AUTOFORMAT_ID_300OVRLN = 10031;
+const sal_uInt16 AUTOFORMAT_ID_680DR14 = 10011;
+const sal_uInt16 AUTOFORMAT_ID_504 = 9801;
+
+void AutoFormatVersions::LoadBlockA( SvStream& rStream, sal_uInt16 nVer )
+{
+ rStream.ReadUInt16( nFontVersion );
+ rStream.ReadUInt16( nFontHeightVersion );
+ rStream.ReadUInt16( nWeightVersion );
+ rStream.ReadUInt16( nPostureVersion );
+ rStream.ReadUInt16( nUnderlineVersion );
+ if ( nVer >= AUTOFORMAT_ID_300OVRLN )
+ rStream.ReadUInt16( nOverlineVersion );
+ rStream.ReadUInt16( nCrossedOutVersion );
+ rStream.ReadUInt16( nContourVersion );
+ rStream.ReadUInt16( nShadowedVersion );
+ rStream.ReadUInt16( nColorVersion );
+ rStream.ReadUInt16( nBoxVersion );
+ if ( nVer >= AUTOFORMAT_ID_680DR14 )
+ rStream.ReadUInt16( nLineVersion );
+ rStream.ReadUInt16( nBrushVersion );
+ rStream.ReadUInt16( nAdjustVersion );
+}
+
+void AutoFormatVersions::LoadBlockB( SvStream& rStream, sal_uInt16 nVer )
+{
+ rStream.ReadUInt16( nHorJustifyVersion );
+ rStream.ReadUInt16( nVerJustifyVersion );
+ rStream.ReadUInt16( nOrientationVersion );
+ rStream.ReadUInt16( nMarginVersion );
+ rStream.ReadUInt16( nBoolVersion );
+ if ( nVer >= AUTOFORMAT_ID_504 )
+ {
+ rStream.ReadUInt16( nInt32Version );
+ rStream.ReadUInt16( nRotateModeVersion );
+ }
+ rStream.ReadUInt16( nNumFormatVersion );
+}
+
+void AutoFormatVersions::WriteBlockA(SvStream& rStream, sal_uInt16 fileVersion)
+{
+ rStream.WriteUInt16(legacy::SvxFont::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxFontHeight::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxWeight::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxPosture::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxTextLine::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxTextLine::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxCrossedOut::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SfxBool::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SfxBool::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxColor::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxBox::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxLine::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxBrush::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxAdjust::GetVersion(fileVersion));
+}
+
+void AutoFormatVersions::WriteBlockB(SvStream& rStream, sal_uInt16 fileVersion)
+{
+ rStream.WriteUInt16(legacy::SvxHorJustify::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxVerJustify::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxOrientation::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxMargin::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SfxBool::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::CntInt32::GetVersion(fileVersion));
+ rStream.WriteUInt16(legacy::SvxRotateMode::GetVersion(fileVersion));
+ rStream.WriteUInt16( 0 ); // NumberFormat
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void AutoFormatBase::SetFont( const SvxFontItem& rNew ) { m_aFont.reset(rNew.Clone()); }
+void AutoFormatBase::SetHeight( const SvxFontHeightItem& rNew ) { m_aHeight.reset(rNew.Clone()); }
+void AutoFormatBase::SetWeight( const SvxWeightItem& rNew ) { m_aWeight.reset(rNew.Clone()); }
+void AutoFormatBase::SetPosture( const SvxPostureItem& rNew ) { m_aPosture.reset(rNew.Clone()); }
+void AutoFormatBase::SetCJKFont( const SvxFontItem& rNew ) { m_aCJKFont.reset(rNew.Clone()); }
+void AutoFormatBase::SetCJKHeight( const SvxFontHeightItem& rNew ) { m_aCJKHeight.reset(rNew.Clone()); }
+void AutoFormatBase::SetCJKWeight( const SvxWeightItem& rNew ) { m_aCJKWeight.reset(rNew.Clone()); }
+void AutoFormatBase::SetCJKPosture( const SvxPostureItem& rNew ) { m_aCJKPosture.reset(rNew.Clone()); }
+void AutoFormatBase::SetCTLFont( const SvxFontItem& rNew ) { m_aCTLFont.reset(rNew.Clone()); }
+void AutoFormatBase::SetCTLHeight( const SvxFontHeightItem& rNew ) { m_aCTLHeight.reset(rNew.Clone()); }
+void AutoFormatBase::SetCTLWeight( const SvxWeightItem& rNew ) { m_aCTLWeight.reset(rNew.Clone()); }
+void AutoFormatBase::SetCTLPosture( const SvxPostureItem& rNew ) { m_aCTLPosture.reset(rNew.Clone()); }
+void AutoFormatBase::SetUnderline( const SvxUnderlineItem& rNew ) { m_aUnderline.reset(rNew.Clone()); }
+void AutoFormatBase::SetOverline( const SvxOverlineItem& rNew ) { m_aOverline.reset(rNew.Clone()); }
+void AutoFormatBase::SetCrossedOut( const SvxCrossedOutItem& rNew ) { m_aCrossedOut.reset(rNew.Clone()); }
+void AutoFormatBase::SetContour( const SvxContourItem& rNew ) { m_aContour.reset(rNew.Clone()); }
+void AutoFormatBase::SetShadowed( const SvxShadowedItem& rNew ) { m_aShadowed.reset(rNew.Clone()); }
+void AutoFormatBase::SetColor( const SvxColorItem& rNew ) { m_aColor.reset(rNew.Clone()); }
+void AutoFormatBase::SetBox( const SvxBoxItem& rNew ) { m_aBox.reset(rNew.Clone()); }
+void AutoFormatBase::SetTLBR( const SvxLineItem& rNew ) { m_aTLBR.reset(rNew.Clone()); }
+void AutoFormatBase::SetBLTR( const SvxLineItem& rNew ) { m_aBLTR.reset(rNew.Clone()); }
+void AutoFormatBase::SetBackground( const SvxBrushItem& rNew ) { m_aBackground.reset(rNew.Clone()); }
+void AutoFormatBase::SetAdjust( const SvxAdjustItem& rNew ) { m_aAdjust.reset(rNew.Clone()); }
+void AutoFormatBase::SetHorJustify( const SvxHorJustifyItem& rNew ) { m_aHorJustify.reset(rNew.Clone()); }
+void AutoFormatBase::SetVerJustify( const SvxVerJustifyItem& rNew ) { m_aVerJustify.reset(rNew.Clone()); }
+void AutoFormatBase::SetStacked( const SfxBoolItem& rNew ) { m_aStacked.reset(rNew.Clone()); }
+void AutoFormatBase::SetMargin( const SvxMarginItem& rNew ) { m_aMargin.reset(rNew.Clone()); }
+void AutoFormatBase::SetLinebreak( const SfxBoolItem& rNew ) { m_aLinebreak.reset(rNew.Clone()); }
+void AutoFormatBase::SetRotateAngle( const SfxInt32Item& rNew ) { m_aRotateAngle.reset(rNew.Clone()); }
+void AutoFormatBase::SetRotateMode( const SvxRotateModeItem& rNew ) { m_aRotateMode.reset(rNew.Clone()); }
+
+AutoFormatBase::AutoFormatBase()
+{
+}
+
+AutoFormatBase::AutoFormatBase( const AutoFormatBase& rNew )
+: m_aFont(rNew.m_aFont->Clone()),
+ m_aHeight(rNew.m_aHeight->Clone()),
+ m_aWeight(rNew.m_aWeight->Clone()),
+ m_aPosture(rNew.m_aPosture->Clone()),
+ m_aCJKFont(rNew.m_aCJKFont->Clone()),
+ m_aCJKHeight(rNew.m_aCJKHeight->Clone()),
+ m_aCJKWeight(rNew.m_aCJKWeight->Clone()),
+ m_aCJKPosture(rNew.m_aCJKPosture->Clone()),
+ m_aCTLFont(rNew.m_aCTLFont->Clone()),
+ m_aCTLHeight(rNew.m_aCTLHeight->Clone()),
+ m_aCTLWeight(rNew.m_aCTLWeight->Clone()),
+ m_aCTLPosture(rNew.m_aCTLPosture->Clone()),
+ m_aUnderline(rNew.m_aUnderline->Clone()),
+ m_aOverline(rNew.m_aOverline->Clone()),
+ m_aCrossedOut(rNew.m_aCrossedOut->Clone()),
+ m_aContour(rNew.m_aContour->Clone()),
+ m_aShadowed(rNew.m_aShadowed->Clone()),
+ m_aColor(rNew.m_aColor->Clone()),
+ m_aBox(rNew.m_aBox->Clone()),
+ m_aTLBR(rNew.m_aTLBR->Clone()),
+ m_aBLTR(rNew.m_aBLTR->Clone()),
+ m_aBackground(rNew.m_aBackground->Clone()),
+ m_aAdjust(rNew.m_aAdjust->Clone()),
+ m_aHorJustify(rNew.m_aHorJustify->Clone()),
+ m_aVerJustify(rNew.m_aVerJustify->Clone()),
+ m_aStacked(rNew.m_aStacked->Clone()),
+ m_aMargin(rNew.m_aMargin->Clone()),
+ m_aLinebreak(rNew.m_aLinebreak->Clone()),
+ m_aRotateAngle(rNew.m_aRotateAngle->Clone()),
+ m_aRotateMode(rNew.m_aRotateMode->Clone())
+{
+}
+
+AutoFormatBase::~AutoFormatBase()
+{
+}
+
+AutoFormatBase& AutoFormatBase::operator=(const AutoFormatBase& rRef)
+{
+ // check self-assignment
+ if(this == &rRef)
+ {
+ return *this;
+ }
+
+ // copy local members - this will use ::Clone() on all involved Items
+ SetFont(rRef.GetFont());
+ SetHeight(rRef.GetHeight());
+ SetWeight(rRef.GetWeight());
+ SetPosture(rRef.GetPosture());
+ SetCJKFont(rRef.GetCJKFont());
+ SetCJKHeight(rRef.GetCJKHeight());
+ SetCJKWeight(rRef.GetCJKWeight());
+ SetCJKPosture(rRef.GetCJKPosture());
+ SetCTLFont(rRef.GetCTLFont());
+ SetCTLHeight(rRef.GetCTLHeight());
+ SetCTLWeight(rRef.GetCTLWeight());
+ SetCTLPosture(rRef.GetCTLPosture());
+ SetUnderline(rRef.GetUnderline());
+ SetOverline(rRef.GetOverline());
+ SetCrossedOut(rRef.GetCrossedOut());
+ SetContour(rRef.GetContour());
+ SetShadowed(rRef.GetShadowed());
+ SetColor(rRef.GetColor());
+ SetBox(rRef.GetBox());
+ SetTLBR(rRef.GetTLBR());
+ SetBLTR(rRef.GetBLTR());
+ SetBackground(rRef.GetBackground());
+ SetAdjust(rRef.GetAdjust());
+ SetHorJustify(rRef.GetHorJustify());
+ SetVerJustify(rRef.GetVerJustify());
+ SetStacked(rRef.GetStacked());
+ SetMargin(rRef.GetMargin());
+ SetLinebreak(rRef.GetLinebreak());
+ SetRotateAngle(rRef.GetRotateAngle());
+ SetRotateMode(rRef.GetRotateMode());
+
+ return *this;
+}
+
+const sal_uInt16 AUTOFORMAT_DATA_ID_641 = 10002;
+const sal_uInt16 AUTOFORMAT_DATA_ID_300OVRLN = 10032;
+const sal_uInt16 AUTOFORMAT_DATA_ID_680DR14 = 10012;
+const sal_uInt16 AUTOFORMAT_DATA_ID_504 = 9802;
+
+bool AutoFormatBase::LoadBlockA( SvStream& rStream, const AutoFormatVersions& rVersions, sal_uInt16 nVer )
+{
+ legacy::SvxFont::Create(*m_aFont, rStream, rVersions.nFontVersion);
+
+ if( rStream.GetStreamCharSet() == m_aFont->GetCharSet() )
+ {
+ m_aFont->SetCharSet(::osl_getThreadTextEncoding());
+ }
+
+ legacy::SvxFontHeight::Create(*m_aHeight, rStream, rVersions.nFontHeightVersion);
+ legacy::SvxWeight::Create(*m_aWeight, rStream, rVersions.nWeightVersion);
+ legacy::SvxPosture::Create(*m_aPosture, rStream, rVersions.nPostureVersion);
+
+ // --- from 641 on: CJK and CTL font settings
+ if( AUTOFORMAT_DATA_ID_641 <= nVer )
+ {
+ legacy::SvxFont::Create(*m_aCJKFont, rStream, rVersions.nFontVersion);
+ legacy::SvxFontHeight::Create(*m_aCJKHeight, rStream, rVersions.nFontHeightVersion);
+ legacy::SvxWeight::Create(*m_aCJKWeight, rStream, rVersions.nWeightVersion);
+ legacy::SvxPosture::Create(*m_aCJKPosture, rStream, rVersions.nPostureVersion);
+
+ legacy::SvxFont::Create(*m_aCTLFont, rStream, rVersions.nFontVersion);
+ legacy::SvxFontHeight::Create(*m_aCTLHeight, rStream, rVersions.nFontHeightVersion);
+ legacy::SvxWeight::Create(*m_aCTLWeight, rStream, rVersions.nWeightVersion);
+ legacy::SvxPosture::Create(*m_aCTLPosture, rStream, rVersions.nPostureVersion);
+ }
+
+ legacy::SvxTextLine::Create(*m_aUnderline, rStream, rVersions.nUnderlineVersion);
+
+ if( nVer >= AUTOFORMAT_DATA_ID_300OVRLN )
+ {
+ legacy::SvxTextLine::Create(*m_aOverline, rStream, rVersions.nOverlineVersion);
+ }
+
+ legacy::SvxCrossedOut::Create(*m_aCrossedOut, rStream, rVersions.nCrossedOutVersion);
+ legacy::SfxBool::Create(*m_aContour, rStream, rVersions.nContourVersion);
+ legacy::SfxBool::Create(*m_aShadowed, rStream, rVersions.nShadowedVersion);
+ legacy::SvxColor::Create(*m_aColor, rStream, rVersions.nColorVersion);
+ legacy::SvxBox::Create(*m_aBox, rStream, rVersions.nBoxVersion);
+
+ // --- from 680/dr14 on: diagonal frame lines
+ if( nVer >= AUTOFORMAT_DATA_ID_680DR14 )
+ {
+ legacy::SvxLine::Create(*m_aTLBR, rStream, rVersions.nLineVersion);
+ legacy::SvxLine::Create(*m_aBLTR, rStream, rVersions.nLineVersion);
+ }
+
+ legacy::SvxBrush::Create(*m_aBackground, rStream, rVersions.nBrushVersion);
+ legacy::SvxAdjust::Create(*m_aAdjust, rStream, rVersions.nAdjustVersion);
+
+ return ERRCODE_NONE == rStream.GetError();
+}
+
+bool AutoFormatBase::LoadBlockB( SvStream& rStream, const AutoFormatVersions& rVersions, sal_uInt16 nVer )
+{
+ legacy::SvxHorJustify::Create(*m_aHorJustify, rStream, rVersions.nHorJustifyVersion);
+ legacy::SvxVerJustify::Create(*m_aVerJustify, rStream, rVersions.nVerJustifyVersion);
+ SvxOrientationItem aOrientation( SvxCellOrientation::Standard, TypedWhichId<SvxOrientationItem>(0));
+ legacy::SvxOrientation::Create(aOrientation, rStream, rVersions.nOrientationVersion);
+ legacy::SvxMargin::Create(*m_aMargin, rStream, rVersions.nMarginVersion);
+ legacy::SfxBool::Create(*m_aLinebreak, rStream, rVersions.nBoolVersion);
+
+ if ( nVer >= AUTOFORMAT_DATA_ID_504 )
+ {
+ legacy::CntInt32::Create(*m_aRotateAngle, rStream, rVersions.nInt32Version);
+ legacy::SvxRotateMode::Create(*m_aRotateMode, rStream, rVersions.nRotateModeVersion);
+ }
+
+ m_aStacked->SetValue( aOrientation.IsStacked() );
+ m_aRotateAngle->SetValue( aOrientation.GetRotation( Degree100(m_aRotateAngle->GetValue()) ).get() );
+
+ return ERRCODE_NONE == rStream.GetError();
+}
+
+bool AutoFormatBase::SaveBlockA( SvStream& rStream, sal_uInt16 fileVersion ) const
+{
+ legacy::SvxFont::Store(*m_aFont, rStream, legacy::SvxFont::GetVersion(fileVersion));
+ legacy::SvxFontHeight::Store(*m_aHeight, rStream, legacy::SvxFontHeight::GetVersion(fileVersion));
+ legacy::SvxWeight::Store(*m_aWeight, rStream, legacy::SvxWeight::GetVersion(fileVersion));
+ legacy::SvxPosture::Store(*m_aPosture, rStream, legacy::SvxPosture::GetVersion(fileVersion));
+
+ // --- from 641 on: CJK and CTL font settings
+ legacy::SvxFont::Store(*m_aCJKFont, rStream, legacy::SvxFont::GetVersion(fileVersion));
+ legacy::SvxFontHeight::Store(*m_aCJKHeight, rStream, legacy::SvxFontHeight::GetVersion(fileVersion));
+ legacy::SvxWeight::Store(*m_aCJKWeight, rStream, legacy::SvxWeight::GetVersion(fileVersion));
+ legacy::SvxPosture::Store(*m_aCJKPosture, rStream, legacy::SvxPosture::GetVersion(fileVersion));
+
+ legacy::SvxFont::Store(*m_aCTLFont, rStream, legacy::SvxFont::GetVersion(fileVersion));
+ legacy::SvxFontHeight::Store(*m_aCTLHeight, rStream, legacy::SvxFontHeight::GetVersion(fileVersion));
+ legacy::SvxWeight::Store(*m_aCTLWeight, rStream, legacy::SvxWeight::GetVersion(fileVersion));
+ legacy::SvxPosture::Store(*m_aCTLPosture, rStream, legacy::SvxPosture::GetVersion(fileVersion));
+
+ legacy::SvxTextLine::Store(*m_aUnderline, rStream, legacy::SvxTextLine::GetVersion(fileVersion));
+
+ // --- from DEV300/overline2 on: overline support
+ legacy::SvxTextLine::Store(*m_aOverline, rStream, legacy::SvxTextLine::GetVersion(fileVersion));
+ legacy::SvxCrossedOut::Store(*m_aCrossedOut, rStream, legacy::SvxCrossedOut::GetVersion(fileVersion));
+ legacy::SfxBool::Store(*m_aContour, rStream, legacy::SfxBool::GetVersion(fileVersion));
+ legacy::SfxBool::Store(*m_aShadowed, rStream, legacy::SfxBool::GetVersion(fileVersion));
+ legacy::SvxColor::Store(*m_aColor, rStream, legacy::SvxColor::GetVersion(fileVersion));
+ legacy::SvxBox::Store(*m_aBox, rStream, legacy::SvxBox::GetVersion(fileVersion));
+
+ // --- from 680/dr14 on: diagonal frame lines
+ legacy::SvxLine::Store(*m_aTLBR, rStream, legacy::SvxLine::GetVersion(fileVersion));
+ legacy::SvxLine::Store(*m_aBLTR, rStream, legacy::SvxLine::GetVersion(fileVersion));
+ legacy::SvxBrush::Store(*m_aBackground, rStream, legacy::SvxBrush::GetVersion(fileVersion));
+ legacy::SvxAdjust::Store(*m_aAdjust, rStream, legacy::SvxAdjust::GetVersion(fileVersion));
+
+ return ERRCODE_NONE == rStream.GetError();
+}
+
+bool AutoFormatBase::SaveBlockB( SvStream& rStream, sal_uInt16 fileVersion ) const
+{
+ legacy::SvxHorJustify::Store(*m_aHorJustify, rStream, legacy::SvxHorJustify::GetVersion(fileVersion));
+ legacy::SvxVerJustify::Store(*m_aVerJustify, rStream, legacy::SvxVerJustify::GetVersion(fileVersion));
+ SvxOrientationItem aOrientation( Degree100(m_aRotateAngle->GetValue()), m_aStacked->GetValue(), TypedWhichId<SvxOrientationItem>(0) );
+ legacy::SvxOrientation::Store(aOrientation, rStream, legacy::SvxOrientation::GetVersion(fileVersion));
+ legacy::SvxMargin::Store(*m_aMargin, rStream, legacy::SvxMargin::GetVersion(fileVersion));
+ legacy::SfxBool::Store(*m_aLinebreak, rStream, legacy::SfxBool::GetVersion(fileVersion));
+
+ // Calc Rotation from SO5
+ legacy::CntInt32::Store(*m_aRotateAngle, rStream, legacy::CntInt32::GetVersion(fileVersion));
+ legacy::SvxRotateMode::Store(*m_aRotateMode, rStream, legacy::SvxRotateMode::GetVersion(fileVersion));
+
+ return ERRCODE_NONE == rStream.GetError();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/chrtitem.cxx b/svx/source/items/chrtitem.cxx
new file mode 100644
index 000000000..6fb6e8523
--- /dev/null
+++ b/svx/source/items/chrtitem.cxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/math.hxx>
+#include <unotools/intlwrapper.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
+
+#include <svx/chrtitem.hxx>
+
+using namespace ::com::sun::star;
+
+
+SfxPoolItem* SvxDoubleItem::CreateDefault() { return new SvxDoubleItem(0.0, TypedWhichId<SvxDoubleItem>(0));}
+
+SvxChartTextOrderItem::SvxChartTextOrderItem(SvxChartTextOrder eOrder,
+ TypedWhichId<SvxChartTextOrderItem> nId) :
+ SfxEnumItem(nId, eOrder)
+{
+}
+
+SvxChartTextOrderItem* SvxChartTextOrderItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SvxChartTextOrderItem(*this);
+}
+
+bool SvxChartTextOrderItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ // the order of the two enums is not equal, so a mapping is required
+ css::chart::ChartAxisArrangeOrderType eAO;
+ SvxChartTextOrder eOrder( GetValue());
+
+ switch( eOrder )
+ {
+ case SvxChartTextOrder::SideBySide:
+ eAO = css::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE; break;
+ case SvxChartTextOrder::UpDown:
+ eAO = css::chart::ChartAxisArrangeOrderType_STAGGER_ODD; break;
+ case SvxChartTextOrder::DownUp:
+ eAO = css::chart::ChartAxisArrangeOrderType_STAGGER_EVEN; break;
+ case SvxChartTextOrder::Auto:
+ eAO = css::chart::ChartAxisArrangeOrderType_AUTO; break;
+ }
+
+ rVal <<= eAO;
+
+ return true;
+}
+
+
+bool SvxChartTextOrderItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
+{
+ // the order of the two enums is not equal, so a mapping is required
+ css::chart::ChartAxisArrangeOrderType eAO;
+ SvxChartTextOrder eOrder;
+
+ if(!(rVal >>= eAO))
+ {
+ // also try an int (for Basic)
+ sal_Int32 nAO = 0;
+ if(!(rVal >>= nAO))
+ return false;
+ eAO = static_cast< css::chart::ChartAxisArrangeOrderType >( nAO );
+ }
+
+ switch( eAO )
+ {
+ case css::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE:
+ eOrder = SvxChartTextOrder::SideBySide; break;
+ case css::chart::ChartAxisArrangeOrderType_STAGGER_ODD:
+ eOrder = SvxChartTextOrder::UpDown; break;
+ case css::chart::ChartAxisArrangeOrderType_STAGGER_EVEN:
+ eOrder = SvxChartTextOrder::DownUp; break;
+ case css::chart::ChartAxisArrangeOrderType_AUTO:
+ eOrder = SvxChartTextOrder::Auto; break;
+ default:
+ return false;
+ }
+
+ SetValue( eOrder );
+
+ return true;
+}
+
+SvxDoubleItem::SvxDoubleItem(double fValue, TypedWhichId<SvxDoubleItem> nId) :
+ SfxPoolItem(nId),
+ fVal(fValue)
+{
+}
+
+SvxDoubleItem::SvxDoubleItem(const SvxDoubleItem& rItem) :
+ SfxPoolItem(rItem),
+ fVal(rItem.fVal)
+{
+}
+
+bool SvxDoubleItem::GetPresentation
+ ( SfxItemPresentation /*ePresentation*/, MapUnit /*eCoreMetric*/,
+ MapUnit /*ePresentationMetric*/, OUString& rText,
+ const IntlWrapper& rIntlWrapper) const
+{
+ rText = ::rtl::math::doubleToUString( fVal, rtl_math_StringFormat_E, 4,
+ rIntlWrapper.getLocaleData()->getNumDecimalSep()[0], true );
+ return true;
+}
+
+bool SvxDoubleItem::operator == (const SfxPoolItem& rItem) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+ return static_cast<const SvxDoubleItem&>(rItem).fVal == fVal;
+}
+
+SvxDoubleItem* SvxDoubleItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SvxDoubleItem(*this);
+}
+
+bool SvxDoubleItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ rVal <<= fVal;
+ return true;
+}
+
+bool SvxDoubleItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
+{
+ return rVal >>= fVal;
+}
+
+SvxChartKindErrorItem::SvxChartKindErrorItem(SvxChartKindError eOrient,
+ TypedWhichId<SvxChartKindErrorItem> nId) :
+ SfxEnumItem(nId, eOrient)
+{
+}
+
+SvxChartKindErrorItem* SvxChartKindErrorItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SvxChartKindErrorItem(*this);
+}
+
+SvxChartIndicateItem::SvxChartIndicateItem(SvxChartIndicate eOrient,
+ TypedWhichId<SvxChartIndicateItem> nId) :
+ SfxEnumItem(nId, eOrient)
+{
+}
+
+SvxChartIndicateItem* SvxChartIndicateItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SvxChartIndicateItem(*this);
+}
+
+SvxChartRegressItem::SvxChartRegressItem(SvxChartRegress eOrient,
+ TypedWhichId<SvxChartRegressItem> nId) :
+ SfxEnumItem(nId, eOrient)
+{
+}
+
+SvxChartRegressItem* SvxChartRegressItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SvxChartRegressItem(*this);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/clipfmtitem.cxx b/svx/source/items/clipfmtitem.cxx
new file mode 100644
index 000000000..caae609f6
--- /dev/null
+++ b/svx/source/items/clipfmtitem.cxx
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <vector>
+
+#include <svx/clipfmtitem.hxx>
+#include <com/sun/star/frame/status/ClipboardFormats.hpp>
+
+struct SvxClipboardFormatItem_Impl
+{
+ std::vector<OUString> aFmtNms;
+ std::vector<SotClipboardFormatId> aFmtIds;
+
+ SvxClipboardFormatItem_Impl() {}
+};
+
+SfxPoolItem* SvxClipboardFormatItem::CreateDefault() { return new SvxClipboardFormatItem(TypedWhichId<SvxClipboardFormatItem>(0)); };
+
+SvxClipboardFormatItem::SvxClipboardFormatItem( TypedWhichId<SvxClipboardFormatItem> nId )
+ : SfxPoolItem( nId ), pImpl( new SvxClipboardFormatItem_Impl )
+{
+}
+
+SvxClipboardFormatItem::SvxClipboardFormatItem( const SvxClipboardFormatItem& rCpy )
+ : SfxPoolItem( rCpy ),
+ pImpl( new SvxClipboardFormatItem_Impl( *rCpy.pImpl ) )
+{
+}
+
+SvxClipboardFormatItem::~SvxClipboardFormatItem()
+{
+}
+
+bool SvxClipboardFormatItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ sal_uInt16 nCount = Count();
+
+ css::frame::status::ClipboardFormats aClipFormats;
+
+ aClipFormats.Identifiers.realloc( nCount );
+ auto pIdentifiers = aClipFormats.Identifiers.getArray();
+ aClipFormats.Names.realloc( nCount );
+ auto pNames = aClipFormats.Names.getArray();
+ for ( sal_uInt16 n=0; n < nCount; n++ )
+ {
+ pIdentifiers[n] = static_cast<sal_Int64>(GetClipbrdFormatId( n ));
+ pNames[n] = GetClipbrdFormatName( n );
+ }
+
+ rVal <<= aClipFormats;
+ return true;
+}
+
+bool SvxClipboardFormatItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
+{
+ css::frame::status::ClipboardFormats aClipFormats;
+ if ( rVal >>= aClipFormats )
+ {
+ sal_uInt16 nCount = sal_uInt16( aClipFormats.Identifiers.getLength() );
+
+ pImpl->aFmtIds.clear();
+ pImpl->aFmtNms.clear();
+ for ( sal_uInt16 n=0; n < nCount; ++n )
+ AddClipbrdFormat( static_cast<SotClipboardFormatId>(aClipFormats.Identifiers[n]), aClipFormats.Names[n], n );
+
+ return true;
+ }
+
+ return false;
+}
+
+bool SvxClipboardFormatItem::operator==( const SfxPoolItem& rComp ) const
+{
+ if (!SfxPoolItem::operator==(rComp))
+ return false;
+ const SvxClipboardFormatItem& rCmp = static_cast<const SvxClipboardFormatItem&>(rComp);
+ if(rCmp.pImpl->aFmtNms.size() != pImpl->aFmtNms.size())
+ return false;
+
+ int nRet = 1;
+ for( sal_uInt16 n = 0, nEnd = rCmp.pImpl->aFmtNms.size(); n < nEnd; ++n )
+ {
+ if( pImpl->aFmtIds[ n ] != rCmp.pImpl->aFmtIds[ n ] ||
+ pImpl->aFmtNms[n] != rCmp.pImpl->aFmtNms[n] )
+ {
+ nRet = 0;
+ break;
+ }
+ }
+
+ return nRet;
+}
+
+SvxClipboardFormatItem* SvxClipboardFormatItem::Clone( SfxItemPool * /*pPool*/ ) const
+{
+ return new SvxClipboardFormatItem( *this );
+}
+
+void SvxClipboardFormatItem::AddClipbrdFormat( SotClipboardFormatId nId )
+{
+ sal_uInt16 nPos = pImpl->aFmtNms.size();
+
+ pImpl->aFmtNms.insert( pImpl->aFmtNms.begin() + nPos, OUString());
+ pImpl->aFmtIds.insert( pImpl->aFmtIds.begin() + nPos, nId );
+}
+
+void SvxClipboardFormatItem::AddClipbrdFormat( SotClipboardFormatId nId, const OUString& rName,
+ sal_uInt16 nPos )
+{
+ if( nPos > pImpl->aFmtNms.size() )
+ nPos = pImpl->aFmtNms.size();
+
+ pImpl->aFmtNms.insert(pImpl->aFmtNms.begin() + nPos, rName);
+ pImpl->aFmtIds.insert( pImpl->aFmtIds.begin()+nPos, nId );
+}
+
+sal_uInt16 SvxClipboardFormatItem::Count() const
+{
+ return pImpl->aFmtIds.size();
+}
+
+SotClipboardFormatId SvxClipboardFormatItem::GetClipbrdFormatId( sal_uInt16 nPos ) const
+{
+ return pImpl->aFmtIds[ nPos ];
+}
+
+OUString const & SvxClipboardFormatItem::GetClipbrdFormatName( sal_uInt16 nPos ) const
+{
+ return pImpl->aFmtNms[nPos];
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/customshapeitem.cxx b/svx/source/items/customshapeitem.cxx
new file mode 100644
index 000000000..3caa270de
--- /dev/null
+++ b/svx/source/items/customshapeitem.cxx
@@ -0,0 +1,347 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <comphelper/anycompare.hxx>
+#include <comphelper/anytohash.hxx>
+#include <svx/sdasitm.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+using namespace ::std;
+using namespace com::sun::star;
+
+
+SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem()
+: SfxPoolItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )
+{}
+
+SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem( const uno::Sequence< beans::PropertyValue >& rVal )
+: SfxPoolItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )
+{
+ SetPropSeq( rVal );
+}
+
+css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName )
+{
+ css::uno::Any* pRet = nullptr;
+ PropertyHashMap::iterator aHashIter( aPropHashMap.find( rPropName ) );
+ if ( aHashIter != aPropHashMap.end() )
+ pRet = &aPropSeq.getArray()[ (*aHashIter).second ].Value;
+ return pRet;
+}
+
+const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName ) const
+{
+ const css::uno::Any* pRet = nullptr;
+ PropertyHashMap::const_iterator aHashIter( aPropHashMap.find( rPropName ) );
+ if ( aHashIter != aPropHashMap.end() )
+ pRet = &aPropSeq[ (*aHashIter).second ].Value;
+ return pRet;
+}
+
+css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName )
+{
+ css::uno::Any* pRet = nullptr;
+ css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
+ if ( pSeqAny )
+ {
+ if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
+ {
+ PropertyPairHashMap::iterator aHashIter( aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
+ if ( aHashIter != aPropPairHashMap.end() )
+ {
+ pRet = &const_cast<css::uno::Sequence<css::beans::PropertyValue> &>(*rSecSequence).getArray()[ (*aHashIter).second ].Value;
+ }
+ }
+ }
+ return pRet;
+}
+
+const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName ) const
+{
+ const css::uno::Any* pRet = nullptr;
+ const css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
+ if ( pSeqAny )
+ {
+ if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
+ {
+ PropertyPairHashMap::const_iterator aHashIter( aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
+ if ( aHashIter != aPropPairHashMap.end() )
+ {
+ pRet = &(*rSecSequence)[ (*aHashIter).second ].Value;
+ }
+ }
+ }
+ return pRet;
+}
+
+void SdrCustomShapeGeometryItem::SetPropertyValue( const css::beans::PropertyValue& rPropVal )
+{
+ css::uno::Any* pAny = GetPropertyValueByName( rPropVal.Name );
+ if ( pAny )
+ { // property is already available
+ if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pAny) )
+ { // old property is a sequence->each entry has to be removed from the HashPairMap
+ for ( auto const & i : *rSecSequence )
+ {
+ PropertyPairHashMap::iterator aHashIter( aPropPairHashMap.find( PropertyPair( rPropVal.Name, i.Name ) ) );
+ if ( aHashIter != aPropPairHashMap.end() )
+ aPropPairHashMap.erase( aHashIter );
+ }
+ }
+ *pAny = rPropVal.Value;
+ if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pAny) )
+ { // the new property is a sequence->each entry has to be inserted into the HashPairMap
+ for ( sal_Int32 i = 0; i < rSecSequence->getLength(); i++ )
+ {
+ beans::PropertyValue const & rPropVal2 = (*rSecSequence)[ i ];
+ aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = i;
+ }
+ }
+ }
+ else
+ { // it's a new property
+ assert(std::none_of(std::cbegin(aPropSeq), std::cend(aPropSeq),
+ [&rPropVal](beans::PropertyValue const& rVal)
+ { return rVal.Name == rPropVal.Name; } ));
+ sal_uInt32 nIndex = aPropSeq.getLength();
+ aPropSeq.realloc( nIndex + 1 );
+ aPropSeq.getArray()[ nIndex ] = rPropVal ;
+
+ aPropHashMap[ rPropVal.Name ] = nIndex;
+ }
+ InvalidateHash();
+}
+
+void SdrCustomShapeGeometryItem::SetPropertyValue( const OUString& rSequenceName, const css::beans::PropertyValue& rPropVal )
+{
+ css::uno::Any* pAny = GetPropertyValueByName( rSequenceName, rPropVal.Name );
+ if ( pAny ) // just replacing
+ *pAny = rPropVal.Value;
+ else
+ {
+ css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
+ if( pSeqAny == nullptr )
+ {
+ css::uno::Sequence < beans::PropertyValue > aSeq;
+ beans::PropertyValue aValue;
+ aValue.Name = rSequenceName;
+ aValue.Value <<= aSeq;
+
+ assert(std::none_of(std::cbegin(aPropSeq), std::cend(aPropSeq),
+ [&rSequenceName](beans::PropertyValue const& rV)
+ { return rV.Name == rSequenceName; } ));
+ sal_uInt32 nIndex = aPropSeq.getLength();
+ aPropSeq.realloc( nIndex + 1 );
+ auto pPropSeq = aPropSeq.getArray();
+ pPropSeq[ nIndex ] = aValue;
+ aPropHashMap[ rSequenceName ] = nIndex;
+
+ pSeqAny = &pPropSeq[ nIndex ].Value;
+ }
+
+ if (auto pSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny))
+ {
+ PropertyPairHashMap::iterator aHashIter(
+ aPropPairHashMap.find(PropertyPair(rSequenceName, rPropVal.Name)));
+ auto& rSeq = const_cast<css::uno::Sequence<css::beans::PropertyValue>&>(*pSecSequence);
+ if (aHashIter != aPropPairHashMap.end())
+ {
+ rSeq.getArray()[(*aHashIter).second].Value = rPropVal.Value;
+ }
+ else
+ {
+ const sal_Int32 nCount = pSecSequence->getLength();
+ rSeq.realloc(nCount + 1);
+ rSeq.getArray()[nCount] = rPropVal;
+
+ aPropPairHashMap[PropertyPair(rSequenceName, rPropVal.Name)] = nCount;
+ }
+ }
+ }
+ InvalidateHash();
+}
+
+void SdrCustomShapeGeometryItem::ClearPropertyValue( const OUString& rPropName )
+{
+ if ( !aPropSeq.hasElements() )
+ return;
+
+ PropertyHashMap::iterator aHashIter( aPropHashMap.find( rPropName ) );
+ if ( aHashIter == aPropHashMap.end() )
+ return;
+
+ auto pPropSeq = aPropSeq.getArray();
+ css::uno::Any& rSeqAny = pPropSeq[(*aHashIter).second].Value;
+ if (auto pSecSequence
+ = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(rSeqAny))
+ {
+ for (const auto& rPropVal : *pSecSequence)
+ {
+ auto _aHashIter(aPropPairHashMap.find(PropertyPair(rPropName, rPropVal.Name)));
+ if (_aHashIter != aPropPairHashMap.end())
+ aPropPairHashMap.erase(_aHashIter); // removing property from pair hashmap
+ }
+ }
+ sal_Int32 nLength = aPropSeq.getLength();
+ if ( nLength )
+ {
+ sal_Int32 nIndex = (*aHashIter).second;
+ if ( nIndex != ( nLength - 1 ) ) // resizing sequence
+ {
+ PropertyHashMap::iterator aHashIter2( aPropHashMap.find( aPropSeq[ nLength - 1 ].Name ) );
+ (*aHashIter2).second = nIndex;
+ pPropSeq[ nIndex ] = aPropSeq[ nLength - 1 ];
+ }
+ aPropSeq.realloc( nLength - 1 );
+ }
+ aPropHashMap.erase( aHashIter ); // removing property from hashmap
+ InvalidateHash();
+}
+
+SdrCustomShapeGeometryItem::~SdrCustomShapeGeometryItem()
+{
+}
+
+bool SdrCustomShapeGeometryItem::operator==( const SfxPoolItem& rCmp ) const
+{
+ if( !SfxPoolItem::operator==( rCmp ))
+ return false;
+ const SdrCustomShapeGeometryItem& other = static_cast<const SdrCustomShapeGeometryItem&>(rCmp);
+ // This is called often by SfxItemPool, and comparing uno sequences is relatively slow.
+ // So keep a hash of the sequence and if either of the sequences has a usable hash,
+ // compare using that.
+ UpdateHash();
+ other.UpdateHash();
+ if( aHashState != other.aHashState )
+ return false;
+ if( aHashState == HashState::Valid && aHash != other.aHash )
+ return false;
+
+ return aPropSeq == other.aPropSeq;
+}
+
+bool SdrCustomShapeGeometryItem::operator<( const SfxPoolItem& rCmp ) const
+{
+ assert(dynamic_cast<const SdrCustomShapeGeometryItem*>( &rCmp ));
+ const SdrCustomShapeGeometryItem& other = static_cast<const SdrCustomShapeGeometryItem&>(rCmp);
+ // Again, try to optimize by checking hashes first (this is operator< for sorting purposes,
+ // so the ordering can be somewhat arbitrary).
+ UpdateHash();
+ other.UpdateHash();
+ if( aHashState != other.aHashState )
+ return aHashState < other.aHashState;
+ if( aHashState == HashState::Valid )
+ return aHash < other.aHash;
+
+ return comphelper::anyLess( css::uno::Any( aPropSeq ),
+ css::uno::Any( other.aPropSeq ));
+}
+
+void SdrCustomShapeGeometryItem::UpdateHash() const
+{
+ if( aHashState != HashState::Unknown )
+ return;
+ std::optional< size_t > hash = comphelper::anyToHash( css::uno::Any( aPropSeq ));
+ if( hash.has_value())
+ {
+ aHash = *hash;
+ aHashState = HashState::Valid;
+ }
+ else
+ aHashState = HashState::Unusable;
+}
+
+void SdrCustomShapeGeometryItem::InvalidateHash()
+{
+ aHashState = HashState::Unknown;
+}
+
+bool SdrCustomShapeGeometryItem::GetPresentation(
+ SfxItemPresentation ePresentation, MapUnit /*eCoreMetric*/,
+ MapUnit /*ePresentationMetric*/, OUString &rText, const IntlWrapper&) const
+{
+ rText += " ";
+ if ( ePresentation == SfxItemPresentation::Complete )
+ {
+ rText = " " + rText;
+ return true;
+ }
+ else if ( ePresentation == SfxItemPresentation::Nameless )
+ return true;
+ return false;
+}
+
+SdrCustomShapeGeometryItem* SdrCustomShapeGeometryItem::Clone( SfxItemPool * /*pPool*/ ) const
+{
+ return new SdrCustomShapeGeometryItem( aPropSeq );
+}
+
+bool SdrCustomShapeGeometryItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ rVal <<= aPropSeq;
+ return true;
+}
+
+bool SdrCustomShapeGeometryItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
+{
+ css::uno::Sequence< css::beans::PropertyValue > propSeq;
+ if ( ! ( rVal >>= propSeq ) )
+ return false;
+
+ SetPropSeq( propSeq );
+ return true;
+}
+
+void SdrCustomShapeGeometryItem::SetPropSeq( const css::uno::Sequence< css::beans::PropertyValue >& rVal )
+{
+ if( aPropSeq == rVal )
+ return;
+
+ aPropSeq = rVal;
+ aPropHashMap.clear();
+ aPropPairHashMap.clear();
+ for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
+ {
+ const beans::PropertyValue& rPropVal = aPropSeq[ i ];
+ std::pair<PropertyHashMap::iterator, bool> const ret(
+ aPropHashMap.insert(std::make_pair(rPropVal.Name, i)));
+ assert(ret.second); // serious bug: duplicate xml attribute exported
+ if (!ret.second)
+ {
+ throw uno::RuntimeException(
+ "CustomShapeGeometry has duplicate property " + rPropVal.Name);
+ }
+ if (auto rPropSeq = o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>(
+ rPropVal.Value))
+ {
+ for ( sal_Int32 j = 0; j < rPropSeq->getLength(); j++ )
+ {
+ beans::PropertyValue const & rPropVal2 = (*rPropSeq)[ j ];
+ aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = j;
+ }
+ }
+ }
+ InvalidateHash();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/drawitem.cxx b/svx/source/items/drawitem.cxx
new file mode 100644
index 000000000..24a6acb39
--- /dev/null
+++ b/svx/source/items/drawitem.cxx
@@ -0,0 +1,349 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/drawitem.hxx>
+#include <svx/xtable.hxx>
+
+using namespace ::com::sun::star;
+
+
+SfxPoolItem* SvxColorListItem::CreateDefault() { return new SvxColorListItem ;}
+SfxPoolItem* SvxGradientListItem::CreateDefault() { return new SvxGradientListItem ;}
+SfxPoolItem* SvxHatchListItem::CreateDefault() { return new SvxHatchListItem ;}
+SfxPoolItem* SvxBitmapListItem::CreateDefault() { return new SvxBitmapListItem ;}
+SfxPoolItem* SvxPatternListItem::CreateDefault() { return new SvxPatternListItem ;}
+SfxPoolItem* SvxDashListItem::CreateDefault() { return new SvxDashListItem ;}
+SfxPoolItem* SvxLineEndListItem::CreateDefault() { return new SvxLineEndListItem ;}
+
+SvxColorListItem::SvxColorListItem()
+{
+}
+
+
+SvxColorListItem::SvxColorListItem( XColorListRef const & pTable, TypedWhichId<SvxColorListItem> nW ) :
+ SfxPoolItem( nW ),
+ pColorList( pTable )
+{
+}
+
+
+SvxColorListItem::SvxColorListItem( const SvxColorListItem& rItem ) :
+ SfxPoolItem( rItem ),
+ pColorList( rItem.pColorList )
+{
+}
+
+bool SvxColorListItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return false;
+}
+
+bool SvxColorListItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+ return static_cast<const SvxColorListItem&>(rItem).pColorList == pColorList;
+}
+
+SvxColorListItem* SvxColorListItem::Clone( SfxItemPool * ) const
+{
+ return new SvxColorListItem( *this );
+}
+
+// Should be a template class but ...
+#define QUERY_PUT_IMPL(svtype, xtype) \
+bool svtype::QueryValue( css::uno::Any& rVal, sal_uInt8 ) const \
+{ \
+ rVal <<= uno::Reference< uno::XWeak >( p##xtype ); \
+ return true; \
+} \
+\
+bool svtype::PutValue( const css::uno::Any& rVal, sal_uInt8 ) \
+{ \
+ uno::Reference< uno::XWeak > xRef; \
+ if( rVal >>= xRef ) { \
+ p##xtype = X##xtype##Ref(dynamic_cast<X##xtype *>(xRef.get())); \
+ return true; \
+ } \
+ return false; \
+}
+
+QUERY_PUT_IMPL( SvxColorListItem, ColorList )
+
+SvxGradientListItem::SvxGradientListItem()
+{
+}
+
+SvxGradientListItem::SvxGradientListItem( XGradientListRef const & pList, TypedWhichId<SvxGradientListItem> nW ) :
+ SfxPoolItem( nW ),
+ pGradientList( pList )
+{
+}
+
+
+SvxGradientListItem::SvxGradientListItem( const SvxGradientListItem& rItem ) :
+ SfxPoolItem( rItem ),
+ pGradientList( rItem.pGradientList )
+{
+}
+
+
+bool SvxGradientListItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return false;
+}
+
+
+bool SvxGradientListItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+ return static_cast<const SvxGradientListItem&>(rItem).pGradientList == pGradientList;
+}
+
+SvxGradientListItem* SvxGradientListItem::Clone( SfxItemPool * ) const
+{
+ return new SvxGradientListItem( *this );
+}
+
+QUERY_PUT_IMPL( SvxGradientListItem, GradientList )
+
+SvxHatchListItem::SvxHatchListItem()
+{
+}
+
+
+SvxHatchListItem::SvxHatchListItem( XHatchListRef const & pList, TypedWhichId<SvxHatchListItem> nW ) :
+ SfxPoolItem( nW ),
+ pHatchList( pList )
+{
+}
+
+
+SvxHatchListItem::SvxHatchListItem( const SvxHatchListItem& rItem ) :
+ SfxPoolItem( rItem ),
+ pHatchList( rItem.pHatchList )
+{
+}
+
+
+bool SvxHatchListItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return false;
+}
+
+
+bool SvxHatchListItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+ return static_cast<const SvxHatchListItem&>(rItem).pHatchList == pHatchList;
+}
+
+SvxHatchListItem* SvxHatchListItem::Clone( SfxItemPool * ) const
+{
+ return new SvxHatchListItem( *this );
+}
+
+QUERY_PUT_IMPL( SvxHatchListItem, HatchList )
+
+SvxBitmapListItem::SvxBitmapListItem()
+{
+}
+
+SvxBitmapListItem::SvxBitmapListItem( XBitmapListRef const & pList, TypedWhichId<SvxBitmapListItem> nW ) :
+ SfxPoolItem( nW ),
+ pBitmapList( pList )
+{
+}
+
+SvxBitmapListItem::SvxBitmapListItem( const SvxBitmapListItem& rItem ) :
+ SfxPoolItem( rItem ),
+ pBitmapList( rItem.pBitmapList )
+{
+}
+
+bool SvxBitmapListItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return false;
+}
+
+bool SvxBitmapListItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+ return static_cast<const SvxBitmapListItem&>(rItem).pBitmapList == pBitmapList;
+}
+
+SvxBitmapListItem* SvxBitmapListItem::Clone( SfxItemPool * ) const
+{
+ return new SvxBitmapListItem( *this );
+}
+
+QUERY_PUT_IMPL( SvxBitmapListItem, BitmapList )
+
+SvxPatternListItem::SvxPatternListItem()
+{
+}
+
+SvxPatternListItem::SvxPatternListItem( XPatternListRef const & pList, TypedWhichId<SvxPatternListItem> nW ) :
+ SfxPoolItem( nW ),
+ pPatternList( pList )
+{
+}
+
+SvxPatternListItem::SvxPatternListItem( const SvxPatternListItem& rItem ) :
+ SfxPoolItem( rItem ),
+ pPatternList( rItem.pPatternList )
+{
+}
+
+bool SvxPatternListItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return false;
+}
+
+bool SvxPatternListItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+ return static_cast<const SvxPatternListItem&>(rItem).pPatternList == pPatternList;
+}
+
+SvxPatternListItem* SvxPatternListItem::Clone( SfxItemPool * ) const
+{
+ return new SvxPatternListItem( *this );
+}
+
+QUERY_PUT_IMPL( SvxPatternListItem, PatternList )
+
+SvxDashListItem::SvxDashListItem()
+{
+}
+
+SvxDashListItem::SvxDashListItem( XDashListRef const & pList, TypedWhichId<SvxDashListItem> nW ) :
+ SfxPoolItem( nW ),
+ pDashList( pList )
+{
+}
+
+SvxDashListItem::SvxDashListItem( const SvxDashListItem& rItem ) :
+ SfxPoolItem( rItem ),
+ pDashList( rItem.pDashList )
+{
+}
+
+bool SvxDashListItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return false;
+}
+
+bool SvxDashListItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+ return static_cast<const SvxDashListItem&>(rItem).pDashList == pDashList;
+}
+
+SvxDashListItem* SvxDashListItem::Clone( SfxItemPool * ) const
+{
+ return new SvxDashListItem( *this );
+}
+
+QUERY_PUT_IMPL( SvxDashListItem, DashList )
+
+SvxLineEndListItem::SvxLineEndListItem()
+{
+}
+
+SvxLineEndListItem::SvxLineEndListItem( XLineEndListRef const & pList, TypedWhichId<SvxLineEndListItem> nW ) :
+ SfxPoolItem( nW ),
+ pLineEndList( pList )
+{
+}
+
+SvxLineEndListItem::SvxLineEndListItem( const SvxLineEndListItem& rItem ) :
+ SfxPoolItem( rItem ),
+ pLineEndList( rItem.pLineEndList )
+{
+}
+
+bool SvxLineEndListItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return false;
+}
+
+bool SvxLineEndListItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+ return static_cast<const SvxLineEndListItem&>(rItem).pLineEndList == pLineEndList;
+}
+
+SvxLineEndListItem* SvxLineEndListItem::Clone( SfxItemPool * ) const
+{
+ return new SvxLineEndListItem( *this );
+}
+
+QUERY_PUT_IMPL( SvxLineEndListItem, LineEndList )
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/e3ditem.cxx b/svx/source/items/e3ditem.cxx
new file mode 100644
index 000000000..135c7efaf
--- /dev/null
+++ b/svx/source/items/e3ditem.cxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/Direction3D.hpp>
+#include <libxml/xmlwriter.h>
+
+#include <svx/e3ditem.hxx>
+
+using namespace ::com::sun::star;
+
+
+SvxB3DVectorItem::~SvxB3DVectorItem()
+{
+}
+
+
+SvxB3DVectorItem::SvxB3DVectorItem( TypedWhichId<SvxB3DVectorItem> _nWhich, const basegfx::B3DVector& rVal ) :
+ SfxPoolItem( _nWhich ),
+ aVal( rVal )
+{
+}
+
+
+SvxB3DVectorItem::SvxB3DVectorItem( const SvxB3DVectorItem& rItem ) :
+ SfxPoolItem( rItem ),
+ aVal( rItem.aVal )
+{
+}
+
+
+bool SvxB3DVectorItem::operator==( const SfxPoolItem &rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+ return static_cast<const SvxB3DVectorItem&>(rItem).aVal == aVal;
+}
+
+SvxB3DVectorItem* SvxB3DVectorItem::Clone( SfxItemPool* /*pPool*/ ) const
+{
+ return new SvxB3DVectorItem( *this );
+}
+
+bool SvxB3DVectorItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ assert(!std::isnan(aVal.getX()) && !std::isnan(aVal.getY()) && !std::isnan(aVal.getZ()));
+
+ drawing::Direction3D aDirection;
+
+ // enter values
+ aDirection.DirectionX = aVal.getX();
+ aDirection.DirectionY = aVal.getY();
+ aDirection.DirectionZ = aVal.getZ();
+
+ rVal <<= aDirection;
+ return true;
+}
+
+
+bool SvxB3DVectorItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
+{
+ drawing::Direction3D aDirection;
+ if(!(rVal >>= aDirection))
+ return false;
+
+ aVal.setX(aDirection.DirectionX);
+ aVal.setY(aDirection.DirectionY);
+ aVal.setZ(aDirection.DirectionZ);
+
+ assert(!std::isnan(aVal.getX()) && !std::isnan(aVal.getY()) && !std::isnan(aVal.getZ()));
+
+ return true;
+}
+
+
+void SvxB3DVectorItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxB3DVectorItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("x"), BAD_CAST(OString::number(aVal.getX()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("y"), BAD_CAST(OString::number(aVal.getY()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("z"), BAD_CAST(OString::number(aVal.getZ()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/galleryitem.cxx b/svx/source/items/galleryitem.cxx
new file mode 100644
index 000000000..5e50c5efb
--- /dev/null
+++ b/svx/source/items/galleryitem.cxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/galleryitem.hxx>
+#include <com/sun/star/gallery/GalleryItemType.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+
+#include <cassert>
+
+
+SfxPoolItem* SvxGalleryItem::CreateDefault() { return new SvxGalleryItem; }
+
+SvxGalleryItem::SvxGalleryItem()
+ : m_nType( css::gallery::GalleryItemType::EMPTY )
+{
+}
+
+SvxGalleryItem::SvxGalleryItem( const SvxGalleryItem &rItem )
+ : SfxPoolItem( rItem )
+ , m_nType( rItem.m_nType )
+ , m_aURL( rItem.m_aURL )
+ , m_xDrawing( rItem.m_xDrawing )
+ , m_xGraphic( rItem.m_xGraphic )
+{
+}
+
+SvxGalleryItem::~SvxGalleryItem()
+{
+}
+
+bool SvxGalleryItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /* nMemberId */ ) const
+{
+ css::uno::Sequence< css::beans::PropertyValue > aSeq{
+ comphelper::makePropertyValue(SVXGALLERYITEM_TYPE, m_nType),
+ comphelper::makePropertyValue(SVXGALLERYITEM_URL, m_aURL),
+ comphelper::makePropertyValue(SVXGALLERYITEM_FILTER, m_aURL),
+ comphelper::makePropertyValue(SVXGALLERYITEM_DRAWING, m_xDrawing),
+ comphelper::makePropertyValue(SVXGALLERYITEM_GRAPHIC, m_xGraphic)
+ };
+ assert(aSeq.getLength() == SVXGALLERYITEM_PARAMS);
+
+ rVal <<= aSeq;
+
+ return true;
+}
+
+bool SvxGalleryItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /* nMemberId */)
+{
+ css::uno::Sequence< css::beans::PropertyValue > aSeq;
+
+ if ( !( rVal >>= aSeq ) || ( aSeq.getLength() < SVXGALLERYITEM_PARAMS ) )
+ return false;
+
+ int nConverted(0);
+ bool bAllConverted( true );
+
+ sal_Int8 nType(0);
+ OUString aURL, aFilterName;
+ css::uno::Reference< css::lang::XComponent > xDrawing;
+ css::uno::Reference< css::graphic::XGraphic > xGraphic;
+
+ for ( const css::beans::PropertyValue& rProp : std::as_const(aSeq) )
+ {
+ if ( rProp.Name == SVXGALLERYITEM_TYPE )
+ {
+ bAllConverted &= ( rProp.Value >>= nType );
+ ++nConverted;
+ }
+ else if ( rProp.Name == SVXGALLERYITEM_URL )
+ {
+ bAllConverted &= ( rProp.Value >>= aURL );
+ ++nConverted;
+ }
+ else if ( rProp.Name == SVXGALLERYITEM_FILTER )
+ {
+ bAllConverted &= ( rProp.Value >>= aFilterName );
+ ++nConverted;
+ }
+ else if ( rProp.Name == SVXGALLERYITEM_DRAWING )
+ {
+ bAllConverted &= ( rProp.Value >>= xDrawing );
+ ++nConverted;
+ }
+ else if ( rProp.Name == SVXGALLERYITEM_GRAPHIC )
+ {
+ bAllConverted &= ( rProp.Value >>= xGraphic );
+ ++nConverted;
+ }
+ }
+
+ if ( !bAllConverted || nConverted != SVXGALLERYITEM_PARAMS )
+ return false;
+
+ m_nType = nType;
+ m_aURL = aURL;
+ m_xDrawing = xDrawing;
+ m_xGraphic = xGraphic;
+
+ return true;
+}
+
+bool SvxGalleryItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+
+ const SvxGalleryItem& rItem = static_cast<const SvxGalleryItem&>(rAttr);
+
+ return m_nType == rItem.m_nType &&
+ m_aURL == rItem.m_aURL &&
+ m_xDrawing == rItem.m_xDrawing &&
+ m_xGraphic == rItem.m_xGraphic;
+}
+
+SvxGalleryItem* SvxGalleryItem::Clone( SfxItemPool * ) const
+{
+ return new SvxGalleryItem( *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/grfitem.cxx b/svx/source/items/grfitem.cxx
new file mode 100644
index 000000000..30c0977a0
--- /dev/null
+++ b/svx/source/items/grfitem.cxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/grfcrop.hxx>
+#include <editeng/itemtype.hxx>
+#include <com/sun/star/text/GraphicCrop.hpp>
+#include <tools/mapunit.hxx>
+#include <tools/UnitConversion.hxx>
+
+using namespace ::com::sun::star;
+
+SvxGrfCrop::SvxGrfCrop( TypedWhichId<SvxGrfCrop> nItemId )
+ : SfxPoolItem( nItemId ),
+ nLeft( 0 ), nRight( 0 ), nTop( 0 ), nBottom( 0 )
+{}
+
+SvxGrfCrop::SvxGrfCrop( sal_Int32 nL, sal_Int32 nR,
+ sal_Int32 nT, sal_Int32 nB, TypedWhichId<SvxGrfCrop> nItemId )
+ : SfxPoolItem( nItemId ),
+ nLeft( nL ), nRight( nR ), nTop( nT ), nBottom( nB )
+{}
+
+SvxGrfCrop::~SvxGrfCrop()
+{
+}
+
+bool SvxGrfCrop::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+
+ const SvxGrfCrop& rCrop = static_cast<const SvxGrfCrop&>(rAttr);
+ return nLeft == rCrop.GetLeft() &&
+ nRight == rCrop.GetRight() &&
+ nTop == rCrop.GetTop() &&
+ nBottom == rCrop.GetBottom();
+}
+
+
+bool SvxGrfCrop::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ text::GraphicCrop aRet;
+ aRet.Left = nLeft;
+ aRet.Right = nRight;
+ aRet.Top = nTop;
+ aRet.Bottom = nBottom;
+
+ if( bConvert )
+ {
+ aRet.Right = convertTwipToMm100(aRet.Right );
+ aRet.Top = convertTwipToMm100(aRet.Top );
+ aRet.Left = convertTwipToMm100(aRet.Left );
+ aRet.Bottom = convertTwipToMm100(aRet.Bottom);
+ }
+
+
+ rVal <<= aRet;
+ return true;
+}
+
+bool SvxGrfCrop::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ text::GraphicCrop aVal;
+
+ if(!(rVal >>= aVal))
+ return false;
+ if( bConvert )
+ {
+ aVal.Right = o3tl::toTwips(aVal.Right, o3tl::Length::mm100);
+ aVal.Top = o3tl::toTwips(aVal.Top, o3tl::Length::mm100);
+ aVal.Left = o3tl::toTwips(aVal.Left, o3tl::Length::mm100);
+ aVal.Bottom = o3tl::toTwips(aVal.Bottom, o3tl::Length::mm100);
+ }
+
+ nLeft = aVal.Left ;
+ nRight = aVal.Right ;
+ nTop = aVal.Top ;
+ nBottom = aVal.Bottom;
+ return true;
+}
+
+bool SvxGrfCrop::GetPresentation(
+ SfxItemPresentation ePres, MapUnit eCoreUnit, MapUnit /*ePresUnit*/,
+ OUString &rText, const IntlWrapper& rIntl ) const
+{
+ rText.clear();
+ switch( ePres )
+ {
+ case SfxItemPresentation::Nameless:
+ return true;
+ case SfxItemPresentation::Complete:
+ rText = "L: " + ::GetMetricText( GetLeft(), eCoreUnit, MapUnit::MapMM, &rIntl ) +
+ " R: " + ::GetMetricText( GetRight(), eCoreUnit, MapUnit::MapMM, &rIntl ) +
+ " T: " + ::GetMetricText( GetTop(), eCoreUnit, MapUnit::MapMM, &rIntl ) +
+ " B: " + ::GetMetricText( GetBottom(), eCoreUnit, MapUnit::MapMM, &rIntl );
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/hlnkitem.cxx b/svx/source/items/hlnkitem.cxx
new file mode 100644
index 000000000..4a8bc3290
--- /dev/null
+++ b/svx/source/items/hlnkitem.cxx
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svxids.hrc>
+#include <sfx2/event.hxx>
+#include <svx/hlnkitem.hxx>
+
+
+SfxPoolItem* SvxHyperlinkItem::CreateDefault() { return new SvxHyperlinkItem(TypedWhichId<SvxHyperlinkItem>(0));}
+
+SvxHyperlinkItem::SvxHyperlinkItem( const SvxHyperlinkItem& rHyperlinkItem ):
+ SfxPoolItem(rHyperlinkItem)
+{
+ sName = rHyperlinkItem.sName;
+ sURL = rHyperlinkItem.sURL;
+ sTarget = rHyperlinkItem.sTarget;
+ eType = rHyperlinkItem.eType;
+ sIntName = rHyperlinkItem.sIntName;
+ nMacroEvents = rHyperlinkItem.nMacroEvents;
+
+ if( rHyperlinkItem.GetMacroTable() )
+ pMacroTable.reset( new SvxMacroTableDtor( *rHyperlinkItem.GetMacroTable() ) );
+
+};
+
+SvxHyperlinkItem::SvxHyperlinkItem( TypedWhichId<SvxHyperlinkItem> _nWhich, const OUString& rName, const OUString& rURL,
+ const OUString& rTarget, const OUString& rIntName, SvxLinkInsertMode eTyp,
+ HyperDialogEvent nEvents, SvxMacroTableDtor const *pMacroTbl ):
+ SfxPoolItem (_nWhich),
+ sName (rName),
+ sURL (rURL),
+ sTarget (rTarget),
+ eType (eTyp),
+ sIntName (rIntName),
+ nMacroEvents (nEvents)
+{
+ if (pMacroTbl)
+ pMacroTable.reset( new SvxMacroTableDtor ( *pMacroTbl ) );
+}
+
+SvxHyperlinkItem* SvxHyperlinkItem::Clone( SfxItemPool* ) const
+{
+ return new SvxHyperlinkItem( *this );
+}
+
+bool SvxHyperlinkItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+
+ const SvxHyperlinkItem& rItem = static_cast<const SvxHyperlinkItem&>(rAttr);
+
+ bool bRet = ( sName == rItem.sName &&
+ sURL == rItem.sURL &&
+ sTarget == rItem.sTarget &&
+ eType == rItem.eType &&
+ sIntName == rItem.sIntName &&
+ nMacroEvents == rItem.nMacroEvents);
+ if (!bRet)
+ return false;
+
+ const SvxMacroTableDtor* pOther = static_cast<const SvxHyperlinkItem&>(rAttr).pMacroTable.get();
+ if( !pMacroTable )
+ return ( !pOther || pOther->empty() );
+ if( !pOther )
+ return pMacroTable->empty();
+
+ const SvxMacroTableDtor& rOwn = *pMacroTable;
+ const SvxMacroTableDtor& rOther = *pOther;
+
+ return rOwn == rOther;
+}
+
+void SvxHyperlinkItem::SetMacro( HyperDialogEvent nEvent, const SvxMacro& rMacro )
+{
+ SvMacroItemId nSfxEvent = SvMacroItemId::NONE;
+ switch( nEvent )
+ {
+ case HyperDialogEvent::MouseOverObject:
+ nSfxEvent = SvMacroItemId::OnMouseOver;
+ break;
+ case HyperDialogEvent::MouseClickObject:
+ nSfxEvent = SvMacroItemId::OnClick;
+ break;
+ case HyperDialogEvent::MouseOutObject:
+ nSfxEvent = SvMacroItemId::OnMouseOut;
+ break;
+ default: break;
+ }
+
+ if( !pMacroTable )
+ pMacroTable.reset( new SvxMacroTableDtor );
+
+ pMacroTable->Insert( nSfxEvent, rMacro);
+}
+
+void SvxHyperlinkItem::SetMacroTable( const SvxMacroTableDtor& rTbl )
+{
+ pMacroTable.reset( new SvxMacroTableDtor ( rTbl ) );
+}
+
+bool SvxHyperlinkItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+ switch(nMemberId)
+ {
+ case MID_HLINK_NAME :
+ rVal <<= sIntName;
+ break;
+ case MID_HLINK_TEXT :
+ rVal <<= sName;
+ break;
+ case MID_HLINK_URL:
+ rVal <<= sURL;
+ break;
+ case MID_HLINK_TARGET:
+ rVal <<= sTarget;
+ break;
+ case MID_HLINK_TYPE:
+ rVal <<= static_cast<sal_Int32>(eType);
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool SvxHyperlinkItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ OUString aStr;
+ sal_Int32 nVal = 0;
+ switch(nMemberId)
+ {
+ case MID_HLINK_NAME :
+ if(!(rVal >>= aStr))
+ return false;
+ sIntName = aStr;
+ break;
+ case MID_HLINK_TEXT :
+ if(!(rVal >>= aStr))
+ return false;
+ sName = aStr;
+ break;
+ case MID_HLINK_URL:
+ if(!(rVal >>= aStr))
+ return false;
+ sURL = aStr;
+ break;
+ case MID_HLINK_TARGET:
+ if(!(rVal >>= aStr))
+ return false;
+ sTarget = aStr;
+ break;
+ case MID_HLINK_TYPE:
+ if(!(rVal >>= nVal))
+ return false;
+ eType = static_cast<SvxLinkInsertMode>(static_cast<sal_uInt16>(nVal));
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/legacyitem.cxx b/svx/source/items/legacyitem.cxx
new file mode 100644
index 000000000..005f97d2d
--- /dev/null
+++ b/svx/source/items/legacyitem.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/legacyitem.hxx>
+#include <tools/stream.hxx>
+#include <svx/algitem.hxx>
+#include <svx/rotmodit.hxx>
+
+namespace legacy
+{
+ namespace SvxOrientation
+ {
+ sal_uInt16 GetVersion(sal_uInt16)
+ {
+ return 0;
+ }
+
+ void Create(SvxOrientationItem& rItem, SvStream& rStrm, sal_uInt16)
+ {
+ sal_uInt16 nVal(0);
+ rStrm.ReadUInt16( nVal );
+ rItem.SetValue(static_cast<::SvxCellOrientation>(nVal));
+ }
+
+ SvStream& Store(const SvxOrientationItem& rItem, SvStream& rStrm, sal_uInt16)
+ {
+ rStrm.WriteUInt16( static_cast<sal_uInt16>(rItem.GetValue()) );
+ return rStrm;
+ }
+ }
+
+ namespace SvxMargin
+ {
+ sal_uInt16 GetVersion(sal_uInt16)
+ {
+ return 0;
+ }
+
+ void Create(SvxMarginItem& rItem, SvStream& rStrm, sal_uInt16)
+ {
+ sal_Int16 nLeft(0);
+ sal_Int16 nTop(0);
+ sal_Int16 nRight(0);
+ sal_Int16 nBottom(0);
+
+ rStrm.ReadInt16( nLeft );
+ rStrm.ReadInt16( nTop );
+ rStrm.ReadInt16( nRight );
+ rStrm.ReadInt16( nBottom );
+
+ rItem.SetLeftMargin(nLeft);
+ rItem.SetTopMargin(nTop);
+ rItem.SetRightMargin(nRight);
+ rItem.SetBottomMargin(nBottom);
+ }
+
+ SvStream& Store(const SvxMarginItem& rItem, SvStream& rStrm, sal_uInt16)
+ {
+ rStrm.WriteInt16( rItem.GetLeftMargin() );
+ rStrm.WriteInt16( rItem.GetTopMargin() );
+ rStrm.WriteInt16( rItem.GetRightMargin() );
+ rStrm.WriteInt16( rItem.GetBottomMargin() );
+ return rStrm;
+ }
+ }
+
+ namespace SvxRotateMode
+ {
+ sal_uInt16 GetVersion(sal_uInt16)
+ {
+ return 0;
+ }
+
+ void Create(SvxRotateModeItem& rItem, SvStream& rStrm, sal_uInt16)
+ {
+ sal_uInt16 nVal(0);
+ rStrm.ReadUInt16( nVal );
+ rItem.SetValue(static_cast<::SvxRotateMode>(nVal));
+ }
+
+ SvStream& Store(const SvxRotateModeItem& rItem, SvStream& rStrm, sal_uInt16)
+ {
+ rStrm.WriteUInt16( static_cast<sal_uInt16>(rItem.GetValue()) );
+ return rStrm;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/numfmtsh.cxx b/svx/source/items/numfmtsh.cxx
new file mode 100644
index 000000000..40811d846
--- /dev/null
+++ b/svx/source/items/numfmtsh.cxx
@@ -0,0 +1,1593 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/color.hxx>
+
+#include <tools/debug.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <o3tl/safeint.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <svl/currencytable.hxx>
+
+#include <svx/numfmtsh.hxx>
+#include <svx/flagsdef.hxx>
+#include <svx/tbcontrl.hxx>
+
+#include <limits>
+
+namespace
+{
+double GetDefaultValNum(const SvNumFormatType nType)
+{
+ switch (nType)
+ {
+ case SvNumFormatType::NUMBER:
+ return fSvxNumValConst[SvxNumValCategory::Standard];
+ case SvNumFormatType::CURRENCY:
+ return fSvxNumValConst[SvxNumValCategory::Currency];
+ case SvNumFormatType::PERCENT:
+ return fSvxNumValConst[SvxNumValCategory::Percent];
+ case SvNumFormatType::DATE:
+ case SvNumFormatType::DATETIME:
+ return fSvxNumValConst[SvxNumValCategory::Date];
+ case SvNumFormatType::TIME:
+ return fSvxNumValConst[SvxNumValCategory::Time];
+ case SvNumFormatType::SCIENTIFIC:
+ return fSvxNumValConst[SvxNumValCategory::Scientific];
+ case SvNumFormatType::FRACTION:
+ return fSvxNumValConst[SvxNumValCategory::Fraction];
+ case SvNumFormatType::LOGICAL:
+ return fSvxNumValConst[SvxNumValCategory::Boolean];
+ default:
+ break;
+ }
+ return fSvxNumValConst[SvxNumValCategory::NoValue];
+}
+}
+
+SvxNumberFormatShell* SvxNumberFormatShell::Create(SvNumberFormatter* pNumFormatter,
+ sal_uInt32 nFormatKey,
+ SvxNumberValueType eNumValType,
+ const OUString& rNumStr)
+{
+ return new SvxNumberFormatShell(pNumFormatter, nFormatKey, eNumValType, rNumStr);
+}
+
+SvxNumberFormatShell* SvxNumberFormatShell::Create(SvNumberFormatter* pNumFormatter,
+ sal_uInt32 nFormatKey,
+ SvxNumberValueType eNumValType, double nNumVal,
+ const OUString* pNumStr)
+{
+ return new SvxNumberFormatShell(pNumFormatter, nFormatKey, eNumValType, nNumVal, pNumStr);
+}
+
+SvxNumberFormatShell::SvxNumberFormatShell(SvNumberFormatter* pNumFormatter, sal_uInt32 nFormatKey,
+ SvxNumberValueType eNumValType, const OUString& rNumStr)
+ : pFormatter(pNumFormatter)
+ , pCurFmtTable(nullptr)
+ , eValType(eNumValType)
+ , bUndoAddList(true)
+ , nCurFormatKey(nFormatKey)
+ , nCurCategory(SvNumFormatType::ALL)
+ , eCurLanguage(LANGUAGE_NONE)
+ , pCurCurrencyEntry(nullptr)
+ , bBankingSymbol(false)
+ , nCurCurrencyEntryPos(sal_uInt16(SELPOS_NONE))
+ , bUseStarFormat(false)
+ , bIsDefaultValNum(true)
+{
+ nValNum = 0;
+
+ switch (eValType)
+ {
+ case SvxNumberValueType::String:
+ aValStr = rNumStr;
+ break;
+ case SvxNumberValueType::Number:
+ if (pFormatter)
+ {
+ nValNum = GetDefaultValNum(pFormatter->GetType(nCurFormatKey));
+ }
+ [[fallthrough]];
+ case SvxNumberValueType::Undefined:
+ default:
+ aValStr.clear();
+ }
+}
+
+SvxNumberFormatShell::SvxNumberFormatShell(SvNumberFormatter* pNumFormatter, sal_uInt32 nFormatKey,
+ SvxNumberValueType eNumValType, double nNumVal,
+ const OUString* pNumStr)
+ : pFormatter(pNumFormatter)
+ , pCurFmtTable(nullptr)
+ , eValType(eNumValType)
+ , bUndoAddList(true)
+ , nCurFormatKey(nFormatKey)
+ , nCurCategory(SvNumFormatType::ALL)
+ , eCurLanguage(LANGUAGE_NONE)
+ , pCurCurrencyEntry(nullptr)
+ , bBankingSymbol(false)
+ , nCurCurrencyEntryPos(sal_uInt16(SELPOS_NONE))
+ , bUseStarFormat(false)
+ , bIsDefaultValNum(false)
+{
+ // #50441# When used in Writer, the SvxNumberInfoItem contains the
+ // original string in addition to the value
+
+ if (pNumStr)
+ aValStr = *pNumStr;
+
+ switch (eValType)
+ {
+ case SvxNumberValueType::Number:
+ nValNum = nNumVal;
+ break;
+ case SvxNumberValueType::String:
+ case SvxNumberValueType::Undefined:
+ default:
+ nValNum = 0;
+ bIsDefaultValNum = true;
+ }
+}
+
+SvxNumberFormatShell::~SvxNumberFormatShell()
+{
+ /*
+ * At this point, depending on whether the added user-defined were
+ * validated (ValidateNewEntries()), the add list is removed from
+ * the number formatter again.
+ *
+ * Deleting formats from the formatter happens for Undo reasons
+ * only in the calling instance.
+ */
+
+ if (bUndoAddList)
+ {
+ // Added formats are invalid => remove them
+
+ for (const auto& rItem : aAddList)
+ pFormatter->DeleteEntry(rItem);
+ }
+}
+
+std::vector<sal_uInt32> const& SvxNumberFormatShell::GetUpdateData() const { return aDelList; }
+
+void SvxNumberFormatShell::CategoryChanged(sal_uInt16 nCatLbPos, short& rFmtSelPos,
+ std::vector<OUString>& rFmtEntries)
+{
+ SvNumFormatType nOldCategory = nCurCategory;
+ PosToCategory_Impl(nCatLbPos, nCurCategory);
+ pCurFmtTable = &(pFormatter->GetEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
+ // reinitialize currency if category newly entered
+ if (nCurCategory == SvNumFormatType::CURRENCY && nOldCategory != nCurCategory)
+ pCurCurrencyEntry = nullptr;
+ rFmtSelPos = FillEntryList_Impl(rFmtEntries);
+}
+
+void SvxNumberFormatShell::LanguageChanged(LanguageType eLangType, short& rFmtSelPos,
+ std::vector<OUString>& rFmtEntries)
+{
+ eCurLanguage = eLangType;
+ pCurFmtTable = &(pFormatter->ChangeCL(nCurCategory, nCurFormatKey, eCurLanguage));
+ rFmtSelPos = FillEntryList_Impl(rFmtEntries);
+}
+
+void SvxNumberFormatShell::FormatChanged(sal_uInt16 nFmtLbPos, OUString& rPreviewStr,
+ const Color*& rpFontColor)
+{
+ if (static_cast<size_t>(nFmtLbPos) >= aCurEntryList.size())
+ return;
+
+ nCurFormatKey = aCurEntryList[nFmtLbPos];
+
+ if (nCurFormatKey != NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ GetPreviewString_Impl(rPreviewStr, rpFontColor);
+ }
+ else if (nCurCategory == SvNumFormatType::CURRENCY)
+ {
+ if (static_cast<size_t>(nFmtLbPos) < aCurrencyFormatList.size())
+ {
+ MakePrevStringFromVal(aCurrencyFormatList[nFmtLbPos], rPreviewStr, rpFontColor,
+ nValNum);
+ }
+ }
+}
+
+bool SvxNumberFormatShell::AddFormat(OUString& rFormat, sal_Int32& rErrPos,
+ sal_uInt16& rCatLbSelPos, short& rFmtSelPos,
+ std::vector<OUString>& rFmtEntries)
+{
+ bool bInserted = false;
+ sal_uInt32 nAddKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
+
+ if (nAddKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // exists already?
+ {
+ ::std::vector<sal_uInt32>::iterator nAt = GetRemoved_Impl(nAddKey);
+ if (nAt != aDelList.end())
+ {
+ aDelList.erase(nAt);
+ bInserted = true;
+ }
+ else
+ {
+ OSL_FAIL("duplicate format!");
+ }
+ }
+ else // new format
+ {
+ sal_Int32 nPos;
+ bInserted = pFormatter->PutEntry(rFormat, nPos, nCurCategory, nAddKey, eCurLanguage);
+ rErrPos = (nPos >= 0) ? nPos : -1;
+
+ if (bInserted)
+ {
+ // May be sorted under a different locale if LCID was parsed.
+ const SvNumberformat* pEntry = pFormatter->GetEntry(nAddKey);
+ if (pEntry)
+ {
+ LanguageType nLang = pEntry->GetLanguage();
+ if (eCurLanguage != nLang)
+ {
+ // Current language's list would not show entry, adapt.
+ eCurLanguage = nLang;
+ }
+ }
+ }
+ }
+
+ if (bInserted)
+ {
+ nCurFormatKey = nAddKey;
+ DBG_ASSERT(GetAdded_Impl(nCurFormatKey) == aAddList.end(), "duplicate format!");
+ aAddList.push_back(nCurFormatKey);
+
+ // get current table
+ pCurFmtTable = &(pFormatter->GetEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
+ nCurCategory = pFormatter->GetType(nAddKey);
+ CategoryToPos_Impl(nCurCategory, rCatLbSelPos);
+ rFmtSelPos = FillEntryList_Impl(rFmtEntries);
+ }
+ else if (rErrPos != 0) // syntax error
+ {
+ ;
+ }
+ else // insert twice not possible
+ {
+ OSL_FAIL("duplicate format!");
+ }
+
+ return bInserted;
+}
+
+void SvxNumberFormatShell::RemoveFormat(std::u16string_view rFormat, sal_uInt16& rCatLbSelPos,
+ short& rFmtSelPos, std::vector<OUString>& rFmtEntries)
+{
+ sal_uInt32 nDelKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
+
+ DBG_ASSERT(nDelKey != NUMBERFORMAT_ENTRY_NOT_FOUND, "entry not found!");
+ DBG_ASSERT(!IsRemoved_Impl(nDelKey), "entry already removed!");
+
+ if ((nDelKey == NUMBERFORMAT_ENTRY_NOT_FOUND) || IsRemoved_Impl(nDelKey))
+ return;
+
+ aDelList.push_back(nDelKey);
+
+ ::std::vector<sal_uInt32>::iterator nAt = GetAdded_Impl(nDelKey);
+ if (nAt != aAddList.end())
+ {
+ aAddList.erase(nAt);
+ }
+
+ nCurCategory = pFormatter->GetType(nDelKey);
+ pCurFmtTable = &(pFormatter->GetEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
+
+ nCurFormatKey = pFormatter->GetStandardFormat(nCurCategory, eCurLanguage);
+
+ CategoryToPos_Impl(nCurCategory, rCatLbSelPos);
+ rFmtSelPos = FillEntryList_Impl(rFmtEntries);
+}
+
+void SvxNumberFormatShell::MakeFormat(OUString& rFormat, bool bThousand, bool bNegRed,
+ sal_uInt16 nPrecision, sal_uInt16 nLeadingZeroes,
+ sal_uInt16 nCurrencyPos)
+{
+ if (aCurrencyFormatList.size() > static_cast<size_t>(nCurrencyPos))
+ {
+ sal_Int32 rErrPos = 0;
+ std::vector<OUString> aFmtEList;
+
+ sal_uInt32 nFound
+ = pFormatter->TestNewString(aCurrencyFormatList[nCurrencyPos], eCurLanguage);
+
+ if (nFound == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ sal_uInt16 rCatLbSelPos = 0;
+ short rFmtSelPos = 0;
+ AddFormat(aCurrencyFormatList[nCurrencyPos], rErrPos, rCatLbSelPos, rFmtSelPos,
+ aFmtEList);
+ }
+
+ if (rErrPos == 0)
+ {
+ rFormat = pFormatter->GenerateFormat(nCurFormatKey, eCurLanguage, bThousand, bNegRed,
+ nPrecision, nLeadingZeroes);
+ }
+ }
+ else
+ {
+ rFormat = pFormatter->GenerateFormat(nCurFormatKey, eCurLanguage, bThousand, bNegRed,
+ nPrecision, nLeadingZeroes);
+ }
+}
+
+sal_uInt16 SvxNumberFormatShell::GetFormatIntegerDigits(std::u16string_view rFormat) const
+{
+ sal_uInt32 nFmtKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
+
+ return pFormatter->GetFormatIntegerDigits(nFmtKey);
+}
+
+void SvxNumberFormatShell::GetOptions(const OUString& rFormat, bool& rThousand, bool& rNegRed,
+ sal_uInt16& rPrecision, sal_uInt16& rLeadingZeroes,
+ sal_uInt16& rCatLbPos)
+{
+ sal_uInt32 nFmtKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
+
+ if (nFmtKey != NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ pFormatter->GetFormatSpecialInfo(nFmtKey, rThousand, rNegRed, rPrecision, rLeadingZeroes);
+
+ CategoryToPos_Impl(pFormatter->GetType(nFmtKey), rCatLbPos);
+ }
+ else
+ {
+ bool bTestBanking = false;
+ sal_uInt16 nPos = FindCurrencyTableEntry(rFormat, bTestBanking);
+
+ if (IsInTable(nPos, bTestBanking, rFormat)
+ && pFormatter->GetFormatSpecialInfo(rFormat, rThousand, rNegRed, rPrecision,
+ rLeadingZeroes, eCurLanguage)
+ == 0)
+ {
+ rCatLbPos = CAT_CURRENCY;
+ }
+ else
+ rCatLbPos = CAT_USERDEFINED;
+ }
+}
+
+void SvxNumberFormatShell::MakePreviewString(const OUString& rFormatStr, OUString& rPreviewStr,
+ const Color*& rpFontColor)
+{
+ rpFontColor = nullptr;
+
+ sal_uInt32 nExistingFormat = pFormatter->GetEntryKey(rFormatStr, eCurLanguage);
+ if (nExistingFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ // real preview - not implemented in NumberFormatter for text formats
+ pFormatter->GetPreviewString(rFormatStr, nValNum, rPreviewStr, &rpFontColor, eCurLanguage,
+ bUseStarFormat);
+ }
+ else
+ {
+ // format exists
+
+ // #50441# if a string was set in addition to the value, use it for text formats
+ bool bUseText = (eValType == SvxNumberValueType::String
+ || (!aValStr.isEmpty()
+ && (pFormatter->GetType(nExistingFormat) & SvNumFormatType::TEXT)));
+
+ if (bUseText)
+ {
+ pFormatter->GetOutputString(aValStr, nExistingFormat, rPreviewStr, &rpFontColor);
+ }
+ else
+ {
+ if (bIsDefaultValNum)
+ nValNum = GetDefaultValNum(pFormatter->GetType(nExistingFormat));
+ pFormatter->GetOutputString(nValNum, nExistingFormat, rPreviewStr, &rpFontColor,
+ bUseStarFormat);
+ }
+ }
+}
+
+bool SvxNumberFormatShell::IsUserDefined(const OUString& rFmtString)
+{
+ sal_uInt32 nFound = pFormatter->GetEntryKey(rFmtString, eCurLanguage);
+
+ bool bFlag = false;
+ if (nFound != NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ bFlag = pFormatter->IsUserDefined(rFmtString, eCurLanguage);
+
+ if (bFlag)
+ {
+ const SvNumberformat* pNumEntry = pFormatter->GetEntry(nFound);
+
+ if (pNumEntry != nullptr && pNumEntry->HasNewCurrency())
+ {
+ bool bTestBanking;
+ sal_uInt16 nPos = FindCurrencyTableEntry(rFmtString, bTestBanking);
+ bFlag = !IsInTable(nPos, bTestBanking, rFmtString);
+ }
+ }
+ }
+ return bFlag;
+}
+
+bool SvxNumberFormatShell::FindEntry(const OUString& rFmtString, sal_uInt32* pAt /* = NULL */)
+{
+ bool bRes = false;
+
+ sal_uInt32 nFound = NUMBERFORMAT_ENTRY_NOT_FOUND;
+ // There may be multiple builtin entries with the same format code, first
+ // try if the current key matches.
+ const SvNumberformat* pEntry = pFormatter->GetEntry(nCurFormatKey);
+ if (pEntry && pEntry->GetLanguage() == eCurLanguage && pEntry->GetFormatstring() == rFmtString)
+ nFound = nCurFormatKey;
+
+ if (nFound == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ // Find the first matching format code.
+ nFound = pFormatter->TestNewString(rFmtString, eCurLanguage);
+
+ if (nFound == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ bool bTestBanking = false;
+ sal_uInt16 nPos = FindCurrencyTableEntry(rFmtString, bTestBanking);
+
+ if (IsInTable(nPos, bTestBanking, rFmtString))
+ {
+ nFound = NUMBERFORMAT_ENTRY_NEW_CURRENCY;
+ bRes = true;
+ }
+ }
+ else
+ {
+ bRes = !IsRemoved_Impl(nFound);
+ }
+
+ if (pAt)
+ *pAt = nFound;
+
+ return bRes;
+}
+
+void SvxNumberFormatShell::GetInitSettings(sal_uInt16& nCatLbPos, LanguageType& rLangType,
+ sal_uInt16& nFmtLbSelPos,
+ std::vector<OUString>& rFmtEntries,
+ OUString& rPrevString, const Color*& rpPrevColor)
+{
+ // precondition: number formater found
+ DBG_ASSERT(pFormatter != nullptr, "Number formatter not found!");
+
+ short nSelPos = SELPOS_NONE;
+
+ // special treatment for undefined number format:
+ if ((eValType == SvxNumberValueType::Undefined) && (nCurFormatKey == 0))
+ PosToCategory_Impl(CAT_ALL, nCurCategory); // category = all
+ else
+ nCurCategory = SvNumFormatType::UNDEFINED; // category = undefined
+
+ pCurFmtTable = &(pFormatter->GetFirstEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
+
+ CategoryToPos_Impl(nCurCategory, nCatLbPos);
+ rLangType = eCurLanguage;
+
+ nSelPos = FillEntryList_Impl(rFmtEntries);
+
+ DBG_ASSERT(nSelPos != SELPOS_NONE, "Leere Formatliste!");
+
+ nFmtLbSelPos = (nSelPos != SELPOS_NONE) ? static_cast<sal_uInt16>(nSelPos) : 0;
+ GetPreviewString_Impl(rPrevString, rpPrevColor);
+}
+
+short SvxNumberFormatShell::FillEntryList_Impl(std::vector<OUString>& rList)
+{
+ /* Create a current list of format entries. The return value is
+ * the list position of the current format. If the list is empty
+ * or if there is no current format, SELPOS_NONE is delivered.
+ */
+ short nSelPos = SELPOS_NONE;
+
+ aCurEntryList.clear();
+
+ if (nCurCategory == SvNumFormatType::ALL)
+ {
+ FillEListWithStd_Impl(rList, SvNumFormatType::NUMBER, nSelPos);
+ nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::NUMBER, nSelPos);
+
+ FillEListWithStd_Impl(rList, SvNumFormatType::PERCENT, nSelPos);
+ nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::PERCENT, nSelPos);
+
+ FillEListWithStd_Impl(rList, SvNumFormatType::CURRENCY, nSelPos);
+ // No FillEListWithUsD_Impl() here, user defined currency formats
+ // were already added.
+
+ FillEListWithStd_Impl(rList, SvNumFormatType::DATE, nSelPos);
+ nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::DATE, nSelPos);
+
+ FillEListWithStd_Impl(rList, SvNumFormatType::TIME, nSelPos);
+ nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::TIME, nSelPos);
+
+ nSelPos = FillEListWithDateTime_Impl(rList, nSelPos, false);
+ nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::DATETIME, nSelPos);
+
+ FillEListWithStd_Impl(rList, SvNumFormatType::SCIENTIFIC, nSelPos);
+ nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::SCIENTIFIC, nSelPos);
+
+ FillEListWithStd_Impl(rList, SvNumFormatType::FRACTION, nSelPos);
+ nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::FRACTION, nSelPos);
+
+ FillEListWithStd_Impl(rList, SvNumFormatType::LOGICAL, nSelPos);
+ nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::LOGICAL, nSelPos);
+
+ FillEListWithStd_Impl(rList, SvNumFormatType::TEXT, nSelPos);
+ nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::TEXT, nSelPos);
+ }
+ else
+ {
+ FillEListWithStd_Impl(rList, nCurCategory, nSelPos, true);
+ if (nCurCategory != SvNumFormatType::CURRENCY)
+ nSelPos = FillEListWithUsD_Impl(rList, nCurCategory, nSelPos);
+ if (nCurCategory == SvNumFormatType::DATE || nCurCategory == SvNumFormatType::TIME)
+ nSelPos = FillEListWithDateTime_Impl(rList, nSelPos, true);
+ }
+
+ return nSelPos;
+}
+
+void SvxNumberFormatShell::FillEListWithStd_Impl(std::vector<OUString>& rList,
+ SvNumFormatType eCategory, short& nSelPos,
+ bool bSuppressDuplicates)
+{
+ /* Create a current list of format entries. The return value is
+ * the list position of the current format. If the list is empty
+ * or if there is no current format, SELPOS_NONE is delivered.
+ */
+
+ assert(pCurFmtTable != nullptr);
+
+ aCurrencyFormatList.clear();
+
+ NfIndexTableOffset eOffsetStart;
+ NfIndexTableOffset eOffsetEnd;
+
+ switch (eCategory)
+ {
+ case SvNumFormatType::NUMBER:
+ eOffsetStart = NF_NUMBER_START;
+ eOffsetEnd = NF_NUMBER_END;
+ break;
+ case SvNumFormatType::PERCENT:
+ eOffsetStart = NF_PERCENT_START;
+ eOffsetEnd = NF_PERCENT_END;
+ break;
+ case SvNumFormatType::CURRENCY:
+ // Currency entries are generated and assembled, ignore
+ // bSuppressDuplicates.
+ nSelPos = FillEListWithCurrency_Impl(rList, nSelPos);
+ return;
+ case SvNumFormatType::DATE:
+ eOffsetStart = NF_DATE_START;
+ eOffsetEnd = NF_DATE_END;
+ break;
+ case SvNumFormatType::TIME:
+ eOffsetStart = NF_TIME_START;
+ eOffsetEnd = NF_TIME_END;
+ break;
+ case SvNumFormatType::SCIENTIFIC:
+ eOffsetStart = NF_SCIENTIFIC_START;
+ eOffsetEnd = NF_SCIENTIFIC_END;
+ break;
+ case SvNumFormatType::FRACTION:
+ eOffsetStart = NF_FRACTION_START;
+ eOffsetEnd = NF_FRACTION_END;
+ // Fraction formats are internally generated by the number
+ // formatter and are not supposed to contain duplicates anyway.
+ nSelPos = FillEListWithFormats_Impl(rList, nSelPos, eOffsetStart, eOffsetEnd, false);
+ nSelPos
+ = FillEListWithFormats_Impl(rList, nSelPos, NF_FRACTION_3D, NF_FRACTION_100, false);
+ return;
+ case SvNumFormatType::LOGICAL:
+ eOffsetStart = NF_BOOLEAN;
+ eOffsetEnd = NF_BOOLEAN;
+ break;
+ case SvNumFormatType::TEXT:
+ eOffsetStart = NF_TEXT;
+ eOffsetEnd = NF_TEXT;
+ break;
+ default:
+ return;
+ }
+
+ nSelPos
+ = FillEListWithFormats_Impl(rList, nSelPos, eOffsetStart, eOffsetEnd, bSuppressDuplicates);
+}
+
+short SvxNumberFormatShell::FillEListWithFormats_Impl(std::vector<OUString>& rList, short nSelPos,
+ NfIndexTableOffset eOffsetStart,
+ NfIndexTableOffset eOffsetEnd,
+ bool bSuppressDuplicates)
+{
+ /* Create a current list of format entries. The return value is
+ * the list position of the current format. If the list is empty
+ * or if there is no current format, SELPOS_NONE is delivered.
+ */
+ for (tools::Long nIndex = eOffsetStart; nIndex <= eOffsetEnd; ++nIndex)
+ {
+ FillEListWithOneFormat_Impl(rList, nSelPos, bSuppressDuplicates,
+ static_cast<NfIndexTableOffset>(nIndex), false);
+ }
+
+ return nSelPos;
+}
+
+short SvxNumberFormatShell::FillEListWithDateTime_Impl(std::vector<OUString>& rList, short nSelPos,
+ bool bSuppressDuplicates)
+{
+ // Append a list of date+time formats.
+
+ // Add first, so a NF_DATETIME_SYSTEM_SHORT_HHMM may be suppressed in
+ // locales that do not use 2-digit years there and this here is the
+ // default.
+ FillEListWithOneFormat_Impl(rList, nSelPos, bSuppressDuplicates, NF_DATETIME_SYS_DDMMYYYY_HHMM,
+ true);
+
+ for (tools::Long nIndex = NF_DATETIME_START; nIndex <= NF_DATETIME_END; ++nIndex)
+ {
+ FillEListWithOneFormat_Impl(rList, nSelPos, bSuppressDuplicates,
+ static_cast<NfIndexTableOffset>(nIndex), true);
+ }
+
+ // Always add the internally generated ISO formats.
+ nSelPos = FillEListWithFormats_Impl(rList, nSelPos, NF_DATETIME_ISO_YYYYMMDD_HHMMSS,
+ NF_DATETIME_ISO_YYYYMMDDTHHMMSS000, false);
+
+ return nSelPos;
+}
+
+void SvxNumberFormatShell::FillEListWithOneFormat_Impl(std::vector<OUString>& rList, short& nSelPos,
+ bool bSuppressDuplicates,
+ NfIndexTableOffset nOffset,
+ bool bSuppressIsoDateTime)
+{
+ sal_uInt32 nNFEntry = pFormatter->GetFormatIndex(nOffset, eCurLanguage);
+
+ const SvNumberformat* pNumEntry = pFormatter->GetEntry(nNFEntry);
+ if (pNumEntry == nullptr)
+ return;
+
+ SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
+ sal_uInt16 nMyType;
+ CategoryToPos_Impl(nMyCat, nMyType);
+ OUString aNewFormNInfo = pNumEntry->GetFormatstring();
+
+ if (nNFEntry == nCurFormatKey)
+ {
+ nSelPos = (!IsRemoved_Impl(nNFEntry)) ? aCurEntryList.size() : SELPOS_NONE;
+ }
+
+ // Ugly hack to suppress an ISO date+time format that is the default
+ // date+time format of the locale and identical to the internally generated
+ // one always to be added after/below.
+ const bool bSupIso
+ = bSuppressIsoDateTime && bSuppressDuplicates
+ && (aNewFormNInfo == "YYYY-MM-DD HH:MM:SS" || aNewFormNInfo == "YYYY-MM-DD\"T\"HH:MM:SS");
+
+ if (!bSupIso
+ && (!bSuppressDuplicates || IsEssentialFormat_Impl(nMyCat, nNFEntry)
+ || std::find(rList.begin(), rList.end(), aNewFormNInfo) == rList.end()))
+ {
+ rList.push_back(aNewFormNInfo);
+ aCurEntryList.push_back(nNFEntry);
+ }
+}
+
+bool SvxNumberFormatShell::IsEssentialFormat_Impl(SvNumFormatType eType, sal_uInt32 nKey)
+{
+ if (nKey == nCurFormatKey)
+ return true;
+
+ const NfIndexTableOffset nIndex = pFormatter->GetIndexTableOffset(nKey);
+ switch (nIndex)
+ {
+ // These are preferred or edit formats.
+ case NF_DATE_SYS_DDMMYYYY:
+ case NF_DATE_ISO_YYYYMMDD:
+ case NF_TIME_HH_MMSS:
+ case NF_TIME_MMSS00:
+ case NF_TIME_HH_MMSS00:
+ case NF_DATETIME_SYS_DDMMYYYY_HHMM:
+ case NF_DATETIME_SYS_DDMMYYYY_HHMMSS:
+ case NF_DATETIME_ISO_YYYYMMDD_HHMMSS:
+ case NF_DATETIME_ISO_YYYYMMDD_HHMMSS000:
+ case NF_DATETIME_ISO_YYYYMMDDTHHMMSS:
+ case NF_DATETIME_ISO_YYYYMMDDTHHMMSS000:
+ return true;
+ default:
+ break;
+ }
+
+ return nKey == pFormatter->GetStandardFormat(eType, eCurLanguage);
+}
+
+short SvxNumberFormatShell::FillEListWithCurrency_Impl(std::vector<OUString>& rList, short nSelPos)
+{
+ /* Create a current list of format entries. The return value is
+ * the list position of the current format. If the list is empty
+ * or if there is no current format, SELPOS_NONE is delivered.
+ */
+ DBG_ASSERT(pCurFmtTable != nullptr, "unknown NumberFormat");
+
+ const NfCurrencyEntry* pTmpCurrencyEntry;
+ bool bTmpBanking;
+ OUString rSymbol;
+
+ bool bFlag = pFormatter->GetNewCurrencySymbolString(nCurFormatKey, rSymbol, &pTmpCurrencyEntry,
+ &bTmpBanking);
+
+ if ((!bFlag && pCurCurrencyEntry == nullptr)
+ || (bFlag && pTmpCurrencyEntry == nullptr && rSymbol.isEmpty())
+ || (nCurCategory == SvNumFormatType::ALL))
+ {
+ if (nCurCategory == SvNumFormatType::ALL)
+ FillEListWithUserCurrencys(rList, nSelPos);
+ nSelPos = FillEListWithSysCurrencys(rList, nSelPos);
+ }
+ else
+ {
+ nSelPos = FillEListWithUserCurrencys(rList, nSelPos);
+ }
+
+ return nSelPos;
+}
+
+short SvxNumberFormatShell::FillEListWithSysCurrencys(std::vector<OUString>& rList, short nSelPos)
+{
+ /* Create a current list of format entries. The return value is
+ * the list position of the current format. If the list is empty
+ * or if there is no current format, SELPOS_NONE is delivered.
+ */
+ sal_uInt16 nMyType;
+
+ DBG_ASSERT(pCurFmtTable != nullptr, "unknown NumberFormat");
+
+ sal_uInt32 nNFEntry;
+ OUString aNewFormNInfo;
+
+ nCurCurrencyEntryPos = 0;
+
+ for (tools::Long nIndex = NF_CURRENCY_START; nIndex <= NF_CURRENCY_END; nIndex++)
+ {
+ nNFEntry
+ = pFormatter->GetFormatIndex(static_cast<NfIndexTableOffset>(nIndex), eCurLanguage);
+
+ if (nCurCategory == SvNumFormatType::ALL && nNFEntry != nCurFormatKey)
+ // Deprecated old currency entries, for ALL add only if used as
+ // current format key.
+ continue;
+
+ const SvNumberformat* pNumEntry = pFormatter->GetEntry(nNFEntry);
+
+ if (pNumEntry == nullptr)
+ continue;
+
+ SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
+ CategoryToPos_Impl(nMyCat, nMyType);
+ aNewFormNInfo = pNumEntry->GetFormatstring();
+
+ if (nNFEntry == nCurFormatKey)
+ {
+ nSelPos = (!IsRemoved_Impl(nNFEntry)) ? aCurEntryList.size() : SELPOS_NONE;
+ }
+
+ rList.push_back(aNewFormNInfo);
+ aCurEntryList.push_back(nNFEntry);
+ }
+
+ if (nCurCategory != SvNumFormatType::ALL)
+ {
+ for (const auto& rEntry : *pCurFmtTable)
+ {
+ sal_uInt32 nKey = rEntry.first;
+ const SvNumberformat* pNumEntry = rEntry.second;
+
+ if (!IsRemoved_Impl(nKey))
+ {
+ bool bUserNewCurrency = false;
+ if (pNumEntry->HasNewCurrency())
+ {
+ const NfCurrencyEntry* pTmpCurrencyEntry;
+ bool bTmpBanking;
+ OUString rSymbol;
+
+ pFormatter->GetNewCurrencySymbolString(nKey, rSymbol, &pTmpCurrencyEntry,
+ &bTmpBanking);
+
+ bUserNewCurrency = (pTmpCurrencyEntry != nullptr);
+ }
+
+ if (!bUserNewCurrency && (pNumEntry->GetType() & SvNumFormatType::DEFINED))
+ {
+ SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
+ CategoryToPos_Impl(nMyCat, nMyType);
+ aNewFormNInfo = pNumEntry->GetFormatstring();
+
+ if (nKey == nCurFormatKey)
+ nSelPos = aCurEntryList.size();
+ rList.push_back(aNewFormNInfo);
+ aCurEntryList.push_back(nKey);
+ }
+ }
+ }
+ }
+ return nSelPos;
+}
+
+short SvxNumberFormatShell::FillEListWithUserCurrencys(std::vector<OUString>& rList, short nSelPos)
+{
+ /* Create a current list of format entries. The return value is
+ * the list position of the current format. If the list is empty
+ * or if there is no current format, SELPOS_NONE is delivered.
+ */
+ sal_uInt16 nMyType;
+
+ DBG_ASSERT(pCurFmtTable != nullptr, "unknown NumberFormat");
+
+ OUString aNewFormNInfo;
+
+ const NfCurrencyEntry* pTmpCurrencyEntry;
+ bool bTmpBanking, bAdaptSelPos;
+ OUString rSymbol;
+ OUString rBankSymbol;
+
+ std::vector<OUString> aList;
+ std::vector<sal_uInt32> aKeyList;
+
+ pFormatter->GetNewCurrencySymbolString(nCurFormatKey, rSymbol, &pTmpCurrencyEntry,
+ &bTmpBanking);
+
+ OUString rShortSymbol;
+
+ if (pCurCurrencyEntry == nullptr)
+ {
+ // #110398# If no currency format was previously selected (we're not
+ // about to add another currency), try to select the initial currency
+ // format (nCurFormatKey) that was set in FormatChanged() after
+ // matching the format string entered in the dialog.
+ bAdaptSelPos = true;
+ pCurCurrencyEntry = const_cast<NfCurrencyEntry*>(pTmpCurrencyEntry);
+ bBankingSymbol = bTmpBanking;
+ nCurCurrencyEntryPos = FindCurrencyFormat(pTmpCurrencyEntry, bTmpBanking);
+ }
+ else
+ {
+ if (pTmpCurrencyEntry == pCurCurrencyEntry)
+ bAdaptSelPos = true;
+ else
+ {
+ bAdaptSelPos = false;
+ pTmpCurrencyEntry = pCurCurrencyEntry;
+ }
+ bTmpBanking = bBankingSymbol;
+ }
+
+ if (pTmpCurrencyEntry != nullptr)
+ {
+ rSymbol = pTmpCurrencyEntry->BuildSymbolString(false);
+ rBankSymbol = pTmpCurrencyEntry->BuildSymbolString(true);
+ rShortSymbol = pTmpCurrencyEntry->BuildSymbolString(bTmpBanking, true);
+ }
+
+ for (const auto& rEntry : *pCurFmtTable)
+ {
+ sal_uInt32 nKey = rEntry.first;
+ const SvNumberformat* pNumEntry = rEntry.second;
+
+ if (!IsRemoved_Impl(nKey))
+ {
+ if (pNumEntry->GetType() & SvNumFormatType::DEFINED || pNumEntry->IsAdditionalBuiltin())
+ {
+ SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
+ CategoryToPos_Impl(nMyCat, nMyType);
+ aNewFormNInfo = pNumEntry->GetFormatstring();
+
+ bool bInsFlag = false;
+ if (pNumEntry->HasNewCurrency())
+ {
+ bInsFlag = true; // merge locale formats into currency selection
+ }
+ else if ((!bTmpBanking && aNewFormNInfo.indexOf(rSymbol) >= 0)
+ || (bTmpBanking && aNewFormNInfo.indexOf(rBankSymbol) >= 0))
+ {
+ bInsFlag = true;
+ }
+ else if (aNewFormNInfo.indexOf(rShortSymbol) >= 0)
+ {
+ OUString rTstSymbol;
+ const NfCurrencyEntry* pTstCurrencyEntry;
+ bool bTstBanking;
+
+ pFormatter->GetNewCurrencySymbolString(nKey, rTstSymbol, &pTstCurrencyEntry,
+ &bTstBanking);
+
+ if (pTmpCurrencyEntry == pTstCurrencyEntry && bTstBanking == bTmpBanking)
+ {
+ bInsFlag = true;
+ }
+ }
+
+ if (bInsFlag)
+ {
+ aList.push_back(aNewFormNInfo);
+ aKeyList.push_back(nKey);
+ }
+ }
+ }
+ }
+
+ NfWSStringsDtor aWSStringsDtor;
+ sal_uInt16 nDefault;
+ if (pTmpCurrencyEntry && nCurCategory != SvNumFormatType::ALL)
+ {
+ nDefault
+ = pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pTmpCurrencyEntry, bTmpBanking);
+ if (!bTmpBanking)
+ pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pTmpCurrencyEntry, true);
+ }
+ else
+ nDefault = 0;
+ if (!bTmpBanking && nCurCategory != SvNumFormatType::ALL)
+ {
+ // append formats for all currencies defined in the current I18N locale
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+ sal_uInt16 nCurrCount = rCurrencyTable.size();
+ LanguageType eLang = MsLangId::getRealLanguage(eCurLanguage);
+ for (sal_uInt16 i = 0; i < nCurrCount; ++i)
+ {
+ const NfCurrencyEntry* pCurr = &rCurrencyTable[i];
+ if (pCurr->GetLanguage() == eLang && pTmpCurrencyEntry != pCurr)
+ {
+ pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pCurr, false);
+ pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pCurr, true);
+ }
+ }
+ }
+
+ size_t nOldListCount = rList.size();
+ for (size_t i = 0, nPos = nOldListCount; i < aWSStringsDtor.size(); ++i)
+ {
+ bool bFlag = true;
+ OUString aInsStr(aWSStringsDtor[i]);
+ size_t j;
+ for (j = 0; j < aList.size(); ++j)
+ {
+ if (aList[j] == aInsStr)
+ {
+ bFlag = false;
+ break;
+ }
+ }
+ if (bFlag)
+ {
+ rList.push_back(aInsStr);
+ aCurEntryList.insert(aCurEntryList.begin() + (nPos++), NUMBERFORMAT_ENTRY_NOT_FOUND);
+ }
+ else
+ {
+ rList.push_back(aList[j]);
+ aList.erase(aList.begin() + j);
+ aCurEntryList.insert(aCurEntryList.begin() + (nPos++), aKeyList[j]);
+ aKeyList.erase(aKeyList.begin() + j);
+ }
+ }
+
+ for (size_t i = 0; i < aKeyList.size(); ++i)
+ {
+ if (aKeyList[i] != NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ rList.push_back(aList[i]);
+ aCurEntryList.push_back(aKeyList[i]);
+ }
+ }
+
+ for (size_t i = nOldListCount; i < rList.size(); ++i)
+ {
+ aCurrencyFormatList.push_back(rList[i]);
+
+ if (nSelPos == SELPOS_NONE && bAdaptSelPos && aCurEntryList[i] == nCurFormatKey)
+ nSelPos = i;
+ }
+
+ if (nSelPos == SELPOS_NONE && nCurCategory != SvNumFormatType::ALL)
+ nSelPos = nDefault;
+
+ return nSelPos;
+}
+
+short SvxNumberFormatShell::FillEListWithUsD_Impl(std::vector<OUString>& rList,
+ SvNumFormatType eCategory, short nSelPos)
+{
+ /* Create a current list of format entries. The return value is
+ * the list position of the current format. If the list is empty
+ * or if there is no current format, SELPOS_NONE is delivered.
+ */
+
+ assert(pCurFmtTable != nullptr);
+
+ OUString aNewFormNInfo;
+
+ const bool bCatDefined = (eCategory == SvNumFormatType::DEFINED);
+ const bool bCategoryMatch = (eCategory != SvNumFormatType::ALL && !bCatDefined);
+
+ for (const auto& rEntry : *pCurFmtTable)
+ {
+ const SvNumberformat* pNumEntry = rEntry.second;
+
+ if (bCategoryMatch && (pNumEntry->GetMaskedType() & eCategory) != eCategory)
+ continue; // for; type does not match category if not ALL
+
+ const bool bUserDefined = bool(pNumEntry->GetType() & SvNumFormatType::DEFINED);
+ if (!bUserDefined && bCatDefined)
+ continue; // for; not user defined in DEFINED category
+
+ if (!(bUserDefined || (!bCatDefined && pNumEntry->IsAdditionalBuiltin())))
+ continue; // for; does not match criteria at all
+
+ const sal_uInt32 nKey = rEntry.first;
+ if (!IsRemoved_Impl(nKey))
+ {
+ aNewFormNInfo = pNumEntry->GetFormatstring();
+
+ bool bAdd = true;
+ if (pNumEntry->HasNewCurrency())
+ {
+ bool bTestBanking;
+ sal_uInt16 nPos = FindCurrencyTableEntry(aNewFormNInfo, bTestBanking);
+ bAdd = !IsInTable(nPos, bTestBanking, aNewFormNInfo);
+ }
+ if (bAdd)
+ {
+ if (nKey == nCurFormatKey)
+ nSelPos = aCurEntryList.size();
+ rList.push_back(aNewFormNInfo);
+ aCurEntryList.push_back(nKey);
+ }
+ }
+ }
+ return nSelPos;
+}
+
+void SvxNumberFormatShell::GetPreviewString_Impl(OUString& rString, const Color*& rpColor)
+{
+ rpColor = nullptr;
+
+ // #50441# if a string was set in addition to the value, use it for text formats
+ bool bUseText
+ = (eValType == SvxNumberValueType::String
+ || (!aValStr.isEmpty() && (pFormatter->GetType(nCurFormatKey) & SvNumFormatType::TEXT)));
+
+ if (bUseText)
+ {
+ pFormatter->GetOutputString(aValStr, nCurFormatKey, rString, &rpColor);
+ }
+ else
+ {
+ pFormatter->GetOutputString(nValNum, nCurFormatKey, rString, &rpColor, bUseStarFormat);
+ }
+}
+
+::std::vector<sal_uInt32>::iterator SvxNumberFormatShell::GetRemoved_Impl(size_t nKey)
+{
+ return ::std::find(aDelList.begin(), aDelList.end(), nKey);
+}
+
+bool SvxNumberFormatShell::IsRemoved_Impl(size_t nKey)
+{
+ return GetRemoved_Impl(nKey) != aDelList.end();
+}
+
+::std::vector<sal_uInt32>::iterator SvxNumberFormatShell::GetAdded_Impl(size_t nKey)
+{
+ return ::std::find(aAddList.begin(), aAddList.end(), nKey);
+}
+
+// Conversion routines:
+void SvxNumberFormatShell::PosToCategory_Impl(sal_uInt16 nPos, SvNumFormatType& rCategory)
+{
+ // map category css::form positions (->resource)
+ switch (nPos)
+ {
+ case CAT_USERDEFINED:
+ rCategory = SvNumFormatType::DEFINED;
+ break;
+ case CAT_NUMBER:
+ rCategory = SvNumFormatType::NUMBER;
+ break;
+ case CAT_PERCENT:
+ rCategory = SvNumFormatType::PERCENT;
+ break;
+ case CAT_CURRENCY:
+ rCategory = SvNumFormatType::CURRENCY;
+ break;
+ case CAT_DATE:
+ rCategory = SvNumFormatType::DATE;
+ break;
+ case CAT_TIME:
+ rCategory = SvNumFormatType::TIME;
+ break;
+ case CAT_SCIENTIFIC:
+ rCategory = SvNumFormatType::SCIENTIFIC;
+ break;
+ case CAT_FRACTION:
+ rCategory = SvNumFormatType::FRACTION;
+ break;
+ case CAT_BOOLEAN:
+ rCategory = SvNumFormatType::LOGICAL;
+ break;
+ case CAT_TEXT:
+ rCategory = SvNumFormatType::TEXT;
+ break;
+ case CAT_ALL:
+ default:
+ rCategory = SvNumFormatType::ALL;
+ break;
+ }
+}
+
+void SvxNumberFormatShell::CategoryToPos_Impl(SvNumFormatType nCategory, sal_uInt16& rPos)
+{
+ // map category to css::form positions (->resource)
+ switch (nCategory)
+ {
+ case SvNumFormatType::DEFINED:
+ rPos = CAT_USERDEFINED;
+ break;
+ case SvNumFormatType::NUMBER:
+ rPos = CAT_NUMBER;
+ break;
+ case SvNumFormatType::PERCENT:
+ rPos = CAT_PERCENT;
+ break;
+ case SvNumFormatType::CURRENCY:
+ rPos = CAT_CURRENCY;
+ break;
+ case SvNumFormatType::DATETIME:
+ case SvNumFormatType::DATE:
+ rPos = CAT_DATE;
+ break;
+ case SvNumFormatType::TIME:
+ rPos = CAT_TIME;
+ break;
+ case SvNumFormatType::SCIENTIFIC:
+ rPos = CAT_SCIENTIFIC;
+ break;
+ case SvNumFormatType::FRACTION:
+ rPos = CAT_FRACTION;
+ break;
+ case SvNumFormatType::LOGICAL:
+ rPos = CAT_BOOLEAN;
+ break;
+ case SvNumFormatType::TEXT:
+ rPos = CAT_TEXT;
+ break;
+ case SvNumFormatType::ALL:
+ default:
+ rPos = CAT_ALL;
+ }
+}
+
+/*
+ * Function: Formats the number nValue dependent on rFormatStr
+ * and stores the result in rPreviewStr.
+ * Input: FormatString, color, number to format
+ * Output: Output string rPreviewStr
+ */
+void SvxNumberFormatShell::MakePrevStringFromVal(const OUString& rFormatStr, OUString& rPreviewStr,
+ const Color*& rpFontColor, double nValue)
+{
+ rpFontColor = nullptr;
+ pFormatter->GetPreviewString(rFormatStr, nValue, rPreviewStr, &rpFontColor, eCurLanguage);
+}
+
+/*
+ * Function: Returns the comment for a given entry.
+ * Input: Number of the entry
+ * Output: Comment string
+ */
+void SvxNumberFormatShell::SetComment4Entry(short nEntry, const OUString& aEntStr)
+{
+ SvNumberformat* pNumEntry;
+ if (nEntry < 0)
+ return;
+ sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
+ pNumEntry = const_cast<SvNumberformat*>(pFormatter->GetEntry(nMyNfEntry));
+ if (pNumEntry != nullptr)
+ pNumEntry->SetComment(aEntStr);
+}
+
+/*
+ * Function: Returns the comment for a given entry.
+ * Input: Number of the entry
+ * Output: Comment string
+ */
+OUString SvxNumberFormatShell::GetComment4Entry(short nEntry)
+{
+ if (nEntry < 0)
+ return OUString();
+
+ if (o3tl::make_unsigned(nEntry) < aCurEntryList.size())
+ {
+ sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
+ const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
+ if (pNumEntry != nullptr)
+ return pNumEntry->GetComment();
+ }
+
+ return OUString();
+}
+
+/*
+ * Function: Returns the category number for a given entry.
+ * Input: Number of the entry
+ * Output: Category number
+ */
+short SvxNumberFormatShell::GetCategory4Entry(short nEntry) const
+{
+ if (nEntry < 0)
+ return 0;
+ if (o3tl::make_unsigned(nEntry) < aCurEntryList.size())
+ {
+ sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
+
+ if (nMyNfEntry != NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
+ if (pNumEntry != nullptr)
+ {
+ SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
+ sal_uInt16 nMyType;
+ CategoryToPos_Impl(nMyCat, nMyType);
+
+ return static_cast<short>(nMyType);
+ }
+ return 0;
+ }
+ else if (!aCurrencyFormatList.empty())
+ {
+ return CAT_CURRENCY;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Function: Returns the information about whether an entry is user-specific.
+ * Input: Number of the entry
+ * Output: User-specific?
+ */
+bool SvxNumberFormatShell::GetUserDefined4Entry(short nEntry)
+{
+ if (nEntry < 0)
+ return false;
+ if (o3tl::make_unsigned(nEntry) < aCurEntryList.size())
+ {
+ sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
+ const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
+
+ if (pNumEntry != nullptr)
+ {
+ if (pNumEntry->GetType() & SvNumFormatType::DEFINED)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/*
+ * Function: Returns the format string for a given entry.
+ * Input: Number of the entry
+ * Output: Format string
+ */
+OUString SvxNumberFormatShell::GetFormat4Entry(short nEntry)
+{
+ if (nEntry < 0)
+ return OUString();
+
+ if (!aCurrencyFormatList.empty())
+ {
+ if (aCurrencyFormatList.size() > o3tl::make_unsigned(nEntry))
+ return aCurrencyFormatList[nEntry];
+ }
+ else
+ {
+ sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
+ const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
+
+ if (pNumEntry != nullptr)
+ return pNumEntry->GetFormatstring();
+ }
+ return OUString();
+}
+
+/*
+ * Function: Returns the list number for a given format index.
+ * Input: Number of the entry
+ * Output: Category number
+ */
+short SvxNumberFormatShell::GetListPos4Entry(sal_uInt32 nIdx, std::u16string_view rFmtString)
+{
+ short nSelP = SELPOS_NONE;
+ if (nIdx != NUMBERFORMAT_ENTRY_NEW_CURRENCY)
+ {
+ // Check list size against return type limit.
+ if (aCurEntryList.size() <= o3tl::make_unsigned(::std::numeric_limits<short>::max()))
+ {
+ for (size_t i = 0; i < aCurEntryList.size(); ++i)
+ {
+ if (aCurEntryList[i] == nIdx)
+ {
+ nSelP = i;
+ break;
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("svx::SvxNumberFormatShell::GetListPos4Entry(), list got too large!");
+ }
+ }
+ else
+ {
+ // A second list holds the generated currency formats.
+ for (size_t i = 0; i < aCurrencyFormatList.size(); ++i)
+ {
+ if (rFmtString == aCurrencyFormatList[i])
+ {
+ nSelP = static_cast<short>(i);
+ break;
+ }
+ }
+ }
+ return nSelP;
+}
+
+OUString SvxNumberFormatShell::GetStandardName() const
+{
+ return pFormatter->GetStandardName(eCurLanguage);
+}
+
+void SvxNumberFormatShell::GetCurrencySymbols(std::vector<OUString>& rList, sal_uInt16* pPos)
+{
+ const NfCurrencyEntry* pTmpCurrencyEntry = SvNumberFormatter::MatchSystemCurrency();
+
+ bool bFlag = (pTmpCurrencyEntry == nullptr);
+
+ SvxCurrencyToolBoxControl::GetCurrencySymbols(rList, bFlag, aCurCurrencyList);
+
+ if (pPos == nullptr)
+ return;
+
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+ sal_uInt16 nTableCount = rCurrencyTable.size();
+
+ *pPos = 0;
+ size_t nCount = aCurCurrencyList.size();
+
+ if (bFlag)
+ {
+ *pPos = 1;
+ nCurCurrencyEntryPos = 1;
+ }
+ else
+ {
+ for (size_t i = 1; i < nCount; i++)
+ {
+ const sal_uInt16 j = aCurCurrencyList[i];
+ if (j != sal_uInt16(-1) && j < nTableCount && pTmpCurrencyEntry == &rCurrencyTable[j])
+ {
+ *pPos = static_cast<sal_uInt16>(i);
+ nCurCurrencyEntryPos = static_cast<sal_uInt16>(i);
+ break;
+ }
+ }
+ }
+}
+
+void SvxNumberFormatShell::SetCurrencySymbol(sal_uInt32 nPos)
+{
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+ sal_uInt16 nCount = rCurrencyTable.size();
+
+ bBankingSymbol = (nPos >= nCount);
+
+ if (nPos >= aCurCurrencyList.size())
+ return;
+
+ sal_uInt16 nCurrencyPos = aCurCurrencyList[nPos];
+ if (nCurrencyPos != sal_uInt16(-1))
+ {
+ pCurCurrencyEntry = const_cast<NfCurrencyEntry*>(&rCurrencyTable[nCurrencyPos]);
+ nCurCurrencyEntryPos = nPos;
+ }
+ else
+ {
+ pCurCurrencyEntry = nullptr;
+ nCurCurrencyEntryPos = 0;
+ nCurFormatKey = pFormatter->GetFormatIndex(NF_CURRENCY_1000DEC2_RED, eCurLanguage);
+ }
+}
+
+void SvxNumberFormatShell::SetCurCurrencyEntry(NfCurrencyEntry* pCEntry)
+{
+ pCurCurrencyEntry = pCEntry;
+}
+
+bool SvxNumberFormatShell::IsTmpCurrencyFormat(const OUString& rFmtString)
+{
+ sal_uInt32 nFound;
+ FindEntry(rFmtString, &nFound);
+ return nFound == NUMBERFORMAT_ENTRY_NEW_CURRENCY;
+}
+
+sal_uInt16 SvxNumberFormatShell::FindCurrencyFormat(const OUString& rFmtString)
+{
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+ sal_uInt16 nCount = rCurrencyTable.size();
+
+ bool bTestBanking = false;
+
+ sal_uInt16 nPos = FindCurrencyTableEntry(rFmtString, bTestBanking);
+
+ if (nPos != sal_uInt16(-1))
+ {
+ sal_uInt16 nStart = 0;
+ if (bTestBanking && aCurCurrencyList.size() > nPos)
+ {
+ nStart = nCount;
+ }
+ for (size_t j = nStart; j < aCurCurrencyList.size(); j++)
+ {
+ if (aCurCurrencyList[j] == nPos)
+ return j;
+ }
+ }
+ return sal_uInt16(-1);
+}
+
+sal_uInt16 SvxNumberFormatShell::FindCurrencyTableEntry(const OUString& rFmtString,
+ bool& bTestBanking)
+{
+ sal_uInt16 nPos = sal_uInt16(-1);
+
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+ sal_uInt16 nCount = rCurrencyTable.size();
+
+ const SvNumberformat* pFormat;
+ OUString aSymbol, aExtension;
+ sal_uInt32 nFound = pFormatter->TestNewString(rFmtString, eCurLanguage);
+ if (nFound != NUMBERFORMAT_ENTRY_NOT_FOUND
+ && ((pFormat = pFormatter->GetEntry(nFound)) != nullptr)
+ && pFormat->GetNewCurrencySymbol(aSymbol, aExtension))
+ {
+ // eventually match with format locale
+ const NfCurrencyEntry* pTmpCurrencyEntry = SvNumberFormatter::GetCurrencyEntry(
+ bTestBanking, aSymbol, aExtension, pFormat->GetLanguage());
+ if (pTmpCurrencyEntry)
+ {
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ if (pTmpCurrencyEntry == &rCurrencyTable[i])
+ {
+ nPos = i;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // search symbol string only
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ const NfCurrencyEntry* pTmpCurrencyEntry = &rCurrencyTable[i];
+ OUString _aSymbol = pTmpCurrencyEntry->BuildSymbolString(false);
+ OUString aBankSymbol = pTmpCurrencyEntry->BuildSymbolString(true);
+
+ if (rFmtString.indexOf(_aSymbol) != -1)
+ {
+ bTestBanking = false;
+ nPos = i;
+ break;
+ }
+ else if (rFmtString.indexOf(aBankSymbol) != -1)
+ {
+ bTestBanking = true;
+ nPos = i;
+ break;
+ }
+ }
+ }
+
+ return nPos;
+}
+
+sal_uInt16 SvxNumberFormatShell::FindCurrencyFormat(const NfCurrencyEntry* pTmpCurrencyEntry,
+ bool bTmpBanking)
+{
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+ sal_uInt16 nCount = rCurrencyTable.size();
+
+ sal_uInt16 nPos = 0;
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ if (pTmpCurrencyEntry == &rCurrencyTable[i])
+ {
+ nPos = i;
+ break;
+ }
+ }
+
+ sal_uInt16 nStart = 0;
+ if (bTmpBanking && aCurCurrencyList.size() > nPos)
+ {
+ nStart = nCount;
+ }
+ for (size_t j = nStart; j < aCurCurrencyList.size(); j++)
+ {
+ if (aCurCurrencyList[j] == nPos)
+ return j;
+ }
+ return sal_uInt16(-1);
+}
+
+bool SvxNumberFormatShell::IsInTable(sal_uInt16 const nPos, bool const bTmpBanking,
+ std::u16string_view rFmtString) const
+{
+ bool bFlag = false;
+
+ if (nPos != sal_uInt16(-1))
+ {
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+
+ if (nPos < rCurrencyTable.size())
+ {
+ NfWSStringsDtor aWSStringsDtor;
+ pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, rCurrencyTable[nPos], bTmpBanking);
+
+ for (const OUString& s : aWSStringsDtor)
+ {
+ if (s == rFmtString)
+ {
+ bFlag = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return bFlag;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/numinf.cxx b/svx/source/items/numinf.cxx
new file mode 100644
index 000000000..d4bb1e915
--- /dev/null
+++ b/svx/source/items/numinf.cxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/numinf.hxx>
+
+
+SvxNumberInfoItem::SvxNumberInfoItem( const TypedWhichId<SvxNumberInfoItem> nId ) :
+ SfxPoolItem ( nId ),
+ pFormatter ( nullptr ),
+ eValueType ( SvxNumberValueType::Undefined ),
+ aStringVal ( "" ),
+ nDoubleVal ( 0 )
+{
+}
+
+
+SvxNumberInfoItem::SvxNumberInfoItem( SvNumberFormatter* pNumFormatter,
+ const TypedWhichId<SvxNumberInfoItem> nId ) :
+ SfxPoolItem ( nId ),
+ pFormatter ( pNumFormatter ),
+ eValueType ( SvxNumberValueType::Undefined ),
+ aStringVal ( "" ),
+ nDoubleVal ( 0 )
+{
+}
+
+
+SvxNumberInfoItem::SvxNumberInfoItem( SvNumberFormatter* pNumFormatter,
+ const OUString& rVal, const TypedWhichId<SvxNumberInfoItem> nId ) :
+ SfxPoolItem ( nId ),
+ pFormatter ( pNumFormatter ),
+ eValueType ( SvxNumberValueType::String ),
+ aStringVal ( rVal ),
+ nDoubleVal ( 0 )
+{
+}
+
+
+SvxNumberInfoItem::SvxNumberInfoItem( SvNumberFormatter* pNumFormatter,
+ const double& rVal, const TypedWhichId<SvxNumberInfoItem> nId ) :
+ SfxPoolItem ( nId ),
+ pFormatter ( pNumFormatter ),
+ eValueType ( SvxNumberValueType::Number ),
+ aStringVal ( "" ),
+ nDoubleVal ( rVal )
+{
+}
+
+
+SvxNumberInfoItem::SvxNumberInfoItem( SvNumberFormatter* pNumFormatter,
+ const double& rVal, const OUString& rValueStr,
+ const TypedWhichId<SvxNumberInfoItem> nId ) :
+ SfxPoolItem ( nId ),
+ pFormatter ( pNumFormatter ),
+ eValueType ( SvxNumberValueType::Number ),
+ aStringVal ( rValueStr ),
+ nDoubleVal ( rVal )
+{
+}
+
+
+SvxNumberInfoItem::SvxNumberInfoItem( const SvxNumberInfoItem& rItem ) :
+ SfxPoolItem ( rItem ),
+ pFormatter ( rItem.pFormatter ),
+ eValueType ( rItem.eValueType ),
+ aStringVal ( rItem.aStringVal ),
+ nDoubleVal ( rItem.nDoubleVal ),
+ mvDelFormats( rItem.mvDelFormats )
+{
+}
+
+
+SvxNumberInfoItem::~SvxNumberInfoItem()
+{
+}
+
+
+bool SvxNumberInfoItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return false;
+}
+
+
+bool SvxNumberInfoItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const SvxNumberInfoItem& rOther = static_cast<const SvxNumberInfoItem&>(rItem);
+
+ return mvDelFormats == rOther.mvDelFormats &&
+ pFormatter == rOther.pFormatter &&
+ eValueType == rOther.eValueType &&
+ nDoubleVal == rOther.nDoubleVal &&
+ aStringVal == rOther.aStringVal;
+}
+
+SvxNumberInfoItem* SvxNumberInfoItem::Clone( SfxItemPool * ) const
+{
+ return new SvxNumberInfoItem( *this );
+}
+
+void SvxNumberInfoItem::SetDelFormats( std::vector<sal_uInt32> && aData )
+{
+ mvDelFormats = std::move(aData);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/ofaitem.cxx b/svx/source/items/ofaitem.cxx
new file mode 100644
index 000000000..688507592
--- /dev/null
+++ b/svx/source/items/ofaitem.cxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/ofaitem.hxx>
+#include <svx/xtable.hxx>
+
+OfaPtrItem::OfaPtrItem( sal_uInt16 _nWhich, void *_pPtr )
+ : SfxPoolItem( _nWhich ), pPtr( _pPtr )
+{
+
+}
+
+bool OfaPtrItem::operator==( const SfxPoolItem& rItem) const
+{
+ return SfxPoolItem::operator==(rItem) &&
+ static_cast<const OfaPtrItem&>(rItem).pPtr == pPtr;
+}
+
+OfaPtrItem* OfaPtrItem::Clone( SfxItemPool * ) const
+{
+ return new OfaPtrItem( *this );
+}
+
+OfaXColorListItem::OfaXColorListItem( sal_uInt16 _nWhich, const rtl::Reference<XColorList> &xRef )
+ : SfxPoolItem( _nWhich ), mxRef( xRef )
+{}
+
+bool OfaXColorListItem::operator==( const SfxPoolItem& rItem ) const
+{
+ return SfxPoolItem::operator==(rItem)
+ && mxRef == static_cast<OfaXColorListItem const &>(rItem).mxRef;
+}
+
+OfaXColorListItem* OfaXColorListItem::Clone( SfxItemPool* /*pPool = 0*/ ) const
+{
+ return new OfaXColorListItem( *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/pageitem.cxx b/svx/source/items/pageitem.cxx
new file mode 100644
index 000000000..93239ea3d
--- /dev/null
+++ b/svx/source/items/pageitem.cxx
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <utility>
+
+#include <osl/diagnose.h>
+#include <comphelper/processfactory.hxx>
+#include <tools/resary.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/strarray.hxx>
+#include <editeng/itemtype.hxx>
+#include <svx/unomid.hxx>
+#include <com/sun/star/text/DefaultNumberingProvider.hpp>
+#include <com/sun/star/text/XNumberingTypeInfo.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/style/PageStyleLayout.hpp>
+#include <svl/itemset.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+using namespace ::com::sun::star;
+
+SfxPoolItem* SvxPageItem::CreateDefault() { return new SvxPageItem(TypedWhichId<SvxPageItem>(0));}
+
+SvxPageItem::SvxPageItem( const TypedWhichId<SvxPageItem> nId ) : SfxPoolItem( nId ),
+
+ eNumType ( SVX_NUM_ARABIC ),
+ bLandscape ( false ),
+ eUse ( SvxPageUsage::All )
+{
+}
+
+// Copy-Ctor
+SvxPageItem::SvxPageItem( const SvxPageItem& rItem )
+ : SfxPoolItem( rItem )
+{
+ eNumType = rItem.eNumType;
+ bLandscape = rItem.bLandscape;
+ eUse = rItem.eUse;
+}
+
+SvxPageItem::~SvxPageItem() {}
+
+// Clone
+SvxPageItem* SvxPageItem::Clone( SfxItemPool * ) const
+{
+ return new SvxPageItem( *this );
+}
+
+// Test for equality
+bool SvxPageItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+ const SvxPageItem& rItem = static_cast<const SvxPageItem&>(rAttr);
+ return ( eNumType == rItem.eNumType &&
+ bLandscape == rItem.bLandscape &&
+ eUse == rItem.eUse );
+}
+
+static OUString GetUsageText( const SvxPageUsage eU )
+{
+ switch( eU )
+ {
+ case SvxPageUsage::Left : return SvxResId(RID_SVXITEMS_PAGE_USAGE_LEFT);
+ case SvxPageUsage::Right : return SvxResId(RID_SVXITEMS_PAGE_USAGE_RIGHT);
+ case SvxPageUsage::All : return SvxResId(RID_SVXITEMS_PAGE_USAGE_ALL);
+ case SvxPageUsage::Mirror: return SvxResId(RID_SVXITEMS_PAGE_USAGE_MIRROR);
+ default: return OUString();
+ }
+}
+
+const TranslateId RID_SVXITEMS_PAGE_NUMS[] =
+{
+ RID_SVXITEMS_PAGE_NUM_CHR_UPPER,
+ RID_SVXITEMS_PAGE_NUM_CHR_LOWER,
+ RID_SVXITEMS_PAGE_NUM_ROM_UPPER,
+ RID_SVXITEMS_PAGE_NUM_ROM_LOWER,
+ RID_SVXITEMS_PAGE_NUM_ARABIC,
+ RID_SVXITEMS_PAGE_NUM_NONE
+};
+
+namespace
+{
+ OUString GetNumberingDescription(SvxNumType eNumType)
+ {
+ // classic ones, keep displaying the old name
+ if (eNumType <= css::style::NumberingType::NUMBER_NONE)
+ return SvxResId(RID_SVXITEMS_PAGE_NUMS[eNumType]);
+ // new ones, reuse the text used in the numbering dropdown list
+ sal_uInt32 n = SvxNumberingTypeTable::FindIndex(eNumType);
+ if (n != RESARRAY_INDEX_NOTFOUND)
+ return SvxNumberingTypeTable::GetString(n);
+ css::uno::Reference<css::uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
+ css::uno::Reference<css::text::XDefaultNumberingProvider> xDefNum = css::text::DefaultNumberingProvider::create(xContext);
+ css::uno::Reference<css::text::XNumberingTypeInfo> xInfo(xDefNum, css::uno::UNO_QUERY);
+ if (!xInfo.is())
+ return OUString();
+ return xInfo->getNumberingIdentifier(eNumType);
+ }
+}
+
+bool SvxPageItem::GetPresentation
+(
+ SfxItemPresentation ePres,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ OUString cpDelimTmp(cpDelim);
+
+ switch ( ePres )
+ {
+ case SfxItemPresentation::Nameless:
+ {
+ if ( !aDescName.isEmpty() )
+ {
+ rText = aDescName + cpDelimTmp;
+ }
+ rText += GetNumberingDescription(eNumType) + cpDelimTmp;
+ if ( bLandscape )
+ rText += SvxResId(RID_SVXITEMS_PAGE_LAND_TRUE);
+ else
+ rText += SvxResId(RID_SVXITEMS_PAGE_LAND_FALSE);
+ OUString aUsageText = GetUsageText( eUse );
+ if (!aUsageText.isEmpty())
+ {
+ rText += cpDelimTmp + aUsageText;
+ }
+ return true;
+ }
+ case SfxItemPresentation::Complete:
+ {
+ rText += SvxResId(RID_SVXITEMS_PAGE_COMPLETE);
+ if ( !aDescName.isEmpty() )
+ {
+ rText += aDescName + cpDelimTmp;
+ }
+ rText += GetNumberingDescription(eNumType) + cpDelimTmp;
+ if ( bLandscape )
+ rText += SvxResId(RID_SVXITEMS_PAGE_LAND_TRUE);
+ else
+ rText += SvxResId(RID_SVXITEMS_PAGE_LAND_FALSE);
+ OUString aUsageText = GetUsageText( eUse );
+ if (!aUsageText.isEmpty())
+ {
+ rText += cpDelimTmp + aUsageText;
+ }
+ return true;
+ }
+ default: ;//prevent warning
+ }
+ return false;
+}
+
+
+bool SvxPageItem::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+ switch( nMemberId )
+ {
+ case MID_PAGE_NUMTYPE:
+ {
+ //! constants aren't in IDLs any more ?!?
+ rVal <<= static_cast<sal_Int16>( eNumType );
+ }
+ break;
+ case MID_PAGE_ORIENTATION:
+ rVal <<= bLandscape;
+ break;
+ case MID_PAGE_LAYOUT :
+ {
+ style::PageStyleLayout eRet;
+ switch(eUse)
+ {
+ case SvxPageUsage::Left : eRet = style::PageStyleLayout_LEFT; break;
+ case SvxPageUsage::Right : eRet = style::PageStyleLayout_RIGHT; break;
+ case SvxPageUsage::All : eRet = style::PageStyleLayout_ALL; break;
+ case SvxPageUsage::Mirror: eRet = style::PageStyleLayout_MIRRORED; break;
+ default:
+ OSL_FAIL("what layout is this?");
+ return false;
+ }
+ rVal <<= eRet;
+ }
+ break;
+ }
+
+ return true;
+}
+
+bool SvxPageItem::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ switch( nMemberId & ~CONVERT_TWIPS )
+ {
+ case MID_PAGE_NUMTYPE:
+ {
+ sal_Int32 nValue = 0;
+ if(!(rVal >>= nValue))
+ return false;
+
+ eNumType = static_cast<SvxNumType>(nValue);
+ }
+ break;
+ case MID_PAGE_ORIENTATION:
+ bLandscape = Any2Bool(rVal);
+ break;
+ case MID_PAGE_LAYOUT :
+ {
+ style::PageStyleLayout eLayout;
+ if(!(rVal >>= eLayout))
+ {
+ sal_Int32 nValue = 0;
+ if(!(rVal >>= nValue))
+ return false;
+ eLayout = static_cast<style::PageStyleLayout>(nValue);
+ }
+ switch( eLayout )
+ {
+ case style::PageStyleLayout_LEFT : eUse = SvxPageUsage::Left ; break;
+ case style::PageStyleLayout_RIGHT : eUse = SvxPageUsage::Right; break;
+ case style::PageStyleLayout_ALL : eUse = SvxPageUsage::All ; break;
+ case style::PageStyleLayout_MIRRORED: eUse = SvxPageUsage::Mirror;break;
+ default: ;//prevent warning
+ }
+ }
+ break;
+ }
+ return true;
+}
+
+// HeaderFooterSet
+SvxSetItem::SvxSetItem( const TypedWhichId<SvxSetItem> nId, const SfxItemSet& rSet ) :
+
+ SfxSetItem( nId, rSet )
+{
+}
+
+SvxSetItem::SvxSetItem( const SvxSetItem& rItem ) :
+
+ SfxSetItem( rItem )
+{
+}
+
+SvxSetItem::SvxSetItem( const TypedWhichId<SvxSetItem> nId, SfxItemSet&& _pSet ) :
+
+ SfxSetItem( nId, std::move(_pSet) )
+{
+}
+
+SvxSetItem* SvxSetItem::Clone( SfxItemPool * ) const
+{
+ return new SvxSetItem(*this);
+}
+
+bool SvxSetItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return false;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/postattr.cxx b/svx/source/items/postattr.cxx
new file mode 100644
index 000000000..267c2cd9a
--- /dev/null
+++ b/svx/source/items/postattr.cxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/postattr.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+SfxPoolItem* SvxPostItAuthorItem::CreateDefault() { return new SvxPostItAuthorItem(TypedWhichId<SvxPostItAuthorItem>(0)); }
+SfxPoolItem* SvxPostItDateItem::CreateDefault() { return new SvxPostItDateItem(TypedWhichId<SvxPostItDateItem>(0)); }
+SfxPoolItem* SvxPostItTextItem::CreateDefault() { return new SvxPostItTextItem(TypedWhichId<SvxPostItTextItem>(0)); }
+SfxPoolItem* SvxPostItIdItem::CreateDefault() { return new SvxPostItIdItem(TypedWhichId<SvxPostItIdItem>(0)); }
+
+SvxPostItAuthorItem::SvxPostItAuthorItem( TypedWhichId<SvxPostItAuthorItem> _nWhich )
+{
+ SetWhich( _nWhich );
+}
+
+
+SvxPostItAuthorItem::SvxPostItAuthorItem( const OUString& rAuthor,
+ TypedWhichId<SvxPostItAuthorItem> _nWhich ) :
+ SfxStringItem( _nWhich, rAuthor )
+{
+}
+
+
+bool SvxPostItAuthorItem::GetPresentation
+(
+ SfxItemPresentation ePres,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ switch ( ePres )
+ {
+ case SfxItemPresentation::Nameless:
+ rText = GetValue();
+ return true;
+ case SfxItemPresentation::Complete:
+ rText = SvxResId(RID_SVXITEMS_AUTHOR_COMPLETE) + GetValue();
+ return true;
+ default: ;//prevent warning
+ }
+ return false;
+}
+
+SvxPostItAuthorItem* SvxPostItAuthorItem::Clone( SfxItemPool * ) const
+{
+ return new SvxPostItAuthorItem( *this );
+}
+
+SvxPostItDateItem::SvxPostItDateItem( TypedWhichId<SvxPostItDateItem> _nWhich )
+ : SfxStringItem(_nWhich)
+{
+}
+
+
+SvxPostItDateItem::SvxPostItDateItem( const OUString& rDate, TypedWhichId<SvxPostItDateItem> _nWhich ) :
+ SfxStringItem( _nWhich, rDate )
+{
+}
+
+
+bool SvxPostItDateItem::GetPresentation
+(
+ SfxItemPresentation ePres,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ switch ( ePres )
+ {
+ case SfxItemPresentation::Nameless:
+ rText = GetValue();
+ return true;
+ case SfxItemPresentation::Complete:
+ rText = SvxResId(RID_SVXITEMS_DATE_COMPLETE) + GetValue();
+ return true;
+ default: ;//prevent warning
+ }
+ return false;
+}
+
+
+SvxPostItDateItem* SvxPostItDateItem::Clone( SfxItemPool * ) const
+{
+ return new SvxPostItDateItem( *this );
+}
+
+SvxPostItTextItem::SvxPostItTextItem( TypedWhichId<SvxPostItTextItem> _nWhich )
+{
+ SetWhich( _nWhich );
+}
+
+SvxPostItTextItem::SvxPostItTextItem( const OUString& rText, TypedWhichId<SvxPostItTextItem> _nWhich ) :
+
+ SfxStringItem( _nWhich, rText )
+{
+}
+
+bool SvxPostItTextItem::GetPresentation
+(
+ SfxItemPresentation ePres,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ switch ( ePres )
+ {
+ case SfxItemPresentation::Nameless:
+ rText = GetValue();
+ return true;
+ case SfxItemPresentation::Complete:
+ rText = SvxResId(RID_SVXITEMS_TEXT_COMPLETE) + GetValue();
+ return true;
+ default: ;//prevent warning
+ }
+ return false;
+}
+
+SvxPostItTextItem* SvxPostItTextItem::Clone( SfxItemPool * ) const
+{
+ return new SvxPostItTextItem( *this );
+}
+
+SvxPostItIdItem::SvxPostItIdItem( TypedWhichId<SvxPostItIdItem> _nWhich )
+{
+ SetWhich( _nWhich );
+}
+
+SvxPostItIdItem* SvxPostItIdItem::Clone( SfxItemPool * ) const
+{
+ return new SvxPostItIdItem( *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/rotmodit.cxx b/svx/source/items/rotmodit.cxx
new file mode 100644
index 000000000..eb559fdae
--- /dev/null
+++ b/svx/source/items/rotmodit.cxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/table/CellVertJustify2.hpp>
+
+#include <svx/dialmgr.hxx>
+#include <svx/rotmodit.hxx>
+#include <rotationstrings.hrc>
+
+using namespace ::com::sun::star;
+
+
+SfxPoolItem* SvxRotateModeItem::CreateDefault() { return new SvxRotateModeItem(SVX_ROTATE_MODE_STANDARD, TypedWhichId<SvxRotateModeItem>(0));}
+
+
+// SvxRotateModeItem - orientation with turned text
+
+
+SvxRotateModeItem::SvxRotateModeItem( SvxRotateMode eMode, TypedWhichId<SvxRotateModeItem> _nWhich )
+ : SfxEnumItem( _nWhich, eMode )
+{
+}
+
+SvxRotateModeItem::SvxRotateModeItem( const SvxRotateModeItem& rItem )
+ : SfxEnumItem( rItem )
+{
+}
+
+SvxRotateModeItem::~SvxRotateModeItem()
+{
+}
+
+OUString SvxRotateModeItem::GetValueText(SvxRotateMode nVal)
+{
+ assert(nVal <= SVX_ROTATE_MODE_BOTTOM && "enum overflow!");
+ return SvxResId(RID_SVXITEMS_ROTATE_MODE[static_cast<size_t>(nVal)]);
+}
+
+bool SvxRotateModeItem::GetPresentation(
+ SfxItemPresentation ePres,
+ MapUnit /*eCoreUnit*/, MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper& ) const
+{
+ rText.clear();
+
+ switch ( ePres )
+ {
+ case SfxItemPresentation::Complete:
+ rText += GetValueText(GetValue());
+ return true;
+
+ case SfxItemPresentation::Nameless:
+ rText += OUString::number( GetValue() );
+ return true;
+ default: ;//prevent warning
+ }
+
+ return false;
+}
+
+sal_uInt16 SvxRotateModeItem::GetValueCount() const
+{
+ return 4; // STANDARD, TOP, CENTER, BOTTOM
+}
+
+SvxRotateModeItem* SvxRotateModeItem::Clone( SfxItemPool* ) const
+{
+ return new SvxRotateModeItem( *this );
+}
+
+bool SvxRotateModeItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ sal_Int32 nUno = table::CellVertJustify2::STANDARD;
+ switch ( GetValue() )
+ {
+ case SVX_ROTATE_MODE_STANDARD: nUno = table::CellVertJustify2::STANDARD; break;
+ case SVX_ROTATE_MODE_TOP: nUno = table::CellVertJustify2::TOP; break;
+ case SVX_ROTATE_MODE_CENTER: nUno = table::CellVertJustify2::CENTER; break;
+ case SVX_ROTATE_MODE_BOTTOM: nUno = table::CellVertJustify2::BOTTOM; break;
+ }
+ rVal <<= nUno;
+ return true;
+}
+
+bool SvxRotateModeItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
+{
+ sal_Int32 nUno(0);
+ if(!(rVal >>= nUno))
+ {
+ nUno = table::CellVertJustify2::STANDARD;
+ }
+
+ SvxRotateMode eSvx = SVX_ROTATE_MODE_STANDARD;
+ switch (nUno)
+ {
+ case table::CellVertJustify2::STANDARD: eSvx = SVX_ROTATE_MODE_STANDARD; break;
+ case table::CellVertJustify2::TOP: eSvx = SVX_ROTATE_MODE_TOP; break;
+ case table::CellVertJustify2::CENTER: eSvx = SVX_ROTATE_MODE_CENTER; break;
+ case table::CellVertJustify2::BOTTOM: eSvx = SVX_ROTATE_MODE_BOTTOM; break;
+ default: ;//prevent warning
+ }
+ SetValue( eSvx );
+ return true;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/svxerr.cxx b/svx/source/items/svxerr.cxx
new file mode 100644
index 000000000..24efadda4
--- /dev/null
+++ b/svx/source/items/svxerr.cxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svxerr.hxx>
+#include <svx/dialmgr.hxx>
+#include <svxerr.hrc>
+
+SvxErrorHandler::SvxErrorHandler() :
+ SfxErrorHandler(
+ RID_SVXERRCODE, ErrCodeArea::Svx, ErrCodeArea::Svx, SvxResLocale())
+{
+}
+
+void SvxErrorHandler::ensure()
+{
+ static SvxErrorHandler SINGLETON;
+ // coverity[side_effect_free : FALSE] - not actually side-effect-free
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/viewlayoutitem.cxx b/svx/source/items/viewlayoutitem.cxx
new file mode 100644
index 000000000..d923133a1
--- /dev/null
+++ b/svx/source/items/viewlayoutitem.cxx
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/viewlayoutitem.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <osl/diagnose.h>
+
+#include <cassert>
+
+
+SfxPoolItem* SvxViewLayoutItem::CreateDefault() { return new SvxViewLayoutItem; }
+
+constexpr OUStringLiteral VIEWLAYOUT_PARAM_COLUMNS = u"Columns";
+constexpr OUStringLiteral VIEWLAYOUT_PARAM_BOOKMODE = u"BookMode";
+#define VIEWLAYOUT_PARAMS 2
+
+
+SvxViewLayoutItem::SvxViewLayoutItem
+(
+ sal_uInt16 nColumns,
+ bool bBookMode,
+ TypedWhichId<SvxViewLayoutItem> _nWhich
+)
+: SfxUInt16Item( _nWhich, nColumns ),
+ mbBookMode( bBookMode )
+{
+}
+
+
+SvxViewLayoutItem::SvxViewLayoutItem( const SvxViewLayoutItem& rOrig )
+: SfxUInt16Item( rOrig ),
+ mbBookMode( rOrig.IsBookMode() )
+{
+}
+
+
+SvxViewLayoutItem::~SvxViewLayoutItem()
+{
+}
+
+SvxViewLayoutItem* SvxViewLayoutItem::Clone( SfxItemPool * /*pPool*/ ) const
+{
+ return new SvxViewLayoutItem( *this );
+}
+
+bool SvxViewLayoutItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+
+ const SvxViewLayoutItem& rItem = static_cast<const SvxViewLayoutItem&>(rAttr);
+
+ return ( GetValue() == rItem.GetValue() &&
+ mbBookMode == rItem.IsBookMode() );
+}
+
+bool SvxViewLayoutItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch ( nMemberId )
+ {
+ case 0 :
+ {
+ css::uno::Sequence< css::beans::PropertyValue > aSeq{
+ comphelper::makePropertyValue(VIEWLAYOUT_PARAM_COLUMNS, sal_Int32( GetValue() )),
+ comphelper::makePropertyValue(VIEWLAYOUT_PARAM_BOOKMODE, mbBookMode)
+ };
+ assert(aSeq.getLength() == VIEWLAYOUT_PARAMS);
+ rVal <<= aSeq;
+ }
+ break;
+
+ case MID_VIEWLAYOUT_COLUMNS : rVal <<= static_cast<sal_Int32>(GetValue()); break;
+ case MID_VIEWLAYOUT_BOOKMODE: rVal <<= mbBookMode; break;
+ default:
+ OSL_FAIL("svx::SvxViewLayoutItem::QueryValue(), Wrong MemberId!");
+ return false;
+ }
+
+ return true;
+}
+
+bool SvxViewLayoutItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch ( nMemberId )
+ {
+ case 0 :
+ {
+ css::uno::Sequence< css::beans::PropertyValue > aSeq;
+ if (( rVal >>= aSeq ) && ( aSeq.getLength() == VIEWLAYOUT_PARAMS ))
+ {
+ sal_Int32 nColumns( 0 );
+ bool bBookMode = false;
+ bool bAllConverted( true );
+ sal_Int16 nConvertedCount( 0 );
+ for ( const auto& rProp : std::as_const(aSeq) )
+ {
+ if ( rProp.Name == VIEWLAYOUT_PARAM_COLUMNS )
+ {
+ bAllConverted &= ( rProp.Value >>= nColumns );
+ ++nConvertedCount;
+ }
+ else if ( rProp.Name == VIEWLAYOUT_PARAM_BOOKMODE )
+ {
+ bAllConverted &= ( rProp.Value >>= bBookMode );
+ ++nConvertedCount;
+ }
+ }
+
+ if ( bAllConverted && nConvertedCount == VIEWLAYOUT_PARAMS )
+ {
+ SetValue( static_cast<sal_uInt16>(nColumns) );
+ mbBookMode = bBookMode;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ case MID_VIEWLAYOUT_COLUMNS:
+ {
+ sal_Int32 nVal = 0;
+ if ( rVal >>= nVal )
+ {
+ SetValue( static_cast<sal_uInt16>(nVal) );
+ return true;
+ }
+ else
+ return false;
+ }
+
+ case MID_VIEWLAYOUT_BOOKMODE:
+ {
+ bool bBookMode = false;
+ if ( rVal >>= bBookMode )
+ {
+ mbBookMode = bBookMode;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ default:
+ OSL_FAIL("svx::SvxViewLayoutItem::PutValue(), Wrong MemberId!");
+ return false;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/items/zoomslideritem.cxx b/svx/source/items/zoomslideritem.cxx
new file mode 100644
index 000000000..046a03591
--- /dev/null
+++ b/svx/source/items/zoomslideritem.cxx
@@ -0,0 +1,219 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <osl/diagnose.h>
+
+#include <svx/zoomslideritem.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+
+SfxPoolItem* SvxZoomSliderItem::CreateDefault() { return new SvxZoomSliderItem; }
+
+constexpr OUStringLiteral ZOOMSLIDER_PARAM_CURRENTZOOM = u"Columns";
+constexpr OUStringLiteral ZOOMSLIDER_PARAM_SNAPPINGPOINTS = u"SnappingPoints";
+constexpr OUStringLiteral ZOOMSLIDER_PARAM_MINZOOM = u"MinValue";
+constexpr OUStringLiteral ZOOMSLIDER_PARAM_MAXZOOM = u"MaxValue";
+#define ZOOMSLIDER_PARAMS 4
+
+
+SvxZoomSliderItem::SvxZoomSliderItem( sal_uInt16 nCurrentZoom, sal_uInt16 nMinZoom, sal_uInt16 nMaxZoom, TypedWhichId<SvxZoomSliderItem> _nWhich )
+: SfxUInt16Item( _nWhich, nCurrentZoom ), mnMinZoom( nMinZoom ), mnMaxZoom( nMaxZoom )
+{
+}
+
+SvxZoomSliderItem* SvxZoomSliderItem::Clone( SfxItemPool * /*pPool*/ ) const
+{
+ return new SvxZoomSliderItem( *this );
+}
+
+bool SvxZoomSliderItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+
+ const SvxZoomSliderItem& rItem = static_cast<const SvxZoomSliderItem&>(rAttr);
+
+ return ( GetValue() == rItem.GetValue() && maValues == rItem.maValues &&
+ mnMinZoom == rItem.mnMinZoom && mnMaxZoom == rItem.mnMaxZoom );
+}
+
+bool SvxZoomSliderItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch ( nMemberId )
+ {
+ case 0 :
+ {
+ css::uno::Sequence< css::beans::PropertyValue > aSeq{
+ comphelper::makePropertyValue(ZOOMSLIDER_PARAM_CURRENTZOOM, sal_Int32( GetValue() )),
+ comphelper::makePropertyValue(ZOOMSLIDER_PARAM_SNAPPINGPOINTS, maValues),
+ comphelper::makePropertyValue(ZOOMSLIDER_PARAM_MINZOOM, mnMinZoom),
+ comphelper::makePropertyValue(ZOOMSLIDER_PARAM_MAXZOOM, mnMaxZoom)
+ };
+ assert(aSeq.getLength() == ZOOMSLIDER_PARAMS);
+ rVal <<= aSeq;
+ }
+ break;
+
+ case MID_ZOOMSLIDER_CURRENTZOOM :
+ {
+ rVal <<= static_cast<sal_Int32>(GetValue());
+ }
+ break;
+ case MID_ZOOMSLIDER_SNAPPINGPOINTS:
+ {
+ rVal <<= maValues;
+ }
+ break;
+ case MID_ZOOMSLIDER_MINZOOM:
+ {
+ rVal <<= mnMinZoom;
+ }
+ break;
+ case MID_ZOOMSLIDER_MAXZOOM:
+ {
+ rVal <<= mnMaxZoom;
+ }
+ break;
+ default:
+ OSL_FAIL("svx::SvxZoomSliderItem::QueryValue(), Wrong MemberId!");
+ return false;
+ }
+
+ return true;
+}
+
+bool SvxZoomSliderItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch ( nMemberId )
+ {
+ case 0 :
+ {
+ css::uno::Sequence< css::beans::PropertyValue > aSeq;
+ if (( rVal >>= aSeq ) && ( aSeq.getLength() == ZOOMSLIDER_PARAMS ))
+ {
+ sal_Int32 nCurrentZoom( 0 );
+ css::uno::Sequence < sal_Int32 > aValues;
+
+ bool bAllConverted( true );
+ sal_Int16 nConvertedCount( 0 );
+ sal_Int32 nMinZoom( 0 ), nMaxZoom( 0 );
+
+ for ( const auto& rProp : std::as_const(aSeq) )
+ {
+ if ( rProp.Name == ZOOMSLIDER_PARAM_CURRENTZOOM )
+ {
+ bAllConverted &= ( rProp.Value >>= nCurrentZoom );
+ ++nConvertedCount;
+ }
+ else if ( rProp.Name == ZOOMSLIDER_PARAM_SNAPPINGPOINTS )
+ {
+ bAllConverted &= ( rProp.Value >>= aValues );
+ ++nConvertedCount;
+ }
+ else if( rProp.Name == ZOOMSLIDER_PARAM_MINZOOM )
+ {
+ bAllConverted &= ( rProp.Value >>= nMinZoom );
+ ++nConvertedCount;
+ }
+ else if( rProp.Name == ZOOMSLIDER_PARAM_MAXZOOM )
+ {
+ bAllConverted &= ( rProp.Value >>= nMaxZoom );
+ ++nConvertedCount;
+ }
+ }
+
+ if ( bAllConverted && nConvertedCount == ZOOMSLIDER_PARAMS )
+ {
+ SetValue( static_cast<sal_uInt16>(nCurrentZoom) );
+ maValues = aValues;
+ mnMinZoom = sal::static_int_cast< sal_uInt16 >( nMinZoom );
+ mnMaxZoom = sal::static_int_cast< sal_uInt16 >( nMaxZoom );
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ case MID_ZOOMSLIDER_CURRENTZOOM:
+ {
+ sal_Int32 nVal = 0;
+ if ( rVal >>= nVal )
+ {
+ SetValue( static_cast<sal_uInt16>(nVal) );
+ return true;
+ }
+ else
+ return false;
+ }
+
+ case MID_ZOOMSLIDER_SNAPPINGPOINTS:
+ {
+ css::uno::Sequence < sal_Int32 > aValues;
+ if ( rVal >>= aValues )
+ {
+ maValues = aValues;
+ return true;
+ }
+ else
+ return false;
+ }
+ case MID_ZOOMSLIDER_MINZOOM:
+ {
+ sal_Int32 nVal = 0;
+ if( rVal >>= nVal )
+ {
+ mnMinZoom = static_cast<sal_uInt16>(nVal);
+ return true;
+ }
+ else
+ return false;
+ }
+ case MID_ZOOMSLIDER_MAXZOOM:
+ {
+ sal_Int32 nVal = 0;
+ if( rVal >>= nVal )
+ {
+ mnMaxZoom = static_cast<sal_uInt16>(nVal);
+ return true;
+ }
+ else
+ return false;
+ }
+ default:
+ OSL_FAIL("svx::SvxZoomSliderItem::PutValue(), Wrong MemberId!");
+ return false;
+ }
+}
+
+void SvxZoomSliderItem::AddSnappingPoint( sal_Int32 nNew )
+{
+ const sal_Int32 nValues = maValues.getLength();
+ maValues.realloc( nValues + 1 );
+ sal_Int32* pValues = maValues.getArray();
+ pValues[ nValues ] = nNew;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/mnuctrls/clipboardctl.cxx b/svx/source/mnuctrls/clipboardctl.cxx
new file mode 100644
index 000000000..1633561a5
--- /dev/null
+++ b/svx/source/mnuctrls/clipboardctl.cxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <svl/intitem.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/weldutils.hxx>
+#include <svx/clipboardctl.hxx>
+#include <svx/clipfmtitem.hxx>
+
+#include <svtools/insdlg.hxx>
+#include <svx/svxids.hrc>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxClipBoardControl, SfxVoidItem /*SfxUInt16Item*/ );
+
+
+SvxClipBoardControl::SvxClipBoardControl(
+ sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+
+ SfxToolBoxControl( nSlotId, nId, rTbx ),
+ bDisabled( false )
+{
+ addStatusListener( ".uno:ClipboardFormatItems");
+ ToolBox& rBox = GetToolBox();
+ rBox.SetItemBits( nId, ToolBoxItemBits::DROPDOWN | rBox.GetItemBits( nId ) );
+ rBox.Invalidate();
+}
+
+SvxClipBoardControl::~SvxClipBoardControl()
+{
+}
+
+void SvxClipBoardControl::CreatePopupWindow()
+{
+ const SvxClipboardFormatItem* pFmtItem = dynamic_cast<SvxClipboardFormatItem*>( pClipboardFmtItem.get() );
+ if ( pFmtItem )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "svx/ui/clipboardmenu.ui"));
+ std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("menu"));
+
+ sal_uInt16 nCount = pFmtItem->Count();
+ for (sal_uInt16 i = 0; i < nCount; ++i)
+ {
+ SotClipboardFormatId nFmtID = pFmtItem->GetClipbrdFormatId( i );
+ OUString aFmtStr( pFmtItem->GetClipbrdFormatName( i ) );
+ if (aFmtStr.isEmpty())
+ aFmtStr = SvPasteObjectHelper::GetSotFormatUIName( nFmtID );
+ xPopup->append(OUString::number(static_cast<sal_uInt32>(nFmtID)), aFmtStr);
+ }
+
+ ToolBox& rBox = GetToolBox();
+ ToolBoxItemId nId = GetId();
+ rBox.SetItemDown( nId, true );
+
+ ::tools::Rectangle aRect(rBox.GetItemRect(nId));
+ weld::Window* pParent = weld::GetPopupParent(rBox, aRect);
+ OString sResult = xPopup->popup_at_rect(pParent, aRect);
+
+ rBox.SetItemDown( nId, false );
+
+ SfxUInt32Item aItem(SID_CLIPBOARD_FORMAT_ITEMS, sResult.toUInt32());
+
+ Any a;
+ aItem.QueryValue( a );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("SelectedFormat", a) };
+ Dispatch( ".uno:ClipboardFormatItems",
+ aArgs );
+ }
+
+ GetToolBox().EndSelection();
+}
+
+void SvxClipBoardControl::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
+{
+ if ( SID_CLIPBOARD_FORMAT_ITEMS == nSID )
+ {
+ pClipboardFmtItem.reset();
+ if ( eState >= SfxItemState::DEFAULT )
+ {
+ pClipboardFmtItem.reset( pState->Clone() );
+ GetToolBox().SetItemBits( GetId(), GetToolBox().GetItemBits( GetId() ) | ToolBoxItemBits::DROPDOWN );
+ }
+ else if ( !bDisabled )
+ GetToolBox().SetItemBits( GetId(), GetToolBox().GetItemBits( GetId() ) & ~ToolBoxItemBits::DROPDOWN );
+ GetToolBox().Invalidate( GetToolBox().GetItemRect( GetId() ) );
+ }
+ else
+ {
+ // enable the item as a whole
+ bDisabled = (GetItemState(pState) == SfxItemState::DISABLED);
+ GetToolBox().EnableItem( GetId(), (GetItemState(pState) != SfxItemState::DISABLED) );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/mnuctrls/smarttagmenu.cxx b/svx/source/mnuctrls/smarttagmenu.cxx
new file mode 100644
index 000000000..86f11e8d0
--- /dev/null
+++ b/svx/source/mnuctrls/smarttagmenu.cxx
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <svtools/popupmenucontrollerbase.hxx>
+#include <svx/SmartTagItem.hxx>
+#include <toolkit/awt/vclxmenu.hxx>
+#include <vcl/commandinfoprovider.hxx>
+
+const sal_uInt16 MN_ST_INSERT_START = 500;
+
+namespace {
+
+class SmartTagMenuController : public svt::PopupMenuControllerBase
+{
+public:
+ explicit SmartTagMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+
+ // XMenuListener
+ virtual void SAL_CALL itemSelected( const css::awt::MenuEvent& rEvent ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+private:
+ void FillMenu();
+ bool MenuSelect(sal_uInt16 nMyId);
+ struct InvokeAction
+ {
+ css::uno::Reference< css::smarttags::XSmartTagAction > m_xAction;
+ css::uno::Reference< css::container::XStringKeyMap > m_xSmartTagProperties;
+ sal_uInt32 m_nActionID;
+ InvokeAction( css::uno::Reference< css::smarttags::XSmartTagAction > const & xAction,
+ css::uno::Reference< css::container::XStringKeyMap > const & xSmartTagProperties,
+ sal_uInt32 nActionID ) : m_xAction( xAction ), m_xSmartTagProperties( xSmartTagProperties ), m_nActionID( nActionID ) {}
+ };
+ std::vector< InvokeAction > m_aInvokeActions;
+ std::unique_ptr< const SvxSmartTagItem > m_pSmartTagItem;
+};
+
+}
+
+SmartTagMenuController::SmartTagMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext )
+ : svt::PopupMenuControllerBase( rxContext )
+{
+}
+
+void SmartTagMenuController::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ resetPopupMenu( m_xPopupMenu );
+
+ css::uno::Sequence< css::beans::PropertyValue > aProperties;
+ if ( !rEvent.IsEnabled || !( rEvent.State >>= aProperties ) )
+ return;
+
+ css::uno::Sequence< css::uno::Sequence< css::uno::Reference< css::smarttags::XSmartTagAction > > > aActionComponents;
+ css::uno::Sequence< css::uno::Sequence< sal_Int32 > > aActionIndices;
+ css::uno::Sequence< css::uno::Reference< css::container::XStringKeyMap > > aStringKeyMaps;
+ css::uno::Reference< css::text::XTextRange > xTextRange;
+ css::uno::Reference< css::frame::XController > xController;
+ css::lang::Locale aLocale;
+ OUString aApplicationName;
+ OUString aRangeText;
+
+ for ( const auto& aProperty : std::as_const(aProperties) )
+ {
+ if ( aProperty.Name == "ActionComponents" )
+ aProperty.Value >>= aActionComponents;
+ else if ( aProperty.Name == "ActionIndices" )
+ aProperty.Value >>= aActionIndices;
+ else if ( aProperty.Name == "StringKeyMaps" )
+ aProperty.Value >>= aStringKeyMaps;
+ else if ( aProperty.Name == "TextRange" )
+ aProperty.Value >>= xTextRange;
+ else if ( aProperty.Name == "Controller" )
+ aProperty.Value >>= xController;
+ else if ( aProperty.Name == "Locale" )
+ aProperty.Value >>= aLocale;
+ else if ( aProperty.Name == "ApplicationName" )
+ aProperty.Value >>= aApplicationName;
+ else if ( aProperty.Name == "RangeText" )
+ aProperty.Value >>= aRangeText;
+ }
+ m_pSmartTagItem.reset( new SvxSmartTagItem( TypedWhichId<SvxSmartTagItem>(0), aActionComponents, aActionIndices, aStringKeyMaps, xTextRange, xController, aLocale, aApplicationName, aRangeText ) );
+ FillMenu();
+}
+
+void SmartTagMenuController::FillMenu()
+{
+ if ( !m_pSmartTagItem )
+ return;
+
+ sal_uInt16 nMenuId = 1;
+ sal_uInt16 nSubMenuId = MN_ST_INSERT_START;
+
+ const css::uno::Sequence< css::uno::Sequence< css::uno::Reference< css::smarttags::XSmartTagAction > > >& rActionComponentsSequence = m_pSmartTagItem->GetActionComponentsSequence();
+ const css::uno::Sequence< css::uno::Sequence< sal_Int32 > >& rActionIndicesSequence = m_pSmartTagItem->GetActionIndicesSequence();
+ const css::uno::Sequence< css::uno::Reference< css::container::XStringKeyMap > >& rStringKeyMaps = m_pSmartTagItem->GetStringKeyMaps();
+ const css::lang::Locale& rLocale = m_pSmartTagItem->GetLocale();
+ const OUString aApplicationName = m_pSmartTagItem->GetApplicationName();
+ const OUString aRangeText = m_pSmartTagItem->GetRangeText();
+ const css::uno::Reference< css::text::XTextRange >& xTextRange = m_pSmartTagItem->GetTextRange();
+ const css::uno::Reference< css::frame::XController >& xController = m_pSmartTagItem->GetController();
+
+ for ( sal_Int32 i = 0; i < rActionComponentsSequence.getLength(); ++i )
+ {
+ css::uno::Reference< css::container::XStringKeyMap > xSmartTagProperties = rStringKeyMaps[i];
+
+ // Get all actions references associated with the current smart tag type
+ const css::uno::Sequence< css::uno::Reference< css::smarttags::XSmartTagAction > >& rActionComponents = rActionComponentsSequence[i];
+ const css::uno::Sequence< sal_Int32 >& rActionIndices = rActionIndicesSequence[i];
+
+ if ( !rActionComponents.hasElements() || !rActionIndices.hasElements() )
+ continue;
+
+ // Ask first entry for the smart tag type caption
+ css::uno::Reference< css::smarttags::XSmartTagAction > xFirstAction = rActionComponents[0];
+
+ if ( !xFirstAction.is() )
+ continue;
+
+ const sal_Int32 nSmartTagIndex = rActionIndices[0];
+ const OUString aSmartTagType = xFirstAction->getSmartTagName( nSmartTagIndex );
+ const OUString aSmartTagCaption = xFirstAction->getSmartTagCaption( nSmartTagIndex, rLocale );
+
+ // No sub-menus if there's only one smart tag type listed
+ css::uno::Reference<css::awt::XPopupMenu> xSubMenu = m_xPopupMenu;
+ if ( 1 < rActionComponentsSequence.getLength() )
+ {
+ m_xPopupMenu->insertItem(nMenuId, aSmartTagCaption, 0, -1);
+ xSubMenu.set(new VCLXPopupMenu);
+ m_xPopupMenu->setPopupMenu(nMenuId++, xSubMenu);
+ }
+
+ // Sub-menu starts with smart tag caption and separator
+ const OUString aSmartTagCaption2 = aSmartTagCaption + ": " + aRangeText;
+ xSubMenu->insertItem(nMenuId++, aSmartTagCaption2, static_cast<sal_Int16>(MenuItemBits::NOSELECT), -1);
+ xSubMenu->insertSeparator(-1);
+
+ // Add subitem for every action reference for the current smart tag type
+ for ( const auto& xAction : rActionComponents )
+ {
+ for ( sal_Int32 j = 0; j < xAction->getActionCount( aSmartTagType, xController, xSmartTagProperties ); ++j )
+ {
+ const sal_uInt32 nActionID = xAction->getActionID( aSmartTagType, j, xController );
+ OUString aActionCaption = xAction->getActionCaptionFromID( nActionID,
+ aApplicationName,
+ rLocale,
+ xSmartTagProperties,
+ aRangeText,
+ OUString(),
+ xController,
+ xTextRange );
+
+ xSubMenu->insertItem(nSubMenuId++, aActionCaption, 0, -1);
+ InvokeAction aEntry( xAction, xSmartTagProperties, nActionID );
+ m_aInvokeActions.push_back( aEntry );
+ }
+ }
+ }
+
+ sal_Int16 nItemCount = m_xPopupMenu->getItemCount();
+ if (nItemCount > 0)
+ {
+ static const OUStringLiteral aCommand = u".uno:AutoCorrectDlg?OpenSmartTag:bool=true";
+ m_xPopupMenu->insertSeparator(nItemCount++);
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommand, m_aModuleName);
+ m_xPopupMenu->insertItem(nMenuId, vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties),
+ 0, nItemCount);
+ m_xPopupMenu->setCommand(nMenuId, aCommand);
+ }
+}
+
+void SmartTagMenuController::itemSelected(const css::awt::MenuEvent& rEvent)
+{
+ if (MenuSelect(rEvent.MenuId))
+ return;
+ svt::PopupMenuControllerBase::itemSelected(rEvent);
+}
+
+bool SmartTagMenuController::MenuSelect(sal_uInt16 nMyId)
+{
+ if ( !m_pSmartTagItem )
+ return false;
+
+ if ( nMyId < MN_ST_INSERT_START )
+ return false;
+
+ nMyId -= MN_ST_INSERT_START;
+
+ // Compute SmartTag lib index and action index
+ css::uno::Reference< css::smarttags::XSmartTagAction > xSmartTagAction = m_aInvokeActions[nMyId].m_xAction;
+
+ if (!xSmartTagAction.is())
+ return false;
+
+ // Execute action
+ xSmartTagAction->invokeAction( m_aInvokeActions[nMyId].m_nActionID,
+ m_pSmartTagItem->GetApplicationName(),
+ m_pSmartTagItem->GetController(),
+ m_pSmartTagItem->GetTextRange(),
+ m_aInvokeActions[nMyId].m_xSmartTagProperties,
+ m_pSmartTagItem->GetRangeText(),
+ OUString(),
+ m_pSmartTagItem->GetLocale() );
+
+ return true;
+}
+
+OUString SmartTagMenuController::getImplementationName()
+{
+ return "com.sun.star.comp.svx.SmartTagMenuController";
+}
+
+css::uno::Sequence< OUString > SmartTagMenuController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.PopupMenuController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_SmartTagMenuController_get_implementation(
+ css::uno::XComponentContext* xContext,
+ css::uno::Sequence< css::uno::Any > const & )
+{
+ return cppu::acquire( new SmartTagMenuController( xContext ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/animation/animationstate.cxx b/svx/source/sdr/animation/animationstate.cxx
new file mode 100644
index 000000000..074f2082e
--- /dev/null
+++ b/svx/source/sdr/animation/animationstate.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/animation/animationstate.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/animation/objectanimator.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
+#include <drawinglayer/animation/animationtiming.hxx>
+#include <comphelper/lok.hxx>
+
+
+namespace sdr::animation
+{
+ double PrimitiveAnimation::getSmallestNextTime(double fCurrentTime)
+ {
+ double fRetval(0.0);
+
+ if(!maAnimatedPrimitives.empty())
+ {
+ const sal_Int32 nCount(maAnimatedPrimitives.size());
+
+ for(sal_Int32 a(0); a < nCount; a++)
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xRef(maAnimatedPrimitives[a]);
+ const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D* pCandidate = static_cast< const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D* >(xRef.get());
+
+ const drawinglayer::animation::AnimationEntry& rAnimEntry = pCandidate->getAnimationEntry();
+ const double fNextTime(rAnimEntry.getNextEventTime(fCurrentTime));
+
+ if(!::basegfx::fTools::equalZero(fNextTime))
+ {
+ if(::basegfx::fTools::equalZero(fRetval))
+ {
+ fRetval = fNextTime;
+ }
+ else if(::basegfx::fTools::less(fNextTime, fRetval))
+ {
+ fRetval = fNextTime;
+ }
+ }
+ }
+ }
+
+ return fRetval;
+ }
+
+ void PrimitiveAnimation::prepareNextEvent()
+ {
+ const double fCurrentTime(mrVOContact.GetObjectContact().getPrimitiveAnimator().GetTime());
+ const double fNextTime(getSmallestNextTime(fCurrentTime));
+
+ // getSmallestNextTime will be zero when animation ended. If not zero, a next step
+ // exists
+ if(::basegfx::fTools::equalZero(fNextTime))
+ return;
+
+ // next time point exists, use it
+ sal_uInt32 nNextTime;
+
+ if(fNextTime >= double(0xffffff00))
+ {
+ // take care for very late points in time, e.g. when a text animation stops
+ // in a defined AnimationEntryFixed with endless (0xffffffff) duration
+ nNextTime = GetTime() + (1000 * 60 * 60); // one hour, works with vcl timers, 0xffffff00 was too much...
+ }
+ else
+ {
+ nNextTime = static_cast<sal_uInt32>(fNextTime);
+ }
+
+ // ensure step forward in integer timing, the floating step difference maybe smaller than 1.0. Use
+ // at least 25ms for next step
+ const sal_uInt32 nMinimumStepTime(static_cast<sal_uInt32>(fCurrentTime) + 25);
+
+ if(nNextTime <= nMinimumStepTime)
+ {
+ nNextTime = nMinimumStepTime;
+ }
+
+ // set time and reactivate by re-adding to the scheduler
+ SetTime(nNextTime);
+ mrVOContact.GetObjectContact().getPrimitiveAnimator().InsertEvent(*this);
+ }
+
+ PrimitiveAnimation::PrimitiveAnimation(sdr::contact::ViewObjectContact& rVOContact, drawinglayer::primitive2d::Primitive2DContainer&& rAnimatedPrimitives)
+ : mrVOContact(rVOContact),
+ maAnimatedPrimitives(std::move(rAnimatedPrimitives))
+ {
+ if (!comphelper::LibreOfficeKit::isActive())
+ // setup initially
+ prepareNextEvent();
+ }
+
+ PrimitiveAnimation::~PrimitiveAnimation()
+ {
+ // ensure that Event member is removed from PrimitiveAnimator
+ mrVOContact.GetObjectContact().getPrimitiveAnimator().RemoveEvent(this);
+ }
+
+ // execute event, from base class Event
+ void PrimitiveAnimation::Trigger(sal_uInt32 /*nTime*/)
+ {
+ // schedule a repaint of associated object
+ mrVOContact.ActionChanged();
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ // re-setup
+ prepareNextEvent();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/animation/objectanimator.cxx b/svx/source/sdr/animation/objectanimator.cxx
new file mode 100644
index 000000000..aad545fd7
--- /dev/null
+++ b/svx/source/sdr/animation/objectanimator.cxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/animation/objectanimator.hxx>
+
+
+namespace sdr::animation
+{
+ primitiveAnimator::primitiveAnimator()
+ {
+ }
+
+ primitiveAnimator::~primitiveAnimator()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/animation/scheduler.cxx b/svx/source/sdr/animation/scheduler.cxx
new file mode 100644
index 000000000..d4451c099
--- /dev/null
+++ b/svx/source/sdr/animation/scheduler.cxx
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/animation/scheduler.hxx>
+
+#include <algorithm>
+#include <vector>
+
+
+// event class
+
+namespace sdr::animation
+{
+ Event::Event() : mnTime(0)
+ {
+ }
+
+ Event::~Event()
+ {
+ }
+
+
+ void Event::SetTime(sal_uInt32 nNew)
+ {
+ if(mnTime != nNew)
+ {
+ mnTime = nNew;
+ }
+ }
+
+ Scheduler::Scheduler()
+ : Timer("sdr::animation::Scheduler"),
+ mnTime(0),
+ mnDeltaTime(0),
+ mbIsPaused(false)
+ {
+ SetPriority(TaskPriority::POST_PAINT);
+ }
+
+ Scheduler::~Scheduler()
+ {
+ Stop();
+ }
+
+ void Scheduler::Invoke()
+ {
+ // stop timer and add time
+ Stop();
+ mnTime += mnDeltaTime;
+
+ // execute events
+ triggerEvents();
+
+ // re-start or stop timer according to event list
+ checkTimeout();
+ }
+
+ void Scheduler::triggerEvents()
+ {
+ if (mvEvents.empty())
+ return;
+
+ // copy events which need to be executed to a vector. Remove them from
+ // the scheduler
+ ::std::vector< Event* > aToBeExecutedList;
+
+ while(!mvEvents.empty() && mvEvents.front()->GetTime() <= mnTime)
+ {
+ Event* pNextEvent = mvEvents.front();
+ mvEvents.erase(mvEvents.begin());
+ aToBeExecutedList.push_back(pNextEvent);
+ }
+
+ // execute events from the vector
+ for(auto& rpCandidate : aToBeExecutedList)
+ {
+ // trigger event. This may re-insert the event to the scheduler again
+ rpCandidate->Trigger(mnTime);
+ }
+ }
+
+ void Scheduler::checkTimeout()
+ {
+ // re-start or stop timer according to event list
+ if(!IsPaused() && !mvEvents.empty())
+ {
+ mnDeltaTime = mvEvents.front()->GetTime() - mnTime;
+
+ if(0 != mnDeltaTime)
+ {
+ SetTimeout(mnDeltaTime);
+ Start();
+ }
+ }
+ else
+ {
+ Stop();
+ }
+ }
+
+
+ // #i38135#
+ void Scheduler::SetTime(sal_uInt32 nTime)
+ {
+ // reset time
+ Stop();
+ mnTime = nTime;
+
+ if (mvEvents.empty())
+ return;
+
+ // reset event time points
+ for (auto & rEvent : mvEvents)
+ {
+ rEvent->SetTime(nTime);
+ }
+
+ if(!IsPaused())
+ {
+ // without delta time, init events by triggering them. This will invalidate
+ // painted objects and add them to the scheduler again
+ mnDeltaTime = 0;
+ triggerEvents();
+ checkTimeout();
+ }
+ }
+
+ void Scheduler::InsertEvent(Event& rNew)
+ {
+ // insert maintaining time ordering
+ auto it = std::find_if(mvEvents.begin(), mvEvents.end(),
+ [&rNew](const Event* pEvent) { return rNew.GetTime() < pEvent->GetTime(); });
+ mvEvents.insert(it, &rNew);
+ checkTimeout();
+ }
+
+ void Scheduler::RemoveEvent(Event* pOld)
+ {
+ if(!mvEvents.empty())
+ {
+ mvEvents.erase(std::remove(mvEvents.begin(), mvEvents.end(), pOld), mvEvents.end());
+ checkTimeout();
+ }
+ }
+
+ void Scheduler::SetPaused(bool bNew)
+ {
+ if(bNew != mbIsPaused)
+ {
+ mbIsPaused = bNew;
+ checkTimeout();
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrallfillattributeshelper.cxx b/svx/source/sdr/attribute/sdrallfillattributeshelper.cxx
new file mode 100644
index 000000000..261eef295
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrallfillattributeshelper.cxx
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/attribute/fillhatchattribute.hxx>
+#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx>
+#include <vcl/graph.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer::attribute
+{
+ void SdrAllFillAttributesHelper::createPrimitive2DSequence(
+ const basegfx::B2DRange& rPaintRange,
+ const basegfx::B2DRange& rDefineRange)
+ {
+ // reset and remember new target range for object geometry
+ maLastPaintRange = rPaintRange;
+ maLastDefineRange = rDefineRange;
+
+ if(isUsed())
+ {
+ maPrimitives.resize(1);
+ maPrimitives[0] = drawinglayer::primitive2d::createPolyPolygonFillPrimitive(
+ basegfx::B2DPolyPolygon(
+ basegfx::utils::createPolygonFromRect(
+ maLastPaintRange)),
+ maLastDefineRange,
+ maFillAttribute ? *maFillAttribute : drawinglayer::attribute::SdrFillAttribute(),
+ maFillGradientAttribute ? *maFillGradientAttribute : drawinglayer::attribute::FillGradientAttribute());
+ }
+ }
+
+ SdrAllFillAttributesHelper::SdrAllFillAttributesHelper(const Color& rColor)
+ {
+ maFillAttribute = drawinglayer::attribute::SdrFillAttribute(
+ 0.0,
+ rColor.GetRGBColor().getBColor(),
+ drawinglayer::attribute::FillGradientAttribute(),
+ drawinglayer::attribute::FillHatchAttribute(),
+ drawinglayer::attribute::SdrFillGraphicAttribute());
+ }
+
+ SdrAllFillAttributesHelper::SdrAllFillAttributesHelper(const SfxItemSet& rSet)
+ : maFillAttribute(
+ drawinglayer::primitive2d::createNewSdrFillAttribute(rSet)),
+ maFillGradientAttribute(
+ drawinglayer::primitive2d::createNewTransparenceGradientAttribute(rSet))
+ {
+ }
+
+ SdrAllFillAttributesHelper::~SdrAllFillAttributesHelper()
+ {
+ }
+
+ bool SdrAllFillAttributesHelper::isUsed() const
+ {
+ // only depends on fill, FillGradientAttribute alone defines no fill
+ return maFillAttribute && !maFillAttribute->isDefault();
+ }
+
+ bool SdrAllFillAttributesHelper::isTransparent() const
+ {
+ if(hasSdrFillAttribute() && 0.0 != maFillAttribute->getTransparence())
+ {
+ return true;
+ }
+
+ if(maFillGradientAttribute && !maFillGradientAttribute->isDefault())
+ {
+ return true;
+ }
+
+ if(hasSdrFillAttribute())
+ {
+ const Graphic& rGraphic = getFillAttribute().getFillGraphic().getFillGraphic();
+
+ return rGraphic.IsSupportedGraphic() && rGraphic.IsTransparent();
+ }
+
+ return false;
+ }
+
+ const drawinglayer::attribute::SdrFillAttribute& SdrAllFillAttributesHelper::getFillAttribute() const
+ {
+ if(!maFillAttribute)
+ {
+ const_cast< SdrAllFillAttributesHelper* >(this)->maFillAttribute.emplace();
+ }
+
+ return *maFillAttribute;
+ }
+
+ const drawinglayer::attribute::FillGradientAttribute& SdrAllFillAttributesHelper::getFillGradientAttribute() const
+ {
+ if(!maFillGradientAttribute)
+ {
+ const_cast< SdrAllFillAttributesHelper* >(this)->maFillGradientAttribute.emplace();
+ }
+
+ return *maFillGradientAttribute;
+ }
+
+ const drawinglayer::primitive2d::Primitive2DContainer& SdrAllFillAttributesHelper::getPrimitive2DSequence(
+ const basegfx::B2DRange& rPaintRange,
+ const basegfx::B2DRange& rDefineRange) const
+ {
+ if(!maPrimitives.empty() && (maLastPaintRange != rPaintRange || maLastDefineRange != rDefineRange))
+ {
+ const_cast< SdrAllFillAttributesHelper* >(this)->maPrimitives.clear();
+ }
+
+ if(maPrimitives.empty())
+ {
+ const_cast< SdrAllFillAttributesHelper* >(this)->createPrimitive2DSequence(rPaintRange, rDefineRange);
+ }
+
+ return maPrimitives;
+ }
+
+ basegfx::BColor SdrAllFillAttributesHelper::getAverageColor(const basegfx::BColor& rFallback) const
+ {
+ basegfx::BColor aRetval(rFallback);
+
+ if(maFillAttribute && !maFillAttribute->isDefault())
+ {
+ const drawinglayer::attribute::FillGradientAttribute& rFillGradientAttribute = maFillAttribute->getGradient();
+ const drawinglayer::attribute::FillHatchAttribute& rFillHatchAttribute = maFillAttribute->getHatch();
+ const drawinglayer::attribute::SdrFillGraphicAttribute& rSdrFillGraphicAttribute = maFillAttribute->getFillGraphic();
+ const drawinglayer::attribute::FillGradientAttribute& rFillTransparenceGradientAttribute = getFillGradientAttribute();
+ double fTransparence(maFillAttribute->getTransparence());
+
+ if(!rFillTransparenceGradientAttribute.isDefault())
+ {
+ const double fTransA = rFillTransparenceGradientAttribute.getStartColor().luminance();
+ const double fTransB = rFillTransparenceGradientAttribute.getEndColor().luminance();
+
+ fTransparence = (fTransA + fTransB) * 0.5;
+ }
+
+ if(!rFillGradientAttribute.isDefault())
+ {
+ // gradient fill
+ const basegfx::BColor& rStart = rFillGradientAttribute.getStartColor();
+ const basegfx::BColor& rEnd = rFillGradientAttribute.getEndColor();
+
+ aRetval = basegfx::interpolate(rStart, rEnd, 0.5);
+ }
+ else if(!rFillHatchAttribute.isDefault())
+ {
+ // hatch fill
+ const basegfx::BColor& rColor = rFillHatchAttribute.getColor();
+
+ if(rFillHatchAttribute.isFillBackground())
+ {
+ const basegfx::BColor& rBackgroundColor = maFillAttribute->getColor();
+
+ // mix colors 50%/50%
+ aRetval = basegfx::interpolate(rColor, rBackgroundColor, 0.5);
+ }
+ else
+ {
+ // mix color with fallback color
+ aRetval = basegfx::interpolate(rColor, rFallback, 0.5);
+ }
+ }
+ else if(!rSdrFillGraphicAttribute.isDefault())
+ {
+ // graphic fill
+
+ // not used yet by purpose (see SwPageFrm::GetDrawBackgrdColor()),
+ // use fallback (already set)
+ }
+ else
+ {
+ // color fill
+ aRetval = maFillAttribute->getColor();
+ }
+
+ if(!basegfx::fTools::equalZero(fTransparence))
+ {
+ // blend into transparency
+ aRetval = basegfx::interpolate(aRetval, rFallback, fTransparence);
+ }
+ }
+
+ return aRetval.clamp();
+ }
+
+ bool SdrAllFillAttributesHelper::needCompleteRepaint() const
+ {
+ if(!isUsed() || !hasSdrFillAttribute())
+ {
+ // not used or no fill
+ return false;
+ }
+
+ const drawinglayer::attribute::SdrFillAttribute& rSdrFillAttribute = getFillAttribute();
+
+ if(!rSdrFillAttribute.getHatch().isDefault())
+ {
+ // hatch is always top-left aligned, needs no full refreshes
+ return false;
+ }
+
+ if(!rSdrFillAttribute.getGradient().isDefault())
+ {
+ // gradients always scale with the object
+ return true;
+ }
+
+ if(!rSdrFillAttribute.getFillGraphic().isDefault())
+ {
+ // some graphic constellations may not need this, but since most do
+ // (stretch to fill, all but top-left aligned, ...) claim to do by default
+ return true;
+ }
+
+ // color fill
+ return false;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdreffectstextattribute.cxx b/svx/source/sdr/attribute/sdreffectstextattribute.cxx
new file mode 100644
index 000000000..3287b8c8e
--- /dev/null
+++ b/svx/source/sdr/attribute/sdreffectstextattribute.cxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdreffectstextattribute.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ SdrEffectsTextAttribute::SdrEffectsTextAttribute(
+ const SdrShadowAttribute& rShadow,
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow,
+ sal_Int32 nSoftEdgeRadius)
+ : maShadow(rShadow),
+ maTextAttribute(rTextAttribute),
+ maGlow(rGlow),
+ mnSoftEdgeRadius(nSoftEdgeRadius)
+ {
+ }
+
+ SdrEffectsTextAttribute::SdrEffectsTextAttribute()
+ {
+ }
+
+ SdrEffectsTextAttribute::SdrEffectsTextAttribute(const SdrEffectsTextAttribute& rCandidate)
+ : maShadow(rCandidate.getShadow()),
+ maTextAttribute(rCandidate.getText()),
+ maGlow(rCandidate.maGlow),
+ mnSoftEdgeRadius(rCandidate.mnSoftEdgeRadius)
+ {
+ }
+
+ SdrEffectsTextAttribute& SdrEffectsTextAttribute::operator=(const SdrEffectsTextAttribute& rCandidate)
+ {
+ maShadow = rCandidate.getShadow();
+ maTextAttribute = rCandidate.getText();
+ maGlow = rCandidate.maGlow;
+ mnSoftEdgeRadius = rCandidate.mnSoftEdgeRadius;
+
+ return *this;
+ }
+
+ bool SdrEffectsTextAttribute::isDefault() const
+ {
+ return (getShadow().isDefault()
+ && getText().isDefault() && maGlow.isDefault() && getSoftEdgeRadius() == 0);
+ }
+
+ bool SdrEffectsTextAttribute::operator==(const SdrEffectsTextAttribute& rCandidate) const
+ {
+ return (getShadow() == rCandidate.getShadow()
+ && getText() == rCandidate.getText()
+ && getGlow() == rCandidate.getGlow()
+ && getSoftEdgeRadius() == rCandidate.getSoftEdgeRadius());
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrfilltextattribute.cxx b/svx/source/sdr/attribute/sdrfilltextattribute.cxx
new file mode 100644
index 000000000..01593c982
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrfilltextattribute.cxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdrfilltextattribute.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ SdrFillTextAttribute::SdrFillTextAttribute(
+ const SdrFillAttribute& rFill,
+ const FillGradientAttribute& rFillFloatTransGradient,
+ const SdrTextAttribute& rTextAttribute)
+ : maFill(rFill),
+ maFillFloatTransGradient(rFillFloatTransGradient),
+ maTextAttribute(rTextAttribute)
+ {
+ }
+
+ SdrFillTextAttribute::SdrFillTextAttribute()
+ {
+ }
+
+ SdrFillTextAttribute::SdrFillTextAttribute(const SdrFillTextAttribute& rCandidate)
+ : maFill(rCandidate.getFill()),
+ maFillFloatTransGradient(rCandidate.getFillFloatTransGradient()),
+ maTextAttribute(rCandidate.getText())
+ {
+ }
+
+ SdrFillTextAttribute& SdrFillTextAttribute::operator=(const SdrFillTextAttribute& rCandidate)
+ {
+ maFill = rCandidate.getFill();
+ maFillFloatTransGradient = rCandidate.getFillFloatTransGradient();
+ maTextAttribute = rCandidate.getText();
+
+ return *this;
+ }
+
+ bool SdrFillTextAttribute::operator==(const SdrFillTextAttribute& rCandidate) const
+ {
+ return(getFill() == rCandidate.getFill()
+ && getFillFloatTransGradient() == rCandidate.getFillFloatTransGradient()
+ && getText() == rCandidate.getText());
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrformtextattribute.cxx b/svx/source/sdr/attribute/sdrformtextattribute.cxx
new file mode 100644
index 000000000..69fff8a8d
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrformtextattribute.cxx
@@ -0,0 +1,372 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/attribute/sdrformtextattribute.hxx>
+#include <basegfx/vector/b2enums.hxx>
+#include <svl/itemset.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/svddef.hxx>
+#include <svx/xftdiit.hxx>
+#include <svx/xftstit.hxx>
+#include <svx/xftshxy.hxx>
+#include <xftshtit.hxx>
+#include <svx/xtextit0.hxx>
+#include <svx/xftadit.hxx>
+#include <svx/xftshit.hxx>
+#include <svx/xftshcit.hxx>
+#include <svx/xftmrit.hxx>
+#include <svx/xftouit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xdash.hxx>
+#include <svx/xlndsit.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+#include <sdr/attribute/sdrformtextoutlineattribute.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+
+
+// helper to get line, stroke and transparence attributes from SfxItemSet
+
+namespace
+{
+ basegfx::B2DLineJoin impGetB2DLineJoin(css::drawing::LineJoint eLineJoint)
+ {
+ switch(eLineJoint)
+ {
+ case css::drawing::LineJoint_BEVEL :
+ {
+ return basegfx::B2DLineJoin::Bevel;
+ }
+ case css::drawing::LineJoint_MIDDLE :
+ case css::drawing::LineJoint_MITER :
+ {
+ return basegfx::B2DLineJoin::Miter;
+ }
+ case css::drawing::LineJoint_ROUND :
+ {
+ return basegfx::B2DLineJoin::Round;
+ }
+ default : // css::drawing::LineJoint_NONE
+ {
+ return basegfx::B2DLineJoin::NONE; // XLINEJOINT_NONE
+ }
+ }
+ }
+
+ sal_uInt8 impGetStrokeTransparence(bool bShadow, const SfxItemSet& rSet)
+ {
+ sal_uInt8 nRetval;
+
+ if(bShadow)
+ {
+ nRetval = static_cast<sal_uInt8>((rSet.Get(SDRATTR_SHADOWTRANSPARENCE).GetValue() * 255) / 100);
+ }
+ else
+ {
+ nRetval = static_cast<sal_uInt8>((rSet.Get(XATTR_LINETRANSPARENCE).GetValue() * 255) / 100);
+ }
+
+ return nRetval;
+ }
+
+ drawinglayer::attribute::LineAttribute impGetLineAttribute(bool bShadow, const SfxItemSet& rSet)
+ {
+ basegfx::BColor aColorAttribute;
+
+ if(bShadow)
+ {
+ const Color aShadowColor(rSet.Get(SDRATTR_SHADOWCOLOR).GetColorValue());
+ aColorAttribute = aShadowColor.getBColor();
+ }
+ else
+ {
+ const Color aLineColor(rSet.Get(XATTR_LINECOLOR).GetColorValue());
+ aColorAttribute = aLineColor.getBColor();
+ }
+
+ const sal_uInt32 nLineWidth = rSet.Get(XATTR_LINEWIDTH).GetValue();
+ const css::drawing::LineJoint eLineJoint = rSet.Get(XATTR_LINEJOINT).GetValue();
+ const css::drawing::LineCap eLineCap = rSet.Get(XATTR_LINECAP).GetValue();
+
+ return drawinglayer::attribute::LineAttribute(
+ aColorAttribute,
+ static_cast<double>(nLineWidth),
+ impGetB2DLineJoin(eLineJoint),
+ eLineCap);
+ }
+
+ drawinglayer::attribute::StrokeAttribute impGetStrokeAttribute(const SfxItemSet& rSet)
+ {
+ const css::drawing::LineStyle eLineStyle = rSet.Get(XATTR_LINESTYLE).GetValue();
+ double fFullDotDashLen(0.0);
+ ::std::vector< double > aDotDashArray;
+
+ if(css::drawing::LineStyle_DASH == eLineStyle)
+ {
+ const XDash& rDash = rSet.Get(XATTR_LINEDASH).GetDashValue();
+
+ if(rDash.GetDots() || rDash.GetDashes())
+ {
+ const sal_uInt32 nLineWidth = rSet.Get(XATTR_LINEWIDTH).GetValue();
+ fFullDotDashLen = rDash.CreateDotDashArray(aDotDashArray, static_cast<double>(nLineWidth));
+ }
+ }
+
+ return drawinglayer::attribute::StrokeAttribute(std::move(aDotDashArray), fFullDotDashLen);
+ }
+} // end of anonymous namespace
+
+
+namespace drawinglayer::attribute
+{
+ class ImpSdrFormTextAttribute
+ {
+ public:
+ // FormText (FontWork) Attributes
+ sal_Int32 mnFormTextDistance; // distance from line in upright direction
+ sal_Int32 mnFormTextStart; // shift from polygon start
+ sal_Int32 mnFormTextShdwXVal; // shadow distance or 10th degrees
+ sal_Int32 mnFormTextShdwYVal; // shadow distance or scaling
+ sal_uInt16 mnFormTextShdwTransp; // shadow transparence
+ XFormTextStyle meFormTextStyle; // on/off and char orientation
+ XFormTextAdjust meFormTextAdjust; // adjustment (left/right/center) and scale
+ XFormTextShadow meFormTextShadow; // shadow mode
+ Color maFormTextShdwColor; // shadow color
+
+ // outline attributes; used when getFormTextOutline() is true and (for
+ // shadow) when getFormTextShadow() != XFormTextShadow::NONE
+ SdrFormTextOutlineAttribute maOutline;
+ SdrFormTextOutlineAttribute maShadowOutline;
+
+ bool mbFormTextMirror : 1; // change orientation
+ bool mbFormTextOutline : 1; // show contour of objects
+
+ explicit ImpSdrFormTextAttribute(const SfxItemSet& rSet)
+ : mnFormTextDistance(rSet.Get(XATTR_FORMTXTDISTANCE).GetValue()),
+ mnFormTextStart(rSet.Get(XATTR_FORMTXTSTART).GetValue()),
+ mnFormTextShdwXVal(rSet.Get(XATTR_FORMTXTSHDWXVAL).GetValue()),
+ mnFormTextShdwYVal(rSet.Get(XATTR_FORMTXTSHDWYVAL).GetValue()),
+ mnFormTextShdwTransp(rSet.Get(XATTR_FORMTXTSHDWTRANSP).GetValue()),
+ meFormTextStyle(rSet.Get(XATTR_FORMTXTSTYLE).GetValue()),
+ meFormTextAdjust(rSet.Get(XATTR_FORMTXTADJUST).GetValue()),
+ meFormTextShadow(rSet.Get(XATTR_FORMTXTSHADOW).GetValue()),
+ maFormTextShdwColor(rSet.Get(XATTR_FORMTXTSHDWCOLOR).GetColorValue()),
+ mbFormTextMirror(rSet.Get(XATTR_FORMTXTMIRROR).GetValue()),
+ mbFormTextOutline(rSet.Get(XATTR_FORMTXTOUTLINE).GetValue())
+ {
+ if(!getFormTextOutline())
+ return;
+
+ const StrokeAttribute aStrokeAttribute(impGetStrokeAttribute(rSet));
+
+ // also need to prepare attributes for outlines
+ {
+ const LineAttribute aLineAttribute(impGetLineAttribute(false, rSet));
+ const sal_uInt8 nTransparence(impGetStrokeTransparence(false, rSet));
+
+ maOutline = SdrFormTextOutlineAttribute(
+ aLineAttribute, aStrokeAttribute, nTransparence);
+ }
+
+ if(XFormTextShadow::NONE != getFormTextShadow())
+ {
+ // also need to prepare attributes for shadow outlines
+ const LineAttribute aLineAttribute(impGetLineAttribute(true, rSet));
+ const sal_uInt8 nTransparence(impGetStrokeTransparence(true, rSet));
+
+ maShadowOutline = SdrFormTextOutlineAttribute(
+ aLineAttribute, aStrokeAttribute, nTransparence);
+ }
+ }
+
+ ImpSdrFormTextAttribute()
+ : mnFormTextDistance(0),
+ mnFormTextStart(0),
+ mnFormTextShdwXVal(0),
+ mnFormTextShdwYVal(0),
+ mnFormTextShdwTransp(0),
+ meFormTextStyle(XFormTextStyle::NONE),
+ meFormTextAdjust(XFormTextAdjust::Center),
+ meFormTextShadow(XFormTextShadow::NONE),
+ mbFormTextMirror(false),
+ mbFormTextOutline(false)
+ {
+ }
+
+ // data read access
+ sal_Int32 getFormTextDistance() const { return mnFormTextDistance; }
+ sal_Int32 getFormTextStart() const { return mnFormTextStart; }
+ sal_Int32 getFormTextShdwXVal() const { return mnFormTextShdwXVal; }
+ sal_Int32 getFormTextShdwYVal() const { return mnFormTextShdwYVal; }
+ XFormTextStyle getFormTextStyle() const { return meFormTextStyle; }
+ XFormTextAdjust getFormTextAdjust() const { return meFormTextAdjust; }
+ XFormTextShadow getFormTextShadow() const { return meFormTextShadow; }
+ const Color& getFormTextShdwColor() const { return maFormTextShdwColor; }
+ const SdrFormTextOutlineAttribute& getOutline() const { return maOutline; }
+ const SdrFormTextOutlineAttribute& getShadowOutline() const { return maShadowOutline; }
+ bool getFormTextMirror() const { return mbFormTextMirror; }
+ bool getFormTextOutline() const { return mbFormTextOutline; }
+
+ // compare operator
+ bool operator==(const ImpSdrFormTextAttribute& rCandidate) const
+ {
+ return (getFormTextDistance() == rCandidate.getFormTextDistance()
+ && getFormTextStart() == rCandidate.getFormTextStart()
+ && getFormTextShdwXVal() == rCandidate.getFormTextShdwXVal()
+ && getFormTextShdwYVal() == rCandidate.getFormTextShdwYVal()
+ && mnFormTextShdwTransp == rCandidate.mnFormTextShdwTransp
+ && getFormTextStyle() == rCandidate.getFormTextStyle()
+ && getFormTextAdjust() == rCandidate.getFormTextAdjust()
+ && getFormTextShadow() == rCandidate.getFormTextShadow()
+ && getFormTextShdwColor() == rCandidate.getFormTextShdwColor()
+ && getOutline() == rCandidate.getOutline()
+ && getShadowOutline() == rCandidate.getShadowOutline()
+ && getFormTextMirror() == rCandidate.getFormTextMirror()
+ && getFormTextOutline() == rCandidate.getFormTextOutline());
+ }
+ };
+
+ namespace
+ {
+ SdrFormTextAttribute::ImplType& theGlobalDefault()
+ {
+ static SdrFormTextAttribute::ImplType SINGLETON;
+ return SINGLETON;
+ }
+ }
+
+ SdrFormTextAttribute::SdrFormTextAttribute(const SfxItemSet& rSet)
+ : mpSdrFormTextAttribute(ImpSdrFormTextAttribute(rSet))
+ {
+ }
+
+ SdrFormTextAttribute::SdrFormTextAttribute()
+ : mpSdrFormTextAttribute(theGlobalDefault())
+ {
+ }
+
+ SdrFormTextAttribute::SdrFormTextAttribute(const SdrFormTextAttribute& rCandidate)
+ : mpSdrFormTextAttribute(rCandidate.mpSdrFormTextAttribute)
+ {
+ }
+
+ SdrFormTextAttribute::SdrFormTextAttribute(SdrFormTextAttribute&& rCandidate) noexcept
+ : mpSdrFormTextAttribute(std::move(rCandidate.mpSdrFormTextAttribute))
+ {
+ }
+
+ SdrFormTextAttribute::~SdrFormTextAttribute()
+ {
+ }
+
+ bool SdrFormTextAttribute::isDefault() const
+ {
+ return mpSdrFormTextAttribute.same_object(theGlobalDefault());
+ }
+
+ SdrFormTextAttribute& SdrFormTextAttribute::operator=(const SdrFormTextAttribute& rCandidate)
+ {
+ mpSdrFormTextAttribute = rCandidate.mpSdrFormTextAttribute;
+ return *this;
+ }
+
+ SdrFormTextAttribute& SdrFormTextAttribute::operator=(SdrFormTextAttribute&& rCandidate) noexcept
+ {
+ mpSdrFormTextAttribute = std::move(rCandidate.mpSdrFormTextAttribute);
+ return *this;
+ }
+
+ bool SdrFormTextAttribute::operator==(const SdrFormTextAttribute& rCandidate) const
+ {
+ // tdf#87509 default attr is always != non-default attr, even with same values
+ if(rCandidate.isDefault() != isDefault())
+ return false;
+
+ return rCandidate.mpSdrFormTextAttribute == mpSdrFormTextAttribute;
+ }
+
+ sal_Int32 SdrFormTextAttribute::getFormTextDistance() const
+ {
+ return mpSdrFormTextAttribute->getFormTextDistance();
+ }
+
+ sal_Int32 SdrFormTextAttribute::getFormTextStart() const
+ {
+ return mpSdrFormTextAttribute->getFormTextStart();
+ }
+
+ sal_Int32 SdrFormTextAttribute::getFormTextShdwXVal() const
+ {
+ return mpSdrFormTextAttribute->getFormTextShdwXVal();
+ }
+
+ sal_Int32 SdrFormTextAttribute::getFormTextShdwYVal() const
+ {
+ return mpSdrFormTextAttribute->getFormTextShdwYVal();
+ }
+
+ XFormTextStyle SdrFormTextAttribute::getFormTextStyle() const
+ {
+ return mpSdrFormTextAttribute->getFormTextStyle();
+ }
+
+ XFormTextAdjust SdrFormTextAttribute::getFormTextAdjust() const
+ {
+ return mpSdrFormTextAttribute->getFormTextAdjust();
+ }
+
+ XFormTextShadow SdrFormTextAttribute::getFormTextShadow() const
+ {
+ return mpSdrFormTextAttribute->getFormTextShadow();
+ }
+
+ Color const & SdrFormTextAttribute::getFormTextShdwColor() const
+ {
+ return mpSdrFormTextAttribute->getFormTextShdwColor();
+ }
+
+ const SdrFormTextOutlineAttribute& SdrFormTextAttribute::getOutline() const
+ {
+ return mpSdrFormTextAttribute->getOutline();
+ }
+
+ const SdrFormTextOutlineAttribute& SdrFormTextAttribute::getShadowOutline() const
+ {
+ return mpSdrFormTextAttribute->getShadowOutline();
+ }
+
+ bool SdrFormTextAttribute::getFormTextMirror() const
+ {
+ return mpSdrFormTextAttribute->getFormTextMirror();
+ }
+
+ bool SdrFormTextAttribute::getFormTextOutline() const
+ {
+ return mpSdrFormTextAttribute->getFormTextOutline();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrformtextoutlineattribute.cxx b/svx/source/sdr/attribute/sdrformtextoutlineattribute.cxx
new file mode 100644
index 000000000..ec97cf044
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrformtextoutlineattribute.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdrformtextoutlineattribute.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ class ImpSdrFormTextOutlineAttribute
+ {
+ public:
+ // one set of attributes for FormText (FontWork) outline visualisation
+ LineAttribute maLineAttribute;
+ StrokeAttribute maStrokeAttribute;
+ sal_uInt8 mnTransparence;
+
+ ImpSdrFormTextOutlineAttribute(
+ const LineAttribute& rLineAttribute,
+ const StrokeAttribute& rStrokeAttribute,
+ sal_uInt8 nTransparence)
+ : maLineAttribute(rLineAttribute),
+ maStrokeAttribute(rStrokeAttribute),
+ mnTransparence(nTransparence)
+ {
+ }
+
+ ImpSdrFormTextOutlineAttribute()
+ : mnTransparence(0)
+ {
+ }
+
+ // data read access
+ const LineAttribute& getLineAttribute() const { return maLineAttribute; }
+ const StrokeAttribute& getStrokeAttribute() const { return maStrokeAttribute; }
+ sal_uInt8 getTransparence() const { return mnTransparence; }
+
+ // compare operator
+ bool operator==(const ImpSdrFormTextOutlineAttribute& rCandidate) const
+ {
+ return (getLineAttribute() == rCandidate.getLineAttribute()
+ && getStrokeAttribute() == rCandidate.getStrokeAttribute()
+ && getTransparence() == rCandidate.getTransparence());
+ }
+ };
+
+ namespace
+ {
+ SdrFormTextOutlineAttribute::ImplType& theGlobalDefault()
+ {
+ static SdrFormTextOutlineAttribute::ImplType SINGLETON;
+ return SINGLETON;
+ }
+ }
+
+ SdrFormTextOutlineAttribute::SdrFormTextOutlineAttribute(
+ const LineAttribute& rLineAttribute,
+ const StrokeAttribute& rStrokeAttribute,
+ sal_uInt8 nTransparence)
+ : mpSdrFormTextOutlineAttribute(
+ ImpSdrFormTextOutlineAttribute(
+ rLineAttribute, rStrokeAttribute, nTransparence))
+ {
+ }
+
+ SdrFormTextOutlineAttribute::SdrFormTextOutlineAttribute()
+ : mpSdrFormTextOutlineAttribute(theGlobalDefault())
+ {
+ }
+
+ SdrFormTextOutlineAttribute::SdrFormTextOutlineAttribute(const SdrFormTextOutlineAttribute& rCandidate)
+ : mpSdrFormTextOutlineAttribute(rCandidate.mpSdrFormTextOutlineAttribute)
+ {
+ }
+
+ SdrFormTextOutlineAttribute::~SdrFormTextOutlineAttribute()
+ {
+ }
+
+ bool SdrFormTextOutlineAttribute::isDefault() const
+ {
+ return mpSdrFormTextOutlineAttribute.same_object(theGlobalDefault());
+ }
+
+ SdrFormTextOutlineAttribute& SdrFormTextOutlineAttribute::operator=(const SdrFormTextOutlineAttribute& rCandidate)
+ {
+ mpSdrFormTextOutlineAttribute = rCandidate.mpSdrFormTextOutlineAttribute;
+ return *this;
+ }
+
+ SdrFormTextOutlineAttribute& SdrFormTextOutlineAttribute::operator=(SdrFormTextOutlineAttribute&& rCandidate) noexcept
+ {
+ mpSdrFormTextOutlineAttribute = std::move(rCandidate.mpSdrFormTextOutlineAttribute);
+ return *this;
+ }
+
+ bool SdrFormTextOutlineAttribute::operator==(const SdrFormTextOutlineAttribute& rCandidate) const
+ {
+ // tdf#87509 default attr is always != non-default attr, even with same values
+ if(rCandidate.isDefault() != isDefault())
+ return false;
+
+ return rCandidate.mpSdrFormTextOutlineAttribute == mpSdrFormTextOutlineAttribute;
+ }
+
+ const LineAttribute& SdrFormTextOutlineAttribute::getLineAttribute() const
+ {
+ return mpSdrFormTextOutlineAttribute->getLineAttribute();
+ }
+
+ const StrokeAttribute& SdrFormTextOutlineAttribute::getStrokeAttribute() const
+ {
+ return mpSdrFormTextOutlineAttribute->getStrokeAttribute();
+ }
+
+ sal_uInt8 SdrFormTextOutlineAttribute::getTransparence() const
+ {
+ return mpSdrFormTextOutlineAttribute->getTransparence();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrlineeffectstextattribute.cxx b/svx/source/sdr/attribute/sdrlineeffectstextattribute.cxx
new file mode 100644
index 000000000..72a3ef032
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrlineeffectstextattribute.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdrlineeffectstextattribute.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ SdrLineEffectsTextAttribute::SdrLineEffectsTextAttribute(
+ const SdrLineAttribute& rLine,
+ const SdrLineStartEndAttribute& rLineStartEnd,
+ const SdrShadowAttribute& rShadow,
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow,
+ sal_Int32 nSoftEdgeRadius)
+ : SdrEffectsTextAttribute(rShadow, rTextAttribute, rGlow, nSoftEdgeRadius),
+ maLine(rLine),
+ maLineStartEnd(rLineStartEnd)
+ {
+ }
+
+ SdrLineEffectsTextAttribute::SdrLineEffectsTextAttribute()
+ {
+ }
+
+ SdrLineEffectsTextAttribute::SdrLineEffectsTextAttribute(const SdrLineEffectsTextAttribute& rCandidate)
+ : SdrEffectsTextAttribute(rCandidate),
+ maLine(rCandidate.getLine()),
+ maLineStartEnd(rCandidate.getLineStartEnd())
+ {
+ }
+
+ SdrLineEffectsTextAttribute& SdrLineEffectsTextAttribute::operator=(const SdrLineEffectsTextAttribute& rCandidate)
+ {
+ SdrEffectsTextAttribute::operator=(rCandidate);
+ maLine = rCandidate.getLine();
+ maLineStartEnd = rCandidate.getLineStartEnd();
+
+ return *this;
+ }
+
+ bool SdrLineEffectsTextAttribute::isDefault() const
+ {
+ return(SdrEffectsTextAttribute::isDefault()
+ && getLine().isDefault()
+ && getLineStartEnd().isDefault());
+ }
+
+ bool SdrLineEffectsTextAttribute::operator==(const SdrLineEffectsTextAttribute& rCandidate) const
+ {
+ return(SdrEffectsTextAttribute::operator==(rCandidate)
+ && getLine() == rCandidate.getLine()
+ && getLineStartEnd() == rCandidate.getLineStartEnd());
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrlinefilleffectstextattribute.cxx b/svx/source/sdr/attribute/sdrlinefilleffectstextattribute.cxx
new file mode 100644
index 000000000..442b51833
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrlinefilleffectstextattribute.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ SdrLineFillEffectsTextAttribute::SdrLineFillEffectsTextAttribute(
+ const SdrLineAttribute& rLine,
+ const SdrFillAttribute& rFill,
+ const SdrLineStartEndAttribute& rLineStartEnd,
+ const SdrShadowAttribute& rShadow,
+ const FillGradientAttribute& rFillFloatTransGradient,
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow,
+ sal_Int32 nSoftEdgeRadius)
+ : SdrLineEffectsTextAttribute(rLine, rLineStartEnd, rShadow, rTextAttribute, rGlow, nSoftEdgeRadius),
+ maFill(rFill),
+ maFillFloatTransGradient(rFillFloatTransGradient)
+ {
+ }
+
+ SdrLineFillEffectsTextAttribute::SdrLineFillEffectsTextAttribute()
+ {
+ }
+
+ SdrLineFillEffectsTextAttribute::SdrLineFillEffectsTextAttribute(const SdrLineFillEffectsTextAttribute& rCandidate)
+ : SdrLineEffectsTextAttribute(rCandidate),
+ maFill(rCandidate.getFill()),
+ maFillFloatTransGradient(rCandidate.getFillFloatTransGradient())
+ {
+ }
+
+ SdrLineFillEffectsTextAttribute& SdrLineFillEffectsTextAttribute::operator=(const SdrLineFillEffectsTextAttribute& rCandidate)
+ {
+ SdrLineEffectsTextAttribute::operator=(rCandidate);
+ maFill = rCandidate.getFill();
+ maFillFloatTransGradient = rCandidate.getFillFloatTransGradient();
+
+ return *this;
+ }
+
+ bool SdrLineFillEffectsTextAttribute::isDefault() const
+ {
+ return (SdrLineEffectsTextAttribute::isDefault()
+ && getFill().isDefault()
+ && getFillFloatTransGradient().isDefault());
+ }
+
+ bool SdrLineFillEffectsTextAttribute::operator==(const SdrLineFillEffectsTextAttribute& rCandidate) const
+ {
+ return(SdrLineEffectsTextAttribute::operator==(rCandidate)
+ && getFill() == rCandidate.getFill()
+ && getFillFloatTransGradient() == rCandidate.getFillFloatTransGradient());
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrtextattribute.cxx b/svx/source/sdr/attribute/sdrtextattribute.cxx
new file mode 100644
index 000000000..5c9ecb34e
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrtextattribute.cxx
@@ -0,0 +1,422 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <sdr/attribute/sdrformtextattribute.hxx>
+#include <svx/svdotext.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/sdr/properties/properties.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ class ImpSdrTextAttribute
+ {
+ public:
+ // all-text attributes. The SdrText itself and a copy
+ // of the OPO
+ const SdrText* mpSdrText;
+ std::shared_ptr<OutlinerParaObject> mxOutlinerParaObject;
+
+ // Set when it's a FormText; contains all FormText attributes
+ SdrFormTextAttribute maSdrFormTextAttribute;
+
+ // text distances
+ sal_Int32 maTextLeftDistance;
+ sal_Int32 maTextUpperDistance;
+ sal_Int32 maTextRightDistance;
+ sal_Int32 maTextLowerDistance;
+
+ // #i101556# use versioning from text attributes to detect changes
+ sal_uInt32 maPropertiesVersion;
+
+ // text alignments
+ SdrTextHorzAdjust maSdrTextHorzAdjust;
+ SdrTextVertAdjust maSdrTextVertAdjust;
+
+ bool mbContour : 1;
+ bool mbFitToSize : 1;
+ bool mbAutoFit : 1;
+ bool mbHideContour : 1;
+ bool mbBlink : 1;
+ bool mbScroll : 1;
+ bool mbInEditMode : 1;
+ bool mbFixedCellHeight : 1;
+ bool mbWrongSpell : 1;
+
+ bool mbChainable : 1;
+
+
+ public:
+ ImpSdrTextAttribute(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ XFormTextStyle eFormTextStyle,
+ sal_Int32 aTextLeftDistance,
+ sal_Int32 aTextUpperDistance,
+ sal_Int32 aTextRightDistance,
+ sal_Int32 aTextLowerDistance,
+ SdrTextHorzAdjust aSdrTextHorzAdjust,
+ SdrTextVertAdjust aSdrTextVertAdjust,
+ bool bContour,
+ bool bFitToSize,
+ bool bAutoFit,
+ bool bHideContour,
+ bool bBlink,
+ bool bScroll,
+ bool bInEditMode,
+ bool bFixedCellHeight,
+ bool bWrongSpell,
+ bool bChainable)
+ : mpSdrText(pSdrText),
+ mxOutlinerParaObject(std::make_shared<OutlinerParaObject>(rOutlinerParaObject)),
+ maTextLeftDistance(aTextLeftDistance),
+ maTextUpperDistance(aTextUpperDistance),
+ maTextRightDistance(aTextRightDistance),
+ maTextLowerDistance(aTextLowerDistance),
+ maPropertiesVersion(0),
+ maSdrTextHorzAdjust(aSdrTextHorzAdjust),
+ maSdrTextVertAdjust(aSdrTextVertAdjust),
+ mbContour(bContour),
+ mbFitToSize(bFitToSize),
+ mbAutoFit(bAutoFit),
+ mbHideContour(bHideContour),
+ mbBlink(bBlink),
+ mbScroll(bScroll),
+ mbInEditMode(bInEditMode),
+ mbFixedCellHeight(bFixedCellHeight),
+ mbWrongSpell(bWrongSpell),
+ mbChainable(bChainable)
+ {
+ if(!pSdrText)
+ return;
+
+ if(XFormTextStyle::NONE != eFormTextStyle)
+ {
+ // text on path. Create FormText attribute
+ const SfxItemSet& rSet = pSdrText->GetItemSet();
+ maSdrFormTextAttribute = SdrFormTextAttribute(rSet);
+ }
+
+ // #i101556# init with version number to detect changes of single text
+ // attribute and/or style sheets in primitive data without having to
+ // copy that data locally (which would be better from principle)
+ maPropertiesVersion = pSdrText->GetObject().GetProperties().getVersion();
+ }
+
+ ImpSdrTextAttribute()
+ : mpSdrText(nullptr),
+ maTextLeftDistance(0),
+ maTextUpperDistance(0),
+ maTextRightDistance(0),
+ maTextLowerDistance(0),
+ maPropertiesVersion(0),
+ maSdrTextHorzAdjust(SDRTEXTHORZADJUST_LEFT),
+ maSdrTextVertAdjust(SDRTEXTVERTADJUST_TOP),
+ mbContour(false),
+ mbFitToSize(false),
+ mbAutoFit(false),
+ mbHideContour(false),
+ mbBlink(false),
+ mbScroll(false),
+ mbInEditMode(false),
+ mbFixedCellHeight(false),
+ mbWrongSpell(false),
+ mbChainable(false)
+ {
+ }
+
+ // data read access
+ const SdrText& getSdrText() const
+ {
+ assert(mpSdrText && "Access to text of default version of ImpSdrTextAttribute (!)");
+ return *mpSdrText;
+ }
+
+ const OutlinerParaObject& getOutlinerParaObject() const
+ {
+ assert(mxOutlinerParaObject && "Access to OutlinerParaObject of default version of ImpSdrTextAttribute (!)");
+ return *mxOutlinerParaObject;
+ }
+
+ bool isContour() const { return mbContour; }
+ bool isFitToSize() const { return mbFitToSize; }
+ bool isAutoFit() const { return mbAutoFit; }
+ bool isHideContour() const { return mbHideContour; }
+ bool isBlink() const { return mbBlink; }
+ bool isScroll() const { return mbScroll; }
+ bool isInEditMode() const { return mbInEditMode; }
+ bool isFixedCellHeight() const { return mbFixedCellHeight; }
+ bool isChainable() const { return mbChainable; }
+ const SdrFormTextAttribute& getSdrFormTextAttribute() const { return maSdrFormTextAttribute; }
+ sal_Int32 getTextLeftDistance() const { return maTextLeftDistance; }
+ sal_Int32 getTextUpperDistance() const { return maTextUpperDistance; }
+ sal_Int32 getTextRightDistance() const { return maTextRightDistance; }
+ sal_Int32 getTextLowerDistance() const { return maTextLowerDistance; }
+ SdrTextHorzAdjust getSdrTextHorzAdjust() const { return maSdrTextHorzAdjust; }
+ SdrTextVertAdjust getSdrTextVertAdjust() const { return maSdrTextVertAdjust; }
+
+ // compare operator
+ bool operator==(const ImpSdrTextAttribute& rCandidate) const
+ {
+ if (mxOutlinerParaObject.get() != rCandidate.mxOutlinerParaObject.get())
+ {
+ if (mxOutlinerParaObject && rCandidate.mxOutlinerParaObject)
+ {
+ // compares OPO and it's contents, but traditionally not the RedLining
+ // which is not seen as model, but as temporary information
+ if(getOutlinerParaObject() != rCandidate.getOutlinerParaObject())
+ {
+ return false;
+ }
+
+ // #i102062# for primitive visualisation, the WrongList (SpellChecking)
+ // is important, too, so use isWrongListEqual since there is no WrongList
+ // comparison in the regular OutlinerParaObject compare (since it's
+ // not-persistent data)
+ if(!(getOutlinerParaObject().isWrongListEqual(rCandidate.getOutlinerParaObject())))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // only one is zero; not equal
+ return false;
+ }
+ }
+
+ return (
+ getSdrFormTextAttribute() == rCandidate.getSdrFormTextAttribute()
+ && getTextLeftDistance() == rCandidate.getTextLeftDistance()
+ && getTextUpperDistance() == rCandidate.getTextUpperDistance()
+ && getTextRightDistance() == rCandidate.getTextRightDistance()
+ && getTextLowerDistance() == rCandidate.getTextLowerDistance()
+ && maPropertiesVersion == rCandidate.maPropertiesVersion
+
+ && getSdrTextHorzAdjust() == rCandidate.getSdrTextHorzAdjust()
+ && getSdrTextVertAdjust() == rCandidate.getSdrTextVertAdjust()
+
+ && isContour() == rCandidate.isContour()
+ && isFitToSize() == rCandidate.isFitToSize()
+ && isAutoFit() == rCandidate.isAutoFit()
+ && isHideContour() == rCandidate.isHideContour()
+ && isBlink() == rCandidate.isBlink()
+ && isScroll() == rCandidate.isScroll()
+ && isInEditMode() == rCandidate.isInEditMode()
+ && isFixedCellHeight() == rCandidate.isFixedCellHeight()
+ && mbWrongSpell == rCandidate.mbWrongSpell );
+ }
+ };
+
+ namespace
+ {
+ SdrTextAttribute::ImplType& theGlobalDefault()
+ {
+ static SdrTextAttribute::ImplType SINGLETON;
+ return SINGLETON;
+ }
+ }
+
+ SdrTextAttribute::SdrTextAttribute(
+ const SdrText& rSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ XFormTextStyle eFormTextStyle,
+ sal_Int32 aTextLeftDistance,
+ sal_Int32 aTextUpperDistance,
+ sal_Int32 aTextRightDistance,
+ sal_Int32 aTextLowerDistance,
+ SdrTextHorzAdjust aSdrTextHorzAdjust,
+ SdrTextVertAdjust aSdrTextVertAdjust,
+ bool bContour,
+ bool bFitToSize,
+ bool bAutoFit,
+ bool bHideContour,
+ bool bBlink,
+ bool bScroll,
+ bool bInEditMode,
+ bool bFixedCellHeight,
+ bool bWrongSpell,
+ bool bChainable)
+ : mpSdrTextAttribute(
+ ImpSdrTextAttribute(
+ &rSdrText, rOutlinerParaObject, eFormTextStyle, aTextLeftDistance,
+ aTextUpperDistance, aTextRightDistance, aTextLowerDistance,
+ aSdrTextHorzAdjust, aSdrTextVertAdjust, bContour, bFitToSize, bAutoFit,
+ bHideContour, bBlink, bScroll, bInEditMode, bFixedCellHeight, bWrongSpell,
+ bChainable))
+ {
+ }
+
+ SdrTextAttribute::SdrTextAttribute()
+ : mpSdrTextAttribute(theGlobalDefault())
+ {
+ }
+
+ SdrTextAttribute::SdrTextAttribute(const SdrTextAttribute& rCandidate)
+ : mpSdrTextAttribute(rCandidate.mpSdrTextAttribute)
+ {
+ }
+
+ SdrTextAttribute::SdrTextAttribute(SdrTextAttribute&& rCandidate) noexcept
+ : mpSdrTextAttribute(std::move(rCandidate.mpSdrTextAttribute))
+ {
+ }
+
+ SdrTextAttribute::~SdrTextAttribute()
+ {
+ }
+
+ bool SdrTextAttribute::isDefault() const
+ {
+ return mpSdrTextAttribute.same_object(theGlobalDefault());
+ }
+
+ SdrTextAttribute& SdrTextAttribute::operator=(const SdrTextAttribute& rCandidate)
+ {
+ mpSdrTextAttribute = rCandidate.mpSdrTextAttribute;
+ return *this;
+ }
+
+ SdrTextAttribute& SdrTextAttribute::operator=(SdrTextAttribute&& rCandidate) noexcept
+ {
+ mpSdrTextAttribute = std::move(rCandidate.mpSdrTextAttribute);
+ return *this;
+ }
+
+ bool SdrTextAttribute::operator==(const SdrTextAttribute& rCandidate) const
+ {
+ // tdf#87509 default attr is always != non-default attr, even with same values
+ if(rCandidate.isDefault() != isDefault())
+ return false;
+
+ return rCandidate.mpSdrTextAttribute == mpSdrTextAttribute;
+ }
+
+ const SdrText& SdrTextAttribute::getSdrText() const
+ {
+ return mpSdrTextAttribute->getSdrText();
+ }
+
+ const OutlinerParaObject& SdrTextAttribute::getOutlinerParaObject() const
+ {
+ return mpSdrTextAttribute->getOutlinerParaObject();
+ }
+
+ bool SdrTextAttribute::isContour() const
+ {
+ return mpSdrTextAttribute->isContour();
+ }
+
+ bool SdrTextAttribute::isFitToSize() const
+ {
+ return mpSdrTextAttribute->isFitToSize();
+ }
+
+ bool SdrTextAttribute::isAutoFit() const
+ {
+ return mpSdrTextAttribute->isAutoFit();
+ }
+
+ bool SdrTextAttribute::isHideContour() const
+ {
+ return mpSdrTextAttribute->isHideContour();
+ }
+
+ bool SdrTextAttribute::isBlink() const
+ {
+ return mpSdrTextAttribute->isBlink();
+ }
+
+ bool SdrTextAttribute::isScroll() const
+ {
+ return mpSdrTextAttribute->isScroll();
+ }
+
+ bool SdrTextAttribute::isInEditMode() const
+ {
+ return mpSdrTextAttribute->isInEditMode();
+ }
+
+ bool SdrTextAttribute::isChainable() const
+ {
+ return mpSdrTextAttribute->isChainable();
+ }
+
+
+ bool SdrTextAttribute::isFixedCellHeight() const
+ {
+ return mpSdrTextAttribute->isFixedCellHeight();
+ }
+
+ const SdrFormTextAttribute& SdrTextAttribute::getSdrFormTextAttribute() const
+ {
+ return mpSdrTextAttribute->getSdrFormTextAttribute();
+ }
+
+ sal_Int32 SdrTextAttribute::getTextLeftDistance() const
+ {
+ return mpSdrTextAttribute->getTextLeftDistance();
+ }
+
+ sal_Int32 SdrTextAttribute::getTextUpperDistance() const
+ {
+ return mpSdrTextAttribute->getTextUpperDistance();
+ }
+
+ sal_Int32 SdrTextAttribute::getTextRightDistance() const
+ {
+ return mpSdrTextAttribute->getTextRightDistance();
+ }
+
+ sal_Int32 SdrTextAttribute::getTextLowerDistance() const
+ {
+ return mpSdrTextAttribute->getTextLowerDistance();
+ }
+
+ SdrTextHorzAdjust SdrTextAttribute::getSdrTextHorzAdjust() const
+ {
+ return mpSdrTextAttribute->getSdrTextHorzAdjust();
+ }
+
+ SdrTextVertAdjust SdrTextAttribute::getSdrTextVertAdjust() const
+ {
+ return mpSdrTextAttribute->getSdrTextVertAdjust();
+ }
+
+ void SdrTextAttribute::getBlinkTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList) const
+ {
+ if(isBlink())
+ {
+ getSdrText().GetObject().impGetBlinkTextTiming(rAnimList);
+ }
+ }
+
+ void SdrTextAttribute::getScrollTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList, double fFrameLength, double fTextLength) const
+ {
+ if(isScroll())
+ {
+ getSdrText().GetObject().impGetScrollTextTiming(rAnimList, fFrameLength, fTextLength);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/displayinfo.cxx b/svx/source/sdr/contact/displayinfo.cxx
new file mode 100644
index 000000000..405fb41a0
--- /dev/null
+++ b/svx/source/sdr/contact/displayinfo.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/displayinfo.hxx>
+
+
+namespace sdr::contact
+{
+ DisplayInfo::DisplayInfo()
+ : maProcessLayers(true), // init layer info with all bits set to draw everything on default
+ mbControlLayerProcessingActive(false),
+ mbPageProcessingActive(true),
+ mbGhostedDrawModeActive(false),
+ mbSubContentActive(false)
+ {
+ }
+
+ // Access to LayerInfos (which layers to process)
+ void DisplayInfo::SetProcessLayers(const SdrLayerIDSet& rSet)
+ {
+ maProcessLayers = rSet;
+ }
+
+ // access to RedrawArea
+ void DisplayInfo::SetRedrawArea(const vcl::Region& rRegion)
+ {
+ maRedrawArea = rRegion;
+ }
+
+ void DisplayInfo::SetWriterPageFrame(basegfx::B2IRectangle const& rPageFrame)
+ {
+ m_WriterPageFrame = rPageFrame;
+ }
+
+ void DisplayInfo::SetControlLayerProcessingActive(bool bDoProcess)
+ {
+ if(mbControlLayerProcessingActive != bDoProcess)
+ {
+ mbControlLayerProcessingActive = bDoProcess;
+ }
+ }
+
+ void DisplayInfo::SetPageProcessingActive(bool bDoProcess)
+ {
+ if(mbPageProcessingActive != bDoProcess)
+ {
+ mbPageProcessingActive = bDoProcess;
+ }
+ }
+
+ void DisplayInfo::ClearGhostedDrawMode()
+ {
+ mbGhostedDrawModeActive = false;
+ }
+
+ void DisplayInfo::SetGhostedDrawMode()
+ {
+ mbGhostedDrawModeActive = true;
+ }
+
+ void DisplayInfo::SetSubContentActive(bool bNew)
+ {
+ if(mbSubContentActive != bNew)
+ {
+ mbSubContentActive = bNew;
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/objectcontact.cxx b/svx/source/sdr/contact/objectcontact.cxx
new file mode 100644
index 000000000..d135a2a29
--- /dev/null
+++ b/svx/source/sdr/contact/objectcontact.cxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <tools/debug.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::contact {
+
+bool ObjectContact::supportsGridOffsets() const
+{
+ // default does not support GridOffset
+ return false;
+}
+
+void ObjectContact::calculateGridOffsetForViewOjectContact(
+ basegfx::B2DVector& /*rTarget*/,
+ const ViewObjectContact& /*rClient*/) const
+{
+ // default does not on-demand calculate GridOffset
+}
+
+void ObjectContact::calculateGridOffsetForB2DRange(
+ basegfx::B2DVector& /*rTarget*/,
+ const basegfx::B2DRange& /*rB2DRange*/) const
+{
+ // default does not on-demand calculate GridOffset
+}
+
+ObjectContact::ObjectContact()
+: mpViewObjectContactRedirector(nullptr),
+ mbIsPreviewRenderer(false)
+{
+}
+
+ObjectContact::~ObjectContact() COVERITY_NOEXCEPT_FALSE
+{
+ // get rid of all registered contacts
+ // #i84257# To avoid that each 'delete pCandidate' again uses
+ // the local RemoveViewObjectContact with a search and removal in the
+ // vector, simply copy and clear local vector.
+ std::vector< ViewObjectContact* > aLocalVOCList;
+ aLocalVOCList.swap(maViewObjectContactVector);
+
+ for (const auto & pCandidate : aLocalVOCList)
+ // ViewObjectContacts only make sense with View and Object contacts.
+ // When the contact to the SdrObject is deleted like in this case,
+ // all ViewObjectContacts can be deleted, too.
+ delete pCandidate;
+
+ // assert when there were new entries added during deletion
+ DBG_ASSERT(maViewObjectContactVector.empty(), "Corrupted ViewObjectContactList (!)");
+}
+
+// LazyInvalidate request. Default implementation directly handles
+// this by calling back triggerLazyInvalidate() at the VOC
+void ObjectContact::setLazyInvalidate(ViewObjectContact& rVOC)
+{
+ rVOC.triggerLazyInvalidate();
+}
+
+// call this to support evtl. preparations for repaint. Default does nothing
+void ObjectContact::PrepareProcessDisplay()
+{
+}
+
+// A new ViewObjectContact was created and shall be remembered.
+void ObjectContact::AddViewObjectContact(ViewObjectContact& rVOContact)
+{
+ maViewObjectContactVector.push_back(&rVOContact);
+}
+
+// A ViewObjectContact was deleted and shall be forgotten.
+void ObjectContact::RemoveViewObjectContact(ViewObjectContact& rVOContact)
+{
+ std::vector< ViewObjectContact* >::iterator aFindResult = std::find(maViewObjectContactVector.begin(), maViewObjectContactVector.end(), &rVOContact);
+
+ if(aFindResult != maViewObjectContactVector.end())
+ {
+ maViewObjectContactVector.erase(aFindResult);
+ }
+}
+
+// Process the whole displaying
+void ObjectContact::ProcessDisplay(DisplayInfo& /*rDisplayInfo*/)
+{
+ // default does nothing
+}
+
+// test if visualizing of entered groups is switched on at all
+bool ObjectContact::DoVisualizeEnteredGroup() const
+{
+ // Do not do that as default
+ return false;
+}
+
+// get active group's (the entered group) ViewContact
+const ViewContact* ObjectContact::getActiveViewContact() const
+{
+ // default has no active VC
+ return nullptr;
+}
+
+// Invalidate given rectangle at the window/output which is represented by
+// this ObjectContact.
+void ObjectContact::InvalidatePartOfView(const basegfx::B2DRange& /*rRange*/) const
+{
+ // nothing to do here in the default version
+}
+
+// Get info about the need to visualize GluePoints
+bool ObjectContact::AreGluePointsVisible() const
+{
+ return false;
+}
+
+// check if text animation is allowed. Default is sal_true.
+bool ObjectContact::IsTextAnimationAllowed() const
+{
+ return true;
+}
+
+// check if graphic animation is allowed. Default is sal_true.
+bool ObjectContact::IsGraphicAnimationAllowed() const
+{
+ return true;
+}
+
+void ObjectContact::SetViewObjectContactRedirector(ViewObjectContactRedirector* pNew)
+{
+ if(mpViewObjectContactRedirector != pNew)
+ {
+ mpViewObjectContactRedirector = pNew;
+ }
+}
+
+// print? Default is false
+bool ObjectContact::isOutputToPrinter() const
+{
+ return false;
+}
+
+// recording MetaFile? Default is false
+bool ObjectContact::isOutputToRecordingMetaFile() const
+{
+ return false;
+}
+
+// pdf export? Default is false
+bool ObjectContact::isOutputToPDFFile() const
+{
+ return false;
+}
+
+bool ObjectContact::isExportTaggedPDF() const
+{
+ return false;
+}
+
+// gray display mode
+bool ObjectContact::isDrawModeGray() const
+{
+ return false;
+}
+
+// high contrast display mode
+bool ObjectContact::isDrawModeHighContrast() const
+{
+ return false;
+}
+
+// access to SdrPageView. Default implementation returns NULL
+SdrPageView* ObjectContact::TryToGetSdrPageView() const
+{
+ return nullptr;
+}
+
+// access to OutputDevice. Default implementation returns NULL
+OutputDevice* ObjectContact::TryToGetOutputDevice() const
+{
+ return nullptr;
+}
+
+void ObjectContact::resetAllGridOffsets()
+{
+ const sal_uInt32 nVOCCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nVOCCount; a++)
+ {
+ ViewObjectContact* pVOC(getViewObjectContact(a));
+ assert(pVOC && "ObjectContact: ViewObjectContact list Corrupt (!)");
+ pVOC->resetGridOffset();
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx b/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx
new file mode 100644
index 000000000..f666eceb1
--- /dev/null
+++ b/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <svx/unoapi.hxx>
+#include <tools/debug.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
+#include <memory>
+
+namespace sdr::contact {
+
+ObjectContactPainter::ObjectContactPainter()
+{
+}
+
+// The destructor.
+ObjectContactPainter::~ObjectContactPainter()
+{
+}
+
+sal_uInt32 ObjectContactOfObjListPainter::GetPaintObjectCount() const
+{
+ return maStartObjects.size();
+}
+
+ViewContact& ObjectContactOfObjListPainter::GetPaintObjectViewContact(sal_uInt32 nIndex)
+{
+ const SdrObject* pObj = maStartObjects[nIndex];
+ DBG_ASSERT(pObj, "ObjectContactOfObjListPainter: Corrupt SdrObjectVector (!)");
+ return pObj->GetViewContact();
+}
+
+ObjectContactOfObjListPainter::ObjectContactOfObjListPainter(
+ OutputDevice& rTargetDevice,
+ SdrObjectVector&& rObjects,
+ const SdrPage* pProcessedPage)
+: mrTargetOutputDevice(rTargetDevice),
+ maStartObjects(std::move(rObjects)),
+ mpProcessedPage(pProcessedPage)
+{
+}
+
+ObjectContactOfObjListPainter::~ObjectContactOfObjListPainter()
+{
+}
+
+// Process the whole displaying
+void ObjectContactOfObjListPainter::ProcessDisplay(DisplayInfo& rDisplayInfo)
+{
+ const sal_uInt32 nCount(GetPaintObjectCount());
+
+ if(!nCount)
+ return;
+
+ OutputDevice* pTargetDevice = TryToGetOutputDevice();
+
+ if(!pTargetDevice)
+ return;
+
+ // update current ViewInformation2D at the ObjectContact
+ const GDIMetaFile* pMetaFile = pTargetDevice->GetConnectMetaFile();
+ const bool bOutputToRecordingMetaFile(pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
+ basegfx::B2DRange aViewRange;
+
+ // create ViewRange
+ if(!bOutputToRecordingMetaFile)
+ {
+ // use visible pixels, but transform to world coordinates
+ const Size aOutputSizePixel(pTargetDevice->GetOutputSizePixel());
+ aViewRange = ::basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
+ aViewRange.transform(pTargetDevice->GetInverseViewTransformation());
+ }
+
+ // update local ViewInformation2D
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
+ basegfx::B2DHomMatrix(),
+ pTargetDevice->GetViewTransformation(),
+ aViewRange,
+ GetXDrawPageForSdrPage(const_cast< SdrPage* >(mpProcessedPage)),
+ 0.0);
+ updateViewInformation2D(aNewViewInformation2D);
+
+ // collect primitive data in a sequence; this will already use the updated ViewInformation2D
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence;
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const ViewObjectContact& rViewObjectContact = GetPaintObjectViewContact(a).GetViewObjectContact(*this);
+
+ rViewObjectContact.getPrimitive2DSequenceHierarchy(rDisplayInfo, xPrimitiveSequence);
+ }
+
+ // if there is something to show, use a vclProcessor to render it
+ if(!xPrimitiveSequence.empty())
+ {
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
+ *pTargetDevice,
+ getViewInformation2D()));
+
+ pProcessor2D->process(xPrimitiveSequence);
+ }
+}
+
+// recording MetaFile?
+bool ObjectContactOfObjListPainter::isOutputToRecordingMetaFile() const
+{
+ GDIMetaFile* pMetaFile = mrTargetOutputDevice.GetConnectMetaFile();
+ return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
+}
+
+// pdf export?
+bool ObjectContactOfObjListPainter::isOutputToPDFFile() const
+{
+ return OUTDEV_PDF == mrTargetOutputDevice.GetOutDevType();
+}
+
+bool ObjectContactOfObjListPainter::isExportTaggedPDF() const
+{
+ if (isOutputToPDFFile())
+ {
+ vcl::PDFExtOutDevData* pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData*>(
+ mrTargetOutputDevice.GetExtOutDevData()));
+
+ if (nullptr != pPDFExtOutDevData)
+ {
+ return pPDFExtOutDevData->GetIsExportTaggedPDF();
+ }
+ }
+ return false;
+}
+
+OutputDevice* ObjectContactOfObjListPainter::TryToGetOutputDevice() const
+{
+ return &mrTargetOutputDevice;
+}
+
+sal_uInt32 ObjectContactOfPagePainter::GetPaintObjectCount() const
+{
+ return (GetStartPage() ? 1 : 0);
+}
+
+ViewContact& ObjectContactOfPagePainter::GetPaintObjectViewContact(sal_uInt32 /*nIndex*/)
+{
+ DBG_ASSERT(GetStartPage(), "ObjectContactOfPagePainter::GetPaintObjectViewContact: no StartPage set (!)");
+ return GetStartPage()->GetViewContact();
+}
+
+ObjectContactOfPagePainter::ObjectContactOfPagePainter(
+ ObjectContact& rOriginalObjectContact)
+: mrOriginalObjectContact(rOriginalObjectContact)
+{
+}
+
+ObjectContactOfPagePainter::~ObjectContactOfPagePainter()
+{
+}
+
+void ObjectContactOfPagePainter::SetStartPage(const SdrPage* pPage)
+{
+ if(pPage != GetStartPage())
+ {
+ mxStartPage = const_cast< SdrPage* >(pPage); // no tools::WeakReference<SdrPage> available to hold a const SdrPage*
+ }
+}
+
+OutputDevice* ObjectContactOfPagePainter::TryToGetOutputDevice() const
+{
+ return mrOriginalObjectContact.TryToGetOutputDevice();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/objectcontactofpageview.cxx b/svx/source/sdr/contact/objectcontactofpageview.cxx
new file mode 100644
index 000000000..31b8b949e
--- /dev/null
+++ b/svx/source/sdr/contact/objectcontactofpageview.cxx
@@ -0,0 +1,451 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_feature_desktop.h>
+
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/animation/objectanimator.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <osl/diagnose.h>
+#include <svx/unoapi.hxx>
+#include <unotools/configmgr.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
+#include <comphelper/lok.hxx>
+
+#include <memory>
+
+using namespace com::sun::star;
+
+namespace sdr::contact
+{
+ // internal access to SdrPage of SdrPageView
+ SdrPage* ObjectContactOfPageView::GetSdrPage() const
+ {
+ return GetPageWindow().GetPageView().GetPage();
+ }
+
+ ObjectContactOfPageView::ObjectContactOfPageView(
+ SdrPageWindow& rPageWindow, const char *pDebugName)
+ : Idle(pDebugName)
+ , mrPageWindow(rPageWindow)
+ {
+ // init PreviewRenderer flag
+ setPreviewRenderer(static_cast<SdrPaintView&>(rPageWindow.GetPageView().GetView()).IsPreviewRenderer());
+
+ // init timer
+ SetPriority(TaskPriority::HIGH_IDLE);
+ Stop();
+ }
+
+ ObjectContactOfPageView::~ObjectContactOfPageView()
+ {
+ // execute missing LazyInvalidates and stop timer
+ Invoke();
+ }
+
+ // LazyInvalidate request. Take action.
+ void ObjectContactOfPageView::setLazyInvalidate(ViewObjectContact& /*rVOC*/)
+ {
+ // do NOT call parent, but remember that something is to do by
+ // starting the LazyInvalidateTimer
+ Start();
+ }
+
+ // call this to support evtl. preparations for repaint
+ void ObjectContactOfPageView::PrepareProcessDisplay()
+ {
+ if(IsActive())
+ // there are still non-triggered LazyInvalidate events, trigger these
+ Invoke();
+ }
+
+ // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
+ void ObjectContactOfPageView::Invoke()
+ {
+ // stop the timer
+ Stop();
+
+ // invalidate all LazyInvalidate VOCs new situations
+ const sal_uInt32 nVOCCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nVOCCount; a++)
+ {
+ ViewObjectContact* pCandidate = getViewObjectContact(a);
+ pCandidate->triggerLazyInvalidate();
+ }
+ }
+
+ // Process the whole displaying
+ void ObjectContactOfPageView::ProcessDisplay(DisplayInfo& rDisplayInfo)
+ {
+ const SdrPage* pStartPage = GetSdrPage();
+
+ if(pStartPage && !rDisplayInfo.GetProcessLayers().IsEmpty())
+ {
+ const ViewContact& rDrawPageVC = pStartPage->GetViewContact();
+
+ if(rDrawPageVC.GetObjectCount())
+ {
+ DoProcessDisplay(rDisplayInfo);
+ }
+ }
+ }
+
+ // Process the whole displaying. Only use given DisplayInfo, do not access other
+ // OutputDevices then the given ones.
+ void ObjectContactOfPageView::DoProcessDisplay(DisplayInfo& rDisplayInfo)
+ {
+ OutputDevice& rTargetOutDev = GetPageWindow().GetPaintWindow().GetTargetOutputDevice();
+ const Size aOutputSizePixel(rTargetOutDev.GetOutputSizePixel());
+ if (!isOutputToRecordingMetaFile() // do those have outdev too?
+ && (0 == aOutputSizePixel.getWidth() ||
+ 0 == aOutputSizePixel.getHeight()))
+ {
+ return;
+ }
+
+ // visualize entered group when that feature is switched on and it's not
+ // a print output. #i29129# No ghosted display for printing.
+ bool bVisualizeEnteredGroup(DoVisualizeEnteredGroup() && !isOutputToPrinter());
+
+ // Visualize entered groups: Set to ghosted as default
+ // start. Do this only for the DrawPage, not for MasterPages
+ if(bVisualizeEnteredGroup)
+ {
+ rDisplayInfo.SetGhostedDrawMode();
+ }
+
+ // #114359# save old and set clip region
+ OutputDevice* pOutDev = TryToGetOutputDevice();
+ OSL_ENSURE(nullptr != pOutDev, "ObjectContactOfPageView without OutDev, someone has overridden TryToGetOutputDevice wrong (!)");
+ bool bClipRegionPushed(false);
+ const vcl::Region& rRedrawArea(rDisplayInfo.GetRedrawArea());
+
+ if(!rRedrawArea.IsEmpty() && !comphelper::LibreOfficeKit::isActive())
+ {
+ bClipRegionPushed = true;
+ pOutDev->Push(vcl::PushFlags::CLIPREGION);
+ pOutDev->IntersectClipRegion(rRedrawArea);
+ }
+
+ // Get start node and process DrawPage contents
+ const ViewObjectContact& rDrawPageVOContact = GetSdrPage()->GetViewContact().GetViewObjectContact(*this);
+
+ // update current ViewInformation2D at the ObjectContact
+ const double fCurrentTime(getPrimitiveAnimator().GetTime());
+ basegfx::B2DRange aViewRange;
+
+ // create ViewRange
+ if(isOutputToRecordingMetaFile())
+ {
+ if (!rDisplayInfo.GetRedrawArea().IsEmpty())
+ {
+ // #i98402# if it's a PDF export, set the ClipRegion as ViewRange. This is
+ // mainly because SW does not use DrawingLayer Page-Oriented and if not doing this,
+ // all existing objects will be collected as primitives and processed.
+ // OD 2009-03-05 #i99876# perform the same also for SW on printing.
+ // fdo#78149 same thing also needed for plain MetaFile
+ // export, so why not do it always
+ const tools::Rectangle aLogicClipRectangle(rDisplayInfo.GetRedrawArea().GetBoundRect());
+
+ aViewRange = vcl::unotools::b2DRectangleFromRectangle(aLogicClipRectangle);
+ }
+ }
+ else
+ {
+ // use visible pixels, but transform to world coordinates
+ aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
+ // if a clip region is set, use it
+ if(!rDisplayInfo.GetRedrawArea().IsEmpty())
+ {
+ // get logic clip range and create discrete one
+ const tools::Rectangle aLogicClipRectangle(rDisplayInfo.GetRedrawArea().GetBoundRect());
+ basegfx::B2DRange aDiscreteClipRange = vcl::unotools::b2DRectangleFromRectangle(aLogicClipRectangle);
+ aDiscreteClipRange.transform(rTargetOutDev.GetViewTransformation());
+
+ // align the discrete one to discrete boundaries (pixel bounds). Also
+ // expand X and Y max by one due to Rectangle definition source
+ aDiscreteClipRange.expand(basegfx::B2DTuple(
+ floor(aDiscreteClipRange.getMinX()),
+ floor(aDiscreteClipRange.getMinY())));
+ aDiscreteClipRange.expand(basegfx::B2DTuple(
+ 1.0 + ceil(aDiscreteClipRange.getMaxX()),
+ 1.0 + ceil(aDiscreteClipRange.getMaxY())));
+
+ // intersect current ViewRange with ClipRange
+ aViewRange.intersect(aDiscreteClipRange);
+ }
+
+ // transform to world coordinates
+ aViewRange.transform(rTargetOutDev.GetInverseViewTransformation());
+ }
+
+ // update local ViewInformation2D
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
+ basegfx::B2DHomMatrix(),
+ rTargetOutDev.GetViewTransformation(),
+ aViewRange,
+ GetXDrawPageForSdrPage(GetSdrPage()),
+ fCurrentTime);
+ updateViewInformation2D(aNewViewInformation2D);
+
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence;
+
+#if HAVE_FEATURE_DESKTOP || defined( ANDROID )
+ // get whole Primitive2DContainer; this will already make use of updated ViewInformation2D
+ // and may use the MapMode from the Target OutDev in the DisplayInfo
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(rDisplayInfo, xPrimitiveSequence);
+#else
+ // Hmm, !HAVE_FEATURE_DESKTOP && !ANDROID means iOS,
+ // right? But does it makes sense to use a different code
+ // path for iOS than for Android; both use tiled rendering
+ // etc now.
+
+ // HACK: this only works when we are drawing sdr shapes via
+ // drawinglayer; but it can happen that the hierarchy contains
+ // more than just the shapes, and then it fails.
+ //
+ // This is good enough for the tiled rendering for the moment, but
+ // we need to come up with the real solution shortly.
+
+ // Only get the expensive hierarchy if we can be sure that the
+ // returned sequence won't be empty anyway.
+ bool bGetHierarchy = rRedrawArea.IsEmpty();
+ if (!bGetHierarchy)
+ {
+ // Not empty? Then not doing a full redraw, check if
+ // getPrimitive2DSequenceHierarchy() is still needed.
+ sal_Int32 nObjCount = GetSdrPage()->GetObjCount();
+ for (sal_Int32 i = 0; i < nObjCount; ++i)
+ {
+ SdrObject* pObject = GetSdrPage()->GetObj(i);
+ if (rRedrawArea.Overlaps(pObject->GetCurrentBoundRect()))
+ {
+ bGetHierarchy = true;
+ break;
+ }
+ }
+ }
+
+ if (bGetHierarchy)
+ // get whole Primitive2DContainer; this will already make use of updated ViewInformation2D
+ // and may use the MapMode from the Target OutDev in the DisplayInfo
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(rDisplayInfo, xPrimitiveSequence);
+#endif
+
+ // if there is something to show, use a primitive processor to render it. There
+ // is a choice between VCL and Canvas processors currently. The decision is made in
+ // createProcessor2DFromOutputDevice and takes into account things like the
+ // Target is a MetaFile, a VDev or something else. The Canvas renderer is triggered
+ // currently using the shown boolean. Canvas is not yet the default.
+ if(!xPrimitiveSequence.empty())
+ {
+ // prepare OutputDevice (historical stuff, maybe soon removed)
+ rDisplayInfo.ClearGhostedDrawMode(); // reset, else the VCL-paint with the processor will not do the right thing
+ pOutDev->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::Default); // reset, default is no BiDi/RTL
+ // create renderer
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
+ drawinglayer::processor2d::createProcessor2DFromOutputDevice(
+ rTargetOutDev, getViewInformation2D()));
+ pProcessor2D->process(xPrimitiveSequence);
+ }
+
+ // #114359# restore old ClipReghion
+ if(bClipRegionPushed)
+ {
+ pOutDev->Pop();
+ }
+
+ // Visualize entered groups: Reset to original DrawMode
+ if(bVisualizeEnteredGroup)
+ {
+ rDisplayInfo.ClearGhostedDrawMode();
+ }
+ }
+
+ // test if visualizing of entered groups is switched on at all
+ bool ObjectContactOfPageView::DoVisualizeEnteredGroup() const
+ {
+ return true;
+ }
+
+ // get active group's (the entered group) ViewContact
+ const ViewContact* ObjectContactOfPageView::getActiveViewContact() const
+ {
+ SdrObjList* pActiveGroupList = GetPageWindow().GetPageView().GetObjList();
+
+ if(pActiveGroupList)
+ {
+ if(nullptr != pActiveGroupList->getSdrPageFromSdrObjList())
+ {
+ // It's a Page itself
+ return &(pActiveGroupList->getSdrPageFromSdrObjList()->GetViewContact());
+ }
+ else if(pActiveGroupList->getSdrObjectFromSdrObjList())
+ {
+ // Group object
+ return &(pActiveGroupList->getSdrObjectFromSdrObjList()->GetViewContact());
+ }
+ }
+ else if(GetSdrPage())
+ {
+ // use page of associated SdrPageView
+ return &(GetSdrPage()->GetViewContact());
+ }
+
+ return nullptr;
+ }
+
+ // Invalidate given rectangle at the window/output which is represented by
+ // this ObjectContact.
+ void ObjectContactOfPageView::InvalidatePartOfView(const basegfx::B2DRange& rRange) const
+ {
+ // invalidate at associated PageWindow
+ GetPageWindow().InvalidatePageWindow(rRange);
+ }
+
+ // Get info about the need to visualize GluePoints
+ bool ObjectContactOfPageView::AreGluePointsVisible() const
+ {
+ bool bTiledRendering = comphelper::LibreOfficeKit::isActive();
+ return !bTiledRendering && GetPageWindow().GetPageView().GetView().ImpIsGlueVisible();
+ }
+
+ // check if text animation is allowed.
+ bool ObjectContactOfPageView::IsTextAnimationAllowed() const
+ {
+ if (utl::ConfigManager::IsFuzzing())
+ return true;
+ SdrView& rView = GetPageWindow().GetPageView().GetView();
+ const SvtAccessibilityOptions& rOpt = rView.getAccessibilityOptions();
+ return rOpt.GetIsAllowAnimatedText();
+ }
+
+ // check if graphic animation is allowed.
+ bool ObjectContactOfPageView::IsGraphicAnimationAllowed() const
+ {
+ if (utl::ConfigManager::IsFuzzing())
+ return true;
+ SdrView& rView = GetPageWindow().GetPageView().GetView();
+ const SvtAccessibilityOptions& rOpt = rView.getAccessibilityOptions();
+ return rOpt.GetIsAllowAnimatedGraphics();
+ }
+
+ // print?
+ bool ObjectContactOfPageView::isOutputToPrinter() const
+ {
+ return (OUTDEV_PRINTER == mrPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType());
+ }
+
+ // recording MetaFile?
+ bool ObjectContactOfPageView::isOutputToRecordingMetaFile() const
+ {
+ GDIMetaFile* pMetaFile = mrPageWindow.GetPaintWindow().GetOutputDevice().GetConnectMetaFile();
+ return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
+ }
+
+ // pdf export?
+ bool ObjectContactOfPageView::isOutputToPDFFile() const
+ {
+ return OUTDEV_PDF == mrPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType();
+ }
+
+ bool ObjectContactOfPageView::isExportTaggedPDF() const
+ {
+ if (isOutputToPDFFile())
+ {
+ vcl::PDFExtOutDevData* pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData*>(
+ mrPageWindow.GetPaintWindow().GetOutputDevice().GetExtOutDevData()));
+
+ if (nullptr != pPDFExtOutDevData)
+ {
+ return pPDFExtOutDevData->GetIsExportTaggedPDF();
+ }
+ }
+ return false;
+ }
+
+ // gray display mode
+ bool ObjectContactOfPageView::isDrawModeGray() const
+ {
+ const DrawModeFlags nDrawMode(mrPageWindow.GetPaintWindow().GetOutputDevice().GetDrawMode());
+ return (nDrawMode == (DrawModeFlags::GrayLine|DrawModeFlags::GrayFill|DrawModeFlags::BlackText|DrawModeFlags::GrayBitmap|DrawModeFlags::GrayGradient));
+ }
+
+ // high contrast display mode
+ bool ObjectContactOfPageView::isDrawModeHighContrast() const
+ {
+ const DrawModeFlags nDrawMode(mrPageWindow.GetPaintWindow().GetOutputDevice().GetDrawMode());
+ return (nDrawMode == (DrawModeFlags::SettingsLine|DrawModeFlags::SettingsFill|DrawModeFlags::SettingsText|DrawModeFlags::SettingsGradient));
+ }
+
+ // access to SdrPageView
+ SdrPageView* ObjectContactOfPageView::TryToGetSdrPageView() const
+ {
+ return &(mrPageWindow.GetPageView());
+ }
+
+
+ // access to OutputDevice
+ OutputDevice* ObjectContactOfPageView::TryToGetOutputDevice() const
+ {
+ SdrPreRenderDevice* pPreRenderDevice = mrPageWindow.GetPaintWindow().GetPreRenderDevice();
+
+ if(pPreRenderDevice)
+ {
+ return &(pPreRenderDevice->GetPreRenderDevice());
+ }
+ else
+ {
+ return &(mrPageWindow.GetPaintWindow().GetOutputDevice());
+ }
+ }
+
+ // set all UNO controls displayed in the view to design/alive mode
+ void ObjectContactOfPageView::SetUNOControlsDesignMode( bool _bDesignMode ) const
+ {
+ const sal_uInt32 nCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const ViewObjectContact* pVOC = getViewObjectContact(a);
+ const ViewObjectContactOfUnoControl* pUnoObjectVOC = dynamic_cast< const ViewObjectContactOfUnoControl* >(pVOC);
+
+ if(pUnoObjectVOC)
+ {
+ pUnoObjectVOC->setControlDesignMode(_bDesignMode);
+ }
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/sdrmediawindow.cxx b/svx/source/sdr/contact/sdrmediawindow.cxx
new file mode 100644
index 000000000..086e12cee
--- /dev/null
+++ b/svx/source/sdr/contact/sdrmediawindow.cxx
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "sdrmediawindow.hxx"
+#include <vcl/transfer.hxx>
+
+#include <sdr/contact/viewobjectcontactofsdrmediaobj.hxx>
+#include <vcl/window.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+
+namespace sdr::contact {
+
+
+SdrMediaWindow::SdrMediaWindow( vcl::Window* pParent, ViewObjectContactOfSdrMediaObj& rViewObjContact ) :
+ ::avmedia::MediaWindow( pParent, false ),
+ mrViewObjectContactOfSdrMediaObj( rViewObjContact )
+{
+}
+
+
+SdrMediaWindow::~SdrMediaWindow()
+{
+}
+
+
+void SdrMediaWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow && getWindow() )
+ {
+ const MouseEvent aTransformedEvent( pWindow->ScreenToOutputPixel( getWindow()->OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ pWindow->MouseMove( aTransformedEvent );
+ setPointer( pWindow->GetPointer() );
+ }
+}
+
+
+void SdrMediaWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow && getWindow() )
+ {
+ const MouseEvent aTransformedEvent( pWindow->ScreenToOutputPixel( getWindow()->OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ pWindow->MouseButtonDown( aTransformedEvent );
+ }
+}
+
+
+void SdrMediaWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow && getWindow() )
+ {
+ const MouseEvent aTransformedEvent( pWindow->ScreenToOutputPixel( getWindow()->OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ pWindow->MouseButtonUp( aTransformedEvent );
+ }
+}
+
+
+void SdrMediaWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow )
+ pWindow->KeyInput( rKEvt );
+}
+
+
+void SdrMediaWindow::KeyUp( const KeyEvent& rKEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow )
+ pWindow->KeyUp( rKEvt );
+}
+
+
+void SdrMediaWindow::Command( const CommandEvent& rCEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow && getWindow() )
+ {
+ const CommandEvent aTransformedEvent( pWindow->ScreenToOutputPixel( getWindow()->OutputToScreenPixel( rCEvt.GetMousePosPixel() ) ),
+ rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetEventData() );
+
+ pWindow->Command( aTransformedEvent );
+ }
+}
+
+
+sal_Int8 SdrMediaWindow::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( pWindow )
+ {
+ DropTargetHelper* pDropTargetHelper = dynamic_cast< DropTargetHelper* >( pWindow );
+
+ if( pDropTargetHelper )
+ {
+ nRet = pDropTargetHelper->AcceptDrop( rEvt );
+ }
+ }
+
+ return nRet;
+}
+
+
+sal_Int8 SdrMediaWindow::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( pWindow )
+ {
+ DropTargetHelper* pDropTargetHelper = dynamic_cast< DropTargetHelper* >( pWindow );
+
+ if( pDropTargetHelper )
+ {
+ nRet = pDropTargetHelper->ExecuteDrop( rEvt );
+ }
+ }
+
+ return nRet;
+}
+
+
+void SdrMediaWindow::StartDrag( sal_Int8 nAction, const Point& rPosPixel )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow )
+ {
+ DragSourceHelper* pDragSourceHelper = dynamic_cast< DragSourceHelper* >( pWindow );
+
+ if( pDragSourceHelper )
+ {
+ pDragSourceHelper->StartDrag( nAction, rPosPixel );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/sdrmediawindow.hxx b/svx/source/sdr/contact/sdrmediawindow.hxx
new file mode 100644
index 000000000..fb3cda6fc
--- /dev/null
+++ b/svx/source/sdr/contact/sdrmediawindow.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_SDR_CONTACT_SDRMEDIAWINDOW_HXX
+#define INCLUDED_SVX_SOURCE_SDR_CONTACT_SDRMEDIAWINDOW_HXX
+
+#include <avmedia/mediawindow.hxx>
+
+namespace sdr::contact {
+
+
+class ViewObjectContactOfSdrMediaObj;
+
+class SdrMediaWindow : public ::avmedia::MediaWindow
+{
+public:
+
+ SdrMediaWindow( vcl::Window* pParent, ViewObjectContactOfSdrMediaObj& rViewObjContact );
+ virtual ~SdrMediaWindow() override;
+
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void KeyUp( const KeyEvent& rKEvt ) override;
+
+ virtual void Command( const CommandEvent& rCEvt ) override;
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+ virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override;
+
+private:
+
+ ViewObjectContactOfSdrMediaObj& mrViewObjectContactOfSdrMediaObj;
+};
+
+}
+
+#endif // INCLUDED_SVX_SOURCE_SDR_CONTACT_SDRMEDIAWINDOW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontact.cxx b/svx/source/sdr/contact/viewcontact.cxx
new file mode 100644
index 000000000..bd79bc5ed
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontact.cxx
@@ -0,0 +1,295 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <osl/diagnose.h>
+#include <tools/debug.hxx>
+
+namespace sdr::contact
+{
+// Create an Object-Specific ViewObjectContact, set ViewContact and
+// ObjectContact. Always needs to return something. Default is to create
+// a standard ViewObjectContact containing the given ObjectContact and *this
+ViewObjectContact& ViewContact::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ return *(new ViewObjectContact(rObjectContact, *this));
+}
+
+ViewContact::ViewContact() {}
+
+ViewContact::~ViewContact() { deleteAllVOCs(); }
+
+void ViewContact::deleteAllVOCs()
+{
+ // get rid of all VOCs
+ // #i84257# To avoid that each 'delete pCandidate' again uses
+ // the local RemoveViewObjectContact with a search and removal in the
+ // vector, simply copy and clear local vector.
+ std::vector<ViewObjectContact*> aLocalVOCList;
+ aLocalVOCList.swap(maViewObjectContactVector);
+
+ for (const auto& pCandidate : aLocalVOCList)
+ // ViewObjectContacts only make sense with View and Object contacts.
+ // When the contact to the SdrObject is deleted like in this case,
+ // all ViewObjectContacts can be deleted, too.
+ delete pCandidate;
+
+ // assert when there were new entries added during deletion
+ DBG_ASSERT(maViewObjectContactVector.empty(), "Corrupted ViewObjectContactList in VC (!)");
+}
+
+// get an Object-specific ViewObjectContact for a specific
+// ObjectContact (->View). Always needs to return something.
+ViewObjectContact& ViewContact::GetViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = nullptr;
+ const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+ // first search if there exists a VOC for the given OC
+ for (sal_uInt32 a(0); !pRetval && a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = maViewObjectContactVector[a];
+ DBG_ASSERT(pCandidate, "Corrupted ViewObjectContactList (!)");
+
+ if (&(pCandidate->GetObjectContact()) == &rObjectContact)
+ {
+ pRetval = pCandidate;
+ }
+ }
+
+ if (!pRetval)
+ {
+ // create a new one. It's inserted to the local list from the
+ // ViewObjectContact constructor via AddViewObjectContact()
+ pRetval = &CreateObjectSpecificViewObjectContact(rObjectContact);
+ }
+
+ return *pRetval;
+}
+
+// A new ViewObjectContact was created and shall be remembered.
+void ViewContact::AddViewObjectContact(ViewObjectContact& rVOContact)
+{
+ maViewObjectContactVector.push_back(&rVOContact);
+}
+
+// A ViewObjectContact was deleted and shall be forgotten.
+void ViewContact::RemoveViewObjectContact(ViewObjectContact& rVOContact)
+{
+ std::vector<ViewObjectContact*>::iterator aFindResult = std::find(
+ maViewObjectContactVector.begin(), maViewObjectContactVector.end(), &rVOContact);
+
+ if (aFindResult != maViewObjectContactVector.end())
+ {
+ maViewObjectContactVector.erase(aFindResult);
+ }
+}
+
+// Test if this ViewContact has ViewObjectContacts at all. This can
+// be used to test if this ViewContact is visualized ATM or not
+bool ViewContact::HasViewObjectContacts() const
+{
+ const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ if (!maViewObjectContactVector[a]->GetObjectContact().IsPreviewRenderer())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Test if this ViewContact has ViewObjectContacts at all. This can
+// be used to test if this ViewContact is visualized ATM or not
+bool ViewContact::isAnimatedInAnyViewObjectContact() const
+{
+ const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ if (maViewObjectContactVector[a]->isAnimated())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Access to possible sub-hierarchy and parent. GetObjectCount() default is 0L
+// and GetViewContact default pops up an assert since it's an error if
+// GetObjectCount has a result != 0 and it's not overridden.
+sal_uInt32 ViewContact::GetObjectCount() const
+{
+ // no sub-objects
+ return 0;
+}
+
+ViewContact& ViewContact::GetViewContact(sal_uInt32 /*nIndex*/) const
+{
+ // This is the default implementation; call would be an error
+ OSL_FAIL("ViewContact::GetViewContact: This call needs to be overridden when GetObjectCount() "
+ "can return results != 0 (!)");
+ return const_cast<ViewContact&>(*this);
+}
+
+ViewContact* ViewContact::GetParentContact() const
+{
+ // default has no parent
+ return nullptr;
+}
+
+void ViewContact::ActionChildInserted(ViewContact& rChild)
+{
+ // propagate change to all existing visualisations which
+ // will force a VOC for the new child and invalidate its range
+ const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = maViewObjectContactVector[a];
+ DBG_ASSERT(pCandidate,
+ "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)");
+
+ // take action at all VOCs. At the VOCs ObjectContact the initial
+ // rectangle will be invalidated at the associated OutputDevice.
+ pCandidate->ActionChildInserted(rChild);
+ }
+}
+
+// React on changes of the object of this ViewContact
+void ViewContact::ActionChanged()
+{
+ // propagate change to all existing VOCs. This will invalidate
+ // all drawn visualisations in all known views
+ const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = maViewObjectContactVector[a];
+ DBG_ASSERT(pCandidate,
+ "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)");
+
+ if (pCandidate)
+ {
+ pCandidate->ActionChanged();
+ }
+ }
+}
+
+// access to SdrObject and/or SdrPage. May return 0L like the default
+// implementations do. Override as needed.
+SdrObject* ViewContact::TryToGetSdrObject() const { return nullptr; }
+
+// primitive stuff
+
+void ViewContact::createViewIndependentPrimitive2DSequence(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // This is the default implementation and should never be called (see header). If this is called,
+ // someone implemented a ViewContact (VC) visualisation object without defining the visualisation by
+ // providing a sequence of primitives -> which cannot be correct.
+ // Since we have no access to any known model data here, the default implementation creates a yellow placeholder
+ // hairline polygon with a default size of (1000, 1000, 5000, 3000)
+ OSL_FAIL("ViewContact::createViewIndependentPrimitive2DSequence(): Never call the fallback "
+ "base implementation, this is always an error (!)");
+ const basegfx::B2DPolygon aOutline(
+ basegfx::utils::createPolygonFromRect(basegfx::B2DRange(1000.0, 1000.0, 5000.0, 3000.0)));
+ const basegfx::BColor aYellow(1.0, 1.0, 0.0);
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aYellow));
+
+ rVisitor.visit(xReference);
+}
+
+void ViewContact::getViewIndependentPrimitive2DContainer(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ /* Local up-to-date checks. Create new list and compare.
+ We cannot just always use the new data because the old data has cached bitmaps in it e.g. see the document in tdf#146108.
+ */
+ drawinglayer::primitive2d::Primitive2DContainer xNew;
+ createViewIndependentPrimitive2DSequence(xNew);
+
+ if (!xNew.empty())
+ {
+ // allow evtl. embedding in object-specific infos, e.g. Name, Title, Description
+ xNew = embedToObjectSpecificInformation(std::move(xNew));
+ }
+
+ if (mxViewIndependentPrimitive2DSequence != xNew)
+ {
+ // has changed, copy content
+ const_cast<ViewContact*>(this)->mxViewIndependentPrimitive2DSequence = std::move(xNew);
+ }
+
+ // return current Primitive2DContainer
+ rVisitor.visit(mxViewIndependentPrimitive2DSequence);
+}
+
+// add Gluepoints (if available)
+drawinglayer::primitive2d::Primitive2DContainer
+ViewContact::createGluePointPrimitive2DSequence() const
+{
+ // default returns empty reference
+ return drawinglayer::primitive2d::Primitive2DContainer();
+}
+
+drawinglayer::primitive2d::Primitive2DContainer ViewContact::embedToObjectSpecificInformation(
+ drawinglayer::primitive2d::Primitive2DContainer aSource) const
+{
+ // nothing to do for default
+ return aSource;
+}
+
+basegfx::B2DRange
+ViewContact::getRange(const drawinglayer::geometry::ViewInformation2D& /*rViewInfo2D*/) const
+{
+ // Return empty range.
+ return basegfx::B2DRange();
+}
+
+void ViewContact::flushViewObjectContacts(bool bWithHierarchy)
+{
+ if (bWithHierarchy)
+ {
+ // flush DrawingLayer hierarchy
+ const sal_uInt32 nCount(GetObjectCount());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewContact& rChild = GetViewContact(a);
+ rChild.flushViewObjectContacts(bWithHierarchy);
+ }
+ }
+
+ // delete local VOCs
+ deleteAllVOCs();
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3d.cxx b/svx/source/sdr/contact/viewcontactofe3d.cxx
new file mode 100644
index 000000000..a504038ce
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3d.cxx
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <sdr/contact/viewobjectcontactofe3d.hxx>
+#include <svx/obj3d.hxx>
+#include <drawinglayer/primitive2d/embedded3dprimitive2d.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/scene3d.hxx>
+#include <drawinglayer/primitive3d/transformprimitive3d.hxx>
+#include <drawinglayer/attribute/sdrsceneattribute3d.hxx>
+#include <drawinglayer/attribute/sdrlightingattribute3d.hxx>
+#include <drawinglayer/attribute/sdrlightattribute3d.hxx>
+
+namespace {
+
+const sdr::contact::ViewContactOfE3dScene* tryToFindVCOfE3DScene(
+ const sdr::contact::ViewContact& rCandidate,
+ basegfx::B3DHomMatrix& o_rInBetweenObjectTransform)
+{
+ const sdr::contact::ViewContactOfE3dScene* pSceneParent =
+ dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(rCandidate.GetParentContact());
+
+ if(pSceneParent)
+ {
+ // each 3d object (including in-between scenes) should have a scene as parent
+ const sdr::contact::ViewContactOfE3dScene* pSceneParentParent =
+ dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(pSceneParent->GetParentContact());
+
+ if(pSceneParentParent)
+ {
+ // the parent scene of rCandidate is an in-between scene, call recursively and collect
+ // the in-between scene's object transformation part in o_rInBetweenObjectTransform
+ const basegfx::B3DHomMatrix& rSceneParentTransform = pSceneParent->GetE3dScene().GetTransform();
+ o_rInBetweenObjectTransform = rSceneParentTransform * o_rInBetweenObjectTransform;
+ return tryToFindVCOfE3DScene(*pSceneParent, o_rInBetweenObjectTransform);
+ }
+ else
+ {
+ // the parent scene is the outmost scene
+ return pSceneParent;
+ }
+ }
+
+ // object hierarchy structure is incorrect; no result
+ return nullptr;
+}
+
+} // end of anonymous namespace
+
+namespace sdr::contact {
+
+drawinglayer::primitive2d::Primitive2DContainer ViewContactOfE3d::impCreateWithGivenPrimitive3DContainer(
+ const drawinglayer::primitive3d::Primitive3DContainer& rxContent3D) const
+{
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+
+ if(!rxContent3D.empty())
+ {
+ // try to get the outmost ViewObjectContactOfE3dScene for this single 3d object,
+ // the ones on the way there are grouping scenes. Collect the in-between scene's
+ // transformations to build a correct object transformation for the embedded
+ // object
+ basegfx::B3DHomMatrix aInBetweenObjectTransform;
+ const ViewContactOfE3dScene* pVCOfE3DScene = tryToFindVCOfE3DScene(*this, aInBetweenObjectTransform);
+
+ if(pVCOfE3DScene)
+ {
+ basegfx::B3DVector aLightNormal;
+ const double fShadowSlant(pVCOfE3DScene->getSdrSceneAttribute().getShadowSlant());
+ const basegfx::B3DRange& rAllContentRange = pVCOfE3DScene->getAllContentRange3D();
+ drawinglayer::geometry::ViewInformation3D aViewInformation3D(pVCOfE3DScene->getViewInformation3D());
+
+ if(!pVCOfE3DScene->getSdrLightingAttribute().getLightVector().empty())
+ {
+ // get light normal from first light and normalize
+ aLightNormal = pVCOfE3DScene->getSdrLightingAttribute().getLightVector()[0].getDirection();
+ aLightNormal.normalize();
+ }
+
+ if(!aInBetweenObjectTransform.isIdentity())
+ {
+ // if aInBetweenObjectTransform is used, create combined ViewInformation3D which
+ // contains the correct object transformation for the embedded 3d object
+ aViewInformation3D = drawinglayer::geometry::ViewInformation3D(
+ aViewInformation3D.getObjectTransformation() * aInBetweenObjectTransform,
+ aViewInformation3D.getOrientation(),
+ aViewInformation3D.getProjection(),
+ aViewInformation3D.getDeviceToView(),
+ aViewInformation3D.getViewTime(),
+ aViewInformation3D.getExtendedInformationSequence());
+ }
+
+ // create embedded 2d primitive and add. LightNormal and ShadowSlant are needed for evtl.
+ // 3D shadow extraction for correct B2DRange calculation (shadow is part of the object)
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::Embedded3DPrimitive2D(
+ rxContent3D,
+ pVCOfE3DScene->getObjectTransformation(),
+ aViewInformation3D,
+ aLightNormal,
+ fShadowSlant,
+ rAllContentRange));
+
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
+ }
+ }
+
+ return xRetval;
+}
+
+ViewContactOfE3d::ViewContactOfE3d(E3dObject& rSdrObject)
+: ViewContactOfSdrObj(rSdrObject)
+{
+}
+
+ViewContactOfE3d::~ViewContactOfE3d()
+{
+}
+
+drawinglayer::primitive3d::Primitive3DContainer const & ViewContactOfE3d::getVIP3DSWithoutObjectTransform() const
+{
+ // local up-to-date checks. Create new list and compare.
+ drawinglayer::primitive3d::Primitive3DContainer xNew(createViewIndependentPrimitive3DContainer());
+
+ if(mxViewIndependentPrimitive3DContainer != xNew)
+ {
+ // has changed, copy content
+ const_cast< ViewContactOfE3d* >(this)->mxViewIndependentPrimitive3DContainer = xNew;
+ }
+
+ // return current Primitive2DContainer
+ return mxViewIndependentPrimitive3DContainer;
+}
+
+drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3d::getViewIndependentPrimitive3DContainer() const
+{
+ // get sequence without object transform
+ drawinglayer::primitive3d::Primitive3DContainer xRetval(getVIP3DSWithoutObjectTransform());
+
+ if(!xRetval.empty())
+ {
+ // add object transform if it's used
+ const basegfx::B3DHomMatrix& rObjectTransform(GetE3dObject().GetTransform());
+
+ if(!rObjectTransform.isIdentity())
+ {
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::TransformPrimitive3D(
+ rObjectTransform,
+ xRetval));
+
+ xRetval = { xReference };
+ }
+ }
+
+ // return current Primitive2DContainer
+ return xRetval;
+}
+
+void ViewContactOfE3d::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // also need to create a 2D embedding when the view-independent part is requested,
+ // see view-dependent part in ViewObjectContactOfE3d::createPrimitive2DSequence
+ // get 3d primitive vector, isPrimitiveVisible() is done in 3d creator
+ return rVisitor.visit(impCreateWithGivenPrimitive3DContainer(getViewIndependentPrimitive3DContainer()));
+}
+
+ViewObjectContact& ViewContactOfE3d::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfE3d(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContactOfE3d::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dcube.cxx b/svx/source/sdr/contact/viewcontactofe3dcube.cxx
new file mode 100644
index 000000000..2687aab32
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dcube.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofe3dcube.hxx>
+#include <svx/cube3d.hxx>
+#include <drawinglayer/primitive3d/sdrcubeprimitive3d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+#include <basegfx/range/b3drange.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfE3dCube::ViewContactOfE3dCube(E3dCubeObj& rCubeObj)
+ : ViewContactOfE3d(rCubeObj)
+ {
+ }
+
+ ViewContactOfE3dCube::~ViewContactOfE3dCube()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dCube::createViewIndependentPrimitive3DContainer() const
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xRetval;
+ const SfxItemSet& rItemSet = GetE3dCubeObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, false));
+
+ // get cube geometry and use as translation and scaling for unit cube
+ basegfx::B3DRange aCubeRange;
+ const basegfx::B3DVector aCubeSize(GetE3dCubeObj().GetCubeSize());
+ const basegfx::B3DPoint aCubePosition(GetE3dCubeObj().GetCubePos());
+ basegfx::B3DHomMatrix aWorldTransform;
+
+ if(GetE3dCubeObj().GetPosIsCenter())
+ {
+ const basegfx::B3DVector aHalfCubeSize(aCubeSize / 2.0);
+ aCubeRange.expand(aCubePosition - aHalfCubeSize);
+ aCubeRange.expand(aCubePosition + aHalfCubeSize);
+ }
+ else
+ {
+ aCubeRange.expand(aCubePosition);
+ aCubeRange.expand(aCubePosition + aCubeSize);
+ }
+
+ // add scale and translate to world transformation
+ const basegfx::B3DVector abjectRange(aCubeRange.getRange());
+ aWorldTransform.scale(abjectRange.getX(), abjectRange.getY(), abjectRange.getZ());
+ aWorldTransform.translate(aCubeRange.getMinX(), aCubeRange.getMinY(), aCubeRange.getMinZ());
+
+ // get 3D Object Attributes
+ drawinglayer::attribute::Sdr3DObjectAttribute aSdr3DObjectAttribute(drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet));
+
+ // calculate texture size to get a perfect mapping for
+ // the front/back sides
+ const basegfx::B2DVector aTextureSize(aCubeSize.getX(), aCubeSize.getY());
+
+ // create primitive and add
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::SdrCubePrimitive3D(
+ aWorldTransform, aTextureSize, aAttribute, aSdr3DObjectAttribute));
+ xRetval = { xReference };
+
+ return xRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dextrude.cxx b/svx/source/sdr/contact/viewcontactofe3dextrude.cxx
new file mode 100644
index 000000000..71100ae34
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dextrude.cxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofe3dextrude.hxx>
+#include <extrud3d.hxx>
+#include <drawinglayer/primitive3d/sdrextrudeprimitive3d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfE3dExtrude::ViewContactOfE3dExtrude(E3dExtrudeObj& rExtrude)
+ : ViewContactOfE3d(rExtrude)
+ {
+ }
+
+ ViewContactOfE3dExtrude::~ViewContactOfE3dExtrude()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dExtrude::createViewIndependentPrimitive3DContainer() const
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xRetval;
+ const SfxItemSet& rItemSet = GetE3dExtrudeObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, false));
+
+ // get extrude geometry
+ const basegfx::B2DPolyPolygon aPolyPolygon(GetE3dExtrudeObj().GetExtrudePolygon());
+
+ // get 3D Object Attributes
+ drawinglayer::attribute::Sdr3DObjectAttribute aSdr3DObjectAttribute(drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet));
+
+ // calculate texture size; use size of top/bottom cap to get a perfect mapping
+ // for the caps. The in-between geometry will get a stretched size with a
+ // relative factor size of caps to extrude depth
+ const basegfx::B2DRange aRange(basegfx::utils::getRange(aPolyPolygon));
+ const basegfx::B2DVector aTextureSize(aRange.getWidth(), aRange.getHeight());
+
+ // get more data
+ const double fDepth(static_cast<double>(GetE3dExtrudeObj().GetExtrudeDepth()));
+ const double fDiagonal(static_cast<double>(GetE3dExtrudeObj().GetPercentDiagonal()) / 100.0);
+ const double fBackScale(static_cast<double>(GetE3dExtrudeObj().GetPercentBackScale()) / 100.0);
+ const bool bSmoothNormals(GetE3dExtrudeObj().GetSmoothNormals()); // Plane itself
+ const bool bSmoothLids(GetE3dExtrudeObj().GetSmoothLids()); // Front/back
+ const bool bCharacterMode(GetE3dExtrudeObj().GetCharacterMode());
+ const bool bCloseFront(GetE3dExtrudeObj().GetCloseFront());
+ const bool bCloseBack(GetE3dExtrudeObj().GetCloseBack());
+
+ // create primitive and add
+ const basegfx::B3DHomMatrix aWorldTransform;
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::SdrExtrudePrimitive3D(
+ aWorldTransform, aTextureSize, aAttribute, aSdr3DObjectAttribute,
+ aPolyPolygon, fDepth, fDiagonal, fBackScale, bSmoothNormals, bSmoothLids,
+ bCharacterMode, bCloseFront, bCloseBack));
+ xRetval = { xReference };
+
+ return xRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dlathe.cxx b/svx/source/sdr/contact/viewcontactofe3dlathe.cxx
new file mode 100644
index 000000000..a3e7086b8
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dlathe.cxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofe3dlathe.hxx>
+#include <svx/lathe3d.hxx>
+#include <drawinglayer/primitive3d/sdrlatheprimitive3d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfE3dLathe::ViewContactOfE3dLathe(E3dLatheObj& rLathe)
+ : ViewContactOfE3d(rLathe)
+ {
+ }
+
+ ViewContactOfE3dLathe::~ViewContactOfE3dLathe()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dLathe::createViewIndependentPrimitive3DContainer() const
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xRetval;
+ const SfxItemSet& rItemSet = GetE3dLatheObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, false));
+
+ // get extrude geometry
+ const basegfx::B2DPolyPolygon aPolyPolygon(GetE3dLatheObj().GetPolyPoly2D());
+
+ // get 3D Object Attributes
+ drawinglayer::attribute::Sdr3DObjectAttribute aSdr3DObjectAttribute(drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet));
+
+ // calculate texture size. Use the polygon length of the longest polygon for
+ // height and the rotated radius for width (using polygon center) to get a good
+ // texture mapping
+ double fPolygonMaxLength(0.0);
+
+ for(auto const& rCandidate : aPolyPolygon)
+ {
+ const double fPolygonLength(basegfx::utils::getLength(rCandidate));
+ fPolygonMaxLength = std::max(fPolygonMaxLength, fPolygonLength);
+ }
+
+ const basegfx::B2DRange aPolyPolygonRange(basegfx::utils::getRange(aPolyPolygon));
+ const basegfx::B2DVector aTextureSize(
+ M_PI * fabs(aPolyPolygonRange.getCenter().getX()), // PI * d
+ fPolygonMaxLength);
+
+ // get more data
+ const sal_uInt32 nHorizontalSegments(GetE3dLatheObj().GetHorizontalSegments());
+ const sal_uInt32 nVerticalSegments(GetE3dLatheObj().GetVerticalSegments());
+ const double fDiagonal(static_cast<double>(GetE3dLatheObj().GetPercentDiagonal()) / 100.0);
+ const double fBackScale(static_cast<double>(GetE3dLatheObj().GetBackScale()) / 100.0);
+ const double fRotation(basegfx::deg2rad<10>(GetE3dLatheObj().GetEndAngle()));
+ const bool bSmoothNormals(GetE3dLatheObj().GetSmoothNormals()); // Plane itself
+ const bool bSmoothLids(GetE3dLatheObj().GetSmoothLids()); // Front/back
+ const bool bCharacterMode(GetE3dLatheObj().GetCharacterMode());
+ const bool bCloseFront(GetE3dLatheObj().GetCloseFront());
+ const bool bCloseBack(GetE3dLatheObj().GetCloseBack());
+
+ // create primitive and add
+ const basegfx::B3DHomMatrix aWorldTransform;
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::SdrLathePrimitive3D(
+ aWorldTransform, aTextureSize, aAttribute, aSdr3DObjectAttribute,
+ aPolyPolygon, nHorizontalSegments, nVerticalSegments,
+ fDiagonal, fBackScale, fRotation,
+ bSmoothNormals, bSmoothLids, bCharacterMode, bCloseFront, bCloseBack));
+ xRetval = { xReference };
+
+ return xRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dpolygon.cxx b/svx/source/sdr/contact/viewcontactofe3dpolygon.cxx
new file mode 100644
index 000000000..2951ead56
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dpolygon.cxx
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofe3dpolygon.hxx>
+#include <polygn3d.hxx>
+#include <drawinglayer/primitive3d/sdrpolypolygonprimitive3d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+#include <basegfx/polygon/b3dpolygon.hxx>
+#include <basegfx/polygon/b3dpolypolygontools.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfE3dPolygon::ViewContactOfE3dPolygon(E3dPolygonObj& rPolygon)
+ : ViewContactOfE3d(rPolygon)
+ {
+ }
+
+ ViewContactOfE3dPolygon::~ViewContactOfE3dPolygon()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dPolygon::createViewIndependentPrimitive3DContainer() const
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xRetval;
+ const SfxItemSet& rItemSet = GetE3dPolygonObj().GetMergedItemSet();
+ const bool bSuppressFill(GetE3dPolygonObj().GetLineOnly());
+ const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, bSuppressFill));
+
+ // get extrude geometry
+ basegfx::B3DPolyPolygon aPolyPolygon3D(GetE3dPolygonObj().GetPolyPolygon3D());
+ const basegfx::B3DPolyPolygon aPolyNormals3D(GetE3dPolygonObj().GetPolyNormals3D());
+ const basegfx::B2DPolyPolygon aPolyTexture2D(GetE3dPolygonObj().GetPolyTexture2D());
+ const bool bNormals(aPolyNormals3D.count() && aPolyNormals3D.count() == aPolyPolygon3D.count());
+ const bool bTexture(aPolyTexture2D.count() && aPolyTexture2D.count() == aPolyPolygon3D.count());
+
+ if(bNormals || bTexture)
+ {
+ for(sal_uInt32 a(0); a < aPolyPolygon3D.count(); a++)
+ {
+ basegfx::B3DPolygon aCandidate3D(aPolyPolygon3D.getB3DPolygon(a));
+ basegfx::B3DPolygon aNormals3D;
+ basegfx::B2DPolygon aTexture2D;
+
+ if(bNormals)
+ {
+ aNormals3D = aPolyNormals3D.getB3DPolygon(a);
+ }
+
+ if(bTexture)
+ {
+ aTexture2D = aPolyTexture2D.getB2DPolygon(a);
+ }
+
+ for(sal_uInt32 b(0); b < aCandidate3D.count(); b++)
+ {
+ if(bNormals)
+ {
+ sal_uInt32 nNormalCount = aNormals3D.count();
+ if( b < nNormalCount )
+ aCandidate3D.setNormal(b, aNormals3D.getB3DPoint(b));
+ else if( nNormalCount > 0 )
+ aCandidate3D.setNormal(b, aNormals3D.getB3DPoint(0));
+ }
+ if(bTexture)
+ {
+ sal_uInt32 nTextureCount = aTexture2D.count();
+ if( b < nTextureCount )
+ aCandidate3D.setTextureCoordinate(b, aTexture2D.getB2DPoint(b));
+ else if( nTextureCount > 0 )
+ aCandidate3D.setTextureCoordinate(b, aTexture2D.getB2DPoint(0));
+ }
+ }
+
+ aPolyPolygon3D.setB3DPolygon(a, aCandidate3D);
+ }
+ }
+
+ // get 3D Object Attributes
+ drawinglayer::attribute::Sdr3DObjectAttribute aSdr3DObjectAttribute(drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet));
+
+ // calculate texture size
+ basegfx::B2DVector aTextureSize(1.0, 1.0);
+
+ if(bTexture)
+ {
+ // #i98314#
+ // create texture size from object's size
+ const basegfx::B3DRange aObjectRange(basegfx::utils::getRange(aPolyPolygon3D));
+
+ double fWidth(0.0);
+ double fHeight(0.0);
+
+ // this is a polygon object, so Width/Height and/or Depth may be zero (e.g. left
+ // wall of chart). Take this into account
+ if(basegfx::fTools::equalZero(aObjectRange.getWidth()))
+ {
+ // width is zero, use height and depth
+ fWidth = aObjectRange.getHeight();
+ fHeight = aObjectRange.getDepth();
+ }
+ else if(basegfx::fTools::equalZero(aObjectRange.getHeight()))
+ {
+ // height is zero, use width and depth
+ fWidth = aObjectRange.getWidth();
+ fHeight = aObjectRange.getDepth();
+ }
+ else
+ {
+ // use width and height
+ fWidth = aObjectRange.getWidth();
+ fHeight = aObjectRange.getHeight();
+ }
+
+ if(basegfx::fTools::lessOrEqual(fWidth, 0.0) ||basegfx::fTools::lessOrEqual(fHeight, 0.0))
+ {
+ // no texture; fallback to very small size
+ aTextureSize.setX(0.01);
+ aTextureSize.setY(0.01);
+ }
+ else
+ {
+ aTextureSize.setX(fWidth);
+ aTextureSize.setY(fHeight);
+ }
+ }
+
+ // #i98295#
+ // unfortunately, this SdrObject type which allows a free 3d geometry definition was defined
+ // wrong topologically in relation to its plane normal and 3D visibility when it was invented
+ // a long time ago. Since the API allows creation of this SDrObject type, it is not possible to
+ // simply change this definition. Only the chart should use it, and at least this object type
+ // only exists at Runtime (is not saved and/or loaded in any FileFormat). Still someone external
+ // may have used it in its API. To not risk wrong 3D lightings, I have to switch the orientation
+ // of the polygon here
+ aPolyPolygon3D.flip();
+
+ // create primitive and add
+ const basegfx::B3DHomMatrix aWorldTransform;
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::SdrPolyPolygonPrimitive3D(
+ aPolyPolygon3D, aWorldTransform, aTextureSize, aAttribute, aSdr3DObjectAttribute));
+ xRetval = { xReference };
+
+ return xRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dscene.cxx b/svx/source/sdr/contact/viewcontactofe3dscene.cxx
new file mode 100644
index 000000000..6bae55263
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dscene.cxx
@@ -0,0 +1,446 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/contact/viewobjectcontactofe3dscene.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b3drange.hxx>
+#include <drawinglayer/primitive3d/baseprimitive3d.hxx>
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <drawinglayer/primitive2d/sceneprimitive2d.hxx>
+#include <drawinglayer/primitive3d/transformprimitive3d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+
+using namespace com::sun::star;
+
+namespace {
+
+// pActiveVC is only true if ghosted is still activated and maybe needs to be switched off in this path
+void createSubPrimitive3DVector(
+ const sdr::contact::ViewContact& rCandidate,
+ drawinglayer::primitive3d::Primitive3DContainer& o_rAllTarget,
+ drawinglayer::primitive3d::Primitive3DContainer* o_pVisibleTarget,
+ const SdrLayerIDSet* pVisibleSdrLayerIDSet,
+ const bool bTestSelectedVisibility)
+{
+ const sdr::contact::ViewContactOfE3dScene* pViewContactOfE3dScene = dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(&rCandidate);
+
+ if(pViewContactOfE3dScene)
+ {
+ const sal_uInt32 nChildrenCount(rCandidate.GetObjectCount());
+
+ if(nChildrenCount)
+ {
+ // provide new collection sequences
+ drawinglayer::primitive3d::Primitive3DContainer aNewAllTarget;
+ drawinglayer::primitive3d::Primitive3DContainer aNewVisibleTarget;
+
+ // add children recursively
+ for(sal_uInt32 a(0); a < nChildrenCount; a++)
+ {
+ createSubPrimitive3DVector(
+ rCandidate.GetViewContact(a),
+ aNewAllTarget,
+ o_pVisibleTarget ? &aNewVisibleTarget : nullptr,
+ pVisibleSdrLayerIDSet,
+ bTestSelectedVisibility);
+ }
+
+ // create transform primitive for the created content combining content and transformtion
+ const drawinglayer::primitive3d::Primitive3DReference xReference(new drawinglayer::primitive3d::TransformPrimitive3D(
+ pViewContactOfE3dScene->GetE3dScene().GetTransform(),
+ aNewAllTarget));
+
+ // add created content to all target
+ o_rAllTarget.push_back(xReference);
+
+ // add created content to visible target if exists
+ if(o_pVisibleTarget)
+ {
+ o_pVisibleTarget->push_back(xReference);
+ }
+ }
+ }
+ else
+ {
+ // access view independent representation of rCandidate
+ const sdr::contact::ViewContactOfE3d* pViewContactOfE3d = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&rCandidate);
+
+ if(pViewContactOfE3d)
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xPrimitive3DSeq(pViewContactOfE3d->getViewIndependentPrimitive3DContainer());
+
+ if(!xPrimitive3DSeq.empty())
+ {
+ // add to all target vector
+ o_rAllTarget.append(xPrimitive3DSeq);
+
+ if(o_pVisibleTarget)
+ {
+ // test visibility. Primitive is visible when both tests are true (AND)
+ bool bVisible(true);
+
+ if(pVisibleSdrLayerIDSet)
+ {
+ // test layer visibility
+ const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject();
+ const SdrLayerID aLayerID(rE3dObject.GetLayer());
+
+ bVisible = pVisibleSdrLayerIDSet->IsSet(aLayerID);
+ }
+
+ if(bVisible && bTestSelectedVisibility)
+ {
+ // test selected visibility (see 3D View's DrawMarkedObj implementation)
+ const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject();
+
+ bVisible = rE3dObject.GetSelected();
+ }
+
+ if (bVisible)
+ {
+ // add to visible target vector
+ o_pVisibleTarget->append(xPrimitive3DSeq);
+ }
+ }
+ }
+ }
+ }
+}
+
+}
+
+namespace sdr::contact {
+
+// Create an Object-Specific ViewObjectContact, set ViewContact and
+// ObjectContact. Always needs to return something.
+ViewObjectContact& ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfE3dScene(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+ViewContactOfE3dScene::ViewContactOfE3dScene(E3dScene& rScene)
+: ViewContactOfSdrObj(rScene)
+{
+}
+
+void ViewContactOfE3dScene::createViewInformation3D(const basegfx::B3DRange& rContentRange)
+{
+ basegfx::B3DHomMatrix aTransformation;
+ basegfx::B3DHomMatrix aOrientation;
+ basegfx::B3DHomMatrix aProjection;
+ basegfx::B3DHomMatrix aDeviceToView;
+
+ // create transformation (scene as group's transformation)
+ // For historical reasons, the outmost scene's transformation is handles as part of the
+ // view transformation. This means that the BoundRect of the contained 3D Objects is
+ // without that transformation and makes it necessary to NOT add the first scene to the
+ // Primitive3DContainer of contained objects.
+ {
+ aTransformation = GetE3dScene().GetTransform();
+ }
+
+ // create orientation (world to camera coordinate system)
+ {
+ // calculate orientation from VRP, VPN and VUV
+ const B3dCamera& rSceneCamera = GetE3dScene().GetCameraSet();
+ const basegfx::B3DPoint& aVRP(rSceneCamera.GetVRP());
+ const basegfx::B3DVector& aVPN(rSceneCamera.GetVPN());
+ const basegfx::B3DVector& aVUV(rSceneCamera.GetVUV());
+
+ aOrientation.orientation(aVRP, aVPN, aVUV);
+ }
+
+ // create projection (camera coordinate system to relative 2d where X,Y and Z are [0.0 .. 1.0])
+ {
+ const basegfx::B3DHomMatrix aWorldToCamera(aOrientation * aTransformation);
+ basegfx::B3DRange aCameraRange(rContentRange);
+ aCameraRange.transform(aWorldToCamera);
+
+ // remember Z-Values, but change orientation
+ const double fMinZ(-aCameraRange.getMaxZ());
+ const double fMaxZ(-aCameraRange.getMinZ());
+
+ // construct temporary matrix from world to device. Use unit values here to measure expansion
+ basegfx::B3DHomMatrix aWorldToDevice(aWorldToCamera);
+ const drawinglayer::attribute::SdrSceneAttribute& rSdrSceneAttribute = getSdrSceneAttribute();
+
+ if(css::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode())
+ {
+ aWorldToDevice.frustum(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ);
+ }
+ else
+ {
+ aWorldToDevice.ortho(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ);
+ }
+
+ // create B3DRange in device. This will create the real used ranges
+ // in camera space. Do not use the Z-Values, though.
+ basegfx::B3DRange aDeviceRange(rContentRange);
+ aDeviceRange.transform(aWorldToDevice);
+
+ // set projection
+ if(css::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode())
+ {
+ aProjection.frustum(
+ aDeviceRange.getMinX(), aDeviceRange.getMaxX(),
+ aDeviceRange.getMinY(), aDeviceRange.getMaxY(),
+ fMinZ, fMaxZ);
+ }
+ else
+ {
+ aProjection.ortho(
+ aDeviceRange.getMinX(), aDeviceRange.getMaxX(),
+ aDeviceRange.getMinY(), aDeviceRange.getMaxY(),
+ fMinZ, fMaxZ);
+ }
+ }
+
+ // create device to view transform
+ {
+ // create standard deviceToView projection for geometry
+ // input is [-1.0 .. 1.0] in X,Y and Z. bring to [0.0 .. 1.0]. Also
+ // necessary to flip Y due to screen orientation
+ // Z is not needed, but will also be brought to [0.0 .. 1.0]
+ aDeviceToView.scale(0.5, -0.5, 0.5);
+ aDeviceToView.translate(0.5, 0.5, 0.5);
+ }
+
+ const uno::Sequence< beans::PropertyValue > aEmptyProperties;
+ maViewInformation3D = drawinglayer::geometry::ViewInformation3D(
+ aTransformation, aOrientation, aProjection,
+ aDeviceToView, 0.0, aEmptyProperties);
+}
+
+void ViewContactOfE3dScene::createObjectTransformation()
+{
+ // create 2d Object Transformation from relative point in 2d scene to world
+ const tools::Rectangle aRectangle(GetE3dScene().GetSnapRect());
+
+ maObjectTransformation.set(0, 0, aRectangle.getWidth());
+ maObjectTransformation.set(1, 1, aRectangle.getHeight());
+ maObjectTransformation.set(0, 2, aRectangle.Left());
+ maObjectTransformation.set(1, 2, aRectangle.Top());
+}
+
+void ViewContactOfE3dScene::createSdrSceneAttribute()
+{
+ const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet();
+ maSdrSceneAttribute = drawinglayer::primitive2d::createNewSdrSceneAttribute(rItemSet);
+}
+
+void ViewContactOfE3dScene::createSdrLightingAttribute()
+{
+ const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet();
+ maSdrLightingAttribute = drawinglayer::primitive2d::createNewSdrLightingAttribute(rItemSet);
+}
+
+drawinglayer::primitive2d::Primitive2DContainer ViewContactOfE3dScene::createScenePrimitive2DSequence(
+ const SdrLayerIDSet* pLayerVisibility) const
+{
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ const sal_uInt32 nChildrenCount(GetObjectCount());
+
+ if(nChildrenCount)
+ {
+ // create 3d scene primitive with visible content tested against rLayerVisibility
+ drawinglayer::primitive3d::Primitive3DContainer aAllSequence;
+ drawinglayer::primitive3d::Primitive3DContainer aVisibleSequence;
+ const bool bTestLayerVisibility(nullptr != pLayerVisibility);
+ const bool bTestSelectedVisibility(GetE3dScene().GetDrawOnlySelected());
+ const bool bTestVisibility(bTestLayerVisibility || bTestSelectedVisibility);
+
+ // add children recursively. Do NOT start with (*this), this would create
+ // a 3D transformPrimitive for the start scene. While this is theoretically not
+ // a bad thing, for historical reasons the transformation of the outmost scene
+ // is seen as part of the ViewTransformation (see text in createViewInformation3D)
+ for(sal_uInt32 a(0); a < nChildrenCount; a++)
+ {
+ createSubPrimitive3DVector(
+ GetViewContact(a),
+ aAllSequence,
+ bTestLayerVisibility ? &aVisibleSequence : nullptr,
+ bTestLayerVisibility ? pLayerVisibility : nullptr,
+ bTestSelectedVisibility);
+ }
+
+ const size_t nAllSize(!aAllSequence.empty() ? aAllSequence.size() : 0);
+ const size_t nVisibleSize(!aVisibleSequence.empty() ? aVisibleSequence.size() : 0);
+
+ if((bTestVisibility && nVisibleSize) || nAllSize)
+ {
+ // for getting the 3D range using getB3DRangeFromPrimitive3DContainer a ViewInformation3D
+ // needs to be given for evtl. decompositions. At the same time createViewInformation3D
+ // currently is based on creating the target-ViewInformation3D using a given range. To
+ // get the true range, use a neutral ViewInformation3D here. This leaves all matrices
+ // on identity and the time on 0.0.
+ const uno::Sequence< beans::PropertyValue > aEmptyProperties;
+ const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties);
+ const basegfx::B3DRange aContentRange(aAllSequence.getB3DRange(aNeutralViewInformation3D));
+
+ // create 2d primitive 3dscene with generated sub-list from collector
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::ScenePrimitive2D(
+ bTestVisibility ? aVisibleSequence : aAllSequence,
+ getSdrSceneAttribute(),
+ getSdrLightingAttribute(),
+ getObjectTransformation(),
+ getViewInformation3D(aContentRange)));
+
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer{ xReference };
+ }
+ }
+
+ // always append an invisible outline for the cases where no visible content exists
+ xRetval.push_back(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ getObjectTransformation()));
+
+ return xRetval;
+}
+
+void ViewContactOfE3dScene::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ if(GetObjectCount())
+ {
+ // create a default ScenePrimitive2D (without visibility test of members)
+ rVisitor.visit(createScenePrimitive2DSequence(nullptr));
+ }
+}
+
+void ViewContactOfE3dScene::ActionChanged()
+{
+ // call parent
+ ViewContactOfSdrObj::ActionChanged();
+
+ // mark locally cached values as invalid
+ maViewInformation3D = drawinglayer::geometry::ViewInformation3D();
+ maObjectTransformation.identity();
+ maSdrSceneAttribute = drawinglayer::attribute::SdrSceneAttribute();
+ maSdrLightingAttribute = drawinglayer::attribute::SdrLightingAttribute();
+}
+
+const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D() const
+{
+ if(maViewInformation3D.isDefault())
+ {
+ // this version will create the content range on demand locally and thus is less
+ // performant than the other one. Since the information is buffered the planned
+ // behaviour is that the version with the given range is used initially.
+ basegfx::B3DRange aContentRange(getAllContentRange3D());
+
+ if(aContentRange.isEmpty())
+ {
+ // empty scene, no 3d action should be necessary. Prepare some
+ // fallback size
+ OSL_FAIL("No need to get ViewInformation3D from an empty scene (!)");
+ aContentRange.expand(basegfx::B3DPoint(-100.0, -100.0, -100.0));
+ aContentRange.expand(basegfx::B3DPoint( 100.0, 100.0, 100.0));
+ }
+
+ const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(aContentRange);
+ }
+
+ return maViewInformation3D;
+}
+
+const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D(const basegfx::B3DRange& rContentRange) const
+{
+ if(maViewInformation3D.isDefault())
+ {
+ const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(rContentRange);
+ }
+
+ return maViewInformation3D;
+}
+
+const basegfx::B2DHomMatrix& ViewContactOfE3dScene::getObjectTransformation() const
+{
+ if(maObjectTransformation.isIdentity())
+ {
+ const_cast < ViewContactOfE3dScene* >(this)->createObjectTransformation();
+ }
+
+ return maObjectTransformation;
+}
+
+const drawinglayer::attribute::SdrSceneAttribute& ViewContactOfE3dScene::getSdrSceneAttribute() const
+{
+ if(maSdrSceneAttribute.isDefault())
+ {
+ const_cast < ViewContactOfE3dScene* >(this)->createSdrSceneAttribute();
+ }
+
+ return maSdrSceneAttribute;
+}
+
+const drawinglayer::attribute::SdrLightingAttribute& ViewContactOfE3dScene::getSdrLightingAttribute() const
+{
+ if(maSdrLightingAttribute.isDefault())
+ {
+ const_cast < ViewContactOfE3dScene* >(this)->createSdrLightingAttribute();
+ }
+
+ return maSdrLightingAttribute;
+}
+
+drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dScene::getAllPrimitive3DContainer() const
+{
+ drawinglayer::primitive3d::Primitive3DContainer aAllPrimitive3DContainer;
+ const sal_uInt32 nChildrenCount(GetObjectCount());
+
+ // add children recursively. Do NOT start with (*this), this would create
+ // a 3D transformPrimitive for the start scene. While this is theoretically not
+ // a bad thing, for historical reasons the transformation of the outmost scene
+ // is seen as part of the ViewTransformation (see text in createViewInformation3D)
+ for(sal_uInt32 a(0); a < nChildrenCount; a++)
+ {
+ createSubPrimitive3DVector(GetViewContact(a), aAllPrimitive3DContainer, nullptr, nullptr, false);
+ }
+
+ return aAllPrimitive3DContainer;
+}
+
+basegfx::B3DRange ViewContactOfE3dScene::getAllContentRange3D() const
+{
+ const drawinglayer::primitive3d::Primitive3DContainer xAllSequence(getAllPrimitive3DContainer());
+ basegfx::B3DRange aAllContentRange3D;
+
+ if(!xAllSequence.empty())
+ {
+ // for getting the 3D range using getB3DRangeFromPrimitive3DContainer a ViewInformation3D
+ // needs to be given for evtl. decompositions. Use a neutral ViewInformation3D here. This
+ // leaves all matrices on identity and the time on 0.0.
+ const uno::Sequence< beans::PropertyValue > aEmptyProperties;
+ const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties);
+
+ aAllContentRange3D = xAllSequence.getB3DRange(aNeutralViewInformation3D);
+ }
+
+ return aAllContentRange3D;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dsphere.cxx b/svx/source/sdr/contact/viewcontactofe3dsphere.cxx
new file mode 100644
index 000000000..7a99719b8
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dsphere.cxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofe3dsphere.hxx>
+#include <svx/sphere3d.hxx>
+#include <drawinglayer/primitive3d/sdrsphereprimitive3d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfE3dSphere::ViewContactOfE3dSphere(E3dSphereObj& rSphere)
+ : ViewContactOfE3d(rSphere)
+ {
+ }
+
+ ViewContactOfE3dSphere::~ViewContactOfE3dSphere()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dSphere::createViewIndependentPrimitive3DContainer() const
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xRetval;
+ const SfxItemSet& rItemSet = GetE3dSphereObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, false));
+
+ // get sphere center and size for geometry
+ const basegfx::B3DPoint aSpherePosition(GetE3dSphereObj().Center());
+ const basegfx::B3DVector aSphereSize(GetE3dSphereObj().Size());
+ basegfx::B3DHomMatrix aWorldTransform;
+
+ aWorldTransform.translate(-0.5, -0.5, -0.5);
+ aWorldTransform.scale(aSphereSize.getX(), aSphereSize.getY(), aSphereSize.getZ());
+ aWorldTransform.translate(aSpherePosition.getX(), aSpherePosition.getY(), aSpherePosition.getZ());
+
+ // get 3D Object Attributes
+ drawinglayer::attribute::Sdr3DObjectAttribute aSdr3DObjectAttribute(drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet));
+
+ // get segment count
+ const sal_uInt32 nHorizontalSegments(GetE3dSphereObj().GetHorizontalSegments());
+ const sal_uInt32 nVerticalSegments(GetE3dSphereObj().GetVerticalSegments());
+
+ // calculate texture size, use radii for (2 * PI * r) to get a perfect
+ // mapping on the sphere
+ const basegfx::B2DVector aTextureSize(
+ M_PI * ((aSphereSize.getX() + aSphereSize.getZ()) / 2.0), // PI * d
+ M_PI_2 * aSphereSize.getY()); // half outline, (PI * d)/2 -> PI/2 * d
+
+ // create primitive and add
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::SdrSpherePrimitive3D(
+ aWorldTransform, aTextureSize, aAttribute, aSdr3DObjectAttribute,
+ nHorizontalSegments, nVerticalSegments));
+ xRetval = { xReference };
+
+ return xRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofgraphic.cxx b/svx/source/sdr/contact/viewcontactofgraphic.cxx
new file mode 100644
index 000000000..6428e5a66
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofgraphic.cxx
@@ -0,0 +1,391 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofgraphic.hxx>
+#include <sdr/contact/viewobjectcontactofgraphic.hxx>
+#include <svx/svdograf.hxx>
+#include <sdgtritm.hxx>
+#include <svx/sdgluitm.hxx>
+#include <sdgcoitm.hxx>
+#include <svx/sdggaitm.hxx>
+#include <sdginitm.hxx>
+#include <svx/sdgmoitm.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <svl/itemset.hxx>
+#include <tools/debug.hxx>
+
+#include <svx/sdgcpitm.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/primitive2d/sdrgrafprimitive2d.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/colritem.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <bitmaps.hlst>
+
+namespace sdr::contact
+{
+ // Create an Object-Specific ViewObjectContact, set ViewContact and
+ // ObjectContact. Always needs to return something.
+ ViewObjectContact& ViewContactOfGraphic::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+ {
+ ViewObjectContact* pRetval = new ViewObjectContactOfGraphic(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+ }
+
+ ViewContactOfGraphic::ViewContactOfGraphic(SdrGrafObj& rGrafObj)
+ : ViewContactOfTextObj(rGrafObj)
+ {
+ }
+
+ ViewContactOfGraphic::~ViewContactOfGraphic()
+ {
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer ViewContactOfGraphic::createVIP2DSForPresObj(
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute& rAttribute) const
+ {
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ GraphicObject aEmptyGraphicObject;
+ GraphicAttr aEmptyGraphicAttr;
+
+ // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts
+ const drawinglayer::primitive2d::Primitive2DReference xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
+ rObjectMatrix,
+ rAttribute,
+ aEmptyGraphicObject,
+ aEmptyGraphicAttr));
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReferenceA };
+
+ // SdrGrafPrimitive2D with content (which is the preview graphic) scaled to smaller size and
+ // without attributes
+ basegfx::B2DHomMatrix aSmallerMatrix;
+
+ // #i94431# for some reason, i forgot to take the PrefMapMode of the graphic
+ // into account. Since EmptyPresObj's are only used in Draw/Impress, it is
+ // safe to assume 100th mm as target.
+ Size aPrefSize(GetGrafObject().GetGrafPrefSize());
+
+ if(MapUnit::MapPixel == GetGrafObject().GetGrafPrefMapMode().GetMapUnit())
+ {
+ aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM));
+ }
+ else
+ {
+ aPrefSize = OutputDevice::LogicToLogic(aPrefSize, GetGrafObject().GetGrafPrefMapMode(), MapMode(MapUnit::Map100thMM));
+ }
+
+ // decompose object matrix to get single values
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ const double fOffsetX((aScale.getX() - aPrefSize.getWidth()) / 2.0);
+ const double fOffsetY((aScale.getY() - aPrefSize.getHeight()) / 2.0);
+
+ if(basegfx::fTools::moreOrEqual(fOffsetX, 0.0) && basegfx::fTools::moreOrEqual(fOffsetY, 0.0))
+ {
+ // create the EmptyPresObj fallback visualisation. The fallback graphic
+ // is already provided in rGraphicObject in this case, use it
+ aSmallerMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aPrefSize.getWidth(), aPrefSize.getHeight(), fOffsetX, fOffsetY);
+ aSmallerMatrix = basegfx::utils::createShearXRotateTranslateB2DHomMatrix(fShearX, fRotate, aTranslate)
+ * aSmallerMatrix;
+
+ const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject();
+ const GraphicAttr aLocalGrafInfo;
+ const drawinglayer::primitive2d::Primitive2DReference xReferenceB(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
+ aSmallerMatrix,
+ drawinglayer::attribute::SdrLineFillEffectsTextAttribute(),
+ rGraphicObject,
+ aLocalGrafInfo));
+
+ xRetval.push_back(xReferenceB);
+ }
+
+ return xRetval;
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer ViewContactOfGraphic::createVIP2DSForDraft(
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute& rAttribute) const
+ {
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ GraphicObject aEmptyGraphicObject;
+ GraphicAttr aEmptyGraphicAttr;
+
+ // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts
+ const drawinglayer::primitive2d::Primitive2DReference xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
+ rObjectMatrix,
+ rAttribute,
+ aEmptyGraphicObject,
+ aEmptyGraphicAttr));
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReferenceA };
+
+ if(rAttribute.getLine().isDefault())
+ {
+ // create a surrounding frame when no linestyle given
+ const Color aColor(Application::GetSettings().GetStyleSettings().GetShadowColor());
+ const basegfx::BColor aBColor(aColor.getBColor());
+ basegfx::B2DPolygon aOutline(basegfx::utils::createUnitPolygon());
+ aOutline.transform(rObjectMatrix);
+
+ xRetval.push_back(
+ drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ aOutline,
+ aBColor)));
+ }
+
+ // decompose object matrix to get single values
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // define a distance value, used for distance from bitmap to borders and from bitmap
+ // to text, too (2 mm)
+ const double fDistance(200.0);
+
+ // consume borders from values
+ aScale.setX(std::max(0.0, aScale.getX() - (2.0 * fDistance)));
+ aScale.setY(std::max(0.0, aScale.getY() - (2.0 * fDistance)));
+ aTranslate.setX(aTranslate.getX() + fDistance);
+ aTranslate.setY(aTranslate.getY() + fDistance);
+
+ // draw a draft bitmap
+ const BitmapEx aDraftBitmap(BMAP_GrafikEi);
+
+ if(!aDraftBitmap.IsEmpty())
+ {
+ Size aPrefSize(aDraftBitmap.GetPrefSize());
+
+ if(MapUnit::MapPixel == aDraftBitmap.GetPrefMapMode().GetMapUnit())
+ {
+ aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aDraftBitmap.GetSizePixel(), MapMode(MapUnit::Map100thMM));
+ }
+ else
+ {
+ aPrefSize = OutputDevice::LogicToLogic(aPrefSize, aDraftBitmap.GetPrefMapMode(), MapMode(MapUnit::Map100thMM));
+ }
+
+ const double fBitmapScaling(2.0);
+ const double fWidth(aPrefSize.getWidth() * fBitmapScaling);
+ const double fHeight(aPrefSize.getHeight() * fBitmapScaling);
+
+ if(basegfx::fTools::more(fWidth, 1.0)
+ && basegfx::fTools::more(fHeight, 1.0)
+ && basegfx::fTools::lessOrEqual(fWidth, aScale.getX())
+ && basegfx::fTools::lessOrEqual(fHeight, aScale.getY()))
+ {
+ const basegfx::B2DHomMatrix aBitmapMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ fWidth, fHeight, fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
+
+ xRetval.push_back(
+ drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::BitmapPrimitive2D(
+ VCLUnoHelper::CreateVCLXBitmap(aDraftBitmap),
+ aBitmapMatrix)));
+
+ // consume bitmap size in X
+ aScale.setX(std::max(0.0, aScale.getX() - (fWidth + fDistance)));
+ aTranslate.setX(aTranslate.getX() + fWidth + fDistance);
+ }
+ }
+
+ // Build the text for the draft object
+ OUString aDraftText = GetGrafObject().GetFileName();
+
+ if (aDraftText.isEmpty())
+ {
+ aDraftText = GetGrafObject().GetName() + " ...";
+ }
+
+ if (!aDraftText.isEmpty())
+ {
+ // #i103255# Goal is to produce TextPrimitives which hold the given text as
+ // BlockText in the available space. It would be very tricky to do
+ // an own word wrap/line layout here.
+ // Using SdrBlockTextPrimitive2D OTOH is critical since it internally
+ // uses the SdrObject it references. To solve this, create a temp
+ // SdrObject with Attributes and Text, generate a SdrBlockTextPrimitive2D
+ // directly and immediately decompose it. After that, it is no longer
+ // needed and can be deleted.
+
+ // create temp RectObj as TextObj and set needed attributes
+ SdrRectObj* pRectObj(new SdrRectObj(GetGrafObject().getSdrModelFromSdrObject(), SdrObjKind::Text));
+ pRectObj->NbcSetText(aDraftText);
+ pRectObj->SetMergedItem(SvxColorItem(COL_LIGHTRED, EE_CHAR_COLOR));
+
+ // get SdrText and OPO
+ SdrText* pSdrText(pRectObj->getText(0));
+ OutlinerParaObject* pOPO(pRectObj->GetOutlinerParaObject());
+
+ if(pSdrText && pOPO)
+ {
+ // directly use the remaining space as TextRangeTransform
+ const basegfx::B2DHomMatrix aTextRangeTransform(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale, fShearX, fRotate, aTranslate));
+
+ // directly create temp SdrBlockTextPrimitive2D
+ rtl::Reference< drawinglayer::primitive2d::SdrBlockTextPrimitive2D > xBlockTextPrimitive(new drawinglayer::primitive2d::SdrBlockTextPrimitive2D(
+ pSdrText,
+ *pOPO,
+ aTextRangeTransform,
+ SDRTEXTHORZADJUST_LEFT,
+ SDRTEXTVERTADJUST_TOP,
+ false,
+ false,
+ false,
+ false));
+
+ // decompose immediately with neutral ViewInformation. This will
+ // layout the text to more simple TextPrimitives from drawinglayer
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ xBlockTextPrimitive->get2DDecomposition(xRetval, aViewInformation2D);
+ }
+
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pRectObj);
+ SdrObject::Free(pTemp);
+ }
+
+ return xRetval;
+ }
+
+ void ViewContactOfGraphic::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SfxItemSet& rItemSet = GetGrafObject().GetMergedItemSet();
+
+ // create and fill GraphicAttr
+ GraphicAttr aLocalGrafInfo;
+ const sal_uInt16 nTrans(rItemSet.Get(SDRATTR_GRAFTRANSPARENCE).GetValue());
+ const SdrGrafCropItem& rCrop(rItemSet.Get(SDRATTR_GRAFCROP));
+ aLocalGrafInfo.SetLuminance(rItemSet.Get(SDRATTR_GRAFLUMINANCE).GetValue());
+ aLocalGrafInfo.SetContrast(rItemSet.Get(SDRATTR_GRAFCONTRAST).GetValue());
+ aLocalGrafInfo.SetChannelR(rItemSet.Get(SDRATTR_GRAFRED).GetValue());
+ aLocalGrafInfo.SetChannelG(rItemSet.Get(SDRATTR_GRAFGREEN).GetValue());
+ aLocalGrafInfo.SetChannelB(rItemSet.Get(SDRATTR_GRAFBLUE).GetValue());
+ aLocalGrafInfo.SetGamma(rItemSet.Get(SDRATTR_GRAFGAMMA).GetValue() * 0.01);
+ aLocalGrafInfo.SetAlpha(255 - static_cast<sal_uInt8>(::basegfx::fround(std::min(nTrans, sal_uInt16(100)) * 2.55)));
+ aLocalGrafInfo.SetInvert(rItemSet.Get(SDRATTR_GRAFINVERT).GetValue());
+ aLocalGrafInfo.SetDrawMode(rItemSet.Get(SDRATTR_GRAFMODE).GetValue());
+ aLocalGrafInfo.SetCrop(rCrop.GetLeft(), rCrop.GetTop(), rCrop.GetRight(), rCrop.GetBottom());
+
+ // we have content if graphic is not completely transparent
+ const bool bHasContent(0 != aLocalGrafInfo.GetAlpha());
+ drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ GetGrafObject().getText(0),
+ bHasContent));
+
+ // take unrotated snap rect for position and size. Directly use model data, not getBoundRect() or getSnapRect()
+ // which will use the primitive data we just create in the near future
+ const ::basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(GetGrafObject().GetGeoRect());
+
+ // look for mirroring
+ const GeoStat& rGeoStat(GetGrafObject().GetGeoStat());
+ const Degree100 nRotationAngle(rGeoStat.nRotationAngle);
+ const bool bMirrored(GetGrafObject().IsMirrored());
+
+ if (bMirrored)
+ aLocalGrafInfo.SetMirrorFlags(BmpMirrorFlags::Horizontal);
+
+ // fill object matrix
+ const double fShearX(-rGeoStat.mfTanShearAngle);
+ const double fRotate(nRotationAngle ? toRadians(36000_deg100 - nRotationAngle) : 0.0);
+ const basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ fShearX, fRotate,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // get the current, unchanged graphic object from SdrGrafObj
+ const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject();
+
+ if(visualisationUsesPresObj())
+ {
+ // it's an EmptyPresObj, create the SdrGrafPrimitive2D without content and another scaled one
+ // with the content which is the placeholder graphic
+ rVisitor.visit(createVIP2DSForPresObj(aObjectMatrix, aAttribute));
+ }
+#ifndef IOS // Enforce swap-in for tiled rendering for now, while we have no delayed updating mechanism
+ else if(visualisationUsesDraft())
+ {
+ // #i102380# The graphic is swapped out. To not force a swap-in here, there is a mechanism
+ // which shows a swapped-out-visualisation (which gets created here now) and an asynchronous
+ // visual update mechanism for swapped-out graphics when they were loaded (see AsynchGraphicLoadingEvent
+ // and ViewObjectContactOfGraphic implementation). Not forcing the swap-in here allows faster
+ // (non-blocking) processing here and thus in the effect e.g. fast scrolling through pages
+ rVisitor.visit(createVIP2DSForDraft(aObjectMatrix, aAttribute));
+ }
+#endif
+ else
+ {
+ // create primitive. Info: Calling the copy-constructor of GraphicObject in this
+ // SdrGrafPrimitive2D constructor will force a full swap-in of the graphic
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrGrafPrimitive2D(
+ aObjectMatrix,
+ aAttribute,
+ rGraphicObject,
+ aLocalGrafInfo));
+
+ rVisitor.visit(xReference);
+ }
+
+ // always append an invisible outline for the cases where no visible content exists
+ rVisitor.visit(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ aObjectMatrix));
+ }
+
+ bool ViewContactOfGraphic::visualisationUsesPresObj() const
+ {
+ return GetGrafObject().IsEmptyPresObj();
+ }
+
+ bool ViewContactOfGraphic::visualisationUsesDraft() const
+ {
+ // no draft when already PresObj
+ if(visualisationUsesPresObj())
+ return false;
+
+ // draft when swapped out
+ const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject();
+
+ // draft when no graphic
+ return GraphicType::NONE == rGraphicObject.GetType() || GraphicType::Default == rGraphicObject.GetType();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofgroup.cxx b/svx/source/sdr/contact/viewcontactofgroup.cxx
new file mode 100644
index 000000000..18e5e07aa
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofgroup.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofgroup.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <sdr/contact/viewobjectcontactofgroup.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <tools/debug.hxx>
+#include <vcl/canvastools.hxx>
+
+
+namespace sdr::contact
+{
+ // Create an Object-Specific ViewObjectContact, set ViewContact and
+ // ObjectContact. Always needs to return something.
+ ViewObjectContact& ViewContactOfGroup::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+ {
+ ViewObjectContact* pRetval = new ViewObjectContactOfGroup(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContactOfGroup::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+ }
+
+ ViewContactOfGroup::ViewContactOfGroup(SdrObjGroup& rGroup)
+ : ViewContactOfSdrObj(rGroup)
+ {
+ }
+
+ ViewContactOfGroup::~ViewContactOfGroup()
+ {
+ }
+
+ void ViewContactOfGroup::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const sal_uInt32 nObjectCount(GetObjectCount());
+
+ if(nObjectCount)
+ {
+ // collect all sub-primitives
+ for(sal_uInt32 a(0); a < nObjectCount; a++)
+ {
+ const ViewContact& rCandidate(GetViewContact(a));
+ rCandidate.getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+ }
+ else
+ {
+ // append an invisible outline for the cases where no visible content exists
+ const basegfx::B2DRange aCurrentRange = vcl::unotools::b2DRectangleFromRectangle(GetSdrObjGroup().GetLastBoundRect());
+
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ false, aCurrentRange));
+
+ rVisitor.visit(xReference);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx b/svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx
new file mode 100644
index 000000000..20463d0fc
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofmasterpagedescriptor.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <sdr/contact/viewobjectcontactofmasterpagedescriptor.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <drawinglayer/attribute/sdrfillattribute.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+
+
+namespace sdr::contact
+{
+ ViewObjectContact& ViewContactOfMasterPageDescriptor::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+ {
+ return *(new ViewObjectContactOfMasterPageDescriptor(rObjectContact, *this));
+ }
+
+ void ViewContactOfMasterPageDescriptor::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ drawinglayer::attribute::SdrFillAttribute aFill;
+ const SdrPageProperties* pCorrectProperties = GetMasterPageDescriptor().getCorrectSdrPageProperties();
+
+ if(pCorrectProperties)
+ {
+ // create page fill attributes when correct properties were identified
+ aFill = drawinglayer::primitive2d::createNewSdrFillAttribute(pCorrectProperties->GetItemSet());
+ }
+
+ if(!aFill.isDefault())
+ {
+ // direct model data is the page size, get and use it
+ const SdrPage& rOwnerPage = GetMasterPageDescriptor().GetOwnerPage();
+ const basegfx::B2DRange aInnerRange(
+ rOwnerPage.GetLeftBorder(), rOwnerPage.GetUpperBorder(),
+ rOwnerPage.GetWidth() - rOwnerPage.GetRightBorder(),
+ rOwnerPage.GetHeight() - rOwnerPage.GetLowerBorder());
+ const basegfx::B2DRange aOuterRange(
+ 0, 0, rOwnerPage.GetWidth(), rOwnerPage.GetHeight());
+ // ??? somehow only the master page's bit is used
+ bool const isFullSize(GetMasterPageDescriptor().GetUsedPage().IsBackgroundFullSize());
+ const basegfx::B2DPolygon aFillPolygon(
+ basegfx::utils::createPolygonFromRect(isFullSize ? aOuterRange : aInnerRange));
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ drawinglayer::primitive2d::createPolyPolygonFillPrimitive(
+ basegfx::B2DPolyPolygon(aFillPolygon),
+ aFill,
+ drawinglayer::attribute::FillGradientAttribute()));
+
+ rVisitor.visit(xReference);
+ }
+ }
+
+ // basic constructor
+ ViewContactOfMasterPageDescriptor::ViewContactOfMasterPageDescriptor(sdr::MasterPageDescriptor& rDescriptor)
+ : mrMasterPageDescriptor(rDescriptor)
+ {
+ }
+
+ // The destructor.
+ ViewContactOfMasterPageDescriptor::~ViewContactOfMasterPageDescriptor()
+ {
+ }
+
+ sal_uInt32 ViewContactOfMasterPageDescriptor::GetObjectCount() const
+ {
+ return GetMasterPageDescriptor().GetUsedPage().GetObjCount();
+ }
+
+ ViewContact& ViewContactOfMasterPageDescriptor::GetViewContact(sal_uInt32 nIndex) const
+ {
+ return GetMasterPageDescriptor().GetUsedPage().GetObj(nIndex)->GetViewContact();
+ }
+
+ ViewContact* ViewContactOfMasterPageDescriptor::GetParentContact() const
+ {
+ return &(GetMasterPageDescriptor().GetOwnerPage().GetViewContact());
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofpageobj.cxx b/svx/source/sdr/contact/viewcontactofpageobj.cxx
new file mode 100644
index 000000000..ffcc18fbc
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofpageobj.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofpageobj.hxx>
+#include <svx/svdopage.hxx>
+#include <vcl/canvastools.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <sdr/contact/viewobjectcontactofpageobj.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+
+namespace sdr::contact
+{
+ViewObjectContact&
+ViewContactOfPageObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageObj(rObjectContact, *this);
+ return *pRetval;
+}
+
+ViewContactOfPageObj::ViewContactOfPageObj(SdrPageObj& rPageObj)
+ : ViewContactOfSdrObj(rPageObj)
+{
+}
+
+ViewContactOfPageObj::~ViewContactOfPageObj() {}
+
+// #i35972# React on changes of the object of this ViewContact
+void ViewContactOfPageObj::ActionChanged()
+{
+ static bool bIsInActionChange(false);
+
+ if (!bIsInActionChange)
+ {
+ // set recursion flag, see description in *.hxx
+ bIsInActionChange = true;
+
+ // call parent
+ ViewContactOfSdrObj::ActionChanged();
+
+ // reset recursion flag, see description in *.hxx
+ bIsInActionChange = false;
+ }
+}
+
+void ViewContactOfPageObj::createViewIndependentPrimitive2DSequence(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // create graphical visualisation data. Since this is the view-independent version which should not be used,
+ // create a replacement graphic visualisation here. Use GetLastBoundRect to access the model data directly
+ // which is aOutRect for SdrPageObj.
+ const tools::Rectangle aModelRectangle(GetPageObj().GetLastBoundRect());
+ const basegfx::B2DRange aModelRange = vcl::unotools::b2DRectangleFromRectangle(aModelRectangle);
+ const basegfx::B2DPolygon aOutline(basegfx::utils::createPolygonFromRect(aModelRange));
+ const basegfx::BColor aYellow(1.0, 1.0, 0.0);
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aYellow));
+
+ rVisitor.visit(xReference);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx b/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx
new file mode 100644
index 000000000..2e668b4dd
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofsdrcaptionobj.hxx>
+#include <svx/svdocapt.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrcaptionprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+
+// includes for special text box shadow (SC)
+
+#include <svl/itemset.hxx>
+#include <svx/xhatch.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdprcitm.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <vcl/canvastools.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::contact
+{
+ ViewContactOfSdrCaptionObj::ViewContactOfSdrCaptionObj(SdrCaptionObj& rCaptionObj)
+ : ViewContactOfSdrRectObj(rCaptionObj)
+ {
+ }
+
+ ViewContactOfSdrCaptionObj::~ViewContactOfSdrCaptionObj()
+ {
+ }
+
+ void ViewContactOfSdrCaptionObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SdrCaptionObj& rCaptionObj(static_cast<const SdrCaptionObj&>(GetSdrObject()));
+ const SfxItemSet& rItemSet = rCaptionObj.GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ rCaptionObj.getText(0),
+ false));
+
+ // take unrotated snap rect (direct model data) for position and size
+ const tools::Rectangle aRectangle(rCaptionObj.GetGeoRect());
+ const ::basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aRectangle);
+ const GeoStat& rGeoStat(rCaptionObj.GetGeoStat());
+
+ // fill object matrix
+ basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ -rGeoStat.mfTanShearAngle,
+ rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // calculate corner radius
+ double fCornerRadiusX;
+ double fCornerRadiusY;
+ drawinglayer::primitive2d::calculateRelativeCornerRadius(
+ rCaptionObj.GetEckenradius(), aObjectRange, fCornerRadiusX, fCornerRadiusY);
+ const basegfx::B2DPolygon aTail(rCaptionObj.getTailPolygon());
+
+ // create primitive. Always create one (even if invisible) to let the decomposition
+ // of SdrCaptionPrimitive2D create needed invisible elements for HitTest and BoundRect
+ drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrCaptionPrimitive2D(
+ aObjectMatrix,
+ aAttribute,
+ aTail,
+ fCornerRadiusX,
+ fCornerRadiusY));
+
+ if(!aAttribute.isDefault() && rCaptionObj.GetSpecialTextBoxShadow())
+ {
+ // for SC, the caption object may have a specialized shadow. The usual object shadow is off
+ // and a specialized shadow gets created here (see old paint)
+ const XColorItem& rShadColItem = rItemSet.Get(SDRATTR_SHADOWCOLOR);
+ const sal_uInt16 nShadowTransparence(rItemSet.Get(SDRATTR_SHADOWTRANSPARENCE).GetValue());
+ const Color aShadowColor(rShadColItem.GetColorValue());
+ const drawing::FillStyle eShadowStyle = rItemSet.Get(XATTR_FILLSTYLE).GetValue();
+
+ // Create own ItemSet and modify as needed
+ // Always hide lines for special calc shadow
+ SfxItemSet aSet(rItemSet);
+ aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+
+ if(drawing::FillStyle_HATCH == eShadowStyle)
+ {
+ // #41666# Hatch color is set hard to shadow color
+ XHatch aHatch = rItemSet.Get(XATTR_FILLHATCH).GetHatchValue();
+ aHatch.SetColor(aShadowColor);
+ aSet.Put(XFillHatchItem(OUString(),aHatch));
+ }
+ else
+ {
+ if(drawing::FillStyle_SOLID != eShadowStyle)
+ {
+ // force fill to solid (for Gradient, Bitmap and *no* fill (#119750# not filled comments *have* shadow))
+ aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ }
+
+ aSet.Put(XFillColorItem(OUString(),aShadowColor));
+ aSet.Put(XFillTransparenceItem(nShadowTransparence));
+ }
+
+ // create FillAttribute from modified ItemSet
+ const drawinglayer::attribute::SdrFillAttribute aFill(
+ drawinglayer::primitive2d::createNewSdrFillAttribute(aSet));
+ drawinglayer::primitive2d::Primitive2DReference xSpecialShadow;
+
+ if(!aFill.isDefault() && 1.0 != aFill.getTransparence())
+ {
+ // add shadow offset to object matrix
+ const sal_uInt32 nXDist(rItemSet.Get(SDRATTR_SHADOWXDIST).GetValue());
+ const sal_uInt32 nYDist(rItemSet.Get(SDRATTR_SHADOWYDIST).GetValue());
+
+ if(nXDist || nYDist)
+ {
+ // #119750# create object and shadow outline, clip shadow outline
+ // on object outline. If there is a rest, create shadow. Do this to
+ // emulate that shadow is *not* visible behind the object for
+ // transparent object fill for comments in excel
+ basegfx::B2DPolygon aObjectOutline(
+ basegfx::utils::createPolygonFromRect(
+ basegfx::B2DRange(0.0, 0.0, 1.0, 1.0),
+ fCornerRadiusX,
+ fCornerRadiusY));
+ aObjectOutline.transform(aObjectMatrix);
+
+ // create shadow outline
+ basegfx::B2DPolygon aShadowOutline(aObjectOutline);
+ aShadowOutline.transform(
+ basegfx::utils::createTranslateB2DHomMatrix(nXDist, nYDist));
+
+ // clip shadow outline against object outline
+ const basegfx::B2DPolyPolygon aClippedShadow(
+ basegfx::utils::clipPolygonOnPolyPolygon(
+ aShadowOutline,
+ basegfx::B2DPolyPolygon(aObjectOutline),
+ false, // take the outside
+ false));
+
+ if(aClippedShadow.count())
+ {
+ // if there is shadow, create the specialized shadow primitive
+ xSpecialShadow = drawinglayer::primitive2d::createPolyPolygonFillPrimitive(
+ aClippedShadow,
+ aFill,
+ drawinglayer::attribute::FillGradientAttribute());
+ }
+ }
+ }
+
+ if(xSpecialShadow.is())
+ {
+ // if we really got a special shadow, create a two-element retval with the shadow
+ // behind the standard object's geometry
+ rVisitor.visit(std::move(xSpecialShadow));
+ }
+ }
+
+ rVisitor.visit(std::move(xReference));
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrcircobj.cxx b/svx/source/sdr/contact/viewcontactofsdrcircobj.cxx
new file mode 100644
index 000000000..042d2160a
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrcircobj.cxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofsdrcircobj.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/sdangitm.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrellipseprimitive2d.hxx>
+#include <svl/itemset.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <vcl/canvastools.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfSdrCircObj::ViewContactOfSdrCircObj(SdrCircObj& rCircObj)
+ : ViewContactOfSdrRectObj(rCircObj)
+ {
+ }
+
+ ViewContactOfSdrCircObj::~ViewContactOfSdrCircObj()
+ {
+ }
+
+ void ViewContactOfSdrCircObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SfxItemSet& rItemSet = GetCircObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ GetCircObj().getText(0),
+ false));
+
+ // take unrotated snap rect (direct model data) for position and size
+ const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(GetCircObj().GetGeoRect());
+ const GeoStat& rGeoStat(GetCircObj().GetGeoStat());
+
+ // fill object matrix
+ const basegfx::B2DHomMatrix aObjectMatrix(
+ basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ -rGeoStat.mfTanShearAngle,
+ rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // create primitive data
+ const SdrObjKind nIdentifier(GetCircObj().GetObjIdentifier());
+
+ // always create primitives to allow the decomposition of SdrEllipsePrimitive2D
+ // or SdrEllipseSegmentPrimitive2D to create needed invisible elements for HitTest
+ // and/or BoundRect
+ if(SdrObjKind::CircleOrEllipse == nIdentifier)
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrEllipsePrimitive2D(
+ aObjectMatrix,
+ aAttribute));
+
+ rVisitor.visit(xReference);
+ }
+ else
+ {
+ const auto nNewStart(rItemSet.Get(SDRATTR_CIRCSTARTANGLE).GetValue());
+ const auto nNewEnd(rItemSet.Get(SDRATTR_CIRCENDANGLE).GetValue());
+ const double fStart(toRadians((36000_deg100 - nNewEnd) % 36000_deg100));
+ const double fEnd(toRadians((36000_deg100 - nNewStart) % 36000_deg100));
+ const bool bCloseSegment(SdrObjKind::CircleArc != nIdentifier);
+ const bool bCloseUsingCenter(SdrObjKind::CircleSection == nIdentifier);
+
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrEllipseSegmentPrimitive2D(
+ aObjectMatrix,
+ aAttribute,
+ fStart,
+ fEnd,
+ bCloseSegment,
+ bCloseUsingCenter));
+
+ rVisitor.visit(xReference);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdredgeobj.cxx b/svx/source/sdr/contact/viewcontactofsdredgeobj.cxx
new file mode 100644
index 000000000..ab9587856
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdredgeobj.cxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofsdredgeobj.hxx>
+#include <svx/svdoedge.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrconnectorprimitive2d.hxx>
+#include <osl/diagnose.h>
+
+
+namespace sdr::contact
+{
+ ViewContactOfSdrEdgeObj::ViewContactOfSdrEdgeObj(SdrEdgeObj& rEdgeObj)
+ : ViewContactOfTextObj(rEdgeObj)
+ {
+ }
+
+ ViewContactOfSdrEdgeObj::~ViewContactOfSdrEdgeObj()
+ {
+ }
+
+ void ViewContactOfSdrEdgeObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const basegfx::B2DPolygon aEdgeTrack(GetEdgeObj().getEdgeTrack());
+
+ // what to do when no EdgeTrack is provided (HitTest and selectability) ?
+ OSL_ENSURE(0 != aEdgeTrack.count(), "Connectors with no geometry are not allowed (!)");
+
+ // ckeck attributes
+ const SfxItemSet& rItemSet = GetEdgeObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineEffectsTextAttribute(
+ rItemSet,
+ GetEdgeObj().getText(0)));
+
+ // create primitive. Always create primitives to allow the decomposition of
+ // SdrConnectorPrimitive2D to create needed invisible elements for HitTest
+ // and/or BoundRect
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrConnectorPrimitive2D(
+ aAttribute,
+ aEdgeTrack));
+
+ rVisitor.visit(xReference);
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrmeasureobj.cxx b/svx/source/sdr/contact/viewcontactofsdrmeasureobj.cxx
new file mode 100644
index 000000000..eb04efd71
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrmeasureobj.cxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofsdrmeasureobj.hxx>
+#include <svx/svdomeas.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <svl/itemset.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sxmbritm.hxx>
+#include <svx/sxmtritm.hxx>
+#include <sxmtaitm.hxx>
+#include <sdr/primitive2d/sdrmeasureprimitive2d.hxx>
+#include <svx/sxmtpitm.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfSdrMeasureObj::ViewContactOfSdrMeasureObj(SdrMeasureObj& rMeasureObj)
+ : ViewContactOfTextObj(rMeasureObj)
+ {
+ }
+
+ ViewContactOfSdrMeasureObj::~ViewContactOfSdrMeasureObj()
+ {
+ }
+
+ void ViewContactOfSdrMeasureObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SfxItemSet& rItemSet = GetMeasureObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineEffectsTextAttribute(
+ rItemSet,
+ GetMeasureObj().getText(0)));
+
+ // take properties which are the model data.
+ const ::basegfx::B2DPoint aStart(GetMeasureObj().GetPoint(0).X(), GetMeasureObj().GetPoint(0).Y());
+ const ::basegfx::B2DPoint aEnd(GetMeasureObj().GetPoint(1).X(), GetMeasureObj().GetPoint(1).Y());
+ const double fDistance(rItemSet.Get(SDRATTR_MEASURELINEDIST).GetValue());
+ const double fUpperDistance(rItemSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG).GetValue());
+ const double fLowerDistance(rItemSet.Get(SDRATTR_MEASUREHELPLINEDIST).GetValue());
+ const double fLeftDelta(rItemSet.Get(SDRATTR_MEASUREHELPLINE1LEN).GetValue());
+ const double fRightDelta(rItemSet.Get(SDRATTR_MEASUREHELPLINE2LEN).GetValue());
+ const bool bBelow(rItemSet.Get(SDRATTR_MEASUREBELOWREFEDGE).GetValue());
+ const bool bTextRotation(rItemSet.Get(SDRATTR_MEASURETEXTROTA90).GetValue());
+ const bool bTextAutoAngle(rItemSet.Get(SDRATTR_MEASURETEXTAUTOANGLE).GetValue());
+ drawinglayer::primitive2d::MeasureTextPosition aMTPHor(drawinglayer::primitive2d::MEASURETEXTPOSITION_AUTOMATIC);
+ drawinglayer::primitive2d::MeasureTextPosition aMTPVer(drawinglayer::primitive2d::MEASURETEXTPOSITION_AUTOMATIC);
+
+ switch(rItemSet.Get(SDRATTR_MEASURETEXTHPOS).GetValue())
+ {
+ case css::drawing::MeasureTextHorzPos::MeasureTextHorzPos_LEFTOUTSIDE:
+ {
+ aMTPHor = drawinglayer::primitive2d::MEASURETEXTPOSITION_NEGATIVE;
+ break;
+ }
+ case css::drawing::MeasureTextHorzPos::MeasureTextHorzPos_INSIDE:
+ {
+ aMTPHor = drawinglayer::primitive2d::MEASURETEXTPOSITION_CENTERED;
+ break;
+ }
+ case css::drawing::MeasureTextHorzPos::MeasureTextHorzPos_RIGHTOUTSIDE:
+ {
+ aMTPHor = drawinglayer::primitive2d::MEASURETEXTPOSITION_POSITIVE;
+ break;
+ }
+ default: // css::drawing::MeasureTextHorzPos::MeasureTextHorzPos_AUTO
+ {
+ break;
+ }
+ }
+
+ switch(rItemSet.Get(SDRATTR_MEASURETEXTVPOS).GetValue())
+ {
+ case css::drawing::MeasureTextVertPos_EAST:
+ {
+ aMTPVer = drawinglayer::primitive2d::MEASURETEXTPOSITION_NEGATIVE;
+ break;
+ }
+ case css::drawing::MeasureTextVertPos_CENTERED:
+ {
+ aMTPVer = drawinglayer::primitive2d::MEASURETEXTPOSITION_CENTERED;
+ break;
+ }
+ case css::drawing::MeasureTextVertPos_WEST:
+ {
+ aMTPVer = drawinglayer::primitive2d::MEASURETEXTPOSITION_POSITIVE;
+ break;
+ }
+ default : // css::drawing::MeasureTextVertPos_AUTO
+ {
+ break;
+ }
+ }
+
+ // create primitive with the model data. Always create primitives to allow the
+ // decomposition of SdrMeasurePrimitive2D to create needed invisible elements for HitTest
+ // and/or BoundRect
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrMeasurePrimitive2D(
+ aAttribute, aStart, aEnd,
+ aMTPHor, aMTPVer, fDistance,
+ fUpperDistance, fLowerDistance,
+ fLeftDelta, fRightDelta, bBelow,
+ bTextRotation, bTextAutoAngle));
+
+ rVisitor.visit(xReference);
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx b/svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx
new file mode 100644
index 000000000..7c713bc4b
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/sdr/contact/viewcontactofsdrmediaobj.hxx>
+#include <svx/svdomedia.hxx>
+#include <sdr/contact/viewobjectcontactofsdrmediaobj.hxx>
+#include <drawinglayer/primitive2d/mediaprimitive2d.hxx>
+#include <vcl/canvastools.hxx>
+
+namespace sdr::contact {
+
+ViewContactOfSdrMediaObj::ViewContactOfSdrMediaObj( SdrMediaObj& rMediaObj ) :
+ ViewContactOfSdrObj( rMediaObj )
+{
+}
+
+ViewContactOfSdrMediaObj::~ViewContactOfSdrMediaObj()
+{
+}
+
+ViewObjectContact& ViewContactOfSdrMediaObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ return *( new ViewObjectContactOfSdrMediaObj( rObjectContact, *this, static_cast< SdrMediaObj& >( GetSdrObject() ).getMediaProperties() ) );
+}
+
+Size ViewContactOfSdrMediaObj::getPreferredSize() const
+{
+ // #i71805# Since we may have a whole bunch of VOCs here, make a loop
+ // return first useful size -> the size from the first which is visualized as a window
+ const sal_uInt32 nCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = getViewObjectContact(a);
+ Size aSize(pCandidate ? static_cast< ViewObjectContactOfSdrMediaObj* >(pCandidate)->getPreferredSize() : Size());
+
+ if(0 != aSize.getWidth() || 0 != aSize.getHeight())
+ {
+ return aSize;
+ }
+ }
+
+ return Size();
+}
+
+void ViewContactOfSdrMediaObj::updateMediaItem( ::avmedia::MediaItem& rItem ) const
+{
+ // #i71805# Since we may have a whole bunch of VOCs here, make a loop
+ const sal_uInt32 nCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = getViewObjectContact(a);
+
+ if(pCandidate)
+ {
+ static_cast< ViewObjectContactOfSdrMediaObj* >(pCandidate)->updateMediaItem(rItem);
+ }
+ }
+}
+
+void ViewContactOfSdrMediaObj::executeMediaItem( const ::avmedia::MediaItem& rItem )
+{
+ const sal_uInt32 nCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = getViewObjectContact(a);
+
+ if(pCandidate)
+ {
+ static_cast< ViewObjectContactOfSdrMediaObj* >(pCandidate)->executeMediaItem(rItem);
+ }
+ }
+}
+
+void ViewContactOfSdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewState )
+{
+ static_cast< SdrMediaObj& >(GetSdrObject()).mediaPropertiesChanged(rNewState);
+}
+
+void ViewContactOfSdrMediaObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // create range using the model data directly. This is in SdrTextObj::aRect which i will access using
+ // GetGeoRect() to not trigger any calculations. It's the unrotated geometry which is okay for MediaObjects ATM.
+ const tools::Rectangle aRectangle(GetSdrMediaObj().GetGeoRect());
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aRectangle);
+
+ // create object transform
+ basegfx::B2DHomMatrix aTransform;
+ aTransform.set(0, 0, aRange.getWidth());
+ aTransform.set(1, 1, aRange.getHeight());
+ aTransform.set(0, 2, aRange.getMinX());
+ aTransform.set(1, 2, aRange.getMinY());
+
+ // create media primitive. Always create primitives to allow the
+ // decomposition of MediaPrimitive2D to create needed invisible elements for HitTest
+ // and/or BoundRect
+ const basegfx::BColor aBackgroundColor(67.0 / 255.0, 67.0 / 255.0, 67.0 / 255.0);
+ const OUString& rURL(GetSdrMediaObj().getURL());
+ const sal_uInt32 nPixelBorder(4);
+ const drawinglayer::primitive2d::Primitive2DReference xRetval(
+ new drawinglayer::primitive2d::MediaPrimitive2D(
+ aTransform, rURL, aBackgroundColor, nPixelBorder,
+ GetSdrMediaObj().getSnapshot()));
+
+ rVisitor.visit(xRetval);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrobj.cxx b/svx/source/sdr/contact/viewcontactofsdrobj.cxx
new file mode 100644
index 000000000..1483b5764
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrobj.cxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdobj.hxx>
+#include <tools/debug.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
+#include <svx/svdhdl.hxx>
+
+namespace sdr::contact {
+
+// Create an Object-Specific ViewObjectContact, set ViewContact and
+// ObjectContact. Always needs to return something.
+ViewObjectContact& ViewContactOfSdrObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfSdrObj(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContactOfSdrObj::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+ViewContactOfSdrObj::ViewContactOfSdrObj(SdrObject& rObj)
+: mrObject(rObj)
+{
+}
+
+ViewContactOfSdrObj::~ViewContactOfSdrObj()
+{
+}
+
+// Access to possible sub-hierarchy
+sal_uInt32 ViewContactOfSdrObj::GetObjectCount() const
+{
+ if(GetSdrObject().GetSubList())
+ {
+ return GetSdrObject().GetSubList()->GetObjCount();
+ }
+
+ return 0;
+}
+
+ViewContact& ViewContactOfSdrObj::GetViewContact(sal_uInt32 nIndex) const
+{
+ assert(GetSdrObject().GetSubList() &&
+ "ViewContactOfSdrObj::GetViewContact: Access to non-existent Sub-List (!)");
+ SdrObject* pObj = GetSdrObject().GetSubList()->GetObj(nIndex);
+ assert(pObj && "ViewContactOfSdrObj::GetViewContact: Corrupt SdrObjList (!)");
+ return pObj->GetViewContact();
+}
+
+ViewContact* ViewContactOfSdrObj::GetParentContact() const
+{
+ ViewContact* pRetval = nullptr;
+ SdrObjList* pObjList = GetSdrObject().getParentSdrObjListFromSdrObject();
+
+ if(pObjList)
+ {
+ if(auto pPage = dynamic_cast<SdrPage*>( pObjList))
+ {
+ // Is a page
+ pRetval = &(pPage->GetViewContact());
+ }
+ else
+ {
+ // Is a group?
+ if(pObjList->getSdrObjectFromSdrObjList())
+ {
+ pRetval = &(pObjList->getSdrObjectFromSdrObjList()->GetViewContact());
+ }
+ }
+ }
+
+ return pRetval;
+}
+
+// React on changes of the object of this ViewContact
+void ViewContactOfSdrObj::ActionChanged()
+{
+ // look for own changes
+ if (SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(&GetSdrObject()))
+ {
+ // tdf#146860 no idea why, but calling this makes the text boxes render properly
+ pTextObj->GetTextAniKind();
+ }
+
+ // call parent
+ ViewContact::ActionChanged();
+}
+
+// override for accessing the SdrObject
+SdrObject* ViewContactOfSdrObj::TryToGetSdrObject() const
+{
+ return &GetSdrObject();
+}
+
+
+// primitive stuff
+
+// add Gluepoints (if available)
+drawinglayer::primitive2d::Primitive2DContainer ViewContactOfSdrObj::createGluePointPrimitive2DSequence() const
+{
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ const SdrGluePointList* pGluePointList = GetSdrObject().GetGluePointList();
+
+ if(pGluePointList)
+ {
+ const sal_uInt32 nCount(pGluePointList->GetCount());
+
+ if(nCount)
+ {
+ // prepare point vector
+ std::vector< basegfx::B2DPoint > aGluepointVector;
+
+ // create GluePoint primitives. ATM these are relative to the SnapRect
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const SdrGluePoint& rCandidate = (*pGluePointList)[static_cast<sal_uInt16>(a)];
+ const Point aPosition(rCandidate.GetAbsolutePos(GetSdrObject()));
+
+ aGluepointVector.emplace_back(aPosition.X(), aPosition.Y());
+ }
+
+ if(!aGluepointVector.empty())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::MarkerArrayPrimitive2D(
+ std::move(aGluepointVector), SdrHdl::createGluePointBitmap()));
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer{ xReference };
+ }
+ }
+ }
+
+ return xRetval;
+}
+
+drawinglayer::primitive2d::Primitive2DContainer ViewContactOfSdrObj::embedToObjectSpecificInformation(drawinglayer::primitive2d::Primitive2DContainer aSource) const
+{
+ if(!aSource.empty() &&
+ (!GetSdrObject().GetName().isEmpty() ||
+ !GetSdrObject().GetTitle().isEmpty() ||
+ !GetSdrObject().GetDescription().isEmpty()))
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::ObjectInfoPrimitive2D(
+ std::move(aSource),
+ GetSdrObject().GetName(),
+ GetSdrObject().GetTitle(),
+ GetSdrObject().GetDescription()));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { xRef };
+ }
+
+ return aSource;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx b/svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx
new file mode 100644
index 000000000..e03dfced8
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofsdrobjcustomshape.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/sdooitm.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrcustomshapeprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svx/obj3d.hxx>
+#include <vcl/canvastools.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfSdrObjCustomShape::ViewContactOfSdrObjCustomShape(SdrObjCustomShape& rCustomShape)
+ : ViewContactOfTextObj(rCustomShape)
+ {
+ }
+
+ ViewContactOfSdrObjCustomShape::~ViewContactOfSdrObjCustomShape()
+ {
+ }
+
+ basegfx::B2DRange ViewContactOfSdrObjCustomShape::getCorrectedTextBoundRect() const
+ {
+ const tools::Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect());
+ tools::Rectangle aTextBound(aObjectBound);
+ GetCustomShapeObj().GetTextBounds(aTextBound);
+ basegfx::B2DRange aTextRange = vcl::unotools::b2DRectangleFromRectangle(aTextBound);
+ const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aObjectBound);
+
+ // no need to correct if no extra text range
+ if(aTextRange != aObjectRange)
+ {
+ const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat());
+
+ // only correct when rotation and/or shear is used
+ if(rGeoStat.nShearAngle || rGeoStat.nRotationAngle )
+ {
+ // text range needs to be corrected by
+ // aObjectRange.getCenter() - aRotObjectRange.getCenter() since it's
+ // defined differently by using rotation around object center. Start
+ // with positive part
+ basegfx::B2DVector aTranslation(aObjectRange.getCenter());
+
+ // get rotated and sheared object's range
+ basegfx::B2DRange aRotObjectRange(aObjectRange);
+ basegfx::B2DHomMatrix aRotMatrix;
+
+ aRotMatrix.translate(-aObjectRange.getMinimum().getX(), -aObjectRange.getMinimum().getY());
+
+ if(rGeoStat.nShearAngle)
+ {
+ aRotMatrix.shearX(-rGeoStat.mfTanShearAngle);
+ }
+
+ if(rGeoStat.nRotationAngle)
+ {
+ aRotMatrix.rotate(toRadians(36000_deg100 - rGeoStat.nRotationAngle));
+ }
+
+ aRotMatrix.translate(aObjectRange.getMinimum().getX(), aObjectRange.getMinimum().getY());
+ aRotObjectRange.transform(aRotMatrix);
+
+ // add negative translation part
+ aTranslation -= aRotObjectRange.getCenter();
+
+ // create new range
+ aTextRange = basegfx::B2DRange(
+ aTextRange.getMinX() + aTranslation.getX(), aTextRange.getMinY() + aTranslation.getY(),
+ aTextRange.getMaxX() + aTranslation.getX(), aTextRange.getMaxY() + aTranslation.getY());
+ }
+
+ // NbcMirror() of SdrTextObj (from which SdrObjCustomShape is derived), adds a
+ // 180deg rotation around the shape center to GeoStat.nRotationAngle. So remove here the
+ // 180° rotation, which was added by GetTextBounds().
+ if(GetCustomShapeObj().IsMirroredY())
+ {
+ basegfx::B2DHomMatrix aRotMatrix(basegfx::utils::createRotateAroundPoint(
+ aObjectRange.getCenterX(), aObjectRange.getCenterY(), M_PI));
+ aTextRange.transform(aRotMatrix);
+ }
+ }
+
+ return aTextRange;
+ }
+
+ void ViewContactOfSdrObjCustomShape::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SfxItemSet& rItemSet = GetCustomShapeObj().GetMergedItemSet();
+
+ // #i98072# Get shadow and text; eventually suppress the text if it's
+ // a TextPath FontworkGallery object
+ const drawinglayer::attribute::SdrEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrEffectsTextAttribute(
+ rItemSet,
+ GetCustomShapeObj().getText(0),
+ GetCustomShapeObj().IsTextPath()));
+ drawinglayer::primitive2d::Primitive2DContainer xGroup;
+ bool bHasText(!aAttribute.getText().isDefault());
+
+ // create Primitive2DContainer from sub-geometry
+ const SdrObject* pSdrObjRepresentation = GetCustomShapeObj().GetSdrObjectFromCustomShape();
+ bool b3DShape(false);
+
+ if(pSdrObjRepresentation)
+ {
+ // tdf#118498 The processing of SdrObjListIter for SdrIterMode::DeepNoGroups
+ // did change for 3D-Objects, it now correctly enters and iterates the
+ // SdrObjects in the E3dScene (same as for SdrObjGroup). This is more correct
+ // as the old version which just checked for dynamic_cast<const SdrObjGroup*>
+ // and *only* entered these, ignoring E3dScene as grouping-object.
+ // But how to fix that? Taking back the SdrObjListIter change would be easy, but
+ // not correct. After checking ViewContactOfE3dScene and ViewContactOfGroup
+ // I see that both traverse their children by themselves (on VC-Level,
+ // see createViewIndependentPrimitive2DSequence implementations and usage of
+ // GetObjectCount()). Thus in principle iterating here (esp. 'deep') seems to
+ // be wrong anyways, it might have even created wrong and double geometries
+ // (only with complex CustomShapes with multiple representation SdrObjects and
+ // only visible when transparency involved, but runtime-expensive).
+ // Thus: Just do not iterate, will check behaviour deeply.
+ b3DShape = (nullptr != dynamic_cast< const E3dObject* >(pSdrObjRepresentation));
+ pSdrObjRepresentation->GetViewContact().getViewIndependentPrimitive2DContainer(xGroup);
+ }
+
+ if(bHasText || !xGroup.empty())
+ {
+ // prepare text box geometry
+ basegfx::B2DHomMatrix aTextBoxMatrix;
+ bool bWordWrap(false);
+
+ // take unrotated snap rect as default, then get the
+ // unrotated text box. Rotation needs to be done centered
+ const tools::Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect());
+ const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aObjectBound);
+
+ if(bHasText)
+ {
+ // #i101684# get the text range unrotated and absolute to the object range
+ const basegfx::B2DRange aTextRange(getCorrectedTextBoundRect());
+
+ // Rotation before scaling
+ if(!basegfx::fTools::equalZero(GetCustomShapeObj().GetExtraTextRotation(true)))
+ {
+ basegfx::B2DVector aTranslation(0.5, 0.5);
+ aTextBoxMatrix.translate( -aTranslation.getX(), -aTranslation.getY() );
+ aTextBoxMatrix.rotate(basegfx::deg2rad(
+ 360.0 - GetCustomShapeObj().GetExtraTextRotation(true)));
+ aTextBoxMatrix.translate( aTranslation.getX(), aTranslation.getY() );
+ }
+ // give text object a size
+ aTextBoxMatrix.scale(aTextRange.getWidth(), aTextRange.getHeight());
+
+ // check if we have a rotation/shear at all to take care of
+ const double fExtraTextRotation(GetCustomShapeObj().GetExtraTextRotation());
+ const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat());
+
+ if(rGeoStat.nShearAngle || rGeoStat.nRotationAngle || !basegfx::fTools::equalZero(fExtraTextRotation))
+ {
+ if(aObjectRange != aTextRange)
+ {
+ // move relative to unrotated object range
+ aTextBoxMatrix.translate(
+ aTextRange.getMinX() - aObjectRange.getMinimum().getX(),
+ aTextRange.getMinY() - aObjectRange.getMinimum().getY());
+ }
+
+ if(!basegfx::fTools::equalZero(fExtraTextRotation))
+ {
+ basegfx::B2DVector aTranslation(
+ ( aTextRange.getWidth() / 2 ) + ( aTextRange.getMinX() - aObjectRange.getMinimum().getX() ),
+ ( aTextRange.getHeight() / 2 ) + ( aTextRange.getMinY() - aObjectRange.getMinimum().getY() ) );
+ aTextBoxMatrix.translate( -aTranslation.getX(), -aTranslation.getY() );
+ aTextBoxMatrix.rotate(basegfx::deg2rad(360.0 - fExtraTextRotation));
+ aTextBoxMatrix.translate( aTranslation.getX(), aTranslation.getY() );
+ }
+
+ if(rGeoStat.nShearAngle)
+ {
+ aTextBoxMatrix.shearX(-rGeoStat.mfTanShearAngle);
+ }
+
+ if(rGeoStat.nRotationAngle)
+ {
+ aTextBoxMatrix.rotate(toRadians(36000_deg100 - rGeoStat.nRotationAngle));
+ }
+
+ // give text it's target position
+ aTextBoxMatrix.translate(aObjectRange.getMinimum().getX(), aObjectRange.getMinimum().getY());
+ }
+ else
+ {
+ aTextBoxMatrix.translate(aTextRange.getMinX(), aTextRange.getMinY());
+ }
+
+ // check if SdrTextWordWrapItem is set
+ bWordWrap = GetCustomShapeObj().GetMergedItem(SDRATTR_TEXT_WORDWRAP).GetValue();
+ }
+
+ // fill object matrix
+ const basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ /*fShearX=*/0, /*fRotate=*/0,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // create primitive
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrCustomShapePrimitive2D(
+ aAttribute,
+ std::move(xGroup),
+ aTextBoxMatrix,
+ bWordWrap,
+ b3DShape,
+ aObjectMatrix));
+ rVisitor.visit(xReference);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrole2obj.cxx b/svx/source/sdr/contact/viewcontactofsdrole2obj.cxx
new file mode 100644
index 000000000..c1a732786
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrole2obj.cxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <drawinglayer/primitive2d/Tools.hxx>
+#include <sdr/contact/viewcontactofsdrole2obj.hxx>
+#include <svx/svdoole2.hxx>
+#include <sdr/contact/viewobjectcontactofsdrole2obj.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/primitive2d/sdrole2primitive2d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <vcl/canvastools.hxx>
+#include <tools/debug.hxx>
+#include <sdr/primitive2d/sdrolecontentprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <svx/charthelper.hxx>
+#include <svtools/embedhlp.hxx>
+
+namespace sdr::contact {
+
+// Create an Object-Specific ViewObjectContact, set ViewContact and
+// ObjectContact. Always needs to return something.
+ViewObjectContact& ViewContactOfSdrOle2Obj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfSdrOle2Obj(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+ViewContactOfSdrOle2Obj::ViewContactOfSdrOle2Obj(SdrOle2Obj& rOle2Obj)
+: ViewContactOfSdrRectObj(rOle2Obj)
+{
+}
+
+ViewContactOfSdrOle2Obj::~ViewContactOfSdrOle2Obj()
+{
+}
+
+basegfx::B2DHomMatrix ViewContactOfSdrOle2Obj::createObjectTransform() const
+{
+ // take unrotated snap rect (direct model data) for position and size
+ const tools::Rectangle aRectangle(GetOle2Obj().GetGeoRect());
+ const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aRectangle);
+
+ // create object matrix
+ const GeoStat& rGeoStat(GetOle2Obj().GetGeoStat());
+ const double fShearX(-rGeoStat.mfTanShearAngle);
+ const double fRotate(rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0);
+
+ return basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ fShearX,
+ fRotate,
+ aObjectRange.getMinX(), aObjectRange.getMinY());
+}
+
+void ViewContactOfSdrOle2Obj::createPrimitive2DSequenceWithParameters(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // get object transformation
+ const basegfx::B2DHomMatrix aObjectMatrix(createObjectTransform());
+
+ // Prepare attribute settings, will be used soon anyways
+ const SfxItemSet& rItemSet = GetOle2Obj().GetMergedItemSet();
+
+ // this may be refined more granular; if no content, attributes may get simpler
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ GetOle2Obj().getText(0),
+ true));
+ drawinglayer::primitive2d::Primitive2DReference xContent;
+
+ if(GetOle2Obj().IsChart())
+ {
+ // try to get chart primitives and chart range directly from xChartModel
+ basegfx::B2DRange aChartContentRange;
+ drawinglayer::primitive2d::Primitive2DContainer aChartSequence(
+ ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
+ GetOle2Obj().getXModel(),
+ aChartContentRange));
+ const double fWidth(aChartContentRange.getWidth());
+ const double fHeight(aChartContentRange.getHeight());
+
+ if(!aChartSequence.empty()
+ && basegfx::fTools::more(fWidth, 0.0)
+ && basegfx::fTools::more(fHeight, 0.0))
+ {
+ // create embedding transformation
+ basegfx::B2DHomMatrix aEmbed(
+ basegfx::utils::createTranslateB2DHomMatrix(
+ -aChartContentRange.getMinX(),
+ -aChartContentRange.getMinY()));
+
+ aEmbed.scale(1.0 / fWidth, 1.0 / fHeight);
+ aEmbed = aObjectMatrix * aEmbed;
+ xContent = new drawinglayer::primitive2d::TransformPrimitive2D(
+ aEmbed,
+ std::move(aChartSequence));
+ }
+ }
+
+ if(!xContent.is())
+ {
+ // #i102063# embed OLE content in an own primitive; this will be able to decompose accessing
+ // the weak SdrOle2 reference and will also implement getB2DRange() for fast BoundRect
+ // calculations without OLE Graphic access (which may trigger e.g. chart recalculation).
+ // It will also take care of HighContrast and ScaleContent
+ xContent = new drawinglayer::primitive2d::SdrOleContentPrimitive2D(
+ GetOle2Obj(),
+ aObjectMatrix,
+
+ // #i104867# add GraphicVersion number to be able to check for
+ // content change in the primitive later
+ GetOle2Obj().getEmbeddedObjectRef().getGraphicVersion() );
+ }
+
+ // create primitive. Use Ole2 primitive here. Prepare attribute settings, will
+ // be used soon anyways. Always create primitives to allow the decomposition of
+ // SdrOle2Primitive2D to create needed invisible elements for HitTest and/or BoundRect
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrOle2Primitive2D(
+ drawinglayer::primitive2d::Primitive2DContainer { xContent },
+ aObjectMatrix,
+ aAttribute));
+
+ rVisitor.visit(xReference);
+}
+
+basegfx::B2DRange ViewContactOfSdrOle2Obj::getRange( const drawinglayer::geometry::ViewInformation2D& rViewInfo2D ) const
+{
+ // this may be refined more granular; if no content, attributes may get simpler
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute =
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ GetOle2Obj().GetMergedItemSet(),
+ GetOle2Obj().getText(0),
+ true);
+
+ basegfx::B2DHomMatrix aObjectMatrix = createObjectTransform();
+
+ drawinglayer::primitive2d::Primitive2DReference xContent =
+ new drawinglayer::primitive2d::SdrOleContentPrimitive2D(
+ GetOle2Obj(),
+ aObjectMatrix,
+ GetOle2Obj().getEmbeddedObjectRef().getGraphicVersion());
+
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrOle2Primitive2D(
+ drawinglayer::primitive2d::Primitive2DContainer { xContent },
+ aObjectMatrix,
+ aAttribute));
+
+ return drawinglayer::primitive2d::getB2DRangeFromPrimitive2DReference(xReference, rViewInfo2D);
+}
+
+void ViewContactOfSdrOle2Obj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ createPrimitive2DSequenceWithParameters(rVisitor);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrpage.cxx b/svx/source/sdr/contact/viewcontactofsdrpage.cxx
new file mode 100644
index 000000000..44cccb319
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrpage.cxx
@@ -0,0 +1,598 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofsdrpage.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <sdr/contact/viewobjectcontactofsdrpage.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svtools/colorcfg.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <vcl/lazydelete.hxx>
+#include <vcl/settings.hxx>
+#include <drawinglayer/primitive2d/discreteshadowprimitive2d.hxx>
+#include <drawinglayer/attribute/sdrfillattribute.hxx>
+#include <bitmaps.hlst>
+
+namespace sdr::contact {
+
+ViewContactOfPageSubObject::ViewContactOfPageSubObject(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: mrParentViewContactOfSdrPage(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfPageSubObject::~ViewContactOfPageSubObject()
+{
+}
+
+ViewContact* ViewContactOfPageSubObject::GetParentContact() const
+{
+ return &mrParentViewContactOfSdrPage;
+}
+
+const SdrPage& ViewContactOfPageSubObject::getPage() const
+{
+ return mrParentViewContactOfSdrPage.GetSdrPage();
+}
+
+ViewObjectContact& ViewContactOfPageBackground::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageBackground(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfPageBackground::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // We have only the page information, not the view information. Use the
+ // svtools::DOCCOLOR color for initialisation
+ const svtools::ColorConfig aColorConfig;
+ const Color aInitColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
+ const basegfx::BColor aRGBColor(aInitColor.getBColor());
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::BackgroundColorPrimitive2D(aRGBColor));
+
+ rVisitor.visit(xReference);
+}
+
+ViewContactOfPageBackground::ViewContactOfPageBackground(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfPageBackground::~ViewContactOfPageBackground()
+{
+}
+
+ViewObjectContact& ViewContactOfPageShadow::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageShadow(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfPageShadow::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ static bool bUseOldPageShadow(false); // loplugin:constvars:ignore
+ const SdrPage& rPage = getPage();
+ basegfx::B2DHomMatrix aPageMatrix;
+ aPageMatrix.set(0, 0, static_cast<double>(rPage.GetWidth()));
+ aPageMatrix.set(1, 1, static_cast<double>(rPage.GetHeight()));
+
+ if(bUseOldPageShadow)
+ {
+ // create page shadow polygon
+ const double fPageBorderFactor(1.0 / 256.0);
+ basegfx::B2DPolygon aPageShadowPolygon;
+ aPageShadowPolygon.append(basegfx::B2DPoint(1.0, fPageBorderFactor));
+ aPageShadowPolygon.append(basegfx::B2DPoint(1.0 + fPageBorderFactor, fPageBorderFactor));
+ aPageShadowPolygon.append(basegfx::B2DPoint(1.0 + fPageBorderFactor, 1.0 + fPageBorderFactor));
+ aPageShadowPolygon.append(basegfx::B2DPoint(fPageBorderFactor, 1.0 + fPageBorderFactor));
+ aPageShadowPolygon.append(basegfx::B2DPoint(fPageBorderFactor, 1.0));
+ aPageShadowPolygon.append(basegfx::B2DPoint(1.0, 1.0));
+ aPageShadowPolygon.setClosed(true);
+ aPageShadowPolygon.transform(aPageMatrix);
+
+ // We have only the page information, not the view information. Use the
+ // svtools::FONTCOLOR color for initialisation
+ const svtools::ColorConfig aColorConfig;
+ const Color aShadowColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
+ const basegfx::BColor aRGBShadowColor(aShadowColor.getBColor());
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aPageShadowPolygon),
+ aRGBShadowColor));
+
+ rVisitor.visit(xReference);
+ }
+ else
+ {
+ static vcl::DeleteOnDeinit< drawinglayer::primitive2d::DiscreteShadow > aDiscreteShadow((
+ BitmapEx(SIP_SA_PAGESHADOW35X35)));
+
+ if(aDiscreteShadow.get())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::DiscreteShadowPrimitive2D(
+ aPageMatrix,
+ *aDiscreteShadow.get()));
+
+ rVisitor.visit(xReference);
+ }
+ }
+}
+
+ViewContactOfPageShadow::ViewContactOfPageShadow(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfPageShadow::~ViewContactOfPageShadow()
+{
+}
+
+ViewObjectContact& ViewContactOfMasterPage::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfMasterPage(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfMasterPage::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // this class is used when the page is a MasterPage and is responsible to
+ // create a visualisation for the MPBGO, if exists. This needs to be suppressed
+ // when a SdrPage which uses a MasterPage creates it's output. Suppression
+ // is done in the corresponding VOC since DisplayInfo data is needed
+ const SdrPage& rPage = getPage();
+
+ if(rPage.IsMasterPage())
+ {
+ if(0 == rPage.GetPageNum())
+ {
+ // #i98063#
+ // filter MasterPage 0 since it's the HandoutPage. Thus, it's a
+ // MasterPage, but has no MPBGO, so there is nothing to do here.
+ }
+ else
+ {
+ drawinglayer::attribute::SdrFillAttribute aFill;
+
+ // #i110846# Suppress SdrPage FillStyle for MasterPages without StyleSheets,
+ // else the PoolDefault (XFILL_COLOR and Blue8) will be used. Normally, all
+ // MasterPages should have a StyleSheet exactly for this reason, but historically
+ // e.g. the Notes MasterPage has no StyleSheet set (and there maybe others).
+ if(rPage.getSdrPageProperties().GetStyleSheet())
+ {
+ // create page fill attributes with correct properties
+ aFill = drawinglayer::primitive2d::createNewSdrFillAttribute(
+ rPage.getSdrPageProperties().GetItemSet());
+ }
+
+ if(!aFill.isDefault())
+ {
+ // direct model data is the page size, get and use it
+ const basegfx::B2DRange aOuterRange(
+ 0, 0, rPage.GetWidth(), rPage.GetHeight());
+ const basegfx::B2DRange aInnerRange(
+ rPage.GetLeftBorder(), rPage.GetUpperBorder(),
+ rPage.GetWidth() - rPage.GetRightBorder(), rPage.GetHeight() - rPage.GetLowerBorder());
+ bool const isFullSize(rPage.IsBackgroundFullSize());
+ const basegfx::B2DPolygon aFillPolygon(
+ basegfx::utils::createPolygonFromRect(isFullSize ? aOuterRange : aInnerRange));
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ drawinglayer::primitive2d::createPolyPolygonFillPrimitive(
+ basegfx::B2DPolyPolygon(aFillPolygon),
+ aFill,
+ drawinglayer::attribute::FillGradientAttribute()));
+
+ rVisitor.visit(xReference);
+ }
+ }
+ }
+}
+
+ViewContactOfMasterPage::ViewContactOfMasterPage(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfMasterPage::~ViewContactOfMasterPage()
+{
+}
+
+ViewObjectContact& ViewContactOfPageFill::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageFill(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfPageFill::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPage& rPage = getPage();
+ const basegfx::B2DRange aPageFillRange(0.0, 0.0, static_cast<double>(rPage.GetWidth()), static_cast<double>(rPage.GetHeight()));
+ const basegfx::B2DPolygon aPageFillPolygon(basegfx::utils::createPolygonFromRect(aPageFillRange));
+
+ // We have only the page information, not the view information. Use the
+ // svtools::DOCCOLOR color for initialisation
+ const svtools::ColorConfig aColorConfig;
+ const Color aPageFillColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
+
+ // create and add primitive
+ const basegfx::BColor aRGBColor(aPageFillColor.getBColor());
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPageFillPolygon), aRGBColor)));
+}
+
+ViewContactOfPageFill::ViewContactOfPageFill(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfPageFill::~ViewContactOfPageFill()
+{
+}
+
+ViewObjectContact& ViewContactOfOuterPageBorder::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfOuterPageBorder(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfOuterPageBorder::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPage& rPage = getPage();
+ const basegfx::B2DRange aPageBorderRange(0.0, 0.0, static_cast<double>(rPage.GetWidth()), static_cast<double>(rPage.GetHeight()));
+
+ // Changed to 0x949599 for renaissance, before svtools::FONTCOLOR was used.
+ // Added old case as fallback for HighContrast.
+ basegfx::BColor aRGBBorderColor(0x94 / double(0xff), 0x95 / double(0xff), 0x99 / double(0xff));
+
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ const svtools::ColorConfig aColorConfig;
+ const Color aBorderColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
+
+ aRGBBorderColor = aBorderColor.getBColor();
+ }
+
+ if(rPage.getPageBorderOnlyLeftRight())
+ {
+ // #i93597# for Report Designer, the page border shall be only displayed right and left,
+ // but not top and bottom. Create simplified geometry.
+ basegfx::B2DPolygon aLeft, aRight;
+
+ aLeft.append(basegfx::B2DPoint(aPageBorderRange.getMinX(), aPageBorderRange.getMinY()));
+ aLeft.append(basegfx::B2DPoint(aPageBorderRange.getMinX(), aPageBorderRange.getMaxY()));
+
+ aRight.append(basegfx::B2DPoint(aPageBorderRange.getMaxX(), aPageBorderRange.getMinY()));
+ aRight.append(basegfx::B2DPoint(aPageBorderRange.getMaxX(), aPageBorderRange.getMaxY()));
+
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aLeft, aRGBBorderColor)));
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aRight, aRGBBorderColor)));
+ }
+ else
+ {
+ const basegfx::B2DPolygon aPageBorderPolygon(basegfx::utils::createPolygonFromRect(aPageBorderRange));
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aPageBorderPolygon, aRGBBorderColor)));
+ }
+}
+
+ViewContactOfOuterPageBorder::ViewContactOfOuterPageBorder(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfOuterPageBorder::~ViewContactOfOuterPageBorder()
+{
+}
+
+ViewObjectContact& ViewContactOfInnerPageBorder::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfInnerPageBorder(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfInnerPageBorder::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPage& rPage = getPage();
+ const basegfx::B2DRange aPageBorderRange(
+ static_cast<double>(rPage.GetLeftBorder()), static_cast<double>(rPage.GetUpperBorder()),
+ static_cast<double>(rPage.GetWidth() - rPage.GetRightBorder()), static_cast<double>(rPage.GetHeight() - rPage.GetLowerBorder()));
+ const basegfx::B2DPolygon aPageBorderPolygon(basegfx::utils::createPolygonFromRect(aPageBorderRange));
+
+ // We have only the page information, not the view information. Use the
+ // svtools::FONTCOLOR or svtools::DOCBOUNDARIES color for initialisation
+ const svtools::ColorConfig aColorConfig;
+ Color aBorderColor;
+
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ aBorderColor = aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor;
+ }
+ else
+ {
+ svtools::ColorConfigValue aBorderConfig = aColorConfig.GetColorValue(svtools::DOCBOUNDARIES);
+ aBorderColor = aBorderConfig.bIsVisible ? aBorderConfig.nColor :
+ aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
+ }
+
+ // create page outer border primitive
+ const basegfx::BColor aRGBBorderColor(aBorderColor.getBColor());
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aPageBorderPolygon, aRGBBorderColor)));
+}
+
+ViewContactOfInnerPageBorder::ViewContactOfInnerPageBorder(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfInnerPageBorder::~ViewContactOfInnerPageBorder()
+{
+}
+
+ViewObjectContact& ViewContactOfPageHierarchy::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageHierarchy(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfPageHierarchy::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // collect sub-hierarchy
+ const sal_uInt32 nObjectCount(GetObjectCount());
+
+ // collect all sub-primitives
+ for(sal_uInt32 a(0); a < nObjectCount; a++)
+ {
+ const ViewContact& rCandidate(GetViewContact(a));
+ rCandidate.getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+}
+
+ViewContactOfPageHierarchy::ViewContactOfPageHierarchy(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfPageHierarchy::~ViewContactOfPageHierarchy()
+{
+}
+
+sal_uInt32 ViewContactOfPageHierarchy::GetObjectCount() const
+{
+ return getPage().GetObjCount();
+}
+
+ViewContact& ViewContactOfPageHierarchy::GetViewContact(sal_uInt32 nIndex) const
+{
+ SdrObject* pObj = getPage().GetObj(nIndex);
+ assert(pObj && "ViewContactOfPageHierarchy::GetViewContact: Corrupt SdrObjList (!)");
+ return pObj->GetViewContact();
+}
+
+ViewObjectContact& ViewContactOfGrid::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageGrid(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfGrid::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor&) const
+{
+ // We have only the page information, not the view information and thus no grid settings. Create empty
+ // default. For the view-dependent implementation, see ViewObjectContactOfPageGrid::createPrimitive2DSequence
+}
+
+ViewContactOfGrid::ViewContactOfGrid(ViewContactOfSdrPage& rParentViewContactOfSdrPage, bool bFront)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage),
+ mbFront(bFront)
+{
+}
+
+ViewContactOfGrid::~ViewContactOfGrid()
+{
+}
+
+ViewObjectContact& ViewContactOfHelplines::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageHelplines(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfHelplines::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor&) const
+{
+ // We have only the page information, not the view information and thus no helplines. Create empty
+ // default. For the view-dependent implementation, see ViewObjectContactOfPageHelplines::createPrimitive2DSequence
+}
+
+ViewContactOfHelplines::ViewContactOfHelplines(ViewContactOfSdrPage& rParentViewContactOfSdrPage, bool bFront)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage),
+ mbFront(bFront)
+{
+}
+
+ViewContactOfHelplines::~ViewContactOfHelplines()
+{
+}
+
+// Create an Object-Specific ViewObjectContact, set ViewContact and
+// ObjectContact. Always needs to return something.
+ViewObjectContact& ViewContactOfSdrPage::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfSdrPage(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+ViewContactOfSdrPage::ViewContactOfSdrPage(SdrPage& rPage)
+: mrPage(rPage),
+ maViewContactOfPageBackground(*this),
+ maViewContactOfPageShadow(*this),
+ maViewContactOfPageFill(*this),
+ maViewContactOfMasterPage(*this),
+ maViewContactOfOuterPageBorder(*this),
+ maViewContactOfInnerPageBorder(*this),
+ maViewContactOfGridBack(*this, false),
+ maViewContactOfHelplinesBack(*this, false),
+ maViewContactOfPageHierarchy(*this),
+ maViewContactOfGridFront(*this, true),
+ maViewContactOfHelplinesFront(*this, true)
+{
+}
+
+ViewContactOfSdrPage::~ViewContactOfSdrPage()
+{
+}
+
+// Access to possible sub-hierarchy
+sal_uInt32 ViewContactOfSdrPage::GetObjectCount() const
+{
+ // Fixed count of content. It contains PageBackground (Wiese), PageShadow, PageFill,
+ // then - depending on if the page has a MasterPage - either MasterPage Hierarchy
+ // or MPBGO. Also OuterPageBorder, InnerPageBorder and two pairs of Grid and Helplines
+ // (for front and back) which internally are visible or not depending on the current
+ // front/back setting for those.
+ return 11;
+}
+
+ViewContact& ViewContactOfSdrPage::GetViewContact(sal_uInt32 nIndex) const
+{
+ switch(nIndex)
+ {
+ case 0: return const_cast<ViewContactOfPageBackground&>(maViewContactOfPageBackground);
+ case 1: return const_cast<ViewContactOfPageShadow&>(maViewContactOfPageShadow);
+ case 2: return const_cast<ViewContactOfPageFill&>(maViewContactOfPageFill);
+ case 3:
+ {
+ const SdrPage& rPage = GetSdrPage();
+
+ if(rPage.TRG_HasMasterPage())
+ {
+ return rPage.TRG_GetMasterPageDescriptorViewContact();
+ }
+ else
+ {
+ return const_cast<ViewContactOfMasterPage&>(maViewContactOfMasterPage);
+ }
+ }
+ case 4: return const_cast<ViewContactOfOuterPageBorder&>(maViewContactOfOuterPageBorder);
+ case 5: return const_cast<ViewContactOfInnerPageBorder&>(maViewContactOfInnerPageBorder);
+ case 6: return const_cast<ViewContactOfGrid&>(maViewContactOfGridBack);
+ case 7: return const_cast<ViewContactOfHelplines&>(maViewContactOfHelplinesBack);
+ case 8: return const_cast<ViewContactOfPageHierarchy&>(maViewContactOfPageHierarchy);
+ case 9: return const_cast<ViewContactOfGrid&>(maViewContactOfGridFront);
+ case 10: case 11: return const_cast<ViewContactOfHelplines&>(maViewContactOfHelplinesFront);
+ default: assert(false);return const_cast<ViewContactOfHelplines&>(maViewContactOfHelplinesFront);
+ }
+}
+
+// React on changes of the object of this ViewContact
+void ViewContactOfSdrPage::ActionChanged()
+{
+ // call parent
+ ViewContact::ActionChanged();
+
+ // apply to local viewContacts, they all rely on page information. Exception
+ // is the sub hierarchy; this will not be influenced by the change
+ maViewContactOfPageBackground.ActionChanged();
+ maViewContactOfPageShadow.ActionChanged();
+ maViewContactOfPageFill.ActionChanged();
+
+ const SdrPage& rPage = GetSdrPage();
+
+ if(rPage.TRG_HasMasterPage())
+ {
+ rPage.TRG_GetMasterPageDescriptorViewContact().ActionChanged();
+ }
+ else if(rPage.IsMasterPage())
+ {
+ maViewContactOfMasterPage.ActionChanged();
+ }
+
+ maViewContactOfOuterPageBorder.ActionChanged();
+ maViewContactOfInnerPageBorder.ActionChanged();
+ maViewContactOfGridBack.ActionChanged();
+ maViewContactOfHelplinesBack.ActionChanged();
+ maViewContactOfGridFront.ActionChanged();
+ maViewContactOfHelplinesFront.ActionChanged();
+}
+
+void ViewContactOfSdrPage::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // collect all sub-sequences including sub hierarchy.
+ maViewContactOfPageBackground.getViewIndependentPrimitive2DContainer(rVisitor);
+ maViewContactOfPageShadow.getViewIndependentPrimitive2DContainer(rVisitor);
+ maViewContactOfPageFill.getViewIndependentPrimitive2DContainer(rVisitor);
+
+ const SdrPage& rPage = GetSdrPage();
+
+ if(rPage.TRG_HasMasterPage())
+ {
+ rPage.TRG_GetMasterPageDescriptorViewContact().getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+ else if(rPage.IsMasterPage())
+ {
+ maViewContactOfMasterPage.getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+
+ maViewContactOfOuterPageBorder.getViewIndependentPrimitive2DContainer(rVisitor);
+ maViewContactOfInnerPageBorder.getViewIndependentPrimitive2DContainer(rVisitor);
+ maViewContactOfPageHierarchy.getViewIndependentPrimitive2DContainer(rVisitor);
+
+ // Only add front versions of grid and helplines since no visibility test is done,
+ // so adding the back incarnations is not necessary. This makes the Front
+ // visualisation the default when no visibility tests are done.
+
+ // Since we have no view here, no grid and helpline definitions are available currently. The used
+ // methods at ViewContactOfHelplines and ViewContactOfGrid return only empty sequences and
+ // do not need to be called ATM. This may change later if grid or helpline info gets
+ // model data (it should not). Keeping the lines commented to hold this hint.
+
+ // drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xRetval, maViewContactOfGridFront.getViewIndependentPrimitive2DContainer());
+ // drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xRetval, maViewContactOfHelplinesFront.getViewIndependentPrimitive2DContainer());
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx b/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx
new file mode 100644
index 000000000..8798d40fb
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofsdrpathobj.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpage.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <sdr/primitive2d/sdrpathprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <osl/diagnose.h>
+#include <unotools/configmgr.hxx>
+#include <vcl/canvastools.hxx>
+
+namespace sdr::contact
+{
+ ViewContactOfSdrPathObj::ViewContactOfSdrPathObj(SdrPathObj& rPathObj)
+ : ViewContactOfTextObj(rPathObj)
+ {
+ }
+
+ ViewContactOfSdrPathObj::~ViewContactOfSdrPathObj()
+ {
+ }
+
+ /// return true if polycount == 1
+ static bool ensureGeometry(basegfx::B2DPolyPolygon& rUnitPolyPolygon)
+ {
+ sal_uInt32 nPolyCount(rUnitPolyPolygon.count());
+ sal_uInt32 nPointCount(0);
+
+ for(auto const& rPolygon : std::as_const(rUnitPolyPolygon))
+ {
+ nPointCount += rPolygon.count();
+ if (nPointCount > 1)
+ return false;
+ }
+
+ if(!nPointCount)
+ {
+ OSL_FAIL("PolyPolygon object without geometry detected, this should not be created (!)");
+ basegfx::B2DPolygon aFallbackLine;
+ aFallbackLine.append(basegfx::B2DPoint(0.0, 0.0));
+ aFallbackLine.append(basegfx::B2DPoint(1000.0, 1000.0));
+ rUnitPolyPolygon = basegfx::B2DPolyPolygon(aFallbackLine);
+
+ nPolyCount = 1;
+ }
+
+ return nPolyCount == 1;
+ }
+
+ void ViewContactOfSdrPathObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SfxItemSet& rItemSet = GetPathObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ GetPathObj().getText(0),
+ false));
+ basegfx::B2DPolyPolygon aUnitPolyPolygon(GetPathObj().GetPathPoly());
+ bool bPolyCountIsOne(ensureGeometry(aUnitPolyPolygon));
+
+ // prepare object transformation and unit polygon (direct model data)
+ basegfx::B2DHomMatrix aObjectMatrix;
+ basegfx::B2DPolyPolygon aUnitDefinitionPolyPolygon;
+ bool bIsLine(
+ !aUnitPolyPolygon.areControlPointsUsed()
+ && bPolyCountIsOne
+ && 2 == aUnitPolyPolygon.getB2DPolygon(0).count());
+
+ if(bIsLine)
+ {
+ //tdf#63955 if we have an extremely long line then clip it to a
+ //very generous range of -1 page width/height vs +1 page
+ //width/height to avoid oom and massive churn generating a huge
+ //polygon chain to cover the length in applyLineDashing if this
+ //line is dashed
+ const SdrPage* pPage(GetPathObj().getSdrPageFromSdrObject());
+ sal_Int32 nPageWidth = pPage ? pPage->GetWidth() : 0;
+ sal_Int32 nPageHeight = pPage ? pPage->GetHeight() : 0;
+
+ //But, see tdf#101187, only do this if our generous clip region
+ //would not over flow into a tiny clip region
+ if (nPageWidth < SAL_MAX_INT32/2 && nPageHeight < SAL_MAX_INT32/2 && !utl::ConfigManager::IsFuzzing())
+ {
+ //But, see tdf#97276, tdf#126184 and tdf#98366. Don't clip too much if the
+ //underlying page dimension is unknown or a paste document
+ //where the page sizes use the odd default of 10x10
+ const sal_Int32 nMaxPaperWidth = SvtOptionsDrawinglayer::GetMaximumPaperWidth() * 1000;
+ const sal_Int32 nMaxPaperHeight = SvtOptionsDrawinglayer::GetMaximumPaperHeight() * 1000;
+ nPageWidth = std::max<sal_Int32>(nPageWidth, nMaxPaperWidth);
+ nPageHeight = std::max<sal_Int32>(nPageHeight, nMaxPaperHeight);
+ basegfx::B2DRange aClipRange(-nPageWidth, -nPageHeight,
+ nPageWidth*2, nPageHeight*2);
+
+ aUnitPolyPolygon = basegfx::utils::clipPolyPolygonOnRange(aUnitPolyPolygon,
+ aClipRange, true, true);
+ bPolyCountIsOne = ensureGeometry(aUnitPolyPolygon);
+
+ // re-check that we have't been clipped out to oblivion
+ bIsLine =
+ !aUnitPolyPolygon.areControlPointsUsed()
+ && bPolyCountIsOne
+ && 2 == aUnitPolyPolygon.getB2DPolygon(0).count();
+ }
+ }
+
+ if(bIsLine)
+ {
+
+ // special handling for single line mode (2 points)
+ const basegfx::B2DPolygon aSubPolygon(aUnitPolyPolygon.getB2DPolygon(0));
+ const basegfx::B2DPoint aStart(aSubPolygon.getB2DPoint(0));
+ const basegfx::B2DPoint aEnd(aSubPolygon.getB2DPoint(1));
+ const basegfx::B2DVector aLine(aEnd - aStart);
+
+ // #i102548# create new unit polygon for line (horizontal)
+ basegfx::B2DPolygon aNewPolygon;
+ aNewPolygon.append(basegfx::B2DPoint(0.0, 0.0));
+ aNewPolygon.append(basegfx::B2DPoint(1.0, 0.0));
+ aUnitPolyPolygon.setB2DPolygon(0, aNewPolygon);
+
+ // #i102548# fill objectMatrix with rotation and offset (no shear for lines)
+ aObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aLine.getLength(), 1.0,
+ 0.0,
+ atan2(aLine.getY(), aLine.getX()),
+ aStart.getX(), aStart.getY());
+ }
+ else
+ {
+ // #i102548# create unscaled, unsheared, unrotated and untranslated polygon
+ // (unit polygon) by creating the object matrix and back-transforming the polygon
+ const basegfx::B2DRange aObjectRange(basegfx::utils::getRange(aUnitPolyPolygon));
+ const GeoStat& rGeoStat(GetPathObj().GetGeoStat());
+ const double fWidth(aObjectRange.getWidth());
+ const double fHeight(aObjectRange.getHeight());
+ const double fScaleX(basegfx::fTools::equalZero(fWidth) ? 1.0 : fWidth);
+ const double fScaleY(basegfx::fTools::equalZero(fHeight) ? 1.0 : fHeight);
+
+ aObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ fScaleX, fScaleY,
+ -rGeoStat.mfTanShearAngle,
+ rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0,
+ aObjectRange.getMinX(), aObjectRange.getMinY());
+
+ // create unit polygon from object's absolute path
+ basegfx::B2DHomMatrix aInverse(aObjectMatrix);
+ aInverse.invert();
+ aUnitPolyPolygon.transform(aInverse);
+
+ // OperationSmiley: Check if a FillGeometryDefiningShape is set
+ const SdrObject* pFillGeometryDefiningShape(GetPathObj().getFillGeometryDefiningShape());
+
+ if(nullptr != pFillGeometryDefiningShape)
+ {
+ // If yes, get it's BoundRange and use as defining Geometry for the FillStyle.
+ // If no, aUnitDefinitionPolyPolygon will just be empty and thus be interpreted
+ // as unused.
+ // Using SnapRect will make the FillDefinition to always be extended e.g.
+ // for rotated/sheared objects.
+ const tools::Rectangle& rSnapRect(pFillGeometryDefiningShape->GetSnapRect());
+
+ aUnitDefinitionPolyPolygon.append(
+ basegfx::utils::createPolygonFromRect(
+ vcl::unotools::b2DRectangleFromRectangle(rSnapRect)));
+
+ // use same coordinate system as the shape geometry -> this
+ // makes it relative to shape's unit geometry and thus freely
+ // transformable with the shape
+ aUnitDefinitionPolyPolygon.transform(aInverse);
+ }
+ }
+
+ // create primitive. Always create primitives to allow the decomposition of
+ // SdrPathPrimitive2D to create needed invisible elements for HitTest and/or BoundRect
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrPathPrimitive2D(
+ aObjectMatrix,
+ aAttribute,
+ aUnitPolyPolygon,
+ aUnitDefinitionPolyPolygon));
+
+ rVisitor.visit(xReference);
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx b/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx
new file mode 100644
index 000000000..6d9ed7bed
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofsdrrectobj.hxx>
+#include <svx/svdorect.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrrectangleprimitive2d.hxx>
+#include <svl/itemset.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svx/svdmodel.hxx>
+#include <vcl/canvastools.hxx>
+#include <svx/sdmetitm.hxx>
+
+namespace sdr::contact {
+
+ViewContactOfSdrRectObj::ViewContactOfSdrRectObj(SdrRectObj& rRectObj)
+: ViewContactOfTextObj(rRectObj)
+{
+}
+
+ViewContactOfSdrRectObj::~ViewContactOfSdrRectObj()
+{
+}
+
+void ViewContactOfSdrRectObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SfxItemSet& rItemSet = GetRectObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ GetRectObj().getText(0),
+ false));
+
+ // take unrotated snap rect (direct model data) for position and size
+ const tools::Rectangle aRectangle(GetRectObj().GetGeoRect());
+ const ::basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aRectangle);
+
+ const GeoStat& rGeoStat(GetRectObj().GetGeoStat());
+
+ // fill object matrix
+ basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ -rGeoStat.mfTanShearAngle,
+ rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // calculate corner radius
+ sal_uInt32 nCornerRadius(rItemSet.Get(SDRATTR_CORNER_RADIUS).GetValue());
+ double fCornerRadiusX;
+ double fCornerRadiusY;
+ drawinglayer::primitive2d::calculateRelativeCornerRadius(nCornerRadius, aObjectRange, fCornerRadiusX, fCornerRadiusY);
+
+ // #i105856# use knowledge about pickthrough from the model
+ const bool bPickThroughTransparentTextFrames(GetRectObj().getSdrModelFromSdrObject().IsPickThroughTransparentTextFrames());
+
+ // create primitive. Always create primitives to allow the decomposition of
+ // SdrRectanglePrimitive2D to create needed invisible elements for HitTest and/or BoundRect
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrRectanglePrimitive2D(
+ aObjectMatrix,
+ aAttribute,
+ fCornerRadiusX,
+ fCornerRadiusY,
+ // #i105856# use fill for HitTest when TextFrame and not PickThrough
+ GetRectObj().IsTextFrame() && !bPickThroughTransparentTextFrames));
+
+ rVisitor.visit(xReference);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactoftextobj.cxx b/svx/source/sdr/contact/viewcontactoftextobj.cxx
new file mode 100644
index 000000000..9e10d0130
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactoftextobj.cxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactoftextobj.hxx>
+#include <svx/svdotext.hxx>
+
+namespace sdr::contact
+{
+ViewContactOfTextObj::ViewContactOfTextObj(SdrTextObj& rTextObj)
+ : ViewContactOfSdrObj(rTextObj)
+{
+}
+
+ViewContactOfTextObj::~ViewContactOfTextObj() {}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofunocontrol.cxx b/svx/source/sdr/contact/viewcontactofunocontrol.cxx
new file mode 100644
index 000000000..f99b24372
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofunocontrol.cxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/contact/viewcontactofunocontrol.hxx>
+#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sdrpagewindow.hxx>
+
+#include <vcl/canvastools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <osl/diagnose.h>
+
+
+namespace sdr::contact {
+
+
+ using ::com::sun::star::awt::XControl;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::awt::XControlContainer;
+ using ::com::sun::star::awt::XControlModel;
+
+
+ //= ViewContactOfUnoControl
+
+ ViewContactOfUnoControl::ViewContactOfUnoControl( SdrUnoObj& _rUnoObject )
+ :ViewContactOfSdrObj( _rUnoObject )
+ {
+ }
+
+
+ ViewContactOfUnoControl::~ViewContactOfUnoControl()
+ {
+ }
+
+
+ Reference< XControl > ViewContactOfUnoControl::getTemporaryControlForWindow(
+ const vcl::Window& _rWindow, Reference< XControlContainer >& _inout_ControlContainer ) const
+ {
+ SdrUnoObj* pUnoObject = dynamic_cast< SdrUnoObj* >( TryToGetSdrObject() );
+ OSL_ENSURE( pUnoObject, "ViewContactOfUnoControl::getTemporaryControlForDevice: no SdrUnoObj!" );
+ if ( !pUnoObject )
+ return nullptr;
+ return ViewObjectContactOfUnoControl::getTemporaryControlForWindow( _rWindow, _inout_ControlContainer, *pUnoObject );
+ }
+
+
+ ViewObjectContact& ViewContactOfUnoControl::CreateObjectSpecificViewObjectContact( ObjectContact& _rObjectContact )
+ {
+ // print or print preview requires special handling
+ const OutputDevice* pDevice = _rObjectContact.TryToGetOutputDevice();
+ ObjectContactOfPageView* const pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &_rObjectContact );
+
+ const bool bPrintOrPreview = pPageViewContact
+ && ( ( ( pDevice != nullptr ) && ( pDevice->GetOutDevType() == OUTDEV_PRINTER ) )
+ || pPageViewContact->GetPageWindow().GetPageView().GetView().IsPrintPreview()
+ )
+ ;
+
+ if ( bPrintOrPreview )
+ return *new UnoControlPrintOrPreviewContact( *pPageViewContact, *this );
+
+ // all others are nowadays served by the same implementation
+ return *new ViewObjectContactOfUnoControl( _rObjectContact, *this );
+ }
+
+
+ void ViewContactOfUnoControl::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // create range. Use model data directly, not getBoundRect()/getSnapRect; these will use
+ // the primitive data themselves in the long run. Use SdrUnoObj's (which is a SdrRectObj)
+ // call to GetGeoRect() to access SdrTextObj::aRect directly and without executing anything
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(GetSdrUnoObj().GetGeoRect());
+
+ // create object transform
+ basegfx::B2DHomMatrix aTransform;
+
+ aTransform.set(0, 0, aRange.getWidth());
+ aTransform.set(1, 1, aRange.getHeight());
+ aTransform.set(0, 2, aRange.getMinX());
+ aTransform.set(1, 2, aRange.getMinY());
+
+ Reference< XControlModel > xControlModel = GetSdrUnoObj().GetUnoControlModel();
+
+ if(xControlModel.is())
+ {
+ // create control primitive WITHOUT possibly existing XControl; this would be done in
+ // the VOC in createPrimitive2DSequence()
+ const drawinglayer::primitive2d::Primitive2DReference xRetval(
+ new drawinglayer::primitive2d::ControlPrimitive2D(
+ aTransform,
+ xControlModel));
+
+ rVisitor.visit(xRetval);
+ }
+ else
+ {
+ // always append an invisible outline for the cases where no visible content exists
+ const drawinglayer::primitive2d::Primitive2DReference xRetval(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ aTransform));
+
+ rVisitor.visit(xRetval);
+ }
+ }
+
+
+} // namespace sdr::contact
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofvirtobj.cxx b/svx/source/sdr/contact/viewcontactofvirtobj.cxx
new file mode 100644
index 000000000..f4087d036
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofvirtobj.cxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewcontactofvirtobj.hxx>
+#include <svx/svdovirt.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+
+namespace sdr::contact {
+
+ViewContactOfVirtObj::ViewContactOfVirtObj(SdrVirtObj& rObj)
+: ViewContactOfSdrObj(rObj)
+{
+}
+
+ViewContactOfVirtObj::~ViewContactOfVirtObj()
+{
+}
+
+SdrVirtObj& ViewContactOfVirtObj::GetVirtObj() const
+{
+ return static_cast<SdrVirtObj&>(mrObject);
+}
+
+// Access to possible sub-hierarchy
+sal_uInt32 ViewContactOfVirtObj::GetObjectCount() const
+{
+ // Here, SdrVirtObj's need to return 0L to show that they have no
+ // sub-hierarchy, even when they are group objects. This is necessary
+ // to avoid that the same VOCs will be added to the draw hierarchy
+ // twice which leads to problems.
+
+ // This solution is only a first solution to get things running. Later
+ // this needs to be replaced with creating real VOCs for the objects
+ // referenced by virtual objects to avoid the 'trick' of setting the
+ // offset for painting at the destination OutputDevice.
+
+ // As can be seen, with primitives, the problem will be solved using
+ // a transformPrimitive, so this solution can stay with primitives.
+ return 0;
+}
+
+void ViewContactOfVirtObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // create displacement transformation if we have content
+ basegfx::B2DHomMatrix aObjectMatrix;
+ Point aAnchor(GetVirtObj().GetAnchorPos());
+
+ if(aAnchor.X() || aAnchor.Y())
+ {
+ aObjectMatrix.set(0, 2, aAnchor.X());
+ aObjectMatrix.set(1, 2, aAnchor.Y());
+ }
+
+ // use method from referenced object to get the Primitive2DContainer
+ drawinglayer::primitive2d::Primitive2DContainer xSequenceVirtual;
+ GetVirtObj().GetReferencedObj().GetViewContact().getViewIndependentPrimitive2DContainer(xSequenceVirtual);
+
+ if(!xSequenceVirtual.empty())
+ {
+ // create transform primitive
+ drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aObjectMatrix,
+ drawinglayer::primitive2d::Primitive2DContainer(xSequenceVirtual)));
+
+ rVisitor.visit(xReference);
+ }
+ else
+ {
+ // always append an invisible outline for the cases where no visible content exists
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ aObjectMatrix));
+
+ rVisitor.visit(xReference);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx b/svx/source/sdr/contact/viewobjectcontact.cxx
new file mode 100644
index 000000000..18acd5e52
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -0,0 +1,570 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/animation/animationstate.hxx>
+#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdotext.hxx>
+#include <vcl/pdfwriter.hxx>
+
+using namespace com::sun::star;
+
+namespace {
+
+// animated extractor
+
+// Necessary to filter a sequence of animated primitives from
+// a sequence of primitives to find out if animated or not. The decision for
+// what to decompose is hard-coded and only done for knowingly animated primitives
+// to not decompose too deeply and unnecessarily. This implies that the list
+// which is view-specific needs to be expanded by hand when new animated objects
+// are added. This may eventually be changed to a dynamically configurable approach
+// if necessary.
+class AnimatedExtractingProcessor2D : public drawinglayer::processor2d::BaseProcessor2D
+{
+protected:
+ // the found animated primitives
+ drawinglayer::primitive2d::Primitive2DContainer maPrimitive2DSequence;
+
+ // text animation allowed?
+ bool mbTextAnimationAllowed : 1;
+
+ // graphic animation allowed?
+ bool mbGraphicAnimationAllowed : 1;
+
+ // as tooling, the process() implementation takes over API handling and calls this
+ // virtual render method when the primitive implementation is BasePrimitive2D-based.
+ virtual void processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D& rCandidate) override;
+
+public:
+ AnimatedExtractingProcessor2D(
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation,
+ bool bTextAnimationAllowed,
+ bool bGraphicAnimationAllowed);
+
+ // data access
+ const drawinglayer::primitive2d::Primitive2DContainer& getPrimitive2DSequence() const { return maPrimitive2DSequence; }
+ drawinglayer::primitive2d::Primitive2DContainer extractPrimitive2DSequence() const { return std::move(maPrimitive2DSequence); }
+};
+
+AnimatedExtractingProcessor2D::AnimatedExtractingProcessor2D(
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation,
+ bool bTextAnimationAllowed,
+ bool bGraphicAnimationAllowed)
+: drawinglayer::processor2d::BaseProcessor2D(rViewInformation),
+ mbTextAnimationAllowed(bTextAnimationAllowed),
+ mbGraphicAnimationAllowed(bGraphicAnimationAllowed)
+{
+}
+
+void AnimatedExtractingProcessor2D::processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D& rCandidate)
+{
+ // known implementation, access directly
+ switch(rCandidate.getPrimitive2DID())
+ {
+ // add and accept animated primitives directly, no need to decompose
+ case PRIMITIVE2D_ID_ANIMATEDSWITCHPRIMITIVE2D :
+ case PRIMITIVE2D_ID_ANIMATEDBLINKPRIMITIVE2D :
+ case PRIMITIVE2D_ID_ANIMATEDINTERPOLATEPRIMITIVE2D :
+ {
+ const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D& rSwitchPrimitive = static_cast< const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D& >(rCandidate);
+
+ if((rSwitchPrimitive.isTextAnimation() && mbTextAnimationAllowed)
+ || (rSwitchPrimitive.isGraphicAnimation() && mbGraphicAnimationAllowed))
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xReference(const_cast< drawinglayer::primitive2d::BasePrimitive2D* >(&rCandidate));
+ maPrimitive2DSequence.push_back(xReference);
+ }
+ break;
+ }
+
+ // decompose animated gifs where SdrGrafPrimitive2D produces a GraphicPrimitive2D
+ // which then produces the animation infos (all when used/needed)
+ case PRIMITIVE2D_ID_SDRGRAFPRIMITIVE2D :
+ case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
+
+ // decompose SdrObjects with evtl. animated text
+ case PRIMITIVE2D_ID_SDRCAPTIONPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRCONNECTORPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRCUSTOMSHAPEPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRELLIPSEPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRELLIPSESEGMENTPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRPATHPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRRECTANGLEPRIMITIVE2D :
+
+ // #121194# With Graphic as Bitmap FillStyle, also check
+ // for primitives filled with animated graphics
+ case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D:
+ case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D:
+ case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D:
+
+ // decompose evtl. animated text contained in MaskPrimitive2D
+ // or group primitives
+ case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
+ case PRIMITIVE2D_ID_GROUPPRIMITIVE2D :
+ {
+ process(rCandidate);
+ break;
+ }
+
+ default :
+ {
+ // nothing to do for the rest
+ break;
+ }
+ }
+}
+
+} // end of anonymous namespace
+
+namespace sdr::contact {
+
+ViewObjectContact::ViewObjectContact(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: mrObjectContact(rObjectContact),
+ mrViewContact(rViewContact),
+ maGridOffset(0.0, 0.0),
+ mnActionChangedCount(0),
+ mbLazyInvalidate(false)
+{
+ // make the ViewContact remember me
+ mrViewContact.AddViewObjectContact(*this);
+
+ // make the ObjectContact remember me
+ mrObjectContact.AddViewObjectContact(*this);
+}
+
+ViewObjectContact::~ViewObjectContact()
+{
+ // invalidate in view
+ if(!getObjectRange().isEmpty())
+ {
+ GetObjectContact().InvalidatePartOfView(maObjectRange);
+ }
+
+ // delete PrimitiveAnimation
+ mpPrimitiveAnimation.reset();
+
+ // take care of remembered ObjectContact. Remove from
+ // OC first. The VC removal (below) CAN trigger a StopGettingViewed()
+ // which (depending of its implementation) may destroy other OCs. This
+ // can trigger the deletion of the helper OC of a page visualising object
+ // which IS the OC of this object. Eventually StopGettingViewed() needs
+ // to get asynchron later
+ GetObjectContact().RemoveViewObjectContact(*this);
+
+ // take care of remembered ViewContact
+ GetViewContact().RemoveViewObjectContact(*this);
+}
+
+const basegfx::B2DRange& ViewObjectContact::getObjectRange() const
+{
+ if(maObjectRange.isEmpty())
+ {
+ const drawinglayer::geometry::ViewInformation2D& rViewInfo2D = GetObjectContact().getViewInformation2D();
+ basegfx::B2DRange aTempRange = GetViewContact().getRange(rViewInfo2D);
+ if (!aTempRange.isEmpty())
+ {
+ const_cast< ViewObjectContact* >(this)->maObjectRange = aTempRange;
+ }
+ else
+ {
+ // if range is not computed (new or LazyInvalidate objects), force it
+ const DisplayInfo aDisplayInfo;
+ const drawinglayer::primitive2d::Primitive2DContainer& xSequence(getPrimitive2DSequence(aDisplayInfo));
+
+ if(!xSequence.empty())
+ {
+ const_cast< ViewObjectContact* >(this)->maObjectRange =
+ xSequence.getB2DRange(rViewInfo2D);
+ }
+ }
+ }
+
+ return maObjectRange;
+}
+
+void ViewObjectContact::ActionChanged()
+{
+ // clear cached primitives
+ mxPrimitive2DSequence.clear();
+ ++mnActionChangedCount;
+
+ if(mbLazyInvalidate)
+ return;
+
+ // set local flag
+ mbLazyInvalidate = true;
+
+ // force ObjectRange
+ getObjectRange();
+
+ if(!getObjectRange().isEmpty())
+ {
+ // invalidate current valid range
+ GetObjectContact().InvalidatePartOfView(maObjectRange);
+
+ // reset gridOffset, it needs to be recalculated
+ if (GetObjectContact().supportsGridOffsets())
+ resetGridOffset();
+ else
+ maObjectRange.reset();
+ }
+
+ // register at OC for lazy invalidate
+ GetObjectContact().setLazyInvalidate(*this);
+}
+
+void ViewObjectContact::triggerLazyInvalidate()
+{
+ if(!mbLazyInvalidate)
+ return;
+
+ // reset flag
+ mbLazyInvalidate = false;
+
+ // force ObjectRange
+ getObjectRange();
+
+ if(!getObjectRange().isEmpty())
+ {
+ // invalidate current valid range
+ GetObjectContact().InvalidatePartOfView(maObjectRange);
+ }
+}
+
+// Take some action when new objects are inserted
+void ViewObjectContact::ActionChildInserted(ViewContact& rChild)
+{
+ // force creation of the new VOC and trigger it's refresh, so it
+ // will take part in LazyInvalidate immediately
+ rChild.GetViewObjectContact(GetObjectContact()).ActionChanged();
+
+ // forward action to ObjectContact
+ // const ViewObjectContact& rChildVOC = rChild.GetViewObjectContact(GetObjectContact());
+ // GetObjectContact().InvalidatePartOfView(rChildVOC.getObjectRange());
+}
+
+void ViewObjectContact::checkForPrimitive2DAnimations()
+{
+ // remove old one
+ mpPrimitiveAnimation.reset();
+
+ // check for animated primitives
+ if(mxPrimitive2DSequence.empty())
+ return;
+
+ const bool bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed());
+ const bool bGraphicAnimationAllowed(GetObjectContact().IsGraphicAnimationAllowed());
+
+ if(bTextAnimationAllowed || bGraphicAnimationAllowed)
+ {
+ AnimatedExtractingProcessor2D aAnimatedExtractor(GetObjectContact().getViewInformation2D(),
+ bTextAnimationAllowed, bGraphicAnimationAllowed);
+ aAnimatedExtractor.process(mxPrimitive2DSequence);
+
+ if(!aAnimatedExtractor.getPrimitive2DSequence().empty())
+ {
+ // derived primitiveList is animated, setup new PrimitiveAnimation
+ mpPrimitiveAnimation.reset( new sdr::animation::PrimitiveAnimation(*this, aAnimatedExtractor.extractPrimitive2DSequence()) );
+ }
+ }
+}
+
+void ViewObjectContact::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // get the view-independent Primitive from the viewContact
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
+
+ if(!xRetval.empty())
+ {
+ // handle GluePoint
+ if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer xGlue(GetViewContact().createGluePointPrimitive2DSequence());
+
+ if(!xGlue.empty())
+ {
+ xRetval.append(xGlue);
+ }
+ }
+
+ // handle ghosted
+ if(isPrimitiveGhosted(rDisplayInfo))
+ {
+ const basegfx::BColor aRGBWhite(1.0, 1.0, 1.0);
+ const basegfx::BColorModifierSharedPtr aBColorModifier =
+ std::make_shared<basegfx::BColorModifier_interpolate>(
+ aRGBWhite,
+ 0.5);
+ drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
+ std::move(xRetval),
+ aBColorModifier));
+
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
+ }
+ }
+
+ rVisitor.visit(xRetval);
+}
+
+drawinglayer::primitive2d::Primitive2DContainer const & ViewObjectContact::getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
+{
+ // only some of the top-level apps are any good at reliably invalidating us (e.g. writer is not)
+ SdrObject* pSdrObj(mrViewContact.TryToGetSdrObject());
+
+ if (nullptr != pSdrObj && pSdrObj->getSdrModelFromSdrObject().IsVOCInvalidationIsReliable())
+ {
+ if (!mxPrimitive2DSequence.empty())
+ return mxPrimitive2DSequence;
+ }
+
+ // prepare new representation
+ drawinglayer::primitive2d::Primitive2DContainer xNewPrimitiveSequence;
+
+ // take care of redirectors and create new list
+ ViewObjectContactRedirector* pRedirector = GetObjectContact().GetViewObjectContactRedirector();
+
+ if(pRedirector)
+ {
+ pRedirector->createRedirectedPrimitive2DSequence(*this, rDisplayInfo, xNewPrimitiveSequence);
+ }
+ else
+ {
+ createPrimitive2DSequence(rDisplayInfo, xNewPrimitiveSequence);
+ }
+
+ // check and eventually embed to GridOffset transform primitive (calc only)
+ if(!xNewPrimitiveSequence.empty() && GetObjectContact().supportsGridOffsets())
+ {
+ const basegfx::B2DVector& rGridOffset(getGridOffset());
+
+ if(0.0 != rGridOffset.getX() || 0.0 != rGridOffset.getY())
+ {
+ const basegfx::B2DHomMatrix aTranslateGridOffset(
+ basegfx::utils::createTranslateB2DHomMatrix(
+ rGridOffset));
+ drawinglayer::primitive2d::Primitive2DReference aEmbed(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aTranslateGridOffset,
+ std::move(xNewPrimitiveSequence)));
+ xNewPrimitiveSequence = drawinglayer::primitive2d::Primitive2DContainer { aEmbed };
+ }
+ }
+
+ // Check if we need to embed to a StructureTagPrimitive2D, too. This
+ // was done at ImplRenderPaintProc::createRedirectedPrimitive2DSequence before
+ if (!xNewPrimitiveSequence.empty() && GetObjectContact().isExportTaggedPDF())
+ {
+ if (nullptr != pSdrObj)
+ {
+ vcl::PDFWriter::StructElement eElement(vcl::PDFWriter::NonStructElement);
+ const SdrInventor nInventor(pSdrObj->GetObjInventor());
+ const SdrObjKind nIdentifier(pSdrObj->GetObjIdentifier());
+ const bool bIsTextObj(nullptr != dynamic_cast<const SdrTextObj *>(pSdrObj));
+
+ // Note: SwFlyDrawObj/SwVirtFlyDrawObj have SdrInventor::Swg - these
+ // are *not* handled here because not all of them are painted
+ // completely with primitives, so a tag here does not encapsulate them.
+ // The tag must be created by SwTaggedPDFHelper until this is fixed.
+ if ( nInventor == SdrInventor::Default )
+ {
+ if ( nIdentifier == SdrObjKind::Group )
+ eElement = vcl::PDFWriter::Section;
+ else if (nIdentifier == SdrObjKind::Table)
+ eElement = vcl::PDFWriter::Table;
+ else if ( nIdentifier == SdrObjKind::TitleText )
+ eElement = vcl::PDFWriter::Heading;
+ else if ( nIdentifier == SdrObjKind::OutlineText )
+ eElement = vcl::PDFWriter::Division;
+ else if ( !bIsTextObj || !static_cast<const SdrTextObj&>(*pSdrObj).HasText() )
+ eElement = vcl::PDFWriter::Figure;
+ else
+ eElement = vcl::PDFWriter::Division;
+ }
+
+ if(vcl::PDFWriter::NonStructElement != eElement)
+ {
+ SdrPage* pSdrPage(pSdrObj->getSdrPageFromSdrObject());
+
+ if(pSdrPage)
+ {
+ const bool bBackground(pSdrPage->IsMasterPage());
+ const bool bImage(SdrObjKind::Graphic == pSdrObj->GetObjIdentifier());
+ // note: there must be output device here, in PDF export
+ sal_Int32 nAnchorId(-1);
+ if (auto const pUserCall = pSdrObj->GetUserCall())
+ {
+ nAnchorId = pUserCall->GetPDFAnchorStructureElementId(
+ *pSdrObj, *GetObjectContact().TryToGetOutputDevice());
+ }
+
+ drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::StructureTagPrimitive2D(
+ eElement,
+ bBackground,
+ bImage,
+ std::move(xNewPrimitiveSequence),
+ nAnchorId));
+ xNewPrimitiveSequence = drawinglayer::primitive2d::Primitive2DContainer { xReference };
+ }
+ }
+ }
+ else
+ {
+ // page backgrounds etc should be tagged as artifacts:
+ xNewPrimitiveSequence = drawinglayer::primitive2d::Primitive2DContainer {
+ new drawinglayer::primitive2d::StructureTagPrimitive2D(
+ // lies to force silly VclMetafileProcessor2D to emit NonStructElement
+ vcl::PDFWriter::Division,
+ true,
+ true,
+ std::move(xNewPrimitiveSequence))
+ };
+ }
+ }
+
+ // Local up-to-date checks. New list different from local one?
+ // This is the important point where it gets decided if the current or the new
+ // representation gets used. This is important for performance, since the
+ // current representation contains possible precious decompositions. That
+ // comparisons triggers exactly if something in the object visualization
+ // has changed.
+ // Note: That is the main reason for BasePrimitive2D::operator== at all. I
+ // have alternatively tried to invalidate the local representation on object
+ // change, but that is simply not reliable.
+ // Note2: I did that once in aw080, the lost CWS, and it worked well enough
+ // so that I could remove *all* operator== from all derivations of
+ // BasePrimitive2D, so it can be done again (with the needed ressources)
+ if(mxPrimitive2DSequence != xNewPrimitiveSequence)
+ {
+ // has changed, copy content
+ const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = std::move(xNewPrimitiveSequence);
+
+ // check for animated stuff
+ const_cast< ViewObjectContact* >(this)->checkForPrimitive2DAnimations();
+
+ // always update object range when PrimitiveSequence changes
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D());
+ const_cast< ViewObjectContact* >(this)->maObjectRange = mxPrimitive2DSequence.getB2DRange(rViewInformation2D);
+ }
+
+ // return current Primitive2DContainer
+ return mxPrimitive2DSequence;
+}
+
+bool ViewObjectContact::isPrimitiveVisible(const DisplayInfo& /*rDisplayInfo*/) const
+{
+ // default: always visible
+ return true;
+}
+
+bool ViewObjectContact::isPrimitiveGhosted(const DisplayInfo& rDisplayInfo) const
+{
+ // default: standard check
+ return (GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo.IsGhostedDrawModeActive());
+}
+
+void ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // check model-view visibility
+ if(!isPrimitiveVisible(rDisplayInfo))
+ return;
+
+ getPrimitive2DSequence(rDisplayInfo);
+ if(mxPrimitive2DSequence.empty())
+ return;
+
+ // get ranges
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D());
+ // tdf#147164 cannot use maObjectRange here, it is unreliable
+ const basegfx::B2DRange aObjectRange(mxPrimitive2DSequence.getB2DRange(rViewInformation2D));
+ const basegfx::B2DRange& aViewRange(rViewInformation2D.getViewport());
+
+ // check geometrical visibility
+ bool bVisible = aViewRange.isEmpty() || aViewRange.overlaps(aObjectRange);
+ if(!bVisible)
+ return;
+
+ // temporarily take over the mxPrimitive2DSequence, in case it gets invalidated while we want to iterate over it
+ auto tmp = std::move(const_cast<ViewObjectContact*>(this)->mxPrimitive2DSequence);
+ int nPrevCount = mnActionChangedCount;
+
+ rVisitor.visit(tmp);
+
+ // if we received ActionChanged() calls while walking the primitives, then leave it empty, otherwise move it back
+ if (mnActionChangedCount == nPrevCount)
+ const_cast<ViewObjectContact*>(this)->mxPrimitive2DSequence = std::move(tmp);
+}
+
+void ViewObjectContact::getPrimitive2DSequenceSubHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount());
+
+ for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
+ {
+ const ViewObjectContact& rCandidate(GetViewContact().GetViewContact(a).GetViewObjectContact(GetObjectContact()));
+
+ rCandidate.getPrimitive2DSequenceHierarchy(rDisplayInfo, rVisitor);
+ }
+}
+
+// Support getting a GridOffset per object and view for non-linear ViewToDevice
+// transformation (calc). On-demand created by delegating to the ObjectContact
+// (->View) that has then all needed information
+const basegfx::B2DVector& ViewObjectContact::getGridOffset() const
+{
+ if(0.0 == maGridOffset.getX() && 0.0 == maGridOffset.getY() && GetObjectContact().supportsGridOffsets())
+ {
+ // create on-demand
+ GetObjectContact().calculateGridOffsetForViewOjectContact(const_cast<ViewObjectContact*>(this)->maGridOffset, *this);
+ }
+
+ return maGridOffset;
+}
+
+void ViewObjectContact::resetGridOffset()
+{
+ // reset buffered GridOffset itself
+ maGridOffset.setX(0.0);
+ maGridOffset.setY(0.0);
+
+ // also reset sequence to get a re-calculation when GridOffset changes
+ mxPrimitive2DSequence.clear();
+ maObjectRange.reset();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofe3d.cxx b/svx/source/sdr/contact/viewobjectcontactofe3d.cxx
new file mode 100644
index 000000000..c6d41bdc9
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofe3d.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewobjectcontactofe3d.hxx>
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <drawinglayer/primitive3d/modifiedcolorprimitive3d.hxx>
+
+namespace sdr::contact
+{
+ ViewObjectContactOfE3d::ViewObjectContactOfE3d(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+ {
+ }
+
+ ViewObjectContactOfE3d::~ViewObjectContactOfE3d()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewObjectContactOfE3d::getPrimitive3DContainer(const DisplayInfo& rDisplayInfo) const
+ {
+ // get the view-independent Primitive from the viewContact
+ const ViewContactOfE3d& rViewContactOfE3d(dynamic_cast< const ViewContactOfE3d& >(GetViewContact()));
+ drawinglayer::primitive3d::Primitive3DContainer xRetval(rViewContactOfE3d.getViewIndependentPrimitive3DContainer());
+
+ // handle ghosted
+ if(isPrimitiveGhosted(rDisplayInfo))
+ {
+ const ::basegfx::BColor aRGBWhite(1.0, 1.0, 1.0);
+ const ::basegfx::BColorModifierSharedPtr aBColorModifier =
+ std::make_shared<basegfx::BColorModifier_interpolate>(
+ aRGBWhite,
+ 0.5);
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::ModifiedColorPrimitive3D(
+ xRetval,
+ aBColorModifier));
+
+ xRetval = { xReference };
+ }
+
+ return xRetval;
+ }
+
+ void ViewObjectContactOfE3d::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const ViewContactOfE3d& rViewContact = static_cast< const ViewContactOfE3d& >(GetViewContact());
+
+ // get 3d primitive vector, isPrimitiveVisible() is done in 3d creator
+ rVisitor.visit(rViewContact.impCreateWithGivenPrimitive3DContainer(getPrimitive3DContainer(rDisplayInfo)));
+ }
+
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofe3dscene.cxx b/svx/source/sdr/contact/viewobjectcontactofe3dscene.cxx
new file mode 100644
index 000000000..ac7ad90f1
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofe3dscene.cxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewobjectcontactofe3dscene.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <basegfx/color/bcolormodifier.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace
+{
+ // Helper method to recursively travel the DrawHierarchy for 3D objects contained in
+ // the 2D Scene. This will create all VOCs for the current OC which are needed
+ // for ActionChanged() functionality
+ void impInternalSubHierarchyTraveller(const sdr::contact::ViewObjectContact& rVOC)
+ {
+ const sdr::contact::ViewContact& rVC = rVOC.GetViewContact();
+ const sal_uInt32 nSubHierarchyCount(rVC.GetObjectCount());
+
+ for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
+ {
+ const sdr::contact::ViewObjectContact& rCandidate(rVC.GetViewContact(a).GetViewObjectContact(rVOC.GetObjectContact()));
+ impInternalSubHierarchyTraveller(rCandidate);
+ }
+ }
+} // end of anonymous namespace
+
+
+namespace sdr::contact
+{
+ ViewObjectContactOfE3dScene::ViewObjectContactOfE3dScene(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+ {
+ }
+
+ ViewObjectContactOfE3dScene::~ViewObjectContactOfE3dScene()
+ {
+ }
+
+ void ViewObjectContactOfE3dScene::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // handle ghosted, else the whole 3d group will be encapsulated to a ghosted primitive set (see below)
+ const bool bHandleGhostedDisplay(GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo.IsGhostedDrawModeActive());
+ const bool bIsActiveVC(bHandleGhostedDisplay && GetObjectContact().getActiveViewContact() == &GetViewContact());
+
+ if(bIsActiveVC)
+ {
+ // switch off ghosted, display contents normal
+ const_cast< DisplayInfo& >(rDisplayInfo).ClearGhostedDrawMode();
+ }
+
+ // create 2d primitive with content, use layer visibility test
+ // this uses no ghosted mode, so scenes in scenes and entering them will not
+ // support ghosted for now. This is no problem currently but would need to be
+ // added when sub-groups in 3d will be added one day.
+ const ViewContactOfE3dScene& rViewContact = dynamic_cast< ViewContactOfE3dScene& >(GetViewContact());
+ const SdrLayerIDSet& rVisibleLayers = rDisplayInfo.GetProcessLayers();
+ drawinglayer::primitive2d::Primitive2DContainer xRetval(rViewContact.createScenePrimitive2DSequence(&rVisibleLayers));
+
+ if(!xRetval.empty())
+ {
+ // allow evtl. embedding in object-specific infos, e.g. Name, Title, Description
+ xRetval = rViewContact.embedToObjectSpecificInformation(std::move(xRetval));
+
+ // handle GluePoint
+ if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer xGlue(GetViewContact().createGluePointPrimitive2DSequence());
+
+ if(!xGlue.empty())
+ {
+ xRetval.append(xGlue);
+ }
+ }
+
+ // handle ghosted
+ if(isPrimitiveGhosted(rDisplayInfo))
+ {
+ const ::basegfx::BColor aRGBWhite(1.0, 1.0, 1.0);
+ const ::basegfx::BColorModifierSharedPtr aBColorModifier =
+ std::make_shared<basegfx::BColorModifier_interpolate>(
+ aRGBWhite,
+ 0.5);
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
+ std::move(xRetval),
+ aBColorModifier));
+
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
+ }
+ }
+
+ if(bIsActiveVC)
+ {
+ // set back, display ghosted again
+ const_cast< DisplayInfo& >(rDisplayInfo).SetGhostedDrawMode();
+ }
+
+ rVisitor.visit(xRetval);
+ }
+
+ void ViewObjectContactOfE3dScene::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // To get the VOCs for the contained 3D objects created to get the correct
+ // Draw hierarchy and ActionChanged() working properly, travel the DrawHierarchy
+ // using a local tooling method
+ impInternalSubHierarchyTraveller(*this);
+
+ // call parent
+ ViewObjectContactOfSdrObj::getPrimitive2DSequenceHierarchy(rDisplayInfo, rVisitor);
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofgraphic.cxx b/svx/source/sdr/contact/viewobjectcontactofgraphic.cxx
new file mode 100644
index 000000000..601ec28df
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofgraphic.cxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewobjectcontactofgraphic.hxx>
+#include <sdr/contact/viewcontactofgraphic.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+
+namespace sdr::contact
+{
+ void ViewObjectContactOfGraphic::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // #i103255# suppress when graphic needs draft visualisation and output
+ // is for PDF export/Printer
+ const ViewContactOfGraphic& rVCOfGraphic = static_cast< const ViewContactOfGraphic& >(GetViewContact());
+
+ if(rVCOfGraphic.visualisationUsesDraft())
+ {
+ const ObjectContact& rObjectContact = GetObjectContact();
+
+ if(rObjectContact.isOutputToPDFFile() || rObjectContact.isOutputToPrinter())
+ {
+ return;
+ }
+ }
+
+ // get return value by calling parent
+ ViewObjectContactOfSdrObj::createPrimitive2DSequence(rDisplayInfo, rVisitor);
+ }
+
+ ViewObjectContactOfGraphic::ViewObjectContactOfGraphic(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+ {
+ }
+
+ ViewObjectContactOfGraphic::~ViewObjectContactOfGraphic()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofgroup.cxx b/svx/source/sdr/contact/viewobjectcontactofgroup.cxx
new file mode 100644
index 000000000..8469a00c1
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofgroup.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewobjectcontactofgroup.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/svdobj.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace sdr::contact
+{
+ ViewObjectContactOfGroup::ViewObjectContactOfGroup(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+ {
+ }
+
+ ViewObjectContactOfGroup::~ViewObjectContactOfGroup()
+ {
+ }
+
+ void ViewObjectContactOfGroup::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // check model-view visibility
+ if(!isPrimitiveVisible(rDisplayInfo))
+ return;
+
+ const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount());
+ if(nSubHierarchyCount)
+ {
+ const bool bDoGhostedDisplaying(
+ GetObjectContact().DoVisualizeEnteredGroup()
+ && !GetObjectContact().isOutputToPrinter()
+ && GetObjectContact().getActiveViewContact() == &GetViewContact());
+
+ if(bDoGhostedDisplaying)
+ {
+ rDisplayInfo.ClearGhostedDrawMode();
+ }
+
+ // visit object hierarchy
+ getPrimitive2DSequenceSubHierarchy(rDisplayInfo, rVisitor);
+
+ if(bDoGhostedDisplaying)
+ {
+ rDisplayInfo.SetGhostedDrawMode();
+ }
+ }
+ else
+ {
+ // draw replacement object for group. This will use ViewContactOfGroup::createViewIndependentPrimitive2DSequence
+ // which creates the replacement primitives for an empty group
+ ViewObjectContactOfSdrObj::getPrimitive2DSequenceHierarchy(rDisplayInfo, rVisitor);
+ }
+ }
+
+ bool ViewObjectContactOfGroup::isPrimitiveVisibleOnAnyLayer(const SdrLayerIDSet& aLayers) const
+ {
+ SdrLayerIDSet aObjectLayers;
+ getSdrObject().getMergedHierarchySdrLayerIDSet(aObjectLayers);
+ aObjectLayers &= aLayers;
+ return !aObjectLayers.IsEmpty();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx b/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx
new file mode 100644
index 000000000..f96ed115d
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewobjectcontactofmasterpagedescriptor.hxx>
+#include <sdr/contact/viewcontactofmasterpagedescriptor.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+
+namespace sdr::contact
+{
+ ViewObjectContactOfMasterPageDescriptor::ViewObjectContactOfMasterPageDescriptor(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContact(rObjectContact, rViewContact)
+ {
+ }
+
+ ViewObjectContactOfMasterPageDescriptor::~ViewObjectContactOfMasterPageDescriptor()
+ {
+ }
+
+ bool ViewObjectContactOfMasterPageDescriptor::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+ {
+ if(rDisplayInfo.GetControlLayerProcessingActive())
+ {
+ return false;
+ }
+
+ if(!rDisplayInfo.GetPageProcessingActive())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ void ViewObjectContactOfMasterPageDescriptor::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ drawinglayer::primitive2d::Primitive2DContainer xMasterPageSequence;
+ const sdr::MasterPageDescriptor& rDescriptor = static_cast< ViewContactOfMasterPageDescriptor& >(GetViewContact()).GetMasterPageDescriptor();
+
+ // used range (retval) is fixed here, it's the MasterPage fill range
+ const SdrPage& rOwnerPage = rDescriptor.GetOwnerPage();
+ const basegfx::B2DRange aInnerRange(
+ rOwnerPage.GetLeftBorder(), rOwnerPage.GetUpperBorder(),
+ rOwnerPage.GetWidth() - rOwnerPage.GetRightBorder(), rOwnerPage.GetHeight() - rOwnerPage.GetLowerBorder());
+ const basegfx::B2DRange aOuterRange(
+ 0, 0, rOwnerPage.GetWidth(), rOwnerPage.GetHeight());
+ // ??? somehow only the master page's bit is used
+ bool const isFullSize(rDescriptor.GetUsedPage().IsBackgroundFullSize());
+ basegfx::B2DRange const& rPageFillRange(isFullSize ? aOuterRange : aInnerRange);
+
+ // Modify DisplayInfo for MasterPageContent collection; remember original layers and
+ // set combined SdrLayerIDSet; set MasterPagePaint flag
+ const SdrLayerIDSet aRememberedLayers(rDisplayInfo.GetProcessLayers());
+ SdrLayerIDSet aPreprocessedLayers(aRememberedLayers);
+ aPreprocessedLayers &= rDescriptor.GetVisibleLayers();
+ rDisplayInfo.SetProcessLayers(aPreprocessedLayers);
+ rDisplayInfo.SetSubContentActive(true);
+
+ // check layer visibility (traditionally was member of layer 1)
+ if(aPreprocessedLayers.IsSet(SdrLayerID(1)))
+ {
+ // hide PageBackground for special DrawModes; historical reasons
+ if(!GetObjectContact().isDrawModeGray() && !GetObjectContact().isDrawModeHighContrast())
+ {
+ // if visible, create the default background primitive sequence
+ static_cast< ViewContactOfMasterPageDescriptor& >(GetViewContact()).getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+ }
+
+ // hide MasterPage content? Test self here for hierarchy
+ if(isPrimitiveVisible(rDisplayInfo))
+ {
+ // get the VOC of the Master-SdrPage and get its object hierarchy
+ ViewContact& rViewContactOfMasterPage(rDescriptor.GetUsedPage().GetViewContact());
+ ViewObjectContact& rVOCOfMasterPage(rViewContactOfMasterPage.GetViewObjectContact(GetObjectContact()));
+
+ rVOCOfMasterPage.getPrimitive2DSequenceHierarchy(rDisplayInfo, xMasterPageSequence);
+ }
+
+ // reset DisplayInfo changes for MasterPage paint
+ rDisplayInfo.SetProcessLayers(aRememberedLayers);
+ rDisplayInfo.SetSubContentActive(false);
+
+ if(!xMasterPageSequence.empty())
+ {
+ // get range of MasterPage sub hierarchy
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D());
+ basegfx::B2DRange aSubHierarchyRange(xMasterPageSequence.getB2DRange(rViewInformation2D));
+
+ if (rPageFillRange.isInside(aSubHierarchyRange))
+ {
+ // completely inside, just render MasterPage content. Add to target
+ rVisitor.visit(xMasterPageSequence);
+ }
+ else if (rPageFillRange.overlaps(aSubHierarchyRange))
+ {
+ // overlapping, compute common area
+ basegfx::B2DRange aCommonArea(rPageFillRange);
+ aCommonArea.intersect(aSubHierarchyRange);
+
+ // need to create a clip primitive, add clipped list to target
+ const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::MaskPrimitive2D(
+ basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aCommonArea)), std::move(xMasterPageSequence)));
+ rVisitor.visit(xReference);
+ }
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx b/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx
new file mode 100644
index 000000000..e3431da91
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx
@@ -0,0 +1,315 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/idle.hxx>
+#include <sdr/contact/viewobjectcontactofpageobj.hxx>
+#include <sdr/contact/viewcontactofpageobj.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svtools/colorcfg.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unoapi.hxx>
+#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <vcl/canvastools.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::contact {
+
+class PagePrimitiveExtractor : public ObjectContactOfPagePainter, public Idle
+{
+private:
+ // the ViewObjectContactOfPageObj using this painter
+ ViewObjectContactOfPageObj& mrViewObjectContactOfPageObj;
+
+public:
+ // basic constructor/destructor
+ explicit PagePrimitiveExtractor(ViewObjectContactOfPageObj& rVOC);
+ virtual ~PagePrimitiveExtractor() override;
+
+ // LazyInvalidate request. Supported here to not automatically
+ // invalidate the second interaction state all the time at the
+ // original OC
+ virtual void setLazyInvalidate(ViewObjectContact& rVOC) override;
+
+ // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
+ virtual void Invoke() final override;
+
+ // get primitive visualization
+ drawinglayer::primitive2d::Primitive2DContainer createPrimitive2DSequenceForPage();
+
+ // Own reaction on changes which will be forwarded to the OC of the owner-VOC
+ virtual void InvalidatePartOfView(const basegfx::B2DRange& rRange) const override;
+
+ // forward access to SdrPageView of ViewObjectContactOfPageObj
+ virtual bool isOutputToPrinter() const override;
+ virtual bool isOutputToRecordingMetaFile() const override;
+ virtual bool isOutputToPDFFile() const override;
+ virtual bool isDrawModeGray() const override;
+ virtual bool isDrawModeHighContrast() const override;
+ virtual SdrPageView* TryToGetSdrPageView() const override;
+ virtual OutputDevice* TryToGetOutputDevice() const override;
+};
+
+PagePrimitiveExtractor::PagePrimitiveExtractor(
+ ViewObjectContactOfPageObj& rVOC)
+: ObjectContactOfPagePainter(rVOC.GetObjectContact()), Idle("svx PagePrimitiveExtractor"),
+ mrViewObjectContactOfPageObj(rVOC)
+{
+ // make this renderer a preview renderer
+ setPreviewRenderer(true);
+
+ // init timer
+ SetPriority(TaskPriority::HIGH_IDLE);
+ Stop();
+}
+
+PagePrimitiveExtractor::~PagePrimitiveExtractor()
+{
+ // execute missing LazyInvalidates and stop timer
+ Invoke();
+}
+
+void PagePrimitiveExtractor::setLazyInvalidate(ViewObjectContact& /*rVOC*/)
+{
+ // do NOT call parent, but remember that something is to do by
+ // starting the LazyInvalidateTimer
+ Start();
+}
+
+// From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
+void PagePrimitiveExtractor::Invoke()
+{
+ // stop the timer
+ Stop();
+
+ // invalidate all LazyInvalidate VOCs new situations
+ const sal_uInt32 nVOCCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nVOCCount; a++)
+ {
+ ViewObjectContact* pCandidate = getViewObjectContact(a);
+ pCandidate->triggerLazyInvalidate();
+ }
+}
+
+drawinglayer::primitive2d::Primitive2DContainer PagePrimitiveExtractor::createPrimitive2DSequenceForPage()
+{
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ SdrPage* pStartPage = GetStartPage();
+
+ if(pStartPage)
+ {
+ // update own ViewInformation2D for visualized page
+ const drawinglayer::geometry::ViewInformation2D& rOriginalViewInformation = mrViewObjectContactOfPageObj.GetObjectContact().getViewInformation2D();
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
+ rOriginalViewInformation.getObjectTransformation(),
+ rOriginalViewInformation.getViewTransformation(),
+
+ // #i101075# use empty range for page content here to force
+ // the content not to be physically clipped in any way. This
+ // would be possible, but would require the internal transformation
+ // which maps between the page visualisation object and the page
+ // content, including the aspect ratios (for details see in
+ // PagePreviewPrimitive2D::create2DDecomposition)
+ basegfx::B2DRange(),
+
+ GetXDrawPageForSdrPage(pStartPage),
+ 0.0); // no time; page previews are not animated
+ updateViewInformation2D(aNewViewInformation2D);
+
+ // create copy of DisplayInfo to set PagePainting
+ DisplayInfo aDisplayInfo;
+
+ // get page's VOC
+ ViewObjectContact& rDrawPageVOContact = pStartPage->GetViewContact().GetViewObjectContact(*this);
+
+ // get whole Primitive2DContainer
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo, xRetval);
+ }
+
+ return xRetval;
+}
+
+void PagePrimitiveExtractor::InvalidatePartOfView(const basegfx::B2DRange& rRange) const
+{
+ // an invalidate is called at this view, this needs to be translated to an invalidate
+ // for the using VOC. Coordinates are in page coordinate system.
+ const SdrPage* pStartPage = GetStartPage();
+
+ if(pStartPage && !rRange.isEmpty())
+ {
+ const basegfx::B2DRange aPageRange(0.0, 0.0, static_cast<double>(pStartPage->GetWidth()), static_cast<double>(pStartPage->GetHeight()));
+
+ if(rRange.overlaps(aPageRange))
+ {
+ // if object on the page is inside or overlapping with page, create ActionChanged() for
+ // involved VOC
+ mrViewObjectContactOfPageObj.ActionChanged();
+ }
+ }
+}
+
+// forward access to SdrPageView to VOCOfPageObj
+bool PagePrimitiveExtractor::isOutputToPrinter() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPrinter(); }
+bool PagePrimitiveExtractor::isOutputToRecordingMetaFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToRecordingMetaFile(); }
+bool PagePrimitiveExtractor::isOutputToPDFFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPDFFile(); }
+bool PagePrimitiveExtractor::isDrawModeGray() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeGray(); }
+bool PagePrimitiveExtractor::isDrawModeHighContrast() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeHighContrast(); }
+SdrPageView* PagePrimitiveExtractor::TryToGetSdrPageView() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetSdrPageView(); }
+OutputDevice* PagePrimitiveExtractor::TryToGetOutputDevice() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetOutputDevice(); }
+
+void ViewObjectContactOfPageObj::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPageObj& rPageObject(static_cast< ViewContactOfPageObj& >(GetViewContact()).GetPageObj());
+ const SdrPage* pPage = rPageObject.GetReferencedPage();
+ const svtools::ColorConfig aColorConfig;
+
+ // get PageObject's geometry
+ basegfx::B2DHomMatrix aPageObjectTransform;
+ {
+ const tools::Rectangle aPageObjectModelData(rPageObject.GetLastBoundRect());
+ const basegfx::B2DRange aPageObjectBound = vcl::unotools::b2DRectangleFromRectangle(aPageObjectModelData);
+
+ aPageObjectTransform.set(0, 0, aPageObjectBound.getWidth());
+ aPageObjectTransform.set(1, 1, aPageObjectBound.getHeight());
+ aPageObjectTransform.set(0, 2, aPageObjectBound.getMinX());
+ aPageObjectTransform.set(1, 2, aPageObjectBound.getMinY());
+ }
+
+ // #i102637# add gray frame also when printing and page exists (handout pages)
+ const bool bCreateGrayFrame(!GetObjectContact().isOutputToPrinter() || pPage);
+
+ // get displayed page's content. This is the unscaled page content
+ if(mpExtractor && pPage)
+ {
+ // get displayed page's geometry
+ drawinglayer::primitive2d::Primitive2DContainer xPageContent;
+ const Size aPageSize(pPage->GetSize());
+ const double fPageWidth(aPageSize.getWidth());
+ const double fPageHeight(aPageSize.getHeight());
+
+ // The case that a PageObject contains another PageObject which visualizes the
+ // same page again would lead to a recursion. Limit that recursion depth to one
+ // by using a local static bool
+ static bool bInCreatePrimitive2D(false);
+
+ if(bInCreatePrimitive2D)
+ {
+ // Recursion is possible. Create a replacement primitive
+ xPageContent.resize(2);
+ const Color aDocColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
+ svtools::ColorConfigValue aBorderConfig = aColorConfig.GetColorValue(svtools::DOCBOUNDARIES);
+ const Color aBorderColor = aBorderConfig.bIsVisible ? aBorderConfig.nColor : aDocColor;
+ const basegfx::B2DRange aPageBound(0.0, 0.0, fPageWidth, fPageHeight);
+ const basegfx::B2DPolygon aOutline(basegfx::utils::createPolygonFromRect(aPageBound));
+
+ // add replacement fill
+ xPageContent[0] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aOutline), aDocColor.getBColor()));
+
+ // add replacement border
+ xPageContent[1] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aBorderColor.getBColor()));
+ }
+ else
+ {
+ // set recursion flag
+ bInCreatePrimitive2D = true;
+
+ // init extractor, guarantee existence, set page there
+ mpExtractor->SetStartPage(pPage);
+
+ // #i105548# also need to copy the VOCRedirector for sub-content creation
+ mpExtractor->SetViewObjectContactRedirector(GetObjectContact().GetViewObjectContactRedirector());
+
+ // create page content
+ xPageContent = mpExtractor->createPrimitive2DSequenceForPage();
+
+ // #i105548# reset VOCRedirector to not accidentally have a pointer to a
+ // temporary class, so calls to it are avoided safely
+ mpExtractor->SetViewObjectContactRedirector(nullptr);
+
+ // reset recursion flag
+ bInCreatePrimitive2D = false;
+ }
+
+ // prepare retval
+ if(!xPageContent.empty())
+ {
+ const uno::Reference< drawing::XDrawPage > xDrawPage(GetXDrawPageForSdrPage(const_cast< SdrPage*>(pPage)));
+ const drawinglayer::primitive2d::Primitive2DReference xPagePreview(new drawinglayer::primitive2d::PagePreviewPrimitive2D(
+ xDrawPage, aPageObjectTransform, fPageWidth, fPageHeight, std::move(xPageContent)));
+ rVisitor.visit(xPagePreview);
+ }
+ }
+ else if(bCreateGrayFrame)
+ {
+ // #i105146# no content, but frame display. To make hitting the page preview objects
+ // on the handout page more simple, add hidden fill geometry
+ const drawinglayer::primitive2d::Primitive2DReference xFrameHit(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ aPageObjectTransform));
+ rVisitor.visit(xFrameHit);
+ }
+
+ // add a gray outline frame, except not when printing
+ if(bCreateGrayFrame)
+ {
+ const Color aFrameColor(aColorConfig.GetColorValue(svtools::OBJECTBOUNDARIES).nColor);
+ basegfx::B2DPolygon aOwnOutline(basegfx::utils::createUnitPolygon());
+ aOwnOutline.transform(aPageObjectTransform);
+
+ const drawinglayer::primitive2d::Primitive2DReference xGrayFrame(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOwnOutline, aFrameColor.getBColor()));
+
+ rVisitor.visit(xGrayFrame);
+ }
+}
+
+ViewObjectContactOfPageObj::ViewObjectContactOfPageObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfSdrObj(rObjectContact, rViewContact),
+ mpExtractor(new PagePrimitiveExtractor(*this))
+{
+}
+
+ViewObjectContactOfPageObj::~ViewObjectContactOfPageObj()
+{
+ // delete the helper OC
+ if(mpExtractor)
+ {
+ // remember candidate and reset own pointer to avoid action when createPrimitive2DSequence()
+ // would be called for any reason
+ std::unique_ptr<PagePrimitiveExtractor> pCandidate = std::move(mpExtractor);
+
+ // also reset the StartPage to avoid ActionChanged() forwardings in the
+ // PagePrimitiveExtractor::InvalidatePartOfView() implementation
+ pCandidate->SetStartPage(nullptr);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofsdrmediaobj.cxx b/svx/source/sdr/contact/viewobjectcontactofsdrmediaobj.cxx
new file mode 100644
index 000000000..777017472
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofsdrmediaobj.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <sdr/contact/viewobjectcontactofsdrmediaobj.hxx>
+#include <svx/sdr/contact/viewcontactofsdrmediaobj.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/window.hxx>
+#include <avmedia/mediaitem.hxx>
+#include "sdrmediawindow.hxx"
+
+namespace sdr::contact {
+
+ViewObjectContactOfSdrMediaObj::ViewObjectContactOfSdrMediaObj( ObjectContact& rObjectContact,
+ ViewContact& rViewContact,
+ const ::avmedia::MediaItem& rMediaItem ) :
+ ViewObjectContactOfSdrObj( rObjectContact, rViewContact )
+{
+#if HAVE_FEATURE_AVMEDIA
+ vcl::Window* pWindow = getWindow();
+
+ if( pWindow )
+ {
+ mpMediaWindow.reset( new SdrMediaWindow( pWindow, *this ) );
+ mpMediaWindow->hide();
+ executeMediaItem( rMediaItem );
+ }
+#else
+ (void) rMediaItem;
+#endif
+}
+
+ViewObjectContactOfSdrMediaObj::~ViewObjectContactOfSdrMediaObj()
+{
+}
+
+
+vcl::Window* ViewObjectContactOfSdrMediaObj::getWindow() const
+{
+ vcl::Window* pRetval = nullptr;
+
+ const OutputDevice* oPageOutputDev = getPageViewOutputDevice();
+ if( oPageOutputDev )
+ {
+ if(OUTDEV_WINDOW == oPageOutputDev->GetOutDevType())
+ {
+ pRetval = oPageOutputDev->GetOwnerWindow();
+ }
+ }
+
+ return pRetval;
+}
+
+
+Size ViewObjectContactOfSdrMediaObj::getPreferredSize() const
+{
+ Size aRet;
+
+#if HAVE_FEATURE_AVMEDIA
+ if( mpMediaWindow )
+ aRet = mpMediaWindow->getPreferredSize();
+#else
+ aRet = Size(0,0);
+#endif
+
+ return aRet;
+}
+
+void ViewObjectContactOfSdrMediaObj::ActionChanged()
+{
+ ViewObjectContactOfSdrObj::ActionChanged();
+ updateMediaWindow(false);
+}
+
+void ViewObjectContactOfSdrMediaObj::updateMediaWindow(bool bShow) const
+{
+#if HAVE_FEATURE_AVMEDIA
+ if (!mpMediaWindow || (!bShow && !mpMediaWindow->isVisible()))
+ return;
+
+ basegfx::B2DRange aViewRange(getObjectRange());
+ aViewRange.transform(GetObjectContact().getViewInformation2D().getViewTransformation());
+
+ const tools::Rectangle aViewRectangle(
+ static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())),
+ static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY())));
+
+ // mpMediaWindow contains a SalObject window and gtk won't accept
+ // the size until after the SalObject widget is shown but if we
+ // show it before setting a size then vcl will detect that the
+ // vcl::Window has no size and make it invisible instead. If we
+ // call setPosSize twice with the same size before and after show
+ // then the second attempt is a no-op as vcl caches the size.
+
+ // so call it initially with a size arbitrarily 1 pixel wider than
+ // we want so we have an initial size to make vcl happy
+ tools::Rectangle aInitialRect(aViewRectangle);
+ aInitialRect.AdjustRight(1);
+ mpMediaWindow->setPosSize(aInitialRect);
+
+ // then make it visible
+ mpMediaWindow->show();
+
+ // set the final desired size which is different to let vcl send it
+ // through to gtk which will now accept it as the underlying
+ // m_pSocket of GtkSalObject::SetPosSize is now visible
+ mpMediaWindow->setPosSize(aViewRectangle);
+#else
+ (void) bShow;
+#endif
+}
+
+void ViewObjectContactOfSdrMediaObj::updateMediaItem( ::avmedia::MediaItem& rItem ) const
+{
+#if HAVE_FEATURE_AVMEDIA
+ if( !mpMediaWindow )
+ return;
+
+ mpMediaWindow->updateMediaItem( rItem );
+
+ // show/hide is now dependent of play state
+ if(avmedia::MediaState::Stop == rItem.getState())
+ {
+ mpMediaWindow->hide();
+ }
+ else
+ {
+ updateMediaWindow(true);
+ }
+#else
+ (void) rItem;
+#endif
+}
+
+
+void ViewObjectContactOfSdrMediaObj::executeMediaItem( const ::avmedia::MediaItem& rItem )
+{
+#if HAVE_FEATURE_AVMEDIA
+ if( mpMediaWindow )
+ {
+ ::avmedia::MediaItem aUpdatedItem;
+
+ mpMediaWindow->executeMediaItem( rItem );
+
+ // query new properties after trying to set the new properties
+ updateMediaItem( aUpdatedItem );
+ static_cast< ViewContactOfSdrMediaObj& >( GetViewContact() ).mediaPropertiesChanged( aUpdatedItem );
+ }
+#else
+ (void) rItem;
+#endif
+}
+
+
+} // end of namespace sdr::contact
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx b/svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx
new file mode 100644
index 000000000..f87906240
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/canvastools.hxx>
+
+#include <fmobj.hxx>
+
+namespace sdr::contact {
+
+const SdrObject& ViewObjectContactOfSdrObj::getSdrObject() const
+{
+ return static_cast< ViewContactOfSdrObj& >(GetViewContact()).GetSdrObject();
+}
+
+ViewObjectContactOfSdrObj::ViewObjectContactOfSdrObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContact(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfSdrObj::~ViewObjectContactOfSdrObj()
+{
+}
+
+bool ViewObjectContactOfSdrObj::isPrimitiveVisibleOnAnyLayer(const SdrLayerIDSet& aLayers) const
+{
+ return aLayers.IsSet(getSdrObject().GetLayer());
+}
+
+bool ViewObjectContactOfSdrObj::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ const SdrObject& rObject = getSdrObject();
+
+ // Test layer visibility
+ if(!isPrimitiveVisibleOnAnyLayer(rDisplayInfo.GetProcessLayers()))
+ {
+ return false;
+ }
+
+ if(GetObjectContact().isOutputToPrinter() )
+ {
+ // Test if print output but not printable
+ if( !rObject.IsPrintable())
+ return false;
+ }
+ else
+ {
+ // test is object is not visible on screen
+ if( !rObject.IsVisible() )
+ return false;
+ }
+
+ // Test for hidden object on MasterPage
+ if(rDisplayInfo.GetSubContentActive() && rObject.IsNotVisibleAsMaster())
+ {
+ return false;
+ }
+
+ // Test for Calc object hiding (for OLE and Graphic it's extra, see there)
+ const SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pSdrPageView)
+ {
+ const SdrView& rSdrView = pSdrPageView->GetView();
+ const bool bHideOle(rSdrView.getHideOle());
+ const bool bHideChart(rSdrView.getHideChart());
+ const bool bHideDraw(rSdrView.getHideDraw());
+ const bool bHideFormControl(rSdrView.getHideFormControl());
+
+ if(bHideOle || bHideChart || bHideDraw || bHideFormControl)
+ {
+ if(SdrObjKind::OLE2 == rObject.GetObjIdentifier())
+ {
+ if(static_cast<const SdrOle2Obj&>(rObject).IsChart())
+ {
+ // chart
+ if(bHideChart)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // OLE
+ if(bHideOle)
+ {
+ return false;
+ }
+ }
+ }
+ else if(SdrObjKind::Graphic == rObject.GetObjIdentifier())
+ {
+ // graphic handled like OLE
+ if(bHideOle)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ const bool bIsFormControl = dynamic_cast< const FmFormObj * >( &rObject ) != nullptr;
+ if(bIsFormControl && bHideFormControl)
+ {
+ return false;
+ }
+ // any other draw object
+ if(!bIsFormControl && bHideDraw)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // tdf#91260 check if the object is anchored on a different Writer page
+ // than the one being painted, and if so ignore it (Writer has only one
+ // SdrPage, so the part of the object that should be visible will be
+ // painted on the page where it is anchored)
+ // Note that we cannot check the ViewInformation2D ViewPort for this
+ // because it is only the part of the page that is currently visible.
+ basegfx::B2IPoint const& rAnchor(vcl::unotools::b2IPointFromPoint(getSdrObject().GetAnchorPos()));
+ if (rAnchor.getX() || rAnchor.getY()) // only Writer sets anchor position
+ {
+ if (!rDisplayInfo.GetWriterPageFrame().isEmpty() &&
+ !rDisplayInfo.GetWriterPageFrame().isInside(rAnchor))
+ {
+ return false;
+ }
+ }
+
+ // Check if this object is in the visible range.
+ const drawinglayer::geometry::ViewInformation2D& rViewInfo = GetObjectContact().getViewInformation2D();
+ basegfx::B2DRange aObjRange = GetViewContact().getRange(rViewInfo);
+ if (!aObjRange.isEmpty())
+ {
+ const basegfx::B2DRange& rViewRange = rViewInfo.getViewport();
+ bool bVisible = rViewRange.isEmpty() || rViewRange.overlaps(aObjRange);
+ if (!bVisible)
+ return false;
+ }
+
+ return true;
+}
+
+const OutputDevice* ViewObjectContactOfSdrObj::getPageViewOutputDevice() const
+{
+ ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &GetObjectContact() );
+ if ( pPageViewContact )
+ {
+ // if the PageWindow has a patched PaintWindow, use the original PaintWindow
+ // this ensures that our control is _not_ re-created just because somebody
+ // (temporarily) changed the window to paint onto.
+ // #i72429# / 2007-02-20 / frank.schoenheit (at) sun.com
+ SdrPageWindow& rPageWindow( pPageViewContact->GetPageWindow() );
+ if ( rPageWindow.GetOriginalPaintWindow() )
+ return &rPageWindow.GetOriginalPaintWindow()->GetOutputDevice();
+
+ return &rPageWindow.GetPaintWindow().GetOutputDevice();
+ }
+ return nullptr;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofsdrole2obj.cxx b/svx/source/sdr/contact/viewobjectcontactofsdrole2obj.cxx
new file mode 100644
index 000000000..66d1a6fb4
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofsdrole2obj.cxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewobjectcontactofsdrole2obj.hxx>
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <sdr/contact/viewcontactofsdrole2obj.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHatchPrimitive2D.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <com/sun/star/embed/EmbedMisc.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svtools/embedhlp.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::contact {
+
+void ViewObjectContactOfSdrOle2Obj::createPrimitive2DSequence(
+ const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // override this method to do some things the old SdrOle2Obj::DoPaintObject did.
+ // In the future, some of these may be solved different, but ATM try to stay compatible
+ // with the old behaviour
+ const SdrOle2Obj& rSdrOle2 = static_cast< ViewContactOfSdrOle2Obj& >(GetViewContact()).GetOle2Obj();
+ sal_Int32 nState(-1);
+
+ {
+ const svt::EmbeddedObjectRef& xObjRef = rSdrOle2.getEmbeddedObjectRef();
+ if ( xObjRef.is() )
+ nState = xObjRef->getCurrentState();
+ }
+
+ const bool bIsOutplaceActive(nState == embed::EmbedStates::ACTIVE);
+ const bool bIsInplaceActive((nState == embed::EmbedStates::INPLACE_ACTIVE) || (nState == embed::EmbedStates::UI_ACTIVE));
+ bool bDone(false);
+
+ if (bIsInplaceActive)
+ {
+ if( !GetObjectContact().isOutputToPrinter() && !GetObjectContact().isOutputToRecordingMetaFile() )
+ {
+ //no need to create a primitive sequence here as the OLE object does render itself
+ //in case of charts the superfluous creation of a metafile is strongly performance relevant!
+ bDone = true;
+ }
+ }
+
+ if( !bDone )
+ {
+ //old stuff that should be reworked
+ {
+ //if no replacement image is available load the OLE object
+// if(!rSdrOle2.GetGraphic()) //try to fetch the metafile - this can lead to the actual creation of the metafile what can be extremely expensive (e.g. for big charts)!!! #i101925#
+// {
+// // try to create embedded object
+// rSdrOle2.GetObjRef(); //this loads the OLE object if it is not loaded already
+// }
+ const svt::EmbeddedObjectRef& xObjRef = rSdrOle2.getEmbeddedObjectRef();
+ if(xObjRef.is())
+ {
+ const sal_Int64 nMiscStatus(xObjRef->getStatus(rSdrOle2.GetAspect()));
+
+ // this hack (to change model data during PAINT argh(!)) should be reworked
+ if(!rSdrOle2.IsResizeProtect() && (nMiscStatus & embed::EmbedMisc::EMBED_NEVERRESIZE))
+ {
+ const_cast< SdrOle2Obj* >(&rSdrOle2)->SetResizeProtect(true);
+ }
+
+ SdrPageView* pPageView = GetObjectContact().TryToGetSdrPageView();
+ if(pPageView && (nMiscStatus & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE))
+ {
+ // connect plugin object
+ pPageView->GetView().DoConnect(const_cast< SdrOle2Obj* >(&rSdrOle2));
+ }
+ }
+ }//end old stuff to rework
+
+ // create OLE primitive stuff directly at VC with HC as parameter
+ const ViewContactOfSdrOle2Obj& rVC = static_cast< const ViewContactOfSdrOle2Obj& >(GetViewContact());
+ rVC.createPrimitive2DSequenceWithParameters(rVisitor);
+
+ if(bIsOutplaceActive)
+ {
+ // do not shade when printing or PDF exporting
+ if(!GetObjectContact().isOutputToPrinter() && !GetObjectContact().isOutputToRecordingMetaFile())
+ {
+ // get object transformation
+ const basegfx::B2DHomMatrix aObjectMatrix(static_cast< ViewContactOfSdrOle2Obj& >(GetViewContact()).createObjectTransform());
+
+ // shade the representation if the object is activated outplace
+ basegfx::B2DPolygon aObjectOutline(basegfx::utils::createUnitPolygon());
+ aObjectOutline.transform(aObjectMatrix);
+
+ // Use a FillHatchPrimitive2D with necessary attributes
+ const drawinglayer::attribute::FillHatchAttribute aFillHatch(
+ drawinglayer::attribute::HatchStyle::Single, // single hatch
+ 125.0, // 1.25 mm
+ basegfx::deg2rad(45.0), // 45 degree diagonal
+ COL_BLACK.getBColor(), // black color
+ 3, // same default as VCL, a minimum of three discrete units (pixels) offset
+ false); // no filling
+
+ const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::PolyPolygonHatchPrimitive2D(
+ basegfx::B2DPolyPolygon(aObjectOutline),
+ COL_BLACK.getBColor(),
+ aFillHatch));
+
+ rVisitor.visit(xReference);
+ }
+ }
+
+ }
+}
+
+ViewObjectContactOfSdrOle2Obj::ViewObjectContactOfSdrOle2Obj(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfSdrOle2Obj::~ViewObjectContactOfSdrOle2Obj()
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofsdrpage.cxx b/svx/source/sdr/contact/viewobjectcontactofsdrpage.cxx
new file mode 100644
index 000000000..fe9855f4c
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofsdrpage.cxx
@@ -0,0 +1,579 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewobjectcontactofsdrpage.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <sdr/contact/viewcontactofsdrpage.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/gridprimitive2d.hxx>
+#include <drawinglayer/primitive2d/helplineprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <sdr/primitive2d/sdrprimitivetools.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::contact {
+
+const SdrPage& ViewObjectContactOfPageSubObject::getPage() const
+{
+ return static_cast< ViewContactOfPageSubObject& >(GetViewContact()).getPage();
+}
+
+ViewObjectContactOfPageSubObject::ViewObjectContactOfPageSubObject(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContact(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageSubObject::~ViewObjectContactOfPageSubObject()
+{
+}
+
+bool ViewObjectContactOfPageSubObject::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(rDisplayInfo.GetSubContentActive())
+ {
+ return false;
+ }
+
+ if(rDisplayInfo.GetControlLayerProcessingActive())
+ {
+ return false;
+ }
+
+ if(!rDisplayInfo.GetPageProcessingActive())
+ {
+ return false;
+ }
+
+ if(GetObjectContact().isOutputToPrinter())
+ {
+ return false;
+ }
+
+ if(!GetObjectContact().TryToGetSdrPageView())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ViewObjectContactOfPageSubObject::isPrimitiveGhosted(const DisplayInfo& /*rDisplayInfo*/) const
+{
+ // suppress ghosted for page parts
+ return false;
+}
+
+ViewObjectContactOfPageBackground::ViewObjectContactOfPageBackground(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageBackground::~ViewObjectContactOfPageBackground()
+{
+}
+
+bool ViewObjectContactOfPageBackground::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ // no page background for preview renderers
+ if(GetObjectContact().IsPreviewRenderer())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void ViewObjectContactOfPageBackground::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // Initialize background. Dependent of IsPageVisible, use ApplicationBackgroundColor or ApplicationDocumentColor. Most
+ // old renderers for export (html, pdf, gallery, ...) set the page to not visible (SetPageVisible(false)). They expect the
+ // given OutputDevice to be initialized with the ApplicationDocumentColor then.
+ const SdrPageView* pPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pPageView)
+ {
+ const SdrView& rView = pPageView->GetView();
+ Color aInitColor;
+
+ if(rView.IsPageVisible())
+ {
+ aInitColor = pPageView->GetApplicationBackgroundColor();
+ }
+ else
+ {
+ aInitColor = pPageView->GetApplicationDocumentColor();
+
+ if(COL_AUTO == aInitColor)
+ {
+ const svtools::ColorConfig aColorConfig;
+ aInitColor = aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
+ }
+ }
+
+ // init background with InitColor
+ const basegfx::BColor aRGBColor(aInitColor.getBColor());
+ rVisitor.visit(new drawinglayer::primitive2d::BackgroundColorPrimitive2D(aRGBColor, (255 - aInitColor.GetAlpha()) / 255.0));
+ }
+}
+
+ViewObjectContactOfMasterPage::ViewObjectContactOfMasterPage(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfMasterPage::~ViewObjectContactOfMasterPage()
+{
+}
+
+bool ViewObjectContactOfMasterPage::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ // this object is only used for MasterPages. When not the MasterPage is
+ // displayed as a page, but another page is using it as sub-object, the
+ // geometry needs to be hidden
+ if(rDisplayInfo.GetSubContentActive())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+ViewObjectContactOfPageFill::ViewObjectContactOfPageFill(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageFill::~ViewObjectContactOfPageFill()
+{
+}
+
+bool ViewObjectContactOfPageFill::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ if(!pSdrPageView->GetView().IsPageVisible())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void ViewObjectContactOfPageFill::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPageView* pPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pPageView)
+ {
+ const SdrPage& rPage = getPage();
+
+ const basegfx::B2DRange aPageFillRange(0.0, 0.0, static_cast<double>(rPage.GetWidth()), static_cast<double>(rPage.GetHeight()));
+ const basegfx::B2DPolygon aPageFillPolygon(basegfx::utils::createPolygonFromRect(aPageFillRange));
+ Color aPageFillColor;
+
+ if(pPageView->GetApplicationDocumentColor() != COL_AUTO)
+ {
+ aPageFillColor = pPageView->GetApplicationDocumentColor();
+ }
+ else
+ {
+ const svtools::ColorConfig aColorConfig;
+ aPageFillColor = aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
+ }
+
+ // create and add primitive
+ const basegfx::BColor aRGBColor(aPageFillColor.getBColor());
+ rVisitor.visit(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPageFillPolygon), aRGBColor));
+ }
+}
+
+ViewObjectContactOfPageShadow::ViewObjectContactOfPageShadow(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageShadow::~ViewObjectContactOfPageShadow()
+{
+}
+
+bool ViewObjectContactOfPageShadow::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ if(!pSdrPageView->GetView().IsPageVisible())
+ {
+ return false;
+ }
+
+ if(!pSdrPageView->GetView().IsPageShadowVisible())
+ {
+ return false;
+ }
+
+ // no page shadow for preview renderers
+ if(GetObjectContact().IsPreviewRenderer())
+ {
+ return false;
+ }
+
+ // no page shadow for high contrast mode
+ if(GetObjectContact().isDrawModeHighContrast())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+ViewObjectContactOfOuterPageBorder::ViewObjectContactOfOuterPageBorder(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfOuterPageBorder::~ViewObjectContactOfOuterPageBorder()
+{
+}
+
+bool ViewObjectContactOfOuterPageBorder::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ const SdrView& rView = pSdrPageView->GetView();
+
+ return rView.IsPageVisible() || !rView.IsPageBorderVisible();
+}
+
+ViewObjectContactOfInnerPageBorder::ViewObjectContactOfInnerPageBorder(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfInnerPageBorder::~ViewObjectContactOfInnerPageBorder()
+{
+}
+
+bool ViewObjectContactOfInnerPageBorder::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ if(!pSdrPageView->GetView().IsBordVisible())
+ {
+ return false;
+ }
+
+ const SdrPage& rPage = getPage();
+
+ if(!rPage.GetLeftBorder() && !rPage.GetUpperBorder() && !rPage.GetRightBorder() && !rPage.GetLowerBorder())
+ {
+ return false;
+ }
+
+ // no inner page border for preview renderers
+ if(GetObjectContact().IsPreviewRenderer())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+ViewObjectContactOfPageHierarchy::ViewObjectContactOfPageHierarchy(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageHierarchy::~ViewObjectContactOfPageHierarchy()
+{
+}
+
+void ViewObjectContactOfPageHierarchy::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // process local sub-hierarchy
+ const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount());
+
+ if(!nSubHierarchyCount)
+ return;
+
+ getPrimitive2DSequenceSubHierarchy(rDisplayInfo, rVisitor);
+}
+
+ViewObjectContactOfPageGrid::ViewObjectContactOfPageGrid(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageGrid::~ViewObjectContactOfPageGrid()
+{
+}
+
+bool ViewObjectContactOfPageGrid::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ const SdrView& rView = pSdrPageView->GetView();
+
+ if(!rView.IsGridVisible())
+ {
+ return false;
+ }
+
+ // no page grid for preview renderers
+ if(GetObjectContact().IsPreviewRenderer())
+ {
+ return false;
+ }
+
+ if(static_cast< ViewContactOfGrid& >(GetViewContact()).getFront() != rView.IsGridFront())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void ViewObjectContactOfPageGrid::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPageView* pPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pPageView)
+ {
+ const SdrView& rView = pPageView->GetView();
+ const SdrPage& rPage = getPage();
+ const Color aGridColor(rView.GetGridColor());
+ const basegfx::BColor aRGBGridColor(aGridColor.getBColor());
+
+ basegfx::B2DHomMatrix aGridMatrix;
+ aGridMatrix.set(0, 0, static_cast<double>(rPage.GetWidth() - (rPage.GetRightBorder() + rPage.GetLeftBorder())));
+ aGridMatrix.set(1, 1, static_cast<double>(rPage.GetHeight() - (rPage.GetLowerBorder() + rPage.GetUpperBorder())));
+ aGridMatrix.set(0, 2, static_cast<double>(rPage.GetLeftBorder()));
+ aGridMatrix.set(1, 2, static_cast<double>(rPage.GetUpperBorder()));
+
+ const Size aRaw(rView.GetGridCoarse());
+ const Size aFine(rView.GetGridFine());
+ const double fWidthX(aRaw.getWidth());
+ const double fWidthY(aRaw.getHeight());
+ const sal_uInt32 nSubdivisionsX(aFine.getWidth() ? aRaw.getWidth() / aFine.getWidth() : 0);
+ const sal_uInt32 nSubdivisionsY(aFine.getHeight() ? aRaw.getHeight() / aFine.getHeight() : 0);
+
+ rVisitor.visit(new drawinglayer::primitive2d::GridPrimitive2D(
+ aGridMatrix, fWidthX, fWidthY, 10.0, 3.0, nSubdivisionsX, nSubdivisionsY, aRGBGridColor,
+ drawinglayer::primitive2d::createDefaultCross_3x3(aRGBGridColor)));
+ }
+}
+
+ViewObjectContactOfPageHelplines::ViewObjectContactOfPageHelplines(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageHelplines::~ViewObjectContactOfPageHelplines()
+{
+}
+
+bool ViewObjectContactOfPageHelplines::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ const SdrView& rView = pSdrPageView->GetView();
+
+ if(!rView.IsHlplVisible())
+ {
+ return false;
+ }
+
+ // no helplines for preview renderers
+ if(GetObjectContact().IsPreviewRenderer())
+ {
+ return false;
+ }
+
+ if(static_cast< ViewContactOfHelplines& >(GetViewContact()).getFront() != rView.IsHlplFront())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void ViewObjectContactOfPageHelplines::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPageView* pPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pPageView)
+ {
+ const SdrHelpLineList& rHelpLineList = pPageView->GetHelpLines();
+ const sal_uInt32 nCount(rHelpLineList.GetCount());
+
+ if(nCount)
+ {
+ const basegfx::BColor aRGBColorA(1.0, 1.0, 1.0);
+ const basegfx::BColor aRGBColorB(0.0, 0.0, 0.0);
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const SdrHelpLine& rHelpLine = rHelpLineList[static_cast<sal_uInt16>(a)];
+ const basegfx::B2DPoint aPosition(static_cast<double>(rHelpLine.GetPos().X()), static_cast<double>(rHelpLine.GetPos().Y()));
+ const double fDiscreteDashLength(4.0);
+
+ switch(rHelpLine.GetKind())
+ {
+ default : // SdrHelpLineKind::Point
+ {
+ rVisitor.visit(new drawinglayer::primitive2d::HelplinePrimitive2D(
+ aPosition, basegfx::B2DVector(1.0, 0.0), drawinglayer::primitive2d::HelplineStyle2D::Point,
+ aRGBColorA, aRGBColorB, fDiscreteDashLength));
+ break;
+ }
+ case SdrHelpLineKind::Vertical :
+ {
+ rVisitor.visit(new drawinglayer::primitive2d::HelplinePrimitive2D(
+ aPosition, basegfx::B2DVector(0.0, 1.0), drawinglayer::primitive2d::HelplineStyle2D::Line,
+ aRGBColorA, aRGBColorB, fDiscreteDashLength));
+ break;
+ }
+ case SdrHelpLineKind::Horizontal :
+ {
+ rVisitor.visit(new drawinglayer::primitive2d::HelplinePrimitive2D(
+ aPosition, basegfx::B2DVector(1.0, 0.0), drawinglayer::primitive2d::HelplineStyle2D::Line,
+ aRGBColorA, aRGBColorB, fDiscreteDashLength));
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+ViewObjectContactOfSdrPage::ViewObjectContactOfSdrPage(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContact(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfSdrPage::~ViewObjectContactOfSdrPage()
+{
+}
+
+void ViewObjectContactOfSdrPage::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // process local sub-hierarchy
+ const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount());
+
+ if(!nSubHierarchyCount)
+ return;
+
+ const bool bDoGhostedDisplaying(
+ GetObjectContact().DoVisualizeEnteredGroup()
+ && !GetObjectContact().isOutputToPrinter()
+ && GetObjectContact().getActiveViewContact() == &GetViewContact());
+
+ if(bDoGhostedDisplaying)
+ {
+ rDisplayInfo.ClearGhostedDrawMode();
+ }
+
+ // visit object hierarchy
+ getPrimitive2DSequenceSubHierarchy(rDisplayInfo, rVisitor);
+
+ if(bDoGhostedDisplaying)
+ {
+ rDisplayInfo.SetGhostedDrawMode();
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
new file mode 100644
index 000000000..5ca5a32d2
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
@@ -0,0 +1,1777 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
+#include <sdr/contact/viewcontactofunocontrol.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sdrpagewindow.hxx>
+
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <com/sun/star/awt/PosSize.hpp>
+#include <com/sun/star/awt/XView.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/awt/InvalidateStyle.hpp>
+#include <com/sun/star/util/XModeChangeListener.hpp>
+#include <com/sun/star/util/XModeChangeBroadcaster.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+
+#include <vcl/canvastools.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
+
+/*
+
+Form controls (more precise: UNO Controls) in the drawing layer are ... prone to breakage, since they have some
+specialities which the drawing layer currently doesn't capture too well. In particular, having a living VCL
+window as child of the document window, and coupling this Window to a drawing layer object, makes things
+difficult sometimes.
+
+Below is a list of issues which existed in the past. Whenever you change code here, you're encouraged to
+verify those issues are still fixed. (Whenever you have some additional time, you're encouraged to write
+an automatic test for one or more of those issues for which this is possible :)
+
+https://bz.apache.org/ooo/show_bug.cgi?id=105992
+zooming documents containing (alive) form controls improperly positions the controls
+
+https://bz.apache.org/ooo/show_bug.cgi?id=104362
+crash when copy a control
+
+https://bz.apache.org/ooo/show_bug.cgi?id=104544
+Gridcontrol duplicated after design view on/off
+
+https://bz.apache.org/ooo/show_bug.cgi?id=102089
+print preview shows control elements with property printable=false
+
+https://bz.apache.org/ooo/show_bug.cgi?id=102090
+problem with setVisible on TextControl
+
+https://bz.apache.org/ooo/show_bug.cgi?id=103138
+loop when insert a control in draw
+
+https://bz.apache.org/ooo/show_bug.cgi?id=101398
+initially-displaying a document with many controls is very slow
+
+https://bz.apache.org/ooo/show_bug.cgi?id=72429
+repaint error in form wizard in bugdoc database
+
+https://bz.apache.org/ooo/show_bug.cgi?id=72694
+form control artifacts when scrolling a text fast
+
+*/
+
+
+namespace sdr::contact {
+
+
+ using namespace ::com::sun::star::awt::InvalidateStyle;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::awt::XControl;
+ using ::com::sun::star::awt::XControlModel;
+ using ::com::sun::star::awt::XControlContainer;
+ using ::com::sun::star::awt::XWindow2;
+ using ::com::sun::star::awt::XWindowListener;
+ using ::com::sun::star::awt::PosSize::POSSIZE;
+ using ::com::sun::star::awt::XView;
+ using ::com::sun::star::awt::WindowEvent;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::awt::XWindowPeer;
+ using ::com::sun::star::beans::XPropertyChangeListener;
+ using ::com::sun::star::util::XModeChangeListener;
+ using ::com::sun::star::util::XModeChangeBroadcaster;
+ using ::com::sun::star::util::ModeChangeEvent;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+ using ::com::sun::star::container::XContainerListener;
+ using ::com::sun::star::container::XContainer;
+ using ::com::sun::star::container::ContainerEvent;
+ using ::com::sun::star::uno::Any;
+
+ namespace {
+
+ class ControlHolder
+ {
+ private:
+ Reference< XControl > m_xControl;
+ Reference< XWindow2 > m_xControlWindow;
+ Reference< XView > m_xControlView;
+
+ public:
+ ControlHolder()
+ {
+ }
+
+ explicit ControlHolder( const Reference< XControl >& _rxControl )
+ {
+ *this = _rxControl;
+ }
+
+ ControlHolder& operator=( const Reference< XControl >& _rxControl )
+ {
+ clear();
+
+ m_xControl = _rxControl;
+ if ( m_xControl.is() )
+ {
+ m_xControlWindow.set( m_xControl, UNO_QUERY );
+ m_xControlView.set( m_xControl, UNO_QUERY );
+ if ( !m_xControlWindow.is() || !m_xControlView.is() )
+ {
+ OSL_FAIL( "ControlHolder::operator=: invalid XControl, missing required interfaces!" );
+ clear();
+ }
+ }
+
+ return *this;
+ }
+
+ public:
+ bool is() const { return m_xControl.is() && m_xControlWindow.is() && m_xControlView.is(); }
+ void clear() { m_xControl.clear(); m_xControlWindow.clear(); m_xControlView.clear(); }
+
+ // delegators for the methods of the UNO interfaces
+ // Note all those will crash if called for a NULL object.
+ bool isDesignMode() const { return m_xControl->isDesignMode(); }
+ void setDesignMode( const bool _bDesign ) const { m_xControl->setDesignMode( _bDesign ); }
+ bool isVisible() const { return m_xControlWindow->isVisible(); }
+ void setVisible( const bool _bVisible ) const { m_xControlWindow->setVisible( _bVisible ); }
+ Reference< XControlModel >
+ getModel() const { return m_xControl->getModel(); }
+ void setModel( const Reference< XControlModel >& _m ) const { m_xControl->setModel( _m ); }
+
+ void addWindowListener( const Reference< XWindowListener >& _l ) const { m_xControlWindow->addWindowListener( _l ); }
+ void removeWindowListener( const Reference< XWindowListener >& _l ) const { m_xControlWindow->removeWindowListener( _l ); }
+ void setPosSize( const tools::Rectangle& _rPosSize ) const;
+ tools::Rectangle
+ getPosSize() const;
+ void setZoom( const ::basegfx::B2DVector& _rScale ) const;
+ ::basegfx::B2DVector
+ getZoom() const;
+
+ void invalidate() const;
+
+ public:
+ const Reference< XControl >& getControl() const { return m_xControl; }
+ };
+
+ bool operator==( const ControlHolder& _rControl, const Reference< XInterface >& _rxCompare )
+ {
+ return _rControl.getControl() == _rxCompare;
+ }
+
+ bool operator==( const ControlHolder& _rControl, const Any& _rxCompare )
+ {
+ return _rControl == Reference< XInterface >( _rxCompare, UNO_QUERY );
+ }
+
+ }
+
+ void ControlHolder::setPosSize( const tools::Rectangle& _rPosSize ) const
+ {
+ // no check whether we're valid, this is the responsibility of the caller
+
+ // don't call setPosSize when pos/size did not change #i104181#
+ ::tools::Rectangle aCurrentRect( getPosSize() );
+ if ( aCurrentRect != _rPosSize )
+ {
+ m_xControlWindow->setPosSize(
+ _rPosSize.Left(), _rPosSize.Top(), _rPosSize.GetWidth(), _rPosSize.GetHeight(),
+ POSSIZE
+ );
+ }
+ }
+
+
+ ::tools::Rectangle ControlHolder::getPosSize() const
+ {
+ // no check whether we're valid, this is the responsibility of the caller
+ return VCLUnoHelper::ConvertToVCLRect( m_xControlWindow->getPosSize() );
+ }
+
+
+ void ControlHolder::setZoom( const ::basegfx::B2DVector& _rScale ) const
+ {
+ // no check whether we're valid, this is the responsibility of the caller
+ m_xControlView->setZoom( static_cast<float>(_rScale.getX()), static_cast<float>(_rScale.getY()) );
+ }
+
+
+ void ControlHolder::invalidate() const
+ {
+ Reference< XWindowPeer > xPeer( m_xControl->getPeer() );
+ if ( xPeer.is() )
+ {
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xPeer );
+ OSL_ENSURE( pWindow, "ControlHolder::invalidate: no implementation access!" );
+ if ( pWindow )
+ pWindow->Invalidate();
+ }
+ }
+
+
+ ::basegfx::B2DVector ControlHolder::getZoom() const
+ {
+ // no check whether we're valid, this is the responsibility of the caller
+
+ // Argh. Why does XView have a setZoom only, but not a getZoom?
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( m_xControl->getPeer() );
+ OSL_ENSURE( pWindow, "ControlHolder::getZoom: no implementation access!" );
+
+ ::basegfx::B2DVector aZoom( 1, 1 );
+ if ( pWindow )
+ {
+ const Fraction& rZoom( pWindow->GetZoom() );
+ aZoom.setX( static_cast<double>(rZoom) );
+ aZoom.setY( static_cast<double>(rZoom) );
+ }
+ return aZoom;
+ }
+
+ namespace UnoControlContactHelper {
+
+ /** positions a control, and sets its zoom mode, using a given transformation and output device
+ */
+ static void adjustControlGeometry_throw( const ControlHolder& _rControl, const tools::Rectangle& _rLogicBoundingRect,
+ const basegfx::B2DHomMatrix& _rViewTransformation, const ::basegfx::B2DHomMatrix& _rZoomLevelNormalization )
+ {
+ OSL_PRECOND( _rControl.is(), "UnoControlContactHelper::adjustControlGeometry_throw: illegal control!" );
+ if ( !_rControl.is() )
+ return;
+
+ #if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DTuple aViewScale, aViewTranslate;
+ double nViewRotate(0), nViewShearX(0);
+ _rViewTransformation.decompose( aViewScale, aViewTranslate, nViewRotate, nViewShearX );
+
+ ::basegfx::B2DTuple aZoomScale, aZoomTranslate;
+ double nZoomRotate(0), nZoomShearX(0);
+ _rZoomLevelNormalization.decompose( aZoomScale, aZoomTranslate, nZoomRotate, nZoomShearX );
+ #endif
+
+ // transform the logic bound rect, using the view transformation, to pixel coordinates
+ ::basegfx::B2DPoint aTopLeft( _rLogicBoundingRect.Left(), _rLogicBoundingRect.Top() );
+ aTopLeft *= _rViewTransformation;
+ ::basegfx::B2DPoint aBottomRight( _rLogicBoundingRect.Right(), _rLogicBoundingRect.Bottom() );
+ aBottomRight *= _rViewTransformation;
+
+ const tools::Rectangle aPaintRectPixel(static_cast<tools::Long>(std::round(aTopLeft.getX())),
+ static_cast<tools::Long>(std::round(aTopLeft.getY())),
+ static_cast<tools::Long>(std::round(aBottomRight.getX())),
+ static_cast<tools::Long>(std::round(aBottomRight.getY())));
+ _rControl.setPosSize( aPaintRectPixel );
+
+ // determine the scale from the current view transformation, and the normalization matrix
+ ::basegfx::B2DHomMatrix aObtainResolutionDependentScale( _rViewTransformation * _rZoomLevelNormalization );
+ ::basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aObtainResolutionDependentScale.decompose( aScale, aTranslate, fRotate, fShearX );
+ _rControl.setZoom( aScale );
+ }
+
+ /** disposes the given control
+ */
+ static void disposeAndClearControl_nothrow( ControlHolder& _rControl )
+ {
+ try
+ {
+ Reference< XComponent > xControlComp = _rControl.getControl();
+ if ( xControlComp.is() )
+ xControlComp->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ _rControl.clear();
+ }
+
+ }
+
+ namespace {
+
+ /** interface encapsulating access to an SdrPageView, stripped down to the methods we really need
+ */
+ class IPageViewAccess
+ {
+ public:
+ /** determines whether the view is currently in design mode
+ */
+ virtual bool isDesignMode() const = 0;
+
+ /** retrieves the control container for a given output device
+ */
+ virtual Reference< XControlContainer >
+ getControlContainer( const OutputDevice& _rDevice ) const = 0;
+
+ /** determines whether a given layer is visible
+ */
+ virtual bool isLayerVisible( SdrLayerID _nLayerID ) const = 0;
+
+ protected:
+ ~IPageViewAccess() {}
+ };
+
+ /** is a ->IPageViewAccess implementation based on a real ->SdrPageView instance
+ */
+ class SdrPageViewAccess : public IPageViewAccess
+ {
+ const SdrPageView& m_rPageView;
+ public:
+ explicit SdrPageViewAccess( const SdrPageView& _rPageView ) : m_rPageView( _rPageView ) { }
+
+ virtual ~SdrPageViewAccess() {}
+
+ virtual bool isDesignMode() const override;
+ virtual Reference< XControlContainer >
+ getControlContainer( const OutputDevice& _rDevice ) const override;
+ virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
+ };
+
+ }
+
+ bool SdrPageViewAccess::isDesignMode() const
+ {
+ return m_rPageView.GetView().IsDesignMode();
+ }
+
+
+ Reference< XControlContainer > SdrPageViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
+ {
+ Reference< XControlContainer > xControlContainer = m_rPageView.GetControlContainer( _rDevice );
+ DBG_ASSERT( xControlContainer.is() || nullptr == m_rPageView.FindPageWindow( _rDevice ),
+ "SdrPageViewAccess::getControlContainer: the output device is known, but there is no control container for it?" );
+ return xControlContainer;
+ }
+
+
+ bool SdrPageViewAccess::isLayerVisible( SdrLayerID _nLayerID ) const
+ {
+ return m_rPageView.GetVisibleLayers().IsSet( _nLayerID );
+ }
+
+ namespace {
+
+ /** is a ->IPageViewAccess implementation which can be used to create an invisible control for
+ an arbitrary window
+ */
+ class InvisibleControlViewAccess : public IPageViewAccess
+ {
+ private:
+ Reference< XControlContainer >& m_rControlContainer;
+ public:
+ explicit InvisibleControlViewAccess( Reference< XControlContainer >& _inout_ControlContainer )
+ :m_rControlContainer( _inout_ControlContainer )
+ {
+ }
+
+ virtual ~InvisibleControlViewAccess() {}
+
+ virtual bool isDesignMode() const override;
+ virtual Reference< XControlContainer >
+ getControlContainer( const OutputDevice& _rDevice ) const override;
+ virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
+ };
+
+ }
+
+ bool InvisibleControlViewAccess::isDesignMode() const
+ {
+ return true;
+ }
+
+
+ Reference< XControlContainer > InvisibleControlViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
+ {
+ if ( !m_rControlContainer.is() )
+ {
+ const vcl::Window* pWindow = _rDevice.GetOwnerWindow();
+ OSL_ENSURE( pWindow, "InvisibleControlViewAccess::getControlContainer: expected to be called for a window only!" );
+ if ( pWindow )
+ m_rControlContainer = VCLUnoHelper::CreateControlContainer( const_cast< vcl::Window* >( pWindow ) );
+ }
+ return m_rControlContainer;
+ }
+
+
+ bool InvisibleControlViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
+ {
+ return false;
+ }
+
+ namespace {
+
+ //= DummyPageViewAccess
+
+ /** is a ->IPageViewAccess implementation which can be used to create a control for an arbitrary
+ non-Window device
+
+ The implementation will report the "PageView" as being in design mode, all layers to be visible,
+ and will not return any ControlContainer, so all control container related features (notifications etc)
+ are not available.
+ */
+ class DummyPageViewAccess : public IPageViewAccess
+ {
+ public:
+ DummyPageViewAccess()
+ {
+ }
+
+ virtual ~DummyPageViewAccess() {}
+
+ virtual bool isDesignMode() const override;
+ virtual Reference< XControlContainer >
+ getControlContainer( const OutputDevice& _rDevice ) const override;
+ virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
+ };
+
+ }
+
+ bool DummyPageViewAccess::isDesignMode() const
+ {
+ return true;
+ }
+
+
+ Reference< XControlContainer > DummyPageViewAccess::getControlContainer( const OutputDevice& /*_rDevice*/ ) const
+ {
+ return nullptr;
+ }
+
+
+ bool DummyPageViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
+ {
+ return true;
+ }
+
+
+ //= ViewObjectContactOfUnoControl_Impl
+
+ typedef ::cppu::WeakImplHelper < XWindowListener
+ , XPropertyChangeListener
+ , XContainerListener
+ , XModeChangeListener
+ > ViewObjectContactOfUnoControl_Impl_Base;
+
+ class ViewObjectContactOfUnoControl_Impl:
+ public ViewObjectContactOfUnoControl_Impl_Base
+ {
+ private:
+ // tdf#41935 note that access to members is protected with SolarMutex;
+ // the class previously had its own mutex but that is prone to deadlock
+
+ /// the instance whose IMPL we are
+ ViewObjectContactOfUnoControl* m_pAntiImpl;
+
+ /// are we currently inside impl_ensureControl_nothrow?
+ bool m_bCreatingControl;
+
+ /// the control we're responsible for
+ ControlHolder m_aControl;
+
+ /// the ControlContainer where we inserted our control
+ Reference< XContainer > m_xContainer;
+
+ /// the output device for which the control was created
+ VclPtr<OutputDevice> m_pOutputDeviceForWindow;
+
+ /// flag indicating whether the control is currently visible
+ bool m_bControlIsVisible;
+
+ /// are we currently listening at a design mode control?
+ bool m_bIsDesignModeListening;
+
+ enum ViewControlMode
+ {
+ eDesign,
+ eAlive,
+ eUnknown
+ };
+ /// is the control currently in design mode?
+ mutable ViewControlMode m_eControlDesignMode;
+
+ ::basegfx::B2DHomMatrix m_aZoomLevelNormalization;
+
+ public:
+ explicit ViewObjectContactOfUnoControl_Impl( ViewObjectContactOfUnoControl* _pAntiImpl );
+ ViewObjectContactOfUnoControl_Impl(const ViewObjectContactOfUnoControl_Impl&) = delete;
+ ViewObjectContactOfUnoControl_Impl& operator=(const ViewObjectContactOfUnoControl_Impl&) = delete;
+
+ /** disposes the instance, which is nonfunctional afterwards
+ */
+ void dispose();
+
+ /** determines whether the instance is disposed
+ */
+ bool isDisposed() const { return impl_isDisposed_nofail(); }
+
+ /** returns the SdrUnoObject associated with the ViewContact
+
+ @precond
+ We're not disposed.
+ */
+ SdrUnoObj* getUnoObject() const;
+
+ /** ensures that we have an ->XControl
+
+ Must only be called if a control is needed when no DisplayInfo is present, yet.
+
+ For creating a control, an ->OutputDevice is needed, and an ->SdrPageView. Both will be obtained
+ from a ->ObjectContactOfPageView. So, if our (anti-impl's) object contact is not a ->ObjectContactOfPageView,
+ this method fill fail.
+
+ Failure of this method will be reported via an assertion in a non-product version.
+ */
+ void ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL );
+
+ /** returns our XControl, if it already has been created
+
+ If you want to ensure that the control exists before accessing it, use ->ensureControl
+ */
+ const ControlHolder&
+ getExistentControl() const { return m_aControl; }
+
+ bool
+ hasControl() const { return m_aControl.is(); }
+
+ /** positions our XControl according to the geometry settings in the SdrUnoObj, modified by the given
+ transformation, and sets proper zoom settings according to our device
+
+ @precond
+ ->m_pOutputDeviceForWindow and ->m_aControl are not <NULL/>
+ */
+ void positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const;
+
+ /** determines whether or not our control is printable
+
+ Effectively, this method returns the value of the "Printable" property
+ of the control's model. If we have no control, <FALSE/> is returned.
+ */
+ bool isPrintableControl() const;
+
+ /** sets the design mode on the control, or at least remembers the flag for the
+ time the control is created
+ */
+ void setControlDesignMode( bool _bDesignMode ) const;
+
+ /** determines whether our control is currently visible
+ @nofail
+ */
+ bool isControlVisible() const { return m_bControlIsVisible; }
+
+ /// creates an XControl for the given device and SdrUnoObj
+ static bool
+ createControlForDevice(
+ IPageViewAccess const & _rPageView,
+ const OutputDevice& _rDevice,
+ const SdrUnoObj& _rUnoObject,
+ const basegfx::B2DHomMatrix& _rInitialViewTransformation,
+ const basegfx::B2DHomMatrix& _rInitialZoomNormalization,
+ ControlHolder& _out_rControl
+ );
+
+ const ViewContactOfUnoControl&
+ getViewContact() const
+ {
+ ENSURE_OR_THROW( !impl_isDisposed_nofail(), "already disposed" );
+ return static_cast< const ViewContactOfUnoControl& >( m_pAntiImpl->GetViewContact() );
+ }
+
+ protected:
+ virtual ~ViewObjectContactOfUnoControl_Impl() override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& Source ) override;
+
+ // XWindowListener
+ virtual void SAL_CALL windowResized( const WindowEvent& e ) override;
+ virtual void SAL_CALL windowMoved( const WindowEvent& e ) override;
+ virtual void SAL_CALL windowShown( const EventObject& e ) override;
+ virtual void SAL_CALL windowHidden( const EventObject& e ) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const PropertyChangeEvent& evt ) override;
+
+ // XModeChangeListener
+ virtual void SAL_CALL modeChanged( const ModeChangeEvent& _rSource ) override;
+
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+
+ private:
+ /** retrieves the SdrPageView which our associated SdrPageViewWindow belongs to
+
+ @param out_rpPageView
+ a reference to a pointer holding, upon return, the desired SdrPageView
+
+ @return
+ <TRUE/> if and only if a ->SdrPageView could be obtained
+
+ @precond
+ We really belong to an SdrPageViewWindow. Perhaps (I'm not sure ATM :)
+ there are instance for which this might not be true, but those instances
+ should never have a need to call this method.
+
+ @precond
+ We're not disposed.
+
+ @postcond
+ The method expects success, if it returns with <FALSE/>, this will have been
+ asserted.
+
+ @nothrow
+ */
+ bool impl_getPageView_nothrow( SdrPageView*& _out_rpPageView );
+
+ /** adjusts the control visibility so it respects its layer's visibility
+
+ @precond
+ ->m_aControl is not <NULL/>
+
+ @precond
+ We're not disposed.
+
+ @precond
+ We really belong to an SdrPageViewWindow. There are instance for which this
+ might not be true, but those instances should never have a need to call
+ this method.
+ */
+ void impl_adjustControlVisibilityToLayerVisibility_throw();
+
+ /** adjusts the control visibility so it respects its layer's visibility
+
+ The control must never be visible if it's in design mode.
+ In alive mode, it must be visibility if and only it's on a visible layer.
+
+ @param _rxControl
+ the control whose visibility is to be adjusted
+
+ @param _rPageView
+ provides access to the attributes of the SdrPageView which the control finally belongs to
+
+ @param _rUnoObject
+ our SdrUnoObj
+
+ @param _bIsCurrentlyVisible
+ determines whether the control is currently visible. Note that this is only a shortcut for
+ querying _rxControl for the XWindow2 interface, and calling isVisible at this interface.
+ This shortcut has been chosen since the caller usually already has this information.
+ If _bForce is <TRUE/>, _bIsCurrentlyVisible is ignored.
+
+ @param _bForce
+ set to <TRUE/> if you want to force a ->XWindow::setVisible call,
+ no matter if the control visibility is already correct
+
+ @precond
+ We're not disposed.
+ */
+ static void impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rxControl, const SdrUnoObj& _rUnoObject,
+ IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce );
+
+ /** starts or stops listening at various aspects of our control
+
+ @precond
+ ->m_aControl is not <NULL/>
+ */
+ void impl_switchControlListening_nothrow( bool _bStart );
+
+ /** starts or stops listening at our control container
+
+ @precond
+ ->m_xContainer is not <NULL/>
+ */
+ void impl_switchContainerListening_nothrow( bool _bStart );
+
+ /** starts or stops listening at the control for design-mode relevant facets
+ */
+ void impl_switchDesignModeListening_nothrow( bool _bStart );
+
+ /** starts or stops listening for all properties at our control
+
+ @param _bStart
+ determines whether to start or to stop listening
+
+ @precond
+ ->m_aControl is not <NULL/>
+ */
+ void impl_switchPropertyListening_nothrow( bool _bStart );
+
+ /** disposes the instance
+ @param _bAlsoDisposeControl
+ determines whether the XControl should be disposed, too
+ */
+ void impl_dispose_nothrow( bool _bAlsoDisposeControl );
+
+ /** determines whether the instance is disposed
+ @nofail
+ */
+ bool impl_isDisposed_nofail() const { return m_pAntiImpl == nullptr; }
+
+ /** determines whether the control currently is in design mode
+
+ @precond
+ The design mode must already be known. It is known when we first had access to
+ an SdrPageView (which carries this flag), or somebody explicitly set it from
+ outside.
+ */
+ bool impl_isControlDesignMode_nothrow() const
+ {
+ DBG_ASSERT( m_eControlDesignMode != eUnknown, "ViewObjectContactOfUnoControl_Impl::impl_isControlDesignMode_nothrow: mode is still unknown!" );
+ return m_eControlDesignMode == eDesign;
+ }
+
+ /** ensures that we have a control for the given PageView/OutputDevice
+ */
+ bool impl_ensureControl_nothrow(
+ IPageViewAccess const & _rPageView,
+ const OutputDevice& _rDevice,
+ const basegfx::B2DHomMatrix& _rInitialViewTransformation
+ );
+
+ const OutputDevice& impl_getOutputDevice_throw() const;
+ };
+
+ namespace {
+
+ class LazyControlCreationPrimitive2D : public ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
+ {
+ private:
+ typedef ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D BufferedDecompositionPrimitive2D;
+
+ protected:
+ virtual void
+ get2DDecomposition(
+ ::drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor,
+ const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
+ ) const override;
+
+ virtual void create2DDecomposition(
+ ::drawinglayer::primitive2d::Primitive2DContainer& rContainer,
+ const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
+ ) const override;
+
+ virtual ::basegfx::B2DRange
+ getB2DRange(
+ const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
+ ) const override;
+
+ public:
+ explicit LazyControlCreationPrimitive2D( const ::rtl::Reference< ViewObjectContactOfUnoControl_Impl >& _pVOCImpl )
+ :m_pVOCImpl( _pVOCImpl )
+ {
+ ENSURE_OR_THROW( m_pVOCImpl.is(), "Illegal argument." );
+ getTransformation( m_pVOCImpl->getViewContact(), m_aTransformation );
+ }
+
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // declare unique ID for this primitive class
+ virtual sal_uInt32 getPrimitive2DID() const override;
+
+ static void getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation );
+
+ private:
+ void impl_positionAndZoomControl( const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
+ {
+ if ( !_rViewInformation.getViewport().isEmpty() )
+ m_pVOCImpl->positionAndZoomControl( _rViewInformation.getObjectToViewTransformation() );
+ }
+
+ private:
+ ::rtl::Reference< ViewObjectContactOfUnoControl_Impl > m_pVOCImpl;
+ /** The geometry is part of the identity of a primitive, so we cannot calculate it on demand
+ (since the data the calculation is based on might have changed then), but need to calc
+ it at construction time, and remember it.
+ */
+ ::basegfx::B2DHomMatrix m_aTransformation;
+ };
+
+ }
+
+ ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl( ViewObjectContactOfUnoControl* _pAntiImpl )
+ :m_pAntiImpl( _pAntiImpl )
+ ,m_bCreatingControl( false )
+ ,m_pOutputDeviceForWindow( nullptr )
+ ,m_bControlIsVisible( false )
+ ,m_bIsDesignModeListening( false )
+ ,m_eControlDesignMode( eUnknown )
+ {
+ DBG_ASSERT( m_pAntiImpl, "ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl: invalid AntiImpl!" );
+
+ const OutputDevice& rPageViewDevice( impl_getOutputDevice_throw() );
+ m_aZoomLevelNormalization = rPageViewDevice.GetInverseViewTransformation();
+
+ #if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
+ #endif
+
+ ::basegfx::B2DHomMatrix aScaleNormalization;
+ const MapMode& aCurrentDeviceMapMode( rPageViewDevice.GetMapMode() );
+ aScaleNormalization.set( 0, 0, static_cast<double>(aCurrentDeviceMapMode.GetScaleX()) );
+ aScaleNormalization.set( 1, 1, static_cast<double>(aCurrentDeviceMapMode.GetScaleY()) );
+ m_aZoomLevelNormalization *= aScaleNormalization;
+
+ #if OSL_DEBUG_LEVEL > 0
+ m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
+ #endif
+ }
+
+
+ ViewObjectContactOfUnoControl_Impl::~ViewObjectContactOfUnoControl_Impl()
+ {
+ if ( !impl_isDisposed_nofail() )
+ {
+ acquire();
+ dispose();
+ }
+
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_dispose_nothrow( bool _bAlsoDisposeControl )
+ {
+ if ( impl_isDisposed_nofail() )
+ return;
+
+ if ( m_aControl.is() )
+ impl_switchControlListening_nothrow( false );
+
+ if ( m_xContainer.is() )
+ impl_switchContainerListening_nothrow( false );
+
+ // dispose the control
+ if ( _bAlsoDisposeControl )
+ UnoControlContactHelper::disposeAndClearControl_nothrow( m_aControl );
+
+ m_aControl.clear();
+ m_xContainer.clear();
+ m_pOutputDeviceForWindow = nullptr;
+ m_bControlIsVisible = false;
+
+ m_pAntiImpl = nullptr;
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::dispose()
+ {
+ SolarMutexGuard aSolarGuard;
+ impl_dispose_nothrow( true );
+ }
+
+
+ SdrUnoObj* ViewObjectContactOfUnoControl_Impl::getUnoObject() const
+ {
+ OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::getUnoObject: already disposed()" );
+ if ( impl_isDisposed_nofail() )
+ return nullptr;
+ auto pRet = dynamic_cast< SdrUnoObj* >( m_pAntiImpl->GetViewContact().TryToGetSdrObject() );
+ DBG_ASSERT( pRet || !m_pAntiImpl->GetViewContact().TryToGetSdrObject(),
+ "ViewObjectContactOfUnoControl_Impl::getUnoObject: invalid SdrObject!" );
+ return pRet;
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const
+ {
+ OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no output device or no control!" );
+ if ( !m_aControl.is() )
+ return;
+
+ try
+ {
+ SdrUnoObj* pUnoObject = getUnoObject();
+ if ( pUnoObject )
+ {
+ const tools::Rectangle aRect( pUnoObject->GetLogicRect() );
+ UnoControlContactHelper::adjustControlGeometry_throw( m_aControl, aRect, _rViewTransformation, m_aZoomLevelNormalization );
+ }
+ else
+ OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no SdrUnoObj!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL )
+ {
+ OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::ensureControl: already disposed()" );
+ if ( impl_isDisposed_nofail() )
+ return;
+
+ ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
+ if ( pPageViewContact )
+ {
+ SdrPageViewAccess aPVAccess( pPageViewContact->GetPageWindow().GetPageView() );
+ const OutputDevice& rDevice( *m_pAntiImpl->getPageViewOutputDevice() );
+ impl_ensureControl_nothrow(
+ aPVAccess,
+ rDevice,
+ _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
+ );
+ return;
+ }
+
+ DummyPageViewAccess aNoPageView;
+ const OutputDevice& rDevice( impl_getOutputDevice_throw() );
+ impl_ensureControl_nothrow(
+ aNoPageView,
+ rDevice,
+ _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
+ );
+ }
+
+
+ const OutputDevice& ViewObjectContactOfUnoControl_Impl::impl_getOutputDevice_throw() const
+ {
+ // do not use ObjectContact::TryToGetOutputDevice, it would not care for the PageWindow's
+ // OriginalPaintWindow
+ const OutputDevice* oPageOutputDev = m_pAntiImpl->getPageViewOutputDevice();
+ if( oPageOutputDev )
+ return *oPageOutputDev;
+
+ const OutputDevice* pDevice = m_pAntiImpl->GetObjectContact().TryToGetOutputDevice();
+ ENSURE_OR_THROW( pDevice, "no output device -> no control" );
+ return *pDevice;
+ }
+
+
+ namespace
+ {
+ void lcl_resetFlag( bool& rbFlag )
+ {
+ rbFlag = false;
+ }
+ }
+
+
+ bool ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow( IPageViewAccess const & _rPageView, const OutputDevice& _rDevice,
+ const basegfx::B2DHomMatrix& _rInitialViewTransformation )
+ {
+ if ( m_bCreatingControl )
+ {
+ OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: reentrance is not really good here!" );
+ // We once had a situation where this was called reentrantly, which lead to all kind of strange effects. All
+ // those affected the grid control, which is the only control so far which is visible in design mode (and
+ // not only in alive mode).
+ // Creating the control triggered a Window::Update on some of its child windows, which triggered a
+ // Paint on parent of the grid control (e.g. the SwEditWin), which triggered a reentrant call to this method,
+ // which it is not really prepared for.
+
+ // /me thinks that re-entrance should be caught on a higher level, i.e. the Drawing Layer should not allow
+ // reentrant paint requests. For the moment, until /me can discuss this with AW, catch it here. #i104544#
+ return false;
+ }
+
+ m_bCreatingControl = true;
+ ::comphelper::ScopeGuard aGuard([&] () { lcl_resetFlag(m_bCreatingControl); });
+
+ if ( m_aControl.is() )
+ {
+ if ( m_pOutputDeviceForWindow.get() == &_rDevice )
+ return true;
+
+ // Somebody requested a control for a new device, which means either of
+ // - our PageView's paint window changed since we were last here
+ // - we don't belong to a page view, and are simply painted onto different devices
+ // The first sounds strange (doesn't it?), the second means we could perhaps
+ // optimize this in the future - there is no need to re-create the control every time,
+ // is it? #i74523#
+ if ( m_xContainer.is() )
+ impl_switchContainerListening_nothrow( false );
+ impl_switchControlListening_nothrow( false );
+ UnoControlContactHelper::disposeAndClearControl_nothrow( m_aControl );
+ }
+
+ SdrUnoObj* pUnoObject = getUnoObject();
+ if ( !pUnoObject )
+ return false;
+
+ ControlHolder aControl;
+ if ( !createControlForDevice( _rPageView, _rDevice, *pUnoObject, _rInitialViewTransformation, m_aZoomLevelNormalization, aControl ) )
+ return false;
+
+ m_pOutputDeviceForWindow = const_cast< OutputDevice * >( &_rDevice );
+ m_aControl = aControl;
+ m_xContainer.set(_rPageView.getControlContainer( _rDevice ), css::uno::UNO_QUERY);
+ DBG_ASSERT( ( m_xContainer.is() // either have a XControlContainer
+ || ( ( !_rPageView.getControlContainer( _rDevice ).is() ) // or don't have any container,
+ && ( _rDevice.GetOwnerWindow() == nullptr ) // which is allowed for non-Window instances only
+ )
+ ),
+ "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: no XContainer at the ControlContainer!" );
+
+ try
+ {
+ m_eControlDesignMode = m_aControl.isDesignMode() ? eDesign : eAlive;
+ m_bControlIsVisible = m_aControl.isVisible();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ // start listening at all aspects of the control which are interesting to us ...
+ impl_switchControlListening_nothrow( true );
+
+ // start listening at the control container, in case somebody tampers with our control
+ if ( m_xContainer.is() )
+ impl_switchContainerListening_nothrow( true );
+
+ return m_aControl.is();
+ }
+
+
+ bool ViewObjectContactOfUnoControl_Impl::createControlForDevice( IPageViewAccess const & _rPageView,
+ const OutputDevice& _rDevice, const SdrUnoObj& _rUnoObject, const basegfx::B2DHomMatrix& _rInitialViewTransformation,
+ const basegfx::B2DHomMatrix& _rInitialZoomNormalization, ControlHolder& _out_rControl )
+ {
+ _out_rControl.clear();
+
+ const Reference< XControlModel >& xControlModel( _rUnoObject.GetUnoControlModel() );
+ DBG_ASSERT( xControlModel.is(), "ViewObjectContactOfUnoControl_Impl::createControlForDevice: no control model at the SdrUnoObject!?" );
+ if ( !xControlModel.is() )
+ return false;
+
+ bool bSuccess = false;
+ try
+ {
+ const OUString& sControlServiceName( _rUnoObject.GetUnoControlTypeName() );
+
+ Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ _out_rControl = Reference<XControl>( xContext->getServiceManager()->createInstanceWithContext(sControlServiceName, xContext), UNO_QUERY_THROW );
+
+ // knit the model and the control
+ _out_rControl.setModel( xControlModel );
+ const tools::Rectangle aRect( _rUnoObject.GetLogicRect() );
+
+ // proper geometry
+ UnoControlContactHelper::adjustControlGeometry_throw(
+ _out_rControl,
+ aRect,
+ _rInitialViewTransformation,
+ _rInitialZoomNormalization
+ );
+
+ // set design mode before peer is created,
+ // this is also needed for accessibility
+ _out_rControl.setDesignMode( _rPageView.isDesignMode() );
+
+ // adjust the initial visibility according to the visibility of the layer
+ impl_adjustControlVisibilityToLayerVisibility_throw( _out_rControl, _rUnoObject, _rPageView, false, true );
+
+ // add the control to the respective control container
+ // do this last
+ Reference< XControlContainer > xControlContainer( _rPageView.getControlContainer( _rDevice ) );
+ if ( xControlContainer.is() )
+ xControlContainer->addControl( sControlServiceName, _out_rControl.getControl() );
+
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ if ( !bSuccess )
+ {
+ // delete the control which might have been created already
+ UnoControlContactHelper::disposeAndClearControl_nothrow( _out_rControl );
+ }
+
+ return _out_rControl.is();
+ }
+
+
+ bool ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow( SdrPageView*& _out_rpPageView )
+ {
+ OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: already disposed!" );
+
+ _out_rpPageView = nullptr;
+ if ( impl_isDisposed_nofail() )
+ return false;
+
+ ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
+ if ( pPageViewContact )
+ _out_rpPageView = &pPageViewContact->GetPageWindow().GetPageView();
+
+ DBG_ASSERT( _out_rpPageView != nullptr, "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: this method is expected to always have success!" );
+ return ( _out_rpPageView != nullptr );
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw()
+ {
+ OSL_PRECOND( m_aControl.is(),
+ "ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw: only valid if we have a control!" );
+
+ SdrPageView* pPageView( nullptr );
+ if ( !impl_getPageView_nothrow( pPageView ) )
+ return;
+
+ SdrUnoObj* pUnoObject = getUnoObject();
+ if ( !pUnoObject )
+ return;
+
+ SdrPageViewAccess aPVAccess( *pPageView );
+ impl_adjustControlVisibilityToLayerVisibility_throw( m_aControl, *pUnoObject, aPVAccess, m_bControlIsVisible, false/*_bForce*/ );
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rControl,
+ const SdrUnoObj& _rUnoObject, IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce )
+ {
+ // in design mode, there is no problem with the visibility: The XControl is hidden by
+ // default, and the Drawing Layer will simply not call our paint routine, if we're in
+ // a hidden layer. So, only alive mode matters.
+ if ( !_rControl.isDesignMode() )
+ {
+ // the layer of our object
+ SdrLayerID nObjectLayer = _rUnoObject.GetLayer();
+ // is the object we're residing in visible in this view?
+ bool bIsObjectVisible = _rUnoObject.IsVisible() && _rPageView.isLayerVisible( nObjectLayer );
+
+ if ( _bForce || ( bIsObjectVisible != _bIsCurrentlyVisible ) )
+ {
+ _rControl.setVisible( bIsObjectVisible );
+ }
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow( bool _bStart )
+ {
+ OSL_PRECOND( m_xContainer.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow: no control container!" );
+ if ( !m_xContainer.is() )
+ return;
+
+ try
+ {
+ if ( _bStart )
+ m_xContainer->addContainerListener( this );
+ else
+ m_xContainer->removeContainerListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow( bool _bStart )
+ {
+ OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow: invalid control!" );
+ if ( !m_aControl.is() )
+ return;
+
+ try
+ {
+ // listen for visibility changes
+ if ( _bStart )
+ m_aControl.addWindowListener( this );
+ else
+ m_aControl.removeWindowListener( this );
+
+ // in design mode, listen for some more aspects
+ impl_switchDesignModeListening_nothrow( impl_isControlDesignMode_nothrow() && _bStart );
+
+ // listen for design mode changes
+ Reference< XModeChangeBroadcaster > xDesignModeChanges( m_aControl.getControl(), UNO_QUERY_THROW );
+ if ( _bStart )
+ xDesignModeChanges->addModeChangeListener( this );
+ else
+ xDesignModeChanges->removeModeChangeListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_switchDesignModeListening_nothrow( bool _bStart )
+ {
+ if ( m_bIsDesignModeListening != _bStart )
+ {
+ m_bIsDesignModeListening = _bStart;
+ impl_switchPropertyListening_nothrow( _bStart );
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow( bool _bStart )
+ {
+ OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow: no control!" );
+ if ( !m_aControl.is() )
+ return;
+
+ try
+ {
+ Reference< XPropertySet > xModelProperties( m_aControl.getModel(), UNO_QUERY_THROW );
+ if ( _bStart )
+ xModelProperties->addPropertyChangeListener( OUString(), this );
+ else
+ xModelProperties->removePropertyChangeListener( OUString(), this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ bool ViewObjectContactOfUnoControl_Impl::isPrintableControl() const
+ {
+ SdrUnoObj* pUnoObject = getUnoObject();
+ if ( !pUnoObject )
+ return false;
+
+ bool bIsPrintable = false;
+ try
+ {
+ Reference< XPropertySet > xModelProperties( pUnoObject->GetUnoControlModel(), UNO_QUERY_THROW );
+ OSL_VERIFY( xModelProperties->getPropertyValue( "Printable" ) >>= bIsPrintable );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return bIsPrintable;
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::disposing( const EventObject& Source )
+ {
+ SolarMutexGuard aSolarGuard;
+ // some code below - in particular our disposal - might trigger actions which require the
+ // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
+ // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
+ // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
+
+ if ( !m_aControl.is() )
+ return;
+
+ if ( ( m_aControl == Source.Source )
+ || ( m_aControl.getModel() == Source.Source )
+ )
+ {
+ // the model or the control is dying ... hmm, not much sense in that we ourself continue
+ // living
+ impl_dispose_nothrow( false );
+ return;
+ }
+
+ DBG_ASSERT( Source.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::disposing: Who's this?" );
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowResized( const WindowEvent& /*e*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowMoved( const WindowEvent& /*e*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowShown( const EventObject& /*e*/ )
+ {
+ SolarMutexGuard aSolarGuard;
+ m_bControlIsVisible = true;
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowHidden( const EventObject& /*e*/ )
+ {
+ SolarMutexGuard aSolarGuard;
+ m_bControlIsVisible = false;
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::propertyChange( const PropertyChangeEvent& /*_rEvent*/ )
+ {
+ SolarMutexGuard aSolarGuard;
+ // (re)painting might require VCL operations, which need the SolarMutex
+
+ OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::propertyChange: already disposed()" );
+ if ( impl_isDisposed_nofail() )
+ return;
+
+ DBG_ASSERT( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::propertyChange: " );
+ if ( !m_aControl.is() )
+ return;
+
+ // a generic property changed. If we're in design mode, we need to repaint the control
+ if ( impl_isControlDesignMode_nothrow() )
+ {
+ m_pAntiImpl->propertyChange();
+ }
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::modeChanged( const ModeChangeEvent& _rSource )
+ {
+ SolarMutexGuard aSolarGuard;
+
+ DBG_ASSERT( _rSource.NewMode == "design" || _rSource.NewMode == "alive", "ViewObjectContactOfUnoControl_Impl::modeChanged: unexpected mode!" );
+
+ m_eControlDesignMode = _rSource.NewMode == "design" ? eDesign : eAlive;
+
+ impl_switchDesignModeListening_nothrow( impl_isControlDesignMode_nothrow() );
+
+ try
+ {
+ // if the control is part of an invisible layer, we need to explicitly hide it in alive mode
+ impl_adjustControlVisibilityToLayerVisibility_throw();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementInserted( const ContainerEvent& /*_Event*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementRemoved( const ContainerEvent& Event )
+ {
+ SolarMutexGuard aSolarGuard;
+ // some code below - in particular our disposal - might trigger actions which require the
+ // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
+ // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
+ // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
+ DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementRemoved: where did this come from?" );
+
+ if ( m_aControl == Event.Element )
+ impl_dispose_nothrow( false );
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementReplaced( const ContainerEvent& Event )
+ {
+ SolarMutexGuard aSolarGuard;
+ DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementReplaced: where did this come from?" );
+
+ if ( ! ( m_aControl == Event.ReplacedElement ) )
+ return;
+
+ Reference< XControl > xNewControl( Event.Element, UNO_QUERY );
+ DBG_ASSERT( xNewControl.is(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: invalid new control!" );
+ if ( !xNewControl.is() )
+ return;
+
+ ENSURE_OR_THROW( m_pOutputDeviceForWindow, "calling this without /me having an output device should be impossible." );
+
+ DBG_ASSERT( xNewControl->getModel() == m_aControl.getModel(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: another model at the new control?" );
+ // another model should - in the drawing layer - also imply another SdrUnoObj, which
+ // should also result in new ViewContact, and thus in new ViewObjectContacts
+
+ impl_switchControlListening_nothrow( false );
+
+ ControlHolder aNewControl( xNewControl );
+ aNewControl.setZoom( m_aControl.getZoom() );
+ aNewControl.setPosSize( m_aControl.getPosSize() );
+ aNewControl.setDesignMode( impl_isControlDesignMode_nothrow() );
+
+ m_aControl = xNewControl;
+ m_bControlIsVisible = m_aControl.isVisible();
+
+ impl_switchControlListening_nothrow( true );
+
+ m_pAntiImpl->onControlChangedOrModified( ViewObjectContactOfUnoControl::ImplAccess() );
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::setControlDesignMode( bool _bDesignMode ) const
+ {
+ if ( ( m_eControlDesignMode != eUnknown ) && ( _bDesignMode == impl_isControlDesignMode_nothrow() ) )
+ // nothing to do
+ return;
+ m_eControlDesignMode = _bDesignMode ? eDesign : eAlive;
+
+ if ( !m_aControl.is() )
+ // nothing to do, the setting will be respected as soon as the control
+ // is created
+ return;
+
+ try
+ {
+ m_aControl.setDesignMode( _bDesignMode );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ //= LazyControlCreationPrimitive2D
+
+
+ bool LazyControlCreationPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if ( !BufferedDecompositionPrimitive2D::operator==( rPrimitive ) )
+ return false;
+
+ const LazyControlCreationPrimitive2D* pRHS = dynamic_cast< const LazyControlCreationPrimitive2D* >( &rPrimitive );
+ if ( !pRHS )
+ return false;
+
+ if ( m_pVOCImpl != pRHS->m_pVOCImpl )
+ return false;
+
+ if ( m_aTransformation != pRHS->m_aTransformation )
+ return false;
+
+ return true;
+ }
+
+
+ void LazyControlCreationPrimitive2D::getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation )
+ {
+ // Do use model data directly to create the correct geometry. Do NOT
+ // use getBoundRect()/getSnapRect() here; these will use the sequence of
+ // primitives themselves in the long run.
+ const tools::Rectangle aSdrGeoData( _rVOC.GetSdrUnoObj().GetGeoRect() );
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aSdrGeoData);
+
+ _out_Transformation.identity();
+ _out_Transformation.set( 0, 0, aRange.getWidth() );
+ _out_Transformation.set( 1, 1, aRange.getHeight() );
+ _out_Transformation.set( 0, 2, aRange.getMinX() );
+ _out_Transformation.set( 1, 2, aRange.getMinY() );
+ }
+
+
+ ::basegfx::B2DRange LazyControlCreationPrimitive2D::getB2DRange( const ::drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/ ) const
+ {
+ ::basegfx::B2DRange aRange( 0.0, 0.0, 1.0, 1.0 );
+ aRange.transform( m_aTransformation );
+ return aRange;
+ }
+
+
+ void LazyControlCreationPrimitive2D::get2DDecomposition( ::drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
+ {
+ #if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
+ #endif
+ if ( m_pVOCImpl->hasControl() )
+ impl_positionAndZoomControl( _rViewInformation );
+ BufferedDecompositionPrimitive2D::get2DDecomposition( rVisitor, _rViewInformation );
+ }
+
+
+ void LazyControlCreationPrimitive2D::create2DDecomposition( ::drawinglayer::primitive2d::Primitive2DContainer& rContainer, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
+ {
+ #if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
+ #endif
+ const bool bHadControl = m_pVOCImpl->getExistentControl().is();
+
+ // force control here to make it a VCL ChildWindow. Will be fetched
+ // and used below by getExistentControl()
+ m_pVOCImpl->ensureControl( &_rViewInformation.getObjectToViewTransformation() );
+ impl_positionAndZoomControl( _rViewInformation );
+
+ // get needed data
+ const ViewContactOfUnoControl& rViewContactOfUnoControl( m_pVOCImpl->getViewContact() );
+ Reference< XControlModel > xControlModel( rViewContactOfUnoControl.GetSdrUnoObj().GetUnoControlModel() );
+ const ControlHolder& rControl( m_pVOCImpl->getExistentControl() );
+
+ if ( !bHadControl && rControl.is() && rControl.isVisible() )
+ rControl.invalidate();
+
+ // check if we already have an XControl.
+ if ( !xControlModel.is() || !rControl.is() )
+ {
+ // use the default mechanism. This will create a ControlPrimitive2D without
+ // handing over a XControl. If not even a XControlModel exists, it will
+ // create the SdrObject fallback visualisation
+ rViewContactOfUnoControl.getViewIndependentPrimitive2DContainer(rContainer);
+ return;
+ }
+
+ // create a primitive and hand over the existing xControl. This will
+ // allow the primitive to not need to create another one on demand.
+ rContainer.push_back( new ::drawinglayer::primitive2d::ControlPrimitive2D(
+ m_aTransformation, xControlModel, rControl.getControl() ) );
+ }
+
+ sal_uInt32 LazyControlCreationPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCONTROLPRIMITIVE2D;
+ }
+
+ ViewObjectContactOfUnoControl::ViewObjectContactOfUnoControl( ObjectContact& _rObjectContact, ViewContactOfUnoControl& _rViewContact )
+ :ViewObjectContactOfSdrObj( _rObjectContact, _rViewContact )
+ ,m_pImpl( new ViewObjectContactOfUnoControl_Impl( this ) )
+ {
+ }
+
+
+ ViewObjectContactOfUnoControl::~ViewObjectContactOfUnoControl()
+ {
+ m_pImpl->dispose();
+ m_pImpl = nullptr;
+
+ }
+
+
+ Reference< XControl > ViewObjectContactOfUnoControl::getControl()
+ {
+ SolarMutexGuard aSolarGuard;
+ m_pImpl->ensureControl( nullptr );
+ return m_pImpl->getExistentControl().getControl();
+ }
+
+
+ Reference< XControl > ViewObjectContactOfUnoControl::getTemporaryControlForWindow(
+ const vcl::Window& _rWindow, Reference< XControlContainer >& _inout_ControlContainer, const SdrUnoObj& _rUnoObject )
+ {
+ ControlHolder aControl;
+
+ InvisibleControlViewAccess aSimulatePageView( _inout_ControlContainer );
+ OSL_VERIFY( ViewObjectContactOfUnoControl_Impl::createControlForDevice( aSimulatePageView, *_rWindow.GetOutDev(), _rUnoObject,
+ _rWindow.GetOutDev()->GetViewTransformation(), _rWindow.GetOutDev()->GetInverseViewTransformation(), aControl ) );
+ return aControl.getControl();
+ }
+
+
+ void ViewObjectContactOfUnoControl::ensureControlVisibility( bool _bVisible ) const
+ {
+ SolarMutexGuard aSolarGuard;
+
+ try
+ {
+ const ControlHolder& rControl( m_pImpl->getExistentControl() );
+ if ( !rControl.is() )
+ return;
+
+ // only need to care for alive mode
+ if ( rControl.isDesignMode() )
+ return;
+
+ // is the visibility correct?
+ if ( m_pImpl->isControlVisible() == _bVisible )
+ return;
+
+ // no -> adjust it
+ rControl.setVisible( _bVisible );
+ DBG_ASSERT( m_pImpl->isControlVisible() == _bVisible, "ViewObjectContactOfUnoControl::ensureControlVisibility: this didn't work!" );
+ // now this would mean that either isControlVisible is not reliable,
+ // or that showing/hiding the window did not work as intended.
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl::setControlDesignMode( bool _bDesignMode ) const
+ {
+ SolarMutexGuard aSolarGuard;
+ m_pImpl->setControlDesignMode( _bDesignMode );
+
+ if(!_bDesignMode)
+ {
+ // when live mode is switched on, a refresh is needed. The edit mode visualisation
+ // needs to be repainted and the now used VCL-Window needs to be positioned and
+ // sized. Both is done from the repaint refresh.
+ const_cast< ViewObjectContactOfUnoControl* >(this)->ActionChanged();
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ if ( m_pImpl->isDisposed() )
+ // our control already died.
+ // TODO: Is it worth re-creating the control? Finally, this is a pathological situation, it means some instance
+ // disposed the control though it doesn't own it. So, /me thinks we should not bother here.
+ return;
+
+ if ( GetObjectContact().getViewInformation2D().getViewTransformation().isIdentity() )
+ // remove this when #i115754# is fixed
+ return;
+
+ // ignore existing controls which are in alive mode and manually switched to "invisible" #i102090#
+ const ControlHolder& rControl( m_pImpl->getExistentControl() );
+ if ( rControl.is() && !rControl.isDesignMode() && !rControl.isVisible() )
+ return;
+
+ rVisitor.visit( new LazyControlCreationPrimitive2D( m_pImpl ) );
+ }
+
+
+ bool ViewObjectContactOfUnoControl::isPrimitiveVisible( const DisplayInfo& _rDisplayInfo ) const
+ {
+ SolarMutexGuard aSolarGuard;
+
+ if ( m_pImpl->hasControl() )
+ {
+ const ::drawinglayer::geometry::ViewInformation2D& rViewInformation( GetObjectContact().getViewInformation2D() );
+ #if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
+ #endif
+
+ if ( !rViewInformation.getViewport().isEmpty() )
+ {
+ // tdf#121963 check and eventually pre-multiply ViewTransformation
+ // with GridOffset transformation to avoid alternating positions of
+ // FormControls which are victims of the non-linear calc ViewTransformation
+ // aka GridOffset. For other paths (e.g. repaint) this is included already
+ // as part of the object's sequence of B2DPrimitive - representation
+ // (see ViewObjectContact::getPrimitive2DSequence and how getGridOffset is used there)
+ basegfx::B2DHomMatrix aViewTransformation(rViewInformation.getObjectToViewTransformation());
+
+ if(GetObjectContact().supportsGridOffsets())
+ {
+ const basegfx::B2DVector& rGridOffset(getGridOffset());
+
+ if(0.0 != rGridOffset.getX() || 0.0 != rGridOffset.getY())
+ {
+ // pre-multiply: GridOffset needs to be applied directly to logic model data
+ // of object coordinates, so multiply GridOffset from right to make it
+ // work as 1st change - these objects may still be part of groups/hierarchies
+ aViewTransformation = aViewTransformation * basegfx::utils::createTranslateB2DHomMatrix(rGridOffset);
+ }
+ }
+
+ m_pImpl->positionAndZoomControl(aViewTransformation);
+ }
+ }
+
+ return ViewObjectContactOfSdrObj::isPrimitiveVisible( _rDisplayInfo );
+ }
+
+
+ void ViewObjectContactOfUnoControl::propertyChange()
+ {
+ impl_onControlChangedOrModified();
+ }
+
+
+ void ViewObjectContactOfUnoControl::ActionChanged()
+ {
+ // call parent
+ ViewObjectContactOfSdrObj::ActionChanged();
+ const ControlHolder& rControl(m_pImpl->getExistentControl());
+
+ if(!rControl.is() || rControl.isDesignMode())
+ return;
+
+ // #i93180# if layer visibility has changed and control is in live mode, it is necessary
+ // to correct visibility to make those control vanish on SdrObject LayerID changes
+ const SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pSdrPageView)
+ {
+ const SdrObject& rObject = getSdrObject();
+ const bool bIsLayerVisible( rObject.IsVisible() && pSdrPageView->GetVisibleLayers().IsSet(rObject.GetLayer()));
+
+ if(rControl.isVisible() != bIsLayerVisible)
+ {
+ rControl.setVisible(bIsLayerVisible);
+ }
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl::impl_onControlChangedOrModified()
+ {
+ // graphical invalidate at all views
+ ActionChanged();
+
+ // #i93318# flush Primitive2DContainer to force recreation with updated XControlModel
+ // since e.g. background color has changed and existing decompositions are possibly no
+ // longer valid. Unfortunately this is not detected from ControlPrimitive2D::operator==
+ // since it only has a uno reference to the XControlModel
+ flushPrimitive2DSequence();
+ }
+
+ UnoControlPrintOrPreviewContact::UnoControlPrintOrPreviewContact( ObjectContactOfPageView& _rObjectContact, ViewContactOfUnoControl& _rViewContact )
+ :ViewObjectContactOfUnoControl( _rObjectContact, _rViewContact )
+ {
+ }
+
+
+ UnoControlPrintOrPreviewContact::~UnoControlPrintOrPreviewContact()
+ {
+ }
+
+
+ void UnoControlPrintOrPreviewContact::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor ) const
+ {
+ if ( !m_pImpl->isPrintableControl() )
+ return;
+ ViewObjectContactOfUnoControl::createPrimitive2DSequence( rDisplayInfo, rVisitor );
+ }
+
+
+} // namespace sdr::contact
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactredirector.cxx b/svx/source/sdr/contact/viewobjectcontactredirector.cxx
new file mode 100644
index 000000000..c49909327
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactredirector.cxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+
+namespace sdr::contact
+{
+// basic constructor.
+ViewObjectContactRedirector::ViewObjectContactRedirector() {}
+
+// The destructor.
+ViewObjectContactRedirector::~ViewObjectContactRedirector() {}
+
+void ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
+ const sdr::contact::ViewObjectContact& rOriginal, const sdr::contact::DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+{
+ return rOriginal.createPrimitive2DSequence(rDisplayInfo, rVisitor);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/misc/ImageMapInfo.cxx b/svx/source/sdr/misc/ImageMapInfo.cxx
new file mode 100644
index 000000000..c50fb2fcc
--- /dev/null
+++ b/svx/source/sdr/misc/ImageMapInfo.cxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/ImageMapInfo.hxx>
+
+#include <svx/svdobj.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <vcl/imapobj.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+
+SvxIMapInfo* SvxIMapInfo::GetIMapInfo(SdrObject const* pObject)
+{
+ assert(pObject);
+
+ SvxIMapInfo* pIMapInfo = nullptr;
+ sal_uInt16 nCount = pObject->GetUserDataCount();
+
+ // Can we find IMap information within the user data?
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ SdrObjUserData* pUserData = pObject->GetUserData(i);
+
+ if ((pUserData->GetInventor() == SdrInventor::StarDrawUserData)
+ && (pUserData->GetId() == SVX_IMAPINFO_ID))
+ pIMapInfo = static_cast<SvxIMapInfo*>(pUserData);
+ }
+
+ return pIMapInfo;
+}
+
+IMapObject* SvxIMapInfo::GetHitIMapObject(const SdrObject* pObj, const Point& rWinPoint,
+ const OutputDevice* pCmpWnd)
+{
+ SvxIMapInfo* pIMapInfo = GetIMapInfo(pObj);
+ IMapObject* pIMapObj = nullptr;
+
+ if (pIMapInfo)
+ {
+ const MapMode aMap100(MapUnit::Map100thMM);
+ Size aGraphSize;
+ Point aRelPoint(rWinPoint);
+ ImageMap& rImageMap = const_cast<ImageMap&>(pIMapInfo->GetImageMap());
+ tools::Rectangle& rRect = const_cast<tools::Rectangle&>(pObj->GetLogicRect());
+
+ if (pCmpWnd)
+ {
+ MapMode aWndMode = pCmpWnd->GetMapMode();
+ aRelPoint = pCmpWnd->LogicToLogic(rWinPoint, &aWndMode, &aMap100);
+ rRect = pCmpWnd->LogicToLogic(pObj->GetLogicRect(), &aWndMode, &aMap100);
+ }
+
+ bool bObjSupported = false;
+
+ // execute HitTest
+ if (auto pGrafObj = dynamic_cast<const SdrGrafObj*>(pObj)) // simple graphics object
+ {
+ const GeoStat& rGeo = pGrafObj->GetGeoStat();
+ std::unique_ptr<SdrGrafObjGeoData> pGeoData(
+ static_cast<SdrGrafObjGeoData*>(pGrafObj->GetGeoData().release()));
+
+ // Undo rotation
+ if (rGeo.nRotationAngle)
+ RotatePoint(aRelPoint, rRect.TopLeft(), -rGeo.mfSinRotationAngle,
+ rGeo.mfCosRotationAngle);
+
+ // Undo mirroring
+ if (pGeoData->bMirrored)
+ aRelPoint.setX(rRect.Right() + rRect.Left() - aRelPoint.X());
+
+ // Undo shearing
+ if (rGeo.nShearAngle)
+ ShearPoint(aRelPoint, rRect.TopLeft(), -rGeo.mfTanShearAngle);
+
+ if (pGrafObj->GetGrafPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ aGraphSize = Application::GetDefaultDevice()->PixelToLogic(
+ pGrafObj->GetGrafPrefSize(), aMap100);
+ else
+ aGraphSize = OutputDevice::LogicToLogic(pGrafObj->GetGrafPrefSize(),
+ pGrafObj->GetGrafPrefMapMode(), aMap100);
+
+ bObjSupported = true;
+ }
+ else if (auto pOleObj = dynamic_cast<const SdrOle2Obj*>(pObj)) // OLE object
+ {
+ aGraphSize = pOleObj->GetOrigObjSize();
+ bObjSupported = true;
+ }
+
+ // Everything worked out well, thus execute HitTest
+ if (bObjSupported)
+ {
+ // Calculate relative position of mouse cursor
+ aRelPoint -= rRect.TopLeft();
+ pIMapObj = rImageMap.GetHitIMapObject(aGraphSize, rRect.GetSize(), aRelPoint);
+
+ // We don't care about deactivated objects
+ if (pIMapObj && !pIMapObj->IsActive())
+ pIMapObj = nullptr;
+ }
+ }
+
+ return pIMapObj;
+}
diff --git a/svx/source/sdr/overlay/overlayanimatedbitmapex.cxx b/svx/source/sdr/overlay/overlayanimatedbitmapex.cxx
new file mode 100644
index 000000000..967e9665b
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayanimatedbitmapex.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayAnimatedBitmapEx::createOverlayObjectPrimitive2DSequence()
+ {
+ if(mbOverlayState)
+ {
+ const drawinglayer::primitive2d::Primitive2DReference aPrimitive(
+ new drawinglayer::primitive2d::OverlayBitmapExPrimitive(
+ maBitmapEx1,
+ getBasePosition(),
+ mnCenterX1,
+ mnCenterY1,
+ getShearX(),
+ getRotation()));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aPrimitive };
+ }
+ else
+ {
+ const drawinglayer::primitive2d::Primitive2DReference aPrimitive(
+ new drawinglayer::primitive2d::OverlayBitmapExPrimitive(
+ maBitmapEx2,
+ getBasePosition(),
+ mnCenterX2,
+ mnCenterY2,
+ getShearX(),
+ getRotation()));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aPrimitive };
+ }
+ }
+
+ OverlayAnimatedBitmapEx::OverlayAnimatedBitmapEx(
+ const basegfx::B2DPoint& rBasePos,
+ const BitmapEx& rBitmapEx1,
+ const BitmapEx& rBitmapEx2,
+ sal_uInt64 nBlinkTime,
+ sal_uInt16 nCenX1,
+ sal_uInt16 nCenY1,
+ sal_uInt16 nCenX2,
+ sal_uInt16 nCenY2,
+ double fShearX,
+ double fRotation)
+ : OverlayObjectWithBasePosition(rBasePos, COL_WHITE),
+ maBitmapEx1(rBitmapEx1),
+ maBitmapEx2(rBitmapEx2),
+ mnCenterX1(nCenX1), mnCenterY1(nCenY1),
+ mnCenterX2(nCenX2), mnCenterY2(nCenY2),
+ mnBlinkTime(impCheckBlinkTimeValueRange(nBlinkTime)),
+ mfShearX(fShearX),
+ mfRotation(fRotation),
+ mbOverlayState(false)
+ {
+ // set AllowsAnimation flag to mark this object as animation capable
+ mbAllowsAnimation = true;
+ }
+
+ OverlayAnimatedBitmapEx::~OverlayAnimatedBitmapEx()
+ {
+ }
+
+ void OverlayAnimatedBitmapEx::Trigger(sal_uInt32 nTime)
+ {
+ if(!getOverlayManager())
+ return;
+
+ // #i53216# produce event after nTime + x
+ SetTime(nTime + mnBlinkTime);
+
+ // switch state
+ if(mbOverlayState)
+ {
+ mbOverlayState = false;
+ }
+ else
+ {
+ mbOverlayState = true;
+ }
+
+ // re-insert me as event
+ getOverlayManager()->InsertEvent(*this);
+
+ // register change (after change)
+ objectChange();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaybitmapex.cxx b/svx/source/sdr/overlay/overlaybitmapex.cxx
new file mode 100644
index 000000000..54ccf788b
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaybitmapex.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <svx/sdr/overlay/overlaybitmapex.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayBitmapEx::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::OverlayBitmapExPrimitive(
+ maBitmapEx,
+ getBasePosition(),
+ mnCenterX,
+ mnCenterY,
+ mfShearX,
+ mfRotation));
+
+ if(basegfx::fTools::more(mfAlpha, 0.0))
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aNewTransPrimitiveVector { aReference };
+ aReference = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aNewTransPrimitiveVector), mfAlpha));
+ }
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ OverlayBitmapEx::OverlayBitmapEx(
+ const basegfx::B2DPoint& rBasePos,
+ const BitmapEx& rBitmapEx,
+ sal_uInt16 nCenX,
+ sal_uInt16 nCenY,
+ double fAlpha,
+ double fShearX,
+ double fRotation)
+ : OverlayObjectWithBasePosition(rBasePos, COL_WHITE),
+ maBitmapEx(rBitmapEx),
+ mnCenterX(nCenX),
+ mnCenterY(nCenY),
+ mfAlpha(fAlpha),
+ mfShearX(fShearX),
+ mfRotation(fRotation)
+ {
+ }
+
+ OverlayBitmapEx::~OverlayBitmapEx()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaycrosshair.cxx b/svx/source/sdr/overlay/overlaycrosshair.cxx
new file mode 100644
index 000000000..942534d68
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaycrosshair.cxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlaycrosshair.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayCrosshairStriped::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(getOverlayManager())
+ {
+ const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor());
+ const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor());
+ const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel());
+
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::OverlayCrosshairPrimitive(
+ getBasePosition(),
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ return aRetval;
+ }
+
+ void OverlayCrosshairStriped::stripeDefinitionHasChanged()
+ {
+ // react on OverlayManager's stripe definition change
+ objectChange();
+ }
+
+ OverlayCrosshairStriped::OverlayCrosshairStriped(const basegfx::B2DPoint& rBasePos)
+ : OverlayObjectWithBasePosition(rBasePos, COL_BLACK)
+ {
+ }
+
+ OverlayCrosshairStriped::~OverlayCrosshairStriped()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayhandle.cxx b/svx/source/sdr/overlay/overlayhandle.cxx
new file mode 100644
index 000000000..c94da8e07
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayhandle.cxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlayhandle.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+
+namespace sdr::overlay {
+
+using namespace drawinglayer;
+using namespace basegfx;
+
+primitive2d::Primitive2DContainer OverlayHandle::createOverlayObjectPrimitive2DSequence()
+{
+ basegfx::BColor aStrokeColor = maStrokeColor.getBColor();
+ basegfx::BColor aFillColor = getBaseColor().getBColor();
+
+ const primitive2d::Primitive2DReference aReference(
+ new primitive2d::OverlayStaticRectanglePrimitive(maBasePosition, maSize, aStrokeColor, aFillColor, 0.3f, 0.0f));
+
+ return primitive2d::Primitive2DContainer { aReference };
+}
+
+OverlayHandle::OverlayHandle(const B2DPoint& rBasePos,
+ const B2DSize& rSize,
+ Color const & rStrokeColor,
+ Color const & rFillColor)
+ : OverlayObjectWithBasePosition(rBasePos, rFillColor)
+ , maSize(rSize)
+ , maStrokeColor(rStrokeColor)
+{
+}
+
+OverlayHandle::~OverlayHandle()
+{
+}
+
+} // end of namespace sdr::overlay
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayhelpline.cxx b/svx/source/sdr/overlay/overlayhelpline.cxx
new file mode 100644
index 000000000..9955122bb
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayhelpline.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlayhelpline.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayHelplineStriped::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(getOverlayManager())
+ {
+ const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor());
+ const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor());
+ const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel());
+ const drawinglayer::primitive2d::HelplineStyle aStyle(
+ SdrHelpLineKind::Point == getKind() ? drawinglayer::primitive2d::HELPLINESTYLE_POINT :
+ SdrHelpLineKind::Vertical == getKind() ? drawinglayer::primitive2d::HELPLINESTYLE_VERTICAL :
+ drawinglayer::primitive2d::HELPLINESTYLE_HORIZONTAL);
+
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::OverlayHelplineStripedPrimitive(
+ getBasePosition(),
+ aStyle,
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ return aRetval;
+ }
+
+ void OverlayHelplineStriped::stripeDefinitionHasChanged()
+ {
+ // react on OverlayManager's stripe definition change
+ objectChange();
+ }
+
+ OverlayHelplineStriped::OverlayHelplineStriped(
+ const basegfx::B2DPoint& rBasePos,
+ SdrHelpLineKind eNewKind)
+ : OverlayObjectWithBasePosition(rBasePos, COL_BLACK),
+ meKind(eNewKind)
+ {
+ }
+
+ OverlayHelplineStriped::~OverlayHelplineStriped()
+ {
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayline.cxx b/svx/source/sdr/overlay/overlayline.cxx
new file mode 100644
index 000000000..30c08f026
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayline.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlayline.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/PolygonMarkerPrimitive2D.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayLineStriped::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(getOverlayManager())
+ {
+ const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor());
+ const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor());
+ const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel());
+ basegfx::B2DPolygon aLine;
+
+ aLine.append(getBasePosition());
+ aLine.append(getSecondPosition());
+
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::PolygonMarkerPrimitive2D(
+ aLine,
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ return aRetval;
+ }
+
+ void OverlayLineStriped::stripeDefinitionHasChanged()
+ {
+ // react on OverlayManager's stripe definition change
+ objectChange();
+ }
+
+ OverlayLineStriped::OverlayLineStriped(
+ const basegfx::B2DPoint& rBasePos,
+ const basegfx::B2DPoint& rSecondPos)
+ : OverlayObjectWithBasePosition(rBasePos, COL_BLACK),
+ maSecondPosition(rSecondPos)
+ {
+ }
+
+ OverlayLineStriped::~OverlayLineStriped()
+ {
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaymanager.cxx b/svx/source/sdr/overlay/overlaymanager.cxx
new file mode 100644
index 000000000..3cbd821fb
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaymanager.cxx
@@ -0,0 +1,346 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <tools/gen.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/window.hxx>
+#include <svx/sdr/overlay/overlayobject.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <osl/diagnose.h>
+#include <memory>
+
+
+using namespace com::sun::star;
+
+
+namespace sdr::overlay
+{
+ void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const
+ {
+ const sal_uInt32 nSize(maOverlayObjects.size());
+
+ if(!nSize)
+ return;
+
+ const AntialiasingFlags nOriginalAA(rDestinationDevice.GetAntialiasing());
+ const bool bIsAntiAliasing(SvtOptionsDrawinglayer::IsAntiAliasing());
+
+ // create processor
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
+ rDestinationDevice,
+ getCurrentViewInformation2D()));
+
+ for(const auto& rpOverlayObject : maOverlayObjects)
+ {
+ OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
+ const OverlayObject& rCandidate = *rpOverlayObject;
+
+ if(rCandidate.isVisible())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer& rSequence = rCandidate.getOverlayObjectPrimitive2DSequence();
+
+ if(!rSequence.empty())
+ {
+ if(rRange.overlaps(rCandidate.getBaseRange()))
+ {
+ if(bIsAntiAliasing && rCandidate.allowsAntiAliase())
+ {
+ rDestinationDevice.SetAntialiasing(nOriginalAA | AntialiasingFlags::Enable);
+ }
+ else
+ {
+ rDestinationDevice.SetAntialiasing(nOriginalAA & ~AntialiasingFlags::Enable);
+ }
+
+ pProcessor->process(rSequence);
+ }
+ }
+ }
+ }
+
+ pProcessor.reset();
+
+ // restore AA settings
+ rDestinationDevice.SetAntialiasing(nOriginalAA);
+ }
+
+ void OverlayManager::ImpStripeDefinitionChanged()
+ {
+ const sal_uInt32 nSize(maOverlayObjects.size());
+
+ if(nSize)
+ {
+ for(const auto& rpOverlayObject : maOverlayObjects)
+ {
+ OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
+ OverlayObject& rCandidate = *rpOverlayObject;
+ rCandidate.stripeDefinitionHasChanged();
+ }
+ }
+ }
+
+ double OverlayManager::getDiscreteOne() const
+ {
+ if(basegfx::fTools::equalZero(mfDiscreteOne))
+ {
+ const basegfx::B2DVector aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0));
+ const_cast< OverlayManager* >(this)->mfDiscreteOne = aDiscreteInLogic.getLength();
+ }
+
+ return mfDiscreteOne;
+ }
+
+ OverlayManager::OverlayManager(OutputDevice& rOutputDevice)
+ : mrOutputDevice(rOutputDevice),
+ maStripeColorA(COL_BLACK),
+ maStripeColorB(COL_WHITE),
+ mnStripeLengthPixel(5),
+ mfDiscreteOne(0.0)
+ {
+ // set Property 'ReducedDisplayQuality' to true to allow simpler interaction
+ // visualisations
+ uno::Sequence< beans::PropertyValue > xProperties{
+ comphelper::makePropertyValue("ReducedDisplayQuality", true)
+ };
+ maViewInformation2D = drawinglayer::geometry::createViewInformation2D(xProperties);
+ }
+
+ rtl::Reference<OverlayManager> OverlayManager::create(OutputDevice& rOutputDevice)
+ {
+ return rtl::Reference<OverlayManager>(new OverlayManager(rOutputDevice));
+ }
+
+ drawinglayer::geometry::ViewInformation2D const & OverlayManager::getCurrentViewInformation2D() const
+ {
+ if(getOutputDevice().GetViewTransformation() != maViewTransformation)
+ {
+ basegfx::B2DRange aViewRange(maViewInformation2D.getViewport());
+
+ if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
+ {
+ const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
+
+ // only set when we *have* an output size, else let aViewRange
+ // stay on empty
+ if(aOutputSizePixel.Width() && aOutputSizePixel.Height())
+ {
+ aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
+ aViewRange.transform(getOutputDevice().GetInverseViewTransformation());
+ }
+ }
+
+ OverlayManager* pThis = const_cast< OverlayManager* >(this);
+
+ pThis->maViewTransformation = getOutputDevice().GetViewTransformation();
+ pThis->maViewInformation2D = drawinglayer::geometry::ViewInformation2D(
+ maViewInformation2D.getObjectTransformation(),
+ maViewTransformation,
+ aViewRange,
+ maViewInformation2D.getVisualizedPage(),
+ maViewInformation2D.getViewTime());
+ pThis->mfDiscreteOne = 0.0;
+ }
+
+ return maViewInformation2D;
+ }
+
+ void OverlayManager::impApplyRemoveActions(OverlayObject& rTarget)
+ {
+ // handle evtl. animation
+ if(rTarget.allowsAnimation())
+ {
+ // remove from event chain
+ RemoveEvent(&rTarget);
+ }
+
+ // make invisible
+ invalidateRange(rTarget.getBaseRange());
+
+ // clear manager
+ rTarget.mpOverlayManager = nullptr;
+ }
+
+ void OverlayManager::impApplyAddActions(OverlayObject& rTarget)
+ {
+ // set manager
+ rTarget.mpOverlayManager = this;
+
+ // make visible
+ invalidateRange(rTarget.getBaseRange());
+
+ // handle evtl. animation
+ if(rTarget.allowsAnimation())
+ {
+ // Trigger at current time to get alive. This will do the
+ // object-specific next time calculation and hand over adding
+ // again to the scheduler to the animated object, too. This works for
+ // a paused or non-paused animator.
+ rTarget.Trigger(GetTime());
+ }
+ }
+
+ OverlayManager::~OverlayManager()
+ {
+ // The OverlayManager is not the owner of the OverlayObjects
+ // and thus will not delete them, but remove them. Profit here
+ // from knowing that all will be removed
+ const sal_uInt32 nSize(maOverlayObjects.size());
+
+ if(nSize)
+ {
+ for(const auto& rpOverlayObject : maOverlayObjects)
+ {
+ OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
+ OverlayObject& rCandidate = *rpOverlayObject;
+ impApplyRemoveActions(rCandidate);
+ }
+
+ // erase vector
+ maOverlayObjects.clear();
+ }
+ }
+
+ void OverlayManager::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const
+ {
+ if(rRegion.IsEmpty() || maOverlayObjects.empty())
+ return;
+
+ // check for changed MapModes. That may influence the
+ // logical size of pixel based OverlayObjects (like BitmapHandles)
+ //ImpCheckMapModeChange();
+
+ // paint members
+ const tools::Rectangle aRegionBoundRect(rRegion.GetBoundRect());
+ const basegfx::B2DRange aRegionRange = vcl::unotools::b2DRectangleFromRectangle(aRegionBoundRect);
+
+ OutputDevice& rTarget = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice();
+ ImpDrawMembers(aRegionRange, rTarget);
+ }
+
+ void OverlayManager::flush()
+ {
+ // default has nothing to do
+ }
+
+ void OverlayManager::add(OverlayObject& rOverlayObject)
+ {
+ OSL_ENSURE(nullptr == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)");
+
+ // add to the end of chain to preserve display order in paint
+ maOverlayObjects.push_back(&rOverlayObject);
+
+ // execute add actions
+ impApplyAddActions(rOverlayObject);
+ }
+
+ void OverlayManager::remove(OverlayObject& rOverlayObject)
+ {
+ OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)");
+
+ // execute remove actions
+ impApplyRemoveActions(rOverlayObject);
+
+ // remove from vector
+ const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject);
+ const bool bFound(aFindResult != maOverlayObjects.end());
+ OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)");
+
+ if(bFound)
+ {
+ maOverlayObjects.erase(aFindResult);
+ }
+ }
+
+ tools::Rectangle OverlayManager::RangeToInvalidateRectangle(const basegfx::B2DRange& rRange) const
+ {
+ if (rRange.isEmpty()) {
+ return {};
+ }
+ if (SvtOptionsDrawinglayer::IsAntiAliasing())
+ {
+ // assume AA needs one pixel more and invalidate one pixel more
+ const double fDiscreteOne(getDiscreteOne());
+ const tools::Rectangle aInvalidateRectangle(
+ static_cast<tools::Long>(floor(rRange.getMinX() - fDiscreteOne)),
+ static_cast<tools::Long>(floor(rRange.getMinY() - fDiscreteOne)),
+ static_cast<tools::Long>(ceil(rRange.getMaxX() + fDiscreteOne)),
+ static_cast<tools::Long>(ceil(rRange.getMaxY() + fDiscreteOne)));
+ return aInvalidateRectangle;
+ }
+ else
+ {
+ // #i77674# transform to rectangle. Use floor/ceil to get all covered
+ // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange
+ const tools::Rectangle aInvalidateRectangle(
+ static_cast<sal_Int32>(floor(rRange.getMinX())), static_cast<sal_Int32>(floor(rRange.getMinY())),
+ static_cast<sal_Int32>(ceil(rRange.getMaxX())), static_cast<sal_Int32>(ceil(rRange.getMaxY())));
+ return aInvalidateRectangle;
+ }
+ }
+
+ void OverlayManager::invalidateRange(const basegfx::B2DRange& rRange)
+ {
+ if (OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
+ {
+ tools::Rectangle aInvalidateRectangle(RangeToInvalidateRectangle(rRange));
+ // simply invalidate
+ getOutputDevice().GetOwnerWindow()->Invalidate(aInvalidateRectangle, InvalidateFlags::NoErase);
+ }
+ }
+
+ // stripe support ColA
+ void OverlayManager::setStripeColorA(Color aNew)
+ {
+ if(aNew != maStripeColorA)
+ {
+ maStripeColorA = aNew;
+ ImpStripeDefinitionChanged();
+ }
+ }
+
+ // stripe support ColB
+ void OverlayManager::setStripeColorB(Color aNew)
+ {
+ if(aNew != maStripeColorB)
+ {
+ maStripeColorB = aNew;
+ ImpStripeDefinitionChanged();
+ }
+ }
+
+ // stripe support StripeLengthPixel
+ void OverlayManager::setStripeLengthPixel(sal_uInt32 nNew)
+ {
+ if(nNew != mnStripeLengthPixel)
+ {
+ mnStripeLengthPixel = nNew;
+ ImpStripeDefinitionChanged();
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaymanagerbuffered.cxx b/svx/source/sdr/overlay/overlaymanagerbuffered.cxx
new file mode 100644
index 000000000..ae37c2ce4
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaymanagerbuffered.cxx
@@ -0,0 +1,441 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlaymanagerbuffered.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <vcl/outdev.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <vcl/window.hxx>
+#include <tools/fract.hxx>
+#include <vcl/cursor.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+
+
+namespace sdr::overlay
+{
+ void OverlayManagerBuffered::ImpPrepareBufferDevice()
+ {
+ // compare size of mpBufferDevice with size of visible area
+ if(mpBufferDevice->GetOutputSizePixel() != getOutputDevice().GetOutputSizePixel())
+ {
+ // set new buffer size, copy as much content as possible (use bool parameter for vcl).
+ // Newly uncovered regions will be repainted.
+ mpBufferDevice->SetOutputSizePixel(getOutputDevice().GetOutputSizePixel(), false);
+ }
+
+ // compare the MapModes for zoom/scroll changes
+ if(mpBufferDevice->GetMapMode() != getOutputDevice().GetMapMode())
+ {
+ const bool bZoomed(
+ mpBufferDevice->GetMapMode().GetScaleX() != getOutputDevice().GetMapMode().GetScaleX()
+ || mpBufferDevice->GetMapMode().GetScaleY() != getOutputDevice().GetMapMode().GetScaleY());
+
+ if(!bZoomed)
+ {
+ const Point& rOriginOld = mpBufferDevice->GetMapMode().GetOrigin();
+ const Point& rOriginNew = getOutputDevice().GetMapMode().GetOrigin();
+ const bool bScrolled(rOriginOld != rOriginNew);
+
+
+ if(bScrolled)
+ {
+ // get pixel bounds (tdf#149322 do subtraction in logic units before converting result back to pixel)
+ const Point aLogicOriginDiff(rOriginNew - rOriginOld);
+ const Size aPixelOriginDiff(mpBufferDevice->LogicToPixel(Size(aLogicOriginDiff.X(), aLogicOriginDiff.Y())));
+ const Point aDestinationOffsetPixel(aPixelOriginDiff.Width(), aPixelOriginDiff.Height());
+ const Size aOutputSizePixel(mpBufferDevice->GetOutputSizePixel());
+
+ // remember and switch off MapMode
+ const bool bMapModeWasEnabled(mpBufferDevice->IsMapModeEnabled());
+ mpBufferDevice->EnableMapMode(false);
+
+ // scroll internally buffered stuff
+ mpBufferDevice->DrawOutDev(
+ aDestinationOffsetPixel, aOutputSizePixel, // destination
+ Point(), aOutputSizePixel); // source
+
+ // restore MapMode
+ mpBufferDevice->EnableMapMode(bMapModeWasEnabled);
+
+ // scroll remembered region, too.
+ if(!maBufferRememberedRangePixel.isEmpty())
+ {
+ const basegfx::B2IPoint aIPointDestinationOffsetPixel(aDestinationOffsetPixel.X(), aDestinationOffsetPixel.Y());
+ const basegfx::B2IPoint aNewMinimum(maBufferRememberedRangePixel.getMinimum() + aIPointDestinationOffsetPixel);
+ const basegfx::B2IPoint aNewMaximum(maBufferRememberedRangePixel.getMaximum() + aIPointDestinationOffsetPixel);
+ maBufferRememberedRangePixel = basegfx::B2IRange(aNewMinimum, aNewMaximum);
+ }
+ }
+ }
+
+ // copy new MapMode
+ mpBufferDevice->SetMapMode(getOutputDevice().GetMapMode());
+ }
+
+ // #i29186#
+ mpBufferDevice->SetDrawMode(getOutputDevice().GetDrawMode());
+ mpBufferDevice->SetSettings(getOutputDevice().GetSettings());
+ mpBufferDevice->SetAntialiasing(getOutputDevice().GetAntialiasing());
+ }
+
+ void OverlayManagerBuffered::ImpRestoreBackground() const
+ {
+ const tools::Rectangle aRegionRectanglePixel(
+ maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
+ maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
+ const vcl::Region aRegionPixel(aRegionRectanglePixel);
+
+ ImpRestoreBackground(aRegionPixel);
+ }
+
+ void OverlayManagerBuffered::ImpRestoreBackground(const vcl::Region& rRegionPixel) const
+ {
+ // MapModes off
+ const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
+ const bool bMapModeWasEnabledSource(mpBufferDevice->IsMapModeEnabled());
+ getOutputDevice().EnableMapMode(false);
+ const_cast<OverlayManagerBuffered*>(this)->mpBufferDevice->EnableMapMode(false);
+
+ // local region
+ RectangleVector aRectangles;
+ rRegionPixel.GetRegionRectangles(aRectangles);
+
+ for(const auto& rRect : aRectangles)
+ {
+ // restore the area
+ const Point aTopLeft(rRect.TopLeft());
+ const Size aSize(rRect.GetSize());
+
+ getOutputDevice().DrawOutDev(
+ aTopLeft, aSize, // destination
+ aTopLeft, aSize, // source
+ *mpBufferDevice);
+ }
+
+ // restore MapModes
+ getOutputDevice().EnableMapMode(bMapModeWasEnabledDest);
+ const_cast<OverlayManagerBuffered*>(this)->mpBufferDevice->EnableMapMode(bMapModeWasEnabledSource);
+ }
+
+ void OverlayManagerBuffered::ImpSaveBackground(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice)
+ {
+ // prepare source
+ OutputDevice& rSource = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice();
+
+ // Ensure buffer is valid
+ ImpPrepareBufferDevice();
+
+ // build region which needs to be copied
+ vcl::Region aRegion(rSource.LogicToPixel(rRegion));
+
+ // limit to PaintRegion if it's a window. This will be evtl. the expanded one,
+ // but always the exact redraw area
+ if(OUTDEV_WINDOW == rSource.GetOutDevType())
+ {
+ vcl::Window& rWindow = *rSource.GetOwnerWindow();
+ vcl::Region aPaintRegionPixel = rWindow.LogicToPixel(rWindow.GetPaintRegion());
+ aRegion.Intersect(aPaintRegionPixel);
+
+ // #i72754# Make sure content is completely rendered, the window
+ // will be used as source of a DrawOutDev soon
+ rWindow.GetOutDev()->Flush();
+ }
+
+ // also limit to buffer size
+ const tools::Rectangle aBufferDeviceRectanglePixel(Point(), mpBufferDevice->GetOutputSizePixel());
+ aRegion.Intersect(aBufferDeviceRectanglePixel);
+
+ // MapModes off
+ const bool bMapModeWasEnabledDest(rSource.IsMapModeEnabled());
+ const bool bMapModeWasEnabledSource(mpBufferDevice->IsMapModeEnabled());
+ rSource.EnableMapMode(false);
+ mpBufferDevice->EnableMapMode(false);
+
+ // prepare to iterate over the rectangles from the region in pixels
+ RectangleVector aRectangles;
+ aRegion.GetRegionRectangles(aRectangles);
+
+ for(const auto& rRect : aRectangles)
+ {
+ // for each rectangle, save the area
+ const Point aTopLeft(rRect.TopLeft());
+ const Size aSize(rRect.GetSize());
+
+ mpBufferDevice->DrawOutDev(
+ aTopLeft, aSize, // destination
+ aTopLeft, aSize, // source
+ rSource);
+ }
+
+ // restore MapModes
+ rSource.EnableMapMode(bMapModeWasEnabledDest);
+ mpBufferDevice->EnableMapMode(bMapModeWasEnabledSource);
+ }
+
+ IMPL_LINK_NOARG(OverlayManagerBuffered, ImpBufferTimerHandler, Timer*, void)
+ {
+ //Resolves: fdo#46728 ensure this exists until end of scope
+ rtl::Reference<OverlayManager> xKeepAlive(this);
+
+ // stop timer
+ maBufferIdle.Stop();
+
+ if(maBufferRememberedRangePixel.isEmpty())
+ return;
+
+ // logic size for impDrawMember call
+ basegfx::B2DRange aBufferRememberedRangeLogic(
+ maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
+ maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
+ aBufferRememberedRangeLogic.transform(getOutputDevice().GetInverseViewTransformation());
+
+ // prepare cursor handling
+ const bool bTargetIsWindow(OUTDEV_WINDOW == mrOutputDevice.GetOutDevType());
+ bool bCursorWasEnabled(false);
+
+ // #i80730# switch off VCL cursor during overlay refresh
+ if(bTargetIsWindow)
+ {
+ vcl::Window& rWindow = *mrOutputDevice.GetOwnerWindow();
+ vcl::Cursor* pCursor = rWindow.GetCursor();
+
+ if(pCursor && pCursor->IsVisible())
+ {
+ pCursor->Hide();
+ bCursorWasEnabled = true;
+ }
+ }
+
+ // refresh with prerendering
+ {
+ // #i73602# ensure valid and sized mpOutputBufferDevice
+ const Size aDestinationSizePixel(mpBufferDevice->GetOutputSizePixel());
+ const Size aOutputBufferSizePixel(mpOutputBufferDevice->GetOutputSizePixel());
+
+ if(aDestinationSizePixel != aOutputBufferSizePixel)
+ {
+ mpOutputBufferDevice->SetOutputSizePixel(aDestinationSizePixel);
+ }
+
+ mpOutputBufferDevice->SetMapMode(getOutputDevice().GetMapMode());
+ mpOutputBufferDevice->EnableMapMode(false);
+ mpOutputBufferDevice->SetDrawMode(mpBufferDevice->GetDrawMode());
+ mpOutputBufferDevice->SetSettings(mpBufferDevice->GetSettings());
+ mpOutputBufferDevice->SetAntialiasing(mpBufferDevice->GetAntialiasing());
+
+ // calculate sizes
+ tools::Rectangle aRegionRectanglePixel(
+ maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
+ maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
+
+ // truncate aRegionRectanglePixel to destination pixel size, more does
+ // not need to be prepared since destination is a buffer for a window. So,
+ // maximum size indirectly shall be limited to getOutputDevice().GetOutputSizePixel()
+ if(aRegionRectanglePixel.Left() < 0)
+ {
+ aRegionRectanglePixel.SetLeft( 0 );
+ }
+
+ if(aRegionRectanglePixel.Top() < 0)
+ {
+ aRegionRectanglePixel.SetTop( 0 );
+ }
+
+ if(aRegionRectanglePixel.Right() > aDestinationSizePixel.getWidth())
+ {
+ aRegionRectanglePixel.SetRight( aDestinationSizePixel.getWidth() );
+ }
+
+ if(aRegionRectanglePixel.Bottom() > aDestinationSizePixel.getHeight())
+ {
+ aRegionRectanglePixel.SetBottom( aDestinationSizePixel.getHeight() );
+ }
+
+ // get sizes
+ const Point aTopLeft(aRegionRectanglePixel.TopLeft());
+ const Size aSize(aRegionRectanglePixel.GetSize());
+
+ {
+ const bool bMapModeWasEnabledDest(mpBufferDevice->IsMapModeEnabled());
+ mpBufferDevice->EnableMapMode(false);
+
+ mpOutputBufferDevice->DrawOutDev(
+ aTopLeft, aSize, // destination
+ aTopLeft, aSize, // source
+ *mpBufferDevice);
+
+ // restore MapModes
+ mpBufferDevice->EnableMapMode(bMapModeWasEnabledDest);
+ }
+
+ // paint overlay content for remembered region, use
+ // method from base class directly
+ mpOutputBufferDevice->EnableMapMode();
+ OverlayManager::ImpDrawMembers(aBufferRememberedRangeLogic, *mpOutputBufferDevice);
+ mpOutputBufferDevice->EnableMapMode(false);
+
+ // copy to output
+ {
+ const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
+ getOutputDevice().EnableMapMode(false);
+
+ getOutputDevice().DrawOutDev(
+ aTopLeft, aSize, // destination
+ aTopLeft, aSize, // source
+ *mpOutputBufferDevice);
+
+ // debug
+ /*getOutputDevice().SetLineCOL_RED);
+ getOutputDevice().SetFillColor();
+ getOutputDevice().DrawRect(Rectangle(aTopLeft, aSize));*/
+
+ // restore MapModes
+ getOutputDevice().EnableMapMode(bMapModeWasEnabledDest);
+ }
+ }
+
+ // VCL hack for transparent child windows
+ // Problem is e.g. a radiobutton form control in life mode. The used window
+ // is a transparence vcl childwindow. This flag only allows the parent window to
+ // paint into the child windows area, but there is no mechanism which takes
+ // care for a repaint of the child window. A transparent child window is NOT
+ // a window which always keeps it's content consistent over the parent, but it's
+ // more like just a paint flag for the parent.
+ // To get the update, the windows in question are updated manually here.
+ if(bTargetIsWindow)
+ {
+ vcl::Window& rWindow = *mrOutputDevice.GetOwnerWindow();
+
+ const tools::Rectangle aRegionRectanglePixel(
+ maBufferRememberedRangePixel.getMinX(),
+ maBufferRememberedRangePixel.getMinY(),
+ maBufferRememberedRangePixel.getMaxX(),
+ maBufferRememberedRangePixel.getMaxY());
+ PaintTransparentChildren(rWindow, aRegionRectanglePixel);
+ }
+
+ // #i80730# restore visibility of VCL cursor
+ if(bCursorWasEnabled)
+ {
+ vcl::Window& rWindow = *mrOutputDevice.GetOwnerWindow();
+ vcl::Cursor* pCursor = rWindow.GetCursor();
+
+ if(pCursor)
+ {
+ // check if cursor still exists. It may have been deleted from someone
+ pCursor->Show();
+ }
+ }
+
+ // forget remembered Region
+ maBufferRememberedRangePixel.reset();
+ }
+
+ OverlayManagerBuffered::OverlayManagerBuffered(
+ OutputDevice& rOutputDevice)
+ : OverlayManager(rOutputDevice),
+ mpBufferDevice(VclPtr<VirtualDevice>::Create()),
+ mpOutputBufferDevice(VclPtr<VirtualDevice>::Create()),
+ maBufferIdle( "sdr::overlay::OverlayManagerBuffered maBufferIdle" )
+ {
+ // Init timer
+ maBufferIdle.SetPriority( TaskPriority::POST_PAINT );
+ maBufferIdle.SetInvokeHandler(LINK(this, OverlayManagerBuffered, ImpBufferTimerHandler));
+ }
+
+ rtl::Reference<OverlayManager> OverlayManagerBuffered::create(
+ OutputDevice& rOutputDevice)
+ {
+ return rtl::Reference<OverlayManager>(new OverlayManagerBuffered(rOutputDevice));
+ }
+
+ OverlayManagerBuffered::~OverlayManagerBuffered()
+ {
+ // Clear timer
+ maBufferIdle.Stop();
+
+ if(!maBufferRememberedRangePixel.isEmpty())
+ {
+ // Restore all rectangles for remembered region from buffer
+ ImpRestoreBackground();
+ }
+ }
+
+ void OverlayManagerBuffered::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const
+ {
+ if(!rRegion.IsEmpty())
+ {
+ // save new background
+ const_cast<OverlayManagerBuffered*>(this)->ImpSaveBackground(rRegion, pPreRenderDevice);
+ }
+
+ // call parent
+ OverlayManager::completeRedraw(rRegion, pPreRenderDevice);
+ }
+
+ void OverlayManagerBuffered::flush()
+ {
+ // call timer handler direct
+ ImpBufferTimerHandler(nullptr);
+ }
+
+ void OverlayManagerBuffered::invalidateRange(const basegfx::B2DRange& rRange)
+ {
+ if(rRange.isEmpty())
+ return;
+
+ // buffered output, do not invalidate but use the timer
+ // to trigger a timer event for refresh
+ maBufferIdle.Start();
+
+ // add the discrete range to the remembered region
+ // #i75163# use double precision and floor/ceil rounding to get overlapped pixel region, even
+ // when the given logic region has a width/height of 0.0. This does NOT work with LogicToPixel
+ // since it just transforms the top left and bottom right points equally without taking
+ // discrete pixel coverage into account. An empty B2DRange and thus empty logic Rectangle translated
+ // to an also empty discrete pixel rectangle - what is wrong.
+ basegfx::B2DRange aDiscreteRange(rRange);
+ aDiscreteRange.transform(getOutputDevice().GetViewTransformation());
+
+ if(SvtOptionsDrawinglayer::IsAntiAliasing())
+ {
+ // assume AA needs one pixel more and invalidate one pixel more
+ const double fDiscreteOne(getDiscreteOne());
+ const basegfx::B2IPoint aTopLeft(
+ static_cast<sal_Int32>(floor(aDiscreteRange.getMinX() - fDiscreteOne)),
+ static_cast<sal_Int32>(floor(aDiscreteRange.getMinY() - fDiscreteOne)));
+ const basegfx::B2IPoint aBottomRight(
+ static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxX() + fDiscreteOne)),
+ static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxY() + fDiscreteOne)));
+
+ maBufferRememberedRangePixel.expand(aTopLeft);
+ maBufferRememberedRangePixel.expand(aBottomRight);
+ }
+ else
+ {
+ const basegfx::B2IPoint aTopLeft(static_cast<sal_Int32>(floor(aDiscreteRange.getMinX())), static_cast<sal_Int32>(floor(aDiscreteRange.getMinY())));
+ const basegfx::B2IPoint aBottomRight(static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxX())), static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxY())));
+
+ maBufferRememberedRangePixel.expand(aTopLeft);
+ maBufferRememberedRangePixel.expand(aBottomRight);
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayobject.cxx b/svx/source/sdr/overlay/overlayobject.cxx
new file mode 100644
index 000000000..4fd227977
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayobject.cxx
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlayobject.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <osl/diagnose.h>
+
+namespace sdr::overlay
+{
+ void OverlayObject::objectChange()
+ {
+ const basegfx::B2DRange aPreviousRange(maBaseRange);
+ maBaseRange.reset();
+ resetPrimitive2DSequence();
+// setPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DContainer());
+
+ if(getOverlayManager() && !aPreviousRange.isEmpty())
+ {
+ getOverlayManager()->invalidateRange(aPreviousRange);
+ }
+
+ const basegfx::B2DRange& rCurrentRange = getBaseRange();
+
+ if(getOverlayManager() && rCurrentRange != aPreviousRange && !rCurrentRange.isEmpty())
+ {
+ getOverlayManager()->invalidateRange(rCurrentRange);
+ }
+ }
+
+ // OverlayObject implementations.
+ drawinglayer::primitive2d::Primitive2DContainer OverlayObject::createOverlayObjectPrimitive2DSequence()
+ {
+ // Default implementation has to assert a missing implementation. It cannot
+ // be useful to have overlay object derivations which have no visualisation
+ // at all
+ OSL_FAIL("OverlayObject derivation without visualisation definition (missing createOverlayObjectPrimitive2DSequence implementation) (!)");
+ return drawinglayer::primitive2d::Primitive2DContainer();
+ }
+
+ sal_uInt32 OverlayObject::impCheckBlinkTimeValueRange(sal_uInt64 nBlinkTime)
+ {
+ if(nBlinkTime < 25)
+ {
+ nBlinkTime = 25;
+ }
+ else if(nBlinkTime > 10000)
+ {
+ nBlinkTime = 10000;
+ }
+
+ return nBlinkTime;
+ }
+
+ void OverlayObject::allowAntiAliase(bool bNew)
+ {
+ if(bNew != mbAllowsAntiAliase)
+ {
+ // remember new value
+ mbAllowsAntiAliase = bNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+ OverlayObject::OverlayObject(Color aBaseColor)
+ : mpOverlayManager(nullptr),
+ maOffset(0.0, 0.0),
+ maBaseColor(aBaseColor),
+ mbIsVisible(true),
+ mbIsHittable(true),
+ mbAllowsAnimation(false),
+ mbAllowsAntiAliase(true)
+ {
+ }
+
+ OverlayObject::~OverlayObject()
+ {
+ OSL_ENSURE(nullptr == getOverlayManager(), "OverlayObject is destructed which is still registered at OverlayManager (!)");
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlayObject::getOverlayObjectPrimitive2DSequence() const
+ {
+ if(getPrimitive2DSequence().empty())
+ {
+ // no existing sequence; create one
+ const_cast< OverlayObject* >(this)->maPrimitive2DSequence = const_cast< OverlayObject* >(this)->createOverlayObjectPrimitive2DSequence();
+
+ if(!getOffset().equalZero())
+ {
+ // embed to offset transformation
+ const basegfx::B2DHomMatrix aTranslateGridOffset(
+ basegfx::utils::createTranslateB2DHomMatrix(
+ getOffset()));
+ drawinglayer::primitive2d::Primitive2DReference aEmbed(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aTranslateGridOffset,
+ std::move(const_cast<drawinglayer::primitive2d::Primitive2DContainer&>(maPrimitive2DSequence))));
+
+ const_cast< OverlayObject* >(this)->maPrimitive2DSequence = drawinglayer::primitive2d::Primitive2DContainer { aEmbed };
+ }
+ }
+
+ return getPrimitive2DSequence();
+ }
+
+ const basegfx::B2DRange& OverlayObject::getBaseRange() const
+ {
+ if(getOverlayManager() && maBaseRange.isEmpty())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer& rSequence = getOverlayObjectPrimitive2DSequence();
+
+ if(!rSequence.empty())
+ {
+ const drawinglayer::geometry::ViewInformation2D & aViewInformation2D(getOverlayManager()->getCurrentViewInformation2D());
+
+ const_cast< sdr::overlay::OverlayObject* >(this)->maBaseRange =
+ rSequence.getB2DRange(aViewInformation2D);
+ }
+ }
+
+ return maBaseRange;
+ }
+
+ void OverlayObject::setVisible(bool bNew)
+ {
+ if(bNew != mbIsVisible)
+ {
+ // remember new value
+ mbIsVisible = bNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+ void OverlayObject::setHittable(bool bNew)
+ {
+ if(bNew != mbIsHittable)
+ {
+ // remember new value
+ mbIsHittable = bNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+ void OverlayObject::setBaseColor(Color aNew)
+ {
+ if(aNew != maBaseColor)
+ {
+ // remember new value
+ maBaseColor = aNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+ void OverlayObject::setOffset(const basegfx::B2DVector& rOffset)
+ {
+ if(rOffset != maOffset)
+ {
+ // remember new value
+ maOffset = rOffset;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+ void OverlayObject::Trigger(sal_uInt32 /*nTime*/)
+ {
+ // default does not register again
+ }
+
+ void OverlayObject::stripeDefinitionHasChanged()
+ {
+ // default does not need to do anything
+ }
+
+
+ OverlayObjectWithBasePosition::OverlayObjectWithBasePosition(const basegfx::B2DPoint& rBasePos, Color aBaseColor)
+ : OverlayObject(aBaseColor),
+ maBasePosition(rBasePos)
+ {
+ }
+
+ OverlayObjectWithBasePosition::~OverlayObjectWithBasePosition()
+ {
+ }
+
+ void OverlayObjectWithBasePosition::setBasePosition(const basegfx::B2DPoint& rNew)
+ {
+ if(rNew != maBasePosition)
+ {
+ // remember new value
+ maBasePosition = rNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayobjectcell.cxx b/svx/source/sdr/overlay/overlayobjectcell.cxx
new file mode 100644
index 000000000..a7da6a299
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayobjectcell.cxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <basegfx/numeric/ftools.hxx>
+#include <sdr/overlay/overlayobjectcell.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+
+using namespace ::basegfx;
+
+namespace sdr::overlay
+{
+ OverlayObjectCell::OverlayObjectCell( const Color& rColor, RangeVector&& rRects )
+ : OverlayObject( rColor ),
+ maRectangles( std::move(rRects) )
+ {
+ // no AA for selection overlays
+ allowAntiAliase(false);
+ }
+
+ OverlayObjectCell::~OverlayObjectCell()
+ {
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlayObjectCell::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+ const sal_uInt32 nCount(maRectangles.size());
+
+ if(nCount)
+ {
+ const basegfx::BColor aRGBColor(getBaseColor().getBColor());
+ aRetval.resize(nCount);
+
+ // create primitives for all ranges
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const basegfx::B2DRange& rRange(maRectangles[a]);
+ const basegfx::B2DPolygon aPolygon(basegfx::utils::createPolygonFromRect(rRange));
+
+ aRetval[a] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aPolygon),
+ aRGBColor));
+ }
+
+
+ // embed in 50% transparent paint
+ drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparence(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ std::move(aRetval),
+ 0.5));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparence };
+ }
+
+ return aRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayobjectlist.cxx b/svx/source/sdr/overlay/overlayobjectlist.cxx
new file mode 100644
index 000000000..d71f6c278
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayobjectlist.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlayobjectlist.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <vcl/outdev.hxx>
+#include <tools/gen.hxx>
+
+#include <drawinglayer/processor2d/hittestprocessor2d.hxx>
+#include <comphelper/lok.hxx>
+
+#define DEFAULT_VALUE_FOR_HITTEST_PIXEL (2)
+#define DEFAULT_VALUE_FOR_HITTEST_TWIP (30)
+
+namespace sdr::overlay
+{
+ OverlayObjectList::~OverlayObjectList()
+ {
+ clear();
+ }
+
+ void OverlayObjectList::clear()
+ {
+ for(auto & pCandidate : maVector)
+ {
+ if(pCandidate->getOverlayManager())
+ pCandidate->getOverlayManager()->remove(*pCandidate);
+ }
+ maVector.clear();
+ }
+
+ void OverlayObjectList::append(std::unique_ptr<OverlayObject> pOverlayObject)
+ {
+ assert(pOverlayObject && "tried to add invalid OverlayObject to OverlayObjectList");
+ maVector.push_back(std::move(pOverlayObject));
+ }
+
+ bool OverlayObjectList::isHitLogic(const basegfx::B2DPoint& rLogicPosition, double fLogicTolerance) const
+ {
+ if(!maVector.empty())
+ {
+ OverlayObject* pFirst = maVector.front().get();
+ OverlayManager* pManager = pFirst->getOverlayManager();
+
+ if(pManager)
+ {
+ if(0.0 == fLogicTolerance)
+ {
+ Size aSizeLogic(pManager->getOutputDevice().PixelToLogic(
+ Size(DEFAULT_VALUE_FOR_HITTEST_PIXEL, DEFAULT_VALUE_FOR_HITTEST_PIXEL)));
+
+ // When tiled rendering, we always work in logic units, use the non-pixel default.
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ aSizeLogic = Size(DEFAULT_VALUE_FOR_HITTEST_TWIP, DEFAULT_VALUE_FOR_HITTEST_TWIP);
+ if (pManager->getOutputDevice().GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ aSizeLogic = o3tl::convert(aSizeLogic, o3tl::Length::twip, o3tl::Length::mm100);
+ }
+
+ fLogicTolerance = aSizeLogic.Width();
+ }
+
+ const drawinglayer::geometry::ViewInformation2D& aViewInformation2D(pManager->getCurrentViewInformation2D());
+ drawinglayer::processor2d::HitTestProcessor2D aHitTestProcessor2D(
+ aViewInformation2D,
+ rLogicPosition,
+ fLogicTolerance,
+ false);
+
+ for(auto & pCandidate : maVector)
+ {
+ if(pCandidate->isHittable())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer& rSequence = pCandidate->getOverlayObjectPrimitive2DSequence();
+
+ if(!rSequence.empty())
+ {
+ aHitTestProcessor2D.process(rSequence);
+
+ if(aHitTestProcessor2D.getHit())
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ bool OverlayObjectList::isHitPixel(const Point& rDiscretePosition) const
+ {
+ constexpr sal_uInt32 nDiscreteTolerance = DEFAULT_VALUE_FOR_HITTEST_PIXEL;
+ if(!maVector.empty())
+ {
+ OverlayObject* pCandidate = maVector.front().get();
+ OverlayManager* pManager = pCandidate->getOverlayManager();
+
+ if(pManager)
+ {
+ const Point aPosLogic(pManager->getOutputDevice().PixelToLogic(rDiscretePosition));
+ const basegfx::B2DPoint aPosition(aPosLogic.X(), aPosLogic.Y());
+
+ const Size aSizeLogic(pManager->getOutputDevice().PixelToLogic(Size(nDiscreteTolerance, nDiscreteTolerance)));
+ return isHitLogic(aPosition, static_cast<double>(aSizeLogic.Width()));
+ }
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange OverlayObjectList::getBaseRange() const
+ {
+ basegfx::B2DRange aRetval;
+
+ for(auto & pCandidate : maVector)
+ {
+ aRetval.expand(pCandidate->getBaseRange());
+ }
+
+ return aRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaypolypolygon.cxx b/svx/source/sdr/overlay/overlaypolypolygon.cxx
new file mode 100644
index 000000000..69dacf375
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaypolypolygon.cxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonSelectionPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+
+
+namespace sdr::overlay
+{
+ OverlayPolyPolygon::OverlayPolyPolygon(
+ const basegfx::B2DPolyPolygon& rLinePolyPolygon,
+ Color const & rLineColor,
+ double fLineWidth,
+ Color const & rFillColor)
+ : OverlayObject(rLineColor)
+ , maLinePolyPolygon(rLinePolyPolygon)
+ , mfLineWidth(fLineWidth)
+ , maFillColor(rFillColor)
+ {
+ }
+
+ OverlayPolyPolygon::~OverlayPolyPolygon() = default;
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlayPolyPolygon::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aReturnContainer;
+
+ if (getOverlayManager())
+ {
+ const drawinglayer::attribute::LineAttribute aLineAttribute(getBaseColor().getBColor(), mfLineWidth);
+
+ aReturnContainer = drawinglayer::primitive2d::Primitive2DContainer {
+ new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(maLinePolyPolygon, aLineAttribute) };
+
+ if (maFillColor.GetAlpha() != 0)
+ {
+ aReturnContainer.push_back(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(maLinePolyPolygon, maFillColor.getBColor()));
+ }
+
+ sal_uInt8 nTransparency = 255 - getBaseColor().GetAlpha();
+ if (nTransparency > 0)
+ {
+ drawinglayer::primitive2d::Primitive2DReference aTransparencePrimitive(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aReturnContainer), nTransparency / 255.0));
+ aReturnContainer = drawinglayer::primitive2d::Primitive2DContainer{ aTransparencePrimitive };
+ }
+ }
+
+ return aReturnContainer;
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlayPolyPolygonStripedAndFilled::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(getOverlayManager())
+ {
+ const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor());
+ const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor());
+ const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel());
+ const drawinglayer::primitive2d::Primitive2DReference aStriped(
+ new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
+ getLinePolyPolygon(),
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aStriped };
+
+ const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor());
+ const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
+
+ const drawinglayer::primitive2d::Primitive2DReference aFilled(
+ new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D(
+ getLinePolyPolygon(),
+ aHilightColor,
+ fTransparence,
+ 3.0,
+ false));
+
+ aRetval.push_back(aFilled);
+ }
+
+ return aRetval;
+ }
+
+ void OverlayPolyPolygonStripedAndFilled::stripeDefinitionHasChanged()
+ {
+ // react on OverlayManager's stripe definition change
+ objectChange();
+ }
+
+ OverlayPolyPolygonStripedAndFilled::OverlayPolyPolygonStripedAndFilled(
+ const basegfx::B2DPolyPolygon& rLinePolyPolygon)
+ : OverlayObject(COL_BLACK),
+ maLinePolyPolygon(rLinePolyPolygon)
+ {
+ }
+
+ OverlayPolyPolygonStripedAndFilled::~OverlayPolyPolygonStripedAndFilled()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx b/svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx
new file mode 100644
index 000000000..eabd290f8
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayPrimitive2DSequenceObject::createOverlayObjectPrimitive2DSequence()
+ {
+ return maSequence;
+ }
+
+ OverlayPrimitive2DSequenceObject::OverlayPrimitive2DSequenceObject(drawinglayer::primitive2d::Primitive2DContainer&& rSequence)
+ : OverlayObjectWithBasePosition(basegfx::B2DPoint(), COL_BLACK),
+ maSequence(std::move(rSequence))
+ {
+ }
+
+ OverlayPrimitive2DSequenceObject::~OverlayPrimitive2DSequenceObject()
+ {
+ }
+} // end of namespace sdr::overlay
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayrectangle.cxx b/svx/source/sdr/overlay/overlayrectangle.cxx
new file mode 100644
index 000000000..617c6d4dc
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayrectangle.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlayrectangle.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayRectangle::createOverlayObjectPrimitive2DSequence()
+ {
+ const basegfx::B2DRange aHatchRange(getBasePosition(), maSecondPosition);
+ basegfx::BColor aColor(getBaseColor().getBColor());
+ static const double fChange(0.1); // just small optical change, do not make it annoying
+
+ if(mbOverlayState)
+ {
+ aColor += basegfx::B3DTuple(fChange, fChange, fChange);
+ aColor.clamp();
+ }
+ else
+ {
+ aColor -= basegfx::B3DTuple(fChange, fChange, fChange);
+ aColor.clamp();
+ }
+
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::OverlayRectanglePrimitive(
+ aHatchRange,
+ aColor,
+ mfTransparence,
+ mfDiscreteGrow,
+ mfDiscreteShrink,
+ mfRotation));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ OverlayRectangle::OverlayRectangle(
+ const basegfx::B2DPoint& rBasePosition,
+ const basegfx::B2DPoint& rSecondPosition,
+ const Color& rHatchColor,
+ double fTransparence,
+ double fDiscreteGrow,
+ double fDiscreteShrink,
+ double fRotation,
+ bool bAnimate)
+ : OverlayObjectWithBasePosition(rBasePosition, rHatchColor),
+ maSecondPosition(rSecondPosition),
+ mfTransparence(fTransparence),
+ mfDiscreteGrow(fDiscreteGrow),
+ mfDiscreteShrink(fDiscreteShrink),
+ mfRotation(fRotation),
+ mnBlinkTime(impCheckBlinkTimeValueRange(500)),
+ mbOverlayState(false)
+ {
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ // no animation in high contrast mode
+ bAnimate = false;
+ }
+
+ // set AllowsAnimation flag to mark this object as animation capable
+ mbAllowsAnimation = bAnimate;
+ }
+
+ void OverlayRectangle::Trigger(sal_uInt32 nTime)
+ {
+ if(!getOverlayManager())
+ return;
+
+ // #i53216# produce event after nTime + x
+ SetTime(nTime + mnBlinkTime);
+
+ // switch state
+ if(mbOverlayState)
+ {
+ mbOverlayState = false;
+ }
+ else
+ {
+ mbOverlayState = true;
+ }
+
+ // re-insert me as event
+ getOverlayManager()->InsertEvent(*this);
+
+ // register change (after change)
+ objectChange();
+ }
+} // end of namespace
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayrollingrectangle.cxx b/svx/source/sdr/overlay/overlayrollingrectangle.cxx
new file mode 100644
index 000000000..f03380edd
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayrollingrectangle.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlayrollingrectangle.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonSelectionPrimitive2D.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayRollingRectangleStriped::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(getOverlayManager() && (mbShowBounds || mbExtendedLines))
+ {
+ const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor());
+ const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor());
+ const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel());
+ const basegfx::B2DRange aRollingRectangle(getBasePosition(), getSecondPosition());
+
+ if(mbShowBounds)
+ {
+ // view-independent part, create directly
+ const basegfx::B2DPolygon aPolygon(basegfx::utils::createPolygonFromRect(aRollingRectangle));
+
+ aRetval.resize(2);
+ aRetval[0] = new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
+ basegfx::B2DPolyPolygon(aPolygon),
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel);
+
+ const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor());
+ const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
+
+ aRetval[1] = new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D(
+ basegfx::B2DPolyPolygon(aPolygon),
+ aHilightColor,
+ fTransparence,
+ 3.0,
+ false);
+ }
+
+ if(mbExtendedLines)
+ {
+ // view-dependent part, use helper primitive
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::OverlayRollingRectanglePrimitive(
+ aRollingRectangle,
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel));
+
+ aRetval.push_back(aReference);
+ }
+ }
+
+ return aRetval;
+ }
+
+ void OverlayRollingRectangleStriped::stripeDefinitionHasChanged()
+ {
+ // react on OverlayManager's stripe definition change
+ objectChange();
+ }
+
+ OverlayRollingRectangleStriped::OverlayRollingRectangleStriped(
+ const basegfx::B2DPoint& rBasePos,
+ const basegfx::B2DPoint& rSecondPos,
+ bool bExtendedLines,
+ bool bShowBounds)
+ : OverlayObjectWithBasePosition(rBasePos, COL_BLACK),
+ maSecondPosition(rSecondPos),
+ mbExtendedLines(bExtendedLines),
+ mbShowBounds(bShowBounds)
+ {
+ }
+
+ OverlayRollingRectangleStriped::~OverlayRollingRectangleStriped()
+ {
+ }
+
+ void OverlayRollingRectangleStriped::setSecondPosition(const basegfx::B2DPoint& rNew)
+ {
+ if(rNew != maSecondPosition)
+ {
+ // remember new value
+ maSecondPosition = rNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayselection.cxx b/svx/source/sdr/overlay/overlayselection.cxx
new file mode 100644
index 000000000..0463567c5
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayselection.cxx
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlayselection.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHairlinePrimitive2D.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+#include <drawinglayer/primitive2d/invertprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+
+
+namespace sdr::overlay
+{
+ // combine rages geometrically to a single, ORed polygon
+ static basegfx::B2DPolyPolygon impCombineRangesToPolyPolygon(const std::vector< basegfx::B2DRange >& rRanges)
+ {
+ const sal_uInt32 nCount(rRanges.size());
+ basegfx::B2DPolyPolygon aRetval;
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const basegfx::B2DPolygon aDiscretePolygon(basegfx::utils::createPolygonFromRect(rRanges[a]));
+
+ if(0 == a)
+ {
+ aRetval.append(aDiscretePolygon);
+ }
+ else
+ {
+ aRetval = basegfx::utils::solvePolygonOperationOr(aRetval, basegfx::B2DPolyPolygon(aDiscretePolygon));
+ }
+ }
+
+ return aRetval;
+ }
+
+ // check if wanted type OverlayType::Transparent or OverlayType::Solid
+ // is possible. If not, fallback to invert mode (classic mode)
+ static OverlayType impCheckPossibleOverlayType(OverlayType aOverlayType)
+ {
+ if(OverlayType::Invert != aOverlayType)
+ {
+ if(!SvtOptionsDrawinglayer::IsTransparentSelection())
+ {
+ // not possible when switched off by user
+ return OverlayType::Invert;
+ }
+ else if (const OutputDevice* pOut = Application::GetDefaultDevice())
+ {
+
+ if(pOut->GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ // not possible when in high contrast mode
+ return OverlayType::Invert;
+ }
+
+ if(!pOut->SupportsOperation(OutDevSupportType::TransparentRect))
+ {
+ // not possible when no fast transparence paint is supported on the system
+ return OverlayType::Invert;
+ }
+ }
+ }
+
+ return aOverlayType;
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlaySelection::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+ const sal_uInt32 nCount(getRanges().size());
+
+ if(nCount)
+ {
+ // create range primitives
+ const bool bInvert(OverlayType::Invert == maLastOverlayType);
+ basegfx::BColor aRGBColor(getBaseColor().getBColor());
+ aRetval.resize(nCount);
+
+ if(bInvert)
+ {
+ // force color to white for invert to get a full invert
+ aRGBColor = basegfx::BColor(1.0, 1.0, 1.0);
+ }
+
+ for(sal_uInt32 a(0);a < nCount; a++)
+ {
+ const basegfx::B2DPolygon aPolygon(basegfx::utils::createPolygonFromRect(maRanges[a]));
+ aRetval[a] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aPolygon),
+ aRGBColor));
+ }
+
+ if(bInvert)
+ {
+ // embed all in invert primitive
+ drawinglayer::primitive2d::Primitive2DReference aInvert(
+ new drawinglayer::primitive2d::InvertPrimitive2D(
+ std::move(aRetval)));
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aInvert };
+ }
+ else if(OverlayType::Transparent == maLastOverlayType)
+ {
+ // embed all rectangles in transparent paint
+ const double fTransparence(mnLastTransparence / 100.0);
+ const drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparence(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ std::move(aRetval),
+ fTransparence));
+
+ if(mbBorder)
+ {
+ const basegfx::B2DPolyPolygon aPolyPolygon(impCombineRangesToPolyPolygon(getRanges()));
+ const drawinglayer::primitive2d::Primitive2DReference aSelectionOutline(
+ new drawinglayer::primitive2d::PolyPolygonHairlinePrimitive2D(
+ aPolyPolygon,
+ aRGBColor));
+
+ // add both to result
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparence, aSelectionOutline };
+ }
+ else
+ {
+ // just add transparent part
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparence };
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ OverlaySelection::OverlaySelection(
+ OverlayType eType,
+ const Color& rColor,
+ std::vector< basegfx::B2DRange >&& rRanges,
+ bool bBorder)
+ : OverlayObject(rColor),
+ meOverlayType(eType),
+ maRanges(std::move(rRanges)),
+ maLastOverlayType(eType),
+ mnLastTransparence(0),
+ mbBorder(bBorder)
+ {
+ // no AA for selection overlays
+ allowAntiAliase(false);
+ }
+
+ OverlaySelection::~OverlaySelection()
+ {
+ if(getOverlayManager())
+ {
+ getOverlayManager()->remove(*this);
+ }
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlaySelection::getOverlayObjectPrimitive2DSequence() const
+ {
+ // get current values
+ const OverlayType aNewOverlayType(impCheckPossibleOverlayType(meOverlayType));
+ const sal_uInt16 nNewTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent());
+
+ if(!getPrimitive2DSequence().empty())
+ {
+ if(aNewOverlayType != maLastOverlayType
+ || nNewTransparence != mnLastTransparence)
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< OverlaySelection* >(this)->resetPrimitive2DSequence();
+ }
+ }
+
+ if(getPrimitive2DSequence().empty())
+ {
+ // remember new values
+ const_cast< OverlaySelection* >(this)->maLastOverlayType = aNewOverlayType;
+ const_cast< OverlaySelection* >(this)->mnLastTransparence = nNewTransparence;
+ }
+
+ // call base implementation
+ return OverlayObject::getOverlayObjectPrimitive2DSequence();
+ }
+
+ void OverlaySelection::setRanges(std::vector< basegfx::B2DRange >&& rNew)
+ {
+ if(rNew != maRanges)
+ {
+ maRanges = std::move(rNew);
+ objectChange();
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaytools.cxx b/svx/source/sdr/overlay/overlaytools.cxx
new file mode 100644
index 000000000..ceeb32b3f
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaytools.cxx
@@ -0,0 +1,601 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/overlay/overlaytools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolygonMarkerPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHatchPrimitive2D.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+
+namespace drawinglayer::primitive2d
+{
+
+OverlayStaticRectanglePrimitive::OverlayStaticRectanglePrimitive(
+ const basegfx::B2DPoint& rPosition,
+ const basegfx::B2DSize& rSize,
+ const basegfx::BColor& rStrokeColor,
+ const basegfx::BColor& rFillColor,
+ double fTransparence,
+ double fRotation)
+ : maPosition(rPosition)
+ , maSize(rSize)
+ , maStrokeColor(rStrokeColor)
+ , maFillColor(rFillColor)
+ , mfTransparence(fTransparence)
+ , mfRotation(fRotation)
+{}
+
+void OverlayStaticRectanglePrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+{
+ Primitive2DContainer aPrimitive2DSequence;
+ const double fHalfWidth = maSize.getX() * getDiscreteUnit() / 2.0;
+ const double fHalfHeight = maSize.getY() * getDiscreteUnit() / 2.0;
+
+ basegfx::B2DRange aRange(
+ maPosition.getX() - fHalfWidth, maPosition.getY() - fHalfHeight,
+ maPosition.getX() + fHalfWidth, maPosition.getY() + fHalfHeight);
+
+ if (basegfx::fTools::more(getDiscreteUnit(), 0.0) && mfTransparence <= 1.0)
+ {
+ basegfx::B2DPolygon aPolygon(
+ basegfx::utils::createPolygonFromRect(aRange));
+
+ // create filled primitive
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ aPolyPolygon.append(aPolygon);
+
+ const attribute::LineAttribute aLineAttribute(maStrokeColor, 1.0);
+
+ // create data
+ const Primitive2DReference aStroke(
+ new PolyPolygonStrokePrimitive2D(aPolyPolygon, aLineAttribute));
+
+ // create fill primitive
+ const Primitive2DReference aFill(
+ new PolyPolygonColorPrimitive2D(aPolyPolygon, maFillColor));
+
+ aPrimitive2DSequence = Primitive2DContainer(2);
+ aPrimitive2DSequence[0] = aFill;
+ aPrimitive2DSequence[1] = aStroke;
+
+ // embed filled to transparency (if used)
+ if (mfTransparence > 0.0)
+ {
+ const Primitive2DReference aFillTransparent(
+ new UnifiedTransparencePrimitive2D(
+ std::move(aPrimitive2DSequence),
+ mfTransparence));
+
+ aPrimitive2DSequence = Primitive2DContainer { aFillTransparent };
+ }
+ }
+
+ rContainer.append(std::move(aPrimitive2DSequence));
+}
+
+bool OverlayStaticRectanglePrimitive::operator==(const BasePrimitive2D& rPrimitive) const
+{
+ if (DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayStaticRectanglePrimitive& rCompare = static_cast<const OverlayStaticRectanglePrimitive&>(rPrimitive);
+
+ return (maPosition == rCompare.maPosition
+ && maSize == rCompare.maSize
+ && maStrokeColor == rCompare.maStrokeColor
+ && maFillColor == rCompare.maFillColor
+ && mfTransparence == rCompare.mfTransparence
+ && mfRotation == rCompare.mfRotation);
+ }
+
+ return false;
+}
+
+sal_uInt32 OverlayStaticRectanglePrimitive::getPrimitive2DID() const
+{
+ return PRIMITIVE2D_ID_OVERLAYRECTANGLEPRIMITIVE;
+}
+
+
+
+ OverlayBitmapExPrimitive::OverlayBitmapExPrimitive(
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DPoint& rBasePosition,
+ sal_uInt16 nCenterX,
+ sal_uInt16 nCenterY,
+ double fShearX,
+ double fRotation)
+ : maBitmapEx(rBitmapEx),
+ maBasePosition(rBasePosition),
+ mnCenterX(nCenterX),
+ mnCenterY(nCenterY),
+ mfShearX(fShearX),
+ mfRotation(fRotation)
+ {}
+
+ void OverlayBitmapExPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ const Size aBitmapSize(getBitmapEx().GetSizePixel());
+
+ if(!aBitmapSize.Width() || !aBitmapSize.Height() || !basegfx::fTools::more(getDiscreteUnit(), 0.0))
+ return;
+
+ // calculate back from internal bitmap's extreme coordinates (the edges)
+ // to logical coordinates. Only use a unified scaling value (getDiscreteUnit(),
+ // the prepared one which expresses how many logic units form a discrete unit)
+ // for this step. This primitive is to be displayed always unscaled (in its pixel size)
+ // and unrotated, more like a marker
+ const double fLeft((0.0 - getCenterX()) * getDiscreteUnit());
+ const double fTop((0.0 - getCenterY()) * getDiscreteUnit());
+ const double fRight((aBitmapSize.getWidth() - getCenterX()) * getDiscreteUnit());
+ const double fBottom((aBitmapSize.getHeight() - getCenterY()) * getDiscreteUnit());
+
+ // create a BitmapPrimitive2D using those positions
+ basegfx::B2DHomMatrix aTransform;
+
+ aTransform.set(0, 0, fRight - fLeft);
+ aTransform.set(1, 1, fBottom - fTop);
+ aTransform.set(0, 2, fLeft);
+ aTransform.set(1, 2, fTop);
+
+ // if shearX is used, apply it, too
+ if(!basegfx::fTools::equalZero(getShearX()))
+ {
+ aTransform.shearX(getShearX());
+ }
+
+ // if rotation is used, apply it, too
+ if(!basegfx::fTools::equalZero(getRotation()))
+ {
+ aTransform.rotate(getRotation());
+ }
+
+ // add BasePosition
+ aTransform.translate(getBasePosition().getX(), getBasePosition().getY());
+
+ rContainer.push_back(
+ new BitmapPrimitive2D(
+ VCLUnoHelper::CreateVCLXBitmap(getBitmapEx()),
+ aTransform));
+ }
+
+ bool OverlayBitmapExPrimitive::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayBitmapExPrimitive& rCompare = static_cast< const OverlayBitmapExPrimitive& >(rPrimitive);
+
+ return (getBitmapEx() == rCompare.getBitmapEx()
+ && getBasePosition() == rCompare.getBasePosition()
+ && getCenterX() == rCompare.getCenterX()
+ && getCenterY() == rCompare.getCenterY()
+ && getShearX() == rCompare.getShearX()
+ && getRotation() == rCompare.getRotation());
+ }
+
+ return false;
+ }
+
+ sal_uInt32 OverlayBitmapExPrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_OVERLAYBITMAPEXPRIMITIVE;
+ }
+
+
+
+ OverlayCrosshairPrimitive::OverlayCrosshairPrimitive(
+ const basegfx::B2DPoint& rBasePosition,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength)
+ : maBasePosition(rBasePosition),
+ maRGBColorA(rRGBColorA),
+ maRGBColorB(rRGBColorB),
+ mfDiscreteDashLength(fDiscreteDashLength)
+ {}
+
+ void OverlayCrosshairPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // use the prepared Viewport information accessible using getViewport()
+
+ if(getViewport().isEmpty())
+ return;
+
+ basegfx::B2DPolygon aPolygon;
+
+ aPolygon.append(basegfx::B2DPoint(getViewport().getMinX(), getBasePosition().getY()));
+ aPolygon.append(basegfx::B2DPoint(getViewport().getMaxX(), getBasePosition().getY()));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aPolygon,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+
+ aPolygon.clear();
+ aPolygon.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMinY()));
+ aPolygon.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMaxY()));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aPolygon,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+ }
+
+ bool OverlayCrosshairPrimitive::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(ViewportDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayCrosshairPrimitive& rCompare = static_cast< const OverlayCrosshairPrimitive& >(rPrimitive);
+
+ return (getBasePosition() == rCompare.getBasePosition()
+ && getRGBColorA() == rCompare.getRGBColorA()
+ && getRGBColorB() == rCompare.getRGBColorB()
+ && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
+ }
+
+ return false;
+ }
+
+ sal_uInt32 OverlayCrosshairPrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_OVERLAYCROSSHAIRPRIMITIVE;
+ }
+
+
+
+ OverlayRectanglePrimitive::OverlayRectanglePrimitive(
+ const basegfx::B2DRange& rObjectRange,
+ const basegfx::BColor& rColor,
+ double fTransparence,
+ double fDiscreteGrow,
+ double fDiscreteShrink,
+ double fRotation)
+ : maObjectRange(rObjectRange),
+ maColor(rColor),
+ mfTransparence(fTransparence),
+ mfDiscreteGrow(fDiscreteGrow),
+ mfDiscreteShrink(fDiscreteShrink),
+ mfRotation(fRotation)
+ {}
+
+ void OverlayRectanglePrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+ basegfx::B2DRange aInnerRange(getObjectRange());
+
+ if(!aInnerRange.isEmpty() && basegfx::fTools::more(getDiscreteUnit(), 0.0) && getTransparence() <= 1.0)
+ {
+ basegfx::B2DRange aOuterRange(getObjectRange());
+
+ // grow/shrink inner/outer polygons
+ aOuterRange.grow(getDiscreteUnit() * getDiscreteGrow());
+ aInnerRange.grow(getDiscreteUnit() * -getDiscreteShrink());
+
+ // convert to polygons
+ const double fFullGrow(getDiscreteGrow() + getDiscreteShrink());
+ const double fRelativeRadiusX(fFullGrow / aOuterRange.getWidth());
+ const double fRelativeRadiusY(fFullGrow / aOuterRange.getHeight());
+ basegfx::B2DPolygon aOuterPolygon(
+ basegfx::utils::createPolygonFromRect(
+ aOuterRange,
+ fRelativeRadiusX,
+ fRelativeRadiusY));
+ basegfx::B2DPolygon aInnerPolygon(
+ basegfx::utils::createPolygonFromRect(
+ aInnerRange));
+
+ // apply evtl. existing rotation
+ if(!basegfx::fTools::equalZero(getRotation()))
+ {
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createRotateAroundPoint(
+ getObjectRange().getMinX(), getObjectRange().getMinY(), getRotation()));
+
+ aOuterPolygon.transform(aTransform);
+ aInnerPolygon.transform(aTransform);
+ }
+
+ // create filled primitive
+ basegfx::B2DPolyPolygon aPolyPolygon;
+
+ aPolyPolygon.append(aOuterPolygon);
+ aPolyPolygon.append(aInnerPolygon);
+
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ // for high contrast, use hatch
+ const basegfx::BColor aHighContrastLineColor(Application::GetSettings().GetStyleSettings().GetFontColor().getBColor());
+ const basegfx::BColor aEmptyColor(0.0, 0.0, 0.0);
+ const double fHatchRotation(basegfx::deg2rad(45));
+ const double fDiscreteHatchDistance(3.0);
+ const drawinglayer::attribute::FillHatchAttribute aFillHatchAttribute(
+ drawinglayer::attribute::HatchStyle::Single,
+ fDiscreteHatchDistance * getDiscreteUnit(),
+ fHatchRotation - getRotation(),
+ aHighContrastLineColor,
+ 3, // same default as VCL, a minimum of three discrete units (pixels) offset
+ false);
+ const Primitive2DReference aHatch(
+ new PolyPolygonHatchPrimitive2D(
+ aPolyPolygon,
+ aEmptyColor,
+ aFillHatchAttribute));
+
+ aRetval = Primitive2DContainer { aHatch };
+ }
+ else
+ {
+ // create fill primitive
+ const Primitive2DReference aFill(
+ new PolyPolygonColorPrimitive2D(
+ aPolyPolygon,
+ getColor()));
+
+ aRetval = Primitive2DContainer { aFill };
+
+ // embed filled to transparency (if used)
+ if(getTransparence() > 0.0)
+ {
+ Primitive2DReference aFillTransparent(
+ new UnifiedTransparencePrimitive2D(
+ std::move(aRetval),
+ getTransparence()));
+
+ aRetval = Primitive2DContainer { aFillTransparent };
+ }
+ }
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ bool OverlayRectanglePrimitive::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayRectanglePrimitive& rCompare = static_cast< const OverlayRectanglePrimitive& >(rPrimitive);
+
+ return (getObjectRange() == rCompare.getObjectRange()
+ && getColor() == rCompare.getColor()
+ && getTransparence() == rCompare.getTransparence()
+ && getDiscreteGrow() == rCompare.getDiscreteGrow()
+ && getDiscreteShrink() == rCompare.getDiscreteShrink()
+ && getRotation() == rCompare.getRotation());
+ }
+
+ return false;
+ }
+
+ sal_uInt32 OverlayRectanglePrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_OVERLAYRECTANGLEPRIMITIVE;
+ }
+
+
+
+ OverlayHelplineStripedPrimitive::OverlayHelplineStripedPrimitive(
+ const basegfx::B2DPoint& rBasePosition,
+ HelplineStyle eStyle,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength)
+ : maBasePosition(rBasePosition),
+ meStyle(eStyle),
+ maRGBColorA(rRGBColorA),
+ maRGBColorB(rRGBColorB),
+ mfDiscreteDashLength(fDiscreteDashLength)
+ {}
+
+ void OverlayHelplineStripedPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // use the prepared Viewport information accessible using getViewport()
+
+ if(getViewport().isEmpty())
+ return;
+
+ switch(getStyle())
+ {
+ case HELPLINESTYLE_VERTICAL :
+ {
+ basegfx::B2DPolygon aLine;
+
+ aLine.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMinY()));
+ aLine.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMaxY()));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aLine,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+ break;
+ }
+
+ case HELPLINESTYLE_HORIZONTAL :
+ {
+ basegfx::B2DPolygon aLine;
+
+ aLine.append(basegfx::B2DPoint(getViewport().getMinX(), getBasePosition().getY()));
+ aLine.append(basegfx::B2DPoint(getViewport().getMaxX(), getBasePosition().getY()));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aLine,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+ break;
+ }
+
+ default: // case HELPLINESTYLE_POINT :
+ {
+ const double fDiscreteUnit((rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength());
+ basegfx::B2DPolygon aLineA, aLineB;
+
+ aLineA.append(basegfx::B2DPoint(getBasePosition().getX(), getBasePosition().getY() - fDiscreteUnit));
+ aLineA.append(basegfx::B2DPoint(getBasePosition().getX(), getBasePosition().getY() + fDiscreteUnit));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aLineA,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+
+ aLineB.append(basegfx::B2DPoint(getBasePosition().getX() - fDiscreteUnit, getBasePosition().getY()));
+ aLineB.append(basegfx::B2DPoint(getBasePosition().getX() + fDiscreteUnit, getBasePosition().getY()));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aLineB,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+
+ break;
+ }
+ }
+ }
+
+ bool OverlayHelplineStripedPrimitive::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(ViewportDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayHelplineStripedPrimitive& rCompare = static_cast< const OverlayHelplineStripedPrimitive& >(rPrimitive);
+
+ return (getBasePosition() == rCompare.getBasePosition()
+ && getStyle() == rCompare.getStyle()
+ && getRGBColorA() == rCompare.getRGBColorA()
+ && getRGBColorB() == rCompare.getRGBColorB()
+ && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
+ }
+
+ return false;
+ }
+
+ sal_uInt32 OverlayHelplineStripedPrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_OVERLAYHELPLINESTRIPEDPRIMITIVE;
+ }
+
+
+
+ OverlayRollingRectanglePrimitive::OverlayRollingRectanglePrimitive(
+ const basegfx::B2DRange& aRollingRectangle,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength)
+ : maRollingRectangle(aRollingRectangle),
+ maRGBColorA(rRGBColorA),
+ maRGBColorB(rRGBColorB),
+ mfDiscreteDashLength(fDiscreteDashLength)
+ {}
+
+ void OverlayRollingRectanglePrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // use the prepared Viewport information accessible using getViewport()
+
+ if(getViewport().isEmpty())
+ return;
+
+ basegfx::B2DPolygon aLine;
+
+ // Left lines
+ aLine.append(basegfx::B2DPoint(getViewport().getMinX(), getRollingRectangle().getMinY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMinY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getViewport().getMinX(), getRollingRectangle().getMaxY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMaxY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ // Right lines
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMinY()));
+ aLine.append(basegfx::B2DPoint(getViewport().getMaxX(), getRollingRectangle().getMinY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMaxY()));
+ aLine.append(basegfx::B2DPoint(getViewport().getMaxX(), getRollingRectangle().getMaxY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ // Top lines
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getViewport().getMinY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMinY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getViewport().getMinY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMinY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ // Bottom lines
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMaxY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getViewport().getMaxY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMaxY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getViewport().getMaxY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ }
+
+ bool OverlayRollingRectanglePrimitive::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(ViewportDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayRollingRectanglePrimitive& rCompare = static_cast< const OverlayRollingRectanglePrimitive& >(rPrimitive);
+
+ return (getRollingRectangle() == rCompare.getRollingRectangle()
+ && getRGBColorA() == rCompare.getRGBColorA()
+ && getRGBColorB() == rCompare.getRGBColorB()
+ && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
+ }
+
+ return false;
+ }
+
+ sal_uInt32 OverlayRollingRectanglePrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_OVERLAYROLLINGRECTANGLEPRIMITIVE;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaytriangle.cxx b/svx/source/sdr/overlay/overlaytriangle.cxx
new file mode 100644
index 000000000..f46fcf1e2
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaytriangle.cxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlaytriangle.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayTriangle::createOverlayObjectPrimitive2DSequence()
+ {
+ basegfx::B2DPolygon aPolygon;
+
+ aPolygon.append(getBasePosition());
+ aPolygon.append(maSecondPosition);
+ aPolygon.append(maThirdPosition);
+ aPolygon.setClosed(true);
+
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aPolygon),
+ getBaseColor().getBColor()));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ OverlayTriangle::OverlayTriangle(
+ const basegfx::B2DPoint& rBasePos,
+ const basegfx::B2DPoint& rSecondPos,
+ const basegfx::B2DPoint& rThirdPos,
+ Color aTriangleColor)
+ : OverlayObjectWithBasePosition(rBasePos, aTriangleColor),
+ maSecondPosition(rSecondPos),
+ maThirdPosition(rThirdPos)
+ {
+ }
+
+ OverlayTriangle::~OverlayTriangle()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/primitivefactory2d.cxx b/svx/source/sdr/primitive2d/primitivefactory2d.cxx
new file mode 100644
index 000000000..c6530fd13
--- /dev/null
+++ b/svx/source/sdr/primitive2d/primitivefactory2d.cxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <sdr/primitive2d/primitivefactory2d.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unoapi.hxx>
+
+using namespace com::sun::star;
+
+css::uno::Sequence< css::uno::Reference< css::graphic::XPrimitive2D > > SAL_CALL PrimitiveFactory2D::createPrimitivesFromXShape(
+ const uno::Reference< drawing::XShape >& xShape,
+ const uno::Sequence< beans::PropertyValue >& /*aParms*/ )
+{
+ css::uno::Sequence< css::uno::Reference< css::graphic::XPrimitive2D > > aRetval;
+
+ if(xShape.is())
+ {
+ SdrObject* pSource = SdrObject::getSdrObjectFromXShape(xShape);
+
+ if(pSource)
+ {
+ const sdr::contact::ViewContact& rSource(pSource->GetViewContact());
+ drawinglayer::primitive2d::Primitive2DContainer aSourceVal;
+ rSource.getViewIndependentPrimitive2DContainer(aSourceVal);
+ aRetval = aSourceVal.toSequence();
+ }
+ }
+
+ return aRetval;
+}
+
+void PrimitiveFactory2D::createPrimitivesFromXShape(
+ const uno::Reference< drawing::XShape >& xShape,
+ const uno::Sequence< beans::PropertyValue >& /*aParms*/,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+{
+ if(xShape.is())
+ {
+ SdrObject* pSource = SdrObject::getSdrObjectFromXShape(xShape);
+
+ if(pSource)
+ {
+ const sdr::contact::ViewContact& rSource(pSource->GetViewContact());
+ rSource.getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+ }
+}
+
+css::uno::Sequence< css::uno::Reference< css::graphic::XPrimitive2D > > SAL_CALL PrimitiveFactory2D::createPrimitivesFromXDrawPage(
+ const uno::Reference< drawing::XDrawPage >& xDrawPage,
+ const uno::Sequence< beans::PropertyValue >& /*aParms*/ )
+{
+ css::uno::Sequence< css::uno::Reference< css::graphic::XPrimitive2D > > aRetval;
+
+ if(xDrawPage.is())
+ {
+ SdrPage* pSource = GetSdrPageFromXDrawPage(xDrawPage);
+
+ if(pSource)
+ {
+ const sdr::contact::ViewContact& rSource(pSource->GetViewContact());
+ drawinglayer::primitive2d::Primitive2DContainer aSourceRetval;
+ rSource.getViewIndependentPrimitive2DContainer(aSourceRetval);
+ aRetval = aSourceRetval.toSequence();
+ }
+ }
+
+ return aRetval;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_graphic_PrimitiveFactory2D_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new PrimitiveFactory2D);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrattributecreator.cxx b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
new file mode 100644
index 000000000..bafa96f95
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
@@ -0,0 +1,1151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <svl/itemset.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/xdef.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflbmpit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnedcit.hxx>
+#include <svx/xdash.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xfilluseslidebackgrounditem.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xgrscit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xflbckit.hxx>
+#include <svx/xflbmsxy.hxx>
+#include <svx/xflbtoxy.hxx>
+#include <svx/xflboxy.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xtextit0.hxx>
+#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx>
+#include <svx/svdotext.hxx>
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svl/itempool.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/GraphicLoader.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <svx/svx3ditems.hxx>
+#include <com/sun/star/drawing/ProjectionMode.hpp>
+#include <com/sun/star/drawing/ShadeMode.hpp>
+#include <drawinglayer/attribute/sdrallattribute3d.hxx>
+#include <svx/rectenum.hxx>
+#include <svx/sdtfchim.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/xflbmsli.hxx>
+#include <editeng/editstat.hxx>
+#include <osl/diagnose.h>
+#include <drawinglayer/attribute/fillhatchattribute.hxx>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+#include <sdr/attribute/sdreffectstextattribute.hxx>
+#include <sdr/attribute/sdrlineeffectstextattribute.hxx>
+#include <sdr/attribute/sdrformtextattribute.hxx>
+#include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
+#include <drawinglayer/attribute/sdrsceneattribute3d.hxx>
+#include <drawinglayer/attribute/sdrlightingattribute3d.hxx>
+#include <drawinglayer/attribute/sdrlightattribute3d.hxx>
+#include <sdr/attribute/sdrfilltextattribute.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
+
+using namespace com::sun::star;
+
+namespace drawinglayer
+{
+ namespace
+ {
+ attribute::GradientStyle XGradientStyleToGradientStyle(css::awt::GradientStyle eStyle)
+ {
+ switch(eStyle)
+ {
+ case css::awt::GradientStyle_LINEAR :
+ {
+ return attribute::GradientStyle::Linear;
+ }
+ case css::awt::GradientStyle_AXIAL :
+ {
+ return attribute::GradientStyle::Axial;
+ }
+ case css::awt::GradientStyle_RADIAL :
+ {
+ return attribute::GradientStyle::Radial;
+ }
+ case css::awt::GradientStyle_ELLIPTICAL :
+ {
+ return attribute::GradientStyle::Elliptical;
+ }
+ case css::awt::GradientStyle_SQUARE :
+ {
+ return attribute::GradientStyle::Square;
+ }
+ default :
+ {
+ return attribute::GradientStyle::Rect; // css::awt::GradientStyle_RECT
+ }
+ }
+ }
+
+ attribute::HatchStyle XHatchStyleToHatchStyle(css::drawing::HatchStyle eStyle)
+ {
+ switch(eStyle)
+ {
+ case css::drawing::HatchStyle_SINGLE :
+ {
+ return attribute::HatchStyle::Single;
+ }
+ case css::drawing::HatchStyle_DOUBLE :
+ {
+ return attribute::HatchStyle::Double;
+ }
+ default :
+ {
+ return attribute::HatchStyle::Triple; // css::drawing::HatchStyle_TRIPLE
+ }
+ }
+ }
+
+ basegfx::B2DLineJoin LineJointToB2DLineJoin(css::drawing::LineJoint eLineJoint)
+ {
+ switch(eLineJoint)
+ {
+ case css::drawing::LineJoint_BEVEL :
+ {
+ return basegfx::B2DLineJoin::Bevel;
+ }
+ case css::drawing::LineJoint_MIDDLE :
+ case css::drawing::LineJoint_MITER :
+ {
+ return basegfx::B2DLineJoin::Miter;
+ }
+ case css::drawing::LineJoint_ROUND :
+ {
+ return basegfx::B2DLineJoin::Round;
+ }
+ default : // css::drawing::LineJoint_NONE
+ {
+ return basegfx::B2DLineJoin::NONE;
+ }
+ }
+ }
+
+ basegfx::B2DVector RectPointToB2DVector(RectPoint eRectPoint)
+ {
+ basegfx::B2DVector aRetval(0.0, 0.0);
+
+ // position changes X
+ switch(eRectPoint)
+ {
+ case RectPoint::LT: case RectPoint::LM: case RectPoint::LB:
+ {
+ aRetval.setX(-1.0);
+ break;
+ }
+
+ case RectPoint::RT: case RectPoint::RM: case RectPoint::RB:
+ {
+ aRetval.setX(1.0);
+ break;
+ }
+
+ default :
+ {
+ break;
+ }
+ }
+
+ // position changes Y
+ switch(eRectPoint)
+ {
+ case RectPoint::LT: case RectPoint::MT: case RectPoint::RT:
+ {
+ aRetval.setY(-1.0);
+ break;
+ }
+
+ case RectPoint::LB: case RectPoint::MB: case RectPoint::RB:
+ {
+ aRetval.setY(1.0);
+ break;
+ }
+
+ default :
+ {
+ break;
+ }
+ }
+
+ return aRetval;
+ }
+
+ attribute::SdrGlowAttribute createNewSdrGlowAttribute(const SfxItemSet& rSet)
+ {
+ sal_Int32 nRadius = rSet.Get(SDRATTR_GLOW_RADIUS).GetValue();
+ if (!nRadius)
+ return attribute::SdrGlowAttribute();
+ Color aColor(rSet.Get(SDRATTR_GLOW_COLOR).GetColorValue());
+ sal_uInt16 nTransparency(rSet.Get(SDRATTR_GLOW_TRANSPARENCY).GetValue());
+ if (nTransparency)
+ aColor.SetAlpha(255 - std::round(nTransparency / 100.0 * 255.0));
+
+ attribute::SdrGlowAttribute glowAttr{ nRadius, aColor };
+ return glowAttr;
+ }
+
+ sal_Int32 getSoftEdgeRadius(const SfxItemSet& rSet)
+ {
+ return rSet.Get(SDRATTR_SOFTEDGE_RADIUS).GetValue();
+ }
+ } // end of anonymous namespace
+} // end of namespace drawinglayer
+
+
+namespace drawinglayer::primitive2d
+{
+ attribute::SdrLineAttribute createNewSdrLineAttribute(const SfxItemSet& rSet)
+ {
+ const css::drawing::LineStyle eStyle(rSet.Get(XATTR_LINESTYLE).GetValue());
+
+ if(drawing::LineStyle_NONE != eStyle)
+ {
+ sal_uInt16 nTransparence(rSet.Get(XATTR_LINETRANSPARENCE).GetValue());
+
+ if(nTransparence > 100)
+ {
+ nTransparence = 100;
+ }
+
+ if(100 != nTransparence)
+ {
+ const sal_uInt32 nWidth(rSet.Get(XATTR_LINEWIDTH).GetValue());
+ const Color aColor(rSet.Get(XATTR_LINECOLOR).GetColorValue());
+ const css::drawing::LineJoint eJoint(rSet.Get(XATTR_LINEJOINT).GetValue());
+ const css::drawing::LineCap eCap(rSet.Get(XATTR_LINECAP).GetValue());
+ ::std::vector< double > aDotDashArray;
+ double fFullDotDashLen(0.0);
+
+ if(drawing::LineStyle_DASH == eStyle)
+ {
+ const XDash& rDash = rSet.Get(XATTR_LINEDASH).GetDashValue();
+
+ if(rDash.GetDots() || rDash.GetDashes())
+ {
+ fFullDotDashLen = rDash.CreateDotDashArray(aDotDashArray, static_cast<double>(nWidth));
+ }
+ }
+
+ return attribute::SdrLineAttribute(
+ LineJointToB2DLineJoin(eJoint),
+ static_cast<double>(nWidth),
+ static_cast<double>(nTransparence) * 0.01,
+ aColor.getBColor(),
+ eCap,
+ std::move(aDotDashArray),
+ fFullDotDashLen);
+ }
+ }
+
+ return attribute::SdrLineAttribute();
+ }
+
+ attribute::SdrLineStartEndAttribute createNewSdrLineStartEndAttribute(
+ const SfxItemSet& rSet,
+ double fWidth)
+ {
+ const sal_Int32 nTempStartWidth(rSet.Get(XATTR_LINESTARTWIDTH).GetValue());
+ const sal_Int32 nTempEndWidth(rSet.Get(XATTR_LINEENDWIDTH).GetValue());
+ basegfx::B2DPolyPolygon aStartPolyPolygon;
+ basegfx::B2DPolyPolygon aEndPolyPolygon;
+ double fStartWidth(0.0);
+ double fEndWidth(0.0);
+ bool bStartActive(false);
+ bool bEndActive(false);
+ bool bStartCentered(true);
+ bool bEndCentered(true);
+
+ if(nTempStartWidth)
+ {
+ if(nTempStartWidth < 0)
+ {
+ fStartWidth = (static_cast<double>(-nTempStartWidth) * fWidth) * 0.01;
+ }
+ else
+ {
+ fStartWidth = static_cast<double>(nTempStartWidth);
+ }
+
+ if(0.0 != fStartWidth)
+ {
+ aStartPolyPolygon = rSet.Get(XATTR_LINESTART).GetLineStartValue();
+
+ if(aStartPolyPolygon.count() && aStartPolyPolygon.getB2DPolygon(0).count())
+ {
+ bStartActive = true;
+ bStartCentered = rSet.Get(XATTR_LINESTARTCENTER).GetValue();
+ }
+ }
+ }
+
+ if(nTempEndWidth)
+ {
+ if(nTempEndWidth < 0)
+ {
+ fEndWidth = (static_cast<double>(-nTempEndWidth) * fWidth) * 0.01;
+ }
+ else
+ {
+ fEndWidth = static_cast<double>(nTempEndWidth);
+ }
+
+ if(0.0 != fEndWidth)
+ {
+ aEndPolyPolygon = rSet.Get(XATTR_LINEEND).GetLineEndValue();
+
+ if(aEndPolyPolygon.count() && aEndPolyPolygon.getB2DPolygon(0).count())
+ {
+ bEndActive = true;
+ bEndCentered = rSet.Get(XATTR_LINEENDCENTER).GetValue();
+ }
+ }
+ }
+
+ if(bStartActive || bEndActive)
+ {
+ return attribute::SdrLineStartEndAttribute(
+ aStartPolyPolygon, aEndPolyPolygon, fStartWidth, fEndWidth,
+ bStartActive, bEndActive, bStartCentered, bEndCentered);
+ }
+
+ return attribute::SdrLineStartEndAttribute();
+ }
+
+ attribute::SdrShadowAttribute createNewSdrShadowAttribute(const SfxItemSet& rSet)
+ {
+ const bool bShadow(rSet.Get(SDRATTR_SHADOW).GetValue());
+
+ if(bShadow)
+ {
+ sal_uInt16 nTransparence(rSet.Get(SDRATTR_SHADOWTRANSPARENCE).GetValue());
+
+ if(nTransparence > 100)
+ {
+ nTransparence = 100;
+ }
+
+ if(nTransparence)
+ {
+ sal_uInt16 nFillTransparence(rSet.Get(XATTR_FILLTRANSPARENCE).GetValue());
+
+ if(nFillTransparence > 100)
+ {
+ nFillTransparence = 100;
+ }
+
+ if(nTransparence == nFillTransparence)
+ {
+ // shadow does not really have an own transparence, but the application
+ // sets the shadow transparence equal to the object transparence for
+ // convenience. This is not useful for primitive creation, so take
+ // this as no shadow transparence
+ nTransparence = 0;
+ }
+ }
+
+ if(100 != nTransparence)
+ {
+ const basegfx::B2DVector aOffset(
+ static_cast<double>(rSet.Get(SDRATTR_SHADOWXDIST).GetValue()),
+ static_cast<double>(rSet.Get(SDRATTR_SHADOWYDIST).GetValue()));
+
+ const basegfx::B2DVector aSize(
+ static_cast<double>(rSet.Get(SDRATTR_SHADOWSIZEX).GetValue()),
+ static_cast<double>(rSet.Get(SDRATTR_SHADOWSIZEY).GetValue()));
+
+ const Color aColor(rSet.Get(SDRATTR_SHADOWCOLOR).GetColorValue());
+
+ sal_Int32 nBlur(rSet.Get(SDRATTR_SHADOWBLUR).GetValue());
+
+ return attribute::SdrShadowAttribute(aOffset, aSize, static_cast<double>(nTransparence) * 0.01,nBlur, aColor.getBColor());
+ }
+ }
+
+ return attribute::SdrShadowAttribute();
+ }
+
+ attribute::SdrFillAttribute createNewSdrFillAttribute(const SfxItemSet& rSet)
+ {
+ const drawing::FillStyle eStyle(rSet.Get(XATTR_FILLSTYLE).GetValue());
+
+ sal_uInt16 nTransparence(rSet.Get(XATTR_FILLTRANSPARENCE).GetValue());
+
+ if(nTransparence > 100)
+ {
+ nTransparence = 100;
+ }
+
+ if(drawing::FillStyle_NONE == eStyle)
+ {
+ XFillUseSlideBackgroundItem aBckItem(rSet.Get(XATTR_FILLUSESLIDEBACKGROUND));
+ const bool bSlideBackgroundFill(aBckItem.GetValue());
+
+ if(bSlideBackgroundFill)
+ {
+ // we have SlideBackgroundFill mode, create a
+ // SdrFillAttribute accordingly
+ return attribute::SdrFillAttribute(true);
+ }
+ }
+
+ if(drawing::FillStyle_NONE != eStyle)
+ {
+ if(100 != nTransparence)
+ {
+ // need to check XFillFloatTransparence, object fill may still be completely transparent
+ const XFillFloatTransparenceItem* pGradientItem;
+
+ if((pGradientItem = rSet.GetItemIfSet(XATTR_FILLFLOATTRANSPARENCE, true))
+ && pGradientItem->IsEnabled())
+ {
+ const XGradient& rGradient = pGradientItem->GetGradientValue();
+ const sal_uInt8 nStartLuminance(rGradient.GetStartColor().GetLuminance());
+ const sal_uInt8 nEndLuminance(rGradient.GetEndColor().GetLuminance());
+ const bool bCompletelyTransparent(0xff == nStartLuminance && 0xff == nEndLuminance);
+
+ if(bCompletelyTransparent)
+ {
+ nTransparence = 100;
+ }
+ }
+ }
+
+ if(100 != nTransparence)
+ {
+ const Color aColor(rSet.Get(XATTR_FILLCOLOR).GetColorValue());
+ attribute::FillGradientAttribute aGradient;
+ attribute::FillHatchAttribute aHatch;
+ attribute::SdrFillGraphicAttribute aFillGraphic;
+
+ switch(eStyle)
+ {
+ default:
+ {
+ // nothing to do, color is defined
+ break;
+ }
+ case drawing::FillStyle_GRADIENT :
+ {
+ XGradient aXGradient(rSet.Get(XATTR_FILLGRADIENT).GetGradientValue());
+
+ const Color aStartColor(aXGradient.GetStartColor());
+ const sal_uInt16 nStartIntens(aXGradient.GetStartIntens());
+ basegfx::BColor aStart(aStartColor.getBColor());
+
+ if(nStartIntens != 100)
+ {
+ const basegfx::BColor aBlack;
+ aStart = interpolate(aBlack, aStart, static_cast<double>(nStartIntens) * 0.01);
+ }
+
+ const Color aEndColor(aXGradient.GetEndColor());
+ const sal_uInt16 nEndIntens(aXGradient.GetEndIntens());
+ basegfx::BColor aEnd(aEndColor.getBColor());
+
+ if(nEndIntens != 100)
+ {
+ const basegfx::BColor aBlack;
+ aEnd = interpolate(aBlack, aEnd, static_cast<double>(nEndIntens) * 0.01);
+ }
+
+ aGradient = attribute::FillGradientAttribute(
+ XGradientStyleToGradientStyle(aXGradient.GetGradientStyle()),
+ static_cast<double>(aXGradient.GetBorder()) * 0.01,
+ static_cast<double>(aXGradient.GetXOffset()) * 0.01,
+ static_cast<double>(aXGradient.GetYOffset()) * 0.01,
+ toRadians(aXGradient.GetAngle()),
+ aStart,
+ aEnd,
+ rSet.Get(XATTR_GRADIENTSTEPCOUNT).GetValue());
+
+ break;
+ }
+ case drawing::FillStyle_HATCH :
+ {
+ const XHatch& rHatch(rSet.Get(XATTR_FILLHATCH).GetHatchValue());
+ const Color aColorB(rHatch.GetColor());
+
+ aHatch = attribute::FillHatchAttribute(
+ XHatchStyleToHatchStyle(rHatch.GetHatchStyle()),
+ static_cast<double>(rHatch.GetDistance()),
+ toRadians(rHatch.GetAngle()),
+ aColorB.getBColor(),
+ 3, // same default as VCL, a minimum of three discrete units (pixels) offset
+ rSet.Get(XATTR_FILLBACKGROUND).GetValue());
+
+ break;
+ }
+ case drawing::FillStyle_BITMAP :
+ {
+ aFillGraphic = createNewSdrFillGraphicAttribute(rSet);
+ break;
+ }
+ }
+
+ return attribute::SdrFillAttribute(
+ static_cast<double>(nTransparence) * 0.01,
+ aColor.getBColor(),
+ aGradient,
+ aHatch,
+ aFillGraphic);
+ }
+ }
+
+ if(nTransparence == 100)
+ {
+ attribute::FillGradientAttribute aGradient;
+ attribute::FillHatchAttribute aHatch;
+ attribute::SdrFillGraphicAttribute aFillGraphic;
+ return attribute::SdrFillAttribute(
+ 1,
+ basegfx::BColor( 0, 0, 0 ),
+ aGradient,
+ aHatch,
+ aFillGraphic);
+ }
+
+ return attribute::SdrFillAttribute();
+ }
+
+ // #i101508# Support handing over given text-to-border distances
+ attribute::SdrTextAttribute createNewSdrTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText& rText,
+ const sal_Int32* pLeft,
+ const sal_Int32* pUpper,
+ const sal_Int32* pRight,
+ const sal_Int32* pLower)
+ {
+ const SdrTextObj& rTextObj = rText.GetObject();
+
+ // Save chaining attributes
+ bool bChainable = rTextObj.IsChainable();
+
+
+ if(rText.GetOutlinerParaObject())
+ {
+ // added TextEdit text suppression
+ bool bInEditMode(false);
+
+ if(rText.GetObject().getTextCount() > 1)
+ {
+ bInEditMode = rTextObj.IsInEditMode() && rText.GetObject().getActiveText() == &rText;
+ }
+ else
+ {
+ bInEditMode = rTextObj.IsInEditMode();
+ }
+
+ OutlinerParaObject aOutlinerParaObject(*rText.GetOutlinerParaObject());
+
+ if(bInEditMode)
+ {
+ std::optional<OutlinerParaObject> pTempObj = rTextObj.CreateEditOutlinerParaObject();
+
+ if(pTempObj)
+ {
+ aOutlinerParaObject = *pTempObj;
+ }
+ else
+ {
+ // #i100537#
+ // CreateEditOutlinerParaObject() returning no object does not mean that
+ // text edit mode is not active. Do not reset the flag here
+ // bInEditMode = false;
+ }
+ }
+
+ const SdrTextAniKind eAniKind(rTextObj.GetTextAniKind());
+
+ // #i107346#
+ const SdrOutliner& rDrawTextOutliner(rText.GetObject().getSdrModelFromSdrObject().GetDrawOutliner(&rTextObj));
+ const bool bWrongSpell(rDrawTextOutliner.GetControlWord() & EEControlBits::ONLINESPELLING);
+
+ return attribute::SdrTextAttribute(
+ rText,
+ aOutlinerParaObject,
+ rSet.Get(XATTR_FORMTXTSTYLE).GetValue(),
+ pLeft ? *pLeft : rTextObj.GetTextLeftDistance(),
+ pUpper ? *pUpper : rTextObj.GetTextUpperDistance(),
+ pRight ? *pRight : rTextObj.GetTextRightDistance(),
+ pLower ? *pLower : rTextObj.GetTextLowerDistance(),
+ rTextObj.GetTextHorizontalAdjust(rSet),
+ rTextObj.GetTextVerticalAdjust(rSet),
+ rSet.Get(SDRATTR_TEXT_CONTOURFRAME).GetValue(),
+ rTextObj.IsFitToSize(),
+ rTextObj.IsAutoFit(),
+ rSet.Get(XATTR_FORMTXTHIDEFORM).GetValue(),
+ SdrTextAniKind::Blink == eAniKind,
+ SdrTextAniKind::Scroll == eAniKind || SdrTextAniKind::Alternate == eAniKind || SdrTextAniKind::Slide == eAniKind,
+ bInEditMode,
+ rSet.Get(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue(),
+ bWrongSpell,
+ bChainable);
+ }
+
+ return attribute::SdrTextAttribute();
+ }
+
+ attribute::FillGradientAttribute createNewTransparenceGradientAttribute(const SfxItemSet& rSet)
+ {
+ const XFillFloatTransparenceItem* pGradientItem;
+
+ if((pGradientItem = rSet.GetItemIfSet(XATTR_FILLFLOATTRANSPARENCE))
+ && pGradientItem->IsEnabled())
+ {
+ // test if float transparence is completely transparent
+ const XGradient& rGradient = pGradientItem->GetGradientValue();
+ const sal_uInt8 nStartLuminance(rGradient.GetStartColor().GetLuminance());
+ const sal_uInt8 nEndLuminance(rGradient.GetEndColor().GetLuminance());
+ const bool bCompletelyTransparent(0xff == nStartLuminance && 0xff == nEndLuminance);
+ const bool bNotTransparent(0x00 == nStartLuminance && 0x00 == nEndLuminance);
+
+ // create nothing when completely transparent: This case is already checked for the
+ // normal fill attributes, XFILL_NONE will be used.
+ // create nothing when not transparent: use normal fill, no need t create a FillGradientAttribute.
+ // Both cases are optimizations, always creating FillGradientAttribute will work, too
+ if(!bNotTransparent && !bCompletelyTransparent)
+ {
+ const double fStartLum(nStartLuminance / 255.0);
+ const double fEndLum(nEndLuminance / 255.0);
+
+ return attribute::FillGradientAttribute(
+ XGradientStyleToGradientStyle(rGradient.GetGradientStyle()),
+ static_cast<double>(rGradient.GetBorder()) * 0.01,
+ static_cast<double>(rGradient.GetXOffset()) * 0.01,
+ static_cast<double>(rGradient.GetYOffset()) * 0.01,
+ toRadians(rGradient.GetAngle()),
+ basegfx::BColor(fStartLum, fStartLum, fStartLum),
+ basegfx::BColor(fEndLum, fEndLum, fEndLum));
+ }
+ }
+
+ return attribute::FillGradientAttribute();
+ }
+
+ attribute::SdrFillGraphicAttribute createNewSdrFillGraphicAttribute(const SfxItemSet& rSet)
+ {
+ Graphic aGraphic(rSet.Get(XATTR_FILLBITMAP).GetGraphicObject().GetGraphic());
+
+ OUString aOriginURL = aGraphic.getOriginURL();
+ if (aGraphic.GetType() == GraphicType::Default && !aOriginURL.isEmpty())
+ {
+ aGraphic = vcl::graphic::loadFromURL(aGraphic.getOriginURL());
+ aGraphic.setOriginURL(aOriginURL);
+ }
+
+ if(GraphicType::Bitmap != aGraphic.GetType() && GraphicType::GdiMetafile != aGraphic.GetType())
+ {
+ // no content if not bitmap or metafile
+ OSL_ENSURE(false, "No fill graphic in SfxItemSet (!)");
+ return attribute::SdrFillGraphicAttribute();
+ }
+
+ Size aPrefSize(aGraphic.GetPrefSize());
+
+ if(!aPrefSize.Width() || !aPrefSize.Height())
+ {
+ // if there is no logical size, create a size from pixel size and set MapMode accordingly
+ if(GraphicType::Bitmap == aGraphic.GetType())
+ {
+ aGraphic.SetPrefSize(aGraphic.GetBitmapEx().GetSizePixel());
+ aGraphic.SetPrefMapMode(MapMode(MapUnit::MapPixel));
+ aPrefSize = aGraphic.GetPrefSize();
+ }
+ }
+
+ if(!aPrefSize.Width() || !aPrefSize.Height())
+ {
+ // no content if no size
+ OSL_ENSURE(false, "Graphic has no size in SfxItemSet (!)");
+ return attribute::SdrFillGraphicAttribute();
+ }
+
+ // convert size and MapMode to destination logical size and MapMode
+ const MapUnit aDestinationMapUnit(rSet.GetPool()->GetMetric(0));
+ basegfx::B2DVector aGraphicLogicSize(aGraphic.GetPrefSize().Width(), aGraphic.GetPrefSize().Height());
+
+ if (aGraphic.GetPrefMapMode().GetMapUnit() != aDestinationMapUnit)
+ {
+ // #i100360# for MapUnit::MapPixel, LogicToLogic will not work properly,
+ // so fallback to Application::GetDefaultDevice()
+ Size aNewSize(0, 0);
+
+ if(MapUnit::MapPixel == aGraphic.GetPrefMapMode().GetMapUnit())
+ {
+ aNewSize = Application::GetDefaultDevice()->PixelToLogic(
+ aGraphic.GetPrefSize(),
+ MapMode(aDestinationMapUnit));
+ }
+ else
+ {
+ aNewSize = OutputDevice::LogicToLogic(
+ aGraphic.GetPrefSize(),
+ aGraphic.GetPrefMapMode(),
+ MapMode(aDestinationMapUnit));
+ }
+
+ // #i124002# do not set new size using SetPrefSize at the graphic, this will lead to problems.
+ // Instead, adapt the GraphicLogicSize which will be used for further decompositions
+ aGraphicLogicSize = basegfx::B2DVector(aNewSize.Width(), aNewSize.Height());
+ }
+
+ // get size
+ const basegfx::B2DVector aSize(
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_SIZEX).GetValue()),
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_SIZEY).GetValue()));
+ const basegfx::B2DVector aOffset(
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_TILEOFFSETX).GetValue()),
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_TILEOFFSETY).GetValue()));
+ const basegfx::B2DVector aOffsetPosition(
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_POSOFFSETX).GetValue()),
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_POSOFFSETY).GetValue()));
+
+ return attribute::SdrFillGraphicAttribute(
+ aGraphic,
+ aGraphicLogicSize,
+ aSize,
+ aOffset,
+ aOffsetPosition,
+ RectPointToB2DVector(rSet.GetItem<XFillBmpPosItem>(XATTR_FILLBMP_POS)->GetValue()),
+ rSet.Get(XATTR_FILLBMP_TILE).GetValue(),
+ rSet.Get(XATTR_FILLBMP_STRETCH).GetValue(),
+ rSet.Get(XATTR_FILLBMP_SIZELOG).GetValue());
+ }
+
+ attribute::SdrEffectsTextAttribute createNewSdrEffectsTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText,
+ bool bSuppressText)
+ {
+ attribute::SdrTextAttribute aText;
+
+ // #i98072# added option to suppress text
+ // look for text first
+ if(!bSuppressText && pText)
+ {
+ aText = createNewSdrTextAttribute(rSet, *pText);
+ }
+
+ // try shadow
+ const attribute::SdrShadowAttribute aShadow(createNewSdrShadowAttribute(rSet));
+ const attribute::SdrGlowAttribute aGlow(createNewSdrGlowAttribute(rSet));
+ const sal_Int32 nSoftEdgeRadius(getSoftEdgeRadius(rSet));
+
+ return attribute::SdrEffectsTextAttribute(aShadow, aText, aGlow, nSoftEdgeRadius);
+ }
+
+ attribute::SdrLineEffectsTextAttribute createNewSdrLineEffectsTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText)
+ {
+ attribute::SdrLineAttribute aLine;
+ attribute::SdrLineStartEndAttribute aLineStartEnd;
+ attribute::SdrTextAttribute aText;
+ bool bFontworkHideContour(false);
+
+ // look for text first
+ if(pText)
+ {
+ aText = createNewSdrTextAttribute(rSet, *pText);
+
+ // when object has text and text is fontwork and hide contour is set for fontwork, force
+ // line and fill style to empty
+ if(!aText.isDefault()
+ && !aText.getSdrFormTextAttribute().isDefault()
+ && aText.isHideContour())
+ {
+ bFontworkHideContour = true;
+ }
+ }
+
+ // try line style
+ if(!bFontworkHideContour)
+ {
+ aLine = createNewSdrLineAttribute(rSet);
+
+ if(!aLine.isDefault())
+ {
+ // try LineStartEnd
+ aLineStartEnd = createNewSdrLineStartEndAttribute(rSet, aLine.getWidth());
+ }
+ }
+
+ if(!aLine.isDefault() || !aText.isDefault())
+ {
+ // try shadow
+ const attribute::SdrShadowAttribute aShadow(createNewSdrShadowAttribute(rSet));
+ const attribute::SdrGlowAttribute aGlow = createNewSdrGlowAttribute(rSet);
+ const sal_Int32 nSoftEdgeRadius(getSoftEdgeRadius(rSet));
+
+ return attribute::SdrLineEffectsTextAttribute(aLine, aLineStartEnd, aShadow, aText,
+ aGlow, nSoftEdgeRadius);
+ }
+
+ return attribute::SdrLineEffectsTextAttribute();
+ }
+
+ attribute::SdrLineFillEffectsTextAttribute createNewSdrLineFillEffectsTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText,
+ bool bHasContent)
+ {
+ attribute::SdrLineAttribute aLine;
+ attribute::SdrFillAttribute aFill;
+ attribute::SdrLineStartEndAttribute aLineStartEnd;
+ attribute::FillGradientAttribute aFillFloatTransGradient;
+ attribute::SdrTextAttribute aText;
+ bool bFontworkHideContour(false);
+
+ // look for text first
+ if(pText)
+ {
+ aText = createNewSdrTextAttribute(rSet, *pText);
+
+ // when object has text and text is fontwork and hide contour is set for fontwork, force
+ // line and fill style to empty
+ if(!aText.getSdrFormTextAttribute().isDefault() && aText.isHideContour())
+ {
+ bFontworkHideContour = true;
+ }
+ }
+
+ if(!bFontworkHideContour)
+ {
+ // try line style
+ aLine = createNewSdrLineAttribute(rSet);
+
+ if(!aLine.isDefault())
+ {
+ // try LineStartEnd
+ aLineStartEnd = createNewSdrLineStartEndAttribute(rSet, aLine.getWidth());
+ }
+
+ // try fill style
+ aFill = createNewSdrFillAttribute(rSet);
+
+ if(!aFill.isDefault())
+ {
+ // try fillfloattransparence
+ aFillFloatTransGradient = createNewTransparenceGradientAttribute(rSet);
+ }
+ }
+
+ // bHasContent is used from OLE and graphic objects. Normally a possible shadow
+ // depends on line, fill or text to be set, but for these objects it is possible
+ // to have none of these, but still content which needs to have a shadow (if set),
+ // so shadow needs to be tried
+ if(bHasContent || !aLine.isDefault() || !aFill.isDefault() || !aText.isDefault())
+ {
+ // try shadow
+ const attribute::SdrShadowAttribute aShadow = createNewSdrShadowAttribute(rSet);
+
+ // glow
+ const attribute::SdrGlowAttribute aGlow = createNewSdrGlowAttribute(rSet);
+
+ const sal_Int32 nSoftEdgeRadius(getSoftEdgeRadius(rSet));
+
+ return attribute::SdrLineFillEffectsTextAttribute(aLine, aFill, aLineStartEnd,
+ aShadow, aFillFloatTransGradient,
+ aText, aGlow, nSoftEdgeRadius);
+ }
+
+ return attribute::SdrLineFillEffectsTextAttribute();
+ }
+
+ attribute::SdrLineFillShadowAttribute3D createNewSdrLineFillShadowAttribute(const SfxItemSet& rSet, bool bSuppressFill)
+ {
+ attribute::SdrFillAttribute aFill;
+ attribute::SdrLineStartEndAttribute aLineStartEnd;
+ attribute::SdrShadowAttribute aShadow;
+ attribute::FillGradientAttribute aFillFloatTransGradient;
+
+ // try line style
+ const attribute::SdrLineAttribute aLine(createNewSdrLineAttribute(rSet));
+
+ if(!aLine.isDefault())
+ {
+ // try LineStartEnd
+ aLineStartEnd = createNewSdrLineStartEndAttribute(rSet, aLine.getWidth());
+ }
+
+ // try fill style
+ if(!bSuppressFill)
+ {
+ aFill = createNewSdrFillAttribute(rSet);
+
+ if(!aFill.isDefault())
+ {
+ // try fillfloattransparence
+ aFillFloatTransGradient = createNewTransparenceGradientAttribute(rSet);
+ }
+ }
+
+ if(!aLine.isDefault() || !aFill.isDefault())
+ {
+ // try shadow
+ aShadow = createNewSdrShadowAttribute(rSet);
+
+ return attribute::SdrLineFillShadowAttribute3D(
+ aLine, aFill, aLineStartEnd, aShadow, aFillFloatTransGradient);
+ }
+
+ return attribute::SdrLineFillShadowAttribute3D();
+ }
+
+ attribute::SdrSceneAttribute createNewSdrSceneAttribute(const SfxItemSet& rSet)
+ {
+ // get perspective
+ css::drawing::ProjectionMode aProjectionMode(css::drawing::ProjectionMode_PARALLEL);
+ const sal_uInt16 nProjectionValue(rSet.Get(SDRATTR_3DSCENE_PERSPECTIVE).GetValue());
+
+ if(1 == nProjectionValue)
+ {
+ aProjectionMode = css::drawing::ProjectionMode_PERSPECTIVE;
+ }
+
+ // get distance
+ const double fDistance(rSet.Get(SDRATTR_3DSCENE_DISTANCE).GetValue());
+
+ // get shadow slant
+ const double fShadowSlant(
+ basegfx::deg2rad(rSet.Get(SDRATTR_3DSCENE_SHADOW_SLANT).GetValue()));
+
+ // get shade mode
+ css::drawing::ShadeMode aShadeMode(css::drawing::ShadeMode_FLAT);
+ const sal_uInt16 nShadeValue(rSet.Get(SDRATTR_3DSCENE_SHADE_MODE).GetValue());
+
+ if(1 == nShadeValue)
+ {
+ aShadeMode = css::drawing::ShadeMode_PHONG;
+ }
+ else if(2 == nShadeValue)
+ {
+ aShadeMode = css::drawing::ShadeMode_SMOOTH;
+ }
+ else if(3 == nShadeValue)
+ {
+ aShadeMode = css::drawing::ShadeMode_DRAFT;
+ }
+
+ // get two sided lighting
+ const bool bTwoSidedLighting(rSet.Get(SDRATTR_3DSCENE_TWO_SIDED_LIGHTING).GetValue());
+
+ return attribute::SdrSceneAttribute(fDistance, fShadowSlant, aProjectionMode, aShadeMode, bTwoSidedLighting);
+ }
+
+ attribute::SdrLightingAttribute createNewSdrLightingAttribute(const SfxItemSet& rSet)
+ {
+ // extract lights from given SfxItemSet (from scene)
+ ::std::vector< attribute::Sdr3DLightAttribute > aLightVector;
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_1).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_1).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_1).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, true);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_2).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_2).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_2).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_3).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_3).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_3).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_4).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_4).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_4).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_5).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_5).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_5).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_6).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_6).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_6).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_7).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_7).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_7).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_8).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_8).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_8).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ // get ambient color
+ const Color aAmbientValue(rSet.Get(SDRATTR_3DSCENE_AMBIENTCOLOR).GetValue());
+ const basegfx::BColor aAmbientLight(aAmbientValue.getBColor());
+
+ return attribute::SdrLightingAttribute(aAmbientLight, std::move(aLightVector));
+ }
+
+ void calculateRelativeCornerRadius(sal_Int32 nRadius, const basegfx::B2DRange& rObjectRange, double& rfCornerRadiusX, double& rfCornerRadiusY)
+ {
+ rfCornerRadiusX = rfCornerRadiusY = static_cast<double>(nRadius);
+
+ if(0.0 != rfCornerRadiusX)
+ {
+ const double fHalfObjectWidth(rObjectRange.getWidth() * 0.5);
+
+ if(0.0 != fHalfObjectWidth)
+ {
+ if(rfCornerRadiusX < 0.0)
+ {
+ rfCornerRadiusX = 0.0;
+ }
+
+ if(rfCornerRadiusX > fHalfObjectWidth)
+ {
+ rfCornerRadiusX = fHalfObjectWidth;
+ }
+
+ rfCornerRadiusX /= fHalfObjectWidth;
+ }
+ else
+ {
+ rfCornerRadiusX = 0.0;
+ }
+ }
+
+ if(0.0 == rfCornerRadiusY)
+ return;
+
+ const double fHalfObjectHeight(rObjectRange.getHeight() * 0.5);
+
+ if(0.0 != fHalfObjectHeight)
+ {
+ if(rfCornerRadiusY < 0.0)
+ {
+ rfCornerRadiusY = 0.0;
+ }
+
+ if(rfCornerRadiusY > fHalfObjectHeight)
+ {
+ rfCornerRadiusY = fHalfObjectHeight;
+ }
+
+ rfCornerRadiusY /= fHalfObjectHeight;
+ }
+ else
+ {
+ rfCornerRadiusY = 0.0;
+ }
+ }
+
+ // #i101508# Support handing over given text-to-border distances
+ attribute::SdrFillTextAttribute createNewSdrFillTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText,
+ const sal_Int32* pLeft,
+ const sal_Int32* pUpper,
+ const sal_Int32* pRight,
+ const sal_Int32* pLower)
+ {
+ attribute::SdrFillAttribute aFill;
+ attribute::FillGradientAttribute aFillFloatTransGradient;
+ attribute::SdrTextAttribute aText;
+ bool bFontworkHideContour(false);
+
+ // look for text first
+ if(pText)
+ {
+ aText = createNewSdrTextAttribute(rSet, *pText, pLeft, pUpper, pRight, pLower);
+
+ // when object has text and text is fontwork and hide contour is set for fontwork, force
+ // fill style to empty
+ if(!aText.getSdrFormTextAttribute().isDefault() && aText.isHideContour())
+ {
+ bFontworkHideContour = true;
+ }
+ }
+
+ if(!bFontworkHideContour)
+ {
+ // try fill style
+ aFill = createNewSdrFillAttribute(rSet);
+
+ if(!aFill.isDefault())
+ {
+ // try fillfloattransparence
+ aFillFloatTransGradient = createNewTransparenceGradientAttribute(rSet);
+ }
+ }
+
+ if(!aFill.isDefault() || !aText.isDefault())
+ {
+ return attribute::SdrFillTextAttribute(aFill, aFillFloatTransGradient, aText);
+ }
+
+ return attribute::SdrFillTextAttribute();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrcaptionprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrcaptionprimitive2d.cxx
new file mode 100644
index 000000000..50787ed39
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrcaptionprimitive2d.cxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrcaptionprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrCaptionPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ const basegfx::B2DPolygon aUnitOutline(basegfx::utils::createPolygonFromRect(
+ basegfx::B2DRange(0.0, 0.0, 1.0, 1.0),
+ getCornerRadiusX(),
+ getCornerRadiusY()));
+
+ // add fill
+ if(getSdrLFSTAttribute().getFill().isDefault())
+ {
+ // create invisible fill for HitTest
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ true,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+ else
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+
+ // add line
+ if(getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // create invisible line for HitTest/BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(getTail()),
+ {}));
+ }
+ else
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ getTail(),
+ getSdrLFSTAttribute().getLine(),
+ getSdrLFSTAttribute().getLineStartEnd()));
+ }
+
+ // add text
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(std::move(aRetval), getSdrLFSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrCaptionPrimitive2D::SdrCaptionPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ const basegfx::B2DPolygon& rTail,
+ double fCornerRadiusX,
+ double fCornerRadiusY)
+ : maTransform(rTransform),
+ maSdrLFSTAttribute(rSdrLFSTAttribute),
+ maTail(rTail),
+ mfCornerRadiusX(fCornerRadiusX),
+ mfCornerRadiusY(fCornerRadiusY)
+ {
+ }
+
+ bool SdrCaptionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrCaptionPrimitive2D& rCompare = static_cast<const SdrCaptionPrimitive2D&>(rPrimitive);
+
+ return (getCornerRadiusX() == rCompare.getCornerRadiusX()
+ && getCornerRadiusY() == rCompare.getCornerRadiusY()
+ && getTail() == rCompare.getTail()
+ && getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrCaptionPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCAPTIONPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrconnectorprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrconnectorprimitive2d.cxx
new file mode 100644
index 000000000..aa663fb7a
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrconnectorprimitive2d.cxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrconnectorprimitive2d.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrConnectorPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // add line
+ if(getSdrLSTAttribute().getLine().isDefault())
+ {
+ // create invisible line for HitTest/BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ basegfx::B2DPolyPolygon(getUnitPolygon())));
+ }
+ else
+ {
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ getUnitPolygon(),
+ getSdrLSTAttribute().getLine(),
+ getSdrLSTAttribute().getLineStartEnd()));
+ }
+
+ // add text
+ if(!getSdrLSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(getUnitPolygon()),
+ basegfx::B2DHomMatrix(),
+ getSdrLSTAttribute().getText(),
+ getSdrLSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrConnectorPrimitive2D::SdrConnectorPrimitive2D(
+ const attribute::SdrLineEffectsTextAttribute& rSdrLSTAttribute,
+ const ::basegfx::B2DPolygon& rUnitPolygon)
+ : maSdrLSTAttribute(rSdrLSTAttribute),
+ maUnitPolygon(rUnitPolygon)
+ {
+ }
+
+ bool SdrConnectorPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrConnectorPrimitive2D& rCompare = static_cast<const SdrConnectorPrimitive2D&>(rPrimitive);
+
+ return (getUnitPolygon() == rCompare.getUnitPolygon()
+ && getSdrLSTAttribute() == rCompare.getSdrLSTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrConnectorPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCONNECTORPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx
new file mode 100644
index 000000000..dddb8aa30
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrcustomshapeprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/attribute/sdrlineattribute.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrCustomShapePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval(getSubPrimitives());
+
+ // Soft edges should be before text, since text is not affected by soft edges
+ if (!aRetval.empty() && getSdrSTAttribute().getSoftEdgeRadius())
+ {
+ aRetval = createEmbeddedSoftEdgePrimitive(std::move(aRetval),
+ getSdrSTAttribute().getSoftEdgeRadius());
+ }
+
+ // add text
+ if(!getSdrSTAttribute().getText().isDefault())
+ {
+ const basegfx::B2DPolygon& aUnitOutline(basegfx::utils::createUnitPolygon());
+
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTextBox(),
+ getSdrSTAttribute().getText(),
+ attribute::SdrLineAttribute(),
+ false,
+ getWordWrap()));
+ }
+
+ // tdf#132199: put glow before shadow, to have shadow of the glow, not the opposite
+ if (!aRetval.empty() && !getSdrSTAttribute().getGlow().isDefault())
+ {
+ // glow
+ aRetval = createEmbeddedGlowPrimitive(std::move(aRetval), getSdrSTAttribute().getGlow());
+ }
+
+ // add shadow
+ if(!aRetval.empty() && !getSdrSTAttribute().getShadow().isDefault())
+ {
+ // #i105323# add generic shadow only for 2D shapes. For
+ // 3D shapes shadow will be set at the individual created
+ // visualisation objects and be visualized by the 3d renderer
+ // as a single shadow.
+
+ // The shadow for AutoShapes could be handled uniformly by not setting any
+ // shadow items at the helper model objects and only adding shadow here for
+ // 2D and 3D (and it works, too), but this would lead to two 3D scenes for
+ // the 3D object; one for the shadow and one for the content. The one for the
+ // shadow will be correct (using ColorModifierStack), but expensive.
+ if(!get3DShape())
+ {
+ aRetval = createEmbeddedShadowPrimitive(std::move(aRetval), getSdrSTAttribute().getShadow(),
+ maTransform);
+ }
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrCustomShapePrimitive2D::SdrCustomShapePrimitive2D(
+ const attribute::SdrEffectsTextAttribute& rSdrSTAttribute,
+ Primitive2DContainer&& rSubPrimitives,
+ const basegfx::B2DHomMatrix& rTextBox,
+ bool bWordWrap,
+ bool b3DShape,
+ const basegfx::B2DHomMatrix& rTransform)
+ : maSdrSTAttribute(rSdrSTAttribute),
+ maSubPrimitives(std::move(rSubPrimitives)),
+ maTextBox(rTextBox),
+ mbWordWrap(bWordWrap),
+ mb3DShape(b3DShape),
+ maTransform(rTransform)
+ {
+ }
+
+ bool SdrCustomShapePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrCustomShapePrimitive2D& rCompare = static_cast<const SdrCustomShapePrimitive2D&>(rPrimitive);
+
+ return (getSdrSTAttribute() == rCompare.getSdrSTAttribute()
+ && getSubPrimitives() == rCompare.getSubPrimitives()
+ && getTextBox() == rCompare.getTextBox()
+ && getWordWrap() == rCompare.getWordWrap()
+ && get3DShape() == rCompare.get3DShape());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrCustomShapePrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCUSTOMSHAPEPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
new file mode 100644
index 000000000..a1838b03f
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
@@ -0,0 +1,884 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
+#include <drawinglayer/primitive2d/PolygonStrokeArrowPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHatchPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonGraphicPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/softedgeprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+#include <drawinglayer/attribute/linestartendattribute.hxx>
+#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <drawinglayer/primitive2d/glowprimitive2d.hxx>
+#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <svx/svdotext.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
+#include <drawinglayer/animation/animationtiming.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
+#include <drawinglayer/attribute/sdrfillattribute.hxx>
+#include <drawinglayer/attribute/sdrlineattribute.hxx>
+#include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
+#include <drawinglayer/attribute/sdrshadowattribute.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
+#include <osl/diagnose.h>
+
+// for SlideBackgroundFillPrimitive2D
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svdpage.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/contact/viewcontactofmasterpagedescriptor.hxx>
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+namespace
+{
+// See also: SdrTextObj::AdjustRectToTextDistance
+basegfx::B2DRange getTextAnchorRange(const attribute::SdrTextAttribute& rText,
+ const basegfx::B2DRange& rSnapRange)
+{
+ // Take vertical text orientation into account when deciding
+ // which dimension is its width, and which is its height
+ const OutlinerParaObject& rOutlinerParaObj = rText.getOutlinerParaObject();
+ const bool bVerticalWriting(rOutlinerParaObj.IsEffectivelyVertical());
+ const double fWidthForText = bVerticalWriting ? rSnapRange.getHeight() : rSnapRange.getWidth();
+ // create a range describing the wanted text position and size (aTextAnchorRange). This
+ // means to use the text distance values here
+ // If the margin is larger than the entire width of the text area, then limit the
+ // margin.
+ const double fTextLeftDistance
+ = std::min(static_cast<double>(rText.getTextLeftDistance()), fWidthForText);
+ const double nTextRightDistance
+ = std::min(static_cast<double>(rText.getTextRightDistance()), fWidthForText);
+ double fDistanceForTextL, fDistanceForTextT, fDistanceForTextR, fDistanceForTextB;
+ if (!bVerticalWriting)
+ {
+ fDistanceForTextL = fTextLeftDistance;
+ fDistanceForTextT = rText.getTextUpperDistance();
+ fDistanceForTextR = nTextRightDistance;
+ fDistanceForTextB = rText.getTextLowerDistance();
+ }
+ else if (rOutlinerParaObj.IsTopToBottom())
+ {
+ fDistanceForTextL = rText.getTextLowerDistance();
+ fDistanceForTextT = fTextLeftDistance;
+ fDistanceForTextR = rText.getTextUpperDistance();
+ fDistanceForTextB = nTextRightDistance;
+ }
+ else
+ {
+ fDistanceForTextL = rText.getTextUpperDistance();
+ fDistanceForTextT = nTextRightDistance;
+ fDistanceForTextR = rText.getTextLowerDistance();
+ fDistanceForTextB = fTextLeftDistance;
+ }
+ const basegfx::B2DPoint aTopLeft(rSnapRange.getMinX() + fDistanceForTextL,
+ rSnapRange.getMinY() + fDistanceForTextT);
+ const basegfx::B2DPoint aBottomRight(rSnapRange.getMaxX() - fDistanceForTextR,
+ rSnapRange.getMaxY() - fDistanceForTextB);
+ basegfx::B2DRange aAnchorRange;
+ aAnchorRange.expand(aTopLeft);
+ aAnchorRange.expand(aBottomRight);
+
+ // If the shape has no width, then don't attempt to break the text into multiple
+ // lines, not a single character would satisfy a zero width requirement.
+ // SdrTextObj::impDecomposeBlockTextPrimitive() uses the same constant to
+ // effectively set no limits.
+ if (!bVerticalWriting && aAnchorRange.getWidth() == 0)
+ {
+ aAnchorRange.expand(basegfx::B2DPoint(aTopLeft.getX() - 1000000, aTopLeft.getY()));
+ aAnchorRange.expand(basegfx::B2DPoint(aBottomRight.getX() + 1000000, aBottomRight.getY()));
+ }
+ else if (bVerticalWriting && aAnchorRange.getHeight() == 0)
+ {
+ aAnchorRange.expand(basegfx::B2DPoint(aTopLeft.getX(), aTopLeft.getY() - 1000000));
+ aAnchorRange.expand(basegfx::B2DPoint(aBottomRight.getX(), aBottomRight.getY() + 1000000));
+ }
+ return aAnchorRange;
+}
+
+drawinglayer::attribute::SdrFillAttribute getMasterPageFillAttribute(
+ const geometry::ViewInformation2D& rViewInformation,
+ basegfx::B2DVector& rPageSize)
+{
+ drawinglayer::attribute::SdrFillAttribute aRetval;
+
+ // get SdrPage
+ const SdrPage* pVisualizedPage(GetSdrPageFromXDrawPage(rViewInformation.getVisualizedPage()));
+
+ if(nullptr != pVisualizedPage)
+ {
+ // copy needed values for further processing
+ rPageSize.setX(pVisualizedPage->GetWidth());
+ rPageSize.setY(pVisualizedPage->GetHeight());
+
+ if(pVisualizedPage->IsMasterPage())
+ {
+ // the page is a MasterPage, so we are in MasterPage view
+ // still need #i110846#, see ViewContactOfMasterPage
+ if(pVisualizedPage->getSdrPageProperties().GetStyleSheet())
+ {
+ // create page fill attributes with correct properties
+ aRetval = drawinglayer::primitive2d::createNewSdrFillAttribute(
+ pVisualizedPage->getSdrPageProperties().GetItemSet());
+ }
+ }
+ else
+ {
+ // the page is *no* MasterPage, we are in normal Page view, get the MasterPage
+ if(pVisualizedPage->TRG_HasMasterPage())
+ {
+ sdr::contact::ViewContact& rVC(pVisualizedPage->TRG_GetMasterPageDescriptorViewContact());
+ sdr::contact::ViewContactOfMasterPageDescriptor* pVCOMPD(
+ dynamic_cast<sdr::contact::ViewContactOfMasterPageDescriptor*>(&rVC));
+
+ if(nullptr != pVCOMPD)
+ {
+ // in this case the still needed #i110846# is part of
+ // getCorrectSdrPageProperties, that's the main reason to re-use
+ // that call/functionality here
+ const SdrPageProperties* pCorrectProperties(
+ pVCOMPD->GetMasterPageDescriptor().getCorrectSdrPageProperties());
+
+ if(pCorrectProperties)
+ {
+ // create page fill attributes when correct properties were identified
+ aRetval = drawinglayer::primitive2d::createNewSdrFillAttribute(
+ pCorrectProperties->GetItemSet());
+ }
+ }
+ }
+ }
+ }
+
+ return aRetval;
+}
+
+// provide a Primitive2D for the SlideBackgroundFill-mode. It is capable
+// of expressing that state of fill and it's decomposition implements all
+// needed preparation of the geometry in an isolated and controllable
+// space and way.
+// It is currently simple buffered (due to being derived from
+// BufferedDecompositionPrimitive2D) and detects if FillStyle changes
+class SlideBackgroundFillPrimitive2D final : public BufferedDecompositionPrimitive2D
+{
+private:
+ /// the basegfx::B2DPolyPolygon geometry
+ basegfx::B2DPolyPolygon maPolyPolygon;
+
+ /// the last SdrFillAttribute the geometry was created for
+ drawinglayer::attribute::SdrFillAttribute maLastFill;
+
+protected:
+ // create decomposition data
+ virtual void create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ const geometry::ViewInformation2D& rViewInformation) const override;
+
+public:
+ /// constructor
+ SlideBackgroundFillPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon);
+
+ /// check existing decomposition data, call parent
+ virtual void get2DDecomposition(
+ Primitive2DDecompositionVisitor& rVisitor,
+ const geometry::ViewInformation2D& rViewInformation) const override;
+
+ /// data read access
+ const basegfx::B2DPolyPolygon& getB2DPolyPolygon() const { return maPolyPolygon; }
+
+ /// compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ /// get range
+ virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
+
+ /// provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+};
+
+SlideBackgroundFillPrimitive2D::SlideBackgroundFillPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon)
+: BufferedDecompositionPrimitive2D()
+, maPolyPolygon(rPolyPolygon)
+, maLastFill()
+{
+}
+
+void SlideBackgroundFillPrimitive2D::create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ const geometry::ViewInformation2D& rViewInformation) const
+{
+ basegfx::B2DVector aPageSize;
+
+ // get fill from target Page, this will check for all needed things
+ // like MasterPage/relationships, etc. (see getMasterPageFillAttribute impl above)
+ drawinglayer::attribute::SdrFillAttribute aFill(
+ getMasterPageFillAttribute(rViewInformation, aPageSize));
+
+ // if fill is on default (empty), nothing will be shown, we are done
+ if(aFill.isDefault())
+ return;
+
+ // Get PolygonRange of own local geometry
+ const basegfx::B2DRange aPolygonRange(getB2DPolyPolygon().getB2DRange());
+
+ // if local geometry is empty, nothing will be shown, we are done
+ if(aPolygonRange.isEmpty())
+ return;
+
+ // Get PageRange
+ const basegfx::B2DRange aPageRange(0.0, 0.0, aPageSize.getX(), aPageSize.getY());
+
+ // if local geometry does not overlap with PageRange, nothing will be shown, we are done
+ if(!aPageRange.overlaps(aPolygonRange))
+ return;
+
+ // create FillPrimitive2D with the geometry (the PolyPolygon) and
+ // the page's definitonRange to:
+ // - on one hand limit to geometry
+ // - on the other hand allow continutation of fill outside of
+ // MasterPage's range
+ const attribute::FillGradientAttribute aEmptyFillTransparenceGradient;
+ const Primitive2DReference aCreatedFill(
+ createPolyPolygonFillPrimitive(
+ getB2DPolyPolygon(), // geometry
+ aPageRange, // definition range
+ aFill,
+ aEmptyFillTransparenceGradient));
+
+ rContainer = Primitive2DContainer { aCreatedFill };
+}
+
+void SlideBackgroundFillPrimitive2D::get2DDecomposition(
+ Primitive2DDecompositionVisitor& rVisitor,
+ const geometry::ViewInformation2D& rViewInformation) const
+{
+ basegfx::B2DVector aPageSize;
+ drawinglayer::attribute::SdrFillAttribute aFill;
+
+ if(!getBuffered2DDecomposition().empty())
+ {
+ aFill = getMasterPageFillAttribute(rViewInformation, aPageSize);
+
+ if(!(aFill == maLastFill))
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< SlideBackgroundFillPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
+ }
+ }
+
+ if(getBuffered2DDecomposition().empty())
+ {
+ // remember last Fill
+ const_cast< SlideBackgroundFillPrimitive2D* >(this)->maLastFill = aFill;
+ }
+
+ // use parent implementation
+ BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
+}
+
+bool SlideBackgroundFillPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+{
+ if (BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SlideBackgroundFillPrimitive2D& rCompare
+ = static_cast<const SlideBackgroundFillPrimitive2D&>(rPrimitive);
+
+ return getB2DPolyPolygon() == rCompare.getB2DPolyPolygon();
+ }
+
+ return false;
+}
+
+basegfx::B2DRange SlideBackgroundFillPrimitive2D::getB2DRange(
+ const geometry::ViewInformation2D& /*rViewInformation*/) const
+{
+ // return range
+ return basegfx::utils::getRange(getB2DPolyPolygon());
+}
+
+// provide unique ID
+sal_uInt32 SlideBackgroundFillPrimitive2D::getPrimitive2DID() const
+{
+ return PRIMITIVE2D_ID_SLIDEBACKGROUNDFILLPRIMITIVE2D;
+}
+
+}; // end of anonymous namespace
+
+ class TransparencePrimitive2D;
+
+ Primitive2DReference createPolyPolygonFillPrimitive(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const attribute::SdrFillAttribute& rFill,
+ const attribute::FillGradientAttribute& rFillGradient)
+ {
+ // when we have no given definition range, use the range of the given geometry
+ // also for definition (simplest case)
+ const basegfx::B2DRange aRange(basegfx::utils::getRange(rPolyPolygon));
+
+ return createPolyPolygonFillPrimitive(
+ rPolyPolygon,
+ aRange,
+ rFill,
+ rFillGradient);
+ }
+
+ Primitive2DReference createPolyPolygonFillPrimitive(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const basegfx::B2DRange& rDefinitionRange,
+ const attribute::SdrFillAttribute& rFill,
+ const attribute::FillGradientAttribute& rFillGradient)
+ {
+ if(basegfx::fTools::moreOrEqual(rFill.getTransparence(), 1.0))
+ {
+ return Primitive2DReference();
+ }
+
+ // prepare fully scaled polygon
+ rtl::Reference<BasePrimitive2D> pNewFillPrimitive;
+
+ if(!rFill.getGradient().isDefault())
+ {
+ pNewFillPrimitive = new PolyPolygonGradientPrimitive2D(
+ rPolyPolygon,
+ rDefinitionRange,
+ rFill.getGradient());
+ }
+ else if(!rFill.getHatch().isDefault())
+ {
+ pNewFillPrimitive = new PolyPolygonHatchPrimitive2D(
+ rPolyPolygon,
+ rDefinitionRange,
+ rFill.getColor(),
+ rFill.getHatch());
+ }
+ else if(!rFill.getFillGraphic().isDefault())
+ {
+ pNewFillPrimitive = new PolyPolygonGraphicPrimitive2D(
+ rPolyPolygon,
+ rDefinitionRange,
+ rFill.getFillGraphic().createFillGraphicAttribute(rDefinitionRange));
+ }
+ else if(rFill.isSlideBackgroundFill())
+ {
+ // create needed Primitive2D representation for
+ // SlideBackgroundFill-mode
+ pNewFillPrimitive = new SlideBackgroundFillPrimitive2D(
+ rPolyPolygon);
+ }
+ else
+ {
+ pNewFillPrimitive = new PolyPolygonColorPrimitive2D(
+ rPolyPolygon,
+ rFill.getColor());
+ }
+
+ if(0.0 != rFill.getTransparence())
+ {
+ // create simpleTransparencePrimitive, add created fill primitive
+ Primitive2DContainer aContent { pNewFillPrimitive };
+ return Primitive2DReference(new UnifiedTransparencePrimitive2D(std::move(aContent), rFill.getTransparence()));
+ }
+ else if(!rFillGradient.isDefault())
+ {
+ // create sequence with created fill primitive
+ Primitive2DContainer aContent { pNewFillPrimitive };
+
+ // create FillGradientPrimitive2D for transparence and add to new sequence
+ // fillGradientPrimitive is enough here (compared to PolyPolygonGradientPrimitive2D) since float transparence will be masked anyways
+ const basegfx::B2DRange aRange(basegfx::utils::getRange(rPolyPolygon));
+ Primitive2DReference xRefB(
+ new FillGradientPrimitive2D(
+ aRange,
+ rDefinitionRange,
+ rFillGradient));
+ Primitive2DContainer aAlpha { xRefB };
+
+ // create TransparencePrimitive2D using alpha and content
+ return Primitive2DReference(new TransparencePrimitive2D(std::move(aContent), std::move(aAlpha)));
+ }
+ else
+ {
+ // add to decomposition
+ return pNewFillPrimitive;
+ }
+ }
+
+ Primitive2DReference createPolygonLinePrimitive(
+ const basegfx::B2DPolygon& rPolygon,
+ const attribute::SdrLineAttribute& rLine,
+ const attribute::SdrLineStartEndAttribute& rStroke)
+ {
+ // create line and stroke attribute
+ const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin(), rLine.getCap());
+ const attribute::StrokeAttribute aStrokeAttribute(std::vector(rLine.getDotDashArray()), rLine.getFullDotDashLen());
+ rtl::Reference<BasePrimitive2D> pNewLinePrimitive;
+
+ if(!rPolygon.isClosed() && !rStroke.isDefault())
+ {
+ attribute::LineStartEndAttribute aStart(rStroke.getStartWidth(), rStroke.getStartPolyPolygon(), rStroke.isStartCentered());
+ attribute::LineStartEndAttribute aEnd(rStroke.getEndWidth(), rStroke.getEndPolyPolygon(), rStroke.isEndCentered());
+
+ // create data
+ pNewLinePrimitive = new PolygonStrokeArrowPrimitive2D(rPolygon, aLineAttribute, aStrokeAttribute, aStart, aEnd);
+ }
+ else
+ {
+ // create data
+ pNewLinePrimitive = new PolygonStrokePrimitive2D(rPolygon, aLineAttribute, aStrokeAttribute);
+ }
+
+ if(0.0 != rLine.getTransparence())
+ {
+ // create simpleTransparencePrimitive, add created fill primitive
+ Primitive2DContainer aContent { pNewLinePrimitive };
+ return Primitive2DReference(new UnifiedTransparencePrimitive2D(std::move(aContent), rLine.getTransparence()));
+ }
+ else
+ {
+ // add to decomposition
+ return pNewLinePrimitive;
+ }
+ }
+
+ Primitive2DReference createTextPrimitive(
+ const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
+ const basegfx::B2DHomMatrix& rObjectTransform,
+ const attribute::SdrTextAttribute& rText,
+ const attribute::SdrLineAttribute& rStroke,
+ bool bCellText,
+ bool bWordWrap)
+ {
+ basegfx::B2DHomMatrix aAnchorTransform(rObjectTransform);
+ rtl::Reference<SdrTextPrimitive2D> pNew;
+
+ if(rText.isContour())
+ {
+ // contour text
+ if(!rStroke.isDefault() && 0.0 != rStroke.getWidth())
+ {
+ // take line width into account and shrink contour polygon accordingly
+ // decompose to get scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // scale outline to object's size to allow growing with value relative to that size
+ // and also to keep aspect ratio
+ basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon);
+ aScaledUnitPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(
+ fabs(aScale.getX()), fabs(aScale.getY())));
+
+ // grow the polygon. To shrink, use negative value (half width)
+ aScaledUnitPolyPolygon = basegfx::utils::growInNormalDirection(aScaledUnitPolyPolygon, -(rStroke.getWidth() * 0.5));
+
+ // scale back to unit polygon
+ aScaledUnitPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(
+ 0.0 != aScale.getX() ? 1.0 / aScale.getX() : 1.0,
+ 0.0 != aScale.getY() ? 1.0 / aScale.getY() : 1.0));
+
+ // create with unit polygon
+ pNew = new SdrContourTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aScaledUnitPolyPolygon,
+ rObjectTransform);
+ }
+ else
+ {
+ // create with unit polygon
+ pNew = new SdrContourTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ rUnitPolyPolygon,
+ rObjectTransform);
+ }
+ }
+ else if(!rText.getSdrFormTextAttribute().isDefault())
+ {
+ // text on path, use scaled polygon
+ basegfx::B2DPolyPolygon aScaledPolyPolygon(rUnitPolyPolygon);
+ aScaledPolyPolygon.transform(rObjectTransform);
+ pNew = new SdrPathTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aScaledPolyPolygon,
+ rText.getSdrFormTextAttribute());
+ }
+ else
+ {
+ // rObjectTransform is the whole SdrObject transformation from unit rectangle
+ // to its size and position. Decompose to allow working with single values.
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // extract mirroring
+ const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
+ const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
+ aScale = basegfx::absolute(aScale);
+
+ // Get the real size, since polygon outline and scale
+ // from the object transformation may vary (e.g. ellipse segments)
+ basegfx::B2DHomMatrix aJustScaleTransform;
+ aJustScaleTransform.set(0, 0, aScale.getX());
+ aJustScaleTransform.set(1, 1, aScale.getY());
+ basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon);
+ aScaledUnitPolyPolygon.transform(aJustScaleTransform);
+ const basegfx::B2DRange aTextAnchorRange
+ = getTextAnchorRange(rText, basegfx::utils::getRange(aScaledUnitPolyPolygon));
+
+ // now create a transformation from this basic range (aTextAnchorRange)
+ // #i121494# if we have no scale use at least 1.0 to have a carrier e.g. for
+ // mirror values, else these will get lost
+ aAnchorTransform = basegfx::utils::createScaleTranslateB2DHomMatrix(
+ basegfx::fTools::equalZero(aTextAnchorRange.getWidth()) ? 1.0 : aTextAnchorRange.getWidth(),
+ basegfx::fTools::equalZero(aTextAnchorRange.getHeight()) ? 1.0 : aTextAnchorRange.getHeight(),
+ aTextAnchorRange.getMinX(), aTextAnchorRange.getMinY());
+
+ // apply mirroring
+ aAnchorTransform.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
+
+ // apply object's other transforms
+ aAnchorTransform = basegfx::utils::createShearXRotateTranslateB2DHomMatrix(fShearX, fRotate, aTranslate)
+ * aAnchorTransform;
+
+ if(rText.isFitToSize())
+ {
+ // stretched text in range
+ pNew = new SdrStretchTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aAnchorTransform,
+ rText.isFixedCellHeight());
+ }
+ else if(rText.isAutoFit())
+ {
+ // isotropically scaled text in range
+ pNew = new SdrAutoFitTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aAnchorTransform,
+ bWordWrap);
+ }
+ else if( rText.isChainable() && !rText.isInEditMode() )
+ {
+ pNew = new SdrChainedTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aAnchorTransform );
+ }
+ else // text in range
+ {
+ // build new primitive
+ pNew = new SdrBlockTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aAnchorTransform,
+ rText.getSdrTextHorzAdjust(),
+ rText.getSdrTextVertAdjust(),
+ rText.isFixedCellHeight(),
+ rText.isScroll(),
+ bCellText,
+ bWordWrap);
+ }
+ }
+
+ OSL_ENSURE(pNew != nullptr, "createTextPrimitive: no text primitive created (!)");
+
+ if(rText.isBlink())
+ {
+ // prepare animation and primitive list
+ drawinglayer::animation::AnimationEntryList aAnimationList;
+ rText.getBlinkTextTiming(aAnimationList);
+
+ if(0.0 != aAnimationList.getDuration())
+ {
+ // create content sequence
+ Primitive2DReference xRefA(pNew);
+ Primitive2DContainer aContent { xRefA };
+
+ // create and add animated switch primitive
+ return Primitive2DReference(new AnimatedBlinkPrimitive2D(aAnimationList, std::move(aContent)));
+ }
+ else
+ {
+ // add to decomposition
+ return Primitive2DReference(pNew);
+ }
+ }
+
+ if(rText.isScroll())
+ {
+ // suppress scroll when FontWork
+ if(rText.getSdrFormTextAttribute().isDefault())
+ {
+ // get scroll direction
+ const SdrTextAniDirection eDirection(rText.getSdrText().GetObject().GetTextAniDirection());
+ const bool bHorizontal(SdrTextAniDirection::Left == eDirection || SdrTextAniDirection::Right == eDirection);
+
+ // decompose to get separated values for the scroll box
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aAnchorTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // build transform from scaled only to full AnchorTransform and inverse
+ const basegfx::B2DHomMatrix aSRT(basegfx::utils::createShearXRotateTranslateB2DHomMatrix(
+ fShearX, fRotate, aTranslate));
+ basegfx::B2DHomMatrix aISRT(aSRT);
+ aISRT.invert();
+
+ // bring the primitive back to scaled only and get scaled range, create new clone for this
+ rtl::Reference<SdrTextPrimitive2D> pNew2 = pNew->createTransformedClone(aISRT);
+ OSL_ENSURE(pNew2, "createTextPrimitive: Could not create transformed clone of text primitive (!)");
+ pNew = pNew2.get();
+
+ // create neutral geometry::ViewInformation2D for local range and decompose calls. This is okay
+ // since the decompose is view-independent
+ geometry::ViewInformation2D aViewInformation2D;
+
+ // get range
+ const basegfx::B2DRange aScaledRange(pNew->getB2DRange(aViewInformation2D));
+
+ // create left outside and right outside transformations. Also take care
+ // of the clip rectangle
+ basegfx::B2DHomMatrix aLeft, aRight;
+ basegfx::B2DPoint aClipTopLeft(0.0, 0.0);
+ basegfx::B2DPoint aClipBottomRight(aScale.getX(), aScale.getY());
+
+ if(bHorizontal)
+ {
+ aClipTopLeft.setY(aScaledRange.getMinY());
+ aClipBottomRight.setY(aScaledRange.getMaxY());
+ aLeft.translate(-aScaledRange.getMaxX(), 0.0);
+ aRight.translate(aScale.getX() - aScaledRange.getMinX(), 0.0);
+ }
+ else
+ {
+ aClipTopLeft.setX(aScaledRange.getMinX());
+ aClipBottomRight.setX(aScaledRange.getMaxX());
+ aLeft.translate(0.0, -aScaledRange.getMaxY());
+ aRight.translate(0.0, aScale.getY() - aScaledRange.getMinY());
+ }
+
+ aLeft *= aSRT;
+ aRight *= aSRT;
+
+ // prepare animation list
+ drawinglayer::animation::AnimationEntryList aAnimationList;
+
+ if(bHorizontal)
+ {
+ rText.getScrollTextTiming(aAnimationList, aScale.getX(), aScaledRange.getWidth());
+ }
+ else
+ {
+ rText.getScrollTextTiming(aAnimationList, aScale.getY(), aScaledRange.getHeight());
+ }
+
+ if(0.0 != aAnimationList.getDuration())
+ {
+ // create a new Primitive2DContainer containing the animated text in its scaled only state.
+ // use the decomposition to force to simple text primitives, those will no longer
+ // need the outliner for formatting (alternatively it is also possible to just add
+ // pNew to aNewPrimitiveSequence)
+ Primitive2DContainer aAnimSequence;
+ pNew->get2DDecomposition(aAnimSequence, aViewInformation2D);
+ pNew.clear();
+
+ // create a new animatedInterpolatePrimitive and add it
+ Primitive2DReference xRefA(new AnimatedInterpolatePrimitive2D({ aLeft, aRight }, aAnimationList, std::move(aAnimSequence)));
+ Primitive2DContainer aContent { xRefA };
+
+ // scrolling needs an encapsulating clipping primitive
+ const basegfx::B2DRange aClipRange(aClipTopLeft, aClipBottomRight);
+ basegfx::B2DPolygon aClipPolygon(basegfx::utils::createPolygonFromRect(aClipRange));
+ aClipPolygon.transform(aSRT);
+ return Primitive2DReference(new MaskPrimitive2D(basegfx::B2DPolyPolygon(aClipPolygon), std::move(aContent)));
+ }
+ else
+ {
+ // add to decomposition
+ return Primitive2DReference(pNew);
+ }
+ }
+ }
+
+ if(rText.isInEditMode())
+ {
+ // #i97628#
+ // encapsulate with TextHierarchyEditPrimitive2D to allow renderers
+ // to suppress actively edited content if needed
+ Primitive2DReference xRefA(pNew);
+ Primitive2DContainer aContent { xRefA };
+
+ // create and add TextHierarchyEditPrimitive2D primitive
+ return Primitive2DReference(new TextHierarchyEditPrimitive2D(std::move(aContent)));
+ }
+ else
+ {
+ // add to decomposition
+ return pNew;
+ }
+ }
+
+ Primitive2DContainer createEmbeddedShadowPrimitive(
+ Primitive2DContainer&& rContent,
+ const attribute::SdrShadowAttribute& rShadow,
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const Primitive2DContainer* pContentForShadow)
+ {
+ if(rContent.empty())
+ return std::move(rContent);
+
+ basegfx::B2DHomMatrix aShadowOffset;
+
+ if(rShadow.getSize().getX() != 100000)
+ {
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate = 0;
+ double fShearX = 0;
+ rObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+ // Scale the shadow
+ double nTranslateX = aTranslate.getX();
+ double nTranslateY = aTranslate.getY();
+
+ // The origin for scaling is the top left corner by default. A negative
+ // shadow offset changes the origin.
+ if (rShadow.getOffset().getX() < 0)
+ nTranslateX += aScale.getX();
+ if (rShadow.getOffset().getY() < 0)
+ nTranslateY += aScale.getY();
+
+ aShadowOffset.translate(-nTranslateX, -nTranslateY);
+ aShadowOffset.scale(rShadow.getSize().getX() * 0.00001, rShadow.getSize().getY() * 0.00001);
+ aShadowOffset.translate(nTranslateX, nTranslateY);
+ }
+
+ aShadowOffset.translate(rShadow.getOffset().getX(), rShadow.getOffset().getY());
+
+ // create shadow primitive and add content
+ const Primitive2DContainer& rContentForShadow
+ = pContentForShadow ? *pContentForShadow : rContent;
+ int nContentWithTransparence = std::count_if(
+ rContentForShadow.begin(), rContentForShadow.end(),
+ [](const Primitive2DReference& xChild) {
+ auto pChild = dynamic_cast<BufferedDecompositionPrimitive2D*>(xChild.get());
+ return pChild && pChild->getTransparenceForShadow() != 0;
+ });
+ if (nContentWithTransparence == 0)
+ {
+ Primitive2DContainer aRetval(2);
+ aRetval[0] = Primitive2DReference(
+ new ShadowPrimitive2D(
+ aShadowOffset,
+ rShadow.getColor(),
+ rShadow.getBlur(),
+ Primitive2DContainer(pContentForShadow ? *pContentForShadow : rContent)));
+
+ if (0.0 != rShadow.getTransparence())
+ {
+ // create SimpleTransparencePrimitive2D
+ Primitive2DContainer aTempContent{ aRetval[0] };
+
+ aRetval[0] = Primitive2DReference(
+ new UnifiedTransparencePrimitive2D(
+ std::move(aTempContent),
+ rShadow.getTransparence()));
+ }
+
+ aRetval[1] = Primitive2DReference(new GroupPrimitive2D(std::move(rContent)));
+ return aRetval;
+ }
+
+ Primitive2DContainer aRetval;
+ for (const auto& xChild : rContentForShadow)
+ {
+ double fChildTransparence = 0.0;
+ auto pChild = dynamic_cast<BufferedDecompositionPrimitive2D*>(xChild.get());
+ if (pChild)
+ {
+ fChildTransparence = pChild->getTransparenceForShadow();
+ fChildTransparence /= 100;
+ }
+ aRetval.push_back(Primitive2DReference(
+ new ShadowPrimitive2D(aShadowOffset, rShadow.getColor(), rShadow.getBlur(),
+ Primitive2DContainer({ xChild }))));
+ if (rShadow.getTransparence() != 0.0 || fChildTransparence != 0.0)
+ {
+ Primitive2DContainer aTempContent{ aRetval.back() };
+
+ double fChildAlpha = 1.0 - fChildTransparence;
+ double fShadowAlpha = 1.0 - rShadow.getTransparence();
+ double fTransparence = 1.0 - fChildAlpha * fShadowAlpha;
+ aRetval.back() = Primitive2DReference(new UnifiedTransparencePrimitive2D(
+ std::move(aTempContent), fTransparence));
+ }
+ }
+
+ aRetval.push_back(
+ Primitive2DReference(new GroupPrimitive2D(std::move(rContent))));
+ return aRetval;
+ }
+
+ Primitive2DContainer createEmbeddedGlowPrimitive(
+ Primitive2DContainer&& rContent,
+ const attribute::SdrGlowAttribute& rGlow)
+ {
+ if(rContent.empty())
+ return std::move(rContent);
+ Primitive2DContainer aRetval(2);
+ aRetval[0] = Primitive2DReference(
+ new GlowPrimitive2D(rGlow.getColor(), rGlow.getRadius(), Primitive2DContainer(rContent)));
+ aRetval[1] = Primitive2DReference(new GroupPrimitive2D(Primitive2DContainer(rContent)));
+ return aRetval;
+ }
+
+ Primitive2DContainer createEmbeddedSoftEdgePrimitive(Primitive2DContainer&& aContent,
+ sal_Int32 nRadius)
+ {
+ if (aContent.empty() || !nRadius)
+ return std::move(aContent);
+ Primitive2DContainer aRetval(1);
+ aRetval[0] = Primitive2DReference(new SoftEdgePrimitive2D(nRadius, std::move(aContent)));
+ return aRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrellipseprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrellipseprimitive2d.cxx
new file mode 100644
index 000000000..89c348beb
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrellipseprimitive2d.cxx
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrellipseprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrEllipsePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ // Do use createPolygonFromUnitCircle, but let create from first quadrant to mimic old geometry creation.
+ // This is needed to have the same look when stroke is used since the polygon start point defines the
+ // stroke start, too.
+ basegfx::B2DPolygon aUnitOutline(basegfx::utils::createPolygonFromUnitCircle(1));
+
+ // scale and move UnitEllipse to UnitObject (-1,-1 1,1) -> (0,0 1,1)
+ const basegfx::B2DHomMatrix aUnitCorrectionMatrix(
+ basegfx::utils::createScaleTranslateB2DHomMatrix(0.5, 0.5, 0.5, 0.5));
+
+ // apply to the geometry
+ aUnitOutline.transform(aUnitCorrectionMatrix);
+
+ // add fill
+ if(!getSdrLFSTAttribute().getFill().isDefault())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+
+ // add line
+ if(getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // create invisible line for HitTest/BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+ else
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+
+ // add text
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLFSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrEllipsePrimitive2D::SdrEllipsePrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute)
+ : maTransform(rTransform),
+ maSdrLFSTAttribute(rSdrLFSTAttribute)
+ {
+ }
+
+ bool SdrEllipsePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrEllipsePrimitive2D& rCompare = static_cast<const SdrEllipsePrimitive2D&>(rPrimitive);
+
+ return (getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrEllipsePrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRELLIPSEPRIMITIVE2D;
+ }
+
+
+
+ void SdrEllipseSegmentPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ basegfx::B2DPolygon aUnitOutline(basegfx::utils::createPolygonFromUnitEllipseSegment(mfStartAngle, mfEndAngle));
+
+ if(mbCloseSegment)
+ {
+ if(mbCloseUsingCenter)
+ {
+ // for compatibility, insert the center point at polygon start to get the same
+ // line stroking pattern as the old painting mechanisms.
+ aUnitOutline.insert(0, basegfx::B2DPoint(0.0, 0.0));
+ }
+
+ aUnitOutline.setClosed(true);
+ }
+
+ // move and scale UnitEllipse to UnitObject (-1,-1 1,1) -> (0,0 1,1)
+ const basegfx::B2DHomMatrix aUnitCorrectionMatrix(
+ basegfx::utils::createScaleTranslateB2DHomMatrix(0.5, 0.5, 0.5, 0.5));
+
+ // apply to the geometry
+ aUnitOutline.transform(aUnitCorrectionMatrix);
+
+ // add fill
+ if(!getSdrLFSTAttribute().getFill().isDefault() && aUnitOutline.isClosed())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+
+ // add line
+ if(getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // create invisible line for HitTest/BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+ else
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ getSdrLFSTAttribute().getLineStartEnd()));
+ }
+
+ // add text
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLFSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrEllipseSegmentPrimitive2D::SdrEllipseSegmentPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ double fStartAngle,
+ double fEndAngle,
+ bool bCloseSegment,
+ bool bCloseUsingCenter)
+ : SdrEllipsePrimitive2D(rTransform, rSdrLFSTAttribute),
+ mfStartAngle(fStartAngle),
+ mfEndAngle(fEndAngle),
+ mbCloseSegment(bCloseSegment),
+ mbCloseUsingCenter(bCloseUsingCenter)
+ {
+ }
+
+ bool SdrEllipseSegmentPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrEllipsePrimitive2D::operator==(rPrimitive))
+ {
+ const SdrEllipseSegmentPrimitive2D& rCompare = static_cast<const SdrEllipseSegmentPrimitive2D&>(rPrimitive);
+
+ if( mfStartAngle == rCompare.mfStartAngle
+ && mfEndAngle == rCompare.mfEndAngle
+ && mbCloseSegment == rCompare.mbCloseSegment
+ && mbCloseUsingCenter == rCompare.mbCloseUsingCenter)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrEllipseSegmentPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRELLIPSESEGMENTPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx
new file mode 100644
index 000000000..0610f43b0
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx
@@ -0,0 +1,928 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx>
+#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <svtools/borderhelper.hxx>
+
+namespace
+{
+ double snapToDiscreteUnit(
+ double fValue,
+ double fMinimalDiscreteUnit)
+ {
+ if(0.0 != fValue)
+ {
+ fValue = std::max(fValue, fMinimalDiscreteUnit);
+ }
+
+ return fValue;
+ }
+
+ class StyleVectorCombination
+ {
+ private:
+ struct OffsetAndHalfWidthAndColor
+ {
+ double mfOffset;
+ double mfHalfWidth;
+ Color maColor;
+
+ OffsetAndHalfWidthAndColor(double offset, double halfWidth, Color color) :
+ mfOffset(offset),
+ mfHalfWidth(halfWidth),
+ maColor(color)
+ {}
+ };
+
+ double mfRefModeOffset;
+ basegfx::B2DVector maB2DVector;
+ double mfAngle;
+ std::vector< OffsetAndHalfWidthAndColor > maOffsets;
+
+ public:
+ StyleVectorCombination(
+ const svx::frame::Style& rStyle,
+ const basegfx::B2DVector& rB2DVector,
+ double fAngle,
+ bool bMirrored,
+ const Color* pForceColor,
+ double fMinimalDiscreteUnit)
+ : mfRefModeOffset(0.0),
+ maB2DVector(rB2DVector),
+ mfAngle(fAngle)
+ {
+ if (!rStyle.IsUsed())
+ return;
+
+ svx::frame::RefMode aRefMode(rStyle.GetRefMode());
+ Color aPrim(rStyle.GetColorPrim());
+ Color aSecn(rStyle.GetColorSecn());
+ const bool bSecnUsed(0.0 != rStyle.Secn());
+
+ // Get the single segment line widths. This is the point where the
+ // minimal discrete unit will be used if given (fMinimalDiscreteUnit). If
+ // not given it's 0.0 and thus will have no influence.
+ double fPrim(snapToDiscreteUnit(rStyle.Prim(), fMinimalDiscreteUnit));
+ const double fDist(snapToDiscreteUnit(rStyle.Dist(), fMinimalDiscreteUnit));
+ double fSecn(snapToDiscreteUnit(rStyle.Secn(), fMinimalDiscreteUnit));
+
+ // Of course also do not use svx::frame::Style::GetWidth() for obvious
+ // reasons.
+ const double fStyleWidth(fPrim + fDist + fSecn);
+
+ if(bMirrored)
+ {
+ switch(aRefMode)
+ {
+ case svx::frame::RefMode::Begin: aRefMode = svx::frame::RefMode::End; break;
+ case svx::frame::RefMode::End: aRefMode = svx::frame::RefMode::Begin; break;
+ default: break;
+ }
+
+ if(bSecnUsed)
+ {
+ std::swap(aPrim, aSecn);
+ std::swap(fPrim, fSecn);
+ }
+ }
+
+ if (svx::frame::RefMode::Centered != aRefMode)
+ {
+ const double fHalfWidth(fStyleWidth * 0.5);
+
+ if (svx::frame::RefMode::Begin == aRefMode)
+ {
+ // move aligned below vector
+ mfRefModeOffset = fHalfWidth;
+ }
+ else if (svx::frame::RefMode::End == aRefMode)
+ {
+ // move aligned above vector
+ mfRefModeOffset = -fHalfWidth;
+ }
+ }
+
+ if (bSecnUsed)
+ {
+ // both or all three lines used
+ const bool bPrimTransparent(rStyle.GetColorPrim().IsFullyTransparent());
+ const bool bDistTransparent(!rStyle.UseGapColor() || rStyle.GetColorGap().IsFullyTransparent());
+ const bool bSecnTransparent(aSecn.IsFullyTransparent());
+
+ if(!bPrimTransparent || !bDistTransparent || !bSecnTransparent)
+ {
+ const double a(mfRefModeOffset - (fStyleWidth * 0.5));
+ const double b(a + fPrim);
+ const double c(b + fDist);
+ const double d(c + fSecn);
+
+ maOffsets.push_back(
+ OffsetAndHalfWidthAndColor(
+ (a + b) * 0.5,
+ fPrim * 0.5,
+ nullptr != pForceColor ? *pForceColor : aPrim));
+
+ maOffsets.push_back(
+ OffsetAndHalfWidthAndColor(
+ (b + c) * 0.5,
+ fDist * 0.5,
+ rStyle.UseGapColor()
+ ? (nullptr != pForceColor ? *pForceColor : rStyle.GetColorGap())
+ : COL_TRANSPARENT));
+
+ maOffsets.push_back(
+ OffsetAndHalfWidthAndColor(
+ (c + d) * 0.5,
+ fSecn * 0.5,
+ nullptr != pForceColor ? *pForceColor : aSecn));
+ }
+ }
+ else
+ {
+ // one line used, push two values, from outer to inner
+ if(!rStyle.GetColorPrim().IsFullyTransparent())
+ {
+ maOffsets.push_back(
+ OffsetAndHalfWidthAndColor(
+ mfRefModeOffset,
+ fPrim * 0.5,
+ nullptr != pForceColor ? *pForceColor : aPrim));
+ }
+ }
+ }
+
+ double getRefModeOffset() const { return mfRefModeOffset; }
+ const basegfx::B2DVector& getB2DVector() const { return maB2DVector; }
+ double getAngle() const { return mfAngle; }
+ bool empty() const { return maOffsets.empty(); }
+ size_t size() const { return maOffsets.size(); }
+
+ void getColorAndOffsetAndHalfWidth(size_t nIndex, Color& rColor, double& rfOffset, double& rfHalfWidth) const
+ {
+ if(nIndex >= maOffsets.size())
+ return;
+ const OffsetAndHalfWidthAndColor& rCandidate(maOffsets[nIndex]);
+ rfOffset = rCandidate.mfOffset;
+ rfHalfWidth = rCandidate.mfHalfWidth;
+ rColor = rCandidate.maColor;
+ }
+ };
+
+ class StyleVectorTable
+ {
+ private:
+ std::vector< StyleVectorCombination > maEntries;
+
+ public:
+ StyleVectorTable()
+ {
+ }
+
+ void add(
+ const svx::frame::Style& rStyle,
+ const basegfx::B2DVector& rMyVector,
+ const basegfx::B2DVector& rOtherVector,
+ bool bMirrored,
+ double fMinimalDiscreteUnit)
+ {
+ if(!rStyle.IsUsed() || basegfx::areParallel(rMyVector, rOtherVector))
+ return;
+
+ // create angle between both. angle() needs vectors pointing away from the same point,
+ // so take the mirrored one. Add M_PI to get from -pi..+pi to [0..M_PI_2] for sorting
+ const double fAngle(basegfx::B2DVector(-rMyVector.getX(), -rMyVector.getY()).angle(rOtherVector) + M_PI);
+ maEntries.emplace_back(
+ rStyle,
+ rOtherVector,
+ fAngle,
+ bMirrored,
+ nullptr,
+ fMinimalDiscreteUnit);
+ }
+
+ void sort()
+ {
+ // sort inverse from highest to lowest
+ std::sort(
+ maEntries.begin(),
+ maEntries.end(),
+ [](const StyleVectorCombination& a, const StyleVectorCombination& b)
+ { return a.getAngle() > b.getAngle(); });
+ }
+
+ bool empty() const { return maEntries.empty(); }
+ const std::vector< StyleVectorCombination >& getEntries() const{ return maEntries; }
+ };
+
+ struct CutSet
+ {
+ double mfOLML;
+ double mfORML;
+ double mfOLMR;
+ double mfORMR;
+
+ CutSet() : mfOLML(0.0), mfORML(0.0), mfOLMR(0.0), mfORMR(0.0)
+ {
+ }
+
+ bool operator<( const CutSet& rOther) const
+ {
+ const double fA(mfOLML + mfORML + mfOLMR + mfORMR);
+ const double fB(rOther.mfOLML + rOther.mfORML + rOther.mfOLMR + rOther.mfORMR);
+
+ return fA < fB;
+ }
+
+ double getSum() const { return mfOLML + mfORML + mfOLMR + mfORMR; }
+ };
+
+ void getCutSet(
+ CutSet& rCutSet,
+ const basegfx::B2DPoint& rLeft,
+ const basegfx::B2DPoint& rRight,
+ const basegfx::B2DVector& rX,
+ const basegfx::B2DPoint& rOtherLeft,
+ const basegfx::B2DPoint& rOtherRight,
+ const basegfx::B2DVector& rOtherX)
+ {
+ basegfx::utils::findCut(
+ rLeft,
+ rX,
+ rOtherLeft,
+ rOtherX,
+ CutFlagValue::LINE,
+ &rCutSet.mfOLML);
+
+ basegfx::utils::findCut(
+ rRight,
+ rX,
+ rOtherLeft,
+ rOtherX,
+ CutFlagValue::LINE,
+ &rCutSet.mfOLMR);
+
+ basegfx::utils::findCut(
+ rLeft,
+ rX,
+ rOtherRight,
+ rOtherX,
+ CutFlagValue::LINE,
+ &rCutSet.mfORML);
+
+ basegfx::utils::findCut(
+ rRight,
+ rX,
+ rOtherRight,
+ rOtherX,
+ CutFlagValue::LINE,
+ &rCutSet.mfORMR);
+ }
+
+ struct ExtendSet
+ {
+ double mfExtLeft;
+ double mfExtRight;
+
+ ExtendSet() : mfExtLeft(0.0), mfExtRight(0.0) {}
+ };
+
+ void getExtends(
+ std::vector<ExtendSet>& rExtendSet, // target Left/Right values to fill
+ const basegfx::B2DPoint& rOrigin, // own vector start
+ const StyleVectorCombination& rCombination, // own vector and offsets for lines
+ const basegfx::B2DVector& rPerpendX, // normalized perpendicular to own vector
+ const std::vector< StyleVectorCombination >& rStyleVector) // other vectors emerging in this point
+ {
+ if(!(!rCombination.empty() && !rStyleVector.empty() && rCombination.size() == rExtendSet.size()))
+ return;
+
+ const size_t nOffsetA(rCombination.size());
+
+ if(1 == nOffsetA)
+ {
+ Color aMyColor; double fMyOffset(0.0); double fMyHalfWidth(0.0);
+ rCombination.getColorAndOffsetAndHalfWidth(0, aMyColor, fMyOffset, fMyHalfWidth);
+
+ if(!aMyColor.IsFullyTransparent())
+ {
+ const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (fMyOffset - fMyHalfWidth)));
+ const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (fMyOffset + fMyHalfWidth)));
+ std::vector< CutSet > aCutSets;
+
+ for(const auto& rStyleCandidate : rStyleVector)
+ {
+ const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleCandidate.getB2DVector()));
+ const size_t nOffsetB(rStyleCandidate.size());
+
+ for(size_t other(0); other < nOffsetB; other++)
+ {
+ Color aOtherColor; double fOtherOffset(0.0); double fOtherHalfWidth(0.0);
+ rStyleCandidate.getColorAndOffsetAndHalfWidth(other, aOtherColor, fOtherOffset, fOtherHalfWidth);
+
+ if(!aOtherColor.IsFullyTransparent())
+ {
+ const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (fOtherOffset - fOtherHalfWidth)));
+ const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (fOtherOffset + fOtherHalfWidth)));
+
+ CutSet aNewCutSet;
+ getCutSet(aNewCutSet, aLeft, aRight, rCombination.getB2DVector(), aOtherLeft, aOtherRight, rStyleCandidate.getB2DVector());
+ aCutSets.push_back(aNewCutSet);
+ }
+ }
+ }
+
+ if(!aCutSets.empty())
+ {
+ CutSet aCutSet(aCutSets[0]);
+ const size_t nNumCutSets(aCutSets.size());
+
+ if(1 != nNumCutSets)
+ {
+ double fCutSet(aCutSet.getSum());
+
+ for(size_t a(1); a < nNumCutSets; a++)
+ {
+ const CutSet& rCandidate(aCutSets[a]);
+ const double fCandidate(rCandidate.getSum());
+
+ if(basegfx::fTools::equalZero(fCandidate - fCutSet))
+ {
+ // both have equal center point, use medium cut
+ const double fNewOLML(std::max(std::min(rCandidate.mfOLML, rCandidate.mfORML), std::min(aCutSet.mfOLML, aCutSet.mfORML)));
+ const double fNewORML(std::min(std::max(rCandidate.mfOLML, rCandidate.mfORML), std::max(aCutSet.mfOLML, aCutSet.mfORML)));
+ const double fNewOLMR(std::max(std::min(rCandidate.mfOLMR, rCandidate.mfORMR), std::min(aCutSet.mfOLMR, aCutSet.mfORMR)));
+ const double fNewORMR(std::min(std::max(rCandidate.mfOLMR, rCandidate.mfORMR), std::max(aCutSet.mfOLMR, aCutSet.mfORMR)));
+ aCutSet.mfOLML = fNewOLML;
+ aCutSet.mfORML = fNewORML;
+ aCutSet.mfOLMR = fNewOLMR;
+ aCutSet.mfORMR = fNewORMR;
+ fCutSet = aCutSet.getSum();
+ }
+ else if(fCandidate < fCutSet)
+ {
+ // get minimum
+ fCutSet = fCandidate;
+ aCutSet = rCandidate;
+ }
+ }
+ }
+
+ ExtendSet& rExt(rExtendSet[0]);
+
+ rExt.mfExtLeft = std::min(aCutSet.mfOLML, aCutSet.mfORML);
+ rExt.mfExtRight = std::min(aCutSet.mfOLMR, aCutSet.mfORMR);
+ }
+ }
+ }
+ else
+ {
+ size_t nVisEdgeUp(0);
+ size_t nVisEdgeDn(0);
+
+ for(size_t my(0); my < nOffsetA; my++)
+ {
+ Color aMyColor; double fMyOffset(0.0); double fMyHalfWidth(0.0);
+ rCombination.getColorAndOffsetAndHalfWidth(my, aMyColor, fMyOffset, fMyHalfWidth);
+
+ if(!aMyColor.IsFullyTransparent())
+ {
+ const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (fMyOffset - fMyHalfWidth)));
+ const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (fMyOffset + fMyHalfWidth)));
+ const bool bUpper(my <= (nOffsetA >> 1));
+ const StyleVectorCombination& rStyleCandidate(bUpper ? rStyleVector.front() : rStyleVector.back());
+ const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleCandidate.getB2DVector()));
+ const size_t nOffsetB(rStyleCandidate.size());
+ std::vector< CutSet > aCutSets;
+
+ for(size_t other(0); other < nOffsetB; other++)
+ {
+ Color aOtherColor; double fOtherOffset(0.0); double fOtherHalfWidth(0.0);
+ rStyleCandidate.getColorAndOffsetAndHalfWidth(other, aOtherColor, fOtherOffset, fOtherHalfWidth);
+
+ if(!aOtherColor.IsFullyTransparent())
+ {
+ const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (fOtherOffset - fOtherHalfWidth)));
+ const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (fOtherOffset + fOtherHalfWidth)));
+ CutSet aCutSet;
+ getCutSet(aCutSet, aLeft, aRight, rCombination.getB2DVector(), aOtherLeft, aOtherRight, rStyleCandidate.getB2DVector());
+ aCutSets.push_back(aCutSet);
+ }
+ }
+
+ if(!aCutSets.empty())
+ {
+ // sort: min to start, max to end
+ std::sort(aCutSets.begin(), aCutSets.end());
+ const bool bOtherUpper(rStyleCandidate.getAngle() > M_PI);
+
+ // check if we need min or max
+ // bUpper bOtherUpper MinMax
+ // t t max
+ // t f min
+ // f f max
+ // f t min
+ const bool bMax(bUpper == bOtherUpper);
+ size_t nBaseIndex(0);
+ const size_t nNumCutSets(aCutSets.size());
+
+ if(bMax)
+ {
+ // access at end
+ nBaseIndex = nNumCutSets - 1 - (bUpper ? nVisEdgeUp : nVisEdgeDn);
+ }
+ else
+ {
+ // access at start
+ nBaseIndex = bUpper ? nVisEdgeUp : nVisEdgeDn;
+ }
+
+ const size_t nSecuredIndex(std::clamp(nBaseIndex, size_t(0), size_t(nNumCutSets - 1)));
+ const CutSet& rCutSet(aCutSets[nSecuredIndex]);
+ ExtendSet& rExt(rExtendSet[my]);
+
+ rExt.mfExtLeft = std::min(rCutSet.mfOLML, rCutSet.mfORML);
+ rExt.mfExtRight = std::min(rCutSet.mfOLMR, rCutSet.mfORMR);
+ }
+
+ if(bUpper)
+ {
+ nVisEdgeUp++;
+ }
+ else
+ {
+ nVisEdgeDn++;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper method to create the correct drawinglayer::primitive2d::BorderLinePrimitive2D
+ * for the given data, especially the correct drawinglayer::primitive2d::BorderLine entries
+ * including the correctly solved/created LineStartEnd extends
+ *
+ * rTarget : Here the evtl. created BorderLinePrimitive2D will be appended
+ * rOrigin : StartPoint of the Borderline
+ * rX : Vector of the Borderline
+ * rBorder : svx::frame::Style of the of the Borderline
+ * rStartStyleVectorTable : All other Borderlines which have to be taken into account because
+ * they have the same StartPoint as the current Borderline. These will be used to calculate
+ * the correct LineStartEnd extends tor the BorderLinePrimitive2D. The definition should be
+ * built up using svx::frame::StyleVectorTable and StyleVectorTable::add and includes:
+ * rStyle : the svx::frame::Style of one other BorderLine
+ * rMyVector : the Vector of the *new* to-be-defined BorderLine, identical to rX
+ * rOtherVector: the Vector of one other BorderLine (may be, but does not need to be normalized),
+ * always *pointing away* from the common StartPoint rOrigin
+ * bMirrored : define if rStyle of one other BorderLine shall be mirrored (e.g. bottom-right edges)
+ * With multiple BorderLines the definitions have to be CounterClockWise. This will be
+ * ensured by StyleVectorTable sorting the entries, but knowing this may allow more efficient
+ * data creation.
+ * rEndStyleVectorTable: All other BorderLines that have the same EndPoint. There are differences to
+ * the Start definitions:
+ * - do not forget to consequently use -rX for rMyVector
+ * - definitions have to be ClockWise for the EndBorderLines, will be ensured by sorting
+ *
+ * If you take all this into account, you will get correctly extended BorderLinePrimitive2D
+ * representations for the new to be defined BorderLine. That extensions will overlap nicely
+ * with the corresponding BorderLines and take all multiple line definitions in the ::Style into
+ * account.
+ * The internal solver is *not limited* to ::Style(s) with three parts (Left/Gap/Right), this is
+ * just due to svx::frame::Style's definitions. A new solver based on this one can be created
+ * anytime using more mulötiple borders based on the more flexible
+ * std::vector< drawinglayer::primitive2d::BorderLine > if needed.
+ */
+ void CreateBorderPrimitives(
+ drawinglayer::primitive2d::Primitive2DContainer& rTarget, /// target for created primitives
+ const basegfx::B2DPoint& rOrigin, /// start point of borderline
+ const basegfx::B2DVector& rX, /// X-Axis of borderline with length
+ const svx::frame::Style& rBorder, /// Style of borderline
+ const StyleVectorTable& rStartStyleVectorTable, /// Styles and vectors (pointing away) at borderline start, ccw
+ const StyleVectorTable& rEndStyleVectorTable, /// Styles and vectors (pointing away) at borderline end, cw
+ const Color* pForceColor, /// If specified, overrides frame border color.
+ double fMinimalDiscreteUnit) /// minimal discrete unit to use for svx::frame::Style width values
+ {
+ // get offset color pairs for style, one per visible line
+ const StyleVectorCombination aCombination(
+ rBorder,
+ rX,
+ 0.0,
+ false,
+ pForceColor,
+ fMinimalDiscreteUnit);
+
+ if(aCombination.empty())
+ return;
+
+ const basegfx::B2DVector aPerpendX(basegfx::getNormalizedPerpendicular(rX));
+ const bool bHasStartStyles(!rStartStyleVectorTable.empty());
+ const bool bHasEndStyles(!rEndStyleVectorTable.empty());
+ const size_t nOffsets(aCombination.size());
+ std::vector<ExtendSet> aExtendSetStart(nOffsets);
+ std::vector<ExtendSet> aExtendSetEnd(nOffsets);
+
+ if(bHasStartStyles)
+ {
+ // create extends for line starts, use given point/vector and offsets
+ getExtends(aExtendSetStart, rOrigin, aCombination, aPerpendX, rStartStyleVectorTable.getEntries());
+ }
+
+ if(bHasEndStyles)
+ {
+ // Create extends for line ends, create inverse point/vector and inverse offsets.
+ const StyleVectorCombination aMirroredCombination(
+ rBorder,
+ -rX,
+ 0.0,
+ true,
+ pForceColor,
+ fMinimalDiscreteUnit);
+
+ getExtends(aExtendSetEnd, rOrigin + rX, aMirroredCombination, -aPerpendX, rEndStyleVectorTable.getEntries());
+
+ // also need to inverse the result to apply to the correct lines
+ std::reverse(aExtendSetEnd.begin(), aExtendSetEnd.end());
+ }
+
+ std::vector< drawinglayer::primitive2d::BorderLine > aBorderlines;
+ const double fNegLength(-rX.getLength());
+
+ for(size_t a(0); a < nOffsets; a++)
+ {
+ Color aMyColor;
+ double fMyOffset(0.0);
+ double fMyHalfWidth(0.0);
+ aCombination.getColorAndOffsetAndHalfWidth(a, aMyColor, fMyOffset, fMyHalfWidth);
+ const ExtendSet& rExtStart(aExtendSetStart[a]);
+ const ExtendSet& rExtEnd(aExtendSetEnd[a]);
+
+ if(aMyColor.IsFullyTransparent())
+ {
+ aBorderlines.push_back(
+ drawinglayer::primitive2d::BorderLine(
+ fMyHalfWidth * 2.0));
+ }
+ else
+ {
+ aBorderlines.push_back(
+ drawinglayer::primitive2d::BorderLine(
+ drawinglayer::attribute::LineAttribute(
+ aMyColor.getBColor(),
+ fMyHalfWidth * 2.0),
+ fNegLength * rExtStart.mfExtLeft,
+ fNegLength * rExtStart.mfExtRight,
+ fNegLength * rExtEnd.mfExtRight,
+ fNegLength * rExtEnd.mfExtLeft));
+ }
+ }
+
+ static const double fPatScFact(10.0); // 10.0 multiply, see old code
+ std::vector<double> aDashing(svtools::GetLineDashing(rBorder.Type(), rBorder.PatternScale() * fPatScFact));
+ const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(std::move(aDashing));
+ const basegfx::B2DPoint aStart(rOrigin + (aPerpendX * aCombination.getRefModeOffset()));
+
+ rTarget.append(
+ drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::BorderLinePrimitive2D(
+ aStart,
+ aStart + rX,
+ std::move(aBorderlines),
+ aStrokeAttribute)));
+ }
+
+ double getMinimalNonZeroValue(double fCurrent, double fNew)
+ {
+ if(0.0 != fNew)
+ {
+ if(0.0 != fCurrent)
+ {
+ fCurrent = std::min(fNew, fCurrent);
+ }
+ else
+ {
+ fCurrent = fNew;
+ }
+ }
+
+ return fCurrent;
+ }
+
+ double getMinimalNonZeroBorderWidthFromStyle(double fCurrent, const svx::frame::Style& rStyle)
+ {
+ if(rStyle.IsUsed())
+ {
+ fCurrent = getMinimalNonZeroValue(fCurrent, rStyle.Prim());
+ fCurrent = getMinimalNonZeroValue(fCurrent, rStyle.Dist());
+ fCurrent = getMinimalNonZeroValue(fCurrent, rStyle.Secn());
+ }
+
+ return fCurrent;
+ }
+}
+
+namespace drawinglayer::primitive2d
+{
+ SdrFrameBorderData::SdrConnectStyleData::SdrConnectStyleData(
+ const svx::frame::Style& rStyle,
+ const basegfx::B2DVector& rNormalizedPerpendicular,
+ bool bStyleMirrored)
+ : maStyle(rStyle),
+ maNormalizedPerpendicular(rNormalizedPerpendicular),
+ mbStyleMirrored(bStyleMirrored)
+ {
+ }
+
+ bool SdrFrameBorderData::SdrConnectStyleData::operator==(const SdrFrameBorderData::SdrConnectStyleData& rCompare) const
+ {
+ return mbStyleMirrored == rCompare.mbStyleMirrored
+ && maStyle == rCompare.maStyle
+ && maNormalizedPerpendicular == rCompare.maNormalizedPerpendicular;
+ }
+
+ SdrFrameBorderData::SdrFrameBorderData(
+ const basegfx::B2DPoint& rOrigin,
+ const basegfx::B2DVector& rX,
+ const svx::frame::Style& rStyle,
+ const Color* pForceColor)
+ : maOrigin(rOrigin),
+ maX(rX),
+ maStyle(rStyle),
+ maColor(nullptr != pForceColor ? *pForceColor : Color()),
+ mbForceColor(nullptr != pForceColor)
+ {
+ }
+
+ void SdrFrameBorderData::addSdrConnectStyleData(
+ bool bStart,
+ const svx::frame::Style& rStyle,
+ const basegfx::B2DVector& rNormalizedPerpendicular,
+ bool bStyleMirrored)
+ {
+ if(rStyle.IsUsed())
+ {
+ if(bStart)
+ {
+ maStart.emplace_back(rStyle, rNormalizedPerpendicular, bStyleMirrored);
+ }
+ else
+ {
+ maEnd.emplace_back(rStyle, rNormalizedPerpendicular, bStyleMirrored);
+ }
+ }
+ }
+
+ void SdrFrameBorderData::create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ double fMinimalDiscreteUnit) const
+ {
+ StyleVectorTable aStartVector;
+ StyleVectorTable aEndVector;
+ const basegfx::B2DVector aAxis(-maX);
+
+ for(const auto& rStart : maStart)
+ {
+ aStartVector.add(
+ rStart.getStyle(),
+ maX,
+ rStart.getNormalizedPerpendicular(),
+ rStart.getStyleMirrored(),
+ fMinimalDiscreteUnit);
+ }
+
+ for(const auto& rEnd : maEnd)
+ {
+ aEndVector.add(
+ rEnd.getStyle(),
+ aAxis,
+ rEnd.getNormalizedPerpendicular(),
+ rEnd.getStyleMirrored(),
+ fMinimalDiscreteUnit);
+ }
+
+ aStartVector.sort();
+ aEndVector.sort();
+
+ CreateBorderPrimitives(
+ rContainer,
+ maOrigin,
+ maX,
+ maStyle,
+ aStartVector,
+ aEndVector,
+ mbForceColor ? &maColor : nullptr,
+ fMinimalDiscreteUnit);
+ }
+
+ double SdrFrameBorderData::getMinimalNonZeroBorderWidth() const
+ {
+ double fRetval(getMinimalNonZeroBorderWidthFromStyle(0.0, maStyle));
+
+ for(const auto& rStart : maStart)
+ {
+ fRetval = getMinimalNonZeroBorderWidthFromStyle(fRetval, rStart.getStyle());
+ }
+
+ for(const auto& rEnd : maEnd)
+ {
+ fRetval = getMinimalNonZeroBorderWidthFromStyle(fRetval, rEnd.getStyle());
+ }
+
+ return fRetval;
+ }
+
+
+ bool SdrFrameBorderData::operator==(const SdrFrameBorderData& rCompare) const
+ {
+ return maOrigin == rCompare.maOrigin
+ && maX == rCompare.maX
+ && maStyle == rCompare.maStyle
+ && maColor == rCompare.maColor
+ && mbForceColor == rCompare.mbForceColor
+ && maStart == rCompare.maStart
+ && maEnd == rCompare.maEnd;
+ }
+
+
+ void SdrFrameBorderPrimitive2D::create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ if(!getFrameBorders())
+ {
+ return;
+ }
+
+ Primitive2DContainer aRetval;
+
+ // Check and use the minimal non-zero BorderWidth for decompose
+ // if that is set and wanted
+ const double fMinimalDiscreteUnit(doForceToSingleDiscreteUnit()
+ ? mfMinimalNonZeroBorderWidthUsedForDecompose
+ : 0.0);
+
+ {
+ // decompose all buffered SdrFrameBorderData entries and try to merge them
+ // to reduce existing number of BorderLinePrimitive2D(s)
+ for(const auto& rCandidate : *getFrameBorders())
+ {
+ // get decomposition on one SdrFrameBorderData entry
+ Primitive2DContainer aPartial;
+ rCandidate.create2DDecomposition(
+ aPartial,
+ fMinimalDiscreteUnit);
+
+ for(const auto& aCandidatePartial : aPartial)
+ {
+ if(aRetval.empty())
+ {
+ // no local data yet, just add as 1st entry, done
+ aRetval.append(aCandidatePartial);
+ }
+ else
+ {
+ bool bDidMerge(false);
+
+ for(auto& aCandidateRetval : aRetval)
+ {
+ // try to merge by appending new data to existing data
+ const drawinglayer::primitive2d::Primitive2DReference aMergeRetvalPartial(
+ drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(
+ static_cast<BorderLinePrimitive2D*>(aCandidateRetval.get()),
+ static_cast<BorderLinePrimitive2D*>(aCandidatePartial.get())));
+
+ if(aMergeRetvalPartial.is())
+ {
+ // could append, replace existing data with merged data, done
+ aCandidateRetval = aMergeRetvalPartial;
+ bDidMerge = true;
+ break;
+ }
+
+ // try to merge by appending existing data to new data
+ const drawinglayer::primitive2d::Primitive2DReference aMergePartialRetval(
+ drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(
+ static_cast<BorderLinePrimitive2D*>(aCandidatePartial.get()),
+ static_cast<BorderLinePrimitive2D*>(aCandidateRetval.get())));
+
+ if(aMergePartialRetval.is())
+ {
+ // could append, replace existing data with merged data, done
+ aCandidateRetval = aMergePartialRetval;
+ bDidMerge = true;
+ break;
+ }
+ }
+
+ if(!bDidMerge)
+ {
+ // no merge after checking all existing data, append as new segment
+ aRetval.append(aCandidatePartial);
+ }
+ }
+ }
+ }
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrFrameBorderPrimitive2D::SdrFrameBorderPrimitive2D(
+ std::shared_ptr<SdrFrameBorderDataVector>& rFrameBorders,
+ bool bForceToSingleDiscreteUnit)
+ : maFrameBorders(std::move(rFrameBorders)),
+ mfMinimalNonZeroBorderWidth(0.0),
+ mfMinimalNonZeroBorderWidthUsedForDecompose(0.0),
+ mbForceToSingleDiscreteUnit(bForceToSingleDiscreteUnit)
+ {
+ if(getFrameBorders() && doForceToSingleDiscreteUnit())
+ {
+ // detect used minimal non-zero partial border width
+ for(const auto& rCandidate : *getFrameBorders())
+ {
+ mfMinimalNonZeroBorderWidth = getMinimalNonZeroValue(
+ mfMinimalNonZeroBorderWidth,
+ rCandidate.getMinimalNonZeroBorderWidth());
+ }
+ }
+ }
+
+ bool SdrFrameBorderPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrFrameBorderPrimitive2D& rCompare = static_cast<const SdrFrameBorderPrimitive2D&>(rPrimitive);
+
+ return (getFrameBorders() == rCompare.getFrameBorders()
+ || (getFrameBorders() && rCompare.getFrameBorders()
+ && *getFrameBorders() == *rCompare.getFrameBorders()))
+ && doForceToSingleDiscreteUnit() == rCompare.doForceToSingleDiscreteUnit();
+ }
+
+ return false;
+ }
+
+ void SdrFrameBorderPrimitive2D::get2DDecomposition(
+ Primitive2DDecompositionVisitor& rVisitor,
+ const geometry::ViewInformation2D& rViewInformation) const
+ {
+ if(doForceToSingleDiscreteUnit())
+ {
+ // Get the current DiscreteUnit, look at X and Y and use the maximum
+ const basegfx::B2DVector aDiscreteVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+ double fDiscreteUnit(std::min(fabs(aDiscreteVector.getX()), fabs(aDiscreteVector.getY())));
+
+ if(fDiscreteUnit <= mfMinimalNonZeroBorderWidth)
+ {
+ // no need to use it, reset
+ fDiscreteUnit = 0.0;
+ }
+
+ if(fDiscreteUnit != mfMinimalNonZeroBorderWidthUsedForDecompose)
+ {
+ // conditions of last local decomposition have changed, delete
+ // possible content
+ if(!getBuffered2DDecomposition().empty())
+ {
+ const_cast< SdrFrameBorderPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
+ }
+
+ // remember new conditions
+ const_cast< SdrFrameBorderPrimitive2D* >(this)->mfMinimalNonZeroBorderWidthUsedForDecompose = fDiscreteUnit;
+ }
+ }
+
+ // call parent. This will call back ::create2DDecomposition above
+ // where mfMinimalNonZeroBorderWidthUsedForDecompose will be used
+ // when doForceToSingleDiscreteUnit() is true
+ BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrFrameBorderPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRFRAMEBORDERTPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrgrafprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrgrafprimitive2d.cxx
new file mode 100644
index 000000000..f5ac21cfc
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrgrafprimitive2d.cxx
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrgrafprimitive2d.hxx>
+#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+namespace drawinglayer::primitive2d
+{
+void SdrGrafPrimitive2D::create2DDecomposition(
+ Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+{
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ const basegfx::B2DPolygon& aUnitOutline(basegfx::utils::createUnitPolygon());
+
+ // add fill, but only when graphic is transparent
+ if (!getSdrLFSTAttribute().getFill().isDefault() && isTransparent())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(aTransformed, getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+
+ // add graphic content
+ if (0 != getGraphicAttr().GetAlpha())
+ {
+ // standard graphic fill
+ const Primitive2DReference xGraphicContentPrimitive(
+ new GraphicPrimitive2D(getTransform(), getGraphicObject(), getGraphicAttr()));
+ aRetval.push_back(xGraphicContentPrimitive);
+ }
+
+ // add line
+ if (!getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // if line width is given, polygon needs to be grown by half of it to make the
+ // outline to be outside of the bitmap
+ if (0.0 != getSdrLFSTAttribute().getLine().getWidth())
+ {
+ // decompose to get scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // create expanded range (add relative half line width to unit rectangle)
+ double fHalfLineWidth(getSdrLFSTAttribute().getLine().getWidth() * 0.5);
+ double fScaleX(0.0 != aScale.getX() ? fHalfLineWidth / fabs(aScale.getX()) : 1.0);
+ double fScaleY(0.0 != aScale.getY() ? fHalfLineWidth / fabs(aScale.getY()) : 1.0);
+ const basegfx::B2DRange aExpandedRange(-fScaleX, -fScaleY, 1.0 + fScaleX,
+ 1.0 + fScaleY);
+ basegfx::B2DPolygon aExpandedUnitOutline(
+ basegfx::utils::createPolygonFromRect(aExpandedRange));
+
+ aExpandedUnitOutline.transform(getTransform());
+ aRetval.push_back(createPolygonLinePrimitive(aExpandedUnitOutline,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+ else
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(createPolygonLinePrimitive(aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+ }
+
+ // Soft edges should be before text, since text is not affected by soft edges
+ if (!aRetval.empty() && getSdrLFSTAttribute().getSoftEdgeRadius())
+ {
+ aRetval = createEmbeddedSoftEdgePrimitive(std::move(aRetval),
+ getSdrLFSTAttribute().getSoftEdgeRadius());
+ }
+
+ // add text
+ if (!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(createTextPrimitive(basegfx::B2DPolyPolygon(aUnitOutline), getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(), false, false));
+ }
+
+ // tdf#132199: put glow before shadow, to have shadow of the glow, not the opposite
+ if (!aRetval.empty() && !getSdrLFSTAttribute().getGlow().isDefault())
+ {
+ // glow
+ aRetval = createEmbeddedGlowPrimitive(std::move(aRetval), getSdrLFSTAttribute().getGlow());
+ }
+
+ // add shadow
+ if (!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(std::move(aRetval),
+ getSdrLFSTAttribute().getShadow(), getTransform());
+ }
+
+ rContainer.append(std::move(aRetval));
+}
+
+SdrGrafPrimitive2D::SdrGrafPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ const GraphicObject& rGraphicObject, const GraphicAttr& rGraphicAttr)
+ : maTransform(rTransform)
+ , maSdrLFSTAttribute(rSdrLFSTAttribute)
+ , maGraphicObject(rGraphicObject)
+ , maGraphicAttr(rGraphicAttr)
+{
+ // reset some values from GraphicAttr which are part of transformation already
+ maGraphicAttr.SetRotation(0_deg10);
+}
+
+bool SdrGrafPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+{
+ if (BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrGrafPrimitive2D& rCompare = static_cast<const SdrGrafPrimitive2D&>(rPrimitive);
+
+ return (getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute()
+ && getGraphicObject() == rCompare.getGraphicObject()
+ && getGraphicAttr() == rCompare.getGraphicAttr());
+ }
+
+ return false;
+}
+
+bool SdrGrafPrimitive2D::isTransparent() const
+{
+ return ((255 != getGraphicAttr().GetAlpha()) || (getGraphicObject().IsTransparent()));
+}
+
+// provide unique ID
+sal_uInt32 SdrGrafPrimitive2D::getPrimitive2DID() const
+{
+ return PRIMITIVE2D_ID_SDRGRAFPRIMITIVE2D;
+}
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrmeasureprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrmeasureprimitive2d.cxx
new file mode 100644
index 000000000..aada2aee0
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrmeasureprimitive2d.cxx
@@ -0,0 +1,498 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrmeasureprimitive2d.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <rtl/ref.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
+#include <osl/diagnose.h>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ Primitive2DReference SdrMeasurePrimitive2D::impCreatePart(
+ const attribute::SdrLineAttribute& rLineAttribute,
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const basegfx::B2DPoint& rStart,
+ const basegfx::B2DPoint& rEnd,
+ bool bLeftActive,
+ bool bRightActive) const
+ {
+ const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
+ basegfx::B2DPolygon aPolygon;
+
+ aPolygon.append(rStart);
+ aPolygon.append(rEnd);
+ aPolygon.transform(rObjectMatrix);
+
+ if(rLineStartEnd.isDefault() || (!bLeftActive && !bRightActive))
+ {
+ return createPolygonLinePrimitive(
+ aPolygon,
+ rLineAttribute,
+ attribute::SdrLineStartEndAttribute());
+ }
+
+ if(bLeftActive && bRightActive)
+ {
+ return createPolygonLinePrimitive(
+ aPolygon,
+ rLineAttribute,
+ rLineStartEnd);
+ }
+
+ const basegfx::B2DPolyPolygon aEmpty;
+ const attribute::SdrLineStartEndAttribute aLineStartEnd(
+ bLeftActive ? rLineStartEnd.getStartPolyPolygon() : aEmpty, bRightActive ? rLineStartEnd.getEndPolyPolygon() : aEmpty,
+ bLeftActive ? rLineStartEnd.getStartWidth() : 0.0, bRightActive ? rLineStartEnd.getEndWidth() : 0.0,
+ bLeftActive && rLineStartEnd.isStartActive(), bRightActive && rLineStartEnd.isEndActive(),
+ bLeftActive && rLineStartEnd.isStartCentered(), bRightActive && rLineStartEnd.isEndCentered());
+
+ return createPolygonLinePrimitive(
+ aPolygon,
+ rLineAttribute,
+ aLineStartEnd);
+ }
+
+ void SdrMeasurePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ rtl::Reference<SdrBlockTextPrimitive2D> xBlockText;
+ basegfx::B2DRange aTextRange;
+ const basegfx::B2DVector aLine(getEnd() - getStart());
+ const double fDistance(aLine.getLength());
+ const double fAngle(atan2(aLine.getY(), aLine.getX()));
+ bool bAutoUpsideDown(false);
+ const attribute::SdrTextAttribute rTextAttribute = getSdrLSTAttribute().getText();
+ const basegfx::B2DHomMatrix aObjectMatrix(
+ basegfx::utils::createShearXRotateTranslateB2DHomMatrix(0.0, fAngle, getStart()));
+
+ // prepare text, but do not add yet; it needs to be aligned to
+ // the line geometry
+ if(!rTextAttribute.isDefault())
+ {
+ basegfx::B2DHomMatrix aTextMatrix;
+ double fTestAngle(fAngle);
+
+ if(getTextRotation())
+ {
+ aTextMatrix.rotate(-M_PI_2);
+ fTestAngle -= (M_PI_2);
+
+ if(getTextAutoAngle() && fTestAngle < -M_PI)
+ {
+ fTestAngle += 2 * M_PI;
+ }
+ }
+
+ if(getTextAutoAngle())
+ {
+ if(fTestAngle > (M_PI / 4.0) || fTestAngle < (-M_PI * (3.0 / 4.0)))
+ {
+ bAutoUpsideDown = true;
+ }
+ }
+
+ // create primitive and get text range
+ xBlockText = new SdrBlockTextPrimitive2D(
+ &rTextAttribute.getSdrText(),
+ rTextAttribute.getOutlinerParaObject(),
+ aTextMatrix,
+ SDRTEXTHORZADJUST_CENTER,
+ SDRTEXTVERTADJUST_CENTER,
+ rTextAttribute.isScroll(),
+ false,
+ false,
+ false);
+
+ aTextRange = xBlockText->getB2DRange(aViewInformation);
+ }
+
+ // prepare line attribute and result
+ double fTextX;
+ double fTextY;
+ {
+ const attribute::SdrLineAttribute rLineAttribute(getSdrLSTAttribute().getLine());
+ bool bArrowsOutside(false);
+ bool bMainLineSplitted(false);
+ const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
+ double fStartArrowW(0.0);
+ double fStartArrowH(0.0);
+ double fEndArrowW(0.0);
+ double fEndArrowH(0.0);
+
+ if(!rLineStartEnd.isDefault())
+ {
+ if(rLineStartEnd.isStartActive())
+ {
+ const basegfx::B2DRange aArrowRange(basegfx::utils::getRange(rLineStartEnd.getStartPolyPolygon()));
+ fStartArrowW = rLineStartEnd.getStartWidth();
+ fStartArrowH = aArrowRange.getHeight() * fStartArrowW / aArrowRange.getWidth();
+
+ if(rLineStartEnd.isStartCentered())
+ {
+ fStartArrowH *= 0.5;
+ }
+ }
+
+ if(rLineStartEnd.isEndActive())
+ {
+ const basegfx::B2DRange aArrowRange(basegfx::utils::getRange(rLineStartEnd.getEndPolyPolygon()));
+ fEndArrowW = rLineStartEnd.getEndWidth();
+ fEndArrowH = aArrowRange.getHeight() * fEndArrowW / aArrowRange.getWidth();
+
+ if(rLineStartEnd.isEndCentered())
+ {
+ fEndArrowH *= 0.5;
+ }
+ }
+ }
+
+ const double fSpaceNeededByArrows(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.5));
+ const double fArrowsOutsideLen((fStartArrowH + fEndArrowH + fStartArrowW + fEndArrowW) * 0.5);
+ const double fHalfLineWidth(rLineAttribute.getWidth() * 0.5);
+
+ if(fSpaceNeededByArrows > fDistance)
+ {
+ bArrowsOutside = true;
+ }
+
+ MeasureTextPosition eHorizontal(getHorizontal());
+ MeasureTextPosition eVertical(getVertical());
+
+ if(MEASURETEXTPOSITION_AUTOMATIC == eVertical)
+ {
+ eVertical = MEASURETEXTPOSITION_NEGATIVE;
+ }
+
+ if(MEASURETEXTPOSITION_CENTERED == eVertical)
+ {
+ bMainLineSplitted = true;
+ }
+
+ if(MEASURETEXTPOSITION_AUTOMATIC == eHorizontal)
+ {
+ if(aTextRange.getWidth() > fDistance)
+ {
+ eHorizontal = MEASURETEXTPOSITION_NEGATIVE;
+ }
+ else
+ {
+ eHorizontal = MEASURETEXTPOSITION_CENTERED;
+ }
+
+ if(bMainLineSplitted)
+ {
+ if(aTextRange.getWidth() + fSpaceNeededByArrows > fDistance)
+ {
+ bArrowsOutside = true;
+ }
+ }
+ else
+ {
+ const double fSmallArrowNeed(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.125));
+
+ if(aTextRange.getWidth() + fSmallArrowNeed > fDistance)
+ {
+ bArrowsOutside = true;
+ }
+ }
+ }
+
+ if(MEASURETEXTPOSITION_CENTERED != eHorizontal)
+ {
+ bArrowsOutside = true;
+ }
+
+ // switch text above/below?
+ if(getBelow() || (bAutoUpsideDown && !getTextRotation()))
+ {
+ if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
+ {
+ eVertical = MEASURETEXTPOSITION_POSITIVE;
+ }
+ else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
+ {
+ eVertical = MEASURETEXTPOSITION_NEGATIVE;
+ }
+ }
+
+ const double fMainLineOffset(getBelow() ? getDistance() : -getDistance());
+ const basegfx::B2DPoint aMainLeft(0.0, fMainLineOffset);
+ const basegfx::B2DPoint aMainRight(fDistance, fMainLineOffset);
+
+ // main line
+ if(bArrowsOutside)
+ {
+ double fLenLeft(fArrowsOutsideLen);
+ double fLenRight(fArrowsOutsideLen);
+
+ if(!bMainLineSplitted)
+ {
+ if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
+ {
+ fLenLeft = fStartArrowH + aTextRange.getWidth();
+ }
+ else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
+ {
+ fLenRight = fEndArrowH + aTextRange.getWidth();
+ }
+ }
+
+ const basegfx::B2DPoint aMainLeftLeft(aMainLeft.getX() - fLenLeft, aMainLeft.getY());
+ const basegfx::B2DPoint aMainRightRight(aMainRight.getX() + fLenRight, aMainRight.getY());
+
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeftLeft, aMainLeft, false, true));
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainRight, aMainRightRight, true, false));
+
+ if(!bMainLineSplitted || MEASURETEXTPOSITION_CENTERED != eHorizontal)
+ {
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, false, false));
+ }
+ }
+ else
+ {
+ if(bMainLineSplitted)
+ {
+ const double fHalfLength((fDistance - (aTextRange.getWidth() + (fStartArrowH + fEndArrowH) * 0.25)) * 0.5);
+ const basegfx::B2DPoint aMainInnerLeft(aMainLeft.getX() + fHalfLength, aMainLeft.getY());
+ const basegfx::B2DPoint aMainInnerRight(aMainRight.getX() - fHalfLength, aMainRight.getY());
+
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainInnerLeft, true, false));
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainInnerRight, aMainRight, false, true));
+ }
+ else
+ {
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, true, true));
+ }
+ }
+
+ // left/right help line value preparation
+ const double fTopEdge(getBelow() ? getUpper() + getDistance() : -getUpper() - getDistance());
+ const double fBottomLeft(getBelow() ? getLower() - getLeftDelta() : getLeftDelta() - getLower());
+ const double fBottomRight(getBelow() ? getLower() - getRightDelta() : getRightDelta() - getLower());
+
+ // left help line
+ const basegfx::B2DPoint aLeftUp(0.0, fTopEdge);
+ const basegfx::B2DPoint aLeftDown(0.0, fBottomLeft);
+
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aLeftDown, aLeftUp, false, false));
+
+ // right help line
+ const basegfx::B2DPoint aRightUp(fDistance, fTopEdge);
+ const basegfx::B2DPoint aRightDown(fDistance, fBottomRight);
+
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aRightDown, aRightUp, false, false));
+
+ // text horizontal position
+ if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
+ {
+ // left
+ const double fSmall(fArrowsOutsideLen * 0.18);
+ fTextX = aMainLeft.getX() - (fStartArrowH + aTextRange.getWidth() + fSmall + fHalfLineWidth);
+
+ if(bMainLineSplitted)
+ {
+ fTextX -= (fArrowsOutsideLen - fStartArrowH);
+ }
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextX -= rTextAttribute.getTextRightDistance();
+ }
+ }
+ else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
+ {
+ // right
+ const double fSmall(fArrowsOutsideLen * 0.18);
+ fTextX = aMainRight.getX() + (fEndArrowH + fSmall + fHalfLineWidth);
+
+ if(bMainLineSplitted)
+ {
+ fTextX += (fArrowsOutsideLen - fEndArrowH);
+ }
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextX += rTextAttribute.getTextLeftDistance();
+ }
+ }
+ else // MEASURETEXTPOSITION_CENTERED
+ {
+ // centered
+ fTextX = aMainLeft.getX() + ((fDistance - aTextRange.getWidth()) * 0.5);
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextX += (rTextAttribute.getTextLeftDistance() - rTextAttribute.getTextRightDistance()) / 2L;
+ }
+ }
+
+ // text vertical position
+ if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
+ {
+ // top
+ const double fSmall(fArrowsOutsideLen * 0.10);
+ fTextY = aMainLeft.getY() - (aTextRange.getHeight() + fSmall + fHalfLineWidth);
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextY -= rTextAttribute.getTextLowerDistance();
+ }
+ }
+ else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
+ {
+ // bottom
+ const double fSmall(fArrowsOutsideLen * 0.10);
+ fTextY = aMainLeft.getY() + (fSmall + fHalfLineWidth);
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextY += rTextAttribute.getTextUpperDistance();
+ }
+ }
+ else // MEASURETEXTPOSITION_CENTERED
+ {
+ // centered
+ fTextY = aMainLeft.getY() - (aTextRange.getHeight() * 0.5);
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextY += (rTextAttribute.getTextUpperDistance() - rTextAttribute.getTextLowerDistance()) / 2L;
+ }
+ }
+ }
+
+ if(getSdrLSTAttribute().getLine().isDefault())
+ {
+ // embed line geometry to invisible (100% transparent) line group for HitTest
+ Primitive2DReference xHiddenLines(new HiddenGeometryPrimitive2D(std::move(aRetval)));
+
+ aRetval = Primitive2DContainer { xHiddenLines };
+ }
+
+ if(xBlockText.is())
+ {
+ // create transformation to text primitive end position
+ basegfx::B2DHomMatrix aChange;
+
+ // handle auto text rotation
+ if(bAutoUpsideDown)
+ {
+ aChange.rotate(M_PI);
+ }
+
+ // move from aTextRange.TopLeft to fTextX, fTextY
+ aChange.translate(fTextX - aTextRange.getMinX(), fTextY - aTextRange.getMinY());
+
+ // apply object matrix
+ aChange *= aObjectMatrix;
+
+ // apply to existing text primitive
+ rtl::Reference<SdrTextPrimitive2D> pNewBlockText = xBlockText->createTransformedClone(aChange);
+ OSL_ENSURE(pNewBlockText, "SdrMeasurePrimitive2D::create2DDecomposition: Could not create transformed clone of text primitive (!)");
+ xBlockText.clear();
+
+ // add to local primitives
+ aRetval.push_back(pNewBlockText);
+ }
+
+ // add shadow
+ if(!getSdrLSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrMeasurePrimitive2D::SdrMeasurePrimitive2D(
+ const attribute::SdrLineEffectsTextAttribute& rSdrLSTAttribute,
+ const basegfx::B2DPoint& rStart,
+ const basegfx::B2DPoint& rEnd,
+ MeasureTextPosition eHorizontal,
+ MeasureTextPosition eVertical,
+ double fDistance,
+ double fUpper,
+ double fLower,
+ double fLeftDelta,
+ double fRightDelta,
+ bool bBelow,
+ bool bTextRotation,
+ bool bTextAutoAngle)
+ : maSdrLSTAttribute(rSdrLSTAttribute),
+ maStart(rStart),
+ maEnd(rEnd),
+ meHorizontal(eHorizontal),
+ meVertical(eVertical),
+ mfDistance(fDistance),
+ mfUpper(fUpper),
+ mfLower(fLower),
+ mfLeftDelta(fLeftDelta),
+ mfRightDelta(fRightDelta),
+ mbBelow(bBelow),
+ mbTextRotation(bTextRotation),
+ mbTextAutoAngle(bTextAutoAngle)
+ {
+ }
+
+ bool SdrMeasurePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrMeasurePrimitive2D& rCompare = static_cast<const SdrMeasurePrimitive2D&>(rPrimitive);
+
+ return (getStart() == rCompare.getStart()
+ && getEnd() == rCompare.getEnd()
+ && getHorizontal() == rCompare.getHorizontal()
+ && getVertical() == rCompare.getVertical()
+ && getDistance() == rCompare.getDistance()
+ && getUpper() == rCompare.getUpper()
+ && getLower() == rCompare.getLower()
+ && getLeftDelta() == rCompare.getLeftDelta()
+ && getRightDelta() == rCompare.getRightDelta()
+ && getBelow() == rCompare.getBelow()
+ && getTextRotation() == rCompare.getTextRotation()
+ && getTextAutoAngle() == rCompare.getTextAutoAngle()
+ && getSdrLSTAttribute() == rCompare.getSdrLSTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrMeasurePrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrole2primitive2d.cxx b/svx/source/sdr/primitive2d/sdrole2primitive2d.cxx
new file mode 100644
index 000000000..e7576b498
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrole2primitive2d.cxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrole2primitive2d.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ SdrOle2Primitive2D::SdrOle2Primitive2D(
+ Primitive2DContainer&& rOLEContent,
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute)
+ : maOLEContent(std::move(rOLEContent)),
+ maTransform(rTransform),
+ maSdrLFSTAttribute(rSdrLFSTAttribute)
+ {
+ }
+
+ bool SdrOle2Primitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BasePrimitive2D::operator==(rPrimitive))
+ {
+ const SdrOle2Primitive2D& rCompare = static_cast<const SdrOle2Primitive2D&>(rPrimitive);
+
+ // #i108636# The standard operator== on two UNO sequences did not work as i
+ // would have expected; it just checks the .is() states and the data type
+ // of the sequence. What i need here is detection of equality of the whole
+ // sequence content, thus i need to use the arePrimitive2DSequencesEqual helper
+ // here instead of the operator== which lead to always returning false and thus
+ // always re-decompositions of the subcontent.
+ if(getOLEContent() == rCompare.getOLEContent()
+ && getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void SdrOle2Primitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ // to take care of getSdrLFSTAttribute() later, the same as in SdrGrafPrimitive2D::create2DDecomposition
+ // should happen. For the moment we only need the OLE itself
+ // Added complete primitive preparation using getSdrLFSTAttribute() now.
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ const basegfx::B2DPolygon& aUnitOutline(basegfx::utils::createUnitPolygon());
+
+ // add fill
+ if(!getSdrLFSTAttribute().getFill().isDefault())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+
+ // add line
+ // #i97981# condition was inverse to purpose. When being compatible to paint version,
+ // border needs to be suppressed
+ if(!getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // if line width is given, polygon needs to be grown by half of it to make the
+ // outline to be outside of the bitmap
+ if(0.0 != getSdrLFSTAttribute().getLine().getWidth())
+ {
+ // decompose to get scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // create expanded range (add relative half line width to unit rectangle)
+ double fHalfLineWidth(getSdrLFSTAttribute().getLine().getWidth() * 0.5);
+ double fScaleX(0.0 != aScale.getX() ? fHalfLineWidth / fabs(aScale.getX()) : 1.0);
+ double fScaleY(0.0 != aScale.getY() ? fHalfLineWidth / fabs(aScale.getY()) : 1.0);
+ const basegfx::B2DRange aExpandedRange(-fScaleX, -fScaleY, 1.0 + fScaleX, 1.0 + fScaleY);
+ basegfx::B2DPolygon aExpandedUnitOutline(basegfx::utils::createPolygonFromRect(aExpandedRange));
+
+ aExpandedUnitOutline.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aExpandedUnitOutline,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+ else
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+ }
+ else
+ {
+ // if initially no line is defined, create one for HitTest and BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+
+ // add graphic content
+ aRetval.append(getOLEContent());
+
+ // add text, no need to suppress to stay compatible since text was
+ // always supported by the old paints, too
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLFSTAttribute().getShadow());
+ }
+
+ rVisitor.visit(std::move(aRetval));
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrOle2Primitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDROLE2PRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrolecontentprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrolecontentprimitive2d.cxx
new file mode 100644
index 000000000..7edd0e601
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrolecontentprimitive2d.cxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrolecontentprimitive2d.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <svx/svdoole2.hxx>
+#include <vcl/svapp.hxx>
+#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <svtools/colorcfg.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrOleContentPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ const SdrOle2Obj* pSource = mpSdrOle2Obj.get();
+ bool bScaleContent(false);
+ Graphic aGraphic;
+
+ if(pSource)
+ {
+ const Graphic* pOLEGraphic = pSource->GetGraphic();
+
+ if(pOLEGraphic)
+ {
+ aGraphic = *pOLEGraphic;
+ bScaleContent = pSource->IsEmptyPresObj();
+ }
+ }
+#ifdef _WIN32 // Little point in displaying the "broken OLE" graphic on OSes that don't have real OLE, maybe?
+ if(GraphicType::NONE == aGraphic.GetType())
+ {
+ // no source, use fallback resource empty OLE graphic
+ aGraphic = SdrOle2Obj::GetEmptyOLEReplacementGraphic();
+ bScaleContent = true;
+ }
+#endif
+ if(GraphicType::NONE == aGraphic.GetType())
+ return;
+
+ const GraphicObject aGraphicObject(aGraphic);
+ const GraphicAttr aGraphicAttr;
+
+ if(bScaleContent)
+ {
+ // get transformation atoms
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getObjectTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // get PrefSize from the graphic in 100th mm
+ Size aPrefSize(aGraphic.GetPrefSize());
+
+ if(MapUnit::MapPixel == aGraphic.GetPrefMapMode().GetMapUnit())
+ {
+ aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM));
+ }
+ else
+ {
+ aPrefSize = OutputDevice::LogicToLogic(aPrefSize, aGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM));
+ }
+
+ const double fOffsetX((aScale.getX() - aPrefSize.getWidth()) / 2.0);
+ const double fOffsetY((aScale.getY() - aPrefSize.getHeight()) / 2.0);
+
+ if(basegfx::fTools::moreOrEqual(fOffsetX, 0.0) && basegfx::fTools::moreOrEqual(fOffsetY, 0.0))
+ {
+ // if content fits into frame, create it
+ basegfx::B2DHomMatrix aInnerObjectMatrix(basegfx::utils::createScaleTranslateB2DHomMatrix(
+ aPrefSize.getWidth(), aPrefSize.getHeight(), fOffsetX, fOffsetY));
+ aInnerObjectMatrix = basegfx::utils::createShearXRotateTranslateB2DHomMatrix(fShearX, fRotate, aTranslate)
+ * aInnerObjectMatrix;
+
+ const drawinglayer::primitive2d::Primitive2DReference aGraphicPrimitive(
+ new drawinglayer::primitive2d::GraphicPrimitive2D(
+ aInnerObjectMatrix,
+ aGraphicObject,
+ aGraphicAttr));
+ rContainer.push_back(aGraphicPrimitive);
+ }
+ }
+ else
+ {
+ // create graphic primitive for content
+ const drawinglayer::primitive2d::Primitive2DReference aGraphicPrimitive(
+ new drawinglayer::primitive2d::GraphicPrimitive2D(
+ getObjectTransform(),
+ aGraphicObject,
+ aGraphicAttr));
+ rContainer.push_back(aGraphicPrimitive);
+ }
+
+ // a standard gray outline is created for scaled content
+ if(!bScaleContent)
+ return;
+
+ const svtools::ColorConfig aColorConfig;
+ const svtools::ColorConfigValue aColor(aColorConfig.GetColorValue(svtools::OBJECTBOUNDARIES));
+
+ if(aColor.bIsVisible)
+ {
+ basegfx::B2DPolygon aOutline(basegfx::utils::createUnitPolygon());
+ const Color aVclColor(aColor.nColor);
+ aOutline.transform(getObjectTransform());
+ const drawinglayer::primitive2d::Primitive2DReference xOutline(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aVclColor.getBColor()));
+ rContainer.push_back(xOutline);
+ }
+ }
+
+ SdrOleContentPrimitive2D::SdrOleContentPrimitive2D(
+ const SdrOle2Obj& rSdrOle2Obj,
+ const basegfx::B2DHomMatrix& rObjectTransform,
+ sal_uInt32 nGraphicVersion
+ )
+ : mpSdrOle2Obj(const_cast< SdrOle2Obj* >(&rSdrOle2Obj)),
+ maObjectTransform(rObjectTransform),
+ mnGraphicVersion(nGraphicVersion)
+ {
+ }
+
+ bool SdrOleContentPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if( BufferedDecompositionPrimitive2D::operator==(rPrimitive) )
+ {
+ const SdrOleContentPrimitive2D& rCompare = static_cast<const SdrOleContentPrimitive2D&>(rPrimitive);
+ const bool bBothNot(!mpSdrOle2Obj.is() && !rCompare.mpSdrOle2Obj.is());
+ const bool bBothAndEqual(mpSdrOle2Obj.is() && rCompare.mpSdrOle2Obj.is()
+ && mpSdrOle2Obj.get() == rCompare.mpSdrOle2Obj.get());
+
+ return ((bBothNot || bBothAndEqual)
+ && getObjectTransform() == rCompare.getObjectTransform()
+
+ // #i104867# to find out if the Graphic content of the
+ // OLE has changed, use GraphicVersion number
+ && mnGraphicVersion == rCompare.mnGraphicVersion
+ );
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange SdrOleContentPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0);
+ aRange.transform(getObjectTransform());
+
+ return aRange;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrOleContentPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDROLECONTENTPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx
new file mode 100644
index 000000000..829525e2b
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrpathprimitive2d.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrPathPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // add fill
+ if(!getSdrLFSTAttribute().getFill().isDefault()
+ && getUnitPolyPolygon().isClosed())
+ {
+ // #i108255# no need to use correctOrientations here; target is
+ // straight visualisation
+ basegfx::B2DPolyPolygon aTransformed(getUnitPolyPolygon());
+ aTransformed.transform(getTransform());
+
+ // OperationSmiley: Check if a UnitDefinitionPolyPolygon is set
+ if(getUnitDefinitionPolyPolygon().count()
+ && getUnitDefinitionPolyPolygon() != getUnitPolyPolygon())
+ {
+ // if yes, use the B2DRange of it's transformed form
+ basegfx::B2DPolyPolygon aTransformedDefinition(getUnitDefinitionPolyPolygon());
+ aTransformedDefinition.transform(getTransform());
+
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ aTransformedDefinition.getB2DRange(),
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+ else
+ {
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+ }
+
+ // add line
+ if(getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // if initially no line is defined, create one for HitTest and BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ getUnitPolyPolygon(),
+ getTransform()));
+ }
+ else
+ {
+ Primitive2DContainer aTemp(getUnitPolyPolygon().count());
+
+ for(sal_uInt32 a(0); a < getUnitPolyPolygon().count(); a++)
+ {
+ basegfx::B2DPolygon aTransformed(getUnitPolyPolygon().getB2DPolygon(a));
+
+ aTransformed.transform(getTransform());
+ aTemp[a] = createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ getSdrLFSTAttribute().getLineStartEnd());
+ }
+
+ aRetval.append(aTemp);
+ }
+
+ // add text
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ getUnitPolyPolygon(),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLFSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrPathPrimitive2D::SdrPathPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
+ const basegfx::B2DPolyPolygon& rUnitDefinitionPolyPolygon)
+ : maTransform(rTransform),
+ maSdrLFSTAttribute(rSdrLFSTAttribute),
+ maUnitPolyPolygon(rUnitPolyPolygon),
+ maUnitDefinitionPolyPolygon(rUnitDefinitionPolyPolygon)
+ {
+ }
+
+ bool SdrPathPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrPathPrimitive2D& rCompare = static_cast<const SdrPathPrimitive2D&>(rPrimitive);
+
+ return (getUnitPolyPolygon() == rCompare.getUnitPolyPolygon()
+ && getUnitDefinitionPolyPolygon() == rCompare.getUnitDefinitionPolyPolygon()
+ && getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrPathPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRPATHPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrprimitivetools.cxx b/svx/source/sdr/primitive2d/sdrprimitivetools.cxx
new file mode 100644
index 000000000..6376fa796
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrprimitivetools.cxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrprimitivetools.hxx>
+#include <vcl/lazydelete.hxx>
+#include <vcl/BitmapTools.hxx>
+#include <mutex>
+
+
+// helper methods
+
+namespace drawinglayer::primitive2d
+{
+ BitmapEx createDefaultCross_3x3(const basegfx::BColor& rBColor)
+ {
+ static vcl::DeleteOnDeinit< BitmapEx > aRetVal(vcl::DeleteOnDeinitFlag::Empty);
+ static basegfx::BColor aBColor;
+ static std::mutex aMutex;
+
+ std::scoped_lock aGuard(aMutex);
+
+ if(!aRetVal.get() || rBColor != aBColor)
+ {
+ // copy values
+ aBColor = rBColor;
+
+ // create bitmap
+ Color c(aBColor);
+ sal_uInt8 r = c.GetRed();
+ sal_uInt8 g = c.GetGreen();
+ sal_uInt8 b = c.GetBlue();
+ sal_uInt8 a = 255;
+ const sal_uInt8 cross[] = {
+ 0, 0, 0, a, r, g, b, 0, 0, 0, 0, a,
+ r, g, b, 0, r, g, b, 0, r, g, b, 0,
+ 0, 0, 0, a, r, g, b, 0, 0, 0, 0, a
+ };
+ BitmapEx aBitmap = vcl::bitmap::CreateFromData(cross, 3, 3, 12, vcl::PixelFormat::N32_BPP);
+
+ // create and exchange at aRetVal
+ aRetVal.set(aBitmap);
+ }
+
+ return aRetVal.get() ? *aRetVal.get() : BitmapEx();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx
new file mode 100644
index 000000000..f289ea6bc
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrrectangleprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrRectanglePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ const basegfx::B2DPolygon aUnitOutline(basegfx::utils::createPolygonFromRect(
+ basegfx::B2DRange(0.0, 0.0, 1.0, 1.0),
+ getCornerRadiusX(),
+ getCornerRadiusY()));
+
+ // add fill
+ if(!getSdrLFSTAttribute().getFill().isDefault())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+ else if(getForceFillForHitTest())
+ {
+ // if no fill and it's a text frame, create a fill for HitTest and
+ // BoundRect fallback
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ true,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+
+ // add line
+ if(!getSdrLFSTAttribute().getLine().isDefault())
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+ else if(!getForceFillForHitTest())
+ {
+ // if initially no line is defined and it's not a text frame, create
+ // a line for HitTest and BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+
+ // add text
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLFSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrRectanglePrimitive2D::SdrRectanglePrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ double fCornerRadiusX,
+ double fCornerRadiusY,
+ bool bForceFillForHitTest)
+ : maTransform(rTransform),
+ maSdrLFSTAttribute(rSdrLFSTAttribute),
+ mfCornerRadiusX(fCornerRadiusX),
+ mfCornerRadiusY(fCornerRadiusY),
+ mbForceFillForHitTest(bForceFillForHitTest)
+ {
+ }
+
+ bool SdrRectanglePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrRectanglePrimitive2D& rCompare = static_cast<const SdrRectanglePrimitive2D&>(rPrimitive);
+
+ return (getCornerRadiusX() == rCompare.getCornerRadiusX()
+ && getCornerRadiusY() == rCompare.getCornerRadiusY()
+ && getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute()
+ && getForceFillForHitTest() == rCompare.getForceFillForHitTest());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrRectanglePrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRRECTANGLEPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx
new file mode 100644
index 000000000..6311c123d
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx
@@ -0,0 +1,545 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/flditem.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdoutl.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <osl/diagnose.h>
+
+
+using namespace com::sun::star;
+
+
+namespace
+{
+ sal_Int16 getPageNumber(const uno::Reference< drawing::XDrawPage >& rxDrawPage)
+ {
+ sal_Int16 nRetval(0);
+ uno::Reference< beans::XPropertySet > xSet(rxDrawPage, uno::UNO_QUERY);
+
+ if (xSet.is())
+ {
+ try
+ {
+ const uno::Any aNumber(xSet->getPropertyValue("Number"));
+ aNumber >>= nRetval;
+ }
+ catch(const uno::Exception&)
+ {
+ OSL_ASSERT(false);
+ }
+ }
+
+ return nRetval;
+ }
+
+ sal_Int16 getPageCount(const uno::Reference< drawing::XDrawPage >& rxDrawPage)
+ {
+ sal_Int16 nRetval(0);
+ SdrPage* pPage = GetSdrPageFromXDrawPage(rxDrawPage);
+
+ if(pPage)
+ {
+ if( (pPage->GetPageNum() == 0) && !pPage->IsMasterPage() )
+ {
+ // handout page!
+ return pPage->getSdrModelFromSdrPage().getHandoutPageCount();
+ }
+ else
+ {
+ const sal_uInt16 nPageCount(pPage->getSdrModelFromSdrPage().GetPageCount());
+ nRetval = (static_cast<sal_Int16>(nPageCount) - 1) / 2;
+ }
+ }
+
+ return nRetval;
+ }
+} // end of anonymous namespace
+
+
+namespace drawinglayer::primitive2d
+{
+ // support for XTEXT_PAINTSHAPE_BEGIN/XTEXT_PAINTSHAPE_END Metafile comments
+ // for slideshow. This uses TextHierarchyBlockPrimitive2D to mark a text block.
+ // ATM there is only one text block per SdrObject, this may get more in the future
+ void SdrTextPrimitive2D::encapsulateWithTextHierarchyBlockPrimitive2D(Primitive2DContainer& rContainer, Primitive2DContainer&& aCandidate)
+ {
+ rContainer.push_back(new TextHierarchyBlockPrimitive2D(drawinglayer::primitive2d::Primitive2DContainer(aCandidate)));
+ }
+
+ SdrTextPrimitive2D::SdrTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject)
+ : mrSdrText(const_cast< SdrText* >(pSdrText)),
+ maOutlinerParaObject(rOutlinerParaObject),
+ mnLastPageNumber(0),
+ mnLastPageCount(0),
+ mbContainsPageField(false),
+ mbContainsPageCountField(false),
+ mbContainsOtherFields(false)
+ {
+ const EditTextObject& rETO = maOutlinerParaObject.GetTextObject();
+
+ mbContainsPageField = rETO.HasField(SvxPageField::CLASS_ID);
+ mbContainsPageCountField = rETO.HasField(SvxPagesField::CLASS_ID);
+ mbContainsOtherFields = rETO.HasField(SvxHeaderField::CLASS_ID)
+ || rETO.HasField(SvxFooterField::CLASS_ID)
+ || rETO.HasField(SvxDateTimeField::CLASS_ID)
+ || rETO.HasField(SvxAuthorField::CLASS_ID);
+ }
+
+ const SdrText* SdrTextPrimitive2D::getSdrText() const { return mrSdrText.get(); }
+
+ bool SdrTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrTextPrimitive2D& rCompare = static_cast<const SdrTextPrimitive2D&>(rPrimitive);
+
+ return (
+
+ // compare OPO and content, but not WrongList
+ getOutlinerParaObject() == rCompare.getOutlinerParaObject()
+
+ // also compare WrongList (not-persistent data, but visualized)
+ && getOutlinerParaObject().isWrongListEqual(rCompare.getOutlinerParaObject()));
+ }
+
+ return false;
+ }
+
+ void SdrTextPrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
+ {
+ uno::Reference< drawing::XDrawPage > xCurrentlyVisualizingPage;
+ bool bCurrentlyVisualizingPageIsSet(false);
+ Color aNewTextBackgroundColor;
+ bool bNewTextBackgroundColorIsSet(false);
+ sal_Int16 nCurrentlyValidPageNumber(0);
+ sal_Int16 nCurrentlyValidPageCount(0);
+
+ if(!getBuffered2DDecomposition().empty())
+ {
+ bool bDoDelete(false);
+
+ // check visualized page
+ if(mbContainsPageField || mbContainsPageCountField || mbContainsOtherFields)
+ {
+ // get visualized page and remember
+ xCurrentlyVisualizingPage = rViewInformation.getVisualizedPage();
+ bCurrentlyVisualizingPageIsSet = true;
+
+ if(xCurrentlyVisualizingPage != mxLastVisualizingPage)
+ {
+ bDoDelete = true;
+ }
+
+ // #i98870# check visualized PageNumber
+ if(!bDoDelete && mbContainsPageField)
+ {
+ nCurrentlyValidPageNumber = getPageNumber(xCurrentlyVisualizingPage);
+
+ if(nCurrentlyValidPageNumber != mnLastPageNumber)
+ {
+ bDoDelete = true;
+ }
+ }
+
+ // #i98870# check visualized PageCount, too
+ if(!bDoDelete && mbContainsPageCountField)
+ {
+ nCurrentlyValidPageCount = getPageCount(xCurrentlyVisualizingPage);
+
+ if(nCurrentlyValidPageCount != mnLastPageCount)
+ {
+ bDoDelete = true;
+ }
+ }
+ }
+
+ // #i101443# check change of TextBackgroundolor
+ if(!bDoDelete && getSdrText())
+ {
+ SdrOutliner& rDrawOutliner = getSdrText()->GetObject().getSdrModelFromSdrObject().GetDrawOutliner();
+ aNewTextBackgroundColor = rDrawOutliner.GetBackgroundColor();
+ bNewTextBackgroundColorIsSet = true;
+
+ if(aNewTextBackgroundColor != maLastTextBackgroundColor)
+ {
+ bDoDelete = true;
+ }
+ }
+
+ if(bDoDelete)
+ {
+ const_cast< SdrTextPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
+ }
+ }
+
+ if(getBuffered2DDecomposition().empty())
+ {
+ if(!bCurrentlyVisualizingPageIsSet && mbContainsPageField)
+ {
+ xCurrentlyVisualizingPage = rViewInformation.getVisualizedPage();
+ }
+
+ if(!nCurrentlyValidPageNumber && mbContainsPageField)
+ {
+ nCurrentlyValidPageNumber = getPageNumber(xCurrentlyVisualizingPage);
+ }
+
+ if(!nCurrentlyValidPageCount && mbContainsPageCountField)
+ {
+ nCurrentlyValidPageCount = getPageCount(xCurrentlyVisualizingPage);
+ }
+
+ if(!bNewTextBackgroundColorIsSet && getSdrText())
+ {
+ SdrOutliner& rDrawOutliner = getSdrText()->GetObject().getSdrModelFromSdrObject().GetDrawOutliner();
+ aNewTextBackgroundColor = rDrawOutliner.GetBackgroundColor();
+ }
+
+ const_cast< SdrTextPrimitive2D* >(this)->mxLastVisualizingPage = xCurrentlyVisualizingPage;
+ const_cast< SdrTextPrimitive2D* >(this)->mnLastPageNumber = nCurrentlyValidPageNumber;
+ const_cast< SdrTextPrimitive2D* >(this)->mnLastPageCount = nCurrentlyValidPageCount;
+ const_cast< SdrTextPrimitive2D* >(this)->maLastTextBackgroundColor = aNewTextBackgroundColor;
+ }
+
+ // call parent
+ BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
+ }
+
+
+
+
+ void SdrContourTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposeContourTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ SdrContourTextPrimitive2D::SdrContourTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
+ const basegfx::B2DHomMatrix& rObjectTransform)
+ : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+ maUnitPolyPolygon(rUnitPolyPolygon),
+ maObjectTransform(rObjectTransform)
+ {
+ }
+
+ bool SdrContourTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrContourTextPrimitive2D& rCompare = static_cast<const SdrContourTextPrimitive2D&>(rPrimitive);
+
+ return (getUnitPolyPolygon() == rCompare.getUnitPolyPolygon()
+ && getObjectTransform() == rCompare.getObjectTransform());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrContourTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+ {
+ return new SdrContourTextPrimitive2D(
+ getSdrText(),
+ getOutlinerParaObject(),
+ getUnitPolyPolygon(),
+ rTransform * getObjectTransform());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrContourTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCONTOURTEXTPRIMITIVE2D;
+ }
+
+
+
+ void SdrPathTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposePathTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ SdrPathTextPrimitive2D::SdrPathTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ const basegfx::B2DPolyPolygon& rPathPolyPolygon,
+ const attribute::SdrFormTextAttribute& rSdrFormTextAttribute)
+ : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+ maPathPolyPolygon(rPathPolyPolygon),
+ maSdrFormTextAttribute(rSdrFormTextAttribute)
+ {
+ }
+
+ bool SdrPathTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrPathTextPrimitive2D& rCompare = static_cast<const SdrPathTextPrimitive2D&>(rPrimitive);
+
+ return (getPathPolyPolygon() == rCompare.getPathPolyPolygon()
+ && getSdrFormTextAttribute() == rCompare.getSdrFormTextAttribute());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrPathTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+ {
+ basegfx::B2DPolyPolygon aNewPolyPolygon(getPathPolyPolygon());
+ aNewPolyPolygon.transform(rTransform);
+
+ return new SdrPathTextPrimitive2D(
+ getSdrText(),
+ getOutlinerParaObject(),
+ aNewPolyPolygon,
+ getSdrFormTextAttribute());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrPathTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRPATHTEXTPRIMITIVE2D;
+ }
+
+
+
+ void SdrBlockTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposeBlockTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ SdrBlockTextPrimitive2D::SdrBlockTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ const basegfx::B2DHomMatrix& rTextRangeTransform,
+ SdrTextHorzAdjust aSdrTextHorzAdjust,
+ SdrTextVertAdjust aSdrTextVertAdjust,
+ bool bFixedCellHeight,
+ bool bUnlimitedPage,
+ bool bCellText,
+ bool bWordWrap)
+ : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+ maTextRangeTransform(rTextRangeTransform),
+ maSdrTextHorzAdjust(aSdrTextHorzAdjust),
+ maSdrTextVertAdjust(aSdrTextVertAdjust),
+ mbFixedCellHeight(bFixedCellHeight),
+ mbUnlimitedPage(bUnlimitedPage),
+ mbCellText(bCellText),
+ mbWordWrap(bWordWrap)
+ {
+ }
+
+ bool SdrBlockTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrBlockTextPrimitive2D& rCompare = static_cast<const SdrBlockTextPrimitive2D&>(rPrimitive);
+
+ return (getTextRangeTransform() == rCompare.getTextRangeTransform()
+ && getSdrTextHorzAdjust() == rCompare.getSdrTextHorzAdjust()
+ && getSdrTextVertAdjust() == rCompare.getSdrTextVertAdjust()
+ && isFixedCellHeight() == rCompare.isFixedCellHeight()
+ && getUnlimitedPage() == rCompare.getUnlimitedPage()
+ && getCellText() == rCompare.getCellText()
+ && getWordWrap() == rCompare.getWordWrap());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrBlockTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+ {
+ return new SdrBlockTextPrimitive2D(
+ getSdrText(),
+ getOutlinerParaObject(),
+ rTransform * getTextRangeTransform(),
+ getSdrTextHorzAdjust(),
+ getSdrTextVertAdjust(),
+ isFixedCellHeight(),
+ getUnlimitedPage(),
+ getCellText(),
+ getWordWrap());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrBlockTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRBLOCKTEXTPRIMITIVE2D;
+ }
+
+
+
+ void SdrAutoFitTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposeAutoFitTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ SdrAutoFitTextPrimitive2D::SdrAutoFitTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rParaObj,
+ const ::basegfx::B2DHomMatrix& rTextRangeTransform,
+ bool bWordWrap)
+ : SdrTextPrimitive2D(pSdrText, rParaObj),
+ maTextRangeTransform(rTextRangeTransform),
+ mbWordWrap(bWordWrap)
+ {
+ }
+
+ bool SdrAutoFitTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrBlockTextPrimitive2D& rCompare = static_cast<const SdrBlockTextPrimitive2D&>(rPrimitive);
+
+ return (getTextRangeTransform() == rCompare.getTextRangeTransform()
+ && getWordWrap() == rCompare.getWordWrap());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrAutoFitTextPrimitive2D::createTransformedClone(const ::basegfx::B2DHomMatrix& rTransform) const
+ {
+ return new SdrAutoFitTextPrimitive2D(getSdrText(), getOutlinerParaObject(), rTransform * getTextRangeTransform(), getWordWrap());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrAutoFitTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRAUTOFITTEXTPRIMITIVE2D;
+ }
+
+
+
+
+ SdrChainedTextPrimitive2D::SdrChainedTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ const basegfx::B2DHomMatrix& rTextRangeTransform)
+ : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+ maTextRangeTransform(rTextRangeTransform)
+ { }
+
+ void SdrChainedTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposeChainedTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ bool SdrChainedTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrBlockTextPrimitive2D& rCompare = static_cast<const SdrBlockTextPrimitive2D&>(rPrimitive);
+
+ return (getTextRangeTransform() == rCompare.getTextRangeTransform());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrChainedTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+ {
+ return new SdrChainedTextPrimitive2D(getSdrText(), getOutlinerParaObject(), rTransform * getTextRangeTransform());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrChainedTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCHAINEDTEXTPRIMITIVE2D;
+ }
+
+
+ void SdrStretchTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposeStretchTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ SdrStretchTextPrimitive2D::SdrStretchTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ const basegfx::B2DHomMatrix& rTextRangeTransform,
+ bool bFixedCellHeight)
+ : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+ maTextRangeTransform(rTextRangeTransform),
+ mbFixedCellHeight(bFixedCellHeight)
+ {
+ }
+
+ bool SdrStretchTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrStretchTextPrimitive2D& rCompare = static_cast<const SdrStretchTextPrimitive2D&>(rPrimitive);
+
+ return (getTextRangeTransform() == rCompare.getTextRangeTransform()
+ && isFixedCellHeight() == rCompare.isFixedCellHeight());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrStretchTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+ {
+ return new SdrStretchTextPrimitive2D(
+ getSdrText(),
+ getOutlinerParaObject(),
+ rTransform * getTextRangeTransform(),
+ isFixedCellHeight());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrStretchTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRSTRETCHTEXTPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive3d/sdrattributecreator3d.cxx b/svx/source/sdr/primitive3d/sdrattributecreator3d.cxx
new file mode 100644
index 000000000..6bf8f8c6e
--- /dev/null
+++ b/svx/source/sdr/primitive3d/sdrattributecreator3d.cxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+#include <svx/svx3ditems.hxx>
+#include <svl/itemset.hxx>
+#include <com/sun/star/drawing/NormalsKind.hpp>
+#include <com/sun/star/drawing/TextureProjectionMode.hpp>
+#include <com/sun/star/drawing/TextureKind2.hpp>
+#include <com/sun/star/drawing/TextureMode.hpp>
+#include <svx/xflclit.hxx>
+#include <drawinglayer/attribute/materialattribute3d.hxx>
+#include <drawinglayer/attribute/sdrobjectattribute3d.hxx>
+
+
+namespace drawinglayer::primitive2d
+{
+ attribute::Sdr3DObjectAttribute createNewSdr3DObjectAttribute(const SfxItemSet& rSet)
+ {
+ // get NormalsKind
+ css::drawing::NormalsKind aNormalsKind(css::drawing::NormalsKind_SPECIFIC);
+ const sal_uInt16 nNormalsValue(rSet.Get(SDRATTR_3DOBJ_NORMALS_KIND).GetValue());
+
+ if(1 == nNormalsValue)
+ {
+ aNormalsKind = css::drawing::NormalsKind_FLAT;
+ }
+ else if(2 == nNormalsValue)
+ {
+ aNormalsKind = css::drawing::NormalsKind_SPHERE;
+ }
+
+ // get NormalsInvert flag
+ const bool bInvertNormals(rSet.Get(SDRATTR_3DOBJ_NORMALS_INVERT).GetValue());
+
+ // get TextureProjectionX
+ css::drawing::TextureProjectionMode aTextureProjectionX(css::drawing::TextureProjectionMode_OBJECTSPECIFIC);
+ const sal_uInt16 nTextureValueX(rSet.Get(SDRATTR_3DOBJ_TEXTURE_PROJ_X).GetValue());
+
+ if(1 == nTextureValueX)
+ {
+ aTextureProjectionX = css::drawing::TextureProjectionMode_PARALLEL;
+ }
+ else if(2 == nTextureValueX)
+ {
+ aTextureProjectionX = css::drawing::TextureProjectionMode_SPHERE;
+ }
+
+ // get TextureProjectionY
+ css::drawing::TextureProjectionMode aTextureProjectionY(css::drawing::TextureProjectionMode_OBJECTSPECIFIC);
+ const sal_uInt16 nTextureValueY(rSet.Get(SDRATTR_3DOBJ_TEXTURE_PROJ_Y).GetValue());
+
+ if(1 == nTextureValueY)
+ {
+ aTextureProjectionY = css::drawing::TextureProjectionMode_PARALLEL;
+ }
+ else if(2 == nTextureValueY)
+ {
+ aTextureProjectionY = css::drawing::TextureProjectionMode_SPHERE;
+ }
+
+ // get DoubleSided flag
+ const bool bDoubleSided(rSet.Get(SDRATTR_3DOBJ_DOUBLE_SIDED).GetValue());
+
+ // get Shadow3D flag
+ const bool bShadow3D(rSet.Get(SDRATTR_3DOBJ_SHADOW_3D).GetValue());
+
+ // get TextureFilter flag
+ const bool bTextureFilter(rSet.Get(SDRATTR_3DOBJ_TEXTURE_FILTER).GetValue());
+
+ // get texture kind
+ // TextureKind: 1 == Base3DTextureLuminance, 2 == Base3DTextureIntensity, 3 == Base3DTextureColor
+ css::drawing::TextureKind2 aTextureKind(css::drawing::TextureKind2_LUMINANCE);
+ const sal_uInt16 nTextureKind(rSet.Get(SDRATTR_3DOBJ_TEXTURE_KIND).GetValue());
+
+ if(2 == nTextureKind)
+ {
+ aTextureKind = css::drawing::TextureKind2_INTENSITY;
+ }
+ else if(3 == nTextureKind)
+ {
+ aTextureKind = css::drawing::TextureKind2_COLOR;
+ }
+
+ // get texture mode
+ // TextureMode: 1 == Base3DTextureReplace, 2 == Base3DTextureModulate, 3 == Base3DTextureBlend
+ css::drawing::TextureMode aTextureMode(css::drawing::TextureMode_REPLACE);
+ const sal_uInt16 nTextureMode(rSet.Get(SDRATTR_3DOBJ_TEXTURE_MODE).GetValue());
+
+ if(2 == nTextureMode)
+ {
+ aTextureMode = css::drawing::TextureMode_MODULATE;
+ }
+ else if(3 == nTextureMode)
+ {
+ aTextureMode = css::drawing::TextureMode_BLEND;
+ }
+
+ // get object color
+ const ::basegfx::BColor aObjectColor(rSet.Get(XATTR_FILLCOLOR).GetColorValue().getBColor());
+
+ // get specular color
+ const ::basegfx::BColor aSpecular(rSet.Get(SDRATTR_3DOBJ_MAT_SPECULAR).GetValue().getBColor());
+
+ // get emissive color
+ const ::basegfx::BColor aEmission(rSet.Get(SDRATTR_3DOBJ_MAT_EMISSION).GetValue().getBColor());
+
+ // get specular intensity
+ sal_uInt16 nSpecularIntensity(rSet.Get(SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY).GetValue());
+
+ if(nSpecularIntensity > 128)
+ {
+ nSpecularIntensity = 128;
+ }
+
+ // get reduced line geometry
+ const bool bReducedLineGeometry(rSet.Get(SDRATTR_3DOBJ_REDUCED_LINE_GEOMETRY).GetValue());
+
+ // prepare material
+ attribute::MaterialAttribute3D aMaterial(aObjectColor, aSpecular, aEmission, nSpecularIntensity);
+
+ return attribute::Sdr3DObjectAttribute(
+ aNormalsKind, aTextureProjectionX, aTextureProjectionY,
+ aTextureKind, aTextureMode, aMaterial,
+ bInvertNormals, bDoubleSided, bShadow3D, bTextureFilter, bReducedLineGeometry);
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/attributeproperties.cxx b/svx/source/sdr/properties/attributeproperties.cxx
new file mode 100644
index 000000000..7f141b8f6
--- /dev/null
+++ b/svx/source/sdr/properties/attributeproperties.cxx
@@ -0,0 +1,541 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/attributeproperties.hxx>
+#include <tools/debug.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svl/whiter.hxx>
+#include <svl/poolitem.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svddef.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <osl/diagnose.h>
+
+namespace sdr::properties
+{
+ void AttributeProperties::ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
+ {
+ if(HasSfxItemSet() && mpStyleSheet)
+ {
+ // Delete hard attributes where items are set in the style sheet
+ if(!bDontRemoveHardAttr)
+ {
+ const SfxItemSet& rStyle = mpStyleSheet->GetItemSet();
+ SfxWhichIter aIter(rStyle);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while(nWhich)
+ {
+ if(SfxItemState::SET == aIter.GetItemState())
+ {
+ mxItemSet->ClearItem(nWhich);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+
+ // set new stylesheet as parent
+ mxItemSet->SetParent(&mpStyleSheet->GetItemSet());
+ }
+ else
+ {
+ OSL_ENSURE(false, "ImpSetParentAtSfxItemSet called without SfxItemSet/SfxStyleSheet (!)");
+ }
+ }
+
+ void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
+ {
+ // test if old StyleSheet is cleared, else it would be lost
+ // after this method -> memory leak (!)
+ DBG_ASSERT(!mpStyleSheet, "Old style sheet not deleted before setting new one (!)");
+
+ if(!pNewStyleSheet)
+ return;
+
+ // local remember
+ mpStyleSheet = pNewStyleSheet;
+
+ if(HasSfxItemSet())
+ {
+ // register as listener
+ StartListening(*pNewStyleSheet->GetPool());
+ StartListening(*pNewStyleSheet);
+
+ // only apply the following when we have an SfxItemSet already, else
+ if(GetStyleSheet())
+ {
+ ImpSetParentAtSfxItemSet(bDontRemoveHardAttr);
+ }
+ }
+ }
+
+ void AttributeProperties::ImpRemoveStyleSheet()
+ {
+ // Check type since it is destroyed when the type is deleted
+ if(GetStyleSheet() && mpStyleSheet)
+ {
+ EndListening(*mpStyleSheet);
+ if (auto const pool = mpStyleSheet->GetPool()) { // TTTT
+ EndListening(*pool);
+ }
+
+ // reset parent of ItemSet
+ if(HasSfxItemSet())
+ {
+ mxItemSet->SetParent(nullptr);
+ }
+
+ SdrObject& rObj = GetSdrObject();
+ rObj.SetBoundRectDirty();
+ rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+ }
+
+ mpStyleSheet = nullptr;
+ }
+
+ // create a new itemset
+ SfxItemSet AttributeProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool,
+
+ // ranges from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST>);
+ }
+
+ AttributeProperties::AttributeProperties(SdrObject& rObj)
+ : DefaultProperties(rObj),
+ mpStyleSheet(nullptr)
+ {
+ // Do nothing else, esp. do *not* try to get and set
+ // a default SfxStyle sheet. Nothing is allowed to be done
+ // that may lead to calls to virtual functions like
+ // CreateObjectSpecificItemSet - these would go *wrong*.
+ // Thus the rest is lazy-init from here.
+ }
+
+ AttributeProperties::AttributeProperties(const AttributeProperties& rProps, SdrObject& rObj)
+ : DefaultProperties(rProps, rObj),
+ mpStyleSheet(nullptr)
+ {
+ SfxStyleSheet* pTargetStyleSheet(rProps.GetStyleSheet());
+
+ if(pTargetStyleSheet)
+ {
+ const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
+
+ if(bModelChange)
+ {
+ // tdf#117506
+ // The error shows that it is definitely necessary to solve this problem.
+ // Interestingly I already had a note here for 'work needed'.
+ // Checked in libreoffice-6-0 what happened there. In principle, the whole
+ // ::Clone of SdrPage and SdrObject happened in the same SdrModel, only
+ // afterwards a ::SetModel was used at the cloned SdrPage which went through
+ // all layers. The StyleSheet-problem was solved in
+ // AttributeProperties::MoveToItemPool at the end. There, a StyleSheet with the
+ // same name was searched for in the target-SdrModel.
+ // Start by resetting the current TargetStyleSheet so that nothing goes wrong
+ // when we do not find a fitting TargetStyleSheet.
+ // Note: The test for SdrModelChange above was wrong (compared the already set
+ // new SdrObject), so this never triggered and pTargetStyleSheet was never set to
+ // nullptr before. This means that a StyleSheet from another SdrModel was used
+ // what of course is very dangerous. Interestingly did not crash since when that
+ // other SdrModel was destroyed the ::Notify mechanism still worked reliably
+ // and de-connected this Properties successfully from the alien-StyleSheet.
+ pTargetStyleSheet = nullptr;
+
+ // Check if we have a TargetStyleSheetPool at the target-SdrModel. This *should*
+ // be the case already (SdrModel::Merge and SdDrawDocument::InsertBookmarkAsPage
+ // have already cloned the StyleSheets to the target-SdrModel when used in Draw/impress).
+ // If none is found, ImpGetDefaultStyleSheet will be used to set a 'default'
+ // StyleSheet as StyleSheet implicitly later (that's what happened in the task,
+ // thus the FillStyle changed to the 'default' Blue).
+ // Note: It *may* be necessary to do more for StyleSheets, e.g. clone/copy the
+ // StyleSheet Hierarchy from the source SdrModel and/or add the Items from there
+ // as hard attributes. If needed, have a look at the older AttributeProperties::SetModel
+ // implementation from e.g. libreoffice-6-0.
+ SfxStyleSheetBasePool* pTargetStyleSheetPool(rObj.getSdrModelFromSdrObject().GetStyleSheetPool());
+
+ if(nullptr != pTargetStyleSheetPool)
+ {
+ // If we have a TargetStyleSheetPool, search for the used StyleSheet
+ // in the target SdrModel using the Name from the original StyleSheet
+ // in the source-SdrModel.
+ pTargetStyleSheet = dynamic_cast< SfxStyleSheet* >(
+ pTargetStyleSheetPool->Find(
+ rProps.GetStyleSheet()->GetName(),
+ SfxStyleFamily::All));
+ }
+ }
+ }
+
+ if(!pTargetStyleSheet)
+ return;
+
+ if(HasSfxItemSet())
+ {
+ // The SfxItemSet has been cloned and exists,
+ // we can directly set the SfxStyleSheet at it
+ ImpAddStyleSheet(pTargetStyleSheet, true);
+ }
+ else
+ {
+ // No SfxItemSet exists yet (there is none in
+ // the source, so none was cloned). Remember the
+ // SfxStyleSheet to set it when the SfxItemSet
+ // got constructed on-demand
+ mpStyleSheet = pTargetStyleSheet;
+ }
+ }
+
+ AttributeProperties::~AttributeProperties()
+ {
+ ImpRemoveStyleSheet();
+ }
+
+ std::unique_ptr<BaseProperties> AttributeProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new AttributeProperties(*this, rObj));
+ }
+
+ const SfxItemSet& AttributeProperties::GetObjectItemSet() const
+ {
+ // remember if we had a SfxItemSet already
+ const bool bHadSfxItemSet(HasSfxItemSet());
+
+ // call parent - this will guarantee SfxItemSet existence
+ DefaultProperties::GetObjectItemSet();
+
+ if(!bHadSfxItemSet)
+ {
+ // need to take care for SfxStyleSheet for newly
+ // created SfxItemSet
+ if(nullptr == mpStyleSheet)
+ {
+ // Set missing defaults without removal of hard attributes.
+ // This is more complicated historically than I first thought:
+ // Originally for GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj
+ // SetStyleSheet(..., false) was used, while for GetDefaultStyleSheet
+ // SetStyleSheet(..., true) was used. Thus, for SdrGrafObj and SdrOle2Obj
+ // bDontRemoveHardAttr == false -> *do* delete hard attributes was used.
+ // This was probably not done by purpose, adding the method
+ // GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj additionally to
+ // GetDefaultStyleSheet was an enhancement to allow for SdrGrafObj/SdrOle2Obj
+ // with full AttributeSet (adding e.g. FillAttributes). To stay as compatible
+ // as possible these SdrObjects got a new default-StyleSheet.
+ // There is no reason to delete the HardAttributes and it anyways has only
+ // AFAIK effects on a single Item - the SdrTextHorzAdjustItem. To get things
+ // unified I will stay with not deleting the HardAttributes and adapt the
+ // UnitTests in CppunitTest_sd_import_tests accordingly.
+ const_cast< AttributeProperties* >(this)->applyDefaultStyleSheetFromSdrModel();
+ }
+ else
+ {
+ // Late-Init of setting parent to SfxStyleSheet after
+ // it's creation. Can only happen from copy-constructor
+ // (where creation of SfxItemSet is avoided due to the
+ // problem with constructors and virtual functions in C++),
+ // thus DontRemoveHardAttr is not needed.
+ const_cast< AttributeProperties* >(this)->SetStyleSheet(
+ mpStyleSheet, true, true);
+ }
+ }
+
+ return *mxItemSet;
+ }
+
+ void AttributeProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > /*aChangedItems*/, sal_uInt16 /*nDeletedWhich*/)
+ {
+ // own modifications
+ SdrObject& rObj = GetSdrObject();
+
+ rObj.SetBoundRectDirty();
+ rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+ rObj.SetChanged();
+ }
+
+ void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
+ {
+ if(pNewItem)
+ {
+ std::unique_ptr<SfxPoolItem> pResultItem;
+ SdrModel& rModel(GetSdrObject().getSdrModelFromSdrObject());
+
+ switch( nWhich )
+ {
+ case XATTR_FILLBITMAP:
+ {
+ // TTTT checkForUniqueItem should use SdrModel&
+ pResultItem = static_cast<const XFillBitmapItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_LINEDASH:
+ {
+ pResultItem = static_cast<const XLineDashItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_LINESTART:
+ {
+ pResultItem = static_cast<const XLineStartItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_LINEEND:
+ {
+ pResultItem = static_cast<const XLineEndItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_FILLGRADIENT:
+ {
+ pResultItem = static_cast<const XFillGradientItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_FILLFLOATTRANSPARENCE:
+ {
+ // #85953# allow all kinds of XFillFloatTransparenceItem to be set
+ pResultItem = static_cast<const XFillFloatTransparenceItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_FILLHATCH:
+ {
+ pResultItem = static_cast<const XFillHatchItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ }
+
+ // guarantee SfxItemSet existence
+ GetObjectItemSet();
+
+ if(pResultItem)
+ {
+ // force ItemSet
+ mxItemSet->Put(std::move(pResultItem));
+ }
+ else
+ {
+ mxItemSet->Put(*pNewItem);
+ }
+ }
+ else
+ {
+ // clear item if ItemSet exists
+ if(HasSfxItemSet())
+ {
+ mxItemSet->ClearItem(nWhich);
+ }
+ }
+ }
+
+ void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool /*bBroadcast*/)
+ {
+ // guarantee SfxItemSet existence
+ GetObjectItemSet();
+
+ ImpRemoveStyleSheet();
+ ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+
+ SdrObject& rObj = GetSdrObject();
+ rObj.SetBoundRectDirty();
+ rObj.SetBoundAndSnapRectsDirty(true);
+ }
+
+ SfxStyleSheet* AttributeProperties::GetStyleSheet() const
+ {
+ return mpStyleSheet;
+ }
+
+ void AttributeProperties::ForceStyleToHardAttributes()
+ {
+ if(!GetStyleSheet() || mpStyleSheet == nullptr)
+ return;
+
+ // guarantee SfxItemSet existence
+ GetObjectItemSet();
+
+ // prepare copied, new itemset, but WITHOUT parent
+ SfxItemSet aDestItemSet(*mxItemSet);
+ aDestItemSet.SetParent(nullptr);
+
+ // prepare forgetting the current stylesheet like in RemoveStyleSheet()
+ EndListening(*mpStyleSheet);
+ EndListening(*mpStyleSheet->GetPool());
+
+ // prepare the iter; use the mpObjectItemSet which may have less
+ // WhichIDs than the style.
+ SfxWhichIter aIter(aDestItemSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+ const SfxPoolItem *pItem = nullptr;
+
+ // now set all hard attributes of the current at the new itemset
+ while(nWhich)
+ {
+ // #i61284# use mpItemSet with parents, makes things easier and reduces to
+ // one loop
+ if(SfxItemState::SET == mxItemSet->GetItemState(nWhich, true, &pItem))
+ {
+ aDestItemSet.Put(*pItem);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+
+ // replace itemsets
+ mxItemSet.emplace(std::move(aDestItemSet));
+
+ // set necessary changes like in RemoveStyleSheet()
+ GetSdrObject().SetBoundRectDirty();
+ GetSdrObject().SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+
+ mpStyleSheet = nullptr;
+ }
+
+ void AttributeProperties::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+ {
+ bool bHintUsed(false);
+
+ const SfxStyleSheetHint* pStyleHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
+
+ if(pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet())
+ {
+ SdrObject& rObj = GetSdrObject();
+ //SdrPage* pPage = rObj.GetPage();
+
+ switch(pStyleHint->GetId())
+ {
+ case SfxHintId::StyleSheetCreated :
+ {
+ // cannot happen, nothing to do
+ break;
+ }
+ case SfxHintId::StyleSheetModified :
+ case SfxHintId::StyleSheetChanged :
+ {
+ // notify change
+ break;
+ }
+ case SfxHintId::StyleSheetErased :
+ case SfxHintId::StyleSheetInDestruction :
+ {
+ // Style needs to be exchanged
+ SfxStyleSheet* pNewStSh = nullptr;
+ SdrModel& rModel(rObj.getSdrModelFromSdrObject());
+
+ // Do nothing if object is in destruction, else a StyleSheet may be found from
+ // a StyleSheetPool which is just being deleted itself. and thus it would be fatal
+ // to register as listener to that new StyleSheet.
+ if(!rObj.IsInDestruction())
+ {
+ if(SfxStyleSheet* pStyleSheet = GetStyleSheet())
+ {
+ pNewStSh = static_cast<SfxStyleSheet*>(rModel.GetStyleSheetPool()->Find(
+ pStyleSheet->GetParent(), pStyleSheet->GetFamily()));
+ }
+
+ if(!pNewStSh)
+ {
+ pNewStSh = rModel.GetDefaultStyleSheet();
+ }
+ }
+
+ // remove used style, it's erased or in destruction
+ ImpRemoveStyleSheet();
+
+ if(pNewStSh)
+ {
+ ImpAddStyleSheet(pNewStSh, true);
+ }
+
+ break;
+ }
+ default: break;
+ }
+
+ // Get old BoundRect. Do this after the style change is handled
+ // in the ItemSet parts because GetBoundRect() may calculate a new
+ tools::Rectangle aBoundRect = rObj.GetLastBoundRect();
+
+ rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+
+ // tell the object about the change
+ rObj.SetChanged();
+ rObj.BroadcastObjectChange();
+
+ //if(pPage && pPage->IsInserted())
+ //{
+ // rObj.BroadcastObjectChange();
+ //}
+
+ rObj.SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect);
+
+ bHintUsed = true;
+ }
+
+ if(!bHintUsed)
+ {
+ // forward to SdrObject ATM. Not sure if this will be necessary
+ // in the future.
+ GetSdrObject().Notify(rBC, rHint);
+ }
+ }
+
+ bool AttributeProperties::isUsedByModel() const
+ {
+ const SdrObject& rObj(GetSdrObject());
+ if (rObj.IsInserted())
+ {
+ const SdrPage* const pPage(rObj.getSdrPageFromSdrObject());
+ if (pPage && pPage->IsInserted())
+ return true;
+ }
+ return false;
+ }
+
+ void AttributeProperties::applyDefaultStyleSheetFromSdrModel()
+ {
+ SfxStyleSheet* pDefaultStyleSheet(GetSdrObject().getSdrModelFromSdrObject().GetDefaultStyleSheet());
+
+ // tdf#118139 Only do this when StyleSheet really differs. It may e.g.
+ // be the case that nullptr == pDefaultStyleSheet and there is none set yet,
+ // so indeed no need to set it (needed for some strange old MSWord2003
+ // documents with CustomShape-'Group' and added Text-Frames, see task description)
+ if(pDefaultStyleSheet != GetStyleSheet())
+ {
+ // do not delete hard attributes when setting dsefault Style
+ SetStyleSheet(pDefaultStyleSheet, true, true);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/captionproperties.cxx b/svx/source/sdr/properties/captionproperties.cxx
new file mode 100644
index 000000000..2f7a2c8a7
--- /dev/null
+++ b/svx/source/sdr/properties/captionproperties.cxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/captionproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdocapt.hxx>
+
+
+namespace sdr::properties
+{
+ // create a new itemset
+ SfxItemSet CaptionProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(
+ rPool,
+ svl::Items<
+ // Ranges from SdrAttrObj, SdrCaptionObj:
+ SDRATTR_START, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ CaptionProperties::CaptionProperties(SdrObject& rObj)
+ : RectangleProperties(rObj)
+ {
+ }
+
+ CaptionProperties::CaptionProperties(const CaptionProperties& rProps, SdrObject& rObj)
+ : RectangleProperties(rProps, rObj)
+ {
+ }
+
+ CaptionProperties::~CaptionProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> CaptionProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new CaptionProperties(*this, rObj));
+ }
+
+ void CaptionProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrCaptionObj& rObj = static_cast<SdrCaptionObj&>(GetSdrObject());
+
+ // local changes
+ rObj.ImpRecalcTail();
+
+ // call parent
+ RectangleProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+ }
+
+ void CaptionProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ RectangleProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ SdrCaptionObj& rObj = static_cast<SdrCaptionObj&>(GetSdrObject());
+ rObj.ImpRecalcTail();
+ }
+
+ void CaptionProperties::ForceDefaultAttributes()
+ {
+ // call parent
+ RectangleProperties::ForceDefaultAttributes();
+
+ // force ItemSet
+ GetObjectItemSet();
+
+ // this was set by TextProperties::ForceDefaultAttributes(),
+ // reset to default
+ mxItemSet->ClearItem(XATTR_LINESTYLE);
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/circleproperties.cxx b/svx/source/sdr/properties/circleproperties.cxx
new file mode 100644
index 000000000..0c2a5bdc1
--- /dev/null
+++ b/svx/source/sdr/properties/circleproperties.cxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/circleproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdocirc.hxx>
+#include <sxcikitm.hxx>
+#include <svx/sxciaitm.hxx>
+
+
+namespace sdr::properties
+{
+ // create a new itemset
+ SfxItemSet CircleProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(
+ rPool,
+ svl::Items<
+ // Ranges from SdrAttrObj, SdrCircObj
+ SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_CIRC_FIRST, SDRATTR_CIRC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ CircleProperties::CircleProperties(SdrObject& rObj)
+ : RectangleProperties(rObj)
+ {
+ }
+
+ CircleProperties::CircleProperties(const CircleProperties& rProps, SdrObject& rObj)
+ : RectangleProperties(rProps, rObj)
+ {
+ }
+
+ CircleProperties::~CircleProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> CircleProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new CircleProperties(*this, rObj));
+ }
+
+ void CircleProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrCircObj& rObj = static_cast<SdrCircObj&>(GetSdrObject());
+
+ // call parent
+ RectangleProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // local changes
+ rObj.ImpSetAttrToCircInfo();
+ }
+
+ void CircleProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ RectangleProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ SdrCircObj& rObj = static_cast<SdrCircObj&>(GetSdrObject());
+ rObj.SetXPolyDirty();
+
+ // local changes
+ rObj.ImpSetAttrToCircInfo();
+ }
+
+ void CircleProperties::ForceDefaultAttributes()
+ {
+ SdrCircObj& rObj = static_cast<SdrCircObj&>(GetSdrObject());
+ SdrCircKind eKind = rObj.GetCircleKind();
+
+ if(eKind != SdrCircKind::Full)
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ mxItemSet->Put(SdrCircKindItem(eKind));
+
+ if(rObj.GetStartAngle())
+ {
+ mxItemSet->Put(makeSdrCircStartAngleItem(rObj.GetStartAngle()));
+ }
+
+ if(rObj.GetEndAngle() != 36000_deg100)
+ {
+ mxItemSet->Put(makeSdrCircEndAngleItem(rObj.GetEndAngle()));
+ }
+ }
+
+ // call parent after SetObjectItem(SdrCircKindItem())
+ // because ForceDefaultAttr() will call
+ // ImpSetAttrToCircInfo() which needs a correct
+ // SdrCircKindItem
+ RectangleProperties::ForceDefaultAttributes();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/connectorproperties.cxx b/svx/source/sdr/properties/connectorproperties.cxx
new file mode 100644
index 000000000..375a98190
--- /dev/null
+++ b/svx/source/sdr/properties/connectorproperties.cxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/connectorproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdoedge.hxx>
+
+
+namespace sdr::properties
+{
+ // create a new itemset
+ SfxItemSet ConnectorProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(
+ rPool,
+ svl::Items<
+ // Ranges from SdrAttrObj, SdrEdgeObj:
+ SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_EDGE_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ ConnectorProperties::ConnectorProperties(SdrObject& rObj)
+ : TextProperties(rObj)
+ {
+ }
+
+ ConnectorProperties::ConnectorProperties(const ConnectorProperties& rProps, SdrObject& rObj)
+ : TextProperties(rProps, rObj)
+ {
+ }
+
+ ConnectorProperties::~ConnectorProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> ConnectorProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new ConnectorProperties(*this, rObj));
+ }
+
+ void ConnectorProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrEdgeObj& rObj = static_cast<SdrEdgeObj&>(GetSdrObject());
+
+ // call parent
+ TextProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // local changes
+ rObj.ImpSetAttrToEdgeInfo();
+ }
+
+ void ConnectorProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ TextProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ SdrEdgeObj& rObj = static_cast<SdrEdgeObj&>(GetSdrObject());
+ rObj.ImpSetAttrToEdgeInfo();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/customshapeproperties.cxx b/svx/source/sdr/properties/customshapeproperties.cxx
new file mode 100644
index 000000000..59135cde1
--- /dev/null
+++ b/svx/source/sdr/properties/customshapeproperties.cxx
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/customshapeproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/sdooitm.hxx>
+#include <editeng/eeitem.hxx>
+#include <svl/whiter.hxx>
+#include <svl/hint.hxx>
+
+
+namespace sdr::properties
+{
+ void CustomShapeProperties::UpdateTextFrameStatus(bool bInvalidateRenderGeometry)
+ {
+ SdrObjCustomShape& rObj = static_cast< SdrObjCustomShape& >(GetSdrObject());
+ const bool bOld(rObj.mbTextFrame);
+
+ // change TextFrame flag when bResizeShapeToFitText changes (which is mapped
+ // on the item SDRATTR_TEXT_AUTOGROWHEIGHT for custom shapes, argh)
+ rObj.mbTextFrame = GetObjectItemSet().Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
+
+ // check if it did change
+ if(rObj.mbTextFrame != bOld)
+ {
+ // on change also invalidate render geometry
+ bInvalidateRenderGeometry = true;
+
+ // #115391# Potential recursion, since it calls SetObjectItemSet again, but rObj.bTextFrame
+ // will not change again. Thus it will be only one level and terminate safely
+ rObj.AdaptTextMinSize();
+ }
+
+ if(bInvalidateRenderGeometry)
+ {
+ // if asked for or bResizeShapeToFitText changed, make sure that
+ // the render geometry is reconstructed using changed parameters
+ rObj.InvalidateRenderGeometry();
+ }
+ }
+
+ SfxItemSet CustomShapeProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(
+ rPool,
+ svl::Items<
+ // Ranges from SdrAttrObj:
+ SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ // Graphic attributes, 3D properties, CustomShape
+ // properties:
+ SDRATTR_GRAF_FIRST, SDRATTR_CUSTOMSHAPE_LAST,
+ SDRATTR_GLOW_FIRST, SDRATTR_SOFTEDGE_LAST,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ bool CustomShapeProperties::AllowItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem ) const
+ {
+ bool bAllowItemChange = true;
+ if ( !pNewItem )
+ {
+ if ( ( nWhich >= SDRATTR_CUSTOMSHAPE_FIRST ) && ( nWhich <= SDRATTR_CUSTOMSHAPE_LAST ) )
+ bAllowItemChange = false;
+ }
+ if ( bAllowItemChange )
+ bAllowItemChange = TextProperties::AllowItemChange( nWhich, pNewItem );
+ return bAllowItemChange;
+ }
+
+ void CustomShapeProperties::ClearObjectItem(const sal_uInt16 nWhich)
+ {
+ if ( !nWhich )
+ {
+ SfxWhichIter aIter( *mxItemSet );
+ sal_uInt16 nWhich2 = aIter.FirstWhich();
+ while( nWhich2 )
+ {
+ TextProperties::ClearObjectItemDirect( nWhich2 );
+ nWhich2 = aIter.NextWhich();
+ }
+ ItemSetChanged({}, 0);
+ }
+ else
+ TextProperties::ClearObjectItem( nWhich );
+ }
+
+ void CustomShapeProperties::ClearObjectItemDirect(const sal_uInt16 nWhich)
+ {
+ if ( !nWhich )
+ {
+ SfxWhichIter aIter( *mxItemSet );
+ sal_uInt16 nWhich2 = aIter.FirstWhich();
+ while( nWhich2 )
+ {
+ TextProperties::ClearObjectItemDirect( nWhich2 );
+ nWhich2 = aIter.NextWhich();
+ }
+ }
+ else
+ TextProperties::ClearObjectItemDirect( nWhich );
+ }
+
+ void CustomShapeProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ // call parent
+ TextProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // update bTextFrame and RenderGeometry
+ UpdateTextFrameStatus(true);
+ }
+
+ void CustomShapeProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ switch(nWhich)
+ {
+ case SDRATTR_TEXT_AUTOGROWHEIGHT:
+ {
+ // #115391# update bTextFrame and RenderGeometry using AdaptTextMinSize()
+ UpdateTextFrameStatus(false);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ // call parent
+ TextProperties::PostItemChange(nWhich);
+ }
+
+ void CustomShapeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
+ {
+ // call parent
+ TextProperties::ItemChange( nWhich, pNewItem );
+
+ // update bTextFrame and RenderGeometry
+ UpdateTextFrameStatus(true);
+ }
+
+ void CustomShapeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ TextProperties::SetStyleSheet( pNewStyleSheet, bDontRemoveHardAttr, bBroadcast );
+
+ // update bTextFrame and RenderGeometry
+ UpdateTextFrameStatus(true);
+ }
+
+ void CustomShapeProperties::ForceDefaultAttributes()
+ {
+ // update bTextFrame and RenderGeometry
+ UpdateTextFrameStatus(true);
+
+ // SJ: Following is no good if creating customshapes, leading to objects that are white after loading via xml
+ // This means: Do *not* call parent here is by purpose...
+ }
+
+ CustomShapeProperties::CustomShapeProperties(SdrObject& rObj)
+ : TextProperties(rObj)
+ {
+ }
+
+ CustomShapeProperties::CustomShapeProperties(const CustomShapeProperties& rProps, SdrObject& rObj)
+ : TextProperties(rProps, rObj)
+ {
+ }
+
+ CustomShapeProperties::~CustomShapeProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> CustomShapeProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new CustomShapeProperties(*this, rObj));
+ }
+
+ void CustomShapeProperties::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+ {
+ TextProperties::Notify( rBC, rHint );
+
+ bool bRemoveRenderGeometry = false;
+ const SfxStyleSheetHint* pStyleHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
+
+ if ( pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet() )
+ {
+ switch( pStyleHint->GetId() )
+ {
+ case SfxHintId::StyleSheetModified :
+ case SfxHintId::StyleSheetChanged :
+ bRemoveRenderGeometry = true;
+ break;
+ default: break;
+ }
+ }
+ else if ( rHint.GetId() == SfxHintId::DataChanged )
+ {
+ bRemoveRenderGeometry = true;
+ }
+
+ // update bTextFrame and RenderGeometry
+ UpdateTextFrameStatus(bRemoveRenderGeometry);
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/defaultproperties.cxx b/svx/source/sdr/properties/defaultproperties.cxx
new file mode 100644
index 000000000..fa5292458
--- /dev/null
+++ b/svx/source/sdr/properties/defaultproperties.cxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <svx/sdr/properties/defaultproperties.hxx>
+#include <sdr/properties/itemsettools.hxx>
+#include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
+#include <vector>
+#include <svx/svdobj.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <libxml/xmlwriter.h>
+#include <svx/svdmodel.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/xbtmpit.hxx>
+
+namespace sdr::properties
+{
+ SfxItemSet DefaultProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ // Basic implementation; Basic object has NO attributes
+ return SfxItemSet(rPool);
+ }
+
+ DefaultProperties::DefaultProperties(SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ }
+
+ DefaultProperties::DefaultProperties(const DefaultProperties& rProps, SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ if(!rProps.mxItemSet)
+ return;
+
+ // Clone may be to another model and thus another ItemPool.
+ // SfxItemSet supports that thus we are able to Clone all
+ // SfxItemState::SET items to the target pool.
+ mxItemSet.emplace(rProps.mxItemSet->CloneAsValue(
+ true,
+ &rObj.getSdrModelFromSdrObject().GetItemPool()));
+
+ // React on ModelChange: If metric has changed, scale items.
+ // As seen above, clone is supported, but scale is not included,
+ // thus: TTTT maybe add scale to SfxItemSet::Clone() (?)
+ // tdf#117707 correct ModelChange detection
+ const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
+
+ if(bModelChange)
+ {
+ const MapUnit aOldUnit(rProps.GetSdrObject().getSdrModelFromSdrObject().GetScaleUnit());
+ const MapUnit aNewUnit(rObj.getSdrModelFromSdrObject().GetScaleUnit());
+ const bool bScaleUnitChanged(aNewUnit != aOldUnit);
+
+ if(bScaleUnitChanged)
+ {
+ const Fraction aMetricFactor(GetMapFactor(aOldUnit, aNewUnit).X());
+
+ ScaleItemSet(*mxItemSet, aMetricFactor);
+ }
+ }
+
+ // do not keep parent info, this may be changed by later constructors.
+ // This class just copies the ItemSet, ignore parent.
+ if(mxItemSet && mxItemSet->GetParent())
+ {
+ mxItemSet->SetParent(nullptr);
+ }
+ }
+
+ std::unique_ptr<BaseProperties> DefaultProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new DefaultProperties(*this, rObj));
+ }
+
+ DefaultProperties::~DefaultProperties() {}
+
+ const SfxItemSet& DefaultProperties::GetObjectItemSet() const
+ {
+ if(!mxItemSet)
+ {
+ mxItemSet.emplace(const_cast<DefaultProperties*>(this)->CreateObjectSpecificItemSet(GetSdrObject().GetObjectItemPool()));
+ const_cast<DefaultProperties*>(this)->ForceDefaultAttributes();
+ }
+
+ assert(mxItemSet && "Could not create an SfxItemSet(!)");
+
+ return *mxItemSet;
+ }
+
+ void DefaultProperties::SetObjectItem(const SfxPoolItem& rItem)
+ {
+ const sal_uInt16 nWhichID(rItem.Which());
+
+ if(!AllowItemChange(nWhichID, &rItem))
+ return;
+
+ ItemChange(nWhichID, &rItem);
+ PostItemChange(nWhichID);
+
+ const SfxPoolItem* pItem = &rItem;
+ ItemSetChanged( {&pItem, 1}, 0);
+ }
+
+ void DefaultProperties::SetObjectItemDirect(const SfxPoolItem& rItem)
+ {
+ const sal_uInt16 nWhichID(rItem.Which());
+
+ if(AllowItemChange(nWhichID, &rItem))
+ {
+ ItemChange(nWhichID, &rItem);
+ }
+ }
+
+ void DefaultProperties::ClearObjectItem(const sal_uInt16 nWhich)
+ {
+ if(!AllowItemChange(nWhich))
+ return;
+
+ ItemChange(nWhich);
+ PostItemChange(nWhich);
+
+ if(nWhich)
+ {
+ ItemSetChanged({}, nWhich);
+ }
+ }
+
+ void DefaultProperties::ClearObjectItemDirect(const sal_uInt16 nWhich)
+ {
+ if(AllowItemChange(nWhich))
+ {
+ ItemChange(nWhich);
+ }
+ }
+
+ void DefaultProperties::SetObjectItemSet(const SfxItemSet& rSet)
+ {
+ if (rSet.HasItem(XATTR_FILLBITMAP))
+ {
+ const XFillBitmapItem* pItem = rSet.GetItem(XATTR_FILLBITMAP);
+ const std::shared_ptr<VectorGraphicData>& pVectorData
+ = pItem->GetGraphicObject().GetGraphic().getVectorGraphicData();
+ if (pVectorData)
+ {
+ // Shape is filled by a vector graphic: tell it our size as a hint.
+ basegfx::B2DTuple aSizeHint;
+ aSizeHint.setX(GetSdrObject().GetSnapRect().getWidth());
+ aSizeHint.setY(GetSdrObject().GetSnapRect().getHeight());
+ pVectorData->setSizeHint(aSizeHint);
+ }
+ }
+
+ SfxWhichIter aWhichIter(rSet);
+ sal_uInt16 nWhich(aWhichIter.FirstWhich());
+ std::vector< const SfxPoolItem * > aPostItemChangeList;
+ // give a hint to STL_Vector
+ aPostItemChangeList.reserve(rSet.Count());
+
+ while(nWhich)
+ {
+ const SfxPoolItem* pPoolItem;
+ if(SfxItemState::SET == aWhichIter.GetItemState(false, &pPoolItem))
+ {
+ if(AllowItemChange(nWhich, pPoolItem))
+ {
+ ItemChange(nWhich, pPoolItem);
+ aPostItemChangeList.emplace_back( pPoolItem );
+ }
+ }
+
+ nWhich = aWhichIter.NextWhich();
+ }
+
+ if(!aPostItemChangeList.empty())
+ {
+ for (const auto& rItem : aPostItemChangeList)
+ {
+ PostItemChange(rItem->Which());
+ }
+
+ ItemSetChanged(aPostItemChangeList, 0);
+ }
+ }
+
+ void DefaultProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > /*aChangedItems*/, sal_uInt16 /*nDeletedWhich*/)
+ {
+ }
+
+ bool DefaultProperties::AllowItemChange(const sal_uInt16 /*nWhich*/, const SfxPoolItem* /*pNewItem*/) const
+ {
+ return true;
+ }
+
+ void DefaultProperties::ItemChange(const sal_uInt16 /*nWhich*/, const SfxPoolItem* /*pNewItem*/)
+ {
+ }
+
+ void DefaultProperties::PostItemChange(const sal_uInt16 nWhich )
+ {
+ if( (nWhich == XATTR_FILLSTYLE) && mxItemSet )
+ CleanupFillProperties(*mxItemSet);
+ }
+
+ void DefaultProperties::SetStyleSheet(SfxStyleSheet* /*pNewStyleSheet*/, bool /*bDontRemoveHardAttr*/,
+ bool /*bBroadcast*/)
+ {
+ // no StyleSheet in DefaultProperties
+ }
+
+ SfxStyleSheet* DefaultProperties::GetStyleSheet() const
+ {
+ // no StyleSheet in DefaultProperties
+ return nullptr;
+ }
+
+ void DefaultProperties::ForceDefaultAttributes()
+ {
+ }
+
+ void DefaultProperties::dumpAsXml(xmlTextWriterPtr pWriter) const
+ {
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("DefaultProperties"));
+ BaseProperties::dumpAsXml(pWriter);
+ if (mxItemSet)
+ {
+ mxItemSet->dumpAsXml(pWriter);
+ }
+ (void)xmlTextWriterEndElement(pWriter);
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dcompoundproperties.cxx b/svx/source/sdr/properties/e3dcompoundproperties.cxx
new file mode 100644
index 000000000..c31d85fdc
--- /dev/null
+++ b/svx/source/sdr/properties/e3dcompoundproperties.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/e3dcompoundproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+
+
+namespace sdr::properties
+{
+ E3dCompoundProperties::E3dCompoundProperties(SdrObject& rObj)
+ : E3dProperties(rObj)
+ {
+ }
+
+ E3dCompoundProperties::E3dCompoundProperties(const E3dCompoundProperties& rProps, SdrObject& rObj)
+ : E3dProperties(rProps, rObj)
+ {
+ }
+
+ E3dCompoundProperties::~E3dCompoundProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dCompoundProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dCompoundProperties(*this, rObj));
+ }
+
+ const SfxItemSet& E3dCompoundProperties::GetMergedItemSet() const
+ {
+ // include Items of scene this object belongs to
+ const E3dCompoundObject& rObj = static_cast<const E3dCompoundObject&>(GetSdrObject());
+ E3dScene* pScene(rObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ // add filtered scene properties (SDRATTR_3DSCENE_) to local itemset
+ SfxItemSetFixed<SDRATTR_3DSCENE_FIRST, SDRATTR_3DSCENE_LAST> aSet(*mxItemSet->GetPool() );
+ aSet.Put(pScene->GetProperties().GetObjectItemSet());
+ mxItemSet->Put(aSet);
+ }
+
+ // call parent
+ return E3dProperties::GetMergedItemSet();
+ }
+
+ void E3dCompoundProperties::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
+ {
+ // Set scene specific items at scene
+ E3dCompoundObject& rObj = static_cast<E3dCompoundObject&>(GetSdrObject());
+ E3dScene* pScene(rObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ // Generate filtered scene properties (SDRATTR_3DSCENE_) itemset
+ SfxItemSetFixed<SDRATTR_3DSCENE_FIRST, SDRATTR_3DSCENE_LAST> aSet(*mxItemSet->GetPool());
+ aSet.Put(rSet);
+
+ if(bClearAllItems)
+ {
+ pScene->GetProperties().ClearObjectItem();
+ }
+
+ if(aSet.Count())
+ {
+ pScene->GetProperties().SetObjectItemSet(aSet);
+ }
+ }
+
+ // call parent. This will set items on local object, too.
+ E3dProperties::SetMergedItemSet(rSet, bClearAllItems);
+ }
+
+ void E3dCompoundProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ // call parent
+ E3dProperties::PostItemChange(nWhich);
+
+ // handle value change
+ E3dCompoundObject& rObj = static_cast<E3dCompoundObject&>(GetSdrObject());
+
+ switch(nWhich)
+ {
+ // #i28528#
+ // Added extra Item (Bool) for chart2 to be able to show reduced line geometry
+ case SDRATTR_3DOBJ_REDUCED_LINE_GEOMETRY:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_DOUBLE_SIDED:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_NORMALS_KIND:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_NORMALS_INVERT:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_TEXTURE_PROJ_X:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_TEXTURE_PROJ_Y:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dextrudeproperties.cxx b/svx/source/sdr/properties/e3dextrudeproperties.cxx
new file mode 100644
index 000000000..9b9ffd8be
--- /dev/null
+++ b/svx/source/sdr/properties/e3dextrudeproperties.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/e3dextrudeproperties.hxx>
+#include <extrud3d.hxx>
+
+
+namespace sdr::properties
+{
+ E3dExtrudeProperties::E3dExtrudeProperties(SdrObject& rObj)
+ : E3dCompoundProperties(rObj)
+ {
+ }
+
+ E3dExtrudeProperties::E3dExtrudeProperties(const E3dExtrudeProperties& rProps, SdrObject& rObj)
+ : E3dCompoundProperties(rProps, rObj)
+ {
+ }
+
+ E3dExtrudeProperties::~E3dExtrudeProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dExtrudeProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dExtrudeProperties(*this, rObj));
+ }
+
+ void E3dExtrudeProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ // call parent
+ E3dCompoundProperties::PostItemChange(nWhich);
+
+ // handle value change
+ E3dExtrudeObj& rObj = static_cast<E3dExtrudeObj&>(GetSdrObject());
+
+ switch(nWhich)
+ {
+ case SDRATTR_3DOBJ_PERCENT_DIAGONAL:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_BACKSCALE:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_DEPTH:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dlatheproperties.cxx b/svx/source/sdr/properties/e3dlatheproperties.cxx
new file mode 100644
index 000000000..feb546534
--- /dev/null
+++ b/svx/source/sdr/properties/e3dlatheproperties.cxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/e3dlatheproperties.hxx>
+#include <svx/lathe3d.hxx>
+
+
+namespace sdr::properties
+{
+ E3dLatheProperties::E3dLatheProperties(SdrObject& rObj)
+ : E3dCompoundProperties(rObj)
+ {
+ }
+
+ E3dLatheProperties::E3dLatheProperties(const E3dLatheProperties& rProps, SdrObject& rObj)
+ : E3dCompoundProperties(rProps, rObj)
+ {
+ }
+
+ E3dLatheProperties::~E3dLatheProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dLatheProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dLatheProperties(*this, rObj));
+ }
+
+ void E3dLatheProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ // call parent
+ E3dCompoundProperties::PostItemChange(nWhich);
+
+ // handle value change
+ E3dLatheObj& rObj = static_cast<E3dLatheObj&>(GetSdrObject());
+
+ switch(nWhich)
+ {
+ case SDRATTR_3DOBJ_HORZ_SEGS:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_VERT_SEGS:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_PERCENT_DIAGONAL:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_BACKSCALE:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_END_ANGLE:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dproperties.cxx b/svx/source/sdr/properties/e3dproperties.cxx
new file mode 100644
index 000000000..946f879de
--- /dev/null
+++ b/svx/source/sdr/properties/e3dproperties.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/e3dproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svddef.hxx>
+#include <svx/obj3d.hxx>
+
+
+namespace sdr::properties
+{
+ // create a new itemset
+ SfxItemSet E3dProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool,
+
+ // ranges from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+
+ // ranges from E3dObject, contains object and scene because of GetMergedItemSet()
+ SDRATTR_3D_FIRST, SDRATTR_3D_LAST>);
+ }
+
+ E3dProperties::E3dProperties(SdrObject& rObj)
+ : AttributeProperties(rObj)
+ {
+ }
+
+ E3dProperties::E3dProperties(const E3dProperties& rProps, SdrObject& rObj)
+ : AttributeProperties(rProps, rObj)
+ {
+ }
+
+ E3dProperties::~E3dProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dProperties(*this, rObj));
+ }
+
+ void E3dProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ E3dObject& rObj = static_cast<E3dObject&>(GetSdrObject());
+
+ // call parent
+ AttributeProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // local changes
+ rObj.StructureChanged();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dsceneproperties.cxx b/svx/source/sdr/properties/e3dsceneproperties.cxx
new file mode 100644
index 000000000..c156db33e
--- /dev/null
+++ b/svx/source/sdr/properties/e3dsceneproperties.cxx
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/e3dsceneproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
+#include <svx/svddef.hxx>
+#include <svx/scene3d.hxx>
+#include <osl/diagnose.h>
+#include <memory>
+
+
+namespace sdr::properties
+{
+ E3dSceneProperties::E3dSceneProperties(SdrObject& rObj)
+ : E3dProperties(rObj)
+ {
+ }
+
+ E3dSceneProperties::E3dSceneProperties(const E3dSceneProperties& rProps, SdrObject& rObj)
+ : E3dProperties(rProps, rObj)
+ {
+ }
+
+ E3dSceneProperties::~E3dSceneProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dSceneProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dSceneProperties(*this, rObj));
+ }
+
+ const SfxItemSet& E3dSceneProperties::GetMergedItemSet() const
+ {
+ // prepare ItemSet
+ if(mxItemSet)
+ {
+ // filter for SDRATTR_3DSCENE_ items, only keep those items
+ SfxItemSetFixed<SDRATTR_3DSCENE_FIRST, SDRATTR_3DSCENE_LAST> aNew(*mxItemSet->GetPool());
+ aNew.Put(*mxItemSet);
+ mxItemSet->ClearItem();
+ mxItemSet->Put(aNew);
+ }
+ else
+ {
+ // No ItemSet yet, force local ItemSet
+ GetObjectItemSet();
+ }
+
+ // collect all ItemSets of contained 3d objects
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SdrObject* pObj = pSub->GetObj(a);
+
+ if(dynamic_cast<const E3dCompoundObject* >(pObj))
+ {
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ // Leave out the SDRATTR_3DSCENE_ range, this would only be double
+ // and always equal.
+ if(nWhich <= SDRATTR_3DSCENE_FIRST || nWhich >= SDRATTR_3DSCENE_LAST)
+ {
+ if(SfxItemState::DONTCARE == aIter.GetItemState(false))
+ {
+ mxItemSet->InvalidateItem(nWhich);
+ }
+ else
+ {
+ mxItemSet->MergeValue(rSet.Get(nWhich), true);
+ }
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+ }
+
+ // call parent
+ return E3dProperties::GetMergedItemSet();
+ }
+
+ void E3dSceneProperties::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
+ {
+ // Set SDRATTR_3DOBJ_ range at contained objects.
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ if(nCount)
+ {
+ // Generate filtered ItemSet which contains all but the SDRATTR_3DSCENE items.
+ // #i50808# Leak fix, Clone produces a new instance and we get ownership here
+ SfxItemSet aNewSet(rSet.CloneAsValue());
+
+ for(sal_uInt16 b(SDRATTR_3DSCENE_FIRST); b <= SDRATTR_3DSCENE_LAST; b++)
+ {
+ aNewSet.ClearItem(b);
+ }
+
+ if(aNewSet.Count())
+ {
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SdrObject* pObj = pSub->GetObj(a);
+
+ if(dynamic_cast<const E3dCompoundObject* >(pObj))
+ {
+ // set merged ItemSet at contained 3d object.
+ pObj->SetMergedItemSet(aNewSet, bClearAllItems);
+ }
+ }
+ }
+ }
+
+ // call parent. This will set items on local object, too.
+ E3dProperties::SetMergedItemSet(rSet, bClearAllItems);
+ }
+
+ void E3dSceneProperties::SetMergedItem(const SfxPoolItem& rItem)
+ {
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ pSub->GetObj(a)->SetMergedItem(rItem);
+ }
+
+ // #i43809# call parent. This will set items on local object, too.
+ E3dProperties::SetMergedItem(rItem);
+ }
+
+ void E3dSceneProperties::ClearMergedItem(const sal_uInt16 nWhich)
+ {
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ pSub->GetObj(a)->ClearMergedItem(nWhich);
+ }
+
+ // #i43809# call parent. This will clear items on local object, too.
+ E3dProperties::ClearMergedItem(nWhich);
+ }
+
+ void E3dSceneProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ // call parent
+ E3dProperties::PostItemChange(nWhich);
+
+ // local changes
+ E3dScene& rObj = static_cast<E3dScene&>(GetSdrObject());
+ rObj.StructureChanged();
+
+ switch(nWhich)
+ {
+ case SDRATTR_3DSCENE_PERSPECTIVE :
+ case SDRATTR_3DSCENE_DISTANCE :
+ case SDRATTR_3DSCENE_FOCAL_LENGTH :
+ {
+ // #83387#, #83391#
+ // one common function for the camera attributes
+ // since SetCamera() sets all three back to the ItemSet
+ Camera3D aSceneCam(rObj.GetCamera());
+ bool bChange(false);
+
+ // for SDRATTR_3DSCENE_PERSPECTIVE:
+ if(aSceneCam.GetProjection() != rObj.GetPerspective())
+ {
+ aSceneCam.SetProjection(rObj.GetPerspective());
+ bChange = true;
+ }
+
+ // for SDRATTR_3DSCENE_DISTANCE:
+ basegfx::B3DPoint aActualPosition(aSceneCam.GetPosition());
+ double fNew = rObj.GetDistance();
+
+ if(fNew != aActualPosition.getZ())
+ {
+ aSceneCam.SetPosition(basegfx::B3DPoint(aActualPosition.getX(), aActualPosition.getY(), fNew));
+ bChange = true;
+ }
+
+ // for SDRATTR_3DSCENE_FOCAL_LENGTH:
+ fNew = rObj.GetFocalLength() / 100.0;
+
+ if(aSceneCam.GetFocalLength() != fNew)
+ {
+ aSceneCam.SetFocalLength(fNew);
+ bChange = true;
+ }
+
+ // for all
+ if(bChange)
+ {
+ rObj.SetCamera(aSceneCam);
+ }
+
+ break;
+ }
+ }
+ }
+
+ void E3dSceneProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ if(bBroadcast)
+ pSub->GetObj(a)->SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+ else
+ pSub->GetObj(a)->NbcSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+ }
+ }
+
+ SfxStyleSheet* E3dSceneProperties::GetStyleSheet() const
+ {
+ SfxStyleSheet* pRetval = nullptr;
+
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SfxStyleSheet* pCandidate = pSub->GetObj(a)->GetStyleSheet();
+
+ if(pRetval)
+ {
+ if(pCandidate != pRetval)
+ {
+ // different StyleSheelts, return none
+ return nullptr;
+ }
+ }
+ else
+ {
+ pRetval = pCandidate;
+ }
+ }
+
+ return pRetval;
+ }
+
+ void E3dSceneProperties::SetSceneItemsFromCamera()
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ E3dScene& rObj = static_cast<E3dScene&>(GetSdrObject());
+ const Camera3D& aSceneCam(rObj.GetCamera());
+
+ // ProjectionType
+ mxItemSet->Put(Svx3DPerspectiveItem(aSceneCam.GetProjection()));
+
+ // CamPos
+ mxItemSet->Put(makeSvx3DDistanceItem(static_cast<sal_uInt32>(aSceneCam.GetPosition().getZ() + 0.5)));
+
+ // FocalLength
+ mxItemSet->Put(makeSvx3DFocalLengthItem(static_cast<sal_uInt32>((aSceneCam.GetFocalLength() * 100.0) + 0.5)));
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dsphereproperties.cxx b/svx/source/sdr/properties/e3dsphereproperties.cxx
new file mode 100644
index 000000000..66f01748f
--- /dev/null
+++ b/svx/source/sdr/properties/e3dsphereproperties.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/e3dsphereproperties.hxx>
+#include <svx/sphere3d.hxx>
+
+
+namespace sdr::properties
+{
+ E3dSphereProperties::E3dSphereProperties(SdrObject& rObj)
+ : E3dCompoundProperties(rObj)
+ {
+ }
+
+ E3dSphereProperties::E3dSphereProperties(const E3dSphereProperties& rProps, SdrObject& rObj)
+ : E3dCompoundProperties(rProps, rObj)
+ {
+ }
+
+ E3dSphereProperties::~E3dSphereProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dSphereProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dSphereProperties(*this, rObj));
+ }
+
+ void E3dSphereProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ // call parent
+ E3dCompoundProperties::PostItemChange(nWhich);
+
+ // handle value change
+ E3dSphereObj& rObj = static_cast<E3dSphereObj&>(GetSdrObject());
+
+ switch(nWhich)
+ {
+ case SDRATTR_3DOBJ_HORZ_SEGS:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_VERT_SEGS:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/emptyproperties.cxx b/svx/source/sdr/properties/emptyproperties.cxx
new file mode 100644
index 000000000..1cad150b2
--- /dev/null
+++ b/svx/source/sdr/properties/emptyproperties.cxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/emptyproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svdobj.hxx>
+
+
+namespace sdr::properties
+{
+ EmptyProperties::EmptyProperties(SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ }
+
+ std::unique_ptr<BaseProperties> EmptyProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new EmptyProperties(rObj));
+ }
+
+ const SfxItemSet& EmptyProperties::GetObjectItemSet() const
+ {
+ assert(!"EmptyProperties::GetObjectItemSet() should never be called");
+ abort();
+ }
+
+ SfxItemSet EmptyProperties::CreateObjectSpecificItemSet(SfxItemPool&)
+ {
+ assert(!"EmptyProperties::CreateObjectSpecificItemSet() should never be called");
+ abort();
+ }
+
+ void EmptyProperties::SetObjectItem(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"EmptyProperties::SetObjectItem() should never be called");
+ }
+
+ void EmptyProperties::SetObjectItemDirect(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"EmptyProperties::SetObjectItemDirect() should never be called");
+ }
+
+ void EmptyProperties::ClearObjectItem(const sal_uInt16 /*nWhich*/)
+ {
+ assert(!"EmptyProperties::ClearObjectItem() should never be called");
+ }
+
+ void EmptyProperties::ClearObjectItemDirect(const sal_uInt16 /*nWhich*/)
+ {
+ assert(!"EmptyProperties::ClearObjectItemDirect() should never be called");
+ }
+
+ void EmptyProperties::SetObjectItemSet(const SfxItemSet& /*rSet*/)
+ {
+ assert(!"EmptyProperties::SetObjectItemSet() should never be called");
+ }
+
+ void EmptyProperties::SetStyleSheet(SfxStyleSheet* /*pNewStyleSheet*/, bool /*bDontRemoveHardAttr*/,
+ bool /*bBroadcast*/)
+ {
+ assert(!"EmptyProperties::SetStyleSheet() should never be called");
+ }
+
+ SfxStyleSheet* EmptyProperties::GetStyleSheet() const
+ {
+ assert(!"EmptyProperties::GetStyleSheet() should never be called");
+ return nullptr;
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/graphicproperties.cxx b/svx/source/sdr/properties/graphicproperties.cxx
new file mode 100644
index 000000000..be9b87800
--- /dev/null
+++ b/svx/source/sdr/properties/graphicproperties.cxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/graphicproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/sdgcpitm.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/sdgluitm.hxx>
+#include <sdgcoitm.hxx>
+#include <svx/sdggaitm.hxx>
+#include <sdgtritm.hxx>
+#include <sdginitm.hxx>
+#include <svx/sdgmoitm.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+
+namespace sdr::properties
+{
+ void GraphicProperties::applyDefaultStyleSheetFromSdrModel()
+ {
+ SfxStyleSheet* pStyleSheet(GetSdrObject().getSdrModelFromSdrObject().GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj());
+
+ if(pStyleSheet)
+ {
+ // do not delete hard attributes when setting dsefault Style
+ SetStyleSheet(pStyleSheet, true, true);
+ }
+ else
+ {
+ SetMergedItem(XFillStyleItem(com::sun::star::drawing::FillStyle_NONE));
+ SetMergedItem(XLineStyleItem(com::sun::star::drawing::LineStyle_NONE));
+ }
+ }
+
+ // create a new itemset
+ SfxItemSet GraphicProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool,
+
+ // range from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+
+ // range from SdrGrafObj
+ SDRATTR_GRAF_FIRST, SDRATTR_GRAF_LAST,
+
+ SDRATTR_GLOW_FIRST, SDRATTR_SOFTEDGE_LAST,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+
+ // range from SdrTextObj
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ GraphicProperties::GraphicProperties(SdrObject& rObj)
+ : RectangleProperties(rObj)
+ {
+ }
+
+ GraphicProperties::GraphicProperties(const GraphicProperties& rProps, SdrObject& rObj)
+ : RectangleProperties(rProps, rObj)
+ {
+ }
+
+ GraphicProperties::~GraphicProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> GraphicProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new GraphicProperties(*this, rObj));
+ }
+
+ void GraphicProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrGrafObj& rObj = static_cast<SdrGrafObj&>(GetSdrObject());
+
+ // local changes
+ rObj.SetXPolyDirty();
+
+ // #i29367# Update GraphicAttr, too. This was formerly
+ // triggered by SdrGrafObj::Notify, which is no longer
+ // called nowadays. BTW: strictly speaking, the whole
+ // ImpSetAttrToGrafInfostuff could
+ // be dumped, when SdrGrafObj::aGrafInfo is removed and
+ // always created on the fly for repaint.
+ rObj.ImpSetAttrToGrafInfo();
+
+ // call parent
+ RectangleProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+ }
+
+ void GraphicProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ RectangleProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ SdrGrafObj& rObj = static_cast<SdrGrafObj&>(GetSdrObject());
+ rObj.SetXPolyDirty();
+
+ // local changes
+ rObj.ImpSetAttrToGrafInfo();
+ }
+
+ void GraphicProperties::ForceDefaultAttributes()
+ {
+ // call parent
+ RectangleProperties::ForceDefaultAttributes();
+
+ // force ItemSet
+ GetObjectItemSet();
+
+ mxItemSet->Put( SdrGrafLuminanceItem( 0 ) );
+ mxItemSet->Put( SdrGrafContrastItem( 0 ) );
+ mxItemSet->Put( SdrGrafRedItem( 0 ) );
+ mxItemSet->Put( SdrGrafGreenItem( 0 ) );
+ mxItemSet->Put( SdrGrafBlueItem( 0 ) );
+ mxItemSet->Put( SdrGrafGamma100Item( 100 ) );
+ mxItemSet->Put( SdrGrafTransparenceItem( 0 ) );
+ mxItemSet->Put( SdrGrafInvertItem( false ) );
+ mxItemSet->Put( SdrGrafModeItem( GraphicDrawMode::Standard ) );
+ mxItemSet->Put( SdrGrafCropItem( 0, 0, 0, 0 ) );
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/groupproperties.cxx b/svx/source/sdr/properties/groupproperties.cxx
new file mode 100644
index 000000000..6ec522aa3
--- /dev/null
+++ b/svx/source/sdr/properties/groupproperties.cxx
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/groupproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdpage.hxx>
+#include <osl/diagnose.h>
+
+
+namespace sdr::properties
+{
+ GroupProperties::GroupProperties(SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ }
+
+ GroupProperties::~GroupProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> GroupProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new GroupProperties(rObj));
+ }
+
+ SfxItemSet GroupProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool);
+ }
+
+ const SfxItemSet& GroupProperties::GetObjectItemSet() const
+ {
+ assert(!"GroupProperties::GetObjectItemSet() should never be called");
+ abort();
+ }
+
+ const SfxItemSet& GroupProperties::GetMergedItemSet() const
+ {
+ // prepare ItemSet
+ if(mxItemSet)
+ // clear local itemset for merge
+ mxItemSet->ClearItem();
+ else if(!mxItemSet)
+ // force local itemset
+ mxItemSet.emplace(GetSdrObject().GetObjectItemPool());
+
+ // collect all ItemSets in mpItemSet
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ const SfxItemSet& rSet = pSub->GetObj(a)->GetMergedItemSet();
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ if(SfxItemState::DONTCARE == aIter.GetItemState(false))
+ {
+ mxItemSet->InvalidateItem(nWhich);
+ }
+ else
+ {
+ mxItemSet->MergeValue(rSet.Get(nWhich), true);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+
+ // For group properties, do not call parent since groups do
+ // not have local ItemSets.
+ return *mxItemSet;
+ }
+
+ void GroupProperties::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
+ {
+ // iterate over contained SdrObjects
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SdrObject* pObj = pSub->GetObj(a);
+
+ if(pObj)
+ {
+ // Set merged ItemSet at contained object
+ pObj->SetMergedItemSet(rSet, bClearAllItems);
+ }
+ }
+
+ // Do not call parent here. Group objects do not have local ItemSets
+ // where items need to be set.
+ }
+
+ void GroupProperties::SetObjectItem(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"GroupProperties::SetObjectItem() should never be called");
+ }
+
+ void GroupProperties::SetObjectItemDirect(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"GroupProperties::SetObjectItemDirect() should never be called");
+ }
+
+ void GroupProperties::ClearObjectItem(const sal_uInt16 nWhich)
+ {
+ // iterate over contained SdrObjects
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SdrObject* pObj = pSub->GetObj(a);
+
+ if(pObj)
+ {
+ pObj->GetProperties().ClearObjectItem(nWhich);
+ }
+ }
+ }
+
+ void GroupProperties::ClearObjectItemDirect(const sal_uInt16 /*nWhich*/)
+ {
+ assert(!"GroupProperties::ClearObjectItemDirect() should never be called");
+ }
+
+ void GroupProperties::SetMergedItem(const SfxPoolItem& rItem)
+ {
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ pSub->GetObj(a)->GetProperties().SetMergedItem(rItem);
+ }
+ }
+
+ void GroupProperties::ClearMergedItem(const sal_uInt16 nWhich)
+ {
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ pSub->GetObj(a)->GetProperties().ClearMergedItem(nWhich);
+ }
+ }
+
+ void GroupProperties::SetObjectItemSet(const SfxItemSet& /*rSet*/)
+ {
+ assert(!"GroupProperties::SetObjectItemSet() should never be called");
+ }
+
+ SfxStyleSheet* GroupProperties::GetStyleSheet() const
+ {
+ SfxStyleSheet* pRetval = nullptr;
+
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SfxStyleSheet* pCandidate = pSub->GetObj(a)->GetStyleSheet();
+
+ if(pRetval)
+ {
+ if(pCandidate != pRetval)
+ {
+ // different StyleSheelts, return none
+ return nullptr;
+ }
+ }
+ else
+ {
+ pRetval = pCandidate;
+ }
+ }
+
+ return pRetval;
+ }
+
+ void GroupProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ if(bBroadcast)
+ pSub->GetObj(a)->SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+ else
+ pSub->GetObj(a)->NbcSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+ }
+ }
+
+ void GroupProperties::ForceStyleToHardAttributes()
+ {
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ pSub->GetObj(a)->GetProperties().ForceStyleToHardAttributes();
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/itemsettools.cxx b/svx/source/sdr/properties/itemsettools.cxx
new file mode 100644
index 000000000..11431d367
--- /dev/null
+++ b/svx/source/sdr/properties/itemsettools.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/itemsettools.hxx>
+#include <tools/fract.hxx>
+#include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svditer.hxx>
+#include <memory>
+
+// class to remember broadcast start positions
+
+namespace sdr::properties
+{
+ ItemChangeBroadcaster::ItemChangeBroadcaster(const SdrObject& rObj)
+ {
+ if (rObj.GetObjIdentifier() == SdrObjKind::Group)
+ {
+ const SdrObjGroup* pGroupObj = static_cast<const SdrObjGroup*>(&rObj);
+ SdrObjListIter aIter(pGroupObj->GetSubList(), SdrIterMode::DeepNoGroups);
+ maRectangles.reserve(aIter.Count());
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pObj = aIter.Next();
+
+ if(pObj)
+ {
+ maRectangles.push_back(pObj->GetLastBoundRect());
+ }
+ }
+ }
+ else
+ {
+ maRectangles.push_back(rObj.GetLastBoundRect());
+ }
+ }
+
+
+ void ScaleItemSet(SfxItemSet& rSet, const Fraction& rScale)
+ {
+ sal_Int32 nMul(rScale.GetNumerator());
+ sal_Int32 nDiv(rScale.GetDenominator());
+
+ if(!rScale.IsValid() || !nDiv)
+ {
+ return;
+ }
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+ const SfxPoolItem *pItem = nullptr;
+
+ while(nWhich)
+ {
+ if(SfxItemState::SET == aIter.GetItemState(false, &pItem))
+ {
+ if(pItem->HasMetrics())
+ {
+ std::unique_ptr<SfxPoolItem> pNewItem(pItem->Clone());
+ pNewItem->ScaleMetrics(nMul, nDiv);
+ rSet.Put(std::move(pNewItem));
+ }
+ }
+ nWhich = aIter.NextWhich();
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/measureproperties.cxx b/svx/source/sdr/properties/measureproperties.cxx
new file mode 100644
index 000000000..07441c385
--- /dev/null
+++ b/svx/source/sdr/properties/measureproperties.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/measureproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdomeas.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/sdynitm.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+
+namespace sdr::properties
+{
+ // create a new itemset
+ SfxItemSet MeasureProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(
+ rPool,
+ svl::Items<
+ // Ranges from SdrAttrObj, SdrMeasureObj:
+ SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_MEASURE_FIRST, SDRATTR_MEASURE_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ MeasureProperties::MeasureProperties(SdrObject& rObj)
+ : TextProperties(rObj)
+ {
+ }
+
+ MeasureProperties::MeasureProperties(const MeasureProperties& rProps, SdrObject& rObj)
+ : TextProperties(rProps, rObj)
+ {
+ }
+
+ MeasureProperties::~MeasureProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> MeasureProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new MeasureProperties(*this, rObj));
+ }
+
+ void MeasureProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrMeasureObj& rObj = static_cast<SdrMeasureObj&>(GetSdrObject());
+
+ // call parent
+ TextProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // local changes
+ rObj.SetTextDirty();
+ }
+
+ void MeasureProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ TextProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ // get access to dimension line object
+ SdrMeasureObj& rObj = static_cast<SdrMeasureObj&>(GetSdrObject());
+
+ // mark dimension line text as changed (dirty) in the dimension line object
+ rObj.SetTextDirty();
+
+ // tdf#98525 ask the dimension line object to redraw the changed text
+ rObj.UndirtyText();
+ }
+
+ void MeasureProperties::ForceDefaultAttributes()
+ {
+ // call parent
+ TextProperties::ForceDefaultAttributes();
+
+ // force ItemSet
+ GetObjectItemSet();
+
+ //#71958# by default, the show units Bool-Item is set as hard
+ // attribute to sal_True to avoid confusion when copying SdrMeasureObj's
+ // from one application to another
+ mxItemSet->Put(SdrYesNoItem(SDRATTR_MEASURESHOWUNIT, true));
+
+ basegfx::B2DPolygon aNewPolygon;
+ aNewPolygon.append(basegfx::B2DPoint(100.0, 0.0));
+ aNewPolygon.append(basegfx::B2DPoint(200.0, 400.0));
+ aNewPolygon.append(basegfx::B2DPoint(0.0, 400.0));
+ aNewPolygon.setClosed(true);
+
+ mxItemSet->Put(XLineStartItem(OUString(), basegfx::B2DPolyPolygon(aNewPolygon)));
+ mxItemSet->Put(XLineStartWidthItem(200));
+ mxItemSet->Put(XLineEndItem(OUString(), basegfx::B2DPolyPolygon(aNewPolygon)));
+ mxItemSet->Put(XLineEndWidthItem(200));
+ mxItemSet->Put(XLineStyleItem(css::drawing::LineStyle_SOLID));
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/oleproperties.cxx b/svx/source/sdr/properties/oleproperties.cxx
new file mode 100644
index 000000000..587ff1d3f
--- /dev/null
+++ b/svx/source/sdr/properties/oleproperties.cxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/oleproperties.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdmodel.hxx>
+
+namespace sdr::properties
+{
+ void OleProperties::applyDefaultStyleSheetFromSdrModel()
+ {
+ SfxStyleSheet* pStyleSheet(GetSdrObject().getSdrModelFromSdrObject().GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj());
+
+ if(pStyleSheet)
+ {
+ // do not delete hard attributes when setting dsefault Style
+ SetStyleSheet(pStyleSheet, true, true);
+ }
+ else
+ {
+ SetMergedItem(XFillStyleItem(com::sun::star::drawing::FillStyle_NONE));
+ SetMergedItem(XLineStyleItem(com::sun::star::drawing::LineStyle_NONE));
+ }
+ }
+
+ OleProperties::OleProperties(SdrObject& rObj)
+ : RectangleProperties(rObj)
+ {
+ }
+
+ OleProperties::OleProperties(const OleProperties& rProps, SdrObject& rObj)
+ : RectangleProperties(rProps, rObj)
+ {
+ }
+
+ OleProperties::~OleProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> OleProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new OleProperties(*this, rObj));
+ }
+
+ void OleProperties::ForceDefaultAttributes()
+ {
+ // call parent
+ RectangleProperties::ForceDefaultAttributes();
+
+ // force ItemSet
+ GetObjectItemSet();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/pageproperties.cxx b/svx/source/sdr/properties/pageproperties.cxx
new file mode 100644
index 000000000..011ab2192
--- /dev/null
+++ b/svx/source/sdr/properties/pageproperties.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/pageproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svdobj.hxx>
+#include <tools/debug.hxx>
+
+
+namespace sdr::properties
+{
+ PageProperties::PageProperties(SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ }
+
+ PageProperties::PageProperties(const PageProperties& /*rProps*/, SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ }
+
+ PageProperties::~PageProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> PageProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new PageProperties(*this, rObj));
+ }
+
+ SfxItemSet PageProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool);
+ }
+
+ // get itemset. Override here to allow creating the empty itemset
+ // without asserting
+ const SfxItemSet& PageProperties::GetObjectItemSet() const
+ {
+ if(!mxEmptyItemSet)
+ {
+ mxEmptyItemSet.emplace(GetSdrObject().GetObjectItemPool());
+ }
+
+ DBG_ASSERT(mxEmptyItemSet, "Could not create an SfxItemSet(!)");
+
+ return *mxEmptyItemSet;
+ }
+
+ SfxStyleSheet* PageProperties::GetStyleSheet() const
+ {
+ // override to legally return a 0L pointer here
+ return nullptr;
+ }
+
+ void PageProperties::SetStyleSheet(SfxStyleSheet* /*pStyleSheet*/, bool /*bDontRemoveHardAttr*/,
+ bool /*bBroadcast*/)
+ {
+ // override to legally ignore the StyleSheet here
+ }
+
+ void PageProperties::ClearObjectItem(const sal_uInt16 /*nWhich*/)
+ {
+ // simply ignore item clearing on page objects
+ }
+
+ void PageProperties::SetObjectItem(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"PageProperties::SetObjectItem() should never be called");
+ }
+
+ void PageProperties::SetObjectItemDirect(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"PageProperties::SetObjectItemDirect() should never be called");
+ }
+
+ void PageProperties::ClearObjectItemDirect(const sal_uInt16 /*nWhich*/)
+ {
+ assert(!"PageProperties::ClearObjectItemDirect() should never be called");
+ }
+
+ void PageProperties::SetObjectItemSet(const SfxItemSet& /*rSet*/)
+ {
+ assert(!"PageProperties::SetObjectItemSet() should never be called");
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/properties.cxx b/svx/source/sdr/properties/properties.cxx
new file mode 100644
index 000000000..97a264712
--- /dev/null
+++ b/svx/source/sdr/properties/properties.cxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <libxml/xmlwriter.h>
+
+#include <svx/sdr/properties/properties.hxx>
+#include <sdr/properties/itemsettools.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svditer.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::properties
+{
+ BaseProperties::BaseProperties(SdrObject& rObj)
+ : mrObject(rObj)
+ {
+ }
+
+ BaseProperties::~BaseProperties()
+ {
+ }
+
+ const SdrObject& BaseProperties::GetSdrObject() const
+ {
+ return mrObject;
+ }
+
+ SdrObject& BaseProperties::GetSdrObject()
+ {
+ return mrObject;
+ }
+
+ const SfxItemSet& BaseProperties::GetMergedItemSet() const
+ {
+ // default implementation falls back to GetObjectItemSet()
+ return GetObjectItemSet();
+ }
+
+ void BaseProperties::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
+ {
+ // clear items if requested
+ if(bClearAllItems)
+ {
+ ClearObjectItem();
+ }
+
+ // default implementation falls back to SetObjectItemSet()
+ SetObjectItemSet(rSet);
+ }
+
+ void BaseProperties::SetMergedItem(const SfxPoolItem& rItem)
+ {
+ // default implementation falls back to SetObjectItem()
+ SetObjectItem(rItem);
+ }
+
+ void BaseProperties::ClearMergedItem(const sal_uInt16 nWhich)
+ {
+ // default implementation falls back to ClearObjectItem()
+ ClearObjectItem(nWhich);
+ }
+
+ void BaseProperties::ForceStyleToHardAttributes()
+ {
+ // force all attributes which come from styles to hard attributes
+ // to be able to live without the style. Default implementation does nothing.
+ // Override where an ItemSet is implemented.
+ }
+
+ void BaseProperties::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems)
+ {
+ ItemChangeBroadcaster aC(GetSdrObject());
+
+ if(bClearAllItems)
+ {
+ ClearObjectItem();
+ }
+
+ SetMergedItemSet(rSet);
+ BroadcastItemChange(aC);
+ }
+
+ const SfxPoolItem& BaseProperties::GetItem(const sal_uInt16 nWhich) const
+ {
+ return GetObjectItemSet().Get(nWhich);
+ }
+
+ void BaseProperties::BroadcastItemChange(const ItemChangeBroadcaster& rChange)
+ {
+ const sal_uInt32 nCount(rChange.GetRectangleCount());
+
+ // invalidate all new rectangles
+ SdrObject* pObj = &GetSdrObject();
+ if (pObj->GetObjIdentifier() == SdrObjKind::Group)
+ {
+ SdrObjGroup* pObjGroup = static_cast<SdrObjGroup*>(pObj);
+ SdrObjListIter aIter(pObjGroup, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pChildObj = aIter.Next();
+ pChildObj->BroadcastObjectChange();
+ }
+ }
+ else
+ {
+ pObj->BroadcastObjectChange();
+ }
+
+ // also send the user calls
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ pObj->SendUserCall(SdrUserCallType::ChangeAttr, rChange.GetRectangle(a));
+ }
+ }
+
+ sal_uInt32 BaseProperties::getVersion() const
+ {
+ return 0;
+ }
+
+ void BaseProperties::dumpAsXml(xmlTextWriterPtr pWriter) const
+ {
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("BaseProperties"));
+ (void)xmlTextWriterEndElement(pWriter);
+ }
+
+ void CleanupFillProperties( SfxItemSet& rItemSet )
+ {
+ const bool bFillBitmap = rItemSet.GetItemState(XATTR_FILLBITMAP, false) == SfxItemState::SET;
+ const bool bFillGradient = rItemSet.GetItemState(XATTR_FILLGRADIENT, false) == SfxItemState::SET;
+ const bool bFillHatch = rItemSet.GetItemState(XATTR_FILLHATCH, false) == SfxItemState::SET;
+ if( !(bFillBitmap || bFillGradient || bFillHatch) )
+ return;
+
+ const XFillStyleItem* pFillStyleItem = rItemSet.GetItem(XATTR_FILLSTYLE);
+ if( !pFillStyleItem )
+ return;
+
+ if( bFillBitmap && (pFillStyleItem->GetValue() != drawing::FillStyle_BITMAP) )
+ {
+ rItemSet.ClearItem( XATTR_FILLBITMAP );
+ }
+
+ if( bFillGradient && (pFillStyleItem->GetValue() != drawing::FillStyle_GRADIENT) )
+ {
+ rItemSet.ClearItem( XATTR_FILLGRADIENT );
+ }
+
+ if( bFillHatch && (pFillStyleItem->GetValue() != drawing::FillStyle_HATCH) )
+ {
+ rItemSet.ClearItem( XATTR_FILLHATCH );
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/rectangleproperties.cxx b/svx/source/sdr/properties/rectangleproperties.cxx
new file mode 100644
index 000000000..4c3a72a2f
--- /dev/null
+++ b/svx/source/sdr/properties/rectangleproperties.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/rectangleproperties.hxx>
+#include <svx/svdorect.hxx>
+
+
+namespace sdr::properties
+{
+ RectangleProperties::RectangleProperties(SdrObject& rObj)
+ : TextProperties(rObj)
+ {
+ }
+
+ RectangleProperties::RectangleProperties(const RectangleProperties& rProps, SdrObject& rObj)
+ : TextProperties(rProps, rObj)
+ {
+ }
+
+ RectangleProperties::~RectangleProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> RectangleProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new RectangleProperties(*this, rObj));
+ }
+
+ void RectangleProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrRectObj& rObj = static_cast<SdrRectObj&>(GetSdrObject());
+
+ // call parent
+ TextProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // local changes
+ rObj.SetXPolyDirty();
+ }
+
+ // set a new StyleSheet and broadcast
+ void RectangleProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ TextProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ SdrRectObj& rObj = static_cast<SdrRectObj&>(GetSdrObject());
+ rObj.SetXPolyDirty();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/textproperties.cxx b/svx/source/sdr/properties/textproperties.cxx
new file mode 100644
index 000000000..d8cdf80df
--- /dev/null
+++ b/svx/source/sdr/properties/textproperties.cxx
@@ -0,0 +1,631 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/textproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svl/itemiter.hxx>
+#include <svl/hint.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdtditm.hxx>
+#include <editeng/writingmodeitem.hxx>
+#include <svx/svdmodel.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <editeng/adjustitem.hxx>
+#include <svx/svdetc.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnwtit.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::properties
+{
+ SfxItemSet TextProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool,
+
+ // range from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+
+ // range from SdrTextObj
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ TextProperties::TextProperties(SdrObject& rObj)
+ : AttributeProperties(rObj),
+ maVersion(0)
+ {
+ }
+
+ TextProperties::TextProperties(const TextProperties& rProps, SdrObject& rObj)
+ : AttributeProperties(rProps, rObj),
+ maVersion(rProps.getVersion())
+ {
+ }
+
+ TextProperties::~TextProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> TextProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new TextProperties(*this, rObj));
+ }
+
+ void TextProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+ // #i101556# ItemSet has changed -> new version
+ maVersion++;
+
+ if (auto pOutliner = rObj.GetTextEditOutliner())
+ {
+ pOutliner->SetTextColumns(rObj.GetTextColumnsNumber(),
+ rObj.GetTextColumnsSpacing());
+ }
+
+ const svx::ITextProvider& rTextProvider(getTextProvider());
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ SdrText* pText = rTextProvider.getText( nText );
+
+ OutlinerParaObject* pParaObj = pText ? pText->GetOutlinerParaObject() : nullptr;
+
+ if(pParaObj)
+ {
+ const bool bTextEdit = rObj.IsTextEditActive() && (rObj.getActiveText() == pText);
+
+ // handle outliner attributes
+ GetObjectItemSet();
+ Outliner* pOutliner = rObj.GetTextEditOutliner();
+
+ if(!bTextEdit)
+ {
+ pOutliner = &rObj.ImpGetDrawOutliner();
+ pOutliner->SetText(*pParaObj);
+ }
+
+ sal_Int32 nParaCount(pOutliner->GetParagraphCount());
+
+ for(sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
+ {
+ SfxItemSet aSet(pOutliner->GetParaAttribs(nPara));
+ for (const SfxPoolItem* pItem : aChangedItems)
+ aSet.Put(*pItem);
+ if (nDeletedWhich)
+ aSet.ClearItem(nDeletedWhich);
+ pOutliner->SetParaAttribs(nPara, aSet);
+ }
+
+ if(!bTextEdit)
+ {
+ if(nParaCount)
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ SfxItemSet aNewSet(pOutliner->GetParaAttribs(0));
+ mxItemSet->Put(aNewSet);
+ }
+
+ std::optional<OutlinerParaObject> pTemp = pOutliner->CreateParaObject(0, nParaCount);
+ pOutliner->Clear();
+
+ rObj.NbcSetOutlinerParaObjectForText(std::move(pTemp),pText);
+ }
+ }
+ }
+
+ // Extra-Repaint for radical layout changes (#43139#)
+ for (const SfxPoolItem* pItem : aChangedItems)
+ if (pItem->Which() == SDRATTR_TEXT_CONTOURFRAME)
+ {
+ // Here only repaint wanted
+ rObj.ActionChanged();
+ //rObj.BroadcastObjectChange();
+ break;
+ }
+
+ // call parent
+ AttributeProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+ }
+
+ void TextProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
+ {
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+ // #i25616#
+ sal_Int32 nOldLineWidth(0);
+
+ if(XATTR_LINEWIDTH == nWhich && rObj.DoesSupportTextIndentingOnLineWidthChange())
+ {
+ nOldLineWidth = GetItem(XATTR_LINEWIDTH).GetValue();
+ }
+
+ if(pNewItem && (SDRATTR_TEXTDIRECTION == nWhich))
+ {
+ bool bVertical(css::text::WritingMode_TB_RL == static_cast<const SvxWritingModeItem*>(pNewItem)->GetValue());
+ rObj.SetVerticalWriting(bVertical);
+ }
+
+ // #95501# reset to default
+ if(!pNewItem && !nWhich && rObj.HasText() )
+ {
+ SdrOutliner& rOutliner = rObj.ImpGetDrawOutliner();
+
+ const svx::ITextProvider& rTextProvider(getTextProvider());
+ sal_Int32 nCount = rTextProvider.getTextCount();
+ while (nCount--)
+ {
+ SdrText* pText = rTextProvider.getText( nCount );
+ OutlinerParaObject* pParaObj = pText->GetOutlinerParaObject();
+ if( pParaObj )
+ {
+ rOutliner.SetText(*pParaObj);
+ sal_Int32 nParaCount(rOutliner.GetParagraphCount());
+
+ if(nParaCount)
+ {
+ ESelection aSelection( 0, 0, EE_PARA_ALL, EE_TEXTPOS_ALL);
+ rOutliner.RemoveAttribs(aSelection, true, 0);
+
+ std::optional<OutlinerParaObject> pTemp = rOutliner.CreateParaObject(0, nParaCount);
+ rOutliner.Clear();
+
+ rObj.NbcSetOutlinerParaObjectForText( std::move(pTemp), pText );
+ }
+ }
+ }
+ }
+
+ // call parent
+ AttributeProperties::ItemChange( nWhich, pNewItem );
+
+ // #i25616#
+ if(!(XATTR_LINEWIDTH == nWhich && rObj.DoesSupportTextIndentingOnLineWidthChange()))
+ return;
+
+ const sal_Int32 nNewLineWidth(GetItem(XATTR_LINEWIDTH).GetValue());
+ const sal_Int32 nDifference((nNewLineWidth - nOldLineWidth) / 2);
+
+ if(!nDifference)
+ return;
+
+ const bool bLineVisible(drawing::LineStyle_NONE != GetItem(XATTR_LINESTYLE).GetValue());
+
+ if(bLineVisible)
+ {
+ const sal_Int32 nLeftDist(GetItem(SDRATTR_TEXT_LEFTDIST).GetValue());
+ const sal_Int32 nRightDist(GetItem(SDRATTR_TEXT_RIGHTDIST).GetValue());
+ const sal_Int32 nUpperDist(GetItem(SDRATTR_TEXT_UPPERDIST).GetValue());
+ const sal_Int32 nLowerDist(GetItem(SDRATTR_TEXT_LOWERDIST).GetValue());
+
+ SetObjectItemDirect(makeSdrTextLeftDistItem(nLeftDist + nDifference));
+ SetObjectItemDirect(makeSdrTextRightDistItem(nRightDist + nDifference));
+ SetObjectItemDirect(makeSdrTextUpperDistItem(nUpperDist + nDifference));
+ SetObjectItemDirect(makeSdrTextLowerDistItem(nLowerDist + nDifference));
+ }
+ }
+
+ const svx::ITextProvider& TextProperties::getTextProvider() const
+ {
+ return static_cast<const SdrTextObj&>(GetSdrObject());
+ }
+
+ void TextProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ AttributeProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // #i101556# StyleSheet has changed -> new version
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+ maVersion++;
+
+ if(!rObj.IsLinkedText() )
+ {
+ SdrOutliner& rOutliner = rObj.ImpGetDrawOutliner();
+
+ const svx::ITextProvider& rTextProvider(getTextProvider());
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ SdrText* pText = rTextProvider.getText( nText );
+
+ OutlinerParaObject* pParaObj = pText ? pText->GetOutlinerParaObject() : nullptr;
+ if( !pParaObj )
+ continue;
+
+ // apply StyleSheet to all paragraphs
+ rOutliner.SetText(*pParaObj);
+ sal_Int32 nParaCount(rOutliner.GetParagraphCount());
+
+ if(nParaCount)
+ {
+ for(sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
+ {
+ std::optional<SfxItemSet> pTempSet;
+
+ // since setting the stylesheet removes all para attributes
+ if(bDontRemoveHardAttr)
+ {
+ // we need to remember them if we want to keep them
+ pTempSet.emplace(rOutliner.GetParaAttribs(nPara));
+ }
+
+ if(GetStyleSheet())
+ {
+ if((SdrObjKind::OutlineText == rObj.GetTextKind()) && (SdrInventor::Default == rObj.GetObjInventor()))
+ {
+ OUString aNewStyleSheetName(GetStyleSheet()->GetName());
+ aNewStyleSheetName = aNewStyleSheetName.copy(0, aNewStyleSheetName.getLength() - 1);
+ sal_Int16 nDepth = rOutliner.GetDepth(nPara);
+ aNewStyleSheetName += OUString::number( nDepth <= 0 ? 1 : nDepth + 1);
+ SfxStyleSheetBasePool* pStylePool(rObj.getSdrModelFromSdrObject().GetStyleSheetPool());
+ SfxStyleSheet* pNewStyle = nullptr;
+ if(pStylePool)
+ pNewStyle = static_cast<SfxStyleSheet*>(pStylePool->Find(aNewStyleSheetName, GetStyleSheet()->GetFamily()));
+ DBG_ASSERT( pNewStyle, "AutoStyleSheetName - Style not found!" );
+
+ if(pNewStyle)
+ {
+ rOutliner.SetStyleSheet(nPara, pNewStyle);
+ }
+ }
+ else
+ {
+ rOutliner.SetStyleSheet(nPara, GetStyleSheet());
+ }
+ }
+ else
+ {
+ // remove StyleSheet
+ rOutliner.SetStyleSheet(nPara, nullptr);
+ }
+
+ if(bDontRemoveHardAttr)
+ {
+ if(pTempSet)
+ {
+ // restore para attributes
+ rOutliner.SetParaAttribs(nPara, *pTempSet);
+ }
+ }
+ else
+ {
+ if(pNewStyleSheet)
+ {
+ // remove all hard paragraph attributes
+ // which occur in StyleSheet, take care of
+ // parents (!)
+ SfxItemIter aIter(pNewStyleSheet->GetItemSet());
+
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem;
+ pItem = aIter.NextItem())
+ {
+ if(!IsInvalidItem(pItem))
+ {
+ sal_uInt16 nW(pItem->Which());
+
+ if(nW >= EE_ITEMS_START && nW <= EE_ITEMS_END)
+ {
+ rOutliner.RemoveCharAttribs(nPara, nW);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ std::optional<OutlinerParaObject> pTemp = rOutliner.CreateParaObject(0, nParaCount);
+ rOutliner.Clear();
+ rObj.NbcSetOutlinerParaObjectForText(std::move(pTemp), pText);
+ }
+ }
+ }
+
+ if(rObj.IsTextFrame())
+ {
+ rObj.NbcAdjustTextFrameWidthAndHeight();
+ }
+ }
+
+ void TextProperties::ForceDefaultAttributes()
+ {
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+ if( rObj.GetObjInventor() == SdrInventor::Default )
+ {
+ const SdrObjKind nSdrObjKind = rObj.GetObjIdentifier();
+
+ if( nSdrObjKind == SdrObjKind::TitleText || nSdrObjKind == SdrObjKind::OutlineText )
+ return; // no defaults for presentation objects
+ }
+
+ bool bTextFrame(rObj.IsTextFrame());
+
+ // force ItemSet
+ GetObjectItemSet();
+
+ if(bTextFrame)
+ {
+ mxItemSet->Put(XLineStyleItem(drawing::LineStyle_NONE));
+ mxItemSet->Put(XFillColorItem(OUString(), COL_WHITE));
+ mxItemSet->Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ else
+ {
+ mxItemSet->Put(SvxAdjustItem(SvxAdjust::Center, EE_PARA_JUST));
+ mxItemSet->Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER));
+ mxItemSet->Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER));
+ }
+ }
+
+ void TextProperties::ForceStyleToHardAttributes()
+ {
+ // #i61284# call parent first to get the hard ObjectItemSet
+ AttributeProperties::ForceStyleToHardAttributes();
+
+ // #i61284# push hard ObjectItemSet to OutlinerParaObject attributes
+ // using existing functionality
+ GetObjectItemSet(); // force ItemSet
+ std::vector<const SfxPoolItem*> aChangedItems;
+ SfxItemIter aIter(*mxItemSet);
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
+ {
+ if(!IsInvalidItem(pItem))
+ aChangedItems.push_back(pItem);
+ }
+ ItemSetChanged(aChangedItems, 0);
+
+ // now the standard TextProperties stuff
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+ if(rObj.IsTextEditActive() || rObj.IsLinkedText())
+ return;
+
+ std::unique_ptr<Outliner> pOutliner = SdrMakeOutliner(OutlinerMode::OutlineObject, rObj.getSdrModelFromSdrObject());
+ const svx::ITextProvider& rTextProvider(getTextProvider());
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ SdrText* pText = rTextProvider.getText( nText );
+
+ OutlinerParaObject* pParaObj = pText ? pText->GetOutlinerParaObject() : nullptr;
+ if( !pParaObj )
+ continue;
+
+ pOutliner->SetText(*pParaObj);
+
+ sal_Int32 nParaCount(pOutliner->GetParagraphCount());
+
+ if(nParaCount)
+ {
+ bool bBurnIn(false);
+
+ for(sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
+ {
+ SfxStyleSheet* pSheet = pOutliner->GetStyleSheet(nPara);
+
+ if(pSheet)
+ {
+ SfxItemSet aParaSet(pOutliner->GetParaAttribs(nPara));
+ SfxItemSet aSet(*aParaSet.GetPool());
+ aSet.Put(pSheet->GetItemSet());
+
+ /** the next code handles a special case for paragraphs that contain a
+ url field. The color for URL fields is either the system color for
+ urls or the char color attribute that formats the portion in which the
+ url field is contained.
+ When we set a char color attribute to the paragraphs item set from the
+ styles item set, we would have this char color attribute as an attribute
+ that is spanned over the complete paragraph after xml import due to some
+ problems in the xml import (using a XCursor on import so it does not know
+ the paragraphs and can't set char attributes to paragraphs ).
+
+ To avoid this, as soon as we try to set a char color attribute from the style
+ we
+ 1. check if we have at least one url field in this paragraph
+ 2. if we found at least one url field, we span the char color attribute over
+ all portions that are not url fields and remove the char color attribute
+ from the paragraphs item set
+ */
+
+ bool bHasURL(false);
+
+ if(aSet.GetItemState(EE_CHAR_COLOR) == SfxItemState::SET)
+ {
+ EditEngine* pEditEngine = const_cast<EditEngine*>(&(pOutliner->GetEditEngine()));
+ std::vector<EECharAttrib> aAttribs;
+ pEditEngine->GetCharAttribs(nPara, aAttribs);
+
+ for(const auto& rAttrib : aAttribs)
+ {
+ if(rAttrib.pAttr && EE_FEATURE_FIELD == rAttrib.pAttr->Which())
+ {
+ const SvxFieldItem* pFieldItem = static_cast<const SvxFieldItem*>(rAttrib.pAttr);
+
+ if(pFieldItem)
+ {
+ const SvxFieldData* pData = pFieldItem->GetField();
+
+ if(dynamic_cast<const SvxURLField*>( pData))
+ {
+ bHasURL = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if(bHasURL)
+ {
+ SfxItemSetFixed<EE_CHAR_COLOR, EE_CHAR_COLOR> aColorSet(*aSet.GetPool());
+ aColorSet.Put(aSet, false);
+
+ ESelection aSel(nPara, 0);
+
+ for(const auto& rAttrib : aAttribs)
+ {
+ if(EE_FEATURE_FIELD == rAttrib.pAttr->Which())
+ {
+ aSel.nEndPos = rAttrib.nStart;
+
+ if(aSel.nStartPos != aSel.nEndPos)
+ pEditEngine->QuickSetAttribs(aColorSet, aSel);
+
+ aSel.nStartPos = rAttrib.nEnd;
+ }
+ }
+
+ aSel.nEndPos = pEditEngine->GetTextLen(nPara);
+
+ if(aSel.nStartPos != aSel.nEndPos)
+ {
+ pEditEngine->QuickSetAttribs( aColorSet, aSel );
+ }
+ }
+
+ }
+
+ aSet.Put(aParaSet, false);
+
+ if(bHasURL)
+ {
+ aSet.ClearItem(EE_CHAR_COLOR);
+ }
+
+ pOutliner->SetParaAttribs(nPara, aSet);
+ bBurnIn = true; // #i51163# Flag was set wrong
+ }
+ }
+
+ if(bBurnIn)
+ {
+ std::optional<OutlinerParaObject> pTemp = pOutliner->CreateParaObject(0, nParaCount);
+ rObj.NbcSetOutlinerParaObjectForText(std::move(pTemp),pText);
+ }
+ }
+
+ pOutliner->Clear();
+ }
+ }
+
+ void TextProperties::SetObjectItemNoBroadcast(const SfxPoolItem& rItem)
+ {
+ GetObjectItemSet();
+ mxItemSet->Put(rItem);
+ }
+
+
+ void TextProperties::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+ {
+ // call parent
+ AttributeProperties::Notify(rBC, rHint);
+
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+ if(!rObj.HasText())
+ return;
+
+ const svx::ITextProvider& rTextProvider(getTextProvider());
+ if(dynamic_cast<const SfxStyleSheet *>(&rBC) != nullptr)
+ {
+ SfxHintId nId(rHint.GetId());
+
+ if(SfxHintId::DataChanged == nId)
+ {
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ OutlinerParaObject* pParaObj = rTextProvider.getText( nText )->GetOutlinerParaObject();
+ if( pParaObj )
+ pParaObj->ClearPortionInfo();
+ }
+ rObj.SetTextSizeDirty();
+
+ if(rObj.IsTextFrame() && rObj.NbcAdjustTextFrameWidthAndHeight())
+ {
+ // here only repaint wanted
+ rObj.ActionChanged();
+ //rObj.BroadcastObjectChange();
+ }
+
+ // #i101556# content of StyleSheet has changed -> new version
+ maVersion++;
+ }
+
+ if(SfxHintId::Dying == nId)
+ {
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ OutlinerParaObject* pParaObj = rTextProvider.getText( nText )->GetOutlinerParaObject();
+ if( pParaObj )
+ pParaObj->ClearPortionInfo();
+ }
+ }
+ }
+ else if(dynamic_cast<const SfxStyleSheetBasePool *>(&rBC) != nullptr)
+ {
+ const SfxStyleSheetModifiedHint* pExtendedHint = dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint);
+
+ if(pExtendedHint
+ && SfxHintId::StyleSheetModified == pExtendedHint->GetId())
+ {
+ const OUString& aOldName(pExtendedHint->GetOldName());
+ OUString aNewName(pExtendedHint->GetStyleSheet()->GetName());
+ SfxStyleFamily eFamily = pExtendedHint->GetStyleSheet()->GetFamily();
+
+ if(aOldName != aNewName)
+ {
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ OutlinerParaObject* pParaObj = rTextProvider.getText( nText )->GetOutlinerParaObject();
+ if( pParaObj )
+ pParaObj->ChangeStyleSheetName(eFamily, aOldName, aNewName);
+ }
+ }
+ }
+ }
+ }
+
+ // #i101556# Handout version information
+ sal_uInt32 TextProperties::getVersion() const
+ {
+ return maVersion;
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/ContextChangeEventMultiplexer.cxx b/svx/source/sidebar/ContextChangeEventMultiplexer.cxx
new file mode 100644
index 000000000..ce552b0ac
--- /dev/null
+++ b/svx/source/sidebar/ContextChangeEventMultiplexer.cxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sidebar/ContextChangeEventMultiplexer.hxx>
+
+#include <com/sun/star/ui/ContextChangeEventObject.hpp>
+#include <com/sun/star/ui/XContextChangeEventMultiplexer.hpp>
+#include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <sfx2/viewsh.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+
+void ContextChangeEventMultiplexer::NotifyContextChange (
+ const css::uno::Reference<css::frame::XController>& rxController,
+ const vcl::EnumContext::Context eContext)
+{
+ if (!(rxController.is() && rxController->getFrame().is()))
+ return;
+
+ const css::ui::ContextChangeEventObject aEvent(
+ rxController,
+ GetModuleName(rxController->getFrame()),
+ vcl::EnumContext::GetContextName(eContext));
+
+ css::uno::Reference<css::ui::XContextChangeEventMultiplexer> xMultiplexer (
+ css::ui::ContextChangeEventMultiplexer::get(
+ ::comphelper::getProcessComponentContext()));
+ if (xMultiplexer.is())
+ xMultiplexer->broadcastContextChangeEvent(aEvent, rxController);
+
+ // notify the LOK too after all the change have taken effect.
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (SfxViewShell* pViewShell = SfxViewShell::Get(rxController))
+ SfxLokHelper::notifyContextChange(pViewShell, GetModuleName(rxController->getFrame()), vcl::EnumContext::GetContextName(eContext));
+ }
+}
+
+
+void ContextChangeEventMultiplexer::NotifyContextChange (
+ const SfxViewShell* pViewShell,
+ const vcl::EnumContext::Context eContext)
+{
+ if (pViewShell != nullptr)
+ NotifyContextChange(pViewShell->GetController(), eContext);
+}
+
+
+OUString ContextChangeEventMultiplexer::GetModuleName (
+ const css::uno::Reference<css::frame::XFrame>& rxFrame)
+{
+ try
+ {
+ const Reference<frame::XModuleManager> xModuleManager =
+ frame::ModuleManager::create( comphelper::getProcessComponentContext() );
+ return xModuleManager->identify(rxFrame);
+ }
+ catch (const Exception&)
+ {
+ // An exception typically means that a context change is notified
+ // during initialization or destruction of a view.
+ // Ignore it.
+ }
+ return vcl::EnumContext::GetApplicationName(
+ vcl::EnumContext::Application::NONE);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/EmptyPanel.cxx b/svx/source/sidebar/EmptyPanel.cxx
new file mode 100644
index 000000000..3bc21636b
--- /dev/null
+++ b/svx/source/sidebar/EmptyPanel.cxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "EmptyPanel.hxx"
+
+namespace svx::sidebar
+{
+EmptyPanel::EmptyPanel(weld::Widget* pParent)
+ : PanelLayout(pParent, "EmptyPanel", "svx/ui/sidebarempty.ui")
+ , mxMessageControl(m_xBuilder->weld_label("message"))
+{
+}
+
+EmptyPanel::~EmptyPanel() {}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/EmptyPanel.hxx b/svx/source/sidebar/EmptyPanel.hxx
new file mode 100644
index 000000000..26007a530
--- /dev/null
+++ b/svx/source/sidebar/EmptyPanel.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_EMPTYPANEL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_EMPTYPANEL_HXX
+
+#include <sfx2/sidebar/PanelLayout.hxx>
+
+namespace svx::sidebar
+{
+/** Display a panel that tells the user that the current deck is
+ intentionally empty.
+*/
+class EmptyPanel final : public PanelLayout
+{
+public:
+ explicit EmptyPanel(weld::Widget* pParent);
+ virtual ~EmptyPanel() override;
+
+private:
+ std::unique_ptr<weld::Label> mxMessageControl;
+};
+
+} // end of namespace svx::sidebar
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/PanelFactory.cxx b/svx/source/sidebar/PanelFactory.cxx
new file mode 100644
index 000000000..f55575d1a
--- /dev/null
+++ b/svx/source/sidebar/PanelFactory.cxx
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include "text/TextPropertyPanel.hxx"
+#include "styles/StylesPropertyPanel.hxx"
+#include "paragraph/ParaPropertyPanel.hxx"
+#include "lists/ListsPropertyPanel.hxx"
+#include "area/AreaPropertyPanel.hxx"
+#include "fontwork/FontworkPropertyPanel.hxx"
+#include "shadow/ShadowPropertyPanel.hxx"
+#include "effect/EffectPropertyPanel.hxx"
+#include "graphic/GraphicPropertyPanel.hxx"
+#include "line/LinePropertyPanel.hxx"
+#include "possize/PosSizePropertyPanel.hxx"
+#include "textcolumns/TextColumnsPropertyPanel.hxx"
+#include <DefaultShapesPanel.hxx>
+#if HAVE_FEATURE_AVMEDIA
+#include "media/MediaPlaybackPanel.hxx"
+#endif
+#include <GalleryControl.hxx>
+#include "EmptyPanel.hxx"
+#include <sfx2/sidebar/SidebarPanelBase.hxx>
+#include <sfx2/templdlg.hxx>
+#include <vcl/weldutils.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/ui/XSidebar.hpp>
+#include <com/sun/star/ui/XUIElementFactory.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+using namespace css;
+using namespace css::uno;
+using namespace svx::sidebar;
+
+
+namespace {
+
+/* Why this is not used ? Doesn't it need to inherit from XServiceInfo ?
+constexpr OUStringLiteral IMPLEMENTATION_NAME = u"org.apache.openoffice.comp.svx.sidebar.PanelFactory";
+constexpr OUStringLiteral SERVICE_NAME = u"com.sun.star.ui.UIElementFactory";
+*/
+
+typedef comphelper::WeakComponentImplHelper< css::ui::XUIElementFactory, css::lang::XServiceInfo >
+ PanelFactoryInterfaceBase;
+
+class PanelFactory
+ : public PanelFactoryInterfaceBase
+{
+public:
+ PanelFactory();
+ PanelFactory(const PanelFactory&) = delete;
+ PanelFactory& operator=(const PanelFactory&) = delete;
+
+ // XUIElementFactory
+ css::uno::Reference<css::ui::XUIElement> SAL_CALL createUIElement (
+ const OUString& rsResourceURL,
+ const ::css::uno::Sequence<css::beans::PropertyValue>& rArguments) override;
+
+ OUString SAL_CALL getImplementationName() override
+ { return "org.apache.openoffice.comp.svx.sidebar.PanelFactory"; }
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
+ { return cppu::supportsService(this, ServiceName); }
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
+ { return {"com.sun.star.ui.UIElementFactory"}; }
+};
+
+PanelFactory::PanelFactory()
+{
+}
+
+Reference<ui::XUIElement> SAL_CALL PanelFactory::createUIElement (
+ const OUString& rsResourceURL,
+ const ::css::uno::Sequence<css::beans::PropertyValue>& rArguments)
+{
+ const ::comphelper::NamedValueCollection aArguments (rArguments);
+ Reference<frame::XFrame> xFrame (aArguments.getOrDefault("Frame", Reference<frame::XFrame>()));
+ Reference<awt::XWindow> xParentWindow (aArguments.getOrDefault("ParentWindow", Reference<awt::XWindow>()));
+ Reference<ui::XSidebar> xSidebar (aArguments.getOrDefault("Sidebar", Reference<ui::XSidebar>()));
+ const sal_uInt64 nBindingsValue (aArguments.getOrDefault("SfxBindings", sal_uInt64(0)));
+ SfxBindings* pBindings = reinterpret_cast<SfxBindings*>(nBindingsValue);
+
+ weld::Widget* pParent(nullptr);
+ if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(xParentWindow.get()))
+ pParent = pTunnel->getWidget();
+
+ if (!pParent)
+ throw RuntimeException(
+ "PanelFactory::createUIElement called without ParentWindow",
+ nullptr);
+ if ( ! xFrame.is())
+ throw RuntimeException(
+ "PanelFactory::createUIElement called without Frame",
+ nullptr);
+ if (pBindings == nullptr)
+ throw RuntimeException(
+ "PanelFactory::createUIElement called without SfxBindings",
+ nullptr);
+
+ std::unique_ptr<PanelLayout> xControl;
+ ui::LayoutSize aLayoutSize (-1,-1,-1);
+
+ if (rsResourceURL.endsWith("/TextPropertyPanel"))
+ {
+ xControl = TextPropertyPanel::Create(pParent, xFrame);
+ }
+ else if (rsResourceURL.endsWith("/StylesPropertyPanel"))
+ {
+ xControl = StylesPropertyPanel::Create(pParent, xFrame);
+ }
+ else if (rsResourceURL.endsWith("/ParaPropertyPanel"))
+ {
+ xControl = ParaPropertyPanel::Create(pParent, xFrame, pBindings, xSidebar);
+ }
+ else if (rsResourceURL.endsWith("/ListsPropertyPanel"))
+ {
+ xControl = ListsPropertyPanel::Create(pParent, xFrame);
+ }
+ else if (rsResourceURL.endsWith("/AreaPropertyPanel"))
+ {
+ xControl = AreaPropertyPanel::Create(pParent, xFrame, pBindings);
+ }
+ else if (rsResourceURL.endsWith("/FontworkPropertyPanel"))
+ {
+ xControl = FontworkPropertyPanel::Create(pParent, xFrame);
+ }
+ else if (rsResourceURL.endsWith("/ShadowPropertyPanel"))
+ {
+ xControl = ShadowPropertyPanel::Create(pParent, pBindings);
+ }
+ else if (rsResourceURL.endsWith("/EffectPropertyPanel"))
+ {
+ xControl = EffectPropertyPanel::Create(pParent, pBindings);
+ }
+ else if (rsResourceURL.endsWith("/GraphicPropertyPanel"))
+ {
+ xControl = GraphicPropertyPanel::Create(pParent, pBindings);
+ }
+ else if (rsResourceURL.endsWith("/LinePropertyPanel"))
+ {
+ xControl = LinePropertyPanel::Create(pParent, xFrame, pBindings);
+ }
+ else if (rsResourceURL.endsWith("/PosSizePropertyPanel"))
+ {
+ xControl = PosSizePropertyPanel::Create(pParent, xFrame, pBindings, xSidebar);
+ }
+ else if (rsResourceURL.endsWith("/DefaultShapesPanel"))
+ {
+ xControl = DefaultShapesPanel::Create(pParent, xFrame);
+ }
+#if HAVE_FEATURE_AVMEDIA
+ else if (rsResourceURL.endsWith("/MediaPlaybackPanel"))
+ {
+ xControl = MediaPlaybackPanel::Create(pParent, pBindings);
+ }
+#endif
+ else if (rsResourceURL.endsWith("/GalleryPanel"))
+ {
+ xControl = std::make_unique<GalleryControl>(pParent);
+ aLayoutSize = ui::LayoutSize(300,-1,400);
+ }
+ else if (rsResourceURL.endsWith("/StyleListPanel"))
+ {
+ xControl = std::make_unique<SfxTemplatePanelControl>(pBindings, pParent);
+ aLayoutSize = ui::LayoutSize(0,-1,-1);
+ }
+ else if (rsResourceURL.endsWith("/EmptyPanel"))
+ {
+ xControl = std::make_unique<EmptyPanel>(pParent);
+ aLayoutSize = ui::LayoutSize(20,-1, 50);
+ }
+ else if (rsResourceURL.endsWith("/TextColumnsPropertyPanel"))
+ {
+ xControl = TextColumnsPropertyPanel::Create(pParent, pBindings);
+ }
+
+ if (xControl)
+ {
+ return sfx2::sidebar::SidebarPanelBase::Create(
+ rsResourceURL,
+ xFrame,
+ std::move(xControl),
+ aLayoutSize);
+ }
+ else
+ return Reference<ui::XUIElement>();
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+org_apache_openoffice_comp_svx_sidebar_PanelFactory_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new PanelFactory);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/SelectionAnalyzer.cxx b/svx/source/sidebar/SelectionAnalyzer.cxx
new file mode 100644
index 000000000..193b6b6b7
--- /dev/null
+++ b/svx/source/sidebar/SelectionAnalyzer.cxx
@@ -0,0 +1,479 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sidebar/SelectionAnalyzer.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/fontworkbar.hxx>
+
+using vcl::EnumContext;
+
+namespace svx::sidebar
+{
+EnumContext::Context SelectionAnalyzer::GetContextForSelection_SC(const SdrMarkList& rMarkList)
+{
+ EnumContext::Context eContext = EnumContext::Context::Unknown;
+
+ switch (rMarkList.GetMarkCount())
+ {
+ case 0:
+ // Empty selection. Return Context::Unknown to let the caller
+ // substitute it with the default context.
+ break;
+
+ case 1:
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ auto pTextObj = dynamic_cast<SdrTextObj*>(pObj);
+ if (pTextObj && pTextObj->IsInEditMode())
+ {
+ eContext = EnumContext::Context::DrawText;
+ }
+ else if (svx::checkForFontWork(pObj))
+ {
+ eContext = EnumContext::Context::DrawFontwork;
+ }
+ else
+ {
+ const SdrInventor nInv = pObj->GetObjInventor();
+ const SdrObjKind nObjId = pObj->GetObjIdentifier();
+ if (nInv == SdrInventor::Default)
+ eContext = GetContextForObjectId_SC(nObjId);
+ else if (nInv == SdrInventor::FmForm)
+ eContext = EnumContext::Context::Form;
+ }
+ break;
+ }
+
+ default:
+ {
+ // Multi selection.
+ switch (GetInventorTypeFromMark(rMarkList))
+ {
+ case SdrInventor::Default:
+ {
+ const SdrObjKind nObjId(GetObjectTypeFromMark(rMarkList));
+ if (nObjId == SdrObjKind::NONE)
+ eContext = EnumContext::Context::MultiObject;
+ else
+ eContext = GetContextForObjectId_SC(nObjId);
+ break;
+ }
+
+ case SdrInventor::FmForm:
+ eContext = EnumContext::Context::Form;
+ break;
+
+ case SdrInventor::Unknown:
+ eContext = EnumContext::Context::MultiObject;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return eContext;
+}
+
+EnumContext::Context SelectionAnalyzer::GetContextForSelection_SD(const SdrMarkList& rMarkList,
+ const ViewType eViewType)
+{
+ EnumContext::Context eContext = EnumContext::Context::Unknown;
+
+ // Note that some cases are handled by the caller. They rely on
+ // sd specific data.
+ switch (rMarkList.GetMarkCount())
+ {
+ case 0:
+ switch (eViewType)
+ {
+ case ViewType::Standard:
+ eContext = EnumContext::Context::DrawPage;
+ break;
+ case ViewType::Master:
+ eContext = EnumContext::Context::MasterPage;
+ break;
+ case ViewType::Handout:
+ eContext = EnumContext::Context::HandoutPage;
+ break;
+ case ViewType::Notes:
+ eContext = EnumContext::Context::NotesPage;
+ break;
+ }
+ break;
+
+ case 1:
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ auto pTextObj = dynamic_cast<SdrTextObj*>(pObj);
+ if (pTextObj && pTextObj->IsInEditMode())
+ {
+ if (pObj->GetObjIdentifier() == SdrObjKind::Table)
+ {
+ // Let a table object take precedence over text
+ // edit mode. The panels for text editing are
+ // present for table context as well, anyway.
+ eContext = EnumContext::Context::Table;
+ }
+ else
+ eContext = EnumContext::Context::DrawText;
+ }
+ else if (svx::checkForFontWork(pObj))
+ {
+ eContext = EnumContext::Context::DrawFontwork;
+ }
+ else
+ {
+ const SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nObjId = pObj->GetObjIdentifier();
+ if (nInv == SdrInventor::Default)
+ {
+ if (nObjId == SdrObjKind::Group)
+ {
+ nObjId = GetObjectTypeFromGroup(pObj);
+ if (nObjId == SdrObjKind::NONE)
+ nObjId = SdrObjKind::Group;
+ }
+ eContext = GetContextForObjectId_SD(nObjId, eViewType);
+ }
+ else if (nInv == SdrInventor::E3d)
+ {
+ eContext = EnumContext::Context::ThreeDObject;
+ }
+ else if (nInv == SdrInventor::FmForm)
+ {
+ eContext = EnumContext::Context::Form;
+ }
+ }
+ break;
+ }
+
+ default:
+ {
+ switch (GetInventorTypeFromMark(rMarkList))
+ {
+ case SdrInventor::Default:
+ {
+ const SdrObjKind nObjId = GetObjectTypeFromMark(rMarkList);
+ if (nObjId == SdrObjKind::NONE)
+ eContext = EnumContext::Context::MultiObject;
+ else
+ eContext = GetContextForObjectId_SD(nObjId, eViewType);
+ break;
+ }
+
+ case SdrInventor::E3d:
+ eContext = EnumContext::Context::ThreeDObject;
+ break;
+
+ case SdrInventor::FmForm:
+ eContext = EnumContext::Context::Form;
+ break;
+
+ case SdrInventor::Unknown:
+ eContext = EnumContext::Context::MultiObject;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ return eContext;
+}
+
+EnumContext::Context SelectionAnalyzer::GetContextForObjectId_SC(const SdrObjKind nObjectId)
+{
+ switch (nObjectId)
+ {
+ case SdrObjKind::Caption:
+ case SdrObjKind::TitleText:
+ case SdrObjKind::OutlineText:
+ case SdrObjKind::Text:
+ case SdrObjKind::Measure:
+ case SdrObjKind::Rectangle:
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathFill:
+ case SdrObjKind::Polygon:
+ case SdrObjKind::CircleSection:
+ case SdrObjKind::CircleArc:
+ case SdrObjKind::CircleCut:
+ case SdrObjKind::CustomShape:
+ case SdrObjKind::Group:
+ return EnumContext::Context::Draw;
+
+ case SdrObjKind::PolyLine:
+ case SdrObjKind::PathLine:
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::Line:
+ case SdrObjKind::Edge:
+ return EnumContext::Context::DrawLine;
+
+ case SdrObjKind::Graphic:
+ return EnumContext::Context::Graphic;
+
+ case SdrObjKind::OLE2:
+ return EnumContext::Context::OLE;
+
+ case SdrObjKind::Media:
+ return EnumContext::Context::Media;
+
+ default:
+ return EnumContext::Context::Unknown;
+ }
+}
+
+EnumContext::Context SelectionAnalyzer::GetContextForObjectId_SD(const SdrObjKind nObjectId,
+ const ViewType eViewType)
+{
+ switch (nObjectId)
+ {
+ case SdrObjKind::Caption:
+ case SdrObjKind::Measure:
+ case SdrObjKind::Rectangle:
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathFill:
+ case SdrObjKind::Polygon:
+ case SdrObjKind::CircleSection:
+ case SdrObjKind::CircleArc:
+ case SdrObjKind::CircleCut:
+ case SdrObjKind::CustomShape:
+ case SdrObjKind::Group:
+ return EnumContext::Context::Draw;
+
+ case SdrObjKind::Edge:
+ case SdrObjKind::PathLine:
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::PolyLine:
+ case SdrObjKind::Line:
+ return EnumContext::Context::DrawLine;
+
+ case SdrObjKind::TitleText:
+ case SdrObjKind::OutlineText:
+ case SdrObjKind::Text:
+ return EnumContext::Context::TextObject;
+
+ case SdrObjKind::Graphic:
+ return EnumContext::Context::Graphic;
+
+ case SdrObjKind::OLE2:
+ return EnumContext::Context::OLE;
+
+ case SdrObjKind::Media:
+ return EnumContext::Context::Media;
+
+ case SdrObjKind::Table:
+ return EnumContext::Context::Table;
+
+ case SdrObjKind::Page:
+ switch (eViewType)
+ {
+ case ViewType::Handout:
+ return EnumContext::Context::HandoutPage;
+ case ViewType::Notes:
+ return EnumContext::Context::NotesPage;
+ default:
+ return EnumContext::Context::Unknown;
+ }
+
+ default:
+ return EnumContext::Context::Unknown;
+ }
+}
+
+SdrInventor SelectionAnalyzer::GetInventorTypeFromMark(const SdrMarkList& rMarkList)
+{
+ const size_t nMarkCount(rMarkList.GetMarkCount());
+
+ if (nMarkCount < 1)
+ return SdrInventor::Unknown;
+
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+ const SdrInventor nFirstInv = pObj->GetObjInventor();
+
+ for (size_t nIndex = 1; nIndex < nMarkCount; ++nIndex)
+ {
+ pMark = rMarkList.GetMark(nIndex);
+ pObj = pMark->GetMarkedSdrObj();
+ const SdrInventor nInv(pObj->GetObjInventor());
+
+ if (nInv != nFirstInv)
+ return SdrInventor::Unknown;
+ }
+
+ return nFirstInv;
+}
+
+SdrObjKind SelectionAnalyzer::GetObjectTypeFromGroup(const SdrObject* pObj)
+{
+ SdrObjList* pObjList = pObj->GetSubList();
+ if (pObjList)
+ {
+ const size_t nSubObjCount(pObjList->GetObjCount());
+
+ if (nSubObjCount > 0)
+ {
+ SdrObject* pSubObj = pObjList->GetObj(0);
+ SdrObjKind nResultType = pSubObj->GetObjIdentifier();
+
+ if (nResultType == SdrObjKind::Group)
+ nResultType = GetObjectTypeFromGroup(pSubObj);
+
+ if (IsShapeType(nResultType))
+ nResultType = SdrObjKind::CustomShape;
+
+ if (IsTextObjType(nResultType))
+ nResultType = SdrObjKind::Text;
+
+ for (size_t nIndex = 1; nIndex < nSubObjCount; ++nIndex)
+ {
+ pSubObj = pObjList->GetObj(nIndex);
+ SdrObjKind nType(pSubObj->GetObjIdentifier());
+
+ if (nType == SdrObjKind::Group)
+ nType = GetObjectTypeFromGroup(pSubObj);
+
+ if (IsShapeType(nType))
+ nType = SdrObjKind::CustomShape;
+
+ if ((nType == SdrObjKind::CustomShape) && (nResultType == SdrObjKind::Text))
+ nType = SdrObjKind::Text;
+
+ if (IsTextObjType(nType))
+ nType = SdrObjKind::Text;
+
+ if ((nType == SdrObjKind::Text) && (nResultType == SdrObjKind::CustomShape))
+ nResultType = SdrObjKind::Text;
+
+ if (nType != nResultType)
+ return SdrObjKind::NONE;
+ }
+
+ return nResultType;
+ }
+ }
+
+ return SdrObjKind::NONE;
+}
+
+SdrObjKind SelectionAnalyzer::GetObjectTypeFromMark(const SdrMarkList& rMarkList)
+{
+ const size_t nMarkCount(rMarkList.GetMarkCount());
+
+ if (nMarkCount < 1)
+ return SdrObjKind::NONE;
+
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+ SdrObjKind nResultType = pObj->GetObjIdentifier();
+
+ if (nResultType == SdrObjKind::Group)
+ nResultType = GetObjectTypeFromGroup(pObj);
+
+ if (IsShapeType(nResultType))
+ nResultType = SdrObjKind::CustomShape;
+
+ if (IsTextObjType(nResultType))
+ nResultType = SdrObjKind::Text;
+
+ for (size_t nIndex = 1; nIndex < nMarkCount; ++nIndex)
+ {
+ pMark = rMarkList.GetMark(nIndex);
+ pObj = pMark->GetMarkedSdrObj();
+ SdrObjKind nType = pObj->GetObjIdentifier();
+
+ if (nType == SdrObjKind::Group)
+ nType = GetObjectTypeFromGroup(pObj);
+
+ if (IsShapeType(nType))
+ nType = SdrObjKind::CustomShape;
+
+ if ((nType == SdrObjKind::CustomShape) && (nResultType == SdrObjKind::Text))
+ nType = SdrObjKind::Text;
+
+ if (IsTextObjType(nType))
+ nType = SdrObjKind::Text;
+
+ if ((nType == SdrObjKind::Text) && (nResultType == SdrObjKind::CustomShape))
+ nResultType = SdrObjKind::Text;
+
+ if (nType != nResultType)
+ return SdrObjKind::NONE;
+ }
+
+ return nResultType;
+}
+
+bool SelectionAnalyzer::IsShapeType(const SdrObjKind nType)
+{
+ switch (nType)
+ {
+ case SdrObjKind::Line:
+ case SdrObjKind::CircleArc:
+ case SdrObjKind::PolyLine:
+ case SdrObjKind::PathLine:
+ case SdrObjKind::Rectangle:
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::CircleSection:
+ case SdrObjKind::CircleCut:
+ case SdrObjKind::PathFill:
+ case SdrObjKind::CustomShape:
+ case SdrObjKind::Caption:
+ case SdrObjKind::Measure:
+ case SdrObjKind::Edge:
+ case SdrObjKind::Polygon:
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::FreehandFill:
+
+ // #122145# adding SdrObjKind::OLE2 since these also allow line/fill style and may
+ // be multiselected/grouped with normal draw objects, e.g. math OLE objects
+ case SdrObjKind::OLE2:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool SelectionAnalyzer::IsTextObjType(const SdrObjKind nType)
+{
+ switch (nType)
+ {
+ case SdrObjKind::Text:
+ case SdrObjKind::TitleText:
+ case SdrObjKind::OutlineText:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/SelectionChangeHandler.cxx b/svx/source/sidebar/SelectionChangeHandler.cxx
new file mode 100644
index 000000000..f4ef4d893
--- /dev/null
+++ b/svx/source/sidebar/SelectionChangeHandler.cxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <svx/sidebar/SelectionChangeHandler.hxx>
+#include <svx/sidebar/ContextChangeEventMultiplexer.hxx>
+
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+
+#include <vcl/EnumContext.hxx>
+
+
+using namespace css;
+using namespace css::uno;
+
+namespace svx::sidebar {
+
+SelectionChangeHandler::SelectionChangeHandler (
+ const std::function<OUString()>& rSelectionChangeCallback,
+ const Reference<css::frame::XController>& rxController,
+ const vcl::EnumContext::Context eDefaultContext)
+ : maSelectionChangeCallback(rSelectionChangeCallback),
+ mxController(rxController),
+ meDefaultContext(eDefaultContext),
+ mbIsConnected(false)
+{
+}
+
+
+SelectionChangeHandler::~SelectionChangeHandler()
+{
+}
+
+
+void SAL_CALL SelectionChangeHandler::selectionChanged (const lang::EventObject&)
+{
+ if (maSelectionChangeCallback)
+ {
+ const vcl::EnumContext::Context eContext (
+ vcl::EnumContext::GetContextEnum(maSelectionChangeCallback()));
+ ContextChangeEventMultiplexer::NotifyContextChange(
+ mxController,
+ eContext==vcl::EnumContext::Context::Unknown
+ ? meDefaultContext
+ : eContext);
+ }
+}
+
+
+void SAL_CALL SelectionChangeHandler::disposing (const lang::EventObject&)
+{
+}
+
+
+void SelectionChangeHandler::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mbIsConnected)
+ Disconnect();
+}
+
+
+void SelectionChangeHandler::Connect()
+{
+ uno::Reference<view::XSelectionSupplier> xSupplier (mxController, uno::UNO_QUERY);
+ if (xSupplier.is())
+ {
+ mbIsConnected = true;
+ xSupplier->addSelectionChangeListener(this);
+ }
+}
+
+
+void SelectionChangeHandler::Disconnect()
+{
+ uno::Reference<view::XSelectionSupplier> xSupplier (mxController, uno::UNO_QUERY);
+ if (xSupplier.is())
+ {
+ mbIsConnected = false;
+ xSupplier->removeSelectionChangeListener(this);
+ }
+}
+
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/area/AreaPropertyPanel.cxx b/svx/source/sidebar/area/AreaPropertyPanel.cxx
new file mode 100644
index 000000000..fa634ee44
--- /dev/null
+++ b/svx/source/sidebar/area/AreaPropertyPanel.cxx
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "AreaPropertyPanel.hxx"
+#include <svx/svxids.hrc>
+#include <svx/xfltrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/bindings.hxx>
+
+
+using namespace css;
+using namespace css::uno;
+
+namespace svx::sidebar {
+
+AreaPropertyPanel::AreaPropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+ : AreaPropertyPanelBase(pParent, rxFrame),
+ maStyleControl(SID_ATTR_FILL_STYLE, *pBindings, *this),
+ maColorControl(SID_ATTR_FILL_COLOR, *pBindings, *this),
+ maGradientControl(SID_ATTR_FILL_GRADIENT, *pBindings, *this),
+ maHatchControl(SID_ATTR_FILL_HATCH, *pBindings, *this),
+ maBitmapControl(SID_ATTR_FILL_BITMAP, *pBindings, *this),
+ maGradientListControl(SID_GRADIENT_LIST, *pBindings, *this),
+ maHatchListControl(SID_HATCH_LIST, *pBindings, *this),
+ maBitmapListControl(SID_BITMAP_LIST, *pBindings, *this),
+ maPatternListControl(SID_PATTERN_LIST, *pBindings, *this),
+ maFillTransparenceController(SID_ATTR_FILL_TRANSPARENCE, *pBindings, *this),
+ maFillFloatTransparenceController(SID_ATTR_FILL_FLOATTRANSPARENCE, *pBindings, *this),
+ maFillUseSlideBackgroundController(SID_ATTR_FILL_USE_SLIDE_BACKGROUND, *pBindings, *this),
+ mpBindings(pBindings)
+{
+}
+
+AreaPropertyPanel::~AreaPropertyPanel()
+{
+ maStyleControl.dispose();
+ maColorControl.dispose();
+ maGradientControl.dispose();
+ maHatchControl.dispose();
+ maBitmapControl.dispose();
+ maGradientListControl.dispose();
+ maHatchListControl.dispose();
+ maBitmapListControl.dispose();
+ maPatternListControl.dispose();
+ maFillTransparenceController.dispose();
+ maFillFloatTransparenceController.dispose();
+}
+
+std::unique_ptr<PanelLayout> AreaPropertyPanel::Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to AreaPropertyPanel::Create", nullptr, 0);
+ if ( ! rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to AreaPropertyPanel::Create", nullptr, 1);
+ if (pBindings == nullptr)
+ throw lang::IllegalArgumentException("no SfxBindings given to AreaPropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<AreaPropertyPanel>(pParent, rxFrame, pBindings);
+}
+
+void AreaPropertyPanel::setFillTransparence(const XFillTransparenceItem& rItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_FILL_TRANSPARENCE,
+ SfxCallMode::RECORD, { &rItem });
+}
+
+void AreaPropertyPanel::setFillUseBackground(const XFillStyleItem* pStyleItem,
+ const XFillUseSlideBackgroundItem& rItem)
+{
+ const SfxPoolItem* pItem = nullptr;
+ auto pDispatcher = GetBindings()->GetDispatcher();
+ auto state = pDispatcher->QueryState(SID_ATTR_FILL_USE_SLIDE_BACKGROUND, pItem);
+ // FillUseSlideBackground is only available in Impress
+ if (state == SfxItemState::DISABLED)
+ {
+ setFillStyle(*pStyleItem);
+ }
+ else
+ {
+ pDispatcher->ExecuteList(SID_ATTR_FILL_USE_SLIDE_BACKGROUND, SfxCallMode::RECORD,
+ std::initializer_list<SfxPoolItem const*>{ &rItem, pStyleItem });
+ }
+}
+
+void AreaPropertyPanel::setFillFloatTransparence(const XFillFloatTransparenceItem& rItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_FILL_FLOATTRANSPARENCE,
+ SfxCallMode::RECORD, { &rItem });
+}
+
+void AreaPropertyPanel::setFillStyle(const XFillStyleItem& rItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_FILL_STYLE,
+ SfxCallMode::RECORD, { &rItem });
+}
+
+void AreaPropertyPanel::setFillStyleAndColor(const XFillStyleItem* pStyleItem,
+ const XFillColorItem& rColorItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_FILL_COLOR,
+ SfxCallMode::RECORD, pStyleItem
+ ? std::initializer_list<SfxPoolItem const*>{ &rColorItem, pStyleItem }
+ : std::initializer_list<SfxPoolItem const*>{ &rColorItem });
+}
+
+void AreaPropertyPanel::setFillStyleAndGradient(const XFillStyleItem* pStyleItem,
+ const XFillGradientItem& rGradientItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_FILL_GRADIENT,
+ SfxCallMode::RECORD, pStyleItem
+ ? std::initializer_list<SfxPoolItem const*>{ &rGradientItem, pStyleItem }
+ : std::initializer_list<SfxPoolItem const*>{ &rGradientItem });
+}
+
+void AreaPropertyPanel::setFillStyleAndHatch(const XFillStyleItem* pStyleItem,
+ const XFillHatchItem& rHatchItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_FILL_HATCH,
+ SfxCallMode::RECORD, pStyleItem
+ ? std::initializer_list<SfxPoolItem const*>{ &rHatchItem, pStyleItem }
+ : std::initializer_list<SfxPoolItem const*>{ &rHatchItem });
+}
+
+void AreaPropertyPanel::setFillStyleAndBitmap(const XFillStyleItem* pStyleItem,
+ const XFillBitmapItem& rBitmapItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_FILL_BITMAP,
+ SfxCallMode::RECORD, pStyleItem
+ ? std::initializer_list<SfxPoolItem const*>{ &rBitmapItem, pStyleItem }
+ : std::initializer_list<SfxPoolItem const*>{ &rBitmapItem });
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/area/AreaPropertyPanel.hxx b/svx/source/sidebar/area/AreaPropertyPanel.hxx
new file mode 100644
index 000000000..6c398e6ac
--- /dev/null
+++ b/svx/source/sidebar/area/AreaPropertyPanel.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_AREA_AREAPROPERTYPANEL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_AREA_AREAPROPERTYPANEL_HXX
+
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+
+#include <svx/sidebar/AreaPropertyPanelBase.hxx>
+
+class XFillFloatTransparenceItem;
+class XFillTransparenceItem;
+class XFillUseSlideBackgroundItem;
+class XFillStyleItem;
+class XFillGradientItem;
+class XFillColorItem;
+class XFillHatchItem;
+class XFillBitmapItem;
+
+namespace svx::sidebar {
+
+class AreaTransparencyGradientControl;
+
+class AreaPropertyPanel : public AreaPropertyPanelBase
+{
+public:
+ static std::unique_ptr<PanelLayout> Create(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings);
+
+ SfxBindings* GetBindings() { return mpBindings;}
+
+ // constructor/destructor
+ AreaPropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings);
+
+ virtual ~AreaPropertyPanel() override;
+
+ virtual void setFillTransparence(const XFillTransparenceItem& rItem) override;
+ virtual void setFillUseBackground(const XFillStyleItem* pStyleItem, const XFillUseSlideBackgroundItem& rItem) override;
+ virtual void setFillFloatTransparence(const XFillFloatTransparenceItem& rItem) override;
+ virtual void setFillStyle(const XFillStyleItem& rItem) override;
+ virtual void setFillStyleAndColor(const XFillStyleItem* pStyleItem, const XFillColorItem& aColorItem) override;
+ virtual void setFillStyleAndGradient(const XFillStyleItem* pStyleItem, const XFillGradientItem& aGradientItem) override;
+ virtual void setFillStyleAndHatch(const XFillStyleItem* pStyleItem, const XFillHatchItem& aHatchItem) override;
+ virtual void setFillStyleAndBitmap(const XFillStyleItem* pStyleItem, const XFillBitmapItem& aHatchItem) override;
+
+private:
+ ::sfx2::sidebar::ControllerItem maStyleControl;
+ ::sfx2::sidebar::ControllerItem maColorControl;
+ ::sfx2::sidebar::ControllerItem maGradientControl;
+ ::sfx2::sidebar::ControllerItem maHatchControl;
+ ::sfx2::sidebar::ControllerItem maBitmapControl;
+ ::sfx2::sidebar::ControllerItem maGradientListControl;
+ ::sfx2::sidebar::ControllerItem maHatchListControl;
+ ::sfx2::sidebar::ControllerItem maBitmapListControl;
+ ::sfx2::sidebar::ControllerItem maPatternListControl;
+ ::sfx2::sidebar::ControllerItem maFillTransparenceController;
+ ::sfx2::sidebar::ControllerItem maFillFloatTransparenceController;
+ ::sfx2::sidebar::ControllerItem maFillUseSlideBackgroundController;
+
+ SfxBindings* mpBindings;
+};
+
+
+} // end of namespace svx::sidebar
+
+
+#endif // INCLUDED_SVX_SOURCE_SIDEBAR_AREA_AREAPROPERTYPANEL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/area/AreaPropertyPanelBase.cxx b/svx/source/sidebar/area/AreaPropertyPanelBase.cxx
new file mode 100644
index 000000000..672ab145f
--- /dev/null
+++ b/svx/source/sidebar/area/AreaPropertyPanelBase.cxx
@@ -0,0 +1,1371 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+#include <svx/sidebar/AreaPropertyPanelBase.hxx>
+#include <svx/drawitem.hxx>
+#include <svx/itemwin.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/objsh.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xfilluseslidebackgrounditem.hxx>
+#include <svx/xtable.hxx>
+#include <sfx2/sidebar/Panel.hxx>
+#include <sfx2/opengrf.hxx>
+#include <sfx2/weldutils.hxx>
+#include <tools/urlobj.hxx>
+#include <bitmaps.hlst>
+#include <comphelper/lok.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+constexpr OStringLiteral SIDEBARGRADIENT = "sidebargradient";
+
+namespace svx::sidebar {
+
+namespace {
+
+enum eFillStyle
+{
+ NONE,
+ SOLID,
+ GRADIENT,
+ HATCH,
+ BITMAP,
+ PATTERN,
+ USE_BACKGROUND
+};
+
+}
+
+const sal_Int32 AreaPropertyPanelBase::DEFAULT_CENTERX = 50;
+const sal_Int32 AreaPropertyPanelBase::DEFAULT_CENTERY = 50;
+const sal_Int32 AreaPropertyPanelBase::DEFAULT_ANGLE = 0;
+const sal_Int32 AreaPropertyPanelBase::DEFAULT_STARTVALUE = 0;
+const sal_Int32 AreaPropertyPanelBase::DEFAULT_ENDVALUE = 16777215;
+const sal_Int32 AreaPropertyPanelBase::DEFAULT_BORDER = 0;
+
+AreaPropertyPanelBase::AreaPropertyPanelBase(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame)
+ : PanelLayout(pParent, "AreaPropertyPanel", "svx/ui/sidebararea.ui"),
+ mxFrame(rxFrame),
+ meLastXFS(static_cast<sal_uInt16>(-1)),
+ mnLastPosHatch(0),
+ mnLastPosBitmap(0),
+ mnLastPosPattern(0),
+ mnLastTransSolid(50),
+ mxColorTextFT(m_xBuilder->weld_label("filllabel")),
+ mxLbFillType(m_xBuilder->weld_combo_box("fillstylearea")),
+ mxLbFillAttr(m_xBuilder->weld_combo_box("fillattrhb")),
+ mxLbFillGradFrom(new ColorListBox(m_xBuilder->weld_menu_button("fillgrad1"), [this]{ return GetFrameWeld(); })),
+ mxLbFillGradTo(new ColorListBox(m_xBuilder->weld_menu_button("fillgrad2"), [this]{ return GetFrameWeld(); })),
+ mxToolBoxColor(m_xBuilder->weld_toolbar("selectcolor")),
+ mxColorDispatch(new ToolbarUnoDispatcher(*mxToolBoxColor, *m_xBuilder, rxFrame)),
+ mxTrspTextFT(m_xBuilder->weld_label("transparencylabel")),
+ mxLBTransType(m_xBuilder->weld_combo_box("transtype")),
+ mxMTRTransparent(m_xBuilder->weld_metric_spin_button("settransparency", FieldUnit::PERCENT)),
+ mxSldTransparent(m_xBuilder->weld_scale("transparencyslider")),
+ mxBTNGradient(m_xBuilder->weld_toolbar("selectgradient")),
+ mxMTRAngle(m_xBuilder->weld_metric_spin_button("gradangle", FieldUnit::DEGREE)),
+ mxGradientStyle(m_xBuilder->weld_combo_box("gradientstyle")),
+ mxBmpImport(m_xBuilder->weld_button("bmpimport")),
+ maImgAxial(BMP_AXIAL),
+ maImgElli(BMP_ELLI),
+ maImgQuad(BMP_QUAD),
+ maImgRadial(BMP_RADIAL),
+ maImgSquare(BMP_SQUARE),
+ maImgLinear(BMP_LINEAR)
+{
+ Initialize();
+}
+
+AreaPropertyPanelBase::~AreaPropertyPanelBase()
+{
+ mxTrGrPopup.reset();
+ mxColorTextFT.reset();
+ mxLbFillType.reset();
+ mxLbFillAttr.reset();
+ mxColorDispatch.reset();
+ mxToolBoxColor.reset();
+ mxTrspTextFT.reset();
+ mxLBTransType.reset();
+ mxMTRTransparent.reset();
+ mxSldTransparent.reset();
+ mxBTNGradient.reset();
+ mxMTRAngle.reset();
+ mxLbFillGradFrom.reset();
+ mxLbFillGradTo.reset();
+ mxGradientStyle.reset();
+ mxBmpImport.reset();
+}
+
+void AreaPropertyPanelBase::Initialize()
+{
+ SvxFillTypeBox::Fill(*mxLbFillType);
+
+ mxLbFillAttr->set_size_request(42, -1);
+
+ maGradientLinear.SetXOffset(DEFAULT_CENTERX);
+ maGradientLinear.SetYOffset(DEFAULT_CENTERY);
+ maGradientLinear.SetAngle(Degree10(DEFAULT_ANGLE));
+ maGradientLinear.SetStartColor(Color(DEFAULT_STARTVALUE));
+ maGradientLinear.SetEndColor(Color(DEFAULT_ENDVALUE));
+ maGradientLinear.SetBorder(DEFAULT_BORDER);
+ maGradientLinear.SetGradientStyle(css::awt::GradientStyle_LINEAR);
+
+ maGradientAxial = maGradientLinear;
+ maGradientAxial.SetGradientStyle(css::awt::GradientStyle_AXIAL);
+
+ maGradientRadial = maGradientLinear;
+ maGradientRadial.SetGradientStyle(css::awt::GradientStyle_RADIAL);
+
+ maGradientElliptical = maGradientLinear;
+ maGradientElliptical.SetGradientStyle(css::awt::GradientStyle_ELLIPTICAL);
+
+ maGradientSquare = maGradientLinear;
+ maGradientSquare.SetGradientStyle(css::awt::GradientStyle_SQUARE);
+
+ maGradientRect = maGradientLinear;
+ maGradientRect.SetGradientStyle(css::awt::GradientStyle_RECT);
+
+
+ mxLbFillType->connect_changed( LINK( this, AreaPropertyPanelBase, SelectFillTypeHdl ) );
+
+ Link<weld::ComboBox&,void> aLink = LINK( this, AreaPropertyPanelBase, SelectFillAttrHdl );
+ mxLbFillAttr->connect_changed( aLink );
+ mxGradientStyle->connect_changed( aLink );
+ Link<ColorListBox&,void> aLink3 = LINK( this, AreaPropertyPanelBase, SelectFillColorHdl );
+ mxLbFillGradFrom->SetSelectHdl( aLink3 );
+ mxLbFillGradTo->SetSelectHdl( aLink3 );
+ mxMTRAngle->connect_value_changed(LINK(this,AreaPropertyPanelBase, ChangeGradientAngle));
+
+ // https://gerrit.libreoffice.org/c/core/+/87313 set a small width to force widgets to
+ // take their final width from other widgets in the grid
+ mxLbFillGradFrom->get_widget().set_size_request(42, -1);
+ mxLbFillGradTo->get_widget().set_size_request(42, -1);
+
+ mxLBTransType->connect_changed(LINK(this, AreaPropertyPanelBase, ChangeTrgrTypeHdl_Impl));
+
+ SetTransparency( 50 );
+ mxMTRTransparent->connect_value_changed(LINK(this, AreaPropertyPanelBase, ModifyTransparentHdl_Impl));
+ mxSldTransparent->connect_value_changed(LINK(this, AreaPropertyPanelBase, ModifyTransSliderHdl));
+
+ mxTrGrPopup = std::make_unique<AreaTransparencyGradientPopup>(mxFrame, *this, mxBTNGradient.get());
+
+ mxBTNGradient->set_item_popover(SIDEBARGRADIENT, mxTrGrPopup->getTopLevel());
+ mxBTNGradient->connect_clicked(LINK(this, AreaPropertyPanelBase, ToolbarHdl_Impl));
+
+ mxBTNGradient->set_item_icon_name(SIDEBARGRADIENT, maImgLinear);
+ mxBTNGradient->hide();
+ mxBmpImport->connect_clicked( LINK(this, AreaPropertyPanelBase, ClickImportBitmapHdl));
+}
+
+IMPL_LINK_NOARG(AreaPropertyPanelBase, ToolbarHdl_Impl, const OString&, void)
+{
+ mxBTNGradient->set_menu_item_active(SIDEBARGRADIENT, !mxBTNGradient->get_menu_item_active(SIDEBARGRADIENT));
+}
+
+void AreaPropertyPanelBase::SetTransparency(sal_uInt16 nVal)
+{
+ mxSldTransparent->set_value(nVal);
+ mxMTRTransparent->set_value(nVal, FieldUnit::PERCENT);
+}
+
+IMPL_LINK_NOARG(AreaPropertyPanelBase, ClickImportBitmapHdl, weld::Button&, void)
+{
+ SvxOpenGraphicDialog aDlg("Import", GetFrameWeld());
+ aDlg.EnableLink(false);
+ if( aDlg.Execute() != ERRCODE_NONE )
+ return;
+
+ Graphic aGraphic;
+ auto xWait = std::make_unique<weld::WaitObject>(m_xContainer.get());
+ ErrCode nError = aDlg.GetGraphic( aGraphic );
+ xWait.reset();
+ if( nError != ERRCODE_NONE )
+ return;
+
+ mxLbFillAttr->clear();
+
+ if (SfxObjectShell* pSh = SfxObjectShell::Current())
+ {
+ INetURLObject aURL(aDlg.GetPath());
+ OUString aFileName = aURL.GetLastName().getToken(0, '.');
+ OUString aName = aFileName;
+
+ XBitmapListRef pList = pSh->GetItem(SID_BITMAP_LIST)->GetBitmapList();
+
+ tools::Long j = 1;
+ bool bValidBitmapName = false;
+ while( !bValidBitmapName )
+ {
+ bValidBitmapName = true;
+ for( tools::Long i = 0; i < pList->Count() && bValidBitmapName; i++ )
+ {
+ if( aName == pList->GetBitmap(i)->GetName() )
+ {
+ bValidBitmapName = false;
+ aName = aFileName + OUString::number(j++);
+ }
+ }
+ }
+
+ pList->Insert(std::make_unique<XBitmapEntry>(aGraphic, aName));
+ pList->Save();
+
+ SvxFillAttrBox::Fill(*mxLbFillAttr, pList);
+
+ mxLbFillAttr->set_active_text(aName);
+ SelectFillAttrHdl(*mxLbFillAttr);
+ }
+}
+
+IMPL_LINK_NOARG(AreaPropertyPanelBase, SelectFillTypeHdl, weld::ComboBox&, void)
+{
+ FillStyleChanged(true);
+}
+
+IMPL_LINK_NOARG(AreaPropertyPanelBase, SelectFillColorHdl, ColorListBox&, void)
+{
+ SelectFillAttrHdl_Impl();
+}
+
+IMPL_LINK_NOARG(AreaPropertyPanelBase, SelectFillAttrHdl, weld::ComboBox&, void)
+{
+ SelectFillAttrHdl_Impl();
+}
+
+IMPL_LINK_NOARG(AreaPropertyPanelBase, ChangeGradientAngle, weld::MetricSpinButton&, void)
+{
+ SelectFillAttrHdl_Impl();
+}
+
+void AreaPropertyPanelBase::SelectFillAttrHdl_Impl()
+{
+ sal_Int32 nPosFillStyle = static_cast<eFillStyle>(mxLbFillType->get_active());
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+
+ // #i122676# dependent from bFillStyleChange, do execute a single or two
+ // changes in one Execute call
+ const bool bFillStyleChange(static_cast<eFillStyle>(meLastXFS) != static_cast<eFillStyle>(nPosFillStyle));
+
+ switch(nPosFillStyle)
+ {
+ case eFillStyle::NONE:
+ {
+ if(bFillStyleChange)
+ {
+ const XFillStyleItem aXFillStyleItem(drawing::FillStyle_NONE);
+ // Need to disable the XFillUseSlideBackgroundItem
+ const XFillUseSlideBackgroundItem aXFillUseSlideBackgroundItem(false);
+ setFillUseBackground(&aXFillStyleItem, aXFillUseSlideBackgroundItem);
+ }
+ break;
+ }
+ case eFillStyle::SOLID:
+ {
+ if(bFillStyleChange)
+ {
+ // #i122676# Single FillStyle change call needed here
+ XFillStyleItem aXFillStyleItem(drawing::FillStyle_SOLID);
+ setFillStyle(aXFillStyleItem);
+ }
+ break;
+ }
+ case eFillStyle::GRADIENT:
+ {
+
+ if (pSh && pSh->GetItem(SID_COLOR_TABLE))
+ {
+ XGradient aGradient;
+ aGradient.SetAngle(Degree10(mxMTRAngle->get_value(FieldUnit::DEGREE) * 10));
+ aGradient.SetGradientStyle(static_cast<css::awt::GradientStyle>(mxGradientStyle->get_active()));
+ aGradient.SetStartColor(mxLbFillGradFrom->GetSelectEntryColor());
+ aGradient.SetEndColor(mxLbFillGradTo->GetSelectEntryColor());
+
+ const XFillGradientItem aXFillGradientItem(mxLbFillAttr->get_active_text(), aGradient);
+
+ // #i122676# Change FillStyle and Gradient in one call
+ XFillStyleItem aXFillStyleItem(drawing::FillStyle_GRADIENT);
+ setFillStyleAndGradient(bFillStyleChange ? &aXFillStyleItem : nullptr, aXFillGradientItem);
+ }
+ break;
+ }
+ case eFillStyle::HATCH:
+ {
+ sal_Int32 nPos = mxLbFillAttr->get_active();
+
+ if (nPos == -1)
+ {
+ nPos = mnLastPosHatch;
+ }
+
+ if (nPos != -1 && pSh && pSh->GetItem(SID_HATCH_LIST))
+ {
+ const SvxHatchListItem * pItem = pSh->GetItem(SID_HATCH_LIST);
+
+ if(nPos < pItem->GetHatchList()->Count())
+ {
+ const XHatch aHatch = pItem->GetHatchList()->GetHatch(nPos)->GetHatch();
+ const XFillHatchItem aXFillHatchItem( mxLbFillAttr->get_active_text(), aHatch);
+
+ // #i122676# Change FillStyle and Hatch in one call
+ XFillStyleItem aXFillStyleItem(drawing::FillStyle_HATCH);
+ setFillStyleAndHatch(bFillStyleChange ? &aXFillStyleItem : nullptr, aXFillHatchItem);
+ }
+ }
+
+ if (nPos != -1)
+ {
+ mnLastPosHatch = nPos;
+ }
+ break;
+ }
+ case eFillStyle::BITMAP:
+ {
+ sal_Int32 nPos = mxLbFillAttr->get_active();
+
+ if (nPos == -1)
+ {
+ nPos = mnLastPosBitmap;
+ }
+
+ if (nPos != -1 && pSh && pSh->GetItem(SID_BITMAP_LIST))
+ {
+ const SvxBitmapListItem * pItem = pSh->GetItem(SID_BITMAP_LIST);
+
+ if(nPos < pItem->GetBitmapList()->Count())
+ {
+ const XBitmapEntry* pXBitmapEntry = pItem->GetBitmapList()->GetBitmap(nPos);
+ const XFillBitmapItem aXFillBitmapItem(mxLbFillAttr->get_active_text(), pXBitmapEntry->GetGraphicObject());
+
+ // #i122676# Change FillStyle and Bitmap in one call
+ XFillStyleItem aXFillStyleItem(drawing::FillStyle_BITMAP);
+ setFillStyleAndBitmap(bFillStyleChange ? &aXFillStyleItem : nullptr, aXFillBitmapItem);
+ }
+ }
+
+ if (nPos != -1)
+ {
+ mnLastPosBitmap = nPos;
+ }
+ break;
+ }
+ case eFillStyle::PATTERN:
+ {
+ sal_Int32 nPos = mxLbFillAttr->get_active();
+
+ if (nPos == -1)
+ {
+ nPos = mnLastPosPattern;
+ }
+
+ if (nPos != -1 && pSh && pSh->GetItem(SID_PATTERN_LIST))
+ {
+ const SvxPatternListItem * pItem = pSh->GetItem(SID_PATTERN_LIST);
+
+ if(nPos < pItem->GetPatternList()->Count())
+ {
+ const XBitmapEntry* pXPatternEntry = pItem->GetPatternList()->GetBitmap(nPos);
+ const XFillBitmapItem aXFillBitmapItem(mxLbFillAttr->get_active_text(), pXPatternEntry->GetGraphicObject());
+
+ // #i122676# Change FillStyle and Bitmap in one call
+ XFillStyleItem aXFillStyleItem(drawing::FillStyle_BITMAP);
+ setFillStyleAndBitmap(bFillStyleChange ? &aXFillStyleItem : nullptr, aXFillBitmapItem);
+ }
+ }
+
+ if (nPos != -1)
+ {
+ mnLastPosPattern = nPos;
+ }
+ break;
+ }
+ }
+ if (m_pPanel && !comphelper::LibreOfficeKit::isActive())
+ m_pPanel->TriggerDeckLayouting();
+}
+
+void AreaPropertyPanelBase::FillStyleChanged(bool bUpdateModel)
+{
+ sal_Int32 nPos = static_cast<eFillStyle>(mxLbFillType->get_active());
+ mxLbFillAttr->clear();
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ if (!pSh)
+ return;
+
+ bool bShowLbFillAttr = false;
+ bool bShowLbFillGradFrom = false;
+ bool bShowLbFillGradTo = false;
+ bool bShowGradientStyle = false;
+ bool bShowMTRAngle = false;
+ bool bShowToolBoxColor = false;
+ bool bShowBmpImport = false;
+
+ // #i122676# Do no longer trigger two Execute calls, one for SID_ATTR_FILL_STYLE
+ // and one for setting the fill attribute itself, but add two SfxPoolItems to the
+ // call to get just one action at the SdrObject and to create only one Undo action, too.
+ // Checked that this works in all apps.
+ switch (nPos)
+ {
+ default:
+ case NONE:
+ {
+ if (bUpdateModel)
+ {
+ const XFillStyleItem aXFillStyleItem(drawing::FillStyle_NONE);
+ // Need to disable the XFillUseSlideBackgroundItem
+ const XFillUseSlideBackgroundItem aXFillUseSlideBackgroundItem(false);
+ setFillUseBackground(&aXFillStyleItem, aXFillUseSlideBackgroundItem);
+ }
+
+ break;
+ }
+ case SOLID:
+ {
+ bShowToolBoxColor = true;
+
+ if (bUpdateModel)
+ {
+ const Color aColor = mpColorItem ? mpColorItem->GetColorValue() : COL_AUTO;
+ const XFillColorItem aXFillColorItem("", aColor);
+
+ // #i122676# change FillStyle and Color in one call
+ XFillStyleItem aXFillStyleItem(drawing::FillStyle_SOLID);
+ setFillStyleAndColor(&aXFillStyleItem, aXFillColorItem);
+ }
+ break;
+ }
+ case GRADIENT:
+ {
+ bShowLbFillGradFrom = true;
+ bShowLbFillGradTo = true;
+ bShowGradientStyle = true;
+ bShowMTRAngle = true;
+
+ mxLbFillAttr->set_sensitive(true);
+ mxLbFillGradTo->set_sensitive(true);
+ mxLbFillGradFrom->set_sensitive(true);
+ mxGradientStyle->set_sensitive(true);
+ mxMTRAngle->set_sensitive(true);
+ mxLbFillAttr->clear();
+
+ if (bUpdateModel)
+ {
+ mxLbFillAttr->hide();
+ mxToolBoxColor->hide();
+ mxBmpImport->hide();
+
+ const SvxGradientListItem* pItem = pSh->GetItem(SID_GRADIENT_LIST);
+ if (pItem->GetGradientList()->Count() > 0)
+ {
+ const XGradient aGradient
+ = pItem->GetGradientList()->GetGradient(0)->GetGradient();
+ const OUString aName = pItem->GetGradientList()->GetGradient(0)->GetName();
+ const XFillGradientItem aXFillGradientItem(aName, aGradient);
+
+ // #i122676# change FillStyle and Gradient in one call
+ XFillStyleItem aXFillStyleItem(drawing::FillStyle_GRADIENT);
+ setFillStyleAndGradient(&aXFillStyleItem, aXFillGradientItem);
+ mxLbFillGradFrom->SelectEntry(aGradient.GetStartColor());
+ mxLbFillGradTo->SelectEntry(aGradient.GetEndColor());
+
+ mxMTRAngle->set_value(toDegrees(aGradient.GetAngle()), FieldUnit::DEGREE);
+ css::awt::GradientStyle eXGS = aGradient.GetGradientStyle();
+ mxGradientStyle->set_active(sal::static_int_cast<sal_Int32>(eXGS));
+ }
+ }
+ else
+ {
+ if (pSh && pSh->GetItem(SID_GRADIENT_LIST))
+ {
+ SvxFillAttrBox::Fill(*mxLbFillAttr,
+ pSh->GetItem(SID_GRADIENT_LIST)->GetGradientList());
+ mxLbFillGradTo->SetNoSelection();
+ mxLbFillGradFrom->SetNoSelection();
+ if (mpFillGradientItem)
+ {
+ const OUString aString(mpFillGradientItem->GetName());
+ mxLbFillAttr->set_active_text(aString);
+ const XGradient aGradient = mpFillGradientItem->GetGradientValue();
+ mxLbFillGradFrom->SelectEntry(aGradient.GetStartColor());
+ mxLbFillGradTo->SelectEntry(aGradient.GetEndColor());
+ mxGradientStyle->set_active(
+ sal::static_int_cast<sal_Int32>(aGradient.GetGradientStyle()));
+ if (mxGradientStyle->get_active() == sal_Int32(GradientStyle::Radial))
+ mxMTRAngle->set_sensitive(false);
+ else
+ mxMTRAngle->set_value(toDegrees(aGradient.GetAngle()),
+ FieldUnit::DEGREE);
+ }
+ else
+ {
+ mxLbFillAttr->set_active(-1);
+ }
+ }
+ else
+ {
+ mxLbFillAttr->set_active(-1);
+ }
+ }
+ break;
+ }
+ case HATCH:
+ {
+ bShowLbFillAttr = true;
+
+ const SvxHatchListItem* pItem(pSh->GetItem(SID_HATCH_LIST));
+ if (pItem)
+ {
+ const XHatchListRef& pXHatchList(pItem->GetHatchList());
+ mxLbFillAttr->set_sensitive(true);
+ mxLbFillAttr->clear();
+ SvxFillAttrBox::Fill(*mxLbFillAttr, pXHatchList);
+
+ if (mnLastPosHatch != -1)
+ {
+ if (mnLastPosHatch < pXHatchList->Count())
+ {
+ const XHatch aHatch = pXHatchList->GetHatch(mnLastPosHatch)->GetHatch();
+ const OUString aName = pXHatchList->GetHatch(mnLastPosHatch)->GetName();
+ const XFillHatchItem aXFillHatchItem(aName, aHatch);
+
+ // #i122676# change FillStyle and Hatch in one call
+ if (bUpdateModel)
+ {
+ XFillStyleItem aXFillStyleItem(drawing::FillStyle_HATCH);
+ setFillStyleAndHatch(&aXFillStyleItem, aXFillHatchItem);
+ }
+ mxLbFillAttr->set_active(mnLastPosHatch);
+ }
+ }
+ }
+ else
+ {
+ mxLbFillAttr->set_sensitive(false);
+ }
+ break;
+ }
+ case BITMAP:
+ case PATTERN:
+ {
+ bShowLbFillAttr = true;
+ mxLbFillAttr->set_sensitive(true);
+ mxLbFillAttr->clear();
+
+ OUString aName;
+ GraphicObject aBitmap;
+ if (nPos == static_cast<sal_Int32>(BITMAP))
+ {
+ if (!comphelper::LibreOfficeKit::isActive())
+ bShowBmpImport = true;
+ const SvxBitmapListItem* pItem = pSh->GetItem(SID_BITMAP_LIST);
+ if (pItem)
+ {
+ const XBitmapListRef& pXBitmapList(pItem->GetBitmapList());
+ SvxFillAttrBox::Fill(*mxLbFillAttr, pXBitmapList);
+
+ if (mnLastPosBitmap != -1)
+ {
+ if (mnLastPosBitmap < pXBitmapList->Count())
+ {
+ const XBitmapEntry* pXBitmapEntry
+ = pXBitmapList->GetBitmap(mnLastPosBitmap);
+ aBitmap = pXBitmapEntry->GetGraphicObject();
+ aName = pXBitmapEntry->GetName();
+ mxLbFillAttr->set_active(mnLastPosBitmap);
+ }
+ }
+ }
+ else
+ {
+ bShowBmpImport = false;
+ }
+ }
+ else if (nPos == static_cast<sal_Int32>(PATTERN))
+ {
+ const SvxPatternListItem* pItem = pSh->GetItem(SID_PATTERN_LIST);
+ if (pItem)
+ {
+ const XPatternListRef& pXPatternList(pItem->GetPatternList());
+ SvxFillAttrBox::Fill(*mxLbFillAttr, pXPatternList);
+
+ if (mnLastPosPattern != -1)
+ {
+ if (mnLastPosPattern < pXPatternList->Count())
+ {
+ const XBitmapEntry* pXPatternEntry
+ = pXPatternList->GetBitmap(mnLastPosPattern);
+ aBitmap = pXPatternEntry->GetGraphicObject();
+ aName = pXPatternEntry->GetName();
+ mxLbFillAttr->set_active(mnLastPosPattern);
+ }
+ }
+ }
+ else
+ {
+ bShowLbFillAttr = false;
+ }
+ }
+ if (bUpdateModel)
+ {
+ const XFillBitmapItem aXFillBitmapItem(aName, aBitmap);
+ const XFillStyleItem aXFillStyleItem(drawing::FillStyle_BITMAP);
+ setFillStyleAndBitmap(&aXFillStyleItem, aXFillBitmapItem);
+ }
+ break;
+ }
+ case USE_BACKGROUND:
+ {
+ // No transparencies here
+ mxLBTransType->hide();
+ mxTrspTextFT->hide();
+ mxMTRTransparent->hide();
+ mxSldTransparent->hide();
+ mxBTNGradient->hide();
+ if (bUpdateModel)
+ {
+ const XFillStyleItem aXFillStyleItem(drawing::FillStyle_NONE);
+ const XFillUseSlideBackgroundItem aXFillUseSlideBackgroundItem(true);
+ setFillUseBackground(&aXFillStyleItem, aXFillUseSlideBackgroundItem);
+ break;
+ }
+ }
+ }
+
+ mxLbFillAttr->set_visible(bShowLbFillAttr);
+ mxLbFillGradFrom->set_visible(bShowLbFillGradFrom);
+ mxLbFillGradTo->set_visible(bShowLbFillGradTo);
+ mxGradientStyle->set_visible(bShowGradientStyle);
+ mxMTRAngle->set_visible(bShowMTRAngle);
+ mxToolBoxColor->set_visible(bShowToolBoxColor);
+ mxBmpImport->set_visible(bShowBmpImport);
+
+ meLastXFS = static_cast<sal_uInt16>(nPos);
+
+ if (m_pPanel && !comphelper::LibreOfficeKit::isActive())
+ m_pPanel->TriggerDeckLayouting();
+}
+
+void AreaPropertyPanelBase::ImpUpdateTransparencies()
+{
+ if(mpTransparenceItem || mpFloatTransparenceItem)
+ {
+ bool bZeroValue(false);
+
+ if (mpTransparenceItem)
+ {
+ const sal_uInt16 nValue(mpTransparenceItem->GetValue());
+
+ if(!nValue)
+ {
+ bZeroValue = true;
+ }
+ else if(nValue <= 100)
+ {
+ mxLBTransType->set_sensitive(true);
+ mxTrspTextFT->set_sensitive(true);
+ mxLBTransType->set_active(1);
+ mxBTNGradient->hide();
+ mxMTRTransparent->show();
+ mxSldTransparent->show();
+ mxMTRTransparent->set_sensitive(true);
+ mxSldTransparent->set_sensitive(true);
+ SetTransparency(nValue);
+ }
+
+ if (!bZeroValue && mxTrGrPopup)
+ {
+ mxBTNGradient->set_menu_item_active(SIDEBARGRADIENT, false);
+ }
+ }
+
+ if(bZeroValue && mpFloatTransparenceItem)
+ {
+ if(mpFloatTransparenceItem->IsEnabled())
+ {
+ const XGradient& rGradient = mpFloatTransparenceItem->GetGradientValue();
+ sal_Int32 nEntryPos(0);
+ OUString* pImage = nullptr;
+
+ mxLBTransType->set_sensitive(true);
+ mxTrspTextFT->set_sensitive(true);
+ mxMTRTransparent->hide();
+ mxSldTransparent->hide();
+ mxBTNGradient->set_sensitive(true);
+ mxBTNGradient->show();
+
+ switch(rGradient.GetGradientStyle())
+ {
+ default:
+ case css::awt::GradientStyle_LINEAR:
+ {
+ nEntryPos = 2;
+ pImage = &maImgLinear;
+ break;
+ }
+ case css::awt::GradientStyle_AXIAL:
+ {
+ nEntryPos = 3;
+ pImage = &maImgAxial;
+ break;
+ }
+ case css::awt::GradientStyle_RADIAL:
+ {
+ nEntryPos = 4;
+ pImage = &maImgRadial;
+ break;
+ }
+ case css::awt::GradientStyle_ELLIPTICAL:
+ {
+ nEntryPos = 5;
+ pImage = &maImgElli;
+ break;
+ }
+ case css::awt::GradientStyle_SQUARE:
+ {
+ nEntryPos = 6;
+ pImage = &maImgQuad;
+ break;
+ }
+ case css::awt::GradientStyle_RECT:
+ {
+ nEntryPos = 7;
+ pImage = &maImgSquare;
+ break;
+ }
+ }
+ mxLBTransType->set_active(nEntryPos);
+ mxBTNGradient->set_item_icon_name(SIDEBARGRADIENT, *pImage);
+ mxTrGrPopup->Rearrange(mpFloatTransparenceItem.get());
+ bZeroValue = false;
+ }
+ else
+ {
+ bZeroValue = true;
+ }
+ }
+
+ if(bZeroValue)
+ {
+ mxLBTransType->set_sensitive(true);
+ mxTrspTextFT->set_sensitive(true);
+ mxLBTransType->set_active(0);
+ mxBTNGradient->hide();
+ mxMTRTransparent->set_sensitive(true);
+ mxSldTransparent->set_sensitive(true);
+ mxMTRTransparent->show();
+ mxSldTransparent->show();
+ SetTransparency(0);
+ }
+ }
+ else
+ {
+ // no transparency at all
+ mxLBTransType->set_active(-1);
+ mxLBTransType->set_sensitive(false);
+ mxTrspTextFT->set_sensitive(false);
+ mxMTRTransparent->set_sensitive(false);
+ mxSldTransparent->set_sensitive(false);
+ mxMTRTransparent->show();
+ mxSldTransparent->show();
+ mxBTNGradient->set_sensitive(false);
+ mxBTNGradient->hide();
+ }
+}
+
+void AreaPropertyPanelBase::updateFillTransparence(bool bDisabled, bool bDefaultOrSet, const SfxPoolItem* pState)
+{
+ if (bDisabled)
+ {
+ mpTransparenceItem.reset();
+ return;
+ }
+ else if (bDefaultOrSet)
+ {
+ if (pState)
+ {
+ const SfxUInt16Item* pItem = static_cast<const SfxUInt16Item*>(pState);
+ mpTransparenceItem.reset(pItem->Clone());
+ }
+ else
+ {
+ mpTransparenceItem.reset();
+ }
+ }
+ else
+ {
+ mpTransparenceItem.reset();
+ }
+
+ // update transparency settings dependent of mpTransparenceItem and mpFloatTransparenceItem
+ ImpUpdateTransparencies();
+}
+
+void AreaPropertyPanelBase::updateFillFloatTransparence(bool bDisabled, bool bDefaultOrSet, const SfxPoolItem* pState)
+{
+ if (bDisabled)
+ {
+ mpFloatTransparenceItem.reset();
+ return;
+ }
+
+ if (bDefaultOrSet)
+ {
+ if (pState)
+ {
+ const XFillFloatTransparenceItem* pItem = static_cast<const XFillFloatTransparenceItem*>(pState);
+ mpFloatTransparenceItem.reset(pItem->Clone());
+ }
+ else
+ {
+ mpFloatTransparenceItem.reset();
+ }
+ }
+ else
+ {
+ mpFloatTransparenceItem.reset();
+ }
+
+ // update transparency settings dependent of mpTransparenceItem and mpFloatTransparenceItem
+ ImpUpdateTransparencies();
+}
+
+void AreaPropertyPanelBase::updateFillStyle(bool bDisabled, bool bDefaultOrSet, const SfxPoolItem* pState)
+{
+ if(bDisabled)
+ {
+ mxLbFillType->set_sensitive(false);
+ mxColorTextFT->set_sensitive(false);
+ mxLbFillType->set_active(-1);
+ mxLbFillAttr->show();
+ mxLbFillAttr->set_sensitive(false);
+ mxLbFillAttr->set_active(-1);
+ mxToolBoxColor->hide();
+ meLastXFS = static_cast<sal_uInt16>(-1);
+ mpStyleItem.reset();
+ }
+ else if (bDefaultOrSet && pState)
+ {
+ const XFillStyleItem* pItem = static_cast<const XFillStyleItem*>(pState);
+ mpStyleItem.reset(pItem->Clone());
+ mxLbFillType->set_sensitive(true);
+ mxColorTextFT->set_sensitive(true);
+ drawing::FillStyle eXFS = mpStyleItem->GetValue();
+ eFillStyle nPos = NONE;
+ switch(eXFS)
+ {
+ default:
+ case drawing::FillStyle_NONE:
+ {
+ mxLbFillAttr->set_active(-1);
+ mxLbFillAttr->set_sensitive(false);
+ // "Use slide background" also uses FillStyle_NONE internally,
+ // don't switch listbox in that case (will be handled by updateFillUseBackground)
+ nPos = meLastXFS == USE_BACKGROUND ? USE_BACKGROUND : NONE;
+ break;
+ }
+ case drawing::FillStyle_SOLID:
+ nPos = SOLID;
+ break;
+ case drawing::FillStyle_GRADIENT:
+ nPos = GRADIENT;
+ break;
+ case drawing::FillStyle_HATCH:
+ nPos = HATCH;
+ break;
+ case drawing::FillStyle_BITMAP:
+ {
+ if(mpBitmapItem)
+ {
+ if(!mpBitmapItem->isPattern())
+ nPos = BITMAP;
+ else
+ nPos = PATTERN;
+ }
+ else
+ nPos = BITMAP;
+ break;
+ }
+ }
+ meLastXFS = static_cast< sal_uInt16 >(mxLbFillType->get_active());
+ mxLbFillType->set_active(static_cast< sal_Int32 >(nPos));
+ FillStyleChanged(false);
+ return;
+ }
+
+ mxLbFillType->set_active(-1);
+ mxLbFillAttr->show();
+ mxLbFillAttr->set_sensitive(false);
+ mxLbFillAttr->set_active(-1);
+ mxToolBoxColor->hide();
+ meLastXFS = static_cast<sal_uInt16>(-1);
+ mpStyleItem.reset();
+}
+
+void AreaPropertyPanelBase::updateFillGradient(bool bDisabled, bool bDefaultOrSet, const SfxPoolItem* pState)
+{
+ if (bDefaultOrSet)
+ {
+ const XFillGradientItem* pItem = static_cast<const XFillGradientItem*>(pState);
+ mpFillGradientItem.reset(pItem ? pItem->Clone() : nullptr);
+ }
+
+ if(mpStyleItem && drawing::FillStyle_GRADIENT == mpStyleItem->GetValue())
+ {
+ mxLbFillAttr->hide();
+ mxLbFillGradFrom->show();
+ mxLbFillGradTo->show();
+ mxMTRAngle->show();
+ mxGradientStyle->show();
+ mxToolBoxColor->hide();
+
+ if (bDefaultOrSet)
+ {
+ mxLbFillType->set_active(GRADIENT);
+ FillStyleChanged(false);
+ }
+ else if(bDisabled)
+ {
+ mxLbFillGradFrom->SetNoSelection();
+ mxLbFillGradTo->SetNoSelection();
+ mxLbFillGradFrom->set_sensitive(false);
+ mxLbFillGradTo->set_sensitive(false);
+ mxMTRAngle->set_sensitive(false);
+ mxGradientStyle->set_sensitive(false);
+ }
+ else
+ {
+ mxLbFillGradFrom->SetNoSelection();
+ mxLbFillGradTo->SetNoSelection();
+ }
+ }
+}
+
+void AreaPropertyPanelBase::updateFillHatch(bool bDisabled, bool bDefaultOrSet, const SfxPoolItem* pState)
+{
+ if (bDefaultOrSet)
+ {
+ const XFillHatchItem* pItem = static_cast<const XFillHatchItem*>(pState);
+ mpHatchItem.reset(pItem ? pItem->Clone() : nullptr);
+ }
+
+ if(mpStyleItem && drawing::FillStyle_HATCH == mpStyleItem->GetValue())
+ {
+ mxLbFillAttr->show();
+ mxToolBoxColor->hide();
+
+ if (bDefaultOrSet)
+ {
+ mxLbFillAttr->set_sensitive(true);
+ mxLbFillType->set_active(HATCH);
+ FillStyleChanged(false);
+ }
+ else if(bDisabled)
+ {
+ mxLbFillAttr->set_sensitive(false);
+ mxLbFillAttr->set_active(-1);
+ }
+ else
+ {
+ mxLbFillAttr->set_active(-1);
+ }
+ }
+ FillStyleChanged(false);
+}
+
+void AreaPropertyPanelBase::updateFillColor(bool bDefaultOrSet, const SfxPoolItem* pState)
+{
+ if (bDefaultOrSet)
+ {
+ const XFillColorItem* pItem = static_cast<const XFillColorItem*>(pState);
+ mpColorItem.reset(pItem ? pItem->Clone() : nullptr);
+ }
+
+ if(mpStyleItem && drawing::FillStyle_SOLID == mpStyleItem->GetValue())
+ {
+ mxLbFillAttr->hide();
+ mxToolBoxColor->show();
+ mxLbFillType->set_active(SOLID);
+ FillStyleChanged(false);
+ }
+}
+
+void AreaPropertyPanelBase::updateFillBitmap(bool bDisabled, bool bDefaultOrSet, const SfxPoolItem* pState)
+{
+ if (bDefaultOrSet)
+ {
+ const XFillBitmapItem* pItem = static_cast<const XFillBitmapItem*>(pState);
+ mpBitmapItem.reset(pItem ? pItem->Clone() : nullptr);
+ }
+
+ if(mpStyleItem && drawing::FillStyle_BITMAP == mpStyleItem->GetValue())
+ {
+ mxLbFillAttr->show();
+ mxToolBoxColor->hide();
+
+ if (bDefaultOrSet)
+ {
+ if(mpBitmapItem->isPattern())
+ mxLbFillType->set_active(PATTERN);
+ else
+ mxLbFillType->set_active(BITMAP);
+ FillStyleChanged(false);
+ }
+ else if(bDisabled)
+ {
+ mxLbFillAttr->hide();
+ mxLbFillAttr->set_active(-1);
+ }
+ else
+ {
+ mxLbFillAttr->set_active(-1);
+ }
+ }
+}
+
+void AreaPropertyPanelBase::updateFillUseBackground(bool bDisabled, bool bDefaultOrSet, const SfxPoolItem* pState)
+{
+ if (bDisabled)
+ {
+ mpUseSlideBackgroundItem.reset();
+ return;
+ }
+
+ if (bDefaultOrSet)
+ {
+ if (pState)
+ {
+ const XFillUseSlideBackgroundItem* pItem = static_cast<const XFillUseSlideBackgroundItem*>(pState);
+ // When XFillUseSlideBackgroundItem is true, select "Use Background Fill". When false, select "None"
+ int nPos = pItem->GetValue() ? USE_BACKGROUND : NONE;
+ mxLbFillType->set_active(nPos);
+ mpUseSlideBackgroundItem.reset(pItem->Clone());
+ FillStyleChanged(false);
+ }
+ else
+ {
+ mpUseSlideBackgroundItem.reset();
+ }
+ }
+ else
+ {
+ mpUseSlideBackgroundItem.reset();
+ }
+}
+
+void AreaPropertyPanelBase::NotifyItemUpdate(
+ sal_uInt16 nSID,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ const bool bDisabled(SfxItemState::DISABLED == eState);
+ const bool bDefaultOrSet(SfxItemState::DEFAULT <= eState);
+ const bool bDefault(SfxItemState::DEFAULT == eState);
+
+ switch(nSID)
+ {
+ case SID_ATTR_FILL_TRANSPARENCE:
+ updateFillTransparence(bDisabled, bDefaultOrSet, pState);
+ break;
+ case SID_ATTR_FILL_FLOATTRANSPARENCE:
+ updateFillFloatTransparence(bDisabled, bDefaultOrSet, pState);
+ break;
+ case SID_ATTR_FILL_STYLE:
+ updateFillStyle(bDisabled, bDefaultOrSet, pState);
+ break;
+ case SID_ATTR_FILL_COLOR:
+ updateFillColor(bDefaultOrSet, pState);
+ break;
+ case SID_ATTR_FILL_GRADIENT:
+ updateFillGradient(bDisabled, bDefaultOrSet, pState);
+ break;
+ case SID_ATTR_FILL_HATCH:
+ updateFillHatch(bDisabled, bDefaultOrSet, pState);
+ break;
+ case SID_ATTR_FILL_BITMAP:
+ updateFillBitmap(bDisabled, bDefaultOrSet, pState);
+ break;
+ case SID_ATTR_FILL_USE_SLIDE_BACKGROUND:
+ updateFillUseBackground(bDisabled, bDefaultOrSet, pState);
+ break;
+ case SID_GRADIENT_LIST:
+ {
+ if(bDefault)
+ {
+ if(mpStyleItem && drawing::FillStyle_GRADIENT == mpStyleItem->GetValue())
+ {
+ if(mpFillGradientItem)
+ {
+ const OUString aString( mpFillGradientItem->GetName() );
+ const SfxObjectShell* pSh = SfxObjectShell::Current();
+ mxLbFillAttr->clear();
+ if (pSh)
+ {
+ mxLbFillAttr->set_sensitive(true);
+ SvxFillAttrBox::Fill(*mxLbFillAttr, pSh->GetItem(SID_GRADIENT_LIST)->GetGradientList());
+ }
+ mxLbFillAttr->set_active_text(aString);
+ }
+ else
+ {
+ mxLbFillAttr->set_active(-1);
+ }
+ }
+ }
+ break;
+ }
+ case SID_HATCH_LIST:
+ {
+ if(bDefault)
+ {
+ if(mpStyleItem && drawing::FillStyle_HATCH == mpStyleItem->GetValue())
+ {
+ if(mpHatchItem)
+ {
+ const OUString aString( mpHatchItem->GetName() );
+ const SfxObjectShell* pSh = SfxObjectShell::Current();
+ mxLbFillAttr->clear();
+ if (pSh)
+ {
+ mxLbFillAttr->set_sensitive(true);
+ SvxFillAttrBox::Fill(*mxLbFillAttr, pSh->GetItem(SID_HATCH_LIST)->GetHatchList());
+ }
+ mxLbFillAttr->set_active_text(aString);
+ }
+ else
+ {
+ mxLbFillAttr->set_active(-1);
+ }
+ }
+ }
+ break;
+ }
+ case SID_BITMAP_LIST:
+ case SID_PATTERN_LIST:
+ {
+ if(bDefault)
+ {
+ if(mpStyleItem && drawing::FillStyle_BITMAP == mpStyleItem->GetValue())
+ {
+ if(mpBitmapItem)
+ {
+ const OUString aString( mpBitmapItem->GetName() );
+ const SfxObjectShell* pSh = SfxObjectShell::Current();
+ mxLbFillAttr->clear();
+ mxLbFillAttr->show();
+ if (pSh)
+ {
+ if(nSID == SID_BITMAP_LIST)
+ SvxFillAttrBox::Fill(*mxLbFillAttr, pSh->GetItem(SID_BITMAP_LIST)->GetBitmapList());
+ else if(nSID == SID_PATTERN_LIST)
+ SvxFillAttrBox::Fill(*mxLbFillAttr, pSh->GetItem(SID_PATTERN_LIST)->GetPatternList());
+ }
+ mxLbFillAttr->set_active_text(aString);
+ }
+ else
+ {
+ mxLbFillAttr->set_active(-1);
+ }
+ }
+ }
+ break;
+ }
+ }
+ FillStyleChanged(false);
+}
+
+IMPL_LINK_NOARG(AreaPropertyPanelBase, ModifyTransSliderHdl, weld::Scale&, void)
+{
+ const sal_uInt16 nVal = mxSldTransparent->get_value();
+ SetTransparency(nVal);
+ const XFillTransparenceItem aLinearItem(nVal);
+ setFillTransparence(aLinearItem);
+}
+
+IMPL_LINK_NOARG(AreaPropertyPanelBase, ChangeTrgrTypeHdl_Impl, weld::ComboBox&, void)
+{
+ sal_Int32 nSelectType = mxLBTransType->get_active();
+ bool bGradient = false;
+ sal_uInt16 nTrans = 0;
+
+ if(!nSelectType)
+ {
+ mxBTNGradient->hide();
+ mxMTRTransparent->show();
+ mxSldTransparent->show();
+ mxMTRTransparent->set_sensitive(true);
+ mxSldTransparent->set_sensitive(true);
+ SetTransparency(0);
+ }
+ else if(1 == nSelectType)
+ {
+ mxBTNGradient->hide();
+ mxMTRTransparent->show();
+ mxSldTransparent->show();
+ nTrans = mnLastTransSolid;
+ mxMTRTransparent->set_value(nTrans, FieldUnit::PERCENT);
+ mxLBTransType->set_active(1);
+ mxMTRTransparent->set_sensitive(true);
+ mxSldTransparent->set_sensitive(true);
+ }
+ else
+ {
+ mxBTNGradient->show();
+
+ switch (nSelectType)
+ {
+ case 2:
+ mxBTNGradient->set_item_icon_name(SIDEBARGRADIENT, maImgLinear);
+ break;
+ case 3:
+ mxBTNGradient->set_item_icon_name(SIDEBARGRADIENT, maImgAxial);
+ break;
+ case 4:
+ mxBTNGradient->set_item_icon_name(SIDEBARGRADIENT, maImgRadial);
+ break;
+ case 5:
+ mxBTNGradient->set_item_icon_name(SIDEBARGRADIENT, maImgElli);
+ break;
+ case 6:
+ mxBTNGradient->set_item_icon_name(SIDEBARGRADIENT, maImgQuad);
+ break;
+ case 7:
+ mxBTNGradient->set_item_icon_name(SIDEBARGRADIENT, maImgSquare);
+ break;
+ }
+
+ mxMTRTransparent->hide();
+ mxSldTransparent->hide();
+ mxBTNGradient->set_sensitive(true);
+ bGradient = true;
+ }
+
+ const XFillTransparenceItem aLinearItem(nTrans);
+ setFillTransparence(aLinearItem);
+
+ if(nSelectType > 1)
+ {
+ nSelectType -= 2;
+ }
+
+ XGradient aTmpGradient;
+
+ switch(static_cast<css::awt::GradientStyle>(nSelectType))
+ {
+ case css::awt::GradientStyle_LINEAR:
+ aTmpGradient = maGradientLinear;
+ break;
+ case css::awt::GradientStyle_AXIAL:
+ aTmpGradient = maGradientAxial;
+ break;
+ case css::awt::GradientStyle_RADIAL:
+ aTmpGradient = maGradientRadial;
+ break;
+ case css::awt::GradientStyle_ELLIPTICAL:
+ aTmpGradient = maGradientElliptical;
+ break;
+ case css::awt::GradientStyle_SQUARE:
+ aTmpGradient = maGradientSquare;
+ break;
+ case css::awt::GradientStyle_RECT:
+ aTmpGradient = maGradientRect;
+ break;
+ default:
+ break;
+ }
+
+ const XFillFloatTransparenceItem aGradientItem(aTmpGradient, bGradient);
+ setFillFloatTransparence(aGradientItem);
+}
+
+IMPL_LINK_NOARG(AreaPropertyPanelBase, ModifyTransparentHdl_Impl, weld::MetricSpinButton&, void)
+{
+ const sal_uInt16 nTrans = static_cast<sal_uInt16>(mxMTRTransparent->get_value(FieldUnit::PERCENT));
+ mnLastTransSolid = nTrans;
+ SetTransparency(nTrans);
+ const sal_Int32 nSelectType = mxLBTransType->get_active();
+
+ if(nTrans && !nSelectType)
+ {
+ mxLBTransType->set_active(1);
+ }
+
+ const XFillTransparenceItem aLinearItem(nTrans);
+ setFillTransparence(aLinearItem);
+}
+
+const XGradient& AreaPropertyPanelBase::GetGradient (const css::awt::GradientStyle eStyle) const
+{
+ switch (eStyle)
+ {
+ default:
+ case css::awt::GradientStyle_LINEAR:
+ return maGradientLinear;
+ case css::awt::GradientStyle_AXIAL:
+ return maGradientAxial;
+ case css::awt::GradientStyle_RADIAL:
+ return maGradientRadial;
+ case css::awt::GradientStyle_ELLIPTICAL:
+ return maGradientElliptical;
+ case css::awt::GradientStyle_SQUARE:
+ return maGradientSquare;
+ case css::awt::GradientStyle_RECT:
+ return maGradientRect;
+ }
+}
+
+void AreaPropertyPanelBase::SetGradient (const XGradient& rGradient)
+{
+ switch (rGradient.GetGradientStyle())
+ {
+ case css::awt::GradientStyle_LINEAR:
+ maGradientLinear = rGradient;
+ break;
+ case css::awt::GradientStyle_AXIAL:
+ maGradientAxial = rGradient;
+ break;
+ case css::awt::GradientStyle_RADIAL:
+ maGradientRadial = rGradient;
+ break;
+ case css::awt::GradientStyle_ELLIPTICAL:
+ maGradientElliptical = rGradient;
+ break;
+ case css::awt::GradientStyle_SQUARE:
+ maGradientSquare = rGradient;
+ break;
+ case css::awt::GradientStyle_RECT:
+ maGradientRect = rGradient;
+ break;
+ default:
+ break;
+ }
+}
+
+sal_Int32 AreaPropertyPanelBase::GetSelectedTransparencyTypeIndex() const
+{
+ return mxLBTransType->get_active();
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/area/AreaTransparencyGradientPopup.cxx b/svx/source/sidebar/area/AreaTransparencyGradientPopup.cxx
new file mode 100644
index 000000000..2d92b6b4b
--- /dev/null
+++ b/svx/source/sidebar/area/AreaTransparencyGradientPopup.cxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sidebar/AreaTransparencyGradientPopup.hxx>
+#include <svx/sidebar/AreaPropertyPanelBase.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xgrad.hxx>
+
+namespace svx::sidebar {
+
+AreaTransparencyGradientPopup::AreaTransparencyGradientPopup(const css::uno::Reference<css::frame::XFrame>& rFrame,
+ AreaPropertyPanelBase& rPanel, weld::Widget* pParent)
+ : WeldToolbarPopup(rFrame, pParent, "svx/ui/floatingareastyle.ui", "FloatingAreaStyle")
+ , mrAreaPropertyPanel(rPanel)
+ , mxCenterGrid(m_xBuilder->weld_widget("centergrid"))
+ , mxAngleGrid(m_xBuilder->weld_widget("anglegrid"))
+ , mxMtrTrgrCenterX(m_xBuilder->weld_metric_spin_button("centerx", FieldUnit::PERCENT))
+ , mxMtrTrgrCenterY(m_xBuilder->weld_metric_spin_button("centery", FieldUnit::PERCENT))
+ , mxMtrTrgrAngle(m_xBuilder->weld_metric_spin_button("angle", FieldUnit::DEGREE))
+ , mxBtnLeft45(m_xBuilder->weld_toolbar("lefttoolbox"))
+ , mxBtnRight45(m_xBuilder->weld_toolbar("righttoolbox"))
+ , mxMtrTrgrStartValue(m_xBuilder->weld_metric_spin_button("start", FieldUnit::PERCENT))
+ , mxMtrTrgrEndValue(m_xBuilder->weld_metric_spin_button("end", FieldUnit::PERCENT))
+ , mxMtrTrgrBorder(m_xBuilder->weld_metric_spin_button("border", FieldUnit::PERCENT))
+{
+ Link<weld::MetricSpinButton&,void> aLink = LINK(this, AreaTransparencyGradientPopup, ModifiedTrgrHdl_Impl);
+ mxMtrTrgrCenterX->connect_value_changed(aLink);
+ mxMtrTrgrCenterY->connect_value_changed(aLink);
+ mxMtrTrgrAngle->connect_value_changed(aLink);
+ mxMtrTrgrBorder->connect_value_changed(aLink);
+ mxMtrTrgrStartValue->connect_value_changed(aLink);
+ mxMtrTrgrEndValue->connect_value_changed(aLink);
+ mxBtnLeft45->connect_clicked(LINK(this, AreaTransparencyGradientPopup, Left_Click45_Impl));
+ mxBtnRight45->connect_clicked(LINK(this, AreaTransparencyGradientPopup, Right_Click45_Impl));
+}
+
+AreaTransparencyGradientPopup::~AreaTransparencyGradientPopup()
+{
+}
+
+void AreaTransparencyGradientPopup::InitStatus(XFillFloatTransparenceItem const * pGradientItem)
+{
+ const XGradient& rGradient = pGradientItem->GetGradientValue();
+
+ XGradient aGradient;
+
+ if (rGradient.GetXOffset() == AreaPropertyPanelBase::DEFAULT_CENTERX
+ && rGradient.GetYOffset() == AreaPropertyPanelBase::DEFAULT_CENTERY
+ && static_cast<sal_Int32>(toDegrees(rGradient.GetAngle())) == AreaPropertyPanelBase::DEFAULT_ANGLE
+ && static_cast<sal_uInt16>(((static_cast<sal_uInt16>(rGradient.GetStartColor().GetRed()) + 1) * 100) / 255)
+ == AreaPropertyPanelBase::DEFAULT_STARTVALUE
+ && static_cast<sal_uInt16>(((static_cast<sal_uInt16>(rGradient.GetEndColor().GetRed()) + 1) * 100) / 255)
+ == AreaPropertyPanelBase::DEFAULT_ENDVALUE
+ && rGradient.GetBorder() == AreaPropertyPanelBase::DEFAULT_BORDER)
+ {
+ aGradient = mrAreaPropertyPanel.GetGradient(rGradient.GetGradientStyle());
+ }
+ else
+ {
+ aGradient = rGradient;
+ }
+ mxMtrTrgrCenterX->set_value(aGradient.GetXOffset(), FieldUnit::PERCENT);
+ mxMtrTrgrCenterY->set_value(aGradient.GetYOffset(), FieldUnit::PERCENT);
+ mxMtrTrgrAngle->set_value(toDegrees(aGradient.GetAngle()), FieldUnit::DEGREE);
+ mxMtrTrgrStartValue->set_value(static_cast<sal_uInt16>(((static_cast<sal_uInt16>(aGradient.GetStartColor().GetRed()) + 1) * 100) / 255), FieldUnit::PERCENT);
+ mxMtrTrgrEndValue->set_value(static_cast<sal_uInt16>(((static_cast<sal_uInt16>(aGradient.GetEndColor().GetRed()) + 1) * 100) / 255), FieldUnit::PERCENT);
+ mxMtrTrgrBorder->set_value(aGradient.GetBorder(), FieldUnit::PERCENT);
+}
+
+void AreaTransparencyGradientPopup::Rearrange(XFillFloatTransparenceItem const * pGradientItem)
+{
+ InitStatus(pGradientItem);
+ const XGradient& rGradient = pGradientItem->GetGradientValue();
+ css::awt::GradientStyle eXGS(rGradient.GetGradientStyle());
+
+ switch(eXGS)
+ {
+ case css::awt::GradientStyle_LINEAR:
+ case css::awt::GradientStyle_AXIAL:
+ mxCenterGrid->hide();
+ mxAngleGrid->show();
+ break;
+ case css::awt::GradientStyle_RADIAL:
+ mxCenterGrid->show();
+ mxAngleGrid->hide();
+ break;
+ case css::awt::GradientStyle_ELLIPTICAL:
+ case css::awt::GradientStyle_SQUARE:
+ case css::awt::GradientStyle_RECT:
+ mxCenterGrid->show();
+ mxAngleGrid->show();
+ break;
+ default:
+ break;
+ }
+}
+
+void AreaTransparencyGradientPopup::ExecuteValueModify(sal_uInt8 nStartCol, sal_uInt8 nEndCol)
+{
+ //Added
+ sal_Int16 aMtrValue = static_cast<sal_Int16>(mxMtrTrgrAngle->get_value(FieldUnit::DEGREE));
+ while(aMtrValue<0)
+ aMtrValue += 360;
+ sal_uInt16 nVal = aMtrValue/360;
+ nVal = aMtrValue - nVal*360;
+ mxMtrTrgrAngle->set_value(nVal, FieldUnit::DEGREE);
+ //End of new code
+ XGradient aTmpGradient(
+ Color(nStartCol, nStartCol, nStartCol),
+ Color(nEndCol, nEndCol, nEndCol),
+ static_cast<css::awt::GradientStyle>(mrAreaPropertyPanel.GetSelectedTransparencyTypeIndex()-2),
+ Degree10(static_cast<sal_Int16>(mxMtrTrgrAngle->get_value(FieldUnit::DEGREE)) * 10),
+ static_cast<sal_uInt16>(mxMtrTrgrCenterX->get_value(FieldUnit::PERCENT)),
+ static_cast<sal_uInt16>(mxMtrTrgrCenterY->get_value(FieldUnit::PERCENT)),
+ static_cast<sal_uInt16>(mxMtrTrgrBorder->get_value(FieldUnit::PERCENT)),
+ 100, 100);
+
+ mrAreaPropertyPanel.SetGradient(aTmpGradient);
+
+ XFillFloatTransparenceItem aGradientItem(aTmpGradient, true );
+
+ mrAreaPropertyPanel.setFillFloatTransparence(aGradientItem);
+}
+
+IMPL_LINK_NOARG(AreaTransparencyGradientPopup, ModifiedTrgrHdl_Impl, weld::MetricSpinButton&, void)
+{
+ sal_uInt8 nStartCol = static_cast<sal_uInt8>((static_cast<sal_uInt16>(mxMtrTrgrStartValue->get_value(FieldUnit::PERCENT)) * 255) / 100);
+ sal_uInt8 nEndCol = static_cast<sal_uInt8>((static_cast<sal_uInt16>(mxMtrTrgrEndValue->get_value(FieldUnit::PERCENT)) * 255) / 100);
+ ExecuteValueModify( nStartCol, nEndCol );
+}
+
+IMPL_LINK_NOARG(AreaTransparencyGradientPopup, Left_Click45_Impl, const OString&, void)
+{
+ sal_uInt8 nStartCol = static_cast<sal_uInt8>((static_cast<sal_uInt16>(mxMtrTrgrStartValue->get_value(FieldUnit::PERCENT)) * 255) / 100);
+ sal_uInt8 nEndCol = static_cast<sal_uInt8>((static_cast<sal_uInt16>(mxMtrTrgrEndValue->get_value(FieldUnit::PERCENT)) * 255) / 100);
+ sal_uInt16 nTemp = static_cast<sal_uInt16>(mxMtrTrgrAngle->get_value(FieldUnit::DEGREE));
+ if (nTemp>=315)
+ nTemp -= 360;
+ nTemp += 45;
+ mxMtrTrgrAngle->set_value(nTemp, FieldUnit::DEGREE);
+ ExecuteValueModify(nStartCol, nEndCol);
+}
+
+IMPL_LINK_NOARG(AreaTransparencyGradientPopup, Right_Click45_Impl, const OString&, void)
+{
+ sal_uInt8 nStartCol = static_cast<sal_uInt8>((static_cast<sal_uInt16>(mxMtrTrgrStartValue->get_value(FieldUnit::PERCENT)) * 255) / 100);
+ sal_uInt8 nEndCol = static_cast<sal_uInt8>((static_cast<sal_uInt16>(mxMtrTrgrEndValue->get_value(FieldUnit::PERCENT)) * 255) / 100);
+ sal_uInt16 nTemp = static_cast<sal_uInt16>(mxMtrTrgrAngle->get_value(FieldUnit::DEGREE));
+ if (nTemp<45)
+ nTemp += 360;
+ nTemp -= 45;
+ mxMtrTrgrAngle->set_value(nTemp, FieldUnit::DEGREE);
+ ExecuteValueModify(nStartCol, nEndCol);
+}
+
+void AreaTransparencyGradientPopup::GrabFocus()
+{
+ mxMtrTrgrCenterX->grab_focus();
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/effect/EffectPropertyPanel.cxx b/svx/source/sidebar/effect/EffectPropertyPanel.cxx
new file mode 100644
index 000000000..77e2dac11
--- /dev/null
+++ b/svx/source/sidebar/effect/EffectPropertyPanel.cxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include "EffectPropertyPanel.hxx"
+
+#include <sfx2/dispatch.hxx>
+#include <svx/colorbox.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svxids.hrc>
+#include <svx/xcolit.hxx>
+
+namespace svx::sidebar
+{
+EffectPropertyPanel::EffectPropertyPanel(weld::Widget* pParent, SfxBindings* pBindings)
+ : PanelLayout(pParent, "EffectPropertyPanel", "svx/ui/sidebareffect.ui")
+ , maGlowColorController(SID_ATTR_GLOW_COLOR, *pBindings, *this)
+ , maGlowRadiusController(SID_ATTR_GLOW_RADIUS, *pBindings, *this)
+ , maGlowTransparencyController(SID_ATTR_GLOW_TRANSPARENCY, *pBindings, *this)
+ , mxFTTransparency(m_xBuilder->weld_label("transparency"))
+ , maSoftEdgeRadiusController(SID_ATTR_SOFTEDGE_RADIUS, *pBindings, *this)
+ , mpBindings(pBindings)
+ , mxGlowRadius(m_xBuilder->weld_metric_spin_button("LB_GLOW_RADIUS", FieldUnit::POINT))
+ , mxLBGlowColor(new ColorListBox(m_xBuilder->weld_menu_button("LB_GLOW_COLOR"),
+ [this] { return GetFrameWeld(); }))
+ , mxGlowTransparency(
+ m_xBuilder->weld_metric_spin_button("LB_GLOW_TRANSPARENCY", FieldUnit::PERCENT))
+ , mxFTRadiusSoftEdge(m_xBuilder->weld_label("radiussoftedge"))
+ , mxFTRadiusGlow(m_xBuilder->weld_label("radiusglow"))
+ , mxFTColor(m_xBuilder->weld_label("glowcolorlabel"))
+ , mxSoftEdgeRadius(m_xBuilder->weld_metric_spin_button("SB_SOFTEDGE_RADIUS", FieldUnit::POINT))
+{
+ Initialize();
+}
+
+EffectPropertyPanel::~EffectPropertyPanel()
+{
+ mxGlowRadius.reset();
+ mxLBGlowColor.reset();
+ mxGlowTransparency.reset();
+ mxFTRadiusSoftEdge.reset();
+ mxFTColor.reset();
+ mxFTTransparency.reset();
+ mxSoftEdgeRadius.reset();
+ mxFTRadiusGlow.reset();
+
+ maGlowColorController.dispose();
+ maGlowRadiusController.dispose();
+ maGlowTransparencyController.dispose();
+ maSoftEdgeRadiusController.dispose();
+}
+
+void EffectPropertyPanel::Initialize()
+{
+ mxGlowRadius->connect_value_changed(LINK(this, EffectPropertyPanel, ModifyGlowRadiusHdl));
+ mxLBGlowColor->SetSelectHdl(LINK(this, EffectPropertyPanel, ModifyGlowColorHdl));
+ mxGlowTransparency->connect_value_changed(
+ LINK(this, EffectPropertyPanel, ModifyGlowTransparencyHdl));
+ mxSoftEdgeRadius->connect_value_changed(
+ LINK(this, EffectPropertyPanel, ModifySoftEdgeRadiusHdl));
+}
+
+IMPL_LINK_NOARG(EffectPropertyPanel, ModifySoftEdgeRadiusHdl, weld::MetricSpinButton&, void)
+{
+ SdrMetricItem aItem(SDRATTR_SOFTEDGE_RADIUS, mxSoftEdgeRadius->get_value(FieldUnit::MM_100TH));
+ mpBindings->GetDispatcher()->ExecuteList(SID_ATTR_SOFTEDGE_RADIUS, SfxCallMode::RECORD,
+ { &aItem });
+}
+
+IMPL_LINK_NOARG(EffectPropertyPanel, ModifyGlowColorHdl, ColorListBox&, void)
+{
+ XColorItem aItem(SDRATTR_GLOW_COLOR, mxLBGlowColor->GetSelectEntryColor());
+ mpBindings->GetDispatcher()->ExecuteList(SID_ATTR_GLOW_COLOR, SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK_NOARG(EffectPropertyPanel, ModifyGlowRadiusHdl, weld::MetricSpinButton&, void)
+{
+ SdrMetricItem aItem(SDRATTR_GLOW_RADIUS, mxGlowRadius->get_value(FieldUnit::MM_100TH));
+ mpBindings->GetDispatcher()->ExecuteList(SID_ATTR_GLOW_RADIUS, SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK_NOARG(EffectPropertyPanel, ModifyGlowTransparencyHdl, weld::MetricSpinButton&, void)
+{
+ SdrPercentItem aItem(SDRATTR_GLOW_TRANSPARENCY,
+ mxGlowTransparency->get_value(FieldUnit::PERCENT));
+ mpBindings->GetDispatcher()->ExecuteList(SID_ATTR_GLOW_TRANSPARENCY, SfxCallMode::RECORD,
+ { &aItem });
+}
+
+void EffectPropertyPanel::UpdateControls()
+{
+ const bool bEnabled = mxGlowRadius->get_value(FieldUnit::MM_100TH) != 0;
+ mxLBGlowColor->set_sensitive(bEnabled);
+ mxGlowTransparency->set_sensitive(bEnabled);
+ mxFTColor->set_sensitive(bEnabled);
+ mxFTTransparency->set_sensitive(bEnabled);
+}
+
+void EffectPropertyPanel::NotifyItemUpdate(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ switch (nSID)
+ {
+ case SID_ATTR_SOFTEDGE_RADIUS:
+ {
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ const SdrMetricItem* pRadiusItem = dynamic_cast<const SdrMetricItem*>(pState);
+ if (pRadiusItem)
+ {
+ mxSoftEdgeRadius->set_value(pRadiusItem->GetValue(), FieldUnit::MM_100TH);
+ }
+ }
+ }
+ break;
+ case SID_ATTR_GLOW_COLOR:
+ {
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ const XColorItem* pColorItem = dynamic_cast<const XColorItem*>(pState);
+ if (pColorItem)
+ {
+ mxLBGlowColor->SelectEntry(pColorItem->GetColorValue());
+ }
+ }
+ }
+ break;
+ case SID_ATTR_GLOW_RADIUS:
+ {
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ const SdrMetricItem* pRadiusItem = dynamic_cast<const SdrMetricItem*>(pState);
+ if (pRadiusItem)
+ {
+ mxGlowRadius->set_value(pRadiusItem->GetValue(), FieldUnit::MM_100TH);
+ }
+ }
+ }
+ break;
+ case SID_ATTR_GLOW_TRANSPARENCY:
+ {
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ if (auto pItem = dynamic_cast<const SdrPercentItem*>(pState))
+ {
+ mxGlowTransparency->set_value(pItem->GetValue(), FieldUnit::PERCENT);
+ }
+ }
+ }
+ break;
+ }
+ UpdateControls();
+}
+
+std::unique_ptr<PanelLayout> EffectPropertyPanel::Create(weld::Widget* pParent,
+ SfxBindings* pBindings)
+{
+ if (pParent == nullptr)
+ throw css::lang::IllegalArgumentException(
+ "no parent Window given to EffectPropertyPanel::Create", nullptr, 0);
+ if (pBindings == nullptr)
+ throw css::lang::IllegalArgumentException(
+ "no SfxBindings given to EffectPropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<EffectPropertyPanel>(pParent, pBindings);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/effect/EffectPropertyPanel.hxx b/svx/source/sidebar/effect/EffectPropertyPanel.hxx
new file mode 100644
index 000000000..d657d83e6
--- /dev/null
+++ b/svx/source/sidebar/effect/EffectPropertyPanel.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_EFFECT_EFFECTPROPERTYPANEL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_EFFECT_EFFECTPROPERTYPANEL_HXX
+
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+
+class ColorListBox;
+
+namespace svx::sidebar
+{
+class EffectPropertyPanel : public PanelLayout,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+ EffectPropertyPanel(weld::Widget* pParent, SfxBindings* pBindings);
+ virtual ~EffectPropertyPanel() override;
+
+ static std::unique_ptr<PanelLayout> Create(weld::Widget* pParent, SfxBindings* pBindings);
+
+ virtual void NotifyItemUpdate(const sal_uInt16 nSId, const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override{};
+
+private:
+ sfx2::sidebar::ControllerItem maGlowColorController;
+ sfx2::sidebar::ControllerItem maGlowRadiusController;
+ sfx2::sidebar::ControllerItem maGlowTransparencyController;
+ std::unique_ptr<weld::Label> mxFTTransparency;
+ sfx2::sidebar::ControllerItem maSoftEdgeRadiusController;
+
+ SfxBindings* mpBindings;
+
+ std::unique_ptr<weld::MetricSpinButton> mxGlowRadius;
+ std::unique_ptr<ColorListBox> mxLBGlowColor;
+ std::unique_ptr<weld::MetricSpinButton> mxGlowTransparency;
+ std::unique_ptr<weld::Label> mxFTRadiusSoftEdge;
+ std::unique_ptr<weld::Label> mxFTRadiusGlow;
+ std::unique_ptr<weld::Label> mxFTColor;
+ std::unique_ptr<weld::MetricSpinButton> mxSoftEdgeRadius;
+
+ void Initialize();
+ void UpdateControls();
+
+ DECL_LINK(ModifyGlowColorHdl, ColorListBox&, void);
+ DECL_LINK(ModifyGlowRadiusHdl, weld::MetricSpinButton&, void);
+ DECL_LINK(ModifyGlowTransparencyHdl, weld::MetricSpinButton&, void);
+ DECL_LINK(ModifySoftEdgeRadiusHdl, weld::MetricSpinButton&, void);
+};
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/fontwork/FontworkPropertyPanel.cxx b/svx/source/sidebar/fontwork/FontworkPropertyPanel.cxx
new file mode 100644
index 000000000..972141b7b
--- /dev/null
+++ b/svx/source/sidebar/fontwork/FontworkPropertyPanel.cxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "FontworkPropertyPanel.hxx"
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+#include <comphelper/lok.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+namespace svx
+{
+namespace sidebar
+{
+FontworkPropertyPanel::FontworkPropertyPanel(weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame)
+ : PanelLayout(pParent, "FontworkPropertyPanel", "svx/ui/sidebarfontwork.ui")
+ , m_pToolbar(m_xBuilder->weld_toolbar("fontwork-toolbox"))
+ , m_xToolbar(new ToolbarUnoDispatcher(*m_pToolbar, *m_xBuilder, rxFrame))
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ m_pToolbar->set_item_visible(".uno:ExtrusionToggle", false);
+}
+
+std::unique_ptr<PanelLayout>
+FontworkPropertyPanel::Create(weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException(
+ "no parent Window given to FontworkPropertyPanel::Create", nullptr, 0);
+ if (!rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to FontworkPropertyPanel::Create",
+ nullptr, 1);
+
+ return std::make_unique<FontworkPropertyPanel>(pParent, rxFrame);
+}
+}
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/fontwork/FontworkPropertyPanel.hxx b/svx/source/sidebar/fontwork/FontworkPropertyPanel.hxx
new file mode 100644
index 000000000..cded09b95
--- /dev/null
+++ b/svx/source/sidebar/fontwork/FontworkPropertyPanel.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_AREA_FONTWORKPROPERTYPANEL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_AREA_FONTWORKPROPERTYPANEL_HXX
+
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <sfx2/weldutils.hxx>
+
+namespace svx
+{
+namespace sidebar
+{
+class FontworkPropertyPanel : public PanelLayout
+{
+public:
+ static std::unique_ptr<PanelLayout>
+ Create(weld::Widget* pParent, const css::uno::Reference<css::frame::XFrame>& rxFrame);
+
+ // constructor/destructor
+ FontworkPropertyPanel(weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame);
+
+private:
+ std::unique_ptr<weld::Toolbar> m_pToolbar;
+ std::unique_ptr<ToolbarUnoDispatcher> m_xToolbar;
+};
+}
+} // end of namespace svx::sidebar
+
+#endif // INCLUDED_SVX_SOURCE_SIDEBAR_AREA_FONTWORKPROPERTYPANEL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/graphic/GraphicPropertyPanel.cxx b/svx/source/sidebar/graphic/GraphicPropertyPanel.cxx
new file mode 100644
index 000000000..550364955
--- /dev/null
+++ b/svx/source/sidebar/graphic/GraphicPropertyPanel.cxx
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "GraphicPropertyPanel.hxx"
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <svx/dialmgr.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+using namespace css;
+using namespace css::uno;
+
+
+// namespace open
+
+namespace svx::sidebar {
+
+
+GraphicPropertyPanel::GraphicPropertyPanel(
+ weld::Widget* pParent,
+ SfxBindings* pBindings)
+: PanelLayout(pParent, "GraphicPropertyPanel", "svx/ui/sidebargraphic.ui"),
+ maBrightControl(SID_ATTR_GRAF_LUMINANCE, *pBindings, *this),
+ maContrastControl(SID_ATTR_GRAF_CONTRAST, *pBindings, *this),
+ maTransparenceControl(SID_ATTR_GRAF_TRANSPARENCE, *pBindings, *this),
+ maRedControl(SID_ATTR_GRAF_RED, *pBindings, *this),
+ maGreenControl(SID_ATTR_GRAF_GREEN, *pBindings, *this),
+ maBlueControl(SID_ATTR_GRAF_BLUE, *pBindings, *this),
+ maGammaControl(SID_ATTR_GRAF_GAMMA, *pBindings, *this),
+ maModeControl(SID_ATTR_GRAF_MODE, *pBindings, *this),
+ mpBindings(pBindings),
+ mxMtrBrightness(m_xBuilder->weld_metric_spin_button("setbrightness", FieldUnit::PERCENT)),
+ mxMtrContrast(m_xBuilder->weld_metric_spin_button("setcontrast", FieldUnit::PERCENT)),
+ mxLBColorMode(m_xBuilder->weld_combo_box("setcolormode")),
+ mxMtrTrans(m_xBuilder->weld_metric_spin_button("setgraphtransparency", FieldUnit::PERCENT))
+{
+ mxLBColorMode->set_size_request(mxLBColorMode->get_preferred_size().Width(), -1);
+ Initialize();
+}
+
+GraphicPropertyPanel::~GraphicPropertyPanel()
+{
+ mxMtrBrightness.reset();
+ mxMtrContrast.reset();
+ mxLBColorMode.reset();
+ mxMtrTrans.reset();
+
+ maBrightControl.dispose();
+ maContrastControl.dispose();
+ maTransparenceControl.dispose();
+ maRedControl.dispose();
+ maGreenControl.dispose();
+ maBlueControl.dispose();
+ maGammaControl.dispose();
+ maModeControl.dispose();
+}
+
+void GraphicPropertyPanel::Initialize()
+{
+ mxMtrBrightness->connect_value_changed( LINK( this, GraphicPropertyPanel, ModifyBrightnessHdl ) );
+ mxMtrContrast->connect_value_changed( LINK( this, GraphicPropertyPanel, ModifyContrastHdl ) );
+ mxMtrTrans->connect_value_changed( LINK( this, GraphicPropertyPanel, ModifyTransHdl ) );
+
+ mxLBColorMode->append_text(SvxResId(RID_SVXSTR_GRAFMODE_STANDARD));
+ mxLBColorMode->append_text(SvxResId(RID_SVXSTR_GRAFMODE_GREYS));
+ mxLBColorMode->append_text(SvxResId(RID_SVXSTR_GRAFMODE_MONO));
+ mxLBColorMode->append_text(SvxResId(RID_SVXSTR_GRAFMODE_WATERMARK));
+ mxLBColorMode->connect_changed( LINK( this, GraphicPropertyPanel, ClickColorModeHdl ));
+}
+
+IMPL_LINK_NOARG( GraphicPropertyPanel, ModifyBrightnessHdl, weld::MetricSpinButton&, void )
+{
+ const sal_Int16 nBright = mxMtrBrightness->get_value(FieldUnit::PERCENT);
+ const SfxInt16Item aBrightItem( SID_ATTR_GRAF_LUMINANCE, nBright );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_GRAF_LUMINANCE,
+ SfxCallMode::RECORD, { &aBrightItem });
+}
+
+
+IMPL_LINK_NOARG( GraphicPropertyPanel, ModifyContrastHdl, weld::MetricSpinButton&, void )
+{
+ const sal_Int16 nContrast = mxMtrContrast->get_value(FieldUnit::PERCENT);
+ const SfxInt16Item aContrastItem( SID_ATTR_GRAF_CONTRAST, nContrast );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_GRAF_CONTRAST,
+ SfxCallMode::RECORD, { &aContrastItem });
+}
+
+
+IMPL_LINK_NOARG( GraphicPropertyPanel, ModifyTransHdl, weld::MetricSpinButton&, void )
+{
+ const sal_Int16 nTrans = mxMtrTrans->get_value(FieldUnit::PERCENT);
+ const SfxUInt16Item aTransItem( SID_ATTR_GRAF_TRANSPARENCE, nTrans );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_GRAF_TRANSPARENCE,
+ SfxCallMode::RECORD, { &aTransItem });
+}
+
+
+IMPL_LINK_NOARG( GraphicPropertyPanel, ClickColorModeHdl, weld::ComboBox&, void )
+{
+ const sal_Int16 nTrans = mxLBColorMode->get_active();
+ const SfxUInt16Item aTransItem( SID_ATTR_GRAF_MODE, nTrans );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_GRAF_MODE,
+ SfxCallMode::RECORD, { &aTransItem });
+}
+
+std::unique_ptr<PanelLayout> GraphicPropertyPanel::Create (
+ weld::Widget* pParent,
+ SfxBindings* pBindings)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to GraphicPropertyPanel::Create", nullptr, 0);
+ if (pBindings == nullptr)
+ throw lang::IllegalArgumentException("no SfxBindings given to GraphicPropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<GraphicPropertyPanel>(pParent, pBindings);
+}
+
+void GraphicPropertyPanel::NotifyItemUpdate(
+ sal_uInt16 nSID,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ switch( nSID )
+ {
+ case SID_ATTR_GRAF_LUMINANCE:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ mxMtrBrightness->set_sensitive(true);
+ const SfxInt16Item* pItem = dynamic_cast< const SfxInt16Item* >(pState);
+
+ if(pItem)
+ {
+ const sal_Int64 nBright = pItem->GetValue();
+ mxMtrBrightness->set_value(nBright, FieldUnit::PERCENT);
+ }
+ }
+ else if(SfxItemState::DISABLED == eState)
+ {
+ mxMtrBrightness->set_sensitive(false);
+ }
+ else
+ {
+ mxMtrBrightness->set_sensitive(true);
+ mxMtrBrightness->set_text(OUString());
+ }
+ break;
+ }
+ case SID_ATTR_GRAF_CONTRAST:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ mxMtrContrast->set_sensitive(true);
+ const SfxInt16Item* pItem = dynamic_cast< const SfxInt16Item* >(pState);
+
+ if(pItem)
+ {
+ const sal_Int64 nContrast = pItem->GetValue();
+ mxMtrContrast->set_value(nContrast, FieldUnit::PERCENT);
+ }
+ }
+ else if(SfxItemState::DISABLED == eState)
+ {
+ mxMtrContrast->set_sensitive(false);
+ }
+ else
+ {
+ mxMtrContrast->set_sensitive(true);
+ mxMtrContrast->set_text(OUString());
+ }
+ break;
+ }
+ case SID_ATTR_GRAF_TRANSPARENCE:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ mxMtrTrans->set_sensitive(true);
+ const SfxUInt16Item* pItem = dynamic_cast< const SfxUInt16Item* >(pState);
+
+ if(pItem)
+ {
+ const sal_Int64 nTrans = pItem->GetValue();
+ mxMtrTrans->set_value(nTrans, FieldUnit::PERCENT);
+ }
+ }
+ else if(SfxItemState::DISABLED == eState)
+ {
+ mxMtrTrans->set_sensitive(false);
+ }
+ else
+ {
+ mxMtrTrans->set_sensitive(true);
+ mxMtrTrans->set_text(OUString());
+ }
+ break;
+ }
+ case SID_ATTR_GRAF_MODE:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ mxLBColorMode->set_sensitive(true);
+
+ if(pState)
+ {
+ const sal_uInt16 nTrans = static_cast< const SfxUInt16Item* >(pState)->GetValue();
+ mxLBColorMode->set_active(nTrans);
+ }
+ }
+ else if(SfxItemState::DISABLED == eState)
+ {
+ mxLBColorMode->set_sensitive(false);
+ }
+ else
+ {
+ mxLBColorMode->set_sensitive(true);
+ mxLBColorMode->set_active(-1);
+ }
+ break;
+ }
+ }
+}
+
+// namespace close
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/graphic/GraphicPropertyPanel.hxx b/svx/source/sidebar/graphic/GraphicPropertyPanel.hxx
new file mode 100644
index 000000000..e7fd4914b
--- /dev/null
+++ b/svx/source/sidebar/graphic/GraphicPropertyPanel.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_GRAPHIC_GRAPHICPROPERTYPANEL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_GRAPHIC_GRAPHICPROPERTYPANEL_HXX
+
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <vcl/weld.hxx>
+
+namespace svx::sidebar {
+
+class GraphicPropertyPanel
+: public PanelLayout,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+ virtual ~GraphicPropertyPanel() override;
+
+ static std::unique_ptr<PanelLayout> Create(
+ weld::Widget* pParent,
+ SfxBindings* pBindings);
+
+ virtual void NotifyItemUpdate(
+ const sal_uInt16 nSId,
+ const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(
+ const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override {};
+
+ SfxBindings* GetBindings() { return mpBindings;}
+
+ // constructor/destructor
+ GraphicPropertyPanel(
+ weld::Widget* pParent,
+ SfxBindings* pBindings);
+
+private:
+ ::sfx2::sidebar::ControllerItem maBrightControl;
+ ::sfx2::sidebar::ControllerItem maContrastControl;
+ ::sfx2::sidebar::ControllerItem maTransparenceControl;
+ ::sfx2::sidebar::ControllerItem maRedControl;
+ ::sfx2::sidebar::ControllerItem maGreenControl;
+ ::sfx2::sidebar::ControllerItem maBlueControl;
+ ::sfx2::sidebar::ControllerItem maGammaControl;
+ ::sfx2::sidebar::ControllerItem maModeControl;
+
+ SfxBindings* mpBindings;
+
+ //ui controls
+ std::unique_ptr<weld::MetricSpinButton> mxMtrBrightness;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrContrast;
+ std::unique_ptr<weld::ComboBox> mxLBColorMode;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrTrans;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrRed;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrGreen;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrBlue;
+ std::unique_ptr<weld::SpinButton> mxMtrGamma;
+
+ DECL_LINK( ModifyBrightnessHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( ModifyContrastHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( ModifyTransHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( ClickColorModeHdl, weld::ComboBox&, void );
+
+ void Initialize();
+};
+
+} // end of namespace svx::sidebar
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/inspector/InspectorTextPanel.cxx b/svx/source/sidebar/inspector/InspectorTextPanel.cxx
new file mode 100644
index 000000000..0b5da3d2d
--- /dev/null
+++ b/svx/source/sidebar/inspector/InspectorTextPanel.cxx
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <o3tl/safeint.hxx>
+#include <sal/config.h>
+
+#include <svx/dialmgr.hxx>
+
+#include <svx/sidebar/InspectorTextPanel.hxx>
+
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <inspectorvalues.hrc>
+
+using namespace css;
+
+const int MinimumPanelWidth = 250;
+
+namespace svx::sidebar
+{
+std::unique_ptr<PanelLayout> InspectorTextPanel::Create(weld::Widget* pParent)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to InspectorTextPanel::Create",
+ nullptr, 0);
+ return std::make_unique<InspectorTextPanel>(pParent);
+}
+
+InspectorTextPanel::InspectorTextPanel(weld::Widget* pParent)
+ : PanelLayout(pParent, "InspectorTextPanel", "svx/ui/inspectortextpanel.ui")
+ , mpListBoxStyles(m_xBuilder->weld_tree_view("listbox_fonts"))
+{
+ mpListBoxStyles->set_size_request(MinimumPanelWidth, -1);
+ float fWidth = mpListBoxStyles->get_approximate_digit_width();
+ std::vector<int> aWidths{ o3tl::narrowing<int>(fWidth * 29) };
+ // 2nd column will fill remaining space
+ mpListBoxStyles->set_column_fixed_widths(aWidths);
+}
+
+static bool GetPropertyValues(std::u16string_view rPropName, const uno::Any& rAny,
+ OUString& rString)
+{
+ // Hide Asian and Complex properties
+ if (!SvtCJKOptions::IsCJKFontEnabled() && rPropName.find(u"Asian") != std::u16string_view::npos)
+ return false;
+ if (!SvtCTLOptions().IsCTLFontEnabled()
+ && rPropName.find(u"Complex") != std::u16string_view::npos)
+ return false;
+
+ if (bool bValue; rAny >>= bValue)
+ {
+ rString = SvxResId(bValue ? RID_TRUE : RID_FALSE); // tdf#139136
+ }
+ else if (OUString aValue; (rAny >>= aValue) && !(aValue.isEmpty()))
+ {
+ rString = aValue;
+ }
+ else if (awt::FontSlant eValue; rAny >>= eValue)
+ {
+ rString = SvxResId(eValue == awt::FontSlant_ITALIC ? RID_ITALIC : RID_NORMAL);
+ }
+ else if (tools::Long nValueLong; rAny >>= nValueLong)
+ {
+ if (rPropName.find(u"Color") != std::u16string_view::npos)
+ rString = "0x" + OUString::number(nValueLong, 16);
+ else
+ rString = OUString::number(nValueLong);
+ }
+ else if (double fValue; rAny >>= fValue)
+ {
+ if (rPropName.find(u"Weight") != std::u16string_view::npos)
+ rString = SvxResId(fValue > 100 ? RID_BOLD : RID_NORMAL);
+ else
+ rString = OUString::number((round(fValue * 100)) / 100.00);
+ }
+ else if (short nValueShort; rAny >>= nValueShort)
+ {
+ rString = OUString::number(nValueShort);
+ }
+ else
+ return false;
+
+ return true;
+}
+
+static void FillBox_Impl(weld::TreeView& rListBoxStyles, const TreeNode& rCurrent,
+ const weld::TreeIter* pParent)
+{
+ std::unique_ptr<weld::TreeIter> pResult = rListBoxStyles.make_iterator();
+ const OUString& rName = rCurrent.sNodeName;
+ OUString sPairValue;
+
+ if (!(rCurrent.NodeType != TreeNode::SimpleProperty
+ || GetPropertyValues(rName, rCurrent.aValue, sPairValue)))
+ return;
+
+ rListBoxStyles.insert(pParent, -1, &rName, nullptr, nullptr, nullptr, false, pResult.get());
+ rListBoxStyles.set_sensitive(*pResult, !rCurrent.isGrey, 0);
+ rListBoxStyles.set_text_emphasis(*pResult, rCurrent.NodeType == TreeNode::Category, 0);
+
+ if (rCurrent.NodeType == TreeNode::SimpleProperty)
+ {
+ rListBoxStyles.set_text(*pResult, sPairValue, 1);
+ rListBoxStyles.set_sensitive(*pResult, !rCurrent.isGrey, 1);
+ rListBoxStyles.set_text_emphasis(*pResult, false, 1);
+ }
+ else
+ {
+ // Necessary, without this the selection line will be truncated.
+ rListBoxStyles.set_text(*pResult, "", 1);
+ }
+
+ for (const TreeNode& rChildNode : rCurrent.children)
+ FillBox_Impl(rListBoxStyles, rChildNode, pResult.get());
+}
+
+void InspectorTextPanel::updateEntries(const std::vector<TreeNode>& rStore, const sal_Int32 nParIdx)
+{
+ mpListBoxStyles->freeze();
+ mpListBoxStyles->clear();
+ for (const TreeNode& rChildNode : rStore)
+ {
+ FillBox_Impl(*mpListBoxStyles, rChildNode, nullptr);
+ }
+
+ mpListBoxStyles->thaw();
+
+ weld::TreeView* pTreeDiagram = mpListBoxStyles.get();
+ pTreeDiagram->all_foreach([pTreeDiagram](weld::TreeIter& rEntry) {
+ pTreeDiagram->expand_row(rEntry);
+ return false;
+ });
+
+ // Collapse "Default Paragraph Style"
+
+ std::unique_ptr<weld::TreeIter> pEntry = mpListBoxStyles->make_iterator();
+ if (!mpListBoxStyles->get_iter_first(*pEntry))
+ return;
+ // skip the optional metadata items before "Default Paragraph Style"
+ for (sal_Int32 i = 0; i < nParIdx; ++i)
+ {
+ if (!mpListBoxStyles->iter_next_sibling(*pEntry))
+ return;
+ }
+ if (!mpListBoxStyles->iter_next(*pEntry))
+ return;
+
+ mpListBoxStyles->collapse_row(*pEntry);
+}
+
+InspectorTextPanel::~InspectorTextPanel() {}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/line/LinePropertyPanel.cxx b/svx/source/sidebar/line/LinePropertyPanel.cxx
new file mode 100644
index 000000000..02dd597bd
--- /dev/null
+++ b/svx/source/sidebar/line/LinePropertyPanel.cxx
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "LinePropertyPanel.hxx"
+#include <svx/svxids.hrc>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+using namespace css;
+using namespace css::uno;
+
+namespace svx::sidebar {
+
+LinePropertyPanel::LinePropertyPanel(
+ weld::Widget* pParent,
+ const uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+: LinePropertyPanelBase(pParent, rxFrame),
+ maStyleControl(SID_ATTR_LINE_STYLE, *pBindings, *this),
+ maDashControl (SID_ATTR_LINE_DASH, *pBindings, *this),
+ maWidthControl(SID_ATTR_LINE_WIDTH, *pBindings, *this),
+ maTransControl(SID_ATTR_LINE_TRANSPARENCE, *pBindings, *this),
+ maEdgeStyle(SID_ATTR_LINE_JOINT, *pBindings, *this),
+ maCapStyle(SID_ATTR_LINE_CAP, *pBindings, *this),
+ mpBindings(pBindings)
+{
+ setMapUnit(maWidthControl.GetCoreMetric());
+}
+
+LinePropertyPanel::~LinePropertyPanel()
+{
+ maStyleControl.dispose();
+ maDashControl.dispose();
+ maWidthControl.dispose();
+ maTransControl.dispose();
+ maEdgeStyle.dispose();
+ maCapStyle.dispose();
+}
+
+std::unique_ptr<PanelLayout> LinePropertyPanel::Create (
+ weld::Widget* pParent,
+ const uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to LinePropertyPanel::Create", nullptr, 0);
+ if ( ! rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to LinePropertyPanel::Create", nullptr, 1);
+ if (pBindings == nullptr)
+ throw lang::IllegalArgumentException("no SfxBindings given to LinePropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<LinePropertyPanel>(pParent, rxFrame, pBindings);
+}
+
+void LinePropertyPanel::NotifyItemUpdate(
+ sal_uInt16 nSID,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ const bool bDisabled(SfxItemState::DISABLED == eState);
+ const bool bSetOrDefault = eState >= SfxItemState::DEFAULT;
+
+ switch(nSID)
+ {
+ case SID_ATTR_LINE_TRANSPARENCE:
+ {
+ updateLineTransparence(bDisabled, bSetOrDefault, pState);
+ break;
+ }
+ case SID_ATTR_LINE_WIDTH:
+ {
+ updateLineWidth(bDisabled, bSetOrDefault, pState);
+ break;
+ }
+ case SID_ATTR_LINE_JOINT:
+ {
+ updateLineJoint(bDisabled, bSetOrDefault, pState);
+ break;
+ }
+ case SID_ATTR_LINE_CAP:
+ {
+ updateLineCap(bDisabled, bSetOrDefault, pState);
+ break;
+ }
+ }
+ ActivateControls();
+}
+
+void LinePropertyPanel::HandleContextChange(
+ const vcl::EnumContext& rContext)
+{
+ if(maContext == rContext)
+ {
+ // Nothing to do
+ return;
+ }
+
+ maContext = rContext;
+ bool bShowArrows = false;
+
+ switch(maContext.GetCombinedContext_DI())
+ {
+ case CombinedEnumContext(Application::Calc, Context::DrawLine):
+ case CombinedEnumContext(Application::DrawImpress, Context::DrawLine):
+ case CombinedEnumContext(Application::DrawImpress, Context::Draw):
+ case CombinedEnumContext(Application::WriterVariants, Context::Draw):
+ // TODO : Implement DrawLine context in Writer
+ bShowArrows = true;
+ break;
+ }
+
+ if (!bShowArrows)
+ disableArrowHead();
+ else
+ enableArrowHead();
+}
+
+void LinePropertyPanel::setLineJoint(const XLineJointItem* pItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_LINE_JOINT,
+ SfxCallMode::RECORD, { pItem });
+}
+
+void LinePropertyPanel::setLineCap(const XLineCapItem* pItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_LINE_CAP,
+ SfxCallMode::RECORD, { pItem });
+}
+
+void LinePropertyPanel::setLineTransparency(const XLineTransparenceItem& rItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_LINE_STYLE,
+ SfxCallMode::RECORD, { &rItem });
+}
+
+void LinePropertyPanel::setLineWidth(const XLineWidthItem& rItem)
+{
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_LINE_WIDTH,
+ SfxCallMode::RECORD, { &rItem });
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/line/LinePropertyPanel.hxx b/svx/source/sidebar/line/LinePropertyPanel.hxx
new file mode 100644
index 000000000..7223cd9f1
--- /dev/null
+++ b/svx/source/sidebar/line/LinePropertyPanel.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_LINE_LINEPROPERTYPANEL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_LINE_LINEPROPERTYPANEL_HXX
+
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/IContextChangeReceiver.hxx>
+#include <svx/sidebar/LinePropertyPanelBase.hxx>
+#include <vcl/EnumContext.hxx>
+
+class XLineStyleItem;
+class XLineDashItem;
+class XLineStartItem;
+class XLineEndItem;
+class XLineEndList;
+class XDashList;
+class ListBox;
+class ToolBox;
+
+namespace svx::sidebar
+{
+
+class LinePropertyPanel : public LinePropertyPanelBase,
+ public sfx2::sidebar::IContextChangeReceiver,
+ public sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+ virtual ~LinePropertyPanel() override;
+
+ static std::unique_ptr<PanelLayout> Create(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings);
+
+ virtual void HandleContextChange(
+ const vcl::EnumContext& rContext) override;
+
+ virtual void NotifyItemUpdate(
+ const sal_uInt16 nSId,
+ const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(
+ const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override {};
+
+ SfxBindings* GetBindings() { return mpBindings;}
+
+ // constructor/destructor
+ LinePropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings);
+
+ virtual void setLineWidth(const XLineWidthItem& rItem) override;
+
+protected:
+
+ virtual void setLineTransparency(const XLineTransparenceItem& rItem) override;
+ virtual void setLineJoint(const XLineJointItem* pItem) override;
+ virtual void setLineCap(const XLineCapItem* pItem) override;
+
+private:
+ //ControllerItem
+ sfx2::sidebar::ControllerItem maStyleControl;
+ sfx2::sidebar::ControllerItem maDashControl;
+ sfx2::sidebar::ControllerItem maWidthControl;
+ sfx2::sidebar::ControllerItem maTransControl;
+ sfx2::sidebar::ControllerItem maEdgeStyle;
+ sfx2::sidebar::ControllerItem maCapStyle;
+
+ SfxBindings* mpBindings;
+ vcl::EnumContext maContext;
+};
+
+} // end of namespace svx::sidebar
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/line/LinePropertyPanelBase.cxx b/svx/source/sidebar/line/LinePropertyPanelBase.cxx
new file mode 100644
index 000000000..454e16a33
--- /dev/null
+++ b/svx/source/sidebar/line/LinePropertyPanelBase.cxx
@@ -0,0 +1,470 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <svx/sidebar/LinePropertyPanelBase.hxx>
+#include <sfx2/weldutils.hxx>
+#include <svx/linectrl.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <bitmaps.hlst>
+
+using namespace css;
+using namespace css::uno;
+
+constexpr OStringLiteral SELECTWIDTH = "SelectWidth";
+
+namespace svx::sidebar {
+
+// trigger disabling the arrows if the none line style is selected
+class LineStyleNoneChange
+{
+private:
+ LinePropertyPanelBase& m_rPanel;
+
+public:
+ LineStyleNoneChange(LinePropertyPanelBase& rPanel)
+ : m_rPanel(rPanel)
+ {
+ }
+
+ void operator()(bool bLineStyleNone)
+ {
+ m_rPanel.SetNoneLineStyle(bLineStyleNone);
+ }
+};
+
+namespace
+{
+ SvxLineStyleToolBoxControl* getLineStyleToolBoxControl(const ToolbarUnoDispatcher& rToolBoxColor)
+ {
+ css::uno::Reference<css::frame::XToolbarController> xController = rToolBoxColor.GetControllerForCommand(".uno:XLineStyle");
+ SvxLineStyleToolBoxControl* pToolBoxLineStyleControl = dynamic_cast<SvxLineStyleToolBoxControl*>(xController.get());
+ return pToolBoxLineStyleControl;
+ }
+}
+
+
+LinePropertyPanelBase::LinePropertyPanelBase(
+ weld::Widget* pParent,
+ const uno::Reference<css::frame::XFrame>& rxFrame)
+: PanelLayout(pParent, "LinePropertyPanel", "svx/ui/sidebarline.ui"),
+ mxTBColor(m_xBuilder->weld_toolbar("color")),
+ mxColorDispatch(new ToolbarUnoDispatcher(*mxTBColor, *m_xBuilder, rxFrame)),
+ mxLineStyleTB(m_xBuilder->weld_toolbar("linestyle")),
+ mxLineStyleDispatch(new ToolbarUnoDispatcher(*mxLineStyleTB, *m_xBuilder, rxFrame)),
+ mnWidthCoreValue(0),
+ mxFTWidth(m_xBuilder->weld_label("widthlabel")),
+ mxTBWidth(m_xBuilder->weld_toolbar("width")),
+ mxFTTransparency(m_xBuilder->weld_label("translabel")),
+ mxMFTransparent(m_xBuilder->weld_metric_spin_button("linetransparency", FieldUnit::PERCENT)),
+ mxFTEdgeStyle(m_xBuilder->weld_label("cornerlabel")),
+ mxLBEdgeStyle(m_xBuilder->weld_combo_box("edgestyle")),
+ mxFTCapStyle(m_xBuilder->weld_label("caplabel")),
+ mxLBCapStyle(m_xBuilder->weld_combo_box("linecapstyle")),
+ mxGridLineProps(m_xBuilder->weld_widget("lineproperties")),
+ mxBoxArrowProps(m_xBuilder->weld_widget("arrowproperties")),
+ mxLineWidthPopup(new LineWidthPopup(mxTBWidth.get(), *this)),
+ mxLineStyleNoneChange(new LineStyleNoneChange(*this)),
+ mnTrans(0),
+ meMapUnit(MapUnit::MapMM),
+ maIMGNone(BMP_NONE_ICON),
+ mbWidthValuable(true),
+ mbArrowSupported(true),
+ mbNoneLineStyle(false)
+{
+ Initialize();
+}
+
+LinePropertyPanelBase::~LinePropertyPanelBase()
+{
+ mxLineWidthPopup.reset();
+ mxFTWidth.reset();
+ mxTBWidth.reset();
+ mxColorDispatch.reset();
+ mxTBColor.reset();
+ mxFTTransparency.reset();
+ mxMFTransparent.reset();
+ mxLineStyleDispatch.reset();
+ mxLineStyleTB.reset();
+ mxFTEdgeStyle.reset();
+ mxLBEdgeStyle.reset();
+ mxFTCapStyle.reset();
+ mxLBCapStyle.reset();
+ mxGridLineProps.reset();
+ mxBoxArrowProps.reset();
+}
+
+void LinePropertyPanelBase::Initialize()
+{
+ mxTBWidth->set_item_popover(SELECTWIDTH, mxLineWidthPopup->getTopLevel());
+
+ maIMGWidthIcon[0] = BMP_WIDTH1_ICON;
+ maIMGWidthIcon[1] = BMP_WIDTH2_ICON;
+ maIMGWidthIcon[2] = BMP_WIDTH3_ICON;
+ maIMGWidthIcon[3] = BMP_WIDTH4_ICON;
+ maIMGWidthIcon[4] = BMP_WIDTH5_ICON;
+ maIMGWidthIcon[5] = BMP_WIDTH6_ICON;
+ maIMGWidthIcon[6] = BMP_WIDTH7_ICON;
+ maIMGWidthIcon[7] = BMP_WIDTH8_ICON;
+
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGWidthIcon[0]);
+ mxTBWidth->connect_clicked(LINK(this, LinePropertyPanelBase, ToolboxWidthSelectHdl));
+
+ mxMFTransparent->connect_value_changed(LINK(this, LinePropertyPanelBase, ChangeTransparentHdl));
+
+ mxLBEdgeStyle->connect_changed( LINK( this, LinePropertyPanelBase, ChangeEdgeStyleHdl ) );
+
+ mxLBCapStyle->connect_changed( LINK( this, LinePropertyPanelBase, ChangeCapStyleHdl ) );
+
+ SvxLineStyleToolBoxControl* pLineStyleControl = getLineStyleToolBoxControl(*mxLineStyleDispatch);
+ pLineStyleControl->setLineStyleIsNoneFunction(*mxLineStyleNoneChange);
+}
+
+void LinePropertyPanelBase::updateLineTransparence(bool bDisabled, bool bSetOrDefault,
+ const SfxPoolItem* pState)
+{
+ if(bDisabled)
+ {
+ mxFTTransparency->set_sensitive(false);
+ mxMFTransparent->set_sensitive(false);
+ }
+ else
+ {
+ mxFTTransparency->set_sensitive(true);
+ mxMFTransparent->set_sensitive(true);
+ }
+
+ if(bSetOrDefault)
+ {
+ if (const XLineTransparenceItem* pItem = dynamic_cast<const XLineTransparenceItem*>(pState))
+ {
+ mnTrans = pItem->GetValue();
+ mxMFTransparent->set_value(mnTrans, FieldUnit::PERCENT);
+ return;
+ }
+ }
+
+ mxMFTransparent->set_value(0, FieldUnit::PERCENT);//add
+ mxMFTransparent->set_text(OUString());
+}
+
+void LinePropertyPanelBase::updateLineWidth(bool bDisabled, bool bSetOrDefault,
+ const SfxPoolItem* pState)
+{
+ if(bDisabled)
+ {
+ mxTBWidth->set_sensitive(false);
+ mxFTWidth->set_sensitive(false);
+ }
+ else
+ {
+ mxTBWidth->set_sensitive(true);
+ mxFTWidth->set_sensitive(true);
+ }
+
+ if(bSetOrDefault)
+ {
+ if (const XLineWidthItem* pItem = dynamic_cast<const XLineWidthItem*>(pState))
+ {
+ mnWidthCoreValue = pItem->GetValue();
+ mbWidthValuable = true;
+ SetWidthIcon();
+ return;
+ }
+ }
+
+ mbWidthValuable = false;
+ SetWidthIcon();
+}
+
+void LinePropertyPanelBase::updateLineJoint(bool bDisabled, bool bSetOrDefault,
+ const SfxPoolItem* pState)
+{
+ if(bDisabled)
+ {
+ mxLBEdgeStyle->set_sensitive(false);
+ mxFTEdgeStyle->set_sensitive(false);
+ }
+ else
+ {
+ mxLBEdgeStyle->set_sensitive(true);
+ mxFTEdgeStyle->set_sensitive(true);
+ }
+
+ if(bSetOrDefault)
+ {
+ if (const XLineJointItem* pItem = dynamic_cast<const XLineJointItem*>(pState))
+ {
+ sal_Int32 nEntryPos(0);
+
+ switch(pItem->GetValue())
+ {
+ case drawing::LineJoint_ROUND:
+ {
+ nEntryPos = 1;
+ break;
+ }
+ case drawing::LineJoint_NONE:
+ {
+ nEntryPos = 2;
+ break;
+ }
+ case drawing::LineJoint_MIDDLE:
+ case drawing::LineJoint_MITER:
+ {
+ nEntryPos = 3;
+ break;
+ }
+ case drawing::LineJoint_BEVEL:
+ {
+ nEntryPos = 4;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if(nEntryPos)
+ {
+ mxLBEdgeStyle->set_active(nEntryPos - 1);
+ return;
+ }
+ }
+ }
+
+ mxLBEdgeStyle->set_active(-1);
+}
+
+void LinePropertyPanelBase::updateLineCap(bool bDisabled, bool bSetOrDefault,
+ const SfxPoolItem* pState)
+{
+ if(bDisabled)
+ {
+ mxLBCapStyle->set_sensitive(false);
+ mxFTCapStyle->set_sensitive(false);
+ }
+ else
+ {
+ mxLBCapStyle->set_sensitive(true);
+ mxLBCapStyle->set_sensitive(true);
+ }
+
+ if(bSetOrDefault)
+ {
+ if (const XLineCapItem* pItem = dynamic_cast<const XLineCapItem*>(pState))
+ {
+ sal_Int32 nEntryPos(0);
+
+ switch(pItem->GetValue())
+ {
+ case drawing::LineCap_BUTT:
+ {
+ nEntryPos = 1;
+ break;
+ }
+ case drawing::LineCap_ROUND:
+ {
+ nEntryPos = 2;
+ break;
+ }
+ case drawing::LineCap_SQUARE:
+ {
+ nEntryPos = 3;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if(nEntryPos)
+ {
+ mxLBCapStyle->set_active(nEntryPos - 1);
+ return;
+ }
+ }
+ }
+
+ mxLBCapStyle->set_active(-1);
+}
+
+IMPL_LINK_NOARG(LinePropertyPanelBase, ChangeEdgeStyleHdl, weld::ComboBox&, void)
+{
+ const sal_Int32 nPos(mxLBEdgeStyle->get_active());
+
+ if (nPos == -1 || !mxLBEdgeStyle->get_value_changed_from_saved())
+ return;
+
+ std::unique_ptr<XLineJointItem> pItem;
+
+ switch(nPos)
+ {
+ case 0: // rounded
+ {
+ pItem.reset(new XLineJointItem(drawing::LineJoint_ROUND));
+ break;
+ }
+ case 1: // none
+ {
+ pItem.reset(new XLineJointItem(drawing::LineJoint_NONE));
+ break;
+ }
+ case 2: // mitered
+ {
+ pItem.reset(new XLineJointItem(drawing::LineJoint_MITER));
+ break;
+ }
+ case 3: // beveled
+ {
+ pItem.reset(new XLineJointItem(drawing::LineJoint_BEVEL));
+ break;
+ }
+ }
+
+ setLineJoint(pItem.get());
+}
+
+IMPL_LINK_NOARG(LinePropertyPanelBase, ChangeCapStyleHdl, weld::ComboBox&, void)
+{
+ const sal_Int32 nPos(mxLBCapStyle->get_active());
+
+ if (!(nPos != -1 && mxLBCapStyle->get_value_changed_from_saved()))
+ return;
+
+ std::unique_ptr<XLineCapItem> pItem;
+
+ switch(nPos)
+ {
+ case 0: // flat
+ {
+ pItem.reset(new XLineCapItem(drawing::LineCap_BUTT));
+ break;
+ }
+ case 1: // round
+ {
+ pItem.reset(new XLineCapItem(drawing::LineCap_ROUND));
+ break;
+ }
+ case 2: // square
+ {
+ pItem.reset(new XLineCapItem(drawing::LineCap_SQUARE));
+ break;
+ }
+ }
+
+ setLineCap(pItem.get());
+}
+
+IMPL_LINK_NOARG(LinePropertyPanelBase, ToolboxWidthSelectHdl, const OString&, void)
+{
+ mxTBWidth->set_menu_item_active(SELECTWIDTH, !mxTBWidth->get_menu_item_active(SELECTWIDTH));
+}
+
+void LinePropertyPanelBase::EndLineWidthPopup()
+{
+ mxTBWidth->set_menu_item_active(SELECTWIDTH, false);
+}
+
+IMPL_LINK_NOARG( LinePropertyPanelBase, ChangeTransparentHdl, weld::MetricSpinButton&, void )
+{
+ sal_uInt16 nVal = static_cast<sal_uInt16>(mxMFTransparent->get_value(FieldUnit::PERCENT));
+ XLineTransparenceItem aItem( nVal );
+
+ setLineTransparency(aItem);
+}
+
+void LinePropertyPanelBase::SetWidthIcon(int n)
+{
+ if (n == 0)
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGNone);
+ else
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGWidthIcon[n-1]);
+}
+
+void LinePropertyPanelBase::SetWidthIcon()
+{
+ if(!mbWidthValuable)
+ {
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGNone);
+ return;
+ }
+
+ tools::Long nVal = OutputDevice::LogicToLogic(mnWidthCoreValue * 10, meMapUnit, MapUnit::MapPoint);
+
+ if(nVal <= 6)
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGWidthIcon[0]);
+ else if (nVal <= 9)
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGWidthIcon[1]);
+ else if (nVal <= 12)
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGWidthIcon[2]);
+ else if (nVal <= 19)
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGWidthIcon[3]);
+ else if (nVal <= 26)
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGWidthIcon[4]);
+ else if (nVal <= 37)
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGWidthIcon[5]);
+ else if (nVal <= 52)
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGWidthIcon[6]);
+ else
+ mxTBWidth->set_item_icon_name(SELECTWIDTH, maIMGWidthIcon[7]);
+
+}
+
+void LinePropertyPanelBase::SetWidth(tools::Long nWidth)
+{
+ mnWidthCoreValue = nWidth;
+ mbWidthValuable = true;
+ mxLineWidthPopup->SetWidthSelect(mnWidthCoreValue, mbWidthValuable, meMapUnit);
+}
+
+void LinePropertyPanelBase::ActivateControls()
+{
+ mxGridLineProps->set_sensitive(!mbNoneLineStyle);
+ mxBoxArrowProps->set_sensitive(!mbNoneLineStyle);
+ mxLineStyleTB->set_item_sensitive(".uno:LineEndStyle", !mbNoneLineStyle);
+
+ mxBoxArrowProps->set_visible(mbArrowSupported);
+ mxLineStyleTB->set_item_visible(".uno:LineEndStyle", mbArrowSupported);
+}
+
+void LinePropertyPanelBase::setMapUnit(MapUnit eMapUnit)
+{
+ meMapUnit = eMapUnit;
+ mxLineWidthPopup->SetWidthSelect(mnWidthCoreValue, mbWidthValuable, meMapUnit);
+}
+
+void LinePropertyPanelBase::disableArrowHead()
+{
+ mbArrowSupported = false;
+ ActivateControls();
+}
+
+void LinePropertyPanelBase::enableArrowHead()
+{
+ mbArrowSupported = true;
+ ActivateControls();
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/line/LineWidthPopup.cxx b/svx/source/sidebar/line/LineWidthPopup.cxx
new file mode 100644
index 000000000..347bb2a3b
--- /dev/null
+++ b/svx/source/sidebar/line/LineWidthPopup.cxx
@@ -0,0 +1,223 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <svx/sidebar/LineWidthPopup.hxx>
+#include <svx/sidebar/LinePropertyPanelBase.hxx>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/xlnwtit.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/viewoptions.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include "LineWidthValueSet.hxx"
+#include <bitmaps.hlst>
+
+namespace svx::sidebar
+{
+LineWidthPopup::LineWidthPopup(weld::Widget* pParent, LinePropertyPanelBase& rParent)
+ : WeldToolbarPopup(nullptr, pParent, "svx/ui/floatinglineproperty.ui", "FloatingLineProperty")
+ , m_rParent(rParent)
+ , m_sPt(SvxResId(RID_SVXSTR_PT))
+ , m_eMapUnit(MapUnit::MapTwip)
+ , m_bVSFocus(true)
+ , m_bCustom(false)
+ , m_nCustomWidth(0)
+ , m_aIMGCus(StockImage::Yes, RID_SVXBMP_WIDTH_CUSTOM)
+ , m_aIMGCusGray(StockImage::Yes, RID_SVXBMP_WIDTH_CUSTOM_GRAY)
+ , m_xMFWidth(m_xBuilder->weld_metric_spin_button("spin", FieldUnit::POINT))
+ , m_xVSWidth(new LineWidthValueSet())
+ , m_xVSWidthWin(new weld::CustomWeld(*m_xBuilder, "lineset", *m_xVSWidth))
+{
+ m_xVSWidth->SetStyle(m_xVSWidth->GetStyle() | WB_3DLOOK | WB_NO_DIRECTSELECT);
+
+ maStrUnits[0] = "0.5";
+ maStrUnits[1] = "0.8";
+ maStrUnits[2] = "1.0";
+ maStrUnits[3] = "1.5";
+ maStrUnits[4] = "2.3";
+ maStrUnits[5] = "3.0";
+ maStrUnits[6] = "4.5";
+ maStrUnits[7] = "6.0";
+ maStrUnits[8] = SvxResId(RID_SVXSTR_WIDTH_LAST_CUSTOM);
+
+ const LocaleDataWrapper& rLocaleWrapper(Application::GetSettings().GetLocaleDataWrapper());
+ const sal_Unicode cSep = rLocaleWrapper.getNumDecimalSep()[0];
+
+ for (int i = 0; i <= 7; i++)
+ {
+ maStrUnits[i] = maStrUnits[i].replace('.', cSep); //Modify
+ maStrUnits[i] += " ";
+ maStrUnits[i] += m_sPt;
+ }
+
+ for (sal_uInt16 i = 1; i <= 9; ++i)
+ {
+ m_xVSWidth->InsertItem(i);
+ m_xVSWidth->SetItemText(i, maStrUnits[i - 1]);
+ }
+
+ m_xVSWidth->SetUnit(maStrUnits);
+ m_xVSWidth->SetItemData(1, reinterpret_cast<void*>(5));
+ m_xVSWidth->SetItemData(2, reinterpret_cast<void*>(8));
+ m_xVSWidth->SetItemData(3, reinterpret_cast<void*>(10));
+ m_xVSWidth->SetItemData(4, reinterpret_cast<void*>(15));
+ m_xVSWidth->SetItemData(5, reinterpret_cast<void*>(23));
+ m_xVSWidth->SetItemData(6, reinterpret_cast<void*>(30));
+ m_xVSWidth->SetItemData(7, reinterpret_cast<void*>(45));
+ m_xVSWidth->SetItemData(8, reinterpret_cast<void*>(60));
+ m_xVSWidth->SetImage(m_aIMGCusGray);
+
+ m_xVSWidth->SetSelItem(0);
+
+ m_xVSWidth->SetSelectHdl(LINK(this, LineWidthPopup, VSSelectHdl));
+ m_xMFWidth->connect_value_changed(LINK(this, LineWidthPopup, MFModifyHdl));
+}
+
+LineWidthPopup::~LineWidthPopup() {}
+
+IMPL_LINK_NOARG(LineWidthPopup, VSSelectHdl, ValueSet*, void)
+{
+ sal_uInt16 iPos = m_xVSWidth->GetSelectedItemId();
+ if (iPos >= 1 && iPos <= 8)
+ {
+ sal_IntPtr nVal = OutputDevice::LogicToLogic(
+ reinterpret_cast<sal_IntPtr>(m_xVSWidth->GetItemData(iPos)), MapUnit::MapPoint,
+ m_eMapUnit);
+ nVal = m_xMFWidth->denormalize(nVal);
+ XLineWidthItem aWidthItem(nVal);
+ m_rParent.setLineWidth(aWidthItem);
+ m_rParent.SetWidthIcon(iPos);
+ m_rParent.SetWidth(nVal);
+ }
+ else if (iPos == 9)
+ { //last custom
+ //modified
+ if (m_bCustom)
+ {
+ tools::Long nVal
+ = OutputDevice::LogicToLogic(m_nCustomWidth, MapUnit::MapPoint, m_eMapUnit);
+ nVal = m_xMFWidth->denormalize(nVal);
+ XLineWidthItem aWidthItem(nVal);
+ m_rParent.setLineWidth(aWidthItem);
+ m_rParent.SetWidth(nVal);
+ }
+ else
+ {
+ m_xVSWidth->SetNoSelection(); //add , set no selection and keep the last select item
+ m_xVSWidth->SetFormat();
+ m_xVSWidth->Invalidate();
+ }
+ //modify end
+ }
+
+ if ((iPos >= 1 && iPos <= 8) || (iPos == 9 && m_bCustom)) //add
+ {
+ m_rParent.EndLineWidthPopup();
+ }
+}
+
+IMPL_LINK_NOARG(LineWidthPopup, MFModifyHdl, weld::MetricSpinButton&, void)
+{
+ if (m_xVSWidth->GetSelItem())
+ {
+ m_xVSWidth->SetSelItem(0);
+ m_xVSWidth->SetFormat();
+ m_xVSWidth->Invalidate();
+ }
+ tools::Long nTmp = static_cast<tools::Long>(m_xMFWidth->get_value(FieldUnit::NONE));
+ tools::Long nVal = OutputDevice::LogicToLogic(nTmp, MapUnit::MapPoint, m_eMapUnit);
+ sal_Int32 nNewWidth = static_cast<short>(m_xMFWidth->denormalize(nVal));
+ XLineWidthItem aWidthItem(nNewWidth);
+ m_rParent.setLineWidth(aWidthItem);
+}
+
+void LineWidthPopup::SetWidthSelect(tools::Long lValue, bool bValuable, MapUnit eMapUnit)
+{
+ m_bVSFocus = true;
+ m_xVSWidth->SetSelItem(0);
+ m_eMapUnit = eMapUnit;
+ SvtViewOptions aWinOpt(EViewType::Window, "PopupPanel_LineWidth");
+ if (aWinOpt.Exists())
+ {
+ css::uno::Sequence<css::beans::NamedValue> aSeq = aWinOpt.GetUserData();
+ OUString aTmp;
+ if (aSeq.hasElements())
+ aSeq[0].Value >>= aTmp;
+
+ OUString aWinData(aTmp);
+ m_nCustomWidth = aWinData.toInt32();
+ m_bCustom = true;
+ m_xVSWidth->SetImage(m_aIMGCus);
+ m_xVSWidth->SetCusEnable(true);
+
+ OUString aStrTip = OUString::number(static_cast<double>(m_nCustomWidth) / 10) + m_sPt;
+ m_xVSWidth->SetItemText(9, aStrTip);
+ }
+ else
+ {
+ m_bCustom = false;
+ m_xVSWidth->SetImage(m_aIMGCusGray);
+ m_xVSWidth->SetCusEnable(false);
+ m_xVSWidth->SetItemText(9, maStrUnits[8]);
+ }
+
+ if (bValuable)
+ {
+ sal_Int64 nVal = OutputDevice::LogicToLogic(lValue, eMapUnit, MapUnit::Map100thMM);
+ nVal = m_xMFWidth->normalize(nVal);
+ m_xMFWidth->set_value(nVal, FieldUnit::MM_100TH);
+ }
+ else
+ {
+ m_xMFWidth->set_text("");
+ }
+
+ OUString strCurrValue = m_xMFWidth->get_text();
+ sal_uInt16 i = 0;
+ for (; i < 8; i++)
+ {
+ if (strCurrValue == maStrUnits[i])
+ {
+ m_xVSWidth->SetSelItem(i + 1);
+ break;
+ }
+ }
+
+ if (i >= 8)
+ {
+ m_bVSFocus = false;
+ m_xVSWidth->SetSelItem(0);
+ }
+
+ m_xVSWidth->SetFormat();
+ m_xVSWidth->Invalidate();
+}
+
+void LineWidthPopup::GrabFocus()
+{
+ if (m_bVSFocus)
+ m_xVSWidth->GrabFocus();
+ else
+ m_xMFWidth->grab_focus();
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/line/LineWidthValueSet.cxx b/svx/source/sidebar/line/LineWidthValueSet.cxx
new file mode 100644
index 000000000..be518fe4f
--- /dev/null
+++ b/svx/source/sidebar/line/LineWidthValueSet.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "LineWidthValueSet.hxx"
+
+#include <i18nlangtag/mslangid.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+namespace svx::sidebar {
+
+LineWidthValueSet::LineWidthValueSet()
+ : ValueSet(nullptr)
+ , nSelItem(0)
+ , bCusEnable(false)
+{
+}
+
+void LineWidthValueSet::Resize()
+{
+ SetColCount();
+ SetLineCount(9);
+ ValueSet::Resize();
+}
+
+LineWidthValueSet::~LineWidthValueSet()
+{
+}
+
+void LineWidthValueSet::SetUnit(std::array<OUString,9> const & strUnits)
+{
+ maStrUnits = strUnits;
+}
+
+void LineWidthValueSet::SetSelItem(sal_uInt16 nSel)
+{
+ nSelItem = nSel;
+ if(nSel == 0)
+ {
+ SelectItem(1); // ,false); // 'false' nut supported by AOO
+ SetNoSelection();
+ }
+ else
+ {
+ SelectItem(nSelItem);
+ GrabFocus();
+ }
+}
+
+void LineWidthValueSet::SetImage(const Image& img)
+{
+ imgCus = img;
+}
+
+void LineWidthValueSet::SetCusEnable(bool bEnable)
+{
+ bCusEnable = bEnable;
+}
+
+void LineWidthValueSet::UserDraw( const UserDrawEvent& rUDEvt )
+{
+ tools::Rectangle aRect = rUDEvt.GetRect();
+ vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
+ sal_uInt16 nItemId = rUDEvt.GetItemId();
+
+ tools::Long nRectHeight = aRect.GetHeight();
+ tools::Long nRectWidth = aRect.GetWidth();
+ Point aBLPos = aRect.TopLeft();
+
+ //const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ //Color aBackColor(0,0,200);
+ //const Color aTextColor = rStyleSettings.GetFieldTextColor();
+ vcl::Font aOldFont = pDev->GetFont();
+ Color aOldColor = pDev->GetLineColor();
+ Color aOldFillColor = pDev->GetFillColor();
+
+ vcl::Font aFont(OutputDevice::GetDefaultFont(DefaultFontType::UI_SANS, MsLangId::getConfiguredSystemLanguage(), GetDefaultFontFlags::OnlyOne));
+ Size aSize = aFont.GetFontSize();
+ aSize.setHeight( nRectHeight*3/5 );
+ aFont.SetFontSize( aSize );
+
+ Point aLineStart(aBLPos.X() + 5, aBLPos.Y() + ( nRectHeight - nItemId )/2);
+ Point aLineEnd(aBLPos.X() + nRectWidth * 7 / 9 - 10, aBLPos.Y() + ( nRectHeight - nItemId )/2);
+ if (nItemId == 9)
+ {
+ Point aImgStart(aBLPos.X() + 5, aBLPos.Y() + ( nRectHeight - 23 ) / 2);
+ pDev->DrawImage(aImgStart, imgCus);
+
+ tools::Rectangle aStrRect = aRect;
+ aStrRect.AdjustTop(nRectHeight/6 );
+ aStrRect.AdjustBottom( -(nRectHeight/6) );
+ aStrRect.AdjustLeft(imgCus.GetSizePixel().Width() + 20 );
+ if(bCusEnable)
+ aFont.SetColor(Application::GetSettings().GetStyleSettings().GetFieldTextColor());
+ else
+ aFont.SetColor(Application::GetSettings().GetStyleSettings().GetDisableColor());
+
+ pDev->SetFont(aFont);
+ pDev->DrawText(aStrRect, maStrUnits[ nItemId - 1 ], DrawTextFlags::EndEllipsis);
+ }
+ else
+ {
+ if( nSelItem == nItemId )
+ {
+ tools::Rectangle aBackRect = aRect;
+ aBackRect.AdjustTop(3 );
+ aBackRect.AdjustBottom( -2 );
+ pDev->SetFillColor(Color(50,107,197));
+ pDev->DrawRect(aBackRect);
+ }
+ else
+ {
+ pDev->SetFillColor( COL_TRANSPARENT );
+ pDev->DrawRect(aRect);
+ }
+
+ //draw text
+ if(nSelItem == nItemId )
+ aFont.SetColor(COL_WHITE);
+ else
+ aFont.SetColor(Application::GetSettings().GetStyleSettings().GetFieldTextColor());
+ pDev->SetFont(aFont);
+ Point aStart(aBLPos.X() + nRectWidth * 7 / 9 , aBLPos.Y() + nRectHeight/6);
+ pDev->DrawText(aStart, maStrUnits[ nItemId - 1 ]); //can't set DrawTextFlags::EndEllipsis here ,or the text will disappear
+
+ //draw line
+ if( nSelItem == nItemId )
+ pDev->SetLineColor(COL_WHITE);
+ else
+ pDev->SetLineColor(Application::GetSettings().GetStyleSettings().GetFieldTextColor());
+
+ for(sal_uInt16 i = 1; i <= nItemId; i++)
+ {
+ pDev->DrawLine(aLineStart,aLineEnd );
+ aLineStart.setY(aLineStart.getY() + 1);
+ aLineEnd.setY (aLineEnd.getY() + 1);
+ }
+ }
+
+ Invalidate( aRect );
+ pDev->SetLineColor(aOldColor);
+ pDev->SetFillColor(aOldFillColor);
+ pDev->SetFont(aOldFont);
+}
+
+void LineWidthValueSet::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ValueSet::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(80, 12 * 9), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/line/LineWidthValueSet.hxx b/svx/source/sidebar/line/LineWidthValueSet.hxx
new file mode 100644
index 000000000..225e706a6
--- /dev/null
+++ b/svx/source/sidebar/line/LineWidthValueSet.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_LINE_LINEWIDTHVALUESET_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_LINE_LINEWIDTHVALUESET_HXX
+
+#include <svtools/valueset.hxx>
+#include <vcl/image.hxx>
+#include <array>
+
+namespace svx::sidebar {
+
+class LineWidthValueSet final : public ValueSet
+{
+public:
+ explicit LineWidthValueSet();
+ virtual ~LineWidthValueSet() override;
+
+ void SetUnit(std::array<OUString,9> const & strUnits);
+ void SetSelItem(sal_uInt16 nSel);
+ sal_uInt16 GetSelItem() const { return nSelItem;}
+ void SetImage(const Image& img);
+ void SetCusEnable(bool bEnable);
+
+ virtual void UserDraw( const UserDrawEvent& rUDEvt ) override;
+ virtual void Resize() override;
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+private:
+ sal_uInt16 nSelItem;
+ std::array<OUString,9> maStrUnits;
+ Image imgCus;
+ bool bCusEnable;
+};
+
+} // end of namespace svx::sidebar
+
+#endif // INCLUDED_SVX_SOURCE_SIDEBAR_LINE_LINEWIDTHVALUESET_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/lists/ListsPropertyPanel.cxx b/svx/source/sidebar/lists/ListsPropertyPanel.cxx
new file mode 100644
index 000000000..58badf679
--- /dev/null
+++ b/svx/source/sidebar/lists/ListsPropertyPanel.cxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "ListsPropertyPanel.hxx"
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+using namespace css;
+using namespace css::uno;
+
+namespace svx::sidebar
+{
+std::unique_ptr<PanelLayout>
+ListsPropertyPanel::Create(weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to ListsPropertyPanel::Create",
+ nullptr, 0);
+ if (!rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to ListsPropertyPanel::Create",
+ nullptr, 1);
+
+ return std::make_unique<ListsPropertyPanel>(pParent, rxFrame);
+}
+
+ListsPropertyPanel::ListsPropertyPanel(weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame)
+ : PanelLayout(pParent, "ListsPropertyPanel", "svx/ui/sidebarlists.ui")
+ , mxTBxNumBullet(m_xBuilder->weld_toolbar("numberbullet"))
+ , mxNumBulletDispatcher(new ToolbarUnoDispatcher(*mxTBxNumBullet, *m_xBuilder, rxFrame))
+ , mxTBxOutline(m_xBuilder->weld_toolbar("outline"))
+ , mxOutlineDispatcher(new ToolbarUnoDispatcher(*mxTBxOutline, *m_xBuilder, rxFrame))
+{
+}
+
+ListsPropertyPanel::~ListsPropertyPanel()
+{
+ mxOutlineDispatcher.reset();
+ mxTBxOutline.reset();
+ mxNumBulletDispatcher.reset();
+ mxTBxNumBullet.reset();
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/lists/ListsPropertyPanel.hxx b/svx/source/sidebar/lists/ListsPropertyPanel.hxx
new file mode 100644
index 000000000..ec20bb430
--- /dev/null
+++ b/svx/source/sidebar/lists/ListsPropertyPanel.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_LISTS_LISTSPROPERTYPANEL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_LISTS_LISTSPROPERTYPANEL_HXX
+
+#include <sfx2/weldutils.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <com/sun/star/frame/XFrame.hpp>
+
+namespace svx::sidebar
+{
+class ListsPropertyPanel : public PanelLayout
+{
+public:
+ virtual ~ListsPropertyPanel() override;
+
+ static std::unique_ptr<PanelLayout>
+ Create(weld::Widget* pParent, const css::uno::Reference<css::frame::XFrame>& rxFrame);
+
+ ListsPropertyPanel(weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame);
+
+private:
+ std::unique_ptr<weld::Toolbar> mxTBxNumBullet;
+ std::unique_ptr<ToolbarUnoDispatcher> mxNumBulletDispatcher;
+ std::unique_ptr<weld::Toolbar> mxTBxOutline;
+ std::unique_ptr<ToolbarUnoDispatcher> mxOutlineDispatcher;
+};
+
+} // end of namespace svx::sidebar
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/media/MediaPlaybackPanel.cxx b/svx/source/sidebar/media/MediaPlaybackPanel.cxx
new file mode 100644
index 000000000..b23c612ff
--- /dev/null
+++ b/svx/source/sidebar/media/MediaPlaybackPanel.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "MediaPlaybackPanel.hxx"
+#include <avmedia/mediaitem.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/dispatch.hxx>
+#include <avmedia/MediaControlBase.hxx>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+using namespace avmedia;
+
+namespace svx::sidebar {
+
+MediaPlaybackPanel::MediaPlaybackPanel (
+ weld::Widget* pParent,
+ SfxBindings* pBindings)
+ : PanelLayout(pParent, "MediaPlaybackPanel", "svx/ui/mediaplayback.ui"),
+ maMediaController(SID_AVMEDIA_TOOLBOX, *pBindings, *this),
+ maIdle("MediaPlaybackPanel"),
+ mpBindings(pBindings)
+{
+ mxTimeEdit = m_xBuilder->weld_entry("timeedit");
+ mxPlayToolBox = m_xBuilder->weld_toolbar("playtoolbox");
+ mxMuteToolBox = m_xBuilder->weld_toolbar("mutetoolbox");
+ mxTimeSlider = m_xBuilder->weld_scale("timeslider");
+ mxVolumeSlider = m_xBuilder->weld_scale("volumeslider");
+ mxZoomListBox = m_xBuilder->weld_combo_box("zoombox");
+
+ Initialize();
+}
+
+std::unique_ptr<PanelLayout> MediaPlaybackPanel::Create(
+ weld::Widget* pParent,
+ SfxBindings* pBindings)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to MediaPlaybackPanel::Create", nullptr, 0);
+ if (pBindings == nullptr)
+ throw lang::IllegalArgumentException("no SfxBindings given to MediaPlaybackPanel::Create", nullptr, 2);
+
+ return std::make_unique<MediaPlaybackPanel>(pParent, pBindings);
+}
+
+void MediaPlaybackPanel::Initialize()
+{
+ InitializeWidgets();
+ mxVolumeSlider->connect_value_changed(LINK(this, MediaPlaybackPanel, VolumeSlideHdl));
+ mxPlayToolBox->connect_clicked(LINK(this, MediaPlaybackPanel, PlayToolBoxSelectHdl));
+ mxMuteToolBox->connect_clicked(LINK(this, MediaPlaybackPanel, PlayToolBoxSelectHdl));
+ mxTimeSlider->connect_value_changed(LINK(this, MediaPlaybackPanel, SeekHdl));
+
+ maIdle.SetPriority( TaskPriority::HIGHEST );
+ maIdle.SetInvokeHandler( LINK( this, MediaPlaybackPanel, TimeoutHdl ) );
+ maIdle.Start();
+ mpBindings->Invalidate(SID_AVMEDIA_TOOLBOX);
+}
+
+MediaPlaybackPanel::~MediaPlaybackPanel()
+{
+ disposeWidgets();
+}
+
+void MediaPlaybackPanel::NotifyItemUpdate(
+ const sal_uInt16 nSID,
+ const SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ if( nSID == SID_AVMEDIA_TOOLBOX )
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ mpMediaItem.reset(pState ? static_cast< MediaItem* >(pState->Clone()) : nullptr);
+ Update();
+ }
+ }
+}
+
+void MediaPlaybackPanel::UpdateToolBoxes(const MediaItem& rMediaItem)
+{
+ mxPlayToolBox->set_sensitive(false);
+ avmedia::MediaControlBase::UpdateToolBoxes(rMediaItem);
+}
+
+void MediaPlaybackPanel::Update()
+{
+ if (mpMediaItem)
+ {
+ UpdateToolBoxes( *mpMediaItem );
+ UpdateTimeSlider( *mpMediaItem );
+ UpdateVolumeSlider( *mpMediaItem );
+ UpdateTimeField( *mpMediaItem, mpMediaItem->getTime() );
+ }
+}
+
+IMPL_LINK_NOARG( MediaPlaybackPanel, VolumeSlideHdl, weld::Scale&, void)
+{
+ MediaItem aItem(SID_AVMEDIA_TOOLBOX);
+ aItem.setVolumeDB(mxVolumeSlider->get_value());
+ mpBindings->GetDispatcher()->ExecuteList(SID_AVMEDIA_TOOLBOX, SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK_NOARG( MediaPlaybackPanel, SeekHdl, weld::Scale&, void)
+{
+ MediaItem aItem(SID_AVMEDIA_TOOLBOX);
+ double nTime = 0;
+ if (mpMediaItem)
+ nTime = mxTimeSlider->get_value() * mpMediaItem->getDuration() / AVMEDIA_TIME_RANGE;
+ aItem.setTime(nTime);
+ mpBindings->GetDispatcher()->ExecuteList(SID_AVMEDIA_TOOLBOX, SfxCallMode::RECORD, { &aItem });
+ mpBindings->Invalidate(SID_AVMEDIA_TOOLBOX);
+}
+
+IMPL_LINK_NOARG( MediaPlaybackPanel, TimeoutHdl, Timer*, void)
+{
+ mpBindings->Invalidate(SID_AVMEDIA_TOOLBOX);
+}
+
+IMPL_LINK( MediaPlaybackPanel, PlayToolBoxSelectHdl, const OString&, rId, void)
+{
+ MediaItem aItem(SID_AVMEDIA_TOOLBOX);
+
+ if (rId == "play")
+ {
+ aItem.setState( MediaState::Play );
+
+ if( !mpMediaItem || (mpMediaItem->getTime() == mpMediaItem->getDuration() ))
+ aItem.setTime( 0.0 );
+ else
+ aItem.setTime( mpMediaItem->getTime());
+ }
+ else if (rId == "pause")
+ {
+ aItem.setState( MediaState::Pause );
+ }
+ else if (rId == "stop")
+ {
+ aItem.setState( MediaState::Stop );
+ aItem.setTime( 0.0 );
+ }
+ else if (rId == "mute")
+ {
+ aItem.setMute( mxMuteToolBox->get_item_active("mute") );
+ }
+ else if (rId == "loop")
+ {
+ aItem.setLoop( mxPlayToolBox->get_item_active("loop") );
+ }
+
+ if(aItem.getMaskSet() != AVMediaSetMask::NONE)
+ {
+ mpBindings->GetDispatcher()->ExecuteList(SID_AVMEDIA_TOOLBOX, SfxCallMode::RECORD, { &aItem } );
+ mpBindings->Invalidate(SID_AVMEDIA_TOOLBOX);
+ }
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/media/MediaPlaybackPanel.hxx b/svx/source/sidebar/media/MediaPlaybackPanel.hxx
new file mode 100644
index 000000000..95f3d6eaa
--- /dev/null
+++ b/svx/source/sidebar/media/MediaPlaybackPanel.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <memory>
+
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <avmedia/mediaitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <avmedia/MediaControlBase.hxx>
+#include <vcl/idle.hxx>
+
+using namespace css;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+
+namespace svx::sidebar {
+
+/** This panel provides media playback control in document
+*/
+class MediaPlaybackPanel
+ : public PanelLayout,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface,
+ public ::avmedia::MediaControlBase
+{
+public:
+ MediaPlaybackPanel (
+ weld::Widget* pParent,
+ SfxBindings* pBindings);
+ static std::unique_ptr<PanelLayout> Create(
+ weld::Widget* pParent,
+ SfxBindings* pBindings);
+ virtual ~MediaPlaybackPanel() override;
+
+protected:
+ virtual void UpdateToolBoxes(const avmedia::MediaItem& rMediaItem) override;
+
+private:
+ std::unique_ptr< ::avmedia::MediaItem > mpMediaItem;
+ ::sfx2::sidebar::ControllerItem maMediaController;
+ Idle maIdle;
+ SfxBindings* mpBindings;
+ void Initialize();
+ void Update();
+ virtual void NotifyItemUpdate( const sal_uInt16 nSID,
+ const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(
+ const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override {};
+
+ DECL_LINK(PlayToolBoxSelectHdl, const OString&, void);
+ DECL_LINK(VolumeSlideHdl, weld::Scale&, void);
+ DECL_LINK(SeekHdl, weld::Scale&, void);
+
+ DECL_LINK(TimeoutHdl, Timer*, void);
+};
+
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/nbdtmg.cxx b/svx/source/sidebar/nbdtmg.cxx
new file mode 100644
index 000000000..241b91673
--- /dev/null
+++ b/svx/source/sidebar/nbdtmg.cxx
@@ -0,0 +1,905 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <svx/nbdtmg.hxx>
+#include <svx/svxids.hrc>
+#include <vcl/svapp.hxx>
+#include <svl/itemset.hxx>
+#include <sfx2/request.hxx>
+#include <svl/stritem.hxx>
+#include <svtools/ctrltool.hxx>
+#include <sfx2/objsh.hxx>
+#include <editeng/flstitem.hxx>
+#include <svl/itempool.hxx>
+#include <vcl/outdev.hxx>
+#include <editeng/brushitem.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <vcl/graph.hxx>
+#include <vcl/settings.hxx>
+
+#include <i18nlangtag/languagetag.hxx>
+#include <o3tl/temporary.hxx>
+#include <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/pathoptions.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/text/DefaultNumberingProvider.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <comphelper/processfactory.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::text;
+using namespace com::sun::star::container;
+using namespace com::sun::star::style;
+
+namespace svx::sidebar {
+
+namespace {
+
+const vcl::Font& lcl_GetDefaultBulletFont()
+{
+ static vcl::Font aDefBulletFont = []()
+ {
+ static vcl::Font tmp("OpenSymbol", "", Size(0, 14));
+ tmp.SetCharSet( RTL_TEXTENCODING_SYMBOL );
+ tmp.SetFamily( FAMILY_DONTKNOW );
+ tmp.SetPitch( PITCH_DONTKNOW );
+ tmp.SetWeight( WEIGHT_DONTKNOW );
+ tmp.SetTransparent( true );
+ return tmp;
+ }();
+ return aDefBulletFont;
+}
+
+const sal_Unicode aDefaultBulletTypes[] =
+{
+ 0x2022,
+ 0x25cf,
+ 0xe00c,
+ 0xe00a,
+ 0x2794,
+ 0x27a2,
+ 0x2717,
+ 0x2714
+};
+
+NumSettings_Impl* lcl_CreateNumberingSettingsPtr(const Sequence<PropertyValue>& rLevelProps)
+{
+ NumSettings_Impl* pNew = new NumSettings_Impl;
+ for(const PropertyValue& rValue : rLevelProps)
+ {
+ if(rValue.Name == "NumberingType")
+ {
+ sal_Int16 nTmp;
+ if (rValue.Value >>= nTmp)
+ pNew->nNumberType = static_cast<SvxNumType>(nTmp);
+ }
+ else if(rValue.Name == "Prefix")
+ rValue.Value >>= pNew->sPrefix;
+ else if(rValue.Name == "Suffix")
+ rValue.Value >>= pNew->sSuffix;
+ else if(rValue.Name == "ParentNumbering")
+ rValue.Value >>= pNew->nParentNumbering;
+ else if(rValue.Name == "BulletChar")
+ rValue.Value >>= pNew->sBulletChar;
+ else if(rValue.Name == "BulletFontName")
+ rValue.Value >>= pNew->sBulletFont;
+ }
+ const sal_Unicode cLocalPrefix = pNew->sPrefix.getLength() ? pNew->sPrefix[0] : 0;
+ const sal_Unicode cLocalSuffix = pNew->sSuffix.getLength() ? pNew->sSuffix[0] : 0;
+ if( cLocalPrefix == ' ') pNew->sPrefix.clear();
+ if( cLocalSuffix == ' ') pNew->sSuffix.clear();
+ return pNew;
+}
+
+}
+
+sal_uInt16 NBOTypeMgrBase:: IsSingleLevel(sal_uInt16 nCurLevel)
+{
+ sal_uInt16 nLv = sal_uInt16(0xFFFF);
+ sal_uInt16 nCount = 0;
+ sal_uInt16 nMask = 1;
+ for( sal_uInt16 i = 0; i < SVX_MAX_NUM; i++ )
+ {
+ if(nCurLevel & nMask)
+ {
+ nCount++;
+ nLv=i;
+ }
+ nMask <<= 1 ;
+ }
+
+ if ( nCount == 1)
+ return nLv;
+ else
+ return sal_uInt16(0xFFFF);
+}
+
+void NBOTypeMgrBase::SetItems(const SfxItemSet* pArg) {
+ pSet = pArg;
+ if ( !pSet )
+ return;
+
+ SfxAllItemSet aSet(*pSet);
+
+ const SfxStringItem* pBulletCharFmt = aSet.GetItem<SfxStringItem>(SID_BULLET_CHAR_FMT, false);
+ if (pBulletCharFmt)
+ aBulletCharFmtName = pBulletCharFmt->GetValue();
+
+ const SfxStringItem* pNumCharFmt = aSet.GetItem<SfxStringItem>(SID_NUM_CHAR_FMT, false);
+ if (pNumCharFmt)
+ aNumCharFmtName = pNumCharFmt->GetValue();
+
+ const SfxPoolItem* pItem;
+ SfxItemState eState = pSet->GetItemState(SID_ATTR_NUMBERING_RULE, false, &pItem);
+ if(eState == SfxItemState::SET)
+ {
+ eCoreUnit = pSet->GetPool()->GetMetric(pSet->GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE));
+ } else {
+ //sd use different sid for numbering rule
+ eState = pSet->GetItemState(EE_PARA_NUMBULLET, false, &pItem);
+ if(eState == SfxItemState::SET)
+ {
+ eCoreUnit = pSet->GetPool()->GetMetric(pSet->GetPool()->GetWhich(EE_PARA_NUMBULLET));
+ }
+ }
+}
+
+void NBOTypeMgrBase::ImplLoad(std::u16string_view filename)
+{
+ bIsLoading = true;
+ MapUnit eOldCoreUnit=eCoreUnit;
+ eCoreUnit = MapUnit::Map100thMM;
+ INetURLObject aFile( SvtPathOptions().GetUserConfigPath() );
+ aFile.Append( filename);
+ std::unique_ptr<SvStream> xIStm(::utl::UcbStreamHelper::CreateStream( aFile.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));
+ if( xIStm ) {
+ sal_uInt32 nVersion = 0;
+ sal_Int32 nNumIndex = 0;
+ xIStm->ReadUInt32( nVersion );
+ if (nVersion==DEFAULT_NUMBERING_CACHE_FORMAT_VERSION) //first version
+ {
+ xIStm->ReadInt32( nNumIndex );
+ while (nNumIndex>=0 && nNumIndex<DEFAULT_NUM_VALUSET_COUNT) {
+ SvxNumRule aNum(*xIStm);
+ //bullet color in font properties is not stored correctly. Need set transparency bits manually
+ for(sal_uInt16 i = 0; i < aNum.GetLevelCount(); i++)
+ {
+ SvxNumberFormat aFmt(aNum.GetLevel(i));
+ if (aFmt.GetBulletFont()) {
+ vcl::Font aFont(*aFmt.GetBulletFont());
+ Color c=aFont.GetColor();
+ c.SetAlpha(0);
+ aFont.SetColor(c);
+ aFmt.SetBulletFont(&aFont);
+ aNum.SetLevel(i, aFmt);
+ }
+ }
+ RelplaceNumRule(aNum,nNumIndex,0x1/*nLevel*/);
+ xIStm->ReadInt32( nNumIndex );
+ }
+ }
+ }
+ eCoreUnit = eOldCoreUnit;
+ bIsLoading = false;
+}
+void NBOTypeMgrBase::ImplStore(std::u16string_view filename)
+{
+ if (bIsLoading) return;
+ MapUnit eOldCoreUnit=eCoreUnit;
+ eCoreUnit = MapUnit::Map100thMM;
+ INetURLObject aFile( SvtPathOptions().GetUserConfigPath() );
+ aFile.Append( filename);
+ std::unique_ptr<SvStream> xOStm(::utl::UcbStreamHelper::CreateStream( aFile.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE ));
+ if( xOStm ) {
+ sal_uInt32 nVersion;
+ sal_Int32 nNumIndex;
+ nVersion = DEFAULT_NUMBERING_CACHE_FORMAT_VERSION;
+ xOStm->WriteUInt32( nVersion );
+ for(sal_Int32 nItem = 0; nItem < DEFAULT_NUM_VALUSET_COUNT; nItem++ ) {
+ if (IsCustomized(nItem)) {
+ SvxNumRule aDefNumRule( SvxNumRuleFlags::BULLET_REL_SIZE | SvxNumRuleFlags::CONTINUOUS | SvxNumRuleFlags::BULLET_COLOR,
+ 10, false,
+ SvxNumRuleType::NUMBERING, SvxNumberFormat::LABEL_ALIGNMENT);
+ xOStm->WriteInt32( nItem );
+ ApplyNumRule(aDefNumRule,nItem,0x1/*nLevel*/,false,true);
+ aDefNumRule.Store(*xOStm);
+ }
+ }
+ nNumIndex = -1;
+ xOStm->WriteInt32( nNumIndex ); //write end flag
+ }
+ eCoreUnit = eOldCoreUnit;
+}
+
+// Character Bullet Type lib
+BulletsSettings* BulletsTypeMgr::pActualBullets[] ={nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr};
+sal_Unicode BulletsTypeMgr::aDynamicBulletTypes[]={' ',' ',' ',' ',' ',' ',' ',' '};
+sal_Unicode BulletsTypeMgr::aDynamicRTLBulletTypes[]={' ',' ',' ',' ',' ',' ',' ',' '};
+
+BulletsTypeMgr::BulletsTypeMgr()
+{
+ Init();
+}
+
+BulletsTypeMgr& BulletsTypeMgr::GetInstance()
+{
+ static BulletsTypeMgr theBulletsTypeMgr;
+ return theBulletsTypeMgr;
+}
+
+void BulletsTypeMgr::Init()
+{
+ const vcl::Font& rActBulletFont = lcl_GetDefaultBulletFont();
+
+ for (sal_uInt16 i=0;i<DEFAULT_BULLET_TYPES;i++)
+ {
+ pActualBullets[i] = new BulletsSettings;
+ pActualBullets[i]->cBulletChar = aDefaultBulletTypes[i];
+ pActualBullets[i]->aFont = rActBulletFont;
+ OString id = OString::Concat(RID_SVXSTR_BULLET_DESCRIPTION_0.mpId) + OString::number(i);
+ pActualBullets[i]->sDescription = SvxResId( TranslateId(RID_SVXSTR_BULLET_DESCRIPTION_0.mpContext, id.getStr()) );
+ }
+}
+sal_uInt16 BulletsTypeMgr::GetNBOIndexForNumRule(SvxNumRule& aNum,sal_uInt16 mLevel,sal_uInt16 nFromIndex)
+{
+ if ( mLevel == sal_uInt16(0xFFFF) || mLevel == 0)
+ return sal_uInt16(0xFFFF);
+ //if ( !lcl_IsNumFmtSet(pNR, mLevel) ) return (sal_uInt16)0xFFFF;
+
+ sal_uInt16 nActLv = IsSingleLevel(mLevel);
+
+ if ( nActLv == sal_uInt16(0xFFFF) )
+ return sal_uInt16(0xFFFF);
+
+ const SvxNumberFormat& aFmt(aNum.GetLevel(nActLv));
+ sal_UCS4 cChar = aFmt.GetBulletChar();
+ for(sal_uInt16 i = nFromIndex; i < DEFAULT_BULLET_TYPES; i++)
+ {
+ if ( (cChar == pActualBullets[i]->cBulletChar) ||
+ (cChar == 9830 && 57356 == pActualBullets[i]->cBulletChar) ||
+ (cChar == 9632 && 57354 == pActualBullets[i]->cBulletChar) )
+ {
+ return i+1;
+ }
+ }
+
+ return sal_uInt16(0xFFFF);
+}
+
+void BulletsTypeMgr::RelplaceNumRule(SvxNumRule& aNum, sal_uInt16 nIndex, sal_uInt16 mLevel)
+{
+ if ( mLevel == sal_uInt16(0xFFFF) || mLevel == 0)
+ return;
+
+ if ( GetNBOIndexForNumRule(aNum,mLevel) != sal_uInt16(0xFFFF) )
+ return;
+
+ sal_uInt16 nActLv = IsSingleLevel(mLevel);
+
+ if ( nActLv == sal_uInt16(0xFFFF) )
+ return;
+
+ SvxNumberFormat aFmt(aNum.GetLevel(nActLv));
+ sal_UCS4 cChar = aFmt.GetBulletChar();
+ std::optional<vcl::Font> pFont = aFmt.GetBulletFont();
+ if ( nIndex >= DEFAULT_BULLET_TYPES )
+ return;
+
+ pActualBullets[nIndex]->cBulletChar = cChar;
+ if ( pFont )
+ pActualBullets[nIndex]->aFont = *pFont;
+ pActualBullets[nIndex]->bIsCustomized = true;
+}
+
+void BulletsTypeMgr::ApplyNumRule(SvxNumRule& aNum, sal_uInt16 nIndex, sal_uInt16 mLevel, bool /*isDefault*/, bool isResetSize)
+{
+ if ( nIndex >= DEFAULT_BULLET_TYPES )
+ return;
+ sal_UCS4 cChar = pActualBullets[nIndex]->cBulletChar;
+ const vcl::Font& rActBulletFont = pActualBullets[nIndex]->aFont;
+
+ sal_uInt16 nMask = 1;
+ OUString sBulletCharFormatName = GetBulletCharFmtName();
+ for(sal_uInt16 i = 0; i < aNum.GetLevelCount(); i++)
+ {
+ if(mLevel & nMask)
+ {
+ SvxNumberFormat aFmt(aNum.GetLevel(i));
+ aFmt.SetNumberingType( SVX_NUM_CHAR_SPECIAL );
+ aFmt.SetBulletFont(&rActBulletFont);
+ aFmt.SetBulletChar(cChar);
+ aFmt.SetCharFormatName(sBulletCharFormatName);
+ aFmt.SetListFormat( "" );
+ if (isResetSize) aFmt.SetBulletRelSize(45);
+ aNum.SetLevel(i, aFmt);
+ }
+ nMask <<= 1;
+ }
+}
+
+OUString BulletsTypeMgr::GetDescription(sal_uInt16 nIndex, bool /*isDefault*/)
+{
+ OUString sRet;
+
+ if ( nIndex >= DEFAULT_BULLET_TYPES )
+ return sRet;
+ else
+ sRet = pActualBullets[nIndex]->sDescription;
+
+ return sRet;
+}
+
+bool BulletsTypeMgr::IsCustomized(sal_uInt16 nIndex)
+{
+ bool bRet = false;
+
+ if ( nIndex >= DEFAULT_BULLET_TYPES )
+ bRet = false;
+ else
+ bRet = pActualBullets[nIndex]->bIsCustomized;
+
+ return bRet;
+}
+
+// Numbering Type lib
+NumberingTypeMgr::NumberingTypeMgr()
+{
+ Init();
+ maDefaultNumberSettingsArr = maNumberSettingsArr;
+ ImplLoad(u"standard.syb");
+}
+
+NumberingTypeMgr::~NumberingTypeMgr()
+{
+}
+
+const TranslateId RID_SVXSTR_SINGLENUM_DESCRIPTIONS[] =
+{
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_0,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_1,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_2,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_3,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_4,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_5,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_6,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_7
+};
+
+NumberingTypeMgr& NumberingTypeMgr::GetInstance()
+{
+ static NumberingTypeMgr theNumberingTypeMgr;
+ return theNumberingTypeMgr;
+}
+
+void NumberingTypeMgr::Init()
+{
+ Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ Reference<XDefaultNumberingProvider> xDefNum = DefaultNumberingProvider::create( xContext );
+
+ Sequence< Sequence< PropertyValue > > aNumberings;
+ Locale aLocale(Application::GetSettings().GetLanguageTag().getLocale());
+ try
+ {
+ aNumberings = xDefNum->getDefaultContinuousNumberingLevels( aLocale );
+
+ sal_Int32 nLength = aNumberings.getLength();
+
+ const Sequence<PropertyValue>* pValuesArr = aNumberings.getConstArray();
+ for(sal_Int32 i = 0; i < nLength; i++)
+ {
+ NumSettings_Impl* pNew = lcl_CreateNumberingSettingsPtr(pValuesArr[i]);
+ std::shared_ptr<NumberSettings_Impl> pNumEntry = std::make_shared<NumberSettings_Impl>();
+ pNumEntry->pNumSetting = pNew;
+ if ( i < 8 )
+ pNumEntry->sDescription = SvxResId(RID_SVXSTR_SINGLENUM_DESCRIPTIONS[i]);
+ maNumberSettingsArr.push_back(pNumEntry);
+ }
+ }
+ catch(Exception&)
+ {
+ }
+}
+
+sal_uInt16 NumberingTypeMgr::GetNBOIndexForNumRule(SvxNumRule& aNum,sal_uInt16 mLevel,sal_uInt16 nFromIndex)
+{
+ if ( mLevel == sal_uInt16(0xFFFF) || mLevel > aNum.GetLevelCount() || mLevel == 0)
+ return sal_uInt16(0xFFFF);
+
+ sal_uInt16 nActLv = IsSingleLevel(mLevel);
+
+ if ( nActLv == sal_uInt16(0xFFFF) )
+ return sal_uInt16(0xFFFF);
+
+ const SvxNumberFormat& aFmt(aNum.GetLevel(nActLv));
+ //sal_Unicode cPrefix = OUString(aFmt.GetPrefix())[0];
+ //sal_Unicode cSuffix = :OUString(aFmt.GetSuffix())[0];
+ const OUString& sPrefix = aFmt.GetPrefix();
+ const OUString& sLclSuffix = aFmt.GetSuffix();
+ sal_Int16 eNumType = aFmt.GetNumberingType();
+
+ sal_uInt16 nCount = maNumberSettingsArr.size();
+ for(sal_uInt16 i = nFromIndex; i < nCount; ++i)
+ {
+ NumberSettings_Impl* _pSet = maNumberSettingsArr[i].get();
+ sal_Int16 eNType = _pSet->pNumSetting->nNumberType;
+ OUString sLocalPrefix = _pSet->pNumSetting->sPrefix;
+ OUString sLocalSuffix = _pSet->pNumSetting->sSuffix;
+ if (sPrefix == sLocalPrefix &&
+ sLclSuffix == sLocalSuffix &&
+ eNumType == eNType )
+ {
+ return i+1;
+ }
+ }
+
+
+ return sal_uInt16(0xFFFF);
+}
+
+void NumberingTypeMgr::RelplaceNumRule(SvxNumRule& aNum, sal_uInt16 nIndex, sal_uInt16 mLevel)
+{
+ sal_uInt16 nActLv = IsSingleLevel(mLevel);
+
+ if ( nActLv == sal_uInt16(0xFFFF) )
+ return;
+
+ const SvxNumberFormat& aFmt(aNum.GetLevel(nActLv));
+ SvxNumType eNumType = aFmt.GetNumberingType();
+
+ sal_uInt16 nCount = maNumberSettingsArr.size();
+ if ( nIndex >= nCount )
+ return;
+
+ NumberSettings_Impl* _pSet = maNumberSettingsArr[nIndex].get();
+
+ _pSet->pNumSetting->sPrefix = aFmt.GetPrefix();
+ _pSet->pNumSetting->sSuffix = aFmt.GetSuffix();
+ _pSet->pNumSetting->nNumberType = eNumType;
+ _pSet->bIsCustomized = true;
+
+ SvxNumRule aTmpRule1(aNum);
+ SvxNumRule aTmpRule2(aNum);
+ ApplyNumRule(aTmpRule1,nIndex,mLevel,true);
+ ApplyNumRule(aTmpRule2,nIndex,mLevel);
+ if (aTmpRule1==aTmpRule2) _pSet->bIsCustomized=false;
+ if (!_pSet->bIsCustomized) {
+ _pSet->sDescription = GetDescription(nIndex,true);
+ }
+ ImplStore(u"standard.syb");
+}
+
+void NumberingTypeMgr::ApplyNumRule(SvxNumRule& aNum, sal_uInt16 nIndex, sal_uInt16 mLevel, bool isDefault, bool isResetSize)
+{
+ if(maNumberSettingsArr.size() <= nIndex)
+ return;
+ NumberSettingsArr_Impl* pCurrentNumberSettingsArr = &maNumberSettingsArr;
+ if (isDefault) pCurrentNumberSettingsArr = &maDefaultNumberSettingsArr;
+ NumberSettings_Impl* _pSet = (*pCurrentNumberSettingsArr)[nIndex].get();
+ SvxNumType eNewType = _pSet->pNumSetting->nNumberType;
+
+ sal_uInt16 nMask = 1;
+ OUString sNumCharFmtName = GetNumCharFmtName();
+ for(sal_uInt16 i = 0; i < aNum.GetLevelCount(); i++)
+ {
+ if(mLevel & nMask)
+ {
+ SvxNumberFormat aFmt(aNum.GetLevel(i));
+ if (eNewType!=aFmt.GetNumberingType()) isResetSize=true;
+ aFmt.SetNumberingType(eNewType);
+ aFmt.SetListFormat(_pSet->pNumSetting->sPrefix, _pSet->pNumSetting->sSuffix, i);
+ aFmt.SetCharFormatName(sNumCharFmtName);
+ if (isResetSize) aFmt.SetBulletRelSize(100);
+ aNum.SetLevel(i, aFmt);
+ }
+ nMask <<= 1 ;
+ }
+}
+
+OUString NumberingTypeMgr::GetDescription(sal_uInt16 nIndex, bool isDefault)
+{
+ OUString sRet;
+ sal_uInt16 nLength = maNumberSettingsArr.size();
+
+ if ( nIndex >= nLength )
+ return sRet;
+ else
+ sRet = maNumberSettingsArr[nIndex]->sDescription;
+ if (isDefault) sRet = maDefaultNumberSettingsArr[nIndex]->sDescription;
+
+ return sRet;
+}
+
+bool NumberingTypeMgr::IsCustomized(sal_uInt16 nIndex)
+{
+ bool bRet = false;
+ sal_uInt16 nLength = maNumberSettingsArr.size();
+
+ if ( nIndex >= nLength )
+ bRet = false;
+ else
+ bRet = maNumberSettingsArr[nIndex]->bIsCustomized;
+
+ return bRet;
+}
+// Multi-level /Outline Type lib
+OutlineTypeMgr::OutlineTypeMgr()
+{
+ Init();
+ for(sal_Int32 nItem = 0; nItem < DEFAULT_NUM_VALUSET_COUNT; nItem++ )
+ {
+ pDefaultOutlineSettingsArrs[nItem] = pOutlineSettingsArrs[nItem];
+ }
+ //Initial the first time to store the default value. Then do it again for customized value
+ Init();
+ ImplLoad(u"standard.syc");
+}
+
+OutlineTypeMgr& OutlineTypeMgr::GetInstance()
+{
+ static OutlineTypeMgr theOutlineTypeMgr;
+ return theOutlineTypeMgr;
+}
+
+void OutlineTypeMgr::Init()
+{
+ Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ Reference<XDefaultNumberingProvider> xDefNum = DefaultNumberingProvider::create( xContext );
+
+ Sequence<Reference<XIndexAccess> > aOutlineAccess;
+ Locale aLocale(Application::GetSettings().GetLanguageTag().getLocale());
+ try
+ {
+ aOutlineAccess = xDefNum->getDefaultOutlineNumberings( aLocale );
+
+ SvxNumRule aDefNumRule( SvxNumRuleFlags::BULLET_REL_SIZE | SvxNumRuleFlags::CONTINUOUS | SvxNumRuleFlags::BULLET_COLOR,
+ 10, false,
+ SvxNumRuleType::NUMBERING, SvxNumberFormat::LABEL_ALIGNMENT);
+
+ auto nSize = std::min<sal_Int32>(aOutlineAccess.getLength(), DEFAULT_NUM_VALUSET_COUNT);
+ for(sal_Int32 nItem = 0; nItem < nSize; nItem++ )
+ {
+ pOutlineSettingsArrs[ nItem ] = new OutlineSettings_Impl;
+ OutlineSettings_Impl* pItemArr = pOutlineSettingsArrs[ nItem ];
+ OString id = OString::Concat(RID_SVXSTR_OUTLINENUM_DESCRIPTION_0.mpId) + OString::number(nItem);
+ pItemArr->sDescription = SvxResId( TranslateId(RID_SVXSTR_OUTLINENUM_DESCRIPTION_0.mpContext, id.getStr()) );
+ pItemArr->pNumSettingsArr = new NumSettingsArr_Impl;
+ Reference<XIndexAccess> xLevel = aOutlineAccess.getConstArray()[nItem];
+ for(sal_Int32 nLevel = 0; nLevel < xLevel->getCount() && nLevel < 5; nLevel++)
+ {
+ Any aValueAny = xLevel->getByIndex(nLevel);
+ Sequence<PropertyValue> aLevelProps;
+ aValueAny >>= aLevelProps;
+ NumSettings_Impl* pNew = lcl_CreateNumberingSettingsPtr(aLevelProps);
+ const SvxNumberFormat& aNumFmt( aDefNumRule.GetLevel( nLevel) );
+ pNew->eLabelFollowedBy = aNumFmt.GetLabelFollowedBy();
+ pNew->nTabValue = aNumFmt.GetListtabPos();
+ pNew->eNumAlign = aNumFmt.GetNumAdjust();
+ pNew->nNumAlignAt = aNumFmt.GetFirstLineIndent();
+ pNew->nNumIndentAt = aNumFmt.GetIndentAt();
+ pItemArr->pNumSettingsArr->push_back(std::shared_ptr<NumSettings_Impl>(pNew));
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ }
+}
+
+sal_uInt16 OutlineTypeMgr::GetNBOIndexForNumRule(SvxNumRule& aNum,sal_uInt16 /*mLevel*/,sal_uInt16 nFromIndex)
+{
+ sal_uInt16 const nLength = SAL_N_ELEMENTS(pOutlineSettingsArrs);
+ for(sal_uInt16 iDex = nFromIndex; iDex < nLength; iDex++)
+ {
+ bool bNotMatch = false;
+ OutlineSettings_Impl* pItemArr = pOutlineSettingsArrs[iDex];
+ sal_uInt16 nCount = pItemArr->pNumSettingsArr->size();
+ for (sal_uInt16 iLevel=0;iLevel < nCount;iLevel++)
+ {
+ NumSettings_Impl* _pSet = (*pItemArr->pNumSettingsArr)[iLevel].get();
+ sal_Int16 eNType = _pSet->nNumberType;
+
+ const SvxNumberFormat& aFmt(aNum.GetLevel(iLevel));
+ const OUString& sPrefix = aFmt.GetPrefix();
+ const OUString& sLclSuffix = aFmt.GetSuffix();
+ sal_Int16 eNumType = aFmt.GetNumberingType();
+ if( eNumType == SVX_NUM_CHAR_SPECIAL)
+ {
+ sal_UCS4 cChar = aFmt.GetBulletChar();
+
+ sal_UCS4 ccChar
+ = _pSet->sBulletChar.iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
+
+ if ( !((cChar == ccChar) &&
+ _pSet->eLabelFollowedBy == aFmt.GetLabelFollowedBy() &&
+ _pSet->nTabValue == aFmt.GetListtabPos() &&
+ _pSet->eNumAlign == aFmt.GetNumAdjust() &&
+ _pSet->nNumAlignAt == aFmt.GetFirstLineIndent() &&
+ _pSet->nNumIndentAt == aFmt.GetIndentAt()))
+ {
+ bNotMatch = true;
+ break;
+ }
+ }
+ else if ((eNumType&(~LINK_TOKEN)) == SVX_NUM_BITMAP )
+ {
+ const SvxBrushItem* pBrsh1 = aFmt.GetBrush();
+ const SvxBrushItem* pBrsh2 = _pSet->pBrushItem;
+ bool bIsMatch = false;
+ if (pBrsh1==pBrsh2) bIsMatch = true;
+ if (pBrsh1 && pBrsh2) {
+ const Graphic* pGrf1 = pBrsh1->GetGraphic();
+ const Graphic* pGrf2 = pBrsh2->GetGraphic();
+ if (pGrf1==pGrf2) bIsMatch = true;
+ if (pGrf1 && pGrf2) {
+ if ( pGrf1->GetBitmapEx() == pGrf2->GetBitmapEx() &&
+ _pSet->aSize == aFmt.GetGraphicSize())
+ bIsMatch = true;
+ }
+ }
+ if (!bIsMatch) {
+ bNotMatch = true;
+ break;
+ }
+ }
+ else
+ {
+ if (!(sPrefix == _pSet->sPrefix &&
+ sLclSuffix == _pSet->sSuffix &&
+ eNumType == eNType &&
+ _pSet->eLabelFollowedBy == aFmt.GetLabelFollowedBy() &&
+ _pSet->nTabValue == aFmt.GetListtabPos() &&
+ _pSet->eNumAlign == aFmt.GetNumAdjust() &&
+ _pSet->nNumAlignAt == aFmt.GetFirstLineIndent() &&
+ _pSet->nNumIndentAt == aFmt.GetIndentAt()))
+ {
+ bNotMatch = true;
+ break;
+ }
+ }
+ }
+ if ( !bNotMatch )
+ return iDex+1;
+ }
+
+
+ return sal_uInt16(0xFFFF);
+}
+
+void OutlineTypeMgr::RelplaceNumRule(SvxNumRule& aNum, sal_uInt16 nIndex, sal_uInt16 mLevel)
+{
+ sal_uInt16 const nLength = SAL_N_ELEMENTS(pOutlineSettingsArrs);
+ if ( nIndex >= nLength )
+ return;
+
+ OutlineSettings_Impl* pItemArr = pOutlineSettingsArrs[nIndex];
+ sal_uInt16 nCount = pItemArr->pNumSettingsArr->size();
+ for (sal_uInt16 iLevel=0;iLevel < nCount;iLevel++)
+ {
+ const SvxNumberFormat& aFmt(aNum.GetLevel(iLevel));
+ SvxNumType eNumType = aFmt.GetNumberingType();
+
+ NumSettings_Impl* _pSet = (*pItemArr->pNumSettingsArr)[iLevel].get();
+
+ _pSet->eLabelFollowedBy = aFmt.GetLabelFollowedBy();
+ _pSet->nTabValue = aFmt.GetListtabPos();
+ _pSet->eNumAlign = aFmt.GetNumAdjust();
+ _pSet->nNumAlignAt = aFmt.GetFirstLineIndent();
+ _pSet->nNumIndentAt = aFmt.GetIndentAt();
+
+ if( eNumType == SVX_NUM_CHAR_SPECIAL)
+ {
+ sal_UCS4 cChar = aFmt.GetBulletChar();
+ OUString sChar(&cChar, 1);
+ _pSet->sBulletChar = sChar;
+ if ( aFmt.GetBulletFont() )
+ _pSet->sBulletFont = aFmt.GetBulletFont()->GetFamilyName();
+ _pSet->nNumberType = eNumType;
+ pItemArr->bIsCustomized = true;
+ }else if ((eNumType&(~LINK_TOKEN)) == SVX_NUM_BITMAP ) {
+ if (_pSet->pBrushItem) {
+ delete _pSet->pBrushItem;
+ _pSet->pBrushItem=nullptr;
+ }
+ if (aFmt.GetBrush())
+ _pSet->pBrushItem = new SvxBrushItem(*aFmt.GetBrush());
+ _pSet->aSize = aFmt.GetGraphicSize();
+ _pSet->nNumberType = eNumType;
+ } else
+ {
+ _pSet->sPrefix = aFmt.GetPrefix();
+ _pSet->sSuffix = aFmt.GetSuffix();
+ _pSet->nNumberType = eNumType;
+ if ( aFmt.GetBulletFont() )
+ _pSet->sBulletFont = aFmt.GetBulletFont()->GetFamilyName();
+ pItemArr->bIsCustomized = true;
+ }
+ }
+ SvxNumRule aTmpRule1(aNum);
+ SvxNumRule aTmpRule2(aNum);
+ ApplyNumRule(aTmpRule1,nIndex,mLevel,true);
+ ApplyNumRule(aTmpRule2,nIndex,mLevel);
+ if (aTmpRule1==aTmpRule2) pItemArr->bIsCustomized=false;
+ if (!pItemArr->bIsCustomized) {
+ pItemArr->sDescription = GetDescription(nIndex,true);
+ }
+ ImplStore(u"standard.syc");
+}
+
+void OutlineTypeMgr::ApplyNumRule(SvxNumRule& aNum, sal_uInt16 nIndex, sal_uInt16 /*mLevel*/, bool isDefault, bool isResetSize)
+{
+ DBG_ASSERT(DEFAULT_NUM_VALUSET_COUNT > nIndex, "wrong index");
+ if(DEFAULT_NUM_VALUSET_COUNT <= nIndex)
+ return;
+
+ const FontList* pList = nullptr;
+
+ OutlineSettings_Impl* pItemArr = pOutlineSettingsArrs[nIndex];
+ if (isDefault) pItemArr=pDefaultOutlineSettingsArrs[nIndex];
+
+ NumSettingsArr_Impl *pNumSettingsArr=pItemArr->pNumSettingsArr;
+
+ NumSettings_Impl* pLevelSettings = nullptr;
+ for(sal_uInt16 i = 0; i < aNum.GetLevelCount(); i++)
+ {
+ if(pNumSettingsArr->size() > i)
+ pLevelSettings = (*pNumSettingsArr)[i].get();
+
+ if(!pLevelSettings)
+ break;
+
+ SvxNumberFormat aFmt(aNum.GetLevel(i));
+ const vcl::Font& rActBulletFont = lcl_GetDefaultBulletFont();
+ if (pLevelSettings->nNumberType !=aFmt.GetNumberingType()) isResetSize=true;
+ aFmt.SetNumberingType( pLevelSettings->nNumberType );
+ sal_uInt16 nUpperLevelOrChar = static_cast<sal_uInt16>(pLevelSettings->nParentNumbering);
+ if(aFmt.GetNumberingType() == SVX_NUM_CHAR_SPECIAL)
+ {
+ if( pLevelSettings->sBulletFont.getLength() &&
+ pLevelSettings->sBulletFont != rActBulletFont.GetFamilyName() )
+ {
+ //search for the font
+ if(!pList)
+ {
+ if (SfxObjectShell* pCurDocShell = SfxObjectShell::Current())
+ {
+ const SvxFontListItem* pFontListItem = static_cast<const SvxFontListItem*>(pCurDocShell->GetItem(SID_ATTR_CHAR_FONTLIST));
+ pList = pFontListItem ? pFontListItem->GetFontList() : nullptr;
+ }
+ }
+ if(pList && pList->IsAvailable( pLevelSettings->sBulletFont ) )
+ {
+ FontMetric aFontMetric = pList->Get(pLevelSettings->sBulletFont,WEIGHT_NORMAL, ITALIC_NONE);
+ vcl::Font aFont(aFontMetric);
+ aFmt.SetBulletFont(&aFont);
+ }
+ else
+ {
+ //if it cannot be found then create a new one
+ vcl::Font aCreateFont( pLevelSettings->sBulletFont, OUString(), Size( 0, 14 ) );
+ aCreateFont.SetCharSet( RTL_TEXTENCODING_DONTKNOW );
+ aCreateFont.SetFamily( FAMILY_DONTKNOW );
+ aCreateFont.SetPitch( PITCH_DONTKNOW );
+ aCreateFont.SetWeight( WEIGHT_DONTKNOW );
+ aCreateFont.SetTransparent( true );
+ aFmt.SetBulletFont( &aCreateFont );
+ }
+ }else
+ aFmt.SetBulletFont( &rActBulletFont );
+
+ sal_UCS4 cChar = 0;
+ if( !pLevelSettings->sBulletChar.isEmpty() )
+ {
+ cChar
+ = pLevelSettings->sBulletChar.iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
+ }
+ if( AllSettings::GetLayoutRTL() )
+ {
+ if( 0 == i && cChar == BulletsTypeMgr::aDynamicBulletTypes[5] )
+ cChar = BulletsTypeMgr::aDynamicRTLBulletTypes[5];
+ else if( 1 == i )
+ {
+ const SvxNumberFormat& numberFmt = aNum.GetLevel(0);
+ if( numberFmt.GetBulletChar() == BulletsTypeMgr::aDynamicRTLBulletTypes[5] )
+ cChar = BulletsTypeMgr::aDynamicRTLBulletTypes[4];
+ }
+ }
+
+ aFmt.SetBulletChar(cChar);
+ aFmt.SetCharFormatName( GetBulletCharFmtName() );
+ if (isResetSize) aFmt.SetBulletRelSize(45);
+ }else if ((aFmt.GetNumberingType()&(~LINK_TOKEN)) == SVX_NUM_BITMAP ) {
+ if (pLevelSettings->pBrushItem) {
+ const Graphic* pGrf = pLevelSettings->pBrushItem->GetGraphic();
+ Size aSize = pLevelSettings->aSize;
+ sal_Int16 eOrient = text::VertOrientation::LINE_CENTER;
+ if (!isResetSize && aFmt.GetGraphicSize()!=Size(0,0))
+ aSize = aFmt.GetGraphicSize();
+ else if (aSize.IsEmpty() && pGrf)
+ aSize = SvxNumberFormat::GetGraphicSizeMM100( pGrf );
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(GetMapUnit()));
+ aFmt.SetGraphicBrush( pLevelSettings->pBrushItem, &aSize, &eOrient );
+ }
+ } else
+ {
+ aFmt.SetIncludeUpperLevels(sal::static_int_cast< sal_uInt8 >(0 != nUpperLevelOrChar ? aNum.GetLevelCount() : 1));
+ aFmt.SetCharFormatName(GetNumCharFmtName());
+ if (isResetSize) aFmt.SetBulletRelSize(100);
+ }
+ if(pNumSettingsArr->size() > i) {
+ aFmt.SetLabelFollowedBy(pLevelSettings->eLabelFollowedBy);
+ aFmt.SetListtabPos(pLevelSettings->nTabValue);
+ aFmt.SetNumAdjust(pLevelSettings->eNumAlign);
+ aFmt.SetFirstLineIndent(pLevelSettings->nNumAlignAt);
+ aFmt.SetIndentAt(pLevelSettings->nNumIndentAt);
+ }
+ aFmt.SetListFormat(pLevelSettings->sPrefix, pLevelSettings->sSuffix, i);
+ aNum.SetLevel(i, aFmt);
+ }
+}
+
+OUString OutlineTypeMgr::GetDescription(sal_uInt16 nIndex, bool isDefault)
+{
+ OUString sRet;
+
+ if ( nIndex >= SAL_N_ELEMENTS(pOutlineSettingsArrs) )
+ return sRet;
+ else
+ {
+ OutlineSettings_Impl* pItemArr = pOutlineSettingsArrs[nIndex];
+ if (isDefault) pItemArr = pDefaultOutlineSettingsArrs[nIndex];
+ if ( pItemArr )
+ {
+ sRet = pItemArr->sDescription;
+ }
+ }
+ return sRet;
+}
+
+bool OutlineTypeMgr::IsCustomized(sal_uInt16 nIndex)
+{
+ bool bRet = false;
+
+ if ( nIndex >= SAL_N_ELEMENTS(pOutlineSettingsArrs) )
+ return bRet;
+ else
+ {
+ OutlineSettings_Impl* pItemArr = pOutlineSettingsArrs[nIndex];
+ if ( pItemArr )
+ {
+ bRet = pItemArr->bIsCustomized;
+ }
+ }
+
+ return bRet;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/nbdtmgfact.cxx b/svx/source/sidebar/nbdtmgfact.cxx
new file mode 100644
index 000000000..14dcd64c4
--- /dev/null
+++ b/svx/source/sidebar/nbdtmgfact.cxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/nbdtmgfact.hxx>
+
+namespace svx::sidebar::NBOutlineTypeMgrFact
+{
+NBOTypeMgrBase* CreateInstance(const NBOType aType)
+{
+ if (aType == NBOType::Bullets)
+ {
+ return &BulletsTypeMgr::GetInstance();
+ }
+ else if (aType == NBOType::Numbering)
+ {
+ return &NumberingTypeMgr::GetInstance();
+ }
+ else if (aType == NBOType::Outline)
+ {
+ return &OutlineTypeMgr::GetInstance();
+ }
+ return nullptr;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/paragraph/ParaLineSpacingControl.cxx b/svx/source/sidebar/paragraph/ParaLineSpacingControl.cxx
new file mode 100644
index 000000000..fee659817
--- /dev/null
+++ b/svx/source/sidebar/paragraph/ParaLineSpacingControl.cxx
@@ -0,0 +1,439 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ParaLineSpacingControl.hxx"
+
+#include <editeng/editids.hrc>
+#include <editeng/lspcitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <svtools/unitconv.hxx>
+
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+
+#include <ParaLineSpacingPopup.hxx>
+
+#define DEFAULT_LINE_SPACING 200
+#define FIX_DIST_DEF 283
+#define LINESPACE_1 100
+#define LINESPACE_15 150
+#define LINESPACE_2 200
+#define LINESPACE_115 115
+
+// values of the mxLineDist listbox
+#define LLINESPACE_1 0
+#define LLINESPACE_115 1
+#define LLINESPACE_15 2
+#define LLINESPACE_2 3
+#define LLINESPACE_PROP 4
+#define LLINESPACE_MIN 5
+#define LLINESPACE_DURCH 6
+#define LLINESPACE_FIX 7
+
+#define MIN_FIXED_DISTANCE 28
+
+using namespace svx;
+
+ParaLineSpacingControl::ParaLineSpacingControl(SvxLineSpacingToolBoxControl* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/paralinespacingcontrol.ui", "ParaLineSpacingControl")
+ , mxControl(pControl)
+ , meLNSpaceUnit(MapUnit::Map100thMM)
+ , mxSpacing1Button(m_xBuilder->weld_button("spacing_1"))
+ , mxSpacing115Button(m_xBuilder->weld_button("spacing_115"))
+ , mxSpacing15Button(m_xBuilder->weld_button("spacing_15"))
+ , mxSpacing2Button(m_xBuilder->weld_button("spacing_2"))
+ , mxLineDist(m_xBuilder->weld_combo_box("line_dist"))
+ , mxLineDistLabel(m_xBuilder->weld_label("value_label"))
+ , mxLineDistAtPercentBox(m_xBuilder->weld_metric_spin_button("percent_box", FieldUnit::PERCENT))
+ , mxLineDistAtMetricBox(m_xBuilder->weld_metric_spin_button("metric_box", FieldUnit::CM))
+ , mpActLineDistFld(mxLineDistAtPercentBox.get())
+{
+ Link<weld::Button&,void> aLink = LINK(this, ParaLineSpacingControl, PredefinedValuesHandler);
+ mxSpacing1Button->connect_clicked(aLink);
+ mxSpacing115Button->connect_clicked(aLink);
+ mxSpacing15Button->connect_clicked(aLink);
+ mxSpacing2Button->connect_clicked(aLink);
+
+ Link<weld::ComboBox&,void> aLink3 = LINK( this, ParaLineSpacingControl, LineSPDistHdl_Impl );
+ mxLineDist->connect_changed(aLink3);
+ SelectEntryPos(LLINESPACE_1);
+
+ Link<weld::MetricSpinButton&,void> aLink2 = LINK( this, ParaLineSpacingControl, LineSPDistAtHdl_Impl );
+ mxLineDistAtPercentBox->connect_value_changed( aLink2 );
+ mxLineDistAtMetricBox->connect_value_changed( aLink2 );
+
+ FieldUnit eUnit = FieldUnit::INCH;
+ const SfxUInt16Item* pItem = nullptr;
+ SfxViewFrame* pCurrent = SfxViewFrame::Current();
+ if (pCurrent && pCurrent->GetBindings().GetDispatcher()->QueryState(SID_ATTR_METRIC, pItem) >= SfxItemState::DEFAULT)
+ eUnit = static_cast<FieldUnit>(pItem->GetValue());
+ else
+ eUnit = SfxModule::GetCurrentFieldUnit();
+
+ SetFieldUnit(*mxLineDistAtMetricBox, eUnit);
+
+ Initialize();
+}
+
+void ParaLineSpacingControl::GrabFocus()
+{
+ switch (mxLineDist->get_active())
+ {
+ case LLINESPACE_1:
+ mxSpacing1Button->grab_focus();
+ break;
+ case LLINESPACE_115:
+ mxSpacing115Button->grab_focus();
+ break;
+ case LLINESPACE_15:
+ mxSpacing15Button->grab_focus();
+ break;
+ case LLINESPACE_2:
+ mxSpacing2Button->grab_focus();
+ break;
+ default:
+ mxLineDist->grab_focus();
+ break;
+ }
+}
+
+ParaLineSpacingControl::~ParaLineSpacingControl()
+{
+}
+
+void ParaLineSpacingControl::Initialize()
+{
+ const SvxLineSpacingItem* pItem(nullptr);
+ SfxViewFrame* pCurrent = SfxViewFrame::Current();
+ const bool bItemStateSet(nullptr != pCurrent);
+ const SfxItemState eState(bItemStateSet
+ ? pCurrent->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PARA_LINESPACE, pItem)
+ : SfxItemState::DEFAULT);
+
+ mxLineDist->set_sensitive(true);
+
+ if( bItemStateSet && (eState == SfxItemState::DEFAULT || eState == SfxItemState::SET) )
+ {
+ const SvxLineSpacingItem* currSPItem = pItem;
+ MapUnit eUnit = pCurrent->GetPool().GetMetric(currSPItem->Which());
+ meLNSpaceUnit = eUnit;
+
+ switch( currSPItem->GetLineSpaceRule() )
+ {
+ case SvxLineSpaceRule::Auto:
+ {
+ SvxInterLineSpaceRule eInter = currSPItem->GetInterLineSpaceRule();
+
+ switch( eInter )
+ {
+ case SvxInterLineSpaceRule::Off:
+ SelectEntryPos(LLINESPACE_1);
+ break;
+
+ case SvxInterLineSpaceRule::Prop:
+ {
+ if ( LINESPACE_1 == currSPItem->GetPropLineSpace() )
+ {
+ SelectEntryPos(LLINESPACE_1);
+ }
+ else if ( LINESPACE_115 == currSPItem->GetPropLineSpace() )
+ {
+ SelectEntryPos(LLINESPACE_115);
+ }
+ else if ( LINESPACE_15 == currSPItem->GetPropLineSpace() )
+ {
+ SelectEntryPos(LLINESPACE_15);
+ }
+ else if ( LINESPACE_2 == currSPItem->GetPropLineSpace() )
+ {
+ SelectEntryPos(LLINESPACE_2);
+ }
+ else
+ {
+ SelectEntryPos(LLINESPACE_PROP);
+ mxLineDistAtPercentBox->set_value(mxLineDistAtPercentBox->normalize(currSPItem->GetPropLineSpace()), FieldUnit::PERCENT);
+ }
+ }
+ break;
+
+ case SvxInterLineSpaceRule::Fix:
+ {
+ SelectEntryPos(LLINESPACE_DURCH);
+ SetMetricValue(*mxLineDistAtMetricBox, currSPItem->GetInterLineSpace(), eUnit);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case SvxLineSpaceRule::Fix:
+ {
+ SelectEntryPos(LLINESPACE_FIX);
+ SetMetricValue(*mxLineDistAtMetricBox, currSPItem->GetLineHeight(), eUnit);
+ }
+ break;
+
+ case SvxLineSpaceRule::Min:
+ {
+ SelectEntryPos(LLINESPACE_MIN);
+ SetMetricValue(*mxLineDistAtMetricBox, currSPItem->GetLineHeight(), eUnit);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else if( bItemStateSet && eState == SfxItemState::DISABLED )
+ {
+ mxLineDist->set_sensitive(false);
+ mxLineDistLabel->set_sensitive(false);
+ mpActLineDistFld->set_sensitive(false);
+ mpActLineDistFld->set_text("");
+
+ }
+ else // !bItemStateSet || eState == SfxItemState::DONTCARE || eState == SfxItemState::UNKNOWN
+ {
+ mxLineDistLabel->set_sensitive(false);
+ mpActLineDistFld->set_sensitive(false);
+ mpActLineDistFld->set_text("");
+ mxLineDist->set_active(-1);
+ }
+
+ mxLineDist->save_value();
+}
+
+void ParaLineSpacingControl::UpdateMetricFields()
+{
+ switch (mxLineDist->get_active())
+ {
+ case LLINESPACE_1:
+ case LLINESPACE_115:
+ case LLINESPACE_15:
+ case LLINESPACE_2:
+ if (mpActLineDistFld == mxLineDistAtPercentBox.get())
+ mxLineDistAtMetricBox->hide();
+ else
+ mxLineDistAtPercentBox->hide();
+
+ mxLineDistLabel->set_sensitive(false);
+ mpActLineDistFld->show();
+ mpActLineDistFld->set_sensitive(false);
+ mpActLineDistFld->set_text("");
+ break;
+
+ case LLINESPACE_DURCH:
+ mxLineDistAtPercentBox->hide();
+
+ mpActLineDistFld = mxLineDistAtMetricBox.get();
+ mxLineDistAtMetricBox->set_min(0, FieldUnit::NONE);
+
+ if (mxLineDistAtMetricBox->get_text().isEmpty())
+ mxLineDistAtMetricBox->set_value(mxLineDistAtMetricBox->normalize(0), FieldUnit::NONE);
+
+ mxLineDistLabel->set_sensitive(true);
+ mpActLineDistFld->show();
+ mpActLineDistFld->set_sensitive(true);
+ break;
+
+ case LLINESPACE_MIN:
+ mxLineDistAtPercentBox->hide();
+
+ mpActLineDistFld = mxLineDistAtMetricBox.get();
+ mxLineDistAtMetricBox->set_min(0, FieldUnit::NONE);
+
+ if (mxLineDistAtMetricBox->get_text().isEmpty())
+ mxLineDistAtMetricBox->set_value(mxLineDistAtMetricBox->normalize(0), FieldUnit::TWIP);
+
+ mxLineDistLabel->set_sensitive(true);
+ mpActLineDistFld->show();
+ mpActLineDistFld->set_sensitive(true);
+ break;
+
+ case LLINESPACE_PROP:
+ mxLineDistAtMetricBox->hide();
+
+ mpActLineDistFld = mxLineDistAtPercentBox.get();
+
+ if (mxLineDistAtPercentBox->get_text().isEmpty())
+ mxLineDistAtPercentBox->set_value(mxLineDistAtPercentBox->normalize(100), FieldUnit::TWIP);
+
+ mxLineDistLabel->set_sensitive(true);
+ mpActLineDistFld->show();
+ mpActLineDistFld->set_sensitive(true);
+ break;
+
+ case LLINESPACE_FIX:
+ mxLineDistAtPercentBox->hide();
+
+ mpActLineDistFld = mxLineDistAtMetricBox.get();
+ sal_Int64 nTemp = mxLineDistAtMetricBox->get_value(FieldUnit::NONE);
+ mxLineDistAtMetricBox->set_min(mxLineDistAtMetricBox->normalize(MIN_FIXED_DISTANCE), FieldUnit::TWIP);
+
+ if (mxLineDistAtMetricBox->get_value(FieldUnit::NONE) != nTemp)
+ SetMetricValue(*mxLineDistAtMetricBox, FIX_DIST_DEF, MapUnit::MapTwip);
+
+ mxLineDistLabel->set_sensitive(true);
+ mpActLineDistFld->show();
+ mpActLineDistFld->set_sensitive(true);
+ break;
+ }
+}
+
+void ParaLineSpacingControl::SelectEntryPos(sal_Int32 nPos)
+{
+ mxLineDist->set_active(nPos);
+ UpdateMetricFields();
+}
+
+IMPL_LINK_NOARG(ParaLineSpacingControl, LineSPDistHdl_Impl, weld::ComboBox&, void)
+{
+ UpdateMetricFields();
+ ExecuteLineSpace();
+}
+
+IMPL_LINK_NOARG( ParaLineSpacingControl, LineSPDistAtHdl_Impl, weld::MetricSpinButton&, void )
+{
+ ExecuteLineSpace();
+}
+
+void ParaLineSpacingControl::ExecuteLineSpace()
+{
+ mxLineDist->save_value();
+
+ SvxLineSpacingItem aSpacing(DEFAULT_LINE_SPACING, SID_ATTR_PARA_LINESPACE);
+ const sal_Int32 nPos = mxLineDist->get_active();
+
+ switch ( nPos )
+ {
+ case LLINESPACE_1:
+ case LLINESPACE_115:
+ case LLINESPACE_15:
+ case LLINESPACE_2:
+ SetLineSpace(aSpacing, nPos);
+ break;
+
+ case LLINESPACE_PROP:
+ SetLineSpace(aSpacing, nPos, mxLineDistAtPercentBox->denormalize(static_cast<tools::Long>(mxLineDistAtPercentBox->get_value(FieldUnit::PERCENT))));
+ break;
+
+ case LLINESPACE_MIN:
+ case LLINESPACE_DURCH:
+ case LLINESPACE_FIX:
+ SetLineSpace(aSpacing, nPos, GetCoreValue(*mxLineDistAtMetricBox, meLNSpaceUnit));
+ break;
+
+ default:
+ break;
+ }
+
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ {
+ pViewFrm->GetBindings().GetDispatcher()->ExecuteList(
+ SID_ATTR_PARA_LINESPACE, SfxCallMode::RECORD, { &aSpacing });
+ }
+}
+
+void ParaLineSpacingControl::SetLineSpace(SvxLineSpacingItem& rLineSpace, sal_Int32 eSpace, tools::Long lValue)
+{
+ switch ( eSpace )
+ {
+ case LLINESPACE_1:
+ rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
+ rLineSpace.SetInterLineSpaceRule( SvxInterLineSpaceRule::Off );
+ break;
+
+ case LLINESPACE_115:
+ rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
+ rLineSpace.SetPropLineSpace( LINESPACE_115 );
+ break;
+
+ case LLINESPACE_15:
+ rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
+ rLineSpace.SetPropLineSpace( LINESPACE_15 );
+ break;
+
+ case LLINESPACE_2:
+ rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
+ rLineSpace.SetPropLineSpace( LINESPACE_2 );
+ break;
+
+ case LLINESPACE_PROP:
+ rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
+ rLineSpace.SetPropLineSpace( static_cast<sal_uInt16>(lValue) );
+ break;
+
+ case LLINESPACE_MIN:
+ rLineSpace.SetLineHeight( static_cast<sal_uInt16>(lValue) );
+ rLineSpace.SetInterLineSpaceRule( SvxInterLineSpaceRule::Off );
+ break;
+
+ case LLINESPACE_DURCH:
+ rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
+ rLineSpace.SetInterLineSpace( static_cast<sal_uInt16>(lValue) );
+ break;
+
+ case LLINESPACE_FIX:
+ rLineSpace.SetLineHeight(static_cast<sal_uInt16>(lValue));
+ rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Fix );
+ rLineSpace.SetInterLineSpaceRule( SvxInterLineSpaceRule::Off );
+ break;
+ }
+}
+
+IMPL_LINK(ParaLineSpacingControl, PredefinedValuesHandler, weld::Button&, rControl, void)
+{
+ if (&rControl == mxSpacing1Button.get())
+ {
+ ExecuteLineSpacing(LLINESPACE_1);
+ }
+ else if (&rControl == mxSpacing115Button.get())
+ {
+ ExecuteLineSpacing(LLINESPACE_115);
+ }
+ else if (&rControl == mxSpacing15Button.get())
+ {
+ ExecuteLineSpacing(LLINESPACE_15);
+ }
+ else if (&rControl == mxSpacing2Button.get())
+ {
+ ExecuteLineSpacing(LLINESPACE_2);
+ }
+}
+
+void ParaLineSpacingControl::ExecuteLineSpacing(sal_Int32 nEntry)
+{
+ SvxLineSpacingItem aSpacing(DEFAULT_LINE_SPACING, SID_ATTR_PARA_LINESPACE);
+
+ SetLineSpace(aSpacing, nEntry);
+
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ {
+ pViewFrm->GetBindings().GetDispatcher()->ExecuteList(
+ SID_ATTR_PARA_LINESPACE, SfxCallMode::RECORD, { &aSpacing });
+ }
+
+ // close when the user used the buttons
+ mxControl->EndPopupMode();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/paragraph/ParaLineSpacingControl.hxx b/svx/source/sidebar/paragraph/ParaLineSpacingControl.hxx
new file mode 100644
index 000000000..e49556f16
--- /dev/null
+++ b/svx/source/sidebar/paragraph/ParaLineSpacingControl.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svtools/toolbarmenu.hxx>
+
+class SvxLineSpacingItem;
+
+namespace svx
+{
+class SvxLineSpacingToolBoxControl;
+
+class ParaLineSpacingControl : public WeldToolbarPopup
+{
+public:
+ explicit ParaLineSpacingControl(SvxLineSpacingToolBoxControl* pControl, weld::Widget* pParent);
+ virtual ~ParaLineSpacingControl() override;
+
+ /// Setup the widgets with values from the document.
+ void Initialize();
+
+ virtual void GrabFocus() override;
+
+private:
+ rtl::Reference<SvxLineSpacingToolBoxControl> mxControl;
+
+ MapUnit meLNSpaceUnit;
+
+ std::unique_ptr<weld::Button> mxSpacing1Button;
+ std::unique_ptr<weld::Button> mxSpacing115Button;
+ std::unique_ptr<weld::Button> mxSpacing15Button;
+ std::unique_ptr<weld::Button> mxSpacing2Button;
+
+ std::unique_ptr<weld::ComboBox> mxLineDist;
+
+ std::unique_ptr<weld::Label> mxLineDistLabel;
+ std::unique_ptr<weld::MetricSpinButton> mxLineDistAtPercentBox;
+ std::unique_ptr<weld::MetricSpinButton> mxLineDistAtMetricBox;
+ weld::MetricSpinButton* mpActLineDistFld;
+
+private:
+ /// Take the values from the widgets, and update the paragraph accordingly.
+ void ExecuteLineSpace();
+
+ /// Set one particular value.
+ static void SetLineSpace(SvxLineSpacingItem& rLineSpace, sal_Int32 eSpace,
+ tools::Long lValue = 0);
+
+ /// For the buttons - set the values, and close the popup.
+ void ExecuteLineSpacing(sal_Int32 aEntry);
+
+ /// Set mpActlineDistFld and visibility of mpLineDist* fields according to what is just selected.
+ void UpdateMetricFields();
+
+ /// Set the entry and update the metric fields.
+ void SelectEntryPos(sal_Int32 nPos);
+
+ DECL_LINK(LineSPDistHdl_Impl, weld::ComboBox&, void);
+ DECL_LINK(LineSPDistAtHdl_Impl, weld::MetricSpinButton&, void);
+ DECL_LINK(PredefinedValuesHandler, weld::Button&, void);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/paragraph/ParaLineSpacingPopup.cxx b/svx/source/sidebar/paragraph/ParaLineSpacingPopup.cxx
new file mode 100644
index 000000000..d8e427840
--- /dev/null
+++ b/svx/source/sidebar/paragraph/ParaLineSpacingPopup.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ParaLineSpacingControl.hxx"
+
+#include <ParaLineSpacingPopup.hxx>
+#include <vcl/toolbox.hxx>
+
+using namespace svx;
+
+SvxLineSpacingToolBoxControl::SvxLineSpacingToolBoxControl(
+ const css::uno::Reference<css::uno::XComponentContext>& rContext)
+ : PopupWindowController(rContext, nullptr, OUString())
+{
+}
+
+SvxLineSpacingToolBoxControl::~SvxLineSpacingToolBoxControl() {}
+
+void SvxLineSpacingToolBoxControl::initialize(const css::uno::Sequence<css::uno::Any>& rArguments)
+{
+ PopupWindowController::initialize(rArguments);
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWNONLY | pToolBox->GetItemBits(nId));
+}
+
+void SAL_CALL SvxLineSpacingToolBoxControl::execute(sal_Int16 /*KeyModifier*/)
+{
+ if (m_pToolbar)
+ {
+ // Toggle the popup also when toolbutton is activated
+ const OString aId(m_aCommandURL.toUtf8());
+ m_pToolbar->set_menu_item_active(aId, !m_pToolbar->get_menu_item_active(aId));
+ }
+ else
+ {
+ // Open the popup also when Enter key is pressed.
+ createPopupWindow();
+ }
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxLineSpacingToolBoxControl::weldPopupWindow()
+{
+ return std::make_unique<ParaLineSpacingControl>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> SvxLineSpacingToolBoxControl::createVclPopupWindow(vcl::Window* pParent)
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(
+ getFrameInterface(), pParent,
+ std::make_unique<ParaLineSpacingControl>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+OUString SvxLineSpacingToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.LineSpacingToolBoxControl";
+}
+
+css::uno::Sequence<OUString> SvxLineSpacingToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_LineSpacingToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new SvxLineSpacingToolBoxControl(rContext));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/paragraph/ParaPropertyPanel.cxx b/svx/source/sidebar/paragraph/ParaPropertyPanel.cxx
new file mode 100644
index 000000000..f4e2fd83b
--- /dev/null
+++ b/svx/source/sidebar/paragraph/ParaPropertyPanel.cxx
@@ -0,0 +1,491 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "ParaPropertyPanel.hxx"
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/weldutils.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <svx/dlgctrl.hxx>
+#include <svx/svxids.hrc>
+#include <svl/intitem.hxx>
+#include <sfx2/objsh.hxx>
+#include <svtools/unitconv.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+using namespace css;
+using namespace css::uno;
+
+namespace svx::sidebar {
+#define DEFAULT_VALUE 0
+
+#define MAX_DURCH 31680 // tdf#68335: 1584 pt for UX interoperability with Word
+
+#define MAX_SW 1709400
+#define MAX_SC_SD 116220200
+#define NEGA_MAXVALUE -10000000
+
+std::unique_ptr<PanelLayout> ParaPropertyPanel::Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to ParaPropertyPanel::Create", nullptr, 0);
+ if ( ! rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to ParaPropertyPanel::Create", nullptr, 1);
+ if (pBindings == nullptr)
+ throw lang::IllegalArgumentException("no SfxBindings given to ParaPropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<ParaPropertyPanel>(pParent, rxFrame, pBindings, rxSidebar);
+}
+
+void ParaPropertyPanel::HandleContextChange (
+ const vcl::EnumContext& rContext)
+{
+ if (maContext == rContext)
+ {
+ // Nothing to do.
+ return;
+ }
+
+ maContext = rContext;
+ switch (maContext.GetCombinedContext_DI())
+ {
+ case CombinedEnumContext(Application::Calc, Context::DrawText):
+ case CombinedEnumContext(Application::WriterVariants, Context::DrawText):
+ mxTBxVertAlign->show();
+ mxTBxBackColor->hide();
+ mxTBxNumBullet->hide();
+ ReSize();
+ break;
+
+ case CombinedEnumContext(Application::DrawImpress, Context::Draw):
+ case CombinedEnumContext(Application::DrawImpress, Context::TextObject):
+ case CombinedEnumContext(Application::DrawImpress, Context::Graphic):
+ case CombinedEnumContext(Application::DrawImpress, Context::DrawText):
+ case CombinedEnumContext(Application::DrawImpress, Context::Table):
+ mxTBxVertAlign->show();
+ mxTBxBackColor->hide();
+ mxTBxNumBullet->hide();
+ ReSize();
+ break;
+
+ case CombinedEnumContext(Application::WriterVariants, Context::Default):
+ case CombinedEnumContext(Application::WriterVariants, Context::Text):
+ mxTBxVertAlign->hide();
+ mxTBxBackColor->show();
+ mxTBxNumBullet->show();
+ ReSize();
+ break;
+
+ case CombinedEnumContext(Application::WriterVariants, Context::Table):
+ mxTBxVertAlign->show();
+ mxTBxBackColor->show();
+ mxTBxNumBullet->show();
+ ReSize();
+ break;
+
+ case CombinedEnumContext(Application::WriterVariants, Context::Annotation):
+ mxTBxVertAlign->hide();
+ mxTBxBackColor->hide();
+ mxTBxNumBullet->hide();
+ ReSize();
+ break;
+
+ case CombinedEnumContext(Application::Calc, Context::EditCell):
+ case CombinedEnumContext(Application::Calc, Context::Cell):
+ case CombinedEnumContext(Application::Calc, Context::Pivot):
+ case CombinedEnumContext(Application::Calc, Context::Sparkline):
+ case CombinedEnumContext(Application::DrawImpress, Context::Text):
+ case CombinedEnumContext(Application::DrawImpress, Context::OutlineText):
+ break;
+
+ default:
+ break;
+ }
+}
+
+void ParaPropertyPanel::ReSize()
+{
+ if (mxSidebar.is())
+ mxSidebar->requestLayout();
+}
+
+void ParaPropertyPanel::InitToolBoxIndent()
+{
+ Link<weld::MetricSpinButton&,void> aLink = LINK( this, ParaPropertyPanel, ModifyIndentHdl_Impl );
+ mxLeftIndent->connect_value_changed( aLink );
+ mxRightIndent->connect_value_changed( aLink );
+ mxFLineIndent->connect_value_changed( aLink );
+
+ m_eLRSpaceUnit = maLRSpaceControl.GetCoreMetric();
+}
+
+void ParaPropertyPanel::InitToolBoxSpacing()
+{
+ Link<weld::MetricSpinButton&,void> aLink = LINK( this, ParaPropertyPanel, ULSpaceHdl_Impl );
+ mxTopDist->connect_value_changed(aLink);
+ mxBottomDist->connect_value_changed( aLink );
+
+ m_eULSpaceUnit = maULSpaceControl.GetCoreMetric();
+}
+
+void ParaPropertyPanel::initial()
+{
+ limitMetricWidths();
+
+ //toolbox
+ InitToolBoxIndent();
+ InitToolBoxSpacing();
+}
+
+// for Paragraph Indent
+IMPL_LINK_NOARG( ParaPropertyPanel, ModifyIndentHdl_Impl, weld::MetricSpinButton&, void)
+{
+ SvxLRSpaceItem aMargin( SID_ATTR_PARA_LRSPACE );
+ aMargin.SetTextLeft(mxLeftIndent->GetCoreValue(m_eLRSpaceUnit));
+ aMargin.SetRight(mxRightIndent->GetCoreValue(m_eLRSpaceUnit));
+ aMargin.SetTextFirstLineOffset(static_cast<short>(mxFLineIndent->GetCoreValue(m_eLRSpaceUnit)));
+
+ GetBindings()->GetDispatcher()->ExecuteList(
+ SID_ATTR_PARA_LRSPACE, SfxCallMode::RECORD, { &aMargin });
+}
+
+
+// for Paragraph Spacing
+IMPL_LINK_NOARG( ParaPropertyPanel, ULSpaceHdl_Impl, weld::MetricSpinButton&, void)
+{
+ SvxULSpaceItem aMargin( SID_ATTR_PARA_ULSPACE );
+ aMargin.SetUpper( static_cast<sal_uInt16>(mxTopDist->GetCoreValue(m_eULSpaceUnit)));
+ aMargin.SetLower( static_cast<sal_uInt16>(mxBottomDist->GetCoreValue(m_eULSpaceUnit)));
+
+ GetBindings()->GetDispatcher()->ExecuteList(
+ SID_ATTR_PARA_ULSPACE, SfxCallMode::RECORD, { &aMargin });
+}
+
+// for Paragraph State change
+void ParaPropertyPanel::NotifyItemUpdate(
+ sal_uInt16 nSID,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ switch (nSID)
+ {
+ case SID_ATTR_METRIC:
+ {
+ m_eMetricUnit = GetCurrentUnit(eState,pState);
+ if( m_eMetricUnit!=m_last_eMetricUnit )
+ {
+ mxLeftIndent->SetFieldUnit(m_eMetricUnit);
+ mxRightIndent->SetFieldUnit(m_eMetricUnit);
+ mxFLineIndent->SetFieldUnit(m_eMetricUnit);
+ mxTopDist->SetFieldUnit(m_eMetricUnit);
+ mxBottomDist->SetFieldUnit(m_eMetricUnit);
+
+ limitMetricWidths();
+ }
+ m_last_eMetricUnit = m_eMetricUnit;
+ }
+ break;
+
+ case SID_ATTR_PARA_LRSPACE:
+ StateChangedIndentImpl( eState, pState );
+ break;
+
+ case SID_ATTR_PARA_ULSPACE:
+ StateChangedULImpl( eState, pState );
+ break;
+ }
+}
+
+void ParaPropertyPanel::StateChangedIndentImpl( SfxItemState eState, const SfxPoolItem* pState )
+{
+ switch (maContext.GetCombinedContext_DI())
+ {
+
+ case CombinedEnumContext(Application::WriterVariants, Context::DrawText):
+ case CombinedEnumContext(Application::WriterVariants, Context::Annotation):
+ case CombinedEnumContext(Application::Calc, Context::DrawText):
+ case CombinedEnumContext(Application::DrawImpress, Context::DrawText):
+ case CombinedEnumContext(Application::DrawImpress, Context::Draw):
+ case CombinedEnumContext(Application::DrawImpress, Context::TextObject):
+ case CombinedEnumContext(Application::DrawImpress, Context::Graphic):
+ case CombinedEnumContext(Application::DrawImpress, Context::Table):
+ {
+ mxLeftIndent->set_min( DEFAULT_VALUE, FieldUnit::NONE );
+ mxRightIndent->set_min( DEFAULT_VALUE, FieldUnit::NONE );
+ mxFLineIndent->set_min( DEFAULT_VALUE, FieldUnit::NONE );
+ }
+ break;
+ case CombinedEnumContext(Application::WriterVariants, Context::Default):
+ case CombinedEnumContext(Application::WriterVariants, Context::Text):
+ case CombinedEnumContext(Application::WriterVariants, Context::Table):
+ {
+ mxLeftIndent->set_min( NEGA_MAXVALUE, FieldUnit::MM_100TH );
+ mxRightIndent->set_min( NEGA_MAXVALUE, FieldUnit::MM_100TH );
+ mxFLineIndent->set_min( NEGA_MAXVALUE, FieldUnit::MM_100TH );
+ }
+ break;
+ }
+
+ bool bDisabled = eState == SfxItemState::DISABLED;
+ mxLeftIndent->set_sensitive(!bDisabled);
+ mxRightIndent->set_sensitive(!bDisabled);
+ mxFLineIndent->set_sensitive(!bDisabled);
+
+ if (pState && eState >= SfxItemState::DEFAULT)
+ {
+ const SvxLRSpaceItem* pSpace = static_cast<const SvxLRSpaceItem*>(pState);
+ maTxtLeft = pSpace->GetTextLeft();
+ maTxtLeft = OutputDevice::LogicToLogic(maTxtLeft, m_eLRSpaceUnit, MapUnit::MapTwip);
+
+ tools::Long aTxtRight = pSpace->GetRight();
+ aTxtRight = OutputDevice::LogicToLogic(aTxtRight, m_eLRSpaceUnit, MapUnit::MapTwip);
+
+ tools::Long aTxtFirstLineOfst = pSpace->GetTextFirstLineOffset();
+ aTxtFirstLineOfst = OutputDevice::LogicToLogic( aTxtFirstLineOfst, m_eLRSpaceUnit, MapUnit::MapTwip );
+
+ tools::Long nVal = o3tl::convert(maTxtLeft, o3tl::Length::twip, o3tl::Length::mm100);
+ nVal = static_cast<tools::Long>(mxLeftIndent->normalize( nVal ));
+
+ if ( maContext.GetCombinedContext_DI() != CombinedEnumContext(Application::WriterVariants, Context::Text)
+ && maContext.GetCombinedContext_DI() != CombinedEnumContext(Application::WriterVariants, Context::Default)
+ && maContext.GetCombinedContext_DI() != CombinedEnumContext(Application::WriterVariants, Context::Table))
+ {
+ mxFLineIndent->set_min( nVal*-1, FieldUnit::MM_100TH );
+ }
+
+ tools::Long nrVal = o3tl::convert(aTxtRight, o3tl::Length::twip, o3tl::Length::mm100);
+ nrVal = static_cast<tools::Long>(mxRightIndent->normalize( nrVal ));
+
+ switch (maContext.GetCombinedContext_DI())
+ {
+ case CombinedEnumContext(Application::WriterVariants, Context::DrawText):
+ case CombinedEnumContext(Application::WriterVariants, Context::Text):
+ case CombinedEnumContext(Application::WriterVariants, Context::Default):
+ case CombinedEnumContext(Application::WriterVariants, Context::Table):
+ case CombinedEnumContext(Application::WriterVariants, Context::Annotation):
+ {
+ mxLeftIndent->set_max( MAX_SW - nrVal, FieldUnit::MM_100TH );
+ mxRightIndent->set_max( MAX_SW - nVal, FieldUnit::MM_100TH );
+ mxFLineIndent->set_max( MAX_SW - nVal - nrVal, FieldUnit::MM_100TH );
+ }
+ break;
+ case CombinedEnumContext(Application::DrawImpress, Context::DrawText):
+ case CombinedEnumContext(Application::DrawImpress, Context::Draw):
+ case CombinedEnumContext(Application::DrawImpress, Context::Table):
+ case CombinedEnumContext(Application::DrawImpress, Context::TextObject):
+ case CombinedEnumContext(Application::DrawImpress, Context::Graphic):
+ {
+ mxLeftIndent->set_max( MAX_SC_SD - nrVal, FieldUnit::MM_100TH );
+ mxRightIndent->set_max( MAX_SC_SD - nVal, FieldUnit::MM_100TH );
+ mxFLineIndent->set_max( MAX_SC_SD - nVal - nrVal, FieldUnit::MM_100TH );
+ }
+ }
+
+ mxLeftIndent->set_value( nVal, FieldUnit::MM_100TH );
+ mxRightIndent->set_value( nrVal, FieldUnit::MM_100TH );
+
+ tools::Long nfVal = o3tl::convert(aTxtFirstLineOfst, o3tl::Length::twip, o3tl::Length::mm100);
+ nfVal = static_cast<tools::Long>(mxFLineIndent->normalize( nfVal ));
+ mxFLineIndent->set_value( nfVal, FieldUnit::MM_100TH );
+ }
+ else if (eState != SfxItemState::DISABLED )
+ {
+ mxLeftIndent->set_text("");
+ mxRightIndent->set_text("");
+ mxFLineIndent->set_text("");
+ }
+
+ limitMetricWidths();
+}
+
+void ParaPropertyPanel::StateChangedULImpl( SfxItemState eState, const SfxPoolItem* pState )
+{
+ mxTopDist->set_max( mxTopDist->normalize( MAX_DURCH ), MapToFieldUnit(m_eULSpaceUnit) );
+ mxBottomDist->set_max( mxBottomDist->normalize( MAX_DURCH ), MapToFieldUnit(m_eULSpaceUnit) );
+
+ bool bDisabled = eState == SfxItemState::DISABLED;
+ mxTopDist->set_sensitive(!bDisabled);
+ mxBottomDist->set_sensitive(!bDisabled);
+
+ if( pState && eState >= SfxItemState::DEFAULT )
+ {
+ const SvxULSpaceItem* pOldItem = static_cast<const SvxULSpaceItem*>(pState);
+
+ maUpper = pOldItem->GetUpper();
+ maUpper = OutputDevice::LogicToLogic(maUpper, m_eULSpaceUnit, MapUnit::MapTwip);
+
+ maLower = pOldItem->GetLower();
+ maLower = OutputDevice::LogicToLogic(maLower, m_eULSpaceUnit, MapUnit::MapTwip);
+
+ sal_Int64 nVal = o3tl::convert(maUpper, o3tl::Length::twip, o3tl::Length::mm100);
+ nVal = mxTopDist->normalize( nVal );
+ mxTopDist->set_value( nVal, FieldUnit::MM_100TH );
+
+ nVal = o3tl::convert(maLower, o3tl::Length::twip, o3tl::Length::mm100);
+ nVal = mxBottomDist->normalize( nVal );
+ mxBottomDist->set_value( nVal, FieldUnit::MM_100TH );
+ }
+ else if (eState != SfxItemState::DISABLED )
+ {
+ mxTopDist->set_text("");
+ mxBottomDist->set_text("");
+ }
+ limitMetricWidths();
+}
+
+FieldUnit ParaPropertyPanel::GetCurrentUnit( SfxItemState eState, const SfxPoolItem* pState )
+{
+ FieldUnit eUnit = FieldUnit::NONE;
+
+ if ( pState && eState >= SfxItemState::DEFAULT )
+ eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pState)->GetValue());
+ else
+ {
+ SfxViewFrame* pFrame = SfxViewFrame::Current();
+ SfxObjectShell* pSh = nullptr;
+ if ( pFrame )
+ pSh = pFrame->GetObjectShell();
+ if ( pSh ) //the object shell is not always available during reload
+ {
+ SfxModule* pModule = pSh->GetModule();
+ if ( pModule )
+ {
+ const SfxPoolItem* pItem = pModule->GetItem( SID_ATTR_METRIC );
+ if ( pItem )
+ eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pItem)->GetValue());
+ }
+ else
+ {
+ SAL_WARN("svx.sidebar", "GetModuleFieldUnit(): no module found");
+ }
+ }
+ }
+
+ return eUnit;
+}
+
+ParaPropertyPanel::ParaPropertyPanel(weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+ : PanelLayout(pParent, "ParaPropertyPanel", "svx/ui/sidebarparagraph.ui"),
+ //Alignment
+ mxTBxHorzAlign(m_xBuilder->weld_toolbar("horizontalalignment")),
+ mxHorzAlignDispatch(new ToolbarUnoDispatcher(*mxTBxHorzAlign, *m_xBuilder, rxFrame)),
+ mxTBxVertAlign(m_xBuilder->weld_toolbar("verticalalignment")),
+ mxVertAlignDispatch(new ToolbarUnoDispatcher(*mxTBxVertAlign, *m_xBuilder, rxFrame)),
+ //NumBullet&Backcolor
+ mxTBxNumBullet(m_xBuilder->weld_toolbar("numberbullet")),
+ mxNumBulletDispatch(new ToolbarUnoDispatcher(*mxTBxNumBullet, *m_xBuilder, rxFrame)),
+ mxTBxBackColor(m_xBuilder->weld_toolbar("backgroundcolor")),
+ mxBackColorDispatch(new ToolbarUnoDispatcher(*mxTBxBackColor, *m_xBuilder, rxFrame)),
+ mxTBxWriteDirection(m_xBuilder->weld_toolbar("writedirection")),
+ mxWriteDirectionDispatch(new ToolbarUnoDispatcher(*mxTBxWriteDirection, *m_xBuilder, rxFrame)),
+ mxTBxParaSpacing(m_xBuilder->weld_toolbar("paraspacing")),
+ mxParaSpacingDispatch(new ToolbarUnoDispatcher(*mxTBxParaSpacing, *m_xBuilder, rxFrame)),
+ mxTBxLineSpacing(m_xBuilder->weld_toolbar("linespacing")),
+ mxLineSpacingDispatch(new ToolbarUnoDispatcher(*mxTBxLineSpacing, *m_xBuilder, rxFrame)),
+ mxTBxIndent(m_xBuilder->weld_toolbar("indent")),
+ mxIndentDispatch(new ToolbarUnoDispatcher(*mxTBxIndent, *m_xBuilder, rxFrame)),
+ //Paragraph spacing
+ mxTopDist(new SvxRelativeField(m_xBuilder->weld_metric_spin_button("aboveparaspacing", FieldUnit::CM))),
+ mxBottomDist(new SvxRelativeField(m_xBuilder->weld_metric_spin_button("belowparaspacing", FieldUnit::CM))),
+ mxLeftIndent(new SvxRelativeField(m_xBuilder->weld_metric_spin_button("beforetextindent", FieldUnit::CM))),
+ mxRightIndent(new SvxRelativeField(m_xBuilder->weld_metric_spin_button("aftertextindent", FieldUnit::CM))),
+ mxFLineIndent(new SvxRelativeField(m_xBuilder->weld_metric_spin_button("firstlineindent", FieldUnit::CM))),
+ maTxtLeft (0),
+ maUpper (0),
+ maLower (0),
+ m_eMetricUnit(FieldUnit::NONE),
+ m_last_eMetricUnit(FieldUnit::NONE),
+ m_eLRSpaceUnit(),
+ m_eULSpaceUnit(),
+ maLRSpaceControl (SID_ATTR_PARA_LRSPACE,*pBindings,*this),
+ maULSpaceControl (SID_ATTR_PARA_ULSPACE, *pBindings,*this),
+ m_aMetricCtl (SID_ATTR_METRIC, *pBindings,*this),
+ mpBindings(pBindings),
+ mxSidebar(rxSidebar)
+{
+ // tdf#130197 We want to give this toolbar a width as if it had 5 entries
+ // (the parent grid has homogeneous width set so both columns will have the
+ // same width). This ParaPropertyPanel is a default panel in writer, so
+ // subsequent panels, e.g. the TableEditPanel panel can have up to 5
+ // entries in each of its column and remain in alignment with this panel
+ padWidthForSidebar(*mxTBxIndent, rxFrame);
+
+ initial();
+ m_aMetricCtl.RequestUpdate();
+}
+
+void ParaPropertyPanel::limitMetricWidths()
+{
+ limitWidthForSidebar(*mxTopDist);
+ limitWidthForSidebar(*mxBottomDist);
+ limitWidthForSidebar(*mxLeftIndent);
+ limitWidthForSidebar(*mxRightIndent);
+ limitWidthForSidebar(*mxFLineIndent);
+}
+
+ParaPropertyPanel::~ParaPropertyPanel()
+{
+ mxHorzAlignDispatch.reset();
+ mxTBxHorzAlign.reset();
+
+ mxVertAlignDispatch.reset();
+ mxTBxVertAlign.reset();
+
+ mxNumBulletDispatch.reset();
+ mxTBxNumBullet.reset();
+
+ mxBackColorDispatch.reset();
+ mxTBxBackColor.reset();
+
+ mxWriteDirectionDispatch.reset();
+ mxTBxWriteDirection.reset();
+
+ mxParaSpacingDispatch.reset();
+ mxTBxParaSpacing.reset();
+
+ mxLineSpacingDispatch.reset();
+ mxTBxLineSpacing.reset();
+
+ mxIndentDispatch.reset();
+ mxTBxIndent.reset();
+
+ mxTopDist.reset();
+ mxBottomDist.reset();
+ mxLeftIndent.reset();
+ mxRightIndent.reset();
+ mxFLineIndent.reset();
+
+ maLRSpaceControl.dispose();
+ maULSpaceControl.dispose();
+ m_aMetricCtl.dispose();
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/paragraph/ParaPropertyPanel.hxx b/svx/source/sidebar/paragraph/ParaPropertyPanel.hxx
new file mode 100644
index 000000000..bd252eb1a
--- /dev/null
+++ b/svx/source/sidebar/paragraph/ParaPropertyPanel.hxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/IContextChangeReceiver.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <svx/relfld.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/ui/XSidebar.hpp>
+
+#include <svl/poolitem.hxx>
+#include <tools/fldunit.hxx>
+#include <vcl/EnumContext.hxx>
+
+class ToolbarUnoDispatcher;
+
+namespace svx::sidebar {
+
+class ParaPropertyPanel
+ : public PanelLayout,
+ public ::sfx2::sidebar::IContextChangeReceiver,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+ virtual ~ParaPropertyPanel() override;
+
+ static std::unique_ptr<PanelLayout> Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+
+ SfxBindings* GetBindings() { return mpBindings;}
+
+ virtual void HandleContextChange (
+ const vcl::EnumContext& rContext) override;
+
+ virtual void NotifyItemUpdate(
+ const sal_uInt16 nSId,
+ const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(
+ const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override {};
+
+ static FieldUnit GetCurrentUnit( SfxItemState eState, const SfxPoolItem* pState );
+
+ ParaPropertyPanel (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+
+private:
+ // UI controls
+ //Alignment
+ std::unique_ptr<weld::Toolbar> mxTBxHorzAlign;
+ std::unique_ptr<ToolbarUnoDispatcher> mxHorzAlignDispatch;
+ std::unique_ptr<weld::Toolbar> mxTBxVertAlign;
+ std::unique_ptr<ToolbarUnoDispatcher> mxVertAlignDispatch;
+ //NumBullet&Backcolor
+ std::unique_ptr<weld::Toolbar> mxTBxNumBullet;
+ std::unique_ptr<ToolbarUnoDispatcher> mxNumBulletDispatch;
+ std::unique_ptr<weld::Toolbar> mxTBxBackColor;
+ std::unique_ptr<ToolbarUnoDispatcher> mxBackColorDispatch;
+
+ std::unique_ptr<weld::Toolbar> mxTBxWriteDirection;
+ std::unique_ptr<ToolbarUnoDispatcher> mxWriteDirectionDispatch;
+ std::unique_ptr<weld::Toolbar> mxTBxParaSpacing;
+ std::unique_ptr<ToolbarUnoDispatcher> mxParaSpacingDispatch;
+ std::unique_ptr<weld::Toolbar> mxTBxLineSpacing;
+ std::unique_ptr<ToolbarUnoDispatcher> mxLineSpacingDispatch;
+ std::unique_ptr<weld::Toolbar> mxTBxIndent;
+ std::unique_ptr<ToolbarUnoDispatcher> mxIndentDispatch;
+
+ //Paragraph spacing
+ std::unique_ptr<SvxRelativeField> mxTopDist;
+ std::unique_ptr<SvxRelativeField> mxBottomDist;
+ std::unique_ptr<SvxRelativeField> mxLeftIndent;
+ std::unique_ptr<SvxRelativeField> mxRightIndent;
+ std::unique_ptr<SvxRelativeField> mxFLineIndent;
+
+ // Data Member
+ tools::Long maTxtLeft;
+ tools::Long maUpper;
+ tools::Long maLower;
+
+ FieldUnit m_eMetricUnit;
+ FieldUnit m_last_eMetricUnit;
+ MapUnit m_eLRSpaceUnit;
+ MapUnit m_eULSpaceUnit;
+ // Control Items
+ ::sfx2::sidebar::ControllerItem maLRSpaceControl;
+ ::sfx2::sidebar::ControllerItem maULSpaceControl;
+ ::sfx2::sidebar::ControllerItem m_aMetricCtl;
+
+ vcl::EnumContext maContext;
+ SfxBindings* mpBindings;
+ css::uno::Reference<css::ui::XSidebar> mxSidebar;
+
+ DECL_LINK(ModifyIndentHdl_Impl, weld::MetricSpinButton&, void);
+ DECL_LINK(ULSpaceHdl_Impl, weld::MetricSpinButton&, void);
+
+ void StateChangedIndentImpl( SfxItemState eState, const SfxPoolItem* pState );
+ void StateChangedULImpl( SfxItemState eState, const SfxPoolItem* pState );
+
+ void initial();
+ void ReSize();
+ void InitToolBoxIndent();
+ void InitToolBoxSpacing();
+ void limitMetricWidths();
+};
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/paragraph/ParaSpacingControl.cxx b/svx/source/sidebar/paragraph/ParaSpacingControl.cxx
new file mode 100644
index 000000000..5b4c40969
--- /dev/null
+++ b/svx/source/sidebar/paragraph/ParaSpacingControl.cxx
@@ -0,0 +1,257 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ParaSpacingWindow.hxx"
+
+#include <cppuhelper/queryinterface.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/editids.hrc>
+#include <svx/ParaSpacingControl.hxx>
+#include <vcl/toolbox.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svl/intitem.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/ui/ContextChangeEventMultiplexer.hpp>
+#include <com/sun/star/ui/XContextChangeEventMultiplexer.hpp>
+
+using namespace svx;
+
+SFX_IMPL_TOOLBOX_CONTROL(ParaAboveSpacingControl, SvxULSpaceItem);
+SFX_IMPL_TOOLBOX_CONTROL(ParaBelowSpacingControl, SvxULSpaceItem);
+
+SFX_IMPL_TOOLBOX_CONTROL(ParaLeftSpacingControl, SvxLRSpaceItem);
+SFX_IMPL_TOOLBOX_CONTROL(ParaRightSpacingControl, SvxLRSpaceItem);
+SFX_IMPL_TOOLBOX_CONTROL(ParaFirstLineSpacingControl, SvxLRSpaceItem);
+
+ParaULSpacingControl::ParaULSpacingControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx)
+ : SfxToolBoxControl(nSlotId, nId, rTbx)
+{
+ addStatusListener(".uno:MetricUnit");
+}
+
+ParaULSpacingControl::~ParaULSpacingControl()
+{
+}
+
+void ParaULSpacingControl::StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ ToolBoxItemId nId = GetId();
+ ToolBox& rTbx = GetToolBox();
+ ParaULSpacingWindow* pWindow = static_cast<ParaULSpacingWindow*>(rTbx.GetItemWindow(nId));
+
+ DBG_ASSERT( pWindow, "Control not found!" );
+
+ if(SfxItemState::DISABLED == eState)
+ pWindow->Disable();
+ else
+ pWindow->Enable();
+
+ rTbx.EnableItem(nId, SfxItemState::DISABLED != eState);
+
+ if(nSID == SID_ATTR_METRIC && pState && eState >= SfxItemState::DEFAULT)
+ {
+ const SfxUInt16Item* pMetricItem = static_cast<const SfxUInt16Item*>(pState);
+ pWindow->SetUnit(static_cast<FieldUnit>(pMetricItem->GetValue()));
+ }
+ else if((nSID == SID_ATTR_PARA_ULSPACE
+ || nSID == SID_ATTR_PARA_ABOVESPACE
+ || nSID == SID_ATTR_PARA_BELOWSPACE )
+ && pState && eState >= SfxItemState::DEFAULT)
+ pWindow->SetValue(static_cast<const SvxULSpaceItem*>(pState));
+}
+
+// ParaAboveSpacingControl
+
+ParaAboveSpacingControl::ParaAboveSpacingControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx)
+ : ParaULSpacingControl(nSlotId, nId, rTbx)
+{
+}
+
+VclPtr<InterimItemWindow> ParaAboveSpacingControl::CreateItemWindow(vcl::Window* pParent)
+{
+ VclPtr<ParaAboveSpacingWindow> pWindow = VclPtr<ParaAboveSpacingWindow>::Create(pParent);
+ pWindow->Show();
+
+ return pWindow;
+}
+
+// ParaBelowSpacingControl
+
+ParaBelowSpacingControl::ParaBelowSpacingControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx)
+ : ParaULSpacingControl(nSlotId, nId, rTbx)
+{
+}
+
+VclPtr<InterimItemWindow> ParaBelowSpacingControl::CreateItemWindow(vcl::Window* pParent)
+{
+ VclPtr<ParaBelowSpacingWindow> pWindow = VclPtr<ParaBelowSpacingWindow>::Create(pParent);
+ pWindow->Show();
+
+ return pWindow;
+}
+
+// ParaLRSpacingControl
+
+ParaLRSpacingControl::ParaLRSpacingControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx)
+ : SfxToolBoxControl(nSlotId, nId, rTbx)
+{
+ addStatusListener(".uno:MetricUnit");
+}
+
+ParaLRSpacingControl::~ParaLRSpacingControl()
+{
+}
+
+void SAL_CALL ParaLRSpacingControl::dispose()
+{
+ if(m_xMultiplexer.is())
+ {
+ m_xMultiplexer->removeAllContextChangeEventListeners(this);
+ m_xMultiplexer.clear();
+ }
+
+ SfxToolBoxControl::dispose();
+}
+
+void ParaLRSpacingControl::StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ ToolBoxItemId nId = GetId();
+ ToolBox& rTbx = GetToolBox();
+ ParaLRSpacingWindow* pWindow = static_cast<ParaLRSpacingWindow*>(rTbx.GetItemWindow(nId));
+
+ DBG_ASSERT( pWindow, "Control not found!" );
+
+ if(SfxItemState::DISABLED == eState)
+ pWindow->Disable();
+ else
+ pWindow->Enable();
+
+ if(!m_xMultiplexer.is() && m_xFrame.is())
+ {
+ m_xMultiplexer = css::ui::ContextChangeEventMultiplexer::get(
+ ::comphelper::getProcessComponentContext());
+
+ m_xMultiplexer->addContextChangeEventListener(this, m_xFrame->getController());
+ }
+
+ if(nSID == SID_ATTR_METRIC && pState && eState >= SfxItemState::DEFAULT)
+ {
+ const SfxUInt16Item* pMetricItem = static_cast<const SfxUInt16Item*>(pState);
+ pWindow->SetUnit(static_cast<FieldUnit>(pMetricItem->GetValue()));
+ }
+ else if(nSID == SID_ATTR_PARA_LRSPACE
+ || nSID == SID_ATTR_PARA_LEFTSPACE
+ || nSID == SID_ATTR_PARA_RIGHTSPACE
+ || nSID == SID_ATTR_PARA_FIRSTLINESPACE
+ )
+ {
+ pWindow->SetValue(eState, pState);
+ }
+}
+
+void SAL_CALL ParaLRSpacingControl::notifyContextChangeEvent(const css::ui::ContextChangeEventObject& rEvent)
+{
+ ToolBoxItemId nId = GetId();
+ ToolBox& rTbx = GetToolBox();
+ ParaLRSpacingWindow* pWindow = static_cast<ParaLRSpacingWindow*>(rTbx.GetItemWindow(nId));
+
+ if(pWindow)
+ {
+ vcl::EnumContext eContext(
+ vcl::EnumContext::GetApplicationEnum(rEvent.ApplicationName),
+ vcl::EnumContext::GetContextEnum(rEvent.ContextName));
+ pWindow->SetContext(eContext);
+ }
+}
+
+::css::uno::Any SAL_CALL ParaLRSpacingControl::queryInterface(const ::css::uno::Type& aType)
+{
+ ::css::uno::Any a(SfxToolBoxControl::queryInterface(aType));
+ if (a.hasValue())
+ return a;
+
+ return ::cppu::queryInterface(aType, static_cast<css::ui::XContextChangeEventListener*>(this));
+}
+
+void SAL_CALL ParaLRSpacingControl::acquire() noexcept
+{
+ SfxToolBoxControl::acquire();
+}
+
+void SAL_CALL ParaLRSpacingControl::disposing(const ::css::lang::EventObject&)
+{
+ SfxToolBoxControl::disposing();
+}
+
+void SAL_CALL ParaLRSpacingControl::release() noexcept
+{
+ SfxToolBoxControl::release();
+}
+
+// ParaLeftSpacingControl
+
+ParaLeftSpacingControl::ParaLeftSpacingControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx)
+: ParaLRSpacingControl(nSlotId, nId, rTbx)
+{
+}
+
+VclPtr<InterimItemWindow> ParaLeftSpacingControl::CreateItemWindow(vcl::Window* pParent)
+{
+ VclPtr<ParaLeftSpacingWindow> pWindow = VclPtr<ParaLeftSpacingWindow>::Create(pParent);
+ pWindow->Show();
+
+ return pWindow;
+}
+
+// ParaRightSpacingControl
+
+ParaRightSpacingControl::ParaRightSpacingControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx)
+: ParaLRSpacingControl(nSlotId, nId, rTbx)
+{
+}
+
+VclPtr<InterimItemWindow> ParaRightSpacingControl::CreateItemWindow(vcl::Window* pParent)
+{
+ VclPtr<ParaRightSpacingWindow> pWindow = VclPtr<ParaRightSpacingWindow>::Create(pParent);
+ pWindow->Show();
+
+ return pWindow;
+}
+
+// ParaFirstLineSpacingControl
+
+ParaFirstLineSpacingControl::ParaFirstLineSpacingControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx)
+: ParaLRSpacingControl(nSlotId, nId, rTbx)
+{
+}
+
+VclPtr<InterimItemWindow> ParaFirstLineSpacingControl::CreateItemWindow(vcl::Window* pParent)
+{
+ VclPtr<ParaFirstLineSpacingWindow> pWindow = VclPtr<ParaFirstLineSpacingWindow>::Create(pParent);
+ pWindow->Show();
+
+ return pWindow;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/paragraph/ParaSpacingWindow.cxx b/svx/source/sidebar/paragraph/ParaSpacingWindow.cxx
new file mode 100644
index 000000000..fa164dd02
--- /dev/null
+++ b/svx/source/sidebar/paragraph/ParaSpacingWindow.cxx
@@ -0,0 +1,341 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ParaSpacingWindow.hxx"
+#include <editeng/editids.hrc>
+#include <editeng/lrspitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/itempool.hxx>
+
+using namespace svx;
+
+#define DEFAULT_VALUE 0
+#define MAX_DURCH 31680 // tdf#68335: 1584 pt for UX interoperability with Word
+#define MAX_SW 1709400
+#define MAX_SC_SD 116220200
+#define NEGA_MAXVALUE -10000000
+
+// ParaULSpacingWindow
+
+ParaULSpacingWindow::ParaULSpacingWindow(vcl::Window* pParent)
+ : InterimItemWindow(pParent, "svx/ui/paraulspacing.ui", "ParaULSpacingWindow")
+ , m_eUnit(MapUnit::MapTwip)
+{
+ m_xAboveSpacing = std::make_unique<SvxRelativeField>(m_xBuilder->weld_metric_spin_button("aboveparaspacing", FieldUnit::CM));
+ m_xBelowSpacing = std::make_unique<SvxRelativeField>(m_xBuilder->weld_metric_spin_button("belowparaspacing", FieldUnit::CM));
+ m_xAboveContainer = m_xBuilder->weld_container("above");
+ m_xBelowContainer = m_xBuilder->weld_container("below");
+
+ Link<weld::MetricSpinButton&,void> aLink = LINK(this, ParaULSpacingWindow, ModifySpacingHdl);
+ m_xAboveSpacing->connect_value_changed(aLink);
+ m_xBelowSpacing->connect_value_changed(aLink);
+
+ /// set the initial values of max width
+ m_xAboveSpacing->set_max(m_xAboveSpacing->normalize(MAX_DURCH), FieldUnit::CM);
+ m_xBelowSpacing->set_max(m_xBelowSpacing->normalize(MAX_DURCH), FieldUnit::CM);
+}
+
+ParaULSpacingWindow::~ParaULSpacingWindow()
+{
+ disposeOnce();
+}
+
+void ParaULSpacingWindow::dispose()
+{
+ m_xAboveSpacing.reset();
+ m_xBelowSpacing.reset();
+ m_xAboveContainer.reset();
+ m_xBelowContainer.reset();
+
+ InterimItemWindow::dispose();
+}
+
+void ParaULSpacingWindow::SetUnit(FieldUnit eUnit)
+{
+ m_xAboveSpacing->SetFieldUnit(eUnit);
+ m_xBelowSpacing->SetFieldUnit(eUnit);
+
+ SfxItemPool &rPool = SfxGetpApp()->GetPool();
+ m_eUnit = rPool.GetMetric(SID_ATTR_PARA_ULSPACE);
+
+ m_xAboveSpacing->set_max(m_xAboveSpacing->normalize(MAX_DURCH), MapToFieldUnit(m_eUnit));
+ m_xBelowSpacing->set_max(m_xBelowSpacing->normalize(MAX_DURCH), MapToFieldUnit(m_eUnit));
+}
+
+void ParaULSpacingWindow::SetValue(const SvxULSpaceItem* pItem)
+{
+ sal_Int64 nVal = pItem->GetUpper();
+ nVal = m_xAboveSpacing->normalize(nVal);
+ m_xAboveSpacing->set_value(nVal, FieldUnit::MM_100TH);
+
+ nVal = pItem->GetLower();
+ nVal = m_xBelowSpacing->normalize(nVal);
+ m_xBelowSpacing->set_value(nVal, FieldUnit::MM_100TH);
+}
+
+IMPL_LINK_NOARG(ParaULSpacingWindow, ModifySpacingHdl, weld::MetricSpinButton&, void)
+{
+ SfxViewFrame* pFrame = SfxViewFrame::Current();
+ if (!pFrame)
+ return;
+ SfxDispatcher* pDisp = pFrame->GetBindings().GetDispatcher();
+ if(pDisp)
+ {
+ SvxULSpaceItem aMargin(SID_ATTR_PARA_ULSPACE);
+ aMargin.SetUpper(m_xAboveSpacing->GetCoreValue(m_eUnit));
+ aMargin.SetLower(m_xBelowSpacing->GetCoreValue(m_eUnit));
+ pDisp->ExecuteList(SID_ATTR_PARA_ULSPACE, SfxCallMode::RECORD, {&aMargin});
+ }
+}
+
+// ParaAboveSpacingWindow
+ParaAboveSpacingWindow::ParaAboveSpacingWindow(vcl::Window* pParent)
+ : ParaULSpacingWindow(pParent)
+{
+ InitControlBase(&m_xAboveSpacing->get_widget());
+
+ m_xAboveContainer->show();
+ m_xBelowContainer->hide();
+
+ SetSizePixel(get_preferred_size());
+}
+
+// ParaBelowSpacingWindow
+ParaBelowSpacingWindow::ParaBelowSpacingWindow(vcl::Window* pParent)
+ : ParaULSpacingWindow(pParent)
+{
+ InitControlBase(&m_xBelowSpacing->get_widget());
+
+ m_xAboveContainer->hide();
+ m_xBelowContainer->show();
+
+ SetSizePixel(get_preferred_size());
+}
+
+// ParaLRSpacingWindow
+ParaLRSpacingWindow::ParaLRSpacingWindow(vcl::Window* pParent)
+ : InterimItemWindow(pParent, "svx/ui/paralrspacing.ui", "ParaLRSpacingWindow")
+ , m_eUnit(MapUnit::MapTwip)
+{
+ m_xBeforeSpacing = std::make_unique<SvxRelativeField>(m_xBuilder->weld_metric_spin_button("beforetextindent", FieldUnit::CM));
+ m_xAfterSpacing = std::make_unique<SvxRelativeField>(m_xBuilder->weld_metric_spin_button("aftertextindent", FieldUnit::CM));
+ m_xFLSpacing = std::make_unique<SvxRelativeField>(m_xBuilder->weld_metric_spin_button("firstlineindent", FieldUnit::CM));
+ m_xBeforeContainer = m_xBuilder->weld_container("before");
+ m_xAfterContainer = m_xBuilder->weld_container("after");
+ m_xFirstLineContainer = m_xBuilder->weld_container("firstline");
+
+ Link<weld::MetricSpinButton&,void> aLink = LINK(this, ParaLRSpacingWindow, ModifySpacingHdl);
+ m_xBeforeSpacing->connect_value_changed(aLink);
+ m_xAfterSpacing->connect_value_changed(aLink);
+ m_xFLSpacing->connect_value_changed(aLink);
+
+ /// set the initial values of max width
+ m_xBeforeSpacing->set_min(NEGA_MAXVALUE, FieldUnit::MM_100TH);
+ m_xAfterSpacing->set_min(NEGA_MAXVALUE, FieldUnit::MM_100TH);
+ m_xFLSpacing->set_min(NEGA_MAXVALUE, FieldUnit::MM_100TH);
+}
+
+ParaLRSpacingWindow::~ParaLRSpacingWindow()
+{
+ disposeOnce();
+}
+
+void ParaLRSpacingWindow::dispose()
+{
+ m_xBeforeSpacing.reset();
+ m_xAfterSpacing.reset();
+ m_xFLSpacing.reset();
+ m_xBeforeContainer.reset();
+ m_xAfterContainer.reset();
+ m_xFirstLineContainer.reset();
+
+ InterimItemWindow::dispose();
+}
+
+void ParaLRSpacingWindow::SetContext(const vcl::EnumContext& eContext)
+{
+ m_aContext = eContext;
+}
+
+void ParaLRSpacingWindow::SetValue(SfxItemState eState, const SfxPoolItem* pState)
+{
+ switch(m_aContext.GetCombinedContext_DI())
+ {
+
+ case CombinedEnumContext(Application::WriterVariants, Context::DrawText):
+ case CombinedEnumContext(Application::WriterVariants, Context::Annotation):
+ case CombinedEnumContext(Application::Calc, Context::DrawText):
+ case CombinedEnumContext(Application::DrawImpress, Context::DrawText):
+ case CombinedEnumContext(Application::DrawImpress, Context::Draw):
+ case CombinedEnumContext(Application::DrawImpress, Context::TextObject):
+ case CombinedEnumContext(Application::DrawImpress, Context::Graphic):
+ case CombinedEnumContext(Application::DrawImpress, Context::Table):
+ {
+ m_xBeforeSpacing->set_min(DEFAULT_VALUE, FieldUnit::NONE);
+ m_xAfterSpacing->set_min(DEFAULT_VALUE, FieldUnit::NONE);
+ m_xFLSpacing->set_min(DEFAULT_VALUE, FieldUnit::NONE);
+ }
+ break;
+ case CombinedEnumContext(Application::WriterVariants, Context::Default):
+ case CombinedEnumContext(Application::WriterVariants, Context::Text):
+ case CombinedEnumContext(Application::WriterVariants, Context::Table):
+ {
+ m_xBeforeSpacing->set_min(NEGA_MAXVALUE, FieldUnit::MM_100TH);
+ m_xAfterSpacing->set_min(NEGA_MAXVALUE, FieldUnit::MM_100TH);
+ m_xFLSpacing->set_min(NEGA_MAXVALUE, FieldUnit::MM_100TH);
+ }
+ break;
+ }
+
+ if(pState && eState >= SfxItemState::DEFAULT)
+ {
+ m_xBeforeSpacing->set_sensitive(true);
+ m_xAfterSpacing->set_sensitive(true);
+ m_xFLSpacing->set_sensitive(true);
+
+ const SvxLRSpaceItem* pSpace = static_cast<const SvxLRSpaceItem*>(pState);
+ tools::Long aTxtLeft = pSpace->GetTextLeft();
+ tools::Long aTxtRight = pSpace->GetRight();
+ tools::Long aTxtFirstLineOfst = pSpace->GetTextFirstLineOffset();
+
+ aTxtLeft = m_xBeforeSpacing->normalize(aTxtLeft);
+
+ if(m_aContext.GetCombinedContext_DI() != CombinedEnumContext(Application::WriterVariants, Context::Text)
+ && m_aContext.GetCombinedContext_DI() != CombinedEnumContext(Application::WriterVariants, Context::Default)
+ && m_aContext.GetCombinedContext_DI() != CombinedEnumContext(Application::WriterVariants, Context::Table))
+ {
+ m_xFLSpacing->set_min(aTxtLeft*-1, FieldUnit::MM_100TH);
+ }
+
+ aTxtRight = m_xAfterSpacing->normalize(aTxtRight);
+
+ switch(m_aContext.GetCombinedContext_DI())
+ {
+ case CombinedEnumContext(Application::WriterVariants, Context::DrawText):
+ case CombinedEnumContext(Application::WriterVariants, Context::Text):
+ case CombinedEnumContext(Application::WriterVariants, Context::Default):
+ case CombinedEnumContext(Application::WriterVariants, Context::Table):
+ case CombinedEnumContext(Application::WriterVariants, Context::Annotation):
+ {
+ m_xBeforeSpacing->set_max(MAX_SW - aTxtRight, FieldUnit::MM_100TH);
+ m_xAfterSpacing->set_max(MAX_SW - aTxtLeft, FieldUnit::MM_100TH);
+ m_xFLSpacing->set_max(MAX_SW - aTxtLeft - aTxtRight, FieldUnit::MM_100TH);
+ }
+ break;
+ case CombinedEnumContext(Application::DrawImpress, Context::DrawText):
+ case CombinedEnumContext(Application::DrawImpress, Context::Draw):
+ case CombinedEnumContext(Application::DrawImpress, Context::Table):
+ case CombinedEnumContext(Application::DrawImpress, Context::TextObject):
+ case CombinedEnumContext(Application::DrawImpress, Context::Graphic):
+ {
+ m_xBeforeSpacing->set_max(MAX_SC_SD - aTxtRight, FieldUnit::MM_100TH);
+ m_xAfterSpacing->set_max(MAX_SC_SD - aTxtLeft, FieldUnit::MM_100TH);
+ m_xFLSpacing->set_max(MAX_SC_SD - aTxtLeft - aTxtRight, FieldUnit::MM_100TH);
+ }
+ }
+
+ m_xBeforeSpacing->set_value(aTxtLeft, FieldUnit::MM_100TH);
+ m_xAfterSpacing->set_value(aTxtRight, FieldUnit::MM_100TH);
+
+ aTxtFirstLineOfst = m_xFLSpacing->normalize(aTxtFirstLineOfst);
+ m_xFLSpacing->set_value(aTxtFirstLineOfst, FieldUnit::MM_100TH);
+ }
+ else if(eState == SfxItemState::DISABLED)
+ {
+ m_xBeforeSpacing->set_sensitive(false);
+ m_xAfterSpacing->set_sensitive(false);
+ m_xFLSpacing->set_sensitive(false);
+ }
+ else
+ {
+ m_xBeforeSpacing->set_text("");
+ m_xAfterSpacing->set_text("");
+ m_xFLSpacing->set_text("");
+ }
+}
+
+void ParaLRSpacingWindow::SetUnit(FieldUnit eUnit)
+{
+ m_xBeforeSpacing->SetFieldUnit(eUnit);
+ m_xAfterSpacing->SetFieldUnit(eUnit);
+ m_xFLSpacing->SetFieldUnit(eUnit);
+
+ SfxItemPool &rPool = SfxGetpApp()->GetPool();
+ m_eUnit = rPool.GetMetric(SID_ATTR_PARA_LRSPACE);
+}
+
+IMPL_LINK_NOARG(ParaLRSpacingWindow, ModifySpacingHdl, weld::MetricSpinButton&, void)
+{
+ SfxViewFrame* pFrame = SfxViewFrame::Current();
+ if (!pFrame)
+ return;
+ SfxDispatcher* pDisp = pFrame->GetBindings().GetDispatcher();
+ if(pDisp)
+ {
+ SvxLRSpaceItem aMargin(SID_ATTR_PARA_LRSPACE);
+ aMargin.SetTextLeft(m_xBeforeSpacing->GetCoreValue(m_eUnit));
+ aMargin.SetRight(m_xAfterSpacing->GetCoreValue(m_eUnit));
+ aMargin.SetTextFirstLineOffset(m_xFLSpacing->GetCoreValue(m_eUnit));
+
+ pDisp->ExecuteList(SID_ATTR_PARA_LRSPACE, SfxCallMode::RECORD, {&aMargin});
+ }
+}
+
+// ParaLeftSpacingWindow
+ParaLeftSpacingWindow::ParaLeftSpacingWindow(vcl::Window* pParent)
+ : ParaLRSpacingWindow(pParent)
+{
+ InitControlBase(&m_xBeforeSpacing->get_widget());
+
+ m_xBeforeContainer->show();
+ m_xAfterContainer->hide();
+ m_xFirstLineContainer->hide();
+
+ SetSizePixel(get_preferred_size());
+}
+
+// ParaRightSpacingWindow
+ParaRightSpacingWindow::ParaRightSpacingWindow(vcl::Window* pParent)
+ : ParaLRSpacingWindow(pParent)
+{
+ InitControlBase(&m_xAfterSpacing->get_widget());
+
+ m_xBeforeContainer->hide();
+ m_xAfterContainer->show();
+ m_xFirstLineContainer->hide();
+
+ SetSizePixel(get_preferred_size());
+}
+
+// ParaFirstLineSpacingWindow
+ParaFirstLineSpacingWindow::ParaFirstLineSpacingWindow(vcl::Window* pParent)
+ : ParaLRSpacingWindow(pParent)
+{
+ InitControlBase(&m_xFLSpacing->get_widget());
+
+ m_xBeforeContainer->hide();
+ m_xAfterContainer->hide();
+ m_xFirstLineContainer->show();
+
+ SetSizePixel(get_preferred_size());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/paragraph/ParaSpacingWindow.hxx b/svx/source/sidebar/paragraph/ParaSpacingWindow.hxx
new file mode 100644
index 000000000..f1730f933
--- /dev/null
+++ b/svx/source/sidebar/paragraph/ParaSpacingWindow.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <editeng/ulspitem.hxx>
+#include <vcl/EnumContext.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <svx/relfld.hxx>
+
+using namespace com::sun::star;
+
+namespace svx
+{
+class ParaULSpacingWindow : public InterimItemWindow
+{
+public:
+ virtual ~ParaULSpacingWindow() override;
+ virtual void dispose() override;
+
+ void SetValue(const SvxULSpaceItem* pItem);
+ void SetUnit(FieldUnit eUnit);
+
+protected:
+ ParaULSpacingWindow(vcl::Window* pParent);
+
+ std::unique_ptr<SvxRelativeField> m_xAboveSpacing;
+ std::unique_ptr<SvxRelativeField> m_xBelowSpacing;
+ std::unique_ptr<weld::Container> m_xAboveContainer;
+ std::unique_ptr<weld::Container> m_xBelowContainer;
+
+ MapUnit m_eUnit;
+
+ DECL_LINK(ModifySpacingHdl, weld::MetricSpinButton&, void);
+};
+
+class ParaAboveSpacingWindow : public ParaULSpacingWindow
+{
+public:
+ explicit ParaAboveSpacingWindow(vcl::Window* pParent);
+};
+
+class ParaBelowSpacingWindow : public ParaULSpacingWindow
+{
+public:
+ explicit ParaBelowSpacingWindow(vcl::Window* pParent);
+};
+
+class ParaLRSpacingWindow : public InterimItemWindow
+{
+public:
+ virtual ~ParaLRSpacingWindow() override;
+ virtual void dispose() override;
+
+ void SetValue(SfxItemState eState, const SfxPoolItem* pState);
+ void SetUnit(FieldUnit eUnit);
+ void SetContext(const vcl::EnumContext& eContext);
+
+protected:
+ ParaLRSpacingWindow(vcl::Window* pParent);
+
+ std::unique_ptr<SvxRelativeField> m_xBeforeSpacing;
+ std::unique_ptr<SvxRelativeField> m_xAfterSpacing;
+ std::unique_ptr<SvxRelativeField> m_xFLSpacing;
+ std::unique_ptr<weld::Container> m_xBeforeContainer;
+ std::unique_ptr<weld::Container> m_xAfterContainer;
+ std::unique_ptr<weld::Container> m_xFirstLineContainer;
+
+ MapUnit m_eUnit;
+
+ vcl::EnumContext m_aContext;
+
+ DECL_LINK(ModifySpacingHdl, weld::MetricSpinButton&, void);
+};
+
+class ParaLeftSpacingWindow : public ParaLRSpacingWindow
+{
+public:
+ explicit ParaLeftSpacingWindow(vcl::Window* pParent);
+};
+
+class ParaRightSpacingWindow : public ParaLRSpacingWindow
+{
+public:
+ explicit ParaRightSpacingWindow(vcl::Window* pParent);
+};
+
+class ParaFirstLineSpacingWindow : public ParaLRSpacingWindow
+{
+public:
+ explicit ParaFirstLineSpacingWindow(vcl::Window* pParent);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/possize/PosSizePropertyPanel.cxx b/svx/source/sidebar/possize/PosSizePropertyPanel.cxx
new file mode 100644
index 000000000..da9e067b2
--- /dev/null
+++ b/svx/source/sidebar/possize/PosSizePropertyPanel.cxx
@@ -0,0 +1,1079 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+
+#include "PosSizePropertyPanel.hxx"
+#include <sal/log.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/weldutils.hxx>
+#include <svx/dialcontrol.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/rectenum.hxx>
+#include <svx/sdangitm.hxx>
+#include <unotools/viewoptions.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/fieldvalues.hxx>
+#include <svl/intitem.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <svx/transfrmhelper.hxx>
+#include <boost/property_tree/ptree.hpp>
+
+#include <svtools/unitconv.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+constexpr OUStringLiteral USERITEM_NAME = u"FitItem";
+
+namespace svx::sidebar {
+
+PosSizePropertyPanel::PosSizePropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+: PanelLayout(pParent, "PosSizePropertyPanel", "svx/ui/sidebarpossize.ui"),
+ mxFtPosX(m_xBuilder->weld_label("horizontallabel")),
+ mxMtrPosX(m_xBuilder->weld_metric_spin_button("horizontalpos", FieldUnit::CM)),
+ mxFtPosY(m_xBuilder->weld_label("verticallabel")),
+ mxMtrPosY(m_xBuilder->weld_metric_spin_button("verticalpos", FieldUnit::CM)),
+ mxFtWidth(m_xBuilder->weld_label("widthlabel")),
+ mxMtrWidth(m_xBuilder->weld_metric_spin_button("selectwidth", FieldUnit::CM)),
+ mxFtHeight(m_xBuilder->weld_label("heightlabel")),
+ mxMtrHeight(m_xBuilder->weld_metric_spin_button("selectheight", FieldUnit::CM)),
+ mxCbxScale(m_xBuilder->weld_check_button("ratio")),
+ mxFtAngle(m_xBuilder->weld_label("rotationlabel")),
+ mxMtrAngle(m_xBuilder->weld_metric_spin_button("rotation", FieldUnit::DEGREE)),
+ mxCtrlDial(new DialControl),
+ mxDial(new weld::CustomWeld(*m_xBuilder, "orientationcontrol", *mxCtrlDial)),
+ mxFtFlip(m_xBuilder->weld_label("fliplabel")),
+ mxFlipTbx(m_xBuilder->weld_toolbar("selectrotationtype")),
+ mxFlipDispatch(new ToolbarUnoDispatcher(*mxFlipTbx, *m_xBuilder, rxFrame)),
+ mxArrangeTbx(m_xBuilder->weld_toolbar("arrangetoolbar")),
+ mxArrangeDispatch(new ToolbarUnoDispatcher(*mxArrangeTbx, *m_xBuilder, rxFrame)),
+ mxArrangeTbx2(m_xBuilder->weld_toolbar("arrangetoolbar2")),
+ mxArrangeDispatch2(new ToolbarUnoDispatcher(*mxArrangeTbx2, *m_xBuilder, rxFrame)),
+ mxAlignTbx(m_xBuilder->weld_toolbar("aligntoolbar")),
+ mxAlignDispatch(new ToolbarUnoDispatcher(*mxAlignTbx, *m_xBuilder, rxFrame)),
+ mxAlignTbx2(m_xBuilder->weld_toolbar("aligntoolbar2")),
+ mxAlignDispatch2(new ToolbarUnoDispatcher(*mxAlignTbx2, *m_xBuilder, rxFrame)),
+ mxBtnEditOLEObject(m_xBuilder->weld_button("btnEditObject")),
+ mpView(nullptr),
+ mlOldWidth(1),
+ mlOldHeight(1),
+ mlRotX(0),
+ mlRotY(0),
+ mePoolUnit(),
+ meDlgUnit(FieldUnit::INCH), // #i124409# init with fallback default
+ maTransfPosXControl(SID_ATTR_TRANSFORM_POS_X, *pBindings, *this),
+ maTransfPosYControl(SID_ATTR_TRANSFORM_POS_Y, *pBindings, *this),
+ maTransfWidthControl(SID_ATTR_TRANSFORM_WIDTH, *pBindings, *this),
+ maTransfHeightControl(SID_ATTR_TRANSFORM_HEIGHT, *pBindings, *this),
+ maSvxAngleControl( SID_ATTR_TRANSFORM_ANGLE, *pBindings, *this),
+ maRotXControl(SID_ATTR_TRANSFORM_ROT_X, *pBindings, *this),
+ maRotYControl(SID_ATTR_TRANSFORM_ROT_Y, *pBindings, *this),
+ maProPosControl(SID_ATTR_TRANSFORM_PROTECT_POS, *pBindings, *this),
+ maProSizeControl(SID_ATTR_TRANSFORM_PROTECT_SIZE, *pBindings, *this),
+ maAutoWidthControl(SID_ATTR_TRANSFORM_AUTOWIDTH, *pBindings, *this),
+ maAutoHeightControl(SID_ATTR_TRANSFORM_AUTOHEIGHT, *pBindings, *this),
+ m_aMetricCtl(SID_ATTR_METRIC, *pBindings, *this),
+ mpBindings(pBindings),
+ mbSizeProtected(false),
+ mbPositionProtected(false),
+ mbAutoWidth(false),
+ mbAutoHeight(false),
+ mbAdjustEnabled(false),
+ mxSidebar(rxSidebar)
+{
+ Initialize();
+
+ // A guesstimate of the longest label in the various sidebar panes to use
+ // to get this pane's contents to align with them, for lack of a better
+ // solution
+ auto nWidth = mxFtWidth->get_preferred_size().Width();
+ OUString sLabel = mxFtWidth->get_label();
+ mxFtWidth->set_label(SvxResId(RID_SVXSTR_TRANSPARENCY));
+ nWidth = std::max(nWidth, mxFtWidth->get_preferred_size().Width());;
+ mxFtWidth->set_label(sLabel);
+ mxFtWidth->set_size_request(nWidth, -1);
+
+ mpBindings->Update( SID_ATTR_METRIC );
+ mpBindings->Update( SID_ATTR_TRANSFORM_WIDTH );
+ mpBindings->Update( SID_ATTR_TRANSFORM_HEIGHT );
+ mpBindings->Update( SID_ATTR_TRANSFORM_PROTECT_SIZE );
+}
+
+PosSizePropertyPanel::~PosSizePropertyPanel()
+{
+ mxFtPosX.reset();
+ mxMtrPosX.reset();
+ mxFtPosY.reset();
+ mxMtrPosY.reset();
+ mxFtWidth.reset();
+ mxMtrWidth.reset();
+ mxFtHeight.reset();
+ mxMtrHeight.reset();
+ mxCbxScale.reset();
+ mxFtAngle.reset();
+ mxMtrAngle.reset();
+ mxDial.reset();
+ mxCtrlDial.reset();
+ mxFtFlip.reset();
+ mxFlipDispatch.reset();
+ mxFlipTbx.reset();
+ mxAlignDispatch.reset();
+ mxAlignDispatch2.reset();
+ mxAlignTbx.reset();
+ mxAlignTbx2.reset();
+ mxArrangeDispatch.reset();
+ mxArrangeDispatch2.reset();
+ mxArrangeTbx.reset();
+ mxArrangeTbx2.reset();
+ mxBtnEditOLEObject.reset();
+
+ maTransfPosXControl.dispose();
+ maTransfPosYControl.dispose();
+ maTransfWidthControl.dispose();
+ maTransfHeightControl.dispose();
+
+ maSvxAngleControl.dispose();
+ maRotXControl.dispose();
+ maRotYControl.dispose();
+ maProPosControl.dispose();
+ maProSizeControl.dispose();
+ maAutoWidthControl.dispose();
+ maAutoHeightControl.dispose();
+ m_aMetricCtl.dispose();
+}
+
+namespace
+{
+ bool hasText(const SdrView& rSdrView)
+ {
+ const SdrMarkList& rMarkList = rSdrView.GetMarkedObjectList();
+
+ if(1 == rMarkList.GetMarkCount())
+ {
+ const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ const SdrObjKind eKind(pObj->GetObjIdentifier());
+
+ if((pObj->GetObjInventor() == SdrInventor::Default) && (SdrObjKind::Text == eKind || SdrObjKind::TitleText == eKind || SdrObjKind::OutlineText == eKind))
+ {
+ const SdrTextObj* pSdrTextObj = dynamic_cast< const SdrTextObj* >(pObj);
+
+ if(pSdrTextObj && pSdrTextObj->HasText())
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+} // end of anonymous namespace
+
+
+void PosSizePropertyPanel::Initialize()
+{
+ //Position : Horizontal / Vertical
+ mxMtrPosX->connect_value_changed( LINK( this, PosSizePropertyPanel, ChangePosXHdl ) );
+ mxMtrPosY->connect_value_changed( LINK( this, PosSizePropertyPanel, ChangePosYHdl ) );
+
+ //Size : Width / Height
+ mxMtrWidth->connect_value_changed( LINK( this, PosSizePropertyPanel, ChangeWidthHdl ) );
+ mxMtrHeight->connect_value_changed( LINK( this, PosSizePropertyPanel, ChangeHeightHdl ) );
+
+ //Size : Keep ratio
+ mxCbxScale->connect_toggled( LINK( this, PosSizePropertyPanel, ClickAutoHdl ) );
+
+ //rotation control
+ mxCtrlDial->SetLinkedField(mxMtrAngle.get(), 2);
+ mxCtrlDial->SetModifyHdl(LINK( this, PosSizePropertyPanel, RotationHdl));
+
+ //use same logic as DialControl_Impl::SetSize
+ weld::DrawingArea* pDrawingArea = mxCtrlDial->GetDrawingArea();
+ int nDim = (std::min<int>(pDrawingArea->get_approximate_digit_width() * 6,
+ pDrawingArea->get_text_height() * 3) - 1) | 1;
+ Size aSize(nDim, nDim);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ mxCtrlDial->Init(aSize);
+
+ mxBtnEditOLEObject->connect_clicked( LINK( this, PosSizePropertyPanel, ClickObjectEditHdl ) );
+
+ SfxViewShell* pCurSh = SfxViewShell::Current();
+ if ( pCurSh )
+ mpView = pCurSh->GetDrawView();
+ else
+ mpView = nullptr;
+
+ if ( mpView != nullptr )
+ {
+ maUIScale = mpView->GetModel()->GetUIScale();
+ mbAdjustEnabled = hasText(*mpView);
+ }
+
+ mePoolUnit = maTransfWidthControl.GetCoreMetric();
+}
+
+std::unique_ptr<PanelLayout> PosSizePropertyPanel::Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to PosSizePropertyPanel::Create", nullptr, 0);
+ if ( ! rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to PosSizePropertyPanel::Create", nullptr, 1);
+ if (pBindings == nullptr)
+ throw lang::IllegalArgumentException("no SfxBindings given to PosSizePropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<PosSizePropertyPanel>(pParent, rxFrame, pBindings, rxSidebar);
+}
+
+void PosSizePropertyPanel::HandleContextChange(
+ const vcl::EnumContext& rContext)
+{
+ if (maContext == rContext)
+ {
+ // Nothing to do.
+ return;
+ }
+
+ maContext = rContext;
+
+ bool bShowPosition = false;
+ bool bShowAngle = false;
+ bool bShowFlip = false;
+ bool bShowEditObject = false;
+ bool bShowArrangeTbx2 = false;
+
+ switch (maContext.GetCombinedContext_DI())
+ {
+ case CombinedEnumContext(Application::WriterVariants, Context::Draw):
+ bShowAngle = true;
+ bShowFlip = true;
+ bShowArrangeTbx2 = true;
+ break;
+
+ case CombinedEnumContext(Application::WriterVariants, Context::Graphic):
+ bShowFlip = true;
+ bShowAngle = true; // RotGrfFlyFrame: Writer FlyFrames for Graphics now support angle
+ break;
+
+ case CombinedEnumContext(Application::Calc, Context::Draw):
+ case CombinedEnumContext(Application::Calc, Context::DrawLine):
+ case CombinedEnumContext(Application::Calc, Context::Graphic):
+ case CombinedEnumContext(Application::DrawImpress, Context::Draw):
+ case CombinedEnumContext(Application::DrawImpress, Context::DrawLine):
+ case CombinedEnumContext(Application::DrawImpress, Context::TextObject):
+ case CombinedEnumContext(Application::DrawImpress, Context::Graphic):
+ bShowPosition = true;
+ bShowAngle = true;
+ bShowFlip = true;
+ break;
+
+ case CombinedEnumContext(Application::WriterVariants, Context::OLE):
+ bShowEditObject = true;
+ break;
+
+ case CombinedEnumContext(Application::Calc, Context::OLE):
+ case CombinedEnumContext(Application::DrawImpress, Context::OLE):
+ bShowPosition = true;
+ bShowEditObject = true;
+ break;
+
+ case CombinedEnumContext(Application::Calc, Context::Chart):
+ case CombinedEnumContext(Application::Calc, Context::Form):
+ case CombinedEnumContext(Application::Calc, Context::Media):
+ case CombinedEnumContext(Application::Calc, Context::MultiObject):
+ case CombinedEnumContext(Application::DrawImpress, Context::Media):
+ case CombinedEnumContext(Application::DrawImpress, Context::Form):
+ case CombinedEnumContext(Application::DrawImpress, Context::ThreeDObject):
+ case CombinedEnumContext(Application::DrawImpress, Context::MultiObject):
+ bShowPosition = true;
+ break;
+ }
+
+ // Position
+ mxFtPosX->set_visible(bShowPosition);
+ mxMtrPosX->set_visible(bShowPosition);
+ mxFtPosY->set_visible(bShowPosition);
+ mxMtrPosY->set_visible(bShowPosition);
+
+ // Rotation
+ mxFtAngle->set_visible(bShowAngle);
+ mxMtrAngle->set_visible(bShowAngle);
+ mxCtrlDial->set_visible(bShowAngle);
+
+ // Flip
+ mxFtFlip->set_visible(bShowFlip);
+ mxFlipTbx->set_visible(bShowFlip);
+
+ // Edit Object
+ mxBtnEditOLEObject->set_visible(bShowEditObject);
+
+ // Arrange tool bar 2
+ mxArrangeTbx2->set_visible(bShowArrangeTbx2);
+
+ if (mxSidebar.is())
+ mxSidebar->requestLayout();
+}
+
+
+IMPL_LINK_NOARG( PosSizePropertyPanel, ChangeWidthHdl, weld::MetricSpinButton&, void )
+{
+ if( mxCbxScale->get_active() &&
+ mxCbxScale->get_sensitive() )
+ {
+ tools::Long nHeight = static_cast<tools::Long>( (static_cast<double>(mlOldHeight) * static_cast<double>(mxMtrWidth->get_value(FieldUnit::NONE))) / static_cast<double>(mlOldWidth) );
+ if( nHeight <= mxMtrHeight->get_max( FieldUnit::NONE ) )
+ {
+ mxMtrHeight->set_value( nHeight, FieldUnit::NONE );
+ }
+ else
+ {
+ nHeight = static_cast<tools::Long>(mxMtrHeight->get_max( FieldUnit::NONE ));
+ mxMtrHeight->set_value(nHeight, FieldUnit::NONE);
+ const tools::Long nWidth = static_cast<tools::Long>( (static_cast<double>(mlOldWidth) * static_cast<double>(nHeight)) / static_cast<double>(mlOldHeight) );
+ mxMtrWidth->set_value( nWidth, FieldUnit::NONE );
+ }
+ }
+ executeSize();
+}
+
+
+IMPL_LINK_NOARG( PosSizePropertyPanel, ChangeHeightHdl, weld::MetricSpinButton&, void )
+{
+ if( mxCbxScale->get_active() &&
+ mxCbxScale->get_sensitive() )
+ {
+ tools::Long nWidth = static_cast<tools::Long>( (static_cast<double>(mlOldWidth) * static_cast<double>(mxMtrHeight->get_value(FieldUnit::NONE))) / static_cast<double>(mlOldHeight) );
+ if( nWidth <= mxMtrWidth->get_max( FieldUnit::NONE ) )
+ {
+ mxMtrWidth->set_value( nWidth, FieldUnit::NONE );
+ }
+ else
+ {
+ nWidth = static_cast<tools::Long>(mxMtrWidth->get_max( FieldUnit::NONE ));
+ mxMtrWidth->set_value( nWidth, FieldUnit::NONE );
+ const tools::Long nHeight = static_cast<tools::Long>( (static_cast<double>(mlOldHeight) * static_cast<double>(nWidth)) / static_cast<double>(mlOldWidth) );
+ mxMtrHeight->set_value( nHeight, FieldUnit::NONE );
+ }
+ }
+ executeSize();
+}
+
+
+IMPL_LINK_NOARG( PosSizePropertyPanel, ChangePosXHdl, weld::MetricSpinButton&, void )
+{
+ if ( mxMtrPosX->get_value_changed_from_saved())
+ {
+ tools::Long lX = GetCoreValue( *mxMtrPosX, mePoolUnit );
+
+ Fraction aUIScale = mpView->GetModel()->GetUIScale();
+ lX = tools::Long( lX * aUIScale );
+
+ SfxInt32Item aPosXItem( SID_ATTR_TRANSFORM_POS_X,static_cast<sal_uInt32>(lX));
+
+ GetBindings()->GetDispatcher()->ExecuteList(
+ SID_ATTR_TRANSFORM, SfxCallMode::RECORD, { &aPosXItem });
+ }
+}
+
+IMPL_LINK_NOARG( PosSizePropertyPanel, ChangePosYHdl, weld::MetricSpinButton&, void )
+{
+ if ( mxMtrPosY->get_value_changed_from_saved() )
+ {
+ tools::Long lY = GetCoreValue( *mxMtrPosY, mePoolUnit );
+
+ Fraction aUIScale = mpView->GetModel()->GetUIScale();
+ lY = tools::Long( lY * aUIScale );
+
+ SfxInt32Item aPosYItem( SID_ATTR_TRANSFORM_POS_Y,static_cast<sal_uInt32>(lY));
+
+ GetBindings()->GetDispatcher()->ExecuteList(
+ SID_ATTR_TRANSFORM, SfxCallMode::RECORD, { &aPosYItem });
+ }
+}
+
+IMPL_LINK_NOARG( PosSizePropertyPanel, ClickAutoHdl, weld::Toggleable&, void )
+{
+ if ( mxCbxScale->get_active() )
+ {
+ mlOldWidth = std::max(GetCoreValue(*mxMtrWidth, mePoolUnit), SAL_CONST_INT64(1));
+ mlOldHeight = std::max(GetCoreValue(*mxMtrHeight, mePoolUnit), SAL_CONST_INT64(1));
+ }
+
+ // mxCbxScale must synchronized with that on Position and Size tabpage on Shape Properties dialog
+ SvtViewOptions aPageOpt(EViewType::TabPage, "cui/ui/possizetabpage/PositionAndSize");
+ aPageOpt.SetUserItem( USERITEM_NAME, css::uno::Any( OUString::number( int(mxCbxScale->get_active()) ) ) );
+}
+
+IMPL_LINK_NOARG( PosSizePropertyPanel, RotationHdl, DialControl&, void )
+{
+ Degree100 nTmp = mxCtrlDial->GetRotation();
+
+ // #i123993# Need to take UIScale into account when executing rotations
+ const double fUIScale(mpView && mpView->GetModel() ? double(mpView->GetModel()->GetUIScale()) : 1.0);
+ SdrAngleItem aAngleItem( SID_ATTR_TRANSFORM_ANGLE, nTmp);
+ SfxInt32Item aRotXItem( SID_ATTR_TRANSFORM_ROT_X, basegfx::fround(mlRotX * fUIScale));
+ SfxInt32Item aRotYItem( SID_ATTR_TRANSFORM_ROT_Y, basegfx::fround(mlRotY * fUIScale));
+
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM,
+ SfxCallMode::RECORD, { &aAngleItem, &aRotXItem, &aRotYItem });
+}
+
+IMPL_STATIC_LINK_NOARG( PosSizePropertyPanel, ClickObjectEditHdl, weld::Button&, void )
+{
+ SfxViewShell* pCurSh = SfxViewShell::Current();
+ if ( pCurSh)
+ {
+ pCurSh->DoVerb( -1 );
+ }
+}
+
+namespace
+{
+ void limitWidth(weld::MetricSpinButton& rMetricSpinButton)
+ {
+ // space is limited in the sidebar, so limit MetricSpinButtons to a width of 7 digits
+ const int nMaxDigits = 7;
+
+ weld::SpinButton& rSpinButton = rMetricSpinButton.get_widget();
+ rSpinButton.set_width_chars(std::min(rSpinButton.get_width_chars(), nMaxDigits));
+ }
+}
+
+void PosSizePropertyPanel::NotifyItemUpdate(
+ sal_uInt16 nSID,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ mxFtAngle->set_sensitive(true);
+ mxMtrAngle->set_sensitive(true);
+ mxDial->set_sensitive(true);
+ mxFtFlip->set_sensitive(true);
+ mxFlipTbx->set_sensitive(true);
+
+ const SfxUInt32Item* pWidthItem;
+ const SfxUInt32Item* pHeightItem;
+
+ SfxViewShell* pCurSh = SfxViewShell::Current();
+ if ( pCurSh )
+ mpView = pCurSh->GetDrawView();
+ else
+ mpView = nullptr;
+
+ if ( mpView == nullptr )
+ return;
+
+ mbAdjustEnabled = hasText(*mpView);
+
+ // Pool unit and dialog unit may have changed, make sure that we
+ // have the current values.
+ mePoolUnit = maTransfWidthControl.GetCoreMetric();
+
+ switch (nSID)
+ {
+ case SID_ATTR_TRANSFORM_WIDTH:
+ if ( SfxItemState::DEFAULT == eState )
+ {
+ pWidthItem = dynamic_cast< const SfxUInt32Item* >(pState);
+
+ if(pWidthItem)
+ {
+ tools::Long lOldWidth1 = tools::Long( pWidthItem->GetValue() / maUIScale );
+ SetFieldUnit( *mxMtrWidth, meDlgUnit, true );
+ SetMetricValue( *mxMtrWidth, lOldWidth1, mePoolUnit );
+ limitWidth(*mxMtrWidth);
+ mlOldWidth = lOldWidth1;
+ mxMtrWidth->save_value();
+ break;
+ }
+ }
+
+ mxMtrWidth->set_text( "" );
+ break;
+
+ case SID_ATTR_TRANSFORM_HEIGHT:
+ if ( SfxItemState::DEFAULT == eState )
+ {
+ pHeightItem = dynamic_cast< const SfxUInt32Item* >(pState);
+
+ if(pHeightItem)
+ {
+ tools::Long nTmp = tools::Long( pHeightItem->GetValue() / maUIScale);
+ SetFieldUnit( *mxMtrHeight, meDlgUnit, true );
+ SetMetricValue( *mxMtrHeight, nTmp, mePoolUnit );
+ limitWidth(*mxMtrHeight);
+ mlOldHeight = nTmp;
+ mxMtrHeight->save_value();
+ break;
+ }
+ }
+
+ mxMtrHeight->set_text( "");
+ break;
+
+ case SID_ATTR_TRANSFORM_POS_X:
+ if(SfxItemState::DEFAULT == eState)
+ {
+ const SfxInt32Item* pItem = dynamic_cast< const SfxInt32Item* >(pState);
+
+ if(pItem)
+ {
+ tools::Long nTmp = tools::Long(pItem->GetValue() / maUIScale);
+ SetFieldUnit( *mxMtrPosX, meDlgUnit, true );
+ SetMetricValue( *mxMtrPosX, nTmp, mePoolUnit );
+ limitWidth(*mxMtrPosX);
+ mxMtrPosX->save_value();
+ break;
+ }
+ }
+
+ mxMtrPosX->set_text( "" );
+ break;
+
+ case SID_ATTR_TRANSFORM_POS_Y:
+ if(SfxItemState::DEFAULT == eState)
+ {
+ const SfxInt32Item* pItem = dynamic_cast< const SfxInt32Item* >(pState);
+
+ if(pItem)
+ {
+ tools::Long nTmp = tools::Long(pItem->GetValue() / maUIScale);
+ SetFieldUnit( *mxMtrPosY, meDlgUnit, true );
+ SetMetricValue( *mxMtrPosY, nTmp, mePoolUnit );
+ limitWidth(*mxMtrPosY);
+ mxMtrPosY->save_value();
+ break;
+ }
+ }
+
+ mxMtrPosY->set_text( "" );
+ break;
+
+ case SID_ATTR_TRANSFORM_ROT_X:
+ if (SfxItemState::DEFAULT == eState)
+ {
+ const SfxInt32Item* pItem = dynamic_cast< const SfxInt32Item* >(pState);
+
+ if(pItem)
+ {
+ mlRotX = pItem->GetValue();
+ mlRotX = tools::Long( mlRotX / maUIScale );
+ }
+ }
+ break;
+
+ case SID_ATTR_TRANSFORM_ROT_Y:
+ if (SfxItemState::DEFAULT == eState)
+ {
+ const SfxInt32Item* pItem = dynamic_cast< const SfxInt32Item* >(pState);
+
+ if(pItem)
+ {
+ mlRotY = pItem->GetValue();
+ mlRotY = tools::Long( mlRotY / maUIScale );
+ }
+ }
+ break;
+
+ case SID_ATTR_TRANSFORM_PROTECT_POS:
+ if(SfxItemState::DEFAULT == eState)
+ {
+ const SfxBoolItem* pItem = dynamic_cast< const SfxBoolItem* >(pState);
+
+ if(pItem)
+ {
+ // record the state of position protect
+ mbPositionProtected = pItem->GetValue();
+ break;
+ }
+ }
+
+ mbPositionProtected = false;
+ break;
+
+ case SID_ATTR_TRANSFORM_PROTECT_SIZE:
+ if(SfxItemState::DEFAULT == eState)
+ {
+ const SfxBoolItem* pItem = dynamic_cast< const SfxBoolItem* >(pState);
+
+ if(pItem)
+ {
+ // record the state of size protect
+ mbSizeProtected = pItem->GetValue();
+ break;
+ }
+ }
+
+ mbSizeProtected = false;
+ break;
+
+ case SID_ATTR_TRANSFORM_AUTOWIDTH:
+ if(SfxItemState::DEFAULT == eState)
+ {
+ const SfxBoolItem* pItem = dynamic_cast< const SfxBoolItem* >(pState);
+
+ if(pItem)
+ {
+ mbAutoWidth = pItem->GetValue();
+ }
+ }
+ break;
+
+ case SID_ATTR_TRANSFORM_AUTOHEIGHT:
+ if(SfxItemState::DEFAULT == eState)
+ {
+ const SfxBoolItem* pItem = dynamic_cast< const SfxBoolItem* >(pState);
+
+ if(pItem)
+ {
+ mbAutoHeight = pItem->GetValue();
+ }
+ }
+ break;
+
+ case SID_ATTR_TRANSFORM_ANGLE:
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ const SdrAngleItem* pItem = dynamic_cast< const SdrAngleItem* >(pState);
+
+ if(pItem)
+ {
+ Degree100 nTmp = NormAngle36000(pItem->GetValue());
+
+ mxMtrAngle->set_value(nTmp.get(), FieldUnit::DEGREE);
+ mxCtrlDial->SetRotation(nTmp);
+
+ break;
+ }
+ }
+
+ mxMtrAngle->set_text( "" );
+ mxCtrlDial->SetRotation( 0_deg100 );
+ break;
+
+ case SID_ATTR_METRIC:
+ MetricState( eState, pState );
+ UpdateUIScale();
+ break;
+
+ default:
+ break;
+ }
+
+ const sal_Int32 nCombinedContext(maContext.GetCombinedContext_DI());
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+
+ switch (rMarkList.GetMarkCount())
+ {
+ case 0:
+ break;
+
+ case 1:
+ {
+ const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ const SdrObjKind eKind(pObj->GetObjIdentifier());
+
+ if(((nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::Draw)
+ || nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::TextObject)
+ ) && SdrObjKind::Edge == eKind)
+ || SdrObjKind::Caption == eKind)
+ {
+ mxFtAngle->set_sensitive(false);
+ mxMtrAngle->set_sensitive(false);
+ mxDial->set_sensitive(false);
+ mxFlipTbx->set_sensitive(false);
+ mxFtFlip->set_sensitive(false);
+ }
+ break;
+ }
+
+ default:
+ {
+ sal_uInt16 nMarkObj = 0;
+ bool isNoEdge = true;
+
+ while(isNoEdge && rMarkList.GetMark(nMarkObj))
+ {
+ const SdrObject* pObj = rMarkList.GetMark(nMarkObj)->GetMarkedSdrObj();
+ const SdrObjKind eKind(pObj->GetObjIdentifier());
+
+ if(((nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::Draw)
+ || nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::TextObject)
+ ) && SdrObjKind::Edge == eKind)
+ || SdrObjKind::Caption == eKind)
+ {
+ isNoEdge = false;
+ break;
+ }
+ nMarkObj++;
+ }
+
+ if(!isNoEdge)
+ {
+ mxFtAngle->set_sensitive(false);
+ mxMtrAngle->set_sensitive(false);
+ mxDial->set_sensitive(false);
+ mxFlipTbx->set_sensitive(false);
+ mxFtFlip->set_sensitive(false);
+ }
+ break;
+ }
+ }
+
+ if(nCombinedContext == CombinedEnumContext(Application::DrawImpress, Context::TextObject))
+ {
+ mxFlipTbx->set_sensitive(false);
+ mxFtFlip->set_sensitive(false);
+ }
+
+ DisableControls();
+
+ // mxCbxScale must synchronized with that on Position and Size tabpage on Shape Properties dialog
+ SvtViewOptions aPageOpt(EViewType::TabPage, "cui/ui/possizetabpage/PositionAndSize");
+ OUString sUserData;
+ css::uno::Any aUserItem = aPageOpt.GetUserItem( USERITEM_NAME );
+ OUString aTemp;
+ if ( aUserItem >>= aTemp )
+ sUserData = aTemp;
+ mxCbxScale->set_active(static_cast<bool>(sUserData.toInt32()));
+}
+
+void PosSizePropertyPanel::GetControlState(const sal_uInt16 nSID, boost::property_tree::ptree& rState)
+{
+ weld::MetricSpinButton* pControl = nullptr;
+ switch (nSID)
+ {
+ case SID_ATTR_TRANSFORM_POS_X:
+ pControl = mxMtrPosX.get();
+ break;
+ case SID_ATTR_TRANSFORM_POS_Y:
+ pControl = mxMtrPosY.get();
+ break;
+ case SID_ATTR_TRANSFORM_WIDTH:
+ pControl = mxMtrWidth.get();
+ break;
+ case SID_ATTR_TRANSFORM_HEIGHT:
+ pControl = mxMtrHeight.get();
+ break;
+ }
+
+ if (pControl && !pControl->get_text().isEmpty())
+ {
+ OUString sValue = Application::GetSettings().GetNeutralLocaleDataWrapper().
+ getNum(pControl->get_value(pControl->get_unit()), pControl->get_digits(), false, false);
+ rState.put(pControl->get_buildable_name().getStr(), sValue.toUtf8().getStr());
+ }
+}
+
+void PosSizePropertyPanel::executeSize()
+{
+ if ( !mxMtrWidth->get_value_changed_from_saved() && !mxMtrHeight->get_value_changed_from_saved())
+ return;
+
+ Fraction aUIScale = mpView->GetModel()->GetUIScale();
+
+ // get Width
+ double nWidth = static_cast<double>(mxMtrWidth->get_value(FieldUnit::MM_100TH));
+ tools::Long lWidth = tools::Long(nWidth * static_cast<double>(aUIScale));
+ lWidth = OutputDevice::LogicToLogic( lWidth, MapUnit::Map100thMM, mePoolUnit );
+ lWidth = static_cast<tools::Long>(mxMtrWidth->denormalize( lWidth ));
+
+ // get Height
+ double nHeight = static_cast<double>(mxMtrHeight->get_value(FieldUnit::MM_100TH));
+ tools::Long lHeight = tools::Long(nHeight * static_cast<double>(aUIScale));
+ lHeight = OutputDevice::LogicToLogic( lHeight, MapUnit::Map100thMM, mePoolUnit );
+ lHeight = static_cast<tools::Long>(mxMtrHeight->denormalize( lHeight ));
+
+ // put Width & Height to itemset
+ SfxUInt32Item aWidthItem( SID_ATTR_TRANSFORM_WIDTH, static_cast<sal_uInt32>(lWidth));
+ SfxUInt32Item aHeightItem( SID_ATTR_TRANSFORM_HEIGHT, static_cast<sal_uInt32>(lHeight));
+ SfxUInt16Item aPointItem (SID_ATTR_TRANSFORM_SIZE_POINT, sal_uInt16(RectPoint::LT));
+ const sal_Int32 nCombinedContext(maContext.GetCombinedContext_DI());
+
+ if( nCombinedContext == CombinedEnumContext(Application::WriterVariants, Context::Graphic)
+ || nCombinedContext == CombinedEnumContext(Application::WriterVariants, Context::OLE)
+ )
+ {
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM,
+ SfxCallMode::RECORD, { &aWidthItem, &aHeightItem, &aPointItem });
+ }
+ else
+ {
+ if ( (mxMtrWidth->get_value_changed_from_saved()) && (mxMtrHeight->get_value_changed_from_saved()))
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM,
+ SfxCallMode::RECORD, { &aWidthItem, &aHeightItem, &aPointItem });
+ else if( mxMtrWidth->get_value_changed_from_saved())
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM,
+ SfxCallMode::RECORD, { &aWidthItem, &aPointItem });
+ else if ( mxMtrHeight->get_value_changed_from_saved())
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_TRANSFORM,
+ SfxCallMode::RECORD, { &aHeightItem, &aPointItem });
+ }
+}
+
+void PosSizePropertyPanel::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
+{
+ if (meDlgUnit != GetCurrentUnit(SfxItemState::DEFAULT, nullptr))
+ {
+ mpBindings->Update( SID_ATTR_METRIC );
+ }
+
+ PanelLayout::DumpAsPropertyTree(rJsonWriter);
+}
+
+void PosSizePropertyPanel::MetricState( SfxItemState eState, const SfxPoolItem* pState )
+{
+ bool bPosXBlank = false;
+ bool bPosYBlank = false;
+ bool bWidthBlank = false;
+ bool bHeightBlank = false;
+
+ // #i124409# use the given Item to get the correct UI unit and initialize it
+ // and the Fields using it
+ meDlgUnit = GetCurrentUnit(eState,pState);
+
+ if (mxMtrPosX->get_text().isEmpty())
+ bPosXBlank = true;
+ SetFieldUnit( *mxMtrPosX, meDlgUnit, true );
+ if(bPosXBlank)
+ mxMtrPosX->set_text(OUString());
+
+ if (mxMtrPosY->get_text().isEmpty())
+ bPosYBlank = true;
+ SetFieldUnit( *mxMtrPosY, meDlgUnit, true );
+ if(bPosYBlank)
+ mxMtrPosY->set_text(OUString());
+ SetPosSizeMinMax();
+
+ if (mxMtrWidth->get_text().isEmpty())
+ bWidthBlank = true;
+ SetFieldUnit( *mxMtrWidth, meDlgUnit, true );
+ if(bWidthBlank)
+ mxMtrWidth->set_text(OUString());
+
+ if (mxMtrHeight->get_text().isEmpty())
+ bHeightBlank = true;
+ SetFieldUnit( *mxMtrHeight, meDlgUnit, true );
+ if(bHeightBlank)
+ mxMtrHeight->set_text(OUString());
+}
+
+
+FieldUnit PosSizePropertyPanel::GetCurrentUnit( SfxItemState eState, const SfxPoolItem* pState )
+{
+ FieldUnit eUnit = FieldUnit::NONE;
+
+ if ( pState && eState >= SfxItemState::DEFAULT )
+ {
+ eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pState)->GetValue());
+ }
+ else
+ {
+ SfxViewFrame* pFrame = SfxViewFrame::Current();
+ SfxObjectShell* pSh = nullptr;
+ if ( pFrame )
+ pSh = pFrame->GetObjectShell();
+ if ( pSh )
+ {
+ SfxModule* pModule = pSh->GetModule();
+ if ( pModule )
+ {
+ const SfxPoolItem* pItem = pModule->GetItem( SID_ATTR_METRIC );
+ if ( pItem )
+ eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pItem)->GetValue());
+ }
+ else
+ {
+ SAL_WARN("svx.sidebar", "GetModuleFieldUnit(): no module found");
+ }
+ }
+ }
+
+ return eUnit;
+}
+
+
+void PosSizePropertyPanel::DisableControls()
+{
+ if( mbPositionProtected )
+ {
+ // the position is protected("Position protect" option in modal dialog is checked),
+ // disable all the Position controls in sidebar
+ mxFtPosX->set_sensitive(false);
+ mxMtrPosX->set_sensitive(false);
+ mxFtPosY->set_sensitive(false);
+ mxMtrPosY->set_sensitive(false);
+ mxFtAngle->set_sensitive(false);
+ mxMtrAngle->set_sensitive(false);
+ mxDial->set_sensitive(false);
+ mxFtFlip->set_sensitive(false);
+ mxFlipTbx->set_sensitive(false);
+
+ mxFtWidth->set_sensitive(false);
+ mxMtrWidth->set_sensitive(false);
+ mxFtHeight->set_sensitive(false);
+ mxMtrHeight->set_sensitive(false);
+ mxCbxScale->set_sensitive(false);
+ }
+ else
+ {
+ mxFtPosX->set_sensitive(true);
+ mxMtrPosX->set_sensitive(true);
+ mxFtPosY->set_sensitive(true);
+ mxMtrPosY->set_sensitive(true);
+
+ if( mbSizeProtected )
+ {
+ mxFtWidth->set_sensitive(false);
+ mxMtrWidth->set_sensitive(false);
+ mxFtHeight->set_sensitive(false);
+ mxMtrHeight->set_sensitive(false);
+ mxCbxScale->set_sensitive(false);
+ }
+ else
+ {
+ if( mbAdjustEnabled )
+ {
+ if( mbAutoWidth )
+ {
+ mxFtWidth->set_sensitive(false);
+ mxMtrWidth->set_sensitive(false);
+ mxCbxScale->set_sensitive(false);
+ }
+ else
+ {
+ mxFtWidth->set_sensitive(true);
+ mxMtrWidth->set_sensitive(true);
+ }
+ if( mbAutoHeight )
+ {
+ mxFtHeight->set_sensitive(false);
+ mxMtrHeight->set_sensitive(false);
+ mxCbxScale->set_sensitive(false);
+ }
+ else
+ {
+ mxFtHeight->set_sensitive(true);
+ mxMtrHeight->set_sensitive(true);
+ }
+ if( !mbAutoWidth && !mbAutoHeight )
+ mxCbxScale->set_sensitive(true);
+ }
+ else
+ {
+ mxFtWidth->set_sensitive(true);
+ mxMtrWidth->set_sensitive(true);
+ mxFtHeight->set_sensitive(true);
+ mxMtrHeight->set_sensitive(true);
+ mxCbxScale->set_sensitive(true);
+ }
+ }
+ }
+}
+
+void PosSizePropertyPanel::SetPosSizeMinMax()
+{
+ SdrPageView* pPV = mpView->GetSdrPageView();
+ if (!pPV)
+ return;
+ tools::Rectangle aTmpRect(mpView->GetAllMarkedRect());
+ pPV->LogicToPagePos(aTmpRect);
+ maRect = vcl::unotools::b2DRectangleFromRectangle(aTmpRect);
+
+ tools::Rectangle aTmpRect2(mpView->GetWorkArea());
+ pPV->LogicToPagePos(aTmpRect2);
+ maWorkArea = vcl::unotools::b2DRectangleFromRectangle(aTmpRect2);
+
+ const Fraction aUIScale(mpView->GetModel()->GetUIScale());
+ TransfrmHelper::ScaleRect( maWorkArea, aUIScale );
+ TransfrmHelper::ScaleRect( maRect, aUIScale );
+
+ const sal_uInt16 nDigits(mxMtrPosX->get_digits());
+ TransfrmHelper::ConvertRect( maWorkArea, nDigits, mePoolUnit, meDlgUnit );
+ TransfrmHelper::ConvertRect( maRect, nDigits, mePoolUnit, meDlgUnit );
+
+ double fLeft(maWorkArea.getMinX());
+ double fTop(maWorkArea.getMinY());
+ double fRight(maWorkArea.getMaxX());
+ double fBottom(maWorkArea.getMaxY());
+
+ // seems that sidebar defaults to top left reference point
+ // and there's no way to set it to something else
+ fRight -= maRect.getWidth();
+ fBottom -= maRect.getHeight();
+
+ const double fMaxLong(static_cast<double>(vcl::ConvertValue( LONG_MAX, 0, MapUnit::Map100thMM, meDlgUnit ) - 1));
+ fLeft = std::clamp(fLeft, -fMaxLong, fMaxLong);
+ fRight = std::clamp(fRight, -fMaxLong, fMaxLong);
+ fTop = std::clamp(fTop, - fMaxLong, fMaxLong);
+ fBottom = std::clamp(fBottom, -fMaxLong, fMaxLong);
+
+ mxMtrPosX->set_range(basegfx::fround64(fLeft), basegfx::fround64(fRight), FieldUnit::NONE);
+ limitWidth(*mxMtrPosX);
+ mxMtrPosY->set_range(basegfx::fround64(fTop), basegfx::fround64(fBottom), FieldUnit::NONE);
+ limitWidth(*mxMtrPosY);
+
+ double fMaxWidth = maWorkArea.getWidth() - (maRect.getWidth() - fLeft);
+ double fMaxHeight = maWorkArea.getHeight() - (maRect.getHeight() - fTop);
+ mxMtrWidth->set_max(std::min<sal_Int64>(INT_MAX, basegfx::fround64(fMaxWidth*100)), FieldUnit::NONE);
+ limitWidth(*mxMtrWidth);
+ mxMtrHeight->set_max(std::min<sal_Int64>(INT_MAX, basegfx::fround64(fMaxHeight*100)), FieldUnit::NONE);
+ limitWidth(*mxMtrHeight);
+}
+
+void PosSizePropertyPanel::UpdateUIScale()
+{
+ const Fraction aUIScale (mpView->GetModel()->GetUIScale());
+ if (maUIScale == aUIScale)
+ return;
+
+ // UI scale has changed.
+
+ // Remember the new UI scale.
+ maUIScale = aUIScale;
+
+ // The content of the position and size boxes is only updated when item changes are notified.
+ // Request such notifications without changing the actual item values.
+ GetBindings()->Invalidate(SID_ATTR_TRANSFORM_POS_X, true);
+ GetBindings()->Invalidate(SID_ATTR_TRANSFORM_POS_Y, true);
+ GetBindings()->Invalidate(SID_ATTR_TRANSFORM_WIDTH, true);
+ GetBindings()->Invalidate(SID_ATTR_TRANSFORM_HEIGHT, true);
+}
+
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/possize/PosSizePropertyPanel.hxx b/svx/source/sidebar/possize/PosSizePropertyPanel.hxx
new file mode 100644
index 000000000..ede3d3e44
--- /dev/null
+++ b/svx/source/sidebar/possize/PosSizePropertyPanel.hxx
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_POSSIZE_POSSIZEPROPERTYPANEL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_POSSIZE_POSSIZEPROPERTYPANEL_HXX
+
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/IContextChangeReceiver.hxx>
+#include <sfx2/weldutils.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <svl/poolitem.hxx>
+#include <tools/fldunit.hxx>
+#include <tools/fract.hxx>
+#include <com/sun/star/ui/XSidebar.hpp>
+#include <basegfx/range/b2drange.hxx>
+#include <vcl/EnumContext.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/weld.hxx>
+
+class SdrView;
+
+namespace svx {
+class DialControl;
+};
+
+namespace svx::sidebar {
+
+class PosSizePropertyPanel
+: public PanelLayout,
+ public ::sfx2::sidebar::IContextChangeReceiver,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+ virtual ~PosSizePropertyPanel() override;
+
+ static std::unique_ptr<PanelLayout> Create(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+
+ virtual void HandleContextChange(
+ const vcl::EnumContext& rContext) override;
+
+ virtual void NotifyItemUpdate(
+ const sal_uInt16 nSId,
+ const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void DumpAsPropertyTree(tools::JsonWriter&) override;
+
+ SfxBindings* GetBindings() { return mpBindings;}
+
+ // constructor/destructor
+ PosSizePropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings,
+ const css::uno::Reference<css::ui::XSidebar>& rxSidebar);
+
+ virtual void GetControlState(
+ const sal_uInt16 nSId,
+ boost::property_tree::ptree& rState) override;
+
+private:
+ //Position
+ std::unique_ptr<weld::Label> mxFtPosX;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrPosX;
+ std::unique_ptr<weld::Label> mxFtPosY;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrPosY;
+
+ // size
+ std::unique_ptr<weld::Label> mxFtWidth;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrWidth;
+ std::unique_ptr<weld::Label> mxFtHeight;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrHeight;
+ std::unique_ptr<weld::CheckButton> mxCbxScale;
+
+ //rotation
+ std::unique_ptr<weld::Label> mxFtAngle;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrAngle;
+
+ //rotation control
+ std::unique_ptr<svx::DialControl> mxCtrlDial;
+ std::unique_ptr<weld::CustomWeld> mxDial;
+
+ //flip
+ std::unique_ptr<weld::Label> mxFtFlip;
+ std::unique_ptr<weld::Toolbar> mxFlipTbx;
+ std::unique_ptr<ToolbarUnoDispatcher> mxFlipDispatch;
+
+ std::unique_ptr<weld::Toolbar> mxArrangeTbx;
+ std::unique_ptr<ToolbarUnoDispatcher> mxArrangeDispatch;
+ std::unique_ptr<weld::Toolbar> mxArrangeTbx2;
+ std::unique_ptr<ToolbarUnoDispatcher> mxArrangeDispatch2;
+
+ std::unique_ptr<weld::Toolbar> mxAlignTbx;
+ std::unique_ptr<ToolbarUnoDispatcher> mxAlignDispatch;
+ std::unique_ptr<weld::Toolbar> mxAlignTbx2;
+ std::unique_ptr<ToolbarUnoDispatcher> mxAlignDispatch2;
+
+ //edit objects button for online's mobile view
+ std::unique_ptr<weld::Button> mxBtnEditOLEObject;
+
+ // Internal variables
+ basegfx::B2DRange maRect;
+ basegfx::B2DRange maWorkArea;
+ const SdrView* mpView;
+ sal_uInt32 mlOldWidth;
+ sal_uInt32 mlOldHeight;
+ tools::Long mlRotX;
+ tools::Long mlRotY;
+ Fraction maUIScale;
+ MapUnit mePoolUnit;
+ FieldUnit meDlgUnit;
+
+ // Controller Items
+ ::sfx2::sidebar::ControllerItem maTransfPosXControl;
+ ::sfx2::sidebar::ControllerItem maTransfPosYControl;
+ ::sfx2::sidebar::ControllerItem maTransfWidthControl;
+ ::sfx2::sidebar::ControllerItem maTransfHeightControl;
+
+ ::sfx2::sidebar::ControllerItem maSvxAngleControl;
+ ::sfx2::sidebar::ControllerItem maRotXControl;
+ ::sfx2::sidebar::ControllerItem maRotYControl;
+ ::sfx2::sidebar::ControllerItem maProPosControl;
+ ::sfx2::sidebar::ControllerItem maProSizeControl;
+ ::sfx2::sidebar::ControllerItem maAutoWidthControl;
+ ::sfx2::sidebar::ControllerItem maAutoHeightControl;
+ ::sfx2::sidebar::ControllerItem m_aMetricCtl;
+
+ vcl::EnumContext maContext;
+ SfxBindings* mpBindings;
+
+ bool mbSizeProtected : 1;
+ bool mbPositionProtected : 1;
+ bool mbAutoWidth : 1;
+ bool mbAutoHeight : 1;
+ bool mbAdjustEnabled : 1;
+
+ css::uno::Reference<css::ui::XSidebar> mxSidebar;
+
+ DECL_LINK( ChangePosXHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( ChangePosYHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( ChangeWidthHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( ChangeHeightHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( ClickAutoHdl, weld::Toggleable&, void );
+ DECL_LINK( RotationHdl, svx::DialControl&, void );
+ DECL_STATIC_LINK( PosSizePropertyPanel, ClickObjectEditHdl, weld::Button&, void );
+
+ void Initialize();
+ void executeSize();
+
+ void MetricState( SfxItemState eState, const SfxPoolItem* pState );
+ static FieldUnit GetCurrentUnit( SfxItemState eState, const SfxPoolItem* pState );
+ void DisableControls();
+ void SetPosSizeMinMax();
+
+ /** Check if the UI scale has changed and handle such a change.
+ UI scale is an SD only feature. The UI scale is represented by items
+ ATTR_OPTIONS_SCALE_X and
+ ATTR_OPTIONS_SCALE_Y.
+ As we have no direct access (there is no dependency of svx on sd) we have to
+ use a small trick (aka hack):
+ a) call this method whenever a change of the metric item is notified,
+ b) check if the UI scale has changed (strangely, the UI scale value is available at the SdrModel.
+ c) invalidate the items for position and size to trigger notifications of their current values.
+ */
+ void UpdateUIScale();
+};
+
+
+} // end of namespace svx::sidebar
+
+
+#endif // INCLUDED_SVX_SOURCE_SIDEBAR_POSSIZE_POSSIZEPROPERTYPANEL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/shadow/ShadowPropertyPanel.cxx b/svx/source/sidebar/shadow/ShadowPropertyPanel.cxx
new file mode 100644
index 000000000..93259adc2
--- /dev/null
+++ b/svx/source/sidebar/shadow/ShadowPropertyPanel.cxx
@@ -0,0 +1,362 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ShadowPropertyPanel.hxx"
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/colorbox.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/sdshtitm.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/sdsxyitm.hxx>
+#include <svx/sdshcitm.hxx>
+#include <comphelper/lok.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+namespace svx::sidebar {
+
+ShadowPropertyPanel::ShadowPropertyPanel(
+ weld::Widget* pParent,
+ SfxBindings* pBindings)
+: PanelLayout(pParent, "ShadowPropertyPanel", "svx/ui/sidebarshadow.ui"),
+ maShadowController(SID_ATTR_FILL_SHADOW, *pBindings, *this),
+ maShadowTransController(SID_ATTR_SHADOW_TRANSPARENCE, *pBindings, *this),
+ maShadowBlurController(SID_ATTR_SHADOW_BLUR, *pBindings, *this),
+ maShadowColorController(SID_ATTR_SHADOW_COLOR, *pBindings, *this),
+ maShadowXDistanceController(SID_ATTR_SHADOW_XDISTANCE, *pBindings, *this),
+ maShadowYDistanceController(SID_ATTR_SHADOW_YDISTANCE, *pBindings, *this),
+ mpBindings(pBindings),
+ nX(0),
+ nY(0),
+ nXY(0),
+ mxShowShadow(m_xBuilder->weld_check_button("SHOW_SHADOW")),
+ mxShadowDistance(m_xBuilder->weld_metric_spin_button("LB_DISTANCE", FieldUnit::POINT)),
+ mxLBShadowColor(new ColorListBox(m_xBuilder->weld_menu_button("LB_SHADOW_COLOR"), [this]{ return GetFrameWeld(); })),
+ mxShadowAngle(m_xBuilder->weld_combo_box("LB_ANGLE")),
+ mxFTAngle(m_xBuilder->weld_label("angle")),
+ mxFTDistance(m_xBuilder->weld_label("distance")),
+ mxFTTransparency(m_xBuilder->weld_label("transparency_label")),
+ mxFTBlur(m_xBuilder->weld_label("blur_label")),
+ mxFTColor(m_xBuilder->weld_label("color")),
+ mxShadowTransSlider(m_xBuilder->weld_scale("transparency_slider")),
+ mxShadowTransMetric(m_xBuilder->weld_metric_spin_button("FIELD_TRANSPARENCY", FieldUnit::PERCENT)),
+ mxShadowBlurMetric(m_xBuilder->weld_metric_spin_button("LB_SHADOW_BLUR", FieldUnit::POINT))
+{
+ Initialize();
+}
+
+ShadowPropertyPanel::~ShadowPropertyPanel()
+{
+ mxShowShadow.reset();
+ mxFTAngle.reset();
+ mxShadowAngle.reset();
+ mxFTDistance.reset();
+ mxShadowDistance.reset();
+ mxFTTransparency.reset();
+ mxShadowTransSlider.reset();
+ mxShadowTransMetric.reset();
+ mxShadowBlurMetric.reset();
+ mxFTBlur.reset();
+ mxFTColor.reset();
+ mxLBShadowColor.reset();
+
+ maShadowController.dispose();
+ maShadowTransController.dispose();
+ maShadowBlurController.dispose();
+ maShadowColorController.dispose();
+ maShadowXDistanceController.dispose();
+ maShadowYDistanceController.dispose();
+}
+
+void ShadowPropertyPanel::Initialize()
+{
+ mxShowShadow->set_state( TRISTATE_FALSE );
+ mxShowShadow->connect_toggled( LINK(this, ShadowPropertyPanel, ClickShadowHdl ) );
+ mxShadowTransMetric->connect_value_changed( LINK(this, ShadowPropertyPanel, ModifyShadowTransMetricHdl) );
+ mxLBShadowColor->SetSelectHdl( LINK( this, ShadowPropertyPanel, ModifyShadowColorHdl ) );
+ mxShadowAngle->connect_changed( LINK(this, ShadowPropertyPanel, ModifyShadowAngleHdl) );
+ mxShadowDistance->connect_value_changed( LINK(this, ShadowPropertyPanel, ModifyShadowDistanceHdl) );
+ mxShadowTransSlider->set_range(0, 100);
+ mxShadowTransSlider->connect_value_changed( LINK(this, ShadowPropertyPanel, ModifyShadowTransSliderHdl) );
+ mxShadowBlurMetric->set_range(0, 150, FieldUnit::POINT);
+ mxShadowBlurMetric->connect_value_changed(LINK(this, ShadowPropertyPanel, ModifyShadowBlurMetricHdl));
+ InsertAngleValues();
+}
+
+IMPL_LINK_NOARG(ShadowPropertyPanel, ClickShadowHdl, weld::Toggleable&, void)
+{
+ if( mxShowShadow->get_state() == TRISTATE_FALSE )
+ {
+ SdrOnOffItem aItem(makeSdrShadowItem(false));
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_FILL_SHADOW,
+ SfxCallMode::RECORD, { &aItem });
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ mxShowShadow->set_state( TRISTATE_FALSE );
+ UpdateControls();
+ }
+ }
+ else
+ {
+ SdrOnOffItem aItem(makeSdrShadowItem(true));
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_FILL_SHADOW,
+ SfxCallMode::RECORD, { &aItem });
+
+ if (mxShadowDistance->get_value(FieldUnit::POINT) == 0)
+ mxShadowDistance->set_value( 8, FieldUnit::POINT );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ mxShowShadow->set_state( TRISTATE_TRUE );
+ UpdateControls();
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ShadowPropertyPanel, ModifyShadowColorHdl, ColorListBox&, void)
+{
+ XColorItem aItem(makeSdrShadowColorItem(mxLBShadowColor->GetSelectEntryColor()));
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_SHADOW_COLOR,
+ SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK_NOARG(ShadowPropertyPanel, ModifyShadowTransMetricHdl, weld::MetricSpinButton&, void)
+{
+ sal_uInt16 nVal = mxShadowTransMetric->get_value(FieldUnit::PERCENT);
+ SetTransparencyValue(nVal);
+ SdrPercentItem aItem( makeSdrShadowTransparenceItem(nVal) );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_SHADOW_TRANSPARENCE,
+ SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK_NOARG(ShadowPropertyPanel, ModifyShadowBlurMetricHdl, weld::MetricSpinButton&, void)
+{
+ SdrMetricItem aItem(SDRATTR_SHADOWBLUR, mxShadowBlurMetric->get_value(FieldUnit::MM_100TH));
+
+ mpBindings->GetDispatcher()->ExecuteList(SID_ATTR_SHADOW_BLUR, SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK_NOARG(ShadowPropertyPanel, ModifyShadowTransSliderHdl, weld::Scale&, void)
+{
+ sal_uInt16 nVal = mxShadowTransSlider->get_value();
+ SetTransparencyValue(nVal);
+ SdrPercentItem aItem( makeSdrShadowTransparenceItem(nVal) );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_SHADOW_TRANSPARENCE,
+ SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK_NOARG(ShadowPropertyPanel, ModifyShadowAngleHdl, weld::ComboBox&, void)
+{
+ ModifyShadowDistance();
+}
+
+IMPL_LINK_NOARG(ShadowPropertyPanel, ModifyShadowDistanceHdl, weld::MetricSpinButton&, void)
+{
+ ModifyShadowDistance();
+}
+
+void ShadowPropertyPanel::ModifyShadowDistance()
+{
+ auto nAngle = mxShadowAngle->get_active_id().toInt32();
+ nXY = mxShadowDistance->get_value(FieldUnit::MM_100TH);
+ switch (nAngle)
+ {
+ case 0: nX = nXY; nY = 0; break;
+ case 45: nX = nXY; nY = -nXY; break;
+ case 90: nX = 0; nY = - nXY; break;
+ case 135: nX = nY = -nXY; break;
+ case 180: nX = -nXY; nY = 0; break;
+ case 225: nX = -nXY; nY = nXY; break;
+ case 270: nX = 0; nY = nXY; break;
+ case 315: nX = nY = nXY; break;
+ }
+ SdrMetricItem aXItem(makeSdrShadowXDistItem(nX));
+ SdrMetricItem aYItem(makeSdrShadowYDistItem(nY));
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_SHADOW_XDISTANCE,
+ SfxCallMode::RECORD, { &aXItem });
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_SHADOW_YDISTANCE,
+ SfxCallMode::RECORD, { &aYItem });
+}
+
+void ShadowPropertyPanel::UpdateControls()
+{
+ if (mxShowShadow->get_state() == TRISTATE_FALSE)
+ {
+ mxShadowDistance->set_sensitive(false);
+ mxLBShadowColor->set_sensitive(false);
+ mxShadowAngle->set_sensitive(false);
+ mxFTAngle->set_sensitive(false);
+ mxFTDistance->set_sensitive(false);
+ mxFTTransparency->set_sensitive(false);
+ mxFTBlur->set_sensitive(false);
+ mxFTColor->set_sensitive(false);
+ mxShadowTransSlider->set_sensitive(false);
+ mxShadowTransMetric->set_sensitive(false);
+ mxShadowBlurMetric->set_sensitive(false);
+
+ return;
+ }
+ else
+ {
+ mxShadowDistance->set_sensitive(true);
+ mxLBShadowColor->set_sensitive(true);
+ mxShadowAngle->set_sensitive(true);
+ mxFTAngle->set_sensitive(true);
+ mxFTDistance->set_sensitive(true);
+ mxFTTransparency->set_sensitive(true);
+ mxFTBlur->set_sensitive(true);
+ mxFTColor->set_sensitive(true);
+ mxShadowTransSlider->set_sensitive(true);
+ mxShadowTransMetric->set_sensitive(true);
+ mxShadowBlurMetric->set_sensitive(true);
+ }
+
+ if(nX > 0 && nY == 0) { mxShadowAngle->set_active(0); nXY = nX; }
+ else if( nX > 0 && nY < 0 ) { mxShadowAngle->set_active(1); nXY = nX; }
+ else if( nX == 0 && nY < 0 ) { mxShadowAngle->set_active(2); nXY = -nY; }
+ else if( nX < 0 && nY < 0 ) { mxShadowAngle->set_active(3); nXY = -nY; }
+ else if( nX < 0 && nY == 0 ) { mxShadowAngle->set_active(4); nXY = -nX; }
+ else if( nX < 0 && nY > 0 ) { mxShadowAngle->set_active(5); nXY = nY; }
+ else if( nX == 0 && nY > 0 ) { mxShadowAngle->set_active(6); nXY = nY; }
+ else if( nX > 0 && nY > 0 ) { mxShadowAngle->set_active(7); nXY = nX; }
+ else { nXY = 0; }
+ mxShadowDistance->set_value(nXY, FieldUnit::MM_100TH);
+}
+
+void ShadowPropertyPanel::SetTransparencyValue(tools::Long nVal)
+{
+ mxShadowTransSlider->set_value(nVal);
+ mxShadowTransMetric->set_value(nVal, FieldUnit::PERCENT);
+}
+
+void ShadowPropertyPanel::InsertAngleValues()
+{
+ OUString sSuffix = weld::MetricSpinButton::MetricToString(FieldUnit::DEGREE);
+
+ const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
+
+ mxShadowAngle->append(OUString::number(0), rLocaleData.getNum(0, 0, true, true) + sSuffix);
+ mxShadowAngle->append(OUString::number(45), rLocaleData.getNum(45, 0, true, true) + sSuffix);
+ mxShadowAngle->append(OUString::number(90), rLocaleData.getNum(90, 0, true, true) + sSuffix);
+ mxShadowAngle->append(OUString::number(135), rLocaleData.getNum(135, 0, true, true) + sSuffix);
+ mxShadowAngle->append(OUString::number(180), rLocaleData.getNum(180, 0, true, true) + sSuffix);
+ mxShadowAngle->append(OUString::number(225), rLocaleData.getNum(225, 0, true, true) + sSuffix);
+ mxShadowAngle->append(OUString::number(270), rLocaleData.getNum(270, 0, true, true) + sSuffix);
+ mxShadowAngle->append(OUString::number(315), rLocaleData.getNum(315, 0, true, true) + sSuffix);
+}
+
+void ShadowPropertyPanel::NotifyItemUpdate(
+ sal_uInt16 nSID,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ switch(nSID)
+ {
+ case SID_ATTR_FILL_SHADOW:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ const SdrOnOffItem* pItem = dynamic_cast< const SdrOnOffItem* >(pState);
+ if (pItem && pItem->GetValue())
+ mxShowShadow->set_state(TRISTATE_TRUE);
+ else
+ mxShowShadow->set_state(TRISTATE_FALSE);
+ }
+ }
+ break;
+
+ case SID_ATTR_SHADOW_TRANSPARENCE:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ const SdrPercentItem* pTransparencyItem = dynamic_cast< const SdrPercentItem* >(pState);
+ if(pTransparencyItem)
+ {
+ const sal_uInt16 nVal = pTransparencyItem->GetValue();
+ SetTransparencyValue(nVal);
+ }
+ else
+ SetTransparencyValue(0);
+ }
+ }
+ break;
+ case SID_ATTR_SHADOW_BLUR:
+ {
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ const SdrMetricItem* pRadiusItem = dynamic_cast<const SdrMetricItem*>(pState);
+ if (pRadiusItem)
+ {
+ mxShadowBlurMetric->set_value(pRadiusItem->GetValue(), FieldUnit::MM_100TH);
+ }
+ }
+ }
+ break;
+ case SID_ATTR_SHADOW_COLOR:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ const XColorItem* pColorItem = dynamic_cast< const XColorItem* >(pState);
+ if(pColorItem)
+ {
+ mxLBShadowColor->SelectEntry(pColorItem->GetColorValue());
+ }
+ }
+ }
+ break;
+ case SID_ATTR_SHADOW_XDISTANCE:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ const SdrMetricItem* pXDistItem = dynamic_cast< const SdrMetricItem* >(pState);
+ if(pXDistItem)
+ {
+ nX = pXDistItem->GetValue();
+ }
+ }
+ }
+ break;
+ case SID_ATTR_SHADOW_YDISTANCE:
+ {
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ const SdrMetricItem* pYDistItem = dynamic_cast< const SdrMetricItem* >(pState);
+ if(pYDistItem)
+ {
+ nY = pYDistItem->GetValue();
+ }
+ }
+ }
+ break;
+ }
+ UpdateControls();
+}
+
+std::unique_ptr<PanelLayout> ShadowPropertyPanel::Create (
+ weld::Widget* pParent,
+ SfxBindings* pBindings)
+{
+ if(pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to ShadowPropertyPanel::Create", nullptr, 0);
+ if(pBindings == nullptr)
+ throw lang::IllegalArgumentException("no SfxBindings given to ShadowPropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<ShadowPropertyPanel>(pParent, pBindings);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/shadow/ShadowPropertyPanel.hxx b/svx/source/sidebar/shadow/ShadowPropertyPanel.hxx
new file mode 100644
index 000000000..a68405eb0
--- /dev/null
+++ b/svx/source/sidebar/shadow/ShadowPropertyPanel.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_AREA_SHADOWPROPERTYPANEL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_AREA_SHADOWPROPERTYPANEL_HXX
+
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+
+class ColorListBox;
+
+namespace svx::sidebar {
+
+class ShadowPropertyPanel
+: public PanelLayout,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+ virtual ~ShadowPropertyPanel() override;
+
+ static std::unique_ptr<PanelLayout> Create(
+ weld::Widget* pParent,
+ SfxBindings* pBindings);
+
+ virtual void NotifyItemUpdate(
+ const sal_uInt16 nSId,
+ const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(
+ const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override {};
+
+ SfxBindings* GetBindings() { return mpBindings;}
+
+ void Initialize();
+
+ ShadowPropertyPanel(
+ weld::Widget* pParent,
+ SfxBindings* pBindings);
+
+private:
+ ::sfx2::sidebar::ControllerItem maShadowController;
+ ::sfx2::sidebar::ControllerItem maShadowTransController;
+ ::sfx2::sidebar::ControllerItem maShadowBlurController;
+ ::sfx2::sidebar::ControllerItem maShadowColorController;
+ ::sfx2::sidebar::ControllerItem maShadowXDistanceController;
+ ::sfx2::sidebar::ControllerItem maShadowYDistanceController;
+
+ SfxBindings* mpBindings;
+ tools::Long nX,nY,nXY;
+
+ std::unique_ptr<weld::CheckButton> mxShowShadow;
+ std::unique_ptr<weld::MetricSpinButton> mxShadowDistance;
+ std::unique_ptr<ColorListBox> mxLBShadowColor;
+ std::unique_ptr<weld::ComboBox> mxShadowAngle;
+ std::unique_ptr<weld::Label> mxFTAngle;
+ std::unique_ptr<weld::Label> mxFTDistance;
+ std::unique_ptr<weld::Label> mxFTTransparency;
+ std::unique_ptr<weld::Label> mxFTBlur;
+ std::unique_ptr<weld::Label> mxFTColor;
+ std::unique_ptr<weld::Scale> mxShadowTransSlider;
+ std::unique_ptr<weld::MetricSpinButton> mxShadowTransMetric;
+ std::unique_ptr<weld::MetricSpinButton> mxShadowBlurMetric;
+
+ void InsertAngleValues();
+ void SetTransparencyValue(tools::Long);
+ void UpdateControls();
+ void ModifyShadowDistance();
+
+ DECL_LINK(ClickShadowHdl, weld::Toggleable&, void);
+ DECL_LINK(ModifyShadowColorHdl, ColorListBox&, void);
+ DECL_LINK(ModifyShadowTransMetricHdl, weld::MetricSpinButton&, void);
+ DECL_LINK(ModifyShadowAngleHdl, weld::ComboBox&, void);
+ DECL_LINK(ModifyShadowDistanceHdl, weld::MetricSpinButton&, void);
+ DECL_LINK(ModifyShadowTransSliderHdl, weld::Scale&, void);
+ DECL_LINK(ModifyShadowBlurMetricHdl, weld::MetricSpinButton&, void);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/shapes/DefaultShapesPanel.cxx b/svx/source/sidebar/shapes/DefaultShapesPanel.cxx
new file mode 100644
index 000000000..2dc8092a5
--- /dev/null
+++ b/svx/source/sidebar/shapes/DefaultShapesPanel.cxx
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <DefaultShapesPanel.hxx>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <comphelper/dispatchcommand.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+namespace svx::sidebar {
+
+DefaultShapesPanel::DefaultShapesPanel (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame)
+ : PanelLayout(pParent, "DefaultShapesPanel", "svx/ui/defaultshapespanel.ui")
+ , mxLineArrowSet(new ValueSet(nullptr))
+ , mxLineArrowSetWin(new weld::CustomWeld(*m_xBuilder, "LinesArrows", *mxLineArrowSet))
+ , mxCurveSet(new ValueSet(nullptr))
+ , mxCurveSetWin(new weld::CustomWeld(*m_xBuilder, "Curves", *mxCurveSet))
+ , mxConnectorSet(new ValueSet(nullptr))
+ , mxConnectorSetWin(new weld::CustomWeld(*m_xBuilder, "Connectors", *mxConnectorSet))
+ , mxBasicShapeSet(new ValueSet(nullptr))
+ , mxBasicShapeSetWin(new weld::CustomWeld(*m_xBuilder, "BasicShapes", *mxBasicShapeSet))
+ , mxSymbolShapeSet(new ValueSet(nullptr))
+ , mxSymbolShapeSetWin(new weld::CustomWeld(*m_xBuilder, "SymbolShapes", *mxSymbolShapeSet))
+ , mxBlockArrowSet(new ValueSet(nullptr))
+ , mxBlockArrowSetWin(new weld::CustomWeld(*m_xBuilder, "BlockArrows", *mxBlockArrowSet))
+ , mxFlowchartSet(new ValueSet(nullptr))
+ , mxFlowchartSetWin(new weld::CustomWeld(*m_xBuilder, "Flowcharts", *mxFlowchartSet))
+ , mxCalloutSet(new ValueSet(nullptr))
+ , mxCalloutSetWin(new weld::CustomWeld(*m_xBuilder, "Callouts", *mxCalloutSet))
+ , mxStarSet(new ValueSet(nullptr))
+ , mxStarSetWin(new weld::CustomWeld(*m_xBuilder, "Stars", *mxStarSet))
+ , mx3DObjectSet(new ValueSet(nullptr))
+ , mx3DObjectSetWin(new weld::CustomWeld(*m_xBuilder, "3DObjects", *mx3DObjectSet))
+ , mxFrame(rxFrame)
+{
+ Initialize();
+ pParent->set_size_request(pParent->get_approximate_digit_width() * 20, -1);
+ m_xContainer->set_size_request(m_xContainer->get_approximate_digit_width() * 25, -1);
+}
+
+std::unique_ptr<PanelLayout> DefaultShapesPanel::Create(
+ weld::Widget* pParent,
+ const Reference< XFrame >& rxFrame)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to DefaultShapesPanel::Create", nullptr, 0);
+ if ( ! rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to DefaultShapesPanel::Create", nullptr, 1);
+
+ return std::make_unique<DefaultShapesPanel>(pParent, rxFrame);
+}
+
+void DefaultShapesPanel::Initialize()
+{
+ mpShapesSetMap = decltype(mpShapesSetMap){
+ { mxLineArrowSet.get(), mpLineShapes },
+ { mxCurveSet.get(), mpCurveShapes },
+ { mxConnectorSet.get(), mpConnectorShapes },
+ { mxBasicShapeSet.get(), mpBasicShapes },
+ { mxSymbolShapeSet.get(), mpSymbolShapes },
+ { mxBlockArrowSet.get(), mpBlockArrowShapes },
+ { mxFlowchartSet.get(), mpFlowchartShapes },
+ { mxCalloutSet.get(), mpCalloutShapes },
+ { mxStarSet.get(), mpStarShapes },
+ { mx3DObjectSet.get(), mp3DShapes }
+ };
+ populateShapes();
+ for(auto& aSetMap: mpShapesSetMap)
+ {
+ aSetMap.first->SetColor(Application::GetSettings().GetStyleSettings().GetDialogColor());
+ aSetMap.first->SetSelectHdl(LINK(this, DefaultShapesPanel, ShapeSelectHdl));
+ }
+}
+
+DefaultShapesPanel::~DefaultShapesPanel()
+{
+ mpShapesSetMap.clear();
+ mxLineArrowSetWin.reset();
+ mxLineArrowSet.reset();
+ mxCurveSetWin.reset();
+ mxCurveSet.reset();
+ mxConnectorSetWin.reset();
+ mxConnectorSet.reset();
+ mxBasicShapeSetWin.reset();
+ mxBasicShapeSet.reset();
+ mxSymbolShapeSetWin.reset();
+ mxSymbolShapeSet.reset();
+ mxBlockArrowSetWin.reset();
+ mxBlockArrowSet.reset();
+ mxFlowchartSetWin.reset();
+ mxFlowchartSet.reset();
+ mxCalloutSetWin.reset();
+ mxCalloutSet.reset();
+ mxStarSetWin.reset();
+ mxStarSet.reset();
+ mx3DObjectSetWin.reset();
+ mx3DObjectSet.reset();
+}
+
+IMPL_LINK(DefaultShapesPanel, ShapeSelectHdl, ValueSet*, rValueSet, void)
+{
+ for(auto& aSetMap : mpShapesSetMap)
+ {
+ if(rValueSet == aSetMap.first)
+ {
+ sal_uInt16 nSelectionId = aSetMap.first->GetSelectedItemId();
+ comphelper::dispatchCommand(aSetMap.second[nSelectionId - 1], {});
+ }
+ else
+ aSetMap.first->SetNoSelection();
+ }
+}
+
+void DefaultShapesPanel::populateShapes()
+{
+ OUString sSlotStr, sLabel;
+ Image aSlotImage;
+ for(auto& aSet : mpShapesSetMap)
+ {
+ aSet.first->SetColCount(6);
+ for(std::map<sal_uInt16, OUString>::size_type i = 0; i < aSet.second.size(); i++)
+ {
+ sSlotStr = aSet.second[i];
+ aSlotImage = vcl::CommandInfoProvider::GetImageForCommand(sSlotStr, mxFrame);
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(sSlotStr,
+ vcl::CommandInfoProvider::GetModuleIdentifier(mxFrame));
+ sLabel = vcl::CommandInfoProvider::GetTooltipForCommand(sSlotStr, aProperties, mxFrame);
+ sal_uInt16 nSelectionId = i + 1; // tdf#142767 id 0 is reserved for nothing-selected
+ aSet.first->InsertItem(nSelectionId, aSlotImage, sLabel);
+ }
+ }
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/shapes/ShapesUtil.cxx b/svx/source/sidebar/shapes/ShapesUtil.cxx
new file mode 100644
index 000000000..ffd1acb62
--- /dev/null
+++ b/svx/source/sidebar/shapes/ShapesUtil.cxx
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ShapesUtil.hxx>
+#include <map>
+#include <rtl/ustring.hxx>
+
+namespace svx::sidebar{
+SvxShapeCommandsMap::SvxShapeCommandsMap()
+{
+ mpLineShapes = decltype(mpLineShapes){
+ {0, ".uno:Line"},
+ {1, ".uno:LineArrowEnd"},
+ {2, ".uno:LineCircleArrow"},
+ {3, ".uno:LineSquareArrow"},
+ {4, ".uno:LineArrows"},
+ {5, ".uno:LineArrowStart"},
+ {6, ".uno:LineArrowCircle"},
+ {7, ".uno:LineArrowSquare"},
+ {8, ".uno:MeasureLine"},
+ {9, ".uno:Line_Diagonal"}
+ };
+
+ mpCurveShapes = decltype(mpCurveShapes){
+ {0, ".uno:Freeline_Unfilled"},
+ {1, ".uno:Bezier_Unfilled"},
+ {2, ".uno:Polygon_Unfilled"},
+ {3, ".uno:Polygon_Diagonal_Unfilled"},
+ {4, ".uno:Freeline"},
+ {5, ".uno:BezierFill"},
+ {6, ".uno:Polygon"},
+ {7, ".uno:Polygon_Diagonal"}
+ };
+
+ mpConnectorShapes = decltype(mpConnectorShapes){
+ {0, ".uno:ConnectorArrowEnd"},
+ {1, ".uno:ConnectorLineArrowEnd"},
+ {2, ".uno:ConnectorCurveArrowEnd"},
+ {3, ".uno:ConnectorLinesArrowEnd"},
+ {4, ".uno:Connector"},
+ {5, ".uno:ConnectorLine"},
+ {6, ".uno:ConnectorCurve"},
+ {7, ".uno:ConnectorLines"},
+ {8, ".uno:ConnectorArrows"},
+ {9, ".uno:ConnectorLineArrows"},
+ {10, ".uno:ConnectorCurveArrows"},
+ {11, ".uno:ConnectorLinesArrows"}
+ };
+
+ mpBasicShapes = decltype(mpBasicShapes){
+ {0, ".uno:BasicShapes.rectangle"},
+ {1, ".uno:BasicShapes.round-rectangle"},
+ {2, ".uno:BasicShapes.quadrat"},
+ {3, ".uno:BasicShapes.round-quadrat"},
+ {4, ".uno:BasicShapes.parallelogram"},
+ {5, ".uno:BasicShapes.trapezoid"},
+ {6, ".uno:BasicShapes.ellipse"},
+ {7, ".uno:BasicShapes.circle"},
+ {8, ".uno:BasicShapes.circle-pie"},
+ {9, ".uno:CircleCut"},
+ {10, ".uno:Arc"},
+ {11, ".uno:BasicShapes.block-arc"},
+ {12, ".uno:BasicShapes.isosceles-triangle"},
+ {13, ".uno:BasicShapes.right-triangle"},
+ {14, ".uno:BasicShapes.diamond"},
+ {15, ".uno:BasicShapes.pentagon"},
+ {16, ".uno:BasicShapes.hexagon"},
+ {17, ".uno:BasicShapes.octagon"},
+ {18, ".uno:BasicShapes.cross"},
+ {19, ".uno:BasicShapes.can"},
+ {20, ".uno:BasicShapes.cube"},
+ {21, ".uno:BasicShapes.paper"},
+ {22, ".uno:BasicShapes.frame"},
+ {23, ".uno:BasicShapes.ring"}
+ };
+
+ mpSymbolShapes = decltype(mpSymbolShapes){
+ {0, ".uno:SymbolShapes.smiley"},
+ {1, ".uno:SymbolShapes.sun"},
+ {2, ".uno:SymbolShapes.moon"},
+ {3, ".uno:SymbolShapes.lightning"},
+ {4, ".uno:SymbolShapes.heart"},
+ {5, ".uno:SymbolShapes.flower"},
+ {6, ".uno:SymbolShapes.cloud"},
+ {7, ".uno:SymbolShapes.forbidden"},
+ {8, ".uno:SymbolShapes.puzzle"},
+ {9, ".uno:SymbolShapes.bracket-pair"},
+ {10, ".uno:SymbolShapes.left-bracket"},
+ {11, ".uno:SymbolShapes.right-bracket"},
+ {12, ".uno:SymbolShapes.brace-pair"},
+ {13, ".uno:SymbolShapes.left-brace"},
+ {14, ".uno:SymbolShapes.right-brace"},
+ {15, ".uno:SymbolShapes.quad-bevel"},
+ {16, ".uno:SymbolShapes.octagon-bevel"},
+ {17, ".uno:SymbolShapes.diamond-bevel"}
+ };
+
+ mpBlockArrowShapes = decltype(mpBlockArrowShapes){
+ {0, ".uno:ArrowShapes.left-arrow"},
+ {1, ".uno:ArrowShapes.right-arrow"},
+ {2, ".uno:ArrowShapes.up-arrow"},
+ {3, ".uno:ArrowShapes.down-arrow"},
+ {4, ".uno:ArrowShapes.left-right-arrow"},
+ {5, ".uno:ArrowShapes.up-down-arrow"},
+ {6, ".uno:ArrowShapes.up-right-arrow"},
+ {7, ".uno:ArrowShapes.up-right-down-arrow"},
+ {8, ".uno:ArrowShapes.quad-arrow"},
+ {9, ".uno:ArrowShapes.corner-right-arrow"},
+ {10, ".uno:ArrowShapes.split-arrow"},
+ {11, ".uno:ArrowShapes.striped-right-arrow"},
+ {12, ".uno:ArrowShapes.notched-right-arrow"},
+ {13, ".uno:ArrowShapes.pentagon-right"},
+ {14, ".uno:ArrowShapes.chevron"},
+ {15, ".uno:ArrowShapes.right-arrow-callout"},
+ {16, ".uno:ArrowShapes.left-arrow-callout"},
+ {17, ".uno:ArrowShapes.up-arrow-callout"},
+ {18, ".uno:ArrowShapes.left-right-arrow-callout"},
+ {19, ".uno:ArrowShapes.up-down-arrow-callout"},
+ {20, ".uno:ArrowShapes.up-right-arrow-callout"},
+ {21, ".uno:ArrowShapes.quad-arrow-callout"},
+ {22, ".uno:ArrowShapes.circular-arrow"},
+ {23, ".uno:ArrowShapes.down-arrow-callout"},
+ {24, ".uno:ArrowShapes.split-round-arrow"},
+ {25, ".uno:ArrowShapes.s-sharped-arrow"}
+ };
+
+ mpFlowchartShapes = decltype(mpFlowchartShapes){
+ {0, ".uno:FlowChartShapes.flowchart-process"},
+ {1, ".uno:FlowChartShapes.flowchart-alternate-process"},
+ {2, ".uno:FlowChartShapes.flowchart-decision"},
+ {3, ".uno:FlowChartShapes.flowchart-data"},
+ {4, ".uno:FlowChartShapes.flowchart-predefined-process"},
+ {5, ".uno:FlowChartShapes.flowchart-internal-storage"},
+ {6, ".uno:FlowChartShapes.flowchart-document"},
+ {7, ".uno:FlowChartShapes.flowchart-multidocument"},
+ {8, ".uno:FlowChartShapes.flowchart-terminator"},
+ {9, ".uno:FlowChartShapes.flowchart-preparation"},
+ {10, ".uno:FlowChartShapes.flowchart-manual-input"},
+ {11, ".uno:FlowChartShapes.flowchart-manual-operation"},
+ {12, ".uno:FlowChartShapes.flowchart-connector"},
+ {13, ".uno:FlowChartShapes.flowchart-off-page-connector"},
+ {14, ".uno:FlowChartShapes.flowchart-card"},
+ {15, ".uno:FlowChartShapes.flowchart-punched-tape"},
+ {16, ".uno:FlowChartShapes.flowchart-summing-junction"},
+ {17, ".uno:FlowChartShapes.flowchart-or"},
+ {18, ".uno:FlowChartShapes.flowchart-collate"},
+ {19, ".uno:FlowChartShapes.flowchart-sort"},
+ {20, ".uno:FlowChartShapes.flowchart-extract"},
+ {21, ".uno:FlowChartShapes.flowchart-merge"},
+ {22, ".uno:FlowChartShapes.flowchart-stored-data"},
+ {23, ".uno:FlowChartShapes.flowchart-delay"},
+ {24, ".uno:FlowChartShapes.flowchart-sequential-access"},
+ {25, ".uno:FlowChartShapes.flowchart-magnetic-disk"},
+ {26, ".uno:FlowChartShapes.flowchart-direct-access-storage"},
+ {27, ".uno:FlowChartShapes.flowchart-display"}
+ };
+
+ mpCalloutShapes = decltype(mpCalloutShapes){
+ {0, ".uno:CalloutShapes.rectangular-callout"},
+ {1, ".uno:CalloutShapes.round-rectangular-callout"},
+ {2, ".uno:CalloutShapes.round-callout"},
+ {3, ".uno:CalloutShapes.cloud-callout"},
+ {4, ".uno:CalloutShapes.line-callout-1"},
+ {5, ".uno:CalloutShapes.line-callout-2"},
+ {6, ".uno:CalloutShapes.line-callout-3"}
+ };
+
+ mpStarShapes = decltype(mpStarShapes){
+ {0, ".uno:StarShapes.star4"},
+ {1, ".uno:StarShapes.star5"},
+ {2, ".uno:StarShapes.star6"},
+ {3, ".uno:StarShapes.star8"},
+ {4, ".uno:StarShapes.star12"},
+ {5, ".uno:StarShapes.star24"},
+ {6, ".uno:StarShapes.bang"},
+ {7, ".uno:StarShapes.vertical-scroll"},
+ {8, ".uno:StarShapes.horizontal-scroll"},
+ {9, ".uno:StarShapes.signet"},
+ {10, ".uno:StarShapes.doorplate"},
+ {11, ".uno:StarShapes.concave-star6"}
+ };
+
+ mp3DShapes = decltype(mp3DShapes){
+ {0, ".uno:Cube"},
+ {1, ".uno:Sphere"},
+ {2, ".uno:Cylinder"},
+ {3, ".uno:Cone"},
+ {4, ".uno:Cyramid"},
+ {5, ".uno:Torus"},
+ {6, ".uno:Shell3D"},
+ {7, ".uno:HalfSphere"}
+ };
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ \ No newline at end of file
diff --git a/svx/source/sidebar/styles/StylesPropertyPanel.cxx b/svx/source/sidebar/styles/StylesPropertyPanel.cxx
new file mode 100644
index 000000000..4e6b2235d
--- /dev/null
+++ b/svx/source/sidebar/styles/StylesPropertyPanel.cxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include <sal/config.h>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+#include "StylesPropertyPanel.hxx"
+
+using namespace css;
+using namespace css::uno;
+
+namespace svx::sidebar {
+
+std::unique_ptr<PanelLayout> StylesPropertyPanel::Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to StylesPropertyPanel::Create", nullptr, 0);
+ if ( ! rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to StylesPropertyPanel::Create", nullptr, 1);
+
+ return std::make_unique<StylesPropertyPanel>(pParent, rxFrame);
+}
+
+StylesPropertyPanel::StylesPropertyPanel(weld::Widget* pParent, const css::uno::Reference<css::frame::XFrame>& rxFrame)
+ : PanelLayout(pParent, "SidebarStylesPanel", "svx/ui/sidebarstylespanel.ui")
+ , m_xFontStyle(m_xBuilder->weld_toolbar("fontstyletoolbox"))
+ , m_xFontStyleDispatch(new ToolbarUnoDispatcher(*m_xFontStyle, *m_xBuilder, rxFrame))
+ , m_xStyle(m_xBuilder->weld_toolbar("style"))
+ , m_xStyleDispatch(new ToolbarUnoDispatcher(*m_xStyle, *m_xBuilder, rxFrame))
+{
+}
+
+StylesPropertyPanel::~StylesPropertyPanel()
+{
+ m_xStyleDispatch.reset();
+ m_xStyle.reset();
+ m_xFontStyleDispatch.reset();
+ m_xFontStyle.reset();
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/sidebar/styles/StylesPropertyPanel.hxx b/svx/source/sidebar/styles/StylesPropertyPanel.hxx
new file mode 100644
index 000000000..66f773ae9
--- /dev/null
+++ b/svx/source/sidebar/styles/StylesPropertyPanel.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <sfx2/weldutils.hxx>
+
+namespace svx::sidebar{
+
+class StylesPropertyPanel : public PanelLayout
+{
+private:
+ std::unique_ptr<weld::Toolbar> m_xFontStyle;
+ std::unique_ptr<ToolbarUnoDispatcher> m_xFontStyleDispatch;
+
+ std::unique_ptr<weld::Toolbar> m_xStyle;
+ std::unique_ptr<ToolbarUnoDispatcher> m_xStyleDispatch;
+
+public:
+ virtual ~StylesPropertyPanel() override;
+
+ static std::unique_ptr<PanelLayout> Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame);
+
+ StylesPropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame);
+};
+
+} //end of namespace svx::sidebar
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/sidebar/text/TextCharacterSpacingControl.cxx b/svx/source/sidebar/text/TextCharacterSpacingControl.cxx
new file mode 100644
index 000000000..ad9650477
--- /dev/null
+++ b/svx/source/sidebar/text/TextCharacterSpacingControl.cxx
@@ -0,0 +1,224 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <sfx2/bindings.hxx>
+#include "TextCharacterSpacingControl.hxx"
+#include <unotools/viewoptions.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/kernitem.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <TextCharacterSpacingPopup.hxx>
+#include <svl/itempool.hxx>
+#include <helpids.h>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+
+#define SPACING_VERY_TIGHT -30
+#define SPACING_TIGHT -15
+#define SPACING_NORMAL 0
+#define SPACING_LOOSE 30
+#define SPACING_VERY_LOOSE 60
+
+namespace svx {
+
+TextCharacterSpacingControl::TextCharacterSpacingControl(TextCharacterSpacingPopup* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/textcharacterspacingcontrol.ui", "TextCharacterSpacingControl")
+ , mnCustomKern(0)
+ , mnLastCus(SPACING_NOCUSTOM)
+ , mxEditKerning(m_xBuilder->weld_metric_spin_button("kerning", FieldUnit::POINT))
+ , mxTight(m_xBuilder->weld_button("tight"))
+ , mxVeryTight(m_xBuilder->weld_button("very_tight"))
+ , mxNormal(m_xBuilder->weld_button("normal"))
+ , mxLoose(m_xBuilder->weld_button("loose"))
+ , mxVeryLoose(m_xBuilder->weld_button("very_loose"))
+ , mxLastCustom(m_xBuilder->weld_button("last_custom"))
+ , mxControl(pControl)
+{
+ mxEditKerning->connect_value_changed(LINK(this, TextCharacterSpacingControl, KerningModifyHdl));
+ mxEditKerning->set_help_id(HID_SPACING_MB_KERN);
+
+ Link<weld::Button&,void> aLink = LINK(this, TextCharacterSpacingControl, PredefinedValuesHdl);
+ mxNormal->connect_clicked(aLink);
+ mxVeryTight->connect_clicked(aLink);
+ mxTight->connect_clicked(aLink);
+ mxVeryLoose->connect_clicked(aLink);
+ mxLoose->connect_clicked(aLink);
+ mxLastCustom->connect_clicked(aLink);
+
+ Initialize();
+}
+
+void TextCharacterSpacingControl::GrabFocus()
+{
+ tools::Long nKerning = mxEditKerning->get_value(FieldUnit::NONE);
+ switch (nKerning)
+ {
+ case SPACING_VERY_TIGHT:
+ mxVeryTight->grab_focus();
+ break;
+ case SPACING_TIGHT:
+ mxTight->grab_focus();
+ break;
+ case SPACING_NORMAL:
+ mxNormal->grab_focus();
+ break;
+ case SPACING_LOOSE:
+ mxLoose->grab_focus();
+ break;
+ case SPACING_VERY_LOOSE:
+ mxVeryLoose->grab_focus();
+ break;
+ default:
+ if (nKerning == mnCustomKern)
+ mxLastCustom->grab_focus();
+ else
+ mxEditKerning->grab_focus();
+ }
+}
+
+TextCharacterSpacingControl::~TextCharacterSpacingControl()
+{
+ if (mnLastCus == SPACING_CLOSE_BY_CUS_EDIT)
+ {
+ SvtViewOptions aWinOpt(EViewType::Window, SIDEBAR_SPACING_GLOBAL_VALUE);
+ css::uno::Sequence<css::beans::NamedValue> aSeq
+ { { "Spacing", css::uno::Any(OUString::number(mnCustomKern)) } };
+ aWinOpt.SetUserData(aSeq);
+ }
+}
+
+void TextCharacterSpacingControl::Initialize()
+{
+ const SvxKerningItem* pKerningItem(nullptr);
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ SfxItemState eState = pViewFrm ? pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_CHAR_KERNING, pKerningItem) : SfxItemState::UNKNOWN;
+
+ tools::Long nKerning = 0;
+
+ if(pKerningItem)
+ nKerning = pKerningItem->GetValue();
+
+ SvtViewOptions aWinOpt(EViewType::Window, SIDEBAR_SPACING_GLOBAL_VALUE);
+ if(aWinOpt.Exists())
+ {
+ css::uno::Sequence<css::beans::NamedValue> aSeq = aWinOpt.GetUserData();
+ OUString aTmp;
+ if(aSeq.hasElements())
+ aSeq[0].Value >>= aTmp;
+
+ OUString aWinData(aTmp);
+ mnCustomKern = aWinData.toInt32();
+ mnLastCus = SPACING_CLOSE_BY_CUS_EDIT;
+ }
+ else
+ {
+ mnLastCus = SPACING_NOCUSTOM;
+ }
+
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ MapUnit eUnit = GetCoreMetric();
+ MapUnit eOrgUnit = eUnit;
+ tools::Long nBig = mxEditKerning->normalize(nKerning);
+ nKerning = OutputDevice::LogicToLogic(nBig, eOrgUnit, MapUnit::MapPoint);
+ mxEditKerning->set_value(nKerning, FieldUnit::NONE);
+ }
+ else if(SfxItemState::DISABLED == eState)
+ {
+ mxEditKerning->set_text(OUString());
+ mxEditKerning->set_sensitive(false);
+ }
+ else
+ {
+ mxEditKerning->set_text(OUString());
+ mxEditKerning->set_sensitive(false);
+ }
+}
+
+void TextCharacterSpacingControl::ExecuteCharacterSpacing(tools::Long nValue, bool bClose)
+{
+ MapUnit eUnit = GetCoreMetric();
+
+ tools::Long nSign = (nValue < 0) ? -1 : 1;
+ nValue = nValue * nSign;
+
+ tools::Long nVal = OutputDevice::LogicToLogic(nValue, MapUnit::MapPoint, eUnit);
+ short nKern = (nValue == 0) ? 0 : static_cast<short>(mxEditKerning->denormalize(nVal));
+
+ SvxKerningItem aKernItem(nSign * nKern, SID_ATTR_CHAR_KERNING);
+
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ {
+ pViewFrm->GetBindings().GetDispatcher()->ExecuteList(SID_ATTR_CHAR_KERNING,
+ SfxCallMode::RECORD, { &aKernItem });
+ }
+
+ if (bClose)
+ mxControl->EndPopupMode();
+}
+
+IMPL_LINK(TextCharacterSpacingControl, PredefinedValuesHdl, weld::Button&, rControl, void)
+{
+ mnLastCus = SPACING_CLOSE_BY_CLICK_ICON;
+
+ if (&rControl == mxNormal.get())
+ {
+ ExecuteCharacterSpacing(SPACING_NORMAL);
+ }
+ else if (&rControl == mxVeryTight.get())
+ {
+ ExecuteCharacterSpacing(SPACING_VERY_TIGHT);
+ }
+ else if (&rControl == mxTight.get())
+ {
+ ExecuteCharacterSpacing(SPACING_TIGHT);
+ }
+ else if (&rControl == mxVeryLoose.get())
+ {
+ ExecuteCharacterSpacing(SPACING_VERY_LOOSE);
+ }
+ else if (&rControl == mxLoose.get())
+ {
+ ExecuteCharacterSpacing(SPACING_LOOSE);
+ }
+ else if (&rControl == mxLastCustom.get())
+ {
+ ExecuteCharacterSpacing(mnCustomKern);
+ }
+}
+
+IMPL_LINK_NOARG(TextCharacterSpacingControl, KerningModifyHdl, weld::MetricSpinButton&, void)
+{
+ mnLastCus = SPACING_CLOSE_BY_CUS_EDIT;
+ mnCustomKern = mxEditKerning->get_value(FieldUnit::NONE);
+
+ ExecuteCharacterSpacing(mnCustomKern, false);
+}
+
+MapUnit TextCharacterSpacingControl::GetCoreMetric()
+{
+ SfxItemPool &rPool = SfxGetpApp()->GetPool();
+ sal_uInt16 nWhich = rPool.GetWhich(SID_ATTR_CHAR_KERNING);
+ return rPool.GetMetric(nWhich);
+}
+
+} // end of namespace svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/text/TextCharacterSpacingControl.hxx b/svx/source/sidebar/text/TextCharacterSpacingControl.hxx
new file mode 100644
index 000000000..a8ce8b7fb
--- /dev/null
+++ b/svx/source/sidebar/text/TextCharacterSpacingControl.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_TEXT_TEXTCHARACTERSPACINGCONTROL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_TEXT_TEXTCHARACTERSPACINGCONTROL_HXX
+
+#include <svtools/toolbarmenu.hxx>
+
+namespace svx {
+#define SPACING_NOCUSTOM 0
+#define SPACING_CLOSE_BY_CLICK_ICON -1
+#define SPACING_CLOSE_BY_CUS_EDIT 1
+
+inline constexpr OUStringLiteral SIDEBAR_SPACING_GLOBAL_VALUE = u"PopupPanel_Spacing";
+
+class TextCharacterSpacingPopup;
+
+class TextCharacterSpacingControl final : public WeldToolbarPopup
+{
+public:
+ explicit TextCharacterSpacingControl(TextCharacterSpacingPopup* pControl, weld::Widget* pParent);
+
+ virtual void GrabFocus() override;
+
+ virtual ~TextCharacterSpacingControl() override;
+
+private:
+ tools::Long mnCustomKern;
+ short mnLastCus;
+
+ std::unique_ptr<weld::MetricSpinButton> mxEditKerning;
+ std::unique_ptr<weld::Button> mxTight;
+ std::unique_ptr<weld::Button> mxVeryTight;
+ std::unique_ptr<weld::Button> mxNormal;
+ std::unique_ptr<weld::Button> mxLoose;
+ std::unique_ptr<weld::Button> mxVeryLoose;
+ std::unique_ptr<weld::Button> mxLastCustom;
+
+ rtl::Reference<TextCharacterSpacingPopup> mxControl;
+
+ void Initialize();
+ void ExecuteCharacterSpacing(tools::Long nValue, bool bClose = true);
+
+ DECL_LINK(PredefinedValuesHdl, weld::Button&, void);
+ DECL_LINK(KerningModifyHdl, weld::MetricSpinButton&, void);
+
+ static MapUnit GetCoreMetric();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/text/TextCharacterSpacingPopup.cxx b/svx/source/sidebar/text/TextCharacterSpacingPopup.cxx
new file mode 100644
index 000000000..a8eef9000
--- /dev/null
+++ b/svx/source/sidebar/text/TextCharacterSpacingPopup.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <TextCharacterSpacingPopup.hxx>
+#include "TextCharacterSpacingControl.hxx"
+#include <vcl/toolbox.hxx>
+
+using namespace svx;
+
+TextCharacterSpacingPopup::TextCharacterSpacingPopup(
+ const css::uno::Reference<css::uno::XComponentContext>& rContext)
+ : PopupWindowController(rContext, nullptr, OUString())
+{
+}
+
+void TextCharacterSpacingPopup::initialize(const css::uno::Sequence<css::uno::Any>& rArguments)
+{
+ PopupWindowController::initialize(rArguments);
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWNONLY | pToolBox->GetItemBits(nId));
+}
+
+TextCharacterSpacingPopup::~TextCharacterSpacingPopup() {}
+
+std::unique_ptr<WeldToolbarPopup> TextCharacterSpacingPopup::weldPopupWindow()
+{
+ return std::make_unique<TextCharacterSpacingControl>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> TextCharacterSpacingPopup::createVclPopupWindow(vcl::Window* pParent)
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(
+ getFrameInterface(), pParent,
+ std::make_unique<TextCharacterSpacingControl>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+OUString TextCharacterSpacingPopup::getImplementationName()
+{
+ return "com.sun.star.comp.svx.CharacterSpacingToolBoxControl";
+}
+
+css::uno::Sequence<OUString> TextCharacterSpacingPopup::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_CharacterSpacingToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new TextCharacterSpacingPopup(rContext));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/text/TextPropertyPanel.cxx b/svx/source/sidebar/text/TextPropertyPanel.cxx
new file mode 100644
index 000000000..1b59a79aa
--- /dev/null
+++ b/svx/source/sidebar/text/TextPropertyPanel.cxx
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TextPropertyPanel.hxx"
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <comphelper/lok.hxx>
+#include <sfx2/viewsh.hxx>
+
+using namespace css;
+
+namespace svx::sidebar {
+
+std::unique_ptr<PanelLayout> TextPropertyPanel::Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to TextPropertyPanel::Create", nullptr, 0);
+ if ( ! rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to TextPropertyPanel::Create", nullptr, 1);
+
+ return std::make_unique<TextPropertyPanel>(pParent, rxFrame);
+}
+
+TextPropertyPanel::TextPropertyPanel(weld::Widget* pParent, const css::uno::Reference<css::frame::XFrame>& rxFrame)
+ : PanelLayout(pParent, "SidebarTextPanel", "svx/ui/sidebartextpanel.ui")
+ , mxFont(m_xBuilder->weld_toolbar("font"))
+ , mxFontDispatch(new ToolbarUnoDispatcher(*mxFont, *m_xBuilder, rxFrame))
+ , mxFontHeight(m_xBuilder->weld_toolbar("fontheight"))
+ , mxFontHeightDispatch(new ToolbarUnoDispatcher(*mxFontHeight, *m_xBuilder, rxFrame))
+ , mxFontEffects(m_xBuilder->weld_toolbar("fonteffects"))
+ , mxFontEffectsDispatch(new ToolbarUnoDispatcher(*mxFontEffects, *m_xBuilder, rxFrame))
+ , mxFontAdjust(m_xBuilder->weld_toolbar("fontadjust"))
+ , mxFontAdjustDispatch(new ToolbarUnoDispatcher(*mxFontAdjust, *m_xBuilder, rxFrame))
+ , mxToolBoxFontColorSw(m_xBuilder->weld_toolbar("colorbar_writer"))
+ , mxToolBoxFontColorSwDispatch(new ToolbarUnoDispatcher(*mxToolBoxFontColorSw, *m_xBuilder, rxFrame))
+ , mxToolBoxFontColor(m_xBuilder->weld_toolbar("colorbar_others"))
+ , mxToolBoxFontColorDispatch(new ToolbarUnoDispatcher(*mxToolBoxFontColor, *m_xBuilder, rxFrame))
+ , mxToolBoxBackgroundColor(m_xBuilder->weld_toolbar("colorbar_background"))
+ , mxToolBoxBackgroundColorDispatch(new ToolbarUnoDispatcher(*mxToolBoxBackgroundColor, *m_xBuilder, rxFrame))
+ , mxResetBar(m_xBuilder->weld_toolbar("resetattr"))
+ , mxResetBarDispatch(new ToolbarUnoDispatcher(*mxResetBar, *m_xBuilder, rxFrame))
+ , mxDefaultBar(m_xBuilder->weld_toolbar("defaultattr"))
+ , mxDefaultBarDispatch(new ToolbarUnoDispatcher(*mxDefaultBar, *m_xBuilder, rxFrame))
+ , mxPositionBar(m_xBuilder->weld_toolbar("position"))
+ , mxPositionBarDispatch(new ToolbarUnoDispatcher(*mxPositionBar, *m_xBuilder, rxFrame))
+ , mxSpacingBar(m_xBuilder->weld_toolbar("spacingbar"))
+ , mxSpacingBarDispatch(new ToolbarUnoDispatcher(*mxSpacingBar, *m_xBuilder, rxFrame))
+{
+ bool isMobilePhone = false;
+ const SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (comphelper::LibreOfficeKit::isActive() &&
+ pViewShell && pViewShell->isLOKMobilePhone())
+ isMobilePhone = true;
+ mxSpacingBar->set_visible(!isMobilePhone);
+}
+
+TextPropertyPanel::~TextPropertyPanel()
+{
+ mxResetBarDispatch.reset();
+ mxDefaultBarDispatch.reset();
+ mxPositionBarDispatch.reset();
+ mxSpacingBarDispatch.reset();
+ mxToolBoxFontColorSwDispatch.reset();
+ mxToolBoxFontColorDispatch.reset();
+ mxToolBoxBackgroundColorDispatch.reset();
+ mxFontAdjustDispatch.reset();
+ mxFontEffectsDispatch.reset();
+ mxFontHeightDispatch.reset();
+ mxFontDispatch.reset();
+
+ mxResetBar.reset();
+ mxDefaultBar.reset();
+ mxPositionBar.reset();
+ mxSpacingBar.reset();
+ mxToolBoxFontColorSw.reset();
+ mxToolBoxFontColor.reset();
+ mxToolBoxBackgroundColor.reset();
+ mxFontAdjust.reset();
+ mxFontEffects.reset();
+ mxFontHeight.reset();
+ mxFont.reset();
+}
+
+void TextPropertyPanel::HandleContextChange (
+ const vcl::EnumContext& rContext)
+{
+ if (maContext == rContext)
+ return;
+
+ maContext = rContext;
+
+ bool bWriterText = false;
+ bool bDrawText = false;
+ bool bCalcText = false;
+
+ switch (maContext.GetCombinedContext_DI())
+ {
+ case CombinedEnumContext(Application::Calc, Context::DrawText):
+ case CombinedEnumContext(Application::WriterVariants, Context::DrawText):
+ case CombinedEnumContext(Application::WriterVariants, Context::Annotation):
+ case CombinedEnumContext(Application::DrawImpress, Context::DrawText):
+ case CombinedEnumContext(Application::DrawImpress, Context::Text):
+ case CombinedEnumContext(Application::DrawImpress, Context::Table):
+ case CombinedEnumContext(Application::DrawImpress, Context::OutlineText):
+ case CombinedEnumContext(Application::DrawImpress, Context::Draw):
+ case CombinedEnumContext(Application::DrawImpress, Context::TextObject):
+ case CombinedEnumContext(Application::DrawImpress, Context::Graphic):
+ bDrawText = true;
+ break;
+
+ case CombinedEnumContext(Application::WriterVariants, Context::Text):
+ case CombinedEnumContext(Application::WriterVariants, Context::Table):
+ bWriterText = true;
+ break;
+
+ case CombinedEnumContext(Application::Calc, Context::Text):
+ case CombinedEnumContext(Application::Calc, Context::Table):
+ case CombinedEnumContext(Application::Calc, Context::Cell):
+ case CombinedEnumContext(Application::Calc, Context::EditCell):
+ case CombinedEnumContext(Application::Calc, Context::Grid):
+ bCalcText = true;
+ break;
+
+ default:
+ break;
+ }
+
+ mxToolBoxFontColor->set_visible(!bWriterText);
+ mxToolBoxFontColorSw->set_visible(bWriterText);
+ mxToolBoxBackgroundColor->set_visible(bDrawText);
+ mxResetBar->set_visible(bWriterText || bCalcText);
+ mxDefaultBar->set_visible(bDrawText);
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/text/TextPropertyPanel.hxx b/svx/source/sidebar/text/TextPropertyPanel.hxx
new file mode 100644
index 000000000..3ad44bde7
--- /dev/null
+++ b/svx/source/sidebar/text/TextPropertyPanel.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_TEXT_TEXTPROPERTYPANEL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_TEXT_TEXTPROPERTYPANEL_HXX
+
+#include <sfx2/sidebar/IContextChangeReceiver.hxx>
+#include <sfx2/weldutils.hxx>
+#include <vcl/EnumContext.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+
+namespace svx::sidebar {
+
+class TextPropertyPanel
+ : public PanelLayout,
+ public ::sfx2::sidebar::IContextChangeReceiver
+{
+public:
+ virtual ~TextPropertyPanel() override;
+
+ static std::unique_ptr<PanelLayout> Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame);
+
+ virtual void HandleContextChange (
+ const vcl::EnumContext& rContext) override;
+
+ TextPropertyPanel (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame);
+
+private:
+ std::unique_ptr<weld::Toolbar> mxFont;
+ std::unique_ptr<ToolbarUnoDispatcher> mxFontDispatch;
+ std::unique_ptr<weld::Toolbar> mxFontHeight;
+ std::unique_ptr<ToolbarUnoDispatcher> mxFontHeightDispatch;
+ std::unique_ptr<weld::Toolbar> mxFontEffects;
+ std::unique_ptr<ToolbarUnoDispatcher> mxFontEffectsDispatch;
+ std::unique_ptr<weld::Toolbar> mxFontAdjust;
+ std::unique_ptr<ToolbarUnoDispatcher> mxFontAdjustDispatch;
+ std::unique_ptr<weld::Toolbar> mxToolBoxFontColorSw;
+ std::unique_ptr<ToolbarUnoDispatcher> mxToolBoxFontColorSwDispatch;
+ std::unique_ptr<weld::Toolbar> mxToolBoxFontColor;
+ std::unique_ptr<ToolbarUnoDispatcher> mxToolBoxFontColorDispatch;
+ std::unique_ptr<weld::Toolbar> mxToolBoxBackgroundColor;
+ std::unique_ptr<ToolbarUnoDispatcher> mxToolBoxBackgroundColorDispatch;
+ std::unique_ptr<weld::Toolbar> mxResetBar;
+ std::unique_ptr<ToolbarUnoDispatcher> mxResetBarDispatch;
+ std::unique_ptr<weld::Toolbar> mxDefaultBar;
+ std::unique_ptr<ToolbarUnoDispatcher> mxDefaultBarDispatch;
+ std::unique_ptr<weld::Toolbar> mxPositionBar;
+ std::unique_ptr<ToolbarUnoDispatcher> mxPositionBarDispatch;
+ std::unique_ptr<weld::Toolbar> mxSpacingBar;
+ std::unique_ptr<ToolbarUnoDispatcher> mxSpacingBarDispatch;
+
+ vcl::EnumContext maContext;
+};
+
+} // end of namespace svx::sidebar
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/text/TextUnderlineControl.cxx b/svx/source/sidebar/text/TextUnderlineControl.cxx
new file mode 100644
index 000000000..ac65b8271
--- /dev/null
+++ b/svx/source/sidebar/text/TextUnderlineControl.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "TextUnderlineControl.hxx"
+#include <svx/svxids.hrc>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <TextUnderlinePopup.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/udlnitem.hxx>
+#include <helpids.h>
+
+namespace svx {
+
+TextUnderlineControl::TextUnderlineControl(TextUnderlinePopup* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/textunderlinecontrol.ui", "TextUnderlineControl")
+ , mxNone(m_xBuilder->weld_button("none"))
+ , mxSingle(m_xBuilder->weld_button("single"))
+ , mxDouble(m_xBuilder->weld_button("double"))
+ , mxBold(m_xBuilder->weld_button("bold"))
+ , mxDot(m_xBuilder->weld_button("dot"))
+ , mxDotBold(m_xBuilder->weld_button("dotbold"))
+ , mxDash(m_xBuilder->weld_button("dash"))
+ , mxDashLong(m_xBuilder->weld_button("dashlong"))
+ , mxDashDot(m_xBuilder->weld_button("dashdot"))
+ , mxDashDotDot(m_xBuilder->weld_button("dashdotdot"))
+ , mxWave(m_xBuilder->weld_button("wave"))
+ , mxMoreOptions(m_xBuilder->weld_button("moreoptions"))
+ , mxControl(pControl)
+{
+ mxMoreOptions->set_help_id(HID_UNDERLINE_BTN);
+
+ Link<weld::Button&,void> aLink = LINK(this, TextUnderlineControl, PBClickHdl);
+ mxNone->connect_clicked(aLink);
+ mxSingle->connect_clicked(aLink);
+ mxDouble->connect_clicked(aLink);
+ mxBold->connect_clicked(aLink);
+ mxDot->connect_clicked(aLink);
+ mxDotBold->connect_clicked(aLink);
+ mxDash->connect_clicked(aLink);
+ mxDashLong->connect_clicked(aLink);
+ mxDashDot->connect_clicked(aLink);
+ mxDashDotDot->connect_clicked(aLink);
+ mxWave->connect_clicked(aLink);
+ mxMoreOptions->connect_clicked(aLink);
+}
+
+void TextUnderlineControl::GrabFocus()
+{
+ mxNone->grab_focus();
+}
+
+TextUnderlineControl::~TextUnderlineControl()
+{
+}
+
+FontLineStyle TextUnderlineControl::getLineStyle(const weld::Button& rButton) const
+{
+ if (&rButton == mxSingle.get())
+ return LINESTYLE_SINGLE;
+ else if (&rButton == mxDouble.get())
+ return LINESTYLE_DOUBLE;
+ else if (&rButton == mxBold.get())
+ return LINESTYLE_BOLD;
+ else if (&rButton == mxDot.get())
+ return LINESTYLE_DOTTED;
+ else if (&rButton == mxDotBold.get())
+ return LINESTYLE_BOLDDOTTED;
+ else if (&rButton == mxDash.get())
+ return LINESTYLE_DASH;
+ else if (&rButton == mxDashLong.get())
+ return LINESTYLE_LONGDASH;
+ else if (&rButton == mxDashDot.get())
+ return LINESTYLE_DASHDOT;
+ else if (&rButton == mxDashDotDot.get())
+ return LINESTYLE_DASHDOTDOT;
+ else if (&rButton == mxWave.get())
+ return LINESTYLE_WAVE;
+
+ return LINESTYLE_NONE;
+}
+
+namespace {
+
+Color GetUnderlineColor()
+{
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ {
+ const SvxUnderlineItem* pUnderlineItem;
+ pViewFrm->GetBindings().GetDispatcher()->QueryState(SID_ATTR_CHAR_UNDERLINE, pUnderlineItem);
+
+ if (pUnderlineItem)
+ return pUnderlineItem->GetColor();
+ }
+
+ return COL_AUTO;
+}
+
+}
+
+IMPL_LINK(TextUnderlineControl, PBClickHdl, weld::Button&, rButton, void)
+{
+ if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
+ {
+ if (&rButton == mxMoreOptions.get())
+ {
+ SfxDispatcher* pDisp = pViewFrm->GetBindings().GetDispatcher();
+ pDisp->Execute(SID_CHAR_DLG_EFFECT, SfxCallMode::ASYNCHRON);
+ }
+ else
+ {
+ const FontLineStyle eUnderline = getLineStyle(rButton);
+
+ SvxUnderlineItem aLineItem(eUnderline, SID_ATTR_CHAR_UNDERLINE);
+ aLineItem.SetColor(GetUnderlineColor());
+
+ pViewFrm->GetBindings().GetDispatcher()->ExecuteList(SID_ATTR_CHAR_UNDERLINE,
+ SfxCallMode::RECORD, { &aLineItem });
+ }
+ }
+ mxControl->EndPopupMode();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/text/TextUnderlineControl.hxx b/svx/source/sidebar/text/TextUnderlineControl.hxx
new file mode 100644
index 000000000..cc1a19c67
--- /dev/null
+++ b/svx/source/sidebar/text/TextUnderlineControl.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_SIDEBAR_TEXT_TEXTUNDERLINECONTROL_HXX
+#define INCLUDED_SVX_SOURCE_SIDEBAR_TEXT_TEXTUNDERLINECONTROL_HXX
+
+#include <svtools/toolbarmenu.hxx>
+
+namespace svx
+{
+class TextUnderlinePopup;
+
+class TextUnderlineControl final : public WeldToolbarPopup
+{
+public:
+ explicit TextUnderlineControl(TextUnderlinePopup* pControl, weld::Widget* pParent);
+ virtual void GrabFocus() override;
+ virtual ~TextUnderlineControl() override;
+
+private:
+ std::unique_ptr<weld::Button> mxNone;
+ std::unique_ptr<weld::Button> mxSingle;
+ std::unique_ptr<weld::Button> mxDouble;
+ std::unique_ptr<weld::Button> mxBold;
+ std::unique_ptr<weld::Button> mxDot;
+ std::unique_ptr<weld::Button> mxDotBold;
+ std::unique_ptr<weld::Button> mxDash;
+ std::unique_ptr<weld::Button> mxDashLong;
+ std::unique_ptr<weld::Button> mxDashDot;
+ std::unique_ptr<weld::Button> mxDashDotDot;
+ std::unique_ptr<weld::Button> mxWave;
+ std::unique_ptr<weld::Button> mxMoreOptions;
+
+ rtl::Reference<TextUnderlinePopup> mxControl;
+
+ FontLineStyle getLineStyle(const weld::Button& rButton) const;
+
+ DECL_LINK(PBClickHdl, weld::Button&, void);
+};
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/text/TextUnderlinePopup.cxx b/svx/source/sidebar/text/TextUnderlinePopup.cxx
new file mode 100644
index 000000000..75529f297
--- /dev/null
+++ b/svx/source/sidebar/text/TextUnderlinePopup.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <TextUnderlinePopup.hxx>
+#include "TextUnderlineControl.hxx"
+#include <vcl/toolbox.hxx>
+
+using namespace svx;
+
+TextUnderlinePopup::TextUnderlinePopup(
+ const css::uno::Reference<css::uno::XComponentContext>& rContext)
+ : PopupWindowController(rContext, nullptr, OUString())
+{
+}
+
+TextUnderlinePopup::~TextUnderlinePopup() {}
+
+void TextUnderlinePopup::initialize(const css::uno::Sequence<css::uno::Any>& rArguments)
+{
+ PopupWindowController::initialize(rArguments);
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox) && pToolBox->GetItemCommand(nId) == m_aCommandURL)
+ pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWN | pToolBox->GetItemBits(nId));
+}
+
+std::unique_ptr<WeldToolbarPopup> TextUnderlinePopup::weldPopupWindow()
+{
+ return std::make_unique<TextUnderlineControl>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> TextUnderlinePopup::createVclPopupWindow(vcl::Window* pParent)
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(
+ getFrameInterface(), pParent,
+ std::make_unique<TextUnderlineControl>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+OUString TextUnderlinePopup::getImplementationName()
+{
+ return "com.sun.star.comp.svx.UnderlineToolBoxControl";
+}
+
+css::uno::Sequence<OUString> TextUnderlinePopup::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_UnderlineToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new TextUnderlinePopup(rContext));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sidebar/textcolumns/TextColumnsPropertyPanel.cxx b/svx/source/sidebar/textcolumns/TextColumnsPropertyPanel.cxx
new file mode 100644
index 000000000..2a06c5705
--- /dev/null
+++ b/svx/source/sidebar/textcolumns/TextColumnsPropertyPanel.cxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include "TextColumnsPropertyPanel.hxx"
+
+#include <sfx2/app.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/itempool.hxx>
+#include <svtools/unitconv.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svxids.hrc>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+namespace
+{
+MapUnit GetUnit(const SfxBindings* pBindings, sal_uInt16 nWhich)
+{
+ assert(pBindings);
+
+ SfxObjectShell* pSh = nullptr;
+ if (auto pShell = pBindings->GetDispatcher()->GetShell(0))
+ pSh = pShell->GetObjectShell();
+ if (!pSh)
+ pSh = SfxObjectShell::Current();
+ SfxItemPool& rPool = pSh ? pSh->GetPool() : SfxGetpApp()->GetPool();
+ return rPool.GetMetric(nWhich);
+}
+}
+
+namespace svx::sidebar
+{
+TextColumnsPropertyPanel::TextColumnsPropertyPanel(weld::Widget* pParent, SfxBindings* pBindings)
+ : PanelLayout(pParent, "TextColumnsPropertyPanel", "svx/ui/sidebartextcolumnspanel.ui")
+ , mpBindings(pBindings)
+ , m_xColumnsNumber(m_xBuilder->weld_spin_button("FLD_COL_NUMBER"))
+ , m_xColumnsSpacing(m_xBuilder->weld_metric_spin_button("MTR_FLD_COL_SPACING", FieldUnit::CM))
+ , maColumnsNumberController(SID_ATTR_TEXTCOLUMNS_NUMBER, *pBindings, *this)
+ , maColumnsSpacingController(SID_ATTR_TEXTCOLUMNS_SPACING, *pBindings, *this)
+{
+ m_xColumnsNumber->connect_value_changed(
+ LINK(this, TextColumnsPropertyPanel, ModifyColumnsNumberHdl));
+ m_xColumnsSpacing->connect_value_changed(
+ LINK(this, TextColumnsPropertyPanel, ModifyColumnsSpacingHdl));
+}
+
+TextColumnsPropertyPanel::~TextColumnsPropertyPanel()
+{
+ maColumnsSpacingController.dispose();
+ maColumnsNumberController.dispose();
+
+ m_xColumnsSpacing.reset();
+ m_xColumnsNumber.reset();
+}
+
+IMPL_LINK_NOARG(TextColumnsPropertyPanel, ModifyColumnsNumberHdl, weld::SpinButton&, void)
+{
+ SfxInt16Item aItem(SDRATTR_TEXTCOLUMNS_NUMBER, m_xColumnsNumber->get_value());
+ mpBindings->GetDispatcher()->ExecuteList(SID_ATTR_TEXTCOLUMNS_NUMBER, SfxCallMode::RECORD,
+ { &aItem });
+}
+
+IMPL_LINK_NOARG(TextColumnsPropertyPanel, ModifyColumnsSpacingHdl, weld::MetricSpinButton&, void)
+{
+ const MapUnit aUnit = GetUnit(mpBindings, SDRATTR_TEXTCOLUMNS_SPACING);
+ SdrMetricItem aItem(SDRATTR_TEXTCOLUMNS_SPACING, GetCoreValue(*m_xColumnsSpacing, aUnit));
+ mpBindings->GetDispatcher()->ExecuteList(SID_ATTR_TEXTCOLUMNS_SPACING, SfxCallMode::RECORD,
+ { &aItem });
+}
+
+void TextColumnsPropertyPanel::NotifyItemUpdate(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ switch (nSID)
+ {
+ case SID_ATTR_TEXTCOLUMNS_NUMBER:
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ if (const auto pItem = dynamic_cast<const SfxInt16Item*>(pState))
+ m_xColumnsNumber->set_value(pItem->GetValue());
+ }
+ break;
+ case SID_ATTR_TEXTCOLUMNS_SPACING:
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ const MapUnit aUnit = GetUnit(mpBindings, SDRATTR_TEXTCOLUMNS_SPACING);
+ if (const auto pItem = dynamic_cast<const SdrMetricItem*>(pState))
+ SetMetricValue(*m_xColumnsSpacing, pItem->GetValue(), aUnit);
+ }
+ break;
+ }
+}
+
+std::unique_ptr<PanelLayout> TextColumnsPropertyPanel::Create(weld::Widget* pParent,
+ SfxBindings* pBindings)
+{
+ if (pParent == nullptr)
+ throw css::lang::IllegalArgumentException(
+ "no parent Window given to TextColumnsPropertyPanel::Create", nullptr, 0);
+ if (pBindings == nullptr)
+ throw css::lang::IllegalArgumentException(
+ "no SfxBindings given to TextColumnsPropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<TextColumnsPropertyPanel>(pParent, pBindings);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/sidebar/textcolumns/TextColumnsPropertyPanel.hxx b/svx/source/sidebar/textcolumns/TextColumnsPropertyPanel.hxx
new file mode 100644
index 000000000..e9c27fcc6
--- /dev/null
+++ b/svx/source/sidebar/textcolumns/TextColumnsPropertyPanel.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+
+class ColorListBox;
+
+namespace svx::sidebar
+{
+class TextColumnsPropertyPanel : public PanelLayout,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+ TextColumnsPropertyPanel(weld::Widget* pParent, SfxBindings* pBindings);
+ virtual ~TextColumnsPropertyPanel() override;
+
+ static std::unique_ptr<PanelLayout> Create(weld::Widget* pParent, SfxBindings* pBindings);
+
+ virtual void NotifyItemUpdate(const sal_uInt16 nSId, const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override{};
+
+private:
+ SfxBindings* mpBindings;
+
+ std::unique_ptr<weld::SpinButton> m_xColumnsNumber;
+ std::unique_ptr<weld::MetricSpinButton> m_xColumnsSpacing;
+
+ sfx2::sidebar::ControllerItem maColumnsNumberController;
+ sfx2::sidebar::ControllerItem maColumnsSpacingController;
+
+ DECL_LINK(ModifyColumnsNumberHdl, weld::SpinButton&, void);
+ DECL_LINK(ModifyColumnsSpacingHdl, weld::MetricSpinButton&, void);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/sidebar/tools/ValueSetWithTextControl.cxx b/svx/source/sidebar/tools/ValueSetWithTextControl.cxx
new file mode 100644
index 000000000..1b6ca2d42
--- /dev/null
+++ b/svx/source/sidebar/tools/ValueSetWithTextControl.cxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <svx/sidebar/ValueSetWithTextControl.hxx>
+#include <sfx2/sidebar/Theme.hxx>
+
+#include <i18nlangtag/mslangid.hxx>
+#include <svtools/valueset.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+namespace svx::sidebar {
+
+ValueSetWithTextControl::ValueSetWithTextControl()
+ : ValueSet(nullptr)
+{
+}
+
+void ValueSetWithTextControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ValueSet::SetDrawingArea(pDrawingArea);
+
+ Size aSize(250, 300);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+
+ SetColCount();
+}
+
+void ValueSetWithTextControl::AddItem(
+ const OUString& rItemText,
+ const OUString& rItemText2 )
+{
+ ValueSetWithTextItem aItem;
+ aItem.maItemText = rItemText;
+ aItem.maItemText2 = rItemText2;
+
+ maItems.push_back( aItem );
+
+ InsertItem( maItems.size() );
+ SetItemText( maItems.size(), rItemText );
+}
+
+void ValueSetWithTextControl::UserDraw( const UserDrawEvent& rUDEvt )
+{
+ const tools::Rectangle aRect = rUDEvt.GetRect();
+ vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
+ pDev->Push();
+ const sal_uInt16 nItemId = rUDEvt.GetItemId();
+
+ const tools::Long nRectHeight = aRect.GetHeight();
+
+ vcl::Font aFont(OutputDevice::GetDefaultFont(DefaultFontType::UI_SANS, MsLangId::getConfiguredSystemLanguage(), GetDefaultFontFlags::OnlyOne));
+ {
+ Size aSize = aFont.GetFontSize();
+ aSize.setHeight( (nRectHeight*4)/9 );
+ aFont.SetFontSize( aSize );
+ }
+
+ {
+ //draw background
+ if ( GetSelectedItemId() == nItemId )
+ {
+ tools::Rectangle aBackRect = aRect;
+ aBackRect.AdjustTop(3 );
+ aBackRect.AdjustBottom( -2 );
+ pDev->SetFillColor( sfx2::sidebar::Theme::GetColor( sfx2::sidebar::Theme::Color_Highlight ) );
+ pDev->DrawRect(aBackRect);
+ }
+ else
+ {
+ pDev->SetFillColor( COL_TRANSPARENT );
+ pDev->DrawRect(aRect);
+ }
+
+ if ( GetSelectedItemId() == nItemId )
+ {
+ aFont.SetColor( sfx2::sidebar::Theme::GetColor( sfx2::sidebar::Theme::Color_HighlightText ) );
+ }
+ else
+ {
+ aFont.SetColor( Application::GetSettings().GetStyleSettings().GetFieldTextColor() );
+ }
+
+ tools::Rectangle aStrRect = aRect;
+ aStrRect.AdjustTop(nRectHeight/4 );
+ aStrRect.AdjustBottom( -(nRectHeight/4) );
+
+ const tools::Long nRectWidth = aRect.GetWidth();
+ aStrRect.AdjustLeft(8 );
+ aStrRect.AdjustRight( -((nRectWidth*2)/3) );
+ pDev->SetFont(aFont);
+ pDev->DrawText(aStrRect, maItems[nItemId-1].maItemText, DrawTextFlags::EndEllipsis);
+ aStrRect.AdjustLeft(nRectWidth/3 );
+ aStrRect.AdjustRight((nRectWidth*2)/3 );
+ pDev->DrawText(aStrRect, maItems[nItemId-1].maItemText2, DrawTextFlags::EndEllipsis);
+ }
+
+ Invalidate( aRect );
+ pDev->Pop();
+}
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/smarttags/SmartTagMgr.cxx b/svx/source/smarttags/SmartTagMgr.cxx
new file mode 100644
index 000000000..875d4557d
--- /dev/null
+++ b/svx/source/smarttags/SmartTagMgr.cxx
@@ -0,0 +1,527 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// SMARTTAGS
+
+#include <svx/SmartTagMgr.hxx>
+
+#include <vcl/svapp.hxx>
+#include <com/sun/star/smarttags/XSmartTagRecognizer.hpp>
+#include <com/sun/star/smarttags/XRangeBasedSmartTagRecognizer.hpp>
+#include <com/sun/star/smarttags/XSmartTagAction.hpp>
+#include <com/sun/star/deployment/ExtensionManager.hpp>
+#include <com/sun/star/smarttags/SmartTagRecognizerMode.hpp>
+#include <com/sun/star/i18n/BreakIterator.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/util/XChangesBatch.hpp>
+#include <com/sun/star/util/XChangesNotifier.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <rtl/ustring.hxx>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::i18n;
+
+
+SmartTagMgr::SmartTagMgr( const OUString& rApplicationName )
+ : maApplicationName( rApplicationName ),
+ mxContext( ::comphelper::getProcessComponentContext() ),
+ mbLabelTextWithSmartTags(true)
+{
+}
+
+SmartTagMgr::~SmartTagMgr()
+{
+}
+
+void SmartTagMgr::Init( std::u16string_view rConfigurationGroupName )
+{
+ PrepareConfiguration( rConfigurationGroupName );
+ ReadConfiguration( true, true );
+ RegisterListener();
+ LoadLibraries();
+}
+
+/** Dispatches the recognize call to all installed smart tag recognizers
+*/
+void SmartTagMgr::RecognizeString( const OUString& rText,
+ const Reference< text::XTextMarkup >& xMarkup,
+ const Reference< frame::XController >& xController,
+ const lang::Locale& rLocale,
+ sal_uInt32 nStart, sal_uInt32 nLen ) const
+{
+ for (const Reference < smarttags::XSmartTagRecognizer >& xRecognizer : maRecognizerList)
+ {
+ // if all smart tag types supported by this recognizer have been
+ // disabled, we do not have to call the recognizer:
+ bool bCallRecognizer = false;
+ const sal_uInt32 nSmartTagCount = xRecognizer->getSmartTagCount();
+ for ( sal_uInt32 j = 0; j < nSmartTagCount && !bCallRecognizer; ++j )
+ {
+ const OUString aSmartTagName = xRecognizer->getSmartTagName(j);
+ if ( IsSmartTagTypeEnabled( aSmartTagName ) )
+ bCallRecognizer = true;
+ }
+
+ if ( bCallRecognizer )
+ {
+ // get the break iterator
+ if ( !mxBreakIter.is() )
+ {
+ mxBreakIter.set( BreakIterator::create(mxContext) );
+ }
+ xRecognizer->recognize( rText, nStart, nLen,
+ smarttags::SmartTagRecognizerMode_PARAGRAPH,
+ rLocale, xMarkup, maApplicationName, xController,
+ mxBreakIter );
+ }
+ }
+}
+
+void SmartTagMgr::RecognizeTextRange(const Reference< text::XTextRange>& xRange,
+ const Reference< text::XTextMarkup >& xMarkup,
+ const Reference< frame::XController >& xController) const
+{
+ for (const Reference<smarttags::XSmartTagRecognizer>& xRecognizer : maRecognizerList)
+ {
+ Reference< smarttags::XRangeBasedSmartTagRecognizer > xRangeBasedRecognizer( xRecognizer, UNO_QUERY);
+
+ if (!xRangeBasedRecognizer.is()) continue;
+
+ // if all smart tag types supported by this recognizer have been
+ // disabled, we do not have to call the recognizer:
+ bool bCallRecognizer = false;
+ const sal_uInt32 nSmartTagCount = xRecognizer->getSmartTagCount();
+ for ( sal_uInt32 j = 0; j < nSmartTagCount && !bCallRecognizer; ++j )
+ {
+ const OUString aSmartTagName = xRecognizer->getSmartTagName(j);
+ if ( IsSmartTagTypeEnabled( aSmartTagName ) )
+ bCallRecognizer = true;
+ }
+
+ if ( bCallRecognizer )
+ {
+ xRangeBasedRecognizer->recognizeTextRange( xRange,
+ smarttags::SmartTagRecognizerMode_PARAGRAPH,
+ xMarkup, maApplicationName, xController);
+ }
+ }
+
+}
+
+void SmartTagMgr::GetActionSequences( std::vector< OUString >& rSmartTagTypes,
+ Sequence < Sequence< Reference< smarttags::XSmartTagAction > > >& rActionComponentsSequence,
+ Sequence < Sequence< sal_Int32 > >& rActionIndicesSequence ) const
+{
+ rActionComponentsSequence.realloc( rSmartTagTypes.size() );
+ auto pActionComponentsSequence = rActionComponentsSequence.getArray();
+ rActionIndicesSequence.realloc( rSmartTagTypes.size() );
+ auto pActionIndicesSequence = rActionIndicesSequence.getArray();
+
+ for ( size_t j = 0; j < rSmartTagTypes.size(); ++j )
+ {
+ const OUString& rSmartTagType = rSmartTagTypes[j];
+
+ const sal_Int32 nNumberOfActionRefs = maSmartTagMap.count( rSmartTagType );
+
+ Sequence< Reference< smarttags::XSmartTagAction > > aActions( nNumberOfActionRefs );
+ auto aActionsRange = asNonConstRange(aActions);
+ Sequence< sal_Int32 > aIndices( nNumberOfActionRefs );
+ auto aIndicesRange = asNonConstRange(aIndices);
+
+ sal_uInt16 i = 0;
+ auto iters = maSmartTagMap.equal_range( rSmartTagType );
+
+ for ( auto aActionsIter = iters.first; aActionsIter != iters.second; ++aActionsIter )
+ {
+ aActionsRange[ i ] = (*aActionsIter).second.mxSmartTagAction;
+ aIndicesRange[ i++ ] = (*aActionsIter).second.mnSmartTagIndex;
+ }
+
+ pActionComponentsSequence[ j ] = aActions;
+ pActionIndicesSequence[ j ] = aIndices;
+ }
+}
+
+/** Returns the caption for a smart tag type.
+*/
+OUString SmartTagMgr::GetSmartTagCaption( const OUString& rSmartTagType, const css::lang::Locale& rLocale ) const
+{
+ OUString aRet;
+
+ auto aLower = maSmartTagMap.find( rSmartTagType );
+
+ if ( aLower != maSmartTagMap.end() )
+ {
+ const ActionReference& rActionRef = (*aLower).second;
+ Reference< smarttags::XSmartTagAction > xAction = rActionRef.mxSmartTagAction;
+
+ if ( xAction.is() )
+ {
+ const sal_Int32 nSmartTagIndex = rActionRef.mnSmartTagIndex;
+ aRet = xAction->getSmartTagCaption( nSmartTagIndex, rLocale );
+ }
+ }
+
+ return aRet;
+}
+
+
+/** Returns true if the given smart tag type is enabled.
+*/
+bool SmartTagMgr::IsSmartTagTypeEnabled( const OUString& rSmartTagType ) const
+{
+ return maDisabledSmartTagTypes.end() == maDisabledSmartTagTypes.find( rSmartTagType );
+}
+
+/** Writes currently disabled smart tag types to configuration.
+*/
+void SmartTagMgr::WriteConfiguration( const bool* pIsLabelTextWithSmartTags,
+ const std::vector< OUString >* pDisabledTypes ) const
+{
+ if ( !mxConfigurationSettings.is() )
+ return;
+
+ bool bCommit = false;
+
+ if ( pIsLabelTextWithSmartTags )
+ {
+ const Any aEnabled( *pIsLabelTextWithSmartTags );
+
+ try
+ {
+ mxConfigurationSettings->setPropertyValue( "RecognizeSmartTags", aEnabled );
+ bCommit = true;
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+ }
+
+ if ( pDisabledTypes )
+ {
+ Sequence< OUString > aTypes = comphelper::containerToSequence(*pDisabledTypes);
+
+ const Any aNewTypes( aTypes );
+
+ try
+ {
+ mxConfigurationSettings->setPropertyValue( "ExcludedSmartTagTypes", aNewTypes );
+ bCommit = true;
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+ }
+
+ if ( bCommit )
+ {
+ try
+ {
+ Reference< util::XChangesBatch >( mxConfigurationSettings, UNO_QUERY_THROW )->commitChanges();
+ }
+ catch ( css::uno::Exception& )
+ {
+ }
+ }
+}
+
+// css::util::XModifyListener
+void SmartTagMgr::modified( const lang::EventObject& )
+{
+ SolarMutexGuard aGuard;
+
+ maRecognizerList.clear();
+ maActionList.clear();
+ maSmartTagMap.clear();
+
+ LoadLibraries();
+}
+
+// css::lang::XEventListener
+void SmartTagMgr::disposing( const lang::EventObject& rEvent )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY );
+ uno::Reference< util::XModifyBroadcaster > xMB(xModel, uno::UNO_QUERY);
+ uno::Reference< util::XChangesNotifier > xCN(xModel, uno::UNO_QUERY);
+
+ try
+ {
+ if( xMB.is() )
+ {
+ uno::Reference< util::XModifyListener > xListener( this );
+ xMB->removeModifyListener( xListener );
+ }
+ else if ( xCN.is() )
+ {
+ uno::Reference< util::XChangesListener > xListener( this );
+ xCN->removeChangesListener( xListener );
+ }
+ }
+ catch(Exception& )
+ {
+ }
+}
+
+// css::util::XChangesListener
+void SmartTagMgr::changesOccurred( const util::ChangesEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+
+ bool bExcludedTypes = false;
+ bool bRecognize = false;
+
+ for( const util::ElementChange& rElementChange : rEvent.Changes)
+ {
+ OUString sTemp;
+ rElementChange.Accessor >>= sTemp;
+
+ if ( sTemp == "ExcludedSmartTagTypes" )
+ bExcludedTypes = true;
+ else if ( sTemp == "RecognizeSmartTags" )
+ bRecognize = true;
+ }
+
+ ReadConfiguration( bExcludedTypes, bRecognize );
+}
+
+void SmartTagMgr::LoadLibraries()
+{
+ Reference< container::XContentEnumerationAccess > rContent( mxContext->getServiceManager(), UNO_QUERY_THROW );
+
+ // load recognizers: No recognizers -> nothing to do.
+ Reference < container::XEnumeration > rEnum = rContent->createContentEnumeration( "com.sun.star.smarttags.SmartTagRecognizer");
+ if ( !rEnum.is() || !rEnum->hasMoreElements() )
+ return;
+
+ // iterate over all implementations of the smart tag recognizer service:
+ while( rEnum->hasMoreElements())
+ {
+ const Any a = rEnum->nextElement();
+ Reference< lang::XSingleComponentFactory > xSCF;
+ Reference< lang::XServiceInfo > xsInfo;
+
+ if (a >>= xsInfo)
+ xSCF.set(xsInfo, UNO_QUERY);
+ else
+ continue;
+
+ Reference< smarttags::XSmartTagRecognizer > xLib ( xSCF->
+ createInstanceWithContext(mxContext), UNO_QUERY );
+
+ if (!xLib.is())
+ continue;
+
+ xLib->initialize( Sequence< Any >() );
+ maRecognizerList.push_back(xLib);
+ }
+
+ // load actions: No actions -> nothing to do.
+ rEnum = rContent->createContentEnumeration( "com.sun.star.smarttags.SmartTagAction");
+ if ( !rEnum.is() )
+ return;
+
+ // iterate over all implementations of the smart tag action service:
+ while( rEnum->hasMoreElements())
+ {
+ const Any a = rEnum->nextElement();
+ Reference< lang::XServiceInfo > xsInfo;
+ Reference< lang::XSingleComponentFactory > xSCF;
+
+ if (a >>= xsInfo)
+ xSCF.set(xsInfo, UNO_QUERY);
+ else
+ continue;
+
+ Reference< smarttags::XSmartTagAction > xLib ( xSCF->
+ createInstanceWithContext(mxContext), UNO_QUERY );
+
+ if (!xLib.is())
+ continue;
+
+ xLib->initialize( Sequence< Any >() );
+ maActionList.push_back(xLib);
+ }
+
+ AssociateActionsWithRecognizers();
+
+}
+
+void SmartTagMgr::PrepareConfiguration( std::u16string_view rConfigurationGroupName )
+{
+ Any aAny(
+ OUString::Concat("/org.openoffice.Office.Common/SmartTags/") + rConfigurationGroupName );
+ beans::PropertyValue aPathArgument;
+ aPathArgument.Name = "nodepath";
+ aPathArgument.Value = aAny;
+ Sequence< Any > aArguments{ Any(aPathArgument) };
+ Reference< lang::XMultiServiceFactory > xConfProv = configuration::theDefaultProvider::get( mxContext );
+
+ // try to get read-write access to configuration:
+ Reference< XInterface > xConfigurationAccess;
+ try
+ {
+ xConfigurationAccess = xConfProv->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationUpdateAccess", aArguments );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+
+ // fallback: try read-only access to configuration:
+ if ( !xConfigurationAccess.is() )
+ {
+ try
+ {
+ xConfigurationAccess = xConfProv->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess", aArguments );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+
+ if ( xConfigurationAccess.is() )
+ {
+ mxConfigurationSettings.set( xConfigurationAccess, UNO_QUERY );
+ }
+}
+
+
+void SmartTagMgr::ReadConfiguration( bool bExcludedTypes, bool bRecognize )
+{
+ if ( !mxConfigurationSettings.is() )
+ return;
+
+ if ( bExcludedTypes )
+ {
+ maDisabledSmartTagTypes.clear();
+
+ Any aAny = mxConfigurationSettings->getPropertyValue( "ExcludedSmartTagTypes" );
+ Sequence< OUString > aValues;
+ aAny >>= aValues;
+
+ for ( const auto& rValue : std::as_const(aValues) )
+ maDisabledSmartTagTypes.insert( rValue );
+ }
+
+ if ( bRecognize )
+ {
+ Any aAny = mxConfigurationSettings->getPropertyValue( "RecognizeSmartTags" );
+ bool bValue = true;
+ aAny >>= bValue;
+
+ mbLabelTextWithSmartTags = bValue;
+ }
+}
+
+void SmartTagMgr::RegisterListener()
+{
+ // register as listener at package manager
+ try
+ {
+ Reference<deployment::XExtensionManager> xExtensionManager(
+ deployment::ExtensionManager::get( mxContext ) );
+ Reference< util::XModifyBroadcaster > xMB ( xExtensionManager, UNO_QUERY_THROW );
+
+ Reference< util::XModifyListener > xListener( this );
+ xMB->addModifyListener( xListener );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+
+ // register as listener at configuration
+ try
+ {
+ Reference<util::XChangesNotifier> xCN( mxConfigurationSettings, UNO_QUERY_THROW );
+ Reference< util::XChangesListener > xListener( this );
+ xCN->addChangesListener( xListener );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+}
+
+typedef std::pair < const OUString, ActionReference > SmartTagMapElement;
+
+/** Sets up a map that maps smart tag type names to actions references.
+*/
+void SmartTagMgr::AssociateActionsWithRecognizers()
+{
+ const sal_uInt32 nActionLibCount = maActionList.size();
+ const sal_uInt32 nRecognizerCount = maRecognizerList.size();
+
+ for ( sal_uInt32 i = 0; i < nRecognizerCount; ++i )
+ {
+ Reference < smarttags::XSmartTagRecognizer > xRecognizer = maRecognizerList[i];
+ const sal_uInt32 nSmartTagCount = xRecognizer->getSmartTagCount();
+ for ( sal_uInt32 j = 0; j < nSmartTagCount; ++j )
+ {
+ const OUString aSmartTagName = xRecognizer->getSmartTagName(j);
+
+ // check if smart tag type has already been processed:
+ if ( maSmartTagMap.find( aSmartTagName ) != maSmartTagMap.end() )
+ continue;
+
+ bool bFound = false;
+ for ( sal_uInt32 k = 0; k < nActionLibCount; ++k )
+ {
+ Reference< smarttags::XSmartTagAction > xActionLib = maActionList[k];
+ const sal_uInt32 nSmartTagCountInActionLib = xActionLib->getSmartTagCount();
+ for ( sal_uInt32 l = 0; l < nSmartTagCountInActionLib; ++l )
+ {
+ const OUString aSmartTagNameInActionLib = xActionLib->getSmartTagName(l);
+ if ( aSmartTagName == aSmartTagNameInActionLib )
+ {
+ // found actions and recognizer for same smarttag
+ ActionReference aActionRef( xActionLib, l );
+
+ // add recognizer/action pair to map
+ maSmartTagMap.insert( SmartTagMapElement( aSmartTagName, aActionRef ));
+
+ bFound = true;
+ }
+ }
+ }
+
+ if ( !bFound )
+ {
+ // insert 'empty' action reference if there is no action associated with
+ // the current smart tag type:
+ Reference< smarttags::XSmartTagAction > xActionLib;
+ ActionReference aActionRef( xActionLib, 0 );
+
+ // add recognizer/action pair to map
+ maSmartTagMap.insert( SmartTagMapElement( aSmartTagName, aActionRef ));
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/stbctrls/insctrl.cxx b/svx/source/stbctrls/insctrl.cxx
new file mode 100644
index 000000000..3ad0fdc1e
--- /dev/null
+++ b/svx/source/stbctrls/insctrl.cxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/status.hxx>
+#include <svl/eitem.hxx>
+#include <tools/debug.hxx>
+
+#include <svx/strings.hrc>
+
+#include <svx/insctrl.hxx>
+#include <svx/dialmgr.hxx>
+
+SFX_IMPL_STATUSBAR_CONTROL(SvxInsertStatusBarControl, SfxBoolItem);
+
+SvxInsertStatusBarControl::SvxInsertStatusBarControl( sal_uInt16 _nSlotId,
+ sal_uInt16 _nId,
+ StatusBar& rStb ) :
+
+ SfxStatusBarControl( _nSlotId, _nId, rStb ),
+ bInsert( true )
+{
+}
+
+SvxInsertStatusBarControl::~SvxInsertStatusBarControl()
+{
+}
+
+void SvxInsertStatusBarControl::StateChangedAtStatusBarControl( sal_uInt16 , SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ if ( SfxItemState::DEFAULT != eState )
+ GetStatusBar().SetItemText( GetId(), "" );
+ else
+ {
+ DBG_ASSERT( dynamic_cast<const SfxBoolItem*>( pState) != nullptr, "invalid item type" );
+ const SfxBoolItem* pItem = static_cast<const SfxBoolItem*>(pState);
+ bInsert = pItem->GetValue();
+
+ if ( bInsert )
+ GetStatusBar().SetQuickHelpText( GetId(), SvxResId( RID_SVXSTR_INSERT_HELPTEXT ) );
+ else
+ GetStatusBar().SetQuickHelpText( GetId(), SvxResId( RID_SVXSTR_OVERWRITE_HELPTEXT ) );
+
+ DrawItemText_Impl();
+ }
+}
+
+void SvxInsertStatusBarControl::Paint( const UserDrawEvent& )
+{
+}
+
+void SvxInsertStatusBarControl::DrawItemText_Impl()
+{
+ OUString aText = "";
+ // tdf#107918 on macOS without an Insert key it's hard to figure out how to switch modes
+ // so we show both Insert and Overwrite
+#ifdef MACOSX
+ if ( bInsert )
+ aText = SvxResId( RID_SVXSTR_INSERT_TEXT );
+#endif
+ if ( !bInsert )
+ aText = SvxResId( RID_SVXSTR_OVERWRITE_TEXT );
+
+ GetStatusBar().SetItemText( GetId(), aText );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/stbctrls/modctrl.cxx b/svx/source/stbctrls/modctrl.cxx
new file mode 100644
index 000000000..d65817526
--- /dev/null
+++ b/svx/source/stbctrls/modctrl.cxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/status.hxx>
+#include <vcl/image.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/event.hxx>
+#include <svl/eitem.hxx>
+#include <tools/debug.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/modctrl.hxx>
+#include <svx/dialmgr.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include "modctrl_internal.hxx"
+#include <bitmaps.hlst>
+
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::beans::PropertyValue;
+
+SFX_IMPL_STATUSBAR_CONTROL(SvxModifyControl, SfxBoolItem);
+
+struct SvxModifyControl::ImplData
+{
+ enum ModificationState
+ {
+ MODIFICATION_STATE_NO = 0,
+ MODIFICATION_STATE_YES,
+ MODIFICATION_STATE_FEEDBACK,
+ MODIFICATION_STATE_SIZE
+ };
+
+ Idle maIdle { "svx::SvxModifyControl maIdle" };
+ Image maImages[MODIFICATION_STATE_SIZE];
+
+ ModificationState mnModState;
+
+ ImplData():
+ mnModState(MODIFICATION_STATE_NO)
+ {
+ maImages[MODIFICATION_STATE_NO] = Image(StockImage::Yes, RID_SVXBMP_DOC_MODIFIED_NO);
+ maImages[MODIFICATION_STATE_YES] = Image(StockImage::Yes, RID_SVXBMP_DOC_MODIFIED_YES);
+ maImages[MODIFICATION_STATE_FEEDBACK] = Image(StockImage::Yes, RID_SVXBMP_DOC_MODIFIED_FEEDBACK);
+
+ maIdle.SetPriority(TaskPriority::LOWEST);
+ }
+};
+
+SvxModifyControl::SvxModifyControl( sal_uInt16 _nSlotId, sal_uInt16 _nId, StatusBar& rStb ) :
+ SfxStatusBarControl( _nSlotId, _nId, rStb ),
+ mxImpl(std::make_shared<ImplData>())
+{
+ mxImpl->maIdle.SetInvokeHandler( LINK(this, SvxModifyControl, OnTimer) );
+}
+
+
+void SvxModifyControl::StateChangedAtStatusBarControl( sal_uInt16, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ if ( SfxItemState::DEFAULT != eState )
+ return;
+
+ DBG_ASSERT( dynamic_cast<const SfxBoolItem*>( pState) != nullptr, "invalid item type" );
+ const SfxBoolItem* pItem = static_cast<const SfxBoolItem*>(pState);
+ mxImpl->maIdle.Stop();
+
+ bool modified = pItem->GetValue();
+ bool start = ( !modified && mxImpl->mnModState == ImplData::MODIFICATION_STATE_YES); // should timer be started and feedback image displayed ?
+
+ mxImpl->mnModState = (start ? ImplData::MODIFICATION_STATE_FEEDBACK : (modified ? ImplData::MODIFICATION_STATE_YES : ImplData::MODIFICATION_STATE_NO));
+
+ _repaint();
+
+ TranslateId pResId = modified ? RID_SVXSTR_DOC_MODIFIED_YES : RID_SVXSTR_DOC_MODIFIED_NO;
+ GetStatusBar().SetQuickHelpText(GetId(), SvxResId(pResId));
+
+ if ( start )
+ mxImpl->maIdle.Start();
+}
+
+
+IMPL_LINK( SvxModifyControl, OnTimer, Timer *, pTimer, void )
+{
+ if (pTimer == nullptr)
+ return;
+
+ pTimer->Stop();
+ mxImpl->mnModState = ImplData::MODIFICATION_STATE_NO;
+
+ _repaint();
+}
+
+
+void SvxModifyControl::_repaint()
+{
+ GetStatusBar().SetItemData( GetId(), nullptr ); // force repaint
+}
+
+/**
+ * Given a bounding rectangle and an image, determine the top-left position
+ * of the image so that the image would look centered both horizontally and
+ * vertically.
+ *
+ * @param rBoundingRect bounding rectangle
+ * @param rImg image
+ *
+ * @return Point top-left corner of the centered image position
+ */
+Point centerImage(const tools::Rectangle& rBoundingRect, const Image& rImg)
+{
+ Size aImgSize = rImg.GetSizePixel();
+ Size aRectSize = rBoundingRect.GetSize();
+ tools::Long nXOffset = (aRectSize.getWidth() - aImgSize.getWidth())/2;
+ tools::Long nYOffset = (aRectSize.getHeight() - aImgSize.getHeight())/2;
+ Point aPt = rBoundingRect.TopLeft();
+ aPt += Point(nXOffset, nYOffset);
+ return aPt;
+}
+
+void SvxModifyControl::Paint( const UserDrawEvent& rUsrEvt )
+{
+ vcl::RenderContext* pDev = rUsrEvt.GetRenderContext();
+ tools::Rectangle aRect(rUsrEvt.GetRect());
+
+ ImplData::ModificationState state = mxImpl->mnModState;
+ Point aPt = centerImage(aRect, mxImpl->maImages[state]);
+ pDev->DrawImage(aPt, mxImpl->maImages[state]);
+}
+
+void SvxModifyControl::Click()
+{
+ if (mxImpl->mnModState != ImplData::MODIFICATION_STATE_YES)
+ // document not modified. nothing to do here.
+ return;
+
+ Sequence<PropertyValue> aArgs;
+ execute(".uno:Save", aArgs);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/stbctrls/modctrl_internal.hxx b/svx/source/stbctrls/modctrl_internal.hxx
new file mode 100644
index 000000000..d6d3d6834
--- /dev/null
+++ b/svx/source/stbctrls/modctrl_internal.hxx
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_STBCTRLS_MODCTRL_INTERNAL_HXX
+#define INCLUDED_SVX_SOURCE_STBCTRLS_MODCTRL_INTERNAL_HXX
+
+#include <tools/gen.hxx>
+
+class Image;
+
+Point centerImage(const tools::Rectangle& rBoundingRect, const Image& rImg);
+
+#endif // INCLUDED_SVX_SOURCE_STBCTRLS_MODCTRL_INTERNAL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/stbctrls/pszctrl.cxx b/svx/source/stbctrls/pszctrl.cxx
new file mode 100644
index 000000000..129ac67eb
--- /dev/null
+++ b/svx/source/stbctrls/pszctrl.cxx
@@ -0,0 +1,486 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/fieldvalues.hxx>
+#include <vcl/status.hxx>
+#include <vcl/image.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+#include <svl/stritem.hxx>
+#include <svl/ptitem.hxx>
+#include <sfx2/module.hxx>
+#include <svl/intitem.hxx>
+#include <sal/log.hxx>
+
+#include <svx/pszctrl.hxx>
+
+#define PAINT_OFFSET 5
+
+#include <editeng/sizeitem.hxx>
+#include "stbctrls.h"
+
+#include <svx/svxids.hrc>
+#include <bitmaps.hlst>
+#include <unotools/localedatawrapper.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+/* [Description]
+
+ Function used to create a text representation of
+ a metric value
+
+ nVal is the metric value in the unit eUnit.
+
+ [cross reference]
+
+ <SvxPosSizeStatusBarControl::Paint(const UserDrawEvent&)>
+*/
+
+OUString SvxPosSizeStatusBarControl::GetMetricStr_Impl( tools::Long nVal ) const
+{
+ // deliver and set the Metric of the application
+ FieldUnit eOutUnit = SfxModule::GetModuleFieldUnit( getFrameInterface() );
+
+ OUString sMetric;
+ const sal_Unicode cSep = Application::GetSettings().GetLocaleDataWrapper().getNumDecimalSep()[0];
+ sal_Int64 nConvVal = vcl::ConvertValue( nVal * 100, 0, 0, FieldUnit::MM_100TH, eOutUnit );
+
+ if ( nConvVal < 0 && ( nConvVal / 100 == 0 ) )
+ sMetric += "-";
+ sMetric += OUString::number(nConvVal / 100);
+
+ if( FieldUnit::NONE != eOutUnit )
+ {
+ sMetric += OUStringChar(cSep);
+ sal_Int64 nFract = nConvVal % 100;
+
+ if ( nFract < 0 )
+ nFract *= -1;
+ if ( nFract < 10 )
+ sMetric += "0";
+ sMetric += OUString::number(nFract);
+ }
+
+ return sMetric;
+}
+
+
+SFX_IMPL_STATUSBAR_CONTROL(SvxPosSizeStatusBarControl, SvxSizeItem);
+
+namespace {
+
+class FunctionPopup_Impl
+{
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Menu> m_xMenu;
+ sal_uInt32 m_nSelected;
+ static sal_uInt16 id_to_function(std::string_view rIdent);
+ static OString function_to_id(sal_uInt16 nFunc);
+public:
+ explicit FunctionPopup_Impl(sal_uInt32 nCheckEncoded);
+ OString Execute(weld::Window* pParent, const tools::Rectangle& rRect)
+ {
+ return m_xMenu->popup_at_rect(pParent, rRect);
+ }
+ sal_uInt32 GetSelected(std::string_view curident) const;
+};
+
+}
+
+sal_uInt16 FunctionPopup_Impl::id_to_function(std::string_view rIdent)
+{
+ if (rIdent == "avg")
+ return PSZ_FUNC_AVG;
+ else if (rIdent == "counta")
+ return PSZ_FUNC_COUNT2;
+ else if (rIdent == "count")
+ return PSZ_FUNC_COUNT;
+ else if (rIdent == "max")
+ return PSZ_FUNC_MAX;
+ else if (rIdent == "min")
+ return PSZ_FUNC_MIN;
+ else if (rIdent == "sum")
+ return PSZ_FUNC_SUM;
+ else if (rIdent == "selection")
+ return PSZ_FUNC_SELECTION_COUNT;
+ else if (rIdent == "none")
+ return PSZ_FUNC_NONE;
+ return 0;
+}
+
+OString FunctionPopup_Impl::function_to_id(sal_uInt16 nFunc)
+{
+ switch (nFunc)
+ {
+ case PSZ_FUNC_AVG:
+ return "avg";
+ case PSZ_FUNC_COUNT2:
+ return "counta";
+ case PSZ_FUNC_COUNT:
+ return "count";
+ case PSZ_FUNC_MAX:
+ return "max";
+ case PSZ_FUNC_MIN:
+ return "min";
+ case PSZ_FUNC_SUM:
+ return "sum";
+ case PSZ_FUNC_SELECTION_COUNT:
+ return "selection";
+ case PSZ_FUNC_NONE:
+ return "none";
+ }
+ return OString();
+}
+
+FunctionPopup_Impl::FunctionPopup_Impl(sal_uInt32 nCheckEncoded)
+ : m_xBuilder(Application::CreateBuilder(nullptr, "svx/ui/functionmenu.ui"))
+ , m_xMenu(m_xBuilder->weld_menu("menu"))
+ , m_nSelected(nCheckEncoded)
+{
+ for ( sal_uInt16 nCheck = 1; nCheck < 32; ++nCheck )
+ if ( nCheckEncoded & (1u << nCheck) )
+ m_xMenu->set_active(function_to_id(nCheck), true);
+}
+
+sal_uInt32 FunctionPopup_Impl::GetSelected(std::string_view curident) const
+{
+ sal_uInt32 nSelected = m_nSelected;
+ sal_uInt16 nCurItemId = id_to_function(curident);
+ if ( nCurItemId == PSZ_FUNC_NONE )
+ nSelected = ( 1 << PSZ_FUNC_NONE );
+ else
+ {
+ nSelected &= (~( 1u << PSZ_FUNC_NONE )); // Clear the "None" bit
+ nSelected ^= ( 1u << nCurItemId ); // Toggle the bit corresponding to nCurItemId
+ if ( !nSelected )
+ nSelected = ( 1u << PSZ_FUNC_NONE );
+ }
+ return nSelected;
+}
+
+struct SvxPosSizeStatusBarControl_Impl
+
+/* [Description]
+
+ This implementation-structure of the class SvxPosSizeStatusBarControl
+ is done for the un-linking of the changes of the exported interface such as
+ the toning down of symbols that are visible externally.
+
+ One instance exists for each SvxPosSizeStatusBarControl-instance
+ during its life time
+*/
+
+{
+ Point aPos; // valid when a position is shown
+ Size aSize; // valid when a size is shown
+ OUString aStr; // valid when a text is shown
+ bool bPos; // show position ?
+ bool bSize; // set size ?
+ bool bTable; // set table index ?
+ bool bHasMenu; // set StarCalc popup menu ?
+ sal_uInt32 nFunctionSet; // the selected StarCalc functions encoded in 32 bits
+ Image aPosImage; // Image to show the position
+ Image aSizeImage; // Image to show the size
+};
+
+/* [Description]
+
+ Ctor():
+ Create an instance of the implementation class,
+ load the images for the position and size
+*/
+
+#define STR_POSITION ".uno:Position"
+#define STR_TABLECELL ".uno:StateTableCell"
+#define STR_FUNC ".uno:StatusBarFunc"
+
+SvxPosSizeStatusBarControl::SvxPosSizeStatusBarControl( sal_uInt16 _nSlotId,
+ sal_uInt16 _nId,
+ StatusBar& rStb ) :
+ SfxStatusBarControl( _nSlotId, _nId, rStb ),
+ pImpl( new SvxPosSizeStatusBarControl_Impl )
+{
+ pImpl->bPos = false;
+ pImpl->bSize = false;
+ pImpl->bTable = false;
+ pImpl->bHasMenu = false;
+ pImpl->nFunctionSet = 0;
+ pImpl->aPosImage = Image(StockImage::Yes, RID_SVXBMP_POSITION);
+ pImpl->aSizeImage = Image(StockImage::Yes, RID_SVXBMP_SIZE);
+
+ addStatusListener( STR_POSITION); // SID_ATTR_POSITION
+ addStatusListener( STR_TABLECELL); // SID_TABLE_CELL
+ addStatusListener( STR_FUNC); // SID_PSZ_FUNCTION
+ ImplUpdateItemText();
+}
+
+/* [Description]
+
+ Dtor():
+ remove the pointer to the implementation class, so that the timer is stopped
+
+*/
+
+SvxPosSizeStatusBarControl::~SvxPosSizeStatusBarControl()
+{
+}
+
+
+/* [Description]
+
+ SID_PSZ_FUNCTION activates the popup menu for Calc:
+
+ Status overview
+ Depending on the type of the item, a special setting is enabled, the others disabled.
+
+ NULL/Void SfxPointItem SvxSizeItem SfxStringItem
+ ------------------------------------------------------------------------
+ Position sal_False FALSE
+ Size FALSE TRUE FALSE
+ Text sal_False sal_False TRUE
+
+*/
+
+void SvxPosSizeStatusBarControl::StateChangedAtStatusBarControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ // Because the combi-controller, always sets the current Id as HelpId
+ // first clean the cached HelpText
+ GetStatusBar().SetHelpText( GetId(), "" );
+
+ switch ( nSID )
+ {
+ case SID_ATTR_POSITION : GetStatusBar().SetHelpId( GetId(), STR_POSITION ); break;
+ case SID_TABLE_CELL: GetStatusBar().SetHelpId( GetId(), STR_TABLECELL ); break;
+ case SID_PSZ_FUNCTION: GetStatusBar().SetHelpId( GetId(), STR_FUNC ); break;
+ default: break;
+ }
+
+ if ( nSID == SID_PSZ_FUNCTION )
+ {
+ if ( eState == SfxItemState::DEFAULT )
+ {
+ pImpl->bHasMenu = true;
+ if ( auto pUInt32Item = dynamic_cast< const SfxUInt32Item* >(pState) )
+ pImpl->nFunctionSet = pUInt32Item->GetValue();
+ }
+ else
+ pImpl->bHasMenu = false;
+ }
+ else if ( SfxItemState::DEFAULT != eState )
+ {
+ // don't switch to empty display before an empty state was
+ // notified for all display types
+
+ if ( nSID == SID_TABLE_CELL )
+ pImpl->bTable = false;
+ else if ( nSID == SID_ATTR_POSITION )
+ pImpl->bPos = false;
+ else if ( nSID == GetSlotId() ) // controller is registered for SID_ATTR_SIZE
+ pImpl->bSize = false;
+ else
+ {
+ SAL_WARN( "svx.stbcrtls","unknown slot id");
+ }
+ }
+ else if ( auto pPointItem = dynamic_cast<const SfxPointItem*>( pState) )
+ {
+ // show position
+ pImpl->aPos = pPointItem->GetValue();
+ pImpl->bPos = true;
+ pImpl->bTable = false;
+ }
+ else if ( auto pSizeItem = dynamic_cast<const SvxSizeItem*>( pState) )
+ {
+ // show size
+ pImpl->aSize = pSizeItem->GetSize();
+ pImpl->bSize = true;
+ pImpl->bTable = false;
+ }
+ else if ( auto pStringItem = dynamic_cast<const SfxStringItem*>( pState) )
+ {
+ // show string (table cel or different)
+ pImpl->aStr = pStringItem->GetValue();
+ pImpl->bTable = true;
+ pImpl->bPos = false;
+ pImpl->bSize = false;
+ }
+ else
+ {
+ SAL_WARN( "svx.stbcrtls", "invalid item type" );
+ pImpl->bPos = false;
+ pImpl->bSize = false;
+ pImpl->bTable = false;
+ }
+
+ GetStatusBar().SetItemData( GetId(), nullptr );
+
+ ImplUpdateItemText();
+}
+
+
+/* [Description]
+
+ execute popup menu, when the status enables this
+*/
+
+void SvxPosSizeStatusBarControl::Command( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() == CommandEventId::ContextMenu && pImpl->bHasMenu )
+ {
+ sal_uInt32 nSelect = pImpl->nFunctionSet;
+ if (!nSelect)
+ nSelect = ( 1 << PSZ_FUNC_NONE );
+ tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1,1));
+ weld::Window* pParent = weld::GetPopupParent(GetStatusBar(), aRect);
+ FunctionPopup_Impl aMenu(nSelect);
+ OString sIdent = aMenu.Execute(pParent, aRect);
+ if (!sIdent.isEmpty())
+ {
+ nSelect = aMenu.GetSelected(sIdent);
+ if (nSelect)
+ {
+ if (nSelect == (1 << PSZ_FUNC_NONE))
+ nSelect = 0;
+
+ css::uno::Any a;
+ SfxUInt32Item aItem( SID_PSZ_FUNCTION, nSelect );
+ aItem.QueryValue( a );
+ css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
+ "StatusBarFunc", a) };
+ execute( ".uno:StatusBarFunc", aArgs );
+ }
+ }
+ }
+ else
+ SfxStatusBarControl::Command( rCEvt );
+}
+
+
+/* [Description]
+
+ Depending on the type to be shown, the value us shown. First the
+ rectangle is repainted (removed).
+*/
+
+void SvxPosSizeStatusBarControl::Paint( const UserDrawEvent& rUsrEvt )
+{
+ vcl::RenderContext* pDev = rUsrEvt.GetRenderContext();
+
+ const tools::Rectangle& rRect = rUsrEvt.GetRect();
+ StatusBar& rBar = GetStatusBar();
+ Point aItemPos = rBar.GetItemTextPos( GetId() );
+ Color aOldLineColor = pDev->GetLineColor();
+ Color aOldFillColor = pDev->GetFillColor();
+ pDev->SetLineColor();
+ pDev->SetFillColor( pDev->GetBackground().GetColor() );
+
+ if ( pImpl->bPos || pImpl->bSize )
+ {
+ // count the position for showing the size
+ tools::Long nSizePosX =
+ rRect.Left() + rRect.GetWidth() / 2 + PAINT_OFFSET;
+ // draw position
+ Point aPnt = rRect.TopLeft();
+ aPnt.setY( aItemPos.Y() );
+ aPnt.AdjustX(PAINT_OFFSET );
+ pDev->DrawImage( aPnt, pImpl->aPosImage );
+ aPnt.AdjustX(pImpl->aPosImage.GetSizePixel().Width() );
+ aPnt.AdjustX(PAINT_OFFSET );
+ OUString aStr = GetMetricStr_Impl( pImpl->aPos.X()) + " / " +
+ GetMetricStr_Impl( pImpl->aPos.Y());
+ tools::Rectangle aRect(aPnt, Point(nSizePosX, rRect.Bottom()));
+ pDev->DrawRect(aRect);
+ vcl::Region aOrigRegion(pDev->GetClipRegion());
+ pDev->SetClipRegion(vcl::Region(aRect));
+ pDev->DrawText(aPnt, aStr);
+ pDev->SetClipRegion(aOrigRegion);
+
+ // draw the size, when available
+ aPnt.setX( nSizePosX );
+
+ if ( pImpl->bSize )
+ {
+ pDev->DrawImage( aPnt, pImpl->aSizeImage );
+ aPnt.AdjustX(pImpl->aSizeImage.GetSizePixel().Width() );
+ Point aDrwPnt = aPnt;
+ aPnt.AdjustX(PAINT_OFFSET );
+ aStr = GetMetricStr_Impl( pImpl->aSize.Width() ) + " x " +
+ GetMetricStr_Impl( pImpl->aSize.Height() );
+ aRect = tools::Rectangle(aDrwPnt, rRect.BottomRight());
+ pDev->DrawRect(aRect);
+ aOrigRegion = pDev->GetClipRegion();
+ pDev->SetClipRegion(vcl::Region(aRect));
+ pDev->DrawText(aPnt, aStr);
+ pDev->SetClipRegion(aOrigRegion);
+ }
+ else
+ pDev->DrawRect( tools::Rectangle( aPnt, rRect.BottomRight() ) );
+ }
+ else if ( pImpl->bTable )
+ {
+ pDev->DrawRect( rRect );
+ pDev->DrawText( Point(
+ rRect.Left() + rRect.GetWidth() / 2 - pDev->GetTextWidth( pImpl->aStr ) / 2,
+ aItemPos.Y() ), pImpl->aStr );
+ }
+ else
+ {
+ // Empty display if neither size nor table position are available.
+ // Date/Time are no longer used (#65302#).
+ pDev->DrawRect( rRect );
+ }
+
+ pDev->SetLineColor( aOldLineColor );
+ pDev->SetFillColor( aOldFillColor );
+}
+
+void SvxPosSizeStatusBarControl::ImplUpdateItemText()
+{
+ // set only strings as text at the statusBar, so that the Help-Tips
+ // can work with the text, when it is too long for the statusBar
+ OUString aText;
+ int nCharsWidth = -1;
+ if ( pImpl->bPos || pImpl->bSize )
+ {
+ aText = GetMetricStr_Impl( pImpl->aPos.X()) + " / " +
+ GetMetricStr_Impl( pImpl->aPos.Y());
+ // widest X/Y string looks like "-999,99"
+ nCharsWidth = 1 + 6 + 3 + 6; // icon + x + slash + y
+ if ( pImpl->bSize )
+ {
+ aText += " " + GetMetricStr_Impl( pImpl->aSize.Width() ) + " x " +
+ GetMetricStr_Impl( pImpl->aSize.Height() );
+ nCharsWidth += 1 + 1 + 4 + 3 + 4; // icon + space + w + x + h
+ }
+ }
+ else if ( pImpl->bTable )
+ aText = pImpl->aStr;
+
+ GetStatusBar().SetItemText( GetId(), aText, nCharsWidth );
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/stbctrls/selctrl.cxx b/svx/source/stbctrls/selctrl.cxx
new file mode 100644
index 000000000..8c32f3ed8
--- /dev/null
+++ b/svx/source/stbctrls/selctrl.cxx
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/event.hxx>
+#include <vcl/status.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
+#include <svl/intitem.hxx>
+#include <tools/urlobj.hxx>
+
+#include <svx/selctrl.hxx>
+
+#include <bitmaps.hlst>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+SFX_IMPL_STATUSBAR_CONTROL(SvxSelectionModeControl, SfxUInt16Item);
+
+namespace {
+
+/// Popup menu to select the selection type
+class SelectionTypePopup
+{
+ weld::Window* m_pPopupParent;
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Menu> m_xMenu;
+ static OString state_to_id(sal_uInt16 nState);
+public:
+ SelectionTypePopup(weld::Window* pPopupParent, sal_uInt16 nCurrent);
+ OUString GetItemTextForState(sal_uInt16 nState) { return m_xMenu->get_label(state_to_id(nState)); }
+ OString popup_at_rect(const tools::Rectangle& rRect)
+ {
+ return m_xMenu->popup_at_rect(m_pPopupParent, rRect);
+ }
+ void HideSelectionType(const OString& rIdent)
+ {
+ m_xMenu->remove(rIdent);
+ }
+ static sal_uInt16 id_to_state(std::string_view ident);
+};
+
+}
+
+sal_uInt16 SelectionTypePopup::id_to_state(std::string_view ident)
+{
+ if (ident == "block")
+ return 3;
+ else if (ident == "adding")
+ return 2;
+ else if (ident == "extending")
+ return 1;
+ else // fall through
+ return 0;
+}
+
+OString SelectionTypePopup::state_to_id(sal_uInt16 nState)
+{
+ switch (nState)
+ {
+ default: // fall through
+ case 0: return "standard";
+ case 1: return "extending";
+ case 2: return "adding";
+ case 3: return "block";
+ }
+}
+
+SelectionTypePopup::SelectionTypePopup(weld::Window* pPopupParent, sal_uInt16 nCurrent)
+ : m_pPopupParent(pPopupParent)
+ , m_xBuilder(Application::CreateBuilder(m_pPopupParent, "svx/ui/selectionmenu.ui"))
+ , m_xMenu(m_xBuilder->weld_menu("menu"))
+{
+ m_xMenu->set_active(state_to_id(nCurrent), true);
+}
+
+SvxSelectionModeControl::SvxSelectionModeControl( sal_uInt16 _nSlotId,
+ sal_uInt16 _nId,
+ StatusBar& rStb ) :
+ SfxStatusBarControl( _nSlotId, _nId, rStb ),
+ mnState( 0 ),
+ maImages{Image(StockImage::Yes, RID_SVXBMP_STANDARD_SELECTION),
+ Image(StockImage::Yes, RID_SVXBMP_EXTENDING_SELECTION),
+ Image(StockImage::Yes, RID_SVXBMP_ADDING_SELECTION),
+ Image(StockImage::Yes, RID_SVXBMP_BLOCK_SELECTION)},
+ mbFeatureEnabled(false)
+{
+ GetStatusBar().SetQuickHelpText(GetId(), u"");
+}
+
+void SvxSelectionModeControl::StateChangedAtStatusBarControl( sal_uInt16, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ mbFeatureEnabled = SfxItemState::DEFAULT == eState;
+ if (mbFeatureEnabled)
+ {
+ DBG_ASSERT( dynamic_cast< const SfxUInt16Item* >(pState) != nullptr, "invalid item type" );
+ const SfxUInt16Item* pItem = static_cast<const SfxUInt16Item*>(pState);
+ mnState = pItem->GetValue();
+ SelectionTypePopup aPop(GetStatusBar().GetFrameWeld(), mnState);
+ GetStatusBar().SetQuickHelpText(GetId(),
+ SvxResId(RID_SVXSTR_SELECTIONMODE_HELPTEXT).
+ replaceFirst("%1", aPop.GetItemTextForState(mnState)));
+ GetStatusBar().Invalidate();
+ }
+}
+
+bool SvxSelectionModeControl::MouseButtonDown( const MouseEvent& rEvt )
+{
+ if (!mbFeatureEnabled)
+ return true;
+
+ ::tools::Rectangle aRect(rEvt.GetPosPixel(), Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(GetStatusBar(), aRect);
+ SelectionTypePopup aPop(pPopupParent, mnState);
+
+ // Check if Calc is opened; if true, hide block selection mode tdf#122280
+ const css::uno::Reference < css::frame::XModel > xModel = m_xFrame->getController()->getModel();
+ css::uno::Reference< css::lang::XServiceInfo > xServices( xModel, css::uno::UNO_QUERY );
+ if ( xServices.is() )
+ {
+ bool bSpecModeCalc = xServices->supportsService("com.sun.star.sheet.SpreadsheetDocument");
+ if (bSpecModeCalc)
+ aPop.HideSelectionType("block");
+ }
+
+ OString sIdent = aPop.popup_at_rect(aRect);
+ if (!sIdent.isEmpty())
+ {
+ sal_uInt16 nNewState = SelectionTypePopup::id_to_state(sIdent);
+ if ( nNewState != mnState )
+ {
+ mnState = nNewState;
+
+ css::uno::Any a;
+ SfxUInt16Item aState( GetSlotId(), mnState );
+ aState.QueryValue( a );
+ INetURLObject aObj( m_aCommandURL );
+
+ css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
+ aObj.GetURLPath(), a) };
+ execute( aArgs );
+ }
+ }
+
+ return true;
+}
+
+void SvxSelectionModeControl::Click()
+{
+}
+
+void SvxSelectionModeControl::Paint( const UserDrawEvent& rUsrEvt )
+{
+ const tools::Rectangle aControlRect = getControlRect();
+ vcl::RenderContext* pDev = rUsrEvt.GetRenderContext();
+ tools::Rectangle aRect = rUsrEvt.GetRect();
+
+ Size aImgSize( maImages[mnState].GetSizePixel() );
+
+ Point aPos( aRect.Left() + ( aControlRect.GetWidth() - aImgSize.Width() ) / 2,
+ aRect.Top() + ( aControlRect.GetHeight() - aImgSize.Height() ) / 2 );
+
+ if (mbFeatureEnabled)
+ pDev->DrawImage(aPos, maImages[mnState]);
+ else
+ pDev->DrawImage(aPos, Image());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/stbctrls/stbctrls.h b/svx/source/stbctrls/stbctrls.h
new file mode 100644
index 000000000..3b12d6f95
--- /dev/null
+++ b/svx/source/stbctrls/stbctrls.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_STBCTRLS_STBCTRLS_H
+#define INCLUDED_SVX_SOURCE_STBCTRLS_STBCTRLS_H
+
+// IDs as in SUBTOTAL_FUNC of Calc
+
+#define PSZ_FUNC_AVG 1
+#define PSZ_FUNC_COUNT2 3
+#define PSZ_FUNC_COUNT 2
+#define PSZ_FUNC_MAX 4
+#define PSZ_FUNC_MIN 5
+#define PSZ_FUNC_SUM 9
+#define PSZ_FUNC_SELECTION_COUNT 13
+#define PSZ_FUNC_NONE 16
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/stbctrls/xmlsecctrl.cxx b/svx/source/stbctrls/xmlsecctrl.cxx
new file mode 100644
index 000000000..0a26128d9
--- /dev/null
+++ b/svx/source/stbctrls/xmlsecctrl.cxx
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/image.hxx>
+#include <vcl/event.hxx>
+#include <vcl/status.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
+#include <sfx2/signaturestate.hxx>
+#include <sfx2/module.hxx>
+
+#include <svl/intitem.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/xmlsecctrl.hxx>
+#include <tools/urlobj.hxx>
+#include <bitmaps.hlst>
+#include <sal/log.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+SFX_IMPL_STATUSBAR_CONTROL( XmlSecStatusBarControl, SfxUInt16Item );
+
+struct XmlSecStatusBarControl::XmlSecStatusBarControl_Impl
+{
+ SignatureState mnState;
+ Image maImage;
+ Image maImageBroken;
+ Image maImageNotValidated;
+};
+
+
+XmlSecStatusBarControl::XmlSecStatusBarControl( sal_uInt16 _nSlotId, sal_uInt16 _nId, StatusBar& _rStb )
+ :SfxStatusBarControl( _nSlotId, _nId, _rStb )
+ ,mpImpl( new XmlSecStatusBarControl_Impl )
+{
+ mpImpl->mnState = SignatureState::UNKNOWN;
+
+ mpImpl->maImage = Image(StockImage::Yes, RID_SVXBMP_SIGNET);
+ mpImpl->maImageBroken = Image(StockImage::Yes, RID_SVXBMP_SIGNET_BROKEN);
+ mpImpl->maImageNotValidated = Image(StockImage::Yes, RID_SVXBMP_SIGNET_NOTVALIDATED);
+}
+
+XmlSecStatusBarControl::~XmlSecStatusBarControl()
+{
+}
+
+void XmlSecStatusBarControl::StateChangedAtStatusBarControl( sal_uInt16, SfxItemState eState, const SfxPoolItem* pState )
+{
+ if( SfxItemState::DEFAULT != eState )
+ {
+ mpImpl->mnState = SignatureState::UNKNOWN;
+ }
+ else if( auto pUint16Item = dynamic_cast< const SfxUInt16Item* >(pState) )
+ {
+ mpImpl->mnState = static_cast<SignatureState>(pUint16Item->GetValue());
+ }
+ else
+ {
+ SAL_WARN( "svx.stbcrtls", "+XmlSecStatusBarControl::StateChangedAtStatusBarControl(): invalid item type" );
+ mpImpl->mnState = SignatureState::UNKNOWN;
+ }
+
+ GetStatusBar().SetItemData( GetId(), nullptr ); // necessary ?
+
+ GetStatusBar().SetItemText( GetId(), "" ); // necessary ?
+
+ TranslateId pResId = RID_SVXSTR_XMLSEC_NO_SIG;
+ if ( mpImpl->mnState == SignatureState::OK )
+ pResId = RID_SVXSTR_XMLSEC_SIG_OK;
+ else if ( mpImpl->mnState == SignatureState::BROKEN )
+ pResId = RID_SVXSTR_XMLSEC_SIG_NOT_OK;
+ else if ( mpImpl->mnState == SignatureState::NOTVALIDATED )
+ pResId = RID_SVXSTR_XMLSEC_SIG_OK_NO_VERIFY;
+ else if ( mpImpl->mnState == SignatureState::PARTIAL_OK )
+ pResId = RID_SVXSTR_XMLSEC_SIG_CERT_OK_PARTIAL_SIG;
+
+ GetStatusBar().SetQuickHelpText(GetId(), SvxResId(pResId));
+}
+
+void XmlSecStatusBarControl::Command( const CommandEvent& rCEvt )
+{
+ if( rCEvt.GetCommand() == CommandEventId::ContextMenu )
+ {
+ tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(GetStatusBar(), aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "svx/ui/xmlsecstatmenu.ui"));
+ std::unique_ptr<weld::Menu> xPopMenu(xBuilder->weld_menu("menu"));
+ if (!xPopMenu->popup_at_rect(pPopupParent, aRect).isEmpty())
+ {
+ css::uno::Any a;
+ SfxUInt16Item aState( GetSlotId(), 0 );
+ aState.QueryValue( a );
+ INetURLObject aObj( m_aCommandURL );
+
+ css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
+ aObj.GetURLPath(), a) };
+ execute( aArgs );
+ }
+ }
+ else
+ SfxStatusBarControl::Command( rCEvt );
+}
+
+void XmlSecStatusBarControl::Paint( const UserDrawEvent& rUsrEvt )
+{
+ vcl::RenderContext* pDev = rUsrEvt.GetRenderContext();
+
+ tools::Rectangle aRect = rUsrEvt.GetRect();
+ Color aOldLineColor = pDev->GetLineColor();
+ Color aOldFillColor = pDev->GetFillColor();
+
+ pDev->SetLineColor();
+ pDev->SetFillColor( pDev->GetBackground().GetColor() );
+
+ tools::Long yOffset = (aRect.GetHeight() - mpImpl->maImage.GetSizePixel().Height()) / 2;
+
+ if( mpImpl->mnState == SignatureState::OK )
+ {
+ aRect.AdjustTop(yOffset );
+ pDev->DrawImage( aRect.TopLeft(), mpImpl->maImage );
+ }
+ else if( mpImpl->mnState == SignatureState::BROKEN )
+ {
+ aRect.AdjustTop(yOffset );
+ pDev->DrawImage( aRect.TopLeft(), mpImpl->maImageBroken );
+ }
+ else if( mpImpl->mnState == SignatureState::NOTVALIDATED
+ || mpImpl->mnState == SignatureState::PARTIAL_OK)
+ {
+ aRect.AdjustTop(yOffset );
+ pDev->DrawImage( aRect.TopLeft(), mpImpl->maImageNotValidated );
+ }
+ else
+ pDev->DrawRect( aRect );
+
+ pDev->SetLineColor( aOldLineColor );
+ pDev->SetFillColor( aOldFillColor );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/stbctrls/zoomctrl.cxx b/svx/source/stbctrls/zoomctrl.cxx
new file mode 100644
index 000000000..57cf99bbd
--- /dev/null
+++ b/svx/source/stbctrls/zoomctrl.cxx
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <i18nutil/unicode.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/status.hxx>
+#include <vcl/weldutils.hxx>
+#include <vcl/settings.hxx>
+#include <tools/urlobj.hxx>
+#include <sal/log.hxx>
+
+#include <svx/strings.hrc>
+
+#include <svx/zoomctrl.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <svx/dialmgr.hxx>
+#include "modctrl_internal.hxx"
+#include <bitmaps.hlst>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+SFX_IMPL_STATUSBAR_CONTROL(SvxZoomStatusBarControl,SvxZoomItem);
+
+namespace {
+
+class ZoomPopup_Impl
+{
+public:
+ ZoomPopup_Impl(weld::Window* pPopupParent, sal_uInt16 nZ, SvxZoomEnableFlags nValueSet);
+
+ sal_uInt16 GetZoom(std::string_view ident) const;
+
+ OString popup_at_rect(const tools::Rectangle& rRect)
+ {
+ return m_xMenu->popup_at_rect(m_pPopupParent, rRect);
+ }
+
+private:
+ weld::Window* m_pPopupParent;
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Menu> m_xMenu;
+ sal_uInt16 nZoom;
+};
+
+}
+
+ZoomPopup_Impl::ZoomPopup_Impl(weld::Window* pPopupParent, sal_uInt16 nZ, SvxZoomEnableFlags nValueSet)
+ : m_pPopupParent(pPopupParent)
+ , m_xBuilder(Application::CreateBuilder(m_pPopupParent, "svx/ui/zoommenu.ui"))
+ , m_xMenu(m_xBuilder->weld_menu("menu"))
+ , nZoom(nZ)
+{
+ if ( !(SvxZoomEnableFlags::N50 & nValueSet) )
+ m_xMenu->set_sensitive("50", false);
+ if ( !(SvxZoomEnableFlags::N100 & nValueSet) )
+ m_xMenu->set_sensitive("100", false);
+ if ( !(SvxZoomEnableFlags::N150 & nValueSet) )
+ m_xMenu->set_sensitive("150", false);
+ if ( !(SvxZoomEnableFlags::N200 & nValueSet) )
+ m_xMenu->set_sensitive("200", false);
+ if ( !(SvxZoomEnableFlags::OPTIMAL & nValueSet) )
+ m_xMenu->set_sensitive("optimal", false);
+ if ( !(SvxZoomEnableFlags::WHOLEPAGE & nValueSet) )
+ m_xMenu->set_sensitive("page", false);
+ if ( !(SvxZoomEnableFlags::PAGEWIDTH & nValueSet) )
+ m_xMenu->set_sensitive("width", false);
+}
+
+sal_uInt16 ZoomPopup_Impl::GetZoom(std::string_view ident) const
+{
+ sal_uInt16 nRet = nZoom;
+
+ if (ident == "200")
+ nRet = 200;
+ else if (ident == "150")
+ nRet = 150;
+ else if (ident == "100")
+ nRet = 100;
+ else if (ident == "75")
+ nRet = 75;
+ else if (ident == "50")
+ nRet = 50;
+ else if (ident == "optimal" || ident == "width" || ident == "page")
+ nRet = 0;
+
+ return nRet;
+}
+
+SvxZoomStatusBarControl::SvxZoomStatusBarControl( sal_uInt16 _nSlotId,
+ sal_uInt16 _nId,
+ StatusBar& rStb ) :
+
+ SfxStatusBarControl( _nSlotId, _nId, rStb ),
+ nZoom( 100 ),
+ nValueSet( SvxZoomEnableFlags::ALL )
+{
+ GetStatusBar().SetQuickHelpText(GetId(), SvxResId(RID_SVXSTR_ZOOMTOOL_HINT));
+ ImplUpdateItemText();
+}
+
+void SvxZoomStatusBarControl::StateChangedAtStatusBarControl( sal_uInt16, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ if( SfxItemState::DEFAULT != eState )
+ {
+ GetStatusBar().SetItemText( GetId(), "" );
+ nValueSet = SvxZoomEnableFlags::NONE;
+ }
+ else if ( auto pItem = dynamic_cast< const SfxUInt16Item* >(pState) )
+ {
+ nZoom = pItem->GetValue();
+ ImplUpdateItemText();
+
+ if ( auto pZoomItem = dynamic_cast<const SvxZoomItem*>(pState) )
+ {
+ nValueSet = pZoomItem->GetValueSet();
+ }
+ else
+ {
+ SAL_INFO( "svx", "use SfxZoomItem for SID_ATTR_ZOOM" );
+ nValueSet = SvxZoomEnableFlags::ALL;
+ }
+ }
+}
+
+void SvxZoomStatusBarControl::ImplUpdateItemText()
+{
+ // workaround - don't bother updating when we don't have a real zoom value
+ if (nZoom)
+ {
+ OUString aStr(unicode::formatPercent(nZoom, Application::GetSettings().GetUILanguageTag()));
+ GetStatusBar().SetItemText( GetId(), aStr );
+ }
+}
+
+void SvxZoomStatusBarControl::Paint( const UserDrawEvent& )
+{
+}
+
+void SvxZoomStatusBarControl::Command( const CommandEvent& rCEvt )
+{
+ if ( CommandEventId::ContextMenu == rCEvt.GetCommand() && bool(nValueSet) )
+ {
+ ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(GetStatusBar(), aRect);
+ ZoomPopup_Impl aPop(pPopupParent, nZoom, nValueSet);
+
+ OString sIdent = aPop.popup_at_rect(aRect);
+ if (!sIdent.isEmpty() && (nZoom != aPop.GetZoom(sIdent) || !nZoom))
+ {
+ nZoom = aPop.GetZoom(sIdent);
+ ImplUpdateItemText();
+ SvxZoomItem aZoom(SvxZoomType::PERCENT, nZoom, GetId());
+
+ if (sIdent == "optimal")
+ aZoom.SetType(SvxZoomType::OPTIMAL);
+ else if (sIdent == "width")
+ aZoom.SetType(SvxZoomType::PAGEWIDTH);
+ else if (sIdent == "page")
+ aZoom.SetType(SvxZoomType::WHOLEPAGE);
+
+ css::uno::Any a;
+ aZoom.QueryValue( a );
+ INetURLObject aObj( m_aCommandURL );
+
+ css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
+ aObj.GetURLPath(), a) };
+ execute( aArgs );
+ }
+ }
+ else
+ SfxStatusBarControl::Command( rCEvt );
+}
+
+SFX_IMPL_STATUSBAR_CONTROL(SvxZoomPageStatusBarControl,SfxVoidItem);
+
+SvxZoomPageStatusBarControl::SvxZoomPageStatusBarControl(sal_uInt16 _nSlotId,
+ sal_uInt16 _nId, StatusBar& rStb)
+ : SfxStatusBarControl(_nSlotId, _nId, rStb)
+ , maImage(StockImage::Yes, RID_SVXBMP_ZOOM_PAGE)
+{
+ GetStatusBar().SetQuickHelpText(GetId(), SvxResId(RID_SVXSTR_FIT_SLIDE));
+}
+
+void SvxZoomPageStatusBarControl::Paint(const UserDrawEvent& rUsrEvt)
+{
+ vcl::RenderContext* pDev = rUsrEvt.GetRenderContext();
+ tools::Rectangle aRect = rUsrEvt.GetRect();
+ Point aPt = centerImage(aRect, maImage);
+ pDev->DrawImage(aPt, maImage);
+}
+
+bool SvxZoomPageStatusBarControl::MouseButtonDown(const MouseEvent&)
+{
+ SvxZoomItem aZoom( SvxZoomType::WHOLEPAGE, 0, GetId() );
+
+ css::uno::Any a;
+ aZoom.QueryValue( a );
+ INetURLObject aObj( m_aCommandURL );
+
+ css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
+ aObj.GetURLPath(), a) };
+ execute( aArgs );
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/stbctrls/zoomsliderctrl.cxx b/svx/source/stbctrls/zoomsliderctrl.cxx
new file mode 100644
index 000000000..c0790b074
--- /dev/null
+++ b/svx/source/stbctrls/zoomsliderctrl.cxx
@@ -0,0 +1,392 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/zoomsliderctrl.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/status.hxx>
+#include <vcl/image.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/event.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <basegfx/utils/zoomtools.hxx>
+#include <bitmaps.hlst>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <set>
+
+SFX_IMPL_STATUSBAR_CONTROL( SvxZoomSliderControl, SvxZoomSliderItem );
+
+struct SvxZoomSliderControl::SvxZoomSliderControl_Impl
+{
+ sal_uInt16 mnCurrentZoom;
+ sal_uInt16 mnMinZoom;
+ sal_uInt16 mnMaxZoom;
+ sal_uInt16 mnSliderCenter;
+ std::vector< tools::Long > maSnappingPointOffsets;
+ std::vector< sal_uInt16 > maSnappingPointZooms;
+ Image maSliderButton;
+ Image maIncreaseButton;
+ Image maDecreaseButton;
+ bool mbValuesSet;
+ bool mbDraggingStarted;
+
+ SvxZoomSliderControl_Impl() :
+ mnCurrentZoom( 0 ),
+ mnMinZoom( 0 ),
+ mnMaxZoom( 0 ),
+ mnSliderCenter( 0 ),
+ mbValuesSet( false ),
+ mbDraggingStarted( false ) {}
+};
+
+const tools::Long nSliderXOffset = 20;
+const tools::Long nSnappingEpsilon = 5; // snapping epsilon in pixels
+const tools::Long nSnappingPointsMinDist = nSnappingEpsilon; // minimum distance of two adjacent snapping points
+
+// nOffset refers to the origin of the control:
+// + ----------- -
+sal_uInt16 SvxZoomSliderControl::Offset2Zoom( tools::Long nOffset ) const
+{
+ const tools::Long nControlWidth = getControlRect().GetWidth();
+ sal_uInt16 nRet = 0;
+
+ if ( nOffset < nSliderXOffset )
+ return mxImpl->mnMinZoom;
+
+ if ( nOffset > nControlWidth - nSliderXOffset )
+ return mxImpl->mnMaxZoom;
+
+ // check for snapping points:
+ sal_uInt16 nCount = 0;
+ for ( const tools::Long nCurrent : mxImpl->maSnappingPointOffsets )
+ {
+ if ( std::abs(nCurrent - nOffset) < nSnappingEpsilon )
+ {
+ nOffset = nCurrent;
+ nRet = mxImpl->maSnappingPointZooms[ nCount ];
+ break;
+ }
+ ++nCount;
+ }
+
+ if ( 0 == nRet )
+ {
+ if ( nOffset < nControlWidth / 2 )
+ {
+ // first half of slider
+ const tools::Long nFirstHalfRange = mxImpl->mnSliderCenter - mxImpl->mnMinZoom;
+ const tools::Long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
+ const tools::Long nZoomPerSliderPixel = (1000 * nFirstHalfRange) / nHalfSliderWidth;
+ const tools::Long nOffsetToSliderLeft = nOffset - nSliderXOffset;
+ nRet = mxImpl->mnMinZoom + sal_uInt16( nOffsetToSliderLeft * nZoomPerSliderPixel / 1000 );
+ }
+ else
+ {
+ // second half of slider
+ const tools::Long nSecondHalfRange = mxImpl->mnMaxZoom - mxImpl->mnSliderCenter;
+ const tools::Long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
+ const tools::Long nZoomPerSliderPixel = 1000 * nSecondHalfRange / nHalfSliderWidth;
+ const tools::Long nOffsetToSliderCenter = nOffset - nControlWidth/2;
+ nRet = mxImpl->mnSliderCenter + sal_uInt16( nOffsetToSliderCenter * nZoomPerSliderPixel / 1000 );
+ }
+ }
+
+ if ( nRet < mxImpl->mnMinZoom )
+ nRet = mxImpl->mnMinZoom;
+ else if ( nRet > mxImpl->mnMaxZoom )
+ nRet = mxImpl->mnMaxZoom;
+
+ return nRet;
+}
+
+// returns the offset to the left control border
+tools::Long SvxZoomSliderControl::Zoom2Offset( sal_uInt16 nCurrentZoom ) const
+{
+ const tools::Long nControlWidth = getControlRect().GetWidth();
+ tools::Long nRet = nSliderXOffset;
+
+ const tools::Long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
+
+ if ( nCurrentZoom <= mxImpl->mnSliderCenter )
+ {
+ nCurrentZoom = nCurrentZoom - mxImpl->mnMinZoom;
+ const tools::Long nFirstHalfRange = mxImpl->mnSliderCenter - mxImpl->mnMinZoom;
+ const tools::Long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth / nFirstHalfRange;
+ const tools::Long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
+ nRet += nOffset;
+ }
+ else
+ {
+ nCurrentZoom = nCurrentZoom - mxImpl->mnSliderCenter;
+ const tools::Long nSecondHalfRange = mxImpl->mnMaxZoom - mxImpl->mnSliderCenter;
+ const tools::Long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth / nSecondHalfRange;
+ const tools::Long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
+ nRet += nHalfSliderWidth + nOffset;
+ }
+
+ return nRet;
+}
+
+SvxZoomSliderControl::SvxZoomSliderControl( sal_uInt16 _nSlotId, sal_uInt16 _nId, StatusBar& rStatusBar ) :
+ SfxStatusBarControl( _nSlotId, _nId, rStatusBar ),
+ mxImpl( new SvxZoomSliderControl_Impl )
+{
+ mxImpl->maSliderButton = Image(StockImage::Yes, RID_SVXBMP_SLIDERBUTTON);
+ mxImpl->maIncreaseButton = Image(StockImage::Yes, RID_SVXBMP_SLIDERINCREASE);
+ mxImpl->maDecreaseButton = Image(StockImage::Yes, RID_SVXBMP_SLIDERDECREASE);
+}
+
+SvxZoomSliderControl::~SvxZoomSliderControl()
+{
+}
+
+void SvxZoomSliderControl::StateChangedAtStatusBarControl( sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState )
+{
+ if ( (SfxItemState::DEFAULT != eState) || pState->IsVoidItem() )
+ {
+ GetStatusBar().SetItemText( GetId(), "" );
+ mxImpl->mbValuesSet = false;
+ }
+ else
+ {
+ assert( dynamic_cast<const SvxZoomSliderItem*>( pState) && "invalid item type: should be a SvxZoomSliderItem" );
+ mxImpl->mnCurrentZoom = static_cast<const SvxZoomSliderItem*>( pState )->GetValue();
+ mxImpl->mnMinZoom = static_cast<const SvxZoomSliderItem*>( pState )->GetMinZoom();
+ mxImpl->mnMaxZoom = static_cast<const SvxZoomSliderItem*>( pState )->GetMaxZoom();
+ mxImpl->mnSliderCenter= 100;
+ mxImpl->mbValuesSet = true;
+
+ if ( mxImpl->mnSliderCenter == mxImpl->mnMaxZoom )
+ mxImpl->mnSliderCenter = mxImpl->mnMinZoom + static_cast<sal_uInt16>((mxImpl->mnMaxZoom - mxImpl->mnMinZoom) * 0.5);
+
+
+ DBG_ASSERT( mxImpl->mnMinZoom <= mxImpl->mnCurrentZoom &&
+ mxImpl->mnMinZoom < mxImpl->mnSliderCenter &&
+ mxImpl->mnMaxZoom >= mxImpl->mnCurrentZoom &&
+ mxImpl->mnMaxZoom > mxImpl->mnSliderCenter,
+ "Looks like the zoom slider item is corrupted" );
+
+ const css::uno::Sequence < sal_Int32 > rSnappingPoints = static_cast<const SvxZoomSliderItem*>( pState )->GetSnappingPoints();
+ mxImpl->maSnappingPointOffsets.clear();
+ mxImpl->maSnappingPointZooms.clear();
+
+ // get all snapping points:
+ std::set< sal_uInt16 > aTmpSnappingPoints;
+ for ( const sal_Int32 nSnappingPoint : rSnappingPoints )
+ {
+ aTmpSnappingPoints.insert( static_cast<sal_uInt16>(nSnappingPoint) );
+ }
+
+ // remove snapping points that are too close to each other:
+ tools::Long nLastOffset = 0;
+
+ for ( const sal_uInt16 nCurrent : aTmpSnappingPoints )
+ {
+ const tools::Long nCurrentOffset = Zoom2Offset( nCurrent );
+
+ if ( nCurrentOffset - nLastOffset >= nSnappingPointsMinDist )
+ {
+ mxImpl->maSnappingPointOffsets.push_back( nCurrentOffset );
+ mxImpl->maSnappingPointZooms.push_back( nCurrent );
+ nLastOffset = nCurrentOffset;
+ }
+ }
+ }
+
+ forceRepaint();
+}
+
+void SvxZoomSliderControl::Paint( const UserDrawEvent& rUsrEvt )
+{
+ if ( !mxImpl->mbValuesSet )
+ return;
+
+ const tools::Rectangle aControlRect = getControlRect();
+ vcl::RenderContext* pDev = rUsrEvt.GetRenderContext();
+ tools::Rectangle aRect = rUsrEvt.GetRect();
+ tools::Rectangle aSlider = aRect;
+
+ tools::Long nSliderHeight = 1 * pDev->GetDPIScaleFactor();
+ tools::Long nSnappingHeight = 2 * pDev->GetDPIScaleFactor();
+
+ aSlider.AdjustTop((aControlRect.GetHeight() - nSliderHeight)/2 );
+ aSlider.SetBottom( aSlider.Top() + nSliderHeight - 1 );
+ aSlider.AdjustLeft(nSliderXOffset );
+ aSlider.AdjustRight( -nSliderXOffset );
+
+ Color aOldLineColor = pDev->GetLineColor();
+ Color aOldFillColor = pDev->GetFillColor();
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ pDev->SetLineColor( rStyleSettings.GetDarkShadowColor() );
+ pDev->SetFillColor( rStyleSettings.GetDarkShadowColor() );
+
+ // draw slider
+ pDev->DrawRect( aSlider );
+ // shadow
+ pDev->SetLineColor( rStyleSettings.GetShadowColor() );
+ pDev->DrawLine(Point(aSlider.Left()+1,aSlider.Bottom()+1), Point(aSlider.Right()+1,aSlider.Bottom()+1));
+ pDev->SetLineColor( rStyleSettings.GetDarkShadowColor() );
+
+ // draw snapping points:
+ for ( const auto& rSnappingPoint : mxImpl->maSnappingPointOffsets )
+ {
+ tools::Long nSnapPosX = aRect.Left() + rSnappingPoint;
+
+ pDev->DrawRect( tools::Rectangle( nSnapPosX - 1, aSlider.Top() - nSnappingHeight,
+ nSnapPosX, aSlider.Bottom() + nSnappingHeight ) );
+ }
+
+ // draw slider button
+ Point aImagePoint = aRect.TopLeft();
+ aImagePoint.AdjustX(Zoom2Offset( mxImpl->mnCurrentZoom ) );
+ aImagePoint.AdjustX( -(mxImpl->maSliderButton.GetSizePixel().Width()/2) );
+ aImagePoint.AdjustY((aControlRect.GetHeight() - mxImpl->maSliderButton.GetSizePixel().Height())/2 );
+ pDev->DrawImage( aImagePoint, mxImpl->maSliderButton );
+
+ // draw decrease button
+ aImagePoint = aRect.TopLeft();
+ aImagePoint.AdjustX((nSliderXOffset - mxImpl->maDecreaseButton.GetSizePixel().Width())/2 );
+ aImagePoint.AdjustY((aControlRect.GetHeight() - mxImpl->maDecreaseButton.GetSizePixel().Height())/2 );
+ pDev->DrawImage( aImagePoint, mxImpl->maDecreaseButton );
+
+ // draw increase button
+ aImagePoint.setX( aRect.Left() + aControlRect.GetWidth() - mxImpl->maIncreaseButton.GetSizePixel().Width() - (nSliderXOffset - mxImpl->maIncreaseButton.GetSizePixel().Height())/2 );
+ pDev->DrawImage( aImagePoint, mxImpl->maIncreaseButton );
+
+ pDev->SetLineColor( aOldLineColor );
+ pDev->SetFillColor( aOldFillColor );
+}
+
+bool SvxZoomSliderControl::MouseButtonDown( const MouseEvent & rEvt )
+{
+ if ( !mxImpl->mbValuesSet )
+ return true;
+
+ const tools::Rectangle aControlRect = getControlRect();
+ const Point aPoint = rEvt.GetPosPixel();
+ const sal_Int32 nXDiff = aPoint.X() - aControlRect.Left();
+
+ tools::Long nIncDecWidth = mxImpl->maIncreaseButton.GetSizePixel().Width();
+
+ const tools::Long nButtonLeftOffset = (nSliderXOffset - nIncDecWidth)/2;
+ const tools::Long nButtonRightOffset = (nSliderXOffset + nIncDecWidth)/2;
+
+ const tools::Long nOldZoom = mxImpl->mnCurrentZoom;
+
+ // click to - button
+ if ( nXDiff >= nButtonLeftOffset && nXDiff <= nButtonRightOffset )
+ mxImpl->mnCurrentZoom = basegfx::zoomtools::zoomOut( static_cast<int>(mxImpl->mnCurrentZoom) );
+ // click to + button
+ else if ( nXDiff >= aControlRect.GetWidth() - nSliderXOffset + nButtonLeftOffset &&
+ nXDiff <= aControlRect.GetWidth() - nSliderXOffset + nButtonRightOffset )
+ mxImpl->mnCurrentZoom = basegfx::zoomtools::zoomIn( static_cast<int>(mxImpl->mnCurrentZoom) );
+ // click to slider
+ else if( nXDiff >= nSliderXOffset && nXDiff <= aControlRect.GetWidth() - nSliderXOffset )
+ {
+ mxImpl->mnCurrentZoom = Offset2Zoom( nXDiff );
+ mxImpl->mbDraggingStarted = true;
+ }
+
+ if ( mxImpl->mnCurrentZoom < mxImpl->mnMinZoom )
+ mxImpl->mnCurrentZoom = mxImpl->mnMinZoom;
+ else if ( mxImpl->mnCurrentZoom > mxImpl->mnMaxZoom )
+ mxImpl->mnCurrentZoom = mxImpl->mnMaxZoom;
+
+ if ( nOldZoom == mxImpl->mnCurrentZoom )
+ return true;
+
+ repaintAndExecute();
+
+ return true;
+}
+
+bool SvxZoomSliderControl::MouseButtonUp( const MouseEvent & )
+{
+ mxImpl->mbDraggingStarted = false;
+ return true;
+}
+
+bool SvxZoomSliderControl::MouseMove( const MouseEvent & rEvt )
+{
+ if ( !mxImpl->mbValuesSet )
+ return true;
+
+ const short nButtons = rEvt.GetButtons();
+ const tools::Rectangle aControlRect = getControlRect();
+ const Point aPoint = rEvt.GetPosPixel();
+ const sal_Int32 nXDiff = aPoint.X() - aControlRect.Left();
+
+ // check mouse move with button pressed
+ if ( 1 == nButtons && mxImpl->mbDraggingStarted )
+ {
+ if ( nXDiff >= nSliderXOffset && nXDiff <= aControlRect.GetWidth() - nSliderXOffset )
+ {
+ mxImpl->mnCurrentZoom = Offset2Zoom( nXDiff );
+
+ repaintAndExecute();
+ }
+ }
+
+ // Tooltips
+
+ tools::Long nIncDecWidth = mxImpl->maIncreaseButton.GetSizePixel().Width();
+
+ const tools::Long nButtonLeftOffset = (nSliderXOffset - nIncDecWidth)/2;
+ const tools::Long nButtonRightOffset = (nSliderXOffset + nIncDecWidth)/2;
+
+ // click to - button
+ if ( nXDiff >= nButtonLeftOffset && nXDiff <= nButtonRightOffset )
+ GetStatusBar().SetQuickHelpText(GetId(), SvxResId(RID_SVXSTR_ZOOM_OUT));
+ // click to + button
+ else if ( nXDiff >= aControlRect.GetWidth() - nSliderXOffset + nButtonLeftOffset &&
+ nXDiff <= aControlRect.GetWidth() - nSliderXOffset + nButtonRightOffset )
+ GetStatusBar().SetQuickHelpText(GetId(), SvxResId(RID_SVXSTR_ZOOM_IN));
+ else
+ // don't hide the slider and its handle with a tooltip during zooming
+ GetStatusBar().SetQuickHelpText(GetId(), "");
+
+ return true;
+}
+
+void SvxZoomSliderControl::forceRepaint() const
+{
+ GetStatusBar().SetItemData(GetId(), nullptr);
+}
+
+void SvxZoomSliderControl::repaintAndExecute()
+{
+ forceRepaint();
+
+ // commit state change
+ SvxZoomSliderItem aZoomSliderItem(mxImpl->mnCurrentZoom);
+
+ css::uno::Any any;
+ aZoomSliderItem.QueryValue(any);
+
+ css::uno::Sequence<css::beans::PropertyValue> aArgs{ comphelper::makePropertyValue("ZoomSlider",
+ any) };
+ execute(aArgs);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/styles/ColorSets.cxx b/svx/source/styles/ColorSets.cxx
new file mode 100644
index 000000000..240b65e2b
--- /dev/null
+++ b/svx/source/styles/ColorSets.cxx
@@ -0,0 +1,375 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <svx/ColorSets.hxx>
+
+#include <sstream>
+
+#include <libxml/xmlwriter.h>
+
+#include <com/sun/star/util/Color.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/sequence.hxx>
+#include <sal/log.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svditer.hxx>
+#include <editeng/unoprnms.hxx>
+
+using namespace com::sun::star;
+
+namespace
+{
+/// Updates a text portion to match a new color set, in case it already uses theme colors.
+void UpdateTextPortionColorSet(const uno::Reference<beans::XPropertySet>& xPortion,
+ const svx::ColorSet& rColorSet)
+{
+ sal_Int16 nCharColorTheme = -1;
+ xPortion->getPropertyValue(UNO_NAME_EDIT_CHAR_COLOR_THEME) >>= nCharColorTheme;
+ if (nCharColorTheme < 0 || nCharColorTheme > 11)
+ {
+ return;
+ }
+
+ Color aColor = rColorSet.getColor(nCharColorTheme);
+ sal_Int32 nCharColorLumMod{};
+ xPortion->getPropertyValue(UNO_NAME_EDIT_CHAR_COLOR_LUM_MOD) >>= nCharColorLumMod;
+ sal_Int32 nCharColorLumOff{};
+ xPortion->getPropertyValue(UNO_NAME_EDIT_CHAR_COLOR_LUM_OFF) >>= nCharColorLumOff;
+ if (nCharColorLumMod != 10000 || nCharColorLumOff != 0)
+ {
+ aColor.ApplyLumModOff(nCharColorLumMod, nCharColorLumOff);
+ }
+
+ sal_Int32 nCharColorTintOrShade{};
+ xPortion->getPropertyValue(UNO_NAME_EDIT_CHAR_COLOR_TINT_OR_SHADE) >>= nCharColorTintOrShade;
+ if (nCharColorTintOrShade != 0)
+ {
+ aColor.ApplyTintOrShade(nCharColorTintOrShade);
+ }
+
+ xPortion->setPropertyValue(UNO_NAME_EDIT_CHAR_COLOR,
+ uno::Any(static_cast<sal_Int32>(aColor)));
+}
+
+void UpdateFillColorSet(const uno::Reference<beans::XPropertySet>& xShape, const svx::ColorSet& rColorSet)
+{
+ if (!xShape->getPropertySetInfo()->hasPropertyByName(UNO_NAME_FILLCOLOR_THEME))
+ {
+ return;
+ }
+
+ sal_Int16 nFillColorTheme = -1;
+ xShape->getPropertyValue(UNO_NAME_FILLCOLOR_THEME) >>= nFillColorTheme;
+ if (nFillColorTheme < 0 || nFillColorTheme > 11)
+ {
+ return;
+ }
+
+ Color aColor = rColorSet.getColor(nFillColorTheme);
+ sal_Int32 nFillColorLumMod{};
+ xShape->getPropertyValue(UNO_NAME_FILLCOLOR_LUM_MOD) >>= nFillColorLumMod;
+ sal_Int32 nFillColorLumOff{};
+ xShape->getPropertyValue(UNO_NAME_FILLCOLOR_LUM_OFF) >>= nFillColorLumOff;
+ if (nFillColorLumMod != 10000 || nFillColorLumOff != 0)
+ {
+ aColor.ApplyLumModOff(nFillColorLumMod, nFillColorLumOff);
+ }
+
+ xShape->setPropertyValue(UNO_NAME_FILLCOLOR, uno::Any(static_cast<sal_Int32>(aColor)));
+}
+
+void UpdateSdrObject(svx::Theme* pTheme, SdrObject* pObject)
+{
+ svx::ColorSet* pColorSet = pTheme->GetColorSet();
+ if (!pColorSet)
+ {
+ return;
+ }
+
+ uno::Reference<drawing::XShape> xShape = pObject->getUnoShape();
+ uno::Reference<text::XTextRange> xShapeText(xShape, uno::UNO_QUERY);
+ if (xShapeText.is())
+ {
+ // E.g. group shapes have no text.
+ uno::Reference<container::XEnumerationAccess> xText(xShapeText->getText(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParagraphs = xText->createEnumeration();
+ while (xParagraphs->hasMoreElements())
+ {
+ uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration();
+ while (xPortions->hasMoreElements())
+ {
+ uno::Reference<beans::XPropertySet> xPortion(xPortions->nextElement(), uno::UNO_QUERY);
+ UpdateTextPortionColorSet(xPortion, *pColorSet);
+ }
+ }
+ }
+
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ UpdateFillColorSet(xShapeProps, *pColorSet);
+}
+}
+
+namespace svx
+{
+
+ColorSet::ColorSet(OUString const & aColorSetName)
+ : maColorSetName(aColorSetName)
+ , maColors(12)
+{}
+
+ColorSets::ColorSets()
+{}
+
+void ColorSet::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ColorSet"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("maColorSetName"),
+ BAD_CAST(maColorSetName.toUtf8().getStr()));
+
+ for (const auto& rColor : maColors)
+ {
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("Color"));
+ std::stringstream ss;
+ ss << rColor;
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(ss.str().c_str()));
+ (void)xmlTextWriterEndElement(pWriter);
+ }
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+ColorSets::~ColorSets()
+{}
+
+void ColorSets::init()
+{
+ {
+ ColorSet aColorSet("Breeze");
+ aColorSet.add(0, 0xFCFCFC);
+ aColorSet.add(1, 0x232629);
+ aColorSet.add(2, 0xEFF0F1);
+ aColorSet.add(3, 0x31363B);
+ aColorSet.add(4, 0xDA4453);
+ aColorSet.add(5, 0xF47750);
+ aColorSet.add(6, 0xFDBC4B);
+ aColorSet.add(7, 0xC9CE3B);
+ aColorSet.add(8, 0x1CDC9A);
+ aColorSet.add(9, 0x2ECC71);
+ aColorSet.add(10, 0x1D99F3);
+ aColorSet.add(11, 0x3DAEE9);
+ maColorSets.push_back(aColorSet);
+ }
+ {
+ ColorSet aColorSet("Material Blue");
+ aColorSet.add(0, 0xFFFFFF);
+ aColorSet.add(1, 0x212121);
+ aColorSet.add(2, 0xECEFF1);
+ aColorSet.add(3, 0x37474F);
+ aColorSet.add(4, 0x7986CB);
+ aColorSet.add(5, 0x303F9F);
+ aColorSet.add(6, 0x64B5F6);
+ aColorSet.add(7, 0x1976D2);
+ aColorSet.add(8, 0x4FC3F7);
+ aColorSet.add(9, 0x0277BD);
+ aColorSet.add(10, 0x4DD0E1);
+ aColorSet.add(11, 0x0097A7);
+ maColorSets.push_back(aColorSet);
+ }
+ {
+ ColorSet aColorSet("Material Red");
+ aColorSet.add(0, 0xFFFFFF);
+ aColorSet.add(1, 0x212121);
+ aColorSet.add(2, 0xF5F5F5);
+ aColorSet.add(3, 0x424242);
+ aColorSet.add(4, 0xFF9800);
+ aColorSet.add(5, 0xFF6D00);
+ aColorSet.add(6, 0xFF5722);
+ aColorSet.add(7, 0xDD2C00);
+ aColorSet.add(8, 0xF44336);
+ aColorSet.add(9, 0xD50000);
+ aColorSet.add(10, 0xE91E63);
+ aColorSet.add(11, 0xC51162);
+ maColorSets.push_back(aColorSet);
+ }
+ {
+ ColorSet aColorSet("Material Green");
+ aColorSet.add(0, 0xFFFFFF);
+ aColorSet.add(1, 0x212121);
+ aColorSet.add(2, 0xF5F5F5);
+ aColorSet.add(3, 0x424242);
+ aColorSet.add(4, 0x009688);
+ aColorSet.add(5, 0x00bfa5);
+ aColorSet.add(6, 0x4caf50);
+ aColorSet.add(7, 0x00c853);
+ aColorSet.add(8, 0x8bc34a);
+ aColorSet.add(9, 0x64dd17);
+ aColorSet.add(10, 0xcddc39);
+ aColorSet.add(11, 0xaeea00);
+ maColorSets.push_back(aColorSet);
+ }
+}
+
+const ColorSet& ColorSets::getColorSet(std::u16string_view rName)
+{
+ for (const ColorSet & rColorSet : maColorSets)
+ {
+ if (rColorSet.getName() == rName)
+ return rColorSet;
+ }
+ return maColorSets[0];
+}
+
+Theme::Theme(const OUString& rName)
+ : maName(rName)
+{
+}
+
+Theme::~Theme() {}
+
+void Theme::SetColorSet(std::unique_ptr<ColorSet> pColorSet) { mpColorSet = std::move(pColorSet); }
+
+ColorSet* Theme::GetColorSet() { return mpColorSet.get(); }
+
+void Theme::SetName(const OUString& rName) { maName = rName; }
+
+const OUString& Theme::GetName() const { return maName; }
+
+void Theme::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("Theme"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("maName"),
+ BAD_CAST(maName.toUtf8().getStr()));
+
+ if (mpColorSet)
+ {
+ mpColorSet->dumpAsXml(pWriter);
+ }
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+void Theme::ToAny(css::uno::Any& rVal) const
+{
+ comphelper::SequenceAsHashMap aMap;
+ aMap["Name"] <<= maName;
+
+ if (mpColorSet)
+ {
+ std::vector<util::Color> aColorScheme;
+ for (size_t i = 0; i < 12; ++i)
+ {
+ aColorScheme.push_back(static_cast<sal_Int32>(mpColorSet->getColor(i)));
+ }
+
+ aMap["ColorSchemeName"] <<= mpColorSet->getName();
+ aMap["ColorScheme"] <<= comphelper::containerToSequence(aColorScheme);
+ }
+
+ rVal <<= aMap.getAsConstPropertyValueList();
+}
+
+std::unique_ptr<Theme> Theme::FromAny(const css::uno::Any& rVal)
+{
+ comphelper::SequenceAsHashMap aMap(rVal);
+ std::unique_ptr<Theme> pTheme;
+ ColorSet* pColorSet = nullptr;
+
+ auto it = aMap.find("Name");
+ if (it != aMap.end())
+ {
+ OUString aName;
+ it->second >>= aName;
+ pTheme = std::make_unique<Theme>(aName);
+ }
+
+ it = aMap.find("ColorSchemeName");
+ if (it != aMap.end() && pTheme)
+ {
+ OUString aName;
+ it->second >>= aName;
+ auto pSet = std::make_unique<ColorSet>(aName);
+ pTheme->SetColorSet(std::move(pSet));
+ pColorSet = pTheme->GetColorSet();
+ }
+
+ it = aMap.find("ColorScheme");
+ if (it != aMap.end() && pColorSet)
+ {
+ uno::Sequence<util::Color> aColors;
+ it->second >>= aColors;
+ for (size_t i = 0; i < aColors.size(); ++i)
+ {
+ if (i >= 12)
+ {
+ SAL_WARN("svx", "Theme::FromAny: too many colors in the color set");
+ break;
+ }
+
+ pColorSet->add(i, Color(ColorTransparency, aColors[i]));
+ }
+ }
+
+ return pTheme;
+}
+
+void Theme::UpdateSdrPage(const SdrPage* pPage)
+{
+ for (size_t nObject = 0; nObject < pPage->GetObjCount(); ++nObject)
+ {
+ SdrObject* pObject = pPage->GetObj(nObject);
+ UpdateSdrObject(this, pObject);
+ SdrObjList* pList = pObject->GetSubList();
+ if (pList)
+ {
+ SdrObjListIter aIter(pList, SdrIterMode::DeepWithGroups);
+ while (aIter.IsMore())
+ {
+ UpdateSdrObject(this, aIter.Next());
+ }
+ }
+ }
+}
+
+std::vector<Color> Theme::GetColors() const
+{
+ if (!mpColorSet)
+ {
+ return {};
+ }
+
+ std::vector<Color> aColors;
+ for (size_t i = 0; i < 12; ++i)
+ {
+ aColors.push_back(mpColorSet->getColor(i));
+ }
+ return aColors;
+}
+
+Color Theme::GetColor(ThemeColorType eType) const
+{
+ if (!mpColorSet)
+ {
+ return {};
+ }
+
+ return mpColorSet->getColor(static_cast<size_t>(eType));
+}
+
+} // end of namespace svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/styles/CommonStyleManager.cxx b/svx/source/styles/CommonStyleManager.cxx
new file mode 100644
index 000000000..7a4279716
--- /dev/null
+++ b/svx/source/styles/CommonStyleManager.cxx
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <svx/CommonStyleManager.hxx>
+#include <CommonStylePreviewRenderer.hxx>
+
+namespace svx
+{
+
+std::unique_ptr<sfx2::StylePreviewRenderer> CommonStyleManager::CreateStylePreviewRenderer(
+ OutputDevice& rOutputDev, SfxStyleSheetBase* pStyle,
+ tools::Long nMaxHeight)
+{
+ return std::unique_ptr<sfx2::StylePreviewRenderer>(new CommonStylePreviewRenderer(mrShell, rOutputDev, pStyle, nMaxHeight));
+}
+
+} // end svx namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/styles/CommonStylePreviewRenderer.cxx b/svx/source/styles/CommonStylePreviewRenderer.cxx
new file mode 100644
index 000000000..df0e3539e
--- /dev/null
+++ b/svx/source/styles/CommonStylePreviewRenderer.cxx
@@ -0,0 +1,233 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <memory>
+#include <CommonStylePreviewRenderer.hxx>
+
+#include <sfx2/objsh.hxx>
+#include <svl/style.hxx>
+#include <svl/itemset.hxx>
+#include <vcl/outdev.hxx>
+
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/svxfont.hxx>
+#include <editeng/cmapitem.hxx>
+
+#include <editeng/editids.hrc>
+
+using namespace css;
+
+namespace svx
+{
+
+CommonStylePreviewRenderer::CommonStylePreviewRenderer(
+ const SfxObjectShell& rShell, OutputDevice& rOutputDev,
+ SfxStyleSheetBase* pStyle, tools::Long nMaxHeight)
+ : StylePreviewRenderer(rShell, rOutputDev, pStyle, nMaxHeight)
+ , maFontColor(COL_AUTO)
+ , maHighlightColor(COL_AUTO)
+ , maBackgroundColor(COL_AUTO)
+ , maStyleName(mpStyle->GetName())
+{
+}
+
+CommonStylePreviewRenderer::~CommonStylePreviewRenderer()
+{}
+
+bool CommonStylePreviewRenderer::recalculate()
+{
+ m_oFont.reset();
+
+ std::optional<SfxItemSet> pItemSet(mpStyle->GetItemSetForPreview());
+
+ if (!pItemSet) return false;
+
+ SvxFont aFont;
+
+ const SfxPoolItem* pItem;
+
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_WEIGHT)) != nullptr)
+ {
+ aFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight());
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_POSTURE)) != nullptr)
+ {
+ aFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture());
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CONTOUR)) != nullptr)
+ {
+ aFont.SetOutline(static_cast< const SvxContourItem*>(pItem)->GetValue());
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_SHADOWED)) != nullptr)
+ {
+ aFont.SetShadow(static_cast<const SvxShadowedItem*>(pItem)->GetValue());
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_RELIEF)) != nullptr)
+ {
+ aFont.SetRelief(static_cast<const SvxCharReliefItem*>(pItem)->GetValue());
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_UNDERLINE)) != nullptr)
+ {
+ aFont.SetUnderline(static_cast< const SvxUnderlineItem*>(pItem)->GetLineStyle());
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_OVERLINE)) != nullptr)
+ {
+ aFont.SetOverline(static_cast<const SvxOverlineItem*>(pItem)->GetValue());
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_STRIKEOUT)) != nullptr)
+ {
+ aFont.SetStrikeout(static_cast<const SvxCrossedOutItem*>(pItem)->GetStrikeout());
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CASEMAP)) != nullptr)
+ {
+ aFont.SetCaseMap(static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap());
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_EMPHASISMARK)) != nullptr)
+ {
+ aFont.SetEmphasisMark(static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark());
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_COLOR)) != nullptr)
+ {
+ maFontColor = static_cast<const SvxColorItem*>(pItem)->GetValue();
+ }
+ if ((pItem = pItemSet->GetItem(SID_ATTR_BRUSH_CHAR)) != nullptr)
+ {
+ maHighlightColor = static_cast<const SvxBrushItem*>(pItem)->GetColor();
+ }
+
+ if (mpStyle->GetFamily() == SfxStyleFamily::Para)
+ {
+ if ((pItem = pItemSet->GetItem(XATTR_FILLSTYLE)) != nullptr)
+ {
+ css::drawing::FillStyle aFillStyle = static_cast<const XFillStyleItem*>(pItem)->GetValue();
+ if (aFillStyle == drawing::FillStyle_SOLID)
+ {
+ if ((pItem = pItemSet->GetItem(XATTR_FILLCOLOR)) != nullptr)
+ {
+ maBackgroundColor = static_cast<const XFillColorItem*>(pItem)->GetColorValue();
+ }
+ }
+ }
+ }
+
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_FONT)) != nullptr)
+ {
+ const SvxFontItem* pFontItem = static_cast<const SvxFontItem*>(pItem);
+ if (IsStarSymbol(pFontItem->GetFamilyName()))
+ return false;
+ aFont.SetFamilyName(pFontItem->GetFamilyName());
+ aFont.SetStyleName(pFontItem->GetStyleName());
+ }
+ else
+ {
+ return false;
+ }
+
+ if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_FONTHEIGHT)) != nullptr)
+ {
+ const SvxFontHeightItem* pFontHeightItem = static_cast<const SvxFontHeightItem*>(pItem);
+ Size aFontSize(0, pFontHeightItem->GetHeight());
+ maPixelSize = mrOutputDev.LogicToPixel(aFontSize, MapMode(mrShell.GetMapUnit()));
+ aFont.SetFontSize(maPixelSize);
+
+ vcl::Font aOldFont(mrOutputDev.GetFont());
+
+ mrOutputDev.SetFont(aFont);
+ tools::Rectangle aTextRect;
+ mrOutputDev.GetTextBoundRect(aTextRect, mpStyle->GetName());
+ if (aTextRect.Bottom() > mnMaxHeight)
+ {
+ double ratio = double(mnMaxHeight) / aTextRect.Bottom();
+ maPixelSize.setWidth( maPixelSize.Width() * ratio );
+ maPixelSize.setHeight( maPixelSize.Height() * ratio );
+ aFont.SetFontSize(maPixelSize);
+ }
+ mrOutputDev.SetFont(aOldFont);
+ }
+ else
+ {
+ return false;
+ }
+
+ m_oFont = aFont;
+ maPixelSize = getRenderSize();
+ return true;
+}
+
+Size CommonStylePreviewRenderer::getRenderSize() const
+{
+ assert(m_oFont);
+ Size aPixelSize = m_oFont->GetTextSize(mrOutputDev, maStyleName);
+
+ if (aPixelSize.Height() > mnMaxHeight)
+ aPixelSize.setHeight( mnMaxHeight );
+
+ return aPixelSize;
+}
+
+bool CommonStylePreviewRenderer::render(const tools::Rectangle& aRectangle, RenderAlign eRenderAlign)
+{
+ const OUString& rText = maStyleName;
+
+ // setup the device & draw
+ mrOutputDev.Push(vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR | vcl::PushFlags::FILLCOLOR | vcl::PushFlags::TEXTFILLCOLOR);
+
+ if (maBackgroundColor != COL_AUTO)
+ {
+ mrOutputDev.SetFillColor(maBackgroundColor);
+ mrOutputDev.DrawRect(aRectangle);
+ }
+
+ if (m_oFont)
+ mrOutputDev.SetFont(*m_oFont);
+
+ if (maFontColor != COL_AUTO)
+ mrOutputDev.SetTextColor(maFontColor);
+
+ if (maHighlightColor != COL_AUTO)
+ mrOutputDev.SetTextFillColor(maHighlightColor);
+
+ Size aPixelSize(m_oFont ? maPixelSize : mrOutputDev.GetFont().GetFontSize());
+
+ Point aFontDrawPosition = aRectangle.TopLeft();
+ if (eRenderAlign == RenderAlign::CENTER)
+ {
+ if (aRectangle.GetHeight() > aPixelSize.Height())
+ aFontDrawPosition.AdjustY((aRectangle.GetHeight() - aPixelSize.Height()) / 2 );
+ }
+
+ if (m_oFont)
+ m_oFont->QuickDrawText( &mrOutputDev, aFontDrawPosition, rText, 0, rText.getLength(), {} );
+ else
+ mrOutputDev.DrawText(aFontDrawPosition, rText);
+
+ mrOutputDev.Pop();
+
+ return true;
+}
+
+} // end svx namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/ActionDescriptionProvider.cxx b/svx/source/svdraw/ActionDescriptionProvider.cxx
new file mode 100644
index 000000000..0dc5e895c
--- /dev/null
+++ b/svx/source/svdraw/ActionDescriptionProvider.cxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/ActionDescriptionProvider.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+OUString ActionDescriptionProvider::createDescription( ActionType eActionType
+ , std::u16string_view rObjectName )
+{
+ TranslateId pResID;
+ switch( eActionType )
+ {
+ case ActionType::Insert:
+ pResID=STR_UndoInsertObj;
+ break;
+ case ActionType::Delete:
+ pResID= STR_EditDelete;
+ break;
+ case ActionType::Move:
+ pResID= STR_EditMove;
+ break;
+ case ActionType::Resize:
+ pResID= STR_EditResize;
+ break;
+ case ActionType::Rotate:
+ pResID= STR_EditRotate;
+ break;
+ case ActionType::Format:
+ pResID= STR_EditSetAttributes;
+ break;
+ case ActionType::MoveToTop:
+ pResID= STR_EditMovToTop;
+ break;
+ case ActionType::MoveToBottom:
+ pResID= STR_EditMovToBtm;
+ break;
+ case ActionType::PosSize:
+ pResID = STR_EditPosSize;
+ break;
+ }
+ if (!pResID)
+ return OUString();
+
+ OUString aStr(SvxResId(pResID));
+ return aStr.replaceAll("%1", rObjectName);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/MediaShellHelpers.cxx b/svx/source/svdraw/MediaShellHelpers.cxx
new file mode 100644
index 000000000..8cf760a7b
--- /dev/null
+++ b/svx/source/svdraw/MediaShellHelpers.cxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+#include <svx/MediaShellHelpers.hxx>
+#include <avmedia/mediaitem.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svl/whiter.hxx>
+#include <svx/sdr/contact/viewcontactofsdrmediaobj.hxx>
+#include <svx/svdmrkv.hxx>
+
+namespace svx::MediaShellHelpers
+{
+void GetState(const SdrMarkView* pSdrView, SfxItemSet& rSet)
+{
+ if (!pSdrView)
+ return;
+
+ SfxWhichIter aIter(rSet);
+
+ for (sal_uInt16 nWhich = aIter.FirstWhich(); nWhich; nWhich = aIter.NextWhich())
+ {
+ if (SID_AVMEDIA_TOOLBOX != nWhich)
+ continue;
+
+#if HAVE_FEATURE_AVMEDIA
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ bool bDisable = true;
+
+ if (1 == rMarkList.GetMarkCount())
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ if (dynamic_cast<SdrMediaObj*>(pObj))
+ {
+ ::avmedia::MediaItem aItem(SID_AVMEDIA_TOOLBOX);
+
+ static_cast<sdr::contact::ViewContactOfSdrMediaObj&>(pObj->GetViewContact())
+ .updateMediaItem(aItem);
+ rSet.Put(aItem);
+ bDisable = false;
+ }
+ }
+
+ if (bDisable)
+#endif
+ rSet.DisableItem(SID_AVMEDIA_TOOLBOX);
+ }
+}
+
+const ::avmedia::MediaItem* Execute(const SdrMarkView* pSdrView, SfxRequest const& rReq)
+{
+#if !HAVE_FEATURE_AVMEDIA
+ (void)pSdrView;
+ (void)rReq;
+ return nullptr;
+#else
+ if (!pSdrView)
+ return nullptr;
+
+ if (SID_AVMEDIA_TOOLBOX != rReq.GetSlot())
+ return nullptr;
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if (!pArgs)
+ return nullptr;
+
+ const ::avmedia::MediaItem* pMediaItem = pArgs->GetItemIfSet(SID_AVMEDIA_TOOLBOX, false);
+ if (!pMediaItem)
+ return nullptr;
+
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+
+ if (1 != rMarkList.GetMarkCount())
+ return nullptr;
+
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ if (!dynamic_cast<SdrMediaObj*>(pObj))
+ return nullptr;
+
+ static_cast<sdr::contact::ViewContactOfSdrMediaObj&>(pObj->GetViewContact())
+ .executeMediaItem(*pMediaItem);
+
+ return pMediaItem;
+#endif
+}
+
+} // end of namespace svx::MediaShellHelpers
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/charthelper.cxx b/svx/source/svdraw/charthelper.cxx
new file mode 100644
index 000000000..cae747228
--- /dev/null
+++ b/svx/source/svdraw/charthelper.cxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/charthelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/util/XUpdatable2.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <sdr/primitive2d/primitivefactory2d.hxx>
+
+using namespace ::com::sun::star;
+
+void ChartHelper::updateChart( const uno::Reference< ::frame::XModel >& rXModel )
+{
+ if (!rXModel.is())
+ return;
+
+ try
+ {
+ const uno::Reference< lang::XMultiServiceFactory > xChartFact(rXModel, uno::UNO_QUERY_THROW);
+ const uno::Reference< lang::XUnoTunnel > xChartView(xChartFact->createInstance("com.sun.star.chart2.ChartView"), uno::UNO_QUERY_THROW);
+ const uno::Reference<util::XUpdatable2> xUpdatable(xChartView, uno::UNO_QUERY_THROW);
+
+ xUpdatable->updateHard();
+ }
+ catch(uno::Exception&)
+ {
+ OSL_ENSURE(false, "Unexpected exception!");
+ }
+}
+
+drawinglayer::primitive2d::Primitive2DContainer ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
+ const uno::Reference< ::frame::XModel >& rXModel,
+ basegfx::B2DRange& rRange)
+{
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if (!rXModel.is())
+ return aRetval;
+
+ // don't broadcast until we're finished building, more efficient
+ rXModel->lockControllers();
+ updateChart(rXModel);
+ rXModel->unlockControllers();
+
+ try
+ {
+ const uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier(rXModel, uno::UNO_QUERY_THROW);
+ const uno::Reference< container::XIndexAccess > xShapeAccess(xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW);
+
+ if(xShapeAccess->getCount())
+ {
+ const sal_Int32 nShapeCount(xShapeAccess->getCount());
+ const uno::Sequence< beans::PropertyValue > aParams;
+ uno::Reference< drawing::XShape > xShape;
+
+ for(sal_Int32 a(0); a < nShapeCount; a++)
+ {
+ xShapeAccess->getByIndex(a) >>= xShape;
+
+ if(xShape.is())
+ {
+ PrimitiveFactory2D::createPrimitivesFromXShape(
+ xShape,
+ aParams,
+ aRetval);
+ }
+ }
+ }
+ }
+ catch(uno::Exception&)
+ {
+ OSL_ENSURE(false, "Unexpected exception!");
+ }
+
+ if(!aRetval.empty())
+ {
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+
+ rRange = aRetval.getB2DRange(aViewInformation2D);
+ }
+
+ return aRetval;
+}
+
+void ChartHelper::AdaptDefaultsForChart(
+ const uno::Reference < embed::XEmbeddedObject > & xEmbObj)
+{
+ if( !xEmbObj.is())
+ return;
+
+ uno::Reference< chart2::XChartDocument > xChartDoc( xEmbObj->getComponent(), uno::UNO_QUERY );
+ OSL_ENSURE( xChartDoc.is(), "Trying to set chart property to non-chart OLE" );
+ if( !xChartDoc.is())
+ return;
+
+ try
+ {
+ if (uno::Reference< beans::XPropertySet > xPageProp = xChartDoc->getPageBackground())
+ {
+ // set background to transparent (none)
+ xPageProp->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_NONE));
+ // set no border
+ xPageProp->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_NONE));
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION("svx.svdraw", "");
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/clonelist.cxx b/svx/source/svdraw/clonelist.cxx
new file mode 100644
index 000000000..12f395ac1
--- /dev/null
+++ b/svx/source/svdraw/clonelist.cxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+// #i13033#
+// New mechanism to hold a list of all original and cloned objects for later
+// re-creating the connections for contained connectors
+#include <clonelist.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/scene3d.hxx>
+
+void CloneList::AddPair(const SdrObject* pOriginal, SdrObject* pClone)
+{
+ maOriginalList.push_back(pOriginal);
+ maCloneList.push_back(pClone);
+
+ // look for subobjects, too.
+ bool bOriginalIsGroup(pOriginal->IsGroupObject());
+ bool bCloneIsGroup(pClone->IsGroupObject());
+
+ if(bOriginalIsGroup && dynamic_cast<const E3dObject* >(pOriginal) != nullptr && dynamic_cast<const E3dScene* >(pOriginal) == nullptr )
+ bOriginalIsGroup = false;
+
+ if(bCloneIsGroup && dynamic_cast<const E3dObject* >(pClone) != nullptr && dynamic_cast<const E3dScene* >(pClone) == nullptr)
+ bCloneIsGroup = false;
+
+ if(!(bOriginalIsGroup && bCloneIsGroup))
+ return;
+
+ const SdrObjList* pOriginalList = pOriginal->GetSubList();
+ SdrObjList* pCloneList = pClone->GetSubList();
+
+ if(pOriginalList && pCloneList
+ && pOriginalList->GetObjCount() == pCloneList->GetObjCount())
+ {
+ for(size_t a = 0; a < pOriginalList->GetObjCount(); ++a)
+ {
+ // recursive call
+ AddPair(pOriginalList->GetObj(a), pCloneList->GetObj(a));
+ }
+ }
+}
+
+const SdrObject* CloneList::GetOriginal(sal_uInt32 nIndex) const
+{
+ return maOriginalList[nIndex];
+}
+
+SdrObject* CloneList::GetClone(sal_uInt32 nIndex) const
+{
+ return maCloneList[nIndex];
+}
+
+void CloneList::CopyConnections() const
+{
+ sal_uInt32 cloneCount = maCloneList.size();
+
+ for(size_t a = 0; a < maOriginalList.size(); a++)
+ {
+ const SdrEdgeObj* pOriginalEdge = dynamic_cast<const SdrEdgeObj*>( GetOriginal(a) );
+ SdrEdgeObj* pCloneEdge = dynamic_cast<SdrEdgeObj*>( GetClone(a) );
+
+ if(pOriginalEdge && pCloneEdge)
+ {
+ SdrObject* pOriginalNode1 = pOriginalEdge->GetConnectedNode(true);
+ SdrObject* pOriginalNode2 = pOriginalEdge->GetConnectedNode(false);
+
+ if(pOriginalNode1)
+ {
+ std::vector<const SdrObject*>::const_iterator it = std::find(maOriginalList.begin(),
+ maOriginalList.end(),
+ pOriginalNode1);
+
+ sal_uInt32 nPos = it - maOriginalList.begin();
+
+ if(it != maOriginalList.end())
+ {
+ SdrObject *cObj = nullptr;
+
+ if (nPos < cloneCount)
+ cObj = GetClone(nPos);
+
+ if(pOriginalEdge->GetConnectedNode(true) != cObj)
+ pCloneEdge->ConnectToNode(true, cObj);
+ }
+ }
+
+ if(pOriginalNode2)
+ {
+ std::vector<const SdrObject*>::const_iterator it = std::find(maOriginalList.begin(),
+ maOriginalList.end(),
+ pOriginalNode2);
+
+ sal_uInt32 nPos = it - maOriginalList.begin();
+
+ if(it != maOriginalList.end())
+ {
+ SdrObject *cObj = nullptr;
+
+ if (nPos < cloneCount)
+ cObj = GetClone(nPos);
+
+ if(pOriginalEdge->GetConnectedNode(false) != cObj)
+ pCloneEdge->ConnectToNode(false, cObj);
+ }
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/gradtrns.cxx b/svx/source/svdraw/gradtrns.cxx
new file mode 100644
index 000000000..d665cd48c
--- /dev/null
+++ b/svx/source/svdraw/gradtrns.cxx
@@ -0,0 +1,527 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "gradtrns.hxx"
+#include <svx/svdobj.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <tools/helpers.hxx>
+#include <vcl/canvastools.hxx>
+
+
+void GradTransformer::GradToVec(GradTransGradient const & rG, GradTransVector& rV, const SdrObject* pObj)
+{
+ // handle start color
+ rV.aCol1 = rG.aGradient.GetStartColor();
+ if(100 != rG.aGradient.GetStartIntens())
+ {
+ const double fFact(static_cast<double>(rG.aGradient.GetStartIntens()) / 100.0);
+ rV.aCol1 = Color(rV.aCol1.getBColor() * fFact);
+ }
+
+ // handle end color
+ rV.aCol2 = rG.aGradient.GetEndColor();
+ if(100 != rG.aGradient.GetEndIntens())
+ {
+ const double fFact(static_cast<double>(rG.aGradient.GetEndIntens()) / 100.0);
+ rV.aCol2 = Color(rV.aCol2.getBColor() * fFact);
+ }
+
+ // calc the basic positions
+ const tools::Rectangle aObjectSnapRectangle(pObj->GetSnapRect());
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aObjectSnapRectangle);
+ const basegfx::B2DPoint aCenter(aRange.getCenter());
+ basegfx::B2DPoint aStartPos, aEndPos;
+
+ switch(rG.aGradient.GetGradientStyle())
+ {
+ case css::awt::GradientStyle_LINEAR :
+ {
+ aStartPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMinY());
+ aEndPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMaximum().getY());
+
+ if(rG.aGradient.GetBorder())
+ {
+ basegfx::B2DVector aFullVec(aStartPos - aEndPos);
+ const double fLen = (aFullVec.getLength() * (100.0 - static_cast<double>(rG.aGradient.GetBorder()))) / 100.0;
+ aFullVec.normalize();
+ aStartPos = aEndPos + (aFullVec * fLen);
+ }
+
+ if(rG.aGradient.GetAngle())
+ {
+ const double fAngle = toRadians(rG.aGradient.GetAngle());
+ const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aCenter, -fAngle));
+
+ aStartPos *= aTransformation;
+ aEndPos *= aTransformation;
+ }
+ break;
+ }
+ case css::awt::GradientStyle_AXIAL :
+ {
+ aStartPos = aCenter;
+ aEndPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMaximum().getY());
+
+ if(rG.aGradient.GetBorder())
+ {
+ basegfx::B2DVector aFullVec(aEndPos - aStartPos);
+ const double fLen = (aFullVec.getLength() * (100.0 - static_cast<double>(rG.aGradient.GetBorder()))) / 100.0;
+ aFullVec.normalize();
+ aEndPos = aStartPos + (aFullVec * fLen);
+ }
+
+ if(rG.aGradient.GetAngle())
+ {
+ const double fAngle = toRadians(rG.aGradient.GetAngle());
+ const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aCenter, -fAngle));
+
+ aStartPos *= aTransformation;
+ aEndPos *= aTransformation;
+ }
+ break;
+ }
+ case css::awt::GradientStyle_RADIAL :
+ case css::awt::GradientStyle_SQUARE :
+ {
+ aStartPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMaximum().getY());
+ aEndPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY());
+
+ if(rG.aGradient.GetBorder())
+ {
+ basegfx::B2DVector aFullVec(aStartPos - aEndPos);
+ const double fLen = (aFullVec.getLength() * (100.0 - static_cast<double>(rG.aGradient.GetBorder()))) / 100.0;
+ aFullVec.normalize();
+ aStartPos = aEndPos + (aFullVec * fLen);
+ }
+
+ if(rG.aGradient.GetAngle())
+ {
+ const double fAngle = toRadians(rG.aGradient.GetAngle());
+ const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aEndPos, -fAngle));
+
+ aStartPos *= aTransformation;
+ aEndPos *= aTransformation;
+ }
+
+ if(rG.aGradient.GetXOffset() || rG.aGradient.GetYOffset())
+ {
+ basegfx::B2DPoint aOffset(
+ (aRange.getWidth() * rG.aGradient.GetXOffset()) / 100.0,
+ (aRange.getHeight() * rG.aGradient.GetYOffset()) / 100.0);
+
+ aStartPos += aOffset;
+ aEndPos += aOffset;
+ }
+
+ break;
+ }
+ case css::awt::GradientStyle_ELLIPTICAL :
+ case css::awt::GradientStyle_RECT :
+ {
+ aStartPos = basegfx::B2DPoint(aRange.getMinX(), aCenter.getY());
+ aEndPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY());
+
+ if(rG.aGradient.GetBorder())
+ {
+ basegfx::B2DVector aFullVec(aStartPos - aEndPos);
+ const double fLen = (aFullVec.getLength() * (100.0 - static_cast<double>(rG.aGradient.GetBorder()))) / 100.0;
+ aFullVec.normalize();
+ aStartPos = aEndPos + (aFullVec * fLen);
+ }
+
+ if(rG.aGradient.GetAngle())
+ {
+ const double fAngle = toRadians(rG.aGradient.GetAngle());
+ const basegfx::B2DHomMatrix aTransformation(basegfx::utils::createRotateAroundPoint(aEndPos, -fAngle));
+
+ aStartPos *= aTransformation;
+ aEndPos *= aTransformation;
+ }
+
+ if(rG.aGradient.GetXOffset() || rG.aGradient.GetYOffset())
+ {
+ basegfx::B2DPoint aOffset(
+ (aRange.getWidth() * rG.aGradient.GetXOffset()) / 100.0,
+ (aRange.getHeight() * rG.aGradient.GetYOffset()) / 100.0);
+
+ aStartPos += aOffset;
+ aEndPos += aOffset;
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ // set values for vector positions now
+ rV.maPositionA = aStartPos;
+ rV.maPositionB = aEndPos;
+}
+
+
+void GradTransformer::VecToGrad(GradTransVector const & rV, GradTransGradient& rG, GradTransGradient const & rGOld, const SdrObject* pObj,
+ bool bMoveSingle, bool bMoveFirst)
+{
+ // fill old gradient to new gradient to have a base
+ rG = rGOld;
+
+ // handle color changes
+ if(rV.aCol1 != rGOld.aGradient.GetStartColor())
+ {
+ rG.aGradient.SetStartColor(rV.aCol1);
+ rG.aGradient.SetStartIntens(100);
+ }
+ if(rV.aCol2 != rGOld.aGradient.GetEndColor())
+ {
+ rG.aGradient.SetEndColor(rV.aCol2);
+ rG.aGradient.SetEndIntens(100);
+ }
+
+ // calc the basic positions
+ const tools::Rectangle aObjectSnapRectangle(pObj->GetSnapRect());
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aObjectSnapRectangle);
+ const basegfx::B2DPoint aCenter(aRange.getCenter());
+ basegfx::B2DPoint aStartPos(rV.maPositionA);
+ basegfx::B2DPoint aEndPos(rV.maPositionB);
+
+ switch(rG.aGradient.GetGradientStyle())
+ {
+ case css::awt::GradientStyle_LINEAR :
+ {
+ if(!bMoveSingle || !bMoveFirst)
+ {
+ basegfx::B2DVector aFullVec(aEndPos - aStartPos);
+
+ if(bMoveSingle)
+ {
+ aFullVec = aEndPos - aCenter;
+ }
+
+ aFullVec.normalize();
+
+ double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec.getY(), aFullVec.getX())));
+ fNewFullAngle *= -10.0;
+ fNewFullAngle += 900.0;
+
+ // clip
+ while(fNewFullAngle < 0.0)
+ {
+ fNewFullAngle += 3600.0;
+ }
+
+ while(fNewFullAngle >= 3600.0)
+ {
+ fNewFullAngle -= 3600.0;
+ }
+
+ // to int and set
+ Degree10 nNewAngle( FRound(fNewFullAngle));
+
+ if(nNewAngle != rGOld.aGradient.GetAngle())
+ {
+ rG.aGradient.SetAngle(nNewAngle);
+ }
+ }
+
+ if(!bMoveSingle || bMoveFirst)
+ {
+ const basegfx::B2DVector aFullVec(aEndPos - aStartPos);
+ const basegfx::B2DPoint aBottomLeft(aRange.getMinX(), aRange.getMaximum().getY());
+ const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
+ const basegfx::B2DVector aOldVec(aBottomLeft - aTopLeft);
+ const double fFullLen(aFullVec.getLength());
+ const double fOldLen(aOldVec.getLength());
+ const double fNewBorder((fFullLen * 100.0) / fOldLen);
+ sal_Int32 nNewBorder(100 - FRound(fNewBorder));
+
+ // clip
+ if(nNewBorder < 0)
+ {
+ nNewBorder = 0;
+ }
+
+ if(nNewBorder > 100)
+ {
+ nNewBorder = 100;
+ }
+
+ // set
+ if(nNewBorder != rG.aGradient.GetBorder())
+ {
+ rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
+ }
+ }
+
+ break;
+ }
+ case css::awt::GradientStyle_AXIAL :
+ {
+ if(!bMoveSingle || !bMoveFirst)
+ {
+ basegfx::B2DVector aFullVec(aEndPos - aCenter);
+ const basegfx::B2DVector aOldVec(basegfx::B2DPoint(aCenter.getX(), aRange.getMaximum().getY()) - aCenter);
+ const double fFullLen(aFullVec.getLength());
+ const double fOldLen(aOldVec.getLength());
+ const double fNewBorder((fFullLen * 100.0) / fOldLen);
+ sal_Int32 nNewBorder = 100 - FRound(fNewBorder);
+
+ // clip
+ if(nNewBorder < 0)
+ {
+ nNewBorder = 0;
+ }
+
+ if(nNewBorder > 100)
+ {
+ nNewBorder = 100;
+ }
+
+ // set
+ if(nNewBorder != rG.aGradient.GetBorder())
+ {
+ rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
+ }
+
+ aFullVec.normalize();
+ double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec.getY(), aFullVec.getX())));
+ fNewFullAngle *= -10.0;
+ fNewFullAngle += 900.0;
+
+ // clip
+ while(fNewFullAngle < 0.0)
+ {
+ fNewFullAngle += 3600.0;
+ }
+
+ while(fNewFullAngle >= 3600.0)
+ {
+ fNewFullAngle -= 3600.0;
+ }
+
+ // to int and set
+ const Degree10 nNewAngle(FRound(fNewFullAngle));
+
+ if(nNewAngle != rGOld.aGradient.GetAngle())
+ {
+ rG.aGradient.SetAngle(nNewAngle);
+ }
+ }
+
+ break;
+ }
+ case css::awt::GradientStyle_RADIAL :
+ case css::awt::GradientStyle_SQUARE :
+ {
+ if(!bMoveSingle || !bMoveFirst)
+ {
+ const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
+ const basegfx::B2DPoint aOffset(aEndPos - aTopLeft);
+ sal_Int32 nNewXOffset(FRound((aOffset.getX() * 100.0) / aRange.getWidth()));
+ sal_Int32 nNewYOffset(FRound((aOffset.getY() * 100.0) / aRange.getHeight()));
+
+ // clip
+ if(nNewXOffset < 0)
+ {
+ nNewXOffset = 0;
+ }
+
+ if(nNewXOffset > 100)
+ {
+ nNewXOffset = 100;
+ }
+
+ if(nNewYOffset < 0)
+ {
+ nNewYOffset = 0;
+ }
+
+ if(nNewYOffset > 100)
+ {
+ nNewYOffset = 100;
+ }
+
+ rG.aGradient.SetXOffset(static_cast<sal_uInt16>(nNewXOffset));
+ rG.aGradient.SetYOffset(static_cast<sal_uInt16>(nNewYOffset));
+
+ aStartPos -= aOffset;
+ aEndPos -= aOffset;
+ }
+
+ if(!bMoveSingle || bMoveFirst)
+ {
+ basegfx::B2DVector aFullVec(aStartPos - aEndPos);
+ const basegfx::B2DPoint aBottomLeft(aRange.getMinX(), aRange.getMaximum().getY());
+ const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
+ const basegfx::B2DVector aOldVec(aBottomLeft - aTopLeft);
+ const double fFullLen(aFullVec.getLength());
+ const double fOldLen(aOldVec.getLength());
+ const double fNewBorder((fFullLen * 100.0) / fOldLen);
+ sal_Int32 nNewBorder(100 - FRound(fNewBorder));
+
+ // clip
+ if(nNewBorder < 0)
+ {
+ nNewBorder = 0;
+ }
+
+ if(nNewBorder > 100)
+ {
+ nNewBorder = 100;
+ }
+
+ // set
+ if(nNewBorder != rG.aGradient.GetBorder())
+ {
+ rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
+ }
+
+ // angle is not definitely necessary for these modes, but it makes
+ // controlling more fun for the user
+ aFullVec.normalize();
+ double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec.getY(), aFullVec.getX())));
+ fNewFullAngle *= -10.0;
+ fNewFullAngle += 900.0;
+
+ // clip
+ while(fNewFullAngle < 0.0)
+ {
+ fNewFullAngle += 3600.0;
+ }
+
+ while(fNewFullAngle >= 3600.0)
+ {
+ fNewFullAngle -= 3600.0;
+ }
+
+ // to int and set
+ const Degree10 nNewAngle(FRound(fNewFullAngle));
+
+ if(nNewAngle != rGOld.aGradient.GetAngle())
+ {
+ rG.aGradient.SetAngle(nNewAngle);
+ }
+ }
+
+ break;
+ }
+ case css::awt::GradientStyle_ELLIPTICAL :
+ case css::awt::GradientStyle_RECT :
+ {
+ if(!bMoveSingle || !bMoveFirst)
+ {
+ const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
+ const basegfx::B2DPoint aOffset(aEndPos - aTopLeft);
+ sal_Int32 nNewXOffset(FRound((aOffset.getX() * 100.0) / aRange.getWidth()));
+ sal_Int32 nNewYOffset(FRound((aOffset.getY() * 100.0) / aRange.getHeight()));
+
+ // clip
+ if(nNewXOffset < 0)
+ {
+ nNewXOffset = 0;
+ }
+
+ if(nNewXOffset > 100)
+ {
+ nNewXOffset = 100;
+ }
+
+ if(nNewYOffset < 0)
+ {
+ nNewYOffset = 0;
+ }
+
+ if(nNewYOffset > 100)
+ {
+ nNewYOffset = 100;
+ }
+
+ rG.aGradient.SetXOffset(static_cast<sal_uInt16>(nNewXOffset));
+ rG.aGradient.SetYOffset(static_cast<sal_uInt16>(nNewYOffset));
+
+ aStartPos -= aOffset;
+ aEndPos -= aOffset;
+ }
+
+ if(!bMoveSingle || bMoveFirst)
+ {
+ basegfx::B2DVector aFullVec(aStartPos - aEndPos);
+ const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
+ const basegfx::B2DPoint aCenterLeft(aRange.getMinX(), aCenter.getY());
+ const basegfx::B2DVector aOldVec(aCenterLeft - aTopLeft);
+ const double fFullLen(aFullVec.getLength());
+ const double fOldLen(aOldVec.getLength());
+ const double fNewBorder((fFullLen * 100.0) / fOldLen);
+ sal_Int32 nNewBorder(100 - FRound(fNewBorder));
+
+ // clip
+ if(nNewBorder < 0)
+ {
+ nNewBorder = 0;
+ }
+
+ if(nNewBorder > 100)
+ {
+ nNewBorder = 100;
+ }
+
+ // set
+ if(nNewBorder != rG.aGradient.GetBorder())
+ {
+ rG.aGradient.SetBorder(static_cast<sal_uInt16>(nNewBorder));
+ }
+
+ // angle is not definitely necessary for these modes, but it makes
+ // controlling more fun for the user
+ aFullVec.normalize();
+ double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec.getY(), aFullVec.getX())));
+ fNewFullAngle *= -10.0;
+ fNewFullAngle += 900.0;
+
+ // clip
+ while(fNewFullAngle < 0.0)
+ {
+ fNewFullAngle += 3600.0;
+ }
+
+ while(fNewFullAngle >= 3600.0)
+ {
+ fNewFullAngle -= 3600.0;
+ }
+
+ // to int and set
+ const Degree10 nNewAngle(FRound(fNewFullAngle));
+
+ if(nNewAngle != rGOld.aGradient.GetAngle())
+ {
+ rG.aGradient.SetAngle(nNewAngle);
+ }
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/gradtrns.hxx b/svx/source/svdraw/gradtrns.hxx
new file mode 100644
index 000000000..eee35582a
--- /dev/null
+++ b/svx/source/svdraw/gradtrns.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_SVDRAW_GRADTRNS_HXX
+#define INCLUDED_SVX_SOURCE_SVDRAW_GRADTRNS_HXX
+
+#include <svx/xgrad.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+
+class SdrObject;
+
+class GradTransVector
+{
+public:
+ basegfx::B2DPoint maPositionA;
+ basegfx::B2DPoint maPositionB;
+ Color aCol1;
+ Color aCol2;
+};
+
+class GradTransGradient
+{
+public:
+ XGradient aGradient;
+};
+
+struct GradTransformer
+{
+ GradTransformer() = delete;
+
+ static void GradToVec(GradTransGradient const & rG, GradTransVector& rV,
+ const SdrObject* pObj);
+ static void VecToGrad(GradTransVector const & rV, GradTransGradient& rG,
+ GradTransGradient const & rGOld, const SdrObject* pObj, bool bMoveSingle, bool bMoveFirst);
+};
+
+#endif // INCLUDED_SVX_SOURCE_SVDRAW_GRADTRNS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/polypolygoneditor.cxx b/svx/source/svdraw/polypolygoneditor.cxx
new file mode 100644
index 000000000..b3f6d3bc5
--- /dev/null
+++ b/svx/source/svdraw/polypolygoneditor.cxx
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+#include <svx/polypolygoneditor.hxx>
+
+namespace sdr {
+
+PolyPolygonEditor::PolyPolygonEditor( const basegfx::B2DPolyPolygon& rPolyPolygon)
+: maPolyPolygon( rPolyPolygon )
+{
+}
+
+bool PolyPolygonEditor::DeletePoints( const o3tl::sorted_vector< sal_uInt16 >& rAbsPoints )
+{
+ bool bPolyPolyChanged = false;
+
+ auto aIter( rAbsPoints.rbegin() );
+ for( ; aIter != rAbsPoints.rend(); ++aIter )
+ {
+ sal_uInt32 nPoly, nPnt;
+ if( GetRelativePolyPoint(maPolyPolygon,(*aIter), nPoly, nPnt) )
+ {
+ // remove point
+ basegfx::B2DPolygon aCandidate(maPolyPolygon.getB2DPolygon(nPoly));
+
+ aCandidate.remove(nPnt);
+
+
+ if( aCandidate.count() < 2 )
+ {
+ maPolyPolygon.remove(nPoly);
+ }
+ else
+ {
+ maPolyPolygon.setB2DPolygon(nPoly, aCandidate);
+ }
+
+ bPolyPolyChanged = true;
+ }
+ }
+
+ return bPolyPolyChanged;
+}
+
+bool PolyPolygonEditor::SetSegmentsKind(SdrPathSegmentKind eKind, const o3tl::sorted_vector< sal_uInt16 >& rAbsPoints )
+{
+ bool bPolyPolyChanged = false;
+
+ auto aIter( rAbsPoints.rbegin() );
+ for( ; aIter != rAbsPoints.rend(); ++aIter )
+ {
+ sal_uInt32 nPolyNum, nPntNum;
+
+ if(PolyPolygonEditor::GetRelativePolyPoint(maPolyPolygon, (*aIter), nPolyNum, nPntNum))
+ {
+ // do change at aNewPolyPolygon. Take a look at edge.
+ basegfx::B2DPolygon aCandidate(maPolyPolygon.getB2DPolygon(nPolyNum));
+ const sal_uInt32 nCount(aCandidate.count());
+
+ if(nCount && (nPntNum + 1 < nCount || aCandidate.isClosed()))
+ {
+ bool bCandidateChanged(false);
+
+ // it's a valid edge, check control point usage
+ const sal_uInt32 nNextIndex((nPntNum + 1) % nCount);
+ const bool bContolUsed(aCandidate.areControlPointsUsed()
+ && (aCandidate.isNextControlPointUsed(nPntNum) || aCandidate.isPrevControlPointUsed(nNextIndex)));
+
+ if(bContolUsed)
+ {
+ if(SdrPathSegmentKind::Toggle == eKind || SdrPathSegmentKind::Line == eKind)
+ {
+ // remove control
+ aCandidate.resetNextControlPoint(nPntNum);
+ aCandidate.resetPrevControlPoint(nNextIndex);
+ bCandidateChanged = true;
+ }
+ }
+ else
+ {
+ if(SdrPathSegmentKind::Toggle == eKind || SdrPathSegmentKind::Curve == eKind)
+ {
+ // add control
+ const basegfx::B2DPoint aStart(aCandidate.getB2DPoint(nPntNum));
+ const basegfx::B2DPoint aEnd(aCandidate.getB2DPoint(nNextIndex));
+
+ aCandidate.setNextControlPoint(nPntNum, interpolate(aStart, aEnd, (1.0 / 3.0)));
+ aCandidate.setPrevControlPoint(nNextIndex, interpolate(aStart, aEnd, (2.0 / 3.0)));
+ bCandidateChanged = true;
+ }
+ }
+
+ if(bCandidateChanged)
+ {
+ maPolyPolygon.setB2DPolygon(nPolyNum, aCandidate);
+ bPolyPolyChanged = true;
+ }
+ }
+ }
+ }
+
+ return bPolyPolyChanged;
+}
+
+bool PolyPolygonEditor::SetPointsSmooth( basegfx::B2VectorContinuity eFlags, const o3tl::sorted_vector< sal_uInt16 >& rAbsPoints)
+{
+ bool bPolyPolygonChanged(false);
+
+ auto aIter( rAbsPoints.rbegin() );
+ for( ; aIter != rAbsPoints.rend(); ++aIter )
+ {
+ sal_uInt32 nPolyNum, nPntNum;
+
+ if(PolyPolygonEditor::GetRelativePolyPoint(maPolyPolygon, (*aIter), nPolyNum, nPntNum))
+ {
+ // do change at aNewPolyPolygon...
+ basegfx::B2DPolygon aCandidate(maPolyPolygon.getB2DPolygon(nPolyNum));
+
+ // set continuity in point, make sure there is a curve
+ bool bPolygonChanged = basegfx::utils::expandToCurveInPoint(aCandidate, nPntNum);
+ bPolygonChanged |= basegfx::utils::setContinuityInPoint(aCandidate, nPntNum, eFlags);
+
+ if(bPolygonChanged)
+ {
+ maPolyPolygon.setB2DPolygon(nPolyNum, aCandidate);
+ bPolyPolygonChanged = true;
+ }
+ }
+ }
+
+ return bPolyPolygonChanged;
+}
+
+bool PolyPolygonEditor::GetRelativePolyPoint( const basegfx::B2DPolyPolygon& rPoly, sal_uInt32 nAbsPnt, sal_uInt32& rPolyNum, sal_uInt32& rPointNum )
+{
+ const sal_uInt32 nPolyCount(rPoly.count());
+ sal_uInt32 nPolyNum(0);
+
+ while(nPolyNum < nPolyCount)
+ {
+ const sal_uInt32 nPointCount(rPoly.getB2DPolygon(nPolyNum).count());
+
+ if(nAbsPnt < nPointCount)
+ {
+ rPolyNum = nPolyNum;
+ rPointNum = nAbsPnt;
+
+ return true;
+ }
+ else
+ {
+ nPolyNum++;
+ nAbsPnt -= nPointCount;
+ }
+ }
+
+ return false;
+}
+
+} // end of namespace sdr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/presetooxhandleadjustmentrelations.cxx b/svx/source/svdraw/presetooxhandleadjustmentrelations.cxx
new file mode 100644
index 000000000..528c8b35c
--- /dev/null
+++ b/svx/source/svdraw/presetooxhandleadjustmentrelations.cxx
@@ -0,0 +1,343 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <o3tl/string_view.hxx>
+#include <rtl/ustring.hxx>
+#include <unordered_map>
+#include "presetooxhandleadjustmentrelations.hxx"
+
+namespace
+{
+typedef std::unordered_map<OUString, OUString> HandleAdjRelHashMap;
+
+struct HandleAdjRel
+{
+ // Shape name without leading "ooxml-", underscore, zero based handle index
+ // e.g. The third handle in shape of type "ooxml-circularArrow" will be
+ // identified by key "circularArrow_2"
+ const char* sShape_Handle;
+
+ // 4 tokens with separator "|"
+ // first: RefX or RefR, na if not exists
+ // second: adj, or adj1 or adj2, etc. as in preset, na if not exists
+ // third: RefY or RefAngle, na if not exists
+ // forth: adj, or adj1 or adj2, etc. as in preset, na if not exists
+ // e.g. The third handle in shape <circularArrow> has in the preset
+ // the tag <ahPolar gdRefR="adj5" minR="0" maxR="25000"> .
+ // The resulting value in the map here is "RefR|adj5|na|na"
+ const char* sAdjReferences;
+};
+
+// The array initializer has been extracted from
+// oox/source/drawingml/customshapes/presetShapeDefinitions.xml
+// by using an XSLT file. That file is attached to tdf#126512.
+constexpr HandleAdjRel aHandleAdjRelArray[]
+ = { { "accentBorderCallout1_0", "RefX|adj2|RefY|adj1" },
+ { "accentBorderCallout1_1", "RefX|adj4|RefY|adj3" },
+ { "accentBorderCallout2_0", "RefX|adj2|RefY|adj1" },
+ { "accentBorderCallout2_1", "RefX|adj4|RefY|adj3" },
+ { "accentBorderCallout2_2", "RefX|adj6|RefY|adj5" },
+ { "accentBorderCallout3_0", "RefX|adj2|RefY|adj1" },
+ { "accentBorderCallout3_1", "RefX|adj4|RefY|adj3" },
+ { "accentBorderCallout3_2", "RefX|adj6|RefY|adj5" },
+ { "accentBorderCallout3_3", "RefX|adj8|RefY|adj7" },
+ { "accentCallout1_0", "RefX|adj2|RefY|adj1" },
+ { "accentCallout1_1", "RefX|adj4|RefY|adj3" },
+ { "accentCallout2_0", "RefX|adj2|RefY|adj1" },
+ { "accentCallout2_1", "RefX|adj4|RefY|adj3" },
+ { "accentCallout2_2", "RefX|adj6|RefY|adj5" },
+ { "accentCallout3_0", "RefX|adj2|RefY|adj1" },
+ { "accentCallout3_1", "RefX|adj4|RefY|adj3" },
+ { "accentCallout3_2", "RefX|adj6|RefY|adj5" },
+ { "accentCallout3_3", "RefX|adj8|RefY|adj7" },
+ { "arc_0", "na|na|RefAngle|adj1" },
+ { "arc_1", "na|na|RefAngle|adj2" },
+ { "bentArrow_0", "RefX|adj1|na|na" },
+ { "bentArrow_1", "na|na|RefY|adj2" },
+ { "bentArrow_2", "RefX|adj3|na|na" },
+ { "bentArrow_3", "RefX|adj4|na|na" },
+ { "bentConnector3_0", "RefX|adj1|na|na" },
+ { "bentConnector4_0", "RefX|adj1|na|na" },
+ { "bentConnector4_1", "na|na|RefY|adj2" },
+ { "bentConnector5_0", "RefX|adj1|na|na" },
+ { "bentConnector5_1", "na|na|RefY|adj2" },
+ { "bentConnector5_2", "RefX|adj3|na|na" },
+ { "bentUpArrow_0", "na|na|RefY|adj1" },
+ { "bentUpArrow_1", "RefX|adj2|na|na" },
+ { "bentUpArrow_2", "na|na|RefY|adj3" },
+ { "bevel_0", "RefX|adj|na|na" },
+ { "blockArc_0", "na|na|RefAngle|adj1" },
+ { "blockArc_1", "RefR|adj3|RefAngle|adj2" },
+ { "borderCallout1_0", "RefX|adj2|RefY|adj1" },
+ { "borderCallout1_1", "RefX|adj4|RefY|adj3" },
+ { "borderCallout2_0", "RefX|adj2|RefY|adj1" },
+ { "borderCallout2_1", "RefX|adj4|RefY|adj3" },
+ { "borderCallout2_2", "RefX|adj6|RefY|adj5" },
+ { "borderCallout3_0", "RefX|adj2|RefY|adj1" },
+ { "borderCallout3_1", "RefX|adj4|RefY|adj3" },
+ { "borderCallout3_2", "RefX|adj6|RefY|adj5" },
+ { "borderCallout3_3", "RefX|adj8|RefY|adj7" },
+ { "bracePair_0", "na|na|RefY|adj" },
+ { "bracketPair_0", "na|na|RefY|adj" },
+ { "callout1_0", "RefX|adj2|RefY|adj1" },
+ { "callout1_1", "RefX|adj4|RefY|adj3" },
+ { "callout2_0", "RefX|adj2|RefY|adj1" },
+ { "callout2_1", "RefX|adj4|RefY|adj3" },
+ { "callout2_2", "RefX|adj6|RefY|adj5" },
+ { "callout3_0", "RefX|adj2|RefY|adj1" },
+ { "callout3_1", "RefX|adj4|RefY|adj3" },
+ { "callout3_2", "RefX|adj6|RefY|adj5" },
+ { "callout3_3", "RefX|adj8|RefY|adj7" },
+ { "can_0", "na|na|RefY|adj" },
+ { "chevron_0", "RefX|adj|na|na" },
+ { "chord_0", "na|na|RefAngle|adj1" },
+ { "chord_1", "na|na|RefAngle|adj2" },
+ { "circularArrow_0", "na|na|RefAngle|adj2" },
+ { "circularArrow_1", "na|na|RefAngle|adj4" },
+ { "circularArrow_2", "RefR|adj1|RefAngle|adj3" },
+ { "circularArrow_3", "RefR|adj5|na|na" },
+ { "cloudCallout_0", "RefX|adj1|RefY|adj2" },
+ { "corner_0", "na|na|RefY|adj1" },
+ { "corner_1", "RefX|adj2|na|na" },
+ { "cube_0", "na|na|RefY|adj" },
+ { "curvedConnector3_0", "RefX|adj1|na|na" },
+ { "curvedConnector4_0", "RefX|adj1|na|na" },
+ { "curvedConnector4_1", "na|na|RefY|adj2" },
+ { "curvedConnector5_0", "RefX|adj1|na|na" },
+ { "curvedConnector5_1", "na|na|RefY|adj2" },
+ { "curvedConnector5_2", "RefX|adj3|na|na" },
+ { "curvedDownArrow_0", "RefX|adj1|na|na" },
+ { "curvedDownArrow_1", "RefX|adj2|na|na" },
+ { "curvedDownArrow_2", "na|na|RefY|adj3" },
+ { "curvedLeftArrow_0", "na|na|RefY|adj1" },
+ { "curvedLeftArrow_1", "na|na|RefY|adj2" },
+ { "curvedLeftArrow_2", "RefX|adj3|na|na" },
+ { "curvedRightArrow_0", "na|na|RefY|adj1" },
+ { "curvedRightArrow_1", "na|na|RefY|adj2" },
+ { "curvedRightArrow_2", "RefX|adj3|na|na" },
+ { "curvedUpArrow_0", "RefX|adj1|na|na" },
+ { "curvedUpArrow_1", "RefX|adj2|na|na" },
+ { "curvedUpArrow_2", "na|na|RefY|adj3" },
+ { "diagStripe_0", "na|na|RefY|adj" },
+ { "donut_0", "RefR|adj|na|na" },
+ { "doubleWave_0", "na|na|RefY|adj1" },
+ { "doubleWave_1", "RefX|adj2|na|na" },
+ { "downArrow_0", "RefX|adj1|na|na" },
+ { "downArrow_1", "na|na|RefY|adj2" },
+ { "downArrowCallout_0", "RefX|adj1|na|na" },
+ { "downArrowCallout_1", "RefX|adj2|na|na" },
+ { "downArrowCallout_2", "na|na|RefY|adj3" },
+ { "downArrowCallout_3", "na|na|RefY|adj4" },
+ { "ellipseRibbon_0", "na|na|RefY|adj1" },
+ { "ellipseRibbon_1", "RefX|adj2|na|na" },
+ { "ellipseRibbon_2", "na|na|RefY|adj3" },
+ { "ellipseRibbon2_0", "na|na|RefY|adj1" },
+ { "ellipseRibbon2_1", "RefX|adj2|na|na" },
+ { "ellipseRibbon2_2", "na|na|RefY|adj3" },
+ { "foldedCorner_0", "RefX|adj|na|na" },
+ { "frame_0", "RefX|adj1|na|na" },
+ { "gear6_0", "na|na|RefY|adj1" },
+ { "gear6_1", "RefX|adj2|na|na" },
+ { "gear9_0", "na|na|RefY|adj1" },
+ { "gear9_1", "RefX|adj2|na|na" },
+ { "halfFrame_0", "na|na|RefY|adj1" },
+ { "halfFrame_1", "RefX|adj2|na|na" },
+ { "hexagon_0", "RefX|adj|na|na" },
+ { "homePlate_0", "RefX|adj|na|na" },
+ { "horizontalScroll_0", "RefX|adj|na|na" },
+ { "leftArrow_0", "na|na|RefY|adj1" },
+ { "leftArrow_1", "RefX|adj2|na|na" },
+ { "leftArrowCallout_0", "na|na|RefY|adj1" },
+ { "leftArrowCallout_1", "na|na|RefY|adj2" },
+ { "leftArrowCallout_2", "RefX|adj3|na|na" },
+ { "leftArrowCallout_3", "RefX|adj4|na|na" },
+ { "leftBrace_0", "na|na|RefY|adj1" },
+ { "leftBrace_1", "na|na|RefY|adj2" },
+ { "leftBracket_0", "na|na|RefY|adj" },
+ { "leftCircularArrow_0", "na|na|RefAngle|adj2" },
+ { "leftCircularArrow_1", "na|na|RefAngle|adj4" },
+ { "leftCircularArrow_2", "RefR|adj1|RefAngle|adj3" },
+ { "leftCircularArrow_3", "RefR|adj5|na|na" },
+ { "leftRightArrow_0", "na|na|RefY|adj1" },
+ { "leftRightArrow_1", "RefX|adj2|na|na" },
+ { "leftRightArrowCallout_0", "na|na|RefY|adj1" },
+ { "leftRightArrowCallout_1", "na|na|RefY|adj2" },
+ { "leftRightArrowCallout_2", "RefX|adj3|na|na" },
+ { "leftRightArrowCallout_3", "RefX|adj4|na|na" },
+ { "leftRightCircularArrow_0", "na|na|RefAngle|adj2" },
+ { "leftRightCircularArrow_1", "na|na|RefAngle|adj4" },
+ { "leftRightCircularArrow_2", "RefR|adj1|RefAngle|adj3" },
+ { "leftRightCircularArrow_3", "RefR|adj5|na|na" },
+ { "leftRightRibbon_0", "na|na|RefY|adj1" },
+ { "leftRightRibbon_1", "RefX|adj2|na|na" },
+ { "leftRightRibbon_2", "na|na|RefY|adj3" },
+ { "leftRightUpArrow_0", "RefX|adj1|na|na" },
+ { "leftRightUpArrow_1", "RefX|adj2|na|na" },
+ { "leftRightUpArrow_2", "na|na|RefY|adj3" },
+ { "leftUpArrow_0", "na|na|RefY|adj1" },
+ { "leftUpArrow_1", "RefX|adj2|na|na" },
+ { "leftUpArrow_2", "na|na|RefY|adj3" },
+ { "mathDivide_0", "na|na|RefY|adj1" },
+ { "mathDivide_1", "na|na|RefY|adj2" },
+ { "mathDivide_2", "RefX|adj3|na|na" },
+ { "mathEqual_0", "na|na|RefY|adj1" },
+ { "mathEqual_1", "na|na|RefY|adj2" },
+ { "mathMinus_0", "na|na|RefY|adj1" },
+ { "mathMultiply_0", "na|na|RefY|adj1" },
+ { "mathNotEqual_0", "na|na|RefY|adj1" },
+ { "mathNotEqual_1", "na|na|RefAngle|adj2" },
+ { "mathNotEqual_2", "na|na|RefY|adj3" },
+ { "mathPlus_0", "na|na|RefY|adj1" },
+ { "moon_0", "RefX|adj|na|na" },
+ { "nonIsoscelesTrapezoid_0", "RefX|adj1|na|na" },
+ { "nonIsoscelesTrapezoid_1", "RefX|adj2|na|na" },
+ { "noSmoking_0", "RefR|adj|na|na" },
+ { "notchedRightArrow_0", "na|na|RefY|adj1" },
+ { "notchedRightArrow_1", "RefX|adj2|na|na" },
+ { "octagon_0", "RefX|adj|na|na" },
+ { "parallelogram_0", "RefX|adj|na|na" },
+ { "pie_0", "na|na|RefAngle|adj1" },
+ { "pie_1", "na|na|RefAngle|adj2" },
+ { "plaque_0", "RefX|adj|na|na" },
+ { "plus_0", "RefX|adj|na|na" },
+ { "quadArrow_0", "RefX|adj1|na|na" },
+ { "quadArrow_1", "RefX|adj2|na|na" },
+ { "quadArrow_2", "na|na|RefY|adj3" },
+ { "quadArrowCallout_0", "RefX|adj1|na|na" },
+ { "quadArrowCallout_1", "RefX|adj2|na|na" },
+ { "quadArrowCallout_2", "na|na|RefY|adj3" },
+ { "quadArrowCallout_3", "na|na|RefY|adj4" },
+ { "ribbon_0", "na|na|RefY|adj1" },
+ { "ribbon_1", "RefX|adj2|na|na" },
+ { "ribbon2_0", "na|na|RefY|adj1" },
+ { "ribbon2_1", "RefX|adj2|na|na" },
+ { "rightArrow_0", "na|na|RefY|adj1" },
+ { "rightArrow_1", "RefX|adj2|na|na" },
+ { "rightArrowCallout_0", "na|na|RefY|adj1" },
+ { "rightArrowCallout_1", "na|na|RefY|adj2" },
+ { "rightArrowCallout_2", "RefX|adj3|na|na" },
+ { "rightArrowCallout_3", "RefX|adj4|na|na" },
+ { "rightBrace_0", "na|na|RefY|adj1" },
+ { "rightBrace_1", "na|na|RefY|adj2" },
+ { "rightBracket_0", "na|na|RefY|adj" },
+ { "round1Rect_0", "RefX|adj|na|na" },
+ { "round2DiagRect_0", "RefX|adj1|na|na" },
+ { "round2DiagRect_1", "RefX|adj2|na|na" },
+ { "round2SameRect_0", "RefX|adj1|na|na" },
+ { "round2SameRect_1", "RefX|adj2|na|na" },
+ { "roundRect_0", "RefX|adj|na|na" },
+ { "smileyFace_0", "na|na|RefY|adj" },
+ { "snip1Rect_0", "RefX|adj|na|na" },
+ { "snip2DiagRect_0", "RefX|adj1|na|na" },
+ { "snip2DiagRect_1", "RefX|adj2|na|na" },
+ { "snip2SameRect_0", "RefX|adj1|na|na" },
+ { "snip2SameRect_1", "RefX|adj2|na|na" },
+ { "snipRoundRect_0", "RefX|adj1|na|na" },
+ { "snipRoundRect_1", "RefX|adj2|na|na" },
+ { "star10_0", "na|na|RefY|adj" },
+ { "star12_0", "na|na|RefY|adj" },
+ { "star16_0", "na|na|RefY|adj" },
+ { "star24_0", "na|na|RefY|adj" },
+ { "star32_0", "na|na|RefY|adj" },
+ { "star4_0", "na|na|RefY|adj" },
+ { "star5_0", "na|na|RefY|adj" },
+ { "star6_0", "na|na|RefY|adj" },
+ { "star7_0", "na|na|RefY|adj" },
+ { "star8_0", "na|na|RefY|adj" },
+ { "stripedRightArrow_0", "na|na|RefY|adj1" },
+ { "stripedRightArrow_1", "RefX|adj2|na|na" },
+ { "sun_0", "RefX|adj|na|na" },
+ { "swooshArrow_0", "na|na|RefY|adj1" },
+ { "swooshArrow_1", "RefX|adj2|na|na" },
+ { "teardrop_0", "RefX|adj|na|na" },
+ { "trapezoid_0", "RefX|adj|na|na" },
+ { "triangle_0", "RefX|adj|na|na" },
+ { "upArrowCallout_0", "RefX|adj1|na|na" },
+ { "upArrowCallout_1", "RefX|adj2|na|na" },
+ { "upArrowCallout_2", "na|na|RefY|adj3" },
+ { "upArrowCallout_3", "na|na|RefY|adj4" },
+ { "upDownArrow_0", "RefX|adj1|na|na" },
+ { "upDownArrow_1", "na|na|RefY|adj2" },
+ { "upArrow_0", "RefX|adj1|na|na" },
+ { "upArrow_1", "na|na|RefY|adj2" },
+ { "upDownArrowCallout_0", "RefX|adj1|na|na" },
+ { "upDownArrowCallout_1", "RefX|adj2|na|na" },
+ { "upDownArrowCallout_2", "na|na|RefY|adj3" },
+ { "upDownArrowCallout_3", "na|na|RefY|adj4" },
+ { "uturnArrow_0", "RefX|adj1|na|na" },
+ { "uturnArrow_1", "RefX|adj2|na|na" },
+ { "uturnArrow_2", "na|na|RefY|adj3" },
+ { "uturnArrow_3", "RefX|adj4|na|na" },
+ { "uturnArrow_4", "na|na|RefY|adj5" },
+ { "verticalScroll_0", "na|na|RefY|adj" },
+ { "wave_0", "na|na|RefY|adj1" },
+ { "wave_1", "RefX|adj2|na|na" },
+ { "wedgeEllipseCallout_0", "RefX|adj1|RefY|adj2" },
+ { "wedgeRectCallout_0", "RefX|adj1|RefY|adj2" },
+ { "wedgeRoundRectCallout_0", "RefX|adj1|RefY|adj2" } };
+}
+
+static sal_Int32 lcl_getAdjIndexFromToken(const sal_Int32 nTokenPos, std::u16string_view rMapValue)
+{
+ std::u16string_view sAdjRef = o3tl::getToken(rMapValue, nTokenPos, '|');
+ std::u16string_view sNumber; // number part from "adj1", "adj2" etc.
+ if (o3tl::starts_with(sAdjRef, u"adj", &sNumber))
+ {
+ if (sNumber.empty() || sNumber == u"1")
+ return 0;
+ else
+ return o3tl::toInt32(sNumber) - 1;
+ }
+ else
+ return -1;
+}
+
+void PresetOOXHandleAdj::GetOOXHandleAdjRelation(
+ std::u16string_view sFullOOXShapeName, const sal_Int32 nHandleIndex, OUString& rFirstRefType,
+ sal_Int32& rFirstAdjValueIndex, OUString& rSecondRefType, sal_Int32& rSecondAdjValueIndex)
+{
+ static const HandleAdjRelHashMap s_HashMap = []() {
+ HandleAdjRelHashMap aH;
+ aH.reserve(std::size(aHandleAdjRelArray));
+ for (const auto& item : aHandleAdjRelArray)
+ aH.emplace(OUString::createFromAscii(item.sShape_Handle),
+ OUString::createFromAscii(item.sAdjReferences));
+ return aH;
+ }();
+
+ std::u16string_view sKey;
+ OUString sValue;
+ rFirstRefType = "na";
+ rFirstAdjValueIndex = -1;
+ rSecondRefType = "na";
+ rSecondAdjValueIndex = -1;
+ if (o3tl::starts_with(sFullOOXShapeName, u"ooxml-", &sKey))
+ {
+ HandleAdjRelHashMap::const_iterator aHashIter(
+ s_HashMap.find(OUString::Concat(sKey) + "_" + OUString::number(nHandleIndex)));
+ if (aHashIter != s_HashMap.end())
+ sValue = (*aHashIter).second;
+ else
+ return;
+ }
+ else
+ return;
+
+ rFirstRefType = sValue.getToken(0, '|');
+ rFirstAdjValueIndex = lcl_getAdjIndexFromToken(1, sValue);
+ rSecondRefType = sValue.getToken(2, '|');
+ rSecondAdjValueIndex = lcl_getAdjIndexFromToken(3, sValue);
+ return;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/svdraw/presetooxhandleadjustmentrelations.hxx b/svx/source/svdraw/presetooxhandleadjustmentrelations.hxx
new file mode 100644
index 000000000..b9404e598
--- /dev/null
+++ b/svx/source/svdraw/presetooxhandleadjustmentrelations.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_SVDRAW_PRESETOOXHANDLEADJUSTMENTRELATIONS_HXX
+#define INCLUDED_SVX_SOURCE_SVDRAW_PRESETOOXHANDLEADJUSTMENTRELATIONS_HXX
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <rtl/ustring.hxx>
+
+namespace PresetOOXHandleAdj
+{
+/* This method is used in SdrObjCustomShape::MergeDefaultAttributes() */
+void GetOOXHandleAdjRelation(
+ std::u16string_view sFullOOXShapeName, /* e.g. "ooxml-circularArrow" */
+ const sal_Int32 nHandleIndex, /* index in sequence from property "Handles" */
+ OUString& rFirstRefType, /* Propertyname, same as by pptx import, e.g. "RefX" */
+ sal_Int32& rFirstAdjValueIndex, /* index in sequence from property "AdjustmentValues" */
+ OUString& rSecondRefType, /* Propertyname, same as by pptx import, e.g. "RefY" */
+ sal_Int32& rSecondAdjValueIndex /* index in sequence from property "AdjustmentValues" */
+);
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/svdraw/sdrhittesthelper.cxx b/svx/source/svdraw/sdrhittesthelper.cxx
new file mode 100644
index 000000000..62ebde956
--- /dev/null
+++ b/svx/source/svdraw/sdrhittesthelper.cxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/sdrhittesthelper.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/helperhittest3d.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <drawinglayer/processor2d/hittestprocessor2d.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+
+
+// #i101872# new Object HitTest as View-tooling
+
+SdrObject* SdrObjectPrimitiveHit(
+ const SdrObject& rObject,
+ const Point& rPnt,
+ sal_uInt16 nTol,
+ const SdrPageView& rSdrPageView,
+ const SdrLayerIDSet* pVisiLayer,
+ bool bTextOnly,
+ drawinglayer::primitive2d::Primitive2DContainer* pHitContainer)
+{
+ SdrObject* pResult = nullptr;
+
+ if(rObject.GetSubList() && rObject.GetSubList()->GetObjCount())
+ {
+ // group or scene with content. Single 3D objects also have a
+ // true == rObject.GetSubList(), but no content
+ pResult = SdrObjListPrimitiveHit(*rObject.GetSubList(), rPnt, nTol, rSdrPageView, pVisiLayer, bTextOnly);
+ }
+ else
+ {
+ if( rObject.IsVisible() && (!pVisiLayer || pVisiLayer->IsSet(rObject.GetLayer())))
+ {
+ // single object, 3d object, empty scene or empty group. Check if
+ // it's a single 3D object
+ const E3dCompoundObject* pE3dCompoundObject = dynamic_cast< const E3dCompoundObject* >(&rObject);
+
+ if(pE3dCompoundObject)
+ {
+ const basegfx::B2DPoint aHitPosition(rPnt.X(), rPnt.Y());
+
+ if(checkHitSingle3DObject(aHitPosition, *pE3dCompoundObject))
+ {
+ pResult = const_cast< E3dCompoundObject* >(pE3dCompoundObject);
+ }
+ }
+ else
+ {
+ // not a single 3D object; Check in first PageWindow using primitives (only SC
+ // with split views uses multiple PageWindows nowadays)
+ if(rSdrPageView.PageWindowCount())
+ {
+ const double fLogicTolerance(nTol);
+ const basegfx::B2DPoint aHitPosition(rPnt.X(), rPnt.Y());
+ const sdr::contact::ViewObjectContact& rVOC = rObject.GetViewContact().GetViewObjectContact(
+ rSdrPageView.GetPageWindow(0)->GetObjectContact());
+
+ if(ViewObjectContactPrimitiveHit(rVOC, aHitPosition, fLogicTolerance, bTextOnly, pHitContainer))
+ {
+ pResult = const_cast< SdrObject* >(&rObject);
+ }
+ }
+ }
+ }
+ }
+
+ return pResult;
+}
+
+
+SdrObject* SdrObjListPrimitiveHit(
+ const SdrObjList& rList,
+ const Point& rPnt,
+ sal_uInt16 nTol,
+ const SdrPageView& rSdrPageView,
+ const SdrLayerIDSet* pVisiLayer,
+ bool bTextOnly)
+{
+ size_t nObjNum(rList.GetObjCount());
+ SdrObject* pRetval = nullptr;
+
+ while(!pRetval && nObjNum > 0)
+ {
+ nObjNum--;
+ SdrObject* pObj = rList.GetObj(nObjNum);
+
+ pRetval = SdrObjectPrimitiveHit(*pObj, rPnt, nTol, rSdrPageView, pVisiLayer, bTextOnly);
+ }
+
+ return pRetval;
+}
+
+
+bool ViewObjectContactPrimitiveHit(
+ const sdr::contact::ViewObjectContact& rVOC,
+ const basegfx::B2DPoint& rHitPosition,
+ double fLogicHitTolerance,
+ bool bTextOnly,
+ drawinglayer::primitive2d::Primitive2DContainer* pHitContainer)
+{
+ basegfx::B2DRange aObjectRange(rVOC.getObjectRange());
+
+ if(!aObjectRange.isEmpty())
+ {
+ // first do a rough B2DRange based HitTest; do not forget to
+ // include the HitTolerance if given
+ if(basegfx::fTools::more(fLogicHitTolerance, 0.0))
+ {
+ aObjectRange.grow(fLogicHitTolerance);
+ }
+
+ if(aObjectRange.isInside(rHitPosition))
+ {
+ // get primitive sequence
+ sdr::contact::DisplayInfo aDisplayInfo;
+ // have to make a copy of this container here, because it might be changed underneath us
+ const drawinglayer::primitive2d::Primitive2DContainer aSequence(rVOC.getPrimitive2DSequence(aDisplayInfo));
+
+ if(!aSequence.empty())
+ {
+ // create a HitTest processor
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation2D = rVOC.GetObjectContact().getViewInformation2D();
+ drawinglayer::processor2d::HitTestProcessor2D aHitTestProcessor2D(
+ rViewInformation2D,
+ rHitPosition,
+ fLogicHitTolerance,
+ bTextOnly);
+
+ // ask for HitStack
+ aHitTestProcessor2D.collectHitStack(pHitContainer != nullptr);
+
+ // feed it with the primitives
+ aHitTestProcessor2D.process(aSequence);
+
+ // deliver result
+ if (aHitTestProcessor2D.getHit())
+ {
+ if (pHitContainer)
+ {
+ // fetch HitStack primitives if requested
+ *pHitContainer = aHitTestProcessor2D.getHitStack();
+ }
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/sdrmasterpagedescriptor.cxx b/svx/source/svdraw/sdrmasterpagedescriptor.cxx
new file mode 100644
index 000000000..1d0843918
--- /dev/null
+++ b/svx/source/svdraw/sdrmasterpagedescriptor.cxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdrmasterpagedescriptor.hxx>
+#include <sdr/contact/viewcontactofmasterpagedescriptor.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <svl/itemset.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr
+{
+ MasterPageDescriptor::MasterPageDescriptor(SdrPage& aOwnerPage, SdrPage& aUsedPage)
+ : maOwnerPage(aOwnerPage),
+ maUsedPage(aUsedPage)
+ {
+ // all layers visible
+ maVisibleLayers.SetAll();
+
+ // register at used page
+ maUsedPage.AddPageUser(*this);
+ }
+
+ MasterPageDescriptor::~MasterPageDescriptor()
+ {
+ // de-register at used page
+ maUsedPage.RemovePageUser(*this);
+
+ mpViewContact.reset();
+ }
+
+ // ViewContact part
+ sdr::contact::ViewContact& MasterPageDescriptor::GetViewContact() const
+ {
+ if(!mpViewContact)
+ {
+ mpViewContact.reset(
+ new sdr::contact::ViewContactOfMasterPageDescriptor(*const_cast< MasterPageDescriptor* >(this)) );
+ }
+
+ return *mpViewContact;
+ }
+
+ // this method is called from the destructor of the referenced page.
+ // do all necessary action to forget the page. It is not necessary to call
+ // RemovePageUser(), that is done from the destructor.
+ void MasterPageDescriptor::PageInDestruction(const SdrPage& /*rPage*/)
+ {
+ maOwnerPage.TRG_ClearMasterPage();
+ }
+
+ void MasterPageDescriptor::SetVisibleLayers(const SdrLayerIDSet& rNew)
+ {
+ if(rNew != maVisibleLayers)
+ {
+ maVisibleLayers = rNew;
+ GetViewContact().ActionChanged();
+ }
+ }
+
+
+ const SdrPageProperties* MasterPageDescriptor::getCorrectSdrPageProperties() const
+ {
+ const SdrPage* pCorrectPage = &GetOwnerPage();
+ const SdrPageProperties* pCorrectProperties = &pCorrectPage->getSdrPageProperties();
+
+ if(drawing::FillStyle_NONE == pCorrectProperties->GetItemSet().Get(XATTR_FILLSTYLE).GetValue())
+ {
+ pCorrectPage = &GetUsedPage();
+ pCorrectProperties = &pCorrectPage->getSdrPageProperties();
+ }
+
+ if(pCorrectPage->IsMasterPage() && !pCorrectProperties->GetStyleSheet())
+ {
+ // #i110846# Suppress SdrPage FillStyle for MasterPages without StyleSheets,
+ // else the PoolDefault (XFILL_COLOR and Blue8) will be used. Normally, all
+ // MasterPages should have a StyleSheet exactly for this reason, but historically
+ // e.g. the Notes MasterPage has no StyleSheet set (and there maybe others).
+ pCorrectProperties = nullptr;
+ }
+
+ return pCorrectProperties;
+ }
+} // end of namespace sdr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/sdrpagewindow.cxx b/svx/source/svdraw/sdrpagewindow.cxx
new file mode 100644
index 000000000..01be77135
--- /dev/null
+++ b/svx/source/svdraw/sdrpagewindow.cxx
@@ -0,0 +1,531 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdrpagewindow.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/awt/PosSize.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/fmview.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <tools/debug.hxx>
+#include <vcl/window.hxx>
+
+using namespace ::com::sun::star;
+
+struct SdrPageWindow::Impl
+{
+ // #110094# ObjectContact section
+ mutable sdr::contact::ObjectContact* mpObjectContact;
+
+ // the SdrPageView this window belongs to
+ SdrPageView& mrPageView;
+
+ // the PaintWindow to paint on. Here is access to OutDev etc.
+ // #i72752# change to pointer to allow patcing it in DrawLayer() if necessary
+ SdrPaintWindow* mpPaintWindow;
+ SdrPaintWindow* mpOriginalPaintWindow;
+
+ // UNO stuff for xControls
+ uno::Reference<awt::XControlContainer> mxControlContainer;
+
+ Impl( SdrPageView& rPageView, SdrPaintWindow& rPaintWindow ) :
+ mpObjectContact(nullptr),
+ mrPageView(rPageView),
+ mpPaintWindow(&rPaintWindow),
+ mpOriginalPaintWindow(nullptr)
+ {
+ }
+};
+
+
+uno::Reference<awt::XControlContainer> const & SdrPageWindow::GetControlContainer( bool _bCreateIfNecessary ) const
+{
+ if (!mpImpl->mxControlContainer.is() && _bCreateIfNecessary)
+ {
+ SdrView& rView = GetPageView().GetView();
+
+ const SdrPaintWindow& rPaintWindow( GetOriginalPaintWindow() ? *GetOriginalPaintWindow() : GetPaintWindow() );
+ if ( rPaintWindow.OutputToWindow() && !rView.IsPrintPreview() )
+ {
+ vcl::Window* pWindow = rPaintWindow.GetOutputDevice().GetOwnerWindow();
+ const_cast< SdrPageWindow* >( this )->mpImpl->mxControlContainer = VCLUnoHelper::CreateControlContainer( pWindow );
+
+ // #100394# xC->setVisible triggers window->Show() and this has
+ // problems when the view is not completely constructed which may
+ // happen when loading. This leads to accessibility broadcasts which
+ // throw asserts due to the not finished view. All this chain can be avoided
+ // since xC->setVisible is here called only for the side effect in
+ // UnoControlContainer::setVisible(...) which calls createPeer(...).
+ // This will now be called directly from here.
+
+ uno::Reference< awt::XControl > xControl(mpImpl->mxControlContainer, uno::UNO_QUERY);
+ if(xControl.is())
+ {
+ uno::Reference< uno::XInterface > xContext = xControl->getContext();
+ if(!xContext.is())
+ {
+ xControl->createPeer( uno::Reference<awt::XToolkit>(), uno::Reference<awt::XWindowPeer>() );
+ }
+ }
+ }
+ else
+ {
+ // Printer and VirtualDevice, or rather: no OutDev
+ uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
+ const_cast< SdrPageWindow* >( this )->mpImpl->mxControlContainer.set(xFactory->createInstance("com.sun.star.awt.UnoControlContainer"), uno::UNO_QUERY);
+ uno::Reference< awt::XControlModel > xModel(xFactory->createInstance("com.sun.star.awt.UnoControlContainerModel"), uno::UNO_QUERY);
+ uno::Reference< awt::XControl > xControl(mpImpl->mxControlContainer, uno::UNO_QUERY);
+ if (xControl.is())
+ xControl->setModel(xModel);
+
+ OutputDevice& rOutDev = rPaintWindow.GetOutputDevice();
+ Point aPosPix = rOutDev.GetMapMode().GetOrigin();
+ Size aSizePix = rOutDev.GetOutputSizePixel();
+
+ uno::Reference< awt::XWindow > xContComp(mpImpl->mxControlContainer, uno::UNO_QUERY);
+ if( xContComp.is() )
+ xContComp->setPosSize(aPosPix.X(), aPosPix.Y(), aSizePix.Width(), aSizePix.Height(), awt::PosSize::POSSIZE);
+ }
+
+ FmFormView* pViewAsFormView = dynamic_cast< FmFormView* >( &rView );
+ if ( pViewAsFormView )
+ pViewAsFormView->InsertControlContainer(mpImpl->mxControlContainer);
+ }
+ return mpImpl->mxControlContainer;
+}
+
+SdrPageWindow::SdrPageWindow(SdrPageView& rPageView, SdrPaintWindow& rPaintWindow) :
+ mpImpl(new Impl(rPageView, rPaintWindow))
+{
+}
+
+SdrPageWindow::~SdrPageWindow()
+{
+ // #i26631#
+ ResetObjectContact();
+
+ if (!mpImpl->mxControlContainer.is())
+ return;
+
+ auto & rView = static_cast<SdrPaintView &>(GetPageView().GetView());
+
+ // notify derived views
+ FmFormView* pViewAsFormView = dynamic_cast< FmFormView* >( &rView );
+ if ( pViewAsFormView )
+ pViewAsFormView->RemoveControlContainer(mpImpl->mxControlContainer);
+
+ // dispose the control container
+ uno::Reference< lang::XComponent > xComponent(mpImpl->mxControlContainer, uno::UNO_QUERY);
+ xComponent->dispose();
+}
+
+SdrPageView& SdrPageWindow::GetPageView() const
+{
+ return mpImpl->mrPageView;
+}
+
+SdrPaintWindow& SdrPageWindow::GetPaintWindow() const
+{
+ return *mpImpl->mpPaintWindow;
+}
+
+const SdrPaintWindow* SdrPageWindow::GetOriginalPaintWindow() const
+{
+ return mpImpl->mpOriginalPaintWindow;
+}
+
+// OVERLAY MANAGER
+rtl::Reference< sdr::overlay::OverlayManager > const & SdrPageWindow::GetOverlayManager() const
+{
+ return GetPaintWindow().GetOverlayManager();
+}
+
+SdrPaintWindow* SdrPageWindow::patchPaintWindow(SdrPaintWindow& rPaintWindow)
+{
+ if (!mpImpl)
+ return nullptr;
+
+ if (!mpImpl->mpOriginalPaintWindow)
+ {
+ // first patch
+ mpImpl->mpOriginalPaintWindow = mpImpl->mpPaintWindow;
+ mpImpl->mpPaintWindow = &rPaintWindow;
+ mpImpl->mpOriginalPaintWindow->setPatched(&rPaintWindow);
+ return mpImpl->mpOriginalPaintWindow;
+ }
+ else
+ {
+ // second or more patch
+ auto pPreviousPaintWindow = mpImpl->mpPaintWindow;
+ mpImpl->mpPaintWindow = &rPaintWindow;
+ mpImpl->mpOriginalPaintWindow->setPatched(&rPaintWindow);
+ return pPreviousPaintWindow;
+ }
+}
+
+void SdrPageWindow::unpatchPaintWindow(SdrPaintWindow* pPreviousPaintWindow)
+{
+ if (pPreviousPaintWindow == mpImpl->mpOriginalPaintWindow)
+ {
+ // first patch
+ mpImpl->mpPaintWindow = mpImpl->mpOriginalPaintWindow;
+ mpImpl->mpOriginalPaintWindow->setPatched(nullptr);
+ mpImpl->mpOriginalPaintWindow = nullptr;
+ }
+ else
+ {
+ // second or more patch
+ mpImpl->mpPaintWindow = pPreviousPaintWindow;
+ mpImpl->mpOriginalPaintWindow->setPatched(pPreviousPaintWindow);
+ }
+}
+
+void SdrPageWindow::PrePaint()
+{
+ // give OC the chance to do ProcessDisplay preparations
+ if(HasObjectContact())
+ {
+ GetObjectContact().PrepareProcessDisplay();
+ }
+}
+
+void SdrPageWindow::PrepareRedraw(const vcl::Region& rReg)
+{
+ // give OC the chance to do ProcessDisplay preparations
+ if(HasObjectContact())
+ {
+ GetObjectContact().PrepareProcessDisplay();
+ }
+
+ // if necessary, remember changed RedrawArea at PaintWindow for usage with
+ // overlay and PreRenderDevice stuff
+ GetPaintWindow().SetRedrawRegion(rReg);
+}
+
+
+// clip test
+#ifdef CLIPPER_TEST
+#include <svx/svdopath.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <tools/helpers.hxx>
+#include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+
+// for ::std::sort
+#include <algorithm>
+
+namespace
+{
+ void impPaintStrokePolygon(const basegfx::B2DPolygon& rCandidate, OutputDevice& rOutDev, Color aColor)
+ {
+ basegfx::B2DPolygon aCandidate(rCandidate);
+
+ if(aCandidate.areControlPointsUsed())
+ {
+ aCandidate = basegfx::utils::adaptiveSubdivideByAngle(rCandidate);
+ }
+
+ if(aCandidate.count())
+ {
+ const sal_uInt32 nLoopCount(aCandidate.isClosed() ? aCandidate.count() : aCandidate.count() - 1);
+ rOutDev.SetFillColor();
+ rOutDev.SetLineColor(aColor);
+
+ for(sal_uInt32 a(0); a < nLoopCount; a++)
+ {
+ const basegfx::B2DPoint aBStart(aCandidate.getB2DPoint(a));
+ const basegfx::B2DPoint aBEnd(aCandidate.getB2DPoint((a + 1) % aCandidate.count()));
+ const Point aStart(FRound(aBStart.getX()), FRound(aBStart.getY()));
+ const Point aEnd(FRound(aBEnd.getX()), FRound(aBEnd.getY()));
+ rOutDev.DrawLine(aStart, aEnd);
+ }
+ }
+ }
+
+ void impTryTest(const SdrPageView& rPageView, OutputDevice& rOutDev)
+ {
+ if(rPageView.GetPage() && rPageView.GetPage()->GetObjCount() >= 2)
+ {
+ SdrPage* pPage = rPageView.GetPage();
+ SdrObject* pObjA = pPage->GetObj(0);
+
+ if(dynamic_cast<const SdrPathObj*>( pObjA))
+ {
+ basegfx::B2DPolyPolygon aPolyA(pObjA->GetPathPoly());
+ aPolyA = basegfx::utils::correctOrientations(aPolyA);
+
+ basegfx::B2DPolyPolygon aPolyB;
+
+ for(sal_uInt32 a(1); a < rPageView.GetPage()->GetObjCount(); a++)
+ {
+ SdrObject* pObjB = pPage->GetObj(a);
+
+ if(dynamic_cast<const SdrPathObj*>( pObjB))
+ {
+ basegfx::B2DPolyPolygon aCandidate(pObjB->GetPathPoly());
+ aCandidate = basegfx::utils::correctOrientations(aCandidate);
+ aPolyB.append(aCandidate);
+ }
+ }
+
+ if(aPolyA.count() && aPolyA.isClosed() && aPolyB.count())
+ {
+ // poly A is the clipregion, clip poly b against it. Algo depends on
+ // poly b being closed.
+ basegfx::B2DPolyPolygon aResult(basegfx::utils::clipPolyPolygonOnPolyPolygon(aPolyB, aPolyA));
+
+ for(auto const& rPolygon : aResult)
+ {
+ int nR = comphelper::rng::uniform_int_distribution(0, 254);
+ int nG = comphelper::rng::uniform_int_distribution(0, 254);
+ int nB = comphelper::rng::uniform_int_distribution(0, 254);
+ Color aColor(nR, nG, nB);
+ impPaintStrokePolygon(rPolygon, rOutDev, aColor);
+ }
+ }
+ }
+ }
+ }
+} // end of anonymous namespace
+#endif // CLIPPER_TEST
+
+
+void SdrPageWindow::RedrawAll( sdr::contact::ViewObjectContactRedirector* pRedirector )
+{
+ // set Redirector
+ GetObjectContact().SetViewObjectContactRedirector(pRedirector);
+
+ // set PaintingPageView
+ const SdrView& rView = mpImpl->mrPageView.GetView();
+ SdrModel& rModel = *(rView.GetModel());
+
+ // get to be processed layers
+ const bool bPrinter(GetPaintWindow().OutputToPrinter());
+ SdrLayerIDSet aProcessLayers = bPrinter ? mpImpl->mrPageView.GetPrintableLayers() : mpImpl->mrPageView.GetVisibleLayers();
+
+ // create PaintInfoRec; use Rectangle only temporarily
+ const vcl::Region& rRegion = GetPaintWindow().GetRedrawRegion();
+
+ // create processing data
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ // Draw all layers. do NOT draw form layer from CompleteRedraw, this is done separately
+ // as a single layer paint
+ const SdrLayerAdmin& rLayerAdmin = rModel.GetLayerAdmin();
+ const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID(rLayerAdmin.GetControlLayerName());
+ aProcessLayers.Clear(nControlLayerId);
+
+ // still something to paint?
+ if(!aProcessLayers.IsEmpty())
+ {
+ aDisplayInfo.SetProcessLayers(aProcessLayers);
+
+ // Set region as redraw area
+ aDisplayInfo.SetRedrawArea(rRegion);
+
+ // Draw/Impress
+ aDisplayInfo.SetPageProcessingActive(rView.IsPagePaintingAllowed()); // #i72889#
+
+ // paint page
+ GetObjectContact().ProcessDisplay(aDisplayInfo);
+ }
+
+ // reset redirector
+ GetObjectContact().SetViewObjectContactRedirector(nullptr);
+
+ // LineClip test
+#ifdef CLIPPER_TEST
+ if(true)
+ {
+ impTryTest(GetPageView(), GetPaintWindow().GetOutputDevice());
+ }
+#endif // CLIPPER_TEST
+}
+
+void SdrPageWindow::RedrawLayer(const SdrLayerID* pId,
+ sdr::contact::ViewObjectContactRedirector* pRedirector,
+ basegfx::B2IRectangle const*const pPageFrame)
+{
+ // set redirector
+ GetObjectContact().SetViewObjectContactRedirector(pRedirector);
+
+ // set PaintingPageView
+ const SdrView& rView = mpImpl->mrPageView.GetView();
+ SdrModel& rModel = *(rView.GetModel());
+
+ // get the layers to process
+ const bool bPrinter(GetPaintWindow().OutputToPrinter());
+ SdrLayerIDSet aProcessLayers = bPrinter ? mpImpl->mrPageView.GetPrintableLayers() : mpImpl->mrPageView.GetVisibleLayers();
+
+ // is the given layer visible at all?
+ if(aProcessLayers.IsSet(*pId))
+ {
+ // find out if we are painting the ControlLayer
+ const SdrLayerAdmin& rLayerAdmin = rModel.GetLayerAdmin();
+ const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID(rLayerAdmin.GetControlLayerName());
+ const bool bControlLayerProcessingActive(nControlLayerId == *pId);
+
+ // create PaintInfoRec, use Rectangle only temporarily
+ const vcl::Region& rRegion = GetPaintWindow().GetRedrawRegion();
+
+ // create processing data
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ // is it the control layer? If Yes, set flag
+ aDisplayInfo.SetControlLayerProcessingActive(bControlLayerProcessingActive);
+
+ // Draw just the one given layer
+ aProcessLayers.ClearAll();
+ aProcessLayers.Set(*pId);
+
+ aDisplayInfo.SetProcessLayers(aProcessLayers);
+
+ // Set region as redraw area
+ aDisplayInfo.SetRedrawArea(rRegion);
+
+ // Writer or calc, coming from original RedrawOneLayer.
+ // #i72889# no page painting for layer painting
+ aDisplayInfo.SetPageProcessingActive(false);
+
+ if (pPageFrame) // Writer page frame for anchor based clipping
+ {
+ aDisplayInfo.SetWriterPageFrame(*pPageFrame);
+ }
+
+ // paint page
+ GetObjectContact().ProcessDisplay(aDisplayInfo);
+ }
+
+ // reset redirector
+ GetObjectContact().SetViewObjectContactRedirector(nullptr);
+}
+
+// Invalidate call, used from ObjectContact(OfPageView) in InvalidatePartOfView(...)
+void SdrPageWindow::InvalidatePageWindow(const basegfx::B2DRange& rRange)
+{
+ if (GetPageView().IsVisible() && GetPaintWindow().OutputToWindow())
+ {
+ OutputDevice& rWindow(GetPaintWindow().GetOutputDevice());
+ basegfx::B2DRange aDiscreteRange(rRange);
+ aDiscreteRange.transform(rWindow.GetViewTransformation());
+
+ if (SvtOptionsDrawinglayer::IsAntiAliasing())
+ {
+ // invalidate one discrete unit more under the assumption that AA
+ // needs one pixel more
+ aDiscreteRange.grow(1.0);
+ }
+
+ // If the shapes use negative X coordinates, make them positive before sending
+ // the invalidation rectangle.
+ bool bNegativeX = mpImpl->mrPageView.GetView().IsNegativeX();
+
+ const tools::Rectangle aVCLDiscreteRectangle(
+ static_cast<tools::Long>(bNegativeX ? std::max(0.0, ceil(-aDiscreteRange.getMaxX())) : floor(aDiscreteRange.getMinX())),
+ static_cast<tools::Long>(floor(aDiscreteRange.getMinY())),
+ static_cast<tools::Long>(bNegativeX ? std::max(0.0, floor(-aDiscreteRange.getMinX())) : ceil(aDiscreteRange.getMaxX())),
+ static_cast<tools::Long>(ceil(aDiscreteRange.getMaxY())));
+
+ const bool bWasMapModeEnabled(rWindow.IsMapModeEnabled());
+ rWindow.EnableMapMode(false);
+ GetPageView().GetView().InvalidateOneWin(rWindow, aVCLDiscreteRectangle);
+ rWindow.EnableMapMode(bWasMapModeEnabled);
+ }
+ else if (comphelper::LibreOfficeKit::isActive())
+ {
+ // we don't really have to have a paint window with LOK; OTOH we know
+ // that the drawinglayer units are 100ths of mm, so they are easy to
+ // convert to twips
+
+ // If the shapes use negative X coordinates, make them positive before sending
+ // the invalidation rectangle.
+ bool bNegativeX = mpImpl->mrPageView.GetView().IsNegativeX();
+ const tools::Rectangle aRect100thMM(
+ static_cast<tools::Long>(bNegativeX ? std::max(0.0, ceil(-rRange.getMaxX())) : floor(rRange.getMinX())),
+ static_cast<tools::Long>(floor(rRange.getMinY())),
+ static_cast<tools::Long>(bNegativeX ? std::max(0.0, floor(-rRange.getMinX())) : ceil(rRange.getMaxX())),
+ static_cast<tools::Long>(ceil(rRange.getMaxY())));
+
+ const tools::Rectangle aRectTwips = o3tl::convert(aRect100thMM, o3tl::Length::mm100, o3tl::Length::twip);
+
+ if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ SfxLokHelper::notifyInvalidation(pViewShell, &aRectTwips);
+ }
+}
+
+// ObjectContact section
+const sdr::contact::ObjectContact& SdrPageWindow::GetObjectContact() const
+{
+ if (!mpImpl->mpObjectContact)
+ {
+ mpImpl->mpObjectContact = GetPageView().GetView().createViewSpecificObjectContact(
+ const_cast<SdrPageWindow&>(*this),
+ "svx::svdraw::SdrPageWindow mpObjectContact");
+ }
+
+ return *mpImpl->mpObjectContact;
+}
+
+sdr::contact::ObjectContact& SdrPageWindow::GetObjectContact()
+{
+ if (!mpImpl->mpObjectContact)
+ {
+ mpImpl->mpObjectContact = GetPageView().GetView().createViewSpecificObjectContact(
+ *this,
+ "svx::svdraw::SdrPageWindow mpObjectContact" );
+ }
+
+ return *mpImpl->mpObjectContact;
+}
+
+bool SdrPageWindow::HasObjectContact() const
+{
+ return mpImpl->mpObjectContact != nullptr;
+}
+
+// #i26631#
+void SdrPageWindow::ResetObjectContact()
+{
+ if (mpImpl->mpObjectContact)
+ {
+ delete mpImpl->mpObjectContact;
+ mpImpl->mpObjectContact = nullptr;
+ }
+}
+
+void SdrPageWindow::SetDesignMode( bool _bDesignMode ) const
+{
+ const sdr::contact::ObjectContactOfPageView* pOC = dynamic_cast< const sdr::contact::ObjectContactOfPageView* >( &GetObjectContact() );
+ DBG_ASSERT( pOC, "SdrPageWindow::SetDesignMode: invalid object contact!" );
+ if ( pOC )
+ pOC->SetUNOControlsDesignMode( _bDesignMode );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/sdrpaintwindow.cxx b/svx/source/svdraw/sdrpaintwindow.cxx
new file mode 100644
index 000000000..6c3b328ba
--- /dev/null
+++ b/svx/source/svdraw/sdrpaintwindow.cxx
@@ -0,0 +1,346 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+#include <svx/sdrpaintwindow.hxx>
+#include <sdr/overlay/overlaymanagerbuffered.hxx>
+#include <svx/svdpntv.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/window.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <set>
+#include <vector>
+
+namespace {
+
+//rhbz#1007697 do this in two loops, one to collect the candidates
+//and another to update them because updating a candidate can
+//trigger the candidate to be deleted, so asking for its
+//sibling after that is going to fail hard
+class CandidateMgr
+{
+ std::vector<VclPtr<vcl::Window> > m_aCandidates;
+ std::set<VclPtr<vcl::Window> > m_aDeletedCandidates;
+ DECL_LINK(WindowEventListener, VclWindowEvent&, void);
+public:
+ void PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect);
+ ~CandidateMgr();
+};
+
+}
+
+IMPL_LINK(CandidateMgr, WindowEventListener, VclWindowEvent&, rEvent, void)
+{
+ vcl::Window* pWindow = rEvent.GetWindow();
+ if (rEvent.GetId() == VclEventId::ObjectDying)
+ {
+ m_aDeletedCandidates.insert(pWindow);
+ }
+}
+
+CandidateMgr::~CandidateMgr()
+{
+ for (VclPtr<vcl::Window>& pCandidate : m_aCandidates)
+ {
+ if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
+ continue;
+ pCandidate->RemoveEventListener(LINK(this, CandidateMgr, WindowEventListener));
+ }
+}
+
+void PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect)
+{
+ if (!rWindow.IsChildTransparentModeEnabled())
+ return;
+
+ CandidateMgr aManager;
+ aManager.PaintTransparentChildren(rWindow, rPixelRect);
+}
+
+void CandidateMgr::PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect)
+{
+ vcl::Window * pCandidate = rWindow.GetWindow( GetWindowType::FirstChild );
+ while (pCandidate)
+ {
+ if (pCandidate->IsPaintTransparent())
+ {
+ const tools::Rectangle aCandidatePosSizePixel(
+ pCandidate->GetPosPixel(),
+ pCandidate->GetSizePixel());
+
+ if (aCandidatePosSizePixel.Overlaps(rPixelRect))
+ {
+ m_aCandidates.emplace_back(pCandidate);
+ pCandidate->AddEventListener(LINK(this, CandidateMgr, WindowEventListener));
+ }
+ }
+ pCandidate = pCandidate->GetWindow( GetWindowType::Next );
+ }
+
+ for (const auto& rpCandidate : m_aCandidates)
+ {
+ pCandidate = rpCandidate.get();
+ if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
+ continue;
+ //rhbz#1007697 this can cause the window itself to be
+ //deleted. So we are listening to see if that happens
+ //and if so, then skip the update
+ pCandidate->Invalidate(InvalidateFlags::NoTransparent|InvalidateFlags::Children);
+ // important: actually paint the child here!
+ if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
+ continue;
+ pCandidate->PaintImmediately();
+ }
+}
+
+SdrPreRenderDevice::SdrPreRenderDevice(OutputDevice& rOriginal)
+: mpOutputDevice(&rOriginal),
+ mpPreRenderDevice(VclPtr<VirtualDevice>::Create())
+{
+}
+
+SdrPreRenderDevice::~SdrPreRenderDevice()
+{
+ mpPreRenderDevice.disposeAndClear();
+}
+
+void SdrPreRenderDevice::PreparePreRenderDevice()
+{
+ // compare size of mpPreRenderDevice with size of visible area
+ if(mpPreRenderDevice->GetOutputSizePixel() != mpOutputDevice->GetOutputSizePixel())
+ {
+ mpPreRenderDevice->SetOutputSizePixel(mpOutputDevice->GetOutputSizePixel());
+ }
+
+ // Also compare the MapModes for zoom/scroll changes
+ if(mpPreRenderDevice->GetMapMode() != mpOutputDevice->GetMapMode())
+ {
+ mpPreRenderDevice->SetMapMode(mpOutputDevice->GetMapMode());
+ }
+
+ // #i29186#
+ mpPreRenderDevice->SetDrawMode(mpOutputDevice->GetDrawMode());
+ mpPreRenderDevice->SetSettings(mpOutputDevice->GetSettings());
+}
+
+void SdrPreRenderDevice::OutputPreRenderDevice(const vcl::Region& rExpandedRegion)
+{
+ // region to pixels
+ const vcl::Region aRegionPixel(mpOutputDevice->LogicToPixel(rExpandedRegion));
+ //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
+ //Rectangle aRegionRectanglePixel;
+
+ // MapModes off
+ bool bMapModeWasEnabledDest(mpOutputDevice->IsMapModeEnabled());
+ bool bMapModeWasEnabledSource(mpPreRenderDevice->IsMapModeEnabled());
+ mpOutputDevice->EnableMapMode(false);
+ mpPreRenderDevice->EnableMapMode(false);
+
+ RectangleVector aRectangles;
+ aRegionPixel.GetRegionRectangles(aRectangles);
+
+ for(const auto& rRect : aRectangles)
+ {
+ // for each rectangle, copy the area
+ const Point aTopLeft(rRect.TopLeft());
+ const Size aSize(rRect.GetSize());
+
+ mpOutputDevice->DrawOutDev(
+ aTopLeft, aSize,
+ aTopLeft, aSize,
+ *mpPreRenderDevice);
+ }
+
+ mpOutputDevice->EnableMapMode(bMapModeWasEnabledDest);
+ mpPreRenderDevice->EnableMapMode(bMapModeWasEnabledSource);
+}
+
+void SdrPaintView::InitOverlayManager(rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager)
+{
+ Color aColA(SvtOptionsDrawinglayer::GetStripeColorA());
+ Color aColB(SvtOptionsDrawinglayer::GetStripeColorB());
+
+ if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor();
+ aColB.Invert();
+ }
+
+ xOverlayManager->setStripeColorA(aColA);
+ xOverlayManager->setStripeColorB(aColB);
+ xOverlayManager->setStripeLengthPixel(SvtOptionsDrawinglayer::GetStripeLength());
+}
+
+rtl::Reference<sdr::overlay::OverlayManager> SdrPaintView::CreateOverlayManager(OutputDevice& rOutputDevice) const
+{
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager;
+ // is it a window?
+ if (OUTDEV_WINDOW == rOutputDevice.GetOutDevType())
+ {
+ vcl::Window* pWindow = rOutputDevice.GetOwnerWindow();
+ // decide which OverlayManager to use
+ if (IsBufferedOverlayAllowed() && !pWindow->SupportsDoubleBuffering())
+ {
+ // buffered OverlayManager, buffers its background and refreshes from there
+ // for pure overlay changes (no system redraw). The 3rd parameter specifies
+ // whether that refresh itself will use a 2nd vdev to avoid flickering.
+ // Also hand over the old OverlayManager if existent; this means to take over
+ // the registered OverlayObjects from it
+ xOverlayManager = sdr::overlay::OverlayManagerBuffered::create(rOutputDevice);
+ }
+ else
+ {
+ // unbuffered OverlayManager, just invalidates places where changes
+ // take place
+ // Also hand over the old OverlayManager if existent; this means to take over
+ // the registered OverlayObjects from it
+ xOverlayManager = sdr::overlay::OverlayManager::create(rOutputDevice);
+ }
+
+ OSL_ENSURE(xOverlayManager.is(), "SdrPaintWindow::SdrPaintWindow: Could not allocate an overlayManager (!)");
+
+ // Request a repaint so that the buffered overlay manager fills
+ // its buffer properly. This is a workaround for missing buffer
+ // updates.
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ pWindow->Invalidate();
+ }
+
+ InitOverlayManager(xOverlayManager);
+ }
+ return xOverlayManager;
+}
+
+void SdrPaintWindow::impCreateOverlayManager()
+{
+ // not yet one created?
+ if(!mxOverlayManager.is())
+ mxOverlayManager = mrPaintView.CreateOverlayManager(GetOutputDevice());
+}
+
+SdrPaintWindow::SdrPaintWindow(SdrPaintView& rNewPaintView, OutputDevice& rOut, vcl::Window* pWindow)
+: mpOutputDevice(&rOut),
+ mpWindow(pWindow),
+ mrPaintView(rNewPaintView),
+ mbTemporaryTarget(false), // #i72889#
+ mbOutputToWindow(OUTDEV_WINDOW == mpOutputDevice->GetOutDevType()),
+ mpPatched(nullptr)
+{
+}
+
+SdrPaintWindow::~SdrPaintWindow()
+{
+ mxOverlayManager.clear();
+
+ DestroyPreRenderDevice();
+}
+
+rtl::Reference< sdr::overlay::OverlayManager > const & SdrPaintWindow::GetOverlayManager() const
+{
+ if(!mxOverlayManager.is())
+ {
+ // Create buffered overlay manager by default.
+ const_cast< SdrPaintWindow* >(this)->impCreateOverlayManager();
+ }
+
+ return mxOverlayManager;
+}
+
+tools::Rectangle SdrPaintWindow::GetVisibleArea() const
+{
+ Size aVisSizePixel(GetOutputDevice().GetOutputSizePixel());
+ return GetOutputDevice().PixelToLogic(tools::Rectangle(Point(0,0), aVisSizePixel));
+}
+
+bool SdrPaintWindow::OutputToRecordingMetaFile() const
+{
+ GDIMetaFile* pMetaFile = mpOutputDevice->GetConnectMetaFile();
+ return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
+}
+
+void SdrPaintWindow::PreparePreRenderDevice()
+{
+ const bool bPrepareBufferedOutput(
+ mrPaintView.IsBufferedOutputAllowed()
+ && !OutputToPrinter()
+ && !mpOutputDevice->IsVirtual()
+ && !OutputToRecordingMetaFile());
+
+ if(bPrepareBufferedOutput)
+ {
+ if(!mpPreRenderDevice)
+ {
+ mpPreRenderDevice.reset(new SdrPreRenderDevice(*mpOutputDevice));
+ }
+ }
+ else
+ {
+ DestroyPreRenderDevice();
+ }
+
+ if(mpPreRenderDevice)
+ {
+ mpPreRenderDevice->PreparePreRenderDevice();
+ }
+}
+
+void SdrPaintWindow::DestroyPreRenderDevice()
+{
+ mpPreRenderDevice.reset();
+}
+
+void SdrPaintWindow::OutputPreRenderDevice(const vcl::Region& rExpandedRegion)
+{
+ if(mpPreRenderDevice)
+ {
+ mpPreRenderDevice->OutputPreRenderDevice(rExpandedRegion);
+ }
+}
+
+// #i73602# add flag if buffer shall be used
+void SdrPaintWindow::DrawOverlay(const vcl::Region& rRegion)
+{
+ // ## force creation of OverlayManager since the first repaint needs to
+ // save the background to get a controlled start into overlay mechanism
+ impCreateOverlayManager();
+
+ if(mxOverlayManager.is() && !OutputToPrinter())
+ {
+ if(mpPreRenderDevice)
+ {
+ mxOverlayManager->completeRedraw(rRegion, &mpPreRenderDevice->GetPreRenderDevice());
+ }
+ else
+ {
+ mxOverlayManager->completeRedraw(rRegion);
+ }
+ }
+}
+
+
+void SdrPaintWindow::SetRedrawRegion(const vcl::Region& rNew)
+{
+ maRedrawRegion = rNew;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/sdrundomanager.cxx b/svx/source/svdraw/sdrundomanager.cxx
new file mode 100644
index 000000000..3d5fde475
--- /dev/null
+++ b/svx/source/svdraw/sdrundomanager.cxx
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdrundomanager.hxx>
+#include <svx/svdundo.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/hint.hxx>
+
+SdrUndoManager::SdrUndoManager()
+ : EditUndoManager(20 /*nMaxUndoActionCount*/)
+ , mpLastUndoActionBeforeTextEdit(nullptr)
+ , mnRedoActionCountBeforeTextEdit(0)
+ , mbEndTextEditTriggeredFromUndo(false)
+ , m_pDocSh(nullptr)
+{
+}
+
+SdrUndoManager::~SdrUndoManager() {}
+
+bool SdrUndoManager::Undo()
+{
+ if (isTextEditActive())
+ {
+ bool bRetval(false);
+
+ // we are in text edit mode
+ if (GetUndoActionCount() && mpLastUndoActionBeforeTextEdit != GetUndoAction())
+ {
+ // there is an undo action for text edit, trigger it
+ bRetval = EditUndoManager::Undo();
+ }
+ else
+ {
+ // no more text edit undo, end text edit
+ mbEndTextEditTriggeredFromUndo = true;
+ maEndTextEditHdl.Call(this);
+ mbEndTextEditTriggeredFromUndo = false;
+ }
+
+ return bRetval;
+ }
+ else
+ {
+ // no undo triggered up to now, trigger local one
+ return SfxUndoManager::Undo();
+ }
+}
+
+bool SdrUndoManager::Redo()
+{
+ bool bRetval(false);
+ bool bClearRedoStack(false);
+
+ if (isTextEditActive())
+ {
+ // we are in text edit mode
+ bRetval = EditUndoManager::Redo();
+ }
+
+ if (!bRetval)
+ {
+ // Check if the current and thus to-be undone UndoAction is a SdrUndoDiagramModelData action
+ const bool bCurrentIsDiagramChange(
+ GetRedoActionCount()
+ && nullptr != dynamic_cast<SdrUndoDiagramModelData*>(GetRedoAction()));
+
+ // no redo triggered up to now, trigger local one
+ bRetval = SfxUndoManager::Redo();
+
+ // it was a SdrUndoDiagramModelData action and we have more Redo actions
+ if (bCurrentIsDiagramChange && GetRedoActionCount())
+ {
+ const bool bNextIsDiagramChange(
+ nullptr != dynamic_cast<SdrUndoDiagramModelData*>(GetRedoAction()));
+
+ // We have more Redo-actions and the 'next' one to be executed is *not* a
+ // SdrUndoDiagramModelData-action. This means that the already executed
+ // one had done a re-Layout/Re-create of the Diagram XShape/SdrObject
+ // representation based on the restored Diagram ModelData. When the next
+ // Redo action is something else (and thus will not itself re-create
+ // XShapes/SdrShapes) it may be that it is an UnGroup/Delete where a former
+ // as-content-of-Diagram created XShape/SdrShape is referenced, an action
+ // that references a XShape/SdrShape by pointer/reference. That
+ // pointer/reference *cannot* be valid anymore (now).
+
+ // The problem here is that Undo/Redo actions historically reference
+ // XShapes/SdrShapes by pointer/reference, e.g. deleting means: remove
+ // from an SdrObjList and add to an Undo action. I is *not*
+ // address/incarnation-invariant in the sense to remember e.g. to
+ // remove the Nth object in the list (that would work).
+
+ // It might be possible to solve/correct this better, but since it's
+ // a rare corner case just avoid the possible crash when continuing Redos
+ // by clearing the Redo-Stack here as a consequence
+ bClearRedoStack = !bNextIsDiagramChange;
+ }
+ }
+
+ if (bClearRedoStack)
+ {
+ // clear Redo-Stack (explanation see above)
+ ClearRedo();
+ }
+
+ return bRetval;
+}
+
+void SdrUndoManager::Clear()
+{
+ if (isTextEditActive())
+ {
+ while (GetUndoActionCount() && mpLastUndoActionBeforeTextEdit != GetUndoAction())
+ {
+ RemoveLastUndoAction();
+ }
+
+ // urgently needed: RemoveLastUndoAction does NOT correct the Redo stack by itself (!)
+ ClearRedo();
+ }
+ else
+ {
+ // call parent
+ EditUndoManager::Clear();
+ }
+}
+
+void SdrUndoManager::SetEndTextEditHdl(const Link<SdrUndoManager*, void>& rLink)
+{
+ maEndTextEditHdl = rLink;
+
+ if (isTextEditActive())
+ {
+ // text edit start, remember last non-textedit action for later cleanup
+ mpLastUndoActionBeforeTextEdit = GetUndoActionCount() ? GetUndoAction() : nullptr;
+ mnRedoActionCountBeforeTextEdit = GetRedoActionCount();
+ }
+ else
+ {
+ // text edit ends, pop all textedit actions up to the remembered non-textedit action from the start
+ // to set back the UndoManager to the state before text edit started. If that action is already gone
+ // (due to being removed from the undo stack in the meantime), all need to be removed anyways
+ while (GetUndoActionCount() && mpLastUndoActionBeforeTextEdit != GetUndoAction())
+ {
+ RemoveLastUndoAction();
+ }
+
+ // urgently needed: RemoveLastUndoAction does NOT correct the Redo stack by itself (!)
+ ClearRedo();
+
+ // forget marker again
+ mpLastUndoActionBeforeTextEdit = nullptr;
+ mnRedoActionCountBeforeTextEdit = 0;
+ }
+}
+
+bool SdrUndoManager::isTextEditActive() const { return maEndTextEditHdl.IsSet(); }
+
+void SdrUndoManager::SetDocShell(SfxObjectShell* pDocShell) { m_pDocSh = pDocShell; }
+
+void SdrUndoManager::EmptyActionsChanged()
+{
+ if (m_pDocSh)
+ {
+ m_pDocSh->Broadcast(SfxHint(SfxHintId::DocumentRepair));
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/selectioncontroller.cxx b/svx/source/svdraw/selectioncontroller.cxx
new file mode 100644
index 000000000..5f6f51312
--- /dev/null
+++ b/svx/source/svdraw/selectioncontroller.cxx
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/selectioncontroller.hxx>
+
+namespace sdr
+{
+
+bool SelectionController::onKeyInput(const KeyEvent& /*rKEvt*/, vcl::Window* /*pWin*/)
+{
+ return false;
+}
+
+bool SelectionController::onMouseButtonDown(const MouseEvent& /*rMEvt*/, vcl::Window* /*pWin*/)
+{
+ return false;
+}
+
+bool SelectionController::onMouseButtonUp(const MouseEvent& /*rMEvt*/, vcl::Window* /*pWin*/)
+{
+ return false;
+}
+
+bool SelectionController::onMouseMove(const MouseEvent& /*rMEvt*/, vcl::Window* /*pWin*/)
+{
+ return false;
+}
+
+void SelectionController::onSelectionHasChanged()
+{
+}
+
+void SelectionController::onSelectAll()
+{
+}
+
+void SelectionController::GetState( SfxItemSet& /*rSet*/ )
+{
+}
+
+void SelectionController::Execute( SfxRequest& /*rReq*/ )
+{
+}
+
+bool SelectionController::DeleteMarked()
+{
+ return false;
+}
+
+bool SelectionController::GetAttributes(SfxItemSet& /*rTargetSet*/, bool /*bOnlyHardAttr*/) const
+{
+ return false;
+}
+
+bool SelectionController::SetAttributes(const SfxItemSet& /*rSet*/, bool /*bReplaceAll*/)
+{
+ return false;
+}
+
+bool SelectionController::GetStyleSheet( SfxStyleSheet* &/*rpStyleSheet*/ ) const
+{
+ return false;
+}
+
+bool SelectionController::SetStyleSheet( SfxStyleSheet* /*pStyleSheet*/, bool /*bDontRemoveHardAttr*/ )
+{
+ return false;
+}
+
+SdrObject* SelectionController::GetMarkedSdrObjClone( SdrModel& /*rTargetModel*/ )
+{
+ return nullptr;
+}
+
+bool SelectionController::PasteObjModel( const SdrModel& /*rModel*/ )
+{
+ return false;
+}
+
+bool SelectionController::ApplyFormatPaintBrush( SfxItemSet& /*rFormatSet*/, bool /*bNoCharacterFormats*/, bool /*bNoParagraphFormats*/ )
+{
+ return false;
+}
+
+bool SelectionController::hasSelectedCells() const
+{
+ return false;
+}
+
+void SelectionController::getSelectedCells(table::CellPos& /*rFirstPos*/, table::CellPos& /*rLastPos*/)
+{
+}
+
+bool SelectionController::setCursorLogicPosition(const Point& /*rPosition*/, bool /*bPoint*/)
+{
+ return false;
+}
+
+
+bool SelectionController::ChangeFontSize(bool /*bGrow*/, const FontList* /*pFontList*/)
+{
+ return false;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdattr.cxx b/svx/source/svdraw/svdattr.cxx
new file mode 100644
index 000000000..c0057b6ae
--- /dev/null
+++ b/svx/source/svdraw/svdattr.cxx
@@ -0,0 +1,2042 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/TextFitToSizeType.hpp>
+#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
+#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <com/sun/star/drawing/TextAnimationKind.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/drawing/TextAnimationDirection.hpp>
+#include <com/sun/star/drawing/ConnectorType.hpp>
+#include <com/sun/star/drawing/MeasureKind.hpp>
+#include <com/sun/star/drawing/MeasureTextHorzPos.hpp>
+#include <com/sun/star/drawing/MeasureTextVertPos.hpp>
+#include <com/sun/star/drawing/CircleKind.hpp>
+
+#include <editeng/boxitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <editeng/xmlcnitm.hxx>
+#include <editeng/writingmodeitem.hxx>
+#include <editeng/charrotateitem.hxx>
+#include <osl/diagnose.h>
+#include <i18nutil/unicode.hxx>
+#include <tools/bigint.hxx>
+#include <unotools/intlwrapper.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/sdgcpitm.hxx>
+#include <svx/sdtfchim.hxx>
+#include <svx/sdasitm.hxx>
+#include <sdgcoitm.hxx>
+#include <svx/sdggaitm.hxx>
+#include <sdginitm.hxx>
+#include <svx/sdgluitm.hxx>
+#include <svx/sdgmoitm.hxx>
+#include <sdgtritm.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/sdtaaitm.hxx>
+#include <svx/sdtacitm.hxx>
+#include <svx/sdtaditm.hxx>
+#include <svx/sdtaiitm.hxx>
+#include <svx/sdtaitm.hxx>
+#include <svx/sdtakitm.hxx>
+#include <svx/sdtayitm.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svx3ditems.hxx>
+#include <svx/svxids.hrc>
+#include <sxallitm.hxx>
+#include <sxcaitm.hxx>
+#include <svx/sxcecitm.hxx>
+#include <svx/sxcgitm.hxx>
+#include <sxcikitm.hxx>
+#include <svx/sxcllitm.hxx>
+#include <svx/sxctitm.hxx>
+#include <svx/sxekitm.hxx>
+#include <svx/sxelditm.hxx>
+#include <svx/sxenditm.hxx>
+#include <sxfiitm.hxx>
+#include <sxlayitm.hxx>
+#include <sxlogitm.hxx>
+#include <svx/sxmbritm.hxx>
+#include <sxmfsitm.hxx>
+#include <sxmkitm.hxx>
+#include <sxmoitm.hxx>
+#include <sxmovitm.hxx>
+#include <sxmsitm.hxx>
+#include <sxmtaitm.hxx>
+#include <svx/sxmtfitm.hxx>
+#include <svx/sxmtpitm.hxx>
+#include <svx/sxmtritm.hxx>
+#include <svx/sxmuitm.hxx>
+#include <svx/xcolit.hxx>
+#include <sxoneitm.hxx>
+#include <sxopitm.hxx>
+#include <sxreaitm.hxx>
+#include <sxreoitm.hxx>
+#include <sxroaitm.hxx>
+#include <sxrooitm.hxx>
+#include <sxsaitm.hxx>
+#include <sxsalitm.hxx>
+#include <sxsiitm.hxx>
+#include <sxsoitm.hxx>
+#include <sxtraitm.hxx>
+#include <libxml/xmlwriter.h>
+
+using namespace ::com::sun::star;
+
+SdrItemPool::SdrItemPool(
+ SfxItemPool* _pMaster)
+: XOutdevItemPool(_pMaster)
+{
+ // prepare some constants
+ const Color aNullCol(COL_BLACK);
+ const sal_Int32 nDefEdgeDist(500); // Defaulting hard for Draw (100TH_MM) currently. MapMode will have to be taken into account in the future.
+
+ // init the non-persistent items
+ for(sal_uInt16 i(SDRATTR_NOTPERSIST_FIRST); i <= SDRATTR_NOTPERSIST_LAST; i++)
+ {
+ mpLocalItemInfos[i - SDRATTR_START]._bPoolable = false;
+ }
+
+ // init own PoolDefaults
+ std::vector<SfxPoolItem*>& rPoolDefaults = *mpLocalPoolDefaults;
+ rPoolDefaults[SDRATTR_SHADOW -SDRATTR_START]=new SdrOnOffItem(SDRATTR_SHADOW, false);
+ rPoolDefaults[SDRATTR_SHADOWCOLOR -SDRATTR_START]=new XColorItem(SDRATTR_SHADOWCOLOR, aNullCol);
+ rPoolDefaults[SDRATTR_SHADOWXDIST -SDRATTR_START]=new SdrMetricItem(SDRATTR_SHADOWXDIST, 0);
+ rPoolDefaults[SDRATTR_SHADOWYDIST -SDRATTR_START]=new SdrMetricItem(SDRATTR_SHADOWYDIST, 0);
+ rPoolDefaults[SDRATTR_SHADOWSIZEX -SDRATTR_START]=new SdrMetricItem(SDRATTR_SHADOWSIZEX, 100000);
+ rPoolDefaults[SDRATTR_SHADOWSIZEY -SDRATTR_START]=new SdrMetricItem(SDRATTR_SHADOWSIZEY, 100000);
+ rPoolDefaults[SDRATTR_SHADOWTRANSPARENCE-SDRATTR_START]=new SdrPercentItem(SDRATTR_SHADOWTRANSPARENCE, 0);
+ rPoolDefaults[SDRATTR_SHADOWBLUR -SDRATTR_START]=new SdrMetricItem(SDRATTR_SHADOWBLUR, 0);
+ rPoolDefaults[SDRATTR_SHADOW3D -SDRATTR_START]=new SfxVoidItem(SDRATTR_SHADOW3D );
+ rPoolDefaults[SDRATTR_SHADOWPERSP -SDRATTR_START]=new SfxVoidItem(SDRATTR_SHADOWPERSP );
+ rPoolDefaults[SDRATTR_CAPTIONTYPE -SDRATTR_START]=new SdrCaptionTypeItem ;
+ rPoolDefaults[SDRATTR_CAPTIONFIXEDANGLE-SDRATTR_START]=new SdrOnOffItem(SDRATTR_CAPTIONFIXEDANGLE, true);
+ rPoolDefaults[SDRATTR_CAPTIONANGLE -SDRATTR_START]=new SdrCaptionAngleItem ;
+ rPoolDefaults[SDRATTR_CAPTIONGAP -SDRATTR_START]=new SdrCaptionGapItem ;
+ rPoolDefaults[SDRATTR_CAPTIONESCDIR -SDRATTR_START]=new SdrCaptionEscDirItem ;
+ rPoolDefaults[SDRATTR_CAPTIONESCISREL -SDRATTR_START]=new SdrCaptionEscIsRelItem ;
+ rPoolDefaults[SDRATTR_CAPTIONESCREL -SDRATTR_START]=new SdrCaptionEscRelItem ;
+ rPoolDefaults[SDRATTR_CAPTIONESCABS -SDRATTR_START]=new SdrCaptionEscAbsItem ;
+ rPoolDefaults[SDRATTR_CAPTIONLINELEN -SDRATTR_START]=new SdrCaptionLineLenItem ;
+ rPoolDefaults[SDRATTR_CAPTIONFITLINELEN-SDRATTR_START]=new SdrCaptionFitLineLenItem;
+ rPoolDefaults[SDRATTR_CORNER_RADIUS -SDRATTR_START]=new SdrMetricItem(SDRATTR_CORNER_RADIUS, 0);
+ rPoolDefaults[SDRATTR_TEXT_MINFRAMEHEIGHT -SDRATTR_START]=new SdrMetricItem(SDRATTR_TEXT_MINFRAMEHEIGHT, 0);
+ rPoolDefaults[SDRATTR_TEXT_AUTOGROWHEIGHT -SDRATTR_START]=new SdrOnOffItem(SDRATTR_TEXT_AUTOGROWHEIGHT, true);
+ rPoolDefaults[SDRATTR_TEXT_FITTOSIZE -SDRATTR_START]=new SdrTextFitToSizeTypeItem;
+ rPoolDefaults[SDRATTR_TEXT_LEFTDIST -SDRATTR_START]=new SdrMetricItem(SDRATTR_TEXT_LEFTDIST, 0);
+ rPoolDefaults[SDRATTR_TEXT_RIGHTDIST -SDRATTR_START]=new SdrMetricItem(SDRATTR_TEXT_RIGHTDIST, 0);
+ rPoolDefaults[SDRATTR_TEXT_UPPERDIST -SDRATTR_START]=new SdrMetricItem(SDRATTR_TEXT_UPPERDIST, 0);
+ rPoolDefaults[SDRATTR_TEXT_LOWERDIST -SDRATTR_START]=new SdrMetricItem(SDRATTR_TEXT_LOWERDIST, 0);
+ rPoolDefaults[SDRATTR_TEXT_VERTADJUST -SDRATTR_START]=new SdrTextVertAdjustItem;
+ rPoolDefaults[SDRATTR_TEXT_MAXFRAMEHEIGHT -SDRATTR_START]=new SdrMetricItem(SDRATTR_TEXT_MAXFRAMEHEIGHT, 0);
+ rPoolDefaults[SDRATTR_TEXT_MINFRAMEWIDTH -SDRATTR_START]=new SdrMetricItem(SDRATTR_TEXT_MINFRAMEWIDTH, 0);
+ rPoolDefaults[SDRATTR_TEXT_MAXFRAMEWIDTH -SDRATTR_START]=new SdrMetricItem(SDRATTR_TEXT_MAXFRAMEWIDTH, 0);
+ rPoolDefaults[SDRATTR_TEXT_AUTOGROWWIDTH -SDRATTR_START]=new SdrOnOffItem(SDRATTR_TEXT_AUTOGROWWIDTH, false);
+ rPoolDefaults[SDRATTR_TEXT_HORZADJUST -SDRATTR_START]=new SdrTextHorzAdjustItem;
+ rPoolDefaults[SDRATTR_TEXT_ANIKIND -SDRATTR_START]=new SdrTextAniKindItem;
+ rPoolDefaults[SDRATTR_TEXT_ANIDIRECTION -SDRATTR_START]=new SdrTextAniDirectionItem;
+ rPoolDefaults[SDRATTR_TEXT_ANISTARTINSIDE -SDRATTR_START]=new SdrTextAniStartInsideItem;
+ rPoolDefaults[SDRATTR_TEXT_ANISTOPINSIDE -SDRATTR_START]=new SdrTextAniStopInsideItem;
+ rPoolDefaults[SDRATTR_TEXT_ANICOUNT -SDRATTR_START]=new SdrTextAniCountItem;
+ rPoolDefaults[SDRATTR_TEXT_ANIDELAY -SDRATTR_START]=new SdrTextAniDelayItem;
+ rPoolDefaults[SDRATTR_TEXT_ANIAMOUNT -SDRATTR_START]=new SdrTextAniAmountItem;
+ rPoolDefaults[SDRATTR_TEXT_CONTOURFRAME -SDRATTR_START]=new SdrOnOffItem(SDRATTR_TEXT_CONTOURFRAME, false);
+ rPoolDefaults[SDRATTR_XMLATTRIBUTES -SDRATTR_START]=new SvXMLAttrContainerItem( SDRATTR_XMLATTRIBUTES );
+ rPoolDefaults[SDRATTR_TEXT_CHAINNEXTNAME -SDRATTR_START]=new SfxStringItem(SDRATTR_TEXT_CHAINNEXTNAME, "");
+ rPoolDefaults[SDRATTR_TEXT_USEFIXEDCELLHEIGHT -SDRATTR_START]=new SdrTextFixedCellHeightItem;
+ rPoolDefaults[SDRATTR_TEXT_WORDWRAP -SDRATTR_START]=new SdrOnOffItem(SDRATTR_TEXT_WORDWRAP, true);
+ rPoolDefaults[SDRATTR_EDGEKIND -SDRATTR_START]=new SdrEdgeKindItem;
+ rPoolDefaults[SDRATTR_EDGENODE1HORZDIST-SDRATTR_START]=new SdrEdgeNode1HorzDistItem(nDefEdgeDist);
+ rPoolDefaults[SDRATTR_EDGENODE1VERTDIST-SDRATTR_START]=new SdrEdgeNode1VertDistItem(nDefEdgeDist);
+ rPoolDefaults[SDRATTR_EDGENODE2HORZDIST-SDRATTR_START]=new SdrEdgeNode2HorzDistItem(nDefEdgeDist);
+ rPoolDefaults[SDRATTR_EDGENODE2VERTDIST-SDRATTR_START]=new SdrEdgeNode2VertDistItem(nDefEdgeDist);
+ rPoolDefaults[SDRATTR_EDGENODE1GLUEDIST-SDRATTR_START]=new SdrEdgeNode1GlueDistItem;
+ rPoolDefaults[SDRATTR_EDGENODE2GLUEDIST-SDRATTR_START]=new SdrEdgeNode2GlueDistItem;
+ rPoolDefaults[SDRATTR_EDGELINEDELTACOUNT-SDRATTR_START]=new SdrEdgeLineDeltaCountItem;
+ rPoolDefaults[SDRATTR_EDGELINE1DELTA -SDRATTR_START]=new SdrMetricItem(SDRATTR_EDGELINE1DELTA, 0);
+ rPoolDefaults[SDRATTR_EDGELINE2DELTA -SDRATTR_START]=new SdrMetricItem(SDRATTR_EDGELINE2DELTA, 0);
+ rPoolDefaults[SDRATTR_EDGELINE3DELTA -SDRATTR_START]=new SdrMetricItem(SDRATTR_EDGELINE3DELTA, 0);
+ rPoolDefaults[SDRATTR_MEASUREKIND -SDRATTR_START]=new SdrMeasureKindItem;
+ rPoolDefaults[SDRATTR_MEASURETEXTHPOS -SDRATTR_START]=new SdrMeasureTextHPosItem;
+ rPoolDefaults[SDRATTR_MEASURETEXTVPOS -SDRATTR_START]=new SdrMeasureTextVPosItem;
+ rPoolDefaults[SDRATTR_MEASURELINEDIST -SDRATTR_START]=new SdrMetricItem(SDRATTR_MEASURELINEDIST, 800);
+ rPoolDefaults[SDRATTR_MEASUREHELPLINEOVERHANG -SDRATTR_START]=new SdrMetricItem(SDRATTR_MEASUREHELPLINEOVERHANG, 200);
+ rPoolDefaults[SDRATTR_MEASUREHELPLINEDIST -SDRATTR_START]=new SdrMetricItem(SDRATTR_MEASUREHELPLINEDIST, 100);
+ rPoolDefaults[SDRATTR_MEASUREHELPLINE1LEN -SDRATTR_START]=new SdrMetricItem(SDRATTR_MEASUREHELPLINE1LEN, 0);
+ rPoolDefaults[SDRATTR_MEASUREHELPLINE2LEN -SDRATTR_START]=new SdrMetricItem(SDRATTR_MEASUREHELPLINE2LEN, 0);
+ rPoolDefaults[SDRATTR_MEASUREBELOWREFEDGE -SDRATTR_START]=new SdrMeasureBelowRefEdgeItem;
+ rPoolDefaults[SDRATTR_MEASURETEXTROTA90 -SDRATTR_START]=new SdrMeasureTextRota90Item;
+ rPoolDefaults[SDRATTR_MEASURETEXTUPSIDEDOWN -SDRATTR_START]=new SdrMeasureTextUpsideDownItem;
+ rPoolDefaults[SDRATTR_MEASUREOVERHANG -SDRATTR_START]=new SdrMeasureOverhangItem(600);
+ rPoolDefaults[SDRATTR_MEASUREUNIT -SDRATTR_START]=new SdrMeasureUnitItem;
+ rPoolDefaults[SDRATTR_MEASURESCALE -SDRATTR_START]=new SdrMeasureScaleItem;
+ rPoolDefaults[SDRATTR_MEASURESHOWUNIT -SDRATTR_START]=new SdrYesNoItem(SDRATTR_MEASURESHOWUNIT, false);
+ rPoolDefaults[SDRATTR_MEASUREFORMATSTRING -SDRATTR_START]=new SdrMeasureFormatStringItem();
+ rPoolDefaults[SDRATTR_MEASURETEXTAUTOANGLE -SDRATTR_START]=new SdrMeasureTextAutoAngleItem();
+ rPoolDefaults[SDRATTR_MEASURETEXTAUTOANGLEVIEW-SDRATTR_START]=new SdrMeasureTextAutoAngleViewItem();
+ rPoolDefaults[SDRATTR_MEASURETEXTISFIXEDANGLE -SDRATTR_START]=new SdrMeasureTextIsFixedAngleItem();
+ rPoolDefaults[SDRATTR_MEASURETEXTFIXEDANGLE -SDRATTR_START]=new SdrMeasureTextFixedAngleItem();
+ rPoolDefaults[SDRATTR_MEASUREDECIMALPLACES -SDRATTR_START]=new SdrMeasureDecimalPlacesItem();
+ rPoolDefaults[SDRATTR_CIRCKIND -SDRATTR_START]=new SdrCircKindItem;
+ rPoolDefaults[SDRATTR_CIRCSTARTANGLE-SDRATTR_START]=new SdrAngleItem(SDRATTR_CIRCSTARTANGLE, 0_deg100);
+ rPoolDefaults[SDRATTR_CIRCENDANGLE -SDRATTR_START]=new SdrAngleItem(SDRATTR_CIRCENDANGLE, 36000_deg100);
+ rPoolDefaults[SDRATTR_OBJMOVEPROTECT -SDRATTR_START]=new SdrYesNoItem(SDRATTR_OBJMOVEPROTECT, false);
+ rPoolDefaults[SDRATTR_OBJSIZEPROTECT -SDRATTR_START]=new SdrYesNoItem(SDRATTR_OBJSIZEPROTECT, false);
+ rPoolDefaults[SDRATTR_OBJPRINTABLE -SDRATTR_START]=new SdrObjPrintableItem;
+ rPoolDefaults[SDRATTR_OBJVISIBLE -SDRATTR_START]=new SdrObjVisibleItem;
+ rPoolDefaults[SDRATTR_LAYERID -SDRATTR_START]=new SdrLayerIdItem(SdrLayerID(0));
+ rPoolDefaults[SDRATTR_LAYERNAME -SDRATTR_START]=new SdrLayerNameItem;
+ rPoolDefaults[SDRATTR_OBJECTNAME -SDRATTR_START]=new SfxStringItem(SDRATTR_OBJECTNAME);
+ rPoolDefaults[SDRATTR_ALLPOSITIONX -SDRATTR_START]=new SdrAllPositionXItem;
+ rPoolDefaults[SDRATTR_ALLPOSITIONY -SDRATTR_START]=new SdrAllPositionYItem;
+ rPoolDefaults[SDRATTR_ALLSIZEWIDTH -SDRATTR_START]=new SdrAllSizeWidthItem;
+ rPoolDefaults[SDRATTR_ALLSIZEHEIGHT -SDRATTR_START]=new SdrAllSizeHeightItem;
+ rPoolDefaults[SDRATTR_ONEPOSITIONX -SDRATTR_START]=new SdrOnePositionXItem;
+ rPoolDefaults[SDRATTR_ONEPOSITIONY -SDRATTR_START]=new SdrOnePositionYItem;
+ rPoolDefaults[SDRATTR_ONESIZEWIDTH -SDRATTR_START]=new SdrOneSizeWidthItem;
+ rPoolDefaults[SDRATTR_ONESIZEHEIGHT -SDRATTR_START]=new SdrOneSizeHeightItem;
+ rPoolDefaults[SDRATTR_LOGICSIZEWIDTH -SDRATTR_START]=new SdrLogicSizeWidthItem;
+ rPoolDefaults[SDRATTR_LOGICSIZEHEIGHT-SDRATTR_START]=new SdrLogicSizeHeightItem;
+ rPoolDefaults[SDRATTR_ROTATEANGLE -SDRATTR_START]=new SdrAngleItem(SDRATTR_ROTATEANGLE, 0_deg100);
+ rPoolDefaults[SDRATTR_SHEARANGLE -SDRATTR_START]=new SdrShearAngleItem;
+ rPoolDefaults[SDRATTR_MOVEX -SDRATTR_START]=new SdrMoveXItem;
+ rPoolDefaults[SDRATTR_MOVEY -SDRATTR_START]=new SdrMoveYItem;
+ rPoolDefaults[SDRATTR_RESIZEXONE -SDRATTR_START]=new SdrResizeXOneItem;
+ rPoolDefaults[SDRATTR_RESIZEYONE -SDRATTR_START]=new SdrResizeYOneItem;
+ rPoolDefaults[SDRATTR_ROTATEONE -SDRATTR_START]=new SdrRotateOneItem;
+ rPoolDefaults[SDRATTR_HORZSHEARONE -SDRATTR_START]=new SdrHorzShearOneItem;
+ rPoolDefaults[SDRATTR_VERTSHEARONE -SDRATTR_START]=new SdrVertShearOneItem;
+ rPoolDefaults[SDRATTR_RESIZEXALL -SDRATTR_START]=new SdrResizeXAllItem;
+ rPoolDefaults[SDRATTR_RESIZEYALL -SDRATTR_START]=new SdrResizeYAllItem;
+ rPoolDefaults[SDRATTR_ROTATEALL -SDRATTR_START]=new SdrRotateAllItem;
+ rPoolDefaults[SDRATTR_HORZSHEARALL -SDRATTR_START]=new SdrHorzShearAllItem;
+ rPoolDefaults[SDRATTR_VERTSHEARALL -SDRATTR_START]=new SdrVertShearAllItem;
+ rPoolDefaults[SDRATTR_TRANSFORMREF1X -SDRATTR_START]=new SdrTransformRef1XItem;
+ rPoolDefaults[SDRATTR_TRANSFORMREF1Y -SDRATTR_START]=new SdrTransformRef1YItem;
+ rPoolDefaults[SDRATTR_TRANSFORMREF2X -SDRATTR_START]=new SdrTransformRef2XItem;
+ rPoolDefaults[SDRATTR_TRANSFORMREF2Y -SDRATTR_START]=new SdrTransformRef2YItem;
+ rPoolDefaults[SDRATTR_TEXTDIRECTION -SDRATTR_START]=new SvxWritingModeItem(css::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION);
+ rPoolDefaults[ SDRATTR_GRAFRED - SDRATTR_START] = new SdrGrafRedItem;
+ rPoolDefaults[ SDRATTR_GRAFGREEN - SDRATTR_START] = new SdrGrafGreenItem;
+ rPoolDefaults[ SDRATTR_GRAFBLUE - SDRATTR_START] = new SdrGrafBlueItem;
+ rPoolDefaults[ SDRATTR_GRAFLUMINANCE - SDRATTR_START] = new SdrGrafLuminanceItem;
+ rPoolDefaults[ SDRATTR_GRAFCONTRAST - SDRATTR_START] = new SdrGrafContrastItem;
+ rPoolDefaults[ SDRATTR_GRAFGAMMA - SDRATTR_START] = new SdrGrafGamma100Item;
+ rPoolDefaults[ SDRATTR_GRAFTRANSPARENCE - SDRATTR_START] = new SdrGrafTransparenceItem;
+ rPoolDefaults[ SDRATTR_GRAFINVERT - SDRATTR_START] = new SdrGrafInvertItem;
+ rPoolDefaults[ SDRATTR_GRAFMODE - SDRATTR_START] = new SdrGrafModeItem;
+ rPoolDefaults[ SDRATTR_GRAFCROP - SDRATTR_START] = new SdrGrafCropItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_PERCENT_DIAGONAL - SDRATTR_START ] = new SfxUInt16Item(SDRATTR_3DOBJ_PERCENT_DIAGONAL, 10);
+ rPoolDefaults[ SDRATTR_3DOBJ_BACKSCALE - SDRATTR_START ] = new SfxUInt16Item(SDRATTR_3DOBJ_BACKSCALE, 100);
+ rPoolDefaults[ SDRATTR_3DOBJ_DEPTH - SDRATTR_START ] = new SfxUInt32Item(SDRATTR_3DOBJ_DEPTH, 1000);
+ rPoolDefaults[ SDRATTR_3DOBJ_HORZ_SEGS - SDRATTR_START ] = new SfxUInt32Item(SDRATTR_3DOBJ_HORZ_SEGS, 24);
+ rPoolDefaults[ SDRATTR_3DOBJ_VERT_SEGS - SDRATTR_START ] = new SfxUInt32Item(SDRATTR_3DOBJ_VERT_SEGS, 24);
+ rPoolDefaults[ SDRATTR_3DOBJ_END_ANGLE - SDRATTR_START ] = new SfxUInt32Item(SDRATTR_3DOBJ_END_ANGLE, 3600);
+ rPoolDefaults[ SDRATTR_3DOBJ_DOUBLE_SIDED - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DOBJ_DOUBLE_SIDED, false);
+ rPoolDefaults[ SDRATTR_3DOBJ_NORMALS_KIND - SDRATTR_START ] = new Svx3DNormalsKindItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_NORMALS_INVERT - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DOBJ_NORMALS_INVERT, false);
+ rPoolDefaults[ SDRATTR_3DOBJ_TEXTURE_PROJ_X - SDRATTR_START ] = new Svx3DTextureProjectionXItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_TEXTURE_PROJ_Y - SDRATTR_START ] = new Svx3DTextureProjectionYItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_SHADOW_3D - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DOBJ_SHADOW_3D, false);
+ rPoolDefaults[ SDRATTR_3DOBJ_MAT_COLOR - SDRATTR_START ] = new SvxColorItem(Color(0x0000b8ff), SDRATTR_3DOBJ_MAT_COLOR);
+ rPoolDefaults[ SDRATTR_3DOBJ_MAT_EMISSION - SDRATTR_START ] = new SvxColorItem(Color(0x00000000), SDRATTR_3DOBJ_MAT_EMISSION);
+ rPoolDefaults[ SDRATTR_3DOBJ_MAT_SPECULAR - SDRATTR_START ] = new SvxColorItem(Color(0x00ffffff), SDRATTR_3DOBJ_MAT_SPECULAR);
+ rPoolDefaults[ SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY - SDRATTR_START ] = new SfxUInt16Item(SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY, 15);
+ rPoolDefaults[ SDRATTR_3DOBJ_TEXTURE_KIND - SDRATTR_START ] = new Svx3DTextureKindItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_TEXTURE_MODE - SDRATTR_START ] = new Svx3DTextureModeItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_TEXTURE_FILTER - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DOBJ_TEXTURE_FILTER, false);
+ rPoolDefaults[ SDRATTR_3DOBJ_SMOOTH_NORMALS - SDRATTR_START ] = new Svx3DSmoothNormalsItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_SMOOTH_LIDS - SDRATTR_START ] = new Svx3DSmoothLidsItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_CHARACTER_MODE - SDRATTR_START ] = new Svx3DCharacterModeItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_CLOSE_FRONT - SDRATTR_START ] = new Svx3DCloseFrontItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_CLOSE_BACK - SDRATTR_START ] = new Svx3DCloseBackItem;
+ rPoolDefaults[ SDRATTR_3DOBJ_REDUCED_LINE_GEOMETRY - SDRATTR_START ] = new Svx3DReducedLineGeometryItem;
+ rPoolDefaults[ SDRATTR_3DSCENE_PERSPECTIVE - SDRATTR_START ] = new Svx3DPerspectiveItem;
+ rPoolDefaults[ SDRATTR_3DSCENE_DISTANCE - SDRATTR_START ] = new SfxUInt32Item(SDRATTR_3DSCENE_DISTANCE, 100);
+ rPoolDefaults[ SDRATTR_3DSCENE_FOCAL_LENGTH - SDRATTR_START ] = new SfxUInt32Item(SDRATTR_3DSCENE_FOCAL_LENGTH, 100);
+ rPoolDefaults[ SDRATTR_3DSCENE_TWO_SIDED_LIGHTING - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DSCENE_TWO_SIDED_LIGHTING, false);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTCOLOR_1 - SDRATTR_START ] = new SvxColorItem(Color(ColorTransparency, 0xffcccccc), SDRATTR_3DSCENE_LIGHTCOLOR_1);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTCOLOR_2 - SDRATTR_START ] = new SvxColorItem(Color(0x00000000), SDRATTR_3DSCENE_LIGHTCOLOR_2);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTCOLOR_3 - SDRATTR_START ] = new SvxColorItem(Color(0x00000000), SDRATTR_3DSCENE_LIGHTCOLOR_3);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTCOLOR_4 - SDRATTR_START ] = new SvxColorItem(Color(0x00000000), SDRATTR_3DSCENE_LIGHTCOLOR_4);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTCOLOR_5 - SDRATTR_START ] = new SvxColorItem(Color(0x00000000), SDRATTR_3DSCENE_LIGHTCOLOR_5);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTCOLOR_6 - SDRATTR_START ] = new SvxColorItem(Color(0x00000000), SDRATTR_3DSCENE_LIGHTCOLOR_6);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTCOLOR_7 - SDRATTR_START ] = new SvxColorItem(Color(0x00000000), SDRATTR_3DSCENE_LIGHTCOLOR_7);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTCOLOR_8 - SDRATTR_START ] = new SvxColorItem(Color(0x00000000), SDRATTR_3DSCENE_LIGHTCOLOR_8);
+ rPoolDefaults[ SDRATTR_3DSCENE_AMBIENTCOLOR - SDRATTR_START ] = new SvxColorItem(Color(0x00666666), SDRATTR_3DSCENE_AMBIENTCOLOR);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTON_1 - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DSCENE_LIGHTON_1, true);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTON_2 - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DSCENE_LIGHTON_2, false);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTON_3 - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DSCENE_LIGHTON_3, false);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTON_4 - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DSCENE_LIGHTON_4, false);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTON_5 - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DSCENE_LIGHTON_5, false);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTON_6 - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DSCENE_LIGHTON_6, false);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTON_7 - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DSCENE_LIGHTON_7, false);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTON_8 - SDRATTR_START ] = new SfxBoolItem(SDRATTR_3DSCENE_LIGHTON_8, false);
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTDIRECTION_1 - SDRATTR_START ] = new SvxB3DVectorItem(SDRATTR_3DSCENE_LIGHTDIRECTION_1, basegfx::B3DVector(0.57735026918963, 0.57735026918963, 0.57735026918963));
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTDIRECTION_2 - SDRATTR_START ] = new SvxB3DVectorItem(SDRATTR_3DSCENE_LIGHTDIRECTION_2, basegfx::B3DVector(0.0,0.0,1.0));
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTDIRECTION_3 - SDRATTR_START ] = new SvxB3DVectorItem(SDRATTR_3DSCENE_LIGHTDIRECTION_3, basegfx::B3DVector(0.0,0.0,1.0));
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTDIRECTION_4 - SDRATTR_START ] = new SvxB3DVectorItem(SDRATTR_3DSCENE_LIGHTDIRECTION_4, basegfx::B3DVector(0.0,0.0,1.0));
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTDIRECTION_5 - SDRATTR_START ] = new SvxB3DVectorItem(SDRATTR_3DSCENE_LIGHTDIRECTION_5, basegfx::B3DVector(0.0,0.0,1.0));
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTDIRECTION_6 - SDRATTR_START ] = new SvxB3DVectorItem(SDRATTR_3DSCENE_LIGHTDIRECTION_6, basegfx::B3DVector(0.0,0.0,1.0));
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTDIRECTION_7 - SDRATTR_START ] = new SvxB3DVectorItem(SDRATTR_3DSCENE_LIGHTDIRECTION_7, basegfx::B3DVector(0.0,0.0,1.0));
+ rPoolDefaults[ SDRATTR_3DSCENE_LIGHTDIRECTION_8 - SDRATTR_START ] = new SvxB3DVectorItem(SDRATTR_3DSCENE_LIGHTDIRECTION_8, basegfx::B3DVector(0.0,0.0,1.0));
+ rPoolDefaults[ SDRATTR_3DSCENE_SHADOW_SLANT - SDRATTR_START ] = new SfxUInt16Item(SDRATTR_3DSCENE_SHADOW_SLANT, 0);
+ rPoolDefaults[ SDRATTR_3DSCENE_SHADE_MODE - SDRATTR_START ] = new Svx3DShadeModeItem;
+ rPoolDefaults[ SDRATTR_CUSTOMSHAPE_ENGINE - SDRATTR_START ] = new SfxStringItem(SDRATTR_CUSTOMSHAPE_ENGINE, "");
+ rPoolDefaults[ SDRATTR_CUSTOMSHAPE_DATA - SDRATTR_START ] = new SfxStringItem(SDRATTR_CUSTOMSHAPE_DATA, "");
+ rPoolDefaults[ SDRATTR_CUSTOMSHAPE_GEOMETRY - SDRATTR_START ] = new SdrCustomShapeGeometryItem;
+
+ SvxBoxItem* pboxItem = new SvxBoxItem( SDRATTR_TABLE_BORDER );
+ pboxItem->SetAllDistances( 100 );
+ rPoolDefaults[ SDRATTR_TABLE_BORDER - SDRATTR_START ] = pboxItem;
+
+ SvxBoxInfoItem* pBoxInfoItem = new SvxBoxInfoItem( SDRATTR_TABLE_BORDER_INNER );
+
+ pBoxInfoItem->SetTable( true );
+ pBoxInfoItem->SetDist( true); // always show margin field
+ pBoxInfoItem->SetValid( SvxBoxInfoItemValidFlags::DISABLE ); // some lines may have DontCare state only in tables
+
+ rPoolDefaults[ SDRATTR_TABLE_BORDER_INNER - SDRATTR_START ] = pBoxInfoItem;
+ rPoolDefaults[ SDRATTR_TABLE_BORDER_TLBR - SDRATTR_START ] = new SvxLineItem( SDRATTR_TABLE_BORDER_TLBR );
+ rPoolDefaults[ SDRATTR_TABLE_BORDER_BLTR - SDRATTR_START ] = new SvxLineItem( SDRATTR_TABLE_BORDER_BLTR );
+ rPoolDefaults[ SDRATTR_TABLE_TEXT_ROTATION - SDRATTR_START ] = new SvxTextRotateItem(0_deg10, SDRATTR_TABLE_TEXT_ROTATION);
+
+ rPoolDefaults[ SDRATTR_GLOW_RADIUS - SDRATTR_START ] = new SdrMetricItem(SDRATTR_GLOW_RADIUS, 0);
+ rPoolDefaults[ SDRATTR_GLOW_COLOR - SDRATTR_START ] = new XColorItem(SDRATTR_GLOW_COLOR, aNullCol);
+ rPoolDefaults[ SDRATTR_GLOW_TRANSPARENCY - SDRATTR_START ] = new SdrPercentItem(SDRATTR_GLOW_TRANSPARENCY, 0);
+
+ rPoolDefaults[SDRATTR_SOFTEDGE_RADIUS - SDRATTR_START] = new SdrMetricItem(SDRATTR_SOFTEDGE_RADIUS, 0);
+
+ rPoolDefaults[SDRATTR_TEXTCOLUMNS_NUMBER - SDRATTR_START] = new SfxInt16Item(SDRATTR_TEXTCOLUMNS_NUMBER, 1);
+ rPoolDefaults[SDRATTR_TEXTCOLUMNS_SPACING - SDRATTR_START] = new SdrMetricItem(SDRATTR_TEXTCOLUMNS_SPACING, 0);
+
+ // set own ItemInfos
+ mpLocalItemInfos[SDRATTR_SHADOW-SDRATTR_START]._nSID=SID_ATTR_FILL_SHADOW;
+ mpLocalItemInfos[SDRATTR_SHADOWCOLOR-SDRATTR_START]._nSID=SID_ATTR_SHADOW_COLOR;
+ mpLocalItemInfos[SDRATTR_SHADOWTRANSPARENCE-SDRATTR_START]._nSID=SID_ATTR_SHADOW_TRANSPARENCE;
+ mpLocalItemInfos[SDRATTR_SHADOWBLUR-SDRATTR_START]._nSID=SID_ATTR_SHADOW_BLUR;
+ mpLocalItemInfos[SDRATTR_SHADOWXDIST-SDRATTR_START]._nSID=SID_ATTR_SHADOW_XDISTANCE;
+ mpLocalItemInfos[SDRATTR_SHADOWYDIST-SDRATTR_START]._nSID=SID_ATTR_SHADOW_YDISTANCE;
+ mpLocalItemInfos[SDRATTR_TEXT_FITTOSIZE-SDRATTR_START]._nSID=SID_ATTR_TEXT_FITTOSIZE;
+ mpLocalItemInfos[SDRATTR_GRAFCROP-SDRATTR_START]._nSID=SID_ATTR_GRAF_CROP;
+
+ mpLocalItemInfos[SDRATTR_TABLE_BORDER - SDRATTR_START ]._nSID = SID_ATTR_BORDER_OUTER;
+ mpLocalItemInfos[SDRATTR_TABLE_BORDER_INNER - SDRATTR_START ]._nSID = SID_ATTR_BORDER_INNER;
+ mpLocalItemInfos[SDRATTR_TABLE_BORDER_TLBR - SDRATTR_START ]._nSID = SID_ATTR_BORDER_DIAG_TLBR;
+ mpLocalItemInfos[SDRATTR_TABLE_BORDER_BLTR - SDRATTR_START ]._nSID = SID_ATTR_BORDER_DIAG_BLTR;
+
+ mpLocalItemInfos[SDRATTR_GLOW_RADIUS - SDRATTR_START]._nSID = SID_ATTR_GLOW_RADIUS;
+ mpLocalItemInfos[SDRATTR_GLOW_COLOR - SDRATTR_START]._nSID = SID_ATTR_GLOW_COLOR;
+ mpLocalItemInfos[SDRATTR_GLOW_TRANSPARENCY - SDRATTR_START]._nSID = SID_ATTR_GLOW_TRANSPARENCY;
+
+ mpLocalItemInfos[SDRATTR_SOFTEDGE_RADIUS - SDRATTR_START]._nSID = SID_ATTR_SOFTEDGE_RADIUS;
+
+ mpLocalItemInfos[SDRATTR_TEXTCOLUMNS_NUMBER - SDRATTR_START]._nSID = 0 /*TODO*/;
+ mpLocalItemInfos[SDRATTR_TEXTCOLUMNS_SPACING - SDRATTR_START]._nSID = 0 /*TODO*/;
+
+ // it's my own creation level, set Defaults and ItemInfos
+ SetDefaults(mpLocalPoolDefaults);
+ SetItemInfos(mpLocalItemInfos.get());
+}
+
+// copy ctor, so that static defaults are cloned
+// (Parameter 2 = sal_True)
+SdrItemPool::SdrItemPool(const SdrItemPool& rPool)
+: XOutdevItemPool(rPool)
+{
+}
+
+rtl::Reference<SfxItemPool> SdrItemPool::Clone() const
+{
+ return new SdrItemPool(*this);
+}
+
+SdrItemPool::~SdrItemPool()
+{
+ // split pools before destroying
+ SetSecondaryPool(nullptr);
+}
+
+bool SdrItemPool::GetPresentation(
+ const SfxPoolItem& rItem,
+ MapUnit ePresentationMetric, OUString& rText,
+ const IntlWrapper& rIntlWrapper) const
+{
+ if (!IsInvalidItem(&rItem)) {
+ sal_uInt16 nWhich=rItem.Which();
+ if (nWhich>=SDRATTR_SHADOW_FIRST && nWhich<=SDRATTR_END) {
+ rItem.GetPresentation(SfxItemPresentation::Nameless,
+ GetMetric(nWhich),ePresentationMetric,rText,
+ rIntlWrapper);
+ rText = GetItemName(nWhich) + " " + rText;
+
+ return true;
+ }
+ }
+ return XOutdevItemPool::GetPresentation(rItem,ePresentationMetric,rText,rIntlWrapper);
+}
+
+OUString SdrItemPool::GetItemName(sal_uInt16 nWhich)
+{
+ TranslateId pResId = SIP_UNKNOWN_ATTR;
+
+ switch (nWhich)
+ {
+ case XATTR_LINESTYLE : pResId = SIP_XA_LINESTYLE;break;
+ case XATTR_LINEDASH : pResId = SIP_XA_LINEDASH;break;
+ case XATTR_LINEWIDTH : pResId = SIP_XA_LINEWIDTH;break;
+ case XATTR_LINECOLOR : pResId = SIP_XA_LINECOLOR;break;
+ case XATTR_LINESTART : pResId = SIP_XA_LINESTART;break;
+ case XATTR_LINEEND : pResId = SIP_XA_LINEEND;break;
+ case XATTR_LINESTARTWIDTH : pResId = SIP_XA_LINESTARTWIDTH;break;
+ case XATTR_LINEENDWIDTH : pResId = SIP_XA_LINEENDWIDTH;break;
+ case XATTR_LINESTARTCENTER : pResId = SIP_XA_LINESTARTCENTER;break;
+ case XATTR_LINEENDCENTER : pResId = SIP_XA_LINEENDCENTER;break;
+ case XATTR_LINETRANSPARENCE : pResId = SIP_XA_LINETRANSPARENCE;break;
+ case XATTR_LINEJOINT : pResId = SIP_XA_LINEJOINT;break;
+ case XATTRSET_LINE : pResId = SIP_XATTRSET_LINE;break;
+
+ case XATTR_FILLSTYLE : pResId = SIP_XA_FILLSTYLE;break;
+ case XATTR_FILLCOLOR : pResId = SIP_XA_FILLCOLOR;break;
+ case XATTR_FILLGRADIENT : pResId = SIP_XA_FILLGRADIENT;break;
+ case XATTR_FILLHATCH : pResId = SIP_XA_FILLHATCH;break;
+ case XATTR_FILLBITMAP : pResId = SIP_XA_FILLBITMAP;break;
+ case XATTR_FILLTRANSPARENCE : pResId = SIP_XA_FILLTRANSPARENCE;break;
+ case XATTR_GRADIENTSTEPCOUNT : pResId = SIP_XA_GRADIENTSTEPCOUNT;break;
+ case XATTR_FILLBMP_TILE : pResId = SIP_XA_FILLBMP_TILE;break;
+ case XATTR_FILLBMP_POS : pResId = SIP_XA_FILLBMP_POS;break;
+ case XATTR_FILLBMP_SIZEX : pResId = SIP_XA_FILLBMP_SIZEX;break;
+ case XATTR_FILLBMP_SIZEY : pResId = SIP_XA_FILLBMP_SIZEY;break;
+ case XATTR_FILLFLOATTRANSPARENCE: pResId = SIP_XA_FILLFLOATTRANSPARENCE;break;
+ case XATTR_SECONDARYFILLCOLOR : pResId = SIP_XA_SECONDARYFILLCOLOR;break;
+ case XATTR_FILLBMP_SIZELOG : pResId = SIP_XA_FILLBMP_SIZELOG;break;
+ case XATTR_FILLBMP_TILEOFFSETX : pResId = SIP_XA_FILLBMP_TILEOFFSETX;break;
+ case XATTR_FILLBMP_TILEOFFSETY : pResId = SIP_XA_FILLBMP_TILEOFFSETY;break;
+ case XATTR_FILLBMP_STRETCH : pResId = SIP_XA_FILLBMP_STRETCH;break;
+ case XATTR_FILLBMP_POSOFFSETX : pResId = SIP_XA_FILLBMP_POSOFFSETX;break;
+ case XATTR_FILLBMP_POSOFFSETY : pResId = SIP_XA_FILLBMP_POSOFFSETY;break;
+ case XATTR_FILLBACKGROUND : pResId = SIP_XA_FILLBACKGROUND;break;
+ case XATTR_FILLUSESLIDEBACKGROUND: pResId = SIP_XA_FILLUSESLIDEBACKGROUND;break;
+
+ case XATTRSET_FILL : pResId = SIP_XATTRSET_FILL;break;
+
+ case XATTR_FORMTXTSTYLE : pResId = SIP_XA_FORMTXTSTYLE;break;
+ case XATTR_FORMTXTADJUST : pResId = SIP_XA_FORMTXTADJUST;break;
+ case XATTR_FORMTXTDISTANCE : pResId = SIP_XA_FORMTXTDISTANCE;break;
+ case XATTR_FORMTXTSTART : pResId = SIP_XA_FORMTXTSTART;break;
+ case XATTR_FORMTXTMIRROR : pResId = SIP_XA_FORMTXTMIRROR;break;
+ case XATTR_FORMTXTOUTLINE : pResId = SIP_XA_FORMTXTOUTLINE;break;
+ case XATTR_FORMTXTSHADOW : pResId = SIP_XA_FORMTXTSHADOW;break;
+ case XATTR_FORMTXTSHDWCOLOR : pResId = SIP_XA_FORMTXTSHDWCOLOR;break;
+ case XATTR_FORMTXTSHDWXVAL : pResId = SIP_XA_FORMTXTSHDWXVAL;break;
+ case XATTR_FORMTXTSHDWYVAL : pResId = SIP_XA_FORMTXTSHDWYVAL;break;
+ case XATTR_FORMTXTHIDEFORM : pResId = SIP_XA_FORMTXTHIDEFORM;break;
+ case XATTR_FORMTXTSHDWTRANSP: pResId = SIP_XA_FORMTXTSHDWTRANSP;break;
+
+ case SDRATTR_SHADOW : pResId = SIP_SA_SHADOW;break;
+ case SDRATTR_SHADOWCOLOR : pResId = SIP_SA_SHADOWCOLOR;break;
+ case SDRATTR_SHADOWXDIST : pResId = SIP_SA_SHADOWXDIST;break;
+ case SDRATTR_SHADOWYDIST : pResId = SIP_SA_SHADOWYDIST;break;
+ case SDRATTR_SHADOWTRANSPARENCE: pResId = SIP_SA_SHADOWTRANSPARENCE;break;
+ case SDRATTR_SHADOWBLUR : pResId = SIP_SA_SHADOWBLUR;break;
+ case SDRATTR_SHADOW3D : pResId = SIP_SA_SHADOW3D;break;
+ case SDRATTR_SHADOWPERSP : pResId = SIP_SA_SHADOWPERSP;break;
+
+ case SDRATTR_GLOW_RADIUS : pResId = SIP_SA_GLOW_RADIUS;break;
+ case SDRATTR_GLOW_COLOR : pResId = SIP_SA_GLOW_COLOR;break;
+ case SDRATTR_GLOW_TRANSPARENCY : pResId = SIP_SA_GLOW_TRANSPARENCY;break;
+
+ case SDRATTR_SOFTEDGE_RADIUS : pResId = SIP_SA_SOFTEDGE_RADIUS; break;
+
+ case SDRATTR_CAPTIONTYPE : pResId = SIP_SA_CAPTIONTYPE;break;
+ case SDRATTR_CAPTIONFIXEDANGLE: pResId = SIP_SA_CAPTIONFIXEDANGLE;break;
+ case SDRATTR_CAPTIONANGLE : pResId = SIP_SA_CAPTIONANGLE;break;
+ case SDRATTR_CAPTIONGAP : pResId = SIP_SA_CAPTIONGAP;break;
+ case SDRATTR_CAPTIONESCDIR : pResId = SIP_SA_CAPTIONESCDIR;break;
+ case SDRATTR_CAPTIONESCISREL : pResId = SIP_SA_CAPTIONESCISREL;break;
+ case SDRATTR_CAPTIONESCREL : pResId = SIP_SA_CAPTIONESCREL;break;
+ case SDRATTR_CAPTIONESCABS : pResId = SIP_SA_CAPTIONESCABS;break;
+ case SDRATTR_CAPTIONLINELEN : pResId = SIP_SA_CAPTIONLINELEN;break;
+ case SDRATTR_CAPTIONFITLINELEN: pResId = SIP_SA_CAPTIONFITLINELEN;break;
+
+ case SDRATTR_CORNER_RADIUS : pResId = SIP_SA_CORNER_RADIUS;break;
+ case SDRATTR_TEXT_MINFRAMEHEIGHT : pResId = SIP_SA_TEXT_MINFRAMEHEIGHT;break;
+ case SDRATTR_TEXT_AUTOGROWHEIGHT : pResId = SIP_SA_TEXT_AUTOGROWHEIGHT;break;
+ case SDRATTR_TEXT_FITTOSIZE : pResId = SIP_SA_TEXT_FITTOSIZE;break;
+ case SDRATTR_TEXT_LEFTDIST : pResId = SIP_SA_TEXT_LEFTDIST;break;
+ case SDRATTR_TEXT_RIGHTDIST : pResId = SIP_SA_TEXT_RIGHTDIST;break;
+ case SDRATTR_TEXT_UPPERDIST : pResId = SIP_SA_TEXT_UPPERDIST;break;
+ case SDRATTR_TEXT_LOWERDIST : pResId = SIP_SA_TEXT_LOWERDIST;break;
+ case SDRATTR_TEXT_VERTADJUST : pResId = SIP_SA_TEXT_VERTADJUST;break;
+ case SDRATTR_TEXT_MAXFRAMEHEIGHT : pResId = SIP_SA_TEXT_MAXFRAMEHEIGHT;break;
+ case SDRATTR_TEXT_MINFRAMEWIDTH : pResId = SIP_SA_TEXT_MINFRAMEWIDTH;break;
+ case SDRATTR_TEXT_MAXFRAMEWIDTH : pResId = SIP_SA_TEXT_MAXFRAMEWIDTH;break;
+ case SDRATTR_TEXT_AUTOGROWWIDTH : pResId = SIP_SA_TEXT_AUTOGROWWIDTH;break;
+ case SDRATTR_TEXT_HORZADJUST : pResId = SIP_SA_TEXT_HORZADJUST;break;
+ case SDRATTR_TEXT_ANIKIND : pResId = SIP_SA_TEXT_ANIKIND;break;
+ case SDRATTR_TEXT_ANIDIRECTION : pResId = SIP_SA_TEXT_ANIDIRECTION;break;
+ case SDRATTR_TEXT_ANISTARTINSIDE : pResId = SIP_SA_TEXT_ANISTARTINSIDE;break;
+ case SDRATTR_TEXT_ANISTOPINSIDE : pResId = SIP_SA_TEXT_ANISTOPINSIDE;break;
+ case SDRATTR_TEXT_ANICOUNT : pResId = SIP_SA_TEXT_ANICOUNT;break;
+ case SDRATTR_TEXT_ANIDELAY : pResId = SIP_SA_TEXT_ANIDELAY;break;
+ case SDRATTR_TEXT_ANIAMOUNT : pResId = SIP_SA_TEXT_ANIAMOUNT;break;
+ case SDRATTR_TEXT_CONTOURFRAME : pResId = SIP_SA_TEXT_CONTOURFRAME;break;
+ case SDRATTR_XMLATTRIBUTES : pResId = SIP_SA_XMLATTRIBUTES;break;
+ case SDRATTR_TEXT_USEFIXEDCELLHEIGHT: pResId = SIP_SA_TEXT_USEFIXEDCELLHEIGHT;break;
+ case SDRATTR_TEXT_WORDWRAP : pResId = SIP_SA_WORDWRAP;break;
+ case SDRATTR_TEXT_CHAINNEXTNAME : pResId = SIP_SA_CHAINNEXTNAME;break;
+
+ case SDRATTR_EDGEKIND : pResId = SIP_SA_EDGEKIND;break;
+ case SDRATTR_EDGENODE1HORZDIST : pResId = SIP_SA_EDGENODE1HORZDIST;break;
+ case SDRATTR_EDGENODE1VERTDIST : pResId = SIP_SA_EDGENODE1VERTDIST;break;
+ case SDRATTR_EDGENODE2HORZDIST : pResId = SIP_SA_EDGENODE2HORZDIST;break;
+ case SDRATTR_EDGENODE2VERTDIST : pResId = SIP_SA_EDGENODE2VERTDIST;break;
+ case SDRATTR_EDGENODE1GLUEDIST : pResId = SIP_SA_EDGENODE1GLUEDIST;break;
+ case SDRATTR_EDGENODE2GLUEDIST : pResId = SIP_SA_EDGENODE2GLUEDIST;break;
+ case SDRATTR_EDGELINEDELTACOUNT : pResId = SIP_SA_EDGELINEDELTACOUNT;break;
+ case SDRATTR_EDGELINE1DELTA : pResId = SIP_SA_EDGELINE1DELTA;break;
+ case SDRATTR_EDGELINE2DELTA : pResId = SIP_SA_EDGELINE2DELTA;break;
+ case SDRATTR_EDGELINE3DELTA : pResId = SIP_SA_EDGELINE3DELTA;break;
+
+ case SDRATTR_MEASUREKIND : pResId = SIP_SA_MEASUREKIND;break;
+ case SDRATTR_MEASURETEXTHPOS : pResId = SIP_SA_MEASURETEXTHPOS;break;
+ case SDRATTR_MEASURETEXTVPOS : pResId = SIP_SA_MEASURETEXTVPOS;break;
+ case SDRATTR_MEASURELINEDIST : pResId = SIP_SA_MEASURELINEDIST;break;
+ case SDRATTR_MEASUREHELPLINEOVERHANG : pResId = SIP_SA_MEASUREHELPLINEOVERHANG;break;
+ case SDRATTR_MEASUREHELPLINEDIST : pResId = SIP_SA_MEASUREHELPLINEDIST;break;
+ case SDRATTR_MEASUREHELPLINE1LEN : pResId = SIP_SA_MEASUREHELPLINE1LEN;break;
+ case SDRATTR_MEASUREHELPLINE2LEN : pResId = SIP_SA_MEASUREHELPLINE2LEN;break;
+ case SDRATTR_MEASUREBELOWREFEDGE : pResId = SIP_SA_MEASUREBELOWREFEDGE;break;
+ case SDRATTR_MEASURETEXTROTA90 : pResId = SIP_SA_MEASURETEXTROTA90;break;
+ case SDRATTR_MEASURETEXTUPSIDEDOWN : pResId = SIP_SA_MEASURETEXTUPSIDEDOWN;break;
+ case SDRATTR_MEASUREOVERHANG : pResId = SIP_SA_MEASUREOVERHANG;break;
+ case SDRATTR_MEASUREUNIT : pResId = SIP_SA_MEASUREUNIT;break;
+ case SDRATTR_MEASURESCALE : pResId = SIP_SA_MEASURESCALE;break;
+ case SDRATTR_MEASURESHOWUNIT : pResId = SIP_SA_MEASURESHOWUNIT;break;
+ case SDRATTR_MEASUREFORMATSTRING : pResId = SIP_SA_MEASUREFORMATSTRING;break;
+ case SDRATTR_MEASURETEXTAUTOANGLE : pResId = SIP_SA_MEASURETEXTAUTOANGLE;break;
+ case SDRATTR_MEASURETEXTAUTOANGLEVIEW: pResId = SIP_SA_MEASURETEXTAUTOANGLEVIEW;break;
+ case SDRATTR_MEASURETEXTISFIXEDANGLE : pResId = SIP_SA_MEASURETEXTISFIXEDANGLE;break;
+ case SDRATTR_MEASURETEXTFIXEDANGLE : pResId = SIP_SA_MEASURETEXTFIXEDANGLE;break;
+ case SDRATTR_MEASUREDECIMALPLACES : pResId = SIP_SA_MEASUREDECIMALPLACES;break;
+
+ case SDRATTR_CIRCKIND : pResId = SIP_SA_CIRCKIND;break;
+ case SDRATTR_CIRCSTARTANGLE: pResId = SIP_SA_CIRCSTARTANGLE;break;
+ case SDRATTR_CIRCENDANGLE : pResId = SIP_SA_CIRCENDANGLE;break;
+
+ case SDRATTR_OBJMOVEPROTECT : pResId = SIP_SA_OBJMOVEPROTECT;break;
+ case SDRATTR_OBJSIZEPROTECT : pResId = SIP_SA_OBJSIZEPROTECT;break;
+ case SDRATTR_OBJPRINTABLE : pResId = SIP_SA_OBJPRINTABLE;break;
+ case SDRATTR_OBJVISIBLE : pResId = SIP_SA_OBJVISIBLE;break;
+ case SDRATTR_LAYERID : pResId = SIP_SA_LAYERID;break;
+ case SDRATTR_LAYERNAME : pResId = SIP_SA_LAYERNAME;break;
+ case SDRATTR_OBJECTNAME : pResId = SIP_SA_OBJECTNAME;break;
+ case SDRATTR_ALLPOSITIONX : pResId = SIP_SA_ALLPOSITIONX;break;
+ case SDRATTR_ALLPOSITIONY : pResId = SIP_SA_ALLPOSITIONY;break;
+ case SDRATTR_ALLSIZEWIDTH : pResId = SIP_SA_ALLSIZEWIDTH;break;
+ case SDRATTR_ALLSIZEHEIGHT : pResId = SIP_SA_ALLSIZEHEIGHT;break;
+ case SDRATTR_ONEPOSITIONX : pResId = SIP_SA_ONEPOSITIONX;break;
+ case SDRATTR_ONEPOSITIONY : pResId = SIP_SA_ONEPOSITIONY;break;
+ case SDRATTR_ONESIZEWIDTH : pResId = SIP_SA_ONESIZEWIDTH;break;
+ case SDRATTR_ONESIZEHEIGHT : pResId = SIP_SA_ONESIZEHEIGHT;break;
+ case SDRATTR_LOGICSIZEWIDTH : pResId = SIP_SA_LOGICSIZEWIDTH;break;
+ case SDRATTR_LOGICSIZEHEIGHT: pResId = SIP_SA_LOGICSIZEHEIGHT;break;
+ case SDRATTR_ROTATEANGLE : pResId = SIP_SA_ROTATEANGLE;break;
+ case SDRATTR_SHEARANGLE : pResId = SIP_SA_SHEARANGLE;break;
+ case SDRATTR_MOVEX : pResId = SIP_SA_MOVEX;break;
+ case SDRATTR_MOVEY : pResId = SIP_SA_MOVEY;break;
+ case SDRATTR_RESIZEXONE : pResId = SIP_SA_RESIZEXONE;break;
+ case SDRATTR_RESIZEYONE : pResId = SIP_SA_RESIZEYONE;break;
+ case SDRATTR_ROTATEONE : pResId = SIP_SA_ROTATEONE;break;
+ case SDRATTR_HORZSHEARONE : pResId = SIP_SA_HORZSHEARONE;break;
+ case SDRATTR_VERTSHEARONE : pResId = SIP_SA_VERTSHEARONE;break;
+ case SDRATTR_RESIZEXALL : pResId = SIP_SA_RESIZEXALL;break;
+ case SDRATTR_RESIZEYALL : pResId = SIP_SA_RESIZEYALL;break;
+ case SDRATTR_ROTATEALL : pResId = SIP_SA_ROTATEALL;break;
+ case SDRATTR_HORZSHEARALL : pResId = SIP_SA_HORZSHEARALL;break;
+ case SDRATTR_VERTSHEARALL : pResId = SIP_SA_VERTSHEARALL;break;
+ case SDRATTR_TRANSFORMREF1X : pResId = SIP_SA_TRANSFORMREF1X;break;
+ case SDRATTR_TRANSFORMREF1Y : pResId = SIP_SA_TRANSFORMREF1Y;break;
+ case SDRATTR_TRANSFORMREF2X : pResId = SIP_SA_TRANSFORMREF2X;break;
+ case SDRATTR_TRANSFORMREF2Y : pResId = SIP_SA_TRANSFORMREF2Y;break;
+
+ case SDRATTR_GRAFRED : pResId = SIP_SA_GRAFRED;break;
+ case SDRATTR_GRAFGREEN : pResId = SIP_SA_GRAFGREEN;break;
+ case SDRATTR_GRAFBLUE : pResId = SIP_SA_GRAFBLUE;break;
+ case SDRATTR_GRAFLUMINANCE : pResId = SIP_SA_GRAFLUMINANCE;break;
+ case SDRATTR_GRAFCONTRAST : pResId = SIP_SA_GRAFCONTRAST;break;
+ case SDRATTR_GRAFGAMMA : pResId = SIP_SA_GRAFGAMMA;break;
+ case SDRATTR_GRAFTRANSPARENCE : pResId = SIP_SA_GRAFTRANSPARENCE;break;
+ case SDRATTR_GRAFINVERT : pResId = SIP_SA_GRAFINVERT;break;
+ case SDRATTR_GRAFMODE : pResId = SIP_SA_GRAFMODE;break;
+ case SDRATTR_GRAFCROP : pResId = SIP_SA_GRAFCROP;break;
+
+ case EE_PARA_HYPHENATE : pResId = SIP_EE_PARA_HYPHENATE;break;
+ case EE_PARA_BULLETSTATE: pResId = SIP_EE_PARA_BULLETSTATE;break;
+ case EE_PARA_OUTLLRSPACE: pResId = SIP_EE_PARA_OUTLLRSPACE;break;
+ case EE_PARA_OUTLLEVEL : pResId = SIP_EE_PARA_OUTLLEVEL;break;
+ case EE_PARA_BULLET : pResId = SIP_EE_PARA_BULLET;break;
+ case EE_PARA_LRSPACE : pResId = SIP_EE_PARA_LRSPACE;break;
+ case EE_PARA_ULSPACE : pResId = SIP_EE_PARA_ULSPACE;break;
+ case EE_PARA_SBL : pResId = SIP_EE_PARA_SBL;break;
+ case EE_PARA_JUST : pResId = SIP_EE_PARA_JUST;break;
+ case EE_PARA_TABS : pResId = SIP_EE_PARA_TABS;break;
+
+ case EE_CHAR_COLOR : pResId = SIP_EE_CHAR_COLOR;break;
+ case EE_CHAR_FONTINFO : pResId = SIP_EE_CHAR_FONTINFO;break;
+ case EE_CHAR_FONTHEIGHT : pResId = SIP_EE_CHAR_FONTHEIGHT;break;
+ case EE_CHAR_FONTWIDTH : pResId = SIP_EE_CHAR_FONTWIDTH;break;
+ case EE_CHAR_WEIGHT : pResId = SIP_EE_CHAR_WEIGHT;break;
+ case EE_CHAR_UNDERLINE : pResId = SIP_EE_CHAR_UNDERLINE;break;
+ case EE_CHAR_OVERLINE : pResId = SIP_EE_CHAR_OVERLINE;break;
+ case EE_CHAR_STRIKEOUT : pResId = SIP_EE_CHAR_STRIKEOUT;break;
+ case EE_CHAR_ITALIC : pResId = SIP_EE_CHAR_ITALIC;break;
+ case EE_CHAR_OUTLINE : pResId = SIP_EE_CHAR_OUTLINE;break;
+ case EE_CHAR_SHADOW : pResId = SIP_EE_CHAR_SHADOW;break;
+ case EE_CHAR_ESCAPEMENT : pResId = SIP_EE_CHAR_ESCAPEMENT;break;
+ case EE_CHAR_PAIRKERNING: pResId = SIP_EE_CHAR_PAIRKERNING;break;
+ case EE_CHAR_KERNING : pResId = SIP_EE_CHAR_KERNING;break;
+ case EE_CHAR_WLM : pResId = SIP_EE_CHAR_WLM;break;
+ case EE_FEATURE_TAB : pResId = SIP_EE_FEATURE_TAB;break;
+ case EE_FEATURE_LINEBR : pResId = SIP_EE_FEATURE_LINEBR;break;
+ case EE_FEATURE_NOTCONV : pResId = SIP_EE_FEATURE_NOTCONV;break;
+ case EE_FEATURE_FIELD : pResId = SIP_EE_FEATURE_FIELD;break;
+
+ case SDRATTR_TEXTCOLUMNS_NUMBER: pResId = SIP_SA_TEXTCOLUMNS_NUMBER; break;
+ case SDRATTR_TEXTCOLUMNS_SPACING: pResId = SIP_SA_TEXTCOLUMNS_SPACING; break;
+ } // switch
+
+ return SvxResId(pResId);
+}
+
+
+// FractionItem
+
+
+bool SdrFractionItem::operator==(const SfxPoolItem& rCmp) const
+{
+ return SfxPoolItem::operator==(rCmp) &&
+ static_cast<const SdrFractionItem&>(rCmp).GetValue()==nValue;
+}
+
+bool SdrFractionItem::GetPresentation(
+ SfxItemPresentation ePresentation, MapUnit /*eCoreMetric*/,
+ MapUnit /*ePresentationMetric*/, OUString &rText, const IntlWrapper&) const
+{
+ if(nValue.IsValid())
+ {
+ sal_Int32 nDiv = nValue.GetDenominator();
+ rText = OUString::number(nValue.GetNumerator());
+
+ if(nDiv != 1)
+ {
+ rText += "/" + OUString::number(nDiv);
+ }
+ }
+ else
+ {
+ rText = "?";
+ }
+
+ if(ePresentation == SfxItemPresentation::Complete)
+ {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ return true;
+ }
+ else if(ePresentation == SfxItemPresentation::Nameless)
+ return true;
+
+ return false;
+}
+
+SdrFractionItem* SdrFractionItem::Clone(SfxItemPool * /*pPool*/) const
+{
+ return new SdrFractionItem(Which(),GetValue());
+}
+
+
+// ScaleItem
+
+
+bool SdrScaleItem::GetPresentation(
+ SfxItemPresentation ePresentation, MapUnit /*eCoreMetric*/,
+ MapUnit /*ePresentationMetric*/, OUString &rText, const IntlWrapper&) const
+{
+ if(GetValue().IsValid())
+ {
+ sal_Int32 nDiv = GetValue().GetDenominator();
+
+ rText = OUString::number(GetValue().GetNumerator()) + ":" + OUString::number(nDiv);
+ }
+ else
+ {
+ rText = "?";
+ }
+
+ if(ePresentation == SfxItemPresentation::Complete)
+ {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+
+ return true;
+}
+
+SdrScaleItem* SdrScaleItem::Clone(SfxItemPool * /*pPool*/) const
+{
+ return new SdrScaleItem(Which(),GetValue());
+}
+
+
+// OnOffItem
+
+
+SdrOnOffItem* SdrOnOffItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrOnOffItem(TypedWhichId<SdrOnOffItem>(Which()),GetValue());
+}
+
+OUString SdrOnOffItem::GetValueTextByVal(bool bVal) const
+{
+ if (bVal)
+ return SvxResId(STR_ItemValON);
+ return SvxResId(STR_ItemValOFF);
+}
+
+bool SdrOnOffItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByVal(GetValue());
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+void SdrOnOffItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrOnOffItem"));
+ if (Which() == SDRATTR_SHADOW)
+ {
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST("SDRATTR_SHADOW"));
+ }
+
+ SfxBoolItem::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+SdrYesNoItem* SdrYesNoItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrYesNoItem(TypedWhichId<SdrYesNoItem>(Which()),GetValue());
+}
+
+OUString SdrYesNoItem::GetValueTextByVal(bool bVal) const
+{
+ if (bVal)
+ return SvxResId(STR_ItemValYES);
+ return SvxResId(STR_ItemValNO);
+}
+
+bool SdrYesNoItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByVal(GetValue());
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+SdrPercentItem* SdrPercentItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrPercentItem(TypedWhichId<SdrPercentItem>(Which()),GetValue());
+}
+
+bool SdrPercentItem::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreMetric*/,
+ MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText = unicode::formatPercent(GetValue(),
+ Application::GetSettings().GetUILanguageTag());
+
+ if(ePres == SfxItemPresentation::Complete)
+ {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+
+ return true;
+}
+
+void SdrPercentItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrPercentItem"));
+ if (Which() == SDRATTR_SHADOWTRANSPARENCE)
+ {
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"),
+ BAD_CAST("SDRATTR_SHADOWTRANSPARENCE"));
+ }
+
+ SfxUInt16Item::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+SdrAngleItem* SdrAngleItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrAngleItem(TypedWhichId<SdrAngleItem>(Which()),GetValue());
+}
+
+bool SdrAngleItem::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/,
+ OUString& rText, const IntlWrapper& rIntlWrapper) const
+{
+ sal_Int32 nValue(GetValue());
+ bool bNeg(nValue < 0);
+
+ if(bNeg)
+ nValue = -nValue;
+
+ OUStringBuffer aText = OUString::number(nValue);
+
+ if(nValue)
+ {
+ sal_Unicode aUnicodeNull('0');
+ sal_Int32 nCount(2);
+
+ if(LocaleDataWrapper::isNumLeadingZero())
+ nCount++;
+
+ while(aText.getLength() < nCount)
+ aText.insert(0, aUnicodeNull);
+
+ sal_Int32 nLen = aText.getLength();
+ bool bNull1(aText[nLen-1] == aUnicodeNull);
+ bool bNull2(bNull1 && aText[nLen-2] == aUnicodeNull);
+
+ if(bNull2)
+ {
+ // no decimal place(s)
+ sal_Int32 idx = nLen-2;
+ aText.remove(idx, aText.getLength()-idx);
+ }
+ else
+ {
+ sal_Unicode cDec =
+ rIntlWrapper.getLocaleData()->getNumDecimalSep()[0];
+ aText.insert(nLen-2, cDec);
+
+ if(bNull1)
+ aText.remove(nLen, aText.getLength()-nLen);
+ }
+
+ if(bNeg)
+ aText.insert(0, '-');
+ }
+
+ aText.append(sal_Unicode(DEGREE_CHAR));
+
+ if(ePres == SfxItemPresentation::Complete)
+ {
+ OUString aStr = SdrItemPool::GetItemName(Which());
+ aText.insert(0, ' ');
+ aText.insert(0, aStr);
+ }
+
+ rText = aText.makeStringAndClear();
+ return true;
+}
+
+SdrMetricItem* SdrMetricItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrMetricItem(TypedWhichId<SdrMetricItem>(Which()),GetValue());
+}
+
+bool SdrMetricItem::HasMetrics() const
+{
+ return true;
+}
+
+void SdrMetricItem::ScaleMetrics(tools::Long nMul, tools::Long nDiv)
+{
+ if (GetValue()!=0) {
+ SetValue(BigInt::Scale(GetValue(), nMul, nDiv));
+ }
+}
+
+bool SdrMetricItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit eCoreMetric, MapUnit ePresMetric, OUString& rText, const IntlWrapper&) const
+{
+ tools::Long nValue=GetValue();
+ SdrFormatter aFmt(eCoreMetric,ePresMetric);
+ rText = aFmt.GetStr(nValue);
+ rText += " " + SdrFormatter::GetUnitStr(ePresMetric);
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+void SdrMetricItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrMetricItem"));
+ if (Which() == SDRATTR_SHADOWXDIST)
+ {
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST("SDRATTR_SHADOWXDIST"));
+ }
+ else if (Which() == SDRATTR_SHADOWYDIST)
+ {
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST("SDRATTR_SHADOWYDIST"));
+ }
+ else if (Which() == SDRATTR_SHADOWSIZEX)
+ {
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST("SDRATTR_SHADOWSIZEX"));
+ }
+ else if (Which() == SDRATTR_SHADOWSIZEY)
+ {
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST("SDRATTR_SHADOWSIZEY"));
+ }
+ else if (Which() == SDRATTR_SHADOWBLUR)
+ {
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST("SDRATTR_SHADOWBLUR"));
+ }
+
+ SfxInt32Item::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+// items of the legend object
+
+
+SdrCaptionTypeItem* SdrCaptionTypeItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrCaptionTypeItem(*this); }
+
+sal_uInt16 SdrCaptionTypeItem::GetValueCount() const { return 4; }
+
+OUString SdrCaptionTypeItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALCAPTIONTYPES[] =
+ {
+ STR_ItemValCAPTIONTYPE1,
+ STR_ItemValCAPTIONTYPE2,
+ STR_ItemValCAPTIONTYPE3,
+ STR_ItemValCAPTIONTYPE4
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALCAPTIONTYPES) && "wrong pos!");
+ return SvxResId(ITEMVALCAPTIONTYPES[nPos]);
+}
+
+bool SdrCaptionTypeItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+
+SdrCaptionEscDirItem* SdrCaptionEscDirItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrCaptionEscDirItem(*this); }
+
+sal_uInt16 SdrCaptionEscDirItem::GetValueCount() const { return 3; }
+
+OUString SdrCaptionEscDirItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALCAPTIONTYPES[] =
+ {
+ STR_ItemValCAPTIONESCHORI,
+ STR_ItemValCAPTIONESCVERT,
+ STR_ItemValCAPTIONESCBESTFIT
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALCAPTIONTYPES) && "wrong pos!");
+ return SvxResId(ITEMVALCAPTIONTYPES[nPos]);
+}
+
+bool SdrCaptionEscDirItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+
+// MiscItems
+
+
+// FitToSize
+
+SfxPoolItem* SdrTextFitToSizeTypeItem::CreateDefault() { return new SdrTextFitToSizeTypeItem; }
+
+SdrTextFitToSizeTypeItem* SdrTextFitToSizeTypeItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrTextFitToSizeTypeItem(*this); }
+
+bool SdrTextFitToSizeTypeItem::operator==(const SfxPoolItem& rItem) const
+{
+ if (!SfxEnumItem<css::drawing::TextFitToSizeType>::operator==(rItem))
+ {
+ return false;
+ }
+
+ return m_nMaxScale == static_cast<const SdrTextFitToSizeTypeItem&>(rItem).m_nMaxScale;
+}
+
+sal_uInt16 SdrTextFitToSizeTypeItem::GetValueCount() const { return 4; }
+
+OUString SdrTextFitToSizeTypeItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALFITTISIZETYPES[] =
+ {
+ STR_ItemValFITTOSIZENONE,
+ STR_ItemValFITTOSIZEPROP,
+ STR_ItemValFITTOSIZEALLLINES,
+ STR_ItemValFITTOSIZERESIZEAT
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALFITTISIZETYPES) && "wrong pos!");
+ return SvxResId(ITEMVALFITTISIZETYPES[nPos]);
+}
+
+bool SdrTextFitToSizeTypeItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrTextFitToSizeTypeItem::HasBoolValue() const { return true; }
+
+bool SdrTextFitToSizeTypeItem::GetBoolValue() const { return GetValue() != drawing::TextFitToSizeType_NONE; }
+
+void SdrTextFitToSizeTypeItem::SetBoolValue(bool bVal)
+{
+ SetValue(bVal ? drawing::TextFitToSizeType_PROPORTIONAL : drawing::TextFitToSizeType_NONE);
+}
+
+bool SdrTextFitToSizeTypeItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ drawing::TextFitToSizeType eFS = GetValue();
+ rVal <<= eFS;
+
+ return true;
+}
+
+bool SdrTextFitToSizeTypeItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextFitToSizeType eFS;
+ if(!(rVal >>= eFS))
+ {
+ sal_Int32 nEnum = 0;
+ if(!(rVal >>= nEnum))
+ return false;
+
+ eFS = static_cast<drawing::TextFitToSizeType>(nEnum);
+ }
+
+ SetValue(eFS);
+
+ return true;
+}
+
+
+SdrTextVertAdjustItem* SdrTextVertAdjustItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrTextVertAdjustItem(*this); }
+
+sal_uInt16 SdrTextVertAdjustItem::GetValueCount() const { return 5; }
+
+OUString SdrTextVertAdjustItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALTEXTVADJTYPES[] =
+ {
+ STR_ItemValTEXTVADJTOP,
+ STR_ItemValTEXTVADJCENTER,
+ STR_ItemValTEXTVADJBOTTOM,
+ STR_ItemValTEXTVADJBLOCK,
+ STR_ItemValTEXTVADJSTRETCH
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALTEXTVADJTYPES) && "wrong pos!");
+ return SvxResId(ITEMVALTEXTVADJTYPES[nPos]);
+}
+
+bool SdrTextVertAdjustItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrTextVertAdjustItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextVerticalAdjust>(GetValue());
+ return true;
+}
+
+bool SdrTextVertAdjustItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextVerticalAdjust eAdj;
+ if(!(rVal >>= eAdj))
+ {
+ sal_Int32 nEnum = 0;
+ if(!(rVal >>= nEnum))
+ return false;
+
+ eAdj = static_cast<drawing::TextVerticalAdjust>(nEnum);
+ }
+
+ SetValue( static_cast<SdrTextVertAdjust>(eAdj) );
+
+ return true;
+}
+
+void SdrTextVertAdjustItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTextVertAdjustItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::number(GetValue()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+SdrTextHorzAdjustItem* SdrTextHorzAdjustItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrTextHorzAdjustItem(*this); }
+
+sal_uInt16 SdrTextHorzAdjustItem::GetValueCount() const { return 5; }
+
+OUString SdrTextHorzAdjustItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALTEXTHADJTYPES[] =
+ {
+ STR_ItemValTEXTHADJLEFT,
+ STR_ItemValTEXTHADJCENTER,
+ STR_ItemValTEXTHADJRIGHT,
+ STR_ItemValTEXTHADJBLOCK,
+ STR_ItemValTEXTHADJSTRETCH
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALTEXTHADJTYPES) && "wrong pos!");
+ return SvxResId(ITEMVALTEXTHADJTYPES[nPos]);
+}
+
+bool SdrTextHorzAdjustItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrTextHorzAdjustItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextHorizontalAdjust>(GetValue());
+ return true;
+}
+
+bool SdrTextHorzAdjustItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextHorizontalAdjust eAdj;
+ if(!(rVal >>= eAdj))
+ {
+ sal_Int32 nEnum = 0;
+ if(!(rVal >>= nEnum))
+ return false;
+
+ eAdj = static_cast<drawing::TextHorizontalAdjust>(nEnum);
+ }
+
+ SetValue( static_cast<SdrTextHorzAdjust>(eAdj) );
+
+ return true;
+}
+
+
+SdrTextAniKindItem* SdrTextAniKindItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrTextAniKindItem(*this); }
+
+sal_uInt16 SdrTextAniKindItem::GetValueCount() const { return 5; }
+
+OUString SdrTextAniKindItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALTEXTANITYPES[] =
+ {
+ STR_ItemValTEXTANI_NONE,
+ STR_ItemValTEXTANI_BLINK,
+ STR_ItemValTEXTANI_SCROLL,
+ STR_ItemValTEXTANI_ALTERNATE,
+ STR_ItemValTEXTANI_SLIDE
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALTEXTANITYPES) && "wrong pos!");
+ return SvxResId(ITEMVALTEXTANITYPES[nPos]);
+}
+
+bool SdrTextAniKindItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrTextAniKindItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextAnimationKind>(GetValue());
+ return true;
+}
+
+bool SdrTextAniKindItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextAnimationKind eKind;
+ if(!(rVal >>= eKind))
+ {
+ sal_Int32 nEnum = 0;
+ if(!(rVal >>= nEnum))
+ return false;
+ eKind = static_cast<drawing::TextAnimationKind>(nEnum);
+ }
+
+ SetValue( static_cast<SdrTextAniKind>(eKind) );
+
+ return true;
+}
+
+
+SdrTextAniDirectionItem* SdrTextAniDirectionItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrTextAniDirectionItem(*this); }
+
+sal_uInt16 SdrTextAniDirectionItem::GetValueCount() const { return 4; }
+
+OUString SdrTextAniDirectionItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALTEXTANITYPES[] =
+ {
+ STR_ItemValTEXTANI_LEFT,
+ STR_ItemValTEXTANI_UP,
+ STR_ItemValTEXTANI_RIGHT,
+ STR_ItemValTEXTANI_DOWN
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALTEXTANITYPES) && "wrong pos!");
+ return SvxResId(ITEMVALTEXTANITYPES[nPos]);
+}
+
+bool SdrTextAniDirectionItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrTextAniDirectionItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextAnimationDirection>(GetValue());
+ return true;
+}
+
+bool SdrTextAniDirectionItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextAnimationDirection eDir;
+ if(!(rVal >>= eDir))
+ {
+ sal_Int32 nEnum = 0;
+ if(!(rVal >>= nEnum))
+ return false;
+
+ eDir = static_cast<drawing::TextAnimationDirection>(nEnum);
+ }
+
+ SetValue( static_cast<SdrTextAniDirection>(eDir) );
+
+ return true;
+}
+
+
+SdrTextAniDelayItem* SdrTextAniDelayItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrTextAniDelayItem(*this); }
+
+bool SdrTextAniDelayItem::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/,
+ OUString& rText, const IntlWrapper&) const
+{
+ rText = OUString::number(GetValue()) + "ms";
+
+ if(ePres == SfxItemPresentation::Complete)
+ {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+
+ return true;
+}
+
+
+SdrTextAniAmountItem* SdrTextAniAmountItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrTextAniAmountItem(*this); }
+
+bool SdrTextAniAmountItem::HasMetrics() const
+{
+ return GetValue()>0;
+}
+
+void SdrTextAniAmountItem::ScaleMetrics(tools::Long nMul, tools::Long nDiv)
+{
+ if (GetValue()>0) {
+ BigInt aVal(GetValue());
+ aVal*=nMul;
+ aVal+=nDiv/2; // to round accurately
+ aVal/=nDiv;
+ SetValue(short(aVal));
+ }
+}
+
+bool SdrTextAniAmountItem::GetPresentation(
+ SfxItemPresentation ePres, MapUnit eCoreMetric, MapUnit ePresMetric,
+ OUString& rText, const IntlWrapper&) const
+{
+ sal_Int32 nValue(GetValue());
+
+ if(!nValue)
+ nValue = -1;
+
+ if(nValue < 0)
+ {
+ rText = OUString::number(-nValue) + "pixel";
+ }
+ else
+ {
+ SdrFormatter aFmt(eCoreMetric, ePresMetric);
+ rText = aFmt.GetStr(nValue) +
+ SdrFormatter::GetUnitStr(ePresMetric);
+ }
+
+ if(ePres == SfxItemPresentation::Complete)
+ {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+
+ return true;
+}
+
+
+SdrTextFixedCellHeightItem::SdrTextFixedCellHeightItem( bool bUseFixedCellHeight )
+ : SfxBoolItem( SDRATTR_TEXT_USEFIXEDCELLHEIGHT, bUseFixedCellHeight )
+{
+}
+bool SdrTextFixedCellHeightItem::GetPresentation( SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresentationMetric*/,
+ OUString &rText, const IntlWrapper& ) const
+{
+ rText = GetValueTextByVal( GetValue() );
+ if (ePres==SfxItemPresentation::Complete)
+ {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+SdrTextFixedCellHeightItem* SdrTextFixedCellHeightItem::Clone( SfxItemPool * /*pPool*/) const
+{
+ return new SdrTextFixedCellHeightItem( GetValue() );
+}
+
+bool SdrTextFixedCellHeightItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ bool bValue = GetValue();
+ rVal <<= bValue;
+ return true;
+}
+bool SdrTextFixedCellHeightItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ bool bValue;
+ if( !( rVal >>= bValue ) )
+ return false;
+ SetValue( bValue );
+ return true;
+}
+
+// EdgeKind
+
+SdrEdgeKindItem* SdrEdgeKindItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrEdgeKindItem(*this); }
+
+sal_uInt16 SdrEdgeKindItem::GetValueCount() const { return 4; }
+
+OUString SdrEdgeKindItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALEDGES[] =
+ {
+ STR_ItemValEDGE_ORTHOLINES,
+ STR_ItemValEDGE_THREELINES,
+ STR_ItemValEDGE_ONELINE,
+ STR_ItemValEDGE_BEZIER
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALEDGES) && "wrong pos!");
+ return SvxResId(ITEMVALEDGES[nPos]);
+}
+
+bool SdrEdgeKindItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrEdgeKindItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ drawing::ConnectorType eCT = drawing::ConnectorType_STANDARD;
+
+ switch( GetValue() )
+ {
+ case SdrEdgeKind::OrthoLines : eCT = drawing::ConnectorType_STANDARD; break;
+ case SdrEdgeKind::ThreeLines : eCT = drawing::ConnectorType_LINES; break;
+ case SdrEdgeKind::OneLine : eCT = drawing::ConnectorType_LINE; break;
+ case SdrEdgeKind::Bezier : eCT = drawing::ConnectorType_CURVE; break;
+ case SdrEdgeKind::Arc : eCT = drawing::ConnectorType_CURVE; break;
+ default:
+ OSL_FAIL( "SdrEdgeKindItem::QueryValue : unknown enum" );
+ }
+
+ rVal <<= eCT;
+
+ return true;
+}
+
+bool SdrEdgeKindItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::ConnectorType eCT;
+ if(!(rVal >>= eCT))
+ {
+ sal_Int32 nEnum = 0;
+ if(!(rVal >>= nEnum))
+ return false;
+
+ eCT = static_cast<drawing::ConnectorType>(nEnum);
+ }
+
+ SdrEdgeKind eEK = SdrEdgeKind::OrthoLines;
+ switch( eCT )
+ {
+ case drawing::ConnectorType_STANDARD : eEK = SdrEdgeKind::OrthoLines; break;
+ case drawing::ConnectorType_CURVE : eEK = SdrEdgeKind::Bezier; break;
+ case drawing::ConnectorType_LINE : eEK = SdrEdgeKind::OneLine; break;
+ case drawing::ConnectorType_LINES : eEK = SdrEdgeKind::ThreeLines; break;
+ default:
+ OSL_FAIL( "SdrEdgeKindItem::PuValue : unknown enum" );
+ }
+ SetValue( eEK );
+
+ return true;
+}
+
+bool SdrEdgeNode1HorzDistItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= GetValue();
+ return true;
+}
+
+bool SdrEdgeNode1HorzDistItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nValue = 0;
+ if(!(rVal >>= nValue))
+ return false;
+
+ SetValue( nValue );
+ return true;
+}
+
+SdrEdgeNode1HorzDistItem* SdrEdgeNode1HorzDistItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrEdgeNode1HorzDistItem(*this);
+}
+
+bool SdrEdgeNode1VertDistItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= GetValue();
+ return true;
+}
+
+bool SdrEdgeNode1VertDistItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nValue = 0;
+ if(!(rVal >>= nValue))
+ return false;
+
+ SetValue( nValue );
+ return true;
+}
+
+SdrEdgeNode1VertDistItem* SdrEdgeNode1VertDistItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrEdgeNode1VertDistItem(*this);
+}
+
+bool SdrEdgeNode2HorzDistItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= GetValue();
+ return true;
+}
+
+bool SdrEdgeNode2HorzDistItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nValue = 0;
+ if(!(rVal >>= nValue))
+ return false;
+
+ SetValue( nValue );
+ return true;
+}
+
+SdrEdgeNode2HorzDistItem* SdrEdgeNode2HorzDistItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrEdgeNode2HorzDistItem(*this);
+}
+
+bool SdrEdgeNode2VertDistItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= GetValue();
+ return true;
+}
+
+bool SdrEdgeNode2VertDistItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nValue = 0;
+ if(!(rVal >>= nValue))
+ return false;
+
+ SetValue( nValue );
+ return true;
+}
+
+SdrEdgeNode2VertDistItem* SdrEdgeNode2VertDistItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrEdgeNode2VertDistItem(*this);
+}
+
+SdrEdgeNode1GlueDistItem* SdrEdgeNode1GlueDistItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrEdgeNode1GlueDistItem(*this);
+}
+
+SdrEdgeNode2GlueDistItem* SdrEdgeNode2GlueDistItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrEdgeNode2GlueDistItem(*this);
+}
+
+SdrMeasureKindItem* SdrMeasureKindItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrMeasureKindItem(*this); }
+
+sal_uInt16 SdrMeasureKindItem::GetValueCount() const { return 2; }
+
+OUString SdrMeasureKindItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALMEASURETYPES[] =
+ {
+ STR_ItemValMEASURE_STD,
+ STR_ItemValMEASURE_RADIUS
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALMEASURETYPES) && "wrong pos!");
+ return SvxResId(ITEMVALMEASURETYPES[nPos]);
+}
+
+bool SdrMeasureKindItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrMeasureKindItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::MeasureKind>(GetValue());
+ return true;
+}
+
+bool SdrMeasureKindItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::MeasureKind eKind;
+ if(!(rVal >>= eKind))
+ {
+ sal_Int32 nEnum = 0;
+ if(!(rVal >>= nEnum))
+ return false;
+
+ eKind = static_cast<drawing::MeasureKind>(nEnum);
+ }
+
+ SetValue( static_cast<SdrMeasureKind>(eKind) );
+ return true;
+}
+
+
+SdrMeasureTextHPosItem* SdrMeasureTextHPosItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrMeasureTextHPosItem(*this); }
+
+sal_uInt16 SdrMeasureTextHPosItem::GetValueCount() const { return 4; }
+
+const OUString & SdrMeasureTextHPosItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static std::array<OUString, 4> aMeasureTextHPosItem
+ {
+ "automatic",
+ "left outside",
+ "inside (centered)",
+ "right outside"
+ };
+ assert(nPos < aMeasureTextHPosItem.size() && "wrong pos!");
+ return aMeasureTextHPosItem[nPos];
+}
+
+bool SdrMeasureTextHPosItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrMeasureTextHPosItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= GetValue();
+ return true;
+}
+
+bool SdrMeasureTextHPosItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::MeasureTextHorzPos ePos;
+ if(!(rVal >>= ePos))
+ {
+ sal_Int32 nEnum = 0;
+ if(!(rVal >>= nEnum))
+ return false;
+
+ ePos = static_cast<drawing::MeasureTextHorzPos>(nEnum);
+ }
+
+ SetValue(ePos);
+ return true;
+}
+
+SdrMeasureTextVPosItem* SdrMeasureTextVPosItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrMeasureTextVPosItem(*this); }
+
+sal_uInt16 SdrMeasureTextVPosItem::GetValueCount() const { return 5; }
+
+OUString SdrMeasureTextVPosItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALMEASURETEXTTYPES[] =
+ {
+ STR_ItemValMEASURE_TEXTVAUTO,
+ STR_ItemValMEASURE_ABOVE,
+ STR_ItemValMEASURETEXT_BREAKEDLINE,
+ STR_ItemValMEASURE_BELOW,
+ STR_ItemValMEASURETEXT_VERTICALCEN
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALMEASURETEXTTYPES) && "wrong pos!");
+ return SvxResId(ITEMVALMEASURETEXTTYPES[nPos]);
+}
+
+bool SdrMeasureTextVPosItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrMeasureTextVPosItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= GetValue();
+ return true;
+}
+
+bool SdrMeasureTextVPosItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::MeasureTextVertPos ePos;
+ if(!(rVal >>= ePos))
+ {
+ sal_Int32 nEnum = 0;
+ if(!(rVal >>= nEnum))
+ return false;
+
+ ePos = static_cast<drawing::MeasureTextVertPos>(nEnum);
+ }
+
+ SetValue(ePos);
+ return true;
+}
+
+SdrMeasureUnitItem* SdrMeasureUnitItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrMeasureUnitItem(*this); }
+
+sal_uInt16 SdrMeasureUnitItem::GetValueCount() const { return 14; }
+
+OUString SdrMeasureUnitItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ if(static_cast<FieldUnit>(nPos) == FieldUnit::NONE)
+ return "default";
+ else
+ return SdrFormatter::GetUnitStr(static_cast<FieldUnit>(nPos));
+}
+
+bool SdrMeasureUnitItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrMeasureUnitItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<sal_Int32>(GetValue());
+ return true;
+}
+
+bool SdrMeasureUnitItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nMeasure = 0;
+ if(!(rVal >>= nMeasure))
+ return false;
+
+ SetValue( static_cast<FieldUnit>(nMeasure) );
+ return true;
+}
+
+
+SdrCircKindItem* SdrCircKindItem::Clone(SfxItemPool* /*pPool*/) const { return new SdrCircKindItem(*this); }
+
+sal_uInt16 SdrCircKindItem::GetValueCount() const { return 4; }
+
+OUString SdrCircKindItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ static TranslateId ITEMVALCIRCTYPES[] =
+ {
+ STR_ItemValCIRC_FULL,
+ STR_ItemValCIRC_SECT,
+ STR_ItemValCIRC_CUT,
+ STR_ItemValCIRC_ARC
+ };
+ assert(nPos < SAL_N_ELEMENTS(ITEMVALCIRCTYPES) && "wrong pos!");
+ return SvxResId(ITEMVALCIRCTYPES[nPos]);
+}
+
+bool SdrCircKindItem::GetPresentation(SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/, OUString& rText, const IntlWrapper&) const
+{
+ rText=GetValueTextByPos(sal::static_int_cast< sal_uInt16 >(GetValue()));
+ if (ePres==SfxItemPresentation::Complete) {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+ return true;
+}
+
+bool SdrCircKindItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::CircleKind>(GetValue());
+ return true;
+}
+
+bool SdrCircKindItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::CircleKind eKind;
+ if(!(rVal >>= eKind))
+ {
+ sal_Int32 nEnum = 0;
+ if(!(rVal >>= nEnum))
+ return false;
+
+ eKind = static_cast<drawing::CircleKind>(nEnum);
+ }
+
+ SetValue( static_cast<SdrCircKind>(eKind) );
+ return true;
+}
+
+SdrSignedPercentItem* SdrSignedPercentItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrSignedPercentItem( Which(), GetValue() );
+}
+
+bool SdrSignedPercentItem::GetPresentation(
+ SfxItemPresentation ePres, MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/,
+ OUString& rText, const IntlWrapper&) const
+{
+ rText = unicode::formatPercent(GetValue(),
+ Application::GetSettings().GetUILanguageTag());
+
+ if(ePres == SfxItemPresentation::Complete)
+ {
+ rText = SdrItemPool::GetItemName(Which()) + " " + rText;
+ }
+
+ return true;
+}
+
+SdrGrafRedItem* SdrGrafRedItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new SdrGrafRedItem( *this );
+}
+
+SdrGrafGreenItem* SdrGrafGreenItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new SdrGrafGreenItem( *this );
+}
+
+SdrGrafBlueItem* SdrGrafBlueItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new SdrGrafBlueItem( *this );
+}
+
+SdrGrafLuminanceItem* SdrGrafLuminanceItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new SdrGrafLuminanceItem( *this );
+}
+
+SdrGrafContrastItem* SdrGrafContrastItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new SdrGrafContrastItem( *this );
+}
+
+SdrGrafGamma100Item* SdrGrafGamma100Item::Clone( SfxItemPool* /*pPool */) const
+{
+ return new SdrGrafGamma100Item( *this );
+}
+
+bool SdrGrafGamma100Item::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<double>(GetValue()) / 100.0;
+ return true;
+}
+
+bool SdrGrafGamma100Item::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ double nGamma = 0;
+ if(!(rVal >>= nGamma))
+ return false;
+
+ SetValue( static_cast<sal_uInt32>(nGamma * 100.0 ) );
+ return true;
+}
+
+SdrGrafInvertItem* SdrGrafInvertItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new SdrGrafInvertItem( *this );
+}
+
+SdrGrafTransparenceItem* SdrGrafTransparenceItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new SdrGrafTransparenceItem( *this );
+}
+
+SdrGrafModeItem* SdrGrafModeItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrGrafModeItem( *this );
+}
+
+sal_uInt16 SdrGrafModeItem::GetValueCount() const
+{
+ return 4;
+}
+
+OUString SdrGrafModeItem::GetValueTextByPos(sal_uInt16 nPos)
+{
+ OUString aStr;
+
+ switch(nPos)
+ {
+ case 1:
+ {
+ aStr = "Greys";
+ break;
+ }
+ case 2:
+ {
+ aStr = "Black/White";
+ break;
+ }
+ case 3:
+ {
+ aStr = "Watermark";
+ break;
+ }
+ default:
+ {
+ aStr = "Standard";
+ break;
+ }
+ }
+
+ return aStr;
+}
+
+bool SdrGrafModeItem::GetPresentation( SfxItemPresentation ePres,
+ MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/,
+ OUString& rText, const IntlWrapper&) const
+{
+ rText = GetValueTextByPos( sal::static_int_cast< sal_uInt16 >( GetValue() ) );
+
+ if( ePres == SfxItemPresentation::Complete )
+ {
+ rText = SdrItemPool::GetItemName( Which() ) + " " + rText;
+ }
+
+ return true;
+}
+
+SdrGrafCropItem* SdrGrafCropItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new SdrGrafCropItem( *this );
+}
+
+SdrTextAniStartInsideItem::~SdrTextAniStartInsideItem()
+{
+}
+
+SdrTextAniStartInsideItem* SdrTextAniStartInsideItem::Clone(SfxItemPool* ) const
+{
+ return new SdrTextAniStartInsideItem(*this);
+}
+
+SdrTextAniStopInsideItem::~SdrTextAniStopInsideItem()
+{
+}
+
+SdrTextAniStopInsideItem* SdrTextAniStopInsideItem::Clone(SfxItemPool* ) const
+{
+ return new SdrTextAniStopInsideItem(*this);
+}
+
+SdrCaptionEscIsRelItem::~SdrCaptionEscIsRelItem()
+{
+}
+
+SdrCaptionEscIsRelItem* SdrCaptionEscIsRelItem::Clone(SfxItemPool* ) const
+{
+ return new SdrCaptionEscIsRelItem(*this);
+}
+
+SdrCaptionEscRelItem::~SdrCaptionEscRelItem()
+{
+}
+
+SdrCaptionEscRelItem* SdrCaptionEscRelItem::Clone(SfxItemPool*) const
+{
+ return new SdrCaptionEscRelItem(*this);
+}
+
+SdrCaptionFitLineLenItem::~SdrCaptionFitLineLenItem()
+{
+}
+
+SdrCaptionFitLineLenItem* SdrCaptionFitLineLenItem::Clone(SfxItemPool* ) const
+{
+ return new SdrCaptionFitLineLenItem(*this);
+}
+
+SdrCaptionLineLenItem::~SdrCaptionLineLenItem()
+{
+}
+
+SdrCaptionLineLenItem* SdrCaptionLineLenItem::Clone(SfxItemPool*) const
+{
+ return new SdrCaptionLineLenItem(*this);
+}
+
+SdrMeasureBelowRefEdgeItem::~SdrMeasureBelowRefEdgeItem()
+{
+}
+
+SdrMeasureBelowRefEdgeItem* SdrMeasureBelowRefEdgeItem::Clone(SfxItemPool* ) const
+{
+ return new SdrMeasureBelowRefEdgeItem(*this);
+}
+
+SdrMeasureTextIsFixedAngleItem::~SdrMeasureTextIsFixedAngleItem()
+{
+}
+
+SdrMeasureTextIsFixedAngleItem* SdrMeasureTextIsFixedAngleItem::Clone(SfxItemPool* ) const
+{
+ return new SdrMeasureTextIsFixedAngleItem(*this);
+}
+
+SdrMeasureTextFixedAngleItem::~SdrMeasureTextFixedAngleItem()
+{
+}
+
+SdrMeasureTextFixedAngleItem* SdrMeasureTextFixedAngleItem::Clone(SfxItemPool* ) const
+{
+ return new SdrMeasureTextFixedAngleItem(*this);
+}
+
+SdrMeasureDecimalPlacesItem::~SdrMeasureDecimalPlacesItem()
+{
+}
+
+SdrMeasureDecimalPlacesItem* SdrMeasureDecimalPlacesItem::Clone(SfxItemPool* ) const
+{
+ return new SdrMeasureDecimalPlacesItem(*this);
+}
+
+SdrMeasureTextRota90Item::~SdrMeasureTextRota90Item()
+{
+}
+
+SdrMeasureTextRota90Item* SdrMeasureTextRota90Item::Clone(SfxItemPool* ) const
+{
+ return new SdrMeasureTextRota90Item(*this);
+}
+
+SdrMeasureTextUpsideDownItem::~SdrMeasureTextUpsideDownItem()
+{
+}
+
+SdrMeasureTextUpsideDownItem* SdrMeasureTextUpsideDownItem::Clone(SfxItemPool* ) const
+{
+ return new SdrMeasureTextUpsideDownItem(*this);
+}
+
+SdrLayerIdItem* SdrLayerIdItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrLayerIdItem(*this);
+}
+
+SdrLayerNameItem* SdrLayerNameItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SdrLayerNameItem(*this);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdcrtv.cxx b/svx/source/svdraw/svdcrtv.cxx
new file mode 100644
index 000000000..9791df7ae
--- /dev/null
+++ b/svx/source/svdraw/svdcrtv.cxx
@@ -0,0 +1,916 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdcrtv.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/view3d.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <fmobj.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
+#include <vcl/ptrstyle.hxx>
+
+using namespace com::sun::star;
+
+class ImplConnectMarkerOverlay
+{
+ // The OverlayObjects
+ sdr::overlay::OverlayObjectList maObjects;
+
+ // The remembered target object
+ const SdrObject& mrObject;
+
+public:
+ ImplConnectMarkerOverlay(const SdrCreateView& rView, SdrObject const & rObject);
+
+ // The OverlayObjects are cleared using the destructor of OverlayObjectList.
+ // That destructor calls clear() at the list which removes all objects from the
+ // OverlayManager and deletes them.
+
+ const SdrObject& GetTargetObject() const { return mrObject; }
+};
+
+ImplConnectMarkerOverlay::ImplConnectMarkerOverlay(const SdrCreateView& rView, SdrObject const & rObject)
+: mrObject(rObject)
+{
+ basegfx::B2DPolyPolygon aB2DPolyPolygon(rObject.TakeXorPoly());
+
+ for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
+ const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
+
+ if(xTargetOverlay.is())
+ {
+ float fScalingFactor = xTargetOverlay->getOutputDevice().GetDPIScaleFactor();
+ Size aHalfLogicSize(xTargetOverlay->getOutputDevice().PixelToLogic(Size(4 * fScalingFactor, 4 * fScalingFactor)));
+
+ // object
+ std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
+ aB2DPolyPolygon));
+ xTargetOverlay->add(*pNew);
+ maObjects.append(std::move(pNew));
+
+ // gluepoints
+ for(sal_uInt16 i(0); i < 4; i++)
+ {
+ SdrGluePoint aGluePoint(rObject.GetVertexGluePoint(i));
+ const Point& rPosition = aGluePoint.GetAbsolutePos(rObject);
+
+ basegfx::B2DPoint aTopLeft(rPosition.X() - aHalfLogicSize.Width(), rPosition.Y() - aHalfLogicSize.Height());
+ basegfx::B2DPoint aBottomRight(rPosition.X() + aHalfLogicSize.Width(), rPosition.Y() + aHalfLogicSize.Height());
+
+ basegfx::B2DPolygon aTempPoly;
+ aTempPoly.append(aTopLeft);
+ aTempPoly.append(basegfx::B2DPoint(aBottomRight.getX(), aTopLeft.getY()));
+ aTempPoly.append(aBottomRight);
+ aTempPoly.append(basegfx::B2DPoint(aTopLeft.getX(), aBottomRight.getY()));
+ aTempPoly.setClosed(true);
+
+ basegfx::B2DPolyPolygon aTempPolyPoly;
+ aTempPolyPoly.append(aTempPoly);
+
+ std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew2(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
+ aTempPolyPoly));
+ xTargetOverlay->add(*pNew2);
+ maObjects.append(std::move(pNew2));
+ }
+ }
+ }
+}
+
+class ImpSdrCreateViewExtraData
+{
+ // The OverlayObjects for XOR replacement
+ sdr::overlay::OverlayObjectList maObjects;
+
+public:
+ ImpSdrCreateViewExtraData();
+ ~ImpSdrCreateViewExtraData();
+
+ void CreateAndShowOverlay(const SdrCreateView& rView, const SdrObject* pObject, const basegfx::B2DPolyPolygon& rPolyPoly);
+ void HideOverlay();
+};
+
+ImpSdrCreateViewExtraData::ImpSdrCreateViewExtraData()
+{
+}
+
+ImpSdrCreateViewExtraData::~ImpSdrCreateViewExtraData()
+{
+ HideOverlay();
+}
+
+void ImpSdrCreateViewExtraData::CreateAndShowOverlay(const SdrCreateView& rView, const SdrObject* pObject, const basegfx::B2DPolyPolygon& rPolyPoly)
+{
+ for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
+ const rtl::Reference<sdr::overlay::OverlayManager>& xOverlayManager = pCandidate->GetOverlayManager();
+
+ if (xOverlayManager.is())
+ {
+ if(pObject)
+ {
+ const sdr::contact::ViewContact& rVC = pObject->GetViewContact();
+ drawinglayer::primitive2d::Primitive2DContainer aSequence;
+ rVC.getViewIndependentPrimitive2DContainer(aSequence);
+ std::unique_ptr<sdr::overlay::OverlayObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(std::move(aSequence)));
+
+ xOverlayManager->add(*pNew);
+ maObjects.append(std::move(pNew));
+ }
+
+ if(rPolyPoly.count())
+ {
+ std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
+ rPolyPoly));
+ xOverlayManager->add(*pNew);
+ maObjects.append(std::move(pNew));
+ }
+ }
+ }
+}
+
+void ImpSdrCreateViewExtraData::HideOverlay()
+{
+ // the clear() call of the list removes all objects from the
+ // OverlayManager and deletes them.
+ maObjects.clear();
+}
+
+
+// CreateView
+
+
+void SdrCreateView::ImpClearConnectMarker()
+{
+ mpCoMaOverlay.reset();
+}
+
+SdrCreateView::SdrCreateView(SdrModel& rSdrModel, OutputDevice* pOut)
+ : SdrDragView(rSdrModel, pOut)
+ , mpCurrentCreate(nullptr)
+ , mpCreatePV(nullptr)
+ , mpCreateViewExtraData(new ImpSdrCreateViewExtraData())
+ , maCurrentCreatePointer(PointerStyle::Cross)
+ , mnAutoCloseDistPix(5)
+ , mnFreeHandMinDistPix(10)
+ , mnCurrentInvent(SdrInventor::Default)
+ , mnCurrentIdent(SdrObjKind::NONE)
+ , mb1stPointAsCenter(false)
+ , mbUseIncompatiblePathCreateInterface(false)
+{
+}
+
+SdrCreateView::~SdrCreateView()
+{
+ ImpClearConnectMarker();
+ mpCreateViewExtraData.reset();
+ SdrObject::Free(mpCurrentCreate);
+}
+
+bool SdrCreateView::IsAction() const
+{
+ return SdrDragView::IsAction() || mpCurrentCreate!=nullptr;
+}
+
+void SdrCreateView::MovAction(const Point& rPnt)
+{
+ SdrDragView::MovAction(rPnt);
+ if (mpCurrentCreate != nullptr) {
+ MovCreateObj(rPnt);
+ }
+}
+
+void SdrCreateView::EndAction()
+{
+ if (mpCurrentCreate != nullptr) EndCreateObj(SdrCreateCmd::ForceEnd);
+ SdrDragView::EndAction();
+}
+
+void SdrCreateView::BckAction()
+{
+ if (mpCurrentCreate != nullptr) BckCreateObj();
+ SdrDragView::BckAction();
+}
+
+void SdrCreateView::BrkAction()
+{
+ SdrDragView::BrkAction();
+ BrkCreateObj();
+}
+
+void SdrCreateView::TakeActionRect(tools::Rectangle& rRect) const
+{
+ if (mpCurrentCreate != nullptr)
+ {
+ rRect=maDragStat.GetActionRect();
+ if (rRect.IsEmpty())
+ {
+ rRect=tools::Rectangle(maDragStat.GetPrev(),maDragStat.GetNow());
+ }
+ }
+ else
+ {
+ SdrDragView::TakeActionRect(rRect);
+ }
+}
+
+bool SdrCreateView::CheckEdgeMode()
+{
+ if (mpCurrentCreate != nullptr)
+ {
+ // is managed by EdgeObj
+ if (mnCurrentInvent==SdrInventor::Default && mnCurrentIdent==SdrObjKind::Edge) return false;
+ }
+
+ if (!IsCreateMode() || mnCurrentInvent!=SdrInventor::Default || mnCurrentIdent!=SdrObjKind::Edge)
+ {
+ ImpClearConnectMarker();
+ return false;
+ }
+ else
+ {
+ // sal_True, if MouseMove should check Connect
+ return !IsAction();
+ }
+}
+
+void SdrCreateView::SetConnectMarker(const SdrObjConnection& rCon)
+{
+ SdrObject* pTargetObject = rCon.pObj;
+
+ if(pTargetObject)
+ {
+ // if target object changes, throw away overlay object to make room for changes
+ if(mpCoMaOverlay && pTargetObject != &mpCoMaOverlay->GetTargetObject())
+ {
+ ImpClearConnectMarker();
+ }
+
+ if(!mpCoMaOverlay)
+ {
+ mpCoMaOverlay.reset(new ImplConnectMarkerOverlay(*this, *pTargetObject));
+ }
+ }
+ else
+ {
+ ImpClearConnectMarker();
+ }
+}
+
+void SdrCreateView::HideConnectMarker()
+{
+ ImpClearConnectMarker();
+}
+
+bool SdrCreateView::MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin)
+{
+ if(CheckEdgeMode() && pWin)
+ {
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(pPV)
+ {
+ // TODO: Change default hit tolerance at IsMarkedHit() some time!
+ Point aPos(pWin->PixelToLogic(rMEvt.GetPosPixel()));
+ bool bMarkHit=PickHandle(aPos)!=nullptr || IsMarkedObjHit(aPos);
+ SdrObjConnection aCon;
+ if (!bMarkHit) SdrEdgeObj::ImpFindConnector(aPos,*pPV,aCon,nullptr,pWin);
+ SetConnectMarker(aCon);
+ }
+ }
+ return SdrDragView::MouseMove(rMEvt,pWin);
+}
+
+bool SdrCreateView::IsTextTool() const
+{
+ return meEditMode==SdrViewEditMode::Create
+ && mnCurrentInvent==SdrInventor::Default
+ && (mnCurrentIdent==SdrObjKind::Text
+ || mnCurrentIdent==SdrObjKind::TitleText
+ || mnCurrentIdent==SdrObjKind::OutlineText);
+}
+
+bool SdrCreateView::IsEdgeTool() const
+{
+ return meEditMode==SdrViewEditMode::Create && mnCurrentInvent==SdrInventor::Default && (mnCurrentIdent==SdrObjKind::Edge);
+}
+
+bool SdrCreateView::IsMeasureTool() const
+{
+ return meEditMode==SdrViewEditMode::Create && mnCurrentInvent==SdrInventor::Default && (mnCurrentIdent==SdrObjKind::Measure);
+}
+
+void SdrCreateView::SetCurrentObj(SdrObjKind nIdent, SdrInventor nInvent)
+{
+ if (mnCurrentInvent!=nInvent || mnCurrentIdent!=nIdent)
+ {
+ mnCurrentInvent=nInvent;
+ mnCurrentIdent=nIdent;
+ SdrObject * pObj = (nIdent == SdrObjKind::NONE) ? nullptr :
+ SdrObjFactory::MakeNewObject(
+ *GetModel(),
+ nInvent,
+ nIdent);
+
+ if(pObj)
+ {
+ // Using text tool, mouse cursor is usually I-Beam,
+ // crosshairs with tiny I-Beam appears only on MouseButtonDown.
+ if(IsTextTool())
+ {
+ // Here the correct pointer needs to be used
+ // if the default is set to vertical writing
+ maCurrentCreatePointer = PointerStyle::Text;
+ }
+ else
+ maCurrentCreatePointer = pObj->GetCreatePointer();
+
+ SdrObject::Free( pObj );
+ }
+ else
+ {
+ maCurrentCreatePointer = PointerStyle::Cross;
+ }
+ }
+
+ CheckEdgeMode();
+ ImpSetGlueVisible3(IsEdgeTool());
+}
+
+bool SdrCreateView::ImpBegCreateObj(SdrInventor nInvent, SdrObjKind nIdent, const Point& rPnt, OutputDevice* pOut,
+ sal_Int16 nMinMov, const tools::Rectangle& rLogRect, SdrObject* pPreparedFactoryObject)
+{
+ bool bRet=false;
+ UnmarkAllObj();
+ BrkAction();
+
+ ImpClearConnectMarker();
+
+ mpCreatePV = GetSdrPageView();
+
+ if (mpCreatePV != nullptr)
+ { // otherwise no side registered!
+ OUString aLay(maActualLayer);
+
+ if(nInvent == SdrInventor::Default && nIdent == SdrObjKind::Measure && !maMeasureLayer.isEmpty())
+ {
+ aLay = maMeasureLayer;
+ }
+
+ SdrLayerID nLayer = mpCreatePV->GetPage()->GetLayerAdmin().GetLayerID(aLay);
+ if (nLayer==SDRLAYER_NOTFOUND) nLayer = SdrLayerID(0);
+ if (!mpCreatePV->GetLockedLayers().IsSet(nLayer) && mpCreatePV->GetVisibleLayers().IsSet(nLayer))
+ {
+ if(pPreparedFactoryObject)
+ {
+ mpCurrentCreate = pPreparedFactoryObject;
+ }
+ else
+ {
+ mpCurrentCreate = SdrObjFactory::MakeNewObject(
+ *mpModel,
+ nInvent,
+ nIdent);
+ }
+
+ Point aPnt(rPnt);
+ if (mnCurrentInvent != SdrInventor::Default || (mnCurrentIdent != SdrObjKind::Edge &&
+ mnCurrentIdent != SdrObjKind::FreehandLine &&
+ mnCurrentIdent != SdrObjKind::FreehandFill )) { // no snapping for Edge and Freehand
+ aPnt=GetSnapPos(aPnt, mpCreatePV);
+ }
+ if (mpCurrentCreate!=nullptr)
+ {
+ if (mpDefaultStyleSheet!=nullptr) mpCurrentCreate->NbcSetStyleSheet(mpDefaultStyleSheet, false);
+
+ // SW uses a naked SdrObject for frame construction. Normally, such an
+ // object should not be created. Since it is possible to use it as a helper
+ // object (e.g. in letting the user define an area with the interactive
+ // construction) at least no items should be set at that object.
+ if(nInvent != SdrInventor::Default || nIdent != SdrObjKind::NONE)
+ {
+ mpCurrentCreate->SetMergedItemSet(maDefaultAttr);
+ }
+
+ if (mpModel && dynamic_cast<const SdrCaptionObj *>(mpCurrentCreate) != nullptr)
+ {
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put(XFillColorItem(OUString(),COL_WHITE)); // in case someone turns on Solid
+ aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+
+ mpCurrentCreate->SetMergedItemSet(aSet);
+ }
+ if (mpModel && nInvent==SdrInventor::Default && (nIdent==SdrObjKind::Text ||
+ nIdent==SdrObjKind::TitleText || nIdent==SdrObjKind::OutlineText))
+ {
+ // default for all text frames: no background, no border
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put(XFillColorItem(OUString(),COL_WHITE)); // in case someone turns on Solid
+ aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ aSet.Put(XLineColorItem(OUString(),COL_BLACK)); // in case someone turns on Solid
+ aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+
+ mpCurrentCreate->SetMergedItemSet(aSet);
+ }
+ if (!rLogRect.IsEmpty()) mpCurrentCreate->NbcSetLogicRect(rLogRect);
+
+ // make sure drag start point is inside WorkArea
+ const tools::Rectangle& rWorkArea = GetWorkArea();
+
+ if(!rWorkArea.IsEmpty())
+ {
+ if(aPnt.X() < rWorkArea.Left())
+ {
+ aPnt.setX( rWorkArea.Left() );
+ }
+
+ if(aPnt.X() > rWorkArea.Right())
+ {
+ aPnt.setX( rWorkArea.Right() );
+ }
+
+ if(aPnt.Y() < rWorkArea.Top())
+ {
+ aPnt.setY( rWorkArea.Top() );
+ }
+
+ if(aPnt.Y() > rWorkArea.Bottom())
+ {
+ aPnt.setY( rWorkArea.Bottom() );
+ }
+ }
+
+ maDragStat.Reset(aPnt);
+ maDragStat.SetView(static_cast<SdrView*>(this));
+ maDragStat.SetPageView(mpCreatePV);
+ maDragStat.SetMinMove(ImpGetMinMovLogic(nMinMov,pOut));
+ mpDragWin=pOut;
+ if (mpCurrentCreate->BegCreate(maDragStat))
+ {
+ ShowCreateObj(/*pOut,sal_True*/);
+ bRet=true;
+ }
+ else
+ {
+ SdrObject::Free(mpCurrentCreate);
+ mpCurrentCreate = nullptr;
+ mpCreatePV = nullptr;
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+bool SdrCreateView::BegCreateObj(const Point& rPnt, OutputDevice* pOut, short nMinMov)
+{
+ return ImpBegCreateObj(mnCurrentInvent,mnCurrentIdent,rPnt,pOut,nMinMov,tools::Rectangle(), nullptr);
+}
+
+bool SdrCreateView::BegCreatePreparedObject(const Point& rPnt, sal_Int16 nMinMov, SdrObject* pPreparedFactoryObject)
+{
+ SdrInventor nInvent(mnCurrentInvent);
+ SdrObjKind nIdent(mnCurrentIdent);
+
+ if(pPreparedFactoryObject)
+ {
+ nInvent = pPreparedFactoryObject->GetObjInventor();
+ nIdent = pPreparedFactoryObject->GetObjIdentifier();
+ }
+
+ return ImpBegCreateObj(nInvent, nIdent, rPnt, nullptr, nMinMov, tools::Rectangle(), pPreparedFactoryObject);
+}
+
+bool SdrCreateView::BegCreateCaptionObj(const Point& rPnt, const Size& rObjSiz,
+ OutputDevice* pOut, short nMinMov)
+{
+ return ImpBegCreateObj(SdrInventor::Default,SdrObjKind::Caption,rPnt,pOut,nMinMov,
+ tools::Rectangle(rPnt,Size(rObjSiz.Width()+1,rObjSiz.Height()+1)), nullptr);
+}
+
+void SdrCreateView::MovCreateObj(const Point& rPnt)
+{
+ if (mpCurrentCreate==nullptr)
+ return;
+
+ Point aPnt(rPnt);
+ if (!maDragStat.IsNoSnap())
+ {
+ aPnt=GetSnapPos(aPnt, mpCreatePV);
+ }
+ if (IsOrtho())
+ {
+ if (maDragStat.IsOrtho8Possible()) OrthoDistance8(maDragStat.GetPrev(),aPnt,IsBigOrtho());
+ else if (maDragStat.IsOrtho4Possible()) OrthoDistance4(maDragStat.GetPrev(),aPnt,IsBigOrtho());
+ }
+
+ // If the drag point was limited and Ortho is active, do
+ // the small ortho correction (reduction) -> last parameter to FALSE.
+ bool bDidLimit(ImpLimitToWorkArea(aPnt));
+ if(bDidLimit && IsOrtho())
+ {
+ if(maDragStat.IsOrtho8Possible())
+ OrthoDistance8(maDragStat.GetPrev(), aPnt, false);
+ else if(maDragStat.IsOrtho4Possible())
+ OrthoDistance4(maDragStat.GetPrev(), aPnt, false);
+ }
+
+ if (aPnt==maDragStat.GetNow()) return;
+ bool bIsMinMoved(maDragStat.IsMinMoved());
+ if (!maDragStat.CheckMinMoved(aPnt))
+ return;
+
+ if (!bIsMinMoved) maDragStat.NextPoint();
+ maDragStat.NextMove(aPnt);
+ mpCurrentCreate->MovCreate(maDragStat);
+
+ // MovCreate changes the object, so use ActionChanged() on it
+ mpCurrentCreate->ActionChanged();
+
+ // replace for DrawCreateObjDiff
+ HideCreateObj();
+ ShowCreateObj();
+}
+
+void SdrCreateView::SetupObjLayer(const SdrPageView* pPageView, const OUString& aActiveLayer, SdrObject* pObj)
+{
+ const SdrLayerAdmin& rAd = pPageView->GetPage()->GetLayerAdmin();
+ SdrLayerID nLayer(0);
+
+ // #i72535#
+ if(dynamic_cast<const FmFormObj*>( pObj) != nullptr)
+ {
+ // for FormControls, force to form layer
+ nLayer = rAd.GetLayerID(rAd.GetControlLayerName());
+ }
+ else
+ {
+ nLayer = rAd.GetLayerID(aActiveLayer);
+ }
+
+ if(SDRLAYER_NOTFOUND == nLayer)
+ {
+ nLayer = SdrLayerID(0);
+ }
+
+ pObj->SetLayer(nLayer);
+}
+
+bool SdrCreateView::EndCreateObj(SdrCreateCmd eCmd)
+{
+ bool bRet=false;
+ SdrObject* pObjCreated=mpCurrentCreate;
+
+ if (mpCurrentCreate!=nullptr)
+ {
+ sal_uInt32 nCount=maDragStat.GetPointCount();
+
+ if (nCount<=1 && eCmd==SdrCreateCmd::ForceEnd)
+ {
+ BrkCreateObj(); // objects with only a single point don't exist (at least today)
+ return false; // sal_False = event not interpreted
+ }
+
+ bool bPntsEq=nCount>1;
+ sal_uInt32 i=1;
+ Point aP0=maDragStat.GetPoint(0);
+ while (bPntsEq && i<nCount) { bPntsEq=aP0==maDragStat.GetPoint(i); i++; }
+
+ if (mpCurrentCreate->EndCreate(maDragStat,eCmd))
+ {
+ HideCreateObj();
+
+ if (!bPntsEq)
+ {
+ // otherwise Brk, because all points are equal
+ SdrObject* pObj=mpCurrentCreate;
+ mpCurrentCreate=nullptr;
+
+ SetupObjLayer(mpCreatePV, maActualLayer, pObj);
+
+ // recognize creation of a new 3D object inside a 3D scene
+ bool bSceneIntoScene(false);
+
+ E3dScene* pObjScene = dynamic_cast<E3dScene*>(pObjCreated);
+ E3dScene* pCurrentScene = pObjScene ? dynamic_cast<E3dScene*>(mpCreatePV->GetCurrentGroup()) : nullptr;
+ if (pCurrentScene)
+ {
+ bool bDidInsert = static_cast<E3dView*>(this)->ImpCloneAll3DObjectsToDestScene(
+ pObjScene, pCurrentScene, Point(0, 0));
+
+ if(bDidInsert)
+ {
+ // delete object, its content is cloned and inserted
+ SdrObject::Free( pObjCreated );
+ pObjCreated = nullptr;
+ bSceneIntoScene = true;
+ }
+ }
+
+ if(!bSceneIntoScene)
+ {
+ // Here an interactively created SdrObject gets added, so
+ // take into account that interaction created an object in
+ // model coordinates. If we have e.g. a GirdOffset, this is a
+ // little bit tricky - we have an object in model coordinates,
+ // so the fetched offset is at the wrong point in principle
+ // since we need to 'substract' the offset here to get to
+ // 'real' model coordinates. But we have nothing better here,
+ // so go for it.
+ // The 2nd a little tricky thing is that this will early-create
+ // a ViewObjectContact for the new SdrObject, but these VOCs
+ // are anyways layouted for being create-on-demand. This will
+ // be adapted/replaced correctly later on.
+ // This *should* be the right place for getting all interactively
+ // created objects, see InsertObjectAtView below that calls
+ // CreateUndoNewObject.
+ basegfx::B2DVector aGridOffset(0.0, 0.0);
+ if(getPossibleGridOffsetForSdrObject(aGridOffset, pObj, mpCreatePV))
+ {
+ const Size aOffset(
+ basegfx::fround(-aGridOffset.getX()),
+ basegfx::fround(-aGridOffset.getY()));
+
+ pObj->NbcMove(aOffset);
+ }
+
+ // do the same as before
+ InsertObjectAtView(pObj, *mpCreatePV);
+ }
+
+ mpCreatePV = nullptr;
+ bRet=true; // sal_True = event interpreted
+ }
+ else
+ {
+ BrkCreateObj();
+ }
+ }
+ else
+ { // more points
+ if (eCmd==SdrCreateCmd::ForceEnd || // nothing there -- force ending
+ nCount==0 || // no existing points (should never happen)
+ (nCount<=1 && !maDragStat.IsMinMoved())) { // MinMove not met
+ BrkCreateObj();
+ }
+ else
+ {
+ // replace for DrawCreateObjDiff
+ HideCreateObj();
+ ShowCreateObj();
+ maDragStat.ResetMinMoved(); // NextPoint is at MovCreateObj()
+ bRet=true;
+ }
+ }
+ }
+ return bRet;
+}
+
+void SdrCreateView::BckCreateObj()
+{
+ if (mpCurrentCreate==nullptr)
+ return;
+
+ if (maDragStat.GetPointCount()<=2 )
+ {
+ BrkCreateObj();
+ }
+ else
+ {
+ HideCreateObj();
+ maDragStat.PrevPoint();
+ if (mpCurrentCreate->BckCreate(maDragStat))
+ {
+ ShowCreateObj();
+ }
+ else
+ {
+ BrkCreateObj();
+ }
+ }
+}
+
+void SdrCreateView::BrkCreateObj()
+{
+ if (mpCurrentCreate!=nullptr)
+ {
+ HideCreateObj();
+ mpCurrentCreate->BrkCreate(maDragStat);
+ SdrObject::Free( mpCurrentCreate );
+ mpCurrentCreate = nullptr;
+ mpCreatePV = nullptr;
+ }
+}
+
+void SdrCreateView::ShowCreateObj(/*OutputDevice* pOut, sal_Bool bFull*/)
+{
+ if(!IsCreateObj() || maDragStat.IsShown())
+ return;
+
+ if (mpCurrentCreate)
+ {
+ // for migration from XOR, replace DrawDragObj here to create
+ // overlay objects instead.
+ bool bUseSolidDragging(IsSolidDragging());
+
+ // #i101648# check if dragged object is a naked SdrObject (not
+ // a derivation). This is e.g. used in SW Frame construction
+ // as placeholder. Do not use SolidDragging for naked SdrObjects,
+ // they cannot have a valid optical representation
+ if(bUseSolidDragging && SdrObjKind::NONE == mpCurrentCreate->GetObjIdentifier())
+ {
+ bUseSolidDragging = false;
+ }
+
+ // check for objects with no fill and no line
+ if(bUseSolidDragging)
+ {
+ const SfxItemSet& rSet = mpCurrentCreate->GetMergedItemSet();
+ const drawing::FillStyle eFill(rSet.Get(XATTR_FILLSTYLE).GetValue());
+ const drawing::LineStyle eLine(rSet.Get(XATTR_LINESTYLE).GetValue());
+
+ if(drawing::LineStyle_NONE == eLine && drawing::FillStyle_NONE == eFill)
+ {
+ bUseSolidDragging = false;
+ }
+ }
+
+ // check for form controls
+ if(bUseSolidDragging)
+ {
+ if (dynamic_cast<const SdrUnoObj*>(mpCurrentCreate) != nullptr)
+ {
+ bUseSolidDragging = false;
+ }
+ }
+
+ // #i101781# force to non-solid dragging when not creating a full circle
+ if(bUseSolidDragging)
+ {
+ SdrCircObj* pCircObj = dynamic_cast<SdrCircObj*>(mpCurrentCreate);
+
+ if(pCircObj && SdrObjKind::CircleOrEllipse != pCircObj->GetObjIdentifier())
+ {
+ // #i103058# Allow SolidDragging with four points
+ if(maDragStat.GetPointCount() < 4)
+ {
+ bUseSolidDragging = false;
+ }
+ }
+ }
+
+ if(bUseSolidDragging)
+ {
+ basegfx::B2DPolyPolygon aDragPolyPolygon;
+
+ if (dynamic_cast<const SdrRectObj*>(mpCurrentCreate) != nullptr)
+ {
+ // ensure object has some size, necessary for SdrTextObj because
+ // there are still untested divisions by that sizes
+ tools::Rectangle aCurrentSnapRect(mpCurrentCreate->GetSnapRect());
+
+ if(aCurrentSnapRect.GetWidth() <= 1 || aCurrentSnapRect.GetHeight() <= 1)
+ {
+ tools::Rectangle aNewRect(maDragStat.GetStart(), maDragStat.GetStart() + Point(2, 2));
+ mpCurrentCreate->NbcSetSnapRect(aNewRect);
+ }
+ }
+
+ if (auto pPathObj = dynamic_cast<SdrPathObj*>(mpCurrentCreate))
+ {
+ // The up-to-now created path needs to be set at the object to have something
+ // that can be visualized
+ const basegfx::B2DPolyPolygon aCurrentPolyPolygon(pPathObj->getObjectPolyPolygon(maDragStat));
+
+ if(aCurrentPolyPolygon.count())
+ {
+ pPathObj->NbcSetPathPoly(aCurrentPolyPolygon);
+ }
+
+ aDragPolyPolygon = pPathObj->getDragPolyPolygon(maDragStat);
+ }
+
+ // use the SdrObject directly for overlay
+ mpCreateViewExtraData->CreateAndShowOverlay(*this, mpCurrentCreate, aDragPolyPolygon);
+ }
+ else
+ {
+ const ::basegfx::B2DPolyPolygon aPoly(mpCurrentCreate->TakeCreatePoly(maDragStat));
+
+ mpCreateViewExtraData->CreateAndShowOverlay(*this, nullptr, aPoly);
+ }
+
+ // #i101679# Force changed overlay to be shown
+ for(sal_uInt32 a(0); a < PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = GetPaintWindow(a);
+ const rtl::Reference<sdr::overlay::OverlayManager>& xOverlayManager = pCandidate->GetOverlayManager();
+
+ if (xOverlayManager.is())
+ {
+ xOverlayManager->flush();
+ }
+ }
+ }
+
+ maDragStat.SetShown(true);
+}
+
+void SdrCreateView::HideCreateObj()
+{
+ if(IsCreateObj() && maDragStat.IsShown())
+ {
+ // for migration from XOR, replace DrawDragObj here to create
+ // overlay objects instead.
+ mpCreateViewExtraData->HideOverlay();
+
+ //DrawCreateObj(pOut,bFull);
+ maDragStat.SetShown(false);
+ }
+}
+
+
+void SdrCreateView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
+{
+ if (mpCurrentCreate)
+ {
+ rTargetSet.Put(mpCurrentCreate->GetMergedItemSet());
+ }
+ else
+ {
+ SdrDragView::GetAttributes(rTargetSet, bOnlyHardAttr);
+ }
+}
+
+bool SdrCreateView::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
+{
+ if (mpCurrentCreate)
+ {
+ mpCurrentCreate->SetMergedItemSetAndBroadcast(rSet, bReplaceAll);
+
+ return true;
+ }
+ else
+ {
+ return SdrDragView::SetAttributes(rSet,bReplaceAll);
+ }
+}
+
+SfxStyleSheet* SdrCreateView::GetStyleSheet() const
+{
+ if (mpCurrentCreate != nullptr)
+ {
+ return mpCurrentCreate->GetStyleSheet();
+ }
+ else
+ {
+ return SdrDragView::GetStyleSheet();
+ }
+}
+
+void SdrCreateView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
+{
+ if (mpCurrentCreate != nullptr)
+ {
+ mpCurrentCreate->SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
+ }
+ else
+ {
+ SdrDragView::SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svddrag.cxx b/svx/source/svdraw/svddrag.cxx
new file mode 100644
index 000000000..0c785dc67
--- /dev/null
+++ b/svx/source/svdraw/svddrag.cxx
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdview.hxx>
+#include <svx/svddrag.hxx>
+
+SdrDragStatUserData::~SdrDragStatUserData() = default;
+
+SdrDragStat::~SdrDragStat()
+{
+}
+
+void SdrDragStat::Clear()
+{
+ mpUserData.reset();
+ mvPnts.clear();
+ mvPnts.emplace_back();
+}
+
+void SdrDragStat::Reset()
+{
+ pView=nullptr;
+ pPageView=nullptr;
+ bShown=false;
+ nMinMov=1;
+ bMinMoved=false;
+ bHorFixed=false;
+ bVerFixed=false;
+ bWantNoSnap=false;
+ pHdl=nullptr;
+ bOrtho4=false;
+ bOrtho8=false;
+ pDragMethod=nullptr;
+ bEndDragChangesAttributes=false;
+ bEndDragChangesGeoAndAttributes=false;
+ mbEndDragChangesLayout=false;
+ bMouseIsUp=false;
+ Clear();
+ aActionRect=tools::Rectangle();
+}
+
+void SdrDragStat::Reset(const Point& rPnt)
+{
+ Reset();
+ mvPnts[0]=rPnt;
+ aPos0=rPnt;
+ aRealNow=rPnt;
+}
+
+void SdrDragStat::NextMove(const Point& rPnt)
+{
+ aPos0=mvPnts.back();
+ aRealNow=rPnt;
+ mvPnts.back()=rPnt;
+}
+
+void SdrDragStat::NextPoint()
+{
+ mvPnts.emplace_back(aRealNow);
+}
+
+void SdrDragStat::PrevPoint()
+{
+ if (mvPnts.size()>1) { // one has to remain at all times
+ mvPnts.erase(mvPnts.begin()+mvPnts.size()-2);
+ mvPnts.back() = aRealNow;
+ }
+}
+
+bool SdrDragStat::CheckMinMoved(const Point& rPnt)
+{
+ if (!bMinMoved) {
+ tools::Long dx=rPnt.X()-GetPrev().X(); if (dx<0) dx=-dx;
+ tools::Long dy=rPnt.Y()-GetPrev().Y(); if (dy<0) dy=-dy;
+ if (dx>=tools::Long(nMinMov) || dy>=tools::Long(nMinMov))
+ bMinMoved=true;
+ }
+ return bMinMoved;
+}
+
+Fraction SdrDragStat::GetXFact() const
+{
+ tools::Long nMul=mvPnts.back().X()-aRef1.X();
+ tools::Long nDiv=GetPrev().X()-aRef1.X();
+ if (nDiv==0) nDiv=1;
+ if (bHorFixed) { nMul=1; nDiv=1; }
+ return Fraction(nMul,nDiv);
+}
+
+Fraction SdrDragStat::GetYFact() const
+{
+ tools::Long nMul=mvPnts.back().Y()-aRef1.Y();
+ tools::Long nDiv=GetPrev().Y()-aRef1.Y();
+ if (nDiv==0) nDiv=1;
+ if (bVerFixed) { nMul=1; nDiv=1; }
+ return Fraction(nMul,nDiv);
+}
+
+void SdrDragStat::TakeCreateRect(tools::Rectangle& rRect) const
+{
+ rRect=tools::Rectangle(mvPnts[0], mvPnts.back());
+ if (mvPnts.size()>1) {
+ Point aBtmRgt(mvPnts[1]);
+ rRect.SetRight(aBtmRgt.X() );
+ rRect.SetBottom(aBtmRgt.Y() );
+ }
+ if (pView!=nullptr && pView->IsCreate1stPointAsCenter()) {
+ rRect.AdjustTop(rRect.Top()-rRect.Bottom() );
+ rRect.AdjustLeft(rRect.Left()-rRect.Right() );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svddrgm1.hxx b/svx/source/svdraw/svddrgm1.hxx
new file mode 100644
index 000000000..54214b956
--- /dev/null
+++ b/svx/source/svdraw/svddrgm1.hxx
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_SVDRAW_SVDDRGM1_HXX
+#define INCLUDED_SVX_SOURCE_SVDRAW_SVDDRGM1_HXX
+
+#include <svx/xpoly.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svddrgv.hxx>
+#include <svx/svddrgmt.hxx>
+
+class SdrDragView;
+
+class SdrDragMovHdl : public SdrDragMethod
+{
+protected:
+ // define nothing, override to do so
+ virtual void createSdrDragEntries() override;
+
+public:
+ explicit SdrDragMovHdl(SdrDragView& rNewView);
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual bool BeginSdrDrag() override;
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+ virtual void CancelSdrDrag() override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+};
+
+class SdrDragRotate : public SdrDragMethod
+{
+private:
+ double nSin;
+ double nCos;
+ Degree100 nAngle0;
+ Degree100 nAngle;
+ bool bRight;
+
+public:
+ explicit SdrDragRotate(SdrDragView& rNewView);
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual bool BeginSdrDrag() override;
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+
+ virtual basegfx::B2DHomMatrix getCurrentTransformation() const override;
+ virtual void applyCurrentTransformationToSdrObject(SdrObject& rTarget) override;
+};
+
+class SdrDragShear : public SdrDragMethod
+{
+private:
+ Fraction aFact;
+ Degree100 nAngle0;
+ Degree100 nAngle;
+ double nTan;
+ bool bVertical; // contort vertically
+ bool bResize; // shear and resize
+ bool bUpSideDown; // mirror and shear/slant
+ bool bSlant;
+
+public:
+ SdrDragShear(SdrDragView& rNewView,bool bSlant1);
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual bool BeginSdrDrag() override;
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+
+ virtual basegfx::B2DHomMatrix getCurrentTransformation() const override;
+ virtual void applyCurrentTransformationToSdrObject(SdrObject& rTarget) override;
+};
+
+class SdrDragMirror : public SdrDragMethod
+{
+private:
+ Point aDif;
+ Degree100 nAngle;
+ bool bMirrored;
+ bool bSide0;
+
+ bool ImpCheckSide(const Point& rPnt) const;
+
+public:
+ explicit SdrDragMirror(SdrDragView& rNewView);
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual bool BeginSdrDrag() override;
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+
+ virtual basegfx::B2DHomMatrix getCurrentTransformation() const override;
+ virtual void applyCurrentTransformationToSdrObject(SdrObject& rTarget) override;
+};
+
+class SdrDragGradient : public SdrDragMethod
+{
+private:
+ // Handles to work on
+ SdrHdlGradient* pIAOHandle;
+
+ // is this for gradient (or for transparency)?
+ bool bIsGradient : 1;
+
+public:
+ SdrDragGradient(SdrDragView& rNewView, bool bGrad = true);
+
+ bool IsGradient() const { return bIsGradient; }
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual bool BeginSdrDrag() override;
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+ virtual void CancelSdrDrag() override;
+};
+
+class SdrDragCrook : public SdrDragMethod
+{
+private:
+ tools::Rectangle aMarkRect;
+ Point aMarkCenter;
+ Point aCenter;
+ Point aStart;
+ Fraction aFact;
+ Point aRad;
+ bool bContortionAllowed;
+ bool bNoContortionAllowed;
+ bool bContortion;
+ bool bResizeAllowed;
+ bool bResize;
+ bool bRotateAllowed;
+ bool bRotate;
+ bool bVertical;
+ bool bValid;
+ bool bLft;
+ bool bRgt;
+ bool bUpr;
+ bool bLwr;
+ bool bAtCenter;
+ Degree100 nAngle;
+ tools::Long nMarkSize;
+ SdrCrookMode eMode;
+
+ // helpers for applyCurrentTransformationToPolyPolygon
+ void MovAllPoints(basegfx::B2DPolyPolygon& rTarget);
+ void MovCrookPoint(Point& rPnt, Point* pC1, Point* pC2);
+
+protected:
+ // needs to add drag geometry to the default
+ virtual void createSdrDragEntries() override;
+
+public:
+ explicit SdrDragCrook(SdrDragView& rNewView);
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual bool BeginSdrDrag() override;
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+
+ virtual void applyCurrentTransformationToSdrObject(SdrObject& rTarget) override;
+ virtual void applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget) override;
+};
+
+class SdrDragDistort : public SdrDragMethod
+{
+private:
+ tools::Rectangle aMarkRect;
+ XPolygon aDistortedRect;
+ sal_uInt16 nPolyPt;
+ bool bContortionAllowed;
+ bool bNoContortionAllowed;
+ bool bContortion;
+
+ // helper for applyCurrentTransformationToPolyPolygon
+ void MovAllPoints(basegfx::B2DPolyPolygon& rTarget);
+
+protected:
+ // needs to add drag geometry to the default
+ virtual void createSdrDragEntries() override;
+
+public:
+ explicit SdrDragDistort(SdrDragView& rNewView);
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual bool BeginSdrDrag() override;
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+
+ virtual void applyCurrentTransformationToSdrObject(SdrObject& rTarget) override;
+ virtual void applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget) override;
+};
+
+// derive from SdrDragObjOwn to have handles aligned to object when it
+// is sheared or rotated
+class SdrDragCrop : public SdrDragObjOwn
+{
+public:
+ explicit SdrDragCrop(SdrDragView& rNewView);
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual bool BeginSdrDrag() override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+};
+
+#endif // INCLUDED_SVX_SOURCE_SVDRAW_SVDDRGM1_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx
new file mode 100644
index 000000000..40fd8df27
--- /dev/null
+++ b/svx/source/svdraw/svddrgmt.cxx
@@ -0,0 +1,3860 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "svddrgm1.hxx"
+#include <math.h>
+
+#include <o3tl/numeric.hxx>
+#include <osl/diagnose.h>
+#include <vcl/canvastools.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <svx/xpoly.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svddrgv.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/sdgcpitm.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <sdr/overlay/overlayrollingrectangle.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/polypolygoneditor.hxx>
+#include <drawinglayer/primitive2d/PolygonMarkerPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonSelectionPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <sdr/primitive2d/sdrprimitivetools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/attribute/sdrlineattribute.hxx>
+#include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
+#include <svl/itempool.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <comphelper/lok.hxx>
+#include <map>
+#include <vector>
+
+
+SdrDragEntry::SdrDragEntry()
+: mbAddToTransparent(false)
+{
+}
+
+SdrDragEntry::~SdrDragEntry()
+{
+}
+
+
+SdrDragEntryPolyPolygon::SdrDragEntryPolyPolygon(const basegfx::B2DPolyPolygon& rOriginalPolyPolygon)
+: maOriginalPolyPolygon(rOriginalPolyPolygon)
+{
+}
+
+SdrDragEntryPolyPolygon::~SdrDragEntryPolyPolygon()
+{
+}
+
+drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPolyPolygon::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
+{
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(maOriginalPolyPolygon.count())
+ {
+ basegfx::B2DPolyPolygon aCopy(maOriginalPolyPolygon);
+
+ rDragMethod.applyCurrentTransformationToPolyPolygon(aCopy);
+ basegfx::BColor aColA(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
+ basegfx::BColor aColB(SvtOptionsDrawinglayer::GetStripeColorB().getBColor());
+ const double fStripeLength(SvtOptionsDrawinglayer::GetStripeLength());
+
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
+ aColB.invert();
+ }
+
+ aRetval.resize(2);
+ aRetval[0] = new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
+ aCopy,
+ aColA,
+ aColB,
+ fStripeLength);
+
+ const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor());
+ const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
+
+ aRetval[1] = new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D(
+ aCopy,
+ aHilightColor,
+ fTransparence,
+ 3.0,
+ false);
+ }
+
+ return aRetval;
+}
+
+
+SdrDragEntrySdrObject::SdrDragEntrySdrObject(
+ const SdrObject& rOriginal,
+ bool bModify)
+: maOriginal(rOriginal),
+ mbModify(bModify)
+{
+ // add SdrObject parts to transparent overlay stuff
+ setAddToTransparent(true);
+}
+
+SdrDragEntrySdrObject::~SdrDragEntrySdrObject()
+{
+}
+
+void SdrDragEntrySdrObject::prepareCurrentState(SdrDragMethod& rDragMethod)
+{
+ // for the moment, i need to re-create the clone in all cases. I need to figure
+ // out when clone and original have the same class, so that i can use operator=
+ // in those cases
+
+ mxClone.reset();
+
+ if(mbModify)
+ {
+ mxClone = maOriginal.getFullDragClone();
+
+ // apply original transformation, implemented at the DragMethods
+ rDragMethod.applyCurrentTransformationToSdrObject(*mxClone);
+ }
+}
+
+drawinglayer::primitive2d::Primitive2DContainer SdrDragEntrySdrObject::createPrimitive2DSequenceInCurrentState(SdrDragMethod&)
+{
+ const SdrObject* pSource = &maOriginal;
+
+ if(mbModify && mxClone)
+ {
+ // choose source for geometry data
+ pSource = mxClone.get();
+ }
+
+ // use the view-independent primitive representation (without
+ // evtl. GridOffset, that may be applied to the DragEntry individually)
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ pSource->GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
+ return xRetval;
+}
+
+
+SdrDragEntryPrimitive2DSequence::SdrDragEntryPrimitive2DSequence(
+ drawinglayer::primitive2d::Primitive2DContainer&& rSequence)
+: maPrimitive2DSequence(std::move(rSequence))
+{
+ // add parts to transparent overlay stuff if necessary
+ setAddToTransparent(true);
+}
+
+SdrDragEntryPrimitive2DSequence::~SdrDragEntryPrimitive2DSequence()
+{
+}
+
+drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPrimitive2DSequence::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
+{
+ drawinglayer::primitive2d::Primitive2DReference aTransformPrimitive2D(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ rDragMethod.getCurrentTransformation(),
+ drawinglayer::primitive2d::Primitive2DContainer(maPrimitive2DSequence)));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aTransformPrimitive2D };
+}
+
+
+SdrDragEntryPointGlueDrag::SdrDragEntryPointGlueDrag(std::vector< basegfx::B2DPoint >&& rPositions, bool bIsPointDrag)
+: maPositions(std::move(rPositions)),
+ mbIsPointDrag(bIsPointDrag)
+{
+ // add SdrObject parts to transparent overlay stuff
+ setAddToTransparent(true);
+}
+
+SdrDragEntryPointGlueDrag::~SdrDragEntryPointGlueDrag()
+{
+}
+
+drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPointGlueDrag::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
+{
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(!maPositions.empty())
+ {
+ basegfx::B2DPolygon aPolygon;
+
+ for(auto const & a: maPositions)
+ {
+ aPolygon.append(a);
+ }
+
+ basegfx::B2DPolyPolygon aPolyPolygon(aPolygon);
+
+ rDragMethod.applyCurrentTransformationToPolyPolygon(aPolyPolygon);
+
+ const basegfx::B2DPolygon aTransformed(aPolyPolygon.getB2DPolygon(0));
+ std::vector< basegfx::B2DPoint > aTransformedPositions;
+
+ aTransformedPositions.reserve(aTransformed.count());
+
+ for(sal_uInt32 a = 0; a < aTransformed.count(); a++)
+ {
+ aTransformedPositions.push_back(aTransformed.getB2DPoint(a));
+ }
+
+ if(mbIsPointDrag)
+ {
+ basegfx::BColor aColor(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
+
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ aColor = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
+ }
+
+ drawinglayer::primitive2d::Primitive2DReference aMarkerArrayPrimitive2D(
+ new drawinglayer::primitive2d::MarkerArrayPrimitive2D(std::move(aTransformedPositions),
+ drawinglayer::primitive2d::createDefaultCross_3x3(aColor)));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aMarkerArrayPrimitive2D };
+ }
+ else
+ {
+ drawinglayer::primitive2d::Primitive2DReference aMarkerArrayPrimitive2D(
+ new drawinglayer::primitive2d::MarkerArrayPrimitive2D(std::move(aTransformedPositions),
+ SdrHdl::createGluePointBitmap()));
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aMarkerArrayPrimitive2D };
+ }
+ }
+
+ return aRetval;
+}
+
+
+void SdrDragMethod::resetSdrDragEntries()
+{
+ // clear entries; creation is on demand
+ clearSdrDragEntries();
+}
+
+basegfx::B2DRange SdrDragMethod::getCurrentRange() const
+{
+ return maOverlayObjectList.getBaseRange();
+}
+
+void SdrDragMethod::clearSdrDragEntries()
+{
+ maSdrDragEntries.clear();
+}
+
+void SdrDragMethod::addSdrDragEntry(std::unique_ptr<SdrDragEntry> pNew)
+{
+ assert(pNew);
+ maSdrDragEntries.push_back(std::move(pNew));
+}
+
+void SdrDragMethod::createSdrDragEntries()
+{
+ if(!(getSdrDragView().GetSdrPageView() && getSdrDragView().GetSdrPageView()->HasMarkedObjPageView()))
+ return;
+
+ if(getSdrDragView().IsDraggingPoints())
+ {
+ createSdrDragEntries_PointDrag();
+ }
+ else if(getSdrDragView().IsDraggingGluePoints())
+ {
+ createSdrDragEntries_GlueDrag();
+ }
+ else
+ {
+ if(getSolidDraggingActive())
+ {
+ createSdrDragEntries_SolidDrag();
+ }
+ else
+ {
+ createSdrDragEntries_PolygonDrag();
+ }
+ }
+}
+
+void SdrDragMethod::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
+{
+ // add full object drag; Clone() at the object has to work
+ // for this
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(rOriginal, true/*bModify*/)));
+}
+
+void SdrDragMethod::insertNewlyCreatedOverlayObjectForSdrDragMethod(
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
+ const sdr::contact::ObjectContact& rObjectContact,
+ sdr::overlay::OverlayManager& rOverlayManager)
+{
+ // check if we have an OverlayObject
+ if(!pOverlayObject)
+ {
+ return;
+ }
+
+ // add to OverlayManager
+ rOverlayManager.add(*pOverlayObject);
+
+ // Add GridOffset for non-linear ViewToDevice transformation (calc)
+ if(rObjectContact.supportsGridOffsets())
+ {
+ const basegfx::B2DRange& rNewRange(pOverlayObject->getBaseRange());
+
+ if(!rNewRange.isEmpty())
+ {
+ basegfx::B2DVector aOffset(0.0, 0.0);
+ rObjectContact.calculateGridOffsetForB2DRange(aOffset, rNewRange);
+
+ if(!aOffset.equalZero())
+ {
+ pOverlayObject->setOffset(aOffset);
+ }
+ }
+ }
+
+ // add to local OverlayObjectList - ownership change (!)
+ maOverlayObjectList.append(std::move(pOverlayObject));
+}
+
+void SdrDragMethod::createSdrDragEntries_SolidDrag()
+{
+ const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
+ SdrPageView* pPV = getSdrDragView().GetSdrPageView();
+
+ if(!pPV)
+ return;
+
+ for(size_t a = 0; a < nMarkCount; ++a)
+ {
+ SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(a);
+
+ if(pM->GetPageView() == pPV)
+ {
+ const SdrObject* pObject = pM->GetMarkedSdrObj();
+
+ if(pObject)
+ {
+ if(pPV->PageWindowCount())
+ {
+ SdrObjListIter aIter(*pObject);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pCandidate = aIter.Next();
+
+ if(pCandidate)
+ {
+ const bool bSuppressFullDrag(!pCandidate->supportsFullDrag());
+ bool bAddWireframe(bSuppressFullDrag);
+
+ if(!bAddWireframe && !pCandidate->HasLineStyle())
+ {
+ // add wireframe for objects without outline
+ bAddWireframe = true;
+ }
+
+ if(!bSuppressFullDrag)
+ {
+ // add full object drag; Clone() at the object has to work
+ // for this
+ createSdrDragEntryForSdrObject(*pCandidate);
+ }
+
+ if(bAddWireframe)
+ {
+ // when dragging a 50% transparent copy of a filled or not filled object without
+ // outline, this is normally hard to see. Add extra wireframe in that case. This
+ // works nice e.g. with text frames etc.
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(pCandidate->TakeXorPoly())));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void SdrDragMethod::createSdrDragEntries_PolygonDrag()
+{
+ const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
+ bool bNoPolygons(getSdrDragView().IsNoDragXorPolys() || nMarkCount > SdrDragView::GetDragXorPolyLimit());
+ basegfx::B2DPolyPolygon aResult;
+ sal_uInt32 nPointCount(0);
+
+ for(size_t a = 0; !bNoPolygons && a < nMarkCount; ++a)
+ {
+ SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(a);
+
+ if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
+ {
+ const basegfx::B2DPolyPolygon aNewPolyPolygon(pM->GetMarkedSdrObj()->TakeXorPoly());
+
+ for(auto const& rPolygon : aNewPolyPolygon)
+ {
+ nPointCount += rPolygon.count();
+ }
+
+ if(nPointCount > SdrDragView::GetDragXorPointLimit())
+ {
+ bNoPolygons = true;
+ }
+
+ if(!bNoPolygons)
+ {
+ aResult.append(aNewPolyPolygon);
+ }
+ }
+ }
+
+ if(bNoPolygons)
+ {
+ const tools::Rectangle aR(getSdrDragView().GetSdrPageView()->MarkSnap());
+ const basegfx::B2DRange aNewRectangle = vcl::unotools::b2DRectangleFromRectangle(aR);
+ basegfx::B2DPolygon aNewPolygon(basegfx::utils::createPolygonFromRect(aNewRectangle));
+
+ aResult = basegfx::B2DPolyPolygon(basegfx::utils::expandToCurve(aNewPolygon));
+ }
+
+ if(aResult.count())
+ {
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aResult)));
+ }
+}
+
+void SdrDragMethod::createSdrDragEntries_PointDrag()
+{
+ const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
+ std::vector< basegfx::B2DPoint > aPositions;
+
+ for(size_t nm = 0; nm < nMarkCount; ++nm)
+ {
+ SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(nm);
+
+ if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
+ {
+ const SdrUShortCont& rPts = pM->GetMarkedPoints();
+
+ if (!rPts.empty())
+ {
+ const SdrObject* pObj = pM->GetMarkedSdrObj();
+ const SdrPathObj* pPath = dynamic_cast< const SdrPathObj* >(pObj);
+
+ if(pPath)
+ {
+ const basegfx::B2DPolyPolygon& aPathXPP = pPath->GetPathPoly();
+
+ if(aPathXPP.count())
+ {
+ for(const sal_uInt16 nObjPt : rPts)
+ {
+ sal_uInt32 nPolyNum, nPointNum;
+
+ if(sdr::PolyPolygonEditor::GetRelativePolyPoint(aPathXPP, nObjPt, nPolyNum, nPointNum))
+ {
+ aPositions.push_back(aPathXPP.getB2DPolygon(nPolyNum).getB2DPoint(nPointNum));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(!aPositions.empty())
+ {
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPointGlueDrag(std::move(aPositions), true)));
+ }
+}
+
+void SdrDragMethod::createSdrDragEntries_GlueDrag()
+{
+ const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
+ std::vector< basegfx::B2DPoint > aPositions;
+
+ for(size_t nm = 0; nm < nMarkCount; ++nm)
+ {
+ SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(nm);
+
+ if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
+ {
+ const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+
+ if (!rPts.empty())
+ {
+ const SdrObject* pObj = pM->GetMarkedSdrObj();
+ const SdrGluePointList* pGPL = pObj->GetGluePointList();
+
+ if (pGPL)
+ {
+ for(const sal_uInt16 nObjPt : rPts)
+ {
+ const sal_uInt16 nGlueNum(pGPL->FindGluePoint(nObjPt));
+
+ if(SDRGLUEPOINT_NOTFOUND != nGlueNum)
+ {
+ const Point aPoint((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
+ aPositions.emplace_back(aPoint.X(), aPoint.Y());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(!aPositions.empty())
+ {
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPointGlueDrag(std::move(aPositions), false)));
+ }
+}
+
+OUString SdrDragMethod::ImpGetDescriptionStr(TranslateId pStrCacheID) const
+{
+ ImpGetDescriptionOptions nOpt=ImpGetDescriptionOptions::NONE;
+ if (IsDraggingPoints()) {
+ nOpt=ImpGetDescriptionOptions::POINTS;
+ } else if (IsDraggingGluePoints()) {
+ nOpt=ImpGetDescriptionOptions::GLUEPOINTS;
+ }
+ return getSdrDragView().ImpGetDescriptionString(pStrCacheID, nOpt);
+}
+
+SdrObject* SdrDragMethod::GetDragObj() const
+{
+ SdrObject* pObj=nullptr;
+ if (getSdrDragView().mpDragHdl!=nullptr) pObj=getSdrDragView().mpDragHdl->GetObj();
+ if (pObj==nullptr) pObj=getSdrDragView().mpMarkedObj;
+ return pObj;
+}
+
+SdrPageView* SdrDragMethod::GetDragPV() const
+{
+ SdrPageView* pPV=nullptr;
+ if (getSdrDragView().mpDragHdl!=nullptr) pPV=getSdrDragView().mpDragHdl->GetPageView();
+ if (pPV==nullptr) pPV=getSdrDragView().mpMarkedPV;
+ return pPV;
+}
+
+void SdrDragMethod::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
+{
+ // the original applies the transformation using TRGetBaseGeometry/TRSetBaseGeometry.
+ // Later this should be the only needed one for linear transforms (not for SdrDragCrook and
+ // SdrDragDistort, those are NOT linear). Currently, this can not yet be used since the
+ // special handling of rotate/mirror due to the not-being-able to handle it in the old
+ // drawinglayer stuff. Text would currently not correctly be mirrored in the preview.
+ basegfx::B2DHomMatrix aObjectTransform;
+ basegfx::B2DPolyPolygon aObjectPolyPolygon;
+ bool bPolyUsed(rTarget.TRGetBaseGeometry(aObjectTransform, aObjectPolyPolygon));
+
+ // apply transform to object transform
+ aObjectTransform *= getCurrentTransformation();
+
+ if(bPolyUsed)
+ {
+ // do something special since the object size is in the polygon
+ // break up matrix to get the scale
+ const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aObjectTransform);
+
+ // get polygon's position and size
+ const basegfx::B2DRange aPolyRange(aObjectPolyPolygon.getB2DRange());
+
+ // get the scaling factors (do not mirror, this is in the object transformation)
+ const double fScaleX(fabs(aTmpDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth()));
+ const double fScaleY(fabs(aTmpDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight()));
+
+ // prepare transform matrix for polygon
+ basegfx::B2DHomMatrix aPolyTransform(
+ basegfx::utils::createTranslateB2DHomMatrix(
+ -aPolyRange.getMinX(),
+ -aPolyRange.getMinY()));
+ aPolyTransform.scale(fScaleX, fScaleY);
+
+ // transform the polygon
+ aObjectPolyPolygon.transform(aPolyTransform);
+ }
+
+ rTarget.TRSetBaseGeometry(getCurrentTransformation() * aObjectTransform, aObjectPolyPolygon);
+}
+
+void SdrDragMethod::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
+{
+ // original uses CurrentTransformation
+ rTarget.transform(getCurrentTransformation());
+}
+
+SdrDragMethod::SdrDragMethod(SdrDragView& rNewView)
+: mrSdrDragView(rNewView),
+ mbMoveOnly(false),
+ mbSolidDraggingActive(getSdrDragView().IsSolidDragging()),
+ mbShiftPressed(false)
+{
+ if(mbSolidDraggingActive && Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ // fallback to wireframe when high contrast is used
+ mbSolidDraggingActive = false;
+ }
+}
+
+SdrDragMethod::~SdrDragMethod()
+{
+ clearSdrDragEntries();
+}
+
+void SdrDragMethod::Show()
+{
+ getSdrDragView().ShowDragObj();
+}
+
+void SdrDragMethod::Hide()
+{
+ getSdrDragView().HideDragObj();
+}
+
+basegfx::B2DHomMatrix SdrDragMethod::getCurrentTransformation() const
+{
+ return basegfx::B2DHomMatrix();
+}
+
+void SdrDragMethod::CancelSdrDrag()
+{
+ Hide();
+}
+
+typedef std::map< const SdrObject*, SdrObject* > SdrObjectAndCloneMap;
+
+void SdrDragMethod::CreateOverlayGeometry(
+ sdr::overlay::OverlayManager& rOverlayManager,
+ const sdr::contact::ObjectContact& rObjectContact)
+{
+ // We do client-side object manipulation with the Kit API
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+
+ // create SdrDragEntries on demand
+ if(maSdrDragEntries.empty())
+ {
+ createSdrDragEntries();
+ }
+
+ // if there are entries, derive OverlayObjects from the entries, including
+ // modification from current interactive state
+ if(!maSdrDragEntries.empty())
+ {
+ // #i54102# SdrDragEntrySdrObject creates clones of SdrObjects as base for creating the needed
+ // primitives, holding the original and the clone. If connectors (Edges) are involved,
+ // the cloned connectors need to be connected to the cloned SdrObjects (after cloning
+ // they are connected to the original SdrObjects). To do so, trigger the preparation
+ // steps for SdrDragEntrySdrObject, save an association of (orig, clone) in a helper
+ // and evtl. remember if it was an edge
+ SdrObjectAndCloneMap aOriginalAndClones;
+ std::vector< SdrEdgeObj* > aEdges;
+
+ // #i54102# execute prepareCurrentState for all SdrDragEntrySdrObject, register pair of original and
+ // clone, remember edges
+ for(auto const & a: maSdrDragEntries)
+ {
+ SdrDragEntrySdrObject* pSdrDragEntrySdrObject = dynamic_cast< SdrDragEntrySdrObject*>(a.get());
+
+ if(pSdrDragEntrySdrObject)
+ {
+ pSdrDragEntrySdrObject->prepareCurrentState(*this);
+
+ SdrEdgeObj* pSdrEdgeObj = dynamic_cast< SdrEdgeObj* >(pSdrDragEntrySdrObject->getClone());
+
+ if(pSdrEdgeObj)
+ {
+ aEdges.push_back(pSdrEdgeObj);
+ }
+
+ if(pSdrDragEntrySdrObject->getClone())
+ {
+ aOriginalAndClones[&pSdrDragEntrySdrObject->getOriginal()] = pSdrDragEntrySdrObject->getClone();
+ }
+ }
+ }
+
+ // #i54102# if there are edges, reconnect their ends to the corresponding clones (if found)
+ for(SdrEdgeObj* pSdrEdgeObj: aEdges)
+ {
+ SdrObject* pConnectedTo = pSdrEdgeObj->GetConnectedNode(true);
+
+ if(pConnectedTo)
+ {
+ SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);
+
+ if(aEntry != aOriginalAndClones.end())
+ {
+ pSdrEdgeObj->ConnectToNode(true, aEntry->second);
+ }
+ }
+
+ pConnectedTo = pSdrEdgeObj->GetConnectedNode(false);
+
+ if(pConnectedTo)
+ {
+ SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);
+
+ if(aEntry != aOriginalAndClones.end())
+ {
+ pSdrEdgeObj->ConnectToNode(false, aEntry->second);
+ }
+ }
+ }
+
+ // collect primitives for visualisation
+ drawinglayer::primitive2d::Primitive2DContainer aResult;
+ drawinglayer::primitive2d::Primitive2DContainer aResultTransparent;
+
+ for(auto & pCandidate: maSdrDragEntries)
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer aCandidateResult(pCandidate->createPrimitive2DSequenceInCurrentState(*this));
+
+ if(!aCandidateResult.empty())
+ {
+ if(pCandidate->getAddToTransparent())
+ {
+ aResultTransparent.append(aCandidateResult);
+ }
+ else
+ {
+ aResult.append(aCandidateResult);
+ }
+ }
+ }
+
+ if(DoAddConnectorOverlays())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer aConnectorOverlays(AddConnectorOverlays());
+
+ if(!aConnectorOverlays.empty())
+ {
+ // add connector overlays to transparent part
+ aResultTransparent.append(aConnectorOverlays);
+ }
+ }
+
+ if(!aResult.empty())
+ {
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
+ new sdr::overlay::OverlayPrimitive2DSequenceObject(
+ std::move(aResult)));
+
+ insertNewlyCreatedOverlayObjectForSdrDragMethod(
+ std::move(pNewOverlayObject),
+ rObjectContact,
+ rOverlayManager);
+ }
+
+ if(!aResultTransparent.empty())
+ {
+ drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aResultTransparent), 0.5));
+ aResultTransparent = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparencePrimitive2D };
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
+ new sdr::overlay::OverlayPrimitive2DSequenceObject(
+ std::move(aResultTransparent)));
+
+ insertNewlyCreatedOverlayObjectForSdrDragMethod(
+ std::move(pNewOverlayObject),
+ rObjectContact,
+ rOverlayManager);
+ }
+ }
+
+ // add DragStripes if necessary (help lines cross the page when dragging)
+ if(!getSdrDragView().IsDragStripes())
+ return;
+
+ tools::Rectangle aActionRectangle;
+ getSdrDragView().TakeActionRect(aActionRectangle);
+
+ const basegfx::B2DPoint aTopLeft(aActionRectangle.Left(), aActionRectangle.Top());
+ const basegfx::B2DPoint aBottomRight(aActionRectangle.Right(), aActionRectangle.Bottom());
+ std::unique_ptr<sdr::overlay::OverlayRollingRectangleStriped> pNew(
+ new sdr::overlay::OverlayRollingRectangleStriped(
+ aTopLeft,
+ aBottomRight,
+ true,
+ false));
+
+ insertNewlyCreatedOverlayObjectForSdrDragMethod(
+ std::move(pNew),
+ rObjectContact,
+ rOverlayManager);
+}
+
+void SdrDragMethod::destroyOverlayGeometry()
+{
+ maOverlayObjectList.clear();
+}
+
+bool SdrDragMethod::DoAddConnectorOverlays()
+{
+ // these conditions are translated from SdrDragView::ImpDrawEdgeXor
+ const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();
+
+ if(!rMarkedNodes.GetMarkCount())
+ {
+ return false;
+ }
+
+ if(getSdrDragView().IsDraggingPoints() || getSdrDragView().IsDraggingGluePoints())
+ {
+ return false;
+ }
+
+ if(!getMoveOnly() && !(
+ dynamic_cast<const SdrDragMove*>(this) != nullptr || dynamic_cast<const SdrDragResize*>(this) != nullptr ||
+ dynamic_cast<const SdrDragRotate*>(this) != nullptr || dynamic_cast<const SdrDragMirror*>(this) != nullptr ))
+ {
+ return false;
+ }
+
+ // one more migrated from SdrEdgeObj::NspToggleEdgeXor
+ if( dynamic_cast< const SdrDragObjOwn* >(this) != nullptr || dynamic_cast< const SdrDragMovHdl* >(this) != nullptr )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+drawinglayer::primitive2d::Primitive2DContainer SdrDragMethod::AddConnectorOverlays()
+{
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+ const bool bDetail(getMoveOnly());
+ const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();
+
+ for(size_t a = 0; a < rMarkedNodes.GetMarkCount(); ++a)
+ {
+ SdrMark* pEM = rMarkedNodes.GetMark(a);
+
+ if(pEM && pEM->GetMarkedSdrObj())
+ {
+ SdrEdgeObj* pEdge = dynamic_cast< SdrEdgeObj* >(pEM->GetMarkedSdrObj());
+
+ if(pEdge)
+ {
+ const basegfx::B2DPolygon aEdgePolygon(pEdge->ImplAddConnectorOverlay(*this, pEM->IsCon1(), pEM->IsCon2(), bDetail));
+
+ if(aEdgePolygon.count())
+ {
+ // this polygon is a temporary calculated connector path, so it is not possible to fetch
+ // the needed primitives directly from the pEdge object which does not get changed. If full
+ // drag is on, use the SdrObjects ItemSet to create an adequate representation
+ bool bUseSolidDragging(getSolidDraggingActive());
+
+ if(bUseSolidDragging)
+ {
+ // switch off solid dragging if connector is not visible
+ if(!pEdge->HasLineStyle())
+ {
+ bUseSolidDragging = false;
+ }
+ }
+
+ if(bUseSolidDragging)
+ {
+ const SfxItemSet& rItemSet = pEdge->GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineAttribute aLine(
+ drawinglayer::primitive2d::createNewSdrLineAttribute(rItemSet));
+
+ if(!aLine.isDefault())
+ {
+ const drawinglayer::attribute::SdrLineStartEndAttribute aLineStartEnd(
+ drawinglayer::primitive2d::createNewSdrLineStartEndAttribute(
+ rItemSet,
+ aLine.getWidth()));
+
+ aRetval.push_back(drawinglayer::primitive2d::createPolygonLinePrimitive(
+ aEdgePolygon,
+ aLine,
+ aLineStartEnd));
+ }
+ }
+ else
+ {
+ basegfx::BColor aColA(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
+ basegfx::BColor aColB(SvtOptionsDrawinglayer::GetStripeColorB().getBColor());
+ const double fStripeLength(SvtOptionsDrawinglayer::GetStripeLength());
+
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
+ aColB.invert();
+ }
+
+ drawinglayer::primitive2d::Primitive2DReference aPolyPolygonMarkerPrimitive2D(
+ new drawinglayer::primitive2d::PolygonMarkerPrimitive2D(
+ aEdgePolygon, aColA, aColB, fStripeLength));
+ aRetval.push_back(aPolyPolygonMarkerPrimitive2D);
+ }
+ }
+ }
+ }
+ }
+
+ return aRetval;
+}
+
+
+SdrDragMovHdl::SdrDragMovHdl(SdrDragView& rNewView)
+: SdrDragMethod(rNewView)
+{
+}
+
+void SdrDragMovHdl::createSdrDragEntries()
+{
+ // SdrDragMovHdl does not use the default drags,
+ // but creates nothing
+}
+
+OUString SdrDragMovHdl::GetSdrDragComment() const
+{
+ OUString aStr=SvxResId(STR_DragMethMovHdl);
+ if (getSdrDragView().IsDragWithCopy()) aStr+=SvxResId(STR_EditWithCopy);
+ return aStr;
+}
+
+bool SdrDragMovHdl::BeginSdrDrag()
+{
+ if( !GetDragHdl() )
+ return false;
+
+ DragStat().SetRef1(GetDragHdl()->GetPos());
+ DragStat().SetShown(!DragStat().IsShown());
+ SdrHdlKind eKind=GetDragHdl()->GetKind();
+ SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
+ SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
+
+ if (eKind==SdrHdlKind::MirrorAxis)
+ {
+ if (pH1==nullptr || pH2==nullptr)
+ {
+ OSL_FAIL("SdrDragMovHdl::BeginSdrDrag(): Moving the axis of reflection: reference handles not found.");
+ return false;
+ }
+
+ DragStat().SetActionRect(tools::Rectangle(pH1->GetPos(),pH2->GetPos()));
+ }
+ else
+ {
+ Point aPt(GetDragHdl()->GetPos());
+ DragStat().SetActionRect(tools::Rectangle(aPt,aPt));
+ }
+
+ return true;
+}
+
+void SdrDragMovHdl::MoveSdrDrag(const Point& rNoSnapPnt)
+{
+ Point aPnt(rNoSnapPnt);
+
+ if ( !(GetDragHdl() && DragStat().CheckMinMoved(rNoSnapPnt)))
+ return;
+
+ if (GetDragHdl()->GetKind()==SdrHdlKind::MirrorAxis)
+ {
+ SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
+ SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
+
+ if (pH1==nullptr || pH2==nullptr)
+ return;
+
+ if (!DragStat().IsNoSnap())
+ {
+ tools::Long nBestXSnap=0;
+ tools::Long nBestYSnap=0;
+ bool bXSnapped=false;
+ bool bYSnapped=false;
+ Point aDif(aPnt-DragStat().GetStart());
+ getSdrDragView().CheckSnap(Ref1()+aDif,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
+ getSdrDragView().CheckSnap(Ref2()+aDif,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
+ aPnt.AdjustX(nBestXSnap );
+ aPnt.AdjustY(nBestYSnap );
+ }
+
+ if (aPnt!=DragStat().GetNow())
+ {
+ Hide();
+ DragStat().NextMove(aPnt);
+ Point aDif(DragStat().GetNow()-DragStat().GetStart());
+ pH1->SetPos(Ref1()+aDif);
+ pH2->SetPos(Ref2()+aDif);
+
+ SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
+
+ if(pHM)
+ pHM->Touch();
+
+ Show();
+ DragStat().SetActionRect(tools::Rectangle(pH1->GetPos(),pH2->GetPos()));
+ }
+ }
+ else
+ {
+ if (!DragStat().IsNoSnap()) SnapPos(aPnt);
+ Degree100 nSA(0);
+
+ if (getSdrDragView().IsAngleSnapEnabled())
+ nSA=getSdrDragView().GetSnapAngle();
+
+ if (getSdrDragView().IsMirrorAllowed(true,true))
+ { // limited
+ if (!getSdrDragView().IsMirrorAllowed()) nSA=4500_deg100;
+ if (!getSdrDragView().IsMirrorAllowed(true)) nSA=9000_deg100;
+ }
+
+ if (getSdrDragView().IsOrtho() && nSA!=9000_deg100)
+ nSA=4500_deg100;
+
+ if (nSA)
+ { // angle snapping
+ SdrHdlKind eRef=SdrHdlKind::Ref1;
+
+ if (GetDragHdl()->GetKind()==SdrHdlKind::Ref1)
+ eRef=SdrHdlKind::Ref2;
+
+ SdrHdl* pH=GetHdlList().GetHdl(eRef);
+
+ if (pH!=nullptr)
+ {
+ Point aRef(pH->GetPos());
+ Degree100 nAngle=NormAngle36000(GetAngle(aPnt-aRef));
+ Degree100 nNewAngle=nAngle;
+ nNewAngle+=nSA/2_deg100;
+ nNewAngle/=nSA;
+ nNewAngle*=nSA;
+ nNewAngle=NormAngle36000(nNewAngle);
+ double a=toRadians(nNewAngle-nAngle);
+ double nSin=sin(a);
+ double nCos=cos(a);
+ RotatePoint(aPnt,aRef,nSin,nCos);
+
+ // eliminate rounding errors for certain values
+ if (nSA==9000_deg100)
+ {
+ if (nNewAngle==0_deg100 || nNewAngle==18000_deg100) aPnt.setY(aRef.Y() );
+ if (nNewAngle==9000_deg100 || nNewAngle==27000_deg100) aPnt.setX(aRef.X() );
+ }
+
+ if (nSA==4500_deg100)
+ OrthoDistance8(aRef,aPnt,true);
+ }
+ }
+
+ if (aPnt!=DragStat().GetNow())
+ {
+ Hide();
+ DragStat().NextMove(aPnt);
+ GetDragHdl()->SetPos(DragStat().GetNow());
+ SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
+
+ if(pHM)
+ pHM->Touch();
+
+ Show();
+ DragStat().SetActionRect(tools::Rectangle(aPnt,aPnt));
+ }
+ }
+}
+
+bool SdrDragMovHdl::EndSdrDrag(bool /*bCopy*/)
+{
+ if( GetDragHdl() )
+ {
+ switch (GetDragHdl()->GetKind())
+ {
+ case SdrHdlKind::Ref1:
+ Ref1()=DragStat().GetNow();
+ break;
+
+ case SdrHdlKind::Ref2:
+ Ref2()=DragStat().GetNow();
+ break;
+
+ case SdrHdlKind::MirrorAxis:
+ Ref1()+=DragStat().GetNow()-DragStat().GetStart();
+ Ref2()+=DragStat().GetNow()-DragStat().GetStart();
+ break;
+
+ default: break;
+ }
+ }
+
+ return true;
+}
+
+void SdrDragMovHdl::CancelSdrDrag()
+{
+ Hide();
+
+ SdrHdl* pHdl = GetDragHdl();
+ if( pHdl )
+ pHdl->SetPos(DragStat().GetRef1());
+
+ SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
+
+ if(pHM)
+ pHM->Touch();
+}
+
+PointerStyle SdrDragMovHdl::GetSdrDragPointer() const
+{
+ const SdrHdl* pHdl = GetDragHdl();
+
+ if (pHdl!=nullptr)
+ {
+ return pHdl->GetPointer();
+ }
+
+ return PointerStyle::RefHand;
+}
+
+
+SdrDragObjOwn::SdrDragObjOwn(SdrDragView& rNewView)
+: SdrDragMethod(rNewView)
+{
+ const SdrObject* pObj = GetDragObj();
+
+ if(pObj)
+ {
+ // suppress full drag for some object types
+ setSolidDraggingActive(pObj->supportsFullDrag());
+ }
+}
+
+SdrDragObjOwn::~SdrDragObjOwn()
+{
+}
+
+void SdrDragObjOwn::createSdrDragEntries()
+{
+ if(!mxClone)
+ return;
+
+ basegfx::B2DPolyPolygon aDragPolyPolygon;
+ bool bAddWireframe(true);
+
+ if(getSolidDraggingActive())
+ {
+ SdrPageView* pPV = getSdrDragView().GetSdrPageView();
+
+ if(pPV && pPV->PageWindowCount())
+ {
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(*mxClone, false)));
+
+ // potentially no wireframe needed, full drag works
+ bAddWireframe = false;
+ }
+ }
+
+ if(!bAddWireframe)
+ {
+ // check for extra conditions for wireframe, e.g. no border at
+ // objects
+ if(!mxClone->HasLineStyle())
+ {
+ bAddWireframe = true;
+ }
+ }
+
+ if(bAddWireframe)
+ {
+ // use wireframe poly when full drag is off or did not work
+ aDragPolyPolygon = mxClone->TakeXorPoly();
+ }
+
+ // add evtl. extra DragPolyPolygon
+ const basegfx::B2DPolyPolygon aSpecialDragPolyPolygon(mxClone->getSpecialDragPoly(DragStat()));
+
+ if(aSpecialDragPolyPolygon.count())
+ {
+ aDragPolyPolygon.append(aSpecialDragPolyPolygon);
+ }
+
+ if(aDragPolyPolygon.count())
+ {
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aDragPolyPolygon)));
+ }
+}
+
+OUString SdrDragObjOwn::GetSdrDragComment() const
+{
+ OUString aStr;
+ // #i103058# get info string from the clone preferred, the original will
+ // not be changed. For security, use original as fallback
+ if(mxClone)
+ {
+ aStr = mxClone->getSpecialDragComment(DragStat());
+ }
+ else
+ {
+ const SdrObject* pObj = GetDragObj();
+
+ if(pObj)
+ {
+ aStr = pObj->getSpecialDragComment(DragStat());
+ }
+ }
+ return aStr;
+}
+
+bool SdrDragObjOwn::BeginSdrDrag()
+{
+ if(!mxClone)
+ {
+ const SdrObject* pObj = GetDragObj();
+
+ if(pObj && !pObj->IsResizeProtect())
+ {
+ if(pObj->beginSpecialDrag(DragStat()))
+ {
+ // create initial clone to have a start visualization
+ mxClone = pObj->getFullDragClone();
+ mxClone->applySpecialDrag(DragStat());
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void SdrDragObjOwn::MoveSdrDrag(const Point& rNoSnapPnt)
+{
+ const SdrObject* pObj = GetDragObj();
+
+ if (!pObj)
+ // No object to drag. Bail out.
+ return;
+
+ Point aPnt(rNoSnapPnt);
+ SdrPageView* pPV = GetDragPV();
+
+ if (!pPV)
+ // No page view available. Bail out.
+ return;
+
+ if(!DragStat().IsNoSnap())
+ {
+ SnapPos(aPnt);
+ }
+ if(getSdrDragView().IsOrtho())
+ {
+ if (DragStat().IsOrtho8Possible())
+ {
+ OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
+ }
+ else if (DragStat().IsOrtho4Possible())
+ {
+ OrthoDistance4(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
+ }
+ }
+
+ if (!DragStat().CheckMinMoved(rNoSnapPnt))
+ // Not moved by the minimum threshold. Nothing to do.
+ return;
+
+ Hide();
+ DragStat().NextMove(aPnt);
+
+ // since SdrDragObjOwn currently supports no transformation of
+ // existing SdrDragEntries but only their recreation, a recreation
+ // after every move is needed in this mode. Delete existing
+ // SdrDragEntries here to force their recreation in the following Show().
+ clearSdrDragEntries();
+
+ // delete current clone (after the last reference to it is deleted above)
+ mxClone.reset();
+
+ // create a new clone and modify to current drag state
+ mxClone = pObj->getFullDragClone();
+ mxClone->applySpecialDrag(DragStat());
+
+ // AutoGrowWidth may change for SdrTextObj due to the automatism used
+ // with bDisableAutoWidthOnDragging, so not only geometry changes but
+ // also this (pretty indirect) property change is possible. If it gets
+ // changed, it needs to be copied to the original since nothing will
+ // happen when it only changes in the drag clone
+ const bool bOldAutoGrowWidth(pObj->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue());
+ const bool bNewAutoGrowWidth(mxClone->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue());
+
+ if (bOldAutoGrowWidth != bNewAutoGrowWidth)
+ {
+ GetDragObj()->SetMergedItem(makeSdrTextAutoGrowWidthItem(bNewAutoGrowWidth));
+ }
+
+ Show();
+}
+
+bool SdrDragObjOwn::EndSdrDrag(bool /*bCopy*/)
+{
+ Hide();
+ std::vector< std::unique_ptr<SdrUndoAction> > vConnectorUndoActions;
+ bool bRet = false;
+ SdrObject* pObj = GetDragObj();
+
+ if(pObj)
+ {
+ std::unique_ptr<SdrUndoAction> pUndo;
+ std::unique_ptr<SdrUndoAction> pUndo2;
+ const bool bUndo = getSdrDragView().IsUndoEnabled();
+
+ if( bUndo )
+ {
+ getSdrDragView().EndTextEditCurrentView();
+ if(!getSdrDragView().IsInsObjPoint() && pObj->IsInserted() )
+ {
+ if (DragStat().IsEndDragChangesAttributes())
+ {
+ pUndo=getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj);
+
+ if (DragStat().IsEndDragChangesGeoAndAttributes())
+ {
+ vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );
+ pUndo2 = getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
+ }
+ }
+ else
+ {
+ vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );
+ pUndo= getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
+ }
+ }
+
+ if( pUndo )
+ {
+ getSdrDragView().BegUndo( pUndo->GetComment() );
+ }
+ else
+ {
+ getSdrDragView().BegUndo();
+ }
+ }
+
+ // Maybe use operator = for setting changed object data (do not change selection in
+ // view, this will destroy the interactor). This is possible since a clone is now
+ // directly modified by the modifiers. Only SdrTableObj is adding own UNDOs
+ // in its SdrTableObj::endSpecialDrag, so currently not possible. OTOH it uses
+ // a CreateUndoGeoObject(), so maybe setting SetEndDragChangesAttributes is okay. I
+ // will test this now
+ tools::Rectangle aBoundRect0;
+
+ if(pObj->GetUserCall())
+ {
+ aBoundRect0 = pObj->GetLastBoundRect();
+ }
+
+ bRet = pObj->applySpecialDrag(DragStat());
+ if (DragStat().IsEndDragChangesLayout())
+ {
+ auto pGeoUndo = dynamic_cast<SdrUndoGeoObj*>(pUndo.get());
+ if (pGeoUndo)
+ pGeoUndo->SetSkipChangeLayout(true);
+ }
+
+ if(bRet)
+ {
+ pObj->SetChanged();
+ pObj->BroadcastObjectChange();
+ pObj->SendUserCall( SdrUserCallType::Resize, aBoundRect0 );
+ }
+
+ if(bRet && bUndo )
+ {
+ getSdrDragView().AddUndoActions( std::move(vConnectorUndoActions) );
+
+ if ( pUndo )
+ {
+ getSdrDragView().AddUndo(std::move(pUndo));
+ }
+
+ if ( pUndo2 )
+ {
+ getSdrDragView().AddUndo(std::move(pUndo2));
+ }
+ }
+
+ if( bUndo )
+ getSdrDragView().EndUndo();
+ }
+
+ return bRet;
+}
+
+PointerStyle SdrDragObjOwn::GetSdrDragPointer() const
+{
+ const SdrHdl* pHdl=GetDragHdl();
+
+ if (pHdl)
+ {
+ return pHdl->GetPointer();
+ }
+
+ return PointerStyle::Move;
+}
+
+
+void SdrDragMove::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
+{
+ // use the view-independent primitive representation (without
+ // evtl. GridOffset, that may be applied to the DragEntry individually)
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ rOriginal.GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
+ addSdrDragEntry(
+ std::unique_ptr<SdrDragEntry>(
+ new SdrDragEntryPrimitive2DSequence(
+ std::move(xRetval))));
+
+}
+
+void SdrDragMove::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
+{
+ rTarget.Move(Size(DragStat().GetDX(), DragStat().GetDY()));
+}
+
+SdrDragMove::SdrDragMove(SdrDragView& rNewView)
+ : SdrDragMethod(rNewView)
+ , nBestXSnap(0)
+ , nBestYSnap(0)
+ , bXSnapped(false)
+ , bYSnapped(false)
+{
+ setMoveOnly(true);
+}
+
+OUString SdrDragMove::GetSdrDragComment() const
+{
+ OUString aStr = ImpGetDescriptionStr(STR_DragMethMove)
+ + " (x="
+ + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDX())
+ + " y="
+ + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDY())
+ + ")";
+
+ if(getSdrDragView().IsDragWithCopy())
+ {
+ if(!getSdrDragView().IsInsObjPoint() && !getSdrDragView().IsInsGluePoint())
+ {
+ aStr += SvxResId(STR_EditWithCopy);
+ }
+ }
+ return aStr;
+}
+
+bool SdrDragMove::BeginSdrDrag()
+{
+ DragStat().SetActionRect(GetMarkedRect());
+ Show();
+
+ return true;
+}
+
+basegfx::B2DHomMatrix SdrDragMove::getCurrentTransformation() const
+{
+ return basegfx::utils::createTranslateB2DHomMatrix(DragStat().GetDX(), DragStat().GetDY());
+}
+
+void SdrDragMove::ImpCheckSnap(const Point& rPt)
+{
+ Point aPt(rPt);
+ SdrSnap nRet=SnapPos(aPt);
+ aPt-=rPt;
+
+ if (nRet & SdrSnap::XSNAPPED)
+ {
+ if (bXSnapped)
+ {
+ if (std::abs(aPt.X())<std::abs(nBestXSnap))
+ {
+ nBestXSnap=aPt.X();
+ }
+ }
+ else
+ {
+ nBestXSnap=aPt.X();
+ bXSnapped=true;
+ }
+ }
+
+ if (!(nRet & SdrSnap::YSNAPPED))
+ return;
+
+ if (bYSnapped)
+ {
+ if (std::abs(aPt.Y())<std::abs(nBestYSnap))
+ {
+ nBestYSnap=aPt.Y();
+ }
+ }
+ else
+ {
+ nBestYSnap=aPt.Y();
+ bYSnapped=true;
+ }
+}
+
+void SdrDragMove::MoveSdrDrag(const Point& rNoSnapPnt_)
+{
+ nBestXSnap=0;
+ nBestYSnap=0;
+ bXSnapped=false;
+ bYSnapped=false;
+ Point aNoSnapPnt(rNoSnapPnt_);
+ const tools::Rectangle& aSR=GetMarkedRect();
+ tools::Long nMovedx=aNoSnapPnt.X()-DragStat().GetStart().X();
+ tools::Long nMovedy=aNoSnapPnt.Y()-DragStat().GetStart().Y();
+ Point aLO(aSR.TopLeft()); aLO.AdjustX(nMovedx ); aLO.AdjustY(nMovedy );
+ Point aRU(aSR.BottomRight()); aRU.AdjustX(nMovedx ); aRU.AdjustY(nMovedy );
+ Point aLU(aLO.X(),aRU.Y());
+ Point aRO(aRU.X(),aLO.Y());
+ ImpCheckSnap(aLO);
+
+ if (!getSdrDragView().IsMoveSnapOnlyTopLeft())
+ {
+ ImpCheckSnap(aRO);
+ ImpCheckSnap(aLU);
+ ImpCheckSnap(aRU);
+ }
+
+ Point aPnt(aNoSnapPnt.X()+nBestXSnap,aNoSnapPnt.Y()+nBestYSnap);
+ bool bOrtho=getSdrDragView().IsOrtho();
+
+ if (bOrtho)
+ OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
+
+ if (!DragStat().CheckMinMoved(aNoSnapPnt))
+ return;
+
+ Point aPt1(aPnt);
+ tools::Rectangle aLR(getSdrDragView().GetWorkArea());
+ bool bWorkArea=!aLR.IsEmpty();
+ bool bDragLimit=IsDragLimit();
+
+ if (bDragLimit || bWorkArea)
+ {
+ tools::Rectangle aSR2(GetMarkedRect());
+ Point aD(aPt1-DragStat().GetStart());
+
+ if (bDragLimit)
+ {
+ tools::Rectangle aR2(GetDragLimitRect());
+
+ if (bWorkArea)
+ aLR.Intersection(aR2);
+ else
+ aLR=aR2;
+ }
+
+ if (aSR2.Left()>aLR.Left() || aSR2.Right()<aLR.Right())
+ { // any space to move to?
+ aSR2.Move(aD.X(),0);
+
+ if (aSR2.Left()<aLR.Left())
+ {
+ aPt1.AdjustX( -(aSR2.Left()-aLR.Left()) );
+ }
+ else if (aSR2.Right()>aLR.Right())
+ {
+ aPt1.AdjustX( -(aSR2.Right()-aLR.Right()) );
+ }
+ }
+ else
+ aPt1.setX(DragStat().GetStart().X() ); // no space to move to
+
+ if (aSR2.Top()>aLR.Top() || aSR2.Bottom()<aLR.Bottom())
+ { // any space to move to?
+ aSR2.Move(0,aD.Y());
+
+ if (aSR2.Top()<aLR.Top())
+ {
+ aPt1.AdjustY( -(aSR2.Top()-aLR.Top()) );
+ }
+ else if (aSR2.Bottom()>aLR.Bottom())
+ {
+ aPt1.AdjustY( -(aSR2.Bottom()-aLR.Bottom()) );
+ }
+ }
+ else
+ aPt1.setY(DragStat().GetStart().Y() ); // no space to move to
+ }
+
+ if (getSdrDragView().IsDraggingGluePoints())
+ { // restrict gluepoints to the BoundRect of the Obj
+ aPt1-=DragStat().GetStart();
+ const SdrMarkList& rML=GetMarkedObjectList();
+ const size_t nMarkCount=rML.GetMarkCount();
+
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
+ {
+ const SdrMark* pM=rML.GetMark(nMarkNum);
+ const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+
+ if (!rPts.empty())
+ {
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+ const SdrGluePointList* pGPL=pObj->GetGluePointList();
+ tools::Rectangle aBound(pObj->GetCurrentBoundRect());
+
+ for (sal_uInt16 nId : rPts)
+ {
+ sal_uInt16 nGlueNum=pGPL->FindGluePoint(nId);
+
+ if (nGlueNum!=SDRGLUEPOINT_NOTFOUND)
+ {
+ Point aPt((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
+ aPt+=aPt1; // move by this much
+ if (aPt.X()<aBound.Left() ) aPt1.AdjustX( -(aPt.X()-aBound.Left()) ) ;
+ if (aPt.X()>aBound.Right() ) aPt1.AdjustX( -(aPt.X()-aBound.Right()) ) ;
+ if (aPt.Y()<aBound.Top() ) aPt1.AdjustY( -(aPt.Y()-aBound.Top()) ) ;
+ if (aPt.Y()>aBound.Bottom()) aPt1.AdjustY( -(aPt.Y()-aBound.Bottom()) );
+ }
+ }
+ }
+ }
+
+ aPt1+=DragStat().GetStart();
+ }
+
+ if (bOrtho)
+ OrthoDistance8(DragStat().GetStart(),aPt1,false);
+
+ if (aPt1!=DragStat().GetNow())
+ {
+ Hide();
+ DragStat().NextMove(aPt1);
+ tools::Rectangle aAction(GetMarkedRect());
+ aAction.Move(DragStat().GetDX(),DragStat().GetDY());
+ DragStat().SetActionRect(aAction);
+ Show();
+ }
+}
+
+bool SdrDragMove::EndSdrDrag(bool bCopy)
+{
+ Hide();
+
+ if (getSdrDragView().IsInsObjPoint() || getSdrDragView().IsInsGluePoint())
+ bCopy=false;
+
+ if (IsDraggingPoints())
+ {
+ getSdrDragView().MoveMarkedPoints(Size(DragStat().GetDX(),DragStat().GetDY()));
+ }
+ else if (IsDraggingGluePoints())
+ {
+ getSdrDragView().MoveMarkedGluePoints(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
+ }
+ else
+ {
+ getSdrDragView().MoveMarkedObj(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
+ }
+
+ return true;
+}
+
+PointerStyle SdrDragMove::GetSdrDragPointer() const
+{
+ if (IsDraggingPoints() || IsDraggingGluePoints())
+ {
+ return PointerStyle::MovePoint;
+ }
+ else
+ {
+ return PointerStyle::Move;
+ }
+}
+
+
+SdrDragResize::SdrDragResize(SdrDragView& rNewView)
+: SdrDragMethod(rNewView),
+ aXFact(1,1),
+ aYFact(1,1)
+{
+}
+
+OUString SdrDragResize::GetSdrDragComment() const
+{
+ OUString aStr = ImpGetDescriptionStr(STR_DragMethResize);
+ Fraction aFact1(1,1);
+ Point aStart(DragStat().GetStart());
+ Point aRef(DragStat().GetRef1());
+ sal_Int32 nXDiv(aStart.X() - aRef.X());
+
+ if(!nXDiv)
+ nXDiv = 1;
+
+ sal_Int32 nYDiv(aStart.Y() - aRef.Y());
+
+ if(!nYDiv)
+ nYDiv = 1;
+
+ bool bX(aXFact != aFact1 && std::abs(nXDiv) > 1);
+ bool bY(aYFact != aFact1 && std::abs(nYDiv) > 1);
+
+ if(bX || bY)
+ {
+ aStr += " (";
+
+ bool bEqual(aXFact == aYFact);
+ if(bX)
+ {
+ if(!bEqual)
+ aStr += "x=";
+
+ aStr += SdrModel::GetPercentString(aXFact);
+ }
+
+ if(bY && !bEqual)
+ {
+ if(bX)
+ aStr += " ";
+
+ aStr += "y=" + SdrModel::GetPercentString(aYFact);
+ }
+
+ aStr += ")";
+ }
+
+ if(getSdrDragView().IsDragWithCopy())
+ aStr += SvxResId(STR_EditWithCopy);
+ return aStr;
+}
+
+bool SdrDragResize::BeginSdrDrag()
+{
+ SdrHdlKind eRefHdl=SdrHdlKind::Move;
+ SdrHdl* pRefHdl=nullptr;
+
+ switch (GetDragHdlKind())
+ {
+ case SdrHdlKind::UpperLeft: eRefHdl=SdrHdlKind::LowerRight; break;
+ case SdrHdlKind::Upper: eRefHdl=SdrHdlKind::Lower; DragStat().SetHorFixed(true); break;
+ case SdrHdlKind::UpperRight: eRefHdl=SdrHdlKind::LowerLeft; break;
+ case SdrHdlKind::Left : eRefHdl=SdrHdlKind::Right; DragStat().SetVerFixed(true); break;
+ case SdrHdlKind::Right: eRefHdl=SdrHdlKind::Left ; DragStat().SetVerFixed(true); break;
+ case SdrHdlKind::LowerLeft: eRefHdl=SdrHdlKind::UpperRight; break;
+ case SdrHdlKind::Lower: eRefHdl=SdrHdlKind::Upper; DragStat().SetHorFixed(true); break;
+ case SdrHdlKind::LowerRight: eRefHdl=SdrHdlKind::UpperLeft; break;
+ default: break;
+ }
+
+ if (eRefHdl!=SdrHdlKind::Move)
+ pRefHdl=GetHdlList().GetHdl(eRefHdl);
+
+ if (pRefHdl!=nullptr && !getSdrDragView().IsResizeAtCenter())
+ {
+ DragStat().SetRef1(pRefHdl->GetPos());
+ }
+ else
+ {
+ SdrHdl* pRef1=GetHdlList().GetHdl(SdrHdlKind::UpperLeft);
+ SdrHdl* pRef2=GetHdlList().GetHdl(SdrHdlKind::LowerRight);
+
+ if (pRef1!=nullptr && pRef2!=nullptr)
+ {
+ DragStat().SetRef1(tools::Rectangle(pRef1->GetPos(),pRef2->GetPos()).Center());
+ }
+ else
+ {
+ DragStat().SetRef1(GetMarkedRect().Center());
+ }
+ }
+
+ Show();
+
+ return true;
+}
+
+basegfx::B2DHomMatrix SdrDragResize::getCurrentTransformation() const
+{
+ basegfx::B2DHomMatrix aRetval(basegfx::utils::createTranslateB2DHomMatrix(
+ -DragStat().GetRef1().X(), -DragStat().GetRef1().Y()));
+ aRetval.scale(double(aXFact), double(aYFact));
+ aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
+
+ return aRetval;
+}
+
+void SdrDragResize::MoveSdrDrag(const Point& rNoSnapPnt)
+{
+ Point aPnt(GetSnapPos(rNoSnapPnt));
+ Point aStart(DragStat().GetStart());
+ Point aRef(DragStat().GetRef1());
+ Fraction aMaxFact(0x7FFFFFFF,1);
+ tools::Rectangle aLR(getSdrDragView().GetWorkArea());
+ bool bWorkArea=!aLR.IsEmpty();
+ bool bDragLimit=IsDragLimit();
+
+ if (bDragLimit || bWorkArea)
+ {
+ tools::Rectangle aSR(GetMarkedRect());
+
+ if (bDragLimit)
+ {
+ tools::Rectangle aR2(GetDragLimitRect());
+
+ if (bWorkArea)
+ aLR.Intersection(aR2);
+ else
+ aLR=aR2;
+ }
+
+ if (aPnt.X()<aLR.Left())
+ aPnt.setX(aLR.Left() );
+ else if (aPnt.X()>aLR.Right())
+ aPnt.setX(aLR.Right() );
+
+ if (aPnt.Y()<aLR.Top())
+ aPnt.setY(aLR.Top() );
+ else if (aPnt.Y()>aLR.Bottom())
+ aPnt.setY(aLR.Bottom() );
+
+ if (aRef.X()>aSR.Left())
+ {
+ Fraction aMax(aRef.X()-aLR.Left(),aRef.X()-aSR.Left());
+
+ if (aMax<aMaxFact)
+ aMaxFact=aMax;
+ }
+
+ if (aRef.X()<aSR.Right())
+ {
+ Fraction aMax(aLR.Right()-aRef.X(),aSR.Right()-aRef.X());
+
+ if (aMax<aMaxFact)
+ aMaxFact=aMax;
+ }
+
+ if (aRef.Y()>aSR.Top())
+ {
+ Fraction aMax(aRef.Y()-aLR.Top(),aRef.Y()-aSR.Top());
+
+ if (aMax<aMaxFact)
+ aMaxFact=aMax;
+ }
+
+ if (aRef.Y()<aSR.Bottom())
+ {
+ Fraction aMax(aLR.Bottom()-aRef.Y(),aSR.Bottom()-aRef.Y());
+
+ if (aMax<aMaxFact)
+ aMaxFact=aMax;
+ }
+ }
+
+ tools::Long nXDiv=aStart.X()-aRef.X(); if (nXDiv==0) nXDiv=1;
+ tools::Long nYDiv=aStart.Y()-aRef.Y(); if (nYDiv==0) nYDiv=1;
+ tools::Long nXMul=aPnt.X()-aRef.X();
+ tools::Long nYMul=aPnt.Y()-aRef.Y();
+
+ if (nXDiv<0)
+ {
+ nXDiv=-nXDiv;
+ nXMul=-nXMul;
+ }
+
+ if (nYDiv<0)
+ {
+ nYDiv=-nYDiv;
+ nYMul=-nYMul;
+ }
+
+ bool bXNeg=nXMul<0; if (bXNeg) nXMul=-nXMul;
+ bool bYNeg=nYMul<0; if (bYNeg) nYMul=-nYMul;
+ bool bOrtho=getSdrDragView().IsOrtho() || !getSdrDragView().IsResizeAllowed();
+
+ if (!DragStat().IsHorFixed() && !DragStat().IsVerFixed())
+ {
+ if (std::abs(nXDiv)<=1 || std::abs(nYDiv)<=1)
+ bOrtho=false;
+
+ if (bOrtho)
+ {
+ if ((Fraction(nXMul,nXDiv)>Fraction(nYMul,nYDiv)) !=getSdrDragView().IsBigOrtho())
+ {
+ nXMul=nYMul;
+ nXDiv=nYDiv;
+ }
+ else
+ {
+ nYMul=nXMul;
+ nYDiv=nXDiv;
+ }
+ }
+ }
+ else
+ {
+ if (bOrtho)
+ {
+ if (DragStat().IsHorFixed())
+ {
+ bXNeg=false;
+ nXMul=nYMul;
+ nXDiv=nYDiv;
+ }
+
+ if (DragStat().IsVerFixed())
+ {
+ bYNeg=false;
+ nYMul=nXMul;
+ nYDiv=nXDiv;
+ }
+ }
+ else
+ {
+ if (DragStat().IsHorFixed())
+ {
+ bXNeg=false;
+ nXMul=1;
+ nXDiv=1;
+ }
+
+ if (DragStat().IsVerFixed())
+ {
+ bYNeg=false;
+ nYMul=1;
+ nYDiv=1;
+ }
+ }
+ }
+
+ Fraction aNewXFact(nXMul,nXDiv);
+ Fraction aNewYFact(nYMul,nYDiv);
+
+ if (bOrtho)
+ {
+ if (aNewXFact>aMaxFact)
+ {
+ aNewXFact=aMaxFact;
+ aNewYFact=aMaxFact;
+ }
+
+ if (aNewYFact>aMaxFact)
+ {
+ aNewXFact=aMaxFact;
+ aNewYFact=aMaxFact;
+ }
+ }
+
+ if (bXNeg)
+ aNewXFact=Fraction(-aNewXFact.GetNumerator(),aNewXFact.GetDenominator());
+
+ if (bYNeg)
+ aNewYFact=Fraction(-aNewYFact.GetNumerator(),aNewYFact.GetDenominator());
+
+ if (DragStat().CheckMinMoved(aPnt))
+ {
+ if ((!DragStat().IsHorFixed() && aPnt.X()!=DragStat().GetNow().X()) ||
+ (!DragStat().IsVerFixed() && aPnt.Y()!=DragStat().GetNow().Y()))
+ {
+ Hide();
+ DragStat().NextMove(aPnt);
+ aXFact=aNewXFact;
+ aYFact=aNewYFact;
+ Show();
+ }
+ }
+}
+
+void SdrDragResize::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
+{
+ rTarget.Resize(DragStat().GetRef1(),aXFact,aYFact);
+}
+
+bool SdrDragResize::EndSdrDrag(bool bCopy)
+{
+ Hide();
+
+ if (IsDraggingPoints())
+ {
+ getSdrDragView().ResizeMarkedPoints(DragStat().GetRef1(),aXFact,aYFact);
+ }
+ else if (IsDraggingGluePoints())
+ {
+ getSdrDragView().ResizeMarkedGluePoints(DragStat().GetRef1(),aXFact,aYFact,bCopy);
+ }
+ else
+ {
+ getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),aXFact,aYFact,bCopy);
+ }
+
+ return true;
+}
+
+PointerStyle SdrDragResize::GetSdrDragPointer() const
+{
+ const SdrHdl* pHdl=GetDragHdl();
+
+ if (pHdl!=nullptr)
+ {
+ return pHdl->GetPointer();
+ }
+
+ return PointerStyle::Move;
+}
+
+
+void SdrDragRotate::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
+{
+ rTarget.Rotate(DragStat().GetRef1(), nAngle, nSin, nCos);
+}
+
+SdrDragRotate::SdrDragRotate(SdrDragView& rNewView)
+: SdrDragMethod(rNewView),
+ nSin(0.0),
+ nCos(1.0),
+ nAngle0(0),
+ nAngle(0),
+ bRight(false)
+{
+}
+
+OUString SdrDragRotate::GetSdrDragComment() const
+{
+ OUString aStr = ImpGetDescriptionStr(STR_DragMethRotate) +
+ " (";
+ Degree100 nTmpAngle(NormAngle36000(nAngle));
+
+ if(bRight && nAngle)
+ {
+ nTmpAngle -= 36000_deg100;
+ }
+
+ aStr += SdrModel::GetAngleString(nTmpAngle) + ")";
+
+ if(getSdrDragView().IsDragWithCopy())
+ aStr += SvxResId(STR_EditWithCopy);
+ return aStr;
+}
+
+bool SdrDragRotate::BeginSdrDrag()
+{
+ SdrHdl* pH=GetHdlList().GetHdl(SdrHdlKind::Ref1);
+
+ if (nullptr != pH)
+ {
+ Show();
+ DragStat().SetRef1(pH->GetPos());
+ nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
+ return true;
+ }
+
+ // RotGrfFlyFrame: Support rotation around center *without* Ref1 (normally
+ // the rotation point)
+ const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());
+
+ if(!aLocalMarkRect.IsEmpty())
+ {
+ Show();
+ DragStat().SetRef1(aLocalMarkRect.Center());
+ nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
+ return true;
+ }
+
+ OSL_FAIL("SdrDragRotate::BeginSdrDrag(): No reference point handle found.");
+ return false;
+}
+
+basegfx::B2DHomMatrix SdrDragRotate::getCurrentTransformation() const
+{
+ return basegfx::utils::createRotateAroundPoint(
+ DragStat().GetRef1().X(), DragStat().GetRef1().Y(),
+ -atan2(nSin, nCos));
+}
+
+void SdrDragRotate::MoveSdrDrag(const Point& rPnt_)
+{
+ Point aPnt(rPnt_);
+ if (!DragStat().CheckMinMoved(aPnt))
+ return;
+
+ Degree100 nNewAngle=NormAngle36000(GetAngle(aPnt-DragStat().GetRef1())-nAngle0);
+ Degree100 nSA(0);
+
+ if (getSdrDragView().IsAngleSnapEnabled())
+ nSA=getSdrDragView().GetSnapAngle();
+
+ if (!getSdrDragView().IsRotateAllowed())
+ nSA=9000_deg100;
+
+ if (nSA)
+ { // angle snapping
+ nNewAngle += nSA / 2_deg100;
+ nNewAngle /= nSA;
+ nNewAngle *= nSA;
+ }
+
+ nNewAngle=NormAngle18000(nNewAngle);
+
+ if (nAngle==nNewAngle)
+ return;
+
+ sal_uInt16 nSekt0=GetAngleSector(nAngle);
+ sal_uInt16 nSekt1=GetAngleSector(nNewAngle);
+
+ if (nSekt0==0 && nSekt1==3)
+ bRight=true;
+
+ if (nSekt0==3 && nSekt1==0)
+ bRight=false;
+
+ nAngle=nNewAngle;
+ double a = toRadians(nAngle);
+ double nSin1=sin(a); // calculate now, so as little time as possible
+ double nCos1=cos(a); // passes between Hide() and Show()
+ Hide();
+ nSin=nSin1;
+ nCos=nCos1;
+ DragStat().NextMove(aPnt);
+ Show();
+}
+
+bool SdrDragRotate::EndSdrDrag(bool bCopy)
+{
+ Hide();
+
+ if (nAngle!=0_deg100)
+ {
+ if (IsDraggingPoints())
+ {
+ getSdrDragView().RotateMarkedPoints(DragStat().GetRef1(),nAngle);
+ }
+ else if (IsDraggingGluePoints())
+ {
+ getSdrDragView().RotateMarkedGluePoints(DragStat().GetRef1(),nAngle,bCopy);
+ }
+ else
+ {
+ getSdrDragView().RotateMarkedObj(DragStat().GetRef1(),nAngle,bCopy);
+ }
+ }
+ return true;
+}
+
+PointerStyle SdrDragRotate::GetSdrDragPointer() const
+{
+ return PointerStyle::Rotate;
+}
+
+
+SdrDragShear::SdrDragShear(SdrDragView& rNewView, bool bSlant1)
+: SdrDragMethod(rNewView),
+ aFact(1,1),
+ nAngle0(0),
+ nAngle(0),
+ nTan(0.0),
+ bVertical(false),
+ bResize(false),
+ bUpSideDown(false),
+ bSlant(bSlant1)
+{
+}
+
+OUString SdrDragShear::GetSdrDragComment() const
+{
+ OUString aStr = ImpGetDescriptionStr(STR_DragMethShear) +
+ " (";
+
+ Degree100 nTmpAngle(nAngle);
+
+ if(bUpSideDown)
+ nTmpAngle += 18000_deg100;
+
+ nTmpAngle = NormAngle18000(nTmpAngle);
+
+ aStr += SdrModel::GetAngleString(nTmpAngle) + ")";
+
+ if(getSdrDragView().IsDragWithCopy())
+ aStr += SvxResId(STR_EditWithCopy);
+ return aStr;
+}
+
+bool SdrDragShear::BeginSdrDrag()
+{
+ SdrHdlKind eRefHdl=SdrHdlKind::Move;
+ SdrHdl* pRefHdl=nullptr;
+
+ switch (GetDragHdlKind())
+ {
+ case SdrHdlKind::Upper: eRefHdl=SdrHdlKind::Lower; break;
+ case SdrHdlKind::Lower: eRefHdl=SdrHdlKind::Upper; break;
+ case SdrHdlKind::Left : eRefHdl=SdrHdlKind::Right; bVertical=true; break;
+ case SdrHdlKind::Right: eRefHdl=SdrHdlKind::Left ; bVertical=true; break;
+ default: break;
+ }
+
+ if (eRefHdl!=SdrHdlKind::Move)
+ pRefHdl=GetHdlList().GetHdl(eRefHdl);
+
+ if (pRefHdl!=nullptr)
+ {
+ DragStat().SetRef1(pRefHdl->GetPos());
+ nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
+ }
+ else
+ {
+ OSL_FAIL("SdrDragShear::BeginSdrDrag(): No reference point handle for shearing found.");
+ return false;
+ }
+
+ Show();
+ return true;
+}
+
+basegfx::B2DHomMatrix SdrDragShear::getCurrentTransformation() const
+{
+ basegfx::B2DHomMatrix aRetval(basegfx::utils::createTranslateB2DHomMatrix(
+ -DragStat().GetRef1().X(), -DragStat().GetRef1().Y()));
+
+ if (bResize)
+ {
+ if (bVertical)
+ {
+ aRetval.scale(double(aFact), 1.0);
+ aRetval.shearY(-nTan);
+ }
+ else
+ {
+ aRetval.scale(1.0, double(aFact));
+ aRetval.shearX(-nTan);
+ }
+ }
+
+ aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
+
+ return aRetval;
+}
+
+void SdrDragShear::MoveSdrDrag(const Point& rPnt)
+{
+ if (!DragStat().CheckMinMoved(rPnt))
+ return;
+
+ bResize=!getSdrDragView().IsOrtho();
+ Degree100 nSA(0);
+
+ if (getSdrDragView().IsAngleSnapEnabled())
+ nSA=getSdrDragView().GetSnapAngle();
+
+ Point aP0(DragStat().GetStart());
+ Point aPnt(rPnt);
+ Fraction aNewFract(1,1);
+
+ // if angle snapping not activated, snap to raster (except when using slant)
+ if (nSA==0_deg100 && !bSlant)
+ aPnt=GetSnapPos(aPnt);
+
+ if (!bSlant && !bResize)
+ { // shear, but no resize
+ if (bVertical)
+ aPnt.setX(aP0.X() );
+ else
+ aPnt.setY(aP0.Y() );
+ }
+
+ Point aRef(DragStat().GetRef1());
+ Point aDif(aPnt-aRef);
+
+ Degree100 nNewAngle(0);
+
+ if (bSlant)
+ {
+ nNewAngle=NormAngle18000(-(GetAngle(aDif)-nAngle0));
+
+ if (bVertical)
+ nNewAngle=NormAngle18000(-nNewAngle);
+ }
+ else
+ {
+ if (bVertical)
+ nNewAngle=NormAngle18000(GetAngle(aDif));
+ else
+ nNewAngle=NormAngle18000(-(GetAngle(aDif)-9000_deg100));
+
+ if (nNewAngle<Degree100(-9000) || nNewAngle>9000_deg100)
+ nNewAngle=NormAngle18000(nNewAngle+18000_deg100);
+
+ if (bResize)
+ {
+ Point aPt2(aPnt);
+
+ if (nSA!=0_deg100)
+ aPt2=GetSnapPos(aPnt); // snap this one in any case
+
+ if (bVertical)
+ {
+ aNewFract=Fraction(aPt2.X()-aRef.X(),aP0.X()-aRef.X());
+ }
+ else
+ {
+ aNewFract=Fraction(aPt2.Y()-aRef.Y(),aP0.Y()-aRef.Y());
+ }
+ }
+ }
+
+ bool bNeg=nNewAngle<0_deg100;
+
+ if (bNeg)
+ nNewAngle=-nNewAngle;
+
+ if (nSA)
+ { // angle snapping
+ nNewAngle += nSA / 2_deg100;
+ nNewAngle /= nSA;
+ nNewAngle *= nSA;
+ }
+
+ nNewAngle=NormAngle36000(nNewAngle);
+ bUpSideDown=nNewAngle>9000_deg100 && nNewAngle<27000_deg100;
+
+ if (bSlant)
+ { // calculate resize for slant
+ // when angle snapping is activated, disable 89 degree limit
+ Degree100 nTmpAngle=nNewAngle;
+ if (bUpSideDown) nNewAngle -= 18000_deg100;
+ if (bNeg) nTmpAngle=-nTmpAngle;
+ bResize=true;
+ aNewFract = cos(toRadians(nTmpAngle));
+ aFact.ReduceInaccurate(10); // three decimals should be enough
+ }
+
+ if (nNewAngle > 8900_deg100)
+ nNewAngle = 8900_deg100;
+
+ if (bNeg)
+ nNewAngle=-nNewAngle;
+
+ if (nAngle!=nNewAngle || aFact!=aNewFract)
+ {
+ nAngle=nNewAngle;
+ aFact=aNewFract;
+ double a = toRadians(nAngle);
+ double nTan1=tan(a); // calculate now, so as little time as possible passes between Hide() and Show()
+ Hide();
+ nTan=nTan1;
+ DragStat().NextMove(rPnt);
+ Show();
+ }
+}
+
+void SdrDragShear::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
+{
+ if (bResize)
+ {
+ if (bVertical)
+ {
+ rTarget.Resize(DragStat().GetRef1(),aFact,Fraction(1,1));
+ }
+ else
+ {
+ rTarget.Resize(DragStat().GetRef1(),Fraction(1,1),aFact);
+ }
+ }
+
+ if (nAngle)
+ {
+ rTarget.Shear(DragStat().GetRef1(), nAngle, nTan, bVertical);
+ }
+}
+
+bool SdrDragShear::EndSdrDrag(bool bCopy)
+{
+ Hide();
+
+ if (bResize && aFact==Fraction(1,1))
+ bResize=false;
+
+ if (nAngle || bResize)
+ {
+ if (nAngle && bResize)
+ {
+ OUString aStr = ImpGetDescriptionStr(STR_EditShear);
+
+ if (bCopy)
+ aStr += SvxResId(STR_EditWithCopy);
+
+ getSdrDragView().BegUndo(aStr);
+ }
+
+ if (bResize)
+ {
+ if (bVertical)
+ {
+ getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),aFact,Fraction(1,1),bCopy);
+ }
+ else
+ {
+ getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),Fraction(1,1),aFact,bCopy);
+ }
+
+ bCopy=false;
+ }
+
+ if (nAngle)
+ {
+ getSdrDragView().ShearMarkedObj(DragStat().GetRef1(),nAngle,bVertical,bCopy);
+ }
+
+ if (nAngle && bResize)
+ getSdrDragView().EndUndo();
+
+ return true;
+ }
+
+ return false;
+}
+
+PointerStyle SdrDragShear::GetSdrDragPointer() const
+{
+ if (bVertical)
+ return PointerStyle::VShear;
+ else
+ return PointerStyle::HShear;
+}
+
+
+void SdrDragMirror::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
+{
+ if(bMirrored)
+ {
+ rTarget.Mirror(DragStat().GetRef1(), DragStat().GetRef2());
+ }
+}
+
+SdrDragMirror::SdrDragMirror(SdrDragView& rNewView)
+: SdrDragMethod(rNewView),
+ nAngle(0),
+ bMirrored(false),
+ bSide0(false)
+{
+}
+
+bool SdrDragMirror::ImpCheckSide(const Point& rPnt) const
+{
+ Degree100 nAngle1=GetAngle(rPnt-DragStat().GetRef1());
+ nAngle1-=nAngle;
+ nAngle1=NormAngle36000(nAngle1);
+
+ return nAngle1<18000_deg100;
+}
+
+OUString SdrDragMirror::GetSdrDragComment() const
+{
+ OUString aStr;
+ if (aDif.X()==0)
+ aStr = ImpGetDescriptionStr(STR_DragMethMirrorHori);
+ else if (aDif.Y()==0)
+ aStr = ImpGetDescriptionStr(STR_DragMethMirrorVert);
+ else if (std::abs(aDif.X()) == std::abs(aDif.Y()))
+ aStr = ImpGetDescriptionStr(STR_DragMethMirrorDiag);
+ else
+ aStr = ImpGetDescriptionStr(STR_DragMethMirrorFree);
+
+ if (getSdrDragView().IsDragWithCopy())
+ aStr+=SvxResId(STR_EditWithCopy);
+ return aStr;
+}
+
+bool SdrDragMirror::BeginSdrDrag()
+{
+ SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
+ SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
+
+ if (pH1!=nullptr && pH2!=nullptr)
+ {
+ DragStat().SetRef1(pH1->GetPos());
+ DragStat().SetRef2(pH2->GetPos());
+ Ref1()=pH1->GetPos();
+ Ref2()=pH2->GetPos();
+ aDif=pH2->GetPos()-pH1->GetPos();
+ bool b90=(aDif.X()==0) || aDif.Y()==0;
+ bool b45=b90 || (std::abs(aDif.X()) == std::abs(aDif.Y()));
+ nAngle=NormAngle36000(GetAngle(aDif));
+
+ if (!getSdrDragView().IsMirrorAllowed() && !b45)
+ return false; // free choice of axis angle not allowed
+
+ if (!getSdrDragView().IsMirrorAllowed() && !b90)
+ return false; // 45 degrees not allowed either
+
+ bSide0=ImpCheckSide(DragStat().GetStart());
+ Show();
+ return true;
+ }
+ else
+ {
+ OSL_FAIL("SdrDragMirror::BeginSdrDrag(): Axis of reflection not found.");
+ return false;
+ }
+}
+
+basegfx::B2DHomMatrix SdrDragMirror::getCurrentTransformation() const
+{
+ basegfx::B2DHomMatrix aRetval;
+
+ if (bMirrored)
+ {
+ const double fDeltaX(DragStat().GetRef2().X() - DragStat().GetRef1().X());
+ const double fDeltaY(DragStat().GetRef2().Y() - DragStat().GetRef1().Y());
+ const double fRotation(atan2(fDeltaY, fDeltaX));
+
+ aRetval = basegfx::utils::createTranslateB2DHomMatrix(-DragStat().GetRef1().X(), -DragStat().GetRef1().Y());
+ aRetval.rotate(-fRotation);
+ aRetval.scale(1.0, -1.0);
+ aRetval.rotate(fRotation);
+ aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
+ }
+
+ return aRetval;
+}
+
+void SdrDragMirror::MoveSdrDrag(const Point& rPnt)
+{
+ if (!DragStat().CheckMinMoved(rPnt))
+ return;
+
+ bool bNewSide=ImpCheckSide(rPnt);
+ bool bNewMirrored=bSide0!=bNewSide;
+
+ if (bMirrored!=bNewMirrored)
+ {
+ Hide();
+ bMirrored=bNewMirrored;
+ DragStat().NextMove(rPnt);
+ Show();
+ }
+}
+
+bool SdrDragMirror::EndSdrDrag(bool bCopy)
+{
+ Hide();
+
+ if (bMirrored)
+ {
+ getSdrDragView().MirrorMarkedObj(DragStat().GetRef1(),DragStat().GetRef2(),bCopy);
+ }
+
+ return true;
+}
+
+PointerStyle SdrDragMirror::GetSdrDragPointer() const
+{
+ return PointerStyle::Mirror;
+}
+
+
+SdrDragGradient::SdrDragGradient(SdrDragView& rNewView, bool bGrad)
+: SdrDragMethod(rNewView),
+ pIAOHandle(nullptr),
+ bIsGradient(bGrad)
+{
+}
+
+OUString SdrDragGradient::GetSdrDragComment() const
+{
+ if(IsGradient())
+ return ImpGetDescriptionStr(STR_DragMethGradient);
+ else
+ return ImpGetDescriptionStr(STR_DragMethTransparence);
+}
+
+bool SdrDragGradient::BeginSdrDrag()
+{
+ bool bRetval(false);
+
+ pIAOHandle = static_cast<SdrHdlGradient*>(GetHdlList().GetHdl(IsGradient() ? SdrHdlKind::Gradient : SdrHdlKind::Transparence));
+
+ if(pIAOHandle)
+ {
+ // save old values
+ DragStat().SetRef1( pIAOHandle->GetPos() );
+ DragStat().SetRef2( pIAOHandle->Get2ndPos() );
+
+ // what was hit?
+ bool bHit(false);
+ SdrHdlColor* pColHdl = pIAOHandle->GetColorHdl1();
+
+ // init handling flags
+ pIAOHandle->SetMoveSingleHandle(false);
+ pIAOHandle->SetMoveFirstHandle(false);
+
+ // test first color handle
+ if(pColHdl)
+ {
+ basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
+
+ if(pColHdl->getOverlayObjectList().isHitLogic(aPosition))
+ {
+ bHit = true;
+ pIAOHandle->SetMoveSingleHandle(true);
+ pIAOHandle->SetMoveFirstHandle(true);
+ }
+ }
+
+ // test second color handle
+ pColHdl = pIAOHandle->GetColorHdl2();
+
+ if(!bHit && pColHdl)
+ {
+ basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
+
+ if(pColHdl->getOverlayObjectList().isHitLogic(aPosition))
+ {
+ bHit = true;
+ pIAOHandle->SetMoveSingleHandle(true);
+ }
+ }
+
+ // test gradient handle itself
+ if(!bHit)
+ {
+ basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
+
+ if(pIAOHandle->getOverlayObjectList().isHitLogic(aPosition))
+ {
+ bHit = true;
+ }
+ }
+
+ // everything up and running :o}
+ bRetval = bHit;
+ }
+ else
+ {
+ OSL_FAIL("SdrDragGradient::BeginSdrDrag(): IAOGradient not found.");
+ }
+
+ return bRetval;
+}
+
+void SdrDragGradient::MoveSdrDrag(const Point& rPnt)
+{
+ if(!(pIAOHandle && DragStat().CheckMinMoved(rPnt)))
+ return;
+
+ DragStat().NextMove(rPnt);
+
+ // Do the Move here!!! DragStat().GetStart()
+ Point aMoveDiff = rPnt - DragStat().GetStart();
+
+ if(pIAOHandle->IsMoveSingleHandle())
+ {
+ if(pIAOHandle->IsMoveFirstHandle())
+ {
+ pIAOHandle->SetPos(DragStat().GetRef1() + aMoveDiff);
+ if(pIAOHandle->GetColorHdl1())
+ pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1() + aMoveDiff);
+ }
+ else
+ {
+ pIAOHandle->Set2ndPos(DragStat().GetRef2() + aMoveDiff);
+ if(pIAOHandle->GetColorHdl2())
+ pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2() + aMoveDiff);
+ }
+ }
+ else
+ {
+ pIAOHandle->SetPos(DragStat().GetRef1() + aMoveDiff);
+ pIAOHandle->Set2ndPos(DragStat().GetRef2() + aMoveDiff);
+
+ if(pIAOHandle->GetColorHdl1())
+ pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1() + aMoveDiff);
+
+ if(pIAOHandle->GetColorHdl2())
+ pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2() + aMoveDiff);
+ }
+
+ // new state
+ pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), false, false);
+}
+
+bool SdrDragGradient::EndSdrDrag(bool /*bCopy*/)
+{
+ Ref1() = pIAOHandle->GetPos();
+ Ref2() = pIAOHandle->Get2ndPos();
+
+ // new state
+ pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), true, true);
+
+ return true;
+}
+
+void SdrDragGradient::CancelSdrDrag()
+{
+ // restore old values
+ pIAOHandle->SetPos(DragStat().GetRef1());
+ pIAOHandle->Set2ndPos(DragStat().GetRef2());
+
+ if(pIAOHandle->GetColorHdl1())
+ pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1());
+
+ if(pIAOHandle->GetColorHdl2())
+ pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2());
+
+ // new state
+ pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), true, false);
+}
+
+PointerStyle SdrDragGradient::GetSdrDragPointer() const
+{
+ return PointerStyle::RefHand;
+}
+
+
+SdrDragCrook::SdrDragCrook(SdrDragView& rNewView)
+: SdrDragMethod(rNewView),
+ aFact(1,1),
+ bContortionAllowed(false),
+ bNoContortionAllowed(false),
+ bContortion(false),
+ bResizeAllowed(false),
+ bResize(false),
+ bRotateAllowed(false),
+ bRotate(false),
+ bVertical(false),
+ bValid(false),
+ bLft(false),
+ bRgt(false),
+ bUpr(false),
+ bLwr(false),
+ bAtCenter(false),
+ nAngle(0),
+ nMarkSize(0),
+ eMode(SdrCrookMode::Rotate)
+{
+}
+
+OUString SdrDragCrook::GetSdrDragComment() const
+{
+ OUString aStr = ImpGetDescriptionStr(!bContortion ? STR_DragMethCrook : STR_DragMethCrookContortion);
+
+ if(bValid)
+ {
+ aStr += " (";
+
+ sal_Int32 nVal(nAngle);
+
+ if(bAtCenter)
+ nVal *= 2;
+
+ nVal = std::abs(nVal);
+ aStr += SdrModel::GetAngleString(Degree100(nVal)) + ")";
+ }
+
+ if(getSdrDragView().IsDragWithCopy())
+ aStr += SvxResId(STR_EditWithCopy);
+ return aStr;
+}
+
+// These defines parametrize the created raster
+// for interactions
+#define DRAG_CROOK_RASTER_MINIMUM (4)
+#define DRAG_CROOK_RASTER_MAXIMUM (15)
+#define DRAG_CROOK_RASTER_DISTANCE (30)
+
+static basegfx::B2DPolyPolygon impCreateDragRaster(SdrPageView const & rPageView, const tools::Rectangle& rMarkRect)
+{
+ basegfx::B2DPolyPolygon aRetval;
+
+ if(rPageView.PageWindowCount())
+ {
+ OutputDevice& rOut = rPageView.GetPageWindow(0)->GetPaintWindow().GetOutputDevice();
+ tools::Rectangle aPixelSize = rOut.LogicToPixel(rMarkRect);
+ sal_uInt32 nHorDiv(aPixelSize.GetWidth() / DRAG_CROOK_RASTER_DISTANCE);
+ sal_uInt32 nVerDiv(aPixelSize.GetHeight() / DRAG_CROOK_RASTER_DISTANCE);
+
+ if(nHorDiv > DRAG_CROOK_RASTER_MAXIMUM)
+ nHorDiv = DRAG_CROOK_RASTER_MAXIMUM;
+ if(nHorDiv < DRAG_CROOK_RASTER_MINIMUM)
+ nHorDiv = DRAG_CROOK_RASTER_MINIMUM;
+
+ if(nVerDiv > DRAG_CROOK_RASTER_MAXIMUM)
+ nVerDiv = DRAG_CROOK_RASTER_MAXIMUM;
+ if(nVerDiv < DRAG_CROOK_RASTER_MINIMUM)
+ nVerDiv = DRAG_CROOK_RASTER_MINIMUM;
+
+ const double fXLen(rMarkRect.GetWidth() / static_cast<double>(nHorDiv));
+ const double fYLen(rMarkRect.GetHeight() / static_cast<double>(nVerDiv));
+ double fYPos(rMarkRect.Top());
+ sal_uInt32 a, b;
+
+ for(a = 0; a <= nVerDiv; a++)
+ {
+ // horizontal lines
+ for(b = 0; b < nHorDiv; b++)
+ {
+ basegfx::B2DPolygon aHorLineSegment;
+
+ const double fNewX(rMarkRect.Left() + (b * fXLen));
+ aHorLineSegment.append(basegfx::B2DPoint(fNewX, fYPos));
+ aHorLineSegment.appendBezierSegment(
+ basegfx::B2DPoint(fNewX + (fXLen * (1.0 / 3.0)), fYPos),
+ basegfx::B2DPoint(fNewX + (fXLen * (2.0 / 3.0)), fYPos),
+ basegfx::B2DPoint(fNewX + fXLen, fYPos));
+ aRetval.append(aHorLineSegment);
+ }
+
+ // increments
+ fYPos += fYLen;
+ }
+
+ double fXPos(rMarkRect.Left());
+
+ for(a = 0; a <= nHorDiv; a++)
+ {
+ // vertical lines
+ for(b = 0; b < nVerDiv; b++)
+ {
+ basegfx::B2DPolygon aVerLineSegment;
+
+ const double fNewY(rMarkRect.Top() + (b * fYLen));
+ aVerLineSegment.append(basegfx::B2DPoint(fXPos, fNewY));
+ aVerLineSegment.appendBezierSegment(
+ basegfx::B2DPoint(fXPos, fNewY + (fYLen * (1.0 / 3.0))),
+ basegfx::B2DPoint(fXPos, fNewY + (fYLen * (2.0 / 3.0))),
+ basegfx::B2DPoint(fXPos, fNewY + fYLen));
+ aRetval.append(aVerLineSegment);
+ }
+
+ // increments
+ fXPos += fXLen;
+ }
+ }
+
+ return aRetval;
+}
+
+void SdrDragCrook::createSdrDragEntries()
+{
+ // Add extended frame raster first, so it will be behind objects
+ if(getSdrDragView().GetSdrPageView())
+ {
+ const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect()));
+
+ if(aDragRaster.count())
+ {
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aDragRaster)));
+ }
+ }
+
+ // call parent
+ SdrDragMethod::createSdrDragEntries();
+}
+
+bool SdrDragCrook::BeginSdrDrag()
+{
+ bContortionAllowed=getSdrDragView().IsCrookAllowed();
+ bNoContortionAllowed=getSdrDragView().IsCrookAllowed(true);
+ bResizeAllowed=getSdrDragView().IsResizeAllowed();
+ bRotateAllowed=getSdrDragView().IsRotateAllowed();
+
+ if (bContortionAllowed || bNoContortionAllowed)
+ {
+ bVertical=(GetDragHdlKind()==SdrHdlKind::Lower || GetDragHdlKind()==SdrHdlKind::Upper);
+ aMarkRect=GetMarkedRect();
+ aMarkCenter=aMarkRect.Center();
+ nMarkSize=bVertical ? (aMarkRect.GetHeight()-1) : (aMarkRect.GetWidth()-1);
+ aCenter=aMarkCenter;
+ aStart=DragStat().GetStart();
+ Show();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void SdrDragCrook::MovAllPoints(basegfx::B2DPolyPolygon& rTarget)
+{
+ SdrPageView* pPV = getSdrDragView().GetSdrPageView();
+
+ if(!pPV)
+ return;
+
+ XPolyPolygon aTempPolyPoly(rTarget);
+
+ if (pPV->HasMarkedObjPageView())
+ {
+ sal_uInt16 nPolyCount=aTempPolyPoly.Count();
+
+ if (!bContortion && !getSdrDragView().IsNoDragXorPolys())
+ {
+ sal_uInt16 n1st=0,nLast=0;
+ Point aC(aCenter);
+
+ while (n1st<nPolyCount)
+ {
+ nLast=n1st;
+ while (nLast<nPolyCount && aTempPolyPoly[nLast].GetPointCount()!=0) nLast++;
+ tools::Rectangle aBound(aTempPolyPoly[n1st].GetBoundRect());
+ sal_uInt16 i;
+
+ for (i=n1st+1; i<nLast; i++)
+ {
+ aBound.Union(aTempPolyPoly[n1st].GetBoundRect());
+ }
+
+ Point aCtr0(aBound.Center());
+ Point aCtr1(aCtr0);
+
+ if (bResize)
+ {
+ Fraction aFact1(1,1);
+
+ if (bVertical)
+ {
+ ResizePoint(aCtr1,aC,aFact1,aFact);
+ }
+ else
+ {
+ ResizePoint(aCtr1,aC,aFact,aFact1);
+ }
+ }
+
+ bool bRotOk=false;
+ double nSin=0,nCos=0;
+
+ if (aRad.X()!=0 && aRad.Y()!=0)
+ {
+ bRotOk=bRotate;
+
+ switch (eMode)
+ {
+ case SdrCrookMode::Rotate : CrookRotateXPoint (aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical); break;
+ case SdrCrookMode::Slant : CrookSlantXPoint (aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical); break;
+ case SdrCrookMode::Stretch: CrookStretchXPoint(aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical,aMarkRect); break;
+ } // switch
+ }
+
+ aCtr1-=aCtr0;
+
+ for (i=n1st; i<nLast; i++)
+ {
+ if (bRotOk)
+ {
+ RotateXPoly(aTempPolyPoly[i],aCtr0,nSin,nCos);
+ }
+
+ aTempPolyPoly[i].Move(aCtr1.X(),aCtr1.Y());
+ }
+
+ n1st=nLast+1;
+ }
+ }
+ else
+ {
+ sal_uInt16 i,j;
+
+ for (j=0; j<nPolyCount; j++)
+ {
+ XPolygon& aPol=aTempPolyPoly[j];
+ sal_uInt16 nPointCount=aPol.GetPointCount();
+ i=0;
+
+ while (i<nPointCount)
+ {
+ Point* pPnt=&aPol[i];
+ Point* pC1=nullptr;
+ Point* pC2=nullptr;
+
+ if (i+1<nPointCount && aPol.IsControl(i))
+ { // control point on the left
+ pC1=pPnt;
+ i++;
+ pPnt=&aPol[i];
+ }
+
+ i++;
+
+ if (i<nPointCount && aPol.IsControl(i))
+ { // control point on the right
+ pC2=&aPol[i];
+ i++;
+ }
+
+ MovCrookPoint(*pPnt,pC1,pC2);
+ }
+ }
+ }
+ }
+
+ rTarget = aTempPolyPoly.getB2DPolyPolygon();
+}
+
+void SdrDragCrook::MovCrookPoint(Point& rPnt, Point* pC1, Point* pC2)
+{
+ bool bVert=bVertical;
+ bool bC1=pC1!=nullptr;
+ bool bC2=pC2!=nullptr;
+ Point aC(aCenter);
+
+ if (bResize)
+ {
+ Fraction aFact1(1,1);
+
+ if (bVert)
+ {
+ ResizePoint(rPnt,aC,aFact1,aFact);
+
+ if (bC1)
+ ResizePoint(*pC1,aC,aFact1,aFact);
+
+ if (bC2)
+ ResizePoint(*pC2,aC,aFact1,aFact);
+ }
+ else
+ {
+ ResizePoint(rPnt,aC,aFact,aFact1);
+
+ if (bC1)
+ ResizePoint(*pC1,aC,aFact,aFact1);
+
+ if (bC2)
+ ResizePoint(*pC2,aC,aFact,aFact1);
+ }
+ }
+
+ if (aRad.X()!=0 && aRad.Y()!=0)
+ {
+ double nSin,nCos;
+
+ switch (eMode)
+ {
+ case SdrCrookMode::Rotate : CrookRotateXPoint (rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert); break;
+ case SdrCrookMode::Slant : CrookSlantXPoint (rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert); break;
+ case SdrCrookMode::Stretch: CrookStretchXPoint(rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert,aMarkRect); break;
+ } // switch
+ }
+}
+
+void SdrDragCrook::MoveSdrDrag(const Point& rPnt)
+{
+ if (!DragStat().CheckMinMoved(rPnt))
+ return;
+
+ bool bNewMoveOnly=getSdrDragView().IsMoveOnlyDragging();
+ bAtCenter=false;
+ SdrCrookMode eNewMode=getSdrDragView().GetCrookMode();
+ bool bNewContortion=!bNewMoveOnly && ((bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed);
+ bResize=!getSdrDragView().IsOrtho() && bResizeAllowed && !bNewMoveOnly;
+ bool bNewRotate=bRotateAllowed && !bNewContortion && !bNewMoveOnly && eNewMode==SdrCrookMode::Rotate;
+
+ Point aPnt(GetSnapPos(rPnt));
+
+ Point aNewCenter(aMarkCenter.X(),aStart.Y());
+
+ if (bVertical)
+ {
+ aNewCenter.setX(aStart.X() );
+ aNewCenter.setY(aMarkCenter.Y() );
+ }
+
+ if (!getSdrDragView().IsCrookAtCenter())
+ {
+ switch (GetDragHdlKind())
+ {
+ case SdrHdlKind::UpperLeft: aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
+ case SdrHdlKind::Upper: aNewCenter.setY(aMarkRect.Bottom() ); bUpr=true; break;
+ case SdrHdlKind::UpperRight: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
+ case SdrHdlKind::Left : aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
+ case SdrHdlKind::Right: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
+ case SdrHdlKind::LowerLeft: aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
+ case SdrHdlKind::Lower: aNewCenter.setY(aMarkRect.Top() ); bLwr=true; break;
+ case SdrHdlKind::LowerRight: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
+ default: bAtCenter=true;
+ }
+ }
+ else
+ bAtCenter=true;
+
+ Fraction aNewFract(1,1);
+ tools::Long dx1=aPnt.X()-aNewCenter.X();
+ tools::Long dy1=aPnt.Y()-aNewCenter.Y();
+ bValid=bVertical ? dx1!=0 : dy1!=0;
+
+ if (bValid)
+ {
+ if (bVertical)
+ bValid = std::abs(dx1)*100>std::abs(dy1);
+ else
+ bValid = std::abs(dy1)*100>std::abs(dx1);
+ }
+
+ tools::Long nNewRad=0;
+ nAngle=0_deg100;
+
+ if (bValid)
+ {
+ double a=0; // slope of the radius
+ Degree100 nPntAngle(0);
+
+ if (bVertical)
+ {
+ a=static_cast<double>(dy1)/static_cast<double>(dx1); // slope of the radius
+ nNewRad=(static_cast<tools::Long>(dy1*a)+dx1) /2;
+ aNewCenter.AdjustX(nNewRad );
+ nPntAngle=GetAngle(aPnt-aNewCenter);
+ }
+ else
+ {
+ a=static_cast<double>(dx1)/static_cast<double>(dy1); // slope of the radius
+ nNewRad=(static_cast<tools::Long>(dx1*a)+dy1) /2;
+ aNewCenter.AdjustY(nNewRad );
+ nPntAngle=GetAngle(aPnt-aNewCenter)-9000_deg100;
+ }
+
+ if (!bAtCenter)
+ {
+ if (nNewRad<0)
+ {
+ if (bRgt) nPntAngle += 18000_deg100;
+ if (bLft) nPntAngle = 18000_deg100 - nPntAngle;
+ if (bLwr) nPntAngle =- nPntAngle;
+ }
+ else
+ {
+ if (bRgt) nPntAngle = -nPntAngle;
+ if (bUpr) nPntAngle = 18000_deg100 - nPntAngle;
+ if (bLwr) nPntAngle += 18000_deg100;
+ }
+
+ nPntAngle=NormAngle36000(nPntAngle);
+ }
+ else
+ {
+ if (nNewRad<0) nPntAngle += 18000_deg100;
+ if (bVertical) nPntAngle = 18000_deg100 - nPntAngle;
+ nPntAngle = NormAngle18000(nPntAngle);
+ nPntAngle = abs(nPntAngle);
+ }
+
+ double nCircumference = 2 * std::abs(nNewRad) * M_PI;
+
+ if (bResize)
+ {
+ tools::Long nMul=static_cast<tools::Long>(nCircumference * NormAngle36000(nPntAngle).get() / 36000.0);
+
+ if (bAtCenter)
+ nMul*=2;
+
+ aNewFract=Fraction(nMul,nMarkSize);
+ nAngle=nPntAngle;
+ }
+ else
+ {
+ nAngle = Degree100(static_cast<tools::Long>((nMarkSize*360/nCircumference)*100)/2);
+
+ if (nAngle==0_deg100)
+ bValid=false;
+ }
+ }
+
+ if (nAngle==0_deg100 || nNewRad==0)
+ bValid=false;
+
+ if (!bValid)
+ nNewRad=0;
+
+ if (!bValid && bResize)
+ {
+ tools::Long nMul=bVertical ? dy1 : dx1;
+
+ if (bLft || bUpr)
+ nMul=-nMul;
+
+ tools::Long nDiv=nMarkSize;
+
+ if (bAtCenter)
+ {
+ nMul*=2;
+ nMul = std::abs(nMul);
+ }
+
+ aNewFract=Fraction(nMul,nDiv);
+ }
+
+ if (aNewCenter==aCenter && bNewContortion==bContortion && aNewFract==aFact &&
+ bNewMoveOnly == getMoveOnly() && bNewRotate==bRotate && eNewMode==eMode)
+ return;
+
+ Hide();
+ setMoveOnly(bNewMoveOnly);
+ bRotate=bNewRotate;
+ eMode=eNewMode;
+ bContortion=bNewContortion;
+ aCenter=aNewCenter;
+ aFact=aNewFract;
+ aRad=Point(nNewRad,nNewRad);
+ bResize=aFact!=Fraction(1,1) && aFact.GetDenominator()!=0 && aFact.IsValid();
+ DragStat().NextMove(aPnt);
+ Show();
+}
+
+void SdrDragCrook::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
+{
+ const bool bDoResize(aFact!=Fraction(1,1));
+ const bool bDoCrook(aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0);
+
+ if (!(bDoCrook || bDoResize))
+ return;
+
+ if (bDoResize)
+ {
+ Fraction aFact1(1,1);
+
+ if (bContortion)
+ {
+ if (bVertical)
+ {
+ rTarget.Resize(aCenter,aFact1,aFact);
+ }
+ else
+ {
+ rTarget.Resize(aCenter,aFact,aFact1);
+ }
+ }
+ else
+ {
+ Point aCtr0(rTarget.GetSnapRect().Center());
+ Point aCtr1(aCtr0);
+
+ if (bVertical)
+ {
+ ResizePoint(aCtr1,aCenter,aFact1,aFact);
+ }
+ else
+ {
+ ResizePoint(aCtr1,aCenter,aFact,aFact1);
+ }
+
+ Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y());
+
+ rTarget.Move(aSiz);
+ }
+ }
+
+ if (bDoCrook)
+ {
+ const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());
+ const bool bLocalRotate(!bContortion && eMode == SdrCrookMode::Rotate && getSdrDragView().IsRotateAllowed());
+
+ SdrEditView::ImpCrookObj(&rTarget,aCenter,aRad,eMode,bVertical,!bContortion,bLocalRotate,aLocalMarkRect);
+ }
+}
+
+void SdrDragCrook::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
+{
+ // use helper derived from old stuff
+ MovAllPoints(rTarget);
+}
+
+bool SdrDragCrook::EndSdrDrag(bool bCopy)
+{
+ Hide();
+
+ if (bResize && aFact==Fraction(1,1))
+ bResize=false;
+
+ const bool bUndo = getSdrDragView().IsUndoEnabled();
+
+ bool bDoCrook=aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0;
+
+ if (bDoCrook || bResize)
+ {
+ if (bResize && bUndo)
+ {
+ OUString aStr = ImpGetDescriptionStr(!bContortion?STR_EditCrook:STR_EditCrookContortion);
+
+ if (bCopy)
+ aStr += SvxResId(STR_EditWithCopy);
+
+ getSdrDragView().BegUndo(aStr);
+ }
+
+ if (bResize)
+ {
+ Fraction aFact1(1,1);
+
+ if (bContortion)
+ {
+ if (bVertical)
+ getSdrDragView().ResizeMarkedObj(aCenter,aFact1,aFact,bCopy);
+ else
+ getSdrDragView().ResizeMarkedObj(aCenter,aFact,aFact1,bCopy);
+ }
+ else
+ {
+ if (bCopy)
+ getSdrDragView().CopyMarkedObj();
+
+ const size_t nMarkCount=getSdrDragView().GetMarkedObjectList().GetMarkCount();
+
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=getSdrDragView().GetMarkedObjectList().GetMark(nm);
+ SdrObject* pO=pM->GetMarkedSdrObj();
+ Point aCtr0(pO->GetSnapRect().Center());
+ Point aCtr1(aCtr0);
+
+ if (bVertical)
+ ResizePoint(aCtr1,aCenter,aFact1,aFact);
+ else
+ ResizePoint(aCtr1,aCenter,aFact,aFact1);
+
+ Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y());
+ if( bUndo )
+ AddUndo(getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoMoveObject(*pO,aSiz));
+ pO->Move(aSiz);
+ }
+ }
+
+ bCopy=false;
+ }
+
+ if (bDoCrook)
+ {
+ getSdrDragView().CrookMarkedObj(aCenter,aRad,eMode,bVertical,!bContortion,bCopy);
+ }
+
+ if (bResize && bUndo)
+ getSdrDragView().EndUndo();
+
+ return true;
+ }
+
+ return false;
+}
+
+PointerStyle SdrDragCrook::GetSdrDragPointer() const
+{
+ return PointerStyle::Crook;
+}
+
+
+SdrDragDistort::SdrDragDistort(SdrDragView& rNewView)
+: SdrDragMethod(rNewView),
+ nPolyPt(0),
+ bContortionAllowed(false),
+ bNoContortionAllowed(false),
+ bContortion(false)
+{
+}
+
+OUString SdrDragDistort::GetSdrDragComment() const
+{
+ OUString aStr = ImpGetDescriptionStr(STR_DragMethDistort)
+ + " (x="
+ + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDX())
+ + " y="
+ + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDY())
+ + ")";
+
+ if(getSdrDragView().IsDragWithCopy())
+ aStr += SvxResId(STR_EditWithCopy);
+ return aStr;
+}
+
+void SdrDragDistort::createSdrDragEntries()
+{
+ // Add extended frame raster first, so it will be behind objects
+ if(getSdrDragView().GetSdrPageView())
+ {
+ const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect()));
+
+ if(aDragRaster.count())
+ {
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aDragRaster)));
+ }
+ }
+
+ // call parent
+ SdrDragMethod::createSdrDragEntries();
+}
+
+bool SdrDragDistort::BeginSdrDrag()
+{
+ bContortionAllowed=getSdrDragView().IsDistortAllowed();
+ bNoContortionAllowed=getSdrDragView().IsDistortAllowed(true);
+
+ if (bContortionAllowed || bNoContortionAllowed)
+ {
+ SdrHdlKind eKind=GetDragHdlKind();
+ nPolyPt=0xFFFF;
+
+ if (eKind==SdrHdlKind::UpperLeft) nPolyPt=0;
+ if (eKind==SdrHdlKind::UpperRight) nPolyPt=1;
+ if (eKind==SdrHdlKind::LowerRight) nPolyPt=2;
+ if (eKind==SdrHdlKind::LowerLeft) nPolyPt=3;
+ if (nPolyPt>3) return false;
+
+ aMarkRect=GetMarkedRect();
+ aDistortedRect=XPolygon(aMarkRect);
+ Show();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void SdrDragDistort::MovAllPoints(basegfx::B2DPolyPolygon& rTarget)
+{
+ if (!bContortion)
+ return;
+
+ SdrPageView* pPV = getSdrDragView().GetSdrPageView();
+
+ if(pPV && pPV->HasMarkedObjPageView())
+ {
+ basegfx::B2DPolyPolygon aDragPolygon(rTarget);
+ const basegfx::B2DRange aOriginalRange = vcl::unotools::b2DRectangleFromRectangle(aMarkRect);
+ const basegfx::B2DPoint aTopLeft(aDistortedRect[0].X(), aDistortedRect[0].Y());
+ const basegfx::B2DPoint aTopRight(aDistortedRect[1].X(), aDistortedRect[1].Y());
+ const basegfx::B2DPoint aBottomLeft(aDistortedRect[3].X(), aDistortedRect[3].Y());
+ const basegfx::B2DPoint aBottomRight(aDistortedRect[2].X(), aDistortedRect[2].Y());
+
+ aDragPolygon = basegfx::utils::distort(aDragPolygon, aOriginalRange, aTopLeft, aTopRight, aBottomLeft, aBottomRight);
+ rTarget = aDragPolygon;
+ }
+}
+
+void SdrDragDistort::MoveSdrDrag(const Point& rPnt)
+{
+ if (!DragStat().CheckMinMoved(rPnt))
+ return;
+
+ Point aPnt(GetSnapPos(rPnt));
+
+ if (getSdrDragView().IsOrtho())
+ OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
+
+ bool bNewContortion=(bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed;
+
+ if (bNewContortion!=bContortion || aDistortedRect[nPolyPt]!=aPnt)
+ {
+ Hide();
+ aDistortedRect[nPolyPt]=aPnt;
+ bContortion=bNewContortion;
+ DragStat().NextMove(aPnt);
+ Show();
+ }
+}
+
+bool SdrDragDistort::EndSdrDrag(bool bCopy)
+{
+ Hide();
+ bool bDoDistort=DragStat().GetDX()!=0 || DragStat().GetDY()!=0;
+
+ if (bDoDistort)
+ {
+ getSdrDragView().DistortMarkedObj(aMarkRect,aDistortedRect,!bContortion,bCopy);
+ return true;
+ }
+
+ return false;
+}
+
+PointerStyle SdrDragDistort::GetSdrDragPointer() const
+{
+ return PointerStyle::RefHand;
+}
+
+void SdrDragDistort::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
+{
+ const bool bDoDistort(DragStat().GetDX()!=0 || DragStat().GetDY()!=0);
+
+ if (bDoDistort)
+ {
+ SdrEditView::ImpDistortObj(&rTarget, aMarkRect, aDistortedRect, !bContortion);
+ }
+}
+
+void SdrDragDistort::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
+{
+ // use helper derived from old stuff
+ MovAllPoints(rTarget);
+}
+
+
+SdrDragCrop::SdrDragCrop(SdrDragView& rNewView)
+: SdrDragObjOwn(rNewView)
+{
+ // switch off solid dragging for crop; it just makes no sense since showing
+ // a 50% transparent object above the original will not be visible
+ setSolidDraggingActive(false);
+}
+
+OUString SdrDragCrop::GetSdrDragComment() const
+{
+ OUString aStr = ImpGetDescriptionStr(STR_DragMethCrop)
+ + " (x="
+ + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDX())
+ + " y="
+ + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDY())
+ + ")";
+
+ if(getSdrDragView().IsDragWithCopy())
+ aStr += SvxResId(STR_EditWithCopy);
+ return aStr;
+}
+
+bool SdrDragCrop::BeginSdrDrag()
+{
+ // call parent
+ bool bRetval(SdrDragObjOwn::BeginSdrDrag());
+
+ if(!GetDragHdl())
+ {
+ // we need the DragHdl, break if not there
+ bRetval = false;
+ }
+
+ return bRetval;
+}
+
+bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
+{
+ Hide();
+
+ if(0 == DragStat().GetDX() && 0 == DragStat().GetDY())
+ {
+ // no change, done
+ return false;
+ }
+
+ const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
+
+ if(1 != rMarkList.GetMarkCount())
+ {
+ // Crop only with single Object selected
+ return false;
+ }
+
+ // prepare for SdrGrafObj or others. This code has to work with usual
+ // SdrGrafObj's from Draw/Impress/Calc, but also with SdrObjects from
+ // Writer. It would be better to handle this in Writer directly, but
+ // there are currently no easy mechanisms to plug an alternative interaction
+ // from there
+ SdrObject* pSdrObject = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ SdrObjectUniquePtr pFullDragClone;
+ bool bExternal(false);
+ SdrObject* pExternalSdrObject(nullptr);
+
+ // RotGrfFlyFrame: Crop decision for DrawingLayer/Writer now
+ // locally, no two-in-one methods any more
+ if (nullptr != pSdrObject && dynamic_cast< const SdrGrafObj* >(pSdrObject) == nullptr)
+ {
+ // If Writer, get the already offered for interaction SdrGrafObj
+ // and set up for using that replacement object that contains the
+ // real transformation. That SdrObject is owned and has to be deleted,
+ // so use a std::unique_ptr with special handling for the protected
+ // SDrObject destructor
+ pFullDragClone = pSdrObject->getFullDragClone();
+
+ if(dynamic_cast< SdrGrafObj* >(pFullDragClone.get()))
+ {
+ bExternal = true;
+ pExternalSdrObject = pSdrObject;
+ pSdrObject = pFullDragClone.get();
+ }
+ }
+
+ // get and check for SdrGrafObj now
+ SdrGrafObj* pObj = dynamic_cast<SdrGrafObj*>( pSdrObject );
+
+ if(!pObj)
+ {
+ return false;
+ }
+
+ // no undo for external needed, done there
+ const bool bUndo(!bExternal && getSdrDragView().IsUndoEnabled());
+
+ if(bUndo)
+ {
+ OUString aUndoStr = ImpGetDescriptionStr(STR_DragMethCrop);
+
+ getSdrDragView().BegUndo( aUndoStr );
+ getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+ // also need attr undo, the SdrGrafCropItem will be changed
+ getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
+ }
+
+ // get the original objects transformation
+ basegfx::B2DHomMatrix aOriginalMatrix;
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ bool bShearCorrected(false);
+ pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon);
+
+ { // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080
+ const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aOriginalMatrix);
+
+ if(!basegfx::fTools::equalZero(aTmpDecomp.getShearX()))
+ {
+ bShearCorrected = true;
+ aOriginalMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aTmpDecomp.getScale(),
+ -aTmpDecomp.getShearX(),
+ aTmpDecomp.getRotate(),
+ aTmpDecomp.getTranslate());
+ }
+ }
+
+ // generate start point of original drag vector in unit coordinates (the
+ // vis-a-vis of the drag point)
+ basegfx::B2DPoint aLocalStart(0.0, 0.0);
+ bool bOnAxis(false);
+
+ switch(GetDragHdlKind())
+ {
+ case SdrHdlKind::UpperLeft: aLocalStart.setX(1.0); aLocalStart.setY(1.0); break;
+ case SdrHdlKind::Upper: aLocalStart.setX(0.5); aLocalStart.setY(1.0); bOnAxis = true; break;
+ case SdrHdlKind::UpperRight: aLocalStart.setX(0.0); aLocalStart.setY(1.0); break;
+ case SdrHdlKind::Left : aLocalStart.setX(1.0); aLocalStart.setY(0.5); bOnAxis = true; break;
+ case SdrHdlKind::Right: aLocalStart.setX(0.0); aLocalStart.setY(0.5); bOnAxis = true; break;
+ case SdrHdlKind::LowerLeft: aLocalStart.setX(1.0); aLocalStart.setY(0.0); break;
+ case SdrHdlKind::Lower: aLocalStart.setX(0.5); aLocalStart.setY(0.0); bOnAxis = true; break;
+ case SdrHdlKind::LowerRight: aLocalStart.setX(0.0); aLocalStart.setY(0.0); break;
+ default: break;
+ }
+
+ // create the current drag position in unit coordinates. To get there,
+ // transform back the DragPoint to UnitCoordinates
+ basegfx::B2DHomMatrix aInverse(aOriginalMatrix);
+ aInverse.invert();
+ basegfx::B2DPoint aLocalCurrent(aInverse * basegfx::B2DPoint(DragStat().GetNow().X(), DragStat().GetNow().Y()));
+
+ // if one of the edge handles is used, limit to X or Y drag only
+ if(bOnAxis)
+ {
+ if(basegfx::fTools::equal(aLocalStart.getX(), 0.5))
+ {
+ aLocalCurrent.setX(aLocalStart.getX());
+ }
+ else
+ {
+ aLocalCurrent.setY(aLocalStart.getY());
+ }
+ }
+
+ // create internal change in unit coordinates
+ basegfx::B2DHomMatrix aDiscreteChangeMatrix;
+
+ if(!basegfx::fTools::equal(aLocalCurrent.getX(), aLocalStart.getX()))
+ {
+ if(aLocalStart.getX() < 0.5)
+ {
+ aDiscreteChangeMatrix.scale(aLocalCurrent.getX(), 1.0);
+ }
+ else
+ {
+ aDiscreteChangeMatrix.scale(1.0 - aLocalCurrent.getX(), 1.0);
+ aDiscreteChangeMatrix.translate(aLocalCurrent.getX(), 0.0);
+ }
+ }
+
+ if(!basegfx::fTools::equal(aLocalCurrent.getY(), aLocalStart.getY()))
+ {
+ if(aLocalStart.getY() < 0.5)
+ {
+ aDiscreteChangeMatrix.scale(1.0, aLocalCurrent.getY());
+ }
+ else
+ {
+ aDiscreteChangeMatrix.scale(1.0, 1.0 - aLocalCurrent.getY());
+ aDiscreteChangeMatrix.translate(0.0, aLocalCurrent.getY());
+ }
+ }
+
+ // We now have the whole executed Crop in UnitCoordinates in
+ // aDiscreteChangeMatrix, go to concrete sizes now.
+ // Create the unrotated original rectangle and the unrotated modified
+ // rectangle as Ranges
+ const basegfx::utils::B2DHomMatrixBufferedDecompose aOriginalMatrixDecomp(aOriginalMatrix);
+
+ // prepare unsheared/unrotated versions of the old and new transformation
+ const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate(
+ basegfx::utils::createScaleTranslateB2DHomMatrix(
+ basegfx::absolute(aOriginalMatrixDecomp.getScale()),
+ aOriginalMatrixDecomp.getTranslate()));
+
+ // create the ranges for these
+ basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
+ basegfx::B2DRange aRangeNewNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
+ aRangeOriginalNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate);
+ aRangeNewNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate * aDiscreteChangeMatrix);
+
+ if(bExternal)
+ {
+ // With aLocalStart point (opposed to dragged point), X scale and Y scale,
+ // we call crop (virtual method) on pSdrObject which calls VirtFlyDrawObj
+ // crop. Use aLocalStart unchanged, so being relative to the Crop-Action,
+ // the called instance knows best how to use it
+ const double fScaleX(aRangeNewNoShearNoRotate.getWidth() / aRangeOriginalNoShearNoRotate.getWidth());
+ const double fScaleY(aRangeNewNoShearNoRotate.getHeight() / aRangeOriginalNoShearNoRotate.getHeight());
+
+ pExternalSdrObject->Crop(
+ aLocalStart,
+ fScaleX,
+ fScaleY);
+ }
+ else
+ {
+ // prepare matrix to apply to object; evtl. back-correct shear
+ basegfx::B2DHomMatrix aNewObjectMatrix(aOriginalMatrix * aDiscreteChangeMatrix);
+
+ if(bShearCorrected)
+ {
+ // back-correct shear
+ const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aNewObjectMatrix);
+
+ aNewObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aTmpDecomp.getScale(),
+ -aTmpDecomp.getShearX(),
+ aTmpDecomp.getRotate(),
+ aTmpDecomp.getTranslate());
+ }
+
+ // apply change to object by applying the unit coordinate change followed
+ // by the original change
+ pObj->TRSetBaseGeometry(aNewObjectMatrix, aPolyPolygon);
+
+ // extract the old Rectangle structures
+ tools::Rectangle aOldRect(
+ basegfx::fround(aRangeOriginalNoShearNoRotate.getMinX()),
+ basegfx::fround(aRangeOriginalNoShearNoRotate.getMinY()),
+ basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxX()),
+ basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxY()));
+ tools::Rectangle aNewRect(
+ basegfx::fround(aRangeNewNoShearNoRotate.getMinX()),
+ basegfx::fround(aRangeNewNoShearNoRotate.getMinY()),
+ basegfx::fround(aRangeNewNoShearNoRotate.getMaxX()),
+ basegfx::fround(aRangeNewNoShearNoRotate.getMaxY()));
+
+ // continue with the old original stuff
+ if (!aOldRect.GetWidth() || !aOldRect.GetHeight())
+ {
+ throw o3tl::divide_by_zero();
+ }
+
+ if((pObj->GetGraphicType() == GraphicType::NONE) || (pObj->GetGraphicType() == GraphicType::Default))
+ {
+ return false;
+ }
+
+ const GraphicObject& rGraphicObject(pObj->GetGraphicObject());
+ // tdf#117145 Usually Writer will go the bExternal path (see above), but more correct for
+ // the future is to use the MapMode from the SdrModel/SfxItemPool if the Writer's current
+ // special handling should be unified to this path in the future. Usually it *should* be
+ // MapUnit::Map100thMM, but better do not mix up Units.
+ // Checked now what SwVirtFlyDrawObj::NbcCrop is doing - it calculates everything forced
+ // to MapUnit::Map100thMM, but extracts/packs Twips to the used SdrGrafCropItem in Writer.
+ const MapMode aMapModePool(pObj->getSdrModelFromSdrObject().GetItemPool().GetMetric(0));
+ Size aGraphicSize(rGraphicObject.GetPrefSize());
+
+ if(MapUnit::MapPixel == rGraphicObject.GetPrefMapMode().GetMapUnit())
+ {
+ aGraphicSize = Application::GetDefaultDevice()->PixelToLogic(aGraphicSize, aMapModePool);
+ }
+ else
+ {
+ aGraphicSize = OutputDevice::LogicToLogic(aGraphicSize, rGraphicObject.GetPrefMapMode(), aMapModePool);
+ }
+
+ if(0 == aGraphicSize.Width() || 0 == aGraphicSize.Height())
+ {
+ return false;
+ }
+
+ const SdrGrafCropItem& rOldCrop = pObj->GetMergedItem(SDRATTR_GRAFCROP);
+ double fScaleX = ( aGraphicSize.Width() - rOldCrop.GetLeft() - rOldCrop.GetRight() ) / static_cast<double>(aOldRect.GetWidth());
+ double fScaleY = ( aGraphicSize.Height() - rOldCrop.GetTop() - rOldCrop.GetBottom() ) / static_cast<double>(aOldRect.GetHeight());
+
+ sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left();
+ sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top();
+ sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right();
+ sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom();
+
+ if(pObj->IsMirrored())
+ {
+ // mirrored X or Y, for old stuff, exchange X
+ // check for aw080
+ sal_Int32 nTmp(nDiffLeft);
+ nDiffLeft = -nDiffRight;
+ nDiffRight = -nTmp;
+ }
+
+ sal_Int32 nLeftCrop = static_cast<sal_Int32>( rOldCrop.GetLeft() + nDiffLeft * fScaleX );
+ sal_Int32 nTopCrop = static_cast<sal_Int32>( rOldCrop.GetTop() + nDiffTop * fScaleY );
+ sal_Int32 nRightCrop = static_cast<sal_Int32>( rOldCrop.GetRight() - nDiffRight * fScaleX );
+ sal_Int32 nBottomCrop = static_cast<sal_Int32>( rOldCrop.GetBottom() - nDiffBottom * fScaleY );
+
+ SfxItemPool& rPool = getSdrDragView().GetModel()->GetItemPool();
+ SfxItemSetFixed<SDRATTR_GRAFCROP, SDRATTR_GRAFCROP> aSet( rPool );
+ aSet.Put( SdrGrafCropItem( nLeftCrop, nTopCrop, nRightCrop, nBottomCrop ) );
+ getSdrDragView().SetAttributes( aSet, false );
+ }
+
+ if(bUndo)
+ {
+ getSdrDragView().EndUndo();
+ }
+
+ return true;
+}
+
+PointerStyle SdrDragCrop::GetSdrDragPointer() const
+{
+ return PointerStyle::Crop;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svddrgv.cxx b/svx/source/svdraw/svddrgv.cxx
new file mode 100644
index 000000000..b6ac05cef
--- /dev/null
+++ b/svx/source/svdraw/svddrgv.cxx
@@ -0,0 +1,919 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <osl/diagnose.h>
+#include <tools/debug.hxx>
+#include <svx/svddrgv.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include "svddrgm1.hxx"
+#include <svx/obj3d.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <unotools/configmgr.hxx>
+#include <comphelper/lok.hxx>
+
+using namespace sdr;
+
+SdrDragView::SdrDragView(SdrModel& rSdrModel, OutputDevice* pOut)
+ : SdrExchangeView(rSdrModel, pOut)
+ , mpDragHdl(nullptr)
+ , mpInsPointUndo(nullptr)
+ , meDragHdl(SdrHdlKind::Move)
+ , mbFramDrag(false)
+ , mbMarkedHitMovesAlways(false)
+ , mbDragLimit(false)
+ , mbDragHdl(false)
+ , mbDragStripes(false)
+ , mbSolidDragging(utl::ConfigManager::IsFuzzing() || SvtOptionsDrawinglayer::IsSolidDragCreate())
+ , mbResizeAtCenter(false)
+ , mbCrookAtCenter(false)
+ , mbDragWithCopy(false)
+ , mbInsGluePoint(false)
+ , mbInsObjPointMode(false)
+ , mbInsGluePointMode(false)
+ , mbNoDragXorPolys(false)
+{
+ meDragMode = SdrDragMode::Move;
+}
+
+SdrDragView::~SdrDragView()
+{
+}
+
+bool SdrDragView::IsAction() const
+{
+ return (mpCurrentSdrDragMethod || SdrExchangeView::IsAction());
+}
+
+void SdrDragView::MovAction(const Point& rPnt)
+{
+ SdrExchangeView::MovAction(rPnt);
+ if (mpCurrentSdrDragMethod)
+ {
+ MovDragObj(rPnt);
+ }
+}
+
+void SdrDragView::EndAction()
+{
+ if (mpCurrentSdrDragMethod)
+ {
+ EndDragObj();
+ }
+ SdrExchangeView::EndAction();
+}
+
+void SdrDragView::BckAction()
+{
+ SdrExchangeView::BckAction();
+ BrkDragObj();
+}
+
+void SdrDragView::BrkAction()
+{
+ SdrExchangeView::BrkAction();
+ BrkDragObj();
+}
+
+void SdrDragView::TakeActionRect(tools::Rectangle& rRect) const
+{
+ if (mpCurrentSdrDragMethod)
+ {
+ rRect=maDragStat.GetActionRect();
+ if (rRect.IsEmpty())
+ {
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(pPV&& pPV->HasMarkedObjPageView())
+ {
+ // #i95646# is this used..?
+ const basegfx::B2DRange aBoundRange(mpCurrentSdrDragMethod->getCurrentRange());
+ if (aBoundRange.isEmpty())
+ {
+ rRect.SetEmpty();
+ }
+ else
+ {
+ rRect = tools::Rectangle(
+ basegfx::fround(aBoundRange.getMinX()), basegfx::fround(aBoundRange.getMinY()),
+ basegfx::fround(aBoundRange.getMaxX()), basegfx::fround(aBoundRange.getMaxY()));
+ }
+ }
+ }
+ if (rRect.IsEmpty())
+ {
+ rRect=tools::Rectangle(maDragStat.GetNow(),maDragStat.GetNow());
+ }
+ }
+ else
+ {
+ SdrExchangeView::TakeActionRect(rRect);
+ }
+}
+
+bool SdrDragView::TakeDragObjAnchorPos(Point& rPos, bool bTR ) const
+{
+ tools::Rectangle aR;
+ TakeActionRect(aR);
+ rPos = bTR ? aR.TopRight() : aR.TopLeft();
+ if (GetMarkedObjectCount()==1 && IsDragObj() && // only on single selection
+ !IsDraggingPoints() && !IsDraggingGluePoints() && // not when moving points
+ dynamic_cast<const SdrDragMovHdl*>( mpCurrentSdrDragMethod.get() ) == nullptr) // not when moving handles
+ {
+ SdrObject* pObj=GetMarkedObjectByIndex(0);
+ if (auto pCaptionObj = dynamic_cast<SdrCaptionObj*>(pObj))
+ {
+ Point aPt(pCaptionObj->GetTailPos());
+ bool bTail=meDragHdl==SdrHdlKind::Poly; // drag tail
+ bool bOwn=dynamic_cast<const SdrDragObjOwn*>( mpCurrentSdrDragMethod.get() ) != nullptr; // specific to object
+ if (!bTail)
+ { // for bTail, TakeActionRect already does the right thing
+ if (bOwn)
+ { // bOwn may be MoveTextFrame, ResizeTextFrame, but may not (any more) be DragTail
+ rPos=aPt;
+ }
+ else
+ {
+ // drag the whole Object (Move, Resize, ...)
+ const basegfx::B2DPoint aTransformed(mpCurrentSdrDragMethod->getCurrentTransformation() * basegfx::B2DPoint(aPt.X(), aPt.Y()));
+ rPos.setX( basegfx::fround(aTransformed.getX()) );
+ rPos.setY( basegfx::fround(aTransformed.getY()) );
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool SdrDragView::TakeDragLimit(SdrDragMode /*eMode*/, tools::Rectangle& /*rRect*/) const
+{
+ return false;
+}
+
+bool SdrDragView::BegDragObj(const Point& rPnt, OutputDevice* pOut, SdrHdl* pHdl, short nMinMov, SdrDragMethod* _pForcedMeth)
+{
+ BrkAction();
+
+ // so we don't leak the object on early return
+ std::unique_ptr<SdrDragMethod> pForcedMeth(_pForcedMeth);
+
+ bool bRet=false;
+ {
+ SetDragWithCopy(false);
+ //TODO: aAni.Reset();
+ mpCurrentSdrDragMethod=nullptr;
+ SdrDragMode eTmpMode=meDragMode;
+ if (eTmpMode==SdrDragMode::Move && pHdl!=nullptr && pHdl->GetKind()!=SdrHdlKind::Move) {
+ eTmpMode=SdrDragMode::Resize;
+ }
+ mbDragLimit=TakeDragLimit(eTmpMode,maDragLimit);
+ mbFramDrag=ImpIsFrameHandles();
+ if (!mbFramDrag &&
+ (mpMarkedObj==nullptr || !mpMarkedObj->hasSpecialDrag()) &&
+ (pHdl==nullptr || pHdl->GetObj()==nullptr)) {
+ mbFramDrag=true;
+ }
+
+ Point aPnt(rPnt);
+ basegfx::B2DVector aGridOffset(0.0, 0.0);
+
+ // Coordinate maybe affected by GridOffset, so we may need to
+ // adapt to Model-coordinates here
+ if((comphelper::LibreOfficeKit::isActive() && mpMarkedObj
+ && getPossibleGridOffsetForSdrObject(aGridOffset, GetMarkedObjectByIndex(0), GetSdrPageView()))
+ || (getPossibleGridOffsetForPosition(
+ aGridOffset,
+ basegfx::B2DPoint(aPnt.X(), aPnt.Y()),
+ GetSdrPageView())))
+ {
+ aPnt.AdjustX(basegfx::fround(-aGridOffset.getX()));
+ aPnt.AdjustY(basegfx::fround(-aGridOffset.getY()));
+ }
+
+ if(pHdl == nullptr
+ || pHdl->GetKind() == SdrHdlKind::Move
+ || pHdl->GetKind() == SdrHdlKind::MirrorAxis
+ || pHdl->GetKind() == SdrHdlKind::Transparence
+ || pHdl->GetKind() == SdrHdlKind::Gradient)
+ {
+ maDragStat.Reset(aPnt);
+ }
+ else
+ {
+ maDragStat.Reset(pHdl->GetPos());
+ }
+
+ maDragStat.SetView(static_cast<SdrView*>(this));
+ maDragStat.SetPageView(mpMarkedPV); // <<-- DragPV has to go here!!!
+ maDragStat.SetMinMove(ImpGetMinMovLogic(nMinMov,pOut));
+ maDragStat.SetHdl(pHdl);
+ maDragStat.NextPoint();
+ mpDragWin=pOut;
+ mpDragHdl=pHdl;
+ meDragHdl= pHdl==nullptr ? SdrHdlKind::Move : pHdl->GetKind();
+ mbDragHdl=meDragHdl==SdrHdlKind::Ref1 || meDragHdl==SdrHdlKind::Ref2 || meDragHdl==SdrHdlKind::MirrorAxis;
+
+ // Expand test for SdrHdlKind::Anchor_TR
+ bool bNotDraggable = (SdrHdlKind::Anchor == meDragHdl || SdrHdlKind::Anchor_TR == meDragHdl);
+
+ if(pHdl && (pHdl->GetKind() == SdrHdlKind::SmartTag) && pForcedMeth )
+ {
+ // just use the forced method for smart tags
+ }
+ else if(mbDragHdl)
+ {
+ mpCurrentSdrDragMethod.reset(new SdrDragMovHdl(*this));
+ }
+ else if(!bNotDraggable)
+ {
+ switch (meDragMode)
+ {
+ case SdrDragMode::Rotate: case SdrDragMode::Shear:
+ {
+ switch (meDragHdl)
+ {
+ case SdrHdlKind::Left: case SdrHdlKind::Right:
+ case SdrHdlKind::Upper: case SdrHdlKind::Lower:
+ {
+ // are 3D objects selected?
+ bool b3DObjSelected = false;
+ for(size_t a=0; !b3DObjSelected && a<GetMarkedObjectCount(); ++a)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(a);
+ if(dynamic_cast< const E3dObject* >(pObj))
+ b3DObjSelected = true;
+ }
+ // If yes, allow shear even when !IsShearAllowed,
+ // because 3D objects are limited rotations
+ if (!b3DObjSelected && !IsShearAllowed())
+ return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragShear(*this,meDragMode==SdrDragMode::Rotate));
+ } break;
+ case SdrHdlKind::UpperLeft: case SdrHdlKind::UpperRight:
+ case SdrHdlKind::LowerLeft: case SdrHdlKind::LowerRight:
+ {
+ if (meDragMode==SdrDragMode::Shear)
+ {
+ if (!IsDistortAllowed(true) && !IsDistortAllowed()) return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragDistort(*this));
+ }
+ else
+ {
+ if (!IsRotateAllowed(true)) return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragRotate(*this));
+ }
+ } break;
+ default:
+ {
+ if (IsMarkedHitMovesAlways() && meDragHdl==SdrHdlKind::Move)
+ { // SdrHdlKind::Move is true, even if Obj is hit directly
+ if (!IsMoveAllowed()) return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragMove(*this));
+ }
+ else
+ {
+ if (!IsRotateAllowed(true)) return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragRotate(*this));
+ }
+ }
+ }
+ } break;
+ case SdrDragMode::Mirror:
+ {
+ if (meDragHdl==SdrHdlKind::Move && IsMarkedHitMovesAlways())
+ {
+ if (!IsMoveAllowed()) return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragMove(*this));
+ }
+ else
+ {
+ if (!IsMirrorAllowed(true,true)) return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragMirror(*this));
+ }
+ } break;
+
+ case SdrDragMode::Crop:
+ {
+ if (meDragHdl==SdrHdlKind::Move && IsMarkedHitMovesAlways())
+ {
+ if (!IsMoveAllowed())
+ return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragMove(*this));
+ }
+ else
+ {
+ if (!IsCropAllowed())
+ return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragCrop(*this));
+ }
+ }
+ break;
+
+ case SdrDragMode::Transparence:
+ {
+ if(meDragHdl == SdrHdlKind::Move && IsMarkedHitMovesAlways())
+ {
+ if(!IsMoveAllowed())
+ return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragMove(*this));
+ }
+ else
+ {
+ if(!IsTransparenceAllowed())
+ return false;
+
+ mpCurrentSdrDragMethod.reset(new SdrDragGradient(*this, false));
+ }
+ break;
+ }
+ case SdrDragMode::Gradient:
+ {
+ if(meDragHdl == SdrHdlKind::Move && IsMarkedHitMovesAlways())
+ {
+ if(!IsMoveAllowed())
+ return false;
+ mpCurrentSdrDragMethod.reset(new SdrDragMove(*this));
+ }
+ else
+ {
+ if(!IsGradientAllowed())
+ return false;
+
+ mpCurrentSdrDragMethod.reset(new SdrDragGradient(*this));
+ }
+ break;
+ }
+
+ case SdrDragMode::Crook :
+ {
+ if (meDragHdl==SdrHdlKind::Move && IsMarkedHitMovesAlways())
+ {
+ if (!IsMoveAllowed()) return false;
+ mpCurrentSdrDragMethod.reset( new SdrDragMove(*this) );
+ }
+ else
+ {
+ if (!IsCrookAllowed(true) && !IsCrookAllowed()) return false;
+ mpCurrentSdrDragMethod.reset( new SdrDragCrook(*this) );
+ }
+ } break;
+
+ default:
+ {
+ // SdrDragMode::Move
+ if((meDragHdl == SdrHdlKind::Move) && !IsMoveAllowed())
+ {
+ return false;
+ }
+ else if(meDragHdl == SdrHdlKind::Glue)
+ {
+ mpCurrentSdrDragMethod.reset( new SdrDragMove(*this) );
+ }
+ else
+ {
+ if(mbFramDrag)
+ {
+ if(meDragHdl == SdrHdlKind::Move)
+ {
+ mpCurrentSdrDragMethod.reset( new SdrDragMove(*this) );
+ }
+ else
+ {
+ if(!IsResizeAllowed(true))
+ {
+ return false;
+ }
+
+ bool bSingleTextObjMark = false; // SJ: #i100490#
+ if ( GetMarkedObjectCount() == 1 )
+ {
+ mpMarkedObj=GetMarkedObjectByIndex(0);
+ if ( mpMarkedObj &&
+ dynamic_cast<const SdrTextObj*>( mpMarkedObj) != nullptr &&
+ static_cast<SdrTextObj*>(mpMarkedObj)->IsTextFrame() )
+ bSingleTextObjMark = true;
+ }
+ if ( bSingleTextObjMark )
+ mpCurrentSdrDragMethod.reset( new SdrDragObjOwn(*this) );
+ else
+ mpCurrentSdrDragMethod.reset( new SdrDragResize(*this) );
+ }
+ }
+ else
+ {
+ if(SdrHdlKind::Move == meDragHdl)
+ {
+ const bool bCustomShapeSelected(1 == GetMarkedObjectCount() && dynamic_cast<const SdrObjCustomShape*>(GetMarkedObjectByIndex(0)) != nullptr);
+
+ if(bCustomShapeSelected)
+ {
+ mpCurrentSdrDragMethod.reset( new SdrDragMove( *this ) );
+ }
+ }
+ else if(SdrHdlKind::Poly == meDragHdl)
+ {
+ const bool bConnectorSelected(1 == GetMarkedObjectCount() && dynamic_cast<const SdrEdgeObj*>(GetMarkedObjectByIndex(0)) != nullptr);
+
+ if(bConnectorSelected)
+ {
+ // #i97784#
+ // fallback to old behaviour for connectors (see
+ // text in task description for more details)
+ }
+ else if(!IsMoveAllowed() || !IsResizeAllowed())
+ {
+ // #i77187#
+ // do not allow move of polygon points if object is move or size protected
+ return false;
+ }
+ }
+
+ if(!mpCurrentSdrDragMethod)
+ {
+ // fallback to DragSpecial if no interaction defined
+ mpCurrentSdrDragMethod.reset( new SdrDragObjOwn(*this) );
+ }
+ }
+ }
+ }
+ }
+ }
+ if (pForcedMeth)
+ {
+ mpCurrentSdrDragMethod = std::move(pForcedMeth);
+ }
+ maDragStat.SetDragMethod(mpCurrentSdrDragMethod.get());
+ if (mpCurrentSdrDragMethod)
+ {
+ bRet = mpCurrentSdrDragMethod->BeginSdrDrag();
+ if (!bRet)
+ {
+ if (pHdl==nullptr && dynamic_cast< const SdrDragObjOwn* >(mpCurrentSdrDragMethod.get()) != nullptr)
+ {
+ // Obj may not Move SpecialDrag, so try with MoveFrameDrag
+ mpCurrentSdrDragMethod.reset();
+
+ if (!IsMoveAllowed())
+ return false;
+
+ mbFramDrag=true;
+ mpCurrentSdrDragMethod.reset( new SdrDragMove(*this) );
+ maDragStat.SetDragMethod(mpCurrentSdrDragMethod.get());
+ bRet = mpCurrentSdrDragMethod->BeginSdrDrag();
+ }
+ }
+ if (!bRet)
+ {
+ mpCurrentSdrDragMethod.reset();
+ maDragStat.SetDragMethod(mpCurrentSdrDragMethod.get());
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void SdrDragView::MovDragObj(const Point& rPnt)
+{
+ if (!mpCurrentSdrDragMethod)
+ return;
+
+ Point aPnt(rPnt);
+ basegfx::B2DVector aGridOffset(0.0, 0.0);
+
+ // Coordinate maybe affected by GridOffset, so we may need to
+ // adapt to Model-coordinates here
+ if((comphelper::LibreOfficeKit::isActive() && mpMarkedObj
+ && getPossibleGridOffsetForSdrObject(aGridOffset, GetMarkedObjectByIndex(0), GetSdrPageView()))
+ || (getPossibleGridOffsetForPosition(
+ aGridOffset,
+ basegfx::B2DPoint(aPnt.X(), aPnt.Y()),
+ GetSdrPageView())))
+ {
+ aPnt.AdjustX(basegfx::fround(-aGridOffset.getX()));
+ aPnt.AdjustY(basegfx::fround(-aGridOffset.getY()));
+ }
+
+ ImpLimitToWorkArea(aPnt);
+ mpCurrentSdrDragMethod->MoveSdrDrag(aPnt); // this call already makes a Hide()/Show combination
+}
+
+bool SdrDragView::EndDragObj(bool bCopy)
+{
+ bool bRet(false);
+
+ // #i73341# If inserting GluePoint, do not insist on last points being different
+ if(mpCurrentSdrDragMethod && maDragStat.IsMinMoved() && (IsInsertGluePoint() || maDragStat.GetNow() != maDragStat.GetPrev()))
+ {
+ sal_Int32 nSavedHdlCount=0;
+
+ if (bEliminatePolyPoints)
+ {
+ nSavedHdlCount=GetMarkablePointCount();
+ }
+
+ const bool bUndo = IsUndoEnabled();
+ if (IsInsertGluePoint() && bUndo)
+ {
+ BegUndo(maInsPointUndoStr);
+ AddUndo(std::unique_ptr<SdrUndoAction>(mpInsPointUndo));
+ }
+
+ bRet = mpCurrentSdrDragMethod->EndSdrDrag(bCopy);
+
+ if( IsInsertGluePoint() && bUndo)
+ EndUndo();
+
+ mpCurrentSdrDragMethod.reset();
+
+ if (bEliminatePolyPoints)
+ {
+ if (nSavedHdlCount!=GetMarkablePointCount())
+ {
+ UnmarkAllPoints();
+ }
+ }
+
+ if (mbInsPolyPoint)
+ {
+ SetMarkHandles(nullptr);
+ mbInsPolyPoint=false;
+ if( bUndo )
+ {
+ BegUndo(maInsPointUndoStr);
+ AddUndo(std::unique_ptr<SdrUndoAction>(mpInsPointUndo));
+ EndUndo();
+ }
+ }
+
+ meDragHdl=SdrHdlKind::Move;
+ mpDragHdl=nullptr;
+
+ if (!mbSomeObjChgdFlag)
+ {
+ // Obj did not broadcast (e. g. Writer FlyFrames)
+ if(!mbDragHdl)
+ {
+ AdjustMarkHdl();
+ }
+ }
+ }
+ else
+ {
+ BrkDragObj();
+ }
+
+ mbInsPolyPoint=false;
+ SetInsertGluePoint(false);
+
+ return bRet;
+}
+
+void SdrDragView::BrkDragObj()
+{
+ if (!mpCurrentSdrDragMethod)
+ return;
+
+ mpCurrentSdrDragMethod->CancelSdrDrag();
+
+ mpCurrentSdrDragMethod.reset();
+
+ if (mbInsPolyPoint)
+ {
+ mpInsPointUndo->Undo(); // delete inserted point again
+ delete mpInsPointUndo;
+ mpInsPointUndo=nullptr;
+ SetMarkHandles(nullptr);
+ mbInsPolyPoint=false;
+ }
+
+ if (IsInsertGluePoint())
+ {
+ mpInsPointUndo->Undo(); // delete inserted gluepoint again
+ delete mpInsPointUndo;
+ mpInsPointUndo=nullptr;
+ SetInsertGluePoint(false);
+ }
+
+ meDragHdl=SdrHdlKind::Move;
+ mpDragHdl=nullptr;
+}
+
+bool SdrDragView::IsInsObjPointPossible() const
+{
+ return mpMarkedObj!=nullptr && mpMarkedObj->IsPolyObj();
+}
+
+bool SdrDragView::ImpBegInsObjPoint(bool bIdxZwang, const Point& rPnt, bool bNewObj, OutputDevice* pOut)
+{
+ bool bRet(false);
+
+ if(auto pMarkedPath = dynamic_cast<SdrPathObj*>( mpMarkedObj))
+ {
+ BrkAction();
+ mpInsPointUndo = dynamic_cast< SdrUndoGeoObj* >( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*mpMarkedObj).release() );
+ DBG_ASSERT( mpInsPointUndo, "svx::SdrDragView::BegInsObjPoint(), could not create correct undo object!" );
+
+ OUString aStr(SvxResId(STR_DragInsertPoint));
+
+ maInsPointUndoStr = aStr.replaceFirst("%1", mpMarkedObj->TakeObjNameSingul() );
+
+ Point aPt(rPnt);
+
+ if(bNewObj)
+ aPt = GetSnapPos(aPt,mpMarkedPV);
+
+ bool bClosed0 = pMarkedPath->IsClosedObj();
+
+ const sal_uInt32 nInsPointNum { bIdxZwang
+ ? pMarkedPath->NbcInsPoint(aPt, bNewObj)
+ : pMarkedPath->NbcInsPointOld(aPt, bNewObj)
+ };
+
+ if(bClosed0 != pMarkedPath->IsClosedObj())
+ {
+ // Obj was closed implicitly
+ // object changed
+ pMarkedPath->SetChanged();
+ pMarkedPath->BroadcastObjectChange();
+ }
+
+ if (nInsPointNum != SAL_MAX_UINT32)
+ {
+ mbInsPolyPoint = true;
+ UnmarkAllPoints();
+ AdjustMarkHdl();
+
+ bRet = BegDragObj(rPnt, pOut, maHdlList.GetHdl(nInsPointNum), 0);
+
+ if (bRet)
+ {
+ maDragStat.SetMinMoved();
+ MovDragObj(rPnt);
+ }
+ }
+ else
+ {
+ delete mpInsPointUndo;
+ mpInsPointUndo = nullptr;
+ }
+ }
+
+ return bRet;
+}
+
+bool SdrDragView::EndInsObjPoint(SdrCreateCmd eCmd)
+{
+ if(IsInsObjPoint())
+ {
+ Point aPnt(maDragStat.GetNow());
+ bool bOk=EndDragObj();
+ if (bOk && eCmd!=SdrCreateCmd::ForceEnd)
+ {
+ // Ret=True means: Action is over.
+ bOk = ! ImpBegInsObjPoint(true, aPnt, eCmd == SdrCreateCmd::NextObject, mpDragWin);
+ }
+
+ return bOk;
+ } else return false;
+}
+
+bool SdrDragView::IsInsGluePointPossible() const
+{
+ bool bRet=false;
+ if (IsInsGluePointMode() && AreObjectsMarked())
+ {
+ if (GetMarkedObjectCount()==1)
+ {
+ // return sal_False, if only 1 object which is a connector.
+ const SdrObject* pObj=GetMarkedObjectByIndex(0);
+ if (dynamic_cast<const SdrEdgeObj *>(pObj) == nullptr)
+ {
+ bRet=true;
+ }
+ }
+ else
+ {
+ bRet=true;
+ }
+ }
+ return bRet;
+}
+
+bool SdrDragView::BegInsGluePoint(const Point& rPnt)
+{
+ bool bRet=false;
+ SdrObject* pObj;
+ SdrPageView* pPV;
+ if (PickMarkedObj(rPnt,pObj,pPV,SdrSearchOptions::PASS2BOUND))
+ {
+ BrkAction();
+ UnmarkAllGluePoints();
+ mpInsPointUndo= dynamic_cast< SdrUndoGeoObj* >( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj).release() );
+ DBG_ASSERT( mpInsPointUndo, "svx::SdrDragView::BegInsObjPoint(), could not create correct undo object!" );
+ OUString aStr(SvxResId(STR_DragInsertGluePoint));
+
+ maInsPointUndoStr = aStr.replaceFirst("%1", pObj->TakeObjNameSingul() );
+
+ SdrGluePointList* pGPL=pObj->ForceGluePointList();
+ if (pGPL!=nullptr)
+ {
+ sal_uInt16 nGlueIdx=pGPL->Insert(SdrGluePoint());
+ SdrGluePoint& rGP=(*pGPL)[nGlueIdx];
+ sal_uInt16 nGlueId=rGP.GetId();
+ rGP.SetAbsolutePos(rPnt,*pObj);
+
+ SdrHdl* pHdl=nullptr;
+ if (MarkGluePoint(pObj,nGlueId,false))
+ {
+ pHdl=GetGluePointHdl(pObj,nGlueId);
+ }
+ if (pHdl!=nullptr && pHdl->GetKind()==SdrHdlKind::Glue && pHdl->GetObj()==pObj && pHdl->GetObjHdlNum()==nGlueId)
+ {
+ SetInsertGluePoint(true);
+ bRet=BegDragObj(rPnt,nullptr,pHdl,0);
+ if (bRet)
+ {
+ maDragStat.SetMinMoved();
+ MovDragObj(rPnt);
+ }
+ else
+ {
+ SetInsertGluePoint(false);
+ delete mpInsPointUndo;
+ mpInsPointUndo=nullptr;
+ }
+ }
+ else
+ {
+ OSL_FAIL("BegInsGluePoint(): GluePoint handle not found.");
+ }
+ }
+ else
+ {
+ // no gluepoints possible for this object (e. g. Edge)
+ SetInsertGluePoint(false);
+ delete mpInsPointUndo;
+ mpInsPointUndo=nullptr;
+ }
+ }
+
+ return bRet;
+}
+
+void SdrDragView::ShowDragObj()
+{
+ if(!mpCurrentSdrDragMethod || maDragStat.IsShown())
+ return;
+
+ // Changed for the GridOffset stuff: No longer iterate over
+ // SdrPaintWindow(s), but now over SdrPageWindow(s), so doing the
+ // same as the SdrHdl visualizations (see ::CreateB2dIAObject) do.
+ // This is needed to get access to an ObjectContact which is needed
+ // to evtl. process that GridOffset in CreateOverlayGeometry
+ SdrPageView* pPageView(GetSdrPageView());
+
+ if(nullptr != pPageView)
+ {
+ for(sal_uInt32 a(0); a < pPageView->PageWindowCount(); a++)
+ {
+ const SdrPageWindow& rPageWindow(*pPageView->GetPageWindow(a));
+ const SdrPaintWindow& rPaintWindow(rPageWindow.GetPaintWindow());
+
+ if(rPaintWindow.OutputToWindow())
+ {
+ const rtl::Reference<sdr::overlay::OverlayManager>& xOverlayManager(
+ rPaintWindow.GetOverlayManager());
+
+ if(xOverlayManager.is())
+ {
+ mpCurrentSdrDragMethod->CreateOverlayGeometry(
+ *xOverlayManager,
+ rPageWindow.GetObjectContact());
+
+ // #i101679# Force changed overlay to be shown
+ xOverlayManager->flush();
+ }
+ }
+ }
+ }
+
+ maDragStat.SetShown(true);
+}
+
+void SdrDragView::HideDragObj()
+{
+ if(mpCurrentSdrDragMethod && maDragStat.IsShown())
+ {
+ mpCurrentSdrDragMethod->destroyOverlayGeometry();
+ maDragStat.SetShown(false);
+ }
+}
+
+
+void SdrDragView::SetNoDragXorPolys(bool bOn)
+{
+ if (IsNoDragXorPolys()==bOn)
+ return;
+
+ const bool bDragging(mpCurrentSdrDragMethod);
+ const bool bShown(bDragging && maDragStat.IsShown());
+
+ if(bShown)
+ {
+ HideDragObj();
+ }
+
+ mbNoDragXorPolys = bOn;
+
+ if(bDragging)
+ {
+ // force recreation of drag content
+ mpCurrentSdrDragMethod->resetSdrDragEntries();
+ }
+
+ if(bShown)
+ {
+ ShowDragObj();
+ }
+}
+
+void SdrDragView::SetDragStripes(bool bOn)
+{
+ if (mpCurrentSdrDragMethod && maDragStat.IsShown())
+ {
+ HideDragObj();
+ mbDragStripes=bOn;
+ ShowDragObj();
+ }
+ else
+ {
+ mbDragStripes=bOn;
+ }
+}
+
+bool SdrDragView::IsOrthoDesired() const
+{
+ if( dynamic_cast< const SdrDragObjOwn* >( mpCurrentSdrDragMethod.get() )
+ || dynamic_cast< const SdrDragResize* >(mpCurrentSdrDragMethod.get() ))
+ {
+ return m_bOrthoDesiredOnMarked;
+ }
+
+ return false;
+}
+
+void SdrDragView::SetMarkHandles(SfxViewShell* pOtherShell)
+{
+ if( mpDragHdl )
+ mpDragHdl = nullptr;
+
+ SdrExchangeView::SetMarkHandles(pOtherShell);
+}
+
+void SdrDragView::SetSolidDragging(bool bOn)
+{
+ if(mbSolidDragging != bOn)
+ {
+ mbSolidDragging = bOn;
+ }
+}
+
+bool SdrDragView::IsSolidDragging() const
+{
+ // allow each user to disable by having a local setting, but using AND for
+ // checking allowance
+ return mbSolidDragging && SvtOptionsDrawinglayer::IsSolidDragCreate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdedtv.cxx b/svx/source/svdraw/svdedtv.cxx
new file mode 100644
index 000000000..b019f26ae
--- /dev/null
+++ b/svx/source/svdraw/svdedtv.cxx
@@ -0,0 +1,1103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdedtv.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdlayer.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpoev.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/e3dsceneupdater.hxx>
+#include <rtl/strbuf.hxx>
+#include <svx/svdview.hxx>
+#include <clonelist.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/xfillit0.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+using namespace com::sun::star;
+
+void SdrEditView::ImpResetPossibilityFlags()
+{
+ m_bReadOnly =false;
+
+ m_bGroupPossible =false;
+ m_bUnGroupPossible =false;
+ m_bGrpEnterPossible =false;
+ m_bToTopPossible =false;
+ m_bToBtmPossible =false;
+ m_bReverseOrderPossible =false;
+
+ m_bImportMtfPossible =false;
+ m_bCombinePossible =false;
+ m_bDismantlePossible =false;
+ m_bCombineNoPolyPolyPossible =false;
+ m_bDismantleMakeLinesPossible=false;
+ m_bOrthoDesiredOnMarked =false;
+
+ m_bOneOrMoreMovable =false;
+ m_bMoreThanOneNoMovRot =false;
+ m_bContortionPossible =false;
+ m_bMoveAllowed =false;
+ m_bResizeFreeAllowed =false;
+ m_bResizePropAllowed =false;
+ m_bRotateFreeAllowed =false;
+ m_bRotate90Allowed =false;
+ m_bMirrorFreeAllowed =false;
+ m_bMirror45Allowed =false;
+ m_bMirror90Allowed =false;
+ m_bTransparenceAllowed =false;
+ m_bCropAllowed =false;
+ m_bGradientAllowed =false;
+ m_bShearAllowed =false;
+ m_bEdgeRadiusAllowed =false;
+ m_bCanConvToPath =false;
+ m_bCanConvToPoly =false;
+ m_bCanConvToContour =false;
+ m_bMoveProtect =false;
+ m_bResizeProtect =false;
+}
+
+SdrEditView::SdrEditView(SdrModel& rSdrModel, OutputDevice* pOut)
+ : SdrMarkView(rSdrModel, pOut)
+ , m_bPossibilitiesDirty(true)
+ , m_bReadOnly(false)
+ , m_bGroupPossible(false)
+ , m_bUnGroupPossible(false)
+ , m_bGrpEnterPossible(false)
+ , m_bToTopPossible(false)
+ , m_bToBtmPossible(false)
+ , m_bReverseOrderPossible(false)
+ , m_bImportMtfPossible(false)
+ , m_bCombinePossible(false)
+ , m_bDismantlePossible(false)
+ , m_bCombineNoPolyPolyPossible(false)
+ , m_bDismantleMakeLinesPossible(false)
+ , m_bOrthoDesiredOnMarked(false)
+ , m_bOneOrMoreMovable(false)
+ , m_bMoreThanOneNoMovRot(false)
+ , m_bContortionPossible(false)
+ , m_bMoveAllowed(false)
+ , m_bResizeFreeAllowed(false)
+ , m_bResizePropAllowed(false)
+ , m_bRotateFreeAllowed(false)
+ , m_bRotate90Allowed(false)
+ , m_bMirrorFreeAllowed(false)
+ , m_bMirror45Allowed(false)
+ , m_bMirror90Allowed(false)
+ , m_bShearAllowed(false)
+ , m_bEdgeRadiusAllowed(false)
+ , m_bTransparenceAllowed(false)
+ , m_bCropAllowed(false)
+ , m_bGradientAllowed(false)
+ , m_bCanConvToPath(false)
+ , m_bCanConvToPoly(false)
+ , m_bCanConvToContour(false)
+ , m_bMoveProtect(false)
+ , m_bResizeProtect(false)
+{
+}
+
+SdrEditView::~SdrEditView()
+{
+}
+
+void SdrEditView::InsertNewLayer(const OUString& rName, sal_uInt16 nPos)
+{
+ SdrLayerAdmin& rLA=mpModel->GetLayerAdmin();
+ sal_uInt16 nMax=rLA.GetLayerCount();
+ if (nPos>nMax) nPos=nMax;
+ rLA.NewLayer(rName,nPos);
+
+ if( GetModel()->IsUndoEnabled() )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewLayer(nPos,rLA,*mpModel));
+
+ mpModel->SetChanged();
+}
+
+bool SdrEditView::ImpDelLayerCheck(SdrObjList const * pOL, SdrLayerID nDelID) const
+{
+ bool bDelAll(true);
+
+ for(size_t nObjNum = pOL->GetObjCount(); nObjNum > 0 && bDelAll;)
+ {
+ nObjNum--;
+ SdrObject* pObj = pOL->GetObj(nObjNum);
+ SdrObjList* pSubOL = pObj->GetSubList();
+
+ // explicitly test for group objects and 3d scenes
+ if(pSubOL && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr || dynamic_cast< const E3dScene* >(pObj) != nullptr))
+ {
+ if(!ImpDelLayerCheck(pSubOL, nDelID))
+ {
+ bDelAll = false;
+ }
+ }
+ else
+ {
+ if(pObj->GetLayer() != nDelID)
+ {
+ bDelAll = false;
+ }
+ }
+ }
+
+ return bDelAll;
+}
+
+void SdrEditView::ImpDelLayerDelObjs(SdrObjList* pOL, SdrLayerID nDelID)
+{
+ const size_t nObjCount(pOL->GetObjCount());
+ // make sure OrdNums are correct
+ pOL->GetObj(0)->GetOrdNum();
+
+ const bool bUndo = GetModel()->IsUndoEnabled();
+
+ for(size_t nObjNum = nObjCount; nObjNum > 0;)
+ {
+ nObjNum--;
+ SdrObject* pObj = pOL->GetObj(nObjNum);
+ SdrObjList* pSubOL = pObj->GetSubList();
+
+
+ // explicitly test for group objects and 3d scenes
+ if(pSubOL && (dynamic_cast<const SdrObjGroup*>( pObj) != nullptr || dynamic_cast<const E3dScene* >(pObj) != nullptr))
+ {
+ if(ImpDelLayerCheck(pSubOL, nDelID))
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true));
+ pOL->RemoveObject(nObjNum);
+
+ if( !bUndo )
+ SdrObject::Free( pObj );
+ }
+ else
+ {
+ ImpDelLayerDelObjs(pSubOL, nDelID);
+ }
+ }
+ else
+ {
+ if(pObj->GetLayer() == nDelID)
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true));
+ pOL->RemoveObject(nObjNum);
+ if( !bUndo )
+ SdrObject::Free( pObj );
+ }
+ }
+ }
+}
+
+void SdrEditView::DeleteLayer(const OUString& rName)
+{
+ SdrLayerAdmin& rLA = mpModel->GetLayerAdmin();
+ SdrLayer* pLayer = rLA.GetLayer(rName);
+
+ if(!pLayer)
+ return;
+
+ sal_uInt16 nLayerNum(rLA.GetLayerPos(pLayer));
+ SdrLayerID nDelID = pLayer->GetID();
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo(SvxResId(STR_UndoDelLayer));
+
+ bool bMaPg(true);
+
+ for(sal_uInt16 nPageKind(0); nPageKind < 2; nPageKind++)
+ {
+ // MasterPages and DrawPages
+ sal_uInt16 nPgCount(bMaPg ? mpModel->GetMasterPageCount() : mpModel->GetPageCount());
+
+ for(sal_uInt16 nPgNum(0); nPgNum < nPgCount; nPgNum++)
+ {
+ // over all pages
+ SdrPage* pPage = bMaPg ? mpModel->GetMasterPage(nPgNum) : mpModel->GetPage(nPgNum);
+ const size_t nObjCount(pPage->GetObjCount());
+
+ // make sure OrdNums are correct
+ if(nObjCount)
+ pPage->GetObj(0)->GetOrdNum();
+
+ for(size_t nObjNum(nObjCount); nObjNum > 0;)
+ {
+ nObjNum--;
+ SdrObject* pObj = pPage->GetObj(nObjNum);
+ SdrObjList* pSubOL = pObj->GetSubList();
+
+ // explicitly test for group objects and 3d scenes
+ if(pSubOL && (dynamic_cast<const SdrObjGroup*>(pObj) != nullptr || dynamic_cast<const E3dScene* >(pObj) != nullptr))
+ {
+ if(ImpDelLayerCheck(pSubOL, nDelID))
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true));
+ pPage->RemoveObject(nObjNum);
+ if( !bUndo )
+ SdrObject::Free(pObj);
+ }
+ else
+ {
+ ImpDelLayerDelObjs(pSubOL, nDelID);
+ }
+ }
+ else
+ {
+ if(pObj->GetLayer() == nDelID)
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj, true));
+ pPage->RemoveObject(nObjNum);
+ if( !bUndo )
+ SdrObject::Free(pObj);
+ }
+ }
+ }
+ }
+ bMaPg = false;
+ }
+
+ if( bUndo )
+ {
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteLayer(nLayerNum, rLA, *mpModel));
+ rLA.RemoveLayer(nLayerNum).release();
+ EndUndo();
+ }
+ else
+ {
+ rLA.RemoveLayer(nLayerNum);
+ }
+
+ mpModel->SetChanged();
+}
+
+
+void SdrEditView::EndUndo()
+{
+ // #i13033#
+ // Comparison changed to 1L since EndUndo() is called later now
+ // and EndUndo WILL change count to count-1
+ if(1 == mpModel->GetUndoBracketLevel())
+ {
+ ImpBroadcastEdgesOfMarkedNodes();
+ }
+
+ // #i13033#
+ // moved to bottom to still have access to UNDOs inside of
+ // ImpBroadcastEdgesOfMarkedNodes()
+ mpModel->EndUndo();
+}
+
+void SdrEditView::ImpBroadcastEdgesOfMarkedNodes()
+{
+ std::vector<SdrObject*>::const_iterator iterPos;
+ const std::vector<SdrObject*>& rAllMarkedObjects = GetTransitiveHullOfMarkedObjects();
+
+ // #i13033#
+ // New mechanism to search for necessary disconnections for
+ // changed connectors inside the transitive hull of all at
+ // the beginning of UNDO selected objects
+ for(size_t a(0); a < rAllMarkedObjects.size(); a++)
+ {
+ SdrEdgeObj* pEdge = dynamic_cast<SdrEdgeObj*>( rAllMarkedObjects[a] );
+
+ if(pEdge)
+ {
+ SdrObject* pObj1 = pEdge->GetConnectedNode(false);
+ SdrObject* pObj2 = pEdge->GetConnectedNode(true);
+
+ if(pObj1 && !pEdge->CheckNodeConnection(false))
+ {
+ iterPos = std::find(rAllMarkedObjects.begin(),rAllMarkedObjects.end(),pObj1);
+
+ if (iterPos == rAllMarkedObjects.end())
+ {
+ if( IsUndoEnabled() )
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pEdge));
+ pEdge->DisconnectFromNode(false);
+ }
+ }
+
+ if(pObj2 && !pEdge->CheckNodeConnection(true))
+ {
+ iterPos = std::find(rAllMarkedObjects.begin(),rAllMarkedObjects.end(),pObj2);
+
+ if (iterPos == rAllMarkedObjects.end())
+ {
+ if( IsUndoEnabled() )
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pEdge));
+ pEdge->DisconnectFromNode(true);
+ }
+ }
+ }
+ }
+
+ const size_t nMarkedEdgeCnt = GetMarkedEdgesOfMarkedNodes().GetMarkCount();
+
+ for (size_t i=0; i<nMarkedEdgeCnt; ++i) {
+ SdrMark* pEM = GetMarkedEdgesOfMarkedNodes().GetMark(i);
+ SdrObject* pEdgeTmp=pEM->GetMarkedSdrObj();
+ SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pEdgeTmp );
+ if (pEdge!=nullptr) {
+ pEdge->SetEdgeTrackDirty();
+ }
+ }
+}
+
+
+// Possibilities
+
+
+void SdrEditView::MarkListHasChanged()
+{
+ SdrMarkView::MarkListHasChanged();
+ m_bPossibilitiesDirty=true;
+}
+
+void SdrEditView::ModelHasChanged()
+{
+ SdrMarkView::ModelHasChanged();
+ m_bPossibilitiesDirty=true;
+}
+
+bool SdrEditView::IsResizeAllowed(bool bProp) const
+{
+ ForcePossibilities();
+ if (m_bResizeProtect) return false;
+ if (bProp) return m_bResizePropAllowed;
+ return m_bResizeFreeAllowed;
+}
+
+bool SdrEditView::IsRotateAllowed(bool b90Deg) const
+{
+ ForcePossibilities();
+ if (m_bMoveProtect) return false;
+ if (b90Deg) return m_bRotate90Allowed;
+ return m_bRotateFreeAllowed;
+}
+
+bool SdrEditView::IsMirrorAllowed(bool b45Deg, bool b90Deg) const
+{
+ ForcePossibilities();
+ if (m_bMoveProtect) return false;
+ if (b90Deg) return m_bMirror90Allowed;
+ if (b45Deg) return m_bMirror45Allowed;
+ return m_bMirrorFreeAllowed;
+}
+
+bool SdrEditView::IsTransparenceAllowed() const
+{
+ ForcePossibilities();
+ return m_bTransparenceAllowed;
+}
+
+bool SdrEditView::IsCropAllowed() const
+{
+ ForcePossibilities();
+ return m_bCropAllowed;
+}
+
+bool SdrEditView::IsGradientAllowed() const
+{
+ ForcePossibilities();
+ return m_bGradientAllowed;
+}
+
+bool SdrEditView::IsShearAllowed() const
+{
+ ForcePossibilities();
+ if (m_bResizeProtect) return false;
+ return m_bShearAllowed;
+}
+
+bool SdrEditView::IsEdgeRadiusAllowed() const
+{
+ ForcePossibilities();
+ return m_bEdgeRadiusAllowed;
+}
+
+bool SdrEditView::IsCrookAllowed(bool bNoContortion) const
+{
+ // CrookMode missing here (no rotations allowed when shearing ...)
+ ForcePossibilities();
+ if (bNoContortion) {
+ if (!m_bRotateFreeAllowed) return false;
+ return !m_bMoveProtect && m_bMoveAllowed;
+ } else {
+ return !m_bResizeProtect && m_bContortionPossible;
+ }
+}
+
+bool SdrEditView::IsDistortAllowed(bool bNoContortion) const
+{
+ ForcePossibilities();
+ if (bNoContortion) {
+ return false;
+ } else {
+ return !m_bResizeProtect && m_bContortionPossible;
+ }
+}
+
+bool SdrEditView::IsCombinePossible(bool bNoPolyPoly) const
+{
+ ForcePossibilities();
+ if (bNoPolyPoly) return m_bCombineNoPolyPolyPossible;
+ else return m_bCombinePossible;
+}
+
+bool SdrEditView::IsDismantlePossible(bool bMakeLines) const
+{
+ ForcePossibilities();
+ if (bMakeLines) return m_bDismantleMakeLinesPossible;
+ else return m_bDismantlePossible;
+}
+
+void SdrEditView::CheckPossibilities()
+{
+ if (mbSomeObjChgdFlag)
+ {
+ m_bPossibilitiesDirty = true;
+
+ // This call IS necessary to correct the MarkList, in which
+ // no longer to the model belonging objects still can reside.
+ // These ones need to be removed.
+ CheckMarked();
+ }
+
+ if (!m_bPossibilitiesDirty)
+ return;
+
+ ImpResetPossibilityFlags();
+ SortMarkedObjects();
+ const size_t nMarkCount = GetMarkedObjectCount();
+ if (nMarkCount != 0)
+ {
+ m_bReverseOrderPossible = (nMarkCount >= 2);
+
+ size_t nMovableCount=0;
+ m_bGroupPossible=nMarkCount>=2;
+ m_bCombinePossible=nMarkCount>=2;
+ if (nMarkCount==1)
+ {
+ // check bCombinePossible more thoroughly
+ // still missing ...
+ const SdrObject* pObj=GetMarkedObjectByIndex(0);
+ //const SdrPathObj* pPath=dynamic_cast<SdrPathObj*>( pObj );
+ bool bGroup=pObj->GetSubList()!=nullptr;
+ bool bHasText=pObj->GetOutlinerParaObject()!=nullptr;
+ if (bGroup || bHasText) {
+ m_bCombinePossible=true;
+ }
+ }
+ m_bCombineNoPolyPolyPossible=m_bCombinePossible;
+ // accept transformations for now
+ m_bMoveAllowed =true;
+ m_bResizeFreeAllowed=true;
+ m_bResizePropAllowed=true;
+ m_bRotateFreeAllowed=true;
+ m_bRotate90Allowed =true;
+ m_bMirrorFreeAllowed=true;
+ m_bMirror45Allowed =true;
+ m_bMirror90Allowed =true;
+ m_bShearAllowed =true;
+ m_bEdgeRadiusAllowed=false;
+ m_bContortionPossible=true;
+ m_bCanConvToContour = true;
+
+ // these ones are only allowed when single object is selected
+ m_bTransparenceAllowed = (nMarkCount == 1);
+ m_bGradientAllowed = (nMarkCount == 1);
+ m_bCropAllowed = (nMarkCount == 1);
+ if(m_bGradientAllowed)
+ {
+ // gradient depends on fill style
+ const SdrMark* pM = GetSdrMarkByIndex(0);
+ const SdrObject* pObj = pM->GetMarkedSdrObj();
+
+ // may be group object, so get merged ItemSet
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+ SfxItemState eState = rSet.GetItemState(XATTR_FILLSTYLE, false);
+
+ if(SfxItemState::DONTCARE != eState)
+ {
+ // If state is not DONTCARE, test the item
+ drawing::FillStyle eFillStyle = rSet.Get(XATTR_FILLSTYLE).GetValue();
+
+ if(eFillStyle != drawing::FillStyle_GRADIENT)
+ {
+ m_bGradientAllowed = false;
+ }
+ }
+ }
+
+ bool bNoMovRotFound=false;
+ const SdrPageView* pPV0=nullptr;
+
+ for (size_t nm=0; nm<nMarkCount; ++nm) {
+ const SdrMark* pM=GetSdrMarkByIndex(nm);
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+ const SdrPageView* pPV=pM->GetPageView();
+ if (pPV!=pPV0) {
+ if (pPV->IsReadOnly()) m_bReadOnly=true;
+ pPV0=pPV;
+ }
+
+ SdrObjTransformInfoRec aInfo;
+ pObj->TakeObjInfo(aInfo);
+ bool bMovPrt=pObj->IsMoveProtect();
+ bool bSizPrt=pObj->IsResizeProtect();
+ if (!bMovPrt && aInfo.bMoveAllowed) nMovableCount++; // count MovableObjs
+ if (bMovPrt) m_bMoveProtect=true;
+ if (bSizPrt) m_bResizeProtect=true;
+
+ // not allowed when not allowed at one object
+ if(!aInfo.bTransparenceAllowed)
+ m_bTransparenceAllowed = false;
+
+ // If one of these can't do something, none can
+ if (!aInfo.bMoveAllowed ) m_bMoveAllowed =false;
+ if (!aInfo.bResizeFreeAllowed) m_bResizeFreeAllowed=false;
+ if (!aInfo.bResizePropAllowed) m_bResizePropAllowed=false;
+ if (!aInfo.bRotateFreeAllowed) m_bRotateFreeAllowed=false;
+ if (!aInfo.bRotate90Allowed ) m_bRotate90Allowed =false;
+ if (!aInfo.bMirrorFreeAllowed) m_bMirrorFreeAllowed=false;
+ if (!aInfo.bMirror45Allowed ) m_bMirror45Allowed =false;
+ if (!aInfo.bMirror90Allowed ) m_bMirror90Allowed =false;
+ if (!aInfo.bShearAllowed ) m_bShearAllowed =false;
+ if (aInfo.bEdgeRadiusAllowed) m_bEdgeRadiusAllowed=true;
+ if (aInfo.bNoContortion ) m_bContortionPossible=false;
+ // For Crook with Contortion: all objects have to be
+ // Movable and Rotatable, except for a maximum of 1 of them
+ if (!m_bMoreThanOneNoMovRot) {
+ if (!aInfo.bMoveAllowed || !aInfo.bResizeFreeAllowed) {
+ m_bMoreThanOneNoMovRot=bNoMovRotFound;
+ bNoMovRotFound=true;
+ }
+ }
+
+ // Must be resizable to allow cropping
+ if (!aInfo.bResizeFreeAllowed && !aInfo.bResizePropAllowed)
+ m_bCropAllowed = false;
+
+ // if one member cannot be converted, no conversion is possible
+ if(!aInfo.bCanConvToContour)
+ m_bCanConvToContour = false;
+
+ // Ungroup
+ if (!m_bUnGroupPossible) m_bUnGroupPossible=pObj->GetSubList()!=nullptr;
+ // ConvertToCurve: If at least one can be converted, that is fine.
+ if (aInfo.bCanConvToPath ) m_bCanConvToPath =true;
+ if (aInfo.bCanConvToPoly ) m_bCanConvToPoly =true;
+
+ // Combine/Dismantle
+ if(m_bCombinePossible)
+ {
+ m_bCombinePossible = ImpCanConvertForCombine(pObj);
+ m_bCombineNoPolyPolyPossible = m_bCombinePossible;
+ }
+
+ if (!m_bDismantlePossible) m_bDismantlePossible = ImpCanDismantle(pObj, false);
+ if (!m_bDismantleMakeLinesPossible) m_bDismantleMakeLinesPossible = ImpCanDismantle(pObj, true);
+ // check OrthoDesiredOnMarked
+ if (!m_bOrthoDesiredOnMarked && !aInfo.bNoOrthoDesired) m_bOrthoDesiredOnMarked=true;
+ // check ImportMtf
+
+ if (!m_bImportMtfPossible)
+ {
+ const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(pObj);
+ if (pSdrGrafObj != nullptr)
+ {
+ if ((pSdrGrafObj->HasGDIMetaFile() && !pSdrGrafObj->IsEPS()) ||
+ pSdrGrafObj->isEmbeddedVectorGraphicData())
+ {
+ m_bImportMtfPossible = true;
+ }
+ }
+
+ const SdrOle2Obj* pSdrOle2Obj = dynamic_cast< const SdrOle2Obj* >(pObj);
+ if (pSdrOle2Obj)
+ {
+ m_bImportMtfPossible = pSdrOle2Obj->GetObjRef().is();
+ }
+ }
+ }
+
+ m_bOneOrMoreMovable=nMovableCount!=0;
+ m_bGrpEnterPossible=m_bUnGroupPossible;
+ }
+ ImpCheckToTopBtmPossible();
+ static_cast<SdrPolyEditView*>(this)->ImpCheckPolyPossibilities();
+ m_bPossibilitiesDirty=false;
+
+ if (m_bReadOnly) {
+ bool bTemp=m_bGrpEnterPossible;
+ ImpResetPossibilityFlags();
+ m_bReadOnly=true;
+ m_bGrpEnterPossible=bTemp;
+ }
+ if (!m_bMoveAllowed) return;
+
+ // Don't allow moving glued connectors.
+ // Currently only implemented for single selection.
+ if (nMarkCount==1) {
+ SdrObject* pObj=GetMarkedObjectByIndex(0);
+ SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
+ if (pEdge!=nullptr) {
+ SdrObject* pNode1=pEdge->GetConnectedNode(true);
+ SdrObject* pNode2=pEdge->GetConnectedNode(false);
+ if (pNode1!=nullptr || pNode2!=nullptr) m_bMoveAllowed=false;
+ }
+ }
+
+ // Don't allow enter Diagrams
+ if (1 == nMarkCount && m_bGrpEnterPossible)
+ {
+ SdrObject* pCandidate(GetMarkedObjectByIndex(0));
+
+ if(nullptr != pCandidate && pCandidate->isDiagram())
+ m_bGrpEnterPossible = false;
+ }
+}
+
+
+void SdrEditView::ForceMarkedObjToAnotherPage()
+{
+ bool bFlg=false;
+ for (size_t nm=0; nm<GetMarkedObjectCount(); ++nm) {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ tools::Rectangle aObjRect(pObj->GetCurrentBoundRect());
+ tools::Rectangle aPgRect(pM->GetPageView()->GetPageRect());
+ if (!aObjRect.Overlaps(aPgRect)) {
+ bool bFnd=false;
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(pPV)
+ {
+ bFnd = aObjRect.Overlaps(pPV->GetPageRect());
+ }
+
+ if(bFnd)
+ {
+ pM->GetPageView()->GetObjList()->RemoveObject(pObj->GetOrdNum());
+ pPV->GetObjList()->InsertObject(pObj, SAL_MAX_SIZE);
+ pM->SetPageView(pPV);
+ InvalidateAllWin(aObjRect);
+ bFlg=true;
+ }
+ }
+ }
+ if (bFlg) {
+ MarkListHasChanged();
+ }
+}
+
+std::vector<SdrObject*> SdrEditView::DeleteMarkedList(SdrMarkList const& rMark)
+{
+ std::vector<SdrObject*> ret;
+ if (rMark.GetMarkCount()!=0)
+ {
+ rMark.ForceSort();
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo();
+ const size_t nMarkCount(rMark.GetMarkCount());
+
+ if(nMarkCount)
+ {
+ std::vector< E3DModifySceneSnapRectUpdater* > aUpdaters;
+
+ if( bUndo )
+ {
+ for(size_t nm = nMarkCount; nm > 0;)
+ {
+ --nm;
+ SdrMark* pM = rMark.GetMark(nm);
+ SdrObject* pObj = pM->GetMarkedSdrObj();
+
+ // extra undo actions for changed connector which now may hold its laid out path (SJ)
+ AddUndoActions(CreateConnectorUndo( *pObj ));
+
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
+ }
+ }
+
+ // make sure, OrderNums are correct:
+ rMark.GetMark(0)->GetMarkedSdrObj()->GetOrdNum();
+
+ for(size_t nm = nMarkCount; nm > 0;)
+ {
+ --nm;
+ SdrMark* pM = rMark.GetMark(nm);
+ SdrObject* pObj = pM->GetMarkedSdrObj();
+ SdrObjList* pOL = pObj->getParentSdrObjListFromSdrObject();
+ const size_t nOrdNum(pObj->GetOrdNumDirect());
+
+ bool bIs3D = dynamic_cast< E3dObject* >(pObj);
+ // set up a scene updater if object is a 3d object
+ if(bIs3D)
+ {
+ aUpdaters.push_back(new E3DModifySceneSnapRectUpdater(pObj));
+ }
+
+ pOL->RemoveObject(nOrdNum);
+
+ if( !bUndo )
+ {
+ // tdf#108863 don't delete objects before EndUndo()
+ ret.push_back(pObj);
+ }
+ }
+
+ // fire scene updaters
+ while(!aUpdaters.empty())
+ {
+ delete aUpdaters.back();
+ aUpdaters.pop_back();
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+ }
+ return ret;
+}
+
+static void lcl_LazyDelete(std::vector<SdrObject*> & rLazyDelete)
+{
+ // now delete removed scene objects
+ while (!rLazyDelete.empty())
+ {
+ SdrObject::Free( rLazyDelete.back() );
+ rLazyDelete.pop_back();
+ }
+}
+
+void SdrEditView::DeleteMarkedObj()
+{
+ // #i110981# return when nothing is to be done at all
+ if(!GetMarkedObjectCount())
+ {
+ return;
+ }
+
+ // moved breaking action and undo start outside loop
+ BrkAction();
+ BegUndo(SvxResId(STR_EditDelete),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::Delete);
+
+ std::vector<SdrObject*> lazyDeleteObjects;
+ // remove as long as something is selected. This allows to schedule objects for
+ // removal for a next run as needed
+ while(GetMarkedObjectCount())
+ {
+ // vector to remember the parents which may be empty after object removal
+ std::vector< SdrObject* > aParents;
+
+ {
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ const size_t nCount(rMarkList.GetMarkCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ // in the first run, add all found parents, but only once
+ SdrMark* pMark(rMarkList.GetMark(a));
+ SdrObject* pObject(pMark->GetMarkedSdrObj());
+ SdrObject* pParent(pObject->getParentSdrObjectFromSdrObject());
+
+ if(pParent)
+ {
+ if(!aParents.empty())
+ {
+ std::vector< SdrObject* >::iterator aFindResult =
+ std::find(aParents.begin(), aParents.end(), pParent);
+
+ if(aFindResult == aParents.end())
+ {
+ aParents.push_back(pParent);
+ }
+ }
+ else
+ {
+ aParents.push_back(pParent);
+ }
+ }
+ }
+
+ if(!aParents.empty())
+ {
+ // in a 2nd run, remove all objects which may already be scheduled for
+ // removal. I am not sure if this can happen, but theoretically
+ // a to-be-removed object may already be the group/3DScene itself
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SdrMark* pMark = rMarkList.GetMark(a);
+ SdrObject* pObject = pMark->GetMarkedSdrObj();
+
+ std::vector< SdrObject* >::iterator aFindResult =
+ std::find(aParents.begin(), aParents.end(), pObject);
+
+ if(aFindResult != aParents.end())
+ {
+ aParents.erase(aFindResult);
+ }
+ }
+ }
+ }
+
+ // original stuff: remove selected objects. Handle clear will
+ // do something only once
+ auto temp(DeleteMarkedList(GetMarkedObjectList()));
+ for (auto p : temp)
+ {
+ lazyDeleteObjects.push_back(p);
+ }
+ GetMarkedObjectListWriteAccess().Clear();
+ maHdlList.Clear();
+
+ while(!aParents.empty() && !GetMarkedObjectCount())
+ {
+ // iterate over remembered parents
+ SdrObject* pParent = aParents.back();
+ aParents.pop_back();
+
+ if(pParent->GetSubList() && 0 == pParent->GetSubList()->GetObjCount())
+ {
+ // we detected an empty parent, a candidate to leave group/3DScene
+ // if entered
+ if(GetSdrPageView()->GetCurrentGroup()
+ && GetSdrPageView()->GetCurrentGroup() == pParent)
+ {
+ GetSdrPageView()->LeaveOneGroup();
+ }
+
+ // schedule empty parent for removal
+ GetMarkedObjectListWriteAccess().InsertEntry(
+ SdrMark(pParent, GetSdrPageView()));
+ }
+ }
+ }
+
+ // end undo and change messaging moved at the end
+ EndUndo();
+ MarkListHasChanged();
+
+ lcl_LazyDelete(lazyDeleteObjects);
+}
+
+void SdrEditView::CopyMarkedObj()
+{
+ SortMarkedObjects();
+
+ SdrMarkList aSourceObjectsForCopy(GetMarkedObjectList());
+ // The following loop is used instead of MarkList::Merge(), to be
+ // able to flag the MarkEntries.
+ const size_t nEdgeCnt = GetEdgesOfMarkedNodes().GetMarkCount();
+ for (size_t nEdgeNum=0; nEdgeNum<nEdgeCnt; ++nEdgeNum) {
+ SdrMark aM(*GetEdgesOfMarkedNodes().GetMark(nEdgeNum));
+ aM.SetUser(1);
+ aSourceObjectsForCopy.InsertEntry(aM);
+ }
+ aSourceObjectsForCopy.ForceSort();
+
+ // #i13033#
+ // New mechanism to re-create the connections of cloned connectors
+ CloneList aCloneList;
+
+ const bool bUndo = IsUndoEnabled();
+
+ GetMarkedObjectListWriteAccess().Clear();
+ size_t nCloneErrCnt=0;
+ std::unordered_set<rtl::OUString> aNameSet;
+ const size_t nMarkCount=aSourceObjectsForCopy.GetMarkCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm) {
+ SdrMark* pM=aSourceObjectsForCopy.GetMark(nm);
+ SdrObject* pSource(pM->GetMarkedSdrObj());
+ SdrObject* pO(pSource->CloneSdrObject(pSource->getSdrModelFromSdrObject()));
+ if (pO!=nullptr) {
+ pM->GetPageView()->GetObjList()->InsertObjectThenMakeNameUnique(pO, aNameSet);
+
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoCopyObject(*pO));
+
+ SdrMark aME(*pM);
+ aME.SetMarkedSdrObj(pO);
+ aCloneList.AddPair(pM->GetMarkedSdrObj(), pO);
+
+ if (pM->GetUser()==0)
+ {
+ // otherwise it is only an Edge we have to copy as well
+ GetMarkedObjectListWriteAccess().InsertEntry(aME);
+ }
+ } else {
+ nCloneErrCnt++;
+ }
+ }
+
+ // #i13033#
+ // New mechanism to re-create the connections of cloned connectors
+ aCloneList.CopyConnections();
+
+ if(nCloneErrCnt)
+ {
+#ifdef DBG_UTIL
+ OStringBuffer aStr("SdrEditView::CopyMarkedObj(): Error when cloning ");
+
+ if(nCloneErrCnt == 1)
+ {
+ aStr.append("a drawing object.");
+ }
+ else
+ {
+ aStr.append(static_cast<sal_Int32>(nCloneErrCnt));
+ aStr.append(" drawing objects.");
+ }
+
+ aStr.append(" This object's/These objects's connections will not be copied.");
+ OSL_FAIL(aStr.getStr());
+#endif
+ }
+ MarkListHasChanged();
+}
+
+
+bool SdrEditView::InsertObjectAtView(SdrObject* pObj, SdrPageView& rPV, SdrInsertFlags nOptions)
+{
+ if (nOptions & SdrInsertFlags::SETDEFLAYER) {
+ SdrLayerID nLayer=rPV.GetPage()->GetLayerAdmin().GetLayerID(maActualLayer);
+ if (nLayer==SDRLAYER_NOTFOUND) nLayer=SdrLayerID(0);
+ if (rPV.GetLockedLayers().IsSet(nLayer) || !rPV.GetVisibleLayers().IsSet(nLayer)) {
+ SdrObject::Free( pObj ); // Layer locked or invisible
+ return false;
+ }
+ pObj->NbcSetLayer(nLayer);
+ }
+ if (nOptions & SdrInsertFlags::SETDEFATTR) {
+ if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false);
+ pObj->SetMergedItemSet(maDefaultAttr);
+ }
+ if (!pObj->IsInserted()) {
+ rPV.GetObjList()->InsertObject(pObj, SAL_MAX_SIZE);
+ }
+ if( IsUndoEnabled())
+ {
+ bool bDontDeleteReally = true;
+ EndTextEditCurrentView(bDontDeleteReally);
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pObj));
+ }
+
+ css::uno::Reference<lang::XServiceInfo> xServices(GetModel()->getUnoModel(),
+ css::uno::UNO_QUERY);
+ if (xServices.is() && (xServices->supportsService("com.sun.star.sheet.SpreadsheetDocument") ||
+ xServices->supportsService("com.sun.star.text.TextDocument")))
+ {
+ const bool bUndo(IsUndoEnabled());
+ GetModel()->EnableUndo(false);
+ pObj->MakeNameUnique();
+ GetModel()->EnableUndo(bUndo);
+ }
+
+ if (!(nOptions & SdrInsertFlags::DONTMARK)) {
+ if (!(nOptions & SdrInsertFlags::ADDMARK)) UnmarkAllObj();
+ MarkObj(pObj,&rPV);
+ }
+ return true;
+}
+
+void SdrEditView::ReplaceObjectAtView(SdrObject* pOldObj, SdrPageView& rPV, SdrObject* pNewObj, bool bMark)
+{
+ if(IsTextEdit())
+ {
+#ifdef DBG_UTIL
+ if(auto pTextObj = dynamic_cast< SdrTextObj* >(pOldObj))
+ if (pTextObj->IsTextEditActive())
+ OSL_ENSURE(false, "OldObject is in TextEdit mode, this has to be ended before replacing it using SdrEndTextEdit (!)");
+
+ if(auto pTextObj = dynamic_cast< SdrTextObj* >(pNewObj))
+ if (pTextObj->IsTextEditActive())
+ OSL_ENSURE(false, "NewObject is in TextEdit mode, this has to be ended before replacing it using SdrEndTextEdit (!)");
+#endif
+
+ // #i123468# emergency repair situation, needs to cast up to a class derived from
+ // this one; (aw080 has a mechanism for that and the view hierarchy is secured to
+ // always be a SdrView)
+ SdrView *pSdrView = dynamic_cast<SdrView*>(this);
+ if (pSdrView)
+ pSdrView->SdrEndTextEdit();
+ }
+
+ SdrObjList* pOL=pOldObj->getParentSdrObjListFromSdrObject();
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoReplaceObject(*pOldObj,*pNewObj));
+
+ if( IsObjMarked( pOldObj ) )
+ MarkObj( pOldObj, &rPV, true /*unmark!*/ );
+
+ pOL->ReplaceObject(pNewObj,pOldObj->GetOrdNum());
+
+ if( !bUndo )
+ SdrObject::Free( pOldObj );
+
+ if (bMark) MarkObj(pNewObj,&rPV);
+}
+
+
+bool SdrEditView::IsUndoEnabled() const
+{
+ return mpModel->IsUndoEnabled();
+}
+
+void SdrEditView::EndTextEditAllViews() const
+{
+ size_t nViews = mpModel->GetListenerCount();
+ for (size_t nView = 0; nView < nViews; ++nView)
+ {
+ SdrObjEditView* pView = dynamic_cast<SdrObjEditView*>(mpModel->GetListener(nView));
+ if (!pView)
+ continue;
+
+ if (pView->IsTextEdit())
+ pView->SdrEndTextEdit();
+ }
+}
+
+void SdrEditView::EndTextEditCurrentView(bool bDontDeleteReally)
+{
+ if (IsTextEdit())
+ {
+ SdrView* pSdrView = dynamic_cast<SdrView*>(this);
+ if (pSdrView)
+ pSdrView->SdrEndTextEdit(bDontDeleteReally);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdedtv1.cxx b/svx/source/svdraw/svdedtv1.cxx
new file mode 100644
index 000000000..371584bd8
--- /dev/null
+++ b/svx/source/svdraw/svdedtv1.cxx
@@ -0,0 +1,2019 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <editeng/eeitem.hxx>
+#include <math.h>
+#include <svl/itemiter.hxx>
+#include <svl/whiter.hxx>
+#include <tools/bigint.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <getallcharpropids.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svditer.hxx>
+#include <svx/strings.hrc>
+
+#include <AffineMatrixItem.hxx>
+#include <svx/e3dsceneupdater.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/rectenum.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sderitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/svdedtv.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svxids.hrc>
+#include <sxallitm.hxx>
+#include <sxmovitm.hxx>
+#include <sxreaitm.hxx>
+#include <sxreoitm.hxx>
+#include <sxroaitm.hxx>
+#include <sxrooitm.hxx>
+#include <sxsalitm.hxx>
+#include <sxsoitm.hxx>
+#include <sxtraitm.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/sdprcitm.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <rtl/ustring.hxx>
+#include <sfx2/viewsh.hxx>
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+
+// EditView
+
+
+void SdrEditView::SetMarkedObjRect(const tools::Rectangle& rRect)
+{
+ DBG_ASSERT(!rRect.IsEmpty(),"SetMarkedObjRect() with an empty Rect does not make sense.");
+ if (rRect.IsEmpty()) return;
+ const size_t nCount=GetMarkedObjectCount();
+ if (nCount==0) return;
+ tools::Rectangle aR0(GetMarkedObjRect());
+ DBG_ASSERT(!aR0.IsEmpty(),"SetMarkedObjRect(): GetMarkedObjRect() is empty.");
+ if (aR0.IsEmpty()) return;
+ tools::Long x0=aR0.Left();
+ tools::Long y0=aR0.Top();
+ tools::Long w0=aR0.Right()-x0;
+ tools::Long h0=aR0.Bottom()-y0;
+ tools::Long x1=rRect.Left();
+ tools::Long y1=rRect.Top();
+ tools::Long w1=rRect.Right()-x1;
+ tools::Long h1=rRect.Bottom()-y1;
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ BegUndo(ImpGetDescriptionString(STR_EditPosSize));
+ }
+
+ for (size_t nm=0; nm<nCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pO=pM->GetMarkedSdrObj();
+ if( bUndo )
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pO));
+
+ tools::Rectangle aR1(pO->GetSnapRect());
+ if (!aR1.IsEmpty())
+ {
+ if (aR1==aR0)
+ {
+ aR1=rRect;
+ }
+ else
+ { // transform aR1 to aR0 after rRect
+ aR1.Move(-x0,-y0);
+ BigInt l(aR1.Left());
+ BigInt r(aR1.Right());
+ BigInt t(aR1.Top());
+ BigInt b(aR1.Bottom());
+ if (w0!=0) {
+ l*=w1; l/=w0;
+ r*=w1; r/=w0;
+ } else {
+ l=0; r=w1;
+ }
+ if (h0!=0) {
+ t*=h1; t/=h0;
+ b*=h1; b/=h0;
+ } else {
+ t=0; b=h1;
+ }
+ aR1.SetLeft(tools::Long(l) );
+ aR1.SetRight(tools::Long(r) );
+ aR1.SetTop(tools::Long(t) );
+ aR1.SetBottom(tools::Long(b) );
+ aR1.Move(x1,y1);
+ }
+ pO->SetSnapRect(aR1);
+ } else {
+ OSL_FAIL("SetMarkedObjRect(): pObj->GetSnapRect() returns empty Rect");
+ }
+ }
+ if( bUndo )
+ EndUndo();
+}
+
+std::vector< std::unique_ptr<SdrUndoAction> > SdrEditView::CreateConnectorUndo( const SdrObject& rO )
+{
+ std::vector< std::unique_ptr<SdrUndoAction> > vUndoActions;
+
+ if ( rO.GetBroadcaster() )
+ {
+ const SdrPage* pPage = rO.getSdrPageFromSdrObject();
+ if ( pPage )
+ {
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
+ while( aIter.IsMore() )
+ {
+ SdrObject* pPartObj = aIter.Next();
+ if ( dynamic_cast<const SdrEdgeObj*>( pPartObj) != nullptr )
+ {
+ if ( ( pPartObj->GetConnectedNode( false ) == &rO ) ||
+ ( pPartObj->GetConnectedNode( true ) == &rO ) )
+ {
+ vUndoActions.push_back( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject( *pPartObj ) );
+ }
+ }
+ }
+ }
+ }
+ return vUndoActions;
+}
+
+void SdrEditView::AddUndoActions( std::vector< std::unique_ptr<SdrUndoAction> > aUndoActions )
+{
+ for (auto & rAction : aUndoActions)
+ AddUndo( std::move(rAction) );
+}
+
+void SdrEditView::MoveMarkedObj(const Size& rSiz, bool bCopy)
+{
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ OUString aStr(SvxResId(STR_EditMove));
+ if (bCopy)
+ aStr += SvxResId(STR_EditWithCopy);
+ // needs its own UndoGroup because of its parameters
+ BegUndo(aStr,GetDescriptionOfMarkedObjects(),SdrRepeatFunc::Move);
+ }
+
+ if (bCopy)
+ CopyMarkedObj();
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pO=pM->GetMarkedSdrObj();
+ if( bUndo )
+ {
+ AddUndoActions( CreateConnectorUndo( *pO ) );
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoMoveObject(*pO,rSiz));
+ }
+ pO->Move(rSiz);
+ }
+
+ if( bUndo )
+ EndUndo();
+}
+
+void SdrEditView::ResizeMarkedObj(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bCopy)
+{
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ OUString aStr {ImpGetDescriptionString(STR_EditResize)};
+ if (bCopy)
+ aStr+=SvxResId(STR_EditWithCopy);
+ BegUndo(aStr);
+ }
+
+ if (bCopy)
+ CopyMarkedObj();
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pO=pM->GetMarkedSdrObj();
+ if( bUndo )
+ {
+ AddUndoActions( CreateConnectorUndo( *pO ) );
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pO));
+ }
+ pO->Resize(rRef,xFact,yFact);
+ }
+
+ if( bUndo )
+ EndUndo();
+}
+void SdrEditView::ResizeMultMarkedObj(const Point& rRef,
+ const Fraction& xFact,
+ const Fraction& yFact,
+ const bool bWdh,
+ const bool bHgt)
+{
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ BegUndo(ImpGetDescriptionString(STR_EditResize));
+ }
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pO=pM->GetMarkedSdrObj();
+ if( bUndo )
+ {
+ AddUndoActions( CreateConnectorUndo( *pO ) );
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pO));
+ }
+
+ Fraction aFrac(1,1);
+ if (bWdh && xFact.IsValid() && bHgt && yFact.IsValid())
+ pO->Resize(rRef, xFact, yFact);
+ else if (bWdh && xFact.IsValid())
+ pO->Resize(rRef, xFact, aFrac);
+ else if (bHgt && yFact.IsValid())
+ pO->Resize(rRef, aFrac, yFact);
+ }
+ if( bUndo )
+ EndUndo();
+}
+
+Degree100 SdrEditView::GetMarkedObjRotate() const
+{
+ Degree100 nRetval(0);
+
+ if(GetMarkedObjectCount())
+ {
+ SdrMark* pM = GetSdrMarkByIndex(0);
+ SdrObject* pO = pM->GetMarkedSdrObj();
+
+ nRetval = pO->GetRotateAngle();
+ }
+
+ return nRetval;
+}
+
+void SdrEditView::RotateMarkedObj(const Point& rRef, Degree100 nAngle, bool bCopy)
+{
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ OUString aStr {ImpGetDescriptionString(STR_EditRotate)};
+ if (bCopy) aStr+=SvxResId(STR_EditWithCopy);
+ BegUndo(aStr);
+ }
+
+ if (bCopy)
+ CopyMarkedObj();
+
+ double nSin = sin(toRadians(nAngle));
+ double nCos = cos(toRadians(nAngle));
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ if(nMarkCount)
+ {
+ std::vector< E3DModifySceneSnapRectUpdater* > aUpdaters;
+
+ for(size_t nm = 0; nm < nMarkCount; ++nm)
+ {
+ SdrMark* pM = GetSdrMarkByIndex(nm);
+ SdrObject* pO = pM->GetMarkedSdrObj();
+
+ if( bUndo )
+ {
+ // extra undo actions for changed connector which now may hold its laid out path (SJ)
+ AddUndoActions( CreateConnectorUndo( *pO ) );
+
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pO));
+ }
+
+ // set up a scene updater if object is a 3d object
+ if(dynamic_cast< E3dObject* >(pO))
+ {
+ aUpdaters.push_back(new E3DModifySceneSnapRectUpdater(pO));
+ }
+
+ pO->Rotate(rRef,nAngle,nSin,nCos);
+ }
+
+ // fire scene updaters
+ while(!aUpdaters.empty())
+ {
+ delete aUpdaters.back();
+ aUpdaters.pop_back();
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+}
+
+void SdrEditView::MirrorMarkedObj(const Point& rRef1, const Point& rRef2, bool bCopy)
+{
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ OUString aStr;
+ Point aDif(rRef2-rRef1);
+ if (aDif.X()==0)
+ aStr = ImpGetDescriptionString(STR_EditMirrorHori);
+ else if (aDif.Y()==0)
+ aStr = ImpGetDescriptionString(STR_EditMirrorVert);
+ else if (std::abs(aDif.X()) == std::abs(aDif.Y()))
+ aStr = ImpGetDescriptionString(STR_EditMirrorDiag);
+ else
+ aStr = ImpGetDescriptionString(STR_EditMirrorFree);
+ if (bCopy) aStr+=SvxResId(STR_EditWithCopy);
+ BegUndo(aStr);
+ }
+
+ if (bCopy)
+ CopyMarkedObj();
+
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ if(nMarkCount)
+ {
+ std::vector< E3DModifySceneSnapRectUpdater* > aUpdaters;
+
+ for(size_t nm = 0; nm < nMarkCount; ++nm)
+ {
+ SdrMark* pM = GetSdrMarkByIndex(nm);
+ SdrObject* pO = pM->GetMarkedSdrObj();
+
+ if( bUndo )
+ {
+ // extra undo actions for changed connector which now may hold its laid out path (SJ)
+ AddUndoActions( CreateConnectorUndo( *pO ) );
+
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pO));
+ }
+
+ // set up a scene updater if object is a 3d object
+ if(dynamic_cast< E3dObject* >(pO))
+ {
+ aUpdaters.push_back(new E3DModifySceneSnapRectUpdater(pO));
+ }
+
+ pO->Mirror(rRef1,rRef2);
+ }
+
+ // fire scene updaters
+ while(!aUpdaters.empty())
+ {
+ delete aUpdaters.back();
+ aUpdaters.pop_back();
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+}
+
+void SdrEditView::MirrorMarkedObjHorizontal()
+{
+ Point aCenter(GetMarkedObjRect().Center());
+ Point aPt2(aCenter);
+ aPt2.AdjustY( 1 );
+ MirrorMarkedObj(aCenter,aPt2);
+}
+
+void SdrEditView::MirrorMarkedObjVertical()
+{
+ Point aCenter(GetMarkedObjRect().Center());
+ Point aPt2(aCenter);
+ aPt2.AdjustX( 1 );
+ MirrorMarkedObj(aCenter,aPt2);
+}
+
+Degree100 SdrEditView::GetMarkedObjShear() const
+{
+ bool b1st=true;
+ bool bOk=true;
+ Degree100 nAngle(0);
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount && bOk; ++nm) {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pO=pM->GetMarkedSdrObj();
+ Degree100 nAngle2=pO->GetShearAngle();
+ if (b1st) nAngle=nAngle2;
+ else if (nAngle2!=nAngle) bOk=false;
+ b1st=false;
+ }
+ if (nAngle>SDRMAXSHEAR) nAngle=SDRMAXSHEAR;
+ if (nAngle<-SDRMAXSHEAR) nAngle=-SDRMAXSHEAR;
+ if (!bOk) nAngle=0_deg100;
+ return nAngle;
+}
+
+void SdrEditView::ShearMarkedObj(const Point& rRef, Degree100 nAngle, bool bVShear, bool bCopy)
+{
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ OUString aStr {ImpGetDescriptionString(STR_EditShear)};
+ if (bCopy)
+ aStr+=SvxResId(STR_EditWithCopy);
+ BegUndo(aStr);
+ }
+
+ if (bCopy)
+ CopyMarkedObj();
+
+ double nTan = tan(toRadians(nAngle));
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pO=pM->GetMarkedSdrObj();
+ if( bUndo )
+ {
+ AddUndoActions( CreateConnectorUndo( *pO ) );
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pO));
+ }
+ pO->Shear(rRef,nAngle,nTan,bVShear);
+ }
+
+ if( bUndo )
+ EndUndo();
+}
+
+void SdrEditView::ImpCrookObj(SdrObject* pO, const Point& rRef, const Point& rRad,
+ SdrCrookMode eMode, bool bVertical, bool bNoContortion, bool bRotate, const tools::Rectangle& rMarkRect)
+{
+ SdrPathObj* pPath=dynamic_cast<SdrPathObj*>( pO );
+ bool bDone = false;
+
+ if(pPath!=nullptr && !bNoContortion)
+ {
+ XPolyPolygon aXPP(pPath->GetPathPoly());
+ switch (eMode) {
+ case SdrCrookMode::Rotate : CrookRotatePoly (aXPP,rRef,rRad,bVertical); break;
+ case SdrCrookMode::Slant : CrookSlantPoly (aXPP,rRef,rRad,bVertical); break;
+ case SdrCrookMode::Stretch: CrookStretchPoly(aXPP,rRef,rRad,bVertical,rMarkRect); break;
+ } // switch
+ pPath->SetPathPoly(aXPP.getB2DPolyPolygon());
+ bDone = true;
+ }
+
+ if(!bDone && !pPath && pO->IsPolyObj() && 0 != pO->GetPointCount())
+ {
+ // for PolyObj's, but NOT for SdrPathObj's, e.g. the measurement object
+ sal_uInt32 nPointCount(pO->GetPointCount());
+ XPolygon aXP(static_cast<sal_uInt16>(nPointCount));
+ sal_uInt32 nPtNum;
+
+ for(nPtNum = 0; nPtNum < nPointCount; nPtNum++)
+ {
+ Point aPt(pO->GetPoint(nPtNum));
+ aXP[static_cast<sal_uInt16>(nPtNum)]=aPt;
+ }
+
+ switch (eMode)
+ {
+ case SdrCrookMode::Rotate : CrookRotatePoly (aXP,rRef,rRad,bVertical); break;
+ case SdrCrookMode::Slant : CrookSlantPoly (aXP,rRef,rRad,bVertical); break;
+ case SdrCrookMode::Stretch: CrookStretchPoly(aXP,rRef,rRad,bVertical,rMarkRect); break;
+ }
+
+ for(nPtNum = 0; nPtNum < nPointCount; nPtNum++)
+ {
+ // broadcasting could be optimized here, but for the
+ // current two points of the measurement object, it's fine
+ pO->SetPoint(aXP[static_cast<sal_uInt16>(nPtNum)],nPtNum);
+ }
+
+ bDone = true;
+ }
+
+ if(bDone)
+ return;
+
+ // for all others or if bNoContortion
+ Point aCtr0(pO->GetSnapRect().Center());
+ Point aCtr1(aCtr0);
+ bool bRotOk(false);
+ double nSin(0.0), nCos(1.0);
+ double nAngle(0.0);
+
+ if(0 != rRad.X() && 0 != rRad.Y())
+ {
+ bRotOk = bRotate;
+
+ switch (eMode)
+ {
+ case SdrCrookMode::Rotate : nAngle=CrookRotateXPoint (aCtr1,nullptr,nullptr,rRef,rRad,nSin,nCos,bVertical); bRotOk=bRotate; break;
+ case SdrCrookMode::Slant : nAngle=CrookSlantXPoint (aCtr1,nullptr,nullptr,rRef,rRad,nSin,nCos,bVertical); break;
+ case SdrCrookMode::Stretch: nAngle=CrookStretchXPoint(aCtr1,nullptr,nullptr,rRef,rRad,nSin,nCos,bVertical,rMarkRect); break;
+ }
+ }
+
+ aCtr1 -= aCtr0;
+
+ if(bRotOk)
+ pO->Rotate(aCtr0, Degree100(FRound(basegfx::rad2deg<100>(nAngle))), nSin, nCos);
+
+ pO->Move(Size(aCtr1.X(),aCtr1.Y()));
+}
+
+void SdrEditView::CrookMarkedObj(const Point& rRef, const Point& rRad, SdrCrookMode eMode,
+ bool bVertical, bool bNoContortion, bool bCopy)
+{
+ tools::Rectangle aMarkRect(GetMarkedObjRect());
+ const bool bUndo = IsUndoEnabled();
+
+ bool bRotate=bNoContortion && eMode==SdrCrookMode::Rotate && IsRotateAllowed();
+
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ OUString aStr {ImpGetDescriptionString(bNoContortion ? STR_EditCrook : STR_EditCrookContortion)};
+ if (bCopy)
+ aStr+=SvxResId(STR_EditWithCopy);
+ BegUndo(aStr);
+ }
+
+ if (bCopy)
+ CopyMarkedObj();
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pO=pM->GetMarkedSdrObj();
+ if( bUndo )
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pO));
+
+ const SdrObjList* pOL=pO->GetSubList();
+ if (bNoContortion || pOL==nullptr) {
+ ImpCrookObj(pO,rRef,rRad,eMode,bVertical,bNoContortion,bRotate,aMarkRect);
+ } else {
+ SdrObjListIter aIter(pOL,SdrIterMode::DeepNoGroups);
+ while (aIter.IsMore()) {
+ SdrObject* pO1=aIter.Next();
+ ImpCrookObj(pO1,rRef,rRad,eMode,bVertical,bNoContortion,bRotate,aMarkRect);
+ }
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+}
+
+void SdrEditView::ImpDistortObj(SdrObject* pO, const tools::Rectangle& rRef, const XPolygon& rDistortedRect, bool bNoContortion)
+{
+ SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pO );
+
+ if(!bNoContortion && pPath)
+ {
+ XPolyPolygon aXPP(pPath->GetPathPoly());
+ aXPP.Distort(rRef, rDistortedRect);
+ pPath->SetPathPoly(aXPP.getB2DPolyPolygon());
+ }
+ else if(pO->IsPolyObj())
+ {
+ // e. g. for the measurement object
+ sal_uInt32 nPointCount(pO->GetPointCount());
+ XPolygon aXP(static_cast<sal_uInt16>(nPointCount));
+ sal_uInt32 nPtNum;
+
+ for(nPtNum = 0; nPtNum < nPointCount; nPtNum++)
+ {
+ Point aPt(pO->GetPoint(nPtNum));
+ aXP[static_cast<sal_uInt16>(nPtNum)]=aPt;
+ }
+
+ aXP.Distort(rRef, rDistortedRect);
+
+ for(nPtNum = 0; nPtNum < nPointCount; nPtNum++)
+ {
+ // broadcasting could be optimized here, but for the
+ // current two points of the measurement object it's fine
+ pO->SetPoint(aXP[static_cast<sal_uInt16>(nPtNum)],nPtNum);
+ }
+ }
+}
+
+void SdrEditView::DistortMarkedObj(const tools::Rectangle& rRef, const XPolygon& rDistortedRect, bool bNoContortion, bool bCopy)
+{
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ OUString aStr {ImpGetDescriptionString(STR_EditDistort)};
+ if (bCopy)
+ aStr+=SvxResId(STR_EditWithCopy);
+ BegUndo(aStr);
+ }
+
+ if (bCopy)
+ CopyMarkedObj();
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pO=pM->GetMarkedSdrObj();
+ if( bUndo )
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pO));
+
+ tools::Rectangle aRefRect(rRef);
+ const SdrObjList* pOL=pO->GetSubList();
+ if (bNoContortion || pOL==nullptr) {
+ ImpDistortObj(pO,aRefRect,rDistortedRect,bNoContortion);
+ } else {
+ SdrObjListIter aIter(pOL,SdrIterMode::DeepNoGroups);
+ while (aIter.IsMore()) {
+ SdrObject* pO1=aIter.Next();
+ ImpDistortObj(pO1,aRefRect,rDistortedRect,bNoContortion);
+ }
+ }
+ }
+ if( bUndo )
+ EndUndo();
+}
+
+
+void SdrEditView::SetNotPersistAttrToMarked(const SfxItemSet& rAttr)
+{
+ // bReplaceAll has no effect here
+ tools::Rectangle aAllSnapRect(GetMarkedObjRect());
+ if (const SdrTransformRef1XItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF1X))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ SetRef1(Point(n,GetRef1().Y()));
+ }
+ if (const SdrTransformRef1YItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF1Y))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ SetRef1(Point(GetRef1().X(),n));
+ }
+ if (const SdrTransformRef2XItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF2X))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ SetRef2(Point(n,GetRef2().Y()));
+ }
+ if (const SdrTransformRef2YItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF2Y))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ SetRef2(Point(GetRef2().X(),n));
+ }
+ tools::Long nAllPosX=0; bool bAllPosX=false;
+ tools::Long nAllPosY=0; bool bAllPosY=false;
+ tools::Long nAllWdt=0; bool bAllWdt=false;
+ tools::Long nAllHgt=0; bool bAllHgt=false;
+ bool bDoIt=false;
+ if (const SdrAllPositionXItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ALLPOSITIONX))
+ {
+ nAllPosX = pPoolItem->GetValue();
+ bAllPosX=true; bDoIt=true;
+ }
+ if (const SdrAllPositionYItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ALLPOSITIONY))
+ {
+ nAllPosY = pPoolItem->GetValue();
+ bAllPosY=true; bDoIt=true;
+ }
+ if (const SdrAllSizeWidthItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ALLSIZEWIDTH))
+ {
+ nAllWdt = pPoolItem->GetValue();
+ bAllWdt=true; bDoIt=true;
+ }
+ if (const SdrAllSizeHeightItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ALLSIZEHEIGHT))
+ {
+ nAllHgt = pPoolItem->GetValue();
+ bAllHgt=true; bDoIt=true;
+ }
+ if (bDoIt) {
+ tools::Rectangle aRect(aAllSnapRect); // TODO: change this for PolyPt's and GluePt's!!!
+ if (bAllPosX) aRect.Move(nAllPosX-aRect.Left(),0);
+ if (bAllPosY) aRect.Move(0,nAllPosY-aRect.Top());
+ if (bAllWdt) aRect.SetRight(aAllSnapRect.Left()+nAllWdt );
+ if (bAllHgt) aRect.SetBottom(aAllSnapRect.Top()+nAllHgt );
+ SetMarkedObjRect(aRect);
+ }
+ if (const SdrResizeXAllItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_RESIZEXALL))
+ {
+ Fraction aXFact = pPoolItem->GetValue();
+ ResizeMarkedObj(aAllSnapRect.TopLeft(),aXFact,Fraction(1,1));
+ }
+ if (const SdrResizeYAllItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_RESIZEYALL))
+ {
+ Fraction aYFact = pPoolItem->GetValue();
+ ResizeMarkedObj(aAllSnapRect.TopLeft(),Fraction(1,1),aYFact);
+ }
+ if (const SdrRotateAllItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ROTATEALL))
+ {
+ Degree100 nAngle = pPoolItem->GetValue();
+ RotateMarkedObj(aAllSnapRect.Center(),nAngle);
+ }
+ if (const SdrHorzShearAllItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_HORZSHEARALL))
+ {
+ Degree100 nAngle = pPoolItem->GetValue();
+ ShearMarkedObj(aAllSnapRect.Center(),nAngle);
+ }
+ if (const SdrVertShearAllItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_VERTSHEARALL))
+ {
+ Degree100 nAngle = pPoolItem->GetValue();
+ ShearMarkedObj(aAllSnapRect.Center(),nAngle,true);
+ }
+
+ const bool bUndo = IsUndoEnabled();
+
+ // TODO: check if WhichRange is necessary.
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ const SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ if( bUndo )
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+
+ pObj->ApplyNotPersistAttr(rAttr);
+ }
+}
+
+void SdrEditView::MergeNotPersistAttrFromMarked(SfxItemSet& rAttr) const
+{
+ // TODO: Take into account the origin and PvPos.
+ tools::Rectangle aAllSnapRect(GetMarkedObjRect()); // TODO: change this for PolyPt's and GluePt's!!!
+ tools::Long nAllSnapPosX=aAllSnapRect.Left();
+ tools::Long nAllSnapPosY=aAllSnapRect.Top();
+ tools::Long nAllSnapWdt=aAllSnapRect.GetWidth()-1;
+ tools::Long nAllSnapHgt=aAllSnapRect.GetHeight()-1;
+ // TODO: could go into CheckPossibilities
+ bool bMovProtect = false, bMovProtectDC = false;
+ bool bSizProtect = false, bSizProtectDC = false;
+ bool bPrintable = true, bPrintableDC = false;
+ bool bVisible = true, bVisibleDC = false;
+ SdrLayerID nLayerId(0);
+ bool bLayerDC=false;
+ tools::Long nSnapPosX=0; bool bSnapPosXDC=false;
+ tools::Long nSnapPosY=0; bool bSnapPosYDC=false;
+ tools::Long nSnapWdt=0; bool bSnapWdtDC=false;
+ tools::Long nSnapHgt=0; bool bSnapHgtDC=false;
+ tools::Long nLogicWdt=0; bool bLogicWdtDC=false,bLogicWdtDiff=false;
+ tools::Long nLogicHgt=0; bool bLogicHgtDC=false,bLogicHgtDiff=false;
+ Degree100 nRotAngle(0); bool bRotAngleDC=false;
+ Degree100 nShrAngle(0); bool bShrAngleDC=false;
+ tools::Rectangle aSnapRect;
+ tools::Rectangle aLogicRect;
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm) {
+ const SdrMark* pM=GetSdrMarkByIndex(nm);
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+ if (nm==0) {
+ nLayerId=pObj->GetLayer();
+ bMovProtect=pObj->IsMoveProtect();
+ bSizProtect=pObj->IsResizeProtect();
+ bPrintable =pObj->IsPrintable();
+ bVisible = pObj->IsVisible();
+ tools::Rectangle aSnapRect2(pObj->GetSnapRect());
+ tools::Rectangle aLogicRect2(pObj->GetLogicRect());
+ nSnapPosX=aSnapRect2.Left();
+ nSnapPosY=aSnapRect2.Top();
+ nSnapWdt=aSnapRect2.GetWidth()-1;
+ nSnapHgt=aSnapRect2.GetHeight()-1;
+ nLogicWdt=aLogicRect2.GetWidth()-1;
+ nLogicHgt=aLogicRect2.GetHeight()-1;
+ bLogicWdtDiff=nLogicWdt!=nSnapWdt;
+ bLogicHgtDiff=nLogicHgt!=nSnapHgt;
+ nRotAngle=pObj->GetRotateAngle();
+ nShrAngle=pObj->GetShearAngle();
+ } else {
+ if (!bLayerDC && nLayerId !=pObj->GetLayer()) bLayerDC = true;
+ if (!bMovProtectDC && bMovProtect!=pObj->IsMoveProtect()) bMovProtectDC = true;
+ if (!bSizProtectDC && bSizProtect!=pObj->IsResizeProtect()) bSizProtectDC = true;
+ if (!bPrintableDC && bPrintable !=pObj->IsPrintable()) bPrintableDC = true;
+ if (!bVisibleDC && bVisible !=pObj->IsVisible()) bVisibleDC=true;
+ if (!bRotAngleDC && nRotAngle !=pObj->GetRotateAngle()) bRotAngleDC=true;
+ if (!bShrAngleDC && nShrAngle !=pObj->GetShearAngle()) bShrAngleDC=true;
+ if (!bSnapWdtDC || !bSnapHgtDC || !bSnapPosXDC || !bSnapPosYDC || !bLogicWdtDiff || !bLogicHgtDiff) {
+ aSnapRect=pObj->GetSnapRect();
+ if (nSnapPosX!=aSnapRect.Left()) bSnapPosXDC=true;
+ if (nSnapPosY!=aSnapRect.Top()) bSnapPosYDC=true;
+ if (nSnapWdt!=aSnapRect.GetWidth()-1) bSnapWdtDC=true;
+ if (nSnapHgt!=aSnapRect.GetHeight()-1) bSnapHgtDC=true;
+ }
+ if (!bLogicWdtDC || !bLogicHgtDC || !bLogicWdtDiff || !bLogicHgtDiff) {
+ aLogicRect=pObj->GetLogicRect();
+ if (nLogicWdt!=aLogicRect.GetWidth()-1) bLogicWdtDC=true;
+ if (nLogicHgt!=aLogicRect.GetHeight()-1) bLogicHgtDC=true;
+ if (!bLogicWdtDiff && aSnapRect.GetWidth()!=aLogicRect.GetWidth()) bLogicWdtDiff=true;
+ if (!bLogicHgtDiff && aSnapRect.GetHeight()!=aLogicRect.GetHeight()) bLogicHgtDiff=true;
+ }
+ }
+ }
+
+ if (bSnapPosXDC || nAllSnapPosX!=nSnapPosX) rAttr.Put(SdrAllPositionXItem(nAllSnapPosX));
+ if (bSnapPosYDC || nAllSnapPosY!=nSnapPosY) rAttr.Put(SdrAllPositionYItem(nAllSnapPosY));
+ if (bSnapWdtDC || nAllSnapWdt !=nSnapWdt ) rAttr.Put(SdrAllSizeWidthItem(nAllSnapWdt));
+ if (bSnapHgtDC || nAllSnapHgt !=nSnapHgt ) rAttr.Put(SdrAllSizeHeightItem(nAllSnapHgt));
+
+ // items for pure transformations
+ rAttr.Put(SdrMoveXItem());
+ rAttr.Put(SdrMoveYItem());
+ rAttr.Put(SdrResizeXOneItem());
+ rAttr.Put(SdrResizeYOneItem());
+ rAttr.Put(SdrRotateOneItem());
+ rAttr.Put(SdrHorzShearOneItem());
+ rAttr.Put(SdrVertShearOneItem());
+
+ if (nMarkCount>1) {
+ rAttr.Put(SdrResizeXAllItem());
+ rAttr.Put(SdrResizeYAllItem());
+ rAttr.Put(SdrRotateAllItem());
+ rAttr.Put(SdrHorzShearAllItem());
+ rAttr.Put(SdrVertShearAllItem());
+ }
+
+ if(meDragMode == SdrDragMode::Rotate || meDragMode == SdrDragMode::Mirror)
+ {
+ rAttr.Put(SdrTransformRef1XItem(GetRef1().X()));
+ rAttr.Put(SdrTransformRef1YItem(GetRef1().Y()));
+ }
+
+ if(meDragMode == SdrDragMode::Mirror)
+ {
+ rAttr.Put(SdrTransformRef2XItem(GetRef2().X()));
+ rAttr.Put(SdrTransformRef2YItem(GetRef2().Y()));
+ }
+}
+
+SfxItemSet SdrEditView::GetAttrFromMarked(bool bOnlyHardAttr) const
+{
+ SfxItemSet aSet(mpModel->GetItemPool());
+ MergeAttrFromMarked(aSet,bOnlyHardAttr);
+ //the EE_FEATURE items should not be set with SetAttrToMarked (see error message there)
+ //so we do not set them here
+ // #i32448#
+ // Do not disable, but clear the items.
+ aSet.ClearItem(EE_FEATURE_TAB);
+ aSet.ClearItem(EE_FEATURE_LINEBR);
+ aSet.ClearItem(EE_FEATURE_NOTCONV);
+ aSet.ClearItem(EE_FEATURE_FIELD);
+
+ return aSet;
+}
+
+void SdrEditView::MergeAttrFromMarked(SfxItemSet& rAttr, bool bOnlyHardAttr) const
+{
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t a = 0; a < nMarkCount; ++a)
+ {
+ // #80277# merging was done wrong in the prev version
+ SdrObject *pObj = GetMarkedObjectByIndex(a);
+ if (!pObj)
+ {
+ continue;
+ }
+
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ if(!bOnlyHardAttr)
+ {
+ if(SfxItemState::DONTCARE == aIter.GetItemState(false))
+ rAttr.InvalidateItem(nWhich);
+ else
+ rAttr.MergeValue(rSet.Get(nWhich), true);
+ }
+ else if(SfxItemState::SET == aIter.GetItemState(false))
+ {
+ const SfxPoolItem& rItem = rSet.Get(nWhich);
+ rAttr.MergeValue(rItem, true);
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ OUString sPayload;
+ switch(nWhich)
+ {
+ case XATTR_LINECOLOR:
+ {
+ const SfxPoolItem* pItem = rSet.GetItem(XATTR_LINECOLOR);
+ if (pItem)
+ {
+ Color aColor = static_cast<const XLineColorItem*>(pItem)->GetColorValue();
+ sPayload = OUString::number(static_cast<sal_uInt32>(aColor));
+
+ sPayload = ".uno:XLineColor=" + sPayload;
+ }
+ break;
+ }
+
+ case XATTR_FILLCOLOR:
+ {
+ const SfxPoolItem* pItem = rSet.GetItem(XATTR_FILLCOLOR);
+ if (pItem)
+ {
+ Color aColor = static_cast<const XFillColorItem*>(pItem)->GetColorValue();
+ sPayload = OUString::number(static_cast<sal_uInt32>(aColor));
+
+ sPayload = ".uno:FillColor=" + sPayload;
+ }
+ break;
+ }
+
+ case XATTR_FILLTRANSPARENCE:
+ {
+ const SfxPoolItem* pItem = rSet.GetItem(XATTR_FILLTRANSPARENCE);
+ if (pItem)
+ {
+ sal_uInt16 nTransparency = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
+ sPayload = OUString::number(nTransparency);
+
+ sPayload = ".uno:FillTransparence=" + sPayload;
+ }
+ break;
+ }
+
+ case XATTR_LINETRANSPARENCE:
+ {
+ const SfxPoolItem* pItem = rSet.GetItem(XATTR_LINETRANSPARENCE);
+ if (pItem)
+ {
+ sal_uInt16 nTransparency = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
+ sPayload = OUString::number(nTransparency);
+
+ sPayload = ".uno:LineTransparence=" + sPayload;
+ }
+ break;
+ }
+
+ case XATTR_LINEWIDTH:
+ {
+ const SfxPoolItem* pItem = rSet.GetItem(XATTR_LINEWIDTH);
+ if (pItem)
+ {
+ sal_uInt32 nWidth = static_cast<const XLineWidthItem*>(pItem)->GetValue();
+ sPayload = OUString::number(nWidth);
+
+ sPayload = ".uno:LineWidth=" + sPayload;
+ }
+ break;
+ }
+
+ case SDRATTR_SHADOWTRANSPARENCE:
+ {
+ const SfxPoolItem* pItem = rSet.GetItem(SDRATTR_SHADOWTRANSPARENCE);
+ if (pItem)
+ {
+ sal_uInt16 nWidth = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
+ sPayload = OUString::number(nWidth);
+
+ sPayload = ".uno:FillShadowTransparency=" + sPayload;
+ }
+ break;
+ }
+ }
+
+ if (!sPayload.isEmpty())
+ GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED,
+ OUStringToOString(sPayload, RTL_TEXTENCODING_ASCII_US).getStr());
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+}
+
+std::vector<sal_uInt16> GetAllCharPropIds(const SfxItemSet& rSet)
+{
+ std::vector<sal_uInt16> aCharWhichIds;
+ {
+ SfxItemIter aIter(rSet);
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
+ {
+ if (!IsInvalidItem(pItem))
+ {
+ sal_uInt16 nWhich = pItem->Which();
+ if (nWhich>=EE_CHAR_START && nWhich<=EE_CHAR_END)
+ aCharWhichIds.push_back( nWhich );
+ }
+ }
+ }
+ return aCharWhichIds;
+}
+
+std::vector<sal_uInt16> GetAllCharPropIds(o3tl::span< const SfxPoolItem* const > aChangedItems)
+{
+ std::vector<sal_uInt16> aCharWhichIds;
+ for (const SfxPoolItem* pItem : aChangedItems)
+ {
+ sal_uInt16 nWhich = pItem->Which();
+ if (nWhich>=EE_CHAR_START && nWhich<=EE_CHAR_END)
+ aCharWhichIds.push_back( nWhich );
+ }
+ return aCharWhichIds;
+}
+
+void SdrEditView::SetAttrToMarked(const SfxItemSet& rAttr, bool bReplaceAll)
+{
+ if (!AreObjectsMarked())
+ return;
+
+#ifdef DBG_UTIL
+ {
+ bool bHasEEFeatureItems=false;
+ SfxItemIter aIter(rAttr);
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); !bHasEEFeatureItems && pItem;
+ pItem = aIter.NextItem())
+ {
+ if (!IsInvalidItem(pItem)) {
+ sal_uInt16 nW=pItem->Which();
+ if (nW>=EE_FEATURE_START && nW<=EE_FEATURE_END) bHasEEFeatureItems=true;
+ }
+ }
+ if(bHasEEFeatureItems)
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ "SdrEditView::SetAttrToMarked(): Setting EE_FEATURE items at the SdrView does not make sense! It only leads to overhead and unreadable documents."));
+ xInfoBox->run();
+ }
+ }
+#endif
+
+ // #103836# if the user sets character attributes to the complete shape,
+ // we want to remove all hard set character attributes with same
+ // which ids from the text. We do that later but here we remember
+ // all character attribute which id's that are set.
+ std::vector<sal_uInt16> aCharWhichIds(GetAllCharPropIds(rAttr));
+
+ // To make Undo reconstruct text attributes correctly after Format.Standard
+ bool bHasEEItems=SearchOutlinerItems(rAttr,bReplaceAll);
+
+ // save additional geometry information when paragraph or character attributes
+ // are changed and the geometrical shape of the text object might be changed
+ bool bPossibleGeomChange(false);
+ SfxWhichIter aIter(rAttr);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while(!bPossibleGeomChange && nWhich)
+ {
+ SfxItemState eState = aIter.GetItemState();
+ if(eState == SfxItemState::SET)
+ {
+ if((nWhich >= SDRATTR_TEXT_MINFRAMEHEIGHT && nWhich <= SDRATTR_TEXT_CONTOURFRAME)
+ || nWhich == SDRATTR_3DOBJ_PERCENT_DIAGONAL
+ || nWhich == SDRATTR_3DOBJ_BACKSCALE
+ || nWhich == SDRATTR_3DOBJ_DEPTH
+ || nWhich == SDRATTR_3DOBJ_END_ANGLE
+ || nWhich == SDRATTR_3DSCENE_DISTANCE)
+ {
+ bPossibleGeomChange = true;
+ }
+ }
+ nWhich = aIter.NextWhich();
+ }
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ BegUndo(ImpGetDescriptionString(STR_EditSetAttributes));
+ }
+
+ const size_t nMarkCount(GetMarkedObjectCount());
+ std::vector< E3DModifySceneSnapRectUpdater* > aUpdaters;
+
+ // create ItemSet without SfxItemState::DONTCARE. Put()
+ // uses its second parameter (bInvalidAsDefault) to
+ // remove all such items to set them to default.
+ SfxItemSet aAttr(*rAttr.GetPool(), rAttr.GetRanges());
+ aAttr.Put(rAttr);
+
+ // #i38135#
+ bool bResetAnimationTimer(false);
+
+ const bool bLineStartWidthExplicitChange(SfxItemState::SET
+ == aAttr.GetItemState(XATTR_LINESTARTWIDTH));
+ const bool bLineEndWidthExplicitChange(SfxItemState::SET
+ == aAttr.GetItemState(XATTR_LINEENDWIDTH));
+ // check if LineWidth is part of the change
+ const bool bAdaptStartEndWidths(!(bLineStartWidthExplicitChange && bLineEndWidthExplicitChange)
+ && SfxItemState::SET == aAttr.GetItemState(XATTR_LINEWIDTH));
+ sal_Int32 nNewLineWidth(0);
+
+ if(bAdaptStartEndWidths)
+ {
+ nNewLineWidth = aAttr.Get(XATTR_LINEWIDTH).GetValue();
+ }
+
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj = pM->GetMarkedSdrObj();
+
+ if( bUndo )
+ {
+ SdrEdgeObj* pEdgeObj = dynamic_cast< SdrEdgeObj* >( pObj );
+ if ( pEdgeObj )
+ bPossibleGeomChange = true;
+ else
+ AddUndoActions( CreateConnectorUndo( *pObj ) );
+ }
+
+ // new geometry undo
+ if(bPossibleGeomChange && bUndo)
+ {
+ // save position and size of object, too
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+ }
+
+ if( bUndo )
+ {
+ // #i8508#
+ // If this is a text object also rescue the OutlinerParaObject since
+ // applying attributes to the object may change text layout when
+ // multiple portions exist with multiple formats. If an OutlinerParaObject
+ // really exists and needs to be rescued is evaluated in the undo
+ // implementation itself.
+ const bool bRescueText = dynamic_cast< SdrTextObj* >(pObj) != nullptr;
+
+ // add attribute undo
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj,false,bHasEEItems || bPossibleGeomChange || bRescueText));
+ }
+
+ // set up a scene updater if object is a 3d object
+ if(dynamic_cast< E3dObject* >(pObj))
+ {
+ aUpdaters.push_back(new E3DModifySceneSnapRectUpdater(pObj));
+ }
+
+ sal_Int32 nOldLineWidth(0);
+ if (bAdaptStartEndWidths)
+ {
+ nOldLineWidth = pObj->GetMergedItem(XATTR_LINEWIDTH).GetValue();
+ }
+
+ // set attributes at object
+ pObj->SetMergedItemSetAndBroadcast(aAttr, bReplaceAll);
+
+ if(bAdaptStartEndWidths)
+ {
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+
+ if(nOldLineWidth != nNewLineWidth)
+ {
+ if(SfxItemState::DONTCARE != rSet.GetItemState(XATTR_LINESTARTWIDTH))
+ {
+ const sal_Int32 nValAct(rSet.Get(XATTR_LINESTARTWIDTH).GetValue());
+ const sal_Int32 nValNewStart(std::max(sal_Int32(0), nValAct + (((nNewLineWidth - nOldLineWidth) * 15) / 10)));
+
+ pObj->SetMergedItem(XLineStartWidthItem(nValNewStart));
+ }
+
+ if(SfxItemState::DONTCARE != rSet.GetItemState(XATTR_LINEENDWIDTH))
+ {
+ const sal_Int32 nValAct(rSet.Get(XATTR_LINEENDWIDTH).GetValue());
+ const sal_Int32 nValNewEnd(std::max(sal_Int32(0), nValAct + (((nNewLineWidth - nOldLineWidth) * 15) / 10)));
+
+ pObj->SetMergedItem(XLineEndWidthItem(nValNewEnd));
+ }
+ }
+ }
+
+ if(auto pTextObj = dynamic_cast<SdrTextObj*>( pObj))
+ {
+ if(!aCharWhichIds.empty())
+ {
+ tools::Rectangle aOldBoundRect = pTextObj->GetLastBoundRect();
+
+ // #110094#-14 pTextObj->SendRepaintBroadcast(pTextObj->GetBoundRect());
+ pTextObj->RemoveOutlinerCharacterAttribs( aCharWhichIds );
+
+ // object has changed, should be called from
+ // RemoveOutlinerCharacterAttribs. This will change when the text
+ // object implementation changes.
+ pTextObj->SetChanged();
+
+ pTextObj->BroadcastObjectChange();
+ pTextObj->SendUserCall(SdrUserCallType::ChangeAttr, aOldBoundRect);
+ }
+ }
+
+ // #i38495#
+ if(!bResetAnimationTimer)
+ {
+ if(pObj->GetViewContact().isAnimatedInAnyViewObjectContact())
+ {
+ bResetAnimationTimer = true;
+ }
+ }
+ }
+
+ // fire scene updaters
+ while(!aUpdaters.empty())
+ {
+ delete aUpdaters.back();
+ aUpdaters.pop_back();
+ }
+
+ // #i38135#
+ if(bResetAnimationTimer)
+ {
+ SetAnimationTimer(0);
+ }
+
+ // better check before what to do:
+ // pObj->SetAttr() or SetNotPersistAttr()
+ // TODO: missing implementation!
+ SetNotPersistAttrToMarked(rAttr);
+
+ if( bUndo )
+ EndUndo();
+}
+
+SfxStyleSheet* SdrEditView::GetStyleSheetFromMarked() const
+{
+ SfxStyleSheet* pRet=nullptr;
+ bool b1st=true;
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm) {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SfxStyleSheet* pSS=pM->GetMarkedSdrObj()->GetStyleSheet();
+ if (b1st) pRet=pSS;
+ else if (pRet!=pSS) return nullptr; // different stylesheets
+ b1st=false;
+ }
+ return pRet;
+}
+
+void SdrEditView::SetStyleSheetToMarked(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
+{
+ if (!AreObjectsMarked())
+ return;
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ OUString aStr;
+ if (pStyleSheet!=nullptr)
+ aStr = ImpGetDescriptionString(STR_EditSetStylesheet);
+ else
+ aStr = ImpGetDescriptionString(STR_EditDelStylesheet);
+ BegUndo(aStr);
+ }
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ if( bUndo )
+ {
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pM->GetMarkedSdrObj()));
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pM->GetMarkedSdrObj(),true,true));
+ }
+ pM->GetMarkedSdrObj()->SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
+ }
+
+ if( bUndo )
+ EndUndo();
+}
+
+
+void SdrEditView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
+{
+ if(GetMarkedObjectCount())
+ {
+ rTargetSet.Put(GetAttrFromMarked(bOnlyHardAttr), false);
+ }
+ else
+ {
+ SdrMarkView::GetAttributes(rTargetSet, bOnlyHardAttr);
+ }
+}
+
+void SdrEditView::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
+{
+ if (GetMarkedObjectCount()!=0) {
+ SetAttrToMarked(rSet,bReplaceAll);
+ } else {
+ SdrMarkView::SetAttributes(rSet,bReplaceAll);
+ }
+}
+
+SfxStyleSheet* SdrEditView::GetStyleSheet() const
+{
+ if (GetMarkedObjectCount()!=0) {
+ return GetStyleSheetFromMarked();
+ } else {
+ return SdrMarkView::GetStyleSheet();
+ }
+}
+
+void SdrEditView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
+{
+ if (GetMarkedObjectCount()!=0) {
+ SetStyleSheetToMarked(pStyleSheet,bDontRemoveHardAttr);
+ } else {
+ SdrMarkView::SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
+ }
+}
+
+
+SfxItemSet SdrEditView::GetGeoAttrFromMarked() const
+{
+ SfxItemSet aRetSet(
+ mpModel->GetItemPool(),
+ svl::Items< // SID_ATTR_TRANSFORM_... from s:svxids.hrc
+ SDRATTR_CORNER_RADIUS, SDRATTR_CORNER_RADIUS,
+ SID_ATTR_TRANSFORM_POS_X, SID_ATTR_TRANSFORM_ANGLE,
+ SID_ATTR_TRANSFORM_PROTECT_POS, SID_ATTR_TRANSFORM_AUTOHEIGHT>);
+
+ if (AreObjectsMarked())
+ {
+ SfxItemSet aMarkAttr(GetAttrFromMarked(false)); // because of AutoGrowHeight and corner radius
+ tools::Rectangle aRect(GetMarkedObjRect());
+
+ if(GetSdrPageView())
+ {
+ GetSdrPageView()->LogicToPagePos(aRect);
+ }
+
+ // position
+ aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_POS_X,aRect.Left()));
+ aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_POS_Y,aRect.Top()));
+
+ // size
+ tools::Long nResizeRefX=aRect.Left();
+ tools::Long nResizeRefY=aRect.Top();
+ if (meDragMode==SdrDragMode::Rotate) { // use rotation axis as a reference for resizing, too
+ nResizeRefX=maRef1.X();
+ nResizeRefY=maRef1.Y();
+ }
+ aRetSet.Put(SfxUInt32Item(SID_ATTR_TRANSFORM_WIDTH,aRect.Right()-aRect.Left()));
+ aRetSet.Put(SfxUInt32Item(SID_ATTR_TRANSFORM_HEIGHT,aRect.Bottom()-aRect.Top()));
+ aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_RESIZE_REF_X,nResizeRefX));
+ aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_RESIZE_REF_Y,nResizeRefY));
+
+ Point aRotateAxe(maRef1);
+
+ if(GetSdrPageView())
+ {
+ GetSdrPageView()->LogicToPagePos(aRotateAxe);
+ }
+
+ // rotation
+ tools::Long nRotateRefX=aRect.Center().X();
+ tools::Long nRotateRefY=aRect.Center().Y();
+ if (meDragMode==SdrDragMode::Rotate) {
+ nRotateRefX=aRotateAxe.X();
+ nRotateRefY=aRotateAxe.Y();
+ }
+ aRetSet.Put(SdrAngleItem(SID_ATTR_TRANSFORM_ANGLE,GetMarkedObjRotate()));
+ aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_ROT_X,nRotateRefX));
+ aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_ROT_Y,nRotateRefY));
+
+ // shearing
+ tools::Long nShearRefX=aRect.Left();
+ tools::Long nShearRefY=aRect.Bottom();
+ if (meDragMode==SdrDragMode::Rotate) { // use rotation axis as a reference for shearing, too
+ nShearRefX=aRotateAxe.X();
+ nShearRefY=aRotateAxe.Y();
+ }
+ aRetSet.Put(SdrAngleItem(SID_ATTR_TRANSFORM_SHEAR,GetMarkedObjShear()));
+ aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_SHEAR_X,nShearRefX));
+ aRetSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_SHEAR_Y,nShearRefY));
+
+ // check every object whether it is protected
+ const SdrMarkList& rMarkList=GetMarkedObjectList();
+ const size_t nMarkCount=rMarkList.GetMarkCount();
+ SdrObject* pObj=rMarkList.GetMark(0)->GetMarkedSdrObj();
+ bool bPosProt=pObj->IsMoveProtect();
+ bool bSizProt=pObj->IsResizeProtect();
+ bool bPosProtDontCare=false;
+ bool bSizProtDontCare=false;
+ for (size_t i=1; i<nMarkCount && (!bPosProtDontCare || !bSizProtDontCare); ++i)
+ {
+ pObj=rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if (bPosProt!=pObj->IsMoveProtect()) bPosProtDontCare=true;
+ if (bSizProt!=pObj->IsResizeProtect()) bSizProtDontCare=true;
+ }
+
+ // InvalidateItem sets item to DONT_CARE
+ if (bPosProtDontCare) {
+ aRetSet.InvalidateItem(SID_ATTR_TRANSFORM_PROTECT_POS);
+ } else {
+ aRetSet.Put(SfxBoolItem(SID_ATTR_TRANSFORM_PROTECT_POS,bPosProt));
+ }
+ if (bSizProtDontCare) {
+ aRetSet.InvalidateItem(SID_ATTR_TRANSFORM_PROTECT_SIZE);
+ } else {
+ aRetSet.Put(SfxBoolItem(SID_ATTR_TRANSFORM_PROTECT_SIZE,bSizProt));
+ }
+
+ SfxItemState eState=aMarkAttr.GetItemState(SDRATTR_TEXT_AUTOGROWWIDTH);
+ bool bAutoGrow=aMarkAttr.Get(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue();
+ if (eState==SfxItemState::DONTCARE) {
+ aRetSet.InvalidateItem(SID_ATTR_TRANSFORM_AUTOWIDTH);
+ } else if (eState==SfxItemState::SET) {
+ aRetSet.Put(SfxBoolItem(SID_ATTR_TRANSFORM_AUTOWIDTH,bAutoGrow));
+ }
+
+ eState=aMarkAttr.GetItemState(SDRATTR_TEXT_AUTOGROWHEIGHT);
+ bAutoGrow=aMarkAttr.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
+ if (eState==SfxItemState::DONTCARE) {
+ aRetSet.InvalidateItem(SID_ATTR_TRANSFORM_AUTOHEIGHT);
+ } else if (eState==SfxItemState::SET) {
+ aRetSet.Put(SfxBoolItem(SID_ATTR_TRANSFORM_AUTOHEIGHT,bAutoGrow));
+ }
+
+ eState=aMarkAttr.GetItemState(SDRATTR_CORNER_RADIUS);
+ tools::Long nRadius=aMarkAttr.Get(SDRATTR_CORNER_RADIUS).GetValue();
+ if (eState==SfxItemState::DONTCARE) {
+ aRetSet.InvalidateItem(SDRATTR_CORNER_RADIUS);
+ } else if (eState==SfxItemState::SET) {
+ aRetSet.Put(makeSdrEckenradiusItem(nRadius));
+ }
+
+ basegfx::B2DHomMatrix aTransformation;
+
+ if(nMarkCount > 1)
+ {
+ // multiple objects, range is collected in aRect
+ aTransformation = basegfx::utils::createScaleTranslateB2DHomMatrix(
+ aRect.Left(), aRect.Top(),
+ aRect.getWidth(), aRect.getHeight());
+ }
+ else
+ {
+ // single object, get homogen transformation
+ basegfx::B2DPolyPolygon aPolyPolygon;
+
+ pObj->TRGetBaseGeometry(aTransformation, aPolyPolygon);
+ }
+
+ if(aTransformation.isIdentity())
+ {
+ aRetSet.InvalidateItem(SID_ATTR_TRANSFORM_MATRIX);
+ }
+ else
+ {
+ css::geometry::AffineMatrix2D aAffineMatrix2D;
+ Point aPageOffset(0, 0);
+
+ if(GetSdrPageView())
+ {
+ aPageOffset = GetSdrPageView()->GetPageOrigin();
+ }
+
+ aAffineMatrix2D.m00 = aTransformation.get(0, 0);
+ aAffineMatrix2D.m01 = aTransformation.get(0, 1);
+ aAffineMatrix2D.m02 = aTransformation.get(0, 2) - aPageOffset.X();
+ aAffineMatrix2D.m10 = aTransformation.get(1, 0);
+ aAffineMatrix2D.m11 = aTransformation.get(1, 1);
+ aAffineMatrix2D.m12 = aTransformation.get(1, 2) - aPageOffset.Y();
+
+ aRetSet.Put(AffineMatrixItem(&aAffineMatrix2D));
+ }
+ }
+
+ return aRetSet;
+}
+
+static Point ImpGetPoint(const tools::Rectangle& rRect, RectPoint eRP)
+{
+ switch(eRP) {
+ case RectPoint::LT: return rRect.TopLeft();
+ case RectPoint::MT: return rRect.TopCenter();
+ case RectPoint::RT: return rRect.TopRight();
+ case RectPoint::LM: return rRect.LeftCenter();
+ case RectPoint::MM: return rRect.Center();
+ case RectPoint::RM: return rRect.RightCenter();
+ case RectPoint::LB: return rRect.BottomLeft();
+ case RectPoint::MB: return rRect.BottomCenter();
+ case RectPoint::RB: return rRect.BottomRight();
+ }
+ return Point(); // Should not happen!
+}
+
+void SdrEditView::SetGeoAttrToMarked(const SfxItemSet& rAttr, bool addPageMargin)
+{
+ const bool bTiledRendering = comphelper::LibreOfficeKit::isActive();
+
+ tools::Rectangle aRect(GetMarkedObjRect());
+
+ if(GetSdrPageView())
+ {
+ if (addPageMargin)
+ {
+ SdrPage * pPage = GetSdrPageView()->GetPage();
+ Point upperLeft(pPage->GetLeftBorder(), pPage->GetUpperBorder());
+ aRect.Move(upperLeft.getX(), upperLeft.getY());
+ }
+ GetSdrPageView()->LogicToPagePos(aRect);
+ }
+
+ Degree100 nOldRotateAngle=GetMarkedObjRotate();
+ Degree100 nOldShearAngle=GetMarkedObjShear();
+ const SdrMarkList& rMarkList=GetMarkedObjectList();
+ SdrObject* pObj=nullptr;
+
+ RectPoint eSizePoint=RectPoint::MM;
+ tools::Long nPosDX=0;
+ tools::Long nPosDY=0;
+ tools::Long nSizX=0;
+ tools::Long nSizY=0;
+ Degree100 nRotateAngle(0);
+
+ bool bModeIsRotate(meDragMode == SdrDragMode::Rotate);
+ tools::Long nRotateX(0);
+ tools::Long nRotateY(0);
+ tools::Long nOldRotateX(0);
+ tools::Long nOldRotateY(0);
+ if(bModeIsRotate)
+ {
+ Point aRotateAxe(maRef1);
+
+ if(GetSdrPageView())
+ {
+ GetSdrPageView()->LogicToPagePos(aRotateAxe);
+ }
+
+ nRotateX = nOldRotateX = aRotateAxe.X();
+ nRotateY = nOldRotateY = aRotateAxe.Y();
+ }
+
+ Degree100 nShearAngle(0);
+ tools::Long nShearX=0;
+ tools::Long nShearY=0;
+ bool bShearVert=false;
+
+ bool bChgPos=false;
+ bool bChgSiz=false;
+ bool bChgWdh=false;
+ bool bChgHgt=false;
+ bool bRotate=false;
+ bool bShear =false;
+
+ bool bSetAttr=false;
+ SfxItemSet aSetAttr(mpModel->GetItemPool());
+
+ // position
+ if (const SfxInt32Item *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_POS_X))
+ {
+ nPosDX = pPoolItem->GetValue() - aRect.Left();
+ bChgPos=true;
+ }
+ if (const SfxInt32Item *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_POS_Y))
+ {
+ nPosDY = pPoolItem->GetValue() - aRect.Top();
+ bChgPos=true;
+ }
+ // size
+ if (const SfxUInt32Item *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_WIDTH))
+ {
+ nSizX = pPoolItem->GetValue();
+ bChgSiz=true;
+ bChgWdh=true;
+ }
+ if (const SfxUInt32Item *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_HEIGHT))
+ {
+ nSizY = pPoolItem->GetValue();
+ bChgSiz=true;
+ bChgHgt=true;
+ }
+ if (bChgSiz) {
+ if (bTiledRendering && SfxItemState::SET != rAttr.GetItemState(SID_ATTR_TRANSFORM_SIZE_POINT))
+ eSizePoint = RectPoint::LT;
+ else
+ eSizePoint = static_cast<RectPoint>(rAttr.Get(SID_ATTR_TRANSFORM_SIZE_POINT).GetValue());
+ }
+
+ // rotation
+ if (const SdrAngleItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_DELTA_ANGLE))
+ {
+ nRotateAngle = pPoolItem->GetValue();
+ bRotate = (nRotateAngle != 0_deg100);
+ }
+
+ // rotation
+ if (const SdrAngleItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_ANGLE))
+ {
+ nRotateAngle = pPoolItem->GetValue() - nOldRotateAngle;
+ bRotate = (nRotateAngle != 0_deg100);
+ }
+
+ // position rotation point x
+ if(bRotate || rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_ROT_X))
+ nRotateX = rAttr.Get(SID_ATTR_TRANSFORM_ROT_X).GetValue();
+
+ // position rotation point y
+ if(bRotate || rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_ROT_Y))
+ nRotateY = rAttr.Get(SID_ATTR_TRANSFORM_ROT_Y).GetValue();
+
+ // shearing
+ if (const SdrAngleItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_SHEAR))
+ {
+ Degree100 nNewShearAngle=pPoolItem->GetValue();
+ if (nNewShearAngle>SDRMAXSHEAR) nNewShearAngle=SDRMAXSHEAR;
+ if (nNewShearAngle<-SDRMAXSHEAR) nNewShearAngle=-SDRMAXSHEAR;
+ if (nNewShearAngle!=nOldShearAngle) {
+ bShearVert = rAttr.Get(SID_ATTR_TRANSFORM_SHEAR_VERTICAL).GetValue();
+ if (bShearVert) {
+ nShearAngle=nNewShearAngle;
+ } else {
+ if (nNewShearAngle!=0_deg100 && nOldShearAngle!=0_deg100) {
+ // bug fix
+ double nOld = tan(toRadians(nOldShearAngle));
+ double nNew = tan(toRadians(nNewShearAngle));
+ nNew-=nOld;
+ nNew = basegfx::rad2deg<100>(atan(nNew));
+ nShearAngle=Degree100(FRound(nNew));
+ } else {
+ nShearAngle=nNewShearAngle-nOldShearAngle;
+ }
+ }
+ bShear=nShearAngle!=0_deg100;
+ if (bShear) {
+ nShearX=static_cast<const SfxInt32Item&>(rAttr.Get(SID_ATTR_TRANSFORM_SHEAR_X)).GetValue();
+ nShearY=static_cast<const SfxInt32Item&>(rAttr.Get(SID_ATTR_TRANSFORM_SHEAR_Y)).GetValue();
+ }
+ }
+ }
+
+ // AutoGrow
+ if (const SfxBoolItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_AUTOWIDTH))
+ {
+ bool bAutoGrow = pPoolItem->GetValue();
+ aSetAttr.Put(makeSdrTextAutoGrowWidthItem(bAutoGrow));
+ bSetAttr=true;
+ }
+
+ if (const SfxBoolItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_AUTOHEIGHT))
+ {
+ bool bAutoGrow = pPoolItem->GetValue();
+ aSetAttr.Put(makeSdrTextAutoGrowHeightItem(bAutoGrow));
+ bSetAttr=true;
+ }
+
+ // corner radius
+ if (m_bEdgeRadiusAllowed)
+ if (const SdrMetricItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_CORNER_RADIUS))
+ {
+ tools::Long nRadius = pPoolItem->GetValue();
+ aSetAttr.Put(makeSdrEckenradiusItem(nRadius));
+ bSetAttr=true;
+ }
+
+ ForcePossibilities();
+
+ BegUndo(SvxResId(STR_EditTransform),GetDescriptionOfMarkedObjects());
+
+ if (bSetAttr) {
+ SetAttrToMarked(aSetAttr,false);
+ }
+
+ // change size and height
+ if (bChgSiz && (m_bResizeFreeAllowed || m_bResizePropAllowed)) {
+ Fraction aWdt(nSizX,aRect.Right()-aRect.Left());
+ Fraction aHgt(nSizY,aRect.Bottom()-aRect.Top());
+ Point aRef(ImpGetPoint(aRect,eSizePoint));
+
+ if(GetSdrPageView())
+ {
+ GetSdrPageView()->PagePosToLogic(aRef);
+ }
+
+ ResizeMultMarkedObj(aRef, aWdt, aHgt, bChgWdh, bChgHgt);
+ }
+
+ // rotate
+ if (bRotate && (m_bRotateFreeAllowed || m_bRotate90Allowed)) {
+ Point aRef(nRotateX,nRotateY);
+
+ if(GetSdrPageView())
+ {
+ GetSdrPageView()->PagePosToLogic(aRef);
+ }
+
+ RotateMarkedObj(aRef,nRotateAngle);
+ }
+
+ // set rotation point position
+ if(bModeIsRotate && (nRotateX != nOldRotateX || nRotateY != nOldRotateY))
+ {
+ Point aNewRef1(nRotateX, nRotateY);
+
+ if(GetSdrPageView())
+ {
+ GetSdrPageView()->PagePosToLogic(aNewRef1);
+ }
+
+ SetRef1(aNewRef1);
+ }
+
+ // shear
+ if (bShear && m_bShearAllowed) {
+ Point aRef(nShearX,nShearY);
+
+ if(GetSdrPageView())
+ {
+ GetSdrPageView()->PagePosToLogic(aRef);
+ }
+
+ ShearMarkedObj(aRef,nShearAngle,bShearVert);
+
+ // #i74358#
+ // ShearMarkedObj creates a linear combination of the existing transformation and
+ // the new shear to apply. If the object is already transformed (e.g. rotated) the
+ // linear combination will not decompose to the same start values again, but to a
+ // new combination. Thus it makes no sense to check if the wanted shear is reached
+ // or not. Taking out.
+ }
+
+ // change position
+ if (bChgPos && m_bMoveAllowed) {
+ MoveMarkedObj(Size(nPosDX,nPosDY));
+ }
+
+ const size_t nMarkCount=rMarkList.GetMarkCount();
+ // protect position
+ if(const SfxBoolItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_PROTECT_POS))
+ {
+ const bool bProtPos(pPoolItem->GetValue());
+ bool bChanged(false);
+
+ for(size_t i = 0; i < nMarkCount; ++i)
+ {
+ pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+
+ if(pObj->IsMoveProtect() != bProtPos)
+ {
+ bChanged = true;
+ pObj->SetMoveProtect(bProtPos);
+
+ if(bProtPos)
+ {
+ pObj->SetResizeProtect(true);
+ }
+ }
+ }
+
+ if(bChanged)
+ {
+ m_bMoveProtect = bProtPos;
+
+ if(bProtPos)
+ {
+ m_bResizeProtect = true;
+ }
+
+ // #i77187# there is no simple method to get the toolbars updated
+ // in the application. The App is listening to selection change and i
+ // will use it here (even if not true). It's acceptable since changing
+ // this model data is pretty rare and only possible using the F4 dialog
+ MarkListHasChanged();
+ }
+ }
+
+ if(!m_bMoveProtect)
+ {
+ // protect size
+ if(const SfxBoolItem *pPoolItem = rAttr.GetItemIfSet(SID_ATTR_TRANSFORM_PROTECT_SIZE))
+ {
+ const bool bProtSize(pPoolItem->GetValue());
+ bool bChanged(false);
+
+ for(size_t i = 0; i < nMarkCount; ++i)
+ {
+ pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+
+ if(pObj->IsResizeProtect() != bProtSize)
+ {
+ bChanged = true;
+ pObj->SetResizeProtect(bProtSize);
+ }
+ }
+
+ if(bChanged)
+ {
+ m_bResizeProtect = bProtSize;
+
+ // #i77187# see above
+ MarkListHasChanged();
+ }
+ }
+ }
+
+ EndUndo();
+}
+
+
+bool SdrEditView::IsAlignPossible() const
+{ // at least two selected objects, at least one of them movable
+ ForcePossibilities();
+ const size_t nCount=GetMarkedObjectCount();
+ if (nCount==0) return false; // nothing selected!
+ if (nCount==1) return m_bMoveAllowed; // align single object to page
+ return m_bOneOrMoreMovable; // otherwise: MarkCount>=2
+}
+
+void SdrEditView::AlignMarkedObjects(SdrHorAlign eHor, SdrVertAlign eVert)
+{
+ if (eHor==SdrHorAlign::NONE && eVert==SdrVertAlign::NONE)
+ return;
+
+ SortMarkedObjects();
+ if (!GetMarkedObjectCount())
+ return;
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ {
+ EndTextEditCurrentView();
+ OUString aStr(GetDescriptionOfMarkedObjects());
+ if (eHor==SdrHorAlign::NONE)
+ {
+ switch (eVert)
+ {
+ case SdrVertAlign::Top:
+ aStr = ImpGetDescriptionString(STR_EditAlignVTop);
+ break;
+ case SdrVertAlign::Bottom:
+ aStr = ImpGetDescriptionString(STR_EditAlignVBottom);
+ break;
+ case SdrVertAlign::Center:
+ aStr = ImpGetDescriptionString(STR_EditAlignVCenter);
+ break;
+ default: break;
+ }
+ }
+ else if (eVert==SdrVertAlign::NONE)
+ {
+ switch (eHor)
+ {
+ case SdrHorAlign::Left:
+ aStr = ImpGetDescriptionString(STR_EditAlignHLeft);
+ break;
+ case SdrHorAlign::Right:
+ aStr = ImpGetDescriptionString(STR_EditAlignHRight);
+ break;
+ case SdrHorAlign::Center:
+ aStr = ImpGetDescriptionString(STR_EditAlignHCenter);
+ break;
+ default: break;
+ }
+ }
+ else if (eHor==SdrHorAlign::Center && eVert==SdrVertAlign::Center)
+ {
+ aStr = ImpGetDescriptionString(STR_EditAlignCenter);
+ }
+ else
+ {
+ aStr = ImpGetDescriptionString(STR_EditAlign);
+ }
+ BegUndo(aStr);
+ }
+
+ tools::Rectangle aBound;
+ const size_t nMarkCount=GetMarkedObjectCount();
+ bool bHasFixed=false;
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrObjTransformInfoRec aInfo;
+ pObj->TakeObjInfo(aInfo);
+ if (!aInfo.bMoveAllowed || pObj->IsMoveProtect())
+ {
+ tools::Rectangle aObjRect(pObj->GetSnapRect());
+ aBound.Union(aObjRect);
+ bHasFixed=true;
+ }
+ }
+ if (!bHasFixed)
+ {
+ if (nMarkCount==1)
+ { // align single object to page
+ const SdrObject* pObj=GetMarkedObjectByIndex(0);
+ const SdrPage* pPage=pObj->getSdrPageFromSdrObject();
+ const SdrPageGridFrameList* pGFL=pPage->GetGridFrameList(GetSdrPageViewOfMarkedByIndex(0),&(pObj->GetSnapRect()));
+ const SdrPageGridFrame* pFrame=nullptr;
+ if (pGFL!=nullptr && pGFL->GetCount()!=0)
+ { // Writer
+ pFrame=&((*pGFL)[0]);
+ }
+
+ if (pFrame!=nullptr)
+ { // Writer
+ aBound=pFrame->GetUserArea();
+ }
+ else
+ {
+ aBound=tools::Rectangle(pPage->GetLeftBorder(),pPage->GetUpperBorder(),
+ pPage->GetWidth()-pPage->GetRightBorder(),
+ pPage->GetHeight()-pPage->GetLowerBorder());
+ }
+ }
+ else
+ {
+ aBound=GetMarkedObjRect();
+ }
+ }
+ Point aCenter(aBound.Center());
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrObjTransformInfoRec aInfo;
+ pObj->TakeObjInfo(aInfo);
+ if (aInfo.bMoveAllowed && !pObj->IsMoveProtect())
+ {
+ tools::Long nXMov=0;
+ tools::Long nYMov=0;
+ tools::Rectangle aObjRect(pObj->GetSnapRect());
+ switch (eVert)
+ {
+ case SdrVertAlign::Top : nYMov=aBound.Top() -aObjRect.Top() ; break;
+ case SdrVertAlign::Bottom: nYMov=aBound.Bottom()-aObjRect.Bottom() ; break;
+ case SdrVertAlign::Center: nYMov=aCenter.Y() -aObjRect.Center().Y(); break;
+ default: break;
+ }
+ switch (eHor)
+ {
+ case SdrHorAlign::Left : nXMov=aBound.Left() -aObjRect.Left() ; break;
+ case SdrHorAlign::Right : nXMov=aBound.Right() -aObjRect.Right() ; break;
+ case SdrHorAlign::Center: nXMov=aCenter.X() -aObjRect.Center().X(); break;
+ default: break;
+ }
+ if (nXMov!=0 || nYMov!=0)
+ {
+ // SdrEdgeObj needs an extra SdrUndoGeoObj since the
+ // connections may need to be saved
+ if( bUndo )
+ {
+ if( dynamic_cast<SdrEdgeObj*>(pObj) )
+ {
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+ }
+
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoMoveObject(*pObj,Size(nXMov,nYMov)));
+ }
+
+ pObj->Move(Size(nXMov,nYMov));
+ }
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdedtv2.cxx b/svx/source/svdraw/svdedtv2.cxx
new file mode 100644
index 000000000..50a7940ca
--- /dev/null
+++ b/svx/source/svdraw/svdedtv2.cxx
@@ -0,0 +1,2250 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdedtv.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xtextit0.hxx>
+#include "svdfmtf.hxx"
+#include <svdpdf.hxx>
+#include <svx/svdetc.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/eeitem.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdoashp.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <i18nutil/unicode.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <memory>
+#include <vector>
+#include <vcl/graph.hxx>
+#include <svx/svxids.hrc>
+#include <dstribut_enum.hxx>
+#include <osl/diagnose.h>
+
+using namespace com::sun::star;
+
+SdrObject* SdrEditView::GetMaxToTopObj(SdrObject* /*pObj*/) const
+{
+ return nullptr;
+}
+
+SdrObject* SdrEditView::GetMaxToBtmObj(SdrObject* /*pObj*/) const
+{
+ return nullptr;
+}
+
+void SdrEditView::ObjOrderChanged(SdrObject* /*pObj*/, size_t /*nOldPos*/, size_t /*nNewPos*/)
+{
+}
+
+void SdrEditView::MovMarkedToTop()
+{
+ const size_t nCount=GetMarkedObjectCount();
+ if (nCount==0)
+ return;
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditMovToTop),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::MoveToTop);
+
+ SortMarkedObjects();
+ for (size_t nm=0; nm<nCount; ++nm)
+ { // All Ordnums have to be correct!
+ GetMarkedObjectByIndex(nm)->GetOrdNum();
+ }
+ bool bChg=false;
+ SdrObjList* pOL0=nullptr;
+ size_t nNewPos=0;
+ for (size_t nm=nCount; nm>0;)
+ {
+ --nm;
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ if (pOL!=pOL0)
+ {
+ nNewPos = pOL->GetObjCount()-1;
+ pOL0=pOL;
+ }
+ const size_t nNowPos = pObj->GetOrdNumDirect();
+ const tools::Rectangle& rBR=pObj->GetCurrentBoundRect();
+ size_t nCmpPos = nNowPos+1;
+ SdrObject* pMaxObj=GetMaxToTopObj(pObj);
+ if (pMaxObj!=nullptr)
+ {
+ size_t nMaxPos=pMaxObj->GetOrdNum();
+ if (nMaxPos!=0)
+ nMaxPos--;
+ if (nNewPos>nMaxPos)
+ nNewPos=nMaxPos; // neither go faster...
+ if (nNewPos<nNowPos)
+ nNewPos=nNowPos; // nor go in the other direction
+ }
+ bool bEnd=false;
+ while (nCmpPos<nNewPos && !bEnd)
+ {
+ SdrObject* pCmpObj=pOL->GetObj(nCmpPos);
+ if (pCmpObj==nullptr)
+ {
+ OSL_FAIL("MovMarkedToTop(): Reference object not found.");
+ bEnd=true;
+ }
+ else if (pCmpObj==pMaxObj)
+ {
+ nNewPos=nCmpPos;
+ nNewPos--;
+ bEnd=true;
+ }
+ else if (rBR.Overlaps(pCmpObj->GetCurrentBoundRect()))
+ {
+ nNewPos=nCmpPos;
+ bEnd=true;
+ }
+ else
+ {
+ nCmpPos++;
+ }
+ }
+ if (nNowPos!=nNewPos)
+ {
+ bChg=true;
+ pOL->SetObjectOrdNum(nNowPos,nNewPos);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
+ ObjOrderChanged(pObj,nNowPos,nNewPos);
+ }
+ nNewPos--;
+ }
+
+ if( bUndo )
+ EndUndo();
+
+ if (bChg)
+ MarkListHasChanged();
+}
+
+void SdrEditView::MovMarkedToBtm()
+{
+ const size_t nCount=GetMarkedObjectCount();
+ if (nCount==0)
+ return;
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditMovToBtm),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::MoveToBottom);
+
+ SortMarkedObjects();
+ for (size_t nm=0; nm<nCount; ++nm)
+ { // All Ordnums have to be correct!
+ GetMarkedObjectByIndex(nm)->GetOrdNum();
+ }
+
+ bool bChg=false;
+ SdrObjList* pOL0=nullptr;
+ size_t nNewPos=0;
+ for (size_t nm=0; nm<nCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ if (pOL!=pOL0)
+ {
+ nNewPos=0;
+ pOL0=pOL;
+ }
+ const size_t nNowPos = pObj->GetOrdNumDirect();
+ const tools::Rectangle& rBR=pObj->GetCurrentBoundRect();
+ size_t nCmpPos = nNowPos;
+ if (nCmpPos>0)
+ --nCmpPos;
+ SdrObject* pMaxObj=GetMaxToBtmObj(pObj);
+ if (pMaxObj!=nullptr)
+ {
+ const size_t nMinPos=pMaxObj->GetOrdNum()+1;
+ if (nNewPos<nMinPos)
+ nNewPos=nMinPos; // neither go faster...
+ if (nNewPos>nNowPos)
+ nNewPos=nNowPos; // nor go in the other direction
+ }
+ bool bEnd=false;
+ // nNewPos in this case is the "maximum" position
+ // the object may reach without going faster than the object before
+ // it (multiple selection).
+ while (nCmpPos>nNewPos && !bEnd)
+ {
+ SdrObject* pCmpObj=pOL->GetObj(nCmpPos);
+ if (pCmpObj==nullptr)
+ {
+ OSL_FAIL("MovMarkedToBtm(): Reference object not found.");
+ bEnd=true;
+ }
+ else if (pCmpObj==pMaxObj)
+ {
+ nNewPos=nCmpPos;
+ nNewPos++;
+ bEnd=true;
+ }
+ else if (rBR.Overlaps(pCmpObj->GetCurrentBoundRect()))
+ {
+ nNewPos=nCmpPos;
+ bEnd=true;
+ }
+ else
+ {
+ nCmpPos--;
+ }
+ }
+ if (nNowPos!=nNewPos)
+ {
+ bChg=true;
+ pOL->SetObjectOrdNum(nNowPos,nNewPos);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
+ ObjOrderChanged(pObj,nNowPos,nNewPos);
+ }
+ nNewPos++;
+ }
+
+ if(bUndo)
+ EndUndo();
+
+ if(bChg)
+ MarkListHasChanged();
+}
+
+void SdrEditView::PutMarkedToTop()
+{
+ PutMarkedInFrontOfObj(nullptr);
+}
+
+void SdrEditView::PutMarkedInFrontOfObj(const SdrObject* pRefObj)
+{
+ const size_t nCount=GetMarkedObjectCount();
+ if (nCount==0)
+ return;
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditPutToTop),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::PutToTop);
+
+ SortMarkedObjects();
+
+ if (pRefObj!=nullptr)
+ {
+ // Make "in front of the object" work, even if the
+ // selected objects are already in front of the other object
+ const size_t nRefMark=TryToFindMarkedObject(pRefObj);
+ SdrMark aRefMark;
+ if (nRefMark!=SAL_MAX_SIZE)
+ {
+ aRefMark=*GetSdrMarkByIndex(nRefMark);
+ GetMarkedObjectListWriteAccess().DeleteMark(nRefMark);
+ }
+ PutMarkedToBtm();
+ if (nRefMark!=SAL_MAX_SIZE)
+ {
+ GetMarkedObjectListWriteAccess().InsertEntry(aRefMark);
+ SortMarkedObjects();
+ }
+ }
+ for (size_t nm=0; nm<nCount; ++nm)
+ { // All Ordnums have to be correct!
+ GetMarkedObjectByIndex(nm)->GetOrdNum();
+ }
+ bool bChg=false;
+ SdrObjList* pOL0=nullptr;
+ size_t nNewPos=0;
+ for (size_t nm=nCount; nm>0;)
+ {
+ --nm;
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ if (pObj!=pRefObj)
+ {
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ if (pOL!=pOL0)
+ {
+ nNewPos=pOL->GetObjCount()-1;
+ pOL0=pOL;
+ }
+ const size_t nNowPos=pObj->GetOrdNumDirect();
+ SdrObject* pMaxObj=GetMaxToTopObj(pObj);
+ if (pMaxObj!=nullptr)
+ {
+ size_t nMaxOrd=pMaxObj->GetOrdNum(); // sadly doesn't work any other way
+ if (nMaxOrd>0)
+ nMaxOrd--;
+ if (nNewPos>nMaxOrd)
+ nNewPos=nMaxOrd; // neither go faster...
+ if (nNewPos<nNowPos)
+ nNewPos=nNowPos; // nor go into the other direction
+ }
+ if (pRefObj!=nullptr)
+ {
+ if (pRefObj->getParentSdrObjListFromSdrObject()==pObj->getParentSdrObjListFromSdrObject())
+ {
+ const size_t nMaxOrd=pRefObj->GetOrdNum(); // sadly doesn't work any other way
+ if (nNewPos>nMaxOrd)
+ nNewPos=nMaxOrd; // neither go faster...
+ if (nNewPos<nNowPos)
+ nNewPos=nNowPos; // nor go into the other direction
+ }
+ else
+ {
+ nNewPos=nNowPos; // different PageView, so don't change
+ }
+ }
+ if (nNowPos!=nNewPos)
+ {
+ bChg=true;
+ pOL->SetObjectOrdNum(nNowPos,nNewPos);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
+ ObjOrderChanged(pObj,nNowPos,nNewPos);
+ }
+ nNewPos--;
+ } // if (pObj!=pRefObj)
+ } // for loop over all selected objects
+
+ if( bUndo )
+ EndUndo();
+
+ if(bChg)
+ MarkListHasChanged();
+}
+
+void SdrEditView::PutMarkedToBtm()
+{
+ PutMarkedBehindObj(nullptr);
+}
+
+void SdrEditView::PutMarkedBehindObj(const SdrObject* pRefObj)
+{
+ const size_t nCount=GetMarkedObjectCount();
+ if (nCount==0)
+ return;
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditPutToBtm),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::PutToBottom);
+
+ SortMarkedObjects();
+ if (pRefObj!=nullptr)
+ {
+ // Make "behind the object" work, even if the
+ // selected objects are already behind the other object
+ const size_t nRefMark=TryToFindMarkedObject(pRefObj);
+ SdrMark aRefMark;
+ if (nRefMark!=SAL_MAX_SIZE)
+ {
+ aRefMark=*GetSdrMarkByIndex(nRefMark);
+ GetMarkedObjectListWriteAccess().DeleteMark(nRefMark);
+ }
+ PutMarkedToTop();
+ if (nRefMark!=SAL_MAX_SIZE)
+ {
+ GetMarkedObjectListWriteAccess().InsertEntry(aRefMark);
+ SortMarkedObjects();
+ }
+ }
+ for (size_t nm=0; nm<nCount; ++nm) { // All Ordnums have to be correct!
+ GetMarkedObjectByIndex(nm)->GetOrdNum();
+ }
+ bool bChg=false;
+ SdrObjList* pOL0=nullptr;
+ size_t nNewPos=0;
+ for (size_t nm=0; nm<nCount; ++nm) {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ if (pObj!=pRefObj) {
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ if (pOL!=pOL0) {
+ nNewPos=0;
+ pOL0=pOL;
+ }
+ const size_t nNowPos=pObj->GetOrdNumDirect();
+ SdrObject* pMinObj=GetMaxToBtmObj(pObj);
+ if (pMinObj!=nullptr) {
+ const size_t nMinOrd=pMinObj->GetOrdNum()+1; // sadly doesn't work any differently
+ if (nNewPos<nMinOrd) nNewPos=nMinOrd; // neither go faster...
+ if (nNewPos>nNowPos) nNewPos=nNowPos; // nor go into the other direction
+ }
+ if (pRefObj!=nullptr) {
+ if (pRefObj->getParentSdrObjListFromSdrObject()==pObj->getParentSdrObjListFromSdrObject()) {
+ const size_t nMinOrd=pRefObj->GetOrdNum(); // sadly doesn't work any differently
+ if (nNewPos<nMinOrd) nNewPos=nMinOrd; // neither go faster...
+ if (nNewPos>nNowPos) nNewPos=nNowPos; // nor go into the other direction
+ } else {
+ nNewPos=nNowPos; // different PageView, so don't change
+ }
+ }
+ if (nNowPos!=nNewPos) {
+ bChg=true;
+ pOL->SetObjectOrdNum(nNowPos,nNewPos);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
+ ObjOrderChanged(pObj,nNowPos,nNewPos);
+ }
+ nNewPos++;
+ } // if (pObj!=pRefObj)
+ } // for loop over all selected objects
+
+ if(bUndo)
+ EndUndo();
+
+ if(bChg)
+ MarkListHasChanged();
+
+}
+
+void SdrEditView::ReverseOrderOfMarked()
+{
+ SortMarkedObjects();
+ const size_t nMarkCount=GetMarkedObjectCount();
+ if (nMarkCount<=0)
+ return;
+
+ bool bChg=false;
+
+ bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditRevOrder),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::ReverseOrder);
+
+ size_t a=0;
+ do {
+ // take into account selection across multiple PageViews
+ size_t b=a+1;
+ while (b<nMarkCount && GetSdrPageViewOfMarkedByIndex(b) == GetSdrPageViewOfMarkedByIndex(a)) ++b;
+ --b;
+ SdrObjList* pOL=GetSdrPageViewOfMarkedByIndex(a)->GetObjList();
+ size_t c=b;
+ if (a<c) { // make sure OrdNums aren't dirty
+ GetMarkedObjectByIndex(a)->GetOrdNum();
+ }
+ while (a<c) {
+ SdrObject* pObj1=GetMarkedObjectByIndex(a);
+ SdrObject* pObj2=GetMarkedObjectByIndex(c);
+ const size_t nOrd1=pObj1->GetOrdNumDirect();
+ const size_t nOrd2=pObj2->GetOrdNumDirect();
+ if( bUndo )
+ {
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj1,nOrd1,nOrd2));
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj2,nOrd2-1,nOrd1));
+ }
+ pOL->SetObjectOrdNum(nOrd1,nOrd2);
+ // Obj 2 has moved forward by one position, so now nOrd2-1
+ pOL->SetObjectOrdNum(nOrd2-1,nOrd1);
+ // use Replace instead of SetOrdNum for performance reasons (recalculation of Ordnums)
+ ++a;
+ --c;
+ bChg=true;
+ }
+ a=b+1;
+ } while (a<nMarkCount);
+
+ if(bUndo)
+ EndUndo();
+
+ if(bChg)
+ MarkListHasChanged();
+}
+
+void SdrEditView::ImpCheckToTopBtmPossible()
+{
+ const size_t nCount=GetMarkedObjectCount();
+ if (nCount==0)
+ return;
+ if (nCount==1)
+ { // special-casing for single selection
+ SdrObject* pObj=GetMarkedObjectByIndex(0);
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ SAL_WARN_IF(!pOL, "svx", "Object somehow has no ObjList");
+ size_t nMax = pOL ? pOL->GetObjCount() : 0;
+ size_t nMin = 0;
+ const size_t nObjNum=pObj->GetOrdNum();
+ SdrObject* pRestrict=GetMaxToTopObj(pObj);
+ if (pRestrict!=nullptr) {
+ const size_t nRestrict=pRestrict->GetOrdNum();
+ if (nRestrict<nMax) nMax=nRestrict;
+ }
+ pRestrict=GetMaxToBtmObj(pObj);
+ if (pRestrict!=nullptr) {
+ const size_t nRestrict=pRestrict->GetOrdNum();
+ if (nRestrict>nMin) nMin=nRestrict;
+ }
+ m_bToTopPossible=nObjNum<nMax-1;
+ m_bToBtmPossible=nObjNum>nMin;
+ } else { // multiple selection
+ SdrObjList* pOL0=nullptr;
+ size_t nPos0 = 0;
+ for (size_t nm = 0; !m_bToBtmPossible && nm<nCount; ++nm) { // check 'send to background'
+ SdrObject* pObj=GetMarkedObjectByIndex(nm);
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ if (pOL!=pOL0) {
+ nPos0 = 0;
+ pOL0=pOL;
+ }
+ const size_t nPos = pObj->GetOrdNum();
+ m_bToBtmPossible = nPos && (nPos-1 > nPos0);
+ nPos0 = nPos;
+ }
+
+ pOL0=nullptr;
+ nPos0 = SAL_MAX_SIZE;
+ for (size_t nm=nCount; !m_bToTopPossible && nm>0; ) { // check 'bring to front'
+ --nm;
+ SdrObject* pObj=GetMarkedObjectByIndex(nm);
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ if (pOL!=pOL0) {
+ nPos0=pOL->GetObjCount();
+ pOL0=pOL;
+ }
+ const size_t nPos = pObj->GetOrdNum();
+ m_bToTopPossible = nPos+1 < nPos0;
+ nPos0=nPos;
+ }
+ }
+}
+
+
+// Combine
+
+
+void SdrEditView::ImpCopyAttributes(const SdrObject* pSource, SdrObject* pDest) const
+{
+ if (pSource!=nullptr) {
+ SdrObjList* pOL=pSource->GetSubList();
+ if (pOL!=nullptr && !pSource->Is3DObj()) { // get first non-group object from group
+ SdrObjListIter aIter(pOL,SdrIterMode::DeepNoGroups);
+ pSource=aIter.Next();
+ }
+ }
+
+ if(!(pSource && pDest))
+ return;
+
+ SfxItemSetFixed<SDRATTR_START, SDRATTR_NOTPERSIST_FIRST-1,
+ SDRATTR_NOTPERSIST_LAST+1, SDRATTR_END,
+ EE_ITEMS_START, EE_ITEMS_END> aSet(mpModel->GetItemPool());
+
+ aSet.Put(pSource->GetMergedItemSet());
+
+ pDest->ClearMergedItem();
+ pDest->SetMergedItemSet(aSet);
+
+ pDest->NbcSetLayer(pSource->GetLayer());
+ pDest->NbcSetStyleSheet(pSource->GetStyleSheet(), true);
+}
+
+bool SdrEditView::ImpCanConvertForCombine1(const SdrObject* pObj)
+{
+ // new condition IsLine() to be able to combine simple Lines
+ bool bIsLine(false);
+
+ const SdrPathObj* pPath = dynamic_cast< const SdrPathObj*>( pObj );
+
+ if(pPath)
+ {
+ bIsLine = pPath->IsLine();
+ }
+
+ SdrObjTransformInfoRec aInfo;
+ pObj->TakeObjInfo(aInfo);
+
+ return (aInfo.bCanConvToPath || aInfo.bCanConvToPoly || bIsLine);
+}
+
+bool SdrEditView::ImpCanConvertForCombine(const SdrObject* pObj)
+{
+ SdrObjList* pOL = pObj->GetSubList();
+
+ if(pOL && !pObj->Is3DObj())
+ {
+ SdrObjListIter aIter(pOL, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pObj1 = aIter.Next();
+
+ // all members of a group have to be convertible
+ if(!ImpCanConvertForCombine1(pObj1))
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if(!ImpCanConvertForCombine1(pObj))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+basegfx::B2DPolyPolygon SdrEditView::ImpGetPolyPolygon1(const SdrObject* pObj)
+{
+ basegfx::B2DPolyPolygon aRetval;
+ const SdrPathObj* pPath = dynamic_cast<const SdrPathObj*>( pObj );
+
+ if(pPath && !pObj->GetOutlinerParaObject())
+ {
+ aRetval = pPath->GetPathPoly();
+ }
+ else
+ {
+ SdrObjectUniquePtr pConvObj = pObj->ConvertToPolyObj(true/*bCombine*/, false);
+
+ if(pConvObj)
+ {
+ SdrObjList* pOL = pConvObj->GetSubList();
+
+ if(pOL)
+ {
+ SdrObjListIter aIter(pOL, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pObj1 = aIter.Next();
+ pPath = dynamic_cast<SdrPathObj*>( pObj1 );
+
+ if(pPath)
+ {
+ aRetval.append(pPath->GetPathPoly());
+ }
+ }
+ }
+ else
+ {
+ pPath = dynamic_cast<SdrPathObj*>( pConvObj.get() );
+
+ if(pPath)
+ {
+ aRetval = pPath->GetPathPoly();
+ }
+ }
+ }
+ }
+
+ return aRetval;
+}
+
+basegfx::B2DPolyPolygon SdrEditView::ImpGetPolyPolygon(const SdrObject* pObj)
+{
+ SdrObjList* pOL = pObj->GetSubList();
+
+ if(pOL && !pObj->Is3DObj())
+ {
+ basegfx::B2DPolyPolygon aRetval;
+ SdrObjListIter aIter(pOL, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pObj1 = aIter.Next();
+ aRetval.append(ImpGetPolyPolygon1(pObj1));
+ }
+
+ return aRetval;
+ }
+ else
+ {
+ return ImpGetPolyPolygon1(pObj);
+ }
+}
+
+basegfx::B2DPolygon SdrEditView::ImpCombineToSinglePolygon(const basegfx::B2DPolyPolygon& rPolyPolygon)
+{
+ const sal_uInt32 nPolyCount(rPolyPolygon.count());
+
+ if(0 == nPolyCount)
+ {
+ return basegfx::B2DPolygon();
+ }
+ else if(1 == nPolyCount)
+ {
+ return rPolyPolygon.getB2DPolygon(0);
+ }
+ else
+ {
+ basegfx::B2DPolygon aRetval(rPolyPolygon.getB2DPolygon(0));
+
+ for(sal_uInt32 a(1); a < nPolyCount; a++)
+ {
+ basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a));
+
+ if(aRetval.count())
+ {
+ if(aCandidate.count())
+ {
+ const basegfx::B2DPoint aCA(aCandidate.getB2DPoint(0));
+ const basegfx::B2DPoint aCB(aCandidate.getB2DPoint(aCandidate.count() - 1));
+ const basegfx::B2DPoint aRA(aRetval.getB2DPoint(0));
+ const basegfx::B2DPoint aRB(aRetval.getB2DPoint(aRetval.count() - 1));
+
+ const double fRACA(basegfx::B2DVector(aCA - aRA).getLength());
+ const double fRACB(basegfx::B2DVector(aCB - aRA).getLength());
+ const double fRBCA(basegfx::B2DVector(aCA - aRB).getLength());
+ const double fRBCB(basegfx::B2DVector(aCB - aRB).getLength());
+
+ const double fSmallestRA(std::min(fRACA, fRACB));
+ const double fSmallestRB(std::min(fRBCA, fRBCB));
+
+ if(fSmallestRA < fSmallestRB)
+ {
+ // flip result
+ aRetval.flip();
+ }
+
+ const double fSmallestCA(std::min(fRACA, fRBCA));
+ const double fSmallestCB(std::min(fRACB, fRBCB));
+
+ if(fSmallestCB < fSmallestCA)
+ {
+ // flip candidate
+ aCandidate.flip();
+ }
+
+ // append candidate to retval
+ aRetval.append(aCandidate);
+ }
+ }
+ else
+ {
+ aRetval = aCandidate;
+ }
+ }
+
+ return aRetval;
+ }
+}
+
+namespace {
+
+// for distribution dialog function
+struct ImpDistributeEntry
+{
+ SdrObject* mpObj;
+ sal_Int32 mnPos;
+ sal_Int32 mnLength;
+};
+
+}
+
+typedef std::vector<ImpDistributeEntry> ImpDistributeEntryList;
+
+void SdrEditView::DistributeMarkedObjects(sal_uInt16 SlotID)
+{
+ const size_t nMark(GetMarkedObjectCount());
+
+ if(nMark <= 2)
+ return;
+
+ SvxDistributeHorizontal eHor = SvxDistributeHorizontal::NONE;
+ SvxDistributeVertical eVer = SvxDistributeVertical::NONE;
+
+ switch (SlotID)
+ {
+ case SID_DISTRIBUTE_HLEFT: eHor = SvxDistributeHorizontal::Left; break;
+ case SID_DISTRIBUTE_HCENTER: eHor = SvxDistributeHorizontal::Center; break;
+ case SID_DISTRIBUTE_HDISTANCE: eHor = SvxDistributeHorizontal::Distance; break;
+ case SID_DISTRIBUTE_HRIGHT: eHor = SvxDistributeHorizontal::Right; break;
+ case SID_DISTRIBUTE_VTOP: eVer = SvxDistributeVertical::Top; break;
+ case SID_DISTRIBUTE_VCENTER: eVer = SvxDistributeVertical::Center; break;
+ case SID_DISTRIBUTE_VDISTANCE: eVer = SvxDistributeVertical::Distance; break;
+ case SID_DISTRIBUTE_VBOTTOM: eVer = SvxDistributeVertical::Bottom; break;
+ }
+
+ ImpDistributeEntryList aEntryList;
+ ImpDistributeEntryList::iterator itEntryList;
+ sal_uInt32 nFullLength;
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo();
+
+ if(eHor != SvxDistributeHorizontal::NONE)
+ {
+ // build sorted entry list
+ nFullLength = 0;
+
+ for( size_t a = 0; a < nMark; ++a )
+ {
+ SdrMark* pMark = GetSdrMarkByIndex(a);
+ ImpDistributeEntry aNew;
+
+ aNew.mpObj = pMark->GetMarkedSdrObj();
+
+ switch(eHor)
+ {
+ case SvxDistributeHorizontal::Left:
+ {
+ aNew.mnPos = aNew.mpObj->GetSnapRect().Left();
+ break;
+ }
+ case SvxDistributeHorizontal::Center:
+ {
+ aNew.mnPos = (aNew.mpObj->GetSnapRect().Right() + aNew.mpObj->GetSnapRect().Left()) / 2;
+ break;
+ }
+ case SvxDistributeHorizontal::Distance:
+ {
+ aNew.mnLength = aNew.mpObj->GetSnapRect().GetWidth() + 1;
+ nFullLength += aNew.mnLength;
+ aNew.mnPos = (aNew.mpObj->GetSnapRect().Right() + aNew.mpObj->GetSnapRect().Left()) / 2;
+ break;
+ }
+ case SvxDistributeHorizontal::Right:
+ {
+ aNew.mnPos = aNew.mpObj->GetSnapRect().Right();
+ break;
+ }
+ default: break;
+ }
+
+ itEntryList = std::find_if(aEntryList.begin(), aEntryList.end(),
+ [&aNew](const ImpDistributeEntry& rEntry) { return rEntry.mnPos >= aNew.mnPos; });
+ if ( itEntryList < aEntryList.end() )
+ aEntryList.insert( itEntryList, aNew );
+ else
+ aEntryList.push_back( aNew );
+ }
+
+ if(eHor == SvxDistributeHorizontal::Distance)
+ {
+ // calculate room in-between
+ sal_Int32 nWidth = GetAllMarkedBoundRect().GetWidth() + 1;
+ double fStepWidth = (static_cast<double>(nWidth) - static_cast<double>(nFullLength)) / static_cast<double>(aEntryList.size() - 1);
+ double fStepStart = static_cast<double>(aEntryList[ 0 ].mnPos);
+ fStepStart += fStepWidth + static_cast<double>((aEntryList[ 0 ].mnLength + aEntryList[ 1 ].mnLength) / 2);
+
+ // move entries 1..n-1
+ for( size_t i = 1, n = aEntryList.size()-1; i < n; ++i )
+ {
+ ImpDistributeEntry& rCurr = aEntryList[ i ];
+ ImpDistributeEntry& rNext = aEntryList[ i + 1];
+ sal_Int32 nDelta = static_cast<sal_Int32>(fStepStart + 0.5) - rCurr.mnPos;
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*rCurr.mpObj));
+ rCurr.mpObj->Move(Size(nDelta, 0));
+ fStepStart += fStepWidth + static_cast<double>((rCurr.mnLength + rNext.mnLength) / 2);
+ }
+ }
+ else
+ {
+ // calculate distances
+ sal_Int32 nWidth = aEntryList[ aEntryList.size() - 1 ].mnPos - aEntryList[ 0 ].mnPos;
+ double fStepWidth = static_cast<double>(nWidth) / static_cast<double>(aEntryList.size() - 1);
+ double fStepStart = static_cast<double>(aEntryList[ 0 ].mnPos);
+ fStepStart += fStepWidth;
+
+ // move entries 1..n-1
+ for( size_t i = 1 ; i < aEntryList.size()-1 ; ++i )
+ {
+ ImpDistributeEntry& rCurr = aEntryList[ i ];
+ sal_Int32 nDelta = static_cast<sal_Int32>(fStepStart + 0.5) - rCurr.mnPos;
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*rCurr.mpObj));
+ rCurr.mpObj->Move(Size(nDelta, 0));
+ fStepStart += fStepWidth;
+ }
+ }
+
+ // clear list
+ aEntryList.clear();
+ }
+
+ if(eVer != SvxDistributeVertical::NONE)
+ {
+ // build sorted entry list
+ nFullLength = 0;
+
+ for( size_t a = 0; a < nMark; ++a )
+ {
+ SdrMark* pMark = GetSdrMarkByIndex(a);
+ ImpDistributeEntry aNew;
+
+ aNew.mpObj = pMark->GetMarkedSdrObj();
+
+ switch(eVer)
+ {
+ case SvxDistributeVertical::Top:
+ {
+ aNew.mnPos = aNew.mpObj->GetSnapRect().Top();
+ break;
+ }
+ case SvxDistributeVertical::Center:
+ {
+ aNew.mnPos = (aNew.mpObj->GetSnapRect().Bottom() + aNew.mpObj->GetSnapRect().Top()) / 2;
+ break;
+ }
+ case SvxDistributeVertical::Distance:
+ {
+ aNew.mnLength = aNew.mpObj->GetSnapRect().GetHeight() + 1;
+ nFullLength += aNew.mnLength;
+ aNew.mnPos = (aNew.mpObj->GetSnapRect().Bottom() + aNew.mpObj->GetSnapRect().Top()) / 2;
+ break;
+ }
+ case SvxDistributeVertical::Bottom:
+ {
+ aNew.mnPos = aNew.mpObj->GetSnapRect().Bottom();
+ break;
+ }
+ default: break;
+ }
+
+ itEntryList = std::find_if(aEntryList.begin(), aEntryList.end(),
+ [&aNew](const ImpDistributeEntry& rEntry) { return rEntry.mnPos >= aNew.mnPos; });
+ if ( itEntryList < aEntryList.end() )
+ aEntryList.insert( itEntryList, aNew );
+ else
+ aEntryList.push_back( aNew );
+ }
+
+ if(eVer == SvxDistributeVertical::Distance)
+ {
+ // calculate room in-between
+ sal_Int32 nHeight = GetAllMarkedBoundRect().GetHeight() + 1;
+ double fStepWidth = (static_cast<double>(nHeight) - static_cast<double>(nFullLength)) / static_cast<double>(aEntryList.size() - 1);
+ double fStepStart = static_cast<double>(aEntryList[ 0 ].mnPos);
+ fStepStart += fStepWidth + static_cast<double>((aEntryList[ 0 ].mnLength + aEntryList[ 1 ].mnLength) / 2);
+
+ // move entries 1..n-1
+ for( size_t i = 1, n = aEntryList.size()-1; i < n; ++i)
+ {
+ ImpDistributeEntry& rCurr = aEntryList[ i ];
+ ImpDistributeEntry& rNext = aEntryList[ i + 1 ];
+ sal_Int32 nDelta = static_cast<sal_Int32>(fStepStart + 0.5) - rCurr.mnPos;
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*rCurr.mpObj));
+ rCurr.mpObj->Move(Size(0, nDelta));
+ fStepStart += fStepWidth + static_cast<double>((rCurr.mnLength + rNext.mnLength) / 2);
+ }
+ }
+ else
+ {
+ // calculate distances
+ sal_Int32 nHeight = aEntryList[ aEntryList.size() - 1 ].mnPos - aEntryList[ 0 ].mnPos;
+ double fStepWidth = static_cast<double>(nHeight) / static_cast<double>(aEntryList.size() - 1);
+ double fStepStart = static_cast<double>(aEntryList[ 0 ].mnPos);
+ fStepStart += fStepWidth;
+
+ // move entries 1..n-1
+ for(size_t i = 1, n = aEntryList.size()-1; i < n; ++i)
+ {
+ ImpDistributeEntry& rCurr = aEntryList[ i ];
+ sal_Int32 nDelta = static_cast<sal_Int32>(fStepStart + 0.5) - rCurr.mnPos;
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*rCurr.mpObj));
+ rCurr.mpObj->Move(Size(0, nDelta));
+ fStepStart += fStepWidth;
+ }
+ }
+
+ // clear list
+ aEntryList.clear();
+ }
+
+ // UNDO-Comment and end of UNDO
+ mpModel->SetUndoComment(SvxResId(STR_DistributeMarkedObjects));
+
+ if( bUndo )
+ EndUndo();
+}
+
+void SdrEditView::MergeMarkedObjects(SdrMergeMode eMode)
+{
+ // #i73441# check content
+ if(!AreObjectsMarked())
+ return;
+
+ SdrMarkList aRemove;
+ SortMarkedObjects();
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo();
+
+ size_t nInsPos = SAL_MAX_SIZE;
+ const SdrObject* pAttrObj = nullptr;
+ basegfx::B2DPolyPolygon aMergePolyPolygonA;
+ basegfx::B2DPolyPolygon aMergePolyPolygonB;
+
+ SdrObjList* pInsOL = nullptr;
+ SdrPageView* pInsPV = nullptr;
+ bool bFirstObjectComplete(false);
+
+ // make sure selected objects are contour objects
+ // since now basegfx::utils::adaptiveSubdivide() is used, it is no longer
+ // necessary to use ConvertMarkedToPolyObj which will subdivide curves using the old
+ // mechanisms. In a next step the polygon clipper will even be able to clip curves...
+ // ConvertMarkedToPolyObj(true);
+ ConvertMarkedToPathObj(true);
+ OSL_ENSURE(AreObjectsMarked(), "no more objects selected after preparations (!)");
+
+ for(size_t a=0; a<GetMarkedObjectCount(); ++a)
+ {
+ SdrMark* pM = GetSdrMarkByIndex(a);
+ SdrObject* pObj = pM->GetMarkedSdrObj();
+
+ if(ImpCanConvertForCombine(pObj))
+ {
+ if(!pAttrObj)
+ pAttrObj = pObj;
+
+ nInsPos = pObj->GetOrdNum() + 1;
+ pInsPV = pM->GetPageView();
+ pInsOL = pObj->getParentSdrObjListFromSdrObject();
+
+ // #i76891# use single iteration from SJ here which works on SdrObjects and takes
+ // groups into account by itself
+ SdrObjListIter aIter(*pObj, SdrIterMode::DeepWithGroups);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pCandidate = aIter.Next();
+ SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>( pCandidate );
+ if(pPathObj)
+ {
+ basegfx::B2DPolyPolygon aTmpPoly(pPathObj->GetPathPoly());
+
+ // #i76891# unfortunately ConvertMarkedToPathObj has converted all
+ // involved polygon data to curve segments, even if not necessary.
+ // It is better to try to reduce to more simple polygons.
+ aTmpPoly = basegfx::utils::simplifyCurveSegments(aTmpPoly);
+
+ // for each part polygon as preparation, remove self-intersections
+ // correct orientations and get rid of possible neutral polygons.
+ aTmpPoly = basegfx::utils::prepareForPolygonOperation(aTmpPoly);
+
+ if(!bFirstObjectComplete)
+ {
+ // #i111987# Also need to collect ORed source shape when more than
+ // a single polygon is involved
+ if(aMergePolyPolygonA.count())
+ {
+ aMergePolyPolygonA = basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonA, aTmpPoly);
+ }
+ else
+ {
+ aMergePolyPolygonA = aTmpPoly;
+ }
+ }
+ else
+ {
+ if(aMergePolyPolygonB.count())
+ {
+ // to topologically correctly collect the 2nd polygon
+ // group it is necessary to OR the parts (each is seen as
+ // XOR-FillRule polygon and they are drawn over each-other)
+ aMergePolyPolygonB = basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonB, aTmpPoly);
+ }
+ else
+ {
+ aMergePolyPolygonB = aTmpPoly;
+ }
+ }
+ }
+ }
+
+ // was there something added to the first polygon?
+ if(!bFirstObjectComplete && aMergePolyPolygonA.count())
+ {
+ bFirstObjectComplete = true;
+ }
+
+ // move object to temporary delete list
+ aRemove.InsertEntry(SdrMark(pObj, pM->GetPageView()));
+ }
+ }
+
+ switch(eMode)
+ {
+ case SdrMergeMode::Merge:
+ {
+ // merge all contained parts (OR)
+ aMergePolyPolygonA = basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonA, aMergePolyPolygonB);
+ break;
+ }
+ case SdrMergeMode::Subtract:
+ {
+ // Subtract B from A
+ aMergePolyPolygonA = basegfx::utils::solvePolygonOperationDiff(aMergePolyPolygonA, aMergePolyPolygonB);
+ break;
+ }
+ case SdrMergeMode::Intersect:
+ {
+ // AND B and A
+ aMergePolyPolygonA = basegfx::utils::solvePolygonOperationAnd(aMergePolyPolygonA, aMergePolyPolygonB);
+ break;
+ }
+ }
+
+ // #i73441# check insert list before taking actions
+ if(pInsOL)
+ {
+ SdrPathObj* pPath = new SdrPathObj(pAttrObj->getSdrModelFromSdrObject(), SdrObjKind::PathFill, aMergePolyPolygonA);
+ ImpCopyAttributes(pAttrObj, pPath);
+ pInsOL->InsertObject(pPath, nInsPos);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath));
+
+ // #i124760# To have a correct selection with only the new object it is necessary to
+ // unmark all objects first. If not doing so, there may remain invalid pointers to objects
+ // TTTT:Not needed for aw080 (!)
+ UnmarkAllObj(pInsPV);
+
+ MarkObj(pPath, pInsPV, false, true);
+ }
+
+ aRemove.ForceSort();
+ switch(eMode)
+ {
+ case SdrMergeMode::Merge:
+ {
+ SetUndoComment(
+ SvxResId(STR_EditMergeMergePoly),
+ aRemove.GetMarkDescription());
+ break;
+ }
+ case SdrMergeMode::Subtract:
+ {
+ SetUndoComment(
+ SvxResId(STR_EditMergeSubstractPoly),
+ aRemove.GetMarkDescription());
+ break;
+ }
+ case SdrMergeMode::Intersect:
+ {
+ SetUndoComment(
+ SvxResId(STR_EditMergeIntersectPoly),
+ aRemove.GetMarkDescription());
+ break;
+ }
+ }
+ DeleteMarkedList(aRemove);
+
+ if( bUndo )
+ EndUndo();
+}
+
+void SdrEditView::EqualizeMarkedObjects(bool bWidth)
+{
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ size_t nMarked = rMarkList.GetMarkCount();
+
+ if (nMarked < 2)
+ return;
+
+ size_t nLastSelected = 0;
+ sal_Int64 nLastSelectedTime = rMarkList.GetMark(0)->getTimeStamp();
+ for (size_t a = 1; a < nMarked; ++a)
+ {
+ sal_Int64 nCandidateTime = rMarkList.GetMark(a)->getTimeStamp();
+ if (nCandidateTime > nLastSelectedTime)
+ {
+ nLastSelectedTime = nCandidateTime;
+ nLastSelected = a;
+ }
+ }
+
+ SdrObject* pLastSelectedObj = rMarkList.GetMark(nLastSelected)->GetMarkedSdrObj();
+ Size aLastRectSize(pLastSelectedObj->GetLogicRect().GetSize());
+
+ const bool bUndo = IsUndoEnabled();
+
+ if (bUndo)
+ BegUndo();
+
+ for (size_t a = 0; a < nMarked; ++a)
+ {
+ if (a == nLastSelected)
+ continue;
+ SdrMark* pM = rMarkList.GetMark(a);
+ SdrObject* pObj = pM->GetMarkedSdrObj();
+ tools::Rectangle aLogicRect(pObj->GetLogicRect());
+ Size aLogicRectSize(aLogicRect.GetSize());
+ if (bWidth)
+ aLogicRectSize.setWidth( aLastRectSize.Width() );
+ else
+ aLogicRectSize.setHeight( aLastRectSize.Height() );
+ aLogicRect.SetSize(aLogicRectSize);
+ if (bUndo)
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+ pObj->SetLogicRect(aLogicRect);
+ }
+
+ SetUndoComment(
+ SvxResId(bWidth ? STR_EqualizeWidthMarkedObjects : STR_EqualizeHeightMarkedObjects),
+ rMarkList.GetMarkDescription());
+
+ if (bUndo)
+ EndUndo();
+}
+
+void SdrEditView::CombineMarkedTextObjects()
+{
+ SdrPageView* pPageView = GetSdrPageView();
+ if ( !pPageView || pPageView->IsLayerLocked( GetActiveLayer() ) )
+ return;
+
+ bool bUndo = IsUndoEnabled();
+
+ // Undo-String will be set later
+ if ( bUndo )
+ BegUndo();
+
+ SdrOutliner& rDrawOutliner = getSdrModelFromSdrView().GetDrawOutliner();
+
+ SdrObjListIter aIter( GetMarkedObjectList(), SdrIterMode::Flat);
+ while ( aIter.IsMore() )
+ {
+ SdrObject* pObj = aIter.Next();
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( pObj );
+ const OutlinerParaObject* pOPO = pTextObj ? pTextObj->GetOutlinerParaObject() : nullptr;
+ if ( pOPO && pTextObj->IsTextFrame()
+ && pTextObj->GetObjIdentifier() == SdrObjKind::Text // not callouts (OBJ_CAPTION)
+ && !pTextObj->IsOutlText() // not impress presentation objects
+ && pTextObj->GetMergedItem(XATTR_FORMTXTSTYLE).GetValue() == XFormTextStyle::NONE // not Fontwork
+ )
+ {
+ // if the last paragraph does not end in paragraph-end punctuation (ignoring whitespace),
+ // assume this text should be added to the end of the last paragraph, instead of starting a new paragraph.
+ const sal_Int32 nPara = rDrawOutliner.GetParagraphCount();
+ const OUString sLastPara = nPara ? rDrawOutliner.GetText( rDrawOutliner.GetParagraph( nPara - 1 ) ) : "";
+ sal_Int32 n = sLastPara.getLength();
+ while ( n && unicode::isWhiteSpace( sLastPara[--n] ) )
+ ;
+ //TODO: find way to use Locale to identify sentence final punctuation. Copied IsSentenceAtEnd() from autofmt.cxx
+ const bool bAppend = !n || ( sLastPara[n] != '.' && sLastPara[n] != '?' && sLastPara[n] != '!' );
+ rDrawOutliner.AddText( *pOPO, bAppend );
+ }
+ else
+ {
+ // Unmark non-textboxes, because all marked objects are deleted at the end. AdjustMarkHdl later.
+ MarkObj(pObj, pPageView, /*bUnmark=*/true, /*bImpNoSetMarkHdl=*/true);
+ }
+ }
+
+ MarkListHasChanged();
+ AdjustMarkHdl();
+
+ if ( GetMarkedObjectCount() > 1 )
+ {
+ SdrRectObj* pReplacement = new SdrRectObj( getSdrModelFromSdrView(), SdrObjKind::Text );
+ pReplacement->SetOutlinerParaObject( rDrawOutliner.CreateParaObject() );
+ pReplacement->SetSnapRect( GetMarkedObjRect() );
+
+ const SdrInsertFlags nFlags = SdrInsertFlags::DONTMARK | SdrInsertFlags::SETDEFLAYER;
+ if ( InsertObjectAtView( pReplacement, *pPageView, nFlags ) )
+ DeleteMarkedObj();
+ }
+
+ if ( bUndo )
+ EndUndo();
+
+ return;
+}
+
+void SdrEditView::CombineMarkedObjects(bool bNoPolyPoly)
+{
+ // #105899# Start of Combine-Undo put to front, else ConvertMarkedToPolyObj would
+ // create a 2nd Undo-action and Undo-Comment.
+
+ bool bUndo = IsUndoEnabled();
+
+ // Undo-String will be set later
+ if( bUndo )
+ BegUndo("", "", bNoPolyPoly ? SdrRepeatFunc::CombineOnePoly : SdrRepeatFunc::CombinePolyPoly);
+
+ // #105899# First, guarantee that all objects are converted to polyobjects,
+ // especially for SdrGrafObj with bitmap filling this is necessary to not
+ // lose the bitmap filling.
+
+ // #i12392#
+ // ConvertMarkedToPolyObj was too strong here, it will lose quality and
+ // information when curve objects are combined. This can be replaced by
+ // using ConvertMarkedToPathObj without changing the previous fix.
+
+ // #i21250#
+ // Instead of simply passing true as LineToArea, use bNoPolyPoly as info
+ // if this command is a 'Combine' or a 'Connect' command. On Connect it's true.
+ // To not concert line segments with a set line width to polygons in that case,
+ // use this info. Do not convert LineToArea on Connect commands.
+ // ConvertMarkedToPathObj(!bNoPolyPoly);
+
+ // This is used for Combine and Connect. In no case it is necessary to force
+ // the content to curve, but it is also not good to force to polygons. Thus,
+ // curve is the less information losing one. Remember: This place is not
+ // used for merge.
+ // LineToArea is never necessary, both commands are able to take over the
+ // set line style and to display it correctly. Thus, i will use a
+ // ConvertMarkedToPathObj with a false in any case. Only drawback is that
+ // simple polygons will be changed to curves, but with no information loss.
+ ConvertMarkedToPathObj(false /* bLineToArea */);
+
+ // continue as before
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ SdrObjList* pCurrentOL = nullptr;
+ SdrMarkList aRemoveBuffer;
+
+ SortMarkedObjects();
+ size_t nInsPos = SAL_MAX_SIZE;
+ SdrObjList* pInsOL = nullptr;
+ SdrPageView* pInsPV = nullptr;
+ const SdrObject* pAttrObj = nullptr;
+
+ for(size_t a = GetMarkedObjectCount(); a; )
+ {
+ --a;
+ SdrMark* pM = GetSdrMarkByIndex(a);
+ SdrObject* pObj = pM->GetMarkedSdrObj();
+ SdrObjList* pThisOL = pObj->getParentSdrObjListFromSdrObject();
+
+ if(pCurrentOL != pThisOL)
+ {
+ pCurrentOL = pThisOL;
+ }
+
+ if(ImpCanConvertForCombine(pObj))
+ {
+ // remember objects to be able to copy attributes
+ pAttrObj = pObj;
+
+ // unfortunately ConvertMarkedToPathObj has converted all
+ // involved polygon data to curve segments, even if not necessary.
+ // It is better to try to reduce to more simple polygons.
+ basegfx::B2DPolyPolygon aTmpPoly(basegfx::utils::simplifyCurveSegments(ImpGetPolyPolygon(pObj)));
+ aPolyPolygon.insert(0, aTmpPoly);
+
+ if(!pInsOL)
+ {
+ nInsPos = pObj->GetOrdNum() + 1;
+ pInsPV = pM->GetPageView();
+ pInsOL = pObj->getParentSdrObjListFromSdrObject();
+ }
+
+ aRemoveBuffer.InsertEntry(SdrMark(pObj, pM->GetPageView()));
+ }
+ }
+
+ if(bNoPolyPoly)
+ {
+ basegfx::B2DPolygon aCombinedPolygon(ImpCombineToSinglePolygon(aPolyPolygon));
+ aPolyPolygon.clear();
+ aPolyPolygon.append(aCombinedPolygon);
+ }
+
+ const sal_uInt32 nPolyCount(aPolyPolygon.count());
+
+ if (nPolyCount && pAttrObj)
+ {
+ SdrObjKind eKind = SdrObjKind::PathFill;
+
+ if(nPolyCount > 1)
+ {
+ aPolyPolygon.setClosed(true);
+ }
+ else
+ {
+ // check for Polyline
+ const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0));
+ const sal_uInt32 nPointCount(aPolygon.count());
+
+ if(nPointCount <= 2)
+ {
+ eKind = SdrObjKind::PathLine;
+ }
+ else
+ {
+ if(!aPolygon.isClosed())
+ {
+ const basegfx::B2DPoint aPointA(aPolygon.getB2DPoint(0));
+ const basegfx::B2DPoint aPointB(aPolygon.getB2DPoint(nPointCount - 1));
+ const double fDistance(basegfx::B2DVector(aPointB - aPointA).getLength());
+ const double fJoinTolerance(10.0);
+
+ if(fDistance < fJoinTolerance)
+ {
+ aPolyPolygon.setClosed(true);
+ }
+ else
+ {
+ eKind = SdrObjKind::PathLine;
+ }
+ }
+ }
+ }
+
+ SdrPathObj* pPath = new SdrPathObj(pAttrObj->getSdrModelFromSdrObject(), eKind, aPolyPolygon);
+
+ // attributes of the lowest object
+ ImpCopyAttributes(pAttrObj, pPath);
+
+ // If LineStyle of pAttrObj is drawing::LineStyle_NONE force to drawing::LineStyle_SOLID to make visible.
+ const drawing::LineStyle eLineStyle = pAttrObj->GetMergedItem(XATTR_LINESTYLE).GetValue();
+ const drawing::FillStyle eFillStyle = pAttrObj->GetMergedItem(XATTR_FILLSTYLE).GetValue();
+
+ // Take fill style/closed state of pAttrObj in account when deciding to change the line style
+ bool bIsClosedPathObj = false;
+ if (auto pPathObj = dynamic_cast<const SdrPathObj*>(pAttrObj))
+ if (pPathObj->IsClosed())
+ bIsClosedPathObj = true;
+
+ if(drawing::LineStyle_NONE == eLineStyle && (drawing::FillStyle_NONE == eFillStyle || !bIsClosedPathObj))
+ {
+ pPath->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
+ }
+
+ pInsOL->InsertObject(pPath,nInsPos);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath));
+
+ // Here was a severe error: Without UnmarkAllObj, the new object was marked
+ // additionally to the two ones which are deleted below. As long as those are
+ // in the UNDO there is no problem, but as soon as they get deleted, the
+ // MarkList will contain deleted objects -> GPF.
+ UnmarkAllObj(pInsPV);
+ MarkObj(pPath, pInsPV, false, true);
+ }
+
+ // build an UndoComment from the objects actually used
+ aRemoveBuffer.ForceSort(); // important for remove (see below)
+ if( bUndo )
+ SetUndoComment(SvxResId(bNoPolyPoly?STR_EditCombine_OnePoly:STR_EditCombine_PolyPoly),aRemoveBuffer.GetMarkDescription());
+
+ // remove objects actually used from the list
+ DeleteMarkedList(aRemoveBuffer);
+ if( bUndo )
+ EndUndo();
+}
+
+
+// Dismantle
+
+
+bool SdrEditView::ImpCanDismantle(const basegfx::B2DPolyPolygon& rPpolyPolygon, bool bMakeLines)
+{
+ bool bCan(false);
+ const sal_uInt32 nPolygonCount(rPpolyPolygon.count());
+
+ if(nPolygonCount >= 2)
+ {
+ // #i69172# dismantle makes sense with 2 or more polygons in a polyPolygon
+ bCan = true;
+ }
+ else if(bMakeLines && 1 == nPolygonCount)
+ {
+ // #i69172# ..or with at least 2 edges (curves or lines)
+ const basegfx::B2DPolygon& aPolygon(rPpolyPolygon.getB2DPolygon(0));
+ const sal_uInt32 nPointCount(aPolygon.count());
+
+ if(nPointCount > 2)
+ {
+ bCan = true;
+ }
+ }
+
+ return bCan;
+}
+
+bool SdrEditView::ImpCanDismantle(const SdrObject* pObj, bool bMakeLines)
+{
+ bool bOtherObjs(false); // true=objects other than PathObj's existent
+ bool bMin1PolyPoly(false); // true=at least 1 tools::PolyPolygon with more than one Polygon existent
+ SdrObjList* pOL = pObj->GetSubList();
+
+ if(pOL)
+ {
+ // group object -- check all members if they're PathObjs
+ SdrObjListIter aIter(pOL, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore() && !bOtherObjs)
+ {
+ const SdrObject* pObj1 = aIter.Next();
+ const SdrPathObj* pPath = dynamic_cast<const SdrPathObj*>( pObj1 );
+
+ if(pPath)
+ {
+ if(ImpCanDismantle(pPath->GetPathPoly(), bMakeLines))
+ {
+ bMin1PolyPoly = true;
+ }
+
+ SdrObjTransformInfoRec aInfo;
+ pObj1->TakeObjInfo(aInfo);
+
+ if(!aInfo.bCanConvToPath)
+ {
+ // happens e. g. in the case of FontWork
+ bOtherObjs = true;
+ }
+ }
+ else
+ {
+ bOtherObjs = true;
+ }
+ }
+ }
+ else
+ {
+ const SdrPathObj* pPath = dynamic_cast<const SdrPathObj*>(pObj);
+ const SdrObjCustomShape* pCustomShape = dynamic_cast<const SdrObjCustomShape*>(pObj);
+
+ // #i37011#
+ if(pPath)
+ {
+ if(ImpCanDismantle(pPath->GetPathPoly(),bMakeLines))
+ {
+ bMin1PolyPoly = true;
+ }
+
+ SdrObjTransformInfoRec aInfo;
+ pObj->TakeObjInfo(aInfo);
+
+ // new condition IsLine() to be able to break simple Lines
+ if(!(aInfo.bCanConvToPath || aInfo.bCanConvToPoly) && !pPath->IsLine())
+ {
+ // happens e. g. in the case of FontWork
+ bOtherObjs = true;
+ }
+ }
+ else if(pCustomShape)
+ {
+ if(bMakeLines)
+ {
+ // allow break command
+ bMin1PolyPoly = true;
+ }
+ }
+ else
+ {
+ bOtherObjs = true;
+ }
+ }
+ return bMin1PolyPoly && !bOtherObjs;
+}
+
+void SdrEditView::ImpDismantleOneObject(const SdrObject* pObj, SdrObjList& rOL, size_t& rPos, SdrPageView* pPV, bool bMakeLines)
+{
+ const SdrPathObj* pSrcPath = dynamic_cast<const SdrPathObj*>( pObj );
+ const SdrObjCustomShape* pCustomShape = dynamic_cast<const SdrObjCustomShape*>( pObj );
+
+ const bool bUndo = IsUndoEnabled();
+
+ if(pSrcPath)
+ {
+ // #i74631# redesigned due to XpolyPolygon removal and explicit constructors
+ SdrObject* pLast = nullptr; // to be able to apply OutlinerParaObject
+ const basegfx::B2DPolyPolygon& rPolyPolygon(pSrcPath->GetPathPoly());
+ const sal_uInt32 nPolyCount(rPolyPolygon.count());
+
+ for(sal_uInt32 a(0); a < nPolyCount; a++)
+ {
+ const basegfx::B2DPolygon& rCandidate(rPolyPolygon.getB2DPolygon(a));
+ const sal_uInt32 nPointCount(rCandidate.count());
+
+ if(!bMakeLines || nPointCount < 2)
+ {
+ SdrPathObj* pPath = new SdrPathObj(
+ pSrcPath->getSdrModelFromSdrObject(),
+ pSrcPath->GetObjIdentifier(),
+ basegfx::B2DPolyPolygon(rCandidate));
+ ImpCopyAttributes(pSrcPath, pPath);
+ pLast = pPath;
+ rOL.InsertObject(pPath, rPos);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath, true));
+ MarkObj(pPath, pPV, false, true);
+ rPos++;
+ }
+ else
+ {
+ const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
+
+ for(sal_uInt32 b(0); b < nLoopCount; b++)
+ {
+ SdrObjKind eKind(SdrObjKind::PolyLine);
+ basegfx::B2DPolygon aNewPolygon;
+ const sal_uInt32 nNextIndex((b + 1) % nPointCount);
+
+ aNewPolygon.append(rCandidate.getB2DPoint(b));
+
+ if(rCandidate.areControlPointsUsed())
+ {
+ aNewPolygon.appendBezierSegment(
+ rCandidate.getNextControlPoint(b),
+ rCandidate.getPrevControlPoint(nNextIndex),
+ rCandidate.getB2DPoint(nNextIndex));
+ eKind = SdrObjKind::PathLine;
+ }
+ else
+ {
+ aNewPolygon.append(rCandidate.getB2DPoint(nNextIndex));
+ }
+
+ SdrPathObj* pPath = new SdrPathObj(
+ pSrcPath->getSdrModelFromSdrObject(),
+ eKind,
+ basegfx::B2DPolyPolygon(aNewPolygon));
+ ImpCopyAttributes(pSrcPath, pPath);
+ pLast = pPath;
+ rOL.InsertObject(pPath, rPos);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath, true));
+ MarkObj(pPath, pPV, false, true);
+ rPos++;
+ }
+ }
+ }
+
+ if(pLast && pSrcPath->GetOutlinerParaObject())
+ {
+ pLast->SetOutlinerParaObject(*pSrcPath->GetOutlinerParaObject());
+ }
+ }
+ else if(pCustomShape)
+ {
+ if(bMakeLines)
+ {
+ // break up custom shape
+ const SdrObject* pReplacement = pCustomShape->GetSdrObjectFromCustomShape();
+
+ if(pReplacement)
+ {
+ SdrObject* pCandidate(pReplacement->CloneSdrObject(pReplacement->getSdrModelFromSdrObject()));
+ DBG_ASSERT(pCandidate, "SdrEditView::ImpDismantleOneObject: Could not clone SdrObject (!)");
+
+ if(pCustomShape->GetMergedItem(SDRATTR_SHADOW).GetValue())
+ {
+ if(dynamic_cast<const SdrObjGroup*>( pReplacement) != nullptr)
+ {
+ pCandidate->SetMergedItem(makeSdrShadowItem(true));
+ }
+ }
+
+ rOL.InsertObject(pCandidate, rPos);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pCandidate, true));
+ MarkObj(pCandidate, pPV, false, true);
+
+ if(pCustomShape->HasText() && !pCustomShape->IsTextPath())
+ {
+ // #i37011# also create a text object and add at rPos + 1
+ SdrObject* pTextObj = SdrObjFactory::MakeNewObject(
+ pCustomShape->getSdrModelFromSdrObject(),
+ pCustomShape->GetObjInventor(),
+ SdrObjKind::Text);
+
+ // Copy text content
+ OutlinerParaObject* pParaObj = pCustomShape->GetOutlinerParaObject();
+ if(pParaObj)
+ {
+ pTextObj->NbcSetOutlinerParaObject(*pParaObj);
+ }
+
+ // copy all attributes
+ SfxItemSet aTargetItemSet(pCustomShape->GetMergedItemSet());
+
+ // clear fill and line style
+ aTargetItemSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ aTargetItemSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+
+ // get the text bounds and set at text object
+ tools::Rectangle aTextBounds = pCustomShape->GetSnapRect();
+ if(pCustomShape->GetTextBounds(aTextBounds))
+ {
+ pTextObj->SetSnapRect(aTextBounds);
+ }
+
+ // if rotated, copy GeoStat, too.
+ const GeoStat& rSourceGeo = pCustomShape->GetGeoStat();
+ if(rSourceGeo.nRotationAngle)
+ {
+ pTextObj->NbcRotate(
+ pCustomShape->GetSnapRect().Center(), rSourceGeo.nRotationAngle,
+ rSourceGeo.mfSinRotationAngle, rSourceGeo.mfCosRotationAngle);
+ }
+
+ // set modified ItemSet at text object
+ pTextObj->SetMergedItemSet(aTargetItemSet);
+
+ // insert object
+ rOL.InsertObject(pTextObj, rPos + 1);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pTextObj, true));
+ MarkObj(pTextObj, pPV, false, true);
+ }
+ }
+ }
+ }
+}
+
+void SdrEditView::DismantleMarkedObjects(bool bMakeLines)
+{
+ // temporary MarkList
+ SdrMarkList aRemoveBuffer;
+
+ SortMarkedObjects();
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ {
+ // comment is constructed later
+ BegUndo("", "", bMakeLines ? SdrRepeatFunc::DismantleLines : SdrRepeatFunc::DismantlePolys);
+ }
+
+ SdrObjList* pOL0=nullptr;
+ for (size_t nm=GetMarkedObjectCount(); nm>0;) {
+ --nm;
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrPageView* pPV=pM->GetPageView();
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ if (pOL!=pOL0) { pOL0=pOL; pObj->GetOrdNum(); } // make sure OrdNums are correct!
+ if (ImpCanDismantle(pObj,bMakeLines)) {
+ aRemoveBuffer.InsertEntry(SdrMark(pObj,pM->GetPageView()));
+ const size_t nPos0=pObj->GetOrdNumDirect();
+ size_t nPos=nPos0+1;
+ SdrObjList* pSubList=pObj->GetSubList();
+ if (pSubList!=nullptr && !pObj->Is3DObj()) {
+ SdrObjListIter aIter(pSubList,SdrIterMode::DeepNoGroups);
+ while (aIter.IsMore()) {
+ const SdrObject* pObj1=aIter.Next();
+ ImpDismantleOneObject(pObj1,*pOL,nPos,pPV,bMakeLines);
+ }
+ } else {
+ ImpDismantleOneObject(pObj,*pOL,nPos,pPV,bMakeLines);
+ }
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj,true));
+ pOL->RemoveObject(nPos0);
+
+ if( !bUndo )
+ SdrObject::Free(pObj);
+ }
+ }
+
+ if( bUndo )
+ {
+ // construct UndoComment from objects actually used
+ SetUndoComment(SvxResId(bMakeLines?STR_EditDismantle_Lines:STR_EditDismantle_Polys),aRemoveBuffer.GetMarkDescription());
+ // remove objects actually used from the list
+ EndUndo();
+ }
+}
+
+
+// Group
+
+
+void SdrEditView::GroupMarked()
+{
+ if (!AreObjectsMarked())
+ return;
+
+ SortMarkedObjects();
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ {
+ BegUndo(SvxResId(STR_EditGroup),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::Group);
+
+ for(size_t nm = GetMarkedObjectCount(); nm>0; )
+ {
+ // add UndoActions for all affected objects
+ --nm;
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj = pM->GetMarkedSdrObj();
+ AddUndoActions( CreateConnectorUndo( *pObj ) );
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject( *pObj ));
+ }
+ }
+
+ SdrMarkList aNewMark;
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(pPV)
+ {
+ SdrObjList* pCurrentLst=pPV->GetObjList();
+ SdrObjList* pSrcLst=pCurrentLst;
+ SdrObjList* pSrcLst0=pSrcLst;
+ // make sure OrdNums are correct
+ if (pSrcLst->IsObjOrdNumsDirty())
+ pSrcLst->RecalcObjOrdNums();
+ SdrObject* pGrp=nullptr;
+ SdrObjList* pDstLst=nullptr;
+ // if all selected objects come from foreign object lists.
+ // the group object is the last one in the list.
+ size_t nInsPos=pSrcLst->GetObjCount();
+ bool bNeedInsPos=true;
+ for (size_t nm=GetMarkedObjectCount(); nm>0;)
+ {
+ --nm;
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ if (pM->GetPageView()==pPV)
+ {
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ if (nullptr==pGrp)
+ {
+ pGrp = new SdrObjGroup(pObj->getSdrModelFromSdrObject());
+ pDstLst=pGrp->GetSubList();
+ DBG_ASSERT(pDstLst!=nullptr,"Alleged group object doesn't return object list.");
+ }
+ pSrcLst=pObj->getParentSdrObjListFromSdrObject();
+ if (pSrcLst!=pSrcLst0)
+ {
+ if (pSrcLst->IsObjOrdNumsDirty())
+ pSrcLst->RecalcObjOrdNums();
+ }
+ bool bForeignList=pSrcLst!=pCurrentLst;
+ if (!bForeignList && bNeedInsPos)
+ {
+ nInsPos=pObj->GetOrdNum(); // this way, all ObjOrdNum of the page are set
+ nInsPos++;
+ bNeedInsPos=false;
+ }
+ pSrcLst->RemoveObject(pObj->GetOrdNumDirect());
+ if (!bForeignList)
+ nInsPos--; // correct InsertPos
+ pDstLst->InsertObject(pObj,0);
+ GetMarkedObjectListWriteAccess().DeleteMark(nm);
+ pSrcLst0=pSrcLst;
+ }
+ }
+ if (pGrp!=nullptr)
+ {
+ aNewMark.InsertEntry(SdrMark(pGrp,pPV));
+ const size_t nCount=pDstLst->GetObjCount();
+ pCurrentLst->InsertObject(pGrp,nInsPos);
+ if( bUndo )
+ {
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pGrp,true)); // no recalculation!
+ for (size_t no=0; no<nCount; ++no)
+ {
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pDstLst->GetObj(no)));
+ }
+ }
+ }
+ }
+ GetMarkedObjectListWriteAccess().Merge(aNewMark);
+ MarkListHasChanged();
+
+ if( bUndo )
+ EndUndo();
+}
+
+
+// Ungroup
+
+
+void SdrEditView::UnGroupMarked()
+{
+ SdrMarkList aNewMark;
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo("", "", SdrRepeatFunc::Ungroup);
+
+ size_t nCount=0;
+ OUString aName1;
+ OUString aName;
+ bool bNameOk=false;
+ for (size_t nm=GetMarkedObjectCount(); nm>0;) {
+ --nm;
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pGrp=pM->GetMarkedSdrObj();
+ SdrObjList* pSrcLst=pGrp->GetSubList();
+ if (pSrcLst!=nullptr) {
+ nCount++;
+ if (nCount==1) {
+ aName = pGrp->TakeObjNameSingul(); // retrieve name of group
+ aName1 = pGrp->TakeObjNamePlural(); // retrieve name of group
+ bNameOk=true;
+ } else {
+ if (nCount==2) aName=aName1; // set plural name
+ if (bNameOk) {
+ OUString aStr(pGrp->TakeObjNamePlural()); // retrieve name of group
+
+ if (aStr != aName)
+ bNameOk = false;
+ }
+ }
+ size_t nDstCnt=pGrp->GetOrdNum();
+ SdrObjList* pDstLst=pM->GetPageView()->GetObjList();
+ size_t nObjCount=pSrcLst->GetObjCount();
+ const bool bIsDiagram(pGrp->isDiagram());
+
+ // If the Group is a Diagram, it has a filler BG object to guarantee
+ // the Diagam's dimensions. Identify that shape
+ if(bIsDiagram && nObjCount)
+ {
+ SdrObject* pObj(pSrcLst->GetObj(0));
+
+ if(nullptr != pObj && !pObj->IsGroupObject() &&
+ !pObj->HasLineStyle() &&
+ pObj->IsMoveProtect() && pObj->IsResizeProtect())
+ {
+ if(pObj->HasFillStyle())
+ {
+ // If it has FillStyle it is a useful object representing that possible
+ // defined fill from oox import. In this case, we should remove the
+ // Move/Resize protection to allow seamless further processing.
+
+ // Undo of these is handled by SdrUndoGeoObj which holds a SdrObjGeoData,
+ // create one
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+
+ pObj->SetMoveProtect(false);
+ pObj->SetResizeProtect(false);
+ }
+ else
+ {
+ // If it has no FillStyle it is not useful for any further processing
+ // but only was used as a placeholder, get directly rid of it
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
+
+ pObj = pSrcLst->RemoveObject(0);
+
+ if( !bUndo )
+ SdrObject::Free(pObj);
+
+ nObjCount = pSrcLst->GetObjCount();
+ }
+ }
+ }
+
+ // FIRST move contained objects to parent of group, so that
+ // the contained objects are NOT migrated to the UNDO-ItemPool
+ // when AddUndo(new SdrUndoDelObj(*pGrp)) is called.
+ if( bUndo )
+ {
+ for (size_t no=nObjCount; no>0;)
+ {
+ no--;
+ SdrObject* pObj=pSrcLst->GetObj(no);
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject(*pObj));
+ }
+ }
+
+ for (size_t no=0; no<nObjCount; ++no)
+ {
+ SdrObject* pObj=pSrcLst->RemoveObject(0);
+ pDstLst->InsertObject(pObj,nDstCnt);
+ if( bUndo )
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pObj,true));
+ nDstCnt++;
+ // No SortCheck when inserting into MarkList, because that would
+ // provoke a RecalcOrdNums() each time because of pObj->GetOrdNum():
+ aNewMark.InsertEntry(SdrMark(pObj,pM->GetPageView()),false);
+ }
+
+ if( bUndo )
+ {
+ // Now it is safe to add the delete-UNDO which triggers the
+ // MigrateItemPool now only for itself, not for the sub-objects.
+ // nDstCnt is right, because previous inserts move group
+ // object deeper and increase nDstCnt.
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pGrp));
+ }
+ pDstLst->RemoveObject(nDstCnt);
+
+ if( !bUndo )
+ SdrObject::Free(pGrp);
+
+ GetMarkedObjectListWriteAccess().DeleteMark(nm);
+ }
+ }
+ if (nCount!=0)
+ {
+ if (!bNameOk)
+ aName=SvxResId(STR_ObjNamePluralGRUP); // Use the term "Group Objects," if different objects are grouped.
+ SetUndoComment(SvxResId(STR_EditUngroup),aName);
+ }
+
+ if( bUndo )
+ EndUndo();
+
+ if (nCount!=0)
+ {
+ GetMarkedObjectListWriteAccess().Merge(aNewMark,true); // Because of the sorting above, aNewMark is reversed
+ MarkListHasChanged();
+ }
+}
+
+
+// ConvertToPoly
+
+
+SdrObject* SdrEditView::ImpConvertOneObj(SdrObject* pObj, bool bPath, bool bLineToArea)
+{
+ SdrObjectUniquePtr pNewObj = pObj->ConvertToPolyObj(bPath, bLineToArea);
+ if (pNewObj)
+ {
+ SdrObjList* pOL = pObj->getParentSdrObjListFromSdrObject();
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoReplaceObject(*pObj,*pNewObj));
+
+ // ownership passed into here (despite the UniquePtr indicating that we are returning it)
+ pOL->ReplaceObject(pNewObj.get(), pObj->GetOrdNum());
+
+ if( !bUndo )
+ SdrObject::Free(pObj);
+ }
+ return pNewObj.release();
+}
+
+void SdrEditView::ImpConvertTo(bool bPath, bool bLineToArea)
+{
+ if (!AreObjectsMarked()) return;
+
+ bool bMrkChg = false;
+ const size_t nMarkCount=GetMarkedObjectCount();
+ TranslateId pDscrID;
+ if(bLineToArea)
+ {
+ if(nMarkCount == 1)
+ pDscrID = STR_EditConvToContour;
+ else
+ pDscrID = STR_EditConvToContours;
+
+ BegUndo(SvxResId(pDscrID), GetDescriptionOfMarkedObjects());
+ }
+ else
+ {
+ if (bPath) {
+ if (nMarkCount==1) pDscrID=STR_EditConvToCurve;
+ else pDscrID=STR_EditConvToCurves;
+ BegUndo(SvxResId(pDscrID),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::ConvertToPath);
+ } else {
+ if (nMarkCount==1) pDscrID=STR_EditConvToPoly;
+ else pDscrID=STR_EditConvToPolys;
+ BegUndo(SvxResId(pDscrID),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::ConvertToPoly);
+ }
+ }
+ for (size_t nm=nMarkCount; nm>0;) {
+ --nm;
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrPageView* pPV=pM->GetPageView();
+ if (pObj->IsGroupObject() && !pObj->Is3DObj()) {
+ SdrObject* pGrp=pObj;
+ SdrObjListIter aIter(*pGrp, SdrIterMode::DeepNoGroups);
+ while (aIter.IsMore()) {
+ pObj=aIter.Next();
+ ImpConvertOneObj(pObj,bPath,bLineToArea);
+ }
+ } else {
+ SdrObject* pNewObj=ImpConvertOneObj(pObj,bPath,bLineToArea);
+ if (pNewObj!=nullptr) {
+ bMrkChg=true;
+ GetMarkedObjectListWriteAccess().ReplaceMark(SdrMark(pNewObj,pPV),nm);
+ }
+ }
+ }
+ EndUndo();
+ if (bMrkChg)
+ {
+ AdjustMarkHdl();
+ MarkListHasChanged();
+ }
+}
+
+void SdrEditView::ConvertMarkedToPathObj(bool bLineToArea)
+{
+ ImpConvertTo(true, bLineToArea);
+}
+
+void SdrEditView::ConvertMarkedToPolyObj()
+{
+ ImpConvertTo(false, false/*bLineToArea*/);
+}
+
+namespace
+{
+ GDIMetaFile GetMetaFile(SdrGrafObj const * pGraf)
+ {
+ if (pGraf->HasGDIMetaFile())
+ return pGraf->GetTransformedGraphic(SdrGrafObjTransformsAttrs::MIRROR).GetGDIMetaFile();
+ assert(pGraf->isEmbeddedVectorGraphicData());
+ return pGraf->getMetafileFromEmbeddedVectorGraphicData();
+ }
+}
+
+// Metafile Import
+void SdrEditView::DoImportMarkedMtf(SvdProgressInfo *pProgrInfo)
+{
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo("", "", SdrRepeatFunc::ImportMtf);
+
+ SortMarkedObjects();
+ SdrMarkList aForTheDescription;
+ SdrMarkList aNewMarked;
+ for (size_t nm =GetMarkedObjectCount(); nm > 0; )
+ {
+ // create Undo objects for all new objects
+ // check for cancellation between the metafiles
+ if (pProgrInfo != nullptr)
+ {
+ pProgrInfo->SetNextObject();
+ if (!pProgrInfo->ReportActions(0))
+ break;
+ }
+
+ --nm;
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrPageView* pPV=pM->GetPageView();
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ const size_t nInsPos=pObj->GetOrdNum()+1;
+ size_t nInsCnt=0;
+ tools::Rectangle aLogicRect;
+
+ SdrGrafObj* pGraf = dynamic_cast<SdrGrafObj*>( pObj );
+ if (pGraf != nullptr)
+ {
+ Graphic aGraphic = pGraf->GetGraphic();
+ auto const & pVectorGraphicData = aGraphic.getVectorGraphicData();
+
+ if (pVectorGraphicData && pVectorGraphicData->getType() == VectorGraphicDataType::Pdf)
+ {
+ auto pPdfium = vcl::pdf::PDFiumLibrary::get();
+ if (pPdfium)
+ {
+ aLogicRect = pGraf->GetLogicRect();
+ ImpSdrPdfImport aFilter(*mpModel, pObj->GetLayer(), aLogicRect, aGraphic);
+ if (aGraphic.getPageNumber() < aFilter.GetPageCount())
+ {
+ nInsCnt = aFilter.DoImport(*pOL, nInsPos, aGraphic.getPageNumber(), pProgrInfo);
+ }
+ }
+ }
+ else if (pGraf->HasGDIMetaFile() || pGraf->isEmbeddedVectorGraphicData() )
+ {
+ GDIMetaFile aMetaFile(GetMetaFile(pGraf));
+ if (aMetaFile.GetActionSize())
+ {
+ aLogicRect = pGraf->GetLogicRect();
+ ImpSdrGDIMetaFileImport aFilter(*mpModel, pObj->GetLayer(), aLogicRect);
+ nInsCnt = aFilter.DoImport(aMetaFile, *pOL, nInsPos, pProgrInfo);
+ }
+ }
+ }
+
+ SdrOle2Obj* pOle2 = dynamic_cast<SdrOle2Obj*>(pObj);
+ if (pOle2 != nullptr && pOle2->GetGraphic())
+ {
+ aLogicRect = pOle2->GetLogicRect();
+ ImpSdrGDIMetaFileImport aFilter(*mpModel, pObj->GetLayer(), aLogicRect);
+ nInsCnt = aFilter.DoImport(pOle2->GetGraphic()->GetGDIMetaFile(), *pOL, nInsPos, pProgrInfo);
+ }
+
+ if (nInsCnt != 0)
+ {
+ // transformation
+ GeoStat aGeoStat(pGraf ? pGraf->GetGeoStat() : pOle2->GetGeoStat());
+ size_t nObj = nInsPos;
+
+ if (aGeoStat.nShearAngle)
+ aGeoStat.RecalcTan();
+
+ if (aGeoStat.nRotationAngle)
+ aGeoStat.RecalcSinCos();
+
+ for (size_t i = 0; i < nInsCnt; i++)
+ {
+ if (bUndo)
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pOL->GetObj(nObj)));
+
+ // update new MarkList
+ SdrObject* pCandidate = pOL->GetObj(nObj);
+
+ // apply original transformation
+ if (aGeoStat.nShearAngle)
+ pCandidate->NbcShear(aLogicRect.TopLeft(), aGeoStat.nShearAngle, aGeoStat.mfTanShearAngle, false);
+
+ if (aGeoStat.nRotationAngle)
+ pCandidate->NbcRotate(aLogicRect.TopLeft(), aGeoStat.nRotationAngle, aGeoStat.mfSinRotationAngle, aGeoStat.mfCosRotationAngle);
+
+ SdrMark aNewMark(pCandidate, pPV);
+ aNewMarked.InsertEntry(aNewMark);
+
+ nObj++;
+ }
+
+ aForTheDescription.InsertEntry(*pM);
+
+ if (bUndo)
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
+
+ // remove object from selection and delete
+ GetMarkedObjectListWriteAccess().DeleteMark(TryToFindMarkedObject(pObj));
+ pOL->RemoveObject(nInsPos-1);
+
+ if (!bUndo)
+ SdrObject::Free(pObj);
+ }
+ }
+
+ if (aNewMarked.GetMarkCount())
+ {
+ // create new selection
+ for (size_t a = 0; a < aNewMarked.GetMarkCount(); ++a)
+ {
+ GetMarkedObjectListWriteAccess().InsertEntry(*aNewMarked.GetMark(a));
+ }
+
+ SortMarkedObjects();
+ }
+
+ if (bUndo)
+ {
+ SetUndoComment(SvxResId(STR_EditImportMtf),aForTheDescription.GetMarkDescription());
+ EndUndo();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
new file mode 100644
index 000000000..c1c248b21
--- /dev/null
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -0,0 +1,2871 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/i18n/WordType.hpp>
+#include <editeng/editdata.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/unotext.hxx>
+#include <o3tl/deleter.hxx>
+#include <svl/itemiter.hxx>
+#include <svl/style.hxx>
+#include <svl/whiter.hxx>
+#include <svtools/accessibilityoptions.hxx>
+#include <svx/sdtfchim.hxx>
+#include <svx/selectioncontroller.hxx>
+#include <svx/svdedxv.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdundo.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/window.hxx>
+#include <comphelper/lok.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <editeng/outliner.hxx>
+#include <sal/log.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdr/overlay/overlayselection.hxx>
+#include <svx/sdr/table/tablecontroller.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/sdrundomanager.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdviter.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <textchain.hxx>
+#include <textchaincursor.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svapp.hxx>
+
+#include <memory>
+
+SdrObjEditView::SdrObjEditView(SdrModel& rSdrModel, OutputDevice* pOut)
+ : SdrGlueEditView(rSdrModel, pOut)
+ , mpTextEditPV(nullptr)
+ , mpTextEditOutlinerView(nullptr)
+ , mpTextEditWin(nullptr)
+ , pTextEditCursorBuffer(nullptr)
+ , pMacroObj(nullptr)
+ , pMacroPV(nullptr)
+ , pMacroWin(nullptr)
+ , nMacroTol(0)
+ , mbTextEditDontDelete(false)
+ , mbTextEditOnlyOneView(false)
+ , mbTextEditNewObj(false)
+ , mbQuickTextEditMode(true)
+ , mbMacroDown(false)
+ , mpOldTextEditUndoManager(nullptr)
+{
+}
+
+SdrObjEditView::~SdrObjEditView()
+{
+ mpTextEditWin = nullptr; // so there's no ShowCursor in SdrEndTextEdit
+ assert(!IsTextEdit());
+ if (IsTextEdit())
+ suppress_fun_call_w_exception(SdrEndTextEdit());
+ mpTextEditOutliner.reset();
+ assert(nullptr == mpOldTextEditUndoManager); // should have been reset
+}
+
+bool SdrObjEditView::IsAction() const { return IsMacroObj() || SdrGlueEditView::IsAction(); }
+
+void SdrObjEditView::MovAction(const Point& rPnt)
+{
+ if (IsMacroObj())
+ MovMacroObj(rPnt);
+ SdrGlueEditView::MovAction(rPnt);
+}
+
+void SdrObjEditView::EndAction()
+{
+ if (IsMacroObj())
+ EndMacroObj();
+ SdrGlueEditView::EndAction();
+}
+
+void SdrObjEditView::BckAction()
+{
+ BrkMacroObj();
+ SdrGlueEditView::BckAction();
+}
+
+void SdrObjEditView::BrkAction()
+{
+ BrkMacroObj();
+ SdrGlueEditView::BrkAction();
+}
+
+SdrPageView* SdrObjEditView::ShowSdrPage(SdrPage* pPage)
+{
+ SdrPageView* pPageView = SdrGlueEditView::ShowSdrPage(pPage);
+
+ if (comphelper::LibreOfficeKit::isActive() && pPageView)
+ {
+ // Check if other views have an active text edit on the same page as
+ // this one.
+ SdrViewIter aIter(pPageView->GetPage());
+ for (SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView())
+ {
+ if (pView == this || !pView->IsTextEdit())
+ continue;
+
+ OutputDevice* pOutDev = GetFirstOutputDevice();
+ if (!pOutDev || pOutDev->GetOutDevType() != OUTDEV_WINDOW)
+ continue;
+
+ // Found one, so create an outliner view, to get invalidations when
+ // the text edit changes.
+ // Call GetSfxViewShell() to make sure ImpMakeOutlinerView()
+ // registers the view shell of this draw view, and not the view
+ // shell of pView.
+ OutlinerView* pOutlinerView
+ = pView->ImpMakeOutlinerView(pOutDev->GetOwnerWindow(), nullptr, GetSfxViewShell());
+ pOutlinerView->HideCursor();
+ pView->GetTextEditOutliner()->InsertView(pOutlinerView);
+ }
+ }
+
+ return pPageView;
+}
+
+namespace
+{
+/// Removes outliner views registered in other draw views that use pOutputDevice.
+void lcl_RemoveTextEditOutlinerViews(SdrObjEditView const* pThis, SdrPageView const* pPageView,
+ OutputDevice const* pOutputDevice)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ if (!pPageView)
+ return;
+
+ if (!pOutputDevice || pOutputDevice->GetOutDevType() != OUTDEV_WINDOW)
+ return;
+
+ SdrViewIter aIter(pPageView->GetPage());
+ for (SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView())
+ {
+ if (pView == pThis || !pView->IsTextEdit())
+ continue;
+
+ SdrOutliner* pOutliner = pView->GetTextEditOutliner();
+ for (size_t nView = 0; nView < pOutliner->GetViewCount(); ++nView)
+ {
+ OutlinerView* pOutlinerView = pOutliner->GetView(nView);
+ if (pOutlinerView->GetWindow()->GetOutDev() != pOutputDevice)
+ continue;
+
+ pOutliner->RemoveView(pOutlinerView);
+ delete pOutlinerView;
+ }
+ }
+}
+}
+
+void SdrObjEditView::HideSdrPage()
+{
+ lcl_RemoveTextEditOutlinerViews(this, GetSdrPageView(), GetFirstOutputDevice());
+
+ if (mpTextEditPV == GetSdrPageView())
+ {
+ // HideSdrPage() will clear mpPageView, avoid a dangling pointer.
+ mpTextEditPV = nullptr;
+ }
+
+ SdrGlueEditView::HideSdrPage();
+}
+
+void SdrObjEditView::TakeActionRect(tools::Rectangle& rRect) const
+{
+ if (IsMacroObj())
+ {
+ rRect = pMacroObj->GetCurrentBoundRect();
+ }
+ else
+ {
+ SdrGlueEditView::TakeActionRect(rRect);
+ }
+}
+
+void SdrObjEditView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ SdrGlueEditView::Notify(rBC, rHint);
+ if (mpTextEditOutliner == nullptr)
+ return;
+
+ // change of printer while editing
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ SdrHintKind eKind = pSdrHint->GetKind();
+ if (eKind == SdrHintKind::RefDeviceChange)
+ {
+ mpTextEditOutliner->SetRefDevice(mpModel->GetRefDevice());
+ }
+ if (eKind == SdrHintKind::DefaultTabChange)
+ {
+ mpTextEditOutliner->SetDefTab(mpModel->GetDefaultTabulator());
+ }
+}
+
+void SdrObjEditView::ModelHasChanged()
+{
+ SdrGlueEditView::ModelHasChanged();
+ if (mxWeakTextEditObj.is() && !mxWeakTextEditObj->IsInserted())
+ SdrEndTextEdit(); // object deleted
+ // TextEditObj changed?
+ if (!IsTextEdit())
+ return;
+
+ SdrTextObj* pTextObj = mxWeakTextEditObj.get();
+ if (pTextObj != nullptr)
+ {
+ size_t nOutlViewCnt = mpTextEditOutliner->GetViewCount();
+ bool bAreaChg = false;
+ bool bAnchorChg = false;
+ bool bColorChg = false;
+ bool bContourFrame = pTextObj->IsContourTextFrame();
+ EEAnchorMode eNewAnchor(EEAnchorMode::VCenterHCenter);
+ tools::Rectangle aOldArea(aMinTextEditArea);
+ aOldArea.Union(aTextEditArea);
+ Color aNewColor;
+ { // check area
+ Size aPaperMin1;
+ Size aPaperMax1;
+ tools::Rectangle aEditArea1;
+ tools::Rectangle aMinArea1;
+ pTextObj->TakeTextEditArea(&aPaperMin1, &aPaperMax1, &aEditArea1, &aMinArea1);
+ Point aPvOfs(pTextObj->GetTextEditOffset());
+
+ // add possible GridOffset to up-to-now view-independent EditAreas
+ basegfx::B2DVector aGridOffset(0.0, 0.0);
+ if (getPossibleGridOffsetForSdrObject(aGridOffset, pTextObj, GetSdrPageView()))
+ {
+ const Point aOffset(basegfx::fround(aGridOffset.getX()),
+ basegfx::fround(aGridOffset.getY()));
+
+ aEditArea1 += aOffset;
+ aMinArea1 += aOffset;
+ }
+
+ aEditArea1.Move(aPvOfs.X(), aPvOfs.Y());
+ aMinArea1.Move(aPvOfs.X(), aPvOfs.Y());
+ tools::Rectangle aNewArea(aMinArea1);
+ aNewArea.Union(aEditArea1);
+
+ if (aNewArea != aOldArea || aEditArea1 != aTextEditArea || aMinArea1 != aMinTextEditArea
+ || mpTextEditOutliner->GetMinAutoPaperSize() != aPaperMin1
+ || mpTextEditOutliner->GetMaxAutoPaperSize() != aPaperMax1)
+ {
+ aTextEditArea = aEditArea1;
+ aMinTextEditArea = aMinArea1;
+
+ const bool bPrevUpdateLayout = mpTextEditOutliner->SetUpdateLayout(false);
+ mpTextEditOutliner->SetMinAutoPaperSize(aPaperMin1);
+ mpTextEditOutliner->SetMaxAutoPaperSize(aPaperMax1);
+ mpTextEditOutliner->SetPaperSize(Size(0, 0)); // re-format Outliner
+
+ if (!bContourFrame)
+ {
+ mpTextEditOutliner->ClearPolygon();
+ EEControlBits nStat = mpTextEditOutliner->GetControlWord();
+ nStat |= EEControlBits::AUTOPAGESIZE;
+ mpTextEditOutliner->SetControlWord(nStat);
+ }
+ else
+ {
+ EEControlBits nStat = mpTextEditOutliner->GetControlWord();
+ nStat &= ~EEControlBits::AUTOPAGESIZE;
+ mpTextEditOutliner->SetControlWord(nStat);
+ tools::Rectangle aAnchorRect;
+ pTextObj->TakeTextAnchorRect(aAnchorRect);
+ pTextObj->ImpSetContourPolygon(*mpTextEditOutliner, aAnchorRect, true);
+ }
+ for (size_t nOV = 0; nOV < nOutlViewCnt; nOV++)
+ {
+ OutlinerView* pOLV = mpTextEditOutliner->GetView(nOV);
+ EVControlBits nStat0 = pOLV->GetControlWord();
+ EVControlBits nStat = nStat0;
+ // AutoViewSize only if not ContourFrame.
+ if (!bContourFrame)
+ nStat |= EVControlBits::AUTOSIZE;
+ else
+ nStat &= ~EVControlBits::AUTOSIZE;
+ if (nStat != nStat0)
+ pOLV->SetControlWord(nStat);
+ }
+
+ mpTextEditOutliner->SetUpdateLayout(bPrevUpdateLayout);
+ bAreaChg = true;
+ }
+ }
+ if (mpTextEditOutlinerView != nullptr)
+ { // check fill and anchor
+ EEAnchorMode eOldAnchor = mpTextEditOutlinerView->GetAnchorMode();
+ eNewAnchor = pTextObj->GetOutlinerViewAnchorMode();
+ bAnchorChg = eOldAnchor != eNewAnchor;
+ Color aOldColor(mpTextEditOutlinerView->GetBackgroundColor());
+ aNewColor = GetTextEditBackgroundColor(*this);
+ bColorChg = aOldColor != aNewColor;
+ }
+ // refresh always when it's a contour frame. That
+ // refresh is necessary since it triggers the repaint
+ // which makes the Handles visible. Changes at TakeTextRect()
+ // seem to have resulted in a case where no refresh is executed.
+ // Before that, a refresh must have been always executed
+ // (else this error would have happened earlier), thus I
+ // even think here a refresh should be done always.
+ // Since follow-up problems cannot even be guessed I only
+ // add this one more case to the if below.
+ // BTW: It's VERY bad style that here, inside ModelHasChanged()
+ // the outliner is again massively changed for the text object
+ // in text edit mode. Normally, all necessary data should be
+ // set at SdrBeginTextEdit(). Some changes and value assigns in
+ // SdrBeginTextEdit() are completely useless since they are set here
+ // again on ModelHasChanged().
+ if (bContourFrame || bAreaChg || bAnchorChg || bColorChg)
+ {
+ for (size_t nOV = 0; nOV < nOutlViewCnt; nOV++)
+ {
+ OutlinerView* pOLV = mpTextEditOutliner->GetView(nOV);
+ { // invalidate old OutlinerView area
+ vcl::Window* pWin = pOLV->GetWindow();
+ tools::Rectangle aTmpRect(aOldArea);
+ sal_uInt16 nPixSiz = pOLV->GetInvalidateMore() + 1;
+ Size aMore(pWin->PixelToLogic(Size(nPixSiz, nPixSiz)));
+ aTmpRect.AdjustLeft(-(aMore.Width()));
+ aTmpRect.AdjustRight(aMore.Width());
+ aTmpRect.AdjustTop(-(aMore.Height()));
+ aTmpRect.AdjustBottom(aMore.Height());
+ InvalidateOneWin(*pWin->GetOutDev(), aTmpRect);
+ }
+ if (bAnchorChg)
+ pOLV->SetAnchorMode(eNewAnchor);
+ if (bColorChg)
+ pOLV->SetBackgroundColor(aNewColor);
+
+ pOLV->SetOutputArea(
+ aTextEditArea); // because otherwise, we're not re-anchoring correctly
+ ImpInvalidateOutlinerView(*pOLV);
+ }
+ mpTextEditOutlinerView->ShowCursor();
+ }
+ }
+ ImpMakeTextCursorAreaVisible();
+}
+
+namespace
+{
+/**
+ Helper class to visualize the content of an active EditView as an
+ OverlayObject. These objects work with Primitives and are handled
+ from the OverlayManager(s) in place as needed.
+
+ It allows complete visualization of the content of the active
+ EditView without the need of Invalidates triggered by the EditView
+ and thus avoiding potentially expensive repaints by using the
+ automatically buffered Overlay mechanism.
+
+ It buffers as much as possible locally and *only* triggers a real
+ change (see call to objectChange()) when really needed.
+ */
+class TextEditOverlayObject : public sdr::overlay::OverlayObject
+{
+protected:
+ /// local access to associated sdr::overlay::OverlaySelection
+ std::unique_ptr<sdr::overlay::OverlaySelection> mxOverlaySelection;
+
+ /// local definition depends on active OutlinerView
+ OutlinerView& mrOutlinerView;
+
+ /// geometry definitions with buffering
+ basegfx::B2DRange maLastRange;
+ basegfx::B2DRange maRange;
+
+ /// text content definitions with buffering
+ drawinglayer::primitive2d::Primitive2DContainer maTextPrimitives;
+ drawinglayer::primitive2d::Primitive2DContainer maLastTextPrimitives;
+
+ /// bitfield
+ bool mbVisualizeSurroundingFrame : 1;
+
+ // geometry creation for OverlayObject, can use local *Last* values
+ virtual drawinglayer::primitive2d::Primitive2DContainer
+ createOverlayObjectPrimitive2DSequence() override;
+
+public:
+ TextEditOverlayObject(const Color& rColor, OutlinerView& rOutlinerView,
+ bool bVisualizeSurroundingFrame);
+ virtual ~TextEditOverlayObject() override;
+
+ // data read access
+ const sdr::overlay::OverlaySelection* getOverlaySelection() const
+ {
+ return mxOverlaySelection.get();
+ }
+ const OutlinerView& getOutlinerView() const { return mrOutlinerView; }
+
+ /// override to check conditions for last createOverlayObjectPrimitive2DSequence
+ virtual drawinglayer::primitive2d::Primitive2DContainer
+ getOverlayObjectPrimitive2DSequence() const override;
+
+ // data write access. In this OverlayObject we only have the
+ // callback that triggers detecting if something *has* changed
+ void checkDataChange(const basegfx::B2DRange& rMinTextEditArea);
+ void checkSelectionChange();
+};
+
+drawinglayer::primitive2d::Primitive2DContainer
+TextEditOverlayObject::createOverlayObjectPrimitive2DSequence()
+{
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ /// outer frame visualization
+ if (mbVisualizeSurroundingFrame)
+ {
+ const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
+ const sal_uInt16 nPixSiz(getOutlinerView().GetInvalidateMore() - 1);
+
+ aRetval.push_back(new drawinglayer::primitive2d::OverlayRectanglePrimitive(
+ maRange, getBaseColor().getBColor(), fTransparence, std::max(6, nPixSiz - 2), // grow
+ 0.0, // shrink
+ 0.0));
+ }
+
+ // add buffered TextPrimitives
+ aRetval.append(maTextPrimitives);
+
+ return aRetval;
+}
+
+TextEditOverlayObject::TextEditOverlayObject(const Color& rColor, OutlinerView& rOutlinerView,
+ bool bVisualizeSurroundingFrame)
+ : OverlayObject(rColor)
+ , mrOutlinerView(rOutlinerView)
+ , mbVisualizeSurroundingFrame(bVisualizeSurroundingFrame)
+{
+ // no AA for TextEdit overlay
+ allowAntiAliase(false);
+
+ // create local OverlaySelection - this is an integral part of EditText
+ // visualization
+ std::vector<basegfx::B2DRange> aEmptySelection{};
+ mxOverlaySelection.reset(new sdr::overlay::OverlaySelection(
+ sdr::overlay::OverlayType::Transparent, rColor, std::move(aEmptySelection), true));
+}
+
+TextEditOverlayObject::~TextEditOverlayObject()
+{
+ mxOverlaySelection.reset();
+
+ if (getOverlayManager())
+ {
+ getOverlayManager()->remove(*this);
+ }
+}
+
+drawinglayer::primitive2d::Primitive2DContainer
+TextEditOverlayObject::getOverlayObjectPrimitive2DSequence() const
+{
+ if (!getPrimitive2DSequence().empty())
+ {
+ if (!maRange.equal(maLastRange) || maLastTextPrimitives != maTextPrimitives)
+ {
+ // conditions of last local decomposition have changed, delete to force new evaluation
+ const_cast<TextEditOverlayObject*>(this)->resetPrimitive2DSequence();
+ }
+ }
+
+ if (getPrimitive2DSequence().empty())
+ {
+ // remember new buffered values
+ const_cast<TextEditOverlayObject*>(this)->maLastRange = maRange;
+ const_cast<TextEditOverlayObject*>(this)->maLastTextPrimitives = maTextPrimitives;
+ }
+
+ // call base implementation
+ return OverlayObject::getOverlayObjectPrimitive2DSequence();
+}
+
+void TextEditOverlayObject::checkDataChange(const basegfx::B2DRange& rMinTextEditArea)
+{
+ bool bObjectChange(false);
+
+ // check current range
+ const tools::Rectangle aOutArea(mrOutlinerView.GetOutputArea());
+ basegfx::B2DRange aNewRange = vcl::unotools::b2DRectangleFromRectangle(aOutArea);
+ aNewRange.expand(rMinTextEditArea);
+
+ if (aNewRange != maRange)
+ {
+ maRange = aNewRange;
+ bObjectChange = true;
+ }
+
+ // check if text primitives did change
+ SdrOutliner* pSdrOutliner = dynamic_cast<SdrOutliner*>(getOutlinerView().GetOutliner());
+
+ if (pSdrOutliner)
+ {
+ // get TextPrimitives directly from active Outliner
+ basegfx::B2DHomMatrix aNewTransformA;
+ basegfx::B2DHomMatrix aNewTransformB;
+ basegfx::B2DRange aClipRange;
+ drawinglayer::primitive2d::Primitive2DContainer aNewTextPrimitives;
+
+ // active Outliner is always in unified oriented coordinate system (currently)
+ // so just translate to TopLeft of visible Range. Keep in mind that top-left
+ // depends on vertical text and top-to-bottom text attributes
+ const tools::Rectangle aVisArea(mrOutlinerView.GetVisArea());
+ const bool bVerticalWriting(pSdrOutliner->IsVertical());
+ const bool bTopToBottom(pSdrOutliner->IsTopToBottom());
+ const double fStartInX(bVerticalWriting && bTopToBottom
+ ? aOutArea.Right() - aVisArea.Left()
+ : aOutArea.Left() - aVisArea.Left());
+ const double fStartInY(bVerticalWriting && !bTopToBottom
+ ? aOutArea.Bottom() - aVisArea.Top()
+ : aOutArea.Top() - aVisArea.Top());
+
+ aNewTransformB.translate(fStartInX, fStartInY);
+
+ // get the current TextPrimitives. This is the most expensive part
+ // of this mechanism, it *may* be possible to buffer layouted
+ // primitives per ParaPortion with/in/dependent on the EditEngine
+ // content if needed. For now, get and compare
+ SdrTextObj::impDecomposeBlockTextPrimitiveDirect(
+ aNewTextPrimitives, *pSdrOutliner, aNewTransformA, aNewTransformB, aClipRange);
+
+ if (aNewTextPrimitives != maTextPrimitives)
+ {
+ maTextPrimitives = std::move(aNewTextPrimitives);
+ bObjectChange = true;
+ }
+ }
+
+ if (bObjectChange)
+ {
+ // if there really *was* a change signal the OverlayManager to
+ // refresh this object's visualization
+ objectChange();
+
+ // on data change, always do a SelectionChange, too
+ // since the selection is an integral part of text visualization
+ checkSelectionChange();
+ }
+}
+
+void TextEditOverlayObject::checkSelectionChange()
+{
+ if (!(getOverlaySelection() && getOverlayManager()))
+ return;
+
+ std::vector<tools::Rectangle> aLogicRects;
+ std::vector<basegfx::B2DRange> aLogicRanges;
+ const Size aLogicPixel(getOverlayManager()->getOutputDevice().PixelToLogic(Size(1, 1)));
+
+ // get logic selection
+ getOutlinerView().GetSelectionRectangles(aLogicRects);
+
+ aLogicRanges.reserve(aLogicRects.size());
+ for (const auto& aRect : aLogicRects)
+ {
+ // convert from logic Rectangles to logic Ranges, do not forget to add
+ // one Unit (in this case logical units for one pixel, pre-calculated)
+ aLogicRanges.emplace_back(
+ aRect.Left() - aLogicPixel.Width(), aRect.Top() - aLogicPixel.Height(),
+ aRect.Right() + aLogicPixel.Width(), aRect.Bottom() + aLogicPixel.Height());
+ }
+
+ mxOverlaySelection->setRanges(std::move(aLogicRanges));
+}
+} // end of anonymous namespace
+
+// TextEdit
+
+// callback from the active EditView, forward to evtl. existing instances of the
+// TextEditOverlayObject(s). This will additionally update the selection which
+// is an integral part of the text visualization
+void SdrObjEditView::EditViewInvalidate(const tools::Rectangle&)
+{
+ if (!IsTextEdit())
+ return;
+
+ // MinTextRange may have changed. Forward it, too
+ const basegfx::B2DRange aMinTextRange
+ = vcl::unotools::b2DRectangleFromRectangle(aMinTextEditArea);
+
+ for (sal_uInt32 a(0); a < maTEOverlayGroup.count(); a++)
+ {
+ TextEditOverlayObject* pCandidate
+ = dynamic_cast<TextEditOverlayObject*>(&maTEOverlayGroup.getOverlayObject(a));
+
+ if (pCandidate)
+ {
+ pCandidate->checkDataChange(aMinTextRange);
+ }
+ }
+}
+
+// callback from the active EditView, forward to evtl. existing instances of the
+// TextEditOverlayObject(s). This cvall *only* updates the selection visualization
+// which is e.g. used when only the selection is changed, but not the text
+void SdrObjEditView::EditViewSelectionChange()
+{
+ if (!IsTextEdit())
+ return;
+
+ for (sal_uInt32 a(0); a < maTEOverlayGroup.count(); a++)
+ {
+ TextEditOverlayObject* pCandidate
+ = dynamic_cast<TextEditOverlayObject*>(&maTEOverlayGroup.getOverlayObject(a));
+
+ if (pCandidate)
+ {
+ pCandidate->checkSelectionChange();
+ }
+ }
+}
+
+OutputDevice& SdrObjEditView::EditViewOutputDevice() const { return *mpTextEditWin->GetOutDev(); }
+
+Point SdrObjEditView::EditViewPointerPosPixel() const
+{
+ return mpTextEditWin->GetPointerPosPixel();
+}
+
+css::uno::Reference<css::datatransfer::clipboard::XClipboard> SdrObjEditView::GetClipboard() const
+{
+ if (!mpTextEditWin)
+ return nullptr;
+ return mpTextEditWin->GetClipboard();
+}
+
+css::uno::Reference<css::datatransfer::dnd::XDropTarget> SdrObjEditView::GetDropTarget()
+{
+ if (!mpTextEditWin)
+ return nullptr;
+ return mpTextEditWin->GetDropTarget();
+}
+
+void SdrObjEditView::EditViewInputContext(const InputContext& rInputContext)
+{
+ if (!mpTextEditWin)
+ return;
+ mpTextEditWin->SetInputContext(rInputContext);
+}
+
+void SdrObjEditView::EditViewCursorRect(const tools::Rectangle& rRect, int nExtTextInputWidth)
+{
+ if (!mpTextEditWin)
+ return;
+ mpTextEditWin->SetCursorRect(&rRect, nExtTextInputWidth);
+}
+
+void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ // adapt all TextEditOverlayObject(s), so call EditViewInvalidate()
+ // to update accordingly (will update selection, too). Suppress new
+ // stuff when LibreOfficeKit is active
+ EditViewInvalidate(tools::Rectangle());
+ }
+ else
+ {
+ // draw old text edit stuff
+ if (IsTextEdit())
+ {
+ const SdrOutliner* pActiveOutliner = GetTextEditOutliner();
+
+ if (pActiveOutliner)
+ {
+ const sal_uInt32 nViewCount(pActiveOutliner->GetViewCount());
+
+ if (nViewCount)
+ {
+ const vcl::Region& rRedrawRegion = rPaintWindow.GetRedrawRegion();
+ const tools::Rectangle aCheckRect(rRedrawRegion.GetBoundRect());
+
+ for (sal_uInt32 i(0); i < nViewCount; i++)
+ {
+ OutlinerView* pOLV = pActiveOutliner->GetView(i);
+
+ // If rPaintWindow knows that the output device is a render
+ // context and is aware of the underlying vcl::Window,
+ // compare against that; that's how double-buffering can
+ // still find the matching OutlinerView.
+ OutputDevice* pOutputDevice = rPaintWindow.GetWindow()
+ ? rPaintWindow.GetWindow()->GetOutDev()
+ : &rPaintWindow.GetOutputDevice();
+ if (pOLV->GetWindow()->GetOutDev() == pOutputDevice
+ || comphelper::LibreOfficeKit::isActive())
+ {
+ ImpPaintOutlinerView(*pOLV, aCheckRect,
+ rPaintWindow.GetTargetOutputDevice());
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void SdrObjEditView::ImpPaintOutlinerView(OutlinerView& rOutlView, const tools::Rectangle& rRect,
+ OutputDevice& rTargetDevice) const
+{
+ const SdrTextObj* pText = GetTextEditObject();
+ bool bTextFrame(pText && pText->IsTextFrame());
+ bool bFitToSize(mpTextEditOutliner->GetControlWord() & EEControlBits::STRETCHING);
+ bool bModified(mpTextEditOutliner->IsModified());
+ tools::Rectangle aBlankRect(rOutlView.GetOutputArea());
+ aBlankRect.Union(aMinTextEditArea);
+ tools::Rectangle aPixRect(rTargetDevice.LogicToPixel(aBlankRect));
+
+ // in the tiled rendering case, the setup is incomplete, and we very
+ // easily get an empty rRect on input - that will cause that everything is
+ // clipped; happens in case of editing text inside a shape in Calc.
+ // FIXME would be better to complete the setup so that we don't get an
+ // empty rRect here
+ if (!comphelper::LibreOfficeKit::isActive() || !rRect.IsEmpty())
+ aBlankRect.Intersection(rRect);
+
+ rOutlView.GetOutliner()->SetUpdateLayout(true); // Bugfix #22596#
+ rOutlView.Paint(aBlankRect, &rTargetDevice);
+
+ if (!bModified)
+ {
+ mpTextEditOutliner->ClearModifyFlag();
+ }
+
+ if (bTextFrame && !bFitToSize)
+ {
+ // completely reworked to use primitives; this ensures same look and functionality
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor(
+ drawinglayer::processor2d::createProcessor2DFromOutputDevice(rTargetDevice,
+ aViewInformation2D));
+
+ const bool bMapModeEnabled(rTargetDevice.IsMapModeEnabled());
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aPixRect);
+ const Color aHilightColor(SvtOptionsDrawinglayer::getHilightColor());
+ const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
+ const sal_uInt16 nPixSiz(rOutlView.GetInvalidateMore() - 1);
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::OverlayRectanglePrimitive(
+ aRange, aHilightColor.getBColor(), fTransparence, std::max(6, nPixSiz - 2), // grow
+ 0.0, // shrink
+ 0.0));
+ const drawinglayer::primitive2d::Primitive2DContainer aSequence{ xReference };
+
+ rTargetDevice.EnableMapMode(false);
+ xProcessor->process(aSequence);
+ rTargetDevice.EnableMapMode(bMapModeEnabled);
+ }
+
+ rOutlView.ShowCursor(/*bGotoCursor=*/true, /*bActivate=*/true);
+}
+
+void SdrObjEditView::ImpInvalidateOutlinerView(OutlinerView const& rOutlView) const
+{
+ vcl::Window* pWin = rOutlView.GetWindow();
+
+ if (!pWin)
+ return;
+
+ const SdrTextObj* pText = GetTextEditObject();
+ bool bTextFrame(pText && pText->IsTextFrame());
+ bool bFitToSize(pText && pText->IsFitToSize());
+
+ if (!bTextFrame || bFitToSize)
+ return;
+
+ tools::Rectangle aBlankRect(rOutlView.GetOutputArea());
+ aBlankRect.Union(aMinTextEditArea);
+ tools::Rectangle aPixRect(pWin->LogicToPixel(aBlankRect));
+ sal_uInt16 nPixSiz(rOutlView.GetInvalidateMore() - 1);
+
+ aPixRect.AdjustLeft(-1);
+ aPixRect.AdjustTop(-1);
+ aPixRect.AdjustRight(1);
+ aPixRect.AdjustBottom(1);
+
+ {
+ // limit xPixRect because of driver problems when pixel coordinates are too far out
+ Size aMaxXY(pWin->GetOutputSizePixel());
+ tools::Long a(2 * nPixSiz);
+ tools::Long nMaxX(aMaxXY.Width() + a);
+ tools::Long nMaxY(aMaxXY.Height() + a);
+
+ if (aPixRect.Left() < -a)
+ aPixRect.SetLeft(-a);
+ if (aPixRect.Top() < -a)
+ aPixRect.SetTop(-a);
+ if (aPixRect.Right() > nMaxX)
+ aPixRect.SetRight(nMaxX);
+ if (aPixRect.Bottom() > nMaxY)
+ aPixRect.SetBottom(nMaxY);
+ }
+
+ tools::Rectangle aOuterPix(aPixRect);
+ aOuterPix.AdjustLeft(-nPixSiz);
+ aOuterPix.AdjustTop(-nPixSiz);
+ aOuterPix.AdjustRight(nPixSiz);
+ aOuterPix.AdjustBottom(nPixSiz);
+
+ bool bMapModeEnabled(pWin->IsMapModeEnabled());
+ pWin->EnableMapMode(false);
+ pWin->Invalidate(aOuterPix);
+ pWin->EnableMapMode(bMapModeEnabled);
+}
+
+OutlinerView* SdrObjEditView::ImpMakeOutlinerView(vcl::Window* pWin, OutlinerView* pGivenView,
+ SfxViewShell* pViewShell) const
+{
+ // background
+ Color aBackground(GetTextEditBackgroundColor(*this));
+ SdrTextObj* pText = mxWeakTextEditObj.get();
+ bool bTextFrame = pText != nullptr && pText->IsTextFrame();
+ bool bContourFrame = pText != nullptr && pText->IsContourTextFrame();
+ // create OutlinerView
+ OutlinerView* pOutlView = pGivenView;
+ mpTextEditOutliner->SetUpdateLayout(false);
+
+ if (pOutlView == nullptr)
+ {
+ pOutlView = new OutlinerView(mpTextEditOutliner.get(), pWin);
+ }
+ else
+ {
+ pOutlView->SetWindow(pWin);
+ }
+
+ if (mbNegativeX)
+ pOutlView->GetEditView().SetNegativeX(mbNegativeX);
+
+ // disallow scrolling
+ EVControlBits nStat = pOutlView->GetControlWord();
+ nStat &= ~EVControlBits::AUTOSCROLL;
+ // AutoViewSize only if not ContourFrame.
+ if (!bContourFrame)
+ nStat |= EVControlBits::AUTOSIZE;
+ if (bTextFrame)
+ {
+ sal_uInt16 nPixSiz = maHdlList.GetHdlSize() * 2 + 1;
+ nStat |= EVControlBits::INVONEMORE;
+ pOutlView->SetInvalidateMore(nPixSiz);
+ }
+ pOutlView->SetControlWord(nStat);
+ pOutlView->SetBackgroundColor(aBackground);
+
+ // In case we're in the process of constructing a new view shell,
+ // SfxViewShell::Current() may still point to the old one. So if possible,
+ // depend on the application owning this draw view to provide the view
+ // shell.
+ SfxViewShell* pSfxViewShell = pViewShell ? pViewShell : GetSfxViewShell();
+ pOutlView->RegisterViewShell(pSfxViewShell ? pSfxViewShell : SfxViewShell::Current());
+
+ if (pText != nullptr)
+ {
+ pOutlView->SetAnchorMode(pText->GetOutlinerViewAnchorMode());
+ mpTextEditOutliner->SetFixedCellHeight(
+ pText->GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue());
+ }
+ // do update before setting output area so that aTextEditArea can be recalculated
+ mpTextEditOutliner->SetUpdateLayout(true);
+ pOutlView->SetOutputArea(aTextEditArea);
+ ImpInvalidateOutlinerView(*pOutlView);
+ return pOutlView;
+}
+
+IMPL_LINK(SdrObjEditView, ImpOutlinerStatusEventHdl, EditStatus&, rEditStat, void)
+{
+ if (mpTextEditOutliner)
+ {
+ SdrTextObj* pTextObj = mxWeakTextEditObj.get();
+ if (pTextObj)
+ {
+ pTextObj->onEditOutlinerStatusEvent(&rEditStat);
+ }
+ }
+}
+
+void SdrObjEditView::ImpChainingEventHdl()
+{
+ if (!mpTextEditOutliner)
+ return;
+
+ SdrTextObj* pTextObj = mxWeakTextEditObj.get();
+ OutlinerView* pOLV = GetTextEditOutlinerView();
+ if (pTextObj && pOLV)
+ {
+ TextChain* pTextChain = pTextObj->GetTextChain();
+
+ // XXX: IsChainable and GetNilChainingEvent are a bit mixed up atm
+ if (!pTextObj->IsChainable())
+ {
+ return;
+ }
+ // This is true during an underflow-caused overflow (with pEdtOutl->SetText())
+ if (pTextChain->GetNilChainingEvent(pTextObj))
+ {
+ return;
+ }
+
+ // We prevent to trigger further handling of overflow/underflow for pTextObj
+ pTextChain->SetNilChainingEvent(pTextObj, true); // XXX
+
+ // Save previous selection pos // NOTE: It must be done to have the right CursorEvent in KeyInput
+ pTextChain->SetPreChainingSel(pTextObj, pOLV->GetSelection());
+ //maPreChainingSel = new ESelection(pOLV->GetSelection());
+
+ // Handling Undo
+ const int nText = 0; // XXX: hardcoded index (SdrTextObj::getText handles only 0)
+
+ const bool bUndoEnabled = GetModel() && IsUndoEnabled();
+ std::unique_ptr<SdrUndoObjSetText> pTxtUndo;
+ if (bUndoEnabled)
+ pTxtUndo.reset(
+ dynamic_cast<SdrUndoObjSetText*>(GetModel()
+ ->GetSdrUndoFactory()
+ .CreateUndoObjectSetText(*pTextObj, nText)
+ .release()));
+
+ // trigger actual chaining
+ pTextObj->onChainingEvent();
+
+ if (pTxtUndo)
+ {
+ pTxtUndo->AfterSetText();
+ if (!pTxtUndo->IsDifferent())
+ {
+ pTxtUndo.reset();
+ }
+ }
+
+ if (pTxtUndo)
+ AddUndo(std::move(pTxtUndo));
+
+ //maCursorEvent = new CursorChainingEvent(pTextChain->GetCursorEvent(pTextObj));
+ //SdrTextObj *pNextLink = pTextObj->GetNextLinkInChain();
+
+ // NOTE: Must be called. Don't let the function return if you set it to true and not reset it
+ pTextChain->SetNilChainingEvent(pTextObj, false);
+ }
+ else
+ {
+ // XXX
+ SAL_INFO("svx.chaining", "[OnChaining] No Edit Outliner View");
+ }
+}
+
+IMPL_LINK_NOARG(SdrObjEditView, ImpAfterCutOrPasteChainingEventHdl, LinkParamNone*, void)
+{
+ SdrTextObj* pTextObj = GetTextEditObject();
+ if (!pTextObj)
+ return;
+ ImpChainingEventHdl();
+ TextChainCursorManager aCursorManager(this, pTextObj);
+ ImpMoveCursorAfterChainingEvent(&aCursorManager);
+}
+
+void SdrObjEditView::ImpMoveCursorAfterChainingEvent(TextChainCursorManager* pCursorManager)
+{
+ if (!mxWeakTextEditObj.is() || !pCursorManager)
+ return;
+
+ SdrTextObj* pTextObj = mxWeakTextEditObj.get();
+
+ // Check if it has links to move it to
+ if (!pTextObj || !pTextObj->IsChainable())
+ return;
+
+ TextChain* pTextChain = pTextObj->GetTextChain();
+ ESelection aNewSel = pTextChain->GetPostChainingSel(pTextObj);
+
+ pCursorManager->HandleCursorEventAfterChaining(pTextChain->GetCursorEvent(pTextObj), aNewSel);
+
+ // Reset event
+ pTextChain->SetCursorEvent(pTextObj, CursorChainingEvent::NULL_EVENT);
+}
+
+IMPL_LINK(SdrObjEditView, ImpOutlinerCalcFieldValueHdl, EditFieldInfo*, pFI, void)
+{
+ bool bOk = false;
+ OUString& rStr = pFI->GetRepresentation();
+ rStr.clear();
+ SdrTextObj* pTextObj = mxWeakTextEditObj.get();
+ if (pTextObj != nullptr)
+ {
+ std::optional<Color> pTxtCol;
+ std::optional<Color> pFldCol;
+ bOk = pTextObj->CalcFieldValue(pFI->GetField(), pFI->GetPara(), pFI->GetPos(), true,
+ pTxtCol, pFldCol, rStr);
+ if (bOk)
+ {
+ if (pTxtCol)
+ {
+ pFI->SetTextColor(*pTxtCol);
+ }
+ if (pFldCol)
+ {
+ pFI->SetFieldColor(*pFldCol);
+ }
+ else
+ {
+ pFI->SetFieldColor(COL_LIGHTGRAY); // TODO: remove this later on (357)
+ }
+ }
+ }
+ Outliner& rDrawOutl = mpModel->GetDrawOutliner(pTextObj);
+ Link<EditFieldInfo*, void> aDrawOutlLink = rDrawOutl.GetCalcFieldValueHdl();
+ if (!bOk && aDrawOutlLink.IsSet())
+ {
+ aDrawOutlLink.Call(pFI);
+ bOk = !rStr.isEmpty();
+ }
+ if (!bOk)
+ {
+ aOldCalcFieldValueLink.Call(pFI);
+ }
+}
+
+IMPL_LINK_NOARG(SdrObjEditView, EndTextEditHdl, SdrUndoManager*, void) { SdrEndTextEdit(); }
+
+// Default implementation - null UndoManager
+std::unique_ptr<SdrUndoManager> SdrObjEditView::createLocalTextUndoManager()
+{
+ SAL_WARN("svx", "SdrObjEditView::createLocalTextUndoManager needs to be overridden");
+ return std::unique_ptr<SdrUndoManager>();
+}
+
+bool SdrObjEditView::SdrBeginTextEdit(SdrObject* pObj_, SdrPageView* pPV, vcl::Window* pWin,
+ bool bIsNewObj, SdrOutliner* pGivenOutliner,
+ OutlinerView* pGivenOutlinerView, bool bDontDeleteOutliner,
+ bool bOnlyOneView, bool bGrabFocus)
+{
+ // FIXME cannot be an assert() yet, the code is not ready for that;
+ // eg. press F7 in Impress when you are inside a text object with spelling
+ // mistakes => boom; and it is unclear how to avoid that
+ SAL_WARN_IF(IsTextEdit(), "svx", "SdrBeginTextEdit called when IsTextEdit() is already true.");
+ // FIXME this encourages all sorts of bad habits and should be removed
+ SdrEndTextEdit();
+
+ SdrTextObj* pObj = dynamic_cast<SdrTextObj*>(pObj_);
+ if (!pObj)
+ return false; // currently only possible with text objects
+
+ if (bGrabFocus && pWin)
+ {
+ // attention, this call may cause an EndTextEdit() call to this view
+ pWin->GrabFocus(); // to force the cursor into the edit view
+ }
+
+ mbTextEditDontDelete = bDontDeleteOutliner && pGivenOutliner != nullptr;
+ mbTextEditOnlyOneView = bOnlyOneView;
+ mbTextEditNewObj = bIsNewObj;
+ const sal_uInt32 nWinCount(PaintWindowCount());
+
+ bool bBrk(false);
+
+ if (!pWin)
+ {
+ for (sal_uInt32 i = 0; i < nWinCount && !pWin; i++)
+ {
+ SdrPaintWindow* pPaintWindow = GetPaintWindow(i);
+
+ if (OUTDEV_WINDOW == pPaintWindow->GetOutputDevice().GetOutDevType())
+ {
+ pWin = pPaintWindow->GetOutputDevice().GetOwnerWindow();
+ }
+ }
+
+ // break, when no window exists
+ if (!pWin)
+ {
+ bBrk = true;
+ }
+ }
+
+ if (!bBrk && !pPV)
+ {
+ pPV = GetSdrPageView();
+
+ // break, when no PageView for the object exists
+ if (!pPV)
+ {
+ bBrk = true;
+ }
+ }
+
+ // no TextEdit on objects in locked Layer
+ if (pPV && pPV->GetLockedLayers().IsSet(pObj->GetLayer()))
+ {
+ bBrk = true;
+ }
+
+ if (mpTextEditOutliner)
+ {
+ OSL_FAIL("SdrObjEditView::SdrBeginTextEdit(): Old Outliner still exists.");
+ mpTextEditOutliner.reset();
+ }
+
+ if (!bBrk)
+ {
+ mpTextEditWin = pWin;
+ mpTextEditPV = pPV;
+ mxWeakTextEditObj.reset(pObj);
+ if (pGivenOutliner)
+ {
+ mpTextEditOutliner.reset(pGivenOutliner);
+ pGivenOutliner = nullptr; // so we don't delete it on the error path
+ }
+ else
+ mpTextEditOutliner = SdrMakeOutliner(OutlinerMode::TextObject,
+ mxWeakTextEditObj->getSdrModelFromSdrObject());
+
+ {
+ SvtAccessibilityOptions aOptions;
+ mpTextEditOutliner->ForceAutoColor(aOptions.GetIsAutomaticFontColor());
+ }
+
+ aOldCalcFieldValueLink = mpTextEditOutliner->GetCalcFieldValueHdl();
+ // FieldHdl has to be set by SdrBeginTextEdit, because this call an UpdateFields
+ mpTextEditOutliner->SetCalcFieldValueHdl(
+ LINK(this, SdrObjEditView, ImpOutlinerCalcFieldValueHdl));
+ mpTextEditOutliner->SetBeginPasteOrDropHdl(LINK(this, SdrObjEditView, BeginPasteOrDropHdl));
+ mpTextEditOutliner->SetEndPasteOrDropHdl(LINK(this, SdrObjEditView, EndPasteOrDropHdl));
+
+ // It is just necessary to make the visualized page known. Set it.
+ mpTextEditOutliner->setVisualizedPage(pPV->GetPage());
+
+ mpTextEditOutliner->SetTextObjNoInit(mxWeakTextEditObj.get());
+
+ if (mxWeakTextEditObj->BegTextEdit(*mpTextEditOutliner))
+ {
+ SdrTextObj* pTextObj = mxWeakTextEditObj.get();
+ DBG_ASSERT(pTextObj, "svx::SdrObjEditView::BegTextEdit(), no text object?");
+ if (!pTextObj)
+ return false;
+
+ // switch off any running TextAnimations
+ pTextObj->SetTextAnimationAllowed(false);
+
+ // remember old cursor
+ if (mpTextEditOutliner->GetViewCount() != 0)
+ {
+ mpTextEditOutliner->RemoveView(static_cast<size_t>(0));
+ }
+
+ // Determine EditArea via TakeTextEditArea.
+ // TODO: This could theoretically be left out, because TakeTextRect() calculates the aTextEditArea,
+ // but aMinTextEditArea has to happen, too (therefore leaving this in right now)
+ pTextObj->TakeTextEditArea(nullptr, nullptr, &aTextEditArea, &aMinTextEditArea);
+
+ tools::Rectangle aTextRect;
+ tools::Rectangle aAnchorRect;
+ pTextObj->TakeTextRect(*mpTextEditOutliner, aTextRect, true,
+ &aAnchorRect /* Give true here, not false */);
+
+ if (!pTextObj->IsContourTextFrame())
+ {
+ // FitToSize not together with ContourFrame, for now
+ if (pTextObj->IsFitToSize())
+ aTextRect = aAnchorRect;
+ }
+
+ aTextEditArea = aTextRect;
+
+ // add possible GridOffset to up-to-now view-independent EditAreas
+ basegfx::B2DVector aGridOffset(0.0, 0.0);
+ if (getPossibleGridOffsetForSdrObject(aGridOffset, pTextObj, pPV))
+ {
+ const Point aOffset(basegfx::fround(aGridOffset.getX()),
+ basegfx::fround(aGridOffset.getY()));
+
+ aTextEditArea += aOffset;
+ aMinTextEditArea += aOffset;
+ }
+
+ Point aPvOfs(pTextObj->GetTextEditOffset());
+ aTextEditArea.Move(aPvOfs.X(), aPvOfs.Y());
+ aMinTextEditArea.Move(aPvOfs.X(), aPvOfs.Y());
+ pTextEditCursorBuffer = pWin->GetCursor();
+
+ maHdlList.SetMoveOutside(true);
+
+ // Since IsMarkHdlWhenTextEdit() is ignored, it is necessary
+ // to call AdjustMarkHdl() always.
+ AdjustMarkHdl();
+
+ mpTextEditOutlinerView = ImpMakeOutlinerView(pWin, pGivenOutlinerView);
+
+ if (!comphelper::LibreOfficeKit::isActive() && mpTextEditOutlinerView)
+ {
+ // activate visualization of EditView on Overlay, suppress when
+ // LibreOfficeKit is active
+ mpTextEditOutlinerView->GetEditView().setEditViewCallbacks(this);
+
+ const Color aHilightColor(SvtOptionsDrawinglayer::getHilightColor());
+ const SdrTextObj* pText = GetTextEditObject();
+ const bool bTextFrame(pText && pText->IsTextFrame());
+ const bool bFitToSize(mpTextEditOutliner->GetControlWord()
+ & EEControlBits::STRETCHING);
+ const bool bVisualizeSurroundingFrame(bTextFrame && !bFitToSize);
+ SdrPageView* pPageView = GetSdrPageView();
+
+ if (pPageView)
+ {
+ for (sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if (rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference<sdr::overlay::OverlayManager>& xManager
+ = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ std::unique_ptr<TextEditOverlayObject> pNewTextEditOverlayObject(
+ new TextEditOverlayObject(aHilightColor,
+ *mpTextEditOutlinerView,
+ bVisualizeSurroundingFrame));
+
+ xManager->add(*pNewTextEditOverlayObject);
+ xManager->add(const_cast<sdr::overlay::OverlaySelection&>(
+ *pNewTextEditOverlayObject->getOverlaySelection()));
+
+ maTEOverlayGroup.append(std::move(pNewTextEditOverlayObject));
+ }
+ }
+ }
+ }
+ }
+
+ // check if this view is already inserted
+ size_t i2, nCount = mpTextEditOutliner->GetViewCount();
+ for (i2 = 0; i2 < nCount; i2++)
+ {
+ if (mpTextEditOutliner->GetView(i2) == mpTextEditOutlinerView)
+ break;
+ }
+
+ if (i2 == nCount)
+ mpTextEditOutliner->InsertView(mpTextEditOutlinerView, 0);
+
+ maHdlList.SetMoveOutside(false);
+ maHdlList.SetMoveOutside(true);
+
+ // register all windows as OutlinerViews with the Outliner
+ if (!bOnlyOneView)
+ {
+ for (sal_uInt32 i = 0; i < nWinCount; i++)
+ {
+ SdrPaintWindow* pPaintWindow = GetPaintWindow(i);
+ OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
+
+ if (&rOutDev != pWin->GetOutDev() && OUTDEV_WINDOW == rOutDev.GetOutDevType())
+ {
+ OutlinerView* pOutlView
+ = ImpMakeOutlinerView(rOutDev.GetOwnerWindow(), nullptr);
+ mpTextEditOutliner->InsertView(pOutlView, static_cast<sal_uInt16>(i));
+ }
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // Register an outliner view for all other sdr views that
+ // show the same page, so that when the text edit changes,
+ // all interested windows get an invalidation.
+ SdrViewIter aIter(pObj->getSdrPageFromSdrObject());
+ for (SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView())
+ {
+ if (pView == this)
+ continue;
+
+ for (sal_uInt32 nViewPaintWindow = 0;
+ nViewPaintWindow < pView->PaintWindowCount(); ++nViewPaintWindow)
+ {
+ SdrPaintWindow* pPaintWindow = pView->GetPaintWindow(nViewPaintWindow);
+ OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
+
+ if (&rOutDev != pWin->GetOutDev()
+ && OUTDEV_WINDOW == rOutDev.GetOutDevType())
+ {
+ OutlinerView* pOutlView
+ = ImpMakeOutlinerView(rOutDev.GetOwnerWindow(), nullptr);
+ pOutlView->HideCursor();
+ rOutDev.GetOwnerWindow()->SetCursor(nullptr);
+ mpTextEditOutliner->InsertView(pOutlView);
+ }
+ }
+ }
+ }
+ }
+
+ mpTextEditOutlinerView->ShowCursor();
+ mpTextEditOutliner->SetStatusEventHdl(
+ LINK(this, SdrObjEditView, ImpOutlinerStatusEventHdl));
+ if (pTextObj->IsChainable())
+ {
+ mpTextEditOutlinerView->SetEndCutPasteLinkHdl(
+ LINK(this, SdrObjEditView, ImpAfterCutOrPasteChainingEventHdl));
+ }
+
+ mpTextEditOutliner->ClearModifyFlag();
+
+ if (pTextObj->IsFitToSize())
+ {
+ pWin->Invalidate(aTextEditArea);
+ }
+
+ if (GetModel())
+ {
+ SdrHint aHint(SdrHintKind::BeginEdit, *pTextObj);
+ GetModel()->Broadcast(aHint);
+ }
+
+ mpTextEditOutliner->setVisualizedPage(nullptr);
+
+ if (mxSelectionController.is())
+ mxSelectionController->onSelectionHasChanged();
+
+ if (GetModel() && IsUndoEnabled()
+ && !GetModel()->GetDisableTextEditUsesCommonUndoManager())
+ {
+ SdrUndoManager* pSdrUndoManager = nullptr;
+ mpLocalTextEditUndoManager = createLocalTextUndoManager();
+
+ if (mpLocalTextEditUndoManager)
+ pSdrUndoManager = mpLocalTextEditUndoManager.get();
+
+ if (pSdrUndoManager)
+ {
+ // we have an outliner, undo manager and it's an EditUndoManager, exchange
+ // the document undo manager and the default one from the outliner and tell
+ // it that text edit starts by setting a callback if it needs to end text edit mode.
+ assert(nullptr == mpOldTextEditUndoManager);
+
+ mpOldTextEditUndoManager = mpTextEditOutliner->SetUndoManager(pSdrUndoManager);
+ pSdrUndoManager->SetEndTextEditHdl(LINK(this, SdrObjEditView, EndTextEditHdl));
+ }
+ else
+ {
+ OSL_ENSURE(false,
+ "The document undo manager is not derived from SdrUndoManager (!)");
+ }
+ }
+
+ return true; // ran fine, let TextEdit run now
+ }
+ else
+ {
+ mpTextEditOutliner->SetCalcFieldValueHdl(aOldCalcFieldValueLink);
+ mpTextEditOutliner->SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*, void>());
+ mpTextEditOutliner->SetEndPasteOrDropHdl(Link<PasteOrDropInfos*, void>());
+ }
+ }
+ if (mpTextEditOutliner != nullptr)
+ {
+ mpTextEditOutliner->setVisualizedPage(nullptr);
+ }
+
+ // something went wrong...
+ if (!bDontDeleteOutliner)
+ {
+ delete pGivenOutliner;
+ if (pGivenOutlinerView != nullptr)
+ {
+ delete pGivenOutlinerView;
+ pGivenOutlinerView = nullptr;
+ }
+ }
+ mpTextEditOutliner.reset();
+
+ mpTextEditOutlinerView = nullptr;
+ mxWeakTextEditObj.reset(nullptr);
+ mpTextEditPV = nullptr;
+ mpTextEditWin = nullptr;
+ maHdlList.SetMoveOutside(false);
+
+ return false;
+}
+
+SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally)
+{
+ SdrEndTextEditKind eRet = SdrEndTextEditKind::Unchanged;
+ SdrTextObj* pTEObj = mxWeakTextEditObj.get();
+ vcl::Window* pTEWin = mpTextEditWin;
+ OutlinerView* pTEOutlinerView = mpTextEditOutlinerView;
+ vcl::Cursor* pTECursorBuffer = pTextEditCursorBuffer;
+ SdrUndoManager* pUndoEditUndoManager = nullptr;
+ bool bNeedToUndoSavedRedoTextEdit(false);
+
+ if (GetModel() && IsUndoEnabled() && pTEObj && mpTextEditOutliner
+ && !GetModel()->GetDisableTextEditUsesCommonUndoManager())
+ {
+ // change back the UndoManager to the remembered original one
+ SfxUndoManager* pOriginal = mpTextEditOutliner->SetUndoManager(mpOldTextEditUndoManager);
+ mpOldTextEditUndoManager = nullptr;
+
+ if (pOriginal)
+ {
+ // check if we got back our document undo manager
+ SdrUndoManager* pSdrUndoManager = mpLocalTextEditUndoManager.get();
+
+ if (pSdrUndoManager && dynamic_cast<SdrUndoManager*>(pOriginal) == pSdrUndoManager)
+ {
+ if (pSdrUndoManager->isEndTextEditTriggeredFromUndo())
+ {
+ // remember the UndoManager where missing Undos have to be triggered after end
+ // text edit. When the undo had triggered the end text edit, the original action
+ // which had to be undone originally is not yet undone.
+ pUndoEditUndoManager = pSdrUndoManager;
+
+ // We are ending text edit; if text edit was triggered from undo, execute all redos
+ // to create a complete text change undo action for the redo buffer. Also mark this
+ // state when at least one redo was executed; the created extra TextChange needs to
+ // be undone in addition to the first real undo outside the text edit changes
+ while (pSdrUndoManager->GetRedoActionCount()
+ > pSdrUndoManager->GetRedoActionCountBeforeTextEdit())
+ {
+ bNeedToUndoSavedRedoTextEdit = true;
+ pSdrUndoManager->Redo();
+ }
+ }
+
+ // reset the callback link and let the undo manager cleanup all text edit
+ // undo actions to get the stack back to the form before the text edit
+ pSdrUndoManager->SetEndTextEditHdl(Link<SdrUndoManager*, void>());
+ }
+ else
+ {
+ OSL_ENSURE(false, "Got UndoManager back in SdrEndTextEdit which is NOT the "
+ "expected document UndoManager (!)");
+ delete pOriginal;
+ }
+
+ // cid#1493241 - Wrapper object use after free
+ if (pUndoEditUndoManager == mpLocalTextEditUndoManager.get())
+ pUndoEditUndoManager = nullptr;
+ mpLocalTextEditUndoManager.reset();
+ }
+ }
+ else
+ {
+ assert(nullptr == mpOldTextEditUndoManager); // cannot be restored!
+ }
+
+ if (GetModel() && mxWeakTextEditObj.is())
+ {
+ SdrHint aHint(SdrHintKind::EndEdit, *mxWeakTextEditObj);
+ GetModel()->Broadcast(aHint);
+ }
+
+ // if new mechanism was used, clean it up. At cleanup no need to check
+ // for LibreOfficeKit
+ if (mpTextEditOutlinerView)
+ {
+ mpTextEditOutlinerView->GetEditView().setEditViewCallbacks(nullptr);
+ maTEOverlayGroup.clear();
+ }
+
+ mxWeakTextEditObj.reset(nullptr);
+ mpTextEditPV = nullptr;
+ mpTextEditWin = nullptr;
+ SdrOutliner* pTEOutliner = mpTextEditOutliner.release();
+ mpTextEditOutlinerView = nullptr;
+ pTextEditCursorBuffer = nullptr;
+ aTextEditArea = tools::Rectangle();
+
+ if (pTEOutliner != nullptr)
+ {
+ bool bModified = pTEOutliner->IsModified();
+ if (pTEOutlinerView != nullptr)
+ {
+ pTEOutlinerView->HideCursor();
+ }
+ if (pTEObj != nullptr)
+ {
+ pTEOutliner->CompleteOnlineSpelling();
+
+ std::unique_ptr<SdrUndoObjSetText> pTxtUndo;
+
+ if (bModified)
+ {
+ sal_Int32 nText;
+ for (nText = 0; nText < pTEObj->getTextCount(); ++nText)
+ if (pTEObj->getText(nText) == pTEObj->getActiveText())
+ break;
+
+ pTxtUndo.reset(
+ dynamic_cast<SdrUndoObjSetText*>(GetModel()
+ ->GetSdrUndoFactory()
+ .CreateUndoObjectSetText(*pTEObj, nText)
+ .release()));
+ }
+ DBG_ASSERT(!bModified || pTxtUndo,
+ "svx::SdrObjEditView::EndTextEdit(), could not create undo action!");
+ // Set old CalcFieldValue-Handler again, this
+ // has to happen before Obj::EndTextEdit(), as this does UpdateFields().
+ pTEOutliner->SetCalcFieldValueHdl(aOldCalcFieldValueLink);
+ pTEOutliner->SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*, void>());
+ pTEOutliner->SetEndPasteOrDropHdl(Link<PasteOrDropInfos*, void>());
+
+ const bool bUndo = IsUndoEnabled();
+ if (bUndo)
+ {
+ OUString aObjName(pTEObj->TakeObjNameSingul());
+ BegUndo(SvxResId(STR_UndoObjSetText), aObjName);
+ }
+
+ pTEObj->EndTextEdit(*pTEOutliner);
+
+ if ((pTEObj->GetRotateAngle() != 0_deg100) || (pTEObj && pTEObj->IsFontwork()))
+ {
+ pTEObj->ActionChanged();
+ }
+
+ if (pTxtUndo != nullptr)
+ {
+ pTxtUndo->AfterSetText();
+ if (!pTxtUndo->IsDifferent())
+ {
+ pTxtUndo.reset();
+ }
+ }
+ // check deletion of entire TextObj
+ std::unique_ptr<SdrUndoAction> pDelUndo;
+ bool bDelObj = false;
+ if (mbTextEditNewObj)
+ {
+ bDelObj = pTEObj->IsTextFrame() && !pTEObj->HasText() && !pTEObj->IsEmptyPresObj()
+ && !pTEObj->HasFill() && !pTEObj->HasLine();
+
+ if (pTEObj->IsInserted() && bDelObj
+ && pTEObj->GetObjInventor() == SdrInventor::Default && !bDontDeleteReally)
+ {
+ SdrObjKind eIdent = pTEObj->GetObjIdentifier();
+ if (eIdent == SdrObjKind::Text)
+ {
+ pDelUndo = GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pTEObj);
+ }
+ }
+ }
+ if (pTxtUndo)
+ {
+ if (bUndo)
+ AddUndo(std::move(pTxtUndo));
+ eRet = SdrEndTextEditKind::Changed;
+ }
+ if (pDelUndo != nullptr)
+ {
+ if (bUndo)
+ {
+ AddUndo(std::move(pDelUndo));
+ }
+ eRet = SdrEndTextEditKind::Deleted;
+ DBG_ASSERT(pTEObj->getParentSdrObjListFromSdrObject() != nullptr,
+ "SdrObjEditView::SdrEndTextEdit(): Fatal: Object edited doesn't have an "
+ "ObjList!");
+ if (pTEObj->getParentSdrObjListFromSdrObject() != nullptr)
+ {
+ pTEObj->getParentSdrObjListFromSdrObject()->RemoveObject(pTEObj->GetOrdNum());
+ CheckMarked(); // remove selection immediately...
+ }
+ }
+ else if (bDelObj)
+ { // for Writer: the app has to do the deletion itself.
+ eRet = SdrEndTextEditKind::ShouldBeDeleted;
+ }
+
+ if (bUndo)
+ EndUndo(); // EndUndo after Remove, in case UndoStack is deleted immediately
+
+ // Switch on any TextAnimation again after TextEdit
+ if (pTEObj)
+ {
+ pTEObj->SetTextAnimationAllowed(true);
+ }
+
+ // Since IsMarkHdlWhenTextEdit() is ignored, it is necessary
+ // to call AdjustMarkHdl() always.
+ AdjustMarkHdl();
+ }
+ // delete all OutlinerViews
+ for (size_t i = pTEOutliner->GetViewCount(); i > 0;)
+ {
+ i--;
+ OutlinerView* pOLV = pTEOutliner->GetView(i);
+ sal_uInt16 nMorePix = pOLV->GetInvalidateMore() + 10;
+ vcl::Window* pWin = pOLV->GetWindow();
+ tools::Rectangle aRect(pOLV->GetOutputArea());
+ pTEOutliner->RemoveView(i);
+ if (!mbTextEditDontDelete || i != 0)
+ {
+ // may not own the zeroth one
+ delete pOLV;
+ }
+ aRect.Union(aTextEditArea);
+ aRect.Union(aMinTextEditArea);
+ aRect = pWin->LogicToPixel(aRect);
+ aRect.AdjustLeft(-nMorePix);
+ aRect.AdjustTop(-nMorePix);
+ aRect.AdjustRight(nMorePix);
+ aRect.AdjustBottom(nMorePix);
+ aRect = pWin->PixelToLogic(aRect);
+ InvalidateOneWin(*pWin->GetOutDev(), aRect);
+ pWin->GetOutDev()->SetFillColor();
+ pWin->GetOutDev()->SetLineColor(COL_BLACK);
+ }
+ // and now the Outliner itself
+ if (!mbTextEditDontDelete)
+ delete pTEOutliner;
+ else
+ pTEOutliner->Clear();
+ if (pTEWin != nullptr)
+ {
+ pTEWin->SetCursor(pTECursorBuffer);
+ }
+ maHdlList.SetMoveOutside(false);
+ if (eRet != SdrEndTextEditKind::Unchanged)
+ {
+ GetMarkedObjectListWriteAccess().SetNameDirty();
+ }
+ }
+
+ if (pTEObj && !pTEObj->getSdrModelFromSdrObject().isLocked() && pTEObj->GetBroadcaster())
+ {
+ SdrHint aHint(SdrHintKind::EndEdit, *pTEObj);
+ const_cast<SfxBroadcaster*>(pTEObj->GetBroadcaster())->Broadcast(aHint);
+ }
+
+ if (pUndoEditUndoManager)
+ {
+ if (bNeedToUndoSavedRedoTextEdit)
+ {
+ // undo the text edit action since it was created as part of an EndTextEdit
+ // callback from undo itself. This needs to be done after the call to
+ // FmFormView::SdrEndTextEdit since it gets created there
+ pUndoEditUndoManager->Undo();
+ }
+
+ // trigger the Undo which was not executed, but lead to this
+ // end text edit
+ pUndoEditUndoManager->Undo();
+ }
+
+ return eRet;
+}
+
+// info about TextEdit. Default is false.
+bool SdrObjEditView::IsTextEdit() const { return mxWeakTextEditObj.is(); }
+
+// info about TextEditPageView. Default is 0L.
+SdrPageView* SdrObjEditView::GetTextEditPageView() const { return mpTextEditPV; }
+
+OutlinerView* SdrObjEditView::ImpFindOutlinerView(vcl::Window const* pWin) const
+{
+ if (pWin == nullptr)
+ return nullptr;
+ if (mpTextEditOutliner == nullptr)
+ return nullptr;
+ OutlinerView* pNewView = nullptr;
+ size_t nWinCount = mpTextEditOutliner->GetViewCount();
+ for (size_t i = 0; i < nWinCount && pNewView == nullptr; i++)
+ {
+ OutlinerView* pView = mpTextEditOutliner->GetView(i);
+ if (pView->GetWindow() == pWin)
+ pNewView = pView;
+ }
+ return pNewView;
+}
+
+void SdrObjEditView::SetTextEditWin(vcl::Window* pWin)
+{
+ if (!(mxWeakTextEditObj.is() && pWin != nullptr && pWin != mpTextEditWin))
+ return;
+
+ OutlinerView* pNewView = ImpFindOutlinerView(pWin);
+ if (pNewView != nullptr && pNewView != mpTextEditOutlinerView)
+ {
+ if (mpTextEditOutlinerView != nullptr)
+ {
+ mpTextEditOutlinerView->HideCursor();
+ }
+ mpTextEditOutlinerView = pNewView;
+ mpTextEditWin = pWin;
+ pWin->GrabFocus(); // Make the cursor blink here as well
+ pNewView->ShowCursor();
+ ImpMakeTextCursorAreaVisible();
+ }
+}
+
+bool SdrObjEditView::IsTextEditHit(const Point& rHit) const
+{
+ bool bOk = false;
+ if (mxWeakTextEditObj.is())
+ {
+ tools::Rectangle aEditArea;
+ if (OutlinerView* pOLV = mpTextEditOutliner->GetView(0))
+ aEditArea.Union(pOLV->GetOutputArea());
+
+ if (aEditArea.Contains(rHit))
+ { // check if any characters were actually hit
+ const Point aPnt(rHit - aEditArea.TopLeft());
+ tools::Long nHitTol = 2000;
+ if (OutputDevice* pRef = mpTextEditOutliner->GetRefDevice())
+ nHitTol = OutputDevice::LogicToLogic(nHitTol, MapUnit::Map100thMM,
+ pRef->GetMapMode().GetMapUnit());
+
+ bOk = mpTextEditOutliner->IsTextPos(aPnt, static_cast<sal_uInt16>(nHitTol));
+ }
+ }
+ return bOk;
+}
+
+bool SdrObjEditView::IsTextEditFrameHit(const Point& rHit) const
+{
+ bool bOk = false;
+ if (mxWeakTextEditObj.is())
+ {
+ SdrTextObj* pText = mxWeakTextEditObj.get();
+ OutlinerView* pOLV = mpTextEditOutliner->GetView(0);
+ if (pOLV)
+ {
+ vcl::Window* pWin = pOLV->GetWindow();
+ if (pText != nullptr && pText->IsTextFrame() && pWin != nullptr)
+ {
+ sal_uInt16 nPixSiz = pOLV->GetInvalidateMore();
+ tools::Rectangle aEditArea(aMinTextEditArea);
+ aEditArea.Union(pOLV->GetOutputArea());
+ if (!aEditArea.Contains(rHit))
+ {
+ Size aSiz(pWin->PixelToLogic(Size(nPixSiz, nPixSiz)));
+ aEditArea.AdjustLeft(-(aSiz.Width()));
+ aEditArea.AdjustTop(-(aSiz.Height()));
+ aEditArea.AdjustRight(aSiz.Width());
+ aEditArea.AdjustBottom(aSiz.Height());
+ bOk = aEditArea.Contains(rHit);
+ }
+ }
+ }
+ }
+ return bOk;
+}
+
+std::unique_ptr<TextChainCursorManager>
+SdrObjEditView::ImpHandleMotionThroughBoxesKeyInput(const KeyEvent& rKEvt, bool* bOutHandled)
+{
+ *bOutHandled = false;
+
+ SdrTextObj* pTextObj = mxWeakTextEditObj.get();
+ if (!pTextObj)
+ return nullptr;
+
+ if (!pTextObj->GetNextLinkInChain() && !pTextObj->GetPrevLinkInChain())
+ return nullptr;
+
+ std::unique_ptr<TextChainCursorManager> pCursorManager(
+ new TextChainCursorManager(this, pTextObj));
+ if (pCursorManager->HandleKeyEvent(rKEvt))
+ {
+ // Possibly do other stuff here if necessary...
+ // XXX: Careful with the checks below (in KeyInput) for pWin and co. You should do them here I guess.
+ *bOutHandled = true;
+ }
+
+ return pCursorManager;
+}
+
+bool SdrObjEditView::KeyInput(const KeyEvent& rKEvt, vcl::Window* pWin)
+{
+ if (mpTextEditOutlinerView)
+ {
+ /* Start special handling of keys within a chain */
+ // We possibly move to another box before any handling
+ bool bHandled = false;
+ std::unique_ptr<TextChainCursorManager> xCursorManager(
+ ImpHandleMotionThroughBoxesKeyInput(rKEvt, &bHandled));
+ if (bHandled)
+ return true;
+ /* End special handling of keys within a chain */
+
+ if (mpTextEditOutlinerView->PostKeyEvent(rKEvt, pWin))
+ {
+ if (mpModel)
+ {
+ if (mpTextEditOutliner && mpTextEditOutliner->IsModified())
+ mpModel->SetChanged();
+ }
+
+ /* Start chaining processing */
+ ImpChainingEventHdl();
+ ImpMoveCursorAfterChainingEvent(xCursorManager.get());
+ /* End chaining processing */
+
+ if (pWin != nullptr && pWin != mpTextEditWin)
+ SetTextEditWin(pWin);
+ ImpMakeTextCursorAreaVisible();
+ return true;
+ }
+ }
+ return SdrGlueEditView::KeyInput(rKEvt, pWin);
+}
+
+bool SdrObjEditView::MouseButtonDown(const MouseEvent& rMEvt, OutputDevice* pWin)
+{
+ if (mpTextEditOutlinerView != nullptr)
+ {
+ bool bPostIt = mpTextEditOutliner->IsInSelectionMode();
+ if (!bPostIt)
+ {
+ Point aPt(rMEvt.GetPosPixel());
+ if (pWin != nullptr)
+ aPt = pWin->PixelToLogic(aPt);
+ else if (mpTextEditWin != nullptr)
+ aPt = mpTextEditWin->PixelToLogic(aPt);
+ bPostIt = IsTextEditHit(aPt);
+ }
+ if (bPostIt)
+ {
+ Point aPixPos(rMEvt.GetPosPixel());
+ if (pWin)
+ {
+ tools::Rectangle aR(pWin->LogicToPixel(mpTextEditOutlinerView->GetOutputArea()));
+ if (aPixPos.X() < aR.Left())
+ aPixPos.setX(aR.Left());
+ if (aPixPos.X() > aR.Right())
+ aPixPos.setX(aR.Right());
+ if (aPixPos.Y() < aR.Top())
+ aPixPos.setY(aR.Top());
+ if (aPixPos.Y() > aR.Bottom())
+ aPixPos.setY(aR.Bottom());
+ }
+ MouseEvent aMEvt(aPixPos, rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(),
+ rMEvt.GetModifier());
+ if (mpTextEditOutlinerView->MouseButtonDown(aMEvt))
+ {
+ if (pWin != nullptr && pWin != mpTextEditWin->GetOutDev()
+ && pWin->GetOutDevType() == OUTDEV_WINDOW)
+ SetTextEditWin(pWin->GetOwnerWindow());
+ ImpMakeTextCursorAreaVisible();
+ return true;
+ }
+ }
+ }
+ return SdrGlueEditView::MouseButtonDown(rMEvt, pWin);
+}
+
+bool SdrObjEditView::MouseButtonUp(const MouseEvent& rMEvt, OutputDevice* pWin)
+{
+ if (mpTextEditOutlinerView != nullptr)
+ {
+ bool bPostIt = mpTextEditOutliner->IsInSelectionMode();
+ if (!bPostIt)
+ {
+ Point aPt(rMEvt.GetPosPixel());
+ if (pWin != nullptr)
+ aPt = pWin->PixelToLogic(aPt);
+ else if (mpTextEditWin != nullptr)
+ aPt = mpTextEditWin->PixelToLogic(aPt);
+ bPostIt = IsTextEditHit(aPt);
+ }
+ if (bPostIt && pWin)
+ {
+ Point aPixPos(rMEvt.GetPosPixel());
+ tools::Rectangle aR(pWin->LogicToPixel(mpTextEditOutlinerView->GetOutputArea()));
+ if (aPixPos.X() < aR.Left())
+ aPixPos.setX(aR.Left());
+ if (aPixPos.X() > aR.Right())
+ aPixPos.setX(aR.Right());
+ if (aPixPos.Y() < aR.Top())
+ aPixPos.setY(aR.Top());
+ if (aPixPos.Y() > aR.Bottom())
+ aPixPos.setY(aR.Bottom());
+ MouseEvent aMEvt(aPixPos, rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(),
+ rMEvt.GetModifier());
+ if (mpTextEditOutlinerView->MouseButtonUp(aMEvt))
+ {
+ ImpMakeTextCursorAreaVisible();
+ return true;
+ }
+ }
+ }
+ return SdrGlueEditView::MouseButtonUp(rMEvt, pWin);
+}
+
+bool SdrObjEditView::MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin)
+{
+ if (mpTextEditOutlinerView != nullptr)
+ {
+ bool bSelMode = mpTextEditOutliner->IsInSelectionMode();
+ bool bPostIt = bSelMode;
+ if (!bPostIt)
+ {
+ Point aPt(rMEvt.GetPosPixel());
+ if (pWin)
+ aPt = pWin->PixelToLogic(aPt);
+ else if (mpTextEditWin)
+ aPt = mpTextEditWin->PixelToLogic(aPt);
+ bPostIt = IsTextEditHit(aPt);
+ }
+ if (bPostIt)
+ {
+ Point aPixPos(rMEvt.GetPosPixel());
+ tools::Rectangle aR(mpTextEditOutlinerView->GetOutputArea());
+ if (pWin)
+ aR = pWin->LogicToPixel(aR);
+ else if (mpTextEditWin)
+ aR = mpTextEditWin->LogicToPixel(aR);
+ if (aPixPos.X() < aR.Left())
+ aPixPos.setX(aR.Left());
+ if (aPixPos.X() > aR.Right())
+ aPixPos.setX(aR.Right());
+ if (aPixPos.Y() < aR.Top())
+ aPixPos.setY(aR.Top());
+ if (aPixPos.Y() > aR.Bottom())
+ aPixPos.setY(aR.Bottom());
+ MouseEvent aMEvt(aPixPos, rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(),
+ rMEvt.GetModifier());
+ if (mpTextEditOutlinerView->MouseMove(aMEvt) && bSelMode)
+ {
+ ImpMakeTextCursorAreaVisible();
+ return true;
+ }
+ }
+ }
+ return SdrGlueEditView::MouseMove(rMEvt, pWin);
+}
+
+bool SdrObjEditView::Command(const CommandEvent& rCEvt, vcl::Window* pWin)
+{
+ // as long as OutlinerView returns a sal_Bool, it only gets CommandEventId::StartDrag
+ if (mpTextEditOutlinerView != nullptr)
+ {
+ if (rCEvt.GetCommand() == CommandEventId::StartDrag)
+ {
+ bool bPostIt = mpTextEditOutliner->IsInSelectionMode() || !rCEvt.IsMouseEvent();
+ if (!bPostIt && rCEvt.IsMouseEvent())
+ {
+ Point aPt(rCEvt.GetMousePosPixel());
+ if (pWin != nullptr)
+ aPt = pWin->PixelToLogic(aPt);
+ else if (mpTextEditWin != nullptr)
+ aPt = mpTextEditWin->PixelToLogic(aPt);
+ bPostIt = IsTextEditHit(aPt);
+ }
+ if (bPostIt)
+ {
+ Point aPixPos(rCEvt.GetMousePosPixel());
+ if (rCEvt.IsMouseEvent() && pWin)
+ {
+ tools::Rectangle aR(
+ pWin->LogicToPixel(mpTextEditOutlinerView->GetOutputArea()));
+ if (aPixPos.X() < aR.Left())
+ aPixPos.setX(aR.Left());
+ if (aPixPos.X() > aR.Right())
+ aPixPos.setX(aR.Right());
+ if (aPixPos.Y() < aR.Top())
+ aPixPos.setY(aR.Top());
+ if (aPixPos.Y() > aR.Bottom())
+ aPixPos.setY(aR.Bottom());
+ }
+ CommandEvent aCEvt(aPixPos, rCEvt.GetCommand(), rCEvt.IsMouseEvent());
+ // Command is void at the OutlinerView, sadly
+ mpTextEditOutlinerView->Command(aCEvt);
+ if (pWin != nullptr && pWin != mpTextEditWin)
+ SetTextEditWin(pWin);
+ ImpMakeTextCursorAreaVisible();
+ return true;
+ }
+ }
+ else
+ {
+ mpTextEditOutlinerView->Command(rCEvt);
+ if (mpModel && comphelper::LibreOfficeKit::isActive())
+ {
+ // It could execute CommandEventId::ExtTextInput, while SdrObjEditView::KeyInput
+ // isn't called
+ if (mpTextEditOutliner && mpTextEditOutliner->IsModified())
+ mpModel->SetChanged();
+ }
+ return true;
+ }
+ }
+ return SdrGlueEditView::Command(rCEvt, pWin);
+}
+
+bool SdrObjEditView::ImpIsTextEditAllSelected() const
+{
+ bool bRet = false;
+ if (mpTextEditOutliner != nullptr && mpTextEditOutlinerView != nullptr)
+ {
+ if (SdrTextObj::HasTextImpl(mpTextEditOutliner.get()))
+ {
+ const sal_Int32 nParaCnt = mpTextEditOutliner->GetParagraphCount();
+ Paragraph* pLastPara
+ = mpTextEditOutliner->GetParagraph(nParaCnt > 1 ? nParaCnt - 1 : 0);
+
+ ESelection aESel(mpTextEditOutlinerView->GetSelection());
+ if (aESel.nStartPara == 0 && aESel.nStartPos == 0 && aESel.nEndPara == (nParaCnt - 1))
+ {
+ if (mpTextEditOutliner->GetText(pLastPara).getLength() == aESel.nEndPos)
+ bRet = true;
+ }
+ // in case the selection was done backwards
+ if (!bRet && aESel.nEndPara == 0 && aESel.nEndPos == 0
+ && aESel.nStartPara == (nParaCnt - 1))
+ {
+ if (mpTextEditOutliner->GetText(pLastPara).getLength() == aESel.nStartPos)
+ bRet = true;
+ }
+ }
+ else
+ {
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+void SdrObjEditView::ImpMakeTextCursorAreaVisible()
+{
+ if (mpTextEditOutlinerView != nullptr && mpTextEditWin != nullptr)
+ {
+ vcl::Cursor* pCsr = mpTextEditWin->GetCursor();
+ if (pCsr != nullptr)
+ {
+ Size aSiz(pCsr->GetSize());
+ if (!aSiz.IsEmpty())
+ {
+ MakeVisible(tools::Rectangle(pCsr->GetPos(), aSiz), *mpTextEditWin);
+ }
+ }
+ }
+}
+
+SvtScriptType SdrObjEditView::GetScriptType() const
+{
+ SvtScriptType nScriptType = SvtScriptType::NONE;
+
+ if (IsTextEdit())
+ {
+ if (mxWeakTextEditObj->GetOutlinerParaObject())
+ nScriptType
+ = mxWeakTextEditObj->GetOutlinerParaObject()->GetTextObject().GetScriptType();
+
+ if (mpTextEditOutlinerView)
+ nScriptType = mpTextEditOutlinerView->GetSelectedScriptType();
+ }
+ else
+ {
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for (size_t i = 0; i < nMarkCount; ++i)
+ {
+ OutlinerParaObject* pParaObj = GetMarkedObjectByIndex(i)->GetOutlinerParaObject();
+
+ if (pParaObj)
+ {
+ nScriptType |= pParaObj->GetTextObject().GetScriptType();
+ }
+ }
+ }
+
+ if (nScriptType == SvtScriptType::NONE)
+ nScriptType = SvtScriptType::LATIN;
+
+ return nScriptType;
+}
+
+void SdrObjEditView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
+{
+ if (mxSelectionController.is())
+ if (mxSelectionController->GetAttributes(rTargetSet, bOnlyHardAttr))
+ return;
+
+ if (IsTextEdit())
+ {
+ DBG_ASSERT(mpTextEditOutlinerView != nullptr,
+ "SdrObjEditView::GetAttributes(): mpTextEditOutlinerView=NULL");
+ DBG_ASSERT(mpTextEditOutliner != nullptr,
+ "SdrObjEditView::GetAttributes(): mpTextEditOutliner=NULL");
+
+ // take care of bOnlyHardAttr(!)
+ if (!bOnlyHardAttr && mxWeakTextEditObj->GetStyleSheet())
+ rTargetSet.Put(mxWeakTextEditObj->GetStyleSheet()->GetItemSet());
+
+ // add object attributes
+ rTargetSet.Put(mxWeakTextEditObj->GetMergedItemSet());
+
+ if (mpTextEditOutlinerView)
+ {
+ // FALSE= regard InvalidItems as "holes," not as Default
+ rTargetSet.Put(mpTextEditOutlinerView->GetAttribs(), false);
+ }
+
+ if (GetMarkedObjectCount() == 1 && GetMarkedObjectByIndex(0) == mxWeakTextEditObj.get())
+ {
+ MergeNotPersistAttrFromMarked(rTargetSet);
+ }
+ }
+ else
+ {
+ SdrGlueEditView::GetAttributes(rTargetSet, bOnlyHardAttr);
+ }
+}
+
+bool SdrObjEditView::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
+{
+ bool bRet = false;
+ bool bTextEdit = mpTextEditOutlinerView != nullptr && mxWeakTextEditObj.is();
+ bool bAllTextSelected = ImpIsTextEditAllSelected();
+ const SfxItemSet* pSet = &rSet;
+
+ if (!bTextEdit)
+ {
+ // no TextEdit active -> all Items to drawing object
+ if (mxSelectionController.is())
+ bRet = mxSelectionController->SetAttributes(*pSet, bReplaceAll);
+
+ if (!bRet)
+ {
+ SdrGlueEditView::SetAttributes(*pSet, bReplaceAll);
+ bRet = true;
+ }
+ }
+ else
+ {
+#ifdef DBG_UTIL
+ {
+ bool bHasEEFeatureItems = false;
+ SfxItemIter aIter(rSet);
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); !bHasEEFeatureItems && pItem;
+ pItem = aIter.NextItem())
+ {
+ if (!IsInvalidItem(pItem))
+ {
+ sal_uInt16 nW = pItem->Which();
+ if (nW >= EE_FEATURE_START && nW <= EE_FEATURE_END)
+ bHasEEFeatureItems = true;
+ }
+ }
+
+ if (bHasEEFeatureItems)
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(
+ nullptr, VclMessageType::Info, VclButtonsType::Ok,
+ "SdrObjEditView::SetAttributes(): Setting EE_FEATURE items "
+ "at the SdrView does not make sense! It only leads to "
+ "overhead and unreadable documents."));
+ xInfoBox->run();
+ }
+ }
+#endif
+
+ bool bOnlyEEItems;
+ bool bNoEEItems = !SearchOutlinerItems(*pSet, bReplaceAll, &bOnlyEEItems);
+ // everything selected? -> attributes to the border, too
+ // if no EEItems, attributes to the border only
+ if (bAllTextSelected || bNoEEItems)
+ {
+ if (mxSelectionController.is())
+ bRet = mxSelectionController->SetAttributes(*pSet, bReplaceAll);
+
+ if (!bRet)
+ {
+ const bool bUndo = IsUndoEnabled();
+
+ if (bUndo)
+ {
+ BegUndo(ImpGetDescriptionString(STR_EditSetAttributes));
+ AddUndo(
+ GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*mxWeakTextEditObj));
+
+ // If this is a text object also rescue the OutlinerParaObject since
+ // applying attributes to the object may change text layout when
+ // multiple portions exist with multiple formats. If an OutlinerParaObject
+ // really exists and needs to be rescued is evaluated in the undo
+ // implementation itself.
+ bool bRescueText = mxWeakTextEditObj;
+
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(
+ *mxWeakTextEditObj, false, !bNoEEItems || bRescueText));
+ EndUndo();
+ }
+
+ mxWeakTextEditObj->SetMergedItemSetAndBroadcast(*pSet, bReplaceAll);
+
+ FlushComeBackTimer(); // to set ModeHasChanged immediately
+ }
+ }
+ else if (!bOnlyEEItems)
+ {
+ // Otherwise split Set, if necessary.
+ // Now we build an ItemSet aSet that doesn't contain EE_Items from
+ // *pSet (otherwise it would be a copy).
+ WhichRangesContainer pNewWhichTable
+ = RemoveWhichRange(pSet->GetRanges(), EE_ITEMS_START, EE_ITEMS_END);
+ SfxItemSet aSet(mpModel->GetItemPool(), std::move(pNewWhichTable));
+ SfxWhichIter aIter(aSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich != 0)
+ {
+ const SfxPoolItem* pItem;
+ SfxItemState eState = pSet->GetItemState(nWhich, false, &pItem);
+ if (eState == SfxItemState::SET)
+ aSet.Put(*pItem);
+ nWhich = aIter.NextWhich();
+ }
+
+ if (mxSelectionController.is())
+ bRet = mxSelectionController->SetAttributes(aSet, bReplaceAll);
+
+ if (!bRet)
+ {
+ if (IsUndoEnabled())
+ {
+ BegUndo(ImpGetDescriptionString(STR_EditSetAttributes));
+ AddUndo(
+ GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*mxWeakTextEditObj));
+ AddUndo(
+ GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*mxWeakTextEditObj));
+ EndUndo();
+ }
+
+ mxWeakTextEditObj->SetMergedItemSetAndBroadcast(aSet, bReplaceAll);
+
+ if (GetMarkedObjectCount() == 1
+ && GetMarkedObjectByIndex(0) == mxWeakTextEditObj.get())
+ {
+ SetNotPersistAttrToMarked(aSet);
+ }
+ }
+ FlushComeBackTimer();
+ }
+ if (!bNoEEItems)
+ {
+ // and now the attributes to the EditEngine
+ if (bReplaceAll)
+ {
+ mpTextEditOutlinerView->RemoveAttribs(true);
+ }
+ mpTextEditOutlinerView->SetAttribs(rSet);
+
+ Outliner* pTEOutliner = mpTextEditOutlinerView->GetOutliner();
+ if (mpModel && pTEOutliner && pTEOutliner->IsModified())
+ mpModel->SetChanged();
+
+ ImpMakeTextCursorAreaVisible();
+ }
+ bRet = true;
+ }
+ return bRet;
+}
+
+SfxStyleSheet* SdrObjEditView::GetStyleSheet() const
+{
+ SfxStyleSheet* pSheet = nullptr;
+
+ if (mxSelectionController.is())
+ {
+ if (mxSelectionController->GetStyleSheet(pSheet))
+ return pSheet;
+ }
+
+ if (mpTextEditOutlinerView)
+ {
+ pSheet = mpTextEditOutlinerView->GetStyleSheet();
+ }
+ else
+ {
+ pSheet = SdrGlueEditView::GetStyleSheet();
+ }
+ return pSheet;
+}
+
+void SdrObjEditView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
+{
+ if (mxSelectionController.is())
+ {
+ if (mxSelectionController->SetStyleSheet(pStyleSheet, bDontRemoveHardAttr))
+ return;
+ }
+
+ // if we are currently in edit mode we must also set the stylesheet
+ // on all paragraphs in the Outliner for the edit view
+ if (nullptr != mpTextEditOutlinerView)
+ {
+ Outliner* pOutliner = mpTextEditOutlinerView->GetOutliner();
+
+ const sal_Int32 nParaCount = pOutliner->GetParagraphCount();
+ for (sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
+ {
+ pOutliner->SetStyleSheet(nPara, pStyleSheet);
+ }
+ }
+
+ SdrGlueEditView::SetStyleSheet(pStyleSheet, bDontRemoveHardAttr);
+}
+
+void SdrObjEditView::AddWindowToPaintView(OutputDevice* pNewWin, vcl::Window* pWindow)
+{
+ SdrGlueEditView::AddWindowToPaintView(pNewWin, pWindow);
+
+ if (mxWeakTextEditObj.is() && !mbTextEditOnlyOneView
+ && pNewWin->GetOutDevType() == OUTDEV_WINDOW)
+ {
+ OutlinerView* pOutlView = ImpMakeOutlinerView(pNewWin->GetOwnerWindow(), nullptr);
+ mpTextEditOutliner->InsertView(pOutlView);
+ }
+}
+
+void SdrObjEditView::DeleteWindowFromPaintView(OutputDevice* pOldWin)
+{
+ SdrGlueEditView::DeleteWindowFromPaintView(pOldWin);
+
+ if (mxWeakTextEditObj.is() && !mbTextEditOnlyOneView
+ && pOldWin->GetOutDevType() == OUTDEV_WINDOW)
+ {
+ for (size_t i = mpTextEditOutliner->GetViewCount(); i > 0;)
+ {
+ i--;
+ OutlinerView* pOLV = mpTextEditOutliner->GetView(i);
+ if (pOLV && pOLV->GetWindow() == pOldWin->GetOwnerWindow())
+ {
+ mpTextEditOutliner->RemoveView(i);
+ }
+ }
+ }
+
+ lcl_RemoveTextEditOutlinerViews(this, GetSdrPageView(), pOldWin);
+}
+
+bool SdrObjEditView::IsTextEditInSelectionMode() const
+{
+ return mpTextEditOutliner != nullptr && mpTextEditOutliner->IsInSelectionMode();
+}
+
+// MacroMode
+
+void SdrObjEditView::BegMacroObj(const Point& rPnt, short nTol, SdrObject* pObj, SdrPageView* pPV,
+ vcl::Window* pWin)
+{
+ BrkMacroObj();
+ if (pObj != nullptr && pPV != nullptr && pWin != nullptr && pObj->HasMacro())
+ {
+ nTol = ImpGetHitTolLogic(nTol, nullptr);
+ pMacroObj = pObj;
+ pMacroPV = pPV;
+ pMacroWin = pWin;
+ mbMacroDown = false;
+ nMacroTol = sal_uInt16(nTol);
+ aMacroDownPos = rPnt;
+ MovMacroObj(rPnt);
+ }
+}
+
+void SdrObjEditView::ImpMacroUp(const Point& rUpPos)
+{
+ if (pMacroObj != nullptr && mbMacroDown)
+ {
+ SdrObjMacroHitRec aHitRec;
+ aHitRec.aPos = rUpPos;
+ aHitRec.nTol = nMacroTol;
+ aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers();
+ aHitRec.pPageView = pMacroPV;
+ pMacroObj->PaintMacro(*pMacroWin->GetOutDev(), tools::Rectangle(), aHitRec);
+ mbMacroDown = false;
+ }
+}
+
+void SdrObjEditView::ImpMacroDown(const Point& rDownPos)
+{
+ if (pMacroObj != nullptr && !mbMacroDown)
+ {
+ SdrObjMacroHitRec aHitRec;
+ aHitRec.aPos = rDownPos;
+ aHitRec.nTol = nMacroTol;
+ aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers();
+ aHitRec.pPageView = pMacroPV;
+ pMacroObj->PaintMacro(*pMacroWin->GetOutDev(), tools::Rectangle(), aHitRec);
+ mbMacroDown = true;
+ }
+}
+
+void SdrObjEditView::MovMacroObj(const Point& rPnt)
+{
+ if (pMacroObj == nullptr)
+ return;
+
+ SdrObjMacroHitRec aHitRec;
+ aHitRec.aPos = rPnt;
+ aHitRec.nTol = nMacroTol;
+ aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers();
+ aHitRec.pPageView = pMacroPV;
+ bool bDown = pMacroObj->IsMacroHit(aHitRec);
+ if (bDown)
+ ImpMacroDown(rPnt);
+ else
+ ImpMacroUp(rPnt);
+}
+
+void SdrObjEditView::BrkMacroObj()
+{
+ if (pMacroObj != nullptr)
+ {
+ ImpMacroUp(aMacroDownPos);
+ pMacroObj = nullptr;
+ pMacroPV = nullptr;
+ pMacroWin = nullptr;
+ }
+}
+
+bool SdrObjEditView::EndMacroObj()
+{
+ if (pMacroObj != nullptr && mbMacroDown)
+ {
+ ImpMacroUp(aMacroDownPos);
+ SdrObjMacroHitRec aHitRec;
+ aHitRec.aPos = aMacroDownPos;
+ aHitRec.nTol = nMacroTol;
+ aHitRec.pVisiLayer = &pMacroPV->GetVisibleLayers();
+ aHitRec.pPageView = pMacroPV;
+ bool bRet = pMacroObj->DoMacro(aHitRec);
+ pMacroObj = nullptr;
+ pMacroPV = nullptr;
+ pMacroWin = nullptr;
+ return bRet;
+ }
+ else
+ {
+ BrkMacroObj();
+ return false;
+ }
+}
+
+/** fills the given any with a XTextCursor for the current text selection.
+ Leaves the any untouched if there currently is no text selected */
+void SdrObjEditView::getTextSelection(css::uno::Any& rSelection)
+{
+ if (!IsTextEdit())
+ return;
+
+ OutlinerView* pOutlinerView = GetTextEditOutlinerView();
+ if (!(pOutlinerView && pOutlinerView->HasSelection()))
+ return;
+
+ SdrObject* pObj = GetTextEditObject();
+
+ if (!pObj)
+ return;
+
+ css::uno::Reference<css::text::XText> xText(pObj->getUnoShape(), css::uno::UNO_QUERY);
+ if (xText.is())
+ {
+ SvxUnoTextBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextBase>(xText);
+ if (pRange)
+ {
+ rSelection <<= pRange->createTextCursorBySelection(pOutlinerView->GetSelection());
+ }
+ }
+}
+
+/* check if we have a single selection and that single object likes
+ to handle the mouse and keyboard events itself
+
+ TODO: the selection controller should be queried from the
+ object specific view contact. Currently this method only
+ works for tables.
+*/
+void SdrObjEditView::MarkListHasChanged()
+{
+ SdrGlueEditView::MarkListHasChanged();
+
+ if (mxSelectionController.is())
+ {
+ mxLastSelectionController = mxSelectionController;
+ mxSelectionController->onSelectionHasChanged();
+ }
+
+ mxSelectionController.clear();
+
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() != 1)
+ return;
+
+ const SdrObject* pObj(rMarkList.GetMark(0)->GetMarkedSdrObj());
+ SdrView* pView(dynamic_cast<SdrView*>(this));
+
+ // check for table
+ if (pObj && pView && (pObj->GetObjInventor() == SdrInventor::Default)
+ && (pObj->GetObjIdentifier() == SdrObjKind::Table))
+ {
+ mxSelectionController = sdr::table::CreateTableController(
+ *pView, static_cast<const sdr::table::SdrTableObj&>(*pObj), mxLastSelectionController);
+
+ if (mxSelectionController.is())
+ {
+ mxLastSelectionController.clear();
+ mxSelectionController->onSelectionHasChanged();
+ }
+ }
+}
+
+IMPL_LINK(SdrObjEditView, EndPasteOrDropHdl, PasteOrDropInfos*, pInfo, void)
+{
+ OnEndPasteOrDrop(pInfo);
+}
+
+IMPL_LINK(SdrObjEditView, BeginPasteOrDropHdl, PasteOrDropInfos*, pInfo, void)
+{
+ OnBeginPasteOrDrop(pInfo);
+}
+
+void SdrObjEditView::OnBeginPasteOrDrop(PasteOrDropInfos*)
+{
+ // applications can derive from these virtual methods to do something before a drop or paste operation
+}
+
+void SdrObjEditView::OnEndPasteOrDrop(PasteOrDropInfos*)
+{
+ // applications can derive from these virtual methods to do something before a drop or paste operation
+}
+
+sal_uInt16 SdrObjEditView::GetSelectionLevel() const
+{
+ sal_uInt16 nLevel = 0xFFFF;
+ if (IsTextEdit())
+ {
+ DBG_ASSERT(mpTextEditOutlinerView != nullptr,
+ "SdrObjEditView::GetAttributes(): mpTextEditOutlinerView=NULL");
+ DBG_ASSERT(mpTextEditOutliner != nullptr,
+ "SdrObjEditView::GetAttributes(): mpTextEditOutliner=NULL");
+ if (mpTextEditOutlinerView)
+ {
+ //start and end position
+ ESelection aSelect = mpTextEditOutlinerView->GetSelection();
+ sal_uInt16 nStartPara = ::std::min(aSelect.nStartPara, aSelect.nEndPara);
+ sal_uInt16 nEndPara = ::std::max(aSelect.nStartPara, aSelect.nEndPara);
+ //get level from each paragraph
+ nLevel = 0;
+ for (sal_uInt16 nPara = nStartPara; nPara <= nEndPara; nPara++)
+ {
+ sal_uInt16 nParaDepth
+ = 1 << static_cast<sal_uInt16>(mpTextEditOutliner->GetDepth(nPara));
+ if (!(nLevel & nParaDepth))
+ nLevel += nParaDepth;
+ }
+ //reduce one level for Outliner Object
+ //if( nLevel > 0 && GetTextEditObject()->GetObjIdentifier() == OBJ_OUTLINETEXT )
+ // nLevel = nLevel >> 1;
+ //no bullet paragraph selected
+ if (nLevel == 0)
+ nLevel = 0xFFFF;
+ }
+ }
+ return nLevel;
+}
+
+bool SdrObjEditView::SupportsFormatPaintbrush(SdrInventor nObjectInventor,
+ SdrObjKind nObjectIdentifier)
+{
+ if (nObjectInventor != SdrInventor::Default && nObjectInventor != SdrInventor::E3d)
+ return false;
+ switch (nObjectIdentifier)
+ {
+ case SdrObjKind::NONE:
+ case SdrObjKind::Group:
+ return false;
+ case SdrObjKind::Line:
+ case SdrObjKind::Rectangle:
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::CircleSection:
+ case SdrObjKind::CircleArc:
+ case SdrObjKind::CircleCut:
+ case SdrObjKind::Polygon:
+ case SdrObjKind::PolyLine:
+ case SdrObjKind::PathLine:
+ case SdrObjKind::PathFill:
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::SplineLine:
+ case SdrObjKind::SplineFill:
+ case SdrObjKind::Text:
+ case SdrObjKind::TitleText:
+ case SdrObjKind::OutlineText:
+ case SdrObjKind::Graphic:
+ case SdrObjKind::OLE2:
+ case SdrObjKind::Table:
+ return true;
+ case SdrObjKind::Caption:
+ return false;
+ case SdrObjKind::Edge:
+ case SdrObjKind::PathPoly:
+ case SdrObjKind::PathPolyLine:
+ return true;
+ case SdrObjKind::Page:
+ case SdrObjKind::Measure:
+ case SdrObjKind::OLEPluginFrame:
+ case SdrObjKind::UNO:
+ return false;
+ case SdrObjKind::CustomShape:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const WhichRangesContainer& GetFormatRangeImpl(bool bTextOnly)
+{
+ static const WhichRangesContainer gFull(
+ svl::Items<XATTR_LINE_FIRST, XATTR_LINE_LAST, XATTR_FILL_FIRST, XATTRSET_FILL,
+ SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST, SDRATTR_MISC_FIRST,
+ SDRATTR_MISC_LAST, // table cell formats
+ SDRATTR_GRAF_FIRST, SDRATTR_GRAF_LAST, SDRATTR_TABLE_FIRST, SDRATTR_TABLE_LAST,
+ SDRATTR_GLOW_FIRST, SDRATTR_GLOW_LAST, SDRATTR_SOFTEDGE_FIRST,
+ SDRATTR_SOFTEDGE_LAST, EE_PARA_START, EE_PARA_END, EE_CHAR_START, EE_CHAR_END>);
+
+ static const WhichRangesContainer gTextOnly(
+ svl::Items<SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST, EE_PARA_START, EE_PARA_END, EE_CHAR_START,
+ EE_CHAR_END>);
+
+ return bTextOnly ? gTextOnly : gFull;
+}
+
+void SdrObjEditView::TakeFormatPaintBrush(std::shared_ptr<SfxItemSet>& rFormatSet)
+{
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() <= 0)
+ return;
+
+ OutlinerView* pOLV = GetTextEditOutlinerView();
+
+ rFormatSet = std::make_shared<SfxItemSet>(GetModel()->GetItemPool(),
+ GetFormatRangeImpl(pOLV != nullptr));
+ if (pOLV)
+ {
+ rFormatSet->Put(pOLV->GetAttribs());
+ }
+ else
+ {
+ const bool bOnlyHardAttr = false;
+ rFormatSet->Put(GetAttrFromMarked(bOnlyHardAttr));
+ }
+
+ // check for cloning from table cell, in which case we need to copy cell-specific formatting attributes
+ const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if (pObj && (pObj->GetObjInventor() == SdrInventor::Default)
+ && (pObj->GetObjIdentifier() == SdrObjKind::Table))
+ {
+ auto pTable = static_cast<const sdr::table::SdrTableObj*>(pObj);
+ if (mxSelectionController.is() && pTable->getActiveCell().is())
+ {
+ mxSelectionController->GetAttributes(*rFormatSet, false);
+ }
+ }
+}
+
+static SfxItemSet CreatePaintSet(const WhichRangesContainer& pRanges, SfxItemPool& rPool,
+ const SfxItemSet& rSourceSet, const SfxItemSet& rTargetSet,
+ bool bNoCharacterFormats, bool bNoParagraphFormats)
+{
+ SfxItemSet aPaintSet(rPool, pRanges);
+
+ for (const auto& pRange : pRanges)
+ {
+ sal_uInt16 nWhich = pRange.first;
+ const sal_uInt16 nLastWhich = pRange.second;
+
+ if (bNoCharacterFormats && (nWhich == EE_CHAR_START))
+ continue;
+
+ if (bNoParagraphFormats && (nWhich == EE_PARA_START))
+ continue;
+
+ for (; nWhich <= nLastWhich; nWhich++)
+ {
+ const SfxPoolItem* pSourceItem = rSourceSet.GetItem(nWhich);
+ const SfxPoolItem* pTargetItem = rTargetSet.GetItem(nWhich);
+
+ if ((pSourceItem && !pTargetItem)
+ || (pSourceItem && pTargetItem && *pSourceItem != *pTargetItem))
+ {
+ aPaintSet.Put(*pSourceItem);
+ }
+ }
+ }
+ return aPaintSet;
+}
+
+void SdrObjEditView::ApplyFormatPaintBrushToText(SfxItemSet const& rFormatSet, SdrTextObj& rTextObj,
+ SdrText* pText, bool bNoCharacterFormats,
+ bool bNoParagraphFormats)
+{
+ OutlinerParaObject* pParaObj = pText ? pText->GetOutlinerParaObject() : nullptr;
+ if (!pParaObj)
+ return;
+
+ SdrOutliner& rOutliner = rTextObj.ImpGetDrawOutliner();
+ rOutliner.SetText(*pParaObj);
+
+ sal_Int32 nParaCount(rOutliner.GetParagraphCount());
+
+ if (!nParaCount)
+ return;
+
+ for (sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
+ {
+ if (!bNoCharacterFormats)
+ rOutliner.RemoveCharAttribs(nPara);
+
+ SfxItemSet aSet(rOutliner.GetParaAttribs(nPara));
+ aSet.Put(CreatePaintSet(GetFormatRangeImpl(true), *aSet.GetPool(), rFormatSet, aSet,
+ bNoCharacterFormats, bNoParagraphFormats));
+ rOutliner.SetParaAttribs(nPara, aSet);
+ }
+
+ std::optional<OutlinerParaObject> pTemp = rOutliner.CreateParaObject(0, nParaCount);
+ rOutliner.Clear();
+
+ rTextObj.NbcSetOutlinerParaObjectForText(std::move(pTemp), pText);
+}
+
+void SdrObjEditView::DisposeUndoManager()
+{
+ if (mpTextEditOutliner)
+ {
+ if (typeid(mpTextEditOutliner->GetUndoManager()) != typeid(EditUndoManager))
+ {
+ // Non-owning pointer, clear it.
+ mpTextEditOutliner->SetUndoManager(nullptr);
+ }
+ }
+
+ mpOldTextEditUndoManager = nullptr;
+}
+
+void SdrObjEditView::ApplyFormatPaintBrush(SfxItemSet& rFormatSet, bool bNoCharacterFormats,
+ bool bNoParagraphFormats)
+{
+ if (mxSelectionController.is()
+ && mxSelectionController->ApplyFormatPaintBrush(rFormatSet, bNoCharacterFormats,
+ bNoParagraphFormats))
+ {
+ return;
+ }
+
+ OutlinerView* pOLV = GetTextEditOutlinerView();
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ if (!pOLV)
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ const SfxItemSet& rShapeSet = pObj->GetMergedItemSet();
+
+ // if not in text edit mode (aka the user selected text or clicked on a word)
+ // apply formatting attributes to selected shape
+ // All formatting items (see ranges above) that are unequal in selected shape and
+ // the format paintbrush are hard set on the selected shape.
+
+ const WhichRangesContainer& pRanges = rFormatSet.GetRanges();
+ bool bTextOnly = true;
+
+ for (const auto& pRange : pRanges)
+ {
+ if ((pRange.first != EE_PARA_START) && (pRange.first != EE_CHAR_START))
+ {
+ bTextOnly = false;
+ break;
+ }
+ }
+
+ if (!bTextOnly)
+ {
+ SfxItemSet aPaintSet(CreatePaintSet(GetFormatRangeImpl(false), *rShapeSet.GetPool(),
+ rFormatSet, rShapeSet, bNoCharacterFormats,
+ bNoParagraphFormats));
+ SetAttrToMarked(aPaintSet, false /*bReplaceAll*/);
+ }
+
+ // now apply character and paragraph formatting to text, if the shape has any
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(pObj);
+ if (pTextObj)
+ {
+ sal_Int32 nText = pTextObj->getTextCount();
+
+ while (--nText >= 0)
+ {
+ SdrText* pText = pTextObj->getText(nText);
+ ApplyFormatPaintBrushToText(rFormatSet, *pTextObj, pText, bNoCharacterFormats,
+ bNoParagraphFormats);
+ }
+ }
+ }
+ else
+ {
+ ::Outliner* pOutliner = pOLV->GetOutliner();
+ if (pOutliner)
+ {
+ const EditEngine& rEditEngine = pOutliner->GetEditEngine();
+
+ ESelection aSel(pOLV->GetSelection());
+ if (!aSel.HasRange())
+ pOLV->SetSelection(rEditEngine.GetWord(aSel, css::i18n::WordType::DICTIONARY_WORD));
+
+ const bool bRemoveParaAttribs = !bNoParagraphFormats;
+ pOLV->RemoveAttribsKeepLanguages(bRemoveParaAttribs);
+ SfxItemSet aSet(pOLV->GetAttribs());
+ SfxItemSet aPaintSet(CreatePaintSet(GetFormatRangeImpl(true), *aSet.GetPool(),
+ rFormatSet, aSet, bNoCharacterFormats,
+ bNoParagraphFormats));
+ pOLV->SetAttribs(aPaintSet);
+ }
+ }
+
+ // check for cloning to table cell, in which case we need to copy cell-specific formatting attributes
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if (pObj && (pObj->GetObjInventor() == SdrInventor::Default)
+ && (pObj->GetObjIdentifier() == SdrObjKind::Table))
+ {
+ auto pTable = static_cast<sdr::table::SdrTableObj*>(pObj);
+ if (pTable->getActiveCell().is() && mxSelectionController.is())
+ {
+ mxSelectionController->SetAttributes(rFormatSet, false);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdetc.cxx b/svx/source/svdraw/svdetc.cxx
new file mode 100644
index 000000000..154bd3c7b
--- /dev/null
+++ b/svx/source/svdraw/svdetc.cxx
@@ -0,0 +1,726 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+
+#include <officecfg/Office/Common.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svdedxv.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdoutl.hxx>
+#include <vcl/BitmapReadAccess.hxx>
+#include <editeng/eeitem.hxx>
+#include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
+#include <svx/xgrad.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/svdoole2.hxx>
+#include <svl/itempool.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <svx/xflbckit.hxx>
+#include <svx/extrusionbar.hxx>
+#include <svx/fontworkbar.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/sdrhittesthelper.hxx>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+using namespace ::com::sun::star;
+
+// Global data of the DrawingEngine
+SdrGlobalData::SdrGlobalData()
+ : pSysLocale(nullptr)
+{
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ svx::ExtrusionBar::RegisterInterface();
+ svx::FontworkBar::RegisterInterface();
+ }
+}
+
+const SvtSysLocale* SdrGlobalData::GetSysLocale()
+{
+ if ( !pSysLocale )
+ pSysLocale = new SvtSysLocale;
+ return pSysLocale;
+}
+const LocaleDataWrapper* SdrGlobalData::GetLocaleData()
+{
+ return &GetSysLocale()->GetLocaleData();
+}
+
+namespace {
+
+struct TheSdrGlobalData: public rtl::Static<SdrGlobalData, TheSdrGlobalData> {};
+
+}
+
+SdrGlobalData & GetSdrGlobalData() {
+ return TheSdrGlobalData::get();
+}
+
+OLEObjCache::OLEObjCache()
+{
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+// This limit is only useful on 32-bit windows, where we can run out of virtual memory (see tdf#95579)
+// For everything else, we are better off keeping it in main memory rather than using our hacky page-out thing
+#if defined _WIN32 && !defined _WIN64
+ nSize = officecfg::Office::Common::Cache::DrawingEngine::OLE_Objects::get();
+#else
+ nSize = SAL_MAX_INT32; // effectively disable the page-out mechanism
+#endif
+ }
+ else
+ nSize = 100;
+ pTimer.reset( new AutoTimer( "svx OLEObjCache pTimer UnloadCheck" ) );
+ pTimer->SetInvokeHandler( LINK(this, OLEObjCache, UnloadCheckHdl) );
+ pTimer->SetTimeout(20000);
+ pTimer->SetStatic();
+}
+
+OLEObjCache::~OLEObjCache()
+{
+ pTimer->Stop();
+}
+
+IMPL_LINK_NOARG(OLEObjCache, UnloadCheckHdl, Timer*, void)
+{
+ if (nSize >= maObjs.size())
+ return;
+
+ // more objects than configured cache size try to remove objects
+ // of course not the freshly inserted one at nIndex=0
+ size_t nCount2 = maObjs.size();
+ size_t nIndex = nCount2-1;
+ while( nIndex && nCount2 > nSize )
+ {
+ SdrOle2Obj* pUnloadObj = maObjs[nIndex--];
+ if (!pUnloadObj)
+ continue;
+
+ try
+ {
+ // it is important to get object without reinitialization to avoid reentrance
+ const uno::Reference< embed::XEmbeddedObject > & xUnloadObj = pUnloadObj->GetObjRef_NoInit();
+
+ bool bUnload = !xUnloadObj || SdrOle2Obj::CanUnloadRunningObj( xUnloadObj, pUnloadObj->GetAspect() );
+
+ // check whether the object can be unloaded before looking for the parent objects
+ if ( xUnloadObj.is() && bUnload )
+ {
+ uno::Reference< frame::XModel > xUnloadModel( xUnloadObj->getComponent(), uno::UNO_QUERY );
+ if ( xUnloadModel.is() )
+ {
+ for (SdrOle2Obj* pCacheObj : maObjs)
+ {
+ if ( pCacheObj && pCacheObj != pUnloadObj )
+ {
+ uno::Reference< frame::XModel > xParentModel = pCacheObj->GetParentXModel();
+ if ( xUnloadModel == xParentModel )
+ {
+ bUnload = false; // the object has running embedded objects
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (bUnload && UnloadObj(*pUnloadObj))
+ {
+ // object was successfully unloaded
+ RemoveObj(pUnloadObj);
+ nCount2 = std::min(nCount2 - 1, maObjs.size());
+ if (nIndex >= nCount2)
+ nIndex = nCount2 - 1;
+ }
+ }
+ catch( uno::Exception& )
+ {}
+ }
+}
+
+void OLEObjCache::InsertObj(SdrOle2Obj* pObj)
+{
+ if (!maObjs.empty())
+ {
+ SdrOle2Obj* pExistingObj = maObjs.front();
+ if ( pObj == pExistingObj )
+ // the object is already on the top, nothing has to be changed
+ return;
+ }
+
+ // get the old position of the object to know whether it is already in container
+ std::vector<SdrOle2Obj*>::iterator it = std::find(maObjs.begin(), maObjs.end(), pObj);
+ bool bFound = it != maObjs.end();
+
+ if (bFound)
+ maObjs.erase(it);
+ // insert object into first position
+ maObjs.insert(maObjs.begin(), pObj);
+
+ // if a new object was inserted, recalculate the cache
+ if (!bFound)
+ pTimer->Invoke();
+
+ if (!bFound || !pTimer->IsActive())
+ pTimer->Start();
+}
+
+void OLEObjCache::RemoveObj(SdrOle2Obj* pObj)
+{
+ std::vector<SdrOle2Obj*>::iterator it = std::find(maObjs.begin(), maObjs.end(), pObj);
+ if (it != maObjs.end())
+ maObjs.erase(it);
+ if (maObjs.empty())
+ pTimer->Stop();
+}
+
+size_t OLEObjCache::size() const
+{
+ return maObjs.size();
+}
+
+SdrOle2Obj* OLEObjCache::operator[](size_t nPos)
+{
+ return maObjs[nPos];
+}
+
+const SdrOle2Obj* OLEObjCache::operator[](size_t nPos) const
+{
+ return maObjs[nPos];
+}
+
+bool OLEObjCache::UnloadObj(SdrOle2Obj& rObj)
+{
+ bool bUnloaded = false;
+
+ //#i80528# The old mechanism is completely useless, only taking into account if
+ // in all views the GrafDraft feature is used. This will nearly never have been the
+ // case since no one ever used this option.
+
+ // A much better (and working) criteria would be the VOC contact count.
+ // The question is what will happen when i make it work now suddenly? I
+ // will try it for 2.4.
+ const sdr::contact::ViewContact& rViewContact = rObj.GetViewContact();
+ const bool bVisible(rViewContact.HasViewObjectContacts());
+
+ if(!bVisible)
+ {
+ bUnloaded = rObj.Unload();
+ }
+
+ return bUnloaded;
+}
+
+bool GetDraftFillColor(const SfxItemSet& rSet, Color& rCol)
+{
+ drawing::FillStyle eFill=rSet.Get(XATTR_FILLSTYLE).GetValue();
+ bool bRetval = false;
+
+ switch(eFill)
+ {
+ case drawing::FillStyle_SOLID:
+ {
+ rCol = rSet.Get(XATTR_FILLCOLOR).GetColorValue();
+ bRetval = true;
+
+ break;
+ }
+ case drawing::FillStyle_HATCH:
+ {
+ Color aCol1(rSet.Get(XATTR_FILLHATCH).GetHatchValue().GetColor());
+ Color aCol2(COL_WHITE);
+
+ // when hatched background is activated, use object fill color as hatch color
+ bool bFillHatchBackground = rSet.Get(XATTR_FILLBACKGROUND).GetValue();
+ if(bFillHatchBackground)
+ {
+ aCol2 = rSet.Get(XATTR_FILLCOLOR).GetColorValue();
+ }
+
+ const basegfx::BColor aAverageColor(basegfx::average(aCol1.getBColor(), aCol2.getBColor()));
+ rCol = Color(aAverageColor);
+ bRetval = true;
+
+ break;
+ }
+ case drawing::FillStyle_GRADIENT: {
+ const XGradient& rGrad=rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
+ Color aCol1(rGrad.GetStartColor());
+ Color aCol2(rGrad.GetEndColor());
+ const basegfx::BColor aAverageColor(basegfx::average(aCol1.getBColor(), aCol2.getBColor()));
+ rCol = Color(aAverageColor);
+ bRetval = true;
+
+ break;
+ }
+ case drawing::FillStyle_BITMAP:
+ {
+ Bitmap aBitmap(rSet.Get(XATTR_FILLBITMAP).GetGraphicObject().GetGraphic().GetBitmapEx().GetBitmap());
+ const Size aSize(aBitmap.GetSizePixel());
+ const sal_uInt32 nWidth = aSize.Width();
+ const sal_uInt32 nHeight = aSize.Height();
+ if (nWidth <= 0 || nHeight <= 0)
+ return bRetval;
+
+ Bitmap::ScopedReadAccess pAccess(aBitmap);
+
+ if (pAccess)
+ {
+ sal_uInt32 nRt(0);
+ sal_uInt32 nGn(0);
+ sal_uInt32 nBl(0);
+ const sal_uInt32 nMaxSteps(8);
+ const sal_uInt32 nXStep((nWidth > nMaxSteps) ? nWidth / nMaxSteps : 1);
+ const sal_uInt32 nYStep((nHeight > nMaxSteps) ? nHeight / nMaxSteps : 1);
+ sal_uInt32 nCount(0);
+
+ for(sal_uInt32 nY(0); nY < nHeight; nY += nYStep)
+ {
+ for(sal_uInt32 nX(0); nX < nWidth; nX += nXStep)
+ {
+ const BitmapColor& rCol2 = pAccess->GetColor(nY, nX);
+
+ nRt += rCol2.GetRed();
+ nGn += rCol2.GetGreen();
+ nBl += rCol2.GetBlue();
+ nCount++;
+ }
+ }
+
+ nRt /= nCount;
+ nGn /= nCount;
+ nBl /= nCount;
+
+ rCol = Color(sal_uInt8(nRt), sal_uInt8(nGn), sal_uInt8(nBl));
+
+ bRetval = true;
+ }
+ break;
+ }
+ default: break;
+ }
+
+ return bRetval;
+}
+
+std::unique_ptr<SdrOutliner> SdrMakeOutliner(OutlinerMode nOutlinerMode, SdrModel& rModel)
+{
+ SfxItemPool* pPool = &rModel.GetItemPool();
+ std::unique_ptr<SdrOutliner> pOutl(new SdrOutliner( pPool, nOutlinerMode ));
+ pOutl->SetEditTextObjectPool( pPool );
+ pOutl->SetStyleSheetPool( static_cast<SfxStyleSheetPool*>(rModel.GetStyleSheetPool()));
+ pOutl->SetDefTab(rModel.GetDefaultTabulator());
+ Outliner::SetForbiddenCharsTable(rModel.GetForbiddenCharsTable());
+ pOutl->SetAsianCompressionMode(rModel.GetCharCompressType());
+ pOutl->SetKernAsianPunctuation(rModel.IsKernAsianPunctuation());
+ pOutl->SetAddExtLeading(rModel.IsAddExtLeading());
+ return pOutl;
+}
+
+std::vector<Link<SdrObjCreatorParams, SdrObject*>>& ImpGetUserMakeObjHdl()
+{
+ SdrGlobalData& rGlobalData=GetSdrGlobalData();
+ return rGlobalData.aUserMakeObjHdl;
+}
+
+bool SearchOutlinerItems(const SfxItemSet& rSet, bool bInklDefaults, bool* pbOnlyEE)
+{
+ bool bHas=false;
+ bool bOnly=true;
+ bool bLookOnly=pbOnlyEE!=nullptr;
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich=aIter.FirstWhich();
+ while (((bLookOnly && bOnly) || !bHas) && nWhich!=0) {
+ // For bInklDefaults, the entire Which range is decisive,
+ // in other cases only the set items are.
+ // Disabled and DontCare are regarded as holes in the Which range.
+ SfxItemState eState=aIter.GetItemState();
+ if ((eState==SfxItemState::DEFAULT && bInklDefaults) || eState==SfxItemState::SET) {
+ if (nWhich<EE_ITEMS_START || nWhich>EE_ITEMS_END) bOnly=false;
+ else bHas=true;
+ }
+ nWhich=aIter.NextWhich();
+ }
+ if (!bHas) bOnly=false;
+ if (pbOnlyEE!=nullptr) *pbOnlyEE=bOnly;
+ return bHas;
+}
+
+WhichRangesContainer RemoveWhichRange(const WhichRangesContainer& pOldWhichTable, sal_uInt16 nRangeBeg, sal_uInt16 nRangeEnd)
+{
+ // Six possible cases (per range):
+ // [Beg..End] [nRangeBeg, nRangeEnd], to delete
+ // [b..e] [b..e] [b..e] Cases 1,3,2: doesn't matter, delete, doesn't matter + Ranges
+ // [b........e] [b........e] Cases 4,5 : shrink range | in
+ // [b......................e] Case 6 : splitting + pOldWhichTable
+ std::vector<WhichPair> buf;
+ for (const auto & rPair : pOldWhichTable) {
+ auto const begin = rPair.first;
+ auto const end = rPair.second;
+ if (end < nRangeBeg || begin > nRangeEnd) { // cases 1, 2
+ buf.push_back({begin, end});
+ } else if (begin >= nRangeBeg && end <= nRangeEnd) { // case 3
+ // drop
+ } else if (end <= nRangeEnd) { // case 4
+ buf.push_back({begin, nRangeBeg - 1});
+ } else if (begin >= nRangeBeg) { // case 5
+ buf.push_back({nRangeEnd + 1, end});
+ } else { // case 6
+ buf.push_back({begin, nRangeBeg - 1});
+ buf.push_back({nRangeEnd + 1, end});
+ }
+ }
+ std::unique_ptr<WhichPair[]> pNewWhichTable(new WhichPair[buf.size()]);
+ std::copy(buf.begin(), buf.end(), pNewWhichTable.get());
+ return WhichRangesContainer(std::move(pNewWhichTable), buf.size());
+}
+
+
+SvdProgressInfo::SvdProgressInfo( const Link<void*,bool>&_rLink )
+{
+ maLink = _rLink;
+ m_nSumCurAction = 0;
+
+ m_nObjCount = 0;
+ m_nCurObj = 0;
+
+ m_nActionCount = 0;
+ m_nCurAction = 0;
+
+ m_nInsertCount = 0;
+ m_nCurInsert = 0;
+}
+
+void SvdProgressInfo::Init( size_t nObjCount )
+{
+ m_nObjCount = nObjCount;
+}
+
+bool SvdProgressInfo::ReportActions( size_t nActionCount )
+{
+ m_nSumCurAction += nActionCount;
+ m_nCurAction += nActionCount;
+ if(m_nCurAction > m_nActionCount)
+ m_nCurAction = m_nActionCount;
+
+ return maLink.Call(nullptr);
+}
+
+void SvdProgressInfo::ReportInserts( size_t nInsertCount )
+{
+ m_nSumCurAction += nInsertCount;
+ m_nCurInsert += nInsertCount;
+
+ maLink.Call(nullptr);
+}
+
+void SvdProgressInfo::ReportRescales( size_t nRescaleCount )
+{
+ m_nSumCurAction += nRescaleCount;
+ maLink.Call(nullptr);
+}
+
+void SvdProgressInfo::SetActionCount( size_t nActionCount )
+{
+ m_nActionCount = nActionCount;
+}
+
+void SvdProgressInfo::SetInsertCount( size_t nInsertCount )
+{
+ m_nInsertCount = nInsertCount;
+}
+
+void SvdProgressInfo::SetNextObject()
+{
+ m_nActionCount = 0;
+ m_nCurAction = 0;
+
+ m_nInsertCount = 0;
+ m_nCurInsert = 0;
+
+ m_nCurObj++;
+ ReportActions(0);
+}
+
+// #i101872# isolate GetTextEditBackgroundColor to tooling; it will anyways only be used as long
+// as text edit is not running on overlay
+
+namespace
+{
+ bool impGetSdrObjListFillColor(
+ const SdrObjList& rList,
+ const Point& rPnt,
+ const SdrPageView& rTextEditPV,
+ const SdrLayerIDSet& rVisLayers,
+ Color& rCol)
+ {
+ bool bRet(false);
+ bool bMaster(rList.getSdrPageFromSdrObjList() && rList.getSdrPageFromSdrObjList()->IsMasterPage());
+
+ for(size_t no(rList.GetObjCount()); !bRet && no > 0; )
+ {
+ no--;
+ SdrObject* pObj = rList.GetObj(no);
+ SdrObjList* pOL = pObj->GetSubList();
+
+ if(pOL)
+ {
+ // group object
+ bRet = impGetSdrObjListFillColor(*pOL, rPnt, rTextEditPV, rVisLayers, rCol);
+ }
+ else
+ {
+ SdrTextObj* pText = dynamic_cast< SdrTextObj * >(pObj);
+
+ // Exclude zero master page object (i.e. background shape) from color query
+ if(pText
+ && pObj->IsClosedObj()
+ && (!bMaster || (!pObj->IsNotVisibleAsMaster() && 0 != no))
+ && pObj->GetCurrentBoundRect().Contains(rPnt)
+ && !pText->IsHideContour()
+ && SdrObjectPrimitiveHit(*pObj, rPnt, 0, rTextEditPV, &rVisLayers, false))
+ {
+ bRet = GetDraftFillColor(pObj->GetMergedItemSet(), rCol);
+ }
+ }
+ }
+
+ return bRet;
+ }
+
+ bool impGetSdrPageFillColor(
+ const SdrPage& rPage,
+ const Point& rPnt,
+ const SdrPageView& rTextEditPV,
+ const SdrLayerIDSet& rVisLayers,
+ Color& rCol,
+ bool bSkipBackgroundShape)
+ {
+ bool bRet(impGetSdrObjListFillColor(rPage, rPnt, rTextEditPV, rVisLayers, rCol));
+
+ if(!bRet && !rPage.IsMasterPage())
+ {
+ if(rPage.TRG_HasMasterPage())
+ {
+ SdrLayerIDSet aSet(rVisLayers);
+ aSet &= rPage.TRG_GetMasterPageVisibleLayers();
+ SdrPage& rMasterPage = rPage.TRG_GetMasterPage();
+
+ // Don't fall back to background shape on
+ // master pages. This is later handled by
+ // GetBackgroundColor, and is necessary to cater for
+ // the silly ordering: 1. shapes, 2. master page
+ // shapes, 3. page background, 4. master page
+ // background.
+ bRet = impGetSdrPageFillColor(rMasterPage, rPnt, rTextEditPV, aSet, rCol, true);
+ }
+ }
+
+ // Only now determine background color from background shapes
+ if(!bRet && !bSkipBackgroundShape)
+ {
+ rCol = rPage.GetPageBackgroundColor();
+ return true;
+ }
+
+ return bRet;
+ }
+
+ Color impCalcBackgroundColor(
+ const tools::Rectangle& rArea,
+ const SdrPageView& rTextEditPV,
+ const SdrPage& rPage)
+ {
+ svtools::ColorConfig aColorConfig;
+ Color aBackground(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ if(!rStyleSettings.GetHighContrastMode())
+ {
+ // search in page
+ const sal_uInt16 SPOTCOUNT(5);
+ Point aSpotPos[SPOTCOUNT];
+ Color aSpotColor[SPOTCOUNT];
+ sal_uInt32 nHeight( rArea.GetSize().Height() );
+ sal_uInt32 nWidth( rArea.GetSize().Width() );
+ sal_uInt32 nWidth14 = nWidth / 4;
+ sal_uInt32 nHeight14 = nHeight / 4;
+ sal_uInt32 nWidth34 = ( 3 * nWidth ) / 4;
+ sal_uInt32 nHeight34 = ( 3 * nHeight ) / 4;
+
+ sal_uInt16 i;
+ for ( i = 0; i < SPOTCOUNT; i++ )
+ {
+ // five spots are used
+ switch ( i )
+ {
+ case 0 :
+ {
+ // Center-Spot
+ aSpotPos[i] = rArea.Center();
+ }
+ break;
+
+ case 1 :
+ {
+ // TopLeft-Spot
+ aSpotPos[i] = rArea.TopLeft();
+ aSpotPos[i].AdjustX(nWidth14 );
+ aSpotPos[i].AdjustY(nHeight14 );
+ }
+ break;
+
+ case 2 :
+ {
+ // TopRight-Spot
+ aSpotPos[i] = rArea.TopLeft();
+ aSpotPos[i].AdjustX(nWidth34 );
+ aSpotPos[i].AdjustY(nHeight14 );
+ }
+ break;
+
+ case 3 :
+ {
+ // BottomLeft-Spot
+ aSpotPos[i] = rArea.TopLeft();
+ aSpotPos[i].AdjustX(nWidth14 );
+ aSpotPos[i].AdjustY(nHeight34 );
+ }
+ break;
+
+ case 4 :
+ {
+ // BottomRight-Spot
+ aSpotPos[i] = rArea.TopLeft();
+ aSpotPos[i].AdjustX(nWidth34 );
+ aSpotPos[i].AdjustY(nHeight34 );
+ }
+ break;
+
+ }
+
+ aSpotColor[i] = COL_WHITE;
+ impGetSdrPageFillColor(rPage, aSpotPos[i], rTextEditPV, rTextEditPV.GetVisibleLayers(), aSpotColor[i], false);
+ }
+
+ sal_uInt16 aMatch[SPOTCOUNT];
+
+ for ( i = 0; i < SPOTCOUNT; i++ )
+ {
+ // were same spot colors found?
+ aMatch[i] = 0;
+
+ for ( sal_uInt16 j = 0; j < SPOTCOUNT; j++ )
+ {
+ if( j != i )
+ {
+ if( aSpotColor[i] == aSpotColor[j] )
+ {
+ aMatch[i]++;
+ }
+ }
+ }
+ }
+
+ // highest weight to center spot
+ aBackground = aSpotColor[0];
+
+ for ( sal_uInt16 nMatchCount = SPOTCOUNT - 1; nMatchCount > 1; nMatchCount-- )
+ {
+ // which spot color was found most?
+ for ( i = 0; i < SPOTCOUNT; i++ )
+ {
+ if( aMatch[i] == nMatchCount )
+ {
+ aBackground = aSpotColor[i];
+ nMatchCount = 1; // break outer for-loop
+ break;
+ }
+ }
+ }
+ }
+
+ return aBackground;
+ }
+} // end of anonymous namespace
+
+Color GetTextEditBackgroundColor(const SdrObjEditView& rView)
+{
+ svtools::ColorConfig aColorConfig;
+ Color aBackground(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ if(!rStyleSettings.GetHighContrastMode())
+ {
+ bool bFound(false);
+ SdrTextObj* pText = rView.GetTextEditObject();
+
+ if(pText && pText->IsClosedObj())
+ {
+ sdr::table::SdrTableObj* pTable = dynamic_cast< sdr::table::SdrTableObj * >( pText );
+
+ if( pTable )
+ bFound = GetDraftFillColor(pTable->GetActiveCellItemSet(), aBackground );
+
+ if( !bFound )
+ bFound=GetDraftFillColor(pText->GetMergedItemSet(), aBackground);
+ }
+
+ if(!bFound && pText)
+ {
+ SdrPageView* pTextEditPV = rView.GetTextEditPageView();
+
+ if(pTextEditPV)
+ {
+ Point aPvOfs(pText->GetTextEditOffset());
+ const SdrPage* pPg = pTextEditPV->GetPage();
+
+ if(pPg)
+ {
+ tools::Rectangle aSnapRect( pText->GetSnapRect() );
+ aSnapRect.Move(aPvOfs.X(), aPvOfs.Y());
+
+ return impCalcBackgroundColor(aSnapRect, *pTextEditPV, *pPg);
+ }
+ }
+ }
+ }
+
+ return aBackground;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdfmtf.cxx b/svx/source/svdraw/svdfmtf.cxx
new file mode 100644
index 000000000..659fae090
--- /dev/null
+++ b/svx/source/svdraw/svdfmtf.cxx
@@ -0,0 +1,1641 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "svdfmtf.hxx"
+#include <math.h>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xgrad.hxx>
+#include <svx/xflgrit.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/colritem.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/metric.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/sdtaitm.hxx>
+#include <svx/sdtditm.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdetc.hxx>
+#include <svl/itemset.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <tools/helpers.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/xlndsit.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/svdpntv.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdogrp.hxx>
+#include <vcl/BitmapTools.hxx>
+#include <osl/diagnose.h>
+
+using namespace com::sun::star;
+
+ImpSdrGDIMetaFileImport::ImpSdrGDIMetaFileImport(
+ SdrModel& rModel,
+ SdrLayerID nLay,
+ const tools::Rectangle& rRect)
+: mpVD(VclPtr<VirtualDevice>::Create()),
+ maScaleRect(rRect),
+ mnMapScalingOfs(0),
+ mpModel(&rModel),
+ mnLayer(nLay),
+ mnLineWidth(0),
+ maLineJoin(basegfx::B2DLineJoin::NONE),
+ maLineCap(css::drawing::LineCap_BUTT),
+ maDash(css::drawing::DashStyle_RECT, 0, 0, 0, 0, 0),
+ mbMov(false),
+ mbSize(false),
+ maOfs(0, 0),
+ mfScaleX(1.0),
+ mfScaleY(1.0),
+ maScaleX(1.0),
+ maScaleY(1.0),
+ mbFntDirty(true),
+ mbLastObjWasPolyWithoutLine(false),
+ mbNoLine(false),
+ mbNoFill(false),
+ mbLastObjWasLine(false)
+{
+ mpVD->EnableOutput(false);
+ mpVD->SetLineColor();
+ mpVD->SetFillColor();
+ maOldLineColor.SetRed( mpVD->GetLineColor().GetRed() + 1 );
+ mpLineAttr = std::make_unique<SfxItemSetFixed<XATTR_LINE_FIRST, XATTR_LINE_LAST>>(rModel.GetItemPool());
+ mpFillAttr = std::make_unique<SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>>(rModel.GetItemPool());
+ mpTextAttr = std::make_unique<SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END>>(rModel.GetItemPool());
+ checkClip();
+}
+
+void ImpSdrGDIMetaFileImport::DoLoopActions(GDIMetaFile const & rMtf, SvdProgressInfo* pProgrInfo, sal_uInt32* pActionsToReport)
+{
+ const sal_uLong nCount(rMtf.GetActionSize());
+
+ for(sal_uLong a(0); a < nCount; a++)
+ {
+ MetaAction* pAct = rMtf.GetAction(a);
+
+ if(!pAct)
+ {
+ OSL_ENSURE(false, "OOps, no action at valid position (!)");
+ pAct = rMtf.GetAction(0);
+ }
+
+ switch (pAct->GetType())
+ {
+ case MetaActionType::PIXEL : break;
+ case MetaActionType::POINT : break;
+ case MetaActionType::LINE : DoAction(static_cast<MetaLineAction &>(*pAct)); break;
+ case MetaActionType::RECT : DoAction(static_cast<MetaRectAction &>(*pAct)); break;
+ case MetaActionType::ROUNDRECT : DoAction(static_cast<MetaRoundRectAction &>(*pAct)); break;
+ case MetaActionType::ELLIPSE : DoAction(static_cast<MetaEllipseAction &>(*pAct)); break;
+ case MetaActionType::ARC : DoAction(static_cast<MetaArcAction &>(*pAct)); break;
+ case MetaActionType::PIE : DoAction(static_cast<MetaPieAction &>(*pAct)); break;
+ case MetaActionType::CHORD : DoAction(static_cast<MetaChordAction &>(*pAct)); break;
+ case MetaActionType::POLYLINE : DoAction(static_cast<MetaPolyLineAction &>(*pAct)); break;
+ case MetaActionType::POLYGON : DoAction(static_cast<MetaPolygonAction &>(*pAct)); break;
+ case MetaActionType::POLYPOLYGON : DoAction(static_cast<MetaPolyPolygonAction &>(*pAct)); break;
+ case MetaActionType::TEXT : DoAction(static_cast<MetaTextAction &>(*pAct)); break;
+ case MetaActionType::TEXTARRAY : DoAction(static_cast<MetaTextArrayAction &>(*pAct)); break;
+ case MetaActionType::STRETCHTEXT : DoAction(static_cast<MetaStretchTextAction &>(*pAct)); break;
+ case MetaActionType::BMP : DoAction(static_cast<MetaBmpAction &>(*pAct)); break;
+ case MetaActionType::BMPSCALE : DoAction(static_cast<MetaBmpScaleAction &>(*pAct)); break;
+ case MetaActionType::BMPEX : DoAction(static_cast<MetaBmpExAction &>(*pAct)); break;
+ case MetaActionType::BMPEXSCALE : DoAction(static_cast<MetaBmpExScaleAction &>(*pAct)); break;
+ case MetaActionType::LINECOLOR : DoAction(static_cast<MetaLineColorAction &>(*pAct)); break;
+ case MetaActionType::FILLCOLOR : DoAction(static_cast<MetaFillColorAction &>(*pAct)); break;
+ case MetaActionType::TEXTCOLOR : DoAction(static_cast<MetaTextColorAction &>(*pAct)); break;
+ case MetaActionType::TEXTFILLCOLOR : DoAction(static_cast<MetaTextFillColorAction &>(*pAct)); break;
+ case MetaActionType::FONT : DoAction(static_cast<MetaFontAction &>(*pAct)); break;
+ case MetaActionType::TEXTALIGN : DoAction(static_cast<MetaTextAlignAction &>(*pAct)); break;
+ case MetaActionType::MAPMODE : DoAction(static_cast<MetaMapModeAction &>(*pAct)); break;
+ case MetaActionType::CLIPREGION : DoAction(static_cast<MetaClipRegionAction &>(*pAct)); break;
+ case MetaActionType::MOVECLIPREGION : DoAction(static_cast<MetaMoveClipRegionAction &>(*pAct)); break;
+ case MetaActionType::ISECTRECTCLIPREGION: DoAction(static_cast<MetaISectRectClipRegionAction&>(*pAct)); break;
+ case MetaActionType::ISECTREGIONCLIPREGION: DoAction(static_cast<MetaISectRegionClipRegionAction&>(*pAct)); break;
+ case MetaActionType::RASTEROP : DoAction(static_cast<MetaRasterOpAction &>(*pAct)); break;
+ case MetaActionType::PUSH : DoAction(static_cast<MetaPushAction &>(*pAct)); break;
+ case MetaActionType::POP : DoAction(static_cast<MetaPopAction &>(*pAct)); break;
+ case MetaActionType::HATCH : DoAction(static_cast<MetaHatchAction &>(*pAct)); break;
+
+ // #i125211# MetaCommentAction may change index, thus hand it over
+ case MetaActionType::COMMENT : DoAction(static_cast<MetaCommentAction&>(*pAct), rMtf, a);
+ break;
+
+ // missing actions added
+ case MetaActionType::TEXTRECT : DoAction(static_cast<MetaTextRectAction&>(*pAct)); break;
+ case MetaActionType::BMPSCALEPART : DoAction(static_cast<MetaBmpScalePartAction&>(*pAct)); break;
+ case MetaActionType::BMPEXSCALEPART : DoAction(static_cast<MetaBmpExScalePartAction&>(*pAct)); break;
+ case MetaActionType::MASK : DoAction(static_cast<MetaMaskAction&>(*pAct)); break;
+ case MetaActionType::MASKSCALE : DoAction(static_cast<MetaMaskScaleAction&>(*pAct)); break;
+ case MetaActionType::MASKSCALEPART : DoAction(static_cast<MetaMaskScalePartAction&>(*pAct)); break;
+ case MetaActionType::GRADIENT : DoAction(static_cast<MetaGradientAction&>(*pAct)); break;
+ case MetaActionType::WALLPAPER : OSL_ENSURE(false, "Tried to construct SdrObject from MetaWallpaperAction: not supported (!)"); break;
+ case MetaActionType::Transparent : DoAction(static_cast<MetaTransparentAction&>(*pAct)); break;
+ case MetaActionType::EPS : OSL_ENSURE(false, "Tried to construct SdrObject from MetaEPSAction: not supported (!)"); break;
+ case MetaActionType::REFPOINT : DoAction(static_cast<MetaRefPointAction&>(*pAct)); break;
+ case MetaActionType::TEXTLINECOLOR : DoAction(static_cast<MetaTextLineColorAction&>(*pAct)); break;
+ case MetaActionType::TEXTLINE : OSL_ENSURE(false, "Tried to construct SdrObject from MetaTextLineAction: not supported (!)"); break;
+ case MetaActionType::FLOATTRANSPARENT : DoAction(static_cast<MetaFloatTransparentAction&>(*pAct)); break;
+ case MetaActionType::GRADIENTEX : DoAction(static_cast<MetaGradientExAction&>(*pAct)); break;
+ case MetaActionType::LAYOUTMODE : DoAction(static_cast<MetaLayoutModeAction&>(*pAct)); break;
+ case MetaActionType::TEXTLANGUAGE : DoAction(static_cast<MetaTextLanguageAction&>(*pAct)); break;
+ case MetaActionType::OVERLINECOLOR : DoAction(static_cast<MetaOverlineColorAction&>(*pAct)); break;
+ default: break;
+ }
+
+ if(pProgrInfo && pActionsToReport)
+ {
+ (*pActionsToReport)++;
+
+ if(*pActionsToReport >= 16) // update all 16 actions
+ {
+ if(!pProgrInfo->ReportActions(*pActionsToReport))
+ break;
+
+ *pActionsToReport = 0;
+ }
+ }
+ }
+}
+
+size_t ImpSdrGDIMetaFileImport::DoImport(
+ const GDIMetaFile& rMtf,
+ SdrObjList& rOL,
+ size_t nInsPos,
+ SvdProgressInfo* pProgrInfo)
+{
+ // setup some global scale parameter
+ // mfScaleX, mfScaleY, maScaleX, maScaleY, mbMov, mbSize
+ mfScaleX = mfScaleY = 1.0;
+ const Size aMtfSize(rMtf.GetPrefSize());
+
+ if(aMtfSize.Width() & aMtfSize.Height() && (!maScaleRect.IsEmpty()))
+ {
+ maOfs = maScaleRect.TopLeft();
+
+ if(aMtfSize.Width() != (maScaleRect.GetWidth() - 1))
+ {
+ mfScaleX = static_cast<double>( maScaleRect.GetWidth() - 1 ) / static_cast<double>(aMtfSize.Width());
+ }
+
+ if(aMtfSize.Height() != (maScaleRect.GetHeight() - 1))
+ {
+ mfScaleY = static_cast<double>( maScaleRect.GetHeight() - 1 ) / static_cast<double>(aMtfSize.Height());
+ }
+ }
+
+ mbMov = maOfs.X()!=0 || maOfs.Y()!=0;
+ mbSize = false;
+ maScaleX = Fraction( 1, 1 );
+ maScaleY = Fraction( 1, 1 );
+
+ if(aMtfSize.Width() != (maScaleRect.GetWidth() - 1))
+ {
+ maScaleX = Fraction(maScaleRect.GetWidth() - 1, aMtfSize.Width());
+ mbSize = true;
+ }
+
+ if(aMtfSize.Height() != (maScaleRect.GetHeight() - 1))
+ {
+ maScaleY = Fraction(maScaleRect.GetHeight() - 1, aMtfSize.Height());
+ mbSize = true;
+ }
+
+ if(pProgrInfo)
+ {
+ pProgrInfo->SetActionCount(rMtf.GetActionSize());
+ }
+
+ sal_uInt32 nActionsToReport(0);
+
+ // execute
+ DoLoopActions(rMtf, pProgrInfo, &nActionsToReport);
+
+ if(pProgrInfo)
+ {
+ pProgrInfo->ReportActions(nActionsToReport);
+ nActionsToReport = 0;
+ }
+
+ // MapMode scaling
+ MapScaling();
+
+ // To calculate the progress meter, we use GetActionSize()*3.
+ // However, maTmpList has a lower entry count limit than GetActionSize(),
+ // so the actions that were assumed were too much have to be re-added.
+ nActionsToReport = (rMtf.GetActionSize() - maTmpList.size()) * 2;
+
+ // announce all currently unannounced rescales
+ if(pProgrInfo)
+ {
+ pProgrInfo->ReportRescales(nActionsToReport);
+ pProgrInfo->SetInsertCount(maTmpList.size());
+ }
+
+ nActionsToReport = 0;
+
+ // insert all objects cached in aTmpList now into rOL from nInsPos
+ nInsPos = std::min(nInsPos, rOL.GetObjCount());
+
+ for(SdrObject* pObj : maTmpList)
+ {
+ rOL.NbcInsertObject(pObj, nInsPos);
+ nInsPos++;
+
+ if(pProgrInfo)
+ {
+ nActionsToReport++;
+
+ if(nActionsToReport >= 32) // update all 32 actions
+ {
+ pProgrInfo->ReportInserts(nActionsToReport);
+ nActionsToReport = 0;
+ }
+ }
+ }
+
+ // report all remaining inserts for the last time
+ if(pProgrInfo)
+ {
+ pProgrInfo->ReportInserts(nActionsToReport);
+ }
+
+ return maTmpList.size();
+}
+
+void ImpSdrGDIMetaFileImport::SetAttributes(SdrObject* pObj, bool bForceTextAttr)
+{
+ mbNoLine = false;
+ mbNoFill = false;
+ bool bLine(!bForceTextAttr);
+ bool bFill(!pObj || (pObj->IsClosedObj() && !bForceTextAttr));
+ bool bText(bForceTextAttr || (pObj && pObj->GetOutlinerParaObject()));
+
+ if(bLine)
+ {
+ if(mnLineWidth)
+ {
+ mpLineAttr->Put(XLineWidthItem(mnLineWidth));
+ }
+ else
+ {
+ mpLineAttr->Put(XLineWidthItem(0));
+ }
+
+ maOldLineColor = mpVD->GetLineColor();
+
+ if(mpVD->IsLineColor())
+ {
+ mpLineAttr->Put(XLineStyleItem(drawing::LineStyle_SOLID));
+ mpLineAttr->Put(XLineColorItem(OUString(), mpVD->GetLineColor()));
+ }
+ else
+ {
+ mpLineAttr->Put(XLineStyleItem(drawing::LineStyle_NONE));
+ }
+
+ switch(maLineJoin)
+ {
+ case basegfx::B2DLineJoin::NONE:
+ mpLineAttr->Put(XLineJointItem(css::drawing::LineJoint_NONE));
+ break;
+ case basegfx::B2DLineJoin::Bevel:
+ mpLineAttr->Put(XLineJointItem(css::drawing::LineJoint_BEVEL));
+ break;
+ case basegfx::B2DLineJoin::Miter:
+ mpLineAttr->Put(XLineJointItem(css::drawing::LineJoint_MITER));
+ break;
+ case basegfx::B2DLineJoin::Round:
+ mpLineAttr->Put(XLineJointItem(css::drawing::LineJoint_ROUND));
+ break;
+ }
+
+ // Add LineCap support
+ mpLineAttr->Put(XLineCapItem(maLineCap));
+
+ if(((maDash.GetDots() && maDash.GetDotLen()) || (maDash.GetDashes() && maDash.GetDashLen())) && maDash.GetDistance())
+ {
+ mpLineAttr->Put(XLineDashItem(OUString(), maDash));
+ }
+ else
+ {
+ mpLineAttr->Put(XLineDashItem(OUString(), XDash(css::drawing::DashStyle_RECT)));
+ }
+ }
+ else
+ {
+ mbNoLine = true;
+ }
+
+ if(bFill)
+ {
+ if(mpVD->IsFillColor())
+ {
+ mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ mpFillAttr->Put(XFillColorItem(OUString(), mpVD->GetFillColor()));
+ }
+ else
+ {
+ mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ }
+ else
+ {
+ mbNoFill = true;
+ }
+
+ if(bText && mbFntDirty)
+ {
+ vcl::Font aFnt(mpVD->GetFont());
+ const sal_uInt32 nHeight(FRound(aFnt.GetFontSize().Height() * mfScaleY));
+
+ mpTextAttr->Put( SvxFontItem( aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(), aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO ) );
+ mpTextAttr->Put( SvxFontItem( aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(), aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO_CJK ) );
+ mpTextAttr->Put( SvxFontItem( aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(), aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO_CTL ) );
+ mpTextAttr->Put(SvxPostureItem(aFnt.GetItalic(), EE_CHAR_ITALIC));
+ mpTextAttr->Put(SvxWeightItem(aFnt.GetWeight(), EE_CHAR_WEIGHT));
+ mpTextAttr->Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
+ mpTextAttr->Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
+ mpTextAttr->Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
+ mpTextAttr->Put(SvxCharScaleWidthItem(100, EE_CHAR_FONTWIDTH));
+ mpTextAttr->Put(SvxUnderlineItem(aFnt.GetUnderline(), EE_CHAR_UNDERLINE));
+ mpTextAttr->Put(SvxOverlineItem(aFnt.GetOverline(), EE_CHAR_OVERLINE));
+ mpTextAttr->Put(SvxCrossedOutItem(aFnt.GetStrikeout(), EE_CHAR_STRIKEOUT));
+ mpTextAttr->Put(SvxShadowedItem(aFnt.IsShadow(), EE_CHAR_SHADOW));
+
+ // #i118485# Setting this item leads to problems (written #i118498# for this)
+ // mpTextAttr->Put(SvxAutoKernItem(aFnt.IsKerning(), EE_CHAR_KERNING));
+
+ mpTextAttr->Put(SvxWordLineModeItem(aFnt.IsWordLineMode(), EE_CHAR_WLM));
+ mpTextAttr->Put(SvxContourItem(aFnt.IsOutline(), EE_CHAR_OUTLINE));
+ mpTextAttr->Put(SvxColorItem(mpVD->GetTextColor(), EE_CHAR_COLOR));
+ //... svxfont textitem svditext
+ mbFntDirty = false;
+ }
+
+ if(!pObj)
+ return;
+
+ pObj->SetLayer(mnLayer);
+
+ if(bLine)
+ {
+ pObj->SetMergedItemSet(*mpLineAttr);
+ }
+
+ if(bFill)
+ {
+ pObj->SetMergedItemSet(*mpFillAttr);
+ }
+
+ if(bText)
+ {
+ pObj->SetMergedItemSet(*mpTextAttr);
+ pObj->SetMergedItem(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT));
+ }
+}
+
+void ImpSdrGDIMetaFileImport::InsertObj(SdrObject* pObj, bool bScale)
+{
+ if(bScale && !maScaleRect.IsEmpty())
+ {
+ if(mbSize)
+ {
+ pObj->NbcResize(Point(), maScaleX, maScaleY);
+ }
+
+ if(mbMov)
+ {
+ pObj->NbcMove(Size(maOfs.X(), maOfs.Y()));
+ }
+ }
+
+ if(isClip())
+ {
+ const basegfx::B2DPolyPolygon aPoly(pObj->TakeXorPoly());
+ const basegfx::B2DRange aOldRange(aPoly.getB2DRange());
+ const SdrLayerID aOldLayer(pObj->GetLayer());
+ const SfxItemSet aOldItemSet(pObj->GetMergedItemSet());
+ const SdrGrafObj* pSdrGrafObj = dynamic_cast< SdrGrafObj* >(pObj);
+ const SdrTextObj* pSdrTextObj = dynamic_cast< SdrTextObj* >(pObj);
+
+ if(pSdrTextObj && pSdrTextObj->HasText())
+ {
+ // all text objects are created from ImportText and have no line or fill attributes, so
+ // it is okay to concentrate on the text itself
+ while(true)
+ {
+ const basegfx::B2DPolyPolygon aTextContour(pSdrTextObj->TakeContour());
+ const basegfx::B2DRange aTextRange(aTextContour.getB2DRange());
+ const basegfx::B2DRange aClipRange(maClip.getB2DRange());
+
+ // no overlap -> completely outside
+ if(!aClipRange.overlaps(aTextRange))
+ {
+ SdrObject::Free(pObj);
+ break;
+ }
+
+ // when the clip is a rectangle fast check for inside is possible
+ if(basegfx::utils::isRectangle(maClip) && aClipRange.isInside(aTextRange))
+ {
+ // completely inside ClipRect
+ break;
+ }
+
+ // here text needs to be clipped; to do so, convert to SdrObjects with polygons
+ // and add these recursively. Delete original object, do not add in this run
+ SdrObject* pConverted = pSdrTextObj->ConvertToPolyObj(true, true).release();
+ SdrObject::Free(pObj);
+
+ if(pConverted)
+ {
+ // recursively add created conversion; per definition this shall not
+ // contain further SdrTextObjs. Visit only non-group objects
+ SdrObjListIter aIter(*pConverted, SdrIterMode::DeepNoGroups);
+
+ // work with clones; the created conversion may contain group objects
+ // and when working with the original objects the loop itself could
+ // break and the cleanup later would be pretty complicated (only delete group
+ // objects, are these empty, ...?)
+ while(aIter.IsMore())
+ {
+ SdrObject* pCandidate = aIter.Next();
+ OSL_ENSURE(pCandidate && dynamic_cast< SdrObjGroup* >(pCandidate) == nullptr, "SdrObjListIter with SdrIterMode::DeepNoGroups error (!)");
+ SdrObject* pNewClone(pCandidate->CloneSdrObject(pCandidate->getSdrModelFromSdrObject()));
+
+ if(pNewClone)
+ {
+ InsertObj(pNewClone, false);
+ }
+ else
+ {
+ OSL_ENSURE(false, "SdrObject::Clone() failed (!)");
+ }
+ }
+
+ // cleanup temporary conversion objects
+ SdrObject::Free(pConverted);
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ BitmapEx aBitmapEx;
+
+ if(pSdrGrafObj)
+ {
+ aBitmapEx = pSdrGrafObj->GetGraphic().GetBitmapEx();
+ }
+
+ SdrObject::Free(pObj);
+
+ if(!aOldRange.isEmpty())
+ {
+ // clip against ClipRegion
+ const basegfx::B2DPolyPolygon aNewPoly(
+ basegfx::utils::clipPolyPolygonOnPolyPolygon(
+ aPoly,
+ maClip,
+ true,
+ !aPoly.isClosed()));
+ const basegfx::B2DRange aNewRange(aNewPoly.getB2DRange());
+
+ if(!aNewRange.isEmpty())
+ {
+ pObj = new SdrPathObj(
+ *mpModel,
+ aNewPoly.isClosed() ? SdrObjKind::Polygon : SdrObjKind::PolyLine,
+ aNewPoly);
+
+ pObj->SetLayer(aOldLayer);
+ pObj->SetMergedItemSet(aOldItemSet);
+
+ if(!aBitmapEx.IsEmpty())
+ {
+ // aNewRange is inside of aOldRange and defines which part of aBitmapEx is used
+ const double fScaleX(aBitmapEx.GetSizePixel().Width() / (aOldRange.getWidth() ? aOldRange.getWidth() : 1.0));
+ const double fScaleY(aBitmapEx.GetSizePixel().Height() / (aOldRange.getHeight() ? aOldRange.getHeight() : 1.0));
+ basegfx::B2DRange aPixel(aNewRange);
+ basegfx::B2DHomMatrix aTrans;
+
+ aTrans.translate(-aOldRange.getMinX(), -aOldRange.getMinY());
+ aTrans.scale(fScaleX, fScaleY);
+ aPixel.transform(aTrans);
+
+ const Size aOrigSizePixel(aBitmapEx.GetSizePixel());
+ const Point aClipTopLeft(
+ basegfx::fround(floor(std::max(0.0, aPixel.getMinX()))),
+ basegfx::fround(floor(std::max(0.0, aPixel.getMinY()))));
+ const Size aClipSize(
+ basegfx::fround(ceil(std::min(static_cast<double>(aOrigSizePixel.Width()), aPixel.getWidth()))),
+ basegfx::fround(ceil(std::min(static_cast<double>(aOrigSizePixel.Height()), aPixel.getHeight()))));
+ const BitmapEx aClippedBitmap(
+ aBitmapEx,
+ aClipTopLeft,
+ aClipSize);
+
+ pObj->SetMergedItem(XFillStyleItem(drawing::FillStyle_BITMAP));
+ pObj->SetMergedItem(XFillBitmapItem(OUString(), Graphic(aClippedBitmap)));
+ pObj->SetMergedItem(XFillBmpTileItem(false));
+ pObj->SetMergedItem(XFillBmpStretchItem(true));
+ }
+ }
+ }
+ }
+ }
+
+ if(!pObj)
+ return;
+
+ // #i111954# check object for visibility
+ // used are SdrPathObj, SdrRectObj, SdrCircObj, SdrGrafObj
+ bool bVisible(false);
+
+ if(pObj->HasLineStyle())
+ {
+ bVisible = true;
+ }
+
+ if(!bVisible && pObj->HasFillStyle())
+ {
+ bVisible = true;
+ }
+
+ if(!bVisible)
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >(pObj);
+
+ if(pTextObj && pTextObj->HasText())
+ {
+ bVisible = true;
+ }
+ }
+
+ if(!bVisible)
+ {
+ SdrGrafObj* pGrafObj = dynamic_cast< SdrGrafObj* >(pObj);
+
+ if(pGrafObj)
+ {
+ // this may be refined to check if the graphic really is visible. It
+ // is here to ensure that graphic objects without fill, line and text
+ // get created
+ bVisible = true;
+ }
+ }
+
+ if(!bVisible)
+ {
+ SdrObject::Free(pObj);
+ }
+ else
+ {
+ maTmpList.push_back(pObj);
+
+ if(dynamic_cast< SdrPathObj* >(pObj))
+ {
+ const bool bClosed(pObj->IsClosedObj());
+
+ mbLastObjWasPolyWithoutLine = mbNoLine && bClosed;
+ mbLastObjWasLine = !bClosed;
+ }
+ else
+ {
+ mbLastObjWasPolyWithoutLine = false;
+ mbLastObjWasLine = false;
+ }
+ }
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaLineAction const & rAct)
+{
+ // #i73407# reformulation to use new B2DPolygon classes
+ const basegfx::B2DPoint aStart(rAct.GetStartPoint().X(), rAct.GetStartPoint().Y());
+ const basegfx::B2DPoint aEnd(rAct.GetEndPoint().X(), rAct.GetEndPoint().Y());
+
+ if(aStart.equal(aEnd))
+ return;
+
+ basegfx::B2DPolygon aLine;
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
+
+ aLine.append(aStart);
+ aLine.append(aEnd);
+ aLine.transform(aTransform);
+
+ const LineInfo& rLineInfo = rAct.GetLineInfo();
+ const sal_Int32 nNewLineWidth(rLineInfo.GetWidth());
+ bool bCreateLineObject(true);
+
+ if(mbLastObjWasLine && (nNewLineWidth == mnLineWidth) && CheckLastLineMerge(aLine))
+ {
+ bCreateLineObject = false;
+ }
+
+ if(!bCreateLineObject)
+ return;
+
+ SdrPathObj* pPath = new SdrPathObj(
+ *mpModel,
+ SdrObjKind::Line,
+ basegfx::B2DPolyPolygon(aLine));
+ mnLineWidth = nNewLineWidth;
+ maLineJoin = rLineInfo.GetLineJoin();
+ maLineCap = rLineInfo.GetLineCap();
+ maDash = XDash(css::drawing::DashStyle_RECT,
+ rLineInfo.GetDotCount(), rLineInfo.GetDotLen(),
+ rLineInfo.GetDashCount(), rLineInfo.GetDashLen(),
+ rLineInfo.GetDistance());
+ SetAttributes(pPath);
+ mnLineWidth = 0;
+ maLineJoin = basegfx::B2DLineJoin::NONE;
+ maDash = XDash();
+ InsertObj(pPath, false);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaRectAction const & rAct)
+{
+ SdrRectObj* pRect = new SdrRectObj(
+ *mpModel,
+ rAct.GetRect());
+ SetAttributes(pRect);
+ InsertObj(pRect);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaRoundRectAction const & rAct)
+{
+ SdrRectObj* pRect = new SdrRectObj(
+ *mpModel,
+ rAct.GetRect());
+ SetAttributes(pRect);
+ tools::Long nRad=(rAct.GetHorzRound()+rAct.GetVertRound())/2;
+ if (nRad!=0) {
+ SfxItemSetFixed<SDRATTR_CORNER_RADIUS, SDRATTR_CORNER_RADIUS> aSet(*mpLineAttr->GetPool());
+ aSet.Put(SdrMetricItem(SDRATTR_CORNER_RADIUS, nRad));
+ pRect->SetMergedItemSet(aSet);
+ }
+ InsertObj(pRect);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaEllipseAction const & rAct)
+{
+ SdrCircObj* pCirc=new SdrCircObj(
+ *mpModel,
+ SdrCircKind::Full,
+ rAct.GetRect());
+ SetAttributes(pCirc);
+ InsertObj(pCirc);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaArcAction const & rAct)
+{
+ Point aCenter(rAct.GetRect().Center());
+ Degree100 nStart=GetAngle(rAct.GetStartPoint()-aCenter);
+ Degree100 nEnd=GetAngle(rAct.GetEndPoint()-aCenter);
+ SdrCircObj* pCirc = new SdrCircObj(
+ *mpModel,
+ SdrCircKind::Arc,
+ rAct.GetRect(),nStart,nEnd);
+ SetAttributes(pCirc);
+ InsertObj(pCirc);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaPieAction const & rAct)
+{
+ Point aCenter(rAct.GetRect().Center());
+ Degree100 nStart=GetAngle(rAct.GetStartPoint()-aCenter);
+ Degree100 nEnd=GetAngle(rAct.GetEndPoint()-aCenter);
+ SdrCircObj* pCirc = new SdrCircObj(
+ *mpModel,
+ SdrCircKind::Section,
+ rAct.GetRect(),
+ nStart,
+ nEnd);
+ SetAttributes(pCirc);
+ InsertObj(pCirc);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaChordAction const & rAct)
+{
+ Point aCenter(rAct.GetRect().Center());
+ Degree100 nStart=GetAngle(rAct.GetStartPoint()-aCenter);
+ Degree100 nEnd=GetAngle(rAct.GetEndPoint()-aCenter);
+ SdrCircObj* pCirc = new SdrCircObj(
+ *mpModel,
+ SdrCircKind::Cut,
+ rAct.GetRect(),
+ nStart,
+ nEnd);
+ SetAttributes(pCirc);
+ InsertObj(pCirc);
+}
+
+bool ImpSdrGDIMetaFileImport::CheckLastLineMerge(const basegfx::B2DPolygon& rSrcPoly)
+{
+ // #i102706# Do not merge closed polygons
+ if(rSrcPoly.isClosed())
+ {
+ return false;
+ }
+
+ // #i73407# reformulation to use new B2DPolygon classes
+ if(mbLastObjWasLine && (maOldLineColor == mpVD->GetLineColor()) && rSrcPoly.count())
+ {
+ SdrObject* pTmpObj = !maTmpList.empty() ? maTmpList[maTmpList.size() - 1] : nullptr;
+ SdrPathObj* pLastPoly = dynamic_cast< SdrPathObj* >(pTmpObj);
+
+ if(pLastPoly)
+ {
+ if(1 == pLastPoly->GetPathPoly().count())
+ {
+ bool bOk(false);
+ basegfx::B2DPolygon aDstPoly(pLastPoly->GetPathPoly().getB2DPolygon(0));
+
+ // #i102706# Do not merge closed polygons
+ if(aDstPoly.isClosed())
+ {
+ return false;
+ }
+
+ if(aDstPoly.count())
+ {
+ const sal_uInt32 nMaxDstPnt(aDstPoly.count() - 1);
+ const sal_uInt32 nMaxSrcPnt(rSrcPoly.count() - 1);
+
+ if(aDstPoly.getB2DPoint(nMaxDstPnt) == rSrcPoly.getB2DPoint(0))
+ {
+ aDstPoly.append(rSrcPoly, 1, rSrcPoly.count() - 1);
+ bOk = true;
+ }
+ else if(aDstPoly.getB2DPoint(0) == rSrcPoly.getB2DPoint(nMaxSrcPnt))
+ {
+ basegfx::B2DPolygon aNew(rSrcPoly);
+ aNew.append(aDstPoly, 1, aDstPoly.count() - 1);
+ aDstPoly = aNew;
+ bOk = true;
+ }
+ else if(aDstPoly.getB2DPoint(0) == rSrcPoly.getB2DPoint(0))
+ {
+ aDstPoly.flip();
+ aDstPoly.append(rSrcPoly, 1, rSrcPoly.count() - 1);
+ bOk = true;
+ }
+ else if(aDstPoly.getB2DPoint(nMaxDstPnt) == rSrcPoly.getB2DPoint(nMaxSrcPnt))
+ {
+ basegfx::B2DPolygon aNew(rSrcPoly);
+ aNew.flip();
+ aDstPoly.append(aNew, 1, aNew.count() - 1);
+ bOk = true;
+ }
+ }
+
+ if(bOk)
+ {
+ pLastPoly->NbcSetPathPoly(basegfx::B2DPolyPolygon(aDstPoly));
+ }
+
+ return bOk;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ImpSdrGDIMetaFileImport::CheckLastPolyLineAndFillMerge(const basegfx::B2DPolyPolygon & rPolyPolygon)
+{
+ // #i73407# reformulation to use new B2DPolygon classes
+ if(mbLastObjWasPolyWithoutLine)
+ {
+ SdrObject* pTmpObj = !maTmpList.empty() ? maTmpList[maTmpList.size() - 1] : nullptr;
+ SdrPathObj* pLastPoly = dynamic_cast< SdrPathObj* >(pTmpObj);
+
+ if(pLastPoly)
+ {
+ if(pLastPoly->GetPathPoly() == rPolyPolygon)
+ {
+ SetAttributes(nullptr);
+
+ if(!mbNoLine && mbNoFill)
+ {
+ pLastPoly->SetMergedItemSet(*mpLineAttr);
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+void ImpSdrGDIMetaFileImport::checkClip()
+{
+ if(!mpVD->IsClipRegion())
+ return;
+
+ maClip = mpVD->GetClipRegion().GetAsB2DPolyPolygon();
+
+ if(isClip())
+ {
+ const basegfx::B2DHomMatrix aTransform(
+ basegfx::utils::createScaleTranslateB2DHomMatrix(
+ mfScaleX,
+ mfScaleY,
+ maOfs.X(),
+ maOfs.Y()));
+
+ maClip.transform(aTransform);
+ }
+}
+
+bool ImpSdrGDIMetaFileImport::isClip() const
+{
+ return !maClip.getB2DRange().isEmpty();
+}
+
+void ImpSdrGDIMetaFileImport::DoAction( MetaPolyLineAction const & rAct )
+{
+ // #i73407# reformulation to use new B2DPolygon classes
+ basegfx::B2DPolygon aSource(rAct.GetPolygon().getB2DPolygon());
+
+ if(aSource.count())
+ {
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
+ aSource.transform(aTransform);
+ }
+
+ const LineInfo& rLineInfo = rAct.GetLineInfo();
+ const sal_Int32 nNewLineWidth(rLineInfo.GetWidth());
+ bool bCreateLineObject(true);
+
+ if(mbLastObjWasLine && (nNewLineWidth == mnLineWidth) && CheckLastLineMerge(aSource))
+ {
+ bCreateLineObject = false;
+ }
+ else if(mbLastObjWasPolyWithoutLine && CheckLastPolyLineAndFillMerge(basegfx::B2DPolyPolygon(aSource)))
+ {
+ bCreateLineObject = false;
+ }
+
+ if(!bCreateLineObject)
+ return;
+
+ SdrPathObj* pPath = new SdrPathObj(
+ *mpModel,
+ aSource.isClosed() ? SdrObjKind::Polygon : SdrObjKind::PolyLine,
+ basegfx::B2DPolyPolygon(aSource));
+ mnLineWidth = nNewLineWidth;
+ maLineJoin = rLineInfo.GetLineJoin();
+ maLineCap = rLineInfo.GetLineCap();
+ maDash = XDash(css::drawing::DashStyle_RECT,
+ rLineInfo.GetDotCount(), rLineInfo.GetDotLen(),
+ rLineInfo.GetDashCount(), rLineInfo.GetDashLen(),
+ rLineInfo.GetDistance());
+ SetAttributes(pPath);
+ mnLineWidth = 0;
+ maLineJoin = basegfx::B2DLineJoin::NONE;
+ maDash = XDash();
+ InsertObj(pPath, false);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction( MetaPolygonAction const & rAct )
+{
+ // #i73407# reformulation to use new B2DPolygon classes
+ basegfx::B2DPolygon aSource(rAct.GetPolygon().getB2DPolygon());
+
+ if(!aSource.count())
+ return;
+
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
+ aSource.transform(aTransform);
+
+ if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(basegfx::B2DPolyPolygon(aSource)))
+ {
+ // #i73407# make sure polygon is closed, it's a filled primitive
+ aSource.setClosed(true);
+ SdrPathObj* pPath = new SdrPathObj(
+ *mpModel,
+ SdrObjKind::Polygon,
+ basegfx::B2DPolyPolygon(aSource));
+ SetAttributes(pPath);
+ InsertObj(pPath, false);
+ }
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaPolyPolygonAction const & rAct)
+{
+ // #i73407# reformulation to use new B2DPolygon classes
+ basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
+
+ if(!aSource.count())
+ return;
+
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
+ aSource.transform(aTransform);
+
+ if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(aSource))
+ {
+ // #i73407# make sure polygon is closed, it's a filled primitive
+ aSource.setClosed(true);
+ SdrPathObj* pPath = new SdrPathObj(
+ *mpModel,
+ SdrObjKind::Polygon,
+ aSource);
+ SetAttributes(pPath);
+ InsertObj(pPath, false);
+ }
+}
+
+void ImpSdrGDIMetaFileImport::ImportText( const Point& rPos, const OUString& rStr, const MetaAction& rAct )
+{
+ // calc text box size, add 5% to make it fit safely
+
+ FontMetric aFontMetric( mpVD->GetFontMetric() );
+ vcl::Font aFnt( mpVD->GetFont() );
+ TextAlign eAlg( aFnt.GetAlignment() );
+
+ sal_Int32 nTextWidth = static_cast<sal_Int32>( mpVD->GetTextWidth( rStr ) * mfScaleX );
+ sal_Int32 nTextHeight = static_cast<sal_Int32>( mpVD->GetTextHeight() * mfScaleY );
+
+ Point aPos( FRound(rPos.X() * mfScaleX + maOfs.X()), FRound(rPos.Y() * mfScaleY + maOfs.Y()) );
+ Size aSize( nTextWidth, nTextHeight );
+
+ if ( eAlg == ALIGN_BASELINE )
+ aPos.AdjustY( -(FRound(aFontMetric.GetAscent() * mfScaleY)) );
+ else if ( eAlg == ALIGN_BOTTOM )
+ aPos.AdjustY( -nTextHeight );
+
+ tools::Rectangle aTextRect( aPos, aSize );
+ SdrRectObj* pText = new SdrRectObj(
+ *mpModel,
+ SdrObjKind::Text,
+ aTextRect);
+
+ pText->SetMergedItem ( makeSdrTextUpperDistItem (0));
+ pText->SetMergedItem ( makeSdrTextLowerDistItem (0));
+ pText->SetMergedItem ( makeSdrTextRightDistItem (0));
+ pText->SetMergedItem ( makeSdrTextLeftDistItem (0));
+
+ if ( aFnt.GetAverageFontWidth() || ( rAct.GetType() == MetaActionType::STRETCHTEXT ) )
+ {
+ pText->ClearMergedItem( SDRATTR_TEXT_AUTOGROWWIDTH );
+ pText->SetMergedItem( makeSdrTextAutoGrowHeightItem( false ) );
+ // don't let the margins eat the space needed for the text
+ pText->SetMergedItem( SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_ALLLINES) );
+ }
+ else
+ {
+ pText->SetMergedItem( makeSdrTextAutoGrowWidthItem( true ) );
+ }
+
+ pText->SetLayer(mnLayer);
+ pText->NbcSetText( rStr );
+ SetAttributes( pText, true );
+ pText->SetSnapRect( aTextRect );
+
+ if (!aFnt.IsTransparent())
+ {
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aAttr(*mpFillAttr->GetPool());
+ aAttr.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ aAttr.Put(XFillColorItem(OUString(), aFnt.GetFillColor()));
+ pText->SetMergedItemSet(aAttr);
+ }
+ Degree100 nAngle = to<Degree100>(aFnt.GetOrientation());
+ if ( nAngle )
+ pText->SdrAttrObj::NbcRotate(aPos,nAngle);
+ InsertObj( pText, false );
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaTextAction const & rAct)
+{
+ OUString aStr(rAct.GetText());
+ aStr = aStr.copy(rAct.GetIndex(), rAct.GetLen());
+ ImportText( rAct.GetPoint(), aStr, rAct );
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaTextArrayAction const & rAct)
+{
+ OUString aStr(rAct.GetText());
+ aStr = aStr.copy(rAct.GetIndex(), rAct.GetLen());
+ ImportText( rAct.GetPoint(), aStr, rAct );
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaStretchTextAction const & rAct)
+{
+ OUString aStr(rAct.GetText());
+ aStr = aStr.copy(rAct.GetIndex(), rAct.GetLen());
+ ImportText( rAct.GetPoint(), aStr, rAct );
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaBmpAction const & rAct)
+{
+ tools::Rectangle aRect(rAct.GetPoint(),rAct.GetBitmap().GetSizePixel());
+ aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
+ SdrGrafObj* pGraf = new SdrGrafObj(
+ *mpModel,
+ Graphic(BitmapEx(rAct.GetBitmap())),
+ aRect);
+
+ // This action is not creating line and fill, set directly, do not use SetAttributes(..)
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaBmpScaleAction const & rAct)
+{
+ tools::Rectangle aRect(rAct.GetPoint(),rAct.GetSize());
+ aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
+ SdrGrafObj* pGraf = new SdrGrafObj(
+ *mpModel,
+ Graphic(BitmapEx(rAct.GetBitmap())),
+ aRect);
+
+ // This action is not creating line and fill, set directly, do not use SetAttributes(..)
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaBmpExAction const & rAct)
+{
+ tools::Rectangle aRect(rAct.GetPoint(),rAct.GetBitmapEx().GetSizePixel());
+ aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
+ SdrGrafObj* pGraf = new SdrGrafObj(
+ *mpModel,
+ rAct.GetBitmapEx(),
+ aRect);
+
+ // This action is not creating line and fill, set directly, do not use SetAttributes(..)
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaBmpExScaleAction const & rAct)
+{
+ tools::Rectangle aRect(rAct.GetPoint(),rAct.GetSize());
+ aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
+ SdrGrafObj* pGraf = new SdrGrafObj(
+ *mpModel,
+ rAct.GetBitmapEx(),
+ aRect);
+
+ // This action is not creating line and fill, set directly, do not use SetAttributes(..)
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+
+void ImpSdrGDIMetaFileImport::DoAction( MetaHatchAction const & rAct )
+{
+ // #i73407# reformulation to use new B2DPolygon classes
+ basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
+
+ if(!aSource.count())
+ return;
+
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
+ aSource.transform(aTransform);
+
+ if(mbLastObjWasPolyWithoutLine && CheckLastPolyLineAndFillMerge(aSource))
+ return;
+
+ const Hatch& rHatch = rAct.GetHatch();
+ SdrPathObj* pPath = new SdrPathObj(
+ *mpModel,
+ SdrObjKind::Polygon,
+ aSource);
+ // #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
+ SfxItemSet aHatchAttr(mpModel->GetItemPool(), pPath->GetMergedItemSet().GetRanges());
+ css::drawing::HatchStyle eStyle;
+
+ switch(rHatch.GetStyle())
+ {
+ case HatchStyle::Triple :
+ {
+ eStyle = css::drawing::HatchStyle_TRIPLE;
+ break;
+ }
+
+ case HatchStyle::Double :
+ {
+ eStyle = css::drawing::HatchStyle_DOUBLE;
+ break;
+ }
+
+ default:
+ {
+ eStyle = css::drawing::HatchStyle_SINGLE;
+ break;
+ }
+ }
+
+ SetAttributes(pPath);
+ aHatchAttr.Put(XFillStyleItem(drawing::FillStyle_HATCH));
+ aHatchAttr.Put(XFillHatchItem(XHatch(rHatch.GetColor(), eStyle, rHatch.GetDistance(), rHatch.GetAngle())));
+ pPath->SetMergedItemSet(aHatchAttr);
+
+ InsertObj(pPath, false);
+}
+
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaLineColorAction& rAct)
+{
+ rAct.Execute(mpVD);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaMapModeAction& rAct)
+{
+ MapScaling();
+ rAct.Execute(mpVD);
+ mbLastObjWasPolyWithoutLine = false;
+ mbLastObjWasLine = false;
+}
+
+void ImpSdrGDIMetaFileImport::MapScaling()
+{
+ const size_t nCount(maTmpList.size());
+ const MapMode& rMap = mpVD->GetMapMode();
+ Point aMapOrg( rMap.GetOrigin() );
+ bool bMov2(aMapOrg.X() != 0 || aMapOrg.Y() != 0);
+
+ if(bMov2)
+ {
+ for(size_t i = mnMapScalingOfs; i < nCount; i++)
+ {
+ SdrObject* pObj = maTmpList[i];
+
+ pObj->NbcMove(Size(aMapOrg.X(), aMapOrg.Y()));
+ }
+ }
+
+ mnMapScalingOfs = nCount;
+}
+
+
+void ImpSdrGDIMetaFileImport::DoAction( MetaCommentAction const & rAct, GDIMetaFile const & rMtf, sal_uLong& a) // GDIMetaFile* pMtf )
+{
+ bool aSkipComment = false;
+
+ if (a < rMtf.GetActionSize() && rAct.GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN"))
+ {
+ // #i125211# Check if next action is a MetaGradientExAction
+ MetaGradientExAction* pAct = dynamic_cast< MetaGradientExAction* >(rMtf.GetAction(a + 1));
+
+ if( pAct && pAct->GetType() == MetaActionType::GRADIENTEX )
+ {
+ // #i73407# reformulation to use new B2DPolygon classes
+ basegfx::B2DPolyPolygon aSource(pAct->GetPolyPolygon().getB2DPolyPolygon());
+
+ if(aSource.count())
+ {
+ if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(aSource))
+ {
+ const Gradient& rGrad = pAct->GetGradient();
+ SdrPathObj* pPath = new SdrPathObj(
+ *mpModel,
+ SdrObjKind::Polygon,
+ aSource);
+ // #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
+ SfxItemSet aGradAttr(mpModel->GetItemPool(), pPath->GetMergedItemSet().GetRanges());
+ XGradient aXGradient;
+
+ aXGradient.SetGradientStyle(static_cast<css::awt::GradientStyle>(rGrad.GetStyle()));
+ aXGradient.SetStartColor(rGrad.GetStartColor());
+ aXGradient.SetEndColor(rGrad.GetEndColor());
+ aXGradient.SetAngle(rGrad.GetAngle());
+ aXGradient.SetBorder(rGrad.GetBorder());
+ aXGradient.SetXOffset(rGrad.GetOfsX());
+ aXGradient.SetYOffset(rGrad.GetOfsY());
+ aXGradient.SetStartIntens(rGrad.GetStartIntensity());
+ aXGradient.SetEndIntens(rGrad.GetEndIntensity());
+ aXGradient.SetSteps(rGrad.GetSteps());
+
+ // no need to use SetAttributes(..) here since line and fill style
+ // need to be set individually
+ // SetAttributes(pPath);
+
+ // switch line off; if there was one there will be a
+ // MetaActionType::POLYLINE following creating another object
+ aGradAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
+
+ // add detected gradient fillstyle
+ aGradAttr.Put(XFillStyleItem(drawing::FillStyle_GRADIENT));
+ aGradAttr.Put(XFillGradientItem(aXGradient));
+
+ pPath->SetMergedItemSet(aGradAttr);
+
+ InsertObj(pPath);
+ }
+ }
+
+ aSkipComment = true;
+ }
+ }
+
+ if(aSkipComment)
+ {
+ // #i125211# forward until closing MetaCommentAction
+ MetaAction* pSkipAct = rMtf.GetAction(++a);
+
+ while( pSkipAct
+ && ((pSkipAct->GetType() != MetaActionType::COMMENT )
+ || !(static_cast<MetaCommentAction*>(pSkipAct)->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_END"))))
+ {
+ pSkipAct = rMtf.GetAction(++a);
+ }
+ }
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaTextRectAction const & rAct)
+{
+ GDIMetaFile aTemp;
+
+ mpVD->AddTextRectActions(rAct.GetRect(), rAct.GetText(), rAct.GetStyle(), aTemp);
+ DoLoopActions(aTemp, nullptr, nullptr);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaBmpScalePartAction const & rAct)
+{
+ tools::Rectangle aRect(rAct.GetDestPoint(), rAct.GetDestSize());
+ BitmapEx aBitmapEx(rAct.GetBitmap());
+
+ aRect.AdjustRight( 1 );
+ aRect.AdjustBottom( 1 );
+ aBitmapEx.Crop(tools::Rectangle(rAct.GetSrcPoint(), rAct.GetSrcSize()));
+ SdrGrafObj* pGraf = new SdrGrafObj(
+ *mpModel,
+ aBitmapEx,
+ aRect);
+
+ // This action is not creating line and fill, set directly, do not use SetAttributes(..)
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaBmpExScalePartAction const & rAct)
+{
+ tools::Rectangle aRect(rAct.GetDestPoint(),rAct.GetDestSize());
+ BitmapEx aBitmapEx(rAct.GetBitmapEx());
+
+ aRect.AdjustRight( 1 );
+ aRect.AdjustBottom( 1 );
+ aBitmapEx.Crop(tools::Rectangle(rAct.GetSrcPoint(), rAct.GetSrcSize()));
+ SdrGrafObj* pGraf = new SdrGrafObj(
+ *mpModel,
+ aBitmapEx,
+ aRect);
+
+ // This action is not creating line and fill, set directly, do not use SetAttributes(..)
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaMaskAction const & rAct)
+{
+ tools::Rectangle aRect(rAct.GetPoint(), rAct.GetBitmap().GetSizePixel());
+ BitmapEx aBitmapEx(rAct.GetBitmap(), rAct.GetColor());
+
+ aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
+ SdrGrafObj* pGraf = new SdrGrafObj(
+ *mpModel,
+ aBitmapEx,
+ aRect);
+
+ // This action is not creating line and fill, set directly, do not use SetAttributes(..)
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaMaskScaleAction const & rAct)
+{
+ tools::Rectangle aRect(rAct.GetPoint(), rAct.GetSize());
+ BitmapEx aBitmapEx(rAct.GetBitmap(), rAct.GetColor());
+
+ aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
+ SdrGrafObj* pGraf = new SdrGrafObj(
+ *mpModel,
+ aBitmapEx,
+ aRect);
+
+ // This action is not creating line and fill, set directly, do not use SetAttributes(..)
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaMaskScalePartAction const & rAct)
+{
+ tools::Rectangle aRect(rAct.GetDestPoint(), rAct.GetDestSize());
+ BitmapEx aBitmapEx(rAct.GetBitmap(), rAct.GetColor());
+
+ aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
+ aBitmapEx.Crop(tools::Rectangle(rAct.GetSrcPoint(), rAct.GetSrcSize()));
+ SdrGrafObj* pGraf = new SdrGrafObj(
+ *mpModel,
+ aBitmapEx,
+ aRect);
+
+ // This action is not creating line and fill, set directly, do not use SetAttributes(..)
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+namespace
+{
+ css::awt::GradientStyle getXGradientStyleFromGradientStyle(const GradientStyle& rGradientStyle)
+ {
+ css::awt::GradientStyle aXGradientStyle(css::awt::GradientStyle_LINEAR);
+
+ switch(rGradientStyle)
+ {
+ case GradientStyle::Linear: aXGradientStyle = css::awt::GradientStyle_LINEAR; break;
+ case GradientStyle::Axial: aXGradientStyle = css::awt::GradientStyle_AXIAL; break;
+ case GradientStyle::Radial: aXGradientStyle = css::awt::GradientStyle_RADIAL; break;
+ case GradientStyle::Elliptical: aXGradientStyle = css::awt::GradientStyle_ELLIPTICAL; break;
+ case GradientStyle::Square: aXGradientStyle = css::awt::GradientStyle_SQUARE; break;
+ case GradientStyle::Rect: aXGradientStyle = css::awt::GradientStyle_RECT; break;
+
+ // Needed due to GradientStyle::FORCE_EQUAL_SIZE; this again is needed
+ // to force the enum defines in VCL to a defined size for the compilers,
+ // so despite it is never used it cannot be removed (would break the
+ // API implementation probably).
+ case GradientStyle::FORCE_EQUAL_SIZE: break;
+ default:
+ break;
+ }
+
+ return aXGradientStyle;
+ }
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaGradientAction const & rAct)
+{
+ basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(rAct.GetRect());
+
+ if(aRange.isEmpty())
+ return;
+
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
+ aRange.transform(aTransform);
+ const Gradient& rGradient = rAct.GetGradient();
+ SdrRectObj* pRect = new SdrRectObj(
+ *mpModel,
+ tools::Rectangle(
+ floor(aRange.getMinX()),
+ floor(aRange.getMinY()),
+ ceil(aRange.getMaxX()),
+ ceil(aRange.getMaxY())));
+ // #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
+ SfxItemSet aGradientAttr(mpModel->GetItemPool(), pRect->GetMergedItemSet().GetRanges());
+ const css::awt::GradientStyle aXGradientStyle(getXGradientStyleFromGradientStyle(rGradient.GetStyle()));
+ const XFillGradientItem aXFillGradientItem(
+ XGradient(
+ rGradient.GetStartColor(),
+ rGradient.GetEndColor(),
+ aXGradientStyle,
+ rGradient.GetAngle(),
+ rGradient.GetOfsX(),
+ rGradient.GetOfsY(),
+ rGradient.GetBorder(),
+ rGradient.GetStartIntensity(),
+ rGradient.GetEndIntensity(),
+ rGradient.GetSteps()));
+
+ SetAttributes(pRect);
+ aGradientAttr.Put(XFillStyleItem(drawing::FillStyle_GRADIENT)); // #i125211#
+ aGradientAttr.Put(aXFillGradientItem);
+ pRect->SetMergedItemSet(aGradientAttr);
+
+ InsertObj(pRect, false);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaTransparentAction const & rAct)
+{
+ basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
+
+ if(!aSource.count())
+ return;
+
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
+ aSource.transform(aTransform);
+ aSource.setClosed(true);
+
+ SdrPathObj* pPath = new SdrPathObj(
+ *mpModel,
+ SdrObjKind::Polygon,
+ aSource);
+ SetAttributes(pPath);
+ pPath->SetMergedItem(XFillTransparenceItem(rAct.GetTransparence()));
+ InsertObj(pPath, false);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaGradientExAction const & rAct)
+{
+ basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
+
+ if(!aSource.count())
+ return;
+
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
+ aSource.transform(aTransform);
+
+ if(mbLastObjWasPolyWithoutLine && CheckLastPolyLineAndFillMerge(aSource))
+ return;
+
+ const Gradient& rGradient = rAct.GetGradient();
+ SdrPathObj* pPath = new SdrPathObj(
+ *mpModel,
+ SdrObjKind::Polygon,
+ aSource);
+ // #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
+ SfxItemSet aGradientAttr(mpModel->GetItemPool(), pPath->GetMergedItemSet().GetRanges());
+ const css::awt::GradientStyle aXGradientStyle(getXGradientStyleFromGradientStyle(rGradient.GetStyle()));
+ const XFillGradientItem aXFillGradientItem(
+ XGradient(
+ rGradient.GetStartColor(),
+ rGradient.GetEndColor(),
+ aXGradientStyle,
+ rGradient.GetAngle(),
+ rGradient.GetOfsX(),
+ rGradient.GetOfsY(),
+ rGradient.GetBorder(),
+ rGradient.GetStartIntensity(),
+ rGradient.GetEndIntensity(),
+ rGradient.GetSteps()));
+
+ SetAttributes(pPath);
+ aGradientAttr.Put(XFillStyleItem(drawing::FillStyle_GRADIENT)); // #i125211#
+ aGradientAttr.Put(aXFillGradientItem);
+ pPath->SetMergedItemSet(aGradientAttr);
+
+ InsertObj(pPath, false);
+}
+
+void ImpSdrGDIMetaFileImport::DoAction(MetaFloatTransparentAction const & rAct)
+{
+ const GDIMetaFile& rMtf = rAct.GetGDIMetaFile();
+
+ if(!rMtf.GetActionSize())
+ return;
+
+ const tools::Rectangle aRect(rAct.GetPoint(),rAct.GetSize());
+
+ // convert metafile sub-content to BitmapEx
+ BitmapEx aBitmapEx(
+ convertMetafileToBitmapEx(
+ rMtf,
+ vcl::unotools::b2DRectangleFromRectangle(aRect),
+ 125000));
+
+ // handle colors
+ const Gradient& rGradient = rAct.GetGradient();
+ basegfx::BColor aStart(rGradient.GetStartColor().getBColor());
+ basegfx::BColor aEnd(rGradient.GetEndColor().getBColor());
+
+ if(100 != rGradient.GetStartIntensity())
+ {
+ aStart *= static_cast<double>(rGradient.GetStartIntensity()) / 100.0;
+ }
+
+ if(100 != rGradient.GetEndIntensity())
+ {
+ aEnd *= static_cast<double>(rGradient.GetEndIntensity()) / 100.0;
+ }
+
+ const bool bEqualColors(aStart == aEnd);
+ const bool bNoSteps(1 == rGradient.GetSteps());
+ bool bCreateObject(true);
+ bool bHasNewMask(false);
+ AlphaMask aNewMask;
+ double fTransparence(0.0);
+ bool bFixedTransparence(false);
+
+ if(bEqualColors || bNoSteps)
+ {
+ // single transparence
+ const basegfx::BColor aMedium(basegfx::average(aStart, aEnd));
+ fTransparence = aMedium.luminance();
+
+ if(basegfx::fTools::lessOrEqual(fTransparence, 0.0))
+ {
+ // no transparence needed, all done
+ }
+ else if(basegfx::fTools::moreOrEqual(fTransparence, 1.0))
+ {
+ // all transparent, no object
+ bCreateObject = false;
+ }
+ else
+ {
+ // 0.0 < transparence < 1.0, apply fixed transparence
+ bFixedTransparence = true;
+ }
+ }
+ else
+ {
+ // gradient transparence
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+
+ pVDev->SetOutputSizePixel(aBitmapEx.GetBitmap().GetSizePixel());
+ pVDev->DrawGradient(tools::Rectangle(Point(0, 0), pVDev->GetOutputSizePixel()), rGradient);
+
+ aNewMask = AlphaMask(pVDev->GetBitmap(Point(0, 0), pVDev->GetOutputSizePixel()));
+ bHasNewMask = true;
+ }
+
+ if(!bCreateObject)
+ return;
+
+ if(bHasNewMask || bFixedTransparence)
+ {
+ if(!aBitmapEx.IsAlpha())
+ {
+ // no transparence yet, apply new one
+ if(bFixedTransparence)
+ {
+ sal_uInt8 aAlpha(basegfx::fround(fTransparence * 255.0));
+
+ aNewMask = AlphaMask(aBitmapEx.GetBitmap().GetSizePixel(), &aAlpha);
+ }
+
+ aBitmapEx = BitmapEx(aBitmapEx.GetBitmap(), aNewMask);
+ }
+ else
+ {
+ vcl::bitmap::DrawAlphaBitmapAndAlphaGradient(aBitmapEx, bFixedTransparence, fTransparence, aNewMask);
+ }
+ }
+
+ // create and add object
+ SdrGrafObj* pGraf = new SdrGrafObj(
+ *mpModel,
+ aBitmapEx,
+ aRect);
+
+ // for MetaFloatTransparentAction, do not use SetAttributes(...)
+ // since these metafile content is not used to draw line/fill
+ // dependent of these setting at the device content
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdfmtf.hxx b/svx/source/svdraw/svdfmtf.hxx
new file mode 100644
index 000000000..0e788bcd5
--- /dev/null
+++ b/svx/source/svdraw/svdfmtf.hxx
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_SVDRAW_SVDFMTF_HXX
+#define INCLUDED_SVX_SOURCE_SVDRAW_SVDFMTF_HXX
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <svl/itemset.hxx>
+#include <tools/fract.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/xdash.hxx>
+
+// Forward Declarations
+
+
+class SfxItemSet;
+class SdrObjList;
+class SdrModel;
+class SdrPage;
+class SdrObject;
+class SvdProgressInfo;
+
+
+// Helper Class ImpSdrGDIMetaFileImport
+class ImpSdrGDIMetaFileImport final
+{
+ ::std::vector< SdrObject* > maTmpList;
+ ScopedVclPtr<VirtualDevice> mpVD;
+ tools::Rectangle maScaleRect;
+ size_t mnMapScalingOfs; // from here on, not edited with MapScaling
+ std::unique_ptr<SfxItemSet> mpLineAttr;
+ std::unique_ptr<SfxItemSet> mpFillAttr;
+ std::unique_ptr<SfxItemSet> mpTextAttr;
+ SdrModel* mpModel;
+ SdrLayerID mnLayer;
+ Color maOldLineColor;
+ sal_Int32 mnLineWidth;
+ basegfx::B2DLineJoin maLineJoin;
+ css::drawing::LineCap maLineCap;
+ XDash maDash;
+
+ bool mbMov;
+ bool mbSize;
+ Point maOfs;
+ double mfScaleX;
+ double mfScaleY;
+ Fraction maScaleX;
+ Fraction maScaleY;
+
+ bool mbFntDirty;
+
+ // to optimize (PenNULL,Brush,DrawPoly),(Pen,BrushNULL,DrawPoly) -> two-in-one
+ bool mbLastObjWasPolyWithoutLine;
+ bool mbNoLine;
+ bool mbNoFill;
+
+ // to optimize multiple lines into a Polyline
+ bool mbLastObjWasLine;
+
+ // clipregion
+ basegfx::B2DPolyPolygon maClip;
+
+ // check for clip and evtl. fill maClip
+ void checkClip();
+ bool isClip() const;
+
+ // actions
+ void DoAction(MetaLineAction const & rAct);
+ void DoAction(MetaRectAction const & rAct);
+ void DoAction(MetaRoundRectAction const & rAct);
+ void DoAction(MetaEllipseAction const & rAct);
+ void DoAction(MetaArcAction const & rAct);
+ void DoAction(MetaPieAction const & rAct);
+ void DoAction(MetaChordAction const & rAct);
+ void DoAction(MetaPolyLineAction const & rAct);
+ void DoAction(MetaPolygonAction const & rAct);
+ void DoAction(MetaPolyPolygonAction const & rAct);
+ void DoAction(MetaTextAction const & rAct);
+ void DoAction(MetaTextArrayAction const & rAct);
+ void DoAction(MetaStretchTextAction const & rAct);
+ void DoAction(MetaBmpAction const & rAct);
+ void DoAction(MetaBmpScaleAction const & rAct);
+ void DoAction(MetaBmpExAction const & rAct);
+ void DoAction(MetaBmpExScaleAction const & rAct);
+ void DoAction(MetaHatchAction const & rAct);
+ void DoAction(MetaLineColorAction & rAct);
+ void DoAction(MetaMapModeAction & rAct);
+ void DoAction(MetaFillColorAction & rAct) { rAct.Execute(mpVD); }
+ void DoAction(MetaTextColorAction & rAct) { rAct.Execute(mpVD); }
+ void DoAction(MetaTextFillColorAction & rAct) { rAct.Execute(mpVD); }
+ void DoAction(MetaFontAction & rAct) { rAct.Execute(mpVD); mbFntDirty = true; }
+ void DoAction(MetaTextAlignAction & rAct) { rAct.Execute(mpVD); mbFntDirty = true; }
+ void DoAction(MetaClipRegionAction & rAct) { rAct.Execute(mpVD); checkClip(); }
+ void DoAction(MetaRasterOpAction & rAct) { rAct.Execute(mpVD); }
+ void DoAction(MetaPushAction & rAct) { rAct.Execute(mpVD); checkClip(); }
+ void DoAction(MetaPopAction & rAct) { rAct.Execute(mpVD); mbFntDirty = true; checkClip(); }
+ void DoAction(MetaMoveClipRegionAction & rAct) { rAct.Execute(mpVD); checkClip(); }
+ void DoAction(MetaISectRectClipRegionAction& rAct) { rAct.Execute(mpVD); checkClip(); }
+ void DoAction(MetaISectRegionClipRegionAction& rAct) { rAct.Execute(mpVD); checkClip(); }
+
+ // #i125211# The MetaCommentAction needs to advance (if used), thus
+ // give current metafile and index which may be changed
+ void DoAction(MetaCommentAction const & rAct, GDIMetaFile const & rMtf, sal_uLong& a);
+
+ // missing actions added
+ void DoAction(MetaTextRectAction const & rAct);
+ void DoAction(MetaBmpScalePartAction const & rAct);
+ void DoAction(MetaBmpExScalePartAction const & rAct);
+ void DoAction(MetaMaskAction const & rAct);
+ void DoAction(MetaMaskScaleAction const & rAct);
+ void DoAction(MetaMaskScalePartAction const & rAct);
+ void DoAction(MetaGradientAction const & rAct);
+ void DoAction(MetaTransparentAction const & rAct);
+ void DoAction(MetaRefPointAction& rAct) { rAct.Execute(mpVD); }
+ void DoAction(MetaTextLineColorAction& rAct) { rAct.Execute(mpVD); mbFntDirty = true; }
+ void DoAction(MetaFloatTransparentAction const & rAct);
+ void DoAction(MetaGradientExAction const & rAct);
+ void DoAction(MetaLayoutModeAction& rAct) { rAct.Execute(mpVD); mbFntDirty = true; }
+ void DoAction(MetaTextLanguageAction& rAct) { rAct.Execute(mpVD); mbFntDirty = true; }
+ void DoAction(MetaOverlineColorAction& rAct) { rAct.Execute(mpVD); mbFntDirty = true; }
+
+ void ImportText(const Point& rPos, const OUString& rStr, const MetaAction& rAct);
+ void SetAttributes(SdrObject* pObj, bool bForceTextAttr = false);
+ void InsertObj(SdrObject* pObj, bool bScale = true);
+ void MapScaling();
+
+ // #i73407# reformulation to use new B2DPolygon classes
+ bool CheckLastLineMerge(const basegfx::B2DPolygon& rSrcPoly);
+ bool CheckLastPolyLineAndFillMerge(const basegfx::B2DPolyPolygon& rPolyPolygon);
+
+ void DoLoopActions(GDIMetaFile const & rMtf, SvdProgressInfo* pProgrInfo, sal_uInt32* pActionsToReport);
+
+ // Copy assignment is forbidden and not implemented.
+ ImpSdrGDIMetaFileImport (const ImpSdrGDIMetaFileImport &) = delete;
+ ImpSdrGDIMetaFileImport & operator= (const ImpSdrGDIMetaFileImport &) = delete;
+
+public:
+ ImpSdrGDIMetaFileImport(
+ SdrModel& rModel,
+ SdrLayerID nLay,
+ const tools::Rectangle& rRect);
+
+ size_t DoImport(
+ const GDIMetaFile& rMtf,
+ SdrObjList& rDestList,
+ size_t nInsPos,
+ SvdProgressInfo* pProgrInfo = nullptr);
+};
+
+#endif // INCLUDED_SVX_SOURCE_SVDRAW_SVDFMTF_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdglev.cxx b/svx/source/svdraw/svdglev.cxx
new file mode 100644
index 000000000..67c64eb1a
--- /dev/null
+++ b/svx/source/svdraw/svdglev.cxx
@@ -0,0 +1,400 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdglev.hxx>
+#include <math.h>
+
+#include <svx/svdundo.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svdglue.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdobj.hxx>
+
+SdrGlueEditView::SdrGlueEditView(
+ SdrModel& rSdrModel,
+ OutputDevice* pOut)
+: SdrPolyEditView(rSdrModel, pOut)
+{
+}
+
+SdrGlueEditView::~SdrGlueEditView()
+{
+}
+
+void SdrGlueEditView::ImpDoMarkedGluePoints(PGlueDoFunc pDoFunc, bool bConst, const void* p1, const void* p2, const void* p3, const void* p4)
+{
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm) {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+ if (!rPts.empty())
+ {
+ SdrGluePointList* pGPL=nullptr;
+ if (bConst) {
+ const SdrGluePointList* pConstGPL=pObj->GetGluePointList();
+ pGPL=const_cast<SdrGluePointList*>(pConstGPL);
+ } else {
+ pGPL=pObj->ForceGluePointList();
+ }
+ if (pGPL!=nullptr)
+ {
+ if(!bConst && IsUndoEnabled() )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+
+ for(sal_uInt16 nPtId : rPts)
+ {
+ sal_uInt16 nGlueIdx=pGPL->FindGluePoint(nPtId);
+ if (nGlueIdx!=SDRGLUEPOINT_NOTFOUND)
+ {
+ SdrGluePoint& rGP=(*pGPL)[nGlueIdx];
+ (*pDoFunc)(rGP,pObj,p1,p2,p3,p4);
+ }
+ }
+ if (!bConst)
+ {
+ pObj->SetChanged();
+ pObj->BroadcastObjectChange();
+ }
+ }
+ }
+ }
+ if (!bConst && nMarkCount!=0) mpModel->SetChanged();
+}
+
+
+static void ImpGetEscDir(SdrGluePoint & rGP, const SdrObject* /*pObj*/, const void* pbFirst, const void* pnThisEsc, const void* pnRet, const void*)
+{
+ TriState& nRet=*const_cast<TriState *>(static_cast<TriState const *>(pnRet));
+ if (nRet!=TRISTATE_INDET) {
+ SdrEscapeDirection nEsc = rGP.GetEscDir();
+ bool bOn = bool(nEsc & *static_cast<SdrEscapeDirection const *>(pnThisEsc));
+ bool& bFirst=*const_cast<bool *>(static_cast<bool const *>(pbFirst));
+ if (bFirst) {
+ nRet = bOn ? TRISTATE_TRUE : TRISTATE_FALSE;
+ bFirst = false;
+ }
+ else if (nRet != (bOn ? TRISTATE_TRUE : TRISTATE_FALSE)) nRet=TRISTATE_INDET;
+ }
+}
+
+TriState SdrGlueEditView::IsMarkedGluePointsEscDir(SdrEscapeDirection nThisEsc) const
+{
+ ForceUndirtyMrkPnt();
+ bool bFirst=true;
+ TriState nRet=TRISTATE_FALSE;
+ const_cast<SdrGlueEditView*>(this)->ImpDoMarkedGluePoints(ImpGetEscDir,true,&bFirst,&nThisEsc,&nRet);
+ return nRet;
+}
+
+static void ImpSetEscDir(SdrGluePoint& rGP, const SdrObject* /*pObj*/, const void* pnThisEsc, const void* pbOn, const void*, const void*)
+{
+ SdrEscapeDirection nEsc=rGP.GetEscDir();
+ if (*static_cast<bool const *>(pbOn))
+ nEsc |= *static_cast<SdrEscapeDirection const *>(pnThisEsc);
+ else
+ nEsc &= ~*static_cast<SdrEscapeDirection const *>(pnThisEsc);
+ rGP.SetEscDir(nEsc);
+}
+
+void SdrGlueEditView::SetMarkedGluePointsEscDir(SdrEscapeDirection nThisEsc, bool bOn)
+{
+ ForceUndirtyMrkPnt();
+ BegUndo(SvxResId(STR_EditSetGlueEscDir),GetDescriptionOfMarkedGluePoints());
+ ImpDoMarkedGluePoints(ImpSetEscDir,false,&nThisEsc,&bOn);
+ EndUndo();
+}
+
+
+static void ImpGetPercent(SdrGluePoint & rGP, const SdrObject* /*pObj*/, const void* pbFirst, const void* pnRet, const void*, const void*)
+{
+ TriState& nRet=*const_cast<TriState *>(static_cast<TriState const *>(pnRet));
+ if (nRet!=TRISTATE_INDET) {
+ bool bOn=rGP.IsPercent();
+ bool& bFirst=*const_cast<bool *>(static_cast<bool const *>(pbFirst));
+ if (bFirst) {
+ nRet = bOn ? TRISTATE_TRUE : TRISTATE_FALSE;
+ bFirst = false;
+ }
+ else if ((nRet!=TRISTATE_FALSE)!=bOn)
+ nRet=TRISTATE_INDET;
+ }
+}
+
+TriState SdrGlueEditView::IsMarkedGluePointsPercent() const
+{
+ ForceUndirtyMrkPnt();
+ bool bFirst=true;
+ TriState nRet = TRISTATE_TRUE;
+ const_cast<SdrGlueEditView*>(this)->ImpDoMarkedGluePoints(ImpGetPercent,true,&bFirst,&nRet);
+ return nRet;
+}
+
+static void ImpSetPercent(SdrGluePoint& rGP, const SdrObject* pObj, const void* pbOn, const void*, const void*, const void*)
+{
+ Point aPos(rGP.GetAbsolutePos(*pObj));
+ rGP.SetPercent(*static_cast<bool const *>(pbOn));
+ rGP.SetAbsolutePos(aPos,*pObj);
+}
+
+void SdrGlueEditView::SetMarkedGluePointsPercent(bool bOn)
+{
+ ForceUndirtyMrkPnt();
+ BegUndo(SvxResId(STR_EditSetGluePercent),GetDescriptionOfMarkedGluePoints());
+ ImpDoMarkedGluePoints(ImpSetPercent,false,&bOn);
+ EndUndo();
+}
+
+
+static void ImpGetAlign(SdrGluePoint & rGP, const SdrObject* /*pObj*/, const void* pbFirst, const void* pbDontCare, const void* pbVert, const void* pnRet)
+{
+ SdrAlign& nRet=*const_cast<SdrAlign *>(static_cast<SdrAlign const *>(pnRet));
+ bool& bDontCare=*const_cast<bool *>(static_cast<bool const *>(pbDontCare));
+ bool bVert=*static_cast<bool const *>(pbVert);
+ if (bDontCare)
+ return;
+
+ SdrAlign nAlg=SdrAlign::NONE;
+ if (bVert) {
+ nAlg=rGP.GetVertAlign();
+ } else {
+ nAlg=rGP.GetHorzAlign();
+ }
+ bool& bFirst=*const_cast<bool *>(static_cast<bool const *>(pbFirst));
+ if (bFirst) { nRet=nAlg; bFirst=false; }
+ else if (nRet!=nAlg) {
+ if (bVert) {
+ nRet=SdrAlign::VERT_DONTCARE;
+ } else {
+ nRet=SdrAlign::HORZ_DONTCARE;
+ }
+ bDontCare=true;
+ }
+}
+
+SdrAlign SdrGlueEditView::GetMarkedGluePointsAlign(bool bVert) const
+{
+ ForceUndirtyMrkPnt();
+ bool bFirst=true;
+ bool bDontCare=false;
+ SdrAlign nRet=SdrAlign::NONE;
+ const_cast<SdrGlueEditView*>(this)->ImpDoMarkedGluePoints(ImpGetAlign,true,&bFirst,&bDontCare,&bVert,&nRet);
+ return nRet;
+}
+
+static void ImpSetAlign(SdrGluePoint& rGP, const SdrObject* pObj, const void* pbVert, const void* pnAlign, const void*, const void*)
+{
+ Point aPos(rGP.GetAbsolutePos(*pObj));
+ if (*static_cast<bool const *>(pbVert)) { // bVert?
+ rGP.SetVertAlign(*static_cast<SdrAlign const *>(pnAlign));
+ } else {
+ rGP.SetHorzAlign(*static_cast<SdrAlign const *>(pnAlign));
+ }
+ rGP.SetAbsolutePos(aPos,*pObj);
+}
+
+void SdrGlueEditView::SetMarkedGluePointsAlign(bool bVert, SdrAlign nAlign)
+{
+ ForceUndirtyMrkPnt();
+ BegUndo(SvxResId(STR_EditSetGlueAlign),GetDescriptionOfMarkedGluePoints());
+ ImpDoMarkedGluePoints(ImpSetAlign,false,&bVert,&nAlign);
+ EndUndo();
+}
+
+void SdrGlueEditView::DeleteMarkedGluePoints()
+{
+ BrkAction();
+ ForceUndirtyMrkPnt();
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditDelete),GetDescriptionOfMarkedGluePoints(),SdrRepeatFunc::Delete);
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+ if (!rPts.empty())
+ {
+ SdrGluePointList* pGPL=pObj->ForceGluePointList();
+ if (pGPL!=nullptr)
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+
+ for(sal_uInt16 nPtId : rPts)
+ {
+ sal_uInt16 nGlueIdx=pGPL->FindGluePoint(nPtId);
+ if (nGlueIdx!=SDRGLUEPOINT_NOTFOUND)
+ {
+ pGPL->Delete(nGlueIdx);
+ }
+ }
+ pObj->SetChanged();
+ pObj->BroadcastObjectChange();
+ }
+ }
+ }
+ if( bUndo )
+ EndUndo();
+ UnmarkAllGluePoints();
+ if (nMarkCount!=0)
+ mpModel->SetChanged();
+}
+
+
+void SdrGlueEditView::ImpCopyMarkedGluePoints()
+{
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo();
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+ SdrGluePointList* pGPL=pObj->ForceGluePointList();
+ if (!rPts.empty() && pGPL!=nullptr)
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+
+ SdrUShortCont aIdsToErase;
+ SdrUShortCont aIdsToInsert;
+ for(sal_uInt16 nPtId : rPts)
+ {
+ sal_uInt16 nGlueIdx=pGPL->FindGluePoint(nPtId);
+ if (nGlueIdx!=SDRGLUEPOINT_NOTFOUND)
+ {
+ SdrGluePoint aNewGP((*pGPL)[nGlueIdx]); // clone GluePoint
+ sal_uInt16 nNewIdx=pGPL->Insert(aNewGP); // and insert it
+ sal_uInt16 nNewId=(*pGPL)[nNewIdx].GetId(); // retrieve ID of new GluePoints
+ aIdsToErase.insert(nPtId); // select it (instead of the old one)
+ aIdsToInsert.insert(nNewId);
+ }
+ }
+ for(const auto& rId : aIdsToErase)
+ rPts.erase(rId);
+ rPts.insert(aIdsToInsert);
+ }
+ }
+ if( bUndo )
+ EndUndo();
+
+ if (nMarkCount!=0)
+ mpModel->SetChanged();
+}
+
+
+void SdrGlueEditView::ImpTransformMarkedGluePoints(PGlueTrFunc pTrFunc, const void* p1, const void* p2, const void* p3, const void* p4)
+{
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm) {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+ if (!rPts.empty()) {
+ SdrGluePointList* pGPL=pObj->ForceGluePointList();
+ if (pGPL!=nullptr)
+ {
+ if( IsUndoEnabled() )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+
+ for(sal_uInt16 nPtId : rPts)
+ {
+ sal_uInt16 nGlueIdx=pGPL->FindGluePoint(nPtId);
+ if (nGlueIdx!=SDRGLUEPOINT_NOTFOUND) {
+ SdrGluePoint& rGP=(*pGPL)[nGlueIdx];
+ Point aPos(rGP.GetAbsolutePos(*pObj));
+ (*pTrFunc)(aPos,p1,p2,p3,p4);
+ rGP.SetAbsolutePos(aPos,*pObj);
+ }
+ }
+ pObj->SetChanged();
+ pObj->BroadcastObjectChange();
+ }
+ }
+ }
+ if (nMarkCount!=0) mpModel->SetChanged();
+}
+
+
+static void ImpMove(Point& rPt, const void* p1, const void* /*p2*/, const void* /*p3*/, const void* /*p4*/)
+{
+ rPt.AdjustX(static_cast<const Size*>(p1)->Width() );
+ rPt.AdjustY(static_cast<const Size*>(p1)->Height() );
+}
+
+void SdrGlueEditView::MoveMarkedGluePoints(const Size& rSiz, bool bCopy)
+{
+ ForceUndirtyMrkPnt();
+ OUString aStr(SvxResId(STR_EditMove));
+ if (bCopy) aStr += SvxResId(STR_EditWithCopy);
+ BegUndo(aStr,GetDescriptionOfMarkedGluePoints(),SdrRepeatFunc::Move);
+ if (bCopy) ImpCopyMarkedGluePoints();
+ ImpTransformMarkedGluePoints(ImpMove,&rSiz);
+ EndUndo();
+ AdjustMarkHdl();
+}
+
+
+static void ImpResize(Point& rPt, const void* p1, const void* p2, const void* p3, const void* /*p4*/)
+{
+ ResizePoint(rPt,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
+}
+
+void SdrGlueEditView::ResizeMarkedGluePoints(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bCopy)
+{
+ ForceUndirtyMrkPnt();
+ OUString aStr(SvxResId(STR_EditResize));
+ if (bCopy) aStr+=SvxResId(STR_EditWithCopy);
+ BegUndo(aStr,GetDescriptionOfMarkedGluePoints(),SdrRepeatFunc::Resize);
+ if (bCopy) ImpCopyMarkedGluePoints();
+ ImpTransformMarkedGluePoints(ImpResize,&rRef,&xFact,&yFact);
+ EndUndo();
+ AdjustMarkHdl();
+}
+
+
+static void ImpRotate(Point& rPt, const void* p1, const void* /*p2*/, const void* p3, const void* p4)
+{
+ RotatePoint(rPt,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
+}
+
+void SdrGlueEditView::RotateMarkedGluePoints(const Point& rRef, Degree100 nAngle, bool bCopy)
+{
+ ForceUndirtyMrkPnt();
+ OUString aStr(SvxResId(STR_EditRotate));
+ if (bCopy) aStr+=SvxResId(STR_EditWithCopy);
+ BegUndo(aStr,GetDescriptionOfMarkedGluePoints(),SdrRepeatFunc::Rotate);
+ if (bCopy) ImpCopyMarkedGluePoints();
+ double nSin = sin(toRadians(nAngle));
+ double nCos = cos(toRadians(nAngle));
+ ImpTransformMarkedGluePoints(ImpRotate,&rRef,&nAngle,&nSin,&nCos);
+ EndUndo();
+ AdjustMarkHdl();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdglue.cxx b/svx/source/svdraw/svdglue.cxx
new file mode 100644
index 000000000..9808372f8
--- /dev/null
+++ b/svx/source/svdraw/svdglue.cxx
@@ -0,0 +1,394 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/debug.hxx>
+#include <vcl/window.hxx>
+
+#include <svx/svdglue.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdtrans.hxx>
+#include <comphelper/lok.hxx>
+
+const Size aGlueHalfSize(4,4);
+
+void SdrGluePoint::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
+{
+ if ( bReallyAbsolute == bOn )
+ return;
+
+ if ( bOn )
+ {
+ aPos=GetAbsolutePos(rObj);
+ bReallyAbsolute=bOn;
+ }
+ else
+ {
+ bReallyAbsolute=bOn;
+ Point aPt(aPos);
+ SetAbsolutePos(aPt,rObj);
+ }
+}
+
+Point SdrGluePoint::GetAbsolutePos(const SdrObject& rObj) const
+{
+ if (bReallyAbsolute) return aPos;
+ tools::Rectangle aSnap(rObj.GetSnapRect());
+ tools::Rectangle aBound(rObj.GetSnapRect());
+ Point aPt(aPos);
+
+ Point aOfs(aSnap.Center());
+ switch (GetHorzAlign()) {
+ case SdrAlign::HORZ_LEFT : aOfs.setX(aSnap.Left() ); break;
+ case SdrAlign::HORZ_RIGHT : aOfs.setX(aSnap.Right() ); break;
+ default: break;
+ }
+ switch (GetVertAlign()) {
+ case SdrAlign::VERT_TOP : aOfs.setY(aSnap.Top() ); break;
+ case SdrAlign::VERT_BOTTOM: aOfs.setY(aSnap.Bottom() ); break;
+ default: break;
+ }
+ if (!bNoPercent) {
+ tools::Long nXMul=aSnap.Right()-aSnap.Left();
+ tools::Long nYMul=aSnap.Bottom()-aSnap.Top();
+ tools::Long nXDiv=10000;
+ tools::Long nYDiv=10000;
+ if (nXMul!=nXDiv) {
+ aPt.setX( aPt.X() * nXMul );
+ aPt.setX( aPt.X() / nXDiv );
+ }
+ if (nYMul!=nYDiv) {
+ aPt.setY( aPt.Y() * nYMul );
+ aPt.setY( aPt.Y() / nYDiv );
+ }
+ }
+ aPt+=aOfs;
+ // Now limit to the BoundRect of the object
+ if (aPt.X()<aBound.Left ()) aPt.setX(aBound.Left () );
+ if (aPt.X()>aBound.Right ()) aPt.setX(aBound.Right () );
+ if (aPt.Y()<aBound.Top ()) aPt.setY(aBound.Top () );
+ if (aPt.Y()>aBound.Bottom()) aPt.setY(aBound.Bottom() );
+ return aPt;
+}
+
+void SdrGluePoint::SetAbsolutePos(const Point& rNewPos, const SdrObject& rObj)
+{
+ if (bReallyAbsolute) {
+ aPos=rNewPos;
+ return;
+ }
+ tools::Rectangle aSnap(rObj.GetSnapRect());
+ Point aPt(rNewPos);
+
+ Point aOfs(aSnap.Center());
+ switch (GetHorzAlign()) {
+ case SdrAlign::HORZ_LEFT : aOfs.setX(aSnap.Left() ); break;
+ case SdrAlign::HORZ_RIGHT : aOfs.setX(aSnap.Right() ); break;
+ default: break;
+ }
+ switch (GetVertAlign()) {
+ case SdrAlign::VERT_TOP : aOfs.setY(aSnap.Top() ); break;
+ case SdrAlign::VERT_BOTTOM: aOfs.setY(aSnap.Bottom() ); break;
+ default: break;
+ }
+ aPt-=aOfs;
+ if (!bNoPercent) {
+ tools::Long nXMul=aSnap.Right()-aSnap.Left();
+ tools::Long nYMul=aSnap.Bottom()-aSnap.Top();
+ if (nXMul==0) nXMul=1;
+ if (nYMul==0) nYMul=1;
+ tools::Long nXDiv=10000;
+ tools::Long nYDiv=10000;
+ if (nXMul!=nXDiv) {
+ aPt.setX( aPt.X() * nXDiv );
+ aPt.setX( aPt.X() / nXMul );
+ }
+ if (nYMul!=nYDiv) {
+ aPt.setY( aPt.Y() * nYDiv );
+ aPt.setY( aPt.Y() / nYMul );
+ }
+ }
+ aPos=aPt;
+}
+
+Degree100 SdrGluePoint::GetAlignAngle() const
+{
+ if (nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
+ return 0_deg100; // Invalid!
+ else if (nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_CENTER))
+ return 0_deg100;
+ else if (nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_TOP))
+ return 4500_deg100;
+ else if (nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP))
+ return 9000_deg100;
+ else if (nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_TOP))
+ return 13500_deg100;
+ else if (nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_CENTER))
+ return 18000_deg100;
+ else if (nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_BOTTOM))
+ return 22500_deg100;
+ else if (nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM))
+ return 27000_deg100;
+ else if (nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_BOTTOM))
+ return 31500_deg100;
+ return 0_deg100;
+}
+
+void SdrGluePoint::SetAlignAngle(Degree100 nAngle)
+{
+ nAngle=NormAngle36000(nAngle);
+ if (nAngle>=33750_deg100 || nAngle<2250_deg100) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_CENTER;
+ else if (nAngle< 6750_deg100) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_TOP ;
+ else if (nAngle<11250_deg100) nAlign=SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP ;
+ else if (nAngle<15750_deg100) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_TOP ;
+ else if (nAngle<20250_deg100) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_CENTER;
+ else if (nAngle<24750_deg100) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_BOTTOM;
+ else if (nAngle<29250_deg100) nAlign=SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM;
+ else if (nAngle<33750_deg100) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_BOTTOM;
+}
+
+Degree100 SdrGluePoint::EscDirToAngle(SdrEscapeDirection nEsc)
+{
+ switch (nEsc) {
+ case SdrEscapeDirection::RIGHT : return 0_deg100;
+ case SdrEscapeDirection::TOP : return 9000_deg100;
+ case SdrEscapeDirection::LEFT : return 18000_deg100;
+ case SdrEscapeDirection::BOTTOM: return 27000_deg100;
+ default: break;
+ } // switch
+ return 0_deg100;
+}
+
+SdrEscapeDirection SdrGluePoint::EscAngleToDir(Degree100 nAngle)
+{
+ nAngle=NormAngle36000(nAngle);
+ if (nAngle>=31500_deg100 || nAngle<4500_deg100)
+ return SdrEscapeDirection::RIGHT;
+ if (nAngle<13500_deg100)
+ return SdrEscapeDirection::TOP;
+ if (nAngle<22500_deg100)
+ return SdrEscapeDirection::LEFT;
+ /* (nAngle<31500)*/
+ return SdrEscapeDirection::BOTTOM;
+}
+
+void SdrGluePoint::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs, const SdrObject* pObj)
+{
+ Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
+ RotatePoint(aPt,rRef,sn,cs);
+ // rotate reference edge
+ if(nAlign != (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
+ {
+ SetAlignAngle(GetAlignAngle()+nAngle);
+ }
+ // rotate exit directions
+ SdrEscapeDirection nEscDir0=nEscDir;
+ SdrEscapeDirection nEscDir1=SdrEscapeDirection::SMART;
+ if (nEscDir0&SdrEscapeDirection::LEFT ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::LEFT )+nAngle);
+ if (nEscDir0&SdrEscapeDirection::TOP ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::TOP )+nAngle);
+ if (nEscDir0&SdrEscapeDirection::RIGHT ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::RIGHT )+nAngle);
+ if (nEscDir0&SdrEscapeDirection::BOTTOM) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::BOTTOM)+nAngle);
+ nEscDir=nEscDir1;
+ if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
+}
+
+void SdrGluePoint::Mirror(const Point& rRef1, const Point& rRef2, Degree100 nAngle, const SdrObject* pObj)
+{
+ Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
+ MirrorPoint(aPt,rRef1,rRef2);
+ // mirror reference edge
+ if(nAlign != (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
+ {
+ Degree100 nAW=GetAlignAngle();
+ nAW+=2_deg100*(nAngle-nAW);
+ SetAlignAngle(nAW);
+ }
+ // mirror exit directions
+ SdrEscapeDirection nEscDir0=nEscDir;
+ SdrEscapeDirection nEscDir1=SdrEscapeDirection::SMART;
+ if (nEscDir0&SdrEscapeDirection::LEFT) {
+ Degree100 nEW=EscDirToAngle(SdrEscapeDirection::LEFT);
+ nEW+=2_deg100*(nAngle-nEW);
+ nEscDir1|=EscAngleToDir(nEW);
+ }
+ if (nEscDir0&SdrEscapeDirection::TOP) {
+ Degree100 nEW=EscDirToAngle(SdrEscapeDirection::TOP);
+ nEW+=2_deg100*(nAngle-nEW);
+ nEscDir1|=EscAngleToDir(nEW);
+ }
+ if (nEscDir0&SdrEscapeDirection::RIGHT) {
+ Degree100 nEW=EscDirToAngle(SdrEscapeDirection::RIGHT);
+ nEW+=2_deg100*(nAngle-nEW);
+ nEscDir1|=EscAngleToDir(nEW);
+ }
+ if (nEscDir0&SdrEscapeDirection::BOTTOM) {
+ Degree100 nEW=EscDirToAngle(SdrEscapeDirection::BOTTOM);
+ nEW+=2_deg100*(nAngle-nEW);
+ nEscDir1|=EscAngleToDir(nEW);
+ }
+ nEscDir=nEscDir1;
+ if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
+}
+
+void SdrGluePoint::Shear(const Point& rRef, double tn, bool bVShear, const SdrObject* pObj)
+{
+ Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
+ ShearPoint(aPt,rRef,tn,bVShear);
+ if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
+}
+
+void SdrGluePoint::Invalidate(vcl::Window& rWin, const SdrObject* pObj) const
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+ bool bMapMode=rWin.IsMapModeEnabled();
+ Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
+ aPt=rWin.LogicToPixel(aPt);
+ rWin.EnableMapMode(false);
+
+ Size aSiz( aGlueHalfSize );
+ tools::Rectangle aRect(aPt.X()-aSiz.Width(),aPt.Y()-aSiz.Height(),
+ aPt.X()+aSiz.Width(),aPt.Y()+aSiz.Height());
+
+ // do not erase background, that causes flicker (!)
+ rWin.Invalidate(aRect, InvalidateFlags::NoErase);
+
+ rWin.EnableMapMode(bMapMode);
+}
+
+bool SdrGluePoint::IsHit(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
+{
+ Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
+ Size aSiz=rOut.PixelToLogic(aGlueHalfSize);
+ tools::Rectangle aRect(aPt.X()-aSiz.Width(),aPt.Y()-aSiz.Height(),aPt.X()+aSiz.Width(),aPt.Y()+aSiz.Height());
+ return aRect.Contains(rPnt);
+}
+
+
+SdrGluePointList& SdrGluePointList::operator=(const SdrGluePointList& rSrcList)
+{
+ if (GetCount()!=0) aList.clear();
+ sal_uInt16 nCount=rSrcList.GetCount();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ Insert(rSrcList[i]);
+ }
+ return *this;
+}
+
+// The ID's of the gluepoints always increase monotonously!
+// If an ID is taken already, the new gluepoint gets a new ID. ID 0 is reserved.
+sal_uInt16 SdrGluePointList::Insert(const SdrGluePoint& rGP)
+{
+ SdrGluePoint aGP(rGP);
+ sal_uInt16 nId=aGP.GetId();
+ sal_uInt16 nCount=GetCount();
+ sal_uInt16 nInsPos=nCount;
+ sal_uInt16 nLastId=nCount!=0 ? aList[nCount-1].GetId() : 0;
+ DBG_ASSERT(nLastId>=nCount,"SdrGluePointList::Insert(): nLastId<nCount");
+ bool bHole = nLastId>nCount;
+ if (nId<=nLastId) {
+ if (!bHole || nId==0) {
+ nId=nLastId+1;
+ } else {
+ bool bBrk = false;
+ for (sal_uInt16 nNum=0; nNum<nCount && !bBrk; nNum++) {
+ const auto& pGP2=aList[nNum];
+ sal_uInt16 nTmpId=pGP2.GetId();
+ if (nTmpId==nId) {
+ nId=nLastId+1; // already in use
+ bBrk = true;
+ }
+ if (nTmpId>nId) {
+ nInsPos=nNum; // insert here (sort)
+ bBrk = true;
+ }
+ }
+ }
+ aGP.SetId(nId);
+ }
+ aList.emplace(aList.begin()+nInsPos, aGP);
+ return nInsPos;
+}
+
+void SdrGluePointList::Invalidate(vcl::Window& rWin, const SdrObject* pObj) const
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+ for (auto& xGP : aList)
+ xGP.Invalidate(rWin,pObj);
+}
+
+sal_uInt16 SdrGluePointList::FindGluePoint(sal_uInt16 nId) const
+{
+ // TODO: Implement a better search algorithm
+ // List should be sorted at all times!
+ sal_uInt16 nCount=GetCount();
+ sal_uInt16 nRet=SDRGLUEPOINT_NOTFOUND;
+ for (sal_uInt16 nNum=0; nNum<nCount && nRet==SDRGLUEPOINT_NOTFOUND; nNum++) {
+ const auto& pGP=aList[nNum];
+ if (pGP.GetId()==nId) nRet=nNum;
+ }
+ return nRet;
+}
+
+sal_uInt16 SdrGluePointList::HitTest(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
+{
+ sal_uInt16 nCount = GetCount();
+ sal_uInt16 nRet = SDRGLUEPOINT_NOTFOUND;
+ sal_uInt16 nNum = nCount;
+ while ((nNum>0) && nRet==SDRGLUEPOINT_NOTFOUND) {
+ nNum--;
+ const auto& pGP = aList[nNum];
+ if (pGP.IsHit(rPnt,rOut,pObj))
+ nRet = nNum;
+ }
+ return nRet;
+}
+
+void SdrGluePointList::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
+{
+ for (auto& xGP : aList)
+ xGP.SetReallyAbsolute(bOn,rObj);
+}
+
+void SdrGluePointList::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs, const SdrObject* pObj)
+{
+ for (auto& xGP : aList)
+ xGP.Rotate(rRef,nAngle,sn,cs,pObj);
+}
+
+void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, const SdrObject* pObj)
+{
+ Point aPt(rRef2); aPt-=rRef1;
+ Degree100 nAngle=GetAngle(aPt);
+ Mirror(rRef1,rRef2,nAngle,pObj);
+}
+
+void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, Degree100 nAngle, const SdrObject* pObj)
+{
+ for (auto& xGP : aList)
+ xGP.Mirror(rRef1,rRef2,nAngle,pObj);
+}
+
+void SdrGluePointList::Shear(const Point& rRef, double tn, bool bVShear, const SdrObject* pObj)
+{
+ for (auto& xGP : aList)
+ xGP.Shear(rRef,tn,bVShear,pObj);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdhdl.cxx b/svx/source/svdraw/svdhdl.cxx
new file mode 100644
index 000000000..31aa07578
--- /dev/null
+++ b/svx/source/svdraw/svdhdl.cxx
@@ -0,0 +1,2675 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <algorithm>
+#include <cassert>
+
+#include <svx/svdhdl.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdmrkv.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/ptrstyle.hxx>
+
+#include <svx/sxekitm.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdmodel.hxx>
+#include "gradtrns.hxx"
+#include <svx/xflgrit.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/xflftrit.hxx>
+
+#include <svx/svdopath.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
+#include <svx/sdr/overlay/overlaybitmapex.hxx>
+#include <sdr/overlay/overlayline.hxx>
+#include <sdr/overlay/overlaytriangle.hxx>
+#include <sdr/overlay/overlayhandle.hxx>
+#include <sdr/overlay/overlayrectangle.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+#include <vcl/lazydelete.hxx>
+#include <vcl/BitmapTools.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <osl/diagnose.h>
+
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <memory>
+#include <bitmaps.hlst>
+
+namespace {
+
+// #i15222#
+// Due to the resource problems in Win95/98 with bitmap resources I
+// will change this handle bitmap providing class. Old version was splitting
+// and preparing all small handle bitmaps in device bitmap format, now this will
+// be done on the fly. Thus, there is only one big bitmap in memory. With
+// three source bitmaps, this will be 3 system bitmap resources instead of hundreds.
+// The price for that needs to be evaluated. Maybe we will need another change here
+// if this is too expensive.
+class SdrHdlBitmapSet
+{
+ // the bitmap holding all information
+ BitmapEx maMarkersBitmap;
+
+ // the cropped Bitmaps for reusage
+ ::std::vector< BitmapEx > maRealMarkers;
+
+ // helpers
+ BitmapEx& impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const tools::Rectangle& rRectangle);
+
+public:
+ explicit SdrHdlBitmapSet();
+
+ const BitmapEx& GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd);
+};
+
+}
+
+#define KIND_COUNT (14)
+#define INDEX_COUNT (6)
+#define INDIVIDUAL_COUNT (5)
+
+SdrHdlBitmapSet::SdrHdlBitmapSet()
+ : maMarkersBitmap(SIP_SA_MARKERS),
+ // 15 kinds (BitmapMarkerKind) use index [0..5] + 5 extra
+ maRealMarkers((KIND_COUNT * INDEX_COUNT) + INDIVIDUAL_COUNT)
+{
+}
+
+BitmapEx& SdrHdlBitmapSet::impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const tools::Rectangle& rRectangle)
+{
+ BitmapEx& rTargetBitmap = maRealMarkers[nIndex];
+
+ if(rTargetBitmap.IsEmpty())
+ {
+ rTargetBitmap = maMarkersBitmap;
+ rTargetBitmap.Crop(rRectangle);
+ }
+
+ return rTargetBitmap;
+}
+
+// change getting of bitmap to use the big resource bitmap
+const BitmapEx& SdrHdlBitmapSet::GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd)
+{
+ // fill in size and source position in maMarkersBitmap
+ const sal_uInt16 nYPos(nInd * 11);
+
+ switch(eKindOfMarker)
+ {
+ default:
+ {
+ OSL_FAIL( "Unknown kind of marker." );
+ [[fallthrough]]; // return Rect_9x9 as default
+ }
+ case BitmapMarkerKind::Rect_9x9:
+ {
+ return impGetOrCreateTargetBitmap((1 * INDEX_COUNT) + nInd, tools::Rectangle(Point(7, nYPos), Size(9, 9)));
+ }
+
+ case BitmapMarkerKind::Rect_7x7:
+ {
+ return impGetOrCreateTargetBitmap((0 * INDEX_COUNT) + nInd, tools::Rectangle(Point(0, nYPos), Size(7, 7)));
+ }
+
+ case BitmapMarkerKind::Rect_11x11:
+ {
+ return impGetOrCreateTargetBitmap((2 * INDEX_COUNT) + nInd, tools::Rectangle(Point(16, nYPos), Size(11, 11)));
+ }
+
+ case BitmapMarkerKind::Rect_13x13:
+ {
+ const sal_uInt16 nIndex((3 * INDEX_COUNT) + nInd);
+
+ switch(nInd)
+ {
+ case 0:
+ {
+ return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(72, 66), Size(13, 13)));
+ }
+ case 1:
+ {
+ return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(85, 66), Size(13, 13)));
+ }
+ case 2:
+ {
+ return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(72, 79), Size(13, 13)));
+ }
+ case 3:
+ {
+ return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(85, 79), Size(13, 13)));
+ }
+ case 4:
+ {
+ return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(98, 79), Size(13, 13)));
+ }
+ default: // case 5:
+ {
+ return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(98, 66), Size(13, 13)));
+ }
+ }
+ }
+
+ case BitmapMarkerKind::Circ_7x7:
+ case BitmapMarkerKind::Customshape_7x7:
+ {
+ return impGetOrCreateTargetBitmap((4 * INDEX_COUNT) + nInd, tools::Rectangle(Point(27, nYPos), Size(7, 7)));
+ }
+
+ case BitmapMarkerKind::Circ_9x9:
+ case BitmapMarkerKind::Customshape_9x9:
+ {
+ return impGetOrCreateTargetBitmap((5 * INDEX_COUNT) + nInd, tools::Rectangle(Point(34, nYPos), Size(9, 9)));
+ }
+
+ case BitmapMarkerKind::Circ_11x11:
+ case BitmapMarkerKind::Customshape_11x11:
+ {
+ return impGetOrCreateTargetBitmap((6 * INDEX_COUNT) + nInd, tools::Rectangle(Point(43, nYPos), Size(11, 11)));
+ }
+
+ case BitmapMarkerKind::Elli_7x9:
+ {
+ return impGetOrCreateTargetBitmap((7 * INDEX_COUNT) + nInd, tools::Rectangle(Point(54, nYPos), Size(7, 9)));
+ }
+
+ case BitmapMarkerKind::Elli_9x11:
+ {
+ return impGetOrCreateTargetBitmap((8 * INDEX_COUNT) + nInd, tools::Rectangle(Point(61, nYPos), Size(9, 11)));
+ }
+
+ case BitmapMarkerKind::Elli_9x7:
+ {
+ return impGetOrCreateTargetBitmap((9 * INDEX_COUNT) + nInd, tools::Rectangle(Point(70, nYPos), Size(9, 7)));
+ }
+
+ case BitmapMarkerKind::Elli_11x9:
+ {
+ return impGetOrCreateTargetBitmap((10 * INDEX_COUNT) + nInd, tools::Rectangle(Point(79, nYPos), Size(11, 9)));
+ }
+
+ case BitmapMarkerKind::RectPlus_7x7:
+ {
+ return impGetOrCreateTargetBitmap((11 * INDEX_COUNT) + nInd, tools::Rectangle(Point(90, nYPos), Size(7, 7)));
+ }
+
+ case BitmapMarkerKind::RectPlus_9x9:
+ {
+ return impGetOrCreateTargetBitmap((12 * INDEX_COUNT) + nInd, tools::Rectangle(Point(97, nYPos), Size(9, 9)));
+ }
+
+ case BitmapMarkerKind::RectPlus_11x11:
+ {
+ return impGetOrCreateTargetBitmap((13 * INDEX_COUNT) + nInd, tools::Rectangle(Point(106, nYPos), Size(11, 11)));
+ }
+
+ case BitmapMarkerKind::Crosshair:
+ {
+ return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 0, tools::Rectangle(Point(0, 68), Size(15, 15)));
+ }
+
+ case BitmapMarkerKind::Glue:
+ {
+ return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 1, tools::Rectangle(Point(15, 76), Size(9, 9)));
+ }
+
+ case BitmapMarkerKind::Glue_Deselected:
+ {
+ return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 2, tools::Rectangle(Point(15, 67), Size(9, 9)));
+ }
+
+ case BitmapMarkerKind::Anchor: // AnchorTR for SW
+ case BitmapMarkerKind::AnchorTR:
+ {
+ return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 3, tools::Rectangle(Point(24, 67), Size(24, 24)));
+ }
+
+ // add AnchorPressed to be able to animate anchor control
+ case BitmapMarkerKind::AnchorPressed:
+ case BitmapMarkerKind::AnchorPressedTR:
+ {
+ return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 4, tools::Rectangle(Point(48, 67), Size(24, 24)));
+ }
+ }
+}
+
+
+SdrHdl::SdrHdl():
+ pObj(nullptr),
+ pPV(nullptr),
+ pHdlList(nullptr),
+ eKind(SdrHdlKind::Move),
+ nRotationAngle(0),
+ nObjHdlNum(0),
+ nPolyNum(0),
+ nPPntNum(0),
+ nSourceHdlNum(0),
+ bSelect(false),
+ b1PixMore(false),
+ bPlusHdl(false),
+ mbMoveOutside(false),
+ mbMouseOver(false)
+{
+}
+
+SdrHdl::SdrHdl(const Point& rPnt, SdrHdlKind eNewKind):
+ pObj(nullptr),
+ pPV(nullptr),
+ pHdlList(nullptr),
+ aPos(rPnt),
+ eKind(eNewKind),
+ nRotationAngle(0),
+ nObjHdlNum(0),
+ nPolyNum(0),
+ nPPntNum(0),
+ nSourceHdlNum(0),
+ bSelect(false),
+ b1PixMore(false),
+ bPlusHdl(false),
+ mbMoveOutside(false),
+ mbMouseOver(false)
+{
+}
+
+SdrHdl::~SdrHdl()
+{
+ GetRidOfIAObject();
+}
+
+void SdrHdl::Set1PixMore(bool bJa)
+{
+ if(b1PixMore != bJa)
+ {
+ b1PixMore = bJa;
+
+ // create new display
+ Touch();
+ }
+}
+
+void SdrHdl::SetMoveOutside( bool bMoveOutside )
+{
+ if(mbMoveOutside != bMoveOutside)
+ {
+ mbMoveOutside = bMoveOutside;
+
+ // create new display
+ Touch();
+ }
+}
+
+void SdrHdl::SetRotationAngle(Degree100 n)
+{
+ if(nRotationAngle != n)
+ {
+ nRotationAngle = n;
+
+ // create new display
+ Touch();
+ }
+}
+
+void SdrHdl::SetPos(const Point& rPnt)
+{
+ if(aPos != rPnt)
+ {
+ // remember new position
+ aPos = rPnt;
+
+ // create new display
+ Touch();
+ }
+}
+
+void SdrHdl::SetSelected(bool bJa)
+{
+ if(bSelect != bJa)
+ {
+ // remember new value
+ bSelect = bJa;
+
+ // create new display
+ Touch();
+ }
+}
+
+void SdrHdl::SetHdlList(SdrHdlList* pList)
+{
+ if(pHdlList != pList)
+ {
+ // remember list
+ pHdlList = pList;
+
+ // now it's possible to create graphic representation
+ Touch();
+ }
+}
+
+void SdrHdl::SetObj(SdrObject* pNewObj)
+{
+ if(pObj != pNewObj)
+ {
+ // remember new object
+ pObj = pNewObj;
+
+ // graphic representation may have changed
+ Touch();
+ }
+}
+
+void SdrHdl::Touch()
+{
+ // force update of graphic representation
+ CreateB2dIAObject();
+}
+
+void SdrHdl::GetRidOfIAObject()
+{
+
+ // OVERLAYMANAGER
+ maOverlayGroup.clear();
+}
+
+void SdrHdl::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ if(!pHdlList || !pHdlList->GetView() || pHdlList->GetView()->areMarkHandlesHidden())
+ return;
+
+ BitmapColorIndex eColIndex = BitmapColorIndex::LightGreen;
+ BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
+
+ bool bRot = pHdlList->IsRotateShear();
+ if(pObj)
+ eColIndex = bSelect ? BitmapColorIndex::Cyan : BitmapColorIndex::LightCyan;
+ if(bRot)
+ {
+ // red rotation handles
+ if(pObj && bSelect)
+ eColIndex = BitmapColorIndex::Red;
+ else
+ eColIndex = BitmapColorIndex::LightRed;
+ }
+
+ switch(eKind)
+ {
+ case SdrHdlKind::Move:
+ {
+ eKindOfMarker = b1PixMore ? BitmapMarkerKind::Rect_9x9 : BitmapMarkerKind::Rect_7x7;
+ break;
+ }
+ case SdrHdlKind::UpperLeft:
+ case SdrHdlKind::UpperRight:
+ case SdrHdlKind::LowerLeft:
+ case SdrHdlKind::LowerRight:
+ {
+ // corner handles
+ if(bRot)
+ {
+ eKindOfMarker = BitmapMarkerKind::Circ_7x7;
+ }
+ else
+ {
+ eKindOfMarker = BitmapMarkerKind::Rect_7x7;
+ }
+ break;
+ }
+ case SdrHdlKind::Upper:
+ case SdrHdlKind::Lower:
+ {
+ // Upper/Lower handles
+ if(bRot)
+ {
+ eKindOfMarker = BitmapMarkerKind::Elli_9x7;
+ }
+ else
+ {
+ eKindOfMarker = BitmapMarkerKind::Rect_7x7;
+ }
+ break;
+ }
+ case SdrHdlKind::Left:
+ case SdrHdlKind::Right:
+ {
+ // Left/Right handles
+ if(bRot)
+ {
+ eKindOfMarker = BitmapMarkerKind::Elli_7x9;
+ }
+ else
+ {
+ eKindOfMarker = BitmapMarkerKind::Rect_7x7;
+ }
+ break;
+ }
+ case SdrHdlKind::Poly:
+ {
+ if(bRot)
+ {
+ eKindOfMarker = b1PixMore ? BitmapMarkerKind::Circ_9x9 : BitmapMarkerKind::Circ_7x7;
+ }
+ else
+ {
+ eKindOfMarker = b1PixMore ? BitmapMarkerKind::Rect_9x9 : BitmapMarkerKind::Rect_7x7;
+ }
+ break;
+ }
+ case SdrHdlKind::BezierWeight: // weight at poly
+ {
+ eKindOfMarker = BitmapMarkerKind::Circ_7x7;
+ break;
+ }
+ case SdrHdlKind::Circle:
+ {
+ eKindOfMarker = BitmapMarkerKind::Rect_11x11;
+ break;
+ }
+ case SdrHdlKind::Ref1:
+ case SdrHdlKind::Ref2:
+ {
+ eKindOfMarker = BitmapMarkerKind::Crosshair;
+ break;
+ }
+ case SdrHdlKind::Glue:
+ {
+ eKindOfMarker = BitmapMarkerKind::Glue;
+ break;
+ }
+ case SdrHdlKind::Anchor:
+ {
+ eKindOfMarker = BitmapMarkerKind::Anchor;
+ break;
+ }
+ case SdrHdlKind::User:
+ {
+ break;
+ }
+ // top right anchor for SW
+ case SdrHdlKind::Anchor_TR:
+ {
+ eKindOfMarker = BitmapMarkerKind::AnchorTR;
+ break;
+ }
+
+ // for SJ and the CustomShapeHandles:
+ case SdrHdlKind::CustomShape1:
+ {
+ eKindOfMarker = b1PixMore ? BitmapMarkerKind::Customshape_9x9 : BitmapMarkerKind::Customshape_7x7;
+ eColIndex = BitmapColorIndex::Yellow;
+ break;
+ }
+ default:
+ break;
+ }
+
+ SdrMarkView* pView = pHdlList->GetView();
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ Point aMoveOutsideOffset(0, 0);
+ OutputDevice& rOutDev = rPageWindow.GetPaintWindow().GetOutputDevice();
+
+ // add offset if necessary
+ if(pHdlList->IsMoveOutside() || mbMoveOutside)
+ {
+ Size aOffset = rOutDev.PixelToLogic(Size(4, 4));
+
+ if(eKind == SdrHdlKind::UpperLeft || eKind == SdrHdlKind::Upper || eKind == SdrHdlKind::UpperRight)
+ aMoveOutsideOffset.AdjustY( -(aOffset.Width()) );
+ if(eKind == SdrHdlKind::LowerLeft || eKind == SdrHdlKind::Lower || eKind == SdrHdlKind::LowerRight)
+ aMoveOutsideOffset.AdjustY(aOffset.Height() );
+ if(eKind == SdrHdlKind::UpperLeft || eKind == SdrHdlKind::Left || eKind == SdrHdlKind::LowerLeft)
+ aMoveOutsideOffset.AdjustX( -(aOffset.Width()) );
+ if(eKind == SdrHdlKind::UpperRight || eKind == SdrHdlKind::Right || eKind == SdrHdlKind::LowerRight)
+ aMoveOutsideOffset.AdjustX(aOffset.Height() );
+ }
+
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject;
+ if (getenv ("SVX_DRAW_HANDLES") && (eKindOfMarker == BitmapMarkerKind::Rect_7x7 || eKindOfMarker == BitmapMarkerKind::Rect_9x9 || eKindOfMarker == BitmapMarkerKind::Rect_11x11))
+ {
+ double fSize = 7.0;
+ switch (eKindOfMarker)
+ {
+ case BitmapMarkerKind::Rect_9x9:
+ fSize = 9.0;
+ break;
+ case BitmapMarkerKind::Rect_11x11:
+ fSize = 11.0;
+ break;
+ default:
+ break;
+ }
+ float fScalingFactor = rOutDev.GetDPIScaleFactor();
+ basegfx::B2DSize aB2DSize(fSize * fScalingFactor, fSize * fScalingFactor);
+
+ Color aHandleFillColor(COL_LIGHTGREEN);
+ switch (eColIndex)
+ {
+ case BitmapColorIndex::Cyan:
+ aHandleFillColor = COL_CYAN;
+ break;
+ case BitmapColorIndex::LightCyan:
+ aHandleFillColor = COL_LIGHTCYAN;
+ break;
+ case BitmapColorIndex::Red:
+ aHandleFillColor = COL_RED;
+ break;
+ case BitmapColorIndex::LightRed:
+ aHandleFillColor = COL_LIGHTRED;
+ break;
+ case BitmapColorIndex::Yellow:
+ aHandleFillColor = COL_YELLOW;
+ break;
+ default:
+ break;
+ }
+ pNewOverlayObject.reset(new sdr::overlay::OverlayHandle(aPosition, aB2DSize, /*HandleStrokeColor*/COL_BLACK, aHandleFillColor));
+ }
+ else
+ {
+ pNewOverlayObject = CreateOverlayObject(
+ aPosition, eColIndex, eKindOfMarker,
+ aMoveOutsideOffset);
+ }
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+BitmapMarkerKind SdrHdl::GetNextBigger(BitmapMarkerKind eKnd)
+{
+ BitmapMarkerKind eRetval(eKnd);
+
+ switch(eKnd)
+ {
+ case BitmapMarkerKind::Rect_7x7: eRetval = BitmapMarkerKind::Rect_9x9; break;
+ case BitmapMarkerKind::Rect_9x9: eRetval = BitmapMarkerKind::Rect_11x11; break;
+ case BitmapMarkerKind::Rect_11x11: eRetval = BitmapMarkerKind::Rect_13x13; break;
+
+ case BitmapMarkerKind::Circ_7x7: eRetval = BitmapMarkerKind::Circ_9x9; break;
+ case BitmapMarkerKind::Circ_9x9: eRetval = BitmapMarkerKind::Circ_11x11; break;
+
+ case BitmapMarkerKind::Customshape_7x7: eRetval = BitmapMarkerKind::Customshape_9x9; break;
+ case BitmapMarkerKind::Customshape_9x9: eRetval = BitmapMarkerKind::Customshape_11x11; break;
+ //case BitmapMarkerKind::Customshape_11x11: eRetval = ; break;
+
+ case BitmapMarkerKind::Elli_7x9: eRetval = BitmapMarkerKind::Elli_9x11; break;
+
+ case BitmapMarkerKind::Elli_9x7: eRetval = BitmapMarkerKind::Elli_11x9; break;
+
+ case BitmapMarkerKind::RectPlus_7x7: eRetval = BitmapMarkerKind::RectPlus_9x9; break;
+ case BitmapMarkerKind::RectPlus_9x9: eRetval = BitmapMarkerKind::RectPlus_11x11; break;
+
+ // let anchor blink with its pressed state
+ case BitmapMarkerKind::Anchor: eRetval = BitmapMarkerKind::AnchorPressed; break;
+
+ // same for AnchorTR
+ case BitmapMarkerKind::AnchorTR: eRetval = BitmapMarkerKind::AnchorPressedTR; break;
+ default:
+ break;
+ }
+
+ return eRetval;
+}
+
+namespace
+{
+
+OUString appendMarkerName(BitmapMarkerKind eKindOfMarker)
+{
+ switch(eKindOfMarker)
+ {
+ case BitmapMarkerKind::Rect_7x7:
+ return "rect7";
+ case BitmapMarkerKind::Rect_9x9:
+ return "rect9";
+ case BitmapMarkerKind::Rect_11x11:
+ return "rect11";
+ case BitmapMarkerKind::Rect_13x13:
+ return "rect13";
+ case BitmapMarkerKind::Circ_7x7:
+ case BitmapMarkerKind::Customshape_7x7:
+ return "circ7";
+ case BitmapMarkerKind::Circ_9x9:
+ case BitmapMarkerKind::Customshape_9x9:
+ return "circ9";
+ case BitmapMarkerKind::Circ_11x11:
+ case BitmapMarkerKind::Customshape_11x11:
+ return "circ11";
+ case BitmapMarkerKind::Elli_7x9:
+ return "elli7x9";
+ case BitmapMarkerKind::Elli_9x11:
+ return "elli9x11";
+ case BitmapMarkerKind::Elli_9x7:
+ return "elli9x7";
+ case BitmapMarkerKind::Elli_11x9:
+ return "elli11x9";
+ case BitmapMarkerKind::RectPlus_7x7:
+ return "rectplus7";
+ case BitmapMarkerKind::RectPlus_9x9:
+ return "rectplus9";
+ case BitmapMarkerKind::RectPlus_11x11:
+ return "rectplus11";
+ case BitmapMarkerKind::Crosshair:
+ return "cross";
+ case BitmapMarkerKind::Anchor:
+ case BitmapMarkerKind::AnchorTR:
+ return "anchor";
+ case BitmapMarkerKind::AnchorPressed:
+ case BitmapMarkerKind::AnchorPressedTR:
+ return "anchor-pressed";
+ case BitmapMarkerKind::Glue:
+ return "glue-selected";
+ case BitmapMarkerKind::Glue_Deselected:
+ return "glue-unselected";
+ default:
+ break;
+ }
+ return OUString();
+}
+
+OUString appendMarkerColor(BitmapColorIndex eIndex)
+{
+ switch(eIndex)
+ {
+ case BitmapColorIndex::LightGreen:
+ return "1";
+ case BitmapColorIndex::Cyan:
+ return "2";
+ case BitmapColorIndex::LightCyan:
+ return "3";
+ case BitmapColorIndex::Red:
+ return "4";
+ case BitmapColorIndex::LightRed:
+ return "5";
+ case BitmapColorIndex::Yellow:
+ return "6";
+ default:
+ break;
+ }
+ return OUString();
+}
+
+BitmapEx ImpGetBitmapEx(BitmapMarkerKind eKindOfMarker, BitmapColorIndex eIndex)
+{
+ // use this code path only when we use HiDPI (for now)
+ if (Application::GetDefaultDevice()->GetDPIScalePercentage() > 100)
+ {
+ OUString sMarkerName = appendMarkerName(eKindOfMarker);
+ if (!sMarkerName.isEmpty())
+ {
+ OUString sMarkerPrefix("svx/res/marker-");
+ BitmapEx aBitmapEx;
+
+ if (eKindOfMarker == BitmapMarkerKind::Crosshair
+ || eKindOfMarker == BitmapMarkerKind::Anchor
+ || eKindOfMarker == BitmapMarkerKind::AnchorTR
+ || eKindOfMarker == BitmapMarkerKind::AnchorPressed
+ || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR
+ || eKindOfMarker == BitmapMarkerKind::Glue
+ || eKindOfMarker == BitmapMarkerKind::Glue_Deselected)
+ {
+ aBitmapEx = vcl::bitmap::loadFromName(sMarkerPrefix + sMarkerName + ".png");
+ }
+ else
+ {
+ aBitmapEx = vcl::bitmap::loadFromName(sMarkerPrefix + sMarkerName + "-" + appendMarkerColor(eIndex) + ".png");
+ }
+
+ if (!aBitmapEx.IsEmpty())
+ return aBitmapEx;
+ }
+ }
+
+ // if we can't load the marker...
+
+ static vcl::DeleteOnDeinit< SdrHdlBitmapSet > aModernSet {};
+ return aModernSet.get()->GetBitmapEx(eKindOfMarker, sal_uInt16(eIndex));
+}
+
+} // end anonymous namespace
+
+std::unique_ptr<sdr::overlay::OverlayObject> SdrHdl::CreateOverlayObject(
+ const basegfx::B2DPoint& rPos,
+ BitmapColorIndex eColIndex, BitmapMarkerKind eKindOfMarker, Point aMoveOutsideOffset)
+{
+ std::unique_ptr<sdr::overlay::OverlayObject> pRetval;
+
+ // support bigger sizes
+ bool bForceBiggerSize(false);
+
+ if (pHdlList && pHdlList->GetHdlSize() > 3)
+ {
+ switch(eKindOfMarker)
+ {
+ case BitmapMarkerKind::Anchor:
+ case BitmapMarkerKind::AnchorPressed:
+ case BitmapMarkerKind::AnchorTR:
+ case BitmapMarkerKind::AnchorPressedTR:
+ {
+ // #i121463# For anchor, do not simply make bigger because of HdlSize,
+ // do it dependent of IsSelected() which Writer can set in drag mode
+ if(IsSelected())
+ {
+ bForceBiggerSize = true;
+ }
+ break;
+ }
+ default:
+ {
+ bForceBiggerSize = true;
+ break;
+ }
+ }
+ }
+
+ if(bForceBiggerSize)
+ {
+ eKindOfMarker = GetNextBigger(eKindOfMarker);
+ }
+
+ // This handle has the focus, visualize it
+ if(IsFocusHdl() && pHdlList && pHdlList->GetFocusHdl() == this)
+ {
+ // create animated handle
+ BitmapMarkerKind eNextBigger = GetNextBigger(eKindOfMarker);
+
+ if(eNextBigger == eKindOfMarker)
+ {
+ // this may happen for the not supported getting-bigger types.
+ // Choose an alternative here
+ switch(eKindOfMarker)
+ {
+ case BitmapMarkerKind::Rect_13x13: eNextBigger = BitmapMarkerKind::Rect_11x11; break;
+ case BitmapMarkerKind::Circ_11x11: eNextBigger = BitmapMarkerKind::Elli_11x9; break;
+ case BitmapMarkerKind::Elli_9x11: eNextBigger = BitmapMarkerKind::Elli_11x9; break;
+ case BitmapMarkerKind::Elli_11x9: eNextBigger = BitmapMarkerKind::Elli_9x11; break;
+ case BitmapMarkerKind::RectPlus_11x11: eNextBigger = BitmapMarkerKind::Rect_13x13; break;
+
+ case BitmapMarkerKind::Crosshair:
+ eNextBigger = BitmapMarkerKind::Glue;
+ break;
+
+ case BitmapMarkerKind::Glue:
+ eNextBigger = BitmapMarkerKind::Crosshair;
+ break;
+ case BitmapMarkerKind::Glue_Deselected:
+ eNextBigger = BitmapMarkerKind::Glue;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // create animated handle
+ BitmapEx aBmpEx1 = ImpGetBitmapEx(eKindOfMarker, eColIndex);
+ BitmapEx aBmpEx2 = ImpGetBitmapEx(eNextBigger, eColIndex);
+
+ // #i53216# Use system cursor blink time. Use the unsigned value.
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const sal_uInt64 nBlinkTime(rStyleSettings.GetCursorBlinkTime());
+
+ if(eKindOfMarker == BitmapMarkerKind::Anchor || eKindOfMarker == BitmapMarkerKind::AnchorPressed)
+ {
+ // when anchor is used take upper left as reference point inside the handle
+ pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime));
+ }
+ else if(eKindOfMarker == BitmapMarkerKind::AnchorTR || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR)
+ {
+ // AnchorTR for SW, take top right as (0,0)
+ pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
+ static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1), 0,
+ static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1), 0));
+ }
+ else
+ {
+ // create centered handle as default
+ pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
+ static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
+ static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
+ static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
+ static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Height() - 1) >> 1));
+ }
+ }
+ else
+ {
+ // create normal handle: use ImpGetBitmapEx(...) now
+ BitmapEx aBmpEx = ImpGetBitmapEx(eKindOfMarker, eColIndex);
+
+ // When the image with handles is not found, the bitmap returned is
+ // empty. This is a problem when we use LibreOffice as a library
+ // (through LOKit - for example on Android) even when we don't show
+ // the handles, because the hit test would always return false.
+ //
+ // This HACK replaces the empty bitmap with a black 13x13 bitmap handle
+ // so that the hit test works for this case.
+ if (aBmpEx.IsEmpty())
+ {
+ aBmpEx = BitmapEx(Size(13, 13), vcl::PixelFormat::N24_BPP);
+ aBmpEx.Erase(COL_BLACK);
+ }
+
+ if(eKindOfMarker == BitmapMarkerKind::Anchor || eKindOfMarker == BitmapMarkerKind::AnchorPressed)
+ {
+ // upper left as reference point inside the handle for AnchorPressed, too
+ pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx));
+ }
+ else if(eKindOfMarker == BitmapMarkerKind::AnchorTR || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR)
+ {
+ // AnchorTR for SW, take top right as (0,0)
+ pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx,
+ static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1), 0));
+ }
+ else
+ {
+ sal_uInt16 nCenX(static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1) >> 1);
+ sal_uInt16 nCenY(static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Height() - 1) >> 1);
+
+ if(aMoveOutsideOffset.X() > 0)
+ {
+ nCenX = 0;
+ }
+ else if(aMoveOutsideOffset.X() < 0)
+ {
+ nCenX = static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1);
+ }
+
+ if(aMoveOutsideOffset.Y() > 0)
+ {
+ nCenY = 0;
+ }
+ else if(aMoveOutsideOffset.Y() < 0)
+ {
+ nCenY = static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Height() - 1);
+ }
+
+ // create centered handle as default
+ pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx, nCenX, nCenY));
+ }
+ }
+
+ return pRetval;
+}
+
+bool SdrHdl::IsHdlHit(const Point& rPnt) const
+{
+ // OVERLAYMANAGER
+ basegfx::B2DPoint aPosition(rPnt.X(), rPnt.Y());
+ return maOverlayGroup.isHitLogic(aPosition);
+}
+
+PointerStyle SdrHdl::GetPointer() const
+{
+ PointerStyle ePtr=PointerStyle::Move;
+ const bool bSize=eKind>=SdrHdlKind::UpperLeft && eKind<=SdrHdlKind::LowerRight;
+ const bool bRot=pHdlList!=nullptr && pHdlList->IsRotateShear();
+ const bool bDis=pHdlList!=nullptr && pHdlList->IsDistortShear();
+ if (bSize && pHdlList!=nullptr && (bRot || bDis)) {
+ switch (eKind) {
+ case SdrHdlKind::UpperLeft: case SdrHdlKind::UpperRight:
+ case SdrHdlKind::LowerLeft: case SdrHdlKind::LowerRight: ePtr=bRot ? PointerStyle::Rotate : PointerStyle::RefHand; break;
+ case SdrHdlKind::Left : case SdrHdlKind::Right: ePtr=PointerStyle::VShear; break;
+ case SdrHdlKind::Upper: case SdrHdlKind::Lower: ePtr=PointerStyle::HShear; break;
+ default:
+ break;
+ }
+ } else {
+ // When resizing rotated rectangles, rotate the mouse cursor slightly, too
+ if (bSize && nRotationAngle!=0_deg100) {
+ Degree100 nHdlAngle(0);
+ switch (eKind) {
+ case SdrHdlKind::LowerRight: nHdlAngle=31500_deg100; break;
+ case SdrHdlKind::Lower: nHdlAngle=27000_deg100; break;
+ case SdrHdlKind::LowerLeft: nHdlAngle=22500_deg100; break;
+ case SdrHdlKind::Left : nHdlAngle=18000_deg100; break;
+ case SdrHdlKind::UpperLeft: nHdlAngle=13500_deg100; break;
+ case SdrHdlKind::Upper: nHdlAngle=9000_deg100; break;
+ case SdrHdlKind::UpperRight: nHdlAngle=4500_deg100; break;
+ case SdrHdlKind::Right: nHdlAngle=0_deg100; break;
+ default:
+ break;
+ }
+ // a little bit more (for rounding)
+ nHdlAngle = NormAngle36000(nHdlAngle + nRotationAngle + 2249_deg100);
+ nHdlAngle/=4500_deg100;
+ switch (static_cast<sal_uInt8>(nHdlAngle.get())) {
+ case 0: ePtr=PointerStyle::ESize; break;
+ case 1: ePtr=PointerStyle::NESize; break;
+ case 2: ePtr=PointerStyle::NSize; break;
+ case 3: ePtr=PointerStyle::NWSize; break;
+ case 4: ePtr=PointerStyle::WSize; break;
+ case 5: ePtr=PointerStyle::SWSize; break;
+ case 6: ePtr=PointerStyle::SSize; break;
+ case 7: ePtr=PointerStyle::SESize; break;
+ } // switch
+ } else {
+ switch (eKind) {
+ case SdrHdlKind::UpperLeft: ePtr=PointerStyle::NWSize; break;
+ case SdrHdlKind::Upper: ePtr=PointerStyle::NSize; break;
+ case SdrHdlKind::UpperRight: ePtr=PointerStyle::NESize; break;
+ case SdrHdlKind::Left : ePtr=PointerStyle::WSize; break;
+ case SdrHdlKind::Right: ePtr=PointerStyle::ESize; break;
+ case SdrHdlKind::LowerLeft: ePtr=PointerStyle::SWSize; break;
+ case SdrHdlKind::Lower: ePtr=PointerStyle::SSize; break;
+ case SdrHdlKind::LowerRight: ePtr=PointerStyle::SESize; break;
+ case SdrHdlKind::Poly : ePtr=PointerStyle::MovePoint; break;
+ case SdrHdlKind::Circle : ePtr=PointerStyle::Hand; break;
+ case SdrHdlKind::Ref1 : ePtr=PointerStyle::RefHand; break;
+ case SdrHdlKind::Ref2 : ePtr=PointerStyle::RefHand; break;
+ case SdrHdlKind::BezierWeight : ePtr=PointerStyle::MoveBezierWeight; break;
+ case SdrHdlKind::Glue : ePtr=PointerStyle::MovePoint; break;
+ case SdrHdlKind::CustomShape1 : ePtr=PointerStyle::Hand; break;
+ default:
+ break;
+ }
+ }
+ }
+ return ePtr;
+}
+
+bool SdrHdl::IsFocusHdl() const
+{
+ switch(eKind)
+ {
+ case SdrHdlKind::UpperLeft:
+ case SdrHdlKind::Upper:
+ case SdrHdlKind::UpperRight:
+ case SdrHdlKind::Left:
+ case SdrHdlKind::Right:
+ case SdrHdlKind::LowerLeft:
+ case SdrHdlKind::Lower:
+ case SdrHdlKind::LowerRight:
+ {
+ // if it's an activated TextEdit, it's moved to extended points
+ return !pHdlList || !pHdlList->IsMoveOutside();
+ }
+
+ case SdrHdlKind::Move: // handle to move object
+ case SdrHdlKind::Poly: // selected point of polygon or curve
+ case SdrHdlKind::BezierWeight: // weight at a curve
+ case SdrHdlKind::Circle: // angle of circle segments, corner radius of rectangles
+ case SdrHdlKind::Ref1: // reference point 1, e. g. center of rotation
+ case SdrHdlKind::Ref2: // reference point 2, e. g. endpoint of reflection axis
+ case SdrHdlKind::Glue: // gluepoint
+
+ // for SJ and the CustomShapeHandles:
+ case SdrHdlKind::CustomShape1:
+
+ case SdrHdlKind::User:
+ {
+ return true;
+ }
+
+ default:
+ {
+ return false;
+ }
+ }
+}
+
+void SdrHdl::onMouseEnter(const MouseEvent& /*rMEvt*/)
+{
+}
+
+void SdrHdl::onHelpRequest()
+{
+}
+
+void SdrHdl::onMouseLeave()
+{
+}
+
+BitmapEx SdrHdl::createGluePointBitmap()
+{
+ return ImpGetBitmapEx(BitmapMarkerKind::Glue_Deselected, BitmapColorIndex::LightGreen);
+}
+
+void SdrHdl::insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
+ const sdr::contact::ObjectContact& rObjectContact,
+ sdr::overlay::OverlayManager& rOverlayManager)
+{
+ // check if we have an OverlayObject
+ if(!pOverlayObject)
+ {
+ return;
+ }
+
+ // Add GridOffset for non-linear ViewToDevice transformation (calc)
+ if(nullptr != GetObj() && rObjectContact.supportsGridOffsets())
+ {
+ basegfx::B2DVector aOffset(0.0, 0.0);
+ const sdr::contact::ViewObjectContact& rVOC(GetObj()->GetViewContact().GetViewObjectContact(
+ const_cast<sdr::contact::ObjectContact&>(rObjectContact)));
+
+ rObjectContact.calculateGridOffsetForViewOjectContact(aOffset, rVOC);
+
+ if(!aOffset.equalZero())
+ {
+ pOverlayObject->setOffset(aOffset);
+ }
+ }
+
+ // add to OverlayManager
+ rOverlayManager.add(*pOverlayObject);
+
+ // add to local OverlayObjectList - ownership change (!)
+ maOverlayGroup.append(std::move(pOverlayObject));
+}
+
+SdrHdlColor::SdrHdlColor(const Point& rRef, Color aCol, const Size& rSize, bool bLum)
+: SdrHdl(rRef, SdrHdlKind::Color),
+ aMarkerSize(rSize),
+ bUseLuminance(bLum)
+{
+ if(IsUseLuminance())
+ aCol = GetLuminance(aCol);
+
+ // remember color
+ aMarkerColor = aCol;
+}
+
+SdrHdlColor::~SdrHdlColor()
+{
+}
+
+void SdrHdlColor::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ if(!pHdlList)
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!pView || pView->areMarkHandlesHidden())
+ return;
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ BitmapEx aBmpCol(CreateColorDropper(aMarkerColor));
+ basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
+ sdr::overlay::OverlayBitmapEx(
+ aPosition,
+ aBmpCol,
+ static_cast<sal_uInt16>(aBmpCol.GetSizePixel().Width() - 1) >> 1,
+ static_cast<sal_uInt16>(aBmpCol.GetSizePixel().Height() - 1) >> 1
+ ));
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+BitmapEx SdrHdlColor::CreateColorDropper(Color aCol)
+{
+ // get the Bitmap
+ VclPtr<VirtualDevice> pWrite(VclPtr<VirtualDevice>::Create());
+ pWrite->SetOutputSizePixel(aMarkerSize);
+ pWrite->SetBackground(aCol);
+ pWrite->Erase();
+
+ // draw outer border
+ sal_Int32 nWidth = aMarkerSize.Width();
+ sal_Int32 nHeight = aMarkerSize.Height();
+
+ pWrite->SetLineColor(COL_LIGHTGRAY);
+ pWrite->DrawLine(Point(0, 0), Point(0, nHeight - 1));
+ pWrite->DrawLine(Point(1, 0), Point(nWidth - 1, 0));
+ pWrite->SetLineColor(COL_GRAY);
+ pWrite->DrawLine(Point(1, nHeight - 1), Point(nWidth - 1, nHeight - 1));
+ pWrite->DrawLine(Point(nWidth - 1, 1), Point(nWidth - 1, nHeight - 2));
+
+ // draw lighter UpperLeft
+ const Color aLightColor(
+ static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetRed()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
+ static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetGreen()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
+ static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetBlue()) + sal_Int16(0x0040)), sal_Int16(0x00ff))));
+ pWrite->SetLineColor(aLightColor);
+ pWrite->DrawLine(Point(1, 1), Point(1, nHeight - 2));
+ pWrite->DrawLine(Point(2, 1), Point(nWidth - 2, 1));
+
+ // draw darker LowerRight
+ const Color aDarkColor(
+ static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetRed()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
+ static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetGreen()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
+ static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetBlue()) - sal_Int16(0x0040)), sal_Int16(0x0000))));
+ pWrite->SetLineColor(aDarkColor);
+ pWrite->DrawLine(Point(2, nHeight - 2), Point(nWidth - 2, nHeight - 2));
+ pWrite->DrawLine(Point(nWidth - 2, 2), Point(nWidth - 2, nHeight - 3));
+
+ return pWrite->GetBitmapEx(Point(0,0), aMarkerSize);
+}
+
+Color SdrHdlColor::GetLuminance(const Color& rCol)
+{
+ sal_uInt8 aLum = rCol.GetLuminance();
+ Color aRetval(aLum, aLum, aLum);
+ return aRetval;
+}
+
+void SdrHdlColor::SetColor(Color aNew, bool bCallLink)
+{
+ if(IsUseLuminance())
+ aNew = GetLuminance(aNew);
+
+ if(aMarkerColor != aNew)
+ {
+ // remember new color
+ aMarkerColor = aNew;
+
+ // create new display
+ Touch();
+
+ // tell about change
+ if(bCallLink)
+ aColorChangeHdl.Call(this);
+ }
+}
+
+void SdrHdlColor::SetSize(const Size& rNew)
+{
+ if(rNew != aMarkerSize)
+ {
+ // remember new size
+ aMarkerSize = rNew;
+
+ // create new display
+ Touch();
+ }
+}
+
+SdrHdlGradient::SdrHdlGradient(const Point& rRef1, const Point& rRef2, bool bGrad)
+ : SdrHdl(rRef1, bGrad ? SdrHdlKind::Gradient : SdrHdlKind::Transparence)
+ , pColHdl1(nullptr)
+ , pColHdl2(nullptr)
+ , a2ndPos(rRef2)
+ , bGradient(bGrad)
+ , bMoveSingleHandle(false)
+ , bMoveFirstHandle(false)
+{
+}
+
+SdrHdlGradient::~SdrHdlGradient()
+{
+}
+
+void SdrHdlGradient::Set2ndPos(const Point& rPnt)
+{
+ if(a2ndPos != rPnt)
+ {
+ // remember new position
+ a2ndPos = rPnt;
+
+ // create new display
+ Touch();
+ }
+}
+
+void SdrHdlGradient::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ if(!pHdlList)
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!pView || pView->areMarkHandlesHidden())
+ return;
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ // striped line in between
+ basegfx::B2DVector aVec(a2ndPos.X() - aPos.X(), a2ndPos.Y() - aPos.Y());
+ double fVecLen = aVec.getLength();
+ double fLongPercentArrow = (1.0 - 0.05) * fVecLen;
+ double fHalfArrowWidth = (0.05 * 0.5) * fVecLen;
+ aVec.normalize();
+ basegfx::B2DVector aPerpend(-aVec.getY(), aVec.getX());
+ sal_Int32 nMidX = static_cast<sal_Int32>(aPos.X() + aVec.getX() * fLongPercentArrow);
+ sal_Int32 nMidY = static_cast<sal_Int32>(aPos.Y() + aVec.getY() * fLongPercentArrow);
+ Point aMidPoint(nMidX, nMidY);
+
+ basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
+ basegfx::B2DPoint aMidPos(aMidPoint.X(), aMidPoint.Y());
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
+ sdr::overlay::OverlayLineStriped(
+ aPosition, aMidPos
+ ));
+
+ pNewOverlayObject->setBaseColor(IsGradient() ? COL_BLACK : COL_BLUE);
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+
+ // arrowhead
+ Point aLeft(aMidPoint.X() + static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
+ aMidPoint.Y() + static_cast<sal_Int32>(aPerpend.getY() * fHalfArrowWidth));
+ Point aRight(aMidPoint.X() - static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
+ aMidPoint.Y() - static_cast<sal_Int32>(aPerpend.getY() * fHalfArrowWidth));
+
+ basegfx::B2DPoint aPositionLeft(aLeft.X(), aLeft.Y());
+ basegfx::B2DPoint aPositionRight(aRight.X(), aRight.Y());
+ basegfx::B2DPoint aPosition2(a2ndPos.X(), a2ndPos.Y());
+
+ pNewOverlayObject.reset(new
+ sdr::overlay::OverlayTriangle(
+ aPositionLeft,
+ aPosition2,
+ aPositionRight,
+ IsGradient() ? COL_BLACK : COL_BLUE
+ ));
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SdrHdlGradient, ColorChangeHdl, SdrHdlColor*, void)
+{
+ if(GetObj())
+ FromIAOToItem(GetObj(), true, true);
+}
+
+void SdrHdlGradient::FromIAOToItem(SdrObject* _pObj, bool bSetItemOnObject, bool bUndo)
+{
+ // from IAO positions and colors to gradient
+ const SfxItemSet& rSet = _pObj->GetMergedItemSet();
+
+ GradTransGradient aOldGradTransGradient;
+ GradTransGradient aGradTransGradient;
+ GradTransVector aGradTransVector;
+
+ aGradTransVector.maPositionA = basegfx::B2DPoint(GetPos().X(), GetPos().Y());
+ aGradTransVector.maPositionB = basegfx::B2DPoint(Get2ndPos().X(), Get2ndPos().Y());
+ if(pColHdl1)
+ aGradTransVector.aCol1 = pColHdl1->GetColor();
+ if(pColHdl2)
+ aGradTransVector.aCol2 = pColHdl2->GetColor();
+
+ if(IsGradient())
+ aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
+ else
+ aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLFLOATTRANSPARENCE).GetGradientValue();
+
+ // transform vector data to gradient
+ GradTransformer::VecToGrad(aGradTransVector, aGradTransGradient, aOldGradTransGradient, _pObj, bMoveSingleHandle, bMoveFirstHandle);
+
+ if(bSetItemOnObject)
+ {
+ SdrModel& rModel(_pObj->getSdrModelFromSdrObject());
+ SfxItemSet aNewSet(rModel.GetItemPool());
+ const OUString aString;
+
+ if(IsGradient())
+ {
+ XFillGradientItem aNewGradItem(aString, aGradTransGradient.aGradient);
+ aNewSet.Put(aNewGradItem);
+ }
+ else
+ {
+ XFillFloatTransparenceItem aNewTransItem(aString, aGradTransGradient.aGradient);
+ aNewSet.Put(aNewTransItem);
+ }
+
+ if(bUndo && rModel.IsUndoEnabled())
+ {
+ rModel.BegUndo(SvxResId(IsGradient() ? SIP_XA_FILLGRADIENT : SIP_XA_FILLTRANSPARENCE));
+ rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoAttrObject(*_pObj));
+ rModel.EndUndo();
+ }
+
+ pObj->SetMergedItemSetAndBroadcast(aNewSet);
+ }
+
+ // back transformation, set values on pIAOHandle
+ GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, _pObj);
+
+ SetPos(Point(FRound(aGradTransVector.maPositionA.getX()), FRound(aGradTransVector.maPositionA.getY())));
+ Set2ndPos(Point(FRound(aGradTransVector.maPositionB.getX()), FRound(aGradTransVector.maPositionB.getY())));
+ if(pColHdl1)
+ {
+ pColHdl1->SetPos(Point(FRound(aGradTransVector.maPositionA.getX()), FRound(aGradTransVector.maPositionA.getY())));
+ pColHdl1->SetColor(aGradTransVector.aCol1);
+ }
+ if(pColHdl2)
+ {
+ pColHdl2->SetPos(Point(FRound(aGradTransVector.maPositionB.getX()), FRound(aGradTransVector.maPositionB.getY())));
+ pColHdl2->SetColor(aGradTransVector.aCol2);
+ }
+}
+
+
+SdrHdlLine::~SdrHdlLine() {}
+
+void SdrHdlLine::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ if(!pHdlList)
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!(pView && !pView->areMarkHandlesHidden() && pHdl1 && pHdl2))
+ return;
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ basegfx::B2DPoint aPosition1(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
+ basegfx::B2DPoint aPosition2(pHdl2->GetPos().X(), pHdl2->GetPos().Y());
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
+ sdr::overlay::OverlayLineStriped(
+ aPosition1,
+ aPosition2
+ ));
+
+ // color(?)
+ pNewOverlayObject->setBaseColor(COL_LIGHTRED);
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+PointerStyle SdrHdlLine::GetPointer() const
+{
+ return PointerStyle::RefHand;
+}
+
+
+SdrHdlBezWgt::~SdrHdlBezWgt() {}
+
+void SdrHdlBezWgt::CreateB2dIAObject()
+{
+ // call parent
+ SdrHdl::CreateB2dIAObject();
+
+ // create lines
+ if(!pHdlList)
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!pView || pView->areMarkHandlesHidden())
+ return;
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ basegfx::B2DPoint aPosition1(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
+ basegfx::B2DPoint aPosition2(aPos.X(), aPos.Y());
+
+ if(!aPosition1.equal(aPosition2))
+ {
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
+ sdr::overlay::OverlayLineStriped(
+ aPosition1,
+ aPosition2
+ ));
+
+ // line part is not hittable
+ pNewOverlayObject->setHittable(false);
+
+ // color(?)
+ pNewOverlayObject->setBaseColor(COL_LIGHTBLUE);
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+ }
+}
+
+
+E3dVolumeMarker::E3dVolumeMarker(const basegfx::B2DPolyPolygon& rWireframePoly)
+{
+ aWireframePoly = rWireframePoly;
+}
+
+void E3dVolumeMarker::CreateB2dIAObject()
+{
+ // create lines
+ if(!pHdlList)
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!pView || pView->areMarkHandlesHidden())
+ return;
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is() && aWireframePoly.count())
+ {
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
+ sdr::overlay::OverlayPolyPolygonStripedAndFilled(
+ aWireframePoly));
+
+ pNewOverlayObject->setBaseColor(COL_BLACK);
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+
+ImpEdgeHdl::~ImpEdgeHdl()
+{
+}
+
+void ImpEdgeHdl::CreateB2dIAObject()
+{
+ if(nObjHdlNum <= 1 && pObj)
+ {
+ // first throw away old one
+ GetRidOfIAObject();
+
+ BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
+ BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
+
+ if(pHdlList)
+ {
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(pView && !pView->areMarkHandlesHidden())
+ {
+ const SdrEdgeObj* pEdge = static_cast<SdrEdgeObj*>(pObj);
+
+ if(pEdge->GetConnectedNode(nObjHdlNum == 0) != nullptr)
+ eColIndex = BitmapColorIndex::LightRed;
+
+ if(nPPntNum < 2)
+ {
+ // Handle with plus sign inside
+ eKindOfMarker = BitmapMarkerKind::Circ_7x7;
+ }
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(pPageView)
+ {
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(CreateOverlayObject(
+ aPosition,
+ eColIndex,
+ eKindOfMarker));
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // call parent
+ SdrHdl::CreateB2dIAObject();
+ }
+}
+
+void ImpEdgeHdl::SetLineCode(SdrEdgeLineCode eCode)
+{
+ if(eLineCode != eCode)
+ {
+ // remember new value
+ eLineCode = eCode;
+
+ // create new display
+ Touch();
+ }
+}
+
+PointerStyle ImpEdgeHdl::GetPointer() const
+{
+ SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
+ if (pEdge==nullptr)
+ return SdrHdl::GetPointer();
+ if (nObjHdlNum<=1)
+ return PointerStyle::MovePoint;
+ if (IsHorzDrag())
+ return PointerStyle::ESize;
+ else
+ return PointerStyle::SSize;
+}
+
+bool ImpEdgeHdl::IsHorzDrag() const
+{
+ SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
+ if (pEdge==nullptr)
+ return false;
+ if (nObjHdlNum<=1)
+ return false;
+
+ SdrEdgeKind eEdgeKind = pEdge->GetObjectItem(SDRATTR_EDGEKIND).GetValue();
+
+ const SdrEdgeInfoRec& rInfo=pEdge->aEdgeInfo;
+ if (eEdgeKind==SdrEdgeKind::OrthoLines || eEdgeKind==SdrEdgeKind::Bezier)
+ {
+ return !rInfo.ImpIsHorzLine(eLineCode,*pEdge->pEdgeTrack);
+ }
+ else if (eEdgeKind==SdrEdgeKind::ThreeLines)
+ {
+ tools::Long nAngle=nObjHdlNum==2 ? rInfo.nAngle1 : rInfo.nAngle2;
+ return nAngle==0 || nAngle==18000;
+ }
+ return false;
+}
+
+
+ImpMeasureHdl::~ImpMeasureHdl()
+{
+}
+
+void ImpMeasureHdl::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ if(!pHdlList)
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!pView || pView->areMarkHandlesHidden())
+ return;
+
+ BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
+ BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_9x9;
+
+ if(nObjHdlNum > 1)
+ {
+ eKindOfMarker = BitmapMarkerKind::Rect_7x7;
+ }
+
+ if(bSelect)
+ {
+ eColIndex = BitmapColorIndex::Cyan;
+ }
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
+ std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(CreateOverlayObject(
+ aPosition,
+ eColIndex,
+ eKindOfMarker));
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+PointerStyle ImpMeasureHdl::GetPointer() const
+{
+ switch (nObjHdlNum)
+ {
+ case 0: case 1: return PointerStyle::Hand;
+ case 2: case 3: return PointerStyle::MovePoint;
+ case 4: case 5: return SdrHdl::GetPointer(); // will then be rotated appropriately
+ } // switch
+ return PointerStyle::NotAllowed;
+}
+
+
+ImpTextframeHdl::ImpTextframeHdl(const tools::Rectangle& rRect) :
+ SdrHdl(rRect.TopLeft(),SdrHdlKind::Move),
+ maRect(rRect)
+{
+}
+
+void ImpTextframeHdl::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ if(!pHdlList)
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+
+ if(!pView || pView->areMarkHandlesHidden())
+ return;
+
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ const basegfx::B2DPoint aTopLeft(maRect.Left(), maRect.Top());
+ const basegfx::B2DPoint aBottomRight(maRect.Right(), maRect.Bottom());
+ const Color aHilightColor(SvtOptionsDrawinglayer::getHilightColor());
+ const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
+
+ std::unique_ptr<sdr::overlay::OverlayRectangle> pNewOverlayObject(new sdr::overlay::OverlayRectangle(
+ aTopLeft,
+ aBottomRight,
+ aHilightColor,
+ fTransparence,
+ 3.0,
+ 3.0,
+ -toRadians(nRotationAngle),
+ true)); // allow animation; the Handle is not shown at text edit time
+
+ pNewOverlayObject->setHittable(false);
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNewOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+
+static bool ImpSdrHdlListSorter(std::unique_ptr<SdrHdl> const& lhs, std::unique_ptr<SdrHdl> const& rhs)
+{
+ SdrHdlKind eKind1=lhs->GetKind();
+ SdrHdlKind eKind2=rhs->GetKind();
+ // Level 1: first normal handles, then Glue, then User, then Plus handles, then reference point handles
+ unsigned n1=1;
+ unsigned n2=1;
+ if (eKind1!=eKind2)
+ {
+ if (eKind1==SdrHdlKind::Ref1 || eKind1==SdrHdlKind::Ref2 || eKind1==SdrHdlKind::MirrorAxis) n1=5;
+ else if (eKind1==SdrHdlKind::Glue) n1=2;
+ else if (eKind1==SdrHdlKind::User) n1=3;
+ else if (eKind1==SdrHdlKind::SmartTag) n1=0;
+ if (eKind2==SdrHdlKind::Ref1 || eKind2==SdrHdlKind::Ref2 || eKind2==SdrHdlKind::MirrorAxis) n2=5;
+ else if (eKind2==SdrHdlKind::Glue) n2=2;
+ else if (eKind2==SdrHdlKind::User) n2=3;
+ else if (eKind2==SdrHdlKind::SmartTag) n2=0;
+ }
+ if (lhs->IsPlusHdl()) n1=4;
+ if (rhs->IsPlusHdl()) n2=4;
+ if (n1==n2)
+ {
+ // Level 2: PageView (Pointer)
+ SdrPageView* pPV1=lhs->GetPageView();
+ SdrPageView* pPV2=rhs->GetPageView();
+ if (pPV1==pPV2)
+ {
+ // Level 3: Position (x+y)
+ SdrObject* pObj1=lhs->GetObj();
+ SdrObject* pObj2=rhs->GetObj();
+ if (pObj1==pObj2)
+ {
+ sal_uInt32 nNum1=lhs->GetObjHdlNum();
+ sal_uInt32 nNum2=rhs->GetObjHdlNum();
+ if (nNum1==nNum2)
+ {
+ if (eKind1==eKind2)
+ return lhs<rhs; // Hack, to always get to the same sorting
+ return static_cast<sal_uInt16>(eKind1)<static_cast<sal_uInt16>(eKind2);
+ }
+ else
+ return nNum1<nNum2;
+ }
+ else
+ {
+ return pObj1<pObj2;
+ }
+ }
+ else
+ {
+ return pPV1<pPV2;
+ }
+ }
+ else
+ {
+ return n1<n2;
+ }
+}
+
+namespace {
+
+// Helper struct for re-sorting handles
+struct ImplHdlAndIndex
+{
+ SdrHdl* mpHdl;
+ sal_uInt32 mnIndex;
+};
+
+}
+
+extern "C" {
+
+// Helper method for sorting handles taking care of OrdNums, keeping order in
+// single objects and re-sorting polygon handles intuitively
+static int ImplSortHdlFunc( const void* pVoid1, const void* pVoid2 )
+{
+ const ImplHdlAndIndex* p1 = static_cast<ImplHdlAndIndex const *>(pVoid1);
+ const ImplHdlAndIndex* p2 = static_cast<ImplHdlAndIndex const *>(pVoid2);
+
+ if(p1->mpHdl->GetObj() == p2->mpHdl->GetObj())
+ {
+ if(p1->mpHdl->GetObj() && dynamic_cast<const SdrPathObj*>(p1->mpHdl->GetObj()) != nullptr)
+ {
+ // same object and a path object
+ if((p1->mpHdl->GetKind() == SdrHdlKind::Poly || p1->mpHdl->GetKind() == SdrHdlKind::BezierWeight)
+ && (p2->mpHdl->GetKind() == SdrHdlKind::Poly || p2->mpHdl->GetKind() == SdrHdlKind::BezierWeight))
+ {
+ // both handles are point or control handles
+ if(p1->mpHdl->GetPolyNum() == p2->mpHdl->GetPolyNum())
+ {
+ if(p1->mpHdl->GetPointNum() < p2->mpHdl->GetPointNum())
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ else if(p1->mpHdl->GetPolyNum() < p2->mpHdl->GetPolyNum())
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ if(!p1->mpHdl->GetObj())
+ {
+ return -1;
+ }
+ else if(!p2->mpHdl->GetObj())
+ {
+ return 1;
+ }
+ else
+ {
+ // different objects, use OrdNum for sort
+ const sal_uInt32 nOrdNum1 = p1->mpHdl->GetObj()->GetOrdNum();
+ const sal_uInt32 nOrdNum2 = p2->mpHdl->GetObj()->GetOrdNum();
+
+ if(nOrdNum1 < nOrdNum2)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+
+ // fallback to indices
+ if(p1->mnIndex < p2->mnIndex)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+}
+
+void SdrHdlList::TravelFocusHdl(bool bForward)
+{
+ // security correction
+ if (mnFocusIndex >= GetHdlCount())
+ mnFocusIndex = SAL_MAX_SIZE;
+
+ if(maList.empty())
+ return;
+
+ // take care of old handle
+ const size_t nOldHdlNum(mnFocusIndex);
+ SdrHdl* pOld = nullptr;
+ if (nOldHdlNum < GetHdlCount())
+ pOld = GetHdl(nOldHdlNum);
+
+ if(pOld)
+ {
+ // switch off old handle
+ mnFocusIndex = SAL_MAX_SIZE;
+ pOld->Touch();
+ }
+
+ // allocate pointer array for sorted handle list
+ std::unique_ptr<ImplHdlAndIndex[]> pHdlAndIndex(new ImplHdlAndIndex[maList.size()]);
+
+ // build sorted handle list
+ for( size_t a = 0; a < maList.size(); ++a)
+ {
+ pHdlAndIndex[a].mpHdl = maList[a].get();
+ pHdlAndIndex[a].mnIndex = a;
+ }
+
+ qsort(pHdlAndIndex.get(), maList.size(), sizeof(ImplHdlAndIndex), ImplSortHdlFunc);
+
+ // look for old num in sorted array
+ size_t nOldHdl(nOldHdlNum);
+
+ if(nOldHdlNum != SAL_MAX_SIZE)
+ {
+ for(size_t a = 0; a < maList.size(); ++a)
+ {
+ if(pHdlAndIndex[a].mpHdl == pOld)
+ {
+ nOldHdl = a;
+ break;
+ }
+ }
+ }
+
+ // build new HdlNum
+ size_t nNewHdl(nOldHdl);
+
+ // do the focus travel
+ if(bForward)
+ {
+ if(nOldHdl != SAL_MAX_SIZE)
+ {
+ if(nOldHdl == maList.size() - 1)
+ {
+ // end forward run
+ nNewHdl = SAL_MAX_SIZE;
+ }
+ else
+ {
+ // simply the next handle
+ nNewHdl++;
+ }
+ }
+ else
+ {
+ // start forward run at first entry
+ nNewHdl = 0;
+ }
+ }
+ else
+ {
+ if(nOldHdl == SAL_MAX_SIZE)
+ {
+ // start backward run at last entry
+ nNewHdl = maList.size() - 1;
+
+ }
+ else
+ {
+ if(nOldHdl == 0)
+ {
+ // end backward run
+ nNewHdl = SAL_MAX_SIZE;
+ }
+ else
+ {
+ // simply the previous handle
+ nNewHdl--;
+ }
+ }
+ }
+
+ // build new HdlNum
+ sal_uIntPtr nNewHdlNum(nNewHdl);
+
+ // look for old num in sorted array
+ if(nNewHdl != SAL_MAX_SIZE)
+ {
+ SdrHdl* pNew = pHdlAndIndex[nNewHdl].mpHdl;
+
+ for(size_t a = 0; a < maList.size(); ++a)
+ {
+ if(maList[a].get() == pNew)
+ {
+ nNewHdlNum = a;
+ break;
+ }
+ }
+ }
+
+ // take care of next handle
+ if(nOldHdlNum != nNewHdlNum)
+ {
+ mnFocusIndex = nNewHdlNum;
+ if (mnFocusIndex < GetHdlCount())
+ {
+ SdrHdl* pNew = GetHdl(mnFocusIndex);
+ pNew->Touch();
+ }
+ }
+}
+
+SdrHdl* SdrHdlList::GetFocusHdl() const
+{
+ if(mnFocusIndex < GetHdlCount())
+ return GetHdl(mnFocusIndex);
+ else
+ return nullptr;
+}
+
+void SdrHdlList::SetFocusHdl(SdrHdl* pNew)
+{
+ if(!pNew)
+ return;
+
+ SdrHdl* pActual = GetFocusHdl();
+
+ if(pActual && pActual == pNew)
+ return;
+
+ const size_t nNewHdlNum = GetHdlNum(pNew);
+
+ if(nNewHdlNum != SAL_MAX_SIZE)
+ {
+ mnFocusIndex = nNewHdlNum;
+
+ if(pActual)
+ {
+ pActual->Touch();
+ }
+
+ pNew->Touch();
+ }
+}
+
+void SdrHdlList::ResetFocusHdl()
+{
+ SdrHdl* pHdl = GetFocusHdl();
+
+ mnFocusIndex = SAL_MAX_SIZE;
+
+ if(pHdl)
+ {
+ pHdl->Touch();
+ }
+}
+
+
+SdrHdlList::SdrHdlList(SdrMarkView* pV)
+: mnFocusIndex(SAL_MAX_SIZE),
+ pView(pV)
+{
+ nHdlSize = 3;
+ bRotateShear = false;
+ bMoveOutside = false;
+ bDistortShear = false;
+}
+
+SdrHdlList::~SdrHdlList()
+{
+ Clear();
+}
+
+void SdrHdlList::SetHdlSize(sal_uInt16 nSiz)
+{
+ if(nHdlSize != nSiz)
+ {
+ // remember new value
+ nHdlSize = nSiz;
+
+ // propagate change to IAOs
+ for(size_t i=0; i<GetHdlCount(); ++i)
+ {
+ SdrHdl* pHdl = GetHdl(i);
+ pHdl->Touch();
+ }
+ }
+}
+
+void SdrHdlList::SetMoveOutside(bool bOn)
+{
+ if(bMoveOutside != bOn)
+ {
+ // remember new value
+ bMoveOutside = bOn;
+
+ // propagate change to IAOs
+ for(size_t i=0; i<GetHdlCount(); ++i)
+ {
+ SdrHdl* pHdl = GetHdl(i);
+ pHdl->Touch();
+ }
+ }
+}
+
+void SdrHdlList::SetRotateShear(bool bOn)
+{
+ bRotateShear = bOn;
+}
+
+void SdrHdlList::SetDistortShear(bool bOn)
+{
+ bDistortShear = bOn;
+}
+
+std::unique_ptr<SdrHdl> SdrHdlList::RemoveHdl(size_t nNum)
+{
+ std::unique_ptr<SdrHdl> pRetval = std::move(maList[nNum]);
+ maList.erase(maList.begin() + nNum);
+
+ return pRetval;
+}
+
+void SdrHdlList::RemoveAllByKind(SdrHdlKind eKind)
+{
+ maList.erase(std::remove_if(maList.begin(), maList.end(),
+ [&eKind](std::unique_ptr<SdrHdl>& rItem) { return rItem->GetKind() == eKind; }),
+ maList.end());
+}
+
+void SdrHdlList::Clear()
+{
+ maList.clear();
+
+ bRotateShear=false;
+ bDistortShear=false;
+}
+
+void SdrHdlList::Sort()
+{
+ // remember currently focused handle
+ SdrHdl* pPrev = GetFocusHdl();
+
+ std::sort( maList.begin(), maList.end(), ImpSdrHdlListSorter );
+
+ // get now and compare
+ SdrHdl* pNow = GetFocusHdl();
+
+ if(pPrev == pNow)
+ return;
+
+ if(pPrev)
+ {
+ pPrev->Touch();
+ }
+
+ if(pNow)
+ {
+ pNow->Touch();
+ }
+}
+
+size_t SdrHdlList::GetHdlNum(const SdrHdl* pHdl) const
+{
+ if (pHdl==nullptr)
+ return SAL_MAX_SIZE;
+ auto it = std::find_if( maList.begin(), maList.end(),
+ [&](const std::unique_ptr<SdrHdl> & p) { return p.get() == pHdl; });
+ assert(it != maList.end());
+ if( it == maList.end() )
+ return SAL_MAX_SIZE;
+ return it - maList.begin();
+}
+
+void SdrHdlList::AddHdl(std::unique_ptr<SdrHdl> pHdl)
+{
+ assert(pHdl);
+ pHdl->SetHdlList(this);
+ maList.push_back(std::move(pHdl));
+}
+
+SdrHdl* SdrHdlList::IsHdlListHit(const Point& rPnt) const
+{
+ SdrHdl* pRet=nullptr;
+ const size_t nCount=GetHdlCount();
+ size_t nNum=nCount;
+ while (nNum>0 && pRet==nullptr)
+ {
+ nNum--;
+ SdrHdl* pHdl=GetHdl(nNum);
+ if (pHdl->IsHdlHit(rPnt))
+ pRet=pHdl;
+ }
+ return pRet;
+}
+
+SdrHdl* SdrHdlList::GetHdl(SdrHdlKind eKind1) const
+{
+ SdrHdl* pRet=nullptr;
+ for (size_t i=0; i<GetHdlCount() && pRet==nullptr; ++i)
+ {
+ SdrHdl* pHdl=GetHdl(i);
+ if (pHdl->GetKind()==eKind1)
+ pRet=pHdl;
+ }
+ return pRet;
+}
+
+void SdrHdlList::MoveTo(SdrHdlList& rOther)
+{
+ for (auto & pHdl : maList)
+ pHdl->SetHdlList(&rOther);
+ rOther.maList.insert(rOther.maList.end(),
+ std::make_move_iterator(maList.begin()), std::make_move_iterator(maList.end()));
+ maList.clear();
+}
+
+SdrCropHdl::SdrCropHdl(
+ const Point& rPnt,
+ SdrHdlKind eNewKind,
+ double fShearX,
+ double fRotation)
+: SdrHdl(rPnt, eNewKind),
+ mfShearX(fShearX),
+ mfRotation(fRotation)
+{
+}
+
+
+BitmapEx SdrCropHdl::GetBitmapForHandle( const BitmapEx& rBitmap, int nSize )
+{
+ int nPixelSize = 0, nX = 0, nY = 0, nOffset = 0;
+
+ if( nSize <= 3 )
+ {
+ nPixelSize = 13;
+ nOffset = 0;
+ }
+ else if( nSize <=4 )
+ {
+ nPixelSize = 17;
+ nOffset = 39;
+ }
+ else
+ {
+ nPixelSize = 21;
+ nOffset = 90;
+ }
+
+ switch( eKind )
+ {
+ case SdrHdlKind::UpperLeft: nX = 0; nY = 0; break;
+ case SdrHdlKind::Upper: nX = 1; nY = 0; break;
+ case SdrHdlKind::UpperRight: nX = 2; nY = 0; break;
+ case SdrHdlKind::Left: nX = 0; nY = 1; break;
+ case SdrHdlKind::Right: nX = 2; nY = 1; break;
+ case SdrHdlKind::LowerLeft: nX = 0; nY = 2; break;
+ case SdrHdlKind::Lower: nX = 1; nY = 2; break;
+ case SdrHdlKind::LowerRight: nX = 2; nY = 2; break;
+ default: break;
+ }
+
+ tools::Rectangle aSourceRect( Point( nX * nPixelSize + nOffset, nY * nPixelSize), Size(nPixelSize, nPixelSize) );
+
+ BitmapEx aRetval(rBitmap);
+ aRetval.Crop(aSourceRect);
+ return aRetval;
+}
+
+
+void SdrCropHdl::CreateB2dIAObject()
+{
+ // first throw away old one
+ GetRidOfIAObject();
+
+ SdrMarkView* pView = pHdlList ? pHdlList->GetView() : nullptr;
+ SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
+
+ if( !pPageView || pView->areMarkHandlesHidden() )
+ return;
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ int nHdlSize = pHdlList->GetHdlSize();
+
+ const BitmapEx aHandlesBitmap(SIP_SA_CROP_MARKERS);
+ BitmapEx aBmpEx1( GetBitmapForHandle( aHandlesBitmap, nHdlSize ) );
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject;
+
+ // animate focused handles
+ if(IsFocusHdl() && (pHdlList->GetFocusHdl() == this))
+ {
+ if( nHdlSize >= 2 )
+ nHdlSize = 1;
+
+ BitmapEx aBmpEx2( GetBitmapForHandle( aHandlesBitmap, nHdlSize + 1 ) );
+
+ const sal_uInt64 nBlinkTime = rStyleSettings.GetCursorBlinkTime();
+
+ pOverlayObject.reset(new sdr::overlay::OverlayAnimatedBitmapEx(
+ aPosition,
+ aBmpEx1,
+ aBmpEx2,
+ nBlinkTime,
+ static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
+ static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
+ static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
+ static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Height() - 1) >> 1,
+ mfShearX,
+ mfRotation));
+ }
+ else
+ {
+ // create centered handle as default
+ pOverlayObject.reset(new sdr::overlay::OverlayBitmapEx(
+ aPosition,
+ aBmpEx1,
+ static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
+ static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
+ 0.0,
+ mfShearX,
+ mfRotation));
+ }
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+
+// with the correction of crop handling I could get rid of the extra mirroring flag, adapted stuff
+// accordingly
+
+SdrCropViewHdl::SdrCropViewHdl(
+ const basegfx::B2DHomMatrix& rObjectTransform,
+ const Graphic& rGraphic,
+ double fCropLeft,
+ double fCropTop,
+ double fCropRight,
+ double fCropBottom)
+: SdrHdl(Point(), SdrHdlKind::User),
+ maObjectTransform(rObjectTransform),
+ maGraphic(rGraphic),
+ mfCropLeft(fCropLeft),
+ mfCropTop(fCropTop),
+ mfCropRight(fCropRight),
+ mfCropBottom(fCropBottom)
+{
+}
+
+namespace {
+
+void translateRotationToMirroring(basegfx::B2DVector & scale, double * rotate) {
+ assert(rotate != nullptr);
+
+ // detect 180 degree rotation, this is the same as mirrored in X and Y,
+ // thus change to mirroring. Prefer mirroring here. Use the equal call
+ // with getSmallValue here, the original which uses rtl::math::approxEqual
+ // is too correct here. Maybe this changes with enhanced precision in aw080
+ // to the better so that this can be reduced to the more precise call again
+ if(basegfx::fTools::equal(fabs(*rotate), M_PI, 0.000000001))
+ {
+ scale.setX(scale.getX() * -1.0);
+ scale.setY(scale.getY() * -1.0);
+ *rotate = 0.0;
+ }
+}
+
+}
+
+void SdrCropViewHdl::CreateB2dIAObject()
+{
+ GetRidOfIAObject();
+ SdrMarkView* pView = pHdlList ? pHdlList->GetView() : nullptr;
+ SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
+
+ if(!pPageView || pView->areMarkHandlesHidden())
+ {
+ return;
+ }
+
+ // decompose to have current translate and scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+
+ maObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ if(aScale.equalZero())
+ {
+ return;
+ }
+
+ translateRotationToMirroring(aScale, &fRotate);
+
+ // remember mirroring, reset at Scale and adapt crop values for usage;
+ // mirroring can stay in the object transformation, so do not have to
+ // cope with it here (except later for the CroppedImage transformation,
+ // see below)
+ const bool bMirroredX(aScale.getX() < 0.0);
+ const bool bMirroredY(aScale.getY() < 0.0);
+ double fCropLeft(mfCropLeft);
+ double fCropTop(mfCropTop);
+ double fCropRight(mfCropRight);
+ double fCropBottom(mfCropBottom);
+
+ if(bMirroredX)
+ {
+ aScale.setX(-aScale.getX());
+ }
+
+ if(bMirroredY)
+ {
+ aScale.setY(-aScale.getY());
+ }
+
+ // create target translate and scale
+ const basegfx::B2DVector aTargetScale(
+ aScale.getX() + fCropRight + fCropLeft,
+ aScale.getY() + fCropBottom + fCropTop);
+ const basegfx::B2DVector aTargetTranslate(
+ aTranslate.getX() - fCropLeft,
+ aTranslate.getY() - fCropTop);
+
+ // create ranges to make comparisons
+ const basegfx::B2DRange aCurrentForCompare(
+ aTranslate.getX(), aTranslate.getY(),
+ aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
+ basegfx::B2DRange aCropped(
+ aTargetTranslate.getX(), aTargetTranslate.getY(),
+ aTargetTranslate.getX() + aTargetScale.getX(), aTargetTranslate.getY() + aTargetScale.getY());
+
+ if(aCropped.isEmpty())
+ {
+ // nothing to return since cropped content is completely empty
+ return;
+ }
+
+ if(aCurrentForCompare.equal(aCropped))
+ {
+ // no crop at all
+ return;
+ }
+
+ // back-transform to have values in unit coordinates
+ basegfx::B2DHomMatrix aBackToUnit;
+ aBackToUnit.translate(-aTranslate.getX(), -aTranslate.getY());
+ aBackToUnit.scale(
+ basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : 1.0 / aScale.getX(),
+ basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : 1.0 / aScale.getY());
+
+ // transform cropped back to unit coordinates
+ aCropped.transform(aBackToUnit);
+
+ // prepare crop PolyPolygon
+ basegfx::B2DPolygon aGraphicOutlinePolygon(
+ basegfx::utils::createPolygonFromRect(
+ aCropped));
+ basegfx::B2DPolyPolygon aCropPolyPolygon(aGraphicOutlinePolygon);
+
+ // current range is unit range
+ basegfx::B2DRange aOverlap(0.0, 0.0, 1.0, 1.0);
+
+ aOverlap.intersect(aCropped);
+
+ if(!aOverlap.isEmpty())
+ {
+ aCropPolyPolygon.append(
+ basegfx::utils::createPolygonFromRect(
+ aOverlap));
+ }
+
+ // transform to object coordinates to prepare for clip
+ aCropPolyPolygon.transform(maObjectTransform);
+ aGraphicOutlinePolygon.transform(maObjectTransform);
+
+ // create cropped transformation
+ basegfx::B2DHomMatrix aCroppedTransform;
+
+ aCroppedTransform.scale(
+ aCropped.getWidth(),
+ aCropped.getHeight());
+ aCroppedTransform.translate(
+ aCropped.getMinX(),
+ aCropped.getMinY());
+ aCroppedTransform = maObjectTransform * aCroppedTransform;
+
+ // prepare graphic primitive (transformed)
+ const drawinglayer::primitive2d::Primitive2DReference aGraphic(
+ new drawinglayer::primitive2d::GraphicPrimitive2D(
+ aCroppedTransform,
+ maGraphic));
+
+ // prepare outline polygon for whole graphic
+ const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor());
+ const drawinglayer::primitive2d::Primitive2DReference aGraphicOutline(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ aGraphicOutlinePolygon,
+ aHilightColor));
+
+ // combine these
+ drawinglayer::primitive2d::Primitive2DContainer aCombination(2);
+ aCombination[0] = aGraphic;
+ aCombination[1] = aGraphicOutline;
+
+ // embed to MaskPrimitive2D
+ const drawinglayer::primitive2d::Primitive2DReference aMaskedGraphic(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ aCropPolyPolygon,
+ std::move(aCombination)));
+
+ // embed to UnifiedTransparencePrimitive2D
+ const drawinglayer::primitive2d::Primitive2DReference aTransparenceMaskedGraphic(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ drawinglayer::primitive2d::Primitive2DContainer { aMaskedGraphic },
+ 0.8));
+
+ const drawinglayer::primitive2d::Primitive2DContainer aSequence { aTransparenceMaskedGraphic };
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
+ const SdrPageWindow& rPageWindow = *(pPageView->GetPageWindow(b));
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if(xManager.is())
+ {
+ std::unique_ptr<sdr::overlay::OverlayObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(drawinglayer::primitive2d::Primitive2DContainer(aSequence)));
+
+ // only informative object, no hit
+ pNew->setHittable(false);
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pNew),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdhlpln.cxx b/svx/source/svdraw/svdhlpln.cxx
new file mode 100644
index 000000000..0d515191e
--- /dev/null
+++ b/svx/source/svdraw/svdhlpln.cxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdhlpln.hxx>
+
+#include <vcl/outdev.hxx>
+#include <vcl/ptrstyle.hxx>
+
+
+PointerStyle SdrHelpLine::GetPointer() const
+{
+ switch (eKind) {
+ case SdrHelpLineKind::Vertical : return PointerStyle::ESize;
+ case SdrHelpLineKind::Horizontal: return PointerStyle::SSize;
+ default : return PointerStyle::Move;
+ } // switch
+}
+
+bool SdrHelpLine::IsHit(const Point& rPnt, sal_uInt16 nTolLog, const OutputDevice& rOut) const
+{
+ Size a1Pix(rOut.PixelToLogic(Size(1,1)));
+ bool bXHit=rPnt.X()>=aPos.X()-nTolLog && rPnt.X()<=aPos.X()+nTolLog+a1Pix.Width();
+ bool bYHit=rPnt.Y()>=aPos.Y()-nTolLog && rPnt.Y()<=aPos.Y()+nTolLog+a1Pix.Height();
+ switch (eKind) {
+ case SdrHelpLineKind::Vertical : return bXHit;
+ case SdrHelpLineKind::Horizontal: return bYHit;
+ case SdrHelpLineKind::Point: {
+ if (bXHit || bYHit) {
+ Size aRad(rOut.PixelToLogic(Size(SDRHELPLINE_POINT_PIXELSIZE,SDRHELPLINE_POINT_PIXELSIZE)));
+ return rPnt.X()>=aPos.X()-aRad.Width() && rPnt.X()<=aPos.X()+aRad.Width()+a1Pix.Width() &&
+ rPnt.Y()>=aPos.Y()-aRad.Height() && rPnt.Y()<=aPos.Y()+aRad.Height()+a1Pix.Height();
+ }
+ } break;
+ } // switch
+ return false;
+}
+
+tools::Rectangle SdrHelpLine::GetBoundRect(const OutputDevice& rOut) const
+{
+ tools::Rectangle aRet(aPos,aPos);
+ Point aOfs(rOut.GetMapMode().GetOrigin());
+ Size aSiz(rOut.GetOutputSize());
+ switch (eKind) {
+ case SdrHelpLineKind::Vertical : aRet.SetTop(-aOfs.Y() ); aRet.SetBottom(-aOfs.Y()+aSiz.Height() ); break;
+ case SdrHelpLineKind::Horizontal: aRet.SetLeft(-aOfs.X() ); aRet.SetRight(-aOfs.X()+aSiz.Width() ); break;
+ case SdrHelpLineKind::Point : {
+ Size aRad(rOut.PixelToLogic(Size(SDRHELPLINE_POINT_PIXELSIZE,SDRHELPLINE_POINT_PIXELSIZE)));
+ aRet.AdjustLeft( -(aRad.Width()) );
+ aRet.AdjustRight(aRad.Width() );
+ aRet.AdjustTop( -(aRad.Height()) );
+ aRet.AdjustBottom(aRad.Height() );
+ } break;
+ } // switch
+ return aRet;
+}
+
+SdrHelpLineList& SdrHelpLineList::operator=(const SdrHelpLineList& rSrcList)
+{
+ aList.clear();
+ sal_uInt16 nCount=rSrcList.GetCount();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ Insert(rSrcList[i]);
+ }
+ return *this;
+}
+
+bool SdrHelpLineList::operator==(const SdrHelpLineList& rSrcList) const
+{
+ bool bEqual = false;
+ sal_uInt16 nCount=GetCount();
+ if (nCount==rSrcList.GetCount()) {
+ bEqual = true;
+ for (sal_uInt16 i=0; i<nCount && bEqual; i++) {
+ if (*aList[i]!=*rSrcList.aList[i]) {
+ bEqual = false;
+ }
+ }
+ }
+ return bEqual;
+}
+
+sal_uInt16 SdrHelpLineList::HitTest(const Point& rPnt, sal_uInt16 nTolLog, const OutputDevice& rOut) const
+{
+ sal_uInt16 nCount=GetCount();
+ for (sal_uInt16 i=nCount; i>0;) {
+ i--;
+ if (aList[i]->IsHit(rPnt,nTolLog,rOut)) return i;
+ }
+ return SDRHELPLINE_NOTFOUND;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svditer.cxx b/svx/source/svdraw/svditer.cxx
new file mode 100644
index 000000000..eaca2b335
--- /dev/null
+++ b/svx/source/svdraw/svditer.cxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svditer.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdmark.hxx>
+#include <osl/diagnose.h>
+
+SdrObjListIter::SdrObjListIter(const SdrObjList* pObjList, SdrIterMode eMode, bool bReverse)
+: mnIndex(0),
+ mbReverse(bReverse),
+ mbUseZOrder(true)
+{
+ if(nullptr != pObjList)
+ {
+ ImpProcessObjectList(*pObjList, eMode);
+ }
+
+ Reset();
+}
+
+SdrObjListIter::SdrObjListIter(const SdrObjList* pObjList, bool bUseZOrder, SdrIterMode eMode, bool bReverse)
+: mnIndex(0),
+ mbReverse(bReverse),
+ mbUseZOrder(bUseZOrder)
+{
+ if(nullptr != pObjList)
+ {
+ // correct when we have no ObjectNavigationOrder
+ if(!mbUseZOrder && !pObjList->HasObjectNavigationOrder())
+ {
+ mbUseZOrder = false;
+ }
+
+ ImpProcessObjectList(*pObjList, eMode);
+ }
+
+ Reset();
+}
+
+SdrObjListIter::SdrObjListIter(const SdrObject& rSdrObject, SdrIterMode eMode, bool bReverse)
+: mnIndex(0),
+ mbReverse(bReverse),
+ mbUseZOrder(true)
+{
+ ImpProcessObj(rSdrObject, eMode);
+ Reset();
+}
+
+SdrObjListIter::SdrObjListIter(const SdrPage* pSdrPage, SdrIterMode eMode, bool bReverse)
+: mnIndex(0),
+ mbReverse(bReverse),
+ mbUseZOrder(true)
+{
+ if (pSdrPage)
+ ImpProcessObjectList(*pSdrPage, eMode);
+ Reset();
+}
+
+SdrObjListIter::SdrObjListIter( const SdrMarkList& rMarkList, SdrIterMode eMode )
+: mnIndex(0),
+ mbReverse(false),
+ mbUseZOrder(true)
+{
+ ImpProcessMarkList(rMarkList, eMode);
+ Reset();
+}
+
+void SdrObjListIter::ImpProcessObjectList(const SdrObjList& rObjList, SdrIterMode eMode)
+{
+ for(size_t nIdx(0), nCount(rObjList.GetObjCount()); nIdx < nCount; ++nIdx)
+ {
+ const SdrObject* pSdrObject(mbUseZOrder
+ ? rObjList.GetObj(nIdx)
+ : rObjList.GetObjectForNavigationPosition(nIdx));
+
+ if(nullptr == pSdrObject)
+ {
+ OSL_ENSURE(false, "SdrObjListIter: corrupted SdrObjList (!)");
+ }
+ else
+ {
+ ImpProcessObj(*pSdrObject, eMode);
+ }
+ }
+}
+
+void SdrObjListIter::ImpProcessMarkList(const SdrMarkList& rMarkList, SdrIterMode eMode)
+{
+ for( size_t nIdx = 0, nCount = rMarkList.GetMarkCount(); nIdx < nCount; ++nIdx )
+ {
+ if( SdrObject* pObj = rMarkList.GetMark( nIdx )->GetMarkedSdrObj() )
+ {
+ ImpProcessObj(*pObj, eMode);
+ }
+ }
+}
+
+void SdrObjListIter::ImpProcessObj(const SdrObject& rSdrObject, SdrIterMode eMode)
+{
+ // TTTT: Note: The behaviour has changed here, it will now deep-iterate
+ // for SdrObjGroup and E3dScene. Old version only deep-dived for SdrObjGroup,
+ // E3dScene was just added flat. This is now more correct, but potentially
+ // there will exist code in the 3D area that *self-iterates* with local
+ // functions/methods due to this iterator was not doing the expected thing.
+ // These will be difficult to find, but in most cases should do no harm,
+ // but cost runtime. Will need to have an eye on this aspect on continued
+ // changes...
+ const SdrObjList* pChildren(rSdrObject.getChildrenOfSdrObject());
+ const bool bIsGroup(nullptr != pChildren);
+
+ if(!bIsGroup || (SdrIterMode::DeepNoGroups != eMode))
+ {
+ maObjList.push_back(&rSdrObject);
+ }
+
+ if(bIsGroup && (SdrIterMode::Flat != eMode))
+ {
+ ImpProcessObjectList(*pChildren, eMode);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdlayer.cxx b/svx/source/svdraw/svdlayer.cxx
new file mode 100644
index 000000000..3146d62f7
--- /dev/null
+++ b/svx/source/svdraw/svdlayer.cxx
@@ -0,0 +1,361 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <svx/svdlayer.hxx>
+#include <svx/svdmodel.hxx>
+
+#include <algorithm>
+
+bool SdrLayerIDSet::IsEmpty() const
+{
+ for(sal_uInt8 i : aData)
+ {
+ if(i != 0)
+ return false;
+ }
+
+ return true;
+}
+
+void SdrLayerIDSet::operator&=(const SdrLayerIDSet& r2ndSet)
+{
+ for(sal_uInt16 i(0); i < 32; i++)
+ {
+ aData[i] &= r2ndSet.aData[i];
+ }
+}
+
+/** initialize this set with a UNO sequence of sal_Int8 (e.g. as stored in settings.xml)
+*/
+void SdrLayerIDSet::PutValue( const css::uno::Any & rAny )
+{
+ css::uno::Sequence< sal_Int8 > aSeq;
+ if( !(rAny >>= aSeq) )
+ return;
+
+ sal_Int16 nCount = static_cast<sal_Int16>(aSeq.getLength());
+ if( nCount > 32 )
+ nCount = 32;
+
+ sal_Int16 nIndex;
+ for( nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ aData[nIndex] = static_cast<sal_uInt8>(aSeq[nIndex]);
+ }
+
+ for( ; nIndex < 32; nIndex++ )
+ {
+ aData[nIndex] = 0;
+ }
+}
+
+SdrLayer::SdrLayer(SdrLayerID nNewID, const OUString& rNewName) :
+ maName(rNewName), pModel(nullptr), nID(nNewID)
+{
+ // ODF default values
+ mbVisibleODF = true;
+ mbPrintableODF = true;
+ mbLockedODF = false;
+}
+
+void SdrLayer::SetName(const OUString& rNewName)
+{
+ if (rNewName == maName)
+ return;
+
+ maName = rNewName;
+
+ if (pModel)
+ {
+ SdrHint aHint(SdrHintKind::LayerChange);
+ pModel->Broadcast(aHint);
+ pModel->SetChanged();
+ }
+}
+
+bool SdrLayer::operator==(const SdrLayer& rCmpLayer) const
+{
+ return (nID == rCmpLayer.nID
+ && maName == rCmpLayer.maName);
+}
+
+SdrLayerAdmin::SdrLayerAdmin(SdrLayerAdmin* pNewParent):
+ pParent(pNewParent),
+ pModel(nullptr),
+ maControlLayerName("controls")
+{
+}
+
+SdrLayerAdmin::SdrLayerAdmin(const SdrLayerAdmin& rSrcLayerAdmin):
+ pParent(nullptr),
+ pModel(nullptr),
+ maControlLayerName("controls")
+{
+ *this = rSrcLayerAdmin;
+}
+
+SdrLayerAdmin::~SdrLayerAdmin()
+{
+}
+
+void SdrLayerAdmin::ClearLayers()
+{
+ maLayers.clear();
+}
+
+SdrLayerAdmin& SdrLayerAdmin::operator=(const SdrLayerAdmin& rSrcLayerAdmin)
+{
+ if (this != &rSrcLayerAdmin)
+ {
+ maLayers.clear();
+ pParent=rSrcLayerAdmin.pParent;
+ sal_uInt16 i;
+ sal_uInt16 nCount=rSrcLayerAdmin.GetLayerCount();
+ for (i=0; i<nCount; i++) {
+ maLayers.emplace_back(new SdrLayer(*rSrcLayerAdmin.GetLayer(i)));
+ }
+ }
+ return *this;
+}
+
+void SdrLayerAdmin::SetModel(SdrModel* pNewModelel)
+{
+ if (pNewModelel!=pModel) {
+ pModel=pNewModelel;
+ sal_uInt16 nCount=GetLayerCount();
+ sal_uInt16 i;
+ for (i=0; i<nCount; i++) {
+ GetLayer(i)->SetModel(pNewModelel);
+ }
+ }
+}
+
+void SdrLayerAdmin::Broadcast() const
+{
+ if (pModel!=nullptr) {
+ SdrHint aHint(SdrHintKind::LayerOrderChange);
+ pModel->Broadcast(aHint);
+ pModel->SetChanged();
+ }
+}
+
+void SdrLayerAdmin::InsertLayer(std::unique_ptr<SdrLayer> pLayer, sal_uInt16 nPos)
+{
+ pLayer->SetModel(pModel);
+ if(nPos==0xFFFF)
+ maLayers.push_back(std::move(pLayer));
+ else
+ maLayers.insert(maLayers.begin() + nPos, std::move(pLayer));
+ Broadcast();
+}
+
+std::unique_ptr<SdrLayer> SdrLayerAdmin::RemoveLayer(sal_uInt16 nPos)
+{
+ std::unique_ptr<SdrLayer> pRetLayer = std::move(maLayers[nPos]);
+ maLayers.erase(maLayers.begin()+nPos);
+ Broadcast();
+ return pRetLayer;
+}
+
+SdrLayer* SdrLayerAdmin::NewLayer(const OUString& rName, sal_uInt16 nPos)
+{
+ SdrLayerID nID=GetUniqueLayerID();
+ SdrLayer* pLay=new SdrLayer(nID,rName);
+ pLay->SetModel(pModel);
+ if(nPos==0xFFFF)
+ maLayers.push_back(std::unique_ptr<SdrLayer>(pLay));
+ else
+ maLayers.insert(maLayers.begin() + nPos, std::unique_ptr<SdrLayer>(pLay));
+ Broadcast();
+ return pLay;
+}
+
+sal_uInt16 SdrLayerAdmin::GetLayerPos(const SdrLayer* pLayer) const
+{
+ sal_uInt16 nRet=SDRLAYERPOS_NOTFOUND;
+ if (pLayer!=nullptr) {
+ auto it = std::find_if(maLayers.begin(), maLayers.end(),
+ [&](const std::unique_ptr<SdrLayer> & p) { return p.get() == pLayer; });
+ if (it!=maLayers.end()) {
+ nRet=it - maLayers.begin();
+ }
+ }
+ return nRet;
+}
+
+SdrLayer* SdrLayerAdmin::GetLayer(const OUString& rName)
+{
+ return const_cast<SdrLayer*>(const_cast<const SdrLayerAdmin*>(this)->GetLayer(rName));
+}
+
+const SdrLayer* SdrLayerAdmin::GetLayer(const OUString& rName) const
+{
+ sal_uInt16 i(0);
+ const SdrLayer* pLay = nullptr;
+
+ while(i < GetLayerCount() && !pLay)
+ {
+ if (rName == GetLayer(i)->GetName())
+ pLay = GetLayer(i);
+ else
+ i++;
+ }
+
+ if(!pLay && pParent)
+ {
+ pLay = pParent->GetLayer(rName);
+ }
+
+ return pLay;
+}
+
+SdrLayerID SdrLayerAdmin::GetLayerID(const OUString& rName) const
+{
+ SdrLayerID nRet=SDRLAYER_NOTFOUND;
+ const SdrLayer* pLay=GetLayer(rName);
+ if (pLay!=nullptr) nRet=pLay->GetID();
+ return nRet;
+}
+
+const SdrLayer* SdrLayerAdmin::GetLayerPerID(SdrLayerID nID) const
+{
+ for (auto const & pLayer : maLayers)
+ if (pLayer->GetID() == nID)
+ return pLayer.get();
+ return nullptr;
+}
+
+// Global LayerIDs begin at 0 and increase,
+// local LayerIDs begin at 254 and decrease;
+// 255 is reserved for SDRLAYER_NOTFOUND.
+
+SdrLayerID SdrLayerAdmin::GetUniqueLayerID() const
+{
+ SdrLayerIDSet aSet;
+ for (sal_uInt16 j=0; j<GetLayerCount(); j++)
+ {
+ aSet.Set(GetLayer(j)->GetID());
+ }
+ sal_uInt8 i;
+ if (pParent != nullptr)
+ {
+ i = 254;
+ while (i && aSet.IsSet(SdrLayerID(i)))
+ --i;
+ assert(i != 0);
+ if (i == 0)
+ i = 254;
+ }
+ else
+ {
+ i = 0;
+ while (i<=254 && aSet.IsSet(SdrLayerID(i)))
+ i++;
+ assert(i <= 254);
+ if (i>254)
+ i = 0;
+ }
+ return SdrLayerID(i);
+}
+
+void SdrLayerAdmin::SetControlLayerName(const OUString& rNewName)
+{
+ maControlLayerName = rNewName;
+}
+
+void SdrLayerAdmin::getVisibleLayersODF( SdrLayerIDSet& rOutSet) const
+{
+ rOutSet.ClearAll();
+ for( auto & pCurrentLayer : maLayers )
+ {
+ if ( pCurrentLayer->IsVisibleODF() )
+ rOutSet.Set( pCurrentLayer->GetID() );
+ }
+}
+
+void SdrLayerAdmin::getPrintableLayersODF( SdrLayerIDSet& rOutSet) const
+{
+ rOutSet.ClearAll();
+ for( auto & pCurrentLayer : maLayers )
+ {
+ if ( pCurrentLayer->IsPrintableODF() )
+ rOutSet.Set( pCurrentLayer->GetID() );
+ }
+}
+
+void SdrLayerAdmin::getLockedLayersODF( SdrLayerIDSet& rOutSet) const
+{
+ rOutSet.ClearAll();
+ for( auto& pCurrentLayer : maLayers )
+ {
+ if ( pCurrentLayer->IsLockedODF() )
+ rOutSet.Set( pCurrentLayer->GetID() );
+ }
+}
+
+ // Generates a bitfield for settings.xml from the SdrLayerIDSet.
+ // Output is a UNO sequence of BYTE (which is 'short' in API).
+void SdrLayerAdmin::QueryValue(const SdrLayerIDSet& rViewLayerSet, css::uno::Any& rAny)
+{
+ // tdf#119392 The SdrLayerIDSet in a view is ordered according LayerID, but in file
+ // the bitfield is interpreted in order of layers in <draw:layer-set>.
+ // First generate a new bitfield based on rViewLayerSet in the needed order.
+ sal_uInt8 aTmp[32]; // 256 bits in settings.xml makes byte 0 to 31
+ for (auto nIndex = 0; nIndex <32; nIndex++)
+ {
+ aTmp[nIndex] = 0;
+ }
+ sal_uInt8 nByteIndex = 0;
+ sal_uInt8 nBitpos = 0;
+ sal_uInt16 nLayerPos = 0; // Position of the layer in member aLayer and in <draw:layer-set> in file
+ sal_uInt16 nLayerIndex = 0;
+ for( const auto& pCurrentLayer : maLayers )
+ {
+ SdrLayerID nCurrentID = pCurrentLayer->GetID();
+ if ( rViewLayerSet.IsSet(nCurrentID) )
+ {
+ nLayerPos = nLayerIndex;
+ nByteIndex = nLayerPos / 8;
+ if (nByteIndex > 31)
+ continue; // skip position, if too large for bitfield
+ nBitpos = nLayerPos % 8;
+ aTmp[nByteIndex] |= (1 << nBitpos);
+ }
+ ++nLayerIndex;
+ }
+
+ // Second transform the bitfield to byte sequence, same as in previous version of QueryValue
+ sal_uInt8 nNumBytesSet = 0;
+ for( auto nIndex = 31; nIndex >= 0; nIndex--)
+ {
+ if( 0 != aTmp[nIndex] )
+ {
+ nNumBytesSet = nIndex + 1;
+ break;
+ }
+ }
+ css::uno::Sequence< sal_Int8 > aSeq( nNumBytesSet );
+ std::transform(aTmp, aTmp + nNumBytesSet, aSeq.getArray(),
+ [](const sal_uInt8 b) { return static_cast<sal_Int8>(b); });
+ rAny <<= aSeq;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdmark.cxx b/svx/source/svdraw/svdmark.cxx
new file mode 100644
index 000000000..e3c77bda1
--- /dev/null
+++ b/svx/source/svdraw/svdmark.cxx
@@ -0,0 +1,791 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <osl/time.h>
+#include <svx/svdmark.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+#include <svl/SfxBroadcaster.hxx>
+#include <svx/svdoedge.hxx>
+#include <osl/diagnose.h>
+
+#include <cassert>
+
+void SdrMark::setTime()
+{
+ TimeValue aNow;
+ osl_getSystemTime(&aNow);
+ mnTimeStamp = sal_Int64(aNow.Seconds) * 1000000000 + aNow.Nanosec;
+}
+
+SdrMark::SdrMark(SdrObject* pNewObj, SdrPageView* pNewPageView)
+: mpSelectedSdrObject(pNewObj),
+ mpPageView(pNewPageView),
+ mbCon1(false),
+ mbCon2(false),
+ mnUser(0)
+{
+ if(mpSelectedSdrObject)
+ {
+ mpSelectedSdrObject->AddObjectUser( *this );
+ }
+ setTime();
+}
+
+SdrMark::SdrMark(const SdrMark& rMark)
+: ObjectUser(),
+ mnTimeStamp(0),
+ mpSelectedSdrObject(nullptr),
+ mpPageView(nullptr),
+ mbCon1(false),
+ mbCon2(false),
+ mnUser(0)
+{
+ *this = rMark;
+}
+
+SdrMark::~SdrMark()
+{
+ if (mpSelectedSdrObject)
+ {
+ mpSelectedSdrObject->RemoveObjectUser( *this );
+ }
+}
+
+void SdrMark::ObjectInDestruction(const SdrObject& rObject)
+{
+ (void) rObject; // avoid warnings
+ OSL_ENSURE(mpSelectedSdrObject && mpSelectedSdrObject == &rObject, "SdrMark::ObjectInDestruction: called from object different from hosted one (!)");
+ OSL_ENSURE(mpSelectedSdrObject, "SdrMark::ObjectInDestruction: still selected SdrObject is deleted, deselect first (!)");
+ mpSelectedSdrObject = nullptr;
+}
+
+void SdrMark::SetMarkedSdrObj(SdrObject* pNewObj)
+{
+ if(mpSelectedSdrObject)
+ {
+ mpSelectedSdrObject->RemoveObjectUser( *this );
+ }
+
+ mpSelectedSdrObject = pNewObj;
+
+ if(mpSelectedSdrObject)
+ {
+ mpSelectedSdrObject->AddObjectUser( *this );
+ }
+}
+
+SdrMark& SdrMark::operator=(const SdrMark& rMark)
+{
+ SetMarkedSdrObj(rMark.mpSelectedSdrObject);
+
+ mnTimeStamp = rMark.mnTimeStamp;
+ mpPageView = rMark.mpPageView;
+ mbCon1 = rMark.mbCon1;
+ mbCon2 = rMark.mbCon2;
+ mnUser = rMark.mnUser;
+ maPoints = rMark.maPoints;
+ maGluePoints = rMark.maGluePoints;
+
+ return *this;
+}
+
+static bool ImpSdrMarkListSorter(std::unique_ptr<SdrMark> const& lhs, std::unique_ptr<SdrMark> const& rhs)
+{
+ SdrObject* pObj1 = lhs->GetMarkedSdrObj();
+ SdrObject* pObj2 = rhs->GetMarkedSdrObj();
+ SdrObjList* pOL1 = pObj1 ? pObj1->getParentSdrObjListFromSdrObject() : nullptr;
+ SdrObjList* pOL2 = pObj2 ? pObj2->getParentSdrObjListFromSdrObject() : nullptr;
+
+ if (pOL1 == pOL2)
+ {
+ // AF: Note that I reverted a change from sal_uInt32 to sal_uLong (made
+ // for 64bit compliance, #i78198#) because internally in SdrObject
+ // both nOrdNum and mnNavigationPosition are stored as sal_uInt32.
+ sal_uInt32 nObjOrd1(pObj1 ? pObj1->GetNavigationPosition() : 0);
+ sal_uInt32 nObjOrd2(pObj2 ? pObj2->GetNavigationPosition() : 0);
+
+ return nObjOrd1 < nObjOrd2;
+ }
+ else
+ {
+ return pOL1 < pOL2;
+ }
+}
+
+
+void SdrMarkList::ForceSort() const
+{
+ if(!mbSorted)
+ {
+ const_cast<SdrMarkList*>(this)->ImpForceSort();
+ }
+}
+
+void SdrMarkList::ImpForceSort()
+{
+ if(mbSorted)
+ return;
+
+ mbSorted = true;
+ size_t nCount = maList.size();
+
+ // remove invalid
+ if(nCount > 0 )
+ {
+ maList.erase(std::remove_if(maList.begin(), maList.end(),
+ [](std::unique_ptr<SdrMark>& rItem) { return rItem->GetMarkedSdrObj() == nullptr; }),
+ maList.end());
+ nCount = maList.size();
+ }
+
+ if(nCount <= 1)
+ return;
+
+ std::sort(maList.begin(), maList.end(), ImpSdrMarkListSorter);
+
+ // remove duplicates
+ if(maList.size() <= 1)
+ return;
+
+ SdrMark* pCurrent = maList.back().get();
+ for (size_t count = maList.size() - 1; count; --count)
+ {
+ size_t i = count - 1;
+ SdrMark* pCmp = maList[i].get();
+ assert(pCurrent->GetMarkedSdrObj());
+ if(pCurrent->GetMarkedSdrObj() == pCmp->GetMarkedSdrObj())
+ {
+ // Con1/Con2 Merging
+ if(pCmp->IsCon1())
+ pCurrent->SetCon1(true);
+
+ if(pCmp->IsCon2())
+ pCurrent->SetCon2(true);
+
+ // delete pCmp
+ maList.erase(maList.begin() + i);
+ }
+ else
+ {
+ pCurrent = pCmp;
+ }
+ }
+}
+
+void SdrMarkList::Clear()
+{
+ maList.clear();
+ mbSorted = true; //we're empty, so can be considered sorted
+ SetNameDirty();
+}
+
+SdrMarkList& SdrMarkList::operator=(const SdrMarkList& rLst)
+{
+ if (this != &rLst)
+ {
+ Clear();
+
+ for(size_t i = 0; i < rLst.GetMarkCount(); ++i)
+ {
+ SdrMark* pMark = rLst.GetMark(i);
+ maList.emplace_back(new SdrMark(*pMark));
+ }
+
+ maMarkName = rLst.maMarkName;
+ mbNameOk = rLst.mbNameOk;
+ maPointName = rLst.maPointName;
+ mbPointNameOk = rLst.mbPointNameOk;
+ maGluePointName = rLst.maGluePointName;
+ mbSorted = rLst.mbSorted;
+ }
+ return *this;
+}
+
+SdrMark* SdrMarkList::GetMark(size_t nNum) const
+{
+ return (nNum < maList.size()) ? maList[nNum].get() : nullptr;
+}
+
+size_t SdrMarkList::FindObject(const SdrObject* pObj) const
+{
+ // Since relying on OrdNums is not allowed for the selection because objects in the
+ // selection may not be inserted in a list if they are e.g. modified ATM, i changed
+ // this loop to just look if the object pointer is in the selection.
+
+ // Problem is that GetOrdNum() which is const, internally casts to non-const and
+ // hardly sets the OrdNum member of the object (nOrdNum) to 0 (ZERO) if the object
+ // is not inserted in an object list.
+ // Since this may be by purpose and necessary somewhere else i decided that it is
+ // less dangerous to change this method then changing SdrObject::GetOrdNum().
+ if(pObj)
+ {
+ for(size_t a = 0; a < maList.size(); ++a)
+ {
+ if(maList[a]->GetMarkedSdrObj() == pObj)
+ {
+ return a;
+ }
+ }
+ }
+
+ return SAL_MAX_SIZE;
+}
+
+void SdrMarkList::InsertEntry(const SdrMark& rMark, bool bChkSort)
+{
+ SetNameDirty();
+ const size_t nCount(maList.size());
+
+ if(!bChkSort || !mbSorted || nCount == 0)
+ {
+ if(!bChkSort)
+ mbSorted = false;
+
+ maList.emplace_back(new SdrMark(rMark));
+ }
+ else
+ {
+ SdrMark* pLast = GetMark(nCount - 1);
+ const SdrObject* pLastObj = pLast->GetMarkedSdrObj();
+ const SdrObject* pNewObj = rMark.GetMarkedSdrObj();
+
+ if(pLastObj == pNewObj)
+ {
+ // This one already exists.
+ // Con1/Con2 Merging
+ if(rMark.IsCon1())
+ pLast->SetCon1(true);
+
+ if(rMark.IsCon2())
+ pLast->SetCon2(true);
+ }
+ else
+ {
+ maList.emplace_back(new SdrMark(rMark));
+
+ // now check if the sort is ok
+ const SdrObjList* pLastOL = pLastObj!=nullptr ? pLastObj->getParentSdrObjListFromSdrObject() : nullptr;
+ const SdrObjList* pNewOL = pNewObj !=nullptr ? pNewObj->getParentSdrObjListFromSdrObject() : nullptr;
+
+ if(pLastOL == pNewOL)
+ {
+ const sal_uLong nLastNum(pLastObj!=nullptr ? pLastObj->GetOrdNum() : 0);
+ const sal_uLong nNewNum(pNewObj !=nullptr ? pNewObj ->GetOrdNum() : 0);
+
+ if(nNewNum < nLastNum)
+ {
+ // at some point, we have to sort
+ mbSorted = false;
+ }
+ }
+ else
+ {
+ // at some point, we have to sort
+ mbSorted = false;
+ }
+ }
+ }
+}
+
+void SdrMarkList::DeleteMark(size_t nNum)
+{
+ SdrMark* pMark = GetMark(nNum);
+ DBG_ASSERT(pMark!=nullptr,"DeleteMark: MarkEntry not found.");
+
+ if(pMark)
+ {
+ maList.erase(maList.begin() + nNum);
+ if (maList.empty())
+ mbSorted = true; //we're empty, so can be considered sorted
+ SetNameDirty();
+ }
+}
+
+void SdrMarkList::ReplaceMark(const SdrMark& rNewMark, size_t nNum)
+{
+ SdrMark* pMark = GetMark(nNum);
+ DBG_ASSERT(pMark!=nullptr,"ReplaceMark: MarkEntry not found.");
+
+ if(pMark)
+ {
+ SetNameDirty();
+ maList[nNum].reset(new SdrMark(rNewMark));
+ mbSorted = false;
+ }
+}
+
+void SdrMarkList::Merge(const SdrMarkList& rSrcList, bool bReverse)
+{
+ const size_t nCount(rSrcList.maList.size());
+
+ if(rSrcList.mbSorted)
+ {
+ // merge without forcing a Sort in rSrcList
+ bReverse = false;
+ }
+
+ if(!bReverse)
+ {
+ for(size_t i = 0; i < nCount; ++i)
+ {
+ SdrMark* pM = rSrcList.maList[i].get();
+ InsertEntry(*pM);
+ }
+ }
+ else
+ {
+ for(size_t i = nCount; i > 0;)
+ {
+ --i;
+ SdrMark* pM = rSrcList.maList[i].get();
+ InsertEntry(*pM);
+ }
+ }
+}
+
+bool SdrMarkList::DeletePageView(const SdrPageView& rPV)
+{
+ bool bChgd(false);
+
+ for(auto it = maList.begin(); it != maList.end(); )
+ {
+ SdrMark* pMark = it->get();
+
+ if(pMark->GetPageView()==&rPV)
+ {
+ it = maList.erase(it);
+ SetNameDirty();
+ bChgd = true;
+ }
+ else
+ ++it;
+ }
+
+ return bChgd;
+}
+
+bool SdrMarkList::InsertPageView(const SdrPageView& rPV)
+{
+ bool bChgd(false);
+ DeletePageView(rPV); // delete all of them, then append the entire page
+ const SdrObjList* pOL = rPV.GetObjList();
+ const size_t nObjCount(pOL->GetObjCount());
+
+ for(size_t nO = 0; nO < nObjCount; ++nO)
+ {
+ SdrObject* pObj = pOL->GetObj(nO);
+ bool bDoIt(rPV.IsObjMarkable(pObj));
+
+ if(bDoIt)
+ {
+ maList.emplace_back(new SdrMark(pObj, const_cast<SdrPageView*>(&rPV)));
+ SetNameDirty();
+ bChgd = true;
+ }
+ }
+
+ return bChgd;
+}
+
+const OUString& SdrMarkList::GetMarkDescription() const
+{
+ const size_t nCount(GetMarkCount());
+
+ if(mbNameOk && 1 == nCount)
+ {
+ // if it's a single selection, cache only text frame
+ const SdrObject* pObj = GetMark(0)->GetMarkedSdrObj();
+ const SdrTextObj* pTextObj = dynamic_cast<const SdrTextObj*>( pObj );
+
+ if(!pTextObj || !pTextObj->IsTextFrame())
+ {
+ const_cast<SdrMarkList*>(this)->mbNameOk = false;
+ }
+ }
+
+ if(!mbNameOk)
+ {
+ SdrMark* pMark = GetMark(0);
+ OUString aNam;
+
+ if(!nCount)
+ {
+ const_cast<SdrMarkList*>(this)->maMarkName = SvxResId(STR_ObjNameNoObj);
+ }
+ else if(1 == nCount)
+ {
+ if(pMark->GetMarkedSdrObj())
+ {
+ aNam = pMark->GetMarkedSdrObj()->TakeObjNameSingul();
+ }
+ }
+ else
+ {
+ if(pMark->GetMarkedSdrObj())
+ {
+ aNam = pMark->GetMarkedSdrObj()->TakeObjNamePlural();
+ bool bEq(true);
+
+ for(size_t i = 1; i < GetMarkCount() && bEq; ++i)
+ {
+ SdrMark* pMark2 = GetMark(i);
+ OUString aStr1(pMark2->GetMarkedSdrObj()->TakeObjNamePlural());
+ bEq = aNam == aStr1;
+ }
+
+ if(!bEq)
+ {
+ aNam = SvxResId(STR_ObjNamePlural);
+ }
+ }
+
+ aNam = OUString::number( nCount ) + " " + aNam;
+ }
+
+ const_cast<SdrMarkList*>(this)->maMarkName = aNam;
+ const_cast<SdrMarkList*>(this)->mbNameOk = true;
+ }
+
+ return maMarkName;
+}
+
+const OUString& SdrMarkList::GetPointMarkDescription(bool bGlue) const
+{
+ bool& rNameOk = const_cast<bool&>(bGlue ? mbGluePointNameOk : mbPointNameOk);
+ OUString& rName = const_cast<OUString&>(bGlue ? maGluePointName : maPointName);
+ const size_t nMarkCount(GetMarkCount());
+ size_t nMarkPtCnt(0);
+ size_t nMarkPtObjCnt(0);
+ size_t n1stMarkNum(SAL_MAX_SIZE);
+
+ for(size_t nMarkNum = 0; nMarkNum < nMarkCount; ++nMarkNum)
+ {
+ const SdrMark* pMark = GetMark(nMarkNum);
+ const SdrUShortCont& rPts = bGlue ? pMark->GetMarkedGluePoints() : pMark->GetMarkedPoints();
+
+ if (!rPts.empty())
+ {
+ if(n1stMarkNum == SAL_MAX_SIZE)
+ {
+ n1stMarkNum = nMarkNum;
+ }
+
+ nMarkPtCnt += rPts.size();
+ nMarkPtObjCnt++;
+ }
+
+ if(nMarkPtObjCnt > 1 && rNameOk)
+ {
+ // preliminary decision
+ return rName;
+ }
+ }
+
+ if(rNameOk && 1 == nMarkPtObjCnt)
+ {
+ // if it's a single selection, cache only text frame
+ const SdrObject* pObj = GetMark(0)->GetMarkedSdrObj();
+ const SdrTextObj* pTextObj = dynamic_cast<const SdrTextObj*>( pObj );
+
+ if(!pTextObj || !pTextObj->IsTextFrame())
+ {
+ rNameOk = false;
+ }
+ }
+
+ if(!nMarkPtObjCnt)
+ {
+ rName.clear();
+ rNameOk = true;
+ }
+ else if(!rNameOk)
+ {
+ const SdrMark* pMark = GetMark(n1stMarkNum);
+ OUString aNam;
+
+ if(1 == nMarkPtObjCnt)
+ {
+ if(pMark->GetMarkedSdrObj())
+ {
+ aNam = pMark->GetMarkedSdrObj()->TakeObjNameSingul();
+ }
+ }
+ else
+ {
+ if(pMark->GetMarkedSdrObj())
+ {
+ aNam = pMark->GetMarkedSdrObj()->TakeObjNamePlural();
+ }
+
+ bool bEq(true);
+
+ for(size_t i = n1stMarkNum + 1; i < GetMarkCount() && bEq; ++i)
+ {
+ const SdrMark* pMark2 = GetMark(i);
+ const SdrUShortCont& rPts = bGlue ? pMark2->GetMarkedGluePoints() : pMark2->GetMarkedPoints();
+
+ if (!rPts.empty() && pMark2->GetMarkedSdrObj())
+ {
+ OUString aStr1(pMark2->GetMarkedSdrObj()->TakeObjNamePlural());
+ bEq = aNam == aStr1;
+ }
+ }
+
+ if(!bEq)
+ {
+ aNam = SvxResId(STR_ObjNamePlural);
+ }
+
+ aNam = OUString::number( nMarkPtObjCnt ) + " " + aNam;
+ }
+
+ OUString aStr1;
+
+ if(1 == nMarkPtCnt)
+ {
+ aStr1 = SvxResId(bGlue ? STR_ViewMarkedGluePoint : STR_ViewMarkedPoint);
+ }
+ else
+ {
+ aStr1 = SvxResId(bGlue ? STR_ViewMarkedGluePoints : STR_ViewMarkedPoints);
+ aStr1 = aStr1.replaceFirst("%2", OUString::number( nMarkPtCnt ));
+ }
+
+ aStr1 = aStr1.replaceFirst("%1", aNam);
+ rName = aStr1;
+ rNameOk = true;
+ }
+
+ return rName;
+}
+
+bool SdrMarkList::TakeBoundRect(SdrPageView const * pPV, tools::Rectangle& rRect) const
+{
+ bool bFnd(false);
+ tools::Rectangle aR;
+
+ for(size_t i = 0; i < GetMarkCount(); ++i)
+ {
+ SdrMark* pMark = GetMark(i);
+
+ if(!pPV || pMark->GetPageView() == pPV)
+ {
+ if(pMark->GetMarkedSdrObj())
+ {
+ aR = pMark->GetMarkedSdrObj()->GetCurrentBoundRect();
+
+ if(bFnd)
+ {
+ rRect.Union(aR);
+ }
+ else
+ {
+ rRect = aR;
+ bFnd = true;
+ }
+ }
+ }
+ }
+
+ return bFnd;
+}
+
+bool SdrMarkList::TakeSnapRect(SdrPageView const * pPV, tools::Rectangle& rRect) const
+{
+ bool bFnd(false);
+
+ for(size_t i = 0; i < GetMarkCount(); ++i)
+ {
+ SdrMark* pMark = GetMark(i);
+
+ if(!pPV || pMark->GetPageView() == pPV)
+ {
+ if(pMark->GetMarkedSdrObj())
+ {
+ tools::Rectangle aR(pMark->GetMarkedSdrObj()->GetSnapRect());
+
+ if(bFnd)
+ {
+ rRect.Union(aR);
+ }
+ else
+ {
+ rRect = aR;
+ bFnd = true;
+ }
+ }
+ }
+ }
+
+ return bFnd;
+}
+
+
+namespace sdr
+{
+ ViewSelection::ViewSelection()
+ : mbEdgesOfMarkedNodesDirty(false)
+ {
+ }
+
+ void ViewSelection::SetEdgesOfMarkedNodesDirty()
+ {
+ if(!mbEdgesOfMarkedNodesDirty)
+ {
+ mbEdgesOfMarkedNodesDirty = true;
+ maEdgesOfMarkedNodes.Clear();
+ maMarkedEdgesOfMarkedNodes.Clear();
+ maAllMarkedObjects.clear();
+ }
+ }
+
+ const SdrMarkList& ViewSelection::GetEdgesOfMarkedNodes() const
+ {
+ if(mbEdgesOfMarkedNodesDirty)
+ {
+ const_cast<ViewSelection*>(this)->ImpForceEdgesOfMarkedNodes();
+ }
+
+ return maEdgesOfMarkedNodes;
+ }
+
+ const SdrMarkList& ViewSelection::GetMarkedEdgesOfMarkedNodes() const
+ {
+ if(mbEdgesOfMarkedNodesDirty)
+ {
+ const_cast<ViewSelection*>(this)->ImpForceEdgesOfMarkedNodes();
+ }
+
+ return maMarkedEdgesOfMarkedNodes;
+ }
+
+ const std::vector<SdrObject*>& ViewSelection::GetAllMarkedObjects() const
+ {
+ if(mbEdgesOfMarkedNodesDirty)
+ const_cast<ViewSelection*>(this)->ImpForceEdgesOfMarkedNodes();
+
+ return maAllMarkedObjects;
+ }
+
+ void ViewSelection::ImplCollectCompleteSelection(SdrObject* pObj)
+ {
+ if(!pObj)
+ return;
+
+ bool bIsGroup(pObj->IsGroupObject());
+
+ if(bIsGroup && dynamic_cast< const E3dObject* >(pObj) != nullptr && dynamic_cast< const E3dScene* >(pObj) == nullptr)
+ {
+ bIsGroup = false;
+ }
+
+ if(bIsGroup)
+ {
+ SdrObjList* pList = pObj->GetSubList();
+
+ for(size_t a = 0; a < pList->GetObjCount(); ++a)
+ {
+ SdrObject* pObj2 = pList->GetObj(a);
+ ImplCollectCompleteSelection(pObj2);
+ }
+ }
+
+ maAllMarkedObjects.push_back(pObj);
+ }
+
+ void ViewSelection::ImpForceEdgesOfMarkedNodes()
+ {
+ if(!mbEdgesOfMarkedNodesDirty)
+ return;
+
+ mbEdgesOfMarkedNodesDirty = false;
+ maMarkedObjectList.ForceSort();
+ maEdgesOfMarkedNodes.Clear();
+ maMarkedEdgesOfMarkedNodes.Clear();
+ maAllMarkedObjects.clear();
+
+ // GetMarkCount after ForceSort
+ const size_t nMarkCount(maMarkedObjectList.GetMarkCount());
+
+ for(size_t a = 0; a < nMarkCount; ++a)
+ {
+ SdrObject* pCandidate = maMarkedObjectList.GetMark(a)->GetMarkedSdrObj();
+
+ if(pCandidate)
+ {
+ // build transitive hull
+ ImplCollectCompleteSelection(pCandidate);
+
+ // travel over broadcaster/listener to access edges connected to the selected object
+ const SfxBroadcaster* pBC = pCandidate->GetBroadcaster();
+
+ if(pBC)
+ {
+ const size_t nLstCnt(pBC->GetSizeOfVector());
+
+ for(size_t nl=0; nl < nLstCnt; ++nl)
+ {
+ SfxListener* pLst = pBC->GetListener(nl);
+ SdrEdgeObj* pEdge = dynamic_cast<SdrEdgeObj*>( pLst );
+
+ if(pEdge && pEdge->IsInserted() && pEdge->getSdrPageFromSdrObject() == pCandidate->getSdrPageFromSdrObject())
+ {
+ SdrMark aM(pEdge, maMarkedObjectList.GetMark(a)->GetPageView());
+
+ if(pEdge->GetConnectedNode(true) == pCandidate)
+ {
+ aM.SetCon1(true);
+ }
+
+ if(pEdge->GetConnectedNode(false) == pCandidate)
+ {
+ aM.SetCon2(true);
+ }
+
+ if(SAL_MAX_SIZE == maMarkedObjectList.FindObject(pEdge))
+ {
+ // check if it itself is selected
+ maEdgesOfMarkedNodes.InsertEntry(aM);
+ }
+ else
+ {
+ maMarkedEdgesOfMarkedNodes.InsertEntry(aM);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ maEdgesOfMarkedNodes.ForceSort();
+ maMarkedEdgesOfMarkedNodes.ForceSort();
+ }
+} // end of namespace sdr
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdmodel.cxx b/svx/source/svdraw/svdmodel.cxx
new file mode 100644
index 000000000..acf05bd94
--- /dev/null
+++ b/svx/source/svdraw/svdmodel.cxx
@@ -0,0 +1,1941 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdmodel.hxx>
+#include <cassert>
+#include <math.h>
+#include <sal/log.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <unotools/configmgr.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svl/whiter.hxx>
+#include <svl/asiancfg.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xlnstit.hxx>
+#include <editeng/editeng.hxx>
+#include <svx/xtable.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdlayer.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdotext.hxx>
+#include <textchain.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svdoutlinercache.hxx>
+#include <svx/sdasitm.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <svl/style.hxx>
+#include <editeng/forbiddencharacterstable.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <editeng/eeitem.hxx>
+#include <svl/itemset.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <memory>
+#include <libxml/xmlwriter.h>
+#include <sfx2/viewsh.hxx>
+#include <o3tl/enumrange.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/UnitConversion.hxx>
+#include <svx/ColorSets.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+
+struct SdrModelImpl
+{
+ SfxUndoManager* mpUndoManager;
+ SdrUndoFactory* mpUndoFactory;
+ bool mbAnchoredTextOverflowLegacy; // tdf#99729 compatibility flag
+ std::unique_ptr<svx::Theme> mpTheme;
+
+ SdrModelImpl()
+ : mpUndoManager(nullptr)
+ , mpUndoFactory(nullptr)
+ , mbAnchoredTextOverflowLegacy(false)
+ {}
+};
+
+
+SdrModel::SdrModel(SfxItemPool* pPool, comphelper::IEmbeddedHelper* pEmbeddedHelper, bool bDisablePropertyFiles)
+ : m_aObjUnit(SdrEngineDefaults::GetMapFraction())
+ , m_eObjUnit(SdrEngineDefaults::GetMapUnit())
+ , m_eUIUnit(FieldUnit::MM)
+ , m_aUIScale(Fraction(1,1))
+ , m_nUIUnitDecimalMark(0)
+ , m_pLayerAdmin(new SdrLayerAdmin)
+ , m_pItemPool(pPool)
+ , m_pEmbeddedHelper(pEmbeddedHelper)
+ , mnDefTextHgt(SdrEngineDefaults::GetFontHeight())
+ , m_pRefOutDev(nullptr)
+ , m_pDefaultStyleSheet(nullptr)
+ , mpDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj(nullptr)
+ , m_pLinkManager(nullptr)
+ , m_nUndoLevel(0)
+ , m_bIsWriter(true)
+ , mbUndoEnabled(true)
+ , mbChanged(false)
+ , m_bPagNumsDirty(false)
+ , m_bMPgNumsDirty(false)
+ , m_bTransportContainer(false)
+ , m_bReadOnly(false)
+ , m_bTransparentTextFrames(false)
+ , m_bSwapGraphics(false)
+ , m_bPasteResize(false)
+ , m_bStarDrawPreviewMode(false)
+ , mbDisableTextEditUsesCommonUndoManager(false)
+ , mbVOCInvalidationIsReliable(false)
+ , m_nDefaultTabulator(0)
+ , m_nMaxUndoCount(16)
+ , m_pTextChain(new TextChain)
+ , mpImpl(new SdrModelImpl)
+ , mnCharCompressType(CharCompressType::NONE)
+ , mnHandoutPageCount(0)
+ , mbModelLocked(false)
+ , mbKernAsianPunctuation(false)
+ , mbAddExtLeading(false)
+ , mbInDestruction(false)
+{
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ mnCharCompressType = static_cast<CharCompressType>(
+ officecfg::Office::Common::AsianLayout::CompressCharacterDistance::get());
+ }
+
+ if (m_pItemPool == nullptr)
+ {
+ m_pItemPool = new SdrItemPool(nullptr);
+ // Outliner doesn't have its own Pool, so use the EditEngine's
+ rtl::Reference<SfxItemPool> pOutlPool=EditEngine::CreatePool();
+ // OutlinerPool as SecondaryPool of SdrPool
+ m_pItemPool->SetSecondaryPool(pOutlPool.get());
+ // remember that I created both pools myself
+ m_bIsWriter = false;
+ }
+ m_pItemPool->SetDefaultMetric(m_eObjUnit);
+
+// using static SdrEngineDefaults only if default SvxFontHeight item is not available
+ const SfxPoolItem* pPoolItem = m_pItemPool->GetPoolDefaultItem( EE_CHAR_FONTHEIGHT );
+ if (pPoolItem)
+ mnDefTextHgt = static_cast<const SvxFontHeightItem*>(pPoolItem)->GetHeight();
+
+ m_pItemPool->SetPoolDefaultItem( makeSdrTextWordWrapItem( false ) );
+
+ SetTextDefaults();
+ m_pLayerAdmin->SetModel(this);
+ ImpSetUIUnit();
+
+ // can't create DrawOutliner OnDemand, because I can't get the Pool,
+ // then (only from 302 onwards!)
+ m_pDrawOutliner = SdrMakeOutliner(OutlinerMode::TextObject, *this);
+ ImpSetOutlinerDefaults(m_pDrawOutliner.get(), true);
+
+ m_pHitTestOutliner = SdrMakeOutliner(OutlinerMode::TextObject, *this);
+ ImpSetOutlinerDefaults(m_pHitTestOutliner.get(), true);
+
+ /* Start Text Chaining related code */
+ // Initialize Chaining Outliner
+ m_pChainingOutliner = SdrMakeOutliner( OutlinerMode::TextObject, *this );
+ ImpSetOutlinerDefaults(m_pChainingOutliner.get(), true);
+
+ ImpCreateTables(bDisablePropertyFiles || utl::ConfigManager::IsFuzzing());
+}
+
+SdrModel::~SdrModel()
+{
+ mbInDestruction = true;
+
+ Broadcast(SdrHint(SdrHintKind::ModelCleared));
+
+ mpOutlinerCache.reset();
+
+ ClearUndoBuffer();
+#ifdef DBG_UTIL
+ SAL_WARN_IF(m_pCurrentUndoGroup, "svx", "In the Dtor of the SdrModel there is an open Undo left: \""
+ << m_pCurrentUndoGroup->GetComment() << '\"');
+#endif
+ m_pCurrentUndoGroup.reset();
+
+ ClearModel(true);
+
+#ifdef DBG_UTIL
+ // SdrObjectLifetimeWatchDog:
+ if(!maAllIncarnatedObjects.empty())
+ {
+ SAL_WARN("svx","SdrModel::~SdrModel: Not all incarnations of SdrObjects deleted, possible memory leak (!)");
+ const std::vector<const SdrObject*> maRemainingObjects(maAllIncarnatedObjects.begin(),
+ maAllIncarnatedObjects.end());
+ for (auto pSdrObject : maRemainingObjects)
+ {
+ SdrObject* pCandidate(const_cast<SdrObject*>(pSdrObject));
+ // calling SdrObject::Free will change maAllIncarnatedObjects, and potentially remove
+ // more than one, so check if the candidate is still in the updated list before Free
+ if (maAllIncarnatedObjects.find(pSdrObject) != maAllIncarnatedObjects.end())
+ SdrObject::Free(pCandidate);
+ }
+ }
+#endif
+
+ m_pLayerAdmin.reset();
+
+ m_pTextChain.reset();
+ // Delete DrawOutliner only after deleting ItemPool, because ItemPool
+ // references Items of the DrawOutliner!
+ m_pChainingOutliner.reset();
+ m_pHitTestOutliner.reset();
+ m_pDrawOutliner.reset();
+
+ // delete StyleSheetPool, derived classes should not do this since
+ // the DrawingEngine may need it in its destructor
+ if( mxStyleSheetPool.is() )
+ {
+ Reference< XComponent > xComponent( static_cast< cppu::OWeakObject* >( mxStyleSheetPool.get() ), UNO_QUERY );
+ if( xComponent.is() ) try
+ {
+ xComponent->dispose();
+ }
+ catch( RuntimeException& )
+ {
+ }
+ mxStyleSheetPool.clear();
+ }
+
+ mpForbiddenCharactersTable.reset();
+
+ delete mpImpl->mpUndoFactory;
+}
+
+void SdrModel::SetSwapGraphics()
+{
+ m_bSwapGraphics = true;
+}
+
+bool SdrModel::IsReadOnly() const
+{
+ return m_bReadOnly;
+}
+
+void SdrModel::SetReadOnly(bool bYes)
+{
+ m_bReadOnly=bYes;
+}
+
+
+void SdrModel::SetMaxUndoActionCount(sal_uInt32 nCount)
+{
+ if (nCount<1) nCount=1;
+ m_nMaxUndoCount=nCount;
+ while (m_aUndoStack.size()>m_nMaxUndoCount)
+ m_aUndoStack.pop_back();
+}
+
+void SdrModel::ClearUndoBuffer()
+{
+ m_aUndoStack.clear();
+ m_aRedoStack.clear();
+}
+
+bool SdrModel::HasUndoActions() const
+{
+ return !m_aUndoStack.empty();
+}
+
+bool SdrModel::HasRedoActions() const
+{
+ return !m_aRedoStack.empty();
+}
+
+void SdrModel::Undo()
+{
+ if( mpImpl->mpUndoManager )
+ {
+ OSL_FAIL("svx::SdrModel::Undo(), method not supported with application undo manager!");
+ }
+ else
+ {
+ if(HasUndoActions())
+ {
+ SfxUndoAction* pDo = m_aUndoStack.front().get();
+ const bool bWasUndoEnabled = mbUndoEnabled;
+ mbUndoEnabled = false;
+ pDo->Undo();
+ std::unique_ptr<SfxUndoAction> p = std::move(m_aUndoStack.front());
+ m_aUndoStack.pop_front();
+ m_aRedoStack.emplace_front(std::move(p));
+ mbUndoEnabled = bWasUndoEnabled;
+ }
+ }
+}
+
+void SdrModel::Redo()
+{
+ if( mpImpl->mpUndoManager )
+ {
+ OSL_FAIL("svx::SdrModel::Redo(), method not supported with application undo manager!");
+ }
+ else
+ {
+ if(HasRedoActions())
+ {
+ SfxUndoAction* pDo = m_aRedoStack.front().get();
+ const bool bWasUndoEnabled = mbUndoEnabled;
+ mbUndoEnabled = false;
+ pDo->Redo();
+ std::unique_ptr<SfxUndoAction> p = std::move(m_aRedoStack.front());
+ m_aRedoStack.pop_front();
+ m_aUndoStack.emplace_front(std::move(p));
+ mbUndoEnabled = bWasUndoEnabled;
+ }
+ }
+}
+
+void SdrModel::Repeat(SfxRepeatTarget& rView)
+{
+ if( mpImpl->mpUndoManager )
+ {
+ OSL_FAIL("svx::SdrModel::Redo(), method not supported with application undo manager!");
+ }
+ else
+ {
+ if(HasUndoActions())
+ {
+ SfxUndoAction* pDo = m_aUndoStack.front().get();
+ if(pDo->CanRepeat(rView))
+ {
+ pDo->Repeat(rView);
+ }
+ }
+ }
+}
+
+void SdrModel::ImpPostUndoAction(std::unique_ptr<SdrUndoAction> pUndo)
+{
+ DBG_ASSERT( mpImpl->mpUndoManager == nullptr, "svx::SdrModel::ImpPostUndoAction(), method not supported with application undo manager!" );
+ if( !IsUndoEnabled() )
+ return;
+
+ if (m_aUndoLink)
+ {
+ m_aUndoLink(std::move(pUndo));
+ }
+ else
+ {
+ m_aUndoStack.emplace_front(std::move(pUndo));
+ while (m_aUndoStack.size()>m_nMaxUndoCount)
+ {
+ m_aUndoStack.pop_back();
+ }
+ m_aRedoStack.clear();
+ }
+}
+
+void SdrModel::BegUndo()
+{
+ if( mpImpl->mpUndoManager )
+ {
+ ViewShellId nViewShellId(-1);
+ if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ nViewShellId = pViewShell->GetViewShellId();
+ mpImpl->mpUndoManager->EnterListAction("","",0,nViewShellId);
+ m_nUndoLevel++;
+ }
+ else if( IsUndoEnabled() )
+ {
+ if(!m_pCurrentUndoGroup)
+ {
+ m_pCurrentUndoGroup.reset(new SdrUndoGroup(*this));
+ m_nUndoLevel=1;
+ }
+ else
+ {
+ m_nUndoLevel++;
+ }
+ }
+}
+
+void SdrModel::BegUndo(const OUString& rComment)
+{
+ if( mpImpl->mpUndoManager )
+ {
+ ViewShellId nViewShellId(-1);
+ if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ nViewShellId = pViewShell->GetViewShellId();
+ mpImpl->mpUndoManager->EnterListAction( rComment, "", 0, nViewShellId );
+ m_nUndoLevel++;
+ }
+ else if( IsUndoEnabled() )
+ {
+ BegUndo();
+ if (m_nUndoLevel==1)
+ {
+ m_pCurrentUndoGroup->SetComment(rComment);
+ }
+ }
+}
+
+void SdrModel::BegUndo(const OUString& rComment, const OUString& rObjDescr, SdrRepeatFunc eFunc)
+{
+ if( mpImpl->mpUndoManager )
+ {
+ OUString aComment(rComment);
+ if( !aComment.isEmpty() && !rObjDescr.isEmpty() )
+ {
+ aComment = aComment.replaceFirst("%1", rObjDescr);
+ }
+ ViewShellId nViewShellId(-1);
+ if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ nViewShellId = pViewShell->GetViewShellId();
+ mpImpl->mpUndoManager->EnterListAction( aComment,"",0,nViewShellId );
+ m_nUndoLevel++;
+ }
+ else if( IsUndoEnabled() )
+ {
+ BegUndo();
+ if (m_nUndoLevel==1)
+ {
+ m_pCurrentUndoGroup->SetComment(rComment);
+ m_pCurrentUndoGroup->SetObjDescription(rObjDescr);
+ m_pCurrentUndoGroup->SetRepeatFunction(eFunc);
+ }
+ }
+}
+
+void SdrModel::EndUndo()
+{
+ DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::EndUndo(): UndoLevel is already 0!");
+ if( mpImpl->mpUndoManager )
+ {
+ if( m_nUndoLevel )
+ {
+ m_nUndoLevel--;
+ mpImpl->mpUndoManager->LeaveListAction();
+ }
+ }
+ else
+ {
+ if(m_pCurrentUndoGroup!=nullptr && IsUndoEnabled())
+ {
+ m_nUndoLevel--;
+ if(m_nUndoLevel==0)
+ {
+ if(m_pCurrentUndoGroup->GetActionCount()!=0)
+ {
+ ImpPostUndoAction(std::move(m_pCurrentUndoGroup));
+ }
+ else
+ {
+ // was empty
+ m_pCurrentUndoGroup.reset();
+ }
+ }
+ }
+ }
+}
+
+void SdrModel::SetUndoComment(const OUString& rComment)
+{
+ DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::SetUndoComment(): UndoLevel is already 0!");
+
+ if( mpImpl->mpUndoManager )
+ {
+ OSL_FAIL("svx::SdrModel::SetUndoComment(), method not supported with application undo manager!" );
+ }
+ else if( IsUndoEnabled() && m_nUndoLevel==1)
+ {
+ m_pCurrentUndoGroup->SetComment(rComment);
+ }
+}
+
+void SdrModel::SetUndoComment(const OUString& rComment, const OUString& rObjDescr)
+{
+ DBG_ASSERT(m_nUndoLevel!=0,"SdrModel::SetUndoComment(): UndoLevel is already 0!");
+ if( mpImpl->mpUndoManager )
+ {
+ OSL_FAIL("svx::SdrModel::SetUndoComment(), method not supported with application undo manager!" );
+ }
+ else
+ {
+ if (m_nUndoLevel==1)
+ {
+ m_pCurrentUndoGroup->SetComment(rComment);
+ m_pCurrentUndoGroup->SetObjDescription(rObjDescr);
+ }
+ }
+}
+
+void SdrModel::AddUndo(std::unique_ptr<SdrUndoAction> pUndo)
+{
+ if( mpImpl->mpUndoManager )
+ {
+ mpImpl->mpUndoManager->AddUndoAction( std::move(pUndo) );
+ }
+ else if( IsUndoEnabled() )
+ {
+ if (m_pCurrentUndoGroup)
+ {
+ m_pCurrentUndoGroup->AddAction(std::move(pUndo));
+ }
+ else
+ {
+ ImpPostUndoAction(std::move(pUndo));
+ }
+ }
+}
+
+void SdrModel::EnableUndo( bool bEnable )
+{
+ if( mpImpl->mpUndoManager )
+ {
+ mpImpl->mpUndoManager->EnableUndo( bEnable );
+ }
+ else
+ {
+ mbUndoEnabled = bEnable;
+ }
+}
+
+bool SdrModel::IsUndoEnabled() const
+{
+ if( mpImpl->mpUndoManager )
+ {
+ return mpImpl->mpUndoManager->IsUndoEnabled();
+ }
+ else
+ {
+ return mbUndoEnabled;
+ }
+}
+
+void SdrModel::ImpCreateTables(bool bDisablePropertyFiles)
+{
+ // use standard path for initial construction
+ const OUString aTablePath(!bDisablePropertyFiles ? SvtPathOptions().GetPalettePath() : "");
+
+ for( auto i : o3tl::enumrange<XPropertyListType>() )
+ {
+ maProperties[i] = XPropertyList::CreatePropertyList(i, aTablePath, ""/*TODO?*/ );
+ }
+}
+
+void SdrModel::ClearModel(bool bCalledFromDestructor)
+{
+ if(bCalledFromDestructor)
+ {
+ mbInDestruction = true;
+ }
+
+ sal_Int32 i;
+ // delete all drawing pages
+ sal_Int32 nCount=GetPageCount();
+ for (i=nCount-1; i>=0; i--)
+ {
+ DeletePage( static_cast<sal_uInt16>(i) );
+ }
+ maPages.clear();
+ PageListChanged();
+
+ // delete all Masterpages
+ nCount=GetMasterPageCount();
+ for(i=nCount-1; i>=0; i--)
+ {
+ DeleteMasterPage( static_cast<sal_uInt16>(i) );
+ }
+ maMasterPages.clear();
+ MasterPageListChanged();
+
+ m_pLayerAdmin->ClearLayers();
+}
+
+SdrModel* SdrModel::AllocModel() const
+{
+ SdrModel* pModel=new SdrModel();
+ pModel->SetScaleUnit(m_eObjUnit,m_aObjUnit);
+ return pModel;
+}
+
+rtl::Reference<SdrPage> SdrModel::AllocPage(bool bMasterPage)
+{
+ return new SdrPage(*this,bMasterPage);
+}
+
+void SdrModel::SetTextDefaults() const
+{
+ SetTextDefaults( m_pItemPool.get(), mnDefTextHgt );
+}
+
+void SdrModel::SetTextDefaults( SfxItemPool* pItemPool, sal_Int32 nDefTextHgt )
+{
+ // set application-language specific dynamic pool language defaults
+ SvxFontItem aSvxFontItem( EE_CHAR_FONTINFO) ;
+ SvxFontItem aSvxFontItemCJK(EE_CHAR_FONTINFO_CJK);
+ SvxFontItem aSvxFontItemCTL(EE_CHAR_FONTINFO_CTL);
+ LanguageType nLanguage;
+ if (!utl::ConfigManager::IsFuzzing())
+ nLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
+ else
+ nLanguage = LANGUAGE_ENGLISH_US;
+
+ // get DEFAULTFONT_LATIN_TEXT and set at pool as dynamic default
+ vcl::Font aFont(OutputDevice::GetDefaultFont(DefaultFontType::LATIN_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
+ aSvxFontItem.SetFamily(aFont.GetFamilyType());
+ aSvxFontItem.SetFamilyName(aFont.GetFamilyName());
+ aSvxFontItem.SetStyleName(OUString());
+ aSvxFontItem.SetPitch( aFont.GetPitch());
+ aSvxFontItem.SetCharSet( aFont.GetCharSet() );
+ pItemPool->SetPoolDefaultItem(aSvxFontItem);
+
+ // get DEFAULTFONT_CJK_TEXT and set at pool as dynamic default
+ vcl::Font aFontCJK(OutputDevice::GetDefaultFont(DefaultFontType::CJK_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
+ aSvxFontItemCJK.SetFamily( aFontCJK.GetFamilyType());
+ aSvxFontItemCJK.SetFamilyName(aFontCJK.GetFamilyName());
+ aSvxFontItemCJK.SetStyleName(OUString());
+ aSvxFontItemCJK.SetPitch( aFontCJK.GetPitch());
+ aSvxFontItemCJK.SetCharSet( aFontCJK.GetCharSet());
+ pItemPool->SetPoolDefaultItem(aSvxFontItemCJK);
+
+ // get DEFAULTFONT_CTL_TEXT and set at pool as dynamic default
+ vcl::Font aFontCTL(OutputDevice::GetDefaultFont(DefaultFontType::CTL_TEXT, nLanguage, GetDefaultFontFlags::OnlyOne));
+ aSvxFontItemCTL.SetFamily(aFontCTL.GetFamilyType());
+ aSvxFontItemCTL.SetFamilyName(aFontCTL.GetFamilyName());
+ aSvxFontItemCTL.SetStyleName(OUString());
+ aSvxFontItemCTL.SetPitch( aFontCTL.GetPitch() );
+ aSvxFontItemCTL.SetCharSet( aFontCTL.GetCharSet());
+ pItemPool->SetPoolDefaultItem(aSvxFontItemCTL);
+
+ // set dynamic FontHeight defaults
+ pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT ) );
+ pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT_CJK ) );
+ pItemPool->SetPoolDefaultItem( SvxFontHeightItem(nDefTextHgt, 100, EE_CHAR_FONTHEIGHT_CTL ) );
+
+ // set FontColor defaults
+ pItemPool->SetPoolDefaultItem( SvxColorItem(SdrEngineDefaults::GetFontColor(), EE_CHAR_COLOR) );
+}
+
+SdrOutliner& SdrModel::GetDrawOutliner(const SdrTextObj* pObj) const
+{
+ m_pDrawOutliner->SetTextObj(pObj);
+ return *m_pDrawOutliner;
+}
+
+SdrOutliner& SdrModel::GetChainingOutliner(const SdrTextObj* pObj) const
+{
+ m_pChainingOutliner->SetTextObj(pObj);
+ return *m_pChainingOutliner;
+}
+
+const SdrTextObj* SdrModel::GetFormattingTextObj() const
+{
+ if (m_pDrawOutliner!=nullptr) {
+ return m_pDrawOutliner->GetTextObj();
+ }
+ return nullptr;
+}
+
+void SdrModel::ImpSetOutlinerDefaults( SdrOutliner* pOutliner, bool bInit )
+{
+ // Initialization of the Outliners for drawing text and HitTest
+ if( bInit )
+ {
+ pOutliner->EraseVirtualDevice();
+ pOutliner->SetUpdateLayout(false);
+ pOutliner->SetEditTextObjectPool(m_pItemPool.get());
+ pOutliner->SetDefTab(m_nDefaultTabulator);
+ }
+
+ pOutliner->SetRefDevice(GetRefDevice());
+ Outliner::SetForbiddenCharsTable(GetForbiddenCharsTable());
+ pOutliner->SetAsianCompressionMode( mnCharCompressType );
+ pOutliner->SetKernAsianPunctuation( IsKernAsianPunctuation() );
+ pOutliner->SetAddExtLeading( IsAddExtLeading() );
+
+ if ( !GetRefDevice() )
+ {
+ MapMode aMapMode(m_eObjUnit, Point(0,0), m_aObjUnit, m_aObjUnit);
+ pOutliner->SetRefMapMode(aMapMode);
+ }
+}
+
+void SdrModel::SetRefDevice(OutputDevice* pDev)
+{
+ m_pRefOutDev=pDev;
+ ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
+ ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
+ RefDeviceChanged();
+}
+
+void SdrModel::ImpReformatAllTextObjects()
+{
+ if( isLocked() )
+ return;
+
+ sal_uInt16 nCount=GetMasterPageCount();
+ sal_uInt16 nNum;
+ for (nNum=0; nNum<nCount; nNum++) {
+ GetMasterPage(nNum)->ReformatAllTextObjects();
+ }
+ nCount=GetPageCount();
+ for (nNum=0; nNum<nCount; nNum++) {
+ GetPage(nNum)->ReformatAllTextObjects();
+ }
+}
+
+/* steps over all available pages and sends notify messages to
+ all edge objects that are connected to other objects so that
+ they may reposition themselves
+*/
+void SdrModel::ImpReformatAllEdgeObjects()
+{
+ if( isLocked() )
+ return;
+
+ sal_uInt16 nCount=GetMasterPageCount();
+ sal_uInt16 nNum;
+ for (nNum=0; nNum<nCount; nNum++)
+ {
+ GetMasterPage(nNum)->ReformatAllEdgeObjects();
+ }
+ nCount=GetPageCount();
+ for (nNum=0; nNum<nCount; nNum++)
+ {
+ GetPage(nNum)->ReformatAllEdgeObjects();
+ }
+}
+
+uno::Reference<embed::XStorage> SdrModel::GetDocumentStorage() const
+{
+ uno::Reference<document::XStorageBasedDocument> const xSBD(
+ const_cast<SdrModel*>(this)->getUnoModel(), uno::UNO_QUERY);
+ if (!xSBD.is())
+ {
+ SAL_WARN("svx", "no UNO model");
+ return nullptr;
+ }
+ return xSBD->getDocumentStorage();
+}
+
+uno::Reference<io::XInputStream>
+SdrModel::GetDocumentStream( OUString const& rURL,
+ ::comphelper::LifecycleProxy const & rProxy) const
+{
+ uno::Reference<embed::XStorage> const xStorage(GetDocumentStorage());
+ if (!xStorage.is())
+ {
+ SAL_WARN("svx", "no storage?");
+ return nullptr;
+ }
+ try {
+ uno::Reference<io::XStream> const xStream(
+ ::comphelper::OStorageHelper::GetStreamAtPackageURL(
+ xStorage, rURL, embed::ElementModes::READ, rProxy));
+ return (xStream.is()) ? xStream->getInputStream() : nullptr;
+ }
+ catch (container::NoSuchElementException const&)
+ {
+ SAL_INFO("svx", "not found");
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+ return nullptr;
+}
+
+// convert template attributes from the string into "hard" attributes
+void SdrModel::BurnInStyleSheetAttributes()
+{
+ sal_uInt16 nCount=GetMasterPageCount();
+ sal_uInt16 nNum;
+ for (nNum=0; nNum<nCount; nNum++) {
+ GetMasterPage(nNum)->BurnInStyleSheetAttributes();
+ }
+ nCount=GetPageCount();
+ for (nNum=0; nNum<nCount; nNum++) {
+ GetPage(nNum)->BurnInStyleSheetAttributes();
+ }
+}
+
+void SdrModel::RefDeviceChanged()
+{
+ Broadcast(SdrHint(SdrHintKind::RefDeviceChange));
+ ImpReformatAllTextObjects();
+}
+
+void SdrModel::SetDefaultFontHeight(sal_Int32 nVal)
+{
+ if (nVal!=mnDefTextHgt) {
+ mnDefTextHgt=nVal;
+ ImpReformatAllTextObjects();
+ }
+}
+
+void SdrModel::SetDefaultTabulator(sal_uInt16 nVal)
+{
+ if (m_nDefaultTabulator!=nVal) {
+ m_nDefaultTabulator=nVal;
+ Outliner& rOutliner=GetDrawOutliner();
+ rOutliner.SetDefTab(nVal);
+ Broadcast(SdrHint(SdrHintKind::DefaultTabChange));
+ ImpReformatAllTextObjects();
+ }
+}
+
+void SdrModel::ImpSetUIUnit()
+{
+ if(0 == m_aUIScale.GetNumerator() || 0 == m_aUIScale.GetDenominator())
+ {
+ m_aUIScale = Fraction(1,1);
+ }
+
+ m_nUIUnitDecimalMark = 0;
+
+ o3tl::Length eFrom = MapToO3tlLength(m_eObjUnit, o3tl::Length::invalid);
+ o3tl::Length eTo;
+
+ switch (m_eUIUnit)
+ {
+ case FieldUnit::CHAR:
+ case FieldUnit::LINE:
+ eTo = o3tl::Length::invalid;
+ break;
+ case FieldUnit::PERCENT:
+ m_nUIUnitDecimalMark += 2;
+ [[fallthrough]];
+ default:
+ eTo = FieldToO3tlLength(m_eUIUnit, o3tl::Length::invalid);
+ } // switch
+
+ sal_Int32 nMul = 1, nDiv = 1;
+ if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
+ {
+ const auto& [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
+ nMul = mul;
+ nDiv = div;
+ }
+ // #i89872# take Unit of Measurement into account
+ if(1 != m_aUIScale.GetDenominator() || 1 != m_aUIScale.GetNumerator())
+ {
+ // divide by UIScale
+ nMul *= m_aUIScale.GetDenominator();
+ nDiv *= m_aUIScale.GetNumerator();
+ }
+
+ // shorten trailing zeros for dividend
+ while(0 == (nMul % 10))
+ {
+ m_nUIUnitDecimalMark--;
+ nMul /= 10;
+ }
+
+ // shorten trailing zeros for divisor
+ while(0 == (nDiv % 10))
+ {
+ m_nUIUnitDecimalMark++;
+ nDiv /= 10;
+ }
+
+ // end preparations, set member values
+ m_aUIUnitFact = Fraction(sal_Int32(nMul), sal_Int32(nDiv));
+ m_aUIUnitStr = GetUnitString(m_eUIUnit);
+}
+
+void SdrModel::SetScaleUnit(MapUnit eMap, const Fraction& rFrac)
+{
+ if (m_eObjUnit!=eMap || m_aObjUnit!=rFrac) {
+ m_eObjUnit=eMap;
+ m_aObjUnit=rFrac;
+ m_pItemPool->SetDefaultMetric(m_eObjUnit);
+ ImpSetUIUnit();
+ ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
+ ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
+ ImpReformatAllTextObjects();
+ }
+}
+
+void SdrModel::SetScaleUnit(MapUnit eMap)
+{
+ if (m_eObjUnit!=eMap) {
+ m_eObjUnit=eMap;
+ m_pItemPool->SetDefaultMetric(m_eObjUnit);
+ ImpSetUIUnit();
+ ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
+ ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
+ ImpReformatAllTextObjects();
+ }
+}
+
+void SdrModel::SetScaleFraction(const Fraction& rFrac)
+{
+ if (m_aObjUnit!=rFrac) {
+ m_aObjUnit=rFrac;
+ ImpSetUIUnit();
+ ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
+ ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
+ ImpReformatAllTextObjects();
+ }
+}
+
+void SdrModel::SetUIUnit(FieldUnit eUnit)
+{
+ if (m_eUIUnit!=eUnit) {
+ m_eUIUnit=eUnit;
+ ImpSetUIUnit();
+ ImpReformatAllTextObjects();
+ }
+}
+
+void SdrModel::SetUIScale(const Fraction& rScale)
+{
+ if (m_aUIScale!=rScale) {
+ m_aUIScale=rScale;
+ ImpSetUIUnit();
+ ImpReformatAllTextObjects();
+ }
+}
+
+void SdrModel::SetUIUnit(FieldUnit eUnit, const Fraction& rScale)
+{
+ if (m_eUIUnit!=eUnit || m_aUIScale!=rScale) {
+ m_eUIUnit=eUnit;
+ m_aUIScale=rScale;
+ ImpSetUIUnit();
+ ImpReformatAllTextObjects();
+ }
+}
+
+OUString SdrModel::GetUnitString(FieldUnit eUnit)
+{
+ switch(eUnit)
+ {
+ default:
+ case FieldUnit::NONE :
+ case FieldUnit::CUSTOM :
+ return OUString();
+ case FieldUnit::MM_100TH:
+ return OUString{"/100mm"};
+ case FieldUnit::MM :
+ return OUString{"mm"};
+ case FieldUnit::CM :
+ return OUString{"cm"};
+ case FieldUnit::M :
+ return OUString{"m"};
+ case FieldUnit::KM :
+ return OUString{"km"};
+ case FieldUnit::TWIP :
+ return OUString{"twip"};
+ case FieldUnit::POINT :
+ return OUString{"pt"};
+ case FieldUnit::PICA :
+ return OUString{"pica"};
+ case FieldUnit::INCH :
+ return OUString{"\""};
+ case FieldUnit::FOOT :
+ return OUString{"ft"};
+ case FieldUnit::MILE :
+ return OUString{"mile(s)"};
+ case FieldUnit::PERCENT:
+ return OUString{"%"};
+ }
+}
+
+OUString SdrModel::GetMetricString(tools::Long nVal, bool bNoUnitChars, sal_Int32 nNumDigits) const
+{
+ // #i22167#
+ // change to double precision usage to not lose decimal places
+ const bool bNegative(nVal < 0);
+ SvtSysLocale aSysLoc;
+ const LocaleDataWrapper& rLoc(aSysLoc.GetLocaleData());
+ double fLocalValue(double(nVal) * double(m_aUIUnitFact));
+
+ if(bNegative)
+ {
+ fLocalValue = -fLocalValue;
+ }
+
+ if( -1 == nNumDigits )
+ {
+ nNumDigits = LocaleDataWrapper::getNumDigits();
+ }
+
+ sal_Int32 nDecimalMark(m_nUIUnitDecimalMark);
+
+ if(nDecimalMark > nNumDigits)
+ {
+ const sal_Int32 nDiff(nDecimalMark - nNumDigits);
+ const double fFactor(pow(10.0, static_cast<int>(nDiff)));
+
+ fLocalValue /= fFactor;
+ nDecimalMark = nNumDigits;
+ }
+ else if(nDecimalMark < nNumDigits)
+ {
+ const sal_Int32 nDiff(nNumDigits - nDecimalMark);
+ const double fFactor(pow(10.0, static_cast<int>(nDiff)));
+
+ fLocalValue *= fFactor;
+ nDecimalMark = nNumDigits;
+ }
+
+ OUStringBuffer aBuf;
+ aBuf.append(static_cast<sal_Int32>(fLocalValue + 0.5));
+
+ if(nDecimalMark < 0)
+ {
+ // negative nDecimalMark (decimal point) means: add zeros
+ sal_Int32 nCount(-nDecimalMark);
+
+ for(sal_Int32 i=0; i<nCount; i++)
+ aBuf.append('0');
+
+ nDecimalMark = 0;
+ }
+
+ // the second condition needs to be <= since inside this loop
+ // also the leading zero is inserted.
+ if (nDecimalMark > 0 && aBuf.getLength() <= nDecimalMark)
+ {
+ // if necessary, add zeros before the decimal point
+ sal_Int32 nCount = nDecimalMark - aBuf.getLength();
+
+ if(nCount >= 0 && LocaleDataWrapper::isNumLeadingZero())
+ nCount++;
+
+ for(sal_Int32 i=0; i<nCount; i++)
+ aBuf.insert(0, '0');
+ }
+
+ const sal_Unicode cDec( rLoc.getNumDecimalSep()[0] );
+
+ // insert the decimal mark character
+ sal_Int32 nBeforeDecimalMark = aBuf.getLength() - nDecimalMark;
+
+ if(nDecimalMark > 0)
+ aBuf.insert(nBeforeDecimalMark, cDec);
+
+ if(!LocaleDataWrapper::isNumTrailingZeros())
+ {
+ sal_Int32 aPos=aBuf.getLength()-1;
+
+ // Remove all trailing zeros.
+ while (aPos>=0 && aBuf[aPos]=='0')
+ --aPos;
+
+ // Remove decimal if it's the last character.
+ if (aPos>=0 && aBuf[aPos]==cDec)
+ --aPos;
+
+ // Adjust aPos to index first char to be truncated, if any
+ if (++aPos<aBuf.getLength())
+ aBuf.truncate(aPos);
+ }
+
+ // if necessary, add separators before every third digit
+ if( nBeforeDecimalMark > 3 )
+ {
+ const OUString& aThoSep( rLoc.getNumThousandSep() );
+ if ( !aThoSep.isEmpty() )
+ {
+ sal_Unicode cTho( aThoSep[0] );
+ sal_Int32 i(nBeforeDecimalMark - 3);
+
+ while(i > 0)
+ {
+ aBuf.insert(i, cTho);
+ i -= 3;
+ }
+ }
+ }
+
+ if (aBuf.isEmpty())
+ aBuf.append("0");
+
+ if(bNegative)
+ {
+ aBuf.insert(0, "-");
+ }
+
+ if(!bNoUnitChars)
+ aBuf.append(m_aUIUnitStr);
+
+ return aBuf.makeStringAndClear();
+}
+
+OUString SdrModel::GetAngleString(Degree100 nAngle)
+{
+ bool bNeg = nAngle < 0_deg100;
+
+ if(bNeg)
+ nAngle = -nAngle;
+
+ OUStringBuffer aBuf;
+ aBuf.append(static_cast<sal_Int32>(nAngle));
+
+ SvtSysLocale aSysLoc;
+ const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
+ sal_Int32 nCount = 2;
+
+ if(LocaleDataWrapper::isNumLeadingZero())
+ nCount++;
+
+ while(aBuf.getLength() < nCount)
+ aBuf.insert(0, '0');
+
+ aBuf.insert(aBuf.getLength()-2, rLoc.getNumDecimalSep()[0]);
+
+ if(bNeg)
+ aBuf.insert(0, '-');
+
+ aBuf.append(DEGREE_CHAR);
+
+ return aBuf.makeStringAndClear();
+}
+
+OUString SdrModel::GetPercentString(const Fraction& rVal)
+{
+ sal_Int32 nMul(rVal.GetNumerator());
+ sal_Int32 nDiv(rVal.GetDenominator());
+ bool bNeg {false};
+
+ if (nDiv < 0)
+ {
+ bNeg = !bNeg;
+ nDiv = -nDiv;
+ }
+
+ if (nMul < 0)
+ {
+ bNeg = !bNeg;
+ nMul = -nMul;
+ }
+
+ sal_Int32 nPct = ((nMul*100) + nDiv/2)/nDiv;
+
+ if (bNeg)
+ nPct = -nPct;
+
+ return OUString::number(nPct) + "%";
+}
+
+void SdrModel::SetChanged(bool bFlg)
+{
+ mbChanged = bFlg;
+}
+
+void SdrModel::RecalcPageNums(bool bMaster)
+{
+ if(bMaster)
+ {
+ sal_uInt16 nCount=sal_uInt16(maMasterPages.size());
+ sal_uInt16 i;
+ for (i=0; i<nCount; i++) {
+ SdrPage* pPg = maMasterPages[i].get();
+ pPg->SetPageNum(i);
+ }
+ m_bMPgNumsDirty=false;
+ }
+ else
+ {
+ sal_uInt16 nCount=sal_uInt16(maPages.size());
+ sal_uInt16 i;
+ for (i=0; i<nCount; i++) {
+ SdrPage* pPg = maPages[i].get();
+ pPg->SetPageNum(i);
+ }
+ m_bPagNumsDirty=false;
+ }
+}
+
+void SdrModel::InsertPage(SdrPage* pPage, sal_uInt16 nPos)
+{
+ sal_uInt16 nCount = GetPageCount();
+ if (nPos > nCount)
+ nPos = nCount;
+
+ maPages.insert(maPages.begin() + nPos, pPage);
+ PageListChanged();
+ pPage->SetInserted();
+ pPage->SetPageNum(nPos);
+
+ if (mbMakePageObjectsNamesUnique)
+ pPage->MakePageObjectsNamesUnique();
+
+ if (nPos<nCount) m_bPagNumsDirty=true;
+ SetChanged();
+ SdrHint aHint(SdrHintKind::PageOrderChange, pPage);
+ Broadcast(aHint);
+}
+
+void SdrModel::DeletePage(sal_uInt16 nPgNum)
+{
+ RemovePage(nPgNum);
+}
+
+rtl::Reference<SdrPage> SdrModel::RemovePage(sal_uInt16 nPgNum)
+{
+ rtl::Reference<SdrPage> pPg = maPages[nPgNum];
+ maPages.erase(maPages.begin()+nPgNum);
+ PageListChanged();
+ if (pPg) {
+ pPg->SetInserted(false);
+ }
+ m_bPagNumsDirty=true;
+ SetChanged();
+ SdrHint aHint(SdrHintKind::PageOrderChange, pPg.get());
+ Broadcast(aHint);
+ return pPg;
+}
+
+void SdrModel::MovePage(sal_uInt16 nPgNum, sal_uInt16 nNewPos)
+{
+ rtl::Reference<SdrPage> pPg = std::move(maPages[nPgNum]);
+ if (pPg) {
+ maPages.erase(maPages.begin()+nPgNum); // shortcut to avoid two broadcasts
+ PageListChanged();
+ pPg->SetInserted(false);
+ InsertPage(pPg.get(), nNewPos);
+ }
+ else
+ RemovePage(nPgNum);
+}
+
+void SdrModel::InsertMasterPage(SdrPage* pPage, sal_uInt16 nPos)
+{
+ sal_uInt16 nCount=GetMasterPageCount();
+ if (nPos>nCount) nPos=nCount;
+ maMasterPages.insert(maMasterPages.begin()+nPos,pPage);
+ MasterPageListChanged();
+ pPage->SetInserted();
+ pPage->SetPageNum(nPos);
+
+ if (nPos<nCount) {
+ m_bMPgNumsDirty=true;
+ }
+
+ SetChanged();
+ SdrHint aHint(SdrHintKind::PageOrderChange, pPage);
+ Broadcast(aHint);
+}
+
+void SdrModel::DeleteMasterPage(sal_uInt16 nPgNum)
+{
+ RemoveMasterPage(nPgNum);
+}
+
+rtl::Reference<SdrPage> SdrModel::RemoveMasterPage(sal_uInt16 nPgNum)
+{
+ rtl::Reference<SdrPage> pRetPg = std::move(maMasterPages[nPgNum]);
+ maMasterPages.erase(maMasterPages.begin()+nPgNum);
+ MasterPageListChanged();
+
+ if(pRetPg)
+ {
+ // Now delete the links from the normal drawing pages to the deleted master page.
+ sal_uInt16 nPageCnt(GetPageCount());
+
+ for(sal_uInt16 np(0); np < nPageCnt; np++)
+ {
+ GetPage(np)->TRG_ImpMasterPageRemoved(*pRetPg);
+ }
+
+ pRetPg->SetInserted(false);
+ }
+
+ m_bMPgNumsDirty=true;
+ SetChanged();
+ SdrHint aHint(SdrHintKind::PageOrderChange, pRetPg.get());
+ Broadcast(aHint);
+ return pRetPg;
+}
+
+void SdrModel::MoveMasterPage(sal_uInt16 nPgNum, sal_uInt16 nNewPos)
+{
+ rtl::Reference<SdrPage> pPg = std::move(maMasterPages[nPgNum]);
+ maMasterPages.erase(maMasterPages.begin()+nPgNum);
+ MasterPageListChanged();
+ if (pPg) {
+ pPg->SetInserted(false);
+ maMasterPages.insert(maMasterPages.begin()+nNewPos,pPg);
+ MasterPageListChanged();
+ }
+ m_bMPgNumsDirty=true;
+ SetChanged();
+ SdrHint aHint(SdrHintKind::PageOrderChange, pPg.get());
+ Broadcast(aHint);
+}
+
+
+void SdrModel::CopyPages(sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum,
+ sal_uInt16 nDestPos,
+ bool bUndo, bool bMoveNoCopy)
+{
+ if( bUndo && !IsUndoEnabled() )
+ bUndo = false;
+
+ if( bUndo )
+ BegUndo(SvxResId(STR_UndoMergeModel));
+
+ sal_uInt16 nPageCnt=GetPageCount();
+ sal_uInt16 nMaxPage=nPageCnt;
+
+ if (nMaxPage!=0)
+ nMaxPage--;
+ if (nFirstPageNum>nMaxPage)
+ nFirstPageNum=nMaxPage;
+ if (nLastPageNum>nMaxPage)
+ nLastPageNum =nMaxPage;
+ bool bReverse=nLastPageNum<nFirstPageNum;
+ if (nDestPos>nPageCnt)
+ nDestPos=nPageCnt;
+
+ // at first, save the pointers of the affected pages in an array
+ sal_uInt16 nPageNum=nFirstPageNum;
+ sal_uInt16 nCopyCnt=((!bReverse)?(nLastPageNum-nFirstPageNum):(nFirstPageNum-nLastPageNum))+1;
+ std::unique_ptr<SdrPage*[]> pPagePtrs(new SdrPage*[nCopyCnt]);
+ sal_uInt16 nCopyNum;
+ for(nCopyNum=0; nCopyNum<nCopyCnt; nCopyNum++)
+ {
+ pPagePtrs[nCopyNum]=GetPage(nPageNum);
+ if (bReverse)
+ nPageNum--;
+ else
+ nPageNum++;
+ }
+
+ // now copy the pages
+ sal_uInt16 nDestNum=nDestPos;
+ for (nCopyNum=0; nCopyNum<nCopyCnt; nCopyNum++)
+ {
+ rtl::Reference<SdrPage> pPg = pPagePtrs[nCopyNum];
+ sal_uInt16 nPageNum2=pPg->GetPageNum();
+ if (!bMoveNoCopy)
+ {
+ const SdrPage* pPg1=GetPage(nPageNum2);
+
+ // Clone to local model
+ pPg = pPg1->CloneSdrPage(*this);
+
+ InsertPage(pPg.get(), nDestNum);
+ if (bUndo)
+ AddUndo(GetSdrUndoFactory().CreateUndoCopyPage(*pPg));
+ nDestNum++;
+ }
+ else
+ {
+ // TODO: Move is untested!
+ if (nDestNum>nPageNum2)
+ nDestNum--;
+
+ if(bUndo)
+ AddUndo(GetSdrUndoFactory().CreateUndoSetPageNum(*GetPage(nPageNum2),nPageNum2,nDestNum));
+
+ pPg=RemovePage(nPageNum2);
+ InsertPage(pPg.get(), nDestNum);
+ nDestNum++;
+ }
+
+ if(bReverse)
+ nPageNum2--;
+ else
+ nPageNum2++;
+ }
+
+ pPagePtrs.reset();
+ if(bUndo)
+ EndUndo();
+}
+
+void SdrModel::Merge(SdrModel& rSourceModel,
+ sal_uInt16 nFirstPageNum, sal_uInt16 nLastPageNum,
+ sal_uInt16 nDestPos,
+ bool bMergeMasterPages, bool bAllMasterPages,
+ bool bUndo, bool bTreadSourceAsConst)
+{
+ if (&rSourceModel==this)
+ {
+ CopyPages(nFirstPageNum,nLastPageNum,nDestPos,bUndo,!bTreadSourceAsConst);
+ return;
+ }
+
+ if( bUndo && !IsUndoEnabled() )
+ bUndo = false;
+
+ if (bUndo)
+ BegUndo(SvxResId(STR_UndoMergeModel));
+
+ sal_uInt16 nSrcPageCnt=rSourceModel.GetPageCount();
+ sal_uInt16 nSrcMasterPageCnt=rSourceModel.GetMasterPageCount();
+ sal_uInt16 nDstMasterPageCnt=GetMasterPageCount();
+ bool bInsPages=(nFirstPageNum<nSrcPageCnt || nLastPageNum<nSrcPageCnt);
+ sal_uInt16 nMaxSrcPage=nSrcPageCnt; if (nMaxSrcPage!=0) nMaxSrcPage--;
+ if (nFirstPageNum>nMaxSrcPage) nFirstPageNum=nMaxSrcPage;
+ if (nLastPageNum>nMaxSrcPage) nLastPageNum =nMaxSrcPage;
+ bool bReverse=nLastPageNum<nFirstPageNum;
+
+ std::unique_ptr<sal_uInt16[]> pMasterMap;
+ std::unique_ptr<bool[]> pMasterNeed;
+ sal_uInt16 nMasterNeed=0;
+ if (bMergeMasterPages && nSrcMasterPageCnt!=0) {
+ // determine which MasterPages from rSrcModel we need
+ pMasterMap.reset(new sal_uInt16[nSrcMasterPageCnt]);
+ pMasterNeed.reset(new bool[nSrcMasterPageCnt]);
+ memset(pMasterMap.get(),0xFF,nSrcMasterPageCnt*sizeof(sal_uInt16));
+ if (bAllMasterPages) {
+ memset(pMasterNeed.get(), true, nSrcMasterPageCnt * sizeof(bool));
+ } else {
+ memset(pMasterNeed.get(), false, nSrcMasterPageCnt * sizeof(bool));
+ sal_uInt16 nStart= bReverse ? nLastPageNum : nFirstPageNum;
+ sal_uInt16 nEnd= bReverse ? nFirstPageNum : nLastPageNum;
+ for (sal_uInt16 i=nStart; i<=nEnd; i++) {
+ const SdrPage* pPg=rSourceModel.GetPage(i);
+ if(pPg->TRG_HasMasterPage())
+ {
+ SdrPage& rMasterPage = pPg->TRG_GetMasterPage();
+ sal_uInt16 nMPgNum(rMasterPage.GetPageNum());
+
+ if(nMPgNum < nSrcMasterPageCnt)
+ {
+ pMasterNeed[nMPgNum] = true;
+ }
+ }
+ }
+ }
+ // now determine the Mapping of the MasterPages
+ sal_uInt16 nCurrentMaPagNum=nDstMasterPageCnt;
+ for (sal_uInt16 i=0; i<nSrcMasterPageCnt; i++) {
+ if (pMasterNeed[i]) {
+ pMasterMap[i]=nCurrentMaPagNum;
+ nCurrentMaPagNum++;
+ nMasterNeed++;
+ }
+ }
+ }
+
+ // get the MasterPages
+ if (pMasterMap && pMasterNeed && nMasterNeed!=0) {
+ for (sal_uInt16 i=nSrcMasterPageCnt; i>0;) {
+ i--;
+ if (pMasterNeed[i])
+ {
+ // Always Clone to new model
+ const SdrPage* pPg1(rSourceModel.GetMasterPage(i));
+ rtl::Reference<SdrPage> pPg = pPg1->CloneSdrPage(*this);
+
+ if(!bTreadSourceAsConst)
+ {
+ // if requested, delete original/modify original model
+ rSourceModel.RemoveMasterPage(i);
+ }
+
+ if (pPg!=nullptr) {
+ // Now append all of them to the end of the DstModel.
+ // Don't use InsertMasterPage(), because everything is
+ // inconsistent until all are in.
+ maMasterPages.insert(maMasterPages.begin()+nDstMasterPageCnt, pPg);
+ MasterPageListChanged();
+ pPg->SetInserted();
+ m_bMPgNumsDirty=true;
+ if (bUndo) AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pPg));
+ } else {
+ OSL_FAIL("SdrModel::Merge(): MasterPage not found in SourceModel.");
+ }
+ }
+ }
+ }
+
+ // get the drawing pages
+ if (bInsPages) {
+ sal_uInt16 nSourcePos=nFirstPageNum;
+ sal_uInt16 nMergeCount=sal_uInt16(std::abs(static_cast<tools::Long>(static_cast<tools::Long>(nFirstPageNum)-nLastPageNum))+1);
+ if (nDestPos>GetPageCount()) nDestPos=GetPageCount();
+ while (nMergeCount>0)
+ {
+ // Always Clone to new model
+ const SdrPage* pPg1(rSourceModel.GetPage(nSourcePos));
+ rtl::Reference<SdrPage> pPg = pPg1->CloneSdrPage(*this);
+
+ if(!bTreadSourceAsConst)
+ {
+ // if requested, delete original/modify original model
+ rSourceModel.RemovePage(nSourcePos);
+ }
+
+ if (pPg!=nullptr) {
+ InsertPage(pPg.get(),nDestPos);
+ if (bUndo) AddUndo(GetSdrUndoFactory().CreateUndoNewPage(*pPg));
+
+ if(pPg->TRG_HasMasterPage())
+ {
+ SdrPage& rMasterPage = pPg->TRG_GetMasterPage();
+ sal_uInt16 nMaPgNum(rMasterPage.GetPageNum());
+
+ if (bMergeMasterPages)
+ {
+ sal_uInt16 nNewNum(0xFFFF);
+
+ if(pMasterMap)
+ {
+ nNewNum = pMasterMap[nMaPgNum];
+ }
+
+ if(nNewNum != 0xFFFF)
+ {
+ // tdf#90357 here pPg and the to-be-set new masterpage are parts of the new model
+ // already, but the currently set masterpage is part of the old model. Remove master
+ // page from already cloned page to prevent creating wrong undo action that can
+ // eventually crash the app.
+ // Do *not* remove it directly after cloning - the old masterpage is still needed
+ // later to find the new to-be-set masterpage.
+ pPg->TRG_ClearMasterPage();
+
+ if(bUndo)
+ {
+ AddUndo(GetSdrUndoFactory().CreateUndoPageChangeMasterPage(*pPg));
+ }
+
+ pPg->TRG_SetMasterPage(*GetMasterPage(nNewNum));
+ }
+ DBG_ASSERT(nNewNum!=0xFFFF,"SdrModel::Merge(): Something is crooked with the mapping of the MasterPages.");
+ } else {
+ if (nMaPgNum>=nDstMasterPageCnt) {
+ // This is outside of the original area of the MasterPage of the DstModel.
+ pPg->TRG_ClearMasterPage();
+ }
+ }
+ }
+
+ } else {
+ OSL_FAIL("SdrModel::Merge(): Drawing page not found in SourceModel.");
+ }
+ nDestPos++;
+ if (bReverse) nSourcePos--;
+ else if (bTreadSourceAsConst) nSourcePos++;
+ nMergeCount--;
+ }
+ }
+
+ pMasterMap.reset();
+ pMasterNeed.reset();
+
+ m_bMPgNumsDirty=true;
+ m_bPagNumsDirty=true;
+
+ SetChanged();
+ // TODO: Missing: merging and mapping of layers
+ // at the objects as well as at the MasterPageDescriptors
+ if (bUndo) EndUndo();
+}
+
+void SdrModel::SetStarDrawPreviewMode(bool bPreview)
+{
+ if (!bPreview && m_bStarDrawPreviewMode && GetPageCount())
+ {
+ // Resetting is not allowed, because the Model might not be loaded completely
+ SAL_WARN("svx", "SdrModel::SetStarDrawPreviewMode(): Resetting not allowed, because Model might not be complete.");
+ }
+ else
+ {
+ m_bStarDrawPreviewMode = bPreview;
+ }
+}
+
+void SdrModel::SetTheme(std::unique_ptr<svx::Theme> pTheme) { mpImpl->mpTheme = std::move(pTheme); }
+
+svx::Theme* SdrModel::GetTheme() { return mpImpl->mpTheme.get(); }
+
+uno::Reference< uno::XInterface > const & SdrModel::getUnoModel()
+{
+ if( !mxUnoModel.is() )
+ mxUnoModel = createUnoModel();
+
+ return mxUnoModel;
+}
+
+void SdrModel::setUnoModel( const css::uno::Reference< css::uno::XInterface >& xModel )
+{
+ mxUnoModel = xModel;
+}
+
+void SdrModel::adaptSizeAndBorderForAllPages(
+ const Size& /*rNewSize*/,
+ tools::Long /*nLeft*/,
+ tools::Long /*nRight*/,
+ tools::Long /*nUpper*/,
+ tools::Long /*nLower*/)
+{
+ // base implementation does currently nothing. It may be added if needed,
+ // but we are on SdrModel level here, thus probably have not enough information
+ // to do this for higher-level (derived) Models (e.g. Draw/Impress)
+}
+
+uno::Reference< uno::XInterface > SdrModel::createUnoModel()
+{
+ OSL_FAIL( "SdrModel::createUnoModel() - base implementation should not be called!" );
+ css::uno::Reference< css::uno::XInterface > xInt;
+ return xInt;
+}
+
+void SdrModel::setLock( bool bLock )
+{
+ if( mbModelLocked != bLock )
+ {
+ // #i120437# need to set first, else ImpReformatAllEdgeObjects will do nothing
+ mbModelLocked = bLock;
+
+ if( !bLock )
+ {
+ ImpReformatAllEdgeObjects();
+ }
+ }
+}
+
+
+void SdrModel::MigrateItemSet( const SfxItemSet* pSourceSet, SfxItemSet* pDestSet, SdrModel* pNewModelel )
+{
+ assert(pNewModelel != nullptr);
+ if( !(pSourceSet && pDestSet && (pSourceSet != pDestSet )) )
+ return;
+
+ SfxWhichIter aWhichIter(*pSourceSet);
+ sal_uInt16 nWhich(aWhichIter.FirstWhich());
+ const SfxPoolItem *pPoolItem;
+
+ while(nWhich)
+ {
+ if(SfxItemState::SET == aWhichIter.GetItemState(false, &pPoolItem))
+ {
+ std::unique_ptr<SfxPoolItem> pResultItem;
+
+ switch( nWhich )
+ {
+ case XATTR_FILLBITMAP:
+ pResultItem = static_cast<const XFillBitmapItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
+ break;
+ case XATTR_LINEDASH:
+ pResultItem = static_cast<const XLineDashItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
+ break;
+ case XATTR_LINESTART:
+ pResultItem = static_cast<const XLineStartItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
+ break;
+ case XATTR_LINEEND:
+ pResultItem = static_cast<const XLineEndItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
+ break;
+ case XATTR_FILLGRADIENT:
+ pResultItem = static_cast<const XFillGradientItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
+ break;
+ case XATTR_FILLFLOATTRANSPARENCE:
+ // allow all kinds of XFillFloatTransparenceItem to be set
+ pResultItem = static_cast<const XFillFloatTransparenceItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
+ break;
+ case XATTR_FILLHATCH:
+ pResultItem = static_cast<const XFillHatchItem*>(pPoolItem)->checkForUniqueItem( pNewModelel );
+ break;
+ }
+
+ // set item
+ if( pResultItem )
+ pDestSet->Put(std::move(pResultItem));
+ else
+ pDestSet->Put(*pPoolItem);
+ }
+ nWhich = aWhichIter.NextWhich();
+ }
+}
+
+
+void SdrModel::SetForbiddenCharsTable(const std::shared_ptr<SvxForbiddenCharactersTable>& xForbiddenChars)
+{
+ mpForbiddenCharactersTable = xForbiddenChars;
+
+ ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
+ ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
+}
+
+
+void SdrModel::SetCharCompressType( CharCompressType nType )
+{
+ if( nType != mnCharCompressType )
+ {
+ mnCharCompressType = nType;
+ ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
+ ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
+ }
+}
+
+void SdrModel::SetKernAsianPunctuation( bool bEnabled )
+{
+ if( mbKernAsianPunctuation != bEnabled )
+ {
+ mbKernAsianPunctuation = bEnabled;
+ ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
+ ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
+ }
+}
+
+void SdrModel::SetAddExtLeading( bool bEnabled )
+{
+ if( mbAddExtLeading != bEnabled )
+ {
+ mbAddExtLeading = bEnabled;
+ ImpSetOutlinerDefaults( m_pDrawOutliner.get() );
+ ImpSetOutlinerDefaults( m_pHitTestOutliner.get() );
+ }
+}
+
+void SdrModel::SetAnchoredTextOverflowLegacy(bool bEnabled)
+{
+ mpImpl->mbAnchoredTextOverflowLegacy = bEnabled;
+}
+
+bool SdrModel::IsAnchoredTextOverflowLegacy() const
+{
+ return mpImpl->mbAnchoredTextOverflowLegacy;
+}
+
+void SdrModel::ReformatAllTextObjects()
+{
+ ImpReformatAllTextObjects();
+}
+
+std::unique_ptr<SdrOutliner> SdrModel::createOutliner( OutlinerMode nOutlinerMode )
+{
+ if( !mpOutlinerCache )
+ mpOutlinerCache.reset(new SdrOutlinerCache(this));
+
+ return mpOutlinerCache->createOutliner( nOutlinerMode );
+}
+
+std::vector<SdrOutliner*> SdrModel::GetActiveOutliners() const
+{
+ std::vector< SdrOutliner* > aRet(mpOutlinerCache ? mpOutlinerCache->GetActiveOutliners() : std::vector< SdrOutliner* >());
+ aRet.push_back(m_pDrawOutliner.get());
+ aRet.push_back(m_pHitTestOutliner.get());
+
+ return aRet;
+}
+
+void SdrModel::disposeOutliner( std::unique_ptr<SdrOutliner> pOutliner )
+{
+ if( mpOutlinerCache )
+ mpOutlinerCache->disposeOutliner( std::move(pOutliner) );
+}
+
+SvxNumType SdrModel::GetPageNumType() const
+{
+ return SVX_NUM_ARABIC;
+}
+
+void SdrModel::ReadUserDataSequenceValue(const css::beans::PropertyValue* pValue)
+{
+ if (pValue->Name == "AnchoredTextOverflowLegacy")
+ {
+ bool bBool = false;
+ if (pValue->Value >>= bBool)
+ {
+ mpImpl->mbAnchoredTextOverflowLegacy = bBool;
+ }
+ }
+}
+
+template <typename T>
+static void addPair(std::vector< std::pair< OUString, Any > >& aUserData, const OUString& name, const T val)
+{
+ aUserData.push_back(std::pair< OUString, Any >(name, css::uno::Any(val)));
+}
+
+void SdrModel::WriteUserDataSequence(css::uno::Sequence < css::beans::PropertyValue >& rValues)
+{
+ std::vector< std::pair< OUString, Any > > aUserData;
+ addPair(aUserData, "AnchoredTextOverflowLegacy", IsAnchoredTextOverflowLegacy());
+
+ const sal_Int32 nOldLength = rValues.getLength();
+ rValues.realloc(nOldLength + aUserData.size());
+
+ css::beans::PropertyValue* pValue = &(rValues.getArray()[nOldLength]);
+
+ for (const auto &aIter : aUserData)
+ {
+ pValue->Name = aIter.first;
+ pValue->Value = aIter.second;
+ ++pValue;
+ }
+}
+
+const SdrPage* SdrModel::GetPage(sal_uInt16 nPgNum) const
+{
+ return nPgNum < maPages.size() ? maPages[nPgNum].get() : nullptr;
+}
+
+SdrPage* SdrModel::GetPage(sal_uInt16 nPgNum)
+{
+ return nPgNum < maPages.size() ? maPages[nPgNum].get() : nullptr;
+}
+
+sal_uInt16 SdrModel::GetPageCount() const
+{
+ return sal_uInt16(maPages.size());
+}
+
+void SdrModel::PageListChanged()
+{
+}
+
+TextChain *SdrModel::GetTextChain() const
+{
+ return m_pTextChain.get();
+}
+
+const SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum) const
+{
+ DBG_ASSERT(nPgNum < maMasterPages.size(), "SdrModel::GetMasterPage: Access out of range (!)");
+ return maMasterPages[nPgNum].get();
+}
+
+SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum)
+{
+ DBG_ASSERT(nPgNum < maMasterPages.size(), "SdrModel::GetMasterPage: Access out of range (!)");
+ return maMasterPages[nPgNum].get();
+}
+
+sal_uInt16 SdrModel::GetMasterPageCount() const
+{
+ return sal_uInt16(maMasterPages.size());
+}
+
+void SdrModel::MasterPageListChanged()
+{
+}
+
+void SdrModel::SetSdrUndoManager( SfxUndoManager* pUndoManager )
+{
+ mpImpl->mpUndoManager = pUndoManager;
+}
+
+SfxUndoManager* SdrModel::GetSdrUndoManager() const
+{
+ return mpImpl->mpUndoManager;
+}
+
+SdrUndoFactory& SdrModel::GetSdrUndoFactory() const
+{
+ if( !mpImpl->mpUndoFactory )
+ mpImpl->mpUndoFactory = new SdrUndoFactory;
+ return *mpImpl->mpUndoFactory;
+}
+
+void SdrModel::SetSdrUndoFactory( SdrUndoFactory* pUndoFactory )
+{
+ if( pUndoFactory && (pUndoFactory != mpImpl->mpUndoFactory) )
+ {
+ delete mpImpl->mpUndoFactory;
+ mpImpl->mpUndoFactory = pUndoFactory;
+ }
+}
+
+void SdrModel::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrModel"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("maMasterPages"));
+ for (size_t i = 0; i < maMasterPages.size(); ++i)
+ {
+ if (const SdrPage* pPage = maMasterPages[i].get())
+ {
+ pPage->dumpAsXml(pWriter);
+ }
+ }
+ (void)xmlTextWriterEndElement(pWriter);
+
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("maPages"));
+ for (size_t i = 0; i < maPages.size(); ++i)
+ {
+ if (const SdrPage* pPage = maPages[i].get())
+ {
+ pPage->dumpAsXml(pWriter);
+ }
+ }
+ (void)xmlTextWriterEndElement(pWriter);
+
+ if (mpImpl->mpTheme)
+ {
+ mpImpl->mpTheme->dumpAsXml(pWriter);
+ }
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+const css::uno::Sequence< sal_Int8 >& SdrModel::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theSdrModelUnoTunnelImplementationId;
+ return theSdrModelUnoTunnelImplementationId.getSeq();
+}
+
+
+SdrHint::SdrHint(SdrHintKind eNewHint)
+: SfxHint(SfxHintId::ThisIsAnSdrHint),
+ meHint(eNewHint),
+ mpObj(nullptr),
+ mpPage(nullptr)
+{
+}
+
+SdrHint::SdrHint(SdrHintKind eNewHint, const SdrObject& rNewObj)
+: SfxHint(SfxHintId::ThisIsAnSdrHint),
+ meHint(eNewHint),
+ mpObj(&rNewObj),
+ mpPage(rNewObj.getSdrPageFromSdrObject())
+{
+}
+
+SdrHint::SdrHint(SdrHintKind eNewHint, const SdrPage* pPage)
+: SfxHint(SfxHintId::ThisIsAnSdrHint),
+ meHint(eNewHint),
+ mpObj(nullptr),
+ mpPage(pPage)
+{
+}
+
+SdrHint::SdrHint(SdrHintKind eNewHint, const SdrObject& rNewObj, const SdrPage* pPage)
+: SfxHint(SfxHintId::ThisIsAnSdrHint),
+ meHint(eNewHint),
+ mpObj(&rNewObj),
+ mpPage(pPage)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdmrkv.cxx b/svx/source/svdraw/svdmrkv.cxx
new file mode 100644
index 000000000..c298e1925
--- /dev/null
+++ b/svx/source/svdraw/svdmrkv.cxx
@@ -0,0 +1,2733 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdmrkv.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdotable.hxx>
+
+#include <osl/diagnose.h>
+#include <osl/thread.h>
+#include <rtl/strbuf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/xgrad.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflgrit.hxx>
+#include "gradtrns.hxx"
+#include <svx/xflftrit.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdundo.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/svdovirt.hxx>
+#include <sdr/overlay/overlayrollingrectangle.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdr/overlay/overlayselection.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrhittesthelper.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+#include <vcl/window.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <sfx2/lokcomponenthelpers.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+
+#include <array>
+
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+
+#include <boost/property_tree/json_parser.hpp>
+
+using namespace com::sun::star;
+
+// Migrate Marking of Objects, Points and GluePoints
+
+class ImplMarkingOverlay
+{
+ // The OverlayObjects
+ sdr::overlay::OverlayObjectList maObjects;
+
+ // The remembered second position in logical coordinates
+ basegfx::B2DPoint maSecondPosition;
+
+ // A flag to remember if the action is for unmarking.
+ bool mbUnmarking : 1;
+
+public:
+ ImplMarkingOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos, bool bUnmarking);
+
+ // The OverlayObjects are cleared using the destructor of OverlayObjectList.
+ // That destructor calls clear() at the list which removes all objects from the
+ // OverlayManager and deletes them.
+
+ void SetSecondPosition(const basegfx::B2DPoint& rNewPosition);
+ bool IsUnmarking() const { return mbUnmarking; }
+};
+
+ImplMarkingOverlay::ImplMarkingOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos, bool bUnmarking)
+: maSecondPosition(rStartPos),
+ mbUnmarking(bUnmarking)
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ return; // We do client-side object manipulation with the Kit API
+
+ for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
+ const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
+
+ if (xTargetOverlay.is())
+ {
+ std::unique_ptr<sdr::overlay::OverlayRollingRectangleStriped> pNew(new sdr::overlay::OverlayRollingRectangleStriped(
+ rStartPos, rStartPos, false));
+ xTargetOverlay->add(*pNew);
+ maObjects.append(std::move(pNew));
+ }
+ }
+}
+
+void ImplMarkingOverlay::SetSecondPosition(const basegfx::B2DPoint& rNewPosition)
+{
+ if(rNewPosition != maSecondPosition)
+ {
+ // apply to OverlayObjects
+ for(sal_uInt32 a(0); a < maObjects.count(); a++)
+ {
+ sdr::overlay::OverlayRollingRectangleStriped& rCandidate = static_cast< sdr::overlay::OverlayRollingRectangleStriped&>(maObjects.getOverlayObject(a));
+ rCandidate.setSecondPosition(rNewPosition);
+ }
+
+ // remember new position
+ maSecondPosition = rNewPosition;
+ }
+}
+
+class MarkingSubSelectionOverlay
+{
+ sdr::overlay::OverlayObjectList maObjects;
+
+public:
+ MarkingSubSelectionOverlay(const SdrPaintView& rView, std::vector<basegfx::B2DRectangle> const & rSelections)
+ {
+ if (comphelper::LibreOfficeKit::isActive())
+ return; // We do client-side object manipulation with the Kit API
+
+ for (sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
+ const rtl::Reference<sdr::overlay::OverlayManager>& xTargetOverlay = pCandidate->GetOverlayManager();
+
+ if (xTargetOverlay.is())
+ {
+ const Color aHighlightColor = SvtOptionsDrawinglayer::getHilightColor();
+
+ std::unique_ptr<sdr::overlay::OverlaySelection> pNew =
+ std::make_unique<sdr::overlay::OverlaySelection>(
+ sdr::overlay::OverlayType::Transparent,
+ aHighlightColor, std::vector(rSelections), false);
+
+ xTargetOverlay->add(*pNew);
+ maObjects.append(std::move(pNew));
+ }
+ }
+ }
+};
+
+SdrMarkView::SdrMarkView(SdrModel& rSdrModel, OutputDevice* pOut)
+ : SdrSnapView(rSdrModel, pOut)
+ , mpMarkedObj(nullptr)
+ , mpMarkedPV(nullptr)
+ , maHdlList(this)
+ , meDragMode(SdrDragMode::Move)
+ , meEditMode(SdrViewEditMode::Edit)
+ , meEditMode0(SdrViewEditMode::Edit)
+ , mbDesignMode(false)
+ , mbForceFrameHandles(false)
+ , mbPlusHdlAlways(false)
+ , mbInsPolyPoint(false)
+ , mbMarkedObjRectDirty(false)
+ , mbMrkPntDirty(false)
+ , mbMarkedPointsRectsDirty(false)
+ , mbMarkHandlesHidden(false)
+ , mbNegativeX(false)
+{
+
+ BrkMarkObj();
+ BrkMarkPoints();
+ BrkMarkGluePoints();
+
+ StartListening(rSdrModel);
+}
+
+SdrMarkView::~SdrMarkView()
+{
+ // Migrate selections
+ BrkMarkObj();
+ BrkMarkPoints();
+ BrkMarkGluePoints();
+}
+
+void SdrMarkView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ SdrHintKind eKind=pSdrHint->GetKind();
+ if (eKind==SdrHintKind::ObjectChange || eKind==SdrHintKind::ObjectInserted || eKind==SdrHintKind::ObjectRemoved)
+ {
+ mbMarkedObjRectDirty=true;
+ mbMarkedPointsRectsDirty=true;
+ }
+ }
+ SdrSnapView::Notify(rBC,rHint);
+}
+
+void SdrMarkView::ModelHasChanged()
+{
+ SdrPaintView::ModelHasChanged();
+ GetMarkedObjectListWriteAccess().SetNameDirty();
+ mbMarkedObjRectDirty=true;
+ mbMarkedPointsRectsDirty=true;
+ // Example: Obj is selected and maMarkedObjectList is sorted.
+ // In another View 2, the ObjOrder is changed (e. g. MovToTop())
+ // Then we need to re-sort MarkList.
+ GetMarkedObjectListWriteAccess().SetUnsorted();
+ SortMarkedObjects();
+ mbMrkPntDirty=true;
+ UndirtyMrkPnt();
+ SdrView* pV=static_cast<SdrView*>(this);
+ if (pV!=nullptr && !pV->IsDragObj() && !pV->IsInsObjPoint()) {
+ AdjustMarkHdl();
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ modelHasChangedLOKit();
+}
+
+void SdrMarkView::modelHasChangedLOKit()
+{
+ if (GetMarkedObjectCount() <= 0)
+ return;
+
+ //TODO: Is MarkedObjRect valid at this point?
+ tools::Rectangle aSelection(GetMarkedObjRect());
+ tools::Rectangle* pResultSelection;
+ if (aSelection.IsEmpty())
+ pResultSelection = nullptr;
+ else
+ {
+ sal_uInt32 nTotalPaintWindows = this->PaintWindowCount();
+ if (nTotalPaintWindows == 1)
+ {
+ const OutputDevice* pOut = this->GetFirstOutputDevice();
+ const vcl::Window* pWin = pOut ? pOut->GetOwnerWindow() : nullptr;
+ if (pWin && pWin->IsChart())
+ {
+ const vcl::Window* pViewShellWindow = GetSfxViewShell()->GetEditWindowForActiveOLEObj();
+ if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
+ {
+ Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
+ Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
+ aSelection.Move(aLogicOffset.getX(), aLogicOffset.getY());
+ }
+ }
+ }
+
+ // In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK.
+ if (mpMarkedPV)
+ {
+ if (OutputDevice* pOutputDevice = mpMarkedPV->GetView().GetFirstOutputDevice())
+ {
+ if (pOutputDevice->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ aSelection = o3tl::convert(aSelection, o3tl::Length::mm100, o3tl::Length::twip);
+ }
+ }
+
+ pResultSelection = &aSelection;
+
+ if (mbNegativeX)
+ {
+ // Convert to positive X doc-coordinates
+ tools::Long nTmp = aSelection.Left();
+ aSelection.SetLeft(-aSelection.Right());
+ aSelection.SetRight(-nTmp);
+ }
+ }
+
+ if (SfxViewShell* pViewShell = GetSfxViewShell())
+ SfxLokHelper::notifyInvalidation(pViewShell, pResultSelection);
+}
+
+bool SdrMarkView::IsAction() const
+{
+ return SdrSnapView::IsAction() || IsMarkObj() || IsMarkPoints() || IsMarkGluePoints();
+}
+
+void SdrMarkView::MovAction(const Point& rPnt)
+{
+ SdrSnapView::MovAction(rPnt);
+
+ if(IsMarkObj())
+ {
+ MovMarkObj(rPnt);
+ }
+ else if(IsMarkPoints())
+ {
+ MovMarkPoints(rPnt);
+ }
+ else if(IsMarkGluePoints())
+ {
+ MovMarkGluePoints(rPnt);
+ }
+}
+
+void SdrMarkView::EndAction()
+{
+ if(IsMarkObj())
+ {
+ EndMarkObj();
+ }
+ else if(IsMarkPoints())
+ {
+ EndMarkPoints();
+ }
+ else if(IsMarkGluePoints())
+ {
+ EndMarkGluePoints();
+ }
+
+ SdrSnapView::EndAction();
+}
+
+void SdrMarkView::BckAction()
+{
+ SdrSnapView::BckAction();
+ BrkMarkObj();
+ BrkMarkPoints();
+ BrkMarkGluePoints();
+}
+
+void SdrMarkView::BrkAction()
+{
+ SdrSnapView::BrkAction();
+ BrkMarkObj();
+ BrkMarkPoints();
+ BrkMarkGluePoints();
+}
+
+void SdrMarkView::TakeActionRect(tools::Rectangle& rRect) const
+{
+ if(IsMarkObj() || IsMarkPoints() || IsMarkGluePoints())
+ {
+ rRect = tools::Rectangle(maDragStat.GetStart(), maDragStat.GetNow());
+ }
+ else
+ {
+ SdrSnapView::TakeActionRect(rRect);
+ }
+}
+
+
+void SdrMarkView::ClearPageView()
+{
+ UnmarkAllObj();
+ SdrSnapView::ClearPageView();
+}
+
+void SdrMarkView::HideSdrPage()
+{
+ bool bMrkChg(false);
+
+ SdrPageView* pPageView = GetSdrPageView();
+ if (pPageView)
+ {
+ // break all creation actions when hiding page (#75081#)
+ BrkAction();
+
+ // Discard all selections on this page
+ bMrkChg = GetMarkedObjectListWriteAccess().DeletePageView(*pPageView);
+ }
+
+ SdrSnapView::HideSdrPage();
+
+ if(bMrkChg)
+ {
+ MarkListHasChanged();
+ AdjustMarkHdl();
+ }
+}
+
+
+void SdrMarkView::BegMarkObj(const Point& rPnt, bool bUnmark)
+{
+ BrkAction();
+
+ DBG_ASSERT(!mpMarkObjOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkObjOverlay (!)");
+
+ basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
+ mpMarkObjOverlay.reset(new ImplMarkingOverlay(*this, aStartPos, bUnmark));
+
+ maDragStat.Reset(rPnt);
+ maDragStat.NextPoint();
+ maDragStat.SetMinMove(mnMinMovLog);
+}
+
+void SdrMarkView::MovMarkObj(const Point& rPnt)
+{
+ if(IsMarkObj() && maDragStat.CheckMinMoved(rPnt))
+ {
+ maDragStat.NextMove(rPnt);
+ DBG_ASSERT(mpMarkObjOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
+ basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
+ mpMarkObjOverlay->SetSecondPosition(aNewPos);
+ }
+}
+
+bool SdrMarkView::EndMarkObj()
+{
+ bool bRetval(false);
+
+ if(IsMarkObj())
+ {
+ if(maDragStat.IsMinMoved())
+ {
+ tools::Rectangle aRect(maDragStat.GetStart(), maDragStat.GetNow());
+ aRect.Justify();
+ MarkObj(aRect, mpMarkObjOverlay->IsUnmarking());
+ bRetval = true;
+ }
+
+ // cleanup
+ BrkMarkObj();
+ }
+
+ return bRetval;
+}
+
+void SdrMarkView::BrkMarkObj()
+{
+ if(IsMarkObj())
+ {
+ DBG_ASSERT(mpMarkObjOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
+ mpMarkObjOverlay.reset();
+ }
+}
+
+
+bool SdrMarkView::BegMarkPoints(const Point& rPnt, bool bUnmark)
+{
+ if(HasMarkablePoints())
+ {
+ BrkAction();
+
+ DBG_ASSERT(!mpMarkPointsOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkPointsOverlay (!)");
+ basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
+ mpMarkPointsOverlay.reset(new ImplMarkingOverlay(*this, aStartPos, bUnmark));
+
+ maDragStat.Reset(rPnt);
+ maDragStat.NextPoint();
+ maDragStat.SetMinMove(mnMinMovLog);
+
+ return true;
+ }
+
+ return false;
+}
+
+void SdrMarkView::MovMarkPoints(const Point& rPnt)
+{
+ if(IsMarkPoints() && maDragStat.CheckMinMoved(rPnt))
+ {
+ maDragStat.NextMove(rPnt);
+
+ DBG_ASSERT(mpMarkPointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
+ basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
+ mpMarkPointsOverlay->SetSecondPosition(aNewPos);
+ }
+}
+
+bool SdrMarkView::EndMarkPoints()
+{
+ bool bRetval(false);
+
+ if(IsMarkPoints())
+ {
+ if(maDragStat.IsMinMoved())
+ {
+ tools::Rectangle aRect(maDragStat.GetStart(), maDragStat.GetNow());
+ aRect.Justify();
+ MarkPoints(&aRect, mpMarkPointsOverlay->IsUnmarking());
+
+ bRetval = true;
+ }
+
+ // cleanup
+ BrkMarkPoints();
+ }
+
+ return bRetval;
+}
+
+void SdrMarkView::BrkMarkPoints()
+{
+ if(IsMarkPoints())
+ {
+ DBG_ASSERT(mpMarkPointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
+ mpMarkPointsOverlay.reset();
+ }
+}
+
+
+bool SdrMarkView::BegMarkGluePoints(const Point& rPnt, bool bUnmark)
+{
+ if(HasMarkableGluePoints())
+ {
+ BrkAction();
+
+ DBG_ASSERT(!mpMarkGluePointsOverlay, "SdrMarkView::BegMarkObj: There exists a mpMarkGluePointsOverlay (!)");
+
+ basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
+ mpMarkGluePointsOverlay.reset(new ImplMarkingOverlay(*this, aStartPos, bUnmark));
+ maDragStat.Reset(rPnt);
+ maDragStat.NextPoint();
+ maDragStat.SetMinMove(mnMinMovLog);
+
+ return true;
+ }
+
+ return false;
+}
+
+void SdrMarkView::MovMarkGluePoints(const Point& rPnt)
+{
+ if(IsMarkGluePoints() && maDragStat.CheckMinMoved(rPnt))
+ {
+ maDragStat.NextMove(rPnt);
+
+ DBG_ASSERT(mpMarkGluePointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
+ basegfx::B2DPoint aNewPos(rPnt.X(), rPnt.Y());
+ mpMarkGluePointsOverlay->SetSecondPosition(aNewPos);
+ }
+}
+
+void SdrMarkView::EndMarkGluePoints()
+{
+ if(IsMarkGluePoints())
+ {
+ if(maDragStat.IsMinMoved())
+ {
+ tools::Rectangle aRect(maDragStat.GetStart(),maDragStat.GetNow());
+ aRect.Justify();
+ MarkGluePoints(&aRect, mpMarkGluePointsOverlay->IsUnmarking());
+ }
+
+ // cleanup
+ BrkMarkGluePoints();
+ }
+}
+
+void SdrMarkView::BrkMarkGluePoints()
+{
+ if(IsMarkGluePoints())
+ {
+ DBG_ASSERT(mpMarkGluePointsOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
+ mpMarkGluePointsOverlay.reset();
+ }
+}
+
+bool SdrMarkView::MarkableObjectsExceed( int n ) const
+{
+ SdrPageView* pPV = GetSdrPageView();
+ if (!pPV)
+ return false;
+
+ SdrObjList* pOL=pPV->GetObjList();
+ const size_t nObjCount = pOL->GetObjCount();
+ for (size_t nObjNum=0; nObjNum<nObjCount; ++nObjNum) {
+ SdrObject* pObj=pOL->GetObj(nObjNum);
+ if (IsObjMarkable(pObj,pPV) && --n<0)
+ return true;
+ }
+
+ return false;
+}
+
+void SdrMarkView::hideMarkHandles()
+{
+ if(!mbMarkHandlesHidden)
+ {
+ mbMarkHandlesHidden = true;
+ AdjustMarkHdl();
+ }
+}
+
+void SdrMarkView::showMarkHandles()
+{
+ if(mbMarkHandlesHidden)
+ {
+ mbMarkHandlesHidden = false;
+ AdjustMarkHdl();
+ }
+}
+
+bool SdrMarkView::ImpIsFrameHandles() const
+{
+ const size_t nMarkCount=GetMarkedObjectCount();
+ bool bFrmHdl=nMarkCount>static_cast<size_t>(mnFrameHandlesLimit) || mbForceFrameHandles;
+ bool bStdDrag=meDragMode==SdrDragMode::Move;
+ if (nMarkCount==1 && bStdDrag && bFrmHdl)
+ {
+ const SdrObject* pObj=GetMarkedObjectByIndex(0);
+ if (pObj && pObj->GetObjInventor()==SdrInventor::Default)
+ {
+ SdrObjKind nIdent=pObj->GetObjIdentifier();
+ if (nIdent==SdrObjKind::Line || nIdent==SdrObjKind::Edge || nIdent==SdrObjKind::Caption || nIdent==SdrObjKind::Measure || nIdent==SdrObjKind::CustomShape || nIdent==SdrObjKind::Table )
+ {
+ bFrmHdl=false;
+ }
+ }
+ }
+ if (!bStdDrag && !bFrmHdl) {
+ // all other drag modes only with FrameHandles
+ bFrmHdl=true;
+ if (meDragMode==SdrDragMode::Rotate) {
+ // when rotating, use ObjOwn drag, if there's at least 1 PolyObj
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount && bFrmHdl; ++nMarkNum) {
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+ bFrmHdl=!pObj->IsPolyObj();
+ }
+ }
+ }
+ if (!bFrmHdl) {
+ // FrameHandles, if at least 1 Obj can't do SpecialDrag
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bFrmHdl; ++nMarkNum) {
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+ bFrmHdl=!pObj->hasSpecialDrag();
+ }
+ }
+
+ // no FrameHdl for crop
+ if(bFrmHdl && SdrDragMode::Crop == meDragMode)
+ {
+ bFrmHdl = false;
+ }
+
+ return bFrmHdl;
+}
+
+namespace
+{
+std::u16string_view lcl_getDragMethodServiceName( std::u16string_view rCID )
+{
+ std::u16string_view aRet;
+
+ size_t nIndexStart = rCID.find( u"DragMethod=" );
+ if( nIndexStart != std::u16string_view::npos )
+ {
+ nIndexStart = rCID.find( '=', nIndexStart );
+ if( nIndexStart != std::u16string_view::npos )
+ {
+ nIndexStart++;
+ size_t nNextSlash = rCID.find( '/', nIndexStart );
+ if( nNextSlash != std::u16string_view::npos )
+ {
+ sal_Int32 nIndexEnd = nNextSlash;
+ size_t nNextColon = rCID.find( ':', nIndexStart );
+ if( nNextColon == std::u16string_view::npos || nNextColon < nNextSlash )
+ nIndexEnd = nNextColon;
+ aRet = rCID.substr(nIndexStart,nIndexEnd-nIndexStart);
+ }
+ }
+ }
+ return aRet;
+}
+
+std::u16string_view lcl_getDragParameterString( std::u16string_view rCID )
+{
+ std::u16string_view aRet;
+
+ size_t nIndexStart = rCID.find( u"DragParameter=" );
+ if( nIndexStart != std::u16string_view::npos )
+ {
+ nIndexStart = rCID.find( '=', nIndexStart );
+ if( nIndexStart != std::u16string_view::npos )
+ {
+ nIndexStart++;
+ size_t nNextSlash = rCID.find( '/', nIndexStart );
+ if( nNextSlash != std::u16string_view::npos )
+ {
+ sal_Int32 nIndexEnd = nNextSlash;
+ size_t nNextColon = rCID.find( ':', nIndexStart );
+ if( nNextColon == std::u16string_view::npos || nNextColon < nNextSlash )
+ nIndexEnd = nNextColon;
+ aRet = rCID.substr(nIndexStart,nIndexEnd-nIndexStart);
+ }
+ }
+ }
+ return aRet;
+}
+} // anonymous namespace
+
+bool SdrMarkView::dumpGluePointsToJSON(boost::property_tree::ptree& rTree)
+{
+ bool result = false;
+ tools::Long nSignX = mbNegativeX ? -1 : 1;
+ if (OutputDevice* pOutDev = mpMarkedPV ? mpMarkedPV->GetView().GetFirstOutputDevice() : nullptr)
+ {
+ bool bConvertUnit = false;
+ if (pOutDev->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ bConvertUnit = true;
+ const SdrObjList* pOL = mpMarkedPV->GetObjList();
+ if (!pOL)
+ return false;
+ const size_t nObjCount = pOL->GetObjCount();
+ boost::property_tree::ptree elements;
+ for (size_t nObjNum = 0; nObjNum < nObjCount; ++nObjNum)
+ {
+ SdrObject* pObj = pOL->GetObj(nObjNum);
+ if (!pObj)
+ continue;
+ if (pObj == GetMarkedObjectByIndex(0))
+ continue;
+ const SdrGluePointList* pGPL = pObj->GetGluePointList();
+ bool VertexObject = !(pGPL && pGPL->GetCount());
+ const size_t count = !VertexObject ? pGPL->GetCount() : 4;
+ boost::property_tree::ptree object;
+ boost::property_tree::ptree points;
+ for (size_t i = 0; i < count; ++i)
+ {
+ boost::property_tree::ptree node;
+ boost::property_tree::ptree point;
+ const SdrGluePoint& rGP = !VertexObject ? (*pGPL)[i] : pObj->GetVertexGluePoint(i);
+ Point rPoint = rGP.GetAbsolutePos(*pObj);
+ if (bConvertUnit)
+ {
+ rPoint = o3tl::convert(rPoint, o3tl::Length::mm100, o3tl::Length::twip);
+ }
+ point.put("x", nSignX * rPoint.getX());
+ point.put("y", rPoint.getY());
+ node.add_child("point", point);
+ points.push_back(std::make_pair("", node));
+ }
+ basegfx::B2DVector aGridOffset(0.0, 0.0);
+ Point objLogicRectTopLeft = pObj->GetLogicRect().TopLeft();
+ if(getPossibleGridOffsetForPosition(aGridOffset, basegfx::B2DPoint(objLogicRectTopLeft.X(), objLogicRectTopLeft.Y()), GetSdrPageView()))
+ {
+ Point p(aGridOffset.getX(), aGridOffset.getY());
+ if (bConvertUnit)
+ {
+ p = o3tl::convert(p, o3tl::Length::mm100, o3tl::Length::twip);
+ }
+ boost::property_tree::ptree gridOffset;
+ gridOffset.put("x", nSignX * p.getX());
+ gridOffset.put("y", p.getY());
+ object.add_child("gridoffset", gridOffset);
+ }
+ object.put("ordnum", pObj->GetOrdNum());
+ object.add_child("gluepoints", points);
+ elements.push_back(std::make_pair("", object));
+ result = true;
+ }
+ rTree.add_child("shapes", elements);
+ }
+ return result;
+}
+
+void SdrMarkView::SetMarkHandlesForLOKit(tools::Rectangle const & rRect, const SfxViewShell* pOtherShell)
+{
+ SfxViewShell* pViewShell = GetSfxViewShell();
+
+ tools::Rectangle aSelection(rRect);
+ tools::Long nSignX = mbNegativeX ? -1 : 1;
+ bool bIsChart = false;
+ Point addLogicOffset(0, 0);
+ bool convertMapMode = false;
+ if (!rRect.IsEmpty())
+ {
+ sal_uInt32 nTotalPaintWindows = this->PaintWindowCount();
+ if (nTotalPaintWindows == 1)
+ {
+ const OutputDevice* pOut = this->GetFirstOutputDevice();
+ const vcl::Window* pWin = pOut ? pOut->GetOwnerWindow() : nullptr;
+ if (pWin && pWin->IsChart())
+ {
+ bIsChart = true;
+ const vcl::Window* pViewShellWindow = GetSfxViewShell()->GetEditWindowForActiveOLEObj();
+ if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
+ {
+ Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
+ if (mbNegativeX && AllSettings::GetLayoutRTL())
+ {
+ // mbNegativeX is set only for Calc in RTL mode.
+ // If global RTL flag is set, vcl-window X offset of chart window is
+ // mirrored w.r.t parent window rectangle. This needs to be reverted.
+ aOffsetPx.setX(pViewShellWindow->GetOutOffXPixel() + pViewShellWindow->GetSizePixel().Width()
+ - pWin->GetOutOffXPixel() - pWin->GetSizePixel().Width());
+ }
+ Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
+ addLogicOffset = aLogicOffset;
+ aSelection.Move(aLogicOffset.getX(), aLogicOffset.getY());
+ }
+ }
+ }
+ }
+
+ if (!aSelection.IsEmpty())
+ {
+ // In case the map mode is in 100th MM, then need to convert the coordinates over to twips for LOK.
+ if (mpMarkedPV)
+ {
+ if (OutputDevice* pOutputDevice = mpMarkedPV->GetView().GetFirstOutputDevice())
+ {
+ if (pOutputDevice->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ {
+ aSelection = o3tl::convert(aSelection, o3tl::Length::mm100, o3tl::Length::twip);
+ convertMapMode = true;
+ }
+ }
+ }
+
+ // hide the text selection too
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "");
+ }
+
+ {
+ OString sSelectionText;
+ OString sSelectionTextView;
+ boost::property_tree::ptree aTableJsonTree;
+ boost::property_tree::ptree aGluePointsTree;
+ bool bTableSelection = false;
+ bool bConnectorSelection = false;
+
+ if (mpMarkedObj && mpMarkedObj->GetObjIdentifier() == SdrObjKind::Table)
+ {
+ auto& rTableObject = dynamic_cast<sdr::table::SdrTableObj&>(*mpMarkedObj);
+ bTableSelection = rTableObject.createTableEdgesJson(aTableJsonTree);
+ }
+ if (mpMarkedObj && mpMarkedObj->GetObjIdentifier() == SdrObjKind::Edge)
+ {
+ bConnectorSelection = dumpGluePointsToJSON(aGluePointsTree);
+ }
+ if (GetMarkedObjectCount())
+ {
+ SdrMark* pM = GetSdrMarkByIndex(0);
+ SdrObject* pO = pM->GetMarkedSdrObj();
+ Degree100 nRotAngle = pO->GetRotateAngle();
+ // true if we are dealing with a RotGrfFlyFrame
+ // (SwVirtFlyDrawObj with a SwGrfNode)
+ bool bWriterGraphic = pO->HasLimitedRotation();
+
+ OStringBuffer aExtraInfo;
+ OString handleArrayStr;
+
+ aExtraInfo.append("{\"id\":\"");
+ aExtraInfo.append(reinterpret_cast<sal_IntPtr>(pO));
+ aExtraInfo.append("\",\"type\":");
+ aExtraInfo.append(static_cast<sal_Int32>(pO->GetObjIdentifier()));
+
+ // In core, the gridOffset is calculated based on the LogicRect's TopLeft coordinate
+ // In online, we have the SnapRect and we calculate it based on its TopLeft coordinate
+ // SnapRect's TopLeft and LogicRect's TopLeft match unless there is rotation
+ // but the rotation is not applied to the LogicRect. Therefore,
+ // what we calculate in online does not match with the core in case of the rotation.
+ // Here we can send the correct gridOffset in the selection callback, this way
+ // whether the shape is rotated or not, we will always have the correct gridOffset
+ // Note that the gridOffset is calculated from the first selected obj
+ basegfx::B2DVector aGridOffset(0.0, 0.0);
+ if(getPossibleGridOffsetForSdrObject(aGridOffset, GetMarkedObjectByIndex(0), GetSdrPageView()))
+ {
+ Point p(aGridOffset.getX(), aGridOffset.getY());
+ if (convertMapMode)
+ p = o3tl::convert(p, o3tl::Length::mm100, o3tl::Length::twip);
+ aExtraInfo.append(",\"gridOffsetX\":");
+ aExtraInfo.append(nSignX * p.getX());
+ aExtraInfo.append(",\"gridOffsetY\":");
+ aExtraInfo.append(p.getY());
+ }
+
+ if (bWriterGraphic)
+ {
+ aExtraInfo.append(", \"isWriterGraphic\": true");
+ }
+ else if (bIsChart)
+ {
+ LokChartHelper aChartHelper(pViewShell);
+ css::uno::Reference<css::frame::XController>& xChartController = aChartHelper.GetXController();
+ css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier( xChartController, uno::UNO_QUERY);
+ if (xSelectionSupplier.is())
+ {
+ uno::Any aSel = xSelectionSupplier->getSelection();
+ OUString aValue;
+ if (aSel >>= aValue)
+ {
+ OString aObjectCID(aValue.getStr(), aValue.getLength(), osl_getThreadTextEncoding());
+ const std::vector<OString> aProps{"Draggable", "Resizable", "Rotatable"};
+ for (const auto& rProp: aProps)
+ {
+ sal_Int32 nPos = aObjectCID.indexOf(rProp);
+ if (nPos == -1) continue;
+ nPos += rProp.getLength() + 1; // '='
+ if (aExtraInfo.getLength() > 2) // != "{ "
+ aExtraInfo.append(", ");
+ aExtraInfo.append("\"is");
+ aExtraInfo.append(rProp);
+ aExtraInfo.append("\": ");
+ aExtraInfo.append(OString::boolean(aObjectCID[nPos] == '1'));
+ }
+
+ std::u16string_view sDragMethod = lcl_getDragMethodServiceName(aValue);
+ if (sDragMethod == u"PieSegmentDragging")
+ {
+ // old initial offset inside the CID returned by xSelectionSupplier->getSelection()
+ // after a pie segment dragging; using SdrObject::GetName for getting a CID with the updated offset
+ aValue = pO->GetName();
+ std::u16string_view sDragParameters = lcl_getDragParameterString(aValue);
+ if (!sDragParameters.empty())
+ {
+ aExtraInfo.append(", \"dragInfo\": { ");
+ aExtraInfo.append("\"dragMethod\": \"");
+ aExtraInfo.append(OUString(sDragMethod).toUtf8());
+ aExtraInfo.append("\"");
+
+ sal_Int32 nStartIndex = 0;
+ std::array<int, 5> aDragParameters;
+ for (auto& rParam : aDragParameters)
+ {
+ std::u16string_view sParam = o3tl::getToken(sDragParameters, 0, ',', nStartIndex);
+ if (sParam.empty())
+ break;
+ rParam = o3tl::toInt32(sParam);
+ }
+
+ // initial offset in %
+ if (aDragParameters[0] < 0)
+ aDragParameters[0] = 0;
+ else if (aDragParameters[0] > 100)
+ aDragParameters[0] = 100;
+
+ aExtraInfo.append(", \"initialOffset\": ");
+ aExtraInfo.append(static_cast<sal_Int32>(aDragParameters[0]));
+
+ // drag direction constraint
+ Point aMinPos(aDragParameters[1], aDragParameters[2]);
+ Point aMaxPos(aDragParameters[3], aDragParameters[4]);
+ Point aDragDirection = aMaxPos - aMinPos;
+ aDragDirection = o3tl::convert(aDragDirection, o3tl::Length::mm100, o3tl::Length::twip);
+
+ aExtraInfo.append(", \"dragDirection\": [");
+ aExtraInfo.append(aDragDirection.toString());
+ aExtraInfo.append("]");
+
+ // polygon approximating the pie segment or donut segment
+ if (pO->GetObjIdentifier() == SdrObjKind::PathFill)
+ {
+ const basegfx::B2DPolyPolygon aPolyPolygon(pO->TakeXorPoly());
+ if (aPolyPolygon.count() == 1)
+ {
+ const basegfx::B2DPolygon aPolygon = aPolyPolygon.getB2DPolygon(0);
+ if (sal_uInt32 nPolySize = aPolygon.count())
+ {
+ const OutputDevice* pOut = this->GetFirstOutputDevice();
+ const vcl::Window* pWin = pOut ? pOut->GetOwnerWindow() : nullptr;
+ const vcl::Window* pViewShellWindow = pViewShell->GetEditWindowForActiveOLEObj();
+ if (pWin && pViewShellWindow && pViewShellWindow->IsAncestorOf(*pWin))
+ {
+ // in the following code escaping sequences used inside raw literal strings
+ // are for making them understandable by the JSON parser
+
+ Point aOffsetPx = pWin->GetOffsetPixelFrom(*pViewShellWindow);
+ Point aLogicOffset = pWin->PixelToLogic(aOffsetPx);
+ OString sPolygonElem("<polygon points=\\\"");
+ for (sal_uInt32 nIndex = 0; nIndex < nPolySize; ++nIndex)
+ {
+ const basegfx::B2DPoint aB2Point = aPolygon.getB2DPoint(nIndex);
+ Point aPoint(aB2Point.getX(), aB2Point.getY());
+ aPoint.Move(aLogicOffset.getX(), aLogicOffset.getY());
+ if (mbNegativeX)
+ aPoint.setX(-aPoint.X());
+ if (nIndex > 0)
+ sPolygonElem += " ";
+ sPolygonElem += aPoint.toString();
+ }
+ sPolygonElem += R"elem(\" style=\"stroke: none; fill: rgb(114,159,207); fill-opacity: 0.8\"/>)elem";
+
+ OString sSVGElem = R"elem(<svg version=\"1.2\" width=\")elem" +
+ OString::number(aSelection.GetWidth() / 100.0) +
+ R"elem(mm\" height=\")elem" +
+ OString::number(aSelection.GetHeight() / 100.0) +
+ R"elem(mm\" viewBox=\")elem" +
+ aSelection.toString() +
+ R"elem(\" preserveAspectRatio=\"xMidYMid\" xmlns=\"http://www.w3.org/2000/svg\">)elem";
+
+ aExtraInfo.append(", \"svg\": \"");
+ aExtraInfo.append(sSVGElem);
+ aExtraInfo.append("\\n ");
+ aExtraInfo.append(sPolygonElem);
+ aExtraInfo.append("\\n</svg>");
+ aExtraInfo.append("\""); // svg
+ }
+ }
+ }
+ }
+ aExtraInfo.append("}"); // dragInfo
+ }
+ }
+ }
+ }
+ }
+ if (!bTableSelection && !pOtherShell && maHdlList.GetHdlCount())
+ {
+ boost::property_tree::ptree responseJSON;
+ boost::property_tree::ptree others;
+ boost::property_tree::ptree anchor;
+ boost::property_tree::ptree rectangle;
+ boost::property_tree::ptree poly;
+ boost::property_tree::ptree custom;
+ boost::property_tree::ptree nodes;
+ for (size_t i = 0; i < maHdlList.GetHdlCount(); i++)
+ {
+ SdrHdl *pHdl = maHdlList.GetHdl(i);
+ boost::property_tree::ptree child;
+ boost::property_tree::ptree point;
+ sal_Int32 kind = static_cast<sal_Int32>(pHdl->GetKind());
+ child.put("id", pHdl->GetObjHdlNum());
+ child.put("kind", kind);
+ child.put("pointer", static_cast<sal_Int32>(pHdl->GetPointer()));
+ Point pHdlPos = pHdl->GetPos();
+ pHdlPos.Move(addLogicOffset.getX(), addLogicOffset.getY());
+ if (convertMapMode)
+ {
+ pHdlPos = o3tl::convert(pHdlPos, o3tl::Length::mm100, o3tl::Length::twip);
+ }
+ point.put("x", pHdlPos.getX());
+ point.put("y", pHdlPos.getY());
+ child.add_child("point", point);
+ const auto node = std::make_pair("", child);
+ boost::property_tree::ptree* selectedNode = nullptr;
+ if (kind >= static_cast<sal_Int32>(SdrHdlKind::UpperLeft) && kind <= static_cast<sal_Int32>(SdrHdlKind::LowerRight))
+ {
+ selectedNode = &rectangle;
+ }
+ else if (kind == static_cast<sal_Int32>(SdrHdlKind::Poly))
+ {
+ selectedNode = &poly;
+ }
+ else if (kind == static_cast<sal_Int32>(SdrHdlKind::CustomShape1))
+ {
+ selectedNode = &custom;
+ }
+ else if (kind == static_cast<sal_Int32>(SdrHdlKind::Anchor) || kind == static_cast<sal_Int32>(SdrHdlKind::Anchor_TR))
+ {
+ if (getSdrModelFromSdrView().IsWriter())
+ selectedNode = &anchor;
+ else
+ // put it to others as we don't render them except in writer
+ selectedNode = &others;
+ }
+ else
+ {
+ selectedNode = &others;
+ }
+ std::string sKind = std::to_string(kind);
+ boost::optional< boost::property_tree::ptree& > kindNode = selectedNode->get_child_optional(sKind.c_str());
+ if (!kindNode)
+ {
+ boost::property_tree::ptree newChild;
+ newChild.push_back(node);
+ selectedNode->add_child(sKind.c_str(), newChild);
+ }
+ else
+ kindNode.get().push_back(node);
+ }
+ nodes.add_child("rectangle", rectangle);
+ nodes.add_child("poly", poly);
+ nodes.add_child("custom", custom);
+ nodes.add_child("anchor", anchor);
+ nodes.add_child("others", others);
+ responseJSON.add_child("kinds", nodes);
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, responseJSON, /*pretty=*/ false);
+ handleArrayStr = ", \"handles\":";
+ handleArrayStr = handleArrayStr + aStream.str().c_str();
+ if (bConnectorSelection)
+ {
+ aStream.str("");
+ boost::property_tree::write_json(aStream, aGluePointsTree, /*pretty=*/ false);
+ handleArrayStr = handleArrayStr + ", \"GluePoints\":";
+ handleArrayStr = handleArrayStr + aStream.str().c_str();
+ }
+ }
+
+ if (mbNegativeX)
+ {
+ tools::Rectangle aNegatedRect(aSelection);
+ aNegatedRect.SetLeft(-aNegatedRect.Left());
+ aNegatedRect.SetRight(-aNegatedRect.Right());
+ aNegatedRect.Justify();
+ sSelectionText = aNegatedRect.toString() +
+ ", " + OString::number(nRotAngle.get());
+ }
+ else
+ {
+ sSelectionText = aSelection.toString() +
+ ", " + OString::number(nRotAngle.get());
+ }
+ if (!aExtraInfo.isEmpty())
+ {
+ sSelectionTextView = sSelectionText + ", " + aExtraInfo + "}";
+ aExtraInfo.append(handleArrayStr);
+ aExtraInfo.append("}");
+ sSelectionText += ", " + aExtraInfo;
+ aExtraInfo.setLength(0);
+ }
+ }
+
+ if (sSelectionText.isEmpty())
+ {
+ sSelectionText = "EMPTY";
+ sSelectionTextView = "EMPTY";
+ }
+
+ if (bTableSelection)
+ {
+ boost::property_tree::ptree aTableRectangle;
+ aTableRectangle.put("x", aSelection.Left());
+ aTableRectangle.put("y", aSelection.Top());
+ aTableRectangle.put("width", aSelection.GetWidth());
+ aTableRectangle.put("height", aSelection.GetHeight());
+ aTableJsonTree.push_back(std::make_pair("rectangle", aTableRectangle));
+
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aTableJsonTree);
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TABLE_SELECTED, aStream.str().c_str());
+ }
+ else if (!getSdrModelFromSdrView().IsWriter())
+ {
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TABLE_SELECTED, "{}");
+ }
+
+ if (pOtherShell)
+ {
+ // Another shell wants to know about our existing
+ // selection.
+ if (pViewShell != pOtherShell)
+ SfxLokHelper::notifyOtherView(pViewShell, pOtherShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", sSelectionTextView);
+ }
+ else
+ {
+ // We have a new selection, so both pViewShell and the
+ // other views want to know about it.
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_GRAPHIC_SELECTION, sSelectionText.getStr());
+ SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", sSelectionTextView);
+ }
+ }
+}
+
+void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell)
+{
+ // remember old focus handle values to search for it again
+ const SdrHdl* pSaveOldFocusHdl = maHdlList.GetFocusHdl();
+ bool bSaveOldFocus(false);
+ sal_uInt32 nSavePolyNum(0), nSavePointNum(0);
+ SdrHdlKind eSaveKind(SdrHdlKind::Move);
+ SdrObject* pSaveObj = nullptr;
+
+ mpMarkingSubSelectionOverlay.reset();
+
+ if(pSaveOldFocusHdl
+ && pSaveOldFocusHdl->GetObj()
+ && dynamic_cast<const SdrPathObj*>(pSaveOldFocusHdl->GetObj()) != nullptr
+ && (pSaveOldFocusHdl->GetKind() == SdrHdlKind::Poly || pSaveOldFocusHdl->GetKind() == SdrHdlKind::BezierWeight))
+ {
+ bSaveOldFocus = true;
+ nSavePolyNum = pSaveOldFocusHdl->GetPolyNum();
+ nSavePointNum = pSaveOldFocusHdl->GetPointNum();
+ pSaveObj = pSaveOldFocusHdl->GetObj();
+ eSaveKind = pSaveOldFocusHdl->GetKind();
+ }
+
+ // delete/clear all handles. This will always be done, even with areMarkHandlesHidden()
+ maHdlList.Clear();
+ maHdlList.SetRotateShear(meDragMode==SdrDragMode::Rotate);
+ maHdlList.SetDistortShear(meDragMode==SdrDragMode::Shear);
+ mpMarkedObj=nullptr;
+ mpMarkedPV=nullptr;
+
+ // are handles enabled at all? Create only then
+ if(areMarkHandlesHidden())
+ return;
+
+ // There can be multiple mark views, but we're only interested in the one that has a window associated.
+ const bool bTiledRendering = comphelper::LibreOfficeKit::isActive() && GetFirstOutputDevice() && GetFirstOutputDevice()->GetOutDevType() == OUTDEV_WINDOW;
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ bool bStdDrag=meDragMode==SdrDragMode::Move;
+ bool bSingleTextObjMark=false;
+ bool bLimitedRotation(false);
+
+ if (nMarkCount==1)
+ {
+ mpMarkedObj=GetMarkedObjectByIndex(0);
+
+ if(nullptr != mpMarkedObj)
+ {
+ bSingleTextObjMark =
+ dynamic_cast<const SdrTextObj*>( mpMarkedObj) != nullptr &&
+ static_cast<SdrTextObj*>(mpMarkedObj)->IsTextFrame();
+
+ // RotGrfFlyFrame: we may have limited rotation
+ bLimitedRotation = SdrDragMode::Rotate == meDragMode && mpMarkedObj->HasLimitedRotation();
+ }
+ }
+
+ bool bFrmHdl=ImpIsFrameHandles();
+
+ if (nMarkCount>0)
+ {
+ mpMarkedPV=GetSdrPageViewOfMarkedByIndex(0);
+
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount && (mpMarkedPV!=nullptr || !bFrmHdl); ++nMarkNum)
+ {
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+
+ if (mpMarkedPV!=pM->GetPageView())
+ {
+ mpMarkedPV=nullptr;
+ }
+ }
+ }
+
+ SfxViewShell* pViewShell = GetSfxViewShell();
+
+ // check if text edit or ole is active and handles need to be suppressed. This may be the case
+ // when a single object is selected
+ // Using a strict return statement is okay here; no handles means *no* handles.
+ if(mpMarkedObj)
+ {
+ // formerly #i33755#: If TextEdit is active the EditEngine will directly paint
+ // to the window, so suppress Overlay and handles completely; a text frame for
+ // the active text edit will be painted by the repaint mechanism in
+ // SdrObjEditView::ImpPaintOutlinerView in this case. This needs to be reworked
+ // in the future
+ // Also formerly #122142#: Pretty much the same for SdrCaptionObj's in calc.
+ if(static_cast<SdrView*>(this)->IsTextEdit())
+ {
+ const SdrTextObj* pSdrTextObj = dynamic_cast< const SdrTextObj* >(mpMarkedObj);
+
+ if (pSdrTextObj && pSdrTextObj->IsInEditMode())
+ {
+ if (!bTiledRendering)
+ return;
+ }
+ }
+
+ // formerly #i118524#: if inplace activated OLE is selected, suppress handles
+ const SdrOle2Obj* pSdrOle2Obj = dynamic_cast< const SdrOle2Obj* >(mpMarkedObj);
+
+ if(pSdrOle2Obj && (pSdrOle2Obj->isInplaceActive() || pSdrOle2Obj->isUiActive()))
+ {
+ return;
+ }
+
+ if (!maSubSelectionList.empty())
+ {
+ mpMarkingSubSelectionOverlay = std::make_unique<MarkingSubSelectionOverlay>(*this, maSubSelectionList);
+ }
+ }
+
+ tools::Rectangle aRect(GetMarkedObjRect());
+
+ if (bFrmHdl)
+ {
+ if(!aRect.IsEmpty())
+ {
+ // otherwise nothing is found
+ const size_t nSiz0(maHdlList.GetHdlCount());
+
+ if( bSingleTextObjMark )
+ {
+ mpMarkedObj->AddToHdlList(maHdlList);
+ }
+ else
+ {
+ const bool bWdt0(aRect.Left() == aRect.Right());
+ const bool bHgt0(aRect.Top() == aRect.Bottom());
+
+ if (bWdt0 && bHgt0)
+ {
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopLeft(), SdrHdlKind::UpperLeft));
+ }
+ else if (!bStdDrag && (bWdt0 || bHgt0))
+ {
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopLeft(), SdrHdlKind::UpperLeft));
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomRight(), SdrHdlKind::LowerRight));
+ }
+ else
+ {
+ if (!bWdt0 && !bHgt0)
+ {
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopLeft(), SdrHdlKind::UpperLeft));
+ }
+
+ if (!bLimitedRotation && !bHgt0)
+ {
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopCenter(), SdrHdlKind::Upper));
+ }
+
+ if (!bWdt0 && !bHgt0)
+ {
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.TopRight(), SdrHdlKind::UpperRight));
+ }
+
+ if (!bLimitedRotation && !bWdt0)
+ {
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.LeftCenter(), SdrHdlKind::Left ));
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.RightCenter(), SdrHdlKind::Right));
+ }
+
+ if (!bWdt0 && !bHgt0)
+ {
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomLeft(), SdrHdlKind::LowerLeft));
+ }
+
+ if (!bLimitedRotation && !bHgt0)
+ {
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomCenter(), SdrHdlKind::Lower));
+ }
+
+ if (!bWdt0 && !bHgt0)
+ {
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(aRect.BottomRight(), SdrHdlKind::LowerRight));
+ }
+ }
+ }
+
+ // Diagram selection visualization support
+ // Caution: CppunitTest_sd_tiledrendering shows that mpMarkedObj *can* actually be nullptr (!)
+ if(nullptr != mpMarkedObj && mpMarkedObj->isDiagram())
+ {
+ mpMarkedObj->AddToHdlList(maHdlList);
+ }
+
+ const size_t nSiz1(maHdlList.GetHdlCount());
+
+ // moved setting the missing parameters at SdrHdl here from the
+ // single loop above (bSingleTextObjMark), this was missing all
+ // the time. Setting SdrObject is now required to correctly get
+ // the View-Dependent evtl. GridOffset adapted
+ for (size_t i=nSiz0; i<nSiz1; ++i)
+ {
+ SdrHdl* pHdl=maHdlList.GetHdl(i);
+ pHdl->SetObj(mpMarkedObj);
+ pHdl->SetPageView(mpMarkedPV);
+ pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
+ }
+ }
+ }
+ else
+ {
+ bool bDone(false);
+
+ // moved crop handling to non-frame part and the handle creation to SdrGrafObj
+ if(1 == nMarkCount && mpMarkedObj && SdrDragMode::Crop == meDragMode)
+ {
+ // Default addCropHandles from SdrObject does nothing. When pMarkedObj is SdrGrafObj, previous
+ // behaviour occurs (code in svx/source/svdraw/svdograf.cxx). When pMarkedObj is SwVirtFlyDrawObj
+ // writer takes the responsibility of adding handles (code in sw/source/core/draw/dflyobj.cxx)
+ const size_t nSiz0(maHdlList.GetHdlCount());
+ mpMarkedObj->addCropHandles(maHdlList);
+ const size_t nSiz1(maHdlList.GetHdlCount());
+
+ // Was missing: Set infos at SdrCropHdl
+ for (size_t i=nSiz0; i<nSiz1; ++i)
+ {
+ SdrHdl* pHdl=maHdlList.GetHdl(i);
+ pHdl->SetObj(mpMarkedObj);
+ pHdl->SetPageView(mpMarkedPV);
+ pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
+ }
+
+ bDone = true;
+ }
+
+ if(!bDone)
+ {
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
+ {
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrPageView* pPV=pM->GetPageView();
+ const size_t nSiz0=maHdlList.GetHdlCount();
+ pObj->AddToHdlList(maHdlList);
+ const size_t nSiz1=maHdlList.GetHdlCount();
+ bool bPoly=pObj->IsPolyObj();
+ const SdrUShortCont& rMrkPnts = pM->GetMarkedPoints();
+ for (size_t i=nSiz0; i<nSiz1; ++i)
+ {
+ SdrHdl* pHdl=maHdlList.GetHdl(i);
+ pHdl->SetObj(pObj);
+ pHdl->SetPageView(pPV);
+ pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
+
+ if (bPoly)
+ {
+ bool bSelected= rMrkPnts.find( sal_uInt16(i-nSiz0) ) != rMrkPnts.end();
+ pHdl->SetSelected(bSelected);
+ if (mbPlusHdlAlways || bSelected)
+ {
+ SdrHdlList plusList(nullptr);
+ pObj->AddToPlusHdlList(plusList, *pHdl);
+ sal_uInt32 nPlusHdlCnt=plusList.GetHdlCount();
+ for (sal_uInt32 nPlusNum=0; nPlusNum<nPlusHdlCnt; nPlusNum++)
+ {
+ SdrHdl* pPlusHdl=plusList.GetHdl(nPlusNum);
+ pPlusHdl->SetObj(pObj);
+ pPlusHdl->SetPageView(pPV);
+ pPlusHdl->SetPlusHdl(true);
+ }
+ plusList.MoveTo(maHdlList);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // GluePoint handles
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
+ {
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ const SdrGluePointList* pGPL=pObj->GetGluePointList();
+ if (!pGPL)
+ continue;
+
+ SdrPageView* pPV=pM->GetPageView();
+ const SdrUShortCont& rMrkGlue=pM->GetMarkedGluePoints();
+ for (sal_uInt16 nId : rMrkGlue)
+ {
+ //nNum changed to nNumGP because already used in for loop
+ sal_uInt16 nNumGP=pGPL->FindGluePoint(nId);
+ if (nNumGP!=SDRGLUEPOINT_NOTFOUND)
+ {
+ const SdrGluePoint& rGP=(*pGPL)[nNumGP];
+ Point aPos(rGP.GetAbsolutePos(*pObj));
+ std::unique_ptr<SdrHdl> pGlueHdl(new SdrHdl(aPos,SdrHdlKind::Glue));
+ pGlueHdl->SetObj(pObj);
+ pGlueHdl->SetPageView(pPV);
+ pGlueHdl->SetObjHdlNum(nId);
+ maHdlList.AddHdl(std::move(pGlueHdl));
+ }
+ }
+ }
+
+ // rotation point/axis of reflection
+ if(!bLimitedRotation)
+ {
+ AddDragModeHdl(meDragMode);
+ }
+
+ // sort handles
+ maHdlList.Sort();
+
+ // add custom handles (used by other apps, e.g. AnchorPos)
+ AddCustomHdl();
+
+ // moved it here to access all the handles for callback.
+ if (bTiledRendering && pViewShell)
+ {
+ SetMarkHandlesForLOKit(aRect, pOtherShell);
+ }
+
+ // try to restore focus handle index from remembered values
+ if(!bSaveOldFocus)
+ return;
+
+ for(size_t a = 0; a < maHdlList.GetHdlCount(); ++a)
+ {
+ SdrHdl* pCandidate = maHdlList.GetHdl(a);
+
+ if(pCandidate->GetObj()
+ && pCandidate->GetObj() == pSaveObj
+ && pCandidate->GetKind() == eSaveKind
+ && pCandidate->GetPolyNum() == nSavePolyNum
+ && pCandidate->GetPointNum() == nSavePointNum)
+ {
+ maHdlList.SetFocusHdl(pCandidate);
+ break;
+ }
+ }
+}
+
+void SdrMarkView::AddCustomHdl()
+{
+ // add custom handles (used by other apps, e.g. AnchorPos)
+}
+
+void SdrMarkView::SetDragMode(SdrDragMode eMode)
+{
+ SdrDragMode eMode0=meDragMode;
+ meDragMode=eMode;
+ if (meDragMode==SdrDragMode::Resize) meDragMode=SdrDragMode::Move;
+ if (meDragMode!=eMode0) {
+ ForceRefToMarked();
+ SetMarkHandles(nullptr);
+ {
+ if (AreObjectsMarked()) MarkListHasChanged();
+ }
+ }
+}
+
+void SdrMarkView::AddDragModeHdl(SdrDragMode eMode)
+{
+ switch(eMode)
+ {
+ case SdrDragMode::Rotate:
+ {
+ // add rotation center
+ maHdlList.AddHdl(std::make_unique<SdrHdl>(maRef1, SdrHdlKind::Ref1));
+ break;
+ }
+ case SdrDragMode::Mirror:
+ {
+ // add axis of reflection
+ std::unique_ptr<SdrHdl> pHdl3(new SdrHdl(maRef2, SdrHdlKind::Ref2));
+ std::unique_ptr<SdrHdl> pHdl2(new SdrHdl(maRef1, SdrHdlKind::Ref1));
+ std::unique_ptr<SdrHdl> pHdl1(new SdrHdlLine(*pHdl2, *pHdl3, SdrHdlKind::MirrorAxis));
+
+ pHdl1->SetObjHdlNum(1); // for sorting
+ pHdl2->SetObjHdlNum(2); // for sorting
+ pHdl3->SetObjHdlNum(3); // for sorting
+
+ maHdlList.AddHdl(std::move(pHdl1)); // line comes first, so it is the last in HitTest
+ maHdlList.AddHdl(std::move(pHdl2));
+ maHdlList.AddHdl(std::move(pHdl3));
+
+ break;
+ }
+ case SdrDragMode::Transparence:
+ {
+ // add interactive transparency handle
+ const size_t nMarkCount = GetMarkedObjectCount();
+ if(nMarkCount == 1)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(0);
+ SdrModel* pModel = GetModel();
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+
+ if(SfxItemState::SET != rSet.GetItemState(XATTR_FILLFLOATTRANSPARENCE, false))
+ {
+ // add this item, it's not yet there
+ XFillFloatTransparenceItem aNewItem(rSet.Get(XATTR_FILLFLOATTRANSPARENCE));
+ XGradient aGrad = aNewItem.GetGradientValue();
+
+ aNewItem.SetEnabled(true);
+ aGrad.SetStartIntens(100);
+ aGrad.SetEndIntens(100);
+ aNewItem.SetGradientValue(aGrad);
+
+ // add undo to allow user to take back this step
+ if( pModel->IsUndoEnabled() )
+ {
+ pModel->BegUndo(SvxResId(SIP_XA_FILLTRANSPARENCE));
+ pModel->AddUndo(pModel->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
+ pModel->EndUndo();
+ }
+
+ SfxItemSet aNewSet(pModel->GetItemPool());
+ aNewSet.Put(aNewItem);
+ pObj->SetMergedItemSetAndBroadcast(aNewSet);
+ }
+
+ // set values and transform to vector set
+ GradTransVector aGradTransVector;
+ GradTransGradient aGradTransGradient;
+
+ aGradTransGradient.aGradient = rSet.Get(XATTR_FILLFLOATTRANSPARENCE).GetGradientValue();
+ GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, pObj);
+
+ // build handles
+ const Point aTmpPos1(basegfx::fround(aGradTransVector.maPositionA.getX()), basegfx::fround(aGradTransVector.maPositionA.getY()));
+ const Point aTmpPos2(basegfx::fround(aGradTransVector.maPositionB.getX()), basegfx::fround(aGradTransVector.maPositionB.getY()));
+ std::unique_ptr<SdrHdlColor> pColHdl1(new SdrHdlColor(aTmpPos1, aGradTransVector.aCol1, SDR_HANDLE_COLOR_SIZE_NORMAL, true));
+ std::unique_ptr<SdrHdlColor> pColHdl2(new SdrHdlColor(aTmpPos2, aGradTransVector.aCol2, SDR_HANDLE_COLOR_SIZE_NORMAL, true));
+ std::unique_ptr<SdrHdlGradient> pGradHdl(new SdrHdlGradient(aTmpPos1, aTmpPos2, false));
+ DBG_ASSERT(pColHdl1 && pColHdl2 && pGradHdl, "Could not get all necessary handles!");
+
+ // link them
+ pGradHdl->SetColorHandles(pColHdl1.get(), pColHdl2.get());
+ pGradHdl->SetObj(pObj);
+ pColHdl1->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
+ pColHdl2->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
+
+ // insert them
+ maHdlList.AddHdl(std::move(pColHdl1));
+ maHdlList.AddHdl(std::move(pColHdl2));
+ maHdlList.AddHdl(std::move(pGradHdl));
+ }
+ break;
+ }
+ case SdrDragMode::Gradient:
+ {
+ // add interactive gradient handle
+ const size_t nMarkCount = GetMarkedObjectCount();
+ if(nMarkCount == 1)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(0);
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+ drawing::FillStyle eFillStyle = rSet.Get(XATTR_FILLSTYLE).GetValue();
+
+ if(eFillStyle == drawing::FillStyle_GRADIENT)
+ {
+ // set values and transform to vector set
+ GradTransVector aGradTransVector;
+ GradTransGradient aGradTransGradient;
+ Size aHdlSize(15, 15);
+
+ aGradTransGradient.aGradient = rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
+ GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, pObj);
+
+ // build handles
+ const Point aTmpPos1(basegfx::fround(aGradTransVector.maPositionA.getX()), basegfx::fround(aGradTransVector.maPositionA.getY()));
+ const Point aTmpPos2(basegfx::fround(aGradTransVector.maPositionB.getX()), basegfx::fround(aGradTransVector.maPositionB.getY()));
+ std::unique_ptr<SdrHdlColor> pColHdl1(new SdrHdlColor(aTmpPos1, aGradTransVector.aCol1, aHdlSize, false));
+ std::unique_ptr<SdrHdlColor> pColHdl2(new SdrHdlColor(aTmpPos2, aGradTransVector.aCol2, aHdlSize, false));
+ std::unique_ptr<SdrHdlGradient> pGradHdl(new SdrHdlGradient(aTmpPos1, aTmpPos2, true));
+ DBG_ASSERT(pColHdl1 && pColHdl2 && pGradHdl, "Could not get all necessary handles!");
+
+ // link them
+ pGradHdl->SetColorHandles(pColHdl1.get(), pColHdl2.get());
+ pGradHdl->SetObj(pObj);
+ pColHdl1->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
+ pColHdl2->SetColorChangeHdl(LINK(pGradHdl.get(), SdrHdlGradient, ColorChangeHdl));
+
+ // insert them
+ maHdlList.AddHdl(std::move(pColHdl1));
+ maHdlList.AddHdl(std::move(pColHdl2));
+ maHdlList.AddHdl(std::move(pGradHdl));
+ }
+ }
+ break;
+ }
+ case SdrDragMode::Crop:
+ {
+ // TODO
+ break;
+ }
+ default: break;
+ }
+}
+
+/** handle mouse over effects for handles */
+bool SdrMarkView::MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin)
+{
+ if(maHdlList.GetHdlCount())
+ {
+ SdrHdl* pMouseOverHdl = nullptr;
+ if( !rMEvt.IsLeaveWindow() && pWin )
+ {
+ Point aMDPos( pWin->PixelToLogic( rMEvt.GetPosPixel() ) );
+ pMouseOverHdl = PickHandle(aMDPos);
+ }
+
+ // notify last mouse over handle that he lost the mouse
+ const size_t nHdlCount = maHdlList.GetHdlCount();
+
+ for(size_t nHdl = 0; nHdl < nHdlCount; ++nHdl)
+ {
+ SdrHdl* pCurrentHdl = GetHdl(nHdl);
+ if( pCurrentHdl->mbMouseOver )
+ {
+ if( pCurrentHdl != pMouseOverHdl )
+ {
+ pCurrentHdl->mbMouseOver = false;
+ pCurrentHdl->onMouseLeave();
+ }
+ break;
+ }
+ }
+
+ // notify current mouse over handle
+ if( pMouseOverHdl )
+ {
+ pMouseOverHdl->mbMouseOver = true;
+ pMouseOverHdl->onMouseEnter(rMEvt);
+ }
+ }
+ return SdrSnapView::MouseMove(rMEvt, pWin);
+}
+
+bool SdrMarkView::RequestHelp(const HelpEvent& rHEvt)
+{
+ if (maHdlList.GetHdlCount())
+ {
+ const size_t nHdlCount = maHdlList.GetHdlCount();
+
+ for (size_t nHdl = 0; nHdl < nHdlCount; ++nHdl)
+ {
+ SdrHdl* pCurrentHdl = GetHdl(nHdl);
+ if (pCurrentHdl->mbMouseOver)
+ {
+ pCurrentHdl->onHelpRequest();
+ return true;
+ }
+ }
+ }
+ return SdrSnapView::RequestHelp(rHEvt);
+}
+
+void SdrMarkView::ForceRefToMarked()
+{
+ switch(meDragMode)
+ {
+ case SdrDragMode::Rotate:
+ {
+ tools::Rectangle aR(GetMarkedObjRect());
+ maRef1 = aR.Center();
+
+ break;
+ }
+
+ case SdrDragMode::Mirror:
+ {
+ // first calculate the length of the axis of reflection
+ tools::Long nOutMin=0;
+ tools::Long nOutMax=0;
+ tools::Long nMinLen=0;
+ tools::Long nObjDst=0;
+ tools::Long nOutHgt=0;
+ OutputDevice* pOut=GetFirstOutputDevice();
+ if (pOut!=nullptr) {
+ // minimum length: 50 pixels
+ nMinLen=pOut->PixelToLogic(Size(0,50)).Height();
+ // 20 pixels distance to the Obj for the reference point
+ nObjDst=pOut->PixelToLogic(Size(0,20)).Height();
+ // MinY/MaxY
+ // margin = minimum length = 10 pixels
+ tools::Long nDst=pOut->PixelToLogic(Size(0,10)).Height();
+ nOutMin=-pOut->GetMapMode().GetOrigin().Y();
+ nOutMax=pOut->GetOutputSize().Height()-1+nOutMin;
+ nOutMin+=nDst;
+ nOutMax-=nDst;
+ // absolute minimum length, however, is 10 pixels
+ if (nOutMax-nOutMin<nDst) {
+ nOutMin+=nOutMax+1;
+ nOutMin/=2;
+ nOutMin-=(nDst+1)/2;
+ nOutMax=nOutMin+nDst;
+ }
+ nOutHgt=nOutMax-nOutMin;
+ // otherwise minimum length = 1/4 OutHgt
+ tools::Long nTemp=nOutHgt/4;
+ if (nTemp>nMinLen) nMinLen=nTemp;
+ }
+
+ tools::Rectangle aR(GetMarkedObjBoundRect());
+ Point aCenter(aR.Center());
+ tools::Long nMarkHgt=aR.GetHeight()-1;
+ tools::Long nHgt=nMarkHgt+nObjDst*2; // 20 pixels overlapping above and below
+ if (nHgt<nMinLen) nHgt=nMinLen; // minimum length 50 pixels or 1/4 OutHgt, respectively
+
+ tools::Long nY1=aCenter.Y()-(nHgt+1)/2;
+ tools::Long nY2=nY1+nHgt;
+
+ if (pOut!=nullptr && nMinLen>nOutHgt) nMinLen=nOutHgt; // TODO: maybe shorten this a little
+
+ if (pOut!=nullptr) { // now move completely into the visible area
+ if (nY1<nOutMin) {
+ nY1=nOutMin;
+ if (nY2<nY1+nMinLen) nY2=nY1+nMinLen;
+ }
+ if (nY2>nOutMax) {
+ nY2=nOutMax;
+ if (nY1>nY2-nMinLen) nY1=nY2-nMinLen;
+ }
+ }
+
+ maRef1.setX(aCenter.X() );
+ maRef1.setY(nY1 );
+ maRef2.setX(aCenter.X() );
+ maRef2.setY(nY2 );
+
+ break;
+ }
+
+ case SdrDragMode::Transparence:
+ case SdrDragMode::Gradient:
+ case SdrDragMode::Crop:
+ {
+ tools::Rectangle aRect(GetMarkedObjBoundRect());
+ maRef1 = aRect.TopLeft();
+ maRef2 = aRect.BottomRight();
+ break;
+ }
+ default: break;
+ }
+}
+
+void SdrMarkView::SetRef1(const Point& rPt)
+{
+ if(meDragMode == SdrDragMode::Rotate || meDragMode == SdrDragMode::Mirror)
+ {
+ maRef1 = rPt;
+ SdrHdl* pH = maHdlList.GetHdl(SdrHdlKind::Ref1);
+ if(pH)
+ pH->SetPos(rPt);
+ }
+}
+
+void SdrMarkView::SetRef2(const Point& rPt)
+{
+ if(meDragMode == SdrDragMode::Mirror)
+ {
+ maRef2 = rPt;
+ SdrHdl* pH = maHdlList.GetHdl(SdrHdlKind::Ref2);
+ if(pH)
+ pH->SetPos(rPt);
+ }
+}
+
+SfxViewShell* SdrMarkView::GetSfxViewShell() const
+{
+ return SfxViewShell::Current();
+}
+
+void SdrMarkView::CheckMarked()
+{
+ for (size_t nm=GetMarkedObjectCount(); nm>0;) {
+ --nm;
+ SdrMark* pM = GetSdrMarkByIndex(nm);
+ SdrObject* pObj = pM->GetMarkedSdrObj();
+ SdrPageView* pPV = pM->GetPageView();
+ bool bRaus = !pObj || !pPV->IsObjMarkable(pObj);
+ if (bRaus)
+ {
+ GetMarkedObjectListWriteAccess().DeleteMark(nm);
+ }
+ else
+ {
+ if (!IsGluePointEditMode()) { // selected gluepoints only in GlueEditMode
+ SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+ rPts.clear();
+ }
+ }
+ }
+
+ // at least reset the remembered BoundRect to prevent handle
+ // generation if bForceFrameHandles is TRUE.
+ mbMarkedObjRectDirty = true;
+}
+
+void SdrMarkView::SetMarkRects()
+{
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(pPV)
+ {
+ pPV->SetHasMarkedObj(GetMarkedObjectList().TakeSnapRect(pPV, pPV->MarkSnap()));
+ GetMarkedObjectList().TakeBoundRect(pPV, pPV->MarkBound());
+ }
+}
+
+void SdrMarkView::SetFrameHandles(bool bOn)
+{
+ if (bOn!=mbForceFrameHandles) {
+ bool bOld=ImpIsFrameHandles();
+ mbForceFrameHandles=bOn;
+ bool bNew=ImpIsFrameHandles();
+ if (bNew!=bOld) {
+ AdjustMarkHdl();
+ MarkListHasChanged();
+ }
+ }
+}
+
+void SdrMarkView::SetEditMode(SdrViewEditMode eMode)
+{
+ if (eMode==meEditMode) return;
+
+ bool bGlue0=meEditMode==SdrViewEditMode::GluePointEdit;
+ bool bEdge0=static_cast<SdrCreateView*>(this)->IsEdgeTool();
+ meEditMode0=meEditMode;
+ meEditMode=eMode;
+ bool bGlue1=meEditMode==SdrViewEditMode::GluePointEdit;
+ bool bEdge1=static_cast<SdrCreateView*>(this)->IsEdgeTool();
+ // avoid flickering when switching between GlueEdit and EdgeTool
+ if (bGlue1 && !bGlue0) ImpSetGlueVisible2(bGlue1);
+ if (bEdge1!=bEdge0) ImpSetGlueVisible3(bEdge1);
+ if (!bGlue1 && bGlue0) ImpSetGlueVisible2(bGlue1);
+ if (bGlue0 && !bGlue1) UnmarkAllGluePoints();
+}
+
+
+bool SdrMarkView::IsObjMarkable(SdrObject const * pObj, SdrPageView const * pPV) const
+{
+ if (pObj)
+ {
+ if (pObj->IsMarkProtect() ||
+ (!mbDesignMode && pObj->IsUnoObj()))
+ {
+ // object not selectable or
+ // SdrUnoObj not in DesignMode
+ return false;
+ }
+ }
+ return pPV==nullptr || pPV->IsObjMarkable(pObj);
+}
+
+bool SdrMarkView::IsMarkedObjHit(const Point& rPnt, short nTol) const
+{
+ bool bRet=false;
+ nTol=ImpGetHitTolLogic(nTol,nullptr);
+ for (size_t nm=0; nm<GetMarkedObjectCount() && !bRet; ++nm) {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ bRet = nullptr != CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pM->GetMarkedSdrObj(),pM->GetPageView(),SdrSearchOptions::NONE,nullptr);
+ }
+ return bRet;
+}
+
+SdrHdl* SdrMarkView::PickHandle(const Point& rPnt) const
+{
+ if (mbSomeObjChgdFlag) { // recalculate handles, if necessary
+ FlushComeBackTimer();
+ }
+ return maHdlList.IsHdlListHit(rPnt);
+}
+
+bool SdrMarkView::MarkObj(const Point& rPnt, short nTol, bool bToggle, bool bDeep)
+{
+ SdrPageView* pPV;
+ nTol=ImpGetHitTolLogic(nTol,nullptr);
+ SdrSearchOptions nOptions=SdrSearchOptions::PICKMARKABLE;
+ if (bDeep) nOptions=nOptions|SdrSearchOptions::DEEP;
+ SdrObject* pObj = PickObj(rPnt, static_cast<sal_uInt16>(nTol), pPV, nOptions);
+ if (pObj) {
+ bool bUnmark=bToggle && IsObjMarked(pObj);
+ MarkObj(pObj,pPV,bUnmark);
+ }
+ return pObj != nullptr;
+}
+
+bool SdrMarkView::MarkNextObj(bool bPrev)
+{
+ SdrPageView* pPageView = GetSdrPageView();
+
+ if(!pPageView)
+ {
+ return false;
+ }
+
+ SortMarkedObjects();
+ const size_t nMarkCount=GetMarkedObjectCount();
+ size_t nChgMarkNum = SAL_MAX_SIZE; // number of the MarkEntry we want to replace
+ size_t nSearchObjNum = bPrev ? 0 : SAL_MAX_SIZE;
+ if (nMarkCount!=0) {
+ nChgMarkNum=bPrev ? 0 : nMarkCount-1;
+ SdrMark* pM=GetSdrMarkByIndex(nChgMarkNum);
+ OSL_ASSERT(pM!=nullptr);
+ if (pM->GetMarkedSdrObj() != nullptr)
+ nSearchObjNum = pM->GetMarkedSdrObj()->GetNavigationPosition();
+ }
+
+ SdrObject* pMarkObj=nullptr;
+ SdrObjList* pSearchObjList=pPageView->GetObjList();
+ const size_t nObjCount = pSearchObjList->GetObjCount();
+ if (nObjCount!=0) {
+ if (nSearchObjNum>nObjCount) nSearchObjNum=nObjCount;
+ while (pMarkObj==nullptr && ((!bPrev && nSearchObjNum>0) || (bPrev && nSearchObjNum<nObjCount)))
+ {
+ if (!bPrev)
+ nSearchObjNum--;
+ SdrObject* pSearchObj = pSearchObjList->GetObjectForNavigationPosition(nSearchObjNum);
+ if (IsObjMarkable(pSearchObj,pPageView))
+ {
+ if (TryToFindMarkedObject(pSearchObj)==SAL_MAX_SIZE)
+ {
+ pMarkObj=pSearchObj;
+ }
+ }
+ if (bPrev) nSearchObjNum++;
+ }
+ }
+
+ if(!pMarkObj)
+ {
+ return false;
+ }
+
+ if (nChgMarkNum!=SAL_MAX_SIZE)
+ {
+ GetMarkedObjectListWriteAccess().DeleteMark(nChgMarkNum);
+ }
+ MarkObj(pMarkObj,pPageView); // also calls MarkListHasChanged(), AdjustMarkHdl()
+ return true;
+}
+
+bool SdrMarkView::MarkNextObj(const Point& rPnt, short nTol, bool bPrev)
+{
+ SortMarkedObjects();
+ nTol=ImpGetHitTolLogic(nTol,nullptr);
+ SdrMark* pTopMarkHit=nullptr;
+ SdrMark* pBtmMarkHit=nullptr;
+ size_t nTopMarkHit=0;
+ size_t nBtmMarkHit=0;
+ // find topmost of the selected objects that is hit by rPnt
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=nMarkCount; nm>0 && pTopMarkHit==nullptr;) {
+ --nm;
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ if(CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pM->GetMarkedSdrObj(),pM->GetPageView(),SdrSearchOptions::NONE,nullptr))
+ {
+ pTopMarkHit=pM;
+ nTopMarkHit=nm;
+ }
+ }
+ // nothing found, in this case, just select an object
+ if (pTopMarkHit==nullptr) return MarkObj(rPnt,sal_uInt16(nTol));
+
+ SdrObject* pTopObjHit=pTopMarkHit->GetMarkedSdrObj();
+ SdrObjList* pObjList=pTopObjHit->getParentSdrObjListFromSdrObject();
+ SdrPageView* pPV=pTopMarkHit->GetPageView();
+ // find lowermost of the selected objects that is hit by rPnt
+ // and is placed on the same PageView as pTopMarkHit
+ for (size_t nm=0; nm<nMarkCount && pBtmMarkHit==nullptr; ++nm) {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrPageView* pPV2=pM->GetPageView();
+ if (pPV2==pPV && CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pM->GetMarkedSdrObj(),pPV2,SdrSearchOptions::NONE,nullptr))
+ {
+ pBtmMarkHit=pM;
+ nBtmMarkHit=nm;
+ }
+ }
+ if (pBtmMarkHit==nullptr) { pBtmMarkHit=pTopMarkHit; nBtmMarkHit=nTopMarkHit; }
+ SdrObject* pBtmObjHit=pBtmMarkHit->GetMarkedSdrObj();
+ const size_t nObjCount = pObjList->GetObjCount();
+
+ size_t nSearchBeg(0);
+ E3dScene* pScene(nullptr);
+ SdrObject* pObjHit(bPrev ? pBtmObjHit : pTopObjHit);
+ bool bRemap =
+ nullptr != dynamic_cast< const E3dCompoundObject* >(pObjHit);
+ if (bRemap)
+ {
+ pScene = dynamic_cast< E3dScene* >(pObjHit->getParentSdrObjectFromSdrObject());
+ bRemap = nullptr != pScene;
+ }
+
+ if(bPrev)
+ {
+ sal_uInt32 nOrdNumBtm(pBtmObjHit->GetOrdNum());
+
+ if(bRemap)
+ {
+ nOrdNumBtm = pScene->RemapOrdNum(nOrdNumBtm);
+ }
+
+ nSearchBeg = nOrdNumBtm + 1;
+ }
+ else
+ {
+ sal_uInt32 nOrdNumTop(pTopObjHit->GetOrdNum());
+
+ if(bRemap)
+ {
+ nOrdNumTop = pScene->RemapOrdNum(nOrdNumTop);
+ }
+
+ nSearchBeg = nOrdNumTop;
+ }
+
+ size_t no=nSearchBeg;
+ SdrObject* pFndObj=nullptr;
+ while (pFndObj==nullptr && ((!bPrev && no>0) || (bPrev && no<nObjCount))) {
+ if (!bPrev) no--;
+ SdrObject* pObj;
+
+ if(bRemap)
+ {
+ pObj = pObjList->GetObj(pScene->RemapOrdNum(no));
+ }
+ else
+ {
+ pObj = pObjList->GetObj(no);
+ }
+
+ if (CheckSingleSdrObjectHit(rPnt,sal_uInt16(nTol),pObj,pPV,SdrSearchOptions::TESTMARKABLE,nullptr))
+ {
+ if (TryToFindMarkedObject(pObj)==SAL_MAX_SIZE) {
+ pFndObj=pObj;
+ } else {
+ // TODO: for performance reasons set on to Top or Btm, if necessary
+ }
+ }
+ if (bPrev) no++;
+ }
+ if (pFndObj!=nullptr)
+ {
+ GetMarkedObjectListWriteAccess().DeleteMark(bPrev?nBtmMarkHit:nTopMarkHit);
+ GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pFndObj,pPV));
+ MarkListHasChanged();
+ AdjustMarkHdl();
+ }
+ return pFndObj!=nullptr;
+}
+
+void SdrMarkView::MarkObj(const tools::Rectangle& rRect, bool bUnmark)
+{
+ bool bFnd=false;
+ tools::Rectangle aR(rRect);
+ SdrObjList* pObjList;
+ BrkAction();
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(pPV)
+ {
+ pObjList=pPV->GetObjList();
+ tools::Rectangle aFrm1(aR);
+ const size_t nObjCount = pObjList->GetObjCount();
+ for (size_t nO=0; nO<nObjCount; ++nO) {
+ SdrObject* pObj=pObjList->GetObj(nO);
+ tools::Rectangle aRect(pObj->GetCurrentBoundRect());
+ if (aFrm1.Contains(aRect)) {
+ if (!bUnmark) {
+ if (IsObjMarkable(pObj,pPV))
+ {
+ GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pObj,pPV));
+ bFnd=true;
+ }
+ } else {
+ const size_t nPos=TryToFindMarkedObject(pObj);
+ if (nPos!=SAL_MAX_SIZE)
+ {
+ GetMarkedObjectListWriteAccess().DeleteMark(nPos);
+ bFnd=true;
+ }
+ }
+ }
+ }
+ }
+ if (bFnd) {
+ SortMarkedObjects();
+ MarkListHasChanged();
+ AdjustMarkHdl();
+ }
+}
+
+namespace {
+
+void collectUIInformation(const SdrObject* pObj)
+{
+ EventDescription aDescription;
+ aDescription.aAction = "SELECT";
+ aDescription.aParent = "MainWindow";
+ aDescription.aKeyWord = "CurrentApp";
+
+ if (!pObj->GetName().isEmpty())
+ aDescription.aParameters = {{"OBJECT", pObj->GetName()}};
+ else
+ aDescription.aParameters = {{"OBJECT", "Unnamed_Obj_" + OUString::number(pObj->GetOrdNum())}};
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+ void SdrMarkView::MarkObj(SdrObject* pObj, SdrPageView* pPV, bool bUnmark, bool bDoNoSetMarkHdl,
+ std::vector<basegfx::B2DRectangle> && rSubSelections)
+{
+ if (!(pObj!=nullptr && pPV!=nullptr && IsObjMarkable(pObj, pPV)))
+ return;
+
+ BrkAction();
+ if (!bUnmark)
+ {
+ GetMarkedObjectListWriteAccess().InsertEntry(SdrMark(pObj,pPV));
+ collectUIInformation(pObj);
+ }
+ else
+ {
+ const size_t nPos=TryToFindMarkedObject(pObj);
+ if (nPos!=SAL_MAX_SIZE)
+ {
+ GetMarkedObjectListWriteAccess().DeleteMark(nPos);
+ }
+ }
+
+ maSubSelectionList = std::move(rSubSelections);
+
+ if (!bDoNoSetMarkHdl) {
+ MarkListHasChanged();
+ AdjustMarkHdl();
+ }
+}
+
+bool SdrMarkView::IsObjMarked(SdrObject const * pObj) const
+{
+ return TryToFindMarkedObject(pObj)!=SAL_MAX_SIZE;
+}
+
+sal_uInt16 SdrMarkView::GetMarkHdlSizePixel() const
+{
+ return maHdlList.GetHdlSize()*2+1;
+}
+
+void SdrMarkView::SetMarkHdlSizePixel(sal_uInt16 nSiz)
+{
+ if (nSiz<3) nSiz=3;
+ nSiz/=2;
+ if (nSiz!=maHdlList.GetHdlSize()) {
+ maHdlList.SetHdlSize(nSiz);
+ }
+}
+
+bool SdrMarkView::getPossibleGridOffsetForSdrObject(
+ basegfx::B2DVector& rOffset,
+ const SdrObject* pObj,
+ const SdrPageView* pPV) const
+{
+ if(nullptr == pObj || nullptr == pPV)
+ {
+ return false;
+ }
+
+ const OutputDevice* pOutputDevice(GetFirstOutputDevice());
+
+ if(nullptr == pOutputDevice)
+ {
+ return false;
+ }
+
+ const SdrPageWindow* pSdrPageWindow(pPV->FindPageWindow(*pOutputDevice));
+
+ if(nullptr == pSdrPageWindow)
+ {
+ return false;
+ }
+
+ const sdr::contact::ObjectContact& rObjectContact(pSdrPageWindow->GetObjectContact());
+
+ if(!rObjectContact.supportsGridOffsets())
+ {
+ return false;
+ }
+
+ const sdr::contact::ViewObjectContact& rVOC(pObj->GetViewContact().GetViewObjectContact(
+ const_cast<sdr::contact::ObjectContact&>(rObjectContact)));
+
+ rOffset = rVOC.getGridOffset();
+
+ return !rOffset.equalZero();
+}
+
+bool SdrMarkView::getPossibleGridOffsetForPosition(
+ basegfx::B2DVector& rOffset,
+ const basegfx::B2DPoint& rPoint,
+ const SdrPageView* pPV) const
+{
+ if(nullptr == pPV)
+ {
+ return false;
+ }
+
+ const OutputDevice* pOutputDevice(GetFirstOutputDevice());
+
+ if(nullptr == pOutputDevice)
+ {
+ return false;
+ }
+
+ const SdrPageWindow* pSdrPageWindow(pPV->FindPageWindow(*pOutputDevice));
+
+ if(nullptr == pSdrPageWindow)
+ {
+ return false;
+ }
+
+ const sdr::contact::ObjectContact& rObjectContact(pSdrPageWindow->GetObjectContact());
+
+ if(!rObjectContact.supportsGridOffsets())
+ {
+ return false;
+ }
+
+ rObjectContact.calculateGridOffsetForB2DRange(rOffset, basegfx::B2DRange(rPoint));
+
+ return !rOffset.equalZero();
+}
+
+SdrObject* SdrMarkView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const
+{
+ if(((nOptions & SdrSearchOptions::IMPISMASTER) && pObj->IsNotVisibleAsMaster()) || (!pObj->IsVisible()))
+ {
+ return nullptr;
+ }
+
+ const bool bCheckIfMarkable(nOptions & SdrSearchOptions::TESTMARKABLE);
+ const bool bDeep(nOptions & SdrSearchOptions::DEEP);
+ const bool bOLE(dynamic_cast< const SdrOle2Obj* >(pObj) != nullptr);
+ auto pTextObj = dynamic_cast<const SdrTextObj*>( pObj);
+ const bool bTXT(pTextObj && pTextObj->IsTextFrame());
+ SdrObject* pRet=nullptr;
+ tools::Rectangle aRect(pObj->GetCurrentBoundRect());
+
+ // add possible GridOffset to up-to-now view-independent BoundRect data
+ basegfx::B2DVector aGridOffset(0.0, 0.0);
+ if(getPossibleGridOffsetForSdrObject(aGridOffset, pObj, pPV))
+ {
+ aRect += Point(
+ basegfx::fround(aGridOffset.getX()),
+ basegfx::fround(aGridOffset.getY()));
+ }
+
+ sal_uInt16 nTol2(nTol);
+
+ // double tolerance for OLE, text frames and objects in
+ // active text edit
+ if(bOLE || bTXT || pObj==static_cast<const SdrObjEditView*>(this)->GetTextEditObject())
+ {
+ nTol2*=2;
+ }
+
+ aRect.AdjustLeft( -nTol2 ); // add 1 tolerance for all objects
+ aRect.AdjustTop( -nTol2 );
+ aRect.AdjustRight(nTol2 );
+ aRect.AdjustBottom(nTol2 );
+
+ if (aRect.Contains(rPnt))
+ {
+ if (!bCheckIfMarkable || IsObjMarkable(pObj,pPV))
+ {
+ SdrObjList* pOL=pObj->GetSubList();
+
+ if (pOL!=nullptr && pOL->GetObjCount()!=0)
+ {
+ SdrObject* pTmpObj;
+ // adjustment hit point for virtual objects
+ Point aPnt( rPnt );
+
+ if ( auto pVirtObj = dynamic_cast<const SdrVirtObj*>( pObj) )
+ {
+ Point aOffset = pVirtObj->GetOffset();
+ aPnt.Move( -aOffset.X(), -aOffset.Y() );
+ }
+
+ pRet=CheckSingleSdrObjectHit(aPnt,nTol,pOL,pPV,nOptions,pMVisLay,pTmpObj);
+ }
+ else
+ {
+ if(!pMVisLay || pMVisLay->IsSet(pObj->GetLayer()))
+ {
+ pRet = SdrObjectPrimitiveHit(*pObj, rPnt, nTol2, *pPV, &pPV->GetVisibleLayers(), false);
+ }
+ }
+ }
+ }
+
+ if (!bDeep && pRet!=nullptr)
+ {
+ pRet=pObj;
+ }
+
+ return pRet;
+}
+
+SdrObject* SdrMarkView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObjList const * pOL, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay, SdrObject*& rpRootObj) const
+{
+ return (*this).CheckSingleSdrObjectHit(rPnt,nTol,pOL,pPV,nOptions,pMVisLay,rpRootObj,nullptr);
+}
+SdrObject* SdrMarkView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObjList const * pOL, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay, SdrObject*& rpRootObj,const SdrMarkList * pMarkList) const
+{
+ SdrObject* pRet=nullptr;
+ rpRootObj=nullptr;
+ if (pOL!=nullptr)
+ {
+ const bool bRemap(
+ nullptr != pOL->getSdrObjectFromSdrObjList()
+ && nullptr != dynamic_cast< const E3dScene* >(pOL->getSdrObjectFromSdrObjList()));
+ const E3dScene* pRemapScene(bRemap ? static_cast< E3dScene* >(pOL->getSdrObjectFromSdrObjList()) : nullptr);
+ const size_t nObjCount(pOL->GetObjCount());
+ size_t nObjNum(nObjCount);
+
+ while (pRet==nullptr && nObjNum>0)
+ {
+ nObjNum--;
+ SdrObject* pObj;
+
+ if(bRemap)
+ {
+ pObj = pOL->GetObj(pRemapScene->RemapOrdNum(nObjNum));
+ }
+ else
+ {
+ pObj = pOL->GetObj(nObjNum);
+ }
+ if (nOptions & SdrSearchOptions::BEFOREMARK)
+ {
+ if (pMarkList!=nullptr)
+ {
+ if ((*pMarkList).FindObject(pObj)!=SAL_MAX_SIZE)
+ {
+ return nullptr;
+ }
+ }
+ }
+ pRet=CheckSingleSdrObjectHit(rPnt,nTol,pObj,pPV,nOptions,pMVisLay);
+ if (pRet!=nullptr) rpRootObj=pObj;
+ }
+ }
+ return pRet;
+}
+
+SdrObject* SdrMarkView::PickObj(const Point& rPnt, short nTol, SdrPageView*& rpPV, SdrSearchOptions nOptions) const
+{
+ return PickObj(rPnt, nTol, rpPV, nOptions, nullptr);
+}
+
+SdrObject* SdrMarkView::PickObj(const Point& rPnt, short nTol, SdrPageView*& rpPV, SdrSearchOptions nOptions, SdrObject** ppRootObj, bool* pbHitPassDirect) const
+{ // TODO: lacks a Pass2,Pass3
+ SortMarkedObjects();
+ if (ppRootObj!=nullptr) *ppRootObj=nullptr;
+ if (pbHitPassDirect!=nullptr) *pbHitPassDirect=true;
+ SdrObject* pRet = nullptr;
+ rpPV=nullptr;
+ bool bMarked(nOptions & SdrSearchOptions::MARKED);
+ bool bMasters=!bMarked && bool(nOptions & SdrSearchOptions::ALSOONMASTER);
+ // nOptions & SdrSearchOptions::NEXT: n.i.
+ // nOptions & SdrSearchOptions::PASS2BOUND: n.i.
+ // nOptions & SdrSearchOptions::PASS3NEAREST// n.i.
+ if (nTol<0) nTol=ImpGetHitTolLogic(nTol,nullptr);
+ SdrObject* pObj=nullptr;
+ SdrObject* pHitObj=nullptr;
+ SdrPageView* pPV=nullptr;
+ if (static_cast<const SdrObjEditView*>(this)->IsTextEditFrameHit(rPnt)) {
+ pObj=static_cast<const SdrObjEditView*>(this)->GetTextEditObject();
+ pHitObj=pObj;
+ pPV=static_cast<const SdrObjEditView*>(this)->GetTextEditPageView();
+ }
+ if (bMarked) {
+ const size_t nMrkCnt=GetMarkedObjectCount();
+ size_t nMrkNum=nMrkCnt;
+ while (pHitObj==nullptr && nMrkNum>0) {
+ nMrkNum--;
+ SdrMark* pM=GetSdrMarkByIndex(nMrkNum);
+ pObj=pM->GetMarkedSdrObj();
+ pPV=pM->GetPageView();
+ pHitObj=CheckSingleSdrObjectHit(rPnt,nTol,pObj,pPV,nOptions,nullptr);
+ }
+ }
+ else
+ {
+ pPV = GetSdrPageView();
+
+ if(pPV)
+ {
+ SdrPage* pPage=pPV->GetPage();
+ sal_uInt16 nPgCount=1;
+
+ if(bMasters && pPage->TRG_HasMasterPage())
+ {
+ nPgCount++;
+ }
+ bool bWholePage(nOptions & SdrSearchOptions::WHOLEPAGE);
+ bool bExtraPassForWholePage=bWholePage && pPage!=pPV->GetObjList();
+ if (bExtraPassForWholePage) nPgCount++; // First search in AktObjList, then on the entire page
+ sal_uInt16 nPgNum=nPgCount;
+ while (pHitObj==nullptr && nPgNum>0) {
+ SdrSearchOptions nTmpOptions=nOptions;
+ nPgNum--;
+ const SdrLayerIDSet* pMVisLay=nullptr;
+ SdrObjList* pObjList=nullptr;
+ if (pbHitPassDirect!=nullptr) *pbHitPassDirect = true;
+ if (nPgNum>=nPgCount-1 || (bExtraPassForWholePage && nPgNum>=nPgCount-2))
+ {
+ pObjList=pPV->GetObjList();
+ if (bExtraPassForWholePage && nPgNum==nPgCount-2) {
+ pObjList=pPage;
+ if (pbHitPassDirect!=nullptr) *pbHitPassDirect = false;
+ }
+ }
+ else
+ {
+ // otherwise MasterPage
+ SdrPage& rMasterPage = pPage->TRG_GetMasterPage();
+ pMVisLay = &pPage->TRG_GetMasterPageVisibleLayers();
+ pObjList = &rMasterPage;
+
+ if (pbHitPassDirect!=nullptr) *pbHitPassDirect = false;
+ nTmpOptions=nTmpOptions | SdrSearchOptions::IMPISMASTER;
+ }
+ pHitObj=CheckSingleSdrObjectHit(rPnt,nTol,pObjList,pPV,nTmpOptions,pMVisLay,pObj,&(GetMarkedObjectList()));
+ }
+ }
+ }
+ if (pHitObj!=nullptr) {
+ if (ppRootObj!=nullptr) *ppRootObj=pObj;
+ if (nOptions & SdrSearchOptions::DEEP) pObj=pHitObj;
+ if (nOptions & SdrSearchOptions::TESTTEXTEDIT) {
+ if (!pObj->HasTextEdit() || pPV->GetLockedLayers().IsSet(pObj->GetLayer())) {
+ pObj=nullptr;
+ }
+ }
+ if (pObj!=nullptr && (nOptions & SdrSearchOptions::TESTMACRO)) {
+ SdrObjMacroHitRec aHitRec;
+ aHitRec.aPos=rPnt;
+ aHitRec.nTol=nTol;
+ aHitRec.pVisiLayer=&pPV->GetVisibleLayers();
+ aHitRec.pPageView=pPV;
+ if (!pObj->HasMacro() || !pObj->IsMacroHit(aHitRec)) pObj=nullptr;
+ }
+ if (pObj!=nullptr) {
+ pRet=pObj;
+ rpPV=pPV;
+ }
+ }
+ return pRet;
+}
+
+bool SdrMarkView::PickMarkedObj(const Point& rPnt, SdrObject*& rpObj, SdrPageView*& rpPV, SdrSearchOptions nOptions) const
+{
+ SortMarkedObjects();
+ const bool bBoundCheckOn2ndPass(nOptions & SdrSearchOptions::PASS2BOUND);
+ rpObj=nullptr;
+ rpPV=nullptr;
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nMarkNum=nMarkCount; nMarkNum>0;) {
+ --nMarkNum;
+ SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ SdrPageView* pPV=pM->GetPageView();
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ if (CheckSingleSdrObjectHit(rPnt,mnHitTolLog,pObj,pPV,SdrSearchOptions::TESTMARKABLE,nullptr)) {
+ rpObj=pObj;
+ rpPV=pPV;
+ return true;
+ }
+ }
+ if (bBoundCheckOn2ndPass) {
+ for (size_t nMarkNum=nMarkCount; nMarkNum>0;) {
+ --nMarkNum;
+ SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ SdrPageView* pPV=pM->GetPageView();
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ tools::Rectangle aRect(pObj->GetCurrentBoundRect());
+ aRect.AdjustLeft( -mnHitTolLog );
+ aRect.AdjustTop( -mnHitTolLog );
+ aRect.AdjustRight(mnHitTolLog );
+ aRect.AdjustBottom(mnHitTolLog );
+ if (aRect.Contains(rPnt)) {
+ rpObj=pObj;
+ rpPV=pPV;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+void SdrMarkView::UnmarkAllObj(SdrPageView const * pPV)
+{
+ if (GetMarkedObjectCount()==0)
+ return;
+
+ BrkAction();
+ if (pPV!=nullptr)
+ {
+ GetMarkedObjectListWriteAccess().DeletePageView(*pPV);
+ }
+ else
+ {
+ GetMarkedObjectListWriteAccess().Clear();
+ }
+ mpMarkedObj=nullptr;
+ mpMarkedPV=nullptr;
+ MarkListHasChanged();
+ AdjustMarkHdl();
+}
+
+void SdrMarkView::MarkAllObj(SdrPageView* pPV)
+{
+ BrkAction();
+
+ if(!pPV)
+ {
+ pPV = GetSdrPageView();
+ }
+
+ // #i69171# pPV may still be NULL if there is no SDrPageView (!), e.g. when inserting
+ // other files
+ if(pPV)
+ {
+ const bool bMarkChg(GetMarkedObjectListWriteAccess().InsertPageView(*pPV));
+
+ if(bMarkChg)
+ {
+ MarkListHasChanged();
+ }
+ }
+
+ if(GetMarkedObjectCount())
+ {
+ AdjustMarkHdl();
+ }
+}
+
+void SdrMarkView::AdjustMarkHdl(SfxViewShell* pOtherShell)
+{
+ CheckMarked();
+ SetMarkRects();
+ SetMarkHandles(pOtherShell);
+}
+
+// BoundRect in model coordinates, no GridOffset added
+tools::Rectangle SdrMarkView::GetMarkedObjBoundRect() const
+{
+ tools::Rectangle aRect;
+ for (size_t nm=0; nm<GetMarkedObjectCount(); ++nm) {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pO=pM->GetMarkedSdrObj();
+ tools::Rectangle aR1(pO->GetCurrentBoundRect());
+ if (aRect.IsEmpty()) aRect=aR1;
+ else aRect.Union(aR1);
+ }
+ return aRect;
+}
+
+// ObjRect in model coordinates, no GridOffset added
+const tools::Rectangle& SdrMarkView::GetMarkedObjRect() const
+{
+ if (mbMarkedObjRectDirty) {
+ const_cast<SdrMarkView*>(this)->mbMarkedObjRectDirty=false;
+ tools::Rectangle aRect;
+ for (size_t nm=0; nm<GetMarkedObjectCount(); ++nm) {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pO = pM->GetMarkedSdrObj();
+ if (!pO)
+ continue;
+ tools::Rectangle aR1(pO->GetSnapRect());
+ if (aRect.IsEmpty()) aRect=aR1;
+ else aRect.Union(aR1);
+ }
+ const_cast<SdrMarkView*>(this)->maMarkedObjRect=aRect;
+ }
+ return maMarkedObjRect;
+}
+
+
+OUString SdrMarkView::ImpGetDescriptionString(TranslateId pStrCacheID, ImpGetDescriptionOptions nOpt) const
+{
+ OUString sStr = SvxResId(pStrCacheID);
+ const sal_Int32 nPos = sStr.indexOf("%1");
+
+ if(nPos != -1)
+ {
+ if(nOpt == ImpGetDescriptionOptions::POINTS)
+ {
+ sStr = sStr.replaceAt(nPos, 2, GetDescriptionOfMarkedPoints());
+ }
+ else if(nOpt == ImpGetDescriptionOptions::GLUEPOINTS)
+ {
+ sStr = sStr.replaceAt(nPos, 2, GetDescriptionOfMarkedGluePoints());
+ }
+ else
+ {
+ sStr = sStr.replaceAt(nPos, 2, GetDescriptionOfMarkedObjects());
+ }
+ }
+
+ return sStr.replaceFirst("%2", "0");
+}
+
+
+void SdrMarkView::EnterMarkedGroup()
+{
+ // We enter only the first group found (in only one PageView), because
+ // PageView::EnterGroup calls an AdjustMarkHdl.
+ // TODO: I'll have to prevent that via a flag.
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(!pPV)
+ return;
+
+ bool bEnter=false;
+ for (size_t nm = GetMarkedObjectCount(); nm > 0 && !bEnter;)
+ {
+ --nm;
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ if (pM->GetPageView()==pPV) {
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ if (pObj->IsGroupObject()) {
+ if (pPV->EnterGroup(pObj)) {
+ bEnter=true;
+ }
+ }
+ }
+ }
+}
+
+
+void SdrMarkView::MarkListHasChanged()
+{
+ GetMarkedObjectListWriteAccess().SetNameDirty();
+ maSdrViewSelection.SetEdgesOfMarkedNodesDirty();
+
+ mbMarkedObjRectDirty=true;
+ mbMarkedPointsRectsDirty=true;
+ bool bOneEdgeMarked=false;
+ if (GetMarkedObjectCount()==1) {
+ const SdrObject* pObj=GetMarkedObjectByIndex(0);
+ if (pObj->GetObjInventor()==SdrInventor::Default) {
+ bOneEdgeMarked = pObj->GetObjIdentifier() == SdrObjKind::Edge;
+ }
+ }
+ ImpSetGlueVisible4(bOneEdgeMarked);
+}
+
+
+void SdrMarkView::SetMoveOutside(bool bOn)
+{
+ maHdlList.SetMoveOutside(bOn);
+}
+
+void SdrMarkView::SetDesignMode( bool bOn )
+{
+ if ( mbDesignMode != bOn )
+ {
+ mbDesignMode = bOn;
+ SdrPageView* pPageView = GetSdrPageView();
+ if ( pPageView )
+ pPageView->SetDesignMode( bOn );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdmrkv1.cxx b/svx/source/svdraw/svdmrkv1.cxx
new file mode 100644
index 000000000..9c732262b
--- /dev/null
+++ b/svx/source/svdraw/svdmrkv1.cxx
@@ -0,0 +1,547 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdmrkv.hxx>
+#include <svx/svdpagv.hxx>
+#include <osl/diagnose.h>
+
+
+// Point Selection
+
+
+bool SdrMarkView::HasMarkablePoints() const
+{
+ ForceUndirtyMrkPnt();
+ bool bRet=false;
+ if (!ImpIsFrameHandles()) {
+ const size_t nMarkCount=GetMarkedObjectCount();
+ if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+ bRet=pObj->IsPolyObj();
+ }
+ }
+ }
+ return bRet;
+}
+
+sal_Int32 SdrMarkView::GetMarkablePointCount() const
+{
+ ForceUndirtyMrkPnt();
+ sal_Int32 nCount=0;
+ if (!ImpIsFrameHandles()) {
+ const size_t nMarkCount=GetMarkedObjectCount();
+ if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+ if (pObj->IsPolyObj()) {
+ nCount+=pObj->GetPointCount();
+ }
+ }
+ }
+ }
+ return nCount;
+}
+
+bool SdrMarkView::HasMarkedPoints() const
+{
+ ForceUndirtyMrkPnt();
+ bool bRet=false;
+ if (!ImpIsFrameHandles()) {
+ const size_t nMarkCount=GetMarkedObjectCount();
+ if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ const SdrUShortCont& rPts = pM->GetMarkedPoints();
+ bRet = !rPts.empty();
+ }
+ }
+ }
+ return bRet;
+}
+
+bool SdrMarkView::IsPointMarkable(const SdrHdl& rHdl) const
+{
+ return !ImpIsFrameHandles() && !rHdl.IsPlusHdl() && rHdl.GetKind()!=SdrHdlKind::Glue && rHdl.GetKind()!=SdrHdlKind::SmartTag && rHdl.GetObj()!=nullptr && rHdl.GetObj()->IsPolyObj();
+}
+
+bool SdrMarkView::MarkPointHelper(SdrHdl* pHdl, SdrMark* pMark, bool bUnmark)
+{
+ return ImpMarkPoint( pHdl, pMark, bUnmark );
+}
+
+bool SdrMarkView::ImpMarkPoint(SdrHdl* pHdl, SdrMark* pMark, bool bUnmark)
+{
+ if (pHdl==nullptr || pHdl->IsPlusHdl() || pHdl->GetKind()==SdrHdlKind::Glue)
+ return false;
+
+ if (pHdl->IsSelected() != bUnmark)
+ return false;
+
+ SdrObject* pObj=pHdl->GetObj();
+ if (pObj==nullptr || !pObj->IsPolyObj())
+ return false;
+
+ if (pMark==nullptr)
+ {
+ const size_t nMarkNum=TryToFindMarkedObject(pObj);
+ if (nMarkNum==SAL_MAX_SIZE)
+ return false;
+ pMark=GetSdrMarkByIndex(nMarkNum);
+ }
+ const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
+ SdrUShortCont& rPts=pMark->GetMarkedPoints();
+ if (!bUnmark)
+ {
+ rPts.insert(static_cast<sal_uInt16>(nHdlNum));
+ }
+ else
+ {
+ SdrUShortCont::const_iterator it = rPts.find( static_cast<sal_uInt16>(nHdlNum) );
+ if (it != rPts.end())
+ {
+ rPts.erase(it);
+ }
+ else
+ {
+ return false; // error case!
+ }
+ }
+
+ pHdl->SetSelected(!bUnmark);
+ if (!mbPlusHdlAlways)
+ {
+ if (!bUnmark)
+ {
+ SdrHdlList plusList(nullptr);
+ pObj->AddToPlusHdlList(plusList, *pHdl);
+ sal_uInt32 nCount(plusList.GetHdlCount());
+ for (sal_uInt32 i=0; i<nCount; i++)
+ {
+ SdrHdl* pPlusHdl=plusList.GetHdl(i);
+ pPlusHdl->SetObj(pObj);
+ pPlusHdl->SetPageView(pMark->GetPageView());
+ pPlusHdl->SetPlusHdl(true);
+ }
+ plusList.MoveTo(maHdlList);
+ }
+ else
+ {
+ for (size_t i = maHdlList.GetHdlCount(); i>0;)
+ {
+ --i;
+ SdrHdl* pPlusHdl=maHdlList.GetHdl(i);
+ if (pPlusHdl->IsPlusHdl() && pPlusHdl->GetSourceHdlNum()==nHdlNum)
+ {
+ maHdlList.RemoveHdl(i);
+ }
+ }
+ }
+ }
+
+ maHdlList.Sort();
+
+ return true;
+}
+
+
+bool SdrMarkView::MarkPoint(SdrHdl& rHdl, bool bUnmark)
+{
+ ForceUndirtyMrkPnt();
+ bool bRet=false;
+ const SdrObject* pObj=rHdl.GetObj();
+ if (IsPointMarkable(rHdl) && rHdl.IsSelected()==bUnmark) {
+ const size_t nMarkNum=TryToFindMarkedObject(pObj);
+ if (nMarkNum!=SAL_MAX_SIZE) {
+ SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ if (ImpMarkPoint(&rHdl,pM,bUnmark)) {
+ MarkListHasChanged();
+ bRet=true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+bool SdrMarkView::MarkPoints(const tools::Rectangle* pRect, bool bUnmark)
+{
+ ForceUndirtyMrkPnt();
+ bool bChgd=false;
+ SortMarkedObjects();
+ const SdrObject* pObj0=nullptr;
+ const SdrPageView* pPV0=nullptr;
+ SdrMark* pM=nullptr;
+ maHdlList.Sort();
+ const size_t nHdlCnt=maHdlList.GetHdlCount();
+ for (size_t nHdlNum=nHdlCnt; nHdlNum>0;) {
+ --nHdlNum;
+ SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
+ if (IsPointMarkable(*pHdl) && pHdl->IsSelected()==bUnmark) {
+ const SdrObject* pObj=pHdl->GetObj();
+ const SdrPageView* pPV=pHdl->GetPageView();
+ if (pObj!=pObj0 || pPV!=pPV0 || pM==nullptr) { // This section is for optimization,
+ const size_t nMarkNum=TryToFindMarkedObject(pObj); // so ImpMarkPoint() doesn't always
+ if (nMarkNum!=SAL_MAX_SIZE) { // have to search the object in the MarkList.
+ pM=GetSdrMarkByIndex(nMarkNum);
+ pObj0=pObj;
+ pPV0=pPV;
+ } else {
+#ifdef DBG_UTIL
+ if (pObj->IsInserted()) {
+ OSL_FAIL("SdrMarkView::MarkPoints(const Rectangle* pRect): Selected object not found.");
+ }
+#endif
+ pM=nullptr;
+ }
+ }
+ Point aPos(pHdl->GetPos());
+ if (pM!=nullptr && (pRect==nullptr || pRect->Contains(aPos))) {
+ if (ImpMarkPoint(pHdl,pM,bUnmark)) bChgd=true;
+ }
+ }
+ }
+ if (bChgd) {
+ MarkListHasChanged();
+ }
+
+ return bChgd;
+}
+
+void SdrMarkView::MarkNextPoint()
+{
+ ForceUndirtyMrkPnt();
+ SortMarkedObjects();
+}
+
+const tools::Rectangle& SdrMarkView::GetMarkedPointsRect() const
+{
+ ForceUndirtyMrkPnt();
+ if (mbMarkedPointsRectsDirty) ImpSetPointsRects();
+ return maMarkedPointsRect;
+}
+
+void SdrMarkView::SetPlusHandlesAlwaysVisible(bool bOn)
+{ // TODO: Optimize HandlePaint!
+ ForceUndirtyMrkPnt();
+ if (bOn!=mbPlusHdlAlways) {
+ mbPlusHdlAlways=bOn;
+ SetMarkHandles(nullptr);
+ MarkListHasChanged();
+ }
+}
+
+
+// ImpSetPointsRects() is for PolyPoints and GluePoints!
+
+
+void SdrMarkView::ImpSetPointsRects() const
+{
+ tools::Rectangle aPnts;
+ tools::Rectangle aGlue;
+ const size_t nHdlCnt=maHdlList.GetHdlCount();
+ for (size_t nHdlNum=0; nHdlNum<nHdlCnt; ++nHdlNum) {
+ const SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
+ SdrHdlKind eKind=pHdl->GetKind();
+ if ((eKind==SdrHdlKind::Poly && pHdl->IsSelected()) || eKind==SdrHdlKind::Glue) {
+ Point aPt(pHdl->GetPos());
+ tools::Rectangle& rR=eKind==SdrHdlKind::Glue ? aGlue : aPnts;
+ if (rR.IsEmpty()) {
+ rR=tools::Rectangle(aPt,aPt);
+ } else {
+ if (aPt.X()<rR.Left ()) rR.SetLeft(aPt.X() );
+ if (aPt.X()>rR.Right ()) rR.SetRight(aPt.X() );
+ if (aPt.Y()<rR.Top ()) rR.SetTop(aPt.Y() );
+ if (aPt.Y()>rR.Bottom()) rR.SetBottom(aPt.Y() );
+ }
+ }
+ }
+ const_cast<SdrMarkView*>(this)->maMarkedPointsRect=aPnts;
+ const_cast<SdrMarkView*>(this)->maMarkedGluePointsRect=aGlue;
+ const_cast<SdrMarkView*>(this)->mbMarkedPointsRectsDirty=false;
+}
+
+
+// UndirtyMrkPnt() is for PolyPoints and GluePoints!
+
+
+void SdrMarkView::UndirtyMrkPnt() const
+{
+ bool bChg=false;
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
+ SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+ // PolyPoints
+ {
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+ if (pObj->IsPolyObj()) {
+ // Remove invalid selected points, that is, all
+ // entries above the number of points in the object.
+ sal_uInt32 nMax(pObj->GetPointCount());
+
+ SdrUShortCont::const_iterator it = rPts.lower_bound(nMax);
+ if( it != rPts.end() )
+ {
+ rPts.erase(it, rPts.end());
+ bChg = true;
+ }
+ }
+ else
+ {
+ if (!rPts.empty())
+ {
+ // only fail *if* there are marked points
+ OSL_FAIL("SdrMarkView::UndirtyMrkPnt(): Selected points on an object that is not a PolyObj!");
+ rPts.clear();
+ bChg = true;
+ }
+ }
+ }
+
+ // GluePoints
+ {
+ SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+ const SdrGluePointList* pGPL=pObj->GetGluePointList();
+ if (pGPL!=nullptr) {
+ // Remove invalid selected gluepoints, that is, all entries
+ // (IDs) that aren't contained in the GluePointList of the
+ // object
+ for(SdrUShortCont::const_iterator it = rPts.begin(); it != rPts.end(); )
+ {
+ sal_uInt16 nId=*it;
+ if (pGPL->FindGluePoint(nId)==SDRGLUEPOINT_NOTFOUND) {
+ it = rPts.erase(it);
+ bChg=true;
+ }
+ else
+ ++it;
+ }
+ } else {
+ if (!rPts.empty()) {
+ rPts.clear(); // object doesn't have any gluepoints (any more)
+ bChg=true;
+ }
+ }
+ }
+ }
+ if (bChg) const_cast<SdrMarkView*>(this)->mbMarkedPointsRectsDirty=true;
+ const_cast<SdrMarkView*>(this)->mbMrkPntDirty=false;
+}
+
+
+bool SdrMarkView::HasMarkableGluePoints() const
+{
+ bool bRet=false;
+ if (IsGluePointEditMode()) {
+ ForceUndirtyMrkPnt();
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+ const SdrGluePointList* pGPL=pObj->GetGluePointList();
+
+ // #i38892#
+ if(pGPL && pGPL->GetCount())
+ {
+ for(sal_uInt16 a(0); !bRet && a < pGPL->GetCount(); a++)
+ {
+ if((*pGPL)[a].IsUserDefined())
+ {
+ bRet = true;
+ }
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+bool SdrMarkView::HasMarkedGluePoints() const
+{
+ ForceUndirtyMrkPnt();
+ bool bRet=false;
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+ bRet = !rPts.empty();
+ }
+ return bRet;
+}
+
+bool SdrMarkView::MarkGluePoints(const tools::Rectangle* pRect, bool bUnmark)
+{
+ if (!IsGluePointEditMode() && !bUnmark) return false;
+ ForceUndirtyMrkPnt();
+ bool bChgd=false;
+ SortMarkedObjects();
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
+ SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+ const SdrGluePointList* pGPL=pObj->GetGluePointList();
+ SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+ if (bUnmark && pRect==nullptr) { // UnmarkAll
+ if (!rPts.empty()) {
+ rPts.clear();
+ bChgd=true;
+ }
+ } else {
+ if (pGPL!=nullptr) {
+ sal_uInt16 nGluePointCnt=pGPL->GetCount();
+ for (sal_uInt16 nGPNum=0; nGPNum<nGluePointCnt; nGPNum++) {
+ const SdrGluePoint& rGP=(*pGPL)[nGPNum];
+
+ // #i38892#
+ if(rGP.IsUserDefined())
+ {
+ Point aPos(rGP.GetAbsolutePos(*pObj));
+ if (pRect==nullptr || pRect->Contains(aPos)) {
+ bool bContains = rPts.find( rGP.GetId() ) != rPts.end();
+ if (!bUnmark && !bContains) {
+ bChgd=true;
+ rPts.insert(rGP.GetId());
+ }
+ if (bUnmark && bContains) {
+ bChgd=true;
+ rPts.erase(rGP.GetId());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (bChgd) {
+ AdjustMarkHdl();
+ MarkListHasChanged();
+ }
+ return bChgd;
+}
+
+bool SdrMarkView::PickGluePoint(const Point& rPnt, SdrObject*& rpObj, sal_uInt16& rnId, SdrPageView*& rpPV) const
+{
+ rpObj=nullptr; rpPV=nullptr; rnId=0;
+ if (!IsGluePointEditMode()) return false;
+ OutputDevice* pOut=mpActualOutDev.get();
+ if (pOut==nullptr) pOut=GetFirstOutputDevice();
+ if (pOut==nullptr) return false;
+ SortMarkedObjects();
+ const size_t nMarkCount=GetMarkedObjectCount();
+ size_t nMarkNum=nMarkCount;
+ while (nMarkNum>0) {
+ nMarkNum--;
+ const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrPageView* pPV=pM->GetPageView();
+ const SdrGluePointList* pGPL=pObj->GetGluePointList();
+ if (pGPL!=nullptr) {
+ sal_uInt16 nNum=pGPL->HitTest(rPnt,*pOut,pObj);
+ if (nNum!=SDRGLUEPOINT_NOTFOUND)
+ {
+ // #i38892#
+ const SdrGluePoint& rCandidate = (*pGPL)[nNum];
+
+ if(rCandidate.IsUserDefined())
+ {
+ rpObj=pObj;
+ rnId=(*pGPL)[nNum].GetId();
+ rpPV=pPV;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool SdrMarkView::MarkGluePoint(const SdrObject* pObj, sal_uInt16 nId, bool bUnmark)
+{
+ if (!IsGluePointEditMode()) return false;
+ ForceUndirtyMrkPnt();
+ bool bChgd=false;
+ if (pObj!=nullptr) {
+ const size_t nMarkPos=TryToFindMarkedObject(pObj);
+ if (nMarkPos!=SAL_MAX_SIZE) {
+ SdrMark* pM=GetSdrMarkByIndex(nMarkPos);
+ SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+ bool bContains = rPts.find( nId ) != rPts.end();
+ if (!bUnmark && !bContains) {
+ bChgd=true;
+ rPts.insert(nId);
+ }
+ if (bUnmark && bContains) {
+ bChgd=true;
+ rPts.erase(nId);
+ }
+ } else {
+ // TODO: implement implicit selection of objects
+ }
+ }
+ if (bChgd) {
+ AdjustMarkHdl();
+ MarkListHasChanged();
+ }
+ return bChgd;
+}
+
+bool SdrMarkView::IsGluePointMarked(const SdrObject* pObj, sal_uInt16 nId) const
+{
+ ForceUndirtyMrkPnt();
+ bool bRet=false;
+ const size_t nPos=TryToFindMarkedObject(pObj); // casting to NonConst
+ if (nPos!=SAL_MAX_SIZE) {
+ const SdrMark* pM=GetSdrMarkByIndex(nPos);
+ const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
+ bRet = rPts.find( nId ) != rPts.end();
+ }
+ return bRet;
+}
+
+SdrHdl* SdrMarkView::GetGluePointHdl(const SdrObject* pObj, sal_uInt16 nId) const
+{
+ ForceUndirtyMrkPnt();
+ const size_t nHdlCnt=maHdlList.GetHdlCount();
+ for (size_t nHdlNum=0; nHdlNum<nHdlCnt; ++nHdlNum) {
+ SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
+ if (pHdl->GetObj()==pObj &&
+ pHdl->GetKind()==SdrHdlKind::Glue &&
+ pHdl->GetObjHdlNum()==nId ) return pHdl;
+ }
+ return nullptr;
+}
+
+void SdrMarkView::MarkNextGluePoint()
+{
+ ForceUndirtyMrkPnt();
+ SortMarkedObjects();
+}
+
+const tools::Rectangle& SdrMarkView::GetMarkedGluePointsRect() const
+{
+ ForceUndirtyMrkPnt();
+ if (mbMarkedPointsRectsDirty) ImpSetPointsRects();
+ return maMarkedGluePointsRect;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdoashp.cxx b/svx/source/svdraw/svdoashp.cxx
new file mode 100644
index 000000000..a21c59415
--- /dev/null
+++ b/svx/source/svdraw/svdoashp.cxx
@@ -0,0 +1,3245 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/BitmapShadowFilter.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/unoapi.hxx>
+#include <com/sun/star/loader/CannotActivateFactoryException.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/XCustomShapeEngine.hpp>
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <com/sun/star/uno/Sequence.h>
+#include <tools/helpers.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svddrgmt.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <editeng/eeitem.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/adjustitem.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/sdtfchim.hxx>
+#include <svx/EnhancedCustomShapeGeometry.hxx>
+#include <svx/EnhancedCustomShapeTypeNames.hxx>
+#include <svx/EnhancedCustomShape2d.hxx>
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
+#include <editeng/writingmodeitem.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <sdr/properties/customshapeproperties.hxx>
+#include <sdr/contact/viewcontactofsdrobjcustomshape.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/sdsxyitm.hxx>
+#include <svx/sdtmfitm.hxx>
+#include <svx/sdasitm.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <svdobjplusdata.hxx>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+#include "presetooxhandleadjustmentrelations.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::drawing;
+
+static void lcl_ShapeSegmentFromBinary( EnhancedCustomShapeSegment& rSegInfo, sal_uInt16 nSDat )
+{
+ switch( nSDat >> 8 )
+ {
+ case 0x00 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::LINETO;
+ rSegInfo.Count = nSDat & 0xff;
+ if ( !rSegInfo.Count )
+ rSegInfo.Count = 1;
+ break;
+ case 0x20 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CURVETO;
+ rSegInfo.Count = nSDat & 0xff;
+ if ( !rSegInfo.Count )
+ rSegInfo.Count = 1;
+ break;
+ case 0x40 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::MOVETO;
+ rSegInfo.Count = nSDat & 0xff;
+ if ( !rSegInfo.Count )
+ rSegInfo.Count = 1;
+ break;
+ case 0x60 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
+ rSegInfo.Count = 0;
+ break;
+ case 0x80 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
+ rSegInfo.Count = 0;
+ break;
+ case 0xa1 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO;
+ rSegInfo.Count = ( nSDat & 0xff ) / 3;
+ break;
+ case 0xa2 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE;
+ rSegInfo.Count = ( nSDat & 0xff ) / 3;
+ break;
+ case 0xa3 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ARCTO;
+ rSegInfo.Count = ( nSDat & 0xff ) >> 2;
+ break;
+ case 0xa4 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ARC;
+ rSegInfo.Count = ( nSDat & 0xff ) >> 2;
+ break;
+ case 0xa5 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO;
+ rSegInfo.Count = ( nSDat & 0xff ) >> 2;
+ break;
+ case 0xa6 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CLOCKWISEARC;
+ rSegInfo.Count = ( nSDat & 0xff ) >> 2;
+ break;
+ case 0xa7 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX;
+ rSegInfo.Count = nSDat & 0xff;
+ break;
+ case 0xa8 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY;
+ rSegInfo.Count = nSDat & 0xff;
+ break;
+ case 0xaa :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::NOFILL;
+ rSegInfo.Count = 0;
+ break;
+ case 0xab :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::NOSTROKE;
+ rSegInfo.Count = 0;
+ break;
+ default:
+ case 0xf8 :
+ rSegInfo.Command = EnhancedCustomShapeSegmentCommand::UNKNOWN;
+ rSegInfo.Count = nSDat;
+ break;
+ }
+}
+
+static MSO_SPT ImpGetCustomShapeType( const SdrObjCustomShape& rCustoShape )
+{
+ MSO_SPT eRetValue = mso_sptNil;
+
+ OUString aEngine( rCustoShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE ).GetValue() );
+ if ( aEngine.isEmpty() || aEngine == "com.sun.star.drawing.EnhancedCustomShapeEngine" )
+ {
+ OUString sShapeType;
+ const SdrCustomShapeGeometryItem& rGeometryItem( rCustoShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ const Any* pAny = rGeometryItem.GetPropertyValueByName( "Type" );
+ if ( pAny && ( *pAny >>= sShapeType ) )
+ eRetValue = EnhancedCustomShapeTypeNames::Get( sShapeType );
+ }
+ return eRetValue;
+};
+
+static bool ImpVerticalSwitch( const SdrObjCustomShape& rCustoShape )
+{
+ bool bRet = false;
+ MSO_SPT eShapeType( ImpGetCustomShapeType( rCustoShape ) );
+ switch( eShapeType )
+ {
+ case mso_sptAccentBorderCallout90 : // 2 ortho
+ case mso_sptBorderCallout1 : // 2 diag
+ case mso_sptBorderCallout2 : // 3
+ {
+ bRet = true;
+ }
+ break;
+ default: break;
+ }
+ return bRet;
+}
+
+// #i37011# create a clone with all attributes changed to shadow attributes
+// and translation executed, too.
+static SdrObject* ImpCreateShadowObjectClone(const SdrObject& rOriginal, const SfxItemSet& rOriginalSet)
+{
+ SdrObject* pRetval = nullptr;
+ const bool bShadow(rOriginalSet.Get(SDRATTR_SHADOW).GetValue());
+
+ if(bShadow)
+ {
+ // create a shadow representing object
+ const sal_Int32 nXDist(rOriginalSet.Get(SDRATTR_SHADOWXDIST).GetValue());
+ const sal_Int32 nYDist(rOriginalSet.Get(SDRATTR_SHADOWYDIST).GetValue());
+ const ::Color aShadowColor(rOriginalSet.Get(SDRATTR_SHADOWCOLOR).GetColorValue());
+ const sal_uInt16 nShadowTransparence(rOriginalSet.Get(SDRATTR_SHADOWTRANSPARENCE).GetValue());
+ pRetval = rOriginal.CloneSdrObject(rOriginal.getSdrModelFromSdrObject());
+ DBG_ASSERT(pRetval, "ImpCreateShadowObjectClone: Could not clone object (!)");
+
+ // look for used stuff
+ SdrObjListIter aIterator(rOriginal);
+ bool bLineUsed(false);
+ bool bAllFillUsed(false);
+ bool bSolidFillUsed(false);
+ bool bGradientFillUsed(false);
+ bool bHatchFillUsed(false);
+ bool bBitmapFillUsed(false);
+
+ while(aIterator.IsMore())
+ {
+ SdrObject* pObj = aIterator.Next();
+ drawing::FillStyle eFillStyle = pObj->GetMergedItem(XATTR_FILLSTYLE).GetValue();
+
+ if(!bLineUsed)
+ {
+ drawing::LineStyle eLineStyle = pObj->GetMergedItem(XATTR_LINESTYLE).GetValue();
+
+ if(drawing::LineStyle_NONE != eLineStyle)
+ {
+ bLineUsed = true;
+ }
+ }
+
+ if(!bAllFillUsed)
+ {
+ if(!bSolidFillUsed && drawing::FillStyle_SOLID == eFillStyle)
+ {
+ bSolidFillUsed = true;
+ bAllFillUsed = (bSolidFillUsed && bGradientFillUsed && bHatchFillUsed && bBitmapFillUsed);
+ }
+ if(!bGradientFillUsed && drawing::FillStyle_GRADIENT == eFillStyle)
+ {
+ bGradientFillUsed = true;
+ bAllFillUsed = (bSolidFillUsed && bGradientFillUsed && bHatchFillUsed && bBitmapFillUsed);
+ }
+ if(!bHatchFillUsed && drawing::FillStyle_HATCH == eFillStyle)
+ {
+ bHatchFillUsed = true;
+ bAllFillUsed = (bSolidFillUsed && bGradientFillUsed && bHatchFillUsed && bBitmapFillUsed);
+ }
+ if(!bBitmapFillUsed && drawing::FillStyle_BITMAP == eFillStyle)
+ {
+ bBitmapFillUsed = true;
+ bAllFillUsed = (bSolidFillUsed && bGradientFillUsed && bHatchFillUsed && bBitmapFillUsed);
+ }
+ }
+ }
+
+ // translate to shadow coordinates
+ pRetval->NbcMove(Size(nXDist, nYDist));
+
+ // set items as needed
+ SfxItemSet aTempSet(rOriginalSet);
+
+ // if a SvxWritingModeItem (Top->Bottom) is set the text object
+ // is creating a paraobject, but paraobjects can not be created without model. So
+ // we are preventing the crash by setting the writing mode always left to right,
+ // this is not bad since our shadow geometry does not contain text.
+ aTempSet.Put( SvxWritingModeItem( css::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION ) );
+
+ // no shadow
+ aTempSet.Put(makeSdrShadowItem(false));
+ aTempSet.Put(makeSdrShadowXDistItem(0));
+ aTempSet.Put(makeSdrShadowYDistItem(0));
+
+ // line color and transparency like shadow
+ if(bLineUsed)
+ {
+ aTempSet.Put(XLineColorItem(OUString(), aShadowColor));
+ aTempSet.Put(XLineTransparenceItem(nShadowTransparence));
+ }
+
+ // fill color and transparency like shadow
+ if(bSolidFillUsed)
+ {
+ aTempSet.Put(XFillColorItem(OUString(), aShadowColor));
+ aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
+ }
+
+ // gradient and transparency like shadow
+ if(bGradientFillUsed)
+ {
+ XGradient aGradient(rOriginalSet.Get(XATTR_FILLGRADIENT).GetGradientValue());
+ sal_uInt8 nStartLuminance(aGradient.GetStartColor().GetLuminance());
+ sal_uInt8 nEndLuminance(aGradient.GetEndColor().GetLuminance());
+
+ if(aGradient.GetStartIntens() != 100)
+ {
+ nStartLuminance = static_cast<sal_uInt8>(nStartLuminance * (static_cast<double>(aGradient.GetStartIntens()) / 100.0));
+ }
+
+ if(aGradient.GetEndIntens() != 100)
+ {
+ nEndLuminance = static_cast<sal_uInt8>(nEndLuminance * (static_cast<double>(aGradient.GetEndIntens()) / 100.0));
+ }
+
+ ::Color aStartColor(
+ static_cast<sal_uInt8>((nStartLuminance * aShadowColor.GetRed()) / 256),
+ static_cast<sal_uInt8>((nStartLuminance * aShadowColor.GetGreen()) / 256),
+ static_cast<sal_uInt8>((nStartLuminance * aShadowColor.GetBlue()) / 256));
+
+ ::Color aEndColor(
+ static_cast<sal_uInt8>((nEndLuminance * aShadowColor.GetRed()) / 256),
+ static_cast<sal_uInt8>((nEndLuminance * aShadowColor.GetGreen()) / 256),
+ static_cast<sal_uInt8>((nEndLuminance * aShadowColor.GetBlue()) / 256));
+
+ aGradient.SetStartColor(aStartColor);
+ aGradient.SetEndColor(aEndColor);
+ aTempSet.Put(XFillGradientItem(aGradient));
+ aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
+ }
+
+ // hatch and transparency like shadow
+ if(bHatchFillUsed)
+ {
+ XHatch aHatch(rOriginalSet.Get(XATTR_FILLHATCH).GetHatchValue());
+ aHatch.SetColor(aShadowColor);
+ aTempSet.Put(XFillHatchItem(aHatch));
+ aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
+ }
+
+ // bitmap and transparency like shadow
+ if(bBitmapFillUsed)
+ {
+ GraphicObject aGraphicObject(rOriginalSet.Get(XATTR_FILLBITMAP).GetGraphicObject());
+ BitmapEx aBitmapEx(aGraphicObject.GetGraphic().GetBitmapEx());
+
+ if(!aBitmapEx.IsEmpty())
+ {
+ ScopedVclPtr<VirtualDevice> pVirDev(VclPtr<VirtualDevice>::Create());
+ pVirDev->SetOutputSizePixel(aBitmapEx.GetSizePixel());
+ BitmapFilter::Filter(aBitmapEx, BitmapShadowFilter(aShadowColor));
+ pVirDev->DrawBitmapEx(Point(), aBitmapEx);
+ aGraphicObject.SetGraphic(Graphic(pVirDev->GetBitmapEx(Point(0,0), aBitmapEx.GetSizePixel())));
+ }
+
+ aTempSet.Put(XFillBitmapItem(aGraphicObject));
+ aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
+ }
+
+ // set attributes and paint shadow object
+ pRetval->SetMergedItemSet( aTempSet );
+ }
+ return pRetval;
+}
+
+
+Reference< XCustomShapeEngine > const & SdrObjCustomShape::GetCustomShapeEngine() const
+{
+ if (mxCustomShapeEngine.is())
+ return mxCustomShapeEngine;
+
+ Reference< XShape > aXShape = GetXShapeForSdrObject(const_cast<SdrObjCustomShape*>(this));
+ if ( !aXShape )
+ return mxCustomShapeEngine;
+
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+
+ OUString aEngine(GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE ).GetValue());
+ static constexpr OUStringLiteral sEnhancedCustomShapeEngine = u"com.sun.star.drawing.EnhancedCustomShapeEngine";
+ if ( aEngine.isEmpty() )
+ aEngine = sEnhancedCustomShapeEngine;
+
+ {
+ static constexpr OUStringLiteral sCustomShape = u"CustomShape";
+ Sequence< PropertyValue > aPropValues{ comphelper::makePropertyValue(sCustomShape,
+ aXShape) };
+ Sequence< Any > aArgument{ Any(aPropValues) };
+ try
+ {
+ Reference<XInterface> xInterface(xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aEngine, aArgument, xContext));
+ if (xInterface.is())
+ mxCustomShapeEngine.set( xInterface, UNO_QUERY );
+ }
+ catch (const css::loader::CannotActivateFactoryException&)
+ {
+ }
+ }
+
+ return mxCustomShapeEngine;
+}
+
+const SdrObject* SdrObjCustomShape::GetSdrObjectFromCustomShape() const
+{
+ if ( !mXRenderedCustomShape.is() )
+ {
+ Reference< XCustomShapeEngine > xCustomShapeEngine( GetCustomShapeEngine() );
+ if ( xCustomShapeEngine.is() )
+ const_cast<SdrObjCustomShape*>(this)->mXRenderedCustomShape = xCustomShapeEngine->render();
+ }
+ SdrObject* pRenderedCustomShape = mXRenderedCustomShape.is()
+ ? SdrObject::getSdrObjectFromXShape( mXRenderedCustomShape )
+ : nullptr;
+ return pRenderedCustomShape;
+}
+
+// #i37011# Shadow geometry creation
+const SdrObject* SdrObjCustomShape::GetSdrObjectShadowFromCustomShape() const
+{
+ if(!mpLastShadowGeometry)
+ {
+ const SdrObject* pSdrObject = GetSdrObjectFromCustomShape();
+ if(pSdrObject)
+ {
+ const SfxItemSet& rOriginalSet = GetObjectItemSet();
+ const bool bShadow(rOriginalSet.Get( SDRATTR_SHADOW ).GetValue());
+
+ if(bShadow)
+ {
+ // create a clone with all attributes changed to shadow attributes
+ // and translation executed, too.
+ const_cast<SdrObjCustomShape*>(this)->mpLastShadowGeometry =
+ ImpCreateShadowObjectClone(*pSdrObject, rOriginalSet);
+ }
+ }
+ }
+
+ return mpLastShadowGeometry;
+}
+
+bool SdrObjCustomShape::IsTextPath() const
+{
+ static const OUStringLiteral sTextPath( u"TextPath" );
+ bool bTextPathOn = false;
+ const SdrCustomShapeGeometryItem& rGeometryItem = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+ const Any* pAny = rGeometryItem.GetPropertyValueByName( sTextPath, sTextPath );
+ if ( pAny )
+ *pAny >>= bTextPathOn;
+ return bTextPathOn;
+}
+
+bool SdrObjCustomShape::UseNoFillStyle() const
+{
+ bool bRet = false;
+ OUString sShapeType;
+ static const OUStringLiteral sType( u"Type" );
+ const SdrCustomShapeGeometryItem& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ const Any* pAny = rGeometryItem.GetPropertyValueByName( sType );
+ if ( pAny )
+ *pAny >>= sShapeType;
+ bRet = !IsCustomShapeFilledByDefault( EnhancedCustomShapeTypeNames::Get( sType ) );
+
+ return bRet;
+}
+
+bool SdrObjCustomShape::IsMirroredX() const
+{
+ bool bMirroredX = false;
+ const SdrCustomShapeGeometryItem & rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ const css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "MirroredX" );
+ if ( pAny )
+ *pAny >>= bMirroredX;
+ return bMirroredX;
+}
+bool SdrObjCustomShape::IsMirroredY() const
+{
+ bool bMirroredY = false;
+ const SdrCustomShapeGeometryItem & rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ const css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "MirroredY" );
+ if ( pAny )
+ *pAny >>= bMirroredY;
+ return bMirroredY;
+}
+void SdrObjCustomShape::SetMirroredX( const bool bMirrorX )
+{
+ SdrCustomShapeGeometryItem aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ PropertyValue aPropVal;
+ aPropVal.Name = "MirroredX";
+ aPropVal.Value <<= bMirrorX;
+ aGeometryItem.SetPropertyValue( aPropVal );
+ SetMergedItem( aGeometryItem );
+}
+void SdrObjCustomShape::SetMirroredY( const bool bMirrorY )
+{
+ SdrCustomShapeGeometryItem aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ PropertyValue aPropVal;
+ aPropVal.Name = "MirroredY";
+ aPropVal.Value <<= bMirrorY;
+ aGeometryItem.SetPropertyValue( aPropVal );
+ SetMergedItem( aGeometryItem );
+}
+
+double SdrObjCustomShape::GetExtraTextRotation( const bool bPreRotation ) const
+{
+ const css::uno::Any* pAny;
+ const SdrCustomShapeGeometryItem& rGeometryItem = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+ pAny = rGeometryItem.GetPropertyValueByName( bPreRotation ? OUString( "TextPreRotateAngle" ) : OUString( "TextRotateAngle" ) );
+ double fExtraTextRotateAngle = 0.0;
+ if ( pAny )
+ *pAny >>= fExtraTextRotateAngle;
+ return fExtraTextRotateAngle;
+}
+
+bool SdrObjCustomShape::GetTextBounds( tools::Rectangle& rTextBound ) const
+{
+ bool bRet = false;
+
+ Reference< XCustomShapeEngine > xCustomShapeEngine( GetCustomShapeEngine() );
+ if ( xCustomShapeEngine.is() )
+ {
+ awt::Rectangle aR( xCustomShapeEngine->getTextBounds() );
+ if ( aR.Width > 1 && aR.Height > 1 )
+ {
+ rTextBound = tools::Rectangle( Point( aR.X, aR.Y ), Size( aR.Width, aR.Height ) );
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+basegfx::B2DPolyPolygon SdrObjCustomShape::GetLineGeometry( const bool bBezierAllowed ) const
+{
+ basegfx::B2DPolyPolygon aRetval;
+ Reference< XCustomShapeEngine > xCustomShapeEngine( GetCustomShapeEngine() );
+ if ( xCustomShapeEngine.is() )
+ {
+ css::drawing::PolyPolygonBezierCoords aBezierCoords = xCustomShapeEngine->getLineGeometry();
+ try
+ {
+ aRetval = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( aBezierCoords );
+ if ( !bBezierAllowed && aRetval.areControlPointsUsed())
+ {
+ aRetval = basegfx::utils::adaptiveSubdivideByAngle(aRetval);
+ }
+ }
+ catch ( const css::lang::IllegalArgumentException & )
+ {
+ }
+ }
+ return aRetval;
+}
+
+std::vector< SdrCustomShapeInteraction > SdrObjCustomShape::GetInteractionHandles() const
+{
+ std::vector< SdrCustomShapeInteraction > aRet;
+ try
+ {
+ Reference< XCustomShapeEngine > xCustomShapeEngine( GetCustomShapeEngine() );
+ if ( xCustomShapeEngine.is() )
+ {
+ int i;
+ Sequence< Reference< XCustomShapeHandle > > xInteractionHandles( xCustomShapeEngine->getInteraction() );
+ for ( i = 0; i < xInteractionHandles.getLength(); i++ )
+ {
+ if ( xInteractionHandles[ i ].is() )
+ {
+ SdrCustomShapeInteraction aSdrCustomShapeInteraction;
+ aSdrCustomShapeInteraction.xInteraction = xInteractionHandles[ i ];
+ aSdrCustomShapeInteraction.aPosition = xInteractionHandles[ i ]->getPosition();
+
+ CustomShapeHandleModes nMode = CustomShapeHandleModes::NONE;
+ switch( ImpGetCustomShapeType( *this ) )
+ {
+ case mso_sptAccentBorderCallout90 : // 2 ortho
+ {
+ if (i == 0)
+ nMode |= CustomShapeHandleModes::RESIZE_FIXED | CustomShapeHandleModes::CREATE_FIXED;
+ else if (i == 1)
+ nMode |= CustomShapeHandleModes::RESIZE_ABSOLUTE_X | CustomShapeHandleModes::RESIZE_ABSOLUTE_Y | CustomShapeHandleModes::MOVE_SHAPE | CustomShapeHandleModes::ORTHO4;
+ }
+ break;
+
+ case mso_sptChevron :
+ case mso_sptHomePlate :
+ nMode |= CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX;
+ break;
+
+ case mso_sptWedgeRectCallout :
+ case mso_sptWedgeRRectCallout :
+ case mso_sptCloudCallout :
+ case mso_sptWedgeEllipseCallout :
+ {
+ if (i == 0)
+ nMode |= CustomShapeHandleModes::RESIZE_FIXED;
+ }
+ break;
+
+ case mso_sptBorderCallout1 : // 2 diag
+ {
+ if (i == 0)
+ nMode |= CustomShapeHandleModes::RESIZE_FIXED | CustomShapeHandleModes::CREATE_FIXED;
+ else if (i == 1)
+ nMode |= CustomShapeHandleModes::RESIZE_ABSOLUTE_X | CustomShapeHandleModes::RESIZE_ABSOLUTE_Y | CustomShapeHandleModes::MOVE_SHAPE;
+ }
+ break;
+ case mso_sptBorderCallout2 : // 3
+ {
+ if (i == 0)
+ nMode |= CustomShapeHandleModes::RESIZE_FIXED | CustomShapeHandleModes::CREATE_FIXED;
+ else if (i == 2)
+ nMode |= CustomShapeHandleModes::RESIZE_ABSOLUTE_X | CustomShapeHandleModes::RESIZE_ABSOLUTE_Y | CustomShapeHandleModes::MOVE_SHAPE;
+ }
+ break;
+ case mso_sptCallout90 :
+ case mso_sptAccentCallout90 :
+ case mso_sptBorderCallout90 :
+ case mso_sptCallout1 :
+ case mso_sptCallout2 :
+ case mso_sptCallout3 :
+ case mso_sptAccentCallout1 :
+ case mso_sptAccentCallout2 :
+ case mso_sptAccentCallout3 :
+ case mso_sptBorderCallout3 :
+ case mso_sptAccentBorderCallout1 :
+ case mso_sptAccentBorderCallout2 :
+ case mso_sptAccentBorderCallout3 :
+ {
+ if (i == 0)
+ nMode |= CustomShapeHandleModes::RESIZE_FIXED | CustomShapeHandleModes::CREATE_FIXED;
+ }
+ break;
+ default: break;
+ }
+ aSdrCustomShapeInteraction.nMode = nMode;
+ aRet.push_back( aSdrCustomShapeInteraction );
+ }
+ }
+ }
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ return aRet;
+}
+
+
+// BaseProperties section
+#define DEFAULT_MINIMUM_SIGNED_COMPARE (sal_Int32(0x80000000))
+#define DEFAULT_MAXIMUM_SIGNED_COMPARE (sal_Int32(0x7fffffff))
+
+static sal_Int32 GetNumberOfProperties ( const SvxMSDffHandle* pData )
+{
+ sal_Int32 nPropertiesNeeded=1; // position is always needed
+ SvxMSDffHandleFlags nFlags = pData->nFlags;
+
+ if ( nFlags & SvxMSDffHandleFlags::MIRRORED_X )
+ nPropertiesNeeded++;
+ if ( nFlags & SvxMSDffHandleFlags::MIRRORED_Y )
+ nPropertiesNeeded++;
+ if ( nFlags & SvxMSDffHandleFlags::SWITCHED )
+ nPropertiesNeeded++;
+ if ( nFlags & SvxMSDffHandleFlags::POLAR )
+ {
+ nPropertiesNeeded++;
+ if ( nFlags & SvxMSDffHandleFlags::RADIUS_RANGE )
+ {
+ if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
+ nPropertiesNeeded++;
+ if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
+ nPropertiesNeeded++;
+ }
+ }
+ else if ( nFlags & SvxMSDffHandleFlags::RANGE )
+ {
+ if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
+ nPropertiesNeeded++;
+ if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
+ nPropertiesNeeded++;
+ if ( pData->nRangeYMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
+ nPropertiesNeeded++;
+ if ( pData->nRangeYMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
+ nPropertiesNeeded++;
+ }
+
+ return nPropertiesNeeded;
+}
+
+static void lcl_ShapePropertiesFromDFF( const SvxMSDffHandle* pData, css::beans::PropertyValues& rPropValues )
+{
+ SvxMSDffHandleFlags nFlags = pData->nFlags;
+ sal_Int32 n=0;
+ auto pPropValues = rPropValues.getArray();
+
+ // POSITION
+ {
+ css::drawing::EnhancedCustomShapeParameterPair aPosition;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.First, pData->nPositionX, true, true );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.Second, pData->nPositionY, true, false );
+ pPropValues[ n ].Name = "Position";
+ pPropValues[ n++ ].Value <<= aPosition;
+ }
+ if ( nFlags & SvxMSDffHandleFlags::MIRRORED_X )
+ {
+ pPropValues[ n ].Name = "MirroredX";
+ pPropValues[ n++ ].Value <<= true;
+ }
+ if ( nFlags & SvxMSDffHandleFlags::MIRRORED_Y )
+ {
+ pPropValues[ n ].Name = "MirroredY";
+ pPropValues[ n++ ].Value <<= true;
+ }
+ if ( nFlags & SvxMSDffHandleFlags::SWITCHED )
+ {
+ pPropValues[ n ].Name = "Switched";
+ pPropValues[ n++ ].Value <<= true;
+ }
+ if ( nFlags & SvxMSDffHandleFlags::POLAR )
+ {
+ css::drawing::EnhancedCustomShapeParameterPair aCenter;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter.First, pData->nCenterX,
+ bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter.Second, pData->nCenterY,
+ bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false );
+ pPropValues[ n ].Name = "Polar";
+ pPropValues[ n++ ].Value <<= aCenter;
+ if ( nFlags & SvxMSDffHandleFlags::RADIUS_RANGE )
+ {
+ if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
+ {
+ css::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum, pData->nRangeXMin,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true );
+ pPropValues[ n ].Name = "RadiusRangeMinimum";
+ pPropValues[ n++ ].Value <<= aRadiusRangeMinimum;
+ }
+ if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
+ {
+ css::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum, pData->nRangeXMax,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
+ pPropValues[ n ].Name = "RadiusRangeMaximum";
+ pPropValues[ n++ ].Value <<= aRadiusRangeMaximum;
+ }
+ }
+ }
+ else if ( nFlags & SvxMSDffHandleFlags::RANGE )
+ {
+ if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
+ {
+ css::drawing::EnhancedCustomShapeParameter aRangeXMinimum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum, pData->nRangeXMin,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true );
+ pPropValues[ n ].Name = "RangeXMinimum";
+ pPropValues[ n++ ].Value <<= aRangeXMinimum;
+ }
+ if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
+ {
+ css::drawing::EnhancedCustomShapeParameter aRangeXMaximum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum, pData->nRangeXMax,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
+ pPropValues[ n ].Name = "RangeXMaximum";
+ pPropValues[ n++ ].Value <<= aRangeXMaximum;
+ }
+ if ( pData->nRangeYMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
+ {
+ css::drawing::EnhancedCustomShapeParameter aRangeYMinimum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum, pData->nRangeYMin,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL ), true );
+ pPropValues[ n ].Name = "RangeYMinimum";
+ pPropValues[ n++ ].Value <<= aRangeYMinimum;
+ }
+ if ( pData->nRangeYMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
+ {
+ css::drawing::EnhancedCustomShapeParameter aRangeYMaximum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum, pData->nRangeYMax,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL ), false );
+ pPropValues[ n ].Name = "RangeYMaximum";
+ pPropValues[ n++ ].Value <<= aRangeYMaximum;
+ }
+ }
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrObjCustomShape::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::CustomShapeProperties>(*this);
+}
+
+SdrObjCustomShape::SdrObjCustomShape(SdrModel& rSdrModel)
+: SdrTextObj(rSdrModel)
+ , fObjectRotation(0.0)
+ , mbAdjustingTextFrameWidthAndHeight(false)
+ , mpLastShadowGeometry(nullptr)
+{
+ m_bClosedObj = true; // custom shapes may be filled
+ mbTextFrame = true;
+}
+
+SdrObjCustomShape::SdrObjCustomShape(SdrModel& rSdrModel, SdrObjCustomShape const & rSource)
+: SdrTextObj(rSdrModel, rSource)
+ , fObjectRotation(0.0)
+ , mbAdjustingTextFrameWidthAndHeight(false)
+ , mpLastShadowGeometry(nullptr)
+{
+ m_bClosedObj = true; // custom shapes may be filled
+ mbTextFrame = true;
+
+ fObjectRotation = rSource.fObjectRotation;
+ mbAdjustingTextFrameWidthAndHeight = rSource.mbAdjustingTextFrameWidthAndHeight;
+ assert(!mbAdjustingTextFrameWidthAndHeight);
+ InvalidateRenderGeometry();
+}
+
+SdrObjCustomShape::~SdrObjCustomShape()
+{
+ // delete buffered display geometry
+ InvalidateRenderGeometry();
+}
+
+void SdrObjCustomShape::MergeDefaultAttributes( const OUString* pType )
+{
+ PropertyValue aPropVal;
+ OUString sShapeType;
+ static const OUStringLiteral sType( u"Type" );
+ SdrCustomShapeGeometryItem aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ if ( pType && !pType->isEmpty() )
+ {
+ sal_Int32 nType = pType->toInt32();
+ if ( nType )
+ sShapeType = EnhancedCustomShapeTypeNames::Get( static_cast< MSO_SPT >( nType ) );
+ else
+ sShapeType = *pType;
+
+ aPropVal.Name = sType;
+ aPropVal.Value <<= sShapeType;
+ aGeometryItem.SetPropertyValue( aPropVal );
+ }
+ else
+ {
+ Any *pAny = aGeometryItem.GetPropertyValueByName( sType );
+ if ( pAny )
+ *pAny >>= sShapeType;
+ }
+ MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
+
+ const sal_Int32* pDefData = nullptr;
+ const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eSpType );
+ if ( pDefCustomShape )
+ pDefData = pDefCustomShape->pDefData;
+
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > seqAdjustmentValues;
+
+
+ // AdjustmentValues
+
+ static const OUStringLiteral sAdjustmentValues( u"AdjustmentValues" );
+ const Any* pAny = aGeometryItem.GetPropertyValueByName( sAdjustmentValues );
+ if ( pAny )
+ *pAny >>= seqAdjustmentValues;
+ if ( pDefCustomShape && pDefData ) // now check if we have to default some adjustment values
+ {
+ // first check if there are adjustment values are to be appended
+ sal_Int32 i, nAdjustmentValues = seqAdjustmentValues.getLength();
+ sal_Int32 nAdjustmentDefaults = *pDefData++;
+ if ( nAdjustmentDefaults > nAdjustmentValues )
+ seqAdjustmentValues.realloc( nAdjustmentDefaults );
+ auto pseqAdjustmentValues = seqAdjustmentValues.getArray();
+ for ( i = nAdjustmentValues; i < nAdjustmentDefaults; i++ )
+ {
+ pseqAdjustmentValues[ i ].Value <<= pDefData[ i ];
+ pseqAdjustmentValues[ i ].State = css::beans::PropertyState_DIRECT_VALUE;
+ }
+ // check if there are defaulted adjustment values that should be filled the hard coded defaults (pDefValue)
+ sal_Int32 nCount = std::min(nAdjustmentValues, nAdjustmentDefaults);
+ for ( i = 0; i < nCount; i++ )
+ {
+ if ( seqAdjustmentValues[ i ].State != css::beans::PropertyState_DIRECT_VALUE )
+ {
+ pseqAdjustmentValues[ i ].Value <<= pDefData[ i ];
+ pseqAdjustmentValues[ i ].State = css::beans::PropertyState_DIRECT_VALUE;
+ }
+ }
+ }
+ aPropVal.Name = sAdjustmentValues;
+ aPropVal.Value <<= seqAdjustmentValues;
+ aGeometryItem.SetPropertyValue( aPropVal );
+
+
+ // Coordsize
+
+ static const OUStringLiteral sViewBox( u"ViewBox" );
+ const Any* pViewBox = aGeometryItem.GetPropertyValueByName( sViewBox );
+ css::awt::Rectangle aViewBox;
+ if ( !pViewBox || !(*pViewBox >>= aViewBox ) )
+ {
+ if ( pDefCustomShape )
+ {
+ aViewBox.X = 0;
+ aViewBox.Y = 0;
+ aViewBox.Width = pDefCustomShape->nCoordWidth;
+ aViewBox.Height= pDefCustomShape->nCoordHeight;
+ aPropVal.Name = sViewBox;
+ aPropVal.Value <<= aViewBox;
+ aGeometryItem.SetPropertyValue( aPropVal );
+ }
+ }
+
+ static const OUStringLiteral sPath( u"Path" );
+
+
+ // Path/Coordinates
+
+ static const OUStringLiteral sCoordinates( u"Coordinates" );
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, sCoordinates );
+ if ( !pAny && pDefCustomShape && pDefCustomShape->nVertices && pDefCustomShape->pVertices )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nVertices;
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqCoordinates( nCount );
+ auto pseqCoordinates = seqCoordinates.getArray();
+ for ( i = 0; i < nCount; i++ )
+ {
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates[ i ].First, pDefCustomShape->pVertices[ i ].nValA );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates[ i ].Second, pDefCustomShape->pVertices[ i ].nValB );
+ }
+ aPropVal.Name = sCoordinates;
+ aPropVal.Value <<= seqCoordinates;
+ aGeometryItem.SetPropertyValue( sPath, aPropVal );
+ }
+
+ // Path/GluePoints
+ static const OUStringLiteral sGluePoints( u"GluePoints" );
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, sGluePoints );
+ if ( !pAny && pDefCustomShape && pDefCustomShape->nGluePoints && pDefCustomShape->pGluePoints )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nGluePoints;
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqGluePoints( nCount );
+ auto pseqGluePoints = seqGluePoints.getArray();
+ for ( i = 0; i < nCount; i++ )
+ {
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints[ i ].First, pDefCustomShape->pGluePoints[ i ].nValA );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints[ i ].Second, pDefCustomShape->pGluePoints[ i ].nValB );
+ }
+ aPropVal.Name = sGluePoints;
+ aPropVal.Value <<= seqGluePoints;
+ aGeometryItem.SetPropertyValue( sPath, aPropVal );
+ }
+
+ // Path/Segments
+ static const OUStringLiteral sSegments( u"Segments" );
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, sSegments );
+ if ( !pAny && pDefCustomShape && pDefCustomShape->nElements && pDefCustomShape->pElements )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nElements;
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > seqSegments( nCount );
+ auto pseqSegments = seqSegments.getArray();
+ for ( i = 0; i < nCount; i++ )
+ {
+ EnhancedCustomShapeSegment& rSegInfo = pseqSegments[ i ];
+ sal_uInt16 nSDat = pDefCustomShape->pElements[ i ];
+ lcl_ShapeSegmentFromBinary( rSegInfo, nSDat );
+ }
+ aPropVal.Name = sSegments;
+ aPropVal.Value <<= seqSegments;
+ aGeometryItem.SetPropertyValue( sPath, aPropVal );
+ }
+
+ // Path/StretchX
+ static const OUStringLiteral sStretchX( u"StretchX" );
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, sStretchX );
+ if ( !pAny && pDefCustomShape )
+ {
+ sal_Int32 nXRef = pDefCustomShape->nXRef;
+ if ( nXRef != DEFAULT_MINIMUM_SIGNED_COMPARE )
+ {
+ aPropVal.Name = sStretchX;
+ aPropVal.Value <<= nXRef;
+ aGeometryItem.SetPropertyValue( sPath, aPropVal );
+ }
+ }
+
+ // Path/StretchY
+ static const OUStringLiteral sStretchY( u"StretchY" );
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, sStretchY );
+ if ( !pAny && pDefCustomShape )
+ {
+ sal_Int32 nYRef = pDefCustomShape->nYRef;
+ if ( nYRef != DEFAULT_MINIMUM_SIGNED_COMPARE )
+ {
+ aPropVal.Name = sStretchY;
+ aPropVal.Value <<= nYRef;
+ aGeometryItem.SetPropertyValue( sPath, aPropVal );
+ }
+ }
+
+ // Path/TextFrames
+ static const OUStringLiteral sTextFrames( u"TextFrames" );
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, sTextFrames );
+ if ( !pAny && pDefCustomShape && pDefCustomShape->nTextRect && pDefCustomShape->pTextRect )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nTextRect;
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > seqTextFrames( nCount );
+ auto pseqTextFrames = seqTextFrames.getArray();
+ const SvxMSDffTextRectangles* pRectangles = pDefCustomShape->pTextRect;
+ for ( i = 0; i < nCount; i++, pRectangles++ )
+ {
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames[ i ].TopLeft.First, pRectangles->nPairA.nValA );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames[ i ].TopLeft.Second, pRectangles->nPairA.nValB );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames[ i ].BottomRight.First, pRectangles->nPairB.nValA );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames[ i ].BottomRight.Second, pRectangles->nPairB.nValB );
+ }
+ aPropVal.Name = sTextFrames;
+ aPropVal.Value <<= seqTextFrames;
+ aGeometryItem.SetPropertyValue( sPath, aPropVal );
+ }
+
+ // Equations
+ static const OUStringLiteral sEquations( u"Equations" );
+ pAny = aGeometryItem.GetPropertyValueByName( sEquations );
+ if ( !pAny && pDefCustomShape && pDefCustomShape->nCalculation && pDefCustomShape->pCalculation )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nCalculation;
+ css::uno::Sequence< OUString > seqEquations( nCount );
+ auto pseqEquations = seqEquations.getArray();
+ const SvxMSDffCalculationData* pData = pDefCustomShape->pCalculation;
+ for ( i = 0; i < nCount; i++, pData++ )
+ pseqEquations[ i ] = EnhancedCustomShape2d::GetEquation( pData->nFlags, pData->nVal[ 0 ], pData->nVal[ 1 ], pData->nVal[ 2 ] );
+ aPropVal.Name = sEquations;
+ aPropVal.Value <<= seqEquations;
+ aGeometryItem.SetPropertyValue( aPropVal );
+ }
+
+ // Handles
+ static const OUStringLiteral sHandles( u"Handles" );
+ pAny = aGeometryItem.GetPropertyValueByName( sHandles );
+ if ( !pAny && pDefCustomShape && pDefCustomShape->nHandles && pDefCustomShape->pHandles )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nHandles;
+ const SvxMSDffHandle* pData = pDefCustomShape->pHandles;
+ css::uno::Sequence< css::beans::PropertyValues > seqHandles( nCount );
+ auto pseqHandles = seqHandles.getArray();
+ for ( i = 0; i < nCount; i++, pData++ )
+ {
+ sal_Int32 nPropertiesNeeded;
+ css::beans::PropertyValues& rPropValues = pseqHandles[ i ];
+ nPropertiesNeeded = GetNumberOfProperties( pData );
+ rPropValues.realloc( nPropertiesNeeded );
+ lcl_ShapePropertiesFromDFF( pData, rPropValues );
+ }
+ aPropVal.Name = sHandles;
+ aPropVal.Value <<= seqHandles;
+ aGeometryItem.SetPropertyValue( aPropVal );
+ }
+ else if (pAny && sShapeType.startsWith("ooxml-") && sShapeType != "ooxml-non-primitive")
+ {
+ // ODF is not able to store the ooxml way of connecting handle to an adjustment
+ // value by name, e.g. attribute RefX="adj". So the information is lost, when exporting
+ // a pptx to odp, for example. This part reconstructs this information for the
+ // ooxml preset shapes from their definition.
+ css::uno::Sequence<css::beans::PropertyValues> seqHandles;
+ *pAny >>= seqHandles;
+ auto seqHandlesRange = asNonConstRange(seqHandles);
+ bool bChanged(false);
+ for (sal_Int32 i = 0; i < seqHandles.getLength(); i++)
+ {
+ comphelper::SequenceAsHashMap aHandleProps(seqHandles[i]);
+ OUString sFirstRefType;
+ sal_Int32 nFirstAdjRef;
+ OUString sSecondRefType;
+ sal_Int32 nSecondAdjRef;
+ PresetOOXHandleAdj::GetOOXHandleAdjRelation(sShapeType, i, sFirstRefType, nFirstAdjRef,
+ sSecondRefType, nSecondAdjRef);
+ if (sFirstRefType != "na" && 0 <= nFirstAdjRef
+ && nFirstAdjRef < seqAdjustmentValues.getLength())
+ {
+ bChanged |= aHandleProps.createItemIfMissing(sFirstRefType, nFirstAdjRef);
+ }
+ if (sSecondRefType != "na" && 0 <= nSecondAdjRef
+ && nSecondAdjRef < seqAdjustmentValues.getLength())
+ {
+ bChanged |= aHandleProps.createItemIfMissing(sSecondRefType, nSecondAdjRef);
+ }
+ aHandleProps >> seqHandlesRange[i];
+ }
+ if (bChanged)
+ {
+ aPropVal.Name = sHandles;
+ aPropVal.Value <<= seqHandles;
+ aGeometryItem.SetPropertyValue(aPropVal);
+ }
+ }
+
+ SetMergedItem( aGeometryItem );
+}
+
+bool SdrObjCustomShape::IsDefaultGeometry( const DefaultType eDefaultType ) const
+{
+ bool bIsDefaultGeometry = false;
+
+ OUString sShapeType;
+ const SdrCustomShapeGeometryItem & rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+
+ const Any *pAny = rGeometryItem.GetPropertyValueByName( "Type" );
+ if ( pAny )
+ *pAny >>= sShapeType;
+
+ MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
+
+ const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eSpType );
+ static const OUStringLiteral sPath( u"Path" );
+ switch( eDefaultType )
+ {
+ case DefaultType::Viewbox :
+ {
+ const Any* pViewBox = rGeometryItem.GetPropertyValueByName( "ViewBox" );
+ css::awt::Rectangle aViewBox;
+ if (pViewBox && (*pViewBox >>= aViewBox) && pDefCustomShape)
+ {
+ if ( ( aViewBox.Width == pDefCustomShape->nCoordWidth )
+ && ( aViewBox.Height == pDefCustomShape->nCoordHeight ) )
+ bIsDefaultGeometry = true;
+ }
+ }
+ break;
+
+ case DefaultType::Path :
+ {
+ pAny = rGeometryItem.GetPropertyValueByName( sPath, "Coordinates" );
+ if ( pAny && pDefCustomShape && pDefCustomShape->nVertices && pDefCustomShape->pVertices )
+ {
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqCoordinates1;
+ if ( *pAny >>= seqCoordinates1 )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nVertices;
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqCoordinates2( nCount );
+ auto pseqCoordinates2 = seqCoordinates2.getArray();
+ for ( i = 0; i < nCount; i++ )
+ {
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates2[ i ].First, pDefCustomShape->pVertices[ i ].nValA );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates2[ i ].Second, pDefCustomShape->pVertices[ i ].nValB );
+ }
+ if ( seqCoordinates1 == seqCoordinates2 )
+ bIsDefaultGeometry = true;
+ }
+ }
+ else if ( pDefCustomShape && ( ( pDefCustomShape->nVertices == 0 ) || ( pDefCustomShape->pVertices == nullptr ) ) )
+ bIsDefaultGeometry = true;
+ }
+ break;
+
+ case DefaultType::Gluepoints :
+ {
+ pAny = rGeometryItem.GetPropertyValueByName( sPath, "GluePoints" );
+ if ( pAny && pDefCustomShape && pDefCustomShape->nGluePoints && pDefCustomShape->pGluePoints )
+ {
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqGluePoints1;
+ if ( *pAny >>= seqGluePoints1 )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nGluePoints;
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqGluePoints2( nCount );
+ auto pseqGluePoints2 = seqGluePoints2.getArray();
+ for ( i = 0; i < nCount; i++ )
+ {
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints2[ i ].First, pDefCustomShape->pGluePoints[ i ].nValA );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints2[ i ].Second, pDefCustomShape->pGluePoints[ i ].nValB );
+ }
+ if ( seqGluePoints1 == seqGluePoints2 )
+ bIsDefaultGeometry = true;
+ }
+ }
+ else if ( pDefCustomShape && ( pDefCustomShape->nGluePoints == 0 ) )
+ bIsDefaultGeometry = true;
+ }
+ break;
+
+ case DefaultType::Segments :
+ {
+ // Path/Segments
+ pAny = rGeometryItem.GetPropertyValueByName( sPath, "Segments" );
+ if ( pAny )
+ {
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > seqSegments1;
+ if ( *pAny >>= seqSegments1 )
+ {
+ if ( pDefCustomShape && pDefCustomShape->nElements && pDefCustomShape->pElements )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nElements;
+ if ( nCount )
+ {
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > seqSegments2( nCount );
+ auto pseqSegments2 = seqSegments2.getArray();
+ for ( i = 0; i < nCount; i++ )
+ {
+ EnhancedCustomShapeSegment& rSegInfo = pseqSegments2[ i ];
+ sal_uInt16 nSDat = pDefCustomShape->pElements[ i ];
+ lcl_ShapeSegmentFromBinary( rSegInfo, nSDat );
+ }
+ if ( seqSegments1 == seqSegments2 )
+ bIsDefaultGeometry = true;
+ }
+ }
+ else
+ {
+ // check if it's the default segment description ( M L Z N )
+ if ( seqSegments1.getLength() == 4 )
+ {
+ if ( ( seqSegments1[ 0 ].Command == EnhancedCustomShapeSegmentCommand::MOVETO )
+ && ( seqSegments1[ 1 ].Command == EnhancedCustomShapeSegmentCommand::LINETO )
+ && ( seqSegments1[ 2 ].Command == EnhancedCustomShapeSegmentCommand::CLOSESUBPATH )
+ && ( seqSegments1[ 3 ].Command == EnhancedCustomShapeSegmentCommand::ENDSUBPATH ) )
+ bIsDefaultGeometry = true;
+ }
+ }
+ }
+ }
+ else if ( pDefCustomShape && ( ( pDefCustomShape->nElements == 0 ) || ( pDefCustomShape->pElements == nullptr ) ) )
+ bIsDefaultGeometry = true;
+ }
+ break;
+
+ case DefaultType::StretchX :
+ {
+ pAny = rGeometryItem.GetPropertyValueByName( sPath, "StretchX" );
+ if ( pAny && pDefCustomShape )
+ {
+ sal_Int32 nStretchX = 0;
+ if ( *pAny >>= nStretchX )
+ {
+ if ( pDefCustomShape->nXRef == nStretchX )
+ bIsDefaultGeometry = true;
+ }
+ }
+ else if ( pDefCustomShape && ( pDefCustomShape->nXRef == DEFAULT_MINIMUM_SIGNED_COMPARE ) )
+ bIsDefaultGeometry = true;
+ }
+ break;
+
+ case DefaultType::StretchY :
+ {
+ pAny = rGeometryItem.GetPropertyValueByName( sPath, "StretchY" );
+ if ( pAny && pDefCustomShape )
+ {
+ sal_Int32 nStretchY = 0;
+ if ( *pAny >>= nStretchY )
+ {
+ if ( pDefCustomShape->nYRef == nStretchY )
+ bIsDefaultGeometry = true;
+ }
+ }
+ else if ( pDefCustomShape && ( pDefCustomShape->nYRef == DEFAULT_MINIMUM_SIGNED_COMPARE ) )
+ bIsDefaultGeometry = true;
+ }
+ break;
+
+ case DefaultType::Equations :
+ {
+ pAny = rGeometryItem.GetPropertyValueByName( "Equations" );
+ if ( pAny && pDefCustomShape && pDefCustomShape->nCalculation && pDefCustomShape->pCalculation )
+ {
+ css::uno::Sequence< OUString > seqEquations1;
+ if ( *pAny >>= seqEquations1 )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nCalculation;
+ css::uno::Sequence< OUString > seqEquations2( nCount );
+ auto pseqEquations2 = seqEquations2.getArray();
+
+ const SvxMSDffCalculationData* pData = pDefCustomShape->pCalculation;
+ for ( i = 0; i < nCount; i++, pData++ )
+ pseqEquations2[ i ] = EnhancedCustomShape2d::GetEquation( pData->nFlags, pData->nVal[ 0 ], pData->nVal[ 1 ], pData->nVal[ 2 ] );
+
+ if ( seqEquations1 == seqEquations2 )
+ bIsDefaultGeometry = true;
+ }
+ }
+ else if ( pDefCustomShape && ( ( pDefCustomShape->nCalculation == 0 ) || ( pDefCustomShape->pCalculation == nullptr ) ) )
+ bIsDefaultGeometry = true;
+ }
+ break;
+
+ case DefaultType::TextFrames :
+ {
+ pAny = rGeometryItem.GetPropertyValueByName( sPath, "TextFrames" );
+ if ( pAny && pDefCustomShape && pDefCustomShape->nTextRect && pDefCustomShape->pTextRect )
+ {
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > seqTextFrames1;
+ if ( *pAny >>= seqTextFrames1 )
+ {
+ sal_Int32 i, nCount = pDefCustomShape->nTextRect;
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > seqTextFrames2( nCount );
+ auto pseqTextFrames2 = seqTextFrames2.getArray();
+ const SvxMSDffTextRectangles* pRectangles = pDefCustomShape->pTextRect;
+ for ( i = 0; i < nCount; i++, pRectangles++ )
+ {
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2[ i ].TopLeft.First, pRectangles->nPairA.nValA );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2[ i ].TopLeft.Second, pRectangles->nPairA.nValB );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2[ i ].BottomRight.First, pRectangles->nPairB.nValA );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2[ i ].BottomRight.Second, pRectangles->nPairB.nValB );
+ }
+ if ( seqTextFrames1 == seqTextFrames2 )
+ bIsDefaultGeometry = true;
+ }
+ }
+ else if ( pDefCustomShape && ( ( pDefCustomShape->nTextRect == 0 ) || ( pDefCustomShape->pTextRect == nullptr ) ) )
+ bIsDefaultGeometry = true;
+ }
+ break;
+ }
+ return bIsDefaultGeometry;
+}
+
+void SdrObjCustomShape::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bResizeFreeAllowed=fObjectRotation == 0.0;
+ rInfo.bResizePropAllowed=true;
+ rInfo.bRotateFreeAllowed=true;
+ rInfo.bRotate90Allowed =true;
+ rInfo.bMirrorFreeAllowed=true;
+ rInfo.bMirror45Allowed =true;
+ rInfo.bMirror90Allowed =true;
+ rInfo.bTransparenceAllowed = false;
+ rInfo.bShearAllowed =true;
+ rInfo.bEdgeRadiusAllowed=false;
+ rInfo.bNoContortion =true;
+
+ // #i37011#
+ if ( !mXRenderedCustomShape.is() )
+ return;
+
+ const SdrObject* pRenderedCustomShape = SdrObject::getSdrObjectFromXShape( mXRenderedCustomShape );
+ if ( !pRenderedCustomShape )
+ return;
+
+ // #i37262#
+ // Iterate self over the contained objects, since there are combinations of
+ // polygon and curve objects. In that case, aInfo.bCanConvToPath and
+ // aInfo.bCanConvToPoly would be false. What is needed here is an or, not an and.
+ SdrObjListIter aIterator(*pRenderedCustomShape);
+ while(aIterator.IsMore())
+ {
+ SdrObject* pCandidate = aIterator.Next();
+ SdrObjTransformInfoRec aInfo;
+ pCandidate->TakeObjInfo(aInfo);
+
+ // set path and poly conversion if one is possible since
+ // this object will first be broken
+ const bool bCanConvToPathOrPoly(aInfo.bCanConvToPath || aInfo.bCanConvToPoly);
+ if(rInfo.bCanConvToPath != bCanConvToPathOrPoly)
+ {
+ rInfo.bCanConvToPath = bCanConvToPathOrPoly;
+ }
+
+ if(rInfo.bCanConvToPoly != bCanConvToPathOrPoly)
+ {
+ rInfo.bCanConvToPoly = bCanConvToPathOrPoly;
+ }
+
+ if(rInfo.bCanConvToContour != aInfo.bCanConvToContour)
+ {
+ rInfo.bCanConvToContour = aInfo.bCanConvToContour;
+ }
+
+ if(rInfo.bShearAllowed != aInfo.bShearAllowed)
+ {
+ rInfo.bShearAllowed = aInfo.bShearAllowed;
+ }
+ }
+}
+
+SdrObjKind SdrObjCustomShape::GetObjIdentifier() const
+{
+ return SdrObjKind::CustomShape;
+}
+
+// #115391# This implementation is based on the TextFrame size of the CustomShape and the
+// state of the ResizeShapeToFitText flag to correctly set TextMinFrameWidth/Height
+void SdrObjCustomShape::AdaptTextMinSize()
+{
+ if (getSdrModelFromSdrObject().IsCreatingDataObj() || getSdrModelFromSdrObject().IsPasteResize())
+ return;
+
+ // check if we need to change anything before creating an SfxItemSet, because that is expensive
+ const bool bResizeShapeToFitText(GetObjectItem(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue());
+ tools::Rectangle aTextBound(maRect);
+ bool bChanged(false);
+ if(bResizeShapeToFitText)
+ bChanged = true;
+ else if(GetTextBounds(aTextBound))
+ bChanged = true;
+ if (!bChanged)
+ return;
+
+ SfxItemSetFixed<SDRATTR_TEXT_MINFRAMEHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT,
+ SDRATTR_TEXT_MINFRAMEWIDTH, SDRATTR_TEXT_AUTOGROWWIDTH> // contains SDRATTR_TEXT_MAXFRAMEWIDTH
+ aSet(*GetObjectItemSet().GetPool());
+
+ if(bResizeShapeToFitText)
+ {
+ // always reset MinWidthHeight to zero to only rely on text size and frame size
+ // to allow resizing being completely dependent on text size only
+ aSet.Put(makeSdrTextMinFrameWidthItem(0));
+ aSet.Put(makeSdrTextMinFrameHeightItem(0));
+ }
+ else
+ {
+ // recreate from CustomShape-specific TextBounds
+ const tools::Long nHDist(GetTextLeftDistance() + GetTextRightDistance());
+ const tools::Long nVDist(GetTextUpperDistance() + GetTextLowerDistance());
+ const tools::Long nTWdt(std::max(tools::Long(0), static_cast<tools::Long>(aTextBound.GetWidth() - 1 - nHDist)));
+ const tools::Long nTHgt(std::max(tools::Long(0), static_cast<tools::Long>(aTextBound.GetHeight() - 1 - nVDist)));
+
+ aSet.Put(makeSdrTextMinFrameWidthItem(nTWdt));
+ aSet.Put(makeSdrTextMinFrameHeightItem(nTHgt));
+ }
+
+ SetObjectItemSet(aSet);
+}
+
+void SdrObjCustomShape::NbcSetSnapRect( const tools::Rectangle& rRect )
+{
+ maRect = rRect;
+ ImpJustifyRect(maRect);
+ InvalidateRenderGeometry();
+
+ AdaptTextMinSize();
+
+ ImpCheckShear();
+ SetBoundAndSnapRectsDirty();
+ SetChanged();
+}
+
+void SdrObjCustomShape::SetSnapRect( const tools::Rectangle& rRect )
+{
+ tools::Rectangle aBoundRect0;
+ if ( m_pUserCall )
+ aBoundRect0 = GetLastBoundRect();
+ NbcSetSnapRect( rRect );
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrObjCustomShape::NbcSetLogicRect( const tools::Rectangle& rRect )
+{
+ maRect = rRect;
+ ImpJustifyRect(maRect);
+ InvalidateRenderGeometry();
+
+ AdaptTextMinSize();
+
+ SetBoundAndSnapRectsDirty();
+ SetChanged();
+}
+
+void SdrObjCustomShape::SetLogicRect( const tools::Rectangle& rRect )
+{
+ tools::Rectangle aBoundRect0;
+ if ( m_pUserCall )
+ aBoundRect0 = GetLastBoundRect();
+ NbcSetLogicRect(rRect);
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrObjCustomShape::Move( const Size& rSiz )
+{
+ if ( rSiz.Width() || rSiz.Height() )
+ {
+ tools::Rectangle aBoundRect0;
+ if ( m_pUserCall )
+ aBoundRect0 = GetLastBoundRect();
+ NbcMove(rSiz);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
+ }
+}
+void SdrObjCustomShape::NbcMove( const Size& rSiz )
+{
+ SdrTextObj::NbcMove( rSiz );
+ if ( mXRenderedCustomShape.is() )
+ {
+ SdrObject* pRenderedCustomShape = SdrObject::getSdrObjectFromXShape(mXRenderedCustomShape);
+ if ( pRenderedCustomShape )
+ {
+ // #i97149# the visualisation shape needs to be informed
+ // about change, too
+ pRenderedCustomShape->ActionChanged();
+ pRenderedCustomShape->NbcMove( rSiz );
+ }
+ }
+
+ // #i37011# adapt geometry shadow
+ if(mpLastShadowGeometry)
+ {
+ mpLastShadowGeometry->NbcMove( rSiz );
+ }
+}
+
+void SdrObjCustomShape::NbcResize( const Point& rRef, const Fraction& rxFact, const Fraction& ryFact )
+{
+ // taking care of handles that should not been changed
+ tools::Rectangle aOld( maRect );
+ std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
+
+ SdrTextObj::NbcResize( rRef, rxFact, ryFact );
+
+ if ( ( rxFact.GetNumerator() != rxFact.GetDenominator() )
+ || ( ryFact.GetNumerator()!= ryFact.GetDenominator() ) )
+ {
+ if ( ( ( rxFact.GetNumerator() < 0 ) && ( rxFact.GetDenominator() > 0 ) ) ||
+ ( ( rxFact.GetNumerator() > 0 ) && ( rxFact.GetDenominator() < 0 ) ) )
+ {
+ SetMirroredX( !IsMirroredX() );
+ }
+ if ( ( ( ryFact.GetNumerator() < 0 ) && ( ryFact.GetDenominator() > 0 ) ) ||
+ ( ( ryFact.GetNumerator() > 0 ) && ( ryFact.GetDenominator() < 0 ) ) )
+ {
+ SetMirroredY( !IsMirroredY() );
+ }
+ }
+
+ for (const auto& rInteraction : aInteractionHandles)
+ {
+ try
+ {
+ if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_FIXED )
+ rInteraction.xInteraction->setControllerPosition( rInteraction.aPosition );
+ if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_X )
+ {
+ sal_Int32 nX = ( rInteraction.aPosition.X - aOld.Left() ) + maRect.Left();
+ rInteraction.xInteraction->setControllerPosition( css::awt::Point( nX, rInteraction.xInteraction->getPosition().Y ) );
+ }
+ else if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX )
+ {
+ sal_Int32 nX = maRect.Right() - (aOld.Right() - rInteraction.aPosition.X);
+ rInteraction.xInteraction->setControllerPosition( css::awt::Point( nX, rInteraction.xInteraction->getPosition().Y ) );
+ }
+ if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_Y )
+ {
+ sal_Int32 nY = ( rInteraction.aPosition.Y - aOld.Top() ) + maRect.Top();
+ rInteraction.xInteraction->setControllerPosition( css::awt::Point( rInteraction.xInteraction->getPosition().X, nY ) );
+ }
+ }
+ catch ( const uno::RuntimeException& )
+ {
+ }
+ }
+
+ // updating fObjectRotation
+ Degree100 nTextObjRotation = maGeo.nRotationAngle;
+ double fAngle = toDegrees(nTextObjRotation);
+ if (IsMirroredX())
+ {
+ if (IsMirroredY())
+ fObjectRotation = fAngle - 180.0;
+ else
+ fObjectRotation = -fAngle;
+ }
+ else
+ {
+ if (IsMirroredY())
+ fObjectRotation = 180.0 - fAngle;
+ else
+ fObjectRotation = fAngle;
+ }
+ while (fObjectRotation < 0)
+ fObjectRotation += 360.0;
+ while (fObjectRotation >= 360.0)
+ fObjectRotation -= 360.0;
+
+ InvalidateRenderGeometry();
+}
+
+void SdrObjCustomShape::NbcRotate( const Point& rRef, Degree100 nAngle, double sn, double cs )
+{
+ bool bMirroredX = IsMirroredX();
+ bool bMirroredY = IsMirroredY();
+
+ fObjectRotation = fmod( fObjectRotation, 360.0 );
+ if ( fObjectRotation < 0 )
+ fObjectRotation = 360 + fObjectRotation;
+
+ // the rotation angle for ashapes is stored in fObjectRotation, this rotation
+ // has to be applied to the text object (which is internally using maGeo.nAngle).
+ SdrTextObj::NbcRotate( maRect.TopLeft(), -maGeo.nRotationAngle, // retrieving the unrotated text object
+ -maGeo.mfSinRotationAngle,
+ maGeo.mfCosRotationAngle );
+ maGeo.nRotationAngle = 0_deg100; // resetting aGeo data
+ maGeo.RecalcSinCos();
+
+ Degree100 nW(static_cast<sal_Int32>( fObjectRotation * 100 )); // applying our object rotation
+ if ( bMirroredX )
+ nW = 36000_deg100 - nW;
+ if ( bMirroredY )
+ nW = 18000_deg100 - nW;
+ nW = nW % 36000_deg100;
+ if ( nW < 0_deg100 )
+ nW = 36000_deg100 + nW;
+ SdrTextObj::NbcRotate( maRect.TopLeft(), nW, // applying text rotation
+ sin( toRadians(nW) ),
+ cos( toRadians(nW) ) );
+
+ int nSwap = 0;
+ if ( bMirroredX )
+ nSwap ^= 1;
+ if ( bMirroredY )
+ nSwap ^= 1;
+
+ double fAngle = toDegrees(nAngle); // updating to our new object rotation
+ fObjectRotation = fmod( nSwap ? fObjectRotation - fAngle : fObjectRotation + fAngle, 360.0 );
+ if ( fObjectRotation < 0 )
+ fObjectRotation = 360 + fObjectRotation;
+
+ SdrTextObj::NbcRotate( rRef, nAngle, sn, cs ); // applying text rotation
+ InvalidateRenderGeometry();
+}
+
+void SdrObjCustomShape::NbcMirror( const Point& rRef1, const Point& rRef2 )
+{
+ // TTTT: Fix for old mirroring, can be removed again in aw080
+ // storing horizontal and vertical flipping without modifying the rotate angle
+ // decompose other flipping to rotation and MirrorX.
+ tools::Long ndx = rRef2.X()-rRef1.X();
+ tools::Long ndy = rRef2.Y()-rRef1.Y();
+
+ if(!ndx) // MirroredX
+ {
+ SetMirroredX(!IsMirroredX());
+ SdrTextObj::NbcMirror( rRef1, rRef2 );
+ }
+ else
+ {
+ if(!ndy) // MirroredY
+ {
+ SetMirroredY(!IsMirroredY());
+ SdrTextObj::NbcMirror( rRef1, rRef2 );
+ }
+ else // neither horizontal nor vertical
+ {
+ SetMirroredX(!IsMirroredX());
+
+ // call parent
+ SdrTextObj::NbcMirror( rRef1, rRef2 );
+
+ // update fObjectRotation
+ Degree100 nTextObjRotation = maGeo.nRotationAngle;
+ double fAngle = toDegrees(nTextObjRotation);
+
+ bool bSingleFlip = (IsMirroredX()!= IsMirroredY());
+
+ fObjectRotation = fmod( bSingleFlip ? -fAngle : fAngle, 360.0 );
+
+ if ( fObjectRotation < 0 )
+ {
+ fObjectRotation = 360.0 + fObjectRotation;
+ }
+ }
+ }
+
+ InvalidateRenderGeometry();
+}
+
+void SdrObjCustomShape::Shear( const Point& rRef, Degree100 nAngle, double tn, bool bVShear )
+{
+ SdrTextObj::Shear( rRef, nAngle, tn, bVShear );
+ InvalidateRenderGeometry();
+}
+void SdrObjCustomShape::NbcShear( const Point& rRef, Degree100 nAngle, double tn, bool bVShear )
+{
+ // TTTT: Fix for old mirroring, can be removed again in aw080
+ SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
+
+ // updating fObjectRotation
+ Degree100 nTextObjRotation = maGeo.nRotationAngle;
+ double fAngle = toDegrees(nTextObjRotation);
+ if (IsMirroredX())
+ {
+ if (IsMirroredY())
+ fObjectRotation = fAngle - 180.0;
+ else
+ fObjectRotation = -fAngle;
+ }
+ else
+ {
+ if (IsMirroredY())
+ fObjectRotation = 180.0 - fAngle;
+ else
+ fObjectRotation = fAngle;
+ }
+ while (fObjectRotation < 0)
+ fObjectRotation += 360.0;
+ while (fObjectRotation >= 360.0)
+ fObjectRotation -= 360.0;
+
+ InvalidateRenderGeometry();
+}
+
+SdrGluePoint SdrObjCustomShape::GetVertexGluePoint(sal_uInt16 nPosNum) const
+{
+ sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
+
+ // #i25616#
+ if(!LineIsOutsideGeometry())
+ {
+ nWdt++;
+ nWdt /= 2;
+ }
+
+ Point aPt;
+ switch (nPosNum) {
+ case 0: aPt=maRect.TopCenter(); aPt.AdjustY( -nWdt ); break;
+ case 1: aPt=maRect.RightCenter(); aPt.AdjustX(nWdt ); break;
+ case 2: aPt=maRect.BottomCenter(); aPt.AdjustY(nWdt ); break;
+ case 3: aPt=maRect.LeftCenter(); aPt.AdjustX( -nWdt ); break;
+ }
+ if (maGeo.nShearAngle != 0_deg100) ShearPoint(aPt, maRect.TopLeft(), maGeo.mfTanShearAngle);
+ if (maGeo.nRotationAngle != 0_deg100) RotatePoint(aPt, maRect.TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ aPt-=GetSnapRect().Center();
+ SdrGluePoint aGP(aPt);
+ aGP.SetPercent(false);
+ return aGP;
+}
+
+
+// #i38892#
+void SdrObjCustomShape::ImpCheckCustomGluePointsAreAdded()
+{
+ const SdrObject* pSdrObject = GetSdrObjectFromCustomShape();
+
+ if(!pSdrObject)
+ return;
+
+ const SdrGluePointList* pSource = pSdrObject->GetGluePointList();
+
+ if(!(pSource && pSource->GetCount()))
+ return;
+
+ if(!SdrTextObj::GetGluePointList())
+ {
+ SdrTextObj::ForceGluePointList();
+ }
+
+ const SdrGluePointList* pList = SdrTextObj::GetGluePointList();
+
+ if(!pList)
+ return;
+
+ SdrGluePointList aNewList;
+ sal_uInt16 a;
+
+ for(a = 0; a < pSource->GetCount(); a++)
+ {
+ SdrGluePoint aCopy((*pSource)[a]);
+ aCopy.SetUserDefined(false);
+ aNewList.Insert(aCopy);
+ }
+
+ bool bMirroredX = IsMirroredX();
+ bool bMirroredY = IsMirroredY();
+
+ Degree100 nShearAngle = maGeo.nShearAngle;
+ double fTan = maGeo.mfTanShearAngle;
+
+ if (maGeo.nRotationAngle || nShearAngle || bMirroredX || bMirroredY)
+ {
+ tools::Polygon aPoly( maRect );
+ if( nShearAngle )
+ {
+ sal_uInt16 nPointCount=aPoly.GetSize();
+ for (sal_uInt16 i=0; i<nPointCount; i++)
+ ShearPoint(aPoly[i],maRect.Center(), fTan );
+ }
+ if (maGeo.nRotationAngle)
+ aPoly.Rotate( maRect.Center(), to<Degree10>(maGeo.nRotationAngle) );
+
+ tools::Rectangle aBoundRect( aPoly.GetBoundRect() );
+ sal_Int32 nXDiff = aBoundRect.Left() - maRect.Left();
+ sal_Int32 nYDiff = aBoundRect.Top() - maRect.Top();
+
+ if (nShearAngle && bMirroredX != bMirroredY)
+ {
+ nShearAngle = -nShearAngle;
+ fTan = -fTan;
+ }
+
+ Point aRef( maRect.GetWidth() / 2, maRect.GetHeight() / 2 );
+ for ( a = 0; a < aNewList.GetCount(); a++ )
+ {
+ SdrGluePoint& rPoint = aNewList[ a ];
+ Point aGlue( rPoint.GetPos() );
+ if ( nShearAngle )
+ ShearPoint( aGlue, aRef, fTan );
+
+ RotatePoint(aGlue, aRef, sin(basegfx::deg2rad(fObjectRotation)),
+ cos(basegfx::deg2rad(fObjectRotation)));
+ if ( bMirroredX )
+ aGlue.setX( maRect.GetWidth() - aGlue.X() );
+ if ( bMirroredY )
+ aGlue.setY( maRect.GetHeight() - aGlue.Y() );
+ aGlue.AdjustX( -nXDiff );
+ aGlue.AdjustY( -nYDiff );
+ rPoint.SetPos( aGlue );
+ }
+ }
+
+ for(a = 0; a < pList->GetCount(); a++)
+ {
+ const SdrGluePoint& rCandidate = (*pList)[a];
+
+ if(rCandidate.IsUserDefined())
+ {
+ aNewList.Insert(rCandidate);
+ }
+ }
+
+ // copy new list to local. This is NOT very convenient behavior, the local
+ // GluePointList should not be set, but we delivered by using GetGluePointList(),
+ // maybe on demand. Since the local object is changed here, this is assumed to
+ // be a result of GetGluePointList and thus the list is copied
+ if(m_pPlusData)
+ {
+ m_pPlusData->SetGluePoints(aNewList);
+ }
+}
+
+// #i38892#
+const SdrGluePointList* SdrObjCustomShape::GetGluePointList() const
+{
+ const_cast<SdrObjCustomShape*>(this)->ImpCheckCustomGluePointsAreAdded();
+ return SdrTextObj::GetGluePointList();
+}
+
+// #i38892#
+SdrGluePointList* SdrObjCustomShape::ForceGluePointList()
+{
+ if(SdrTextObj::ForceGluePointList())
+ {
+ ImpCheckCustomGluePointsAreAdded();
+ return SdrTextObj::ForceGluePointList();
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+
+sal_uInt32 SdrObjCustomShape::GetHdlCount() const
+{
+ const sal_uInt32 nBasicHdlCount(SdrTextObj::GetHdlCount());
+ return ( GetInteractionHandles().size() + nBasicHdlCount );
+}
+
+void SdrObjCustomShape::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ SdrTextObj::AddToHdlList(rHdlList);
+
+ int nCustomShapeHdlNum = 0;
+ for (SdrCustomShapeInteraction const & rInteraction : GetInteractionHandles())
+ {
+ if ( rInteraction.xInteraction.is() )
+ {
+ try
+ {
+ css::awt::Point aPosition( rInteraction.xInteraction->getPosition() );
+ std::unique_ptr<SdrHdl> pH(new SdrHdl( Point( aPosition.X, aPosition.Y ), SdrHdlKind::CustomShape1 ));
+ pH->SetPointNum( nCustomShapeHdlNum );
+ pH->SetObj( const_cast<SdrObjCustomShape*>(this) );
+ rHdlList.AddHdl(std::move(pH));
+ }
+ catch ( const uno::RuntimeException& )
+ {
+ }
+ }
+ ++nCustomShapeHdlNum;
+ }
+}
+
+bool SdrObjCustomShape::hasSpecialDrag() const
+{
+ return true;
+}
+
+bool SdrObjCustomShape::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ const SdrHdl* pHdl = rDrag.GetHdl();
+
+ if(pHdl && SdrHdlKind::CustomShape1 == pHdl->GetKind())
+ {
+ rDrag.SetEndDragChangesAttributes(true);
+ rDrag.SetNoSnap();
+ }
+ else
+ {
+ const SdrHdl* pHdl2 = rDrag.GetHdl();
+ const SdrHdlKind eHdl((pHdl2 == nullptr) ? SdrHdlKind::Move : pHdl2->GetKind());
+
+ switch( eHdl )
+ {
+ case SdrHdlKind::UpperLeft :
+ case SdrHdlKind::Upper :
+ case SdrHdlKind::UpperRight :
+ case SdrHdlKind::Left :
+ case SdrHdlKind::Right :
+ case SdrHdlKind::LowerLeft :
+ case SdrHdlKind::Lower :
+ case SdrHdlKind::LowerRight :
+ case SdrHdlKind::Move :
+ {
+ break;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void SdrObjCustomShape::DragResizeCustomShape( const tools::Rectangle& rNewRect )
+{
+ tools::Rectangle aOld( maRect );
+ bool bOldMirroredX( IsMirroredX() );
+ bool bOldMirroredY( IsMirroredY() );
+
+ tools::Rectangle aNewRect( rNewRect );
+ aNewRect.Justify();
+
+ std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
+
+ GeoStat aGeoStat( GetGeoStat() );
+ if ( aNewRect.TopLeft()!= maRect.TopLeft() &&
+ ( maGeo.nRotationAngle || maGeo.nShearAngle ) )
+ {
+ Point aNewPos( aNewRect.TopLeft() );
+ if ( maGeo.nShearAngle ) ShearPoint( aNewPos, aOld.TopLeft(), aGeoStat.mfTanShearAngle );
+ if ( maGeo.nRotationAngle ) RotatePoint(aNewPos, aOld.TopLeft(), aGeoStat.mfSinRotationAngle, aGeoStat.mfCosRotationAngle );
+ aNewRect.SetPos( aNewPos );
+ }
+ if ( aNewRect == maRect )
+ return;
+
+ SetLogicRect( aNewRect );
+ InvalidateRenderGeometry();
+
+ if ( rNewRect.Left() > rNewRect.Right() )
+ {
+ Point aTop( ( GetSnapRect().Left() + GetSnapRect().Right() ) >> 1, GetSnapRect().Top() );
+ Point aBottom( aTop.X(), aTop.Y() + 1000 );
+ NbcMirror( aTop, aBottom );
+ }
+ if ( rNewRect.Top() > rNewRect.Bottom() )
+ {
+ Point aLeft( GetSnapRect().Left(), ( GetSnapRect().Top() + GetSnapRect().Bottom() ) >> 1 );
+ Point aRight( aLeft.X() + 1000, aLeft.Y() );
+ NbcMirror( aLeft, aRight );
+ }
+
+ for (const auto& rInteraction : aInteractionHandles)
+ {
+ try
+ {
+ if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_FIXED )
+ rInteraction.xInteraction->setControllerPosition( rInteraction.aPosition );
+ if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_X ||
+ rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX )
+ {
+ if (rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX)
+ bOldMirroredX = !bOldMirroredX;
+
+ sal_Int32 nX;
+ if ( bOldMirroredX )
+ {
+ nX = ( rInteraction.aPosition.X - aOld.Right() );
+ if ( rNewRect.Left() > rNewRect.Right() )
+ nX = maRect.Left() - nX;
+ else
+ nX += maRect.Right();
+ }
+ else
+ {
+ nX = ( rInteraction.aPosition.X - aOld.Left() );
+ if ( rNewRect.Left() > rNewRect.Right() )
+ nX = maRect.Right() - nX;
+ else
+ nX += maRect.Left();
+ }
+ rInteraction.xInteraction->setControllerPosition( css::awt::Point( nX, rInteraction.xInteraction->getPosition().Y ) );
+ }
+ if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_ABSOLUTE_Y )
+ {
+ sal_Int32 nY;
+ if ( bOldMirroredY )
+ {
+ nY = ( rInteraction.aPosition.Y - aOld.Bottom() );
+ if ( rNewRect.Top() > rNewRect.Bottom() )
+ nY = maRect.Top() - nY;
+ else
+ nY += maRect.Bottom();
+ }
+ else
+ {
+ nY = ( rInteraction.aPosition.Y - aOld.Top() );
+ if ( rNewRect.Top() > rNewRect.Bottom() )
+ nY = maRect.Bottom() - nY;
+ else
+ nY += maRect.Top();
+ }
+ rInteraction.xInteraction->setControllerPosition( css::awt::Point( rInteraction.xInteraction->getPosition().X, nY ) );
+ }
+ }
+ catch ( const uno::RuntimeException& )
+ {
+ }
+ }
+}
+
+void SdrObjCustomShape::DragMoveCustomShapeHdl( const Point& rDestination,
+ const sal_uInt16 nCustomShapeHdlNum, bool bMoveCalloutRectangle )
+{
+ std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
+ if ( nCustomShapeHdlNum >= aInteractionHandles.size() )
+ return;
+
+ SdrCustomShapeInteraction aInteractionHandle( aInteractionHandles[ nCustomShapeHdlNum ] );
+ if ( !aInteractionHandle.xInteraction.is() )
+ return;
+
+ try
+ {
+ css::awt::Point aPt( rDestination.X(), rDestination.Y() );
+ if ( aInteractionHandle.nMode & CustomShapeHandleModes::MOVE_SHAPE && bMoveCalloutRectangle )
+ {
+ sal_Int32 nXDiff = aPt.X - aInteractionHandle.aPosition.X;
+ sal_Int32 nYDiff = aPt.Y - aInteractionHandle.aPosition.Y;
+
+ maRect.Move( nXDiff, nYDiff );
+ m_aOutRect.Move( nXDiff, nYDiff );
+ maSnapRect.Move( nXDiff, nYDiff );
+ SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+ InvalidateRenderGeometry();
+
+ for (const auto& rInteraction : aInteractionHandles)
+ {
+ if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_FIXED )
+ {
+ if ( rInteraction.xInteraction.is() )
+ rInteraction.xInteraction->setControllerPosition( rInteraction.aPosition );
+ }
+ }
+ }
+ aInteractionHandle.xInteraction->setControllerPosition( aPt );
+ }
+ catch ( const uno::RuntimeException& )
+ {
+ }
+}
+
+bool SdrObjCustomShape::applySpecialDrag(SdrDragStat& rDrag)
+{
+ const SdrHdl* pHdl = rDrag.GetHdl();
+ const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
+
+ switch(eHdl)
+ {
+ case SdrHdlKind::CustomShape1 :
+ {
+ rDrag.SetEndDragChangesGeoAndAttributes(true);
+ DragMoveCustomShapeHdl( rDrag.GetNow(), static_cast<sal_uInt16>(pHdl->GetPointNum()), !rDrag.GetDragMethod()->IsShiftPressed() );
+ SetBoundAndSnapRectsDirty();
+ InvalidateRenderGeometry();
+ SetChanged();
+ break;
+ }
+
+ case SdrHdlKind::UpperLeft :
+ case SdrHdlKind::Upper :
+ case SdrHdlKind::UpperRight :
+ case SdrHdlKind::Left :
+ case SdrHdlKind::Right :
+ case SdrHdlKind::LowerLeft :
+ case SdrHdlKind::Lower :
+ case SdrHdlKind::LowerRight :
+ {
+ DragResizeCustomShape( ImpDragCalcRect(rDrag) );
+ break;
+ }
+ case SdrHdlKind::Move :
+ {
+ Move(Size(rDrag.GetDX(), rDrag.GetDY()));
+ break;
+ }
+ default: break;
+ }
+
+ return true;
+}
+
+
+void SdrObjCustomShape::DragCreateObject( SdrDragStat& rStat )
+{
+ tools::Rectangle aRect1;
+ rStat.TakeCreateRect( aRect1 );
+
+ std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
+
+ constexpr sal_uInt32 nDefaultObjectSizeWidth = 3000; // default width from SDOptions ?
+ constexpr sal_uInt32 nDefaultObjectSizeHeight= 3000;
+
+ if ( ImpVerticalSwitch( *this ) )
+ {
+ SetMirroredX( aRect1.Left() > aRect1.Right() );
+
+ aRect1 = tools::Rectangle( rStat.GetNow(), Size( nDefaultObjectSizeWidth, nDefaultObjectSizeHeight ) );
+ // subtracting the horizontal difference of the latest handle from shape position
+ if ( !aInteractionHandles.empty() )
+ {
+ sal_Int32 nHandlePos = aInteractionHandles[ aInteractionHandles.size() - 1 ].xInteraction->getPosition().X;
+ aRect1.Move( maRect.Left() - nHandlePos, 0 );
+ }
+ }
+ ImpJustifyRect( aRect1 );
+ rStat.SetActionRect( aRect1 );
+ maRect = aRect1;
+ SetBoundAndSnapRectsDirty();
+
+ for (const auto& rInteraction : aInteractionHandles)
+ {
+ try
+ {
+ if ( rInteraction.nMode & CustomShapeHandleModes::CREATE_FIXED )
+ rInteraction.xInteraction->setControllerPosition( awt::Point( rStat.GetStart().X(), rStat.GetStart().Y() ) );
+ }
+ catch ( const uno::RuntimeException& )
+ {
+ }
+ }
+
+ SetBoundRectDirty();
+ m_bSnapRectDirty=true;
+}
+
+bool SdrObjCustomShape::MovCreate(SdrDragStat& rStat)
+{
+ SdrView* pView = rStat.GetView(); // #i37448#
+ if( pView && pView->IsSolidDragging() )
+ {
+ InvalidateRenderGeometry();
+ }
+ DragCreateObject( rStat );
+ SetBoundAndSnapRectsDirty();
+ return true;
+}
+
+bool SdrObjCustomShape::EndCreate( SdrDragStat& rStat, SdrCreateCmd eCmd )
+{
+ DragCreateObject( rStat );
+
+ AdaptTextMinSize();
+
+ SetBoundAndSnapRectsDirty();
+ return ( eCmd == SdrCreateCmd::ForceEnd || rStat.GetPointCount() >= 2 );
+}
+
+basegfx::B2DPolyPolygon SdrObjCustomShape::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
+{
+ return GetLineGeometry( false );
+}
+
+
+// in context with the SdrObjCustomShape the SdrTextAutoGrowHeightItem == true -> Resize Shape to fit text,
+// the SdrTextAutoGrowWidthItem == true -> Word wrap text in Shape
+bool SdrObjCustomShape::IsAutoGrowHeight() const
+{
+ const SfxItemSet& rSet = GetMergedItemSet();
+ bool bIsAutoGrowHeight = rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
+ if ( bIsAutoGrowHeight && IsVerticalWriting() )
+ bIsAutoGrowHeight = !rSet.Get(SDRATTR_TEXT_WORDWRAP).GetValue();
+ return bIsAutoGrowHeight;
+}
+bool SdrObjCustomShape::IsAutoGrowWidth() const
+{
+ const SfxItemSet& rSet = GetMergedItemSet();
+ bool bIsAutoGrowWidth = rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
+ if ( bIsAutoGrowWidth && !IsVerticalWriting() )
+ bIsAutoGrowWidth = !rSet.Get(SDRATTR_TEXT_WORDWRAP).GetValue();
+ return bIsAutoGrowWidth;
+}
+
+/* The following method is identical to the SdrTextObj::SetVerticalWriting method, the only difference
+ is that the SdrAutoGrowWidthItem and SdrAutoGrowHeightItem are not exchanged if the vertical writing
+ mode has been changed */
+
+void SdrObjCustomShape::SetVerticalWriting( bool bVertical )
+{
+ ForceOutlinerParaObject();
+
+ OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+
+ DBG_ASSERT( pOutlinerParaObject, "SdrTextObj::SetVerticalWriting() without OutlinerParaObject!" );
+
+ if( !pOutlinerParaObject ||
+ (pOutlinerParaObject->IsEffectivelyVertical() == bVertical) )
+ return;
+
+ // get item settings
+ const SfxItemSet& rSet = GetObjectItemSet();
+
+ // Also exchange horizontal and vertical adjust items
+ SdrTextHorzAdjust eHorz = rSet.Get(SDRATTR_TEXT_HORZADJUST).GetValue();
+ SdrTextVertAdjust eVert = rSet.Get(SDRATTR_TEXT_VERTADJUST).GetValue();
+
+ // rescue object size, SetSnapRect below expects logic rect,
+ // not snap rect.
+ tools::Rectangle aObjectRect = GetLogicRect();
+
+ // prepare ItemSet to set exchanged width and height items
+ SfxItemSetFixed<SDRATTR_TEXT_AUTOGROWHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT,
+ // Expanded item ranges to also support horizontal and vertical adjust.
+ SDRATTR_TEXT_VERTADJUST, SDRATTR_TEXT_VERTADJUST,
+ SDRATTR_TEXT_AUTOGROWWIDTH, SDRATTR_TEXT_HORZADJUST> aNewSet(*rSet.GetPool());
+
+ aNewSet.Put(rSet);
+
+ // Exchange horizontal and vertical adjusts
+ switch(eVert)
+ {
+ case SDRTEXTVERTADJUST_TOP: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT)); break;
+ case SDRTEXTVERTADJUST_CENTER: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER)); break;
+ case SDRTEXTVERTADJUST_BOTTOM: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT)); break;
+ case SDRTEXTVERTADJUST_BLOCK: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK)); break;
+ }
+ switch(eHorz)
+ {
+ case SDRTEXTHORZADJUST_LEFT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM)); break;
+ case SDRTEXTHORZADJUST_CENTER: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER)); break;
+ case SDRTEXTHORZADJUST_RIGHT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP)); break;
+ case SDRTEXTHORZADJUST_BLOCK: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BLOCK)); break;
+ }
+
+ pOutlinerParaObject = GetOutlinerParaObject();
+ if ( pOutlinerParaObject )
+ pOutlinerParaObject->SetVertical(bVertical);
+ SetObjectItemSet( aNewSet );
+
+ // restore object size
+ SetSnapRect(aObjectRect);
+}
+
+void SdrObjCustomShape::SuggestTextFrameSize(Size aSuggestedTextFrameSize)
+{
+ m_aSuggestedTextFrameSize = aSuggestedTextFrameSize;
+}
+
+bool SdrObjCustomShape::AdjustTextFrameWidthAndHeight(tools::Rectangle& rR, bool bHgt, bool bWdt) const
+{
+ // Either we have text or the application has native text and suggested its size to us.
+ bool bHasText = HasText() || !m_aSuggestedTextFrameSize.IsEmpty();
+ if ( bHasText && !rR.IsEmpty() )
+ {
+ bool bWdtGrow=bWdt && IsAutoGrowWidth();
+ bool bHgtGrow=bHgt && IsAutoGrowHeight();
+ if ( bWdtGrow || bHgtGrow )
+ {
+ tools::Rectangle aR0(rR);
+ tools::Long nHgt=0,nMinHgt=0,nMaxHgt=0;
+ tools::Long nWdt=0,nMinWdt=0,nMaxWdt=0;
+ Size aSiz(rR.GetSize()); aSiz.AdjustWidth( -1 ); aSiz.AdjustHeight( -1 );
+ Size aMaxSiz(100000,100000);
+ Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
+ if (aTmpSiz.Width()!=0) aMaxSiz.setWidth(aTmpSiz.Width() );
+ if (aTmpSiz.Height()!=0) aMaxSiz.setHeight(aTmpSiz.Height() );
+ if (bWdtGrow)
+ {
+ nMinWdt=GetMinTextFrameWidth();
+ nMaxWdt=GetMaxTextFrameWidth();
+ if (nMaxWdt==0 || nMaxWdt>aMaxSiz.Width()) nMaxWdt=aMaxSiz.Width();
+ if (nMinWdt<=0) nMinWdt=1;
+ aSiz.setWidth(nMaxWdt );
+ }
+ if (bHgtGrow)
+ {
+ nMinHgt=GetMinTextFrameHeight();
+ nMaxHgt=GetMaxTextFrameHeight();
+ if (nMaxHgt==0 || nMaxHgt>aMaxSiz.Height()) nMaxHgt=aMaxSiz.Height();
+ if (nMinHgt<=0) nMinHgt=1;
+ aSiz.setHeight(nMaxHgt );
+ }
+ tools::Long nHDist=GetTextLeftDistance()+GetTextRightDistance();
+ tools::Long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
+ aSiz.AdjustWidth( -nHDist );
+ aSiz.AdjustHeight( -nVDist );
+ if ( aSiz.Width() < 2 )
+ aSiz.setWidth( 2 ); // minimum size=2
+ if ( aSiz.Height() < 2 )
+ aSiz.setHeight( 2 ); // minimum size=2
+
+ if (HasText())
+ {
+ if(mpEditingOutliner)
+ {
+ mpEditingOutliner->SetMaxAutoPaperSize( aSiz );
+ if (bWdtGrow)
+ {
+ Size aSiz2(mpEditingOutliner->CalcTextSize());
+ nWdt=aSiz2.Width()+1; // a little more tolerance
+ if (bHgtGrow) nHgt=aSiz2.Height()+1; // a little more tolerance
+ } else
+ {
+ nHgt=mpEditingOutliner->GetTextHeight()+1; // a little more tolerance
+ }
+ }
+ else
+ {
+ Outliner& rOutliner=ImpGetDrawOutliner();
+ rOutliner.SetPaperSize(aSiz);
+ rOutliner.SetUpdateLayout(true);
+ // TODO: add the optimization with bPortionInfoChecked again.
+ OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+ if( pOutlinerParaObject != nullptr )
+ {
+ rOutliner.SetText(*pOutlinerParaObject);
+ rOutliner.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue());
+ }
+ if ( bWdtGrow )
+ {
+ Size aSiz2(rOutliner.CalcTextSize());
+ nWdt=aSiz2.Width()+1; // a little more tolerance
+ if ( bHgtGrow )
+ nHgt=aSiz2.Height()+1; // a little more tolerance
+ }
+ else
+ {
+ nHgt = rOutliner.GetTextHeight()+1; // a little more tolerance
+
+ sal_Int16 nColumns = GetMergedItem(SDRATTR_TEXTCOLUMNS_NUMBER).GetValue();
+ if (bHgtGrow && nColumns > 1)
+ {
+ // Both 'resize shape to fix text' and multiple columns are enabled. The
+ // first means a dynamic height, the second expects a fixed height.
+ // Resolve this conflict by going with the original height.
+ nHgt = rR.getHeight();
+ }
+ }
+ rOutliner.Clear();
+ }
+ }
+ else
+ {
+ nHgt = m_aSuggestedTextFrameSize.Height();
+ nWdt = m_aSuggestedTextFrameSize.Width();
+ }
+ if ( nWdt < nMinWdt )
+ nWdt = nMinWdt;
+ if ( nWdt > nMaxWdt )
+ nWdt = nMaxWdt;
+ nWdt += nHDist;
+ if ( nWdt < 1 )
+ nWdt = 1; // nHDist may also be negative
+ if ( nHgt < nMinHgt )
+ nHgt = nMinHgt;
+ if ( nHgt > nMaxHgt )
+ nHgt = nMaxHgt;
+ nHgt+=nVDist;
+ if ( nHgt < 1 )
+ nHgt = 1; // nVDist may also be negative
+ tools::Long nWdtGrow = nWdt-(rR.Right()-rR.Left());
+ tools::Long nHgtGrow = nHgt-(rR.Bottom()-rR.Top());
+ if ( nWdtGrow == 0 )
+ bWdtGrow = false;
+ if ( nHgtGrow == 0 )
+ bHgtGrow=false;
+ if ( bWdtGrow || bHgtGrow || !m_aSuggestedTextFrameSize.IsEmpty())
+ {
+ if ( bWdtGrow || m_aSuggestedTextFrameSize.Width() )
+ {
+ SdrTextHorzAdjust eHAdj=GetTextHorizontalAdjust();
+ if (m_aSuggestedTextFrameSize.Width())
+ {
+ rR.SetRight(rR.Left() + m_aSuggestedTextFrameSize.Width());
+ }
+ else if ( eHAdj == SDRTEXTHORZADJUST_LEFT )
+ rR.AdjustRight(nWdtGrow );
+ else if ( eHAdj == SDRTEXTHORZADJUST_RIGHT )
+ rR.AdjustLeft( -nWdtGrow );
+ else
+ {
+ tools::Long nWdtGrow2=nWdtGrow/2;
+ rR.AdjustLeft( -nWdtGrow2 );
+ rR.SetRight(rR.Left()+nWdt );
+ }
+ }
+ if ( bHgtGrow || m_aSuggestedTextFrameSize.Height() )
+ {
+ SdrTextVertAdjust eVAdj=GetTextVerticalAdjust();
+ if (m_aSuggestedTextFrameSize.Height())
+ {
+ rR.SetBottom(rR.Top() + m_aSuggestedTextFrameSize.Height());
+ }
+ else if ( eVAdj == SDRTEXTVERTADJUST_TOP )
+ rR.AdjustBottom(nHgtGrow );
+ else if ( eVAdj == SDRTEXTVERTADJUST_BOTTOM )
+ rR.AdjustTop( -nHgtGrow );
+ else
+ {
+ tools::Long nHgtGrow2=nHgtGrow/2;
+ rR.AdjustTop( -nHgtGrow2 );
+ rR.SetBottom(rR.Top()+nHgt );
+ }
+ }
+ if ( maGeo.nRotationAngle )
+ {
+ Point aD1(rR.TopLeft());
+ aD1-=aR0.TopLeft();
+ Point aD2(aD1);
+ RotatePoint(aD2,Point(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ aD2-=aD1;
+ rR.Move(aD2.X(),aD2.Y());
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+tools::Rectangle SdrObjCustomShape::ImpCalculateTextFrame( const bool bHgt, const bool bWdt )
+{
+ tools::Rectangle aReturnValue;
+
+ tools::Rectangle aOldTextRect( maRect ); // <- initial text rectangle
+
+ tools::Rectangle aNewTextRect( maRect ); // <- new text rectangle returned from the custom shape renderer,
+ GetTextBounds( aNewTextRect ); // it depends to the current logical shape size
+
+ tools::Rectangle aAdjustedTextRect( aNewTextRect ); // <- new text rectangle is being tested by AdjustTextFrameWidthAndHeight to ensure
+ if ( AdjustTextFrameWidthAndHeight( aAdjustedTextRect, bHgt, bWdt ) ) // that the new text rectangle is matching the current text size from the outliner
+ {
+ if (aAdjustedTextRect != aNewTextRect && aOldTextRect != aAdjustedTextRect &&
+ aNewTextRect.GetWidth() && aNewTextRect.GetHeight())
+ {
+ aReturnValue = maRect;
+ double fXScale = static_cast<double>(aOldTextRect.GetWidth()) / static_cast<double>(aNewTextRect.GetWidth());
+ double fYScale = static_cast<double>(aOldTextRect.GetHeight()) / static_cast<double>(aNewTextRect.GetHeight());
+ double fRightDiff = static_cast<double>( aAdjustedTextRect.Right() - aNewTextRect.Right() ) * fXScale;
+ double fLeftDiff = static_cast<double>( aAdjustedTextRect.Left() - aNewTextRect.Left() ) * fXScale;
+ double fTopDiff = static_cast<double>( aAdjustedTextRect.Top() - aNewTextRect.Top() ) * fYScale;
+ double fBottomDiff= static_cast<double>( aAdjustedTextRect.Bottom()- aNewTextRect.Bottom()) * fYScale;
+ aReturnValue.AdjustLeft(static_cast<sal_Int32>(fLeftDiff) );
+ aReturnValue.AdjustRight(static_cast<sal_Int32>(fRightDiff) );
+ aReturnValue.AdjustTop(static_cast<sal_Int32>(fTopDiff) );
+ aReturnValue.AdjustBottom(static_cast<sal_Int32>(fBottomDiff) );
+ }
+ }
+ return aReturnValue;
+}
+
+bool SdrObjCustomShape::NbcAdjustTextFrameWidthAndHeight(bool bHgt, bool bWdt)
+{
+ tools::Rectangle aNewTextRect = ImpCalculateTextFrame(bHgt, bWdt);
+ const bool bRet = !aNewTextRect.IsEmpty() && aNewTextRect != maRect;
+ if (bRet && !mbAdjustingTextFrameWidthAndHeight)
+ {
+ mbAdjustingTextFrameWidthAndHeight = true;
+
+ // taking care of handles that should not been changed
+ std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
+
+ maRect = aNewTextRect;
+ SetBoundAndSnapRectsDirty();
+ SetChanged();
+
+ for (const auto& rInteraction : aInteractionHandles)
+ {
+ try
+ {
+ if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_FIXED )
+ rInteraction.xInteraction->setControllerPosition( rInteraction.aPosition );
+ }
+ catch ( const uno::RuntimeException& )
+ {
+ }
+ }
+ InvalidateRenderGeometry();
+
+ mbAdjustingTextFrameWidthAndHeight = false;
+ }
+ return bRet;
+}
+
+bool SdrObjCustomShape::AdjustTextFrameWidthAndHeight()
+{
+ tools::Rectangle aNewTextRect = ImpCalculateTextFrame( true/*bHgt*/, true/*bWdt*/ );
+ bool bRet = !aNewTextRect.IsEmpty() && ( aNewTextRect != maRect );
+ if ( bRet )
+ {
+ tools::Rectangle aBoundRect0;
+ if ( m_pUserCall )
+ aBoundRect0 = GetCurrentBoundRect();
+
+ // taking care of handles that should not been changed
+ std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles() );
+
+ maRect = aNewTextRect;
+ SetBoundAndSnapRectsDirty();
+
+ for (const auto& rInteraction : aInteractionHandles)
+ {
+ try
+ {
+ if ( rInteraction.nMode & CustomShapeHandleModes::RESIZE_FIXED )
+ rInteraction.xInteraction->setControllerPosition( rInteraction.aPosition );
+ }
+ catch ( const uno::RuntimeException& )
+ {
+ }
+ }
+
+ InvalidateRenderGeometry();
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+ return bRet;
+}
+void SdrObjCustomShape::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
+{
+ tools::Rectangle aViewInit;
+ TakeTextAnchorRect( aViewInit );
+ if (maGeo.nRotationAngle)
+ {
+ Point aCenter(aViewInit.Center());
+ aCenter-=aViewInit.TopLeft();
+ Point aCenter0(aCenter);
+ RotatePoint(aCenter, Point(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ aCenter-=aCenter0;
+ aViewInit.Move(aCenter.X(),aCenter.Y());
+ }
+ Size aAnkSiz(aViewInit.GetSize());
+ aAnkSiz.AdjustWidth( -1 ); aAnkSiz.AdjustHeight( -1 ); // because GetSize() adds 1
+ Size aMaxSiz(1000000,1000000);
+ {
+ Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
+ if (aTmpSiz.Width()!=0) aMaxSiz.setWidth(aTmpSiz.Width() );
+ if (aTmpSiz.Height()!=0) aMaxSiz.setHeight(aTmpSiz.Height() );
+ }
+ SdrTextHorzAdjust eHAdj(GetTextHorizontalAdjust());
+ SdrTextVertAdjust eVAdj(GetTextVerticalAdjust());
+
+ tools::Long nMinWdt = GetMinTextFrameWidth();
+ tools::Long nMinHgt = GetMinTextFrameHeight();
+ tools::Long nMaxWdt = GetMaxTextFrameWidth();
+ tools::Long nMaxHgt = GetMaxTextFrameHeight();
+ if (nMinWdt<1) nMinWdt=1;
+ if (nMinHgt<1) nMinHgt=1;
+ if ( nMaxWdt == 0 || nMaxWdt > aMaxSiz.Width() )
+ nMaxWdt = aMaxSiz.Width();
+ if ( nMaxHgt == 0 || nMaxHgt > aMaxSiz.Height() )
+ nMaxHgt=aMaxSiz.Height();
+
+ if (GetMergedItem(SDRATTR_TEXT_WORDWRAP).GetValue())
+ {
+ if ( IsVerticalWriting() )
+ {
+ nMaxHgt = aAnkSiz.Height();
+ nMinHgt = nMaxHgt;
+ }
+ else
+ {
+ nMaxWdt = aAnkSiz.Width();
+ nMinWdt = nMaxWdt;
+ }
+ }
+ Size aPaperMax(nMaxWdt, nMaxHgt);
+ Size aPaperMin(nMinWdt, nMinHgt);
+
+ if ( pViewMin )
+ {
+ *pViewMin = aViewInit;
+
+ tools::Long nXFree = aAnkSiz.Width() - aPaperMin.Width();
+ if ( eHAdj == SDRTEXTHORZADJUST_LEFT )
+ pViewMin->AdjustRight( -nXFree );
+ else if ( eHAdj == SDRTEXTHORZADJUST_RIGHT )
+ pViewMin->AdjustLeft(nXFree );
+ else { pViewMin->AdjustLeft(nXFree / 2 ); pViewMin->SetRight( pViewMin->Left() + aPaperMin.Width() ); }
+
+ tools::Long nYFree = aAnkSiz.Height() - aPaperMin.Height();
+ if ( eVAdj == SDRTEXTVERTADJUST_TOP )
+ pViewMin->AdjustBottom( -nYFree );
+ else if ( eVAdj == SDRTEXTVERTADJUST_BOTTOM )
+ pViewMin->AdjustTop(nYFree );
+ else { pViewMin->AdjustTop(nYFree / 2 ); pViewMin->SetBottom( pViewMin->Top() + aPaperMin.Height() ); }
+ }
+
+ if( IsVerticalWriting() )
+ aPaperMin.setWidth( 0 );
+ else
+ aPaperMin.setHeight( 0 );
+
+ if( eHAdj != SDRTEXTHORZADJUST_BLOCK )
+ aPaperMin.setWidth(0 );
+
+ // For complete vertical adjust support, set paper min height to 0, here.
+ if(SDRTEXTVERTADJUST_BLOCK != eVAdj )
+ aPaperMin.setHeight( 0 );
+
+ if (pPaperMin!=nullptr) *pPaperMin=aPaperMin;
+ if (pPaperMax!=nullptr) *pPaperMax=aPaperMax;
+ if (pViewInit!=nullptr) *pViewInit=aViewInit;
+}
+void SdrObjCustomShape::EndTextEdit( SdrOutliner& rOutl )
+{
+ SdrTextObj::EndTextEdit( rOutl );
+ InvalidateRenderGeometry();
+}
+void SdrObjCustomShape::TakeTextAnchorRect( tools::Rectangle& rAnchorRect ) const
+{
+ if ( GetTextBounds( rAnchorRect ) )
+ {
+ Point aRotateRef( maSnapRect.Center() );
+ AdjustRectToTextDistance(rAnchorRect);
+
+ if ( rAnchorRect.GetWidth() < 2 )
+ rAnchorRect.SetRight( rAnchorRect.Left() + 1 ); // minimal width is 2
+ if ( rAnchorRect.GetHeight() < 2 )
+ rAnchorRect.SetBottom( rAnchorRect.Top() + 1 ); // minimal height is 2
+ if (maGeo.nRotationAngle)
+ {
+ Point aP( rAnchorRect.TopLeft() );
+ RotatePoint(aP, aRotateRef, maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ rAnchorRect.SetPos( aP );
+ }
+ }
+ else
+ SdrTextObj::TakeTextAnchorRect( rAnchorRect );
+}
+void SdrObjCustomShape::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText,
+ tools::Rectangle* pAnchorRect, bool /*bLineWidth*/) const
+{
+ tools::Rectangle aAnkRect; // Rect in which we anchor
+ TakeTextAnchorRect(aAnkRect);
+ SdrTextVertAdjust eVAdj=GetTextVerticalAdjust();
+ SdrTextHorzAdjust eHAdj=GetTextHorizontalAdjust();
+ EEControlBits nStat0=rOutliner.GetControlWord();
+ Size aNullSize;
+
+ rOutliner.SetControlWord(nStat0|EEControlBits::AUTOPAGESIZE);
+ rOutliner.SetMinAutoPaperSize(aNullSize);
+ sal_Int32 nMaxAutoPaperWidth = 1000000;
+ sal_Int32 nMaxAutoPaperHeight= 1000000;
+
+ tools::Long nAnkWdt=aAnkRect.GetWidth();
+ tools::Long nAnkHgt=aAnkRect.GetHeight();
+
+ if (GetMergedItem(SDRATTR_TEXT_WORDWRAP).GetValue())
+ {
+ if ( IsVerticalWriting() )
+ nMaxAutoPaperHeight = nAnkHgt;
+ else
+ nMaxAutoPaperWidth = nAnkWdt;
+ }
+ if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
+ {
+ rOutliner.SetMinAutoPaperSize(Size(nAnkWdt, 0));
+ }
+
+ if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
+ {
+ rOutliner.SetMinAutoPaperSize(Size(0, nAnkHgt));
+ }
+ rOutliner.SetMaxAutoPaperSize( Size( nMaxAutoPaperWidth, nMaxAutoPaperHeight ) );
+ rOutliner.SetPaperSize( aNullSize );
+
+ // put text into the Outliner - if necessary the use the text from the EditOutliner
+ std::optional<OutlinerParaObject> pPara;
+ if (GetOutlinerParaObject())
+ pPara = *GetOutlinerParaObject();
+ if (mpEditingOutliner && !bNoEditText)
+ pPara=mpEditingOutliner->CreateParaObject();
+
+ if (pPara)
+ {
+ bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner);
+ const SdrTextObj* pTestObj = rOutliner.GetTextObj();
+
+ if( !pTestObj || !bHitTest || pTestObj != this ||
+ pTestObj->GetOutlinerParaObject() != GetOutlinerParaObject() )
+ {
+ if( bHitTest )
+ rOutliner.SetTextObj( this );
+
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetText(*pPara);
+ }
+ }
+ else
+ {
+ rOutliner.SetTextObj( nullptr );
+ }
+
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetControlWord(nStat0);
+
+ SdrText* pText = getActiveText();
+ if( pText )
+ pText->CheckPortionInfo( rOutliner );
+
+ Point aTextPos(aAnkRect.TopLeft());
+ Size aTextSiz(rOutliner.GetPaperSize()); // GetPaperSize() has a little added tolerance, no?
+
+ // For draw objects containing text correct horizontal/vertical alignment if text is bigger
+ // than the object itself. Without that correction, the text would always be
+ // formatted to the left edge (or top edge when vertical) of the draw object.
+
+ if( !IsTextFrame() )
+ {
+ if(aAnkRect.GetWidth() < aTextSiz.Width() && !IsVerticalWriting())
+ {
+ // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
+ // else the alignment is wanted.
+ if(SDRTEXTHORZADJUST_BLOCK == eHAdj)
+ {
+ SvxAdjust eAdjust = GetObjectItemSet().Get(EE_PARA_JUST).GetAdjust();
+ switch (eAdjust)
+ {
+ case SvxAdjust::Left: eHAdj = SDRTEXTHORZADJUST_LEFT; break;
+ case SvxAdjust::Right: eHAdj = SDRTEXTHORZADJUST_RIGHT; break;
+ case SvxAdjust::Center: eHAdj = SDRTEXTHORZADJUST_CENTER; break;
+ default: break;
+ }
+ }
+ }
+
+ if(aAnkRect.GetHeight() < aTextSiz.Height() && IsVerticalWriting())
+ {
+ // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
+ // else the alignment is wanted.
+ if(SDRTEXTVERTADJUST_BLOCK == eVAdj)
+ {
+ eVAdj = SDRTEXTVERTADJUST_CENTER;
+ }
+ }
+ }
+
+ if (eHAdj==SDRTEXTHORZADJUST_CENTER || eHAdj==SDRTEXTHORZADJUST_RIGHT)
+ {
+ tools::Long nFreeWdt=aAnkRect.GetWidth()-aTextSiz.Width();
+ if (eHAdj==SDRTEXTHORZADJUST_CENTER)
+ aTextPos.AdjustX(nFreeWdt/2 );
+ if (eHAdj==SDRTEXTHORZADJUST_RIGHT)
+ aTextPos.AdjustX(nFreeWdt );
+ }
+ if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
+ {
+ tools::Long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
+ if (eVAdj==SDRTEXTVERTADJUST_CENTER)
+ aTextPos.AdjustY(nFreeHgt/2 );
+ if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
+ aTextPos.AdjustY(nFreeHgt );
+ }
+ if (maGeo.nRotationAngle != 0_deg100)
+ RotatePoint(aTextPos,aAnkRect.TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+
+ if (pAnchorRect)
+ *pAnchorRect=aAnkRect;
+
+ // using rTextRect together with ContourFrame doesn't always work correctly
+ rTextRect=tools::Rectangle(aTextPos,aTextSiz);
+}
+
+void SdrObjCustomShape::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject)
+{
+ SdrTextObj::NbcSetOutlinerParaObject( std::move(pTextObject) );
+ SetBoundRectDirty();
+ SetBoundAndSnapRectsDirty(true);
+ InvalidateRenderGeometry();
+}
+
+SdrObjCustomShape* SdrObjCustomShape::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrObjCustomShape(rTargetModel, *this);
+}
+
+OUString SdrObjCustomShape::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulCUSTOMSHAPE));
+ OUString aNm(GetName());
+ if (!aNm.isEmpty())
+ sName += " '" + aNm + "'";
+ return sName;
+}
+
+OUString SdrObjCustomShape::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralCUSTOMSHAPE);
+}
+
+basegfx::B2DPolyPolygon SdrObjCustomShape::TakeXorPoly() const
+{
+ return GetLineGeometry( false );
+}
+
+basegfx::B2DPolyPolygon SdrObjCustomShape::TakeContour() const
+{
+ const SdrObject* pSdrObject = GetSdrObjectFromCustomShape();
+ if ( pSdrObject )
+ return pSdrObject->TakeContour();
+ return basegfx::B2DPolyPolygon();
+}
+
+SdrObjectUniquePtr SdrObjCustomShape::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ // #i37011#
+ SdrObjectUniquePtr pRetval;
+ SdrObject* pRenderedCustomShape = nullptr;
+
+ if ( !mXRenderedCustomShape.is() )
+ {
+ // force CustomShape
+ GetSdrObjectFromCustomShape();
+ }
+
+ if ( mXRenderedCustomShape.is() )
+ {
+ pRenderedCustomShape = SdrObject::getSdrObjectFromXShape(mXRenderedCustomShape);
+ }
+
+ if ( pRenderedCustomShape )
+ {
+ // Clone to same SdrModel
+ SdrObject* pCandidate(pRenderedCustomShape->CloneSdrObject(pRenderedCustomShape->getSdrModelFromSdrObject()));
+ DBG_ASSERT(pCandidate, "SdrObjCustomShape::DoConvertToPolyObj: Could not clone SdrObject (!)");
+ pRetval = pCandidate->DoConvertToPolyObj(bBezier, bAddText);
+ SdrObject::Free( pCandidate );
+
+ if(pRetval)
+ {
+ const bool bShadow(GetMergedItem(SDRATTR_SHADOW).GetValue());
+ if(bShadow)
+ {
+ pRetval->SetMergedItem(makeSdrShadowItem(true));
+ }
+ }
+
+ if(bAddText && HasText() && !IsTextPath())
+ {
+ pRetval = ImpConvertAddText(std::move(pRetval), bBezier);
+ }
+ }
+
+ return pRetval;
+}
+
+void SdrObjCustomShape::InternalSetStyleSheet( SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr, bool bBroadcast )
+{
+ // #i40944#
+ InvalidateRenderGeometry();
+ SdrObject::InternalSetStyleSheet( pNewStyleSheet, bDontRemoveHardAttr, bBroadcast );
+}
+
+void SdrObjCustomShape::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ // call parent
+ SdrTextObj::handlePageChange(pOldPage, pNewPage);
+
+ if(nullptr != pNewPage)
+ {
+ // invalidating rectangles by SetRectsDirty is not sufficient,
+ // AdjustTextFrameWidthAndHeight() also has to be made, both
+ // actions are done by NbcSetSnapRect
+ tools::Rectangle aTmp( maRect ); //creating temporary rectangle #i61108#
+ NbcSetSnapRect( aTmp );
+ }
+}
+
+std::unique_ptr<SdrObjGeoData> SdrObjCustomShape::NewGeoData() const
+{
+ return std::make_unique<SdrAShapeObjGeoData>();
+}
+
+void SdrObjCustomShape::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrTextObj::SaveGeoData( rGeo );
+ SdrAShapeObjGeoData& rAGeo=static_cast<SdrAShapeObjGeoData&>(rGeo);
+ rAGeo.fObjectRotation = fObjectRotation;
+ rAGeo.bMirroredX = IsMirroredX();
+ rAGeo.bMirroredY = IsMirroredY();
+
+ const Any* pAny = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ).GetPropertyValueByName( "AdjustmentValues" );
+ if ( pAny )
+ *pAny >>= rAGeo.aAdjustmentSeq;
+}
+
+void SdrObjCustomShape::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrTextObj::RestoreGeoData( rGeo );
+ const SdrAShapeObjGeoData& rAGeo=static_cast<const SdrAShapeObjGeoData&>(rGeo);
+ fObjectRotation = rAGeo.fObjectRotation;
+ SetMirroredX( rAGeo.bMirroredX );
+ SetMirroredY( rAGeo.bMirroredY );
+
+ SdrCustomShapeGeometryItem rGeometryItem = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+ PropertyValue aPropVal;
+ aPropVal.Name = "AdjustmentValues";
+ aPropVal.Value <<= rAGeo.aAdjustmentSeq;
+ rGeometryItem.SetPropertyValue( aPropVal );
+ SetMergedItem( rGeometryItem );
+
+ InvalidateRenderGeometry();
+}
+
+void SdrObjCustomShape::AdjustToMaxRect(const tools::Rectangle& rMaxRect, bool bShrinkOnly /* = false */)
+{
+ SAL_INFO_IF(bShrinkOnly, "svx", "Case bShrinkOnly == true is not implemented yet.");
+
+ if (rMaxRect.IsEmpty() || rMaxRect == GetSnapRect())
+ return;
+
+ // Get a matrix, that would produce the existing shape, when applied to a unit square
+ basegfx::B2DPolyPolygon aPolyPolygon; //not used, but formal needed
+ basegfx::B2DHomMatrix aMatrix;
+ TRGetBaseGeometry(aMatrix, aPolyPolygon);
+ // Using TRSetBaseGeometry(aMatrix, aPolyPolygon) would regenerate the current shape. But
+ // applying aMatrix to a unit square will not generate the current shape. Scaling,
+ // rotation and translation are correct, but shear angle has wrong sign. So break up
+ // matrix and create a mathematically correct new one.
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate, fShearX;
+ aMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+ basegfx::B2DHomMatrix aMathMatrix;
+ aMathMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale,
+ basegfx::fTools::equalZero(fShearX) ? 0.0 : -fShearX,
+ basegfx::fTools::equalZero(fRotate) ? 0.0 : fRotate,
+ aTranslate);
+
+ // Calculate scaling factors from size of the transformed unit polygon as ersatz for the not
+ // usable current snap rectangle.
+ basegfx::B2DPolygon aB2DPolygon(basegfx::utils::createUnitPolygon());
+ aB2DPolygon.transform(aMathMatrix);
+ basegfx::B2DRange aB2DRange(aB2DPolygon.getB2DRange());
+ double fPolygonWidth = aB2DRange.getWidth();
+ if (fPolygonWidth == 0)
+ fPolygonWidth = 1;
+ double fPolygonHeight = aB2DRange.getHeight();
+ if (fPolygonHeight == 0)
+ fPolygonHeight = 1;
+ const double aFactorX = static_cast<double>(rMaxRect.GetWidth()) / fPolygonWidth;
+ const double aFactorY = static_cast<double>(rMaxRect.GetHeight()) / fPolygonHeight;
+
+ // Generate matrix, that would produce the desired rMaxRect when applied to unit square
+ aMathMatrix.scale(aFactorX, aFactorY);
+ aB2DPolygon = basegfx::utils::createUnitPolygon();
+ aB2DPolygon.transform(aMathMatrix);
+ aB2DRange = aB2DPolygon.getB2DRange();
+ const double fPolygonLeft = aB2DRange.getMinX();
+ const double fPolygonTop = aB2DRange.getMinY();
+ aMathMatrix.translate(rMaxRect.Left() - fPolygonLeft, rMaxRect.Top() - fPolygonTop);
+
+ // Create a Matrix from aMathMatrix, which is usable with TRSetBaseGeometry
+ aMathMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+ aMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale,
+ basegfx::fTools::equalZero(fShearX) ? 0.0 : -fShearX,
+ basegfx::fTools::equalZero(fRotate) ? 0.0 : fRotate,
+ aTranslate);
+
+ // Now use TRSetBaseGeometry to actually perform scale, shear, rotate and translate
+ // on the shape. That considers gluepoints, interaction handles and text area, and includes
+ // setting rectangles dirty and broadcast.
+ TRSetBaseGeometry(aMatrix, aPolyPolygon);
+}
+
+void SdrObjCustomShape::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
+{
+ // The shape might have already flipping in its enhanced geometry. LibreOffice applies
+ // such after all transformations. We remove it, but remember it to apply them later.
+ bool bIsMirroredX = IsMirroredX();
+ bool bIsMirroredY = IsMirroredY();
+ if (bIsMirroredX || bIsMirroredY)
+ {
+ Point aCurrentCenter = GetSnapRect().Center();
+ if (bIsMirroredX) // mirror on the y-axis
+ {
+ Mirror(aCurrentCenter, Point(aCurrentCenter.X(), aCurrentCenter.Y() + 1000));
+ }
+ if (bIsMirroredY) // mirror on the x-axis
+ {
+ Mirror(aCurrentCenter, Point(aCurrentCenter.X() + 1000, aCurrentCenter.Y()));
+ }
+ }
+
+ // break up matrix
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate, fShearX;
+ rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // reset object shear and rotations
+ fObjectRotation = 0.0;
+ maGeo.nRotationAngle = 0_deg100;
+ maGeo.RecalcSinCos();
+ maGeo.nShearAngle = 0_deg100;
+ maGeo.RecalcTan();
+
+ // if anchor is used, make position relative to it
+ if(getSdrModelFromSdrObject().IsWriter())
+ {
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // scale
+ Size aSize(FRound(fabs(aScale.getX())), FRound(fabs(aScale.getY())));
+ // fdo#47434 We need a valid rectangle here
+ if( !aSize.Height() ) aSize.setHeight( 1 );
+ if( !aSize.Width() ) aSize.setWidth( 1 );
+ tools::Rectangle aBaseRect(Point(), aSize);
+ SetLogicRect(aBaseRect);
+
+ // Apply flipping from Matrix, which is a transformation relative to origin
+ if (basegfx::fTools::less(aScale.getX(), 0.0))
+ Mirror(Point(0, 0), Point(0, 1000)); // mirror on the y-axis
+ if (basegfx::fTools::less(aScale.getY(), 0.0))
+ Mirror(Point(0, 0), Point(1000, 0)); // mirror on the x-axis
+
+ // shear?
+ if(!basegfx::fTools::equalZero(fShearX))
+ {
+ GeoStat aGeoStat;
+ // #i123181# The fix for #121932# here was wrong, the trunk version does not correct the
+ // mirrored shear values, neither at the object level, nor on the API or XML level. Taking
+ // back the mirroring of the shear angle
+ aGeoStat.nShearAngle = Degree100(FRound(basegfx::rad2deg<100>(atan(fShearX))));
+ aGeoStat.RecalcTan();
+ Shear(Point(), aGeoStat.nShearAngle, aGeoStat.mfTanShearAngle, false);
+ }
+
+ // rotation?
+ if(!basegfx::fTools::equalZero(fRotate))
+ {
+ GeoStat aGeoStat;
+
+ // #i78696#
+ // fRotate is mathematically correct, but aGeoStat.nRotationAngle is
+ // mirrored -> mirror value here
+ aGeoStat.nRotationAngle = NormAngle36000(Degree100(FRound(-basegfx::rad2deg<100>(fRotate))));
+ aGeoStat.RecalcSinCos();
+ Rotate(Point(), aGeoStat.nRotationAngle, aGeoStat.mfSinRotationAngle, aGeoStat.mfCosRotationAngle);
+ }
+
+ // translate?
+ if(!aTranslate.equalZero())
+ {
+ Move(Size(FRound(aTranslate.getX()), FRound(aTranslate.getY())));
+ }
+
+ // Apply flipping from enhanced geometry at center of the shape.
+ if (!(bIsMirroredX || bIsMirroredY))
+ return;
+
+ // create mathematically matrix for the applied transformations
+ // aScale was in most cases built from a rectangle including edge
+ // and is therefore mathematically too large by 1
+ if (aScale.getX() > 2.0 && aScale.getY() > 2.0)
+ aScale -= basegfx::B2DTuple(1.0, 1.0);
+ basegfx::B2DHomMatrix aMathMat = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale, -fShearX, basegfx::fTools::equalZero(fRotate) ? 0.0 : fRotate,
+ aTranslate);
+ // Use matrix to get current center
+ basegfx::B2DPoint aCenter(0.5,0.5);
+ aCenter = aMathMat * aCenter;
+ double fCenterX = aCenter.getX();
+ double fCenterY = aCenter.getY();
+ if (bIsMirroredX) // vertical axis
+ Mirror(Point(FRound(fCenterX),FRound(fCenterY)),
+ Point(FRound(fCenterX), FRound(fCenterY + 1000.0)));
+ if (bIsMirroredY) // horizontal axis
+ Mirror(Point(FRound(fCenterX),FRound(fCenterY)),
+ Point(FRound(fCenterX + 1000.0), FRound(fCenterY)));
+}
+
+// taking fObjectRotation instead of aGeo.nAngle
+bool SdrObjCustomShape::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
+{
+ // get turn and shear
+ double fRotate = basegfx::deg2rad(fObjectRotation);
+ double fShearX = toRadians(maGeo.nShearAngle);
+
+ // get aRect, this is the unrotated snaprect
+ tools::Rectangle aRectangle(maRect);
+
+ bool bMirroredX = IsMirroredX();
+ bool bMirroredY = IsMirroredY();
+ if ( bMirroredX || bMirroredY )
+ { // we have to retrieve the unmirrored rect
+
+ GeoStat aNewGeo(maGeo);
+
+ if ( bMirroredX )
+ {
+ fShearX = -fShearX;
+ tools::Polygon aPol = Rect2Poly(maRect, aNewGeo);
+ tools::Rectangle aBoundRect( aPol.GetBoundRect() );
+
+ Point aRef1( ( aBoundRect.Left() + aBoundRect.Right() ) >> 1, aBoundRect.Top() );
+ Point aRef2( aRef1.X(), aRef1.Y() + 1000 );
+ sal_uInt16 i;
+ sal_uInt16 nPointCount=aPol.GetSize();
+ for (i=0; i<nPointCount; i++)
+ {
+ MirrorPoint(aPol[i],aRef1,aRef2);
+ }
+ // mirror polygon and move it a bit
+ tools::Polygon aPol0(aPol);
+ aPol[0]=aPol0[1];
+ aPol[1]=aPol0[0];
+ aPol[2]=aPol0[3];
+ aPol[3]=aPol0[2];
+ aPol[4]=aPol0[1];
+ Poly2Rect(aPol,aRectangle,aNewGeo);
+ }
+ if ( bMirroredY )
+ {
+ fShearX = -fShearX;
+ tools::Polygon aPol( Rect2Poly( aRectangle, aNewGeo ) );
+ tools::Rectangle aBoundRect( aPol.GetBoundRect() );
+
+ Point aRef1( aBoundRect.Left(), ( aBoundRect.Top() + aBoundRect.Bottom() ) >> 1 );
+ Point aRef2( aRef1.X() + 1000, aRef1.Y() );
+ sal_uInt16 i;
+ sal_uInt16 nPointCount=aPol.GetSize();
+ for (i=0; i<nPointCount; i++)
+ {
+ MirrorPoint(aPol[i],aRef1,aRef2);
+ }
+ // mirror polygon and move it a bit
+ tools::Polygon aPol0(aPol);
+ aPol[0]=aPol0[1]; // This was WRONG for vertical (!)
+ aPol[1]=aPol0[0]; // #i121932# Despite my own comment above
+ aPol[2]=aPol0[3]; // it was *not* wrong even when the reordering
+ aPol[3]=aPol0[2]; // *seems* to be specific for X-Mirrorings. Oh
+ aPol[4]=aPol0[1]; // will I be happy when this old stuff is |gone| with aw080 (!)
+ Poly2Rect(aPol,aRectangle,aNewGeo);
+ }
+ }
+
+ // fill other values
+ basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight());
+ basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top());
+
+ // position may be relative to anchorpos, convert
+ if(getSdrModelFromSdrObject().IsWriter())
+ {
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // build matrix
+ rMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale,
+ basegfx::fTools::equalZero(fShearX) ? 0.0 : tan(fShearX),
+ basegfx::fTools::equalZero(fRotate) ? 0.0 : -fRotate,
+ aTranslate);
+
+ return false;
+}
+
+std::unique_ptr<sdr::contact::ViewContact> SdrObjCustomShape::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrObjCustomShape>(*this);
+}
+
+// #i33136#
+bool SdrObjCustomShape::doConstructOrthogonal(std::u16string_view rName)
+{
+ bool bRetval(false);
+
+ if(o3tl::equalsIgnoreAsciiCase(rName, u"quadrat"))
+ {
+ bRetval = true;
+ }
+ else if(o3tl::equalsIgnoreAsciiCase(rName, u"round-quadrat"))
+ {
+ bRetval = true;
+ }
+ else if(o3tl::equalsIgnoreAsciiCase(rName, u"circle"))
+ {
+ bRetval = true;
+ }
+ else if(o3tl::equalsIgnoreAsciiCase(rName, u"circle-pie"))
+ {
+ bRetval = true;
+ }
+ else if(o3tl::equalsIgnoreAsciiCase(rName, u"ring"))
+ {
+ bRetval = true;
+ }
+
+ return bRetval;
+}
+
+// #i37011# centralize throw-away of render geometry
+void SdrObjCustomShape::InvalidateRenderGeometry()
+{
+ mXRenderedCustomShape = nullptr;
+ SdrObject::Free( mpLastShadowGeometry );
+ mpLastShadowGeometry = nullptr;
+}
+
+void SdrObjCustomShape::setUnoShape(const uno::Reference<drawing::XShape>& rxUnoShape)
+{
+ SdrTextObj::setUnoShape(rxUnoShape);
+
+ // The shape engine is created with _current_ shape. This means we
+ // _must_ reset it when the shape changes.
+ mxCustomShapeEngine.set(nullptr);
+}
+
+OUString SdrObjCustomShape::GetCustomShapeName() const
+{
+ OUString sShapeName;
+ OUString aEngine( GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE ).GetValue() );
+ if ( aEngine.isEmpty()
+ || aEngine == "com.sun.star.drawing.EnhancedCustomShapeEngine" )
+ {
+ OUString sShapeType;
+ const SdrCustomShapeGeometryItem& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ const Any* pAny = rGeometryItem.GetPropertyValueByName( "Type" );
+ if ( pAny && ( *pAny >>= sShapeType ) )
+ sShapeName = EnhancedCustomShapeTypeNames::GetAccName( sShapeType );
+ }
+ return sShapeName;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdoattr.cxx b/svx/source/svdraw/svdoattr.cxx
new file mode 100644
index 000000000..2c1b208d3
--- /dev/null
+++ b/svx/source/svdraw/svdoattr.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdoattr.hxx>
+#include <svx/svdmodel.hxx>
+#include <svl/hint.hxx>
+#include <svl/itemset.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlnwtit.hxx>
+#include <sdr/properties/attributeproperties.hxx>
+
+using namespace com::sun::star;
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrAttrObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::AttributeProperties>(*this);
+}
+
+SdrAttrObj::SdrAttrObj(SdrModel& rSdrModel)
+ : SdrObject(rSdrModel)
+{
+}
+
+SdrAttrObj::SdrAttrObj(SdrModel& rSdrModel, SdrAttrObj const& rSource)
+ : SdrObject(rSdrModel, rSource)
+{
+}
+
+SdrAttrObj::~SdrAttrObj() {}
+
+const tools::Rectangle& SdrAttrObj::GetSnapRect() const
+{
+ if (m_bSnapRectDirty)
+ {
+ const_cast<SdrAttrObj*>(this)->RecalcSnapRect();
+ const_cast<SdrAttrObj*>(this)->m_bSnapRectDirty = false;
+ }
+
+ return maSnapRect;
+}
+
+// syntactical sugar for ItemSet accesses
+void SdrAttrObj::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ bool bDataChg(SfxHintId::DataChanged == rHint.GetId());
+
+ if (bDataChg)
+ {
+ tools::Rectangle aBoundRect = GetLastBoundRect();
+ SetBoundRectDirty();
+ SetBoundAndSnapRectsDirty(/*bNotMyself*/ true);
+
+ // This may have led to object change
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect);
+ }
+}
+
+sal_Int32 SdrAttrObj::ImpGetLineWdt() const
+{
+ sal_Int32 nRetval(0);
+
+ if (drawing::LineStyle_NONE != GetObjectItem(XATTR_LINESTYLE).GetValue())
+ {
+ nRetval = GetObjectItem(XATTR_LINEWIDTH).GetValue();
+ }
+
+ return nRetval;
+}
+
+bool SdrAttrObj::HasFill() const
+{
+ return m_bClosedObj
+ && GetProperties().GetObjectItemSet().Get(XATTR_FILLSTYLE).GetValue()
+ != drawing::FillStyle_NONE;
+}
+
+bool SdrAttrObj::HasLine() const
+{
+ return GetProperties().GetObjectItemSet().Get(XATTR_LINESTYLE).GetValue()
+ != drawing::LineStyle_NONE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx
new file mode 100644
index 000000000..4f13059a7
--- /dev/null
+++ b/svx/source/svdraw/svdobj.cxx
@@ -0,0 +1,3375 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdobj.hxx>
+#include <config_features.h>
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <drawinglayer/processor2d/contourextractor2d.hxx>
+#include <drawinglayer/processor2d/linegeometryextractor2d.hxx>
+#include <comphelper/processfactory.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/outlobj.hxx>
+#include <o3tl/deleter.hxx>
+#include <math.h>
+#include <svl/grabbagitem.hxx>
+#include <tools/bigint.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/helpers.hxx>
+#include <unotools/configmgr.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vector>
+
+#include <svx/shapepropertynotifier.hxx>
+#include <svx/svdotable.hxx>
+
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+#include <sdr/properties/emptyproperties.hxx>
+#include <svx/sdrhittesthelper.hxx>
+#include <svx/sdrobjectuser.hxx>
+#include <svx/sdrobjectfilter.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdomeas.hxx>
+#include <svx/svdomedia.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdovirt.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdview.hxx>
+#include <sxlayitm.hxx>
+#include <sxlogitm.hxx>
+#include <sxmovitm.hxx>
+#include <sxoneitm.hxx>
+#include <sxopitm.hxx>
+#include <sxreoitm.hxx>
+#include <sxrooitm.hxx>
+#include <sxsaitm.hxx>
+#include <sxsoitm.hxx>
+#include <sxtraitm.hxx>
+#include <svx/unopage.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/svdglue.hxx>
+#include <svx/svdsob.hxx>
+#include <svdobjplusdata.hxx>
+#include <svdobjuserdatalist.hxx>
+
+#include <unordered_set>
+
+#include <optional>
+#include <libxml/xmlwriter.h>
+#include <memory>
+
+#include <svx/scene3d.hxx>
+#include <rtl/character.hxx>
+#include <tools/UnitConversion.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star;
+
+
+SdrObjUserCall::~SdrObjUserCall()
+{
+}
+
+void SdrObjUserCall::Changed(const SdrObject& /*rObj*/, SdrUserCallType /*eType*/, const tools::Rectangle& /*rOldBoundRect*/)
+{
+}
+
+sal_Int32 SdrObjUserCall::GetPDFAnchorStructureElementId(SdrObject const&, OutputDevice const&)
+{
+ return -1;
+}
+
+SdrObjMacroHitRec::SdrObjMacroHitRec() :
+ pVisiLayer(nullptr),
+ pPageView(nullptr),
+ nTol(0) {}
+
+
+SdrObjUserData::SdrObjUserData(SdrInventor nInv, sal_uInt16 nId) :
+ nInventor(nInv),
+ nIdentifier(nId) {}
+
+SdrObjUserData::SdrObjUserData(const SdrObjUserData& rData) :
+ nInventor(rData.nInventor),
+ nIdentifier(rData.nIdentifier) {}
+
+SdrObjUserData::~SdrObjUserData() {}
+
+SdrObjGeoData::SdrObjGeoData():
+ bMovProt(false),
+ bSizProt(false),
+ bNoPrint(false),
+ bClosedObj(false),
+ mbVisible(true),
+ mnLayerID(0)
+{
+}
+
+SdrObjGeoData::~SdrObjGeoData()
+{
+}
+
+SdrObjTransformInfoRec::SdrObjTransformInfoRec() :
+ bMoveAllowed(true),
+ bResizeFreeAllowed(true),
+ bResizePropAllowed(true),
+ bRotateFreeAllowed(true),
+ bRotate90Allowed(true),
+ bMirrorFreeAllowed(true),
+ bMirror45Allowed(true),
+ bMirror90Allowed(true),
+ bTransparenceAllowed(true),
+ bShearAllowed(true),
+ bEdgeRadiusAllowed(true),
+ bNoOrthoDesired(true),
+ bNoContortion(true),
+ bCanConvToPath(true),
+ bCanConvToPoly(true),
+ bCanConvToContour(false),
+ bCanConvToPathLineToArea(true),
+ bCanConvToPolyLineToArea(true) {}
+
+struct SdrObject::Impl
+{
+ sdr::ObjectUserVector maObjectUsers;
+ std::optional<double> mnRelativeWidth;
+ std::optional<double> mnRelativeHeight;
+ sal_Int16 meRelativeWidthRelation;
+ sal_Int16 meRelativeHeightRelation;
+
+ Impl() :
+ meRelativeWidthRelation(text::RelOrientation::PAGE_FRAME),
+ meRelativeHeightRelation(text::RelOrientation::PAGE_FRAME) {}
+};
+
+const std::shared_ptr< svx::diagram::IDiagramHelper >& SdrObject::getDiagramHelper() const
+{
+ static std::shared_ptr< svx::diagram::IDiagramHelper > aEmpty;
+ return aEmpty;
+}
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrObject::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::EmptyProperties>(*this);
+}
+
+sdr::properties::BaseProperties& SdrObject::GetProperties() const
+{
+ if(!mpProperties)
+ {
+ // CAUTION(!) Do *not* call this during SdrObject construction,
+ // that will lead to wrong type-casts (dependent on constructor-level)
+ // and thus eventually create the wrong sdr::properties (!). Is there
+ // a way to check if on the stack is a SdrObject-constructor (?)
+ const_cast< SdrObject* >(this)->mpProperties =
+ const_cast< SdrObject* >(this)->CreateObjectSpecificProperties();
+ }
+
+ return *mpProperties;
+}
+
+
+// ObjectUser section
+
+void SdrObject::AddObjectUser(sdr::ObjectUser& rNewUser)
+{
+ mpImpl->maObjectUsers.push_back(&rNewUser);
+}
+
+void SdrObject::RemoveObjectUser(sdr::ObjectUser& rOldUser)
+{
+ const sdr::ObjectUserVector::iterator aFindResult =
+ std::find(mpImpl->maObjectUsers.begin(), mpImpl->maObjectUsers.end(), &rOldUser);
+ if (aFindResult != mpImpl->maObjectUsers.end())
+ {
+ mpImpl->maObjectUsers.erase(aFindResult);
+ }
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrObject::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrObj>(*this);
+}
+
+sdr::contact::ViewContact& SdrObject::GetViewContact() const
+{
+ if(!mpViewContact)
+ {
+ const_cast< SdrObject* >(this)->mpViewContact =
+ const_cast< SdrObject* >(this)->CreateObjectSpecificViewContact();
+ }
+
+ return *mpViewContact;
+}
+
+// DrawContact support: Methods for handling Object changes
+void SdrObject::ActionChanged() const
+{
+ // Do necessary ViewContact actions
+ GetViewContact().ActionChanged();
+}
+
+SdrPage* SdrObject::getSdrPageFromSdrObject() const
+{
+ if (SdrObjList* pParentList = getParentSdrObjListFromSdrObject())
+ {
+ return pParentList->getSdrPageFromSdrObjList();
+ }
+
+ return nullptr;
+}
+
+SdrModel& SdrObject::getSdrModelFromSdrObject() const
+{
+ return mrSdrModelFromSdrObject;
+}
+
+void SdrObject::setParentOfSdrObject(SdrObjList* pNewObjList)
+{
+ if(getParentSdrObjListFromSdrObject() == pNewObjList)
+ return;
+
+ // remember current page
+ SdrPage* pOldPage(getSdrPageFromSdrObject());
+
+ // set new parent
+ mpParentOfSdrObject = pNewObjList;
+
+ // get new page
+ SdrPage* pNewPage(getSdrPageFromSdrObject());
+
+ // broadcast page change over objects if needed
+ if(pOldPage != pNewPage)
+ {
+ handlePageChange(pOldPage, pNewPage);
+ }
+}
+
+SdrObjList* SdrObject::getParentSdrObjListFromSdrObject() const
+{
+ return mpParentOfSdrObject;
+}
+
+SdrObjList* SdrObject::getChildrenOfSdrObject() const
+{
+ // default has no children
+ return nullptr;
+}
+
+void SdrObject::SetBoundRectDirty()
+{
+ m_aOutRect = tools::Rectangle();
+}
+
+#ifdef DBG_UTIL
+// SdrObjectLifetimeWatchDog:
+void impAddIncarnatedSdrObjectToSdrModel(const SdrObject& rSdrObject, SdrModel& rSdrModel)
+{
+ rSdrModel.maAllIncarnatedObjects.insert(&rSdrObject);
+}
+void impRemoveIncarnatedSdrObjectToSdrModel(const SdrObject& rSdrObject, SdrModel& rSdrModel)
+{
+ if(!rSdrModel.maAllIncarnatedObjects.erase(&rSdrObject))
+ {
+ SAL_WARN("svx","SdrObject::~SdrObject: Destructed incarnation of SdrObject not member of this SdrModel (!)");
+ }
+}
+#endif
+
+SdrObject::SdrObject(SdrModel& rSdrModel)
+: mpFillGeometryDefiningShape(nullptr)
+ ,mrSdrModelFromSdrObject(rSdrModel)
+ ,m_pUserCall(nullptr)
+ ,mpImpl(new Impl)
+ ,mpParentOfSdrObject(nullptr)
+ ,m_nOrdNum(0)
+ ,mnNavigationPosition(SAL_MAX_UINT32)
+ ,mnLayerID(0)
+ ,mpSvxShape( nullptr )
+ ,mbDoNotInsertIntoPageAutomatically(false)
+{
+ m_bVirtObj =false;
+ m_bSnapRectDirty =true;
+ m_bMovProt =false;
+ m_bSizProt =false;
+ m_bNoPrint =false;
+ m_bEmptyPresObj =false;
+ m_bNotVisibleAsMaster=false;
+ m_bClosedObj =false;
+ mbVisible = true;
+
+ // #i25616#
+ mbLineIsOutsideGeometry = false;
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+
+ m_bIsEdge=false;
+ m_bIs3DObj=false;
+ m_bMarkProt=false;
+ m_bIsUnoObj=false;
+#ifdef DBG_UTIL
+ // SdrObjectLifetimeWatchDog:
+ impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
+#endif
+}
+
+SdrObject::SdrObject(SdrModel& rSdrModel, SdrObject const & rSource)
+: mpFillGeometryDefiningShape(nullptr)
+ ,mrSdrModelFromSdrObject(rSdrModel)
+ ,m_pUserCall(nullptr)
+ ,mpImpl(new Impl)
+ ,mpParentOfSdrObject(nullptr)
+ ,m_nOrdNum(0)
+ ,mnNavigationPosition(SAL_MAX_UINT32)
+ ,mnLayerID(0)
+ ,mpSvxShape( nullptr )
+ ,mbDoNotInsertIntoPageAutomatically(false)
+{
+ m_bVirtObj =false;
+ m_bSnapRectDirty =true;
+ m_bMovProt =false;
+ m_bSizProt =false;
+ m_bNoPrint =false;
+ m_bEmptyPresObj =false;
+ m_bNotVisibleAsMaster=false;
+ m_bClosedObj =false;
+ mbVisible = true;
+
+ // #i25616#
+ mbLineIsOutsideGeometry = false;
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+
+ m_bIsEdge=false;
+ m_bIs3DObj=false;
+ m_bMarkProt=false;
+ m_bIsUnoObj=false;
+#ifdef DBG_UTIL
+ // SdrObjectLifetimeWatchDog:
+ impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
+#endif
+
+ mpProperties.reset();
+ mpViewContact.reset();
+
+ // The CloneSdrObject() method uses the local copy constructor from the individual
+ // sdr::properties::BaseProperties class. Since the target class maybe for another
+ // draw object, an SdrObject needs to be provided, as in the normal constructor.
+ mpProperties = rSource.GetProperties().Clone(*this);
+
+ m_aOutRect=rSource.m_aOutRect;
+ mnLayerID = rSource.mnLayerID;
+ m_aAnchor =rSource.m_aAnchor;
+ m_bVirtObj=rSource.m_bVirtObj;
+ m_bSizProt=rSource.m_bSizProt;
+ m_bMovProt=rSource.m_bMovProt;
+ m_bNoPrint=rSource.m_bNoPrint;
+ mbVisible=rSource.mbVisible;
+ m_bMarkProt=rSource.m_bMarkProt;
+ m_bEmptyPresObj =rSource.m_bEmptyPresObj;
+ m_bNotVisibleAsMaster=rSource.m_bNotVisibleAsMaster;
+ m_bSnapRectDirty=true;
+ m_pPlusData.reset();
+ if (rSource.m_pPlusData!=nullptr) {
+ m_pPlusData.reset(rSource.m_pPlusData->Clone(this));
+ }
+ if (m_pPlusData!=nullptr && m_pPlusData->pBroadcast!=nullptr) {
+ m_pPlusData->pBroadcast.reset(); // broadcaster isn't copied
+ }
+
+ m_pGrabBagItem.reset();
+ if (rSource.m_pGrabBagItem!=nullptr)
+ m_pGrabBagItem.reset(rSource.m_pGrabBagItem->Clone());
+}
+
+SdrObject::~SdrObject()
+{
+ // Tell all the registered ObjectUsers that the page is in destruction.
+ // And clear the vector. This means that user do not need to call RemoveObjectUser()
+ // when they get called from ObjectInDestruction().
+ sdr::ObjectUserVector aList;
+ aList.swap(mpImpl->maObjectUsers);
+ for(sdr::ObjectUser* pObjectUser : aList)
+ {
+ DBG_ASSERT(pObjectUser, "SdrObject::~SdrObject: corrupt ObjectUser list (!)");
+ pObjectUser->ObjectInDestruction(*this);
+ }
+
+ // UserCall
+ SendUserCall(SdrUserCallType::Delete, GetLastBoundRect());
+ o3tl::reset_preserve_ptr_during(m_pPlusData);
+
+ m_pGrabBagItem.reset();
+ mpProperties.reset();
+ mpViewContact.reset();
+
+#ifdef DBG_UTIL
+ // SdrObjectLifetimeWatchDog:
+ impRemoveIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
+#endif
+}
+
+void SdrObject::Free( SdrObject*& _rpObject )
+{
+ SdrObject* pObject = _rpObject; _rpObject = nullptr;
+
+ if(nullptr == pObject)
+ {
+ // nothing to do
+ return;
+ }
+
+ SvxShape* pShape(pObject->getSvxShape());
+
+ if(pShape)
+ {
+ if(pShape->HasSdrObjectOwnership())
+ {
+ // only the SvxShape is allowed to delete me, and will reset
+ // the ownership before doing so
+ return;
+ }
+ else
+ {
+ // not only delete pObject, but also need to dispose uno shape
+ try
+ {
+ pShape->InvalidateSdrObject();
+ uno::Reference< lang::XComponent > xShapeComp( pObject->getWeakUnoShape().get(), uno::UNO_QUERY_THROW );
+ xShapeComp->dispose();
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+
+ delete pObject;
+}
+
+void SdrObject::SetBoundAndSnapRectsDirty(bool bNotMyself, bool bRecursive)
+{
+ if (!bNotMyself)
+ {
+ SetBoundRectDirty();
+ m_bSnapRectDirty=true;
+ }
+
+ if (bRecursive && nullptr != getParentSdrObjListFromSdrObject())
+ {
+ getParentSdrObjListFromSdrObject()->SetSdrObjListRectsDirty();
+ }
+}
+
+void SdrObject::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ // The creation of the UNO shape in SdrObject::getUnoShape is influenced
+ // by pPage, so when the page changes we need to discard the cached UNO
+ // shape so that a new one will be created.
+ // If the page is changing to another page with the same model, we
+ // assume they create compatible UNO shape objects so we shouldn't have
+ // to invalidate.
+ // TTTT: This causes quite some problems in SvxDrawPage::add when used
+ // e.g. from Writer - the SdrObject may be cloned to target model, and
+ // the xShape was added to it by purpose (see there). Thus it will be
+ // good to think about if this is really needed - it *seems* to be intended
+ // for a xShape being a on-demand-creatable resource - with the argument that
+ // the SdrPage/UnoPage used influences the SvxShape creation. This uses
+ // resources and would be nice to get rid of anyways.
+ if(nullptr == pOldPage || nullptr == pNewPage)
+ {
+ SvxShape* const pShape(getSvxShape());
+
+ if (pShape && !pShape->HasSdrObjectOwnership())
+ {
+ setUnoShape(nullptr);
+ }
+ }
+}
+
+
+// global static ItemPool for not-yet-inserted items
+static rtl::Reference<SdrItemPool> mpGlobalItemPool;
+
+/** If we let the libc runtime clean us up, we trigger a crash */
+namespace
+{
+class TerminateListener : public ::cppu::WeakImplHelper< css::frame::XTerminateListener >
+{
+ void SAL_CALL queryTermination( const lang::EventObject& ) override
+ {}
+ void SAL_CALL notifyTermination( const lang::EventObject& ) override
+ {
+ mpGlobalItemPool.clear();
+ }
+ virtual void SAL_CALL disposing( const ::css::lang::EventObject& ) override
+ {}
+};
+};
+
+// init global static itempool
+SdrItemPool& SdrObject::GetGlobalDrawObjectItemPool()
+{
+ if(!mpGlobalItemPool)
+ {
+ mpGlobalItemPool = new SdrItemPool();
+ rtl::Reference<SfxItemPool> pGlobalOutlPool = EditEngine::CreatePool();
+ mpGlobalItemPool->SetSecondaryPool(pGlobalOutlPool.get());
+ mpGlobalItemPool->SetDefaultMetric(SdrEngineDefaults::GetMapUnit());
+ mpGlobalItemPool->FreezeIdRanges();
+ if (utl::ConfigManager::IsFuzzing())
+ mpGlobalItemPool->acquire();
+ else
+ {
+ uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(comphelper::getProcessComponentContext());
+ uno::Reference< frame::XTerminateListener > xListener( new TerminateListener );
+ xDesktop->addTerminateListener( xListener );
+ }
+ }
+
+ return *mpGlobalItemPool;
+}
+
+void SdrObject::SetRelativeWidth( double nValue )
+{
+ mpImpl->mnRelativeWidth = nValue;
+}
+
+void SdrObject::SetRelativeWidthRelation( sal_Int16 eValue )
+{
+ mpImpl->meRelativeWidthRelation = eValue;
+}
+
+void SdrObject::SetRelativeHeight( double nValue )
+{
+ mpImpl->mnRelativeHeight = nValue;
+}
+
+void SdrObject::SetRelativeHeightRelation( sal_Int16 eValue )
+{
+ mpImpl->meRelativeHeightRelation = eValue;
+}
+
+const double* SdrObject::GetRelativeWidth( ) const
+{
+ if (!mpImpl->mnRelativeWidth)
+ return nullptr;
+
+ return &*mpImpl->mnRelativeWidth;
+}
+
+sal_Int16 SdrObject::GetRelativeWidthRelation() const
+{
+ return mpImpl->meRelativeWidthRelation;
+}
+
+const double* SdrObject::GetRelativeHeight( ) const
+{
+ if (!mpImpl->mnRelativeHeight)
+ return nullptr;
+
+ return &*mpImpl->mnRelativeHeight;
+}
+
+sal_Int16 SdrObject::GetRelativeHeightRelation() const
+{
+ return mpImpl->meRelativeHeightRelation;
+}
+
+SfxItemPool& SdrObject::GetObjectItemPool() const
+{
+ return getSdrModelFromSdrObject().GetItemPool();
+}
+
+SdrInventor SdrObject::GetObjInventor() const
+{
+ return SdrInventor::Default;
+}
+
+SdrObjKind SdrObject::GetObjIdentifier() const
+{
+ return SdrObjKind::NONE;
+}
+
+void SdrObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bRotateFreeAllowed=false;
+ rInfo.bMirrorFreeAllowed=false;
+ rInfo.bTransparenceAllowed = false;
+ rInfo.bShearAllowed =false;
+ rInfo.bEdgeRadiusAllowed=false;
+ rInfo.bCanConvToPath =false;
+ rInfo.bCanConvToPoly =false;
+ rInfo.bCanConvToContour = false;
+ rInfo.bCanConvToPathLineToArea=false;
+ rInfo.bCanConvToPolyLineToArea=false;
+}
+
+SdrLayerID SdrObject::GetLayer() const
+{
+ return mnLayerID;
+}
+
+void SdrObject::getMergedHierarchySdrLayerIDSet(SdrLayerIDSet& rSet) const
+{
+ rSet.Set(GetLayer());
+ SdrObjList* pOL=GetSubList();
+ if (pOL!=nullptr) {
+ const size_t nObjCount = pOL->GetObjCount();
+ for (size_t nObjNum = 0; nObjNum<nObjCount; ++nObjNum) {
+ pOL->GetObj(nObjNum)->getMergedHierarchySdrLayerIDSet(rSet);
+ }
+ }
+}
+
+void SdrObject::NbcSetLayer(SdrLayerID nLayer)
+{
+ mnLayerID = nLayer;
+}
+
+void SdrObject::SetLayer(SdrLayerID nLayer)
+{
+ NbcSetLayer(nLayer);
+ SetChanged();
+ BroadcastObjectChange();
+}
+
+void SdrObject::AddListener(SfxListener& rListener)
+{
+ ImpForcePlusData();
+ if (m_pPlusData->pBroadcast==nullptr) m_pPlusData->pBroadcast.reset(new SfxBroadcaster);
+
+ // SdrEdgeObj may be connected to same SdrObject on both ends so allow it
+ // to listen twice
+ SdrEdgeObj const*const pEdge(dynamic_cast<SdrEdgeObj const*>(&rListener));
+ rListener.StartListening(*m_pPlusData->pBroadcast, pEdge ? DuplicateHandling::Allow : DuplicateHandling::Unexpected);
+}
+
+void SdrObject::RemoveListener(SfxListener& rListener)
+{
+ if (m_pPlusData!=nullptr && m_pPlusData->pBroadcast!=nullptr) {
+ rListener.EndListening(*m_pPlusData->pBroadcast);
+ if (!m_pPlusData->pBroadcast->HasListeners()) {
+ m_pPlusData->pBroadcast.reset();
+ }
+ }
+}
+
+const SfxBroadcaster* SdrObject::GetBroadcaster() const
+{
+ return m_pPlusData!=nullptr ? m_pPlusData->pBroadcast.get() : nullptr;
+}
+
+void SdrObject::AddReference(SdrVirtObj& rVrtObj)
+{
+ AddListener(rVrtObj);
+}
+
+void SdrObject::DelReference(SdrVirtObj& rVrtObj)
+{
+ RemoveListener(rVrtObj);
+}
+
+bool SdrObject::IsGroupObject() const
+{
+ return GetSubList()!=nullptr;
+}
+
+SdrObjList* SdrObject::GetSubList() const
+{
+ return nullptr;
+}
+
+SdrObject* SdrObject::getParentSdrObjectFromSdrObject() const
+{
+ SdrObjList* pParent(getParentSdrObjListFromSdrObject());
+
+ if(nullptr == pParent)
+ {
+ return nullptr;
+ }
+
+ return pParent->getSdrObjectFromSdrObjList();
+}
+
+void SdrObject::SetName(const OUString& rStr, const bool bSetChanged)
+{
+ if (!rStr.isEmpty() && !m_pPlusData)
+ {
+ ImpForcePlusData();
+ }
+
+ if(!(m_pPlusData && m_pPlusData->aObjName != rStr))
+ return;
+
+ // Undo/Redo for setting object's name (#i73249#)
+ bool bUndo( false );
+ if ( getSdrModelFromSdrObject().IsUndoEnabled() )
+ {
+ bUndo = true;
+ std::unique_ptr<SdrUndoAction> pUndoAction =
+ SdrUndoFactory::CreateUndoObjectStrAttr(
+ *this,
+ SdrUndoObjStrAttr::ObjStrAttrType::Name,
+ GetName(),
+ rStr );
+ getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
+ getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
+ }
+ m_pPlusData->aObjName = rStr;
+ // Undo/Redo for setting object's name (#i73249#)
+ if ( bUndo )
+ {
+ getSdrModelFromSdrObject().EndUndo();
+ }
+ if (bSetChanged)
+ {
+ SetChanged();
+ BroadcastObjectChange();
+ }
+}
+
+const OUString & SdrObject::GetName() const
+{
+ static const OUString EMPTY = u"";
+
+ if(m_pPlusData)
+ {
+ return m_pPlusData->aObjName;
+ }
+
+ return EMPTY;
+}
+
+void SdrObject::SetTitle(const OUString& rStr)
+{
+ if (!rStr.isEmpty() && !m_pPlusData)
+ {
+ ImpForcePlusData();
+ }
+
+ if(!(m_pPlusData && m_pPlusData->aObjTitle != rStr))
+ return;
+
+ // Undo/Redo for setting object's title (#i73249#)
+ bool bUndo( false );
+ if ( getSdrModelFromSdrObject().IsUndoEnabled() )
+ {
+ bUndo = true;
+ std::unique_ptr<SdrUndoAction> pUndoAction =
+ SdrUndoFactory::CreateUndoObjectStrAttr(
+ *this,
+ SdrUndoObjStrAttr::ObjStrAttrType::Title,
+ GetTitle(),
+ rStr );
+ getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
+ getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
+ }
+ m_pPlusData->aObjTitle = rStr;
+ // Undo/Redo for setting object's title (#i73249#)
+ if ( bUndo )
+ {
+ getSdrModelFromSdrObject().EndUndo();
+ }
+ SetChanged();
+ BroadcastObjectChange();
+}
+
+OUString SdrObject::GetTitle() const
+{
+ if(m_pPlusData)
+ {
+ return m_pPlusData->aObjTitle;
+ }
+
+ return OUString();
+}
+
+void SdrObject::SetDescription(const OUString& rStr)
+{
+ if (!rStr.isEmpty() && !m_pPlusData)
+ {
+ ImpForcePlusData();
+ }
+
+ if(!(m_pPlusData && m_pPlusData->aObjDescription != rStr))
+ return;
+
+ // Undo/Redo for setting object's description (#i73249#)
+ bool bUndo( false );
+ if ( getSdrModelFromSdrObject().IsUndoEnabled() )
+ {
+ bUndo = true;
+ std::unique_ptr<SdrUndoAction> pUndoAction =
+ SdrUndoFactory::CreateUndoObjectStrAttr(
+ *this,
+ SdrUndoObjStrAttr::ObjStrAttrType::Description,
+ GetDescription(),
+ rStr );
+ getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
+ getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
+ }
+ m_pPlusData->aObjDescription = rStr;
+ // Undo/Redo for setting object's description (#i73249#)
+ if ( bUndo )
+ {
+ getSdrModelFromSdrObject().EndUndo();
+ }
+ SetChanged();
+ BroadcastObjectChange();
+}
+
+OUString SdrObject::GetDescription() const
+{
+ if(m_pPlusData)
+ {
+ return m_pPlusData->aObjDescription;
+ }
+
+ return OUString();
+}
+
+sal_uInt32 SdrObject::GetOrdNum() const
+{
+ if (SdrObjList* pParentList = getParentSdrObjListFromSdrObject())
+ {
+ if (pParentList->IsObjOrdNumsDirty())
+ {
+ pParentList->RecalcObjOrdNums();
+ }
+ } else const_cast<SdrObject*>(this)->m_nOrdNum=0;
+ return m_nOrdNum;
+}
+
+void SdrObject::SetOrdNum(sal_uInt32 nNum)
+{
+ m_nOrdNum = nNum;
+}
+
+void SdrObject::GetGrabBagItem(css::uno::Any& rVal) const
+{
+ if (m_pGrabBagItem != nullptr)
+ m_pGrabBagItem->QueryValue(rVal);
+ else
+ rVal <<= uno::Sequence<beans::PropertyValue>();
+}
+
+void SdrObject::SetGrabBagItem(const css::uno::Any& rVal)
+{
+ if (m_pGrabBagItem == nullptr)
+ m_pGrabBagItem.reset(new SfxGrabBagItem);
+
+ m_pGrabBagItem->PutValue(rVal, 0);
+
+ SetChanged();
+ BroadcastObjectChange();
+}
+
+sal_uInt32 SdrObject::GetNavigationPosition() const
+{
+ if (nullptr != getParentSdrObjListFromSdrObject() && getParentSdrObjListFromSdrObject()->RecalcNavigationPositions())
+ {
+ return mnNavigationPosition;
+ }
+ else
+ return GetOrdNum();
+}
+
+
+void SdrObject::SetNavigationPosition (const sal_uInt32 nNewPosition)
+{
+ mnNavigationPosition = nNewPosition;
+}
+
+
+// To make clearer that this method may trigger RecalcBoundRect and thus may be
+// expensive and sometimes problematic (inside a bigger object change you will get
+// non-useful BoundRects sometimes) I rename that method from GetBoundRect() to
+// GetCurrentBoundRect().
+const tools::Rectangle& SdrObject::GetCurrentBoundRect() const
+{
+ if(m_aOutRect.IsEmpty())
+ {
+ const_cast< SdrObject* >(this)->RecalcBoundRect();
+ }
+
+ return m_aOutRect;
+}
+
+// To have a possibility to get the last calculated BoundRect e.g for producing
+// the first rectangle for repaints (old and new need to be used) without forcing
+// a RecalcBoundRect (which may be problematical and expensive sometimes) I add here
+// a new method for accessing the last BoundRect.
+const tools::Rectangle& SdrObject::GetLastBoundRect() const
+{
+ return m_aOutRect;
+}
+
+void SdrObject::RecalcBoundRect()
+{
+ // #i101680# suppress BoundRect calculations on import(s)
+ if ((getSdrModelFromSdrObject().isLocked()) || utl::ConfigManager::IsFuzzing())
+ return;
+
+ // central new method which will calculate the BoundRect using primitive geometry
+ if(!m_aOutRect.IsEmpty())
+ return;
+
+ // Use view-independent data - we do not want any connections
+ // to e.g. GridOffset in SdrObject-level
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitives;
+ GetViewContact().getViewIndependentPrimitive2DContainer(xPrimitives);
+
+ if(xPrimitives.empty())
+ return;
+
+ // use neutral ViewInformation and get the range of the primitives
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D));
+
+ if(!aRange.isEmpty())
+ {
+ m_aOutRect = tools::Rectangle(
+ static_cast<tools::Long>(floor(aRange.getMinX())),
+ static_cast<tools::Long>(floor(aRange.getMinY())),
+ static_cast<tools::Long>(ceil(aRange.getMaxX())),
+ static_cast<tools::Long>(ceil(aRange.getMaxY())));
+ return;
+ }
+}
+
+void SdrObject::BroadcastObjectChange() const
+{
+ if ((getSdrModelFromSdrObject().isLocked()) || utl::ConfigManager::IsFuzzing())
+ return;
+
+ bool bPlusDataBroadcast(m_pPlusData && m_pPlusData->pBroadcast);
+ bool bObjectChange(IsInserted());
+
+ if(!(bPlusDataBroadcast || bObjectChange))
+ return;
+
+ SdrHint aHint(SdrHintKind::ObjectChange, *this);
+
+ if(bPlusDataBroadcast)
+ {
+ m_pPlusData->pBroadcast->Broadcast(aHint);
+ }
+
+ if(bObjectChange)
+ {
+ getSdrModelFromSdrObject().Broadcast(aHint);
+ }
+}
+
+void SdrObject::SetChanged()
+{
+ // For testing purposes, use the new ViewContact for change
+ // notification now.
+ ActionChanged();
+
+ // TTTT Need to check meaning/usage of IsInserted in one
+ // of the next changes. It should not mean to have a SdrModel
+ // set (this is guaranteed now), but should be connected to
+ // being added to a SdrPage (?)
+ // TTTT tdf#120066 Indeed - This triggers e.g. by CustomShape
+ // geometry-presenting SdrObjects that are in a SdrObjGroup,
+ // but the SdrObjGroup is *by purpose* not inserted.
+ // Need to check deeper and maybe identify all ::IsInserted()
+ // calls by rename and let the compiler work...
+ if(nullptr != getSdrPageFromSdrObject())
+ {
+ getSdrModelFromSdrObject().SetChanged();
+ }
+}
+
+// tooling for painting a single object to an OutputDevice.
+void SdrObject::SingleObjectPainter(OutputDevice& rOut) const
+{
+ sdr::contact::SdrObjectVector aObjectVector;
+ aObjectVector.push_back(const_cast< SdrObject* >(this));
+
+ sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, std::move(aObjectVector), getSdrPageFromSdrObject());
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ aPainter.ProcessDisplay(aDisplayInfo);
+}
+
+bool SdrObject::LineGeometryUsageIsNecessary() const
+{
+ drawing::LineStyle eXLS = GetMergedItem(XATTR_LINESTYLE).GetValue();
+ return (eXLS != drawing::LineStyle_NONE);
+}
+
+bool SdrObject::HasLimitedRotation() const
+{
+ // RotGrfFlyFrame: Default is false, support full rotation
+ return false;
+}
+
+SdrObject* SdrObject::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrObject(rTargetModel, *this);
+}
+
+OUString SdrObject::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulNONE));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+ return sName;
+}
+
+OUString SdrObject::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralNONE);
+}
+
+OUString SdrObject::ImpGetDescriptionStr(TranslateId pStrCacheID) const
+{
+ OUString aStr = SvxResId(pStrCacheID);
+ sal_Int32 nPos = aStr.indexOf("%1");
+ if (nPos >= 0)
+ {
+ // Replace '%1' with the object name.
+ OUString aObjName(TakeObjNameSingul());
+ aStr = aStr.replaceAt(nPos, 2, aObjName);
+ }
+
+ nPos = aStr.indexOf("%2");
+ if (nPos >= 0)
+ // Replace '%2' with the passed value.
+ aStr = aStr.replaceAt(nPos, 2, u"0");
+ return aStr;
+}
+
+void SdrObject::ImpForcePlusData()
+{
+ if (!m_pPlusData)
+ m_pPlusData.reset( new SdrObjPlusData );
+}
+
+OUString SdrObject::GetMetrStr(tools::Long nVal) const
+{
+ return getSdrModelFromSdrObject().GetMetricString(nVal);
+}
+
+basegfx::B2DPolyPolygon SdrObject::TakeXorPoly() const
+{
+ basegfx::B2DPolyPolygon aRetval;
+ const tools::Rectangle aR(GetCurrentBoundRect());
+ aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aR)));
+
+ return aRetval;
+}
+
+basegfx::B2DPolyPolygon SdrObject::TakeContour() const
+{
+ basegfx::B2DPolyPolygon aRetval;
+
+ // create cloned object without text, but with drawing::LineStyle_SOLID,
+ // COL_BLACK as line color and drawing::FillStyle_NONE
+ SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject()));
+
+ if(pClone)
+ {
+ const SdrTextObj* pTextObj = dynamic_cast< const SdrTextObj* >(this);
+
+ if(pTextObj)
+ {
+ // no text and no text animation
+ pClone->SetMergedItem(SdrTextAniKindItem(SdrTextAniKind::NONE));
+ pClone->SetOutlinerParaObject(std::nullopt);
+ }
+
+ const SdrEdgeObj* pEdgeObj = dynamic_cast< const SdrEdgeObj* >(this);
+
+ if(pEdgeObj)
+ {
+ // create connections if connector, will be cleaned up when
+ // deleting the connector again
+ SdrObject* pLeft = pEdgeObj->GetConnectedNode(true);
+ SdrObject* pRight = pEdgeObj->GetConnectedNode(false);
+
+ if(pLeft)
+ {
+ pClone->ConnectToNode(true, pLeft);
+ }
+
+ if(pRight)
+ {
+ pClone->ConnectToNode(false, pRight);
+ }
+ }
+
+ SfxItemSet aNewSet(GetObjectItemPool());
+
+ // #i101980# ignore LineWidth; that's what the old implementation
+ // did. With line width, the result may be huge due to fat/thick
+ // line decompositions
+ aNewSet.Put(XLineWidthItem(0));
+
+ // solid black lines and no fill
+ aNewSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
+ aNewSet.Put(XLineColorItem(OUString(), COL_BLACK));
+ aNewSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ pClone->SetMergedItemSet(aNewSet);
+
+ // get sequence from clone
+ const sdr::contact::ViewContact& rVC(pClone->GetViewContact());
+ drawinglayer::primitive2d::Primitive2DContainer xSequence;
+ rVC.getViewIndependentPrimitive2DContainer(xSequence);
+
+ if(!xSequence.empty())
+ {
+ // use neutral ViewInformation
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+
+ // create extractor, process and get result (with hairlines as opened polygons)
+ drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, false);
+ aExtractor.process(xSequence);
+ const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour());
+ const sal_uInt32 nSize(rResult.size());
+
+ // when count is one, it is implied that the object has only its normal
+ // contour anyways and TakeContour() is to return an empty PolyPolygon
+ // (see old implementation for historical reasons)
+ if(nSize > 1)
+ {
+ // the topology for contour is correctly a vector of PolyPolygons; for
+ // historical reasons cut it back to a single tools::PolyPolygon here
+ for(sal_uInt32 a(0); a < nSize; a++)
+ {
+ aRetval.append(rResult[a]);
+ }
+ }
+ }
+
+ // Always use SdrObject::Free to delete SdrObjects (!)
+ SdrObject::Free(pClone);
+ }
+
+ return aRetval;
+}
+
+sal_uInt32 SdrObject::GetHdlCount() const
+{
+ return 8;
+}
+
+void SdrObject::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ const tools::Rectangle& rR=GetSnapRect();
+ for (sal_uInt32 nHdlNum=0; nHdlNum<8; ++nHdlNum)
+ {
+ std::unique_ptr<SdrHdl> pH;
+ switch (nHdlNum) {
+ case 0: pH.reset(new SdrHdl(rR.TopLeft(), SdrHdlKind::UpperLeft)); break;
+ case 1: pH.reset(new SdrHdl(rR.TopCenter(), SdrHdlKind::Upper)); break;
+ case 2: pH.reset(new SdrHdl(rR.TopRight(), SdrHdlKind::UpperRight)); break;
+ case 3: pH.reset(new SdrHdl(rR.LeftCenter(), SdrHdlKind::Left )); break;
+ case 4: pH.reset(new SdrHdl(rR.RightCenter(), SdrHdlKind::Right)); break;
+ case 5: pH.reset(new SdrHdl(rR.BottomLeft(), SdrHdlKind::LowerLeft)); break;
+ case 6: pH.reset(new SdrHdl(rR.BottomCenter(),SdrHdlKind::Lower)); break;
+ case 7: pH.reset(new SdrHdl(rR.BottomRight(), SdrHdlKind::LowerRight)); break;
+ }
+ rHdlList.AddHdl(std::move(pH));
+ }
+}
+
+void SdrObject::AddToPlusHdlList(SdrHdlList&, SdrHdl&) const
+{
+}
+
+void SdrObject::addCropHandles(SdrHdlList& /*rTarget*/) const
+{
+ // Default implementation, does nothing. Overloaded in
+ // SdrGrafObj and SwVirtFlyDrawObj
+}
+
+tools::Rectangle SdrObject::ImpDragCalcRect(const SdrDragStat& rDrag) const
+{
+ tools::Rectangle aTmpRect(GetSnapRect());
+ tools::Rectangle aRect(aTmpRect);
+ const SdrHdl* pHdl=rDrag.GetHdl();
+ SdrHdlKind eHdl=pHdl==nullptr ? SdrHdlKind::Move : pHdl->GetKind();
+ bool bEcke=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::LowerLeft || eHdl==SdrHdlKind::LowerRight);
+ bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
+ bool bBigOrtho=bEcke && bOrtho && rDrag.GetView()->IsBigOrtho();
+ Point aPos(rDrag.GetNow());
+ bool bLft=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::LowerLeft);
+ bool bRgt=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerRight);
+ bool bTop=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperLeft);
+ bool bBtm=(eHdl==SdrHdlKind::LowerRight || eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerLeft);
+ if (bLft) aTmpRect.SetLeft(aPos.X() );
+ if (bRgt) aTmpRect.SetRight(aPos.X() );
+ if (bTop) aTmpRect.SetTop(aPos.Y() );
+ if (bBtm) aTmpRect.SetBottom(aPos.Y() );
+ if (bOrtho) { // Ortho
+ tools::Long nWdt0=aRect.Right() -aRect.Left();
+ tools::Long nHgt0=aRect.Bottom()-aRect.Top();
+ tools::Long nXMul=aTmpRect.Right() -aTmpRect.Left();
+ tools::Long nYMul=aTmpRect.Bottom()-aTmpRect.Top();
+ tools::Long nXDiv=nWdt0;
+ tools::Long nYDiv=nHgt0;
+ bool bXNeg=(nXMul<0)!=(nXDiv<0);
+ bool bYNeg=(nYMul<0)!=(nYDiv<0);
+ nXMul=std::abs(nXMul);
+ nYMul=std::abs(nYMul);
+ nXDiv=std::abs(nXDiv);
+ nYDiv=std::abs(nYDiv);
+ Fraction aXFact(nXMul,nXDiv); // fractions for canceling
+ Fraction aYFact(nYMul,nYDiv); // and for comparing
+ nXMul=aXFact.GetNumerator();
+ nYMul=aYFact.GetNumerator();
+ nXDiv=aXFact.GetDenominator();
+ nYDiv=aYFact.GetDenominator();
+ if (bEcke) { // corner point handles
+ bool bUseX=(aXFact<aYFact) != bBigOrtho;
+ if (bUseX) {
+ tools::Long nNeed=tools::Long(BigInt(nHgt0)*BigInt(nXMul)/BigInt(nXDiv));
+ if (bYNeg) nNeed=-nNeed;
+ if (bTop) aTmpRect.SetTop(aTmpRect.Bottom()-nNeed );
+ if (bBtm) aTmpRect.SetBottom(aTmpRect.Top()+nNeed );
+ } else {
+ tools::Long nNeed=tools::Long(BigInt(nWdt0)*BigInt(nYMul)/BigInt(nYDiv));
+ if (bXNeg) nNeed=-nNeed;
+ if (bLft) aTmpRect.SetLeft(aTmpRect.Right()-nNeed );
+ if (bRgt) aTmpRect.SetRight(aTmpRect.Left()+nNeed );
+ }
+ } else { // apex handles
+ if ((bLft || bRgt) && nXDiv!=0) {
+ tools::Long nHgt0b=aRect.Bottom()-aRect.Top();
+ tools::Long nNeed=tools::Long(BigInt(nHgt0b)*BigInt(nXMul)/BigInt(nXDiv));
+ aTmpRect.AdjustTop( -((nNeed-nHgt0b)/2) );
+ aTmpRect.SetBottom(aTmpRect.Top()+nNeed );
+ }
+ if ((bTop || bBtm) && nYDiv!=0) {
+ tools::Long nWdt0b=aRect.Right()-aRect.Left();
+ tools::Long nNeed=tools::Long(BigInt(nWdt0b)*BigInt(nYMul)/BigInt(nYDiv));
+ aTmpRect.AdjustLeft( -((nNeed-nWdt0b)/2) );
+ aTmpRect.SetRight(aTmpRect.Left()+nNeed );
+ }
+ }
+ }
+ aTmpRect.Justify();
+ return aTmpRect;
+}
+
+
+bool SdrObject::hasSpecialDrag() const
+{
+ return false;
+}
+
+bool SdrObject::supportsFullDrag() const
+{
+ return true;
+}
+
+SdrObjectUniquePtr SdrObject::getFullDragClone() const
+{
+ // default uses simple clone
+ return SdrObjectUniquePtr(CloneSdrObject(getSdrModelFromSdrObject()));
+}
+
+bool SdrObject::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ const SdrHdl* pHdl = rDrag.GetHdl();
+
+ SdrHdlKind eHdl = (pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind();
+
+ return eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperRight ||
+ eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerLeft ||
+ eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerRight;
+}
+
+bool SdrObject::applySpecialDrag(SdrDragStat& rDrag)
+{
+ tools::Rectangle aNewRect(ImpDragCalcRect(rDrag));
+
+ if(aNewRect != GetSnapRect())
+ {
+ NbcSetSnapRect(aNewRect);
+ }
+
+ return true;
+}
+
+OUString SdrObject::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
+{
+ return OUString();
+}
+
+basegfx::B2DPolyPolygon SdrObject::getSpecialDragPoly(const SdrDragStat& /*rDrag*/) const
+{
+ // default has nothing to add
+ return basegfx::B2DPolyPolygon();
+}
+
+
+// Create
+bool SdrObject::BegCreate(SdrDragStat& rStat)
+{
+ rStat.SetOrtho4Possible();
+ tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
+ aRect1.Justify();
+ rStat.SetActionRect(aRect1);
+ m_aOutRect = aRect1;
+ return true;
+}
+
+bool SdrObject::MovCreate(SdrDragStat& rStat)
+{
+ rStat.TakeCreateRect(m_aOutRect);
+ rStat.SetActionRect(m_aOutRect);
+ m_aOutRect.Justify();
+
+ return true;
+}
+
+bool SdrObject::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ rStat.TakeCreateRect(m_aOutRect);
+ m_aOutRect.Justify();
+
+ return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
+}
+
+void SdrObject::BrkCreate(SdrDragStat& /*rStat*/)
+{
+}
+
+bool SdrObject::BckCreate(SdrDragStat& /*rStat*/)
+{
+ return false;
+}
+
+basegfx::B2DPolyPolygon SdrObject::TakeCreatePoly(const SdrDragStat& rDrag) const
+{
+ tools::Rectangle aRect1;
+ rDrag.TakeCreateRect(aRect1);
+ aRect1.Justify();
+
+ basegfx::B2DPolyPolygon aRetval;
+ aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aRect1)));
+ return aRetval;
+}
+
+PointerStyle SdrObject::GetCreatePointer() const
+{
+ return PointerStyle::Cross;
+}
+
+// transformations
+void SdrObject::NbcMove(const Size& rSiz)
+{
+ m_aOutRect.Move(rSiz);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
+ bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
+ if (bXMirr || bYMirr) {
+ Point aRef1(GetSnapRect().Center());
+ if (bXMirr) {
+ Point aRef2(aRef1);
+ aRef2.AdjustY( 1 );
+ NbcMirrorGluePoints(aRef1,aRef2);
+ }
+ if (bYMirr) {
+ Point aRef2(aRef1);
+ aRef2.AdjustX( 1 );
+ NbcMirrorGluePoints(aRef1,aRef2);
+ }
+ }
+ ResizeRect(m_aOutRect,rRef,xFact,yFact);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrObject::NbcRotate(const Point& rRef, Degree100 nAngle)
+{
+ if (nAngle)
+ {
+ double a = toRadians(nAngle);
+ NbcRotate( rRef, nAngle, sin( a ), cos( a ) );
+ }
+}
+
+void SdrObject::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ SetGlueReallyAbsolute(true);
+ m_aOutRect.Move(-rRef.X(),-rRef.Y());
+ tools::Rectangle R(m_aOutRect);
+ if (sn==1.0 && cs==0.0) { // 90deg
+ m_aOutRect.SetLeft(-R.Bottom() );
+ m_aOutRect.SetRight(-R.Top() );
+ m_aOutRect.SetTop(R.Left() );
+ m_aOutRect.SetBottom(R.Right() );
+ } else if (sn==0.0 && cs==-1.0) { // 180deg
+ m_aOutRect.SetLeft(-R.Right() );
+ m_aOutRect.SetRight(-R.Left() );
+ m_aOutRect.SetTop(-R.Bottom() );
+ m_aOutRect.SetBottom(-R.Top() );
+ } else if (sn==-1.0 && cs==0.0) { // 270deg
+ m_aOutRect.SetLeft(R.Top() );
+ m_aOutRect.SetRight(R.Bottom() );
+ m_aOutRect.SetTop(-R.Right() );
+ m_aOutRect.SetBottom(-R.Left() );
+ }
+ m_aOutRect.Move(rRef.X(),rRef.Y());
+ m_aOutRect.Justify(); // just in case
+ SetBoundAndSnapRectsDirty();
+ NbcRotateGluePoints(rRef,nAngle,sn,cs);
+ SetGlueReallyAbsolute(false);
+}
+
+void SdrObject::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ SetGlueReallyAbsolute(true);
+ m_aOutRect.Move(-rRef1.X(),-rRef1.Y());
+ tools::Rectangle R(m_aOutRect);
+ tools::Long dx=rRef2.X()-rRef1.X();
+ tools::Long dy=rRef2.Y()-rRef1.Y();
+ if (dx==0) { // vertical axis
+ m_aOutRect.SetLeft(-R.Right() );
+ m_aOutRect.SetRight(-R.Left() );
+ } else if (dy==0) { // horizontal axis
+ m_aOutRect.SetTop(-R.Bottom() );
+ m_aOutRect.SetBottom(-R.Top() );
+ } else if (dx==dy) { // 45deg axis
+ m_aOutRect.SetLeft(R.Top() );
+ m_aOutRect.SetRight(R.Bottom() );
+ m_aOutRect.SetTop(R.Left() );
+ m_aOutRect.SetBottom(R.Right() );
+ } else if (dx==-dy) { // 45deg axis
+ m_aOutRect.SetLeft(-R.Bottom() );
+ m_aOutRect.SetRight(-R.Top() );
+ m_aOutRect.SetTop(-R.Right() );
+ m_aOutRect.SetBottom(-R.Left() );
+ }
+ m_aOutRect.Move(rRef1.X(),rRef1.Y());
+ m_aOutRect.Justify(); // just in case
+ SetBoundAndSnapRectsDirty();
+ NbcMirrorGluePoints(rRef1,rRef2);
+ SetGlueReallyAbsolute(false);
+}
+
+void SdrObject::NbcShear(const Point& rRef, Degree100 /*nAngle*/, double tn, bool bVShear)
+{
+ SetGlueReallyAbsolute(true);
+ NbcShearGluePoints(rRef,tn,bVShear);
+ SetGlueReallyAbsolute(false);
+}
+
+void SdrObject::Move(const Size& rSiz)
+{
+ if (rSiz.Width()!=0 || rSiz.Height()!=0) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcMove(rSiz);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
+ }
+}
+
+void SdrObject::NbcCrop(const basegfx::B2DPoint& /*aRef*/, double /*fxFact*/, double /*fyFact*/)
+{
+ // Default: does nothing. Real behaviour in SwVirtFlyDrawObj and SdrDragCrop::EndSdrDrag.
+ // Where SwVirtFlyDrawObj is the only real user of it to do something local
+}
+
+void SdrObject::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
+{
+ if (xFact.GetNumerator() == xFact.GetDenominator() && yFact.GetNumerator() == yFact.GetDenominator())
+ return;
+
+ if (bUnsetRelative)
+ {
+ mpImpl->mnRelativeWidth.reset();
+ mpImpl->meRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
+ mpImpl->meRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
+ mpImpl->mnRelativeHeight.reset();
+ }
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcResize(rRef,xFact,yFact);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrObject::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcCrop(rRef, fxFact, fyFact);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrObject::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ if (nAngle) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcRotate(rRef,nAngle,sn,cs);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+}
+
+void SdrObject::Mirror(const Point& rRef1, const Point& rRef2)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcMirror(rRef1,rRef2);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrObject::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ if (nAngle) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcShear(rRef,nAngle,tn,bVShear);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+}
+
+void SdrObject::NbcSetRelativePos(const Point& rPnt)
+{
+ Point aRelPos0(GetSnapRect().TopLeft()-m_aAnchor);
+ Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
+ NbcMove(aSiz); // This also calls SetRectsDirty()
+}
+
+void SdrObject::SetRelativePos(const Point& rPnt)
+{
+ if (rPnt!=GetRelativePos()) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcSetRelativePos(rPnt);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
+ }
+}
+
+Point SdrObject::GetRelativePos() const
+{
+ return GetSnapRect().TopLeft()-m_aAnchor;
+}
+
+void SdrObject::ImpSetAnchorPos(const Point& rPnt)
+{
+ m_aAnchor = rPnt;
+}
+
+void SdrObject::NbcSetAnchorPos(const Point& rPnt)
+{
+ Size aSiz(rPnt.X()-m_aAnchor.X(),rPnt.Y()-m_aAnchor.Y());
+ m_aAnchor=rPnt;
+ NbcMove(aSiz); // This also calls SetRectsDirty()
+}
+
+void SdrObject::SetAnchorPos(const Point& rPnt)
+{
+ if (rPnt!=m_aAnchor) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcSetAnchorPos(rPnt);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
+ }
+}
+
+const Point& SdrObject::GetAnchorPos() const
+{
+ return m_aAnchor;
+}
+
+void SdrObject::RecalcSnapRect()
+{
+}
+
+const tools::Rectangle& SdrObject::GetSnapRect() const
+{
+ return m_aOutRect;
+}
+
+void SdrObject::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ m_aOutRect=rRect;
+}
+
+const tools::Rectangle& SdrObject::GetLogicRect() const
+{
+ return GetSnapRect();
+}
+
+void SdrObject::NbcSetLogicRect(const tools::Rectangle& rRect)
+{
+ NbcSetSnapRect(rRect);
+}
+
+void SdrObject::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
+{
+ SetLogicRect( rMaxRect );
+}
+
+void SdrObject::SetSnapRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcSetSnapRect(rRect);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrObject::SetLogicRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcSetLogicRect(rRect);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+Degree100 SdrObject::GetRotateAngle() const
+{
+ return 0_deg100;
+}
+
+Degree100 SdrObject::GetShearAngle(bool /*bVertical*/) const
+{
+ return 0_deg100;
+}
+
+sal_uInt32 SdrObject::GetSnapPointCount() const
+{
+ return GetPointCount();
+}
+
+Point SdrObject::GetSnapPoint(sal_uInt32 i) const
+{
+ return GetPoint(i);
+}
+
+bool SdrObject::IsPolyObj() const
+{
+ return false;
+}
+
+sal_uInt32 SdrObject::GetPointCount() const
+{
+ return 0;
+}
+
+Point SdrObject::GetPoint(sal_uInt32 /*i*/) const
+{
+ return Point();
+}
+
+void SdrObject::SetPoint(const Point& rPnt, sal_uInt32 i)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcSetPoint(rPnt, i);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrObject::NbcSetPoint(const Point& /*rPnt*/, sal_uInt32 /*i*/)
+{
+}
+
+bool SdrObject::HasTextEdit() const
+{
+ return false;
+}
+
+bool SdrObject::Equals(const SdrObject& rOtherObj) const
+{
+ return (m_aAnchor.X() == rOtherObj.m_aAnchor.X() && m_aAnchor.Y() == rOtherObj.m_aAnchor.Y() &&
+ m_nOrdNum == rOtherObj.m_nOrdNum && mnNavigationPosition == rOtherObj.mnNavigationPosition &&
+ mbSupportTextIndentingOnLineWidthChange == rOtherObj.mbSupportTextIndentingOnLineWidthChange &&
+ mbLineIsOutsideGeometry == rOtherObj.mbLineIsOutsideGeometry && m_bMarkProt == rOtherObj.m_bMarkProt &&
+ m_bIs3DObj == rOtherObj.m_bIs3DObj && m_bIsEdge == rOtherObj.m_bIsEdge && m_bClosedObj == rOtherObj.m_bClosedObj &&
+ m_bNotVisibleAsMaster == rOtherObj.m_bNotVisibleAsMaster && m_bEmptyPresObj == rOtherObj.m_bEmptyPresObj &&
+ mbVisible == rOtherObj.mbVisible && m_bNoPrint == rOtherObj.m_bNoPrint && m_bSizProt == rOtherObj.m_bSizProt &&
+ m_bMovProt == rOtherObj.m_bMovProt && m_bVirtObj == rOtherObj.m_bVirtObj &&
+ mnLayerID == rOtherObj.mnLayerID && GetMergedItemSet().Equals(rOtherObj.GetMergedItemSet(), false) );
+}
+
+void SdrObject::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrObject"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*this).name()));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("name"), "%s", BAD_CAST(GetName().toUtf8().getStr()));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("title"), "%s", BAD_CAST(GetTitle().toUtf8().getStr()));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("description"), "%s", BAD_CAST(GetDescription().toUtf8().getStr()));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("nOrdNum"), "%" SAL_PRIuUINT32, GetOrdNumDirect());
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("aOutRect"), BAD_CAST(m_aOutRect.toString().getStr()));
+
+ if (m_pGrabBagItem)
+ {
+ m_pGrabBagItem->dumpAsXml(pWriter);
+ }
+
+ if (mpProperties)
+ {
+ mpProperties->dumpAsXml(pWriter);
+ }
+
+ if (const OutlinerParaObject* pOutliner = GetOutlinerParaObject())
+ pOutliner->dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+void SdrObject::SetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcSetOutlinerParaObject(std::move(pTextObject));
+ SetChanged();
+ BroadcastObjectChange();
+ if (GetCurrentBoundRect()!=aBoundRect0) {
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+
+ if (!getSdrModelFromSdrObject().IsUndoEnabled())
+ return;
+
+ // Don't do this during import.
+ SdrObject* pTopGroupObj = nullptr;
+ if (getParentSdrObjectFromSdrObject())
+ {
+ pTopGroupObj = getParentSdrObjectFromSdrObject();
+ while (pTopGroupObj->getParentSdrObjectFromSdrObject())
+ {
+ pTopGroupObj = pTopGroupObj->getParentSdrObjectFromSdrObject();
+ }
+ }
+ if (pTopGroupObj)
+ {
+ // A shape was modified, which is in a group shape. Empty the group shape's grab-bag,
+ // which potentially contains the old text of the shapes in case of diagrams.
+ pTopGroupObj->SetGrabBagItem(uno::Any(uno::Sequence<beans::PropertyValue>()));
+ }
+}
+
+void SdrObject::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> /*pTextObject*/)
+{
+}
+
+OutlinerParaObject* SdrObject::GetOutlinerParaObject() const
+{
+ return nullptr;
+}
+
+void SdrObject::NbcReformatText()
+{
+}
+
+void SdrObject::BurnInStyleSheetAttributes()
+{
+ GetProperties().ForceStyleToHardAttributes();
+}
+
+bool SdrObject::HasMacro() const
+{
+ return false;
+}
+
+SdrObject* SdrObject::CheckMacroHit(const SdrObjMacroHitRec& rRec) const
+{
+ if(rRec.pPageView)
+ {
+ return SdrObjectPrimitiveHit(*this, rRec.aPos, rRec.nTol, *rRec.pPageView, rRec.pVisiLayer, false);
+ }
+
+ return nullptr;
+}
+
+PointerStyle SdrObject::GetMacroPointer(const SdrObjMacroHitRec&) const
+{
+ return PointerStyle::RefHand;
+}
+
+void SdrObject::PaintMacro(OutputDevice& rOut, const tools::Rectangle& , const SdrObjMacroHitRec& ) const
+{
+ const RasterOp eRop(rOut.GetRasterOp());
+ const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());
+
+ rOut.SetLineColor(COL_BLACK);
+ rOut.SetFillColor();
+ rOut.SetRasterOp(RasterOp::Invert);
+
+ for(auto const& rPolygon : aPolyPolygon)
+ {
+ rOut.DrawPolyLine(rPolygon);
+ }
+
+ rOut.SetRasterOp(eRop);
+}
+
+bool SdrObject::DoMacro(const SdrObjMacroHitRec&)
+{
+ return false;
+}
+
+bool SdrObject::IsMacroHit(const SdrObjMacroHitRec& rRec) const
+{
+ return CheckMacroHit(rRec) != nullptr;
+}
+
+
+std::unique_ptr<SdrObjGeoData> SdrObject::NewGeoData() const
+{
+ return std::make_unique<SdrObjGeoData>();
+}
+
+void SdrObject::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ rGeo.aBoundRect =GetCurrentBoundRect();
+ rGeo.aAnchor =m_aAnchor ;
+ rGeo.bMovProt =m_bMovProt ;
+ rGeo.bSizProt =m_bSizProt ;
+ rGeo.bNoPrint =m_bNoPrint ;
+ rGeo.mbVisible =mbVisible ;
+ rGeo.bClosedObj =m_bClosedObj ;
+ rGeo.mnLayerID = mnLayerID;
+
+ // user-defined gluepoints
+ if (m_pPlusData!=nullptr && m_pPlusData->pGluePoints!=nullptr) {
+ if (rGeo.pGPL!=nullptr) {
+ *rGeo.pGPL=*m_pPlusData->pGluePoints;
+ } else {
+ rGeo.pGPL.reset( new SdrGluePointList(*m_pPlusData->pGluePoints) );
+ }
+ } else {
+ rGeo.pGPL.reset();
+ }
+}
+
+void SdrObject::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SetBoundAndSnapRectsDirty();
+ m_aOutRect =rGeo.aBoundRect ;
+ m_aAnchor =rGeo.aAnchor ;
+ m_bMovProt =rGeo.bMovProt ;
+ m_bSizProt =rGeo.bSizProt ;
+ m_bNoPrint =rGeo.bNoPrint ;
+ mbVisible =rGeo.mbVisible ;
+ m_bClosedObj =rGeo.bClosedObj ;
+ mnLayerID = rGeo.mnLayerID;
+
+ // user-defined gluepoints
+ if (rGeo.pGPL!=nullptr) {
+ ImpForcePlusData();
+ if (m_pPlusData->pGluePoints!=nullptr) {
+ *m_pPlusData->pGluePoints=*rGeo.pGPL;
+ } else {
+ m_pPlusData->pGluePoints.reset(new SdrGluePointList(*rGeo.pGPL));
+ }
+ } else {
+ if (m_pPlusData!=nullptr && m_pPlusData->pGluePoints!=nullptr) {
+ m_pPlusData->pGluePoints.reset();
+ }
+ }
+}
+
+std::unique_ptr<SdrObjGeoData> SdrObject::GetGeoData() const
+{
+ std::unique_ptr<SdrObjGeoData> pGeo = NewGeoData();
+ SaveGeoData(*pGeo);
+ return pGeo;
+}
+
+void SdrObject::SetGeoData(const SdrObjGeoData& rGeo)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ RestoreGeoData(rGeo);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+
+// ItemSet access
+
+const SfxItemSet& SdrObject::GetObjectItemSet() const
+{
+ return GetProperties().GetObjectItemSet();
+}
+
+const SfxItemSet& SdrObject::GetMergedItemSet() const
+{
+ return GetProperties().GetMergedItemSet();
+}
+
+void SdrObject::SetObjectItem(const SfxPoolItem& rItem)
+{
+ GetProperties().SetObjectItem(rItem);
+}
+
+void SdrObject::SetMergedItem(const SfxPoolItem& rItem)
+{
+ GetProperties().SetMergedItem(rItem);
+}
+
+void SdrObject::ClearMergedItem(const sal_uInt16 nWhich)
+{
+ GetProperties().ClearMergedItem(nWhich);
+}
+
+void SdrObject::SetObjectItemSet(const SfxItemSet& rSet)
+{
+ GetProperties().SetObjectItemSet(rSet);
+}
+
+void SdrObject::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
+{
+ GetProperties().SetMergedItemSet(rSet, bClearAllItems);
+}
+
+const SfxPoolItem& SdrObject::GetObjectItem(const sal_uInt16 nWhich) const
+{
+ return GetObjectItemSet().Get(nWhich);
+}
+
+const SfxPoolItem& SdrObject::GetMergedItem(const sal_uInt16 nWhich) const
+{
+ return GetMergedItemSet().Get(nWhich);
+}
+
+void SdrObject::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems)
+{
+ GetProperties().SetMergedItemSetAndBroadcast(rSet, bClearAllItems);
+}
+
+void SdrObject::ApplyNotPersistAttr(const SfxItemSet& rAttr)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcApplyNotPersistAttr(rAttr);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrObject::NbcApplyNotPersistAttr(const SfxItemSet& rAttr)
+{
+ const tools::Rectangle& rSnap=GetSnapRect();
+ const tools::Rectangle& rLogic=GetLogicRect();
+ Point aRef1(rSnap.Center());
+
+ if (const SdrTransformRef1XItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF1X))
+ {
+ aRef1.setX(pPoolItem->GetValue() );
+ }
+ if (const SdrTransformRef1YItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF1Y))
+ {
+ aRef1.setY(pPoolItem->GetValue() );
+ }
+
+ tools::Rectangle aNewSnap(rSnap);
+ if (const SdrMoveXItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_MOVEX))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ aNewSnap.Move(n,0);
+ }
+ if (const SdrMoveYItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_MOVEY))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ aNewSnap.Move(0,n);
+ }
+ if (const SdrOnePositionXItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONEPOSITIONX))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ aNewSnap.Move(n-aNewSnap.Left(),0);
+ }
+ if (const SdrOnePositionYItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONEPOSITIONY))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ aNewSnap.Move(0,n-aNewSnap.Top());
+ }
+ if (const SdrOneSizeWidthItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONESIZEWIDTH))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ aNewSnap.SetRight(aNewSnap.Left()+n );
+ }
+ if (const SdrOneSizeHeightItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONESIZEHEIGHT))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ aNewSnap.SetBottom(aNewSnap.Top()+n );
+ }
+ if (aNewSnap!=rSnap) {
+ if (aNewSnap.GetSize()==rSnap.GetSize()) {
+ NbcMove(Size(aNewSnap.Left()-rSnap.Left(),aNewSnap.Top()-rSnap.Top()));
+ } else {
+ NbcSetSnapRect(aNewSnap);
+ }
+ }
+
+ if (const SdrShearAngleItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_SHEARANGLE))
+ {
+ Degree100 n = pPoolItem->GetValue();
+ n-=GetShearAngle();
+ if (n) {
+ double nTan = tan(toRadians(n));
+ NbcShear(aRef1,n,nTan,false);
+ }
+ }
+ if (const SdrAngleItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ROTATEANGLE))
+ {
+ Degree100 n = pPoolItem->GetValue();
+ n-=GetRotateAngle();
+ if (n) {
+ NbcRotate(aRef1,n);
+ }
+ }
+ if (const SdrRotateOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ROTATEONE))
+ {
+ Degree100 n = pPoolItem->GetValue();
+ NbcRotate(aRef1,n);
+ }
+ if (const SdrHorzShearOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_HORZSHEARONE))
+ {
+ Degree100 n = pPoolItem->GetValue();
+ double nTan = tan(toRadians(n));
+ NbcShear(aRef1,n,nTan,false);
+ }
+ if (const SdrVertShearOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_VERTSHEARONE))
+ {
+ Degree100 n = pPoolItem->GetValue();
+ double nTan = tan(toRadians(n));
+ NbcShear(aRef1,n,nTan,true);
+ }
+
+ if (const SdrYesNoItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJMOVEPROTECT))
+ {
+ bool b = pPoolItem->GetValue();
+ SetMoveProtect(b);
+ }
+ if (const SdrYesNoItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJSIZEPROTECT))
+ {
+ bool b = pPoolItem->GetValue();
+ SetResizeProtect(b);
+ }
+
+ /* move protect always sets size protect */
+ if( IsMoveProtect() )
+ SetResizeProtect( true );
+
+ if (const SdrObjPrintableItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJPRINTABLE))
+ {
+ bool b = pPoolItem->GetValue();
+ SetPrintable(b);
+ }
+
+ if (const SdrObjVisibleItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJVISIBLE))
+ {
+ bool b = pPoolItem->GetValue();
+ SetVisible(b);
+ }
+
+ SdrLayerID nLayer=SDRLAYER_NOTFOUND;
+ if (const SdrLayerIdItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LAYERID))
+ {
+ nLayer = pPoolItem->GetValue();
+ }
+ if (const SdrLayerNameItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LAYERNAME))
+ {
+ OUString aLayerName = pPoolItem->GetValue();
+ const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject()
+ ? getSdrPageFromSdrObject()->GetLayerAdmin()
+ : getSdrModelFromSdrObject().GetLayerAdmin());
+ const SdrLayer* pLayer = rLayAd.GetLayer(aLayerName);
+
+ if(nullptr != pLayer)
+ {
+ nLayer=pLayer->GetID();
+ }
+ }
+ if (nLayer!=SDRLAYER_NOTFOUND) {
+ NbcSetLayer(nLayer);
+ }
+
+ if (const SfxStringItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJECTNAME))
+ {
+ OUString aName = pPoolItem->GetValue();
+ SetName(aName);
+ }
+ tools::Rectangle aNewLogic(rLogic);
+ if (const SdrLogicSizeWidthItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LOGICSIZEWIDTH))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ aNewLogic.SetRight(aNewLogic.Left()+n );
+ }
+ if (const SdrLogicSizeHeightItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LOGICSIZEHEIGHT))
+ {
+ tools::Long n = pPoolItem->GetValue();
+ aNewLogic.SetBottom(aNewLogic.Top()+n );
+ }
+ if (aNewLogic!=rLogic) {
+ NbcSetLogicRect(aNewLogic);
+ }
+ Fraction aResizeX(1,1);
+ Fraction aResizeY(1,1);
+ if (const SdrResizeXOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_RESIZEXONE))
+ {
+ aResizeX *= pPoolItem->GetValue();
+ }
+ if (const SdrResizeYOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_RESIZEYONE))
+ {
+ aResizeY *= pPoolItem->GetValue();
+ }
+ if (aResizeX!=Fraction(1,1) || aResizeY!=Fraction(1,1)) {
+ NbcResize(aRef1,aResizeX,aResizeY);
+ }
+}
+
+void SdrObject::TakeNotPersistAttr(SfxItemSet& rAttr) const
+{
+ const tools::Rectangle& rSnap=GetSnapRect();
+ const tools::Rectangle& rLogic=GetLogicRect();
+ rAttr.Put(SdrYesNoItem(SDRATTR_OBJMOVEPROTECT, IsMoveProtect()));
+ rAttr.Put(SdrYesNoItem(SDRATTR_OBJSIZEPROTECT, IsResizeProtect()));
+ rAttr.Put(SdrObjPrintableItem(IsPrintable()));
+ rAttr.Put(SdrObjVisibleItem(IsVisible()));
+ rAttr.Put(SdrAngleItem(SDRATTR_ROTATEANGLE, GetRotateAngle()));
+ rAttr.Put(SdrShearAngleItem(GetShearAngle()));
+ rAttr.Put(SdrOneSizeWidthItem(rSnap.GetWidth()-1));
+ rAttr.Put(SdrOneSizeHeightItem(rSnap.GetHeight()-1));
+ rAttr.Put(SdrOnePositionXItem(rSnap.Left()));
+ rAttr.Put(SdrOnePositionYItem(rSnap.Top()));
+ if (rLogic.GetWidth()!=rSnap.GetWidth()) {
+ rAttr.Put(SdrLogicSizeWidthItem(rLogic.GetWidth()-1));
+ }
+ if (rLogic.GetHeight()!=rSnap.GetHeight()) {
+ rAttr.Put(SdrLogicSizeHeightItem(rLogic.GetHeight()-1));
+ }
+ OUString aName(GetName());
+
+ if (!aName.isEmpty())
+ {
+ rAttr.Put(SfxStringItem(SDRATTR_OBJECTNAME, aName));
+ }
+
+ rAttr.Put(SdrLayerIdItem(GetLayer()));
+ const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject()
+ ? getSdrPageFromSdrObject()->GetLayerAdmin()
+ : getSdrModelFromSdrObject().GetLayerAdmin());
+ const SdrLayer* pLayer = rLayAd.GetLayerPerID(GetLayer());
+ if(nullptr != pLayer)
+ {
+ rAttr.Put(SdrLayerNameItem(pLayer->GetName()));
+ }
+ Point aRef1(rSnap.Center());
+ Point aRef2(aRef1); aRef2.AdjustY( 1 );
+ rAttr.Put(SdrTransformRef1XItem(aRef1.X()));
+ rAttr.Put(SdrTransformRef1YItem(aRef1.Y()));
+ rAttr.Put(SdrTransformRef2XItem(aRef2.X()));
+ rAttr.Put(SdrTransformRef2YItem(aRef2.Y()));
+}
+
+SfxStyleSheet* SdrObject::GetStyleSheet() const
+{
+ return GetProperties().GetStyleSheet();
+}
+
+void SdrObject::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
+{
+ tools::Rectangle aBoundRect0;
+
+ if(m_pUserCall)
+ aBoundRect0 = GetLastBoundRect();
+
+ InternalSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, true);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect0);
+}
+
+void SdrObject::NbcSetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
+{
+ InternalSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, false);
+}
+
+void SdrObject::InternalSetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr, bool bBroadcast)
+{
+ GetProperties().SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+}
+
+// Broadcasting while setting attributes is managed by the AttrObj.
+
+
+SdrGluePoint SdrObject::GetVertexGluePoint(sal_uInt16 nPosNum) const
+{
+ // #i41936# Use SnapRect for default GluePoints
+ const tools::Rectangle aR(GetSnapRect());
+ Point aPt;
+
+ switch(nPosNum)
+ {
+ case 0 : aPt = aR.TopCenter(); break;
+ case 1 : aPt = aR.RightCenter(); break;
+ case 2 : aPt = aR.BottomCenter(); break;
+ case 3 : aPt = aR.LeftCenter(); break;
+ }
+
+ aPt -= aR.Center();
+ SdrGluePoint aGP(aPt);
+ aGP.SetPercent(false);
+
+ return aGP;
+}
+
+SdrGluePoint SdrObject::GetCornerGluePoint(sal_uInt16 nPosNum) const
+{
+ tools::Rectangle aR(GetCurrentBoundRect());
+ Point aPt;
+ switch (nPosNum) {
+ case 0 : aPt=aR.TopLeft(); break;
+ case 1 : aPt=aR.TopRight(); break;
+ case 2 : aPt=aR.BottomRight(); break;
+ case 3 : aPt=aR.BottomLeft(); break;
+ }
+ aPt-=GetSnapRect().Center();
+ SdrGluePoint aGP(aPt);
+ aGP.SetPercent(false);
+ return aGP;
+}
+
+const SdrGluePointList* SdrObject::GetGluePointList() const
+{
+ if (m_pPlusData!=nullptr) return m_pPlusData->pGluePoints.get();
+ return nullptr;
+}
+
+
+SdrGluePointList* SdrObject::ForceGluePointList()
+{
+ ImpForcePlusData();
+ if (m_pPlusData->pGluePoints==nullptr) {
+ m_pPlusData->pGluePoints.reset(new SdrGluePointList);
+ }
+ return m_pPlusData->pGluePoints.get();
+}
+
+void SdrObject::SetGlueReallyAbsolute(bool bOn)
+{
+ // First a const call to see whether there are any gluepoints.
+ // Force const call!
+ if (GetGluePointList()!=nullptr) {
+ SdrGluePointList* pGPL=ForceGluePointList();
+ pGPL->SetReallyAbsolute(bOn,*this);
+ }
+}
+
+void SdrObject::NbcRotateGluePoints(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ // First a const call to see whether there are any gluepoints.
+ // Force const call!
+ if (GetGluePointList()!=nullptr) {
+ SdrGluePointList* pGPL=ForceGluePointList();
+ pGPL->Rotate(rRef,nAngle,sn,cs,this);
+ }
+}
+
+void SdrObject::NbcMirrorGluePoints(const Point& rRef1, const Point& rRef2)
+{
+ // First a const call to see whether there are any gluepoints.
+ // Force const call!
+ if (GetGluePointList()!=nullptr) {
+ SdrGluePointList* pGPL=ForceGluePointList();
+ pGPL->Mirror(rRef1,rRef2,this);
+ }
+}
+
+void SdrObject::NbcShearGluePoints(const Point& rRef, double tn, bool bVShear)
+{
+ // First a const call to see whether there are any gluepoints.
+ // Force const call!
+ if (GetGluePointList()!=nullptr) {
+ SdrGluePointList* pGPL=ForceGluePointList();
+ pGPL->Shear(rRef,tn,bVShear,this);
+ }
+}
+
+void SdrObject::ConnectToNode(bool /*bTail1*/, SdrObject* /*pObj*/)
+{
+}
+
+void SdrObject::DisconnectFromNode(bool /*bTail1*/)
+{
+}
+
+SdrObject* SdrObject::GetConnectedNode(bool /*bTail1*/) const
+{
+ return nullptr;
+}
+
+
+static void extractLineContourFromPrimitive2DSequence(
+ const drawinglayer::primitive2d::Primitive2DContainer& rxSequence,
+ basegfx::B2DPolygonVector& rExtractedHairlines,
+ basegfx::B2DPolyPolygonVector& rExtractedLineFills)
+{
+ rExtractedHairlines.clear();
+ rExtractedLineFills.clear();
+
+ if(rxSequence.empty())
+ return;
+
+ // use neutral ViewInformation
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+
+ // create extractor, process and get result
+ drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D);
+ aExtractor.process(rxSequence);
+
+ // copy line results
+ rExtractedHairlines = aExtractor.getExtractedHairlines();
+
+ // copy fill rsults
+ rExtractedLineFills = aExtractor.getExtractedLineFills();
+}
+
+
+SdrObject* SdrObject::ImpConvertToContourObj(bool bForceLineDash)
+{
+ SdrObject* pRetval(nullptr);
+
+ if(LineGeometryUsageIsNecessary())
+ {
+ basegfx::B2DPolyPolygon aMergedLineFillPolyPolygon;
+ basegfx::B2DPolyPolygon aMergedHairlinePolyPolygon;
+ drawinglayer::primitive2d::Primitive2DContainer xSequence;
+ GetViewContact().getViewIndependentPrimitive2DContainer(xSequence);
+
+ if(!xSequence.empty())
+ {
+ basegfx::B2DPolygonVector aExtractedHairlines;
+ basegfx::B2DPolyPolygonVector aExtractedLineFills;
+
+ extractLineContourFromPrimitive2DSequence(xSequence, aExtractedHairlines, aExtractedLineFills);
+
+ // for SdrObject creation, just copy all to a single Hairline-PolyPolygon
+ for(const basegfx::B2DPolygon & rExtractedHairline : aExtractedHairlines)
+ {
+ aMergedHairlinePolyPolygon.append(rExtractedHairline);
+ }
+
+ // check for fill rsults
+ if (!aExtractedLineFills.empty() && !utl::ConfigManager::IsFuzzing())
+ {
+ // merge to a single tools::PolyPolygon (OR)
+ aMergedLineFillPolyPolygon = basegfx::utils::mergeToSinglePolyPolygon(std::move(aExtractedLineFills));
+ }
+ }
+
+ if(aMergedLineFillPolyPolygon.count() || (bForceLineDash && aMergedHairlinePolyPolygon.count()))
+ {
+ SfxItemSet aSet(GetMergedItemSet());
+ drawing::FillStyle eOldFillStyle = aSet.Get(XATTR_FILLSTYLE).GetValue();
+ SdrPathObj* aLinePolygonPart = nullptr;
+ SdrPathObj* aLineHairlinePart = nullptr;
+ bool bBuildGroup(false);
+
+ if(aMergedLineFillPolyPolygon.count())
+ {
+ // create SdrObject for filled line geometry
+ aLinePolygonPart = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathFill,
+ aMergedLineFillPolyPolygon);
+
+ // correct item properties
+ aSet.Put(XLineWidthItem(0));
+ aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ Color aColorLine = aSet.Get(XATTR_LINECOLOR).GetColorValue();
+ sal_uInt16 nTransLine = aSet.Get(XATTR_LINETRANSPARENCE).GetValue();
+ aSet.Put(XFillColorItem(OUString(), aColorLine));
+ aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ aSet.Put(XFillTransparenceItem(nTransLine));
+
+ aLinePolygonPart->SetMergedItemSet(aSet);
+ }
+
+ if(aMergedHairlinePolyPolygon.count())
+ {
+ // create SdrObject for hairline geometry
+ // OBJ_PATHLINE is necessary here, not OBJ_PATHFILL. This is intended
+ // to get a non-filled object. If the poly is closed, the PathObj takes care for
+ // the correct closed state.
+ aLineHairlinePart = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aMergedHairlinePolyPolygon);
+
+ aSet.Put(XLineWidthItem(0));
+ aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ aSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
+
+ // it is also necessary to switch off line start and ends here
+ aSet.Put(XLineStartWidthItem(0));
+ aSet.Put(XLineEndWidthItem(0));
+
+ aLineHairlinePart->SetMergedItemSet(aSet);
+
+ if(aLinePolygonPart)
+ {
+ bBuildGroup = true;
+ }
+ }
+
+ // check if original geometry should be added (e.g. filled and closed)
+ bool bAddOriginalGeometry(false);
+ SdrPathObj* pPath = dynamic_cast<SdrPathObj*>(this);
+
+ if(pPath && pPath->IsClosed())
+ {
+ if(eOldFillStyle != drawing::FillStyle_NONE)
+ {
+ bAddOriginalGeometry = true;
+ }
+ }
+
+ // do we need a group?
+ if(bBuildGroup || bAddOriginalGeometry)
+ {
+ SdrObject* pGroup = new SdrObjGroup(getSdrModelFromSdrObject());
+
+ if(bAddOriginalGeometry)
+ {
+ // Add a clone of the original geometry.
+ aSet.ClearItem();
+ aSet.Put(GetMergedItemSet());
+ aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ aSet.Put(XLineWidthItem(0));
+
+ SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject()));
+ pClone->SetMergedItemSet(aSet);
+
+ pGroup->GetSubList()->NbcInsertObject(pClone);
+ }
+
+ if(aLinePolygonPart)
+ {
+ pGroup->GetSubList()->NbcInsertObject(aLinePolygonPart);
+ }
+
+ if(aLineHairlinePart)
+ {
+ pGroup->GetSubList()->NbcInsertObject(aLineHairlinePart);
+ }
+
+ pRetval = pGroup;
+ }
+ else
+ {
+ if(aLinePolygonPart)
+ {
+ pRetval = aLinePolygonPart;
+ }
+ else if(aLineHairlinePart)
+ {
+ pRetval = aLineHairlinePart;
+ }
+ }
+ }
+ }
+
+ if(nullptr == pRetval)
+ {
+ // due to current method usage, create and return a clone when nothing has changed
+ SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject()));
+ pRetval = pClone;
+ }
+
+ return pRetval;
+}
+
+
+void SdrObject::SetMarkProtect(bool bProt)
+{
+ m_bMarkProt = bProt;
+}
+
+
+void SdrObject::SetEmptyPresObj(bool bEpt)
+{
+ m_bEmptyPresObj = bEpt;
+}
+
+
+void SdrObject::SetNotVisibleAsMaster(bool bFlg)
+{
+ m_bNotVisibleAsMaster=bFlg;
+}
+
+
+// convert this path object to contour object, even when it is a group
+SdrObject* SdrObject::ConvertToContourObj(SdrObject* pRet, bool bForceLineDash) const
+{
+ if(dynamic_cast<const SdrObjGroup*>( pRet) != nullptr)
+ {
+ SdrObjList* pObjList2 = pRet->GetSubList();
+ SdrObject* pGroup = new SdrObjGroup(getSdrModelFromSdrObject());
+
+ for(size_t a=0; a<pObjList2->GetObjCount(); ++a)
+ {
+ SdrObject* pIterObj = pObjList2->GetObj(a);
+ pGroup->GetSubList()->NbcInsertObject(ConvertToContourObj(pIterObj, bForceLineDash));
+ }
+
+ pRet = pGroup;
+ }
+ else
+ {
+ if (SdrPathObj *pPathObj = dynamic_cast<SdrPathObj*>(pRet))
+ {
+ // bezier geometry got created, even for straight edges since the given
+ // object is a result of DoConvertToPolyObj. For conversion to contour
+ // this is not really needed and can be reduced again AFAP
+ pPathObj->SetPathPoly(basegfx::utils::simplifyCurveSegments(pPathObj->GetPathPoly()));
+ }
+
+ pRet = pRet->ImpConvertToContourObj(bForceLineDash);
+ }
+
+ // #i73441# preserve LayerID
+ if(pRet && pRet->GetLayer() != GetLayer())
+ {
+ pRet->SetLayer(GetLayer());
+ }
+
+ return pRet;
+}
+
+
+SdrObjectUniquePtr SdrObject::ConvertToPolyObj(bool bBezier, bool bLineToArea) const
+{
+ SdrObjectUniquePtr pRet = DoConvertToPolyObj(bBezier, true);
+
+ if(pRet && bLineToArea)
+ {
+ SdrObject* pNewRet = ConvertToContourObj(pRet.get());
+ pRet.reset(pNewRet);
+ }
+
+ // #i73441# preserve LayerID
+ if(pRet && pRet->GetLayer() != GetLayer())
+ {
+ pRet->SetLayer(GetLayer());
+ }
+
+ return pRet;
+}
+
+
+SdrObjectUniquePtr SdrObject::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
+{
+ return nullptr;
+}
+
+
+void SdrObject::InsertedStateChange()
+{
+ const bool bIsInserted(nullptr != getParentSdrObjListFromSdrObject());
+ const tools::Rectangle aBoundRect0(GetLastBoundRect());
+
+ if(bIsInserted)
+ {
+ SendUserCall(SdrUserCallType::Inserted, aBoundRect0);
+ }
+ else
+ {
+ SendUserCall(SdrUserCallType::Removed, aBoundRect0);
+ }
+
+ if(nullptr != m_pPlusData && nullptr != m_pPlusData->pBroadcast)
+ {
+ SdrHint aHint(bIsInserted ? SdrHintKind::ObjectInserted : SdrHintKind::ObjectRemoved, *this);
+ m_pPlusData->pBroadcast->Broadcast(aHint);
+ }
+}
+
+void SdrObject::SetMoveProtect(bool bProt)
+{
+ if(IsMoveProtect() != bProt)
+ {
+ // #i77187# secured and simplified
+ m_bMovProt = bProt;
+ SetChanged();
+ BroadcastObjectChange();
+ }
+}
+
+void SdrObject::SetResizeProtect(bool bProt)
+{
+ if(IsResizeProtect() != bProt)
+ {
+ // #i77187# secured and simplified
+ m_bSizProt = bProt;
+ SetChanged();
+ BroadcastObjectChange();
+ }
+}
+
+void SdrObject::SetPrintable(bool bPrn)
+{
+ if( bPrn == m_bNoPrint )
+ {
+ m_bNoPrint=!bPrn;
+ SetChanged();
+ if (IsInserted())
+ {
+ SdrHint aHint(SdrHintKind::ObjectChange, *this);
+ getSdrModelFromSdrObject().Broadcast(aHint);
+ }
+ }
+}
+
+void SdrObject::SetVisible(bool bVisible)
+{
+ if( bVisible != mbVisible )
+ {
+ mbVisible = bVisible;
+ SetChanged();
+ if (IsInserted())
+ {
+ SdrHint aHint(SdrHintKind::ObjectChange, *this);
+ getSdrModelFromSdrObject().Broadcast(aHint);
+ }
+ }
+}
+
+
+sal_uInt16 SdrObject::GetUserDataCount() const
+{
+ if (m_pPlusData==nullptr || m_pPlusData->pUserDataList==nullptr) return 0;
+ return m_pPlusData->pUserDataList->GetUserDataCount();
+}
+
+SdrObjUserData* SdrObject::GetUserData(sal_uInt16 nNum) const
+{
+ if (m_pPlusData==nullptr || m_pPlusData->pUserDataList==nullptr) return nullptr;
+ return &m_pPlusData->pUserDataList->GetUserData(nNum);
+}
+
+void SdrObject::AppendUserData(std::unique_ptr<SdrObjUserData> pData)
+{
+ if (!pData)
+ {
+ OSL_FAIL("SdrObject::AppendUserData(): pData is NULL pointer.");
+ return;
+ }
+
+ ImpForcePlusData();
+ if (!m_pPlusData->pUserDataList)
+ m_pPlusData->pUserDataList.reset( new SdrObjUserDataList );
+
+ m_pPlusData->pUserDataList->AppendUserData(std::move(pData));
+}
+
+void SdrObject::DeleteUserData(sal_uInt16 nNum)
+{
+ sal_uInt16 nCount=GetUserDataCount();
+ if (nNum<nCount) {
+ m_pPlusData->pUserDataList->DeleteUserData(nNum);
+ if (nCount==1) {
+ m_pPlusData->pUserDataList.reset();
+ }
+ } else {
+ OSL_FAIL("SdrObject::DeleteUserData(): Invalid Index.");
+ }
+}
+
+void SdrObject::SetUserCall(SdrObjUserCall* pUser)
+{
+ m_pUserCall = pUser;
+}
+
+
+void SdrObject::SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle& rBoundRect) const
+{
+ SdrObject* pGroup(getParentSdrObjectFromSdrObject());
+
+ if ( m_pUserCall )
+ {
+ m_pUserCall->Changed( *this, eUserCall, rBoundRect );
+ }
+
+ if(nullptr != pGroup && pGroup->GetUserCall())
+ {
+ // broadcast to group
+ SdrUserCallType eChildUserType = SdrUserCallType::ChildChangeAttr;
+
+ switch( eUserCall )
+ {
+ case SdrUserCallType::MoveOnly:
+ eChildUserType = SdrUserCallType::ChildMoveOnly;
+ break;
+
+ case SdrUserCallType::Resize:
+ eChildUserType = SdrUserCallType::ChildResize;
+ break;
+
+ case SdrUserCallType::ChangeAttr:
+ eChildUserType = SdrUserCallType::ChildChangeAttr;
+ break;
+
+ case SdrUserCallType::Delete:
+ eChildUserType = SdrUserCallType::ChildDelete;
+ break;
+
+ case SdrUserCallType::Inserted:
+ eChildUserType = SdrUserCallType::ChildInserted;
+ break;
+
+ case SdrUserCallType::Removed:
+ eChildUserType = SdrUserCallType::ChildRemoved;
+ break;
+
+ default: break;
+ }
+
+ pGroup->GetUserCall()->Changed( *this, eChildUserType, rBoundRect );
+ }
+
+ // notify our UNO shape listeners
+ switch ( eUserCall )
+ {
+ case SdrUserCallType::Resize:
+ notifyShapePropertyChange( svx::ShapePropertyProviderId::Size );
+ [[fallthrough]]; // RESIZE might also imply a change of the position
+ case SdrUserCallType::MoveOnly:
+ notifyShapePropertyChange( svx::ShapePropertyProviderId::Position );
+ break;
+ default:
+ // not interested in
+ break;
+ }
+}
+
+void SdrObject::setUnoShape( const uno::Reference< drawing::XShape >& _rxUnoShape )
+{
+ const uno::Reference< uno::XInterface>& xOldUnoShape( maWeakUnoShape );
+ // the UNO shape would be gutted by the following code; return early
+ if ( _rxUnoShape == xOldUnoShape )
+ {
+ if ( !xOldUnoShape.is() )
+ {
+ // make sure there is no stale impl. pointer if the UNO
+ // shape was destroyed meanwhile (remember we only hold weak
+ // reference to it!)
+ mpSvxShape = nullptr;
+ }
+ return;
+ }
+
+ bool bTransferOwnership( false );
+ if ( xOldUnoShape.is() )
+ {
+ bTransferOwnership = mpSvxShape->HasSdrObjectOwnership();
+ // Remove yourself from the current UNO shape. Its destructor
+ // will reset our UNO shape otherwise.
+ mpSvxShape->InvalidateSdrObject();
+ }
+
+ maWeakUnoShape = _rxUnoShape;
+ mpSvxShape = comphelper::getFromUnoTunnel<SvxShape>( _rxUnoShape );
+
+ // I think this may never happen... But I am not sure enough .-)
+ if ( bTransferOwnership )
+ {
+ if (mpSvxShape)
+ mpSvxShape->TakeSdrObjectOwnership();
+ SAL_WARN( "svx.uno", "a UNO shape took over an SdrObject previously owned by another UNO shape!");
+ }
+}
+
+/** only for internal use! */
+SvxShape* SdrObject::getSvxShape()
+{
+ DBG_TESTSOLARMUTEX();
+ // retrieving the impl pointer and subsequently using it is not thread-safe, of course, so it needs to be
+ // guarded by the SolarMutex
+
+ uno::Reference< uno::XInterface > xShape( maWeakUnoShape );
+#if OSL_DEBUG_LEVEL > 0
+ OSL_ENSURE( !( !xShape.is() && mpSvxShape ),
+ "SdrObject::getSvxShape: still having IMPL-Pointer to dead object!" );
+#endif
+ //#113608#, make sure mpSvxShape is always synchronized with maWeakUnoShape
+ if ( mpSvxShape && !xShape.is() )
+ mpSvxShape = nullptr;
+
+ return mpSvxShape;
+}
+
+css::uno::Reference< css::drawing::XShape > SdrObject::getUnoShape()
+{
+ // try weak reference first
+ uno::Reference< css::drawing::XShape > xShape( getWeakUnoShape() );
+ if( xShape )
+ return xShape;
+
+ OSL_ENSURE( mpSvxShape == nullptr, "SdrObject::getUnoShape: XShape already dead, but still an IMPL pointer!" );
+
+ // try to access SdrPage from this SdrObject. This will only exist if the SdrObject is
+ // inserted in a SdrObjList (page/group/3dScene)
+ SdrPage* pPageCandidate(getSdrPageFromSdrObject());
+
+ // tdf#12152, tdf#120728
+ //
+ // With the paradigm change to only get a SdrPage for a SdrObject when the SdrObject
+ // is *inserted*, the functionality for creating 1:1 associated UNO API implementation
+ // SvxShapes was partially broken: The used ::CreateShape relies on the SvxPage being
+ // derived and the CreateShape method overloaded, implementing additional SdrInventor
+ // types as needed.
+ //
+ // The fallback to use SvxDrawPage::CreateShapeByTypeAndInventor is a trap: It's only
+ // a static fallback that handles the SdrInventor types SdrInventor::E3d and
+ // SdrInventor::Default. Due to that, e.g. the ReportDesigner broke in various conditions.
+ //
+ // That again has to do with the ReportDesigner being implemented using the UNO API
+ // aspects of SdrObjects early during their construction, not just after these are
+ // inserted to a SdrPage - but that is not illegal or wrong, the SdrObject exists already.
+ //
+ // As a current solution, use the (now always available) SdrModel and any of the
+ // existing SdrPages. The only important thing is to get a SdrPage where ::CreateShape is
+ // overloaded and implemented as needed.
+ //
+ // Note for the future:
+ // In a more ideal world there would be only one factory method for creating SdrObjects (not
+ // ::CreateShape and ::CreateShapeByTypeAndInventor). This also would not be placed at
+ // SdrPage/SvxPage at all, but at the Model where it belongs - where else would you expect
+ // objects for the current Model to be constructed? To have this at the Page only would make
+ // sense if different shapes would need to be constructed for different Pages in the same Model
+ // - this is never the case.
+ // At that Model extended functionality for that factory (or overloads and implementations)
+ // should be placed. But to be realistic, migrating the factories to Model now is too much
+ // work - maybe over time when melting SdrObject/SvxObject one day...
+ //
+ // More Note (added by noel grandin)
+ // Except that sd/ is being naughty and doing all kinds of magic during CreateShape that
+ // requires knowing which page the object is being created for. Fixing that would require
+ // moving a bunch of nasty logic from object creation time, to the point in time when
+ // it is actually added to a page.
+ if(nullptr == pPageCandidate)
+ {
+ // If not inserted, alternatively access a SdrPage using the SdrModel. There is
+ // no reason not to create and return a UNO API XShape when the SdrObject is not
+ // inserted - it may be in construction. Main paradigm is that it exists.
+ if(0 != getSdrModelFromSdrObject().GetPageCount())
+ {
+ // Take 1st SdrPage. That may be e.g. a special page (in SD), but the
+ // to-be-used method ::CreateShape will be correctly overloaded in
+ // all cases
+ pPageCandidate = getSdrModelFromSdrObject().GetPage(0);
+ }
+ }
+
+ if(nullptr != pPageCandidate)
+ {
+ uno::Reference< uno::XInterface > xPage(pPageCandidate->getUnoPage());
+ if( xPage.is() )
+ {
+ SvxDrawPage* pDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>(xPage);
+ if( pDrawPage )
+ {
+ // create one
+ xShape = pDrawPage->CreateShape( this );
+ setUnoShape( xShape );
+ }
+ }
+ }
+ else
+ {
+ // Fallback to static base functionality. CAUTION: This will only support
+ // the most basic stuff like SdrInventor::E3d and SdrInventor::Default. All
+ // the other SdrInventor enum entries are from overloads and are *not accessible*
+ // using this fallback (!) - what a bad trap
+ rtl::Reference<SvxShape> xNewShape = SvxDrawPage::CreateShapeByTypeAndInventor( GetObjIdentifier(), GetObjInventor(), this );
+ mpSvxShape = xNewShape.get();
+ maWeakUnoShape = xShape = mpSvxShape;
+ }
+
+ return xShape;
+}
+
+svx::PropertyChangeNotifier& SdrObject::getShapePropertyChangeNotifier()
+{
+ DBG_TESTSOLARMUTEX();
+
+ SvxShape* pSvxShape = getSvxShape();
+ ENSURE_OR_THROW( pSvxShape, "no SvxShape, yet!" );
+ return pSvxShape->getShapePropertyChangeNotifier();
+}
+
+void SdrObject::notifyShapePropertyChange( const svx::ShapePropertyProviderId _eProperty ) const
+{
+ DBG_TESTSOLARMUTEX();
+
+ SvxShape* pSvxShape = const_cast< SdrObject* >( this )->getSvxShape();
+ if ( pSvxShape )
+ return pSvxShape->getShapePropertyChangeNotifier().notifyPropertyChange( _eProperty );
+}
+
+
+// transformation interface for StarOfficeAPI. This implements support for
+// homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
+// moment it contains a shearX, rotation and translation, but for setting all linear
+// transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
+
+
+// gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
+// with the base geometry and returns TRUE. Otherwise it returns FALSE.
+bool SdrObject::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
+{
+ // any kind of SdrObject, just use SnapRect
+ tools::Rectangle aRectangle(GetSnapRect());
+
+ // convert to transformation values
+ basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight());
+ basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top());
+
+ // position maybe relative to anchorpos, convert
+ if(getSdrModelFromSdrObject().IsWriter())
+ {
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // build matrix
+ rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
+
+ return false;
+}
+
+// sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
+// If it's an SdrPathObj it will use the provided geometry information. The Polygon has
+// to use (0,0) as upper left and will be scaled to the given size in the matrix.
+void SdrObject::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
+{
+ // break up matrix
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate, fShearX;
+ rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
+ // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
+ if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
+ {
+ aScale.setX(fabs(aScale.getX()));
+ aScale.setY(fabs(aScale.getY()));
+ }
+
+ // if anchor is used, make position relative to it
+ if(getSdrModelFromSdrObject().IsWriter())
+ {
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // build BaseRect
+ Point aPoint(FRound(aTranslate.getX()), FRound(aTranslate.getY()));
+ tools::Rectangle aBaseRect(aPoint, Size(FRound(aScale.getX()), FRound(aScale.getY())));
+
+ // set BaseRect
+ SetSnapRect(aBaseRect);
+}
+
+// Give info if object is in destruction
+bool SdrObject::IsInDestruction() const
+{
+ return getSdrModelFromSdrObject().IsInDestruction();
+}
+
+// return if fill is != drawing::FillStyle_NONE
+bool SdrObject::HasFillStyle() const
+{
+ return GetObjectItem(XATTR_FILLSTYLE).GetValue() != drawing::FillStyle_NONE;
+}
+
+bool SdrObject::HasLineStyle() const
+{
+ return GetObjectItem(XATTR_LINESTYLE).GetValue() != drawing::LineStyle_NONE;
+}
+
+
+// #i52224#
+// on import of OLE object from MS documents the BLIP size might be retrieved,
+// the following four methods are used to control it;
+// usually this data makes no sense after the import is finished, since the object
+// might be resized
+
+
+void SdrObject::SetBLIPSizeRectangle( const tools::Rectangle& aRect )
+{
+ maBLIPSizeRectangle = aRect;
+}
+
+void SdrObject::SetContextWritingMode( const sal_Int16 /*_nContextWritingMode*/ )
+{
+ // this base class does not support different writing modes, so ignore the call
+}
+
+void SdrObject::SetDoNotInsertIntoPageAutomatically(const bool bSet)
+{
+ mbDoNotInsertIntoPageAutomatically = bSet;
+}
+
+
+// #i121917#
+bool SdrObject::HasText() const
+{
+ return false;
+}
+
+bool SdrObject::IsTextBox() const
+{
+ return false;
+}
+
+void SdrObject::MakeNameUnique()
+{
+ if (GetName().isEmpty())
+ {
+ if (const E3dScene* pE3dObj = dynamic_cast<const E3dScene*>(this))
+ {
+ SdrObjList* pObjList = pE3dObj->GetSubList();
+ if (pObjList)
+ {
+ SdrObject* pObj0 = pObjList->GetObj(0);
+ if (pObj0)
+ SetName(pObj0->TakeObjNameSingul());
+ }
+ }
+ else
+ SetName(TakeObjNameSingul());
+ }
+
+ std::unordered_set<OUString> aNameSet;
+ MakeNameUnique(aNameSet);
+}
+
+void SdrObject::MakeNameUnique(std::unordered_set<OUString>& rNameSet)
+{
+ if (GetName().isEmpty())
+ return;
+
+ if (rNameSet.empty())
+ {
+ SdrPage* pPage;
+ SdrObject* pObj;
+ for (sal_uInt16 nPage(0); nPage < mrSdrModelFromSdrObject.GetPageCount(); ++nPage)
+ {
+ pPage = mrSdrModelFromSdrObject.GetPage(nPage);
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
+ while (aIter.IsMore())
+ {
+ pObj = aIter.Next();
+ if (pObj != this)
+ rNameSet.insert(pObj->GetName());
+ }
+ }
+ }
+
+ OUString sName(GetName().trim());
+ OUString sRootName(sName);
+
+ if (!sName.isEmpty() && rtl::isAsciiDigit(sName[sName.getLength() - 1]))
+ {
+ sal_Int32 nPos(sName.getLength() - 1);
+ while (nPos > 0 && rtl::isAsciiDigit(sName[--nPos]));
+ sRootName = o3tl::trim(sName.subView(0, nPos + 1));
+ }
+ else
+ sName += " 1";
+
+ for (sal_uInt32 n = 1; rNameSet.find(sName) != rNameSet.end(); n++)
+ sName = sRootName + " " + OUString::number(n);
+ rNameSet.insert(sName);
+
+ SetName(sName);
+}
+
+void SdrObject::ForceMetricToItemPoolMetric(basegfx::B2DPolyPolygon& rPolyPolygon) const noexcept
+{
+ MapUnit eMapUnit(getSdrModelFromSdrObject().GetItemPool().GetMetric(0));
+ if(eMapUnit == MapUnit::Map100thMM)
+ return;
+
+ if (const auto eTo = MapToO3tlLength(eMapUnit); eTo != o3tl::Length::invalid)
+ {
+ const double fConvert(o3tl::convert(1.0, o3tl::Length::mm100, eTo));
+ rPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(fConvert, fConvert));
+ }
+ else
+ {
+ OSL_FAIL("Missing unit translation to PoolMetric!");
+ }
+}
+
+SdrObject* SdrObjFactory::CreateObjectFromFactory(SdrModel& rSdrModel, SdrInventor nInventor, SdrObjKind nObjIdentifier)
+{
+ SdrObjCreatorParams aParams { nInventor, nObjIdentifier, rSdrModel };
+ for (const auto & i : ImpGetUserMakeObjHdl()) {
+ SdrObject* pObj = i.Call(aParams);
+ if (pObj) {
+ return pObj;
+ }
+ }
+ return nullptr;
+}
+
+SdrObject* SdrObjFactory::MakeNewObject(
+ SdrModel& rSdrModel,
+ SdrInventor nInventor,
+ SdrObjKind nIdentifier,
+ const tools::Rectangle* pSnapRect)
+{
+ SdrObject* pObj(nullptr);
+ bool bSetSnapRect(nullptr != pSnapRect);
+
+ if (nInventor == SdrInventor::Default)
+ {
+ switch (nIdentifier)
+ {
+ case SdrObjKind::Measure:
+ {
+ if(nullptr != pSnapRect)
+ {
+ pObj = new SdrMeasureObj(
+ rSdrModel,
+ pSnapRect->TopLeft(),
+ pSnapRect->BottomRight());
+ }
+ else
+ {
+ pObj = new SdrMeasureObj(rSdrModel);
+ }
+ }
+ break;
+ case SdrObjKind::Line:
+ {
+ if(nullptr != pSnapRect)
+ {
+ basegfx::B2DPolygon aPoly;
+
+ aPoly.append(
+ basegfx::B2DPoint(
+ pSnapRect->Left(),
+ pSnapRect->Top()));
+ aPoly.append(
+ basegfx::B2DPoint(
+ pSnapRect->Right(),
+ pSnapRect->Bottom()));
+ pObj = new SdrPathObj(
+ rSdrModel,
+ SdrObjKind::Line,
+ basegfx::B2DPolyPolygon(aPoly));
+ }
+ else
+ {
+ pObj = new SdrPathObj(
+ rSdrModel,
+ SdrObjKind::Line);
+ }
+ }
+ break;
+ case SdrObjKind::Text:
+ case SdrObjKind::TitleText:
+ case SdrObjKind::OutlineText:
+ {
+ if(nullptr != pSnapRect)
+ {
+ pObj = new SdrRectObj(
+ rSdrModel,
+ nIdentifier,
+ *pSnapRect);
+ bSetSnapRect = false;
+ }
+ else
+ {
+ pObj = new SdrRectObj(
+ rSdrModel,
+ nIdentifier);
+ }
+ }
+ break;
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::CircleSection:
+ case SdrObjKind::CircleArc:
+ case SdrObjKind::CircleCut:
+ {
+ SdrCircKind eCircKind = ToSdrCircKind(nIdentifier);
+ if(nullptr != pSnapRect)
+ {
+ pObj = new SdrCircObj(rSdrModel, eCircKind, *pSnapRect);
+ bSetSnapRect = false;
+ }
+ else
+ {
+ pObj = new SdrCircObj(rSdrModel, eCircKind);
+ }
+ }
+ break;
+ case SdrObjKind::NONE : pObj=new SdrObject(rSdrModel); break;
+ case SdrObjKind::Group : pObj=new SdrObjGroup(rSdrModel); break;
+ case SdrObjKind::Polygon : pObj=new SdrPathObj(rSdrModel, SdrObjKind::Polygon ); break;
+ case SdrObjKind::PolyLine : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PolyLine ); break;
+ case SdrObjKind::PathLine : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PathLine ); break;
+ case SdrObjKind::PathFill : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PathFill ); break;
+ case SdrObjKind::FreehandLine : pObj=new SdrPathObj(rSdrModel, SdrObjKind::FreehandLine ); break;
+ case SdrObjKind::FreehandFill : pObj=new SdrPathObj(rSdrModel, SdrObjKind::FreehandFill ); break;
+ case SdrObjKind::PathPoly : pObj=new SdrPathObj(rSdrModel, SdrObjKind::Polygon ); break;
+ case SdrObjKind::PathPolyLine : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PolyLine ); break;
+ case SdrObjKind::Edge : pObj=new SdrEdgeObj(rSdrModel); break;
+ case SdrObjKind::Rectangle : pObj=new SdrRectObj(rSdrModel); break;
+ case SdrObjKind::Graphic : pObj=new SdrGrafObj(rSdrModel); break;
+ case SdrObjKind::OLE2 : pObj=new SdrOle2Obj(rSdrModel); break;
+ case SdrObjKind::OLEPluginFrame : pObj=new SdrOle2Obj(rSdrModel, true); break;
+ case SdrObjKind::Caption : pObj=new SdrCaptionObj(rSdrModel); break;
+ case SdrObjKind::Page : pObj=new SdrPageObj(rSdrModel); break;
+ case SdrObjKind::UNO : pObj=new SdrUnoObj(rSdrModel, OUString()); break;
+ case SdrObjKind::CustomShape: pObj=new SdrObjCustomShape(rSdrModel); break;
+#if HAVE_FEATURE_AVMEDIA
+ case SdrObjKind::Media : pObj=new SdrMediaObj(rSdrModel); break;
+#endif
+ case SdrObjKind::Table : pObj=new sdr::table::SdrTableObj(rSdrModel); break;
+ default: break;
+ }
+ }
+
+ if (!pObj)
+ {
+ pObj = CreateObjectFromFactory(rSdrModel, nInventor, nIdentifier);
+ }
+
+ if (!pObj)
+ {
+ // Well, if no one wants it...
+ return nullptr;
+ }
+
+ if(bSetSnapRect && nullptr != pSnapRect)
+ {
+ pObj->SetSnapRect(*pSnapRect);
+ }
+
+ return pObj;
+}
+
+void SdrObjFactory::InsertMakeObjectHdl(Link<SdrObjCreatorParams, SdrObject*> const & rLink)
+{
+ std::vector<Link<SdrObjCreatorParams, SdrObject*>>& rLL=ImpGetUserMakeObjHdl();
+ auto it = std::find(rLL.begin(), rLL.end(), rLink);
+ if (it != rLL.end()) {
+ OSL_FAIL("SdrObjFactory::InsertMakeObjectHdl(): Link already in place.");
+ } else {
+ rLL.push_back(rLink);
+ }
+}
+
+void SdrObjFactory::RemoveMakeObjectHdl(Link<SdrObjCreatorParams, SdrObject*> const & rLink)
+{
+ std::vector<Link<SdrObjCreatorParams, SdrObject*>>& rLL=ImpGetUserMakeObjHdl();
+ auto it = std::find(rLL.begin(), rLL.end(), rLink);
+ if (it != rLL.end())
+ rLL.erase(it);
+}
+
+namespace svx
+{
+ ISdrObjectFilter::~ISdrObjectFilter()
+ {
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdobjplusdata.cxx b/svx/source/svdraw/svdobjplusdata.cxx
new file mode 100644
index 000000000..af27c5629
--- /dev/null
+++ b/svx/source/svdraw/svdobjplusdata.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+* This file is part of the LibreOffice project.
+*
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/.
+*/
+
+#include <svdobjplusdata.hxx>
+#include <svdobjuserdatalist.hxx>
+#include <o3tl/deleter.hxx>
+#include <svx/svdglue.hxx>
+#include <svl/SfxBroadcaster.hxx>
+#include <osl/diagnose.h>
+
+SdrObjPlusData::SdrObjPlusData()
+{
+}
+
+SdrObjPlusData::~SdrObjPlusData()
+{
+ o3tl::reset_preserve_ptr_during(pBroadcast);
+ pUserDataList.reset();
+ pGluePoints.reset();
+}
+
+SdrObjPlusData* SdrObjPlusData::Clone(SdrObject* pObj1) const
+{
+ SdrObjPlusData* pNewPlusData=new SdrObjPlusData;
+ if (pUserDataList!=nullptr) {
+ sal_uInt16 nCount=pUserDataList->GetUserDataCount();
+ if (nCount!=0) {
+ pNewPlusData->pUserDataList.reset(new SdrObjUserDataList);
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ std::unique_ptr<SdrObjUserData> pNewUserData=pUserDataList->GetUserData(i).Clone(pObj1);
+ if (pNewUserData!=nullptr) {
+ pNewPlusData->pUserDataList->AppendUserData(std::move(pNewUserData));
+ } else {
+ OSL_FAIL("SdrObjPlusData::Clone(): UserData.Clone() returns NULL.");
+ }
+ }
+ }
+ }
+ if (pGluePoints!=nullptr) pNewPlusData->pGluePoints.reset(new SdrGluePointList(*pGluePoints));
+ // MtfAnimator isn't copied either
+
+ // #i68101#
+ // copy object name, title and description
+ pNewPlusData->aObjName = aObjName;
+ pNewPlusData->aObjTitle = aObjTitle;
+ pNewPlusData->aObjDescription = aObjDescription;
+
+ return pNewPlusData;
+}
+
+void SdrObjPlusData::SetGluePoints(const SdrGluePointList& rPts)
+{
+ *pGluePoints = rPts;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdobjuserdatalist.cxx b/svx/source/svdraw/svdobjuserdatalist.cxx
new file mode 100644
index 000000000..cae5e8db6
--- /dev/null
+++ b/svx/source/svdraw/svdobjuserdatalist.cxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+* This file is part of the LibreOffice project.
+*
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/.
+*/
+
+#include <memory>
+#include <svdobjuserdatalist.hxx>
+
+SdrObjUserDataList::SdrObjUserDataList() {}
+SdrObjUserDataList::~SdrObjUserDataList() {}
+
+size_t SdrObjUserDataList::GetUserDataCount() const
+{
+ return maList.size();
+}
+
+SdrObjUserData& SdrObjUserDataList::GetUserData(size_t nNum)
+{
+ return *maList.at(nNum);
+}
+
+void SdrObjUserDataList::AppendUserData(std::unique_ptr<SdrObjUserData> pData)
+{
+ maList.push_back(std::move(pData));
+}
+
+void SdrObjUserDataList::DeleteUserData(size_t nNum)
+{
+ maList.erase(maList.begin()+nNum);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdocapt.cxx b/svx/source/svdraw/svdocapt.cxx
new file mode 100644
index 000000000..4734ea222
--- /dev/null
+++ b/svx/source/svdraw/svdocapt.cxx
@@ -0,0 +1,756 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/tuple/b2dtuple.hxx>
+#include <tools/bigint.hxx>
+#include <tools/helpers.hxx>
+
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+#include <sdr/contact/viewcontactofsdrcaptionobj.hxx>
+#include <sdr/properties/captionproperties.hxx>
+#include <svx/sdrhittesthelper.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sxcecitm.hxx>
+#include <svx/sxcgitm.hxx>
+#include <svx/sxcllitm.hxx>
+#include <svx/sxctitm.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/ptrstyle.hxx>
+
+namespace {
+
+enum EscDir {LKS,RTS,OBN,UNT};
+
+}
+
+class ImpCaptParams
+{
+public:
+ SdrCaptionType eType;
+ tools::Long nGap;
+ tools::Long nEscRel;
+ tools::Long nEscAbs;
+ tools::Long nLineLen;
+ SdrCaptionEscDir eEscDir;
+ bool bFitLineLen;
+ bool bEscRel;
+ bool bFixedAngle;
+
+public:
+ ImpCaptParams()
+ : eType(SdrCaptionType::Type3),
+ nGap(0), nEscRel(5000), nEscAbs(0),
+ nLineLen(0), eEscDir(SdrCaptionEscDir::Horizontal),
+ bFitLineLen(true), bEscRel(true), bFixedAngle(false)
+ {
+ }
+ void CalcEscPos(const Point& rTail, const tools::Rectangle& rRect, Point& rPt, EscDir& rDir) const;
+};
+
+void ImpCaptParams::CalcEscPos(const Point& rTailPt, const tools::Rectangle& rRect, Point& rPt, EscDir& rDir) const
+{
+ Point aTl(rTailPt); // copy locally for performance reasons
+ tools::Long nX,nY;
+ if (bEscRel) {
+ nX=rRect.Right()-rRect.Left();
+ nX=BigMulDiv(nX,nEscRel,10000);
+ nY=rRect.Bottom()-rRect.Top();
+ nY=BigMulDiv(nY,nEscRel,10000);
+ } else {
+ nX=nEscAbs;
+ nY=nEscAbs;
+ }
+ nX+=rRect.Left();
+ nY+=rRect.Top();
+ Point aBestPt;
+ EscDir eBestDir=LKS;
+ bool bTryH=eEscDir==SdrCaptionEscDir::BestFit;
+ if (!bTryH) {
+ if (eType!=SdrCaptionType::Type1) {
+ bTryH=eEscDir==SdrCaptionEscDir::Horizontal;
+ } else {
+ bTryH=eEscDir==SdrCaptionEscDir::Vertical;
+ }
+ }
+ bool bTryV=eEscDir==SdrCaptionEscDir::BestFit;
+ if (!bTryV) {
+ if (eType!=SdrCaptionType::Type1) {
+ bTryV=eEscDir==SdrCaptionEscDir::Vertical;
+ } else {
+ bTryV=eEscDir==SdrCaptionEscDir::Horizontal;
+ }
+ }
+
+ if (bTryH) {
+ Point aLft(rRect.Left()-nGap,nY);
+ Point aRgt(rRect.Right()+nGap,nY);
+ bool bLft=(aTl.X()-aLft.X()<aRgt.X()-aTl.X());
+ if (bLft) {
+ eBestDir=LKS;
+ aBestPt=aLft;
+ } else {
+ eBestDir=RTS;
+ aBestPt=aRgt;
+ }
+ }
+ if (bTryV) {
+ Point aTop(nX,rRect.Top()-nGap);
+ Point aBtm(nX,rRect.Bottom()+nGap);
+ bool bTop=(aTl.Y()-aTop.Y()<aBtm.Y()-aTl.Y());
+ Point aBest2;
+ EscDir eBest2;
+ if (bTop) {
+ eBest2=OBN;
+ aBest2=aTop;
+ } else {
+ eBest2=UNT;
+ aBest2=aBtm;
+ }
+ bool bTakeIt=eEscDir!=SdrCaptionEscDir::BestFit;
+ if (!bTakeIt) {
+ BigInt aHorX(aBestPt.X()-aTl.X()); aHorX*=aHorX;
+ BigInt aHorY(aBestPt.Y()-aTl.Y()); aHorY*=aHorY;
+ BigInt aVerX(aBest2.X()-aTl.X()); aVerX*=aVerX;
+ BigInt aVerY(aBest2.Y()-aTl.Y()); aVerY*=aVerY;
+ if (eType!=SdrCaptionType::Type1) {
+ bTakeIt=aVerX+aVerY<aHorX+aHorY;
+ } else {
+ bTakeIt=aVerX+aVerY>=aHorX+aHorY;
+ }
+ }
+ if (bTakeIt) {
+ aBestPt=aBest2;
+ eBestDir=eBest2;
+ }
+ }
+ rPt=aBestPt;
+ rDir=eBestDir;
+}
+
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrCaptionObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::CaptionProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrCaptionObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrCaptionObj>(*this);
+}
+
+
+SdrCaptionObj::SdrCaptionObj(SdrModel& rSdrModel)
+: SdrRectObj(rSdrModel, SdrObjKind::Text),
+ aTailPoly(3), // default size: 3 points = 2 lines
+ mbSpecialTextBoxShadow(false),
+ mbFixedTail(false),
+ mbSuppressGetBitmap(false)
+{
+}
+
+SdrCaptionObj::SdrCaptionObj(SdrModel& rSdrModel, SdrCaptionObj const & rSource)
+: SdrRectObj(rSdrModel, rSource),
+ mbSuppressGetBitmap(false)
+{
+ aTailPoly = rSource.aTailPoly;
+ mbSpecialTextBoxShadow = rSource.mbSpecialTextBoxShadow;
+ mbFixedTail = rSource.mbFixedTail;
+ maFixedTailPos = rSource.maFixedTailPos;
+}
+
+SdrCaptionObj::SdrCaptionObj(
+ SdrModel& rSdrModel,
+ const tools::Rectangle& rRect,
+ const Point& rTail)
+: SdrRectObj(rSdrModel, SdrObjKind::Text,rRect),
+ aTailPoly(3), // default size: 3 points = 2 lines
+ mbSpecialTextBoxShadow(false),
+ mbFixedTail(false),
+ mbSuppressGetBitmap(false)
+{
+ aTailPoly[0]=maFixedTailPos=rTail;
+}
+
+SdrCaptionObj::~SdrCaptionObj()
+{
+}
+
+void SdrCaptionObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bRotateFreeAllowed=false;
+ rInfo.bRotate90Allowed =false;
+ rInfo.bMirrorFreeAllowed=false;
+ rInfo.bMirror45Allowed =false;
+ rInfo.bMirror90Allowed =false;
+ rInfo.bTransparenceAllowed = false;
+ rInfo.bShearAllowed =false;
+ rInfo.bEdgeRadiusAllowed=false;
+ rInfo.bCanConvToPath =true;
+ rInfo.bCanConvToPoly =true;
+ rInfo.bCanConvToPathLineToArea=false;
+ rInfo.bCanConvToPolyLineToArea=false;
+ rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
+}
+
+SdrObjKind SdrCaptionObj::GetObjIdentifier() const
+{
+ return SdrObjKind::Caption;
+}
+
+SdrCaptionObj* SdrCaptionObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrCaptionObj(rTargetModel, *this);
+}
+
+OUString SdrCaptionObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulCAPTION));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+OUString SdrCaptionObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralCAPTION);
+}
+
+basegfx::B2DPolyPolygon SdrCaptionObj::TakeXorPoly() const
+{
+ basegfx::B2DPolyPolygon aPolyPoly(SdrRectObj::TakeXorPoly());
+ aPolyPoly.append(aTailPoly.getB2DPolygon());
+
+ return aPolyPoly;
+}
+
+sal_uInt32 SdrCaptionObj::GetHdlCount() const
+{
+ sal_uInt32 nCount1(SdrRectObj::GetHdlCount());
+ // Currently only dragging the tail's end is implemented.
+ return nCount1 + 1;
+}
+
+void SdrCaptionObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ SdrRectObj::AddToHdlList(rHdlList);
+ // Currently only dragging the tail's end is implemented.
+ std::unique_ptr<SdrHdl> pHdl(new SdrHdl(aTailPoly.GetPoint(0), SdrHdlKind::Poly));
+ pHdl->SetPolyNum(1);
+ pHdl->SetPointNum(0);
+ rHdlList.AddHdl(std::move(pHdl));
+}
+
+bool SdrCaptionObj::hasSpecialDrag() const
+{
+ return true;
+}
+
+bool SdrCaptionObj::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ const SdrHdl* pHdl = rDrag.GetHdl();
+ rDrag.SetEndDragChangesAttributes(true);
+ rDrag.SetEndDragChangesGeoAndAttributes(true);
+
+ if(pHdl && 0 == pHdl->GetPolyNum())
+ {
+ return SdrRectObj::beginSpecialDrag(rDrag);
+ }
+ else
+ {
+ rDrag.SetOrtho8Possible();
+
+ if(!pHdl)
+ {
+ if (m_bMovProt)
+ return false;
+
+ rDrag.SetNoSnap();
+ rDrag.SetActionRect(maRect);
+
+ Point aHit(rDrag.GetStart());
+
+ if(rDrag.GetPageView() && SdrObjectPrimitiveHit(*this, aHit, 0, *rDrag.GetPageView(), nullptr, false))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if((1 == pHdl->GetPolyNum()) && (0 == pHdl->GetPointNum()))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool SdrCaptionObj::applySpecialDrag(SdrDragStat& rDrag)
+{
+ const SdrHdl* pHdl = rDrag.GetHdl();
+
+ if(pHdl && 0 == pHdl->GetPolyNum())
+ {
+ const bool bRet(SdrRectObj::applySpecialDrag(rDrag));
+ ImpRecalcTail();
+ ActionChanged();
+
+ return bRet;
+ }
+ else
+ {
+ Point aDelt(rDrag.GetNow()-rDrag.GetStart());
+
+ if(!pHdl)
+ {
+ maRect.Move(aDelt.X(),aDelt.Y());
+ }
+ else
+ {
+ aTailPoly[0] += aDelt;
+ }
+
+ ImpRecalcTail();
+ ActionChanged();
+
+ return true;
+ }
+}
+
+OUString SdrCaptionObj::getSpecialDragComment(const SdrDragStat& rDrag) const
+{
+ const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
+
+ if(bCreateComment)
+ {
+ return OUString();
+ }
+ else
+ {
+ const SdrHdl* pHdl = rDrag.GetHdl();
+
+ if(pHdl && 0 == pHdl->GetPolyNum())
+ {
+ return SdrRectObj::getSpecialDragComment(rDrag);
+ }
+ else
+ {
+ if(!pHdl)
+ {
+ return ImpGetDescriptionStr(STR_DragCaptFram);
+ }
+ else
+ {
+ return ImpGetDescriptionStr(STR_DragCaptTail);
+ }
+ }
+ }
+}
+
+
+void SdrCaptionObj::ImpGetCaptParams(ImpCaptParams& rPara) const
+{
+ const SfxItemSet& rSet = GetObjectItemSet();
+ rPara.eType =rSet.Get(SDRATTR_CAPTIONTYPE ).GetValue();
+ rPara.bFixedAngle=rSet.Get(SDRATTR_CAPTIONFIXEDANGLE).GetValue();
+ rPara.nGap =static_cast<const SdrCaptionGapItem&> (rSet.Get(SDRATTR_CAPTIONGAP )).GetValue();
+ rPara.eEscDir =rSet.Get(SDRATTR_CAPTIONESCDIR ).GetValue();
+ rPara.bEscRel =rSet.Get(SDRATTR_CAPTIONESCISREL ).GetValue();
+ rPara.nEscRel =rSet.Get(SDRATTR_CAPTIONESCREL ).GetValue();
+ rPara.nEscAbs =rSet.Get(SDRATTR_CAPTIONESCABS ).GetValue();
+ rPara.nLineLen =rSet.Get(SDRATTR_CAPTIONLINELEN ).GetValue();
+ rPara.bFitLineLen=rSet.Get(SDRATTR_CAPTIONFITLINELEN).GetValue();
+}
+
+void SdrCaptionObj::ImpRecalcTail()
+{
+ ImpCaptParams aPara;
+ ImpGetCaptParams(aPara);
+ ImpCalcTail(aPara, aTailPoly, maRect);
+ SetBoundAndSnapRectsDirty();
+ SetXPolyDirty();
+}
+
+// #i35971#
+// SdrCaptionObj::ImpCalcTail1 does move the object(!). What a hack.
+// I really wonder why this had not triggered problems before. I am
+// sure there are some places where SetTailPos() is called at least
+// twice or SetSnapRect after it again just to work around this.
+// Changed this method to not do that.
+// Also found why this has been done: For interactive dragging of the
+// tail end pos for SdrCaptionType::Type1. This sure was the simplest method
+// to achieve this, at the cost of making a whole group of const methods
+// of this object implicitly change the object's position.
+void SdrCaptionObj::ImpCalcTail1(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
+{
+ tools::Polygon aPol(2);
+ Point aTl(rPoly[0]);
+
+ aPol[0] = aTl;
+ aPol[1] = aTl;
+
+ EscDir eEscDir;
+ Point aEscPos;
+
+ rPara.CalcEscPos(aTl, rRect, aEscPos, eEscDir);
+ aPol[1] = aEscPos;
+
+ if(eEscDir==LKS || eEscDir==RTS)
+ {
+ aPol[0].setX( aEscPos.X() );
+ }
+ else
+ {
+ aPol[0].setY( aEscPos.Y() );
+ }
+
+ rPoly = aPol;
+}
+
+void SdrCaptionObj::ImpCalcTail2(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
+{ // Gap/EscDir/EscPos/Angle
+ tools::Polygon aPol(2);
+ Point aTl(rPoly[0]);
+ aPol[0]=aTl;
+
+ EscDir eEscDir;
+ Point aEscPos;
+ rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
+ aPol[1]=aEscPos;
+
+ if (!rPara.bFixedAngle) {
+ // TODO: Implementation missing.
+ }
+ rPoly=aPol;
+}
+
+void SdrCaptionObj::ImpCalcTail3(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
+{ // Gap/EscDir/EscPos/Angle/LineLen
+ tools::Polygon aPol(3);
+ Point aTl(rPoly[0]);
+ aPol[0]=aTl;
+
+ EscDir eEscDir;
+ Point aEscPos;
+ rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
+ aPol[1]=aEscPos;
+ aPol[2]=aEscPos;
+
+ if (eEscDir==LKS || eEscDir==RTS) {
+ if (rPara.bFitLineLen) {
+ aPol[1].setX((aTl.X()+aEscPos.X())/2 );
+ } else {
+ if (eEscDir==LKS) aPol[1].AdjustX( -(rPara.nLineLen) );
+ else aPol[1].AdjustX(rPara.nLineLen );
+ }
+ } else {
+ if (rPara.bFitLineLen) {
+ aPol[1].setY((aTl.Y()+aEscPos.Y())/2 );
+ } else {
+ if (eEscDir==OBN) aPol[1].AdjustY( -(rPara.nLineLen) );
+ else aPol[1].AdjustY(rPara.nLineLen );
+ }
+ }
+ if (!rPara.bFixedAngle) {
+ // TODO: Implementation missing.
+ }
+ rPoly=aPol;
+}
+
+void SdrCaptionObj::ImpCalcTail(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
+{
+ switch (rPara.eType) {
+ case SdrCaptionType::Type1: ImpCalcTail1(rPara,rPoly,rRect); break;
+ case SdrCaptionType::Type2: ImpCalcTail2(rPara,rPoly,rRect); break;
+ case SdrCaptionType::Type3: ImpCalcTail3(rPara,rPoly,rRect); break;
+ case SdrCaptionType::Type4: ImpCalcTail3(rPara,rPoly,rRect); break;
+ }
+}
+
+bool SdrCaptionObj::BegCreate(SdrDragStat& rStat)
+{
+ if (maRect.IsEmpty()) return false; // Create currently only works with the given Rect
+
+ ImpCaptParams aPara;
+ ImpGetCaptParams(aPara);
+ maRect.SetPos(rStat.GetNow());
+ aTailPoly[0]=rStat.GetStart();
+ ImpCalcTail(aPara,aTailPoly,maRect);
+ rStat.SetActionRect(maRect);
+ return true;
+}
+
+bool SdrCaptionObj::MovCreate(SdrDragStat& rStat)
+{
+ ImpCaptParams aPara;
+ ImpGetCaptParams(aPara);
+ maRect.SetPos(rStat.GetNow());
+ ImpCalcTail(aPara,aTailPoly,maRect);
+ rStat.SetActionRect(maRect);
+ SetBoundRectDirty();
+ m_bSnapRectDirty=true;
+ return true;
+}
+
+bool SdrCaptionObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ ImpCaptParams aPara;
+ ImpGetCaptParams(aPara);
+ maRect.SetPos(rStat.GetNow());
+ ImpCalcTail(aPara,aTailPoly,maRect);
+ SetBoundAndSnapRectsDirty();
+ return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
+}
+
+bool SdrCaptionObj::BckCreate(SdrDragStat& /*rStat*/)
+{
+ return false;
+}
+
+void SdrCaptionObj::BrkCreate(SdrDragStat& /*rStat*/)
+{
+}
+
+basegfx::B2DPolyPolygon SdrCaptionObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
+{
+ basegfx::B2DPolyPolygon aRetval;
+ const basegfx::B2DRange aRange =vcl::unotools::b2DRectangleFromRectangle(maRect);
+ aRetval.append(basegfx::utils::createPolygonFromRect(aRange));
+ aRetval.append(aTailPoly.getB2DPolygon());
+ return aRetval;
+}
+
+PointerStyle SdrCaptionObj::GetCreatePointer() const
+{
+ return PointerStyle::DrawCaption;
+}
+
+void SdrCaptionObj::NbcMove(const Size& rSiz)
+{
+ SdrRectObj::NbcMove(rSiz);
+ MovePoly(aTailPoly,rSiz);
+ if(mbFixedTail)
+ SetTailPos(GetFixedTailPos());
+}
+
+void SdrCaptionObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ SdrRectObj::NbcResize(rRef,xFact,yFact);
+ ResizePoly(aTailPoly,rRef,xFact,yFact);
+ ImpRecalcTail();
+ if(mbFixedTail)
+ SetTailPos(GetFixedTailPos());
+}
+
+void SdrCaptionObj::NbcSetRelativePos(const Point& rPnt)
+{
+ Point aRelPos0(aTailPoly.GetPoint(0)-m_aAnchor);
+ Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
+ NbcMove(aSiz); // This also calls SetRectsDirty()
+}
+
+Point SdrCaptionObj::GetRelativePos() const
+{
+ return aTailPoly.GetPoint(0)-m_aAnchor;
+}
+
+const tools::Rectangle& SdrCaptionObj::GetLogicRect() const
+{
+ return maRect;
+}
+
+void SdrCaptionObj::NbcSetLogicRect(const tools::Rectangle& rRect)
+{
+ SdrRectObj::NbcSetLogicRect(rRect);
+ ImpRecalcTail();
+}
+
+const Point& SdrCaptionObj::GetTailPos() const
+{
+ return aTailPoly[0];
+}
+
+void SdrCaptionObj::SetTailPos(const Point& rPos)
+{
+ if (aTailPoly.GetSize()==0 || aTailPoly[0]!=rPos) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcSetTailPos(rPos);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+}
+
+void SdrCaptionObj::NbcSetTailPos(const Point& rPos)
+{
+ aTailPoly[0]=rPos;
+ ImpRecalcTail();
+}
+
+sal_uInt32 SdrCaptionObj::GetSnapPointCount() const
+{
+ // TODO: Implementation missing.
+ return 0;
+}
+
+Point SdrCaptionObj::GetSnapPoint(sal_uInt32 /*i*/) const
+{
+ // TODO: Implementation missing.
+ return Point(0,0);
+}
+
+void SdrCaptionObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ SdrRectObj::Notify(rBC,rHint);
+ ImpRecalcTail();
+}
+
+std::unique_ptr<SdrObjGeoData> SdrCaptionObj::NewGeoData() const
+{
+ return std::make_unique<SdrCaptObjGeoData>();
+}
+
+void SdrCaptionObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrRectObj::SaveGeoData(rGeo);
+ SdrCaptObjGeoData& rCGeo=static_cast<SdrCaptObjGeoData&>(rGeo);
+ rCGeo.aTailPoly=aTailPoly;
+}
+
+void SdrCaptionObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrRectObj::RestoreGeoData(rGeo);
+ const SdrCaptObjGeoData& rCGeo=static_cast<const SdrCaptObjGeoData&>(rGeo);
+ aTailPoly=rCGeo.aTailPoly;
+}
+
+SdrObjectUniquePtr SdrCaptionObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ SdrObjectUniquePtr pRect = SdrRectObj::DoConvertToPolyObj(bBezier, bAddText);
+ SdrObjectUniquePtr pTail = ImpConvertMakeObj(basegfx::B2DPolyPolygon(aTailPoly.getB2DPolygon()), false, bBezier);
+ SdrObjectUniquePtr pRet;
+ if (pTail && !pRect)
+ pRet = std::move(pTail);
+ else if (pRect && !pTail)
+ pRet = std::move(pRect);
+ else if (pTail && pRect)
+ {
+ if (pTail->GetSubList())
+ {
+ pTail->GetSubList()->NbcInsertObject(pRect.release());
+ pRet = std::move(pTail);
+ }
+ else if (pRect->GetSubList())
+ {
+ pRect->GetSubList()->NbcInsertObject(pTail.release(),0);
+ pRet = std::move(pRect);
+ }
+ else
+ {
+ SdrObjGroup* pGrp = new SdrObjGroup(getSdrModelFromSdrObject());
+ pGrp->GetSubList()->NbcInsertObject(pRect.release());
+ pGrp->GetSubList()->NbcInsertObject(pTail.release(),0);
+ pRet.reset(pGrp);
+ }
+ }
+ return pRet;
+}
+
+namespace {
+
+void handleNegativeScale(basegfx::B2DTuple & scale, double * rotate) {
+ assert(rotate != nullptr);
+
+ // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
+ // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
+ if(basegfx::fTools::less(scale.getX(), 0.0) && basegfx::fTools::less(scale.getY(), 0.0))
+ {
+ scale.setX(fabs(scale.getX()));
+ scale.setY(fabs(scale.getY()));
+ *rotate = fmod(*rotate + M_PI, 2 * M_PI);
+ }
+}
+
+}
+
+// #i32599#
+// Add own implementation for TRSetBaseGeometry to handle TailPos over changes.
+void SdrCaptionObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
+{
+ // break up matrix
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate, fShearX;
+ rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ handleNegativeScale(aScale, &fRotate);
+
+ // if anchor is used, make position relative to it
+ if(getSdrModelFromSdrObject().IsWriter())
+ {
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // build BaseRect
+ Point aPoint(FRound(aTranslate.getX()), FRound(aTranslate.getY()));
+ tools::Rectangle aBaseRect(aPoint, Size(FRound(aScale.getX()), FRound(aScale.getY())));
+
+ // set BaseRect, but rescue TailPos over this call
+ const Point aTailPoint = GetTailPos();
+ SetSnapRect(aBaseRect);
+ SetTailPos(aTailPoint);
+ ImpRecalcTail();
+}
+
+// geometry access
+basegfx::B2DPolygon SdrCaptionObj::getTailPolygon() const
+{
+ return aTailPoly.getB2DPolygon();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdocirc.cxx b/svx/source/svdraw/svdocirc.cxx
new file mode 100644
index 000000000..0204b2c2e
--- /dev/null
+++ b/svx/source/svdraw/svdocirc.cxx
@@ -0,0 +1,1154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <math.h>
+#include <rtl/ustrbuf.hxx>
+
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+#include <sdr/contact/viewcontactofsdrcircobj.hxx>
+#include <sdr/properties/circleproperties.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sxciaitm.hxx>
+#include <sxcikitm.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/ptrstyle.hxx>
+
+using namespace com::sun::star;
+
+static Point GetAnglePnt(const tools::Rectangle& rR, Degree100 nAngle)
+{
+ Point aCenter(rR.Center());
+ tools::Long nWdt=rR.Right()-rR.Left();
+ tools::Long nHgt=rR.Bottom()-rR.Top();
+ tools::Long nMaxRad=(std::max(nWdt,nHgt)+1) /2;
+ double a = toRadians(nAngle);
+ Point aRetval(FRound(cos(a)*nMaxRad),-FRound(sin(a)*nMaxRad));
+ if (nWdt==0) aRetval.setX(0 );
+ if (nHgt==0) aRetval.setY(0 );
+ if (nWdt!=nHgt) {
+ if (nWdt>nHgt) {
+ if (nWdt!=0) {
+ // stop possible overruns for very large objects
+ if (std::abs(nHgt)>32767 || std::abs(aRetval.Y())>32767) {
+ aRetval.setY(BigMulDiv(aRetval.Y(),nHgt,nWdt) );
+ } else {
+ aRetval.setY(aRetval.Y()*nHgt/nWdt );
+ }
+ }
+ } else {
+ if (nHgt!=0) {
+ // stop possible overruns for very large objects
+ if (std::abs(nWdt)>32767 || std::abs(aRetval.X())>32767) {
+ aRetval.setX(BigMulDiv(aRetval.X(),nWdt,nHgt) );
+ } else {
+ aRetval.setX(aRetval.X()*nWdt/nHgt );
+ }
+ }
+ }
+ }
+ aRetval+=aCenter;
+ return aRetval;
+}
+
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrCircObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::CircleProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrCircObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrCircObj>(*this);
+}
+
+SdrCircKind ToSdrCircKind(SdrObjKind eKind)
+{
+ switch (eKind)
+ {
+ case SdrObjKind::CircleOrEllipse: return SdrCircKind::Full;
+ case SdrObjKind::CircleSection: return SdrCircKind::Section;
+ case SdrObjKind::CircleArc: return SdrCircKind::Arc;
+ case SdrObjKind::CircleCut: return SdrCircKind::Cut;
+ default: assert(false);
+ }
+ return SdrCircKind::Full;
+}
+
+SdrCircObj::SdrCircObj(
+ SdrModel& rSdrModel,
+ SdrCircKind eNewKind)
+: SdrRectObj(rSdrModel)
+{
+ nStartAngle=0_deg100;
+ nEndAngle=36000_deg100;
+ meCircleKind=eNewKind;
+ m_bClosedObj=eNewKind!=SdrCircKind::Arc;
+}
+
+SdrCircObj::SdrCircObj(SdrModel& rSdrModel, SdrCircObj const & rSource)
+: SdrRectObj(rSdrModel, rSource)
+{
+ meCircleKind = rSource.meCircleKind;
+ nStartAngle = rSource.nStartAngle;
+ nEndAngle = rSource.nEndAngle;
+ m_bClosedObj = rSource.m_bClosedObj;
+}
+
+SdrCircObj::SdrCircObj(
+ SdrModel& rSdrModel,
+ SdrCircKind eNewKind,
+ const tools::Rectangle& rRect)
+: SdrRectObj(rSdrModel, rRect)
+{
+ nStartAngle=0_deg100;
+ nEndAngle=36000_deg100;
+ meCircleKind=eNewKind;
+ m_bClosedObj=eNewKind!=SdrCircKind::Arc;
+}
+
+SdrCircObj::SdrCircObj(
+ SdrModel& rSdrModel,
+ SdrCircKind eNewKind,
+ const tools::Rectangle& rRect,
+ Degree100 nNewStartAngle,
+ Degree100 nNewEndAngle)
+: SdrRectObj(rSdrModel, rRect)
+{
+ Degree100 nAngleDif=nNewEndAngle-nNewStartAngle;
+ nStartAngle=NormAngle36000(nNewStartAngle);
+ nEndAngle=NormAngle36000(nNewEndAngle);
+ if (nAngleDif==36000_deg100) nEndAngle+=nAngleDif; // full circle
+ meCircleKind=eNewKind;
+ m_bClosedObj=eNewKind!=SdrCircKind::Arc;
+}
+
+SdrCircObj::~SdrCircObj()
+{
+}
+
+void SdrCircObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ bool bCanConv=!HasText() || ImpCanConvTextToCurve();
+ rInfo.bEdgeRadiusAllowed = false;
+ rInfo.bCanConvToPath=bCanConv;
+ rInfo.bCanConvToPoly=bCanConv;
+ rInfo.bCanConvToContour = !IsFontwork() && (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
+}
+
+SdrObjKind SdrCircObj::GetObjIdentifier() const
+{
+ switch (meCircleKind)
+ {
+ case SdrCircKind::Full: return SdrObjKind::CircleOrEllipse;
+ case SdrCircKind::Section: return SdrObjKind::CircleSection;
+ case SdrCircKind::Cut: return SdrObjKind::CircleCut;
+ case SdrCircKind::Arc: return SdrObjKind::CircleArc;
+ default: assert(false);
+ }
+ return SdrObjKind::CircleOrEllipse;
+}
+
+bool SdrCircObj::PaintNeedsXPolyCirc() const
+{
+ // XPoly is necessary for all rotated ellipse objects, circle and
+ // ellipse segments.
+ // If not WIN, then (for now) also for circle/ellipse segments and circle/
+ // ellipse arcs (for precision)
+ bool bNeed = maGeo.nRotationAngle || maGeo.nShearAngle || meCircleKind == SdrCircKind::Cut;
+ // If not WIN, then for everything except full circle (for now!)
+ if (meCircleKind!=SdrCircKind::Full) bNeed = true;
+
+ const SfxItemSet& rSet = GetObjectItemSet();
+ if(!bNeed)
+ {
+ // XPoly is necessary for everything that isn't LineSolid or LineNone
+ drawing::LineStyle eLine = rSet.Get(XATTR_LINESTYLE).GetValue();
+ bNeed = eLine != drawing::LineStyle_NONE && eLine != drawing::LineStyle_SOLID;
+
+ // XPoly is necessary for thick lines
+ if(!bNeed && eLine != drawing::LineStyle_NONE)
+ bNeed = rSet.Get(XATTR_LINEWIDTH).GetValue() != 0;
+
+ // XPoly is necessary for circle arcs with line ends
+ if(!bNeed && meCircleKind == SdrCircKind::Arc)
+ {
+ // start of the line is here if StartPolygon, StartWidth!=0
+ bNeed=rSet.Get(XATTR_LINESTART).GetLineStartValue().count() != 0 &&
+ rSet.Get(XATTR_LINESTARTWIDTH).GetValue() != 0;
+
+ if(!bNeed)
+ {
+ // end of the line is here if EndPolygon, EndWidth!=0
+ bNeed = rSet.Get(XATTR_LINEEND).GetLineEndValue().count() != 0 &&
+ rSet.Get(XATTR_LINEENDWIDTH).GetValue() != 0;
+ }
+ }
+ }
+
+ // XPoly is necessary if Fill !=None and !=Solid
+ if(!bNeed && meCircleKind != SdrCircKind::Arc)
+ {
+ drawing::FillStyle eFill=rSet.Get(XATTR_FILLSTYLE).GetValue();
+ bNeed = eFill != drawing::FillStyle_NONE && eFill != drawing::FillStyle_SOLID;
+ }
+
+ if(!bNeed && meCircleKind != SdrCircKind::Full && nStartAngle == nEndAngle)
+ bNeed = true; // otherwise we're drawing a full circle
+
+ return bNeed;
+}
+
+basegfx::B2DPolygon SdrCircObj::ImpCalcXPolyCirc(const SdrCircKind eCircleKind, const tools::Rectangle& rRect1, Degree100 nStart, Degree100 nEnd) const
+{
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(rRect1);
+ basegfx::B2DPolygon aCircPolygon;
+
+ if(SdrCircKind::Full == eCircleKind)
+ {
+ // create full circle. Do not use createPolygonFromEllipse; it's necessary
+ // to get the start point to the bottom of the circle to keep compatible to
+ // old geometry creation
+ aCircPolygon = basegfx::utils::createPolygonFromUnitCircle(1);
+
+ // needs own scaling and translation from unit circle to target size (same as
+ // would be in createPolygonFromEllipse)
+ const basegfx::B2DPoint aCenter(aRange.getCenter());
+ const basegfx::B2DHomMatrix aMatrix(basegfx::utils::createScaleTranslateB2DHomMatrix(
+ aRange.getWidth() / 2.0, aRange.getHeight() / 2.0,
+ aCenter.getX(), aCenter.getY()));
+ aCircPolygon.transform(aMatrix);
+ }
+ else
+ {
+ // mirror start, end for geometry creation since model coordinate system is mirrored in Y
+ const double fStart(toRadians((36000_deg100 - nEnd) % 36000_deg100));
+ const double fEnd(toRadians((36000_deg100 - nStart) % 36000_deg100));
+
+ // create circle segment. This is not closed by default
+ aCircPolygon = basegfx::utils::createPolygonFromEllipseSegment(
+ aRange.getCenter(), aRange.getWidth() / 2.0, aRange.getHeight() / 2.0,
+ fStart, fEnd);
+
+ // check closing states
+ const bool bCloseSegment(SdrCircKind::Arc != eCircleKind);
+ const bool bCloseUsingCenter(SdrCircKind::Section == eCircleKind);
+
+ if(bCloseSegment)
+ {
+ if(bCloseUsingCenter)
+ {
+ // add center point at start (for historical reasons)
+ basegfx::B2DPolygon aSector;
+ aSector.append(aRange.getCenter());
+ aSector.append(aCircPolygon);
+ aCircPolygon = aSector;
+ }
+
+ // close
+ aCircPolygon.setClosed(true);
+ }
+ }
+
+ // #i76950#
+ if (maGeo.nShearAngle || maGeo.nRotationAngle)
+ {
+ // translate top left to (0,0)
+ const basegfx::B2DPoint aTopLeft(aRange.getMinimum());
+ basegfx::B2DHomMatrix aMatrix(basegfx::utils::createTranslateB2DHomMatrix(
+ -aTopLeft.getX(), -aTopLeft.getY()));
+
+ // shear, rotate and back to top left (if needed)
+ aMatrix = basegfx::utils::createShearXRotateTranslateB2DHomMatrix(
+ -maGeo.mfTanShearAngle,
+ maGeo.nRotationAngle ? toRadians(36000_deg100 - maGeo.nRotationAngle) : 0.0,
+ aTopLeft) * aMatrix;
+
+ // apply transformation
+ aCircPolygon.transform(aMatrix);
+ }
+
+ return aCircPolygon;
+}
+
+void SdrCircObj::RecalcXPoly()
+{
+ basegfx::B2DPolygon aPolyCirc(ImpCalcXPolyCirc(meCircleKind, maRect, nStartAngle, nEndAngle));
+ mpXPoly = XPolygon(aPolyCirc);
+}
+
+OUString SdrCircObj::TakeObjNameSingul() const
+{
+ TranslateId pID=STR_ObjNameSingulCIRC;
+ if (maRect.GetWidth() == maRect.GetHeight() && maGeo.nShearAngle==0_deg100)
+ {
+ switch (meCircleKind) {
+ case SdrCircKind::Full: pID=STR_ObjNameSingulCIRC; break;
+ case SdrCircKind::Section: pID=STR_ObjNameSingulSECT; break;
+ case SdrCircKind::Arc: pID=STR_ObjNameSingulCARC; break;
+ case SdrCircKind::Cut: pID=STR_ObjNameSingulCCUT; break;
+ default: break;
+ }
+ } else {
+ switch (meCircleKind) {
+ case SdrCircKind::Full: pID=STR_ObjNameSingulCIRCE; break;
+ case SdrCircKind::Section: pID=STR_ObjNameSingulSECTE; break;
+ case SdrCircKind::Arc: pID=STR_ObjNameSingulCARCE; break;
+ case SdrCircKind::Cut: pID=STR_ObjNameSingulCCUTE; break;
+ default: break;
+ }
+ }
+ OUString sName(SvxResId(pID));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+ return sName;
+}
+
+OUString SdrCircObj::TakeObjNamePlural() const
+{
+ TranslateId pID=STR_ObjNamePluralCIRC;
+ if (maRect.GetWidth() == maRect.GetHeight() && maGeo.nShearAngle==0_deg100)
+ {
+ switch (meCircleKind) {
+ case SdrCircKind::Full: pID=STR_ObjNamePluralCIRC; break;
+ case SdrCircKind::Section: pID=STR_ObjNamePluralSECT; break;
+ case SdrCircKind::Arc: pID=STR_ObjNamePluralCARC; break;
+ case SdrCircKind::Cut: pID=STR_ObjNamePluralCCUT; break;
+ default: break;
+ }
+ } else {
+ switch (meCircleKind) {
+ case SdrCircKind::Full: pID=STR_ObjNamePluralCIRCE; break;
+ case SdrCircKind::Section: pID=STR_ObjNamePluralSECTE; break;
+ case SdrCircKind::Arc: pID=STR_ObjNamePluralCARCE; break;
+ case SdrCircKind::Cut: pID=STR_ObjNamePluralCCUTE; break;
+ default: break;
+ }
+ }
+ return SvxResId(pID);
+}
+
+SdrCircObj* SdrCircObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrCircObj(rTargetModel, *this);
+}
+
+basegfx::B2DPolyPolygon SdrCircObj::TakeXorPoly() const
+{
+ const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, maRect, nStartAngle, nEndAngle));
+ return basegfx::B2DPolyPolygon(aCircPolygon);
+}
+
+namespace {
+
+struct ImpCircUser : public SdrDragStatUserData
+{
+ tools::Rectangle aR;
+ Point aCenter;
+ Point aP1;
+ tools::Long nHgt;
+ tools::Long nWdt;
+ Degree100 nStart;
+ Degree100 nEnd;
+
+public:
+ ImpCircUser()
+ : nHgt(0),
+ nWdt(0),
+ nStart(0),
+ nEnd(0)
+ {}
+ void SetCreateParams(SdrDragStat const & rStat);
+};
+
+}
+
+sal_uInt32 SdrCircObj::GetHdlCount() const
+{
+ if(SdrCircKind::Full != meCircleKind)
+ {
+ return 10;
+ }
+ else
+ {
+ return 8;
+ }
+}
+
+void SdrCircObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ for (sal_uInt32 nHdlNum=(SdrCircKind::Full==meCircleKind)?2:0; nHdlNum<=9; ++nHdlNum)
+ {
+ Point aPnt;
+ SdrHdlKind eLocalKind(SdrHdlKind::Move);
+ sal_uInt32 nPNum(0);
+
+ switch (nHdlNum)
+ {
+ case 0:
+ aPnt = GetAnglePnt(maRect,nStartAngle);
+ eLocalKind = SdrHdlKind::Circle;
+ nPNum = 1;
+ break;
+ case 1:
+ aPnt = GetAnglePnt(maRect,nEndAngle);
+ eLocalKind = SdrHdlKind::Circle;
+ nPNum = 2;
+ break;
+ case 2:
+ aPnt = maRect.TopLeft();
+ eLocalKind = SdrHdlKind::UpperLeft;
+ break;
+ case 3:
+ aPnt = maRect.TopCenter();
+ eLocalKind = SdrHdlKind::Upper;
+ break;
+ case 4:
+ aPnt = maRect.TopRight();
+ eLocalKind = SdrHdlKind::UpperRight;
+ break;
+ case 5:
+ aPnt = maRect.LeftCenter();
+ eLocalKind = SdrHdlKind::Left;
+ break;
+ case 6:
+ aPnt = maRect.RightCenter();
+ eLocalKind = SdrHdlKind::Right;
+ break;
+ case 7:
+ aPnt = maRect.BottomLeft();
+ eLocalKind = SdrHdlKind::LowerLeft;
+ break;
+ case 8:
+ aPnt = maRect.BottomCenter();
+ eLocalKind = SdrHdlKind::Lower;
+ break;
+ case 9:
+ aPnt = maRect.BottomRight();
+ eLocalKind = SdrHdlKind::LowerRight;
+ break;
+ }
+
+ if (maGeo.nShearAngle)
+ {
+ ShearPoint(aPnt, maRect.TopLeft(), maGeo.mfTanShearAngle);
+ }
+
+ if (maGeo.nRotationAngle)
+ {
+ RotatePoint(aPnt, maRect.TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ }
+
+ std::unique_ptr<SdrHdl> pH(new SdrHdl(aPnt,eLocalKind));
+ pH->SetPointNum(nPNum);
+ pH->SetObj(const_cast<SdrCircObj*>(this));
+ pH->SetRotationAngle(maGeo.nRotationAngle);
+ rHdlList.AddHdl(std::move(pH));
+ }
+}
+
+
+bool SdrCircObj::hasSpecialDrag() const
+{
+ return true;
+}
+
+bool SdrCircObj::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ const bool bAngle(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
+
+ if(bAngle)
+ {
+ if(1 == rDrag.GetHdl()->GetPointNum() || 2 == rDrag.GetHdl()->GetPointNum())
+ {
+ rDrag.SetNoSnap();
+ }
+
+ return true;
+ }
+
+ return SdrTextObj::beginSpecialDrag(rDrag);
+}
+
+bool SdrCircObj::applySpecialDrag(SdrDragStat& rDrag)
+{
+ const bool bAngle(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
+
+ if(bAngle)
+ {
+ Point aPt(rDrag.GetNow());
+
+ if (maGeo.nRotationAngle)
+ RotatePoint(aPt,maRect.TopLeft(), -maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+
+ if (maGeo.nShearAngle)
+ ShearPoint(aPt,maRect.TopLeft(), -maGeo.mfTanShearAngle);
+
+ aPt -= maRect.Center();
+
+ tools::Long nWdt = maRect.Right() - maRect.Left();
+ tools::Long nHgt = maRect.Bottom() - maRect.Top();
+
+ if(nWdt>=nHgt)
+ {
+ aPt.setY(BigMulDiv(aPt.Y(),nWdt,nHgt) );
+ }
+ else
+ {
+ aPt.setX(BigMulDiv(aPt.X(),nHgt,nWdt) );
+ }
+
+ Degree100 nAngle=NormAngle36000(GetAngle(aPt));
+
+ if (rDrag.GetView() && rDrag.GetView()->IsAngleSnapEnabled())
+ {
+ Degree100 nSA=rDrag.GetView()->GetSnapAngle();
+
+ if (nSA)
+ {
+ nAngle+=nSA/2_deg100;
+ nAngle/=nSA;
+ nAngle*=nSA;
+ nAngle=NormAngle36000(nAngle);
+ }
+ }
+
+ if(1 == rDrag.GetHdl()->GetPointNum())
+ {
+ nStartAngle = nAngle;
+ }
+ else if(2 == rDrag.GetHdl()->GetPointNum())
+ {
+ nEndAngle = nAngle;
+ }
+
+ SetBoundAndSnapRectsDirty();
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+ SetChanged();
+
+ return true;
+ }
+ else
+ {
+ return SdrTextObj::applySpecialDrag(rDrag);
+ }
+}
+
+OUString SdrCircObj::getSpecialDragComment(const SdrDragStat& rDrag) const
+{
+ const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
+
+ if(bCreateComment)
+ {
+ OUStringBuffer aBuf(ImpGetDescriptionStr(STR_ViewCreateObj));
+ const sal_uInt32 nPointCount(rDrag.GetPointCount());
+
+ if(SdrCircKind::Full != meCircleKind && nPointCount > 2)
+ {
+ const ImpCircUser* pU = static_cast<const ImpCircUser*>(rDrag.GetUser());
+ Degree100 nAngle;
+
+ aBuf.append(" (");
+
+ if(3 == nPointCount)
+ {
+ nAngle = pU->nStart;
+ }
+ else
+ {
+ nAngle = pU->nEnd;
+ }
+
+ aBuf.append(SdrModel::GetAngleString(nAngle));
+ aBuf.append(')');
+ }
+
+ return aBuf.makeStringAndClear();
+ }
+ else
+ {
+ const bool bAngle(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
+
+ if(bAngle)
+ {
+ const Degree100 nAngle(1 == rDrag.GetHdl()->GetPointNum() ? nStartAngle : nEndAngle);
+
+ return ImpGetDescriptionStr(STR_DragCircAngle) +
+ " (" +
+ SdrModel::GetAngleString(nAngle) +
+ ")";
+ }
+ else
+ {
+ return SdrTextObj::getSpecialDragComment(rDrag);
+ }
+ }
+}
+
+
+void ImpCircUser::SetCreateParams(SdrDragStat const & rStat)
+{
+ rStat.TakeCreateRect(aR);
+ aR.Justify();
+ aCenter=aR.Center();
+ nWdt=aR.Right()-aR.Left();
+ nHgt=aR.Bottom()-aR.Top();
+ nStart=0_deg100;
+ nEnd=36000_deg100;
+ if (rStat.GetPointCount()>2) {
+ Point aP(rStat.GetPoint(2)-aCenter);
+ if (nWdt==0) aP.setX(0 );
+ if (nHgt==0) aP.setY(0 );
+ if (nWdt>=nHgt) {
+ if (nHgt!=0) aP.setY(aP.Y()*nWdt/nHgt );
+ } else {
+ if (nWdt!=0) aP.setX(aP.X()*nHgt/nWdt );
+ }
+ nStart=NormAngle36000(GetAngle(aP));
+ if (rStat.GetView()!=nullptr && rStat.GetView()->IsAngleSnapEnabled()) {
+ Degree100 nSA=rStat.GetView()->GetSnapAngle();
+ if (nSA) { // angle snapping
+ nStart+=nSA/2_deg100;
+ nStart/=nSA;
+ nStart*=nSA;
+ nStart=NormAngle36000(nStart);
+ }
+ }
+ aP1 = GetAnglePnt(aR,nStart);
+ nEnd=nStart;
+ } else aP1=aCenter;
+ if (rStat.GetPointCount()<=3)
+ return;
+
+ Point aP(rStat.GetPoint(3)-aCenter);
+ if (nWdt>=nHgt) {
+ aP.setY(BigMulDiv(aP.Y(),nWdt,nHgt) );
+ } else {
+ aP.setX(BigMulDiv(aP.X(),nHgt,nWdt) );
+ }
+ nEnd=NormAngle36000(GetAngle(aP));
+ if (rStat.GetView()!=nullptr && rStat.GetView()->IsAngleSnapEnabled()) {
+ Degree100 nSA=rStat.GetView()->GetSnapAngle();
+ if (nSA) { // angle snapping
+ nEnd+=nSA/2_deg100;
+ nEnd/=nSA;
+ nEnd*=nSA;
+ nEnd=NormAngle36000(nEnd);
+ }
+ }
+}
+
+void SdrCircObj::ImpSetCreateParams(SdrDragStat& rStat)
+{
+ ImpCircUser* pU=static_cast<ImpCircUser*>(rStat.GetUser());
+ if (pU==nullptr) {
+ pU=new ImpCircUser;
+ rStat.SetUser(std::unique_ptr<ImpCircUser>(pU));
+ }
+ pU->SetCreateParams(rStat);
+}
+
+bool SdrCircObj::BegCreate(SdrDragStat& rStat)
+{
+ rStat.SetOrtho4Possible();
+ tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
+ aRect1.Justify();
+ rStat.SetActionRect(aRect1);
+ maRect = aRect1;
+ ImpSetCreateParams(rStat);
+ return true;
+}
+
+bool SdrCircObj::MovCreate(SdrDragStat& rStat)
+{
+ ImpSetCreateParams(rStat);
+ ImpCircUser* pU=static_cast<ImpCircUser*>(rStat.GetUser());
+ rStat.SetActionRect(pU->aR);
+ maRect = pU->aR; // for ObjName
+ ImpJustifyRect(maRect);
+ nStartAngle=pU->nStart;
+ nEndAngle=pU->nEnd;
+ SetBoundRectDirty();
+ m_bSnapRectDirty=true;
+ SetXPolyDirty();
+
+ // #i103058# push current angle settings to ItemSet to
+ // allow FullDrag visualisation
+ if(rStat.GetPointCount() >= 4)
+ {
+ ImpSetCircInfoToAttr();
+ }
+
+ return true;
+}
+
+bool SdrCircObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ ImpSetCreateParams(rStat);
+ ImpCircUser* pU=static_cast<ImpCircUser*>(rStat.GetUser());
+ bool bRet = false;
+ if (eCmd==SdrCreateCmd::ForceEnd && rStat.GetPointCount()<4) meCircleKind=SdrCircKind::Full;
+ if (meCircleKind==SdrCircKind::Full) {
+ bRet=rStat.GetPointCount()>=2;
+ if (bRet) {
+ maRect = pU->aR;
+ ImpJustifyRect(maRect);
+ }
+ } else {
+ rStat.SetNoSnap(rStat.GetPointCount()>=2);
+ rStat.SetOrtho4Possible(rStat.GetPointCount()<2);
+ bRet=rStat.GetPointCount()>=4;
+ if (bRet) {
+ maRect = pU->aR;
+ ImpJustifyRect(maRect);
+ nStartAngle=pU->nStart;
+ nEndAngle=pU->nEnd;
+ }
+ }
+ m_bClosedObj=meCircleKind!=SdrCircKind::Arc;
+ SetBoundAndSnapRectsDirty();
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+ if (bRet)
+ rStat.SetUser(nullptr);
+ return bRet;
+}
+
+void SdrCircObj::BrkCreate(SdrDragStat& rStat)
+{
+ rStat.SetUser(nullptr);
+}
+
+bool SdrCircObj::BckCreate(SdrDragStat& rStat)
+{
+ rStat.SetNoSnap(rStat.GetPointCount()>=3);
+ rStat.SetOrtho4Possible(rStat.GetPointCount()<3);
+ return meCircleKind!=SdrCircKind::Full;
+}
+
+basegfx::B2DPolyPolygon SdrCircObj::TakeCreatePoly(const SdrDragStat& rDrag) const
+{
+ const ImpCircUser* pU = static_cast<const ImpCircUser*>(rDrag.GetUser());
+
+ if(rDrag.GetPointCount() < 4)
+ {
+ // force to OBJ_CIRC to get full visualisation
+ basegfx::B2DPolyPolygon aRetval(ImpCalcXPolyCirc(SdrCircKind::Full, pU->aR, pU->nStart, pU->nEnd));
+
+ if(3 == rDrag.GetPointCount())
+ {
+ // add edge to first point on ellipse
+ basegfx::B2DPolygon aNew;
+
+ aNew.append(basegfx::B2DPoint(pU->aCenter.X(), pU->aCenter.Y()));
+ aNew.append(basegfx::B2DPoint(pU->aP1.X(), pU->aP1.Y()));
+ aRetval.append(aNew);
+ }
+
+ return aRetval;
+ }
+ else
+ {
+ return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind, pU->aR, pU->nStart, pU->nEnd));
+ }
+}
+
+PointerStyle SdrCircObj::GetCreatePointer() const
+{
+ switch (meCircleKind) {
+ case SdrCircKind::Full: return PointerStyle::DrawEllipse;
+ case SdrCircKind::Section: return PointerStyle::DrawPie;
+ case SdrCircKind::Arc: return PointerStyle::DrawArc;
+ case SdrCircKind::Cut: return PointerStyle::DrawCircleCut;
+ default: break;
+ } // switch
+ return PointerStyle::Cross;
+}
+
+void SdrCircObj::NbcMove(const Size& aSiz)
+{
+ maRect.Move(aSiz);
+ m_aOutRect.Move(aSiz);
+ maSnapRect.Move(aSiz);
+ SetXPolyDirty();
+ SetBoundAndSnapRectsDirty(true);
+}
+
+void SdrCircObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ Degree100 nAngle0 = maGeo.nRotationAngle;
+ bool bNoShearRota = (maGeo.nRotationAngle == 0_deg100 && maGeo.nShearAngle == 0_deg100);
+ SdrTextObj::NbcResize(rRef,xFact,yFact);
+ bNoShearRota |= (maGeo.nRotationAngle == 0_deg100 && maGeo.nShearAngle == 0_deg100);
+ if (meCircleKind!=SdrCircKind::Full) {
+ bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
+ bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
+ if (bXMirr || bYMirr) {
+ // At bXMirr!=bYMirr we should actually swap both line ends.
+ // That, however, is pretty bad (because of forced "hard" formatting).
+ // Alternatively, we could implement a bMirrored flag (maybe even
+ // a more general one, e. g. for mirrored text, ...).
+ Degree100 nS0=nStartAngle;
+ Degree100 nE0=nEndAngle;
+ if (bNoShearRota) {
+ // the RectObj already mirrors at VMirror because of a 180deg rotation
+ if (! (bXMirr && bYMirr)) {
+ Degree100 nTmp=nS0;
+ nS0=18000_deg100-nE0;
+ nE0=18000_deg100-nTmp;
+ }
+ } else { // mirror contorted ellipses
+ if (bXMirr!=bYMirr) {
+ nS0+=nAngle0;
+ nE0+=nAngle0;
+ if (bXMirr) {
+ Degree100 nTmp=nS0;
+ nS0=18000_deg100-nE0;
+ nE0=18000_deg100-nTmp;
+ }
+ if (bYMirr) {
+ Degree100 nTmp=nS0;
+ nS0=-nE0;
+ nE0=-nTmp;
+ }
+ nS0 -= maGeo.nRotationAngle;
+ nE0 -= maGeo.nRotationAngle;
+ }
+ }
+ Degree100 nAngleDif=nE0-nS0;
+ nStartAngle=NormAngle36000(nS0);
+ nEndAngle =NormAngle36000(nE0);
+ if (nAngleDif==36000_deg100) nEndAngle+=nAngleDif; // full circle
+ }
+ }
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+}
+
+void SdrCircObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+}
+
+void SdrCircObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ bool bFreeMirr=meCircleKind!=SdrCircKind::Full;
+ Point aTmpPt1;
+ Point aTmpPt2;
+ if (bFreeMirr) { // some preparations for using an arbitrary axis of reflection
+ Point aCenter(maRect.Center());
+ tools::Long nWdt=maRect.GetWidth()-1;
+ tools::Long nHgt=maRect.GetHeight()-1;
+ tools::Long nMaxRad=(std::max(nWdt,nHgt)+1) /2;
+ // starting point
+ double a = toRadians(nStartAngle);
+ aTmpPt1=Point(FRound(cos(a)*nMaxRad),-FRound(sin(a)*nMaxRad));
+ if (nWdt==0) aTmpPt1.setX(0 );
+ if (nHgt==0) aTmpPt1.setY(0 );
+ aTmpPt1+=aCenter;
+ // finishing point
+ a = toRadians(nEndAngle);
+ aTmpPt2=Point(FRound(cos(a)*nMaxRad),-FRound(sin(a)*nMaxRad));
+ if (nWdt==0) aTmpPt2.setX(0 );
+ if (nHgt==0) aTmpPt2.setY(0 );
+ aTmpPt2+=aCenter;
+ if (maGeo.nRotationAngle)
+ {
+ RotatePoint(aTmpPt1, maRect.TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ RotatePoint(aTmpPt2, maRect.TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ }
+ if (maGeo.nShearAngle)
+ {
+ ShearPoint(aTmpPt1, maRect.TopLeft(), maGeo.mfTanShearAngle);
+ ShearPoint(aTmpPt2, maRect.TopLeft(), maGeo.mfTanShearAngle);
+ }
+ }
+ SdrTextObj::NbcMirror(rRef1,rRef2);
+ if (meCircleKind!=SdrCircKind::Full) { // adapt starting and finishing angle
+ MirrorPoint(aTmpPt1,rRef1,rRef2);
+ MirrorPoint(aTmpPt2,rRef1,rRef2);
+ // unrotate:
+ if (maGeo.nRotationAngle)
+ {
+ RotatePoint(aTmpPt1, maRect.TopLeft(), -maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle); // -sin for reversion
+ RotatePoint(aTmpPt2, maRect.TopLeft(), -maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle); // -sin for reversion
+ }
+ // unshear:
+ if (maGeo.nShearAngle)
+ {
+ ShearPoint(aTmpPt1, maRect.TopLeft(), -maGeo.mfTanShearAngle); // -tan for reversion
+ ShearPoint(aTmpPt2, maRect.TopLeft(), -maGeo.mfTanShearAngle); // -tan for reversion
+ }
+ Point aCenter(maRect.Center());
+ aTmpPt1-=aCenter;
+ aTmpPt2-=aCenter;
+ // because it's mirrored, the angles are swapped, too
+ nStartAngle=GetAngle(aTmpPt2);
+ nEndAngle =GetAngle(aTmpPt1);
+ Degree100 nAngleDif=nEndAngle-nStartAngle;
+ nStartAngle=NormAngle36000(nStartAngle);
+ nEndAngle =NormAngle36000(nEndAngle);
+ if (nAngleDif==36000_deg100) nEndAngle+=nAngleDif; // full circle
+ }
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+}
+
+std::unique_ptr<SdrObjGeoData> SdrCircObj::NewGeoData() const
+{
+ return std::make_unique<SdrCircObjGeoData>();
+}
+
+void SdrCircObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrRectObj::SaveGeoData(rGeo);
+ SdrCircObjGeoData& rCGeo=static_cast<SdrCircObjGeoData&>(rGeo);
+ rCGeo.nStartAngle=nStartAngle;
+ rCGeo.nEndAngle =nEndAngle;
+}
+
+void SdrCircObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrRectObj::RestoreGeoData(rGeo);
+ const SdrCircObjGeoData& rCGeo=static_cast<const SdrCircObjGeoData&>(rGeo);
+ nStartAngle=rCGeo.nStartAngle;
+ nEndAngle =rCGeo.nEndAngle;
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+}
+
+static void Union(tools::Rectangle& rR, const Point& rP)
+{
+ if (rP.X()<rR.Left ()) rR.SetLeft(rP.X() );
+ if (rP.X()>rR.Right ()) rR.SetRight(rP.X() );
+ if (rP.Y()<rR.Top ()) rR.SetTop(rP.Y() );
+ if (rP.Y()>rR.Bottom()) rR.SetBottom(rP.Y() );
+}
+
+void SdrCircObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
+{
+ rRect = maRect;
+ if (meCircleKind!=SdrCircKind::Full) {
+ const Point aPntStart(GetAnglePnt(maRect,nStartAngle));
+ const Point aPntEnd(GetAnglePnt(maRect,nEndAngle));
+ Degree100 a=nStartAngle;
+ Degree100 e=nEndAngle;
+ rRect.SetLeft(maRect.Right() );
+ rRect.SetRight(maRect.Left() );
+ rRect.SetTop(maRect.Bottom() );
+ rRect.SetBottom(maRect.Top() );
+ Union(rRect,aPntStart);
+ Union(rRect,aPntEnd);
+ if ((a<=18000_deg100 && e>=18000_deg100) || (a>e && (a<=18000_deg100 || e>=18000_deg100))) {
+ Union(rRect,maRect.LeftCenter());
+ }
+ if ((a<=27000_deg100 && e>=27000_deg100) || (a>e && (a<=27000_deg100 || e>=27000_deg100))) {
+ Union(rRect,maRect.BottomCenter());
+ }
+ if (a>e) {
+ Union(rRect,maRect.RightCenter());
+ }
+ if ((a<=9000_deg100 && e>=9000_deg100) || (a>e && (a<=9000_deg100 || e>=9000_deg100))) {
+ Union(rRect,maRect.TopCenter());
+ }
+ if (meCircleKind==SdrCircKind::Section) {
+ Union(rRect,maRect.Center());
+ }
+ if (maGeo.nRotationAngle)
+ {
+ Point aDst(rRect.TopLeft());
+ aDst-=maRect.TopLeft();
+ Point aDst0(aDst);
+ RotatePoint(aDst,Point(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ aDst-=aDst0;
+ rRect.Move(aDst.X(),aDst.Y());
+ }
+ }
+ if (maGeo.nShearAngle==0_deg100)
+ return;
+
+ tools::Long nDst = FRound((rRect.Bottom() - rRect.Top()) * maGeo.mfTanShearAngle);
+ if (maGeo.nShearAngle > 0_deg100)
+ {
+ Point aRef(rRect.TopLeft());
+ rRect.AdjustLeft( -nDst );
+ Point aTmpPt(rRect.TopLeft());
+ RotatePoint(aTmpPt, aRef, maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ aTmpPt-=rRect.TopLeft();
+ rRect.Move(aTmpPt.X(),aTmpPt.Y());
+ } else {
+ rRect.AdjustRight( -nDst );
+ }
+}
+
+void SdrCircObj::RecalcSnapRect()
+{
+ if (PaintNeedsXPolyCirc()) {
+ maSnapRect=GetXPoly().GetBoundRect();
+ } else {
+ TakeUnrotatedSnapRect(maSnapRect);
+ }
+}
+
+void SdrCircObj::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ if (maGeo.nRotationAngle || maGeo.nShearAngle || meCircleKind != SdrCircKind::Full)
+ {
+ tools::Rectangle aSR0(GetSnapRect());
+ tools::Long nWdt0=aSR0.Right()-aSR0.Left();
+ tools::Long nHgt0=aSR0.Bottom()-aSR0.Top();
+ tools::Long nWdt1=rRect.Right()-rRect.Left();
+ tools::Long nHgt1=rRect.Bottom()-rRect.Top();
+ NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
+ NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
+ } else {
+ maRect=rRect;
+ ImpJustifyRect(maRect);
+ }
+ SetBoundAndSnapRectsDirty();
+ SetXPolyDirty();
+ ImpSetCircInfoToAttr();
+}
+
+sal_uInt32 SdrCircObj::GetSnapPointCount() const
+{
+ if (meCircleKind==SdrCircKind::Full) {
+ return 1;
+ } else {
+ return 3;
+ }
+}
+
+Point SdrCircObj::GetSnapPoint(sal_uInt32 i) const
+{
+ switch (i) {
+ case 1 : return GetAnglePnt(maRect,nStartAngle);
+ case 2 : return GetAnglePnt(maRect,nEndAngle);
+ default: return maRect.Center();
+ }
+}
+
+void SdrCircObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ SetXPolyDirty();
+ SdrRectObj::Notify(rBC,rHint);
+ ImpSetAttrToCircInfo();
+}
+
+
+void SdrCircObj::ImpSetAttrToCircInfo()
+{
+ const SfxItemSet& rSet = GetObjectItemSet();
+ SdrCircKind eNewKind = rSet.Get(SDRATTR_CIRCKIND).GetValue();
+
+ Degree100 nNewStart = rSet.Get(SDRATTR_CIRCSTARTANGLE).GetValue();
+ Degree100 nNewEnd = rSet.Get(SDRATTR_CIRCENDANGLE).GetValue();
+
+ bool bKindChg = meCircleKind != eNewKind;
+ bool bAngleChg = nNewStart != nStartAngle || nNewEnd != nEndAngle;
+
+ if(bKindChg || bAngleChg)
+ {
+ meCircleKind = eNewKind;
+ nStartAngle = nNewStart;
+ nEndAngle = nNewEnd;
+
+ if(bKindChg || (meCircleKind != SdrCircKind::Full && bAngleChg))
+ {
+ SetXPolyDirty();
+ SetBoundAndSnapRectsDirty();
+ }
+ }
+}
+
+void SdrCircObj::ImpSetCircInfoToAttr()
+{
+ const SfxItemSet& rSet = GetObjectItemSet();
+
+ SdrCircKind eOldKindA = rSet.Get(SDRATTR_CIRCKIND).GetValue();
+ Degree100 nOldStartAngle = rSet.Get(SDRATTR_CIRCSTARTANGLE).GetValue();
+ Degree100 nOldEndAngle = rSet.Get(SDRATTR_CIRCENDANGLE).GetValue();
+
+ if(meCircleKind == eOldKindA && nStartAngle == nOldStartAngle && nEndAngle == nOldEndAngle)
+ return;
+
+ // since SetItem() implicitly calls ImpSetAttrToCircInfo()
+ // setting the item directly is necessary here.
+ if(meCircleKind != eOldKindA)
+ {
+ GetProperties().SetObjectItemDirect(SdrCircKindItem(meCircleKind));
+ }
+
+ if(nStartAngle != nOldStartAngle)
+ {
+ GetProperties().SetObjectItemDirect(makeSdrCircStartAngleItem(nStartAngle));
+ }
+
+ if(nEndAngle != nOldEndAngle)
+ {
+ GetProperties().SetObjectItemDirect(makeSdrCircEndAngleItem(nEndAngle));
+ }
+
+ SetXPolyDirty();
+ ImpSetAttrToCircInfo();
+}
+
+SdrObjectUniquePtr SdrCircObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ const bool bFill(meCircleKind != SdrCircKind::Arc);
+ const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, maRect, nStartAngle, nEndAngle));
+ SdrObjectUniquePtr pRet = ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon), bFill, bBezier);
+
+ if(bAddText)
+ {
+ pRet = ImpConvertAddText(std::move(pRet), bBezier);
+ }
+
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdoedge.cxx b/svx/source/svdraw/svdoedge.cxx
new file mode 100644
index 000000000..769a720c3
--- /dev/null
+++ b/svx/source/svdraw/svdoedge.cxx
@@ -0,0 +1,2647 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <osl/diagnose.h>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <svl/hint.hxx>
+
+#include <sdr/contact/viewcontactofsdredgeobj.hxx>
+#include <sdr/properties/connectorproperties.hxx>
+#include <svx/sdrhittesthelper.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svddrgmt.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sxekitm.hxx>
+#include <svx/sxelditm.hxx>
+#include <svx/sxenditm.hxx>
+#include <svx/xpoly.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <comphelper/lok.hxx>
+
+void SdrObjConnection::ResetVars()
+{
+ pObj=nullptr;
+ nConId=0;
+ bBestConn=true;
+ bBestVertex=true;
+ bAutoVertex=false;
+ bAutoCorner=false;
+}
+
+bool SdrObjConnection::TakeGluePoint(SdrGluePoint& rGP) const
+{
+ bool bRet = false;
+ if (pObj!=nullptr) { // one object has to be docked already!
+ if (bAutoVertex) {
+ rGP=pObj->GetVertexGluePoint(nConId);
+ bRet = true;
+ } else if (bAutoCorner) {
+ rGP=pObj->GetCornerGluePoint(nConId);
+ bRet = true;
+ } else {
+ const SdrGluePointList* pGPL=pObj->GetGluePointList();
+ if (pGPL!=nullptr) {
+ sal_uInt16 nNum=pGPL->FindGluePoint(nConId);
+ if (nNum!=SDRGLUEPOINT_NOTFOUND) {
+ rGP=(*pGPL)[nNum];
+ bRet = true;
+ }
+ }
+ }
+ }
+ if (bRet) {
+ Point aPt(rGP.GetAbsolutePos(*pObj));
+ aPt+=aObjOfs;
+ rGP.SetPos(aPt);
+ }
+ return bRet;
+}
+
+Point& SdrEdgeInfoRec::ImpGetLineOffsetPoint(SdrEdgeLineCode eLineCode)
+{
+ switch (eLineCode) {
+ case SdrEdgeLineCode::Obj1Line2 : return aObj1Line2;
+ case SdrEdgeLineCode::Obj1Line3 : return aObj1Line3;
+ case SdrEdgeLineCode::Obj2Line2 : return aObj2Line2;
+ case SdrEdgeLineCode::Obj2Line3 : return aObj2Line3;
+ case SdrEdgeLineCode::MiddleLine: return aMiddleLine;
+ } // switch
+ return aMiddleLine;
+}
+
+sal_uInt16 SdrEdgeInfoRec::ImpGetPolyIdx(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const
+{
+ switch (eLineCode) {
+ case SdrEdgeLineCode::Obj1Line2 : return 1;
+ case SdrEdgeLineCode::Obj1Line3 : return 2;
+ case SdrEdgeLineCode::Obj2Line2 : return rXP.GetPointCount()-3;
+ case SdrEdgeLineCode::Obj2Line3 : return rXP.GetPointCount()-4;
+ case SdrEdgeLineCode::MiddleLine: return nMiddleLine;
+ } // switch
+ return 0;
+}
+
+bool SdrEdgeInfoRec::ImpIsHorzLine(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const
+{
+ sal_uInt16 nIdx=ImpGetPolyIdx(eLineCode,rXP);
+ bool bHorz=nAngle1==0 || nAngle1==18000;
+ if (eLineCode==SdrEdgeLineCode::Obj2Line2 || eLineCode==SdrEdgeLineCode::Obj2Line3) {
+ nIdx=rXP.GetPointCount()-nIdx;
+ bHorz=nAngle2==0 || nAngle2==18000;
+ }
+ if ((nIdx & 1)==1) bHorz=!bHorz;
+ return bHorz;
+}
+
+void SdrEdgeInfoRec::ImpSetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon& rXP, tools::Long nVal)
+{
+ Point& rPt=ImpGetLineOffsetPoint(eLineCode);
+ if (ImpIsHorzLine(eLineCode,rXP)) rPt.setY(nVal );
+ else rPt.setX(nVal );
+}
+
+tools::Long SdrEdgeInfoRec::ImpGetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const
+{
+ const Point& rPt = const_cast<SdrEdgeInfoRec*>(this)->ImpGetLineOffsetPoint(eLineCode);
+ if (ImpIsHorzLine(eLineCode,rXP))
+ return rPt.Y();
+ else
+ return rPt.X();
+}
+
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrEdgeObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::ConnectorProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrEdgeObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrEdgeObj>(*this);
+}
+
+
+SdrEdgeObj::SdrEdgeObj(SdrModel& rSdrModel)
+: SdrTextObj(rSdrModel),
+ nNotifyingCount(0),
+ bEdgeTrackDirty(false),
+ bEdgeTrackUserDefined(false),
+ // Default is to allow default connects
+ mbSuppressDefaultConnect(false),
+ mbBoundRectCalculationRunning(false),
+ mbSuppressed(false)
+{
+ m_bClosedObj=false;
+ m_bIsEdge=true;
+ pEdgeTrack = XPolygon();
+}
+
+SdrEdgeObj::SdrEdgeObj(SdrModel& rSdrModel, SdrEdgeObj const & rSource)
+: SdrTextObj(rSdrModel, rSource),
+ nNotifyingCount(0),
+ bEdgeTrackDirty(false),
+ bEdgeTrackUserDefined(false),
+ // Default is to allow default connects
+ mbSuppressDefaultConnect(false),
+ mbBoundRectCalculationRunning(false),
+ mbSuppressed(false)
+{
+ m_bClosedObj = false;
+ m_bIsEdge = true;
+ pEdgeTrack = rSource.pEdgeTrack;
+ bEdgeTrackDirty=rSource.bEdgeTrackDirty;
+ aCon1 =rSource.aCon1;
+ aCon2 =rSource.aCon2;
+ aCon1.pObj=nullptr;
+ aCon2.pObj=nullptr;
+ aEdgeInfo=rSource.aEdgeInfo;
+}
+
+SdrEdgeObj::~SdrEdgeObj()
+{
+ SdrEdgeObj::DisconnectFromNode(true);
+ SdrEdgeObj::DisconnectFromNode(false);
+}
+
+void SdrEdgeObj::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ // call parent
+ SdrTextObj::handlePageChange(pOldPage, pNewPage);
+
+ if(nullptr != GetConnection(true).GetObject() || nullptr != GetConnection(false).GetObject())
+ {
+ // check broadcasters; when we are not inserted we do not need broadcasters
+ // TTTT not yet added, but keep hint to do this here
+ // mpCon1->ownerPageChange();
+ // mpCon2->ownerPageChange();
+ }
+}
+
+void SdrEdgeObj::ImpSetAttrToEdgeInfo()
+{
+ const SfxItemSet& rSet = GetObjectItemSet();
+ SdrEdgeKind eKind = rSet.Get(SDRATTR_EDGEKIND).GetValue();
+ sal_Int32 nVal1 = rSet.Get(SDRATTR_EDGELINE1DELTA).GetValue();
+ sal_Int32 nVal2 = rSet.Get(SDRATTR_EDGELINE2DELTA).GetValue();
+ sal_Int32 nVal3 = rSet.Get(SDRATTR_EDGELINE3DELTA).GetValue();
+
+ if(eKind == SdrEdgeKind::OrthoLines || eKind == SdrEdgeKind::Bezier)
+ {
+ sal_Int32 nVals[3] = { nVal1, nVal2, nVal3 };
+ sal_uInt16 n = 0;
+
+ if(aEdgeInfo.nObj1Lines >= 2 && n < 3)
+ {
+ aEdgeInfo.ImpSetLineOffset(SdrEdgeLineCode::Obj1Line2, *pEdgeTrack, nVals[n]);
+ n++;
+ }
+
+ if(aEdgeInfo.nObj1Lines >= 3 && n < 3)
+ {
+ aEdgeInfo.ImpSetLineOffset(SdrEdgeLineCode::Obj1Line3, *pEdgeTrack, nVals[n]);
+ n++;
+ }
+
+ if(aEdgeInfo.nMiddleLine != 0xFFFF && n < 3)
+ {
+ aEdgeInfo.ImpSetLineOffset(SdrEdgeLineCode::MiddleLine, *pEdgeTrack, nVals[n]);
+ n++;
+ }
+
+ if(aEdgeInfo.nObj2Lines >= 3 && n < 3)
+ {
+ aEdgeInfo.ImpSetLineOffset(SdrEdgeLineCode::Obj2Line3, *pEdgeTrack, nVals[n]);
+ n++;
+ }
+
+ if(aEdgeInfo.nObj2Lines >= 2 && n < 3)
+ {
+ aEdgeInfo.ImpSetLineOffset(SdrEdgeLineCode::Obj2Line2, *pEdgeTrack, nVals[n]);
+ n++;
+ }
+ }
+ else if(eKind == SdrEdgeKind::ThreeLines)
+ {
+ bool bHor1 = aEdgeInfo.nAngle1 == 0 || aEdgeInfo.nAngle1 == 18000;
+ bool bHor2 = aEdgeInfo.nAngle2 == 0 || aEdgeInfo.nAngle2 == 18000;
+
+ if(bHor1)
+ {
+ aEdgeInfo.aObj1Line2.setX( nVal1 );
+ }
+ else
+ {
+ aEdgeInfo.aObj1Line2.setY( nVal1 );
+ }
+
+ if(bHor2)
+ {
+ aEdgeInfo.aObj2Line2.setX( nVal2 );
+ }
+ else
+ {
+ aEdgeInfo.aObj2Line2.setY( nVal2 );
+ }
+ }
+
+ ImpDirtyEdgeTrack();
+}
+
+void SdrEdgeObj::ImpSetEdgeInfoToAttr()
+{
+ const SfxItemSet& rSet = GetObjectItemSet();
+ SdrEdgeKind eKind = rSet.Get(SDRATTR_EDGEKIND).GetValue();
+ sal_Int32 nValCnt = rSet.Get(SDRATTR_EDGELINEDELTACOUNT).GetValue();
+ sal_Int32 nVal1 = rSet.Get(SDRATTR_EDGELINE1DELTA).GetValue();
+ sal_Int32 nVal2 = rSet.Get(SDRATTR_EDGELINE2DELTA).GetValue();
+ sal_Int32 nVal3 = rSet.Get(SDRATTR_EDGELINE3DELTA).GetValue();
+ sal_Int32 nVals[3] = { nVal1, nVal2, nVal3 };
+ sal_uInt16 n = 0;
+
+ if(eKind == SdrEdgeKind::OrthoLines || eKind == SdrEdgeKind::Bezier)
+ {
+ if(aEdgeInfo.nObj1Lines >= 2 && n < 3)
+ {
+ nVals[n] = aEdgeInfo.ImpGetLineOffset(SdrEdgeLineCode::Obj1Line2, *pEdgeTrack);
+ n++;
+ }
+
+ if(aEdgeInfo.nObj1Lines >= 3 && n < 3)
+ {
+ nVals[n] = aEdgeInfo.ImpGetLineOffset(SdrEdgeLineCode::Obj1Line3, *pEdgeTrack);
+ n++;
+ }
+
+ if(aEdgeInfo.nMiddleLine != 0xFFFF && n < 3)
+ {
+ nVals[n] = aEdgeInfo.ImpGetLineOffset(SdrEdgeLineCode::MiddleLine, *pEdgeTrack);
+ n++;
+ }
+
+ if(aEdgeInfo.nObj2Lines >= 3 && n < 3)
+ {
+ nVals[n] = aEdgeInfo.ImpGetLineOffset(SdrEdgeLineCode::Obj2Line3, *pEdgeTrack);
+ n++;
+ }
+
+ if(aEdgeInfo.nObj2Lines >= 2 && n < 3)
+ {
+ nVals[n] = aEdgeInfo.ImpGetLineOffset(SdrEdgeLineCode::Obj2Line2, *pEdgeTrack);
+ n++;
+ }
+ }
+ else if(eKind == SdrEdgeKind::ThreeLines)
+ {
+ bool bHor1 = aEdgeInfo.nAngle1 == 0 || aEdgeInfo.nAngle1 == 18000;
+ bool bHor2 = aEdgeInfo.nAngle2 == 0 || aEdgeInfo.nAngle2 == 18000;
+
+ n = 2;
+ nVals[0] = bHor1 ? aEdgeInfo.aObj1Line2.X() : aEdgeInfo.aObj1Line2.Y();
+ nVals[1] = bHor2 ? aEdgeInfo.aObj2Line2.X() : aEdgeInfo.aObj2Line2.Y();
+ }
+
+ if(!(n != nValCnt || nVals[0] != nVal1 || nVals[1] != nVal2 || nVals[2] != nVal3))
+ return;
+
+ // Here no more notifying is necessary, just local changes are OK.
+ if(n != nValCnt)
+ {
+ GetProperties().SetObjectItemDirect(SdrEdgeLineDeltaCountItem(n));
+ }
+
+ if(nVals[0] != nVal1)
+ {
+ GetProperties().SetObjectItemDirect(makeSdrEdgeLine1DeltaItem(nVals[0]));
+ }
+
+ if(nVals[1] != nVal2)
+ {
+ GetProperties().SetObjectItemDirect(makeSdrEdgeLine2DeltaItem(nVals[1]));
+ }
+
+ if(nVals[2] != nVal3)
+ {
+ GetProperties().SetObjectItemDirect(makeSdrEdgeLine3DeltaItem(nVals[2]));
+ }
+
+ if(n < 3)
+ {
+ GetProperties().ClearObjectItemDirect(SDRATTR_EDGELINE3DELTA);
+ }
+
+ if(n < 2)
+ {
+ GetProperties().ClearObjectItemDirect(SDRATTR_EDGELINE2DELTA);
+ }
+
+ if(n < 1)
+ {
+ GetProperties().ClearObjectItemDirect(SDRATTR_EDGELINE1DELTA);
+ }
+}
+
+void SdrEdgeObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ // #i54102# allow rotation, mirror and shear
+ rInfo.bRotateFreeAllowed = true;
+ rInfo.bRotate90Allowed = true;
+ rInfo.bMirrorFreeAllowed = true;
+ rInfo.bMirror45Allowed = true;
+ rInfo.bMirror90Allowed = true;
+ rInfo.bTransparenceAllowed = false;
+ rInfo.bShearAllowed = true;
+ rInfo.bEdgeRadiusAllowed = false;
+ bool bCanConv=!HasText() || ImpCanConvTextToCurve();
+ rInfo.bCanConvToPath=bCanConv;
+ rInfo.bCanConvToPoly=bCanConv;
+ rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
+}
+
+SdrObjKind SdrEdgeObj::GetObjIdentifier() const
+{
+ return SdrObjKind::Edge;
+}
+
+const tools::Rectangle& SdrEdgeObj::GetCurrentBoundRect() const
+{
+ if(bEdgeTrackDirty)
+ {
+ const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
+ }
+
+ return SdrTextObj::GetCurrentBoundRect();
+}
+
+const tools::Rectangle& SdrEdgeObj::GetSnapRect() const
+{
+ if(bEdgeTrackDirty)
+ {
+ const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
+ }
+
+ return SdrTextObj::GetSnapRect();
+}
+
+void SdrEdgeObj::RecalcSnapRect()
+{
+ maSnapRect=pEdgeTrack->GetBoundRect();
+}
+
+void SdrEdgeObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
+{
+ rRect=GetSnapRect();
+}
+
+SdrGluePoint SdrEdgeObj::GetVertexGluePoint(sal_uInt16 nNum) const
+{
+ Point aPt;
+ sal_uInt16 nPointCount=pEdgeTrack->GetPointCount();
+ if (nPointCount>0)
+ {
+ Point aOfs = GetSnapRect().Center();
+ if (nNum==2 && GetConnectedNode(true)==nullptr) aPt=(*pEdgeTrack)[0];
+ else if (nNum==3 && GetConnectedNode(false)==nullptr) aPt=(*pEdgeTrack)[nPointCount-1];
+ else {
+ if ((nPointCount & 1) ==1) {
+ aPt=(*pEdgeTrack)[nPointCount/2];
+ } else {
+ Point aPt1((*pEdgeTrack)[nPointCount/2-1]);
+ Point aPt2((*pEdgeTrack)[nPointCount/2]);
+ aPt1+=aPt2;
+ aPt1.setX( aPt1.X() / 2 );
+ aPt1.setY( aPt1.Y() / 2 );
+ aPt=aPt1;
+ }
+ }
+ aPt-=aOfs;
+ }
+ SdrGluePoint aGP(aPt);
+ aGP.SetPercent(false);
+ return aGP;
+}
+
+SdrGluePoint SdrEdgeObj::GetCornerGluePoint(sal_uInt16 nNum) const
+{
+ return GetVertexGluePoint(nNum);
+}
+
+const SdrGluePointList* SdrEdgeObj::GetGluePointList() const
+{
+ return nullptr; // no user defined gluepoints for connectors
+}
+
+SdrGluePointList* SdrEdgeObj::ForceGluePointList()
+{
+ return nullptr; // no user defined gluepoints for connectors
+}
+
+void SdrEdgeObj::ConnectToNode(bool bTail1, SdrObject* pObj)
+{
+ SdrObjConnection& rCon=GetConnection(bTail1);
+ DisconnectFromNode(bTail1);
+ if (pObj!=nullptr) {
+ pObj->AddListener(*this);
+ rCon.pObj=pObj;
+
+ // #i120437# If connection is set, reset bEdgeTrackUserDefined
+ bEdgeTrackUserDefined = false;
+
+ ImpDirtyEdgeTrack();
+ }
+}
+
+void SdrEdgeObj::DisconnectFromNode(bool bTail1)
+{
+ SdrObjConnection& rCon=GetConnection(bTail1);
+ if (rCon.pObj!=nullptr) {
+ rCon.pObj->RemoveListener(*this);
+ rCon.pObj=nullptr;
+ }
+}
+
+SdrObject* SdrEdgeObj::GetConnectedNode(bool bTail1) const
+{
+ SdrObject* pObj(GetConnection(bTail1).pObj);
+
+ if(nullptr != pObj
+ && (pObj->getSdrPageFromSdrObject() != getSdrPageFromSdrObject() || !pObj->IsInserted()))
+ {
+ pObj = nullptr;
+ }
+
+ return pObj;
+}
+
+bool SdrEdgeObj::CheckNodeConnection(bool bTail1) const
+{
+ bool bRet = false;
+ const SdrObjConnection& rCon=GetConnection(bTail1);
+ sal_uInt16 nPointCount=pEdgeTrack->GetPointCount();
+
+ if(nullptr != rCon.pObj && rCon.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject() && 0 != nPointCount)
+ {
+ const SdrGluePointList* pGPL=rCon.pObj->GetGluePointList();
+ sal_uInt16 nGluePointCnt=pGPL==nullptr ? 0 : pGPL->GetCount();
+ sal_uInt16 nGesAnz=nGluePointCnt+8;
+ Point aTail(bTail1 ? (*pEdgeTrack)[0] : (*pEdgeTrack)[sal_uInt16(nPointCount-1)]);
+ for (sal_uInt16 i=0; i<nGesAnz && !bRet; i++) {
+ if (i<nGluePointCnt) { // UserDefined
+ bRet=aTail==(*pGPL)[i].GetAbsolutePos(*rCon.pObj);
+ } else if (i<nGluePointCnt+4) { // Vertex
+ SdrGluePoint aPt(rCon.pObj->GetVertexGluePoint(i-nGluePointCnt));
+ bRet=aTail==aPt.GetAbsolutePos(*rCon.pObj);
+ } else { // Corner
+ SdrGluePoint aPt(rCon.pObj->GetCornerGluePoint(i-nGluePointCnt-4));
+ bRet=aTail==aPt.GetAbsolutePos(*rCon.pObj);
+ }
+ }
+ }
+ return bRet;
+}
+
+void SdrEdgeObj::ImpSetTailPoint(bool bTail1, const Point& rPt)
+{
+ sal_uInt16 nPointCount=pEdgeTrack->GetPointCount();
+ if (nPointCount==0) {
+ (*pEdgeTrack)[0]=rPt;
+ (*pEdgeTrack)[1]=rPt;
+ } else if (nPointCount==1) {
+ if (!bTail1) (*pEdgeTrack)[1]=rPt;
+ else { (*pEdgeTrack)[1]=(*pEdgeTrack)[0]; (*pEdgeTrack)[0]=rPt; }
+ } else {
+ if (!bTail1) (*pEdgeTrack)[sal_uInt16(nPointCount-1)]=rPt;
+ else (*pEdgeTrack)[0]=rPt;
+ }
+ ImpRecalcEdgeTrack();
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrEdgeObj::ImpDirtyEdgeTrack()
+{
+ if ( !bEdgeTrackUserDefined || !getSdrModelFromSdrObject().isLocked() )
+ bEdgeTrackDirty = true;
+}
+
+void SdrEdgeObj::ImpUndirtyEdgeTrack()
+{
+ if (bEdgeTrackDirty && getSdrModelFromSdrObject().isLocked())
+ {
+ ImpRecalcEdgeTrack();
+ }
+}
+
+void SdrEdgeObj::ImpRecalcEdgeTrack()
+{
+ // #i120437# if bEdgeTrackUserDefined, do not recalculate
+ if(bEdgeTrackUserDefined)
+ {
+ return;
+ }
+
+ // #i120437# also not when model locked during import, but remember
+ if(getSdrModelFromSdrObject().isLocked())
+ {
+ mbSuppressed = true;
+ return;
+ }
+
+ // #i110649#
+ if(mbBoundRectCalculationRunning)
+ {
+ // This object is involved into another ImpRecalcEdgeTrack() call
+ // from another SdrEdgeObj. Do not calculate again to avoid loop.
+ // Also, do not change bEdgeTrackDirty so that it gets recalculated
+ // later at the first non-looping call.
+ }
+ else
+ {
+ // To not run in a depth loop, use a coloring algorithm on
+ // SdrEdgeObj BoundRect calculations
+ mbBoundRectCalculationRunning = true;
+
+ if(mbSuppressed)
+ {
+ // #i123048# If layouting was ever suppressed, it needs to be done once
+ // and the attr need to be set at EdgeInfo, else these attr *will be lost*
+ // in the following call to ImpSetEdgeInfoToAttr() since they were never
+ // set before (!)
+ *pEdgeTrack=ImpCalcEdgeTrack(*pEdgeTrack,aCon1,aCon2,&aEdgeInfo);
+ ImpSetAttrToEdgeInfo();
+ mbSuppressed = false;
+ }
+
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetCurrentBoundRect();
+ SetBoundAndSnapRectsDirty();
+ *pEdgeTrack=ImpCalcEdgeTrack(*pEdgeTrack,aCon1,aCon2,&aEdgeInfo);
+ ImpSetEdgeInfoToAttr(); // copy values from aEdgeInfo into the pool
+ bEdgeTrackDirty=false;
+
+ // Only redraw here, no object change
+ ActionChanged();
+
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+
+ mbBoundRectCalculationRunning = false;
+ }
+}
+
+SdrEscapeDirection SdrEdgeObj::ImpCalcEscAngle(SdrObject const * pObj, const Point& rPt)
+{
+ if (pObj==nullptr) return SdrEscapeDirection::ALL;
+ tools::Rectangle aR(pObj->GetSnapRect());
+ tools::Long dxl=rPt.X()-aR.Left();
+ tools::Long dyo=rPt.Y()-aR.Top();
+ tools::Long dxr=aR.Right()-rPt.X();
+ tools::Long dyu=aR.Bottom()-rPt.Y();
+ bool bxMitt=std::abs(dxl-dxr)<2;
+ bool byMitt=std::abs(dyo-dyu)<2;
+ tools::Long dx=std::min(dxl,dxr);
+ tools::Long dy=std::min(dyo,dyu);
+ bool bDiag=std::abs(dx-dy)<2;
+ if (bxMitt && byMitt) return SdrEscapeDirection::ALL; // in the center
+ if (bDiag) { // diagonally
+ SdrEscapeDirection nRet=SdrEscapeDirection::SMART;
+ if (byMitt) nRet|=SdrEscapeDirection::VERT;
+ if (bxMitt) nRet|=SdrEscapeDirection::HORZ;
+ if (dxl<dxr) { // left
+ if (dyo<dyu) nRet|=SdrEscapeDirection::LEFT | SdrEscapeDirection::TOP;
+ else nRet|=SdrEscapeDirection::LEFT | SdrEscapeDirection::BOTTOM;
+ } else { // right
+ if (dyo<dyu) nRet|=SdrEscapeDirection::RIGHT | SdrEscapeDirection::TOP;
+ else nRet|=SdrEscapeDirection::RIGHT | SdrEscapeDirection::BOTTOM;
+ }
+ return nRet;
+ }
+ if (dx<dy) { // horizontal
+ if (bxMitt) return SdrEscapeDirection::HORZ;
+ if (dxl<dxr) return SdrEscapeDirection::LEFT;
+ else return SdrEscapeDirection::RIGHT;
+ } else { // vertical
+ if (byMitt) return SdrEscapeDirection::VERT;
+ if (dyo<dyu) return SdrEscapeDirection::TOP;
+ else return SdrEscapeDirection::BOTTOM;
+ }
+}
+
+XPolygon SdrEdgeObj::ImpCalcObjToCenter(const Point& rStPt, tools::Long nEscAngle, const tools::Rectangle& rRect, const Point& rMeeting)
+{
+ XPolygon aXP;
+ aXP.Insert(XPOLY_APPEND,rStPt,PolyFlags::Normal);
+ bool bRts=nEscAngle==0;
+ bool bObn=nEscAngle==9000;
+ bool bLks=nEscAngle==18000;
+ bool bUnt=nEscAngle==27000;
+
+ Point aP1(rStPt); // mandatory difference first,...
+ if (bLks) aP1.setX(rRect.Left() );
+ if (bRts) aP1.setX(rRect.Right() );
+ if (bObn) aP1.setY(rRect.Top() );
+ if (bUnt) aP1.setY(rRect.Bottom() );
+
+ Point aP2(aP1); // ...now increase to Meeting height, if necessary
+ if (bLks && rMeeting.X()<=aP2.X()) aP2.setX(rMeeting.X() );
+ if (bRts && rMeeting.X()>=aP2.X()) aP2.setX(rMeeting.X() );
+ if (bObn && rMeeting.Y()<=aP2.Y()) aP2.setY(rMeeting.Y() );
+ if (bUnt && rMeeting.Y()>=aP2.Y()) aP2.setY(rMeeting.Y() );
+ aXP.Insert(XPOLY_APPEND,aP2,PolyFlags::Normal);
+
+ Point aP3(aP2);
+ if ((bLks && rMeeting.X()>aP2.X()) || (bRts && rMeeting.X()<aP2.X())) { // around
+ if (rMeeting.Y()<aP2.Y()) {
+ aP3.setY(rRect.Top() );
+ if (rMeeting.Y()<aP3.Y()) aP3.setY(rMeeting.Y() );
+ } else {
+ aP3.setY(rRect.Bottom() );
+ if (rMeeting.Y()>aP3.Y()) aP3.setY(rMeeting.Y() );
+ }
+ aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
+ if (aP3.Y()!=rMeeting.Y()) {
+ aP3.setX(rMeeting.X() );
+ aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
+ }
+ }
+ if ((bObn && rMeeting.Y()>aP2.Y()) || (bUnt && rMeeting.Y()<aP2.Y())) { // around
+ if (rMeeting.X()<aP2.X()) {
+ aP3.setX(rRect.Left() );
+ if (rMeeting.X()<aP3.X()) aP3.setX(rMeeting.X() );
+ } else {
+ aP3.setX(rRect.Right() );
+ if (rMeeting.X()>aP3.X()) aP3.setX(rMeeting.X() );
+ }
+ aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
+ if (aP3.X()!=rMeeting.X()) {
+ aP3.setY(rMeeting.Y() );
+ aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
+ }
+ }
+#ifdef DBG_UTIL
+ if (aXP.GetPointCount()>4) {
+ OSL_FAIL("SdrEdgeObj::ImpCalcObjToCenter(): Polygon has more than 4 points!");
+ }
+#endif
+ return aXP;
+}
+
+XPolygon SdrEdgeObj::ImpCalcEdgeTrack(const XPolygon& rTrack0, SdrObjConnection& rCon1, SdrObjConnection& rCon2, SdrEdgeInfoRec* pInfo) const
+{
+ Point aPt1,aPt2;
+ SdrGluePoint aGP1,aGP2;
+ SdrEscapeDirection nEsc1=SdrEscapeDirection::ALL,nEsc2=SdrEscapeDirection::ALL;
+ tools::Rectangle aBoundRect1;
+ tools::Rectangle aBoundRect2;
+ tools::Rectangle aBewareRect1;
+ tools::Rectangle aBewareRect2;
+ // first, get the old corner points
+ if (rTrack0.GetPointCount()!=0) {
+ aPt1=rTrack0[0];
+ sal_uInt16 nSiz=rTrack0.GetPointCount();
+ nSiz--;
+ aPt2=rTrack0[nSiz];
+ } else {
+ if (!m_aOutRect.IsEmpty()) {
+ aPt1=m_aOutRect.TopLeft();
+ aPt2=m_aOutRect.BottomRight();
+ }
+ }
+
+ // #i54102# To allow interactive preview, do also if not inserted
+ const bool bCon1(nullptr != rCon1.pObj && rCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
+ const bool bCon2(nullptr != rCon2.pObj && rCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
+ const SfxItemSet& rSet = GetObjectItemSet();
+
+ if (bCon1)
+ {
+ if (rCon1.pObj==static_cast<SdrObject const *>(this))
+ {
+ // check, just in case
+ aBoundRect1=m_aOutRect;
+ }
+ else
+ {
+ aBoundRect1 = rCon1.pObj->GetCurrentBoundRect();
+ }
+
+ aBoundRect1.Move(rCon1.aObjOfs.X(),rCon1.aObjOfs.Y());
+ aBewareRect1=aBoundRect1;
+ sal_Int32 nH = rSet.Get(SDRATTR_EDGENODE1HORZDIST).GetValue();
+ sal_Int32 nV = rSet.Get(SDRATTR_EDGENODE1VERTDIST).GetValue();
+ aBewareRect1.AdjustLeft( -nH );
+ aBewareRect1.AdjustRight(nH );
+ aBewareRect1.AdjustTop( -nV );
+ aBewareRect1.AdjustBottom(nV );
+ }
+ else
+ {
+ aBoundRect1=tools::Rectangle(aPt1,aPt1);
+ aBoundRect1.Move(rCon1.aObjOfs.X(),rCon1.aObjOfs.Y());
+ aBewareRect1=aBoundRect1;
+ }
+
+ if (bCon2)
+ {
+ if (rCon2.pObj==static_cast<SdrObject const *>(this))
+ { // check, just in case
+ aBoundRect2=m_aOutRect;
+ }
+ else
+ {
+ aBoundRect2 = rCon2.pObj->GetCurrentBoundRect();
+ }
+
+ aBoundRect2.Move(rCon2.aObjOfs.X(),rCon2.aObjOfs.Y());
+ aBewareRect2=aBoundRect2;
+ sal_Int32 nH = rSet.Get(SDRATTR_EDGENODE2HORZDIST).GetValue();
+ sal_Int32 nV = rSet.Get(SDRATTR_EDGENODE2VERTDIST).GetValue();
+ aBewareRect2.AdjustLeft( -nH );
+ aBewareRect2.AdjustRight(nH );
+ aBewareRect2.AdjustTop( -nV );
+ aBewareRect2.AdjustBottom(nV );
+ }
+ else
+ {
+ aBoundRect2=tools::Rectangle(aPt2,aPt2);
+ aBoundRect2.Move(rCon2.aObjOfs.X(),rCon2.aObjOfs.Y());
+ aBewareRect2=aBoundRect2;
+ }
+
+ XPolygon aBestXP;
+ sal_uIntPtr nBestQual=0xFFFFFFFF;
+ SdrEdgeInfoRec aBestInfo;
+ bool bAuto1=bCon1 && rCon1.bBestVertex;
+ bool bAuto2=bCon2 && rCon2.bBestVertex;
+ if (bAuto1) rCon1.bAutoVertex=true;
+ if (bAuto2) rCon2.bAutoVertex=true;
+ sal_uInt16 nBestAuto1=0;
+ sal_uInt16 nBestAuto2=0;
+ sal_uInt16 nCount1=bAuto1 ? 4 : 1;
+ sal_uInt16 nCount2=bAuto2 ? 4 : 1;
+
+ for (sal_uInt16 nNum1=0; nNum1<nCount1; nNum1++)
+ {
+ if (bAuto1) rCon1.nConId=nNum1;
+ if (bCon1 && rCon1.TakeGluePoint(aGP1))
+ {
+ aPt1=aGP1.GetPos();
+ nEsc1=aGP1.GetEscDir();
+ if (nEsc1==SdrEscapeDirection::SMART) nEsc1=ImpCalcEscAngle(rCon1.pObj,aPt1-rCon1.aObjOfs);
+ }
+ for (sal_uInt16 nNum2=0; nNum2<nCount2; nNum2++)
+ {
+ if (bAuto2) rCon2.nConId=nNum2;
+ if (bCon2 && rCon2.TakeGluePoint(aGP2))
+ {
+ aPt2=aGP2.GetPos();
+ nEsc2=aGP2.GetEscDir();
+ if (nEsc2==SdrEscapeDirection::SMART) nEsc2=ImpCalcEscAngle(rCon2.pObj,aPt2-rCon2.aObjOfs);
+ }
+ for (tools::Long nA1=0; nA1<36000; nA1+=9000)
+ {
+ SdrEscapeDirection nE1 = nA1==0 ? SdrEscapeDirection::RIGHT : nA1==9000 ? SdrEscapeDirection::TOP : nA1==18000 ? SdrEscapeDirection::LEFT : nA1==27000 ? SdrEscapeDirection::BOTTOM : SdrEscapeDirection::SMART;
+ for (tools::Long nA2=0; nA2<36000; nA2+=9000)
+ {
+ SdrEscapeDirection nE2 = nA2==0 ? SdrEscapeDirection::RIGHT : nA2==9000 ? SdrEscapeDirection::TOP : nA2==18000 ? SdrEscapeDirection::LEFT : nA2==27000 ? SdrEscapeDirection::BOTTOM : SdrEscapeDirection::SMART;
+ if ((nEsc1&nE1) && (nEsc2&nE2))
+ {
+ sal_uIntPtr nQual=0;
+ SdrEdgeInfoRec aInfo;
+ if (pInfo!=nullptr) aInfo=*pInfo;
+ XPolygon aXP(ImpCalcEdgeTrack(aPt1,nA1,aBoundRect1,aBewareRect1,aPt2,nA2,aBoundRect2,aBewareRect2,&nQual,&aInfo));
+ if (nQual<nBestQual)
+ {
+ aBestXP=std::move(aXP);
+ nBestQual=nQual;
+ aBestInfo=aInfo;
+ nBestAuto1=nNum1;
+ nBestAuto2=nNum2;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (bAuto1) rCon1.nConId=nBestAuto1;
+ if (bAuto2) rCon2.nConId=nBestAuto2;
+ if (pInfo!=nullptr) *pInfo=aBestInfo;
+ return aBestXP;
+}
+
+XPolygon SdrEdgeObj::ImpCalcEdgeTrack(const Point& rPt1, tools::Long nAngle1, const tools::Rectangle& rBoundRect1, const tools::Rectangle& rBewareRect1,
+ const Point& rPt2, tools::Long nAngle2, const tools::Rectangle& rBoundRect2, const tools::Rectangle& rBewareRect2,
+ sal_uIntPtr* pnQuality, SdrEdgeInfoRec* pInfo) const
+{
+ SdrEdgeKind eKind=GetObjectItem(SDRATTR_EDGEKIND).GetValue();
+ bool bRts1=nAngle1==0;
+ bool bObn1=nAngle1==9000;
+ bool bLks1=nAngle1==18000;
+ bool bUnt1=nAngle1==27000;
+ bool bHor1=bLks1 || bRts1;
+ bool bVer1=bObn1 || bUnt1;
+ bool bRts2=nAngle2==0;
+ bool bObn2=nAngle2==9000;
+ bool bLks2=nAngle2==18000;
+ bool bUnt2=nAngle2==27000;
+ bool bHor2=bLks2 || bRts2;
+ bool bVer2=bObn2 || bUnt2;
+ bool bInfo=pInfo!=nullptr;
+ if (bInfo) {
+ pInfo->nAngle1=nAngle1;
+ pInfo->nAngle2=nAngle2;
+ pInfo->nObj1Lines=1;
+ pInfo->nObj2Lines=1;
+ pInfo->nMiddleLine=0xFFFF;
+ }
+ Point aPt1(rPt1);
+ Point aPt2(rPt2);
+ tools::Rectangle aBoundRect1 (rBoundRect1 );
+ tools::Rectangle aBoundRect2 (rBoundRect2 );
+ tools::Rectangle aBewareRect1(rBewareRect1);
+ tools::Rectangle aBewareRect2(rBewareRect2);
+ Point aMeeting((aPt1.X()+aPt2.X()+1)/2,(aPt1.Y()+aPt2.Y()+1)/2);
+ if (eKind==SdrEdgeKind::OneLine) {
+ XPolygon aXP(2);
+ aXP[0]=rPt1;
+ aXP[1]=rPt2;
+ if (pnQuality!=nullptr) {
+ *pnQuality=std::abs(rPt1.X()-rPt2.X())+std::abs(rPt1.Y()-rPt2.Y());
+ }
+ return aXP;
+ } else if (eKind==SdrEdgeKind::ThreeLines) {
+ XPolygon aXP(4);
+ aXP[0]=rPt1;
+ aXP[1]=rPt1;
+ aXP[2]=rPt2;
+ aXP[3]=rPt2;
+ if (bRts1) aXP[1].setX(aBewareRect1.Right() ); //+=500;
+ if (bObn1) aXP[1].setY(aBewareRect1.Top() ); //-=500;
+ if (bLks1) aXP[1].setX(aBewareRect1.Left() ); //-=500;
+ if (bUnt1) aXP[1].setY(aBewareRect1.Bottom() ); //+=500;
+ if (bRts2) aXP[2].setX(aBewareRect2.Right() ); //+=500;
+ if (bObn2) aXP[2].setY(aBewareRect2.Top() ); //-=500;
+ if (bLks2) aXP[2].setX(aBewareRect2.Left() ); //-=500;
+ if (bUnt2) aXP[2].setY(aBewareRect2.Bottom() ); //+=500;
+ if (pnQuality!=nullptr) {
+ tools::Long nQ=std::abs(aXP[1].X()-aXP[0].X())+std::abs(aXP[1].Y()-aXP[0].Y());
+ nQ+=std::abs(aXP[2].X()-aXP[1].X())+std::abs(aXP[2].Y()-aXP[1].Y());
+ nQ+=std::abs(aXP[3].X()-aXP[2].X())+std::abs(aXP[3].Y()-aXP[2].Y());
+ *pnQuality=nQ;
+ }
+ if (bInfo) {
+ pInfo->nObj1Lines=2;
+ pInfo->nObj2Lines=2;
+ if (bHor1) {
+ aXP[1].AdjustX(pInfo->aObj1Line2.X() );
+ } else {
+ aXP[1].AdjustY(pInfo->aObj1Line2.Y() );
+ }
+ if (bHor2) {
+ aXP[2].AdjustX(pInfo->aObj2Line2.X() );
+ } else {
+ aXP[2].AdjustY(pInfo->aObj2Line2.Y() );
+ }
+ }
+ return aXP;
+ }
+ sal_uInt16 nIntersections=0;
+ {
+ Point aC1(aBewareRect1.Center());
+ Point aC2(aBewareRect2.Center());
+ if (aBewareRect1.Left()<=aBewareRect2.Right() && aBewareRect1.Right()>=aBewareRect2.Left()) {
+ // overlapping on the x axis
+ tools::Long n1=std::max(aBewareRect1.Left(),aBewareRect2.Left());
+ tools::Long n2=std::min(aBewareRect1.Right(),aBewareRect2.Right());
+ aMeeting.setX((n1+n2+1)/2 );
+ } else {
+ // otherwise the center point of the empty space
+ if (aC1.X()<aC2.X()) {
+ aMeeting.setX((aBewareRect1.Right()+aBewareRect2.Left()+1)/2 );
+ } else {
+ aMeeting.setX((aBewareRect1.Left()+aBewareRect2.Right()+1)/2 );
+ }
+ }
+ if (aBewareRect1.Top()<=aBewareRect2.Bottom() && aBewareRect1.Bottom()>=aBewareRect2.Top()) {
+ // overlapping on the x axis
+ tools::Long n1=std::max(aBewareRect1.Top(),aBewareRect2.Top());
+ tools::Long n2=std::min(aBewareRect1.Bottom(),aBewareRect2.Bottom());
+ aMeeting.setY((n1+n2+1)/2 );
+ } else {
+ // otherwise the center point of the empty space
+ if (aC1.Y()<aC2.Y()) {
+ aMeeting.setY((aBewareRect1.Bottom()+aBewareRect2.Top()+1)/2 );
+ } else {
+ aMeeting.setY((aBewareRect1.Top()+aBewareRect2.Bottom()+1)/2 );
+ }
+ }
+ // Here, there are three cases:
+ // 1. both go into the same direction
+ // 2. both go into opposite directions
+ // 3. one is vertical, the other is horizontal
+ tools::Long nXMin=std::min(aBewareRect1.Left(),aBewareRect2.Left());
+ tools::Long nXMax=std::max(aBewareRect1.Right(),aBewareRect2.Right());
+ tools::Long nYMin=std::min(aBewareRect1.Top(),aBewareRect2.Top());
+ tools::Long nYMax=std::max(aBewareRect1.Bottom(),aBewareRect2.Bottom());
+ bool bBewareOverlap=aBewareRect1.Right()>aBewareRect2.Left() && aBewareRect1.Left()<aBewareRect2.Right() &&
+ aBewareRect1.Bottom()>aBewareRect2.Top() && aBewareRect1.Top()<aBewareRect2.Bottom();
+ unsigned nMainCase=3;
+ if (nAngle1==nAngle2) nMainCase=1;
+ else if ((bHor1 && bHor2) || (bVer1 && bVer2)) nMainCase=2;
+ if (nMainCase==1) { // case 1 (both go in one direction) is possible
+ if (bVer1) aMeeting.setX((aPt1.X()+aPt2.X()+1)/2 ); // Here, this is better than
+ if (bHor1) aMeeting.setY((aPt1.Y()+aPt2.Y()+1)/2 ); // using center point of empty space
+ // bX1Ok means that the vertical exiting Obj1 doesn't conflict with Obj2, ...
+ bool bX1Ok=aPt1.X()<=aBewareRect2.Left() || aPt1.X()>=aBewareRect2.Right();
+ bool bX2Ok=aPt2.X()<=aBewareRect1.Left() || aPt2.X()>=aBewareRect1.Right();
+ bool bY1Ok=aPt1.Y()<=aBewareRect2.Top() || aPt1.Y()>=aBewareRect2.Bottom();
+ bool bY2Ok=aPt2.Y()<=aBewareRect1.Top() || aPt2.Y()>=aBewareRect1.Bottom();
+ if (bLks1 && (bY1Ok || aBewareRect1.Left()<aBewareRect2.Right()) && (bY2Ok || aBewareRect2.Left()<aBewareRect1.Right())) {
+ aMeeting.setX(nXMin );
+ }
+ if (bRts1 && (bY1Ok || aBewareRect1.Right()>aBewareRect2.Left()) && (bY2Ok || aBewareRect2.Right()>aBewareRect1.Left())) {
+ aMeeting.setX(nXMax );
+ }
+ if (bObn1 && (bX1Ok || aBewareRect1.Top()<aBewareRect2.Bottom()) && (bX2Ok || aBewareRect2.Top()<aBewareRect1.Bottom())) {
+ aMeeting.setY(nYMin );
+ }
+ if (bUnt1 && (bX1Ok || aBewareRect1.Bottom()>aBewareRect2.Top()) && (bX2Ok || aBewareRect2.Bottom()>aBewareRect1.Top())) {
+ aMeeting.setY(nYMax );
+ }
+ } else if (nMainCase==2) {
+ // case 2:
+ if (bHor1) { // both horizontal
+ /* 9 sub-cases:
+ (legend: line exits to the left (-|), right (|-))
+
+ 2.1: Facing; overlap only on y axis
+ * * *
+ |--| *
+ * * *
+
+ 2.2, 2.3: Facing, offset vertically; no overlap on either
+ axis
+ |- * * * * *
+ * -| * * -| *
+ * * * , * * *
+
+ 2.4, 2.5: One below the other; overlap only on y axis
+ * |- * * * *
+ * -| * * -| *
+ * * * , * |- *
+
+ 2.6, 2.7: Not facing, offset vertically; no overlap on either
+ axis
+ * * |- * * *
+ * -| * * -| *
+ * * * , * * |-
+
+ 2.8: Not facing; overlap only on y axis
+ * * *
+ * -| |-
+ * * *
+
+ 2.9: The objects's BewareRects overlap on x and y axis
+
+ These cases, with some modifications are also valid for
+ horizontal line exits.
+ Cases 2.1 through 2.7 are covered well enough with the
+ default meetings. Only for cases 2.8 and 2.9 do we determine
+ special meeting points here.
+ */
+
+ // normalization; be aR1 the one exiting to the right,
+ // be aR2 the one exiting to the left
+ tools::Rectangle aBewR1(bRts1 ? aBewareRect1 : aBewareRect2);
+ tools::Rectangle aBewR2(bRts1 ? aBewareRect2 : aBewareRect1);
+ tools::Rectangle aBndR1(bRts1 ? aBoundRect1 : aBoundRect2);
+ tools::Rectangle aBndR2(bRts1 ? aBoundRect2 : aBoundRect1);
+ if (aBewR1.Bottom()>aBewR2.Top() && aBewR1.Top()<aBewR2.Bottom()) {
+ // overlap on y axis; cases 2.1, 2.8, 2.9
+ if (aBewR1.Right()>aBewR2.Left()) {
+ /* Cases 2.8, 2.9:
+ Case 2.8: always going around on the outside
+ (bDirect=false).
+
+ Case 2.9 could also be a direct connection (in the
+ case that the BewareRects overlap only slightly and
+ the BoundRects don't overlap at all and if the
+ line exits would otherwise violate the respective
+ other object's BewareRect).
+ */
+ bool bCase29Direct = false;
+ bool bCase29=aBewR1.Right()>aBewR2.Left();
+ if (aBndR1.Right()<=aBndR2.Left()) { // case 2.9 without BoundRect overlap
+ if ((aPt1.Y()>aBewareRect2.Top() && aPt1.Y()<aBewareRect2.Bottom()) ||
+ (aPt2.Y()>aBewareRect1.Top() && aPt2.Y()<aBewareRect1.Bottom())) {
+ bCase29Direct = true;
+ }
+ }
+ if (!bCase29Direct) {
+ bool bObenLang=std::abs(nYMin-aMeeting.Y())<=std::abs(nYMax-aMeeting.Y());
+ if (bObenLang) {
+ aMeeting.setY(nYMin );
+ } else {
+ aMeeting.setY(nYMax );
+ }
+ if (bCase29) {
+ // now make sure that the surrounded object
+ // isn't traversed
+ if ((aBewR1.Center().Y()<aBewR2.Center().Y()) != bObenLang) {
+ aMeeting.setX(aBewR2.Right() );
+ } else {
+ aMeeting.setX(aBewR1.Left() );
+ }
+ }
+ } else {
+ // We need a direct connection (3-line Z connection),
+ // because we have to violate the BewareRects.
+ // Use rule of three to scale down the BewareRects.
+ tools::Long nWant1=aBewR1.Right()-aBndR1.Right(); // distance at Obj1
+ tools::Long nWant2=aBndR2.Left()-aBewR2.Left(); // distance at Obj2
+ tools::Long nSpace=aBndR2.Left()-aBndR1.Right(); // available space
+ tools::Long nGet1=BigMulDiv(nWant1,nSpace,nWant1+nWant2);
+ tools::Long nGet2=nSpace-nGet1;
+ if (bRts1) { // revert normalization
+ aBewareRect1.AdjustRight(nGet1-nWant1 );
+ aBewareRect2.AdjustLeft( -(nGet2-nWant2) );
+ } else {
+ aBewareRect2.AdjustRight(nGet1-nWant1 );
+ aBewareRect1.AdjustLeft( -(nGet2-nWant2) );
+ }
+ nIntersections++; // lower quality
+ }
+ }
+ }
+ } else if (bVer1) { // both horizontal
+ tools::Rectangle aBewR1(bUnt1 ? aBewareRect1 : aBewareRect2);
+ tools::Rectangle aBewR2(bUnt1 ? aBewareRect2 : aBewareRect1);
+ tools::Rectangle aBndR1(bUnt1 ? aBoundRect1 : aBoundRect2);
+ tools::Rectangle aBndR2(bUnt1 ? aBoundRect2 : aBoundRect1);
+ if (aBewR1.Right()>aBewR2.Left() && aBewR1.Left()<aBewR2.Right()) {
+ // overlap on y axis; cases 2.1, 2.8, 2.9
+ if (aBewR1.Bottom()>aBewR2.Top()) {
+ /* Cases 2.8, 2.9
+ Case 2.8 always going around on the outside (bDirect=false).
+
+ Case 2.9 could also be a direct connection (in the
+ case that the BewareRects overlap only slightly and
+ the BoundRects don't overlap at all and if the
+ line exits would otherwise violate the respective
+ other object's BewareRect).
+ */
+ bool bCase29Direct = false;
+ bool bCase29=aBewR1.Bottom()>aBewR2.Top();
+ if (aBndR1.Bottom()<=aBndR2.Top()) { // case 2.9 without BoundRect overlap
+ if ((aPt1.X()>aBewareRect2.Left() && aPt1.X()<aBewareRect2.Right()) ||
+ (aPt2.X()>aBewareRect1.Left() && aPt2.X()<aBewareRect1.Right())) {
+ bCase29Direct = true;
+ }
+ }
+ if (!bCase29Direct) {
+ bool bLinksLang=std::abs(nXMin-aMeeting.X())<=std::abs(nXMax-aMeeting.X());
+ if (bLinksLang) {
+ aMeeting.setX(nXMin );
+ } else {
+ aMeeting.setX(nXMax );
+ }
+ if (bCase29) {
+ // now make sure that the surrounded object
+ // isn't traversed
+ if ((aBewR1.Center().X()<aBewR2.Center().X()) != bLinksLang) {
+ aMeeting.setY(aBewR2.Bottom() );
+ } else {
+ aMeeting.setY(aBewR1.Top() );
+ }
+ }
+ } else {
+ // We need a direct connection (3-line Z connection),
+ // because we have to violate the BewareRects.
+ // Use rule of three to scale down the BewareRects.
+ tools::Long nWant1=aBewR1.Bottom()-aBndR1.Bottom(); // difference at Obj1
+ tools::Long nWant2=aBndR2.Top()-aBewR2.Top(); // difference at Obj2
+ tools::Long nSpace=aBndR2.Top()-aBndR1.Bottom(); // available space
+ tools::Long nGet1=BigMulDiv(nWant1,nSpace,nWant1+nWant2);
+ tools::Long nGet2=nSpace-nGet1;
+ if (bUnt1) { // revert normalization
+ aBewareRect1.AdjustBottom(nGet1-nWant1 );
+ aBewareRect2.AdjustTop( -(nGet2-nWant2) );
+ } else {
+ aBewareRect2.AdjustBottom(nGet1-nWant1 );
+ aBewareRect1.AdjustTop( -(nGet2-nWant2) );
+ }
+ nIntersections++; // lower quality
+ }
+ }
+ }
+ }
+ } else if (nMainCase==3) { // case 3: one horizontal, the other vertical
+ /* legend:
+ The line exits to the:
+ -| left
+
+ |- right
+
+ _|_ top
+
+ T bottom
+
+ * . * . * -- no overlap, at most might touch
+ . . . . . -- overlap
+ * . |- . * -- same height
+ . . . . . -- overlap
+ * . * . * -- no overlap, at most might touch
+
+ Overall, there are 96 possible constellations, some of these can't even
+ be unambiguously assigned to a certain case/method of handling.
+
+
+ 3.1: All those constellations that are covered reasonably well
+ by the default MeetingPoint (20+12).
+
+ T T T . _|_ _|_ . T T T these 12 * . * T * * . * . * * T * . * * . * . *
+ . . . . _|_ _|_ . . . . constellations . . . . . . . . . T . . . . . T . . . .
+ * . |- . * * . -| . * are covered * . |- . _|_ * . |- . T _|_ . -| . * T . -| . *
+ . . . . T T . . . . only in . . . . _|_ . . . . . _|_ . . . . . . . . .
+ _|__|__|_ . T T . _|__|__|_ part: * . * _|_ * * . * . * * _|_ * . * * . * . *
+
+ The last 16 of these cases can be excluded, if the objects face each other openly.
+
+
+ 3.2: The objects face each other openly, thus a connection using only two lines is possible (4+20);
+ This case is priority #1.
+ * . * . T T . * . * these 20 * . * T * * T * . * * . * . * * . * . *
+ . . . . . . . . . . constellations . . . T T T T . . . . . . . . . . . . .
+ * . |- . * * . -| . * are covered * . |-_|__|_ _|__|_-| . * * . |- T T T T -| . *
+ . . . . . . . . . . only in . . . _|__|_ _|__|_ . . . . . . . . . . . . .
+ * . * . _|_ _|_ . * . * part: * . * _|_ * * _|_ * . * * . * . * * . * . *
+
+ 3.3: The line exits point away from the other object or miss its back (52+4).
+ _|__|__|__|_ * * _|__|__|__|_ * . . . * * . * . * these 4 * . * . * * . * . *
+ _|__|__|__|_ . . _|__|__|__|_ T T T . . . . T T T constellations . . . T . . T . . .
+ _|__|_ |- . * * . -| _|__|_ T T |- . * * . -| T T are covered * . |- . * * . -| . *
+ _|__|__|_ . . . . _|__|__|_ T T T T . . T T T T only in . . . _|_ . . _|_ . . .
+ * . * . * * . * . * T T T T * * T T T T part: * . * . * * . * . *
+ */
+
+ // case 3.2
+ tools::Rectangle aTmpR1(aBewareRect1);
+ tools::Rectangle aTmpR2(aBewareRect2);
+ if (bBewareOverlap) {
+ // overlapping BewareRects: use BoundRects for checking for case 3.2
+ aTmpR1=aBoundRect1;
+ aTmpR2=aBoundRect2;
+ }
+ if ((((bRts1 && aTmpR1.Right ()<=aPt2.X()) || (bLks1 && aTmpR1.Left()>=aPt2.X())) &&
+ ((bUnt2 && aTmpR2.Bottom()<=aPt1.Y()) || (bObn2 && aTmpR2.Top ()>=aPt1.Y()))) ||
+ (((bRts2 && aTmpR2.Right ()<=aPt1.X()) || (bLks2 && aTmpR2.Left()>=aPt1.X())) &&
+ ((bUnt1 && aTmpR1.Bottom()<=aPt2.Y()) || (bObn1 && aTmpR1.Top ()>=aPt2.Y())))) {
+ // case 3.2 applies: connector with only 2 lines
+ if (bHor1) {
+ aMeeting.setX(aPt2.X() );
+ aMeeting.setY(aPt1.Y() );
+ } else {
+ aMeeting.setX(aPt1.X() );
+ aMeeting.setY(aPt2.Y() );
+ }
+ // in the case of overlapping BewareRects:
+ aBewareRect1=aTmpR1;
+ aBewareRect2=aTmpR2;
+ } else if ((((bRts1 && aBewareRect1.Right ()>aBewareRect2.Left ()) ||
+ (bLks1 && aBewareRect1.Left ()<aBewareRect2.Right ())) &&
+ ((bUnt2 && aBewareRect2.Bottom()>aBewareRect1.Top ()) ||
+ (bObn2 && aBewareRect2.Top ()<aBewareRect1.Bottom()))) ||
+ (((bRts2 && aBewareRect2.Right ()>aBewareRect1.Left ()) ||
+ (bLks2 && aBewareRect2.Left ()<aBewareRect1.Right ())) &&
+ ((bUnt1 && aBewareRect1.Bottom()>aBewareRect2.Top ()) ||
+ (bObn1 && aBewareRect1.Top ()<aBewareRect2.Bottom())))) {
+ // case 3.3
+ if (bRts1 || bRts2) { aMeeting.setX(nXMax ); }
+ if (bLks1 || bLks2) { aMeeting.setX(nXMin ); }
+ if (bUnt1 || bUnt2) { aMeeting.setY(nYMax ); }
+ if (bObn1 || bObn2) { aMeeting.setY(nYMin ); }
+ }
+ }
+ }
+
+ XPolygon aXP1(ImpCalcObjToCenter(aPt1,nAngle1,aBewareRect1,aMeeting));
+ XPolygon aXP2(ImpCalcObjToCenter(aPt2,nAngle2,aBewareRect2,aMeeting));
+ sal_uInt16 nXP1Cnt=aXP1.GetPointCount();
+ sal_uInt16 nXP2Cnt=aXP2.GetPointCount();
+ if (bInfo) {
+ pInfo->nObj1Lines=nXP1Cnt; if (nXP1Cnt>1) pInfo->nObj1Lines--;
+ pInfo->nObj2Lines=nXP2Cnt; if (nXP2Cnt>1) pInfo->nObj2Lines--;
+ }
+ Point aEP1(aXP1[nXP1Cnt-1]);
+ Point aEP2(aXP2[nXP2Cnt-1]);
+ bool bInsMeetingPoint=aEP1.X()!=aEP2.X() && aEP1.Y()!=aEP2.Y();
+ bool bHorzE1=aEP1.Y()==aXP1[nXP1Cnt-2].Y(); // is last line of XP1 horizontal?
+ bool bHorzE2=aEP2.Y()==aXP2[nXP2Cnt-2].Y(); // is last line of XP2 horizontal?
+ if (aEP1==aEP2 && ((bHorzE1 && bHorzE2 && aEP1.Y()==aEP2.Y()) || (!bHorzE1 && !bHorzE2 && aEP1.X()==aEP2.X()))) {
+ // special casing 'I' connectors
+ nXP1Cnt--; aXP1.Remove(nXP1Cnt,1);
+ nXP2Cnt--; aXP2.Remove(nXP2Cnt,1);
+ }
+ if (bInsMeetingPoint) {
+ aXP1.Insert(XPOLY_APPEND,aMeeting,PolyFlags::Normal);
+ if (bInfo) {
+ // Inserting a MeetingPoint adds 2 new lines,
+ // either might become the center line.
+ if (pInfo->nObj1Lines==pInfo->nObj2Lines) {
+ pInfo->nObj1Lines++;
+ pInfo->nObj2Lines++;
+ } else {
+ if (pInfo->nObj1Lines>pInfo->nObj2Lines) {
+ pInfo->nObj2Lines++;
+ pInfo->nMiddleLine=nXP1Cnt-1;
+ } else {
+ pInfo->nObj1Lines++;
+ pInfo->nMiddleLine=nXP1Cnt;
+ }
+ }
+ }
+ } else if (bInfo && aEP1!=aEP2 && nXP1Cnt+nXP2Cnt>=4) {
+ // By connecting both ends, another line is added, this becomes the center line.
+ pInfo->nMiddleLine=nXP1Cnt-1;
+ }
+ sal_uInt16 nNum=aXP2.GetPointCount();
+ if (aXP1[nXP1Cnt-1]==aXP2[nXP2Cnt-1] && nXP1Cnt>1 && nXP2Cnt>1) nNum--;
+ while (nNum>0) {
+ nNum--;
+ aXP1.Insert(XPOLY_APPEND,aXP2[nNum],PolyFlags::Normal);
+ }
+ sal_uInt16 nPointCount=aXP1.GetPointCount();
+ char cForm;
+ if (bInfo || pnQuality!=nullptr) {
+ if (nPointCount==2) cForm='I';
+ else if (nPointCount==3) cForm='L';
+ else if (nPointCount==4) { // Z or U
+ if (nAngle1==nAngle2) cForm='U';
+ else cForm='Z';
+ } else if (nPointCount==6) { // S or C or ...
+ if (nAngle1!=nAngle2) {
+ // For type S, line 2 has the same direction as line 4.
+ // For type C, the opposite is true.
+ Point aP1(aXP1[1]);
+ Point aP2(aXP1[2]);
+ Point aP3(aXP1[3]);
+ Point aP4(aXP1[4]);
+ if (aP1.Y()==aP2.Y()) { // else both lines are horizontal
+ if ((aP1.X()<aP2.X())==(aP3.X()<aP4.X())) cForm='S';
+ else cForm='C';
+ } else { // else both lines are vertical
+ if ((aP1.Y()<aP2.Y())==(aP3.Y()<aP4.Y())) cForm='S';
+ else cForm='C';
+ }
+ } else cForm='4'; // else is case 3 with 5 lines
+ } else cForm='?';
+ // more shapes:
+ if (bInfo) {
+ if (cForm=='I' || cForm=='L' || cForm=='Z' || cForm=='U') {
+ pInfo->nObj1Lines=1;
+ pInfo->nObj2Lines=1;
+ if (cForm=='Z' || cForm=='U') {
+ pInfo->nMiddleLine=1;
+ } else {
+ pInfo->nMiddleLine=0xFFFF;
+ }
+ } else if (cForm=='S' || cForm=='C') {
+ pInfo->nObj1Lines=2;
+ pInfo->nObj2Lines=2;
+ pInfo->nMiddleLine=2;
+ }
+ }
+ }
+ else
+ {
+ cForm = 0;
+ }
+ if (pnQuality!=nullptr) {
+ sal_uIntPtr nQual=0;
+ sal_uIntPtr nQual0=nQual; // prevent overruns
+ bool bOverflow = false;
+ Point aPt0(aXP1[0]);
+ for (sal_uInt16 nPntNum=1; nPntNum<nPointCount; nPntNum++) {
+ Point aPt1b(aXP1[nPntNum]);
+ nQual+=std::abs(aPt1b.X()-aPt0.X())+std::abs(aPt1b.Y()-aPt0.Y());
+ if (nQual<nQual0) bOverflow = true;
+ nQual0=nQual;
+ aPt0=aPt1b;
+ }
+
+ sal_uInt16 nTmp=nPointCount;
+ if (cForm=='Z') {
+ nTmp=2; // Z shape with good quality (nTmp=2 instead of 4)
+ sal_uIntPtr n1=std::abs(aXP1[1].X()-aXP1[0].X())+std::abs(aXP1[1].Y()-aXP1[0].Y());
+ sal_uIntPtr n2=std::abs(aXP1[2].X()-aXP1[1].X())+std::abs(aXP1[2].Y()-aXP1[1].Y());
+ sal_uIntPtr n3=std::abs(aXP1[3].X()-aXP1[2].X())+std::abs(aXP1[3].Y()-aXP1[2].Y());
+ // try to make lines lengths similar
+ sal_uIntPtr nBesser=0;
+ n1+=n3;
+ n3=n2/4;
+ if (n1>=n2) nBesser=6;
+ else if (n1>=3*n3) nBesser=4;
+ else if (n1>=2*n3) nBesser=2;
+ if (aXP1[0].Y()!=aXP1[1].Y()) nBesser++; // vertical starting line gets a plus (for H/V-Prio)
+ if (nQual>nBesser) nQual-=nBesser; else nQual=0;
+ }
+ if (nTmp>=3) {
+ nQual0=nQual;
+ nQual+=static_cast<sal_uIntPtr>(nTmp)*0x01000000;
+ if (nQual<nQual0 || nTmp>15) bOverflow = true;
+ }
+ if (nPointCount>=2) { // check exit angle again
+ Point aP1(aXP1[1]); aP1-=aXP1[0];
+ Point aP2(aXP1[nPointCount-2]); aP2-=aXP1[nPointCount-1];
+ tools::Long nAng1=0; if (aP1.X()<0) nAng1=18000; if (aP1.Y()>0) nAng1=27000;
+ if (aP1.Y()<0) nAng1=9000;
+ if (aP1.X()!=0 && aP1.Y()!=0) nAng1=1; // slant?!
+ tools::Long nAng2=0; if (aP2.X()<0) nAng2=18000; if (aP2.Y()>0) nAng2=27000;
+ if (aP2.Y()<0) nAng2=9000;
+ if (aP2.X()!=0 && aP2.Y()!=0) nAng2=1; // slant?!
+ if (nAng1!=nAngle1) nIntersections++;
+ if (nAng2!=nAngle2) nIntersections++;
+ }
+
+ // For the quality check, use the original Rects and at the same time
+ // check whether one them was scaled down for the calculation of the
+ // Edges (e. g. case 2.9)
+ aBewareRect1=rBewareRect1;
+ aBewareRect2=rBewareRect2;
+
+ for (sal_uInt16 i=0; i<nPointCount; i++) {
+ Point aPt1b(aXP1[i]);
+ bool b1=aPt1b.X()>aBewareRect1.Left() && aPt1b.X()<aBewareRect1.Right() &&
+ aPt1b.Y()>aBewareRect1.Top() && aPt1b.Y()<aBewareRect1.Bottom();
+ bool b2=aPt1b.X()>aBewareRect2.Left() && aPt1b.X()<aBewareRect2.Right() &&
+ aPt1b.Y()>aBewareRect2.Top() && aPt1b.Y()<aBewareRect2.Bottom();
+ sal_uInt16 nInt0=nIntersections;
+ if (i==0 || i==nPointCount-1) {
+ if (b1 && b2) nIntersections++;
+ } else {
+ if (b1) nIntersections++;
+ if (b2) nIntersections++;
+ }
+ // check for overlaps
+ if (i>0 && nInt0==nIntersections) {
+ if (aPt0.Y()==aPt1b.Y()) { // horizontal line
+ if (aPt0.Y()>aBewareRect1.Top() && aPt0.Y()<aBewareRect1.Bottom() &&
+ ((aPt0.X()<=aBewareRect1.Left() && aPt1b.X()>=aBewareRect1.Right()) ||
+ (aPt1b.X()<=aBewareRect1.Left() && aPt0.X()>=aBewareRect1.Right()))) nIntersections++;
+ if (aPt0.Y()>aBewareRect2.Top() && aPt0.Y()<aBewareRect2.Bottom() &&
+ ((aPt0.X()<=aBewareRect2.Left() && aPt1b.X()>=aBewareRect2.Right()) ||
+ (aPt1b.X()<=aBewareRect2.Left() && aPt0.X()>=aBewareRect2.Right()))) nIntersections++;
+ } else { // vertical line
+ if (aPt0.X()>aBewareRect1.Left() && aPt0.X()<aBewareRect1.Right() &&
+ ((aPt0.Y()<=aBewareRect1.Top() && aPt1b.Y()>=aBewareRect1.Bottom()) ||
+ (aPt1b.Y()<=aBewareRect1.Top() && aPt0.Y()>=aBewareRect1.Bottom()))) nIntersections++;
+ if (aPt0.X()>aBewareRect2.Left() && aPt0.X()<aBewareRect2.Right() &&
+ ((aPt0.Y()<=aBewareRect2.Top() && aPt1b.Y()>=aBewareRect2.Bottom()) ||
+ (aPt1b.Y()<=aBewareRect2.Top() && aPt0.Y()>=aBewareRect2.Bottom()))) nIntersections++;
+ }
+ }
+ aPt0=aPt1b;
+ }
+ if (nPointCount<=1) nIntersections++;
+ nQual0=nQual;
+ nQual+=static_cast<sal_uIntPtr>(nIntersections)*0x10000000;
+ if (nQual<nQual0 || nIntersections>15) bOverflow = true;
+
+ if (bOverflow || nQual==0xFFFFFFFF) nQual=0xFFFFFFFE;
+ *pnQuality=nQual;
+ }
+ if (bInfo) { // now apply line offsets to aXP1
+ if (pInfo->nMiddleLine!=0xFFFF) {
+ sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::MiddleLine,aXP1);
+ if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::MiddleLine,aXP1)) {
+ aXP1[nIdx].AdjustY(pInfo->aMiddleLine.Y() );
+ aXP1[nIdx+1].AdjustY(pInfo->aMiddleLine.Y() );
+ } else {
+ aXP1[nIdx].AdjustX(pInfo->aMiddleLine.X() );
+ aXP1[nIdx+1].AdjustX(pInfo->aMiddleLine.X() );
+ }
+ }
+ if (pInfo->nObj1Lines>=2) {
+ sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj1Line2,aXP1);
+ if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj1Line2,aXP1)) {
+ aXP1[nIdx].AdjustY(pInfo->aObj1Line2.Y() );
+ aXP1[nIdx+1].AdjustY(pInfo->aObj1Line2.Y() );
+ } else {
+ aXP1[nIdx].AdjustX(pInfo->aObj1Line2.X() );
+ aXP1[nIdx+1].AdjustX(pInfo->aObj1Line2.X() );
+ }
+ }
+ if (pInfo->nObj1Lines>=3) {
+ sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj1Line3,aXP1);
+ if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj1Line3,aXP1)) {
+ aXP1[nIdx].AdjustY(pInfo->aObj1Line3.Y() );
+ aXP1[nIdx+1].AdjustY(pInfo->aObj1Line3.Y() );
+ } else {
+ aXP1[nIdx].AdjustX(pInfo->aObj1Line3.X() );
+ aXP1[nIdx+1].AdjustX(pInfo->aObj1Line3.X() );
+ }
+ }
+ if (pInfo->nObj2Lines>=2) {
+ sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj2Line2,aXP1);
+ if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj2Line2,aXP1)) {
+ aXP1[nIdx].AdjustY(pInfo->aObj2Line2.Y() );
+ aXP1[nIdx+1].AdjustY(pInfo->aObj2Line2.Y() );
+ } else {
+ aXP1[nIdx].AdjustX(pInfo->aObj2Line2.X() );
+ aXP1[nIdx+1].AdjustX(pInfo->aObj2Line2.X() );
+ }
+ }
+ if (pInfo->nObj2Lines>=3) {
+ sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj2Line3,aXP1);
+ if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj2Line3,aXP1)) {
+ aXP1[nIdx].AdjustY(pInfo->aObj2Line3.Y() );
+ aXP1[nIdx+1].AdjustY(pInfo->aObj2Line3.Y() );
+ } else {
+ aXP1[nIdx].AdjustX(pInfo->aObj2Line3.X() );
+ aXP1[nIdx+1].AdjustX(pInfo->aObj2Line3.X() );
+ }
+ }
+ }
+ // make the connector a bezier curve, if appropriate
+ if (eKind==SdrEdgeKind::Bezier && nPointCount>2) {
+ Point* pPt1=&aXP1[0];
+ Point* pPt2=&aXP1[1];
+ Point* pPt3=&aXP1[nPointCount-2];
+ Point* pPt4=&aXP1[nPointCount-1];
+ tools::Long dx1=pPt2->X()-pPt1->X();
+ tools::Long dy1=pPt2->Y()-pPt1->Y();
+ tools::Long dx2=pPt3->X()-pPt4->X();
+ tools::Long dy2=pPt3->Y()-pPt4->Y();
+ if (cForm=='L') { // nPointCount==3
+ aXP1.SetFlags(1,PolyFlags::Control);
+ Point aPt3(*pPt2);
+ aXP1.Insert(2,aPt3,PolyFlags::Control);
+ nPointCount=aXP1.GetPointCount();
+ pPt2=&aXP1[1];
+ pPt3=&aXP1[nPointCount-2];
+ pPt2->AdjustX( -(dx1/3) );
+ pPt2->AdjustY( -(dy1/3) );
+ pPt3->AdjustX( -(dx2/3) );
+ pPt3->AdjustY( -(dy2/3) );
+ } else if (nPointCount>=4 && nPointCount<=6) { // Z or U or ...
+ // To all others, the end points of the original lines become control
+ // points for now. Thus, we need to do some more work for nPointCount>4!
+ aXP1.SetFlags(1,PolyFlags::Control);
+ aXP1.SetFlags(nPointCount-2,PolyFlags::Control);
+ // distance x1.5
+ pPt2->AdjustX(dx1/2 );
+ pPt2->AdjustY(dy1/2 );
+ pPt3->AdjustX(dx2/2 );
+ pPt3->AdjustY(dy2/2 );
+ if (nPointCount==5) {
+ // add a control point before and after center
+ Point aCenter(aXP1[2]);
+ tools::Long dx1b=aCenter.X()-aXP1[1].X();
+ tools::Long dy1b=aCenter.Y()-aXP1[1].Y();
+ tools::Long dx2b=aCenter.X()-aXP1[3].X();
+ tools::Long dy2b=aCenter.Y()-aXP1[3].Y();
+ aXP1.Insert(2,aCenter,PolyFlags::Control);
+ aXP1.SetFlags(3,PolyFlags::Symmetric);
+ aXP1.Insert(4,aCenter,PolyFlags::Control);
+ aXP1[2].AdjustX( -(dx1b/2) );
+ aXP1[2].AdjustY( -(dy1b/2) );
+ aXP1[3].AdjustX( -((dx1b+dx2b)/4) );
+ aXP1[3].AdjustY( -((dy1b+dy2b)/4) );
+ aXP1[4].AdjustX( -(dx2b/2) );
+ aXP1[4].AdjustY( -(dy2b/2) );
+ }
+ if (nPointCount==6) {
+ Point aPt1b(aXP1[2]);
+ Point aPt2b(aXP1[3]);
+ aXP1.Insert(2,aPt1b,PolyFlags::Control);
+ aXP1.Insert(5,aPt2b,PolyFlags::Control);
+ tools::Long dx=aPt1b.X()-aPt2b.X();
+ tools::Long dy=aPt1b.Y()-aPt2b.Y();
+ aXP1[3].AdjustX( -(dx/2) );
+ aXP1[3].AdjustY( -(dy/2) );
+ aXP1.SetFlags(3,PolyFlags::Symmetric);
+ aXP1.Remove(4,1); // because it's identical with aXP1[3]
+ }
+ }
+ }
+ return aXP1;
+}
+
+/*
+There could be a maximum of 64 different developments with 5 lines, a
+maximum of 32 developments with 4 lines, a maximum of 16 developments with
+3 lines, a maximum of 8 developments with 2 lines.
+This gives us a total of 124 possibilities.
+Normalized for the 1st exit angle to the right, there remain 31 possibilities.
+Now, normalizing away the vertical mirroring, we get to a total of 16
+characteristic developments with 1 through 5 lines:
+
+1 line (type "I") --
+
+2 lines (type "L") __|
+
+3 lines (type "U") __ (type "Z") _
+ __| _|
+ _ _
+4 lines #1 _| #2 | | #3 |_ #4 | |
+ _| _| _| _|
+ Of these, #1 is implausible, #2 is a rotated version of #3. This leaves
+ #2 (from now on referred to as 4.1) and #4 (from now on referred to as 4.2).
+ _ _
+5 lines #1 _| #2 _| #3 ___ #4 _
+ _| _| _| _| _| |_
+ _ _ _
+ #5 |_ #6 |_ #7 _| | #8 ____
+ _| _| _| |_ _|
+ Of these, 5.1, 5.2, 5.4 and 5.5 are implausible, 5.7 is a reversed version
+ of 5.3. This leaves 5.3 (type "4"), 5.6 (type "S") and 5.8 (type "C").
+
+We now have discerned the 9 basic types to cover all 400 possible constellations
+of object positions and exit angles. 4 of the 9 types have got a center
+line (CL). The number of object margins per object varies between 0 and 3:
+
+ CL O1 O2 Note
+"I": n 0 0
+"L": n 0 0
+"U": n 0-1 0-1
+"Z": y 0 0
+4.2: y 0 1 = U+1, respectively 1+U
+4.4: n 0-2 0-2 = Z+1
+"4": y 0 2 = Z+2
+"S": y 1 1 = 1+Z+1
+"C": n 0-3 0-3 = 1+U+1
+*/
+
+void SdrEdgeObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ const SfxHintId nId = rHint.GetId();
+ bool bDataChg=nId==SfxHintId::DataChanged;
+ bool bDying=nId==SfxHintId::Dying;
+ bool bObj1=aCon1.pObj!=nullptr && aCon1.pObj->GetBroadcaster()==&rBC;
+ bool bObj2=aCon2.pObj!=nullptr && aCon2.pObj->GetBroadcaster()==&rBC;
+ if (bDying && (bObj1 || bObj2)) {
+ // catch Dying, so AttrObj doesn't start broadcasting
+ // about an alleged change of template
+ if (bObj1) aCon1.pObj=nullptr;
+ if (bObj2) aCon2.pObj=nullptr;
+ return;
+ }
+ if ( bObj1 || bObj2 )
+ {
+ bEdgeTrackUserDefined = false;
+ }
+ SdrTextObj::Notify(rBC,rHint);
+ if (nNotifyingCount!=0)return;
+
+// a locking flag
+ nNotifyingCount++;
+ const SdrHint* pSdrHint = ( rHint.GetId() == SfxHintId::ThisIsAnSdrHint ? static_cast<const SdrHint*>(&rHint) : nullptr );
+
+ if (bDataChg) { // StyleSheet changed
+ ImpSetAttrToEdgeInfo(); // when changing templates, copy values from Pool to aEdgeInfo
+ }
+ if (bDataChg ||
+ (bObj1 && aCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject()) ||
+ (bObj2 && aCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject()) ||
+ (pSdrHint && pSdrHint->GetKind()==SdrHintKind::ObjectRemoved))
+ {
+ // broadcasting only, if on the same page
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetCurrentBoundRect();
+ ImpDirtyEdgeTrack();
+
+ // only redraw here, object hasn't actually changed
+ ActionChanged();
+
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+ nNotifyingCount--;
+}
+
+/** updates edges that are connected to the edges of this object
+ as if the connected objects sent a repaint broadcast
+*/
+void SdrEdgeObj::Reformat()
+{
+ if( nullptr != aCon1.pObj )
+ {
+ SfxHint aHint( SfxHintId::DataChanged );
+ Notify( *const_cast<SfxBroadcaster*>(aCon1.pObj->GetBroadcaster()), aHint );
+ }
+
+ if( nullptr != aCon2.pObj )
+ {
+ SfxHint aHint( SfxHintId::DataChanged );
+ Notify( *const_cast<SfxBroadcaster*>(aCon2.pObj->GetBroadcaster()), aHint );
+ }
+}
+
+SdrEdgeObj* SdrEdgeObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrEdgeObj(rTargetModel, *this);
+}
+
+OUString SdrEdgeObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulEDGE));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+ return sName;
+}
+
+OUString SdrEdgeObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralEDGE);
+}
+
+basegfx::B2DPolyPolygon SdrEdgeObj::TakeXorPoly() const
+{
+ basegfx::B2DPolyPolygon aPolyPolygon;
+
+ if (bEdgeTrackDirty)
+ {
+ const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
+ }
+
+ if(pEdgeTrack)
+ {
+ aPolyPolygon.append(pEdgeTrack->getB2DPolygon());
+ }
+
+ return aPolyPolygon;
+}
+
+void SdrEdgeObj::SetEdgeTrackPath( const basegfx::B2DPolyPolygon& rPoly )
+{
+ if ( !rPoly.count() )
+ {
+ bEdgeTrackDirty = true;
+ bEdgeTrackUserDefined = false;
+ }
+ else
+ {
+ *pEdgeTrack = XPolygon( rPoly.getB2DPolygon( 0 ) );
+ bEdgeTrackDirty = false;
+ bEdgeTrackUserDefined = true;
+
+ // #i110629# also set aRect and maSnapeRect depending on pEdgeTrack
+ const tools::Rectangle aPolygonBounds(pEdgeTrack->GetBoundRect());
+ maRect = aPolygonBounds;
+ maSnapRect = aPolygonBounds;
+ }
+}
+
+basegfx::B2DPolyPolygon SdrEdgeObj::GetEdgeTrackPath() const
+{
+ basegfx::B2DPolyPolygon aPolyPolygon;
+
+ if (bEdgeTrackDirty)
+ const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
+
+ aPolyPolygon.append( pEdgeTrack->getB2DPolygon() );
+
+ return aPolyPolygon;
+}
+
+sal_uInt32 SdrEdgeObj::GetHdlCount() const
+{
+ SdrEdgeKind eKind=GetObjectItem(SDRATTR_EDGEKIND).GetValue();
+ sal_uInt32 nHdlCnt(0);
+ sal_uInt32 nPointCount(pEdgeTrack->GetPointCount());
+
+ if(nPointCount)
+ {
+ nHdlCnt = 2;
+ if ((eKind==SdrEdgeKind::OrthoLines || eKind==SdrEdgeKind::Bezier) && nPointCount >= 4)
+ {
+ sal_uInt32 nO1(aEdgeInfo.nObj1Lines > 0 ? aEdgeInfo.nObj1Lines - 1 : 0);
+ sal_uInt32 nO2(aEdgeInfo.nObj2Lines > 0 ? aEdgeInfo.nObj2Lines - 1 : 0);
+ sal_uInt32 nM(aEdgeInfo.nMiddleLine != 0xFFFF ? 1 : 0);
+ nHdlCnt += nO1 + nO2 + nM;
+ }
+ else if (eKind==SdrEdgeKind::ThreeLines && nPointCount == 4)
+ {
+ if(GetConnectedNode(true))
+ nHdlCnt++;
+
+ if(GetConnectedNode(false))
+ nHdlCnt++;
+ }
+ }
+
+ return nHdlCnt;
+}
+
+void SdrEdgeObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ sal_uInt32 nPointCount(pEdgeTrack->GetPointCount());
+ if (nPointCount==0)
+ return;
+
+ {
+ std::unique_ptr<SdrHdl> pHdl(new ImpEdgeHdl((*pEdgeTrack)[0],SdrHdlKind::Poly));
+ if (aCon1.pObj!=nullptr && aCon1.bBestVertex) pHdl->Set1PixMore();
+ pHdl->SetPointNum(0);
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+ {
+ std::unique_ptr<SdrHdl> pHdl(new ImpEdgeHdl((*pEdgeTrack)[sal_uInt16(nPointCount-1)],SdrHdlKind::Poly));
+ if (aCon2.pObj!=nullptr && aCon2.bBestVertex) pHdl->Set1PixMore();
+ pHdl->SetPointNum(1);
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+ {
+ SdrEdgeKind eKind=GetObjectItem(SDRATTR_EDGEKIND).GetValue();
+ if ((eKind==SdrEdgeKind::OrthoLines || eKind==SdrEdgeKind::Bezier) && nPointCount >= 4)
+ {
+ sal_uInt32 nO1(aEdgeInfo.nObj1Lines > 0 ? aEdgeInfo.nObj1Lines - 1 : 0);
+ sal_uInt32 nO2(aEdgeInfo.nObj2Lines > 0 ? aEdgeInfo.nObj2Lines - 1 : 0);
+ sal_uInt32 nM(aEdgeInfo.nMiddleLine != 0xFFFF ? 1 : 0);
+ for(sal_uInt32 i = 0; i < (nO1 + nO2 + nM); ++i)
+ {
+ sal_Int32 nPt(0);
+ sal_uInt32 nNum = i;
+ std::unique_ptr<ImpEdgeHdl> pHdl(new ImpEdgeHdl(Point(),SdrHdlKind::Poly));
+ if (nNum<nO1) {
+ nPt=nNum+1;
+ if (nNum==0) pHdl->SetLineCode(SdrEdgeLineCode::Obj1Line2);
+ if (nNum==1) pHdl->SetLineCode(SdrEdgeLineCode::Obj1Line3);
+ } else {
+ nNum=nNum-nO1;
+ if (nNum<nO2) {
+ nPt=nPointCount-3-nNum;
+ if (nNum==0) pHdl->SetLineCode(SdrEdgeLineCode::Obj2Line2);
+ if (nNum==1) pHdl->SetLineCode(SdrEdgeLineCode::Obj2Line3);
+ } else {
+ nNum=nNum-nO2;
+ if (nNum<nM) {
+ nPt=aEdgeInfo.nMiddleLine;
+ pHdl->SetLineCode(SdrEdgeLineCode::MiddleLine);
+ }
+ }
+ }
+ if (nPt>0) {
+ Point aPos((*pEdgeTrack)[static_cast<sal_uInt16>(nPt)]);
+ aPos+=(*pEdgeTrack)[static_cast<sal_uInt16>(nPt)+1];
+ aPos.setX( aPos.X() / 2 );
+ aPos.setY( aPos.Y() / 2 );
+ pHdl->SetPos(aPos);
+ pHdl->SetPointNum(i + 2);
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+ }
+ }
+ else if (eKind==SdrEdgeKind::ThreeLines && nPointCount == 4)
+ {
+ if(GetConnectedNode(true))
+ {
+ Point aPos((*pEdgeTrack)[1]);
+ std::unique_ptr<ImpEdgeHdl> pHdl(new ImpEdgeHdl(aPos,SdrHdlKind::Poly));
+ pHdl->SetLineCode(SdrEdgeLineCode::Obj1Line2);
+ pHdl->SetPointNum(2);
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+ if(GetConnectedNode(false))
+ {
+ Point aPos((*pEdgeTrack)[2]);
+ std::unique_ptr<ImpEdgeHdl> pHdl(new ImpEdgeHdl(aPos,SdrHdlKind::Poly));
+ pHdl->SetLineCode(SdrEdgeLineCode::Obj2Line2);
+ pHdl->SetPointNum(3);
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+ }
+ }
+}
+
+bool SdrEdgeObj::hasSpecialDrag() const
+{
+ return true;
+}
+
+SdrObjectUniquePtr SdrEdgeObj::getFullDragClone() const
+{
+ // use Clone operator
+ SdrEdgeObj* pRetval(CloneSdrObject(getSdrModelFromSdrObject()));
+
+ // copy connections for clone, SdrEdgeObj::operator= does not do this
+ pRetval->ConnectToNode(true, GetConnectedNode(true));
+ pRetval->ConnectToNode(false, GetConnectedNode(false));
+
+ return SdrObjectUniquePtr(pRetval);
+}
+
+bool SdrEdgeObj::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ if(!rDrag.GetHdl())
+ return false;
+
+ rDrag.SetEndDragChangesAttributes(true);
+
+ if(rDrag.GetHdl()->GetPointNum() < 2)
+ {
+ rDrag.SetNoSnap();
+ }
+
+ return true;
+}
+
+bool SdrEdgeObj::applySpecialDrag(SdrDragStat& rDragStat)
+{
+ SdrEdgeObj* pOriginalEdge = dynamic_cast< SdrEdgeObj* >(rDragStat.GetHdl()->GetObj());
+ const bool bOriginalEdgeModified(pOriginalEdge == this);
+
+ if(!bOriginalEdgeModified && pOriginalEdge)
+ {
+ // copy connections when clone is modified. This is needed because
+ // as preparation to this modification the data from the original object
+ // was copied to the clone using the operator=. As can be seen there,
+ // that operator does not copy the connections (for good reason)
+ ConnectToNode(true, pOriginalEdge->GetConnection(true).GetObject());
+ ConnectToNode(false, pOriginalEdge->GetConnection(false).GetObject());
+ }
+
+ if(rDragStat.GetHdl()->GetPointNum() < 2)
+ {
+ // start or end point connector drag
+ const bool bDragA(0 == rDragStat.GetHdl()->GetPointNum());
+ const Point aPointNow(rDragStat.GetNow());
+
+ rDragStat.SetEndDragChangesGeoAndAttributes(true);
+
+ if(rDragStat.GetPageView())
+ {
+ SdrObjConnection* pDraggedOne(bDragA ? &aCon1 : &aCon2);
+
+ // clear connection
+ DisconnectFromNode(bDragA);
+
+ // look for new connection
+ ImpFindConnector(aPointNow, *rDragStat.GetPageView(), *pDraggedOne, pOriginalEdge, nullptr, &rDragStat);
+
+ if(pDraggedOne->pObj)
+ {
+ // if found, officially connect to it; ImpFindConnector only
+ // sets pObj hard
+ SdrObject* pNewConnection = pDraggedOne->pObj;
+ pDraggedOne->pObj = nullptr;
+ ConnectToNode(bDragA, pNewConnection);
+ }
+
+ if(rDragStat.GetView() && !bOriginalEdgeModified)
+ {
+ // show IA helper, but only do this during IA, so not when the original
+ // Edge gets modified in the last call
+ rDragStat.GetView()->SetConnectMarker(*pDraggedOne);
+ }
+ }
+
+ if(pEdgeTrack)
+ {
+ // change pEdgeTrack to modified position
+ if(bDragA)
+ {
+ (*pEdgeTrack)[0] = aPointNow;
+ }
+ else
+ {
+ (*pEdgeTrack)[sal_uInt16(pEdgeTrack->GetPointCount()-1)] = aPointNow;
+ }
+ }
+
+ // reset edge info's offsets, this is an end point drag
+ aEdgeInfo.aObj1Line2 = Point();
+ aEdgeInfo.aObj1Line3 = Point();
+ aEdgeInfo.aObj2Line2 = Point();
+ aEdgeInfo.aObj2Line3 = Point();
+ aEdgeInfo.aMiddleLine = Point();
+ }
+ else
+ {
+ // control point connector drag
+ const ImpEdgeHdl* pEdgeHdl = static_cast<const ImpEdgeHdl*>(rDragStat.GetHdl());
+ const SdrEdgeLineCode eLineCode = pEdgeHdl->GetLineCode();
+ const Point aDist(rDragStat.GetNow() - rDragStat.GetStart());
+ sal_Int32 nDist(pEdgeHdl->IsHorzDrag() ? aDist.X() : aDist.Y());
+
+ nDist += aEdgeInfo.ImpGetLineOffset(eLineCode, *pEdgeTrack);
+ aEdgeInfo.ImpSetLineOffset(eLineCode, *pEdgeTrack, nDist);
+ }
+
+ // force recalculation of EdgeTrack
+ *pEdgeTrack = ImpCalcEdgeTrack(*pEdgeTrack, aCon1, aCon2, &aEdgeInfo);
+ bEdgeTrackDirty=false;
+
+ // save EdgeInfos and mark object as user modified
+ ImpSetEdgeInfoToAttr();
+ bEdgeTrackUserDefined = false;
+
+ SetBoundAndSnapRectsDirty();
+
+ if(bOriginalEdgeModified && rDragStat.GetView())
+ {
+ // hide connect marker helper again when original gets changed.
+ // This happens at the end of the interaction
+ rDragStat.GetView()->HideConnectMarker();
+ }
+
+ return true;
+}
+
+OUString SdrEdgeObj::getSpecialDragComment(const SdrDragStat& rDrag) const
+{
+ const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
+
+ if(bCreateComment)
+ {
+ return OUString();
+ }
+ else
+ {
+ return ImpGetDescriptionStr(STR_DragEdgeTail);
+ }
+}
+
+
+basegfx::B2DPolygon SdrEdgeObj::ImplAddConnectorOverlay(const SdrDragMethod& rDragMethod, bool bTail1, bool bTail2, bool bDetail) const
+{
+ basegfx::B2DPolygon aResult;
+
+ if(bDetail)
+ {
+ SdrObjConnection aMyCon1(aCon1);
+ SdrObjConnection aMyCon2(aCon2);
+
+ if (bTail1)
+ {
+ const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aMyCon1.aObjOfs.X(), aMyCon1.aObjOfs.Y()));
+ aMyCon1.aObjOfs.setX( basegfx::fround(aTemp.getX()) );
+ aMyCon1.aObjOfs.setY( basegfx::fround(aTemp.getY()) );
+ }
+
+ if (bTail2)
+ {
+ const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aMyCon2.aObjOfs.X(), aMyCon2.aObjOfs.Y()));
+ aMyCon2.aObjOfs.setX( basegfx::fround(aTemp.getX()) );
+ aMyCon2.aObjOfs.setY( basegfx::fround(aTemp.getY()) );
+ }
+
+ SdrEdgeInfoRec aInfo(aEdgeInfo);
+ XPolygon aXP(ImpCalcEdgeTrack(*pEdgeTrack, aMyCon1, aMyCon2, &aInfo));
+
+ if(aXP.GetPointCount())
+ {
+ aResult = aXP.getB2DPolygon();
+ }
+ }
+ else
+ {
+ Point aPt1((*pEdgeTrack)[0]);
+ Point aPt2((*pEdgeTrack)[sal_uInt16(pEdgeTrack->GetPointCount() - 1)]);
+
+ if (aCon1.pObj && (aCon1.bBestConn || aCon1.bBestVertex))
+ aPt1 = aCon1.pObj->GetSnapRect().Center();
+
+ if (aCon2.pObj && (aCon2.bBestConn || aCon2.bBestVertex))
+ aPt2 = aCon2.pObj->GetSnapRect().Center();
+
+ if (bTail1)
+ {
+ const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aPt1.X(), aPt1.Y()));
+ aPt1.setX( basegfx::fround(aTemp.getX()) );
+ aPt1.setY( basegfx::fround(aTemp.getY()) );
+ }
+
+ if (bTail2)
+ {
+ const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aPt2.X(), aPt2.Y()));
+ aPt2.setX( basegfx::fround(aTemp.getX()) );
+ aPt2.setY( basegfx::fround(aTemp.getY()) );
+ }
+
+ aResult.append(basegfx::B2DPoint(aPt1.X(), aPt1.Y()));
+ aResult.append(basegfx::B2DPoint(aPt2.X(), aPt2.Y()));
+ }
+
+ return aResult;
+}
+
+bool SdrEdgeObj::BegCreate(SdrDragStat& rDragStat)
+{
+ rDragStat.SetNoSnap();
+ pEdgeTrack->SetPointCount(2);
+ (*pEdgeTrack)[0]=rDragStat.GetStart();
+ (*pEdgeTrack)[1]=rDragStat.GetNow();
+ if (rDragStat.GetPageView()!=nullptr) {
+ ImpFindConnector(rDragStat.GetStart(),*rDragStat.GetPageView(),aCon1,this);
+ ConnectToNode(true,aCon1.pObj);
+ }
+ *pEdgeTrack=ImpCalcEdgeTrack(*pEdgeTrack,aCon1,aCon2,&aEdgeInfo);
+ return true;
+}
+
+bool SdrEdgeObj::MovCreate(SdrDragStat& rDragStat)
+{
+ sal_uInt16 nMax=pEdgeTrack->GetPointCount();
+ (*pEdgeTrack)[nMax-1]=rDragStat.GetNow();
+ if (rDragStat.GetPageView()!=nullptr) {
+ ImpFindConnector(rDragStat.GetNow(),*rDragStat.GetPageView(),aCon2,this);
+ rDragStat.GetView()->SetConnectMarker(aCon2);
+ }
+ SetBoundRectDirty();
+ m_bSnapRectDirty=true;
+ ConnectToNode(false,aCon2.pObj);
+ *pEdgeTrack=ImpCalcEdgeTrack(*pEdgeTrack,aCon1,aCon2,&aEdgeInfo);
+ bEdgeTrackDirty=false;
+ return true;
+}
+
+bool SdrEdgeObj::EndCreate(SdrDragStat& rDragStat, SdrCreateCmd eCmd)
+{
+ bool bOk=(eCmd==SdrCreateCmd::ForceEnd || rDragStat.GetPointCount()>=2);
+ if (bOk) {
+ ConnectToNode(true,aCon1.pObj);
+ ConnectToNode(false,aCon2.pObj);
+ if (rDragStat.GetView()!=nullptr) {
+ rDragStat.GetView()->HideConnectMarker();
+ }
+ ImpSetEdgeInfoToAttr(); // copy values from aEdgeInfo into the pool
+ }
+ SetBoundAndSnapRectsDirty();
+ return bOk;
+}
+
+bool SdrEdgeObj::BckCreate(SdrDragStat& rDragStat)
+{
+ if (rDragStat.GetView()!=nullptr) {
+ rDragStat.GetView()->HideConnectMarker();
+ }
+ return false;
+}
+
+void SdrEdgeObj::BrkCreate(SdrDragStat& rDragStat)
+{
+ if (rDragStat.GetView()!=nullptr) {
+ rDragStat.GetView()->HideConnectMarker();
+ }
+}
+
+basegfx::B2DPolyPolygon SdrEdgeObj::TakeCreatePoly(const SdrDragStat& /*rStatDrag*/) const
+{
+ basegfx::B2DPolyPolygon aRetval;
+ aRetval.append(pEdgeTrack->getB2DPolygon());
+ return aRetval;
+}
+
+PointerStyle SdrEdgeObj::GetCreatePointer() const
+{
+ return PointerStyle::DrawConnect;
+}
+
+bool SdrEdgeObj::ImpFindConnector(const Point& rPt, const SdrPageView& rPV, SdrObjConnection& rCon, const SdrEdgeObj* pThis, OutputDevice* pOut, SdrDragStat* pDragStat)
+{
+ rCon.ResetVars();
+ if (pOut==nullptr) pOut=rPV.GetView().GetFirstOutputDevice();
+ if (pOut==nullptr) return false;
+ SdrObjList* pOL=rPV.GetObjList();
+ const SdrLayerIDSet& rVisLayer=rPV.GetVisibleLayers();
+ // sensitive area of connectors is twice as large as the one of the handles
+ sal_uInt16 nMarkHdSiz=rPV.GetView().GetMarkHdlSizePixel();
+ Size aHalfConSiz(nMarkHdSiz,nMarkHdSiz);
+ if (comphelper::LibreOfficeKit::isActive() && pOut->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ aHalfConSiz=pOut->PixelToLogic(aHalfConSiz, MapMode(MapUnit::Map100thMM));
+ else
+ aHalfConSiz=pOut->PixelToLogic(aHalfConSiz);
+ tools::Rectangle aMouseRect(rPt,rPt);
+ aMouseRect.AdjustLeft( -(aHalfConSiz.Width()) );
+ aMouseRect.AdjustTop( -(aHalfConSiz.Height()) );
+ aMouseRect.AdjustRight(aHalfConSiz.Width() );
+ aMouseRect.AdjustBottom(aHalfConSiz.Height() );
+ sal_uInt16 nBoundHitTol=static_cast<sal_uInt16>(aHalfConSiz.Width())/2; if (nBoundHitTol==0) nBoundHitTol=1;
+ size_t no=pOL->GetObjCount();
+ bool bFnd = false;
+ SdrObjConnection aTestCon;
+ bool bTiledRendering = comphelper::LibreOfficeKit::isActive();
+ bool bHasRequestedOrdNum = false;
+ sal_Int32 requestedOrdNum = -1;
+
+ if (bTiledRendering && pDragStat)
+ {
+ auto& glueOptions = pDragStat->GetGlueOptions();
+ if (glueOptions.objectOrdNum != -1)
+ {
+ requestedOrdNum = glueOptions.objectOrdNum;
+ bHasRequestedOrdNum = true;
+ }
+ }
+
+ while (no>0 && !bFnd) {
+ // issue: group objects on different layers return LayerID=0!
+ no--;
+ SdrObject* pObj=pOL->GetObj(no);
+ if (bHasRequestedOrdNum)
+ {
+ if (pObj->GetOrdNumDirect() != static_cast<sal_uInt32>(requestedOrdNum))
+ continue;
+ }
+ if (rVisLayer.IsSet(pObj->GetLayer()) && pObj->IsVisible() && // only visible objects
+ (pThis==nullptr || pObj!=static_cast<SdrObject const *>(pThis))) // don't connect it to itself
+ {
+ tools::Rectangle aObjBound(pObj->GetCurrentBoundRect());
+ if (aObjBound.Overlaps(aMouseRect)) {
+ aTestCon.ResetVars();
+ bool bEdge=dynamic_cast<const SdrEdgeObj *>(pObj) != nullptr; // no BestCon for Edge
+ // User-defined connectors have absolute priority.
+ // After those come Vertex, Corner and center (Best), all prioritized equally.
+ // Finally, a HitTest for the object.
+ const SdrGluePointList* pGPL=pObj->GetGluePointList();
+ sal_uInt16 nGluePointCnt=pGPL==nullptr ? 0 : pGPL->GetCount();
+ sal_uInt16 nGesAnz=nGluePointCnt+9;
+ bool bUserFnd = false;
+ sal_uIntPtr nBestDist=0xFFFFFFFF;
+ for (sal_uInt16 i=0; i<nGesAnz; i++)
+ {
+ bool bUser=i<nGluePointCnt;
+ bool bVertex=i>=nGluePointCnt+0 && i<nGluePointCnt+4;
+ bool bCorner=i>=nGluePointCnt+4 && i<nGluePointCnt+8;
+ bool bCenter=i==nGluePointCnt+8;
+ bool bOk = false;
+ Point aConPos;
+ sal_uInt16 nConNum=i;
+ if (bUser) {
+ const SdrGluePoint& rGP=(*pGPL)[nConNum];
+ aConPos=rGP.GetAbsolutePos(*pObj);
+ nConNum=rGP.GetId();
+ bOk = true;
+ } else if (bVertex && !bUserFnd) {
+ nConNum=nConNum-nGluePointCnt;
+ SdrGluePoint aPt(pObj->GetVertexGluePoint(nConNum));
+ aConPos=aPt.GetAbsolutePos(*pObj);
+ bOk = true;
+ } else if (bCorner && !bUserFnd) {
+ nConNum-=nGluePointCnt+4;
+ i+=3;
+ }
+ else if (bCenter && !bUserFnd && !bEdge)
+ {
+ // Suppress default connect at object center
+ if(!pThis || !pThis->GetSuppressDefaultConnect())
+ {
+ // not the edges!
+ nConNum=0;
+ aConPos=aObjBound.Center();
+ bOk = true;
+ }
+ }
+ if (bOk && aMouseRect.Contains(aConPos)) {
+ if (bUser) bUserFnd = true;
+ bFnd = true;
+ sal_uIntPtr nDist=static_cast<sal_uIntPtr>(std::abs(aConPos.X()-rPt.X()))+static_cast<sal_uIntPtr>(std::abs(aConPos.Y()-rPt.Y()));
+ if (nDist<nBestDist) {
+ nBestDist=nDist;
+ aTestCon.pObj=pObj;
+ aTestCon.nConId=nConNum;
+ aTestCon.bAutoCorner=bCorner;
+ aTestCon.bAutoVertex=bVertex;
+ aTestCon.bBestConn=false; // bCenter;
+ aTestCon.bBestVertex=bCenter;
+ }
+ }
+ }
+ // if no connector is hit, try HitTest again, for BestConnector (=bCenter)
+ if(!bFnd &&
+ !bEdge &&
+ SdrObjectPrimitiveHit(*pObj, rPt, nBoundHitTol, rPV, &rVisLayer, false))
+ {
+ // Suppress default connect at object inside bound
+ if(!pThis || !pThis->GetSuppressDefaultConnect())
+ {
+ bFnd = true;
+ aTestCon.pObj=pObj;
+ aTestCon.bBestConn=true;
+ }
+ }
+ if (bFnd) {
+ aMouseRect.AdjustLeft( -nBoundHitTol );
+ aMouseRect.AdjustTop( -nBoundHitTol );
+ aMouseRect.AdjustRight(nBoundHitTol );
+ aMouseRect.AdjustBottom(nBoundHitTol );
+ }
+
+ }
+ }
+ }
+ rCon=aTestCon;
+ return bFnd;
+}
+
+void SdrEdgeObj::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ const tools::Rectangle aOld(GetSnapRect());
+
+ if(aOld == rRect)
+ return;
+
+ if (maRect.IsEmpty() && 0 == pEdgeTrack->GetPointCount())
+ {
+ // #i110629# When initializing, do not scale on empty Rectangle; this
+ // will mirror the underlying text object (!)
+ maRect = rRect;
+ maSnapRect = rRect;
+ }
+ else
+ {
+ tools::Long nMulX = rRect.Right() - rRect.Left();
+ tools::Long nDivX = aOld.Right() - aOld.Left();
+ tools::Long nMulY = rRect.Bottom() - rRect.Top();
+ tools::Long nDivY = aOld.Bottom() - aOld.Top();
+ if ( nDivX == 0 ) { nMulX = 1; nDivX = 1; }
+ if ( nDivY == 0 ) { nMulY = 1; nDivY = 1; }
+ Fraction aX(nMulX, nDivX);
+ Fraction aY(nMulY, nDivY);
+ NbcResize(aOld.TopLeft(), aX, aY);
+ NbcMove(Size(rRect.Left() - aOld.Left(), rRect.Top() - aOld.Top()));
+ }
+}
+
+void SdrEdgeObj::NbcMove(const Size& rSiz)
+{
+ SdrTextObj::NbcMove(rSiz);
+ MoveXPoly(*pEdgeTrack,rSiz);
+}
+
+void SdrEdgeObj::NbcResize(const Point& rRefPnt, const Fraction& aXFact, const Fraction& aYFact)
+{
+ SdrTextObj::NbcResize(rRefPnt,aXFact,aXFact);
+ ResizeXPoly(*pEdgeTrack,rRefPnt,aXFact,aYFact);
+
+ // if resize is not from paste, forget user distances
+ if (!getSdrModelFromSdrObject().IsPasteResize())
+ {
+ aEdgeInfo.aObj1Line2 = Point();
+ aEdgeInfo.aObj1Line3 = Point();
+ aEdgeInfo.aObj2Line2 = Point();
+ aEdgeInfo.aObj2Line3 = Point();
+ aEdgeInfo.aMiddleLine = Point();
+ }
+}
+
+// #i54102# added rotation support
+void SdrEdgeObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ if(bEdgeTrackUserDefined)
+ {
+ // #i120437# special handling when track is imported, apply
+ // transformation directly to imported track.
+ SdrTextObj::NbcRotate(rRef, nAngle, sn, cs);
+ RotateXPoly(*pEdgeTrack, rRef, sn, cs);
+ }
+ else
+ {
+ // handle start and end point if not connected
+ const bool bCon1(nullptr != aCon1.pObj && aCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
+ const bool bCon2(nullptr != aCon2.pObj && aCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
+
+ if(!bCon1 && pEdgeTrack)
+ {
+ RotatePoint((*pEdgeTrack)[0],rRef,sn,cs);
+ ImpDirtyEdgeTrack();
+ }
+
+ if(!bCon2 && pEdgeTrack)
+ {
+ sal_uInt16 nPointCount = pEdgeTrack->GetPointCount();
+ RotatePoint((*pEdgeTrack)[sal_uInt16(nPointCount-1)],rRef,sn,cs);
+ ImpDirtyEdgeTrack();
+ }
+ }
+}
+
+// #i54102# added mirror support
+void SdrEdgeObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ if(bEdgeTrackUserDefined)
+ {
+ // #i120437# special handling when track is imported, apply
+ // transformation directly to imported track.
+ SdrTextObj::NbcMirror(rRef1, rRef2);
+ MirrorXPoly(*pEdgeTrack, rRef1, rRef2);
+ }
+ else
+ {
+ // handle start and end point if not connected
+ const bool bCon1(nullptr != aCon1.pObj && aCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
+ const bool bCon2(nullptr != aCon2.pObj && aCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
+
+ if(!bCon1 && pEdgeTrack)
+ {
+ MirrorPoint((*pEdgeTrack)[0],rRef1,rRef2);
+ ImpDirtyEdgeTrack();
+ }
+
+ if(!bCon2 && pEdgeTrack)
+ {
+ sal_uInt16 nPointCount = pEdgeTrack->GetPointCount();
+ MirrorPoint((*pEdgeTrack)[sal_uInt16(nPointCount-1)],rRef1,rRef2);
+ ImpDirtyEdgeTrack();
+ }
+ }
+}
+
+// #i54102# added shear support
+void SdrEdgeObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ if(bEdgeTrackUserDefined)
+ {
+ // #i120437# special handling when track is imported, apply
+ // transformation directly to imported track.
+ SdrTextObj::NbcShear(rRef, nAngle, tn, bVShear);
+ ShearXPoly(*pEdgeTrack, rRef, tn, bVShear);
+ }
+ else
+ {
+ // handle start and end point if not connected
+ const bool bCon1(nullptr != aCon1.pObj && aCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
+ const bool bCon2(nullptr != aCon2.pObj && aCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
+
+ if(!bCon1 && pEdgeTrack)
+ {
+ ShearPoint((*pEdgeTrack)[0],rRef,tn,bVShear);
+ ImpDirtyEdgeTrack();
+ }
+
+ if(!bCon2 && pEdgeTrack)
+ {
+ sal_uInt16 nPointCount = pEdgeTrack->GetPointCount();
+ ShearPoint((*pEdgeTrack)[sal_uInt16(nPointCount-1)],rRef,tn,bVShear);
+ ImpDirtyEdgeTrack();
+ }
+ }
+}
+
+SdrObjectUniquePtr SdrEdgeObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ aPolyPolygon.append(pEdgeTrack->getB2DPolygon());
+ SdrObjectUniquePtr pRet = ImpConvertMakeObj(aPolyPolygon, false, bBezier);
+
+ if(bAddText)
+ {
+ pRet = ImpConvertAddText(std::move(pRet), bBezier);
+ }
+
+ return pRet;
+}
+
+sal_uInt32 SdrEdgeObj::GetSnapPointCount() const
+{
+ return 2;
+}
+
+Point SdrEdgeObj::GetSnapPoint(sal_uInt32 i) const
+{
+ const_cast<SdrEdgeObj*>(this)->ImpUndirtyEdgeTrack();
+ sal_uInt16 nCount=pEdgeTrack->GetPointCount();
+ if (i==0) return (*pEdgeTrack)[0];
+ else return (*pEdgeTrack)[nCount-1];
+}
+
+bool SdrEdgeObj::IsPolyObj() const
+{
+ return false;
+}
+
+sal_uInt32 SdrEdgeObj::GetPointCount() const
+{
+ return 0;
+}
+
+Point SdrEdgeObj::GetPoint(sal_uInt32 i) const
+{
+ const_cast<SdrEdgeObj*>(this)->ImpUndirtyEdgeTrack();
+ sal_uInt16 nCount=pEdgeTrack->GetPointCount();
+ if (0 == i)
+ return (*pEdgeTrack)[0];
+ else
+ return (*pEdgeTrack)[nCount-1];
+}
+
+void SdrEdgeObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
+{
+ // TODO: Need an implementation to connect differently.
+ ImpUndirtyEdgeTrack();
+ sal_uInt16 nCount=pEdgeTrack->GetPointCount();
+ if (0 == i)
+ (*pEdgeTrack)[0]=rPnt;
+ if (1 == i)
+ (*pEdgeTrack)[nCount-1]=rPnt;
+ SetEdgeTrackDirty();
+ SetBoundAndSnapRectsDirty();
+}
+
+SdrEdgeObjGeoData::SdrEdgeObjGeoData()
+ : pEdgeTrack(std::in_place)
+ , bEdgeTrackDirty(false)
+ , bEdgeTrackUserDefined(false)
+{
+}
+
+SdrEdgeObjGeoData::~SdrEdgeObjGeoData()
+{
+}
+
+std::unique_ptr<SdrObjGeoData> SdrEdgeObj::NewGeoData() const
+{
+ return std::make_unique<SdrEdgeObjGeoData>();
+}
+
+void SdrEdgeObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrTextObj::SaveGeoData(rGeo);
+ SdrEdgeObjGeoData& rEGeo=static_cast<SdrEdgeObjGeoData&>(rGeo);
+ rEGeo.aCon1 =aCon1;
+ rEGeo.aCon2 =aCon2;
+ *rEGeo.pEdgeTrack =*pEdgeTrack;
+ rEGeo.bEdgeTrackDirty=bEdgeTrackDirty;
+ rEGeo.bEdgeTrackUserDefined=bEdgeTrackUserDefined;
+ rEGeo.aEdgeInfo =aEdgeInfo;
+}
+
+void SdrEdgeObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrTextObj::RestoreGeoData(rGeo);
+ const SdrEdgeObjGeoData& rEGeo=static_cast<const SdrEdgeObjGeoData&>(rGeo);
+ if (aCon1.pObj!=rEGeo.aCon1.pObj) {
+ if (aCon1.pObj!=nullptr) aCon1.pObj->RemoveListener(*this);
+ aCon1=rEGeo.aCon1;
+ if (aCon1.pObj!=nullptr) aCon1.pObj->AddListener(*this);
+ }
+ else
+ aCon1=rEGeo.aCon1;
+
+ if (aCon2.pObj!=rEGeo.aCon2.pObj) {
+ if (aCon2.pObj!=nullptr) aCon2.pObj->RemoveListener(*this);
+ aCon2=rEGeo.aCon2;
+ if (aCon2.pObj!=nullptr) aCon2.pObj->AddListener(*this);
+ }
+ else
+ aCon2=rEGeo.aCon2;
+
+ *pEdgeTrack =*rEGeo.pEdgeTrack;
+ bEdgeTrackDirty=rEGeo.bEdgeTrackDirty;
+ bEdgeTrackUserDefined=rEGeo.bEdgeTrackUserDefined;
+ aEdgeInfo =rEGeo.aEdgeInfo;
+}
+
+Point SdrEdgeObj::GetTailPoint( bool bTail ) const
+{
+ if( pEdgeTrack && pEdgeTrack->GetPointCount()!=0)
+ {
+ const XPolygon& rTrack0 = *pEdgeTrack;
+ if(bTail)
+ {
+ return rTrack0[0];
+ }
+ else
+ {
+ const sal_uInt16 nSiz = rTrack0.GetPointCount() - 1;
+ return rTrack0[nSiz];
+ }
+ }
+ else
+ {
+ if(bTail)
+ return m_aOutRect.TopLeft();
+ else
+ return m_aOutRect.BottomRight();
+ }
+
+}
+
+void SdrEdgeObj::SetTailPoint( bool bTail, const Point& rPt )
+{
+ ImpSetTailPoint( bTail, rPt );
+ SetChanged();
+}
+
+/** this method is used by the api to set a gluepoint for a connection
+ nId == -1 : The best default point is automatically chosen
+ 0 <= nId <= 3 : One of the default points is chosen
+ nId >= 4 : A user defined gluepoint is chosen
+*/
+void SdrEdgeObj::setGluePointIndex( bool bTail, sal_Int32 nIndex /* = -1 */ )
+{
+ SdrObjConnection& rConn1 = GetConnection( bTail );
+
+ rConn1.SetAutoVertex( nIndex >= 0 && nIndex <= 3 );
+ rConn1.SetBestConnection( nIndex < 0 );
+ rConn1.SetBestVertex( nIndex < 0 );
+
+ if( nIndex > 3 )
+ {
+ nIndex -= 3; // the start api index is 0, whereas the implementation in svx starts from 1
+
+ // for user defined gluepoints we have
+ // to get the id for this index first
+ const SdrGluePointList* pList = rConn1.GetObject() ? rConn1.GetObject()->GetGluePointList() : nullptr;
+ if( pList == nullptr || SDRGLUEPOINT_NOTFOUND == pList->FindGluePoint(static_cast<sal_uInt16>(nIndex)) )
+ return;
+ }
+ else if( nIndex < 0 )
+ {
+ nIndex = 0;
+ }
+
+ rConn1.SetConnectorId( static_cast<sal_uInt16>(nIndex) );
+
+ SetChanged();
+ SetBoundAndSnapRectsDirty();
+ ImpRecalcEdgeTrack();
+}
+
+/** this method is used by the api to return a gluepoint id for a connection.
+ See setGluePointId for possible return values */
+sal_Int32 SdrEdgeObj::getGluePointIndex( bool bTail )
+{
+ SdrObjConnection& rConn1 = GetConnection( bTail );
+ sal_Int32 nId = -1;
+ if( !rConn1.IsBestConnection() )
+ {
+ nId = rConn1.GetConnectorId();
+ if( !rConn1.IsAutoVertex() )
+ nId += 3; // the start api index is 0, whereas the implementation in svx starts from 1
+ }
+ return nId;
+}
+
+// Implementation was missing; edge track needs to be invalidated additionally.
+void SdrEdgeObj::NbcSetAnchorPos(const Point& rPnt)
+{
+ // call parent functionality
+ SdrTextObj::NbcSetAnchorPos(rPnt);
+
+ // Additionally, invalidate edge track
+ ImpDirtyEdgeTrack();
+}
+
+bool SdrEdgeObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& rPolyPolygon) const
+{
+ // use base method from SdrObject, it's not rotatable and
+ // a call to GetSnapRect() is used. That's what we need for Connector.
+ return SdrObject::TRGetBaseGeometry(rMatrix, rPolyPolygon);
+}
+
+void SdrEdgeObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& rPolyPolygon)
+{
+ // where appropriate take care for existing connections. For now, just use the
+ // implementation from SdrObject.
+ SdrObject::TRSetBaseGeometry(rMatrix, rPolyPolygon);
+}
+
+// for geometry access
+::basegfx::B2DPolygon SdrEdgeObj::getEdgeTrack() const
+{
+ if(bEdgeTrackDirty)
+ {
+ const_cast< SdrEdgeObj* >(this)->ImpRecalcEdgeTrack();
+ }
+
+ if(pEdgeTrack)
+ {
+ return pEdgeTrack->getB2DPolygon();
+ }
+ else
+ {
+ return ::basegfx::B2DPolygon();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdograf.cxx b/svx/source/svdraw/svdograf.cxx
new file mode 100644
index 000000000..c369c5fcc
--- /dev/null
+++ b/svx/source/svdraw/svdograf.cxx
@@ -0,0 +1,1274 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unotools/streamwrap.hxx>
+
+#include <sfx2/lnkbase.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/helpers.hxx>
+#include <tools/stream.hxx>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <vcl/GraphicObject.hxx>
+#include <vcl/svapp.hxx>
+
+#include <sfx2/linkmgr.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdhdl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflbmtit.hxx>
+#include "svdfmtf.hxx"
+#include <sdgcoitm.hxx>
+#include <svx/sdgcpitm.hxx>
+#include <svx/sdggaitm.hxx>
+#include <sdginitm.hxx>
+#include <svx/sdgluitm.hxx>
+#include <svx/sdgmoitm.hxx>
+#include <sdgtritm.hxx>
+#include <sdr/properties/graphicproperties.hxx>
+#include <sdr/contact/viewcontactofgraphic.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/processor2d/objectinfoextractor2d.hxx>
+#include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+
+class SdrGraphicLink : public sfx2::SvBaseLink
+{
+ SdrGrafObj& rGrafObj;
+
+public:
+ explicit SdrGraphicLink(SdrGrafObj& rObj);
+
+ virtual void Closed() override;
+
+ virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
+ const OUString& rMimeType, const css::uno::Any & rValue ) override;
+
+ void Connect() { GetRealObject(); }
+};
+
+SdrGraphicLink::SdrGraphicLink(SdrGrafObj& rObj)
+: ::sfx2::SvBaseLink( ::SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SVXB )
+, rGrafObj( rObj )
+{
+ SetSynchron( false );
+}
+
+::sfx2::SvBaseLink::UpdateResult SdrGraphicLink::DataChanged(
+ const OUString& rMimeType, const css::uno::Any & rValue )
+{
+ SdrModel& rModel(rGrafObj.getSdrModelFromSdrObject());
+ sfx2::LinkManager* pLinkManager(rModel.GetLinkManager());
+
+ if( pLinkManager && rValue.hasValue() )
+ {
+ sfx2::LinkManager::GetDisplayNames( this, nullptr, &rGrafObj.aFileName, nullptr, &rGrafObj.aFilterName );
+
+ Graphic aGraphic;
+ if (pLinkManager->GetGraphicFromAny(rMimeType, rValue, aGraphic, nullptr))
+ {
+ rGrafObj.ImpSetLinkedGraphic(aGraphic);
+ }
+ else if( SotExchange::GetFormatIdFromMimeType( rMimeType ) != sfx2::LinkManager::RegisterStatusInfoId() )
+ {
+ // broadcasting, to update slide sorter
+ rGrafObj.BroadcastObjectChange();
+ }
+ }
+ return SUCCESS;
+}
+
+void SdrGraphicLink::Closed()
+{
+ // close connection; set pLink of the object to NULL, as link instance is just about getting destructed.
+ rGrafObj.ForceSwapIn();
+ rGrafObj.pGraphicLink=nullptr;
+ rGrafObj.ReleaseGraphicLink();
+ SvBaseLink::Closed();
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrGrafObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::GraphicProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrGrafObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfGraphic>(*this);
+}
+
+
+// check if SVG and if try to get ObjectInfoPrimitive2D and extract info
+
+void SdrGrafObj::onGraphicChanged()
+{
+ if (!mpGraphicObject || !mpGraphicObject->GetGraphic().isAvailable())
+ return;
+
+ auto const & rVectorGraphicDataPtr = mpGraphicObject->GetGraphic().getVectorGraphicData();
+
+ if (!rVectorGraphicDataPtr)
+ return;
+
+ // Skip for PDF as it is only a bitmap primitive in a sequence and
+ // doesn't contain metadata. However getting the primitive sequence
+ // will also trigger a premature rendering of the PDF.
+ if (rVectorGraphicDataPtr->getType() == VectorGraphicDataType::Pdf)
+ return;
+
+ const std::deque<css::uno::Reference<css::graphic::XPrimitive2D>>& rContainer(rVectorGraphicDataPtr->getPrimitive2DSequence());
+
+ if (rContainer.empty())
+ return;
+
+ drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ drawinglayer::processor2d::ObjectInfoPrimitiveExtractor2D aProcessor(aViewInformation2D);
+
+ aProcessor.process(rContainer);
+
+ const drawinglayer::primitive2d::ObjectInfoPrimitive2D* pResult = aProcessor.getResult();
+
+ if (!pResult)
+ return;
+
+ OUString aName = pResult->getName();
+ OUString aTitle = pResult->getTitle();
+ OUString aDesc = pResult->getDesc();
+
+ if(!aName.isEmpty())
+ {
+ SetName(aName);
+ }
+
+ if(!aTitle.isEmpty())
+ {
+ SetTitle(aTitle);
+ }
+
+ if(!aDesc.isEmpty())
+ {
+ SetDescription(aDesc);
+ }
+}
+
+SdrGrafObj::SdrGrafObj(SdrModel& rSdrModel)
+: SdrRectObj(rSdrModel)
+ ,mpGraphicObject(new GraphicObject)
+ ,pGraphicLink(nullptr)
+ ,bMirrored(false)
+ ,mbIsSignatureLine(false)
+ ,mbIsSignatureLineShowSignDate(true)
+ ,mbIsSignatureLineCanAddComment(false)
+ ,mbSignatureLineIsSigned(false)
+{
+ onGraphicChanged();
+
+ // #i118485# Shear allowed and possible now
+ mbNoShear = false;
+
+ mbGrafAnimationAllowed = true;
+
+ // #i25616#
+ mbLineIsOutsideGeometry = true;
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+}
+
+SdrGrafObj::SdrGrafObj(SdrModel& rSdrModel, SdrGrafObj const & rSource)
+: SdrRectObj(rSdrModel, rSource)
+ ,mpGraphicObject(new GraphicObject)
+ ,pGraphicLink(nullptr)
+{
+ onGraphicChanged();
+
+ // #i118485# Shear allowed and possible now
+ mbNoShear = false;
+
+ mbGrafAnimationAllowed = true;
+
+ // #i25616#
+ mbLineIsOutsideGeometry = true;
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+
+ aFileName = rSource.aFileName;
+ bMirrored = rSource.bMirrored;
+
+ mbIsSignatureLine = rSource.mbIsSignatureLine;
+ maSignatureLineId = rSource.maSignatureLineId;
+ maSignatureLineSuggestedSignerName = rSource.maSignatureLineSuggestedSignerName;
+ maSignatureLineSuggestedSignerTitle = rSource.maSignatureLineSuggestedSignerTitle;
+ maSignatureLineSuggestedSignerEmail = rSource.maSignatureLineSuggestedSignerEmail;
+ maSignatureLineSigningInstructions = rSource.maSignatureLineSigningInstructions;
+ mbIsSignatureLineShowSignDate = rSource.mbIsSignatureLineShowSignDate;
+ mbIsSignatureLineCanAddComment = rSource.mbIsSignatureLineCanAddComment;
+ mbSignatureLineIsSigned = false;
+ mpSignatureLineUnsignedGraphic = rSource.mpSignatureLineUnsignedGraphic;
+
+ if(rSource.mpBarCode)
+ {
+ mpBarCode = std::make_unique<css::drawing::BarCode>(*rSource.mpBarCode);
+ }
+ else
+ {
+ mpBarCode.reset();
+ }
+
+ if (mbIsSignatureLine && rSource.mpSignatureLineUnsignedGraphic)
+ mpGraphicObject->SetGraphic(rSource.mpSignatureLineUnsignedGraphic);
+ else
+ mpGraphicObject->SetGraphic( rSource.GetGraphic() );
+
+ if( rSource.IsLinkedGraphic() )
+ {
+ SetGraphicLink( aFileName );
+ }
+
+ ImpSetAttrToGrafInfo();
+}
+
+SdrGrafObj::SdrGrafObj(
+ SdrModel& rSdrModel,
+ const Graphic& rGraphic,
+ const tools::Rectangle& rRect)
+: SdrRectObj(rSdrModel, rRect)
+ ,mpGraphicObject(new GraphicObject(rGraphic))
+ ,pGraphicLink(nullptr)
+ ,bMirrored(false)
+ ,mbIsSignatureLine(false)
+ ,mbIsSignatureLineShowSignDate(true)
+ ,mbIsSignatureLineCanAddComment(false)
+ ,mbSignatureLineIsSigned(false)
+{
+ onGraphicChanged();
+
+ // #i118485# Shear allowed and possible now
+ mbNoShear = false;
+
+ mbGrafAnimationAllowed = true;
+
+ // #i25616#
+ mbLineIsOutsideGeometry = true;
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+}
+
+SdrGrafObj::SdrGrafObj(
+ SdrModel& rSdrModel,
+ const Graphic& rGraphic)
+: SdrRectObj(rSdrModel)
+ ,mpGraphicObject(new GraphicObject(rGraphic))
+ ,pGraphicLink(nullptr)
+ ,bMirrored(false)
+ ,mbIsSignatureLine(false)
+ ,mbIsSignatureLineShowSignDate(true)
+ ,mbIsSignatureLineCanAddComment(false)
+ ,mbSignatureLineIsSigned(false)
+{
+ onGraphicChanged();
+
+ // #i118485# Shear allowed and possible now
+ mbNoShear = false;
+
+ mbGrafAnimationAllowed = true;
+
+ // #i25616#
+ mbLineIsOutsideGeometry = true;
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+}
+
+SdrGrafObj::~SdrGrafObj()
+{
+ ImpDeregisterLink();
+}
+
+void SdrGrafObj::SetGraphicObject(const GraphicObject& rGraphicObject)
+{
+ mpGraphicObject.reset(new GraphicObject(rGraphicObject));
+ mpReplacementGraphicObject.reset();
+ mpGraphicObject->SetUserData();
+ SetChanged();
+ BroadcastObjectChange();
+ onGraphicChanged();
+}
+
+const GraphicObject& SdrGrafObj::GetGraphicObject(bool bForceSwapIn) const
+{
+ if (bForceSwapIn)
+ ForceSwapIn();
+ return *mpGraphicObject;
+}
+
+const GraphicObject* SdrGrafObj::GetReplacementGraphicObject() const
+{
+ if (!mpReplacementGraphicObject && mpGraphicObject)
+ {
+ auto const & rVectorGraphicDataPtr = mpGraphicObject->GetGraphic().getVectorGraphicData();
+
+ if (rVectorGraphicDataPtr)
+ {
+ const_cast< SdrGrafObj* >(this)->mpReplacementGraphicObject.reset(new GraphicObject(rVectorGraphicDataPtr->getReplacement()));
+ }
+ else if (mpGraphicObject->GetGraphic().GetType() == GraphicType::GdiMetafile)
+ {
+ // Replacement graphic for PDF and metafiles is just the bitmap.
+ const_cast<SdrGrafObj*>(this)->mpReplacementGraphicObject.reset(new GraphicObject(mpGraphicObject->GetGraphic().GetBitmapEx()));
+ }
+ }
+
+ return mpReplacementGraphicObject.get();
+}
+
+void SdrGrafObj::NbcSetGraphic(const Graphic& rGraphic)
+{
+ mpGraphicObject->SetGraphic(rGraphic);
+ mpReplacementGraphicObject.reset();
+ mpGraphicObject->SetUserData();
+ onGraphicChanged();
+}
+
+void SdrGrafObj::SetGraphic( const Graphic& rGraphic )
+{
+ if (!rGraphic.getOriginURL().isEmpty())
+ {
+ ImpDeregisterLink();
+ aFileName = rGraphic.getOriginURL();
+ aFilterName = "";
+ }
+ NbcSetGraphic(rGraphic);
+ if (!rGraphic.getOriginURL().isEmpty())
+ {
+ ImpRegisterLink();
+ mpGraphicObject->SetUserData();
+ }
+ SetChanged();
+ BroadcastObjectChange();
+ ForceSwapIn();
+}
+
+const Graphic& SdrGrafObj::GetGraphic() const
+{
+ return mpGraphicObject->GetGraphic();
+}
+
+Graphic SdrGrafObj::GetTransformedGraphic( SdrGrafObjTransformsAttrs nTransformFlags ) const
+{
+ // Refactored most of the code to GraphicObject, where
+ // everybody can use e.g. the cropping functionality
+ MapMode aDestMap(
+ getSdrModelFromSdrObject().GetScaleUnit(),
+ Point(),
+ getSdrModelFromSdrObject().GetScaleFraction(),
+ getSdrModelFromSdrObject().GetScaleFraction());
+ const Size aDestSize( GetLogicRect().GetSize() );
+ GraphicAttr aActAttr = GetGraphicAttr(nTransformFlags);
+
+ // Delegate to moved code in GraphicObject
+ return GetGraphicObject().GetTransformedGraphic( aDestSize, aDestMap, aActAttr );
+}
+
+GraphicType SdrGrafObj::GetGraphicType() const
+{
+ return mpGraphicObject->GetType();
+}
+
+GraphicAttr SdrGrafObj::GetGraphicAttr( SdrGrafObjTransformsAttrs nTransformFlags ) const
+{
+ GraphicAttr aActAttr;
+
+ GraphicType eType = GetGraphicType();
+ if( SdrGrafObjTransformsAttrs::NONE != nTransformFlags &&
+ GraphicType::NONE != eType )
+ {
+ const bool bMirror = bool( nTransformFlags & SdrGrafObjTransformsAttrs::MIRROR );
+ const bool bRotate = bool( nTransformFlags & SdrGrafObjTransformsAttrs::ROTATE ) &&
+ (maGeo.nRotationAngle && maGeo.nRotationAngle != 18000_deg100);
+
+ // Need cropping info earlier
+ const_cast<SdrGrafObj*>(this)->ImpSetAttrToGrafInfo();
+
+ // Actually transform the graphic only in this case.
+ // Cropping always happens, though.
+ aActAttr = aGrafInfo;
+
+ if( bMirror )
+ {
+ sal_uInt16 nMirrorCase = ( maGeo.nRotationAngle == 18000_deg100 ) ? ( bMirrored ? 3 : 4 ) : ( bMirrored ? 2 : 1 );
+ bool bHMirr = nMirrorCase == 2 || nMirrorCase == 4;
+ bool bVMirr = nMirrorCase == 3 || nMirrorCase == 4;
+
+ aActAttr.SetMirrorFlags( ( bHMirr ? BmpMirrorFlags::Horizontal : BmpMirrorFlags::NONE ) | ( bVMirr ? BmpMirrorFlags::Vertical : BmpMirrorFlags::NONE ) );
+ }
+
+ if( bRotate )
+ aActAttr.SetRotation( to<Degree10>(maGeo.nRotationAngle ) );
+ }
+
+ return aActAttr;
+}
+
+bool SdrGrafObj::IsAnimated() const
+{
+ return mpGraphicObject->IsAnimated();
+}
+
+bool SdrGrafObj::IsEPS() const
+{
+ return mpGraphicObject->IsEPS();
+}
+
+MapMode SdrGrafObj::GetGrafPrefMapMode() const
+{
+ return mpGraphicObject->GetPrefMapMode();
+}
+
+Size SdrGrafObj::GetGrafPrefSize() const
+{
+ return mpGraphicObject->GetPrefSize();
+}
+
+void SdrGrafObj::SetGrafStreamURL( const OUString& rGraphicStreamURL )
+{
+ if( rGraphicStreamURL.isEmpty() )
+ {
+ mpGraphicObject->SetUserData();
+ }
+ else if(getSdrModelFromSdrObject().IsSwapGraphics() )
+ {
+ mpGraphicObject->SetUserData( rGraphicStreamURL );
+ }
+}
+
+OUString const & SdrGrafObj::GetGrafStreamURL() const
+{
+ return mpGraphicObject->GetUserData();
+}
+
+Size SdrGrafObj::getOriginalSize() const
+{
+ Size aSize = GetGrafPrefSize();
+
+ if (aGrafInfo.IsCropped())
+ {
+ const tools::Long aCroppedTop(OutputDevice::LogicToLogic(aGrafInfo.GetTopCrop(), getSdrModelFromSdrObject().GetScaleUnit(), GetGrafPrefMapMode().GetMapUnit()));
+ const tools::Long aCroppedBottom(OutputDevice::LogicToLogic(aGrafInfo.GetBottomCrop(), getSdrModelFromSdrObject().GetScaleUnit(), GetGrafPrefMapMode().GetMapUnit()));
+ const tools::Long aCroppedLeft(OutputDevice::LogicToLogic(aGrafInfo.GetLeftCrop(), getSdrModelFromSdrObject().GetScaleUnit(), GetGrafPrefMapMode().GetMapUnit()));
+ const tools::Long aCroppedRight(OutputDevice::LogicToLogic(aGrafInfo.GetRightCrop(), getSdrModelFromSdrObject().GetScaleUnit(), GetGrafPrefMapMode().GetMapUnit()));
+ const tools::Long aCroppedWidth(aSize.getWidth() - aCroppedLeft + aCroppedRight);
+ const tools::Long aCroppedHeight(aSize.getHeight() - aCroppedTop + aCroppedBottom);
+
+ aSize = Size ( aCroppedWidth, aCroppedHeight);
+ }
+
+ if ( GetGrafPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
+ aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, MapMode(getSdrModelFromSdrObject().GetScaleUnit()));
+ else
+ aSize = OutputDevice::LogicToLogic(aSize, GetGrafPrefMapMode(), MapMode(getSdrModelFromSdrObject().GetScaleUnit()));
+
+ return aSize;
+}
+
+// TODO Remove
+void SdrGrafObj::ForceSwapIn() const
+{
+ if (pGraphicLink && (mpGraphicObject->GetType() == GraphicType::NONE ||
+ mpGraphicObject->GetType() == GraphicType::Default) )
+ {
+ pGraphicLink->Update();
+ }
+}
+
+void SdrGrafObj::ImpRegisterLink()
+{
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
+
+ if( pLinkManager != nullptr && pGraphicLink == nullptr )
+ {
+ if (!aFileName.isEmpty())
+ {
+ pGraphicLink = new SdrGraphicLink( *this );
+ pLinkManager->InsertFileLink(
+ *pGraphicLink, sfx2::SvBaseLinkObjectType::ClientGraphic, aFileName, (aFilterName.isEmpty() ? nullptr : &aFilterName));
+ pGraphicLink->Connect();
+ }
+ }
+}
+
+void SdrGrafObj::ImpDeregisterLink()
+{
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
+
+ if( pLinkManager != nullptr && pGraphicLink!=nullptr)
+ {
+ // When using Remove, the *pGraphicLink is implicitly deleted
+ pLinkManager->Remove( pGraphicLink );
+ pGraphicLink=nullptr;
+ }
+}
+
+void SdrGrafObj::SetGraphicLink(const OUString& rFileName)
+{
+ Graphic aGraphic;
+ aGraphic.setOriginURL(rFileName);
+ SetGraphic(aGraphic);
+}
+
+void SdrGrafObj::ReleaseGraphicLink()
+{
+ ImpDeregisterLink();
+ aFileName.clear();
+ aFilterName.clear();
+
+ auto aGraphic = mpGraphicObject->GetGraphic();
+ aGraphic.setOriginURL("");
+ SetGraphic(aGraphic);
+}
+
+bool SdrGrafObj::IsLinkedGraphic() const
+{
+ return !mpGraphicObject->GetGraphic().getOriginURL().isEmpty();
+}
+
+void SdrGrafObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ bool bNoPresGrf = ( mpGraphicObject->GetType() != GraphicType::NONE ) && !m_bEmptyPresObj;
+
+ rInfo.bResizeFreeAllowed = maGeo.nRotationAngle.get() % 9000 == 0 ||
+ maGeo.nRotationAngle.get() % 18000 == 0 ||
+ maGeo.nRotationAngle.get() % 27000 == 0;
+
+ rInfo.bResizePropAllowed = true;
+ rInfo.bRotateFreeAllowed = bNoPresGrf;
+ rInfo.bRotate90Allowed = bNoPresGrf;
+ rInfo.bMirrorFreeAllowed = bNoPresGrf;
+ rInfo.bMirror45Allowed = bNoPresGrf;
+ rInfo.bMirror90Allowed = !m_bEmptyPresObj;
+ rInfo.bTransparenceAllowed = false;
+
+ // #i118485# Shear allowed and possible now
+ rInfo.bShearAllowed = true;
+
+ rInfo.bEdgeRadiusAllowed=false;
+ rInfo.bCanConvToPath = !IsEPS();
+ rInfo.bCanConvToPathLineToArea = false;
+ rInfo.bCanConvToPolyLineToArea = false;
+ rInfo.bCanConvToPoly = !IsEPS();
+ rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
+}
+
+SdrObjKind SdrGrafObj::GetObjIdentifier() const
+{
+ return SdrObjKind::Graphic;
+}
+
+void SdrGrafObj::ImpSetLinkedGraphic( const Graphic& rGraphic )
+{
+ const bool bIsChanged(getSdrModelFromSdrObject().IsChanged());
+ NbcSetGraphic( rGraphic );
+ ActionChanged();
+ BroadcastObjectChange();
+ getSdrModelFromSdrObject().SetChanged(bIsChanged);
+}
+
+OUString SdrGrafObj::TakeObjNameSingul() const
+{
+ if (!mpGraphicObject)
+ return OUString();
+
+ auto const & rVectorGraphicDataPtr = mpGraphicObject->GetGraphic().getVectorGraphicData();
+
+ OUStringBuffer sName;
+
+ if (rVectorGraphicDataPtr)
+ {
+ switch (rVectorGraphicDataPtr->getType())
+ {
+ case VectorGraphicDataType::Svg:
+ {
+ sName.append(SvxResId(STR_ObjNameSingulGRAFSVG));
+ break;
+ }
+ case VectorGraphicDataType::Wmf:
+ {
+ sName.append(SvxResId(STR_ObjNameSingulGRAFWMF));
+ break;
+ }
+ case VectorGraphicDataType::Emf:
+ {
+ sName.append(SvxResId(STR_ObjNameSingulGRAFEMF));
+ break;
+ }
+ case VectorGraphicDataType::Pdf:
+ {
+ sName.append(SvxResId(STR_ObjNameSingulGRAFPDF));
+ break;
+ }
+ } //no default, see tdf#137813
+ }
+ else
+ {
+ switch( mpGraphicObject->GetType() )
+ {
+ case GraphicType::Bitmap:
+ {
+ TranslateId pId = ( ( mpGraphicObject->IsTransparent() || GetObjectItem( SDRATTR_GRAFTRANSPARENCE ).GetValue() ) ?
+ ( IsLinkedGraphic() ? STR_ObjNameSingulGRAFBMPTRANSLNK : STR_ObjNameSingulGRAFBMPTRANS ) :
+ ( IsLinkedGraphic() ? STR_ObjNameSingulGRAFBMPLNK : STR_ObjNameSingulGRAFBMP ) );
+
+ sName.append(SvxResId(pId));
+ }
+ break;
+
+ case GraphicType::GdiMetafile:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNameSingulGRAFMTFLNK : STR_ObjNameSingulGRAFMTF));
+ break;
+
+ case GraphicType::NONE:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNameSingulGRAFNONELNK : STR_ObjNameSingulGRAFNONE));
+ break;
+
+ default:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNameSingulGRAFLNK : STR_ObjNameSingulGRAF));
+ break;
+ }
+ }
+
+ const OUString aName(GetName());
+
+ if (!aName.isEmpty())
+ {
+ sName.append(" '");
+ sName.append(aName);
+ sName.append('\'' );
+ }
+
+ return sName.makeStringAndClear();
+}
+
+OUString SdrGrafObj::TakeObjNamePlural() const
+{
+ if (!mpGraphicObject)
+ return OUString();
+
+ auto const & rVectorGraphicDataPtr = mpGraphicObject->GetGraphic().getVectorGraphicData();
+
+ OUStringBuffer sName;
+
+ if (rVectorGraphicDataPtr)
+ {
+ switch (rVectorGraphicDataPtr->getType())
+ {
+ case VectorGraphicDataType::Svg:
+ {
+ sName.append(SvxResId(STR_ObjNamePluralGRAFSVG));
+ break;
+ }
+ case VectorGraphicDataType::Wmf:
+ {
+ sName.append(SvxResId(STR_ObjNamePluralGRAFWMF));
+ break;
+ }
+ case VectorGraphicDataType::Emf:
+ {
+ sName.append(SvxResId(STR_ObjNamePluralGRAFEMF));
+ break;
+ }
+ case VectorGraphicDataType::Pdf:
+ {
+ sName.append(SvxResId(STR_ObjNamePluralGRAFPDF));
+ break;
+ }
+ } //no default, see tdf#137813
+ }
+ else
+ {
+ switch(mpGraphicObject->GetType())
+ {
+ case GraphicType::Bitmap:
+ {
+ TranslateId pId = ( ( mpGraphicObject->IsTransparent() || GetObjectItem( SDRATTR_GRAFTRANSPARENCE ).GetValue() ) ?
+ ( IsLinkedGraphic() ? STR_ObjNamePluralGRAFBMPTRANSLNK : STR_ObjNamePluralGRAFBMPTRANS ) :
+ ( IsLinkedGraphic() ? STR_ObjNamePluralGRAFBMPLNK : STR_ObjNamePluralGRAFBMP ) );
+
+ sName.append(SvxResId(pId));
+ }
+ break;
+
+ case GraphicType::GdiMetafile:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNamePluralGRAFMTFLNK : STR_ObjNamePluralGRAFMTF));
+ break;
+
+ case GraphicType::NONE:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNamePluralGRAFNONELNK : STR_ObjNamePluralGRAFNONE));
+ break;
+
+ default:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNamePluralGRAFLNK : STR_ObjNamePluralGRAF));
+ break;
+ }
+ }
+
+ const OUString aName(GetName());
+
+ if (!aName.isEmpty())
+ {
+ sName.append(" '");
+ sName.append(aName);
+ sName.append('\'');
+ }
+
+ return sName.makeStringAndClear();
+}
+
+SdrObjectUniquePtr SdrGrafObj::getFullDragClone() const
+{
+ // call parent
+ SdrObjectUniquePtr pRetval = SdrRectObj::getFullDragClone();
+
+ // #i103116# the full drag clone leads to problems
+ // with linked graphics, so reset the link in this
+ // temporary interaction object and load graphic
+ if(pRetval && IsLinkedGraphic())
+ {
+ static_cast< SdrGrafObj* >(pRetval.get())->ReleaseGraphicLink();
+ }
+
+ return pRetval;
+}
+
+SdrGrafObj* SdrGrafObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrGrafObj(rTargetModel, *this);
+}
+
+sal_uInt32 SdrGrafObj::GetHdlCount() const
+{
+ return 8;
+}
+
+void SdrGrafObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ SdrHdlList tempList(nullptr);
+ SdrRectObj::AddToHdlList( tempList );
+ tempList.RemoveHdl(0);
+ tempList.MoveTo(rHdlList);
+}
+
+void SdrGrafObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ SdrRectObj::NbcResize( rRef, xFact, yFact );
+
+ bool bMirrX = xFact.GetNumerator() < 0;
+ bool bMirrY = yFact.GetNumerator() < 0;
+
+ if( bMirrX != bMirrY )
+ bMirrored = !bMirrored;
+}
+
+void SdrGrafObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ SdrRectObj::NbcMirror(rRef1,rRef2);
+ bMirrored = !bMirrored;
+}
+
+std::unique_ptr<SdrObjGeoData> SdrGrafObj::NewGeoData() const
+{
+ return std::make_unique<SdrGrafObjGeoData>();
+}
+
+void SdrGrafObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrRectObj::SaveGeoData(rGeo);
+ SdrGrafObjGeoData& rGGeo=static_cast<SdrGrafObjGeoData&>(rGeo);
+ rGGeo.bMirrored=bMirrored;
+}
+
+void SdrGrafObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrRectObj::RestoreGeoData(rGeo);
+ const SdrGrafObjGeoData& rGGeo=static_cast<const SdrGrafObjGeoData&>(rGeo);
+ bMirrored=rGGeo.bMirrored;
+}
+
+void SdrGrafObj::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ const bool bRemove(pNewPage == nullptr && pOldPage != nullptr);
+ const bool bInsert(pNewPage != nullptr && pOldPage == nullptr);
+
+ if( bRemove )
+ {
+ // No SwapIn necessary here, because if something's not loaded, it can't be animated either.
+ if( mpGraphicObject->IsAnimated())
+ mpGraphicObject->StopAnimation();
+
+ if( pGraphicLink != nullptr )
+ ImpDeregisterLink();
+ }
+
+ // call parent
+ SdrRectObj::handlePageChange(pOldPage, pNewPage);
+
+ if (!aFileName.isEmpty() && bInsert)
+ {
+ ImpRegisterLink();
+ }
+}
+
+void SdrGrafObj::StartAnimation()
+{
+ SetGrafAnimationAllowed(true);
+}
+
+bool SdrGrafObj::HasGDIMetaFile() const
+{
+ return( mpGraphicObject->GetType() == GraphicType::GdiMetafile );
+}
+
+bool SdrGrafObj::isEmbeddedVectorGraphicData() const
+{
+ return GraphicType::Bitmap == GetGraphicType() && GetGraphic().getVectorGraphicData();
+}
+
+GDIMetaFile SdrGrafObj::getMetafileFromEmbeddedVectorGraphicData() const
+{
+ GDIMetaFile aRetval;
+
+ if(isEmbeddedVectorGraphicData())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pOut;
+ const tools::Rectangle aBoundRect(GetCurrentBoundRect());
+ const MapMode aMap(
+ getSdrModelFromSdrObject().GetScaleUnit(),
+ Point(),
+ getSdrModelFromSdrObject().GetScaleFraction(),
+ getSdrModelFromSdrObject().GetScaleFraction());
+
+ pOut->EnableOutput(false);
+ pOut->SetMapMode(aMap);
+ aRetval.Record(pOut);
+ SingleObjectPainter(*pOut);
+ aRetval.Stop();
+ aRetval.WindStart();
+ aRetval.Move(-aBoundRect.Left(), -aBoundRect.Top());
+ aRetval.SetPrefMapMode(aMap);
+ aRetval.SetPrefSize(aBoundRect.GetSize());
+ }
+
+ return aRetval;
+}
+
+GDIMetaFile SdrGrafObj::GetMetaFile(GraphicType &rGraphicType) const
+{
+ if (isEmbeddedVectorGraphicData())
+ {
+ // Embedded Vector Graphic Data
+ // There is currently no helper to create SdrObjects from primitives (even if I'm thinking
+ // about writing one for some time). To get the roundtrip to SdrObjects it is necessary to
+ // use the old converter path over the MetaFile mechanism. Create Metafile from Svg
+ // primitives here pretty directly
+ rGraphicType = GraphicType::GdiMetafile;
+ return getMetafileFromEmbeddedVectorGraphicData();
+ }
+ else if (GraphicType::GdiMetafile == rGraphicType)
+ {
+ return GetTransformedGraphic(SdrGrafObjTransformsAttrs::MIRROR).GetGDIMetaFile();
+ }
+ return GDIMetaFile();
+}
+
+SdrObjectUniquePtr SdrGrafObj::DoConvertToPolyObj(bool bBezier, bool bAddText ) const
+{
+ SdrObject* pRetval = nullptr;
+ GraphicType aGraphicType(GetGraphicType());
+ GDIMetaFile aMtf(GetMetaFile(aGraphicType));
+ switch(aGraphicType)
+ {
+ case GraphicType::GdiMetafile:
+ {
+ // Sort into group and return ONLY those objects that can be created from the MetaFile.
+ ImpSdrGDIMetaFileImport aFilter(
+ getSdrModelFromSdrObject(),
+ GetLayer(),
+ maRect);
+ SdrObjGroup* pGrp = new SdrObjGroup(getSdrModelFromSdrObject());
+
+ if(aFilter.DoImport(aMtf, *pGrp->GetSubList(), 0))
+ {
+ {
+ // copy transformation
+ GeoStat aGeoStat(GetGeoStat());
+
+ if(aGeoStat.nShearAngle)
+ {
+ aGeoStat.RecalcTan();
+ pGrp->NbcShear(maRect.TopLeft(), aGeoStat.nShearAngle, aGeoStat.mfTanShearAngle, false);
+ }
+
+ if(aGeoStat.nRotationAngle)
+ {
+ aGeoStat.RecalcSinCos();
+ pGrp->NbcRotate(maRect.TopLeft(), aGeoStat.nRotationAngle, aGeoStat.mfSinRotationAngle, aGeoStat.mfCosRotationAngle);
+ }
+ }
+
+ pRetval = pGrp;
+ pGrp->NbcSetLayer(GetLayer());
+
+ if(bAddText)
+ {
+ pRetval = ImpConvertAddText(SdrObjectUniquePtr(pRetval), bBezier).release();
+ }
+
+ // convert all children
+ if( pRetval )
+ {
+ SdrObject* pHalfDone = pRetval;
+ pRetval = pRetval->DoConvertToPolyObj(bBezier, bAddText).release();
+ SdrObject::Free( pHalfDone ); // resulting object is newly created
+
+ if( pRetval )
+ {
+ // flatten subgroups. As we call
+ // DoConvertToPolyObj() on the resulting group
+ // objects, subgroups can exist (e.g. text is
+ // a group object for every line).
+ SdrObjList* pList = pRetval->GetSubList();
+ if( pList )
+ pList->FlattenGroups();
+ }
+ }
+ }
+ else
+ {
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pGrp);
+ SdrObject::Free(pTemp);
+ }
+
+ // #i118485# convert line and fill
+ SdrObjectUniquePtr pLineFill = SdrRectObj::DoConvertToPolyObj(bBezier, false);
+
+ if(pLineFill)
+ {
+ if(pRetval)
+ {
+ pGrp = dynamic_cast< SdrObjGroup* >(pRetval);
+
+ if(!pGrp)
+ {
+ pGrp = new SdrObjGroup(getSdrModelFromSdrObject());
+ pGrp->NbcSetLayer(GetLayer());
+ pGrp->GetSubList()->NbcInsertObject(pRetval);
+ }
+
+ pGrp->GetSubList()->NbcInsertObject(pLineFill.release(), 0);
+ }
+ else
+ {
+ pRetval = pLineFill.release();
+ }
+ }
+
+ break;
+ }
+ case GraphicType::Bitmap:
+ {
+ // create basic object and add fill
+ pRetval = SdrRectObj::DoConvertToPolyObj(bBezier, bAddText).release();
+
+ // save bitmap as an attribute
+ if(pRetval)
+ {
+ // retrieve bitmap for the fill
+ SfxItemSet aSet(GetObjectItemSet());
+
+ aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP));
+ const BitmapEx aBitmapEx(GetTransformedGraphic().GetBitmapEx());
+ aSet.Put(XFillBitmapItem(OUString(), Graphic(aBitmapEx)));
+ aSet.Put(XFillBmpTileItem(false));
+
+ pRetval->SetMergedItemSet(aSet);
+ }
+ break;
+ }
+ case GraphicType::NONE:
+ case GraphicType::Default:
+ {
+ pRetval = SdrRectObj::DoConvertToPolyObj(bBezier, bAddText).release();
+ break;
+ }
+ }
+
+ return SdrObjectUniquePtr(pRetval);
+}
+
+void SdrGrafObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ SetXPolyDirty();
+ SdrRectObj::Notify( rBC, rHint );
+ ImpSetAttrToGrafInfo();
+}
+
+
+void SdrGrafObj::SetMirrored( bool _bMirrored )
+{
+ bMirrored = _bMirrored;
+}
+
+void SdrGrafObj::ImpSetAttrToGrafInfo()
+{
+ const SfxItemSet& rSet = GetObjectItemSet();
+ const sal_uInt16 nTrans = rSet.Get( SDRATTR_GRAFTRANSPARENCE ).GetValue();
+ const SdrGrafCropItem& rCrop = rSet.Get( SDRATTR_GRAFCROP );
+
+ aGrafInfo.SetLuminance( rSet.Get( SDRATTR_GRAFLUMINANCE ).GetValue() );
+ aGrafInfo.SetContrast( rSet.Get( SDRATTR_GRAFCONTRAST ).GetValue() );
+ aGrafInfo.SetChannelR( rSet.Get( SDRATTR_GRAFRED ).GetValue() );
+ aGrafInfo.SetChannelG( rSet.Get( SDRATTR_GRAFGREEN ).GetValue() );
+ aGrafInfo.SetChannelB( rSet.Get( SDRATTR_GRAFBLUE ).GetValue() );
+ aGrafInfo.SetGamma( rSet.Get( SDRATTR_GRAFGAMMA ).GetValue() * 0.01 );
+ aGrafInfo.SetAlpha( 255 - static_cast<sal_uInt8>(FRound( std::min( nTrans, sal_uInt16(100) ) * 2.55 )) );
+ aGrafInfo.SetInvert( rSet.Get( SDRATTR_GRAFINVERT ).GetValue() );
+ aGrafInfo.SetDrawMode( rSet.Get( SDRATTR_GRAFMODE ).GetValue() );
+ aGrafInfo.SetCrop( rCrop.GetLeft(), rCrop.GetTop(), rCrop.GetRight(), rCrop.GetBottom() );
+
+ SetXPolyDirty();
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrGrafObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool bShrinkOnly )
+{
+ Size aSize;
+ Size aMaxSize( rMaxRect.GetSize() );
+ if (mpGraphicObject->GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ aSize = Application::GetDefaultDevice()->PixelToLogic(mpGraphicObject->GetPrefSize(), MapMode(MapUnit::Map100thMM));
+ else
+ aSize = OutputDevice::LogicToLogic( mpGraphicObject->GetPrefSize(),
+ mpGraphicObject->GetPrefMapMode(),
+ MapMode( MapUnit::Map100thMM ) );
+
+ if( aSize.IsEmpty() )
+ return;
+
+ Point aPos( rMaxRect.TopLeft() );
+
+ // if the graphic is too large, fit it to page
+ if ( (!bShrinkOnly ||
+ ( aSize.Height() > aMaxSize.Height() ) ||
+ ( aSize.Width() > aMaxSize.Width() ) )&&
+ aSize.Height() && aMaxSize.Height() )
+ {
+ float fGrfWH = static_cast<float>(aSize.Width()) /
+ static_cast<float>(aSize.Height());
+ float fWinWH = static_cast<float>(aMaxSize.Width()) /
+ static_cast<float>(aMaxSize.Height());
+
+ // Scale graphic to page size
+ if ( fGrfWH < fWinWH )
+ {
+ aSize.setWidth( static_cast<tools::Long>(aMaxSize.Height() * fGrfWH) );
+ aSize.setHeight( aMaxSize.Height() );
+ }
+ else if ( fGrfWH > 0.F )
+ {
+ aSize.setWidth( aMaxSize.Width() );
+ aSize.setHeight( static_cast<tools::Long>(aMaxSize.Width() / fGrfWH) );
+ }
+
+ aPos = rMaxRect.Center();
+ }
+
+ if( bShrinkOnly )
+ aPos = maRect.TopLeft();
+
+ aPos.AdjustX( -(aSize.Width() / 2) );
+ aPos.AdjustY( -(aSize.Height() / 2) );
+ SetLogicRect( tools::Rectangle( aPos, aSize ) );
+}
+
+void SdrGrafObj::SetGrafAnimationAllowed(bool bNew)
+{
+ if(mbGrafAnimationAllowed != bNew)
+ {
+ mbGrafAnimationAllowed = bNew;
+ ActionChanged();
+ }
+}
+
+Reference< XInputStream > SdrGrafObj::getInputStream() const
+{
+ Reference< XInputStream > xStream;
+
+ if (mpGraphicObject && GetGraphic().IsGfxLink())
+ {
+ Graphic aGraphic( GetGraphic() );
+ GfxLink aLink( aGraphic.GetGfxLink() );
+ sal_uInt32 nSize = aLink.GetDataSize();
+ const void* pSourceData = static_cast<const void*>(aLink.GetData());
+ if( nSize && pSourceData )
+ {
+ sal_uInt8 * pBuffer = new sal_uInt8[ nSize ];
+ memcpy( pBuffer, pSourceData, nSize );
+
+ SvMemoryStream* pStream = new SvMemoryStream( static_cast<void*>(pBuffer), static_cast<std::size_t>(nSize), StreamMode::READ );
+ pStream->ObjectOwnsMemory( true );
+ xStream.set( new utl::OInputStreamWrapper( pStream, true ) );
+ }
+ }
+
+ if (!xStream.is() && !aFileName.isEmpty())
+ {
+ SvFileStream* pStream = new SvFileStream( aFileName, StreamMode::READ );
+ xStream.set( new utl::OInputStreamWrapper( pStream ) );
+ }
+
+ return xStream;
+}
+
+// moved crop handle creation here; this is the object type using them
+void SdrGrafObj::addCropHandles(SdrHdlList& rTarget) const
+{
+ basegfx::B2DHomMatrix aMatrix;
+ basegfx::B2DPolyPolygon aPolyPolygon;
+
+ // get object transformation
+ TRGetBaseGeometry(aMatrix, aPolyPolygon);
+
+ // part of object transformation correction, but used later, so defined outside next scope
+ double fShearX(0.0), fRotate(0.0);
+
+ { // TTTT correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+
+ aMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ if(!basegfx::fTools::equalZero(fShearX))
+ {
+ // shearX is used, correct it
+ fShearX = -fShearX;
+ }
+
+ aMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale,
+ fShearX,
+ fRotate,
+ aTranslate);
+ }
+
+ // get crop values
+ const SdrGrafCropItem& rCrop = GetMergedItem(SDRATTR_GRAFCROP);
+
+ if(rCrop.GetLeft() || rCrop.GetTop() || rCrop.GetRight() ||rCrop.GetBottom())
+ {
+ // decompose object transformation to have current translate and scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fLclRotate, fLclShearX;
+
+ aMatrix.decompose(aScale, aTranslate, fLclRotate, fLclShearX);
+
+ if(!aScale.equalZero())
+ {
+ // get crop scale
+ const basegfx::B2DVector aCropScaleFactor(
+ GetGraphicObject().calculateCropScaling(
+ aScale.getX(),
+ aScale.getY(),
+ rCrop.GetLeft(),
+ rCrop.GetTop(),
+ rCrop.GetRight(),
+ rCrop.GetBottom()));
+
+ // apply crop scale
+ const double fCropLeft(rCrop.GetLeft() * aCropScaleFactor.getX());
+ const double fCropTop(rCrop.GetTop() * aCropScaleFactor.getY());
+ const double fCropRight(rCrop.GetRight() * aCropScaleFactor.getX());
+ const double fCropBottom(rCrop.GetBottom() * aCropScaleFactor.getY());
+ basegfx::B2DHomMatrix aMatrixForCropViewHdl(aMatrix);
+
+ if(IsMirrored())
+ {
+ // create corrected new matrix, TTTT can be removed with aw080
+ // the old mirror only can mirror horizontally; the vertical mirror
+ // is faked by using the horizontal and 180 degree rotation. Since
+ // the object can be rotated differently from 180 degree, this is
+ // not safe to detect. Just correct horizontal mirror (which is
+ // in IsMirrored()) and keep the rotation angle
+ // caution: Do not modify aMatrix, it is used below to calculate
+ // the exact handle positions
+ basegfx::B2DHomMatrix aPreMultiply;
+
+ // mirrored X, apply
+ aPreMultiply.translate(-0.5, 0.0);
+ aPreMultiply.scale(-1.0, 1.0);
+ aPreMultiply.translate(0.5, 0.0);
+
+ aMatrixForCropViewHdl = aMatrixForCropViewHdl * aPreMultiply;
+ }
+
+ rTarget.AddHdl(
+ std::make_unique<SdrCropViewHdl>(
+ aMatrixForCropViewHdl,
+ GetGraphicObject().GetGraphic(),
+ fCropLeft,
+ fCropTop,
+ fCropRight,
+ fCropBottom));
+ }
+ }
+
+ basegfx::B2DPoint aPos;
+
+ aPos = aMatrix * basegfx::B2DPoint(0.0, 0.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperLeft, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(0.5, 0.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Upper, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(1.0, 0.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperRight, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(0.0, 0.5);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Left , fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(1.0, 0.5);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Right, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(0.0, 1.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerLeft, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(0.5, 1.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Lower, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(1.0, 1.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerRight, fShearX, fRotate));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdogrp.cxx b/svx/source/svdraw/svdogrp.cxx
new file mode 100644
index 000000000..7fc8e0b12
--- /dev/null
+++ b/svx/source/svdraw/svdogrp.cxx
@@ -0,0 +1,835 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdogrp.hxx>
+
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+#include <sdr/properties/groupproperties.hxx>
+#include <sdr/contact/viewcontactofgroup.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <libxml/xmlwriter.h>
+#include <vcl/canvastools.hxx>
+#include <svx/diagram/IDiagramHelper.hxx>
+
+const std::shared_ptr< svx::diagram::IDiagramHelper >& SdrObjGroup::getDiagramHelper() const
+{
+ return mp_DiagramHelper;
+}
+
+// BaseProperties section
+std::unique_ptr<sdr::properties::BaseProperties> SdrObjGroup::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::GroupProperties>(*this);
+}
+
+// DrawContact section
+std::unique_ptr<sdr::contact::ViewContact> SdrObjGroup::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfGroup>(*this);
+}
+
+SdrObjGroup::SdrObjGroup(SdrModel& rSdrModel)
+: SdrObject(rSdrModel)
+, SdrObjList()
+, maRefPoint(0, 0)
+, mp_DiagramHelper()
+{
+ m_bClosedObj=false;
+}
+
+SdrObjGroup::SdrObjGroup(SdrModel& rSdrModel, SdrObjGroup const & rSource)
+: SdrObject(rSdrModel, rSource)
+, SdrObjList()
+, maRefPoint(0, 0)
+, mp_DiagramHelper()
+{
+ m_bClosedObj=false;
+
+ // copy child SdrObjects
+ if(nullptr != rSource.GetSubList())
+ {
+ // #i36404# Copy SubList, init model and page first
+ const SdrObjList& rSourceSubList(*rSource.GetSubList());
+
+ CopyObjects(rSourceSubList);
+
+ // tdf#116979: needed here, we need bSnapRectDirty to be true
+ // which it is after using SdrObject::operator= (see above),
+ // but set to false again using CopyObjects
+ SetBoundAndSnapRectsDirty();
+ }
+
+ // copy local parameters
+ maRefPoint = rSource.maRefPoint;
+}
+
+void SdrObjGroup::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ // only for diagram, so do nothing for just groups
+ if(!isDiagram())
+ return;
+
+ svx::diagram::IDiagramHelper::AddAdditionalVisualization(*this, rHdlList);
+}
+
+SdrObjGroup::~SdrObjGroup()
+{
+}
+
+SdrPage* SdrObjGroup::getSdrPageFromSdrObjList() const
+{
+ return getSdrPageFromSdrObject();
+}
+
+SdrObject* SdrObjGroup::getSdrObjectFromSdrObjList() const
+{
+ return const_cast< SdrObjGroup* >(this);
+}
+
+SdrObjList* SdrObjGroup::getChildrenOfSdrObject() const
+{
+ return const_cast< SdrObjGroup* >(this);
+}
+
+void SdrObjGroup::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bNoContortion=false;
+ const size_t nObjCount(GetObjCount());
+ for (size_t i=0; i<nObjCount; ++i) {
+ SdrObject* pObj(GetObj(i));
+ SdrObjTransformInfoRec aInfo;
+ pObj->TakeObjInfo(aInfo);
+ if (!aInfo.bMoveAllowed ) rInfo.bMoveAllowed =false;
+ if (!aInfo.bResizeFreeAllowed ) rInfo.bResizeFreeAllowed =false;
+ if (!aInfo.bResizePropAllowed ) rInfo.bResizePropAllowed =false;
+ if (!aInfo.bRotateFreeAllowed ) rInfo.bRotateFreeAllowed =false;
+ if (!aInfo.bRotate90Allowed ) rInfo.bRotate90Allowed =false;
+ if (!aInfo.bMirrorFreeAllowed ) rInfo.bMirrorFreeAllowed =false;
+ if (!aInfo.bMirror45Allowed ) rInfo.bMirror45Allowed =false;
+ if (!aInfo.bMirror90Allowed ) rInfo.bMirror90Allowed =false;
+ if (!aInfo.bShearAllowed ) rInfo.bShearAllowed =false;
+ if (!aInfo.bEdgeRadiusAllowed ) rInfo.bEdgeRadiusAllowed =false;
+ if (!aInfo.bNoOrthoDesired ) rInfo.bNoOrthoDesired =false;
+ if (aInfo.bNoContortion ) rInfo.bNoContortion =true;
+ if (!aInfo.bCanConvToPath ) rInfo.bCanConvToPath =false;
+
+ if(!aInfo.bCanConvToContour)
+ rInfo.bCanConvToContour = false;
+
+ if (!aInfo.bCanConvToPoly ) rInfo.bCanConvToPoly =false;
+ if (!aInfo.bCanConvToPathLineToArea) rInfo.bCanConvToPathLineToArea=false;
+ if (!aInfo.bCanConvToPolyLineToArea) rInfo.bCanConvToPolyLineToArea=false;
+ }
+ if (nObjCount==0) {
+ rInfo.bRotateFreeAllowed=false;
+ rInfo.bRotate90Allowed =false;
+ rInfo.bMirrorFreeAllowed=false;
+ rInfo.bMirror45Allowed =false;
+ rInfo.bMirror90Allowed =false;
+ rInfo.bTransparenceAllowed = false;
+ rInfo.bShearAllowed =false;
+ rInfo.bEdgeRadiusAllowed=false;
+ rInfo.bNoContortion =true;
+ }
+ if(nObjCount != 1)
+ {
+ // only allowed if single object selected
+ rInfo.bTransparenceAllowed = false;
+ }
+}
+
+void SdrObjGroup::SetBoundRectDirty()
+{
+ // avoid resetting aOutRect which in case of this object is model data,
+ // not re-creatable view data
+}
+
+SdrObjKind SdrObjGroup::GetObjIdentifier() const
+{
+ return SdrObjKind::Group;
+}
+
+SdrLayerID SdrObjGroup::GetLayer() const
+{
+ bool b1st = true;
+ SdrLayerID nLay = SdrObject::GetLayer();
+ const size_t nObjCount(GetObjCount());
+ for (size_t i=0; i<nObjCount; ++i) {
+ SdrLayerID nLay1(GetObj(i)->GetLayer());
+ if (b1st) { nLay=nLay1; b1st = false; }
+ else if (nLay1!=nLay) return SdrLayerID(0);
+ }
+ return nLay;
+}
+
+void SdrObjGroup::NbcSetLayer(SdrLayerID nLayer)
+{
+ SdrObject::NbcSetLayer(nLayer);
+ const size_t nObjCount(GetObjCount());
+ for (size_t i=0; i<nObjCount; ++i) {
+ GetObj(i)->NbcSetLayer(nLayer);
+ }
+}
+
+void SdrObjGroup::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ // call parent
+ SdrObject::handlePageChange(pOldPage, pNewPage);
+
+ for(size_t i(0); i < GetObjCount(); i++)
+ {
+ GetObj(i)->handlePageChange(pOldPage, pNewPage);
+ }
+}
+
+SdrObjList* SdrObjGroup::GetSubList() const
+{
+ return const_cast< SdrObjGroup* >(this);
+}
+
+static bool containsOOXData(const css::uno::Any& rVal)
+{
+ const css::uno::Sequence<css::beans::PropertyValue>& propList(rVal.get< css::uno::Sequence<css::beans::PropertyValue> >());
+ for (const auto& rProp : std::as_const(propList))
+ {
+ if(rProp.Name.startsWith("OOX"))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void SdrObjGroup::SetGrabBagItem(const css::uno::Any& rVal)
+{
+ // detect if the intention is to disable Diagram functionality
+ if(isDiagram() && !containsOOXData(rVal))
+ {
+ css::uno::Any aOld;
+ GetGrabBagItem(aOld);
+
+ if(containsOOXData(aOld))
+ {
+ mp_DiagramHelper.reset();
+ }
+ }
+
+ // call parent
+ SdrObject::SetGrabBagItem(rVal);
+}
+
+const tools::Rectangle& SdrObjGroup::GetCurrentBoundRect() const
+{
+ // <aOutRect> has to contain the bounding rectangle
+ if(0 != GetObjCount())
+ {
+ m_aOutRect = GetAllObjBoundRect();
+ }
+
+ return m_aOutRect;
+}
+
+const tools::Rectangle& SdrObjGroup::GetSnapRect() const
+{
+ // <aOutRect> has to contain the bounding rectangle
+ if(0 != GetObjCount())
+ {
+ return GetAllObjSnapRect();
+ }
+ else
+ {
+ return m_aOutRect;
+ }
+}
+
+SdrObjGroup* SdrObjGroup::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrObjGroup(rTargetModel, *this);
+}
+
+OUString SdrObjGroup::TakeObjNameSingul() const
+{
+ OUString sName;
+
+ if(0 == GetObjCount())
+ {
+ sName = SvxResId(STR_ObjNameSingulGRUPEMPTY);
+ }
+ else
+ {
+ if(isDiagram())
+ sName = SvxResId(STR_ObjNameSingulDIAGRAM);
+ else
+ sName = SvxResId(STR_ObjNameSingulGRUP);
+ }
+
+ const OUString aName(GetName());
+
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+
+OUString SdrObjGroup::TakeObjNamePlural() const
+{
+ if(0 == GetObjCount())
+ return SvxResId(STR_ObjNamePluralGRUPEMPTY);
+ if(isDiagram())
+ return SvxResId(RID_GALLERYSTR_THEME_DIAGRAMS);
+ return SvxResId(STR_ObjNamePluralGRUP);
+}
+
+
+void SdrObjGroup::RecalcSnapRect()
+{
+ // TODO: unnecessary, because we use the Rects from the SubList
+}
+
+basegfx::B2DPolyPolygon SdrObjGroup::TakeXorPoly() const
+{
+ basegfx::B2DPolyPolygon aRetval;
+ const size_t nObjCount(GetObjCount());
+
+ for(size_t a = 0; a < nObjCount; ++a)
+ {
+ SdrObject* pObj(GetObj(a));
+ aRetval.append(pObj->TakeXorPoly());
+ }
+
+ if(!aRetval.count())
+ {
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(m_aOutRect);
+ aRetval.append(basegfx::utils::createPolygonFromRect(aRange));
+ }
+
+ return aRetval;
+}
+
+bool SdrObjGroup::beginSpecialDrag(SdrDragStat& /*rDrag*/) const
+{
+ return false;
+}
+
+
+bool SdrObjGroup::BegCreate(SdrDragStat& /*rStat*/)
+{
+ return false;
+}
+
+
+Degree100 SdrObjGroup::GetRotateAngle() const
+{
+ Degree100 nRetval(0);
+
+ if(0 != GetObjCount())
+ {
+ SdrObject* pObj(GetObj(0));
+
+ nRetval = pObj->GetRotateAngle();
+ }
+
+ return nRetval;
+}
+
+
+Degree100 SdrObjGroup::GetShearAngle(bool /*bVertical*/) const
+{
+ Degree100 nRetval(0);
+
+ if(0 != GetObjCount())
+ {
+ SdrObject* pObj(GetObj(0));
+
+ nRetval = pObj->GetShearAngle();
+ }
+
+ return nRetval;
+}
+
+
+void SdrObjGroup::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aOld(GetSnapRect());
+ tools::Long nMulX=rRect.Right()-rRect.Left();
+ tools::Long nDivX=aOld.Right()-aOld.Left();
+ tools::Long nMulY=rRect.Bottom()-rRect.Top();
+ tools::Long nDivY=aOld.Bottom()-aOld.Top();
+ if (nDivX==0) { nMulX=1; nDivX=1; }
+ if (nDivY==0) { nMulY=1; nDivY=1; }
+ if (nMulX!=nDivX || nMulY!=nDivY) {
+ Fraction aX(nMulX,nDivX);
+ Fraction aY(nMulY,nDivY);
+ NbcResize(aOld.TopLeft(),aX,aY);
+ }
+ if (rRect.Left()!=aOld.Left() || rRect.Top()!=aOld.Top()) {
+ NbcMove(Size(rRect.Left()-aOld.Left(),rRect.Top()-aOld.Top()));
+ }
+}
+
+
+void SdrObjGroup::NbcSetLogicRect(const tools::Rectangle& rRect)
+{
+ NbcSetSnapRect(rRect);
+}
+
+
+void SdrObjGroup::NbcMove(const Size& rSiz)
+{
+ maRefPoint.Move(rSiz);
+ const size_t nObjCount(GetObjCount());
+
+ if(0 != nObjCount)
+ {
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ pObj->NbcMove(rSiz);
+ }
+ }
+ else
+ {
+ m_aOutRect.Move(rSiz);
+ SetBoundAndSnapRectsDirty();
+ }
+}
+
+
+void SdrObjGroup::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
+ bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
+ if (bXMirr || bYMirr) {
+ Point aRef1(GetSnapRect().Center());
+ if (bXMirr) {
+ Point aRef2(aRef1);
+ aRef2.AdjustY( 1 );
+ NbcMirrorGluePoints(aRef1,aRef2);
+ }
+ if (bYMirr) {
+ Point aRef2(aRef1);
+ aRef2.AdjustX( 1 );
+ NbcMirrorGluePoints(aRef1,aRef2);
+ }
+ }
+
+ ResizePoint(maRefPoint, rRef, xFact, yFact);
+
+ const size_t nObjCount(GetObjCount());
+ if(0 != nObjCount)
+ {
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ pObj->NbcResize(rRef,xFact,yFact);
+ }
+ }
+ else
+ {
+ ResizeRect(m_aOutRect,rRef,xFact,yFact);
+ SetBoundAndSnapRectsDirty();
+ }
+}
+
+
+void SdrObjGroup::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ SetGlueReallyAbsolute(true);
+ RotatePoint(maRefPoint, rRef, sn, cs);
+ const size_t nObjCount(GetObjCount());
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ pObj->NbcRotate(rRef,nAngle,sn,cs);
+ }
+
+ NbcRotateGluePoints(rRef,nAngle,sn,cs);
+ SetGlueReallyAbsolute(false);
+}
+
+
+void SdrObjGroup::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ SetGlueReallyAbsolute(true);
+ MirrorPoint(maRefPoint, rRef1, rRef2); // implementation missing in SvdEtc!
+ const size_t nObjCount(GetObjCount());
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ pObj->NbcMirror(rRef1,rRef2);
+ }
+
+ NbcMirrorGluePoints(rRef1,rRef2);
+ SetGlueReallyAbsolute(false);
+}
+
+
+void SdrObjGroup::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ SetGlueReallyAbsolute(true);
+ ShearPoint(maRefPoint, rRef, tn);
+ const size_t nObjCount(GetObjCount());
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ pObj->NbcShear(rRef,nAngle,tn,bVShear);
+ }
+
+ NbcShearGluePoints(rRef,tn,bVShear);
+ SetGlueReallyAbsolute(false);
+}
+
+
+void SdrObjGroup::NbcSetAnchorPos(const Point& rPnt)
+{
+ m_aAnchor=rPnt;
+ Size aSiz(rPnt.X()-m_aAnchor.X(),rPnt.Y()-m_aAnchor.Y());
+ maRefPoint.Move(aSiz);
+ const size_t nObjCount(GetObjCount());
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ pObj->NbcSetAnchorPos(rPnt);
+ }
+}
+
+
+void SdrObjGroup::SetSnapRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ tools::Rectangle aOld(GetSnapRect());
+ if (aOld.IsEmpty())
+ {
+ Fraction aX(1,1);
+ Fraction aY(1,1);
+ Resize(aOld.TopLeft(),aX,aY);
+ }
+ else
+ {
+ tools::Long nMulX=rRect.Right()-rRect.Left();
+ tools::Long nDivX=aOld.Right()-aOld.Left();
+ tools::Long nMulY=rRect.Bottom()-rRect.Top();
+ tools::Long nDivY=aOld.Bottom()-aOld.Top();
+ if (nDivX==0) { nMulX=1; nDivX=1; }
+ if (nDivY==0) { nMulY=1; nDivY=1; }
+ if (nMulX!=nDivX || nMulY!=nDivY) {
+ Fraction aX(nMulX,nDivX);
+ Fraction aY(nMulY,nDivY);
+ Resize(aOld.TopLeft(),aX,aY);
+ }
+ }
+ if (rRect.Left()!=aOld.Left() || rRect.Top()!=aOld.Top()) {
+ Move(Size(rRect.Left()-aOld.Left(),rRect.Top()-aOld.Top()));
+ }
+
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+
+void SdrObjGroup::SetLogicRect(const tools::Rectangle& rRect)
+{
+ SetSnapRect(rRect);
+}
+
+
+void SdrObjGroup::Move(const Size& rSiz)
+{
+ if (rSiz.Width()==0 && rSiz.Height()==0)
+ return;
+
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ maRefPoint.Move(rSiz);
+ const size_t nObjCount(GetObjCount());
+
+ if(0 != nObjCount)
+ {
+ // first move the connectors, then everything else
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (pObj->IsEdgeObj())
+ pObj->Move(rSiz);
+ }
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (!pObj->IsEdgeObj())
+ pObj->Move(rSiz);
+ }
+ }
+ else
+ {
+ m_aOutRect.Move(rSiz);
+ SetBoundAndSnapRectsDirty();
+ }
+
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
+}
+
+
+void SdrObjGroup::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
+{
+ if (xFact.GetNumerator()==xFact.GetDenominator() && yFact.GetNumerator()==yFact.GetDenominator())
+ return;
+
+ bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
+ bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
+ if (bXMirr || bYMirr) {
+ Point aRef1(GetSnapRect().Center());
+ if (bXMirr) {
+ Point aRef2(aRef1);
+ aRef2.AdjustY( 1 );
+ NbcMirrorGluePoints(aRef1,aRef2);
+ }
+ if (bYMirr) {
+ Point aRef2(aRef1);
+ aRef2.AdjustX( 1 );
+ NbcMirrorGluePoints(aRef1,aRef2);
+ }
+ }
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ ResizePoint(maRefPoint, rRef, xFact, yFact);
+ const size_t nObjCount(GetObjCount());
+
+ if(0 != nObjCount)
+ {
+ // move the connectors first, everything else afterwards
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (pObj->IsEdgeObj())
+ pObj->Resize(rRef,xFact,yFact,bUnsetRelative);
+ }
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (!pObj->IsEdgeObj())
+ pObj->Resize(rRef,xFact,yFact,bUnsetRelative);
+ }
+ }
+ else
+ {
+ ResizeRect(m_aOutRect,rRef,xFact,yFact);
+ SetBoundAndSnapRectsDirty();
+ }
+
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+
+void SdrObjGroup::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ if (nAngle==0_deg100)
+ return;
+
+ SetGlueReallyAbsolute(true);
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ RotatePoint(maRefPoint, rRef, sn, cs);
+ // move the connectors first, everything else afterwards
+ const size_t nObjCount(GetObjCount());
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (pObj->IsEdgeObj())
+ pObj->Rotate(rRef,nAngle,sn,cs);
+ }
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (!pObj->IsEdgeObj())
+ pObj->Rotate(rRef,nAngle,sn,cs);
+ }
+
+ NbcRotateGluePoints(rRef,nAngle,sn,cs);
+ SetGlueReallyAbsolute(false);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+
+void SdrObjGroup::Mirror(const Point& rRef1, const Point& rRef2)
+{
+ SetGlueReallyAbsolute(true);
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ MirrorPoint(maRefPoint, rRef1, rRef2); // implementation missing in SvdEtc!
+ // move the connectors first, everything else afterwards
+ const size_t nObjCount(GetObjCount());
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (pObj->IsEdgeObj())
+ pObj->Mirror(rRef1,rRef2);
+ }
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (!pObj->IsEdgeObj())
+ pObj->Mirror(rRef1,rRef2);
+ }
+
+ NbcMirrorGluePoints(rRef1,rRef2);
+ SetGlueReallyAbsolute(false);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+
+void SdrObjGroup::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ if (nAngle==0_deg100)
+ return;
+
+ SetGlueReallyAbsolute(true);
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ ShearPoint(maRefPoint, rRef, tn);
+ // move the connectors first, everything else afterwards
+ const size_t nObjCount(GetObjCount());
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (pObj->IsEdgeObj())
+ pObj->Shear(rRef,nAngle,tn,bVShear);
+ }
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (!pObj->IsEdgeObj())
+ pObj->Shear(rRef,nAngle,tn,bVShear);
+ }
+
+ NbcShearGluePoints(rRef,tn,bVShear);
+ SetGlueReallyAbsolute(false);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+
+}
+
+
+void SdrObjGroup::SetAnchorPos(const Point& rPnt)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ bool bChg=m_aAnchor!=rPnt;
+ m_aAnchor=rPnt;
+ Size aSiz(rPnt.X()-m_aAnchor.X(),rPnt.Y()-m_aAnchor.Y());
+ maRefPoint.Move(aSiz);
+ // move the connectors first, everything else afterwards
+ const size_t nObjCount(GetObjCount());
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (pObj->IsEdgeObj())
+ pObj->SetAnchorPos(rPnt);
+ }
+
+ for (size_t i=0; i<nObjCount; ++i)
+ {
+ SdrObject* pObj(GetObj(i));
+ if (!pObj->IsEdgeObj())
+ pObj->SetAnchorPos(rPnt);
+ }
+
+ if (bChg)
+ {
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
+ }
+}
+
+
+void SdrObjGroup::NbcSetRelativePos(const Point& rPnt)
+{
+ Point aRelPos0(GetSnapRect().TopLeft()-m_aAnchor);
+ Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
+ NbcMove(aSiz); // this also calls SetRectsDirty()
+}
+
+void SdrObjGroup::SetRelativePos(const Point& rPnt)
+{
+ Point aRelPos0(GetSnapRect().TopLeft()-m_aAnchor);
+ Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
+ if (aSiz.Width()!=0 || aSiz.Height()!=0) Move(aSiz); // this also calls SetRectsDirty() and Broadcast, ...
+}
+
+void SdrObjGroup::NbcReformatText()
+{
+ NbcReformatAllTextObjects();
+}
+
+SdrObjectUniquePtr SdrObjGroup::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ SdrObjectUniquePtr pGroup( new SdrObjGroup(getSdrModelFromSdrObject()) );
+ const size_t nObjCount(GetObjCount());
+
+ for(size_t a=0; a < nObjCount; ++a)
+ {
+ SdrObject* pIterObj(GetObj(a));
+ SdrObjectUniquePtr pResult(pIterObj->DoConvertToPolyObj(bBezier, bAddText));
+
+ // pResult can be NULL e.g. for empty objects
+ if( pResult )
+ pGroup->GetSubList()->NbcInsertObject(pResult.release());
+ }
+
+ return pGroup;
+}
+
+void SdrObjGroup::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrObjGroup"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+
+ SdrObject::dumpAsXml(pWriter);
+ SdrObjList::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdomeas.cxx b/svx/source/svdraw/svdomeas.cxx
new file mode 100644
index 000000000..da9959c84
--- /dev/null
+++ b/svx/source/svdraw/svdomeas.cxx
@@ -0,0 +1,1429 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/measfld.hxx>
+#include <editeng/outlobj.hxx>
+#include <math.h>
+#include <svl/style.hxx>
+
+#include <sdr/contact/viewcontactofsdrmeasureobj.hxx>
+#include <sdr/properties/measureproperties.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdomeas.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sxmbritm.hxx>
+#include <svx/sxmlhitm.hxx>
+#include <sxmsitm.hxx>
+#include <sxmtaitm.hxx>
+#include <svx/sxmtfitm.hxx>
+#include <svx/sxmtpitm.hxx>
+#include <svx/sxmtritm.hxx>
+#include <svx/sxmuitm.hxx>
+#include <svx/xlnedcit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xpoly.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/ptrstyle.hxx>
+
+
+SdrMeasureObjGeoData::SdrMeasureObjGeoData() {}
+SdrMeasureObjGeoData::~SdrMeasureObjGeoData() {}
+
+OUString SdrMeasureObj::TakeRepresentation(SdrMeasureFieldKind eMeasureFieldKind) const
+{
+ OUString aStr;
+ Fraction aMeasureScale(1, 1);
+ bool bTextRota90(false);
+ bool bShowUnit(false);
+ FieldUnit eMeasureUnit(FieldUnit::NONE);
+ FieldUnit eModUIUnit(FieldUnit::NONE);
+
+ const SfxItemSet& rSet = GetMergedItemSet();
+ bTextRota90 = rSet.Get(SDRATTR_MEASURETEXTROTA90).GetValue();
+ eMeasureUnit = rSet.Get(SDRATTR_MEASUREUNIT).GetValue();
+ aMeasureScale = rSet.Get(SDRATTR_MEASURESCALE).GetValue();
+ bShowUnit = rSet.Get(SDRATTR_MEASURESHOWUNIT).GetValue();
+ sal_Int16 nNumDigits = rSet.Get(SDRATTR_MEASUREDECIMALPLACES).GetValue();
+
+ switch(eMeasureFieldKind)
+ {
+ case SdrMeasureFieldKind::Value:
+ {
+ eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();
+
+ if(eMeasureUnit == FieldUnit::NONE)
+ eMeasureUnit = eModUIUnit;
+
+ sal_Int32 nLen(GetLen(aPt2 - aPt1));
+ Fraction aFact(1,1);
+
+ if(eMeasureUnit != eModUIUnit)
+ {
+ // for the unit conversion
+ aFact *= GetMapFactor(eModUIUnit, eMeasureUnit).X();
+ }
+
+ if(aMeasureScale.GetNumerator() != aMeasureScale.GetDenominator())
+ {
+ aFact *= aMeasureScale;
+ }
+
+ if(aFact.GetNumerator() != aFact.GetDenominator())
+ {
+ // scale via BigInt, to avoid overruns
+ nLen = BigMulDiv(nLen, aFact.GetNumerator(), aFact.GetDenominator());
+ }
+
+ if(!aFact.IsValid())
+ {
+ aStr = "?";
+ }
+ else
+ {
+ aStr = getSdrModelFromSdrObject().GetMetricString(nLen, true, nNumDigits);
+ }
+
+ SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& rLocaleDataWrapper = aSysLocale.GetLocaleData();
+ sal_Unicode cDec(rLocaleDataWrapper.getNumDecimalSep()[0]);
+ sal_Unicode cDecAlt(rLocaleDataWrapper.getNumDecimalSepAlt().toChar());
+
+ if(aStr.indexOf(cDec) != -1 || (cDecAlt && aStr.indexOf(cDecAlt) != -1))
+ {
+ sal_Int32 nLen2(aStr.getLength() - 1);
+
+ while(aStr[nLen2] == '0')
+ {
+ aStr = aStr.copy(0, nLen2);
+ nLen2--;
+ }
+
+ if(aStr[nLen2] == cDec || (cDecAlt && aStr[nLen2] == cDecAlt))
+ {
+ aStr = aStr.copy(0, nLen2);
+ nLen2--;
+ }
+
+ if(aStr.isEmpty())
+ aStr += "0";
+ }
+
+ break;
+ }
+ case SdrMeasureFieldKind::Unit:
+ {
+ if(bShowUnit)
+ {
+ eModUIUnit = getSdrModelFromSdrObject().GetUIUnit();
+
+ if(eMeasureUnit == FieldUnit::NONE)
+ eMeasureUnit = eModUIUnit;
+
+ aStr = SdrModel::GetUnitString(eMeasureUnit);
+ }
+
+ break;
+ }
+ case SdrMeasureFieldKind::Rotate90Blanks:
+ {
+ if(bTextRota90)
+ {
+ aStr = " ";
+ }
+
+ break;
+ }
+ }
+ return aStr;
+}
+
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrMeasureObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::MeasureProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrMeasureObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrMeasureObj>(*this);
+}
+
+
+SdrMeasureObj::SdrMeasureObj(SdrModel& rSdrModel)
+: SdrTextObj(rSdrModel),
+ bTextDirty(false)
+{
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+}
+
+SdrMeasureObj::SdrMeasureObj(SdrModel& rSdrModel, SdrMeasureObj const & rSource)
+: SdrTextObj(rSdrModel, rSource),
+ bTextDirty(false)
+{
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+
+ aPt1 = rSource.aPt1;
+ aPt2 = rSource.aPt2;
+ bTextDirty = rSource.bTextDirty;
+}
+
+SdrMeasureObj::SdrMeasureObj(
+ SdrModel& rSdrModel,
+ const Point& rPt1,
+ const Point& rPt2)
+: SdrTextObj(rSdrModel),
+ aPt1(rPt1),
+ aPt2(rPt2),
+ bTextDirty(false)
+{
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+}
+
+SdrMeasureObj::~SdrMeasureObj()
+{
+}
+
+void SdrMeasureObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bMoveAllowed =true;
+ rInfo.bResizeFreeAllowed=true;
+ rInfo.bResizePropAllowed=true;
+ rInfo.bRotateFreeAllowed=true;
+ rInfo.bRotate90Allowed =true;
+ rInfo.bMirrorFreeAllowed=true;
+ rInfo.bMirror45Allowed =true;
+ rInfo.bMirror90Allowed =true;
+ rInfo.bTransparenceAllowed = false;
+ rInfo.bShearAllowed =true;
+ rInfo.bEdgeRadiusAllowed=false;
+ rInfo.bNoOrthoDesired =true;
+ rInfo.bNoContortion =false;
+ rInfo.bCanConvToPath =false;
+ rInfo.bCanConvToPoly =true;
+ rInfo.bCanConvToPathLineToArea=false;
+ rInfo.bCanConvToPolyLineToArea=false;
+ rInfo.bCanConvToContour = LineGeometryUsageIsNecessary();
+}
+
+SdrObjKind SdrMeasureObj::GetObjIdentifier() const
+{
+ return SdrObjKind::Measure;
+}
+
+struct ImpMeasureRec : public SdrDragStatUserData
+{
+ Point aPt1;
+ Point aPt2;
+ css::drawing::MeasureTextHorzPos eWantTextHPos;
+ css::drawing::MeasureTextVertPos eWantTextVPos;
+ tools::Long nLineDist;
+ tools::Long nHelplineOverhang;
+ tools::Long nHelplineDist;
+ tools::Long nHelpline1Len;
+ tools::Long nHelpline2Len;
+ bool bBelowRefEdge;
+ bool bTextRota90;
+ bool bTextUpsideDown;
+ bool bTextAutoAngle;
+ Degree100 nTextAutoAngleView;
+};
+
+namespace {
+
+struct ImpLineRec
+{
+ Point aP1;
+ Point aP2;
+};
+
+}
+
+struct ImpMeasurePoly
+{
+ ImpLineRec aMainline1; // those with the 1st arrowhead
+ ImpLineRec aMainline2; // those with the 2nd arrowhead
+ ImpLineRec aMainline3; // those in between
+ ImpLineRec aHelpline1;
+ ImpLineRec aHelpline2;
+ Size aTextSize;
+ tools::Long nLineLen;
+ Degree100 nLineAngle;
+ Degree100 nTextAngle;
+ Degree100 nHlpAngle;
+ double nLineSin;
+ double nLineCos;
+ sal_uInt16 nMainlineCnt;
+ css::drawing::MeasureTextHorzPos eUsedTextHPos;
+ css::drawing::MeasureTextVertPos eUsedTextVPos;
+ tools::Long nLineWdt2; // half the line width
+ tools::Long nArrow1Len; // length of 1st arrowhead; for Center, use only half
+ tools::Long nArrow2Len; // length of 2nd arrowhead; for Center, use only half
+ tools::Long nArrow1Wdt; // width of 1st arrow
+ tools::Long nArrow2Wdt; // width of 2nd arrow
+ tools::Long nShortLineLen; // line length, if PfeileAussen (arrowheads on the outside)
+ bool bAutoUpsideDown; // UpsideDown via automation
+ bool bBreakedLine;
+};
+
+void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec& rRec) const
+{
+ rRec.aPt1 = aPt1;
+ rRec.aPt2 = aPt2;
+
+ const SfxItemSet& rSet = GetObjectItemSet();
+ rRec.eWantTextHPos =rSet.Get(SDRATTR_MEASURETEXTHPOS ).GetValue();
+ rRec.eWantTextVPos =rSet.Get(SDRATTR_MEASURETEXTVPOS ).GetValue();
+ rRec.nLineDist =rSet.Get(SDRATTR_MEASURELINEDIST ).GetValue();
+ rRec.nHelplineOverhang =rSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG).GetValue();
+ rRec.nHelplineDist =rSet.Get(SDRATTR_MEASUREHELPLINEDIST ).GetValue();
+ rRec.nHelpline1Len =rSet.Get(SDRATTR_MEASUREHELPLINE1LEN ).GetValue();
+ rRec.nHelpline2Len =rSet.Get(SDRATTR_MEASUREHELPLINE2LEN ).GetValue();
+ rRec.bBelowRefEdge =rSet.Get(SDRATTR_MEASUREBELOWREFEDGE ).GetValue();
+ rRec.bTextRota90 =rSet.Get(SDRATTR_MEASURETEXTROTA90 ).GetValue();
+ rRec.bTextUpsideDown =static_cast<const SdrMeasureTextUpsideDownItem& >(rSet.Get(SDRATTR_MEASURETEXTUPSIDEDOWN )).GetValue();
+ rRec.bTextAutoAngle =rSet.Get(SDRATTR_MEASURETEXTAUTOANGLE ).GetValue();
+ rRec.nTextAutoAngleView=static_cast<const SdrMeasureTextAutoAngleViewItem&>(rSet.Get(SDRATTR_MEASURETEXTAUTOANGLEVIEW)).GetValue();
+}
+
+static tools::Long impGetLineStartEndDistance(const basegfx::B2DPolyPolygon& rPolyPolygon, tools::Long nNewWidth, bool bCenter)
+{
+ const basegfx::B2DRange aPolygonRange(rPolyPolygon.getB2DRange());
+ const double fOldWidth(std::max(aPolygonRange.getWidth(), 1.0));
+ const double fScale(static_cast<double>(nNewWidth) / fOldWidth);
+ tools::Long nHeight(basegfx::fround(aPolygonRange.getHeight() * fScale));
+
+ if(bCenter)
+ {
+ nHeight /= 2;
+ }
+
+ return nHeight;
+}
+
+void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec& rRec, ImpMeasurePoly& rPol) const
+{
+ Point aP1(rRec.aPt1);
+ Point aP2(rRec.aPt2);
+ Point aDelt(aP2); aDelt-=aP1;
+
+ rPol.aTextSize=GetTextSize();
+ rPol.nLineLen=GetLen(aDelt);
+
+ rPol.nLineWdt2=0;
+ tools::Long nArrow1Len=0; bool bArrow1Center=false;
+ tools::Long nArrow2Len=0; bool bArrow2Center=false;
+ tools::Long nArrow1Wdt=0;
+ tools::Long nArrow2Wdt=0;
+ rPol.nArrow1Wdt=0;
+ rPol.nArrow2Wdt=0;
+ tools::Long nArrowNeed=0;
+ tools::Long nShortLen=0;
+ bool bPfeileAussen = false;
+
+ const SfxItemSet& rSet = GetObjectItemSet();
+ sal_Int32 nLineWdt = rSet.Get(XATTR_LINEWIDTH).GetValue(); // line width
+ rPol.nLineWdt2 = (nLineWdt + 1) / 2;
+
+ nArrow1Wdt = rSet.Get(XATTR_LINESTARTWIDTH).GetValue();
+ if(nArrow1Wdt < 0)
+ nArrow1Wdt = -nLineWdt * nArrow1Wdt / 100; // <0 = relative
+
+ nArrow2Wdt = rSet.Get(XATTR_LINEENDWIDTH).GetValue();
+ if(nArrow2Wdt < 0)
+ nArrow2Wdt = -nLineWdt * nArrow2Wdt / 100; // <0 = relative
+
+ basegfx::B2DPolyPolygon aPol1(rSet.Get(XATTR_LINESTART).GetLineStartValue());
+ basegfx::B2DPolyPolygon aPol2(rSet.Get(XATTR_LINEEND).GetLineEndValue());
+ bArrow1Center = rSet.Get(XATTR_LINESTARTCENTER).GetValue();
+ bArrow2Center = rSet.Get(XATTR_LINEENDCENTER).GetValue();
+ nArrow1Len = impGetLineStartEndDistance(aPol1, nArrow1Wdt, bArrow1Center) - 1;
+ nArrow2Len = impGetLineStartEndDistance(aPol2, nArrow2Wdt, bArrow2Center) - 1;
+
+ // nArrowLen is already halved at bCenter.
+ // In the case of 2 arrowheads each 4mm long, we can't go below 10mm.
+ nArrowNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2;
+ if (rPol.nLineLen<nArrowNeed) bPfeileAussen = true;
+ nShortLen=(nArrow1Len+nArrow1Wdt + nArrow2Len+nArrow2Wdt) /2;
+
+ rPol.eUsedTextHPos=rRec.eWantTextHPos;
+ rPol.eUsedTextVPos=rRec.eWantTextVPos;
+ if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_AUTO)
+ rPol.eUsedTextVPos = css::drawing::MeasureTextVertPos_EAST;
+ bool bBrkLine=false;
+ if (rPol.eUsedTextVPos == css::drawing::MeasureTextVertPos_CENTERED)
+ {
+ OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
+ if (pOutlinerParaObject!=nullptr && pOutlinerParaObject->GetTextObject().GetParagraphCount()==1)
+ {
+ bBrkLine=true; // dashed line if there's only on paragraph.
+ }
+ }
+ rPol.bBreakedLine=bBrkLine;
+ if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_AUTO) { // if text is too wide, push it outside
+ bool bOutside = false;
+ tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
+ if (nNeedSiz>rPol.nLineLen) bOutside = true; // text doesn't fit in between
+ if (bBrkLine) {
+ if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
+ } else {
+ tools::Long nSmallNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2/4;
+ if (nNeedSiz+nSmallNeed>rPol.nLineLen) bPfeileAussen = true; // text fits in between, if arrowheads are on the outside
+ }
+ rPol.eUsedTextHPos=bOutside ? css::drawing::MeasureTextHorzPos_LEFTOUTSIDE : css::drawing::MeasureTextHorzPos_INSIDE;
+ }
+ if (rPol.eUsedTextHPos != css::drawing::MeasureTextHorzPos_INSIDE) bPfeileAussen = true;
+ rPol.nArrow1Wdt=nArrow1Wdt;
+ rPol.nArrow2Wdt=nArrow2Wdt;
+ rPol.nShortLineLen=nShortLen;
+ rPol.nArrow1Len=nArrow1Len;
+ rPol.nArrow2Len=nArrow2Len;
+
+ rPol.nLineAngle=GetAngle(aDelt);
+ double a = toRadians(rPol.nLineAngle);
+ double nLineSin=sin(a);
+ double nLineCos=cos(a);
+ rPol.nLineSin=nLineSin;
+ rPol.nLineCos=nLineCos;
+
+ rPol.nTextAngle=rPol.nLineAngle;
+ if (rRec.bTextRota90) rPol.nTextAngle+=9000_deg100;
+
+ rPol.bAutoUpsideDown=false;
+ if (rRec.bTextAutoAngle) {
+ Degree100 nTmpAngle=NormAngle36000(rPol.nTextAngle-rRec.nTextAutoAngleView);
+ if (nTmpAngle>=18000_deg100) {
+ rPol.nTextAngle+=18000_deg100;
+ rPol.bAutoUpsideDown=true;
+ }
+ }
+
+ if (rRec.bTextUpsideDown) rPol.nTextAngle+=18000_deg100;
+ rPol.nTextAngle=NormAngle36000(rPol.nTextAngle);
+ rPol.nHlpAngle=rPol.nLineAngle+9000_deg100;
+ if (rRec.bBelowRefEdge) rPol.nHlpAngle+=18000_deg100;
+ rPol.nHlpAngle=NormAngle36000(rPol.nHlpAngle);
+ double nHlpSin=nLineCos;
+ double nHlpCos=-nLineSin;
+ if (rRec.bBelowRefEdge) {
+ nHlpSin=-nHlpSin;
+ nHlpCos=-nHlpCos;
+ }
+
+ tools::Long nLineDist=rRec.nLineDist;
+ tools::Long nOverhang=rRec.nHelplineOverhang;
+ tools::Long nHelplineDist=rRec.nHelplineDist;
+
+ tools::Long dx= FRound(nLineDist*nHlpCos);
+ tools::Long dy=-FRound(nLineDist*nHlpSin);
+ tools::Long dxh1a= FRound((nHelplineDist-rRec.nHelpline1Len)*nHlpCos);
+ tools::Long dyh1a=-FRound((nHelplineDist-rRec.nHelpline1Len)*nHlpSin);
+ tools::Long dxh1b= FRound((nHelplineDist-rRec.nHelpline2Len)*nHlpCos);
+ tools::Long dyh1b=-FRound((nHelplineDist-rRec.nHelpline2Len)*nHlpSin);
+ tools::Long dxh2= FRound((nLineDist+nOverhang)*nHlpCos);
+ tools::Long dyh2=-FRound((nLineDist+nOverhang)*nHlpSin);
+
+ // extension line 1
+ rPol.aHelpline1.aP1=Point(aP1.X()+dxh1a,aP1.Y()+dyh1a);
+ rPol.aHelpline1.aP2=Point(aP1.X()+dxh2,aP1.Y()+dyh2);
+
+ // extension line 2
+ rPol.aHelpline2.aP1=Point(aP2.X()+dxh1b,aP2.Y()+dyh1b);
+ rPol.aHelpline2.aP2=Point(aP2.X()+dxh2,aP2.Y()+dyh2);
+
+ // dimension line
+ Point aMainlinePt1(aP1.X()+dx,aP1.Y()+dy);
+ Point aMainlinePt2(aP2.X()+dx,aP2.Y()+dy);
+ if (!bPfeileAussen) {
+ rPol.aMainline1.aP1=aMainlinePt1;
+ rPol.aMainline1.aP2=aMainlinePt2;
+ rPol.aMainline2=rPol.aMainline1;
+ rPol.aMainline3=rPol.aMainline1;
+ rPol.nMainlineCnt=1;
+ if (bBrkLine) {
+ tools::Long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
+ tools::Long nHalfLen=(rPol.nLineLen-nNeedSiz-nArrow1Wdt/4-nArrow2Wdt/4) /2;
+ rPol.nMainlineCnt=2;
+ rPol.aMainline1.aP2=aMainlinePt1;
+ rPol.aMainline1.aP2.AdjustX(nHalfLen );
+ RotatePoint(rPol.aMainline1.aP2,rPol.aMainline1.aP1,nLineSin,nLineCos);
+ rPol.aMainline2.aP1=aMainlinePt2;
+ rPol.aMainline2.aP1.AdjustX( -nHalfLen );
+ RotatePoint(rPol.aMainline2.aP1,rPol.aMainline2.aP2,nLineSin,nLineCos);
+ }
+ } else {
+ tools::Long nLen1=nShortLen; // arrowhead's width as line length outside of the arrowhead
+ tools::Long nLen2=nShortLen;
+ tools::Long nTextWdt=rRec.bTextRota90 ? rPol.aTextSize.Height() : rPol.aTextSize.Width();
+ if (!bBrkLine) {
+ if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) nLen1=nArrow1Len+nTextWdt;
+ if (rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) nLen2=nArrow2Len+nTextWdt;
+ }
+ rPol.aMainline1.aP1=aMainlinePt1;
+ rPol.aMainline1.aP2=aMainlinePt1; rPol.aMainline1.aP2.AdjustX( -nLen1 ); RotatePoint(rPol.aMainline1.aP2,aMainlinePt1,nLineSin,nLineCos);
+ rPol.aMainline2.aP1=aMainlinePt2; rPol.aMainline2.aP1.AdjustX(nLen2 ); RotatePoint(rPol.aMainline2.aP1,aMainlinePt2,nLineSin,nLineCos);
+ rPol.aMainline2.aP2=aMainlinePt2;
+ rPol.aMainline3.aP1=aMainlinePt1;
+ rPol.aMainline3.aP2=aMainlinePt2;
+ rPol.nMainlineCnt=3;
+ if (bBrkLine && rPol.eUsedTextHPos==css::drawing::MeasureTextHorzPos_INSIDE) rPol.nMainlineCnt=2;
+ }
+}
+
+basegfx::B2DPolyPolygon SdrMeasureObj::ImpCalcXPoly(const ImpMeasurePoly& rPol)
+{
+ basegfx::B2DPolyPolygon aRetval;
+ basegfx::B2DPolygon aPartPolyA;
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP1.X(), rPol.aMainline1.aP1.Y()));
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP2.X(), rPol.aMainline1.aP2.Y()));
+ aRetval.append(aPartPolyA);
+
+ if(rPol.nMainlineCnt > 1)
+ {
+ aPartPolyA.clear();
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP1.X(), rPol.aMainline2.aP1.Y()));
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP2.X(), rPol.aMainline2.aP2.Y()));
+ aRetval.append(aPartPolyA);
+ }
+
+ if(rPol.nMainlineCnt > 2)
+ {
+ aPartPolyA.clear();
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP1.X(), rPol.aMainline3.aP1.Y()));
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP2.X(), rPol.aMainline3.aP2.Y()));
+ aRetval.append(aPartPolyA);
+ }
+
+ aPartPolyA.clear();
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP1.X(), rPol.aHelpline1.aP1.Y()));
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP2.X(), rPol.aHelpline1.aP2.Y()));
+ aRetval.append(aPartPolyA);
+
+ aPartPolyA.clear();
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP1.X(), rPol.aHelpline2.aP1.Y()));
+ aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP2.X(), rPol.aHelpline2.aP2.Y()));
+ aRetval.append(aPartPolyA);
+
+ return aRetval;
+}
+
+bool SdrMeasureObj::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_uInt16 nPos,
+ bool bEdit,
+ std::optional<Color>& rpTxtColor, std::optional<Color>& rpFldColor, OUString& rRet) const
+{
+ const SvxFieldData* pField=rField.GetField();
+ const SdrMeasureField* pMeasureField=dynamic_cast<const SdrMeasureField*>( pField );
+ if (pMeasureField!=nullptr) {
+ rRet = TakeRepresentation(pMeasureField->GetMeasureFieldKind());
+ if (rpFldColor && !bEdit)
+ {
+ rpFldColor.reset();
+ }
+ return true;
+ } else {
+ return SdrTextObj::CalcFieldValue(rField,nPara,nPos,bEdit,rpTxtColor,rpFldColor,rRet);
+ }
+}
+
+void SdrMeasureObj::UndirtyText() const
+{
+ if (!bTextDirty)
+ return;
+
+ SdrOutliner& rOutliner=ImpGetDrawOutliner();
+ OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
+ if(pOutlinerParaObject==nullptr)
+ {
+ rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks), EE_FEATURE_FIELD), ESelection(0,0));
+ rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Value), EE_FEATURE_FIELD),ESelection(0,1));
+ rOutliner.QuickInsertText(" ", ESelection(0,2));
+ rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Unit), EE_FEATURE_FIELD),ESelection(0,3));
+ rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SdrMeasureFieldKind::Rotate90Blanks), EE_FEATURE_FIELD),ESelection(0,4));
+
+ if(GetStyleSheet())
+ rOutliner.SetStyleSheet(0, GetStyleSheet());
+
+ rOutliner.SetParaAttribs(0, GetObjectItemSet());
+
+ // cast to nonconst
+ const_cast<SdrMeasureObj*>(this)->NbcSetOutlinerParaObject( rOutliner.CreateParaObject() );
+ }
+ else
+ {
+ rOutliner.SetText(*pOutlinerParaObject);
+ }
+
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.UpdateFields();
+ Size aSiz(rOutliner.CalcTextSize());
+ rOutliner.Clear();
+ // cast to nonconst three times
+ const_cast<SdrMeasureObj*>(this)->maTextSize = aSiz;
+ const_cast<SdrMeasureObj*>(this)->mbTextSizeDirty = false;
+ const_cast<SdrMeasureObj*>(this)->bTextDirty = false;
+}
+
+void SdrMeasureObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
+{
+ if (bTextDirty) UndirtyText();
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+ ImpTakeAttr(aRec);
+ ImpCalcGeometrics(aRec,aMPol);
+
+ // determine TextSize including text frame margins
+ Size aTextSize2(aMPol.aTextSize);
+ if (aTextSize2.Width()<1) aTextSize2.setWidth(1 );
+ if (aTextSize2.Height()<1) aTextSize2.setHeight(1 );
+ aTextSize2.AdjustWidth(GetTextLeftDistance()+GetTextRightDistance() );
+ aTextSize2.AdjustHeight(GetTextUpperDistance()+GetTextLowerDistance() );
+
+ Point aPt1b(aMPol.aMainline1.aP1);
+ tools::Long nLen=aMPol.nLineLen;
+ tools::Long nLWdt=aMPol.nLineWdt2;
+ tools::Long nArr1Len=aMPol.nArrow1Len;
+ tools::Long nArr2Len=aMPol.nArrow2Len;
+ if (aMPol.bBreakedLine) {
+ // In the case of a dashed line and Outside, the text should be
+ // placed next to the line at the arrowhead instead of directly
+ // at the arrowhead.
+ nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
+ nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
+ }
+
+ Point aTextPos;
+ bool bRota90=aRec.bTextRota90;
+ bool bUpsideDown=aRec.bTextUpsideDown!=aMPol.bAutoUpsideDown;
+ bool bBelowRefEdge=aRec.bBelowRefEdge;
+ css::drawing::MeasureTextHorzPos eMH=aMPol.eUsedTextHPos;
+ css::drawing::MeasureTextVertPos eMV=aMPol.eUsedTextVPos;
+ if (!bRota90) {
+ switch (eMH) {
+ case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Width()-nArr1Len-nLWdt ); break;
+ case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len+nLWdt ); break;
+ default: aTextPos.setX(aPt1b.X() ); aTextSize2.setWidth(nLen );
+ }
+ switch (eMV) {
+ case css::drawing::MeasureTextVertPos_CENTERED:
+ aTextPos.setY(aPt1b.Y()-aTextSize2.Height()/2 ); break;
+ case css::drawing::MeasureTextVertPos_WEST: {
+ if (!bUpsideDown) aTextPos.setY(aPt1b.Y()+nLWdt );
+ else aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
+ } break;
+ default: {
+ if (!bUpsideDown) aTextPos.setY(aPt1b.Y()-aTextSize2.Height()-nLWdt );
+ else aTextPos.setY(aPt1b.Y()+nLWdt );
+ }
+ }
+ if (bUpsideDown) {
+ aTextPos.AdjustX(aTextSize2.Width() );
+ aTextPos.AdjustY(aTextSize2.Height() );
+ }
+ } else { // also if bTextRota90==TRUE
+ switch (eMH) {
+ case css::drawing::MeasureTextHorzPos_LEFTOUTSIDE: aTextPos.setX(aPt1b.X()-aTextSize2.Height()-nArr1Len ); break;
+ case css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE: aTextPos.setX(aPt1b.X()+nLen+nArr2Len ); break;
+ default: aTextPos.setX(aPt1b.X() ); aTextSize2.setHeight(nLen );
+ }
+ switch (eMV) {
+ case css::drawing::MeasureTextVertPos_CENTERED:
+ aTextPos.setY(aPt1b.Y()+aTextSize2.Width()/2 ); break;
+ case css::drawing::MeasureTextVertPos_WEST: {
+ if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
+ else aTextPos.setY(aPt1b.Y()-nLWdt );
+ } break;
+ default: {
+ if (!bBelowRefEdge) aTextPos.setY(aPt1b.Y()-nLWdt );
+ else aTextPos.setY(aPt1b.Y()+aTextSize2.Width()+nLWdt );
+ }
+ }
+ if (bUpsideDown) {
+ aTextPos.AdjustX(aTextSize2.Height() );
+ aTextPos.AdjustY( -(aTextSize2.Width()) );
+ }
+ }
+ if (aMPol.nTextAngle != maGeo.nRotationAngle) {
+ const_cast<SdrMeasureObj*>(this)->maGeo.nRotationAngle=aMPol.nTextAngle;
+ const_cast<SdrMeasureObj*>(this)->maGeo.RecalcSinCos();
+ }
+ RotatePoint(aTextPos,aPt1b,aMPol.nLineSin,aMPol.nLineCos);
+ aTextSize2.AdjustWidth( 1 ); aTextSize2.AdjustHeight( 1 ); // because of the Rect-Ctor's odd behavior
+ rRect=tools::Rectangle(aTextPos,aTextSize2);
+ rRect.Justify();
+ const_cast<SdrMeasureObj*>(this)->maRect=rRect;
+
+ if (aMPol.nTextAngle != maGeo.nRotationAngle) {
+ const_cast<SdrMeasureObj*>(this)->maGeo.nRotationAngle=aMPol.nTextAngle;
+ const_cast<SdrMeasureObj*>(this)->maGeo.RecalcSinCos();
+ }
+}
+
+SdrMeasureObj* SdrMeasureObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrMeasureObj(rTargetModel, *this);
+}
+
+OUString SdrMeasureObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulMEASURE));
+
+ OUString aName( GetName() );
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+OUString SdrMeasureObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralMEASURE);
+}
+
+basegfx::B2DPolyPolygon SdrMeasureObj::TakeXorPoly() const
+{
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+ ImpTakeAttr(aRec);
+ ImpCalcGeometrics(aRec,aMPol);
+ return ImpCalcXPoly(aMPol);
+}
+
+sal_uInt32 SdrMeasureObj::GetHdlCount() const
+{
+ return 6;
+}
+
+void SdrMeasureObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+ ImpTakeAttr(aRec);
+ aRec.nHelplineDist=0;
+ ImpCalcGeometrics(aRec,aMPol);
+
+ for (sal_uInt32 nHdlNum=0; nHdlNum<6; ++nHdlNum)
+ {
+ Point aPt;
+ switch (nHdlNum) {
+ case 0: aPt=aMPol.aHelpline1.aP1; break;
+ case 1: aPt=aMPol.aHelpline2.aP1; break;
+ case 2: aPt=aPt1; break;
+ case 3: aPt=aPt2; break;
+ case 4: aPt=aMPol.aHelpline1.aP2; break;
+ case 5: aPt=aMPol.aHelpline2.aP2; break;
+ } // switch
+ std::unique_ptr<SdrHdl> pHdl(new ImpMeasureHdl(aPt,SdrHdlKind::User));
+ pHdl->SetObjHdlNum(nHdlNum);
+ pHdl->SetRotationAngle(aMPol.nLineAngle);
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+}
+
+
+bool SdrMeasureObj::hasSpecialDrag() const
+{
+ return true;
+}
+
+bool SdrMeasureObj::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ const SdrHdl* pHdl = rDrag.GetHdl();
+
+ if(pHdl)
+ {
+ const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
+
+ if(nHdlNum != 2 && nHdlNum != 3)
+ {
+ rDrag.SetEndDragChangesAttributes(true);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool SdrMeasureObj::applySpecialDrag(SdrDragStat& rDrag)
+{
+ ImpMeasureRec aMeasureRec;
+ const SdrHdl* pHdl = rDrag.GetHdl();
+ const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
+
+ ImpTakeAttr(aMeasureRec);
+ ImpEvalDrag(aMeasureRec, rDrag);
+
+ switch (nHdlNum)
+ {
+ case 2:
+ {
+ aPt1 = aMeasureRec.aPt1;
+ SetTextDirty();
+ break;
+ }
+ case 3:
+ {
+ aPt2 = aMeasureRec.aPt2;
+ SetTextDirty();
+ break;
+ }
+ default:
+ {
+ switch(nHdlNum)
+ {
+ case 0:
+ case 1:
+ {
+ ImpMeasureRec aOrigMeasureRec;
+ ImpTakeAttr(aOrigMeasureRec);
+
+ if(aMeasureRec.nHelpline1Len != aOrigMeasureRec.nHelpline1Len)
+ {
+ SetObjectItem(makeSdrMeasureHelpline1LenItem(aMeasureRec.nHelpline1Len));
+ }
+
+ if(aMeasureRec.nHelpline2Len != aOrigMeasureRec.nHelpline2Len)
+ {
+ SetObjectItem(makeSdrMeasureHelpline2LenItem(aMeasureRec.nHelpline2Len));
+ }
+
+ break;
+ }
+
+ case 4:
+ case 5:
+ {
+ ImpMeasureRec aOrigMeasureRec;
+ ImpTakeAttr(aOrigMeasureRec);
+
+ if(aMeasureRec.nLineDist != aOrigMeasureRec.nLineDist)
+ {
+ SetObjectItem(makeSdrMeasureLineDistItem(aMeasureRec.nLineDist));
+ }
+
+ if(aMeasureRec.bBelowRefEdge != aOrigMeasureRec.bBelowRefEdge)
+ {
+ SetObjectItem(SdrMeasureBelowRefEdgeItem(aMeasureRec.bBelowRefEdge));
+ }
+ }
+ }
+ }
+ } // switch
+
+ SetBoundAndSnapRectsDirty();
+ SetChanged();
+
+ return true;
+}
+
+OUString SdrMeasureObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
+{
+ return OUString();
+}
+
+void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec& rRec, const SdrDragStat& rDrag) const
+{
+ Degree100 nLineAngle=GetAngle(rRec.aPt2-rRec.aPt1);
+ double a = toRadians(nLineAngle);
+ double nSin=sin(a);
+ double nCos=cos(a);
+
+ const SdrHdl* pHdl=rDrag.GetHdl();
+ sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
+ bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
+ bool bBigOrtho=bOrtho && rDrag.GetView()->IsBigOrtho();
+ bool bBelow=rRec.bBelowRefEdge;
+ Point aPt(rDrag.GetNow());
+
+ switch (nHdlNum) {
+ case 0: {
+ RotatePoint(aPt,aPt1,nSin,-nCos);
+ rRec.nHelpline1Len=aPt1.Y()-aPt.Y();
+ if (bBelow) rRec.nHelpline1Len=-rRec.nHelpline1Len;
+ if (bOrtho) rRec.nHelpline2Len=rRec.nHelpline1Len;
+ } break;
+ case 1: {
+ RotatePoint(aPt,aPt2,nSin,-nCos);
+ rRec.nHelpline2Len=aPt2.Y()-aPt.Y();
+ if (bBelow) rRec.nHelpline2Len=-rRec.nHelpline2Len;
+ if (bOrtho) rRec.nHelpline1Len=rRec.nHelpline2Len;
+ } break;
+ case 2: case 3: {
+ bool bAnf=nHdlNum==2;
+ Point& rMov=bAnf ? rRec.aPt1 : rRec.aPt2;
+ Point aMov(rMov);
+ Point aFix(bAnf ? rRec.aPt2 : rRec.aPt1);
+ if (bOrtho) {
+ tools::Long ndx0=aMov.X()-aFix.X();
+ tools::Long ndy0=aMov.Y()-aFix.Y();
+ bool bHLin=ndy0==0;
+ bool bVLin=ndx0==0;
+ if (!bHLin || !bVLin) { // else aPt1==aPt2
+ tools::Long ndx=aPt.X()-aFix.X();
+ tools::Long ndy=aPt.Y()-aFix.Y();
+ double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0);
+ double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0);
+ bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
+ bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
+ if (bHor) ndy=tools::Long(ndy0*nXFact);
+ if (bVer) ndx=tools::Long(ndx0*nYFact);
+ aPt=aFix;
+ aPt.AdjustX(ndx );
+ aPt.AdjustY(ndy );
+ } // else Ortho8
+ }
+ rMov=aPt;
+ } break;
+ case 4: case 5: {
+ tools::Long nVal0=rRec.nLineDist;
+ RotatePoint(aPt,(nHdlNum==4 ? aPt1 : aPt2),nSin,-nCos);
+ rRec.nLineDist=aPt.Y()- (nHdlNum==4 ? aPt1.Y() : aPt2.Y());
+ if (bBelow) rRec.nLineDist=-rRec.nLineDist;
+ if (rRec.nLineDist<0) {
+ rRec.nLineDist=-rRec.nLineDist;
+ rRec.bBelowRefEdge=!bBelow;
+ }
+ rRec.nLineDist-=rRec.nHelplineOverhang;
+ if (bOrtho) rRec.nLineDist=nVal0;
+ } break;
+ } // switch
+}
+
+
+bool SdrMeasureObj::BegCreate(SdrDragStat& rStat)
+{
+ rStat.SetOrtho8Possible();
+ aPt1=rStat.GetStart();
+ aPt2=rStat.GetNow();
+ SetTextDirty();
+ return true;
+}
+
+bool SdrMeasureObj::MovCreate(SdrDragStat& rStat)
+{
+ SdrView* pView=rStat.GetView();
+ aPt1=rStat.GetStart();
+ aPt2=rStat.GetNow();
+ if (pView!=nullptr && pView->IsCreate1stPointAsCenter()) {
+ aPt1+=aPt1;
+ aPt1-=rStat.GetNow();
+ }
+ SetTextDirty();
+ SetBoundRectDirty();
+ m_bSnapRectDirty=true;
+ return true;
+}
+
+bool SdrMeasureObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ SetTextDirty();
+ SetBoundAndSnapRectsDirty();
+ return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
+}
+
+bool SdrMeasureObj::BckCreate(SdrDragStat& /*rStat*/)
+{
+ return false;
+}
+
+void SdrMeasureObj::BrkCreate(SdrDragStat& /*rStat*/)
+{
+}
+
+basegfx::B2DPolyPolygon SdrMeasureObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
+{
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+
+ ImpTakeAttr(aRec);
+ ImpCalcGeometrics(aRec, aMPol);
+
+ return ImpCalcXPoly(aMPol);
+}
+
+PointerStyle SdrMeasureObj::GetCreatePointer() const
+{
+ return PointerStyle::Cross;
+}
+
+void SdrMeasureObj::NbcMove(const Size& rSiz)
+{
+ SdrTextObj::NbcMove(rSiz);
+ aPt1.Move(rSiz);
+ aPt2.Move(rSiz);
+}
+
+void SdrMeasureObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ SdrTextObj::NbcResize(rRef,xFact,yFact);
+ ResizePoint(aPt1,rRef,xFact,yFact);
+ ResizePoint(aPt2,rRef,xFact,yFact);
+ SetTextDirty();
+}
+
+void SdrMeasureObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
+ tools::Long nLen0=GetLen(aPt2-aPt1);
+ RotatePoint(aPt1,rRef,sn,cs);
+ RotatePoint(aPt2,rRef,sn,cs);
+ tools::Long nLen1=GetLen(aPt2-aPt1);
+ if (nLen1!=nLen0) { // rounding error!
+ tools::Long dx=aPt2.X()-aPt1.X();
+ tools::Long dy=aPt2.Y()-aPt1.Y();
+ dx=BigMulDiv(dx,nLen0,nLen1);
+ dy=BigMulDiv(dy,nLen0,nLen1);
+ if (rRef==aPt2) {
+ aPt1.setX(aPt2.X()-dx );
+ aPt1.setY(aPt2.Y()-dy );
+ } else {
+ aPt2.setX(aPt1.X()+dx );
+ aPt2.setY(aPt1.Y()+dy );
+ }
+ }
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrMeasureObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ SdrTextObj::NbcMirror(rRef1,rRef2);
+ MirrorPoint(aPt1,rRef1,rRef2);
+ MirrorPoint(aPt2,rRef1,rRef2);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrMeasureObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
+ ShearPoint(aPt1,rRef,tn,bVShear);
+ ShearPoint(aPt2,rRef,tn,bVShear);
+ SetBoundAndSnapRectsDirty();
+ SetTextDirty();
+}
+
+Degree100 SdrMeasureObj::GetRotateAngle() const
+{
+ return GetAngle(aPt2-aPt1);
+}
+
+void SdrMeasureObj::RecalcSnapRect()
+{
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+ XPolyPolygon aXPP;
+
+ ImpTakeAttr(aRec);
+ ImpCalcGeometrics(aRec, aMPol);
+ aXPP = XPolyPolygon(ImpCalcXPoly(aMPol));
+ maSnapRect = aXPP.GetBoundRect();
+}
+
+sal_uInt32 SdrMeasureObj::GetSnapPointCount() const
+{
+ return 2;
+}
+
+Point SdrMeasureObj::GetSnapPoint(sal_uInt32 i) const
+{
+ if (i==0) return aPt1;
+ else return aPt2;
+}
+
+bool SdrMeasureObj::IsPolyObj() const
+{
+ return true;
+}
+
+sal_uInt32 SdrMeasureObj::GetPointCount() const
+{
+ return 2;
+}
+
+Point SdrMeasureObj::GetPoint(sal_uInt32 i) const
+{
+ return (0 == i) ? aPt1 : aPt2;
+}
+
+void SdrMeasureObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
+{
+ if (0 == i)
+ aPt1=rPnt;
+ if (1 == i)
+ aPt2=rPnt;
+ SetBoundAndSnapRectsDirty();
+ SetTextDirty();
+}
+
+std::unique_ptr<SdrObjGeoData> SdrMeasureObj::NewGeoData() const
+{
+ return std::make_unique<SdrMeasureObjGeoData>();
+}
+
+void SdrMeasureObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrTextObj::SaveGeoData(rGeo);
+ SdrMeasureObjGeoData& rMGeo=static_cast<SdrMeasureObjGeoData&>(rGeo);
+ rMGeo.aPt1=aPt1;
+ rMGeo.aPt2=aPt2;
+}
+
+void SdrMeasureObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrTextObj::RestoreGeoData(rGeo);
+ const SdrMeasureObjGeoData& rMGeo=static_cast<const SdrMeasureObjGeoData&>(rGeo);
+ aPt1=rMGeo.aPt1;
+ aPt2=rMGeo.aPt2;
+ SetTextDirty();
+}
+
+SdrObjectUniquePtr SdrMeasureObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ // get XOR Poly as base
+ XPolyPolygon aTmpPolyPolygon(TakeXorPoly());
+
+ // get local ItemSet and StyleSheet
+ SfxItemSet aSet(GetObjectItemSet());
+ SfxStyleSheet* pStyleSheet = GetStyleSheet();
+
+ // prepare group
+ std::unique_ptr<SdrObjGroup,SdrObjectFreeOp> pGroup(new SdrObjGroup(getSdrModelFromSdrObject()));
+
+ // prepare parameters
+ basegfx::B2DPolyPolygon aPolyPoly;
+ SdrPathObj* pPath;
+ sal_uInt16 nCount(aTmpPolyPolygon.Count());
+ sal_uInt16 nLoopStart(0);
+
+ if(nCount == 3)
+ {
+ // three lines, first one is the middle one
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
+
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+ aSet.Put(XLineStartWidthItem(0));
+ aSet.Put(XLineEndWidthItem(0));
+ nLoopStart = 1;
+ }
+ else if(nCount == 4)
+ {
+ // four lines, middle line with gap, so there are two lines used
+ // which have one arrow each
+ sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
+ aSet.Put(XLineEndWidthItem(0));
+
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+
+ aSet.Put(XLineEndWidthItem(nEndWidth));
+ aSet.Put(XLineStartWidthItem(0));
+
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+
+ aSet.Put(XLineEndWidthItem(0));
+ nLoopStart = 2;
+ }
+ else if(nCount == 5)
+ {
+ // five lines, first two are the outer ones
+ sal_Int32 nEndWidth = aSet.Get(XATTR_LINEENDWIDTH).GetValue();
+
+ aSet.Put(XLineEndWidthItem(0));
+
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+
+ aSet.Put(XLineEndWidthItem(nEndWidth));
+ aSet.Put(XLineStartWidthItem(0));
+
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+
+ aSet.Put(XLineEndWidthItem(0));
+ nLoopStart = 2;
+ }
+
+ for(;nLoopStart<nCount;nLoopStart++)
+ {
+ aPolyPoly.clear();
+ aPolyPoly.append(aTmpPolyPolygon[nLoopStart].getB2DPolygon());
+ pPath = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPoly);
+
+ pPath->SetMergedItemSet(aSet);
+ pPath->SetStyleSheet(pStyleSheet, true);
+
+ pGroup->GetSubList()->NbcInsertObject(pPath);
+ }
+
+ if(bAddText)
+ {
+ return ImpConvertAddText(std::move(pGroup), bBezier);
+ }
+ else
+ {
+ return pGroup;
+ }
+}
+
+bool SdrMeasureObj::BegTextEdit(SdrOutliner& rOutl)
+{
+ UndirtyText();
+ return SdrTextObj::BegTextEdit(rOutl);
+}
+
+const Size& SdrMeasureObj::GetTextSize() const
+{
+ if (bTextDirty) UndirtyText();
+ return SdrTextObj::GetTextSize();
+}
+
+OutlinerParaObject* SdrMeasureObj::GetOutlinerParaObject() const
+{
+ if(bTextDirty)
+ UndirtyText();
+ return SdrTextObj::GetOutlinerParaObject();
+}
+
+void SdrMeasureObj::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject)
+{
+ SdrTextObj::NbcSetOutlinerParaObject(std::move(pTextObject));
+ if(SdrTextObj::GetOutlinerParaObject())
+ SetTextDirty(); // recalculate text
+}
+
+void SdrMeasureObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText,
+ tools::Rectangle* pAnchorRect, bool bLineWidth ) const
+{
+ if (bTextDirty) UndirtyText();
+ SdrTextObj::TakeTextRect( rOutliner, rTextRect, bNoEditText, pAnchorRect, bLineWidth );
+}
+
+void SdrMeasureObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
+{
+ if (bTextDirty) UndirtyText();
+ SdrTextObj::TakeTextAnchorRect(rAnchorRect);
+}
+
+void SdrMeasureObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
+{
+ if (bTextDirty) UndirtyText();
+ SdrTextObj::TakeTextEditArea(pPaperMin,pPaperMax,pViewInit,pViewMin);
+}
+
+EEAnchorMode SdrMeasureObj::GetOutlinerViewAnchorMode() const
+{
+ if (bTextDirty) UndirtyText();
+ ImpMeasureRec aRec;
+ ImpMeasurePoly aMPol;
+ ImpTakeAttr(aRec);
+ ImpCalcGeometrics(aRec,aMPol);
+
+ SdrTextHorzAdjust eTH=GetTextHorizontalAdjust();
+ SdrTextVertAdjust eTV=GetTextVerticalAdjust();
+ css::drawing::MeasureTextHorzPos eMH = aMPol.eUsedTextHPos;
+ css::drawing::MeasureTextVertPos eMV = aMPol.eUsedTextVPos;
+ bool bTextRota90=aRec.bTextRota90;
+ bool bBelowRefEdge=aRec.bBelowRefEdge;
+
+ // TODO: bTextUpsideDown should be interpreted here!
+ if (!bTextRota90) {
+ if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTH=SDRTEXTHORZADJUST_RIGHT;
+ if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTH=SDRTEXTHORZADJUST_LEFT;
+ // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor horizontally
+ if (eMV==css::drawing::MeasureTextVertPos_EAST) eTV=SDRTEXTVERTADJUST_BOTTOM;
+ if (eMV==css::drawing::MeasureTextVertPos_WEST) eTV=SDRTEXTVERTADJUST_TOP;
+ if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTV=SDRTEXTVERTADJUST_CENTER;
+ } else {
+ if (eMH==css::drawing::MeasureTextHorzPos_LEFTOUTSIDE) eTV=SDRTEXTVERTADJUST_BOTTOM;
+ if (eMH==css::drawing::MeasureTextHorzPos_RIGHTOUTSIDE) eTV=SDRTEXTVERTADJUST_TOP;
+ // at eMH==css::drawing::MeasureTextHorzPos_INSIDE we can anchor vertically
+ if (!bBelowRefEdge) {
+ if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_LEFT;
+ if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_RIGHT;
+ } else {
+ if (eMV==css::drawing::MeasureTextVertPos_EAST) eTH=SDRTEXTHORZADJUST_RIGHT;
+ if (eMV==css::drawing::MeasureTextVertPos_WEST) eTH=SDRTEXTHORZADJUST_LEFT;
+ }
+ if (eMV==css::drawing::MeasureTextVertPos_CENTERED) eTH=SDRTEXTHORZADJUST_CENTER;
+ }
+
+ EEAnchorMode eRet=EEAnchorMode::BottomHCenter;
+ if (eTH==SDRTEXTHORZADJUST_LEFT) {
+ if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopLeft;
+ else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomLeft;
+ else eRet=EEAnchorMode::VCenterLeft;
+ } else if (eTH==SDRTEXTHORZADJUST_RIGHT) {
+ if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopRight;
+ else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomRight;
+ else eRet=EEAnchorMode::VCenterRight;
+ } else {
+ if (eTV==SDRTEXTVERTADJUST_TOP) eRet=EEAnchorMode::TopHCenter;
+ else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=EEAnchorMode::BottomHCenter;
+ else eRet=EEAnchorMode::VCenterHCenter;
+ }
+ return eRet;
+}
+
+
+// #i97878#
+// TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions,
+// same as line geometry in SdrPathObj. Thus needs to be overridden and
+// implemented since currently it is derived from SdrTextObj which uses
+// a functionality based on SnapRect which is not useful here
+
+bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
+{
+ // handle the same as a simple line since the definition is based on two points
+ const basegfx::B2DRange aRange(aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y());
+ basegfx::B2DTuple aScale(aRange.getRange());
+ basegfx::B2DTuple aTranslate(aRange.getMinimum());
+
+ // position maybe relative to anchor position, convert
+ if( getSdrModelFromSdrObject().IsWriter() )
+ {
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // build return value matrix
+ rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
+
+ return true;
+}
+
+void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
+{
+ // use given transformation to derive the two defining points from unit line
+ basegfx::B2DPoint aPosA(rMatrix * basegfx::B2DPoint(0.0, 0.0));
+ basegfx::B2DPoint aPosB(rMatrix * basegfx::B2DPoint(1.0, 0.0));
+
+ if( getSdrModelFromSdrObject().IsWriter() )
+ {
+ // if anchor is used, make position relative to it
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ const basegfx::B2DVector aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());
+
+ aPosA += aAnchorOffset;
+ aPosB += aAnchorOffset;
+ }
+ }
+
+ // derive new model data
+ const Point aNewPt1(basegfx::fround(aPosA.getX()), basegfx::fround(aPosA.getY()));
+ const Point aNewPt2(basegfx::fround(aPosB.getX()), basegfx::fround(aPosB.getY()));
+
+ if(aNewPt1 == aPt1 && aNewPt2 == aPt2)
+ return;
+
+ // set model values and broadcast
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+
+ aPt1 = aNewPt1;
+ aPt2 = aNewPt2;
+
+ SetTextDirty();
+ ActionChanged();
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdomedia.cxx b/svx/source/svdraw/svdomedia.cxx
new file mode 100644
index 000000000..46a35c2d6
--- /dev/null
+++ b/svx/source/svdraw/svdomedia.cxx
@@ -0,0 +1,457 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column:100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <svx/svdomedia.hxx>
+
+#include <com/sun/star/text/GraphicCrop.hpp>
+
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+
+#include <ucbhelper/content.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/storagehelper.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include <svx/svdmodel.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/sdr/contact/viewcontactofsdrmediaobj.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+
+
+struct SdrMediaObj::Impl
+{
+ ::avmedia::MediaItem m_MediaProperties;
+#if HAVE_FEATURE_AVMEDIA
+ // Note: the temp file is read only, until it is deleted!
+ // It may be shared between multiple documents in case of copy/paste,
+ // hence the shared_ptr.
+ std::shared_ptr< ::avmedia::MediaTempFile > m_pTempFile;
+#endif
+ uno::Reference< graphic::XGraphic > m_xCachedSnapshot;
+ rtl::Reference<avmedia::PlayerListener> m_xPlayerListener;
+ OUString m_LastFailedPkgURL;
+};
+
+SdrMediaObj::SdrMediaObj(SdrModel& rSdrModel)
+: SdrRectObj(rSdrModel)
+ ,m_xImpl( new Impl )
+{
+}
+
+SdrMediaObj::SdrMediaObj(SdrModel& rSdrModel, SdrMediaObj const & rSource)
+: SdrRectObj(rSdrModel, rSource)
+ ,m_xImpl( new Impl )
+{
+#if HAVE_FEATURE_AVMEDIA
+ m_xImpl->m_pTempFile = rSource.m_xImpl->m_pTempFile; // before props
+#endif
+ setMediaProperties( rSource.getMediaProperties() );
+ m_xImpl->m_xCachedSnapshot = rSource.m_xImpl->m_xCachedSnapshot;
+}
+
+SdrMediaObj::SdrMediaObj(
+ SdrModel& rSdrModel,
+ const tools::Rectangle& rRect)
+: SdrRectObj(rSdrModel, rRect)
+ ,m_xImpl( new Impl )
+{
+ const bool bUndo(rSdrModel.IsUndoEnabled());
+ rSdrModel.EnableUndo(false);
+ MakeNameUnique();
+ rSdrModel.EnableUndo(bUndo);
+}
+
+SdrMediaObj::~SdrMediaObj()
+{
+}
+
+bool SdrMediaObj::HasTextEdit() const
+{
+ return false;
+}
+
+std::unique_ptr<sdr::contact::ViewContact> SdrMediaObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrMediaObj>( *this );
+}
+
+void SdrMediaObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const
+{
+ rInfo.bMoveAllowed = true;
+ rInfo.bResizeFreeAllowed = true;
+ rInfo.bResizePropAllowed = true;
+ rInfo.bRotateFreeAllowed = false;
+ rInfo.bRotate90Allowed = false;
+ rInfo.bMirrorFreeAllowed = false;
+ rInfo.bMirror45Allowed = false;
+ rInfo.bMirror90Allowed = false;
+ rInfo.bTransparenceAllowed = false;
+ rInfo.bShearAllowed = false;
+ rInfo.bEdgeRadiusAllowed = false;
+ rInfo.bNoOrthoDesired = false;
+ rInfo.bNoContortion = false;
+ rInfo.bCanConvToPath = false;
+ rInfo.bCanConvToPoly = false;
+ rInfo.bCanConvToContour = false;
+ rInfo.bCanConvToPathLineToArea = false;
+ rInfo.bCanConvToPolyLineToArea = false;
+}
+
+SdrObjKind SdrMediaObj::GetObjIdentifier() const
+{
+ return SdrObjKind::Media;
+}
+
+OUString SdrMediaObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulMEDIA));
+
+ OUString aName(GetName());
+
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+OUString SdrMediaObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralMEDIA);
+}
+
+SdrMediaObj* SdrMediaObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrMediaObj(rTargetModel, *this);
+}
+
+uno::Reference< graphic::XGraphic > const & SdrMediaObj::getSnapshot() const
+{
+#if HAVE_FEATURE_AVMEDIA
+ if( !m_xImpl->m_xCachedSnapshot.is() )
+ {
+ Graphic aGraphic = m_xImpl->m_MediaProperties.getGraphic();
+ if (!aGraphic.IsNone())
+ {
+ Size aPref = aGraphic.GetPrefSize();
+ Size aPixel = aGraphic.GetSizePixel();
+ const text::GraphicCrop& rCrop = m_xImpl->m_MediaProperties.getCrop();
+ if (rCrop.Bottom > 0 || rCrop.Left > 0 || rCrop.Right > 0 || rCrop.Top > 0)
+ {
+ tools::Long nLeft = aPixel.getWidth() * rCrop.Left / aPref.getWidth();
+ tools::Long nTop = aPixel.getHeight() * rCrop.Top / aPref.getHeight();
+ tools::Long nRight = aPixel.getWidth() * rCrop.Right / aPref.getWidth();
+ tools::Long nBottom = aPixel.getHeight() * rCrop.Bottom / aPref.getHeight();
+ BitmapEx aBitmapEx = aGraphic.GetBitmapEx();
+ aBitmapEx.Crop({nLeft, nTop, aPixel.getWidth() - nRight, aPixel.getHeight() - nBottom});
+ aGraphic = aBitmapEx;
+ }
+
+ // We have an explicit graphic for this media object, then go with that instead of
+ // generating our own one.
+ m_xImpl->m_xCachedSnapshot = aGraphic.GetXGraphic();
+ return m_xImpl->m_xCachedSnapshot;
+ }
+
+ OUString aRealURL = m_xImpl->m_MediaProperties.getTempURL();
+ if( aRealURL.isEmpty() )
+ aRealURL = m_xImpl->m_MediaProperties.getURL();
+ OUString sReferer = m_xImpl->m_MediaProperties.getReferer();
+ OUString sMimeType = m_xImpl->m_MediaProperties.getMimeType();
+ uno::Reference<graphic::XGraphic> xCachedSnapshot = m_xImpl->m_xCachedSnapshot;
+
+ m_xImpl->m_xPlayerListener.set(new avmedia::PlayerListener(
+ [this, xCachedSnapshot, aRealURL, sReferer, sMimeType](const css::uno::Reference<css::media::XPlayer>& rPlayer){
+ SolarMutexGuard g;
+ uno::Reference<graphic::XGraphic> xGraphic
+ = m_xImpl->m_MediaProperties.getGraphic().GetXGraphic();
+ m_xImpl->m_xCachedSnapshot = avmedia::MediaWindow::grabFrame(rPlayer, xGraphic);
+ ActionChanged();
+ }));
+
+ avmedia::MediaWindow::grabFrame(aRealURL, sReferer, sMimeType, m_xImpl->m_xPlayerListener);
+ }
+#endif
+ return m_xImpl->m_xCachedSnapshot;
+}
+
+void SdrMediaObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool bShrinkOnly /* = false */ )
+{
+ Size aSize( Application::GetDefaultDevice()->PixelToLogic(
+ static_cast< sdr::contact::ViewContactOfSdrMediaObj& >( GetViewContact() ).getPreferredSize(),
+ MapMode(MapUnit::Map100thMM)) );
+ Size aMaxSize( rMaxRect.GetSize() );
+
+ if( aSize.IsEmpty() )
+ return;
+
+ Point aPos( rMaxRect.TopLeft() );
+
+ // if graphic is too large, fit it to the page
+ if ( (!bShrinkOnly ||
+ ( aSize.Height() > aMaxSize.Height() ) ||
+ ( aSize.Width() > aMaxSize.Width() ) )&&
+ aSize.Height() && aMaxSize.Height() )
+ {
+ float fGrfWH = static_cast<float>(aSize.Width()) /
+ static_cast<float>(aSize.Height());
+ float fWinWH = static_cast<float>(aMaxSize.Width()) /
+ static_cast<float>(aMaxSize.Height());
+
+ // scale graphic to page size
+ if ( fGrfWH < fWinWH )
+ {
+ aSize.setWidth( static_cast<tools::Long>(aMaxSize.Height() * fGrfWH) );
+ aSize.setHeight( aMaxSize.Height() );
+ }
+ else if ( fGrfWH > 0.F )
+ {
+ aSize.setWidth( aMaxSize.Width() );
+ aSize.setHeight( static_cast<tools::Long>(aMaxSize.Width() / fGrfWH) );
+ }
+
+ aPos = rMaxRect.Center();
+ }
+
+ if( bShrinkOnly )
+ aPos = maRect.TopLeft();
+
+ aPos.AdjustX( -(aSize.Width() / 2) );
+ aPos.AdjustY( -(aSize.Height() / 2) );
+ SetLogicRect( tools::Rectangle( aPos, aSize ) );
+}
+
+void SdrMediaObj::setURL( const OUString& rURL, const OUString& rReferer, const OUString& rMimeType )
+{
+ ::avmedia::MediaItem aURLItem;
+#if HAVE_FEATURE_AVMEDIA
+ if( !rMimeType.isEmpty() )
+ m_xImpl->m_MediaProperties.setMimeType(rMimeType);
+ aURLItem.setURL( rURL, "", rReferer );
+#else
+ (void) rMimeType;
+ (void) rURL;
+ (void) rReferer;
+#endif
+ setMediaProperties( aURLItem );
+}
+
+const OUString& SdrMediaObj::getURL() const
+{
+#if HAVE_FEATURE_AVMEDIA
+ return m_xImpl->m_MediaProperties.getURL();
+#else
+ static OUString ret;
+ return ret;
+#endif
+}
+
+void SdrMediaObj::setMediaProperties( const ::avmedia::MediaItem& rState )
+{
+ mediaPropertiesChanged( rState );
+ static_cast< sdr::contact::ViewContactOfSdrMediaObj& >( GetViewContact() ).executeMediaItem( getMediaProperties() );
+}
+
+const ::avmedia::MediaItem& SdrMediaObj::getMediaProperties() const
+{
+ return m_xImpl->m_MediaProperties;
+}
+
+uno::Reference<io::XInputStream> SdrMediaObj::GetInputStream() const
+{
+#if HAVE_FEATURE_AVMEDIA
+ if (!m_xImpl->m_pTempFile)
+ {
+ SAL_WARN("svx", "this is only intended for embedded media");
+ return nullptr;
+ }
+ ucbhelper::Content tempFile(m_xImpl->m_pTempFile->m_TempFileURL,
+ uno::Reference<ucb::XCommandEnvironment>(),
+ comphelper::getProcessComponentContext());
+ return tempFile.openStream();
+#else
+ return nullptr;
+#endif
+}
+
+void SdrMediaObj::SetInputStream(uno::Reference<io::XInputStream> const& xStream)
+{
+#if !HAVE_FEATURE_AVMEDIA
+ (void) xStream;
+#else
+ if (m_xImpl->m_pTempFile || m_xImpl->m_LastFailedPkgURL.isEmpty())
+ {
+ SAL_WARN("svx", "this is only intended for embedded media");
+ return;
+ }
+
+ OUString tempFileURL;
+ const bool bSuccess(
+ ::avmedia::CreateMediaTempFile(
+ xStream,
+ tempFileURL,
+ u""));
+
+ if (bSuccess)
+ {
+ m_xImpl->m_pTempFile = std::make_shared<::avmedia::MediaTempFile>(tempFileURL);
+ m_xImpl->m_MediaProperties.setURL(
+ m_xImpl->m_LastFailedPkgURL, tempFileURL, "");
+ }
+ m_xImpl->m_LastFailedPkgURL.clear(); // once only
+#endif
+}
+
+/// copy a stream from XStorage to temp file
+#if HAVE_FEATURE_AVMEDIA
+static bool lcl_HandlePackageURL(
+ OUString const & rURL,
+ const SdrModel& rModel,
+ OUString & o_rTempFileURL)
+{
+ ::comphelper::LifecycleProxy sourceProxy;
+ uno::Reference<io::XInputStream> xInStream;
+ try {
+ xInStream = rModel.GetDocumentStream(rURL, sourceProxy);
+ }
+ catch (container::NoSuchElementException const&)
+ {
+ SAL_INFO("svx", "not found: '" << rURL << "'");
+ return false;
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ return false;
+ }
+ if (!xInStream.is())
+ {
+ SAL_WARN("svx", "no stream?");
+ return false;
+ }
+ // Make sure the temporary copy has the same file name extension as the original media file
+ // (like .mp4). That seems to be important for some AVFoundation APIs. For random extension-less
+ // file names, they don't seem to even bother looking inside the file.
+ sal_Int32 nLastDot = rURL.lastIndexOf('.');
+ sal_Int32 nLastSlash = rURL.lastIndexOf('/');
+ OUString sDesiredExtension;
+ if (nLastDot > nLastSlash && nLastDot+1 < rURL.getLength())
+ sDesiredExtension = rURL.copy(nLastDot);
+ return ::avmedia::CreateMediaTempFile(xInStream, o_rTempFileURL, sDesiredExtension);
+}
+#endif
+
+void SdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewProperties )
+{
+ bool bBroadcastChanged = false;
+#if HAVE_FEATURE_AVMEDIA
+ const AVMediaSetMask nMaskSet = rNewProperties.getMaskSet();
+
+ // use only a subset of MediaItem properties for own properties
+ if( AVMediaSetMask::MIME_TYPE & nMaskSet )
+ m_xImpl->m_MediaProperties.setMimeType( rNewProperties.getMimeType() );
+
+ if (nMaskSet & AVMediaSetMask::GRAPHIC)
+ {
+ m_xImpl->m_MediaProperties.setGraphic(rNewProperties.getGraphic());
+ }
+
+ if (nMaskSet & AVMediaSetMask::CROP)
+ {
+ m_xImpl->m_MediaProperties.setCrop(rNewProperties.getCrop());
+ }
+
+ if( ( AVMediaSetMask::URL & nMaskSet ) &&
+ ( rNewProperties.getURL() != getURL() ))
+ {
+ m_xImpl->m_xCachedSnapshot.clear();
+ m_xImpl->m_xPlayerListener.clear();
+ OUString const& url(rNewProperties.getURL());
+ if (url.startsWithIgnoreAsciiCase("vnd.sun.star.Package:"))
+ {
+ if ( !m_xImpl->m_pTempFile
+ || (m_xImpl->m_pTempFile->m_TempFileURL !=
+ rNewProperties.getTempURL()))
+ {
+ OUString tempFileURL;
+ const bool bSuccess(
+ lcl_HandlePackageURL(
+ url,
+ getSdrModelFromSdrObject(),
+ tempFileURL));
+
+ if (bSuccess)
+ {
+ m_xImpl->m_pTempFile =
+ std::make_shared<::avmedia::MediaTempFile>(tempFileURL);
+ m_xImpl->m_MediaProperties.setURL(url, tempFileURL, "");
+ }
+ else // this case is for Clone via operator=
+ {
+ m_xImpl->m_pTempFile.reset();
+ m_xImpl->m_MediaProperties.setURL("", "", "");
+ // UGLY: oox import also gets here, because unlike ODF
+ // getDocumentStorage() is not the imported file...
+ m_xImpl->m_LastFailedPkgURL = url;
+ }
+ }
+ else
+ {
+ m_xImpl->m_MediaProperties.setURL(url,
+ rNewProperties.getTempURL(), "");
+ }
+ }
+ else
+ {
+ m_xImpl->m_pTempFile.reset();
+ m_xImpl->m_MediaProperties.setURL(url, "", rNewProperties.getReferer());
+ }
+ bBroadcastChanged = true;
+ }
+
+ if( AVMediaSetMask::LOOP & nMaskSet )
+ m_xImpl->m_MediaProperties.setLoop( rNewProperties.isLoop() );
+
+ if( AVMediaSetMask::MUTE & nMaskSet )
+ m_xImpl->m_MediaProperties.setMute( rNewProperties.isMute() );
+
+ if( AVMediaSetMask::VOLUMEDB & nMaskSet )
+ m_xImpl->m_MediaProperties.setVolumeDB( rNewProperties.getVolumeDB() );
+
+ if( AVMediaSetMask::ZOOM & nMaskSet )
+ m_xImpl->m_MediaProperties.setZoom( rNewProperties.getZoom() );
+#else
+ (void) rNewProperties;
+#endif
+
+ if( bBroadcastChanged )
+ {
+ SetChanged();
+ BroadcastObjectChange();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdoole2.cxx b/svx/source/svdraw/svdoole2.cxx
new file mode 100644
index 000000000..110240782
--- /dev/null
+++ b/svx/source/svdraw/svdoole2.cxx
@@ -0,0 +1,1990 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdoole2.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/EmbedMisc.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/ObjectSaveVetoException.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XEmbedPersist2.hpp>
+#include <com/sun/star/embed/XInplaceClient.hpp>
+#include <com/sun/star/embed/XInplaceObject.hpp>
+#include <com/sun/star/embed/XLinkageSupport.hpp>
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/embed/XWindowSupplier.hpp>
+#include <com/sun/star/document/XEventListener.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <toolkit/helper/convert.hxx>
+
+#include <svtools/colorcfg.hxx>
+#include <svtools/embedhlp.hxx>
+
+#include <sfx2/objsh.hxx>
+#include <sfx2/ipclient.hxx>
+#include <sfx2/lnkbase.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <tools/debug.hxx>
+#include <tools/globname.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/classids.hxx>
+#include <comphelper/propertyvalue.hxx>
+
+#include <sot/formats.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include <svx/svdmodel.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdetc.hxx>
+#include <unomlstr.hxx>
+#include <sdr/contact/viewcontactofsdrole2obj.hxx>
+#include <svx/svdograf.hxx>
+#include <sdr/properties/oleproperties.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflbstit.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/svdpage.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ref.hxx>
+#include <bitmaps.hlst>
+
+using namespace ::com::sun::star;
+
+static uno::Reference < beans::XPropertySet > lcl_getFrame_throw(const SdrOle2Obj* _pObject)
+{
+ uno::Reference < beans::XPropertySet > xFrame;
+ if ( _pObject )
+ {
+ uno::Reference< frame::XController> xController = _pObject->GetParentXModel()->getCurrentController();
+ if ( xController.is() )
+ {
+ xFrame.set( xController->getFrame(),uno::UNO_QUERY_THROW);
+ }
+ } // if ( _pObject )
+ return xFrame;
+}
+
+namespace {
+
+class SdrLightEmbeddedClient_Impl : public ::cppu::WeakImplHelper
+ < embed::XStateChangeListener
+ , document::XEventListener
+ , embed::XInplaceClient
+ , embed::XEmbeddedClient
+ , embed::XWindowSupplier
+ >
+{
+ uno::Reference< awt::XWindow > m_xWindow;
+ SdrOle2Obj* mpObj;
+
+ Fraction m_aScaleWidth;
+ Fraction m_aScaleHeight;
+
+
+public:
+ explicit SdrLightEmbeddedClient_Impl( SdrOle2Obj* pObj );
+ virtual ~SdrLightEmbeddedClient_Impl() override;
+
+ void SetSizeScale( const Fraction& aScaleWidth, const Fraction& aScaleHeight )
+ {
+ m_aScaleWidth = aScaleWidth;
+ m_aScaleHeight = aScaleHeight;
+ }
+
+ const Fraction& GetScaleWidth() const { return m_aScaleWidth; }
+ const Fraction& GetScaleHeight() const { return m_aScaleHeight; }
+
+ void setWindow(const uno::Reference< awt::XWindow >& _xWindow);
+
+ void disconnect();
+private:
+
+ tools::Rectangle impl_getScaledRect_nothrow() const;
+ // XStateChangeListener
+ virtual void SAL_CALL changingState( const css::lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override;
+ virtual void SAL_CALL stateChanged( const css::lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& aEvent ) override;
+
+ // document::XEventListener
+ virtual void SAL_CALL notifyEvent( const document::EventObject& aEvent ) override;
+
+ // XEmbeddedClient
+ virtual void SAL_CALL saveObject() override;
+ virtual void SAL_CALL visibilityChanged( sal_Bool bVisible ) override;
+
+ // XComponentSupplier
+ virtual uno::Reference< util::XCloseable > SAL_CALL getComponent() override;
+
+ // XInplaceClient
+ virtual sal_Bool SAL_CALL canInplaceActivate() override;
+ virtual void SAL_CALL activatingInplace() override;
+ virtual void SAL_CALL activatingUI() override;
+ virtual void SAL_CALL deactivatedInplace() override;
+ virtual void SAL_CALL deactivatedUI() override;
+ virtual uno::Reference< css::frame::XLayoutManager > SAL_CALL getLayoutManager() override;
+ virtual uno::Reference< frame::XDispatchProvider > SAL_CALL getInplaceDispatchProvider() override;
+ virtual awt::Rectangle SAL_CALL getPlacement() override;
+ virtual awt::Rectangle SAL_CALL getClipRectangle() override;
+ virtual void SAL_CALL translateAccelerators( const uno::Sequence< awt::KeyEvent >& aKeys ) override;
+ virtual void SAL_CALL scrollObject( const awt::Size& aOffset ) override;
+ virtual void SAL_CALL changedPlacement( const awt::Rectangle& aPosRect ) override;
+
+ // XWindowSupplier
+ virtual uno::Reference< awt::XWindow > SAL_CALL getWindow() override;
+};
+
+}
+
+SdrLightEmbeddedClient_Impl::SdrLightEmbeddedClient_Impl( SdrOle2Obj* pObj )
+: mpObj( pObj )
+{
+}
+SdrLightEmbeddedClient_Impl::~SdrLightEmbeddedClient_Impl()
+{
+ assert(!mpObj);
+}
+tools::Rectangle SdrLightEmbeddedClient_Impl::impl_getScaledRect_nothrow() const
+{
+ tools::Rectangle aLogicRect( mpObj->GetLogicRect() );
+ // apply scaling to object area and convert to pixels
+ aLogicRect.SetSize( Size( tools::Long( aLogicRect.GetWidth() * m_aScaleWidth),
+ tools::Long( aLogicRect.GetHeight() * m_aScaleHeight) ) );
+ return aLogicRect;
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::changingState( const css::lang::EventObject& /*aEvent*/, ::sal_Int32 /*nOldState*/, ::sal_Int32 /*nNewState*/ )
+{
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::stateChanged( const css::lang::EventObject& /*aEvent*/, ::sal_Int32 nOldState, ::sal_Int32 nNewState )
+{
+ SolarMutexGuard aGuard;
+
+ if ( mpObj && nOldState == embed::EmbedStates::LOADED && nNewState == embed::EmbedStates::RUNNING )
+ {
+ mpObj->ObjectLoaded();
+ GetSdrGlobalData().GetOLEObjCache().InsertObj(mpObj);
+ }
+ else if ( mpObj && nNewState == embed::EmbedStates::LOADED && nOldState == embed::EmbedStates::RUNNING )
+ {
+ GetSdrGlobalData().GetOLEObjCache().RemoveObj(mpObj);
+ }
+}
+
+void SdrLightEmbeddedClient_Impl::disconnect()
+{
+ SolarMutexGuard aGuard;
+ if (!mpObj)
+ return;
+ GetSdrGlobalData().GetOLEObjCache().RemoveObj(mpObj);
+ mpObj = nullptr;
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::disposing( const css::lang::EventObject& /*aEvent*/ )
+{
+ disconnect();
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::notifyEvent( const document::EventObject& aEvent )
+{
+ // TODO/LATER: when writer uses this implementation the code could be shared with SfxInPlaceClient_Impl
+
+ SolarMutexGuard aGuard;
+
+ // the code currently makes sense only in case there is no other client
+ if ( !(mpObj && mpObj->GetAspect() != embed::Aspects::MSOLE_ICON && aEvent.EventName == "OnVisAreaChanged"
+ && mpObj->GetObjRef().is() && mpObj->GetObjRef()->getClientSite() == uno::Reference< embed::XEmbeddedClient >( this )) )
+ return;
+
+ try
+ {
+ MapUnit aContainerMapUnit( MapUnit::Map100thMM );
+ uno::Reference< embed::XVisualObject > xParentVis( mpObj->GetParentXModel(), uno::UNO_QUERY );
+ if ( xParentVis.is() )
+ aContainerMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xParentVis->getMapUnit( mpObj->GetAspect() ) );
+
+ MapUnit aObjMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( mpObj->GetObjRef()->getMapUnit( mpObj->GetAspect() ) );
+
+ tools::Rectangle aVisArea;
+ awt::Size aSz;
+ try
+ {
+ aSz = mpObj->GetObjRef()->getVisualAreaSize( mpObj->GetAspect() );
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.svdraw", "No visual area size!");
+ aSz.Width = 5000;
+ aSz.Height = 5000;
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.svdraw", "");
+ aSz.Width = 5000;
+ aSz.Height = 5000;
+ }
+
+ aVisArea.SetSize( Size( aSz.Width, aSz.Height ) );
+ aVisArea = OutputDevice::LogicToLogic(aVisArea, MapMode(aObjMapUnit), MapMode(aContainerMapUnit));
+ Size aScaledSize( static_cast< tools::Long >( m_aScaleWidth * Fraction( aVisArea.GetWidth() ) ),
+ static_cast< tools::Long >( m_aScaleHeight * Fraction( aVisArea.GetHeight() ) ) );
+ tools::Rectangle aLogicRect( mpObj->GetLogicRect() );
+
+ // react to the change if the difference is bigger than one pixel
+ Size aPixelDiff =
+ Application::GetDefaultDevice()->LogicToPixel(
+ Size( aLogicRect.GetWidth() - aScaledSize.Width(),
+ aLogicRect.GetHeight() - aScaledSize.Height() ),
+ MapMode(aContainerMapUnit));
+ if( aPixelDiff.Width() || aPixelDiff.Height() )
+ {
+ mpObj->SetLogicRect( tools::Rectangle( aLogicRect.TopLeft(), aScaledSize ) );
+ mpObj->BroadcastObjectChange();
+ }
+ else
+ mpObj->ActionChanged();
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.svdraw", "");
+ }
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::saveObject()
+{
+ // TODO/LATER: when writer uses this implementation the code could be shared with SfxInPlaceClient_Impl
+ uno::Reference< embed::XCommonEmbedPersist > xPersist;
+ uno::Reference< util::XModifiable > xModifiable;
+
+ {
+ SolarMutexGuard aGuard;
+
+ if ( !mpObj )
+ throw embed::ObjectSaveVetoException();
+
+ // the common persistence is supported by objects and links
+ xPersist.set( mpObj->GetObjRef(), uno::UNO_QUERY_THROW );
+ xModifiable.set( mpObj->GetParentXModel(), uno::UNO_QUERY );
+ }
+
+ xPersist->storeOwn();
+
+ if ( xModifiable.is() )
+ xModifiable->setModified( true );
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::visibilityChanged( sal_Bool /*bVisible*/ )
+{
+ // nothing to do currently
+ // TODO/LATER: when writer uses this implementation the code could be shared with SfxInPlaceClient_Impl
+ if ( mpObj )
+ {
+ tools::Rectangle aLogicRect( mpObj->GetLogicRect() );
+ Size aLogicSize( aLogicRect.GetWidth(), aLogicRect.GetHeight() );
+
+ if( mpObj->IsChart() )
+ {
+ //charts never should be stretched see #i84323# for example
+ mpObj->SetLogicRect( tools::Rectangle( aLogicRect.TopLeft(), aLogicSize ) );
+ mpObj->BroadcastObjectChange();
+ } // if( mpObj->IsChart() )
+ }
+}
+
+uno::Reference< util::XCloseable > SAL_CALL SdrLightEmbeddedClient_Impl::getComponent()
+{
+ uno::Reference< util::XCloseable > xResult;
+
+ SolarMutexGuard aGuard;
+ if ( mpObj )
+ xResult.set( mpObj->GetParentXModel(), uno::UNO_QUERY );
+
+ return xResult;
+}
+// XInplaceClient
+
+sal_Bool SAL_CALL SdrLightEmbeddedClient_Impl::canInplaceActivate()
+{
+ bool bRet = false;
+ SolarMutexGuard aGuard;
+ if ( mpObj )
+ {
+ uno::Reference< embed::XEmbeddedObject > xObject = mpObj->GetObjRef();
+ if ( !xObject.is() )
+ throw uno::RuntimeException();
+ // we don't want to switch directly from outplace to inplace mode
+ bRet = ( xObject->getCurrentState() != embed::EmbedStates::ACTIVE && mpObj->GetAspect() != embed::Aspects::MSOLE_ICON );
+ } // if ( mpObj )
+ return bRet;
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::activatingInplace()
+{
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::activatingUI()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference < beans::XPropertySet > xFrame( lcl_getFrame_throw(mpObj));
+ uno::Reference < frame::XFrame > xOwnFrame( xFrame,uno::UNO_QUERY);
+ uno::Reference < frame::XFramesSupplier > xParentFrame = xOwnFrame->getCreator();
+ if ( xParentFrame.is() )
+ xParentFrame->setActiveFrame( xOwnFrame );
+
+ OLEObjCache& rObjCache = GetSdrGlobalData().GetOLEObjCache();
+ const size_t nCount = rObjCache.size();
+ for(sal_Int32 i = nCount-1 ; i >= 0;--i)
+ {
+ SdrOle2Obj* pObj = rObjCache[i];
+ if ( pObj != mpObj )
+ {
+ // only deactivate ole objects which belongs to the same frame
+ if ( xFrame == lcl_getFrame_throw(pObj) )
+ {
+ const uno::Reference< embed::XEmbeddedObject >& xObject = pObj->GetObjRef();
+ try
+ {
+ if ( xObject->getStatus( pObj->GetAspect() ) & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE )
+ xObject->changeState( embed::EmbedStates::INPLACE_ACTIVE );
+ else
+ {
+ // the links should not stay in running state for long time because of locking
+ uno::Reference< embed::XLinkageSupport > xLink( xObject, uno::UNO_QUERY );
+ if ( xLink.is() && xLink->isLink() )
+ xObject->changeState( embed::EmbedStates::LOADED );
+ else
+ xObject->changeState( embed::EmbedStates::RUNNING );
+ }
+ }
+ catch (css::uno::Exception& )
+ {}
+ }
+ }
+ } // for(sal_Int32 i = nCount-1 ; i >= 0;--i)
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::deactivatedInplace()
+{
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::deactivatedUI()
+{
+ SolarMutexGuard aGuard;
+ css::uno::Reference< css::frame::XLayoutManager > xLayoutManager(getLayoutManager());
+ if ( xLayoutManager.is() )
+ {
+ static constexpr OUStringLiteral aMenuBarURL = u"private:resource/menubar/menubar";
+ if ( !xLayoutManager->isElementVisible( aMenuBarURL ) )
+ xLayoutManager->createElement( aMenuBarURL );
+ }
+}
+
+uno::Reference< css::frame::XLayoutManager > SAL_CALL SdrLightEmbeddedClient_Impl::getLayoutManager()
+{
+ uno::Reference< css::frame::XLayoutManager > xMan;
+ SolarMutexGuard aGuard;
+ uno::Reference < beans::XPropertySet > xFrame( lcl_getFrame_throw(mpObj));
+ try
+ {
+ xMan.set(xFrame->getPropertyValue("LayoutManager"),uno::UNO_QUERY);
+ }
+ catch ( uno::Exception& ex )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( ex.Message,
+ nullptr, anyEx );
+ }
+
+ return xMan;
+}
+
+uno::Reference< frame::XDispatchProvider > SAL_CALL SdrLightEmbeddedClient_Impl::getInplaceDispatchProvider()
+{
+ SolarMutexGuard aGuard;
+ return uno::Reference < frame::XDispatchProvider >( lcl_getFrame_throw(mpObj), uno::UNO_QUERY_THROW );
+}
+
+awt::Rectangle SAL_CALL SdrLightEmbeddedClient_Impl::getPlacement()
+{
+ SolarMutexGuard aGuard;
+ if ( !mpObj )
+ throw uno::RuntimeException();
+
+ tools::Rectangle aLogicRect = impl_getScaledRect_nothrow();
+ MapUnit aContainerMapUnit( MapUnit::Map100thMM );
+ uno::Reference< embed::XVisualObject > xParentVis( mpObj->GetParentXModel(), uno::UNO_QUERY );
+ if ( xParentVis.is() )
+ aContainerMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xParentVis->getMapUnit( mpObj->GetAspect() ) );
+
+ aLogicRect = Application::GetDefaultDevice()->LogicToPixel(aLogicRect, MapMode(aContainerMapUnit));
+ return AWTRectangle( aLogicRect );
+}
+
+awt::Rectangle SAL_CALL SdrLightEmbeddedClient_Impl::getClipRectangle()
+{
+ return getPlacement();
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::translateAccelerators( const uno::Sequence< awt::KeyEvent >& /*aKeys*/ )
+{
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::scrollObject( const awt::Size& /*aOffset*/ )
+{
+}
+
+void SAL_CALL SdrLightEmbeddedClient_Impl::changedPlacement( const awt::Rectangle& aPosRect )
+{
+ SolarMutexGuard aGuard;
+ if ( !mpObj )
+ throw uno::RuntimeException();
+
+ uno::Reference< embed::XInplaceObject > xInplace( mpObj->GetObjRef(), uno::UNO_QUERY_THROW );
+
+ // check if the change is at least one pixel in size
+ awt::Rectangle aOldRect = getPlacement();
+ tools::Rectangle aNewPixelRect = VCLRectangle( aPosRect );
+ tools::Rectangle aOldPixelRect = VCLRectangle( aOldRect );
+ if ( aOldPixelRect == aNewPixelRect )
+ // nothing has changed
+ return;
+
+ // new scaled object area
+ MapUnit aContainerMapUnit( MapUnit::Map100thMM );
+ uno::Reference< embed::XVisualObject > xParentVis( mpObj->GetParentXModel(), uno::UNO_QUERY );
+ if ( xParentVis.is() )
+ aContainerMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xParentVis->getMapUnit( mpObj->GetAspect() ) );
+
+ tools::Rectangle aNewLogicRect = Application::GetDefaultDevice()->PixelToLogic(aNewPixelRect, MapMode(aContainerMapUnit));
+ tools::Rectangle aLogicRect = impl_getScaledRect_nothrow();
+
+ if ( aNewLogicRect == aLogicRect )
+ return;
+
+ // the calculation of the object area has not changed the object size
+ // it should be done here then
+ //SfxBooleanFlagGuard aGuard( m_bResizeNoScale, true );
+
+ // new size of the object area without scaling
+ Size aNewObjSize( tools::Long( aNewLogicRect.GetWidth() / m_aScaleWidth ),
+ tools::Long( aNewLogicRect.GetHeight() / m_aScaleHeight ) );
+
+ // now remove scaling from new placement and keep this at the new object area
+ aNewLogicRect.SetSize( aNewObjSize );
+ // react to the change if the difference is bigger than one pixel
+ Size aPixelDiff =
+ Application::GetDefaultDevice()->LogicToPixel(
+ Size( aLogicRect.GetWidth() - aNewObjSize.Width(),
+ aLogicRect.GetHeight() - aNewObjSize.Height() ),
+ MapMode(aContainerMapUnit));
+ if( aPixelDiff.Width() || aPixelDiff.Height() )
+ {
+ mpObj->SetLogicRect( tools::Rectangle( aLogicRect.TopLeft(), aNewObjSize ) );
+ mpObj->BroadcastObjectChange();
+ }
+ else
+ mpObj->ActionChanged();
+}
+// XWindowSupplier
+
+uno::Reference< awt::XWindow > SAL_CALL SdrLightEmbeddedClient_Impl::getWindow()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< awt::XWindow > xCurrent = m_xWindow;
+ if ( !xCurrent.is() )
+ {
+ if ( !mpObj )
+ throw uno::RuntimeException();
+ uno::Reference< frame::XFrame> xFrame(lcl_getFrame_throw(mpObj),uno::UNO_QUERY_THROW);
+ xCurrent = xFrame->getComponentWindow();
+ } // if ( !xCurrent.is() )
+ return xCurrent;
+}
+void SdrLightEmbeddedClient_Impl::setWindow(const uno::Reference< awt::XWindow >& _xWindow)
+{
+ m_xWindow = _xWindow;
+}
+
+SdrEmbedObjectLink::SdrEmbedObjectLink(SdrOle2Obj* pObject):
+ ::sfx2::SvBaseLink( ::SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SVXB ),
+ pObj(pObject)
+{
+ SetSynchron( false );
+}
+
+SdrEmbedObjectLink::~SdrEmbedObjectLink()
+{
+}
+
+::sfx2::SvBaseLink::UpdateResult SdrEmbedObjectLink::DataChanged(
+ const OUString& /*rMimeType*/, const css::uno::Any & /*rValue*/ )
+{
+ if ( !pObj->UpdateLinkURL_Impl() )
+ {
+ // the link URL was not changed
+ uno::Reference< embed::XEmbeddedObject > xObject = pObj->GetObjRef();
+ OSL_ENSURE( xObject.is(), "The object must exist always!" );
+ if ( xObject.is() )
+ {
+ // let the object reload the link
+ // TODO/LATER: reload call could be used for this case
+
+ try
+ {
+ sal_Int32 nState = xObject->getCurrentState();
+ if ( nState != embed::EmbedStates::LOADED )
+ {
+ // in some cases the linked file probably is not locked so it could be changed
+ xObject->changeState( embed::EmbedStates::LOADED );
+ xObject->changeState( nState );
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ }
+
+ pObj->GetNewReplacement();
+ pObj->SetChanged();
+
+ return SUCCESS;
+}
+
+void SdrEmbedObjectLink::Closed()
+{
+ pObj->BreakFileLink_Impl();
+ SvBaseLink::Closed();
+}
+
+SdrIFrameLink::SdrIFrameLink(SdrOle2Obj* pObject)
+ : ::sfx2::SvBaseLink(::SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SVXB)
+ , m_pObject(pObject)
+{
+ SetSynchron( false );
+}
+
+::sfx2::SvBaseLink::UpdateResult SdrIFrameLink::DataChanged(
+ const OUString&, const uno::Any& )
+{
+ uno::Reference<embed::XEmbeddedObject> xObject = m_pObject->GetObjRef();
+ uno::Reference<embed::XCommonEmbedPersist> xPersObj(xObject, uno::UNO_QUERY);
+ if (xPersObj.is())
+ {
+ // let the IFrameObject reload the link
+ try
+ {
+ xPersObj->reload(uno::Sequence<beans::PropertyValue>(), uno::Sequence<beans::PropertyValue>());
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ m_pObject->SetChanged();
+ }
+
+ return SUCCESS;
+}
+
+class SdrOle2ObjImpl
+{
+public:
+ svt::EmbeddedObjectRef mxObjRef;
+
+ std::unique_ptr<Graphic> mxGraphic;
+ OUString maProgName;
+ OUString aPersistName; // name of object in persist
+ rtl::Reference<SdrLightEmbeddedClient_Impl> mxLightClient; // must be registered as client only using AddOwnLightClient() call
+
+ bool mbFrame:1; // Due to compatibility at SdrTextObj for now
+ bool mbSuppressSetVisAreaSize:1; // #i118524#
+ mutable bool mbTypeAsked:1;
+ mutable bool mbIsChart:1;
+ bool mbLoadingOLEObjectFailed:1; // New local var to avoid repeated loading if load of OLE2 fails
+ bool mbConnected:1;
+
+ sfx2::SvBaseLink* mpObjectLink;
+ OUString maLinkURL;
+
+ rtl::Reference<SvxUnoShapeModifyListener> mxModifyListener;
+
+ explicit SdrOle2ObjImpl( bool bFrame ) :
+ mbFrame(bFrame),
+ mbSuppressSetVisAreaSize(false),
+ mbTypeAsked(false),
+ mbIsChart(false),
+ mbLoadingOLEObjectFailed(false),
+ mbConnected(false),
+ mpObjectLink(nullptr)
+ {
+ mxObjRef.Lock();
+ }
+
+ SdrOle2ObjImpl( bool bFrame, const svt::EmbeddedObjectRef& rObjRef ) :
+ mxObjRef(rObjRef),
+ mbFrame(bFrame),
+ mbSuppressSetVisAreaSize(false),
+ mbTypeAsked(false),
+ mbIsChart(false),
+ mbLoadingOLEObjectFailed(false),
+ mbConnected(false),
+ mpObjectLink(nullptr)
+ {
+ mxObjRef.Lock();
+ }
+
+ ~SdrOle2ObjImpl()
+ {
+ mxGraphic.reset();
+
+ if (mxModifyListener.is())
+ {
+ mxModifyListener->invalidate();
+ }
+ }
+};
+
+// Predicate determining whether the given OLE is an internal math
+// object
+static bool ImplIsMathObj( const uno::Reference < embed::XEmbeddedObject >& rObjRef )
+{
+ if ( !rObjRef.is() )
+ return false;
+
+ SvGlobalName aClassName( rObjRef->getClassID() );
+ return aClassName == SvGlobalName(SO3_SM_CLASSID_30) ||
+ aClassName == SvGlobalName(SO3_SM_CLASSID_40) ||
+ aClassName == SvGlobalName(SO3_SM_CLASSID_50) ||
+ aClassName == SvGlobalName(SO3_SM_CLASSID_60) ||
+ aClassName == SvGlobalName(SO3_SM_CLASSID);
+}
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrOle2Obj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::OleProperties>(*this);
+}
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrOle2Obj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrOle2Obj>(*this);
+}
+
+void SdrOle2Obj::Init()
+{
+ // Stuff that was done from old SetModel:
+ // #i43086# #i85304 redo the change for charts for the above bugfix, as #i43086# does not occur anymore
+ // so maybe the ImpSetVisAreaSize call can be removed here completely
+ // Nevertheless I leave it in for other objects as I am not sure about the side effects when removing now
+ if(!getSdrModelFromSdrObject().isLocked() && !IsChart())
+ {
+ ImpSetVisAreaSize();
+ }
+
+ ::comphelper::IEmbeddedHelper* pDestPers(getSdrModelFromSdrObject().GetPersist());
+ if(pDestPers && !IsEmptyPresObj())
+ {
+ // object wasn't connected, now it should be
+ Connect_Impl();
+ }
+
+ AddListeners_Impl();
+}
+
+SdrOle2Obj::SdrOle2Obj(
+ SdrModel& rSdrModel,
+ bool bFrame_)
+: SdrRectObj(rSdrModel),
+ mpImpl(new SdrOle2ObjImpl(bFrame_))
+{
+ Init();
+}
+
+SdrOle2Obj::SdrOle2Obj(SdrModel& rSdrModel, SdrOle2Obj const & rSource)
+: SdrRectObj(rSdrModel, rSource),
+ mpImpl(new SdrOle2ObjImpl(/*bFrame*/false))
+{
+ Init();
+
+ // Manually copying bClosedObj attribute
+ SetClosedObj( rSource.IsClosedObj() );
+
+ mpImpl->aPersistName = rSource.mpImpl->aPersistName;
+ mpImpl->maProgName = rSource.mpImpl->maProgName;
+ mpImpl->mbFrame = rSource.mpImpl->mbFrame;
+
+ if (rSource.mpImpl->mxGraphic)
+ {
+ mpImpl->mxGraphic.reset(new Graphic(*rSource.mpImpl->mxGraphic));
+ }
+
+ if( IsEmptyPresObj() )
+ return;
+
+ ::comphelper::IEmbeddedHelper* pDestPers(getSdrModelFromSdrObject().GetPersist());
+ ::comphelper::IEmbeddedHelper* pSrcPers(rSource.getSdrModelFromSdrObject().GetPersist());
+ if( !(pDestPers && pSrcPers) )
+ return;
+
+ DBG_ASSERT( !mpImpl->mxObjRef.is(), "Object already existing!" );
+ comphelper::EmbeddedObjectContainer& rContainer = pSrcPers->getEmbeddedObjectContainer();
+ uno::Reference < embed::XEmbeddedObject > xObj = rContainer.GetEmbeddedObject( mpImpl->aPersistName );
+ if ( xObj.is() )
+ {
+ OUString aTmp;
+ mpImpl->mxObjRef.Assign( pDestPers->getEmbeddedObjectContainer().CopyAndGetEmbeddedObject(
+ rContainer, xObj, aTmp, pSrcPers->getDocumentBaseURL(), pDestPers->getDocumentBaseURL()), rSource.GetAspect());
+ mpImpl->mbTypeAsked = false;
+ mpImpl->aPersistName = aTmp;
+ CheckFileLink_Impl();
+ }
+
+ Connect();
+}
+
+SdrOle2Obj::SdrOle2Obj(
+ SdrModel& rSdrModel,
+ const svt::EmbeddedObjectRef& rNewObjRef,
+ const OUString& rNewObjName,
+ const tools::Rectangle& rNewRect)
+: SdrRectObj(rSdrModel, rNewRect),
+ mpImpl(new SdrOle2ObjImpl(false/*bFrame_*/, rNewObjRef))
+{
+ mpImpl->aPersistName = rNewObjName;
+
+ if (mpImpl->mxObjRef.is() && (mpImpl->mxObjRef->getStatus( GetAspect() ) & embed::EmbedMisc::EMBED_NEVERRESIZE ) )
+ m_bSizProt = true;
+
+ // For math objects, set closed state to transparent
+ SetClosedObj(!ImplIsMathObj( mpImpl->mxObjRef.GetObject() ));
+
+ Init();
+}
+
+OUString SdrOle2Obj::GetStyleString()
+{
+ OUString strStyle;
+ if (mpImpl->mxObjRef.is() && mpImpl->mxObjRef.IsChart())
+ {
+ strStyle = mpImpl->mxObjRef.GetChartType();
+ }
+ return strStyle;
+}
+
+SdrOle2Obj::~SdrOle2Obj()
+{
+ if ( mpImpl->mbConnected )
+ Disconnect();
+
+ DisconnectFileLink_Impl();
+
+ if (mpImpl->mxLightClient)
+ {
+ mpImpl->mxLightClient->disconnect();
+ mpImpl->mxLightClient.clear();
+ }
+}
+
+void SdrOle2Obj::SetAspect( sal_Int64 nAspect )
+{
+ mpImpl->mxObjRef.SetViewAspect( nAspect );
+}
+
+const svt::EmbeddedObjectRef& SdrOle2Obj::getEmbeddedObjectRef() const
+{
+ return mpImpl->mxObjRef;
+}
+
+sal_Int64 SdrOle2Obj::GetAspect() const
+{
+ return mpImpl->mxObjRef.GetViewAspect();
+}
+
+bool SdrOle2Obj::isInplaceActive() const
+{
+ return mpImpl->mxObjRef.is() && embed::EmbedStates::INPLACE_ACTIVE == mpImpl->mxObjRef->getCurrentState();
+}
+
+bool SdrOle2Obj::isUiActive() const
+{
+ return mpImpl->mxObjRef.is() && embed::EmbedStates::UI_ACTIVE == mpImpl->mxObjRef->getCurrentState();
+}
+
+void SdrOle2Obj::SetGraphic(const Graphic& rGrf)
+{
+ // only for setting a preview graphic
+ mpImpl->mxGraphic.reset(new Graphic(rGrf));
+
+ SetChanged();
+ BroadcastObjectChange();
+}
+
+void SdrOle2Obj::ClearGraphic()
+{
+ mpImpl->mxGraphic.reset();
+
+ SetChanged();
+ BroadcastObjectChange();
+}
+
+void SdrOle2Obj::SetProgName( const OUString& rName )
+{
+ mpImpl->maProgName = rName;
+}
+
+const OUString& SdrOle2Obj::GetProgName() const
+{
+ return mpImpl->maProgName;
+}
+
+bool SdrOle2Obj::IsEmpty() const
+{
+ return !mpImpl->mxObjRef.is();
+}
+
+void SdrOle2Obj::Connect(SvxOle2Shape* pCreator)
+{
+ if( IsEmptyPresObj() )
+ return;
+
+ if( mpImpl->mbConnected )
+ {
+ // currently there are situations where it seems to be unavoidable to have multiple connects
+ // changing this would need a larger code rewrite, so for now I remove the assertion
+ // OSL_FAIL("Connect() called on connected object!");
+ return;
+ }
+
+ Connect_Impl(pCreator);
+ AddListeners_Impl();
+}
+
+bool SdrOle2Obj::UpdateLinkURL_Impl()
+{
+ bool bResult = false;
+
+ if ( mpImpl->mpObjectLink )
+ {
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
+
+ if ( pLinkManager )
+ {
+ OUString aNewLinkURL;
+ sfx2::LinkManager::GetDisplayNames( mpImpl->mpObjectLink, nullptr, &aNewLinkURL );
+ if ( !aNewLinkURL.equalsIgnoreAsciiCase( mpImpl->maLinkURL ) )
+ {
+ GetObjRef_Impl();
+ uno::Reference<embed::XCommonEmbedPersist> xPersObj( mpImpl->mxObjRef.GetObject(), uno::UNO_QUERY );
+ OSL_ENSURE( xPersObj.is(), "The object must exist!" );
+ if ( xPersObj.is() )
+ {
+ try
+ {
+ sal_Int32 nCurState = mpImpl->mxObjRef->getCurrentState();
+ if ( nCurState != embed::EmbedStates::LOADED )
+ mpImpl->mxObjRef->changeState(embed::EmbedStates::LOADED);
+
+ // TODO/LATER: there should be possible to get current mediadescriptor settings from the object
+ uno::Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
+ "URL", aNewLinkURL) };
+ xPersObj->reload( aArgs, uno::Sequence< beans::PropertyValue >() );
+
+ mpImpl->maLinkURL = aNewLinkURL;
+ bResult = true;
+
+ if ( nCurState != embed::EmbedStates::LOADED )
+ mpImpl->mxObjRef->changeState(nCurState);
+ }
+ catch( css::uno::Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::UpdateLinkURL_Impl()" );
+ }
+ }
+
+ if ( !bResult )
+ {
+ // TODO/LATER: return the old name to the link manager, is it possible?
+ }
+ }
+ }
+ }
+
+ return bResult;
+}
+
+void SdrOle2Obj::BreakFileLink_Impl()
+{
+ uno::Reference<document::XStorageBasedDocument> xDoc(getSdrModelFromSdrObject().getUnoModel(), uno::UNO_QUERY);
+
+ if ( !xDoc.is() )
+ return;
+
+ uno::Reference< embed::XStorage > xStorage = xDoc->getDocumentStorage();
+ if ( !xStorage.is() )
+ return;
+
+ try
+ {
+ uno::Reference< embed::XLinkageSupport > xLinkSupport( mpImpl->mxObjRef.GetObject(), uno::UNO_QUERY_THROW );
+ xLinkSupport->breakLink( xStorage, mpImpl->aPersistName );
+ DisconnectFileLink_Impl();
+ mpImpl->maLinkURL.clear();
+ }
+ catch( css::uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::BreakFileLink_Impl()" );
+ }
+}
+
+void SdrOle2Obj::DisconnectFileLink_Impl()
+{
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
+
+ if ( pLinkManager && mpImpl->mpObjectLink )
+ {
+ pLinkManager->Remove( mpImpl->mpObjectLink );
+ mpImpl->mpObjectLink = nullptr;
+ }
+}
+
+void SdrOle2Obj::CheckFileLink_Impl()
+{
+ if (!mpImpl->mxObjRef.GetObject().is() || mpImpl->mpObjectLink)
+ return;
+
+ try
+ {
+ uno::Reference<embed::XEmbeddedObject> xObject = mpImpl->mxObjRef.GetObject();
+ if (!xObject)
+ return;
+
+ bool bIFrame = false;
+
+ OUString aLinkURL;
+ uno::Reference<embed::XLinkageSupport> xLinkSupport(xObject, uno::UNO_QUERY);
+ if (xLinkSupport)
+ {
+ if (xLinkSupport->isLink())
+ aLinkURL = xLinkSupport->getLinkURL();
+ }
+ else
+ {
+ // get IFrame (Floating Frames) listed and updatable from the
+ // manage links dialog
+ SvGlobalName aClassId(xObject->getClassID());
+ if (aClassId == SvGlobalName(SO3_IFRAME_CLASSID))
+ {
+ uno::Reference<beans::XPropertySet> xSet(xObject->getComponent(), uno::UNO_QUERY);
+ if (xSet.is())
+ xSet->getPropertyValue("FrameURL") >>= aLinkURL;
+ bIFrame = true;
+ }
+ }
+
+ if (!aLinkURL.isEmpty()) // this is a file link so the model link manager should handle it
+ {
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
+
+ if ( pLinkManager )
+ {
+ SdrEmbedObjectLink* pEmbedObjectLink = nullptr;
+ if (!bIFrame)
+ {
+ pEmbedObjectLink = new SdrEmbedObjectLink(this);
+ mpImpl->mpObjectLink = pEmbedObjectLink;
+ }
+ else
+ mpImpl->mpObjectLink = new SdrIFrameLink(this);
+ mpImpl->maLinkURL = aLinkURL;
+ pLinkManager->InsertFileLink( *mpImpl->mpObjectLink, sfx2::SvBaseLinkObjectType::ClientOle, aLinkURL );
+ if (pEmbedObjectLink)
+ pEmbedObjectLink->Connect();
+ }
+ }
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "SdrOle2Obj::CheckFileLink_Impl()");
+ }
+}
+
+void SdrOle2Obj::Connect_Impl(SvxOle2Shape* pCreator)
+{
+ if(mpImpl->aPersistName.isEmpty() )
+ return;
+
+ try
+ {
+ ::comphelper::IEmbeddedHelper* pPers(getSdrModelFromSdrObject().GetPersist());
+
+ if ( pPers )
+ {
+ comphelper::EmbeddedObjectContainer& rContainer = pPers->getEmbeddedObjectContainer();
+
+ if ( !rContainer.HasEmbeddedObject( mpImpl->aPersistName )
+ || ( mpImpl->mxObjRef.is() && !rContainer.HasEmbeddedObject( mpImpl->mxObjRef.GetObject() ) ) )
+ {
+ // object not known to container document
+ // No object -> disaster!
+ DBG_ASSERT( mpImpl->mxObjRef.is(), "No object in connect!");
+ if ( mpImpl->mxObjRef.is() )
+ {
+ // object came from the outside, now add it to the container
+ OUString aTmp;
+ rContainer.InsertEmbeddedObject( mpImpl->mxObjRef.GetObject(), aTmp );
+ mpImpl->aPersistName = aTmp;
+ }
+ }
+ else if ( !mpImpl->mxObjRef.is() )
+ {
+ mpImpl->mxObjRef.Assign( rContainer.GetEmbeddedObject( mpImpl->aPersistName ), mpImpl->mxObjRef.GetViewAspect() );
+ mpImpl->mbTypeAsked = false;
+ }
+
+ if ( mpImpl->mxObjRef.GetObject().is() )
+ {
+ mpImpl->mxObjRef.AssignToContainer( &rContainer, mpImpl->aPersistName );
+ mpImpl->mbConnected = true;
+ mpImpl->mxObjRef.Lock();
+ }
+ }
+
+ if (pCreator)
+ {
+ OUString sFrameURL(pCreator->GetAndClearInitialFrameURL());
+ if (!sFrameURL.isEmpty() && svt::EmbeddedObjectRef::TryRunningState(mpImpl->mxObjRef.GetObject()))
+ {
+ uno::Reference<beans::XPropertySet> xSet(mpImpl->mxObjRef->getComponent(), uno::UNO_QUERY);
+ if (xSet.is())
+ xSet->setPropertyValue("FrameURL", uno::Any(sFrameURL));
+ }
+ }
+
+ if ( mpImpl->mxObjRef.is() )
+ {
+ if ( !mpImpl->mxLightClient.is() )
+ mpImpl->mxLightClient = new SdrLightEmbeddedClient_Impl( this );
+
+ mpImpl->mxObjRef->addStateChangeListener( mpImpl->mxLightClient );
+ mpImpl->mxObjRef->addEventListener( mpImpl->mxLightClient );
+
+ if ( mpImpl->mxObjRef->getCurrentState() != embed::EmbedStates::LOADED )
+ GetSdrGlobalData().GetOLEObjCache().InsertObj(this);
+
+ CheckFileLink_Impl();
+
+ uno::Reference< container::XChild > xChild( mpImpl->mxObjRef.GetObject(), uno::UNO_QUERY );
+ if( xChild.is() )
+ {
+ uno::Reference< uno::XInterface > xParent( getSdrModelFromSdrObject().getUnoModel());
+ if( xParent.is())
+ xChild->setParent( getSdrModelFromSdrObject().getUnoModel() );
+ }
+
+ }
+ }
+ catch( css::uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::Connect_Impl()" );
+ }
+}
+
+void SdrOle2Obj::ObjectLoaded()
+{
+ AddListeners_Impl();
+}
+
+void SdrOle2Obj::AddListeners_Impl()
+{
+ if( !(mpImpl->mxObjRef.is() && mpImpl->mxObjRef->getCurrentState() != embed::EmbedStates::LOADED) )
+ return;
+
+ // register modify listener
+ if (!mpImpl->mxModifyListener.is())
+ {
+ mpImpl->mxModifyListener = new SvxUnoShapeModifyListener(this);
+ }
+
+ uno::Reference< util::XModifyBroadcaster > xBC( getXModel(), uno::UNO_QUERY );
+ if (xBC.is())
+ {
+ xBC->addModifyListener( mpImpl->mxModifyListener );
+ }
+}
+
+void SdrOle2Obj::Disconnect()
+{
+ if( IsEmptyPresObj() )
+ return;
+
+ if( !mpImpl->mbConnected )
+ {
+ OSL_FAIL("Disconnect() called on disconnected object!");
+ return;
+ }
+
+ RemoveListeners_Impl();
+ Disconnect_Impl();
+}
+
+void SdrOle2Obj::RemoveListeners_Impl()
+{
+ if ( !mpImpl->mxObjRef.is() || mpImpl->aPersistName.isEmpty() )
+ return;
+
+ try
+ {
+ sal_Int32 nState = mpImpl->mxObjRef->getCurrentState();
+ if ( nState != embed::EmbedStates::LOADED )
+ {
+ uno::Reference< util::XModifyBroadcaster > xBC( getXModel(), uno::UNO_QUERY );
+ if (xBC.is() && mpImpl->mxModifyListener.is())
+ {
+ xBC->removeModifyListener( mpImpl->mxModifyListener );
+ }
+ }
+ }
+ catch( css::uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::RemoveListeners_Impl()" );
+ }
+}
+
+void SdrOle2Obj::Disconnect_Impl()
+{
+ try
+ {
+ if ( !mpImpl->aPersistName.isEmpty() )
+ {
+ if( getSdrModelFromSdrObject().IsInDestruction() )
+ {
+ // TODO/LATER: here we must assume that the destruction of the model is enough to make clear that we will not
+ // remove the object from the container, even if the DrawingObject itself is not destroyed (unfortunately this
+ // There is no real need to do the following removing of the object from the container
+ // in case the model has correct persistence, but in case of problems such a removing
+ // would make the behavior of the office more stable
+
+ comphelper::EmbeddedObjectContainer* pContainer = mpImpl->mxObjRef.GetContainer();
+ if ( pContainer )
+ {
+ pContainer->CloseEmbeddedObject( mpImpl->mxObjRef.GetObject() );
+ mpImpl->mxObjRef.AssignToContainer( nullptr, mpImpl->aPersistName );
+ }
+
+ // happens later than the destruction of the model, so we can't assert that).
+ //DBG_ASSERT( bInDestruction, "Model is destroyed, but not me?!" );
+ //TODO/LATER: should be make sure that the ObjectShell also forgets the object, because we will close it soon?
+ /*
+ uno::Reference < util::XCloseable > xClose( xObjRef, uno::UNO_QUERY );
+ if ( xClose.is() )
+ {
+ try
+ {
+ xClose->close( true );
+ }
+ catch ( util::CloseVetoException& )
+ {
+ // there's still someone who needs the object!
+ }
+ }
+
+ xObjRef = NULL;*/
+ }
+ else if ( mpImpl->mxObjRef.is() )
+ {
+ if ( getSdrModelFromSdrObject().getUnoModel().is() )
+ {
+ // remove object, but don't close it (that's up to someone else)
+ comphelper::EmbeddedObjectContainer* pContainer = mpImpl->mxObjRef.GetContainer();
+ if ( pContainer )
+ {
+ pContainer->RemoveEmbeddedObject( mpImpl->mxObjRef.GetObject() );
+
+ // TODO/LATER: mpImpl->aPersistName contains outdated information, to keep it updated
+ // it should be returned from RemoveEmbeddedObject call. Currently it is no problem,
+ // since no container is adjusted, actually the empty string could be provided as a name here
+ mpImpl->mxObjRef.AssignToContainer( nullptr, mpImpl->aPersistName );
+ }
+
+ DisconnectFileLink_Impl();
+ }
+ }
+ }
+
+ if ( mpImpl->mxObjRef.is() && mpImpl->mxLightClient.is() )
+ {
+ mpImpl->mxObjRef->removeStateChangeListener ( mpImpl->mxLightClient );
+ mpImpl->mxObjRef->removeEventListener( mpImpl->mxLightClient );
+ mpImpl->mxObjRef->setClientSite( nullptr );
+
+ GetSdrGlobalData().GetOLEObjCache().RemoveObj(this);
+ }
+ }
+ catch( css::uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::Disconnect_Impl()" );
+ }
+
+ mpImpl->mbConnected = false;
+}
+
+SdrObjectUniquePtr SdrOle2Obj::createSdrGrafObjReplacement(bool bAddText) const
+{
+ const Graphic* pOLEGraphic = GetGraphic();
+
+ if(pOLEGraphic)
+ {
+ // #i118485# allow creating a SdrGrafObj representation
+ SdrGrafObj* pClone = new SdrGrafObj(
+ getSdrModelFromSdrObject(),
+ *pOLEGraphic);
+
+ // copy transformation
+ basegfx::B2DHomMatrix aMatrix;
+ basegfx::B2DPolyPolygon aPolyPolygon;
+
+ TRGetBaseGeometry(aMatrix, aPolyPolygon);
+ pClone->TRSetBaseGeometry(aMatrix, aPolyPolygon);
+
+ // copy all attributes to support graphic styles for OLEs
+ pClone->SetStyleSheet(GetStyleSheet(), false);
+ pClone->SetMergedItemSet(GetMergedItemSet());
+
+ if(bAddText)
+ {
+ // #i118485# copy text (Caution! Model needed, as guaranteed in aw080)
+ OutlinerParaObject* pOPO = GetOutlinerParaObject();
+
+ if(pOPO)
+ {
+ pClone->NbcSetOutlinerParaObject(*pOPO);
+ }
+ }
+
+ return SdrObjectUniquePtr(pClone);
+ }
+ else
+ {
+ // #i100710# pOLEGraphic may be zero (no visualisation available),
+ // so we need to use the OLE replacement graphic
+ SdrRectObj* pClone = new SdrRectObj(
+ getSdrModelFromSdrObject(),
+ GetSnapRect());
+
+ // gray outline
+ pClone->SetMergedItem(XLineStyleItem(css::drawing::LineStyle_SOLID));
+ const svtools::ColorConfig aColorConfig;
+ const svtools::ColorConfigValue aColor(aColorConfig.GetColorValue(svtools::OBJECTBOUNDARIES));
+ pClone->SetMergedItem(XLineColorItem(OUString(), aColor.nColor));
+
+ // bitmap fill
+ pClone->SetMergedItem(XFillStyleItem(drawing::FillStyle_BITMAP));
+ pClone->SetMergedItem(XFillBitmapItem(OUString(), GetEmptyOLEReplacementGraphic()));
+ pClone->SetMergedItem(XFillBmpTileItem(false));
+ pClone->SetMergedItem(XFillBmpStretchItem(false));
+
+ return SdrObjectUniquePtr(pClone);
+ }
+}
+
+SdrObjectUniquePtr SdrOle2Obj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ // #i118485# missing converter added
+ SdrObjectUniquePtr pRetval = createSdrGrafObjReplacement(true);
+
+ if(pRetval)
+ {
+ return pRetval->DoConvertToPolyObj(bBezier, bAddText);
+ }
+
+ return nullptr;
+}
+
+void SdrOle2Obj::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ const bool bRemove(pNewPage == nullptr && pOldPage != nullptr);
+ const bool bInsert(pNewPage != nullptr && pOldPage == nullptr);
+
+ if (bRemove && mpImpl->mbConnected )
+ {
+ Disconnect();
+ }
+
+ // call parent
+ SdrRectObj::handlePageChange(pOldPage, pNewPage);
+
+ if (bInsert && !mpImpl->mbConnected )
+ {
+ Connect();
+ }
+}
+
+void SdrOle2Obj::SetObjRef( const css::uno::Reference < css::embed::XEmbeddedObject >& rNewObjRef )
+{
+ DBG_ASSERT( !rNewObjRef.is() || !mpImpl->mxObjRef.GetObject().is(), "SetObjRef called on already initialized object!");
+ if( rNewObjRef == mpImpl->mxObjRef.GetObject() )
+ return;
+
+ // the caller of the method is responsible to control the old object, it will not be closed here
+ // Otherwise WW8 import crashes because it transfers control to OLENode by this method
+ if ( mpImpl->mxObjRef.GetObject().is() )
+ mpImpl->mxObjRef.Lock( false );
+
+ // avoid removal of object in Disconnect! It is definitely a HACK to call SetObjRef(0)!
+ // This call will try to close the objects; so if anybody else wants to keep it, it must be locked by a CloseListener
+ mpImpl->mxObjRef.Clear();
+
+ if ( mpImpl->mbConnected )
+ Disconnect();
+
+ mpImpl->mxObjRef.Assign( rNewObjRef, GetAspect() );
+ mpImpl->mbTypeAsked = false;
+
+ if ( mpImpl->mxObjRef.is() )
+ {
+ mpImpl->mxGraphic.reset();
+
+ if ( mpImpl->mxObjRef->getStatus( GetAspect() ) & embed::EmbedMisc::EMBED_NEVERRESIZE )
+ SetResizeProtect(true);
+
+ // For math objects, set closed state to transparent
+ SetClosedObj(!ImplIsMathObj( rNewObjRef ));
+
+ Connect();
+ }
+
+ SetChanged();
+ BroadcastObjectChange();
+}
+
+void SdrOle2Obj::SetClosedObj( bool bIsClosed )
+{
+ // TODO/LATER: do we still need this hack?
+ // Allow changes to the closed state of OLE objects
+ m_bClosedObj = bIsClosed;
+}
+
+SdrObjectUniquePtr SdrOle2Obj::getFullDragClone() const
+{
+ // #i118485# use central replacement generator
+ return createSdrGrafObjReplacement(false);
+}
+
+void SdrOle2Obj::SetPersistName( const OUString& rPersistName, SvxOle2Shape* pCreator )
+{
+ DBG_ASSERT( mpImpl->aPersistName.isEmpty(), "Persist name changed!");
+
+ mpImpl->aPersistName = rPersistName;
+ mpImpl->mbLoadingOLEObjectFailed = false;
+
+ Connect(pCreator);
+ SetChanged();
+}
+
+void SdrOle2Obj::AbandonObject()
+{
+ mpImpl->aPersistName.clear();
+ mpImpl->mbLoadingOLEObjectFailed = false;
+ SetObjRef(nullptr);
+}
+
+const OUString& SdrOle2Obj::GetPersistName() const
+{
+ return mpImpl->aPersistName;
+}
+
+void SdrOle2Obj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ // #i118485# Allowing much more attributes for OLEs
+ rInfo.bRotateFreeAllowed = true;
+ rInfo.bRotate90Allowed = true;
+ rInfo.bMirrorFreeAllowed = true;
+ rInfo.bMirror45Allowed = true;
+ rInfo.bMirror90Allowed = true;
+ rInfo.bTransparenceAllowed = true;
+ rInfo.bShearAllowed = true;
+ rInfo.bEdgeRadiusAllowed = false;
+ rInfo.bNoOrthoDesired = false;
+ rInfo.bCanConvToPath = true;
+ rInfo.bCanConvToPoly = true;
+ rInfo.bCanConvToPathLineToArea = false;
+ rInfo.bCanConvToPolyLineToArea = false;
+ rInfo.bCanConvToContour = true;
+}
+
+SdrObjKind SdrOle2Obj::GetObjIdentifier() const
+{
+ return mpImpl->mbFrame ? SdrObjKind::OLEPluginFrame : SdrObjKind::OLE2;
+}
+
+OUString SdrOle2Obj::TakeObjNameSingul() const
+{
+ OUStringBuffer sName(SvxResId(mpImpl->mbFrame ? STR_ObjNameSingulFrame : STR_ObjNameSingulOLE2));
+
+ const OUString aName(GetName());
+
+ if (!aName.isEmpty())
+ {
+ sName.append(" '");
+ sName.append(aName);
+ sName.append('\'');
+ }
+
+ return sName.makeStringAndClear();
+}
+
+OUString SdrOle2Obj::TakeObjNamePlural() const
+{
+ return SvxResId(mpImpl->mbFrame ? STR_ObjNamePluralFrame : STR_ObjNamePluralOLE2);
+}
+
+SdrOle2Obj* SdrOle2Obj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrOle2Obj(rTargetModel, *this);
+}
+
+void SdrOle2Obj::ImpSetVisAreaSize()
+{
+ // #i118524# do not again set VisAreaSize when the call comes from OLE client (e.g. ObjectAreaChanged)
+ if (mpImpl->mbSuppressSetVisAreaSize)
+ return;
+
+ // currently there is no need to recalculate scaling for iconified objects
+ // TODO/LATER: it might be needed in future when it is possible to change the icon
+ if ( GetAspect() == embed::Aspects::MSOLE_ICON )
+ return;
+
+ // the object area of an embedded object was changed, e.g. by user interaction an a selected object
+ GetObjRef();
+ if (!mpImpl->mxObjRef.is())
+ return;
+
+ sal_Int64 nMiscStatus = mpImpl->mxObjRef->getStatus( GetAspect() );
+
+ // the client is required to get access to scaling
+ SfxInPlaceClient* pClient(
+ SfxInPlaceClient::GetClient(
+ dynamic_cast<SfxObjectShell*>(
+ getSdrModelFromSdrObject().GetPersist()),
+ mpImpl->mxObjRef.GetObject()));
+ const bool bHasOwnClient(
+ mpImpl->mxLightClient.is() &&
+ mpImpl->mxObjRef->getClientSite() == uno::Reference< embed::XEmbeddedClient >( mpImpl->mxLightClient ) );
+
+ if ( pClient || bHasOwnClient )
+ {
+ // TODO: IMHO we need to do similar things when object is UIActive or OutplaceActive?!
+ if ( ((nMiscStatus & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE) &&
+ svt::EmbeddedObjectRef::TryRunningState( mpImpl->mxObjRef.GetObject() ))
+ || mpImpl->mxObjRef->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE
+ )
+ {
+ Fraction aScaleWidth;
+ Fraction aScaleHeight;
+ if ( pClient )
+ {
+ aScaleWidth = pClient->GetScaleWidth();
+ aScaleHeight = pClient->GetScaleHeight();
+ }
+ else
+ {
+ aScaleWidth = mpImpl->mxLightClient->GetScaleWidth();
+ aScaleHeight = mpImpl->mxLightClient->GetScaleHeight();
+ }
+
+ // The object wants to resize itself (f.e. Chart wants to recalculate the layout)
+ // or object is inplace active and so has a window that must be resized also
+ // In these cases the change in the object area size will be reflected in a change of the
+ // objects' visual area. The scaling will not change, but it might exist already and must
+ // be used in calculations
+ MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( mpImpl->mxObjRef->getMapUnit( GetAspect() ) );
+ Size aVisSize;
+ if (sal_Int32(aScaleWidth) != 0 && sal_Int32(aScaleHeight) != 0) // avoid div by zero
+ aVisSize = Size( static_cast<tools::Long>( Fraction( maRect.GetWidth() ) / aScaleWidth ),
+ static_cast<tools::Long>( Fraction( maRect.GetHeight() ) / aScaleHeight ) );
+
+ aVisSize = OutputDevice::LogicToLogic(
+ aVisSize,
+ MapMode(getSdrModelFromSdrObject().GetScaleUnit()),
+ MapMode(aMapUnit));
+ awt::Size aSz;
+ aSz.Width = aVisSize.Width();
+ aSz.Height = aVisSize.Height();
+ mpImpl->mxObjRef->setVisualAreaSize( GetAspect(), aSz );
+
+ try
+ {
+ aSz = mpImpl->mxObjRef->getVisualAreaSize( GetAspect() );
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {}
+
+ tools::Rectangle aAcceptedVisArea;
+ aAcceptedVisArea.SetSize( Size( static_cast<tools::Long>( Fraction( tools::Long( aSz.Width ) ) * aScaleWidth ),
+ static_cast<tools::Long>( Fraction( tools::Long( aSz.Height ) ) * aScaleHeight ) ) );
+ if (aVisSize != aAcceptedVisArea.GetSize())
+ {
+ // server changed VisArea to its liking and the VisArea is different than the suggested one
+ // store the new value as given by the object
+ MapUnit aNewMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( mpImpl->mxObjRef->getMapUnit( GetAspect() ) );
+ maRect.SetSize(
+ OutputDevice::LogicToLogic(
+ aAcceptedVisArea.GetSize(),
+ MapMode(aNewMapUnit),
+ MapMode(getSdrModelFromSdrObject().GetScaleUnit())));
+ }
+
+ // make the new object area known to the client
+ // compared to the "else" branch aRect might have been changed by the object and no additional scaling was applied
+ // WHY this -> OSL_ASSERT( pClient );
+ if( pClient )
+ pClient->SetObjArea(maRect);
+
+ // we need a new replacement image as the object has resized itself
+
+ //#i79578# don't request a new replacement image for charts to often
+ //a chart sends a modified call to the framework if it was changed
+ //thus the replacement update is already handled there
+ if( !IsChart() )
+ mpImpl->mxObjRef.UpdateReplacement();
+ }
+ else
+ {
+ // The object isn't active and does not want to resize itself so the changed object area size
+ // will be reflected in a changed object scaling
+ Fraction aScaleWidth;
+ Fraction aScaleHeight;
+ Size aObjAreaSize;
+ if ( CalculateNewScaling( aScaleWidth, aScaleHeight, aObjAreaSize ) )
+ {
+ if ( pClient )
+ {
+ tools::Rectangle aScaleRect(maRect.TopLeft(), aObjAreaSize);
+ pClient->SetObjAreaAndScale( aScaleRect, aScaleWidth, aScaleHeight);
+ }
+ else
+ {
+ mpImpl->mxLightClient->SetSizeScale( aScaleWidth, aScaleHeight );
+ }
+ }
+ }
+ }
+ else if( (nMiscStatus & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE) &&
+ svt::EmbeddedObjectRef::TryRunningState( mpImpl->mxObjRef.GetObject() ) )
+ {
+ //also handle not sfx based ole objects e.g. charts
+ //#i83860# resizing charts in impress distorts fonts
+ uno::Reference< embed::XVisualObject > xVisualObject( getXModel(), uno::UNO_QUERY );
+ if( xVisualObject.is() )
+ {
+ const MapUnit aMapUnit(
+ VCLUnoHelper::UnoEmbed2VCLMapUnit(
+ mpImpl->mxObjRef->getMapUnit(GetAspect())));
+ const Point aTL( maRect.TopLeft() );
+ const Point aBR( maRect.BottomRight() );
+ const Point aTL2(
+ OutputDevice::LogicToLogic(
+ aTL,
+ MapMode(getSdrModelFromSdrObject().GetScaleUnit()),
+ MapMode(aMapUnit)));
+ const Point aBR2(
+ OutputDevice::LogicToLogic(
+ aBR,
+ MapMode(getSdrModelFromSdrObject().GetScaleUnit()),
+ MapMode(aMapUnit)));
+ const tools::Rectangle aNewRect(
+ aTL2,
+ aBR2);
+
+ xVisualObject->setVisualAreaSize(
+ GetAspect(),
+ awt::Size(
+ aNewRect.GetWidth(),
+ aNewRect.GetHeight()));
+ }
+ }
+}
+
+void SdrOle2Obj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ if(!getSdrModelFromSdrObject().isLocked())
+ {
+ GetObjRef();
+
+ if ( mpImpl->mxObjRef.is() && ( mpImpl->mxObjRef->getStatus( GetAspect() ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE ) )
+ {
+ // if the object needs recompose on resize
+ // the client site should be created before the resize will take place
+ // check whether there is no client site and create it if necessary
+ AddOwnLightClient();
+ }
+ }
+
+ SdrRectObj::NbcResize(rRef,xFact,yFact);
+
+ if( !getSdrModelFromSdrObject().isLocked() )
+ ImpSetVisAreaSize();
+}
+
+void SdrOle2Obj::SetGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrRectObj::SetGeoData(rGeo);
+
+ if( !getSdrModelFromSdrObject().isLocked() )
+ ImpSetVisAreaSize();
+}
+
+void SdrOle2Obj::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ SdrRectObj::NbcSetSnapRect(rRect);
+
+ if( !getSdrModelFromSdrObject().isLocked() )
+ ImpSetVisAreaSize();
+
+ if ( mpImpl->mxObjRef.is() && IsChart() )
+ {
+ //#i103460# charts do not necessarily have an own size within ODF files,
+ //for this case they need to use the size settings from the surrounding frame,
+ //which is made available with this method as there is no other way
+ mpImpl->mxObjRef.SetDefaultSizeForChart( Size( rRect.GetWidth(), rRect.GetHeight() ) );
+ }
+}
+
+void SdrOle2Obj::NbcSetLogicRect(const tools::Rectangle& rRect)
+{
+ SdrRectObj::NbcSetLogicRect(rRect);
+
+ if( !getSdrModelFromSdrObject().isLocked() )
+ ImpSetVisAreaSize();
+}
+
+const Graphic* SdrOle2Obj::GetGraphic() const
+{
+ if ( mpImpl->mxObjRef.is() )
+ return mpImpl->mxObjRef.GetGraphic();
+ return mpImpl->mxGraphic.get();
+}
+
+void SdrOle2Obj::GetNewReplacement()
+{
+ if ( mpImpl->mxObjRef.is() )
+ mpImpl->mxObjRef.UpdateReplacement();
+}
+
+Size SdrOle2Obj::GetOrigObjSize( MapMode const * pTargetMapMode ) const
+{
+ return mpImpl->mxObjRef.GetSize( pTargetMapMode );
+}
+
+void SdrOle2Obj::setSuppressSetVisAreaSize( bool bNew )
+{
+ mpImpl->mbSuppressSetVisAreaSize = bNew;
+}
+
+void SdrOle2Obj::NbcMove(const Size& rSize)
+{
+ SdrRectObj::NbcMove(rSize);
+
+ if( !getSdrModelFromSdrObject().isLocked() )
+ ImpSetVisAreaSize();
+}
+
+bool SdrOle2Obj::CanUnloadRunningObj( const uno::Reference< embed::XEmbeddedObject >& xObj, sal_Int64 nAspect )
+{
+ uno::Reference<embed::XEmbedPersist2> xPersist(xObj, uno::UNO_QUERY);
+ if (xPersist.is())
+ {
+ if (!xPersist->isStored())
+ // It doesn't have persistent storage. We can't unload this.
+ return false;
+ }
+
+ bool bResult = false;
+
+ sal_Int32 nState = xObj->getCurrentState();
+ if ( nState == embed::EmbedStates::LOADED )
+ {
+ // the object is already unloaded
+ bResult = true;
+ }
+ else
+ {
+ uno::Reference < util::XModifiable > xModifiable( xObj->getComponent(), uno::UNO_QUERY );
+ if ( !xModifiable.is() )
+ bResult = true;
+ else
+ {
+ sal_Int64 nMiscStatus = xObj->getStatus( nAspect );
+
+ if ( embed::EmbedMisc::MS_EMBED_ALWAYSRUN != ( nMiscStatus & embed::EmbedMisc::MS_EMBED_ALWAYSRUN ) &&
+ embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY != ( nMiscStatus & embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY ) &&
+ !( xModifiable.is() && xModifiable->isModified() ) &&
+ !( nState == embed::EmbedStates::INPLACE_ACTIVE || nState == embed::EmbedStates::UI_ACTIVE || nState == embed::EmbedStates::ACTIVE ) )
+ {
+ bResult = true;
+ }
+ }
+ }
+
+ return bResult;
+}
+
+bool SdrOle2Obj::Unload( const uno::Reference< embed::XEmbeddedObject >& xObj, sal_Int64 nAspect )
+{
+ bool bResult = false;
+
+ if ( CanUnloadRunningObj( xObj, nAspect ) )
+ {
+ try
+ {
+ xObj->changeState( embed::EmbedStates::LOADED );
+ bResult = true;
+ }
+ catch( css::uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::Unload()" );
+ }
+ }
+
+ return bResult;
+}
+
+bool SdrOle2Obj::Unload()
+{
+ if (!mpImpl->mxObjRef.is())
+ // Already unloaded.
+ return true;
+
+ return Unload(mpImpl->mxObjRef.GetObject(), GetAspect());
+}
+
+void SdrOle2Obj::GetObjRef_Impl()
+{
+ if ( !mpImpl->mxObjRef.is() && !mpImpl->aPersistName.isEmpty() && getSdrModelFromSdrObject().GetPersist() )
+ {
+ // Only try loading if it did not went wrong up to now
+ if(!mpImpl->mbLoadingOLEObjectFailed)
+ {
+ mpImpl->mxObjRef.Assign(
+ getSdrModelFromSdrObject().GetPersist()->getEmbeddedObjectContainer().GetEmbeddedObject(mpImpl->aPersistName),
+ GetAspect());
+ mpImpl->mbTypeAsked = false;
+ CheckFileLink_Impl();
+
+ // If loading of OLE object failed, remember that to not invoke an endless
+ // loop trying to load it again and again.
+ if( mpImpl->mxObjRef.is() )
+ {
+ mpImpl->mbLoadingOLEObjectFailed = true;
+ }
+
+ // For math objects, set closed state to transparent
+ SetClosedObj(!ImplIsMathObj( mpImpl->mxObjRef.GetObject() ));
+ }
+
+ if ( mpImpl->mxObjRef.is() )
+ {
+ if( !IsEmptyPresObj() )
+ {
+ // remember modified status of model
+ const bool bWasChanged(getSdrModelFromSdrObject().IsChanged());
+
+ // perhaps preview not valid anymore
+ // This line changes the modified state of the model
+ ClearGraphic();
+
+ // if status was not set before, force it back
+ // to not set, so that SetGraphic(0) above does not
+ // set the modified state of the model.
+ if(!bWasChanged && getSdrModelFromSdrObject().IsChanged())
+ {
+ getSdrModelFromSdrObject().SetChanged( false );
+ }
+ }
+ }
+
+ if ( mpImpl->mxObjRef.is() )
+ Connect();
+ }
+
+ if ( mpImpl->mbConnected )
+ {
+ // move object to first position in cache
+ GetSdrGlobalData().GetOLEObjCache().InsertObj(this);
+ }
+}
+
+uno::Reference < embed::XEmbeddedObject > const & SdrOle2Obj::GetObjRef() const
+{
+ const_cast<SdrOle2Obj*>(this)->GetObjRef_Impl();
+ return mpImpl->mxObjRef.GetObject();
+}
+
+uno::Reference < embed::XEmbeddedObject > const & SdrOle2Obj::GetObjRef_NoInit() const
+{
+ return mpImpl->mxObjRef.GetObject();
+}
+
+uno::Reference< frame::XModel > SdrOle2Obj::getXModel() const
+{
+ if (svt::EmbeddedObjectRef::TryRunningState(GetObjRef()))
+ return uno::Reference< frame::XModel >( mpImpl->mxObjRef->getComponent(), uno::UNO_QUERY );
+ else
+ return uno::Reference< frame::XModel >();
+}
+
+bool SdrOle2Obj::IsChart() const
+{
+ if (!mpImpl->mbTypeAsked)
+ {
+ mpImpl->mbIsChart = mpImpl->mxObjRef.IsChart();
+ mpImpl->mbTypeAsked = true;
+ }
+ return mpImpl->mbIsChart;
+}
+
+void SdrOle2Obj::SetGraphicToObj( const Graphic& aGraphic )
+{
+ mpImpl->mxObjRef.SetGraphic( aGraphic, OUString() );
+ // if the object isn't valid, e.g. link to something that doesn't exist, set the fallback
+ // graphic as mxGraphic so SdrOle2Obj::GetGraphic will show the fallback
+ if (const Graphic* pObjGraphic = mpImpl->mxObjRef.is() ? nullptr : mpImpl->mxObjRef.GetGraphic())
+ mpImpl->mxGraphic.reset(new Graphic(*pObjGraphic));
+}
+
+void SdrOle2Obj::SetGraphicToObj( const uno::Reference< io::XInputStream >& xGrStream, const OUString& aMediaType )
+{
+ mpImpl->mxObjRef.SetGraphicStream( xGrStream, aMediaType );
+ // if the object isn't valid, e.g. link to something that doesn't exist, set the fallback
+ // graphic as mxGraphic so SdrOle2Obj::GetGraphic will show the fallback
+ if (const Graphic* pObjGraphic = mpImpl->mxObjRef.is() ? nullptr : mpImpl->mxObjRef.GetGraphic())
+ mpImpl->mxGraphic.reset(new Graphic(*pObjGraphic));
+}
+
+bool SdrOle2Obj::IsCalc() const
+{
+ if ( !mpImpl->mxObjRef.is() )
+ return false;
+
+ SvGlobalName aObjClsId( mpImpl->mxObjRef->getClassID() );
+ return SvGlobalName(SO3_SC_CLASSID_30) == aObjClsId
+ || SvGlobalName(SO3_SC_CLASSID_40) == aObjClsId
+ || SvGlobalName(SO3_SC_CLASSID_50) == aObjClsId
+ || SvGlobalName(SO3_SC_CLASSID_60) == aObjClsId
+ || SvGlobalName(SO3_SC_OLE_EMBED_CLASSID_60) == aObjClsId
+ || SvGlobalName(SO3_SC_OLE_EMBED_CLASSID_8) == aObjClsId
+ || SvGlobalName(SO3_SC_CLASSID) == aObjClsId;
+}
+
+uno::Reference< frame::XModel > SdrOle2Obj::GetParentXModel() const
+{
+ uno::Reference< frame::XModel > xDoc(getSdrModelFromSdrObject().getUnoModel(), uno::UNO_QUERY);
+ return xDoc;
+}
+
+bool SdrOle2Obj::CalculateNewScaling( Fraction& aScaleWidth, Fraction& aScaleHeight, Size& aObjAreaSize )
+{
+ // TODO/LEAN: to avoid rounding errors scaling always uses the VisArea.
+ // If we don't cache it for own objects also we must load the object here
+ if (!mpImpl->mxObjRef.is())
+ return false;
+
+ MapMode aMapMode(getSdrModelFromSdrObject().GetScaleUnit());
+ aObjAreaSize = mpImpl->mxObjRef.GetSize( &aMapMode );
+
+ Size aSize = maRect.GetSize();
+ aScaleWidth = Fraction(aSize.Width(), aObjAreaSize.Width() );
+ aScaleHeight = Fraction(aSize.Height(), aObjAreaSize.Height() );
+
+ // reduce to 10 binary digits
+ aScaleHeight.ReduceInaccurate(10);
+ aScaleWidth.ReduceInaccurate(10);
+
+ return true;
+}
+
+bool SdrOle2Obj::AddOwnLightClient()
+{
+ // The Own Light Client must be registered in object only using this method!
+ if ( !SfxInPlaceClient::GetClient( dynamic_cast<SfxObjectShell*>(getSdrModelFromSdrObject().GetPersist()), mpImpl->mxObjRef.GetObject() )
+ && !( mpImpl->mxLightClient.is() && mpImpl->mxObjRef->getClientSite() == uno::Reference< embed::XEmbeddedClient >( mpImpl->mxLightClient ) ) )
+ {
+ Connect();
+
+ if ( mpImpl->mxObjRef.is() && mpImpl->mxLightClient.is() )
+ {
+ Fraction aScaleWidth;
+ Fraction aScaleHeight;
+ Size aObjAreaSize;
+ if ( CalculateNewScaling( aScaleWidth, aScaleHeight, aObjAreaSize ) )
+ {
+ mpImpl->mxLightClient->SetSizeScale( aScaleWidth, aScaleHeight );
+ try {
+ mpImpl->mxObjRef->setClientSite( mpImpl->mxLightClient );
+ return true;
+ } catch( uno::Exception& )
+ {}
+ }
+
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+Graphic SdrOle2Obj::GetEmptyOLEReplacementGraphic()
+{
+ return Graphic(BitmapEx(BMP_SVXOLEOBJ));
+}
+
+void SdrOle2Obj::SetWindow(const css::uno::Reference < css::awt::XWindow >& _xWindow)
+{
+ if ( mpImpl->mxObjRef.is() && mpImpl->mxLightClient.is() )
+ {
+ mpImpl->mxLightClient->setWindow(_xWindow);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdopage.cxx b/svx/source/svdraw/svdopage.cxx
new file mode 100644
index 000000000..67c7a104e
--- /dev/null
+++ b/svx/source/svdraw/svdopage.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdopage.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <sdr/properties/pageproperties.hxx>
+#include <sdr/contact/viewcontactofpageobj.hxx>
+
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrPageObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::PageProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrPageObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfPageObj>(*this);
+}
+
+
+// this method is called from the destructor of the referenced page.
+// do all necessary action to forget the page. It is not necessary to call
+// RemovePageUser(), that is done from the destructor.
+void SdrPageObj::PageInDestruction(const SdrPage& rPage)
+{
+ if(mpShownPage && mpShownPage == &rPage)
+ {
+ // #i58769# Do not call ActionChanged() here, because that would
+ // lead to the construction of a view contact object for a page that
+ // is being destroyed.
+
+ mpShownPage = nullptr;
+ }
+}
+
+SdrPageObj::SdrPageObj(
+ SdrModel& rSdrModel,
+ SdrPage* pNewPage)
+: SdrObject(rSdrModel),
+ mpShownPage(pNewPage)
+{
+ if(mpShownPage)
+ {
+ mpShownPage->AddPageUser(*this);
+ }
+}
+
+SdrPageObj::SdrPageObj(SdrModel& rSdrModel, SdrPageObj const & rSource)
+: SdrObject(rSdrModel, rSource),
+ mpShownPage(nullptr)
+{
+ SetReferencedPage( rSource.GetReferencedPage());
+}
+
+SdrPageObj::SdrPageObj(
+ SdrModel& rSdrModel,
+ const tools::Rectangle& rRect,
+ SdrPage* pNewPage)
+: SdrObject(rSdrModel),
+ mpShownPage(pNewPage)
+{
+ if(mpShownPage)
+ {
+ mpShownPage->AddPageUser(*this);
+ }
+
+ m_aOutRect = rRect;
+}
+
+SdrPageObj::~SdrPageObj()
+{
+ if(mpShownPage)
+ {
+ mpShownPage->RemovePageUser(*this);
+ }
+}
+
+
+void SdrPageObj::SetReferencedPage(SdrPage* pNewPage)
+{
+ if(mpShownPage == pNewPage)
+ return;
+
+ if(mpShownPage)
+ {
+ mpShownPage->RemovePageUser(*this);
+ }
+
+ mpShownPage = pNewPage;
+
+ if(mpShownPage)
+ {
+ mpShownPage->AddPageUser(*this);
+ }
+
+ SetChanged();
+ BroadcastObjectChange();
+}
+
+// #i96598#
+void SdrPageObj::SetBoundRectDirty()
+{
+ // avoid resetting aOutRect which in case of this object is model data,
+ // not re-creatable view data
+}
+
+SdrObjKind SdrPageObj::GetObjIdentifier() const
+{
+ return SdrObjKind::Page;
+}
+
+void SdrPageObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bRotateFreeAllowed=false;
+ rInfo.bRotate90Allowed =false;
+ rInfo.bMirrorFreeAllowed=false;
+ rInfo.bMirror45Allowed =false;
+ rInfo.bMirror90Allowed =false;
+ rInfo.bTransparenceAllowed = false;
+ rInfo.bShearAllowed =false;
+ rInfo.bEdgeRadiusAllowed=false;
+ rInfo.bNoOrthoDesired =false;
+ rInfo.bCanConvToPath =false;
+ rInfo.bCanConvToPoly =false;
+ rInfo.bCanConvToPathLineToArea=false;
+ rInfo.bCanConvToPolyLineToArea=false;
+}
+
+SdrPageObj* SdrPageObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrPageObj(rTargetModel, *this);
+}
+
+OUString SdrPageObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulPAGE));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+OUString SdrPageObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralPAGE);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdopath.cxx b/svx/source/svdraw/svdopath.cxx
new file mode 100644
index 000000000..9f338301e
--- /dev/null
+++ b/svx/source/svdraw/svdopath.cxx
@@ -0,0 +1,2994 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <o3tl/unit_conversion.hxx>
+#include <tools/bigint.hxx>
+#include <tools/helpers.hxx>
+#include <svx/svdopath.hxx>
+#include <math.h>
+#include <svx/xpoly.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svdview.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+#include <svx/polypolygoneditor.hxx>
+#include <sdr/contact/viewcontactofsdrpathobj.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/curve/b2dcubicbezier.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <sdr/attribute/sdrformtextattribute.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <memory>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+using namespace sdr;
+
+static sal_uInt16 GetPrevPnt(sal_uInt16 nPnt, sal_uInt16 nPntMax, bool bClosed)
+{
+ if (nPnt>0) {
+ nPnt--;
+ } else {
+ nPnt=nPntMax;
+ if (bClosed) nPnt--;
+ }
+ return nPnt;
+}
+
+static sal_uInt16 GetNextPnt(sal_uInt16 nPnt, sal_uInt16 nPntMax, bool bClosed)
+{
+ nPnt++;
+ if (nPnt>nPntMax || (bClosed && nPnt>=nPntMax)) nPnt=0;
+ return nPnt;
+}
+
+namespace {
+
+struct ImpSdrPathDragData : public SdrDragStatUserData
+{
+ XPolygon aXP; // section of the original polygon
+ bool bValid; // FALSE = too few points
+ bool bClosed; // closed object?
+ sal_uInt16 nPoly; // number of the polygon in the PolyPolygon
+ sal_uInt16 nPnt; // number of point in the above polygon
+ sal_uInt16 nPointCount; // number of points of the polygon
+ bool bBegPnt; // dragged point is first point of a Polyline
+ bool bEndPnt; // dragged point is finishing point of a Polyline
+ sal_uInt16 nPrevPnt; // index of previous point
+ sal_uInt16 nNextPnt; // index of next point
+ bool bPrevIsBegPnt; // previous point is first point of a Polyline
+ bool bNextIsEndPnt; // next point is first point of a Polyline
+ sal_uInt16 nPrevPrevPnt; // index of point before previous point
+ sal_uInt16 nNextNextPnt; // index of point after next point
+ bool bControl; // point is a control point
+ bool bIsNextControl; // point is a control point after a support point
+ bool bPrevIsControl; // if nPnt is a support point: a control point comes before
+ bool bNextIsControl; // if nPnt is a support point: a control point comes after
+ sal_uInt16 nPrevPrevPnt0;
+ sal_uInt16 nPrevPnt0;
+ sal_uInt16 nPnt0;
+ sal_uInt16 nNextPnt0;
+ sal_uInt16 nNextNextPnt0;
+ bool bEliminate; // delete point? (is set by MovDrag)
+
+ bool mbMultiPointDrag;
+ const XPolyPolygon maOrig;
+ XPolyPolygon maMove;
+ std::vector<SdrHdl*> maHandles;
+
+public:
+ ImpSdrPathDragData(const SdrPathObj& rPO, const SdrHdl& rHdl, bool bMuPoDr, const SdrDragStat& rDrag);
+ void ResetPoly(const SdrPathObj& rPO);
+ bool IsMultiPointDrag() const { return mbMultiPointDrag; }
+};
+
+}
+
+ImpSdrPathDragData::ImpSdrPathDragData(const SdrPathObj& rPO, const SdrHdl& rHdl, bool bMuPoDr, const SdrDragStat& rDrag)
+ : aXP(5)
+ , bValid(false)
+ , bClosed(false)
+ , nPoly(0)
+ , nPnt(0)
+ , nPointCount(0)
+ , bBegPnt(false)
+ , bEndPnt(false)
+ , nPrevPnt(0)
+ , nNextPnt(0)
+ , bPrevIsBegPnt(false)
+ , bNextIsEndPnt(false)
+ , nPrevPrevPnt(0)
+ , nNextNextPnt(0)
+ , bControl(false)
+ , bIsNextControl(false)
+ , bPrevIsControl(false)
+ , bNextIsControl(false)
+ , nPrevPrevPnt0(0)
+ , nPrevPnt0(0)
+ , nPnt0(0)
+ , nNextPnt0(0)
+ , nNextNextPnt0(0)
+ , bEliminate(false)
+ , mbMultiPointDrag(bMuPoDr)
+ , maOrig(rPO.GetPathPoly())
+ , maHandles(0)
+{
+ if(mbMultiPointDrag)
+ {
+ const SdrMarkView& rMarkView = *rDrag.GetView();
+ const SdrHdlList& rHdlList = rMarkView.GetHdlList();
+ const size_t nHdlCount = rHdlList.GetHdlCount();
+ const SdrObject* pInteractionObject(nHdlCount && rHdlList.GetHdl(0) ? rHdlList.GetHdl(0)->GetObj() : nullptr);
+
+ for(size_t a = 0; a < nHdlCount; ++a)
+ {
+ SdrHdl* pTestHdl = rHdlList.GetHdl(a);
+
+ if(pTestHdl && pTestHdl->IsSelected() && pTestHdl->GetObj() == pInteractionObject)
+ {
+ maHandles.push_back(pTestHdl);
+ }
+ }
+
+ maMove = maOrig;
+ bValid = true;
+ }
+ else
+ {
+ sal_uInt16 nPntMax = 0; // maximum index
+ bValid=false;
+ bClosed=rPO.IsClosed(); // closed object?
+ nPoly=static_cast<sal_uInt16>(rHdl.GetPolyNum()); // number of the polygon in the PolyPolygon
+ nPnt=static_cast<sal_uInt16>(rHdl.GetPointNum()); // number of points in the above polygon
+ const XPolygon aTmpXP(rPO.GetPathPoly().getB2DPolygon(nPoly));
+ nPointCount=aTmpXP.GetPointCount(); // number of point of the polygon
+ if (nPointCount==0 || (bClosed && nPointCount==1)) return; // minimum of 1 points for Lines, minimum of 2 points for Polygon
+ nPntMax=nPointCount-1; // maximum index
+ bBegPnt=!bClosed && nPnt==0; // dragged point is first point of a Polyline
+ bEndPnt=!bClosed && nPnt==nPntMax; // dragged point is finishing point of a Polyline
+ if (bClosed && nPointCount<=3) { // if polygon is only a line
+ bBegPnt=(nPointCount<3) || nPnt==0;
+ bEndPnt=(nPointCount<3) || nPnt==nPntMax-1;
+ }
+ nPrevPnt=nPnt; // index of previous point
+ nNextPnt=nPnt; // index of next point
+ if (!bBegPnt) nPrevPnt=GetPrevPnt(nPnt,nPntMax,bClosed);
+ if (!bEndPnt) nNextPnt=GetNextPnt(nPnt,nPntMax,bClosed);
+ bPrevIsBegPnt=bBegPnt || (!bClosed && nPrevPnt==0);
+ bNextIsEndPnt=bEndPnt || (!bClosed && nNextPnt==nPntMax);
+ nPrevPrevPnt=nPnt; // index of point before previous point
+ nNextNextPnt=nPnt; // index of point after next point
+ if (!bPrevIsBegPnt) nPrevPrevPnt=GetPrevPnt(nPrevPnt,nPntMax,bClosed);
+ if (!bNextIsEndPnt) nNextNextPnt=GetNextPnt(nNextPnt,nPntMax,bClosed);
+ bControl=rHdl.IsPlusHdl(); // point is a control point
+ bIsNextControl=false; // point is a control point after a support point
+ bPrevIsControl=false; // if nPnt is a support point: a control point comes before
+ bNextIsControl=false; // if nPnt is a support point: a control point comes after
+ if (bControl) {
+ bIsNextControl=!aTmpXP.IsControl(nPrevPnt);
+ } else {
+ bPrevIsControl=!bBegPnt && !bPrevIsBegPnt && aTmpXP.GetFlags(nPrevPnt)==PolyFlags::Control;
+ bNextIsControl=!bEndPnt && !bNextIsEndPnt && aTmpXP.GetFlags(nNextPnt)==PolyFlags::Control;
+ }
+ nPrevPrevPnt0=nPrevPrevPnt;
+ nPrevPnt0 =nPrevPnt;
+ nPnt0 =nPnt;
+ nNextPnt0 =nNextPnt;
+ nNextNextPnt0=nNextNextPnt;
+ nPrevPrevPnt=0;
+ nPrevPnt=1;
+ nPnt=2;
+ nNextPnt=3;
+ nNextNextPnt=4;
+ bEliminate=false;
+ ResetPoly(rPO);
+ bValid=true;
+ }
+}
+
+void ImpSdrPathDragData::ResetPoly(const SdrPathObj& rPO)
+{
+ const XPolygon aTmpXP(rPO.GetPathPoly().getB2DPolygon(nPoly));
+ aXP[0]=aTmpXP[nPrevPrevPnt0]; aXP.SetFlags(0,aTmpXP.GetFlags(nPrevPrevPnt0));
+ aXP[1]=aTmpXP[nPrevPnt0]; aXP.SetFlags(1,aTmpXP.GetFlags(nPrevPnt0));
+ aXP[2]=aTmpXP[nPnt0]; aXP.SetFlags(2,aTmpXP.GetFlags(nPnt0));
+ aXP[3]=aTmpXP[nNextPnt0]; aXP.SetFlags(3,aTmpXP.GetFlags(nNextPnt0));
+ aXP[4]=aTmpXP[nNextNextPnt0]; aXP.SetFlags(4,aTmpXP.GetFlags(nNextNextPnt0));
+}
+
+namespace {
+
+struct ImpPathCreateUser : public SdrDragStatUserData
+{
+ Point aBezControl0;
+ Point aBezStart;
+ Point aBezCtrl1;
+ Point aBezCtrl2;
+ Point aBezEnd;
+ Point aCircStart;
+ Point aCircEnd;
+ Point aCircCenter;
+ Point aLineStart;
+ Point aLineEnd;
+ Point aRectP1;
+ Point aRectP2;
+ Point aRectP3;
+ tools::Long nCircRadius;
+ Degree100 nCircStAngle;
+ Degree100 nCircRelAngle;
+ bool bBezier;
+ bool bBezHasCtrl0;
+ bool bCircle;
+ bool bAngleSnap;
+ bool bLine;
+ bool bLine90;
+ bool bRect;
+ bool bMixedCreate;
+ sal_uInt16 nBezierStartPoint;
+ SdrObjKind eStartKind;
+ SdrObjKind eCurrentKind;
+
+public:
+ ImpPathCreateUser(): nCircRadius(0),nCircStAngle(0),nCircRelAngle(0),
+ bBezier(false),bBezHasCtrl0(false),bCircle(false),bAngleSnap(false),bLine(false),bLine90(false),bRect(false),
+ bMixedCreate(false),nBezierStartPoint(0),eStartKind(SdrObjKind::NONE),eCurrentKind(SdrObjKind::NONE) { }
+
+ void ResetFormFlags() { bBezier=false; bCircle=false; bLine=false; bRect=false; }
+ bool IsFormFlag() const { return bBezier || bCircle || bLine || bRect; }
+ XPolygon GetFormPoly() const;
+ void CalcBezier(const Point& rP1, const Point& rP2, const Point& rDir, bool bMouseDown);
+ XPolygon GetBezierPoly() const;
+ void CalcCircle(const Point& rP1, const Point& rP2, const Point& rDir, SdrView const * pView);
+ XPolygon GetCirclePoly() const;
+ void CalcLine(const Point& rP1, const Point& rP2, const Point& rDir, SdrView const * pView);
+ static Point CalcLine(const Point& rCsr, tools::Long nDirX, tools::Long nDirY, SdrView const * pView);
+ XPolygon GetLinePoly() const;
+ void CalcRect(const Point& rP1, const Point& rP2, const Point& rDir, SdrView const * pView);
+ XPolygon GetRectPoly() const;
+};
+
+}
+
+XPolygon ImpPathCreateUser::GetFormPoly() const
+{
+ if (bBezier) return GetBezierPoly();
+ if (bCircle) return GetCirclePoly();
+ if (bLine) return GetLinePoly();
+ if (bRect) return GetRectPoly();
+ return XPolygon();
+}
+
+void ImpPathCreateUser::CalcBezier(const Point& rP1, const Point& rP2, const Point& rDir, bool bMouseDown)
+{
+ aBezStart=rP1;
+ aBezCtrl1=rP1+rDir;
+ aBezCtrl2=rP2;
+
+ // #i21479#
+ // Also copy the end point when no end point is set yet
+ if (!bMouseDown || (0 == aBezEnd.X() && 0 == aBezEnd.Y())) aBezEnd=rP2;
+
+ bBezier=true;
+}
+
+XPolygon ImpPathCreateUser::GetBezierPoly() const
+{
+ XPolygon aXP(4);
+ aXP[0]=aBezStart; aXP.SetFlags(0,PolyFlags::Smooth);
+ aXP[1]=aBezCtrl1; aXP.SetFlags(1,PolyFlags::Control);
+ aXP[2]=aBezCtrl2; aXP.SetFlags(2,PolyFlags::Control);
+ aXP[3]=aBezEnd;
+ return aXP;
+}
+
+void ImpPathCreateUser::CalcCircle(const Point& rP1, const Point& rP2, const Point& rDir, SdrView const * pView)
+{
+ Degree100 nTangAngle=GetAngle(rDir);
+ aCircStart=rP1;
+ aCircEnd=rP2;
+ aCircCenter=rP1;
+ tools::Long dx=rP2.X()-rP1.X();
+ tools::Long dy=rP2.Y()-rP1.Y();
+ Degree100 dAngle=GetAngle(Point(dx,dy))-nTangAngle;
+ dAngle=NormAngle36000(dAngle);
+ Degree100 nTmpAngle=NormAngle36000(9000_deg100-dAngle);
+ bool bRet=nTmpAngle!=9000_deg100 && nTmpAngle!=27000_deg100;
+ tools::Long nRad=0;
+ if (bRet) {
+ double cs = cos(toRadians(nTmpAngle));
+ double nR=static_cast<double>(GetLen(Point(dx,dy)))/cs/2;
+ nRad=std::abs(FRound(nR));
+ }
+ if (dAngle<18000_deg100) {
+ nCircStAngle=NormAngle36000(nTangAngle-9000_deg100);
+ nCircRelAngle=NormAngle36000(2_deg100*dAngle);
+ aCircCenter.AdjustX(FRound(nRad * cos(toRadians(nTangAngle + 9000_deg100))));
+ aCircCenter.AdjustY(-(FRound(nRad * sin(toRadians(nTangAngle + 9000_deg100)))));
+ } else {
+ nCircStAngle=NormAngle36000(nTangAngle+9000_deg100);
+ nCircRelAngle=-NormAngle36000(36000_deg100-2_deg100*dAngle);
+ aCircCenter.AdjustX(FRound(nRad * cos(toRadians(nTangAngle - 9000_deg100))));
+ aCircCenter.AdjustY(-(FRound(nRad * sin(toRadians(nTangAngle - 9000_deg100)))));
+ }
+ bAngleSnap=pView!=nullptr && pView->IsAngleSnapEnabled();
+ if (bAngleSnap) {
+ Degree100 nSA=pView->GetSnapAngle();
+ if (nSA) { // angle snapping
+ bool bNeg=nCircRelAngle<0_deg100;
+ if (bNeg) nCircRelAngle=-nCircRelAngle;
+ nCircRelAngle+=nSA/2_deg100;
+ nCircRelAngle/=nSA;
+ nCircRelAngle*=nSA;
+ nCircRelAngle=NormAngle36000(nCircRelAngle);
+ if (bNeg) nCircRelAngle=-nCircRelAngle;
+ }
+ }
+ nCircRadius=nRad;
+ if (nRad==0 || abs(nCircRelAngle).get()<5) bRet=false;
+ bCircle=bRet;
+}
+
+XPolygon ImpPathCreateUser::GetCirclePoly() const
+{
+ if (nCircRelAngle>=0_deg100) {
+ XPolygon aXP(aCircCenter,nCircRadius,nCircRadius,
+ nCircStAngle, nCircStAngle+nCircRelAngle,false);
+ aXP[0]=aCircStart; aXP.SetFlags(0,PolyFlags::Smooth);
+ if (!bAngleSnap) aXP[aXP.GetPointCount()-1]=aCircEnd;
+ return aXP;
+ } else {
+ XPolygon aXP(aCircCenter,nCircRadius,nCircRadius,
+ NormAngle36000(nCircStAngle+nCircRelAngle), nCircStAngle,false);
+ sal_uInt16 nCount=aXP.GetPointCount();
+ for (sal_uInt16 nNum=nCount/2; nNum>0;) {
+ nNum--; // reverse XPoly's order of points
+ sal_uInt16 n2=nCount-nNum-1;
+ Point aPt(aXP[nNum]);
+ aXP[nNum]=aXP[n2];
+ aXP[n2]=aPt;
+ }
+ aXP[0]=aCircStart; aXP.SetFlags(0,PolyFlags::Smooth);
+ if (!bAngleSnap) aXP[aXP.GetPointCount()-1]=aCircEnd;
+ return aXP;
+ }
+}
+
+Point ImpPathCreateUser::CalcLine(const Point& aCsr, tools::Long nDirX, tools::Long nDirY, SdrView const * pView)
+{
+ tools::Long x=aCsr.X();
+ tools::Long y=aCsr.Y();
+ bool bHLin=nDirY==0;
+ bool bVLin=nDirX==0;
+ if (bHLin) y=0;
+ else if (bVLin) x=0;
+ else {
+ tools::Long x1=BigMulDiv(y,nDirX,nDirY);
+ tools::Long y1=y;
+ tools::Long x2=x;
+ tools::Long y2=BigMulDiv(x,nDirY,nDirX);
+ tools::Long l1=std::abs(x1)+std::abs(y1);
+ tools::Long l2=std::abs(x2)+std::abs(y2);
+ if ((l1<=l2) != (pView!=nullptr && pView->IsBigOrtho())) {
+ x=x1; y=y1;
+ } else {
+ x=x2; y=y2;
+ }
+ }
+ return Point(x,y);
+}
+
+void ImpPathCreateUser::CalcLine(const Point& rP1, const Point& rP2, const Point& rDir, SdrView const * pView)
+{
+ aLineStart=rP1;
+ aLineEnd=rP2;
+ bLine90=false;
+ if (rP1==rP2 || (rDir.X()==0 && rDir.Y()==0)) { bLine=false; return; }
+ Point aTmpPt(rP2-rP1);
+ tools::Long nDirX=rDir.X();
+ tools::Long nDirY=rDir.Y();
+ Point aP1(CalcLine(aTmpPt, nDirX, nDirY,pView)); aP1-=aTmpPt; tools::Long nQ1=std::abs(aP1.X())+std::abs(aP1.Y());
+ Point aP2(CalcLine(aTmpPt, nDirY,-nDirX,pView)); aP2-=aTmpPt; tools::Long nQ2=std::abs(aP2.X())+std::abs(aP2.Y());
+ if (pView!=nullptr && pView->IsOrtho()) nQ1=0; // Ortho turns off at right angle
+ bLine90=nQ1>2*nQ2;
+ if (!bLine90) { // smooth transition
+ aLineEnd+=aP1;
+ } else { // rectangular transition
+ aLineEnd+=aP2;
+ }
+ bLine=true;
+}
+
+XPolygon ImpPathCreateUser::GetLinePoly() const
+{
+ XPolygon aXP(2);
+ aXP[0]=aLineStart; if (!bLine90) aXP.SetFlags(0,PolyFlags::Smooth);
+ aXP[1]=aLineEnd;
+ return aXP;
+}
+
+void ImpPathCreateUser::CalcRect(const Point& rP1, const Point& rP2, const Point& rDir, SdrView const * pView)
+{
+ aRectP1=rP1;
+ aRectP2=rP1;
+ aRectP3=rP2;
+ if (rP1==rP2 || (rDir.X()==0 && rDir.Y()==0)) { bRect=false; return; }
+ Point aTmpPt(rP2-rP1);
+ tools::Long nDirX=rDir.X();
+ tools::Long nDirY=rDir.Y();
+ tools::Long x=aTmpPt.X();
+ tools::Long y=aTmpPt.Y();
+ bool bHLin=nDirY==0;
+ bool bVLin=nDirX==0;
+ if (bHLin) y=0;
+ else if (bVLin) x=0;
+ else {
+ y=BigMulDiv(x,nDirY,nDirX);
+ tools::Long nHypLen=aTmpPt.Y()-y;
+ Degree100 nTangAngle=-GetAngle(rDir);
+ // sin=g/h, g=h*sin
+ double a = toRadians(nTangAngle);
+ double sn=sin(a);
+ double cs=cos(a);
+ double nGKathLen=nHypLen*sn;
+ y+=FRound(nGKathLen*sn);
+ x+=FRound(nGKathLen*cs);
+ }
+ aRectP2.AdjustX(x );
+ aRectP2.AdjustY(y );
+ if (pView!=nullptr && pView->IsOrtho()) {
+ tools::Long dx1=aRectP2.X()-aRectP1.X(); tools::Long dx1a=std::abs(dx1);
+ tools::Long dy1=aRectP2.Y()-aRectP1.Y(); tools::Long dy1a=std::abs(dy1);
+ tools::Long dx2=aRectP3.X()-aRectP2.X(); tools::Long dx2a=std::abs(dx2);
+ tools::Long dy2=aRectP3.Y()-aRectP2.Y(); tools::Long dy2a=std::abs(dy2);
+ bool b1MoreThan2=dx1a+dy1a>dx2a+dy2a;
+ if (b1MoreThan2 != pView->IsBigOrtho()) {
+ tools::Long xtemp=dy2a-dx1a; if (dx1<0) xtemp=-xtemp;
+ tools::Long ytemp=dx2a-dy1a; if (dy1<0) ytemp=-ytemp;
+ aRectP2.AdjustX(xtemp );
+ aRectP2.AdjustY(ytemp );
+ aRectP3.AdjustX(xtemp );
+ aRectP3.AdjustY(ytemp );
+ } else {
+ tools::Long xtemp=dy1a-dx2a; if (dx2<0) xtemp=-xtemp;
+ tools::Long ytemp=dx1a-dy2a; if (dy2<0) ytemp=-ytemp;
+ aRectP3.AdjustX(xtemp );
+ aRectP3.AdjustY(ytemp );
+ }
+ }
+ bRect=true;
+}
+
+XPolygon ImpPathCreateUser::GetRectPoly() const
+{
+ XPolygon aXP(3);
+ aXP[0]=aRectP1; aXP.SetFlags(0,PolyFlags::Smooth);
+ aXP[1]=aRectP2;
+ if (aRectP3!=aRectP2) aXP[2]=aRectP3;
+ return aXP;
+}
+
+class ImpPathForDragAndCreate
+{
+ SdrPathObj& mrSdrPathObject;
+ XPolyPolygon aPathPolygon;
+ SdrObjKind meObjectKind;
+ std::unique_ptr<ImpSdrPathDragData>
+ mpSdrPathDragData;
+ bool mbCreating;
+
+public:
+ explicit ImpPathForDragAndCreate(SdrPathObj& rSdrPathObject);
+
+ // drag stuff
+ bool beginPathDrag( SdrDragStat const & rDrag ) const;
+ bool movePathDrag( SdrDragStat& rDrag ) const;
+ bool endPathDrag( SdrDragStat const & rDrag );
+ OUString getSpecialDragComment(const SdrDragStat& rDrag) const;
+ basegfx::B2DPolyPolygon getSpecialDragPoly(const SdrDragStat& rDrag) const;
+
+ // create stuff
+ void BegCreate(SdrDragStat& rStat);
+ bool MovCreate(SdrDragStat& rStat);
+ bool EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd);
+ bool BckCreate(SdrDragStat const & rStat);
+ void BrkCreate(SdrDragStat& rStat);
+ PointerStyle GetCreatePointer() const;
+
+ // helping stuff
+ static bool IsClosed(SdrObjKind eKind) { return eKind==SdrObjKind::Polygon || eKind==SdrObjKind::PathPoly || eKind==SdrObjKind::PathFill || eKind==SdrObjKind::FreehandFill || eKind==SdrObjKind::SplineFill; }
+ static bool IsFreeHand(SdrObjKind eKind) { return eKind==SdrObjKind::FreehandLine || eKind==SdrObjKind::FreehandFill; }
+ static bool IsBezier(SdrObjKind eKind) { return eKind==SdrObjKind::PathLine || eKind==SdrObjKind::PathFill; }
+ bool IsCreating() const { return mbCreating; }
+
+ // get the polygon
+ basegfx::B2DPolyPolygon TakeObjectPolyPolygon(const SdrDragStat& rDrag) const;
+ static basegfx::B2DPolyPolygon TakeDragPolyPolygon(const SdrDragStat& rDrag);
+ basegfx::B2DPolyPolygon getModifiedPolyPolygon() const { return aPathPolygon.getB2DPolyPolygon(); }
+};
+
+ImpPathForDragAndCreate::ImpPathForDragAndCreate(SdrPathObj& rSdrPathObject)
+: mrSdrPathObject(rSdrPathObject),
+ aPathPolygon(rSdrPathObject.GetPathPoly()),
+ meObjectKind(mrSdrPathObject.meKind),
+ mbCreating(false)
+{
+}
+
+bool ImpPathForDragAndCreate::beginPathDrag( SdrDragStat const & rDrag ) const
+{
+ const SdrHdl* pHdl=rDrag.GetHdl();
+ if(!pHdl)
+ return false;
+
+ bool bMultiPointDrag(true);
+
+ if(aPathPolygon[static_cast<sal_uInt16>(pHdl->GetPolyNum())].IsControl(static_cast<sal_uInt16>(pHdl->GetPointNum())))
+ bMultiPointDrag = false;
+
+ if(bMultiPointDrag)
+ {
+ const SdrMarkView& rMarkView = *rDrag.GetView();
+ const SdrHdlList& rHdlList = rMarkView.GetHdlList();
+ const size_t nHdlCount = rHdlList.GetHdlCount();
+ const SdrObject* pInteractionObject(nHdlCount && rHdlList.GetHdl(0) ? rHdlList.GetHdl(0)->GetObj() : nullptr);
+ sal_uInt32 nSelectedPoints(0);
+
+ for(size_t a = 0; a < nHdlCount; ++a)
+ {
+ SdrHdl* pTestHdl = rHdlList.GetHdl(a);
+
+ if(pTestHdl && pTestHdl->IsSelected() && pTestHdl->GetObj() == pInteractionObject)
+ {
+ nSelectedPoints++;
+ }
+ }
+
+ if(nSelectedPoints <= 1)
+ bMultiPointDrag = false;
+ }
+
+ const_cast<ImpPathForDragAndCreate*>(this)->mpSdrPathDragData.reset( new ImpSdrPathDragData(mrSdrPathObject,*pHdl,bMultiPointDrag,rDrag) );
+
+ if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
+ {
+ OSL_FAIL("ImpPathForDragAndCreate::BegDrag(): ImpSdrPathDragData is invalid.");
+ const_cast<ImpPathForDragAndCreate*>(this)->mpSdrPathDragData.reset();
+ return false;
+ }
+
+ return true;
+}
+
+bool ImpPathForDragAndCreate::movePathDrag( SdrDragStat& rDrag ) const
+{
+ if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
+ {
+ OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
+ return false;
+ }
+
+ if(mpSdrPathDragData->IsMultiPointDrag())
+ {
+ Point aDelta(rDrag.GetNow() - rDrag.GetStart());
+
+ if(aDelta.X() || aDelta.Y())
+ {
+ for(SdrHdl* pHandle : mpSdrPathDragData->maHandles)
+ {
+ const sal_uInt16 nPolyIndex(static_cast<sal_uInt16>(pHandle->GetPolyNum()));
+ const sal_uInt16 nPointIndex(static_cast<sal_uInt16>(pHandle->GetPointNum()));
+ const XPolygon& rOrig = mpSdrPathDragData->maOrig[nPolyIndex];
+ XPolygon& rMove = mpSdrPathDragData->maMove[nPolyIndex];
+ const sal_uInt16 nPointCount(rOrig.GetPointCount());
+ bool bClosed(rOrig[0] == rOrig[nPointCount-1]);
+
+ // move point itself
+ rMove[nPointIndex] = rOrig[nPointIndex] + aDelta;
+
+ // when point is first and poly closed, move close point, too.
+ if(nPointCount > 0 && !nPointIndex && bClosed)
+ {
+ rMove[nPointCount - 1] = rOrig[nPointCount - 1] + aDelta;
+
+ // when moving the last point it may be necessary to move the
+ // control point in front of this one, too.
+ if(nPointCount > 1 && rOrig.IsControl(nPointCount - 2))
+ rMove[nPointCount - 2] = rOrig[nPointCount - 2] + aDelta;
+ }
+
+ // is a control point before this?
+ if(nPointIndex > 0 && rOrig.IsControl(nPointIndex - 1))
+ {
+ // Yes, move it, too
+ rMove[nPointIndex - 1] = rOrig[nPointIndex - 1] + aDelta;
+ }
+
+ // is a control point after this?
+ if(nPointIndex + 1 < nPointCount && rOrig.IsControl(nPointIndex + 1))
+ {
+ // Yes, move it, too
+ rMove[nPointIndex + 1] = rOrig[nPointIndex + 1] + aDelta;
+ }
+ }
+ }
+ }
+ else
+ {
+ mpSdrPathDragData->ResetPoly(mrSdrPathObject);
+
+ // copy certain data locally to use less code and have faster access times
+ bool bClosed =mpSdrPathDragData->bClosed ; // closed object?
+ sal_uInt16 nPnt =mpSdrPathDragData->nPnt ; // number of point in the above polygon
+ bool bBegPnt =mpSdrPathDragData->bBegPnt ; // dragged point is first point of a Polyline
+ bool bEndPnt =mpSdrPathDragData->bEndPnt ; // dragged point is last point of a Polyline
+ sal_uInt16 nPrevPnt =mpSdrPathDragData->nPrevPnt ; // index of previous point
+ sal_uInt16 nNextPnt =mpSdrPathDragData->nNextPnt ; // index of next point
+ bool bPrevIsBegPnt =mpSdrPathDragData->bPrevIsBegPnt ; // previous point is first point of a Polyline
+ bool bNextIsEndPnt =mpSdrPathDragData->bNextIsEndPnt ; // next point is last point of a Polyline
+ sal_uInt16 nPrevPrevPnt =mpSdrPathDragData->nPrevPrevPnt ; // index of the point before the previous point
+ sal_uInt16 nNextNextPnt =mpSdrPathDragData->nNextNextPnt ; // index if the point after the next point
+ bool bControl =mpSdrPathDragData->bControl ; // point is a control point
+ bool bIsNextControl =mpSdrPathDragData->bIsNextControl; // point is a control point after a support point
+ bool bPrevIsControl =mpSdrPathDragData->bPrevIsControl; // if nPnt is a support point: there's a control point before
+ bool bNextIsControl =mpSdrPathDragData->bNextIsControl; // if nPnt is a support point: there's a control point after
+
+ // Ortho for lines/polygons: keep angle
+ if (!bControl && rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho()) {
+ bool bBigOrtho=rDrag.GetView()->IsBigOrtho();
+ Point aPos(rDrag.GetNow()); // current position
+ Point aPnt(mpSdrPathDragData->aXP[nPnt]); // the dragged point
+ sal_uInt16 nPnt1=0xFFFF,nPnt2=0xFFFF; // its neighboring points
+ Point aNewPos1,aNewPos2; // new alternative for aPos
+ bool bPnt1 = false, bPnt2 = false; // are these valid alternatives?
+ if (!bClosed && mpSdrPathDragData->nPointCount>=2) { // minimum of 2 points for lines
+ if (!bBegPnt) nPnt1=nPrevPnt;
+ if (!bEndPnt) nPnt2=nNextPnt;
+ }
+ if (bClosed && mpSdrPathDragData->nPointCount>=3) { // minimum of 3 points for polygon
+ nPnt1=nPrevPnt;
+ nPnt2=nNextPnt;
+ }
+ if (nPnt1!=0xFFFF && !bPrevIsControl) {
+ Point aPnt1=mpSdrPathDragData->aXP[nPnt1];
+ tools::Long ndx0=aPnt.X()-aPnt1.X();
+ tools::Long ndy0=aPnt.Y()-aPnt1.Y();
+ bool bHLin=ndy0==0;
+ bool bVLin=ndx0==0;
+ if (!bHLin || !bVLin) {
+ tools::Long ndx=aPos.X()-aPnt1.X();
+ tools::Long ndy=aPos.Y()-aPnt1.Y();
+ bPnt1=true;
+ double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0);
+ double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0);
+ bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
+ bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
+ if (bHor) ndy=tools::Long(ndy0*nXFact);
+ if (bVer) ndx=tools::Long(ndx0*nYFact);
+ aNewPos1=aPnt1;
+ aNewPos1.AdjustX(ndx );
+ aNewPos1.AdjustY(ndy );
+ }
+ }
+ if (nPnt2!=0xFFFF && !bNextIsControl) {
+ Point aPnt2=mpSdrPathDragData->aXP[nPnt2];
+ tools::Long ndx0=aPnt.X()-aPnt2.X();
+ tools::Long ndy0=aPnt.Y()-aPnt2.Y();
+ bool bHLin=ndy0==0;
+ bool bVLin=ndx0==0;
+ if (!bHLin || !bVLin) {
+ tools::Long ndx=aPos.X()-aPnt2.X();
+ tools::Long ndy=aPos.Y()-aPnt2.Y();
+ bPnt2=true;
+ double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0);
+ double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0);
+ bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
+ bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
+ if (bHor) ndy=tools::Long(ndy0*nXFact);
+ if (bVer) ndx=tools::Long(ndx0*nYFact);
+ aNewPos2=aPnt2;
+ aNewPos2.AdjustX(ndx );
+ aNewPos2.AdjustY(ndy );
+ }
+ }
+ if (bPnt1 && bPnt2) { // both alternatives exist (and compete)
+ BigInt nX1(aNewPos1.X()-aPos.X()); nX1*=nX1;
+ BigInt nY1(aNewPos1.Y()-aPos.Y()); nY1*=nY1;
+ BigInt nX2(aNewPos2.X()-aPos.X()); nX2*=nX2;
+ BigInt nY2(aNewPos2.Y()-aPos.Y()); nY2*=nY2;
+ nX1+=nY1; // correction distance to square
+ nX2+=nY2; // correction distance to square
+ // let the alternative that allows fewer correction win
+ if (nX1<nX2) bPnt2=false; else bPnt1=false;
+ }
+ if (bPnt1) rDrag.SetNow(aNewPos1);
+ if (bPnt2) rDrag.SetNow(aNewPos2);
+ }
+ rDrag.SetActionRect(tools::Rectangle(rDrag.GetNow(),rDrag.GetNow()));
+
+ // specially for IBM: Eliminate points if both adjoining lines form near 180 degrees angle anyway
+ if (!bControl && rDrag.GetView()!=nullptr && rDrag.GetView()->IsEliminatePolyPoints() &&
+ !bBegPnt && !bEndPnt && !bPrevIsControl && !bNextIsControl)
+ {
+ Point aPt(mpSdrPathDragData->aXP[nNextPnt]);
+ aPt-=rDrag.GetNow();
+ Degree100 nAngle1=GetAngle(aPt);
+ aPt=rDrag.GetNow();
+ aPt-=mpSdrPathDragData->aXP[nPrevPnt];
+ Degree100 nAngle2=GetAngle(aPt);
+ Degree100 nDiff=nAngle1-nAngle2;
+ nDiff=abs(nDiff);
+ mpSdrPathDragData->bEliminate=nDiff<=rDrag.GetView()->GetEliminatePolyPointLimitAngle();
+ if (mpSdrPathDragData->bEliminate) { // adapt position, Smooth is true for the ends
+ aPt=mpSdrPathDragData->aXP[nNextPnt];
+ aPt+=mpSdrPathDragData->aXP[nPrevPnt];
+ aPt/=2;
+ rDrag.SetNow(aPt);
+ }
+ }
+
+ // we dragged by this distance
+ Point aDiff(rDrag.GetNow()); aDiff-=mpSdrPathDragData->aXP[nPnt];
+
+ /* There are 8 possible cases:
+ X 1. A control point neither on the left nor on the right.
+ o--X--o 2. There are control points on the left and the right, we are dragging a support point.
+ o--X 3. There is a control point on the left, we are dragging a support point.
+ X--o 4. There is a control point on the right, we are dragging a support point.
+ x--O--o 5. There are control points on the left and the right, we are dragging the left one.
+ x--O 6. There is a control point on the left, we are dragging it.
+ o--O--x 7. There are control points on the left and the right, we are dragging the right one.
+ O--x 8. There is a control point on the right, we are dragging it.
+ Note: modifying a line (not a curve!) might create a curve on the other end of the line
+ if Smooth is set there (with control points aligned to line).
+ */
+
+ mpSdrPathDragData->aXP[nPnt]+=aDiff;
+
+ // now check symmetric plus handles
+ if (bControl) { // cases 5,6,7,8
+ sal_uInt16 nSt; // the associated support point
+ sal_uInt16 nFix; // the opposing control point
+ if (bIsNextControl) { // if the next one is a control point, the on before has to be a support point
+ nSt=nPrevPnt;
+ nFix=nPrevPrevPnt;
+ } else {
+ nSt=nNextPnt;
+ nFix=nNextNextPnt;
+ }
+ if (mpSdrPathDragData->aXP.IsSmooth(nSt)) {
+ mpSdrPathDragData->aXP.CalcSmoothJoin(nSt,nPnt,nFix);
+ }
+ }
+
+ if (!bControl) { // Cases 1,2,3,4. In case 1, nothing happens; in cases 3 and 4, there is more following below.
+ // move both control points
+ if (bPrevIsControl) mpSdrPathDragData->aXP[nPrevPnt]+=aDiff;
+ if (bNextIsControl) mpSdrPathDragData->aXP[nNextPnt]+=aDiff;
+ // align control point to line, if appropriate
+ if (mpSdrPathDragData->aXP.IsSmooth(nPnt)) {
+ if (bPrevIsControl && !bNextIsControl && !bEndPnt) { // case 3
+ mpSdrPathDragData->aXP.CalcSmoothJoin(nPnt,nNextPnt,nPrevPnt);
+ }
+ if (bNextIsControl && !bPrevIsControl && !bBegPnt) { // case 4
+ mpSdrPathDragData->aXP.CalcSmoothJoin(nPnt,nPrevPnt,nNextPnt);
+ }
+ }
+ // Now check the other ends of the line (nPnt+-1). If there is a
+ // curve (IsControl(nPnt+-2)) with SmoothJoin (nPnt+-1), the
+ // associated control point (nPnt+-2) has to be adapted.
+ if (!bBegPnt && !bPrevIsControl && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsSmooth(nPrevPnt)) {
+ if (mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
+ mpSdrPathDragData->aXP.CalcSmoothJoin(nPrevPnt,nPnt,nPrevPrevPnt);
+ }
+ }
+ if (!bEndPnt && !bNextIsControl && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsSmooth(nNextPnt)) {
+ if (mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
+ mpSdrPathDragData->aXP.CalcSmoothJoin(nNextPnt,nPnt,nNextNextPnt);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ImpPathForDragAndCreate::endPathDrag(SdrDragStat const & rDrag)
+{
+ Point aLinePt1;
+ Point aLinePt2;
+ bool bLineGlueMirror(SdrObjKind::Line == meObjectKind);
+ if (bLineGlueMirror) {
+ XPolygon& rXP=aPathPolygon[0];
+ aLinePt1=rXP[0];
+ aLinePt2=rXP[1];
+ }
+
+ if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
+ {
+ OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
+ return false;
+ }
+
+ if(mpSdrPathDragData->IsMultiPointDrag())
+ {
+ aPathPolygon = mpSdrPathDragData->maMove;
+ }
+ else
+ {
+ const SdrHdl* pHdl=rDrag.GetHdl();
+
+ // reference the polygon
+ XPolygon& rXP=aPathPolygon[static_cast<sal_uInt16>(pHdl->GetPolyNum())];
+
+ // the 5 points that might have changed
+ if (!mpSdrPathDragData->bPrevIsBegPnt) rXP[mpSdrPathDragData->nPrevPrevPnt0]=mpSdrPathDragData->aXP[mpSdrPathDragData->nPrevPrevPnt];
+ if (!mpSdrPathDragData->bNextIsEndPnt) rXP[mpSdrPathDragData->nNextNextPnt0]=mpSdrPathDragData->aXP[mpSdrPathDragData->nNextNextPnt];
+ if (!mpSdrPathDragData->bBegPnt) rXP[mpSdrPathDragData->nPrevPnt0] =mpSdrPathDragData->aXP[mpSdrPathDragData->nPrevPnt];
+ if (!mpSdrPathDragData->bEndPnt) rXP[mpSdrPathDragData->nNextPnt0] =mpSdrPathDragData->aXP[mpSdrPathDragData->nNextPnt];
+ rXP[mpSdrPathDragData->nPnt0] =mpSdrPathDragData->aXP[mpSdrPathDragData->nPnt];
+
+ // for closed objects: last point has to be equal to first point
+ if (mpSdrPathDragData->bClosed) rXP[rXP.GetPointCount()-1]=rXP[0];
+
+ if (mpSdrPathDragData->bEliminate)
+ {
+ basegfx::B2DPolyPolygon aTempPolyPolygon(aPathPolygon.getB2DPolyPolygon());
+ sal_uInt32 nPoly,nPnt;
+
+ if(PolyPolygonEditor::GetRelativePolyPoint(aTempPolyPolygon, rDrag.GetHdl()->GetSourceHdlNum(), nPoly, nPnt))
+ {
+ basegfx::B2DPolygon aCandidate(aTempPolyPolygon.getB2DPolygon(nPoly));
+ aCandidate.remove(nPnt);
+
+ if(aCandidate.count() < 2)
+ {
+ aTempPolyPolygon.remove(nPoly);
+ }
+ else
+ {
+ aTempPolyPolygon.setB2DPolygon(nPoly, aCandidate);
+ }
+ }
+
+ aPathPolygon = XPolyPolygon(aTempPolyPolygon);
+ }
+
+ // adapt angle for text beneath a simple line
+ if (bLineGlueMirror)
+ {
+ Point aLinePt1_(aPathPolygon[0][0]);
+ Point aLinePt2_(aPathPolygon[0][1]);
+ bool bXMirr=(aLinePt1_.X()>aLinePt2_.X())!=(aLinePt1.X()>aLinePt2.X());
+ bool bYMirr=(aLinePt1_.Y()>aLinePt2_.Y())!=(aLinePt1.Y()>aLinePt2.Y());
+ if (bXMirr || bYMirr) {
+ Point aRef1(mrSdrPathObject.GetSnapRect().Center());
+ if (bXMirr) {
+ Point aRef2(aRef1);
+ aRef2.AdjustY( 1 );
+ mrSdrPathObject.NbcMirrorGluePoints(aRef1,aRef2);
+ }
+ if (bYMirr) {
+ Point aRef2(aRef1);
+ aRef2.AdjustX( 1 );
+ mrSdrPathObject.NbcMirrorGluePoints(aRef1,aRef2);
+ }
+ }
+ }
+ }
+
+ mpSdrPathDragData.reset();
+
+ return true;
+}
+
+OUString ImpPathForDragAndCreate::getSpecialDragComment(const SdrDragStat& rDrag) const
+{
+ OUString aStr;
+ const SdrHdl* pHdl = rDrag.GetHdl();
+ const bool bCreateComment(rDrag.GetView() && &mrSdrPathObject == rDrag.GetView()->GetCreateObj());
+
+ if(bCreateComment && rDrag.GetUser())
+ {
+ // #i103058# re-add old creation comment mode
+ const ImpPathCreateUser* pU = static_cast<const ImpPathCreateUser*>(rDrag.GetUser());
+ const SdrObjKind eOriginalKind(meObjectKind);
+ mrSdrPathObject.meKind = pU->eCurrentKind;
+ aStr = mrSdrPathObject.ImpGetDescriptionStr(STR_ViewCreateObj);
+ mrSdrPathObject.meKind = eOriginalKind;
+
+ Point aPrev(rDrag.GetPrev());
+ Point aNow(rDrag.GetNow());
+
+ if(pU->bLine)
+ aNow = pU->aLineEnd;
+
+ aNow -= aPrev;
+ aStr += " (";
+
+ if(pU->bCircle)
+ {
+ aStr += SdrModel::GetAngleString(abs(pU->nCircRelAngle))
+ + " r="
+ + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(pU->nCircRadius, true);
+ }
+
+ aStr += "dx="
+ + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(aNow.X(), true)
+ + " dy="
+ + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(aNow.Y(), true);
+
+ if(!IsFreeHand(meObjectKind))
+ {
+ sal_Int32 nLen(GetLen(aNow));
+ Degree100 nAngle(GetAngle(aNow));
+ aStr += " l="
+ + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(nLen, true)
+ + " "
+ + SdrModel::GetAngleString(nAngle);
+ }
+
+ aStr += ")";
+ }
+ else if(!pHdl)
+ {
+ // #i103058# fallback when no model and/or Handle, both needed
+ // for else-path
+ aStr = mrSdrPathObject.ImpGetDescriptionStr(STR_DragPathObj);
+ }
+ else
+ {
+ // #i103058# standard for modification; model and handle needed
+ ImpSdrPathDragData* pDragData = mpSdrPathDragData.get();
+
+ if(!pDragData)
+ {
+ // getSpecialDragComment is also used from create, so fallback to GetUser()
+ // when mpSdrPathDragData is not set
+ pDragData = static_cast<ImpSdrPathDragData*>(rDrag.GetUser());
+ }
+
+ if(!pDragData)
+ {
+ OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
+ return OUString();
+ }
+
+ if(!pDragData->IsMultiPointDrag() && pDragData->bEliminate)
+ {
+ // point of ...
+ aStr = mrSdrPathObject.ImpGetDescriptionStr(STR_ViewMarkedPoint);
+
+ // delete %O
+ OUString aStr2(SvxResId(STR_EditDelete));
+
+ // UNICODE: delete point of ...
+ aStr2 = aStr2.replaceFirst("%1", aStr);
+
+ return aStr2;
+ }
+
+ // dx=0.00 dy=0.00 -- both sides bezier
+ // dx=0.00 dy=0.00 l=0.00 0.00\302\260 -- one bezier/lever on one side, a start, or an ending
+ // dx=0.00 dy=0.00 l=0.00 0.00\302\260 / l=0.00 0.00\302\260 -- in between
+ Point aBeg(rDrag.GetStart());
+ Point aNow(rDrag.GetNow());
+
+ aStr.clear();
+ aStr += "dx="
+ + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(aNow.X() - aBeg.X(), true)
+ + " dy="
+ + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(aNow.Y() - aBeg.Y(), true);
+
+ if(!pDragData->IsMultiPointDrag())
+ {
+ sal_uInt16 nPntNum(static_cast<sal_uInt16>(pHdl->GetPointNum()));
+ const XPolygon& rXPoly = aPathPolygon[static_cast<sal_uInt16>(rDrag.GetHdl()->GetPolyNum())];
+ sal_uInt16 nPointCount(rXPoly.GetPointCount());
+ bool bClose(IsClosed(meObjectKind));
+
+ if(bClose)
+ nPointCount--;
+
+ if(pHdl->IsPlusHdl())
+ {
+ // lever
+ sal_uInt16 nRef(nPntNum);
+
+ if(rXPoly.IsControl(nPntNum + 1))
+ nRef--;
+ else
+ nRef++;
+
+ aNow -= rXPoly[nRef];
+
+ sal_Int32 nLen(GetLen(aNow));
+ Degree100 nAngle(GetAngle(aNow));
+ aStr += " l="
+ + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(nLen, true)
+ + " "
+ + SdrModel::GetAngleString(nAngle);
+ }
+ else if(nPointCount > 1)
+ {
+ sal_uInt16 nPntMax(nPointCount - 1);
+ bool bIsClosed(IsClosed(meObjectKind));
+ bool bPt1(nPntNum > 0);
+ bool bPt2(nPntNum < nPntMax);
+
+ if(bIsClosed && nPointCount > 2)
+ {
+ bPt1 = true;
+ bPt2 = true;
+ }
+
+ sal_uInt16 nPt1,nPt2;
+
+ if(nPntNum > 0)
+ nPt1 = nPntNum - 1;
+ else
+ nPt1 = nPntMax;
+
+ if(nPntNum < nPntMax)
+ nPt2 = nPntNum + 1;
+ else
+ nPt2 = 0;
+
+ if(bPt1 && rXPoly.IsControl(nPt1))
+ bPt1 = false; // don't display
+
+ if(bPt2 && rXPoly.IsControl(nPt2))
+ bPt2 = false; // of bezier data
+
+ if(bPt1)
+ {
+ Point aPt(aNow);
+ aPt -= rXPoly[nPt1];
+
+ sal_Int32 nLen(GetLen(aPt));
+ Degree100 nAngle(GetAngle(aPt));
+ aStr += " l="
+ + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(nLen, true)
+ + " "
+ + SdrModel::GetAngleString(nAngle);
+ }
+
+ if(bPt2)
+ {
+ if(bPt1)
+ aStr += " / ";
+ else
+ aStr += " ";
+
+ Point aPt(aNow);
+ aPt -= rXPoly[nPt2];
+
+ sal_Int32 nLen(GetLen(aPt));
+ Degree100 nAngle(GetAngle(aPt));
+ aStr += "l="
+ + mrSdrPathObject.getSdrModelFromSdrObject().GetMetricString(nLen, true)
+ + " "
+ + SdrModel::GetAngleString(nAngle);
+ }
+ }
+ }
+ }
+
+ return aStr;
+}
+
+basegfx::B2DPolyPolygon ImpPathForDragAndCreate::getSpecialDragPoly(const SdrDragStat& rDrag) const
+{
+ if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
+ {
+ OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid.");
+ return basegfx::B2DPolyPolygon();
+ }
+
+ XPolyPolygon aRetval;
+
+ if(mpSdrPathDragData->IsMultiPointDrag())
+ {
+ aRetval.Insert(mpSdrPathDragData->maMove);
+ }
+ else
+ {
+ const XPolygon& rXP=aPathPolygon[static_cast<sal_uInt16>(rDrag.GetHdl()->GetPolyNum())];
+ if (rXP.GetPointCount()<=2) {
+ XPolygon aXPoly(rXP);
+ aXPoly[static_cast<sal_uInt16>(rDrag.GetHdl()->GetPointNum())]=rDrag.GetNow();
+ aRetval.Insert(std::move(aXPoly));
+ return aRetval.getB2DPolyPolygon();
+ }
+ // copy certain data locally to use less code and have faster access times
+ bool bClosed =mpSdrPathDragData->bClosed ; // closed object?
+ sal_uInt16 nPointCount = mpSdrPathDragData->nPointCount; // number of points
+ sal_uInt16 nPnt =mpSdrPathDragData->nPnt ; // number of points in the polygon
+ bool bBegPnt =mpSdrPathDragData->bBegPnt ; // dragged point is the first point of a Polyline
+ bool bEndPnt =mpSdrPathDragData->bEndPnt ; // dragged point is the last point of a Polyline
+ sal_uInt16 nPrevPnt =mpSdrPathDragData->nPrevPnt ; // index of the previous point
+ sal_uInt16 nNextPnt =mpSdrPathDragData->nNextPnt ; // index of the next point
+ bool bPrevIsBegPnt =mpSdrPathDragData->bPrevIsBegPnt ; // previous point is first point of a Polyline
+ bool bNextIsEndPnt =mpSdrPathDragData->bNextIsEndPnt ; // next point is last point of a Polyline
+ sal_uInt16 nPrevPrevPnt =mpSdrPathDragData->nPrevPrevPnt ; // index of the point before the previous point
+ sal_uInt16 nNextNextPnt =mpSdrPathDragData->nNextNextPnt ; // index of the point after the last point
+ bool bControl =mpSdrPathDragData->bControl ; // point is a control point
+ bool bIsNextControl =mpSdrPathDragData->bIsNextControl; //point is a control point after a support point
+ bool bPrevIsControl =mpSdrPathDragData->bPrevIsControl; // if nPnt is a support point: there's a control point before
+ bool bNextIsControl =mpSdrPathDragData->bNextIsControl; // if nPnt is a support point: there's a control point after
+ XPolygon aXPoly(mpSdrPathDragData->aXP);
+ XPolygon aLine1(2);
+ XPolygon aLine2(2);
+ XPolygon aLine3(2);
+ XPolygon aLine4(2);
+ if (bControl) {
+ aLine1[1]=mpSdrPathDragData->aXP[nPnt];
+ if (bIsNextControl) { // is this a control point after the support point?
+ aLine1[0]=mpSdrPathDragData->aXP[nPrevPnt];
+ aLine2[0]=mpSdrPathDragData->aXP[nNextNextPnt];
+ aLine2[1]=mpSdrPathDragData->aXP[nNextPnt];
+ if (mpSdrPathDragData->aXP.IsSmooth(nPrevPnt) && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
+ aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],PolyFlags::Control);
+ aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-2],PolyFlags::Normal);
+ // leverage lines for the opposing curve segment
+ aLine3[0]=mpSdrPathDragData->aXP[nPrevPnt];
+ aLine3[1]=mpSdrPathDragData->aXP[nPrevPrevPnt];
+ aLine4[0]=rXP[mpSdrPathDragData->nPrevPrevPnt0-2];
+ aLine4[1]=rXP[mpSdrPathDragData->nPrevPrevPnt0-1];
+ } else {
+ aXPoly.Remove(0,1);
+ }
+ } else { // else this is a control point before a support point
+ aLine1[0]=mpSdrPathDragData->aXP[nNextPnt];
+ aLine2[0]=mpSdrPathDragData->aXP[nPrevPrevPnt];
+ aLine2[1]=mpSdrPathDragData->aXP[nPrevPnt];
+ if (mpSdrPathDragData->aXP.IsSmooth(nNextPnt) && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
+ aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],PolyFlags::Control);
+ aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+2],PolyFlags::Normal);
+ // leverage lines for the opposing curve segment
+ aLine3[0]=mpSdrPathDragData->aXP[nNextPnt];
+ aLine3[1]=mpSdrPathDragData->aXP[nNextNextPnt];
+ aLine4[0]=rXP[mpSdrPathDragData->nNextNextPnt0+2];
+ aLine4[1]=rXP[mpSdrPathDragData->nNextNextPnt0+1];
+ } else {
+ aXPoly.Remove(aXPoly.GetPointCount()-1,1);
+ }
+ }
+ } else { // else is not a control point
+ if (mpSdrPathDragData->bEliminate) {
+ aXPoly.Remove(2,1);
+ }
+ if (bPrevIsControl) aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],PolyFlags::Normal);
+ else if (!bBegPnt && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
+ aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],PolyFlags::Control);
+ aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-2],PolyFlags::Normal);
+ } else {
+ aXPoly.Remove(0,1);
+ if (bBegPnt) aXPoly.Remove(0,1);
+ }
+ if (bNextIsControl) aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],PolyFlags::Normal);
+ else if (!bEndPnt && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
+ aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],PolyFlags::Control);
+ aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+2],PolyFlags::Normal);
+ } else {
+ aXPoly.Remove(aXPoly.GetPointCount()-1,1);
+ if (bEndPnt) aXPoly.Remove(aXPoly.GetPointCount()-1,1);
+ }
+ if (bClosed) { // "pear problem": 2 lines, 1 curve, everything smoothed, a point between both lines is dragged
+ if (aXPoly.GetPointCount()>nPointCount && aXPoly.IsControl(1)) {
+ sal_uInt16 a=aXPoly.GetPointCount();
+ aXPoly[a-2]=aXPoly[2]; aXPoly.SetFlags(a-2,aXPoly.GetFlags(2));
+ aXPoly[a-1]=aXPoly[3]; aXPoly.SetFlags(a-1,aXPoly.GetFlags(3));
+ aXPoly.Remove(0,3);
+ }
+ }
+ }
+ aRetval.Insert(std::move(aXPoly));
+ if (aLine1.GetPointCount()>1) aRetval.Insert(std::move(aLine1));
+ if (aLine2.GetPointCount()>1) aRetval.Insert(std::move(aLine2));
+ if (aLine3.GetPointCount()>1) aRetval.Insert(std::move(aLine3));
+ if (aLine4.GetPointCount()>1) aRetval.Insert(std::move(aLine4));
+ }
+
+ return aRetval.getB2DPolyPolygon();
+}
+
+void ImpPathForDragAndCreate::BegCreate(SdrDragStat& rStat)
+{
+ bool bFreeHand(IsFreeHand(meObjectKind));
+ rStat.SetNoSnap(bFreeHand);
+ rStat.SetOrtho8Possible();
+ aPathPolygon.Clear();
+ mbCreating=true;
+ bool bMakeStartPoint = true;
+ SdrView* pView=rStat.GetView();
+ if (pView!=nullptr && pView->IsUseIncompatiblePathCreateInterface() &&
+ (meObjectKind==SdrObjKind::Polygon || meObjectKind==SdrObjKind::PolyLine || meObjectKind==SdrObjKind::PathLine || meObjectKind==SdrObjKind::PathFill)) {
+ bMakeStartPoint = false;
+ }
+ aPathPolygon.Insert(XPolygon());
+ aPathPolygon[0][0]=rStat.GetStart();
+ if (bMakeStartPoint) {
+ aPathPolygon[0][1]=rStat.GetNow();
+ }
+ std::unique_ptr<ImpPathCreateUser> pU(new ImpPathCreateUser);
+ pU->eStartKind=meObjectKind;
+ pU->eCurrentKind=meObjectKind;
+ rStat.SetUser(std::move(pU));
+}
+
+bool ImpPathForDragAndCreate::MovCreate(SdrDragStat& rStat)
+{
+ ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
+ SdrView* pView=rStat.GetView();
+ XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1];
+ if (pView!=nullptr && pView->IsCreateMode()) {
+ // switch to different CreateTool, if appropriate
+ SdrObjKind nIdent;
+ SdrInventor nInvent;
+ pView->TakeCurrentObj(nIdent,nInvent);
+ if (nInvent==SdrInventor::Default && pU->eCurrentKind != nIdent) {
+ SdrObjKind eNewKind = nIdent;
+ switch (eNewKind) {
+ case SdrObjKind::CircleArc:
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::CircleCut:
+ case SdrObjKind::CircleSection:
+ eNewKind=SdrObjKind::CircleArc;
+ [[fallthrough]];
+ case SdrObjKind::Rectangle:
+ case SdrObjKind::Line:
+ case SdrObjKind::PolyLine:
+ case SdrObjKind::Polygon:
+ case SdrObjKind::PathLine:
+ case SdrObjKind::PathFill:
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::SplineLine:
+ case SdrObjKind::SplineFill: {
+ pU->eCurrentKind=eNewKind;
+ pU->bMixedCreate=true;
+ pU->nBezierStartPoint=rXPoly.GetPointCount();
+ if (pU->nBezierStartPoint>0) pU->nBezierStartPoint--;
+ } break;
+ default: break;
+ } // switch
+ }
+ }
+ sal_uInt16 nCurrentPoint=rXPoly.GetPointCount();
+ if (aPathPolygon.Count()>1 && rStat.IsMouseDown() && nCurrentPoint<2) {
+ rXPoly[0]=rStat.GetPos0();
+ rXPoly[1]=rStat.GetNow();
+ nCurrentPoint=2;
+ }
+ if (nCurrentPoint==0) {
+ rXPoly[0]=rStat.GetPos0();
+ } else nCurrentPoint--;
+ bool bFreeHand=IsFreeHand(pU->eCurrentKind);
+ rStat.SetNoSnap(bFreeHand);
+ rStat.SetOrtho8Possible(pU->eCurrentKind!=SdrObjKind::CircleArc && pU->eCurrentKind!=SdrObjKind::Rectangle && (!pU->bMixedCreate || pU->eCurrentKind!=SdrObjKind::Line));
+ rXPoly[nCurrentPoint]=rStat.GetNow();
+ if (!pU->bMixedCreate && pU->eStartKind==SdrObjKind::Line && rXPoly.GetPointCount()>=1) {
+ Point aPt(rStat.GetStart());
+ if (pView!=nullptr && pView->IsCreate1stPointAsCenter()) {
+ aPt+=aPt;
+ aPt-=rStat.GetNow();
+ }
+ rXPoly[0]=aPt;
+ }
+ OutputDevice* pOut=pView==nullptr ? nullptr : pView->GetFirstOutputDevice();
+ if (bFreeHand) {
+ if (pU->nBezierStartPoint>nCurrentPoint) pU->nBezierStartPoint=nCurrentPoint;
+ if (rStat.IsMouseDown() && nCurrentPoint>0) {
+ // don't allow two consecutive points to occupy too similar positions
+ tools::Long nMinDist=1;
+ if (pView!=nullptr) nMinDist=pView->GetFreeHandMinDistPix();
+ if (pOut!=nullptr) nMinDist=pOut->PixelToLogic(Size(nMinDist,0)).Width();
+ if (nMinDist<1) nMinDist=1;
+
+ Point aPt0(rXPoly[nCurrentPoint-1]);
+ Point aPt1(rStat.GetNow());
+ tools::Long dx=aPt0.X()-aPt1.X(); if (dx<0) dx=-dx;
+ tools::Long dy=aPt0.Y()-aPt1.Y(); if (dy<0) dy=-dy;
+ if (dx<nMinDist && dy<nMinDist) return false;
+
+ // TODO: the following is copied from EndCreate (with a few smaller modifications)
+ // and should be combined into a method with the code there.
+
+ if (nCurrentPoint-pU->nBezierStartPoint>=3 && ((nCurrentPoint-pU->nBezierStartPoint)%3)==0) {
+ rXPoly.PointsToBezier(nCurrentPoint-3);
+ rXPoly.SetFlags(nCurrentPoint-1,PolyFlags::Control);
+ rXPoly.SetFlags(nCurrentPoint-2,PolyFlags::Control);
+
+ if (nCurrentPoint>=6 && rXPoly.IsControl(nCurrentPoint-4)) {
+ rXPoly.CalcTangent(nCurrentPoint-3,nCurrentPoint-4,nCurrentPoint-2);
+ rXPoly.SetFlags(nCurrentPoint-3,PolyFlags::Smooth);
+ }
+ }
+ rXPoly[nCurrentPoint+1]=rStat.GetNow();
+ rStat.NextPoint();
+ } else {
+ pU->nBezierStartPoint=nCurrentPoint;
+ }
+ }
+
+ pU->ResetFormFlags();
+ if (IsBezier(pU->eCurrentKind)) {
+ if (nCurrentPoint>=2) {
+ pU->CalcBezier(rXPoly[nCurrentPoint-1],rXPoly[nCurrentPoint],rXPoly[nCurrentPoint-1]-rXPoly[nCurrentPoint-2],rStat.IsMouseDown());
+ } else if (pU->bBezHasCtrl0) {
+ pU->CalcBezier(rXPoly[nCurrentPoint-1],rXPoly[nCurrentPoint],pU->aBezControl0-rXPoly[nCurrentPoint-1],rStat.IsMouseDown());
+ }
+ }
+ if (pU->eCurrentKind==SdrObjKind::CircleArc && nCurrentPoint>=2) {
+ pU->CalcCircle(rXPoly[nCurrentPoint-1],rXPoly[nCurrentPoint],rXPoly[nCurrentPoint-1]-rXPoly[nCurrentPoint-2],pView);
+ }
+ if (pU->eCurrentKind==SdrObjKind::Line && nCurrentPoint>=2) {
+ pU->CalcLine(rXPoly[nCurrentPoint-1],rXPoly[nCurrentPoint],rXPoly[nCurrentPoint-1]-rXPoly[nCurrentPoint-2],pView);
+ }
+ if (pU->eCurrentKind==SdrObjKind::Rectangle && nCurrentPoint>=2) {
+ pU->CalcRect(rXPoly[nCurrentPoint-1],rXPoly[nCurrentPoint],rXPoly[nCurrentPoint-1]-rXPoly[nCurrentPoint-2],pView);
+ }
+
+ return true;
+}
+
+bool ImpPathForDragAndCreate::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
+ bool bRet = false;
+ SdrView* pView=rStat.GetView();
+ bool bIncomp=pView!=nullptr && pView->IsUseIncompatiblePathCreateInterface();
+ XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1];
+ sal_uInt16 nCurrentPoint=rXPoly.GetPointCount()-1;
+ rXPoly[nCurrentPoint]=rStat.GetNow();
+ if (!pU->bMixedCreate && pU->eStartKind==SdrObjKind::Line) {
+ if (rStat.GetPointCount()>=2) eCmd=SdrCreateCmd::ForceEnd;
+ bRet = eCmd==SdrCreateCmd::ForceEnd;
+ if (bRet) {
+ mbCreating = false;
+ rStat.SetUser(nullptr);
+ }
+ return bRet;
+ }
+
+ if (!pU->bMixedCreate && IsFreeHand(pU->eStartKind)) {
+ if (rStat.GetPointCount()>=2) eCmd=SdrCreateCmd::ForceEnd;
+ bRet=eCmd==SdrCreateCmd::ForceEnd;
+ if (bRet) {
+ mbCreating=false;
+ rStat.SetUser(nullptr);
+ }
+ return bRet;
+ }
+ if (eCmd==SdrCreateCmd::NextPoint || eCmd==SdrCreateCmd::NextObject) {
+ // don't allow two consecutive points to occupy the same position
+ if (nCurrentPoint==0 || rStat.GetNow()!=rXPoly[nCurrentPoint-1]) {
+ if (bIncomp) {
+ if (pU->nBezierStartPoint>nCurrentPoint) pU->nBezierStartPoint=nCurrentPoint;
+ if (IsBezier(pU->eCurrentKind) && nCurrentPoint-pU->nBezierStartPoint>=3 && ((nCurrentPoint-pU->nBezierStartPoint)%3)==0) {
+ rXPoly.PointsToBezier(nCurrentPoint-3);
+ rXPoly.SetFlags(nCurrentPoint-1,PolyFlags::Control);
+ rXPoly.SetFlags(nCurrentPoint-2,PolyFlags::Control);
+
+ if (nCurrentPoint>=6 && rXPoly.IsControl(nCurrentPoint-4)) {
+ rXPoly.CalcTangent(nCurrentPoint-3,nCurrentPoint-4,nCurrentPoint-2);
+ rXPoly.SetFlags(nCurrentPoint-3,PolyFlags::Smooth);
+ }
+ }
+ } else {
+ if (nCurrentPoint==1 && IsBezier(pU->eCurrentKind) && !pU->bBezHasCtrl0) {
+ pU->aBezControl0=rStat.GetNow();
+ pU->bBezHasCtrl0=true;
+ nCurrentPoint--;
+ }
+ if (pU->IsFormFlag()) {
+ sal_uInt16 nPointCount0=rXPoly.GetPointCount();
+ rXPoly.Remove(nCurrentPoint-1,2); // remove last two points and replace by form
+ rXPoly.Insert(XPOLY_APPEND,pU->GetFormPoly());
+ sal_uInt16 nPointCount1=rXPoly.GetPointCount();
+ for (sal_uInt16 i=nPointCount0+1; i<nPointCount1-1; i++) { // to make BckAction work
+ if (!rXPoly.IsControl(i)) rStat.NextPoint();
+ }
+ nCurrentPoint=rXPoly.GetPointCount()-1;
+ }
+ }
+ nCurrentPoint++;
+ rXPoly[nCurrentPoint]=rStat.GetNow();
+ }
+ if (eCmd==SdrCreateCmd::NextObject) {
+ if (rXPoly.GetPointCount()>=2) {
+ pU->bBezHasCtrl0=false;
+ // only a singular polygon may be opened, so close this
+ rXPoly[nCurrentPoint]=rXPoly[0];
+ XPolygon aXP;
+ aXP[0]=rStat.GetNow();
+ aPathPolygon.Insert(std::move(aXP));
+ }
+ }
+ }
+
+ sal_uInt16 nPolyCount=aPathPolygon.Count();
+ if (nPolyCount!=0) {
+ // delete last point, if necessary
+ if (eCmd==SdrCreateCmd::ForceEnd) {
+ XPolygon& rXP=aPathPolygon[nPolyCount-1];
+ sal_uInt16 nPointCount=rXP.GetPointCount();
+ if (nPointCount>=2) {
+ if (!rXP.IsControl(nPointCount-2)) {
+ if (rXP[nPointCount-1]==rXP[nPointCount-2]) {
+ rXP.Remove(nPointCount-1,1);
+ }
+ } else {
+ if (rXP[nPointCount-3]==rXP[nPointCount-2]) {
+ rXP.Remove(nPointCount-3,3);
+ }
+ }
+ }
+ }
+ for (sal_uInt16 nPolyNum=nPolyCount; nPolyNum>0;) {
+ nPolyNum--;
+ XPolygon& rXP=aPathPolygon[nPolyNum];
+ sal_uInt16 nPointCount=rXP.GetPointCount();
+ // delete polygons with too few points
+ if (nPolyNum<nPolyCount-1 || eCmd==SdrCreateCmd::ForceEnd) {
+ if (nPointCount<2) aPathPolygon.Remove(nPolyNum);
+ }
+ }
+ }
+ pU->ResetFormFlags();
+ bRet=eCmd==SdrCreateCmd::ForceEnd;
+ if (bRet) {
+ mbCreating=false;
+ rStat.SetUser(nullptr);
+ }
+ return bRet;
+}
+
+bool ImpPathForDragAndCreate::BckCreate(SdrDragStat const & rStat)
+{
+ ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
+ if (aPathPolygon.Count()>0) {
+ XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1];
+ sal_uInt16 nCurrentPoint=rXPoly.GetPointCount();
+ if (nCurrentPoint>0) {
+ nCurrentPoint--;
+ // make the last part of a bezier curve a line
+ rXPoly.Remove(nCurrentPoint,1);
+ if (nCurrentPoint>=3 && rXPoly.IsControl(nCurrentPoint-1)) {
+ // there should never be a bezier segment at the end, so this is just in case...
+ rXPoly.Remove(nCurrentPoint-1,1);
+ if (rXPoly.IsControl(nCurrentPoint-2)) rXPoly.Remove(nCurrentPoint-2,1);
+ }
+ }
+ nCurrentPoint=rXPoly.GetPointCount();
+ if (nCurrentPoint>=4) { // no bezier segment at the end
+ nCurrentPoint--;
+ if (rXPoly.IsControl(nCurrentPoint-1)) {
+ rXPoly.Remove(nCurrentPoint-1,1);
+ if (rXPoly.IsControl(nCurrentPoint-2)) rXPoly.Remove(nCurrentPoint-2,1);
+ }
+ }
+ if (rXPoly.GetPointCount()<2) {
+ aPathPolygon.Remove(aPathPolygon.Count()-1);
+ }
+ if (aPathPolygon.Count()>0) {
+ XPolygon& rLocalXPoly=aPathPolygon[aPathPolygon.Count()-1];
+ sal_uInt16 nLocalCurrentPoint=rLocalXPoly.GetPointCount();
+ if (nLocalCurrentPoint>0) {
+ nLocalCurrentPoint--;
+ rLocalXPoly[nLocalCurrentPoint]=rStat.GetNow();
+ }
+ }
+ }
+ pU->ResetFormFlags();
+ return aPathPolygon.Count()!=0;
+}
+
+void ImpPathForDragAndCreate::BrkCreate(SdrDragStat& rStat)
+{
+ aPathPolygon.Clear();
+ mbCreating=false;
+ rStat.SetUser(nullptr);
+}
+
+basegfx::B2DPolyPolygon ImpPathForDragAndCreate::TakeObjectPolyPolygon(const SdrDragStat& rDrag) const
+{
+ basegfx::B2DPolyPolygon aRetval(aPathPolygon.getB2DPolyPolygon());
+ SdrView* pView = rDrag.GetView();
+
+ if(pView && pView->IsUseIncompatiblePathCreateInterface())
+ return aRetval;
+
+ ImpPathCreateUser* pU = static_cast<ImpPathCreateUser*>(rDrag.GetUser());
+ basegfx::B2DPolygon aNewPolygon(aRetval.count() ? aRetval.getB2DPolygon(aRetval.count() - 1) : basegfx::B2DPolygon());
+
+ if(pU->IsFormFlag() && aNewPolygon.count() > 1)
+ {
+ // remove last segment and replace with current
+ // do not forget to rescue the previous control point which will be lost when
+ // the point it's associated with is removed
+ const sal_uInt32 nChangeIndex(aNewPolygon.count() - 2);
+ const basegfx::B2DPoint aSavedPrevCtrlPoint(aNewPolygon.getPrevControlPoint(nChangeIndex));
+
+ aNewPolygon.remove(nChangeIndex, 2);
+ aNewPolygon.append(pU->GetFormPoly().getB2DPolygon());
+
+ if(nChangeIndex < aNewPolygon.count())
+ {
+ // if really something was added, set the saved previous control point to the
+ // point where it belongs
+ aNewPolygon.setPrevControlPoint(nChangeIndex, aSavedPrevCtrlPoint);
+ }
+ }
+
+ if(aRetval.count())
+ {
+ aRetval.setB2DPolygon(aRetval.count() - 1, aNewPolygon);
+ }
+ else
+ {
+ aRetval.append(aNewPolygon);
+ }
+
+ return aRetval;
+}
+
+basegfx::B2DPolyPolygon ImpPathForDragAndCreate::TakeDragPolyPolygon(const SdrDragStat& rDrag)
+{
+ basegfx::B2DPolyPolygon aRetval;
+ SdrView* pView = rDrag.GetView();
+
+ if(pView && pView->IsUseIncompatiblePathCreateInterface())
+ return aRetval;
+
+ const ImpPathCreateUser* pU = static_cast<const ImpPathCreateUser*>(rDrag.GetUser());
+
+ if(pU && pU->bBezier && rDrag.IsMouseDown())
+ {
+ // no more XOR, no need for complicated helplines
+ basegfx::B2DPolygon aHelpline;
+ aHelpline.append(basegfx::B2DPoint(pU->aBezCtrl2.X(), pU->aBezCtrl2.Y()));
+ aHelpline.append(basegfx::B2DPoint(pU->aBezEnd.X(), pU->aBezEnd.Y()));
+ aRetval.append(aHelpline);
+ }
+
+ return aRetval;
+}
+
+PointerStyle ImpPathForDragAndCreate::GetCreatePointer() const
+{
+ switch (meObjectKind) {
+ case SdrObjKind::Line : return PointerStyle::DrawLine;
+ case SdrObjKind::Polygon : return PointerStyle::DrawPolygon;
+ case SdrObjKind::PolyLine : return PointerStyle::DrawPolygon;
+ case SdrObjKind::PathLine: return PointerStyle::DrawBezier;
+ case SdrObjKind::PathFill: return PointerStyle::DrawBezier;
+ case SdrObjKind::FreehandLine: return PointerStyle::DrawFreehand;
+ case SdrObjKind::FreehandFill: return PointerStyle::DrawFreehand;
+ case SdrObjKind::SplineLine: return PointerStyle::DrawFreehand;
+ case SdrObjKind::SplineFill: return PointerStyle::DrawFreehand;
+ case SdrObjKind::PathPoly: return PointerStyle::DrawPolygon;
+ case SdrObjKind::PathPolyLine: return PointerStyle::DrawPolygon;
+ default: break;
+ } // switch
+ return PointerStyle::Cross;
+}
+
+SdrPathObjGeoData::SdrPathObjGeoData()
+ : meKind(SdrObjKind::NONE)
+{
+}
+
+SdrPathObjGeoData::~SdrPathObjGeoData()
+{
+}
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrPathObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrPathObj>(*this);
+}
+
+
+SdrPathObj::SdrPathObj(
+ SdrModel& rSdrModel,
+ SdrObjKind eNewKind)
+: SdrTextObj(rSdrModel),
+ meKind(eNewKind)
+{
+ m_bClosedObj = IsClosed();
+}
+
+SdrPathObj::SdrPathObj(SdrModel& rSdrModel, SdrPathObj const & rSource)
+: SdrTextObj(rSdrModel, rSource),
+ meKind(rSource.meKind)
+{
+ m_bClosedObj = IsClosed();
+ maPathPolygon = rSource.GetPathPoly();
+}
+
+SdrPathObj::SdrPathObj(
+ SdrModel& rSdrModel,
+ SdrObjKind eNewKind,
+ const basegfx::B2DPolyPolygon& rPathPoly)
+: SdrTextObj(rSdrModel),
+ maPathPolygon(rPathPoly),
+ meKind(eNewKind)
+{
+ m_bClosedObj = IsClosed();
+ ImpForceKind();
+}
+
+SdrPathObj::~SdrPathObj() = default;
+
+static bool lcl_ImpIsLine(const basegfx::B2DPolyPolygon& rPolyPolygon)
+{
+ return (1 == rPolyPolygon.count() && 2 == rPolyPolygon.getB2DPolygon(0).count());
+}
+
+static tools::Rectangle lcl_ImpGetBoundRect(const basegfx::B2DPolyPolygon& rPolyPolygon)
+{
+ basegfx::B2DRange aRange(basegfx::utils::getRange(rPolyPolygon));
+
+ if (aRange.isEmpty())
+ return tools::Rectangle();
+
+ return tools::Rectangle(
+ FRound(aRange.getMinX()), FRound(aRange.getMinY()),
+ FRound(aRange.getMaxX()), FRound(aRange.getMaxY()));
+}
+
+void SdrPathObj::ImpForceLineAngle()
+{
+ if(SdrObjKind::Line != meKind || !lcl_ImpIsLine(GetPathPoly()))
+ return;
+
+ const basegfx::B2DPolygon aPoly(GetPathPoly().getB2DPolygon(0));
+ const basegfx::B2DPoint aB2DPoint0(aPoly.getB2DPoint(0));
+ const basegfx::B2DPoint aB2DPoint1(aPoly.getB2DPoint(1));
+ const Point aPoint0(FRound(aB2DPoint0.getX()), FRound(aB2DPoint0.getY()));
+ const Point aPoint1(FRound(aB2DPoint1.getX()), FRound(aB2DPoint1.getY()));
+ const basegfx::B2DPoint aB2DDelt(aB2DPoint1 - aB2DPoint0);
+ const Point aDelt(FRound(aB2DDelt.getX()), FRound(aB2DDelt.getY()));
+
+ maGeo.nRotationAngle=GetAngle(aDelt);
+ maGeo.nShearAngle=0_deg100;
+ maGeo.RecalcSinCos();
+ maGeo.RecalcTan();
+
+ // for SdrTextObj, keep aRect up to date
+ maRect = tools::Rectangle::Justify(aPoint0, aPoint1);
+}
+
+void SdrPathObj::ImpForceKind()
+{
+ if (meKind==SdrObjKind::PathPolyLine) meKind=SdrObjKind::PolyLine;
+ if (meKind==SdrObjKind::PathPoly) meKind=SdrObjKind::Polygon;
+
+ if(GetPathPoly().areControlPointsUsed())
+ {
+ switch (meKind)
+ {
+ case SdrObjKind::Line: meKind=SdrObjKind::PathLine; break;
+ case SdrObjKind::PolyLine: meKind=SdrObjKind::PathLine; break;
+ case SdrObjKind::Polygon: meKind=SdrObjKind::PathFill; break;
+ default: break;
+ }
+ }
+ else
+ {
+ switch (meKind)
+ {
+ case SdrObjKind::PathLine: meKind=SdrObjKind::PolyLine; break;
+ case SdrObjKind::FreehandLine: meKind=SdrObjKind::PolyLine; break;
+ case SdrObjKind::PathFill: meKind=SdrObjKind::Polygon; break;
+ case SdrObjKind::FreehandFill: meKind=SdrObjKind::Polygon; break;
+ default: break;
+ }
+ }
+
+ if (meKind==SdrObjKind::Line && !lcl_ImpIsLine(GetPathPoly())) meKind=SdrObjKind::PolyLine;
+ if (meKind==SdrObjKind::PolyLine && lcl_ImpIsLine(GetPathPoly())) meKind=SdrObjKind::Line;
+
+ m_bClosedObj=IsClosed();
+
+ if (meKind==SdrObjKind::Line)
+ {
+ ImpForceLineAngle();
+ }
+ else
+ {
+ // #i10659#, for polys with more than 2 points.
+
+ // Here i again need to fix something, because when Path-Polys are Copy-Pasted
+ // between Apps with different measurements (e.g. 100TH_MM and TWIPS) there is
+ // a scaling loop started from SdrExchangeView::Paste. In itself, this is not
+ // wrong, but aRect is wrong here and not even updated by RecalcSnapRect(). If
+ // this is the case, some size needs to be set here in aRect to avoid that the cycle
+ // through Rect2Poly - Poly2Rect does something badly wrong since that cycle is
+ // BASED on aRect. That cycle is triggered in SdrTextObj::NbcResize() which is called
+ // from the local Resize() implementation.
+
+ // Basic problem is that the member aRect in SdrTextObj basically is a unrotated
+ // text rectangle for the text object itself and methods at SdrTextObj do handle it
+ // in that way. Many draw objects derived from SdrTextObj 'abuse' aRect as SnapRect
+ // which is basically wrong. To make the SdrText methods which deal with aRect directly
+ // work it is necessary to always keep aRect updated. This e.g. not done after a Clone()
+ // command for SdrPathObj. Since adding this update mechanism with #101412# to
+ // ImpForceLineAngle() for lines was very successful, i add it to where ImpForceLineAngle()
+ // was called, once here below and once on a 2nd place below.
+
+ // #i10659# for SdrTextObj, keep aRect up to date
+ if(GetPathPoly().count())
+ {
+ maRect = lcl_ImpGetBoundRect(GetPathPoly());
+ }
+ }
+
+ // #i75974# adapt polygon state to object type. This may include a reinterpretation
+ // of a closed geometry as open one, but with identical first and last point
+ for(auto& rPolygon : maPathPolygon)
+ {
+ if(IsClosed() != rPolygon.isClosed())
+ {
+ // #i80213# really change polygon geometry; else e.g. the last point which
+ // needs to be identical with the first one will be missing when opening
+ // due to OBJ_PATH type
+ if(rPolygon.isClosed())
+ {
+ basegfx::utils::openWithGeometryChange(rPolygon);
+ }
+ else
+ {
+ basegfx::utils::closeWithGeometryChange(rPolygon);
+ }
+ }
+ }
+}
+
+void SdrPathObj::ImpSetClosed(bool bClose)
+{
+ if(bClose)
+ {
+ switch (meKind)
+ {
+ case SdrObjKind::Line : meKind=SdrObjKind::Polygon; break;
+ case SdrObjKind::PolyLine : meKind=SdrObjKind::Polygon; break;
+ case SdrObjKind::PathLine: meKind=SdrObjKind::PathFill; break;
+ case SdrObjKind::FreehandLine: meKind=SdrObjKind::FreehandFill; break;
+ case SdrObjKind::SplineLine: meKind=SdrObjKind::SplineFill; break;
+ default: break;
+ }
+
+ m_bClosedObj = true;
+ }
+ else
+ {
+ switch (meKind)
+ {
+ case SdrObjKind::Polygon : meKind=SdrObjKind::PolyLine; break;
+ case SdrObjKind::PathFill: meKind=SdrObjKind::PathLine; break;
+ case SdrObjKind::FreehandFill: meKind=SdrObjKind::FreehandLine; break;
+ case SdrObjKind::SplineFill: meKind=SdrObjKind::SplineLine; break;
+ default: break;
+ }
+
+ m_bClosedObj = false;
+ }
+
+ ImpForceKind();
+}
+
+void SdrPathObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bNoContortion=false;
+
+ bool bCanConv = !HasText() || ImpCanConvTextToCurve();
+ bool bIsPath = IsBezier() || IsSpline();
+
+ rInfo.bEdgeRadiusAllowed = false;
+ rInfo.bCanConvToPath = bCanConv && !bIsPath;
+ rInfo.bCanConvToPoly = bCanConv && bIsPath;
+ rInfo.bCanConvToContour = !IsFontwork() && (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
+}
+
+SdrObjKind SdrPathObj::GetObjIdentifier() const
+{
+ return meKind;
+}
+
+SdrPathObj* SdrPathObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrPathObj(rTargetModel, *this);
+}
+
+OUString SdrPathObj::TakeObjNameSingul() const
+{
+ OUString sName;
+
+ if(SdrObjKind::Line == meKind)
+ {
+ TranslateId pId(STR_ObjNameSingulLINE);
+
+ if(lcl_ImpIsLine(GetPathPoly()))
+ {
+ const basegfx::B2DPolygon aPoly(GetPathPoly().getB2DPolygon(0));
+ const basegfx::B2DPoint aB2DPoint0(aPoly.getB2DPoint(0));
+ const basegfx::B2DPoint aB2DPoint1(aPoly.getB2DPoint(1));
+
+ if(aB2DPoint0 != aB2DPoint1)
+ {
+ if(aB2DPoint0.getY() == aB2DPoint1.getY())
+ {
+ pId = STR_ObjNameSingulLINE_Hori;
+ }
+ else if(aB2DPoint0.getX() == aB2DPoint1.getX())
+ {
+ pId = STR_ObjNameSingulLINE_Vert;
+ }
+ else
+ {
+ const double fDx(fabs(aB2DPoint0.getX() - aB2DPoint1.getX()));
+ const double fDy(fabs(aB2DPoint0.getY() - aB2DPoint1.getY()));
+
+ if(fDx == fDy)
+ {
+ pId = STR_ObjNameSingulLINE_Diag;
+ }
+ }
+ }
+ }
+
+ sName = SvxResId(pId);
+ }
+ else if(SdrObjKind::PolyLine == meKind || SdrObjKind::Polygon == meKind)
+ {
+ const bool bClosed(SdrObjKind::Polygon == meKind);
+ TranslateId pId;
+
+ if(mpDAC && mpDAC->IsCreating())
+ {
+ if(bClosed)
+ {
+ pId = STR_ObjNameSingulPOLY;
+ }
+ else
+ {
+ pId = STR_ObjNameSingulPLIN;
+ }
+
+ sName = SvxResId(pId);
+ }
+ else
+ {
+ // get point count
+ sal_uInt32 nPointCount(0);
+
+ for(auto const& rPolygon : GetPathPoly())
+ {
+ nPointCount += rPolygon.count();
+ }
+
+ if(bClosed)
+ {
+ pId = STR_ObjNameSingulPOLY_PointCount;
+ }
+ else
+ {
+ pId = STR_ObjNameSingulPLIN_PointCount;
+ }
+
+ // #i96537#
+ sName = SvxResId(pId).replaceFirst("%2", OUString::number(nPointCount));
+ }
+ }
+ else
+ {
+ switch (meKind)
+ {
+ case SdrObjKind::PathLine: sName = SvxResId(STR_ObjNameSingulPATHLINE); break;
+ case SdrObjKind::FreehandLine: sName = SvxResId(STR_ObjNameSingulFREELINE); break;
+ case SdrObjKind::SplineLine: sName = SvxResId(STR_ObjNameSingulNATSPLN); break;
+ case SdrObjKind::PathFill: sName = SvxResId(STR_ObjNameSingulPATHFILL); break;
+ case SdrObjKind::FreehandFill: sName = SvxResId(STR_ObjNameSingulFREEFILL); break;
+ case SdrObjKind::SplineFill: sName = SvxResId(STR_ObjNameSingulPERSPLN); break;
+ default: break;
+ }
+ }
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+OUString SdrPathObj::TakeObjNamePlural() const
+{
+ OUString sName;
+ switch(meKind)
+ {
+ case SdrObjKind::Line : sName=SvxResId(STR_ObjNamePluralLINE ); break;
+ case SdrObjKind::PolyLine : sName=SvxResId(STR_ObjNamePluralPLIN ); break;
+ case SdrObjKind::Polygon : sName=SvxResId(STR_ObjNamePluralPOLY ); break;
+ case SdrObjKind::PathLine: sName=SvxResId(STR_ObjNamePluralPATHLINE); break;
+ case SdrObjKind::FreehandLine: sName=SvxResId(STR_ObjNamePluralFREELINE); break;
+ case SdrObjKind::SplineLine: sName=SvxResId(STR_ObjNamePluralNATSPLN); break;
+ case SdrObjKind::PathFill: sName=SvxResId(STR_ObjNamePluralPATHFILL); break;
+ case SdrObjKind::FreehandFill: sName=SvxResId(STR_ObjNamePluralFREEFILL); break;
+ case SdrObjKind::SplineFill: sName=SvxResId(STR_ObjNamePluralPERSPLN); break;
+ default: break;
+ }
+ return sName;
+}
+
+basegfx::B2DPolyPolygon SdrPathObj::TakeXorPoly() const
+{
+ return GetPathPoly();
+}
+
+sal_uInt32 SdrPathObj::GetHdlCount() const
+{
+ sal_uInt32 nRetval(0);
+
+ for(auto const& rPolygon : GetPathPoly())
+ {
+ nRetval += rPolygon.count();
+ }
+
+ return nRetval;
+}
+
+void SdrPathObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ // keep old stuff to be able to keep old SdrHdl stuff, too
+ const XPolyPolygon aOldPathPolygon(GetPathPoly());
+ sal_uInt16 nPolyCnt=aOldPathPolygon.Count();
+ bool bClosed=IsClosed();
+ sal_uInt16 nIdx=0;
+
+ for (sal_uInt16 i=0; i<nPolyCnt; i++) {
+ const XPolygon& rXPoly=aOldPathPolygon.GetObject(i);
+ sal_uInt16 nPntCnt=rXPoly.GetPointCount();
+ if (bClosed && nPntCnt>1) nPntCnt--;
+
+ for (sal_uInt16 j=0; j<nPntCnt; j++) {
+ if (rXPoly.GetFlags(j)!=PolyFlags::Control) {
+ const Point& rPnt=rXPoly[j];
+ std::unique_ptr<SdrHdl> pHdl(new SdrHdl(rPnt,SdrHdlKind::Poly));
+ pHdl->SetPolyNum(i);
+ pHdl->SetPointNum(j);
+ pHdl->Set1PixMore(j==0);
+ pHdl->SetSourceHdlNum(nIdx);
+ nIdx++;
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+ }
+ }
+}
+
+void SdrPathObj::AddToPlusHdlList(SdrHdlList& rHdlList, SdrHdl& rHdl) const
+{
+ // keep old stuff to be able to keep old SdrHdl stuff, too
+ const XPolyPolygon aOldPathPolygon(GetPathPoly());
+ sal_uInt16 nPnt = static_cast<sal_uInt16>(rHdl.GetPointNum());
+ sal_uInt16 nPolyNum = static_cast<sal_uInt16>(rHdl.GetPolyNum());
+
+ if (nPolyNum>=aOldPathPolygon.Count())
+ return;
+
+ const XPolygon& rXPoly = aOldPathPolygon[nPolyNum];
+ sal_uInt16 nPntMax = rXPoly.GetPointCount();
+
+ if (nPntMax<=0)
+ return;
+ nPntMax--;
+ if (nPnt>nPntMax)
+ return;
+
+ // calculate the number of plus points
+ sal_uInt16 nCnt = 0;
+ if (rXPoly.GetFlags(nPnt)!=PolyFlags::Control)
+ {
+ if (nPnt==0 && IsClosed())
+ nPnt=nPntMax;
+ if (nPnt>0 && rXPoly.GetFlags(nPnt-1)==PolyFlags::Control)
+ nCnt++;
+ if (nPnt==nPntMax && IsClosed())
+ nPnt=0;
+ if (nPnt<nPntMax && rXPoly.GetFlags(nPnt+1)==PolyFlags::Control)
+ nCnt++;
+ }
+
+ // construct the plus points
+ for (sal_uInt32 nPlusNum = 0; nPlusNum < nCnt; ++nPlusNum)
+ {
+ nPnt = static_cast<sal_uInt16>(rHdl.GetPointNum());
+ std::unique_ptr<SdrHdl> pHdl(new SdrHdlBezWgt(&rHdl));
+ pHdl->SetPolyNum(rHdl.GetPolyNum());
+
+ if (nPnt==0 && IsClosed())
+ nPnt=nPntMax;
+ if (nPnt>0 && rXPoly.GetFlags(nPnt-1)==PolyFlags::Control && nPlusNum==0)
+ {
+ pHdl->SetPos(rXPoly[nPnt-1]);
+ pHdl->SetPointNum(nPnt-1);
+ }
+ else
+ {
+ if (nPnt==nPntMax && IsClosed())
+ nPnt=0;
+ if (nPnt<rXPoly.GetPointCount()-1 && rXPoly.GetFlags(nPnt+1)==PolyFlags::Control)
+ {
+ pHdl->SetPos(rXPoly[nPnt+1]);
+ pHdl->SetPointNum(nPnt+1);
+ }
+ }
+
+ pHdl->SetSourceHdlNum(rHdl.GetSourceHdlNum());
+ pHdl->SetPlusHdl(true);
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+}
+
+// tdf#123321: Make sure that SdrPathObj (e.g. line) has big enough extent for
+// visibility. This is realised by ensuring GetLogicRect() is the same as
+// GetSnapRect() for the SdrPathObj. Other SdrTextObj objects like
+// SdrObjCustomShape will still use a different version of this method that
+// does not consider the rotation. Otherwise, the rotated SdrObjCustomShape
+// would become mistakenly larger after save and reload (tdf#91687).
+// The invocation of the GetLogicRect() method that caused tdf#123321 was in
+// PlcDrawObj::WritePlc().
+const tools::Rectangle &SdrPathObj::GetLogicRect() const
+{
+ return GetSnapRect();
+}
+
+// dragging
+
+bool SdrPathObj::hasSpecialDrag() const
+{
+ return true;
+}
+
+bool SdrPathObj::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ ImpPathForDragAndCreate aDragAndCreate(*const_cast<SdrPathObj*>(this));
+
+ return aDragAndCreate.beginPathDrag(rDrag);
+}
+
+bool SdrPathObj::applySpecialDrag(SdrDragStat& rDrag)
+{
+ ImpPathForDragAndCreate aDragAndCreate(*this);
+ bool bRetval(aDragAndCreate.beginPathDrag(rDrag));
+
+ if(bRetval)
+ {
+ bRetval = aDragAndCreate.movePathDrag(rDrag);
+ }
+
+ if(bRetval)
+ {
+ bRetval = aDragAndCreate.endPathDrag(rDrag);
+ }
+
+ if(bRetval)
+ {
+ NbcSetPathPoly(aDragAndCreate.getModifiedPolyPolygon());
+ }
+
+ return bRetval;
+}
+
+OUString SdrPathObj::getSpecialDragComment(const SdrDragStat& rDrag) const
+{
+ OUString aRetval;
+
+ if(mpDAC)
+ {
+ // #i103058# also get a comment when in creation
+ const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
+
+ if(bCreateComment)
+ {
+ aRetval = mpDAC->getSpecialDragComment(rDrag);
+ }
+ }
+ else
+ {
+ ImpPathForDragAndCreate aDragAndCreate(*const_cast<SdrPathObj*>(this));
+ bool bDidWork(aDragAndCreate.beginPathDrag(rDrag));
+
+ if(bDidWork)
+ {
+ aRetval = aDragAndCreate.getSpecialDragComment(rDrag);
+ }
+ }
+
+ return aRetval;
+}
+
+basegfx::B2DPolyPolygon SdrPathObj::getSpecialDragPoly(const SdrDragStat& rDrag) const
+{
+ basegfx::B2DPolyPolygon aRetval;
+ ImpPathForDragAndCreate aDragAndCreate(*const_cast<SdrPathObj*>(this));
+ bool bDidWork(aDragAndCreate.beginPathDrag(rDrag));
+
+ if(bDidWork)
+ {
+ aRetval = aDragAndCreate.getSpecialDragPoly(rDrag);
+ }
+
+ return aRetval;
+}
+
+// creation
+
+bool SdrPathObj::BegCreate(SdrDragStat& rStat)
+{
+ mpDAC.reset();
+ impGetDAC().BegCreate(rStat);
+ return true;
+}
+
+bool SdrPathObj::MovCreate(SdrDragStat& rStat)
+{
+ return impGetDAC().MovCreate(rStat);
+}
+
+bool SdrPathObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ bool bRetval(impGetDAC().EndCreate(rStat, eCmd));
+
+ if(bRetval && mpDAC)
+ {
+ SetPathPoly(mpDAC->getModifiedPolyPolygon());
+
+ // #i75974# Check for AutoClose feature. Moved here from ImpPathForDragAndCreate::EndCreate
+ // to be able to use the type-changing ImpSetClosed method
+ if(!IsClosedObj())
+ {
+ SdrView* pView = rStat.GetView();
+
+ if(pView && !pView->IsUseIncompatiblePathCreateInterface())
+ {
+ OutputDevice* pOut = pView->GetFirstOutputDevice();
+
+ if(pOut)
+ {
+ if(GetPathPoly().count())
+ {
+ const basegfx::B2DPolygon aCandidate(GetPathPoly().getB2DPolygon(0));
+
+ if(aCandidate.count() > 2)
+ {
+ // check distance of first and last point
+ const sal_Int32 nCloseDist(pOut->PixelToLogic(Size(pView->GetAutoCloseDistPix(), 0)).Width());
+ const basegfx::B2DVector aDistVector(aCandidate.getB2DPoint(aCandidate.count() - 1) - aCandidate.getB2DPoint(0));
+
+ if(aDistVector.getLength() <= static_cast<double>(nCloseDist))
+ {
+ // close it
+ ImpSetClosed(true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ mpDAC.reset();
+ }
+
+ return bRetval;
+}
+
+bool SdrPathObj::BckCreate(SdrDragStat& rStat)
+{
+ return impGetDAC().BckCreate(rStat);
+}
+
+void SdrPathObj::BrkCreate(SdrDragStat& rStat)
+{
+ impGetDAC().BrkCreate(rStat);
+ mpDAC.reset();
+}
+
+// polygons
+
+basegfx::B2DPolyPolygon SdrPathObj::TakeCreatePoly(const SdrDragStat& rDrag) const
+{
+ basegfx::B2DPolyPolygon aRetval;
+
+ if(mpDAC)
+ {
+ aRetval = mpDAC->TakeObjectPolyPolygon(rDrag);
+ aRetval.append(ImpPathForDragAndCreate::TakeDragPolyPolygon(rDrag));
+ }
+
+ return aRetval;
+}
+
+// during drag or create, allow accessing the so-far created/modified polyPolygon
+basegfx::B2DPolyPolygon SdrPathObj::getObjectPolyPolygon(const SdrDragStat& rDrag) const
+{
+ basegfx::B2DPolyPolygon aRetval;
+
+ if(mpDAC)
+ {
+ aRetval = mpDAC->TakeObjectPolyPolygon(rDrag);
+ }
+
+ return aRetval;
+}
+
+basegfx::B2DPolyPolygon SdrPathObj::getDragPolyPolygon(const SdrDragStat& rDrag) const
+{
+ basegfx::B2DPolyPolygon aRetval;
+
+ if(mpDAC)
+ {
+ aRetval = ImpPathForDragAndCreate::TakeDragPolyPolygon(rDrag);
+ }
+
+ return aRetval;
+}
+
+PointerStyle SdrPathObj::GetCreatePointer() const
+{
+ return impGetDAC().GetCreatePointer();
+}
+
+void SdrPathObj::NbcMove(const Size& rSiz)
+{
+ maPathPolygon.transform(basegfx::utils::createTranslateB2DHomMatrix(rSiz.Width(), rSiz.Height()));
+
+ // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
+ SdrTextObj::NbcMove(rSiz);
+}
+
+void SdrPathObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ const double fResizeX(xFact);
+ const double fResizeY(yFact);
+
+ if(basegfx::fTools::equal(fResizeX, 1.0) && basegfx::fTools::equal(fResizeY, 1.0))
+ {
+ // tdf#106792 avoid numerical unprecisions: If both scale factors are 1.0, do not
+ // manipulate at all - that may change maGeo rapidly (and wrongly) in
+ // SdrTextObj::NbcResize. Combined with the UNO API trying to not 'apply'
+ // a rotation but to manipulate the existing one, this is fatal. So just
+ // avoid this error as long as we have to deal with imprecise geometry
+ // manipulations
+ return;
+ }
+
+ basegfx::B2DHomMatrix aTrans(basegfx::utils::createTranslateB2DHomMatrix(-rRef.X(), -rRef.Y()));
+ aTrans = basegfx::utils::createScaleTranslateB2DHomMatrix(
+ double(xFact), double(yFact), rRef.X(), rRef.Y()) * aTrans;
+ maPathPolygon.transform(aTrans);
+
+ // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
+ SdrTextObj::NbcResize(rRef,xFact,yFact);
+}
+
+void SdrPathObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ // Thank JOE, the angles are defined mirrored to the mathematical meanings
+ const basegfx::B2DHomMatrix aTrans(
+ basegfx::utils::createRotateAroundPoint(rRef.X(), rRef.Y(), -toRadians(nAngle)));
+ maPathPolygon.transform(aTrans);
+
+ // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
+ SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
+}
+
+void SdrPathObj::NbcShear(const Point& rRefPnt, Degree100 nAngle, double fTan, bool bVShear)
+{
+ basegfx::B2DHomMatrix aTrans(basegfx::utils::createTranslateB2DHomMatrix(-rRefPnt.X(), -rRefPnt.Y()));
+
+ if(bVShear)
+ {
+ // Thank JOE, the angles are defined mirrored to the mathematical meanings
+ aTrans.shearY(-fTan);
+ }
+ else
+ {
+ aTrans.shearX(-fTan);
+ }
+
+ aTrans.translate(rRefPnt.X(), rRefPnt.Y());
+ maPathPolygon.transform(aTrans);
+
+ // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
+ SdrTextObj::NbcShear(rRefPnt,nAngle,fTan,bVShear);
+}
+
+void SdrPathObj::NbcMirror(const Point& rRefPnt1, const Point& rRefPnt2)
+{
+ const double fDiffX(rRefPnt2.X() - rRefPnt1.X());
+ const double fDiffY(rRefPnt2.Y() - rRefPnt1.Y());
+ const double fRot(atan2(fDiffY, fDiffX));
+ basegfx::B2DHomMatrix aTrans(basegfx::utils::createTranslateB2DHomMatrix(-rRefPnt1.X(), -rRefPnt1.Y()));
+ aTrans.rotate(-fRot);
+ aTrans.scale(1.0, -1.0);
+ aTrans.rotate(fRot);
+ aTrans.translate(rRefPnt1.X(), rRefPnt1.Y());
+ maPathPolygon.transform(aTrans);
+
+ // Do Joe's special handling for lines when mirroring, too
+ ImpForceKind();
+
+ // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints)
+ SdrTextObj::NbcMirror(rRefPnt1,rRefPnt2);
+}
+
+void SdrPathObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
+{
+ if(!maGeo.nRotationAngle)
+ {
+ rRect = GetSnapRect();
+ }
+ else
+ {
+ XPolyPolygon aXPP(GetPathPoly());
+ RotateXPoly(aXPP,Point(),-maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ rRect=aXPP.GetBoundRect();
+ Point aTmp(rRect.TopLeft());
+ RotatePoint(aTmp,Point(),maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ aTmp-=rRect.TopLeft();
+ rRect.Move(aTmp.X(),aTmp.Y());
+ }
+}
+
+void SdrPathObj::RecalcSnapRect()
+{
+ if(GetPathPoly().count())
+ {
+ maSnapRect = lcl_ImpGetBoundRect(GetPathPoly());
+ }
+}
+
+void SdrPathObj::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aOld(GetSnapRect());
+ if (aOld.IsEmpty())
+ {
+ Fraction aX(1,1);
+ Fraction aY(1,1);
+ NbcResize(aOld.TopLeft(), aX, aY);
+ NbcMove(Size(rRect.Left() - aOld.Left(), rRect.Top() - aOld.Top()));
+ return;
+ }
+
+ // Take empty into account when calculating scale factors
+ tools::Long nMulX = rRect.IsWidthEmpty() ? 0 : rRect.Right() - rRect.Left();
+
+ tools::Long nDivX = aOld.Right() - aOld.Left();
+
+ // Take empty into account when calculating scale factors
+ tools::Long nMulY = rRect.IsHeightEmpty() ? 0 : rRect.Bottom() - rRect.Top();
+
+ tools::Long nDivY = aOld.Bottom() - aOld.Top();
+ if ( nDivX == 0 ) { nMulX = 1; nDivX = 1; }
+ if ( nDivY == 0 ) { nMulY = 1; nDivY = 1; }
+ if ( nDivX == nMulX ) { nMulX = 1; nDivX = 1; }
+ if ( nDivY == nMulY ) { nMulY = 1; nDivY = 1; }
+ Fraction aX(nMulX,nDivX);
+ Fraction aY(nMulY,nDivY);
+ NbcResize(aOld.TopLeft(), aX, aY);
+ NbcMove(Size(rRect.Left() - aOld.Left(), rRect.Top() - aOld.Top()));
+}
+
+sal_uInt32 SdrPathObj::GetSnapPointCount() const
+{
+ return GetHdlCount();
+}
+
+Point SdrPathObj::GetSnapPoint(sal_uInt32 nSnapPnt) const
+{
+ sal_uInt32 nPoly,nPnt;
+ if(!PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nSnapPnt, nPoly, nPnt))
+ {
+ SAL_WARN("svx", "SdrPathObj::GetSnapPoint: Point nSnapPnt does not exist.");
+ }
+
+ const basegfx::B2DPoint aB2DPoint(GetPathPoly().getB2DPolygon(nPoly).getB2DPoint(nPnt));
+ return Point(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
+}
+
+bool SdrPathObj::IsPolyObj() const
+{
+ return true;
+}
+
+sal_uInt32 SdrPathObj::GetPointCount() const
+{
+ sal_uInt32 nRetval(0);
+
+ for(auto const& rPolygon : GetPathPoly())
+ {
+ nRetval += rPolygon.count();
+ }
+
+ return nRetval;
+}
+
+Point SdrPathObj::GetPoint(sal_uInt32 nHdlNum) const
+{
+ Point aRetval;
+ sal_uInt32 nPoly,nPnt;
+
+ if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum, nPoly, nPnt))
+ {
+ const basegfx::B2DPolygon aPoly(GetPathPoly().getB2DPolygon(nPoly));
+ const basegfx::B2DPoint aPoint(aPoly.getB2DPoint(nPnt));
+ aRetval = Point(FRound(aPoint.getX()), FRound(aPoint.getY()));
+ }
+
+ return aRetval;
+}
+
+void SdrPathObj::NbcSetPoint(const Point& rPnt, sal_uInt32 nHdlNum)
+{
+ sal_uInt32 nPoly,nPnt;
+
+ if(!PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum, nPoly, nPnt))
+ return;
+
+ basegfx::B2DPolygon aNewPolygon(GetPathPoly().getB2DPolygon(nPoly));
+ aNewPolygon.setB2DPoint(nPnt, basegfx::B2DPoint(rPnt.X(), rPnt.Y()));
+ maPathPolygon.setB2DPolygon(nPoly, aNewPolygon);
+
+ if(meKind==SdrObjKind::Line)
+ {
+ ImpForceLineAngle();
+ }
+ else
+ {
+ if(GetPathPoly().count())
+ {
+ // #i10659# for SdrTextObj, keep aRect up to date
+ maRect = lcl_ImpGetBoundRect(GetPathPoly());
+ }
+ }
+
+ SetBoundAndSnapRectsDirty();
+}
+
+sal_uInt32 SdrPathObj::NbcInsPointOld(const Point& rPos, bool bNewObj)
+{
+ sal_uInt32 nNewHdl;
+
+ if(bNewObj)
+ {
+ nNewHdl = NbcInsPoint(rPos, true);
+ }
+ else
+ {
+ // look for smallest distance data
+ const basegfx::B2DPoint aTestPoint(rPos.X(), rPos.Y());
+ sal_uInt32 nSmallestPolyIndex(0);
+ sal_uInt32 nSmallestEdgeIndex(0);
+ double fSmallestCut;
+ basegfx::utils::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint, nSmallestPolyIndex, nSmallestEdgeIndex, fSmallestCut);
+
+ nNewHdl = NbcInsPoint(rPos, false);
+ }
+
+ ImpForceKind();
+ return nNewHdl;
+}
+
+sal_uInt32 SdrPathObj::NbcInsPoint(const Point& rPos, bool bNewObj)
+{
+ sal_uInt32 nNewHdl;
+
+ if(bNewObj)
+ {
+ basegfx::B2DPolygon aNewPoly;
+ const basegfx::B2DPoint aPoint(rPos.X(), rPos.Y());
+ aNewPoly.append(aPoint);
+ aNewPoly.setClosed(IsClosed());
+ maPathPolygon.append(aNewPoly);
+ SetBoundAndSnapRectsDirty();
+ nNewHdl = GetHdlCount();
+ }
+ else
+ {
+ // look for smallest distance data
+ const basegfx::B2DPoint aTestPoint(rPos.X(), rPos.Y());
+ sal_uInt32 nSmallestPolyIndex(0);
+ sal_uInt32 nSmallestEdgeIndex(0);
+ double fSmallestCut;
+ basegfx::utils::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint, nSmallestPolyIndex, nSmallestEdgeIndex, fSmallestCut);
+ basegfx::B2DPolygon aCandidate(GetPathPoly().getB2DPolygon(nSmallestPolyIndex));
+ const bool bBefore(!aCandidate.isClosed() && 0 == nSmallestEdgeIndex && 0.0 == fSmallestCut);
+ const bool bAfter(!aCandidate.isClosed() && aCandidate.count() == nSmallestEdgeIndex + 2 && 1.0 == fSmallestCut);
+
+ if(bBefore)
+ {
+ // before first point
+ aCandidate.insert(0, aTestPoint);
+
+ if(aCandidate.areControlPointsUsed())
+ {
+ if(aCandidate.isNextControlPointUsed(1))
+ {
+ aCandidate.setNextControlPoint(0, interpolate(aTestPoint, aCandidate.getB2DPoint(1), (1.0 / 3.0)));
+ aCandidate.setPrevControlPoint(1, interpolate(aTestPoint, aCandidate.getB2DPoint(1), (2.0 / 3.0)));
+ }
+ }
+
+ nNewHdl = 0;
+ }
+ else if(bAfter)
+ {
+ // after last point
+ aCandidate.append(aTestPoint);
+
+ if(aCandidate.areControlPointsUsed())
+ {
+ if(aCandidate.isPrevControlPointUsed(aCandidate.count() - 2))
+ {
+ aCandidate.setNextControlPoint(aCandidate.count() - 2, interpolate(aCandidate.getB2DPoint(aCandidate.count() - 2), aTestPoint, (1.0 / 3.0)));
+ aCandidate.setPrevControlPoint(aCandidate.count() - 1, interpolate(aCandidate.getB2DPoint(aCandidate.count() - 2), aTestPoint, (2.0 / 3.0)));
+ }
+ }
+
+ nNewHdl = aCandidate.count() - 1;
+ }
+ else
+ {
+ // in between
+ bool bSegmentSplit(false);
+ const sal_uInt32 nNextIndex((nSmallestEdgeIndex + 1) % aCandidate.count());
+
+ if(aCandidate.areControlPointsUsed())
+ {
+ if(aCandidate.isNextControlPointUsed(nSmallestEdgeIndex) || aCandidate.isPrevControlPointUsed(nNextIndex))
+ {
+ bSegmentSplit = true;
+ }
+ }
+
+ if(bSegmentSplit)
+ {
+ // rebuild original segment to get the split data
+ basegfx::B2DCubicBezier aBezierA, aBezierB;
+ const basegfx::B2DCubicBezier aBezier(
+ aCandidate.getB2DPoint(nSmallestEdgeIndex),
+ aCandidate.getNextControlPoint(nSmallestEdgeIndex),
+ aCandidate.getPrevControlPoint(nNextIndex),
+ aCandidate.getB2DPoint(nNextIndex));
+
+ // split and insert hit point
+ aBezier.split(fSmallestCut, &aBezierA, &aBezierB);
+ aCandidate.insert(nSmallestEdgeIndex + 1, aTestPoint);
+
+ // since we inserted hit point and not split point, we need to add an offset
+ // to the control points to get the C1 continuity we want to achieve
+ const basegfx::B2DVector aOffset(aTestPoint - aBezierA.getEndPoint());
+ aCandidate.setNextControlPoint(nSmallestEdgeIndex, aBezierA.getControlPointA() + aOffset);
+ aCandidate.setPrevControlPoint(nSmallestEdgeIndex + 1, aBezierA.getControlPointB() + aOffset);
+ aCandidate.setNextControlPoint(nSmallestEdgeIndex + 1, aBezierB.getControlPointA() + aOffset);
+ aCandidate.setPrevControlPoint((nSmallestEdgeIndex + 2) % aCandidate.count(), aBezierB.getControlPointB() + aOffset);
+ }
+ else
+ {
+ aCandidate.insert(nSmallestEdgeIndex + 1, aTestPoint);
+ }
+
+ nNewHdl = nSmallestEdgeIndex + 1;
+ }
+
+ maPathPolygon.setB2DPolygon(nSmallestPolyIndex, aCandidate);
+
+ // create old polygon index from it
+ for(sal_uInt32 a(0); a < nSmallestPolyIndex; a++)
+ {
+ nNewHdl += GetPathPoly().getB2DPolygon(a).count();
+ }
+ }
+
+ ImpForceKind();
+ return nNewHdl;
+}
+
+SdrObject* SdrPathObj::RipPoint(sal_uInt32 nHdlNum, sal_uInt32& rNewPt0Index)
+{
+ SdrPathObj* pNewObj = nullptr;
+ const basegfx::B2DPolyPolygon aLocalPolyPolygon(GetPathPoly());
+ sal_uInt32 nPoly, nPnt;
+
+ if(PolyPolygonEditor::GetRelativePolyPoint(aLocalPolyPolygon, nHdlNum, nPoly, nPnt))
+ {
+ if(0 == nPoly)
+ {
+ const basegfx::B2DPolygon& aCandidate(aLocalPolyPolygon.getB2DPolygon(nPoly));
+ const sal_uInt32 nPointCount(aCandidate.count());
+
+ if(nPointCount)
+ {
+ if(IsClosed())
+ {
+ // when closed, RipPoint means to open the polygon at the selected point. To
+ // be able to do that, it is necessary to make the selected point the first one
+ basegfx::B2DPolygon aNewPolygon(basegfx::utils::makeStartPoint(aCandidate, nPnt));
+ SetPathPoly(basegfx::B2DPolyPolygon(aNewPolygon));
+ ToggleClosed();
+
+ // give back new position of old start point (historical reasons)
+ rNewPt0Index = (nPointCount - nPnt) % nPointCount;
+ }
+ else
+ {
+ if(nPointCount >= 3 && nPnt != 0 && nPnt + 1 < nPointCount)
+ {
+ // split in two objects at point nPnt
+ basegfx::B2DPolygon aSplitPolyA(aCandidate, 0, nPnt + 1);
+ SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyA));
+
+ pNewObj = CloneSdrObject(getSdrModelFromSdrObject());
+ basegfx::B2DPolygon aSplitPolyB(aCandidate, nPnt, nPointCount - nPnt);
+ pNewObj->SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyB));
+ }
+ }
+ }
+ }
+ }
+
+ return pNewObj;
+}
+
+SdrObjectUniquePtr SdrPathObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ // #i89784# check for FontWork with activated HideContour
+ const drawinglayer::attribute::SdrTextAttribute aText(
+ drawinglayer::primitive2d::createNewSdrTextAttribute(GetObjectItemSet(), *getText(0)));
+ const bool bHideContour(
+ !aText.isDefault() && !aText.getSdrFormTextAttribute().isDefault() && aText.isHideContour());
+
+ SdrObjectUniquePtr pRet;
+
+ if(!bHideContour)
+ {
+ SdrPathObjUniquePtr pPath = ImpConvertMakeObj(GetPathPoly(), IsClosed(), bBezier);
+
+ if(pPath->GetPathPoly().areControlPointsUsed())
+ {
+ if(!bBezier)
+ {
+ // reduce all bezier curves
+ pPath->SetPathPoly(basegfx::utils::adaptiveSubdivideByAngle(pPath->GetPathPoly()));
+ }
+ }
+ else
+ {
+ if(bBezier)
+ {
+ // create bezier curves
+ pPath->SetPathPoly(basegfx::utils::expandToCurve(pPath->GetPathPoly()));
+ }
+ }
+ pRet = std::move(pPath);
+ }
+
+ if(bAddText)
+ {
+ pRet = ImpConvertAddText(std::move(pRet), bBezier);
+ }
+
+ return pRet;
+}
+
+std::unique_ptr<SdrObjGeoData> SdrPathObj::NewGeoData() const
+{
+ return std::make_unique<SdrPathObjGeoData>();
+}
+
+void SdrPathObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrTextObj::SaveGeoData(rGeo);
+ SdrPathObjGeoData& rPGeo = static_cast<SdrPathObjGeoData&>( rGeo );
+ rPGeo.maPathPolygon=GetPathPoly();
+ rPGeo.meKind=meKind;
+}
+
+void SdrPathObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrTextObj::RestoreGeoData(rGeo);
+ const SdrPathObjGeoData& rPGeo=static_cast<const SdrPathObjGeoData&>(rGeo);
+ maPathPolygon=rPGeo.maPathPolygon;
+ meKind=rPGeo.meKind;
+ ImpForceKind(); // to set bClosed (among other things)
+}
+
+void SdrPathObj::NbcSetPathPoly(const basegfx::B2DPolyPolygon& rPathPoly)
+{
+ if(GetPathPoly() != rPathPoly)
+ {
+ maPathPolygon=rPathPoly;
+ ImpForceKind();
+ SetBoundAndSnapRectsDirty();
+ }
+}
+
+void SdrPathObj::SetPathPoly(const basegfx::B2DPolyPolygon& rPathPoly)
+{
+ if(GetPathPoly() != rPathPoly)
+ {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcSetPathPoly(rPathPoly);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+}
+
+void SdrPathObj::ToggleClosed()
+{
+ tools::Rectangle aBoundRect0;
+ if(m_pUserCall != nullptr)
+ aBoundRect0 = GetLastBoundRect();
+ ImpSetClosed(!IsClosed()); // set new ObjKind
+ ImpForceKind(); // because we want Line -> Poly -> PolyLine instead of Line -> Poly -> Line
+ SetBoundAndSnapRectsDirty();
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize, aBoundRect0);
+}
+
+ImpPathForDragAndCreate& SdrPathObj::impGetDAC() const
+{
+ if(!mpDAC)
+ {
+ const_cast<SdrPathObj*>(this)->mpDAC.reset(new ImpPathForDragAndCreate(*const_cast<SdrPathObj*>(this)));
+ }
+
+ return *mpDAC;
+}
+
+
+// transformation interface for StarOfficeAPI. This implements support for
+// homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
+// moment it contains a shearX, rotation and translation, but for setting all linear
+// transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
+
+
+// gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
+// with the base geometry and returns TRUE. Otherwise it returns FALSE.
+bool SdrPathObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& rPolyPolygon) const
+{
+ double fRotate(0.0);
+ double fShearX(0.0);
+ basegfx::B2DTuple aScale(1.0, 1.0);
+ basegfx::B2DTuple aTranslate(0.0, 0.0);
+
+ if(GetPathPoly().count())
+ {
+ // copy geometry
+ basegfx::B2DHomMatrix aMoveToZeroMatrix;
+ rPolyPolygon = GetPathPoly();
+
+ if(SdrObjKind::Line == meKind)
+ {
+ // ignore shear and rotate, just use scale and translate
+ OSL_ENSURE(GetPathPoly().count() > 0 && GetPathPoly().getB2DPolygon(0).count() > 1, "OBJ_LINE with too few polygons (!)");
+ // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
+ // itself, else this method will no longer return the full polygon information (curve will
+ // be lost)
+ const basegfx::B2DRange aPolyRangeNoCurve(basegfx::utils::getRange(rPolyPolygon));
+ aScale = aPolyRangeNoCurve.getRange();
+ aTranslate = aPolyRangeNoCurve.getMinimum();
+
+ // define matrix for move polygon to zero point
+ aMoveToZeroMatrix.translate(-aTranslate.getX(), -aTranslate.getY());
+ }
+ else
+ {
+ if(maGeo.nShearAngle || maGeo.nRotationAngle)
+ {
+ // get rotate and shear in drawingLayer notation
+ fRotate = toRadians(maGeo.nRotationAngle);
+ fShearX = toRadians(maGeo.nShearAngle);
+
+ // build mathematically correct (negative shear and rotate) object transform
+ // containing shear and rotate to extract unsheared, unrotated polygon
+ basegfx::B2DHomMatrix aObjectMatrix;
+ aObjectMatrix.shearX(-maGeo.mfTanShearAngle);
+ aObjectMatrix.rotate(toRadians(36000_deg100 - maGeo.nRotationAngle));
+
+ // create inverse from it and back-transform polygon
+ basegfx::B2DHomMatrix aInvObjectMatrix(aObjectMatrix);
+ aInvObjectMatrix.invert();
+ rPolyPolygon.transform(aInvObjectMatrix);
+
+ // get range from unsheared, unrotated polygon and extract scale and translate.
+ // transform topLeft from it back to transformed state to get original
+ // topLeft (rotation center)
+ // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
+ // itself, else this method will no longer return the full polygon information (curve will
+ // be lost)
+ const basegfx::B2DRange aCorrectedRangeNoCurve(basegfx::utils::getRange(rPolyPolygon));
+ aTranslate = aObjectMatrix * aCorrectedRangeNoCurve.getMinimum();
+ aScale = aCorrectedRangeNoCurve.getRange();
+
+ // define matrix for move polygon to zero point
+ // #i112280# Added missing minus for Y-Translation
+ aMoveToZeroMatrix.translate(-aCorrectedRangeNoCurve.getMinX(), -aCorrectedRangeNoCurve.getMinY());
+ }
+ else
+ {
+ // get scale and translate from unsheared, unrotated polygon
+ // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon
+ // itself, else this method will no longer return the full polygon information (curve will
+ // be lost)
+ const basegfx::B2DRange aPolyRangeNoCurve(basegfx::utils::getRange(rPolyPolygon));
+ aScale = aPolyRangeNoCurve.getRange();
+ aTranslate = aPolyRangeNoCurve.getMinimum();
+
+ // define matrix for move polygon to zero point
+ aMoveToZeroMatrix.translate(-aTranslate.getX(), -aTranslate.getY());
+ }
+ }
+
+ // move polygon to zero point with pre-defined matrix
+ rPolyPolygon.transform(aMoveToZeroMatrix);
+ }
+
+ // position maybe relative to anchorpos, convert
+ if( getSdrModelFromSdrObject().IsWriter() )
+ {
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // build return value matrix
+ rMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale,
+ basegfx::fTools::equalZero(fShearX) ? 0.0 : tan(fShearX),
+ basegfx::fTools::equalZero(fRotate) ? 0.0 : -fRotate,
+ aTranslate);
+
+ return true;
+}
+
+void SdrPathObj::SetHandleScale(bool bHandleScale)
+{
+ mbHandleScale = bHandleScale;
+}
+
+// Sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
+// If it's an SdrPathObj it will use the provided geometry information. The Polygon has
+// to use (0,0) as upper left and will be scaled to the given size in the matrix.
+void SdrPathObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& rPolyPolygon)
+{
+ // break up matrix
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate, fShearX;
+ rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
+ // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
+ if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
+ {
+ aScale.setX(fabs(aScale.getX()));
+ aScale.setY(fabs(aScale.getY()));
+ fRotate = fmod(fRotate + M_PI, 2 * M_PI);
+ }
+
+ // copy poly
+ basegfx::B2DPolyPolygon aNewPolyPolygon(rPolyPolygon);
+
+ // reset object shear and rotations
+ maGeo.nRotationAngle = 0_deg100;
+ maGeo.RecalcSinCos();
+ maGeo.nShearAngle = 0_deg100;
+ maGeo.RecalcTan();
+
+ if( getSdrModelFromSdrObject().IsWriter() )
+ {
+ // if anchor is used, make position relative to it
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // create transformation for polygon, set values at maGeo direct
+ basegfx::B2DHomMatrix aTransform;
+
+ // #i75086#
+ // Given polygon is already scaled (for historical reasons), but not mirrored yet.
+ // Thus, when scale is negative in X or Y, apply the needed mirroring accordingly.
+ double fScaleX(basegfx::fTools::less(aScale.getX(), 0.0) ? -1.0 : 1.0);
+ double fScaleY(basegfx::fTools::less(aScale.getY(), 0.0) ? -1.0 : 1.0);
+
+ // tdf#98565, tdf#98584. While loading a shape, svg:width and svg:height is used to scale
+ // the polygon. But draw:transform might introduce additional scaling factors, which need to
+ // be applied to the polygon too, so aScale cannot be ignored while loading.
+ // I use "maSnapRect.IsEmpty() && GetPathPoly().count()" to detect this case. Any better
+ // idea? The behavior in other cases is the same as it was before this fix.
+ if (maSnapRect.IsEmpty() && GetPathPoly().count() && mbHandleScale)
+ {
+ // In case of a Writer document, the scaling factors were converted to twips. That is not
+ // correct here, because width and height are already in the points coordinates and aScale
+ // is no length but only a factor here. Convert back.
+ if (getSdrModelFromSdrObject().IsWriter())
+ {
+ aScale.setX(o3tl::convert(aScale.getX(), o3tl::Length::twip, o3tl::Length::mm100));
+ aScale.setY(o3tl::convert(aScale.getY(), o3tl::Length::twip, o3tl::Length::mm100));
+ }
+ fScaleX *= fabs(aScale.getX());
+ fScaleY *= fabs(aScale.getY());
+ }
+
+ if (fScaleX != 1.0 || fScaleY != 1.0)
+ aTransform.scale(fScaleX, fScaleY);
+
+ if(!basegfx::fTools::equalZero(fShearX))
+ {
+ aTransform.shearX(tan(-atan(fShearX)));
+ maGeo.nShearAngle = Degree100(FRound(basegfx::rad2deg<100>(atan(fShearX))));
+ maGeo.RecalcTan();
+ }
+
+ if(!basegfx::fTools::equalZero(fRotate))
+ {
+ // #i78696#
+ // fRotate is mathematically correct for linear transformations, so it's
+ // the one to use for the geometry change
+ aTransform.rotate(fRotate);
+
+ // #i78696#
+ // fRotate is mathematically correct, but aGeoStat.nRotationAngle is
+ // mirrored -> mirror value here
+ maGeo.nRotationAngle = NormAngle36000(Degree100(FRound(-basegfx::rad2deg<100>(fRotate))));
+ maGeo.RecalcSinCos();
+ }
+
+ if(!aTranslate.equalZero())
+ {
+ // #i39529# absolute positioning, so get current position (without control points (!))
+ const basegfx::B2DRange aCurrentRange(basegfx::utils::getRange(aNewPolyPolygon));
+ aTransform.translate(aTranslate.getX() - aCurrentRange.getMinX(), aTranslate.getY() - aCurrentRange.getMinY());
+ }
+
+ // transform polygon and trigger change
+ aNewPolyPolygon.transform(aTransform);
+ SetPathPoly(aNewPolyPolygon);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdorect.cxx b/svx/source/svdraw/svdorect.cxx
new file mode 100644
index 000000000..2674464d2
--- /dev/null
+++ b/svx/source/svdraw/svdorect.cxx
@@ -0,0 +1,567 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdorect.hxx>
+#include <svx/xpoly.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <sdr/properties/rectangleproperties.hxx>
+#include <sdr/contact/viewcontactofsdrrectobj.hxx>
+#include <tools/debug.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <osl/diagnose.h>
+
+using namespace com::sun::star;
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrRectObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::RectangleProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrRectObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrRectObj>(*this);
+}
+
+
+SdrRectObj::SdrRectObj(SdrModel& rSdrModel)
+: SdrTextObj(rSdrModel)
+{
+ m_bClosedObj=true;
+}
+
+SdrRectObj::SdrRectObj(SdrModel& rSdrModel, SdrRectObj const & rSource)
+: SdrTextObj(rSdrModel, rSource)
+{
+ m_bClosedObj=true;
+ mpXPoly = rSource.mpXPoly;
+}
+
+SdrRectObj::SdrRectObj(
+ SdrModel& rSdrModel,
+ const tools::Rectangle& rRect)
+: SdrTextObj(rSdrModel, rRect)
+{
+ m_bClosedObj=true;
+}
+
+SdrRectObj::SdrRectObj(
+ SdrModel& rSdrModel,
+ SdrObjKind eNewTextKind)
+: SdrTextObj(rSdrModel, eNewTextKind)
+{
+ DBG_ASSERT(meTextKind == SdrObjKind::Text ||
+ meTextKind == SdrObjKind::OutlineText || meTextKind == SdrObjKind::TitleText,
+ "SdrRectObj::SdrRectObj(SdrObjKind) can only be applied to text frames.");
+ m_bClosedObj=true;
+}
+
+SdrRectObj::SdrRectObj(
+ SdrModel& rSdrModel,
+ SdrObjKind eNewTextKind,
+ const tools::Rectangle& rRect)
+: SdrTextObj(rSdrModel, eNewTextKind, rRect)
+{
+ DBG_ASSERT(meTextKind == SdrObjKind::Text ||
+ meTextKind == SdrObjKind::OutlineText || meTextKind == SdrObjKind::TitleText,
+ "SdrRectObj::SdrRectObj(SdrObjKind,...) can only be applied to text frames.");
+ m_bClosedObj=true;
+}
+
+SdrRectObj::~SdrRectObj()
+{
+}
+
+void SdrRectObj::SetXPolyDirty()
+{
+ mpXPoly.reset();
+}
+
+XPolygon SdrRectObj::ImpCalcXPoly(const tools::Rectangle& rRect1, tools::Long nRad1) const
+{
+ XPolygon aXPoly(rRect1,nRad1,nRad1);
+ const sal_uInt16 nPointCnt(aXPoly.GetPointCount());
+ XPolygon aNewPoly(nPointCnt+1);
+ sal_uInt16 nShift=nPointCnt-2;
+ if (nRad1!=0) nShift=nPointCnt-5;
+ sal_uInt16 j=nShift;
+ for (sal_uInt16 i=1; i<nPointCnt; i++) {
+ aNewPoly[i]=aXPoly[j];
+ aNewPoly.SetFlags(i,aXPoly.GetFlags(j));
+ j++;
+ if (j>=nPointCnt) j=1;
+ }
+ aNewPoly[0]=rRect1.BottomCenter();
+ aNewPoly[nPointCnt]=aNewPoly[0];
+ aXPoly=aNewPoly;
+
+ // these angles always relate to the top left corner of aRect
+ if (maGeo.nShearAngle) ShearXPoly(aXPoly,maRect.TopLeft(),maGeo.mfTanShearAngle);
+ if (maGeo.nRotationAngle) RotateXPoly(aXPoly,maRect.TopLeft(),maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ return aXPoly;
+}
+
+void SdrRectObj::RecalcXPoly()
+{
+ mpXPoly = ImpCalcXPoly(maRect,GetEckenradius());
+}
+
+const XPolygon& SdrRectObj::GetXPoly() const
+{
+ if(!mpXPoly)
+ {
+ const_cast<SdrRectObj*>(this)->RecalcXPoly();
+ }
+
+ return *mpXPoly;
+}
+
+void SdrRectObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ bool bNoTextFrame=!IsTextFrame();
+ rInfo.bResizeFreeAllowed=bNoTextFrame || ((maGeo.nRotationAngle.get() % 9000) == 0);
+ rInfo.bResizePropAllowed=true;
+ rInfo.bRotateFreeAllowed=true;
+ rInfo.bRotate90Allowed =true;
+ rInfo.bMirrorFreeAllowed=bNoTextFrame;
+ rInfo.bMirror45Allowed =bNoTextFrame;
+ rInfo.bMirror90Allowed =bNoTextFrame;
+
+ // allow transparency
+ rInfo.bTransparenceAllowed = true;
+
+ rInfo.bShearAllowed =bNoTextFrame;
+ rInfo.bEdgeRadiusAllowed=true;
+
+ bool bCanConv=!HasText() || ImpCanConvTextToCurve();
+ if (bCanConv && !bNoTextFrame && !HasText()) {
+ bCanConv=HasFill() || HasLine();
+ }
+ rInfo.bCanConvToPath =bCanConv;
+ rInfo.bCanConvToPoly =bCanConv;
+ rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
+}
+
+SdrObjKind SdrRectObj::GetObjIdentifier() const
+{
+ if (IsTextFrame())
+ return meTextKind;
+ else return SdrObjKind::Rectangle;
+}
+
+void SdrRectObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
+{
+ rRect = maRect;
+ if (maGeo.nShearAngle==0_deg100)
+ return;
+
+ tools::Long nDst=FRound((maRect.Bottom()-maRect.Top()) * maGeo.mfTanShearAngle);
+ if (maGeo.nShearAngle>0_deg100)
+ {
+ Point aRef(rRect.TopLeft());
+ rRect.AdjustLeft( -nDst );
+ Point aTmpPt(rRect.TopLeft());
+ RotatePoint(aTmpPt,aRef,maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ aTmpPt-=rRect.TopLeft();
+ rRect.Move(aTmpPt.X(),aTmpPt.Y());
+ }
+ else
+ {
+ rRect.AdjustRight( -nDst );
+ }
+}
+
+OUString SdrRectObj::TakeObjNameSingul() const
+{
+ if (IsTextFrame())
+ {
+ return SdrTextObj::TakeObjNameSingul();
+ }
+
+ bool bRounded = GetEckenradius() != 0; // rounded down
+ TranslateId pResId = bRounded ? STR_ObjNameSingulRECTRND : STR_ObjNameSingulRECT;
+ if (maGeo.nShearAngle)
+ {
+ pResId = bRounded ? STR_ObjNameSingulPARALRND : STR_ObjNameSingulPARAL; // parallelogram or, maybe, rhombus
+ }
+ else if (maRect.GetWidth() == maRect.GetHeight())
+ {
+ pResId = bRounded ? STR_ObjNameSingulQUADRND : STR_ObjNameSingulQUAD; // square
+ }
+ OUString sName(SvxResId(pResId));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+OUString SdrRectObj::TakeObjNamePlural() const
+{
+ if (IsTextFrame())
+ {
+ return SdrTextObj::TakeObjNamePlural();
+ }
+
+ bool bRounded = GetEckenradius() != 0; // rounded down
+ TranslateId pResId = bRounded ? STR_ObjNamePluralRECTRND : STR_ObjNamePluralRECT;
+ if (maGeo.nShearAngle)
+ {
+ pResId = bRounded ? STR_ObjNamePluralPARALRND : STR_ObjNamePluralPARAL; // parallelogram or rhombus
+ }
+ else if (maRect.GetWidth() == maRect.GetHeight())
+ {
+ pResId = bRounded ? STR_ObjNamePluralQUADRND : STR_ObjNamePluralQUAD; // square
+ }
+
+ return SvxResId(pResId);
+}
+
+SdrRectObj* SdrRectObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrRectObj(rTargetModel, *this);
+}
+
+basegfx::B2DPolyPolygon SdrRectObj::TakeXorPoly() const
+{
+ XPolyPolygon aXPP;
+ aXPP.Insert(ImpCalcXPoly(maRect,GetEckenradius()));
+ return aXPP.getB2DPolyPolygon();
+}
+
+void SdrRectObj::RecalcSnapRect()
+{
+ tools::Long nEckRad=GetEckenradius();
+ if ((maGeo.nRotationAngle || maGeo.nShearAngle) && nEckRad!=0) {
+ maSnapRect=GetXPoly().GetBoundRect();
+ } else {
+ SdrTextObj::RecalcSnapRect();
+ }
+}
+
+void SdrRectObj::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ SdrTextObj::NbcSetSnapRect(rRect);
+ SetXPolyDirty();
+}
+
+void SdrRectObj::NbcSetLogicRect(const tools::Rectangle& rRect)
+{
+ SdrTextObj::NbcSetLogicRect(rRect);
+ SetXPolyDirty();
+}
+
+sal_uInt32 SdrRectObj::GetHdlCount() const
+{
+ return IsTextFrame() ? 10 : 9;
+}
+
+void SdrRectObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ // A text box has an additional (pseudo-)handle for the blinking frame.
+ if(IsTextFrame())
+ {
+ OSL_ENSURE(!IsTextEditActive(), "Do not use an ImpTextframeHdl for highlighting text in active text edit, this will collide with EditEngine paints (!)");
+ std::unique_ptr<SdrHdl> pH(new ImpTextframeHdl(maRect));
+ pH->SetObj(const_cast<SdrRectObj*>(this));
+ pH->SetRotationAngle(maGeo.nRotationAngle);
+ rHdlList.AddHdl(std::move(pH));
+ }
+
+ for(sal_Int32 nHdlNum = 1; nHdlNum <= 9; ++nHdlNum)
+ {
+ Point aPnt;
+ SdrHdlKind eKind = SdrHdlKind::Move;
+
+ switch(nHdlNum)
+ {
+ case 1: // Handle for changing the corner radius
+ {
+ tools::Long a = GetEckenradius();
+ tools::Long b = std::max(maRect.GetWidth(),maRect.GetHeight())/2; // rounded up, because GetWidth() adds 1
+ if (a>b) a=b;
+ if (a<0) a=0;
+ aPnt=maRect.TopLeft();
+ aPnt.AdjustX(a );
+ eKind = SdrHdlKind::Circle;
+ break;
+ }
+ case 2: aPnt=maRect.TopLeft(); eKind = SdrHdlKind::UpperLeft; break;
+ case 3: aPnt=maRect.TopCenter(); eKind = SdrHdlKind::Upper; break;
+ case 4: aPnt=maRect.TopRight(); eKind = SdrHdlKind::UpperRight; break;
+ case 5: aPnt=maRect.LeftCenter(); eKind = SdrHdlKind::Left ; break;
+ case 6: aPnt=maRect.RightCenter(); eKind = SdrHdlKind::Right; break;
+ case 7: aPnt=maRect.BottomLeft(); eKind = SdrHdlKind::LowerLeft; break;
+ case 8: aPnt=maRect.BottomCenter(); eKind = SdrHdlKind::Lower; break;
+ case 9: aPnt=maRect.BottomRight(); eKind = SdrHdlKind::LowerRight; break;
+ }
+
+ if (maGeo.nShearAngle)
+ {
+ ShearPoint(aPnt,maRect.TopLeft(),maGeo.mfTanShearAngle);
+ }
+ if (maGeo.nRotationAngle)
+ {
+ RotatePoint(aPnt,maRect.TopLeft(),maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ }
+
+ std::unique_ptr<SdrHdl> pH(new SdrHdl(aPnt,eKind));
+ pH->SetObj(const_cast<SdrRectObj*>(this));
+ pH->SetRotationAngle(maGeo.nRotationAngle);
+ rHdlList.AddHdl(std::move(pH));
+ }
+}
+
+bool SdrRectObj::hasSpecialDrag() const
+{
+ return true;
+}
+
+bool SdrRectObj::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ const bool bRad(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
+
+ if(bRad)
+ {
+ rDrag.SetEndDragChangesAttributes(true);
+
+ return true;
+ }
+
+ return SdrTextObj::beginSpecialDrag(rDrag);
+}
+
+bool SdrRectObj::applySpecialDrag(SdrDragStat& rDrag)
+{
+ const bool bRad(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
+
+ if (bRad)
+ {
+ Point aPt(rDrag.GetNow());
+
+ if (maGeo.nRotationAngle)
+ RotatePoint(aPt, maRect.TopLeft(), -maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+
+ sal_Int32 nRad(aPt.X() - maRect.Left());
+
+ if (nRad < 0)
+ nRad = 0;
+
+ if(nRad != GetEckenradius())
+ {
+ NbcSetEckenradius(nRad);
+ }
+
+ return true;
+ }
+ else
+ {
+ return SdrTextObj::applySpecialDrag(rDrag);
+ }
+}
+
+OUString SdrRectObj::getSpecialDragComment(const SdrDragStat& rDrag) const
+{
+ const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
+
+ if(bCreateComment)
+ {
+ return OUString();
+ }
+ else
+ {
+ const bool bRad(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
+
+ if(bRad)
+ {
+ Point aPt(rDrag.GetNow());
+
+ // -sin for reversal
+ if (maGeo.nRotationAngle)
+ RotatePoint(aPt, maRect.TopLeft(), -maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+
+ sal_Int32 nRad(aPt.X() - maRect.Left());
+
+ if(nRad < 0)
+ nRad = 0;
+
+ return ImpGetDescriptionStr(STR_DragRectEckRad) +
+ " (" +
+ GetMetrStr(nRad) +
+ ")";
+ }
+ else
+ {
+ return SdrTextObj::getSpecialDragComment(rDrag);
+ }
+ }
+}
+
+
+basegfx::B2DPolyPolygon SdrRectObj::TakeCreatePoly(const SdrDragStat& rDrag) const
+{
+ tools::Rectangle aRect1;
+ rDrag.TakeCreateRect(aRect1);
+ aRect1.Justify();
+
+ basegfx::B2DPolyPolygon aRetval;
+ aRetval.append(ImpCalcXPoly(aRect1,GetEckenradius()).getB2DPolygon());
+ return aRetval;
+}
+
+PointerStyle SdrRectObj::GetCreatePointer() const
+{
+ if (IsTextFrame()) return PointerStyle::DrawText;
+ return PointerStyle::DrawRect;
+}
+
+void SdrRectObj::NbcMove(const Size& rSiz)
+{
+ SdrTextObj::NbcMove(rSiz);
+ SetXPolyDirty();
+}
+
+void SdrRectObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ SdrTextObj::NbcResize(rRef,xFact,yFact);
+ SetXPolyDirty();
+}
+
+void SdrRectObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
+ SetXPolyDirty();
+}
+
+void SdrRectObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
+ SetXPolyDirty();
+}
+
+void SdrRectObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ SdrTextObj::NbcMirror(rRef1,rRef2);
+ SetXPolyDirty();
+}
+
+SdrGluePoint SdrRectObj::GetVertexGluePoint(sal_uInt16 nPosNum) const
+{
+ sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
+
+ // #i25616#
+ if(!LineIsOutsideGeometry())
+ {
+ nWdt++;
+ nWdt /= 2;
+ }
+
+ Point aPt;
+ switch (nPosNum) {
+ case 0: aPt=maRect.TopCenter(); aPt.AdjustY( -nWdt ); break;
+ case 1: aPt=maRect.RightCenter(); aPt.AdjustX(nWdt ); break;
+ case 2: aPt=maRect.BottomCenter(); aPt.AdjustY(nWdt ); break;
+ case 3: aPt=maRect.LeftCenter(); aPt.AdjustX( -nWdt ); break;
+ }
+ if (maGeo.nShearAngle) ShearPoint(aPt, maRect.TopLeft(), maGeo.mfTanShearAngle);
+ if (maGeo.nRotationAngle) RotatePoint(aPt, maRect.TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ aPt-=GetSnapRect().Center();
+ SdrGluePoint aGP(aPt);
+ aGP.SetPercent(false);
+ return aGP;
+}
+
+SdrGluePoint SdrRectObj::GetCornerGluePoint(sal_uInt16 nPosNum) const
+{
+ sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
+
+ // #i25616#
+ if(!LineIsOutsideGeometry())
+ {
+ nWdt++;
+ nWdt /= 2;
+ }
+
+ Point aPt;
+ switch (nPosNum) {
+ case 0: aPt=maRect.TopLeft(); aPt.AdjustX( -nWdt ); aPt.AdjustY( -nWdt ); break;
+ case 1: aPt=maRect.TopRight(); aPt.AdjustX(nWdt ); aPt.AdjustY( -nWdt ); break;
+ case 2: aPt=maRect.BottomRight(); aPt.AdjustX(nWdt ); aPt.AdjustY(nWdt ); break;
+ case 3: aPt=maRect.BottomLeft(); aPt.AdjustX( -nWdt ); aPt.AdjustY(nWdt ); break;
+ }
+ if (maGeo.nShearAngle) ShearPoint(aPt,maRect.TopLeft(),maGeo.mfTanShearAngle);
+ if (maGeo.nRotationAngle) RotatePoint(aPt,maRect.TopLeft(),maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ aPt-=GetSnapRect().Center();
+ SdrGluePoint aGP(aPt);
+ aGP.SetPercent(false);
+ return aGP;
+}
+
+SdrObjectUniquePtr SdrRectObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ XPolygon aXP(ImpCalcXPoly(maRect,GetEckenradius()));
+ { // TODO: this is only for the moment, until we have the new TakeContour()
+ aXP.Remove(0,1);
+ aXP[aXP.GetPointCount()-1]=aXP[0];
+ }
+
+ basegfx::B2DPolyPolygon aPolyPolygon(aXP.getB2DPolygon());
+ aPolyPolygon.removeDoublePoints();
+ SdrObjectUniquePtr pRet;
+
+ // small correction: Do not create something when no fill and no line. To
+ // be sure to not damage something with non-text frames, do this only
+ // when used with bAddText==false from other converters
+ if((bAddText && !IsTextFrame()) || HasFill() || HasLine())
+ {
+ pRet = ImpConvertMakeObj(aPolyPolygon, true, bBezier);
+ }
+
+ if(bAddText)
+ {
+ pRet = ImpConvertAddText(std::move(pRet), bBezier);
+ }
+
+ return pRet;
+}
+
+void SdrRectObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ SdrTextObj::Notify(rBC,rHint);
+ SetXPolyDirty(); // because of the corner radius
+}
+
+void SdrRectObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrTextObj::RestoreGeoData(rGeo);
+ SetXPolyDirty();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdotext.cxx b/svx/source/svdraw/svdotext.cxx
new file mode 100644
index 000000000..fe5e13446
--- /dev/null
+++ b/svx/source/svdraw/svdotext.cxx
@@ -0,0 +1,2174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <comphelper/string.hxx>
+#include <svl/stritem.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <editeng/writingmodeitem.hxx>
+#include <svx/sdtfchim.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/outliner.hxx>
+#include <textchain.hxx>
+#include <textchainflow.hxx>
+#include <tools/helpers.hxx>
+#include <svx/sderitm.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svx/sdtmfitm.hxx>
+#include <svx/xtextit0.hxx>
+#include <sdr/properties/textproperties.hxx>
+#include <sdr/contact/viewcontactoftextobj.hxx>
+#include <basegfx/tuple/b2dtuple.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/virdev.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <sal/log.hxx>
+#include <o3tl/temporary.hxx>
+#include <unotools/configmgr.hxx>
+
+using namespace com::sun::star;
+
+// BaseProperties section
+std::unique_ptr<sdr::properties::BaseProperties> SdrTextObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::TextProperties>(*this);
+}
+
+// DrawContact section
+std::unique_ptr<sdr::contact::ViewContact> SdrTextObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfTextObj>(*this);
+}
+
+SdrTextObj::SdrTextObj(SdrModel& rSdrModel)
+: SdrAttrObj(rSdrModel),
+ mpEditingOutliner(nullptr),
+ meTextKind(SdrObjKind::Text)
+{
+ mbTextSizeDirty = false;
+ mbTextFrame = false;
+ mbNoShear = false;
+ mbDisableAutoWidthOnDragging = false;
+
+ mbInEditMode = false;
+ mbTextAnimationAllowed = true;
+ maTextEditOffset = Point(0, 0);
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = true;
+ mbInDownScale = false;
+}
+
+SdrTextObj::SdrTextObj(SdrModel& rSdrModel, SdrTextObj const & rSource)
+: SdrAttrObj(rSdrModel, rSource),
+ mpEditingOutliner(nullptr)
+{
+ mbInEditMode = false;
+ mbTextAnimationAllowed = true;
+ maTextEditOffset = Point(0, 0);
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = true;
+ mbInDownScale = false;
+
+ maRect = rSource.maRect;
+ maGeo = rSource.maGeo;
+ meTextKind = rSource.meTextKind;
+ mbTextFrame = rSource.mbTextFrame;
+ maTextSize = rSource.maTextSize;
+ mbTextSizeDirty = rSource.mbTextSizeDirty;
+
+ // Not all of the necessary parameters were copied yet.
+ mbNoShear = rSource.mbNoShear;
+ mbDisableAutoWidthOnDragging = rSource.mbDisableAutoWidthOnDragging;
+ SdrText* pText = getActiveText();
+
+ if( pText && rSource.HasText() )
+ {
+ // before pNewOutlinerParaObject was created the same, but
+ // set at mpText (outside this scope), but mpText might be
+ // empty (this operator== seems not prepared for MultiText
+ // objects). In the current form it makes only sense to
+ // create locally and use locally on a known existing SdrText
+ const Outliner* pEO = rSource.mpEditingOutliner;
+ std::optional<OutlinerParaObject> pNewOutlinerParaObject;
+
+ if (pEO!=nullptr)
+ {
+ pNewOutlinerParaObject = pEO->CreateParaObject();
+ }
+ else if (nullptr != rSource.getActiveText()->GetOutlinerParaObject())
+ {
+ pNewOutlinerParaObject = *rSource.getActiveText()->GetOutlinerParaObject();
+ }
+
+ pText->SetOutlinerParaObject( std::move(pNewOutlinerParaObject) );
+ }
+
+ ImpSetTextStyleSheetListeners();
+}
+
+SdrTextObj::SdrTextObj(
+ SdrModel& rSdrModel,
+ const tools::Rectangle& rNewRect)
+: SdrAttrObj(rSdrModel),
+ maRect(rNewRect),
+ mpEditingOutliner(nullptr),
+ meTextKind(SdrObjKind::Text)
+{
+ mbTextSizeDirty = false;
+ mbTextFrame = false;
+ mbNoShear = false;
+ mbDisableAutoWidthOnDragging = false;
+ ImpJustifyRect(maRect);
+
+ mbInEditMode = false;
+ mbTextAnimationAllowed = true;
+ mbInDownScale = false;
+ maTextEditOffset = Point(0, 0);
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = true;
+}
+
+SdrTextObj::SdrTextObj(
+ SdrModel& rSdrModel,
+ SdrObjKind eNewTextKind)
+: SdrAttrObj(rSdrModel),
+ mpEditingOutliner(nullptr),
+ meTextKind(eNewTextKind)
+{
+ mbTextSizeDirty = false;
+ mbTextFrame = true;
+ mbNoShear = true;
+ mbDisableAutoWidthOnDragging = false;
+
+ mbInEditMode = false;
+ mbTextAnimationAllowed = true;
+ mbInDownScale = false;
+ maTextEditOffset = Point(0, 0);
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = true;
+}
+
+SdrTextObj::SdrTextObj(
+ SdrModel& rSdrModel,
+ SdrObjKind eNewTextKind,
+ const tools::Rectangle& rNewRect)
+: SdrAttrObj(rSdrModel),
+ maRect(rNewRect),
+ mpEditingOutliner(nullptr),
+ meTextKind(eNewTextKind)
+{
+ mbTextSizeDirty = false;
+ mbTextFrame = true;
+ mbNoShear = true;
+ mbDisableAutoWidthOnDragging = false;
+ ImpJustifyRect(maRect);
+
+ mbInEditMode = false;
+ mbTextAnimationAllowed = true;
+ mbInDownScale = false;
+ maTextEditOffset = Point(0, 0);
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = true;
+}
+
+SdrTextObj::~SdrTextObj()
+{
+ SdrOutliner& rOutl(getSdrModelFromSdrObject().GetHitTestOutliner());
+ if( rOutl.GetTextObj() == this )
+ rOutl.SetTextObj( nullptr );
+ mpText.reset();
+ ImpDeregisterLink();
+}
+
+void SdrTextObj::FitFrameToTextSize()
+{
+ ImpJustifyRect(maRect);
+
+ SdrText* pText = getActiveText();
+ if(pText==nullptr || !pText->GetOutlinerParaObject())
+ return;
+
+ SdrOutliner& rOutliner=ImpGetDrawOutliner();
+ rOutliner.SetPaperSize(Size(maRect.Right()-maRect.Left(),maRect.Bottom()-maRect.Top()));
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetText(*pText->GetOutlinerParaObject());
+ Size aNewSize(rOutliner.CalcTextSize());
+ rOutliner.Clear();
+ aNewSize.AdjustWidth( 1 ); // because of possible rounding errors
+ aNewSize.AdjustWidth(GetTextLeftDistance()+GetTextRightDistance() );
+ aNewSize.AdjustHeight(GetTextUpperDistance()+GetTextLowerDistance() );
+ tools::Rectangle aNewRect(maRect);
+ aNewRect.SetSize(aNewSize);
+ ImpJustifyRect(aNewRect);
+ if (aNewRect!=maRect) {
+ SetLogicRect(aNewRect);
+ }
+}
+
+void SdrTextObj::NbcSetText(const OUString& rStr)
+{
+ SdrOutliner& rOutliner=ImpGetDrawOutliner();
+ rOutliner.SetStyleSheet( 0, GetStyleSheet());
+ rOutliner.SetText(rStr,rOutliner.GetParagraph( 0 ));
+ std::optional<OutlinerParaObject> pNewText=rOutliner.CreateParaObject();
+ NbcSetOutlinerParaObject(std::move(pNewText));
+ mbTextSizeDirty=true;
+}
+
+void SdrTextObj::SetText(const OUString& rStr)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcSetText(rStr);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrTextObj::NbcSetText(SvStream& rInput, const OUString& rBaseURL, EETextFormat eFormat)
+{
+ SdrOutliner& rOutliner=ImpGetDrawOutliner();
+ rOutliner.SetStyleSheet( 0, GetStyleSheet());
+ rOutliner.Read(rInput,rBaseURL,eFormat);
+ std::optional<OutlinerParaObject> pNewText=rOutliner.CreateParaObject();
+ rOutliner.SetUpdateLayout(true);
+ Size aSize(rOutliner.CalcTextSize());
+ rOutliner.Clear();
+ NbcSetOutlinerParaObject(std::move(pNewText));
+ maTextSize=aSize;
+ mbTextSizeDirty=false;
+}
+
+void SdrTextObj::SetText(SvStream& rInput, const OUString& rBaseURL, EETextFormat eFormat)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcSetText(rInput,rBaseURL,eFormat);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+const Size& SdrTextObj::GetTextSize() const
+{
+ if (mbTextSizeDirty)
+ {
+ Size aSiz;
+ SdrText* pText = getActiveText();
+ if( pText && pText->GetOutlinerParaObject ())
+ {
+ SdrOutliner& rOutliner=ImpGetDrawOutliner();
+ rOutliner.SetText(*pText->GetOutlinerParaObject());
+ rOutliner.SetUpdateLayout(true);
+ aSiz=rOutliner.CalcTextSize();
+ rOutliner.Clear();
+ }
+ // casting to nonconst twice
+ const_cast<SdrTextObj*>(this)->maTextSize = aSiz;
+ const_cast<SdrTextObj*>(this)->mbTextSizeDirty = false;
+ }
+ return maTextSize;
+}
+
+bool SdrTextObj::IsAutoGrowHeight() const
+{
+ if(!mbTextFrame)
+ return false; // AutoGrow only together with TextFrames
+
+ const SfxItemSet& rSet = GetObjectItemSet();
+ bool bRet = rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
+
+ if(bRet)
+ {
+ SdrTextAniKind eAniKind = rSet.Get(SDRATTR_TEXT_ANIKIND).GetValue();
+
+ if(eAniKind == SdrTextAniKind::Scroll || eAniKind == SdrTextAniKind::Alternate || eAniKind == SdrTextAniKind::Slide)
+ {
+ SdrTextAniDirection eDirection = rSet.Get(SDRATTR_TEXT_ANIDIRECTION).GetValue();
+
+ if(eDirection == SdrTextAniDirection::Up || eDirection == SdrTextAniDirection::Down)
+ {
+ bRet = false;
+ }
+ }
+ }
+ return bRet;
+}
+
+bool SdrTextObj::IsAutoGrowWidth() const
+{
+ if (!mbTextFrame)
+ return false; // AutoGrow only together with TextFrames
+
+ const SfxItemSet& rSet = GetObjectItemSet();
+ bool bRet = rSet.Get(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue();
+
+ bool bInEditMOde = IsInEditMode();
+
+ if(!bInEditMOde && bRet)
+ {
+ SdrTextAniKind eAniKind = rSet.Get(SDRATTR_TEXT_ANIKIND).GetValue();
+
+ if(eAniKind == SdrTextAniKind::Scroll || eAniKind == SdrTextAniKind::Alternate || eAniKind == SdrTextAniKind::Slide)
+ {
+ SdrTextAniDirection eDirection = rSet.Get(SDRATTR_TEXT_ANIDIRECTION).GetValue();
+
+ if(eDirection == SdrTextAniDirection::Left || eDirection == SdrTextAniDirection::Right)
+ {
+ bRet = false;
+ }
+ }
+ }
+ return bRet;
+}
+
+SdrTextHorzAdjust SdrTextObj::GetTextHorizontalAdjust() const
+{
+ return GetTextHorizontalAdjust(GetObjectItemSet());
+}
+
+SdrTextHorzAdjust SdrTextObj::GetTextHorizontalAdjust(const SfxItemSet& rSet) const
+{
+ if(IsContourTextFrame())
+ return SDRTEXTHORZADJUST_BLOCK;
+
+ SdrTextHorzAdjust eRet = rSet.Get(SDRATTR_TEXT_HORZADJUST).GetValue();
+
+ bool bInEditMode = IsInEditMode();
+
+ if(!bInEditMode && eRet == SDRTEXTHORZADJUST_BLOCK)
+ {
+ SdrTextAniKind eAniKind = rSet.Get(SDRATTR_TEXT_ANIKIND).GetValue();
+
+ if(eAniKind == SdrTextAniKind::Scroll || eAniKind == SdrTextAniKind::Alternate || eAniKind == SdrTextAniKind::Slide)
+ {
+ SdrTextAniDirection eDirection = rSet.Get(SDRATTR_TEXT_ANIDIRECTION).GetValue();
+
+ if(eDirection == SdrTextAniDirection::Left || eDirection == SdrTextAniDirection::Right)
+ {
+ eRet = SDRTEXTHORZADJUST_LEFT;
+ }
+ }
+ }
+
+ return eRet;
+} // defaults: BLOCK (justify) for text frame, CENTER for captions of drawing objects
+
+SdrTextVertAdjust SdrTextObj::GetTextVerticalAdjust() const
+{
+ return GetTextVerticalAdjust(GetObjectItemSet());
+}
+
+SdrTextVertAdjust SdrTextObj::GetTextVerticalAdjust(const SfxItemSet& rSet) const
+{
+ if(IsContourTextFrame())
+ return SDRTEXTVERTADJUST_TOP;
+
+ // Take care for vertical text animation here
+ SdrTextVertAdjust eRet = rSet.Get(SDRATTR_TEXT_VERTADJUST).GetValue();
+ bool bInEditMode = IsInEditMode();
+
+ // Take care for vertical text animation here
+ if(!bInEditMode && eRet == SDRTEXTVERTADJUST_BLOCK)
+ {
+ SdrTextAniKind eAniKind = rSet.Get(SDRATTR_TEXT_ANIKIND).GetValue();
+
+ if(eAniKind == SdrTextAniKind::Scroll || eAniKind == SdrTextAniKind::Alternate || eAniKind == SdrTextAniKind::Slide)
+ {
+ SdrTextAniDirection eDirection = rSet.Get(SDRATTR_TEXT_ANIDIRECTION).GetValue();
+
+ if(eDirection == SdrTextAniDirection::Left || eDirection == SdrTextAniDirection::Right)
+ {
+ eRet = SDRTEXTVERTADJUST_TOP;
+ }
+ }
+ }
+
+ return eRet;
+} // defaults: TOP for text frame, CENTER for captions of drawing objects
+
+void SdrTextObj::ImpJustifyRect(tools::Rectangle& rRect)
+{
+ if (!rRect.IsEmpty()) {
+ rRect.Justify();
+ if (rRect.Left()==rRect.Right()) rRect.AdjustRight( 1 );
+ if (rRect.Top()==rRect.Bottom()) rRect.AdjustBottom( 1 );
+ }
+}
+
+void SdrTextObj::ImpCheckShear()
+{
+ if (mbNoShear && maGeo.nShearAngle)
+ {
+ maGeo.nShearAngle = 0_deg100;
+ maGeo.mfTanShearAngle = 0;
+ }
+}
+
+void SdrTextObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ bool bNoTextFrame=!IsTextFrame();
+ rInfo.bResizeFreeAllowed=bNoTextFrame || ((maGeo.nRotationAngle.get() % 9000) == 0);
+ rInfo.bResizePropAllowed=true;
+ rInfo.bRotateFreeAllowed=true;
+ rInfo.bRotate90Allowed =true;
+ rInfo.bMirrorFreeAllowed=bNoTextFrame;
+ rInfo.bMirror45Allowed =bNoTextFrame;
+ rInfo.bMirror90Allowed =bNoTextFrame;
+
+ // allow transparency
+ rInfo.bTransparenceAllowed = true;
+
+ rInfo.bShearAllowed =bNoTextFrame;
+ rInfo.bEdgeRadiusAllowed=true;
+ bool bCanConv=ImpCanConvTextToCurve();
+ rInfo.bCanConvToPath =bCanConv;
+ rInfo.bCanConvToPoly =bCanConv;
+ rInfo.bCanConvToPathLineToArea=bCanConv;
+ rInfo.bCanConvToPolyLineToArea=bCanConv;
+ rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
+}
+
+SdrObjKind SdrTextObj::GetObjIdentifier() const
+{
+ return meTextKind;
+}
+
+bool SdrTextObj::HasTextImpl( SdrOutliner const * pOutliner )
+{
+ bool bRet=false;
+ if(pOutliner)
+ {
+ Paragraph* p1stPara=pOutliner->GetParagraph( 0 );
+ sal_Int32 nParaCount=pOutliner->GetParagraphCount();
+ if(p1stPara==nullptr)
+ nParaCount=0;
+
+ if(nParaCount==1)
+ {
+ // if it is only one paragraph, check if that paragraph is empty
+ if( pOutliner->GetText(p1stPara).isEmpty() )
+ nParaCount = 0;
+ }
+
+ bRet= nParaCount!=0;
+ }
+ return bRet;
+}
+
+void SdrTextObj::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ const bool bRemove(pNewPage == nullptr && pOldPage != nullptr);
+ const bool bInsert(pNewPage != nullptr && pOldPage == nullptr);
+ const bool bLinked(IsLinkedText());
+
+ if (bLinked && bRemove)
+ {
+ ImpDeregisterLink();
+ }
+
+ // call parent
+ SdrAttrObj::handlePageChange(pOldPage, pNewPage);
+
+ if (bLinked && bInsert)
+ {
+ ImpRegisterLink();
+ }
+}
+
+void SdrTextObj::NbcSetEckenradius(tools::Long nRad)
+{
+ SetObjectItem(makeSdrEckenradiusItem(nRad));
+}
+
+// #115391# This implementation is based on the object size (aRect) and the
+// states of IsAutoGrowWidth/Height to correctly set TextMinFrameWidth/Height
+void SdrTextObj::AdaptTextMinSize()
+{
+ if (!mbTextFrame)
+ // Only do this for text frame.
+ return;
+
+ if (getSdrModelFromSdrObject().IsPasteResize())
+ // Don't do this during paste resize.
+ return;
+
+ const bool bW = IsAutoGrowWidth();
+ const bool bH = IsAutoGrowHeight();
+
+ if (!bW && !bH)
+ // No auto grow requested. Bail out.
+ return;
+
+ SfxItemSetFixed<SDRATTR_TEXT_MINFRAMEHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT,
+ SDRATTR_TEXT_MINFRAMEWIDTH, SDRATTR_TEXT_AUTOGROWWIDTH> // contains SDRATTR_TEXT_MAXFRAMEWIDTH
+ aSet(*GetObjectItemSet().GetPool());
+
+ if(bW)
+ {
+ // Set minimum width.
+ const tools::Long nDist = GetTextLeftDistance() + GetTextRightDistance();
+ const tools::Long nW = std::max<tools::Long>(0, maRect.GetWidth() - 1 - nDist); // text width without margins
+
+ aSet.Put(makeSdrTextMinFrameWidthItem(nW));
+
+ if(!IsVerticalWriting() && mbDisableAutoWidthOnDragging)
+ {
+ mbDisableAutoWidthOnDragging = true;
+ aSet.Put(makeSdrTextAutoGrowWidthItem(false));
+ }
+ }
+
+ if(bH)
+ {
+ // Set Minimum height.
+ const tools::Long nDist = GetTextUpperDistance() + GetTextLowerDistance();
+ const tools::Long nH = std::max<tools::Long>(0, maRect.GetHeight() - 1 - nDist); // text height without margins
+
+ aSet.Put(makeSdrTextMinFrameHeightItem(nH));
+
+ if(IsVerticalWriting() && mbDisableAutoWidthOnDragging)
+ {
+ mbDisableAutoWidthOnDragging = false;
+ aSet.Put(makeSdrTextAutoGrowHeightItem(false));
+ }
+ }
+
+ SetObjectItemSet(aSet);
+}
+
+void SdrTextObj::ImpSetContourPolygon( SdrOutliner& rOutliner, tools::Rectangle const & rAnchorRect, bool bLineWidth ) const
+{
+ basegfx::B2DPolyPolygon aXorPolyPolygon(TakeXorPoly());
+ std::optional<basegfx::B2DPolyPolygon> pContourPolyPolygon;
+ basegfx::B2DHomMatrix aMatrix(basegfx::utils::createTranslateB2DHomMatrix(
+ -rAnchorRect.Left(), -rAnchorRect.Top()));
+
+ if(maGeo.nRotationAngle)
+ {
+ // Unrotate!
+ aMatrix.rotate(-toRadians(maGeo.nRotationAngle));
+ }
+
+ aXorPolyPolygon.transform(aMatrix);
+
+ if( bLineWidth )
+ {
+ // Take line width into account.
+ // When doing the hit test, avoid this. (Performance!)
+ pContourPolyPolygon.emplace();
+
+ // test if shadow needs to be avoided for TakeContour()
+ const SfxItemSet& rSet = GetObjectItemSet();
+ bool bShadowOn = rSet.Get(SDRATTR_SHADOW).GetValue();
+
+ // #i33696#
+ // Remember TextObject currently set at the DrawOutliner, it WILL be
+ // replaced during calculating the outline since it uses an own paint
+ // and that one uses the DrawOutliner, too.
+ const SdrTextObj* pLastTextObject = rOutliner.GetTextObj();
+
+ if(bShadowOn)
+ {
+ // force shadow off
+ SdrObject* pCopy(CloneSdrObject(getSdrModelFromSdrObject()));
+ pCopy->SetMergedItem(makeSdrShadowItem(false));
+ *pContourPolyPolygon = pCopy->TakeContour();
+ SdrObject::Free( pCopy );
+ }
+ else
+ {
+ *pContourPolyPolygon = TakeContour();
+ }
+
+ // #i33696#
+ // restore remembered text object
+ if(pLastTextObject != rOutliner.GetTextObj())
+ {
+ rOutliner.SetTextObj(pLastTextObject);
+ }
+
+ pContourPolyPolygon->transform(aMatrix);
+ }
+
+ rOutliner.SetPolygon(aXorPolyPolygon, pContourPolyPolygon ? &*pContourPolyPolygon : nullptr);
+}
+
+void SdrTextObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
+{
+ rRect=maRect;
+}
+
+// See also: <unnamed>::getTextAnchorRange in svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
+void SdrTextObj::AdjustRectToTextDistance(tools::Rectangle& rAnchorRect) const
+{
+ const tools::Long nLeftDist = GetTextLeftDistance();
+ const tools::Long nRightDist = GetTextRightDistance();
+ const tools::Long nUpperDist = GetTextUpperDistance();
+ const tools::Long nLowerDist = GetTextLowerDistance();
+ if (!IsVerticalWriting())
+ {
+ rAnchorRect.AdjustLeft(nLeftDist);
+ rAnchorRect.AdjustTop(nUpperDist);
+ rAnchorRect.AdjustRight(-nRightDist);
+ rAnchorRect.AdjustBottom(-nLowerDist);
+ }
+ else if (IsTopToBottom())
+ {
+ rAnchorRect.AdjustLeft(nLowerDist);
+ rAnchorRect.AdjustTop(nLeftDist);
+ rAnchorRect.AdjustRight(-nUpperDist);
+ rAnchorRect.AdjustBottom(-nRightDist);
+ }
+ else
+ {
+ rAnchorRect.AdjustLeft(nUpperDist);
+ rAnchorRect.AdjustTop(nRightDist);
+ rAnchorRect.AdjustRight(-nLowerDist);
+ rAnchorRect.AdjustBottom(-nLeftDist);
+ }
+
+ // Since sizes may be bigger than the object bounds it is necessary to
+ // justify the rect now.
+ ImpJustifyRect(rAnchorRect);
+}
+
+void SdrTextObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
+{
+ tools::Rectangle aAnkRect(maRect); // the rectangle in which we anchor
+ bool bFrame=IsTextFrame();
+ if (!bFrame) {
+ TakeUnrotatedSnapRect(aAnkRect);
+ }
+ Point aRotateRef(aAnkRect.TopLeft());
+ AdjustRectToTextDistance(aAnkRect);
+
+ if (bFrame) {
+ // TODO: Optimize this.
+ if (aAnkRect.GetWidth()<2) aAnkRect.SetRight(aAnkRect.Left()+1 ); // minimum size h and v: 2 px
+ if (aAnkRect.GetHeight()<2) aAnkRect.SetBottom(aAnkRect.Top()+1 );
+ }
+ if (maGeo.nRotationAngle) {
+ Point aTmpPt(aAnkRect.TopLeft());
+ RotatePoint(aTmpPt,aRotateRef,maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ aTmpPt-=aAnkRect.TopLeft();
+ aAnkRect.Move(aTmpPt.X(),aTmpPt.Y());
+ }
+ rAnchorRect=aAnkRect;
+}
+
+void SdrTextObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText,
+ tools::Rectangle* pAnchorRect, bool bLineWidth ) const
+{
+ tools::Rectangle aAnkRect; // the rectangle in which we anchor
+ TakeTextAnchorRect(aAnkRect);
+ SdrTextVertAdjust eVAdj=GetTextVerticalAdjust();
+ SdrTextHorzAdjust eHAdj=GetTextHorizontalAdjust();
+ SdrTextAniKind eAniKind=GetTextAniKind();
+ SdrTextAniDirection eAniDirection=GetTextAniDirection();
+
+ bool bFitToSize(IsFitToSize());
+ bool bContourFrame=IsContourTextFrame();
+
+ bool bFrame=IsTextFrame();
+ EEControlBits nStat0=rOutliner.GetControlWord();
+ Size aNullSize;
+ if (!bContourFrame)
+ {
+ rOutliner.SetControlWord(nStat0|EEControlBits::AUTOPAGESIZE);
+ rOutliner.SetMinAutoPaperSize(aNullSize);
+ rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
+ }
+
+ if (!bFitToSize && !bContourFrame)
+ {
+ tools::Long nAnkWdt=aAnkRect.GetWidth();
+ tools::Long nAnkHgt=aAnkRect.GetHeight();
+ if (bFrame)
+ {
+ tools::Long nWdt=nAnkWdt;
+ tools::Long nHgt=nAnkHgt;
+
+ bool bInEditMode = IsInEditMode();
+
+ if (!bInEditMode && (eAniKind==SdrTextAniKind::Scroll || eAniKind==SdrTextAniKind::Alternate || eAniKind==SdrTextAniKind::Slide))
+ {
+ // unlimited paper size for ticker text
+ if (eAniDirection==SdrTextAniDirection::Left || eAniDirection==SdrTextAniDirection::Right) nWdt=1000000;
+ if (eAniDirection==SdrTextAniDirection::Up || eAniDirection==SdrTextAniDirection::Down) nHgt=1000000;
+ }
+
+ bool bChainedFrame = IsChainable();
+ // Might be required for overflow check working: do limit height to frame if box is chainable.
+ if (!bChainedFrame) {
+ // #i119885# Do not limit/force height to geometrical frame (vice versa for vertical writing)
+
+ if(IsVerticalWriting())
+ {
+ nWdt = 1000000;
+ }
+ else
+ {
+ nHgt = 1000000;
+ }
+ }
+
+ rOutliner.SetMaxAutoPaperSize(Size(nWdt,nHgt));
+ }
+
+ // New try with _BLOCK for hor and ver after completely
+ // supporting full width for vertical text.
+ if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
+ {
+ rOutliner.SetMinAutoPaperSize(Size(nAnkWdt, 0));
+ rOutliner.SetMinColumnWrapHeight(nAnkHgt);
+ }
+
+ if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
+ {
+ rOutliner.SetMinAutoPaperSize(Size(0, nAnkHgt));
+ rOutliner.SetMinColumnWrapHeight(nAnkWdt);
+ }
+ }
+
+ rOutliner.SetPaperSize(aNullSize);
+ if (bContourFrame)
+ ImpSetContourPolygon( rOutliner, aAnkRect, bLineWidth );
+
+ // put text into the outliner, if available from the edit outliner
+ SdrText* pText = getActiveText();
+ OutlinerParaObject* pOutlinerParaObject = pText ? pText->GetOutlinerParaObject() : nullptr;
+ std::optional<OutlinerParaObject> pPara;
+ if (mpEditingOutliner && !bNoEditText)
+ pPara = mpEditingOutliner->CreateParaObject();
+ else if (pOutlinerParaObject)
+ pPara = *pOutlinerParaObject;
+
+ if (pPara)
+ {
+ const bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner);
+ const SdrTextObj* pTestObj = rOutliner.GetTextObj();
+
+ if( !pTestObj || !bHitTest || pTestObj != this ||
+ pTestObj->GetOutlinerParaObject() != pOutlinerParaObject )
+ {
+ if( bHitTest ) // #i33696# take back fix #i27510#
+ {
+ rOutliner.SetTextObj( this );
+ rOutliner.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue());
+ }
+
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetText(*pPara);
+ }
+ }
+ else
+ {
+ rOutliner.SetTextObj( nullptr );
+ }
+
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetControlWord(nStat0);
+
+ if( pText )
+ pText->CheckPortionInfo(rOutliner);
+
+ Point aTextPos(aAnkRect.TopLeft());
+ Size aTextSiz(rOutliner.GetPaperSize()); // GetPaperSize() adds a little tolerance, right?
+
+ // For draw objects containing text correct hor/ver alignment if text is bigger
+ // than the object itself. Without that correction, the text would always be
+ // formatted to the left edge (or top edge when vertical) of the draw object.
+ if(!IsTextFrame())
+ {
+ if(aAnkRect.GetWidth() < aTextSiz.Width() && !IsVerticalWriting())
+ {
+ // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
+ // else the alignment is wanted.
+ if(SDRTEXTHORZADJUST_BLOCK == eHAdj)
+ {
+ eHAdj = SDRTEXTHORZADJUST_CENTER;
+ }
+ }
+
+ if(aAnkRect.GetHeight() < aTextSiz.Height() && IsVerticalWriting())
+ {
+ // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
+ // else the alignment is wanted.
+ if(SDRTEXTVERTADJUST_BLOCK == eVAdj)
+ {
+ eVAdj = SDRTEXTVERTADJUST_CENTER;
+ }
+ }
+ }
+
+ if (eHAdj==SDRTEXTHORZADJUST_CENTER || eHAdj==SDRTEXTHORZADJUST_RIGHT)
+ {
+ tools::Long nFreeWdt=aAnkRect.GetWidth()-aTextSiz.Width();
+ if (eHAdj==SDRTEXTHORZADJUST_CENTER)
+ aTextPos.AdjustX(nFreeWdt/2 );
+ if (eHAdj==SDRTEXTHORZADJUST_RIGHT)
+ aTextPos.AdjustX(nFreeWdt );
+ }
+ if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
+ {
+ tools::Long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
+ if (eVAdj==SDRTEXTVERTADJUST_CENTER)
+ aTextPos.AdjustY(nFreeHgt/2 );
+ if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
+ aTextPos.AdjustY(nFreeHgt );
+ }
+ if (maGeo.nRotationAngle)
+ RotatePoint(aTextPos,aAnkRect.TopLeft(),maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+
+ if (pAnchorRect)
+ *pAnchorRect=aAnkRect;
+
+ // rTextRect might not be correct in some cases at ContourFrame
+ rTextRect=tools::Rectangle(aTextPos,aTextSiz);
+ if (bContourFrame)
+ rTextRect=aAnkRect;
+}
+
+bool SdrTextObj::CanCreateEditOutlinerParaObject() const
+{
+ if( HasTextImpl( mpEditingOutliner ) )
+ {
+ return mpEditingOutliner->GetParagraphCount() > 0;
+ }
+ return false;
+}
+
+std::optional<OutlinerParaObject> SdrTextObj::CreateEditOutlinerParaObject() const
+{
+ std::optional<OutlinerParaObject> pPara;
+ if( HasTextImpl( mpEditingOutliner ) )
+ {
+ sal_Int32 nParaCount = mpEditingOutliner->GetParagraphCount();
+ pPara = mpEditingOutliner->CreateParaObject(0, nParaCount);
+ }
+ return pPara;
+}
+
+void SdrTextObj::ImpSetCharStretching(SdrOutliner& rOutliner, const Size& rTextSize, const Size& rShapeSize, Fraction& rFitXCorrection)
+{
+ OutputDevice* pOut = rOutliner.GetRefDevice();
+ bool bNoStretching(false);
+
+ if(pOut && pOut->GetOutDevType() == OUTDEV_PRINTER)
+ {
+ // check whether CharStretching is possible at all
+ GDIMetaFile* pMtf = pOut->GetConnectMetaFile();
+ OUString aTestString(u'J');
+
+ if(pMtf && (!pMtf->IsRecord() || pMtf->IsPause()))
+ pMtf = nullptr;
+
+ if(pMtf)
+ pMtf->Pause(true);
+
+ vcl::Font aOriginalFont(pOut->GetFont());
+ vcl::Font aTmpFont( OutputDevice::GetDefaultFont( DefaultFontType::SERIF, LANGUAGE_SYSTEM, GetDefaultFontFlags::OnlyOne ) );
+
+ aTmpFont.SetFontSize(Size(0,100));
+ pOut->SetFont(aTmpFont);
+ Size aSize1(pOut->GetTextWidth(aTestString), pOut->GetTextHeight());
+ aTmpFont.SetFontSize(Size(800,100));
+ pOut->SetFont(aTmpFont);
+ Size aSize2(pOut->GetTextWidth(aTestString), pOut->GetTextHeight());
+ pOut->SetFont(aOriginalFont);
+
+ if(pMtf)
+ pMtf->Pause(false);
+
+ bNoStretching = (aSize1 == aSize2);
+
+#ifdef _WIN32
+ // Windows zooms the font proportionally when using Size(100,500),
+ // we don't like that.
+ if(aSize2.Height() >= aSize1.Height() * 2)
+ {
+ bNoStretching = true;
+ }
+#endif
+ }
+ unsigned nLoopCount=0;
+ bool bNoMoreLoop = false;
+ tools::Long nXDiff0=0x7FFFFFFF;
+ tools::Long nWantWdt=rShapeSize.Width();
+ tools::Long nIsWdt=rTextSize.Width();
+ if (nIsWdt==0) nIsWdt=1;
+
+ tools::Long nWantHgt=rShapeSize.Height();
+ tools::Long nIsHgt=rTextSize.Height();
+ if (nIsHgt==0) nIsHgt=1;
+
+ tools::Long nXTolPl=nWantWdt/100; // tolerance: +1%
+ tools::Long nXTolMi=nWantWdt/25; // tolerance: -4%
+ tools::Long nXCorr =nWantWdt/20; // correction scale: 5%
+
+ tools::Long nX=(nWantWdt*100) /nIsWdt; // calculate X stretching
+ tools::Long nY=(nWantHgt*100) /nIsHgt; // calculate Y stretching
+ bool bChkX = true;
+ if (bNoStretching) { // might only be possible proportionally
+ if (nX>nY) { nX=nY; bChkX=false; }
+ else { nY=nX; }
+ }
+
+ while (nLoopCount<5 && !bNoMoreLoop) {
+ if (nX<0) nX=-nX;
+ if (nX<1) { nX=1; bNoMoreLoop = true; }
+ if (nX>65535) { nX=65535; bNoMoreLoop = true; }
+
+ if (nY<0) nY=-nY;
+ if (nY<1) { nY=1; bNoMoreLoop = true; }
+ if (nY>65535) { nY=65535; bNoMoreLoop = true; }
+
+ // exception, there is no text yet (horizontal case)
+ if(nIsWdt <= 1)
+ {
+ nX = nY;
+ bNoMoreLoop = true;
+ }
+
+ // exception, there is no text yet (vertical case)
+ if(nIsHgt <= 1)
+ {
+ nY = nX;
+ bNoMoreLoop = true;
+ }
+
+ rOutliner.SetGlobalCharStretching(static_cast<sal_uInt16>(nX),static_cast<sal_uInt16>(nY));
+ nLoopCount++;
+ Size aSiz(rOutliner.CalcTextSize());
+ tools::Long nXDiff=aSiz.Width()-nWantWdt;
+ rFitXCorrection=Fraction(nWantWdt,aSiz.Width());
+ if (((nXDiff>=nXTolMi || !bChkX) && nXDiff<=nXTolPl) || nXDiff==nXDiff0) {
+ bNoMoreLoop = true;
+ } else {
+ // correct stretching factors
+ tools::Long nMul=nWantWdt;
+ tools::Long nDiv=aSiz.Width();
+ if (std::abs(nXDiff)<=2*nXCorr) {
+ if (nMul>nDiv) nDiv+=(nMul-nDiv)/2; // but only add half of what we calculated,
+ else nMul+=(nDiv-nMul)/2; // because the EditEngine calculates wrongly later on
+ }
+ nX=nX*nMul/nDiv;
+ if (bNoStretching) nY=nX;
+ }
+ nXDiff0=nXDiff;
+ }
+}
+
+OUString SdrTextObj::TakeObjNameSingul() const
+{
+ OUString aStr;
+
+ switch(meTextKind)
+ {
+ case SdrObjKind::OutlineText:
+ {
+ aStr = SvxResId(STR_ObjNameSingulOUTLINETEXT);
+ break;
+ }
+
+ case SdrObjKind::TitleText :
+ {
+ aStr = SvxResId(STR_ObjNameSingulTITLETEXT);
+ break;
+ }
+
+ default:
+ {
+ if(IsLinkedText())
+ aStr = SvxResId(STR_ObjNameSingulTEXTLNK);
+ else
+ aStr = SvxResId(STR_ObjNameSingulTEXT);
+ break;
+ }
+ }
+
+ OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+ if(pOutlinerParaObject && meTextKind != SdrObjKind::OutlineText)
+ {
+ // shouldn't currently cause any problems at OUTLINETEXT
+ OUString aStr2(comphelper::string::stripStart(pOutlinerParaObject->GetTextObject().GetText(0), ' '));
+
+ // avoid non expanded text portions in object name
+ // (second condition is new)
+ if(!aStr2.isEmpty() && aStr2.indexOf(u'\x00FF') == -1)
+ {
+ // space between ResStr and content text
+ aStr += " \'";
+
+ if(aStr2.getLength() > 10)
+ {
+ aStr2 = OUString::Concat(aStr2.subView(0, 8)) + "...";
+ }
+
+ aStr += aStr2 + "\'";
+ }
+ }
+
+ OUString sName(aStr);
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+OUString SdrTextObj::TakeObjNamePlural() const
+{
+ OUString sName;
+ switch (meTextKind)
+ {
+ case SdrObjKind::OutlineText: sName=SvxResId(STR_ObjNamePluralOUTLINETEXT); break;
+ case SdrObjKind::TitleText : sName=SvxResId(STR_ObjNamePluralTITLETEXT); break;
+ default: {
+ if (IsLinkedText()) {
+ sName=SvxResId(STR_ObjNamePluralTEXTLNK);
+ } else {
+ sName=SvxResId(STR_ObjNamePluralTEXT);
+ }
+ } break;
+ } // switch
+ return sName;
+}
+
+SdrTextObj* SdrTextObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrTextObj(rTargetModel, *this);
+}
+
+basegfx::B2DPolyPolygon SdrTextObj::TakeXorPoly() const
+{
+ tools::Polygon aPol(maRect);
+ if (maGeo.nShearAngle) ShearPoly(aPol,maRect.TopLeft(),maGeo.mfTanShearAngle);
+ if (maGeo.nRotationAngle) RotatePoly(aPol,maRect.TopLeft(),maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+
+ basegfx::B2DPolyPolygon aRetval;
+ aRetval.append(aPol.getB2DPolygon());
+ return aRetval;
+}
+
+basegfx::B2DPolyPolygon SdrTextObj::TakeContour() const
+{
+ basegfx::B2DPolyPolygon aRetval(SdrAttrObj::TakeContour());
+
+ // and now add the BoundRect of the text, if necessary
+ if ( GetOutlinerParaObject() && !IsFontwork() && !IsContourTextFrame() )
+ {
+ // using Clone()-Paint() strategy inside TakeContour() leaves a destroyed
+ // SdrObject as pointer in DrawOutliner. Set *this again in fetching the outliner
+ // in every case
+ SdrOutliner& rOutliner=ImpGetDrawOutliner();
+
+ tools::Rectangle aAnchor2;
+ tools::Rectangle aR;
+ TakeTextRect(rOutliner,aR,false,&aAnchor2);
+ rOutliner.Clear();
+ bool bFitToSize(IsFitToSize());
+ if (bFitToSize) aR=aAnchor2;
+ tools::Polygon aPol(aR);
+ if (maGeo.nRotationAngle) RotatePoly(aPol,aR.TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+
+ aRetval.append(aPol.getB2DPolygon());
+ }
+
+ return aRetval;
+}
+
+void SdrTextObj::RecalcSnapRect()
+{
+ if (maGeo.nRotationAngle || maGeo.nShearAngle)
+ {
+ maSnapRect = Rect2Poly(maRect, maGeo).GetBoundRect();
+ } else {
+ maSnapRect = maRect;
+ }
+}
+
+sal_uInt32 SdrTextObj::GetSnapPointCount() const
+{
+ return 4;
+}
+
+Point SdrTextObj::GetSnapPoint(sal_uInt32 i) const
+{
+ Point aP;
+ switch (i) {
+ case 0: aP=maRect.TopLeft(); break;
+ case 1: aP=maRect.TopRight(); break;
+ case 2: aP=maRect.BottomLeft(); break;
+ case 3: aP=maRect.BottomRight(); break;
+ default: aP=maRect.Center(); break;
+ }
+ if (maGeo.nShearAngle) ShearPoint(aP,maRect.TopLeft(),maGeo.mfTanShearAngle);
+ if (maGeo.nRotationAngle) RotatePoint(aP,maRect.TopLeft(),maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ return aP;
+}
+
+// Extracted from ImpGetDrawOutliner()
+void SdrTextObj::ImpInitDrawOutliner( SdrOutliner& rOutl ) const
+{
+ rOutl.SetUpdateLayout(false);
+ OutlinerMode nOutlinerMode = OutlinerMode::OutlineObject;
+ if ( !IsOutlText() )
+ nOutlinerMode = OutlinerMode::TextObject;
+ rOutl.Init( nOutlinerMode );
+
+ rOutl.SetGlobalCharStretching();
+ EEControlBits nStat=rOutl.GetControlWord();
+ nStat &= ~EEControlBits(EEControlBits::STRETCHING|EEControlBits::AUTOPAGESIZE);
+ rOutl.SetControlWord(nStat);
+ Size aMaxSize(100000,100000);
+ rOutl.SetMinAutoPaperSize(Size());
+ rOutl.SetMaxAutoPaperSize(aMaxSize);
+ rOutl.SetPaperSize(aMaxSize);
+ rOutl.ClearPolygon();
+}
+
+SdrOutliner& SdrTextObj::ImpGetDrawOutliner() const
+{
+ SdrOutliner& rOutl(getSdrModelFromSdrObject().GetDrawOutliner(this));
+
+ // Code extracted to ImpInitDrawOutliner()
+ ImpInitDrawOutliner( rOutl );
+
+ return rOutl;
+}
+
+// Extracted from Paint()
+void SdrTextObj::ImpSetupDrawOutlinerForPaint( bool bContourFrame,
+ SdrOutliner& rOutliner,
+ tools::Rectangle& rTextRect,
+ tools::Rectangle& rAnchorRect,
+ tools::Rectangle& rPaintRect,
+ Fraction& rFitXCorrection ) const
+{
+ if (!bContourFrame)
+ {
+ // FitToSize can't be used together with ContourFrame for now
+ if (IsFitToSize() || IsAutoFit())
+ {
+ EEControlBits nStat=rOutliner.GetControlWord();
+ nStat|=EEControlBits::STRETCHING|EEControlBits::AUTOPAGESIZE;
+ rOutliner.SetControlWord(nStat);
+ }
+ }
+ rOutliner.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue());
+ TakeTextRect(rOutliner, rTextRect, false, &rAnchorRect);
+ rPaintRect = rTextRect;
+
+ if (bContourFrame)
+ return;
+
+ // FitToSize can't be used together with ContourFrame for now
+ if (IsFitToSize())
+ {
+ ImpSetCharStretching(rOutliner,rTextRect.GetSize(),rAnchorRect.GetSize(),rFitXCorrection);
+ rPaintRect=rAnchorRect;
+ }
+ else if (IsAutoFit())
+ {
+ ImpAutoFitText(rOutliner);
+ }
+}
+
+sal_uInt16 SdrTextObj::GetFontScaleY() const
+{
+ SdrOutliner& rOutliner = ImpGetDrawOutliner();
+ // This eventually calls ImpAutoFitText
+ UpdateOutlinerFormatting(rOutliner, o3tl::temporary(tools::Rectangle()));
+
+ sal_uInt16 nStretchY;
+ rOutliner.GetGlobalCharStretching(o3tl::temporary(sal_uInt16()), nStretchY);
+ return nStretchY;
+}
+
+void SdrTextObj::ImpAutoFitText( SdrOutliner& rOutliner ) const
+{
+ const Size aShapeSize=GetSnapRect().GetSize();
+ ImpAutoFitText( rOutliner,
+ Size(aShapeSize.Width()-GetTextLeftDistance()-GetTextRightDistance(),
+ aShapeSize.Height()-GetTextUpperDistance()-GetTextLowerDistance()),
+ IsVerticalWriting() );
+}
+
+void SdrTextObj::ImpAutoFitText(SdrOutliner& rOutliner, const Size& rTextSize,
+ bool bIsVerticalWriting) const
+{
+ // EditEngine formatting is unstable enough for
+ // line-breaking text that we need some more samples
+
+ // loop early-exits if we detect an already attained value
+ sal_uInt16 nMinStretchX=0, nMinStretchY=0;
+ sal_uInt16 aOldStretchXVals[]={0,0,0,0,0,0,0,0,0,0};
+ const size_t aStretchArySize=SAL_N_ELEMENTS(aOldStretchXVals);
+ for(unsigned int i=0; i<aStretchArySize; ++i)
+ {
+ const Size aCurrTextSize = rOutliner.CalcTextSizeNTP();
+ double fFactor(1.0);
+ if( bIsVerticalWriting )
+ {
+ if (aCurrTextSize.Width() != 0)
+ {
+ fFactor = double(rTextSize.Width())/aCurrTextSize.Width();
+ }
+ }
+ else if (aCurrTextSize.Height() != 0)
+ {
+ fFactor = double(rTextSize.Height())/aCurrTextSize.Height();
+ }
+ // fFactor scales in both x and y directions
+ // - this is fine for bulleted words
+ // - but it scales too much for a long paragraph
+ // - taking sqrt scales long paragraphs the best
+ // - bulleted words will have to go through more iterations
+ fFactor = std::sqrt(fFactor);
+
+ sal_uInt16 nCurrStretchX, nCurrStretchY;
+ rOutliner.GetGlobalCharStretching(nCurrStretchX, nCurrStretchY);
+
+ if (fFactor >= 1.0 )
+ {
+ // resulting text area fits into available shape rect -
+ // err on the larger stretching, to optimally fill area
+ nMinStretchX = std::max(nMinStretchX,nCurrStretchX);
+ nMinStretchY = std::max(nMinStretchY,nCurrStretchY);
+ }
+
+ aOldStretchXVals[i] = nCurrStretchX;
+ if( std::find(aOldStretchXVals, aOldStretchXVals+i, nCurrStretchX) != aOldStretchXVals+i )
+ break; // same value already attained once; algo is looping, exit
+
+ if (fFactor < 1.0 || nCurrStretchX != 100)
+ {
+ nCurrStretchX = sal::static_int_cast<sal_uInt16>(nCurrStretchX*fFactor);
+ nCurrStretchY = sal::static_int_cast<sal_uInt16>(nCurrStretchY*fFactor);
+ rOutliner.SetGlobalCharStretching(std::min(sal_uInt16(100),nCurrStretchX),
+ std::min(sal_uInt16(100),nCurrStretchY));
+ SAL_INFO("svx", "zoom is " << nCurrStretchX);
+ }
+ }
+
+ const SdrTextFitToSizeTypeItem& rItem = GetObjectItem(SDRATTR_TEXT_FITTOSIZE);
+ if (rItem.GetMaxScale() > 0)
+ {
+ nMinStretchX = std::min<sal_uInt16>(rItem.GetMaxScale(), nMinStretchX);
+ nMinStretchY = std::min<sal_uInt16>(rItem.GetMaxScale(), nMinStretchY);
+ }
+
+ SAL_INFO("svx", "final zoom is " << nMinStretchX);
+ rOutliner.SetGlobalCharStretching(std::min(sal_uInt16(100),nMinStretchX),
+ std::min(sal_uInt16(100),nMinStretchY));
+}
+
+void SdrTextObj::SetupOutlinerFormatting( SdrOutliner& rOutl, tools::Rectangle& rPaintRect ) const
+{
+ ImpInitDrawOutliner( rOutl );
+ UpdateOutlinerFormatting( rOutl, rPaintRect );
+}
+
+void SdrTextObj::UpdateOutlinerFormatting( SdrOutliner& rOutl, tools::Rectangle& rPaintRect ) const
+{
+ tools::Rectangle aTextRect;
+ tools::Rectangle aAnchorRect;
+ Fraction aFitXCorrection(1,1);
+
+ const bool bContourFrame(IsContourTextFrame());
+ const MapMode aMapMode(
+ getSdrModelFromSdrObject().GetScaleUnit(),
+ Point(0,0),
+ getSdrModelFromSdrObject().GetScaleFraction(),
+ getSdrModelFromSdrObject().GetScaleFraction());
+
+ rOutl.SetRefMapMode(aMapMode);
+ ImpSetupDrawOutlinerForPaint(
+ bContourFrame,
+ rOutl,
+ aTextRect,
+ aAnchorRect,
+ rPaintRect,
+ aFitXCorrection);
+}
+
+
+OutlinerParaObject* SdrTextObj::GetOutlinerParaObject() const
+{
+ SdrText* pText = getActiveText();
+ if( pText )
+ return pText->GetOutlinerParaObject();
+ else
+ return nullptr;
+}
+
+void SdrTextObj::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject)
+{
+ NbcSetOutlinerParaObjectForText( std::move(pTextObject), getActiveText() );
+}
+
+namespace
+{
+ bool IsAutoGrow(const SdrTextObj& rObj)
+ {
+ bool bAutoGrow = rObj.IsAutoGrowHeight() || rObj.IsAutoGrowWidth();
+ return bAutoGrow && !utl::ConfigManager::IsFuzzing();
+ }
+}
+
+void SdrTextObj::NbcSetOutlinerParaObjectForText( std::optional<OutlinerParaObject> pTextObject, SdrText* pText )
+{
+ if( pText )
+ pText->SetOutlinerParaObject( std::move(pTextObject) );
+
+ if (pText && pText->GetOutlinerParaObject())
+ {
+ SvxWritingModeItem aWritingMode(pText->GetOutlinerParaObject()->IsEffectivelyVertical() && pText->GetOutlinerParaObject()->IsTopToBottom()
+ ? css::text::WritingMode_TB_RL
+ : css::text::WritingMode_LR_TB,
+ SDRATTR_TEXTDIRECTION);
+ GetProperties().SetObjectItemDirect(aWritingMode);
+ }
+
+ SetTextSizeDirty();
+ if (IsTextFrame() && IsAutoGrow(*this))
+ { // adapt text frame!
+ NbcAdjustTextFrameWidthAndHeight();
+ }
+ if (!IsTextFrame())
+ {
+ // the SnapRect keeps its size
+ SetBoundAndSnapRectsDirty(true);
+ }
+
+ // always invalidate BoundRect on change
+ SetBoundRectDirty();
+ ActionChanged();
+
+ ImpSetTextStyleSheetListeners();
+}
+
+void SdrTextObj::NbcReformatText()
+{
+ SdrText* pText = getActiveText();
+ if( !(pText && pText->GetOutlinerParaObject()) )
+ return;
+
+ pText->ReformatText();
+ if (mbTextFrame)
+ {
+ NbcAdjustTextFrameWidthAndHeight();
+ }
+ else
+ {
+ // the SnapRect keeps its size
+ SetBoundRectDirty();
+ SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+ }
+ SetTextSizeDirty();
+ ActionChanged();
+ // i22396
+ // Necessary here since we have no compare operator at the outliner
+ // para object which may detect changes regarding the combination
+ // of outliner para data and configuration (e.g., change of
+ // formatting of text numerals)
+ GetViewContact().flushViewObjectContacts(false);
+}
+
+std::unique_ptr<SdrObjGeoData> SdrTextObj::NewGeoData() const
+{
+ return std::make_unique<SdrTextObjGeoData>();
+}
+
+void SdrTextObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrAttrObj::SaveGeoData(rGeo);
+ SdrTextObjGeoData& rTGeo=static_cast<SdrTextObjGeoData&>(rGeo);
+ rTGeo.maRect = maRect;
+ rTGeo.maGeo = maGeo;
+}
+
+void SdrTextObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{ // RectsDirty is called by SdrObject
+ SdrAttrObj::RestoreGeoData(rGeo);
+ const SdrTextObjGeoData& rTGeo=static_cast<const SdrTextObjGeoData&>(rGeo);
+ NbcSetLogicRect(rTGeo.maRect);
+ maGeo = rTGeo.maGeo;
+ SetTextSizeDirty();
+}
+
+drawing::TextFitToSizeType SdrTextObj::GetFitToSize() const
+{
+ drawing::TextFitToSizeType eType = drawing::TextFitToSizeType_NONE;
+
+ if(!IsAutoGrowWidth())
+ eType = GetObjectItem(SDRATTR_TEXT_FITTOSIZE).GetValue();
+
+ return eType;
+}
+
+const tools::Rectangle& SdrTextObj::GetGeoRect() const
+{
+ return maRect;
+}
+
+void SdrTextObj::ForceOutlinerParaObject()
+{
+ SdrText* pText = getActiveText();
+ if( pText && (pText->GetOutlinerParaObject() == nullptr) )
+ {
+ OutlinerMode nOutlMode = OutlinerMode::TextObject;
+ if( IsTextFrame() && meTextKind == SdrObjKind::OutlineText )
+ nOutlMode = OutlinerMode::OutlineObject;
+
+ pText->ForceOutlinerParaObject( nOutlMode );
+ }
+}
+
+TextChain *SdrTextObj::GetTextChain() const
+{
+ //if (!IsChainable())
+ // return NULL;
+
+ return getSdrModelFromSdrObject().GetTextChain();
+}
+
+bool SdrTextObj::IsVerticalWriting() const
+{
+ if(mpEditingOutliner)
+ {
+ return mpEditingOutliner->IsVertical();
+ }
+
+ OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+ if(pOutlinerParaObject)
+ {
+ return pOutlinerParaObject->IsEffectivelyVertical();
+ }
+
+ return false;
+}
+
+void SdrTextObj::SetVerticalWriting(bool bVertical)
+{
+ OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+
+ if( !pOutlinerParaObject && bVertical )
+ {
+ // we only need to force an outliner para object if the default of
+ // horizontal text is changed
+ ForceOutlinerParaObject();
+ pOutlinerParaObject = GetOutlinerParaObject();
+ }
+
+ if (!pOutlinerParaObject ||
+ (pOutlinerParaObject->IsEffectivelyVertical() == bVertical))
+ return;
+
+ // get item settings
+ const SfxItemSet& rSet = GetObjectItemSet();
+ bool bAutoGrowWidth = rSet.Get(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue();
+ bool bAutoGrowHeight = rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
+
+ // Also exchange hor/ver adjust items
+ SdrTextHorzAdjust eHorz = rSet.Get(SDRATTR_TEXT_HORZADJUST).GetValue();
+ SdrTextVertAdjust eVert = rSet.Get(SDRATTR_TEXT_VERTADJUST).GetValue();
+
+ // rescue object size
+ tools::Rectangle aObjectRect = GetSnapRect();
+
+ // prepare ItemSet to set exchanged width and height items
+ SfxItemSetFixed<SDRATTR_TEXT_AUTOGROWHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT,
+ // Expanded item ranges to also support hor and ver adjust.
+ SDRATTR_TEXT_VERTADJUST, SDRATTR_TEXT_VERTADJUST,
+ SDRATTR_TEXT_AUTOGROWWIDTH, SDRATTR_TEXT_HORZADJUST> aNewSet(*rSet.GetPool());
+
+ aNewSet.Put(rSet);
+ aNewSet.Put(makeSdrTextAutoGrowWidthItem(bAutoGrowHeight));
+ aNewSet.Put(makeSdrTextAutoGrowHeightItem(bAutoGrowWidth));
+
+ // Exchange horz and vert adjusts
+ switch (eVert)
+ {
+ case SDRTEXTVERTADJUST_TOP: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT)); break;
+ case SDRTEXTVERTADJUST_CENTER: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER)); break;
+ case SDRTEXTVERTADJUST_BOTTOM: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT)); break;
+ case SDRTEXTVERTADJUST_BLOCK: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK)); break;
+ }
+ switch (eHorz)
+ {
+ case SDRTEXTHORZADJUST_LEFT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM)); break;
+ case SDRTEXTHORZADJUST_CENTER: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER)); break;
+ case SDRTEXTHORZADJUST_RIGHT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP)); break;
+ case SDRTEXTHORZADJUST_BLOCK: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BLOCK)); break;
+ }
+
+ SetObjectItemSet(aNewSet);
+
+ pOutlinerParaObject = GetOutlinerParaObject();
+ if (pOutlinerParaObject)
+ {
+ // set ParaObject orientation accordingly
+ pOutlinerParaObject->SetVertical(bVertical);
+ }
+
+ // restore object size
+ SetSnapRect(aObjectRect);
+}
+
+bool SdrTextObj::IsTopToBottom() const
+{
+ if (mpEditingOutliner)
+ return mpEditingOutliner->IsTopToBottom();
+
+ if (OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject())
+ return pOutlinerParaObject->IsTopToBottom();
+
+ return false;
+}
+
+// transformation interface for StarOfficeAPI. This implements support for
+// homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
+// moment it contains a shearX, rotation and translation, but for setting all linear
+// transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
+
+
+// gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
+// with the base geometry and returns TRUE. Otherwise it returns FALSE.
+bool SdrTextObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
+{
+ // get turn and shear
+ double fRotate = toRadians(maGeo.nRotationAngle);
+ double fShearX = toRadians(maGeo.nShearAngle);
+
+ // get aRect, this is the unrotated snaprect
+ tools::Rectangle aRectangle(maRect);
+
+ // fill other values
+ basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight());
+ basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top());
+
+ // position maybe relative to anchorpos, convert
+ if( getSdrModelFromSdrObject().IsWriter() )
+ {
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // build matrix
+ rMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale,
+ basegfx::fTools::equalZero(fShearX) ? 0.0 : tan(fShearX),
+ basegfx::fTools::equalZero(fRotate) ? 0.0 : -fRotate,
+ aTranslate);
+
+ return false;
+}
+
+// sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
+// If it's an SdrPathObj it will use the provided geometry information. The Polygon has
+// to use (0,0) as upper left and will be scaled to the given size in the matrix.
+void SdrTextObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
+{
+ // break up matrix
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate(0.0);
+ double fShearX(0.0);
+ rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // flip?
+ bool bFlipX = aScale.getX() < 0.0,
+ bFlipY = aScale.getY() < 0.0;
+ if (bFlipX)
+ {
+ aScale.setX(fabs(aScale.getX()));
+ }
+ if (bFlipY)
+ {
+ aScale.setY(fabs(aScale.getY()));
+ }
+
+ // reset object shear and rotations
+ maGeo.nRotationAngle = 0_deg100;
+ maGeo.RecalcSinCos();
+ maGeo.nShearAngle = 0_deg100;
+ maGeo.RecalcTan();
+
+ // if anchor is used, make position relative to it
+ if( getSdrModelFromSdrObject().IsWriter() )
+ {
+ if(GetAnchorPos().X() || GetAnchorPos().Y())
+ {
+ aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
+ }
+ }
+
+ // build and set BaseRect (use scale)
+ Size aSize(FRound(aScale.getX()), FRound(aScale.getY()));
+ tools::Rectangle aBaseRect(Point(), aSize);
+ SetSnapRect(aBaseRect);
+
+ // flip?
+ if (bFlipX)
+ {
+ Mirror(Point(), Point(0, 1));
+ }
+ if (bFlipY)
+ {
+ Mirror(Point(), Point(1, 0));
+ }
+
+ // shear?
+ if(!basegfx::fTools::equalZero(fShearX))
+ {
+ GeoStat aGeoStat;
+ aGeoStat.nShearAngle = Degree100(FRound(basegfx::rad2deg<100>(atan(fShearX))));
+ aGeoStat.RecalcTan();
+ Shear(Point(), aGeoStat.nShearAngle, aGeoStat.mfTanShearAngle, false);
+ }
+
+ // rotation?
+ if(!basegfx::fTools::equalZero(fRotate))
+ {
+ GeoStat aGeoStat;
+
+ // #i78696#
+ // fRotate is matematically correct, but aGeoStat.nRotationAngle is
+ // mirrored -> mirror value here
+ aGeoStat.nRotationAngle = NormAngle36000(Degree100(FRound(-basegfx::rad2deg<100>(fRotate))));
+ aGeoStat.RecalcSinCos();
+ Rotate(Point(), aGeoStat.nRotationAngle, aGeoStat.mfSinRotationAngle, aGeoStat.mfCosRotationAngle);
+ }
+
+ // translate?
+ if(!aTranslate.equalZero())
+ {
+ Move(Size(FRound(aTranslate.getX()), FRound(aTranslate.getY())));
+ }
+}
+
+bool SdrTextObj::IsReallyEdited() const
+{
+ return mpEditingOutliner && mpEditingOutliner->IsModified();
+}
+
+// moved inlines here form hxx
+
+tools::Long SdrTextObj::GetEckenradius() const
+{
+ return GetObjectItemSet().Get(SDRATTR_CORNER_RADIUS).GetValue();
+}
+
+tools::Long SdrTextObj::GetMinTextFrameHeight() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXT_MINFRAMEHEIGHT).GetValue();
+}
+
+tools::Long SdrTextObj::GetMaxTextFrameHeight() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXT_MAXFRAMEHEIGHT).GetValue();
+}
+
+tools::Long SdrTextObj::GetMinTextFrameWidth() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXT_MINFRAMEWIDTH).GetValue();
+}
+
+tools::Long SdrTextObj::GetMaxTextFrameWidth() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXT_MAXFRAMEWIDTH).GetValue();
+}
+
+bool SdrTextObj::IsFontwork() const
+{
+ return !mbTextFrame // Default is FALSE
+ && GetObjectItemSet().Get(XATTR_FORMTXTSTYLE).GetValue() != XFormTextStyle::NONE;
+}
+
+bool SdrTextObj::IsHideContour() const
+{
+ return !mbTextFrame // Default is: no, don't HideContour; HideContour not together with TextFrames
+ && GetObjectItemSet().Get(XATTR_FORMTXTHIDEFORM).GetValue();
+}
+
+bool SdrTextObj::IsContourTextFrame() const
+{
+ return !mbTextFrame // ContourFrame not together with normal TextFrames
+ && GetObjectItemSet().Get(SDRATTR_TEXT_CONTOURFRAME).GetValue();
+}
+
+tools::Long SdrTextObj::GetTextLeftDistance() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXT_LEFTDIST).GetValue();
+}
+
+tools::Long SdrTextObj::GetTextRightDistance() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXT_RIGHTDIST).GetValue();
+}
+
+tools::Long SdrTextObj::GetTextUpperDistance() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXT_UPPERDIST).GetValue();
+}
+
+tools::Long SdrTextObj::GetTextLowerDistance() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXT_LOWERDIST).GetValue();
+}
+
+SdrTextAniKind SdrTextObj::GetTextAniKind() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXT_ANIKIND).GetValue();
+}
+
+SdrTextAniDirection SdrTextObj::GetTextAniDirection() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXT_ANIDIRECTION).GetValue();
+}
+
+bool SdrTextObj::HasTextColumnsNumber() const
+{
+ return GetObjectItemSet().HasItem(SDRATTR_TEXTCOLUMNS_NUMBER);
+}
+
+sal_Int16 SdrTextObj::GetTextColumnsNumber() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXTCOLUMNS_NUMBER).GetValue();
+}
+
+void SdrTextObj::SetTextColumnsNumber(sal_Int16 nColumns)
+{
+ SetObjectItem(SfxInt16Item(SDRATTR_TEXTCOLUMNS_NUMBER, nColumns));
+}
+
+bool SdrTextObj::HasTextColumnsSpacing() const
+{
+ return GetObjectItemSet().HasItem(SDRATTR_TEXTCOLUMNS_SPACING);
+}
+
+sal_Int32 SdrTextObj::GetTextColumnsSpacing() const
+{
+ return GetObjectItemSet().Get(SDRATTR_TEXTCOLUMNS_SPACING).GetValue();
+}
+
+void SdrTextObj::SetTextColumnsSpacing(sal_Int32 nSpacing)
+{
+ SetObjectItem(SdrMetricItem(SDRATTR_TEXTCOLUMNS_SPACING, nSpacing));
+}
+
+// Get necessary data for text scroll animation. ATM base it on a Text-Metafile and a
+// painting rectangle. Rotation is excluded from the returned values.
+GDIMetaFile* SdrTextObj::GetTextScrollMetaFileAndRectangle(
+ tools::Rectangle& rScrollRectangle, tools::Rectangle& rPaintRectangle)
+{
+ GDIMetaFile* pRetval = nullptr;
+ SdrOutliner& rOutliner = ImpGetDrawOutliner();
+ tools::Rectangle aTextRect;
+ tools::Rectangle aAnchorRect;
+ tools::Rectangle aPaintRect;
+ Fraction aFitXCorrection(1,1);
+ bool bContourFrame(IsContourTextFrame());
+
+ // get outliner set up. To avoid getting a somehow rotated MetaFile,
+ // temporarily disable object rotation.
+ Degree100 nAngle(maGeo.nRotationAngle);
+ maGeo.nRotationAngle = 0_deg100;
+ ImpSetupDrawOutlinerForPaint( bContourFrame, rOutliner, aTextRect, aAnchorRect, aPaintRect, aFitXCorrection );
+ maGeo.nRotationAngle = nAngle;
+
+ tools::Rectangle aScrollFrameRect(aPaintRect);
+ const SfxItemSet& rSet = GetObjectItemSet();
+ SdrTextAniDirection eDirection = rSet.Get(SDRATTR_TEXT_ANIDIRECTION).GetValue();
+
+ if(SdrTextAniDirection::Left == eDirection || SdrTextAniDirection::Right == eDirection)
+ {
+ aScrollFrameRect.SetLeft( aAnchorRect.Left() );
+ aScrollFrameRect.SetRight( aAnchorRect.Right() );
+ }
+
+ if(SdrTextAniDirection::Up == eDirection || SdrTextAniDirection::Down == eDirection)
+ {
+ aScrollFrameRect.SetTop( aAnchorRect.Top() );
+ aScrollFrameRect.SetBottom( aAnchorRect.Bottom() );
+ }
+
+ // create the MetaFile
+ pRetval = new GDIMetaFile;
+ ScopedVclPtrInstance< VirtualDevice > pBlackHole;
+ pBlackHole->EnableOutput(false);
+ pRetval->Record(pBlackHole);
+ Point aPaintPos = aPaintRect.TopLeft();
+
+ rOutliner.Draw(*pBlackHole, aPaintPos);
+
+ pRetval->Stop();
+ pRetval->WindStart();
+
+ // return PaintRectanglePixel and pRetval;
+ rScrollRectangle = aScrollFrameRect;
+ rPaintRectangle = aPaintRect;
+
+ return pRetval;
+}
+
+// Access to TextAnimationAllowed flag
+bool SdrTextObj::IsAutoFit() const
+{
+ return GetFitToSize() == drawing::TextFitToSizeType_AUTOFIT;
+}
+
+bool SdrTextObj::IsFitToSize() const
+{
+ const drawing::TextFitToSizeType eFit = GetFitToSize();
+ return (eFit == drawing::TextFitToSizeType_PROPORTIONAL
+ || eFit == drawing::TextFitToSizeType_ALLLINES);
+}
+
+void SdrTextObj::SetTextAnimationAllowed(bool bNew)
+{
+ if(mbTextAnimationAllowed != bNew)
+ {
+ mbTextAnimationAllowed = bNew;
+ ActionChanged();
+ }
+}
+
+/** called from the SdrObjEditView during text edit when the status of the edit outliner changes */
+void SdrTextObj::onEditOutlinerStatusEvent( EditStatus* pEditStatus )
+{
+ const EditStatusFlags nStat = pEditStatus->GetStatusWord();
+ const bool bGrowX = bool(nStat & EditStatusFlags::TEXTWIDTHCHANGED);
+ const bool bGrowY = bool(nStat & EditStatusFlags::TextHeightChanged);
+ if(!(mbTextFrame && (bGrowX || bGrowY)))
+ return;
+
+ if ((bGrowX && IsAutoGrowWidth()) || (bGrowY && IsAutoGrowHeight()))
+ {
+ AdjustTextFrameWidthAndHeight();
+ }
+ else if ( (IsAutoFit() || IsFitToSize()) && !mbInDownScale)
+ {
+ assert(mpEditingOutliner);
+ mbInDownScale = true;
+
+ // sucks that we cannot disable paints via
+ // mpEditingOutliner->SetUpdateMode(FALSE) - but EditEngine skips
+ // formatting as well, then.
+ ImpAutoFitText(*mpEditingOutliner);
+ mbInDownScale = false;
+ }
+}
+
+/* Begin chaining code */
+
+// XXX: Make it a method somewhere?
+static SdrObject *ImpGetObjByName(SdrObjList const *pObjList, std::u16string_view aObjName)
+{
+ // scan the whole list
+ size_t nObjCount = pObjList->GetObjCount();
+ for (size_t i = 0; i < nObjCount; i++) {
+ SdrObject *pCurObj = pObjList->GetObj(i);
+
+ if (pCurObj->GetName() == aObjName) {
+ return pCurObj;
+ }
+ }
+ // not found
+ return nullptr;
+}
+
+// XXX: Make it a (private) method of SdrTextObj
+static void ImpUpdateChainLinks(SdrTextObj *pTextObj, std::u16string_view aNextLinkName)
+{
+ // XXX: Current implementation constraints text boxes to be on the same page
+
+ // No next link
+ if (aNextLinkName.empty()) {
+ pTextObj->SetNextLinkInChain(nullptr);
+ return;
+ }
+
+ SdrPage *pPage(pTextObj->getSdrPageFromSdrObject());
+ assert(pPage);
+ SdrTextObj *pNextTextObj = dynamic_cast< SdrTextObj * >
+ (ImpGetObjByName(pPage, aNextLinkName));
+ if (!pNextTextObj) {
+ SAL_INFO("svx.chaining", "[CHAINING] Can't find object as next link.");
+ return;
+ }
+
+ pTextObj->SetNextLinkInChain(pNextTextObj);
+}
+
+bool SdrTextObj::IsChainable() const
+{
+ // Read it as item
+ const SfxItemSet& rSet = GetObjectItemSet();
+ OUString aNextLinkName = rSet.Get(SDRATTR_TEXT_CHAINNEXTNAME).GetValue();
+
+ // Update links if any inconsistency is found
+ bool bNextLinkUnsetYet = !aNextLinkName.isEmpty() && !mpNextInChain;
+ bool bInconsistentNextLink = mpNextInChain && mpNextInChain->GetName() != aNextLinkName;
+ // if the link is not set despite there should be one OR if it has changed
+ if (bNextLinkUnsetYet || bInconsistentNextLink) {
+ ImpUpdateChainLinks(const_cast<SdrTextObj *>(this), aNextLinkName);
+ }
+
+ return !aNextLinkName.isEmpty(); // XXX: Should we also check for GetNilChainingEvent? (see old code below)
+
+/*
+ // Check that no overflow is going on
+ if (!GetTextChain() || GetTextChain()->GetNilChainingEvent(this))
+ return false;
+*/
+}
+
+void SdrTextObj::onChainingEvent()
+{
+ if (!mpEditingOutliner)
+ return;
+
+ // Outliner for text transfer
+ SdrOutliner &aDrawOutliner = ImpGetDrawOutliner();
+
+ EditingTextChainFlow aTxtChainFlow(this);
+ aTxtChainFlow.CheckForFlowEvents(mpEditingOutliner);
+
+ if (aTxtChainFlow.IsOverflow()) {
+ SAL_INFO("svx.chaining", "[CHAINING] Overflow going on");
+ // One outliner is for non-overflowing text, the other for overflowing text
+ // We remove text directly from the editing outliner
+ aTxtChainFlow.ExecuteOverflow(mpEditingOutliner, &aDrawOutliner);
+ } else if (aTxtChainFlow.IsUnderflow()) {
+ SAL_INFO("svx.chaining", "[CHAINING] Underflow going on");
+ // underflow-induced overflow
+ aTxtChainFlow.ExecuteUnderflow(&aDrawOutliner);
+ bool bIsOverflowFromUnderflow = aTxtChainFlow.IsOverflow();
+ // handle overflow
+ if (bIsOverflowFromUnderflow) {
+ SAL_INFO("svx.chaining", "[CHAINING] Overflow going on (underflow induced)");
+ // prevents infinite loops when setting text for editing outliner
+ aTxtChainFlow.ExecuteOverflow(&aDrawOutliner, &aDrawOutliner);
+ }
+ }
+}
+
+SdrTextObj* SdrTextObj::GetNextLinkInChain() const
+{
+ /*
+ if (GetTextChain())
+ return GetTextChain()->GetNextLink(this);
+
+ return NULL;
+ */
+
+ return mpNextInChain;
+}
+
+void SdrTextObj::SetNextLinkInChain(SdrTextObj *pNextObj)
+{
+ // Basically a doubly linked list implementation
+
+ SdrTextObj *pOldNextObj = mpNextInChain;
+
+ // Replace next link
+ mpNextInChain = pNextObj;
+ // Deal with old next link's prev link
+ if (pOldNextObj) {
+ pOldNextObj->mpPrevInChain = nullptr;
+ }
+
+ // Deal with new next link's prev link
+ if (mpNextInChain) {
+ // If there is a prev already at all and this is not already the current object
+ if (mpNextInChain->mpPrevInChain &&
+ mpNextInChain->mpPrevInChain != this)
+ mpNextInChain->mpPrevInChain->mpNextInChain = nullptr;
+ mpNextInChain->mpPrevInChain = this;
+ }
+
+ // TODO: Introduce check for circular chains
+
+}
+
+SdrTextObj* SdrTextObj::GetPrevLinkInChain() const
+{
+ /*
+ if (GetTextChain())
+ return GetTextChain()->GetPrevLink(this);
+
+ return NULL;
+ */
+
+ return mpPrevInChain;
+}
+
+bool SdrTextObj::GetPreventChainable() const
+{
+ // Prevent chaining it 1) during dragging && 2) when we are editing next link
+ return mbIsUnchainableClone || (GetNextLinkInChain() && GetNextLinkInChain()->IsInEditMode());
+}
+
+SdrObjectUniquePtr SdrTextObj::getFullDragClone() const
+{
+ SdrObjectUniquePtr pClone = SdrAttrObj::getFullDragClone();
+ SdrTextObj *pTextObjClone = dynamic_cast<SdrTextObj *>(pClone.get());
+ if (pTextObjClone != nullptr) {
+ // Avoid transferring of text for chainable object during dragging
+ pTextObjClone->mbIsUnchainableClone = true;
+ }
+
+ return pClone;
+ }
+
+/* End chaining code */
+
+/** returns the currently active text. */
+SdrText* SdrTextObj::getActiveText() const
+{
+ if( !mpText )
+ return getText( 0 );
+ else
+ return mpText.get();
+}
+
+/** returns the nth available text. */
+SdrText* SdrTextObj::getText( sal_Int32 nIndex ) const
+{
+ if( nIndex == 0 )
+ {
+ if( !mpText )
+ const_cast< SdrTextObj* >(this)->mpText.reset( new SdrText( *const_cast< SdrTextObj* >(this) ) );
+ return mpText.get();
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+/** returns the number of texts available for this object. */
+sal_Int32 SdrTextObj::getTextCount() const
+{
+ return 1;
+}
+
+/** changes the current active text */
+void SdrTextObj::setActiveText( sal_Int32 /*nIndex*/ )
+{
+}
+
+/** returns the index of the text that contains the given point or -1 */
+sal_Int32 SdrTextObj::CheckTextHit(const Point& /*rPnt*/) const
+{
+ return 0;
+}
+
+void SdrTextObj::SetObjectItemNoBroadcast(const SfxPoolItem& rItem)
+{
+ static_cast< sdr::properties::TextProperties& >(GetProperties()).SetObjectItemNoBroadcast(rItem);
+}
+
+
+// The concept of the text object:
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+// Attributes/Variations:
+// - bool text frame / graphics object with caption
+// - bool FontWork (if it is not a text frame and not a ContourTextFrame)
+// - bool ContourTextFrame (if it is not a text frame and not Fontwork)
+// - long rotation angle (if it is not FontWork)
+// - long text frame margins (if it is not FontWork)
+// - bool FitToSize (if it is not FontWork)
+// - bool AutoGrowingWidth/Height (if it is not FitToSize and not FontWork)
+// - long Min/MaxFrameWidth/Height (if AutoGrowingWidth/Height)
+// - enum horizontal text anchoring left,center,right,justify/block,Stretch(ni)
+// - enum vertical text anchoring top, middle, bottom, block, stretch(ni)
+// - enum ticker text (if it is not FontWork)
+
+// Every derived object is either a text frame (mbTextFrame=true)
+// or a drawing object with a caption (mbTextFrame=false).
+
+// Default anchoring for text frames:
+// SDRTEXTHORZADJUST_BLOCK, SDRTEXTVERTADJUST_TOP
+// = static Pool defaults
+// Default anchoring for drawing objects with a caption:
+// SDRTEXTHORZADJUST_CENTER, SDRTEXTVERTADJUST_CENTER
+// via "hard" attribution of SdrAttrObj
+
+// Every object derived from SdrTextObj must return an "UnrotatedSnapRect"
+// (->TakeUnrotatedSnapRect()) (the reference point for the rotation is the top
+// left of the rectangle (maGeo.nRotationAngle)) which is the basis for anchoring
+// text. We then subtract the text frame margins from this rectangle, as a re-
+// sult we get the anchoring area (->TakeTextAnchorRect()). Within this area, we
+// calculate the anchoring point and the painting area, depending on the hori-
+// zontal and vertical adjustment of the text (SdrTextVertAdjust,
+// SdrTextHorzAdjust).
+// In the case of drawing objects with a caption the painting area might well
+// be larger than the anchoring area, for text frames on the other hand, it is
+// always of the same or a smaller size (except when there are negative text
+// frame margins).
+
+// FitToSize takes priority over text anchoring and AutoGrowHeight/Width. When
+// FitToSize is turned on, the painting area is always equal to the anchoring
+// area. Additionally, FitToSize doesn't allow automatic line breaks.
+
+// ContourTextFrame:
+// - long rotation angle
+// - long text frame margins (maybe later)
+// - bool FitToSize (maybe later)
+// - bool AutoGrowingWidth/Height (maybe much later)
+// - long Min/MaxFrameWidth/Height (maybe much later)
+// - enum horizontal text anchoring (maybe later, for now: left, centered)
+// - enum vertical text anchoring (maybe later, for now: top)
+// - enum ticker text (maybe later, maybe even with correct clipping)
+
+// When making changes, check these:
+// - Paint
+// - HitTest
+// - ConvertToPoly
+// - Edit
+// - Printing, Saving, Painting in neighboring View while editing
+// - ModelChanged (e. g. through a neighboring View or rulers) while editing
+// - FillColorChanged while editing
+// - and many more...
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx
new file mode 100644
index 000000000..522375b1f
--- /dev/null
+++ b/svx/source/svdraw/svdotextdecomposition.cxx
@@ -0,0 +1,1698 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdetc.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/sdasitm.hxx>
+#include <textchain.hxx>
+#include <textchainflow.hxx>
+#include <svx/sdtacitm.hxx>
+#include <svx/sdtayitm.hxx>
+#include <svx/sdtaiitm.hxx>
+#include <svx/sdtaaitm.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xbtmpit.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editstat.hxx>
+#include <tools/helpers.hxx>
+#include <svl/itemset.hxx>
+#include <drawinglayer/animation/animationtiming.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <vcl/svapp.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/svxenum.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
+#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
+#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <svx/unoapi.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <editeng/outlobj.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+using namespace com::sun::star;
+
+// helpers
+
+namespace
+{
+ class impTextBreakupHandler
+ {
+ private:
+ drawinglayer::primitive2d::Primitive2DContainer maTextPortionPrimitives;
+ drawinglayer::primitive2d::Primitive2DContainer maLinePrimitives;
+ drawinglayer::primitive2d::Primitive2DContainer maParagraphPrimitives;
+
+ SdrOutliner& mrOutliner;
+ basegfx::B2DHomMatrix maNewTransformA;
+ basegfx::B2DHomMatrix maNewTransformB;
+
+ // the visible area for contour text decomposition
+ basegfx::B2DVector maScale;
+
+ // ClipRange for BlockText decomposition; only text portions completely
+ // inside are to be accepted, so this is different from geometric clipping
+ // (which would allow e.g. upper parts of portions to remain). Only used for
+ // BlockText (see there)
+ basegfx::B2DRange maClipRange;
+
+ DECL_LINK(decomposeContourTextPrimitive, DrawPortionInfo*, void);
+ DECL_LINK(decomposeBlockTextPrimitive, DrawPortionInfo*, void);
+ DECL_LINK(decomposeStretchTextPrimitive, DrawPortionInfo*, void);
+
+ DECL_LINK(decomposeContourBulletPrimitive, DrawBulletInfo*, void);
+ DECL_LINK(decomposeBlockBulletPrimitive, DrawBulletInfo*, void);
+ DECL_LINK(decomposeStretchBulletPrimitive, DrawBulletInfo*, void);
+
+ void impCreateTextPortionPrimitive(const DrawPortionInfo& rInfo);
+ static rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D* pPrimitive, const DrawPortionInfo& rInfo);
+ void impFlushTextPortionPrimitivesToLinePrimitives();
+ void impFlushLinePrimitivesToParagraphPrimitives(sal_Int32 nPara);
+ void impHandleDrawPortionInfo(const DrawPortionInfo& rInfo);
+ void impHandleDrawBulletInfo(const DrawBulletInfo& rInfo);
+
+ public:
+ explicit impTextBreakupHandler(SdrOutliner& rOutliner)
+ : mrOutliner(rOutliner)
+ {
+ }
+
+ void decomposeContourTextPrimitive(const basegfx::B2DHomMatrix& rNewTransformA, const basegfx::B2DHomMatrix& rNewTransformB, const basegfx::B2DVector& rScale)
+ {
+ maScale = rScale;
+ maNewTransformA = rNewTransformA;
+ maNewTransformB = rNewTransformB;
+ mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeContourTextPrimitive));
+ mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeContourBulletPrimitive));
+ mrOutliner.StripPortions();
+ mrOutliner.SetDrawPortionHdl(Link<DrawPortionInfo*,void>());
+ mrOutliner.SetDrawBulletHdl(Link<DrawBulletInfo*,void>());
+ }
+
+ void decomposeBlockTextPrimitive(
+ const basegfx::B2DHomMatrix& rNewTransformA,
+ const basegfx::B2DHomMatrix& rNewTransformB,
+ const basegfx::B2DRange& rClipRange)
+ {
+ maNewTransformA = rNewTransformA;
+ maNewTransformB = rNewTransformB;
+ maClipRange = rClipRange;
+ mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeBlockTextPrimitive));
+ mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeBlockBulletPrimitive));
+ mrOutliner.StripPortions();
+ mrOutliner.SetDrawPortionHdl(Link<DrawPortionInfo*,void>());
+ mrOutliner.SetDrawBulletHdl(Link<DrawBulletInfo*,void>());
+ }
+
+ void decomposeStretchTextPrimitive(const basegfx::B2DHomMatrix& rNewTransformA, const basegfx::B2DHomMatrix& rNewTransformB)
+ {
+ maNewTransformA = rNewTransformA;
+ maNewTransformB = rNewTransformB;
+ mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decomposeStretchTextPrimitive));
+ mrOutliner.SetDrawBulletHdl(LINK(this, impTextBreakupHandler, decomposeStretchBulletPrimitive));
+ mrOutliner.StripPortions();
+ mrOutliner.SetDrawPortionHdl(Link<DrawPortionInfo*,void>());
+ mrOutliner.SetDrawBulletHdl(Link<DrawBulletInfo*,void>());
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer extractPrimitive2DSequence();
+ };
+
+ void impTextBreakupHandler::impCreateTextPortionPrimitive(const DrawPortionInfo& rInfo)
+ {
+ if(rInfo.maText.isEmpty() || !rInfo.mnTextLen)
+ return;
+
+ OUString caseMappedText = rInfo.mrFont.CalcCaseMap( rInfo.maText );
+ basegfx::B2DVector aFontScaling;
+ drawinglayer::attribute::FontAttribute aFontAttribute(
+ drawinglayer::primitive2d::getFontAttributeFromVclFont(
+ aFontScaling,
+ rInfo.mrFont,
+ rInfo.IsRTL(),
+ false));
+ basegfx::B2DHomMatrix aNewTransform;
+
+ // add font scale to new transform
+ aNewTransform.scale(aFontScaling.getX(), aFontScaling.getY());
+
+ // look for proportional font scaling, if necessary, scale accordingly
+ sal_Int8 nPropr(rInfo.mrFont.GetPropr());
+ if(100 != nPropr)
+ {
+ const double fFactor(rInfo.mrFont.GetPropr() / 100.0);
+ aNewTransform.scale(fFactor, fFactor);
+ }
+
+ // apply font rotate
+ if(rInfo.mrFont.GetOrientation())
+ {
+ aNewTransform.rotate(-toRadians(rInfo.mrFont.GetOrientation()));
+ }
+
+ // look for escapement, if necessary, translate accordingly
+ if(rInfo.mrFont.GetEscapement())
+ {
+ sal_Int16 nEsc(rInfo.mrFont.GetEscapement());
+
+ if(DFLT_ESC_AUTO_SUPER == nEsc)
+ {
+ nEsc = .8 * (100 - nPropr);
+ assert (nEsc == DFLT_ESC_SUPER && "I'm sure this formula needs to be changed, but how to confirm that???");
+ nEsc = DFLT_ESC_SUPER;
+ }
+ else if(DFLT_ESC_AUTO_SUB == nEsc)
+ {
+ nEsc = .2 * -(100 - nPropr);
+ assert (nEsc == -20 && "I'm sure this formula needs to be changed, but how to confirm that???");
+ nEsc = -20;
+ }
+
+ if(nEsc > MAX_ESC_POS)
+ {
+ nEsc = MAX_ESC_POS;
+ }
+ else if(nEsc < -MAX_ESC_POS)
+ {
+ nEsc = -MAX_ESC_POS;
+ }
+
+ const double fEscapement(nEsc / -100.0);
+ aNewTransform.translate(0.0, fEscapement * aFontScaling.getY());
+ }
+
+ // apply transformA
+ aNewTransform *= maNewTransformA;
+
+ // apply local offset
+ aNewTransform.translate(rInfo.mrStartPos.X(), rInfo.mrStartPos.Y());
+
+ // also apply embedding object's transform
+ aNewTransform *= maNewTransformB;
+
+ // prepare DXArray content. To make it independent from font size (and such from
+ // the text transformation), scale it to unit coordinates
+ ::std::vector< double > aDXArray;
+
+ if(!rInfo.mpDXArray.empty() && rInfo.mnTextLen)
+ {
+ aDXArray.reserve(rInfo.mnTextLen);
+
+ for(sal_Int32 a=0; a < rInfo.mnTextLen; a++)
+ {
+ aDXArray.push_back(static_cast<double>(rInfo.mpDXArray[a]));
+ }
+ }
+
+ // create complex text primitive and append
+ const Color aFontColor(rInfo.mrFont.GetColor());
+ const basegfx::BColor aBFontColor(aFontColor.getBColor());
+
+ const Color aTextFillColor(rInfo.mrFont.GetFillColor());
+
+ // prepare wordLineMode (for underline and strikeout)
+ // NOT for bullet texts. It is set (this may be an error by itself), but needs to be suppressed to hinder e.g. '1)'
+ // to be split which would not look like the original
+ const bool bWordLineMode(rInfo.mrFont.IsWordLineMode() && !rInfo.mbEndOfBullet);
+
+ // prepare new primitive
+ rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> pNewPrimitive;
+ const bool bDecoratedIsNeeded(
+ LINESTYLE_NONE != rInfo.mrFont.GetOverline()
+ || LINESTYLE_NONE != rInfo.mrFont.GetUnderline()
+ || STRIKEOUT_NONE != rInfo.mrFont.GetStrikeout()
+ || FontEmphasisMark::NONE != (rInfo.mrFont.GetEmphasisMark() & FontEmphasisMark::Style)
+ || FontRelief::NONE != rInfo.mrFont.GetRelief()
+ || rInfo.mrFont.IsShadow()
+ || bWordLineMode);
+
+ if(bDecoratedIsNeeded)
+ {
+ // TextDecoratedPortionPrimitive2D needed, prepare some more data
+ // get overline and underline color. If it's on automatic (0xffffffff) use FontColor instead
+ const Color aUnderlineColor(rInfo.maTextLineColor);
+ const basegfx::BColor aBUnderlineColor((aUnderlineColor == COL_AUTO) ? aBFontColor : aUnderlineColor.getBColor());
+ const Color aOverlineColor(rInfo.maOverlineColor);
+ const basegfx::BColor aBOverlineColor((aOverlineColor == COL_AUTO) ? aBFontColor : aOverlineColor.getBColor());
+
+ // prepare overline and underline data
+ const drawinglayer::primitive2d::TextLine eFontOverline(
+ drawinglayer::primitive2d::mapFontLineStyleToTextLine(rInfo.mrFont.GetOverline()));
+ const drawinglayer::primitive2d::TextLine eFontLineStyle(
+ drawinglayer::primitive2d::mapFontLineStyleToTextLine(rInfo.mrFont.GetUnderline()));
+
+ // check UnderlineAbove
+ const bool bUnderlineAbove(
+ drawinglayer::primitive2d::TEXT_LINE_NONE != eFontLineStyle && rInfo.mrFont.IsUnderlineAbove());
+
+ // prepare strikeout data
+ const drawinglayer::primitive2d::TextStrikeout eTextStrikeout(
+ drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rInfo.mrFont.GetStrikeout()));
+
+ // prepare emphasis mark data
+ drawinglayer::primitive2d::TextEmphasisMark eTextEmphasisMark(drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_NONE);
+
+ switch(rInfo.mrFont.GetEmphasisMark() & FontEmphasisMark::Style)
+ {
+ case FontEmphasisMark::Dot : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_DOT; break;
+ case FontEmphasisMark::Circle : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_CIRCLE; break;
+ case FontEmphasisMark::Disc : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_DISC; break;
+ case FontEmphasisMark::Accent : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_ACCENT; break;
+ default: break;
+ }
+
+ const bool bEmphasisMarkAbove(rInfo.mrFont.GetEmphasisMark() & FontEmphasisMark::PosAbove);
+ const bool bEmphasisMarkBelow(rInfo.mrFont.GetEmphasisMark() & FontEmphasisMark::PosBelow);
+
+ // prepare font relief data
+ drawinglayer::primitive2d::TextRelief eTextRelief(drawinglayer::primitive2d::TEXT_RELIEF_NONE);
+
+ switch(rInfo.mrFont.GetRelief())
+ {
+ case FontRelief::Embossed : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED; break;
+ case FontRelief::Engraved : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED; break;
+ default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE
+ }
+
+ // prepare shadow/outline data
+ const bool bShadow(rInfo.mrFont.IsShadow());
+
+ // TextDecoratedPortionPrimitive2D is needed, create one
+ pNewPrimitive = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
+
+ // attributes for TextSimplePortionPrimitive2D
+ aNewTransform,
+ caseMappedText,
+ rInfo.mnTextStart,
+ rInfo.mnTextLen,
+ std::vector(aDXArray),
+ aFontAttribute,
+ rInfo.mpLocale ? *rInfo.mpLocale : css::lang::Locale(),
+ aBFontColor,
+ aTextFillColor,
+
+ // attributes for TextDecoratedPortionPrimitive2D
+ aBOverlineColor,
+ aBUnderlineColor,
+ eFontOverline,
+ eFontLineStyle,
+ bUnderlineAbove,
+ eTextStrikeout,
+ bWordLineMode,
+ eTextEmphasisMark,
+ bEmphasisMarkAbove,
+ bEmphasisMarkBelow,
+ eTextRelief,
+ bShadow);
+ }
+ else
+ {
+ // TextSimplePortionPrimitive2D is enough
+ pNewPrimitive = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aNewTransform,
+ caseMappedText,
+ rInfo.mnTextStart,
+ rInfo.mnTextLen,
+ std::vector(aDXArray),
+ aFontAttribute,
+ rInfo.mpLocale ? *rInfo.mpLocale : css::lang::Locale(),
+ aBFontColor,
+ rInfo.mbFilled,
+ rInfo.mnWidthToFill,
+ aTextFillColor);
+ }
+
+ if (aFontColor.IsTransparent())
+ {
+ // Handle semi-transparent text for both the decorated and simple case here.
+ pNewPrimitive = new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ drawinglayer::primitive2d::Primitive2DContainer{ pNewPrimitive },
+ (255 - aFontColor.GetAlpha()) / 255.0);
+ }
+
+ if(rInfo.mbEndOfBullet)
+ {
+ // embed in TextHierarchyBulletPrimitive2D
+ drawinglayer::primitive2d::Primitive2DReference aNewReference(pNewPrimitive);
+ drawinglayer::primitive2d::Primitive2DContainer aNewSequence { aNewReference } ;
+ pNewPrimitive = new drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(std::move(aNewSequence));
+ }
+
+ if(rInfo.mpFieldData)
+ {
+ pNewPrimitive = impCheckFieldPrimitive(pNewPrimitive.get(), rInfo);
+ }
+
+ maTextPortionPrimitives.push_back(pNewPrimitive);
+
+ // support for WrongSpellVector. Create WrongSpellPrimitives as needed
+ if(!rInfo.mpWrongSpellVector || aDXArray.empty())
+ return;
+
+ const sal_Int32 nSize(rInfo.mpWrongSpellVector->size());
+ const sal_Int32 nDXCount(aDXArray.size());
+ const basegfx::BColor aSpellColor(1.0, 0.0, 0.0); // red, hard coded
+
+ for(sal_Int32 a(0); a < nSize; a++)
+ {
+ const EEngineData::WrongSpellClass& rCandidate = (*rInfo.mpWrongSpellVector)[a];
+
+ if(rCandidate.nStart >= rInfo.mnTextStart && rCandidate.nEnd >= rInfo.mnTextStart && rCandidate.nEnd > rCandidate.nStart)
+ {
+ const sal_Int32 nStart(rCandidate.nStart - rInfo.mnTextStart);
+ const sal_Int32 nEnd(rCandidate.nEnd - rInfo.mnTextStart);
+ double fStart(0.0);
+ double fEnd(0.0);
+
+ if(nStart > 0 && nStart - 1 < nDXCount)
+ {
+ fStart = aDXArray[nStart - 1];
+ }
+
+ if(nEnd > 0 && nEnd - 1 < nDXCount)
+ {
+ fEnd = aDXArray[nEnd - 1];
+ }
+
+ if(!basegfx::fTools::equal(fStart, fEnd))
+ {
+ if(rInfo.IsRTL())
+ {
+ // #i98523#
+ // When the portion is RTL, mirror the redlining using the
+ // full portion width
+ const double fTextWidth(aDXArray[aDXArray.size() - 1]);
+
+ fStart = fTextWidth - fStart;
+ fEnd = fTextWidth - fEnd;
+ }
+
+ // need to take FontScaling out of values; it's already part of
+ // aNewTransform and would be double applied
+ const double fFontScaleX(aFontScaling.getX());
+
+ if(!basegfx::fTools::equal(fFontScaleX, 1.0)
+ && !basegfx::fTools::equalZero(fFontScaleX))
+ {
+ fStart /= fFontScaleX;
+ fEnd /= fFontScaleX;
+ }
+
+ maTextPortionPrimitives.push_back(new drawinglayer::primitive2d::WrongSpellPrimitive2D(
+ aNewTransform,
+ fStart,
+ fEnd,
+ aSpellColor));
+ }
+ }
+ }
+ }
+
+ rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> impTextBreakupHandler::impCheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D* pPrimitive, const DrawPortionInfo& rInfo)
+ {
+ rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> xRet = pPrimitive;
+ if(rInfo.mpFieldData)
+ {
+ // Support for FIELD_SEQ_BEGIN, FIELD_SEQ_END. If used, create a TextHierarchyFieldPrimitive2D
+ // which holds the field type and, if applicable, the URL
+ const SvxURLField* pURLField = dynamic_cast< const SvxURLField* >(rInfo.mpFieldData);
+ const SvxPageField* pPageField = dynamic_cast< const SvxPageField* >(rInfo.mpFieldData);
+
+ // embed current primitive to a sequence
+ drawinglayer::primitive2d::Primitive2DContainer aSequence;
+
+ if(pPrimitive)
+ {
+ aSequence.resize(1);
+ aSequence[0] = drawinglayer::primitive2d::Primitive2DReference(pPrimitive);
+ }
+
+ if(pURLField)
+ {
+ // extended this to hold more of the contents of the original
+ // SvxURLField since that stuff is still used in HitTest and e.g. Calc
+ std::vector< std::pair< OUString, OUString>> meValues;
+ meValues.emplace_back("URL", pURLField->GetURL());
+ meValues.emplace_back("Representation", pURLField->GetRepresentation());
+ meValues.emplace_back("TargetFrame", pURLField->GetTargetFrame());
+ meValues.emplace_back("SvxURLFormat", OUString::number(static_cast<sal_uInt16>(pURLField->GetFormat())));
+ xRet = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(std::move(aSequence), drawinglayer::primitive2d::FIELD_TYPE_URL, &meValues);
+ }
+ else if(pPageField)
+ {
+ xRet = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(std::move(aSequence), drawinglayer::primitive2d::FIELD_TYPE_PAGE);
+ }
+ else
+ {
+ xRet = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(std::move(aSequence), drawinglayer::primitive2d::FIELD_TYPE_COMMON);
+ }
+ }
+
+ return xRet;
+ }
+
+ void impTextBreakupHandler::impFlushTextPortionPrimitivesToLinePrimitives()
+ {
+ // only create a line primitive when we had content; there is no need for
+ // empty line primitives (contrary to paragraphs, see below).
+ if(!maTextPortionPrimitives.empty())
+ {
+ maLinePrimitives.push_back(new drawinglayer::primitive2d::TextHierarchyLinePrimitive2D(std::move(maTextPortionPrimitives)));
+ }
+ }
+
+ void impTextBreakupHandler::impFlushLinePrimitivesToParagraphPrimitives(sal_Int32 nPara)
+ {
+ sal_Int16 nDepth = mrOutliner.GetDepth(nPara);
+ EBulletInfo eInfo = mrOutliner.GetBulletInfo(nPara);
+ // Pass -1 to signal VclMetafileProcessor2D that there is no active
+ // bullets/numbering in this paragraph (i.e. this is normal text)
+ const sal_Int16 nOutlineLevel( eInfo.bVisible ? nDepth : -1);
+
+ // ALWAYS create a paragraph primitive, even when no content was added. This is done to
+ // have the correct paragraph count even with empty paragraphs. Those paragraphs will
+ // have an empty sub-PrimitiveSequence.
+ maParagraphPrimitives.push_back(
+ new drawinglayer::primitive2d::TextHierarchyParagraphPrimitive2D(
+ std::move(maLinePrimitives),
+ nOutlineLevel));
+ }
+
+ void impTextBreakupHandler::impHandleDrawPortionInfo(const DrawPortionInfo& rInfo)
+ {
+ impCreateTextPortionPrimitive(rInfo);
+
+ if(rInfo.mbEndOfLine || rInfo.mbEndOfParagraph)
+ {
+ impFlushTextPortionPrimitivesToLinePrimitives();
+ }
+
+ if(rInfo.mbEndOfParagraph)
+ {
+ impFlushLinePrimitivesToParagraphPrimitives(rInfo.mnPara);
+ }
+ }
+
+ void impTextBreakupHandler::impHandleDrawBulletInfo(const DrawBulletInfo& rInfo)
+ {
+ basegfx::B2DHomMatrix aNewTransform;
+
+ // add size to new transform
+ aNewTransform.scale(rInfo.maBulletSize.getWidth(), rInfo.maBulletSize.getHeight());
+
+ // apply transformA
+ aNewTransform *= maNewTransformA;
+
+ // apply local offset
+ aNewTransform.translate(rInfo.maBulletPosition.X(), rInfo.maBulletPosition.Y());
+
+ // also apply embedding object's transform
+ aNewTransform *= maNewTransformB;
+
+ // prepare empty GraphicAttr
+ const GraphicAttr aGraphicAttr;
+
+ // create GraphicPrimitive2D
+ const drawinglayer::primitive2d::Primitive2DReference aNewReference(new drawinglayer::primitive2d::GraphicPrimitive2D(
+ aNewTransform,
+ rInfo.maBulletGraphicObject,
+ aGraphicAttr));
+
+ // embed in TextHierarchyBulletPrimitive2D
+ drawinglayer::primitive2d::Primitive2DContainer aNewSequence { aNewReference };
+ rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> pNewPrimitive = new drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(std::move(aNewSequence));
+
+ // add to output
+ maTextPortionPrimitives.push_back(pNewPrimitive);
+ }
+
+ IMPL_LINK(impTextBreakupHandler, decomposeContourTextPrimitive, DrawPortionInfo*, pInfo, void)
+ {
+ // for contour text, ignore (clip away) all portions which are below
+ // the visible area given by maScale
+ if(pInfo && static_cast<double>(pInfo->mrStartPos.Y()) < maScale.getY())
+ {
+ impHandleDrawPortionInfo(*pInfo);
+ }
+ }
+
+ IMPL_LINK(impTextBreakupHandler, decomposeBlockTextPrimitive, DrawPortionInfo*, pInfo, void)
+ {
+ if(!pInfo)
+ return;
+
+ // Is clipping wanted? This is text clipping; only accept a portion
+ // if it's completely in the range
+ if(!maClipRange.isEmpty())
+ {
+ // Test start position first; this allows to not get the text range at
+ // all if text is far outside
+ const basegfx::B2DPoint aStartPosition(pInfo->mrStartPos.X(), pInfo->mrStartPos.Y());
+
+ if(!maClipRange.isInside(aStartPosition))
+ {
+ return;
+ }
+
+ // Start position is inside. Get TextBoundRect and TopLeft next
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
+ aTextLayouterDevice.setFont(pInfo->mrFont);
+
+ const basegfx::B2DRange aTextBoundRect(
+ aTextLayouterDevice.getTextBoundRect(
+ pInfo->maText, pInfo->mnTextStart, pInfo->mnTextLen));
+ const basegfx::B2DPoint aTopLeft(aTextBoundRect.getMinimum() + aStartPosition);
+
+ if(!maClipRange.isInside(aTopLeft))
+ {
+ return;
+ }
+
+ // TopLeft is inside. Get BottomRight and check
+ const basegfx::B2DPoint aBottomRight(aTextBoundRect.getMaximum() + aStartPosition);
+
+ if(!maClipRange.isInside(aBottomRight))
+ {
+ return;
+ }
+
+ // all inside, clip was successful
+ }
+ impHandleDrawPortionInfo(*pInfo);
+ }
+
+ IMPL_LINK(impTextBreakupHandler, decomposeStretchTextPrimitive, DrawPortionInfo*, pInfo, void)
+ {
+ if(pInfo)
+ {
+ impHandleDrawPortionInfo(*pInfo);
+ }
+ }
+
+ IMPL_LINK(impTextBreakupHandler, decomposeContourBulletPrimitive, DrawBulletInfo*, pInfo, void)
+ {
+ if(pInfo)
+ {
+ impHandleDrawBulletInfo(*pInfo);
+ }
+ }
+
+ IMPL_LINK(impTextBreakupHandler, decomposeBlockBulletPrimitive, DrawBulletInfo*, pInfo, void)
+ {
+ if(pInfo)
+ {
+ impHandleDrawBulletInfo(*pInfo);
+ }
+ }
+
+ IMPL_LINK(impTextBreakupHandler, decomposeStretchBulletPrimitive, DrawBulletInfo*, pInfo, void)
+ {
+ if(pInfo)
+ {
+ impHandleDrawBulletInfo(*pInfo);
+ }
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer impTextBreakupHandler::extractPrimitive2DSequence()
+ {
+ if(!maTextPortionPrimitives.empty())
+ {
+ // collect non-closed lines
+ impFlushTextPortionPrimitivesToLinePrimitives();
+ }
+
+ if(!maLinePrimitives.empty())
+ {
+ // collect non-closed paragraphs
+ impFlushLinePrimitivesToParagraphPrimitives(mrOutliner.GetParagraphCount() - 1);
+ }
+
+ return std::move(maParagraphPrimitives);
+ }
+} // end of anonymous namespace
+
+
+// primitive decompositions
+
+void SdrTextObj::impDecomposeContourTextPrimitive(
+ drawinglayer::primitive2d::Primitive2DContainer& rTarget,
+ const drawinglayer::primitive2d::SdrContourTextPrimitive2D& rSdrContourTextPrimitive,
+ const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
+{
+ // decompose matrix to have position and size of text
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rSdrContourTextPrimitive.getObjectTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // prepare contour polygon, force to non-mirrored for laying out
+ basegfx::B2DPolyPolygon aPolyPolygon(rSdrContourTextPrimitive.getUnitPolyPolygon());
+ aPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(fabs(aScale.getX()), fabs(aScale.getY())));
+
+ // prepare outliner
+ SolarMutexGuard aSolarGuard;
+ SdrOutliner& rOutliner = ImpGetDrawOutliner();
+ const Size aNullSize;
+ rOutliner.SetPaperSize(aNullSize);
+ rOutliner.SetPolygon(aPolyPolygon);
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetText(rSdrContourTextPrimitive.getOutlinerParaObject());
+
+ // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
+ rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
+
+ // prepare matrices to apply to newly created primitives
+ basegfx::B2DHomMatrix aNewTransformA;
+
+ // mirroring. We are now in the polygon sizes. When mirroring in X and Y,
+ // move the null point which was top left to bottom right.
+ const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
+ const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
+
+ // in-between the translations of the single primitives will take place. Afterwards,
+ // the object's transformations need to be applied
+ const basegfx::B2DHomMatrix aNewTransformB(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
+ fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
+
+ // now break up text primitives.
+ impTextBreakupHandler aConverter(rOutliner);
+ aConverter.decomposeContourTextPrimitive(aNewTransformA, aNewTransformB, aScale);
+
+ // cleanup outliner
+ rOutliner.Clear();
+ rOutliner.setVisualizedPage(nullptr);
+
+ rTarget = aConverter.extractPrimitive2DSequence();
+}
+
+void SdrTextObj::impDecomposeAutoFitTextPrimitive(
+ drawinglayer::primitive2d::Primitive2DContainer& rTarget,
+ const drawinglayer::primitive2d::SdrAutoFitTextPrimitive2D& rSdrAutofitTextPrimitive,
+ const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
+{
+ // decompose matrix to have position and size of text
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rSdrAutofitTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // use B2DRange aAnchorTextRange for calculations
+ basegfx::B2DRange aAnchorTextRange(aTranslate);
+ aAnchorTextRange.expand(aTranslate + aScale);
+
+ // prepare outliner
+ const SfxItemSet& rTextItemSet = rSdrAutofitTextPrimitive.getSdrText()->GetItemSet();
+ SolarMutexGuard aSolarGuard;
+ SdrOutliner& rOutliner = ImpGetDrawOutliner();
+ SdrTextVertAdjust eVAdj = GetTextVerticalAdjust(rTextItemSet);
+ SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust(rTextItemSet);
+ const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
+ const Size aNullSize;
+
+ // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
+ rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
+
+ rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::AUTOPAGESIZE|EEControlBits::STRETCHING);
+ rOutliner.SetMinAutoPaperSize(aNullSize);
+ rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
+
+ // That color needs to be restored on leaving this method
+ Color aOriginalBackColor(rOutliner.GetBackgroundColor());
+ setSuitableOutlinerBg(rOutliner);
+
+ // add one to rage sizes to get back to the old Rectangle and outliner measurements
+ const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1));
+ const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1));
+ const OutlinerParaObject* pOutlinerParaObject = rSdrAutofitTextPrimitive.getSdrText()->GetOutlinerParaObject();
+ OSL_ENSURE(pOutlinerParaObject, "impDecomposeBlockTextPrimitive used with no OutlinerParaObject (!)");
+ const bool bVerticalWriting(pOutlinerParaObject->IsEffectivelyVertical());
+ const bool bTopToBottom(pOutlinerParaObject->IsTopToBottom());
+ const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
+
+ if(rSdrAutofitTextPrimitive.getWordWrap() || IsTextFrame())
+ {
+ rOutliner.SetMaxAutoPaperSize(aAnchorTextSize);
+ }
+
+ if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWriting)
+ {
+ rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
+ rOutliner.SetMinColumnWrapHeight(nAnchorTextHeight);
+ }
+
+ if(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWriting)
+ {
+ rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
+ rOutliner.SetMinColumnWrapHeight(nAnchorTextWidth);
+ }
+
+ rOutliner.SetPaperSize(aNullSize);
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetText(*pOutlinerParaObject);
+ ImpAutoFitText(rOutliner,aAnchorTextSize,bVerticalWriting);
+
+ // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
+ rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
+
+ // now get back the layouted text size from outliner
+ const Size aOutlinerTextSize(rOutliner.GetPaperSize());
+ const basegfx::B2DVector aOutlinerScale(aOutlinerTextSize.Width(), aOutlinerTextSize.Height());
+ basegfx::B2DVector aAdjustTranslate(0.0, 0.0);
+
+ // correct horizontal translation using the now known text size
+ if(SDRTEXTHORZADJUST_CENTER == eHAdj || SDRTEXTHORZADJUST_RIGHT == eHAdj)
+ {
+ const double fFree(aAnchorTextRange.getWidth() - aOutlinerScale.getX());
+
+ if(SDRTEXTHORZADJUST_CENTER == eHAdj)
+ {
+ aAdjustTranslate.setX(fFree / 2.0);
+ }
+
+ if(SDRTEXTHORZADJUST_RIGHT == eHAdj)
+ {
+ aAdjustTranslate.setX(fFree);
+ }
+ }
+
+ // correct vertical translation using the now known text size
+ if(SDRTEXTVERTADJUST_CENTER == eVAdj || SDRTEXTVERTADJUST_BOTTOM == eVAdj)
+ {
+ const double fFree(aAnchorTextRange.getHeight() - aOutlinerScale.getY());
+
+ if(SDRTEXTVERTADJUST_CENTER == eVAdj)
+ {
+ aAdjustTranslate.setY(fFree / 2.0);
+ }
+
+ if(SDRTEXTVERTADJUST_BOTTOM == eVAdj)
+ {
+ aAdjustTranslate.setY(fFree);
+ }
+ }
+
+ // prepare matrices to apply to newly created primitives. aNewTransformA
+ // will get coordinates in aOutlinerScale size and positive in X, Y.
+ basegfx::B2DHomMatrix aNewTransformA;
+ basegfx::B2DHomMatrix aNewTransformB;
+
+ // translate relative to given primitive to get same rotation and shear
+ // as the master shape we are working on. For vertical, use the top-right
+ // corner
+ const double fStartInX(bVerticalWriting && bTopToBottom ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
+ const double fStartInY(bVerticalWriting && !bTopToBottom ? aAdjustTranslate.getY() + aOutlinerScale.getY() : aAdjustTranslate.getY());
+ aNewTransformA.translate(fStartInX, fStartInY);
+
+ // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
+ // move the null point which was top left to bottom right.
+ const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
+ const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
+ aNewTransformB.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
+
+ // in-between the translations of the single primitives will take place. Afterwards,
+ // the object's transformations need to be applied
+ aNewTransformB.shearX(fShearX);
+ aNewTransformB.rotate(fRotate);
+ aNewTransformB.translate(aTranslate.getX(), aTranslate.getY());
+
+ basegfx::B2DRange aClipRange;
+
+ // now break up text primitives.
+ impTextBreakupHandler aConverter(rOutliner);
+ aConverter.decomposeBlockTextPrimitive(aNewTransformA, aNewTransformB, aClipRange);
+
+ // cleanup outliner
+ rOutliner.SetBackgroundColor(aOriginalBackColor);
+ rOutliner.Clear();
+ rOutliner.setVisualizedPage(nullptr);
+ rOutliner.SetControlWord(nOriginalControlWord);
+
+ rTarget = aConverter.extractPrimitive2DSequence();
+}
+
+// Resolves: fdo#35779 set background color of this shape as the editeng background if there
+// is one. Check the shape itself, then the host page, then that page's master page.
+bool SdrObject::setSuitableOutlinerBg(::Outliner& rOutliner) const
+{
+ const SfxItemSet* pBackgroundFillSet = getBackgroundFillSet();
+ if (drawing::FillStyle_NONE != pBackgroundFillSet->Get(XATTR_FILLSTYLE).GetValue())
+ {
+ Color aColor(rOutliner.GetBackgroundColor());
+ GetDraftFillColor(*pBackgroundFillSet, aColor);
+ rOutliner.SetBackgroundColor(aColor);
+ return true;
+ }
+ return false;
+}
+
+const SfxItemSet* SdrObject::getBackgroundFillSet() const
+{
+ const SfxItemSet* pBackgroundFillSet = &GetObjectItemSet();
+
+ if (drawing::FillStyle_NONE == pBackgroundFillSet->Get(XATTR_FILLSTYLE).GetValue())
+ {
+ SdrPage* pOwnerPage(getSdrPageFromSdrObject());
+ if (pOwnerPage)
+ {
+ pBackgroundFillSet = &pOwnerPage->getSdrPageProperties().GetItemSet();
+
+ if (drawing::FillStyle_NONE == pBackgroundFillSet->Get(XATTR_FILLSTYLE).GetValue())
+ {
+ if (!pOwnerPage->IsMasterPage() && pOwnerPage->TRG_HasMasterPage())
+ {
+ pBackgroundFillSet = &pOwnerPage->TRG_GetMasterPage().getSdrPageProperties().GetItemSet();
+ }
+ }
+ }
+ }
+ return pBackgroundFillSet;
+}
+
+const Graphic* SdrObject::getFillGraphic() const
+{
+ if(IsGroupObject()) // Doesn't make sense, and GetObjectItemSet() asserts.
+ return nullptr;
+ const SfxItemSet* pBackgroundFillSet = getBackgroundFillSet();
+ if (drawing::FillStyle_BITMAP != pBackgroundFillSet->Get(XATTR_FILLSTYLE).GetValue())
+ return nullptr;
+ return &pBackgroundFillSet->Get(XATTR_FILLBITMAP).GetGraphicObject().GetGraphic();
+}
+
+void SdrTextObj::impDecomposeBlockTextPrimitive(
+ drawinglayer::primitive2d::Primitive2DContainer& rTarget,
+ const drawinglayer::primitive2d::SdrBlockTextPrimitive2D& rSdrBlockTextPrimitive,
+ const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
+{
+ // decompose matrix to have position and size of text
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rSdrBlockTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // use B2DRange aAnchorTextRange for calculations
+ basegfx::B2DRange aAnchorTextRange(aTranslate);
+ aAnchorTextRange.expand(aTranslate + aScale);
+
+ // prepare outliner
+ const bool bIsCell(rSdrBlockTextPrimitive.getCellText());
+ SolarMutexGuard aSolarGuard;
+ SdrOutliner& rOutliner = ImpGetDrawOutliner();
+ SdrTextHorzAdjust eHAdj = rSdrBlockTextPrimitive.getSdrTextHorzAdjust();
+ SdrTextVertAdjust eVAdj = rSdrBlockTextPrimitive.getSdrTextVertAdjust();
+ const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
+ const Size aNullSize;
+
+ // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
+ rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
+ rOutliner.SetFixedCellHeight(rSdrBlockTextPrimitive.isFixedCellHeight());
+ rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::AUTOPAGESIZE);
+ rOutliner.SetMinAutoPaperSize(aNullSize);
+ rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
+
+ // That color needs to be restored on leaving this method
+ Color aOriginalBackColor(rOutliner.GetBackgroundColor());
+ setSuitableOutlinerBg(rOutliner);
+
+ // add one to rage sizes to get back to the old Rectangle and outliner measurements
+ const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1));
+ const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1));
+ const bool bVerticalWriting(rSdrBlockTextPrimitive.getOutlinerParaObject().IsEffectivelyVertical());
+ const bool bTopToBottom(rSdrBlockTextPrimitive.getOutlinerParaObject().IsTopToBottom());
+ const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
+
+ if(bIsCell)
+ {
+ // cell text is formatted neither like a text object nor like an object
+ // text, so use a special setup here
+ rOutliner.SetMaxAutoPaperSize(aAnchorTextSize);
+
+ // #i106214# To work with an unchangeable PaperSize (CellSize in
+ // this case) Set(Min|Max)AutoPaperSize and SetPaperSize have to be used.
+ // #i106214# This was not completely correct; to still measure the real
+ // text height to allow vertical adjust (and vice versa for VerticalWritintg)
+ // only one aspect has to be set, but the other one to zero
+ if(bVerticalWriting)
+ {
+ // measure the horizontal text size
+ rOutliner.SetMinAutoPaperSize(Size(0, aAnchorTextSize.Height()));
+ }
+ else
+ {
+ // measure the vertical text size
+ rOutliner.SetMinAutoPaperSize(Size(aAnchorTextSize.Width(), 0));
+ }
+
+ rOutliner.SetPaperSize(aAnchorTextSize);
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetText(rSdrBlockTextPrimitive.getOutlinerParaObject());
+ }
+ else
+ {
+ // check if block text is used (only one of them can be true)
+ const bool bHorizontalIsBlock(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWriting);
+ const bool bVerticalIsBlock(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWriting);
+
+ // set minimal paper size horizontally/vertically if needed
+ if(bHorizontalIsBlock)
+ {
+ rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
+ rOutliner.SetMinColumnWrapHeight(nAnchorTextHeight);
+ }
+ else if(bVerticalIsBlock)
+ {
+ rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
+ rOutliner.SetMinColumnWrapHeight(nAnchorTextWidth);
+ }
+
+ if((rSdrBlockTextPrimitive.getWordWrap() || IsTextFrame()) && !rSdrBlockTextPrimitive.getUnlimitedPage())
+ {
+ // #i103454# maximal paper size hor/ver needs to be limited to text
+ // frame size. If it's block text, still allow the 'other' direction
+ // to grow to get a correct real text size when using GetPaperSize().
+ // When just using aAnchorTextSize as maximum, GetPaperSize()
+ // would just return aAnchorTextSize again: this means, the wanted
+ // 'measurement' of the real size of block text would not work
+ Size aMaxAutoPaperSize(aAnchorTextSize);
+
+ // Usual processing - always grow in one of directions
+ bool bAllowGrowVertical = !bVerticalWriting;
+ bool bAllowGrowHorizontal = bVerticalWriting;
+
+ // Compatibility mode for tdf#99729
+ if (getSdrModelFromSdrObject().IsAnchoredTextOverflowLegacy())
+ {
+ bAllowGrowVertical = bHorizontalIsBlock;
+ bAllowGrowHorizontal = bVerticalIsBlock;
+ }
+
+ if (bAllowGrowVertical)
+ {
+ // allow to grow vertical for horizontal texts
+ aMaxAutoPaperSize.setHeight(1000000);
+ }
+ else if (bAllowGrowHorizontal)
+ {
+ // allow to grow horizontal for vertical texts
+ aMaxAutoPaperSize.setWidth(1000000);
+ }
+
+ rOutliner.SetMaxAutoPaperSize(aMaxAutoPaperSize);
+ }
+
+ rOutliner.SetPaperSize(aNullSize);
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetText(rSdrBlockTextPrimitive.getOutlinerParaObject());
+ }
+
+ rOutliner.SetControlWord(nOriginalControlWord);
+
+ // now get back the layouted text size from outliner
+ const Size aOutlinerTextSize(rOutliner.GetPaperSize());
+ const basegfx::B2DVector aOutlinerScale(aOutlinerTextSize.Width(), aOutlinerTextSize.Height());
+ basegfx::B2DVector aAdjustTranslate(0.0, 0.0);
+
+ // For draw objects containing text correct hor/ver alignment if text is bigger
+ // than the object itself. Without that correction, the text would always be
+ // formatted to the left edge (or top edge when vertical) of the draw object.
+ if(!IsTextFrame() && !bIsCell)
+ {
+ if(aAnchorTextRange.getWidth() < aOutlinerScale.getX() && !bVerticalWriting)
+ {
+ // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
+ // else the alignment is wanted.
+ if(SDRTEXTHORZADJUST_BLOCK == eHAdj)
+ {
+ SvxAdjust eAdjust = GetObjectItemSet().Get(EE_PARA_JUST).GetAdjust();
+ switch(eAdjust)
+ {
+ case SvxAdjust::Left: eHAdj = SDRTEXTHORZADJUST_LEFT; break;
+ case SvxAdjust::Right: eHAdj = SDRTEXTHORZADJUST_RIGHT; break;
+ case SvxAdjust::Center: eHAdj = SDRTEXTHORZADJUST_CENTER; break;
+ default: break;
+ }
+ }
+ }
+
+ if(aAnchorTextRange.getHeight() < aOutlinerScale.getY() && bVerticalWriting)
+ {
+ // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
+ // else the alignment is wanted.
+ if(SDRTEXTVERTADJUST_BLOCK == eVAdj)
+ {
+ eVAdj = SDRTEXTVERTADJUST_CENTER;
+ }
+ }
+ }
+
+ // correct horizontal translation using the now known text size
+ if(SDRTEXTHORZADJUST_CENTER == eHAdj || SDRTEXTHORZADJUST_RIGHT == eHAdj)
+ {
+ const double fFree(aAnchorTextRange.getWidth() - aOutlinerScale.getX());
+
+ if(SDRTEXTHORZADJUST_CENTER == eHAdj)
+ {
+ aAdjustTranslate.setX(fFree / 2.0);
+ }
+
+ if(SDRTEXTHORZADJUST_RIGHT == eHAdj)
+ {
+ aAdjustTranslate.setX(fFree);
+ }
+ }
+
+ // correct vertical translation using the now known text size
+ if(SDRTEXTVERTADJUST_CENTER == eVAdj || SDRTEXTVERTADJUST_BOTTOM == eVAdj)
+ {
+ const double fFree(aAnchorTextRange.getHeight() - aOutlinerScale.getY());
+
+ if(SDRTEXTVERTADJUST_CENTER == eVAdj)
+ {
+ aAdjustTranslate.setY(fFree / 2.0);
+ }
+
+ if(SDRTEXTVERTADJUST_BOTTOM == eVAdj)
+ {
+ aAdjustTranslate.setY(fFree);
+ }
+ }
+
+ // prepare matrices to apply to newly created primitives. aNewTransformA
+ // will get coordinates in aOutlinerScale size and positive in X, Y.
+ // Translate relative to given primitive to get same rotation and shear
+ // as the master shape we are working on. For vertical, use the top-right
+ // corner
+ const double fStartInX(bVerticalWriting && bTopToBottom ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
+ const double fStartInY(bVerticalWriting && !bTopToBottom ? aAdjustTranslate.getY() + aOutlinerScale.getY() : aAdjustTranslate.getY());
+ basegfx::B2DHomMatrix aNewTransformA(basegfx::utils::createTranslateB2DHomMatrix(fStartInX, fStartInY));
+
+ // Apply the camera rotation. It have to be applied after adjustment of
+ // the text (top, bottom, center, left, right).
+ if(GetCameraZRotation() != 0)
+ {
+ // First find the text rect.
+ basegfx::B2DRange aTextRectangle(/*x1=*/aTranslate.getX() + aAdjustTranslate.getX(),
+ /*y1=*/aTranslate.getY() + aAdjustTranslate.getY(),
+ /*x2=*/aTranslate.getX() + aOutlinerScale.getX() - aAdjustTranslate.getX(),
+ /*y2=*/aTranslate.getY() + aOutlinerScale.getY() - aAdjustTranslate.getY());
+
+ // Rotate the text from the center point.
+ basegfx::B2DVector aTranslateToCenter(aTextRectangle.getWidth() / 2, aTextRectangle.getHeight() / 2);
+ aNewTransformA.translate(-aTranslateToCenter.getX(), -aTranslateToCenter.getY());
+ aNewTransformA.rotate(basegfx::deg2rad(360.0 - GetCameraZRotation() ));
+ aNewTransformA.translate(aTranslateToCenter.getX(), aTranslateToCenter.getY());
+ }
+
+ // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
+ // move the null point which was top left to bottom right.
+ const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
+ const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
+
+ // in-between the translations of the single primitives will take place. Afterwards,
+ // the object's transformations need to be applied
+ const basegfx::B2DHomMatrix aNewTransformB(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
+ fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
+
+
+ // create ClipRange (if needed)
+ basegfx::B2DRange aClipRange;
+
+ // now break up text primitives.
+ impTextBreakupHandler aConverter(rOutliner);
+ aConverter.decomposeBlockTextPrimitive(aNewTransformA, aNewTransformB, aClipRange);
+
+ // cleanup outliner
+ rOutliner.SetBackgroundColor(aOriginalBackColor);
+ rOutliner.Clear();
+ rOutliner.setVisualizedPage(nullptr);
+
+ rTarget = aConverter.extractPrimitive2DSequence();
+}
+
+void SdrTextObj::impDecomposeStretchTextPrimitive(
+ drawinglayer::primitive2d::Primitive2DContainer& rTarget,
+ const drawinglayer::primitive2d::SdrStretchTextPrimitive2D& rSdrStretchTextPrimitive,
+ const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
+{
+ // decompose matrix to have position and size of text
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rSdrStretchTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // prepare outliner
+ SolarMutexGuard aSolarGuard;
+ SdrOutliner& rOutliner = ImpGetDrawOutliner();
+ const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
+ const Size aNullSize;
+
+ rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::STRETCHING|EEControlBits::AUTOPAGESIZE);
+ rOutliner.SetFixedCellHeight(rSdrStretchTextPrimitive.isFixedCellHeight());
+ rOutliner.SetMinAutoPaperSize(aNullSize);
+ rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
+ rOutliner.SetPaperSize(aNullSize);
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetText(rSdrStretchTextPrimitive.getOutlinerParaObject());
+
+ // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
+ rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
+
+ // now get back the laid out text size from outliner
+ const Size aOutlinerTextSize(rOutliner.CalcTextSize());
+ const basegfx::B2DVector aOutlinerScale(
+ aOutlinerTextSize.Width() == tools::Long(0) ? 1.0 : aOutlinerTextSize.Width(),
+ aOutlinerTextSize.Height() == tools::Long(0) ? 1.0 : aOutlinerTextSize.Height());
+
+ // prepare matrices to apply to newly created primitives
+ basegfx::B2DHomMatrix aNewTransformA;
+
+ // #i101957# Check for vertical text. If used, aNewTransformA
+ // needs to translate the text initially around object width to orient
+ // it relative to the topper right instead of the topper left
+ const bool bVertical(rSdrStretchTextPrimitive.getOutlinerParaObject().IsEffectivelyVertical());
+ const bool bTopToBottom(rSdrStretchTextPrimitive.getOutlinerParaObject().IsTopToBottom());
+
+ if(bVertical)
+ {
+ if(bTopToBottom)
+ aNewTransformA.translate(aScale.getX(), 0.0);
+ else
+ aNewTransformA.translate(0.0, aScale.getY());
+ }
+
+ // calculate global char stretching scale parameters. Use non-mirrored sizes
+ // to layout without mirroring
+ const double fScaleX(fabs(aScale.getX()) / aOutlinerScale.getX());
+ const double fScaleY(fabs(aScale.getY()) / aOutlinerScale.getY());
+ rOutliner.SetGlobalCharStretching(static_cast<sal_Int16>(FRound(fScaleX * 100.0)), static_cast<sal_Int16>(FRound(fScaleY * 100.0)));
+
+ // When mirroring in X and Y,
+ // move the null point which was top left to bottom right.
+ const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
+ const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
+
+ // in-between the translations of the single primitives will take place. Afterwards,
+ // the object's transformations need to be applied
+ const basegfx::B2DHomMatrix aNewTransformB(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0,
+ fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
+
+ // now break up text primitives.
+ impTextBreakupHandler aConverter(rOutliner);
+ aConverter.decomposeStretchTextPrimitive(aNewTransformA, aNewTransformB);
+
+ // cleanup outliner
+ rOutliner.SetControlWord(nOriginalControlWord);
+ rOutliner.Clear();
+ rOutliner.setVisualizedPage(nullptr);
+
+ rTarget = aConverter.extractPrimitive2DSequence();
+}
+
+
+// timing generators
+#define ENDLESS_LOOP (0xffffffff)
+#define ENDLESS_TIME (double(0xffffffff))
+#define PIXEL_DPI (96.0)
+
+void SdrTextObj::impGetBlinkTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList) const
+{
+ if(SdrTextAniKind::Blink != GetTextAniKind())
+ return;
+
+ // get values
+ const SfxItemSet& rSet = GetObjectItemSet();
+ const sal_uInt32 nRepeat(static_cast<sal_uInt32>(rSet.Get(SDRATTR_TEXT_ANICOUNT).GetValue()));
+ double fDelay(static_cast<double>(rSet.Get(SDRATTR_TEXT_ANIDELAY).GetValue()));
+
+ if(0.0 == fDelay)
+ {
+ // use default
+ fDelay = 250.0;
+ }
+
+ // prepare loop and add
+ drawinglayer::animation::AnimationEntryLoop aLoop(nRepeat ? nRepeat : ENDLESS_LOOP);
+ drawinglayer::animation::AnimationEntryFixed aStart(fDelay, 0.0);
+ aLoop.append(aStart);
+ drawinglayer::animation::AnimationEntryFixed aEnd(fDelay, 1.0);
+ aLoop.append(aEnd);
+ rAnimList.append(aLoop);
+
+ // add stopped state if loop is not endless
+ if(0 != nRepeat)
+ {
+ bool bVisibleWhenStopped(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE).GetValue());
+ drawinglayer::animation::AnimationEntryFixed aStop(ENDLESS_TIME, bVisibleWhenStopped ? 0.0 : 1.0);
+ rAnimList.append(aStop);
+ }
+}
+
+static void impCreateScrollTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, bool bForward, double fTimeFullPath, double fFrequency)
+{
+ bool bVisibleWhenStopped(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE).GetValue());
+ bool bVisibleWhenStarted(rSet.Get(SDRATTR_TEXT_ANISTARTINSIDE).GetValue());
+ const sal_uInt32 nRepeat(rSet.Get(SDRATTR_TEXT_ANICOUNT).GetValue());
+
+ if(bVisibleWhenStarted)
+ {
+ // move from center to outside
+ drawinglayer::animation::AnimationEntryLinear aInOut(fTimeFullPath * 0.5, fFrequency, 0.5, bForward ? 1.0 : 0.0);
+ rAnimList.append(aInOut);
+ }
+
+ // loop. In loop, move through
+ drawinglayer::animation::AnimationEntryLoop aLoop(nRepeat ? nRepeat : ENDLESS_LOOP);
+ drawinglayer::animation::AnimationEntryLinear aThrough(fTimeFullPath, fFrequency, bForward ? 0.0 : 1.0, bForward ? 1.0 : 0.0);
+ aLoop.append(aThrough);
+ rAnimList.append(aLoop);
+
+ if(0 != nRepeat && bVisibleWhenStopped)
+ {
+ // move from outside to center
+ drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, bForward ? 0.0 : 1.0, 0.5);
+ rAnimList.append(aOutIn);
+
+ // add timing for staying at the end
+ drawinglayer::animation::AnimationEntryFixed aEnd(ENDLESS_TIME, 0.5);
+ rAnimList.append(aEnd);
+ }
+}
+
+static void impCreateAlternateTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, double fRelativeTextLength, bool bForward, double fTimeFullPath, double fFrequency)
+{
+ if(basegfx::fTools::more(fRelativeTextLength, 0.5))
+ {
+ // this is the case when fTextLength > fFrameLength, text is bigger than animation frame.
+ // In that case, correct direction
+ bForward = !bForward;
+ }
+
+ const double fStartPosition(bForward ? fRelativeTextLength : 1.0 - fRelativeTextLength);
+ const double fEndPosition(bForward ? 1.0 - fRelativeTextLength : fRelativeTextLength);
+ bool bVisibleWhenStarted(rSet.Get(SDRATTR_TEXT_ANISTARTINSIDE).GetValue());
+ const sal_uInt32 nRepeat(rSet.Get(SDRATTR_TEXT_ANICOUNT).GetValue());
+
+ if(!bVisibleWhenStarted)
+ {
+ // move from outside to center
+ drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, bForward ? 0.0 : 1.0, 0.5);
+ rAnimList.append(aOutIn);
+ }
+
+ // loop. In loop, move out and in again. fInnerMovePath may be negative when text is bigger then frame,
+ // so use absolute value
+ const double fInnerMovePath(fabs(1.0 - (fRelativeTextLength * 2.0)));
+ const double fTimeForInnerPath(fTimeFullPath * fInnerMovePath);
+ const double fHalfInnerPath(fTimeForInnerPath * 0.5);
+ const sal_uInt32 nDoubleRepeat(nRepeat / 2L);
+
+ if(nDoubleRepeat || 0 == nRepeat)
+ {
+ // double forth and back loop
+ drawinglayer::animation::AnimationEntryLoop aLoop(nDoubleRepeat ? nDoubleRepeat : ENDLESS_LOOP);
+ drawinglayer::animation::AnimationEntryLinear aTime0(fHalfInnerPath, fFrequency, 0.5, fEndPosition);
+ aLoop.append(aTime0);
+ drawinglayer::animation::AnimationEntryLinear aTime1(fTimeForInnerPath, fFrequency, fEndPosition, fStartPosition);
+ aLoop.append(aTime1);
+ drawinglayer::animation::AnimationEntryLinear aTime2(fHalfInnerPath, fFrequency, fStartPosition, 0.5);
+ aLoop.append(aTime2);
+ rAnimList.append(aLoop);
+ }
+
+ if(nRepeat % 2L)
+ {
+ // repeat is uneven, so we need one more forth and back to center
+ drawinglayer::animation::AnimationEntryLinear aTime0(fHalfInnerPath, fFrequency, 0.5, fEndPosition);
+ rAnimList.append(aTime0);
+ drawinglayer::animation::AnimationEntryLinear aTime1(fHalfInnerPath, fFrequency, fEndPosition, 0.5);
+ rAnimList.append(aTime1);
+ }
+
+ if(0 == nRepeat)
+ return;
+
+ bool bVisibleWhenStopped(rSet.Get(SDRATTR_TEXT_ANISTOPINSIDE).GetValue());
+ if(bVisibleWhenStopped)
+ {
+ // add timing for staying at the end
+ drawinglayer::animation::AnimationEntryFixed aEnd(ENDLESS_TIME, 0.5);
+ rAnimList.append(aEnd);
+ }
+ else
+ {
+ // move from center to outside
+ drawinglayer::animation::AnimationEntryLinear aInOut(fTimeFullPath * 0.5, fFrequency, 0.5, bForward ? 1.0 : 0.0);
+ rAnimList.append(aInOut);
+ }
+}
+
+static void impCreateSlideTiming(const SfxItemSet& rSet, drawinglayer::animation::AnimationEntryList& rAnimList, bool bForward, double fTimeFullPath, double fFrequency)
+{
+ // move in from outside, start outside
+ const double fStartPosition(bForward ? 0.0 : 1.0);
+ const sal_uInt32 nRepeat(rSet.Get(SDRATTR_TEXT_ANICOUNT).GetValue());
+
+ // move from outside to center
+ drawinglayer::animation::AnimationEntryLinear aOutIn(fTimeFullPath * 0.5, fFrequency, fStartPosition, 0.5);
+ rAnimList.append(aOutIn);
+
+ // loop. In loop, move out and in again
+ if(nRepeat > 1 || 0 == nRepeat)
+ {
+ drawinglayer::animation::AnimationEntryLoop aLoop(nRepeat ? nRepeat - 1 : ENDLESS_LOOP);
+ drawinglayer::animation::AnimationEntryLinear aTime0(fTimeFullPath * 0.5, fFrequency, 0.5, fStartPosition);
+ aLoop.append(aTime0);
+ drawinglayer::animation::AnimationEntryLinear aTime1(fTimeFullPath * 0.5, fFrequency, fStartPosition, 0.5);
+ aLoop.append(aTime1);
+ rAnimList.append(aLoop);
+ }
+
+ // always visible when stopped, so add timing for staying at the end when not endless
+ if(0 != nRepeat)
+ {
+ drawinglayer::animation::AnimationEntryFixed aEnd(ENDLESS_TIME, 0.5);
+ rAnimList.append(aEnd);
+ }
+}
+
+void SdrTextObj::impGetScrollTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList, double fFrameLength, double fTextLength) const
+{
+ const SdrTextAniKind eAniKind(GetTextAniKind());
+
+ if(SdrTextAniKind::Scroll != eAniKind && SdrTextAniKind::Alternate != eAniKind && SdrTextAniKind::Slide != eAniKind)
+ return;
+
+ // get data. Goal is to calculate fTimeFullPath which is the time needed to
+ // move animation from (0.0) to (1.0) state
+ const SfxItemSet& rSet = GetObjectItemSet();
+ double fAnimationDelay(static_cast<double>(rSet.Get(SDRATTR_TEXT_ANIDELAY).GetValue()));
+ double fSingleStepWidth(static_cast<double>(rSet.Get(SDRATTR_TEXT_ANIAMOUNT).GetValue()));
+ const SdrTextAniDirection eDirection(GetTextAniDirection());
+ const bool bForward(SdrTextAniDirection::Right == eDirection || SdrTextAniDirection::Down == eDirection);
+
+ if(basegfx::fTools::equalZero(fAnimationDelay))
+ {
+ // default to 1/20 second
+ fAnimationDelay = 50.0;
+ }
+
+ if(basegfx::fTools::less(fSingleStepWidth, 0.0))
+ {
+ // data is in pixels, convert to logic. Imply PIXEL_DPI dpi.
+ // It makes no sense to keep the view-transformation centered
+ // definitions, so get rid of them here.
+ fSingleStepWidth = (-fSingleStepWidth * (2540.0 / PIXEL_DPI));
+ }
+
+ if(basegfx::fTools::equalZero(fSingleStepWidth))
+ {
+ // default to 1 millimeter
+ fSingleStepWidth = 100.0;
+ }
+
+ // use the length of the full animation path and the number of steps
+ // to get the full path time
+ const double fFullPathLength(fFrameLength + fTextLength);
+ const double fNumberOfSteps(fFullPathLength / fSingleStepWidth);
+ double fTimeFullPath(fNumberOfSteps * fAnimationDelay);
+
+ if(fTimeFullPath < fAnimationDelay)
+ {
+ fTimeFullPath = fAnimationDelay;
+ }
+
+ switch(eAniKind)
+ {
+ case SdrTextAniKind::Scroll :
+ {
+ impCreateScrollTiming(rSet, rAnimList, bForward, fTimeFullPath, fAnimationDelay);
+ break;
+ }
+ case SdrTextAniKind::Alternate :
+ {
+ double fRelativeTextLength(fTextLength / (fFrameLength + fTextLength));
+ impCreateAlternateTiming(rSet, rAnimList, fRelativeTextLength, bForward, fTimeFullPath, fAnimationDelay);
+ break;
+ }
+ case SdrTextAniKind::Slide :
+ {
+ impCreateSlideTiming(rSet, rAnimList, bForward, fTimeFullPath, fAnimationDelay);
+ break;
+ }
+ default : break; // SdrTextAniKind::NONE, SdrTextAniKind::Blink
+ }
+}
+
+void SdrTextObj::impHandleChainingEventsDuringDecomposition(SdrOutliner &rOutliner) const
+{
+ if (GetTextChain()->GetNilChainingEvent(this))
+ return;
+
+ GetTextChain()->SetNilChainingEvent(this, true);
+
+ TextChainFlow aTxtChainFlow(const_cast<SdrTextObj*>(this));
+ bool bIsOverflow;
+
+#ifdef DBG_UTIL
+ // Some debug output
+ size_t nObjCount(getSdrPageFromSdrObject()->GetObjCount());
+ for (size_t i = 0; i < nObjCount; i++)
+ {
+ SdrTextObj* pCurObj(dynamic_cast< SdrTextObj* >(getSdrPageFromSdrObject()->GetObj(i)));
+ if(pCurObj == this)
+ {
+ SAL_INFO("svx.chaining", "Working on TextBox " << i);
+ break;
+ }
+ }
+#endif
+
+ aTxtChainFlow.CheckForFlowEvents(&rOutliner);
+
+ if (aTxtChainFlow.IsUnderflow() && !IsInEditMode())
+ {
+ // underflow-induced overflow
+ aTxtChainFlow.ExecuteUnderflow(&rOutliner);
+ bIsOverflow = aTxtChainFlow.IsOverflow();
+ } else {
+ // standard overflow (no underflow before)
+ bIsOverflow = aTxtChainFlow.IsOverflow();
+ }
+
+ if (bIsOverflow && !IsInEditMode()) {
+ // Initialize Chaining Outliner
+ SdrOutliner &rChainingOutl(getSdrModelFromSdrObject().GetChainingOutliner(this));
+ ImpInitDrawOutliner( rChainingOutl );
+ rChainingOutl.SetUpdateLayout(true);
+ // We must pass the chaining outliner otherwise we would mess up decomposition
+ aTxtChainFlow.ExecuteOverflow(&rOutliner, &rChainingOutl);
+ }
+
+ GetTextChain()->SetNilChainingEvent(this, false);
+}
+
+void SdrTextObj::impDecomposeChainedTextPrimitive(
+ drawinglayer::primitive2d::Primitive2DContainer& rTarget,
+ const drawinglayer::primitive2d::SdrChainedTextPrimitive2D& rSdrChainedTextPrimitive,
+ const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
+{
+ // decompose matrix to have position and size of text
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rSdrChainedTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // use B2DRange aAnchorTextRange for calculations
+ basegfx::B2DRange aAnchorTextRange(aTranslate);
+ aAnchorTextRange.expand(aTranslate + aScale);
+
+ // prepare outliner
+ const SfxItemSet& rTextItemSet = rSdrChainedTextPrimitive.getSdrText()->GetItemSet();
+ SolarMutexGuard aSolarGuard;
+ SdrOutliner& rOutliner = ImpGetDrawOutliner();
+
+ SdrTextVertAdjust eVAdj = GetTextVerticalAdjust(rTextItemSet);
+ SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust(rTextItemSet);
+ const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
+ const Size aNullSize;
+
+ // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
+ rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
+
+ rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::AUTOPAGESIZE|EEControlBits::STRETCHING);
+ rOutliner.SetMinAutoPaperSize(aNullSize);
+ rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
+
+ // add one to rage sizes to get back to the old Rectangle and outliner measurements
+ const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1));
+ const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1));
+
+ // Text
+ const OutlinerParaObject* pOutlinerParaObject = rSdrChainedTextPrimitive.getSdrText()->GetOutlinerParaObject();
+ OSL_ENSURE(pOutlinerParaObject, "impDecomposeBlockTextPrimitive used with no OutlinerParaObject (!)");
+
+ const bool bVerticalWriting(pOutlinerParaObject->IsEffectivelyVertical());
+ const bool bTopToBottom(pOutlinerParaObject->IsTopToBottom());
+ const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
+
+ if(IsTextFrame())
+ {
+ rOutliner.SetMaxAutoPaperSize(aAnchorTextSize);
+ }
+
+ if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWriting)
+ {
+ rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
+ }
+
+ if(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWriting)
+ {
+ rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
+ }
+
+ rOutliner.SetPaperSize(aNullSize);
+ rOutliner.SetUpdateLayout(true);
+ // Sets original text
+ rOutliner.SetText(*pOutlinerParaObject);
+
+ /* Begin overflow/underflow handling */
+
+ impHandleChainingEventsDuringDecomposition(rOutliner);
+
+ /* End overflow/underflow handling */
+
+ // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
+ rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
+
+ // now get back the layouted text size from outliner
+ const Size aOutlinerTextSize(rOutliner.GetPaperSize());
+ const basegfx::B2DVector aOutlinerScale(aOutlinerTextSize.Width(), aOutlinerTextSize.Height());
+ basegfx::B2DVector aAdjustTranslate(0.0, 0.0);
+
+ // correct horizontal translation using the now known text size
+ if(SDRTEXTHORZADJUST_CENTER == eHAdj || SDRTEXTHORZADJUST_RIGHT == eHAdj)
+ {
+ const double fFree(aAnchorTextRange.getWidth() - aOutlinerScale.getX());
+
+ if(SDRTEXTHORZADJUST_CENTER == eHAdj)
+ {
+ aAdjustTranslate.setX(fFree / 2.0);
+ }
+
+ if(SDRTEXTHORZADJUST_RIGHT == eHAdj)
+ {
+ aAdjustTranslate.setX(fFree);
+ }
+ }
+
+ // correct vertical translation using the now known text size
+ if(SDRTEXTVERTADJUST_CENTER == eVAdj || SDRTEXTVERTADJUST_BOTTOM == eVAdj)
+ {
+ const double fFree(aAnchorTextRange.getHeight() - aOutlinerScale.getY());
+
+ if(SDRTEXTVERTADJUST_CENTER == eVAdj)
+ {
+ aAdjustTranslate.setY(fFree / 2.0);
+ }
+
+ if(SDRTEXTVERTADJUST_BOTTOM == eVAdj)
+ {
+ aAdjustTranslate.setY(fFree);
+ }
+ }
+
+ // prepare matrices to apply to newly created primitives. aNewTransformA
+ // will get coordinates in aOutlinerScale size and positive in X, Y.
+ basegfx::B2DHomMatrix aNewTransformA;
+ basegfx::B2DHomMatrix aNewTransformB;
+
+ // translate relative to given primitive to get same rotation and shear
+ // as the master shape we are working on. For vertical, use the top-right
+ // corner
+ const double fStartInX(bVerticalWriting && bTopToBottom ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
+ const double fStartInY(bVerticalWriting && !bTopToBottom ? aAdjustTranslate.getY() + aOutlinerScale.getY() : aAdjustTranslate.getY());
+ aNewTransformA.translate(fStartInX, fStartInY);
+
+ // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
+ // move the null point which was top left to bottom right.
+ const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
+ const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
+ aNewTransformB.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
+
+ // in-between the translations of the single primitives will take place. Afterwards,
+ // the object's transformations need to be applied
+ aNewTransformB.shearX(fShearX);
+ aNewTransformB.rotate(fRotate);
+ aNewTransformB.translate(aTranslate.getX(), aTranslate.getY());
+
+ basegfx::B2DRange aClipRange;
+
+ // now break up text primitives.
+ impTextBreakupHandler aConverter(rOutliner);
+ aConverter.decomposeBlockTextPrimitive(aNewTransformA, aNewTransformB, aClipRange);
+
+ // cleanup outliner
+ rOutliner.Clear();
+ rOutliner.setVisualizedPage(nullptr);
+ rOutliner.SetControlWord(nOriginalControlWord);
+
+ rTarget = aConverter.extractPrimitive2DSequence();
+}
+
+// Direct decomposer for text visualization when you already have a prepared
+// Outliner containing all the needed information
+void SdrTextObj::impDecomposeBlockTextPrimitiveDirect(
+ drawinglayer::primitive2d::Primitive2DContainer& rTarget,
+ SdrOutliner& rOutliner,
+ const basegfx::B2DHomMatrix& rNewTransformA,
+ const basegfx::B2DHomMatrix& rNewTransformB,
+ const basegfx::B2DRange& rClipRange)
+{
+ impTextBreakupHandler aConverter(rOutliner);
+ aConverter.decomposeBlockTextPrimitive(rNewTransformA, rNewTransformB, rClipRange);
+ rTarget.append(aConverter.extractPrimitive2DSequence());
+}
+
+double SdrTextObj::GetCameraZRotation() const
+{
+ const css::uno::Any* pAny;
+ double fTextCameraZRotateAngle = 0.0;
+ const SfxItemSet& rSet = GetObjectItemSet();
+ const SdrCustomShapeGeometryItem& rGeometryItem(rSet.Get(SDRATTR_CUSTOMSHAPE_GEOMETRY));
+
+ pAny = rGeometryItem.GetPropertyValueByName("TextCameraZRotateAngle");
+
+ if ( pAny )
+ *pAny >>= fTextCameraZRotateAngle;
+
+ return fTextCameraZRotateAngle;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdotextpathdecomposition.cxx b/svx/source/svdraw/svdotextpathdecomposition.cxx
new file mode 100644
index 000000000..14bbd73ca
--- /dev/null
+++ b/svx/source/svdraw/svdotextpathdecomposition.cxx
@@ -0,0 +1,748 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/safeint.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdoutl.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <algorithm>
+#include <com/sun/star/i18n/BreakIterator.hpp>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <basegfx/color/bcolor.hxx>
+
+
+// primitive decomposition helpers
+
+#include <drawinglayer/attribute/strokeattribute.hxx>
+#include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <svx/unoapi.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <sdr/attribute/sdrformtextoutlineattribute.hxx>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::i18n;
+
+
+// PathTextPortion helper
+
+namespace
+{
+ class impPathTextPortion
+ {
+ basegfx::B2DVector maOffset;
+ OUString maText;
+ sal_Int32 mnTextStart;
+ sal_Int32 mnTextLength;
+ sal_Int32 mnParagraph;
+ SvxFont maFont;
+ ::std::vector< double > maDblDXArray; // double DXArray, font size independent -> unit coordinate system
+ css::lang::Locale maLocale;
+
+ bool mbRTL : 1;
+
+ public:
+ explicit impPathTextPortion(const DrawPortionInfo& rInfo)
+ : maOffset(rInfo.mrStartPos.X(), rInfo.mrStartPos.Y()),
+ maText(rInfo.maText),
+ mnTextStart(rInfo.mnTextStart),
+ mnTextLength(rInfo.mnTextLen),
+ mnParagraph(rInfo.mnPara),
+ maFont(rInfo.mrFont),
+ maLocale(rInfo.mpLocale ? *rInfo.mpLocale : css::lang::Locale()),
+ mbRTL(!rInfo.mrFont.IsVertical() && rInfo.IsRTL())
+ {
+ if(mnTextLength && !rInfo.mpDXArray.empty())
+ {
+ maDblDXArray.reserve(mnTextLength);
+
+ for(sal_Int32 a=0; a < mnTextLength; a++)
+ {
+ maDblDXArray.push_back(static_cast<double>(rInfo.mpDXArray[a]));
+ }
+ }
+ }
+
+ // for ::std::sort
+ bool operator<(const impPathTextPortion& rComp) const
+ {
+ if(mnParagraph < rComp.mnParagraph)
+ {
+ return true;
+ }
+
+ if(maOffset.getX() < rComp.maOffset.getX())
+ {
+ return true;
+ }
+
+ return (maOffset.getY() < rComp.maOffset.getY());
+ }
+
+ const OUString& getText() const { return maText; }
+ sal_Int32 getTextStart() const { return mnTextStart; }
+ sal_Int32 getTextLength() const { return mnTextLength; }
+ sal_Int32 getParagraph() const { return mnParagraph; }
+ const SvxFont& getFont() const { return maFont; }
+ bool isRTL() const { return mbRTL; }
+ const ::std::vector< double >& getDoubleDXArray() const { return maDblDXArray; }
+ const css::lang::Locale& getLocale() const { return maLocale; }
+
+ sal_Int32 getPortionIndex(sal_Int32 nIndex, sal_Int32 nLength) const
+ {
+ if(mbRTL)
+ {
+ return (mnTextStart + (mnTextLength - (nIndex + nLength)));
+ }
+ else
+ {
+ return (mnTextStart + nIndex);
+ }
+ }
+
+ double getDisplayLength(sal_Int32 nIndex, sal_Int32 nLength) const
+ {
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
+ double fRetval(0.0);
+
+ if(maFont.IsVertical())
+ {
+ fRetval = aTextLayouter.getTextHeight() * static_cast<double>(nLength);
+ }
+ else
+ {
+ fRetval = aTextLayouter.getTextWidth(maText, getPortionIndex(nIndex, nLength), nLength);
+ }
+
+ return fRetval;
+ }
+ };
+} // end of anonymous namespace
+
+
+// TextBreakup helper
+
+namespace
+{
+ class impTextBreakupHandler
+ {
+ SdrOutliner& mrOutliner;
+ ::std::vector< impPathTextPortion > maPathTextPortions;
+
+ DECL_LINK(decompositionPathTextPrimitive, DrawPortionInfo*, void );
+
+ public:
+ explicit impTextBreakupHandler(SdrOutliner& rOutliner)
+ : mrOutliner(rOutliner)
+ {
+ }
+
+ const ::std::vector< impPathTextPortion >& decompositionPathTextPrimitive()
+ {
+ // strip portions to maPathTextPortions
+ mrOutliner.SetDrawPortionHdl(LINK(this, impTextBreakupHandler, decompositionPathTextPrimitive));
+ mrOutliner.StripPortions();
+
+ if(!maPathTextPortions.empty())
+ {
+ // sort portions by paragraph, x and y
+ ::std::sort(maPathTextPortions.begin(), maPathTextPortions.end());
+ }
+
+ return maPathTextPortions;
+ }
+ };
+
+ IMPL_LINK(impTextBreakupHandler, decompositionPathTextPrimitive, DrawPortionInfo*, pInfo, void)
+ {
+ maPathTextPortions.emplace_back(*pInfo);
+ }
+} // end of anonymous namespace
+
+
+// TextBreakup one poly and one paragraph helper
+
+namespace
+{
+ class impPolygonParagraphHandler
+ {
+ const drawinglayer::attribute::SdrFormTextAttribute maSdrFormTextAttribute; // FormText parameters
+ drawinglayer::primitive2d::Primitive2DContainer& mrDecomposition; // destination primitive list
+ drawinglayer::primitive2d::Primitive2DContainer& mrShadowDecomposition; // destination primitive list for shadow
+ Reference < css::i18n::XBreakIterator > mxBreak; // break iterator
+
+ static double getParagraphTextLength(const ::std::vector< const impPathTextPortion* >& rTextPortions)
+ {
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
+ double fRetval(0.0);
+
+ for(const impPathTextPortion* pCandidate : rTextPortions)
+ {
+ if(pCandidate && pCandidate->getTextLength())
+ {
+ aTextLayouter.setFont(pCandidate->getFont());
+ fRetval += pCandidate->getDisplayLength(0, pCandidate->getTextLength());
+ }
+ }
+
+ return fRetval;
+ }
+
+ sal_Int32 getNextGlyphLen(const impPathTextPortion* pCandidate, sal_Int32 nPosition, const css::lang::Locale& rFontLocale)
+ {
+ sal_Int32 nNextGlyphLen(1);
+
+ if(mxBreak.is())
+ {
+ sal_Int32 nDone(0);
+ nNextGlyphLen = mxBreak->nextCharacters(pCandidate->getText(), nPosition,
+ rFontLocale, CharacterIteratorMode::SKIPCELL, 1, nDone) - nPosition;
+ }
+
+ return nNextGlyphLen;
+ }
+
+ public:
+ impPolygonParagraphHandler(
+ const drawinglayer::attribute::SdrFormTextAttribute& rSdrFormTextAttribute,
+ drawinglayer::primitive2d::Primitive2DContainer& rDecomposition,
+ drawinglayer::primitive2d::Primitive2DContainer& rShadowDecomposition)
+ : maSdrFormTextAttribute(rSdrFormTextAttribute),
+ mrDecomposition(rDecomposition),
+ mrShadowDecomposition(rShadowDecomposition)
+ {
+ // prepare BreakIterator
+ Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ mxBreak = css::i18n::BreakIterator::create(xContext);
+ }
+
+ void HandlePair(const basegfx::B2DPolygon& rPolygonCandidate, const ::std::vector< const impPathTextPortion* >& rTextPortions)
+ {
+ // prepare polygon geometry, take into account as many parameters as possible
+ basegfx::B2DPolygon aPolygonCandidate(rPolygonCandidate);
+ const double fPolyLength(basegfx::utils::getLength(aPolygonCandidate));
+ double fPolyEnd(fPolyLength);
+ double fPolyStart(0.0);
+ double fAutosizeScaleFactor(1.0);
+ bool bAutosizeScale(false);
+
+ if(maSdrFormTextAttribute.getFormTextMirror())
+ {
+ aPolygonCandidate.flip();
+ }
+
+ if(maSdrFormTextAttribute.getFormTextStart()
+ && (XFormTextAdjust::Left == maSdrFormTextAttribute.getFormTextAdjust()
+ || XFormTextAdjust::Right == maSdrFormTextAttribute.getFormTextAdjust()))
+ {
+ if(XFormTextAdjust::Left == maSdrFormTextAttribute.getFormTextAdjust())
+ {
+ fPolyStart += maSdrFormTextAttribute.getFormTextStart();
+
+ if(fPolyStart > fPolyEnd)
+ {
+ fPolyStart = fPolyEnd;
+ }
+ }
+ else
+ {
+ fPolyEnd -= maSdrFormTextAttribute.getFormTextStart();
+
+ if(fPolyEnd < fPolyStart)
+ {
+ fPolyEnd = fPolyStart;
+ }
+ }
+ }
+
+ if(XFormTextAdjust::Left != maSdrFormTextAttribute.getFormTextAdjust())
+ {
+ // calculate total text length of this paragraph, some layout needs to be done
+ const double fParagraphTextLength(getParagraphTextLength(rTextPortions));
+
+ // check if text is too long for paragraph. If yes, handle as if left aligned (default),
+ // but still take care of XFormTextAdjust::AutoSize in that case
+ const bool bTextTooLong(fParagraphTextLength > (fPolyEnd - fPolyStart));
+
+ if(XFormTextAdjust::Right == maSdrFormTextAttribute.getFormTextAdjust())
+ {
+ if(!bTextTooLong)
+ {
+ // if right aligned, add difference to polygon start
+ fPolyStart += ((fPolyEnd - fPolyStart) - fParagraphTextLength);
+ }
+ }
+ else if(XFormTextAdjust::Center == maSdrFormTextAttribute.getFormTextAdjust())
+ {
+ if(!bTextTooLong)
+ {
+ // if centered, add half of difference to polygon start
+ fPolyStart += ((fPolyEnd - fPolyStart) - fParagraphTextLength) / 2.0;
+ }
+ }
+ else if(XFormTextAdjust::AutoSize == maSdrFormTextAttribute.getFormTextAdjust())
+ {
+ // if scale, prepare scale factor between curve length and text length
+ if(0.0 != fParagraphTextLength)
+ {
+ fAutosizeScaleFactor = (fPolyEnd - fPolyStart) / fParagraphTextLength;
+ bAutosizeScale = true;
+ }
+ }
+ }
+
+ // handle text portions for this paragraph
+ for(auto a = rTextPortions.begin(); a != rTextPortions.end() && fPolyStart < fPolyEnd; ++a)
+ {
+ const impPathTextPortion* pCandidate = *a;
+ basegfx::B2DVector aFontScaling;
+
+ if(pCandidate && pCandidate->getTextLength())
+ {
+ const drawinglayer::attribute::FontAttribute aCandidateFontAttribute(
+ drawinglayer::primitive2d::getFontAttributeFromVclFont(
+ aFontScaling,
+ pCandidate->getFont(),
+ pCandidate->isRTL(),
+ false));
+
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
+ aTextLayouter.setFont(pCandidate->getFont());
+ sal_Int32 nUsedTextLength(0);
+
+ while(nUsedTextLength < pCandidate->getTextLength() && fPolyStart < fPolyEnd)
+ {
+ sal_Int32 nNextGlyphLen(getNextGlyphLen(pCandidate, pCandidate->getTextStart() + nUsedTextLength, pCandidate->getLocale()));
+
+ // prepare portion length. Takes RTL sections into account.
+ double fPortionLength(pCandidate->getDisplayLength(nUsedTextLength, nNextGlyphLen));
+
+ if(bAutosizeScale)
+ {
+ // when autosize scaling, expand portion length
+ fPortionLength *= fAutosizeScaleFactor;
+ }
+
+ // create transformation
+ basegfx::B2DHomMatrix aNewTransformA, aNewTransformB, aNewShadowTransform;
+ basegfx::B2DPoint aStartPos(basegfx::utils::getPositionAbsolute(aPolygonCandidate, fPolyStart, fPolyLength));
+ basegfx::B2DPoint aEndPos(aStartPos);
+
+ // add font scaling
+ aNewTransformA.scale(aFontScaling.getX(), aFontScaling.getY());
+
+ // prepare scaling of text primitive
+ if(bAutosizeScale)
+ {
+ // when autosize scaling, expand text primitive scaling to it
+ aNewTransformA.scale(fAutosizeScaleFactor, fAutosizeScaleFactor);
+ }
+
+ // eventually create shadow primitives from aDecomposition and add to rDecomposition
+ const bool bShadow(XFormTextShadow::NONE != maSdrFormTextAttribute.getFormTextShadow());
+
+ if(bShadow)
+ {
+ if(XFormTextShadow::Normal == maSdrFormTextAttribute.getFormTextShadow())
+ {
+ aNewShadowTransform.translate(
+ maSdrFormTextAttribute.getFormTextShdwXVal(),
+ -maSdrFormTextAttribute.getFormTextShdwYVal());
+ }
+ else // XFormTextShadow::Slant
+ {
+ double fScaleValue(maSdrFormTextAttribute.getFormTextShdwYVal() / 100.0);
+ double fShearValue(-basegfx::deg2rad<10>(maSdrFormTextAttribute.getFormTextShdwXVal()));
+
+ aNewShadowTransform.scale(1.0, fScaleValue);
+ aNewShadowTransform.shearX(sin(fShearValue));
+ aNewShadowTransform.scale(1.0, cos(fShearValue));
+ }
+ }
+
+ switch(maSdrFormTextAttribute.getFormTextStyle())
+ {
+ case XFormTextStyle::Rotate :
+ {
+ aEndPos = basegfx::utils::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
+ const basegfx::B2DVector aDirection(aEndPos - aStartPos);
+ aNewTransformB.rotate(atan2(aDirection.getY(), aDirection.getX()));
+ aNewTransformB.translate(aStartPos.getX(), aStartPos.getY());
+
+ break;
+ }
+ case XFormTextStyle::Upright :
+ {
+ aNewTransformB.translate(aStartPos.getX() - (fPortionLength / 2.0), aStartPos.getY());
+
+ break;
+ }
+ case XFormTextStyle::SlantX :
+ {
+ aEndPos = basegfx::utils::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
+ const basegfx::B2DVector aDirection(aEndPos - aStartPos);
+ const double fShearValue(atan2(aDirection.getY(), aDirection.getX()));
+ const double fSin(sin(fShearValue));
+ const double fCos(cos(fShearValue));
+
+ aNewTransformB.shearX(-fSin);
+
+ // Scale may lead to objects without height since fCos == 0.0 is possible.
+ // Renderers need to handle that, it's not a forbidden value and does not
+ // need to be avoided
+ aNewTransformB.scale(1.0, fCos);
+ aNewTransformB.translate(aStartPos.getX() - (fPortionLength / 2.0), aStartPos.getY());
+
+ break;
+ }
+ case XFormTextStyle::SlantY :
+ {
+ aEndPos = basegfx::utils::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
+ const basegfx::B2DVector aDirection(aEndPos - aStartPos);
+ const double fShearValue(atan2(aDirection.getY(), aDirection.getX()));
+ const double fCos(cos(fShearValue));
+ const double fTan(tan(fShearValue));
+
+ // shear to 'stand' on the curve
+ aNewTransformB.shearY(fTan);
+
+ // scale in X to make as tight as needed. As with XFT_SLANT_X, this may
+ // lead to primitives without width which the renderers will handle
+ aNewTransformA.scale(fCos, 1.0);
+
+ aNewTransformB.translate(aStartPos.getX(), aStartPos.getY());
+
+ break;
+ }
+ default : break; // XFormTextStyle::NONE
+ }
+
+ // distance from path?
+ if(maSdrFormTextAttribute.getFormTextDistance())
+ {
+ if(aEndPos.equal(aStartPos))
+ {
+ aEndPos = basegfx::utils::getPositionAbsolute(aPolygonCandidate, fPolyStart + fPortionLength, fPolyLength);
+ }
+
+ // use back vector (aStartPos - aEndPos) here to get mirrored perpendicular as in old stuff
+ const basegfx::B2DVector aPerpendicular(
+ basegfx::getNormalizedPerpendicular(aStartPos - aEndPos) *
+ maSdrFormTextAttribute.getFormTextDistance());
+ aNewTransformB.translate(aPerpendicular.getX(), aPerpendicular.getY());
+ }
+
+ if(!pCandidate->getText().isEmpty() && nNextGlyphLen)
+ {
+ const sal_Int32 nPortionIndex(pCandidate->getPortionIndex(nUsedTextLength, nNextGlyphLen));
+ ::std::vector< double > aNewDXArray;
+
+ if(nNextGlyphLen > 1 && !pCandidate->getDoubleDXArray().empty())
+ {
+ // copy DXArray for portion
+ aNewDXArray.insert(
+ aNewDXArray.begin(),
+ pCandidate->getDoubleDXArray().begin() + nPortionIndex,
+ pCandidate->getDoubleDXArray().begin() + (nPortionIndex + nNextGlyphLen));
+
+ if(nPortionIndex > 0)
+ {
+ // adapt to portion start
+ double fDXOffset= *(pCandidate->getDoubleDXArray().begin() + (nPortionIndex - 1));
+ ::std::transform(
+ aNewDXArray.begin(), aNewDXArray.end(),
+ aNewDXArray.begin(), [fDXOffset](double x) { return x - fDXOffset; });
+ }
+
+ if(bAutosizeScale)
+ {
+ // when autosize scaling, adapt to DXArray, too
+ ::std::transform(
+ aNewDXArray.begin(), aNewDXArray.end(),
+ aNewDXArray.begin(), [fAutosizeScaleFactor](double x) { return x * fAutosizeScaleFactor; });
+ }
+ }
+
+ if(bShadow)
+ {
+ // shadow primitive creation
+ const Color aShadowColor(maSdrFormTextAttribute.getFormTextShdwColor());
+ const basegfx::BColor aRGBShadowColor(aShadowColor.getBColor());
+
+ mrShadowDecomposition.push_back(
+ new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aNewTransformB * aNewShadowTransform * aNewTransformA,
+ pCandidate->getText(),
+ nPortionIndex,
+ nNextGlyphLen,
+ std::vector(aNewDXArray),
+ aCandidateFontAttribute,
+ pCandidate->getLocale(),
+ aRGBShadowColor) );
+ }
+
+ {
+ // primitive creation
+ const Color aColor(pCandidate->getFont().GetColor());
+ const basegfx::BColor aRGBColor(aColor.getBColor());
+
+ mrDecomposition.push_back(
+ new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aNewTransformB * aNewTransformA,
+ pCandidate->getText(),
+ nPortionIndex,
+ nNextGlyphLen,
+ std::move(aNewDXArray),
+ aCandidateFontAttribute,
+ pCandidate->getLocale(),
+ aRGBColor) );
+ }
+ }
+
+ // consume from portion
+ nUsedTextLength += nNextGlyphLen;
+
+ // consume from polygon
+ fPolyStart += fPortionLength;
+ }
+ }
+ }
+ }
+ };
+} // end of anonymous namespace
+
+
+// primitive decomposition helpers
+
+namespace
+{
+ void impAddPolygonStrokePrimitives(
+ const basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector,
+ const basegfx::B2DHomMatrix& rTransform,
+ const drawinglayer::attribute::LineAttribute& rLineAttribute,
+ const drawinglayer::attribute::StrokeAttribute& rStrokeAttribute,
+ drawinglayer::primitive2d::Primitive2DContainer& rTarget)
+ {
+ for(const auto& rB2DPolyPolygon : rB2DPolyPolyVector)
+ {
+ // prepare PolyPolygons
+ basegfx::B2DPolyPolygon aB2DPolyPolygon = rB2DPolyPolygon;
+ aB2DPolyPolygon.transform(rTransform);
+
+ for(auto const& rPolygon : std::as_const(aB2DPolyPolygon))
+ {
+ // create one primitive per polygon
+ rTarget.push_back(
+ new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
+ rPolygon, rLineAttribute, rStrokeAttribute) );
+ }
+ }
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer impAddPathTextOutlines(
+ const drawinglayer::primitive2d::Primitive2DContainer& rSource,
+ const drawinglayer::attribute::SdrFormTextOutlineAttribute& rOutlineAttribute)
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aNewPrimitives;
+
+ for(const drawinglayer::primitive2d::Primitive2DReference& a : rSource)
+ {
+ const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pTextCandidate = dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(a.get());
+
+ if(pTextCandidate)
+ {
+ basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
+ basegfx::B2DHomMatrix aPolygonTransform;
+
+ // get text outlines and their object transformation
+ pTextCandidate->getTextOutlinesAndTransformation(aB2DPolyPolyVector, aPolygonTransform);
+
+ if(!aB2DPolyPolyVector.empty())
+ {
+ // create stroke primitives
+ drawinglayer::primitive2d::Primitive2DContainer aStrokePrimitives;
+ impAddPolygonStrokePrimitives(
+ aB2DPolyPolyVector,
+ aPolygonTransform,
+ rOutlineAttribute.getLineAttribute(),
+ rOutlineAttribute.getStrokeAttribute(),
+ aStrokePrimitives);
+ const sal_uInt32 nStrokeCount(aStrokePrimitives.size());
+
+ if(nStrokeCount)
+ {
+ if(rOutlineAttribute.getTransparence())
+ {
+ // create UnifiedTransparencePrimitive2D
+ aNewPrimitives.push_back(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ std::move(aStrokePrimitives),
+ static_cast<double>(rOutlineAttribute.getTransparence()) / 100.0) );
+ }
+ else
+ {
+ // add polygons to rDecomposition as polygonStrokePrimitives
+ aNewPrimitives.append( std::move(aStrokePrimitives) );
+ }
+ }
+ }
+ }
+ }
+
+ return aNewPrimitives;
+ }
+} // end of anonymous namespace
+
+
+// primitive decomposition
+
+void SdrTextObj::impDecomposePathTextPrimitive(
+ drawinglayer::primitive2d::Primitive2DContainer& rTarget,
+ const drawinglayer::primitive2d::SdrPathTextPrimitive2D& rSdrPathTextPrimitive,
+ const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
+{
+ drawinglayer::primitive2d::Primitive2DContainer aRetvalA;
+ drawinglayer::primitive2d::Primitive2DContainer aRetvalB;
+
+ // prepare outliner
+ SdrOutliner& rOutliner = ImpGetDrawOutliner();
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.Clear();
+ rOutliner.SetPaperSize(Size(LONG_MAX,LONG_MAX));
+ rOutliner.SetText(rSdrPathTextPrimitive.getOutlinerParaObject());
+
+ // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
+ rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
+
+ // now break up to text portions
+ impTextBreakupHandler aConverter(rOutliner);
+ const ::std::vector< impPathTextPortion > rPathTextPortions = aConverter.decompositionPathTextPrimitive();
+
+ if(!rPathTextPortions.empty())
+ {
+ // get FormText and polygon values
+ const drawinglayer::attribute::SdrFormTextAttribute& rFormTextAttribute = rSdrPathTextPrimitive.getSdrFormTextAttribute();
+ const basegfx::B2DPolyPolygon& rPathPolyPolygon(rSdrPathTextPrimitive.getPathPolyPolygon());
+
+ // get loop count
+ sal_uInt32 nLoopCount(rPathPolyPolygon.count());
+
+ if(o3tl::make_unsigned(rOutliner.GetParagraphCount()) < nLoopCount)
+ {
+ nLoopCount = rOutliner.GetParagraphCount();
+ }
+
+ if(nLoopCount)
+ {
+ // prepare common decomposition stuff
+ drawinglayer::primitive2d::Primitive2DContainer aRegularDecomposition;
+ drawinglayer::primitive2d::Primitive2DContainer aShadowDecomposition;
+ impPolygonParagraphHandler aPolygonParagraphHandler(
+ rFormTextAttribute,
+ aRegularDecomposition,
+ aShadowDecomposition);
+ sal_uInt32 a;
+
+ for(a = 0; a < nLoopCount; a++)
+ {
+ // filter text portions for this paragraph
+ ::std::vector< const impPathTextPortion* > aParagraphTextPortions;
+
+ for(const auto & rCandidate : rPathTextPortions)
+ {
+ if(static_cast<sal_uInt32>(rCandidate.getParagraph()) == a)
+ {
+ aParagraphTextPortions.push_back(&rCandidate);
+ }
+ }
+
+ // handle data pair polygon/ParagraphTextPortions
+ if(!aParagraphTextPortions.empty())
+ {
+ aPolygonParagraphHandler.HandlePair(rPathPolyPolygon.getB2DPolygon(a), aParagraphTextPortions);
+ }
+ }
+
+ const sal_uInt32 nShadowCount(aShadowDecomposition.size());
+ const sal_uInt32 nRegularCount(aRegularDecomposition.size());
+
+ if(nShadowCount)
+ {
+ // add shadow primitives to decomposition
+
+ // if necessary, add shadow outlines
+ if(rFormTextAttribute.getFormTextOutline()
+ && !rFormTextAttribute.getShadowOutline().isDefault())
+ {
+ aRetvalA = aShadowDecomposition;
+ const drawinglayer::primitive2d::Primitive2DContainer aOutlines(
+ impAddPathTextOutlines(
+ aShadowDecomposition,
+ rFormTextAttribute.getShadowOutline()));
+
+ aRetvalA.append(aOutlines);
+ }
+ else
+ aRetvalA = std::move(aShadowDecomposition);
+ }
+
+ if(nRegularCount)
+ {
+ // add normal primitives to decomposition
+
+ // if necessary, add outlines
+ if(rFormTextAttribute.getFormTextOutline()
+ && !rFormTextAttribute.getOutline().isDefault())
+ {
+ aRetvalB = aRegularDecomposition;
+ const drawinglayer::primitive2d::Primitive2DContainer aOutlines(
+ impAddPathTextOutlines(
+ aRegularDecomposition,
+ rFormTextAttribute.getOutline()));
+
+ aRetvalB.append(aOutlines);
+ }
+ else
+ aRetvalB = std::move(aRegularDecomposition);
+ }
+ }
+ }
+
+ // clean up outliner
+ rOutliner.SetDrawPortionHdl(Link<DrawPortionInfo*,void>());
+ rOutliner.Clear();
+ rOutliner.setVisualizedPage(nullptr);
+
+ // concatenate all results
+ rTarget.append(std::move(aRetvalA));
+ rTarget.append(std::move(aRetvalB));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdotxat.cxx b/svx/source/svdraw/svdotxat.cxx
new file mode 100644
index 000000000..97bdb5e59
--- /dev/null
+++ b/svx/source/svdraw/svdotxat.cxx
@@ -0,0 +1,457 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/string.hxx>
+#include <o3tl/sorted_vector.hxx>
+#include <o3tl/string_view.hxx>
+#include <svl/style.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdocapt.hxx>
+#include <editeng/editdata.hxx>
+#include <svx/sdtfchim.hxx>
+
+
+#include <editeng/outlobj.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/editobj.hxx>
+
+namespace {
+// The style family which is appended to the style names is padded to this many characters.
+const short PADDING_LENGTH_FOR_STYLE_FAMILY = 5;
+// this character will be used to pad the style families when they are appended to the style names
+const char PADDING_CHARACTER_FOR_STYLE_FAMILY = ' ';
+}
+
+bool SdrTextObj::AdjustTextFrameWidthAndHeight( tools::Rectangle& rR, bool bHgt, bool bWdt ) const
+{
+ if (!mbTextFrame)
+ // Not a text frame. Bail out.
+ return false;
+
+ if (rR.IsEmpty())
+ // Empty rectangle.
+ return false;
+
+ bool bFitToSize = IsFitToSize();
+ if (bFitToSize)
+ return false;
+
+ bool bWdtGrow = bWdt && IsAutoGrowWidth();
+ bool bHgtGrow = bHgt && IsAutoGrowHeight();
+ if (!bWdtGrow && !bHgtGrow)
+ // Not supposed to auto-adjust width or height.
+ return false;
+
+ SdrTextAniKind eAniKind = GetTextAniKind();
+ SdrTextAniDirection eAniDir = GetTextAniDirection();
+
+ bool bScroll = eAniKind == SdrTextAniKind::Scroll || eAniKind == SdrTextAniKind::Alternate || eAniKind == SdrTextAniKind::Slide;
+ bool bHScroll = bScroll && (eAniDir == SdrTextAniDirection::Left || eAniDir == SdrTextAniDirection::Right);
+ bool bVScroll = bScroll && (eAniDir == SdrTextAniDirection::Up || eAniDir == SdrTextAniDirection::Down);
+
+ tools::Rectangle aOldRect = rR;
+ tools::Long nHgt = 0, nMinHgt = 0, nMaxHgt = 0;
+ tools::Long nWdt = 0, nMinWdt = 0, nMaxWdt = 0;
+
+ Size aNewSize = rR.GetSize();
+ aNewSize.AdjustWidth( -1 ); aNewSize.AdjustHeight( -1 );
+
+ Size aMaxSiz(100000, 100000);
+ Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
+
+ if (aTmpSiz.Width())
+ aMaxSiz.setWidth( aTmpSiz.Width() );
+ if (aTmpSiz.Height())
+ aMaxSiz.setHeight( aTmpSiz.Height() );
+
+ if (bWdtGrow)
+ {
+ nMinWdt = GetMinTextFrameWidth();
+ nMaxWdt = GetMaxTextFrameWidth();
+ if (nMaxWdt == 0 || nMaxWdt > aMaxSiz.Width())
+ nMaxWdt = aMaxSiz.Width();
+ if (nMinWdt <= 0)
+ nMinWdt = 1;
+
+ aNewSize.setWidth( nMaxWdt );
+ }
+
+ if (bHgtGrow)
+ {
+ nMinHgt = GetMinTextFrameHeight();
+ nMaxHgt = GetMaxTextFrameHeight();
+ if (nMaxHgt == 0 || nMaxHgt > aMaxSiz.Height())
+ nMaxHgt = aMaxSiz.Height();
+ if (nMinHgt <= 0)
+ nMinHgt = 1;
+
+ aNewSize.setHeight( nMaxHgt );
+ }
+
+ tools::Long nHDist = GetTextLeftDistance() + GetTextRightDistance();
+ tools::Long nVDist = GetTextUpperDistance() + GetTextLowerDistance();
+ aNewSize.AdjustWidth( -nHDist );
+ aNewSize.AdjustHeight( -nVDist );
+
+ if (aNewSize.Width() < 2)
+ aNewSize.setWidth( 2 );
+ if (aNewSize.Height() < 2)
+ aNewSize.setHeight( 2 );
+
+ if (!IsInEditMode())
+ {
+ if (bHScroll)
+ aNewSize.setWidth( 0x0FFFFFFF ); // don't break ticker text
+ if (bVScroll)
+ aNewSize.setHeight( 0x0FFFFFFF );
+ }
+
+ if (mpEditingOutliner)
+ {
+ mpEditingOutliner->SetMaxAutoPaperSize(aNewSize);
+ if (bWdtGrow)
+ {
+ Size aSiz2(mpEditingOutliner->CalcTextSize());
+ nWdt = aSiz2.Width() + 1; // a little tolerance
+ if (bHgtGrow)
+ nHgt = aSiz2.Height() + 1; // a little tolerance
+ }
+ else
+ {
+ nHgt = mpEditingOutliner->GetTextHeight() + 1; // a little tolerance
+ }
+ }
+ else
+ {
+ Outliner& rOutliner = ImpGetDrawOutliner();
+ rOutliner.SetPaperSize(aNewSize);
+ rOutliner.SetUpdateLayout(true);
+ // TODO: add the optimization with bPortionInfoChecked etc. here
+ OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+ if (pOutlinerParaObject)
+ {
+ rOutliner.SetText(*pOutlinerParaObject);
+ rOutliner.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue());
+ }
+
+ if (bWdtGrow)
+ {
+ Size aSiz2(rOutliner.CalcTextSize());
+ nWdt = aSiz2.Width() + 1; // a little tolerance
+ if (bHgtGrow)
+ nHgt = aSiz2.Height() + 1; // a little tolerance
+ }
+ else
+ {
+ nHgt = rOutliner.GetTextHeight() + 1; // a little tolerance
+ }
+ rOutliner.Clear();
+ }
+
+ if (nWdt < nMinWdt)
+ nWdt = nMinWdt;
+ if (nWdt > nMaxWdt)
+ nWdt = nMaxWdt;
+ nWdt += nHDist;
+ if (nWdt < 1)
+ nWdt = 1; // nHDist may be negative
+ if (nHgt < nMinHgt)
+ nHgt = nMinHgt;
+ if (nHgt > nMaxHgt)
+ nHgt = nMaxHgt;
+ nHgt += nVDist;
+ if (nHgt < 1)
+ nHgt = 1; // nVDist may be negative
+ tools::Long nWdtGrow = nWdt - (rR.Right() - rR.Left());
+ tools::Long nHgtGrow = nHgt - (rR.Bottom() - rR.Top());
+
+ if (nWdtGrow == 0)
+ bWdtGrow = false;
+ if (nHgtGrow == 0)
+ bHgtGrow = false;
+
+ if (!bWdtGrow && !bHgtGrow)
+ return false;
+
+ if (bWdtGrow)
+ {
+ SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust();
+
+ if (eHAdj == SDRTEXTHORZADJUST_LEFT)
+ rR.AdjustRight(nWdtGrow );
+ else if (eHAdj == SDRTEXTHORZADJUST_RIGHT)
+ rR.AdjustLeft( -nWdtGrow );
+ else
+ {
+ tools::Long nWdtGrow2 = nWdtGrow / 2;
+ rR.AdjustLeft( -nWdtGrow2 );
+ rR.SetRight( rR.Left() + nWdt );
+ }
+ }
+
+ if (bHgtGrow)
+ {
+ SdrTextVertAdjust eVAdj = GetTextVerticalAdjust();
+
+ if (eVAdj == SDRTEXTVERTADJUST_TOP)
+ rR.AdjustBottom(nHgtGrow );
+ else if (eVAdj == SDRTEXTVERTADJUST_BOTTOM)
+ rR.AdjustTop( -nHgtGrow );
+ else
+ {
+ tools::Long nHgtGrow2 = nHgtGrow / 2;
+ rR.AdjustTop( -nHgtGrow2 );
+ rR.SetBottom( rR.Top() + nHgt );
+ }
+ }
+
+ if (maGeo.nRotationAngle)
+ {
+ // Object is rotated.
+ Point aD1(rR.TopLeft());
+ aD1 -= aOldRect.TopLeft();
+ Point aD2(aD1);
+ RotatePoint(aD2, Point(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
+ aD2 -= aD1;
+ rR.Move(aD2.X(), aD2.Y());
+ }
+
+ return true;
+}
+
+bool SdrTextObj::NbcAdjustTextFrameWidthAndHeight(bool bHgt, bool bWdt)
+{
+ bool bRet = AdjustTextFrameWidthAndHeight(maRect,bHgt,bWdt);
+ if (bRet)
+ {
+ SetBoundAndSnapRectsDirty();
+ if (auto pRectObj = dynamic_cast<SdrRectObj *>(this)) { // this is a hack
+ pRectObj->SetXPolyDirty();
+ }
+ if (auto pCaptionObj = dynamic_cast<SdrCaptionObj *>(this)) { // this is a hack
+ pCaptionObj->ImpRecalcTail();
+ }
+ }
+ return bRet;
+}
+
+bool SdrTextObj::AdjustTextFrameWidthAndHeight()
+{
+ tools::Rectangle aNewRect(maRect);
+ bool bRet=AdjustTextFrameWidthAndHeight(aNewRect);
+ if (bRet) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ maRect = aNewRect;
+ SetBoundAndSnapRectsDirty();
+ if (auto pRectObj = dynamic_cast<SdrRectObj *>(this)) { // this is a hack
+ pRectObj->SetXPolyDirty();
+ }
+ bool bScPostIt = false;
+ if (auto pCaptionObj = dynamic_cast<SdrCaptionObj *>(this)) { // this is a hack
+ pCaptionObj->ImpRecalcTail();
+ // tdf#114956, tdf#138549 use GetSpecialTextBoxShadow to recognize
+ // that this SdrCaption is for a ScPostit
+ bScPostIt = pCaptionObj->GetSpecialTextBoxShadow();
+ }
+
+ // to not slow down EditView visualization on Overlay (see
+ // TextEditOverlayObject) it is necessary to suppress the
+ // Invalidates for the deep repaint when the size of the
+ // TextFrame changed (AdjustTextFrameWidthAndHeight returned
+ // true). The ObjectChanges are valid, invalidate will be
+ // done on EndTextEdit anyways
+ const bool bSuppressChangeWhenEditOnOverlay(
+ IsInEditMode() &&
+ GetTextEditOutliner() &&
+ GetTextEditOutliner()->hasEditViewCallbacks());
+
+ if (!bSuppressChangeWhenEditOnOverlay || bScPostIt)
+ {
+ SetChanged();
+ BroadcastObjectChange();
+ }
+
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+ return bRet;
+}
+
+void SdrTextObj::ImpSetTextStyleSheetListeners()
+{
+ SfxStyleSheetBasePool* pStylePool(getSdrModelFromSdrObject().GetStyleSheetPool());
+ if (pStylePool==nullptr)
+ return;
+
+ std::vector<OUString> aStyleNames;
+ OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+ if (pOutlinerParaObject!=nullptr)
+ {
+ // First, we collect all stylesheets contained in the ParaObject in
+ // the container aStyles. The Family is always appended to the name
+ // of the stylesheet.
+ const EditTextObject& rTextObj=pOutlinerParaObject->GetTextObject();
+ OUString aStyleName;
+ SfxStyleFamily eStyleFam;
+ sal_Int32 nParaCnt=rTextObj.GetParagraphCount();
+
+
+ for(sal_Int32 nParaNum(0); nParaNum < nParaCnt; nParaNum++)
+ {
+ rTextObj.GetStyleSheet(nParaNum, aStyleName, eStyleFam);
+
+ if (!aStyleName.isEmpty())
+ {
+ AppendFamilyToStyleName(aStyleName, eStyleFam);
+
+ bool bFnd(false);
+ sal_uInt32 nNum(aStyleNames.size());
+
+ while(!bFnd && nNum > 0)
+ {
+ // we don't want duplicate stylesheets
+ nNum--;
+ bFnd = aStyleName == aStyleNames[nNum];
+ }
+
+ if(!bFnd)
+ {
+ aStyleNames.push_back(aStyleName);
+ }
+ }
+ }
+ }
+
+ // now convert the strings in the vector from names to StyleSheet*
+ o3tl::sorted_vector<SfxStyleSheet*> aStyleSheets;
+ while (!aStyleNames.empty()) {
+ OUString aName = aStyleNames.back();
+ aStyleNames.pop_back();
+
+ SfxStyleFamily eFam = ReadFamilyFromStyleName(aName);
+ SfxStyleSheetBase* pStyleBase = pStylePool->Find(aName,eFam);
+ SfxStyleSheet* pStyle = dynamic_cast<SfxStyleSheet*>( pStyleBase );
+ if (pStyle!=nullptr && pStyle!=GetStyleSheet()) {
+ aStyleSheets.insert(pStyle);
+ }
+ }
+ // now remove all superfluous stylesheets
+ sal_uInt16 nNum=GetBroadcasterCount();
+ while (nNum>0) {
+ nNum--;
+ SfxBroadcaster* pBroadcast=GetBroadcasterJOE(nNum);
+ SfxStyleSheet* pStyle=dynamic_cast<SfxStyleSheet*>( pBroadcast );
+ if (pStyle!=nullptr && pStyle!=GetStyleSheet()) { // special case for stylesheet of the object
+ if (aStyleSheets.find(pStyle)==aStyleSheets.end()) {
+ EndListening(*pStyle);
+ }
+ }
+ }
+ // and finally, merge all stylesheets that are contained in aStyles with previous broadcasters
+ for(SfxStyleSheet* pStyle : aStyleSheets) {
+ // let StartListening see for itself if there's already a listener registered
+ StartListening(*pStyle, DuplicateHandling::Prevent);
+ }
+}
+
+/** iterates over the paragraphs of a given SdrObject and removes all
+ hard set character attributes with the which ids contained in the
+ given vector
+*/
+void SdrTextObj::RemoveOutlinerCharacterAttribs( const std::vector<sal_uInt16>& rCharWhichIds )
+{
+ sal_Int32 nText = getTextCount();
+
+ while( --nText >= 0 )
+ {
+ SdrText* pText = getText( nText );
+ OutlinerParaObject* pOutlinerParaObject = pText ? pText->GetOutlinerParaObject() : nullptr;
+
+ if(pOutlinerParaObject)
+ {
+ Outliner* pOutliner = nullptr;
+
+ if( mpEditingOutliner || (pText == getActiveText()) )
+ pOutliner = mpEditingOutliner;
+
+ if(!pOutliner)
+ {
+ pOutliner = &ImpGetDrawOutliner();
+ pOutliner->SetText(*pOutlinerParaObject);
+ }
+
+ ESelection aSelAll( 0, 0, EE_PARA_ALL, EE_TEXTPOS_ALL );
+ for( const auto& rWhichId : rCharWhichIds )
+ {
+ pOutliner->RemoveAttribs( aSelAll, false, rWhichId );
+ }
+
+ if(!mpEditingOutliner || (pText != getActiveText()) )
+ {
+ const sal_Int32 nParaCount = pOutliner->GetParagraphCount();
+ std::optional<OutlinerParaObject> pTemp = pOutliner->CreateParaObject(0, nParaCount);
+ pOutliner->Clear();
+ NbcSetOutlinerParaObjectForText(std::move(pTemp), pText);
+ }
+ }
+ }
+}
+
+bool SdrTextObj::HasText() const
+{
+ if (mpEditingOutliner)
+ return HasTextImpl(mpEditingOutliner);
+
+ OutlinerParaObject* pOPO = GetOutlinerParaObject();
+
+ bool bHasText = false;
+ if( pOPO )
+ {
+ const EditTextObject& rETO = pOPO->GetTextObject();
+ sal_Int32 nParaCount = rETO.GetParagraphCount();
+
+ if( nParaCount > 0 )
+ bHasText = (nParaCount > 1) || (!rETO.GetText( 0 ).isEmpty());
+ }
+
+ return bHasText;
+}
+
+void SdrTextObj::AppendFamilyToStyleName(OUString& styleName, SfxStyleFamily family)
+{
+ OUStringBuffer aFam;
+ aFam.append(static_cast<sal_Int32>(family));
+ comphelper::string::padToLength(aFam, PADDING_LENGTH_FOR_STYLE_FAMILY , PADDING_CHARACTER_FOR_STYLE_FAMILY);
+
+ styleName += "|" + aFam;
+}
+
+SfxStyleFamily SdrTextObj::ReadFamilyFromStyleName(const OUString& styleName)
+{
+ std::u16string_view familyString = styleName.subView(styleName.getLength() - PADDING_LENGTH_FOR_STYLE_FAMILY);
+ familyString = comphelper::string::stripEnd(familyString, PADDING_CHARACTER_FOR_STYLE_FAMILY);
+ sal_uInt16 nFam = static_cast<sal_uInt16>(o3tl::toInt32(familyString));
+ assert(nFam != 0);
+ return static_cast<SfxStyleFamily>(nFam);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdotxdr.cxx b/svx/source/svdraw/svdotxdr.cxx
new file mode 100644
index 000000000..ad2f79933
--- /dev/null
+++ b/svx/source/svdraw/svdotxdr.cxx
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdotext.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svddrag.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdoashp.hxx>
+#include <tools/bigint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/ptrstyle.hxx>
+
+
+sal_uInt32 SdrTextObj::GetHdlCount() const
+{
+ return 8;
+}
+
+void SdrTextObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ for(sal_uInt32 nHdlNum=0; nHdlNum<8; ++nHdlNum)
+ {
+ Point aPnt;
+ SdrHdlKind eKind = SdrHdlKind::UpperLeft;
+ switch (nHdlNum) {
+ case 0: aPnt=maRect.TopLeft(); eKind=SdrHdlKind::UpperLeft; break;
+ case 1: aPnt=maRect.TopCenter(); eKind=SdrHdlKind::Upper; break;
+ case 2: aPnt=maRect.TopRight(); eKind=SdrHdlKind::UpperRight; break;
+ case 3: aPnt=maRect.LeftCenter(); eKind=SdrHdlKind::Left ; break;
+ case 4: aPnt=maRect.RightCenter(); eKind=SdrHdlKind::Right; break;
+ case 5: aPnt=maRect.BottomLeft(); eKind=SdrHdlKind::LowerLeft; break;
+ case 6: aPnt=maRect.BottomCenter(); eKind=SdrHdlKind::Lower; break;
+ case 7: aPnt=maRect.BottomRight(); eKind=SdrHdlKind::LowerRight; break;
+ }
+ if (maGeo.nShearAngle) ShearPoint(aPnt,maRect.TopLeft(),maGeo.mfTanShearAngle);
+ if (maGeo.nRotationAngle) RotatePoint(aPnt,maRect.TopLeft(),maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ std::unique_ptr<SdrHdl> pH(new SdrHdl(aPnt,eKind));
+ pH->SetObj(const_cast<SdrTextObj*>(this));
+ pH->SetRotationAngle(maGeo.nRotationAngle);
+ rHdlList.AddHdl(std::move(pH));
+ }
+}
+
+
+bool SdrTextObj::hasSpecialDrag() const
+{
+ return true;
+}
+
+tools::Rectangle SdrTextObj::ImpDragCalcRect(const SdrDragStat& rDrag) const
+{
+ tools::Rectangle aTmpRect(maRect);
+ const SdrHdl* pHdl=rDrag.GetHdl();
+ SdrHdlKind eHdl=pHdl==nullptr ? SdrHdlKind::Move : pHdl->GetKind();
+ bool bEcke=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::LowerLeft || eHdl==SdrHdlKind::LowerRight);
+ bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
+ bool bBigOrtho=bEcke && bOrtho && rDrag.GetView()->IsBigOrtho();
+ Point aPos(rDrag.GetNow());
+ // Unrotate:
+ if (maGeo.nRotationAngle) RotatePoint(aPos,aTmpRect.TopLeft(),-maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ // Unshear:
+ if (maGeo.nShearAngle) ShearPoint(aPos,aTmpRect.TopLeft(),-maGeo.mfTanShearAngle);
+
+ bool bLft=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::LowerLeft);
+ bool bRgt=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerRight);
+ bool bTop=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperLeft);
+ bool bBtm=(eHdl==SdrHdlKind::LowerRight || eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerLeft);
+ if (bLft) aTmpRect.SetLeft(aPos.X() );
+ if (bRgt) aTmpRect.SetRight(aPos.X() );
+ if (bTop) aTmpRect.SetTop(aPos.Y() );
+ if (bBtm) aTmpRect.SetBottom(aPos.Y() );
+ if (bOrtho) { // Ortho
+ tools::Long nWdt0=maRect.Right() -maRect.Left();
+ tools::Long nHgt0=maRect.Bottom()-maRect.Top();
+ tools::Long nXMul=aTmpRect.Right() -aTmpRect.Left();
+ tools::Long nYMul=aTmpRect.Bottom()-aTmpRect.Top();
+ tools::Long nXDiv=nWdt0;
+ tools::Long nYDiv=nHgt0;
+ bool bXNeg=(nXMul<0)!=(nXDiv<0);
+ bool bYNeg=(nYMul<0)!=(nYDiv<0);
+ nXMul=std::abs(nXMul);
+ nYMul=std::abs(nYMul);
+ nXDiv=std::abs(nXDiv);
+ nYDiv=std::abs(nYDiv);
+ Fraction aXFact(nXMul,nXDiv); // fractions for canceling
+ Fraction aYFact(nYMul,nYDiv); // and for comparing
+ nXMul=aXFact.GetNumerator();
+ nYMul=aYFact.GetNumerator();
+ nXDiv=aXFact.GetDenominator();
+ nYDiv=aYFact.GetDenominator();
+ if (bEcke) { // corner point handles
+ bool bUseX=(aXFact<aYFact) != bBigOrtho;
+ if (bUseX) {
+ tools::Long nNeed=tools::Long(BigInt(nHgt0)*BigInt(nXMul)/BigInt(nXDiv));
+ if (bYNeg) nNeed=-nNeed;
+ if (bTop) aTmpRect.SetTop(aTmpRect.Bottom()-nNeed );
+ if (bBtm) aTmpRect.SetBottom(aTmpRect.Top()+nNeed );
+ } else {
+ tools::Long nNeed=tools::Long(BigInt(nWdt0)*BigInt(nYMul)/BigInt(nYDiv));
+ if (bXNeg) nNeed=-nNeed;
+ if (bLft) aTmpRect.SetLeft(aTmpRect.Right()-nNeed );
+ if (bRgt) aTmpRect.SetRight(aTmpRect.Left()+nNeed );
+ }
+ } else { // apex handles
+ if ((bLft || bRgt) && nXDiv!=0) {
+ tools::Long nHgt0b=maRect.Bottom()-maRect.Top();
+ tools::Long nNeed=tools::Long(BigInt(nHgt0b)*BigInt(nXMul)/BigInt(nXDiv));
+ aTmpRect.AdjustTop( -((nNeed-nHgt0b)/2) );
+ aTmpRect.SetBottom(aTmpRect.Top()+nNeed );
+ }
+ if ((bTop || bBtm) && nYDiv!=0) {
+ tools::Long nWdt0b=maRect.Right()-maRect.Left();
+ tools::Long nNeed=tools::Long(BigInt(nWdt0b)*BigInt(nYMul)/BigInt(nYDiv));
+ aTmpRect.AdjustLeft( -((nNeed-nWdt0b)/2) );
+ aTmpRect.SetRight(aTmpRect.Left()+nNeed );
+ }
+ }
+ }
+ if (dynamic_cast<const SdrObjCustomShape*>(this) == nullptr) // not justifying when in CustomShapes, to be able to detect if a shape has to be mirrored
+ ImpJustifyRect(aTmpRect);
+ return aTmpRect;
+}
+
+
+// drag
+
+bool SdrTextObj::applySpecialDrag(SdrDragStat& rDrag)
+{
+ tools::Rectangle aNewRect(ImpDragCalcRect(rDrag));
+
+ if(aNewRect.TopLeft() != maRect.TopLeft() && (maGeo.nRotationAngle || maGeo.nShearAngle))
+ {
+ Point aNewPos(aNewRect.TopLeft());
+
+ if (maGeo.nShearAngle)
+ ShearPoint(aNewPos,maRect.TopLeft(),maGeo.mfTanShearAngle);
+
+ if (maGeo.nRotationAngle)
+ RotatePoint(aNewPos,maRect.TopLeft(),maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+
+ aNewRect.SetPos(aNewPos);
+ }
+
+ if (aNewRect != maRect)
+ {
+ NbcSetLogicRect(aNewRect);
+ }
+
+ return true;
+}
+
+OUString SdrTextObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
+{
+ return ImpGetDescriptionStr(STR_DragRectResize);
+}
+
+
+// Create
+
+bool SdrTextObj::BegCreate(SdrDragStat& rStat)
+{
+ rStat.SetOrtho4Possible();
+ tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
+ aRect1.Justify();
+ rStat.SetActionRect(aRect1);
+ maRect = aRect1;
+ return true;
+}
+
+bool SdrTextObj::MovCreate(SdrDragStat& rStat)
+{
+ tools::Rectangle aRect1;
+ rStat.TakeCreateRect(aRect1);
+ ImpJustifyRect(aRect1);
+ rStat.SetActionRect(aRect1);
+ maRect = aRect1; // for ObjName
+ SetBoundRectDirty();
+ m_bSnapRectDirty=true;
+ if (auto pRectObj = dynamic_cast<SdrRectObj *>(this)) {
+ pRectObj->SetXPolyDirty();
+ }
+ return true;
+}
+
+bool SdrTextObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ rStat.TakeCreateRect(maRect);
+ ImpJustifyRect(maRect);
+
+ AdaptTextMinSize();
+
+ SetBoundAndSnapRectsDirty();
+ if (auto pRectObj = dynamic_cast<SdrRectObj *>(this)) {
+ pRectObj->SetXPolyDirty();
+ }
+ return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
+}
+
+void SdrTextObj::BrkCreate(SdrDragStat& /*rStat*/)
+{
+}
+
+bool SdrTextObj::BckCreate(SdrDragStat& /*rStat*/)
+{
+ return true;
+}
+
+basegfx::B2DPolyPolygon SdrTextObj::TakeCreatePoly(const SdrDragStat& rDrag) const
+{
+ tools::Rectangle aRect1;
+ rDrag.TakeCreateRect(aRect1);
+ aRect1.Justify();
+
+ basegfx::B2DPolyPolygon aRetval;
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aRect1);
+ aRetval.append(basegfx::utils::createPolygonFromRect(aRange));
+ return aRetval;
+}
+
+PointerStyle SdrTextObj::GetCreatePointer() const
+{
+ if (IsTextFrame()) return PointerStyle::DrawText;
+ return PointerStyle::Cross;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdotxed.cxx b/svx/source/svdraw/svdotxed.cxx
new file mode 100644
index 000000000..96523d679
--- /dev/null
+++ b/svx/source/svdraw/svdotxed.cxx
@@ -0,0 +1,360 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdotext.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editstat.hxx>
+#include <svl/itemset.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/sdtfchim.hxx>
+#include <textchain.hxx>
+
+
+bool SdrTextObj::HasTextEdit() const
+{
+ // linked text objects may be changed (no automatic reload)
+ return true;
+}
+
+bool SdrTextObj::BegTextEdit(SdrOutliner& rOutl)
+{
+ if (mpEditingOutliner!=nullptr) return false; // Textedit might already run in another View!
+ mpEditingOutliner=&rOutl;
+
+ mbInEditMode = true;
+
+ OutlinerMode nOutlinerMode = OutlinerMode::OutlineObject;
+ if ( !IsOutlText() )
+ nOutlinerMode = OutlinerMode::TextObject;
+ rOutl.Init( nOutlinerMode );
+ rOutl.SetRefDevice(getSdrModelFromSdrObject().GetRefDevice());
+
+ bool bFitToSize(IsFitToSize());
+ bool bContourFrame=IsContourTextFrame();
+ ImpSetTextEditParams();
+
+ if (!bContourFrame) {
+ EEControlBits nStat=rOutl.GetControlWord();
+ nStat|=EEControlBits::AUTOPAGESIZE;
+ if (bFitToSize || IsAutoFit())
+ nStat|=EEControlBits::STRETCHING;
+ else
+ nStat&=~EEControlBits::STRETCHING;
+ rOutl.SetControlWord(nStat);
+ }
+
+ // disable AUTOPAGESIZE if IsChainable (might be required for overflow check)
+ if ( IsChainable() ) {
+ EEControlBits nStat1=rOutl.GetControlWord();
+ nStat1 &=~EEControlBits::AUTOPAGESIZE;
+ rOutl.SetControlWord(nStat1);
+ }
+
+
+ OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+ if(pOutlinerParaObject!=nullptr)
+ {
+ rOutl.SetText(*GetOutlinerParaObject());
+ rOutl.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue());
+ }
+
+ // if necessary, set frame attributes for the first (new) paragraph of the
+ // outliner
+ if( !HasTextImpl( &rOutl ) )
+ {
+ // Outliner has no text so we must set some
+ // empty text so the outliner initialise itself
+ rOutl.SetText( "", rOutl.GetParagraph( 0 ) );
+
+ if(GetStyleSheet())
+ rOutl.SetStyleSheet( 0, GetStyleSheet());
+
+ // When setting the "hard" attributes for first paragraph, the Parent
+ // pOutlAttr (i. e. the template) has to be removed temporarily. Else,
+ // at SetParaAttribs(), all attributes contained in the parent become
+ // attributed hard to the paragraph.
+ const SfxItemSet& rSet = GetObjectItemSet();
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aFilteredSet(*rSet.GetPool());
+ aFilteredSet.Put(rSet);
+ rOutl.SetParaAttribs(0, aFilteredSet);
+ }
+ if (bFitToSize)
+ {
+ tools::Rectangle aAnchorRect;
+ tools::Rectangle aTextRect;
+ TakeTextRect(rOutl, aTextRect, false,
+ &aAnchorRect);
+ Fraction aFitXCorrection(1,1);
+ ImpSetCharStretching(rOutl,aTextRect.GetSize(),aAnchorRect.GetSize(),aFitXCorrection);
+ }
+ else if (IsAutoFit())
+ {
+ ImpAutoFitText(rOutl);
+ }
+
+ if(pOutlinerParaObject)
+ {
+ if (maGeo.nRotationAngle || IsFontwork())
+ {
+ // only repaint here, no real objectchange
+ BroadcastObjectChange();
+ }
+ }
+
+ rOutl.UpdateFields();
+ rOutl.ClearModifyFlag();
+
+ return true;
+}
+
+void SdrTextObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
+{
+ bool bFitToSize(IsFitToSize());
+ Size aPaperMin,aPaperMax;
+ tools::Rectangle aViewInit;
+ TakeTextAnchorRect(aViewInit);
+ if (maGeo.nRotationAngle) {
+ Point aCenter(aViewInit.Center());
+ aCenter-=aViewInit.TopLeft();
+ Point aCenter0(aCenter);
+ RotatePoint(aCenter,Point(),maGeo.mfSinRotationAngle,maGeo.mfCosRotationAngle);
+ aCenter-=aCenter0;
+ aViewInit.Move(aCenter.X(),aCenter.Y());
+ }
+ Size aAnkSiz(aViewInit.GetSize());
+ aAnkSiz.AdjustWidth( -1 ); aAnkSiz.AdjustHeight( -1 ); // because GetSize() adds 1
+ Size aMaxSiz(1000000,1000000);
+ Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
+ if (aTmpSiz.Width()!=0) aMaxSiz.setWidth(aTmpSiz.Width() );
+ if (aTmpSiz.Height()!=0) aMaxSiz.setHeight(aTmpSiz.Height() );
+
+ // Done earlier since used in else tree below
+ SdrTextHorzAdjust eHAdj(GetTextHorizontalAdjust());
+ SdrTextVertAdjust eVAdj(GetTextVerticalAdjust());
+
+ if(IsTextFrame())
+ {
+ tools::Long nMinWdt=GetMinTextFrameWidth();
+ tools::Long nMinHgt=GetMinTextFrameHeight();
+ tools::Long nMaxWdt=GetMaxTextFrameWidth();
+ tools::Long nMaxHgt=GetMaxTextFrameHeight();
+ if (nMinWdt<1) nMinWdt=1;
+ if (nMinHgt<1) nMinHgt=1;
+ if (!bFitToSize) {
+ if (nMaxWdt==0 || nMaxWdt>aMaxSiz.Width()) nMaxWdt=aMaxSiz.Width();
+ if (nMaxHgt==0 || nMaxHgt>aMaxSiz.Height()) nMaxHgt=aMaxSiz.Height();
+
+ if (!IsAutoGrowWidth() )
+ {
+ nMinWdt = aAnkSiz.Width();
+ nMaxWdt = nMinWdt;
+ }
+
+ if (!IsAutoGrowHeight())
+ {
+ nMinHgt = aAnkSiz.Height();
+ nMaxHgt = nMinHgt;
+ }
+
+ SdrTextAniKind eAniKind=GetTextAniKind();
+ SdrTextAniDirection eAniDirection=GetTextAniDirection();
+
+ bool bInEditMode = IsInEditMode();
+
+ if (!bInEditMode && (eAniKind==SdrTextAniKind::Scroll || eAniKind==SdrTextAniKind::Alternate || eAniKind==SdrTextAniKind::Slide))
+ {
+ // ticker text uses an unlimited paper size
+ if (eAniDirection==SdrTextAniDirection::Left || eAniDirection==SdrTextAniDirection::Right) nMaxWdt=1000000;
+ if (eAniDirection==SdrTextAniDirection::Up || eAniDirection==SdrTextAniDirection::Down) nMaxHgt=1000000;
+ }
+
+ bool bChainedFrame = IsChainable();
+ // Might be required for overflow check working: do limit height to frame if box is chainable.
+ if (!bChainedFrame) {
+ // #i119885# Do not limit/force height to geometrical frame (vice versa for vertical writing)
+ if(IsVerticalWriting())
+ {
+ nMaxWdt = 1000000;
+ }
+ else
+ {
+ nMaxHgt = 1000000;
+ }
+ }
+
+ aPaperMax.setWidth(nMaxWdt );
+ aPaperMax.setHeight(nMaxHgt );
+ }
+ else
+ {
+ aPaperMax=aMaxSiz;
+ }
+ aPaperMin.setWidth(nMinWdt );
+ aPaperMin.setHeight(nMinHgt );
+ }
+ else
+ {
+ // aPaperMin needs to be set to object's size if full width is activated
+ // for hor or ver writing respectively
+ if((SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
+ || (SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting()))
+ {
+ aPaperMin = aAnkSiz;
+ }
+
+ aPaperMax=aMaxSiz;
+ }
+
+ if (pViewMin!=nullptr) {
+ *pViewMin=aViewInit;
+
+ tools::Long nXFree=aAnkSiz.Width()-aPaperMin.Width();
+ if (eHAdj==SDRTEXTHORZADJUST_LEFT) pViewMin->AdjustRight( -nXFree );
+ else if (eHAdj==SDRTEXTHORZADJUST_RIGHT) pViewMin->AdjustLeft(nXFree );
+ else { pViewMin->AdjustLeft(nXFree/2 ); pViewMin->SetRight(pViewMin->Left()+aPaperMin.Width() ); }
+
+ tools::Long nYFree=aAnkSiz.Height()-aPaperMin.Height();
+ if (eVAdj==SDRTEXTVERTADJUST_TOP) pViewMin->AdjustBottom( -nYFree );
+ else if (eVAdj==SDRTEXTVERTADJUST_BOTTOM) pViewMin->AdjustTop(nYFree );
+ else { pViewMin->AdjustTop(nYFree/2 ); pViewMin->SetBottom(pViewMin->Top()+aPaperMin.Height() ); }
+ }
+
+ // PaperSize should grow automatically in most cases
+ if(IsVerticalWriting())
+ aPaperMin.setWidth( 0 );
+ else
+ aPaperMin.setHeight( 0 );
+
+ if(eHAdj!=SDRTEXTHORZADJUST_BLOCK || bFitToSize) {
+ aPaperMin.setWidth(0 );
+ }
+
+ // For complete vertical adjustment support, set paper min height to 0, here.
+ if(SDRTEXTVERTADJUST_BLOCK != eVAdj || bFitToSize)
+ {
+ aPaperMin.setHeight( 0 );
+ }
+
+ if (pPaperMin!=nullptr) *pPaperMin=aPaperMin;
+ if (pPaperMax!=nullptr) *pPaperMax=aPaperMax;
+ if (pViewInit!=nullptr) *pViewInit=aViewInit;
+}
+
+void SdrTextObj::EndTextEdit(SdrOutliner& rOutl)
+{
+ if(rOutl.IsModified())
+ {
+
+ // to make the gray field background vanish again
+ rOutl.UpdateFields();
+
+ std::optional<OutlinerParaObject> pNewText = rOutl.CreateParaObject( 0, rOutl.GetParagraphCount() );
+
+ // need to end edit mode early since SetOutlinerParaObject already
+ // uses GetCurrentBoundRect() which needs to take the text into account
+ // to work correct
+ mbInEditMode = false;
+
+ // We don't want broadcasting if we are merely trying to move to next box (this prevents infinite loops)
+ if (IsChainable() && GetTextChain()->GetSwitchingToNextBox(this)) {
+ GetTextChain()->SetSwitchingToNextBox(this, false);
+ if( getActiveText() )
+ {
+ getActiveText()->SetOutlinerParaObject( std::move(pNewText) );
+ }
+ } else { // If we are not doing in-chaining switching just set the ParaObject
+ SetOutlinerParaObject(std::move(pNewText));
+ }
+ }
+
+ /* Chaining-related code */
+ rOutl.ClearOverflowingParaNum();
+
+ mpEditingOutliner = nullptr;
+ rOutl.Clear();
+ EEControlBits nStat = rOutl.GetControlWord();
+ nStat &= ~EEControlBits::AUTOPAGESIZE;
+ rOutl.SetControlWord(nStat);
+
+ mbInEditMode = false;
+}
+
+EEAnchorMode SdrTextObj::GetOutlinerViewAnchorMode() const
+{
+ SdrTextHorzAdjust eH=GetTextHorizontalAdjust();
+ SdrTextVertAdjust eV=GetTextVerticalAdjust();
+ EEAnchorMode eRet=EEAnchorMode::TopLeft;
+ if (IsContourTextFrame()) return eRet;
+ if (eH==SDRTEXTHORZADJUST_LEFT) {
+ if (eV==SDRTEXTVERTADJUST_TOP) {
+ eRet=EEAnchorMode::TopLeft;
+ } else if (eV==SDRTEXTVERTADJUST_BOTTOM) {
+ eRet=EEAnchorMode::BottomLeft;
+ } else {
+ eRet=EEAnchorMode::VCenterLeft;
+ }
+ } else if (eH==SDRTEXTHORZADJUST_RIGHT) {
+ if (eV==SDRTEXTVERTADJUST_TOP) {
+ eRet=EEAnchorMode::TopRight;
+ } else if (eV==SDRTEXTVERTADJUST_BOTTOM) {
+ eRet=EEAnchorMode::BottomRight;
+ } else {
+ eRet=EEAnchorMode::VCenterRight;
+ }
+ } else {
+ if (eV==SDRTEXTVERTADJUST_TOP) {
+ eRet=EEAnchorMode::TopHCenter;
+ } else if (eV==SDRTEXTVERTADJUST_BOTTOM) {
+ eRet=EEAnchorMode::BottomHCenter;
+ } else {
+ eRet=EEAnchorMode::VCenterHCenter;
+ }
+ }
+ return eRet;
+}
+
+void SdrTextObj::ImpSetTextEditParams() const
+{
+ if (mpEditingOutliner==nullptr)
+ return;
+
+ bool bUpdBuf=mpEditingOutliner->SetUpdateLayout(false);
+ Size aPaperMin;
+ Size aPaperMax;
+ tools::Rectangle aEditArea;
+ TakeTextEditArea(&aPaperMin,&aPaperMax,&aEditArea,nullptr);
+ bool bContourFrame=IsContourTextFrame();
+ mpEditingOutliner->SetMinAutoPaperSize(aPaperMin);
+ mpEditingOutliner->SetMaxAutoPaperSize(aPaperMax);
+ mpEditingOutliner->SetPaperSize(Size());
+ mpEditingOutliner->SetTextColumns(GetTextColumnsNumber(), GetTextColumnsSpacing());
+ if (bContourFrame) {
+ tools::Rectangle aAnchorRect;
+ TakeTextAnchorRect(aAnchorRect);
+ ImpSetContourPolygon(*mpEditingOutliner,aAnchorRect, true);
+ }
+ if (bUpdBuf) mpEditingOutliner->SetUpdateLayout(true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdotxfl.cxx b/svx/source/svdraw/svdotxfl.cxx
new file mode 100644
index 000000000..e2c7c7515
--- /dev/null
+++ b/svx/source/svdraw/svdotxfl.cxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdotext.hxx>
+
+bool SdrTextObj::CalcFieldValue(const SvxFieldItem& /*rField*/, sal_Int32 /*nPara*/, sal_uInt16 /*nPos*/,
+ bool /*bEdit*/, std::optional<Color>& /*rpTxtColor*/, std::optional<Color>& /*rpFldColor*/, OUString& /*rRet*/) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdotxln.cxx b/svx/source/svdraw/svdotxln.cxx
new file mode 100644
index 000000000..19953dcc6
--- /dev/null
+++ b/svx/source/svdraw/svdotxln.cxx
@@ -0,0 +1,277 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/processfactory.hxx>
+#include <osl/file.hxx>
+#include <osl/thread.h>
+#include <unotools/ucbstreamhelper.hxx>
+#include <ucbhelper/content.hxx>
+#include <unotools/datetime.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdmodel.hxx>
+#include <editeng/editdata.hxx>
+#include <sfx2/lnkbase.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/debug.hxx>
+#include <tools/tenccvt.hxx>
+#include <memory>
+
+class ImpSdrObjTextLink: public ::sfx2::SvBaseLink
+{
+ SdrTextObj* pSdrObj;
+
+public:
+ explicit ImpSdrObjTextLink( SdrTextObj* pObj1 )
+ : ::sfx2::SvBaseLink( ::SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SIMPLE_FILE ),
+ pSdrObj( pObj1 )
+ {}
+
+ virtual void Closed() override;
+ virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
+ const OUString& rMimeType, const css::uno::Any & rValue ) override;
+};
+
+void ImpSdrObjTextLink::Closed()
+{
+ if (pSdrObj )
+ {
+ // set pLink of the object to NULL, because we are destroying the link instance now
+ ImpSdrObjTextLinkUserData* pData=pSdrObj->GetLinkUserData();
+ if (pData!=nullptr) pData->mpLink = nullptr;
+ pSdrObj->ReleaseTextLink();
+ }
+ SvBaseLink::Closed();
+}
+
+
+::sfx2::SvBaseLink::UpdateResult ImpSdrObjTextLink::DataChanged(
+ const OUString& /*rMimeType*/, const css::uno::Any & /*rValue */)
+{
+ bool bForceReload = false;
+ SdrModel* pModel(pSdrObj ? &pSdrObj->getSdrModelFromSdrObject() : nullptr);
+ sfx2::LinkManager* pLinkManager(pModel ? pModel->GetLinkManager() : nullptr);
+
+ if( pLinkManager )
+ {
+ ImpSdrObjTextLinkUserData* pData=pSdrObj->GetLinkUserData();
+ if( pData )
+ {
+ OUString aFile;
+ OUString aFilter;
+ sfx2::LinkManager::GetDisplayNames( this, nullptr,&aFile, nullptr, &aFilter );
+
+ if( pData->maFileName != aFile ||
+ pData->maFilterName != aFilter )
+ {
+ pData->maFileName = aFile;
+ pData->maFilterName = aFilter;
+ pSdrObj->SetChanged();
+ bForceReload = true;
+ }
+ }
+ }
+ if (pSdrObj )
+ pSdrObj->ReloadLinkedText( bForceReload );
+
+ return SUCCESS;
+}
+
+
+ImpSdrObjTextLinkUserData::ImpSdrObjTextLinkUserData():
+ SdrObjUserData(SdrInventor::Default,SDRUSERDATA_OBJTEXTLINK),
+ maFileDate0( DateTime::EMPTY ),
+ meCharSet(RTL_TEXTENCODING_DONTKNOW)
+{
+}
+
+ImpSdrObjTextLinkUserData::~ImpSdrObjTextLinkUserData()
+{
+}
+
+std::unique_ptr<SdrObjUserData> ImpSdrObjTextLinkUserData::Clone(SdrObject* ) const
+{
+ ImpSdrObjTextLinkUserData* pData = new ImpSdrObjTextLinkUserData;
+ pData->maFileName = maFileName;
+ pData->maFilterName = maFilterName;
+ pData->maFileDate0 = maFileDate0;
+ pData->meCharSet = meCharSet;
+ pData->mpLink = nullptr;
+ return std::unique_ptr<SdrObjUserData>(pData);
+}
+
+
+void SdrTextObj::SetTextLink(const OUString& rFileName, const OUString& rFilterName)
+{
+ rtl_TextEncoding eCharSet = osl_getThreadTextEncoding();
+
+ ImpSdrObjTextLinkUserData* pData=GetLinkUserData();
+ if (pData!=nullptr) {
+ ReleaseTextLink();
+ }
+ pData=new ImpSdrObjTextLinkUserData;
+ pData->maFileName = rFileName;
+ pData->maFilterName = rFilterName;
+ pData->meCharSet = eCharSet;
+ AppendUserData(std::unique_ptr<SdrObjUserData>(pData));
+ ImpRegisterLink();
+}
+
+void SdrTextObj::ReleaseTextLink()
+{
+ ImpDeregisterLink();
+ sal_uInt16 nCount=GetUserDataCount();
+ for (sal_uInt16 nNum=nCount; nNum>0;) {
+ nNum--;
+ SdrObjUserData* pData=GetUserData(nNum);
+ if (pData->GetInventor()==SdrInventor::Default && pData->GetId()==SDRUSERDATA_OBJTEXTLINK) {
+ DeleteUserData(nNum);
+ }
+ }
+}
+
+bool SdrTextObj::ReloadLinkedText( bool bForceLoad)
+{
+ ImpSdrObjTextLinkUserData* pData = GetLinkUserData();
+ bool bRet = true;
+
+ if( pData )
+ {
+ DateTime aFileDT( DateTime::EMPTY );
+ bool bExists = true;
+
+ try
+ {
+ INetURLObject aURL( pData->maFileName );
+ DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+
+ ::ucbhelper::Content aCnt( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), css::uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ css::uno::Any aAny( aCnt.getPropertyValue("DateModified") );
+ css::util::DateTime aDateTime;
+
+ aAny >>= aDateTime;
+ ::utl::typeConvert( aDateTime, aFileDT );
+ }
+ catch( ... )
+ {
+ bExists = false;
+ }
+
+ if( bExists )
+ {
+ bool bLoad = false;
+ if( bForceLoad )
+ bLoad = true;
+ else
+ bLoad = ( aFileDT > pData->maFileDate0 );
+
+ if( bLoad )
+ {
+ bRet = LoadText( pData->maFileName, pData->meCharSet );
+ }
+
+ pData->maFileDate0 = aFileDT;
+ }
+ }
+
+ return bRet;
+}
+
+bool SdrTextObj::LoadText(const OUString& rFileName, rtl_TextEncoding eCharSet)
+{
+ INetURLObject aFileURL( rFileName );
+ bool bRet = false;
+
+ if( aFileURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ OUString aFileURLStr;
+
+ if( osl::FileBase::getFileURLFromSystemPath( rFileName, aFileURLStr ) == osl::FileBase::E_None )
+ aFileURL = INetURLObject( aFileURLStr );
+ else
+ aFileURL.SetSmartURL( rFileName );
+ }
+
+ DBG_ASSERT( aFileURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream( aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));
+
+ if( pIStm )
+ {
+ pIStm->SetStreamCharSet(GetSOLoadTextEncoding(eCharSet));
+
+ char cRTF[5];
+ cRTF[4] = 0;
+ pIStm->ReadBytes(cRTF, 5);
+
+ bool bRTF = cRTF[0] == '{' && cRTF[1] == '\\' && cRTF[2] == 'r' && cRTF[3] == 't' && cRTF[4] == 'f';
+
+ pIStm->Seek(0);
+
+ if( !pIStm->GetError() )
+ {
+ SetText( *pIStm, aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), bRTF ? EETextFormat::Rtf : EETextFormat::Text );
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+ImpSdrObjTextLinkUserData* SdrTextObj::GetLinkUserData() const
+{
+ sal_uInt16 nCount=GetUserDataCount();
+ for (sal_uInt16 nNum=nCount; nNum>0;) {
+ nNum--;
+ SdrObjUserData * pData=GetUserData(nNum);
+ if (pData->GetInventor() == SdrInventor::Default
+ && pData->GetId() == SDRUSERDATA_OBJTEXTLINK)
+ {
+ return static_cast<ImpSdrObjTextLinkUserData *>(pData);
+ }
+ }
+ return nullptr;
+}
+
+void SdrTextObj::ImpRegisterLink()
+{
+ ImpSdrObjTextLinkUserData* pData=GetLinkUserData();
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
+ if (pLinkManager!=nullptr && pData!=nullptr && pData->mpLink==nullptr) { // don't register twice
+ pData->mpLink = new ImpSdrObjTextLink(this);
+ pLinkManager->InsertFileLink(*pData->mpLink,sfx2::SvBaseLinkObjectType::ClientFile,pData->maFileName,
+ !pData->maFilterName.isEmpty() ?
+ &pData->maFilterName : nullptr);
+ }
+}
+
+void SdrTextObj::ImpDeregisterLink()
+{
+ ImpSdrObjTextLinkUserData* pData=GetLinkUserData();
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
+ if (pLinkManager!=nullptr && pData!=nullptr && pData->mpLink!=nullptr) { // don't register twice
+ // when doing Remove, *pLink is deleted implicitly
+ pLinkManager->Remove( pData->mpLink.get() );
+ pData->mpLink=nullptr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdotxtr.cxx b/svx/source/svdraw/svdotxtr.cxx
new file mode 100644
index 000000000..7da067468
--- /dev/null
+++ b/svx/source/svdraw/svdotxtr.cxx
@@ -0,0 +1,496 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdotext.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdmodel.hxx>
+#include <sdr/properties/itemsettools.hxx>
+#include <svx/sdr/properties/properties.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svl/itemset.hxx>
+#include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/sdshitm.hxx>
+
+using namespace com::sun::star;
+
+void SdrTextObj::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ if (maGeo.nRotationAngle || maGeo.nShearAngle)
+ {
+ // Either the rotation or shear angle exists.
+ tools::Rectangle aSR0(GetSnapRect());
+ tools::Long nWdt0=aSR0.Right()-aSR0.Left();
+ tools::Long nHgt0=aSR0.Bottom()-aSR0.Top();
+ tools::Long nWdt1=rRect.Right()-rRect.Left();
+ tools::Long nHgt1=rRect.Bottom()-rRect.Top();
+ SdrTextObj::NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
+ SdrTextObj::NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
+ }
+ else
+ {
+ // No rotation or shear.
+
+ maRect = rRect;
+ ImpJustifyRect(maRect);
+
+ AdaptTextMinSize();
+
+ ImpCheckShear();
+ SetBoundAndSnapRectsDirty();
+ }
+}
+
+const tools::Rectangle& SdrTextObj::GetLogicRect() const
+{
+ return maRect;
+}
+
+void SdrTextObj::NbcSetLogicRect(const tools::Rectangle& rRect)
+{
+ maRect = rRect;
+ ImpJustifyRect(maRect);
+
+ AdaptTextMinSize();
+
+ SetBoundAndSnapRectsDirty();
+}
+
+Degree100 SdrTextObj::GetRotateAngle() const
+{
+ return maGeo.nRotationAngle;
+}
+
+Degree100 SdrTextObj::GetShearAngle(bool /*bVertical*/) const
+{
+ return maGeo.nShearAngle;
+}
+
+void SdrTextObj::NbcMove(const Size& rSiz)
+{
+ maRect.Move(rSiz);
+ m_aOutRect.Move(rSiz);
+ maSnapRect.Move(rSiz);
+ SetBoundAndSnapRectsDirty(true);
+}
+
+void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ bool bNotSheared=maGeo.nShearAngle==0_deg100;
+ bool bRotate90=bNotSheared && maGeo.nRotationAngle.get() % 9000 ==0;
+ bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
+ bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
+ if (bXMirr || bYMirr) {
+ Point aRef1(GetSnapRect().Center());
+ if (bXMirr) {
+ Point aRef2(aRef1);
+ aRef2.AdjustY( 1 );
+ NbcMirrorGluePoints(aRef1,aRef2);
+ }
+ if (bYMirr) {
+ Point aRef2(aRef1);
+ aRef2.AdjustX( 1 );
+ NbcMirrorGluePoints(aRef1,aRef2);
+ }
+ }
+
+ if (maGeo.nRotationAngle==0_deg100 && maGeo.nShearAngle==0_deg100) {
+ ResizeRect(maRect,rRef,xFact,yFact);
+ if (bYMirr) {
+ maRect.Justify();
+ maRect.Move(maRect.Right()-maRect.Left(),maRect.Bottom()-maRect.Top());
+ maGeo.nRotationAngle=18000_deg100;
+ maGeo.RecalcSinCos();
+ }
+ }
+ else
+ {
+ tools::Polygon aPol(Rect2Poly(maRect,maGeo));
+
+ for(sal_uInt16 a(0); a < aPol.GetSize(); a++)
+ {
+ ResizePoint(aPol[a], rRef, xFact, yFact);
+ }
+
+ if(bXMirr != bYMirr)
+ {
+ // turn polygon and move it a little
+ tools::Polygon aPol0(aPol);
+
+ aPol[0] = aPol0[1];
+ aPol[1] = aPol0[0];
+ aPol[2] = aPol0[3];
+ aPol[3] = aPol0[2];
+ aPol[4] = aPol0[1];
+ }
+
+ Poly2Rect(aPol, maRect, maGeo);
+ }
+
+ if (bRotate90) {
+ bool bRota90=maGeo.nRotationAngle.get() % 9000 ==0;
+ if (!bRota90) { // there's seems to be a rounding error occurring: correct it
+ Degree100 a=NormAngle36000(maGeo.nRotationAngle);
+ if (a<4500_deg100) a=0_deg100;
+ else if (a<13500_deg100) a=9000_deg100;
+ else if (a<22500_deg100) a=18000_deg100;
+ else if (a<31500_deg100) a=27000_deg100;
+ else a=0_deg100;
+ maGeo.nRotationAngle=a;
+ maGeo.RecalcSinCos();
+ }
+ if (bNotSheared!=(maGeo.nShearAngle==0_deg100)) { // correct a rounding error occurring with Shear
+ maGeo.nShearAngle=0_deg100;
+ maGeo.RecalcTan();
+ }
+ }
+
+ ImpJustifyRect(maRect);
+
+ AdaptTextMinSize();
+
+ if(mbTextFrame && !getSdrModelFromSdrObject().IsPasteResize())
+ {
+ NbcAdjustTextFrameWidthAndHeight();
+ }
+
+ ImpCheckShear();
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrTextObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ SetGlueReallyAbsolute(true);
+ tools::Long dx=maRect.Right()-maRect.Left();
+ tools::Long dy=maRect.Bottom()-maRect.Top();
+ Point aP(maRect.TopLeft());
+ RotatePoint(aP,rRef,sn,cs);
+ maRect.SetLeft(aP.X() );
+ maRect.SetTop(aP.Y() );
+ maRect.SetRight(maRect.Left()+dx );
+ maRect.SetBottom(maRect.Top()+dy );
+ if (maGeo.nRotationAngle==0_deg100) {
+ maGeo.nRotationAngle=NormAngle36000(nAngle);
+ maGeo.mfSinRotationAngle=sn;
+ maGeo.mfCosRotationAngle=cs;
+ } else {
+ maGeo.nRotationAngle=NormAngle36000(maGeo.nRotationAngle+nAngle);
+ maGeo.RecalcSinCos();
+ }
+ SetBoundAndSnapRectsDirty();
+ NbcRotateGluePoints(rRef,nAngle,sn,cs);
+ SetGlueReallyAbsolute(false);
+}
+
+void SdrTextObj::NbcShear(const Point& rRef, Degree100 /*nAngle*/, double tn, bool bVShear)
+{
+ SetGlueReallyAbsolute(true);
+
+ // when this is a SdrPathObj, aRect may be uninitialized
+ tools::Polygon aPol(Rect2Poly(maRect.IsEmpty() ? GetSnapRect() : maRect, maGeo));
+
+ sal_uInt16 nPointCount=aPol.GetSize();
+ for (sal_uInt16 i=0; i<nPointCount; i++) {
+ ShearPoint(aPol[i],rRef,tn,bVShear);
+ }
+ Poly2Rect(aPol,maRect,maGeo);
+ ImpJustifyRect(maRect);
+ if (mbTextFrame) {
+ NbcAdjustTextFrameWidthAndHeight();
+ }
+ ImpCheckShear();
+ SetBoundAndSnapRectsDirty();
+ NbcShearGluePoints(rRef,tn,bVShear);
+ SetGlueReallyAbsolute(false);
+}
+
+void SdrTextObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ SetGlueReallyAbsolute(true);
+ bool bNotSheared=maGeo.nShearAngle==0_deg100;
+ bool bRotate90 = false;
+ if (bNotSheared &&
+ (rRef1.X()==rRef2.X() || rRef1.Y()==rRef2.Y() ||
+ std::abs(rRef1.X()-rRef2.X())==std::abs(rRef1.Y()-rRef2.Y()))) {
+ bRotate90=maGeo.nRotationAngle.get() % 9000 ==0;
+ }
+ tools::Polygon aPol(Rect2Poly(maRect,maGeo));
+ sal_uInt16 i;
+ sal_uInt16 nPointCount=aPol.GetSize();
+ for (i=0; i<nPointCount; i++) {
+ MirrorPoint(aPol[i],rRef1,rRef2);
+ }
+ // turn polygon and move it a little
+ tools::Polygon aPol0(aPol);
+ aPol[0]=aPol0[1];
+ aPol[1]=aPol0[0];
+ aPol[2]=aPol0[3];
+ aPol[3]=aPol0[2];
+ aPol[4]=aPol0[1];
+ Poly2Rect(aPol,maRect,maGeo);
+
+ if (bRotate90) {
+ bool bRota90=maGeo.nRotationAngle.get() % 9000 ==0;
+ if (bRotate90 && !bRota90) { // there's seems to be a rounding error occurring: correct it
+ Degree100 a=NormAngle36000(maGeo.nRotationAngle);
+ if (a<4500_deg100) a=0_deg100;
+ else if (a<13500_deg100) a=9000_deg100;
+ else if (a<22500_deg100) a=18000_deg100;
+ else if (a<31500_deg100) a=27000_deg100;
+ else a=0_deg100;
+ maGeo.nRotationAngle=a;
+ maGeo.RecalcSinCos();
+ }
+ }
+ if (bNotSheared!=(maGeo.nShearAngle==0_deg100)) { // correct a rounding error occurring with Shear
+ maGeo.nShearAngle=0_deg100;
+ maGeo.RecalcTan();
+ }
+
+ ImpJustifyRect(maRect);
+ if (mbTextFrame) {
+ NbcAdjustTextFrameWidthAndHeight();
+ }
+ ImpCheckShear();
+ SetBoundAndSnapRectsDirty();
+ NbcMirrorGluePoints(rRef1,rRef2);
+ SetGlueReallyAbsolute(false);
+}
+
+
+SdrObjectUniquePtr SdrTextObj::ImpConvertContainedTextToSdrPathObjs(bool bToPoly) const
+{
+ SdrObjectUniquePtr pRetval;
+
+ if(!ImpCanConvTextToCurve())
+ {
+ // suppress HelpTexts from PresObj's
+ return nullptr;
+ }
+
+ // create an extractor with neutral ViewInformation
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
+
+ // extract text as polygons
+ GetViewContact().getViewIndependentPrimitive2DContainer(aExtractor);
+
+ // get results
+ const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
+ const sal_uInt32 nResultCount(rResult.size());
+
+ if(nResultCount)
+ {
+ // prepare own target
+ SdrObjGroup* pGroup = new SdrObjGroup(getSdrModelFromSdrObject());
+ SdrObjList* pObjectList = pGroup->GetSubList();
+
+ // process results
+ for(sal_uInt32 a(0); a < nResultCount; a++)
+ {
+ const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a];
+ basegfx::B2DPolyPolygon aPolyPolygon(rCandidate.getB2DPolyPolygon());
+
+ if(aPolyPolygon.count())
+ {
+ // take care of wanted polygon type
+ if(bToPoly)
+ {
+ if(aPolyPolygon.areControlPointsUsed())
+ {
+ aPolyPolygon = basegfx::utils::adaptiveSubdivideByAngle(aPolyPolygon);
+ }
+ }
+ else
+ {
+ if(!aPolyPolygon.areControlPointsUsed())
+ {
+ aPolyPolygon = basegfx::utils::expandToCurve(aPolyPolygon);
+ }
+ }
+
+ // create ItemSet with object attributes
+ SfxItemSet aAttributeSet(GetObjectItemSet());
+ SdrPathObj* pPathObj = nullptr;
+
+ // always clear objectshadow; this is included in the extraction
+ aAttributeSet.Put(makeSdrShadowItem(false));
+
+ if(rCandidate.getIsFilled())
+ {
+ // set needed items
+ aAttributeSet.Put(XFillColorItem(OUString(), Color(rCandidate.getBColor())));
+ aAttributeSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ aAttributeSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+
+ // create filled SdrPathObj
+ pPathObj = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathFill,
+ aPolyPolygon);
+ }
+ else
+ {
+ // set needed items
+ aAttributeSet.Put(XLineColorItem(OUString(), Color(rCandidate.getBColor())));
+ aAttributeSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
+ aAttributeSet.Put(XLineWidthItem(0));
+ aAttributeSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+
+ // create line SdrPathObj
+ pPathObj = new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ SdrObjKind::PathLine,
+ aPolyPolygon);
+ }
+
+ // copy basic information from original
+ pPathObj->ImpSetAnchorPos(GetAnchorPos());
+ pPathObj->NbcSetLayer(GetLayer());
+ pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
+
+ // apply prepared ItemSet and add to target
+ pPathObj->SetMergedItemSet(aAttributeSet);
+ pObjectList->InsertObject(pPathObj);
+ }
+ }
+
+ // postprocess; if no result and/or only one object, simplify
+ if(!pObjectList->GetObjCount())
+ {
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pGroup);
+ SdrObject::Free(pTemp);
+ }
+ else if(1 == pObjectList->GetObjCount())
+ {
+ pRetval.reset(pObjectList->RemoveObject(0));
+
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pGroup);
+ SdrObject::Free(pTemp);
+ }
+ else
+ {
+ pRetval.reset(pGroup);
+ }
+ }
+
+ return pRetval;
+}
+
+
+SdrObjectUniquePtr SdrTextObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
+{
+ if(bAddText)
+ {
+ return ImpConvertContainedTextToSdrPathObjs(!bBezier);
+ }
+
+ return nullptr;
+}
+
+bool SdrTextObj::ImpCanConvTextToCurve() const
+{
+ return !IsOutlText();
+}
+
+SdrPathObjUniquePtr SdrTextObj::ImpConvertMakeObj(const basegfx::B2DPolyPolygon& rPolyPolygon, bool bClosed, bool bBezier) const
+{
+ SdrObjKind ePathKind = bClosed ? SdrObjKind::PathFill : SdrObjKind::PathLine;
+ basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPolygon);
+
+ // #i37011#
+ if(!bBezier)
+ {
+ aB2DPolyPolygon = basegfx::utils::adaptiveSubdivideByAngle(aB2DPolyPolygon);
+ ePathKind = bClosed ? SdrObjKind::Polygon : SdrObjKind::PolyLine;
+ }
+
+ SdrPathObjUniquePtr pPathObj(new SdrPathObj(
+ getSdrModelFromSdrObject(),
+ ePathKind,
+ aB2DPolyPolygon));
+
+ if(bBezier)
+ {
+ // create bezier curves
+ pPathObj->SetPathPoly(basegfx::utils::expandToCurve(pPathObj->GetPathPoly()));
+ }
+
+ pPathObj->ImpSetAnchorPos(m_aAnchor);
+ pPathObj->NbcSetLayer(GetLayer());
+ sdr::properties::ItemChangeBroadcaster aC(*pPathObj);
+ pPathObj->ClearMergedItem();
+ pPathObj->SetMergedItemSet(GetObjectItemSet());
+ pPathObj->GetProperties().BroadcastItemChange(aC);
+ pPathObj->NbcSetStyleSheet(GetStyleSheet(), true);
+
+ return pPathObj;
+}
+
+SdrObjectUniquePtr SdrTextObj::ImpConvertAddText(SdrObjectUniquePtr pObj, bool bBezier) const
+{
+ if(!ImpCanConvTextToCurve())
+ {
+ return pObj;
+ }
+
+ SdrObjectUniquePtr pText = ImpConvertContainedTextToSdrPathObjs(!bBezier);
+
+ if(!pText)
+ {
+ return pObj;
+ }
+
+ if(!pObj)
+ {
+ return pText;
+ }
+
+ if(pText->IsGroupObject())
+ {
+ // is already group object, add partial shape in front
+ SdrObjList* pOL=pText->GetSubList();
+ pOL->InsertObject(pObj.release(),0);
+
+ return pText;
+ }
+ else
+ {
+ // not yet a group, create one and add partial and new shapes
+ std::unique_ptr<SdrObjGroup, SdrObjectFreeOp> pGrp(new SdrObjGroup(getSdrModelFromSdrObject()));
+ SdrObjList* pOL=pGrp->GetSubList();
+ pOL->InsertObject(pObj.release());
+ pOL->InsertObject(pText.release());
+
+ return pGrp;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdouno.cxx b/svx/source/svdraw/svdouno.cxx
new file mode 100644
index 000000000..4f7066726
--- /dev/null
+++ b/svx/source/svdraw/svdouno.cxx
@@ -0,0 +1,502 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofunocontrol.hxx>
+#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/processfactory.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdview.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdviter.hxx>
+#include <rtl/ref.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/debug.hxx>
+#include <o3tl/sorted_vector.hxx>
+
+using namespace ::com::sun::star;
+using namespace sdr::contact;
+
+
+// Defines
+
+
+// Helper class SdrControlEventListenerImpl
+
+#include <com/sun/star/lang/XEventListener.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+
+class SdrControlEventListenerImpl : public ::cppu::WeakImplHelper< css::lang::XEventListener >
+{
+protected:
+ SdrUnoObj* pObj;
+
+public:
+ explicit SdrControlEventListenerImpl(SdrUnoObj* _pObj)
+ : pObj(_pObj)
+ {}
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ void StopListening(const uno::Reference< lang::XComponent >& xComp);
+ void StartListening(const uno::Reference< lang::XComponent >& xComp);
+};
+
+// XEventListener
+void SAL_CALL SdrControlEventListenerImpl::disposing( const css::lang::EventObject& /*Source*/)
+{
+ if (pObj)
+ {
+ pObj->xUnoControlModel = nullptr;
+ }
+}
+
+void SdrControlEventListenerImpl::StopListening(const uno::Reference< lang::XComponent >& xComp)
+{
+ if (xComp.is())
+ xComp->removeEventListener(this);
+}
+
+void SdrControlEventListenerImpl::StartListening(const uno::Reference< lang::XComponent >& xComp)
+{
+ if (xComp.is())
+ xComp->addEventListener(this);
+}
+
+
+struct SdrUnoObjDataHolder
+{
+ mutable ::rtl::Reference< SdrControlEventListenerImpl >
+ pEventListener;
+};
+
+
+namespace
+{
+ void lcl_ensureControlVisibility( SdrView const * _pView, const SdrUnoObj* _pObject, bool _bVisible )
+ {
+ OSL_PRECOND( _pObject, "lcl_ensureControlVisibility: no object -> no survival!" );
+
+ SdrPageView* pPageView = _pView ? _pView->GetSdrPageView() : nullptr;
+ DBG_ASSERT( pPageView, "lcl_ensureControlVisibility: no view found!" );
+ if ( !pPageView )
+ return;
+
+ ViewContact& rUnoControlContact( _pObject->GetViewContact() );
+
+ for ( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); ++i )
+ {
+ SdrPageWindow* pPageWindow = pPageView->GetPageWindow( i );
+ DBG_ASSERT( pPageWindow, "lcl_ensureControlVisibility: invalid PageViewWindow!" );
+ if ( !pPageWindow )
+ continue;
+
+ if ( !pPageWindow->HasObjectContact() )
+ continue;
+
+ ObjectContact& rPageViewContact( pPageWindow->GetObjectContact() );
+ const ViewObjectContact& rViewObjectContact( rUnoControlContact.GetViewObjectContact( rPageViewContact ) );
+ const ViewObjectContactOfUnoControl* pUnoControlContact = dynamic_cast< const ViewObjectContactOfUnoControl* >( &rViewObjectContact );
+ DBG_ASSERT( pUnoControlContact, "lcl_ensureControlVisibility: wrong ViewObjectContact type!" );
+ if ( !pUnoControlContact )
+ continue;
+
+ pUnoControlContact->ensureControlVisibility( _bVisible );
+ }
+ }
+}
+
+SdrUnoObj::SdrUnoObj(
+ SdrModel& rSdrModel,
+ const OUString& rModelName)
+: SdrRectObj(rSdrModel),
+ m_pImpl( new SdrUnoObjDataHolder )
+{
+ m_bIsUnoObj = true;
+
+ m_pImpl->pEventListener = new SdrControlEventListenerImpl(this);
+
+ // only an owner may create independently
+ if (!rModelName.isEmpty())
+ CreateUnoControlModel(rModelName);
+}
+
+SdrUnoObj::SdrUnoObj( SdrModel& rSdrModel, SdrUnoObj const & rSource)
+: SdrRectObj(rSdrModel, rSource),
+ m_pImpl( new SdrUnoObjDataHolder )
+{
+ m_bIsUnoObj = true;
+
+ m_pImpl->pEventListener = new SdrControlEventListenerImpl(this);
+
+ aUnoControlModelTypeName = rSource.aUnoControlModelTypeName;
+ aUnoControlTypeName = rSource.aUnoControlTypeName;
+
+ // copy the uno control model
+ const uno::Reference< awt::XControlModel > xSourceControlModel = rSource.GetUnoControlModel();
+ if ( xSourceControlModel.is() )
+ {
+ try
+ {
+ uno::Reference< util::XCloneable > xClone( xSourceControlModel, uno::UNO_QUERY_THROW );
+ xUnoControlModel.set( xClone->createClone(), uno::UNO_QUERY_THROW );
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+ // get service name of the control from the control model
+ uno::Reference< beans::XPropertySet > xSet(xUnoControlModel, uno::UNO_QUERY);
+ if (xSet.is())
+ {
+ uno::Any aValue( xSet->getPropertyValue("DefaultControl") );
+ OUString aStr;
+
+ if( aValue >>= aStr )
+ aUnoControlTypeName = aStr;
+ }
+
+ uno::Reference< lang::XComponent > xComp(xUnoControlModel, uno::UNO_QUERY);
+ if (xComp.is())
+ m_pImpl->pEventListener->StartListening(xComp);
+}
+
+SdrUnoObj::SdrUnoObj(
+ SdrModel& rSdrModel,
+ const OUString& rModelName,
+ const uno::Reference< lang::XMultiServiceFactory >& rxSFac)
+: SdrRectObj(rSdrModel),
+ m_pImpl( new SdrUnoObjDataHolder )
+{
+ m_bIsUnoObj = true;
+
+ m_pImpl->pEventListener = new SdrControlEventListenerImpl(this);
+
+ // only an owner may create independently
+ if (!rModelName.isEmpty())
+ CreateUnoControlModel(rModelName,rxSFac);
+}
+
+SdrUnoObj::~SdrUnoObj()
+{
+ try
+ {
+ // clean up the control model
+ uno::Reference< lang::XComponent > xComp(xUnoControlModel, uno::UNO_QUERY);
+ if (xComp.is())
+ {
+ // is the control model owned by its environment?
+ uno::Reference< container::XChild > xContent(xUnoControlModel, uno::UNO_QUERY);
+ if (xContent.is() && !xContent->getParent().is())
+ xComp->dispose();
+ else
+ m_pImpl->pEventListener->StopListening(xComp);
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "SdrUnoObj::~SdrUnoObj" );
+ }
+}
+
+void SdrUnoObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bRotateFreeAllowed = false;
+ rInfo.bRotate90Allowed = false;
+ rInfo.bMirrorFreeAllowed = false;
+ rInfo.bMirror45Allowed = false;
+ rInfo.bMirror90Allowed = false;
+ rInfo.bTransparenceAllowed = false;
+ rInfo.bShearAllowed = false;
+ rInfo.bEdgeRadiusAllowed = false;
+ rInfo.bNoOrthoDesired = false;
+ rInfo.bCanConvToPath = false;
+ rInfo.bCanConvToPoly = false;
+ rInfo.bCanConvToPathLineToArea = false;
+ rInfo.bCanConvToPolyLineToArea = false;
+ rInfo.bCanConvToContour = false;
+}
+
+SdrObjKind SdrUnoObj::GetObjIdentifier() const
+{
+ return SdrObjKind::UNO;
+}
+
+void SdrUnoObj::SetContextWritingMode( const sal_Int16 _nContextWritingMode )
+{
+ try
+ {
+ uno::Reference< beans::XPropertySet > xModelProperties( GetUnoControlModel(), uno::UNO_QUERY_THROW );
+ xModelProperties->setPropertyValue( "ContextWritingMode", uno::Any( _nContextWritingMode ) );
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+}
+
+OUString SdrUnoObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulUno));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+OUString SdrUnoObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralUno);
+}
+
+SdrUnoObj* SdrUnoObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrUnoObj(rTargetModel, *this);
+}
+
+void SdrUnoObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ SdrRectObj::NbcResize(rRef,xFact,yFact);
+
+ if (maGeo.nShearAngle==0_deg100 && maGeo.nRotationAngle==0_deg100)
+ return;
+
+ // small correctors
+ if (maGeo.nRotationAngle>=9000_deg100 && maGeo.nRotationAngle<27000_deg100)
+ {
+ maRect.Move(maRect.Left()-maRect.Right(),maRect.Top()-maRect.Bottom());
+ }
+
+ maGeo.nRotationAngle = 0_deg100;
+ maGeo.nShearAngle = 0_deg100;
+ maGeo.mfSinRotationAngle = 0.0;
+ maGeo.mfCosRotationAngle = 1.0;
+ maGeo.mfTanShearAngle = 0.0;
+ SetBoundAndSnapRectsDirty();
+}
+
+
+bool SdrUnoObj::hasSpecialDrag() const
+{
+ // no special drag; we have no rounding rect and
+ // do want frame handles
+ return false;
+}
+
+void SdrUnoObj::NbcSetLayer( SdrLayerID _nLayer )
+{
+ if ( GetLayer() == _nLayer )
+ { // redundant call -> not interested in doing anything here
+ SdrRectObj::NbcSetLayer( _nLayer );
+ return;
+ }
+
+ // we need some special handling here in case we're moved from an invisible layer
+ // to a visible one, or vice versa
+ // (relative to a layer. Remember that the visibility of a layer is a view attribute
+ // - the same layer can be visible in one view, and invisible in another view, at the
+ // same time)
+
+ // collect all views in which our old layer is visible
+ o3tl::sorted_vector< SdrView* > aPreviouslyVisible;
+
+ {
+ SdrViewIter aIter( this );
+ for ( SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView() )
+ aPreviouslyVisible.insert( pView );
+ }
+
+ SdrRectObj::NbcSetLayer( _nLayer );
+
+ // collect all views in which our new layer is visible
+ o3tl::sorted_vector< SdrView* > aNewlyVisible;
+
+ {
+ SdrViewIter aIter( this );
+ for ( SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView() )
+ {
+ if ( aPreviouslyVisible.erase(pView) == 0 )
+ {
+ // in pView, we were visible _before_ the layer change, and are
+ // _not_ visible after the layer change
+ // => remember this view, as our visibility there changed
+ aNewlyVisible.insert( pView );
+ }
+ }
+ }
+
+ // now aPreviouslyVisible contains all views where we became invisible
+ for (const auto& rpView : aPreviouslyVisible)
+ {
+ lcl_ensureControlVisibility( rpView, this, false );
+ }
+
+ // and aNewlyVisible all views where we became visible
+ for (const auto& rpView : aNewlyVisible)
+ {
+ lcl_ensureControlVisibility( rpView, this, true );
+ }
+}
+
+void SdrUnoObj::CreateUnoControlModel(const OUString& rModelName)
+{
+ DBG_ASSERT(!xUnoControlModel.is(), "model already exists");
+
+ aUnoControlModelTypeName = rModelName;
+
+ uno::Reference< awt::XControlModel > xModel;
+ uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ if (!aUnoControlModelTypeName.isEmpty() )
+ {
+ xModel.set(xContext->getServiceManager()->createInstanceWithContext(
+ aUnoControlModelTypeName, xContext), uno::UNO_QUERY);
+
+ if (xModel.is())
+ SetChanged();
+ }
+
+ SetUnoControlModel(xModel);
+}
+
+void SdrUnoObj::CreateUnoControlModel(const OUString& rModelName,
+ const uno::Reference< lang::XMultiServiceFactory >& rxSFac)
+{
+ DBG_ASSERT(!xUnoControlModel.is(), "model already exists");
+
+ aUnoControlModelTypeName = rModelName;
+
+ uno::Reference< awt::XControlModel > xModel;
+ if (!aUnoControlModelTypeName.isEmpty() && rxSFac.is() )
+ {
+ xModel.set(rxSFac->createInstance(aUnoControlModelTypeName), uno::UNO_QUERY);
+
+ if (xModel.is())
+ SetChanged();
+ }
+
+ SetUnoControlModel(xModel);
+}
+
+void SdrUnoObj::SetUnoControlModel( const uno::Reference< awt::XControlModel >& xModel)
+{
+ if (xUnoControlModel.is())
+ {
+ uno::Reference< lang::XComponent > xComp(xUnoControlModel, uno::UNO_QUERY);
+ if (xComp.is())
+ m_pImpl->pEventListener->StopListening(xComp);
+ }
+
+ xUnoControlModel = xModel;
+
+ // control model has to contain service name of the control
+ if (xUnoControlModel.is())
+ {
+ uno::Reference< beans::XPropertySet > xSet(xUnoControlModel, uno::UNO_QUERY);
+ if (xSet.is())
+ {
+ uno::Any aValue( xSet->getPropertyValue("DefaultControl") );
+ OUString aStr;
+ if( aValue >>= aStr )
+ aUnoControlTypeName = aStr;
+ }
+
+ uno::Reference< lang::XComponent > xComp(xUnoControlModel, uno::UNO_QUERY);
+ if (xComp.is())
+ m_pImpl->pEventListener->StartListening(xComp);
+ }
+
+ // invalidate all ViewObject contacts
+ ViewContactOfUnoControl* pVC = nullptr;
+ if ( impl_getViewContact( pVC ) )
+ {
+ // flushViewObjectContacts() removes all existing VOCs for the local DrawHierarchy. This
+ // is always allowed since they will be re-created on demand (and with the changed model)
+ GetViewContact().flushViewObjectContacts();
+ }
+}
+
+
+uno::Reference< awt::XControl > SdrUnoObj::GetUnoControl(const SdrView& _rView, const OutputDevice& _rOut) const
+{
+ uno::Reference< awt::XControl > xControl;
+
+ SdrPageView* pPageView = _rView.GetSdrPageView();
+ OSL_ENSURE( pPageView && getSdrPageFromSdrObject() == pPageView->GetPage(), "SdrUnoObj::GetUnoControl: This object is not displayed in that particular view!" );
+ if ( !pPageView || getSdrPageFromSdrObject() != pPageView->GetPage() )
+ return nullptr;
+
+ SdrPageWindow* pPageWindow = pPageView->FindPageWindow( _rOut );
+ OSL_ENSURE( pPageWindow, "SdrUnoObj::GetUnoControl: did not find my SdrPageWindow!" );
+ if ( !pPageWindow )
+ return nullptr;
+
+ ViewObjectContact& rViewObjectContact( GetViewContact().GetViewObjectContact( pPageWindow->GetObjectContact() ) );
+ ViewObjectContactOfUnoControl* pUnoContact = dynamic_cast< ViewObjectContactOfUnoControl* >( &rViewObjectContact );
+ OSL_ENSURE( pUnoContact, "SdrUnoObj::GetUnoControl: wrong contact type!" );
+ if ( pUnoContact )
+ xControl = pUnoContact->getControl();
+
+ return xControl;
+}
+
+
+uno::Reference< awt::XControl > SdrUnoObj::GetTemporaryControlForWindow(
+ const vcl::Window& _rWindow, uno::Reference< awt::XControlContainer >& _inout_ControlContainer ) const
+{
+ uno::Reference< awt::XControl > xControl;
+
+ ViewContactOfUnoControl* pVC = nullptr;
+ if ( impl_getViewContact( pVC ) )
+ xControl = pVC->getTemporaryControlForWindow( _rWindow, _inout_ControlContainer );
+
+ return xControl;
+}
+
+
+bool SdrUnoObj::impl_getViewContact( ViewContactOfUnoControl*& _out_rpContact ) const
+{
+ ViewContact& rViewContact( GetViewContact() );
+ _out_rpContact = dynamic_cast< ViewContactOfUnoControl* >( &rViewContact );
+ DBG_ASSERT( _out_rpContact, "SdrUnoObj::impl_getViewContact: could not find my ViewContact!" );
+ return ( _out_rpContact != nullptr );
+}
+
+
+std::unique_ptr<sdr::contact::ViewContact> SdrUnoObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfUnoControl>( *this );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdoutl.cxx b/svx/source/svdraw/svdoutl.cxx
new file mode 100644
index 000000000..3737b1fdf
--- /dev/null
+++ b/svx/source/svdraw/svdoutl.cxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdoutl.hxx>
+#include <editeng/outliner.hxx>
+#include <svx/svdotext.hxx>
+#include <editeng/editstat.hxx>
+#include <svl/itempool.hxx>
+#include <editeng/editview.hxx>
+
+
+SdrOutliner::SdrOutliner( SfxItemPool* pItemPool, OutlinerMode nMode )
+: Outliner( pItemPool, nMode ),
+ mpVisualizedPage(nullptr)
+{
+}
+
+
+SdrOutliner::~SdrOutliner()
+{
+}
+
+
+void SdrOutliner::SetTextObj( const SdrTextObj* pObj )
+{
+ if( pObj && pObj != mxWeakTextObj.get() )
+ {
+ SetUpdateLayout(false);
+ OutlinerMode nOutlinerMode2 = OutlinerMode::OutlineObject;
+ if ( !pObj->IsOutlText() )
+ nOutlinerMode2 = OutlinerMode::TextObject;
+ Init( nOutlinerMode2 );
+
+ SetGlobalCharStretching();
+
+ EEControlBits nStat = GetControlWord();
+ nStat &= ~EEControlBits( EEControlBits::STRETCHING | EEControlBits::AUTOPAGESIZE );
+ SetControlWord(nStat);
+
+ Size aMaxSize( 100000,100000 );
+ SetMinAutoPaperSize( Size() );
+ SetMaxAutoPaperSize( aMaxSize );
+ SetPaperSize( aMaxSize );
+ SetTextColumns(pObj->GetTextColumnsNumber(), pObj->GetTextColumnsSpacing());
+ ClearPolygon();
+ }
+
+ mxWeakTextObj.reset( const_cast< SdrTextObj* >(pObj) );
+}
+
+void SdrOutliner::SetTextObjNoInit( const SdrTextObj* pObj )
+{
+ mxWeakTextObj.reset( const_cast< SdrTextObj* >(pObj) );
+}
+
+OUString SdrOutliner::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos,
+ std::optional<Color>& rpTxtColor, std::optional<Color>& rpFldColor)
+{
+ bool bOk = false;
+ OUString aRet;
+
+ if(mxWeakTextObj.is())
+ bOk = mxWeakTextObj->CalcFieldValue(rField, nPara, nPos, false, rpTxtColor, rpFldColor, aRet);
+
+ if (!bOk)
+ aRet = Outliner::CalcFieldValue(rField, nPara, nPos, rpTxtColor, rpFldColor);
+
+ return aRet;
+}
+
+const SdrTextObj* SdrOutliner::GetTextObj() const
+{
+ return mxWeakTextObj.get();
+}
+
+bool SdrOutliner::hasEditViewCallbacks() const
+{
+ for (size_t a(0); a < GetViewCount(); a++)
+ {
+ OutlinerView* pOutlinerView = GetView(a);
+
+ if (pOutlinerView && pOutlinerView->GetEditView().getEditViewCallbacks())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdoutlinercache.cxx b/svx/source/svdraw/svdoutlinercache.cxx
new file mode 100644
index 000000000..0fc6fc973
--- /dev/null
+++ b/svx/source/svdraw/svdoutlinercache.cxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svdoutlinercache.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdetc.hxx>
+
+SdrOutlinerCache::SdrOutlinerCache( SdrModel* pModel )
+: mpModel( pModel )
+{
+}
+
+std::unique_ptr<SdrOutliner> SdrOutlinerCache::createOutliner( OutlinerMode nOutlinerMode )
+{
+ std::unique_ptr<SdrOutliner> pOutliner;
+
+ if( (OutlinerMode::OutlineObject == nOutlinerMode) && !maModeOutline.empty() )
+ {
+ pOutliner = std::move(maModeOutline.back());
+ maModeOutline.pop_back();
+ }
+ else if( (OutlinerMode::TextObject == nOutlinerMode) && !maModeText.empty() )
+ {
+ pOutliner = std::move(maModeText.back());
+ maModeText.pop_back();
+ }
+ else
+ {
+ pOutliner = SdrMakeOutliner(nOutlinerMode, *mpModel);
+ Outliner& aDrawOutliner = mpModel->GetDrawOutliner();
+ pOutliner->SetCalcFieldValueHdl( aDrawOutliner.GetCalcFieldValueHdl() );
+ maActiveOutliners.insert(pOutliner.get());
+ }
+
+ return pOutliner;
+}
+
+SdrOutlinerCache::~SdrOutlinerCache()
+{
+}
+
+void SdrOutlinerCache::disposeOutliner( std::unique_ptr<SdrOutliner> pOutliner )
+{
+ if( !pOutliner )
+ return;
+
+ OutlinerMode nOutlMode = pOutliner->GetOutlinerMode();
+
+ if( OutlinerMode::OutlineObject == nOutlMode )
+ {
+ pOutliner->Clear();
+ pOutliner->SetVertical( false );
+
+ // Deregister on outliner, might be reused from outliner cache
+ pOutliner->SetNotifyHdl( Link<EENotify&,void>() );
+ maModeOutline.emplace_back(std::move(pOutliner));
+ }
+ else if( OutlinerMode::TextObject == nOutlMode )
+ {
+ pOutliner->Clear();
+ pOutliner->SetVertical( false );
+
+ // Deregister on outliner, might be reused from outliner cache
+ pOutliner->SetNotifyHdl( Link<EENotify&,void>() );
+ maModeText.emplace_back(std::move(pOutliner));
+ }
+ else
+ {
+ maActiveOutliners.erase(pOutliner.get());
+ }
+}
+
+std::vector< SdrOutliner* > SdrOutlinerCache::GetActiveOutliners() const
+{
+ return std::vector< SdrOutliner* >(maActiveOutliners.begin(), maActiveOutliners.end());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdovirt.cxx b/svx/source/svdraw/svdovirt.cxx
new file mode 100644
index 000000000..372756cce
--- /dev/null
+++ b/svx/source/svdraw/svdovirt.cxx
@@ -0,0 +1,567 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdovirt.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/sdr/contact/viewcontactofvirtobj.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svddrgv.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+sdr::properties::BaseProperties& SdrVirtObj::GetProperties() const
+{
+ return rRefObj.GetProperties();
+}
+
+
+// #i27224#
+std::unique_ptr<sdr::contact::ViewContact> SdrVirtObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfVirtObj>(*this);
+}
+
+SdrVirtObj::SdrVirtObj(
+ SdrModel& rSdrModel,
+ SdrObject& rNewObj)
+: SdrObject(rSdrModel),
+ rRefObj(rNewObj)
+{
+ m_bVirtObj=true; // this is only a virtual object
+ rRefObj.AddReference(*this);
+ m_bClosedObj=rRefObj.IsClosedObj();
+}
+
+SdrVirtObj::SdrVirtObj(
+ SdrModel& rSdrModel, SdrVirtObj const & rSource)
+: SdrObject(rSdrModel, rSource),
+ rRefObj(rSource.rRefObj)
+{
+ m_bVirtObj=true; // this is only a virtual object
+ m_bClosedObj=rRefObj.IsClosedObj();
+
+ rRefObj.AddReference(*this);
+
+ aSnapRect = rSource.aSnapRect;
+ m_aAnchor = rSource.m_aAnchor;
+}
+
+SdrVirtObj::~SdrVirtObj()
+{
+ rRefObj.DelReference(*this);
+}
+
+const SdrObject& SdrVirtObj::GetReferencedObj() const
+{
+ return rRefObj;
+}
+
+SdrObject& SdrVirtObj::ReferencedObj()
+{
+ return rRefObj;
+}
+
+void SdrVirtObj::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& /*rHint*/)
+{
+ m_bClosedObj=rRefObj.IsClosedObj();
+ SetBoundAndSnapRectsDirty(); // TODO: Optimize this.
+
+ // Only a repaint here, rRefObj may have changed and broadcasts
+ ActionChanged();
+}
+
+void SdrVirtObj::NbcSetAnchorPos(const Point& rAnchorPos)
+{
+ m_aAnchor=rAnchorPos;
+}
+
+void SdrVirtObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rRefObj.TakeObjInfo(rInfo);
+}
+
+SdrInventor SdrVirtObj::GetObjInventor() const
+{
+ return rRefObj.GetObjInventor();
+}
+
+SdrObjKind SdrVirtObj::GetObjIdentifier() const
+{
+ return rRefObj.GetObjIdentifier();
+}
+
+SdrObjList* SdrVirtObj::GetSubList() const
+{
+ return rRefObj.GetSubList();
+}
+
+void SdrVirtObj::SetName(const OUString& rStr, const bool bSetChanged)
+{
+ return rRefObj.SetName(rStr, bSetChanged);
+}
+
+const OUString & SdrVirtObj::GetName() const
+{
+ return rRefObj.GetName();
+}
+
+void SdrVirtObj::SetTitle(const OUString& rStr)
+{
+ return rRefObj.SetTitle(rStr);
+}
+
+OUString SdrVirtObj::GetTitle() const
+{
+ return rRefObj.GetTitle();
+}
+
+void SdrVirtObj::SetDescription(const OUString& rStr)
+{
+ return rRefObj.SetDescription(rStr);
+}
+
+OUString SdrVirtObj::GetDescription() const
+{
+ return rRefObj.GetDescription();
+}
+
+const tools::Rectangle& SdrVirtObj::GetCurrentBoundRect() const
+{
+ m_aOutRect = rRefObj.GetCurrentBoundRect(); // TODO: Optimize this.
+ m_aOutRect += m_aAnchor;
+ return m_aOutRect;
+}
+
+const tools::Rectangle& SdrVirtObj::GetLastBoundRect() const
+{
+ m_aOutRect = rRefObj.GetLastBoundRect(); // TODO: Optimize this.
+ m_aOutRect += m_aAnchor;
+ return m_aOutRect;
+}
+
+void SdrVirtObj::RecalcBoundRect()
+{
+ m_aOutRect=rRefObj.GetCurrentBoundRect();
+ m_aOutRect+=m_aAnchor;
+}
+
+SdrVirtObj* SdrVirtObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrVirtObj(rTargetModel, *this);
+ // TTTT not sure if the above works - how could SdrObjFactory::MakeNewObject
+ // create an object with correct rRefObj (?) OTOH VirtObj probably needs not
+ // to be cloned ever - only used in Writer for multiple instances e.g. Header/Footer
+ // return new SdrVirtObj(
+ // getSdrModelFromSdrObject(),
+ // rRefObj); // only a further reference
+}
+
+OUString SdrVirtObj::TakeObjNameSingul() const
+{
+ OUString sName = "[" + rRefObj.TakeObjNameSingul() + "]";
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+OUString SdrVirtObj::TakeObjNamePlural() const
+{
+ return "[" + rRefObj.TakeObjNamePlural() + "]";
+}
+
+bool SdrVirtObj::HasLimitedRotation() const
+{
+ // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation
+ return rRefObj.HasLimitedRotation();
+}
+
+basegfx::B2DPolyPolygon SdrVirtObj::TakeXorPoly() const
+{
+ basegfx::B2DPolyPolygon aPolyPolygon(rRefObj.TakeXorPoly());
+
+ if(m_aAnchor.X() || m_aAnchor.Y())
+ {
+ aPolyPolygon.transform(basegfx::utils::createTranslateB2DHomMatrix(m_aAnchor.X(), m_aAnchor.Y()));
+ }
+
+ return aPolyPolygon;
+}
+
+
+sal_uInt32 SdrVirtObj::GetHdlCount() const
+{
+ return rRefObj.GetHdlCount();
+}
+
+void SdrVirtObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ SdrHdlList tempList(nullptr);
+ rRefObj.AddToHdlList(tempList);
+ for (size_t i=0; i<tempList.GetHdlCount(); ++i)
+ {
+ SdrHdl* pHdl = tempList.GetHdl(i);
+ Point aP(pHdl->GetPos()+m_aAnchor);
+ pHdl->SetPos(aP);
+ }
+ tempList.MoveTo(rHdlList);
+}
+
+void SdrVirtObj::AddToPlusHdlList(SdrHdlList& rHdlList, SdrHdl& rHdl) const
+{
+ SdrHdlList tempList(nullptr);
+ rRefObj.AddToPlusHdlList(tempList, rHdl);
+ for (size_t i=0; i<tempList.GetHdlCount(); ++i)
+ {
+ SdrHdl* pHdl = tempList.GetHdl(i);
+ Point aP(pHdl->GetPos()+m_aAnchor);
+ pHdl->SetPos(aP);
+ }
+ tempList.MoveTo(rHdlList);
+}
+
+bool SdrVirtObj::hasSpecialDrag() const
+{
+ return rRefObj.hasSpecialDrag();
+}
+
+bool SdrVirtObj::supportsFullDrag() const
+{
+ return false;
+}
+
+SdrObjectUniquePtr SdrVirtObj::getFullDragClone() const
+{
+ SdrObject& rReferencedObject = const_cast<SdrVirtObj*>(this)->ReferencedObj();
+ return SdrObjectUniquePtr(new SdrGrafObj(
+ getSdrModelFromSdrObject(),
+ SdrDragView::GetObjGraphic(rReferencedObject),
+ GetLogicRect()));
+}
+
+bool SdrVirtObj::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ return rRefObj.beginSpecialDrag(rDrag);
+}
+
+bool SdrVirtObj::applySpecialDrag(SdrDragStat& rDrag)
+{
+ return rRefObj.applySpecialDrag(rDrag);
+}
+
+basegfx::B2DPolyPolygon SdrVirtObj::getSpecialDragPoly(const SdrDragStat& rDrag) const
+{
+ return rRefObj.getSpecialDragPoly(rDrag);
+ // TODO: we don't handle offsets yet!
+}
+
+OUString SdrVirtObj::getSpecialDragComment(const SdrDragStat& rDrag) const
+{
+ return rRefObj.getSpecialDragComment(rDrag);
+}
+
+
+bool SdrVirtObj::BegCreate(SdrDragStat& rStat)
+{
+ return rRefObj.BegCreate(rStat);
+}
+
+bool SdrVirtObj::MovCreate(SdrDragStat& rStat)
+{
+ return rRefObj.MovCreate(rStat);
+}
+
+bool SdrVirtObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ return rRefObj.EndCreate(rStat,eCmd);
+}
+
+bool SdrVirtObj::BckCreate(SdrDragStat& rStat)
+{
+ return rRefObj.BckCreate(rStat);
+}
+
+void SdrVirtObj::BrkCreate(SdrDragStat& rStat)
+{
+ rRefObj.BrkCreate(rStat);
+}
+
+basegfx::B2DPolyPolygon SdrVirtObj::TakeCreatePoly(const SdrDragStat& rDrag) const
+{
+ return rRefObj.TakeCreatePoly(rDrag);
+ // TODO: we don't handle offsets yet!
+}
+
+
+void SdrVirtObj::NbcMove(const Size& rSiz)
+{
+ m_aAnchor.Move(rSiz);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrVirtObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ rRefObj.NbcResize(rRef-m_aAnchor,xFact,yFact);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrVirtObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ rRefObj.NbcRotate(rRef-m_aAnchor,nAngle,sn,cs);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrVirtObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ rRefObj.NbcMirror(rRef1-m_aAnchor,rRef2-m_aAnchor);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrVirtObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ rRefObj.NbcShear(rRef-m_aAnchor,nAngle,tn,bVShear);
+ SetBoundAndSnapRectsDirty();
+}
+
+
+void SdrVirtObj::Move(const Size& rSiz)
+{
+ if (!rSiz.IsEmpty()) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ NbcMove(rSiz);
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
+ }
+}
+
+void SdrVirtObj::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
+{
+ if (xFact.GetNumerator()!=xFact.GetDenominator() || yFact.GetNumerator()!=yFact.GetDenominator()) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ rRefObj.Resize(rRef-m_aAnchor,xFact,yFact, bUnsetRelative);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+}
+
+void SdrVirtObj::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ if (nAngle) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ rRefObj.Rotate(rRef-m_aAnchor,nAngle,sn,cs);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+}
+
+void SdrVirtObj::Mirror(const Point& rRef1, const Point& rRef2)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ rRefObj.Mirror(rRef1-m_aAnchor,rRef2-m_aAnchor);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrVirtObj::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ if (nAngle) {
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ rRefObj.Shear(rRef-m_aAnchor,nAngle,tn,bVShear);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+}
+
+
+void SdrVirtObj::RecalcSnapRect()
+{
+ aSnapRect=rRefObj.GetSnapRect();
+ aSnapRect+=m_aAnchor;
+}
+
+const tools::Rectangle& SdrVirtObj::GetSnapRect() const
+{
+ const_cast<SdrVirtObj*>(this)->aSnapRect=rRefObj.GetSnapRect();
+ const_cast<SdrVirtObj*>(this)->aSnapRect+=m_aAnchor;
+ return aSnapRect;
+}
+
+void SdrVirtObj::SetSnapRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ tools::Rectangle aR(rRect);
+ aR-=m_aAnchor;
+ rRefObj.SetSnapRect(aR);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrVirtObj::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aR(rRect);
+ aR-=m_aAnchor;
+ SetBoundAndSnapRectsDirty();
+ rRefObj.NbcSetSnapRect(aR);
+}
+
+
+const tools::Rectangle& SdrVirtObj::GetLogicRect() const
+{
+ const_cast<SdrVirtObj*>(this)->aSnapRect=rRefObj.GetLogicRect(); // An abuse of aSnapRect!
+ const_cast<SdrVirtObj*>(this)->aSnapRect+=m_aAnchor; // If there's trouble, we need another Rectangle Member (or a Heap).
+ return aSnapRect;
+}
+
+void SdrVirtObj::SetLogicRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ tools::Rectangle aR(rRect);
+ aR-=m_aAnchor;
+ rRefObj.SetLogicRect(aR);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+void SdrVirtObj::NbcSetLogicRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aR(rRect);
+ aR-=m_aAnchor;
+ SetBoundAndSnapRectsDirty();
+ rRefObj.NbcSetLogicRect(aR);
+}
+
+
+Degree100 SdrVirtObj::GetRotateAngle() const
+{
+ return rRefObj.GetRotateAngle();
+}
+
+Degree100 SdrVirtObj::GetShearAngle(bool bVertical) const
+{
+ return rRefObj.GetShearAngle(bVertical);
+}
+
+
+sal_uInt32 SdrVirtObj::GetSnapPointCount() const
+{
+ return rRefObj.GetSnapPointCount();
+}
+
+Point SdrVirtObj::GetSnapPoint(sal_uInt32 i) const
+{
+ Point aP(rRefObj.GetSnapPoint(i));
+ aP+=m_aAnchor;
+ return aP;
+}
+
+bool SdrVirtObj::IsPolyObj() const
+{
+ return rRefObj.IsPolyObj();
+}
+
+sal_uInt32 SdrVirtObj::GetPointCount() const
+{
+ return rRefObj.GetPointCount();
+}
+
+Point SdrVirtObj::GetPoint(sal_uInt32 i) const
+{
+ return rRefObj.GetPoint(i) + m_aAnchor;
+}
+
+void SdrVirtObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
+{
+ Point aP(rPnt);
+ aP-=m_aAnchor;
+ rRefObj.SetPoint(aP,i);
+ SetBoundAndSnapRectsDirty();
+}
+
+
+std::unique_ptr<SdrObjGeoData> SdrVirtObj::NewGeoData() const
+{
+ return rRefObj.NewGeoData();
+}
+
+void SdrVirtObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ rRefObj.SaveGeoData(rGeo);
+}
+
+void SdrVirtObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ rRefObj.RestoreGeoData(rGeo);
+ SetBoundAndSnapRectsDirty();
+}
+
+
+std::unique_ptr<SdrObjGeoData> SdrVirtObj::GetGeoData() const
+{
+ return rRefObj.GetGeoData();
+}
+
+void SdrVirtObj::SetGeoData(const SdrObjGeoData& rGeo)
+{
+ tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ rRefObj.SetGeoData(rGeo);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+}
+
+
+void SdrVirtObj::NbcReformatText()
+{
+ rRefObj.NbcReformatText();
+}
+
+bool SdrVirtObj::HasMacro() const
+{
+ return rRefObj.HasMacro();
+}
+
+SdrObject* SdrVirtObj::CheckMacroHit(const SdrObjMacroHitRec& rRec) const
+{
+ return rRefObj.CheckMacroHit(rRec); // TODO: positioning offset
+}
+
+PointerStyle SdrVirtObj::GetMacroPointer(const SdrObjMacroHitRec& rRec) const
+{
+ return rRefObj.GetMacroPointer(rRec); // TODO: positioning offset
+}
+
+void SdrVirtObj::PaintMacro(OutputDevice& rOut, const tools::Rectangle& rDirtyRect, const SdrObjMacroHitRec& rRec) const
+{
+ rRefObj.PaintMacro(rOut,rDirtyRect,rRec); // TODO: positioning offset
+}
+
+bool SdrVirtObj::DoMacro(const SdrObjMacroHitRec& rRec)
+{
+ return rRefObj.DoMacro(rRec); // TODO: positioning offset
+}
+
+Point SdrVirtObj::GetOffset() const
+{
+ // #i73248# default offset of SdrVirtObj is aAnchor
+ return m_aAnchor;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdpage.cxx b/svx/source/svdraw/svdpage.cxx
new file mode 100644
index 000000000..b7aa8777e
--- /dev/null
+++ b/svx/source/svdraw/svdpage.cxx
@@ -0,0 +1,1895 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <cassert>
+#include <set>
+#include <unordered_set>
+
+#include <svx/svdpage.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <string.h>
+
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <svtools/colorcfg.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdlayer.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/fmdpage.hxx>
+
+#include <sdr/contact/viewcontactofsdrpage.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <algorithm>
+#include <svl/hint.hxx>
+#include <rtl/strbuf.hxx>
+#include <libxml/xmlwriter.h>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+using namespace ::com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+SdrObjList::SdrObjList()
+: mbObjOrdNumsDirty(false),
+ mbRectsDirty(false),
+ mbIsNavigationOrderDirty(false)
+{
+}
+
+void SdrObjList::impClearSdrObjList(bool bBroadcast)
+{
+ SdrModel* pSdrModelFromRemovedSdrObject(nullptr);
+
+ while(!maList.empty())
+ {
+ // remove last object from list
+ SdrObject* pObj(maList.back());
+ RemoveObjectFromContainer(maList.size()-1);
+
+ // flushViewObjectContacts() is done since SdrObject::Free is not guaranteed
+ // to delete the object and thus refresh visualisations
+ pObj->GetViewContact().flushViewObjectContacts();
+
+ if(bBroadcast)
+ {
+ if(nullptr == pSdrModelFromRemovedSdrObject)
+ {
+ pSdrModelFromRemovedSdrObject = &pObj->getSdrModelFromSdrObject();
+ }
+
+ // sent remove hint (after removal, see RemoveObject())
+ // TTTT SdrPage not needed, can be accessed using SdrObject
+ SdrHint aHint(SdrHintKind::ObjectRemoved, *pObj, getSdrPageFromSdrObjList());
+ pObj->getSdrModelFromSdrObject().Broadcast(aHint);
+ }
+
+ // delete the object itself
+ SdrObject::Free( pObj );
+ }
+
+ if(bBroadcast && nullptr != pSdrModelFromRemovedSdrObject)
+ {
+ pSdrModelFromRemovedSdrObject->SetChanged();
+ }
+}
+
+void SdrObjList::ClearSdrObjList()
+{
+ // clear SdrObjects with broadcasting
+ impClearSdrObjList(true);
+}
+
+SdrObjList::~SdrObjList()
+{
+ // clear SdrObjects without broadcasting
+ impClearSdrObjList(false);
+}
+
+SdrPage* SdrObjList::getSdrPageFromSdrObjList() const
+{
+ // default is no page and returns zero
+ return nullptr;
+}
+
+SdrObject* SdrObjList::getSdrObjectFromSdrObjList() const
+{
+ // default is no SdrObject (SdrObjGroup)
+ return nullptr;
+}
+
+void SdrObjList::CopyObjects(const SdrObjList& rSrcList)
+{
+ // clear SdrObjects with broadcasting
+ ClearSdrObjList();
+
+ mbObjOrdNumsDirty = false;
+ mbRectsDirty = false;
+ size_t nCloneErrCnt(0);
+ const size_t nCount(rSrcList.GetObjCount());
+
+ if(nullptr == getSdrObjectFromSdrObjList() && nullptr == getSdrPageFromSdrObjList())
+ {
+ OSL_ENSURE(false, "SdrObjList which is not part of SdrPage or SdrObject (!)");
+ return;
+ }
+
+ SdrModel& rTargetSdrModel(nullptr == getSdrObjectFromSdrObjList()
+ ? getSdrPageFromSdrObjList()->getSdrModelFromSdrPage()
+ : getSdrObjectFromSdrObjList()->getSdrModelFromSdrObject());
+
+ for (size_t no(0); no < nCount; ++no)
+ {
+ SdrObject* pSO(rSrcList.GetObj(no));
+ SdrObject* pDO(pSO->CloneSdrObject(rTargetSdrModel));
+
+ if(nullptr != pDO)
+ {
+ NbcInsertObject(pDO, SAL_MAX_SIZE);
+ }
+ else
+ {
+ nCloneErrCnt++;
+ }
+ }
+
+ // and now for the Connectors
+ // The new objects would be shown in the rSrcList
+ // and then the object connections are made.
+ // Similar implementation are setup as the following:
+ // void SdrObjList::CopyObjects(const SdrObjList& rSrcList)
+ // SdrModel* SdrExchangeView::CreateMarkedObjModel() const
+ // BOOL SdrExchangeView::Paste(const SdrModel& rMod,...)
+ // void SdrEditView::CopyMarked()
+ if (nCloneErrCnt==0) {
+ for (size_t no=0; no<nCount; ++no) {
+ const SdrObject* pSrcOb=rSrcList.GetObj(no);
+ const SdrEdgeObj* pSrcEdge=dynamic_cast<const SdrEdgeObj*>( pSrcOb );
+ if (pSrcEdge!=nullptr) {
+ SdrObject* pSrcNode1=pSrcEdge->GetConnectedNode(true);
+ SdrObject* pSrcNode2=pSrcEdge->GetConnectedNode(false);
+ if (pSrcNode1!=nullptr && pSrcNode1->getParentSdrObjListFromSdrObject()!=pSrcEdge->getParentSdrObjListFromSdrObject()) pSrcNode1=nullptr; // can't do this
+ if (pSrcNode2!=nullptr && pSrcNode2->getParentSdrObjListFromSdrObject()!=pSrcEdge->getParentSdrObjListFromSdrObject()) pSrcNode2=nullptr; // across all lists (yet)
+ if (pSrcNode1!=nullptr || pSrcNode2!=nullptr) {
+ SdrObject* pEdgeObjTmp=GetObj(no);
+ SdrEdgeObj* pDstEdge=dynamic_cast<SdrEdgeObj*>( pEdgeObjTmp );
+ if (pDstEdge!=nullptr) {
+ if (pSrcNode1!=nullptr) {
+ sal_uInt32 nDstNode1=pSrcNode1->GetOrdNum();
+ SdrObject* pDstNode1=GetObj(nDstNode1);
+ if (pDstNode1!=nullptr) { // else we get an error!
+ pDstEdge->ConnectToNode(true,pDstNode1);
+ } else {
+ OSL_FAIL("SdrObjList::operator=(): pDstNode1==NULL!");
+ }
+ }
+ if (pSrcNode2!=nullptr) {
+ sal_uInt32 nDstNode2=pSrcNode2->GetOrdNum();
+ SdrObject* pDstNode2=GetObj(nDstNode2);
+ if (pDstNode2!=nullptr) { // else the node was probably not selected
+ pDstEdge->ConnectToNode(false,pDstNode2);
+ } else {
+ OSL_FAIL("SdrObjList::operator=(): pDstNode2==NULL!");
+ }
+ }
+ } else {
+ OSL_FAIL("SdrObjList::operator=(): pDstEdge==NULL!");
+ }
+ }
+ }
+ }
+ } else {
+#ifdef DBG_UTIL
+ OStringBuffer aStr("SdrObjList::operator=(): Error when cloning ");
+
+ if(nCloneErrCnt == 1)
+ {
+ aStr.append("a drawing object.");
+ }
+ else
+ {
+ aStr.append(static_cast<sal_Int32>(nCloneErrCnt));
+ aStr.append(" drawing objects.");
+ }
+
+ aStr.append(" Not copying connectors.");
+
+ OSL_FAIL(aStr.getStr());
+#endif
+ }
+}
+
+void SdrObjList::RecalcObjOrdNums()
+{
+ const size_t nCount = GetObjCount();
+ for (size_t no=0; no<nCount; ++no) {
+ SdrObject* pObj=GetObj(no);
+ pObj->SetOrdNum(no);
+ }
+ mbObjOrdNumsDirty=false;
+}
+
+void SdrObjList::RecalcRects()
+{
+ maSdrObjListOutRect=tools::Rectangle();
+ maSdrObjListSnapRect=maSdrObjListOutRect;
+ const size_t nCount = GetObjCount();
+ for (size_t i=0; i<nCount; ++i) {
+ SdrObject* pObj=GetObj(i);
+ if (i==0) {
+ maSdrObjListOutRect=pObj->GetCurrentBoundRect();
+ maSdrObjListSnapRect=pObj->GetSnapRect();
+ } else {
+ maSdrObjListOutRect.Union(pObj->GetCurrentBoundRect());
+ maSdrObjListSnapRect.Union(pObj->GetSnapRect());
+ }
+ }
+}
+
+void SdrObjList::SetSdrObjListRectsDirty()
+{
+ mbRectsDirty=true;
+ SdrObject* pParentSdrObject(getSdrObjectFromSdrObjList());
+
+ if(nullptr != pParentSdrObject)
+ {
+ pParentSdrObject->SetBoundAndSnapRectsDirty();
+ }
+}
+
+void SdrObjList::impChildInserted(SdrObject const & rChild)
+{
+ sdr::contact::ViewContact* pParent = rChild.GetViewContact().GetParentContact();
+
+ if(pParent)
+ {
+ pParent->ActionChildInserted(rChild.GetViewContact());
+ }
+}
+
+void SdrObjList::NbcInsertObject(SdrObject* pObj, size_t nPos)
+{
+ DBG_ASSERT(pObj!=nullptr,"SdrObjList::NbcInsertObject(NULL)");
+ if (pObj==nullptr)
+ return;
+
+ DBG_ASSERT(!pObj->IsInserted(),"The object already has the status Inserted.");
+ const size_t nCount = GetObjCount();
+ if (nPos>nCount) nPos=nCount;
+ InsertObjectIntoContainer(*pObj,nPos);
+
+ if (nPos<nCount) mbObjOrdNumsDirty=true;
+ pObj->SetOrdNum(nPos);
+ pObj->setParentOfSdrObject(this);
+
+ // Inform the parent about change to allow invalidations at
+ // evtl. existing parent visualisations
+ impChildInserted(*pObj);
+
+ if (!mbRectsDirty) {
+ mbRectsDirty = true;
+ }
+ pObj->InsertedStateChange(); // calls the UserCall (among others)
+}
+
+void SdrObjList::InsertObjectThenMakeNameUnique(SdrObject* pObj)
+{
+ std::unordered_set<rtl::OUString> aNameSet;
+ InsertObjectThenMakeNameUnique(pObj, aNameSet);
+}
+
+void SdrObjList::InsertObjectThenMakeNameUnique(SdrObject* pObj, std::unordered_set<OUString>& rNameSet, size_t nPos)
+{
+ InsertObject(pObj, nPos);
+ if (pObj->GetName().isEmpty())
+ return;
+
+ pObj->MakeNameUnique(rNameSet);
+ SdrObjList* pSdrObjList = pObj->GetSubList(); // group
+ if (pSdrObjList)
+ {
+ SdrObject* pListObj;
+ SdrObjListIter aIter(pSdrObjList, SdrIterMode::DeepWithGroups);
+ while (aIter.IsMore())
+ {
+ pListObj = aIter.Next();
+ pListObj->MakeNameUnique(rNameSet);
+ }
+ }
+}
+
+void SdrObjList::InsertObject(SdrObject* pObj, size_t nPos)
+{
+ DBG_ASSERT(pObj!=nullptr,"SdrObjList::InsertObject(NULL)");
+
+ if(!pObj)
+ return;
+
+ // if anchor is used, reset it before grouping
+ if(getSdrObjectFromSdrObjList())
+ {
+ const Point& rAnchorPos = pObj->GetAnchorPos();
+ if(rAnchorPos.X() || rAnchorPos.Y())
+ pObj->NbcSetAnchorPos(Point());
+ }
+
+ // do insert to new group
+ NbcInsertObject(pObj, nPos);
+
+ // In case the object is inserted into a group and doesn't overlap with
+ // the group's other members, it needs an own repaint.
+ SdrObject* pParentSdrObject(getSdrObjectFromSdrObjList());
+
+ if(pParentSdrObject)
+ {
+ // only repaint here
+ pParentSdrObject->ActionChanged();
+ }
+
+ // TODO: We need a different broadcast here!
+ // Repaint from object number ... (heads-up: GroupObj)
+ if(pObj->getSdrPageFromSdrObject() && !pObj->getSdrModelFromSdrObject().isLocked())
+ {
+ SdrHint aHint(SdrHintKind::ObjectInserted, *pObj);
+ pObj->getSdrModelFromSdrObject().Broadcast(aHint);
+ }
+
+ pObj->getSdrModelFromSdrObject().SetChanged();
+}
+
+SdrObject* SdrObjList::NbcRemoveObject(size_t nObjNum)
+{
+ if (nObjNum >= maList.size())
+ {
+ OSL_ASSERT(nObjNum<maList.size());
+ return nullptr;
+ }
+
+ const size_t nCount = GetObjCount();
+ SdrObject* pObj=maList[nObjNum];
+ RemoveObjectFromContainer(nObjNum);
+
+ DBG_ASSERT(pObj!=nullptr,"Could not find object to remove.");
+ if (pObj!=nullptr)
+ {
+ // flushViewObjectContacts() clears the VOC's and those invalidate
+ pObj->GetViewContact().flushViewObjectContacts();
+
+ DBG_ASSERT(pObj->IsInserted(),"The object does not have the status Inserted.");
+
+ // tdf#121022 Do first remove from SdrObjList - InsertedStateChange
+ // relies now on IsInserted which uses getParentSdrObjListFromSdrObject
+ pObj->setParentOfSdrObject(nullptr);
+
+ // calls UserCall, among other
+ pObj->InsertedStateChange();
+
+ if (!mbObjOrdNumsDirty)
+ {
+ // optimizing for the case that the last object has to be removed
+ if (nObjNum+1!=nCount) {
+ mbObjOrdNumsDirty=true;
+ }
+ }
+ SetSdrObjListRectsDirty();
+ }
+ return pObj;
+}
+
+SdrObject* SdrObjList::RemoveObject(size_t nObjNum)
+{
+ if (nObjNum >= maList.size())
+ {
+ OSL_ASSERT(nObjNum<maList.size());
+ return nullptr;
+ }
+
+ const size_t nCount = GetObjCount();
+ SdrObject* pObj=maList[nObjNum];
+ RemoveObjectFromContainer(nObjNum);
+
+ DBG_ASSERT(pObj!=nullptr,"Object to remove not found.");
+ if(pObj)
+ {
+ // flushViewObjectContacts() clears the VOC's and those invalidate
+ pObj->GetViewContact().flushViewObjectContacts();
+ DBG_ASSERT(pObj->IsInserted(),"The object does not have the status Inserted.");
+
+ // TODO: We need a different broadcast here.
+ if (pObj->getSdrPageFromSdrObject()!=nullptr)
+ {
+ SdrHint aHint(SdrHintKind::ObjectRemoved, *pObj);
+ pObj->getSdrModelFromSdrObject().Broadcast(aHint);
+ }
+
+ pObj->getSdrModelFromSdrObject().SetChanged();
+
+ // tdf#121022 Do first remove from SdrObjList - InsertedStateChange
+ // relies now on IsInserted which uses getParentSdrObjListFromSdrObject
+ pObj->setParentOfSdrObject(nullptr);
+
+ // calls, among other things, the UserCall
+ pObj->InsertedStateChange();
+
+ if (!mbObjOrdNumsDirty)
+ {
+ // optimization for the case that the last object is removed
+ if (nObjNum+1!=nCount) {
+ mbObjOrdNumsDirty=true;
+ }
+ }
+
+ SetSdrObjListRectsDirty();
+ SdrObject* pParentSdrObject(getSdrObjectFromSdrObjList());
+
+ if(pParentSdrObject && !GetObjCount())
+ {
+ // empty group created; it needs to be repainted since it's
+ // visualization changes
+ pParentSdrObject->ActionChanged();
+ }
+ }
+ return pObj;
+}
+
+SdrObject* SdrObjList::ReplaceObject(SdrObject* pNewObj, size_t nObjNum)
+{
+ if (nObjNum >= maList.size())
+ {
+ OSL_ASSERT(nObjNum<maList.size());
+ return nullptr;
+ }
+ if (pNewObj == nullptr)
+ {
+ OSL_ASSERT(pNewObj!=nullptr);
+ return nullptr;
+ }
+
+ SdrObject* pObj=maList[nObjNum];
+ DBG_ASSERT(pObj!=nullptr,"SdrObjList::ReplaceObject: Could not find object to remove.");
+ if (pObj!=nullptr) {
+ DBG_ASSERT(pObj->IsInserted(),"SdrObjList::ReplaceObject: the object does not have status Inserted.");
+
+ // TODO: We need a different broadcast here.
+ if (pObj->getSdrPageFromSdrObject()!=nullptr)
+ {
+ SdrHint aHint(SdrHintKind::ObjectRemoved, *pObj);
+ pObj->getSdrModelFromSdrObject().Broadcast(aHint);
+ }
+
+ // Change parent and replace in SdrObjList
+ pObj->setParentOfSdrObject(nullptr);
+ ReplaceObjectInContainer(*pNewObj,nObjNum);
+
+ // tdf#121022 InsertedStateChange uses the parent
+ // to detect if pObj is inserted or not, so have to call
+ // it *after* changing these settings, else an obviously wrong
+ // 'SdrUserCallType::Inserted' would be sent
+ pObj->InsertedStateChange();
+
+ // flushViewObjectContacts() clears the VOC's and those
+ // trigger the evtl. needed invalidate(s)
+ pObj->GetViewContact().flushViewObjectContacts();
+
+ // Setup data at new SdrObject - it already *is* inserted to
+ // the SdrObjList due to 'ReplaceObjectInContainer' above
+ pNewObj->SetOrdNum(nObjNum);
+ pNewObj->setParentOfSdrObject(this);
+
+ // Inform the parent about change to allow invalidations at
+ // evtl. existing parent visualisations, but also react on
+ // newly inserted SdrObjects (as e.g. GraphCtrlUserCall does)
+ impChildInserted(*pNewObj);
+
+ pNewObj->InsertedStateChange();
+
+ // TODO: We need a different broadcast here.
+ if (pNewObj->getSdrPageFromSdrObject()!=nullptr) {
+ SdrHint aHint(SdrHintKind::ObjectInserted, *pNewObj);
+ pNewObj->getSdrModelFromSdrObject().Broadcast(aHint);
+ }
+
+ pNewObj->getSdrModelFromSdrObject().SetChanged();
+
+ SetSdrObjListRectsDirty();
+ }
+ return pObj;
+}
+
+SdrObject* SdrObjList::SetObjectOrdNum(size_t nOldObjNum, size_t nNewObjNum)
+{
+ if (nOldObjNum >= maList.size() || nNewObjNum >= maList.size())
+ {
+ OSL_ASSERT(nOldObjNum<maList.size());
+ OSL_ASSERT(nNewObjNum<maList.size());
+ return nullptr;
+ }
+
+ SdrObject* pObj=maList[nOldObjNum];
+ if (nOldObjNum==nNewObjNum) return pObj;
+ DBG_ASSERT(pObj!=nullptr,"SdrObjList::SetObjectOrdNum: Object not found.");
+ if (pObj!=nullptr) {
+ DBG_ASSERT(pObj->IsInserted(),"SdrObjList::SetObjectOrdNum: the object does not have status Inserted.");
+ RemoveObjectFromContainer(nOldObjNum);
+ InsertObjectIntoContainer(*pObj,nNewObjNum);
+
+ // No need to delete visualisation data since same object
+ // gets inserted again. Also a single ActionChanged is enough
+ pObj->ActionChanged();
+
+ pObj->SetOrdNum(nNewObjNum);
+ mbObjOrdNumsDirty=true;
+
+ // TODO: We need a different broadcast here.
+ if (pObj->getSdrPageFromSdrObject()!=nullptr)
+ pObj->getSdrModelFromSdrObject().Broadcast(SdrHint(SdrHintKind::ObjectChange, *pObj));
+ pObj->getSdrModelFromSdrObject().SetChanged();
+ }
+ return pObj;
+}
+
+void SdrObjList::SetExistingObjectOrdNum(SdrObject* pObj, size_t nNewObjNum)
+{
+ assert(std::find(maList.begin(), maList.end(), pObj) != maList.end() && "This method requires that the child object already be inserted");
+ assert(pObj->IsInserted() && "SdrObjList::SetObjectOrdNum: the object does not have status Inserted.");
+
+ // I am deliberately bypassing getOrdNum() because I don't want to unnecessarily
+ // trigger RecalcObjOrdNums()
+ const sal_uInt32 nOldOrdNum = pObj->m_nOrdNum;
+ if (!mbObjOrdNumsDirty && nOldOrdNum == nNewObjNum)
+ return;
+
+ // Update the navigation positions.
+ if (HasObjectNavigationOrder())
+ {
+ tools::WeakReference<SdrObject> aReference (pObj);
+ auto iObject = ::std::find(
+ mxNavigationOrder->begin(),
+ mxNavigationOrder->end(),
+ aReference);
+ mxNavigationOrder->erase(iObject);
+ mbIsNavigationOrderDirty = true;
+ // The new object does not have a user defined position so append it
+ // to the list.
+ pObj->SetNavigationPosition(mxNavigationOrder->size());
+ mxNavigationOrder->push_back(pObj);
+ }
+ if (nOldOrdNum < maList.size() && maList[nOldOrdNum] == pObj)
+ maList.erase(maList.begin()+nOldOrdNum);
+ else
+ {
+ auto it = std::find(maList.begin(), maList.end(), pObj);
+ maList.erase(it);
+ }
+ // Insert object into object list. Because the insert() method requires
+ // a valid iterator as insertion position, we have to use push_back() to
+ // insert at the end of the list.
+ if (nNewObjNum >= maList.size())
+ maList.push_back(pObj);
+ else
+ maList.insert(maList.begin()+nNewObjNum, pObj);
+
+ mbObjOrdNumsDirty=true;
+
+ // No need to delete visualisation data since same object
+ // gets inserted again. Also a single ActionChanged is enough
+ pObj->ActionChanged();
+
+ pObj->SetOrdNum(nNewObjNum);
+ mbObjOrdNumsDirty=true;
+
+ // TODO: We need a different broadcast here.
+ if (pObj->getSdrPageFromSdrObject()!=nullptr)
+ pObj->getSdrModelFromSdrObject().Broadcast(SdrHint(SdrHintKind::ObjectChange, *pObj));
+ pObj->getSdrModelFromSdrObject().SetChanged();
+}
+
+void SdrObjList::sort( std::vector<sal_Int32>& sortOrder)
+{
+ // no negative indexes and indexes larger than maList size are allowed
+ auto it = std::find_if( sortOrder.begin(), sortOrder.end(), [this](const sal_Int32& rIt)
+ { return ( rIt < 0 || o3tl::make_unsigned(rIt) >= maList.size() ); } );
+ if ( it != sortOrder.end())
+ throw css::lang::IllegalArgumentException("negative index of shape", nullptr, 1);
+
+ // no duplicates
+ std::vector<bool> aNoDuplicates(sortOrder.size(), false);
+ for (size_t i = 0; i < sortOrder.size(); ++i )
+ {
+ size_t idx = static_cast<size_t>( sortOrder[i] );
+
+ if ( aNoDuplicates[idx] )
+ throw css::lang::IllegalArgumentException("duplicate index of shape", nullptr, 2);
+
+ aNoDuplicates[idx] = true;
+ }
+
+ // example sortOrder [2 0 1]
+ // example maList [T T S T T] ( T T = shape with textbox, S = just a shape )
+ // (shapes at positions 0 and 2 have a textbox)
+
+ std::deque<SdrObject*> aNewList(maList.size());
+ std::set<sal_Int32> aShapesWithTextbox;
+ std::vector<sal_Int32> aIncrements;
+ std::vector<sal_Int32> aDuplicates;
+
+ if ( maList.size() > 1)
+ {
+ for (size_t i = 1; i< maList.size(); ++i)
+ {
+ // if this shape is a textbox, then look at its left neighbour
+ // (shape this textbox is in)
+ // and insert the number of textboxes to the left of it
+ if (maList[i]->IsTextBox())
+ aShapesWithTextbox.insert( i - 1 - aShapesWithTextbox.size() );
+ }
+ // example aShapesWithTextbox [0 2]
+ }
+
+ if (aShapesWithTextbox.size() != maList.size() - sortOrder.size())
+ {
+ throw lang::IllegalArgumentException("mismatch of no. of shapes", nullptr, 0);
+ }
+
+ for (size_t i = 0; i< sortOrder.size(); ++i)
+ {
+
+ if (aShapesWithTextbox.count(sortOrder[i]) > 0)
+ aDuplicates.push_back(sortOrder[i]);
+
+ aDuplicates.push_back(sortOrder[i]);
+
+ // example aDuplicates [2 2 0 0 1]
+ }
+ assert(aDuplicates.size() == maList.size());
+
+ aIncrements.push_back(0);
+ for (size_t i = 1; i< sortOrder.size(); ++i)
+ {
+ if (aShapesWithTextbox.count(i - 1))
+ aIncrements.push_back(aIncrements[i-1] + 1 );
+ else
+ aIncrements.push_back(aIncrements[i-1]);
+
+ // example aIncrements [0 1 1]
+ }
+ assert(aIncrements.size() == sortOrder.size());
+
+ std::vector<sal_Int32> aNewSortOrder(maList.size());
+ sal_Int32 nPrev = -1;
+ for (size_t i = 0; i< aDuplicates.size(); ++i)
+ {
+ if (nPrev != aDuplicates[i])
+ aNewSortOrder[i] = aDuplicates[i] + aIncrements[aDuplicates[i]];
+ else
+ aNewSortOrder[i] = aNewSortOrder[i-1] + 1;
+
+ nPrev = aDuplicates[i];
+
+ // example aNewSortOrder [3 4 0 1 2]
+ }
+ assert(aNewSortOrder.size() == maList.size());
+
+#ifndef NDEBUG
+ {
+ std::vector<sal_Int32> tmp(aNewSortOrder);
+ std::sort(tmp.begin(), tmp.end());
+ for (size_t i = 0; i < tmp.size(); ++i)
+ {
+ assert(size_t(tmp[i]) == i);
+ }
+ }
+#endif
+
+ SdrModel & rModel(getSdrPageFromSdrObjList()->getSdrModelFromSdrPage());
+ bool const isUndo(rModel.IsUndoEnabled());
+ if (isUndo)
+ {
+ rModel.AddUndo(SdrUndoFactory::CreateUndoSort(*getSdrPageFromSdrObjList(), sortOrder));
+ }
+
+ for (size_t i = 0; i < aNewSortOrder.size(); ++i)
+ {
+ aNewList[i] = maList[ aNewSortOrder[i] ];
+ aNewList[i]->SetOrdNum(i);
+ }
+
+ std::swap(aNewList, maList);
+}
+
+const tools::Rectangle& SdrObjList::GetAllObjSnapRect() const
+{
+ if (mbRectsDirty) {
+ const_cast<SdrObjList*>(this)->RecalcRects();
+ const_cast<SdrObjList*>(this)->mbRectsDirty=false;
+ }
+ return maSdrObjListSnapRect;
+}
+
+const tools::Rectangle& SdrObjList::GetAllObjBoundRect() const
+{
+ // #i106183# for deep group hierarchies like in chart2, the invalidates
+ // through the hierarchy are not correct; use a 2nd hint for the needed
+ // recalculation. Future versions will have no bool flag at all, but
+ // just maSdrObjListOutRect in empty state to represent an invalid state, thus
+ // it's a step in the right direction.
+ if (mbRectsDirty || maSdrObjListOutRect.IsEmpty())
+ {
+ const_cast<SdrObjList*>(this)->RecalcRects();
+ const_cast<SdrObjList*>(this)->mbRectsDirty=false;
+ }
+ return maSdrObjListOutRect;
+}
+
+void SdrObjList::NbcReformatAllTextObjects()
+{
+ size_t nCount=GetObjCount();
+ size_t nNum=0;
+
+ while (nNum<nCount)
+ {
+ SdrObject* pObj = GetObj(nNum);
+
+ pObj->NbcReformatText();
+ nCount=GetObjCount(); // ReformatText may delete an object
+ nNum++;
+ }
+
+}
+
+void SdrObjList::ReformatAllTextObjects()
+{
+ NbcReformatAllTextObjects();
+}
+
+/** steps over all available objects and reformats all
+ edge objects that are connected to other objects so that
+ they may reposition themselves.
+*/
+void SdrObjList::ReformatAllEdgeObjects()
+{
+ // #i120437# go over whole hierarchy, not only over object level null (seen from grouping)
+ SdrObjListIter aIter(this, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pObj = aIter.Next();
+ if (pObj->GetObjIdentifier() != SdrObjKind::Edge)
+ continue;
+
+ SdrEdgeObj* pSdrEdgeObj = static_cast< SdrEdgeObj* >(pObj);
+ pSdrEdgeObj->Reformat();
+ }
+}
+
+void SdrObjList::BurnInStyleSheetAttributes()
+{
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ GetObj(a)->BurnInStyleSheetAttributes();
+ }
+}
+
+size_t SdrObjList::GetObjCount() const
+{
+ return maList.size();
+}
+
+
+SdrObject* SdrObjList::GetObj(size_t nNum) const
+{
+ if (nNum < maList.size())
+ return maList[nNum];
+
+ return nullptr;
+}
+
+
+bool SdrObjList::IsReadOnly() const
+{
+ bool bRet(false);
+ SdrObject* pParentSdrObject(getSdrObjectFromSdrObjList());
+
+ if(nullptr != pParentSdrObject)
+ {
+ SdrPage* pSdrPage(pParentSdrObject->getSdrPageFromSdrObject());
+
+ if(nullptr != pSdrPage)
+ {
+ bRet = pSdrPage->IsReadOnly();
+ }
+ }
+
+ return bRet;
+}
+
+void SdrObjList::FlattenGroups()
+{
+ const size_t nObj = GetObjCount();
+ for( size_t i = nObj; i>0; )
+ UnGroupObj(--i);
+}
+
+void SdrObjList::UnGroupObj( size_t nObjNum )
+{
+ // if the given object is no group, this method is a noop
+ SdrObject* pUngroupObj = GetObj( nObjNum );
+ if( pUngroupObj )
+ {
+ SdrObjList* pSrcLst = pUngroupObj->GetSubList();
+ if(pSrcLst)
+ if(auto pUngroupGroup = dynamic_cast<SdrObjGroup*>( pUngroupObj))
+ {
+ // ungroup recursively (has to be head recursion,
+ // otherwise our indices will get trashed when doing it in
+ // the loop)
+ pSrcLst->FlattenGroups();
+
+ // the position at which we insert the members of rUngroupGroup
+ size_t nInsertPos( pUngroupGroup->GetOrdNum() );
+
+ const size_t nCount = pSrcLst->GetObjCount();
+ for( size_t i=0; i<nCount; ++i )
+ {
+ SdrObject* pObj = pSrcLst->RemoveObject(0);
+ InsertObject(pObj, nInsertPos);
+ ++nInsertPos;
+ }
+
+ RemoveObject(nInsertPos);
+ }
+ }
+#ifdef DBG_UTIL
+ else
+ OSL_FAIL("SdrObjList::UnGroupObj: object index invalid");
+#endif
+}
+
+bool SdrObjList::HasObjectNavigationOrder() const { return bool(mxNavigationOrder); }
+
+void SdrObjList::SetObjectNavigationPosition (
+ SdrObject& rObject,
+ const sal_uInt32 nNewPosition)
+{
+ // When the navigation order container has not yet been created then
+ // create one now. It is initialized with the z-order taken from
+ // maList.
+ if (!mxNavigationOrder)
+ {
+ mxNavigationOrder.emplace(maList.begin(), maList.end());
+ }
+ OSL_ASSERT(bool(mxNavigationOrder));
+ OSL_ASSERT( mxNavigationOrder->size() == maList.size());
+
+ tools::WeakReference<SdrObject> aReference (&rObject);
+
+ // Look up the object whose navigation position is to be changed.
+ auto iObject = ::std::find(
+ mxNavigationOrder->begin(),
+ mxNavigationOrder->end(),
+ aReference);
+ if (iObject == mxNavigationOrder->end())
+ {
+ // The given object is not a member of the navigation order.
+ return;
+ }
+
+ // Move the object to its new position.
+ const sal_uInt32 nOldPosition = ::std::distance(mxNavigationOrder->begin(), iObject);
+ if (nOldPosition == nNewPosition)
+ return;
+
+ mxNavigationOrder->erase(iObject);
+ sal_uInt32 nInsertPosition (nNewPosition);
+ // Adapt insertion position for the just erased object.
+ if (nNewPosition >= nOldPosition)
+ nInsertPosition -= 1;
+ if (nInsertPosition >= mxNavigationOrder->size())
+ mxNavigationOrder->push_back(aReference);
+ else
+ mxNavigationOrder->insert(mxNavigationOrder->begin()+nInsertPosition, aReference);
+
+ mbIsNavigationOrderDirty = true;
+
+ // The navigation order is written out to file so mark the model as modified.
+ rObject.getSdrModelFromSdrObject().SetChanged();
+}
+
+
+SdrObject* SdrObjList::GetObjectForNavigationPosition (const sal_uInt32 nNavigationPosition) const
+{
+ if (HasObjectNavigationOrder())
+ {
+ // There is a user defined navigation order. Make sure the object
+ // index is correct and look up the object in mxNavigationOrder.
+ if (nNavigationPosition >= mxNavigationOrder->size())
+ {
+ OSL_ASSERT(nNavigationPosition < mxNavigationOrder->size());
+ }
+ else
+ return (*mxNavigationOrder)[nNavigationPosition].get();
+ }
+ else
+ {
+ // There is no user defined navigation order. Use the z-order
+ // instead.
+ if (nNavigationPosition >= maList.size())
+ {
+ OSL_ASSERT(nNavigationPosition < maList.size());
+ }
+ else
+ return maList[nNavigationPosition];
+ }
+ return nullptr;
+}
+
+
+void SdrObjList::ClearObjectNavigationOrder()
+{
+ mxNavigationOrder.reset();
+ mbIsNavigationOrderDirty = true;
+}
+
+
+bool SdrObjList::RecalcNavigationPositions()
+{
+ if (mbIsNavigationOrderDirty)
+ {
+ if (mxNavigationOrder)
+ {
+ mbIsNavigationOrderDirty = false;
+
+ sal_uInt32 nIndex (0);
+ for (auto& rpObject : *mxNavigationOrder)
+ {
+ rpObject->SetNavigationPosition(nIndex);
+ ++nIndex;
+ }
+ }
+ }
+
+ return bool(mxNavigationOrder);
+}
+
+
+void SdrObjList::SetNavigationOrder (const uno::Reference<container::XIndexAccess>& rxOrder)
+{
+ if (rxOrder.is())
+ {
+ const sal_Int32 nCount = rxOrder->getCount();
+ if (static_cast<sal_uInt32>(nCount) != maList.size())
+ return;
+
+ if (!mxNavigationOrder)
+ mxNavigationOrder = std::vector<tools::WeakReference<SdrObject>>(nCount);
+
+ for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
+ {
+ uno::Reference<uno::XInterface> xShape (rxOrder->getByIndex(nIndex), uno::UNO_QUERY);
+ SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xShape);
+ if (pObject == nullptr)
+ break;
+ (*mxNavigationOrder)[nIndex] = pObject;
+ }
+
+ mbIsNavigationOrderDirty = true;
+ }
+ else
+ {
+ ClearObjectNavigationOrder();
+ }
+}
+
+
+void SdrObjList::InsertObjectIntoContainer (
+ SdrObject& rObject,
+ const sal_uInt32 nInsertPosition)
+{
+ OSL_ASSERT(nInsertPosition<=maList.size());
+
+ // Update the navigation positions.
+ if (HasObjectNavigationOrder())
+ {
+ // The new object does not have a user defined position so append it
+ // to the list.
+ rObject.SetNavigationPosition(mxNavigationOrder->size());
+ mxNavigationOrder->push_back(&rObject);
+ }
+
+ // Insert object into object list. Because the insert() method requires
+ // a valid iterator as insertion position, we have to use push_back() to
+ // insert at the end of the list.
+ if (nInsertPosition >= maList.size())
+ maList.push_back(&rObject);
+ else
+ maList.insert(maList.begin()+nInsertPosition, &rObject);
+ mbObjOrdNumsDirty=true;
+}
+
+
+void SdrObjList::ReplaceObjectInContainer (
+ SdrObject& rNewObject,
+ const sal_uInt32 nObjectPosition)
+{
+ if (nObjectPosition >= maList.size())
+ {
+ OSL_ASSERT(nObjectPosition<maList.size());
+ return;
+ }
+
+ // Update the navigation positions.
+ if (HasObjectNavigationOrder())
+ {
+ // A user defined position of the object that is to be replaced is
+ // not transferred to the new object so erase the former and append
+ // the later object from/to the navigation order.
+ OSL_ASSERT(nObjectPosition < maList.size());
+ tools::WeakReference<SdrObject> aReference (maList[nObjectPosition]);
+ auto iObject = ::std::find(
+ mxNavigationOrder->begin(),
+ mxNavigationOrder->end(),
+ aReference);
+ if (iObject != mxNavigationOrder->end())
+ mxNavigationOrder->erase(iObject);
+
+ mxNavigationOrder->push_back(&rNewObject);
+
+ mbIsNavigationOrderDirty = true;
+ }
+
+ maList[nObjectPosition] = &rNewObject;
+ mbObjOrdNumsDirty=true;
+}
+
+
+void SdrObjList::RemoveObjectFromContainer (
+ const sal_uInt32 nObjectPosition)
+{
+ if (nObjectPosition >= maList.size())
+ {
+ OSL_ASSERT(nObjectPosition<maList.size());
+ return;
+ }
+
+ // Update the navigation positions.
+ if (HasObjectNavigationOrder())
+ {
+ tools::WeakReference<SdrObject> aReference (maList[nObjectPosition]);
+ auto iObject = ::std::find(
+ mxNavigationOrder->begin(),
+ mxNavigationOrder->end(),
+ aReference);
+ if (iObject != mxNavigationOrder->end())
+ mxNavigationOrder->erase(iObject);
+ mbIsNavigationOrderDirty = true;
+ }
+
+ maList.erase(maList.begin()+nObjectPosition);
+ mbObjOrdNumsDirty=true;
+}
+
+void SdrObjList::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrObjList"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*this).name()));
+
+ size_t nObjCount = GetObjCount();
+ for (size_t i = 0; i < nObjCount; ++i)
+ {
+ if (const SdrObject* pObject = GetObj(i))
+ pObject->dumpAsXml(pWriter);
+ }
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+
+void SdrPageGridFrameList::Clear()
+{
+ sal_uInt16 nCount=GetCount();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ delete GetObject(i);
+ }
+ aList.clear();
+}
+
+
+// PageUser section
+
+void SdrPage::AddPageUser(sdr::PageUser& rNewUser)
+{
+ maPageUsers.push_back(&rNewUser);
+}
+
+void SdrPage::RemovePageUser(sdr::PageUser& rOldUser)
+{
+ const sdr::PageUserVector::iterator aFindResult = ::std::find(maPageUsers.begin(), maPageUsers.end(), &rOldUser);
+ if(aFindResult != maPageUsers.end())
+ {
+ maPageUsers.erase(aFindResult);
+ }
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrPage::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfSdrPage>(*this);
+}
+
+const sdr::contact::ViewContact& SdrPage::GetViewContact() const
+{
+ if (!mpViewContact)
+ const_cast<SdrPage*>(this)->mpViewContact =
+ const_cast<SdrPage*>(this)->CreateObjectSpecificViewContact();
+
+ return *mpViewContact;
+}
+
+sdr::contact::ViewContact& SdrPage::GetViewContact()
+{
+ if (!mpViewContact)
+ mpViewContact = CreateObjectSpecificViewContact();
+
+ return *mpViewContact;
+}
+
+void SdrPageProperties::ImpRemoveStyleSheet()
+{
+ if(mpStyleSheet)
+ {
+ EndListening(*mpStyleSheet);
+ maProperties.SetParent(nullptr);
+ mpStyleSheet = nullptr;
+ }
+}
+
+void SdrPageProperties::ImpAddStyleSheet(SfxStyleSheet& rNewStyleSheet)
+{
+ if(mpStyleSheet != &rNewStyleSheet)
+ {
+ ImpRemoveStyleSheet();
+ mpStyleSheet = &rNewStyleSheet;
+ StartListening(rNewStyleSheet);
+ maProperties.SetParent(&rNewStyleSheet.GetItemSet());
+ }
+}
+
+static void ImpPageChange(SdrPage& rSdrPage)
+{
+ rSdrPage.ActionChanged();
+ rSdrPage.getSdrModelFromSdrPage().SetChanged();
+ SdrHint aHint(SdrHintKind::PageOrderChange, &rSdrPage);
+ rSdrPage.getSdrModelFromSdrPage().Broadcast(aHint);
+}
+
+SdrPageProperties::SdrPageProperties(SdrPage& rSdrPage)
+: mpSdrPage(&rSdrPage),
+ mpStyleSheet(nullptr),
+ maProperties(
+ mpSdrPage->getSdrModelFromSdrPage().GetItemPool(),
+ svl::Items<XATTR_FILL_FIRST, XATTR_FILL_LAST>)
+{
+ if(!rSdrPage.IsMasterPage())
+ {
+ maProperties.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+}
+
+SdrPageProperties::~SdrPageProperties()
+{
+ ImpRemoveStyleSheet();
+}
+
+void SdrPageProperties::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ switch(rHint.GetId())
+ {
+ case SfxHintId::DataChanged :
+ {
+ // notify change, broadcast
+ ImpPageChange(*mpSdrPage);
+ break;
+ }
+ case SfxHintId::Dying :
+ {
+ // Style needs to be forgotten
+ ImpRemoveStyleSheet();
+ break;
+ }
+ default: break;
+ }
+}
+
+bool SdrPageProperties::isUsedByModel() const
+{
+ assert(mpSdrPage);
+ return mpSdrPage->IsInserted();
+}
+
+
+void SdrPageProperties::PutItemSet(const SfxItemSet& rSet)
+{
+ OSL_ENSURE(!mpSdrPage->IsMasterPage(), "Item set at MasterPage Attributes (!)");
+ maProperties.Put(rSet);
+ ImpPageChange(*mpSdrPage);
+}
+
+void SdrPageProperties::PutItem(const SfxPoolItem& rItem)
+{
+ OSL_ENSURE(!mpSdrPage->IsMasterPage(), "Item set at MasterPage Attributes (!)");
+ maProperties.Put(rItem);
+ ImpPageChange(*mpSdrPage);
+}
+
+void SdrPageProperties::ClearItem(const sal_uInt16 nWhich)
+{
+ maProperties.ClearItem(nWhich);
+ ImpPageChange(*mpSdrPage);
+}
+
+void SdrPageProperties::SetStyleSheet(SfxStyleSheet* pStyleSheet)
+{
+ if(pStyleSheet)
+ {
+ ImpAddStyleSheet(*pStyleSheet);
+ }
+ else
+ {
+ ImpRemoveStyleSheet();
+ }
+
+ ImpPageChange(*mpSdrPage);
+}
+
+void SdrPageProperties::SetTheme(std::unique_ptr<svx::Theme> pTheme)
+{
+ mpTheme = std::move(pTheme);
+
+ if (mpTheme && mpSdrPage->IsMasterPage())
+ {
+ SdrModel& rModel = mpSdrPage->getSdrModelFromSdrPage();
+ sal_uInt16 nPageCount = rModel.GetPageCount();
+ for (sal_uInt16 nPage = 0; nPage < nPageCount; ++nPage)
+ {
+ SdrPage* pPage = rModel.GetPage(nPage);
+ if (!pPage->TRG_HasMasterPage() || &pPage->TRG_GetMasterPage() != mpSdrPage)
+ {
+ continue;
+ }
+
+ mpTheme->UpdateSdrPage(pPage);
+ }
+ }
+}
+
+svx::Theme* SdrPageProperties::GetTheme() { return mpTheme.get(); }
+
+void SdrPageProperties::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrPageProperties"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+
+ if (mpTheme)
+ {
+ mpTheme->dumpAsXml(pWriter);
+ }
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+SdrPage::SdrPage(SdrModel& rModel, bool bMasterPage)
+: mrSdrModelFromSdrPage(rModel),
+ mnWidth(10),
+ mnHeight(10),
+ mnBorderLeft(0),
+ mnBorderUpper(0),
+ mnBorderRight(0),
+ mnBorderLower(0),
+ mpLayerAdmin(new SdrLayerAdmin(&rModel.GetLayerAdmin())),
+ nPageNum(0),
+ mbMaster(bMasterPage),
+ mbInserted(false),
+ mbObjectsNotPersistent(false),
+ mbPageBorderOnlyLeftRight(false)
+{
+ mpSdrPageProperties.reset(new SdrPageProperties(*this));
+}
+
+SdrPage::~SdrPage()
+{
+ if( mxUnoPage.is() ) try
+ {
+ uno::Reference< lang::XComponent > xPageComponent( mxUnoPage, uno::UNO_QUERY_THROW );
+ mxUnoPage.clear();
+ xPageComponent->dispose();
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ // tell all the registered PageUsers that the page is in destruction
+ // This causes some (all?) PageUsers to remove themselves from the list
+ // of page users. Therefore we have to use a copy of the list for the
+ // iteration.
+ sdr::PageUserVector aListCopy (maPageUsers.begin(), maPageUsers.end());
+ for(sdr::PageUser* pPageUser : aListCopy)
+ {
+ DBG_ASSERT(pPageUser, "SdrPage::~SdrPage: corrupt PageUser list (!)");
+ pPageUser->PageInDestruction(*this);
+ }
+
+ // Clear the vector. This means that user do not need to call RemovePageUser()
+ // when they get called from PageInDestruction().
+ maPageUsers.clear();
+
+ mpLayerAdmin.reset();
+
+ TRG_ClearMasterPage();
+
+ mpViewContact.reset();
+ mpSdrPageProperties.reset();
+}
+
+void SdrPage::lateInit(const SdrPage& rSrcPage)
+{
+ assert(!mpViewContact);
+ assert(!mxUnoPage.is());
+
+ // copy all the local parameters to make this instance
+ // a valid copy of source page before copying and inserting
+ // the contained objects
+ mbMaster = rSrcPage.mbMaster;
+ mbPageBorderOnlyLeftRight = rSrcPage.mbPageBorderOnlyLeftRight;
+ mnWidth = rSrcPage.mnWidth;
+ mnHeight = rSrcPage.mnHeight;
+ mnBorderLeft = rSrcPage.mnBorderLeft;
+ mnBorderUpper = rSrcPage.mnBorderUpper;
+ mnBorderRight = rSrcPage.mnBorderRight;
+ mnBorderLower = rSrcPage.mnBorderLower;
+ mbBackgroundFullSize = rSrcPage.mbBackgroundFullSize;
+ nPageNum = rSrcPage.nPageNum;
+
+ if(rSrcPage.TRG_HasMasterPage())
+ {
+ TRG_SetMasterPage(rSrcPage.TRG_GetMasterPage());
+ TRG_SetMasterPageVisibleLayers(rSrcPage.TRG_GetMasterPageVisibleLayers());
+ }
+ else
+ {
+ TRG_ClearMasterPage();
+ }
+
+ mbObjectsNotPersistent = rSrcPage.mbObjectsNotPersistent;
+
+ {
+ mpSdrPageProperties.reset(new SdrPageProperties(*this));
+
+ if(!IsMasterPage())
+ {
+ mpSdrPageProperties->PutItemSet(rSrcPage.getSdrPageProperties().GetItemSet());
+ }
+
+ mpSdrPageProperties->SetStyleSheet(rSrcPage.getSdrPageProperties().GetStyleSheet());
+ }
+
+ // Now copy the contained objects
+ if(0 != rSrcPage.GetObjCount())
+ {
+ CopyObjects(rSrcPage);
+ }
+}
+
+rtl::Reference<SdrPage> SdrPage::CloneSdrPage(SdrModel& rTargetModel) const
+{
+ rtl::Reference<SdrPage> pClonedPage(new SdrPage(rTargetModel));
+ pClonedPage->lateInit(*this);
+ return pClonedPage;
+}
+
+void SdrPage::SetSize(const Size& aSiz)
+{
+ bool bChanged(false);
+
+ if(aSiz.Width() != mnWidth)
+ {
+ mnWidth = aSiz.Width();
+ bChanged = true;
+ }
+
+ if(aSiz.Height() != mnHeight)
+ {
+ mnHeight = aSiz.Height();
+ bChanged = true;
+ }
+
+ if(bChanged)
+ {
+ SetChanged();
+ }
+}
+
+Size SdrPage::GetSize() const
+{
+ return Size(mnWidth,mnHeight);
+}
+
+tools::Long SdrPage::GetWidth() const
+{
+ return mnWidth;
+}
+
+void SdrPage::SetOrientation(Orientation eOri)
+{
+ // square: handle like portrait format
+ Size aSiz(GetSize());
+ if (aSiz.Width()!=aSiz.Height()) {
+ if ((eOri==Orientation::Portrait) == (aSiz.Width()>aSiz.Height())) {
+ // coverity[swapped_arguments : FALSE] - this is in the correct order
+ SetSize(Size(aSiz.Height(),aSiz.Width()));
+ }
+ }
+}
+
+Orientation SdrPage::GetOrientation() const
+{
+ // square: handle like portrait format
+ Orientation eRet=Orientation::Portrait;
+ Size aSiz(GetSize());
+ if (aSiz.Width()>aSiz.Height()) eRet=Orientation::Landscape;
+ return eRet;
+}
+
+tools::Long SdrPage::GetHeight() const
+{
+ return mnHeight;
+}
+
+void SdrPage::SetBorder(sal_Int32 nLft, sal_Int32 nUpp, sal_Int32 nRgt, sal_Int32 nLwr)
+{
+ bool bChanged(false);
+
+ if(mnBorderLeft != nLft)
+ {
+ mnBorderLeft = nLft;
+ bChanged = true;
+ }
+
+ if(mnBorderUpper != nUpp)
+ {
+ mnBorderUpper = nUpp;
+ bChanged = true;
+ }
+
+ if(mnBorderRight != nRgt)
+ {
+ mnBorderRight = nRgt;
+ bChanged = true;
+ }
+
+ if(mnBorderLower != nLwr)
+ {
+ mnBorderLower = nLwr;
+ bChanged = true;
+ }
+
+ if(bChanged)
+ {
+ SetChanged();
+ }
+}
+
+void SdrPage::SetLeftBorder(sal_Int32 nBorder)
+{
+ if(mnBorderLeft != nBorder)
+ {
+ mnBorderLeft = nBorder;
+ SetChanged();
+ }
+}
+
+void SdrPage::SetUpperBorder(sal_Int32 nBorder)
+{
+ if(mnBorderUpper != nBorder)
+ {
+ mnBorderUpper = nBorder;
+ SetChanged();
+ }
+}
+
+void SdrPage::SetRightBorder(sal_Int32 nBorder)
+{
+ if(mnBorderRight != nBorder)
+ {
+ mnBorderRight=nBorder;
+ SetChanged();
+ }
+}
+
+void SdrPage::SetLowerBorder(sal_Int32 nBorder)
+{
+ if(mnBorderLower != nBorder)
+ {
+ mnBorderLower=nBorder;
+ SetChanged();
+ }
+}
+
+sal_Int32 SdrPage::GetLeftBorder() const
+{
+ return mnBorderLeft;
+}
+
+sal_Int32 SdrPage::GetUpperBorder() const
+{
+ return mnBorderUpper;
+}
+
+sal_Int32 SdrPage::GetRightBorder() const
+{
+ return mnBorderRight;
+}
+
+sal_Int32 SdrPage::GetLowerBorder() const
+{
+ return mnBorderLower;
+}
+
+void SdrPage::SetBackgroundFullSize(bool const bIn)
+{
+ if (bIn != mbBackgroundFullSize)
+ {
+ mbBackgroundFullSize = bIn;
+ SetChanged();
+ }
+}
+
+bool SdrPage::IsBackgroundFullSize() const
+{
+ return mbBackgroundFullSize;
+}
+
+// #i68775# React on PageNum changes (from Model in most cases)
+void SdrPage::SetPageNum(sal_uInt16 nNew)
+{
+ if(nNew != nPageNum)
+ {
+ // change
+ nPageNum = nNew;
+
+ // notify visualisations, also notifies e.g. buffered MasterPages
+ ActionChanged();
+ }
+}
+
+sal_uInt16 SdrPage::GetPageNum() const
+{
+ if (!mbInserted)
+ return 0;
+
+ if (mbMaster) {
+ if (getSdrModelFromSdrPage().IsMPgNumsDirty())
+ getSdrModelFromSdrPage().RecalcPageNums(true);
+ } else {
+ if (getSdrModelFromSdrPage().IsPagNumsDirty())
+ getSdrModelFromSdrPage().RecalcPageNums(false);
+ }
+ return nPageNum;
+}
+
+void SdrPage::SetChanged()
+{
+ // For test purposes, use the new ViewContact for change
+ // notification now.
+ ActionChanged();
+ getSdrModelFromSdrPage().SetChanged();
+}
+
+SdrPage* SdrPage::getSdrPageFromSdrObjList() const
+{
+ return const_cast< SdrPage* >(this);
+}
+
+// MasterPage interface
+
+void SdrPage::TRG_SetMasterPage(SdrPage& rNew)
+{
+ if(mpMasterPageDescriptor && &(mpMasterPageDescriptor->GetUsedPage()) == &rNew)
+ return;
+
+ if(mpMasterPageDescriptor)
+ TRG_ClearMasterPage();
+
+ mpMasterPageDescriptor.reset(new sdr::MasterPageDescriptor(*this, rNew));
+ GetViewContact().ActionChanged();
+}
+
+void SdrPage::TRG_ClearMasterPage()
+{
+ if(mpMasterPageDescriptor)
+ {
+ SetChanged();
+
+ // the flushViewObjectContacts() will do needed invalidates by deleting the involved VOCs
+ mpMasterPageDescriptor->GetUsedPage().GetViewContact().flushViewObjectContacts();
+
+ mpMasterPageDescriptor.reset();
+ }
+}
+
+SdrPage& SdrPage::TRG_GetMasterPage() const
+{
+ DBG_ASSERT(mpMasterPageDescriptor != nullptr, "TRG_GetMasterPage(): No MasterPage available. Use TRG_HasMasterPage() before access (!)");
+ return mpMasterPageDescriptor->GetUsedPage();
+}
+
+const SdrLayerIDSet& SdrPage::TRG_GetMasterPageVisibleLayers() const
+{
+ DBG_ASSERT(mpMasterPageDescriptor != nullptr, "TRG_GetMasterPageVisibleLayers(): No MasterPage available. Use TRG_HasMasterPage() before access (!)");
+ return mpMasterPageDescriptor->GetVisibleLayers();
+}
+
+void SdrPage::TRG_SetMasterPageVisibleLayers(const SdrLayerIDSet& rNew)
+{
+ DBG_ASSERT(mpMasterPageDescriptor != nullptr, "TRG_SetMasterPageVisibleLayers(): No MasterPage available. Use TRG_HasMasterPage() before access (!)");
+ mpMasterPageDescriptor->SetVisibleLayers(rNew);
+}
+
+sdr::contact::ViewContact& SdrPage::TRG_GetMasterPageDescriptorViewContact() const
+{
+ DBG_ASSERT(mpMasterPageDescriptor != nullptr, "TRG_GetMasterPageDescriptorViewContact(): No MasterPage available. Use TRG_HasMasterPage() before access (!)");
+ return mpMasterPageDescriptor->GetViewContact();
+}
+
+// used from SdrModel::RemoveMasterPage
+void SdrPage::TRG_ImpMasterPageRemoved(const SdrPage& rRemovedPage)
+{
+ if(TRG_HasMasterPage())
+ {
+ if(&TRG_GetMasterPage() == &rRemovedPage)
+ {
+ TRG_ClearMasterPage();
+ }
+ }
+}
+
+void SdrPage::MakePageObjectsNamesUnique()
+{
+ std::unordered_set<OUString> aNameSet;
+ for (size_t no(0); no < GetObjCount(); ++no)
+ {
+ SdrObject* pObj(GetObj(no));
+ if(nullptr != pObj)
+ {
+ if (!pObj->GetName().isEmpty())
+ {
+ pObj->MakeNameUnique(aNameSet);
+ SdrObjList* pSdrObjList = pObj->GetSubList(); // group
+ if (pSdrObjList)
+ {
+ SdrObject* pListObj;
+ SdrObjListIter aIter(pSdrObjList, SdrIterMode::DeepWithGroups);
+ while (aIter.IsMore())
+ {
+ pListObj = aIter.Next();
+ pListObj->MakeNameUnique(aNameSet);
+ }
+ }
+ }
+ }
+ }
+}
+
+const SdrPageGridFrameList* SdrPage::GetGridFrameList(const SdrPageView* /*pPV*/, const tools::Rectangle* /*pRect*/) const
+{
+ return nullptr;
+}
+
+const SdrLayerAdmin& SdrPage::GetLayerAdmin() const
+{
+ return *mpLayerAdmin;
+}
+
+SdrLayerAdmin& SdrPage::GetLayerAdmin()
+{
+ return *mpLayerAdmin;
+}
+
+OUString SdrPage::GetLayoutName() const
+{
+ return OUString();
+}
+
+void SdrPage::SetInserted( bool bIns )
+{
+ if( mbInserted == bIns )
+ return;
+
+ mbInserted = bIns;
+
+ // #i120437# go over whole hierarchy, not only over object level null (seen from grouping)
+ SdrObjListIter aIter(this, SdrIterMode::DeepNoGroups);
+
+ while ( aIter.IsMore() )
+ {
+ SdrObject* pObj = aIter.Next();
+ if ( auto pOleObj = dynamic_cast<SdrOle2Obj* >(pObj) )
+ {
+ if( mbInserted )
+ pOleObj->Connect();
+ else
+ pOleObj->Disconnect();
+ }
+ }
+}
+
+void SdrPage::SetUnoPage(uno::Reference<drawing::XDrawPage> const& xNewPage)
+{
+ mxUnoPage = xNewPage;
+}
+
+uno::Reference< uno::XInterface > const & SdrPage::getUnoPage()
+{
+ if( !mxUnoPage.is() )
+ {
+ // create one
+ mxUnoPage = createUnoPage();
+ }
+
+ return mxUnoPage;
+}
+
+uno::Reference< uno::XInterface > SdrPage::createUnoPage()
+{
+ css::uno::Reference< css::uno::XInterface > xInt =
+ static_cast<cppu::OWeakObject*>( new SvxFmDrawPage( this ) );
+ return xInt;
+}
+
+SfxStyleSheet* SdrPage::GetTextStyleSheetForObject( SdrObject* pObj ) const
+{
+ return pObj->GetStyleSheet();
+}
+
+/** returns an averaged background color of this page */
+// #i75566# GetBackgroundColor -> GetPageBackgroundColor and bScreenDisplay hint value
+Color SdrPage::GetPageBackgroundColor( SdrPageView const * pView, bool bScreenDisplay ) const
+{
+ Color aColor;
+
+ if(bScreenDisplay && (!pView || pView->GetApplicationDocumentColor() == COL_AUTO))
+ {
+ svtools::ColorConfig aColorConfig;
+ aColor = aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor;
+ }
+ else
+ {
+ aColor = pView->GetApplicationDocumentColor();
+ }
+
+ const SfxItemSet* pBackgroundFill = &getSdrPageProperties().GetItemSet();
+
+ if(!IsMasterPage() && TRG_HasMasterPage())
+ {
+ if(drawing::FillStyle_NONE == pBackgroundFill->Get(XATTR_FILLSTYLE).GetValue())
+ {
+ pBackgroundFill = &TRG_GetMasterPage().getSdrPageProperties().GetItemSet();
+ }
+ }
+
+ GetDraftFillColor(*pBackgroundFill, aColor);
+
+ return aColor;
+}
+
+/** *deprecated, use GetBackgroundColor with SdrPageView */
+Color SdrPage::GetPageBackgroundColor() const
+// #i75566# GetBackgroundColor -> GetPageBackgroundColor
+{
+ return GetPageBackgroundColor( nullptr );
+}
+
+/** this method returns true if the object from the ViewObjectContact should
+ be visible on this page while rendering.
+ bEdit selects if visibility test is for an editing view or a final render,
+ like printing.
+*/
+bool SdrPage::checkVisibility(
+ const sdr::contact::ViewObjectContact& /*rOriginal*/,
+ const sdr::contact::DisplayInfo& /*rDisplayInfo*/,
+ bool /*bEdit*/)
+{
+ // this will be handled in the application if needed
+ return true;
+}
+
+void SdrPage::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrPage"));
+ SdrObjList::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("width"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("value"), "%s",
+ BAD_CAST(OString::number(mnWidth).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("height"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("value"), "%s",
+ BAD_CAST(OString::number(mnHeight).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+
+ if (mpSdrPageProperties)
+ {
+ mpSdrPageProperties->dumpAsXml(pWriter);
+ }
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+// DrawContact support: Methods for handling Page changes
+void SdrPage::ActionChanged()
+{
+ // Do necessary ViewContact actions
+ GetViewContact().ActionChanged();
+
+ // #i48535# also handle MasterPage change
+ if(TRG_HasMasterPage())
+ {
+ TRG_GetMasterPageDescriptorViewContact().ActionChanged();
+ }
+}
+
+SdrPageProperties& SdrPage::getSdrPageProperties()
+{
+ return *mpSdrPageProperties;
+}
+
+const SdrPageProperties& SdrPage::getSdrPageProperties() const
+{
+ return *mpSdrPageProperties;
+}
+
+const SdrPageProperties* SdrPage::getCorrectSdrPageProperties() const
+{
+ if(mpMasterPageDescriptor)
+ {
+ return mpMasterPageDescriptor->getCorrectSdrPageProperties();
+ }
+ else
+ {
+ return &getSdrPageProperties();
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdpagv.cxx b/svx/source/svdraw/svdpagv.cxx
new file mode 100644
index 000000000..60cd8cfe8
--- /dev/null
+++ b/svx/source/svdraw/svdpagv.cxx
@@ -0,0 +1,894 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdpagv.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdview.hxx>
+
+#include <svx/svdobj.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdtypes.hxx>
+
+#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
+
+#include <algorithm>
+
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <basegfx/range/b2irectangle.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::com::sun::star;
+
+// interface to SdrPageWindow
+
+SdrPageWindow* SdrPageView::FindPageWindow(const SdrPaintWindow& rPaintWindow) const
+{
+ for(auto & a : maPageWindows)
+ {
+ if(&(a->GetPaintWindow()) == &rPaintWindow)
+ {
+ return a.get();
+ }
+ }
+
+ return nullptr;
+}
+
+const SdrPageWindow* SdrPageView::FindPatchedPageWindow( const OutputDevice& _rOutDev ) const
+{
+ for ( auto const & pPageWindow : maPageWindows )
+ {
+ const SdrPaintWindow& rPaintWindow( pPageWindow->GetOriginalPaintWindow() ? *pPageWindow->GetOriginalPaintWindow() : pPageWindow->GetPaintWindow() );
+ if ( &rPaintWindow.GetOutputDevice() == &_rOutDev )
+ {
+ return pPageWindow.get();
+ }
+ }
+
+ return nullptr;
+}
+
+SdrPageWindow* SdrPageView::FindPageWindow(const OutputDevice& rOutDev) const
+{
+ for ( auto const & pPageWindow : maPageWindows )
+ {
+ if(&(pPageWindow->GetPaintWindow().GetOutputDevice()) == &rOutDev)
+ {
+ return pPageWindow.get();
+ }
+ }
+
+ return nullptr;
+}
+
+SdrPageWindow* SdrPageView::GetPageWindow(sal_uInt32 nIndex) const
+{
+ return maPageWindows[nIndex].get();
+}
+
+SdrPageView::SdrPageView(SdrPage* pPage1, SdrView& rNewView)
+: mrView(rNewView),
+ // col_auto color lets the view takes the default SvxColorConfig entry
+ maDocumentColor( COL_AUTO ),
+ maBackgroundColor( COL_AUTO ), // #i48367# also react on autocolor
+ mpPreparedPageWindow(nullptr) // #i72752#
+{
+ mpPage = pPage1;
+
+ if(mpPage)
+ {
+ aPgOrg.setX(mpPage->GetLeftBorder() );
+ aPgOrg.setY(mpPage->GetUpperBorder() );
+ }
+ // For example, in the case of charts, there is a LayerAdmin, but it has no valid values. Therefore
+ // a solution like pLayerAdmin->getVisibleLayersODF(aLayerVisi) is not possible. So use the
+ // generic SetAll() for now.
+ aLayerVisi.SetAll();
+ aLayerPrn.SetAll();
+
+ mbHasMarked = false;
+ mbVisible = false;
+ pCurrentList = nullptr;
+ pCurrentGroup = nullptr;
+ SetCurrentGroupAndList(nullptr, mpPage);
+
+ for(sal_uInt32 a(0); a < rNewView.PaintWindowCount(); a++)
+ {
+ AddPaintWindowToPageView(*rNewView.GetPaintWindow(a));
+ }
+}
+
+SdrPageView::~SdrPageView()
+{
+}
+
+void SdrPageView::AddPaintWindowToPageView(SdrPaintWindow& rPaintWindow)
+{
+ if(!FindPageWindow(rPaintWindow))
+ {
+ maPageWindows.emplace_back(new SdrPageWindow(*this, rPaintWindow));
+ }
+}
+
+void SdrPageView::RemovePaintWindowFromPageView(SdrPaintWindow& rPaintWindow)
+{
+ auto it = std::find_if(maPageWindows.begin(), maPageWindows.end(),
+ [&rPaintWindow](const std::unique_ptr<SdrPageWindow>& rpWindow) {
+ return &(rpWindow->GetPaintWindow()) == &rPaintWindow;
+ });
+ if (it != maPageWindows.end())
+ maPageWindows.erase(it);
+}
+
+css::uno::Reference< css::awt::XControlContainer > SdrPageView::GetControlContainer( const OutputDevice& _rDevice ) const
+{
+ css::uno::Reference< css::awt::XControlContainer > xReturn;
+ const SdrPageWindow* pCandidate = FindPatchedPageWindow( _rDevice );
+
+ if ( pCandidate )
+ xReturn = pCandidate->GetControlContainer();
+
+ return xReturn;
+}
+
+void SdrPageView::ModelHasChanged()
+{
+ if (GetCurrentGroup()!=nullptr) CheckCurrentGroup();
+}
+
+bool SdrPageView::IsReadOnly() const
+{
+ return (nullptr == GetPage() || GetView().GetModel()->IsReadOnly() || GetPage()->IsReadOnly() || GetObjList()->IsReadOnly());
+}
+
+void SdrPageView::Show()
+{
+ if(!IsVisible())
+ {
+ mbVisible = true;
+
+ for(sal_uInt32 a(0); a < GetView().PaintWindowCount(); a++)
+ {
+ AddPaintWindowToPageView(*GetView().GetPaintWindow(a));
+ }
+ }
+}
+
+void SdrPageView::Hide()
+{
+ if(IsVisible())
+ {
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ InvalidateAllWin();
+ }
+ mbVisible = false;
+ maPageWindows.clear();
+ }
+}
+
+tools::Rectangle SdrPageView::GetPageRect() const
+{
+ if (GetPage()==nullptr) return tools::Rectangle();
+ return tools::Rectangle(Point(),Size(GetPage()->GetWidth()+1,GetPage()->GetHeight()+1));
+}
+
+void SdrPageView::InvalidateAllWin()
+{
+ if(IsVisible() && GetPage())
+ {
+ tools::Rectangle aRect(Point(0,0),Size(GetPage()->GetWidth()+1,GetPage()->GetHeight()+1));
+ aRect.Union(GetPage()->GetAllObjBoundRect());
+ GetView().InvalidateAllWin(aRect);
+ }
+}
+
+
+void SdrPageView::PrePaint()
+{
+ const sal_uInt32 nCount(PageWindowCount());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ SdrPageWindow* pCandidate = GetPageWindow(a);
+
+ if(pCandidate)
+ {
+ pCandidate->PrePaint();
+ }
+ }
+}
+
+void SdrPageView::CompleteRedraw(
+ SdrPaintWindow& rPaintWindow, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector )
+{
+ if(!GetPage())
+ return;
+
+ SdrPageWindow* pPageWindow = FindPageWindow(rPaintWindow);
+ std::unique_ptr<SdrPageWindow> pTempPageWindow;
+
+ if(!pPageWindow)
+ {
+ // create temp PageWindow
+ pTempPageWindow.reset(new SdrPageWindow(*this, rPaintWindow));
+ pPageWindow = pTempPageWindow.get();
+ }
+
+ // do the redraw
+ pPageWindow->PrepareRedraw(rReg);
+ pPageWindow->RedrawAll(pRedirector);
+}
+
+
+// #i74769# use SdrPaintWindow directly
+
+void SdrPageView::setPreparedPageWindow(SdrPageWindow* pKnownTarget)
+{
+ // #i72752# remember prepared SdrPageWindow
+ mpPreparedPageWindow = pKnownTarget;
+}
+
+void SdrPageView::DrawLayer(SdrLayerID nID, OutputDevice* pGivenTarget,
+ sdr::contact::ViewObjectContactRedirector* pRedirector,
+ const tools::Rectangle& rRect, basegfx::B2IRectangle const*const pPageFrame)
+{
+ if(!GetPage())
+ return;
+
+ if(pGivenTarget)
+ {
+ SdrPageWindow* pKnownTarget = FindPageWindow(*pGivenTarget);
+
+ if(pKnownTarget)
+ {
+ // paint known target
+ pKnownTarget->RedrawLayer(&nID, pRedirector, pPageFrame);
+ }
+ else
+ {
+ // #i72752# DrawLayer() uses an OutputDevice different from BeginDrawLayer. This happens
+ // e.g. when SW paints a single text line in text edit mode. Try to use it
+ SdrPageWindow* pPreparedTarget = mpPreparedPageWindow;
+
+ if(pPreparedTarget)
+ {
+ // if we have a prepared target, do not use a new SdrPageWindow since this
+ // works but is expensive. Just use a temporary PaintWindow
+ SdrPaintWindow aTemporaryPaintWindow(mrView, *pGivenTarget);
+
+ // Copy existing paint region to use the same as prepared in BeginDrawLayer
+ SdrPaintWindow& rExistingPaintWindow = pPreparedTarget->GetPaintWindow();
+ const vcl::Region& rExistingRegion = rExistingPaintWindow.GetRedrawRegion();
+ bool bUseRect(false);
+ if (!rRect.IsEmpty())
+ {
+ vcl::Region r(rExistingRegion);
+ r.Intersect(rRect);
+ // fdo#74435: FIXME: visibility check broken if empty
+ if (!r.IsEmpty())
+ bUseRect = true;
+ }
+ if (!bUseRect)
+ aTemporaryPaintWindow.SetRedrawRegion(rExistingRegion);
+ else
+ aTemporaryPaintWindow.SetRedrawRegion(vcl::Region(rRect));
+
+ // patch the ExistingPageWindow
+ auto pPreviousWindow = pPreparedTarget->patchPaintWindow(aTemporaryPaintWindow);
+ // unpatch window when leaving the scope
+ const ::comphelper::ScopeGuard aGuard(
+ [&pPreviousWindow, &pPreparedTarget]() { pPreparedTarget->unpatchPaintWindow(pPreviousWindow); } );
+ // redraw the layer
+ pPreparedTarget->RedrawLayer(&nID, pRedirector, pPageFrame);
+ }
+ else
+ {
+ OSL_FAIL("SdrPageView::DrawLayer: Creating temporary SdrPageWindow (ObjectContact), this should never be needed (!)");
+
+ // None of the known OutputDevices is the target of this paint, use
+ // a temporary SdrPageWindow for this Redraw.
+ SdrPaintWindow aTemporaryPaintWindow(mrView, *pGivenTarget);
+ SdrPageWindow aTemporaryPageWindow(*this, aTemporaryPaintWindow);
+
+ // #i72752#
+ // Copy existing paint region if other PageWindows exist, this was created by
+ // PrepareRedraw() from BeginDrawLayer(). Needs to be used e.g. when suddenly SW
+ // paints into an unknown device other than the view was created for (e.g. VirtualDevice)
+ if(PageWindowCount())
+ {
+ SdrPageWindow* pExistingPageWindow = GetPageWindow(0);
+ SdrPaintWindow& rExistingPaintWindow = pExistingPageWindow->GetPaintWindow();
+ const vcl::Region& rExistingRegion = rExistingPaintWindow.GetRedrawRegion();
+ aTemporaryPaintWindow.SetRedrawRegion(rExistingRegion);
+ }
+
+ aTemporaryPageWindow.RedrawLayer(&nID, pRedirector, nullptr);
+ }
+ }
+ }
+ else
+ {
+ // paint in all known windows
+ for(sal_uInt32 a(0); a < PageWindowCount(); a++)
+ {
+ SdrPageWindow* pTarget = GetPageWindow(a);
+ pTarget->RedrawLayer(&nID, pRedirector, nullptr);
+ }
+ }
+}
+
+void SdrPageView::SetDesignMode( bool _bDesignMode ) const
+{
+ for ( sal_uInt32 i = 0; i < PageWindowCount(); ++i )
+ {
+ const SdrPageWindow& rPageViewWindow = *GetPageWindow(i);
+ rPageViewWindow.SetDesignMode( _bDesignMode );
+ }
+}
+
+
+void SdrPageView::DrawPageViewGrid(OutputDevice& rOut, const tools::Rectangle& rRect, Color aColor)
+{
+ if (GetPage()==nullptr)
+ return;
+
+ tools::Long nx1=GetView().maGridBig.Width();
+ tools::Long nx2=GetView().maGridFin.Width();
+ tools::Long ny1=GetView().maGridBig.Height();
+ tools::Long ny2=GetView().maGridFin.Height();
+
+ if (nx1==0) nx1=nx2;
+ if (nx2==0) nx2=nx1;
+ if (ny1==0) ny1=ny2;
+ if (ny2==0) ny2=ny1;
+ if (nx1==0) { nx1=ny1; nx2=ny2; }
+ if (ny1==0) { ny1=nx1; ny2=nx2; }
+ if (nx1<0) nx1=-nx1;
+ if (nx2<0) nx2=-nx2;
+ if (ny1<0) ny1=-ny1;
+ if (ny2<0) ny2=-ny2;
+
+ if (nx1==0)
+ return;
+
+ // no more global output size, use window size instead to decide grid sizes
+ tools::Long nScreenWdt = rOut.GetOutputSizePixel().Width();
+
+ tools::Long nMinDotPix=2;
+ tools::Long nMinLinPix=4;
+
+ if (nScreenWdt>=1600)
+ {
+ nMinDotPix=4;
+ nMinLinPix=8;
+ }
+ else if (nScreenWdt>=1024)
+ {
+ nMinDotPix=3;
+ nMinLinPix=6;
+ }
+ else
+ { // e. g. 640x480
+ nMinDotPix=2;
+ nMinLinPix=4;
+ }
+ Size aMinDotDist(rOut.PixelToLogic(Size(nMinDotPix,nMinDotPix)));
+ Size aMinLinDist(rOut.PixelToLogic(Size(nMinLinPix,nMinLinPix)));
+ bool bHoriSolid=nx2<aMinDotDist.Width();
+ bool bVertSolid=ny2<aMinDotDist.Height();
+ // enlarge line offset (minimum 4 pixels)
+ // enlarge by: *2 *5 *10 *20 *50 *100 ...
+ int nTgl=0;
+ tools::Long nVal0=nx1;
+ while (nx1<aMinLinDist.Width())
+ {
+ tools::Long a=nx1;
+
+ if (nTgl==0) nx1*=2;
+ if (nTgl==1) nx1=nVal0*5; // => nx1*=2.5
+ if (nTgl==2) nx1*=2;
+
+ nVal0=a;
+ nTgl++; if (nTgl>=3) nTgl=0;
+ }
+ nTgl=0;
+ nVal0=ny1;
+ while (ny1<aMinLinDist.Height())
+ {
+ tools::Long a=ny1;
+
+ if (nTgl==0) ny1*=2;
+ if (nTgl==1) ny1=nVal0*5; // => ny1*=2.5
+ if (nTgl==2) ny1*=2;
+
+ nVal0=a;
+ nTgl++;
+
+ if (nTgl>=3) nTgl=0;
+ }
+
+ bool bHoriFine=nx2<nx1;
+ bool bVertFine=ny2<ny1;
+ bool bHoriLines=bHoriSolid || bHoriFine || !bVertFine;
+ bool bVertLines=bVertSolid || bVertFine;
+
+ Color aOriginalLineColor( rOut.GetLineColor() );
+ rOut.SetLineColor( aColor );
+
+ bool bMap0=rOut.IsMapModeEnabled();
+
+ tools::Long nWrX=0;
+ tools::Long nWrY=0;
+ Point aOrg(aPgOrg);
+ tools::Long x1 = 0;
+ tools::Long x2 = 0;
+ if (GetPage()->GetWidth() < 0) // ScDrawPage of RTL sheet
+ {
+ x1 = GetPage()->GetWidth() + GetPage()->GetLeftBorder() + 1;
+ x2 = - GetPage()->GetRightBorder() - 1;
+ }
+ else
+ {
+ x1 = GetPage()->GetLeftBorder() + 1;
+ x2 = GetPage()->GetWidth() - GetPage()->GetRightBorder() - 1;
+ }
+ tools::Long y1 = GetPage()->GetUpperBorder() + 1;
+ tools::Long y2 = GetPage()->GetHeight() - GetPage()->GetLowerBorder() - 1;
+ const SdrPageGridFrameList* pFrames=GetPage()->GetGridFrameList(this,nullptr);
+
+ sal_uInt16 nGridPaintCnt=1;
+ if (pFrames!=nullptr) nGridPaintCnt=pFrames->GetCount();
+ for (sal_uInt16 nGridPaintNum=0; nGridPaintNum<nGridPaintCnt; nGridPaintNum++) {
+ if (pFrames!=nullptr) {
+ const SdrPageGridFrame& rGF=(*pFrames)[nGridPaintNum];
+ nWrX=rGF.GetPaperRect().Left();
+ nWrY=rGF.GetPaperRect().Top();
+ x1=rGF.GetUserArea().Left();
+ x2=rGF.GetUserArea().Right();
+ y1=rGF.GetUserArea().Top();
+ y2=rGF.GetUserArea().Bottom();
+ aOrg=rGF.GetUserArea().TopLeft();
+ aOrg-=rGF.GetPaperRect().TopLeft();
+ }
+ if (!rRect.IsEmpty()) {
+ Size a1PixSiz(rOut.PixelToLogic(Size(1,1)));
+ tools::Long nX1Pix=a1PixSiz.Width(); // add 1 pixel of tolerance
+ tools::Long nY1Pix=a1PixSiz.Height();
+ if (x1<rRect.Left() -nX1Pix) x1=rRect.Left() -nX1Pix;
+ if (x2>rRect.Right() +nX1Pix) x2=rRect.Right() +nX1Pix;
+ if (y1<rRect.Top() -nY1Pix) y1=rRect.Top() -nY1Pix;
+ if (y2>rRect.Bottom()+nY1Pix) y2=rRect.Bottom()+nY1Pix;
+ }
+
+ tools::Long xBigOrg=aOrg.X()+nWrX;
+ while (xBigOrg>=x1) xBigOrg-=nx1;
+ while (xBigOrg<x1) xBigOrg+=nx1;
+ tools::Long xFinOrg=xBigOrg;
+ while (xFinOrg>=x1) xFinOrg-=nx2;
+ while (xFinOrg<x1) xFinOrg+=nx2;
+
+ tools::Long yBigOrg=aOrg.Y()+nWrY;
+ while (yBigOrg>=y1) yBigOrg-=ny1;
+ while (yBigOrg<y1) yBigOrg+=ny1;
+ tools::Long yFinOrg=yBigOrg;
+ while (yFinOrg>=y1) yFinOrg-=ny2;
+ while (yFinOrg<y1) yFinOrg+=ny2;
+
+ if( x1 <= x2 && y1 <= y2 )
+ {
+ if( bHoriLines )
+ {
+ DrawGridFlags nGridFlags = ( bHoriSolid ? DrawGridFlags::HorzLines : DrawGridFlags::Dots );
+ sal_uInt16 nSteps = sal_uInt16(nx1 / nx2);
+ sal_uInt32 nRestPerStepMul1000 = nSteps ? ( ((nx1 * 1000)/ nSteps) - (nx2 * 1000) ) : 0;
+ sal_uInt32 nStepOffset = 0;
+ sal_uInt16 nPointOffset = 0;
+
+ for(sal_uInt16 a=0;a<nSteps;a++)
+ {
+ // draw
+ rOut.DrawGrid(
+ tools::Rectangle( xFinOrg + (a * nx2) + nPointOffset, yBigOrg, x2, y2 ),
+ Size( nx1, ny1 ), nGridFlags );
+
+ // do a step
+ nStepOffset += nRestPerStepMul1000;
+ while(nStepOffset >= 1000)
+ {
+ nStepOffset -= 1000;
+ nPointOffset++;
+ }
+ }
+ }
+
+ if( bVertLines )
+ {
+ DrawGridFlags nGridFlags = ( bVertSolid ? DrawGridFlags::VertLines : DrawGridFlags::Dots );
+ sal_uInt16 nSteps = sal_uInt16(ny1 / ny2);
+ sal_uInt32 nRestPerStepMul1000 = nSteps ? ( ((ny1 * 1000L)/ nSteps) - (ny2 * 1000L) ) : 0;
+ sal_uInt32 nStepOffset = 0;
+ sal_uInt16 nPointOffset = 0;
+
+ for(sal_uInt16 a=0;a<nSteps;a++)
+ {
+ // draw
+ rOut.DrawGrid(
+ tools::Rectangle( xBigOrg, yFinOrg + (a * ny2) + nPointOffset, x2, y2 ),
+ Size( nx1, ny1 ), nGridFlags );
+
+ // do a step
+ nStepOffset += nRestPerStepMul1000;
+ while(nStepOffset >= 1000)
+ {
+ nStepOffset -= 1000;
+ nPointOffset++;
+ }
+ }
+ }
+ }
+ }
+
+ rOut.EnableMapMode(bMap0);
+ rOut.SetLineColor(aOriginalLineColor);
+}
+
+void SdrPageView::AdjHdl()
+{
+ GetView().AdjustMarkHdl();
+}
+
+void SdrPageView::SetLayer(const OUString& rName, SdrLayerIDSet& rBS, bool bJa)
+{
+ if(!GetPage())
+ return;
+
+ SdrLayerID nID = GetPage()->GetLayerAdmin().GetLayerID(rName);
+
+ if(SDRLAYER_NOTFOUND != nID)
+ rBS.Set(nID, bJa);
+}
+
+bool SdrPageView::IsLayer(const OUString& rName, const SdrLayerIDSet& rBS) const
+{
+ if(!GetPage())
+ return false;
+
+ bool bRet(false);
+
+ if (!rName.isEmpty())
+ {
+ SdrLayerID nId = GetPage()->GetLayerAdmin().GetLayerID(rName);
+
+ if(SDRLAYER_NOTFOUND != nId)
+ {
+ bRet = rBS.IsSet(nId);
+ }
+ }
+
+ return bRet;
+}
+
+bool SdrPageView::IsObjMarkable(SdrObject const * pObj) const
+{
+ if (!pObj)
+ return false;
+ if (pObj->IsMarkProtect())
+ return false; // excluded from selection?
+ if (!pObj->IsVisible())
+ return false; // only visible are selectable
+ if (!pObj->IsInserted())
+ return false; // Obj deleted?
+ if (auto pObjGroup = dynamic_cast<const SdrObjGroup*>(pObj))
+ {
+ // If object is a Group object, visibility may depend on
+ // multiple layers. If one object is markable, Group is markable.
+ SdrObjList* pObjList = pObjGroup->GetSubList();
+
+ if (pObjList && pObjList->GetObjCount())
+ {
+ for (size_t a = 0; a < pObjList->GetObjCount(); ++a)
+ {
+ SdrObject* pCandidate = pObjList->GetObj(a);
+ // call recursively
+ if (IsObjMarkable(pCandidate))
+ return true;
+ }
+ return false;
+ }
+ else
+ {
+ // #i43302#
+ // Allow empty groups to be selected to be able to delete them
+ return true;
+ }
+ }
+ if (!pObj->Is3DObj() && pObj->getSdrPageFromSdrObject() != GetPage())
+ {
+ // Obj suddenly in different Page
+ return false;
+ }
+
+ // the layer has to be visible and must not be locked
+ SdrLayerID nL = pObj->GetLayer();
+ if (!aLayerVisi.IsSet(nL))
+ return false;
+ if (aLayerLock.IsSet(nL))
+ return false;
+ return true;
+}
+
+void SdrPageView::SetPageOrigin(const Point& rOrg)
+{
+ if (rOrg!=aPgOrg) {
+ aPgOrg=rOrg;
+ if (GetView().IsGridVisible()) {
+ InvalidateAllWin();
+ }
+ }
+}
+
+void SdrPageView::ImpInvalidateHelpLineArea(sal_uInt16 nNum) const
+{
+ if (!(GetView().IsHlplVisible() && nNum<aHelpLines.GetCount())) return;
+
+ const SdrHelpLine& rHL=aHelpLines[nNum];
+
+ for(sal_uInt32 a(0); a < GetView().PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = GetView().GetPaintWindow(a);
+
+ if(pCandidate->OutputToWindow())
+ {
+ OutputDevice& rOutDev = pCandidate->GetOutputDevice();
+ tools::Rectangle aR(rHL.GetBoundRect(rOutDev));
+ Size aSiz(rOutDev.PixelToLogic(Size(1,1)));
+ aR.AdjustLeft( -(aSiz.Width()) );
+ aR.AdjustRight(aSiz.Width() );
+ aR.AdjustTop( -(aSiz.Height()) );
+ aR.AdjustBottom(aSiz.Height() );
+ const_cast<SdrView&>(GetView()).InvalidateOneWin(rOutDev, aR);
+ }
+ }
+}
+
+void SdrPageView::SetHelpLines(const SdrHelpLineList& rHLL)
+{
+ aHelpLines=rHLL;
+ InvalidateAllWin();
+}
+
+void SdrPageView::SetHelpLine(sal_uInt16 nNum, const SdrHelpLine& rNewHelpLine)
+{
+ if (nNum >= aHelpLines.GetCount() || aHelpLines[nNum] == rNewHelpLine)
+ return;
+
+ bool bNeedRedraw = true;
+ if (aHelpLines[nNum].GetKind()==rNewHelpLine.GetKind()) {
+ switch (rNewHelpLine.GetKind()) {
+ case SdrHelpLineKind::Vertical : if (aHelpLines[nNum].GetPos().X()==rNewHelpLine.GetPos().X()) bNeedRedraw = false; break;
+ case SdrHelpLineKind::Horizontal: if (aHelpLines[nNum].GetPos().Y()==rNewHelpLine.GetPos().Y()) bNeedRedraw = false; break;
+ default: break;
+ } // switch
+ }
+ if (bNeedRedraw) ImpInvalidateHelpLineArea(nNum);
+ aHelpLines[nNum]=rNewHelpLine;
+ if (bNeedRedraw) ImpInvalidateHelpLineArea(nNum);
+}
+
+void SdrPageView::DeleteHelpLine(sal_uInt16 nNum)
+{
+ if (nNum<aHelpLines.GetCount()) {
+ ImpInvalidateHelpLineArea(nNum);
+ aHelpLines.Delete(nNum);
+ }
+}
+
+void SdrPageView::InsertHelpLine(const SdrHelpLine& rHL)
+{
+ sal_uInt16 nNum = aHelpLines.GetCount();
+ aHelpLines.Insert(rHL,nNum);
+ if (GetView().IsHlplVisible())
+ ImpInvalidateHelpLineArea(nNum);
+}
+
+// set current group and list
+void SdrPageView::SetCurrentGroupAndList(SdrObject* pNewGroup, SdrObjList* pNewList)
+{
+ if(pCurrentGroup != pNewGroup)
+ {
+ pCurrentGroup = pNewGroup;
+ }
+ if(pCurrentList != pNewList)
+ {
+ pCurrentList = pNewList;
+ }
+}
+
+bool SdrPageView::EnterGroup(SdrObject* pObj)
+{
+ if(!pObj || !pObj->IsGroupObject())
+ return false;
+
+ // Don't allow enter Diagrams
+ if(nullptr != pObj && pObj->isDiagram())
+ return false;
+
+ const bool bGlueInvalidate(GetView().ImpIsGlueVisible());
+
+ if (bGlueInvalidate)
+ {
+ GetView().GlueInvalidate();
+ }
+
+ // deselect all
+ GetView().UnmarkAll();
+
+ // set current group and list
+ SdrObjList* pNewObjList = pObj->GetSubList();
+ SetCurrentGroupAndList(pObj, pNewObjList);
+
+ // select contained object if only one object is contained,
+ // else select nothing and let the user decide what to do next
+ if(pNewObjList && pNewObjList->GetObjCount() == 1)
+ {
+ SdrObject* pFirstObject = pNewObjList->GetObj(0);
+
+ if(GetView().GetSdrPageView())
+ {
+ GetView().MarkObj(pFirstObject, GetView().GetSdrPageView());
+ }
+ }
+
+ // build new handles
+ GetView().AdjustMarkHdl();
+
+ // invalidate only when view wants to visualize group entering
+ InvalidateAllWin();
+
+ if (bGlueInvalidate)
+ {
+ GetView().GlueInvalidate();
+ }
+
+ return true;
+}
+
+void SdrPageView::LeaveOneGroup()
+{
+ SdrObject* pLastGroup = GetCurrentGroup();
+ if (!pLastGroup)
+ return;
+
+ bool bGlueInvalidate = GetView().ImpIsGlueVisible();
+
+ if(bGlueInvalidate)
+ GetView().GlueInvalidate();
+
+ SdrObject* pParentGroup = pLastGroup->getParentSdrObjectFromSdrObject();
+ SdrObjList* pParentList = GetPage();
+
+ if(pParentGroup)
+ pParentList = pParentGroup->GetSubList();
+
+ // deselect everything
+ GetView().UnmarkAll();
+
+ // allocations, pCurrentGroup and pCurrentList need to be set
+ SetCurrentGroupAndList(pParentGroup, pParentList);
+
+ // select the group we just left
+ if (GetView().GetSdrPageView())
+ GetView().MarkObj(pLastGroup, GetView().GetSdrPageView());
+
+ GetView().AdjustMarkHdl();
+
+ // invalidate only if view wants to visualize group entering
+ InvalidateAllWin();
+
+ if(bGlueInvalidate)
+ GetView().GlueInvalidate();
+}
+
+void SdrPageView::LeaveAllGroup()
+{
+ SdrObject* pLastGroup = GetCurrentGroup();
+ if (!pLastGroup)
+ return;
+
+ bool bGlueInvalidate = GetView().ImpIsGlueVisible();
+
+ if(bGlueInvalidate)
+ GetView().GlueInvalidate();
+
+ // deselect everything
+ GetView().UnmarkAll();
+
+ // allocations, pCurrentGroup and pCurrentList always need to be set
+ SetCurrentGroupAndList(nullptr, GetPage());
+
+ // find and select uppermost group
+ while (pLastGroup->getParentSdrObjectFromSdrObject())
+ pLastGroup = pLastGroup->getParentSdrObjectFromSdrObject();
+
+ if (GetView().GetSdrPageView())
+ GetView().MarkObj(pLastGroup, GetView().GetSdrPageView());
+
+ GetView().AdjustMarkHdl();
+
+ // invalidate only when view wants to visualize group entering
+ InvalidateAllWin();
+
+ if(bGlueInvalidate)
+ GetView().GlueInvalidate();
+}
+
+sal_uInt16 SdrPageView::GetEnteredLevel() const
+{
+ sal_uInt16 nCount=0;
+ SdrObject* pGrp=GetCurrentGroup();
+ while (pGrp!=nullptr) {
+ nCount++;
+ pGrp=pGrp->getParentSdrObjectFromSdrObject();
+ }
+ return nCount;
+}
+
+void SdrPageView::CheckCurrentGroup()
+{
+ SdrObject* pGrp(GetCurrentGroup());
+
+ while(nullptr != pGrp &&
+ (!pGrp->IsInserted() || nullptr == pGrp->getParentSdrObjListFromSdrObject() || nullptr == pGrp->getSdrPageFromSdrObject()))
+ {
+ // anything outside of the borders?
+ pGrp = pGrp->getParentSdrObjectFromSdrObject();
+ }
+
+ if(pGrp != GetCurrentGroup())
+ {
+ if(nullptr != pGrp)
+ {
+ EnterGroup(pGrp);
+ }
+ else
+ {
+ LeaveAllGroup();
+ }
+ }
+}
+
+// Set background color for svx at SdrPageViews
+void SdrPageView::SetApplicationBackgroundColor(Color aBackgroundColor)
+{
+ maBackgroundColor = aBackgroundColor;
+}
+
+
+// Set document color for svx at SdrPageViews
+void SdrPageView::SetApplicationDocumentColor(Color aDocumentColor)
+{
+ maDocumentColor = aDocumentColor;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdpdf.cxx b/svx/source/svdraw/svdpdf.cxx
new file mode 100644
index 000000000..7beba145a
--- /dev/null
+++ b/svx/source/svdraw/svdpdf.cxx
@@ -0,0 +1,1052 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svdpdf.hxx>
+
+#include <tools/UnitConversion.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/vectorgraphicdata.hxx>
+
+#include <math.h>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xflclit.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/colritem.hxx>
+#include <vcl/metric.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <svx/sdtditm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdetc.hxx>
+#include <svl/itemset.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <tools/helpers.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/xlndsit.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xlineit0.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdogrp.hxx>
+#include <vcl/dibtools.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+using namespace com::sun::star;
+
+ImpSdrPdfImport::ImpSdrPdfImport(SdrModel& rModel, SdrLayerID nLay, const tools::Rectangle& rRect,
+ Graphic const& rGraphic)
+ : mpVD(VclPtr<VirtualDevice>::Create())
+ , maScaleRect(rRect)
+ , mnMapScalingOfs(0)
+ , mpModel(&rModel)
+ , mnLayer(nLay)
+ , mnLineWidth(0)
+ , maDash(css::drawing::DashStyle_RECT, 0, 0, 0, 0, 0)
+ , mbMov(false)
+ , mbSize(false)
+ , maOfs(0, 0)
+ , mfScaleX(1.0)
+ , mfScaleY(1.0)
+ , maScaleX(1.0)
+ , maScaleY(1.0)
+ , mbFntDirty(true)
+ , mbLastObjWasPolyWithoutLine(false)
+ , mbNoLine(false)
+ , mbNoFill(false)
+ , mnPageCount(0)
+ , mdPageHeightPts(0)
+ , mpPDFium(vcl::pdf::PDFiumLibrary::get())
+{
+ mpVD->EnableOutput(false);
+ mpVD->SetLineColor();
+ mpVD->SetFillColor();
+ maOldLineColor.SetRed(mpVD->GetLineColor().GetRed() + 1);
+ mpLineAttr = std::make_unique<SfxItemSetFixed<XATTR_LINE_FIRST, XATTR_LINE_LAST>>(
+ rModel.GetItemPool());
+ mpFillAttr = std::make_unique<SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>>(
+ rModel.GetItemPool());
+ mpTextAttr
+ = std::make_unique<SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END>>(rModel.GetItemPool());
+
+ checkClip();
+
+ // Load the buffer using pdfium.
+ auto const& rVectorGraphicData = rGraphic.getVectorGraphicData();
+ auto* pData = rVectorGraphicData->getBinaryDataContainer().getData();
+ sal_Int32 nSize = rVectorGraphicData->getBinaryDataContainer().getSize();
+ mpPdfDocument = mpPDFium ? mpPDFium->openDocument(pData, nSize, OString()) : nullptr;
+ if (!mpPdfDocument)
+ return;
+
+ mnPageCount = mpPdfDocument->getPageCount();
+}
+
+ImpSdrPdfImport::~ImpSdrPdfImport() = default;
+
+void ImpSdrPdfImport::DoObjects(SvdProgressInfo* pProgrInfo, sal_uInt32* pActionsToReport,
+ int nPageIndex)
+{
+ const int nPageCount = mpPdfDocument->getPageCount();
+ if (!(nPageCount > 0 && nPageIndex >= 0 && nPageIndex < nPageCount))
+ return;
+
+ // Render next page.
+ auto pPdfPage = mpPdfDocument->openPage(nPageIndex);
+ if (!pPdfPage)
+ return;
+
+ basegfx::B2DSize dPageSize = mpPdfDocument->getPageSize(nPageIndex);
+
+ const double dPageWidth = dPageSize.getX();
+ const double dPageHeight = dPageSize.getY();
+
+ SetupPageScale(dPageWidth, dPageHeight);
+
+ // Load the page text to extract it when we get text elements.
+ auto pTextPage = pPdfPage->getTextPage();
+
+ const int nPageObjectCount = pPdfPage->getObjectCount();
+ if (pProgrInfo)
+ pProgrInfo->SetActionCount(nPageObjectCount);
+
+ for (int nPageObjectIndex = 0; nPageObjectIndex < nPageObjectCount; ++nPageObjectIndex)
+ {
+ auto pPageObject = pPdfPage->getObject(nPageObjectIndex);
+ ImportPdfObject(pPageObject, pTextPage, nPageObjectIndex);
+ if (pProgrInfo && pActionsToReport)
+ {
+ (*pActionsToReport)++;
+
+ if (*pActionsToReport >= 16)
+ {
+ if (!pProgrInfo->ReportActions(*pActionsToReport))
+ break;
+
+ *pActionsToReport = 0;
+ }
+ }
+ }
+}
+
+void ImpSdrPdfImport::SetupPageScale(const double dPageWidth, const double dPageHeight)
+{
+ mfScaleX = mfScaleY = 1.0;
+
+ // Store the page dimensions in Points.
+ mdPageHeightPts = dPageHeight;
+
+ Size aPageSize(convertPointToMm100(dPageWidth), convertPointToMm100(dPageHeight));
+
+ if (aPageSize.Width() && aPageSize.Height() && (!maScaleRect.IsEmpty()))
+ {
+ maOfs = maScaleRect.TopLeft();
+
+ if (aPageSize.Width() != (maScaleRect.GetWidth() - 1))
+ {
+ mfScaleX = static_cast<double>(maScaleRect.GetWidth() - 1)
+ / static_cast<double>(aPageSize.Width());
+ }
+
+ if (aPageSize.Height() != (maScaleRect.GetHeight() - 1))
+ {
+ mfScaleY = static_cast<double>(maScaleRect.GetHeight() - 1)
+ / static_cast<double>(aPageSize.Height());
+ }
+ }
+
+ mbMov = maOfs.X() != 0 || maOfs.Y() != 0;
+ mbSize = false;
+ maScaleX = Fraction(1, 1);
+ maScaleY = Fraction(1, 1);
+
+ if (aPageSize.Width() != (maScaleRect.GetWidth() - 1))
+ {
+ maScaleX = Fraction(maScaleRect.GetWidth() - 1, aPageSize.Width());
+ mbSize = true;
+ }
+
+ if (aPageSize.Height() != (maScaleRect.GetHeight() - 1))
+ {
+ maScaleY = Fraction(maScaleRect.GetHeight() - 1, aPageSize.Height());
+ mbSize = true;
+ }
+}
+
+size_t ImpSdrPdfImport::DoImport(SdrObjList& rOL, size_t nInsPos, int nPageNumber,
+ SvdProgressInfo* pProgrInfo)
+{
+ sal_uInt32 nActionsToReport(0);
+
+ // execute
+ DoObjects(pProgrInfo, &nActionsToReport, nPageNumber);
+
+ if (pProgrInfo)
+ {
+ pProgrInfo->ReportActions(nActionsToReport);
+ nActionsToReport = 0;
+ }
+
+ // MapMode scaling
+ MapScaling();
+
+ // To calculate the progress meter, we use GetActionSize()*3.
+ // However, maTmpList has a lower entry count limit than GetActionSize(),
+ // so the actions that were assumed were too much have to be re-added.
+ // nActionsToReport = (rMtf.GetActionSize() - maTmpList.size()) * 2;
+
+ // announce all currently unannounced rescales
+ if (pProgrInfo)
+ {
+ pProgrInfo->ReportRescales(nActionsToReport);
+ pProgrInfo->SetInsertCount(maTmpList.size());
+ }
+
+ nActionsToReport = 0;
+
+ // insert all objects cached in aTmpList now into rOL from nInsPos
+ nInsPos = std::min(nInsPos, rOL.GetObjCount());
+
+ for (SdrObject* pObj : maTmpList)
+ {
+ rOL.NbcInsertObject(pObj, nInsPos);
+ nInsPos++;
+
+ if (pProgrInfo)
+ {
+ nActionsToReport++;
+
+ if (nActionsToReport >= 32) // update all 32 actions
+ {
+ pProgrInfo->ReportInserts(nActionsToReport);
+ nActionsToReport = 0;
+ }
+ }
+ }
+
+ // report all remaining inserts for the last time
+ if (pProgrInfo)
+ {
+ pProgrInfo->ReportInserts(nActionsToReport);
+ }
+
+ return maTmpList.size();
+}
+
+void ImpSdrPdfImport::SetAttributes(SdrObject* pObj, bool bForceTextAttr)
+{
+ mbNoLine = false;
+ mbNoFill = false;
+ bool bLine(!bForceTextAttr);
+ bool bFill(!pObj || (pObj->IsClosedObj() && !bForceTextAttr));
+ bool bText(bForceTextAttr || (pObj && pObj->GetOutlinerParaObject()));
+
+ if (bLine)
+ {
+ if (mnLineWidth)
+ {
+ mpLineAttr->Put(XLineWidthItem(mnLineWidth));
+ }
+ else
+ {
+ mpLineAttr->Put(XLineWidthItem(0));
+ }
+
+ maOldLineColor = mpVD->GetLineColor();
+
+ if (mpVD->IsLineColor())
+ {
+ mpLineAttr->Put(XLineStyleItem(drawing::LineStyle_SOLID)); //TODO support dashed lines.
+ mpLineAttr->Put(XLineColorItem(OUString(), mpVD->GetLineColor()));
+ }
+ else
+ {
+ mpLineAttr->Put(XLineStyleItem(drawing::LineStyle_NONE));
+ }
+
+ mpLineAttr->Put(XLineJointItem(css::drawing::LineJoint_NONE));
+
+ // Add LineCap support
+ mpLineAttr->Put(XLineCapItem(gaLineCap));
+
+ if (((maDash.GetDots() && maDash.GetDotLen())
+ || (maDash.GetDashes() && maDash.GetDashLen()))
+ && maDash.GetDistance())
+ {
+ mpLineAttr->Put(XLineDashItem(OUString(), maDash));
+ }
+ else
+ {
+ mpLineAttr->Put(XLineDashItem(OUString(), XDash(css::drawing::DashStyle_RECT)));
+ }
+ }
+ else
+ {
+ mbNoLine = true;
+ }
+
+ if (bFill)
+ {
+ if (mpVD->IsFillColor())
+ {
+ mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ mpFillAttr->Put(XFillColorItem(OUString(), mpVD->GetFillColor()));
+ }
+ else
+ {
+ mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ }
+ else
+ {
+ mbNoFill = true;
+ }
+
+ if (bText && mbFntDirty)
+ {
+ vcl::Font aFnt(mpVD->GetFont());
+ const sal_uInt32 nHeight(FRound(aFnt.GetFontSize().Height() * mfScaleY));
+
+ mpTextAttr->Put(SvxFontItem(aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(),
+ aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO));
+ mpTextAttr->Put(SvxFontItem(aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(),
+ aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO_CJK));
+ mpTextAttr->Put(SvxFontItem(aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(),
+ aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO_CTL));
+ mpTextAttr->Put(SvxPostureItem(aFnt.GetItalic(), EE_CHAR_ITALIC));
+ mpTextAttr->Put(SvxWeightItem(aFnt.GetWeight(), EE_CHAR_WEIGHT));
+ mpTextAttr->Put(SvxFontHeightItem(nHeight, 100, EE_CHAR_FONTHEIGHT));
+ mpTextAttr->Put(SvxFontHeightItem(nHeight, 100, EE_CHAR_FONTHEIGHT_CJK));
+ mpTextAttr->Put(SvxFontHeightItem(nHeight, 100, EE_CHAR_FONTHEIGHT_CTL));
+ mpTextAttr->Put(SvxCharScaleWidthItem(100, EE_CHAR_FONTWIDTH));
+ mpTextAttr->Put(SvxUnderlineItem(aFnt.GetUnderline(), EE_CHAR_UNDERLINE));
+ mpTextAttr->Put(SvxOverlineItem(aFnt.GetOverline(), EE_CHAR_OVERLINE));
+ mpTextAttr->Put(SvxCrossedOutItem(aFnt.GetStrikeout(), EE_CHAR_STRIKEOUT));
+ mpTextAttr->Put(SvxShadowedItem(aFnt.IsShadow(), EE_CHAR_SHADOW));
+
+ // #i118485# Setting this item leads to problems (written #i118498# for this)
+ // mpTextAttr->Put(SvxAutoKernItem(aFnt.IsKerning(), EE_CHAR_KERNING));
+
+ mpTextAttr->Put(SvxWordLineModeItem(aFnt.IsWordLineMode(), EE_CHAR_WLM));
+ mpTextAttr->Put(SvxContourItem(aFnt.IsOutline(), EE_CHAR_OUTLINE));
+ mpTextAttr->Put(SvxColorItem(mpVD->GetTextColor(), EE_CHAR_COLOR));
+ //... svxfont textitem svditext
+ mbFntDirty = false;
+ }
+
+ if (!pObj)
+ return;
+
+ pObj->SetLayer(mnLayer);
+
+ if (bLine)
+ {
+ pObj->SetMergedItemSet(*mpLineAttr);
+ }
+
+ if (bFill)
+ {
+ pObj->SetMergedItemSet(*mpFillAttr);
+ }
+
+ if (bText)
+ {
+ pObj->SetMergedItemSet(*mpTextAttr);
+ pObj->SetMergedItem(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT));
+ }
+}
+
+void ImpSdrPdfImport::InsertObj(SdrObject* pObj, bool bScale)
+{
+ if (bScale && !maScaleRect.IsEmpty())
+ {
+ if (mbSize)
+ {
+ pObj->NbcResize(Point(), maScaleX, maScaleY);
+ }
+
+ if (mbMov)
+ {
+ pObj->NbcMove(Size(maOfs.X(), maOfs.Y()));
+ }
+ }
+
+ if (isClip())
+ {
+ const basegfx::B2DPolyPolygon aPoly(pObj->TakeXorPoly());
+ const basegfx::B2DRange aOldRange(aPoly.getB2DRange());
+ const SdrLayerID aOldLayer(pObj->GetLayer());
+ const SfxItemSet aOldItemSet(pObj->GetMergedItemSet());
+ const SdrGrafObj* pSdrGrafObj = dynamic_cast<SdrGrafObj*>(pObj);
+ const SdrTextObj* pSdrTextObj = dynamic_cast<SdrTextObj*>(pObj);
+
+ if (pSdrTextObj && pSdrTextObj->HasText())
+ {
+ // all text objects are created from ImportText and have no line or fill attributes, so
+ // it is okay to concentrate on the text itself
+ while (true)
+ {
+ const basegfx::B2DPolyPolygon aTextContour(pSdrTextObj->TakeContour());
+ const basegfx::B2DRange aTextRange(aTextContour.getB2DRange());
+ const basegfx::B2DRange aClipRange(maClip.getB2DRange());
+
+ // no overlap -> completely outside
+ if (!aClipRange.overlaps(aTextRange))
+ {
+ SdrObject::Free(pObj);
+ break;
+ }
+
+ // when the clip is a rectangle fast check for inside is possible
+ if (basegfx::utils::isRectangle(maClip) && aClipRange.isInside(aTextRange))
+ {
+ // completely inside ClipRect
+ break;
+ }
+
+ // here text needs to be clipped; to do so, convert to SdrObjects with polygons
+ // and add these recursively. Delete original object, do not add in this run
+ SdrObjectUniquePtr pConverted = pSdrTextObj->ConvertToPolyObj(true, true);
+ SdrObject::Free(pObj);
+
+ if (pConverted)
+ {
+ // recursively add created conversion; per definition this shall not
+ // contain further SdrTextObjs. Visit only non-group objects
+ SdrObjListIter aIter(*pConverted, SdrIterMode::DeepNoGroups);
+
+ // work with clones; the created conversion may contain group objects
+ // and when working with the original objects the loop itself could
+ // break and the cleanup later would be pretty complicated (only delete group
+ // objects, are these empty, ...?)
+ while (aIter.IsMore())
+ {
+ SdrObject* pCandidate = aIter.Next();
+ OSL_ENSURE(pCandidate && dynamic_cast<SdrObjGroup*>(pCandidate) == nullptr,
+ "SdrObjListIter with SdrIterMode::DeepNoGroups error (!)");
+ SdrObject* pNewClone(
+ pCandidate->CloneSdrObject(pCandidate->getSdrModelFromSdrObject()));
+
+ if (pNewClone)
+ {
+ InsertObj(pNewClone, false);
+ }
+ else
+ {
+ OSL_ENSURE(false, "SdrObject::Clone() failed (!)");
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ BitmapEx aBitmapEx;
+
+ if (pSdrGrafObj)
+ {
+ aBitmapEx = pSdrGrafObj->GetGraphic().GetBitmapEx();
+ }
+
+ SdrObject::Free(pObj);
+
+ if (!aOldRange.isEmpty())
+ {
+ // clip against ClipRegion
+ const basegfx::B2DPolyPolygon aNewPoly(basegfx::utils::clipPolyPolygonOnPolyPolygon(
+ aPoly, maClip, true, !aPoly.isClosed()));
+ const basegfx::B2DRange aNewRange(aNewPoly.getB2DRange());
+
+ if (!aNewRange.isEmpty())
+ {
+ pObj = new SdrPathObj(
+ *mpModel, aNewPoly.isClosed() ? SdrObjKind::Polygon : SdrObjKind::PolyLine,
+ aNewPoly);
+
+ pObj->SetLayer(aOldLayer);
+ pObj->SetMergedItemSet(aOldItemSet);
+
+ if (!aBitmapEx.IsEmpty())
+ {
+ // aNewRange is inside of aOldRange and defines which part of aBitmapEx is used
+ const double fScaleX(aBitmapEx.GetSizePixel().Width()
+ / (aOldRange.getWidth() ? aOldRange.getWidth() : 1.0));
+ const double fScaleY(
+ aBitmapEx.GetSizePixel().Height()
+ / (aOldRange.getHeight() ? aOldRange.getHeight() : 1.0));
+ basegfx::B2DRange aPixel(aNewRange);
+ basegfx::B2DHomMatrix aTrans;
+
+ aTrans.translate(-aOldRange.getMinX(), -aOldRange.getMinY());
+ aTrans.scale(fScaleX, fScaleY);
+ aPixel.transform(aTrans);
+
+ const Size aOrigSizePixel(aBitmapEx.GetSizePixel());
+ const Point aClipTopLeft(
+ basegfx::fround(floor(std::max(0.0, aPixel.getMinX()))),
+ basegfx::fround(floor(std::max(0.0, aPixel.getMinY()))));
+ const Size aClipSize(
+ basegfx::fround(ceil(std::min(
+ static_cast<double>(aOrigSizePixel.Width()), aPixel.getWidth()))),
+ basegfx::fround(
+ ceil(std::min(static_cast<double>(aOrigSizePixel.Height()),
+ aPixel.getHeight()))));
+ const BitmapEx aClippedBitmap(aBitmapEx, aClipTopLeft, aClipSize);
+
+ pObj->SetMergedItem(XFillStyleItem(drawing::FillStyle_BITMAP));
+ pObj->SetMergedItem(XFillBitmapItem(OUString(), Graphic(aClippedBitmap)));
+ pObj->SetMergedItem(XFillBmpTileItem(false));
+ pObj->SetMergedItem(XFillBmpStretchItem(true));
+ }
+ }
+ }
+ }
+ }
+
+ if (!pObj)
+ return;
+
+ // #i111954# check object for visibility
+ // used are SdrPathObj, SdrRectObj, SdrCircObj, SdrGrafObj
+ bool bVisible(false);
+
+ if (pObj->HasLineStyle())
+ {
+ bVisible = true;
+ }
+
+ if (!bVisible && pObj->HasFillStyle())
+ {
+ bVisible = true;
+ }
+
+ if (!bVisible)
+ {
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(pObj);
+
+ if (pTextObj && pTextObj->HasText())
+ {
+ bVisible = true;
+ }
+ }
+
+ if (!bVisible)
+ {
+ SdrGrafObj* pGrafObj = dynamic_cast<SdrGrafObj*>(pObj);
+
+ if (pGrafObj)
+ {
+ // this may be refined to check if the graphic really is visible. It
+ // is here to ensure that graphic objects without fill, line and text
+ // get created
+ bVisible = true;
+ }
+ }
+
+ if (!bVisible)
+ {
+ SdrObject::Free(pObj);
+ }
+ else
+ {
+ maTmpList.push_back(pObj);
+
+ if (dynamic_cast<SdrPathObj*>(pObj))
+ {
+ const bool bClosed(pObj->IsClosedObj());
+
+ mbLastObjWasPolyWithoutLine = mbNoLine && bClosed;
+ }
+ else
+ {
+ mbLastObjWasPolyWithoutLine = false;
+ }
+ }
+}
+
+bool ImpSdrPdfImport::CheckLastPolyLineAndFillMerge(const basegfx::B2DPolyPolygon& rPolyPolygon)
+{
+ // #i73407# reformulation to use new B2DPolygon classes
+ if (mbLastObjWasPolyWithoutLine)
+ {
+ SdrObject* pTmpObj = !maTmpList.empty() ? maTmpList[maTmpList.size() - 1] : nullptr;
+ SdrPathObj* pLastPoly = dynamic_cast<SdrPathObj*>(pTmpObj);
+
+ if (pLastPoly)
+ {
+ if (pLastPoly->GetPathPoly() == rPolyPolygon)
+ {
+ SetAttributes(nullptr);
+
+ if (!mbNoLine && mbNoFill)
+ {
+ pLastPoly->SetMergedItemSet(*mpLineAttr);
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+void ImpSdrPdfImport::checkClip()
+{
+ if (mpVD->IsClipRegion())
+ {
+ maClip = mpVD->GetClipRegion().GetAsB2DPolyPolygon();
+
+ if (isClip())
+ {
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(
+ mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
+
+ maClip.transform(aTransform);
+ }
+ }
+}
+
+bool ImpSdrPdfImport::isClip() const { return !maClip.getB2DRange().isEmpty(); }
+void ImpSdrPdfImport::ImportPdfObject(
+ std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+ std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage, int nPageObjectIndex)
+{
+ if (!pPageObject)
+ return;
+
+ const vcl::pdf::PDFPageObjectType ePageObjectType = pPageObject->getType();
+ switch (ePageObjectType)
+ {
+ case vcl::pdf::PDFPageObjectType::Text:
+ ImportText(pPageObject, pTextPage, nPageObjectIndex);
+ break;
+ case vcl::pdf::PDFPageObjectType::Path:
+ ImportPath(pPageObject, nPageObjectIndex);
+ break;
+ case vcl::pdf::PDFPageObjectType::Image:
+ ImportImage(pPageObject, nPageObjectIndex);
+ break;
+ case vcl::pdf::PDFPageObjectType::Shading:
+ SAL_WARN("sd.filter", "Got page object SHADING: " << nPageObjectIndex);
+ break;
+ case vcl::pdf::PDFPageObjectType::Form:
+ ImportForm(pPageObject, pTextPage, nPageObjectIndex);
+ break;
+ default:
+ SAL_WARN("sd.filter", "Unknown PDF page object #" << nPageObjectIndex << " of type: "
+ << static_cast<int>(ePageObjectType));
+ break;
+ }
+}
+
+void ImpSdrPdfImport::ImportForm(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+ std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage,
+ int /*nPageObjectIndex*/)
+{
+ // Get the form matrix to perform correct translation/scaling of the form sub-objects.
+ const basegfx::B2DHomMatrix aOldMatrix = maCurrentMatrix;
+
+ maCurrentMatrix = pPageObject->getMatrix();
+
+ const int nCount = pPageObject->getFormObjectCount();
+ for (int nIndex = 0; nIndex < nCount; ++nIndex)
+ {
+ auto pFormObject = pPageObject->getFormObject(nIndex);
+
+ ImportPdfObject(pFormObject, pTextPage, -1);
+ }
+
+ // Restore the old one.
+ maCurrentMatrix = aOldMatrix;
+}
+
+void ImpSdrPdfImport::ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+ std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage,
+ int /*nPageObjectIndex*/)
+{
+ basegfx::B2DRectangle aTextRect = pPageObject->getBounds();
+ basegfx::B2DHomMatrix aMatrix = pPageObject->getMatrix();
+
+ basegfx::B2DHomMatrix aTextMatrix(maCurrentMatrix);
+
+ aTextRect *= aTextMatrix;
+ const tools::Rectangle aRect = PointsToLogic(aTextRect.getMinX(), aTextRect.getMaxX(),
+ aTextRect.getMinY(), aTextRect.getMaxY());
+
+ OUString sText = pPageObject->getText(pTextPage);
+
+ const double dFontSize = pPageObject->getFontSize();
+ double dFontSizeH = fabs(std::hypot(aMatrix.a(), aMatrix.c()) * dFontSize);
+ double dFontSizeV = fabs(std::hypot(aMatrix.b(), aMatrix.d()) * dFontSize);
+
+ dFontSizeH = convertPointToMm100(dFontSizeH);
+ dFontSizeV = convertPointToMm100(dFontSizeV);
+
+ const Size aFontSize(dFontSizeH, dFontSizeV);
+ vcl::Font aFnt = mpVD->GetFont();
+ if (aFontSize != aFnt.GetFontSize())
+ {
+ aFnt.SetFontSize(aFontSize);
+ mpVD->SetFont(aFnt);
+ mbFntDirty = true;
+ }
+
+ OUString sFontName = pPageObject->getFontName();
+ if (!sFontName.isEmpty() && sFontName != aFnt.GetFamilyName())
+ {
+ aFnt.SetFamilyName(sFontName);
+ mpVD->SetFont(aFnt);
+ mbFntDirty = true;
+ }
+
+ Color aTextColor(COL_TRANSPARENT);
+ bool bFill = false;
+ bool bUse = true;
+ switch (pPageObject->getTextRenderMode())
+ {
+ case vcl::pdf::PDFTextRenderMode::Fill:
+ case vcl::pdf::PDFTextRenderMode::FillClip:
+ case vcl::pdf::PDFTextRenderMode::FillStroke:
+ case vcl::pdf::PDFTextRenderMode::FillStrokeClip:
+ bFill = true;
+ break;
+ case vcl::pdf::PDFTextRenderMode::Stroke:
+ case vcl::pdf::PDFTextRenderMode::StrokeClip:
+ case vcl::pdf::PDFTextRenderMode::Unknown:
+ break;
+ case vcl::pdf::PDFTextRenderMode::Invisible:
+ case vcl::pdf::PDFTextRenderMode::Clip:
+ bUse = false;
+ break;
+ }
+ if (bUse)
+ {
+ Color aColor = bFill ? pPageObject->getFillColor() : pPageObject->getStrokeColor();
+ if (aColor != COL_TRANSPARENT)
+ aTextColor = aColor.GetRGBColor();
+ }
+
+ if (aTextColor != mpVD->GetTextColor())
+ {
+ mpVD->SetTextColor(aTextColor);
+ mbFntDirty = true;
+ }
+
+ InsertTextObject(aRect.TopLeft(), aRect.GetSize(), sText);
+}
+
+void ImpSdrPdfImport::InsertTextObject(const Point& rPos, const Size& rSize, const OUString& rStr)
+{
+ // calc text box size, add 5% to make it fit safely
+
+ FontMetric aFontMetric(mpVD->GetFontMetric());
+ vcl::Font aFont(mpVD->GetFont());
+ TextAlign eAlignment(aFont.GetAlignment());
+
+ // sal_Int32 nTextWidth = static_cast<sal_Int32>(mpVD->GetTextWidth(rStr) * mfScaleX);
+ sal_Int32 nTextHeight = static_cast<sal_Int32>(mpVD->GetTextHeight() * mfScaleY);
+
+ Point aPosition(FRound(rPos.X() * mfScaleX + maOfs.X()),
+ FRound(rPos.Y() * mfScaleY + maOfs.Y()));
+ Size aSize(FRound(rSize.Width() * mfScaleX), FRound(rSize.Height() * mfScaleY));
+
+ if (eAlignment == ALIGN_BASELINE)
+ aPosition.AdjustY(-FRound(aFontMetric.GetAscent() * mfScaleY));
+ else if (eAlignment == ALIGN_BOTTOM)
+ aPosition.AdjustY(-nTextHeight);
+
+ tools::Rectangle aTextRect(aPosition, aSize);
+ SdrRectObj* pText = new SdrRectObj(*mpModel, SdrObjKind::Text, aTextRect);
+
+ pText->SetMergedItem(makeSdrTextUpperDistItem(0));
+ pText->SetMergedItem(makeSdrTextLowerDistItem(0));
+ pText->SetMergedItem(makeSdrTextRightDistItem(0));
+ pText->SetMergedItem(makeSdrTextLeftDistItem(0));
+
+ if (aFont.GetAverageFontWidth())
+ {
+ pText->ClearMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH);
+ pText->SetMergedItem(makeSdrTextAutoGrowHeightItem(false));
+ // don't let the margins eat the space needed for the text
+ pText->SetMergedItem(SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_ALLLINES));
+ }
+ else
+ {
+ pText->SetMergedItem(makeSdrTextAutoGrowWidthItem(true));
+ }
+
+ pText->SetLayer(mnLayer);
+ pText->NbcSetText(rStr);
+ SetAttributes(pText, true);
+ pText->SetSnapRect(aTextRect);
+
+ if (!aFont.IsTransparent())
+ {
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aAttr(*mpFillAttr->GetPool());
+ aAttr.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ aAttr.Put(XFillColorItem(OUString(), aFont.GetFillColor()));
+ pText->SetMergedItemSet(aAttr);
+ }
+ Degree100 nAngle = to<Degree100>(aFont.GetOrientation());
+ if (nAngle)
+ pText->SdrAttrObj::NbcRotate(aPosition, nAngle);
+ InsertObj(pText, false);
+}
+
+void ImpSdrPdfImport::MapScaling()
+{
+ const size_t nCount(maTmpList.size());
+ const MapMode& rMap = mpVD->GetMapMode();
+ Point aMapOrg(rMap.GetOrigin());
+ bool bMov2(aMapOrg.X() != 0 || aMapOrg.Y() != 0);
+
+ if (bMov2)
+ {
+ for (size_t i = mnMapScalingOfs; i < nCount; i++)
+ {
+ SdrObject* pObj = maTmpList[i];
+
+ pObj->NbcMove(Size(aMapOrg.X(), aMapOrg.Y()));
+ }
+ }
+
+ mnMapScalingOfs = nCount;
+}
+
+void ImpSdrPdfImport::ImportImage(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+ int /*nPageObjectIndex*/)
+{
+ std::unique_ptr<vcl::pdf::PDFiumBitmap> bitmap = pPageObject->getImageBitmap();
+ if (!bitmap)
+ {
+ SAL_WARN("sd.filter", "Failed to get IMAGE");
+ return;
+ }
+
+ const vcl::pdf::PDFBitmapType format = bitmap->getFormat();
+ if (format == vcl::pdf::PDFBitmapType::Unknown)
+ {
+ SAL_WARN("sd.filter", "Failed to get IMAGE format");
+ return;
+ }
+
+ const unsigned char* pBuf = bitmap->getBuffer();
+ const int nWidth = bitmap->getWidth();
+ const int nHeight = bitmap->getHeight();
+ const int nStride = bitmap->getStride();
+ BitmapEx aBitmap(Size(nWidth, nHeight), vcl::PixelFormat::N24_BPP);
+
+ switch (format)
+ {
+ case vcl::pdf::PDFBitmapType::BGR:
+ ReadRawDIB(aBitmap, pBuf, ScanlineFormat::N24BitTcBgr, nHeight, nStride);
+ break;
+ case vcl::pdf::PDFBitmapType::BGRx:
+ ReadRawDIB(aBitmap, pBuf, ScanlineFormat::N32BitTcRgba, nHeight, nStride);
+ break;
+ case vcl::pdf::PDFBitmapType::BGRA:
+ ReadRawDIB(aBitmap, pBuf, ScanlineFormat::N32BitTcBgra, nHeight, nStride);
+ break;
+ default:
+ SAL_WARN("sd.filter", "Got IMAGE width: " << nWidth << ", height: " << nHeight
+ << ", stride: " << nStride
+ << ", format: " << static_cast<int>(format));
+ break;
+ }
+
+ basegfx::B2DRectangle aBounds = pPageObject->getBounds();
+ float left = aBounds.getMinX();
+ // Upside down.
+ float bottom = aBounds.getMinY();
+ float right = aBounds.getMaxX();
+ // Upside down.
+ float top = aBounds.getMaxY();
+ tools::Rectangle aRect = PointsToLogic(left, right, top, bottom);
+ aRect.AdjustRight(1);
+ aRect.AdjustBottom(1);
+
+ SdrGrafObj* pGraf = new SdrGrafObj(*mpModel, Graphic(aBitmap), aRect);
+
+ // This action is not creating line and fill, set directly, do not use SetAttributes(..)
+ pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
+ InsertObj(pGraf);
+}
+
+void ImpSdrPdfImport::ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject,
+ int /*nPageObjectIndex*/)
+{
+ auto aPathMatrix = pPageObject->getMatrix();
+
+ aPathMatrix *= maCurrentMatrix;
+
+ basegfx::B2DPolyPolygon aPolyPoly;
+ basegfx::B2DPolygon aPoly;
+ std::vector<basegfx::B2DPoint> aBezier;
+
+ const int nSegments = pPageObject->getPathSegmentCount();
+ for (int nSegmentIndex = 0; nSegmentIndex < nSegments; ++nSegmentIndex)
+ {
+ auto pPathSegment = pPageObject->getPathSegment(nSegmentIndex);
+ if (pPathSegment != nullptr)
+ {
+ basegfx::B2DPoint aB2DPoint = pPathSegment->getPoint();
+ aB2DPoint *= aPathMatrix;
+
+ const bool bClose = pPathSegment->isClosed();
+ if (bClose)
+ aPoly.setClosed(bClose); // TODO: Review
+
+ Point aPoint = PointsToLogic(aB2DPoint.getX(), aB2DPoint.getY());
+ aB2DPoint.setX(aPoint.X());
+ aB2DPoint.setY(aPoint.Y());
+
+ const vcl::pdf::PDFSegmentType eSegmentType = pPathSegment->getType();
+ switch (eSegmentType)
+ {
+ case vcl::pdf::PDFSegmentType::Lineto:
+ aPoly.append(aB2DPoint);
+ break;
+
+ case vcl::pdf::PDFSegmentType::Bezierto:
+ aBezier.emplace_back(aB2DPoint.getX(), aB2DPoint.getY());
+ if (aBezier.size() == 3)
+ {
+ aPoly.appendBezierSegment(aBezier[0], aBezier[1], aBezier[2]);
+ aBezier.clear();
+ }
+ break;
+
+ case vcl::pdf::PDFSegmentType::Moveto:
+ // New Poly.
+ if (aPoly.count() > 0)
+ {
+ aPolyPoly.append(aPoly, 1);
+ aPoly.clear();
+ }
+
+ aPoly.append(aB2DPoint);
+ break;
+
+ case vcl::pdf::PDFSegmentType::Unknown:
+ default:
+ SAL_WARN("sd.filter", "Unknown path segment type in PDF: "
+ << static_cast<int>(eSegmentType));
+ break;
+ }
+ }
+ }
+
+ if (aBezier.size() == 3)
+ {
+ aPoly.appendBezierSegment(aBezier[0], aBezier[1], aBezier[2]);
+ aBezier.clear();
+ }
+
+ if (aPoly.count() > 0)
+ {
+ aPolyPoly.append(aPoly, 1);
+ aPoly.clear();
+ }
+
+ const basegfx::B2DHomMatrix aTransform(
+ basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
+ aPolyPoly.transform(aTransform);
+
+ float fWidth = pPageObject->getStrokeWidth();
+ const double dWidth = 0.5 * fabs(std::hypot(aPathMatrix.a(), aPathMatrix.c()) * fWidth);
+ mnLineWidth = convertPointToMm100(dWidth);
+
+ vcl::pdf::PDFFillMode nFillMode = vcl::pdf::PDFFillMode::Alternate;
+ bool bStroke = true; // Assume we have to draw, unless told otherwise.
+ if (pPageObject->getDrawMode(nFillMode, bStroke))
+ {
+ if (nFillMode == vcl::pdf::PDFFillMode::Alternate)
+ mpVD->SetDrawMode(DrawModeFlags::Default);
+ else if (nFillMode == vcl::pdf::PDFFillMode::Winding)
+ mpVD->SetDrawMode(DrawModeFlags::Default);
+ else
+ mpVD->SetDrawMode(DrawModeFlags::NoFill);
+ }
+
+ mpVD->SetFillColor(pPageObject->getFillColor());
+
+ if (bStroke)
+ {
+ mpVD->SetLineColor(pPageObject->getStrokeColor());
+ }
+ else
+ mpVD->SetLineColor(COL_TRANSPARENT);
+
+ if (!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(aPolyPoly))
+ {
+ SdrPathObj* pPath = new SdrPathObj(*mpModel, SdrObjKind::Polygon, aPolyPoly);
+ SetAttributes(pPath);
+ InsertObj(pPath, false);
+ }
+}
+
+Point ImpSdrPdfImport::PointsToLogic(double x, double y) const
+{
+ y = correctVertOrigin(y);
+
+ Point aPos(convertPointToMm100(x), convertPointToMm100(y));
+ return aPos;
+}
+
+tools::Rectangle ImpSdrPdfImport::PointsToLogic(double left, double right, double top,
+ double bottom) const
+{
+ top = correctVertOrigin(top);
+ bottom = correctVertOrigin(bottom);
+
+ Point aPos(convertPointToMm100(left), convertPointToMm100(top));
+ Size aSize(convertPointToMm100(right - left), convertPointToMm100(bottom - top));
+
+ return tools::Rectangle(aPos, aSize);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdpntv.cxx b/svx/source/svdraw/svdpntv.cxx
new file mode 100644
index 000000000..f403ddd57
--- /dev/null
+++ b/svx/source/svdraw/svdpntv.cxx
@@ -0,0 +1,1206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <svx/svdpntv.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/window.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svdmodel.hxx>
+
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svl/hint.hxx>
+
+#include <svx/svdview.hxx>
+#include <svx/svdglue.hxx>
+#include <svx/svdobj.hxx>
+#include <sxlayitm.hxx>
+#include <svl/itemiter.hxx>
+#include <editeng/eeitem.hxx>
+#include <svl/whiter.hxx>
+#include <svl/style.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/animation/objectanimator.hxx>
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#include <drawinglayer/converters.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <comphelper/lok.hxx>
+#include <svx/svdviter.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::com::sun::star;
+
+// interface to SdrPaintWindow
+
+SdrPaintWindow* SdrPaintView::FindPaintWindow(const OutputDevice& rOut) const
+{
+ // back to loop - there is more to test than a std::find_if and a lambda can do
+ for(auto& candidate : maPaintWindows)
+ {
+ if(&(candidate->GetOutputDevice()) == &rOut)
+ {
+ return candidate.get();
+ }
+
+ // check for patched to allow finding in that state, too
+ if(nullptr != candidate->getPatched() && &(candidate->getPatched()->GetOutputDevice()) == &rOut)
+ {
+ return candidate->getPatched();
+ }
+ }
+
+ return nullptr;
+}
+
+SdrPaintWindow* SdrPaintView::GetPaintWindow(sal_uInt32 nIndex) const
+{
+ return maPaintWindows[nIndex].get();
+}
+
+void SdrPaintView::DeletePaintWindow(const SdrPaintWindow& rOld)
+{
+ auto aFindResult = ::std::find_if(maPaintWindows.begin(), maPaintWindows.end(),
+ [&](const std::unique_ptr<SdrPaintWindow>& p) { return p.get() == &rOld; });
+
+ if(aFindResult != maPaintWindows.end())
+ {
+ maPaintWindows.erase(aFindResult);
+ }
+}
+
+OutputDevice* SdrPaintView::GetFirstOutputDevice() const
+{
+ if(PaintWindowCount())
+ {
+ return &(GetPaintWindow(0)->GetOutputDevice());
+ }
+
+ return nullptr;
+}
+
+
+SvxViewChangedHint::SvxViewChangedHint()
+{
+}
+
+
+BitmapEx convertMetafileToBitmapEx(
+ const GDIMetaFile& rMtf,
+ const basegfx::B2DRange& rTargetRange,
+ const sal_uInt32 nMaximumQuadraticPixels)
+{
+ BitmapEx aBitmapEx;
+
+ if(rMtf.GetActionSize())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference aMtf(
+ new drawinglayer::primitive2d::MetafilePrimitive2D(
+ basegfx::utils::createScaleTranslateB2DHomMatrix(
+ rTargetRange.getRange(),
+ rTargetRange.getMinimum()),
+ rMtf));
+ aBitmapEx = drawinglayer::convertPrimitive2DContainerToBitmapEx(
+ drawinglayer::primitive2d::Primitive2DContainer { aMtf },
+ rTargetRange,
+ nMaximumQuadraticPixels);
+ }
+
+ return aBitmapEx;
+}
+
+SdrPaintView::SdrPaintView(SdrModel& rSdrModel, OutputDevice* pOut)
+ : mrSdrModelFromSdrView(rSdrModel)
+ , mpModel(&rSdrModel)
+ , mpActualOutDev(nullptr)
+ , mpDragWin(nullptr)
+ , mpDefaultStyleSheet(nullptr)
+ , maDefaultAttr(rSdrModel.GetItemPool())
+ , maComeBackIdle( "svx::SdrPaintView aComeBackIdle" )
+ , meAnimationMode(SdrAnimationMode::Animate)
+ , mnHitTolPix(2)
+ , mnMinMovPix(3)
+ , mnHitTolLog(0)
+ , mnMinMovLog(0)
+ , mbPageVisible(true)
+ , mbPageShadowVisible(true)
+ , mbPageBorderVisible(true)
+ , mbBordVisible(true)
+ , mbGridVisible(true)
+ , mbGridFront(false)
+ , mbHlplVisible(true)
+ , mbHlplFront(true)
+ , mbGlueVisible(false)
+ , mbGlueVisible2(false)
+ , mbGlueVisible3(false)
+ , mbGlueVisible4(false)
+ , mbSomeObjChgdFlag(false)
+ , mbSwapAsynchron(false)
+ , mbPrintPreview(false)
+ , mbAnimationPause(false)
+ , mbBufferedOutputAllowed(false)
+ , mbBufferedOverlayAllowed(false)
+ , mbPagePaintingAllowed(true)
+ , mbPreviewRenderer(false)
+ , mbHideOle(false)
+ , mbHideChart(false)
+ , mbHideDraw(false)
+ , mbHideFormControl(false)
+ , maGridColor(COL_BLACK)
+{
+ maComeBackIdle.SetPriority(TaskPriority::REPAINT);
+ maComeBackIdle.SetInvokeHandler(LINK(this,SdrPaintView,ImpComeBackHdl));
+
+ if (mpModel)
+ SetDefaultStyleSheet(mpModel->GetDefaultStyleSheet(), true);
+
+ if (pOut)
+ AddWindowToPaintView(pOut, nullptr);
+
+ maColorConfig.AddListener(this);
+ onChangeColorConfig();
+}
+
+SdrPaintView::~SdrPaintView()
+{
+ if (mpDefaultStyleSheet)
+ EndListening(*mpDefaultStyleSheet);
+
+ maColorConfig.RemoveListener(this);
+ ClearPageView();
+
+ // delete existing SdrPaintWindows
+ maPaintWindows.clear();
+}
+
+
+void SdrPaintView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ //If the stylesheet has been destroyed
+ if (&rBC == mpDefaultStyleSheet)
+ {
+ if (rHint.GetId() == SfxHintId::Dying)
+ mpDefaultStyleSheet = nullptr;
+ return;
+ }
+
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ SdrHintKind eKind = pSdrHint->GetKind();
+ if (eKind==SdrHintKind::ObjectChange || eKind==SdrHintKind::ObjectInserted || eKind==SdrHintKind::ObjectRemoved)
+ {
+ bool bObjChg = !mbSomeObjChgdFlag; // if true, evaluate for ComeBack timer
+ if (bObjChg)
+ {
+ mbSomeObjChgdFlag=true;
+ maComeBackIdle.Start();
+ }
+ }
+
+ if (eKind==SdrHintKind::PageOrderChange)
+ {
+ const SdrPage* pPg=pSdrHint->GetPage();
+ if (pPg && !pPg->IsInserted())
+ {
+ if(mpPageView && mpPageView->GetPage() == pPg)
+ {
+ HideSdrPage();
+ }
+ }
+ }
+}
+
+void SdrPaintView::ConfigurationChanged( ::utl::ConfigurationBroadcaster* , ConfigurationHints )
+{
+ onChangeColorConfig();
+ InvalidateAllWin();
+}
+
+IMPL_LINK_NOARG(SdrPaintView, ImpComeBackHdl, Timer *, void)
+{
+ if (mbSomeObjChgdFlag) {
+ mbSomeObjChgdFlag=false;
+ ModelHasChanged();
+ }
+}
+
+void SdrPaintView::FlushComeBackTimer() const
+{
+ if (mbSomeObjChgdFlag) {
+ // casting to nonconst
+ const_cast<SdrPaintView*>(this)->ImpComeBackHdl(&const_cast<SdrPaintView*>(this)->maComeBackIdle);
+ const_cast<SdrPaintView*>(this)->maComeBackIdle.Stop();
+ }
+}
+
+void SdrPaintView::ModelHasChanged()
+{
+ // broadcast to all PageViews
+ if(mpPageView && !mpPageView->GetPage()->IsInserted())
+ {
+ HideSdrPage();
+ }
+
+ // test mpPageView here again, HideSdrPage() may have invalidated it.
+ if(mpPageView)
+ {
+ mpPageView->ModelHasChanged();
+ }
+}
+
+
+bool SdrPaintView::IsAction() const
+{
+ return false;
+}
+
+void SdrPaintView::MovAction(const Point&)
+{
+}
+
+void SdrPaintView::EndAction()
+{
+}
+
+void SdrPaintView::BckAction()
+{
+}
+
+void SdrPaintView::BrkAction()
+{
+}
+
+void SdrPaintView::TakeActionRect(tools::Rectangle&) const
+{
+}
+
+
+// info about TextEdit. Default is false.
+bool SdrPaintView::IsTextEdit() const
+{
+ return false;
+}
+
+sal_uInt16 SdrPaintView::ImpGetMinMovLogic(short nMinMov, const OutputDevice* pOut) const
+{
+ if (nMinMov>=0) return sal_uInt16(nMinMov);
+ if (pOut==nullptr)
+ {
+ pOut = GetFirstOutputDevice();
+ }
+ if (pOut!=nullptr) {
+ return short(-pOut->PixelToLogic(Size(nMinMov,0)).Width());
+ } else {
+ return 0;
+ }
+}
+
+sal_uInt16 SdrPaintView::ImpGetHitTolLogic(short nHitTol, const OutputDevice* pOut) const
+{
+ if (nHitTol>=0) return sal_uInt16(nHitTol);
+ if (pOut==nullptr)
+ {
+ pOut = GetFirstOutputDevice();
+ }
+ if (pOut!=nullptr) {
+ return short(-pOut->PixelToLogic(Size(nHitTol,0)).Width());
+ } else {
+ return 0;
+ }
+}
+
+void SdrPaintView::TheresNewMapMode()
+{
+ if (mpActualOutDev) {
+ mnHitTolLog=static_cast<sal_uInt16>(mpActualOutDev->PixelToLogic(Size(mnHitTolPix,0)).Width());
+ mnMinMovLog=static_cast<sal_uInt16>(mpActualOutDev->PixelToLogic(Size(mnMinMovPix,0)).Width());
+ }
+}
+
+void SdrPaintView::SetActualWin(const OutputDevice* pWin)
+{
+ mpActualOutDev = const_cast<OutputDevice *>(pWin);
+ TheresNewMapMode();
+}
+
+
+void SdrPaintView::ClearPageView()
+{
+ BrkAction();
+
+ if(mpPageView)
+ {
+ InvalidateAllWin();
+ mpPageView.reset();
+ }
+}
+
+SdrPageView* SdrPaintView::ShowSdrPage(SdrPage* pPage)
+{
+ if(pPage && (!mpPageView || mpPageView->GetPage() != pPage))
+ {
+ if(mpPageView)
+ {
+ InvalidateAllWin();
+ mpPageView.reset();
+ }
+
+ if (SdrView *pView = dynamic_cast<SdrView*>(this))
+ {
+ mpPageView.reset(new SdrPageView(pPage, *pView));
+ mpPageView->Show();
+ }
+ }
+
+ return mpPageView.get();
+}
+
+void SdrPaintView::HideSdrPage()
+{
+ if(mpPageView)
+ {
+ mpPageView->Hide();
+ mpPageView.reset();
+ }
+}
+
+void SdrPaintView::AddWindowToPaintView(OutputDevice* pNewWin, vcl::Window *pWindow)
+{
+ DBG_ASSERT(pNewWin, "SdrPaintView::AddWindowToPaintView: No OutputDevice(!)");
+ SdrPaintWindow* pNewPaintWindow = new SdrPaintWindow(*this, *pNewWin, pWindow);
+ maPaintWindows.emplace_back(pNewPaintWindow);
+
+ if(mpPageView)
+ {
+ mpPageView->AddPaintWindowToPageView(*pNewPaintWindow);
+ }
+}
+
+void SdrPaintView::DeleteWindowFromPaintView(OutputDevice* pOldWin)
+{
+ assert(pOldWin && "SdrPaintView::DeleteWindowFromPaintView: No OutputDevice(!)");
+ SdrPaintWindow* pCandidate = FindPaintWindow(*pOldWin);
+
+ if(pCandidate)
+ {
+ if(mpPageView)
+ {
+ mpPageView->RemovePaintWindowFromPageView(*pCandidate);
+ }
+
+ DeletePaintWindow(*pCandidate);
+ }
+}
+
+void SdrPaintView::SetLayerVisible(const OUString& rName, bool bShow)
+{
+ if(mpPageView)
+ {
+ mpPageView->SetLayerVisible(rName, bShow);
+ }
+
+ InvalidateAllWin();
+}
+
+bool SdrPaintView::IsLayerVisible(const OUString& rName) const
+{
+ if(mpPageView)
+ {
+ return mpPageView->IsLayerVisible(rName);
+ }
+
+ return false;
+}
+
+void SdrPaintView::SetLayerLocked(const OUString& rName, bool bLock)
+{
+ if(mpPageView)
+ {
+ mpPageView->SetLayerLocked(rName,bLock);
+ }
+}
+
+bool SdrPaintView::IsLayerLocked(const OUString& rName) const
+{
+ if(mpPageView)
+ {
+ return mpPageView->IsLayerLocked(rName);
+ }
+
+ return false;
+}
+
+void SdrPaintView::SetLayerPrintable(const OUString& rName, bool bPrn)
+{
+ if(mpPageView)
+ {
+ mpPageView->SetLayerPrintable(rName,bPrn);
+ }
+}
+
+bool SdrPaintView::IsLayerPrintable(const OUString& rName) const
+{
+ if(mpPageView)
+ {
+ return mpPageView->IsLayerPrintable(rName);
+ }
+
+ return false;
+}
+
+void SdrPaintView::PrePaint()
+{
+ if(mpPageView)
+ {
+ mpPageView->PrePaint();
+ }
+}
+
+
+// #define SVX_REPAINT_TIMER_TEST
+
+void SdrPaintView::CompleteRedraw(OutputDevice* pOut, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector)
+{
+#ifdef SVX_REPAINT_TIMER_TEST
+#define REMEMBERED_TIMES_COUNT (10)
+ static bool bDoTimerTest(false);
+ static bool bTimesInited(false);
+ static sal_uInt32 nRepeatCount(10);
+ static double fLastTimes[REMEMBERED_TIMES_COUNT];
+ const sal_uInt64 nStartTime(tools::Time::GetSystemTicks());
+ sal_uInt32 count(1);
+ sal_uInt32 a;
+
+ if(bDoTimerTest)
+ {
+ count = nRepeatCount;
+ }
+
+ for(a = 0; a < count; a++)
+ {
+#endif // SVX_REPAINT_TIMER_TEST
+
+ // #i74769# check if pOut is a win and has a ClipRegion. If Yes, the Region
+ // rReg may be made more granular (fine) with using it. Normally, rReg
+ // does come from Window::Paint() anyways and thus is based on a single
+ // rectangle which was derived from exactly that repaint region
+ vcl::Region aOptimizedRepaintRegion(rReg);
+
+ if(pOut && OUTDEV_WINDOW == pOut->GetOutDevType())
+ {
+ vcl::Window* pWindow = pOut->GetOwnerWindow();
+
+ if(pWindow->IsInPaint())
+ {
+ if(!pWindow->GetPaintRegion().IsEmpty())
+ {
+ aOptimizedRepaintRegion.Intersect(pWindow->GetPaintRegion());
+ }
+ }
+ }
+
+ SdrPaintWindow* pPaintWindow = BeginCompleteRedraw(pOut);
+ OSL_ENSURE(pPaintWindow, "SdrPaintView::CompleteRedraw: No OutDev (!)");
+
+ DoCompleteRedraw(*pPaintWindow, aOptimizedRepaintRegion, pRedirector);
+ EndCompleteRedraw(*pPaintWindow, true);
+
+#ifdef SVX_REPAINT_TIMER_TEST
+ }
+
+ if(bDoTimerTest)
+ {
+ const sal_uInt64 nStopTime(tools::Time::GetSystemTicks());
+ const sal_uInt64 nNeededTime(nStopTime - nStartTime);
+ const double fTimePerPaint((double)nNeededTime / (double)nRepeatCount);
+
+ if(!bTimesInited)
+ {
+ for(a = 0; a < REMEMBERED_TIMES_COUNT; a++)
+ {
+ fLastTimes[a] = fTimePerPaint;
+ }
+
+ bTimesInited = true;
+ }
+ else
+ {
+ for(a = 1; a < REMEMBERED_TIMES_COUNT; a++)
+ {
+ fLastTimes[a - 1] = fLastTimes[a];
+ }
+
+ fLastTimes[REMEMBERED_TIMES_COUNT - 1] = fTimePerPaint;
+ }
+
+ double fAddedTimes(0.0);
+
+ for(a = 0; a < REMEMBERED_TIMES_COUNT; a++)
+ {
+ fAddedTimes += fLastTimes[a];
+ }
+
+ const double fAverageTimePerPaint(fAddedTimes / (double)REMEMBERED_TIMES_COUNT);
+
+ fprintf(stderr, "-----------(start result)----------\n");
+ fprintf(stderr, "StartTime : %" SAL_PRIuUINT64 ", StopTime: %" SAL_PRIuUINT64 ", NeededTime: %" SAL_PRIuUINT64 ", TimePerPaint: %f\n", nStartTime, nStopTime, nNeededTime, fTimePerPaint);
+ fprintf(stderr, "Remembered times: ");
+
+ for(a = 0; a < REMEMBERED_TIMES_COUNT; a++)
+ {
+ fprintf(stderr, "%d: %f ", a, fLastTimes[a]);
+ }
+
+ fprintf(stderr, "\n");
+ fprintf(stderr, "AverageTimePerPaint: %f\n", fAverageTimePerPaint);
+ fprintf(stderr, "-----------(stop result)----------\n");
+ }
+#endif // SVX_REPAINT_TIMER_TEST
+}
+
+
+// #i72889#
+
+SdrPaintWindow* SdrPaintView::BeginCompleteRedraw(OutputDevice* pOut)
+{
+ OSL_ENSURE(pOut, "SdrPaintView::BeginCompleteRedraw: No OutDev (!)");
+ SdrPaintWindow* pPaintWindow = FindPaintWindow(*pOut);
+
+ if(pPaintWindow)
+ {
+ // draw preprocessing, only for known devices
+ // prepare PreRendering
+ pPaintWindow->PreparePreRenderDevice();
+ }
+ else
+ {
+ // None of the known OutputDevices is the target of this paint, use
+ // a temporary SdrPaintWindow for this Redraw.
+ pPaintWindow = new SdrPaintWindow(*this, *pOut);
+ pPaintWindow->setTemporaryTarget(true);
+ }
+
+ return pPaintWindow;
+}
+
+void SdrPaintView::DoCompleteRedraw(SdrPaintWindow& rPaintWindow, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector)
+{
+ // redraw all PageViews with the target. This may expand the RedrawRegion
+ // at the PaintWindow, plus taking care of FormLayer expansion
+ if(mpPageView)
+ {
+ mpPageView->CompleteRedraw(rPaintWindow, rReg, pRedirector);
+ }
+}
+
+void SdrPaintView::EndCompleteRedraw(SdrPaintWindow& rPaintWindow, bool bPaintFormLayer)
+{
+ std::unique_ptr<SdrPaintWindow> pPaintWindow;
+ if (comphelper::LibreOfficeKit::isActive() && rPaintWindow.getTemporaryTarget())
+ {
+ // Tiled rendering, we must paint the TextEdit to the output device.
+ pPaintWindow.reset(&rPaintWindow);
+ pPaintWindow->setTemporaryTarget(false);
+ }
+
+ if(rPaintWindow.getTemporaryTarget())
+ {
+ // get rid of temp target again
+ delete &rPaintWindow;
+ }
+ else
+ {
+ // draw postprocessing, only for known devices
+ // it is necessary to always paint FormLayer
+ if(bPaintFormLayer)
+ {
+ ImpFormLayerDrawing(rPaintWindow);
+ }
+
+ // look for active TextEdit. As long as this cannot be painted to a VDev,
+ // it cannot get part of buffering. In that case, output evtl. prerender
+ // early and paint text edit to window.
+ if(IsTextEdit() && GetSdrPageView())
+ {
+ static_cast< SdrView* >(this)->TextEditDrawing(rPaintWindow);
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // Look for active text edits in other views showing the same page,
+ // and show them as well.
+ if (SdrPageView* pPageView = GetSdrPageView())
+ {
+ SdrViewIter aIter(pPageView->GetPage());
+ for (SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView())
+ {
+ if (pView == this)
+ continue;
+
+ if (pView->IsTextEdit() && pView->GetSdrPageView())
+ {
+ pView->TextEditDrawing(rPaintWindow);
+ }
+ }
+ }
+ }
+
+ // draw Overlay, also to PreRender device if exists
+ rPaintWindow.DrawOverlay(rPaintWindow.GetRedrawRegion());
+
+ // output PreRendering
+ rPaintWindow.OutputPreRenderDevice(rPaintWindow.GetRedrawRegion());
+ }
+}
+
+
+SdrPaintWindow* SdrPaintView::BeginDrawLayers(OutputDevice* pOut, const vcl::Region& rReg, bool bDisableIntersect)
+{
+ // #i74769# use BeginCompleteRedraw() as common base
+ SdrPaintWindow* pPaintWindow = BeginCompleteRedraw(pOut);
+ OSL_ENSURE(pPaintWindow, "SdrPaintView::BeginDrawLayers: No SdrPaintWindow (!)");
+
+ if(mpPageView)
+ {
+ SdrPageWindow* pKnownTarget = mpPageView->FindPageWindow(*pPaintWindow);
+
+ if(pKnownTarget)
+ {
+ vcl::Region aOptimizedRepaintRegion = OptimizeDrawLayersRegion( pOut, rReg, bDisableIntersect );
+
+ // prepare redraw
+ pKnownTarget->PrepareRedraw(aOptimizedRepaintRegion);
+
+ // remember prepared SdrPageWindow
+ mpPageView->setPreparedPageWindow(pKnownTarget);
+ }
+ }
+
+ return pPaintWindow;
+}
+
+void SdrPaintView::EndDrawLayers(SdrPaintWindow& rPaintWindow, bool bPaintFormLayer)
+{
+ // #i74769# use EndCompleteRedraw() as common base
+ EndCompleteRedraw(rPaintWindow, bPaintFormLayer);
+
+ if(mpPageView)
+ {
+ // forget prepared SdrPageWindow
+ mpPageView->setPreparedPageWindow(nullptr);
+ }
+}
+
+void SdrPaintView::UpdateDrawLayersRegion(const OutputDevice* pOut, const vcl::Region& rReg)
+{
+ SdrPaintWindow* pPaintWindow = FindPaintWindow(*pOut);
+ OSL_ENSURE(pPaintWindow, "SdrPaintView::UpdateDrawLayersRegion: No SdrPaintWindow (!)");
+
+ if(mpPageView)
+ {
+ SdrPageWindow* pKnownTarget = mpPageView->FindPageWindow(*pPaintWindow);
+
+ if(pKnownTarget)
+ {
+ vcl::Region aOptimizedRepaintRegion = OptimizeDrawLayersRegion( pOut, rReg, false/*bDisableIntersect*/ );
+ pKnownTarget->GetPaintWindow().SetRedrawRegion(aOptimizedRepaintRegion);
+ mpPageView->setPreparedPageWindow(pKnownTarget); // already set actually
+ }
+ }
+}
+
+vcl::Region SdrPaintView::OptimizeDrawLayersRegion(const OutputDevice* pOut, const vcl::Region& rReg, bool bDisableIntersect)
+{
+ // #i74769# check if pOut is a win and has a ClipRegion. If Yes, the Region
+ // rReg may be made more granular (fine) with using it. Normally, rReg
+ // does come from Window::Paint() anyways and thus is based on a single
+ // rectangle which was derived from exactly that repaint region
+ vcl::Region aOptimizedRepaintRegion(rReg);
+
+ // #i76114# Intersecting the region with the Window's paint region is disabled
+ // for print preview in Calc, because the intersection can be empty (if the paint
+ // region is outside of the table area of the page), and then no clip region
+ // would be set.
+ if(pOut && OUTDEV_WINDOW == pOut->GetOutDevType() && !bDisableIntersect)
+ {
+ vcl::Window* pWindow = pOut->GetOwnerWindow();
+
+ if(pWindow->IsInPaint())
+ {
+ if(!pWindow->GetPaintRegion().IsEmpty())
+ {
+ aOptimizedRepaintRegion.Intersect(pWindow->GetPaintRegion());
+ }
+ }
+ }
+ return aOptimizedRepaintRegion;
+}
+
+
+void SdrPaintView::ImpFormLayerDrawing( SdrPaintWindow& rPaintWindow )
+{
+ if(!mpPageView)
+ return;
+
+ SdrPageWindow* pKnownTarget = mpPageView->FindPageWindow(rPaintWindow);
+
+ if(pKnownTarget)
+ {
+ const SdrModel& rModel = *(GetModel());
+ const SdrLayerAdmin& rLayerAdmin = rModel.GetLayerAdmin();
+ const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID(rLayerAdmin.GetControlLayerName());
+
+ // BUFFERED use GetTargetOutputDevice() now, it may be targeted to VDevs, too
+ // need to set PreparedPageWindow to make DrawLayer use the correct ObjectContact
+ mpPageView->setPreparedPageWindow(pKnownTarget);
+ mpPageView->DrawLayer(nControlLayerId, &rPaintWindow.GetTargetOutputDevice());
+ mpPageView->setPreparedPageWindow(nullptr);
+ }
+}
+
+
+bool SdrPaintView::KeyInput(const KeyEvent& /*rKEvt*/, vcl::Window* /*pWin*/)
+{
+ return false;
+}
+
+void SdrPaintView::GlueInvalidate() const
+{
+ // Do not invalidate GluePoints in Online
+ // They are handled on front-end
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+
+ const sal_uInt32 nWindowCount(PaintWindowCount());
+
+ for(sal_uInt32 nWinNum(0); nWinNum < nWindowCount; nWinNum++)
+ {
+ SdrPaintWindow* pPaintWindow = GetPaintWindow(nWinNum);
+
+ if(pPaintWindow->OutputToWindow())
+ {
+ OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
+
+ if(mpPageView)
+ {
+ const SdrObjList* pOL=mpPageView->GetObjList();
+ const size_t nObjCount = pOL->GetObjCount();
+ for (size_t nObjNum=0; nObjNum<nObjCount; ++nObjNum) {
+ const SdrObject* pObj=pOL->GetObj(nObjNum);
+ const SdrGluePointList* pGPL=pObj->GetGluePointList();
+ if (pGPL!=nullptr && pGPL->GetCount()!=0) {
+ pGPL->Invalidate(*rOutDev.GetOwnerWindow(), pObj);
+ }
+ }
+ }
+ }
+ }
+}
+
+void SdrPaintView::InvalidateAllWin()
+{
+ const sal_uInt32 nWindowCount(PaintWindowCount());
+
+ for(sal_uInt32 a(0); a < nWindowCount; a++)
+ {
+ SdrPaintWindow* pPaintWindow = GetPaintWindow(a);
+
+ if(pPaintWindow->OutputToWindow())
+ {
+ InvalidateOneWin(pPaintWindow->GetOutputDevice());
+ }
+ }
+}
+
+void SdrPaintView::InvalidateAllWin(const tools::Rectangle& rRect)
+{
+ const sal_uInt32 nWindowCount(PaintWindowCount());
+
+ for(sal_uInt32 a(0); a < nWindowCount; a++)
+ {
+ SdrPaintWindow* pPaintWindow = GetPaintWindow(a);
+
+ if(pPaintWindow->OutputToWindow())
+ {
+ OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
+ tools::Rectangle aRect(rRect);
+
+ Point aOrg(rOutDev.GetMapMode().GetOrigin());
+ aOrg.setX(-aOrg.X() ); aOrg.setY(-aOrg.Y() );
+ tools::Rectangle aOutRect(aOrg, rOutDev.GetOutputSize());
+
+ // In case of tiled rendering we want to get all invalidations, so visual area is not interesting.
+ if (aRect.Overlaps(aOutRect) || comphelper::LibreOfficeKit::isActive())
+ {
+ InvalidateOneWin(rOutDev, aRect);
+ }
+ }
+ }
+}
+
+void SdrPaintView::InvalidateOneWin(OutputDevice& rDevice)
+{
+ // do not erase background, that causes flicker (!)
+ rDevice.GetOwnerWindow()->Invalidate(InvalidateFlags::NoErase);
+}
+
+void SdrPaintView::InvalidateOneWin(OutputDevice& rDevice, const tools::Rectangle& rRect)
+{
+ // do not erase background, that causes flicker (!)
+ rDevice.GetOwnerWindow()->Invalidate(rRect, InvalidateFlags::NoErase);
+}
+
+void SdrPaintView::LeaveOneGroup()
+{
+ if(mpPageView)
+ {
+ mpPageView->LeaveOneGroup();
+ }
+}
+
+void SdrPaintView::LeaveAllGroup()
+{
+ if(mpPageView)
+ {
+ mpPageView->LeaveAllGroup();
+ }
+}
+
+bool SdrPaintView::IsGroupEntered() const
+{
+ if(mpPageView)
+ {
+ return (mpPageView->GetEnteredLevel() != 0);
+ }
+
+ return false;
+}
+
+void SdrPaintView::SetNotPersistDefaultAttr(const SfxItemSet& rAttr)
+{
+ // bReplaceAll has no effect here at all.
+ bool bMeasure= dynamic_cast<const SdrView*>(this) != nullptr && static_cast<SdrView*>(this)->IsMeasureTool();
+
+ if (const SdrLayerIdItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LAYERID))
+ {
+ SdrLayerID nLayerId = pPoolItem->GetValue();
+ const SdrLayer* pLayer=mpModel->GetLayerAdmin().GetLayerPerID(nLayerId);
+ if (pLayer!=nullptr) {
+ if (bMeasure) maMeasureLayer=pLayer->GetName();
+ else maActualLayer=pLayer->GetName();
+ }
+ }
+ if (const SdrLayerNameItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LAYERNAME))
+ {
+ if (bMeasure) maMeasureLayer = pPoolItem->GetValue();
+ else maActualLayer = pPoolItem->GetValue();
+ }
+}
+
+void SdrPaintView::MergeNotPersistDefaultAttr(SfxItemSet& rAttr) const
+{
+ // bOnlyHardAttr has no effect here at all.
+ bool bMeasure= dynamic_cast<const SdrView*>(this) != nullptr && static_cast<const SdrView*>(this)->IsMeasureTool();
+ const OUString& aNam = bMeasure ? maMeasureLayer : maActualLayer;
+ rAttr.Put(SdrLayerNameItem(aNam));
+ SdrLayerID nLayer=mpModel->GetLayerAdmin().GetLayerID(aNam);
+ if (nLayer!=SDRLAYER_NOTFOUND) {
+ rAttr.Put(SdrLayerIdItem(nLayer));
+ }
+}
+
+void SdrPaintView::SetDefaultAttr(const SfxItemSet& rAttr, bool bReplaceAll)
+{
+#ifdef DBG_UTIL
+ {
+ bool bHasEEFeatureItems=false;
+ SfxItemIter aIter(rAttr);
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); !bHasEEFeatureItems && pItem;
+ pItem = aIter.NextItem())
+ {
+ if (!IsInvalidItem(pItem)) {
+ sal_uInt16 nW=pItem->Which();
+ if (nW>=EE_FEATURE_START && nW<=EE_FEATURE_END) bHasEEFeatureItems=true;
+ }
+ }
+
+ if(bHasEEFeatureItems)
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ "SdrPaintView::SetDefaultAttr(): Setting EE_FEATURE items at the SdrView does not make sense! It only leads to overhead and unreadable documents."));
+ xInfoBox->run();
+ }
+ }
+#endif
+ if (bReplaceAll) maDefaultAttr.Set(rAttr);
+ else maDefaultAttr.Put(rAttr,false); // if FALSE, regard InvalidItems as "holes," not as Default
+ SetNotPersistDefaultAttr(rAttr);
+}
+
+void SdrPaintView::SetDefaultStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
+{
+ if (mpDefaultStyleSheet)
+ EndListening(*mpDefaultStyleSheet);
+ mpDefaultStyleSheet=pStyleSheet;
+ if (mpDefaultStyleSheet)
+ StartListening(*mpDefaultStyleSheet);
+
+ if (pStyleSheet!=nullptr && !bDontRemoveHardAttr) {
+ SfxWhichIter aIter(pStyleSheet->GetItemSet());
+ sal_uInt16 nWhich=aIter.FirstWhich();
+ while (nWhich!=0) {
+ if (aIter.GetItemState()==SfxItemState::SET) {
+ maDefaultAttr.ClearItem(nWhich);
+ }
+ nWhich=aIter.NextWhich();
+ }
+ }
+}
+
+void SdrPaintView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
+{
+ if(bOnlyHardAttr || !mpDefaultStyleSheet)
+ {
+ rTargetSet.Put(maDefaultAttr, false);
+ }
+ else
+ {
+ // else merge with DefStyleSheet
+ rTargetSet.Put(mpDefaultStyleSheet->GetItemSet(), false);
+ rTargetSet.Put(maDefaultAttr, false);
+ }
+ MergeNotPersistDefaultAttr(rTargetSet);
+}
+
+void SdrPaintView::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
+{
+ SetDefaultAttr(rSet,bReplaceAll);
+}
+
+SfxStyleSheet* SdrPaintView::GetStyleSheet() const
+{
+ return mpDefaultStyleSheet;
+}
+
+void SdrPaintView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
+{
+ SetDefaultStyleSheet(pStyleSheet,bDontRemoveHardAttr);
+}
+
+void SdrPaintView::MakeVisible(const tools::Rectangle& rRect, vcl::Window& rWin)
+{
+ // TODO: handle when the text cursor goes out of the chart area
+ // However this hack avoids that the cursor gets misplaced wrt the text.
+ if (comphelper::LibreOfficeKit::isActive() && rWin.IsChart())
+ {
+ return;
+ }
+
+ MapMode aMap(rWin.GetMapMode());
+ Size aActualSize(rWin.GetOutDev()->GetOutputSize());
+
+ if( aActualSize.IsEmpty() )
+ return;
+
+ Size aNewSize(rRect.GetSize());
+ bool bNewScale=false;
+ bool bNeedMoreX=aNewSize.Width()>aActualSize.Width();
+ bool bNeedMoreY=aNewSize.Height()>aActualSize.Height();
+ if (bNeedMoreX || bNeedMoreY)
+ {
+ bNewScale=true;
+ // set new MapMode (Size+Org) and invalidate everything
+ Fraction aXFact(aNewSize.Width(),aActualSize.Width());
+ Fraction aYFact(aNewSize.Height(),aActualSize.Height());
+ if (aYFact>aXFact) aXFact=aYFact;
+ aXFact*=aMap.GetScaleX();
+ aXFact.ReduceInaccurate(10); // to avoid runovers and BigInt mapping
+ aMap.SetScaleX(aXFact);
+ aMap.SetScaleY(aYFact);
+ rWin.SetMapMode(aMap);
+ aActualSize=rWin.GetOutDev()->GetOutputSize();
+ }
+ Point aOrg(aMap.GetOrigin());
+ tools::Long dx=0,dy=0;
+ tools::Long l=-aOrg.X();
+ tools::Long r=-aOrg.X()+aActualSize.Width()-1;
+ tools::Long o=-aOrg.Y();
+ tools::Long u=-aOrg.Y()+aActualSize.Height()-1;
+ if (l>rRect.Left()) dx=rRect.Left()-l;
+ else if (r<rRect.Right()) dx=rRect.Right()-r;
+ if (o>rRect.Top()) dy=rRect.Top()-o;
+ else if (u<rRect.Bottom()) dy=rRect.Bottom()-u;
+ aMap.SetOrigin(Point(aOrg.X()-dx,aOrg.Y()-dy));
+ if (!bNewScale) {
+ if (dx!=0 || dy!=0) {
+ rWin.Scroll(-dx,-dy);
+ rWin.SetMapMode(aMap);
+ rWin.PaintImmediately();
+ }
+ } else {
+ rWin.SetMapMode(aMap);
+ InvalidateOneWin(*rWin.GetOutDev());
+ }
+}
+
+void SdrPaintView::DoConnect(SdrOle2Obj* /*pOleObj*/)
+{
+}
+
+void SdrPaintView::SetAnimationEnabled( bool bEnable )
+{
+ SetAnimationMode( bEnable ? SdrAnimationMode::Animate : SdrAnimationMode::Disable );
+}
+
+void SdrPaintView::SetAnimationPause( bool bSet )
+{
+ if(mbAnimationPause == bSet)
+ return;
+
+ mbAnimationPause = bSet;
+
+ if(!mpPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < mpPageView->PageWindowCount(); b++)
+ {
+ SdrPageWindow& rPageWindow = *(mpPageView->GetPageWindow(b));
+ sdr::contact::ObjectContact& rObjectContact = rPageWindow.GetObjectContact();
+ sdr::animation::primitiveAnimator& rAnimator = rObjectContact.getPrimitiveAnimator();
+
+ if(rAnimator.IsPaused() != bSet)
+ {
+ rAnimator.SetPaused(bSet);
+ }
+ }
+}
+
+void SdrPaintView::SetAnimationMode( const SdrAnimationMode eMode )
+{
+ meAnimationMode = eMode;
+}
+
+void SdrPaintView::VisAreaChanged(const OutputDevice* pOut)
+{
+ if(!mpPageView)
+ return;
+
+ if (pOut)
+ {
+ SdrPageWindow* pWindow = mpPageView->FindPageWindow(*const_cast<OutputDevice*>(pOut));
+
+ if(pWindow)
+ {
+ VisAreaChanged();
+ }
+ }
+ else
+ {
+ VisAreaChanged();
+ }
+}
+
+void SdrPaintView::VisAreaChanged()
+{
+ // notify SfxListener
+ Broadcast(SvxViewChangedHint());
+}
+
+
+void SdrPaintView::onChangeColorConfig()
+{
+ maGridColor = maColorConfig.GetColorValue( svtools::DRAWGRID ).nColor;
+}
+
+
+// Set background color for svx at SdrPageViews
+void SdrPaintView::SetApplicationBackgroundColor(Color aBackgroundColor)
+{
+ if(mpPageView)
+ {
+ mpPageView->SetApplicationBackgroundColor(aBackgroundColor);
+ }
+}
+
+// Set document color for svx at SdrPageViews
+void SdrPaintView::SetApplicationDocumentColor(Color aDocumentColor)
+{
+ if(mpPageView)
+ {
+ mpPageView->SetApplicationDocumentColor(aDocumentColor);
+ }
+}
+
+bool SdrPaintView::IsBufferedOutputAllowed() const
+{
+ return (mbBufferedOutputAllowed && SvtOptionsDrawinglayer::IsPaintBuffer());
+}
+
+void SdrPaintView::SetBufferedOutputAllowed(bool bNew)
+{
+ if(bNew != mbBufferedOutputAllowed)
+ {
+ mbBufferedOutputAllowed = bNew;
+ }
+}
+
+bool SdrPaintView::IsBufferedOverlayAllowed() const
+{
+ return (mbBufferedOverlayAllowed && SvtOptionsDrawinglayer::IsOverlayBuffer());
+}
+
+void SdrPaintView::SetBufferedOverlayAllowed(bool bNew)
+{
+ if(bNew != mbBufferedOverlayAllowed)
+ {
+ mbBufferedOverlayAllowed = bNew;
+ }
+}
+
+
+void SdrPaintView::SetPagePaintingAllowed(bool bNew)
+{
+ if(bNew != mbPagePaintingAllowed)
+ {
+ mbPagePaintingAllowed = bNew;
+ }
+}
+
+// #i38135# Sets the timer for Object animations and restarts.
+void SdrPaintView::SetAnimationTimer(sal_uInt32 nTime)
+{
+ if(mpPageView)
+ {
+ // first, reset all timers at all windows to 0L
+ for(sal_uInt32 a(0); a < mpPageView->PageWindowCount(); a++)
+ {
+ SdrPageWindow& rPageWindow = *mpPageView->GetPageWindow(a);
+ sdr::contact::ObjectContact& rObjectContact = rPageWindow.GetObjectContact();
+ sdr::animation::primitiveAnimator& rAnimator = rObjectContact.getPrimitiveAnimator();
+ rAnimator.SetTime(nTime);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdpoev.cxx b/svx/source/svdraw/svdpoev.cxx
new file mode 100644
index 000000000..bcf9168a4
--- /dev/null
+++ b/svx/source/svdraw/svdpoev.cxx
@@ -0,0 +1,652 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdpoev.hxx>
+#include <math.h>
+#include <svx/svdpagv.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svdtrans.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <tools/debug.hxx>
+#include <tools/helpers.hxx>
+
+#include <svx/polypolygoneditor.hxx>
+
+using namespace sdr;
+
+
+void SdrPolyEditView::ImpResetPolyPossibilityFlags()
+{
+ eMarkedPointsSmooth=SdrPathSmoothKind::DontCare;
+ eMarkedSegmentsKind=SdrPathSegmentKind::DontCare;
+ bSetMarkedPointsSmoothPossible=false;
+ bSetMarkedSegmentsKindPossible=false;
+}
+
+SdrPolyEditView::SdrPolyEditView(
+ SdrModel& rSdrModel,
+ OutputDevice* pOut)
+: SdrEditView(rSdrModel, pOut)
+{
+ ImpResetPolyPossibilityFlags();
+}
+
+SdrPolyEditView::~SdrPolyEditView()
+{
+}
+
+void SdrPolyEditView::ImpCheckPolyPossibilities()
+{
+ ImpResetPolyPossibilityFlags();
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ if(!nMarkCount || ImpIsFrameHandles())
+ return;
+
+ bool b1stSmooth(true);
+ bool b1stSegm(true);
+ bool bCurve(false);
+ bool bSmoothFuz(false);
+ bool bSegmFuz(false);
+ basegfx::B2VectorContinuity eSmooth = basegfx::B2VectorContinuity::NONE;
+
+ for(size_t nMarkNum = 0; nMarkNum < nMarkCount; ++nMarkNum)
+ {
+ SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
+ CheckPolyPossibilitiesHelper( pM, b1stSmooth, b1stSegm, bCurve, bSmoothFuz, bSegmFuz, eSmooth );
+ }
+}
+
+void SdrPolyEditView::CheckPolyPossibilitiesHelper( SdrMark* pM, bool& b1stSmooth, bool& b1stSegm, bool& bCurve, bool& bSmoothFuz, bool& bSegmFuz, basegfx::B2VectorContinuity& eSmooth )
+{
+ SdrObject* pObj = pM->GetMarkedSdrObj();
+ SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pObj );
+
+ if (!pPath)
+ return;
+
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+ if (rPts.empty())
+ return;
+
+ const bool bClosed(pPath->IsClosed());
+ bSetMarkedPointsSmoothPossible = true;
+
+ if (bClosed)
+ {
+ bSetMarkedSegmentsKindPossible = true;
+ }
+
+ for (const auto& rPt : rPts)
+ {
+ sal_uInt32 nNum(rPt);
+ sal_uInt32 nPolyNum, nPntNum;
+
+ if(PolyPolygonEditor::GetRelativePolyPoint(pPath->GetPathPoly(), nNum, nPolyNum, nPntNum))
+ {
+ const basegfx::B2DPolygon aLocalPolygon(pPath->GetPathPoly().getB2DPolygon(nPolyNum));
+ bool bCanSegment(bClosed || nPntNum < aLocalPolygon.count() - 1);
+
+ if(!bSetMarkedSegmentsKindPossible && bCanSegment)
+ {
+ bSetMarkedSegmentsKindPossible = true;
+ }
+
+ if(!bSmoothFuz)
+ {
+ if (b1stSmooth)
+ {
+ b1stSmooth = false;
+ eSmooth = basegfx::utils::getContinuityInPoint(aLocalPolygon, nPntNum);
+ }
+ else
+ {
+ bSmoothFuz = (eSmooth != basegfx::utils::getContinuityInPoint(aLocalPolygon, nPntNum));
+ }
+ }
+
+ if(!bSegmFuz && bCanSegment)
+ {
+ bool bCrv(aLocalPolygon.isNextControlPointUsed(nPntNum));
+
+ if(b1stSegm)
+ {
+ b1stSegm = false;
+ bCurve = bCrv;
+ }
+ else
+ {
+ bSegmFuz = (bCrv != bCurve);
+ }
+ }
+ }
+ }
+
+ if(!b1stSmooth && !bSmoothFuz)
+ {
+ if(basegfx::B2VectorContinuity::NONE == eSmooth)
+ {
+ eMarkedPointsSmooth = SdrPathSmoothKind::Angular;
+ }
+
+ if(basegfx::B2VectorContinuity::C1 == eSmooth)
+ {
+ eMarkedPointsSmooth = SdrPathSmoothKind::Asymmetric;
+ }
+
+ if(basegfx::B2VectorContinuity::C2 == eSmooth)
+ {
+ eMarkedPointsSmooth = SdrPathSmoothKind::Symmetric;
+ }
+ }
+
+ if(!b1stSegm && !bSegmFuz)
+ {
+ eMarkedSegmentsKind = bCurve ? SdrPathSegmentKind::Curve : SdrPathSegmentKind::Line;
+ }
+}
+
+void SdrPolyEditView::SetMarkedPointsSmooth(SdrPathSmoothKind eKind)
+{
+ basegfx::B2VectorContinuity eFlags;
+
+ if(SdrPathSmoothKind::Angular == eKind)
+ {
+ eFlags = basegfx::B2VectorContinuity::NONE;
+ }
+ else if(SdrPathSmoothKind::Asymmetric == eKind)
+ {
+ eFlags = basegfx::B2VectorContinuity::C1;
+ }
+ else if(SdrPathSmoothKind::Symmetric == eKind)
+ {
+ eFlags = basegfx::B2VectorContinuity::C2;
+ }
+ else
+ {
+ return;
+ }
+
+ if(!HasMarkedPoints())
+ return;
+
+ SortMarkedObjects();
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditSetPointsSmooth), GetDescriptionOfMarkedPoints());
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t nMarkNum(nMarkCount); nMarkNum > 0;)
+ {
+ --nMarkNum;
+ SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
+ SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
+ if (!pPath)
+ continue;
+
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+ PolyPolygonEditor aEditor(pPath->GetPathPoly());
+ if (aEditor.SetPointsSmooth(eFlags, rPts))
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath));
+ pPath->SetPathPoly(aEditor.GetPolyPolygon());
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+}
+
+void SdrPolyEditView::SetMarkedSegmentsKind(SdrPathSegmentKind eKind)
+{
+ if(!HasMarkedPoints())
+ return;
+
+ SortMarkedObjects();
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditSetSegmentsKind), GetDescriptionOfMarkedPoints());
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t nMarkNum=nMarkCount; nMarkNum > 0;)
+ {
+ --nMarkNum;
+ SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
+ SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
+ if (!pPath)
+ continue;
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+ PolyPolygonEditor aEditor( pPath->GetPathPoly());
+ if (aEditor.SetSegmentsKind(eKind, rPts))
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath));
+ pPath->SetPathPoly(aEditor.GetPolyPolygon());
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+}
+
+bool SdrPolyEditView::IsSetMarkedPointsSmoothPossible() const
+{
+ ForcePossibilities();
+ return bSetMarkedPointsSmoothPossible;
+}
+
+SdrPathSmoothKind SdrPolyEditView::GetMarkedPointsSmooth() const
+{
+ ForcePossibilities();
+ return eMarkedPointsSmooth;
+}
+
+bool SdrPolyEditView::IsSetMarkedSegmentsKindPossible() const
+{
+ ForcePossibilities();
+ return bSetMarkedSegmentsKindPossible;
+}
+
+SdrPathSegmentKind SdrPolyEditView::GetMarkedSegmentsKind() const
+{
+ ForcePossibilities();
+ return eMarkedSegmentsKind;
+}
+
+bool SdrPolyEditView::IsDeleteMarkedPointsPossible() const
+{
+ return HasMarkedPoints();
+}
+
+void SdrPolyEditView::DeleteMarkedPoints()
+{
+ if (!HasMarkedPoints())
+ return;
+
+ BrkAction();
+ SortMarkedObjects();
+ const size_t nMarkCount=GetMarkedObjectCount();
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ {
+ // Description
+ BegUndo(SvxResId(STR_EditDelete),GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Delete);
+ }
+
+ for (size_t nMarkNum=nMarkCount; nMarkNum>0;)
+ {
+ --nMarkNum;
+ SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
+ SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
+ if (!pPath)
+ continue;
+
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+ PolyPolygonEditor aEditor( pPath->GetPathPoly());
+ if (aEditor.DeletePoints(rPts))
+ {
+ if( aEditor.GetPolyPolygon().count() )
+ {
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath ));
+ pPath->SetPathPoly( aEditor.GetPolyPolygon() );
+ }
+ else
+ {
+ if( bUndo )
+ AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pPath ) );
+ pM->GetPageView()->GetObjList()->RemoveObject(pPath->GetOrdNum());
+ if( !bUndo )
+ {
+ SdrObject* pObj = pPath;
+ SdrObject::Free(pObj);
+ }
+ }
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+ UnmarkAllPoints();
+ MarkListHasChanged();
+}
+
+void SdrPolyEditView::RipUpAtMarkedPoints()
+{
+ if(!HasMarkedPoints())
+ return;
+
+ SortMarkedObjects();
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ const bool bUndo = IsUndoEnabled();
+ if( bUndo )
+ BegUndo(SvxResId(STR_EditRipUp), GetDescriptionOfMarkedPoints());
+
+ for(size_t nMarkNum = nMarkCount; nMarkNum > 0;)
+ {
+ --nMarkNum;
+ SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
+ SdrPathObj* pObj = dynamic_cast<SdrPathObj*>( pM->GetMarkedSdrObj() );
+ if (!pObj)
+ continue;
+
+ SdrUShortCont& rPts = pM->GetMarkedPoints();
+
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+ bool bCorrectionFlag(false);
+ sal_uInt32 nMax(pObj->GetHdlCount());
+
+ for(SdrUShortCont::const_reverse_iterator it = rPts.rbegin(); it != rPts.rend(); ++it)
+ {
+ sal_uInt32 nNewPt0Idx(0);
+ SdrObject* pNewObj = pObj->RipPoint(*it, nNewPt0Idx);
+
+ if(pNewObj)
+ {
+ pM->GetPageView()->GetObjList()->InsertObject(pNewObj, pObj->GetOrdNum() + 1);
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewObj));
+ MarkObj(pNewObj, pM->GetPageView(), false, true);
+ }
+
+ if(nNewPt0Idx)
+ {
+ // correction necessary?
+ DBG_ASSERT(!bCorrectionFlag,"Multiple index corrections at SdrPolyEditView::RipUp().");
+ if(!bCorrectionFlag)
+ {
+ bCorrectionFlag = true;
+
+ SdrUShortCont aReplaceSet;
+ for(const auto& rPt : rPts)
+ {
+ sal_uInt32 nPntNum(rPt);
+ nPntNum += nNewPt0Idx;
+
+ if(nPntNum >= nMax)
+ {
+ nPntNum -= nMax;
+ }
+
+ aReplaceSet.insert( static_cast<sal_uInt16>(nPntNum) );
+ }
+ rPts.swap(aReplaceSet);
+
+ it = rPts.rbegin();
+ }
+ }
+ }
+ }
+
+ UnmarkAllPoints();
+ if( bUndo )
+ EndUndo();
+ MarkListHasChanged();
+}
+
+bool SdrPolyEditView::IsRipUpAtMarkedPointsPossible() const
+{
+ bool bRetval(false);
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t a = 0; a < nMarkCount; ++a)
+ {
+ const SdrMark* pMark = GetSdrMarkByIndex(a);
+ const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
+
+ if (!pMarkedPathObject)
+ continue;
+
+ const SdrUShortCont& rSelectedPoints = pMark->GetMarkedPoints();
+ if (rSelectedPoints.empty())
+ continue;
+
+ const basegfx::B2DPolyPolygon& rPathPolyPolygon = pMarkedPathObject->GetPathPoly();
+
+ if(1 == rPathPolyPolygon.count())
+ {
+ // #i76617# Do not yet use basegfx::B2DPolygon since curve definitions
+ // are different and methods need to be changed thoroughly with interaction rework
+ const tools::Polygon aPathPolygon(rPathPolyPolygon.getB2DPolygon(0));
+ const sal_uInt16 nPointCount(aPathPolygon.GetSize());
+
+ if(nPointCount >= 3)
+ {
+ bRetval = pMarkedPathObject->IsClosedObj() // #i76617#
+ || std::any_of(rSelectedPoints.begin(), rSelectedPoints.end(),
+ [nPointCount](const sal_uInt16 nMarkedPointNum) {
+ return nMarkedPointNum > 0 && nMarkedPointNum < nPointCount - 1;
+ });
+ }
+ }
+ }
+
+ return bRetval;
+}
+
+bool SdrPolyEditView::IsOpenCloseMarkedObjectsPossible() const
+{
+ bool bRetval(false);
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t a = 0; a < nMarkCount; ++a)
+ {
+ const SdrMark* pMark = GetSdrMarkByIndex(a);
+ const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
+
+ if(pMarkedPathObject)
+ {
+ // #i76617# Do not yet use basegfx::B2DPolygon since curve definitions
+ // are different and methods need to be changed thoroughly with interaction rework
+ const tools::PolyPolygon aPathPolyPolygon(pMarkedPathObject->GetPathPoly());
+ const sal_uInt16 nPolygonCount(aPathPolyPolygon.Count());
+
+ for(sal_uInt16 b(0); !bRetval && b < nPolygonCount; b++)
+ {
+ const tools::Polygon& rPathPolygon = aPathPolyPolygon[b];
+ const sal_uInt16 nPointCount(rPathPolygon.GetSize());
+
+ bRetval = (nPointCount >= 3);
+ }
+ }
+ }
+
+ return bRetval;
+}
+
+SdrObjClosedKind SdrPolyEditView::GetMarkedObjectsClosedState() const
+{
+ bool bOpen(false);
+ bool bClosed(false);
+ const size_t nMarkCount(GetMarkedObjectCount());
+
+ for(size_t a = 0; !(bOpen && bClosed) && a < nMarkCount; ++a)
+ {
+ const SdrMark* pMark = GetSdrMarkByIndex(a);
+ const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
+
+ if(pMarkedPathObject)
+ {
+ if(pMarkedPathObject->IsClosedObj())
+ {
+ bClosed = true;
+ }
+ else
+ {
+ bOpen = true;
+ }
+ }
+ }
+
+ if(bOpen && bClosed)
+ {
+ return SdrObjClosedKind::DontCare;
+ }
+ else if(bOpen)
+ {
+ return SdrObjClosedKind::Open;
+ }
+ else
+ {
+ return SdrObjClosedKind::Closed;
+ }
+}
+
+void SdrPolyEditView::ImpTransformMarkedPoints(PPolyTrFunc pTrFunc, const void* p1, const void* p2, const void* p3, const void* p4)
+{
+ const bool bUndo = IsUndoEnabled();
+
+ const size_t nMarkCount=GetMarkedObjectCount();
+ for (size_t nm=0; nm<nMarkCount; ++nm)
+ {
+ SdrMark* pM=GetSdrMarkByIndex(nm);
+ SdrObject* pObj=pM->GetMarkedSdrObj();
+ SdrPathObj* pPath=dynamic_cast<SdrPathObj*>( pObj );
+ if (!pPath)
+ continue;
+
+ const SdrUShortCont& rPts = pM->GetMarkedPoints();
+ if (rPts.empty())
+ continue;
+
+ if( bUndo )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
+
+ basegfx::B2DPolyPolygon aXPP(pPath->GetPathPoly());
+
+ for (const auto& rPt : rPts)
+ {
+ sal_uInt32 nPt = rPt;
+ sal_uInt32 nPolyNum, nPointNum;
+
+ if(PolyPolygonEditor::GetRelativePolyPoint(aXPP, nPt, nPolyNum, nPointNum))
+ {
+ //#i83671# used nLocalPointNum (which was the polygon point count)
+ // instead of the point index (nPointNum). This of course led
+ // to a wrong point access to the B2DPolygon.
+ basegfx::B2DPolygon aNewXP(aXPP.getB2DPolygon(nPolyNum));
+ Point aPos, aC1, aC2;
+ bool bC1(false);
+ bool bC2(false);
+
+ const basegfx::B2DPoint aB2DPos(aNewXP.getB2DPoint(nPointNum));
+ aPos = Point(FRound(aB2DPos.getX()), FRound(aB2DPos.getY()));
+
+ if(aNewXP.isPrevControlPointUsed(nPointNum))
+ {
+ const basegfx::B2DPoint aB2DC1(aNewXP.getPrevControlPoint(nPointNum));
+ aC1 = Point(FRound(aB2DC1.getX()), FRound(aB2DC1.getY()));
+ bC1 = true;
+ }
+
+ if(aNewXP.isNextControlPointUsed(nPointNum))
+ {
+ const basegfx::B2DPoint aB2DC2(aNewXP.getNextControlPoint(nPointNum));
+ aC2 = Point(FRound(aB2DC2.getX()), FRound(aB2DC2.getY()));
+ bC2 = true;
+ }
+
+ (*pTrFunc)(aPos,&aC1,&aC2,p1,p2,p3,p4);
+ aNewXP.setB2DPoint(nPointNum, basegfx::B2DPoint(aPos.X(), aPos.Y()));
+
+ if (bC1)
+ {
+ aNewXP.setPrevControlPoint(nPointNum, basegfx::B2DPoint(aC1.X(), aC1.Y()));
+ }
+
+ if (bC2)
+ {
+ aNewXP.setNextControlPoint(nPointNum, basegfx::B2DPoint(aC2.X(), aC2.Y()));
+ }
+
+ aXPP.setB2DPolygon(nPolyNum, aNewXP);
+ }
+ }
+
+ pPath->SetPathPoly(aXPP);
+ }
+}
+
+
+static void ImpMove(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* /*p2*/, const void* /*p3*/, const void* /*p4*/)
+{
+ rPt.Move(*static_cast<const Size*>(p1));
+ if (pC1!=nullptr) pC1->Move(*static_cast<const Size*>(p1));
+ if (pC2!=nullptr) pC2->Move(*static_cast<const Size*>(p1));
+}
+
+void SdrPolyEditView::MoveMarkedPoints(const Size& rSiz)
+{
+ ForceUndirtyMrkPnt();
+ OUString aStr(SvxResId(STR_EditMove));
+ BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Move);
+ ImpTransformMarkedPoints(ImpMove,&rSiz);
+ EndUndo();
+ AdjustMarkHdl();
+}
+
+static void ImpResize(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* p2, const void* p3, const void* /*p4*/)
+{
+ ResizePoint(rPt,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
+ if (pC1!=nullptr) ResizePoint(*pC1,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
+ if (pC2!=nullptr) ResizePoint(*pC2,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
+}
+
+void SdrPolyEditView::ResizeMarkedPoints(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ ForceUndirtyMrkPnt();
+ OUString aStr(SvxResId(STR_EditResize));
+ BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Resize);
+ ImpTransformMarkedPoints(ImpResize,&rRef,&xFact,&yFact);
+ EndUndo();
+ AdjustMarkHdl();
+}
+
+static void ImpRotate(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* /*p2*/, const void* p3, const void* p4)
+{
+ RotatePoint(rPt,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
+ if (pC1!=nullptr) RotatePoint(*pC1,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
+ if (pC2!=nullptr) RotatePoint(*pC2,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
+}
+
+void SdrPolyEditView::RotateMarkedPoints(const Point& rRef, Degree100 nAngle)
+{
+ ForceUndirtyMrkPnt();
+ OUString aStr(SvxResId(STR_EditResize));
+ BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Rotate);
+ double nSin = sin(toRadians(nAngle));
+ double nCos = cos(toRadians(nAngle));
+ ImpTransformMarkedPoints(ImpRotate,&rRef,&nAngle,&nSin,&nCos);
+ EndUndo();
+ AdjustMarkHdl();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdsnpv.cxx b/svx/source/svdraw/svdsnpv.cxx
new file mode 100644
index 000000000..bcef8b3c3
--- /dev/null
+++ b/svx/source/svdraw/svdsnpv.cxx
@@ -0,0 +1,633 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdsnpv.hxx>
+#include <math.h>
+
+#include <svx/svdobj.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svditer.hxx>
+#include <svx/sdr/overlay/overlayobjectlist.hxx>
+#include <sdr/overlay/overlaycrosshair.hxx>
+#include <sdr/overlay/overlayhelpline.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <tools/debug.hxx>
+#include <vcl/ptrstyle.hxx>
+
+
+class ImplPageOriginOverlay
+{
+ // The OverlayObjects
+ sdr::overlay::OverlayObjectList maObjects;
+
+ // The current position in logical coordinates
+ basegfx::B2DPoint maPosition;
+
+public:
+ ImplPageOriginOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos);
+
+ // The OverlayObjects are cleared using the destructor of OverlayObjectList.
+ // That destructor calls clear() at the list which removes all objects from the
+ // OverlayManager and deletes them.
+
+ void SetPosition(const basegfx::B2DPoint& rNewPosition);
+};
+
+ImplPageOriginOverlay::ImplPageOriginOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos)
+: maPosition(rStartPos)
+{
+ for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
+ const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
+
+ if (xTargetOverlay.is())
+ {
+ std::unique_ptr<sdr::overlay::OverlayCrosshairStriped> aNew(new sdr::overlay::OverlayCrosshairStriped(
+ maPosition));
+ xTargetOverlay->add(*aNew);
+ maObjects.append(std::move(aNew));
+ }
+ }
+}
+
+void ImplPageOriginOverlay::SetPosition(const basegfx::B2DPoint& rNewPosition)
+{
+ if(rNewPosition == maPosition)
+ return;
+
+ // apply to OverlayObjects
+ for(sal_uInt32 a(0); a < maObjects.count(); a++)
+ {
+ sdr::overlay::OverlayCrosshairStriped* pCandidate =
+ static_cast< sdr::overlay::OverlayCrosshairStriped* >(&maObjects.getOverlayObject(a));
+
+ if(pCandidate)
+ {
+ pCandidate->setBasePosition(rNewPosition);
+ }
+ }
+
+ // remember new position
+ maPosition = rNewPosition;
+}
+
+
+class ImplHelpLineOverlay
+{
+ // The OverlayObjects
+ sdr::overlay::OverlayObjectList maObjects;
+
+ // The current position in logical coordinates
+ basegfx::B2DPoint maPosition;
+
+ // HelpLine specific stuff
+ SdrPageView* mpPageView;
+ sal_uInt16 mnHelpLineNumber;
+ SdrHelpLineKind meHelpLineKind;
+
+public:
+ ImplHelpLineOverlay(const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos,
+ SdrPageView* pPageView, sal_uInt16 nHelpLineNumber, SdrHelpLineKind eKind);
+
+ // The OverlayObjects are cleared using the destructor of OverlayObjectList.
+ // That destructor calls clear() at the list which removes all objects from the
+ // OverlayManager and deletes them.
+
+ void SetPosition(const basegfx::B2DPoint& rNewPosition);
+
+ // access to HelpLine specific stuff
+ SdrPageView* GetPageView() const { return mpPageView; }
+ sal_uInt16 GetHelpLineNumber() const { return mnHelpLineNumber; }
+ SdrHelpLineKind GetHelpLineKind() const { return meHelpLineKind; }
+};
+
+ImplHelpLineOverlay::ImplHelpLineOverlay(
+ const SdrPaintView& rView, const basegfx::B2DPoint& rStartPos,
+ SdrPageView* pPageView, sal_uInt16 nHelpLineNumber, SdrHelpLineKind eKind)
+: maPosition(rStartPos),
+ mpPageView(pPageView),
+ mnHelpLineNumber(nHelpLineNumber),
+ meHelpLineKind(eKind)
+{
+ for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
+ const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
+
+ if (xTargetOverlay.is())
+ {
+ std::unique_ptr<sdr::overlay::OverlayHelplineStriped> aNew(new sdr::overlay::OverlayHelplineStriped(
+ maPosition, meHelpLineKind));
+ xTargetOverlay->add(*aNew);
+ maObjects.append(std::move(aNew));
+ }
+ }
+}
+
+void ImplHelpLineOverlay::SetPosition(const basegfx::B2DPoint& rNewPosition)
+{
+ if(rNewPosition == maPosition)
+ return;
+
+ // apply to OverlayObjects
+ for(sal_uInt32 a(0); a < maObjects.count(); a++)
+ {
+ sdr::overlay::OverlayHelplineStriped* pCandidate =
+ static_cast< sdr::overlay::OverlayHelplineStriped* >(&maObjects.getOverlayObject(a));
+
+ if(pCandidate)
+ {
+ pCandidate->setBasePosition(rNewPosition);
+ }
+ }
+
+ // remember new position
+ maPosition = rNewPosition;
+}
+
+SdrSnapView::SdrSnapView(
+ SdrModel& rSdrModel,
+ OutputDevice* pOut)
+: SdrPaintView(rSdrModel, pOut)
+ ,mpPageOriginOverlay(nullptr)
+ ,mpHelpLineOverlay(nullptr)
+ ,nMagnSizPix(4)
+ ,nSnapAngle(1500)
+ ,nEliminatePolyPointLimitAngle(0)
+ ,eCrookMode(SdrCrookMode::Rotate)
+ ,bSnapEnab(true)
+ ,bGridSnap(true)
+ ,bBordSnap(true)
+ ,bHlplSnap(true)
+ ,bOFrmSnap(true)
+ ,bOPntSnap(false)
+ ,bOConSnap(true)
+ ,bMoveSnapOnlyTopLeft(false)
+ ,bOrtho(false)
+ ,bBigOrtho(true)
+ ,bAngleSnapEnab(false)
+ ,bMoveOnlyDragging(false)
+ ,bSlantButShear(false)
+ ,bCrookNoContortion(false)
+ ,bEliminatePolyPoints(false)
+{
+}
+
+SdrSnapView::~SdrSnapView()
+{
+ BrkSetPageOrg();
+ BrkDragHelpLine();
+}
+
+
+bool SdrSnapView::IsAction() const
+{
+ return IsSetPageOrg() || IsDragHelpLine() || SdrPaintView::IsAction();
+}
+
+void SdrSnapView::MovAction(const Point& rPnt)
+{
+ SdrPaintView::MovAction(rPnt);
+ if (IsSetPageOrg()) {
+ MovSetPageOrg(rPnt);
+ }
+ if (IsDragHelpLine()) {
+ MovDragHelpLine(rPnt);
+ }
+}
+
+void SdrSnapView::EndAction()
+{
+ if (IsSetPageOrg()) {
+ EndSetPageOrg();
+ }
+ if (IsDragHelpLine()) {
+ EndDragHelpLine();
+ }
+ SdrPaintView::EndAction();
+}
+
+void SdrSnapView::BckAction()
+{
+ BrkSetPageOrg();
+ BrkDragHelpLine();
+ SdrPaintView::BckAction();
+}
+
+void SdrSnapView::BrkAction()
+{
+ BrkSetPageOrg();
+ BrkDragHelpLine();
+ SdrPaintView::BrkAction();
+}
+
+void SdrSnapView::TakeActionRect(tools::Rectangle& rRect) const
+{
+ if (IsSetPageOrg() || IsDragHelpLine()) {
+ rRect=tools::Rectangle(maDragStat.GetNow(),maDragStat.GetNow());
+ } else {
+ SdrPaintView::TakeActionRect(rRect);
+ }
+}
+
+
+Point SdrSnapView::GetSnapPos(const Point& rPnt, const SdrPageView* pPV) const
+{
+ Point aPt(rPnt);
+ SnapPos(aPt,pPV);
+ return aPt;
+}
+
+#define NOT_SNAPPED 0x7FFFFFFF
+SdrSnap SdrSnapView::SnapPos(Point& rPnt, const SdrPageView* pPV) const
+{
+ if (!bSnapEnab) return SdrSnap::NOTSNAPPED;
+ tools::Long x=rPnt.X();
+ tools::Long y=rPnt.Y();
+ if (pPV==nullptr) {
+ pPV=GetSdrPageView();
+ if (pPV==nullptr) return SdrSnap::NOTSNAPPED;
+ }
+
+ tools::Long dx=NOT_SNAPPED;
+ tools::Long dy=NOT_SNAPPED;
+ tools::Long dx1,dy1;
+ tools::Long mx=aMagnSiz.Width();
+ tools::Long my=aMagnSiz.Height();
+ if (mbHlplVisible && bHlplSnap && !IsDragHelpLine())
+ {
+ const SdrHelpLineList& rHLL=pPV->GetHelpLines();
+ sal_uInt16 nCount=rHLL.GetCount();
+ for (sal_uInt16 i=nCount; i>0;) {
+ i--;
+ const SdrHelpLine& rHL=rHLL[i];
+ const Point& rPos=rHL.GetPos();
+ switch (rHL.GetKind()) {
+ case SdrHelpLineKind::Vertical: {
+ tools::Long a=x-rPos.X();
+ if (std::abs(a)<=mx) { dx1=-a; if (std::abs(dx1)<std::abs(dx)) dx=dx1; }
+ } break;
+ case SdrHelpLineKind::Horizontal: {
+ tools::Long b=y-rPos.Y();
+ if (std::abs(b)<=my) { dy1=-b; if (std::abs(dy1)<std::abs(dy)) dy=dy1; }
+ } break;
+ case SdrHelpLineKind::Point: {
+ tools::Long a=x-rPos.X();
+ tools::Long b=y-rPos.Y();
+ if (std::abs(a)<=mx && std::abs(b)<=my) {
+ dx1=-a; dy1=-b;
+ if (std::abs(dx1)<std::abs(dx) && std::abs(dy1)<std::abs(dy)) { dx=dx1; dy=dy1; }
+ }
+ } break;
+ } // switch
+ }
+ }
+ if (mbBordVisible && bBordSnap) {
+ SdrPage* pPage=pPV->GetPage();
+ tools::Long xs=pPage->GetWidth();
+ tools::Long ys=pPage->GetHeight();
+ tools::Long lft=pPage->GetLeftBorder();
+ tools::Long rgt=pPage->GetRightBorder();
+ tools::Long upp=pPage->GetUpperBorder();
+ tools::Long lwr=pPage->GetLowerBorder();
+ tools::Long a;
+ a=x- lft ; if (std::abs(a)<=mx) { dx1=-a; if (std::abs(dx1)<std::abs(dx)) dx=dx1; } // left margin
+ a=x-(xs-rgt); if (std::abs(a)<=mx) { dx1=-a; if (std::abs(dx1)<std::abs(dx)) dx=dx1; } // right margin
+ a=x ; if (std::abs(a)<=mx) { dx1=-a; if (std::abs(dx1)<std::abs(dx)) dx=dx1; } // left edge of paper
+ a=x- xs ; if (std::abs(a)<=mx) { dx1=-a; if (std::abs(dx1)<std::abs(dx)) dx=dx1; } // right edge of paper
+ a=y- upp ; if (std::abs(a)<=my) { dy1=-a; if (std::abs(dy1)<std::abs(dy)) dy=dy1; } // left margin
+ a=y-(ys-lwr); if (std::abs(a)<=my) { dy1=-a; if (std::abs(dy1)<std::abs(dy)) dy=dy1; } // right margin
+ a=y ; if (std::abs(a)<=my) { dy1=-a; if (std::abs(dy1)<std::abs(dy)) dy=dy1; } // left edge of paper
+ a=y- ys ; if (std::abs(a)<=my) { dy1=-a; if (std::abs(dy1)<std::abs(dy)) dy=dy1; } // right edge of paper
+ }
+ if (bOFrmSnap || bOPntSnap) {
+ sal_uInt32 nMaxPointSnapCount=200;
+ sal_uInt32 nMaxFrameSnapCount=200;
+
+ // go back to SdrIterMode::DeepNoGroups runthrough for snap to object comparisons
+ SdrObjListIter aIter(pPV->GetPage(),SdrIterMode::DeepNoGroups,true);
+
+ while (aIter.IsMore() && (nMaxPointSnapCount>0 || nMaxFrameSnapCount>0)) {
+ SdrObject* pO=aIter.Next();
+ tools::Rectangle aRect(pO->GetCurrentBoundRect());
+ aRect.AdjustLeft( -mx );
+ aRect.AdjustRight(mx );
+ aRect.AdjustTop( -my );
+ aRect.AdjustBottom(my );
+ if (aRect.Contains(rPnt)) {
+ if (bOPntSnap && nMaxPointSnapCount>0)
+ {
+ sal_uInt32 nCount(pO->GetSnapPointCount());
+ for (sal_uInt32 i(0); i < nCount && nMaxPointSnapCount > 0; i++)
+ {
+ Point aP(pO->GetSnapPoint(i));
+ dx1=x-aP.X();
+ dy1=y-aP.Y();
+ if (std::abs(dx1)<=mx && std::abs(dy1)<=my && std::abs(dx1)<std::abs(dx) && std::abs(dy1)<std::abs(dy)) {
+ dx=-dx1;
+ dy=-dy1;
+ }
+ nMaxPointSnapCount--;
+ }
+ }
+ if (bOFrmSnap && nMaxFrameSnapCount>0) {
+ tools::Rectangle aLog(pO->GetSnapRect());
+ tools::Rectangle aR1(aLog);
+ aR1.AdjustLeft( -mx );
+ aR1.AdjustRight(mx );
+ aR1.AdjustTop( -my );
+ aR1.AdjustBottom(my );
+ if (aR1.Contains(rPnt)) {
+ if (std::abs(x-aLog.Left ())<=mx) { dx1=-(x-aLog.Left ()); if (std::abs(dx1)<std::abs(dx)) dx=dx1; }
+ if (std::abs(x-aLog.Right ())<=mx) { dx1=-(x-aLog.Right ()); if (std::abs(dx1)<std::abs(dx)) dx=dx1; }
+ if (std::abs(y-aLog.Top ())<=my) { dy1=-(y-aLog.Top ()); if (std::abs(dy1)<std::abs(dy)) dy=dy1; }
+ if (std::abs(y-aLog.Bottom())<=my) { dy1=-(y-aLog.Bottom()); if (std::abs(dy1)<std::abs(dy)) dy=dy1; }
+ }
+ nMaxFrameSnapCount--;
+ }
+ }
+ }
+ }
+ if(bGridSnap)
+ {
+ double fSnapWidth(aSnapWdtX);
+ if(dx == NOT_SNAPPED && fSnapWidth != 0.0)
+ {
+ double fx = static_cast<double>(x);
+
+ // round instead of trunc
+ if(fx - static_cast<double>(pPV->GetPageOrigin().X()) >= 0.0)
+ fx += fSnapWidth / 2.0;
+ else
+ fx -= fSnapWidth / 2.0;
+
+ x = static_cast<tools::Long>((fx - static_cast<double>(pPV->GetPageOrigin().X())) / fSnapWidth);
+ x = static_cast<tools::Long>(static_cast<double>(x) * fSnapWidth + static_cast<double>(pPV->GetPageOrigin().X()));
+ dx = 0;
+ }
+ fSnapWidth = double(aSnapWdtY);
+ if(dy == NOT_SNAPPED && fSnapWidth)
+ {
+ double fy = static_cast<double>(y);
+
+ // round instead of trunc
+ if(fy - static_cast<double>(pPV->GetPageOrigin().Y()) >= 0.0)
+ fy += fSnapWidth / 2.0;
+ else
+ fy -= fSnapWidth / 2.0;
+
+ y = static_cast<tools::Long>((fy - static_cast<double>(pPV->GetPageOrigin().Y())) / fSnapWidth);
+ y = static_cast<tools::Long>(static_cast<double>(y) * fSnapWidth + static_cast<double>(pPV->GetPageOrigin().Y()));
+ dy = 0;
+ }
+ }
+ SdrSnap bRet=SdrSnap::NOTSNAPPED;
+ if (dx==NOT_SNAPPED) dx=0; else bRet|=SdrSnap::XSNAPPED;
+ if (dy==NOT_SNAPPED) dy=0; else bRet|=SdrSnap::YSNAPPED;
+ rPnt.setX(x+dx );
+ rPnt.setY(y+dy );
+ return bRet;
+}
+
+void SdrSnapView::CheckSnap(const Point& rPt, tools::Long& nBestXSnap, tools::Long& nBestYSnap, bool& bXSnapped, bool& bYSnapped) const
+{
+ Point aPt(rPt);
+ SdrSnap nRet=SnapPos(aPt,nullptr);
+ aPt-=rPt;
+ if (nRet & SdrSnap::XSNAPPED) {
+ if (bXSnapped) {
+ if (std::abs(aPt.X())<std::abs(nBestXSnap)) {
+ nBestXSnap=aPt.X();
+ }
+ } else {
+ nBestXSnap=aPt.X();
+ bXSnapped=true;
+ }
+ }
+ if (nRet & SdrSnap::YSNAPPED) {
+ if (bYSnapped) {
+ if (std::abs(aPt.Y())<std::abs(nBestYSnap)) {
+ nBestYSnap=aPt.Y();
+ }
+ } else {
+ nBestYSnap=aPt.Y();
+ bYSnapped=true;
+ }
+ }
+}
+
+
+void SdrSnapView::BegSetPageOrg(const Point& rPnt)
+{
+ BrkAction();
+
+ DBG_ASSERT(nullptr == mpPageOriginOverlay, "SdrSnapView::BegSetPageOrg: There exists an ImplPageOriginOverlay (!)");
+ basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
+ mpPageOriginOverlay = new ImplPageOriginOverlay(*this, aStartPos);
+ maDragStat.Reset(GetSnapPos(rPnt,nullptr));
+}
+
+void SdrSnapView::MovSetPageOrg(const Point& rPnt)
+{
+ if(IsSetPageOrg())
+ {
+ maDragStat.NextMove(GetSnapPos(rPnt,nullptr));
+ DBG_ASSERT(mpPageOriginOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
+ basegfx::B2DPoint aNewPos(maDragStat.GetNow().X(), maDragStat.GetNow().Y());
+ mpPageOriginOverlay->SetPosition(aNewPos);
+ }
+}
+
+void SdrSnapView::EndSetPageOrg()
+{
+ if(!IsSetPageOrg())
+ return;
+
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(pPV)
+ {
+ Point aPnt(maDragStat.GetNow());
+ pPV->SetPageOrigin(aPnt);
+ }
+
+ // cleanup
+ BrkSetPageOrg();
+}
+
+void SdrSnapView::BrkSetPageOrg()
+{
+ if(IsSetPageOrg())
+ {
+ DBG_ASSERT(mpPageOriginOverlay, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
+ delete mpPageOriginOverlay;
+ mpPageOriginOverlay = nullptr;
+ }
+}
+
+
+bool SdrSnapView::PickHelpLine(const Point& rPnt, short nTol, const OutputDevice& rOut, sal_uInt16& rnHelpLineNum, SdrPageView*& rpPV) const
+{
+ rpPV=nullptr;
+ nTol=ImpGetHitTolLogic(nTol,&rOut);
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(pPV)
+ {
+ Point aPnt(rPnt);
+ sal_uInt16 nIndex=pPV->GetHelpLines().HitTest(aPnt,sal_uInt16(nTol),rOut);
+ if (nIndex!=SDRHELPLINE_NOTFOUND) {
+ rpPV=pPV;
+ rnHelpLineNum=nIndex;
+ return true;
+ }
+ }
+ return false;
+}
+
+// start HelpLine drag for new HelpLine
+bool SdrSnapView::BegDragHelpLine(sal_uInt16 nHelpLineNum, SdrPageView* pPV)
+{
+ bool bRet(false);
+
+ BrkAction();
+
+ if(pPV && nHelpLineNum < pPV->GetHelpLines().GetCount())
+ {
+ const SdrHelpLineList& rHelpLines = pPV->GetHelpLines();
+ const SdrHelpLine& rHelpLine = rHelpLines[nHelpLineNum];
+ Point aHelpLinePos = rHelpLine.GetPos();
+ basegfx::B2DPoint aStartPos(aHelpLinePos.X(), aHelpLinePos.Y());
+
+ DBG_ASSERT(nullptr == mpHelpLineOverlay, "SdrSnapView::BegDragHelpLine: There exists an ImplHelpLineOverlay (!)");
+ mpHelpLineOverlay = new ImplHelpLineOverlay(*this, aStartPos, pPV, nHelpLineNum, rHelpLine.GetKind());
+
+ maDragStat.Reset(GetSnapPos(aHelpLinePos, pPV));
+ maDragStat.SetMinMove(ImpGetMinMovLogic(-3, nullptr));
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+// start HelpLine drag with existing HelpLine
+void SdrSnapView::BegDragHelpLine(const Point& rPnt, SdrHelpLineKind eNewKind)
+{
+ BrkAction();
+
+ if(GetSdrPageView())
+ {
+ DBG_ASSERT(nullptr == mpHelpLineOverlay, "SdrSnapView::BegDragHelpLine: There exists an ImplHelpLineOverlay (!)");
+ basegfx::B2DPoint aStartPos(rPnt.X(), rPnt.Y());
+ mpHelpLineOverlay = new ImplHelpLineOverlay(*this, aStartPos, nullptr, 0, eNewKind);
+ maDragStat.Reset(GetSnapPos(rPnt, nullptr));
+ }
+}
+
+PointerStyle SdrSnapView::GetDraggedHelpLinePointer() const
+{
+ if(IsDragHelpLine())
+ {
+ switch(mpHelpLineOverlay->GetHelpLineKind())
+ {
+ case SdrHelpLineKind::Vertical : return PointerStyle::ESize;
+ case SdrHelpLineKind::Horizontal: return PointerStyle::SSize;
+ default : return PointerStyle::Move;
+ }
+ }
+
+ return PointerStyle::Move;
+}
+
+void SdrSnapView::MovDragHelpLine(const Point& rPnt)
+{
+ if(IsDragHelpLine() && maDragStat.CheckMinMoved(rPnt))
+ {
+ Point aPnt(GetSnapPos(rPnt, nullptr));
+
+ if(aPnt != maDragStat.GetNow())
+ {
+ maDragStat.NextMove(aPnt);
+ DBG_ASSERT(mpHelpLineOverlay, "SdrSnapView::MovDragHelpLine: no ImplHelpLineOverlay (!)");
+ basegfx::B2DPoint aNewPos(maDragStat.GetNow().X(), maDragStat.GetNow().Y());
+ mpHelpLineOverlay->SetPosition(aNewPos);
+ }
+ }
+}
+
+bool SdrSnapView::EndDragHelpLine()
+{
+ bool bRet(false);
+
+ if(IsDragHelpLine())
+ {
+ if(maDragStat.IsMinMoved())
+ {
+ SdrPageView* pPageView = mpHelpLineOverlay->GetPageView();
+
+ if(pPageView)
+ {
+ // moved existing one
+ Point aPnt(maDragStat.GetNow());
+ const SdrHelpLineList& rHelpLines = pPageView->GetHelpLines();
+ SdrHelpLine aChangedHelpLine = rHelpLines[mpHelpLineOverlay->GetHelpLineNumber()];
+ aChangedHelpLine.SetPos(aPnt);
+ pPageView->SetHelpLine(mpHelpLineOverlay->GetHelpLineNumber(), aChangedHelpLine);
+
+ bRet = true;
+ }
+ else
+ {
+ // create new one
+ pPageView = GetSdrPageView();
+
+ if(pPageView)
+ {
+ Point aPnt(maDragStat.GetNow());
+ SdrHelpLine aNewHelpLine(mpHelpLineOverlay->GetHelpLineKind(), aPnt);
+ pPageView->InsertHelpLine(aNewHelpLine);
+
+ bRet = true;
+ }
+ }
+ }
+
+ // cleanup
+ BrkDragHelpLine();
+ }
+
+ return bRet;
+}
+
+void SdrSnapView::BrkDragHelpLine()
+{
+ if(IsDragHelpLine())
+ {
+ DBG_ASSERT(mpHelpLineOverlay, "SdrSnapView::EndDragHelpLine: no ImplHelpLineOverlay (!)");
+ delete mpHelpLineOverlay;
+ mpHelpLineOverlay = nullptr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdtext.cxx b/svx/source/svdraw/svdtext.cxx
new file mode 100644
index 000000000..72591ef67
--- /dev/null
+++ b/svx/source/svdraw/svdtext.cxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdotext.hxx>
+#include <svx/svdetc.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svl/itemset.hxx>
+#include <osl/diagnose.h>
+#include <libxml/xmlwriter.h>
+#include <memory>
+
+SdrText::SdrText( SdrTextObj& rObject )
+: mrObject( rObject )
+, mbPortionInfoChecked( false )
+{
+ OSL_ENSURE(&mrObject, "SdrText created without SdrTextObj (!)");
+}
+
+SdrText::~SdrText()
+{
+ clearWeak();
+}
+
+void SdrText::CheckPortionInfo( const SdrOutliner& rOutliner )
+{
+ if(mbPortionInfoChecked)
+ return;
+
+ // #i102062# no action when the Outliner is the HitTestOutliner,
+ // this will remove WrongList info at the OPO
+ if(&rOutliner == &mrObject.getSdrModelFromSdrObject().GetHitTestOutliner())
+ return;
+
+ // TODO: optimization: we could create a BigTextObject
+ mbPortionInfoChecked=true;
+
+ if(mpOutlinerParaObject && rOutliner.ShouldCreateBigTextObject())
+ {
+ // #i102062# MemoryLeak closed
+ mpOutlinerParaObject = rOutliner.CreateParaObject();
+ }
+}
+
+void SdrText::ReformatText()
+{
+ mbPortionInfoChecked=false;
+ mpOutlinerParaObject->ClearPortionInfo();
+}
+
+const SfxItemSet& SdrText::GetItemSet() const
+{
+ return const_cast< SdrText* >(this)->GetObjectItemSet();
+}
+
+void SdrText::SetOutlinerParaObject( std::optional<OutlinerParaObject> pTextObject )
+{
+ // Update HitTestOutliner
+ const SdrTextObj* pTestObj(mrObject.getSdrModelFromSdrObject().GetHitTestOutliner().GetTextObj());
+
+ if(pTestObj)
+ if ( (!pTestObj->GetOutlinerParaObject() && !mpOutlinerParaObject)
+ || (pTestObj->GetOutlinerParaObject() && mpOutlinerParaObject && *pTestObj->GetOutlinerParaObject() == *mpOutlinerParaObject) )
+ {
+ mrObject.getSdrModelFromSdrObject().GetHitTestOutliner().SetTextObj(nullptr);
+ }
+
+ mpOutlinerParaObject = std::move(pTextObject);
+ mbPortionInfoChecked = false;
+}
+
+OutlinerParaObject* SdrText::GetOutlinerParaObject()
+{
+ return mpOutlinerParaObject ? &*mpOutlinerParaObject : nullptr;
+}
+
+const OutlinerParaObject* SdrText::GetOutlinerParaObject() const
+{
+ return mpOutlinerParaObject ? &*mpOutlinerParaObject : nullptr;
+}
+
+/** returns the current OutlinerParaObject and removes it from this instance */
+std::optional<OutlinerParaObject> SdrText::RemoveOutlinerParaObject()
+{
+ // Update HitTestOutliner
+ const SdrTextObj* pTestObj(mrObject.getSdrModelFromSdrObject().GetHitTestOutliner().GetTextObj());
+
+ if(pTestObj)
+ if ( (!pTestObj->GetOutlinerParaObject() && !mpOutlinerParaObject)
+ || (pTestObj->GetOutlinerParaObject() && mpOutlinerParaObject && *pTestObj->GetOutlinerParaObject() == *mpOutlinerParaObject) )
+ {
+ mrObject.getSdrModelFromSdrObject().GetHitTestOutliner().SetTextObj(nullptr);
+ }
+
+ std::optional<OutlinerParaObject> pOPO = std::move(mpOutlinerParaObject);
+ mbPortionInfoChecked = false;
+
+ return pOPO;
+}
+
+void SdrText::ForceOutlinerParaObject( OutlinerMode nOutlMode )
+{
+ if(mpOutlinerParaObject)
+ return;
+
+ std::unique_ptr<Outliner> pOutliner(
+ SdrMakeOutliner(
+ nOutlMode,
+ mrObject.getSdrModelFromSdrObject()));
+
+ if(pOutliner)
+ {
+ Outliner& aDrawOutliner(mrObject.getSdrModelFromSdrObject().GetDrawOutliner());
+ pOutliner->SetCalcFieldValueHdl( aDrawOutliner.GetCalcFieldValueHdl() );
+ pOutliner->SetStyleSheet( 0, GetStyleSheet());
+ SetOutlinerParaObject( pOutliner->CreateParaObject() );
+ }
+}
+
+const SfxItemSet& SdrText::GetObjectItemSet()
+{
+ return mrObject.GetObjectItemSet();
+}
+
+SfxStyleSheet* SdrText::GetStyleSheet() const
+{
+ return mrObject.GetStyleSheet();
+}
+
+void SdrText::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrText"));
+ mpOutlinerParaObject->dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdtrans.cxx b/svx/source/svdraw/svdtrans.cxx
new file mode 100644
index 000000000..201e9f86d
--- /dev/null
+++ b/svx/source/svdraw/svdtrans.cxx
@@ -0,0 +1,867 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdtrans.hxx>
+#include <math.h>
+#include <svx/xpoly.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <vcl/virdev.hxx>
+#include <tools/bigint.hxx>
+#include <tools/UnitConversion.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <sal/log.hxx>
+
+void MoveXPoly(XPolygon& rPoly, const Size& S)
+{
+ rPoly.Move(S.Width(),S.Height());
+}
+
+void ResizeRect(tools::Rectangle& rRect, const Point& rRef, const Fraction& rxFact, const Fraction& ryFact)
+{
+ Fraction aXFact(rxFact);
+ Fraction aYFact(ryFact);
+
+ if (!aXFact.IsValid()) {
+ SAL_WARN( "svx.svdraw", "invalid fraction xFract, using Fraction(1,1)" );
+ aXFact = Fraction(1,1);
+ tools::Long nWdt = rRect.Right() - rRect.Left();
+ if (nWdt == 0) rRect.AdjustRight( 1 );
+ }
+ rRect.SetLeft( rRef.X() + FRound( (rRect.Left() - rRef.X()) * double(aXFact) ) );
+ rRect.SetRight( rRef.X() + FRound( (rRect.Right() - rRef.X()) * double(aXFact) ) );
+
+ if (!aYFact.IsValid()) {
+ SAL_WARN( "svx.svdraw", "invalid fraction yFract, using Fraction(1,1)" );
+ aYFact = Fraction(1,1);
+ tools::Long nHgt = rRect.Bottom() - rRect.Top();
+ if (nHgt == 0) rRect.AdjustBottom( 1 );
+ }
+ rRect.SetTop( rRef.Y() + FRound( (rRect.Top() - rRef.Y()) * double(aYFact) ) );
+ rRect.SetBottom( rRef.Y() + FRound( (rRect.Bottom() - rRef.Y()) * double(aYFact) ) );
+
+ rRect.Justify();
+}
+
+
+void ResizePoly(tools::Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ sal_uInt16 nCount=rPoly.GetSize();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ ResizePoint(rPoly[i],rRef,xFact,yFact);
+ }
+}
+
+void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ sal_uInt16 nCount=rPoly.GetPointCount();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ ResizePoint(rPoly[i],rRef,xFact,yFact);
+ }
+}
+
+void RotatePoly(tools::Polygon& rPoly, const Point& rRef, double sn, double cs)
+{
+ sal_uInt16 nCount=rPoly.GetSize();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ RotatePoint(rPoly[i],rRef,sn,cs);
+ }
+}
+
+void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs)
+{
+ sal_uInt16 nCount=rPoly.GetPointCount();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ RotatePoint(rPoly[i],rRef,sn,cs);
+ }
+}
+
+void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs)
+{
+ sal_uInt16 nCount=rPoly.Count();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ RotateXPoly(rPoly[i],rRef,sn,cs);
+ }
+}
+
+void MirrorPoint(Point& rPnt, const Point& rRef1, const Point& rRef2)
+{
+ tools::Long mx=rRef2.X()-rRef1.X();
+ tools::Long my=rRef2.Y()-rRef1.Y();
+ if (mx==0) { // vertical axis
+ tools::Long dx=rRef1.X()-rPnt.X();
+ rPnt.AdjustX(2*dx );
+ } else if (my==0) { // horizontal axis
+ tools::Long dy=rRef1.Y()-rPnt.Y();
+ rPnt.AdjustY(2*dy );
+ } else if (mx==my) { // diagonal axis '\'
+ tools::Long dx1=rPnt.X()-rRef1.X();
+ tools::Long dy1=rPnt.Y()-rRef1.Y();
+ rPnt.setX(rRef1.X()+dy1 );
+ rPnt.setY(rRef1.Y()+dx1 );
+ } else if (mx==-my) { // diagonal axis '/'
+ tools::Long dx1=rPnt.X()-rRef1.X();
+ tools::Long dy1=rPnt.Y()-rRef1.Y();
+ rPnt.setX(rRef1.X()-dy1 );
+ rPnt.setY(rRef1.Y()-dx1 );
+ } else { // arbitrary axis
+ // TODO: Optimize this! Raise perpendicular on the mirroring axis..?
+ Degree100 nRefAngle=GetAngle(rRef2-rRef1);
+ rPnt-=rRef1;
+ Degree100 nPntAngle=GetAngle(rPnt);
+ Degree100 nAngle=2_deg100*(nRefAngle-nPntAngle);
+ double a = toRadians(nAngle);
+ double nSin=sin(a);
+ double nCos=cos(a);
+ RotatePoint(rPnt,Point(),nSin,nCos);
+ rPnt+=rRef1;
+ }
+}
+
+void MirrorXPoly(XPolygon& rPoly, const Point& rRef1, const Point& rRef2)
+{
+ sal_uInt16 nCount=rPoly.GetPointCount();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ MirrorPoint(rPoly[i],rRef1,rRef2);
+ }
+}
+
+void ShearPoly(tools::Polygon& rPoly, const Point& rRef, double tn)
+{
+ sal_uInt16 nCount=rPoly.GetSize();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ ShearPoint(rPoly[i],rRef,tn);
+ }
+}
+
+void ShearXPoly(XPolygon& rPoly, const Point& rRef, double tn, bool bVShear)
+{
+ sal_uInt16 nCount=rPoly.GetPointCount();
+ for (sal_uInt16 i=0; i<nCount; i++) {
+ ShearPoint(rPoly[i],rRef,tn,bVShear);
+ }
+}
+
+double CrookRotateXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
+ const Point& rRad, double& rSin, double& rCos, bool bVert)
+{
+ bool bC1=pC1!=nullptr;
+ bool bC2=pC2!=nullptr;
+ tools::Long x0=rPnt.X();
+ tools::Long y0=rPnt.Y();
+ tools::Long cx=rCenter.X();
+ tools::Long cy=rCenter.Y();
+ double nAngle=GetCrookAngle(rPnt,rCenter,rRad,bVert);
+ double sn=sin(nAngle);
+ double cs=cos(nAngle);
+ RotatePoint(rPnt,rCenter,sn,cs);
+ if (bC1) {
+ if (bVert) {
+ // move into the direction of the center, as a basic position for the rotation
+ pC1->AdjustY( -y0 );
+ // resize, account for the distance from the center
+ pC1->setY(FRound(static_cast<double>(pC1->Y()) /rRad.X()*(cx-pC1->X())) );
+ pC1->AdjustY(cy );
+ } else {
+ // move into the direction of the center, as a basic position for the rotation
+ pC1->AdjustX( -x0 );
+ // resize, account for the distance from the center
+ tools::Long nPntRad=cy-pC1->Y();
+ double nFact=static_cast<double>(nPntRad)/static_cast<double>(rRad.Y());
+ pC1->setX(FRound(static_cast<double>(pC1->X())*nFact) );
+ pC1->AdjustX(cx );
+ }
+ RotatePoint(*pC1,rCenter,sn,cs);
+ }
+ if (bC2) {
+ if (bVert) {
+ // move into the direction of the center, as a basic position for the rotation
+ pC2->AdjustY( -y0 );
+ // resize, account for the distance from the center
+ pC2->setY(FRound(static_cast<double>(pC2->Y()) /rRad.X()*(rCenter.X()-pC2->X())) );
+ pC2->AdjustY(cy );
+ } else {
+ // move into the direction of the center, as a basic position for the rotation
+ pC2->AdjustX( -x0 );
+ // resize, account for the distance from the center
+ tools::Long nPntRad=rCenter.Y()-pC2->Y();
+ double nFact=static_cast<double>(nPntRad)/static_cast<double>(rRad.Y());
+ pC2->setX(FRound(static_cast<double>(pC2->X())*nFact) );
+ pC2->AdjustX(cx );
+ }
+ RotatePoint(*pC2,rCenter,sn,cs);
+ }
+ rSin=sn;
+ rCos=cs;
+ return nAngle;
+}
+
+double CrookSlantXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
+ const Point& rRad, double& rSin, double& rCos, bool bVert)
+{
+ bool bC1=pC1!=nullptr;
+ bool bC2=pC2!=nullptr;
+ tools::Long x0=rPnt.X();
+ tools::Long y0=rPnt.Y();
+ tools::Long dx1=0,dy1=0;
+ tools::Long dxC1=0,dyC1=0;
+ tools::Long dxC2=0,dyC2=0;
+ if (bVert) {
+ tools::Long nStart=rCenter.X()-rRad.X();
+ dx1=rPnt.X()-nStart;
+ rPnt.setX(nStart );
+ if (bC1) {
+ dxC1=pC1->X()-nStart;
+ pC1->setX(nStart );
+ }
+ if (bC2) {
+ dxC2=pC2->X()-nStart;
+ pC2->setX(nStart );
+ }
+ } else {
+ tools::Long nStart=rCenter.Y()-rRad.Y();
+ dy1=rPnt.Y()-nStart;
+ rPnt.setY(nStart );
+ if (bC1) {
+ dyC1=pC1->Y()-nStart;
+ pC1->setY(nStart );
+ }
+ if (bC2) {
+ dyC2=pC2->Y()-nStart;
+ pC2->setY(nStart );
+ }
+ }
+ double nAngle=GetCrookAngle(rPnt,rCenter,rRad,bVert);
+ double sn=sin(nAngle);
+ double cs=cos(nAngle);
+ RotatePoint(rPnt,rCenter,sn,cs);
+ if (bC1) { if (bVert) pC1->AdjustY( -(y0-rCenter.Y()) ); else pC1->AdjustX( -(x0-rCenter.X()) ); RotatePoint(*pC1,rCenter,sn,cs); }
+ if (bC2) { if (bVert) pC2->AdjustY( -(y0-rCenter.Y()) ); else pC2->AdjustX( -(x0-rCenter.X()) ); RotatePoint(*pC2,rCenter,sn,cs); }
+ if (bVert) {
+ rPnt.AdjustX(dx1 );
+ if (bC1) pC1->AdjustX(dxC1 );
+ if (bC2) pC2->AdjustX(dxC2 );
+ } else {
+ rPnt.AdjustY(dy1 );
+ if (bC1) pC1->AdjustY(dyC1 );
+ if (bC2) pC2->AdjustY(dyC2 );
+ }
+ rSin=sn;
+ rCos=cs;
+ return nAngle;
+}
+
+double CrookStretchXPoint(Point& rPnt, Point* pC1, Point* pC2, const Point& rCenter,
+ const Point& rRad, double& rSin, double& rCos, bool bVert,
+ const tools::Rectangle& rRefRect)
+{
+ tools::Long y0=rPnt.Y();
+ CrookSlantXPoint(rPnt,pC1,pC2,rCenter,rRad,rSin,rCos,bVert);
+ if (bVert) {
+ } else {
+ tools::Long nTop=rRefRect.Top();
+ tools::Long nBtm=rRefRect.Bottom();
+ tools::Long nHgt=nBtm-nTop;
+ tools::Long dy=rPnt.Y()-y0;
+ double a=static_cast<double>(y0-nTop)/nHgt;
+ a*=dy;
+ rPnt.setY(y0+FRound(a) );
+ }
+ return 0.0;
+}
+
+
+void CrookRotatePoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
+{
+ double nSin,nCos;
+ sal_uInt16 nPointCnt=rPoly.GetPointCount();
+ sal_uInt16 i=0;
+ while (i<nPointCnt) {
+ Point* pPnt=&rPoly[i];
+ Point* pC1=nullptr;
+ Point* pC2=nullptr;
+ if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left
+ pC1=pPnt;
+ i++;
+ pPnt=&rPoly[i];
+ }
+ i++;
+ if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right
+ pC2=&rPoly[i];
+ i++;
+ }
+ CrookRotateXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
+ }
+}
+
+void CrookSlantPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
+{
+ double nSin,nCos;
+ sal_uInt16 nPointCnt=rPoly.GetPointCount();
+ sal_uInt16 i=0;
+ while (i<nPointCnt) {
+ Point* pPnt=&rPoly[i];
+ Point* pC1=nullptr;
+ Point* pC2=nullptr;
+ if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left
+ pC1=pPnt;
+ i++;
+ pPnt=&rPoly[i];
+ }
+ i++;
+ if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right
+ pC2=&rPoly[i];
+ i++;
+ }
+ CrookSlantXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert);
+ }
+}
+
+void CrookStretchPoly(XPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const tools::Rectangle& rRefRect)
+{
+ double nSin,nCos;
+ sal_uInt16 nPointCnt=rPoly.GetPointCount();
+ sal_uInt16 i=0;
+ while (i<nPointCnt) {
+ Point* pPnt=&rPoly[i];
+ Point* pC1=nullptr;
+ Point* pC2=nullptr;
+ if (i+1<nPointCnt && rPoly.IsControl(i)) { // control point to the left
+ pC1=pPnt;
+ i++;
+ pPnt=&rPoly[i];
+ }
+ i++;
+ if (i<nPointCnt && rPoly.IsControl(i)) { // control point to the right
+ pC2=&rPoly[i];
+ i++;
+ }
+ CrookStretchXPoint(*pPnt,pC1,pC2,rCenter,rRad,nSin,nCos,bVert,rRefRect);
+ }
+}
+
+
+void CrookRotatePoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
+{
+ sal_uInt16 nPolyCount=rPoly.Count();
+ for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
+ CrookRotatePoly(rPoly[nPolyNum],rCenter,rRad,bVert);
+ }
+}
+
+void CrookSlantPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert)
+{
+ sal_uInt16 nPolyCount=rPoly.Count();
+ for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
+ CrookSlantPoly(rPoly[nPolyNum],rCenter,rRad,bVert);
+ }
+}
+
+void CrookStretchPoly(XPolyPolygon& rPoly, const Point& rCenter, const Point& rRad, bool bVert, const tools::Rectangle& rRefRect)
+{
+ sal_uInt16 nPolyCount=rPoly.Count();
+ for (sal_uInt16 nPolyNum=0; nPolyNum<nPolyCount; nPolyNum++) {
+ CrookStretchPoly(rPoly[nPolyNum],rCenter,rRad,bVert,rRefRect);
+ }
+}
+
+
+Degree100 GetAngle(const Point& rPnt)
+{
+ Degree100 a;
+ if (rPnt.Y()==0) {
+ if (rPnt.X()<0) a=-18000_deg100;
+ } else if (rPnt.X()==0) {
+ if (rPnt.Y()>0) a=-9000_deg100;
+ else a=9000_deg100;
+ } else {
+ a = Degree100(FRound(basegfx::rad2deg<100>(atan2(static_cast<double>(-rPnt.Y()), static_cast<double>(rPnt.X())))));
+ }
+ return a;
+}
+
+Degree100 NormAngle18000(Degree100 a)
+{
+ while (a<-18000_deg100) a+=36000_deg100;
+ while (a>=18000_deg100) a-=36000_deg100;
+ return a;
+}
+
+Degree100 NormAngle36000(Degree100 a)
+{
+ a %= 36000_deg100;
+ if (a < 0_deg100)
+ a += 36000_deg100;
+ return a;
+}
+
+sal_uInt16 GetAngleSector(Degree100 nAngle) { return (NormAngle36000(nAngle) / 9000_deg100).get(); }
+
+tools::Long GetLen(const Point& rPnt)
+{
+ tools::Long x=std::abs(rPnt.X());
+ tools::Long y=std::abs(rPnt.Y());
+ if (x+y<0x8000) { // because 7FFF * 7FFF * 2 = 7FFE0002
+ x*=x;
+ y*=y;
+ x+=y;
+ x=FRound(sqrt(static_cast<double>(x)));
+ return x;
+ } else {
+ double nx=x;
+ double ny=y;
+ nx*=nx;
+ ny*=ny;
+ nx+=ny;
+ nx=sqrt(nx);
+ if (nx>0x7FFFFFFF) {
+ return 0x7FFFFFFF; // we can't go any further, for fear of an overrun!
+ } else {
+ return FRound(nx);
+ }
+ }
+}
+
+
+void GeoStat::RecalcSinCos()
+{
+ if (nRotationAngle==0_deg100) {
+ mfSinRotationAngle=0.0;
+ mfCosRotationAngle=1.0;
+ } else {
+ double a = toRadians(nRotationAngle);
+ mfSinRotationAngle=sin(a);
+ mfCosRotationAngle=cos(a);
+ }
+}
+
+void GeoStat::RecalcTan()
+{
+ if (nShearAngle==0_deg100) {
+ mfTanShearAngle=0.0;
+ } else {
+ double a = toRadians(nShearAngle);
+ mfTanShearAngle=tan(a);
+ }
+}
+
+
+tools::Polygon Rect2Poly(const tools::Rectangle& rRect, const GeoStat& rGeo)
+{
+ tools::Polygon aPol(5);
+ aPol[0]=rRect.TopLeft();
+ aPol[1]=rRect.TopRight();
+ aPol[2]=rRect.BottomRight();
+ aPol[3]=rRect.BottomLeft();
+ aPol[4]=rRect.TopLeft();
+ if (rGeo.nShearAngle) ShearPoly(aPol,rRect.TopLeft(),rGeo.mfTanShearAngle);
+ if (rGeo.nRotationAngle) RotatePoly(aPol,rRect.TopLeft(),rGeo.mfSinRotationAngle,rGeo.mfCosRotationAngle);
+ return aPol;
+}
+
+void Poly2Rect(const tools::Polygon& rPol, tools::Rectangle& rRect, GeoStat& rGeo)
+{
+ rGeo.nRotationAngle=GetAngle(rPol[1]-rPol[0]);
+ rGeo.nRotationAngle=NormAngle36000(rGeo.nRotationAngle);
+ // rotation successful
+ rGeo.RecalcSinCos();
+
+ Point aPt1(rPol[1]-rPol[0]);
+ if (rGeo.nRotationAngle) RotatePoint(aPt1,Point(0,0),-rGeo.mfSinRotationAngle,rGeo.mfCosRotationAngle); // -Sin to reverse rotation
+ tools::Long nWdt=aPt1.X();
+
+ Point aPt0(rPol[0]);
+ Point aPt3(rPol[3]-rPol[0]);
+ if (rGeo.nRotationAngle) RotatePoint(aPt3,Point(0,0),-rGeo.mfSinRotationAngle,rGeo.mfCosRotationAngle); // -Sin to reverse rotation
+ tools::Long nHgt=aPt3.Y();
+
+
+ Degree100 nShW=GetAngle(aPt3);
+ nShW-=27000_deg100; // ShearWink is measured against a vertical line
+ nShW=-nShW; // negating, because '+' is shearing clock-wise
+
+ bool bMirr=aPt3.Y()<0;
+ if (bMirr) { // "exchange of points" when mirroring
+ nHgt=-nHgt;
+ nShW+=18000_deg100;
+ aPt0=rPol[3];
+ }
+ nShW=NormAngle18000(nShW);
+ if (nShW<-9000_deg100 || nShW>9000_deg100) {
+ nShW=NormAngle18000(nShW+18000_deg100);
+ }
+ if (nShW<-SDRMAXSHEAR) nShW=-SDRMAXSHEAR; // limit ShearWinkel (shear angle) to +/- 89.00 deg
+ if (nShW>SDRMAXSHEAR) nShW=SDRMAXSHEAR;
+ rGeo.nShearAngle=nShW;
+ rGeo.RecalcTan();
+ Point aRU(aPt0);
+ aRU.AdjustX(nWdt );
+ aRU.AdjustY(nHgt );
+ rRect=tools::Rectangle(aPt0,aRU);
+}
+
+
+void OrthoDistance8(const Point& rPt0, Point& rPt, bool bBigOrtho)
+{
+ tools::Long dx=rPt.X()-rPt0.X();
+ tools::Long dy=rPt.Y()-rPt0.Y();
+ tools::Long dxa=std::abs(dx);
+ tools::Long dya=std::abs(dy);
+ if (dx==0 || dy==0 || dxa==dya) return;
+ if (dxa>=dya*2) { rPt.setY(rPt0.Y() ); return; }
+ if (dya>=dxa*2) { rPt.setX(rPt0.X() ); return; }
+ if ((dxa<dya) != bBigOrtho) {
+ rPt.setY(rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) ) );
+ } else {
+ rPt.setX(rPt0.X()+(dya* (dx>=0 ? 1 : -1) ) );
+ }
+}
+
+void OrthoDistance4(const Point& rPt0, Point& rPt, bool bBigOrtho)
+{
+ tools::Long dx=rPt.X()-rPt0.X();
+ tools::Long dy=rPt.Y()-rPt0.Y();
+ tools::Long dxa=std::abs(dx);
+ tools::Long dya=std::abs(dy);
+ if ((dxa<dya) != bBigOrtho) {
+ rPt.setY(rPt0.Y()+(dxa* (dy>=0 ? 1 : -1) ) );
+ } else {
+ rPt.setX(rPt0.X()+(dya* (dx>=0 ? 1 : -1) ) );
+ }
+}
+
+
+tools::Long BigMulDiv(tools::Long nVal, tools::Long nMul, tools::Long nDiv)
+{
+ if (!nDiv)
+ return 0x7fffffff;
+ return BigInt::Scale(nVal, nMul, nDiv);
+}
+
+static FrPair toPair(o3tl::Length eFrom, o3tl::Length eTo)
+{
+ const auto& [nNum, nDen] = o3tl::getConversionMulDiv(eFrom, eTo);
+ return FrPair(nNum, nDen);
+}
+
+// How many eU units fit into a mm, respectively an inch?
+// Or: How many mm, respectively inches, are there in an eU (and then give me the inverse)
+
+static FrPair GetInchOrMM(MapUnit eU)
+{
+ switch (eU) {
+ case MapUnit::Map1000thInch: return toPair(o3tl::Length::in, o3tl::Length::in1000);
+ case MapUnit::Map100thInch : return toPair(o3tl::Length::in, o3tl::Length::in100);
+ case MapUnit::Map10thInch : return toPair(o3tl::Length::in, o3tl::Length::in10);
+ case MapUnit::MapInch : return toPair(o3tl::Length::in, o3tl::Length::in);
+ case MapUnit::MapPoint : return toPair(o3tl::Length::in, o3tl::Length::pt);
+ case MapUnit::MapTwip : return toPair(o3tl::Length::in, o3tl::Length::twip);
+ case MapUnit::Map100thMM : return toPair(o3tl::Length::mm, o3tl::Length::mm100);
+ case MapUnit::Map10thMM : return toPair(o3tl::Length::mm, o3tl::Length::mm10);
+ case MapUnit::MapMM : return toPair(o3tl::Length::mm, o3tl::Length::mm);
+ case MapUnit::MapCM : return toPair(o3tl::Length::mm, o3tl::Length::cm);
+ case MapUnit::MapPixel : {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ pVD->SetMapMode(MapMode(MapUnit::Map100thMM));
+ Point aP(pVD->PixelToLogic(Point(64,64))); // 64 pixels for more accuracy
+ return FrPair(6400,aP.X(),6400,aP.Y());
+ }
+ case MapUnit::MapAppFont: case MapUnit::MapSysFont: {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ pVD->SetMapMode(MapMode(eU));
+ Point aP(pVD->LogicToPixel(Point(32,32))); // 32 units for more accuracy
+ pVD->SetMapMode(MapMode(MapUnit::Map100thMM));
+ aP=pVD->PixelToLogic(aP);
+ return FrPair(3200,aP.X(),3200,aP.Y());
+ }
+ default: break;
+ }
+ return Fraction(1,1);
+}
+
+// Calculate the factor that we need to convert units from eS to eD.
+// e. g. GetMapFactor(UNIT_MM,UNIT_100TH_MM) => 100.
+
+FrPair GetMapFactor(MapUnit eS, MapUnit eD)
+{
+ if (eS==eD) return FrPair(1,1,1,1);
+ const auto eFrom = MapToO3tlLength(eS, o3tl::Length::invalid);
+ const auto eTo = MapToO3tlLength(eD, o3tl::Length::invalid);
+ if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
+ return toPair(eFrom, eTo);
+ FrPair aS(GetInchOrMM(eS));
+ FrPair aD(GetInchOrMM(eD));
+ bool bSInch=IsInch(eS);
+ bool bDInch=IsInch(eD);
+ FrPair aRet(aD.X()/aS.X(),aD.Y()/aS.Y());
+ if (bSInch && !bDInch) { aRet.X()*=Fraction(127,5); aRet.Y()*=Fraction(127,5); }
+ if (!bSInch && bDInch) { aRet.X()*=Fraction(5,127); aRet.Y()*=Fraction(5,127); }
+ return aRet;
+};
+
+FrPair GetMapFactor(FieldUnit eS, FieldUnit eD)
+{
+ if (eS==eD) return FrPair(1,1,1,1);
+ auto eFrom = FieldToO3tlLength(eS), eTo = FieldToO3tlLength(eD);
+ if (eFrom == o3tl::Length::invalid)
+ {
+ if (eTo == o3tl::Length::invalid)
+ return FrPair(1,1,1,1);
+ eFrom = IsInch(eD) ? o3tl::Length::in : o3tl::Length::mm;
+ }
+ else if (eTo == o3tl::Length::invalid)
+ eTo = IsInch(eS) ? o3tl::Length::in : o3tl::Length::mm;
+ return toPair(eFrom, eTo);
+};
+
+void SdrFormatter::Undirty()
+{
+ const o3tl::Length eFrom = MapToO3tlLength(eSrcMU, o3tl::Length::invalid);
+ const o3tl::Length eTo = MapToO3tlLength(eDstMU, o3tl::Length::invalid);
+ if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
+ {
+ const auto& [mul, div] = o3tl::getConversionMulDiv(eFrom, eTo);
+ sal_Int64 nMul = mul;
+ sal_Int64 nDiv = div;
+ short nComma = 0;
+
+ // shorten trailing zeros for dividend
+ while (0 == (nMul % 10))
+ {
+ nComma--;
+ nMul /= 10;
+ }
+
+ // shorten trailing zeros for divisor
+ while (0 == (nDiv % 10))
+ {
+ nComma++;
+ nDiv /= 10;
+ }
+ nMul_ = nMul;
+ nDiv_ = nDiv;
+ nComma_ = nComma;
+ }
+ else
+ {
+ nMul_ = nDiv_ = 1;
+ nComma_ = 0;
+ }
+ bDirty=false;
+}
+
+
+OUString SdrFormatter::GetStr(tools::Long nVal) const
+{
+ const OUString aNullCode("0");
+
+ if(!nVal)
+ {
+ return aNullCode;
+ }
+
+ // we may lose some decimal places here, because of MulDiv instead of Real
+ bool bNeg(nVal < 0);
+ SvtSysLocale aSysLoc;
+ const LocaleDataWrapper& rLoc = aSysLoc.GetLocaleData();
+
+ if (bDirty)
+ const_cast<SdrFormatter*>(this)->Undirty();
+
+ sal_Int16 nC(nComma_);
+
+ if(bNeg)
+ nVal = -nVal;
+
+ while(nC <= -3)
+ {
+ nVal *= 1000;
+ nC += 3;
+ }
+
+ while(nC <= -1)
+ {
+ nVal *= 10;
+ nC++;
+ }
+
+ if(nMul_ != nDiv_)
+ nVal = BigMulDiv(nVal, nMul_, nDiv_);
+
+ OUStringBuffer aStr = OUString::number(nVal);
+
+ if(nC > 0 && aStr.getLength() <= nC )
+ {
+ // decimal separator necessary
+ sal_Int32 nCount(nC - aStr.getLength());
+
+ if(nCount >= 0 && LocaleDataWrapper::isNumLeadingZero())
+ nCount++;
+
+ for(sal_Int32 i=0; i<nCount; i++)
+ aStr.insert(0, aNullCode);
+
+ // remove superfluous decimal points
+ sal_Int32 nNumDigits(LocaleDataWrapper::getNumDigits());
+ sal_Int32 nWeg(nC - nNumDigits);
+
+ if(nWeg > 0)
+ {
+ // TODO: we should round here
+ aStr.remove(aStr.getLength() - nWeg, nWeg);
+ nC = nNumDigits;
+ }
+ }
+
+ // remember everything before the decimal separator for later
+ sal_Int32 nForComma(aStr.getLength() - nC);
+
+ if(nC > 0)
+ {
+ // insert comma char (decimal separator)
+ // remove trailing zeros
+ while(nC > 0 && aStr[aStr.getLength() - 1] == aNullCode[0])
+ {
+ aStr.remove(aStr.getLength() - 1, 1);
+ nC--;
+ }
+
+ if(nC > 0)
+ {
+ // do we still have decimal places?
+ sal_Unicode cDec(rLoc.getNumDecimalSep()[0]);
+ aStr.insert(nForComma, cDec);
+ }
+ }
+
+ // add in thousands separator (if necessary)
+ if( nForComma > 3 )
+ {
+ const OUString& aThoSep( rLoc.getNumThousandSep() );
+ if ( aThoSep.getLength() > 0 )
+ {
+ sal_Unicode cTho( aThoSep[0] );
+ sal_Int32 i(nForComma - 3);
+
+ while(i > 0)
+ {
+ aStr.insert(i, cTho);
+ i -= 3;
+ }
+ }
+ }
+
+ if(aStr.isEmpty())
+ aStr.append(aNullCode);
+
+ if(bNeg && (aStr.getLength() > 1 || aStr[0] != aNullCode[0]))
+ {
+ aStr.insert(0, "-");
+ }
+
+ return aStr.makeStringAndClear();
+}
+
+OUString SdrFormatter::GetUnitStr(MapUnit eUnit)
+{
+ switch(eUnit)
+ {
+ // metrically
+ case MapUnit::Map100thMM :
+ return "/100mm";
+ case MapUnit::Map10thMM :
+ return "/10mm";
+ case MapUnit::MapMM :
+ return "mm";
+ case MapUnit::MapCM :
+ return "cm";
+
+ // Inch
+ case MapUnit::Map1000thInch:
+ return "/1000\"";
+ case MapUnit::Map100thInch :
+ return "/100\"";
+ case MapUnit::Map10thInch :
+ return "/10\"";
+ case MapUnit::MapInch :
+ return "\"";
+ case MapUnit::MapPoint :
+ return "pt";
+ case MapUnit::MapTwip :
+ return "twip";
+
+ // others
+ case MapUnit::MapPixel :
+ return "pixel";
+ case MapUnit::MapSysFont :
+ return "sysfont";
+ case MapUnit::MapAppFont :
+ return "appfont";
+ case MapUnit::MapRelative :
+ return "%";
+ default:
+ return OUString();
+ }
+}
+
+OUString SdrFormatter::GetUnitStr(FieldUnit eUnit)
+{
+ switch(eUnit)
+ {
+ default :
+ case FieldUnit::NONE :
+ case FieldUnit::CUSTOM :
+ return OUString();
+
+ // metrically
+ case FieldUnit::MM_100TH:
+ return "/100mm";
+ case FieldUnit::MM :
+ return "mm";
+ case FieldUnit::CM :
+ return "cm";
+ case FieldUnit::M :
+ return "m";
+ case FieldUnit::KM :
+ return "km";
+
+ // Inch
+ case FieldUnit::TWIP :
+ return "twip";
+ case FieldUnit::POINT :
+ return "pt";
+ case FieldUnit::PICA :
+ return "pica";
+ case FieldUnit::INCH :
+ return "\"";
+ case FieldUnit::FOOT :
+ return "ft";
+ case FieldUnit::MILE :
+ return "mile(s)";
+
+ // others
+ case FieldUnit::PERCENT:
+ return "%";
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdundo.cxx b/svx/source/svdraw/svdundo.cxx
new file mode 100644
index 000000000..15c690427
--- /dev/null
+++ b/svx/source/svdraw/svdundo.cxx
@@ -0,0 +1,1834 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/FillStyle.hpp>
+
+#include <svx/svdundo.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdlayer.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdview.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/scene3d.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/svdogrp.hxx>
+#include <sdr/properties/itemsettools.hxx>
+#include <svx/sdr/properties/properties.hxx>
+#include <svx/svdocapt.hxx>
+#include <svl/whiter.hxx>
+#include <svx/e3dsceneupdater.hxx>
+#include <svx/svdviter.hxx>
+#include <svx/svdotable.hxx> // #i124389#
+#include <vcl/svapp.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svx/svdoashp.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <svx/diagram/datamodel.hxx>
+#include <svx/diagram/IDiagramHelper.hxx>
+
+
+// iterates over all views and unmarks this SdrObject if it is marked
+static void ImplUnmarkObject( SdrObject* pObj )
+{
+ SdrViewIter aIter( pObj );
+ for ( SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView() )
+ {
+ pView->MarkObj( pObj, pView->GetSdrPageView(), true );
+ }
+}
+
+SdrUndoAction::SdrUndoAction(SdrModel& rNewMod)
+ : rMod(rNewMod), m_nViewShellId(-1)
+{
+ if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ m_nViewShellId = pViewShell->GetViewShellId();
+}
+
+SdrUndoAction::~SdrUndoAction() {}
+
+bool SdrUndoAction::CanRepeat(SfxRepeatTarget& rView) const
+{
+ SdrView* pV=dynamic_cast<SdrView*>( &rView );
+ if (pV!=nullptr) return CanSdrRepeat(*pV);
+ return false;
+}
+
+void SdrUndoAction::Repeat(SfxRepeatTarget& rView)
+{
+ SdrView* pV=dynamic_cast<SdrView*>( &rView );
+ if (pV!=nullptr) SdrRepeat(*pV);
+ DBG_ASSERT(pV!=nullptr,"Repeat: SfxRepeatTarget that was handed over is not a SdrView");
+}
+
+OUString SdrUndoAction::GetRepeatComment(SfxRepeatTarget& rView) const
+{
+ SdrView* pV=dynamic_cast<SdrView*>( &rView );
+ if (pV!=nullptr) return GetSdrRepeatComment();
+ return OUString();
+}
+
+bool SdrUndoAction::CanSdrRepeat(SdrView& /*rView*/) const
+{
+ return false;
+}
+
+void SdrUndoAction::SdrRepeat(SdrView& /*rView*/)
+{
+}
+
+OUString SdrUndoAction::GetSdrRepeatComment() const
+{
+ return OUString();
+}
+
+ViewShellId SdrUndoAction::GetViewShellId() const
+{
+ return m_nViewShellId;
+}
+
+SdrUndoGroup::SdrUndoGroup(SdrModel& rNewMod)
+: SdrUndoAction(rNewMod),
+ eFunction(SdrRepeatFunc::NONE)
+{}
+
+SdrUndoGroup::~SdrUndoGroup()
+{
+}
+
+void SdrUndoGroup::AddAction(std::unique_ptr<SdrUndoAction> pAct)
+{
+ maActions.push_back(std::move(pAct));
+}
+
+void SdrUndoGroup::Undo()
+{
+ for (auto it = maActions.rbegin(); it != maActions.rend(); ++it)
+ (*it)->Undo();
+}
+
+void SdrUndoGroup::Redo()
+{
+ for (std::unique_ptr<SdrUndoAction> & pAction : maActions)
+ pAction->Redo();
+}
+
+OUString SdrUndoGroup::GetComment() const
+{
+ return aComment.replaceAll("%1", aObjDescription);
+}
+
+bool SdrUndoGroup::CanSdrRepeat(SdrView& rView) const
+{
+ switch (eFunction)
+ {
+ case SdrRepeatFunc::NONE : return false;
+ case SdrRepeatFunc::Delete : return rView.AreObjectsMarked();
+ case SdrRepeatFunc::CombinePolyPoly: return rView.IsCombinePossible();
+ case SdrRepeatFunc::CombineOnePoly : return rView.IsCombinePossible(true);
+ case SdrRepeatFunc::DismantlePolys : return rView.IsDismantlePossible();
+ case SdrRepeatFunc::DismantleLines : return rView.IsDismantlePossible(true);
+ case SdrRepeatFunc::ConvertToPoly : return rView.IsConvertToPolyObjPossible();
+ case SdrRepeatFunc::ConvertToPath : return rView.IsConvertToPathObjPossible();
+ case SdrRepeatFunc::Group : return rView.IsGroupPossible();
+ case SdrRepeatFunc::Ungroup : return rView.IsUnGroupPossible();
+ case SdrRepeatFunc::PutToTop : return rView.IsToTopPossible();
+ case SdrRepeatFunc::PutToBottom : return rView.IsToBtmPossible();
+ case SdrRepeatFunc::MoveToTop : return rView.IsToTopPossible();
+ case SdrRepeatFunc::MoveToBottom : return rView.IsToBtmPossible();
+ case SdrRepeatFunc::ReverseOrder : return rView.IsReverseOrderPossible();
+ case SdrRepeatFunc::ImportMtf : return rView.IsImportMtfPossible();
+ default: break;
+ } // switch
+ return false;
+}
+
+void SdrUndoGroup::SdrRepeat(SdrView& rView)
+{
+ switch (eFunction)
+ {
+ case SdrRepeatFunc::NONE : break;
+ case SdrRepeatFunc::Delete : rView.DeleteMarked(); break;
+ case SdrRepeatFunc::CombinePolyPoly : rView.CombineMarkedObjects(false); break;
+ case SdrRepeatFunc::CombineOnePoly : rView.CombineMarkedObjects(); break;
+ case SdrRepeatFunc::DismantlePolys : rView.DismantleMarkedObjects(); break;
+ case SdrRepeatFunc::DismantleLines : rView.DismantleMarkedObjects(true); break;
+ case SdrRepeatFunc::ConvertToPoly : rView.ConvertMarkedToPolyObj(); break;
+ case SdrRepeatFunc::ConvertToPath : rView.ConvertMarkedToPathObj(false); break;
+ case SdrRepeatFunc::Group : rView.GroupMarked(); break;
+ case SdrRepeatFunc::Ungroup : rView.UnGroupMarked(); break;
+ case SdrRepeatFunc::PutToTop : rView.PutMarkedToTop(); break;
+ case SdrRepeatFunc::PutToBottom : rView.PutMarkedToBtm(); break;
+ case SdrRepeatFunc::MoveToTop : rView.MovMarkedToTop(); break;
+ case SdrRepeatFunc::MoveToBottom : rView.MovMarkedToBtm(); break;
+ case SdrRepeatFunc::ReverseOrder : rView.ReverseOrderOfMarked(); break;
+ case SdrRepeatFunc::ImportMtf : rView.DoImportMarkedMtf(); break;
+ default: break;
+ } // switch
+}
+
+OUString SdrUndoGroup::GetSdrRepeatComment() const
+{
+ return aComment.replaceAll("%1", SvxResId(STR_ObjNameSingulPlural));
+}
+
+SdrUndoObj::SdrUndoObj(SdrObject& rNewObj)
+: SdrUndoAction(rNewObj.getSdrModelFromSdrObject())
+ ,pObj(&rNewObj)
+{
+}
+
+OUString SdrUndoObj::GetDescriptionStringForObject( const SdrObject& _rForObject, TranslateId pStrCacheID, bool bRepeat )
+{
+ const OUString rStr {SvxResId(pStrCacheID)};
+
+ const sal_Int32 nPos = rStr.indexOf("%1");
+ if (nPos < 0)
+ return rStr;
+
+ if (bRepeat)
+ return rStr.replaceAt(nPos, 2, SvxResId(STR_ObjNameSingulPlural));
+
+ return rStr.replaceAt(nPos, 2, _rForObject.TakeObjNameSingul());
+}
+
+OUString SdrUndoObj::ImpGetDescriptionStr(TranslateId pStrCacheID, bool bRepeat) const
+{
+ if ( pObj )
+ return GetDescriptionStringForObject( *pObj, pStrCacheID, bRepeat );
+ return OUString();
+}
+
+// common call method for possible change of the page when UNDO/REDO is triggered
+void SdrUndoObj::ImpShowPageOfThisObject()
+{
+ if(pObj && pObj->IsInserted() && pObj->getSdrPageFromSdrObject())
+ {
+ SdrHint aHint(SdrHintKind::SwitchToPage, *pObj, pObj->getSdrPageFromSdrObject());
+ pObj->getSdrModelFromSdrObject().Broadcast(aHint);
+ }
+}
+
+void SdrUndoAttrObj::ensureStyleSheetInStyleSheetPool(SfxStyleSheetBasePool& rStyleSheetPool, SfxStyleSheet& rSheet)
+{
+ SfxStyleSheetBase* pThere = rStyleSheetPool.Find(rSheet.GetName(), rSheet.GetFamily());
+
+ if(!pThere)
+ {
+ // re-insert remembered style which was removed in the meantime. To do this
+ // without assertion, do it without parent and set parent after insertion
+ const OUString aParent(rSheet.GetParent());
+
+ rSheet.SetParent(OUString());
+ rStyleSheetPool.Insert(&rSheet);
+ rSheet.SetParent(aParent);
+ }
+}
+
+SdrUndoAttrObj::SdrUndoAttrObj(SdrObject& rNewObj, bool bStyleSheet1, bool bSaveText)
+ : SdrUndoObj(rNewObj)
+ , bHaveToTakeRedoSet(true)
+{
+ bStyleSheet = bStyleSheet1;
+
+ SdrObjList* pOL = rNewObj.GetSubList();
+ bool bIsGroup(pOL!=nullptr && pOL->GetObjCount());
+ bool bIs3DScene(bIsGroup && dynamic_cast< E3dScene* >(pObj) != nullptr);
+
+ if(bIsGroup)
+ {
+ // it's a group object!
+ pUndoGroup.reset(new SdrUndoGroup(pObj->getSdrModelFromSdrObject()));
+ const size_t nObjCount(pOL->GetObjCount());
+
+ for(size_t nObjNum = 0; nObjNum < nObjCount; ++nObjNum)
+ {
+ pUndoGroup->AddAction(
+ std::make_unique<SdrUndoAttrObj>(*pOL->GetObj(nObjNum), bStyleSheet1));
+ }
+ }
+
+ if(bIsGroup && !bIs3DScene)
+ return;
+
+ moUndoSet.emplace( pObj->GetMergedItemSet() );
+
+ if(bStyleSheet)
+ mxUndoStyleSheet = pObj->GetStyleSheet();
+
+ if(bSaveText)
+ {
+ auto p = pObj->GetOutlinerParaObject();
+ if(p)
+ pTextUndo = *p;
+ }
+}
+
+SdrUndoAttrObj::~SdrUndoAttrObj()
+{
+ moUndoSet.reset();
+ moRedoSet.reset();
+ pUndoGroup.reset();
+ pTextUndo.reset();
+ pTextRedo.reset();
+}
+
+void SdrUndoAttrObj::Undo()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(pObj);
+ bool bIs3DScene(dynamic_cast< E3dScene* >(pObj) != nullptr);
+
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+
+ if(!pUndoGroup || bIs3DScene)
+ {
+ if(bHaveToTakeRedoSet)
+ {
+ bHaveToTakeRedoSet = false;
+
+ moRedoSet.emplace( pObj->GetMergedItemSet() );
+
+ if(bStyleSheet)
+ mxRedoStyleSheet = pObj->GetStyleSheet();
+
+ if(pTextUndo)
+ {
+ // #i8508#
+ auto p = pObj->GetOutlinerParaObject();
+ if(p)
+ pTextRedo = *p;
+ }
+ }
+
+ if(bStyleSheet)
+ {
+ mxRedoStyleSheet = pObj->GetStyleSheet();
+ SfxStyleSheet* pSheet = dynamic_cast< SfxStyleSheet* >(mxUndoStyleSheet.get());
+
+ if(pSheet && pObj->getSdrModelFromSdrObject().GetStyleSheetPool())
+ {
+ ensureStyleSheetInStyleSheetPool(*pObj->getSdrModelFromSdrObject().GetStyleSheetPool(), *pSheet);
+ pObj->SetStyleSheet(pSheet, true);
+ }
+ else
+ {
+ OSL_ENSURE(false, "OOps, something went wrong in SdrUndoAttrObj (!)");
+ }
+ }
+
+ sdr::properties::ItemChangeBroadcaster aItemChange(*pObj);
+
+ // Since ClearItem sets back everything to normal
+ // it also sets fit-to-size text to non-fit-to-size text and
+ // switches on autogrowheight (the default). That may lead to
+ // losing the geometry size info for the object when it is
+ // laid out again from AdjustTextFrameWidthAndHeight(). This makes
+ // rescuing the size of the object necessary.
+ const tools::Rectangle aSnapRect = pObj->GetSnapRect();
+ // SdrObjCustomShape::NbcSetSnapRect needs logic instead of snap rect
+ const tools::Rectangle aLogicRect = pObj->GetLogicRect();
+
+ if(moUndoSet)
+ {
+ if(dynamic_cast<const SdrCaptionObj*>( pObj) != nullptr)
+ {
+ // do a more smooth item deletion here, else the text
+ // rect will be reformatted, especially when information regarding
+ // vertical text is changed. When clearing only set items it's
+ // slower, but safer regarding such information (it's not changed
+ // usually)
+ SfxWhichIter aIter(*moUndoSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ if(SfxItemState::SET != aIter.GetItemState(false))
+ {
+ pObj->ClearMergedItem(nWhich);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+ else
+ {
+ pObj->ClearMergedItem();
+ }
+
+ pObj->SetMergedItemSet(*moUndoSet);
+ }
+
+ // Restore previous size here when it was changed.
+ if(aSnapRect != pObj->GetSnapRect())
+ {
+ if(dynamic_cast<const SdrObjCustomShape*>(pObj))
+ pObj->NbcSetSnapRect(aLogicRect);
+ else
+ pObj->NbcSetSnapRect(aSnapRect);
+ }
+
+ pObj->GetProperties().BroadcastItemChange(aItemChange);
+
+ if(pTextUndo)
+ {
+ pObj->SetOutlinerParaObject(*pTextUndo);
+ }
+ }
+
+ if(pUndoGroup)
+ {
+ pUndoGroup->Undo();
+ }
+}
+
+void SdrUndoAttrObj::Redo()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(pObj);
+ bool bIs3DScene(dynamic_cast< E3dScene* >(pObj) != nullptr);
+
+ if(!pUndoGroup || bIs3DScene)
+ {
+ if(bStyleSheet)
+ {
+ mxUndoStyleSheet = pObj->GetStyleSheet();
+ SfxStyleSheet* pSheet = dynamic_cast< SfxStyleSheet* >(mxRedoStyleSheet.get());
+
+ if(pSheet && pObj->getSdrModelFromSdrObject().GetStyleSheetPool())
+ {
+ ensureStyleSheetInStyleSheetPool(*pObj->getSdrModelFromSdrObject().GetStyleSheetPool(), *pSheet);
+ pObj->SetStyleSheet(pSheet, true);
+ }
+ else
+ {
+ OSL_ENSURE(false, "OOps, something went wrong in SdrUndoAttrObj (!)");
+ }
+ }
+
+ sdr::properties::ItemChangeBroadcaster aItemChange(*pObj);
+
+ const tools::Rectangle aSnapRect = pObj->GetSnapRect();
+ const tools::Rectangle aLogicRect = pObj->GetLogicRect();
+
+ if(moRedoSet)
+ {
+ if(dynamic_cast<const SdrCaptionObj*>( pObj) != nullptr)
+ {
+ // do a more smooth item deletion here, else the text
+ // rect will be reformatted, especially when information regarding
+ // vertical text is changed. When clearing only set items it's
+ // slower, but safer regarding such information (it's not changed
+ // usually)
+ SfxWhichIter aIter(*moRedoSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ if(SfxItemState::SET != aIter.GetItemState(false))
+ {
+ pObj->ClearMergedItem(nWhich);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+ else
+ {
+ pObj->ClearMergedItem();
+ }
+
+ pObj->SetMergedItemSet(*moRedoSet);
+ }
+
+ // Restore previous size here when it was changed.
+ if(aSnapRect != pObj->GetSnapRect())
+ {
+ if(dynamic_cast<const SdrObjCustomShape*>(pObj))
+ pObj->NbcSetSnapRect(aLogicRect);
+ else
+ pObj->NbcSetSnapRect(aSnapRect);
+ }
+
+ pObj->GetProperties().BroadcastItemChange(aItemChange);
+
+ // #i8508#
+ if(pTextRedo)
+ {
+ pObj->SetOutlinerParaObject(*pTextRedo);
+ }
+ }
+
+ if(pUndoGroup)
+ {
+ pUndoGroup->Redo();
+ }
+
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+}
+
+OUString SdrUndoAttrObj::GetComment() const
+{
+ if(bStyleSheet)
+ {
+ return ImpGetDescriptionStr(STR_EditSetStylesheet);
+ }
+ else
+ {
+ return ImpGetDescriptionStr(STR_EditSetAttributes);
+ }
+}
+
+OUString SdrUndoAttrObj::GetSdrRepeatComment() const
+{
+ if(bStyleSheet)
+ {
+ return ImpGetDescriptionStr(STR_EditSetStylesheet, true);
+ }
+ else
+ {
+ return ImpGetDescriptionStr(STR_EditSetAttributes, true);
+ }
+}
+
+
+SdrUndoMoveObj::~SdrUndoMoveObj() {}
+
+void SdrUndoMoveObj::Undo()
+{
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+
+ pObj->Move(Size(-aDistance.Width(),-aDistance.Height()));
+}
+
+void SdrUndoMoveObj::Redo()
+{
+ pObj->Move(Size(aDistance.Width(),aDistance.Height()));
+
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+}
+
+OUString SdrUndoMoveObj::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_EditMove);
+}
+
+void SdrUndoMoveObj::SdrRepeat(SdrView& rView)
+{
+ rView.MoveMarkedObj(aDistance);
+}
+
+bool SdrUndoMoveObj::CanSdrRepeat(SdrView& rView) const
+{
+ return rView.AreObjectsMarked();
+}
+
+OUString SdrUndoMoveObj::GetSdrRepeatComment() const
+{
+ return ImpGetDescriptionStr(STR_EditMove,true);
+}
+
+
+SdrUndoGeoObj::SdrUndoGeoObj(SdrObject& rNewObj)
+ : SdrUndoObj(rNewObj)
+ , mbSkipChangeLayout(false)
+{
+ SdrObjList* pOL=rNewObj.GetSubList();
+ if (pOL!=nullptr && pOL->GetObjCount() && dynamic_cast<const E3dScene* >( &rNewObj) == nullptr)
+ {
+ // this is a group object!
+ // If this were 3D scene, we'd only add an Undo for the scene itself
+ // (which we do elsewhere).
+ pUndoGroup.reset(new SdrUndoGroup(pObj->getSdrModelFromSdrObject()));
+ const size_t nObjCount = pOL->GetObjCount();
+ for (size_t nObjNum = 0; nObjNum<nObjCount; ++nObjNum) {
+ pUndoGroup->AddAction(std::make_unique<SdrUndoGeoObj>(*pOL->GetObj(nObjNum)));
+ }
+ }
+ else
+ {
+ pUndoGeo = pObj->GetGeoData();
+ }
+}
+
+SdrUndoGeoObj::~SdrUndoGeoObj()
+{
+ pUndoGeo.reset();
+ pRedoGeo.reset();
+ pUndoGroup.reset();
+}
+
+void SdrUndoGeoObj::Undo()
+{
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+
+ if(pUndoGroup)
+ {
+ pUndoGroup->Undo();
+
+ // only repaint, no objectchange
+ pObj->ActionChanged();
+ }
+ else
+ {
+ pRedoGeo = pObj->GetGeoData();
+
+ auto pTableObj = dynamic_cast<sdr::table::SdrTableObj*>(pObj);
+ if (pTableObj && mbSkipChangeLayout)
+ pTableObj->SetSkipChangeLayout(true);
+ pObj->SetGeoData(*pUndoGeo);
+ if (pTableObj && mbSkipChangeLayout)
+ pTableObj->SetSkipChangeLayout(false);
+ }
+}
+
+void SdrUndoGeoObj::Redo()
+{
+ if(pUndoGroup)
+ {
+ pUndoGroup->Redo();
+
+ // only repaint, no objectchange
+ pObj->ActionChanged();
+ }
+ else
+ {
+ pUndoGeo = pObj->GetGeoData();
+ pObj->SetGeoData(*pRedoGeo);
+ }
+
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+}
+
+OUString SdrUndoGeoObj::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_DragMethObjOwn);
+}
+
+SdrUndoDiagramModelData::SdrUndoDiagramModelData(SdrObject& rNewObj, svx::diagram::DiagramDataStatePtr& rStartState)
+: SdrUndoObj(rNewObj)
+, m_aStartState(rStartState)
+, m_aEndState()
+{
+ if(rNewObj.isDiagram())
+ m_aEndState = rNewObj.getDiagramHelper()->extractDiagramDataState();
+}
+
+SdrUndoDiagramModelData::~SdrUndoDiagramModelData()
+{
+}
+
+void SdrUndoDiagramModelData::implUndoRedo(bool bUndo)
+{
+ if(nullptr == pObj)
+ return;
+
+ if(!pObj->isDiagram())
+ return;
+
+ pObj->getDiagramHelper()->applyDiagramDataState(
+ bUndo ? m_aStartState : m_aEndState);
+ pObj->getDiagramHelper()->reLayout(*static_cast<SdrObjGroup*>(pObj));
+}
+
+void SdrUndoDiagramModelData::Undo()
+{
+ implUndoRedo(true);
+}
+
+void SdrUndoDiagramModelData::Redo()
+{
+ implUndoRedo(false);
+}
+
+OUString SdrUndoDiagramModelData::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_DiagramModelDataChange);
+}
+
+SdrUndoObjList::SdrUndoObjList(SdrObject& rNewObj, bool bOrdNumDirect)
+ : SdrUndoObj(rNewObj)
+ , bOwner(false)
+{
+ pObjList=pObj->getParentSdrObjListFromSdrObject();
+ if (bOrdNumDirect)
+ {
+ nOrdNum=pObj->GetOrdNumDirect();
+ }
+ else
+ {
+ nOrdNum=pObj->GetOrdNum();
+ }
+}
+
+SdrUndoObjList::~SdrUndoObjList()
+{
+ SolarMutexGuard aGuard;
+
+ if (pObj!=nullptr && IsOwner())
+ {
+ // Attribute have to go back to the regular Pool
+ SetOwner(false);
+
+ // now delete
+ SdrObject::Free( pObj );
+ }
+}
+
+void SdrUndoObjList::SetOwner(bool bNew)
+{
+ bOwner = bNew;
+}
+
+
+void SdrUndoRemoveObj::Undo()
+{
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+
+ DBG_ASSERT(!pObj->IsInserted(),"UndoRemoveObj: pObj has already been inserted.");
+ if (pObj->IsInserted())
+ return;
+
+ // #i11426#
+ // For UNDOs in Calc/Writer it is necessary to adapt the anchor
+ // position of the target object.
+ Point aOwnerAnchorPos(0, 0);
+
+ if (dynamic_cast< const SdrObjGroup* >(pObjList->getSdrObjectFromSdrObjList()) != nullptr)
+ {
+ aOwnerAnchorPos = pObjList->getSdrObjectFromSdrObjList()->GetAnchorPos();
+ }
+
+ E3DModifySceneSnapRectUpdater aUpdater(pObjList->getSdrObjectFromSdrObjList());
+ pObjList->InsertObject(pObj,nOrdNum);
+
+ // #i11426#
+ if(aOwnerAnchorPos.X() || aOwnerAnchorPos.Y())
+ {
+ pObj->NbcSetAnchorPos(aOwnerAnchorPos);
+ }
+}
+
+void SdrUndoRemoveObj::Redo()
+{
+ DBG_ASSERT(pObj->IsInserted(),"RedoRemoveObj: pObj is not inserted.");
+ if (pObj->IsInserted())
+ {
+ ImplUnmarkObject( pObj );
+ E3DModifySceneSnapRectUpdater aUpdater(pObj);
+ pObjList->RemoveObject(pObj->GetOrdNum());
+ }
+
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+}
+
+SdrUndoRemoveObj::~SdrUndoRemoveObj()
+{
+}
+
+
+void SdrUndoInsertObj::Undo()
+{
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+
+ DBG_ASSERT(pObj->IsInserted(),"UndoInsertObj: pObj is not inserted.");
+ if (pObj->IsInserted())
+ {
+ ImplUnmarkObject( pObj );
+
+ SdrObject* pChkObj= pObjList->RemoveObject(pObj->GetOrdNum());
+ DBG_ASSERT(pChkObj==pObj,"UndoInsertObj: RemoveObjNum!=pObj");
+ }
+}
+
+void SdrUndoInsertObj::Redo()
+{
+ DBG_ASSERT(!pObj->IsInserted(),"RedoInsertObj: pObj is already inserted");
+ if (!pObj->IsInserted())
+ {
+ // Restore anchor position of an object,
+ // which becomes a member of a group, because its cleared in method
+ // <InsertObject(..)>. Needed for correct Redo in Writer. (#i45952#)
+ Point aAnchorPos( 0, 0 );
+
+ if (dynamic_cast<const SdrObjGroup*>(pObjList->getSdrObjectFromSdrObjList()) != nullptr)
+ {
+ aAnchorPos = pObj->GetAnchorPos();
+ }
+
+ pObjList->InsertObject(pObj,nOrdNum);
+
+ // Arcs lose position when grouped (#i45952#)
+ if ( aAnchorPos.X() || aAnchorPos.Y() )
+ {
+ pObj->NbcSetAnchorPos( aAnchorPos );
+ }
+ }
+
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+}
+
+SdrUndoDelObj::SdrUndoDelObj(SdrObject& rNewObj, bool bOrdNumDirect)
+: SdrUndoRemoveObj(rNewObj,bOrdNumDirect)
+{
+ SetOwner(true);
+}
+
+void SdrUndoDelObj::Undo()
+{
+ SdrUndoRemoveObj::Undo();
+ DBG_ASSERT(IsOwner(),"UndoDeleteObj: pObj does not belong to UndoAction");
+ SetOwner(false);
+}
+
+void SdrUndoDelObj::Redo()
+{
+ SdrUndoRemoveObj::Redo();
+ DBG_ASSERT(!IsOwner(),"RedoDeleteObj: pObj already belongs to UndoAction");
+ SetOwner(true);
+}
+
+OUString SdrUndoDelObj::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_EditDelete);
+}
+
+void SdrUndoDelObj::SdrRepeat(SdrView& rView)
+{
+ rView.DeleteMarked();
+}
+
+bool SdrUndoDelObj::CanSdrRepeat(SdrView& rView) const
+{
+ return rView.AreObjectsMarked();
+}
+
+OUString SdrUndoDelObj::GetSdrRepeatComment() const
+{
+ return ImpGetDescriptionStr(STR_EditDelete,true);
+}
+
+
+void SdrUndoNewObj::Undo()
+{
+ SdrUndoInsertObj::Undo();
+ DBG_ASSERT(!IsOwner(),"RedoNewObj: pObj already belongs to UndoAction");
+ SetOwner(true);
+}
+
+void SdrUndoNewObj::Redo()
+{
+ SdrUndoInsertObj::Redo();
+ DBG_ASSERT(IsOwner(),"RedoNewObj: pObj does not belong to UndoAction");
+ SetOwner(false);
+}
+
+OUString SdrUndoNewObj::GetComment( const SdrObject& _rForObject )
+{
+ return GetDescriptionStringForObject( _rForObject, STR_UndoInsertObj );
+}
+
+OUString SdrUndoNewObj::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoInsertObj);
+}
+
+SdrUndoReplaceObj::SdrUndoReplaceObj(SdrObject& rOldObj1, SdrObject& rNewObj1)
+ : SdrUndoObj(rOldObj1)
+ , bOldOwner(false)
+ , bNewOwner(false)
+ , pNewObj(&rNewObj1)
+{
+ SetOldOwner(true);
+ pObjList=pObj->getParentSdrObjListFromSdrObject();
+}
+
+SdrUndoReplaceObj::~SdrUndoReplaceObj()
+{
+ if (pObj!=nullptr && IsOldOwner())
+ {
+ // Attribute have to go back into the Pool
+ SetOldOwner(false);
+
+ // now delete
+ SdrObject::Free( pObj );
+ }
+ if (pNewObj!=nullptr && IsNewOwner())
+ {
+ // Attribute have to go back into the Pool
+ SetNewOwner(false);
+
+ // now delete
+ SdrObject::Free( pNewObj );
+ }
+}
+
+void SdrUndoReplaceObj::Undo()
+{
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+
+ if (IsOldOwner() && !IsNewOwner())
+ {
+ DBG_ASSERT(!pObj->IsInserted(),"SdrUndoReplaceObj::Undo(): Old object is already inserted!");
+ DBG_ASSERT(pNewObj->IsInserted(),"SdrUndoReplaceObj::Undo(): New object is not inserted!");
+ SetOldOwner(false);
+ SetNewOwner(true);
+
+ ImplUnmarkObject( pNewObj );
+ pObjList->ReplaceObject(pObj,pNewObj->GetOrdNum());
+ }
+ else
+ {
+ OSL_FAIL("SdrUndoReplaceObj::Undo(): Wrong IsMine flags. Did you call Undo twice?");
+ }
+}
+
+void SdrUndoReplaceObj::Redo()
+{
+ if (!IsOldOwner() && IsNewOwner())
+ {
+ DBG_ASSERT(!pNewObj->IsInserted(),"SdrUndoReplaceObj::Redo(): New object is already inserted!!");
+ DBG_ASSERT(pObj->IsInserted(),"SdrUndoReplaceObj::Redo(): Old object is not inserted!!");
+ SetOldOwner(true);
+ SetNewOwner(false);
+
+ ImplUnmarkObject( pObj );
+ pObjList->ReplaceObject(pNewObj,pObj->GetOrdNum());
+
+ }
+ else
+ {
+ OSL_FAIL("SdrUndoReplaceObj::Redo(): Wrong IsMine flags. Did you call Redo twice?");
+ }
+
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+}
+
+void SdrUndoReplaceObj::SetNewOwner(bool bNew)
+{
+ bNewOwner = bNew;
+}
+
+void SdrUndoReplaceObj::SetOldOwner(bool bNew)
+{
+ bOldOwner = bNew;
+}
+
+
+OUString SdrUndoCopyObj::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoCopyObj);
+}
+
+
+// #i11702#
+
+SdrUndoObjectLayerChange::SdrUndoObjectLayerChange(SdrObject& rObj, SdrLayerID aOldLayer, SdrLayerID aNewLayer)
+ : SdrUndoObj(rObj)
+ , maOldLayer(aOldLayer)
+ , maNewLayer(aNewLayer)
+{
+}
+
+void SdrUndoObjectLayerChange::Undo()
+{
+ ImpShowPageOfThisObject();
+ pObj->SetLayer(maOldLayer);
+}
+
+void SdrUndoObjectLayerChange::Redo()
+{
+ pObj->SetLayer(maNewLayer);
+ ImpShowPageOfThisObject();
+}
+
+
+SdrUndoObjOrdNum::SdrUndoObjOrdNum(SdrObject& rNewObj, sal_uInt32 nOldOrdNum1, sal_uInt32 nNewOrdNum1)
+ : SdrUndoObj(rNewObj)
+ , nOldOrdNum(nOldOrdNum1)
+ , nNewOrdNum(nNewOrdNum1)
+{
+}
+
+void SdrUndoObjOrdNum::Undo()
+{
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ if (pOL==nullptr)
+ {
+ OSL_FAIL("UndoObjOrdNum: pObj does not have an ObjList.");
+ return;
+ }
+ pOL->SetObjectOrdNum(nNewOrdNum,nOldOrdNum);
+}
+
+void SdrUndoObjOrdNum::Redo()
+{
+ SdrObjList* pOL=pObj->getParentSdrObjListFromSdrObject();
+ if (pOL==nullptr)
+ {
+ OSL_FAIL("RedoObjOrdNum: pObj does not have an ObjList.");
+ return;
+ }
+ pOL->SetObjectOrdNum(nOldOrdNum,nNewOrdNum);
+
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+}
+
+OUString SdrUndoObjOrdNum::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoObjOrdNum);
+}
+
+SdrUndoSort::SdrUndoSort(const SdrPage & rPage,
+ ::std::vector<sal_Int32> const& rSortOrder)
+ : SdrUndoAction(rPage.getSdrModelFromSdrPage())
+ , m_OldSortOrder(rSortOrder.size())
+ , m_NewSortOrder(rSortOrder)
+ , m_nPage(rPage.GetPageNum())
+{
+ // invert order
+ for (size_t i = 0; i < rSortOrder.size(); ++i)
+ {
+ m_OldSortOrder[rSortOrder[i]] = i;
+ }
+}
+
+void SdrUndoSort::Do(::std::vector<sal_Int32> & rSortOrder)
+{
+ SdrPage & rPage(*rMod.GetPage(m_nPage));
+ if (rPage.GetObjCount() != rSortOrder.size())
+ {
+ // can probably happen with sw's cursed SdrVirtObj mess - no good solution for that
+ SAL_WARN("svx", "SdrUndoSort size mismatch");
+ return;
+ }
+
+ // hopefully this can't throw
+ rPage.sort(rSortOrder);
+}
+
+void SdrUndoSort::Undo()
+{
+ Do(m_OldSortOrder);
+}
+
+void SdrUndoSort::Redo()
+{
+ Do(m_NewSortOrder);
+}
+
+OUString SdrUndoSort::GetComment() const
+{
+ return SvxResId(STR_SortShapes);
+}
+
+SdrUndoObjSetText::SdrUndoObjSetText(SdrObject& rNewObj, sal_Int32 nText)
+ : SdrUndoObj(rNewObj)
+ , bNewTextAvailable(false)
+ , bEmptyPresObj(false)
+ , mnText(nText)
+{
+ SdrText* pText = static_cast< SdrTextObj*>( &rNewObj )->getText(mnText);
+ if( pText && pText->GetOutlinerParaObject() )
+ pOldText = *pText->GetOutlinerParaObject();
+
+ bEmptyPresObj = rNewObj.IsEmptyPresObj();
+}
+
+SdrUndoObjSetText::~SdrUndoObjSetText()
+{
+ pOldText.reset();
+ pNewText.reset();
+}
+
+bool SdrUndoObjSetText::IsDifferent() const
+{
+ if (!pOldText || !pNewText)
+ return pOldText || pNewText;
+ return *pOldText != *pNewText;
+}
+
+void SdrUndoObjSetText::AfterSetText()
+{
+ if (!bNewTextAvailable)
+ {
+ SdrText* pText = static_cast< SdrTextObj*>( pObj )->getText(mnText);
+ if( pText && pText->GetOutlinerParaObject() )
+ pNewText = *pText->GetOutlinerParaObject();
+ bNewTextAvailable=true;
+ }
+}
+
+void SdrUndoObjSetText::Undo()
+{
+ // only works with SdrTextObj
+ SdrTextObj* pTarget = dynamic_cast< SdrTextObj* >(pObj);
+
+ if(!pTarget)
+ {
+ OSL_ENSURE(false, "SdrUndoObjSetText::Undo with SdrObject not based on SdrTextObj (!)");
+ return;
+ }
+
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+
+ // save old text for Redo
+ if(!bNewTextAvailable)
+ {
+ AfterSetText();
+ }
+
+ SdrText* pText = pTarget->getText(mnText);
+ if (pText)
+ {
+ // copy text for Undo, because the original now belongs to SetOutlinerParaObject()
+ pTarget->NbcSetOutlinerParaObjectForText(pOldText, pText);
+ }
+
+ pTarget->SetEmptyPresObj(bEmptyPresObj);
+ pTarget->ActionChanged();
+
+ // #i124389# if it's a table, also need to relayout TextFrame
+ if(dynamic_cast< sdr::table::SdrTableObj* >(pTarget) != nullptr)
+ {
+ pTarget->NbcAdjustTextFrameWidthAndHeight();
+ }
+
+ // #i122410# SetOutlinerParaObject at SdrText does not trigger a
+ // BroadcastObjectChange, but it is needed to make evtl. SlideSorters
+ // update their preview.
+ pTarget->BroadcastObjectChange();
+}
+
+void SdrUndoObjSetText::Redo()
+{
+ // only works with SdrTextObj
+ SdrTextObj* pTarget = dynamic_cast< SdrTextObj* >(pObj);
+
+ if(!pTarget)
+ {
+ OSL_ENSURE(false, "SdrUndoObjSetText::Redo with SdrObject not based on SdrTextObj (!)");
+ return;
+ }
+
+ SdrText* pText = pTarget->getText(mnText);
+ if (pText)
+ {
+ // copy text for Undo, because the original now belongs to SetOutlinerParaObject()
+ pTarget->NbcSetOutlinerParaObjectForText( pNewText, pText );
+ }
+
+ pTarget->ActionChanged();
+
+ // #i124389# if it's a table, also need to relayout TextFrame
+ if(dynamic_cast< sdr::table::SdrTableObj* >(pTarget) != nullptr)
+ {
+ pTarget->NbcAdjustTextFrameWidthAndHeight();
+ }
+
+ // #i122410# NbcSetOutlinerParaObjectForText at SdrTextObj does not trigger a
+ // BroadcastObjectChange, but it is needed to make evtl. SlideSorters
+ // update their preview.
+ pTarget->BroadcastObjectChange();
+
+ // Trigger PageChangeCall
+ ImpShowPageOfThisObject();
+}
+
+OUString SdrUndoObjSetText::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoObjSetText);
+}
+
+OUString SdrUndoObjSetText::GetSdrRepeatComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoObjSetText);
+}
+
+void SdrUndoObjSetText::SdrRepeat(SdrView& rView)
+{
+ if (!(bNewTextAvailable && rView.AreObjectsMarked()))
+ return;
+
+ const SdrMarkList& rML=rView.GetMarkedObjectList();
+
+ const bool bUndo = rView.IsUndoEnabled();
+ if( bUndo )
+ {
+ OUString aStr = ImpGetDescriptionStr(STR_UndoObjSetText);
+ rView.BegUndo(aStr);
+ }
+
+ const size_t nCount=rML.GetMarkCount();
+ for (size_t nm=0; nm<nCount; ++nm)
+ {
+ SdrObject* pObj2=rML.GetMark(nm)->GetMarkedSdrObj();
+ SdrTextObj* pTextObj=dynamic_cast<SdrTextObj*>( pObj2 );
+ if (pTextObj!=nullptr)
+ {
+ if( bUndo )
+ rView.AddUndo(std::make_unique<SdrUndoObjSetText>(*pTextObj,0));
+
+ pTextObj->SetOutlinerParaObject(pNewText);
+ }
+ }
+
+ if( bUndo )
+ rView.EndUndo();
+}
+
+bool SdrUndoObjSetText::CanSdrRepeat(SdrView& rView) const
+{
+ bool bOk = false;
+ if (bNewTextAvailable && rView.AreObjectsMarked()) {
+ bOk=true;
+ }
+ return bOk;
+}
+
+// Undo/Redo for setting object's name (#i73249#)
+SdrUndoObjStrAttr::SdrUndoObjStrAttr( SdrObject& rNewObj,
+ const ObjStrAttrType eObjStrAttr,
+ const OUString& sOldStr,
+ const OUString& sNewStr)
+ : SdrUndoObj( rNewObj )
+ , meObjStrAttr( eObjStrAttr )
+ , msOldStr( sOldStr )
+ , msNewStr( sNewStr )
+{
+}
+
+void SdrUndoObjStrAttr::Undo()
+{
+ ImpShowPageOfThisObject();
+
+ switch ( meObjStrAttr )
+ {
+ case ObjStrAttrType::Name:
+ pObj->SetName( msOldStr );
+ break;
+ case ObjStrAttrType::Title:
+ pObj->SetTitle( msOldStr );
+ break;
+ case ObjStrAttrType::Description:
+ pObj->SetDescription( msOldStr );
+ break;
+ }
+}
+
+void SdrUndoObjStrAttr::Redo()
+{
+ switch ( meObjStrAttr )
+ {
+ case ObjStrAttrType::Name:
+ pObj->SetName( msNewStr );
+ break;
+ case ObjStrAttrType::Title:
+ pObj->SetTitle( msNewStr );
+ break;
+ case ObjStrAttrType::Description:
+ pObj->SetDescription( msNewStr );
+ break;
+ }
+
+ ImpShowPageOfThisObject();
+}
+
+OUString SdrUndoObjStrAttr::GetComment() const
+{
+ OUString aStr;
+ switch ( meObjStrAttr )
+ {
+ case ObjStrAttrType::Name:
+ aStr = ImpGetDescriptionStr( STR_UndoObjName) +
+ " '" + msNewStr + "'";
+ break;
+ case ObjStrAttrType::Title:
+ aStr = ImpGetDescriptionStr( STR_UndoObjTitle );
+ break;
+ case ObjStrAttrType::Description:
+ aStr = ImpGetDescriptionStr( STR_UndoObjDescription );
+ break;
+ }
+
+ return aStr;
+}
+
+
+SdrUndoLayer::SdrUndoLayer(sal_uInt16 nLayerNum, SdrLayerAdmin& rNewLayerAdmin, SdrModel& rNewModel)
+ : SdrUndoAction(rNewModel)
+ , pLayer(rNewLayerAdmin.GetLayer(nLayerNum))
+ , pLayerAdmin(&rNewLayerAdmin)
+ , nNum(nLayerNum)
+ , bItsMine(false)
+{
+}
+
+SdrUndoLayer::~SdrUndoLayer()
+{
+ if (bItsMine)
+ {
+ delete pLayer;
+ }
+}
+
+
+void SdrUndoNewLayer::Undo()
+{
+ DBG_ASSERT(!bItsMine,"SdrUndoNewLayer::Undo(): Layer already belongs to UndoAction.");
+ bItsMine=true;
+ SdrLayer* pCmpLayer= pLayerAdmin->RemoveLayer(nNum).release();
+ DBG_ASSERT(pCmpLayer==pLayer,"SdrUndoNewLayer::Undo(): Removed layer is != pLayer.");
+}
+
+void SdrUndoNewLayer::Redo()
+{
+ DBG_ASSERT(bItsMine,"SdrUndoNewLayer::Undo(): Layer does not belong to UndoAction.");
+ bItsMine=false;
+ pLayerAdmin->InsertLayer(std::unique_ptr<SdrLayer>(pLayer),nNum);
+}
+
+OUString SdrUndoNewLayer::GetComment() const
+{
+ return SvxResId(STR_UndoNewLayer);
+}
+
+
+void SdrUndoDelLayer::Undo()
+{
+ DBG_ASSERT(bItsMine,"SdrUndoDelLayer::Undo(): Layer does not belong to UndoAction.");
+ bItsMine=false;
+ pLayerAdmin->InsertLayer(std::unique_ptr<SdrLayer>(pLayer),nNum);
+}
+
+void SdrUndoDelLayer::Redo()
+{
+ DBG_ASSERT(!bItsMine,"SdrUndoDelLayer::Undo(): Layer already belongs to UndoAction.");
+ bItsMine=true;
+ SdrLayer* pCmpLayer= pLayerAdmin->RemoveLayer(nNum).release();
+ DBG_ASSERT(pCmpLayer==pLayer,"SdrUndoDelLayer::Redo(): Removed layer is != pLayer.");
+}
+
+OUString SdrUndoDelLayer::GetComment() const
+{
+ return SvxResId(STR_UndoDelLayer);
+}
+
+
+SdrUndoPage::SdrUndoPage(SdrPage& rNewPg)
+: SdrUndoAction(rNewPg.getSdrModelFromSdrPage())
+ ,mxPage(&rNewPg)
+{
+}
+
+SdrUndoPage::~SdrUndoPage() {}
+
+void SdrUndoPage::ImpInsertPage(sal_uInt16 nNum)
+{
+ DBG_ASSERT(!mxPage->IsInserted(),"SdrUndoPage::ImpInsertPage(): mxPage is already inserted.");
+ if (!mxPage->IsInserted())
+ {
+ if (mxPage->IsMasterPage())
+ {
+ rMod.InsertMasterPage(mxPage.get(), nNum);
+ }
+ else
+ {
+ rMod.InsertPage(mxPage.get(), nNum);
+ }
+ }
+}
+
+void SdrUndoPage::ImpRemovePage(sal_uInt16 nNum)
+{
+ DBG_ASSERT(mxPage->IsInserted(),"SdrUndoPage::ImpRemovePage(): mxPage is not inserted.");
+ if (!mxPage->IsInserted())
+ return;
+
+ rtl::Reference<SdrPage> pChkPg;
+ if (mxPage->IsMasterPage())
+ {
+ pChkPg = rMod.RemoveMasterPage(nNum);
+ }
+ else
+ {
+ pChkPg = rMod.RemovePage(nNum);
+ }
+ DBG_ASSERT(pChkPg==mxPage,"SdrUndoPage::ImpRemovePage(): RemovePage!=mxPage");
+}
+
+void SdrUndoPage::ImpMovePage(sal_uInt16 nOldNum, sal_uInt16 nNewNum)
+{
+ DBG_ASSERT(mxPage->IsInserted(),"SdrUndoPage::ImpMovePage(): mxPage is not inserted.");
+ if (mxPage->IsInserted())
+ {
+ if (mxPage->IsMasterPage())
+ {
+ rMod.MoveMasterPage(nOldNum,nNewNum);
+ }
+ else
+ {
+ rMod.MovePage(nOldNum,nNewNum);
+ }
+ }
+}
+
+OUString SdrUndoPage::ImpGetDescriptionStr(TranslateId pStrCacheID)
+{
+ return SvxResId(pStrCacheID);
+}
+
+
+SdrUndoPageList::SdrUndoPageList(SdrPage& rNewPg)
+ : SdrUndoPage(rNewPg)
+{
+ nPageNum=rNewPg.GetPageNum();
+}
+
+SdrUndoPageList::~SdrUndoPageList()
+{
+}
+
+
+SdrUndoDelPage::SdrUndoDelPage(SdrPage& rNewPg)
+ : SdrUndoPageList(rNewPg)
+ , mbHasFillBitmap(false)
+{
+ // keep fill bitmap separately to remove it from pool if not used elsewhere
+ if (mxPage->IsMasterPage())
+ {
+ SfxStyleSheet* const pStyleSheet = mxPage->getSdrPageProperties().GetStyleSheet();
+ if (pStyleSheet)
+ queryFillBitmap(pStyleSheet->GetItemSet());
+ }
+ else
+ {
+ queryFillBitmap(mxPage->getSdrPageProperties().GetItemSet());
+ }
+ if (bool(mpFillBitmapItem))
+ clearFillBitmap();
+
+ // now remember the master page relationships
+ if(!mxPage->IsMasterPage())
+ return;
+
+ sal_uInt16 nPageCnt(rMod.GetPageCount());
+
+ for(sal_uInt16 nPageNum2(0); nPageNum2 < nPageCnt; nPageNum2++)
+ {
+ SdrPage* pDrawPage = rMod.GetPage(nPageNum2);
+
+ if(pDrawPage->TRG_HasMasterPage())
+ {
+ SdrPage& rMasterPage = pDrawPage->TRG_GetMasterPage();
+
+ if(mxPage.get() == &rMasterPage)
+ {
+ if(!pUndoGroup)
+ {
+ pUndoGroup.reset( new SdrUndoGroup(rMod) );
+ }
+
+ pUndoGroup->AddAction(rMod.GetSdrUndoFactory().CreateUndoPageRemoveMasterPage(*pDrawPage));
+ }
+ }
+ }
+}
+
+SdrUndoDelPage::~SdrUndoDelPage()
+{
+}
+
+void SdrUndoDelPage::Undo()
+{
+ if (bool(mpFillBitmapItem))
+ restoreFillBitmap();
+ ImpInsertPage(nPageNum);
+ if (pUndoGroup!=nullptr)
+ {
+ // recover master page relationships
+ pUndoGroup->Undo();
+ }
+}
+
+void SdrUndoDelPage::Redo()
+{
+ ImpRemovePage(nPageNum);
+ if (bool(mpFillBitmapItem))
+ clearFillBitmap();
+}
+
+OUString SdrUndoDelPage::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoDelPage);
+}
+
+OUString SdrUndoDelPage::GetSdrRepeatComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoDelPage);
+}
+
+void SdrUndoDelPage::SdrRepeat(SdrView& /*rView*/)
+{
+}
+
+bool SdrUndoDelPage::CanSdrRepeat(SdrView& /*rView*/) const
+{
+ return false;
+}
+
+void SdrUndoDelPage::queryFillBitmap(const SfxItemSet& rItemSet)
+{
+ if (const XFillBitmapItem *pItem = rItemSet.GetItemIfSet(XATTR_FILLBITMAP, false))
+ mpFillBitmapItem.reset(pItem->Clone());
+ if (const XFillStyleItem *pItem = rItemSet.GetItemIfSet(XATTR_FILLSTYLE, false))
+ mbHasFillBitmap = pItem->GetValue() == css::drawing::FillStyle_BITMAP;
+}
+
+void SdrUndoDelPage::clearFillBitmap()
+{
+ if (mxPage->IsMasterPage())
+ {
+ SfxStyleSheet* const pStyleSheet = mxPage->getSdrPageProperties().GetStyleSheet();
+ assert(bool(pStyleSheet)); // who took away my stylesheet?
+ if (pStyleSheet->GetListenerCount() == 1)
+ {
+ SfxItemSet& rItemSet = pStyleSheet->GetItemSet();
+ rItemSet.ClearItem(XATTR_FILLBITMAP);
+ if (mbHasFillBitmap)
+ rItemSet.ClearItem(XATTR_FILLSTYLE);
+ }
+ }
+ else
+ {
+ SdrPageProperties &rPageProps = mxPage->getSdrPageProperties();
+ rPageProps.ClearItem(XATTR_FILLBITMAP);
+ if (mbHasFillBitmap)
+ rPageProps.ClearItem(XATTR_FILLSTYLE);
+ }
+}
+
+void SdrUndoDelPage::restoreFillBitmap()
+{
+ if (mxPage->IsMasterPage())
+ {
+ SfxStyleSheet* const pStyleSheet = mxPage->getSdrPageProperties().GetStyleSheet();
+ assert(bool(pStyleSheet)); // who took away my stylesheet?
+ if (pStyleSheet->GetListenerCount() == 1)
+ {
+ SfxItemSet& rItemSet = pStyleSheet->GetItemSet();
+ rItemSet.Put(*mpFillBitmapItem);
+ if (mbHasFillBitmap)
+ rItemSet.Put(XFillStyleItem(css::drawing::FillStyle_BITMAP));
+ }
+ }
+ else
+ {
+ SdrPageProperties &rPageProps = mxPage->getSdrPageProperties();
+ rPageProps.PutItem(*mpFillBitmapItem);
+ if (mbHasFillBitmap)
+ rPageProps.PutItem(XFillStyleItem(css::drawing::FillStyle_BITMAP));
+ }
+}
+
+
+void SdrUndoNewPage::Undo()
+{
+ ImpRemovePage(nPageNum);
+}
+
+void SdrUndoNewPage::Redo()
+{
+ ImpInsertPage(nPageNum);
+}
+
+OUString SdrUndoNewPage::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoNewPage);
+}
+
+
+OUString SdrUndoCopyPage::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoCopPage);
+}
+
+OUString SdrUndoCopyPage::GetSdrRepeatComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoCopPage);
+}
+
+void SdrUndoCopyPage::SdrRepeat(SdrView& /*rView*/)
+{
+
+}
+
+bool SdrUndoCopyPage::CanSdrRepeat(SdrView& /*rView*/) const
+{
+ return false;
+}
+
+
+void SdrUndoSetPageNum::Undo()
+{
+ ImpMovePage(nNewPageNum,nOldPageNum);
+}
+
+void SdrUndoSetPageNum::Redo()
+{
+ ImpMovePage(nOldPageNum,nNewPageNum);
+}
+
+OUString SdrUndoSetPageNum::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoMovPage);
+}
+
+SdrUndoPageMasterPage::SdrUndoPageMasterPage(SdrPage& rChangedPage)
+ : SdrUndoPage(rChangedPage)
+ , mbOldHadMasterPage(mxPage->TRG_HasMasterPage())
+ , maOldMasterPageNumber(0)
+{
+ // get current state from page
+ if(mbOldHadMasterPage)
+ {
+ maOldSet = mxPage->TRG_GetMasterPageVisibleLayers();
+ maOldMasterPageNumber = mxPage->TRG_GetMasterPage().GetPageNum();
+ }
+}
+
+SdrUndoPageMasterPage::~SdrUndoPageMasterPage()
+{
+}
+
+SdrUndoPageRemoveMasterPage::SdrUndoPageRemoveMasterPage(SdrPage& rChangedPage)
+: SdrUndoPageMasterPage(rChangedPage)
+{
+}
+
+void SdrUndoPageRemoveMasterPage::Undo()
+{
+ if(mbOldHadMasterPage)
+ {
+ mxPage->TRG_SetMasterPage(*mxPage->getSdrModelFromSdrPage().GetMasterPage(maOldMasterPageNumber));
+ mxPage->TRG_SetMasterPageVisibleLayers(maOldSet);
+ }
+}
+
+void SdrUndoPageRemoveMasterPage::Redo()
+{
+ mxPage->TRG_ClearMasterPage();
+}
+
+OUString SdrUndoPageRemoveMasterPage::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoDelPageMasterDscr);
+}
+
+SdrUndoPageChangeMasterPage::SdrUndoPageChangeMasterPage(SdrPage& rChangedPage)
+ : SdrUndoPageMasterPage(rChangedPage)
+ , mbNewHadMasterPage(false)
+ , maNewMasterPageNumber(0)
+{
+}
+
+void SdrUndoPageChangeMasterPage::Undo()
+{
+ // remember values from new page
+ if(mxPage->TRG_HasMasterPage())
+ {
+ mbNewHadMasterPage = true;
+ maNewSet = mxPage->TRG_GetMasterPageVisibleLayers();
+ maNewMasterPageNumber = mxPage->TRG_GetMasterPage().GetPageNum();
+ }
+
+ // restore old values
+ if(mbOldHadMasterPage)
+ {
+ mxPage->TRG_ClearMasterPage();
+ mxPage->TRG_SetMasterPage(*mxPage->getSdrModelFromSdrPage().GetMasterPage(maOldMasterPageNumber));
+ mxPage->TRG_SetMasterPageVisibleLayers(maOldSet);
+ }
+}
+
+void SdrUndoPageChangeMasterPage::Redo()
+{
+ // restore new values
+ if(mbNewHadMasterPage)
+ {
+ mxPage->TRG_ClearMasterPage();
+ mxPage->TRG_SetMasterPage(*mxPage->getSdrModelFromSdrPage().GetMasterPage(maNewMasterPageNumber));
+ mxPage->TRG_SetMasterPageVisibleLayers(maNewSet);
+ }
+}
+
+OUString SdrUndoPageChangeMasterPage::GetComment() const
+{
+ return ImpGetDescriptionStr(STR_UndoChgPageMasterDscr);
+}
+
+
+SdrUndoFactory::~SdrUndoFactory(){}
+
+// shapes
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoMoveObject( SdrObject& rObject, const Size& rDist )
+{
+ return std::make_unique<SdrUndoMoveObj>( rObject, rDist );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoGeoObject( SdrObject& rObject )
+{
+ return std::make_unique<SdrUndoGeoObj>( rObject );
+}
+
+// Diagram ModelData changes
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoDiagramModelData( SdrObject& rObject, std::shared_ptr< svx::diagram::DiagramDataState >& rStartState )
+{
+ return std::make_unique<SdrUndoDiagramModelData>( rObject, rStartState );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoAttrObject( SdrObject& rObject, bool bStyleSheet1, bool bSaveText )
+{
+ return std::make_unique<SdrUndoAttrObj>( rObject, bStyleSheet1, bSaveText );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoRemoveObject(SdrObject& rObject)
+{
+ return std::make_unique<SdrUndoRemoveObj>(rObject);
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoInsertObject( SdrObject& rObject, bool bOrdNumDirect )
+{
+ return std::make_unique<SdrUndoInsertObj>( rObject, bOrdNumDirect );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoDeleteObject( SdrObject& rObject, bool bOrdNumDirect )
+{
+ return std::make_unique<SdrUndoDelObj>( rObject, bOrdNumDirect );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoNewObject( SdrObject& rObject, bool bOrdNumDirect )
+{
+ return std::make_unique<SdrUndoNewObj>( rObject, bOrdNumDirect );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoCopyObject( SdrObject& rObject, bool bOrdNumDirect )
+{
+ return std::make_unique<SdrUndoCopyObj>( rObject, bOrdNumDirect );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoObjectOrdNum( SdrObject& rObject, sal_uInt32 nOldOrdNum1, sal_uInt32 nNewOrdNum1)
+{
+ return std::make_unique<SdrUndoObjOrdNum>( rObject, nOldOrdNum1, nNewOrdNum1 );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoSort(SdrPage & rPage, ::std::vector<sal_Int32> const& rSortOrder)
+{
+ return std::make_unique<SdrUndoSort>(rPage, rSortOrder);
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoReplaceObject( SdrObject& rOldObject, SdrObject& rNewObject )
+{
+ return std::make_unique<SdrUndoReplaceObj>( rOldObject, rNewObject );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoObjectLayerChange( SdrObject& rObject, SdrLayerID aOldLayer, SdrLayerID aNewLayer )
+{
+ return std::make_unique<SdrUndoObjectLayerChange>( rObject, aOldLayer, aNewLayer );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoObjectSetText( SdrObject& rNewObj, sal_Int32 nText )
+{
+ return std::make_unique<SdrUndoObjSetText>( rNewObj, nText );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoObjectStrAttr( SdrObject& rObject,
+ SdrUndoObjStrAttr::ObjStrAttrType eObjStrAttrType,
+ const OUString& sOldStr,
+ const OUString& sNewStr )
+{
+ return std::make_unique<SdrUndoObjStrAttr>( rObject, eObjStrAttrType, sOldStr, sNewStr );
+}
+
+
+// layer
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoNewLayer(sal_uInt16 nLayerNum, SdrLayerAdmin& rNewLayerAdmin, SdrModel& rNewModel)
+{
+ return std::make_unique<SdrUndoNewLayer>( nLayerNum, rNewLayerAdmin, rNewModel );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoDeleteLayer(sal_uInt16 nLayerNum, SdrLayerAdmin& rNewLayerAdmin, SdrModel& rNewModel)
+{
+ return std::make_unique<SdrUndoDelLayer>( nLayerNum, rNewLayerAdmin, rNewModel );
+}
+
+// page
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoDeletePage(SdrPage& rPage)
+{
+ return std::make_unique<SdrUndoDelPage>(rPage);
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoNewPage(SdrPage& rPage)
+{
+ return std::make_unique<SdrUndoNewPage>( rPage );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoCopyPage(SdrPage& rPage)
+{
+ return std::make_unique<SdrUndoCopyPage>( rPage );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoSetPageNum(SdrPage& rNewPg, sal_uInt16 nOldPageNum1, sal_uInt16 nNewPageNum1)
+{
+ return std::make_unique<SdrUndoSetPageNum>( rNewPg, nOldPageNum1, nNewPageNum1 );
+}
+ // master page
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoPageRemoveMasterPage(SdrPage& rChangedPage)
+{
+ return std::make_unique<SdrUndoPageRemoveMasterPage>( rChangedPage );
+}
+
+std::unique_ptr<SdrUndoAction> SdrUndoFactory::CreateUndoPageChangeMasterPage(SdrPage& rChangedPage)
+{
+ return std::make_unique<SdrUndoPageChangeMasterPage>(rChangedPage);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdview.cxx b/svx/source/svdraw/svdview.cxx
new file mode 100644
index 000000000..d7d6d5d3a
--- /dev/null
+++ b/svx/source/svdraw/svdview.cxx
@@ -0,0 +1,1544 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/outlobj.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdmrkv.hxx>
+#include <svx/svdedxv.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdomedia.hxx>
+#include <svx/svdetc.hxx>
+
+#include <svx/sdr/table/tablecontroller.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdview.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/svddrgmt.hxx>
+#include <svx/svdotable.hxx>
+#include <tools/debug.hxx>
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrhittesthelper.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <sal/log.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/window.hxx>
+#include <comphelper/lok.hxx>
+
+
+SdrViewEvent::SdrViewEvent()
+ : mpHdl(nullptr),
+ mpObj(nullptr),
+ mpRootObj(nullptr),
+ mpPV(nullptr),
+ mpURLField(nullptr),
+ meHit(SdrHitKind::NONE),
+ meEvent(SdrEventKind::NONE),
+ mnMouseClicks(0),
+ mnMouseMode(MouseEventModifiers::NONE),
+ mnMouseCode(0),
+ mnHlplIdx(0),
+ mnGlueId(0),
+ mbMouseDown(false),
+ mbMouseUp(false),
+ mbIsAction(false),
+ mbIsTextEdit(false),
+ mbAddMark(false),
+ mbUnmark(false),
+ mbPrevNextMark(false),
+ mbMarkPrev(false)
+{
+}
+
+// helper class for all D&D overlays
+
+void SdrDropMarkerOverlay::ImplCreateOverlays(
+ const SdrView& rView,
+ const basegfx::B2DPolyPolygon& rLinePolyPolygon)
+{
+ for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
+ const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
+
+ if (xTargetOverlay.is())
+ {
+ std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
+ rLinePolyPolygon));
+
+ xTargetOverlay->add(*pNew);
+ maObjects.append(std::move(pNew));
+ }
+ }
+}
+
+SdrDropMarkerOverlay::SdrDropMarkerOverlay(const SdrView& rView, const SdrObject& rObject)
+{
+ ImplCreateOverlays(
+ rView,
+ rObject.TakeXorPoly());
+}
+
+SdrDropMarkerOverlay::SdrDropMarkerOverlay(const SdrView& rView, const tools::Rectangle& rRectangle)
+{
+ basegfx::B2DPolygon aB2DPolygon;
+
+ aB2DPolygon.append(basegfx::B2DPoint(rRectangle.Left(), rRectangle.Top()));
+ aB2DPolygon.append(basegfx::B2DPoint(rRectangle.Right(), rRectangle.Top()));
+ aB2DPolygon.append(basegfx::B2DPoint(rRectangle.Right(), rRectangle.Bottom()));
+ aB2DPolygon.append(basegfx::B2DPoint(rRectangle.Left(), rRectangle.Bottom()));
+ aB2DPolygon.setClosed(true);
+
+ ImplCreateOverlays(
+ rView,
+ basegfx::B2DPolyPolygon(aB2DPolygon));
+}
+
+SdrDropMarkerOverlay::SdrDropMarkerOverlay(const SdrView& rView, const Point& rStart, const Point& rEnd)
+{
+ basegfx::B2DPolygon aB2DPolygon;
+
+ aB2DPolygon.append(basegfx::B2DPoint(rStart.X(), rStart.Y()));
+ aB2DPolygon.append(basegfx::B2DPoint(rEnd.X(), rEnd.Y()));
+ aB2DPolygon.setClosed(true);
+
+ ImplCreateOverlays(
+ rView,
+ basegfx::B2DPolyPolygon(aB2DPolygon));
+}
+
+SdrDropMarkerOverlay::~SdrDropMarkerOverlay()
+{
+ // The OverlayObjects are cleared using the destructor of OverlayObjectList.
+ // That destructor calls clear() at the list which removes all objects from the
+ // OverlayManager and deletes them.
+}
+
+SdrView::SdrView(
+ SdrModel& rSdrModel,
+ OutputDevice* pOut)
+: SdrCreateView(rSdrModel, pOut),
+ mbNoExtendedMouseDispatcher(false),
+ mbNoExtendedKeyDispatcher(false),
+ mbMasterPagePaintCaching(false)
+{
+ maAccessibilityOptions.AddListener(this);
+ onAccessibilityOptionsChanged();
+}
+
+SdrView::~SdrView()
+{
+ maAccessibilityOptions.RemoveListener(this);
+}
+
+bool SdrView::KeyInput(const KeyEvent& rKEvt, vcl::Window* pWin)
+{
+ SetActualWin(pWin ? pWin->GetOutDev() : nullptr);
+ bool bRet = SdrCreateView::KeyInput(rKEvt,pWin);
+ if (!bRet && !IsExtendedKeyInputDispatcherEnabled()) {
+ bRet = true;
+ switch (rKEvt.GetKeyCode().GetFullFunction()) {
+ case KeyFuncType::DELETE: DeleteMarked(); break;
+ case KeyFuncType::UNDO: mpModel->Undo(); break;
+ case KeyFuncType::REDO: mpModel->Redo(); break;
+ default: {
+ switch (rKEvt.GetKeyCode().GetFullCode()) {
+ case KEY_ESCAPE: {
+ if (IsTextEdit()) SdrEndTextEdit();
+ if (IsAction()) BrkAction();
+ if (pWin!=nullptr) pWin->ReleaseMouse();
+ } break;
+ case KEY_DELETE: DeleteMarked(); break;
+ case KEY_UNDO: case KEY_BACKSPACE+KEY_MOD2: mpModel->Undo(); break;
+ case KEY_BACKSPACE+KEY_MOD2+KEY_SHIFT: mpModel->Redo(); break;
+ case KEY_REPEAT: case KEY_BACKSPACE+KEY_MOD2+KEY_MOD1: mpModel->Repeat(*this); break;
+ case KEY_MOD1+KEY_A: MarkAll(); break;
+ default: bRet=false;
+ } // switch
+ }
+ } // switch
+ if (bRet && pWin!=nullptr) {
+ pWin->SetPointer(GetPreferredPointer(
+ pWin->PixelToLogic(pWin->ScreenToOutputPixel( pWin->GetPointerPosPixel() ) ),
+ pWin->GetOutDev(),
+ rKEvt.GetKeyCode().GetModifier()));
+ }
+ }
+ return bRet;
+}
+
+bool SdrView::MouseButtonDown(const MouseEvent& rMEvt, OutputDevice* pWin)
+{
+ SetActualWin(pWin);
+ if (rMEvt.IsLeft()) maDragStat.SetMouseDown(true);
+ bool bRet = SdrCreateView::MouseButtonDown(rMEvt,pWin);
+ if (!bRet && !IsExtendedMouseEventDispatcherEnabled()) {
+ SdrViewEvent aVEvt;
+ PickAnything(rMEvt,SdrMouseEventKind::BUTTONDOWN,aVEvt);
+ bRet = DoMouseEvent(aVEvt);
+ }
+ return bRet;
+}
+
+bool SdrView::MouseButtonUp(const MouseEvent& rMEvt, OutputDevice* pWin)
+{
+ SetActualWin(pWin);
+ if (rMEvt.IsLeft()) maDragStat.SetMouseDown(false);
+ bool bAction = IsAction();
+ bool bRet = !bAction && SdrCreateView::MouseButtonUp(rMEvt,pWin);
+ if (!bRet && !IsExtendedMouseEventDispatcherEnabled()) {
+ SdrViewEvent aVEvt;
+ PickAnything(rMEvt,SdrMouseEventKind::BUTTONUP,aVEvt);
+ bRet = DoMouseEvent(aVEvt);
+ }
+ return bRet;
+}
+
+bool SdrView::MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin)
+{
+ SetActualWin(pWin);
+ maDragStat.SetMouseDown(rMEvt.IsLeft());
+ bool bRet = SdrCreateView::MouseMove(rMEvt,pWin);
+ if (!IsExtendedMouseEventDispatcherEnabled() && !IsTextEditInSelectionMode()) {
+ SdrViewEvent aVEvt;
+ PickAnything(rMEvt,SdrMouseEventKind::MOVE,aVEvt);
+ if (DoMouseEvent(aVEvt)) bRet=true;
+ }
+
+ return bRet;
+}
+
+bool SdrView::Command(const CommandEvent& rCEvt, vcl::Window* pWin)
+{
+ SetActualWin(pWin->GetOutDev());
+ bool bRet = SdrCreateView::Command(rCEvt,pWin);
+ return bRet;
+}
+
+void SdrView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
+{
+ SdrCreateView::GetAttributes(rTargetSet, bOnlyHardAttr);
+}
+
+SdrHitKind SdrView::PickAnything(const MouseEvent& rMEvt, SdrMouseEventKind nEventKind, SdrViewEvent& rVEvt) const
+{
+ rVEvt.mbMouseDown = nEventKind==SdrMouseEventKind::BUTTONDOWN;
+ rVEvt.mbMouseUp = nEventKind==SdrMouseEventKind::BUTTONUP;
+ rVEvt.mnMouseClicks = rMEvt.GetClicks();
+ rVEvt.mnMouseMode = rMEvt.GetMode();
+ rVEvt.mnMouseCode = rMEvt.GetButtons() | rMEvt.GetModifier();
+ const OutputDevice* pOut=mpActualOutDev;
+ if (pOut==nullptr)
+ {
+ pOut = GetFirstOutputDevice();
+ }
+ Point aPnt(rMEvt.GetPosPixel());
+ if (pOut!=nullptr) aPnt=pOut->PixelToLogic(aPnt);
+
+ if (mbNegativeX)
+ {
+ // Shape's x coordinates are all negated,
+ // Hence negate mouse event's x coord to match.
+ aPnt.setX(-aPnt.X());
+ }
+
+ rVEvt.maLogicPos = aPnt;
+ return PickAnything(aPnt,rVEvt);
+}
+
+// Dragging with the Mouse (Move)
+// Example when creating a rectangle: MouseDown has to happen without a ModKey,
+// else we usually force a selection (see below).
+// When pressing Shift, Ctrl and Alt at the same time while doing a MouseMove,
+// a centered, not snapped square is created.
+// The dual allocation of Ortho and Shift won't usually create a problem, as the
+// two functions are in most cases mutually exclusive. Only shearing (the kind
+// that happens when contorting, not when rotating) can use both functions at
+// the same time. To get around this, the user can use e. g. help lines.
+#define MODKEY_NoSnap bCtrl /* temporarily disable snapping */
+#define MODKEY_Ortho bShift /* ortho */
+#define MODKEY_Center bAlt /* create/resize centeredly */
+#define MODKEY_AngleSnap bShift
+#define MODKEY_CopyDrag bCtrl /* drag and copy */
+
+// click somewhere (MouseDown)
+#define MODKEY_PolyPoly bAlt /* new Poly at InsPt and at Create */
+#define MODKEY_MultiMark bShift /* MarkObj without doing UnmarkAll first */
+#define MODKEY_Unmark bAlt /* deselect with a dragged frame */
+#define MODKEY_ForceMark bCtrl /* force dragging a frame, even if there's an object at cursor position */
+#define MODKEY_DeepMark bAlt /* MarkNextObj */
+#define MODKEY_DeepBackw bShift /* MarkNextObj but backwards */
+
+SdrHitKind SdrView::PickAnything(const Point& rLogicPos, SdrViewEvent& rVEvt) const
+{
+ const OutputDevice* pOut=mpActualOutDev;
+ if (pOut==nullptr)
+ {
+ pOut = GetFirstOutputDevice();
+ }
+
+ // #i73628# Use a non-changeable copy of he logic position
+ const Point aLocalLogicPosition(rLogicPos);
+
+ bool bEditMode=IsEditMode();
+ bool bPointMode=bEditMode && HasMarkablePoints();
+ bool bGluePointMode=IsGluePointEditMode();
+ bool bInsPolyPt=bPointMode && IsInsObjPointMode() && IsInsObjPointPossible();
+ bool bInsGluePt=bGluePointMode && IsInsGluePointMode() && IsInsGluePointPossible();
+ bool bIsTextEdit=IsTextEdit();
+ bool bTextEditHit=IsTextEditHit(aLocalLogicPosition);
+ bool bTextEditSel=IsTextEditInSelectionMode();
+ bool bShift = (rVEvt.mnMouseCode & KEY_SHIFT) != 0;
+ bool bCtrl = (rVEvt.mnMouseCode & KEY_MOD1) != 0;
+ bool bAlt = (rVEvt.mnMouseCode & KEY_MOD2) != 0;
+ SdrHitKind eHit=SdrHitKind::NONE;
+ SdrHdl* pHdl=pOut!=nullptr && !bTextEditSel ? PickHandle(aLocalLogicPosition) : nullptr;
+ SdrPageView* pPV=nullptr;
+ SdrObject* pObj=nullptr;
+ SdrObject* pHitObj=nullptr;
+ bool bHitPassDirect=true;
+ sal_uInt16 nHlplIdx=0;
+ sal_uInt16 nGlueId=0;
+ if (bTextEditHit || bTextEditSel)
+ {
+ eHit=SdrHitKind::TextEdit;
+ }
+ else if (pHdl!=nullptr)
+ {
+ eHit=SdrHitKind::Handle; // handle is hit: highest priority
+ }
+ else if (bEditMode && IsHlplVisible() && IsHlplFront() && pOut!=nullptr && PickHelpLine(aLocalLogicPosition,mnHitTolLog,*pOut,nHlplIdx,pPV))
+ {
+ eHit=SdrHitKind::HelpLine; // help line in the foreground hit: can be moved now
+ }
+ else if (bGluePointMode && PickGluePoint(aLocalLogicPosition,pObj,nGlueId,pPV))
+ {
+ eHit=SdrHitKind::Gluepoint; // deselected gluepoint hit
+ }
+ else if ((pHitObj = PickObj(aLocalLogicPosition,mnHitTolLog,pPV,SdrSearchOptions::DEEP|SdrSearchOptions::MARKED,&pObj,&bHitPassDirect)))
+ {
+ eHit=SdrHitKind::MarkedObject;
+ sdr::table::SdrTableObj* pTableObj = dynamic_cast< sdr::table::SdrTableObj* >( pObj );
+ if( pTableObj )
+ {
+ sal_Int32 nX = 0, nY = 0;
+ switch( pTableObj->CheckTableHit( aLocalLogicPosition, nX, nY ) )
+ {
+ case sdr::table::TableHitKind::Cell:
+ eHit = SdrHitKind::Cell;
+ break;
+ case sdr::table::TableHitKind::CellTextArea:
+ eHit = SdrHitKind::TextEditObj;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else if ((pHitObj = PickObj(aLocalLogicPosition,mnHitTolLog,pPV,SdrSearchOptions::DEEP|SdrSearchOptions::ALSOONMASTER|SdrSearchOptions::WHOLEPAGE,&pObj,&bHitPassDirect)))
+ {
+ // MasterPages and WholePage for Macro and URL
+ eHit=SdrHitKind::UnmarkedObject;
+ sdr::table::SdrTableObj* pTableObj = dynamic_cast< sdr::table::SdrTableObj* >( pObj );
+ if( pTableObj )
+ {
+ sal_Int32 nX = 0, nY = 0;
+ switch( pTableObj->CheckTableHit( aLocalLogicPosition, nX, nY, mnHitTolLog ) )
+ {
+ case sdr::table::TableHitKind::Cell:
+ eHit = SdrHitKind::Cell;
+ break;
+ case sdr::table::TableHitKind::CellTextArea:
+ // Keep state on UnmarkedObject to allow the below
+ // 'check for URL field' to be executed, else popups
+ // for e.g. URL links when hoovering and clicking
+ // them will not work. Tried several other changes,
+ // but this one safely keeps existing behaviour as-is.
+ // Except for the LOK. LOK doesn't have hoovering popup
+ // feature.
+ eHit = comphelper::LibreOfficeKit::isActive() ? SdrHitKind::TextEditObj : SdrHitKind::UnmarkedObject;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else if (bEditMode && IsHlplVisible() && !IsHlplFront() && pOut!=nullptr && PickHelpLine(aLocalLogicPosition,mnHitTolLog,*pOut,nHlplIdx,pPV))
+ {
+ eHit=SdrHitKind::HelpLine; // help line in foreground hit: can be moved now
+ }
+ if (eHit==SdrHitKind::UnmarkedObject)
+ {
+ bool bRoot=pObj->HasMacro();
+ bool bDeep=pObj!=pHitObj && pHitObj->HasMacro();
+ bool bMid=false; // Have we hit upon a grouped group with a macro?
+ SdrObject* pMidObj=nullptr;
+ if (pObj!=pHitObj)
+ {
+ SdrObject* pObjTmp=pHitObj->getParentSdrObjectFromSdrObject();
+ if (pObjTmp==pObj) pObjTmp=nullptr;
+ while (pObjTmp!=nullptr)
+ {
+ if (pObjTmp->HasMacro())
+ {
+ bMid=true;
+ pMidObj=pObjTmp;
+ }
+ pObjTmp=pObjTmp->getParentSdrObjectFromSdrObject();
+ if (pObjTmp==pObj) pObjTmp=nullptr;
+ }
+ }
+
+ if (bDeep || bMid || bRoot)
+ {
+ SdrObjMacroHitRec aHitRec;
+ aHitRec.aPos=aLocalLogicPosition;
+ aHitRec.nTol=mnHitTolLog;
+ aHitRec.pVisiLayer=&pPV->GetVisibleLayers();
+ aHitRec.pPageView=pPV;
+ if (bDeep) bDeep=pHitObj->IsMacroHit(aHitRec);
+ if (bMid ) bMid =pMidObj->IsMacroHit(aHitRec);
+ if (bRoot) bRoot=pObj->IsMacroHit(aHitRec);
+ if (bRoot || bMid || bDeep)
+ {
+ // Priorities: 1. Root, 2. Mid, 3. Deep
+ rVEvt.mpRootObj = pObj;
+ if (!bRoot) pObj=pMidObj;
+ if (!bRoot && !bMid) pObj=pHitObj;
+ eHit=SdrHitKind::Macro;
+ }
+ }
+ }
+ // check for URL field
+ if (eHit==SdrHitKind::UnmarkedObject)
+ {
+ SdrTextObj* pTextObj=dynamic_cast<SdrTextObj*>( pHitObj );
+ if (pTextObj!=nullptr && pTextObj->HasText())
+ {
+ // use the primitive-based HitTest which is more accurate anyways. It
+ // will correctly handle rotated/mirrored/sheared/scaled text and can
+ // now return a HitContainer containing the primitive hierarchy of the
+ // primitive that triggered the hit. The first entry is that primitive,
+ // the others are the full stack of primitives leading to that one which
+ // includes grouping primitives (like TextHierarchyPrimitives we deed here)
+ // but also all decomposed ones which lead to the creation of that primitive
+ drawinglayer::primitive2d::Primitive2DContainer aHitContainer;
+ const bool bTEHit(pPV && SdrObjectPrimitiveHit(*pTextObj, aLocalLogicPosition, 0, *pPV, &pPV->GetVisibleLayers(), true, &aHitContainer));
+
+ if (bTEHit && !aHitContainer.empty())
+ {
+ // search for TextHierarchyFieldPrimitive2D which contains the needed information
+ // about a possible URLField
+ const drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D* pTextHierarchyFieldPrimitive2D = nullptr;
+
+ for (const drawinglayer::primitive2d::Primitive2DReference& xReference : aHitContainer)
+ {
+ auto pBasePrimitive = xReference.get();
+ if (pBasePrimitive && pBasePrimitive->getPrimitive2DID() == PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D)
+ {
+ pTextHierarchyFieldPrimitive2D = static_cast<const drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D*>(pBasePrimitive);
+ break;
+ }
+ }
+
+ if (nullptr != pTextHierarchyFieldPrimitive2D)
+ {
+ if (drawinglayer::primitive2d::FieldType::FIELD_TYPE_URL == pTextHierarchyFieldPrimitive2D->getType())
+ {
+ // problem with the old code is that a *pointer* to an instance of
+ // SvxURLField is set in the Event which is per se not good since that
+ // data comes from a temporary EditEngine's data and could vanish any
+ // moment. Have to replace for now with a static instance that gets
+ // filled/initialized from the original data held in the TextHierarchyField-
+ // Primitive2D (see impTextBreakupHandler::impCheckFieldPrimitive).
+ // Unfortunately things like 'TargetFrame' are still used in Calc, so this
+ // can currently not get replaced. For the future the Name/Value vector or
+ // the TextHierarchyFieldPrimitive2D itself should/will be used for handling
+ // that data
+ static SvxURLField aSvxURLField;
+
+ aSvxURLField.SetURL(pTextHierarchyFieldPrimitive2D->getValue("URL"));
+ aSvxURLField.SetRepresentation(pTextHierarchyFieldPrimitive2D->getValue("Representation"));
+ aSvxURLField.SetTargetFrame(pTextHierarchyFieldPrimitive2D->getValue("TargetFrame"));
+ const OUString aFormat(pTextHierarchyFieldPrimitive2D->getValue("SvxURLFormat"));
+
+ if (!aFormat.isEmpty())
+ {
+ aSvxURLField.SetFormat(static_cast<SvxURLFormat>(aFormat.toInt32()));
+ }
+
+ // set HitKind and pointer to local static instance in the Event
+ // to comply to old stuff
+ eHit = SdrHitKind::UrlField;
+ rVEvt.mpURLField = &aSvxURLField;
+ }
+ }
+ }
+ }
+ if (eHit==SdrHitKind::UnmarkedObject && !pHitObj->getHyperlink().isEmpty())
+ {
+ static SvxURLField aSvxURLField;
+ aSvxURLField.SetURL(pHitObj->getHyperlink());
+ rVEvt.mpURLField = &aSvxURLField;
+ eHit = SdrHitKind::UrlField;
+ }
+ }
+
+ if (bHitPassDirect &&
+ (eHit==SdrHitKind::MarkedObject || eHit==SdrHitKind::UnmarkedObject) &&
+ (IsTextTool() || (IsEditMode() && IsQuickTextEditMode())) && pHitObj->HasTextEdit())
+ {
+ // Around the TextEditArea there's a border to select without going into text edit mode.
+ tools::Rectangle aBoundRect(pHitObj->GetCurrentBoundRect());
+
+ // Force to SnapRect when Fontwork
+ if( auto pTextObj = dynamic_cast<const SdrTextObj*>(pHitObj) )
+ if( pTextObj->IsFontwork() )
+ aBoundRect = pHitObj->GetSnapRect();
+
+ sal_Int32 nTolerance(mnHitTolLog);
+ bool bBoundRectHit(false);
+
+ if(pOut)
+ {
+ nTolerance = pOut->PixelToLogic(Size(2, 0)).Width();
+ }
+
+ if( (aLocalLogicPosition.X() >= aBoundRect.Left() - nTolerance && aLocalLogicPosition.X() <= aBoundRect.Left() + nTolerance)
+ || (aLocalLogicPosition.X() >= aBoundRect.Right() - nTolerance && aLocalLogicPosition.X() <= aBoundRect.Right() + nTolerance)
+ || (aLocalLogicPosition.Y() >= aBoundRect.Top() - nTolerance && aLocalLogicPosition.Y() <= aBoundRect.Top() + nTolerance)
+ || (aLocalLogicPosition.Y() >= aBoundRect.Bottom() - nTolerance && aLocalLogicPosition.Y() <= aBoundRect.Bottom() + nTolerance))
+ {
+ bBoundRectHit = true;
+ }
+
+ if(!bBoundRectHit)
+ {
+ bool bTEHit(pPV &&
+ SdrObjectPrimitiveHit(*pHitObj, aLocalLogicPosition, 0, *pPV, &pPV->GetVisibleLayers(), true));
+
+ // TextEdit attached to an object in a locked layer
+ if (bTEHit && pPV->GetLockedLayers().IsSet(pHitObj->GetLayer()))
+ {
+ bTEHit=false;
+ }
+
+ if (bTEHit)
+ {
+ rVEvt.mpRootObj=pObj;
+ pObj=pHitObj;
+ eHit=SdrHitKind::TextEditObj;
+ }
+ }
+ }
+ if (!bHitPassDirect && eHit==SdrHitKind::UnmarkedObject) {
+ eHit=SdrHitKind::NONE;
+ pObj=nullptr;
+ pPV=nullptr;
+ }
+ bool bMouseLeft = (rVEvt.mnMouseCode & MOUSE_LEFT) != 0;
+ bool bMouseRight = (rVEvt.mnMouseCode & MOUSE_RIGHT) != 0;
+ bool bMouseDown = rVEvt.mbMouseDown;
+ bool bMouseUp = rVEvt.mbMouseUp;
+ SdrEventKind eEvent=SdrEventKind::NONE;
+ bool bIsAction=IsAction();
+
+ if (bIsAction)
+ {
+ if (bMouseDown)
+ {
+ if (bMouseRight) eEvent=SdrEventKind::BackAction;
+ }
+ else if (bMouseUp)
+ {
+ if (bMouseLeft)
+ {
+ eEvent=SdrEventKind::EndAction;
+ if (IsDragObj())
+ {
+ eEvent=SdrEventKind::EndDrag;
+ }
+ else if (IsCreateObj() || IsInsObjPoint())
+ {
+ eEvent=IsCreateObj() ? SdrEventKind::EndCreate : SdrEventKind::EndInsertObjPoint;
+ }
+ else if (IsMarking())
+ {
+ eEvent=SdrEventKind::EndMark;
+ if (!maDragStat.IsMinMoved())
+ {
+ eEvent=SdrEventKind::BrkMark;
+ rVEvt.mbAddMark = MODKEY_MultiMark;
+ }
+ }
+ }
+ }
+ else
+ {
+ eEvent=SdrEventKind::MoveAction;
+ }
+ }
+ else if (eHit==SdrHitKind::TextEdit)
+ {
+ eEvent=SdrEventKind::TextEdit;
+ }
+ else if (bMouseDown && bMouseLeft)
+ {
+ if (rVEvt.mnMouseClicks == 2 && rVEvt.mnMouseCode == MOUSE_LEFT && pObj!=nullptr && pHitObj!=nullptr && pHitObj->HasTextEdit() && eHit==SdrHitKind::MarkedObject)
+ {
+ rVEvt.mpRootObj = pObj;
+ pObj=pHitObj;
+ eEvent=SdrEventKind::BeginTextEdit;
+ }
+ else if (MODKEY_ForceMark && eHit!=SdrHitKind::UrlField)
+ {
+ eEvent=SdrEventKind::BeginMark; // AddMark,Unmark */
+ }
+ else if (eHit==SdrHitKind::HelpLine)
+ {
+ eEvent=SdrEventKind::BeginDragHelpline; // nothing, actually
+ }
+ else if (eHit==SdrHitKind::Gluepoint)
+ {
+ eEvent=SdrEventKind::MarkGluePoint; // AddMark+Drag
+ rVEvt.mbAddMark = MODKEY_MultiMark || MODKEY_DeepMark; // if not hit with Deep
+ }
+ else if (eHit==SdrHitKind::Handle)
+ {
+ eEvent=SdrEventKind::BeginDragObj; // Mark+Drag,AddMark+Drag,DeepMark+Drag,Unmark
+ bool bGlue=pHdl->GetKind()==SdrHdlKind::Glue;
+ bool bPoly=!bGlue && IsPointMarkable(*pHdl);
+ bool bMarked=bGlue || (bPoly && pHdl->IsSelected());
+ if (bGlue || bPoly)
+ {
+ eEvent=bGlue ? SdrEventKind::MarkGluePoint : SdrEventKind::MarkPoint;
+ if (MODKEY_DeepMark)
+ {
+ rVEvt.mbAddMark = true;
+ rVEvt.mbPrevNextMark = true;
+ rVEvt.mbMarkPrev = MODKEY_DeepBackw;
+ }
+ else if (MODKEY_MultiMark)
+ {
+ rVEvt.mbAddMark = true;
+ rVEvt.mbUnmark = bMarked; // Toggle
+ if (bGlue)
+ {
+ pObj=pHdl->GetObj();
+ nGlueId=static_cast<sal_uInt16>(pHdl->GetObjHdlNum());
+ }
+ }
+ else if (bMarked)
+ {
+ eEvent=SdrEventKind::BeginDragObj; // don't change MarkState, only change Drag
+ }
+ }
+ }
+ else if (bInsPolyPt && (MODKEY_PolyPoly || (!MODKEY_MultiMark && !MODKEY_DeepMark)))
+ {
+ eEvent=SdrEventKind::BeginInsertObjPoint;
+ }
+ else if (bInsGluePt && !MODKEY_MultiMark && !MODKEY_DeepMark)
+ {
+ eEvent=SdrEventKind::BeginInsertGluePoint;
+ }
+ else if (eHit==SdrHitKind::TextEditObj)
+ {
+ eEvent=SdrEventKind::BeginTextEdit; // AddMark+Drag,DeepMark+Drag,Unmark
+ if (MODKEY_MultiMark || MODKEY_DeepMark)
+ { // if not hit with Deep
+ eEvent=SdrEventKind::MarkObj;
+ }
+ }
+ else if (eHit==SdrHitKind::Macro)
+ {
+ eEvent=SdrEventKind::BeginMacroObj; // AddMark+Drag
+ if (MODKEY_MultiMark || MODKEY_DeepMark)
+ { // if not hit with Deep
+ eEvent=SdrEventKind::MarkObj;
+ }
+ }
+ else if (eHit==SdrHitKind::UrlField)
+ {
+ eEvent=SdrEventKind::ExecuteUrl; // AddMark+Drag
+ if (MODKEY_MultiMark || MODKEY_DeepMark)
+ { // if not hit with Deep
+ eEvent=SdrEventKind::MarkObj;
+ }
+ }
+ else if (eHit==SdrHitKind::MarkedObject)
+ {
+ eEvent=SdrEventKind::BeginDragObj; // DeepMark+Drag,Unmark
+
+ if (MODKEY_MultiMark || MODKEY_DeepMark)
+ { // if not hit with Deep
+ eEvent=SdrEventKind::MarkObj;
+ }
+ }
+ else if (IsCreateMode())
+ {
+ eEvent=SdrEventKind::BeginCreateObj; // nothing, actually
+ }
+ else if (eHit==SdrHitKind::UnmarkedObject)
+ {
+ eEvent=SdrEventKind::MarkObj; // AddMark+Drag
+ }
+ else
+ {
+ eEvent=SdrEventKind::BeginMark;
+ }
+
+ if (eEvent==SdrEventKind::MarkObj)
+ {
+ rVEvt.mbAddMark = MODKEY_MultiMark || MODKEY_DeepMark; // if not hit with Deep
+ rVEvt.mbPrevNextMark = MODKEY_DeepMark;
+ rVEvt.mbMarkPrev = MODKEY_DeepMark && MODKEY_DeepBackw;
+ }
+ if (eEvent==SdrEventKind::BeginMark)
+ {
+ rVEvt.mbAddMark = MODKEY_MultiMark;
+ rVEvt.mbUnmark = MODKEY_Unmark;
+ }
+ }
+ rVEvt.mbIsAction = bIsAction;
+ rVEvt.mbIsTextEdit = bIsTextEdit;
+ rVEvt.maLogicPos = aLocalLogicPosition;
+ rVEvt.mpHdl = pHdl;
+ rVEvt.mpObj = pObj;
+ if (rVEvt.mpRootObj == nullptr)
+ rVEvt.mpRootObj = pObj;
+ rVEvt.mpPV = pPV;
+ rVEvt.mnHlplIdx = nHlplIdx;
+ rVEvt.mnGlueId = nGlueId;
+ rVEvt.meHit = eHit;
+ rVEvt.meEvent = eEvent;
+#ifdef DGB_UTIL
+ if (rVEvt.mpRootObj != nullptr)
+ {
+ if (rVEvt.mpRootObj->getParentSdrObjListFromSdrObject() != rVEvt.mpPV->GetObjList())
+ {
+ OSL_FAIL("SdrView::PickAnything(): pRootObj->getParentSdrObjListFromSdrObject()!=pPV->GetObjList() !");
+ }
+ }
+#endif
+ return eHit;
+}
+
+bool SdrView::DoMouseEvent(const SdrViewEvent& rVEvt)
+{
+ bool bRet=false;
+ SdrHitKind eHit = rVEvt.meHit;
+ Point aLogicPos(rVEvt.maLogicPos);
+
+ bool bShift = (rVEvt.mnMouseCode & KEY_SHIFT) != 0;
+ bool bCtrl = (rVEvt.mnMouseCode & KEY_MOD1) != 0;
+ bool bAlt = (rVEvt.mnMouseCode & KEY_MOD2) != 0;
+ bool bMouseLeft = (rVEvt.mnMouseCode & MOUSE_LEFT) != 0;
+ bool bMouseDown = rVEvt.mbMouseDown;
+ bool bMouseUp = rVEvt.mbMouseUp;
+ if (bMouseDown) {
+ if (bMouseLeft) maDragStat.SetMouseDown(true);
+ } else if (bMouseUp) {
+ if (bMouseLeft) maDragStat.SetMouseDown(false);
+ } else { // else, MouseMove
+ maDragStat.SetMouseDown(bMouseLeft);
+ }
+
+#ifdef MODKEY_NoSnap
+ SetSnapEnabled(!MODKEY_NoSnap);
+#endif
+#ifdef MODKEY_Ortho
+ SetOrtho(MODKEY_Ortho!=IsOrthoDesired());
+#endif
+#ifdef MODKEY_AngleSnap
+ SetAngleSnapEnabled(MODKEY_AngleSnap);
+#endif
+#ifdef MODKEY_CopyDrag
+ SetDragWithCopy(MODKEY_CopyDrag);
+#endif
+#ifdef MODKEY_Center
+ SetCreate1stPointAsCenter(MODKEY_Center);
+ SetResizeAtCenter(MODKEY_Center);
+ SetCrookAtCenter(MODKEY_Center);
+#endif
+ if (bMouseLeft && bMouseDown && rVEvt.mbIsTextEdit && (eHit==SdrHitKind::UnmarkedObject || eHit==SdrHitKind::NONE)) {
+ SdrEndTextEdit(); // User has clicked beneath object, exit edit mode.
+ // pHdl is invalid, then, that shouldn't matter, though, as we expect
+ // pHdl==NULL (because of eHit).
+ }
+ switch (rVEvt.meEvent)
+ {
+ case SdrEventKind::NONE: bRet=false; break;
+ case SdrEventKind::TextEdit: bRet=false; break; // Events handled by the OutlinerView are not taken into account here.
+ case SdrEventKind::MoveAction: MovAction(aLogicPos); bRet=true; break;
+ case SdrEventKind::EndAction: EndAction(); bRet=true; break;
+ case SdrEventKind::BackAction: BckAction(); bRet=true; break;
+ case SdrEventKind::EndMark : EndAction(); bRet=true; break;
+ case SdrEventKind::BrkMark : {
+ BrkAction();
+ if (!MarkObj(aLogicPos, mnHitTolLog, rVEvt.mbAddMark))
+ {
+ // No object hit. Do the following:
+ // 1. deselect any selected gluepoints
+ // 2. deselect any selected polygon points
+ // 3. deselect any selected objects
+ if (!rVEvt.mbAddMark) UnmarkAll();
+ }
+ bRet=true;
+ } break;
+ case SdrEventKind::EndCreate: { // if necessary, MarkObj
+ SdrCreateCmd eCmd=SdrCreateCmd::NextPoint;
+ if (MODKEY_PolyPoly) eCmd=SdrCreateCmd::NextObject;
+ if (rVEvt.mnMouseClicks > 1) eCmd=SdrCreateCmd::ForceEnd;
+ if (!EndCreateObj(eCmd)) { // Don't evaluate event for Create? -> Select
+ if (eHit==SdrHitKind::UnmarkedObject || eHit==SdrHitKind::TextEdit) {
+ MarkObj(rVEvt.mpRootObj, rVEvt.mpPV);
+ if (eHit==SdrHitKind::TextEdit)
+ {
+ bool bRet2(mpActualOutDev && OUTDEV_WINDOW == mpActualOutDev->GetOutDevType() &&
+ SdrBeginTextEdit(rVEvt.mpObj, rVEvt.mpPV, mpActualOutDev->GetOwnerWindow()));
+
+ if(bRet2)
+ {
+ MouseEvent aMEvt(mpActualOutDev->LogicToPixel(aLogicPos), 1,
+ rVEvt.mnMouseMode,rVEvt.mnMouseCode,rVEvt.mnMouseCode);
+
+ OutlinerView* pOLV=GetTextEditOutlinerView();
+ if (pOLV!=nullptr) {
+ pOLV->MouseButtonDown(aMEvt); // event for the Outliner, but without double-click
+ pOLV->MouseButtonUp(aMEvt); // event for the Outliner, but without double-click
+ }
+ }
+ }
+ bRet=true; // object is selected and (if necessary) TextEdit is started
+ } else bRet=false; // canceled Create, nothing else
+ } else bRet=true; // return true for EndCreate
+ } break;
+ case SdrEventKind::EndDrag: {
+ bRet=EndDragObj(IsDragWithCopy());
+ ForceMarkedObjToAnotherPage(); // TODO: Undo+bracing missing!
+ } break;
+ case SdrEventKind::MarkObj: { // + (if applicable) BegDrag
+ if (!rVEvt.mbAddMark) UnmarkAllObj();
+ bool bUnmark = rVEvt.mbUnmark;
+ if (rVEvt.mbPrevNextMark) {
+ bRet=MarkNextObj(aLogicPos, mnHitTolLog, rVEvt.mbMarkPrev);
+ } else {
+ SortMarkedObjects();
+ const size_t nCount0=GetMarkedObjectCount();
+ bRet=MarkObj(aLogicPos, mnHitTolLog, rVEvt.mbAddMark);
+ SortMarkedObjects();
+ const size_t nCount1=GetMarkedObjectCount();
+ bUnmark=nCount1<nCount0;
+ }
+ if (!bUnmark) {
+ BegDragObj(aLogicPos,nullptr,nullptr,mnMinMovLog);
+ bRet=true;
+ }
+ } break;
+ case SdrEventKind::MarkPoint: { // + (if applicable) BegDrag
+ if (!rVEvt.mbAddMark) UnmarkAllPoints();
+ if (rVEvt.mbPrevNextMark) {
+ MarkNextPoint();
+ bRet=false;
+ } else {
+ bRet = MarkPoint(*rVEvt.mpHdl, rVEvt.mbUnmark);
+ }
+ if (!rVEvt.mbUnmark && !rVEvt.mbPrevNextMark) {
+ BegDragObj(aLogicPos, nullptr, rVEvt.mpHdl, mnMinMovLog);
+ bRet=true;
+ }
+ } break;
+ case SdrEventKind::MarkGluePoint: { // + (if applicable) BegDrag
+ if (!rVEvt.mbAddMark) UnmarkAllGluePoints();
+ if (rVEvt.mbPrevNextMark) {
+ MarkNextGluePoint();
+ bRet=false;
+ } else {
+ bRet=MarkGluePoint(rVEvt.mpObj,rVEvt.mnGlueId,rVEvt.mbUnmark);
+ }
+ if (!rVEvt.mbUnmark && !rVEvt.mbPrevNextMark) {
+ SdrHdl* pHdl = GetGluePointHdl(rVEvt.mpObj, rVEvt.mnGlueId);
+ BegDragObj(aLogicPos,nullptr,pHdl,mnMinMovLog);
+ bRet=true;
+ }
+ } break;
+ case SdrEventKind::BeginMark: bRet = BegMark(aLogicPos,rVEvt.mbAddMark,rVEvt.mbUnmark); break;
+ case SdrEventKind::BeginInsertObjPoint: bRet = BegInsObjPoint(aLogicPos, MODKEY_PolyPoly); break;
+ case SdrEventKind::EndInsertObjPoint: {
+ SdrCreateCmd eCmd=SdrCreateCmd::NextPoint;
+ if (MODKEY_PolyPoly) eCmd=SdrCreateCmd::NextObject;
+ if (rVEvt.mnMouseClicks > 1) eCmd = SdrCreateCmd::ForceEnd;
+ EndInsObjPoint(eCmd);
+ bRet=true;
+ } break;
+ case SdrEventKind::BeginInsertGluePoint: bRet=BegInsGluePoint(aLogicPos); break;
+ case SdrEventKind::BeginDragHelpline: bRet = BegDragHelpLine(rVEvt.mnHlplIdx,rVEvt.mpPV); break;
+ case SdrEventKind::BeginDragObj: bRet=BegDragObj(aLogicPos, nullptr, rVEvt.mpHdl, mnMinMovLog); break;
+ case SdrEventKind::BeginCreateObj: {
+ if (mnCurrentInvent==SdrInventor::Default && mnCurrentIdent==SdrObjKind::Caption) {
+ tools::Long nHgt=SdrEngineDefaults::GetFontHeight();
+ bRet=BegCreateCaptionObj(aLogicPos,Size(5*nHgt,2*nHgt));
+ } else bRet=BegCreateObj(aLogicPos);
+ } break;
+ case SdrEventKind::BeginMacroObj: {
+ BegMacroObj(aLogicPos, mnHitTolLog, rVEvt.mpObj, rVEvt.mpPV, mpActualOutDev->GetOwnerWindow());
+ bRet=false;
+ } break;
+ case SdrEventKind::BeginTextEdit: {
+ if (!IsObjMarked(rVEvt.mpObj)) {
+ UnmarkAllObj();
+ MarkObj(rVEvt.mpRootObj,rVEvt.mpPV);
+ }
+
+ bRet = mpActualOutDev && OUTDEV_WINDOW == mpActualOutDev->GetOutDevType()&&
+ SdrBeginTextEdit(rVEvt.mpObj, rVEvt.mpPV, mpActualOutDev->GetOwnerWindow());
+
+ if(bRet)
+ {
+ MouseEvent aMEvt(mpActualOutDev->LogicToPixel(aLogicPos),
+ 1, rVEvt.mnMouseMode, rVEvt.mnMouseCode, rVEvt.mnMouseCode);
+ OutlinerView* pOLV=GetTextEditOutlinerView();
+ if (pOLV!=nullptr) pOLV->MouseButtonDown(aMEvt); // event for the Outliner, but without double-click
+ }
+ } break;
+ default: break;
+ } // switch
+ if (bRet && mpActualOutDev && mpActualOutDev->GetOutDevType()==OUTDEV_WINDOW) {
+ vcl::Window* pWin=mpActualOutDev->GetOwnerWindow();
+ // left mouse button pressed?
+ bool bLeftDown = (rVEvt.mnMouseCode & MOUSE_LEFT) != 0 && rVEvt.mbMouseDown;
+ // left mouse button released?
+ bool bLeftUp = (rVEvt.mnMouseCode & MOUSE_LEFT) != 0 && rVEvt.mbMouseUp;
+ // left mouse button pressed or held?
+ bool bLeftDown1=(rVEvt.mnMouseCode & MOUSE_LEFT) != 0 && !rVEvt.mbMouseUp;
+ pWin->SetPointer(GetPreferredPointer(rVEvt.maLogicPos, pWin->GetOutDev(),
+ rVEvt.mnMouseCode & (KEY_SHIFT|KEY_MOD1|KEY_MOD2),bLeftDown1));
+ bool bAction=IsAction();
+ if (bLeftDown && bAction)
+ pWin->CaptureMouse();
+ else if (bLeftUp || (rVEvt.mbIsAction && !bAction))
+ pWin->ReleaseMouse();
+ }
+ return bRet;
+}
+
+PointerStyle SdrView::GetPreferredPointer(const Point& rMousePos, const OutputDevice* pOut, sal_uInt16 nModifier, bool bLeftDown) const
+{
+ // Actions
+ if (IsCreateObj())
+ {
+ return mpCurrentCreate->GetCreatePointer();
+ }
+ if (mpCurrentSdrDragMethod)
+ {
+ return mpCurrentSdrDragMethod->GetSdrDragPointer();
+ }
+ if (IsMarkObj() || IsMarkPoints() || IsMarkGluePoints() || IsSetPageOrg()) return PointerStyle::Arrow;
+ if (IsDragHelpLine()) return GetDraggedHelpLinePointer();
+ if (IsMacroObj()) {
+ SdrObjMacroHitRec aHitRec;
+ aHitRec.aPos=pOut->LogicToPixel(rMousePos);
+ aHitRec.nTol=nMacroTol;
+ aHitRec.pVisiLayer=&pMacroPV->GetVisibleLayers();
+ aHitRec.pPageView=pMacroPV;
+ return pMacroObj->GetMacroPointer(aHitRec);
+ }
+
+ // TextEdit, ObjEdit, Macro
+ if (IsTextEdit() && (IsTextEditInSelectionMode() || IsTextEditHit(rMousePos)))
+ {
+ if(!pOut || IsTextEditInSelectionMode())
+ {
+ if (mpTextEditOutliner->IsVertical())
+ return PointerStyle::TextVertical;
+ else
+ return PointerStyle::Text;
+ }
+ // Outliner should return something here...
+ Point aPos(pOut->LogicToPixel(rMousePos));
+ PointerStyle aPointer(mpTextEditOutlinerView->GetPointer(aPos));
+ if (aPointer==PointerStyle::Arrow)
+ {
+ if (mpTextEditOutliner->IsVertical())
+ aPointer = PointerStyle::TextVertical;
+ else
+ aPointer = PointerStyle::Text;
+ }
+ return aPointer;
+ }
+
+ SdrViewEvent aVEvt;
+ aVEvt.mnMouseCode = (nModifier&(KEY_SHIFT|KEY_MOD1|KEY_MOD2))|MOUSE_LEFT; // to see what would happen on MouseLeftDown
+ aVEvt.mbMouseDown = !bLeftDown; // What if ..?
+ aVEvt.mbMouseUp = bLeftDown; // What if ..?
+ if (pOut!=nullptr)
+ const_cast<SdrView*>(this)->SetActualWin(pOut);
+ SdrHitKind eHit=PickAnything(rMousePos,aVEvt);
+ SdrEventKind eEvent = aVEvt.meEvent;
+ switch (eEvent)
+ {
+ case SdrEventKind::BeginCreateObj:
+ return maCurrentCreatePointer;
+ case SdrEventKind::MarkObj:
+ return PointerStyle::Move;
+ case SdrEventKind::BeginMark:
+ return PointerStyle::Arrow;
+ case SdrEventKind::MarkPoint:
+ case SdrEventKind::MarkGluePoint:
+ return PointerStyle::MovePoint;
+ case SdrEventKind::BeginInsertObjPoint:
+ case SdrEventKind::BeginInsertGluePoint:
+ return PointerStyle::Cross;
+ case SdrEventKind::ExecuteUrl:
+ return PointerStyle::RefHand;
+ case SdrEventKind::BeginMacroObj:
+ {
+ SdrObjMacroHitRec aHitRec;
+ aHitRec.aPos = aVEvt.maLogicPos;
+ aHitRec.nTol=mnHitTolLog;
+ aHitRec.pVisiLayer = &aVEvt.mpPV->GetVisibleLayers();
+ aHitRec.pPageView = aVEvt.mpPV;
+ return aVEvt.mpObj->GetMacroPointer(aHitRec);
+ }
+ default: break;
+ } // switch
+
+ switch(eHit)
+ {
+ case SdrHitKind::Cell:
+ return PointerStyle::Arrow;
+ case SdrHitKind::HelpLine :
+ return aVEvt.mpPV->GetHelpLines()[aVEvt.mnHlplIdx].GetPointer();
+ case SdrHitKind::Gluepoint:
+ return PointerStyle::MovePoint;
+ case SdrHitKind::TextEdit :
+ case SdrHitKind::TextEditObj:
+ {
+ SdrTextObj* pText = dynamic_cast< SdrTextObj* >(aVEvt.mpObj);
+ if(pText && pText->HasText())
+ {
+ OutlinerParaObject* pParaObj = pText->GetOutlinerParaObject();
+ if(pParaObj && pParaObj->IsEffectivelyVertical())
+ return PointerStyle::TextVertical;
+ }
+ return PointerStyle::Text;
+ }
+ default: break;
+ }
+
+ bool bMarkHit=eHit==SdrHitKind::MarkedObject;
+ SdrHdl* pHdl = aVEvt.mpHdl;
+ // now check the pointers for dragging
+ if (pHdl!=nullptr || bMarkHit) {
+ SdrHdlKind eHdl= pHdl!=nullptr ? pHdl->GetKind() : SdrHdlKind::Move;
+ bool bCorner=pHdl!=nullptr && pHdl->IsCornerHdl();
+ bool bVertex=pHdl!=nullptr && pHdl->IsVertexHdl();
+ bool bMov=eHdl==SdrHdlKind::Move;
+ if (bMov && (meDragMode==SdrDragMode::Move || meDragMode==SdrDragMode::Resize || mbMarkedHitMovesAlways)) {
+ if (!IsMoveAllowed()) return PointerStyle::Arrow; // because double click or drag & drop is possible
+ return PointerStyle::Move;
+ }
+ switch (meDragMode) {
+ case SdrDragMode::Rotate: {
+ if ((bCorner || bMov) && !IsRotateAllowed(true))
+ return PointerStyle::NotAllowed;
+
+ // are 3D objects selected?
+ bool b3DObjSelected = false;
+ for (size_t a=0; !b3DObjSelected && a<GetMarkedObjectCount(); ++a) {
+ SdrObject* pObj = GetMarkedObjectByIndex(a);
+ if(dynamic_cast<const E3dObject* >(pObj) != nullptr)
+ b3DObjSelected = true;
+ }
+ // If we have a 3D object, go on despite !IsShearAllowed,
+ // because then we have a rotation instead of a shear.
+ if (bVertex && !IsShearAllowed() && !b3DObjSelected)
+ return PointerStyle::NotAllowed;
+ if (bMov)
+ return PointerStyle::Rotate;
+ } break;
+ case SdrDragMode::Shear: {
+ if (bCorner) {
+ if (!IsDistortAllowed(true) && !IsDistortAllowed()) return PointerStyle::NotAllowed;
+ else return PointerStyle::RefHand;
+ }
+ if (bVertex && !IsShearAllowed()) return PointerStyle::NotAllowed;
+ if (bMov) {
+ if (!IsMoveAllowed()) return PointerStyle::Arrow; // because double click or drag & drop is possible
+ return PointerStyle::Move;
+ }
+ } break;
+ case SdrDragMode::Mirror: {
+ if (bCorner || bVertex || bMov) {
+ SdrHdl* pH1=maHdlList.GetHdl(SdrHdlKind::Ref1);
+ SdrHdl* pH2=maHdlList.GetHdl(SdrHdlKind::Ref2);
+ bool b90=false;
+ bool b45=false;
+ if (pH1!=nullptr && pH2!=nullptr) {
+ Point aDif = pH2->GetPos()-pH1->GetPos();
+ b90=(aDif.X()==0) || aDif.Y()==0;
+ b45=b90 || (std::abs(aDif.X())==std::abs(aDif.Y()));
+ }
+ bool bNo=false;
+ if (!IsMirrorAllowed(true,true)) bNo=true; // any mirroring is forbidden
+ if (!IsMirrorAllowed() && !b45) bNo=true; // mirroring freely is forbidden
+ if (!IsMirrorAllowed(true) && !b90) bNo=true; // mirroring horizontally/vertically is allowed
+ if (bNo) return PointerStyle::NotAllowed;
+ if (b90) {
+ return PointerStyle::Mirror;
+ }
+ return PointerStyle::Mirror;
+ }
+ } break;
+
+ case SdrDragMode::Transparence:
+ {
+ if(!IsTransparenceAllowed())
+ return PointerStyle::NotAllowed;
+
+ return PointerStyle::RefHand;
+ }
+
+ case SdrDragMode::Gradient:
+ {
+ if(!IsGradientAllowed())
+ return PointerStyle::NotAllowed;
+
+ return PointerStyle::RefHand;
+ }
+
+ case SdrDragMode::Crook: {
+ if (bCorner || bVertex || bMov) {
+ if (!IsCrookAllowed(true) && !IsCrookAllowed()) return PointerStyle::NotAllowed;
+ return PointerStyle::Crook;
+ }
+ break;
+ }
+
+ case SdrDragMode::Crop:
+ {
+ return PointerStyle::Crop;
+ }
+
+ default: {
+ if ((bCorner || bVertex) && !IsResizeAllowed(true)) return PointerStyle::NotAllowed;
+ }
+ }
+ if (pHdl!=nullptr) return pHdl->GetPointer();
+ if (bMov) {
+ if (!IsMoveAllowed()) return PointerStyle::Arrow; // because double click or drag & drop is possible
+ return PointerStyle::Move;
+ }
+ }
+ if (meEditMode==SdrViewEditMode::Create) return maCurrentCreatePointer;
+ return PointerStyle::Arrow;
+}
+
+constexpr OUStringLiteral STR_NOTHING = u"nothing";
+OUString SdrView::GetStatusText()
+{
+ OUString aName;
+ OUString aStr = STR_NOTHING;
+
+ if (mpCurrentCreate!=nullptr)
+ {
+ aStr=mpCurrentCreate->getSpecialDragComment(maDragStat);
+
+ if(aStr.isEmpty())
+ {
+ aName = mpCurrentCreate->TakeObjNameSingul();
+ aStr = SvxResId(STR_ViewCreateObj);
+ }
+ }
+ else if (mpCurrentSdrDragMethod)
+ {
+ if (mbInsPolyPoint || IsInsertGluePoint())
+ {
+ aStr=maInsPointUndoStr;
+ }
+ else
+ {
+ if (maDragStat.IsMinMoved())
+ {
+ SAL_INFO(
+ "svx.svdraw",
+ "(" << this << ") " << mpCurrentSdrDragMethod.get());
+ aStr = mpCurrentSdrDragMethod->GetSdrDragComment();
+ }
+ }
+ }
+ else if(IsMarkObj())
+ {
+ if(AreObjectsMarked())
+ {
+ aStr = SvxResId(STR_ViewMarkMoreObjs);
+ }
+ else
+ {
+ aStr = SvxResId(STR_ViewMarkObjs);
+ }
+ }
+ else if(IsMarkPoints())
+ {
+ if(HasMarkedPoints())
+ {
+ aStr = SvxResId(STR_ViewMarkMorePoints);
+ }
+ else
+ {
+ aStr = SvxResId(STR_ViewMarkPoints);
+ }
+ } else if (IsMarkGluePoints())
+ {
+ if(HasMarkedGluePoints())
+ {
+ aStr = SvxResId(STR_ViewMarkMoreGluePoints);
+ }
+ else
+ {
+ aStr = SvxResId(STR_ViewMarkGluePoints);
+ }
+ }
+ else if (IsTextEdit() && mpTextEditOutlinerView != nullptr) {
+ aStr=SvxResId(STR_ViewTextEdit); // "TextEdit - Row y, Column x";
+ ESelection aSel(mpTextEditOutlinerView->GetSelection());
+ tools::Long nPar = aSel.nEndPara,nLin=0,nCol=aSel.nEndPos;
+ if (aSel.nEndPara>0) {
+ for (sal_Int32 nParaNum=0; nParaNum<aSel.nEndPara; nParaNum++) {
+ nLin += mpTextEditOutliner->GetLineCount(nParaNum);
+ }
+ }
+ // A little imperfection:
+ // At the end of a line of any multi-line paragraph, we display the
+ // position of the next line of the same paragraph, if there is one.
+ sal_uInt16 nParaLine = 0;
+ sal_uLong nParaLineCount = mpTextEditOutliner->GetLineCount(aSel.nEndPara);
+ bool bBrk = false;
+ while (!bBrk)
+ {
+ sal_uInt16 nLen = mpTextEditOutliner->GetLineLen(aSel.nEndPara, nParaLine);
+ bool bLastLine = (nParaLine == nParaLineCount - 1);
+ if (nCol>nLen || (!bLastLine && nCol == nLen))
+ {
+ nCol -= nLen;
+ nLin++;
+ nParaLine++;
+ }
+ else
+ bBrk = true;
+
+ if (nLen == 0)
+ bBrk = true; // to be sure
+ }
+
+ aStr = aStr.replaceFirst("%1", OUString::number(nPar + 1));
+ aStr = aStr.replaceFirst("%2", OUString::number(nLin + 1));
+ aStr = aStr.replaceFirst("%3", OUString::number(nCol + 1));
+
+#ifdef DBG_UTIL
+ aStr += ", Level " + OUString::number(mpTextEditOutliner->GetDepth( aSel.nEndPara ));
+#endif
+ }
+
+ if(aStr == STR_NOTHING)
+ {
+ if (AreObjectsMarked()) {
+ aStr = ImpGetDescriptionString(STR_ViewMarked);
+ if (IsGluePointEditMode()) {
+ if (HasMarkedGluePoints()) {
+ aStr = ImpGetDescriptionString(STR_ViewMarked, ImpGetDescriptionOptions::GLUEPOINTS);
+ }
+ } else {
+ if (HasMarkedPoints()) {
+ aStr = ImpGetDescriptionString(STR_ViewMarked, ImpGetDescriptionOptions::POINTS);
+ }
+ }
+ } else {
+ aStr.clear();
+ }
+ }
+ else if(!aName.isEmpty())
+ {
+ aStr = aStr.replaceFirst("%1", aName);
+ }
+
+ if(!aStr.isEmpty())
+ {
+ // capitalize first letter
+ aStr = aStr.replaceAt(0, 1, OUString(aStr[0]).toAsciiUpperCase());
+ }
+ return aStr;
+}
+
+SdrViewContext SdrView::GetContext() const
+{
+ if( IsGluePointEditMode() )
+ return SdrViewContext::GluePointEdit;
+
+ const size_t nMarkCount = GetMarkedObjectCount();
+
+ if( HasMarkablePoints() && !IsFrameHandles() )
+ {
+ bool bPath=true;
+ for( size_t nMarkNum = 0; nMarkNum < nMarkCount && bPath; ++nMarkNum )
+ if (dynamic_cast<const SdrPathObj*>(GetMarkedObjectByIndex(nMarkNum)) == nullptr)
+ bPath=false;
+
+ if( bPath )
+ return SdrViewContext::PointEdit;
+ }
+
+ if( GetMarkedObjectCount() )
+ {
+ bool bGraf = true, bMedia = true, bTable = true;
+
+ for( size_t nMarkNum = 0; nMarkNum < nMarkCount && ( bGraf || bMedia ); ++nMarkNum )
+ {
+ const SdrObject* pMarkObj = GetMarkedObjectByIndex( nMarkNum );
+ DBG_ASSERT( pMarkObj, "SdrView::GetContext(), null pointer in mark list!" );
+
+ if( !pMarkObj )
+ continue;
+
+ if( dynamic_cast<const SdrGrafObj*>( pMarkObj) == nullptr )
+ bGraf = false;
+
+ if( dynamic_cast<const SdrMediaObj*>( pMarkObj) == nullptr )
+ bMedia = false;
+
+ if( dynamic_cast<const sdr::table::SdrTableObj* >( pMarkObj ) == nullptr )
+ bTable = false;
+ }
+
+ if( bGraf )
+ return SdrViewContext::Graphic;
+ else if( bMedia )
+ return SdrViewContext::Media;
+ else if( bTable )
+ return SdrViewContext::Table;
+ }
+
+ return SdrViewContext::Standard;
+}
+
+void SdrView::MarkAll()
+{
+ if (IsTextEdit()) {
+ GetTextEditOutlinerView()->SetSelection(ESelection(0,0,EE_PARA_ALL,EE_TEXTPOS_ALL));
+ } else if (IsGluePointEditMode()) MarkAllGluePoints();
+ else if (HasMarkablePoints()) MarkAllPoints();
+ else {
+ // check for table
+ bool bMarkAll = true;
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ const SdrObject* pObj(rMarkList.GetMark(0)->GetMarkedSdrObj());
+ SdrView* pView = this;
+ if (pObj && pView && (pObj->GetObjInventor() == SdrInventor::Default)
+ && (pObj->GetObjIdentifier() == SdrObjKind::Table))
+ {
+ mxSelectionController.clear();
+ mxSelectionController = sdr::table::CreateTableController(
+ *pView, static_cast<const sdr::table::SdrTableObj&>(*pObj),
+ mxLastSelectionController);
+
+ if (mxSelectionController.is())
+ {
+ mxLastSelectionController.clear();
+ mxSelectionController->onSelectAll();
+ bMarkAll = false;
+ }
+ }
+ }
+ if ( bMarkAll )
+ MarkAllObj();
+ }
+}
+
+void SdrView::UnmarkAll()
+{
+ if (IsTextEdit()) {
+ ESelection eSel=GetTextEditOutlinerView()->GetSelection();
+ eSel.nStartPara=eSel.nEndPara;
+ eSel.nStartPos=eSel.nEndPos;
+ GetTextEditOutlinerView()->SetSelection(eSel);
+ } else if (HasMarkedGluePoints()) UnmarkAllGluePoints();
+ else if (HasMarkedPoints()) UnmarkAllPoints(); // Marked, not Markable!
+ else UnmarkAllObj();
+}
+
+const tools::Rectangle& SdrView::GetMarkedRect() const
+{
+ if (IsGluePointEditMode() && HasMarkedGluePoints()) {
+ return GetMarkedGluePointsRect();
+ }
+ if (HasMarkedPoints()) {
+ return GetMarkedPointsRect();
+ }
+ return GetMarkedObjRect();
+}
+
+void SdrView::DeleteMarked()
+{
+ if (IsTextEdit())
+ {
+ SdrObjEditView::KeyInput(KeyEvent(0, vcl::KeyCode(KeyFuncType::DELETE)), mpTextEditWin);
+ }
+ else
+ {
+ if( mxSelectionController.is() && mxSelectionController->DeleteMarked() )
+ {
+ // action already performed by current selection controller, do nothing
+ }
+ else if (IsGluePointEditMode() && HasMarkedGluePoints())
+ {
+ DeleteMarkedGluePoints();
+ }
+ else if (GetContext()==SdrViewContext::PointEdit && HasMarkedPoints())
+ {
+ DeleteMarkedPoints();
+ }
+ else
+ {
+ DeleteMarkedObj();
+ }
+ }
+}
+
+bool SdrView::BegMark(const Point& rPnt, bool bAddMark, bool bUnmark)
+{
+ if (bUnmark) bAddMark=true;
+ if (IsGluePointEditMode()) {
+ if (!bAddMark) UnmarkAllGluePoints();
+ return BegMarkGluePoints(rPnt,bUnmark);
+ } else if (HasMarkablePoints()) {
+ if (!bAddMark) UnmarkAllPoints();
+ return BegMarkPoints(rPnt,bUnmark);
+ } else {
+ if (!bAddMark) UnmarkAllObj();
+ BegMarkObj(rPnt,bUnmark);
+ return true;
+ }
+}
+
+bool SdrView::MoveShapeHandle(const sal_uInt32 handleNum, const Point& aEndPoint, const sal_Int32 aObjectOrdNum)
+{
+ if (GetHdlList().IsMoveOutside())
+ return false;
+
+ if (!GetMarkedObjectList().GetMarkCount())
+ return false;
+
+ SdrHdl * pHdl = GetHdlList().GetHdl(handleNum);
+ if (pHdl == nullptr)
+ return false;
+
+ SdrDragStat& rDragStat = const_cast<SdrDragStat&>(GetDragStat());
+ // start dragging
+ BegDragObj(pHdl->GetPos(), nullptr, pHdl, 0);
+ if (!IsDragObj())
+ return false;
+
+ bool bWasNoSnap = rDragStat.IsNoSnap();
+ bool bWasSnapEnabled = IsSnapEnabled();
+
+ // switch snapping off
+ if(!bWasNoSnap)
+ rDragStat.SetNoSnap();
+ if(bWasSnapEnabled)
+ SetSnapEnabled(false);
+
+ if (aObjectOrdNum != -1)
+ {
+ rDragStat.GetGlueOptions().objectOrdNum = aObjectOrdNum;
+ }
+ MovDragObj(aEndPoint);
+ EndDragObj();
+
+ // Clear Glue Options
+ rDragStat.GetGlueOptions().objectOrdNum = -1;
+
+ if (!bWasNoSnap)
+ rDragStat.SetNoSnap(bWasNoSnap);
+ if (bWasSnapEnabled)
+ SetSnapEnabled(bWasSnapEnabled);
+
+ return true;
+}
+
+void SdrView::ConfigurationChanged( ::utl::ConfigurationBroadcaster*p, ConfigurationHints nHint)
+{
+ onAccessibilityOptionsChanged();
+ SdrCreateView::ConfigurationChanged(p, nHint);
+}
+
+
+/** method is called whenever the global SvtAccessibilityOptions is changed */
+void SdrView::onAccessibilityOptionsChanged()
+{
+}
+
+void SdrView::SetMasterPagePaintCaching(bool bOn)
+{
+ if(mbMasterPagePaintCaching == bOn)
+ return;
+
+ mbMasterPagePaintCaching = bOn;
+
+ // reset at all SdrPageWindows
+ SdrPageView* pPageView = GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+ {
+ SdrPageWindow* pPageWindow = pPageView->GetPageWindow(b);
+ assert(pPageWindow && "SdrView::SetMasterPagePaintCaching: Corrupt SdrPageWindow list (!)");
+
+ // force deletion of ObjectContact, so at re-display all VOCs
+ // will be re-created with updated flag setting
+ pPageWindow->ResetObjectContact();
+ }
+
+ // force redraw of this view
+ pPageView->InvalidateAllWin();
+}
+
+// Default ObjectContact is ObjectContactOfPageView
+sdr::contact::ObjectContact* SdrView::createViewSpecificObjectContact(
+ SdrPageWindow& rPageWindow,
+ const char* pDebugName) const
+{
+ return new sdr::contact::ObjectContactOfPageView(rPageWindow, pDebugName);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdviter.cxx b/svx/source/svdraw/svdviter.cxx
new file mode 100644
index 000000000..ff2d6da5f
--- /dev/null
+++ b/svx/source/svdraw/svdviter.cxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdviter.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdsob.hxx>
+
+void SdrViewIter::ImpInitVars()
+{
+ mnListenerNum = 0;
+ mpCurrentView = nullptr;
+}
+
+SdrViewIter::SdrViewIter(const SdrPage* pPage)
+{
+ mpPage = pPage;
+ mpModel = pPage ? &pPage->getSdrModelFromSdrPage() : nullptr;
+ mpObject = nullptr;
+ ImpInitVars();
+}
+
+SdrViewIter::SdrViewIter(const SdrObject* pObject)
+{
+ mpObject = pObject;
+ mpModel = pObject ? &pObject->getSdrModelFromSdrObject() : nullptr;
+ mpPage = pObject ? pObject->getSdrPageFromSdrObject() : nullptr;
+
+ if (!mpModel || !mpPage)
+ {
+ mpModel = nullptr;
+ mpPage = nullptr;
+ }
+
+ ImpInitVars();
+}
+
+bool SdrViewIter::ImpCheckPageView(SdrPageView const* pPV) const
+{
+ if (!mpPage)
+ return true;
+
+ bool bMaster(mpPage->IsMasterPage());
+ SdrPage* pPg = pPV->GetPage();
+
+ if (pPg == mpPage)
+ {
+ if (mpObject)
+ {
+ // Looking for an object? First, determine if it visible in
+ // this PageView.
+ SdrLayerIDSet aObjLay;
+ mpObject->getMergedHierarchySdrLayerIDSet(aObjLay);
+ aObjLay &= pPV->GetVisibleLayers();
+ return !aObjLay.IsEmpty();
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else if (bMaster && (!mpObject || !mpObject->IsNotVisibleAsMaster()))
+ {
+ if (pPg->TRG_HasMasterPage())
+ {
+ SdrPage& rMasterPage = pPg->TRG_GetMasterPage();
+
+ if (&rMasterPage == mpPage)
+ {
+ // the page we're looking for is a master page in this PageView
+ if (mpObject)
+ {
+ // Looking for an object? First, determine if it visible in
+ // this PageView.
+ SdrLayerIDSet aObjLay;
+ mpObject->getMergedHierarchySdrLayerIDSet(aObjLay);
+ aObjLay &= pPV->GetVisibleLayers();
+ aObjLay &= pPg->TRG_GetMasterPageVisibleLayers();
+
+ if (!aObjLay.IsEmpty())
+ {
+ return true;
+ } // else, look at the next master page of this page...
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ // master page forbidden or no fitting master page found
+ return false;
+}
+
+SdrView* SdrViewIter::ImpFindView()
+{
+ if (mpModel)
+ {
+ const size_t nLsCnt(mpModel->GetSizeOfVector());
+
+ while (mnListenerNum < nLsCnt)
+ {
+ SfxListener* pLs = mpModel->GetListener(mnListenerNum);
+ mpCurrentView = dynamic_cast<SdrView*>(pLs);
+
+ if (mpCurrentView)
+ {
+ if (mpPage)
+ {
+ SdrPageView* pPV = mpCurrentView->GetSdrPageView();
+
+ if (pPV && ImpCheckPageView(pPV))
+ {
+ return mpCurrentView;
+ }
+ }
+ else
+ {
+ return mpCurrentView;
+ }
+ }
+
+ mnListenerNum++;
+ }
+ }
+
+ mpCurrentView = nullptr;
+ return mpCurrentView;
+}
+
+SdrView* SdrViewIter::FirstView()
+{
+ ImpInitVars();
+ return ImpFindView();
+}
+
+SdrView* SdrViewIter::NextView()
+{
+ mnListenerNum++;
+ return ImpFindView();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdxcgv.cxx b/svx/source/svdraw/svdxcgv.cxx
new file mode 100644
index 000000000..a9b720f30
--- /dev/null
+++ b/svx/source/svdraw/svdxcgv.cxx
@@ -0,0 +1,784 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vector>
+#include <unordered_set>
+#include <editeng/editdata.hxx>
+#include <rtl/strbuf.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/svdxcgv.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <tools/bigint.hxx>
+#include <clonelist.hxx>
+#include <vcl/virdev.hxx>
+#include <svl/style.hxx>
+#include <fmobj.hxx>
+#include <vcl/vectorgraphicdata.hxx>
+#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/converters.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/svdotable.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/lok.hxx>
+
+using namespace com::sun::star;
+
+SdrExchangeView::SdrExchangeView(
+ SdrModel& rSdrModel,
+ OutputDevice* pOut)
+: SdrObjEditView(rSdrModel, pOut)
+{
+}
+
+bool SdrExchangeView::ImpLimitToWorkArea(Point& rPt) const
+{
+ bool bRet(false);
+
+ if(!maMaxWorkArea.IsEmpty())
+ {
+ if(rPt.X()<maMaxWorkArea.Left())
+ {
+ rPt.setX( maMaxWorkArea.Left() );
+ bRet = true;
+ }
+
+ if(rPt.X()>maMaxWorkArea.Right())
+ {
+ rPt.setX( maMaxWorkArea.Right() );
+ bRet = true;
+ }
+
+ if(rPt.Y()<maMaxWorkArea.Top())
+ {
+ rPt.setY( maMaxWorkArea.Top() );
+ bRet = true;
+ }
+
+ if(rPt.Y()>maMaxWorkArea.Bottom())
+ {
+ rPt.setY( maMaxWorkArea.Bottom() );
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+void SdrExchangeView::ImpGetPasteObjList(Point& /*rPos*/, SdrObjList*& rpLst)
+{
+ if (rpLst==nullptr)
+ {
+ SdrPageView* pPV = GetSdrPageView();
+
+ if (pPV!=nullptr) {
+ rpLst=pPV->GetObjList();
+ }
+ }
+}
+
+bool SdrExchangeView::ImpGetPasteLayer(const SdrObjList* pObjList, SdrLayerID& rLayer) const
+{
+ bool bRet=false;
+ rLayer=SdrLayerID(0);
+ if (pObjList!=nullptr) {
+ const SdrPage* pPg=pObjList->getSdrPageFromSdrObjList();
+ if (pPg!=nullptr) {
+ rLayer=pPg->GetLayerAdmin().GetLayerID(maActualLayer);
+ if (rLayer==SDRLAYER_NOTFOUND) rLayer=SdrLayerID(0);
+ SdrPageView* pPV = GetSdrPageView();
+ if (pPV!=nullptr) {
+ bRet=!pPV->GetLockedLayers().IsSet(rLayer) && pPV->GetVisibleLayers().IsSet(rLayer);
+ }
+ }
+ }
+ return bRet;
+}
+
+bool SdrExchangeView::Paste(const OUString& rStr, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
+{
+ if (rStr.isEmpty())
+ return false;
+
+ Point aPos(rPos);
+ ImpGetPasteObjList(aPos,pLst);
+ ImpLimitToWorkArea( aPos );
+ if (pLst==nullptr) return false;
+ SdrLayerID nLayer;
+ if (!ImpGetPasteLayer(pLst,nLayer)) return false;
+ bool bUnmark = (nOptions & (SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit();
+ if (bUnmark) UnmarkAllObj();
+ tools::Rectangle aTextRect(0,0,500,500);
+ SdrPage* pPage=pLst->getSdrPageFromSdrObjList();
+ if (pPage!=nullptr) {
+ aTextRect.SetSize(pPage->GetSize());
+ }
+ SdrRectObj* pObj = new SdrRectObj(
+ getSdrModelFromSdrView(),
+ SdrObjKind::Text,
+ aTextRect);
+
+ pObj->SetLayer(nLayer);
+ pObj->NbcSetText(rStr); // SetText before SetAttr, else SetAttr doesn't work!
+ if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false);
+
+ pObj->SetMergedItemSet(maDefaultAttr);
+
+ SfxItemSet aTempAttr(mpModel->GetItemPool()); // no fill, no line
+ aTempAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ aTempAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
+
+ pObj->SetMergedItemSet(aTempAttr);
+
+ pObj->FitFrameToTextSize();
+ Size aSiz(pObj->GetLogicRect().GetSize());
+ MapUnit eMap=mpModel->GetScaleUnit();
+ Fraction aMap=mpModel->GetScaleFraction();
+ ImpPasteObject(pObj,*pLst,aPos,aSiz,MapMode(eMap,Point(0,0),aMap,aMap),nOptions);
+ return true;
+}
+
+bool SdrExchangeView::Paste(SvStream& rInput, EETextFormat eFormat, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
+{
+ Point aPos(rPos);
+ ImpGetPasteObjList(aPos,pLst);
+ ImpLimitToWorkArea( aPos );
+ if (pLst==nullptr) return false;
+ SdrLayerID nLayer;
+ if (!ImpGetPasteLayer(pLst,nLayer)) return false;
+ bool bUnmark=(nOptions&(SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit();
+ if (bUnmark) UnmarkAllObj();
+ tools::Rectangle aTextRect(0,0,500,500);
+ SdrPage* pPage=pLst->getSdrPageFromSdrObjList();
+ if (pPage!=nullptr) {
+ aTextRect.SetSize(pPage->GetSize());
+ }
+ SdrRectObj* pObj = new SdrRectObj(
+ getSdrModelFromSdrView(),
+ SdrObjKind::Text,
+ aTextRect);
+
+ pObj->SetLayer(nLayer);
+ if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false);
+
+ pObj->SetMergedItemSet(maDefaultAttr);
+
+ SfxItemSet aTempAttr(mpModel->GetItemPool()); // no fill, no line
+ aTempAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
+ aTempAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
+
+ pObj->SetMergedItemSet(aTempAttr);
+
+ pObj->NbcSetText(rInput,OUString(),eFormat);
+ pObj->FitFrameToTextSize();
+ Size aSiz(pObj->GetLogicRect().GetSize());
+ MapUnit eMap=mpModel->GetScaleUnit();
+ Fraction aMap=mpModel->GetScaleFraction();
+ ImpPasteObject(pObj,*pLst,aPos,aSiz,MapMode(eMap,Point(0,0),aMap,aMap),nOptions);
+
+ // b4967543
+ if(pObj->GetOutlinerParaObject())
+ {
+ SdrOutliner& rOutliner = pObj->getSdrModelFromSdrObject().GetHitTestOutliner();
+ rOutliner.SetText(*pObj->GetOutlinerParaObject());
+
+ if(1 == rOutliner.GetParagraphCount())
+ {
+ SfxStyleSheet* pCandidate = rOutliner.GetStyleSheet(0);
+
+ if(pCandidate)
+ {
+ if(pObj->getSdrModelFromSdrObject().GetStyleSheetPool() == pCandidate->GetPool())
+ {
+ pObj->NbcSetStyleSheet(pCandidate, true);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool SdrExchangeView::Paste(
+ const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
+{
+ const SdrModel* pSrcMod=&rMod;
+ if (pSrcMod==mpModel)
+ return false; // this can't work, right?
+
+ const bool bUndo = IsUndoEnabled();
+
+ if( bUndo )
+ BegUndo(SvxResId(STR_ExchangePaste));
+
+ if( mxSelectionController.is() && mxSelectionController->PasteObjModel( rMod ) )
+ {
+ if( bUndo )
+ EndUndo();
+ return true;
+ }
+
+ Point aPos(rPos);
+ ImpGetPasteObjList(aPos,pLst);
+ SdrPageView* pMarkPV=nullptr;
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(pPV && pPV->GetObjList() == pLst )
+ pMarkPV=pPV;
+
+ ImpLimitToWorkArea( aPos );
+ if (pLst==nullptr)
+ return false;
+
+ bool bUnmark=(nOptions&(SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit();
+ if (bUnmark)
+ UnmarkAllObj();
+
+ // Rescale, if the Model uses a different MapUnit.
+ // Calculate the necessary factors first.
+ MapUnit eSrcUnit=pSrcMod->GetScaleUnit();
+ MapUnit eDstUnit=mpModel->GetScaleUnit();
+ bool bResize=eSrcUnit!=eDstUnit;
+ Fraction aXResize,aYResize;
+ Point aPt0;
+ if (bResize)
+ {
+ FrPair aResize(GetMapFactor(eSrcUnit,eDstUnit));
+ aXResize=aResize.X();
+ aYResize=aResize.Y();
+ }
+ SdrObjList* pDstLst=pLst;
+ sal_uInt16 nPg,nPgCount=pSrcMod->GetPageCount();
+ for (nPg=0; nPg<nPgCount; nPg++)
+ {
+ const SdrPage* pSrcPg=pSrcMod->GetPage(nPg);
+
+ // Use SnapRect, not BoundRect here
+ tools::Rectangle aR=pSrcPg->GetAllObjSnapRect();
+
+ if (bResize)
+ ResizeRect(aR,aPt0,aXResize,aYResize);
+ Point aDist(aPos-aR.Center());
+ Size aSiz(aDist.X(),aDist.Y());
+ size_t nCloneErrCnt = 0;
+ const size_t nObjCount = pSrcPg->GetObjCount();
+ bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE;
+
+ // #i13033#
+ // New mechanism to re-create the connections of cloned connectors
+ CloneList aCloneList;
+ std::unordered_set<rtl::OUString> aNameSet;
+ for (size_t nOb=0; nOb<nObjCount; ++nOb)
+ {
+ const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
+
+ SdrObject* pNewObj(pSrcOb->CloneSdrObject(*mpModel));
+
+ if (pNewObj!=nullptr)
+ {
+ if(bResize)
+ {
+ pNewObj->getSdrModelFromSdrObject().SetPasteResize(true);
+ pNewObj->NbcResize(aPt0,aXResize,aYResize);
+ pNewObj->getSdrModelFromSdrObject().SetPasteResize(false);
+ }
+
+ // #i39861#
+ pNewObj->NbcMove(aSiz);
+
+ const SdrPage* pPg = pDstLst->getSdrPageFromSdrObjList();
+
+ if(pPg)
+ {
+ // #i72535#
+ const SdrLayerAdmin& rAd = pPg->GetLayerAdmin();
+ SdrLayerID nLayer(0);
+
+ if(dynamic_cast<const FmFormObj*>( pNewObj) != nullptr)
+ {
+ // for FormControls, force to form layer
+ nLayer = rAd.GetLayerID(rAd.GetControlLayerName());
+ }
+ else
+ {
+ nLayer = rAd.GetLayerID(maActualLayer);
+ }
+
+ if(SDRLAYER_NOTFOUND == nLayer)
+ {
+ nLayer = SdrLayerID(0);
+ }
+
+ pNewObj->SetLayer(nLayer);
+ }
+
+ pDstLst->InsertObjectThenMakeNameUnique(pNewObj, aNameSet);
+
+ if( bUndo )
+ AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pNewObj));
+
+ if (bMark) {
+ // Don't already set Markhandles!
+ // That is instead being done by ModelHasChanged in MarkView.
+ MarkObj(pNewObj,pMarkPV,false,true);
+ }
+
+ // #i13033#
+ aCloneList.AddPair(pSrcOb, pNewObj);
+ }
+ else
+ {
+ nCloneErrCnt++;
+ }
+ }
+
+ // #i13033#
+ // New mechanism to re-create the connections of cloned connectors
+ aCloneList.CopyConnections();
+
+ if(0 != nCloneErrCnt)
+ {
+#ifdef DBG_UTIL
+ OStringBuffer aStr("SdrExchangeView::Paste(): Error when cloning ");
+
+ if(nCloneErrCnt == 1)
+ {
+ aStr.append("a drawing object.");
+ }
+ else
+ {
+ aStr.append(static_cast<sal_Int32>(nCloneErrCnt));
+ aStr.append(" drawing objects.");
+ }
+
+ aStr.append(" Not copying object connectors.");
+
+ OSL_FAIL(aStr.getStr());
+#endif
+ }
+ }
+
+ if( bUndo )
+ EndUndo();
+
+ return true;
+}
+
+void SdrExchangeView::ImpPasteObject(SdrObject* pObj, SdrObjList& rLst, const Point& rCenter, const Size& rSiz, const MapMode& rMap, SdrInsertFlags nOptions)
+{
+ BigInt nSizX(rSiz.Width());
+ BigInt nSizY(rSiz.Height());
+ MapUnit eSrcMU=rMap.GetMapUnit();
+ MapUnit eDstMU=mpModel->GetScaleUnit();
+ FrPair aMapFact(GetMapFactor(eSrcMU,eDstMU));
+ Fraction aDstFr(mpModel->GetScaleFraction());
+ nSizX *= double(aMapFact.X() * rMap.GetScaleX() * aDstFr);
+ nSizX *= aDstFr.GetDenominator();
+ nSizY *= double(aMapFact.Y() * rMap.GetScaleY());
+ nSizY /= aDstFr.GetNumerator();
+ tools::Long xs=nSizX;
+ tools::Long ys=nSizY;
+ // set the pos to 0, 0 for online case
+ bool isLOK = comphelper::LibreOfficeKit::isActive();
+ Point aPos(isLOK ? 0 : rCenter.X()-xs/2, isLOK ? 0 : rCenter.Y()-ys/2);
+ tools::Rectangle aR(aPos.X(),aPos.Y(),aPos.X()+xs,aPos.Y()+ys);
+ pObj->SetLogicRect(aR);
+ rLst.InsertObject(pObj, SAL_MAX_SIZE);
+
+ if( IsUndoEnabled() )
+ AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pObj));
+
+ SdrPageView* pMarkPV=nullptr;
+ SdrPageView* pPV = GetSdrPageView();
+
+ if(pPV && pPV->GetObjList()==&rLst)
+ pMarkPV=pPV;
+
+ bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE;
+ if (bMark)
+ { // select object the first PageView we found
+ MarkObj(pObj,pMarkPV);
+ }
+}
+
+BitmapEx SdrExchangeView::GetMarkedObjBitmapEx(bool bNoVDevIfOneBmpMarked, const sal_uInt32 nMaximumQuadraticPixels, const std::optional<Size>& rTargetDPI) const
+{
+ BitmapEx aBmp;
+
+ if( AreObjectsMarked() )
+ {
+ if(1 == GetMarkedObjectCount())
+ {
+ if(bNoVDevIfOneBmpMarked)
+ {
+ SdrObject* pGrafObjTmp = GetMarkedObjectByIndex( 0 );
+ SdrGrafObj* pGrafObj = dynamic_cast<SdrGrafObj*>( pGrafObjTmp );
+
+ if( pGrafObj && ( pGrafObj->GetGraphicType() == GraphicType::Bitmap ) )
+ {
+ aBmp = pGrafObj->GetTransformedGraphic().GetBitmapEx();
+ }
+ }
+ else
+ {
+ const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(GetMarkedObjectByIndex(0));
+
+ if(pSdrGrafObj && pSdrGrafObj->isEmbeddedVectorGraphicData())
+ {
+ aBmp = pSdrGrafObj->GetGraphic().getVectorGraphicData()->getReplacement();
+ }
+ }
+ }
+
+ if( aBmp.IsEmpty() )
+ {
+ // choose conversion directly using primitives to bitmap to avoid
+ // rendering errors with tiled bitmap fills (these will be tiled in a
+ // in-between metafile, but tend to show 'gaps' since the target is *no*
+ // bitmap rendering)
+ ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
+ const sal_uInt32 nCount(aSdrObjects.size());
+
+ if(nCount)
+ {
+ // collect sub-primitives as group objects, thus no expensive append
+ // to existing sequence is needed
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitives(nCount);
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ SdrObject* pCandidate = aSdrObjects[a];
+ SdrGrafObj* pSdrGrafObj = dynamic_cast< SdrGrafObj* >(pCandidate);
+
+ if(pSdrGrafObj)
+ {
+ // #122753# To ensure existence of graphic content, force swap in
+ pSdrGrafObj->ForceSwapIn();
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ pCandidate->GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
+ xPrimitives[a] = new drawinglayer::primitive2d::GroupPrimitive2D(
+ std::move(xRetval));
+ }
+
+ // get logic range
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D));
+
+ if(!aRange.isEmpty())
+ {
+ o3tl::Length eRangeUnit = o3tl::Length::mm100;
+
+ if (GetModel()->IsWriter())
+ {
+ eRangeUnit = o3tl::Length::twip;
+ }
+
+ // if we have geometry and it has a range, convert to BitmapEx using
+ // common tooling
+ aBmp = drawinglayer::convertPrimitive2DContainerToBitmapEx(
+ std::move(xPrimitives),
+ aRange,
+ nMaximumQuadraticPixels,
+ eRangeUnit,
+ rTargetDPI);
+ }
+ }
+ }
+ }
+
+ return aBmp;
+}
+
+
+GDIMetaFile SdrExchangeView::GetMarkedObjMetaFile(bool bNoVDevIfOneMtfMarked) const
+{
+ GDIMetaFile aMtf;
+
+ if( AreObjectsMarked() )
+ {
+ tools::Rectangle aBound( GetMarkedObjBoundRect() );
+ Size aBoundSize( aBound.GetWidth(), aBound.GetHeight() );
+ MapMode aMap( mpModel->GetScaleUnit(), Point(), mpModel->GetScaleFraction(), mpModel->GetScaleFraction() );
+
+ if( bNoVDevIfOneMtfMarked )
+ {
+ SdrObject* pGrafObjTmp = GetMarkedObjectByIndex( 0 );
+ SdrGrafObj* pGrafObj = ( GetMarkedObjectCount() ==1 ) ? dynamic_cast<SdrGrafObj*>( pGrafObjTmp ) : nullptr;
+
+ if( pGrafObj )
+ {
+ Graphic aGraphic( pGrafObj->GetTransformedGraphic() );
+
+ // #119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
+ aMtf = aGraphic.GetGDIMetaFile();
+ }
+ }
+
+ if( !aMtf.GetActionSize() )
+ {
+ ScopedVclPtrInstance< VirtualDevice > pOut;
+ const Size aDummySize(2, 2);
+
+ pOut->SetOutputSizePixel(aDummySize);
+ pOut->EnableOutput(false);
+ pOut->SetMapMode(aMap);
+ aMtf.Clear();
+ aMtf.Record(pOut);
+
+ DrawMarkedObj(*pOut);
+
+ aMtf.Stop();
+ aMtf.WindStart();
+
+ // moving the result is more reliable then setting a relative MapMode at the VDev (used
+ // before), also see #i99268# in GetObjGraphic() below. Some draw actions at
+ // the OutDev are simply not handled correctly when a MapMode is set at the
+ // target device, e.g. MetaFloatTransparentAction. Even the Move for this action
+ // was missing the manipulation of the embedded Metafile
+ aMtf.Move(-aBound.Left(), -aBound.Top());
+
+ aMtf.SetPrefMapMode( aMap );
+
+ // removed PrefSize extension. It is principally wrong to set a reduced size at
+ // the created MetaFile. The mentioned errors occur at output time since the integer
+ // MapModes from VCL lead to errors. It is now corrected in the VCLRenderer for
+ // primitives (and may later be done in breaking up a MetaFile to primitives)
+ aMtf.SetPrefSize(aBoundSize);
+ }
+ }
+
+ return aMtf;
+}
+
+
+Graphic SdrExchangeView::GetAllMarkedGraphic() const
+{
+ Graphic aRet;
+
+ if( AreObjectsMarked() )
+ {
+ if( ( 1 == GetMarkedObjectCount() ) && GetSdrMarkByIndex( 0 ) )
+ aRet = SdrExchangeView::GetObjGraphic(*GetMarkedObjectByIndex(0));
+ else
+ aRet = GetMarkedObjMetaFile();
+ }
+
+ return aRet;
+}
+
+
+Graphic SdrExchangeView::GetObjGraphic(const SdrObject& rSdrObject)
+{
+ Graphic aRet;
+
+ // try to get a graphic from the object first
+ const SdrGrafObj* pSdrGrafObj(dynamic_cast< const SdrGrafObj* >(&rSdrObject));
+ const SdrOle2Obj* pSdrOle2Obj(dynamic_cast< const SdrOle2Obj* >(&rSdrObject));
+
+ if(pSdrGrafObj)
+ {
+ if(pSdrGrafObj->isEmbeddedVectorGraphicData())
+ {
+ // get Metafile for Svg content
+ aRet = pSdrGrafObj->getMetafileFromEmbeddedVectorGraphicData();
+ }
+ else
+ {
+ // Make behaviour coherent with metafile
+ // recording below (which of course also takes
+ // view-transformed objects)
+ aRet = pSdrGrafObj->GetTransformedGraphic();
+ }
+ }
+ else if(pSdrOle2Obj)
+ {
+ if(pSdrOle2Obj->GetGraphic())
+ {
+ aRet = *pSdrOle2Obj->GetGraphic();
+ }
+ }
+
+ // if graphic could not be retrieved => go the hard way and create a MetaFile
+ if((GraphicType::NONE == aRet.GetType()) || (GraphicType::Default == aRet.GetType()))
+ {
+ ScopedVclPtrInstance< VirtualDevice > pOut;
+ GDIMetaFile aMtf;
+ const tools::Rectangle aBoundRect(rSdrObject.GetCurrentBoundRect());
+ const MapMode aMap(rSdrObject.getSdrModelFromSdrObject().GetScaleUnit(),
+ Point(),
+ rSdrObject.getSdrModelFromSdrObject().GetScaleFraction(),
+ rSdrObject.getSdrModelFromSdrObject().GetScaleFraction());
+
+ pOut->EnableOutput(false);
+ pOut->SetMapMode(aMap);
+ aMtf.Record(pOut);
+ rSdrObject.SingleObjectPainter(*pOut);
+ aMtf.Stop();
+ aMtf.WindStart();
+
+ // #i99268# replace the original offset from using XOutDev's SetOffset
+ // NOT (as tried with #i92760#) with another MapMode which gets recorded
+ // by the Metafile itself (what always leads to problems), but by
+ // moving the result directly
+ aMtf.Move(-aBoundRect.Left(), -aBoundRect.Top());
+ aMtf.SetPrefMapMode(aMap);
+ aMtf.SetPrefSize(aBoundRect.GetSize());
+
+ if(aMtf.GetActionSize())
+ {
+ aRet = aMtf;
+ }
+ }
+
+ return aRet;
+}
+
+
+::std::vector< SdrObject* > SdrExchangeView::GetMarkedObjects() const
+{
+ SortMarkedObjects();
+ ::std::vector< SdrObject* > aRetval;
+
+ ::std::vector< ::std::vector< SdrMark* > > aObjVectors( 2 );
+ ::std::vector< SdrMark* >& rObjVector1 = aObjVectors[ 0 ];
+ ::std::vector< SdrMark* >& rObjVector2 = aObjVectors[ 1 ];
+ const SdrLayerAdmin& rLayerAdmin = mpModel->GetLayerAdmin();
+ const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID( rLayerAdmin.GetControlLayerName() );
+
+ for( size_t n = 0, nCount = GetMarkedObjectCount(); n < nCount; ++n )
+ {
+ SdrMark* pMark = GetSdrMarkByIndex( n );
+
+ // paint objects on control layer on top of all other objects
+ if( nControlLayerId == pMark->GetMarkedSdrObj()->GetLayer() )
+ rObjVector2.push_back( pMark );
+ else
+ rObjVector1.push_back( pMark );
+ }
+
+ for(const std::vector<SdrMark*> & rObjVector : aObjVectors)
+ {
+ for(SdrMark* pMark : rObjVector)
+ {
+ aRetval.push_back(pMark->GetMarkedSdrObj());
+ }
+ }
+
+ return aRetval;
+}
+
+
+void SdrExchangeView::DrawMarkedObj(OutputDevice& rOut) const
+{
+ ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
+
+ if(!aSdrObjects.empty())
+ {
+ sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, std::move(aSdrObjects), aSdrObjects[0]->getSdrPageFromSdrObject());
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ // do processing
+ aPainter.ProcessDisplay(aDisplayInfo);
+ }
+}
+
+std::unique_ptr<SdrModel> SdrExchangeView::CreateMarkedObjModel() const
+{
+ // Sorting the MarkList here might be problematic in the future, so
+ // use a copy.
+ SortMarkedObjects();
+ std::unique_ptr<SdrModel> pNewModel(mpModel->AllocModel());
+ rtl::Reference<SdrPage> pNewPage = pNewModel->AllocPage(false);
+ pNewModel->InsertPage(pNewPage.get());
+ ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
+
+ // #i13033#
+ // New mechanism to re-create the connections of cloned connectors
+ CloneList aCloneList;
+
+ for(SdrObject* pObj : aSdrObjects)
+ {
+ SdrObject* pNewObj(nullptr);
+
+ if(nullptr != dynamic_cast< const SdrPageObj* >(pObj))
+ {
+ // convert SdrPageObj's to a graphic representation, because
+ // virtual connection to referenced page gets lost in new model
+ pNewObj = new SdrGrafObj(
+ *pNewModel,
+ GetObjGraphic(*pObj),
+ pObj->GetLogicRect());
+ }
+ else if(nullptr != dynamic_cast< const sdr::table::SdrTableObj* >(pObj))
+ {
+ // check if we have a valid selection *different* from whole table
+ // being selected
+ if(mxSelectionController.is())
+ {
+ pNewObj = mxSelectionController->GetMarkedSdrObjClone(*pNewModel);
+ }
+ }
+
+ if(nullptr == pNewObj)
+ {
+ // not cloned yet
+ if(pObj->GetObjIdentifier() == SdrObjKind::OLE2 && nullptr == mpModel->GetPersist())
+ {
+ // tdf#125520 - former fix was wrong, the SdrModel
+ // has to have a GetPersist() already, see task.
+ // We can still warn here when this is not the case
+ SAL_WARN( "svx", "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" );
+ }
+
+ // use default way
+ pNewObj = pObj->CloneSdrObject(*pNewModel);
+ }
+
+ if(pNewObj)
+ {
+ pNewPage->InsertObject(pNewObj, SAL_MAX_SIZE);
+
+ // #i13033#
+ aCloneList.AddPair(pObj, pNewObj);
+ }
+ }
+
+ // #i13033#
+ // New mechanism to re-create the connections of cloned connectors
+ aCloneList.CopyConnections();
+
+ return pNewModel;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/textchain.cxx b/svx/source/svdraw/textchain.cxx
new file mode 100644
index 000000000..32c1f9b4e
--- /dev/null
+++ b/svx/source/svdraw/textchain.cxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <textchain.hxx>
+#include <svx/svdotext.hxx>
+
+/*
+ * Definition of Properties Interface
+*/
+
+CursorChainingEvent const & TextChain::GetCursorEvent(const SdrTextObj *pTarget)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ return pLinkProperties->aCursorEvent;
+}
+void TextChain::SetCursorEvent(const SdrTextObj *pTarget, CursorChainingEvent const & rPropParam)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ pLinkProperties->aCursorEvent = rPropParam;
+}
+
+bool TextChain::GetNilChainingEvent(const SdrTextObj *pTarget)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ return pLinkProperties->aNilChainingEvent;
+}
+void TextChain::SetNilChainingEvent(const SdrTextObj *pTarget, bool b)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ pLinkProperties->aNilChainingEvent = b;
+}
+
+ESelection const & TextChain::GetPreChainingSel(const SdrTextObj *pTarget)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ return pLinkProperties->aPreChainingSel;
+}
+void TextChain::SetPreChainingSel(const SdrTextObj *pTarget, ESelection const & rPropParam)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ pLinkProperties->aPreChainingSel = rPropParam;
+}
+
+ESelection const & TextChain::GetPostChainingSel(const SdrTextObj *pTarget)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ return pLinkProperties->aPostChainingSel;
+}
+void TextChain::SetPostChainingSel(const SdrTextObj *pTarget, ESelection const & rPropParam)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ pLinkProperties->aPostChainingSel = rPropParam;
+}
+
+bool TextChain::GetIsPartOfLastParaInNextLink(const SdrTextObj *pTarget)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ return pLinkProperties->aIsPartOfLastParaInNextLink;
+}
+void TextChain::SetIsPartOfLastParaInNextLink(const SdrTextObj *pTarget, bool b)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ pLinkProperties->aIsPartOfLastParaInNextLink = b;
+}
+
+bool TextChain::GetSwitchingToNextBox(const SdrTextObj *pTarget)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ return pLinkProperties->aSwitchingToNextBox;
+}
+void TextChain::SetSwitchingToNextBox(const SdrTextObj *pTarget, bool b)
+{
+ ImpChainLinkProperties *pLinkProperties = GetLinkProperties(pTarget);
+ pLinkProperties->aSwitchingToNextBox = b;
+}
+
+/* End Definition of Properties Interface */
+
+/* TextChain */
+
+// NOTE: All getters in the class assume that the guy is in the chain
+
+TextChain::TextChain()
+{
+}
+
+TextChain::~TextChain()
+{
+ // XXX: Should free all LinkProperties
+}
+
+namespace {
+
+ChainLinkId GetId(const SdrTextObj *pLink)
+{
+ return pLink->GetName();
+}
+
+}
+
+ImpChainLinkProperties *TextChain::GetLinkProperties(const SdrTextObj *pLink)
+{
+ // if the guy does not already have properties in the map make them
+ ChainLinkId aLinkId = GetId(pLink);
+ if (maLinkPropertiesMap.find(aLinkId) == maLinkPropertiesMap.end()) {
+ maLinkPropertiesMap[aLinkId] = new ImpChainLinkProperties;
+ }
+
+ return maLinkPropertiesMap[aLinkId];
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/textchaincursor.cxx b/svx/source/svdraw/textchaincursor.cxx
new file mode 100644
index 000000000..51c4d1d8e
--- /dev/null
+++ b/svx/source/svdraw/textchaincursor.cxx
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <textchain.hxx>
+#include <textchaincursor.hxx>
+#include <svx/svdedxv.hxx>
+#include <svx/svdoutl.hxx>
+#include <vcl/event.hxx>
+
+// XXX: Possible duplication of code in behavior with stuff in ImpEditView (or ImpEditEngine) and OutlinerView
+
+// XXX: We violate Demeter's Law several times here, I'm afraid
+
+TextChainCursorManager::TextChainCursorManager(SdrObjEditView *pEditView, const SdrTextObj *pTextObj) :
+ mpEditView(pEditView),
+ mpTextObj(pTextObj),
+ mbHandlingDel(false)
+{
+ assert(mpEditView);
+ assert(mpTextObj);
+
+}
+
+bool TextChainCursorManager::HandleKeyEvent( const KeyEvent& rKEvt )
+{
+ ESelection aNewSel;
+ CursorChainingEvent aCursorEvent;
+
+ // check what the cursor/event situation looks like
+ bool bCompletelyHandled = false;
+ impDetectEvent(rKEvt, aCursorEvent, aNewSel, bCompletelyHandled);
+
+ if (aCursorEvent == CursorChainingEvent::NULL_EVENT)
+ return false;
+ else {
+ HandleCursorEvent(aCursorEvent, aNewSel);
+ // return value depends on the situation we are in
+ return bCompletelyHandled;
+ }
+}
+
+void TextChainCursorManager::impDetectEvent(const KeyEvent& rKEvt,
+ CursorChainingEvent& rOutCursorEvt,
+ ESelection& rOutSel,
+ bool& rOutHandled)
+{
+ SdrOutliner *pOutl = mpEditView->GetTextEditOutliner();
+ OutlinerView *pOLV = mpEditView->GetTextEditOutlinerView();
+
+ SdrTextObj *pNextLink = mpTextObj->GetNextLinkInChain();
+ SdrTextObj *pPrevLink = mpTextObj->GetPrevLinkInChain();
+
+ KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
+
+ // We need to have this KeyFuncType
+ if (eFunc != KeyFuncType::DONTKNOW && eFunc != KeyFuncType::DELETE)
+ {
+ rOutCursorEvt = CursorChainingEvent::NULL_EVENT;
+ return;
+ }
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+ ESelection aCurSel = pOLV->GetSelection();
+
+ ESelection aEndSelPrevBox(100000, 100000);
+
+ sal_Int32 nLastPara = pOutl->GetParagraphCount()-1;
+ OUString aLastParaText = pOutl->GetText(pOutl->GetParagraph(nLastPara));
+ sal_Int32 nLastParaLen = aLastParaText.getLength();
+
+ ESelection aEndSel(nLastPara, nLastParaLen);
+ bool bAtEndOfTextContent = aCurSel == aEndSel;
+
+ // Possibility: Are we "pushing" at the end of the object?
+ if (nCode == KEY_RIGHT && bAtEndOfTextContent && pNextLink)
+ {
+ rOutCursorEvt = CursorChainingEvent::TO_NEXT_LINK;
+ // Selection unchanged: we are at the beginning of the box
+ rOutHandled = true; // Nothing more to do than move cursor
+ return;
+ }
+
+ // Possibility: Are we "pushing" at the end of the object?
+ if (eFunc == KeyFuncType::DELETE && bAtEndOfTextContent && pNextLink)
+ {
+ rOutCursorEvt = CursorChainingEvent::TO_NEXT_LINK;
+ // Selection unchanged: we are at the beginning of the box
+ rOutHandled = false; // We still need to delete the characters
+ mbHandlingDel = true;
+ return;
+ }
+
+ ESelection aStartSel(0, 0);
+ bool bAtStartOfTextContent = aCurSel == aStartSel;
+
+ // Possibility: Are we "pushing" at the start of the object?
+ if (nCode == KEY_LEFT && bAtStartOfTextContent && pPrevLink)
+ {
+ rOutCursorEvt = CursorChainingEvent::TO_PREV_LINK;
+ rOutSel = aEndSelPrevBox; // Set at end of selection
+ rOutHandled = true; // Nothing more to do than move cursor
+ return;
+ }
+
+ // Possibility: Are we "pushing" at the start of the object and deleting left?
+ if (nCode == KEY_BACKSPACE && bAtStartOfTextContent && pPrevLink)
+ {
+ rOutCursorEvt = CursorChainingEvent::TO_PREV_LINK;
+ rOutSel = aEndSelPrevBox; // Set at end of selection
+ rOutHandled = false; // We need to delete characters after moving cursor
+ return;
+ }
+
+ // If arrived here there is no event detected
+ rOutCursorEvt = CursorChainingEvent::NULL_EVENT;
+
+}
+
+void TextChainCursorManager::HandleCursorEventAfterChaining(
+ const CursorChainingEvent aCurEvt,
+ const ESelection& aNewSel)
+
+{
+ // Special case for DELETE handling: we need to get back at the end of the prev box
+ if (mbHandlingDel) {
+ // reset flag
+ mbHandlingDel = false;
+
+ // Move to end of prev box
+ SdrTextObj *pPrevLink = mpTextObj->GetPrevLinkInChain();
+ ESelection aEndSel(100000, 100000);
+ impChangeEditingTextObj(pPrevLink, aEndSel);
+ return;
+ }
+
+ // Standard handling
+ HandleCursorEvent(aCurEvt, aNewSel);
+}
+
+
+void TextChainCursorManager::HandleCursorEvent(
+ const CursorChainingEvent aCurEvt,
+ const ESelection& aNewSel)
+
+{
+
+ OutlinerView* pOLV = mpEditView->GetTextEditOutlinerView();
+ SdrTextObj *pNextLink = mpTextObj->GetNextLinkInChain();
+ SdrTextObj *pPrevLink = mpTextObj->GetPrevLinkInChain();
+
+
+ switch ( aCurEvt ) {
+ case CursorChainingEvent::UNCHANGED:
+ // Set same selection as before the chaining (which is saved as PostChainingSel)
+ // We need an explicit set because the Outliner is messed up
+ // after text transfer and otherwise it brings us at arbitrary positions.
+ pOLV->SetSelection(aNewSel);
+ break;
+ case CursorChainingEvent::TO_NEXT_LINK:
+ mpTextObj->GetTextChain()->SetSwitchingToNextBox(mpTextObj, true);
+ impChangeEditingTextObj(pNextLink, aNewSel);
+ break;
+ case CursorChainingEvent::TO_PREV_LINK:
+ impChangeEditingTextObj(pPrevLink, aNewSel);
+ break;
+ case CursorChainingEvent::NULL_EVENT:
+ // Do nothing here
+ break;
+ }
+
+}
+
+void TextChainCursorManager::impChangeEditingTextObj(SdrTextObj *pTargetTextObj, ESelection aNewSel)
+{
+ assert(pTargetTextObj);
+
+ mpEditView->SdrEndTextEdit();
+ mpEditView->SdrBeginTextEdit(pTargetTextObj);
+ // OutlinerView has changed, so we update the pointer
+ OutlinerView *pOLV = mpEditView->GetTextEditOutlinerView();
+ pOLV->SetSelection(aNewSel);
+
+ // Update reference text obj
+ mpTextObj = pTargetTextObj;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/textchainflow.cxx b/svx/source/svdraw/textchainflow.cxx
new file mode 100644
index 000000000..9763ea501
--- /dev/null
+++ b/svx/source/svdraw/textchainflow.cxx
@@ -0,0 +1,314 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdotext.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/overflowingtxt.hxx>
+#include <textchainflow.hxx>
+#include <sal/log.hxx>
+
+TextChainFlow::TextChainFlow(SdrTextObj *pChainTarget)
+ : mpTargetLink(pChainTarget)
+{
+ SAL_INFO("svx.chaining", "[TEXTCHAINFLOW] Creating a new TextChainFlow");
+
+ mpTextChain = mpTargetLink->GetTextChain();
+ mpNextLink = mpTargetLink->GetNextLinkInChain();
+
+ bUnderflow = bOverflow = false;
+
+ mbOFisUFinduced = false;
+
+ mpOverflChText = nullptr;
+ mpUnderflChText = nullptr;
+
+ mbPossiblyCursorOut = false;
+}
+
+
+TextChainFlow::~TextChainFlow()
+{
+ mpOverflChText.reset();
+ mpUnderflChText.reset();
+}
+
+void TextChainFlow::impSetFlowOutlinerParams(SdrOutliner *, SdrOutliner *)
+{
+ // Nothing to do if not in editing mode
+}
+
+/*
+ * Check for overflow in the state of pFlowOutl.
+ * If pParamOutl is not NULL sets some parameters from there.
+ * This is useful in case the outliner is not set for overflow
+ * (e.g. in editing mode we check for overflow in drawing outl but
+ * parameters come from editing outliner)
+*/
+void TextChainFlow::impCheckForFlowEvents(SdrOutliner *pFlowOutl, SdrOutliner *pParamOutl)
+{
+ bool bOldUpdateMode = pFlowOutl->IsUpdateLayout();
+
+ // XXX: This could be reorganized moving most of this stuff inside EditingTextChainFlow
+ if (pParamOutl != nullptr)
+ {
+ // We need this since it's required to check overflow
+ pFlowOutl->SetUpdateLayout(true);
+
+ // XXX: does this work if you do it before setting the text? Seems so.
+ impSetFlowOutlinerParams(pFlowOutl, pParamOutl);
+ }
+
+ bool bIsPageOverflow = pFlowOutl->IsPageOverflow();
+
+ // NOTE: overflow and underflow cannot be both true
+ bOverflow = bIsPageOverflow && mpNextLink;
+ bUnderflow = !bIsPageOverflow && mpNextLink && mpNextLink->HasText();
+
+ // Get old state on whether to merge para-s or not
+ // NOTE: We handle UF/OF using the _old_ state. The new one is simply saved
+ bool bMustMergeParaAmongLinks = GetTextChain()->GetIsPartOfLastParaInNextLink(mpTargetLink);
+
+ // Set (Non)OverflowingTxt here (if any)
+
+ // If we had an underflow before we have to deep merge paras anyway
+ bool bMustMergeParaOF = bMustMergeParaAmongLinks || mbOFisUFinduced;
+
+ mpOverflChText.reset( bOverflow ?
+ new OFlowChainedText(pFlowOutl, bMustMergeParaOF) :
+ nullptr );
+
+ // Set current underflowing text (if any)
+ mpUnderflChText.reset( bUnderflow ?
+ new UFlowChainedText(pFlowOutl, bMustMergeParaAmongLinks) :
+ nullptr );
+
+ // Reset update mode // Reset it here because we use WriteRTF (needing updatemode = true) in the two constructors above
+ if (!bOldUpdateMode) // Reset only if the old value was false
+ pFlowOutl->SetUpdateLayout(bOldUpdateMode);
+
+ // NOTE: Must be called after mp*ChText abd b*flow have been set but before mbOFisUFinduced is reset
+ impUpdateCursorInfo();
+
+ // To check whether an overflow is underflow induced or not (useful in cursor checking)
+ mbOFisUFinduced = bUnderflow;
+}
+
+void TextChainFlow::impUpdateCursorInfo()
+{
+ // XXX: Maybe we can get rid of mbOFisUFinduced by not allowing handling of more than one event by the same TextChainFlow
+ // if this is not an OF triggered during an UF
+
+ mbPossiblyCursorOut = bOverflow;
+
+ if(mbPossiblyCursorOut ) {
+ maOverflowPosSel = mpOverflChText->GetOverflowPointSel();
+ ESelection aSelAtUFTime = GetTextChain()->GetPreChainingSel(GetLinkTarget());
+ // Might be an invalid selection if the cursor at UF time was before
+ // the (possibly UF-induced) Overflowing point but we don't use it in that case
+ maPostChainingSel = ESelection(aSelAtUFTime.nStartPara-maOverflowPosSel.nStartPara,
+ aSelAtUFTime.nStartPos-maOverflowPosSel.nStartPos );
+ }
+
+ // XXX: It may not be necessary anymore to keep this method separated from EditingTextChainFlow::impBroadcastCursorInfo
+}
+
+void TextChainFlow::CheckForFlowEvents(SdrOutliner *pFlowOutl)
+{
+ impCheckForFlowEvents(pFlowOutl, nullptr);
+}
+
+
+bool TextChainFlow::IsOverflow() const
+{
+ return bOverflow;
+}
+
+bool TextChainFlow::IsUnderflow() const
+{
+ return bUnderflow;
+}
+
+
+// XXX: In editing mode you need to get "underflowing" text from editing outliner, so it's kinda separate from the drawing one!
+
+// XXX:Would it be possible to unify underflow and its possibly following overflow?
+void TextChainFlow::ExecuteUnderflow(SdrOutliner *pOutl)
+{
+ //GetTextChain()->SetNilChainingEvent(mpTargetLink, true);
+ // making whole text
+ // merges underflowing text with the one in the next box
+ std::optional<OutlinerParaObject> pNewText = mpUnderflChText->CreateMergedUnderflowParaObject(pOutl, mpNextLink->GetOutlinerParaObject());
+
+ // Set the other box empty; it will be replaced by the rest of the text if overflow occurs
+ if (!mpTargetLink->GetPreventChainable())
+ mpNextLink->NbcSetOutlinerParaObject(pOutl->GetEmptyParaObject());
+
+ // We store the size since NbcSetOutlinerParaObject can change it
+ //Size aOldSize = pOutl->GetMaxAutoPaperSize();
+
+ // This should not be done in editing mode!! //XXX
+ if (!mpTargetLink->IsInEditMode())
+ {
+ mpTargetLink->NbcSetOutlinerParaObject(pNewText);
+ }
+
+ // Restore size and set new text
+ //pOutl->SetMaxAutoPaperSize(aOldSize); // XXX (it seems to be working anyway without this)
+ pOutl->SetText(*pNewText);
+
+ //GetTextChain()->SetNilChainingEvent(mpTargetLink, false);
+
+ // Check for new overflow
+ CheckForFlowEvents(pOutl);
+}
+
+void TextChainFlow::ExecuteOverflow(SdrOutliner *pNonOverflOutl, SdrOutliner *pOverflOutl)
+{
+ //GetTextChain()->SetNilChainingEvent(mpTargetLink, true);
+ // Leave only non overflowing text
+ impLeaveOnlyNonOverflowingText(pNonOverflOutl);
+
+ // Transfer of text to next link
+ if (!mpTargetLink->GetPreventChainable() ) // we don't transfer text while dragging because of resizing
+ {
+ impMoveChainedTextToNextLink(pOverflOutl);
+ }
+
+ //GetTextChain()->SetNilChainingEvent(mpTargetLink, false);
+}
+
+void TextChainFlow::impLeaveOnlyNonOverflowingText(SdrOutliner *pNonOverflOutl)
+{
+ std::optional<OutlinerParaObject> pNewText = mpOverflChText->RemoveOverflowingText(pNonOverflOutl);
+
+ SAL_INFO("svx.chaining", "[TEXTCHAINFLOW - OF] SOURCE box set to "
+ << pNewText->GetTextObject().GetParagraphCount() << " paras");
+
+ // adds it to current outliner anyway (useful in static decomposition)
+ pNonOverflOutl->SetText(*pNewText);
+
+ mpTargetLink->NbcSetOutlinerParaObject(std::move(pNewText));
+ // For some reason the paper size is lost after last instruction, so we set it.
+ pNonOverflOutl->SetPaperSize(Size(pNonOverflOutl->GetPaperSize().Width(),
+ pNonOverflOutl->GetTextHeight()));
+
+}
+
+void TextChainFlow::impMoveChainedTextToNextLink(SdrOutliner *pOverflOutl)
+{
+ // prevent copying text in same box
+ if ( mpNextLink == mpTargetLink ) {
+ SAL_INFO("svx.chaining", "[CHAINING] Trying to copy text for next link in same object");
+ return;
+ }
+
+ std::optional<OutlinerParaObject> pNewText =
+ mpOverflChText->InsertOverflowingText(pOverflOutl,
+ mpNextLink->GetOutlinerParaObject());
+ SAL_INFO("svx.chaining", "[TEXTCHAINFLOW - OF] DEST box set to "
+ << pNewText->GetTextObject().GetParagraphCount() << " paras");
+
+ if (pNewText)
+ mpNextLink->NbcSetOutlinerParaObject(std::move(pNewText));
+
+ // Set Deep Merge status
+ SAL_INFO("svx.chaining", "[DEEPMERGE] Setting deepMerge to "
+ << mpOverflChText->IsLastParaInterrupted());
+ GetTextChain()->SetIsPartOfLastParaInNextLink(
+ mpTargetLink,
+ mpOverflChText->IsLastParaInterrupted());
+}
+
+SdrTextObj *TextChainFlow::GetLinkTarget() const
+{
+ return mpTargetLink;
+}
+
+TextChain *TextChainFlow::GetTextChain() const
+{
+ return mpTextChain;
+}
+
+// EditingTextChainFlow
+
+EditingTextChainFlow::EditingTextChainFlow(SdrTextObj *pLinkTarget) :
+ TextChainFlow(pLinkTarget)
+{
+ SAL_INFO("svx.chaining", "[TEXTCHAINFLOW] Creating a new EditingTextChainFlow");
+}
+
+void EditingTextChainFlow::CheckForFlowEvents(SdrOutliner *pFlowOutl)
+{
+ // if this is editing outliner no need to set parameters
+ if (pFlowOutl == GetLinkTarget()->mpEditingOutliner)
+ impCheckForFlowEvents(pFlowOutl, nullptr);
+ else
+ impCheckForFlowEvents(pFlowOutl, GetLinkTarget()->mpEditingOutliner);
+
+ // Broadcast events for cursor handling
+ impBroadcastCursorInfo();
+}
+
+void EditingTextChainFlow::impLeaveOnlyNonOverflowingText(SdrOutliner *pNonOverflOutl)
+{
+ mpOverflChText->RemoveOverflowingText(pNonOverflOutl);
+ //impSetTextForEditingOutliner(pNewText); //XXX: Don't call it since we do everything with NonOverflowingText::ToParaObject // XXX: You may need this for Underflow
+
+ // XXX: I'm not sure whether we need this (after all operations such as Paste don't change this - as far as I understand)
+ //GetLinkTarget()->NbcSetOutlinerParaObject(pNewText);
+}
+
+void EditingTextChainFlow::impSetFlowOutlinerParams(SdrOutliner *pFlowOutl, SdrOutliner *pParamOutl)
+{
+ // Set right size for overflow
+ pFlowOutl->SetMaxAutoPaperSize(pParamOutl->GetMaxAutoPaperSize());
+ pFlowOutl->SetMinAutoPaperSize(pParamOutl->GetMinAutoPaperSize());
+ pFlowOutl->SetPaperSize(pParamOutl->GetPaperSize());
+}
+
+void EditingTextChainFlow::impBroadcastCursorInfo() const
+{
+ ESelection aPreChainingSel = GetTextChain()->GetPreChainingSel(GetLinkTarget()) ;
+
+ // Test whether the cursor is out of the box.
+ bool bCursorOut = mbPossiblyCursorOut && maOverflowPosSel < aPreChainingSel;
+
+ // NOTE: I handled already the stuff for the comments below. They will be kept temporarily till stuff settles down.
+ // Possibility: 1) why don't we stop passing the actual event to the TextChain and instead we pass
+ // the overflow pos and mbPossiblyCursorOut
+ // 2) We pass the current selection before anything happens and we make impBroadcastCursorInfo compute it.
+
+
+ if (bCursorOut) {
+ //maCursorEvent = CursorChainingEvent::TO_NEXT_LINK;
+ GetTextChain()->SetPostChainingSel(GetLinkTarget(), maPostChainingSel);
+ GetTextChain()->SetCursorEvent(GetLinkTarget(), CursorChainingEvent::TO_NEXT_LINK);
+ } else {
+ //maCursorEvent = CursorChainingEvent::UNCHANGED;
+ GetTextChain()->SetPostChainingSel(GetLinkTarget(), aPreChainingSel);
+ GetTextChain()->SetCursorEvent(GetLinkTarget(), CursorChainingEvent::UNCHANGED);
+ }
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/accessiblecell.cxx b/svx/source/table/accessiblecell.cxx
new file mode 100644
index 000000000..1052ab5eb
--- /dev/null
+++ b/svx/source/table/accessiblecell.cxx
@@ -0,0 +1,600 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <memory>
+
+#include "accessiblecell.hxx"
+#include <cell.hxx>
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+
+#include <editeng/unoedsrc.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+
+#include <unotools/accessiblestatesethelper.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/sequence.hxx>
+#include <svx/IAccessibleViewForwarder.hxx>
+#include <svx/unoshtxt.hxx>
+#include <svx/svdotext.hxx>
+#include <tools/debug.hxx>
+
+using namespace sdr::table;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+
+namespace accessibility {
+
+AccessibleCell::AccessibleCell( const css::uno::Reference< css::accessibility::XAccessible>& rxParent, const sdr::table::CellRef& rCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo& rShapeTreeInfo )
+: AccessibleCellBase( rxParent, AccessibleRole::TABLE_CELL )
+, maShapeTreeInfo( rShapeTreeInfo )
+, mnIndexInParent( nIndex )
+, mxCell( rCell )
+{
+ //Init the pAccTable var
+ pAccTable = dynamic_cast <AccessibleTableShape *> (rxParent.get());
+}
+
+
+AccessibleCell::~AccessibleCell()
+{
+ DBG_ASSERT( mpText == nullptr, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" );
+}
+
+
+void AccessibleCell::Init()
+{
+ SdrView* pView = maShapeTreeInfo.GetSdrView();
+ const vcl::Window* pWindow = maShapeTreeInfo.GetWindow ();
+ if( !((pView != nullptr) && (pWindow != nullptr) && mxCell.is()))
+ return;
+
+ // create AccessibleTextHelper to handle this shape's text
+ if( mxCell->CanCreateEditOutlinerParaObject() || mxCell->GetOutlinerParaObject() != nullptr )
+ {
+ // non-empty text -> use full-fledged edit source right away
+
+ mpText.reset( new AccessibleTextHelper( std::make_unique<SvxTextEditSource>(mxCell->GetObject(), mxCell.get(), *pView, *pWindow->GetOutDev()) ) );
+ if( mxCell.is() && mxCell->IsActiveCell() )
+ mpText->SetFocus();
+ mpText->SetEventSource(this);
+ }
+}
+
+
+bool AccessibleCell::SetState (sal_Int16 aState)
+{
+ bool bStateHasChanged = false;
+
+ if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
+ {
+ // Offer FOCUSED state to edit engine and detect whether the state
+ // changes.
+ bool bIsFocused = mpText->HaveFocus ();
+ mpText->SetFocus();
+ bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
+ }
+ else
+ bStateHasChanged = AccessibleContextBase::SetState (aState);
+
+ return bStateHasChanged;
+}
+
+
+bool AccessibleCell::ResetState (sal_Int16 aState)
+{
+ bool bStateHasChanged = false;
+
+ if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
+ {
+ // Try to remove FOCUSED state from the edit engine and detect
+ // whether the state changes.
+ bool bIsFocused = mpText->HaveFocus ();
+ mpText->SetFocus (false);
+ bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
+ }
+ else
+ bStateHasChanged = AccessibleContextBase::ResetState (aState);
+
+ return bStateHasChanged;
+}
+
+
+// XInterface
+
+
+Any SAL_CALL AccessibleCell::queryInterface( const Type& aType )
+{
+ return AccessibleCellBase::queryInterface( aType );
+}
+
+
+void SAL_CALL AccessibleCell::acquire( ) noexcept
+{
+ AccessibleCellBase::acquire();
+}
+
+
+void SAL_CALL AccessibleCell::release( ) noexcept
+{
+ AccessibleCellBase::release();
+}
+
+
+// XAccessibleContext
+
+
+/** The children of this cell come from the paragraphs of text.
+*/
+sal_Int32 SAL_CALL AccessibleCell::getAccessibleChildCount()
+{
+ SolarMutexGuard aSolarGuard;
+ ThrowIfDisposed ();
+ return mpText != nullptr ? mpText->GetChildCount () : 0;
+}
+
+
+/** Forward the request to the shape. Return the requested shape or throw
+ an exception for a wrong index.
+*/
+Reference<XAccessible> SAL_CALL AccessibleCell::getAccessibleChild (sal_Int32 nIndex)
+{
+ SolarMutexGuard aSolarGuard;
+ ThrowIfDisposed ();
+
+ // todo: does GetChild throw IndexOutOfBoundsException?
+ return mpText->GetChild (nIndex);
+}
+
+
+/** Return a copy of the state set.
+ Possible states are:
+ ENABLED
+ SHOWING
+ VISIBLE
+*/
+Reference<XAccessibleStateSet> SAL_CALL AccessibleCell::getAccessibleStateSet()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard (m_aMutex);
+ Reference<XAccessibleStateSet> xStateSet;
+
+ if (rBHelper.bDisposed || mpText == nullptr)
+ {
+ // Return a minimal state set that only contains the DEFUNC state.
+ xStateSet = AccessibleContextBase::getAccessibleStateSet ();
+ }
+ else
+ {
+ if(mxStateSet)
+ {
+ // Merge current FOCUSED state from edit engine.
+ if (mpText != nullptr)
+ {
+ if (mpText->HaveFocus())
+ mxStateSet->AddState (AccessibleStateType::FOCUSED);
+ else
+ mxStateSet->RemoveState (AccessibleStateType::FOCUSED);
+ }
+ // Set the invisible state for merged cell
+ if (mxCell.is() && mxCell->isMerged())
+ mxStateSet->RemoveState(AccessibleStateType::VISIBLE);
+ else
+ mxStateSet->AddState(AccessibleStateType::VISIBLE);
+
+
+ //Just when the parent table is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
+ css::uno::Reference<XAccessible> xTempAcc = getAccessibleParent();
+ if( xTempAcc.is() )
+ {
+ css::uno::Reference<XAccessibleContext>
+ xTempAccContext = xTempAcc->getAccessibleContext();
+ if( xTempAccContext.is() )
+ {
+ css::uno::Reference<XAccessibleStateSet> rState =
+ xTempAccContext->getAccessibleStateSet();
+ if( rState.is() )
+ {
+ const css::uno::Sequence<short> aStates = rState->getStates();
+ if (std::find(aStates.begin(), aStates.end(), AccessibleStateType::EDITABLE) != aStates.end())
+ {
+ mxStateSet->AddState (AccessibleStateType::EDITABLE);
+ mxStateSet->AddState (AccessibleStateType::RESIZABLE);
+ mxStateSet->AddState (AccessibleStateType::MOVEABLE);
+ }
+ }
+ }
+ }
+ // Create a copy of the state set that may be modified by the
+ // caller without affecting the current state set.
+ xStateSet.set(new ::utl::AccessibleStateSetHelper (*mxStateSet));
+ }
+ }
+
+ return xStateSet;
+}
+
+
+// XAccessibleComponent
+
+
+sal_Bool SAL_CALL AccessibleCell::containsPoint( const css::awt::Point& aPoint)
+{
+ return AccessibleComponentBase::containsPoint( aPoint );
+}
+
+/** The implementation below is at the moment straightforward. It iterates
+ over all children (and thereby instances all children which have not
+ been already instantiated) until a child covering the specified point is
+ found.
+ This leaves room for improvement. For instance, first iterate only over
+ the already instantiated children and only if no match is found
+ instantiate the remaining ones.
+*/
+Reference<XAccessible > SAL_CALL AccessibleCell::getAccessibleAtPoint ( const css::awt::Point& aPoint)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ sal_Int32 nChildCount = getAccessibleChildCount ();
+ for (sal_Int32 i=0; i<nChildCount; ++i)
+ {
+ Reference<XAccessible> xChild (getAccessibleChild (i));
+ if (xChild.is())
+ {
+ Reference<XAccessibleComponent> xChildComponent (xChild->getAccessibleContext(), uno::UNO_QUERY);
+ if (xChildComponent.is())
+ {
+ awt::Rectangle aBBox (xChildComponent->getBounds());
+ if ( (aPoint.X >= aBBox.X)
+ && (aPoint.Y >= aBBox.Y)
+ && (aPoint.X < aBBox.X+aBBox.Width)
+ && (aPoint.Y < aBBox.Y+aBBox.Height) )
+ return xChild;
+ }
+ }
+ }
+
+ // Have not found a child under the given point. Returning empty
+ // reference to indicate this.
+ return uno::Reference<XAccessible>();
+}
+
+
+css::awt::Rectangle SAL_CALL AccessibleCell::getBounds()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ ThrowIfDisposed ();
+ css::awt::Rectangle aBoundingBox;
+ if( mxCell.is() )
+ {
+ // Get the cell's bounding box in internal coordinates (in 100th of mm)
+ const ::tools::Rectangle aCellRect( mxCell->getCellRect() );
+
+ // Transform coordinates from internal to pixel.
+ if (maShapeTreeInfo.GetViewForwarder() == nullptr)
+ throw uno::RuntimeException ("AccessibleCell has no valid view forwarder",static_cast<uno::XWeak*>(this));
+
+ ::Size aPixelSize( maShapeTreeInfo.GetViewForwarder()->LogicToPixel(::Size(aCellRect.GetWidth(), aCellRect.GetHeight())) );
+ ::Point aPixelPosition( maShapeTreeInfo.GetViewForwarder()->LogicToPixel( aCellRect.TopLeft() ));
+
+ // Clip the shape's bounding box with the bounding box of its parent.
+ Reference<XAccessibleComponent> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY);
+ if (xParentComponent.is())
+ {
+ // Make the coordinates relative to the parent.
+ awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
+ int x = aPixelPosition.getX() - aParentLocation.X;
+ int y = aPixelPosition.getY() - aParentLocation.Y;
+
+ // Clip with parent (with coordinates relative to itself).
+ ::tools::Rectangle aBBox ( x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
+ awt::Size aParentSize (xParentComponent->getSize());
+ ::tools::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
+ aBBox = aBBox.GetIntersection (aParentBBox);
+ aBoundingBox = awt::Rectangle ( aBBox.Left(), aBBox.Top(), aBBox.getWidth(), aBBox.getHeight());
+ }
+ else
+ {
+ SAL_INFO("svx", "parent does not support component");
+ aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight());
+ }
+ }
+
+ return aBoundingBox;
+}
+
+
+css::awt::Point SAL_CALL AccessibleCell::getLocation()
+{
+ ThrowIfDisposed ();
+ css::awt::Rectangle aBoundingBox(getBounds());
+ return css::awt::Point(aBoundingBox.X, aBoundingBox.Y);
+}
+
+
+css::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen()
+{
+ ThrowIfDisposed ();
+
+ // Get relative position...
+ css::awt::Point aLocation(getLocation ());
+
+ // ... and add absolute position of the parent.
+ Reference<XAccessibleComponent> xParentComponent( getAccessibleParent(), uno::UNO_QUERY);
+ if(xParentComponent.is())
+ {
+ css::awt::Point aParentLocation(xParentComponent->getLocationOnScreen());
+ aLocation.X += aParentLocation.X;
+ aLocation.Y += aParentLocation.Y;
+ }
+ else
+ {
+ SAL_WARN("svx", "parent does not support XAccessibleComponent");
+ }
+
+ return aLocation;
+}
+
+
+awt::Size SAL_CALL AccessibleCell::getSize()
+{
+ ThrowIfDisposed ();
+ awt::Rectangle aBoundingBox (getBounds());
+ return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
+}
+
+
+void SAL_CALL AccessibleCell::grabFocus()
+{
+ AccessibleComponentBase::grabFocus();
+}
+
+
+sal_Int32 SAL_CALL AccessibleCell::getForeground()
+{
+ ThrowIfDisposed ();
+
+ // todo
+ return sal_Int32(0x0ffffffL);
+}
+
+
+sal_Int32 SAL_CALL AccessibleCell::getBackground()
+{
+ ThrowIfDisposed ();
+
+ // todo
+ return 0;
+}
+
+
+// XAccessibleExtendedComponent
+
+
+css::uno::Reference< css::awt::XFont > SAL_CALL AccessibleCell::getFont()
+{
+//todo
+ return AccessibleComponentBase::getFont();
+}
+
+
+OUString SAL_CALL AccessibleCell::getTitledBorderText()
+{
+ return AccessibleComponentBase::getTitledBorderText();
+}
+
+
+OUString SAL_CALL AccessibleCell::getToolTipText()
+{
+ return AccessibleComponentBase::getToolTipText();
+}
+
+
+// XAccessibleEventBroadcaster
+
+
+void SAL_CALL AccessibleCell::addAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard (m_aMutex);
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ {
+ Reference<XInterface> xSource( static_cast<XComponent *>(this) );
+ lang::EventObject aEventObj(xSource);
+ rxListener->disposing(aEventObj);
+ }
+ else
+ {
+ AccessibleContextBase::addAccessibleEventListener (rxListener);
+ if (mpText != nullptr)
+ mpText->AddEventListener (rxListener);
+ }
+}
+
+
+void SAL_CALL AccessibleCell::removeAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
+{
+ SolarMutexGuard aSolarGuard;
+ AccessibleContextBase::removeAccessibleEventListener(rxListener);
+ if (mpText != nullptr)
+ mpText->RemoveEventListener (rxListener);
+}
+
+
+// XServiceInfo
+
+
+OUString SAL_CALL AccessibleCell::getImplementationName()
+{
+ return "AccessibleCell";
+}
+
+
+Sequence<OUString> SAL_CALL AccessibleCell::getSupportedServiceNames()
+{
+ ThrowIfDisposed ();
+ const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleCell" };
+ return comphelper::concatSequences(AccessibleContextBase::getSupportedServiceNames(), vals);
+}
+
+
+// IAccessibleViewForwarderListener
+
+
+void AccessibleCell::ViewForwarderChanged()
+{
+ // Inform all listeners that the graphical representation (i.e. size
+ // and/or position) of the shape has changed.
+ CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any());
+
+ // update our children that our screen position might have changed
+ if( mpText )
+ mpText->UpdateChildren();
+}
+
+
+// protected
+
+
+void AccessibleCell::disposing()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard (m_aMutex);
+
+ // Make sure to send an event that this object loses the focus in the
+ // case that it has the focus.
+ if (mxStateSet != nullptr)
+ mxStateSet->RemoveState(AccessibleStateType::FOCUSED);
+
+ if (mpText != nullptr)
+ {
+ mpText->Dispose();
+ mpText.reset();
+ }
+
+ // Cleanup. Remove references to objects to allow them to be
+ // destroyed.
+ mxCell.clear();
+ maShapeTreeInfo.dispose();
+
+ // Call base classes.
+ AccessibleContextBase::dispose ();
+}
+
+sal_Int32 SAL_CALL AccessibleCell::getAccessibleIndexInParent()
+{
+ ThrowIfDisposed ();
+ return mnIndexInParent;
+}
+
+
+OUString AccessibleCell::getCellName( sal_Int32 nCol, sal_Int32 nRow )
+{
+ OUStringBuffer aBuf;
+
+ if (nCol < 26*26)
+ {
+ if (nCol < 26)
+ aBuf.append( static_cast<sal_Unicode>( 'A' +
+ static_cast<sal_uInt16>(nCol)));
+ else
+ {
+ aBuf.append( static_cast<sal_Unicode>( 'A' +
+ (static_cast<sal_uInt16>(nCol) / 26) - 1));
+ aBuf.append( static_cast<sal_Unicode>( 'A' +
+ (static_cast<sal_uInt16>(nCol) % 26)));
+ }
+ }
+ else
+ {
+ OUStringBuffer aStr;
+ while (nCol >= 26)
+ {
+ sal_Int32 nC = nCol % 26;
+ aStr.append(static_cast<sal_Unicode>( 'A' +
+ static_cast<sal_uInt16>(nC)));
+ nCol = nCol - nC;
+ nCol = nCol / 26 - 1;
+ }
+ aStr.append(static_cast<sal_Unicode>( 'A' +
+ static_cast<sal_uInt16>(nCol)));
+ aBuf.append(comphelper::string::reverseString(aStr));
+ }
+ aBuf.append(nRow+1);
+ return aBuf.makeStringAndClear();
+}
+
+OUString SAL_CALL AccessibleCell::getAccessibleName()
+{
+ ThrowIfDisposed ();
+ SolarMutexGuard aSolarGuard;
+
+ if( pAccTable )
+ {
+ try
+ {
+ sal_Int32 nRow = 0, nCol = 0;
+ pAccTable->getColumnAndRow(mnIndexInParent, nCol, nRow);
+ return getCellName( nCol, nRow );
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+
+ return AccessibleCellBase::getAccessibleName();
+}
+
+void AccessibleCell::UpdateChildren()
+{
+ if (mpText)
+ mpText->UpdateChildren();
+}
+
+/* MT: Above getAccessibleName was introduced with IA2 CWS, while below was introduce in 3.3 meanwhile. Check which one is correct
++If this is correct, we also don't need sdr::table::CellRef getCellRef(), UpdateChildren(), getCellName( sal_Int32 nCol, sal_Int32 nRow ) above
++
+
+OUString SAL_CALL AccessibleCell::getAccessibleName() throw (css::uno::RuntimeException)
+{
+ ThrowIfDisposed ();
+ SolarMutexGuard aSolarGuard;
+
+ if( mxCell.is() )
+ return mxCell->getName();
+
+ return AccessibleCellBase::getAccessibleName();
+}
+*/
+
+} // end of namespace accessibility
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/accessiblecell.hxx b/svx/source/table/accessiblecell.hxx
new file mode 100644
index 000000000..65b9665ab
--- /dev/null
+++ b/svx/source/table/accessiblecell.hxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_ACCESSIBLECELL_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_ACCESSIBLECELL_HXX
+
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp>
+
+#include <editeng/AccessibleContextBase.hxx>
+#include <editeng/AccessibleComponentBase.hxx>
+#include <svx/IAccessibleViewForwarderListener.hxx>
+#include <svx/AccessibleTextHelper.hxx>
+#include <svx/AccessibleShapeTreeInfo.hxx>
+#include <AccessibleTableShape.hxx>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <celltypes.hxx>
+
+
+namespace accessibility
+{
+
+class AccessibleShapeTreeInfo;
+
+typedef ::cppu::ImplInheritanceHelper< AccessibleContextBase, css::accessibility::XAccessibleExtendedComponent > AccessibleCellBase;
+
+class AccessibleCell : public AccessibleCellBase
+ , public AccessibleComponentBase
+ , public IAccessibleViewForwarderListener
+{
+public:
+ AccessibleCell( const css::uno::Reference< css::accessibility::XAccessible>& rxParent, const sdr::table::CellRef& rCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo& rShapeTreeInfo);
+ virtual ~AccessibleCell() override;
+ AccessibleCell(const AccessibleCell&) = delete;
+ AccessibleCell& operator=(const AccessibleCell&) = delete;
+
+ void Init();
+
+ virtual bool SetState (sal_Int16 aState) override;
+ virtual bool ResetState (sal_Int16 aState) override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire( ) noexcept override;
+ virtual void SAL_CALL release( ) noexcept override;
+
+ // XAccessibleContext
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL getAccessibleChild(sal_Int32 nIndex) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet> SAL_CALL getAccessibleStateSet() override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override;
+ virtual OUString SAL_CALL getAccessibleName() override;
+ const sdr::table::CellRef& getCellRef() const { return mxCell;}
+ void UpdateChildren();
+ static OUString getCellName( sal_Int32 nCol, sal_Int32 nRow );
+
+ // XAccessibleComponent
+ virtual sal_Bool SAL_CALL containsPoint( const css::awt::Point& aPoint) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint(const css::awt::Point& aPoint) override;
+ virtual css::awt::Rectangle SAL_CALL getBounds() override;
+ virtual css::awt::Point SAL_CALL getLocation() override;
+ virtual css::awt::Point SAL_CALL getLocationOnScreen() override;
+ virtual css::awt::Size SAL_CALL getSize() override;
+ virtual void SAL_CALL grabFocus() override;
+ virtual sal_Int32 SAL_CALL getForeground() override;
+ virtual sal_Int32 SAL_CALL getBackground() override;
+
+ // XAccessibleExtendedComponent
+ virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont() override;
+ virtual OUString SAL_CALL getTitledBorderText() override;
+ virtual OUString SAL_CALL getToolTipText() override;
+
+ // XAccessibleEventBroadcaster
+ virtual void SAL_CALL addAccessibleEventListener( const css::uno::Reference< css::accessibility::XAccessibleEventListener >& rxListener) override;
+ virtual void SAL_CALL removeAccessibleEventListener( const css::uno::Reference< css::accessibility::XAccessibleEventListener >& rxListener) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // IAccessibleViewForwarderListener
+ virtual void ViewForwarderChanged() override;
+
+ // Misc
+
+ /** set the index _nIndex at the accessible cell param _nIndex The new index in parent.
+ */
+ void setIndexInParent(sal_Int32 _nIndex) { mnIndexInParent = _nIndex; }
+
+ //Get the parent table
+ AccessibleTableShape* GetParentTable() { return pAccTable; }
+protected:
+ /// Bundle of information passed to all shapes in a document tree.
+ AccessibleShapeTreeInfo maShapeTreeInfo;
+
+ /// the index in parent.
+ sal_Int32 mnIndexInParent;
+
+ /// The accessible text engine. May be NULL if it can not be created.
+ std::unique_ptr<AccessibleTextHelper> mpText;
+
+ sdr::table::CellRef mxCell;
+
+ /// This method is called from the component helper base class while disposing.
+ virtual void SAL_CALL disposing() override;
+
+ AccessibleTableShape *pAccTable;
+};
+
+} // end of namespace accessibility
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/accessibletableshape.cxx b/svx/source/table/accessibletableshape.cxx
new file mode 100644
index 000000000..540ae3116
--- /dev/null
+++ b/svx/source/table/accessibletableshape.cxx
@@ -0,0 +1,1324 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/table/XMergeableCell.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+
+#include <AccessibleTableShape.hxx>
+#include <svx/sdr/table/tablecontroller.hxx>
+#include "accessiblecell.hxx"
+#include <cell.hxx>
+
+#include <algorithm>
+#include <unordered_map>
+
+#include <cppuhelper/implbase.hxx>
+#include <svx/svdotable.hxx>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+
+
+using namespace ::accessibility;
+using namespace sdr::table;
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::container;
+
+namespace accessibility
+{
+
+typedef std::unordered_map< Reference< XCell >, rtl::Reference< AccessibleCell > > AccessibleCellMap;
+
+class AccessibleTableShapeImpl : public cppu::WeakImplHelper< XModifyListener >
+{
+public:
+ explicit AccessibleTableShapeImpl( AccessibleShapeTreeInfo& rShapeTreeInfo );
+
+ void init( const Reference< XAccessible>& xAccessible, const Reference< XTable >& xTable );
+ void dispose();
+
+ /// @throws IndexOutOfBoundsException
+ /// @throws RuntimeException
+ Reference< XAccessible > getAccessibleChild(sal_Int32 i);
+ /// @throws IndexOutOfBoundsException
+ void getColumnAndRow( sal_Int32 nChildIndex, sal_Int32& rnColumn, sal_Int32& rnRow );
+
+ // XModifyListener
+ virtual void SAL_CALL modified( const EventObject& aEvent ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& Source ) override;
+
+ AccessibleShapeTreeInfo& mrShapeTreeInfo;
+ Reference< XTable > mxTable;
+ AccessibleCellMap maChildMap;
+ Reference< XAccessible> mxAccessible;
+ sal_Int32 mRowCount, mColCount;
+ //get the cached AccessibleCell from XCell
+ rtl::Reference< AccessibleCell > getAccessibleCell (const Reference< XCell >& xCell);
+ /// @throws IndexOutOfBoundsException
+ /// @throws RuntimeException
+ rtl::Reference< AccessibleCell > getAccessibleCell (sal_Int32 nRow, sal_Int32 nColumn);
+};
+
+
+AccessibleTableShapeImpl::AccessibleTableShapeImpl( AccessibleShapeTreeInfo& rShapeTreeInfo )
+: mrShapeTreeInfo( rShapeTreeInfo )
+, mRowCount(0)
+, mColCount(0)
+{
+}
+
+
+void AccessibleTableShapeImpl::init( const Reference< XAccessible>& xAccessible, const Reference< XTable >& xTable )
+{
+ mxAccessible = xAccessible;
+ mxTable = xTable;
+
+ if( mxTable.is() )
+ {
+ Reference< XModifyListener > xListener( this );
+ mxTable->addModifyListener( xListener );
+ //register the listener with table model
+ Reference< css::view::XSelectionSupplier > xSelSupplier(xTable, UNO_QUERY);
+ Reference< css::view::XSelectionChangeListener > xSelListener( xAccessible, UNO_QUERY );
+ if (xSelSupplier.is())
+ xSelSupplier->addSelectionChangeListener(xSelListener);
+ mRowCount = mxTable->getRowCount();
+ mColCount = mxTable->getColumnCount();
+ }
+}
+
+
+void AccessibleTableShapeImpl::dispose()
+{
+ if( mxTable.is() )
+ {
+ //remove all the cell's acc object in table's dispose.
+ for( auto& rEntry : maChildMap )
+ {
+ rEntry.second->dispose();
+ }
+ maChildMap.clear();
+ Reference< XModifyListener > xListener( this );
+ mxTable->removeModifyListener( xListener );
+ mxTable.clear();
+ }
+ mxAccessible.clear();
+}
+
+
+//get the cached AccessibleCell from XCell
+rtl::Reference< AccessibleCell > AccessibleTableShapeImpl::getAccessibleCell (const Reference< XCell >& xCell)
+{
+ AccessibleCellMap::iterator iter( maChildMap.find( xCell ) );
+
+ if( iter != maChildMap.end() )
+ {
+ rtl::Reference< AccessibleCell > xChild( (*iter).second );
+ return xChild;
+ }
+ return rtl::Reference< AccessibleCell >();
+}
+
+rtl::Reference< AccessibleCell > AccessibleTableShapeImpl::getAccessibleCell (sal_Int32 nRow, sal_Int32 nColumn)
+{
+ Reference< XCell > xCell( mxTable->getCellByPosition( nColumn, nRow ) );
+ rtl::Reference< AccessibleCell > xChild = getAccessibleCell( xCell );
+
+ if( !xChild.is() && mxTable.is() )
+ {
+ sal_Int32 nChildIndex = mxTable->getColumnCount() * nRow + nColumn;
+ CellRef xCellRef( dynamic_cast< Cell* >( xCell.get() ) );
+
+ rtl::Reference< AccessibleCell > xAccessibleCell( new AccessibleCell( mxAccessible, xCellRef, nChildIndex, mrShapeTreeInfo ) );
+
+ xAccessibleCell->Init();
+ maChildMap[xCell] = xAccessibleCell;
+
+ xChild = xAccessibleCell;
+ }
+ return xChild;
+}
+
+
+Reference< XAccessible > AccessibleTableShapeImpl::getAccessibleChild(sal_Int32 nChildIndex)
+{
+ sal_Int32 nColumn = 0, nRow = 0;
+ getColumnAndRow( nChildIndex, nColumn, nRow );
+
+ Reference< XCell > xCell( mxTable->getCellByPosition( nColumn, nRow ) );
+ AccessibleCellMap::iterator iter( maChildMap.find( xCell ) );
+
+ if( iter != maChildMap.end() )
+ {
+ Reference< XAccessible > xChild( (*iter).second );
+ return xChild;
+ }
+ else
+ {
+ CellRef xCellRef( dynamic_cast< Cell* >( xCell.get() ) );
+
+ rtl::Reference< AccessibleCell > xAccessibleCell( new AccessibleCell( mxAccessible, xCellRef, nChildIndex, mrShapeTreeInfo ) );
+
+ xAccessibleCell->Init();
+ maChildMap[xCell] = xAccessibleCell;
+
+ return xAccessibleCell;
+ }
+}
+
+
+void AccessibleTableShapeImpl::getColumnAndRow( sal_Int32 nChildIndex, sal_Int32& rnColumn, sal_Int32& rnRow )
+{
+ rnRow = 0;
+ rnColumn = nChildIndex;
+
+ if( mxTable.is() )
+ {
+ const sal_Int32 nColumnCount = mxTable->getColumnCount();
+ while( rnColumn >= nColumnCount )
+ {
+ rnRow++;
+ rnColumn -= nColumnCount;
+ }
+
+ if( rnRow < mxTable->getRowCount() )
+ return;
+ }
+
+ throw IndexOutOfBoundsException();
+}
+
+// XModifyListener
+void SAL_CALL AccessibleTableShapeImpl::modified( const EventObject& /*aEvent*/ )
+{
+ if( !mxTable.is() )
+ return;
+
+ try
+ {
+ // structural changes may have happened to the table, validate all accessible cell instances
+ AccessibleCellMap aTempChildMap;
+ aTempChildMap.swap( maChildMap );
+
+ // first move all still existing cells to maChildMap again and update their index
+
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+ const sal_Int32 nColCount = mxTable->getColumnCount();
+
+ bool bRowOrColumnChanged = false;
+ if (mRowCount != nRowCount || mColCount != nColCount )
+ {
+ bRowOrColumnChanged = true;
+ mRowCount = nRowCount;
+ mColCount = nColCount;
+ }
+ sal_Int32 nChildIndex = 0;
+
+ for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ Reference< XCell > xCell( mxTable->getCellByPosition( nCol, nRow ) );
+ AccessibleCellMap::iterator iter( aTempChildMap.find( xCell ) );
+
+ if( iter != aTempChildMap.end() )
+ {
+ rtl::Reference< AccessibleCell > xAccessibleCell( (*iter).second );
+ xAccessibleCell->setIndexInParent( nChildIndex );
+ xAccessibleCell->UpdateChildren();
+ // If row or column count is changed, there is split or merge, so all cell's acc name should be updated
+ if (bRowOrColumnChanged)
+ {
+ xAccessibleCell->SetAccessibleName(xAccessibleCell->getAccessibleName(), AccessibleContextBase::ManuallySet);
+ }
+ // For merged cell, add invisible & disabled state.
+ Reference< XMergeableCell > xMergedCell( mxTable->getCellByPosition( nCol, nRow ), UNO_QUERY );
+ if (xMergedCell.is() && xMergedCell->isMerged())
+ {
+ xAccessibleCell->ResetState(AccessibleStateType::VISIBLE);
+ xAccessibleCell->ResetState(AccessibleStateType::ENABLED);
+ // IA2 CWS. MT: OFFSCREEN == !SHOWING, should stay consistent
+ // xAccessibleCell->SetState(AccessibleStateType::OFFSCREEN);
+ xAccessibleCell->ResetState(AccessibleStateType::SHOWING);
+ }
+ else
+ {
+ xAccessibleCell->SetState(AccessibleStateType::VISIBLE);
+ xAccessibleCell->SetState(AccessibleStateType::ENABLED);
+ // IA2 CWS. MT: OFFSCREEN == !SHOWING, should stay consistent
+ // xAccessibleCell->ResetState(AccessibleStateType::OFFSCREEN);
+ xAccessibleCell->SetState(AccessibleStateType::SHOWING);
+ }
+
+ // move still existing cell from temporary child map to our child map
+ maChildMap[xCell] = xAccessibleCell;
+ aTempChildMap.erase( iter );
+ }
+ else
+ {
+ CellRef xCellRef( dynamic_cast< Cell* >( xCell.get() ) );
+
+ rtl::Reference< AccessibleCell > xAccessibleCell( new AccessibleCell( mxAccessible, xCellRef, nChildIndex, mrShapeTreeInfo ) );
+
+ xAccessibleCell->Init();
+ maChildMap[xCell] = xAccessibleCell;
+ }
+
+ ++nChildIndex;
+ }
+ }
+
+ // all accessible cell instances still left in aTempChildMap must be disposed
+ // as they are no longer part of the table
+
+ for( auto& rEntry : aTempChildMap )
+ {
+ rEntry.second->dispose();
+ }
+ //notify bridge to update the acc cache.
+ AccessibleTableShape *pAccTable = dynamic_cast <AccessibleTableShape *> (mxAccessible.get());
+ if (pAccTable)
+ pAccTable->CommitChange(AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any());
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+}
+
+// XEventListener
+void SAL_CALL AccessibleTableShapeImpl::disposing( const EventObject& /*Source*/ )
+{
+}
+
+AccessibleTableShape::AccessibleTableShape( const AccessibleShapeInfo& rShapeInfo, const AccessibleShapeTreeInfo& rShapeTreeInfo)
+: AccessibleTableShape_Base(rShapeInfo, rShapeTreeInfo)
+, mnPreviousSelectionCount(0)
+, mxImpl( new AccessibleTableShapeImpl( maShapeTreeInfo ) )
+{
+}
+
+
+AccessibleTableShape::~AccessibleTableShape()
+{
+}
+
+
+void AccessibleTableShape::Init()
+{
+ try
+ {
+ Reference< XPropertySet > xSet( mxShape, UNO_QUERY_THROW );
+ Reference< XTable > xTable( xSet->getPropertyValue("Model"), UNO_QUERY_THROW );
+
+ mxImpl->init( this, xTable );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+
+ AccessibleTableShape_Base::Init();
+}
+
+
+SvxTableController* AccessibleTableShape::getTableController()
+{
+ SdrView* pView = maShapeTreeInfo.GetSdrView ();
+ if( pView )
+ return dynamic_cast< SvxTableController* >( pView->getSelectionController().get() );
+ else
+ return nullptr;
+}
+
+
+// XInterface
+
+
+Any SAL_CALL AccessibleTableShape::queryInterface( const Type& aType )
+{
+ if ( aType == cppu::UnoType<XAccessibleTableSelection>::get())
+ {
+ Reference<XAccessibleTableSelection> xThis( this );
+ Any aRet;
+ aRet <<= xThis;
+ return aRet;
+ }
+ else
+ return AccessibleTableShape_Base::queryInterface( aType );
+}
+
+
+void SAL_CALL AccessibleTableShape::acquire( ) noexcept
+{
+ AccessibleTableShape_Base::acquire();
+}
+
+
+void SAL_CALL AccessibleTableShape::release( ) noexcept
+{
+ AccessibleTableShape_Base::release();
+}
+
+
+// XAccessible
+
+
+OUString SAL_CALL AccessibleTableShape::getImplementationName()
+{
+ return "com.sun.star.comp.accessibility.AccessibleTableShape";
+}
+
+
+OUString AccessibleTableShape::CreateAccessibleBaseName()
+{
+ return "TableShape";
+}
+
+
+sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleChildCount( )
+{
+ SolarMutexGuard aSolarGuard;
+ return mxImpl->mxTable.is() ? mxImpl->mxTable->getRowCount() * mxImpl->mxTable->getColumnCount() : 0;
+}
+
+
+Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleChild( sal_Int32 i )
+{
+ SolarMutexGuard aSolarGuard;
+ ThrowIfDisposed();
+
+ return mxImpl->getAccessibleChild( i );
+}
+
+
+sal_Int16 SAL_CALL AccessibleTableShape::getAccessibleRole()
+{
+ return AccessibleRole::TABLE;
+}
+
+
+void SAL_CALL AccessibleTableShape::disposing()
+{
+ mxImpl->dispose();
+
+ // let the base do its stuff
+ AccessibleShape::disposing();
+}
+
+
+// XAccessibleTable
+
+
+sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleRowCount()
+{
+ SolarMutexGuard aSolarGuard;
+ return mxImpl->mxTable.is() ? mxImpl->mxTable->getRowCount() : 0;
+}
+
+
+sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleColumnCount( )
+{
+ SolarMutexGuard aSolarGuard;
+ return mxImpl->mxTable.is() ? mxImpl->mxTable->getColumnCount() : 0;
+}
+
+
+OUString SAL_CALL AccessibleTableShape::getAccessibleRowDescription( sal_Int32 nRow )
+{
+ checkCellPosition( 0, nRow );
+ return OUString();
+}
+
+
+OUString SAL_CALL AccessibleTableShape::getAccessibleColumnDescription( sal_Int32 nColumn )
+{
+ SolarMutexGuard aSolarGuard;
+ checkCellPosition( nColumn, 0 );
+ return OUString();
+}
+
+
+sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aSolarGuard;
+ checkCellPosition( nColumn, nRow );
+ if( mxImpl->mxTable.is() )
+ {
+ Reference< XMergeableCell > xCell( mxImpl->mxTable->getCellByPosition( nColumn, nRow ), UNO_QUERY );
+ if( xCell.is() )
+ return xCell->getRowSpan();
+ }
+ return 1;
+}
+
+
+sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aSolarGuard;
+ checkCellPosition( nColumn, nRow );
+ if( mxImpl->mxTable.is() )
+ {
+ Reference< XMergeableCell > xCell( mxImpl->mxTable->getCellByPosition( nColumn, nRow ), UNO_QUERY );
+ if( xCell.is() )
+ return xCell->getColumnSpan();
+ }
+ return 1;
+}
+
+
+Reference< XAccessibleTable > SAL_CALL AccessibleTableShape::getAccessibleRowHeaders( )
+{
+ Reference< XAccessibleTable > xRet;
+ SvxTableController* pController = getTableController();
+ if( pController )
+ {
+ if( pController->isRowHeader() )
+ {
+ xRet = new AccessibleTableHeaderShape( this, true );
+ }
+ }
+ return xRet;
+}
+
+
+Reference< XAccessibleTable > SAL_CALL AccessibleTableShape::getAccessibleColumnHeaders( )
+{
+ Reference< XAccessibleTable > xRet;
+ SvxTableController* pController = getTableController();
+ if( pController )
+ {
+ if( pController->isColumnHeader() )
+ {
+ xRet = new AccessibleTableHeaderShape( this, false );
+ }
+ }
+ return xRet;
+}
+
+
+Sequence< sal_Int32 > SAL_CALL AccessibleTableShape::getSelectedAccessibleRows( )
+{
+ sal_Int32 nRow = getAccessibleRowCount();
+ ::std::vector<bool> aSelected( nRow, true );
+ sal_Int32 nCount = nRow;
+ for( sal_Int32 i = 0; i < nRow; i++ )
+ {
+ try
+ {
+ aSelected[i] = isAccessibleRowSelected( i );
+ }
+ catch( ... )
+ {
+ return Sequence< sal_Int32 >();
+ }
+
+ if( !aSelected[i] )
+ nCount--;
+ }
+ Sequence < sal_Int32 > aRet( nCount );
+ sal_Int32 *pRet = aRet.getArray();
+ sal_Int32 nPos = 0;
+ size_t nSize = aSelected.size();
+ for( size_t i=0; i < nSize && nPos < nCount; i++ )
+ {
+ if( aSelected[i] )
+ {
+ *pRet++ = i;
+ nPos++;
+ }
+ }
+
+ return aRet;
+}
+
+
+Sequence< sal_Int32 > SAL_CALL AccessibleTableShape::getSelectedAccessibleColumns( )
+{
+ sal_Int32 nColumn = getAccessibleColumnCount();
+ ::std::vector<bool> aSelected( nColumn, true );
+ sal_Int32 nCount = nColumn;
+ for( sal_Int32 i = 0; i < nColumn; i++ )
+ {
+ try
+ {
+ aSelected[i] = isAccessibleColumnSelected( i );
+ }
+ catch( ... )
+ {
+ return Sequence< sal_Int32 >();
+ }
+
+ if( !aSelected[i] )
+ nCount--;
+ }
+ Sequence < sal_Int32 > aRet( nCount );
+ sal_Int32 *pRet = aRet.getArray();
+ sal_Int32 nPos = 0;
+ size_t nSize = aSelected.size();
+ for( size_t i=0; i < nSize && nPos < nCount; i++ )
+ {
+ if( aSelected[i] )
+ {
+ *pRet++ = i;
+ nPos++;
+ }
+ }
+
+ return aRet;
+}
+
+
+sal_Bool SAL_CALL AccessibleTableShape::isAccessibleRowSelected( sal_Int32 nRow )
+{
+ SolarMutexGuard aSolarGuard;
+ checkCellPosition( 0, nRow );
+ SvxTableController* pController = getTableController();
+ if( pController )
+ {
+ return pController->isRowSelected( nRow );
+ }
+ return false;
+}
+
+
+sal_Bool SAL_CALL AccessibleTableShape::isAccessibleColumnSelected( sal_Int32 nColumn )
+{
+ SolarMutexGuard aSolarGuard;
+ checkCellPosition( nColumn, 0 );
+ SvxTableController* pController = getTableController();
+ if( pController )
+ {
+ return pController->isColumnSelected( nColumn );
+ }
+ return false;
+}
+
+
+Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aSolarGuard;
+ checkCellPosition( nColumn, nRow );
+
+ sal_Int32 nChildIndex = 0;
+ if( mxImpl->mxTable.is() )
+ nChildIndex = mxImpl->mxTable->getColumnCount() * nRow + nColumn;
+
+ return getAccessibleChild( nChildIndex );
+}
+
+
+Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleCaption( )
+{
+ Reference< XAccessible > xRet;
+ return xRet;
+}
+
+
+Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleSummary( )
+{
+ Reference< XAccessible > xRet;
+ return xRet;
+}
+
+
+sal_Bool SAL_CALL AccessibleTableShape::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aSolarGuard;
+ checkCellPosition( nColumn, nRow );
+
+ SvxTableController* pController = getTableController();
+ if( pController && pController->hasSelectedCells() )
+ {
+ CellPos aFirstPos, aLastPos;
+ pController->getSelectedCells( aFirstPos, aLastPos );
+ if( (aFirstPos.mnRow <= nRow) && (aFirstPos.mnCol <= nColumn) && (nRow <= aLastPos.mnRow) && (nColumn <= aLastPos.mnCol) )
+ return true;
+ }
+
+ return false;
+}
+
+
+sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aSolarGuard;
+ checkCellPosition( nColumn, nRow );
+ return mxImpl->mxTable.is() ? (nRow * mxImpl->mxTable->getColumnCount() + nColumn) : 0;
+}
+
+
+sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleRow( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aSolarGuard;
+ sal_Int32 nColumn = 0, nRow = 0;
+ mxImpl->getColumnAndRow( nChildIndex, nColumn, nRow );
+ return nRow;
+}
+
+
+sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleColumn( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aSolarGuard;
+ sal_Int32 nColumn = 0, nRow = 0;
+ mxImpl->getColumnAndRow( nChildIndex, nColumn, nRow );
+ return nColumn;
+}
+
+
+// XAccessibleSelection
+
+
+void SAL_CALL AccessibleTableShape::selectAccessibleChild( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aSolarGuard;
+ CellPos aPos;
+ mxImpl->getColumnAndRow( nChildIndex, aPos.mnCol, aPos.mnRow );
+
+ // todo, select table shape?!?
+ SvxTableController* pController = getTableController();
+ if( !pController )
+ return;
+
+ CellPos aFirstPos( aPos ), aLastPos( aPos );
+ if( pController->hasSelectedCells() )
+ {
+ pController->getSelectedCells( aFirstPos, aLastPos );
+
+ aFirstPos.mnRow = std::min( aFirstPos.mnRow, aPos.mnRow );
+ aFirstPos.mnCol = std::min( aFirstPos.mnCol, aPos.mnCol );
+ aLastPos.mnRow = std::max( aLastPos.mnRow, aPos.mnRow );
+ aLastPos.mnCol = std::max( aLastPos.mnCol, aPos.mnCol );
+ }
+ pController->setSelectedCells( aFirstPos, aLastPos );
+}
+
+
+sal_Bool SAL_CALL AccessibleTableShape::isAccessibleChildSelected( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aSolarGuard;
+ CellPos aPos;
+ mxImpl->getColumnAndRow( nChildIndex, aPos.mnCol, aPos.mnRow );
+
+ return isAccessibleSelected(aPos.mnRow, aPos.mnCol);
+}
+
+
+void SAL_CALL AccessibleTableShape::clearAccessibleSelection()
+{
+ SolarMutexGuard aSolarGuard;
+
+ SvxTableController* pController = getTableController();
+ if( pController )
+ pController->clearSelection();
+}
+
+
+void SAL_CALL AccessibleTableShape::selectAllAccessibleChildren()
+{
+ SolarMutexGuard aSolarGuard;
+
+ // todo: force selection of shape?
+ SvxTableController* pController = getTableController();
+ if( pController )
+ pController->selectAll();
+}
+
+
+sal_Int32 SAL_CALL AccessibleTableShape::getSelectedAccessibleChildCount()
+{
+ SolarMutexGuard aSolarGuard;
+
+ SvxTableController* pController = getTableController();
+ if( pController && pController->hasSelectedCells() )
+ {
+ CellPos aFirstPos, aLastPos;
+ pController->getSelectedCells( aFirstPos, aLastPos );
+
+ const sal_Int32 nSelectedColumns = std::max( sal_Int32(0), aLastPos.mnCol - aFirstPos.mnCol ) + 1;
+ const sal_Int32 nSelectedRows = std::max( sal_Int32(0), aLastPos.mnRow - aFirstPos.mnRow ) + 1;
+ return nSelectedRows * nSelectedColumns;
+ }
+
+ return 0;
+}
+
+
+Reference< XAccessible > SAL_CALL AccessibleTableShape::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if( nSelectedChildIndex < 0 )
+ throw IndexOutOfBoundsException();
+
+ sal_Int32 nChildIndex = GetIndexOfSelectedChild( nSelectedChildIndex );
+
+ if( nChildIndex < 0 )
+ throw IndexOutOfBoundsException();
+
+ if ( nChildIndex >= getAccessibleChildCount() )
+ {
+ throw IndexOutOfBoundsException();
+ }
+
+ return getAccessibleChild( nChildIndex );
+}
+
+
+void SAL_CALL AccessibleTableShape::deselectAccessibleChild( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aSolarGuard;
+ CellPos aPos;
+ mxImpl->getColumnAndRow( nChildIndex, aPos.mnCol, aPos.mnRow );
+
+ // todo, select table shape?!?
+ SvxTableController* pController = getTableController();
+ if( !(pController && pController->hasSelectedCells()) )
+ return;
+
+ CellPos aFirstPos, aLastPos;
+ pController->getSelectedCells( aFirstPos, aLastPos );
+
+ // create a selection where aPos is not part of anymore
+ aFirstPos.mnRow = std::min( aFirstPos.mnRow, aPos.mnRow+1 );
+ aFirstPos.mnCol = std::min( aFirstPos.mnCol, aPos.mnCol+1 );
+ aLastPos.mnRow = std::max( aLastPos.mnRow, aPos.mnRow-1 );
+ aLastPos.mnCol = std::max( aLastPos.mnCol, aPos.mnCol-1 );
+
+ // new selection may be invalid (child to deselect is not at a border of the selection but in between)
+ if( (aFirstPos.mnRow > aLastPos.mnRow) || (aFirstPos.mnCol > aLastPos.mnCol) )
+ pController->clearSelection(); // if selection is invalid, clear all
+ else
+ pController->setSelectedCells( aFirstPos, aLastPos );
+}
+
+// XAccessibleTableSelection
+sal_Bool SAL_CALL AccessibleTableShape::selectRow( sal_Int32 row )
+{
+ SolarMutexGuard aSolarGuard;
+ SvxTableController* pController = getTableController();
+ if( !pController )
+ return false;
+ return pController->selectRow( row );
+}
+
+sal_Bool SAL_CALL AccessibleTableShape::selectColumn( sal_Int32 column )
+{
+ SolarMutexGuard aSolarGuard;
+ SvxTableController* pController = getTableController();
+ if( !pController )
+ return false;
+ return pController->selectColumn( column );
+}
+
+sal_Bool SAL_CALL AccessibleTableShape::unselectRow( sal_Int32 row )
+{
+ SolarMutexGuard aSolarGuard;
+ SvxTableController* pController = getTableController();
+ if( !pController )
+ return false;
+ return pController->deselectRow( row );
+}
+
+sal_Bool SAL_CALL AccessibleTableShape::unselectColumn( sal_Int32 column )
+{
+ SolarMutexGuard aSolarGuard;
+ SvxTableController* pController = getTableController();
+ if( !pController )
+ return false;
+ return pController->deselectColumn( column );
+}
+
+sal_Int32 AccessibleTableShape::GetIndexOfSelectedChild(
+ sal_Int32 nSelectedChildIndex ) const
+{
+ sal_Int32 nChildren = const_cast<AccessibleTableShape*>(this)->getAccessibleChildCount();
+
+ if( nSelectedChildIndex >= nChildren )
+ return -1;
+
+ sal_Int32 n = 0;
+ while( n < nChildren )
+ {
+ if( const_cast<AccessibleTableShape*>(this)->isAccessibleChildSelected( n ) )
+ {
+ if( 0 == nSelectedChildIndex )
+ break;
+ else
+ --nSelectedChildIndex;
+ }
+ ++n;
+ }
+
+ return n < nChildren ? n : -1;
+}
+void AccessibleTableShape::getColumnAndRow( sal_Int32 nChildIndex, sal_Int32& rnColumn, sal_Int32& rnRow )
+{
+ mxImpl->getColumnAndRow(nChildIndex, rnColumn, rnRow);
+}
+
+// XSelectionChangeListener
+void SAL_CALL
+ AccessibleTableShape::disposing (const EventObject& aEvent)
+{
+ AccessibleShape::disposing(aEvent);
+}
+void SAL_CALL AccessibleTableShape::selectionChanged (const EventObject& rEvent)
+{
+ //sdr::table::CellRef xCellRef = static_cast< sdr::table::CellRef > (rEvent.Source);
+ Reference< XCell > xCell(rEvent.Source, UNO_QUERY);
+ if (!xCell.is())
+ return;
+
+ rtl::Reference< AccessibleCell > xAccCell = mxImpl->getAccessibleCell( xCell );
+ if (!xAccCell.is())
+ return;
+
+ sal_Int32 nIndex = xAccCell->getAccessibleIndexInParent(),
+ nCount = getSelectedAccessibleChildCount();
+ bool bSelected = isAccessibleChildSelected(nIndex);
+ if (mnPreviousSelectionCount == 0 && nCount > 0 && bSelected)
+ {
+ xAccCell->SetState(AccessibleStateType::SELECTED);
+ xAccCell->CommitChange(AccessibleEventId::SELECTION_CHANGED, Any(), Any());
+ }
+ else if (bSelected)
+ {
+ xAccCell->SetState(AccessibleStateType::SELECTED);
+ xAccCell->CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD, Any(), Any());
+ }
+ else
+ {
+ xAccCell->ResetState(AccessibleStateType::SELECTED);
+ xAccCell->CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE, Any(), Any());
+ }
+ mnPreviousSelectionCount = nCount;
+}
+// Get the currently active cell which is text editing
+AccessibleCell* AccessibleTableShape::GetActiveAccessibleCell()
+{
+ rtl::Reference< AccessibleCell > xAccCell;
+ AccessibleCell* pAccCell = nullptr;
+ SvxTableController* pController = getTableController();
+ if (pController)
+ {
+ sdr::table::SdrTableObj* pTableObj = pController->GetTableObj();
+ if ( pTableObj )
+ {
+ const sdr::table::CellRef& xCellRef (pTableObj->getActiveCell());
+ if ( xCellRef.is() )
+ {
+ try
+ {
+ CellPos rPos;
+ pTableObj->getActiveCellPos( rPos );
+ xAccCell = mxImpl->getAccessibleCell( rPos.mnRow, rPos.mnCol );
+ if ( xAccCell.is() )
+ pAccCell = xAccCell.get();
+ }
+ catch ( IndexOutOfBoundsException& ) {}
+ }
+ }
+ }
+ return pAccCell;
+}
+
+//If current active cell is in editing, the focus state should be set to internal text
+bool AccessibleTableShape::SetState (sal_Int16 aState)
+{
+ if( aState == AccessibleStateType::FOCUSED )
+ {
+ AccessibleCell* pActiveAccessibleCell = GetActiveAccessibleCell();
+ if( pActiveAccessibleCell != nullptr )
+ return pActiveAccessibleCell->SetState(aState);
+ }
+
+ return AccessibleShape::SetState (aState);
+}
+
+//If current active cell is in editing, the focus state should be reset to internal text
+bool AccessibleTableShape::ResetState (sal_Int16 aState)
+{
+ if( aState == AccessibleStateType::FOCUSED )
+ {
+ AccessibleCell* pActiveAccessibleCell = GetActiveAccessibleCell();
+ if( pActiveAccessibleCell != nullptr )
+ return pActiveAccessibleCell->ResetState(aState);
+ }
+
+ return AccessibleShape::ResetState (aState);
+}
+
+bool AccessibleTableShape::SetStateDirectly (sal_Int16 aState)
+{
+ return AccessibleContextBase::SetState (aState);
+}
+
+bool AccessibleTableShape::ResetStateDirectly (sal_Int16 aState)
+{
+ return AccessibleContextBase::ResetState (aState);
+}
+
+void AccessibleTableShape::checkCellPosition( sal_Int32 nCol, sal_Int32 nRow )
+{
+ if( (nCol >= 0) && (nRow >= 0) && mxImpl->mxTable.is() && (nCol < mxImpl->mxTable->getColumnCount()) && (nRow < mxImpl->mxTable->getRowCount()) )
+ return;
+
+ throw IndexOutOfBoundsException();
+}
+
+AccessibleTableHeaderShape::AccessibleTableHeaderShape( AccessibleTableShape* pTable, bool bRow )
+{
+ mpTable = pTable;
+ mbRow = bRow;
+}
+
+AccessibleTableHeaderShape::~AccessibleTableHeaderShape()
+{
+ mpTable = nullptr;
+}
+
+// XAccessible
+Reference< XAccessibleContext > SAL_CALL AccessibleTableHeaderShape::getAccessibleContext()
+{
+ return this;
+}
+
+// XAccessibleContext
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getAccessibleChildCount( )
+{
+ return getAccessibleRowCount() * getAccessibleColumnCount();
+}
+
+Reference< XAccessible > SAL_CALL AccessibleTableHeaderShape::getAccessibleChild( sal_Int32 i )
+{
+ return mpTable->getAccessibleChild( i );
+}
+
+Reference< XAccessible > SAL_CALL AccessibleTableHeaderShape::getAccessibleParent()
+{
+ Reference< XAccessible > XParent;
+ return XParent;
+}
+
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getAccessibleIndexInParent()
+{
+ return -1;
+}
+
+sal_Int16 SAL_CALL AccessibleTableHeaderShape::getAccessibleRole()
+{
+ return mpTable->getAccessibleRole();
+}
+
+OUString SAL_CALL AccessibleTableHeaderShape::getAccessibleDescription()
+{
+ return mpTable->getAccessibleDescription();
+}
+
+OUString SAL_CALL AccessibleTableHeaderShape::getAccessibleName()
+{
+ return mpTable->getAccessibleName();
+}
+
+Reference< XAccessibleStateSet > SAL_CALL AccessibleTableHeaderShape::getAccessibleStateSet()
+{
+ return mpTable->getAccessibleStateSet();
+}
+
+Reference< XAccessibleRelationSet > SAL_CALL AccessibleTableHeaderShape::getAccessibleRelationSet()
+{
+ return mpTable->getAccessibleRelationSet();
+}
+
+Locale SAL_CALL AccessibleTableHeaderShape::getLocale()
+{
+ return mpTable->getLocale();
+}
+
+//XAccessibleComponent
+sal_Bool SAL_CALL AccessibleTableHeaderShape::containsPoint ( const css::awt::Point& aPoint )
+{
+ return mpTable->containsPoint( aPoint );
+}
+
+Reference< XAccessible > SAL_CALL AccessibleTableHeaderShape::getAccessibleAtPoint ( const css::awt::Point& aPoint)
+{
+ return mpTable->getAccessibleAtPoint( aPoint );
+}
+
+css::awt::Rectangle SAL_CALL AccessibleTableHeaderShape::getBounds()
+{
+ return mpTable->getBounds();
+}
+
+css::awt::Point SAL_CALL AccessibleTableHeaderShape::getLocation()
+{
+ return mpTable->getLocation();
+}
+
+css::awt::Point SAL_CALL AccessibleTableHeaderShape::getLocationOnScreen()
+{
+ return mpTable->getLocationOnScreen();
+}
+
+css::awt::Size SAL_CALL AccessibleTableHeaderShape::getSize()
+{
+ return mpTable->getSize();
+}
+
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getForeground()
+{
+ return mpTable->getForeground();
+}
+
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getBackground()
+{
+ return mpTable->getBackground();
+}
+
+void SAL_CALL AccessibleTableHeaderShape::grabFocus()
+{
+ mpTable->grabFocus();
+}
+// XAccessibleTable
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getAccessibleRowCount()
+{
+ return mbRow ? 1 : mpTable->getAccessibleRowCount();
+}
+
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getAccessibleColumnCount()
+{
+ return !mbRow ? 1 : mpTable->getAccessibleColumnCount();
+}
+
+OUString SAL_CALL AccessibleTableHeaderShape::getAccessibleRowDescription( sal_Int32 nRow )
+{
+ return mpTable->getAccessibleRowDescription( nRow );
+}
+
+OUString SAL_CALL AccessibleTableHeaderShape::getAccessibleColumnDescription( sal_Int32 nColumn )
+{
+ return mpTable->getAccessibleColumnDescription( nColumn );
+}
+
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ return mpTable->getAccessibleRowExtentAt( nRow, nColumn );
+}
+
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ return mpTable->getAccessibleColumnExtentAt( nRow, nColumn );
+}
+
+Reference< XAccessibleTable > SAL_CALL AccessibleTableHeaderShape::getAccessibleRowHeaders( )
+{
+ Reference< XAccessibleTable > xRet;
+ return xRet;
+}
+
+Reference< XAccessibleTable > SAL_CALL AccessibleTableHeaderShape::getAccessibleColumnHeaders( )
+{
+ Reference< XAccessibleTable > xRet;
+ return xRet;
+}
+
+Sequence< sal_Int32 > SAL_CALL AccessibleTableHeaderShape::getSelectedAccessibleRows( )
+{
+ sal_Int32 nRow = getAccessibleRowCount();
+ ::std::vector<bool> aSelected( nRow, true );
+ sal_Int32 nCount = nRow;
+ for( sal_Int32 i = 0; i < nRow; i++ )
+ {
+ try
+ {
+ aSelected[i] = isAccessibleRowSelected( i );
+ }
+ catch( ... )
+ {
+ return Sequence< sal_Int32 >();
+ }
+
+ if( !aSelected[i] )
+ nCount--;
+ }
+ Sequence < sal_Int32 > aRet( nCount );
+ sal_Int32 *pRet = aRet.getArray();
+ sal_Int32 nPos = 0;
+ size_t nSize = aSelected.size();
+ for( size_t i=0; i < nSize && nPos < nCount; i++ )
+ {
+ if( aSelected[i] )
+ {
+ *pRet++ = i;
+ nPos++;
+ }
+ }
+
+ return aRet;
+}
+
+Sequence< sal_Int32 > SAL_CALL AccessibleTableHeaderShape::getSelectedAccessibleColumns( )
+{
+ sal_Int32 nColumn = getAccessibleColumnCount();
+ ::std::vector<bool> aSelected( nColumn, true );
+ sal_Int32 nCount = nColumn;
+ for( sal_Int32 i = 0; i < nColumn; i++ )
+ {
+ try
+ {
+ aSelected[i] = isAccessibleColumnSelected( i );
+ }
+ catch( ... )
+ {
+ return Sequence< sal_Int32 >();
+ }
+
+ if( !aSelected[i] )
+ nCount--;
+ }
+ Sequence < sal_Int32 > aRet( nCount );
+ sal_Int32 *pRet = aRet.getArray();
+ sal_Int32 nPos = 0;
+ size_t nSize = aSelected.size();
+ for( size_t i=0; i < nSize && nPos < nCount; i++ )
+ {
+ if( aSelected[i] )
+ {
+ *pRet++ = i;
+ nPos++;
+ }
+ }
+
+ return aRet;
+}
+
+sal_Bool SAL_CALL AccessibleTableHeaderShape::isAccessibleRowSelected( sal_Int32 nRow )
+{
+ return mpTable->isAccessibleRowSelected( nRow );
+}
+
+sal_Bool SAL_CALL AccessibleTableHeaderShape::isAccessibleColumnSelected( sal_Int32 nColumn )
+{
+ return mpTable->isAccessibleColumnSelected( nColumn );
+}
+
+Reference< XAccessible > SAL_CALL AccessibleTableHeaderShape::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ return mpTable->getAccessibleCellAt( nRow, nColumn );
+}
+
+Reference< XAccessible > SAL_CALL AccessibleTableHeaderShape::getAccessibleCaption( )
+{
+ return mpTable->getAccessibleCaption();
+}
+
+Reference< XAccessible > SAL_CALL AccessibleTableHeaderShape::getAccessibleSummary( )
+{
+ return mpTable->getAccessibleSummary();
+}
+
+sal_Bool SAL_CALL AccessibleTableHeaderShape::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ return mpTable->isAccessibleSelected( nRow, nColumn );
+}
+
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ return mpTable->getAccessibleIndex( nRow, nColumn );
+}
+
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getAccessibleRow( sal_Int32 nChildIndex )
+{
+ return mpTable->getAccessibleRow( nChildIndex );
+}
+
+sal_Int32 SAL_CALL AccessibleTableHeaderShape::getAccessibleColumn( sal_Int32 nChildIndex )
+{
+ return mpTable->getAccessibleColumn( nChildIndex );
+}
+
+// XAccessibleTableSelection
+sal_Bool SAL_CALL AccessibleTableHeaderShape::selectRow( sal_Int32 row )
+{
+ if( mbRow )
+ return mpTable->selectRow( row );
+ else
+ {
+ mpTable->clearAccessibleSelection();
+ sal_Int32 nIndex = mpTable->getAccessibleIndex( row, 0 );
+ mpTable->selectAccessibleChild( nIndex );
+ return true;
+ }
+}
+
+sal_Bool SAL_CALL AccessibleTableHeaderShape::selectColumn( sal_Int32 column )
+{
+ if( !mbRow )
+ return mpTable->selectColumn( column );
+ else
+ {
+ mpTable->clearAccessibleSelection();
+ sal_Int32 nIndex = mpTable->getAccessibleIndex( 0, column );
+ mpTable->selectAccessibleChild( nIndex );
+ return true;
+ }
+}
+
+sal_Bool SAL_CALL AccessibleTableHeaderShape::unselectRow( sal_Int32 row )
+{
+ if( mbRow )
+ return mpTable->unselectRow( row );
+ else
+ {
+ sal_Int32 nIndex = mpTable->getAccessibleIndex( row, 0 );
+ mpTable->deselectAccessibleChild( nIndex );
+ return true;
+ }
+}
+
+sal_Bool SAL_CALL AccessibleTableHeaderShape::unselectColumn( sal_Int32 column )
+{
+ if( !mbRow )
+ return mpTable->unselectColumn( column );
+ else
+ {
+ sal_Int32 nIndex = mpTable->getAccessibleIndex( 0, column );
+ mpTable->deselectAccessibleChild( nIndex );
+ return true;
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/cell.cxx b/svx/source/table/cell.cxx
new file mode 100644
index 000000000..ba335ca27
--- /dev/null
+++ b/svx/source/table/cell.cxx
@@ -0,0 +1,1712 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/drawing/BitmapMode.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <o3tl/any.hxx>
+#include <svl/style.hxx>
+#include <svl/itemset.hxx>
+
+#include <vcl/svapp.hxx>
+#include <libxml/xmlwriter.h>
+
+#include <sdr/properties/textproperties.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/writingmodeitem.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/unoshtxt.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/xit.hxx>
+#include <getallcharpropids.hxx>
+#include "tableundo.hxx"
+#include <cell.hxx>
+#include <svx/unoshprp.hxx>
+#include <svx/unoshape.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/charrotateitem.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/xflclit.hxx>
+#include <tools/diagnose_ex.h>
+
+
+using ::editeng::SvxBorderLine;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::container;
+
+
+static const SvxItemPropertySet* ImplGetSvxCellPropertySet()
+{
+ // property map for an outliner text
+ static const SfxItemPropertyMapEntry aSvxCellPropertyMap[] =
+ {
+ FILL_PROPERTIES
+// { "HasLevels", OWN_ATTR_HASLEVELS, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"Style", OWN_ATTR_STYLE, cppu::UnoType< css::style::XStyle >::get(), css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { UNO_NAME_TEXT_WRITINGMODE, SDRATTR_TEXTDIRECTION, cppu::UnoType<css::text::WritingMode>::get(), 0, 0},
+ { UNO_NAME_TEXT_HORZADJUST, SDRATTR_TEXT_HORZADJUST, cppu::UnoType<css::drawing::TextHorizontalAdjust>::get(), 0, 0},
+ { UNO_NAME_TEXT_LEFTDIST, SDRATTR_TEXT_LEFTDIST, cppu::UnoType<sal_Int32>::get(), 0, 0, PropertyMoreFlags::METRIC_ITEM},
+ { UNO_NAME_TEXT_LOWERDIST, SDRATTR_TEXT_LOWERDIST, cppu::UnoType<sal_Int32>::get(), 0, 0, PropertyMoreFlags::METRIC_ITEM},
+ { UNO_NAME_TEXT_RIGHTDIST, SDRATTR_TEXT_RIGHTDIST, cppu::UnoType<sal_Int32>::get(), 0, 0, PropertyMoreFlags::METRIC_ITEM},
+ { UNO_NAME_TEXT_UPPERDIST, SDRATTR_TEXT_UPPERDIST, cppu::UnoType<sal_Int32>::get(), 0, 0, PropertyMoreFlags::METRIC_ITEM},
+ { UNO_NAME_TEXT_VERTADJUST, SDRATTR_TEXT_VERTADJUST, cppu::UnoType<css::drawing::TextVerticalAdjust>::get(), 0, 0},
+ { UNO_NAME_TEXT_WORDWRAP, SDRATTR_TEXT_WORDWRAP, cppu::UnoType<bool>::get(), 0, 0},
+
+ { u"TableBorder", OWN_ATTR_TABLEBORDER, cppu::UnoType<TableBorder>::get(), 0, 0 },
+ { u"TopBorder", SDRATTR_TABLE_BORDER, cppu::UnoType<BorderLine>::get(), 0, TOP_BORDER },
+ { u"BottomBorder", SDRATTR_TABLE_BORDER, cppu::UnoType<BorderLine>::get(), 0, BOTTOM_BORDER },
+ { u"LeftBorder", SDRATTR_TABLE_BORDER, cppu::UnoType<BorderLine>::get(), 0, LEFT_BORDER },
+ { u"RightBorder", SDRATTR_TABLE_BORDER, cppu::UnoType<BorderLine>::get(), 0, RIGHT_BORDER },
+ { u"RotateAngle", SDRATTR_TABLE_TEXT_ROTATION, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+
+ SVX_UNOEDIT_OUTLINER_PROPERTIES,
+ SVX_UNOEDIT_CHAR_PROPERTIES,
+ SVX_UNOEDIT_PARA_PROPERTIES,
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ static SvxItemPropertySet aSvxCellPropertySet( aSvxCellPropertyMap, SdrObject::GetGlobalDrawObjectItemPool() );
+ return &aSvxCellPropertySet;
+}
+
+namespace
+{
+
+class CellTextProvider : public svx::ITextProvider
+{
+public:
+ explicit CellTextProvider(const sdr::table::CellRef& rCell);
+ virtual ~CellTextProvider();
+
+private:
+ virtual sal_Int32 getTextCount() const override;
+ virtual SdrText* getText(sal_Int32 nIndex) const override;
+
+private:
+ const sdr::table::CellRef m_xCell;
+};
+
+CellTextProvider::CellTextProvider(const sdr::table::CellRef& rCell)
+ : m_xCell(rCell)
+{
+}
+
+CellTextProvider::~CellTextProvider()
+{
+}
+
+sal_Int32 CellTextProvider::getTextCount() const
+{
+ return 1;
+}
+
+SdrText* CellTextProvider::getText(sal_Int32 nIndex) const
+{
+ (void) nIndex;
+ assert(nIndex == 0);
+ return m_xCell.get();
+}
+
+}
+
+namespace sdr::properties
+{
+ class CellProperties : public TextProperties
+ {
+ protected:
+ // create a new itemset
+ SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
+
+ const svx::ITextProvider& getTextProvider() const override;
+
+ public:
+ // basic constructor
+ CellProperties(SdrObject& rObj, sdr::table::Cell* pCell );
+
+ // constructor for copying, but using new object
+ CellProperties(const CellProperties& rProps, SdrObject& rObj, sdr::table::Cell* pCell);
+
+ // Clone() operator, normally just calls the local copy constructor
+ std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ void ForceDefaultAttributes() override;
+
+ void ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich) override;
+
+ void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = nullptr) override;
+
+ sdr::table::CellRef mxCell;
+
+ private:
+ const CellTextProvider maTextProvider;
+ };
+
+ // create a new itemset
+ SfxItemSet CellProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool,
+
+ // range from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+
+ // range for SdrTableObj
+ SDRATTR_TABLE_FIRST, SDRATTR_TABLE_LAST,
+
+ // range from SdrTextObj
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ const svx::ITextProvider& CellProperties::getTextProvider() const
+ {
+ return maTextProvider;
+ }
+
+ CellProperties::CellProperties(SdrObject& rObj, sdr::table::Cell* pCell)
+ : TextProperties(rObj)
+ , mxCell(pCell)
+ , maTextProvider(mxCell)
+ {
+ }
+
+ CellProperties::CellProperties(const CellProperties& rProps, SdrObject& rObj, sdr::table::Cell* pCell)
+ : TextProperties(rProps, rObj)
+ , mxCell( pCell )
+ , maTextProvider(mxCell)
+ {
+ }
+
+ std::unique_ptr<BaseProperties> CellProperties::Clone(SdrObject& rObj) const
+ {
+ OSL_FAIL("CellProperties::Clone(), does not work yet!");
+ return std::unique_ptr<BaseProperties>(new CellProperties(*this, rObj,nullptr));
+ }
+
+ void CellProperties::ForceDefaultAttributes()
+ {
+ }
+
+ void CellProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+ if( mxCell.is() )
+ {
+ std::optional<OutlinerParaObject> pParaObj = mxCell->CreateEditOutlinerParaObject();
+
+ if( !pParaObj && mxCell->GetOutlinerParaObject())
+ pParaObj = *mxCell->GetOutlinerParaObject();
+
+ if(pParaObj)
+ {
+ // handle outliner attributes
+ Outliner* pOutliner = nullptr;
+
+ if(mxCell->IsTextEditActive())
+ {
+ pOutliner = rObj.GetTextEditOutliner();
+ }
+ else
+ {
+ pOutliner = &rObj.ImpGetDrawOutliner();
+ pOutliner->SetText(*pParaObj);
+ }
+
+ sal_Int32 nParaCount(pOutliner->GetParagraphCount());
+
+ // if the user sets character attributes to the complete
+ // cell we want to remove all hard set character attributes
+ // with same which ids from the text
+ std::vector<sal_uInt16> aCharWhichIds(GetAllCharPropIds(aChangedItems));
+
+ for(sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
+ {
+ SfxItemSet aSet(pOutliner->GetParaAttribs(nPara));
+ for (const SfxPoolItem* pItem : aChangedItems)
+ aSet.Put(*pItem);
+ if (nDeletedWhich)
+ aSet.ClearItem(nDeletedWhich);
+
+ for (const auto& rWhichId : aCharWhichIds)
+ {
+ pOutliner->RemoveCharAttribs(nPara, rWhichId);
+ }
+
+ pOutliner->SetParaAttribs(nPara, aSet);
+ }
+
+ if(!mxCell->IsTextEditActive())
+ {
+ if(nParaCount)
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ SfxItemSet aNewSet(pOutliner->GetParaAttribs(0));
+ mxItemSet->Put(aNewSet);
+ }
+
+ std::optional<OutlinerParaObject> pTemp = pOutliner->CreateParaObject(0, nParaCount);
+ pOutliner->Clear();
+ mxCell->SetOutlinerParaObject(std::move(pTemp));
+ }
+
+ }
+ }
+
+ // call parent
+ AttributeProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ if( mxCell.is() )
+ mxCell->notifyModified();
+ }
+
+ void CellProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
+ {
+ if(pNewItem && (SDRATTR_TEXTDIRECTION == nWhich))
+ {
+ bool bVertical(css::text::WritingMode_TB_RL == static_cast<const SvxWritingModeItem*>(pNewItem)->GetValue());
+
+ sdr::table::SdrTableObj& rObj = static_cast<sdr::table::SdrTableObj&>(GetSdrObject());
+ rObj.SetVerticalWriting(bVertical);
+
+ // Set a cell vertical property
+ std::optional<OutlinerParaObject> pEditParaObj = mxCell->CreateEditOutlinerParaObject();
+
+ if( !pEditParaObj && mxCell->GetOutlinerParaObject() )
+ {
+ OutlinerParaObject* pParaObj = mxCell->GetOutlinerParaObject();
+ if(pParaObj)
+ pParaObj->SetVertical(bVertical);
+ }
+ }
+
+ if (pNewItem && (SDRATTR_TABLE_TEXT_ROTATION == nWhich))
+ {
+ const SvxTextRotateItem* pRotateItem = static_cast<const SvxTextRotateItem*>(pNewItem);
+
+ // Set a cell vertical property
+ std::optional<OutlinerParaObject> pEditParaObj = mxCell->CreateEditOutlinerParaObject();
+
+ if (!pEditParaObj && mxCell->GetOutlinerParaObject())
+ {
+ OutlinerParaObject* pParaObj = mxCell->GetOutlinerParaObject();
+ if (pParaObj)
+ {
+ if(pRotateItem->IsVertical() && pRotateItem->IsTopToBottom())
+ pParaObj->SetRotation(TextRotation::TOPTOBOTTOM);
+ else if (pRotateItem->IsVertical())
+ pParaObj->SetRotation(TextRotation::BOTTOMTOTOP);
+ else
+ pParaObj->SetRotation(TextRotation::NONE);
+ }
+ }
+
+ // Change autogrow direction
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+ // rescue object size
+ tools::Rectangle aObjectRect = rObj.GetSnapRect();
+
+ const SfxItemSet& rSet = rObj.GetObjectItemSet();
+ bool bAutoGrowWidth = rSet.Get(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue();
+ bool bAutoGrowHeight = rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
+
+ // prepare ItemSet to set exchanged width and height items
+ SfxItemSetFixed<SDRATTR_TEXT_AUTOGROWHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT> aNewSet(*rSet.GetPool());
+
+ aNewSet.Put(rSet);
+ aNewSet.Put(makeSdrTextAutoGrowWidthItem(bAutoGrowHeight));
+ aNewSet.Put(makeSdrTextAutoGrowHeightItem(bAutoGrowWidth));
+ rObj.SetObjectItemSet(aNewSet);
+
+ // restore object size
+ rObj.SetSnapRect(aObjectRect);
+ }
+
+ // call parent
+ AttributeProperties::ItemChange( nWhich, pNewItem );
+ }
+
+} // end of namespace sdr::properties
+
+namespace sdr::table {
+
+
+// Cell
+
+
+rtl::Reference< Cell > Cell::create( SdrTableObj& rTableObj )
+{
+ rtl::Reference< Cell > xCell( new Cell( rTableObj ) );
+ if( xCell->mxTable.is() )
+ {
+ xCell->mxTable->addEventListener( xCell );
+ }
+ return xCell;
+}
+
+
+Cell::Cell(
+ SdrTableObj& rTableObj)
+: SdrText(rTableObj)
+ ,SvxUnoTextBase( ImplGetSvxUnoOutlinerTextCursorSvxPropertySet() )
+ ,mpPropSet( ImplGetSvxCellPropertySet() )
+ ,mpProperties( new sdr::properties::CellProperties( rTableObj, this ) )
+ ,mnCellContentType( CellContentType_EMPTY )
+ ,mfValue( 0.0 )
+ ,mnError( 0 )
+ ,mbMerged( false )
+ ,mnRowSpan( 1 )
+ ,mnColSpan( 1 )
+ ,mxTable( rTableObj.getTable() )
+{
+ // Caution: Old SetModel() indirectly did a very necessary thing here,
+ // it created a valid SvxTextEditSource which is needed to bind contained
+ // Text to the UNO API and thus to save/load and more. Added version without
+ // model change.
+ // Also done was (not needed, for reference):
+ // SetStyleSheet( nullptr, true );
+ // ForceOutlinerParaObject( OutlinerMode::TextObject );
+ if(nullptr == GetEditSource())
+ {
+ SetEditSource(new SvxTextEditSource(&GetObject(), this));
+ }
+}
+
+Cell::~Cell() COVERITY_NOEXCEPT_FALSE
+{
+ dispose();
+}
+
+void Cell::dispose()
+{
+ if( mxTable.is() )
+ {
+ try
+ {
+ Reference< XEventListener > xThis( this );
+ mxTable->removeEventListener( xThis );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+ mxTable.clear();
+ }
+
+ // tdf#118199 avoid double dispose, detect by using mpProperties
+ // as indicator. Only use SetOutlinerParaObject once
+ if( mpProperties )
+ {
+ mpProperties.reset();
+ SetOutlinerParaObject( std::nullopt );
+ }
+}
+
+void Cell::merge( sal_Int32 nColumnSpan, sal_Int32 nRowSpan )
+{
+ if ((mnColSpan != nColumnSpan) || (mnRowSpan != nRowSpan) || mbMerged)
+ {
+ mnColSpan = nColumnSpan;
+ mnRowSpan = nRowSpan;
+ mbMerged = false;
+ notifyModified();
+ }
+}
+
+
+void Cell::mergeContent( const CellRef& xSourceCell )
+{
+ SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() );
+
+ if( !xSourceCell->hasText() )
+ return;
+
+ SdrOutliner& rOutliner=rTableObj.ImpGetDrawOutliner();
+ rOutliner.SetUpdateLayout(true);
+
+ if( hasText() )
+ {
+ rOutliner.SetText(*GetOutlinerParaObject());
+ rOutliner.AddText(*xSourceCell->GetOutlinerParaObject());
+ }
+ else
+ {
+ rOutliner.SetText(*xSourceCell->GetOutlinerParaObject());
+ }
+
+ SetOutlinerParaObject( rOutliner.CreateParaObject() );
+ rOutliner.Clear();
+ xSourceCell->SetOutlinerParaObject(rOutliner.CreateParaObject());
+ rOutliner.Clear();
+ SetStyleSheet( GetStyleSheet(), true );
+}
+
+
+void Cell::cloneFrom( const CellRef& xCell )
+{
+ if( xCell.is() )
+ {
+ replaceContentAndFormatting( xCell );
+
+ mnCellContentType = xCell->mnCellContentType;
+
+ msFormula = xCell->msFormula;
+ mfValue = xCell->mfValue;
+ mnError = xCell->mnError;
+
+ mbMerged = xCell->mbMerged;
+ mnRowSpan = xCell->mnRowSpan;
+ mnColSpan = xCell->mnColSpan;
+
+ }
+ notifyModified();
+}
+
+void Cell::replaceContentAndFormatting( const CellRef& xSourceCell )
+{
+ if( !(xSourceCell.is() && mpProperties) )
+ return;
+
+ mpProperties->SetMergedItemSet( xSourceCell->GetObjectItemSet() );
+
+ // tdf#118354 OutlinerParaObject may be nullptr, do not dereference when
+ // not set (!)
+ if(xSourceCell->GetOutlinerParaObject())
+ {
+ SetOutlinerParaObject( *xSourceCell->GetOutlinerParaObject() );
+ }
+
+ SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() );
+ SdrTableObj& rSourceTableObj = dynamic_cast< SdrTableObj& >( xSourceCell->GetObject() );
+
+ if(&rSourceTableObj.getSdrModelFromSdrObject() != &rTableObj.getSdrModelFromSdrObject())
+ {
+ // TTTT should not happen - if, then a clone may be needed
+ // Maybe add an assertion here later
+ SetStyleSheet( nullptr, true );
+ }
+}
+
+
+void Cell::setMerged()
+{
+ if( !mbMerged )
+ {
+ mbMerged = true;
+ notifyModified();
+ }
+}
+
+
+void Cell::copyFormatFrom( const CellRef& xSourceCell )
+{
+ if( !(xSourceCell.is() && mpProperties) )
+ return;
+
+ mpProperties->SetMergedItemSet( xSourceCell->GetObjectItemSet() );
+ SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() );
+ SdrTableObj& rSourceTableObj = dynamic_cast< SdrTableObj& >( xSourceCell->GetObject() );
+
+ if(&rSourceTableObj.getSdrModelFromSdrObject() != &rTableObj.getSdrModelFromSdrObject())
+ {
+ // TTTT should not happen - if, then a clone may be needed
+ // Maybe add an assertion here later
+ SetStyleSheet( nullptr, true );
+ }
+
+ notifyModified();
+}
+
+
+void Cell::notifyModified()
+{
+ if( mxTable.is() )
+ mxTable->setModified( true );
+}
+
+
+// SdrTextShape proxy
+
+
+bool Cell::IsActiveCell() const
+{
+ bool isActive = false;
+ SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() );
+ if( rTableObj.getActiveCell().get() == this )
+ isActive = true;
+
+ return isActive;
+}
+
+bool Cell::IsTextEditActive() const
+{
+ bool isActive = false;
+ SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() );
+ if(rTableObj.getActiveCell().get() == this )
+ {
+ if( rTableObj.CanCreateEditOutlinerParaObject() )
+ {
+ isActive = true;
+ }
+ }
+ return isActive;
+}
+
+
+bool Cell::hasText() const
+{
+ const OutlinerParaObject* pParaObj = GetOutlinerParaObject();
+ if( pParaObj )
+ {
+ const EditTextObject& rTextObj = pParaObj->GetTextObject();
+ if( rTextObj.GetParagraphCount() >= 1 )
+ {
+ if( rTextObj.GetParagraphCount() == 1 )
+ {
+ if( rTextObj.GetText(0).isEmpty() )
+ return false;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Cell::CanCreateEditOutlinerParaObject() const
+{
+ SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() );
+ if( rTableObj.getActiveCell().get() == this )
+ return rTableObj.CanCreateEditOutlinerParaObject();
+ return false;
+}
+
+std::optional<OutlinerParaObject> Cell::CreateEditOutlinerParaObject() const
+{
+ SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() );
+ if( rTableObj.getActiveCell().get() == this )
+ return rTableObj.CreateEditOutlinerParaObject();
+ return std::nullopt;
+}
+
+
+void Cell::SetStyleSheet( SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr )
+{
+ // only allow cell styles for cells
+ if( pStyleSheet && pStyleSheet->GetFamily() != SfxStyleFamily::Frame )
+ return;
+
+ if( mpProperties && (mpProperties->GetStyleSheet() != pStyleSheet) )
+ {
+ mpProperties->SetStyleSheet( pStyleSheet, bDontRemoveHardAttr, true );
+ }
+}
+
+
+const SfxItemSet& Cell::GetObjectItemSet()
+{
+ if( mpProperties )
+ {
+ return mpProperties->GetObjectItemSet();
+ }
+ else
+ {
+ OSL_FAIL("Cell::GetObjectItemSet(), called without properties!");
+ return GetObject().GetObjectItemSet();
+ }
+}
+
+void Cell::SetObjectItem(const SfxPoolItem& rItem)
+{
+ if( mpProperties )
+ {
+ mpProperties->SetObjectItem( rItem );
+ notifyModified();
+ }
+}
+
+void Cell::SetMergedItem(const SfxPoolItem& rItem)
+{
+ SetObjectItem(rItem);
+}
+
+SfxStyleSheet* Cell::GetStyleSheet() const
+{
+ if( mpProperties )
+ return mpProperties->GetStyleSheet();
+ else
+ return nullptr;
+}
+
+void Cell::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
+{
+ rAnchorRect.SetLeft( maCellRect.Left() + GetTextLeftDistance() );
+ rAnchorRect.SetRight( maCellRect.Right() - GetTextRightDistance() );
+ rAnchorRect.SetTop( maCellRect.Top() + GetTextUpperDistance() );
+ rAnchorRect.SetBottom( maCellRect.Bottom() - GetTextLowerDistance() );
+}
+
+
+void Cell::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems)
+{
+ if( mpProperties )
+ {
+ mpProperties->SetMergedItemSetAndBroadcast(rSet, bClearAllItems);
+ notifyModified();
+ }
+}
+
+
+sal_Int32 Cell::calcPreferredWidth( const Size aSize )
+{
+ if ( !hasText() )
+ return getMinimumWidth();
+
+ Outliner& rOutliner=static_cast< SdrTableObj& >( GetObject() ).ImpGetDrawOutliner();
+ rOutliner.SetPaperSize(aSize);
+ rOutliner.SetUpdateLayout(true);
+ ForceOutlinerParaObject( OutlinerMode::TextObject );
+
+ if( GetOutlinerParaObject() )
+ rOutliner.SetText(*GetOutlinerParaObject());
+
+ sal_Int32 nPreferredWidth = const_cast<EditEngine&>(rOutliner.GetEditEngine()).CalcTextWidth();
+ rOutliner.Clear();
+
+ return GetTextLeftDistance() + GetTextRightDistance() + nPreferredWidth;
+}
+
+sal_Int32 Cell::getMinimumWidth() const
+{
+ return GetTextLeftDistance() + GetTextRightDistance() + 100;
+}
+
+
+sal_Int32 Cell::getMinimumHeight()
+{
+ if( !mpProperties )
+ return 0;
+
+ SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() );
+ sal_Int32 nMinimumHeight = 0;
+
+ tools::Rectangle aTextRect;
+ TakeTextAnchorRect( aTextRect );
+ Size aSize( aTextRect.GetSize() );
+ aSize.setHeight(0x0FFFFFFF );
+
+ SdrOutliner* pEditOutliner = rTableObj.GetCellTextEditOutliner( *this );
+ if(pEditOutliner)
+ {
+ pEditOutliner->SetMaxAutoPaperSize(aSize);
+ nMinimumHeight = pEditOutliner->GetTextHeight()+1;
+ }
+ else
+ {
+ Outliner& rOutliner=rTableObj.ImpGetDrawOutliner();
+ rOutliner.SetPaperSize(aSize);
+ rOutliner.SetUpdateLayout(true);
+ ForceOutlinerParaObject( OutlinerMode::TextObject );
+
+ if( GetOutlinerParaObject() )
+ {
+ rOutliner.SetText(*GetOutlinerParaObject());
+ }
+ nMinimumHeight=rOutliner.GetTextHeight()+1;
+ rOutliner.Clear();
+ }
+
+ nMinimumHeight += GetTextUpperDistance() + GetTextLowerDistance();
+ return nMinimumHeight;
+}
+
+
+tools::Long Cell::GetTextLeftDistance() const
+{
+ return GetItemSet().Get(SDRATTR_TEXT_LEFTDIST).GetValue();
+}
+
+
+tools::Long Cell::GetTextRightDistance() const
+{
+ return GetItemSet().Get(SDRATTR_TEXT_RIGHTDIST).GetValue();
+}
+
+
+tools::Long Cell::GetTextUpperDistance() const
+{
+ return GetItemSet().Get(SDRATTR_TEXT_UPPERDIST).GetValue();
+}
+
+
+tools::Long Cell::GetTextLowerDistance() const
+{
+ return GetItemSet().Get(SDRATTR_TEXT_LOWERDIST).GetValue();
+}
+
+
+SdrTextVertAdjust Cell::GetTextVerticalAdjust() const
+{
+ return GetItemSet().Get(SDRATTR_TEXT_VERTADJUST).GetValue();
+}
+
+
+SdrTextHorzAdjust Cell::GetTextHorizontalAdjust() const
+{
+ return GetItemSet().Get(SDRATTR_TEXT_HORZADJUST).GetValue();
+}
+
+
+void Cell::SetOutlinerParaObject( std::optional<OutlinerParaObject> pTextObject )
+{
+ bool bNullTextObject = !pTextObject;
+ SdrText::SetOutlinerParaObject( std::move(pTextObject) );
+ maSelection.nStartPara = EE_PARA_MAX_COUNT;
+
+ if( bNullTextObject )
+ ForceOutlinerParaObject( OutlinerMode::TextObject );
+}
+
+
+void Cell::AddUndo()
+{
+ SdrObject& rObj = GetObject();
+
+ if( rObj.IsInserted() && rObj.getSdrModelFromSdrObject().IsUndoEnabled() )
+ {
+ CellRef xCell( this );
+ rObj.getSdrModelFromSdrObject().AddUndo( std::make_unique<CellUndo>( &rObj, xCell ) );
+
+ // Undo action for the after-text-edit-ended stack.
+ SdrTableObj* pTableObj = dynamic_cast<sdr::table::SdrTableObj*>(&rObj);
+ if (pTableObj && pTableObj->IsTextEditActive())
+ pTableObj->AddUndo(new CellUndo(pTableObj, xCell));
+ }
+}
+
+
+sdr::properties::TextProperties* Cell::CloneProperties( sdr::properties::TextProperties const * pProperties, SdrObject& rNewObj, Cell& rNewCell )
+{
+ if( pProperties )
+ return new sdr::properties::CellProperties( *static_cast<sdr::properties::CellProperties const *>(pProperties), rNewObj, &rNewCell );
+ else
+ return nullptr;
+}
+
+
+sdr::properties::TextProperties* Cell::CloneProperties( SdrObject& rNewObj, Cell& rNewCell )
+{
+ return CloneProperties(mpProperties.get(),rNewObj,rNewCell);
+}
+
+
+// XInterface
+
+
+Any SAL_CALL Cell::queryInterface( const Type & rType )
+{
+ if( rType == cppu::UnoType<XMergeableCell>::get() )
+ return Any( Reference< XMergeableCell >( this ) );
+
+ if( rType == cppu::UnoType<XCell>::get() )
+ return Any( Reference< XCell >( this ) );
+
+ if( rType == cppu::UnoType<XLayoutConstrains>::get() )
+ return Any( Reference< XLayoutConstrains >( this ) );
+
+ if( rType == cppu::UnoType<XEventListener>::get() )
+ return Any( Reference< XEventListener >( this ) );
+
+ Any aRet( SvxUnoTextBase::queryAggregation( rType ) );
+ if( aRet.hasValue() )
+ return aRet;
+
+ return ::cppu::OWeakObject::queryInterface( rType );
+}
+
+
+void SAL_CALL Cell::acquire() noexcept
+{
+ ::cppu::OWeakObject::acquire();
+}
+
+
+void SAL_CALL Cell::release() noexcept
+{
+ ::cppu::OWeakObject::release();
+}
+
+
+// XTypeProvider
+
+
+Sequence< Type > SAL_CALL Cell::getTypes( )
+{
+ return comphelper::concatSequences( SvxUnoTextBase::getTypes(),
+ Sequence {
+ cppu::UnoType<XMergeableCell>::get(),
+ cppu::UnoType<XLayoutConstrains>::get() });
+}
+
+
+Sequence< sal_Int8 > SAL_CALL Cell::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XLayoutConstrains
+css::awt::Size SAL_CALL Cell::getMinimumSize()
+{
+ return css::awt::Size( getMinimumWidth(), getMinimumHeight() );
+}
+
+
+css::awt::Size SAL_CALL Cell::getPreferredSize()
+{
+ return getMinimumSize();
+}
+
+
+css::awt::Size SAL_CALL Cell::calcAdjustedSize( const css::awt::Size& aNewSize )
+{
+ return aNewSize;
+}
+
+
+// XMergeableCell
+
+
+sal_Int32 SAL_CALL Cell::getRowSpan()
+{
+ return mnRowSpan;
+}
+
+
+sal_Int32 SAL_CALL Cell::getColumnSpan()
+{
+ return mnColSpan;
+}
+
+
+sal_Bool SAL_CALL Cell::isMerged()
+{
+ return mbMerged;
+}
+
+
+// XCell
+
+
+OUString SAL_CALL Cell::getFormula( )
+{
+ return msFormula;
+}
+
+
+void SAL_CALL Cell::setFormula( const OUString& aFormula )
+{
+ if( msFormula != aFormula )
+ {
+ msFormula = aFormula;
+ }
+}
+
+
+double SAL_CALL Cell::getValue( )
+{
+ return mfValue;
+}
+
+
+void SAL_CALL Cell::setValue( double nValue )
+{
+ if( mfValue != nValue )
+ {
+ mfValue = nValue;
+ mnCellContentType = CellContentType_VALUE;
+ }
+}
+
+
+CellContentType SAL_CALL Cell::getType()
+{
+ return mnCellContentType;
+}
+
+
+sal_Int32 SAL_CALL Cell::getError( )
+{
+ return mnError;
+}
+
+
+// XPropertySet
+
+
+Any Cell::GetAnyForItem( SfxItemSet const & aSet, const SfxItemPropertyMapEntry* pMap )
+{
+ Any aAny( SvxItemPropertySet_getPropertyValue( pMap, aSet ) );
+
+ if( pMap->aType != aAny.getValueType() )
+ {
+ // since the sfx uint16 item now exports a sal_Int32, we may have to fix this here
+ if( ( pMap->aType == ::cppu::UnoType<sal_Int16>::get()) && aAny.getValueType() == ::cppu::UnoType<sal_Int32>::get() )
+ {
+ sal_Int32 nValue = 0;
+ aAny >>= nValue;
+ aAny <<= static_cast<sal_Int16>(nValue);
+ }
+ else
+ {
+ OSL_FAIL("GetAnyForItem() Returnvalue has wrong Type!" );
+ }
+ }
+
+ return aAny;
+}
+
+Reference< XPropertySetInfo > SAL_CALL Cell::getPropertySetInfo()
+{
+ return mpPropSet->getPropertySetInfo();
+}
+
+
+void SAL_CALL Cell::setPropertyValue( const OUString& rPropertyName, const Any& rValue )
+{
+ ::SolarMutexGuard aGuard;
+
+ if(mpProperties == nullptr)
+ throw DisposedException();
+
+ const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(rPropertyName);
+ if( pMap )
+ {
+ if( (pMap->nFlags & PropertyAttribute::READONLY ) != 0 )
+ throw PropertyVetoException();
+
+ switch( pMap->nWID )
+ {
+ case OWN_ATTR_STYLE:
+ {
+ Reference< XStyle > xStyle;
+ if( !( rValue >>= xStyle ) )
+ throw IllegalArgumentException();
+
+ SfxUnoStyleSheet* pStyle = SfxUnoStyleSheet::getUnoStyleSheet(xStyle);
+ SetStyleSheet( pStyle, true );
+ return;
+ }
+ case OWN_ATTR_TABLEBORDER:
+ {
+ auto pBorder = o3tl::tryAccess<TableBorder>(rValue);
+ if(!pBorder)
+ break;
+
+ SvxBoxItem aBox( SDRATTR_TABLE_BORDER );
+ SvxBoxInfoItem aBoxInfo( SDRATTR_TABLE_BORDER_INNER );
+ SvxBorderLine aLine;
+
+ bool bSet = SvxBoxItem::LineToSvxLine(pBorder->TopLine, aLine, false);
+ aBox.SetLine(bSet ? &aLine : nullptr, SvxBoxItemLine::TOP);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::TOP, pBorder->IsTopLineValid);
+
+ bSet = SvxBoxItem::LineToSvxLine(pBorder->BottomLine, aLine, false);
+ aBox.SetLine(bSet ? &aLine : nullptr, SvxBoxItemLine::BOTTOM);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::BOTTOM, pBorder->IsBottomLineValid);
+
+ bSet = SvxBoxItem::LineToSvxLine(pBorder->LeftLine, aLine, false);
+ aBox.SetLine(bSet ? &aLine : nullptr, SvxBoxItemLine::LEFT);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::LEFT, pBorder->IsLeftLineValid);
+
+ bSet = SvxBoxItem::LineToSvxLine(pBorder->RightLine, aLine, false);
+ aBox.SetLine(bSet ? &aLine : nullptr, SvxBoxItemLine::RIGHT);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::RIGHT, pBorder->IsRightLineValid);
+
+ bSet = SvxBoxItem::LineToSvxLine(pBorder->HorizontalLine, aLine, false);
+ aBoxInfo.SetLine(bSet ? &aLine : nullptr, SvxBoxInfoItemLine::HORI);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI, pBorder->IsHorizontalLineValid);
+
+ bSet = SvxBoxItem::LineToSvxLine(pBorder->VerticalLine, aLine, false);
+ aBoxInfo.SetLine(bSet ? &aLine : nullptr, SvxBoxInfoItemLine::VERT);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT, pBorder->IsVerticalLineValid);
+
+ aBox.SetAllDistances(pBorder->Distance); //TODO
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE, pBorder->IsDistanceValid);
+
+ mpProperties->SetObjectItem(aBox);
+ mpProperties->SetObjectItem(aBoxInfo);
+ return;
+ }
+ case OWN_ATTR_FILLBMP_MODE:
+ {
+ BitmapMode eMode;
+ if(!(rValue >>= eMode) )
+ {
+ sal_Int32 nMode = 0;
+ if(!(rValue >>= nMode))
+ throw IllegalArgumentException();
+
+ eMode = static_cast<BitmapMode>(nMode);
+ }
+
+ mpProperties->SetObjectItem( XFillBmpStretchItem( eMode == BitmapMode_STRETCH ) );
+ mpProperties->SetObjectItem( XFillBmpTileItem( eMode == BitmapMode_REPEAT ) );
+ return;
+ }
+ case SDRATTR_TABLE_TEXT_ROTATION:
+ {
+ sal_Int32 nRotVal = 0;
+ if (!(rValue >>= nRotVal))
+ throw IllegalArgumentException();
+
+ if (nRotVal != 27000 && nRotVal != 9000 && nRotVal != 0)
+ throw IllegalArgumentException();
+
+ mpProperties->SetObjectItem(SvxTextRotateItem(Degree10(nRotVal/10), SDRATTR_TABLE_TEXT_ROTATION));
+ return;
+ }
+ default:
+ {
+ SfxItemSet aSet(GetObject().getSdrModelFromSdrObject().GetItemPool(), pMap->nWID, pMap->nWID);
+ aSet.Put(mpProperties->GetItem(pMap->nWID));
+
+ bool bSpecial = false;
+
+ switch( pMap->nWID )
+ {
+ case XATTR_FILLBITMAP:
+ case XATTR_FILLGRADIENT:
+ case XATTR_FILLHATCH:
+ case XATTR_FILLFLOATTRANSPARENCE:
+ case XATTR_LINEEND:
+ case XATTR_LINESTART:
+ case XATTR_LINEDASH:
+ {
+ if( pMap->nMemberId == MID_NAME )
+ {
+ OUString aApiName;
+ if( rValue >>= aApiName )
+ {
+ if(SvxShape::SetFillAttribute(pMap->nWID, aApiName, aSet, &GetObject().getSdrModelFromSdrObject()))
+ bSpecial = true;
+ }
+ }
+ }
+ break;
+ }
+
+ if( !bSpecial )
+ {
+
+ if( !SvxUnoTextRangeBase::SetPropertyValueHelper( pMap, rValue, aSet ))
+ {
+ if( aSet.GetItemState( pMap->nWID ) != SfxItemState::SET )
+ {
+ // fetch the default from ItemPool
+ if(SfxItemPool::IsWhich(pMap->nWID))
+ aSet.Put(GetObject().getSdrModelFromSdrObject().GetItemPool().GetDefaultItem(pMap->nWID));
+ }
+
+ if( aSet.GetItemState( pMap->nWID ) == SfxItemState::SET )
+ {
+ SvxItemPropertySet_setPropertyValue( pMap, rValue, aSet );
+ }
+ }
+ }
+
+ GetObject().getSdrModelFromSdrObject().SetChanged();
+ mpProperties->SetMergedItemSetAndBroadcast( aSet );
+ return;
+ }
+ }
+ }
+ throw UnknownPropertyException( rPropertyName, static_cast<cppu::OWeakObject*>(this));
+}
+
+
+Any SAL_CALL Cell::getPropertyValue( const OUString& PropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ if(mpProperties == nullptr)
+ throw DisposedException();
+
+ const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName);
+ if( pMap )
+ {
+ switch( pMap->nWID )
+ {
+ case OWN_ATTR_STYLE:
+ {
+ return Any( Reference< XStyle >( dynamic_cast< SfxUnoStyleSheet* >( GetStyleSheet() ) ) );
+ }
+ case OWN_ATTR_TABLEBORDER:
+ {
+ const SvxBoxInfoItem& rBoxInfoItem = mpProperties->GetItem(SDRATTR_TABLE_BORDER_INNER);
+ const SvxBoxItem& rBox = mpProperties->GetItem(SDRATTR_TABLE_BORDER);
+
+ TableBorder aTableBorder;
+ aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), false);
+ aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP);
+ aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), false);
+ aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
+ aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), false);
+ aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT);
+ aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), false);
+ aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT );
+ aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), false);
+ aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI);
+ aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), false);
+ aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT);
+ aTableBorder.Distance = rBox.GetSmallestDistance();
+ aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
+
+ return Any( aTableBorder );
+ }
+ case OWN_ATTR_FILLBMP_MODE:
+ {
+ const XFillBmpStretchItem& rStretchItem = mpProperties->GetItem(XATTR_FILLBMP_STRETCH);
+ const XFillBmpTileItem& rTileItem = mpProperties->GetItem(XATTR_FILLBMP_TILE);
+ if( rTileItem.GetValue() )
+ {
+ return Any( BitmapMode_REPEAT );
+ }
+ else if( rStretchItem.GetValue() )
+ {
+ return Any( BitmapMode_STRETCH );
+ }
+ else
+ {
+ return Any( BitmapMode_NO_REPEAT );
+ }
+ }
+ case SDRATTR_TABLE_TEXT_ROTATION:
+ {
+ const SvxTextRotateItem& rTextRotate = mpProperties->GetItem(SDRATTR_TABLE_TEXT_ROTATION);
+ return Any(sal_Int32(to<Degree100>(rTextRotate.GetValue())));
+ }
+ default:
+ {
+ SfxItemSet aSet(GetObject().getSdrModelFromSdrObject().GetItemPool(), pMap->nWID, pMap->nWID);
+ aSet.Put(mpProperties->GetItem(pMap->nWID));
+
+ Any aAny;
+ if(!SvxUnoTextRangeBase::GetPropertyValueHelper( aSet, pMap, aAny ))
+ {
+ if(!aSet.Count())
+ {
+ // fetch the default from ItemPool
+ if(SfxItemPool::IsWhich(pMap->nWID))
+ aSet.Put(GetObject().getSdrModelFromSdrObject().GetItemPool().GetDefaultItem(pMap->nWID));
+ }
+
+ if( aSet.Count() )
+ aAny = GetAnyForItem( aSet, pMap );
+ }
+
+ return aAny;
+ }
+ }
+ }
+ throw UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+}
+
+
+void SAL_CALL Cell::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ )
+{
+}
+
+
+void SAL_CALL Cell::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*aListener*/ )
+{
+}
+
+
+void SAL_CALL Cell::addVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener >& /*aListener*/ )
+{
+}
+
+
+void SAL_CALL Cell::removeVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener >& /*aListener*/ )
+{
+}
+
+
+// XMultiPropertySet
+
+
+void SAL_CALL Cell::setPropertyValues( const Sequence< OUString >& aPropertyNames, const Sequence< Any >& aValues )
+{
+ ::SolarMutexGuard aSolarGuard;
+
+ if(mpProperties == nullptr)
+ throw DisposedException();
+
+ const sal_Int32 nCount = aPropertyNames.getLength();
+
+ const OUString* pNames = aPropertyNames.getConstArray();
+ const Any* pValues = aValues.getConstArray();
+
+ for( sal_Int32 nIdx = 0; nIdx < nCount; nIdx++, pNames++, pValues++ )
+ {
+ try
+ {
+ setPropertyValue( *pNames, *pValues );
+ }
+ catch( UnknownPropertyException& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "unknown property!");
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+ }
+}
+
+
+Sequence< Any > SAL_CALL Cell::getPropertyValues( const Sequence< OUString >& aPropertyNames )
+{
+ ::SolarMutexGuard aSolarGuard;
+
+ if(mpProperties == nullptr)
+ throw DisposedException();
+
+ const sal_Int32 nCount = aPropertyNames.getLength();
+ Sequence< Any > aRet( nCount );
+ Any* pValue = aRet.getArray();
+
+ for( const OUString& rName : aPropertyNames )
+ {
+ try
+ {
+ *pValue = getPropertyValue( rName );
+ }
+ catch( UnknownPropertyException& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "unknown property!");
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+ pValue++;
+ }
+
+ return aRet;
+}
+
+
+void SAL_CALL Cell::addPropertiesChangeListener( const Sequence< OUString >& /*aPropertyNames*/, const Reference< XPropertiesChangeListener >& /*xListener*/ )
+{
+}
+
+
+void SAL_CALL Cell::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& /*xListener*/ )
+{
+}
+
+
+void SAL_CALL Cell::firePropertiesChangeEvent( const Sequence< OUString >& /*aPropertyNames*/, const Reference< XPropertiesChangeListener >& /*xListener*/ )
+{
+}
+
+
+// XPropertyState
+
+
+PropertyState SAL_CALL Cell::getPropertyState( const OUString& PropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ if(mpProperties == nullptr)
+ throw DisposedException();
+
+ const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName);
+
+ if( pMap )
+ {
+ PropertyState eState;
+ switch( pMap->nWID )
+ {
+ case OWN_ATTR_FILLBMP_MODE:
+ {
+ const SfxItemSet& rSet = mpProperties->GetMergedItemSet();
+
+ const bool bStretch = rSet.GetItemState( XATTR_FILLBMP_STRETCH, false ) == SfxItemState::SET;
+ const bool bTile = rSet.GetItemState( XATTR_FILLBMP_TILE, false ) == SfxItemState::SET;
+ if( bStretch || bTile )
+ {
+ eState = PropertyState_DIRECT_VALUE;
+ }
+ else
+ {
+ eState = PropertyState_DEFAULT_VALUE;
+ }
+ break;
+ }
+ case OWN_ATTR_STYLE:
+ {
+ return PropertyState_DIRECT_VALUE;
+ }
+ case OWN_ATTR_TABLEBORDER:
+ {
+ const SfxItemSet& rSet = mpProperties->GetMergedItemSet();
+ if( (rSet.GetItemState( SDRATTR_TABLE_BORDER_INNER, false ) == SfxItemState::DEFAULT) && (rSet.GetItemState( SDRATTR_TABLE_BORDER, false ) == SfxItemState::DEFAULT) )
+ return PropertyState_DEFAULT_VALUE;
+
+ return PropertyState_DIRECT_VALUE;
+ }
+ default:
+ {
+ const SfxItemSet& rSet = mpProperties->GetMergedItemSet();
+
+ switch( rSet.GetItemState( pMap->nWID, false ) )
+ {
+ case SfxItemState::SET:
+ eState = PropertyState_DIRECT_VALUE;
+ break;
+ case SfxItemState::DEFAULT:
+ eState = PropertyState_DEFAULT_VALUE;
+ break;
+ default:
+ eState = PropertyState_AMBIGUOUS_VALUE;
+ break;
+ }
+
+ // if an item is set, this doesn't mean we want it :)
+ if( PropertyState_DIRECT_VALUE == eState )
+ {
+ switch( pMap->nWID )
+ {
+ // the following items are disabled by changing the
+ // fill style or the line style. so there is no need
+ // to export items without names which should be empty
+ case XATTR_FILLBITMAP:
+ case XATTR_FILLGRADIENT:
+ case XATTR_FILLHATCH:
+ case XATTR_LINEDASH:
+ {
+ const NameOrIndex* pItem = rSet.GetItem<NameOrIndex>(pMap->nWID);
+ if( ( pItem == nullptr ) || pItem->GetName().isEmpty() )
+ eState = PropertyState_DEFAULT_VALUE;
+ }
+ break;
+
+ // #i36115#
+ // If e.g. the LineStart is on NONE and thus the string has length 0, it still
+ // may be a hard attribute covering the set LineStart of the parent (Style).
+ // #i37644#
+ // same is for fill float transparency
+ case XATTR_LINEEND:
+ case XATTR_LINESTART:
+ case XATTR_FILLFLOATTRANSPARENCE:
+ {
+ const NameOrIndex* pItem = rSet.GetItem<NameOrIndex>(pMap->nWID);
+ if( pItem == nullptr )
+ eState = PropertyState_DEFAULT_VALUE;
+ }
+ break;
+ case XATTR_FILLCOLOR:
+ if (pMap->nMemberId == MID_COLOR_THEME_INDEX)
+ {
+ const XFillColorItem* pColor = rSet.GetItem<XFillColorItem>(pMap->nWID);
+ if (pColor->GetThemeColor().GetThemeIndex() == -1)
+ {
+ eState = PropertyState_DEFAULT_VALUE;
+ }
+ }
+ else if (pMap->nMemberId == MID_COLOR_LUM_MOD)
+ {
+ const XFillColorItem* pColor = rSet.GetItem<XFillColorItem>(pMap->nWID);
+ if (pColor->GetThemeColor().GetLumMod() == 10000)
+ {
+ eState = PropertyState_DEFAULT_VALUE;
+ }
+ }
+ else if (pMap->nMemberId == MID_COLOR_LUM_OFF)
+ {
+ const XFillColorItem* pColor = rSet.GetItem<XFillColorItem>(pMap->nWID);
+ if (pColor->GetThemeColor().GetLumOff() == 0)
+ {
+ eState = PropertyState_DEFAULT_VALUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ return eState;
+ }
+ throw UnknownPropertyException(PropertyName);
+}
+
+
+Sequence< PropertyState > SAL_CALL Cell::getPropertyStates( const Sequence< OUString >& aPropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ if(mpProperties == nullptr)
+ throw DisposedException();
+
+ const sal_Int32 nCount = aPropertyName.getLength();
+ Sequence< PropertyState > aRet( nCount );
+
+ std::transform(aPropertyName.begin(), aPropertyName.end(), aRet.getArray(),
+ [this](const OUString& rName) -> PropertyState {
+ try
+ {
+ return getPropertyState( rName );
+ }
+ catch( Exception& )
+ {
+ return PropertyState_AMBIGUOUS_VALUE;
+ }
+ });
+
+ return aRet;
+}
+
+
+void SAL_CALL Cell::setPropertyToDefault( const OUString& PropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ if(mpProperties == nullptr)
+ throw DisposedException();
+
+ const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName);
+ if( pMap )
+ {
+ switch( pMap->nWID )
+ {
+ case OWN_ATTR_FILLBMP_MODE:
+ {
+ mpProperties->ClearObjectItem( XATTR_FILLBMP_STRETCH );
+ mpProperties->ClearObjectItem( XATTR_FILLBMP_TILE );
+ break;
+ }
+ case OWN_ATTR_STYLE:
+ break;
+
+ case OWN_ATTR_TABLEBORDER:
+ {
+ mpProperties->ClearObjectItem( SDRATTR_TABLE_BORDER_INNER );
+ mpProperties->ClearObjectItem( SDRATTR_TABLE_BORDER );
+ break;
+ }
+
+ default:
+ {
+ mpProperties->ClearObjectItem( pMap->nWID );
+ }
+ }
+
+ GetObject().getSdrModelFromSdrObject().SetChanged();
+ return;
+ }
+ throw UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+}
+
+
+Any SAL_CALL Cell::getPropertyDefault( const OUString& aPropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ if(mpProperties == nullptr)
+ throw DisposedException();
+
+ const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(aPropertyName);
+ if( pMap )
+ {
+ switch( pMap->nWID )
+ {
+ case OWN_ATTR_FILLBMP_MODE:
+ return Any( BitmapMode_NO_REPEAT );
+
+ case OWN_ATTR_STYLE:
+ {
+ Reference< XStyle > xStyle;
+ return Any( xStyle );
+ }
+
+ case OWN_ATTR_TABLEBORDER:
+ {
+ TableBorder aBorder;
+ return Any( aBorder );
+ }
+
+ default:
+ {
+ if( SfxItemPool::IsWhich(pMap->nWID) )
+ {
+ SfxItemSet aSet(GetObject().getSdrModelFromSdrObject().GetItemPool(), pMap->nWID, pMap->nWID);
+ aSet.Put(GetObject().getSdrModelFromSdrObject().GetItemPool().GetDefaultItem(pMap->nWID));
+ return GetAnyForItem( aSet, pMap );
+ }
+ }
+ }
+ }
+ throw UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+}
+
+
+// XMultiPropertyStates
+
+
+void SAL_CALL Cell::setAllPropertiesToDefault()
+{
+ mpProperties.reset(new sdr::properties::CellProperties( static_cast< SdrTableObj& >( GetObject() ), this ));
+
+ SdrOutliner& rOutliner = GetObject().ImpGetDrawOutliner();
+
+ OutlinerParaObject* pParaObj = GetOutlinerParaObject();
+ if( !pParaObj )
+ return;
+
+ rOutliner.SetText(*pParaObj);
+ sal_Int32 nParaCount(rOutliner.GetParagraphCount());
+
+ if(nParaCount)
+ {
+ ESelection aSelection( 0, 0, EE_PARA_ALL, EE_TEXTPOS_ALL);
+ rOutliner.RemoveAttribs(aSelection, true, 0);
+
+ std::optional<OutlinerParaObject> pTemp = rOutliner.CreateParaObject(0, nParaCount);
+ rOutliner.Clear();
+
+ SetOutlinerParaObject(std::move(pTemp));
+ }
+}
+
+
+void SAL_CALL Cell::setPropertiesToDefault( const Sequence< OUString >& aPropertyNames )
+{
+ for(const OUString& rName : aPropertyNames)
+ setPropertyToDefault( rName );
+}
+
+
+Sequence< Any > SAL_CALL Cell::getPropertyDefaults( const Sequence< OUString >& aPropertyNames )
+{
+ sal_Int32 nCount = aPropertyNames.getLength();
+ Sequence< Any > aDefaults( nCount );
+
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aDefaults.getArray(),
+ [this](const OUString& rName) -> Any { return getPropertyDefault(rName); });
+
+ return aDefaults;
+}
+
+
+// XText
+
+
+void SAL_CALL Cell::insertTextContent( const Reference< XTextRange >& xRange, const Reference< XTextContent >& xContent, sal_Bool bAbsorb )
+{
+ SvxUnoTextBase::insertTextContent( xRange, xContent, bAbsorb );
+ notifyModified();
+}
+
+
+void SAL_CALL Cell::removeTextContent( const Reference< XTextContent >& xContent )
+{
+ SvxUnoTextBase::removeTextContent( xContent );
+ notifyModified();
+}
+
+
+// XSimpleText
+
+
+void SAL_CALL Cell::insertString( const Reference< XTextRange >& xRange, const OUString& aString, sal_Bool bAbsorb )
+{
+ SvxUnoTextBase::insertString( xRange, aString, bAbsorb );
+ notifyModified();
+}
+
+
+void SAL_CALL Cell::insertControlCharacter( const Reference< XTextRange >& xRange, sal_Int16 nControlCharacter, sal_Bool bAbsorb )
+{
+ SvxUnoTextBase::insertControlCharacter( xRange, nControlCharacter, bAbsorb );
+ notifyModified();
+}
+
+
+// XTextRange
+
+
+OUString SAL_CALL Cell::getString( )
+{
+ maSelection.nStartPara = EE_PARA_MAX_COUNT;
+ return SvxUnoTextBase::getString();
+}
+
+
+void SAL_CALL Cell::setString( const OUString& aString )
+{
+ SvxUnoTextBase::setString( aString );
+ notifyModified();
+}
+
+// XEventListener
+void SAL_CALL Cell::disposing( const EventObject& /*Source*/ )
+{
+ mxTable.clear();
+ dispose();
+}
+
+void Cell::dumpAsXml(xmlTextWriterPtr pWriter, sal_Int32 nRow, sal_Int32 nCol) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("Cell"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("row"), "%" SAL_PRIdINT32, nRow);
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("col"), "%" SAL_PRIdINT32, nCol);
+ SdrText::dumpAsXml(pWriter);
+ //SvxUnoTextBase::dumpAsXml(pWriter);
+ //mpPropSet->dumpAsXml(pWriter);
+ mpProperties->dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/cellcursor.cxx b/svx/source/table/cellcursor.cxx
new file mode 100644
index 000000000..313ec63df
--- /dev/null
+++ b/svx/source/table/cellcursor.cxx
@@ -0,0 +1,546 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <svx/svdotable.hxx>
+#include "cellcursor.hxx"
+#include "tablelayouter.hxx"
+#include <cell.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::table;
+
+
+namespace sdr::table {
+
+CellCursor::CellCursor( const TableModelRef & xTable, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+: CellCursorBase( xTable, nLeft, nTop, nRight, nBottom )
+{
+}
+
+
+CellCursor::~CellCursor()
+{
+}
+
+
+// XCellCursor
+
+
+Reference< XCell > SAL_CALL CellCursor::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow )
+{
+ return CellRange::getCellByPosition( nColumn, nRow );
+}
+
+
+Reference< XCellRange > SAL_CALL CellCursor::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ return CellRange::getCellRangeByPosition( nLeft, nTop, nRight, nBottom );
+}
+
+
+Reference< XCellRange > SAL_CALL CellCursor::getCellRangeByName( const OUString& aRange )
+{
+ return CellRange::getCellRangeByName( aRange );
+}
+
+
+// XCellCursor
+
+
+void SAL_CALL CellCursor::gotoStart( )
+{
+ mnRight = mnLeft;
+ mnBottom = mnTop;
+}
+
+
+void SAL_CALL CellCursor::gotoEnd( )
+{
+ mnLeft = mnRight;
+ mnTop = mnBottom;
+}
+
+
+void SAL_CALL CellCursor::gotoNext( )
+{
+ if( mxTable.is() )
+ {
+ mnRight++;
+ if( mnRight >= mxTable->getColumnCount() )
+ {
+ // if we past the last column, try skip to the row line
+ mnTop++;
+ if( mnTop >= mxTable->getRowCount() )
+ {
+ // if we past the last row, do not move cursor at all
+ mnTop--;
+ mnRight--;
+ }
+ else
+ {
+ // restart at the first column on the next row
+ mnRight = 0;
+ }
+ }
+ }
+
+ mnLeft = mnRight;
+ mnTop = mnBottom;
+}
+
+
+void SAL_CALL CellCursor::gotoPrevious( )
+{
+ if( mxTable.is() )
+ {
+ if( mnLeft > 0 )
+ {
+ --mnLeft;
+ }
+ else if( mnTop > 0 )
+ {
+ --mnTop;
+ mnLeft = mxTable->getColumnCount() - 1;
+ }
+ }
+
+ mnRight = mnLeft;
+ mnBottom = mnTop;
+}
+
+
+void SAL_CALL CellCursor::gotoOffset( ::sal_Int32 nColumnOffset, ::sal_Int32 nRowOffset )
+{
+ if( mxTable.is() )
+ {
+ const sal_Int32 nLeft = mnLeft + nColumnOffset;
+ if( (nLeft >= 0) && (nLeft < mxTable->getColumnCount() ) )
+ mnRight = mnLeft = nLeft;
+
+ const sal_Int32 nTop = mnTop + nRowOffset;
+ if( (nTop >= 0) && (nTop < mxTable->getRowCount()) )
+ mnTop = mnBottom = nTop;
+ }
+}
+
+
+// XMergeableCellCursor
+
+
+/** returns true and the merged cell positions if a merge is valid or false if a merge is
+ not valid for that range */
+bool CellCursor::GetMergedSelection( CellPos& rStart, CellPos& rEnd )
+{
+ rStart.mnCol = mnLeft; rStart.mnRow = mnTop;
+ rEnd.mnCol = mnRight; rEnd.mnRow = mnBottom;
+
+ // single cell merge is never valid
+ if( mxTable.is() && ((mnLeft != mnRight) || (mnTop != mnBottom)) ) try
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( mnLeft, mnTop ).get() ) );
+
+ // check if first cell is merged
+ if( xCell.is() && xCell->isMerged() )
+ findMergeOrigin( mxTable, mnLeft, mnTop, rStart.mnCol, rStart.mnRow );
+
+ // check if last cell is merged
+ xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( mnRight, mnBottom ).get() ) );
+ if( xCell.is() )
+ {
+ if( xCell->isMerged() )
+ {
+ findMergeOrigin( mxTable, mnRight, mnBottom, rEnd.mnCol, rEnd.mnRow );
+ // merge not possible if selection is only one cell and all its merges
+ if( rEnd == rStart )
+ return false;
+ xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rEnd.mnCol, rEnd.mnRow ).get() ) );
+ }
+ }
+ if( xCell.is() )
+ {
+ rEnd.mnCol += xCell->getColumnSpan()-1;
+ rEnd.mnRow += xCell->getRowSpan()-1;
+ }
+
+ // now check if everything is inside the given bounds
+ sal_Int32 nRow, nCol;
+ for( nRow = rStart.mnRow; nRow <= rEnd.mnRow; nRow++ )
+ {
+ for( nCol = rStart.mnCol; nCol <= rEnd.mnCol; nCol++ )
+ {
+ xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( !xCell.is() )
+ continue;
+
+ if( xCell->isMerged() )
+ {
+ sal_Int32 nOriginCol, nOriginRow;
+ if( findMergeOrigin( mxTable, nCol, nRow, nOriginCol, nOriginRow ) )
+ {
+ if( (nOriginCol < rStart.mnCol) || (nOriginRow < rStart.mnRow) )
+ return false;
+
+ xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( nOriginCol, nOriginRow ).get() ) );
+ if( xCell.is() )
+ {
+ nOriginCol += xCell->getColumnSpan()-1;
+ nOriginRow += xCell->getRowSpan()-1;
+
+ if( (nOriginCol > rEnd.mnCol) || (nOriginRow > rEnd.mnRow) )
+ return false;
+ }
+ }
+ }
+ else if( ((nCol + xCell->getColumnSpan() - 1) > rEnd.mnCol) || ((nRow + xCell->getRowSpan() - 1 ) > rEnd.mnRow) )
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+ return false;
+}
+
+
+void SAL_CALL CellCursor::merge( )
+{
+ CellPos aStart, aEnd;
+ if( !GetMergedSelection( aStart, aEnd ) )
+ throw NoSupportException();
+
+ if( !mxTable.is() || (mxTable->getSdrTableObj() == nullptr) )
+ throw DisposedException();
+
+ SdrModel& rModel(mxTable->getSdrTableObj()->getSdrModelFromSdrObject());
+ const bool bUndo(mxTable->getSdrTableObj()->IsInserted() && rModel.IsUndoEnabled());
+
+ if( bUndo )
+ rModel.BegUndo( SvxResId(STR_TABLE_MERGE) );
+
+ try
+ {
+ mxTable->merge( aStart.mnCol, aStart.mnRow, aEnd.mnCol - aStart.mnCol + 1, aEnd.mnRow - aStart.mnRow + 1 );
+ mxTable->optimize();
+ mxTable->setModified(true);
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+
+ if( bUndo )
+ rModel.EndUndo();
+
+ rModel.SetChanged();
+}
+
+
+void CellCursor::split_column( sal_Int32 nCol, sal_Int32 nColumns, std::vector< sal_Int32 >& rLeftOvers )
+{
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+
+ sal_Int32 nNewCols = 0, nRow;
+
+ // first check how many columns we need to add
+ for( nRow = mnTop; nRow <= mnBottom; ++nRow )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xCell.is() && !xCell->isMerged() )
+ nNewCols = std::max( nNewCols, nColumns - xCell->getColumnSpan() + 1 - rLeftOvers[nRow] );
+ }
+
+ if( nNewCols > 0 )
+ {
+ static const OUStringLiteral sWidth(u"Width");
+ Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_SET_THROW );
+ Reference< XPropertySet > xRefColumn( xCols->getByIndex( nCol ), UNO_QUERY_THROW );
+ sal_Int32 nWidth = 0;
+ xRefColumn->getPropertyValue( sWidth ) >>= nWidth;
+ const sal_Int32 nNewWidth = nWidth / (nNewCols + 1);
+
+ // reference column gets new width + rounding errors
+ xRefColumn->setPropertyValue( sWidth, Any( nWidth - (nNewWidth * nNewCols) ) );
+
+ xCols->insertByIndex( nCol + 1, nNewCols );
+ mnRight += nNewCols;
+
+ // distribute new width
+ for( sal_Int32 nNewCol = nCol + nNewCols; nNewCol > nCol; --nNewCol )
+ {
+ Reference< XPropertySet > xNewCol( xCols->getByIndex( nNewCol ), UNO_QUERY_THROW );
+ xNewCol->setPropertyValue( sWidth, Any( nNewWidth ) );
+ }
+ }
+
+ for( nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( !xCell.is() || xCell->isMerged() )
+ {
+ if( nNewCols > 0 )
+ {
+ // merged cells are ignored, but newly added columns will be added to leftovers
+ xCell.set( dynamic_cast< Cell* >(mxTable->getCellByPosition( nCol+1, nRow ).get() ) );
+ if( !xCell.is() || !xCell->isMerged() )
+ rLeftOvers[nRow] += nNewCols;
+ }
+ }
+ else
+ {
+ sal_Int32 nRowSpan = xCell->getRowSpan() - 1;
+ sal_Int32 nColSpan = xCell->getColumnSpan() - 1;
+
+ if( (nRow >= mnTop) && (nRow <= mnBottom) )
+ {
+ sal_Int32 nCellsAvailable = 1 + nColSpan + rLeftOvers[nRow];
+ if( nColSpan == 0 )
+ nCellsAvailable += nNewCols;
+
+ DBG_ASSERT( nCellsAvailable > nColumns, "sdr::table::CellCursor::split_column(), somethings wrong" );
+
+ sal_Int32 nSplitSpan = (nCellsAvailable / (nColumns + 1)) - 1;
+
+ sal_Int32 nSplitCol = nCol;
+ sal_Int32 nSplits = nColumns + 1;
+ while( nSplits-- )
+ {
+ // last split eats rounding cells
+ if( nSplits == 0 )
+ nSplitSpan = nCellsAvailable - ((nSplitSpan+1) * nColumns) - 1;
+
+ mxTable->merge( nSplitCol, nRow, nSplitSpan + 1, nRowSpan + 1);
+ if( nSplits > 0 )
+ nSplitCol += nSplitSpan + 1;
+ }
+
+ do
+ {
+ rLeftOvers[nRow++] = 0;
+ }
+ while( nRowSpan-- );
+ --nRow;
+ }
+ else
+ {
+ // cope with outside cells, merge if needed
+ if( nColSpan < (rLeftOvers[nRow] + nNewCols) )
+ mxTable->merge( nCol, nRow, (rLeftOvers[nRow] + nNewCols) + 1, nRowSpan + 1 );
+
+ do
+ {
+ rLeftOvers[nRow++] = 0; // consumed
+ }
+ while( nRowSpan-- );
+ --nRow;
+ }
+ }
+ }
+}
+
+
+void CellCursor::split_horizontal( sal_Int32 nColumns )
+{
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+
+ std::vector< sal_Int32 > aLeftOvers( nRowCount );
+
+ for( sal_Int32 nCol = mnRight; nCol >= mnLeft; --nCol )
+ split_column( nCol, nColumns, aLeftOvers );
+}
+
+
+void CellCursor::split_row( sal_Int32 nRow, sal_Int32 nRows, std::vector< sal_Int32 >& rLeftOvers )
+{
+ const sal_Int32 nColCount = mxTable->getColumnCount();
+
+ sal_Int32 nNewRows = 0, nCol;
+
+ // first check how many columns we need to add
+ for( nCol = mnLeft; nCol <= mnRight; ++nCol )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xCell.is() && !xCell->isMerged() )
+ nNewRows = std::max( nNewRows, nRows - xCell->getRowSpan() + 1 - rLeftOvers[nCol] );
+ }
+
+ if( nNewRows > 0 )
+ {
+ static const OUStringLiteral sHeight(u"Height");
+ Reference< XTableRows > xRows( mxTable->getRows(), UNO_SET_THROW );
+ Reference< XPropertySet > xRefRow( xRows->getByIndex( nRow ), UNO_QUERY_THROW );
+ sal_Int32 nHeight = 0;
+ xRefRow->getPropertyValue( sHeight ) >>= nHeight;
+ const sal_Int32 nNewHeight = nHeight / (nNewRows + 1);
+
+ // reference row gets new height + rounding errors
+ xRefRow->setPropertyValue( sHeight, Any( nHeight - (nNewHeight * nNewRows) ) );
+
+ xRows->insertByIndex( nRow + 1, nNewRows );
+ mnBottom += nNewRows;
+
+ // distribute new width
+ for( sal_Int32 nNewRow = nRow + nNewRows; nNewRow > nRow; --nNewRow )
+ {
+ Reference< XPropertySet > xNewRow( xRows->getByIndex( nNewRow ), UNO_QUERY_THROW );
+ xNewRow->setPropertyValue( sHeight, Any( nNewHeight ) );
+ }
+ }
+
+ for( nCol = 0; nCol < nColCount; ++nCol )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( !xCell.is() || xCell->isMerged() )
+ {
+ if( nNewRows )
+ {
+ // merged cells are ignored, but newly added columns will be added to leftovers
+ xCell.set( dynamic_cast< Cell* >(mxTable->getCellByPosition( nCol, nRow+1 ).get() ) );
+ if( !xCell.is() || !xCell->isMerged() )
+ rLeftOvers[nCol] += nNewRows;
+ }
+ }
+ else
+ {
+ sal_Int32 nRowSpan = xCell->getRowSpan() - 1;
+ sal_Int32 nColSpan = xCell->getColumnSpan() - 1;
+
+ if( (nCol >= mnLeft) && (nCol <= mnRight) )
+ {
+ sal_Int32 nCellsAvailable = 1 + nRowSpan + rLeftOvers[nCol];
+ if( nRowSpan == 0 )
+ nCellsAvailable += nNewRows;
+
+ DBG_ASSERT( nCellsAvailable > nRows, "sdr::table::CellCursor::split_row(), somethings wrong" );
+
+ sal_Int32 nSplitSpan = (nCellsAvailable / (nRows + 1)) - 1;
+
+ sal_Int32 nSplitRow = nRow;
+ sal_Int32 nSplits = nRows + 1;
+ while( nSplits-- )
+ {
+ // last split eats rounding cells
+ if( nSplits == 0 )
+ nSplitSpan = nCellsAvailable - ((nSplitSpan+1) * nRows) - 1;
+
+ mxTable->merge( nCol, nSplitRow, nColSpan + 1, nSplitSpan + 1 );
+ if( nSplits > 0 )
+ nSplitRow += nSplitSpan + 1;
+ }
+
+ do
+ {
+ rLeftOvers[nCol++] = 0;
+ }
+ while( nColSpan-- );
+ --nCol;
+ }
+ else
+ {
+ // cope with outside cells, merge if needed
+ if( nRowSpan < (rLeftOvers[nCol] + nNewRows) )
+ mxTable->merge( nCol, nRow, nColSpan + 1, (rLeftOvers[nCol] + nNewRows) + 1 );
+
+ do
+ {
+ rLeftOvers[nCol++] = 0; // consumed
+ }
+ while( nColSpan-- );
+ --nCol;
+ }
+ }
+ }
+}
+
+
+void CellCursor::split_vertical( sal_Int32 nRows )
+{
+ const sal_Int32 nColCount = mxTable->getColumnCount();
+
+ std::vector< sal_Int32 > aLeftOvers( nColCount );
+
+ for( sal_Int32 nRow = mnBottom; nRow >= mnTop; --nRow )
+ split_row( nRow, nRows, aLeftOvers );
+}
+
+
+void SAL_CALL CellCursor::split( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ if( (nColumns < 0) || (nRows < 0) )
+ throw IllegalArgumentException();
+
+ if( !mxTable.is() || (mxTable->getSdrTableObj() == nullptr) )
+ throw DisposedException();
+
+ SdrModel& rModel(mxTable->getSdrTableObj()->getSdrModelFromSdrObject());
+ const bool bUndo(mxTable->getSdrTableObj()->IsInserted() && rModel.IsUndoEnabled());
+
+ if( bUndo )
+ rModel.BegUndo( SvxResId(STR_TABLE_SPLIT) );
+
+ try
+ {
+ if( nColumns > 0 )
+ split_horizontal( nColumns );
+
+ if( nRows > 0 )
+ split_vertical( nRows );
+
+ if( nColumns > 0 ||nRows > 0 )
+ mxTable->setModified(true);
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ throw NoSupportException();
+ }
+
+ if( bUndo )
+ rModel.EndUndo();
+
+ rModel.SetChanged();
+}
+
+
+sal_Bool SAL_CALL CellCursor::isMergeable( )
+{
+ CellPos aStart, aEnd;
+ return GetMergedSelection( aStart, aEnd );
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/cellcursor.hxx b/svx/source/table/cellcursor.hxx
new file mode 100644
index 000000000..e6756c926
--- /dev/null
+++ b/svx/source/table/cellcursor.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_CELLCURSOR_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_CELLCURSOR_HXX
+
+#include <com/sun/star/table/XMergeableCellRange.hpp>
+#include <com/sun/star/table/XCellCursor.hpp>
+#include <cppuhelper/implbase.hxx>
+#include "cellrange.hxx"
+
+
+namespace sdr::table {
+
+struct CellPos;
+
+typedef ::cppu::ImplInheritanceHelper< CellRange, css::table::XCellCursor, css::table::XMergeableCellRange > CellCursorBase;
+
+class CellCursor final : public CellCursorBase
+{
+public:
+ CellCursor( const TableModelRef& xTableModel, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom );
+ virtual ~CellCursor() override;
+
+ // XCellRange
+ virtual css::uno::Reference< css::table::XCell > SAL_CALL getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) override;
+ virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) override;
+ virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByName( const OUString& aRange ) override;
+
+ // XCellCursor
+ virtual void SAL_CALL gotoStart( ) override;
+ virtual void SAL_CALL gotoEnd( ) override;
+ virtual void SAL_CALL gotoNext( ) override;
+ virtual void SAL_CALL gotoPrevious( ) override;
+ virtual void SAL_CALL gotoOffset( ::sal_Int32 nColumnOffset, ::sal_Int32 nRowOffset ) override;
+
+ // XMergeableCellRange
+ virtual void SAL_CALL merge( ) override;
+ virtual void SAL_CALL split( ::sal_Int32 Columns, ::sal_Int32 Rows ) override;
+ virtual sal_Bool SAL_CALL isMergeable( ) override;
+
+private:
+ bool GetMergedSelection( CellPos& rStart, CellPos& rEnd );
+
+ void split_column( sal_Int32 nCol, sal_Int32 nColumns, std::vector< sal_Int32 >& rLeftOvers );
+ void split_horizontal( sal_Int32 nColumns );
+ void split_row( sal_Int32 nRow, sal_Int32 nRows, std::vector< sal_Int32 >& rLeftOvers );
+ void split_vertical( sal_Int32 nRows );
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/cellrange.cxx b/svx/source/table/cellrange.cxx
new file mode 100644
index 000000000..f9941fd24
--- /dev/null
+++ b/svx/source/table/cellrange.cxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include "cellrange.hxx"
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::table;
+
+
+namespace sdr::table {
+
+CellRange::CellRange( const TableModelRef & xTable, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+: mxTable( xTable )
+, mnLeft(nLeft)
+, mnTop(nTop)
+, mnRight(nRight)
+, mnBottom(nBottom)
+{
+}
+
+
+CellRange::~CellRange()
+{
+}
+
+
+// ICellRange
+
+
+sal_Int32 CellRange::getLeft()
+{
+ return mnLeft;
+}
+
+sal_Int32 CellRange::getTop()
+{
+ return mnTop;
+}
+
+sal_Int32 CellRange::getRight()
+{
+ return mnRight;
+}
+
+sal_Int32 CellRange::getBottom()
+{
+ return mnBottom;
+}
+
+Reference< XTable > CellRange::getTable()
+{
+ return mxTable;
+}
+
+
+// XCellRange
+
+
+Reference< XCell > SAL_CALL CellRange::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow )
+{
+ return mxTable->getCellByPosition( mnLeft + nColumn, mnTop + nRow );
+}
+
+
+Reference< XCellRange > SAL_CALL CellRange::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ if( (nLeft >= 0 ) && (nTop >= 0) && (nRight >= nLeft) && (nBottom >= nTop) )
+ {
+ nLeft += mnLeft;
+ nTop += mnTop;
+ nRight += mnLeft;
+ nBottom += mnTop;
+
+ const sal_Int32 nMaxColumns = (mnRight == -1) ? mxTable->getColumnCount() : mnLeft;
+ const sal_Int32 nMaxRows = (mnBottom == -1) ? mxTable->getRowCount() : mnBottom;
+ if( (nLeft < nMaxColumns) && (nRight < nMaxColumns) && (nTop < nMaxRows) && (nBottom < nMaxRows) )
+ {
+ return mxTable->getCellRangeByPosition( nLeft, nTop, nRight, nBottom );
+ }
+ }
+ throw IndexOutOfBoundsException();
+}
+
+
+Reference< XCellRange > SAL_CALL CellRange::getCellRangeByName( const OUString& /*aRange*/ )
+{
+ return Reference< XCellRange >();
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/cellrange.hxx b/svx/source/table/cellrange.hxx
new file mode 100644
index 000000000..b4802eff0
--- /dev/null
+++ b/svx/source/table/cellrange.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_CELLRANGE_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_CELLRANGE_HXX
+
+#include <com/sun/star/table/XCellRange.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+#include <tablemodel.hxx>
+
+
+namespace sdr::table {
+
+class CellRange : public ::cppu::WeakAggImplHelper1< css::table::XCellRange >, public ICellRange
+{
+public:
+ CellRange( const TableModelRef & xTable, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom );
+ virtual ~CellRange() override;
+
+ // ICellRange
+ virtual sal_Int32 getLeft() override;
+ virtual sal_Int32 getTop() override;
+ virtual sal_Int32 getRight() override;
+ virtual sal_Int32 getBottom() override;
+ virtual css::uno::Reference< css::table::XTable > getTable() override;
+
+ // XCellRange
+ virtual css::uno::Reference< css::table::XCell > SAL_CALL getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) override;
+ virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) override;
+ virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByName( const OUString& aRange ) override;
+
+protected:
+ TableModelRef mxTable;
+ sal_Int32 mnLeft;
+ sal_Int32 mnTop;
+ sal_Int32 mnRight;
+ sal_Int32 mnBottom;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/propertyset.cxx b/svx/source/table/propertyset.cxx
new file mode 100644
index 000000000..0dc90358c
--- /dev/null
+++ b/svx/source/table/propertyset.cxx
@@ -0,0 +1,206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "propertyset.hxx"
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+
+namespace sdr::table {
+
+FastPropertySetInfo::FastPropertySetInfo( const PropertyVector& rProps )
+{
+ addProperties( rProps );
+}
+
+
+FastPropertySetInfo::~FastPropertySetInfo()
+{
+}
+
+
+void FastPropertySetInfo::addProperties( const PropertyVector& rProps )
+{
+ sal_uInt32 nIndex = maProperties.size();
+ sal_uInt32 nCount = rProps.size();
+ maProperties.resize( nIndex + nCount );
+ for( const Property& rProperty : rProps )
+ {
+ maProperties[nIndex] = rProperty;
+ maMap[ rProperty.Name ] = nIndex++;
+ }
+}
+
+
+const Property& FastPropertySetInfo::getProperty( const OUString& aName )
+{
+ PropertyMap::iterator aIter( maMap.find( aName ) );
+ if( aIter == maMap.end() )
+ throw UnknownPropertyException( aName, static_cast<cppu::OWeakObject*>(this));
+ return maProperties[(*aIter).second];
+}
+
+
+const Property* FastPropertySetInfo::hasProperty( const OUString& aName )
+{
+ PropertyMap::iterator aIter( maMap.find( aName ) );
+ if( aIter == maMap.end() )
+ return nullptr;
+ else
+ return &maProperties[(*aIter).second];
+}
+
+
+// XPropertySetInfo
+
+
+Sequence< Property > SAL_CALL FastPropertySetInfo::getProperties()
+{
+ return Sequence< Property >( maProperties.data(), maProperties.size() );
+}
+
+
+Property SAL_CALL FastPropertySetInfo::getPropertyByName( const OUString& aName )
+{
+ return getProperty( aName );
+}
+
+
+sal_Bool SAL_CALL FastPropertySetInfo::hasPropertyByName( const OUString& aName )
+{
+ return hasProperty( aName ) != nullptr;
+}
+
+FastPropertySet::FastPropertySet( const rtl::Reference< FastPropertySetInfo >& xInfo )
+: mxInfo( xInfo )
+{
+}
+
+
+FastPropertySet::~FastPropertySet()
+{
+}
+
+
+// XPropertySet
+
+
+Reference< XPropertySetInfo > SAL_CALL FastPropertySet::getPropertySetInfo( )
+{
+ return mxInfo;
+}
+
+
+void SAL_CALL FastPropertySet::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ setFastPropertyValue( mxInfo->getProperty( aPropertyName ).Handle, aValue );
+}
+
+
+Any SAL_CALL FastPropertySet::getPropertyValue( const OUString& aPropertyName )
+{
+ return getFastPropertyValue( mxInfo->getProperty( aPropertyName ).Handle );
+}
+
+
+void SAL_CALL FastPropertySet::addPropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& )
+{
+}
+
+
+void SAL_CALL FastPropertySet::removePropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& )
+{
+}
+
+
+void SAL_CALL FastPropertySet::addVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& )
+{
+}
+
+
+void SAL_CALL FastPropertySet::removeVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& )
+{
+}
+
+
+// XMultiPropertySet
+
+
+void SAL_CALL FastPropertySet::setPropertyValues( const Sequence< OUString >& aPropertyNames, const Sequence< Any >& aValues )
+{
+ if( aPropertyNames.getLength() != aValues.getLength() )
+ throw IllegalArgumentException();
+
+ const Any* pValues = aValues.getConstArray();
+ for( const OUString& rPropertyName : aPropertyNames )
+ {
+ const Property* pProperty = mxInfo->hasProperty( rPropertyName );
+ if( pProperty ) try
+ {
+ setFastPropertyValue( pProperty->Handle, *pValues );
+ }
+ catch( UnknownPropertyException& )
+ {
+ }
+ pValues++;
+ }
+}
+
+
+Sequence< Any > SAL_CALL FastPropertySet::getPropertyValues( const Sequence< OUString >& aPropertyNames )
+{
+ sal_Int32 nCount = aPropertyNames.getLength();
+ Sequence< Any > aValues( nCount );
+
+ Any* pValues = aValues.getArray();
+ for( const OUString& rPropertyName : aPropertyNames )
+ {
+ const Property* pProperty = mxInfo->hasProperty( rPropertyName );
+ if( pProperty ) try
+ {
+ *pValues = getFastPropertyValue( pProperty->Handle );
+ }
+ catch( UnknownPropertyException& )
+ {
+ }
+ pValues++;
+ }
+ return aValues;
+}
+
+
+void SAL_CALL FastPropertySet::addPropertiesChangeListener( const Sequence< OUString >&, const Reference< XPropertiesChangeListener >& )
+{
+}
+
+
+void SAL_CALL FastPropertySet::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& )
+{
+}
+
+
+void SAL_CALL FastPropertySet::firePropertiesChangeEvent( const Sequence< OUString >&, const Reference< XPropertiesChangeListener >& )
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/propertyset.hxx b/svx/source/table/propertyset.hxx
new file mode 100644
index 000000000..69500afe0
--- /dev/null
+++ b/svx/source/table/propertyset.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_PROPERTYSET_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_PROPERTYSET_HXX
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <rtl/ref.hxx>
+#include <unordered_map>
+#include <vector>
+
+#include <cppuhelper/implbase1.hxx>
+#include <cppuhelper/implbase3.hxx>
+
+namespace sdr::table {
+
+typedef std::vector< css::beans::Property > PropertyVector;
+typedef std::unordered_map< OUString, ::sal_uInt32 > PropertyMap;
+
+class FastPropertySetInfo : public ::cppu::WeakAggImplHelper1< css::beans::XPropertySetInfo >
+{
+public:
+ explicit FastPropertySetInfo( const PropertyVector& rProps );
+ virtual ~FastPropertySetInfo() override;
+
+ void addProperties( const PropertyVector& rProps );
+
+ /// @throws css::beans::UnknownPropertyException
+ const css::beans::Property& getProperty( const OUString& aName );
+ const css::beans::Property* hasProperty( const OUString& aName );
+
+ // XPropertySetInfo
+ virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties( ) override;
+ virtual css::beans::Property SAL_CALL getPropertyByName( const OUString& aName ) override;
+ virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override;
+
+private:
+ PropertyVector maProperties;
+ PropertyMap maMap;
+};
+
+
+class FastPropertySet : public ::cppu::WeakAggImplHelper3< css::beans::XPropertySet, css::beans::XMultiPropertySet, css::beans::XFastPropertySet >
+{
+public:
+ explicit FastPropertySet( const rtl::Reference< FastPropertySetInfo >& xInfo );
+ virtual ~FastPropertySet() override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // XMultiPropertySet
+// virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override;
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override;
+ virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+ virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override;
+
+ // XFastPropertySet
+ virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle, const css::uno::Any& aValue ) override = 0;
+ virtual css::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) override = 0;
+
+private:
+ rtl::Reference< FastPropertySetInfo > mxInfo;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/svdotable.cxx b/svx/source/table/svdotable.cxx
new file mode 100644
index 000000000..8b46feb29
--- /dev/null
+++ b/svx/source/table/svdotable.cxx
@@ -0,0 +1,2534 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <unotools/configmgr.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <svl/style.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/outlobj.hxx>
+#include <sdr/properties/textproperties.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/svdhdl.hxx>
+#include "viewcontactoftableobj.hxx"
+#include <svx/svdoutl.hxx>
+#include <svx/svddrag.hxx>
+#include <tablemodel.hxx>
+#include <cell.hxx>
+#include "tablelayouter.hxx"
+#include "tablehandles.hxx"
+#include <svx/sdr/table/tabledesign.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <editeng/writingmodeitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <libxml/xmlwriter.h>
+#include <tools/diagnose_ex.h>
+
+#include <boost/property_tree/ptree.hpp>
+
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::style::XStyle;
+using ::com::sun::star::table::XTableRows;
+using ::com::sun::star::table::XTableColumns;
+using ::com::sun::star::table::XTable;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::util::XModifyBroadcaster;
+using sdr::properties::TextProperties;
+using sdr::properties::BaseProperties;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::style;
+
+namespace sdr::table {
+
+namespace {
+
+class TableProperties : public TextProperties
+{
+protected:
+ // create a new itemset
+ SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
+
+public:
+ // basic constructor
+ explicit TableProperties(SdrObject& rObj );
+
+ // constructor for copying, but using new object
+ TableProperties(const TableProperties& rProps, SdrObject& rObj );
+
+ // Clone() operator, normally just calls the local copy constructor
+ std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
+
+ virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = nullptr) override;
+};
+
+}
+
+TableProperties::TableProperties(SdrObject& rObj)
+: TextProperties(rObj)
+{
+}
+
+TableProperties::TableProperties(const TableProperties& rProps, SdrObject& rObj)
+: TextProperties(rProps, rObj)
+{
+}
+
+std::unique_ptr<BaseProperties> TableProperties::Clone(SdrObject& rObj) const
+{
+ return std::unique_ptr<BaseProperties>(new TableProperties(*this, rObj));
+}
+
+void TableProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
+{
+ if( nWhich == SDRATTR_TEXTDIRECTION )
+ AttributeProperties::ItemChange( nWhich, pNewItem );
+ else
+ TextProperties::ItemChange( nWhich, pNewItem );
+}
+
+// create a new itemset
+SfxItemSet TableProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+{
+ return SfxItemSet(rPool,
+
+ // range from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+
+ // range for SdrTableObj
+ SDRATTR_TABLE_FIRST, SDRATTR_TABLE_LAST,
+
+ // range from SdrTextObj
+ EE_ITEMS_START, EE_ITEMS_END>);
+}
+
+namespace {
+
+class TableObjectGeoData : public SdrTextObjGeoData
+{
+public:
+ tools::Rectangle maLogicRect;
+};
+
+}
+
+TableStyleSettings::TableStyleSettings()
+: mbUseFirstRow(true)
+, mbUseLastRow(false)
+, mbUseFirstColumn(false)
+, mbUseLastColumn(false)
+, mbUseRowBanding(true)
+, mbUseColumnBanding(false)
+{
+}
+
+TableStyleSettings::TableStyleSettings( const TableStyleSettings& rStyle )
+{
+ (*this) = rStyle;
+}
+
+TableStyleSettings& TableStyleSettings::operator=(const TableStyleSettings& rStyle)
+{
+ mbUseFirstRow = rStyle.mbUseFirstRow;
+ mbUseLastRow = rStyle.mbUseLastRow;
+ mbUseFirstColumn = rStyle.mbUseFirstColumn;
+ mbUseLastColumn = rStyle.mbUseLastColumn;
+ mbUseRowBanding = rStyle.mbUseRowBanding;
+ mbUseColumnBanding = rStyle.mbUseColumnBanding;
+ return *this;
+}
+
+bool TableStyleSettings::operator==( const TableStyleSettings& rStyle ) const
+{
+ return
+ (mbUseFirstRow == rStyle.mbUseFirstRow) &&
+ (mbUseLastRow == rStyle.mbUseLastRow) &&
+ (mbUseFirstColumn == rStyle.mbUseFirstColumn) &&
+ (mbUseLastColumn == rStyle.mbUseLastColumn) &&
+ (mbUseRowBanding == rStyle.mbUseRowBanding) &&
+ (mbUseColumnBanding == rStyle.mbUseColumnBanding);
+}
+
+
+class SdrTableObjImpl : public TableDesignUser, public ::cppu::WeakImplHelper< css::util::XModifyListener >
+{
+public:
+ CellRef mxActiveCell;
+ TableModelRef mxTable;
+ SdrTableObj* mpTableObj;
+ std::unique_ptr<TableLayouter> mpLayouter;
+ CellPos maEditPos;
+ TableStyleSettings maTableStyle;
+ Reference< XIndexAccess > mxTableStyle;
+ std::vector<std::unique_ptr<SdrUndoAction>> maUndos;
+ bool mbSkipChangeLayout;
+
+ void CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd);
+
+ CellRef getCell( const CellPos& rPos ) const;
+ void LayoutTable( tools::Rectangle& rArea, bool bFitWidth, bool bFitHeight );
+
+ void ApplyCellStyles();
+ void UpdateCells( tools::Rectangle const & rArea );
+
+ SdrTableObjImpl();
+ virtual ~SdrTableObjImpl() override;
+
+ void init( SdrTableObj* pTable, sal_Int32 nColumns, sal_Int32 nRows );
+ void dispose();
+
+ sal_Int32 getColumnCount() const;
+ /// Get widths of the columns in the table.
+ std::vector<sal_Int32> getColumnWidths() const;
+ sal_Int32 getRowCount() const;
+
+ void DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset );
+
+ SdrTableObjImpl& operator=( const SdrTableObjImpl& rSource );
+
+ // XModifyListener
+ virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ void update();
+
+ void connectTableStyle();
+ void disconnectTableStyle();
+ virtual bool isInUse() override;
+ void dumpAsXml(xmlTextWriterPtr pWriter) const;
+private:
+ static SdrTableObjImpl* lastLayoutTable;
+ static tools::Rectangle lastLayoutInputRectangle;
+ static tools::Rectangle lastLayoutResultRectangle;
+ static bool lastLayoutFitWidth;
+ static bool lastLayoutFitHeight;
+ static WritingMode lastLayoutMode;
+ static sal_Int32 lastRowCount;
+ static sal_Int32 lastColCount;
+ static std::vector<sal_Int32> lastColWidths;
+ static bool rowSizeChanged;
+};
+
+SdrTableObjImpl* SdrTableObjImpl::lastLayoutTable = nullptr;
+tools::Rectangle SdrTableObjImpl::lastLayoutInputRectangle;
+tools::Rectangle SdrTableObjImpl::lastLayoutResultRectangle;
+bool SdrTableObjImpl::lastLayoutFitWidth;
+bool SdrTableObjImpl::lastLayoutFitHeight;
+WritingMode SdrTableObjImpl::lastLayoutMode;
+sal_Int32 SdrTableObjImpl::lastRowCount;
+sal_Int32 SdrTableObjImpl::lastColCount;
+bool SdrTableObjImpl::rowSizeChanged = false;
+std::vector<sal_Int32> SdrTableObjImpl::lastColWidths;
+
+SdrTableObjImpl::SdrTableObjImpl()
+: mpTableObj( nullptr )
+, mbSkipChangeLayout(false)
+{
+}
+
+
+SdrTableObjImpl::~SdrTableObjImpl()
+{
+ if( lastLayoutTable == this )
+ lastLayoutTable = nullptr;
+}
+
+
+void SdrTableObjImpl::CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd)
+{
+ if(!mxTable.is())
+ {
+ return;
+ }
+
+ const sal_Int32 nColumns(rEnd.mnCol - rStart.mnCol + 1);
+ const sal_Int32 nRows(rEnd.mnRow - rStart.mnRow + 1);
+
+ if(nColumns < 1 || nRows < 1 || nColumns > getColumnCount() || nRows > getRowCount())
+ {
+ return;
+ }
+
+ // tdf#116977 First thought was to create the new TableModel, copy data to it and then exchange
+ // mxTable and dispose old one. This does *not* work, even when all stuff looks nicely referenced
+ // and safe *because* Cell::create gets handed over the current SdrTableObj, hands it to
+ // ::Cell and there the local mxTable is initialized using rTableObj.getTable() (!). Due to This,
+ // the new created Cells in a new created TableModel based on given mpTableObj *will be disposed*
+ // when the old mxTable gets disposed - ARGH!
+ // To avoid, change strategy: Remember old TableModel, reset mxTable immediately - this is the
+ // SdrTableObjImpl of the current SdrTableObj anyways. Luckily, this works as intended...
+
+ // remember old TableModel
+ TableModelRef xOldTable(mxTable);
+
+ // immediately create new one and initialize. This creates ::Cell's which then will use
+ // the correct TableModel (accessed through SdrTableObj, but using local mxTable)
+ mxTable = new TableModel(mpTableObj);
+ mxTable->init(nColumns, nRows);
+
+ // copy cells
+ for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
+ {
+ for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol ) try
+ {
+ CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xTargetCell.is() )
+ xTargetCell->cloneFrom( dynamic_cast< Cell* >( xOldTable->getCellByPosition( rStart.mnCol + nCol, rStart.mnRow + nRow ).get() ) );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+ }
+
+ // copy row heights
+ Reference< XTableRows > xNewRows(mxTable->getRows(), css::uno::UNO_SET_THROW );
+ static const OUStringLiteral sHeight( u"Height" );
+ for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
+ {
+ Reference< XPropertySet > xNewSet( xNewRows->getByIndex( nRow ), UNO_QUERY_THROW );
+ xNewSet->setPropertyValue( sHeight, Any( mpLayouter->getRowHeight( rStart.mnRow + nRow ) ) );
+ }
+
+ // copy column widths
+ Reference< XTableColumns > xNewColumns( mxTable->getColumns(), css::uno::UNO_SET_THROW );
+ static const OUStringLiteral sWidth( u"Width" );
+ for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol )
+ {
+ Reference< XPropertySet > xNewSet( xNewColumns->getByIndex( nCol ), UNO_QUERY_THROW );
+ xNewSet->setPropertyValue( sWidth, Any( mpLayouter->getColumnWidth( rStart.mnCol + nCol ) ) );
+ }
+
+ // reset layouter which still holds a copy to old TableModel
+ mpLayouter.reset();
+
+ // cleanup old TableModel
+ {
+ Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
+ xOldTable->removeModifyListener( xListener );
+ xOldTable->dispose();
+ xOldTable.clear();
+ }
+
+ // create and hand over to new TableLayouter
+ mpLayouter.reset(new TableLayouter( mxTable ));
+
+ // add needed listener to react on changes
+ Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
+ mxTable->addModifyListener( xListener );
+
+ // Apply Style to Cells
+ ApplyCellStyles();
+
+ // layout cropped table
+ LayoutTable( mpTableObj->maRect, false, false );
+}
+
+void SdrTableObjImpl::init( SdrTableObj* pTable, sal_Int32 nColumns, sal_Int32 nRows )
+{
+ mpTableObj = pTable;
+ mxTable = new TableModel( pTable );
+ mxTable->init( nColumns, nRows );
+ Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
+ mxTable->addModifyListener( xListener );
+ mpLayouter.reset(new TableLayouter( mxTable ));
+ LayoutTable( mpTableObj->maRect, true, true );
+ mpTableObj->maLogicRect = mpTableObj->maRect;
+}
+
+
+SdrTableObjImpl& SdrTableObjImpl::operator=( const SdrTableObjImpl& rSource )
+{
+ if(this == &rSource)
+ {
+ return *this;
+ }
+
+ if(nullptr == mpTableObj || nullptr == rSource.mpTableObj)
+ {
+ // error: need both SdrObjects to successfully copy data
+ return *this;
+ }
+
+ // remove evtl. listeners from local
+ disconnectTableStyle();
+
+ // reset layouter which holds a copy
+ mpLayouter.reset();
+
+ // cleanup local mxTable if used
+ if( mxTable.is() )
+ {
+ Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
+ mxTable->removeModifyListener( xListener );
+ mxTable->dispose();
+ mxTable.clear();
+ }
+
+ // tdf#127481: reset active cell reference
+ mxActiveCell.clear();
+
+ // copy TableStyle (short internal data)
+ maTableStyle = rSource.maTableStyle;
+
+ // create/copy new mxTable. This will copy all needed cells, too
+ mxTable = new TableModel( mpTableObj, rSource.mxTable );
+
+ // create and hand over to new TableLayouter
+ mpLayouter.reset(new TableLayouter( mxTable ));
+
+ // add needed listener to react on changes
+ Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
+ mxTable->addModifyListener( xListener );
+
+ // handle TableStyle
+ Reference< XIndexAccess > xNewTableStyle;
+ SdrModel& rSourceSdrModel(rSource.mpTableObj->getSdrModelFromSdrObject());
+ SdrModel& rTargetSdrModel(mpTableObj->getSdrModelFromSdrObject());
+
+ if(rSource.mxTableStyle.is() && &rSourceSdrModel == &rTargetSdrModel)
+ {
+ // source and target model the same -> keep current TableStyle
+ xNewTableStyle = rSource.mxTableStyle;
+ }
+
+ if(!xNewTableStyle.is() && rSource.mxTableStyle.is()) try
+ {
+ // search in target SdrModel for that TableStyle
+ const OUString sStyleName( Reference< XNamed >( rSource.mxTableStyle, UNO_QUERY_THROW )->getName() );
+ Reference< XStyleFamiliesSupplier > xSFS(rTargetSdrModel.getUnoModel(), UNO_QUERY_THROW );
+ Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), css::uno::UNO_SET_THROW );
+ Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( "table" ), UNO_QUERY_THROW );
+
+ if( xTableFamilyAccess->hasByName( sStyleName ) )
+ {
+ // found table style with the same name
+ xTableFamilyAccess->getByName( sStyleName ) >>= xNewTableStyle;
+ }
+ else
+ {
+ // copy or? Not found, use 1st existing TableStyle (or none)
+ Reference< XIndexAccess > xIndexAccess( xTableFamilyAccess, UNO_QUERY_THROW );
+ xIndexAccess->getByIndex( 0 ) >>= xNewTableStyle;
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+
+ // set that TableStyle
+ mxTableStyle = xNewTableStyle;
+
+ // Apply Style to Cells
+ ApplyCellStyles();
+
+ // copy geometry
+ mpTableObj->maRect = mpTableObj->maLogicRect;
+
+ // layout cloned table
+ LayoutTable( mpTableObj->maRect, false, false );
+
+ // re-connect to styles (evtl. in new SdrModel)
+ connectTableStyle();
+
+ return *this;
+}
+
+void SdrTableObjImpl::ApplyCellStyles()
+{
+ if( !mxTable.is() || !mxTableStyle.is() )
+ return;
+
+ const sal_Int32 nColCount = getColumnCount();
+ const sal_Int32 nRowCount = getRowCount();
+
+ const TableStyleSettings& rStyle = maTableStyle;
+
+ CellPos aPos;
+ for( aPos.mnRow = 0; aPos.mnRow < nRowCount; ++aPos.mnRow )
+ {
+ const bool bFirstRow = (aPos.mnRow == 0) && rStyle.mbUseFirstRow;
+ const bool bLastRow = (aPos.mnRow == nRowCount-1) && rStyle.mbUseLastRow;
+
+ for( aPos.mnCol = 0; aPos.mnCol < nColCount; ++aPos.mnCol )
+ {
+ Reference< XStyle > xStyle;
+
+ // first and last row win first, if used and available
+ if( bFirstRow )
+ {
+ mxTableStyle->getByIndex(first_row_style) >>= xStyle;
+ }
+ else if( bLastRow )
+ {
+ mxTableStyle->getByIndex(last_row_style) >>= xStyle;
+ }
+
+ if( !xStyle.is() )
+ {
+ // next come first and last column, if used and available
+ if( rStyle.mbUseFirstColumn && (aPos.mnCol == 0) )
+ {
+ mxTableStyle->getByIndex(first_column_style) >>= xStyle;
+ }
+ else if( rStyle.mbUseLastColumn && (aPos.mnCol == nColCount-1) )
+ {
+ mxTableStyle->getByIndex(last_column_style) >>= xStyle;
+ }
+ }
+
+ if( !xStyle.is() && rStyle.mbUseRowBanding )
+ {
+ if( (aPos.mnRow & 1) == 0 )
+ {
+ mxTableStyle->getByIndex(even_rows_style) >>= xStyle;
+ }
+ else
+ {
+ mxTableStyle->getByIndex(odd_rows_style) >>= xStyle;
+ }
+ }
+
+ if( !xStyle.is() && rStyle.mbUseColumnBanding )
+ {
+ if( (aPos.mnCol & 1) == 0 )
+ {
+ mxTableStyle->getByIndex(even_columns_style) >>= xStyle;
+ }
+ else
+ {
+ mxTableStyle->getByIndex(odd_columns_style) >>= xStyle;
+ }
+ }
+
+ if( !xStyle.is() )
+ {
+ // use default cell style if non found yet
+ mxTableStyle->getByIndex(body_style) >>= xStyle;
+ }
+
+
+ if( xStyle.is() )
+ {
+ SfxUnoStyleSheet* pStyle = SfxUnoStyleSheet::getUnoStyleSheet(xStyle);
+
+ if( pStyle )
+ {
+ CellRef xCell( getCell( aPos ) );
+ if( xCell.is() && ( xCell->GetStyleSheet() != pStyle ) )
+ {
+ xCell->SetStyleSheet( pStyle, true );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void SdrTableObjImpl::dispose()
+{
+ disconnectTableStyle();
+ mxTableStyle.clear();
+
+ mpLayouter.reset();
+
+ if( mxTable.is() )
+ {
+ Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
+ mxTable->removeModifyListener( xListener );
+ mxTable->dispose();
+ mxTable.clear();
+ }
+}
+
+
+void SdrTableObjImpl::DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset )
+{
+ if( !((nEdge >= 0) && mxTable.is()))
+ return;
+
+ try
+ {
+ static const OUStringLiteral sSize( u"Size" );
+ if( mbHorizontal )
+ {
+ if (nEdge <= getRowCount())
+ {
+ sal_Int32 nHeight = mpLayouter->getRowHeight( (!nEdge)?nEdge:(nEdge-1) );
+ if(nEdge==0)
+ nHeight -= nOffset;
+ else
+ nHeight += nOffset;
+ Reference< XIndexAccess > xRows( mxTable->getRows(), UNO_QUERY_THROW );
+ Reference< XPropertySet > xRowSet( xRows->getByIndex( (!nEdge)?nEdge:(nEdge-1) ), UNO_QUERY_THROW );
+ xRowSet->setPropertyValue( sSize, Any( nHeight ) );
+ rowSizeChanged = true;
+ }
+ }
+ else
+ {
+ /*
+ fixes fdo#59889 and resizing of table in edge dragging
+ Total vertical edges in a NxN table is N+1, indexed from 0 to N and total Columns is N, indexed from 0 to N-1
+ In LTR table vertical edge responsible for dragging of column x(x=0 to N-1) is, Edge x+1
+ But in RTL table vertical edge responsible for dragging of column x(x=0 to N-1, but from right to left)is, Edge x
+ In LTR table dragging of edge 0(for RTL table edge N) does nothing.
+ */
+ //Todo: Implement Dragging functionality for leftmost edge of table.
+ if (nEdge <= getColumnCount())
+ {
+ const bool bRTL = mpTableObj != nullptr && (mpTableObj->GetWritingMode() == WritingMode_RL_TB);
+ sal_Int32 nWidth;
+ if(bRTL)
+ {
+ nWidth = mpLayouter->getColumnWidth( nEdge );
+ }
+ else
+ {
+ nWidth = mpLayouter->getColumnWidth( (!nEdge)?nEdge:(nEdge-1) );
+ }
+ Reference< XIndexAccess > xCols( mxTable->getColumns(), UNO_QUERY_THROW );
+ nWidth += nOffset;
+ if(bRTL && nEdge<getColumnCount())
+ {
+ Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge ), UNO_QUERY_THROW );
+ xColSet->setPropertyValue( sSize, Any( nWidth ) );
+ }
+ else if(!bRTL && nEdge>0)
+ {
+ Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge-1 ), UNO_QUERY_THROW );
+ xColSet->setPropertyValue( sSize, Any( nWidth ) );
+ }
+ /* To prevent the table resizing on edge dragging */
+ if( nEdge > 0 && nEdge < mxTable->getColumnCount() )
+ {
+ if( bRTL )
+ nEdge--;
+
+ nWidth = mpLayouter->getColumnWidth(nEdge);
+ nWidth = std::max(static_cast<sal_Int32>(nWidth - nOffset), sal_Int32(0));
+
+ Reference<XPropertySet> xColSet(xCols->getByIndex(nEdge), UNO_QUERY_THROW);
+ xColSet->setPropertyValue(sSize, Any(nWidth));
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+}
+
+
+// XModifyListener
+
+
+void SAL_CALL SdrTableObjImpl::modified( const css::lang::EventObject& /*aEvent*/ )
+{
+ update();
+}
+
+void SdrTableObjImpl::update()
+{
+ // source can be the table model itself or the assigned table template
+ TableModelNotifyGuard aGuard( mxTable.get() );
+ if( !mpTableObj )
+ return;
+
+ if( (maEditPos.mnRow >= getRowCount()) || (maEditPos.mnCol >= getColumnCount()) || (getCell( maEditPos ) != mxActiveCell) )
+ {
+ if(maEditPos.mnRow >= getRowCount())
+ maEditPos.mnRow = getRowCount()-1;
+
+ if(maEditPos.mnCol >= getColumnCount())
+ maEditPos.mnCol = getColumnCount()-1;
+
+ mpTableObj->setActiveCell( maEditPos );
+ }
+
+ ApplyCellStyles();
+
+ mpTableObj->maRect = mpTableObj->maLogicRect;
+ LayoutTable( mpTableObj->maRect, false, false );
+
+ mpTableObj->SetBoundAndSnapRectsDirty();
+ mpTableObj->ActionChanged();
+ mpTableObj->BroadcastObjectChange();
+}
+
+
+void SdrTableObjImpl::connectTableStyle()
+{
+ if( mxTableStyle.is() )
+ {
+ Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY );
+ if( xBroadcaster.is() )
+ {
+ Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
+ xBroadcaster->addModifyListener( xListener );
+ }
+ }
+}
+
+
+void SdrTableObjImpl::disconnectTableStyle()
+{
+ if( mxTableStyle.is() )
+ {
+ Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY );
+ if( xBroadcaster.is() )
+ {
+ Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
+ xBroadcaster->removeModifyListener( xListener );
+ }
+ }
+}
+
+
+bool SdrTableObjImpl::isInUse()
+{
+ return mpTableObj && mpTableObj->IsInserted();
+}
+
+void SdrTableObjImpl::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTableObjImpl"));
+ if (mpLayouter)
+ mpLayouter->dumpAsXml(pWriter);
+ mxTable->dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+
+// XEventListener
+
+
+void SAL_CALL SdrTableObjImpl::disposing( const css::lang::EventObject& /*Source*/ )
+{
+ mxActiveCell.clear();
+ mxTable.clear();
+ mpLayouter.reset();
+ mpTableObj = nullptr;
+}
+
+
+CellRef SdrTableObjImpl::getCell( const CellPos& rPos ) const
+{
+ CellRef xCell;
+ if( mxTable.is() ) try
+ {
+ xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+ return xCell;
+}
+
+
+sal_Int32 SdrTableObjImpl::getColumnCount() const
+{
+ return mxTable.is() ? mxTable->getColumnCount() : 0;
+}
+
+std::vector<sal_Int32> SdrTableObjImpl::getColumnWidths() const
+{
+ std::vector<sal_Int32> aRet;
+
+ if (mxTable.is())
+ aRet = mxTable->getColumnWidths();
+
+ return aRet;
+}
+
+sal_Int32 SdrTableObjImpl::getRowCount() const
+{
+ return mxTable.is() ? mxTable->getRowCount() : 0;
+}
+
+void SdrTableObjImpl::LayoutTable( tools::Rectangle& rArea, bool bFitWidth, bool bFitHeight )
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return;
+ if(!mpLayouter)
+ return;
+
+ // Optimization: SdrTableObj::SetChanged() can call this very often, repeatedly
+ // with the same settings, noticeably increasing load time. Skip if already done.
+ bool bInteractiveMightGrowBecauseTextChanged =
+ mpTableObj->IsReallyEdited() && (mpTableObj->IsAutoGrowHeight() || mpTableObj->IsAutoGrowWidth());
+ WritingMode writingMode = mpTableObj->GetWritingMode();
+ if( bInteractiveMightGrowBecauseTextChanged
+ || lastLayoutTable != this || lastLayoutInputRectangle != rArea
+ || lastLayoutFitWidth != bFitWidth || lastLayoutFitHeight != bFitHeight
+ || lastLayoutMode != writingMode
+ || lastRowCount != getRowCount()
+ || lastColCount != getColumnCount()
+ || lastColWidths != getColumnWidths()
+ || rowSizeChanged )
+ {
+ lastLayoutTable = this;
+ lastLayoutInputRectangle = rArea;
+ lastLayoutFitWidth = bFitWidth;
+ lastLayoutFitHeight = bFitHeight;
+ lastLayoutMode = writingMode;
+ lastRowCount = getRowCount();
+ lastColCount = getColumnCount();
+ // Column resize, when the total width and column count of the
+ // table is unchanged, but re-layout is still needed.
+ lastColWidths = getColumnWidths();
+ TableModelNotifyGuard aGuard( mxTable.get() );
+ mpLayouter->LayoutTable( rArea, bFitWidth, bFitHeight );
+ lastLayoutResultRectangle = rArea;
+ rowSizeChanged = false;
+ }
+ else
+ {
+ rArea = lastLayoutResultRectangle;
+ mpLayouter->UpdateBorderLayout();
+ }
+}
+
+void SdrTableObjImpl::UpdateCells( tools::Rectangle const & rArea )
+{
+ if( mpLayouter && mxTable.is() )
+ {
+ TableModelNotifyGuard aGuard( mxTable.get() );
+ mpLayouter->updateCells( rArea );
+ mxTable->setModified(true);
+ }
+}
+
+
+// BaseProperties section
+
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrTableObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<TableProperties>(*this);
+}
+
+
+// DrawContact section
+
+
+std::unique_ptr<sdr::contact::ViewContact> SdrTableObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfTableObj>(*this);
+}
+
+SdrTableObj::SdrTableObj(SdrModel& rSdrModel)
+: SdrTextObj(rSdrModel)
+{
+ init( 1, 1 );
+}
+
+SdrTableObj::SdrTableObj(SdrModel& rSdrModel, SdrTableObj const & rSource)
+: SdrTextObj(rSdrModel, rSource)
+{
+ init( 1, 1 );
+
+ TableModelNotifyGuard aGuard( mpImpl.is() ? mpImpl->mxTable.get() : nullptr );
+
+ maLogicRect = rSource.maLogicRect;
+ maRect = rSource.maRect;
+ maGeo = rSource.maGeo;
+ meTextKind = rSource.meTextKind;
+ mbTextFrame = rSource.mbTextFrame;
+ maTextSize = rSource.maTextSize;
+ mbTextSizeDirty = rSource.mbTextSizeDirty;
+ mbNoShear = rSource.mbNoShear;
+ mbDisableAutoWidthOnDragging = rSource.mbDisableAutoWidthOnDragging;
+
+ // use SdrTableObjImpl::operator= now to
+ // copy model data and other stuff (see there)
+ *mpImpl = *rSource.mpImpl;
+}
+
+SdrTableObj::SdrTableObj(
+ SdrModel& rSdrModel,
+ const ::tools::Rectangle& rNewRect,
+ sal_Int32 nColumns,
+ sal_Int32 nRows)
+: SdrTextObj(rSdrModel, rNewRect)
+ ,maLogicRect(rNewRect)
+{
+ if( nColumns <= 0 )
+ nColumns = 1;
+
+ if( nRows <= 0 )
+ nRows = 1;
+
+ init( nColumns, nRows );
+}
+
+
+void SdrTableObj::init( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ m_bClosedObj = true;
+
+ mpImpl = new SdrTableObjImpl;
+ mpImpl->init( this, nColumns, nRows );
+
+ // Stuff done from old SetModel:
+ if( !maLogicRect.IsEmpty() )
+ {
+ maRect = maLogicRect;
+ mpImpl->LayoutTable( maRect, false, false );
+ }
+}
+
+
+SdrTableObj::~SdrTableObj()
+{
+ mpImpl->dispose();
+}
+
+
+// table stuff
+
+
+Reference< XTable > SdrTableObj::getTable() const
+{
+ return mpImpl->mxTable;
+}
+
+
+bool SdrTableObj::isValid( const CellPos& rPos ) const
+{
+ return (rPos.mnCol >= 0) && (rPos.mnCol < mpImpl->getColumnCount()) && (rPos.mnRow >= 0) && (rPos.mnRow < mpImpl->getRowCount());
+}
+
+
+CellPos SdrTableObj::getFirstCell()
+{
+ return CellPos( 0,0 );
+}
+
+
+CellPos SdrTableObj::getLastCell() const
+{
+ CellPos aPos;
+ if( mpImpl->mxTable.is() )
+ {
+ aPos.mnCol = mpImpl->getColumnCount()-1;
+ aPos.mnRow = mpImpl->getRowCount()-1;
+ }
+ return aPos;
+}
+
+
+CellPos SdrTableObj::getLeftCell( const CellPos& rPos, bool bEdgeTravel ) const
+{
+ switch( GetWritingMode() )
+ {
+ default:
+ case WritingMode_LR_TB:
+ return getPreviousCell( rPos, bEdgeTravel );
+ case WritingMode_RL_TB:
+ return getNextCell( rPos, bEdgeTravel );
+ case WritingMode_TB_RL:
+ return getPreviousRow( rPos, bEdgeTravel );
+ }
+}
+
+
+CellPos SdrTableObj::getRightCell( const CellPos& rPos, bool bEdgeTravel ) const
+{
+ switch( GetWritingMode() )
+ {
+ default:
+ case WritingMode_LR_TB:
+ return getNextCell( rPos, bEdgeTravel );
+ case WritingMode_RL_TB:
+ return getPreviousCell( rPos, bEdgeTravel );
+ case WritingMode_TB_RL:
+ return getNextRow( rPos, bEdgeTravel );
+ }
+}
+
+
+CellPos SdrTableObj::getUpCell( const CellPos& rPos, bool bEdgeTravel ) const
+{
+ switch( GetWritingMode() )
+ {
+ default:
+ case WritingMode_LR_TB:
+ case WritingMode_RL_TB:
+ return getPreviousRow( rPos, bEdgeTravel );
+ case WritingMode_TB_RL:
+ return getPreviousCell( rPos, bEdgeTravel );
+ }
+}
+
+
+CellPos SdrTableObj::getDownCell( const CellPos& rPos, bool bEdgeTravel ) const
+{
+ switch( GetWritingMode() )
+ {
+ default:
+ case WritingMode_LR_TB:
+ case WritingMode_RL_TB:
+ return getNextRow( rPos, bEdgeTravel );
+ case WritingMode_TB_RL:
+ return getNextCell( rPos, bEdgeTravel );
+ }
+}
+
+
+CellPos SdrTableObj::getPreviousCell( const CellPos& rPos, bool bEdgeTravel ) const
+{
+ CellPos aPos( rPos );
+ if( mpImpl.is() )
+ {
+ CellRef xCell( mpImpl->getCell( aPos ) );
+ if( xCell.is() && xCell->isMerged() )
+ {
+ sal_Int32 nTemp = 0;
+ findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, nTemp );
+ }
+
+ if( aPos.mnCol > 0 )
+ {
+ --aPos.mnCol;
+ }
+
+ else if( bEdgeTravel && (aPos.mnRow > 0) )
+ {
+ aPos.mnCol = mpImpl->mxTable->getColumnCount()-1;
+ --aPos.mnRow;
+ }
+ }
+ return aPos;
+}
+
+
+CellPos SdrTableObj::getNextCell( const CellPos& rPos, bool bEdgeTravel ) const
+{
+ CellPos aPos( rPos );
+ if( mpImpl.is() )
+ {
+ CellRef xCell( mpImpl->getCell( aPos ) );
+ if( xCell.is() )
+ {
+ if( xCell->isMerged() )
+ {
+ findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow );
+
+ xCell = mpImpl->getCell(aPos);
+
+ if( xCell.is() )
+ {
+ aPos.mnCol += xCell->getColumnSpan();
+ aPos.mnRow = rPos.mnRow;
+ }
+ }
+ else
+ {
+ aPos.mnCol += xCell->getColumnSpan();
+ }
+
+ if( aPos.mnCol < mpImpl->mxTable->getColumnCount() )
+ return aPos;
+
+ if( bEdgeTravel && ((aPos.mnRow + 1) < mpImpl->getRowCount()) )
+ {
+ aPos.mnCol = 0;
+ aPos.mnRow += 1;
+ return aPos;
+ }
+ }
+ }
+
+ // last cell reached, no traveling possible
+ return rPos;
+}
+
+
+CellPos SdrTableObj::getPreviousRow( const CellPos& rPos, bool bEdgeTravel ) const
+{
+ CellPos aPos( rPos );
+ if( mpImpl.is() )
+ {
+ CellRef xCell( mpImpl->getCell( aPos ) );
+ if( xCell.is() && xCell->isMerged() )
+ {
+ sal_Int32 nTemp = 0;
+ findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, nTemp, aPos.mnRow );
+ }
+
+ if( aPos.mnRow > 0 )
+ {
+ --aPos.mnRow;
+ }
+ else if( bEdgeTravel && (aPos.mnCol > 0) )
+ {
+ aPos.mnRow = mpImpl->mxTable->getRowCount()-1;
+ --aPos.mnCol;
+ }
+ }
+ return aPos;
+}
+
+
+CellPos SdrTableObj::getNextRow( const CellPos& rPos, bool bEdgeTravel ) const
+{
+ CellPos aPos( rPos );
+
+ if( mpImpl.is() )
+ {
+ CellRef xCell( mpImpl->getCell( rPos ) );
+ if( xCell.is() )
+ {
+ if( xCell->isMerged() )
+ {
+ findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow );
+ xCell = mpImpl->getCell(aPos);
+ aPos.mnCol = rPos.mnCol;
+ }
+
+ if( xCell.is() )
+ aPos.mnRow += xCell->getRowSpan();
+
+ if( aPos.mnRow < mpImpl->mxTable->getRowCount() )
+ return aPos;
+
+ if( bEdgeTravel && (aPos.mnCol + 1) < mpImpl->mxTable->getColumnCount() )
+ {
+ aPos.mnRow = 0;
+ aPos.mnCol += 1;
+
+ while( aPos.mnCol < mpImpl->mxTable->getColumnCount() )
+ {
+ xCell = mpImpl->getCell( aPos );
+ if( xCell.is() && !xCell->isMerged() )
+ return aPos;
+ aPos.mnCol += 1;
+ }
+ }
+ }
+ }
+
+ // last position reached, no more traveling possible
+ return rPos;
+}
+
+
+const TableStyleSettings& SdrTableObj::getTableStyleSettings() const
+{
+ if( mpImpl.is())
+ {
+ return mpImpl->maTableStyle;
+ }
+ else
+ {
+ static TableStyleSettings aTmp;
+ return aTmp;
+ }
+}
+
+
+void SdrTableObj::setTableStyleSettings( const TableStyleSettings& rStyle )
+{
+ if( mpImpl.is() )
+ {
+ mpImpl->maTableStyle = rStyle;
+ mpImpl->update();
+ }
+}
+
+
+TableHitKind SdrTableObj::CheckTableHit( const Point& rPos, sal_Int32& rnX, sal_Int32& rnY, const sal_uInt16 aTol ) const
+{
+ if( !mpImpl.is() || !mpImpl->mxTable.is() )
+ return TableHitKind::NONE;
+
+ rnX = 0;
+ rnY = 0;
+
+ const sal_Int32 nColCount = mpImpl->getColumnCount();
+ const sal_Int32 nRowCount = mpImpl->getRowCount();
+
+ sal_Int32 nX = rPos.X() - maRect.Left();
+ sal_Int32 nY = rPos.Y() - maRect.Top();
+
+ if( (nX < 0) || (nX > maRect.GetWidth()) || (nY < 0) || (nY > maRect.GetHeight() ) )
+ return TableHitKind::NONE;
+
+ // get vertical edge number and check for a hit
+ const bool bRTL = (GetWritingMode() == WritingMode_RL_TB);
+ bool bVrtHit = false;
+ if( !bRTL )
+ {
+ while( rnX <= nColCount )
+ {
+ if( nX - aTol <= 0 )
+ {
+ bVrtHit = true;
+ break;
+ }
+
+ if( rnX == nColCount )
+ break;
+
+ nX -= mpImpl->mpLayouter->getColumnWidth( rnX );
+ if( nX < 0 )
+ break;
+ rnX++;
+ }
+ }
+ else
+ {
+ rnX = nColCount;
+ while( rnX >= 0 )
+ {
+ if( nX - aTol <= 0 )
+ {
+ bVrtHit = true;
+ break;
+ }
+
+ if( rnX == 0 )
+ break;
+
+ rnX--;
+ nX -= mpImpl->mpLayouter->getColumnWidth( rnX );
+ if( nX < 0 )
+ break;
+ }
+ }
+
+ // rnX is now the edge number left to the pointer, if it was hit bHrzHit is also true
+
+ // get vertical edge number and check for a hit
+ bool bHrzHit = false;
+ while( rnY <= nRowCount )
+ {
+ if( nY - aTol <= 0 )
+ {
+ bHrzHit = true;
+ break;
+ }
+
+ if( rnY == nRowCount )
+ break;
+
+ nY -= mpImpl->mpLayouter->getRowHeight(rnY);
+ if( nY < 0 )
+ break;
+ rnY++;
+ }
+
+ // rnY is now the edge number above the pointer, if it was hit bVrtHit is also true
+
+ if( bVrtHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, false ) )
+ return TableHitKind::VerticallBorder;
+
+ if( bHrzHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, true ) )
+ return TableHitKind::HorizontalBorder;
+
+ CellRef xCell( mpImpl->getCell( CellPos( rnX, rnY ) ) );
+ if( xCell.is() && xCell->isMerged() )
+ findMergeOrigin( mpImpl->mxTable, rnX, rnY, rnX, rnY );
+
+ if( xCell.is() )
+ {
+ nX += mpImpl->mpLayouter->getColumnWidth( rnX );
+ //Fix for fdo#62673 : non-editable cell in table on cell merge
+ sal_Int32 i=0;
+ while(xCell.is() && xCell->isMerged())
+ {
+ nX += mpImpl->mpLayouter->getColumnWidth( rnX+i );
+ i++;
+ if(rnX+i < nColCount)
+ xCell=mpImpl->getCell( CellPos( rnX+i, rnY) );
+ else
+ break;
+ }
+
+ if( nX < xCell->GetTextLeftDistance() )
+ return TableHitKind::Cell;
+ }
+
+ return TableHitKind::CellTextArea;
+}
+
+const SfxItemSet& SdrTableObj::GetActiveCellItemSet() const
+{
+ return getActiveCell()->GetItemSet();
+}
+
+void SdrTableObj::setTableStyle( const Reference< XIndexAccess >& xTableStyle )
+{
+ if( mpImpl.is() && (mpImpl->mxTableStyle != xTableStyle) )
+ {
+ mpImpl->disconnectTableStyle();
+ mpImpl->mxTableStyle = xTableStyle;
+ mpImpl->connectTableStyle();
+ mpImpl->update();
+ }
+}
+
+
+const Reference< XIndexAccess >& SdrTableObj::getTableStyle() const
+{
+ if( mpImpl.is() )
+ {
+ return mpImpl->mxTableStyle;
+ }
+ else
+ {
+ static Reference< XIndexAccess > aTmp;
+ return aTmp;
+ }
+}
+
+
+// text stuff
+
+
+/** returns the currently active text. */
+SdrText* SdrTableObj::getActiveText() const
+{
+ return getActiveCell().get();
+}
+
+
+/** returns the nth available text. */
+SdrText* SdrTableObj::getText( sal_Int32 nIndex ) const
+{
+ if( mpImpl->mxTable.is() )
+ {
+ const sal_Int32 nColCount = mpImpl->getColumnCount();
+ if( nColCount )
+ {
+ CellPos aPos( nIndex % nColCount, nIndex / nColCount );
+
+ CellRef xCell( mpImpl->getCell( aPos ) );
+ return xCell.get();
+ }
+ }
+ return nullptr;
+}
+
+
+/** returns the number of texts available for this object. */
+sal_Int32 SdrTableObj::getTextCount() const
+{
+ if( mpImpl->mxTable.is() )
+ {
+ const sal_Int32 nColCount = mpImpl->getColumnCount();
+ const sal_Int32 nRowCount = mpImpl->getRowCount();
+
+ return nColCount * nRowCount;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+/** changes the current active text */
+void SdrTableObj::setActiveText( sal_Int32 nIndex )
+{
+ if( mpImpl.is() && mpImpl->mxTable.is() )
+ {
+ const sal_Int32 nColCount = mpImpl->mxTable->getColumnCount();
+ if( nColCount )
+ {
+ CellPos aPos( nIndex % nColCount, nIndex / nColCount );
+ if( isValid( aPos ) )
+ setActiveCell( aPos );
+ }
+ }
+}
+
+
+/** returns the index of the text that contains the given point or -1 */
+sal_Int32 SdrTableObj::CheckTextHit(const Point& rPnt) const
+{
+ if( mpImpl.is() && mpImpl->mxTable.is() )
+ {
+ CellPos aPos;
+ if( CheckTableHit( rPnt, aPos.mnCol, aPos.mnRow ) == TableHitKind::CellTextArea )
+ return aPos.mnRow * mpImpl->mxTable->getColumnCount() + aPos.mnCol;
+ }
+
+ return 0;
+}
+
+SdrOutliner* SdrTableObj::GetCellTextEditOutliner( const Cell& rCell ) const
+{
+ if( mpImpl.is() && (mpImpl->getCell( mpImpl->maEditPos ).get() == &rCell) )
+ return mpEditingOutliner;
+ else
+ return nullptr;
+}
+
+const TableLayouter& SdrTableObj::getTableLayouter() const
+{
+ assert(mpImpl.is() && mpImpl->mpLayouter && "getTableLayouter() error: no mpImpl or mpLayouter (!)");
+ return *(mpImpl->mpLayouter);
+}
+
+bool SdrTableObj::IsAutoGrowHeight() const
+{
+ return true;
+}
+
+bool SdrTableObj::IsAutoGrowWidth() const
+{
+ return true;
+}
+
+bool SdrTableObj::HasText() const
+{
+ return true;
+}
+
+bool SdrTableObj::IsTextEditActive( const CellPos& rPos )
+{
+ return mpEditingOutliner && mpImpl.is() && (rPos == mpImpl->maEditPos);
+}
+
+
+void SdrTableObj::onEditOutlinerStatusEvent( EditStatus* pEditStatus )
+{
+ if( (pEditStatus->GetStatusWord() & EditStatusFlags::TextHeightChanged) && mpImpl.is() && mpImpl->mpLayouter )
+ {
+ tools::Rectangle aRect0( maRect );
+ maRect = maLogicRect;
+ mpImpl->LayoutTable( maRect, false, false );
+ SetBoundAndSnapRectsDirty();
+ ActionChanged();
+ BroadcastObjectChange();
+ if (aRect0 != maRect)
+ SendUserCall(SdrUserCallType::Resize,aRect0);
+ }
+}
+
+
+void SdrTableObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bResizeFreeAllowed=true;
+ rInfo.bResizePropAllowed=true;
+ rInfo.bRotateFreeAllowed=false;
+ rInfo.bRotate90Allowed =false;
+ rInfo.bMirrorFreeAllowed=false;
+ rInfo.bMirror45Allowed =false;
+ rInfo.bMirror90Allowed =false;
+
+ // allow transparence
+ rInfo.bTransparenceAllowed = true;
+
+ rInfo.bShearAllowed =false;
+ rInfo.bEdgeRadiusAllowed=false;
+ rInfo.bCanConvToPath =false;
+ rInfo.bCanConvToPoly =false;
+ rInfo.bCanConvToPathLineToArea=false;
+ rInfo.bCanConvToPolyLineToArea=false;
+ rInfo.bCanConvToContour = false;
+}
+
+SdrObjKind SdrTableObj::GetObjIdentifier() const
+{
+ return SdrObjKind::Table;
+}
+
+void SdrTableObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect, bool /*bLineWidth*/ ) const
+{
+ if( mpImpl.is() )
+ TakeTextRect( mpImpl->maEditPos, rOutliner, rTextRect, bNoEditText, pAnchorRect );
+}
+
+
+void SdrTableObj::TakeTextRect( const CellPos& rPos, SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect ) const
+{
+ if( !mpImpl.is())
+ return;
+
+ CellRef xCell( mpImpl->getCell( rPos ) );
+ if( !xCell.is() )
+ return;
+
+ tools::Rectangle aAnkRect;
+ TakeTextAnchorRect( rPos, aAnkRect );
+
+ SdrTextVertAdjust eVAdj=xCell->GetTextVerticalAdjust();
+
+ EEControlBits nStat0=rOutliner.GetControlWord();
+ nStat0 |= EEControlBits::AUTOPAGESIZE;
+ rOutliner.SetControlWord(nStat0);
+ rOutliner.SetMinAutoPaperSize(Size());
+ rOutliner.SetMaxAutoPaperSize(aAnkRect.GetSize());
+ rOutliner.SetPaperSize(aAnkRect.GetSize());
+
+ // #103516# New try with _BLOCK for hor and ver after completely
+ // supporting full width for vertical text.
+// if( SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
+// {
+ rOutliner.SetMinAutoPaperSize(Size(aAnkRect.GetWidth(), 0));
+// }
+// else if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
+// {
+// rOutliner.SetMinAutoPaperSize(Size(0, aAnkRect.GetHeight()));
+// }
+
+
+ // set text at outliner, maybe from edit outliner
+ std::optional<OutlinerParaObject> pPara;
+ if (xCell->GetOutlinerParaObject())
+ pPara = *xCell->GetOutlinerParaObject();
+ if (mpEditingOutliner && !bNoEditText && mpImpl->mxActiveCell == xCell )
+ pPara = mpEditingOutliner->CreateParaObject();
+
+ if (pPara)
+ {
+ const bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner);
+ const SdrTextObj* pTestObj(rOutliner.GetTextObj());
+
+ if( !pTestObj || !bHitTest || (pTestObj != this) || (pTestObj->GetOutlinerParaObject() != xCell->GetOutlinerParaObject()) )
+ {
+ if( bHitTest ) // #i33696# take back fix #i27510#
+ rOutliner.SetTextObj( this );
+
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetText(*pPara);
+ }
+ }
+ else
+ {
+ rOutliner.SetTextObj( nullptr );
+ }
+
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetControlWord(nStat0);
+
+ Point aTextPos(aAnkRect.TopLeft());
+ Size aTextSiz(rOutliner.GetPaperSize());
+ if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
+ {
+ tools::Long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
+ if (eVAdj==SDRTEXTVERTADJUST_CENTER)
+ aTextPos.AdjustY(nFreeHgt/2 );
+ if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
+ aTextPos.AdjustY(nFreeHgt );
+ }
+
+ if (pAnchorRect)
+ *pAnchorRect=aAnkRect;
+
+ rTextRect=tools::Rectangle(aTextPos,aTextSiz);
+}
+
+
+const CellRef& SdrTableObj::getActiveCell() const
+{
+ if( mpImpl.is() )
+ {
+ if( !mpImpl->mxActiveCell.is() )
+ {
+ CellPos aPos;
+ const_cast< SdrTableObj* >(this)->setActiveCell( aPos );
+ }
+ return mpImpl->mxActiveCell;
+ }
+ else
+ {
+ static CellRef xCell;
+ return xCell;
+ }
+}
+
+
+sal_Int32 SdrTableObj::getColumnCount() const
+{
+ return mpImpl.is() ? mpImpl->getColumnCount() : 0;
+}
+
+sal_Int32 SdrTableObj::getRowCount() const
+{
+ return mpImpl.is() ? mpImpl->getRowCount() : 0;
+}
+
+void SdrTableObj::changeEdge(bool bHorizontal, int nEdge, sal_Int32 nOffset)
+{
+ if (mpImpl.is())
+ mpImpl->DragEdge(bHorizontal, nEdge, nOffset);
+}
+
+void SdrTableObj::setActiveCell( const CellPos& rPos )
+{
+ if( !(mpImpl.is() && mpImpl->mxTable.is()) )
+ return;
+
+ try
+ {
+ mpImpl->mxActiveCell.set( dynamic_cast< Cell* >( mpImpl->mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) );
+ if( mpImpl->mxActiveCell.is() && mpImpl->mxActiveCell->isMerged() )
+ {
+ CellPos aOrigin;
+ findMergeOrigin( mpImpl->mxTable, rPos.mnCol, rPos.mnRow, aOrigin.mnCol, aOrigin.mnRow );
+ mpImpl->mxActiveCell.set( dynamic_cast< Cell* >( mpImpl->mxTable->getCellByPosition( aOrigin.mnCol, aOrigin.mnRow ).get() ) );
+ mpImpl->maEditPos = aOrigin;
+ }
+ else
+ {
+ mpImpl->maEditPos = rPos;
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+}
+
+
+void SdrTableObj::getActiveCellPos( CellPos& rPos ) const
+{
+ rPos = mpImpl->maEditPos;
+}
+
+
+void SdrTableObj::getCellBounds( const CellPos& rPos, ::tools::Rectangle& rCellRect )
+{
+ if( mpImpl.is() )
+ {
+ CellRef xCell( mpImpl->getCell( rPos ) );
+ if( xCell.is() )
+ rCellRect = xCell->getCellRect();
+ }
+}
+
+
+void SdrTableObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
+{
+ if( mpImpl.is() )
+ TakeTextAnchorRect( mpImpl->maEditPos, rAnchorRect );
+}
+
+
+void SdrTableObj::TakeTextAnchorRect( const CellPos& rPos, tools::Rectangle& rAnchorRect ) const
+{
+ tools::Rectangle aAnkRect(maRect);
+
+ if( mpImpl.is() )
+ {
+ CellRef xCell( mpImpl->getCell( rPos ) );
+ if( xCell.is() )
+ xCell->TakeTextAnchorRect( aAnkRect );
+ }
+
+ ImpJustifyRect(aAnkRect);
+ rAnchorRect=aAnkRect;
+}
+
+
+void SdrTableObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
+{
+ if( mpImpl.is() )
+ TakeTextEditArea( mpImpl->maEditPos, pPaperMin, pPaperMax, pViewInit, pViewMin );
+}
+
+
+void SdrTableObj::TakeTextEditArea( const CellPos& rPos, Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin ) const
+{
+ Size aPaperMin,aPaperMax;
+ tools::Rectangle aViewInit;
+ TakeTextAnchorRect( rPos, aViewInit );
+
+ Size aAnkSiz(aViewInit.GetSize());
+ aAnkSiz.AdjustWidth( -1 ); aAnkSiz.AdjustHeight( -1 ); // because GetSize() increments by one
+
+ Size aMaxSiz(aAnkSiz.Width(),1000000);
+ Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
+ if (aTmpSiz.Height()!=0)
+ aMaxSiz.setHeight(aTmpSiz.Height() );
+
+ CellRef xCell( mpImpl->getCell( rPos ) );
+ SdrTextVertAdjust eVAdj = xCell.is() ? xCell->GetTextVerticalAdjust() : SDRTEXTVERTADJUST_TOP;
+
+ aPaperMax=aMaxSiz;
+
+ aPaperMin.setWidth( aAnkSiz.Width() );
+
+ if (pViewMin!=nullptr)
+ {
+ *pViewMin=aViewInit;
+ tools::Long nYFree=aAnkSiz.Height()-aPaperMin.Height();
+
+ if (eVAdj==SDRTEXTVERTADJUST_TOP)
+ {
+ pViewMin->AdjustBottom( -nYFree );
+ }
+ else if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
+ {
+ pViewMin->AdjustTop(nYFree );
+ }
+ else
+ {
+ pViewMin->AdjustTop(nYFree/2 );
+ pViewMin->SetBottom(pViewMin->Top()+aPaperMin.Height() );
+ }
+ }
+
+
+ if(IsVerticalWriting())
+ aPaperMin.setWidth( 0 );
+ else
+ aPaperMin.setHeight( 0 );
+
+ if (pPaperMin!=nullptr) *pPaperMin=aPaperMin;
+ if (pPaperMax!=nullptr) *pPaperMax=aPaperMax;
+ if (pViewInit!=nullptr) *pViewInit=aViewInit;
+}
+
+
+EEAnchorMode SdrTableObj::GetOutlinerViewAnchorMode() const
+{
+ EEAnchorMode eRet=EEAnchorMode::TopLeft;
+ CellRef xCell( getActiveCell() );
+ if( xCell.is() )
+ {
+ SdrTextVertAdjust eV=xCell->GetTextVerticalAdjust();
+
+ {
+ if (eV==SDRTEXTVERTADJUST_TOP)
+ {
+ eRet=EEAnchorMode::TopLeft;
+ }
+ else if (eV==SDRTEXTVERTADJUST_BOTTOM)
+ {
+ eRet=EEAnchorMode::BottomLeft;
+ }
+ else
+ {
+ eRet=EEAnchorMode::VCenterLeft;
+ }
+ }
+ }
+ return eRet;
+}
+
+
+OUString SdrTableObj::TakeObjNameSingul() const
+{
+ OUString sName(SvxResId(STR_ObjNameSingulTable));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ sName += " '" + aName + "'";
+
+ return sName;
+}
+
+
+OUString SdrTableObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralTable);
+}
+
+
+SdrTableObj* SdrTableObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrTableObj(rTargetModel, *this);
+}
+
+
+const tools::Rectangle& SdrTableObj::GetSnapRect() const
+{
+ return maRect;
+}
+
+
+void SdrTableObj::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ NbcSetLogicRect( rRect );
+}
+
+
+const tools::Rectangle& SdrTableObj::GetLogicRect() const
+{
+ return maLogicRect;
+}
+
+
+void SdrTableObj::RecalcSnapRect()
+{
+}
+
+
+bool SdrTableObj::BegTextEdit(SdrOutliner& rOutl)
+{
+ if( mpEditingOutliner != nullptr )
+ return false;
+
+ mpEditingOutliner=&rOutl;
+
+ mbInEditMode = true;
+
+ rOutl.Init( OutlinerMode::TextObject );
+ rOutl.SetRefDevice(getSdrModelFromSdrObject().GetRefDevice());
+
+ bool bUpdateMode = rOutl.SetUpdateLayout(false);
+ Size aPaperMin;
+ Size aPaperMax;
+ tools::Rectangle aEditArea;
+ TakeTextEditArea(&aPaperMin,&aPaperMax,&aEditArea,nullptr);
+
+ rOutl.SetMinAutoPaperSize(aPaperMin);
+ rOutl.SetMaxAutoPaperSize(aPaperMax);
+ rOutl.SetPaperSize(aPaperMax);
+
+ if (bUpdateMode) rOutl.SetUpdateLayout(true);
+
+ EEControlBits nStat=rOutl.GetControlWord();
+ nStat |= EEControlBits::AUTOPAGESIZE;
+ nStat &=~EEControlBits::STRETCHING;
+ rOutl.SetControlWord(nStat);
+
+ OutlinerParaObject* pPara = GetOutlinerParaObject();
+ if(pPara)
+ rOutl.SetText(*pPara);
+
+ rOutl.UpdateFields();
+ rOutl.ClearModifyFlag();
+
+ return true;
+}
+
+
+void SdrTableObj::EndTextEdit(SdrOutliner& rOutl)
+{
+
+ if (getSdrModelFromSdrObject().IsUndoEnabled() && !mpImpl->maUndos.empty())
+ {
+ // These actions should be on the undo stack after text edit.
+ for (std::unique_ptr<SdrUndoAction>& pAction : mpImpl->maUndos)
+ getSdrModelFromSdrObject().AddUndo( std::move(pAction));
+ mpImpl->maUndos.clear();
+
+ getSdrModelFromSdrObject().AddUndo(getSdrModelFromSdrObject().GetSdrUndoFactory().CreateUndoGeoObject(*this));
+ }
+
+ if(rOutl.IsModified())
+ {
+ std::optional<OutlinerParaObject> pNewText;
+ Paragraph* p1stPara = rOutl.GetParagraph( 0 );
+ sal_Int32 nParaCnt = rOutl.GetParagraphCount();
+
+ if(p1stPara)
+ {
+ // to remove the grey field background
+ rOutl.UpdateFields();
+
+ // create new text object
+ pNewText = rOutl.CreateParaObject( 0, nParaCnt );
+ }
+ SetOutlinerParaObject(std::move(pNewText));
+ }
+
+ mpEditingOutliner = nullptr;
+ rOutl.Clear();
+ EEControlBits nStat = rOutl.GetControlWord();
+ nStat &= ~EEControlBits::AUTOPAGESIZE;
+ rOutl.SetControlWord(nStat);
+
+ mbInEditMode = false;
+}
+
+
+OutlinerParaObject* SdrTableObj::GetOutlinerParaObject() const
+{
+ CellRef xCell( getActiveCell() );
+ if( xCell.is() )
+ return xCell->GetOutlinerParaObject();
+ else
+ return nullptr;
+}
+
+
+void SdrTableObj::NbcSetOutlinerParaObject( std::optional<OutlinerParaObject> pTextObject)
+{
+ CellRef xCell( getActiveCell() );
+ if( !xCell.is() )
+ return;
+
+ // Update HitTestOutliner
+ const SdrTextObj* pTestObj(getSdrModelFromSdrObject().GetHitTestOutliner().GetTextObj());
+
+ if(pTestObj && pTestObj->GetOutlinerParaObject() == xCell->GetOutlinerParaObject())
+ {
+ getSdrModelFromSdrObject().GetHitTestOutliner().SetTextObj(nullptr);
+ }
+
+ xCell->SetOutlinerParaObject( std::move(pTextObject) );
+ SetTextSizeDirty();
+ NbcAdjustTextFrameWidthAndHeight();
+}
+
+
+void SdrTableObj::NbcSetLogicRect(const tools::Rectangle& rRect)
+{
+ maLogicRect=rRect;
+ ImpJustifyRect(maLogicRect);
+ const bool bWidth = maLogicRect.getWidth() != maRect.getWidth();
+ const bool bHeight = maLogicRect.getHeight() != maRect.getHeight();
+ maRect = maLogicRect;
+ if (mpImpl->mbSkipChangeLayout)
+ // Avoid distributing newly available space between existing cells.
+ NbcAdjustTextFrameWidthAndHeight();
+ else
+ NbcAdjustTextFrameWidthAndHeight(!bHeight, !bWidth);
+ SetBoundAndSnapRectsDirty();
+}
+
+
+void SdrTableObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
+{
+ tools::Rectangle aAdjustRect( rMaxRect );
+ aAdjustRect.setHeight( GetLogicRect().getHeight() );
+ SetLogicRect( aAdjustRect );
+}
+
+
+void SdrTableObj::NbcMove(const Size& rSiz)
+{
+ maLogicRect.Move(rSiz);
+ SdrTextObj::NbcMove( rSiz );
+ if( mpImpl.is() )
+ mpImpl->UpdateCells( maRect );
+}
+
+
+void SdrTableObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ tools::Rectangle aOldRect( maLogicRect );
+ ResizeRect(maLogicRect,rRef,xFact,yFact);
+
+ maRect = maLogicRect;
+ NbcAdjustTextFrameWidthAndHeight( maLogicRect.GetHeight() == aOldRect.GetHeight(), maLogicRect.GetWidth() == aOldRect.GetWidth() );
+ SetBoundAndSnapRectsDirty();
+}
+
+
+bool SdrTableObj::AdjustTextFrameWidthAndHeight()
+{
+ tools::Rectangle aNewRect(maLogicRect);
+ bool bRet=AdjustTextFrameWidthAndHeight(aNewRect);
+ if (bRet)
+ {
+ tools::Rectangle aBoundRect0;
+ if (m_pUserCall!=nullptr)
+ aBoundRect0=GetLastBoundRect();
+ maRect = aNewRect;
+ SetBoundAndSnapRectsDirty();
+ SetChanged();
+ BroadcastObjectChange();
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+ return bRet;
+}
+
+
+bool SdrTableObj::AdjustTextFrameWidthAndHeight(tools::Rectangle& rR, bool bHeight, bool bWidth) const
+{
+ if(rR.IsEmpty() || !mpImpl.is() || !mpImpl->mxTable.is())
+ return false;
+
+ tools::Rectangle aRectangle( rR );
+ mpImpl->LayoutTable( aRectangle, !bWidth, !bHeight );
+
+ if( aRectangle != rR )
+ {
+ rR = aRectangle;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void SdrTableObj::NbcReformatText()
+{
+ NbcAdjustTextFrameWidthAndHeight();
+}
+
+
+bool SdrTableObj::IsVerticalWriting() const
+{
+ const SvxWritingModeItem& rModeItem = GetObjectItem( SDRATTR_TEXTDIRECTION );
+ return rModeItem.GetValue() == css::text::WritingMode_TB_RL;
+}
+
+
+void SdrTableObj::SetVerticalWriting(bool bVertical)
+{
+ if(bVertical != IsVerticalWriting() )
+ {
+ SvxWritingModeItem aModeItem( css::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION );
+ SetObjectItem( aModeItem );
+ }
+}
+
+
+WritingMode SdrTableObj::GetWritingMode() const
+{
+ SfxStyleSheet* pStyle = GetStyleSheet();
+ if ( !pStyle )
+ return WritingMode_LR_TB;
+
+ WritingMode eWritingMode = WritingMode_LR_TB;
+ const SfxItemSet &rSet = pStyle->GetItemSet();
+
+ if ( const SvxWritingModeItem *pItem = rSet.GetItemIfSet( SDRATTR_TEXTDIRECTION ))
+ eWritingMode = pItem->GetValue();
+
+ if ( const SvxFrameDirectionItem *pItem;
+ ( eWritingMode != WritingMode_TB_RL ) &&
+ ( pItem = rSet.GetItemIfSet( EE_PARA_WRITINGDIR, false ) ) )
+ {
+ if ( pItem->GetValue() == SvxFrameDirection::Horizontal_LR_TB )
+ eWritingMode = WritingMode_LR_TB;
+ else
+ eWritingMode = WritingMode_RL_TB;
+ }
+
+ return eWritingMode;
+}
+
+void SdrTableObj::AddUndo(SdrUndoAction* pUndo)
+{
+ mpImpl->maUndos.push_back(std::unique_ptr<SdrUndoAction>(pUndo));
+}
+
+void SdrTableObj::SetSkipChangeLayout(bool bSkipChangeLayout)
+{
+ mpImpl->mbSkipChangeLayout = bSkipChangeLayout;
+}
+
+bool SdrTableObj::IsReallyEdited() const
+{
+ return mpEditingOutliner && mpEditingOutliner->IsModified();
+}
+
+bool SdrTableObj::IsFontwork() const
+{
+ return false;
+}
+
+sal_uInt32 SdrTableObj::GetHdlCount() const
+{
+ sal_uInt32 nCount = SdrTextObj::GetHdlCount();
+ const sal_Int32 nRowCount = mpImpl->getRowCount();
+ const sal_Int32 nColCount = mpImpl->getColumnCount();
+
+ if( nRowCount && nColCount )
+ nCount += nRowCount + nColCount + 2 + 1;
+
+ return nCount;
+}
+
+void SdrTableObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ const sal_Int32 nRowCount = mpImpl->getRowCount();
+ const sal_Int32 nColCount = mpImpl->getColumnCount();
+
+ // first add row handles
+ std::vector<TableEdgeHdl*> aRowEdges(nRowCount + 1);
+ for (auto const & rEdge : mpImpl->mpLayouter->getHorizontalEdges())
+ {
+ Point aPoint(maRect.TopLeft());
+ aPoint.AdjustY(rEdge.nPosition);
+
+ std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, true, rEdge.nMin, rEdge.nMax, nColCount + 1));
+ pHdl->SetPointNum(rEdge.nIndex);
+ aRowEdges[rEdge.nIndex] = pHdl.get();
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+
+ // second add column handles
+ std::vector<TableEdgeHdl*> aColEdges(nColCount + 1);
+ for (auto const & rEdge : mpImpl->mpLayouter->getVerticalEdges())
+ {
+ Point aPoint(maRect.TopLeft());
+ aPoint.AdjustX(rEdge.nPosition);
+
+ std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, false, rEdge.nMin, rEdge.nMax, nRowCount + 1));
+ pHdl->SetPointNum(rEdge.nIndex);
+ aColEdges[rEdge.nIndex] = pHdl.get();
+ rHdlList.AddHdl(std::move(pHdl));
+ }
+
+ // now add visible edges to row and column handles
+ if( mpImpl->mpLayouter )
+ {
+ TableLayouter& rLayouter = *mpImpl->mpLayouter;
+
+ sal_Int32 nY = 0;
+
+ for( sal_Int32 nRow = 0; nRow <= nRowCount; ++nRow )
+ {
+ const sal_Int32 nRowHeight = (nRow == nRowCount) ? 0 : rLayouter.getRowHeight(nRow);
+ sal_Int32 nX = 0;
+
+ for( sal_Int32 nCol = 0; nCol <= nColCount; ++nCol )
+ {
+ const sal_Int32 nColWidth = (nCol == nColCount) ? 0 : rLayouter.getColumnWidth(nCol);
+
+ if( nRowHeight > 0 )
+ {
+ if( rLayouter.isEdgeVisible( nCol, nRow, false ) )
+ aColEdges[nCol]->SetEdge( nRow, nY, nY + nRowHeight, (rLayouter.getBorderLine( nCol, nRow, false ) == nullptr) ? Visible : Invisible);
+ }
+
+ if( nColWidth > 0 )
+ {
+ if( rLayouter.isEdgeVisible( nCol, nRow, true ) )
+ aRowEdges[nRow]->SetEdge( nCol, nX, nX + nColWidth, (rLayouter.getBorderLine( nCol, nRow, true ) == nullptr) ? Visible : Invisible);
+ }
+
+ nX += nColWidth;
+ }
+
+ nY += nRowHeight;
+ }
+ }
+
+ // add remaining handles
+ SdrHdlList tempList(nullptr);
+ tempList.AddHdl( std::make_unique<TableBorderHdl>( maRect, !IsTextEditActive() ) );
+ tempList.AddHdl( std::make_unique<SdrHdl>(maRect.TopLeft(),SdrHdlKind::UpperLeft) );
+ tempList.AddHdl( std::make_unique<SdrHdl>(maRect.TopCenter(),SdrHdlKind::Upper) );
+ tempList.AddHdl( std::make_unique<SdrHdl>(maRect.TopRight(),SdrHdlKind::UpperRight) );
+ tempList.AddHdl( std::make_unique<SdrHdl>(maRect.LeftCenter(),SdrHdlKind::Left) );
+ tempList.AddHdl( std::make_unique<SdrHdl>(maRect.RightCenter(),SdrHdlKind::Right) );
+ tempList.AddHdl( std::make_unique<SdrHdl>(maRect.BottomLeft(),SdrHdlKind::LowerLeft) );
+ tempList.AddHdl( std::make_unique<SdrHdl>(maRect.BottomCenter(),SdrHdlKind::Lower) );
+ tempList.AddHdl( std::make_unique<SdrHdl>(maRect.BottomRight(),SdrHdlKind::LowerRight) );
+ for( size_t nHdl = 0; nHdl < tempList.GetHdlCount(); ++nHdl )
+ tempList.GetHdl(nHdl)->SetMoveOutside(true);
+ tempList.MoveTo(rHdlList);
+
+ const size_t nHdlCount = rHdlList.GetHdlCount();
+ for( size_t nHdl = 0; nHdl < nHdlCount; ++nHdl )
+ rHdlList.GetHdl(nHdl)->SetObj(const_cast<SdrTableObj*>(this));
+}
+
+// Dragging
+
+bool SdrTableObj::hasSpecialDrag() const
+{
+ return true;
+}
+
+bool SdrTableObj::beginSpecialDrag(SdrDragStat& rDrag) const
+{
+ const SdrHdl* pHdl = rDrag.GetHdl();
+ const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
+
+ switch( eHdl )
+ {
+ case SdrHdlKind::UpperLeft:
+ case SdrHdlKind::Upper:
+ case SdrHdlKind::UpperRight:
+ case SdrHdlKind::Left:
+ case SdrHdlKind::Right:
+ case SdrHdlKind::LowerLeft:
+ case SdrHdlKind::Lower:
+ case SdrHdlKind::LowerRight:
+ case SdrHdlKind::Move:
+ {
+ break;
+ }
+
+ case SdrHdlKind::User:
+ {
+ rDrag.SetEndDragChangesAttributes(false);
+ rDrag.SetNoSnap();
+ break;
+ }
+
+ default:
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool SdrTableObj::applySpecialDrag(SdrDragStat& rDrag)
+{
+ bool bRet(true);
+ const SdrHdl* pHdl = rDrag.GetHdl();
+ const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
+
+ switch( eHdl )
+ {
+ case SdrHdlKind::UpperLeft:
+ case SdrHdlKind::Upper:
+ case SdrHdlKind::UpperRight:
+ case SdrHdlKind::Left:
+ case SdrHdlKind::Right:
+ case SdrHdlKind::LowerLeft:
+ case SdrHdlKind::Lower:
+ case SdrHdlKind::LowerRight:
+ {
+ const tools::Rectangle aNewRectangle(ImpDragCalcRect(rDrag));
+
+ if (aNewRectangle != maRect)
+ {
+ NbcSetLogicRect(aNewRectangle);
+ }
+
+ break;
+ }
+
+ case SdrHdlKind::Move:
+ {
+ NbcMove( Size( rDrag.GetDX(), rDrag.GetDY() ) );
+ break;
+ }
+
+ case SdrHdlKind::User:
+ {
+ rDrag.SetEndDragChangesAttributes(false);
+ rDrag.SetNoSnap();
+ const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl );
+
+ if( pEdgeHdl )
+ {
+ if( IsInserted() )
+ {
+ rDrag.SetEndDragChangesAttributes(true);
+ rDrag.SetEndDragChangesLayout(true);
+ }
+
+ mpImpl->DragEdge( pEdgeHdl->IsHorizontalEdge(), pEdgeHdl->GetPointNum(), pEdgeHdl->GetValidDragOffset( rDrag ) );
+ }
+ break;
+ }
+
+ default:
+ {
+ bRet = false;
+ }
+ }
+
+ return bRet;
+}
+
+basegfx::B2DPolyPolygon SdrTableObj::getSpecialDragPoly(const SdrDragStat& rDrag) const
+{
+ basegfx::B2DPolyPolygon aRetval;
+ const SdrHdl* pHdl = rDrag.GetHdl();
+
+ if( pHdl && (SdrHdlKind::User == pHdl->GetKind()) )
+ {
+ const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl );
+
+ if( pEdgeHdl )
+ {
+ aRetval = pEdgeHdl->getSpecialDragPoly( rDrag );
+ }
+ }
+
+ return aRetval;
+}
+
+
+// Create
+
+
+bool SdrTableObj::BegCreate(SdrDragStat& rStat)
+{
+ rStat.SetOrtho4Possible();
+ tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
+ aRect1.Justify();
+ rStat.SetActionRect(aRect1);
+ maRect = aRect1;
+ return true;
+}
+
+
+bool SdrTableObj::MovCreate(SdrDragStat& rStat)
+{
+ tools::Rectangle aRect1;
+ rStat.TakeCreateRect(aRect1);
+ ImpJustifyRect(aRect1);
+ rStat.SetActionRect(aRect1);
+ maRect = aRect1; // for ObjName
+ SetBoundRectDirty();
+ m_bSnapRectDirty=true;
+ return true;
+}
+
+
+bool SdrTableObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ rStat.TakeCreateRect(maRect);
+ ImpJustifyRect(maRect);
+ return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
+}
+
+void SdrTableObj::BrkCreate(SdrDragStat& /*rStat*/)
+{
+}
+
+
+bool SdrTableObj::BckCreate(SdrDragStat& /*rStat*/)
+{
+ return true;
+}
+
+
+basegfx::B2DPolyPolygon SdrTableObj::TakeCreatePoly(const SdrDragStat& rDrag) const
+{
+ tools::Rectangle aRect1;
+ rDrag.TakeCreateRect(aRect1);
+ aRect1.Justify();
+
+ basegfx::B2DPolyPolygon aRetval;
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aRect1);
+ aRetval.append(basegfx::utils::createPolygonFromRect(aRange));
+ return aRetval;
+}
+
+
+PointerStyle SdrTableObj::GetCreatePointer() const
+{
+ return PointerStyle::Cross;
+}
+
+
+void SdrTableObj::createCell( CellRef& xNewCell )
+{
+ xNewCell = Cell::create( *this );
+}
+
+
+std::unique_ptr<SdrObjGeoData> SdrTableObj::NewGeoData() const
+{
+ return std::make_unique<TableObjectGeoData>();
+}
+
+
+void SdrTableObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ DBG_ASSERT( dynamic_cast< TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::SaveGeoData(), illegal geo data!" );
+ SdrTextObj::SaveGeoData (rGeo);
+
+ static_cast<TableObjectGeoData &>(rGeo).maLogicRect = maLogicRect;
+}
+
+
+void SdrTableObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ DBG_ASSERT( dynamic_cast< const TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::SaveGeoData(), illegal geo data!" );
+
+ maLogicRect = static_cast<const TableObjectGeoData &>(rGeo).maLogicRect;
+
+ SdrTextObj::RestoreGeoData (rGeo);
+
+ if( mpImpl.is() )
+ mpImpl->LayoutTable(maRect, false, false);
+ ActionChanged();
+}
+
+void SdrTableObj::CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd)
+{
+ if(!mpImpl.is())
+ {
+ return;
+ }
+
+ mpImpl->CropTableModelToSelection(rStart, rEnd);
+}
+
+sal_Int32 SdrTableObj::getHeightWithoutFitting()
+{
+ tools::Rectangle aRect{};
+ if( mpImpl.is() && mpImpl->mpLayouter)
+ {
+ mpImpl->mpLayouter->LayoutTableHeight(aRect, /*bFit=*/false);
+ return aRect.GetHeight();
+ }
+ else
+ return 0;
+}
+
+void SdrTableObj::DistributeColumns( sal_Int32 nFirstColumn, sal_Int32 nLastColumn, const bool bOptimize, const bool bMinimize )
+{
+ if( mpImpl.is() && mpImpl->mpLayouter )
+ {
+ TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
+ mpImpl->mpLayouter->DistributeColumns( maRect, nFirstColumn, nLastColumn, bOptimize, bMinimize );
+ }
+}
+
+
+void SdrTableObj::DistributeRows( sal_Int32 nFirstRow, sal_Int32 nLastRow, const bool bOptimize, const bool bMinimize )
+{
+ if( mpImpl.is() && mpImpl->mpLayouter )
+ {
+ TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
+ mpImpl->mpLayouter->DistributeRows( maRect, nFirstRow, nLastRow, bOptimize, bMinimize );
+ }
+}
+
+
+void SdrTableObj::SetChanged()
+{
+ if( mpImpl.is() )
+ {
+ mpImpl->LayoutTable( maRect, false, false );
+ }
+
+ ::SdrTextObj::SetChanged();
+}
+
+
+void SdrTableObj::uno_lock()
+{
+ if( mpImpl.is() && mpImpl->mxTable.is() )
+ mpImpl->mxTable->lockBroadcasts();
+}
+
+
+void SdrTableObj::uno_unlock()
+{
+ if( mpImpl.is() && mpImpl->mxTable.is() )
+ mpImpl->mxTable->unlockBroadcasts();
+}
+
+void SdrTableObj::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTableObj"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+
+ SdrObject::dumpAsXml(pWriter);
+
+ mpImpl->dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+bool SdrTableObj::createTableEdgesJson(boost::property_tree::ptree & rJsonRoot)
+{
+ if (!mpImpl.is() || !mpImpl->mxTable.is())
+ return false;
+
+ tools::Rectangle aRect = GetCurrentBoundRect();
+ boost::property_tree::ptree aTableColumns;
+ {
+ aTableColumns.put("tableOffset", o3tl::toTwips(aRect.Left(), o3tl::Length::mm100));
+
+ boost::property_tree::ptree aEntries;
+ auto const & aEdges = mpImpl->mpLayouter->getVerticalEdges();
+ for (auto & rEdge : aEdges)
+ {
+ if (rEdge.nIndex == 0)
+ {
+ aTableColumns.put("left", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
+ }
+ else if (rEdge.nIndex == sal_Int32(aEdges.size() - 1))
+ {
+ aTableColumns.put("right", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
+ }
+ else
+ {
+ boost::property_tree::ptree aEntry;
+ aEntry.put("position", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
+ aEntry.put("min", o3tl::toTwips(rEdge.nPosition + rEdge.nMin, o3tl::Length::mm100));
+ aEntry.put("max", o3tl::toTwips(rEdge.nPosition + rEdge.nMax, o3tl::Length::mm100));
+ aEntry.put("hidden", false);
+ aEntries.push_back(std::make_pair("", aEntry));
+ }
+ }
+ aTableColumns.push_back(std::make_pair("entries", aEntries));
+ }
+ rJsonRoot.add_child("columns", aTableColumns);
+
+ boost::property_tree::ptree aTableRows;
+ {
+ aTableRows.put("tableOffset", o3tl::toTwips(aRect.Top(), o3tl::Length::mm100));
+
+ boost::property_tree::ptree aEntries;
+ auto const & aEdges = mpImpl->mpLayouter->getHorizontalEdges();
+ for (auto & rEdge : aEdges)
+ {
+ if (rEdge.nIndex == 0)
+ {
+ aTableRows.put("left", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
+ }
+ else if (rEdge.nIndex == sal_Int32(aEdges.size() - 1))
+ {
+ aTableRows.put("right", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
+ }
+ else
+ {
+ boost::property_tree::ptree aEntry;
+ aEntry.put("position", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
+ aEntry.put("min", o3tl::toTwips(rEdge.nPosition + rEdge.nMin, o3tl::Length::mm100));
+ aEntry.put("max", o3tl::toTwips(rEdge.nPosition + rEdge.nMax, o3tl::Length::mm100));
+ aEntry.put("hidden", false);
+ aEntries.push_back(std::make_pair("", aEntry));
+ }
+ }
+ aTableRows.push_back(std::make_pair("entries", aEntries));
+ }
+ rJsonRoot.add_child("rows", aTableRows);
+ return true;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablecolumn.cxx b/svx/source/table/tablecolumn.cxx
new file mode 100644
index 000000000..d9e33db47
--- /dev/null
+++ b/svx/source/table/tablecolumn.cxx
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <tablemodel.hxx>
+#include "tablecolumn.hxx"
+#include "tableundo.hxx"
+#include <svx/svdmodel.hxx>
+#include <svx/svdotable.hxx>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::beans;
+
+
+namespace sdr::table {
+
+const sal_Int32 Property_Width = 0;
+const sal_Int32 Property_OptimalWidth = 1;
+const sal_Int32 Property_IsVisible = 2;
+const sal_Int32 Property_IsStartOfNewPage = 3;
+
+
+// TableRow
+
+
+TableColumn::TableColumn( const TableModelRef& xTableModel, sal_Int32 nColumn )
+: TableColumnBase( getStaticPropertySetInfo() )
+, mxTableModel( xTableModel )
+, mnColumn( nColumn )
+, mnWidth( 0 )
+, mbOptimalWidth( true )
+, mbIsVisible( true )
+, mbIsStartOfNewPage( false )
+{
+}
+
+
+TableColumn::~TableColumn()
+{
+}
+
+
+void TableColumn::dispose()
+{
+ mxTableModel.clear();
+}
+
+
+void TableColumn::throwIfDisposed() const
+{
+ if( !mxTableModel.is() )
+ throw DisposedException();
+}
+
+
+TableColumn& TableColumn::operator=( const TableColumn& r )
+{
+ mnWidth = r.mnWidth;
+ mbOptimalWidth = r.mbOptimalWidth;
+ mbIsVisible = r.mbIsVisible;
+ mbIsStartOfNewPage = r.mbIsStartOfNewPage;
+ maName = r.maName;
+ mnColumn = r.mnColumn;
+
+ return *this;
+}
+
+
+// XCellRange
+
+
+Reference< XCell > SAL_CALL TableColumn::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow )
+{
+ throwIfDisposed();
+ if( nColumn != 0 )
+ throw IndexOutOfBoundsException();
+
+ return mxTableModel->getCellByPosition( mnColumn, nRow );
+}
+
+
+Reference< XCellRange > SAL_CALL TableColumn::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ throwIfDisposed();
+ if( (nTop >= 0 ) && (nLeft == 0) && (nBottom >= nTop) && (nRight == 0) )
+ {
+ return mxTableModel->getCellRangeByPosition( mnColumn, nTop, mnColumn, nBottom );
+ }
+ throw IndexOutOfBoundsException();
+}
+
+
+Reference< XCellRange > SAL_CALL TableColumn::getCellRangeByName( const OUString& /*aRange*/ )
+{
+ return Reference< XCellRange >();
+}
+
+
+// XNamed
+
+
+OUString SAL_CALL TableColumn::getName()
+{
+ return maName;
+}
+
+
+void SAL_CALL TableColumn::setName( const OUString& aName )
+{
+ maName = aName;
+}
+
+
+// XFastPropertySet
+
+
+void SAL_CALL TableColumn::setFastPropertyValue( sal_Int32 nHandle, const Any& aValue )
+{
+ bool bOk = false;
+ bool bChange = false;
+
+ SdrModel& rModel(mxTableModel->getSdrTableObj()->getSdrModelFromSdrObject());
+ std::unique_ptr<TableColumnUndo> pUndo;
+
+ if( mxTableModel.is() && mxTableModel->getSdrTableObj() && mxTableModel->getSdrTableObj()->IsInserted() && rModel.IsUndoEnabled() )
+ {
+ TableColumnRef xThis( this );
+ pUndo.reset( new TableColumnUndo( xThis ) );
+ }
+
+ switch( nHandle )
+ {
+ case Property_Width:
+ {
+ sal_Int32 nWidth = mnWidth;
+ bOk = aValue >>= nWidth;
+ if( bOk && (nWidth != mnWidth) )
+ {
+ mnWidth = nWidth;
+ mbOptimalWidth = mnWidth == 0;
+ bChange = true;
+ }
+ break;
+ }
+ case Property_OptimalWidth:
+ {
+ bool bOptimalWidth = mbOptimalWidth;
+ bOk = aValue >>= bOptimalWidth;
+ if( bOk && (mbOptimalWidth != bOptimalWidth) )
+ {
+ mbOptimalWidth = bOptimalWidth;
+ if( bOptimalWidth )
+ mnWidth = 0;
+ bChange = true;
+ }
+ break;
+ }
+ case Property_IsVisible:
+ {
+ bool bIsVisible = mbIsVisible;
+ bOk = aValue >>= bIsVisible;
+ if( bOk && (mbIsVisible != bIsVisible) )
+ {
+ mbIsVisible = bIsVisible;
+ bChange = true;
+ }
+ break;
+ }
+
+ case Property_IsStartOfNewPage:
+ {
+ bool bIsStartOfNewPage = mbIsStartOfNewPage;
+ bOk = aValue >>= bIsStartOfNewPage;
+ if( bOk && (mbIsStartOfNewPage != bIsStartOfNewPage) )
+ {
+ mbIsStartOfNewPage = bIsStartOfNewPage;
+ bChange = true;
+ }
+ break;
+ }
+ default:
+ throw UnknownPropertyException( OUString::number(nHandle), static_cast<cppu::OWeakObject*>(this));
+ }
+ if( !bOk )
+ {
+ throw IllegalArgumentException();
+ }
+
+ if( bChange )
+ {
+ if( pUndo )
+ {
+ rModel.AddUndo( std::move(pUndo) );
+ }
+ mxTableModel->setModified(true);
+ }
+}
+
+
+Any SAL_CALL TableColumn::getFastPropertyValue( sal_Int32 nHandle )
+{
+ switch( nHandle )
+ {
+ case Property_Width: return Any( mnWidth );
+ case Property_OptimalWidth: return Any( mbOptimalWidth );
+ case Property_IsVisible: return Any( mbIsVisible );
+ case Property_IsStartOfNewPage: return Any( mbIsStartOfNewPage );
+ default: throw UnknownPropertyException( OUString::number(nHandle), static_cast<cppu::OWeakObject*>(this));
+ }
+}
+
+
+rtl::Reference< FastPropertySetInfo > TableColumn::getStaticPropertySetInfo()
+{
+ static rtl::Reference<FastPropertySetInfo> xInfo = []() {
+ PropertyVector aProperties(6);
+
+ aProperties[0].Name = "Width";
+ aProperties[0].Handle = Property_Width;
+ aProperties[0].Type = ::cppu::UnoType<sal_Int32>::get();
+ aProperties[0].Attributes = 0;
+
+ aProperties[1].Name = "OptimalWidth";
+ aProperties[1].Handle = Property_OptimalWidth;
+ aProperties[1].Type = cppu::UnoType<bool>::get();
+ aProperties[1].Attributes = 0;
+
+ aProperties[2].Name = "IsVisible";
+ aProperties[2].Handle = Property_IsVisible;
+ aProperties[2].Type = cppu::UnoType<bool>::get();
+ aProperties[2].Attributes = 0;
+
+ aProperties[3].Name = "IsStartOfNewPage";
+ aProperties[3].Handle = Property_IsStartOfNewPage;
+ aProperties[3].Type = cppu::UnoType<bool>::get();
+ aProperties[3].Attributes = 0;
+
+ aProperties[4].Name = "Size";
+ aProperties[4].Handle = Property_Width;
+ aProperties[4].Type = ::cppu::UnoType<sal_Int32>::get();
+ aProperties[4].Attributes = 0;
+
+ aProperties[5].Name = "OptimalSize";
+ aProperties[5].Handle = Property_OptimalWidth;
+ aProperties[5].Type = cppu::UnoType<bool>::get();
+ aProperties[5].Attributes = 0;
+
+ return rtl::Reference<FastPropertySetInfo>(new FastPropertySetInfo(aProperties));
+ }();
+
+ return xInfo;
+}
+
+TableModelRef const & TableColumn::getModel() const
+{
+ return mxTableModel;
+}
+
+sal_Int32 TableColumn::getWidth() const
+{
+ return mnWidth;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablecolumn.hxx b/svx/source/table/tablecolumn.hxx
new file mode 100644
index 000000000..0d1dbb802
--- /dev/null
+++ b/svx/source/table/tablecolumn.hxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_TABLECOLUMN_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_TABLECOLUMN_HXX
+
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include "propertyset.hxx"
+#include <celltypes.hxx>
+
+
+namespace sdr::table {
+
+typedef ::cppu::ImplInheritanceHelper< FastPropertySet, css::table::XCellRange, css::container::XNamed > TableColumnBase;
+
+class TableColumn : public TableColumnBase
+{
+ friend class TableColumnUndo;
+ friend class TableModel;
+public:
+ TableColumn( const TableModelRef& xTableModel, sal_Int32 nColumn );
+ virtual ~TableColumn() override;
+
+ void dispose();
+ /// @throws css::uno::RuntimeException
+ void throwIfDisposed() const;
+
+ TableColumn& operator=( const TableColumn& );
+
+ // XCellRange
+ virtual css::uno::Reference< css::table::XCell > SAL_CALL getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) override;
+ virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) override;
+ virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByName( const OUString& aRange ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+
+ // XFastPropertySet
+ virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) override;
+
+ /// Get the table that owns this column.
+ TableModelRef const & getModel() const;
+ /// Get the width of this column.
+ sal_Int32 getWidth() const;
+
+private:
+ static rtl::Reference< FastPropertySetInfo > getStaticPropertySetInfo();
+
+ TableModelRef mxTableModel;
+ sal_Int32 mnColumn;
+ sal_Int32 mnWidth;
+ bool mbOptimalWidth;
+ bool mbIsVisible;
+ bool mbIsStartOfNewPage;
+ OUString maName;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablecolumns.cxx b/svx/source/table/tablecolumns.cxx
new file mode 100644
index 000000000..c202f3a52
--- /dev/null
+++ b/svx/source/table/tablecolumns.cxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <tablemodel.hxx>
+#include "tablecolumns.hxx"
+#include "tablecolumn.hxx"
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::table;
+
+
+namespace sdr::table {
+
+TableColumns::TableColumns( const TableModelRef& xTableModel )
+: mxTableModel( xTableModel )
+{
+}
+
+
+TableColumns::~TableColumns()
+{
+ dispose();
+}
+
+
+void TableColumns::dispose()
+{
+ mxTableModel.clear();
+}
+
+
+void TableColumns::throwIfDisposed() const
+{
+ if( !mxTableModel.is() )
+ throw DisposedException();
+}
+
+
+// XTableRows
+
+
+void SAL_CALL TableColumns::insertByIndex( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ throwIfDisposed();
+ mxTableModel->insertColumns( nIndex, nCount );
+}
+
+
+void SAL_CALL TableColumns::removeByIndex( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ throwIfDisposed();
+ mxTableModel->removeColumns( nIndex, nCount );
+}
+
+
+// XIndexAccess
+
+
+sal_Int32 SAL_CALL TableColumns::getCount()
+{
+ throwIfDisposed();
+ return mxTableModel->getColumnCount();
+}
+
+
+Any SAL_CALL TableColumns::getByIndex( sal_Int32 Index )
+{
+ throwIfDisposed();
+
+ if( ( Index < 0 ) || ( Index >= mxTableModel->getColumnCount() ) )
+ throw IndexOutOfBoundsException();
+
+ return Any( Reference< XCellRange >( mxTableModel->getColumn( Index ) ) );
+}
+
+
+// XElementAccess
+
+
+Type SAL_CALL TableColumns::getElementType()
+{
+ throwIfDisposed();
+
+ return cppu::UnoType<XCellRange>::get();
+}
+
+
+sal_Bool SAL_CALL TableColumns::hasElements()
+{
+ throwIfDisposed();
+
+ return mxTableModel->getColumnCount() != 0;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablecolumns.hxx b/svx/source/table/tablecolumns.hxx
new file mode 100644
index 000000000..696463aac
--- /dev/null
+++ b/svx/source/table/tablecolumns.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_TABLECOLUMNS_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_TABLECOLUMNS_HXX
+
+#include <com/sun/star/table/XTableColumns.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+#include <celltypes.hxx>
+
+
+namespace sdr::table {
+
+class TableColumns : public ::cppu::WeakAggImplHelper1< css::table::XTableColumns >
+{
+public:
+ explicit TableColumns( const TableModelRef& xTableModel );
+ virtual ~TableColumns() override;
+
+ void dispose();
+ /// @throws css::uno::RuntimeException
+ void throwIfDisposed() const;
+
+ // XTableColumns
+ virtual void SAL_CALL insertByIndex( sal_Int32 nIndex, sal_Int32 nCount ) override;
+ virtual void SAL_CALL removeByIndex( sal_Int32 nIndex, sal_Int32 nCount ) override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // Methods
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+private:
+ TableModelRef mxTableModel;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablecontroller.cxx b/svx/source/table/tablecontroller.cxx
new file mode 100644
index 000000000..1ceaa5141
--- /dev/null
+++ b/svx/source/table/tablecontroller.cxx
@@ -0,0 +1,3363 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <algorithm>
+
+#include <svx/sdr/table/tablecontroller.hxx>
+#include <tablemodel.hxx>
+
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/table/XMergeableCellRange.hpp>
+#include <com/sun/star/table/XMergeableCell.hpp>
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/window.hxx>
+
+#include <svl/whiter.hxx>
+#include <svl/stritem.hxx>
+
+#include <sfx2/request.hxx>
+
+#include <svx/svdotable.hxx>
+#include <sdr/overlay/overlayobjectcell.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svdoutl.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/selectioncontroller.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svxdlg.hxx>
+#include <editeng/boxitem.hxx>
+#include <cell.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/lineitem.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdtditm.hxx>
+#include "tableundo.hxx"
+#include "tablelayouter.hxx"
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <memory>
+#include <o3tl/enumarray.hxx>
+#include <o3tl/enumrange.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/viewsh.hxx>
+#include <editeng/editview.hxx>
+#include <tools/UnitConversion.hxx>
+#include <tools/diagnose_ex.h>
+
+using ::editeng::SvxBorderLine;
+using namespace sdr::table;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::style;
+
+namespace {
+
+enum class CellPosFlag // signals the relative position of a cell to a selection
+{
+ NONE = 0x0000, // not set or inside
+ // row
+ Before = 0x0001,
+ Left = 0x0002,
+ Right = 0x0004,
+ After = 0x0008,
+ // column
+ Upper = 0x0010,
+ Top = 0x0020,
+ Bottom = 0x0040,
+ Lower = 0x0080
+};
+
+}
+
+namespace o3tl
+{ template<> struct typed_flags<CellPosFlag> : is_typed_flags<CellPosFlag, 0xff> {}; }
+
+namespace sdr::table {
+
+namespace {
+
+class SvxTableControllerModifyListener : public ::cppu::WeakImplHelper< css::util::XModifyListener >
+{
+public:
+ explicit SvxTableControllerModifyListener( SvxTableController* pController )
+ : mpController( pController ) {}
+
+ // XModifyListener
+ virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ SvxTableController* mpController;
+};
+
+}
+
+// XModifyListener
+
+
+void SAL_CALL SvxTableControllerModifyListener::modified( const css::lang::EventObject& )
+{
+ if( mpController )
+ mpController->onTableModified();
+}
+
+
+// XEventListener
+
+
+void SAL_CALL SvxTableControllerModifyListener::disposing( const css::lang::EventObject& )
+{
+ mpController = nullptr;
+}
+
+
+
+
+rtl::Reference< sdr::SelectionController > CreateTableController(
+ SdrView& rView,
+ const SdrTableObj& rObj,
+ const rtl::Reference< sdr::SelectionController >& xRefController )
+{
+ return SvxTableController::create(rView, rObj, xRefController);
+}
+
+
+rtl::Reference< sdr::SelectionController > SvxTableController::create(
+ SdrView& rView,
+ const SdrTableObj& rObj,
+ const rtl::Reference< sdr::SelectionController >& xRefController )
+{
+ if( xRefController.is() )
+ {
+ SvxTableController* pController = dynamic_cast< SvxTableController* >( xRefController.get() );
+
+ if(pController && (pController->mxTableObj.get() == &rObj) && (&pController->mrView == &rView))
+ {
+ return xRefController;
+ }
+ }
+
+ return new SvxTableController(rView, rObj);
+}
+
+
+SvxTableController::SvxTableController(
+ SdrView& rView,
+ const SdrTableObj& rObj)
+: mbCellSelectionMode(false)
+ ,mbHasJustMerged(false)
+ ,mbLeftButtonDown(false)
+ ,mrView(rView)
+ ,mxTableObj(const_cast< SdrTableObj* >(&rObj))
+ ,mnUpdateEvent( nullptr )
+{
+ mxTableObj->getActiveCellPos( maCursorFirstPos );
+ maCursorLastPos = maCursorFirstPos;
+
+ Reference< XTable > xTable( mxTableObj->getTable() );
+ if( xTable.is() )
+ {
+ mxModifyListener = new SvxTableControllerModifyListener( this );
+ xTable->addModifyListener( mxModifyListener );
+
+ mxTable.set( dynamic_cast< TableModel* >( xTable.get() ) );
+ }
+}
+
+SvxTableController::~SvxTableController()
+{
+ if( mnUpdateEvent )
+ {
+ Application::RemoveUserEvent( mnUpdateEvent );
+ }
+
+ if( mxModifyListener.is() && mxTableObj )
+ {
+ Reference< XTable > xTable( mxTableObj->getTable() );
+ if( xTable.is() )
+ {
+ xTable->removeModifyListener( mxModifyListener );
+ mxModifyListener.clear();
+ }
+ }
+}
+
+bool SvxTableController::onKeyInput(const KeyEvent& rKEvt, vcl::Window* pWindow )
+{
+ if(!checkTableObject())
+ return false;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+
+ // check if we are read only
+ if( rModel.IsReadOnly())
+ {
+ switch( rKEvt.GetKeyCode().GetCode() )
+ {
+ case awt::Key::DOWN:
+ case awt::Key::UP:
+ case awt::Key::LEFT:
+ case awt::Key::RIGHT:
+ case awt::Key::TAB:
+ case awt::Key::HOME:
+ case awt::Key::END:
+ case awt::Key::NUM2:
+ case awt::Key::NUM4:
+ case awt::Key::NUM6:
+ case awt::Key::NUM8:
+ case awt::Key::ESCAPE:
+ case awt::Key::F2:
+ break;
+ default:
+ // tell the view we eat the event, no further processing needed
+ return true;
+ }
+ }
+
+ TblAction nAction = getKeyboardAction(rKEvt);
+
+ return executeAction( nAction, rKEvt.GetKeyCode().IsShift(), pWindow );
+}
+
+namespace {
+
+Point pixelToLogic(const Point& rPoint, vcl::Window const * pWindow)
+{
+ if (!pWindow)
+ return rPoint;
+
+ return pWindow->PixelToLogic(rPoint);
+}
+
+}
+
+bool SvxTableController::onMouseButtonDown(const MouseEvent& rMEvt, vcl::Window* pWindow )
+{
+ if (comphelper::LibreOfficeKit::isActive() && !pWindow)
+ {
+ // Tiled rendering: get the window that has the disabled map mode.
+ if (OutputDevice* pOutputDevice = mrView.GetFirstOutputDevice())
+ {
+ if (pOutputDevice->GetOutDevType() == OUTDEV_WINDOW)
+ pWindow = pOutputDevice->GetOwnerWindow();
+ }
+ }
+
+ if( !pWindow || !checkTableObject() )
+ return false;
+
+ SdrViewEvent aVEvt;
+ if( !rMEvt.IsRight() && mrView.PickAnything(rMEvt,SdrMouseEventKind::BUTTONDOWN, aVEvt) == SdrHitKind::Handle )
+ return false;
+
+ TableHitKind eHit = mxTableObj->CheckTableHit(pixelToLogic(rMEvt.GetPosPixel(), pWindow), maMouseDownPos.mnCol, maMouseDownPos.mnRow);
+
+ mbLeftButtonDown = (rMEvt.GetClicks() == 1) && rMEvt.IsLeft();
+
+ if( eHit == TableHitKind::Cell )
+ {
+ StartSelection( maMouseDownPos );
+ return true;
+ }
+
+ if( rMEvt.IsRight() && eHit != TableHitKind::NONE )
+ return true; // right click will become context menu
+
+ // for cell selection with the mouse remember our first hit
+ if( mbLeftButtonDown )
+ {
+ RemoveSelection();
+
+ SdrHdl* pHdl = mrView.PickHandle(pixelToLogic(rMEvt.GetPosPixel(), pWindow));
+
+ if( pHdl )
+ {
+ mbLeftButtonDown = false;
+ }
+ else
+ {
+ sdr::table::SdrTableObj* pTableObj = mxTableObj.get();
+
+ if (!pTableObj || eHit == TableHitKind::NONE)
+ {
+ mbLeftButtonDown = false;
+ }
+ }
+ }
+
+ if (comphelper::LibreOfficeKit::isActive() && rMEvt.GetClicks() == 2 && rMEvt.IsLeft() && eHit == TableHitKind::CellTextArea)
+ {
+ bool bEmptyOutliner = false;
+ if (Outliner* pOutliner = mrView.GetTextEditOutliner())
+ {
+ if (pOutliner->GetParagraphCount() == 1)
+ {
+ if (Paragraph* pParagraph = pOutliner->GetParagraph(0))
+ bEmptyOutliner = pOutliner->GetText(pParagraph).isEmpty();
+ }
+ }
+ if (bEmptyOutliner)
+ {
+ // Tiled rendering: a left double-click in an empty cell: select it.
+ StartSelection(maMouseDownPos);
+ setSelectedCells(maMouseDownPos, maMouseDownPos);
+ // Update graphic selection, should be hidden now.
+ mrView.AdjustMarkHdl();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool SvxTableController::onMouseButtonUp(const MouseEvent& rMEvt, vcl::Window* /*pWin*/)
+{
+ if( !checkTableObject() )
+ return false;
+
+ mbLeftButtonDown = false;
+
+ return rMEvt.GetClicks() == 2;
+}
+
+
+bool SvxTableController::onMouseMove(const MouseEvent& rMEvt, vcl::Window* pWindow )
+{
+ if( !checkTableObject() )
+ return false;
+
+ SdrTableObj* pTableObj = mxTableObj.get();
+ CellPos aPos;
+ if (mbLeftButtonDown && pTableObj && pTableObj->CheckTableHit(pixelToLogic(rMEvt.GetPosPixel(), pWindow), aPos.mnCol, aPos.mnRow ) != TableHitKind::NONE)
+ {
+ if(aPos != maMouseDownPos)
+ {
+ if( mbCellSelectionMode )
+ {
+ setSelectedCells( maMouseDownPos, aPos );
+ return true;
+ }
+ else
+ {
+ StartSelection( maMouseDownPos );
+ }
+ }
+ else if( mbCellSelectionMode )
+ {
+ UpdateSelection( aPos );
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void SvxTableController::onSelectionHasChanged()
+{
+ bool bSelected = false;
+
+ SdrTableObj* pTableObj = mxTableObj.get();
+ if( pTableObj && pTableObj->IsTextEditActive() )
+ {
+ pTableObj->getActiveCellPos( maCursorFirstPos );
+ maCursorLastPos = maCursorFirstPos;
+ mbCellSelectionMode = false;
+ }
+ else
+ {
+ const SdrMarkList& rMarkList= mrView.GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ bSelected = mxTableObj.get() == rMarkList.GetMark(0)->GetMarkedSdrObj();
+ }
+
+ if( bSelected )
+ {
+ updateSelectionOverlay();
+ }
+ else
+ {
+ destroySelectionOverlay();
+ }
+}
+void SvxTableController::onSelectAll()
+{
+ sdr::table::SdrTableObj* pTableObj = mxTableObj.get();
+ if ( pTableObj && !pTableObj->IsTextEditActive())
+ {
+ selectAll();
+ }
+}
+
+
+void SvxTableController::GetState( SfxItemSet& rSet )
+{
+ if(!mxTable.is() || !mxTableObj.is())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ std::optional<SfxItemSet> oSet;
+ bool bVertDone(false);
+
+ // Iterate over all requested items in the set.
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ switch (nWhich)
+ {
+ case SID_TABLE_VERT_BOTTOM:
+ case SID_TABLE_VERT_CENTER:
+ case SID_TABLE_VERT_NONE:
+ {
+ if(!bVertDone)
+ {
+ if (!oSet)
+ {
+ oSet.emplace(rModel.GetItemPool());
+ MergeAttrFromSelectedCells(*oSet, false);
+ }
+
+ SdrTextVertAdjust eAdj = SDRTEXTVERTADJUST_BLOCK;
+
+ if (oSet->GetItemState( SDRATTR_TEXT_VERTADJUST ) != SfxItemState::DONTCARE)
+ eAdj = oSet->Get(SDRATTR_TEXT_VERTADJUST).GetValue();
+
+ rSet.Put(SfxBoolItem(SID_TABLE_VERT_BOTTOM, eAdj == SDRTEXTVERTADJUST_BOTTOM));
+ rSet.Put(SfxBoolItem(SID_TABLE_VERT_CENTER, eAdj == SDRTEXTVERTADJUST_CENTER));
+ rSet.Put(SfxBoolItem(SID_TABLE_VERT_NONE, eAdj == SDRTEXTVERTADJUST_TOP));
+ bVertDone = true;
+ }
+ break;
+ }
+ case SID_TABLE_DELETE_ROW:
+ if( !mxTable.is() || !hasSelectedCells() || (!comphelper::LibreOfficeKit::isActive() && mxTable->getRowCount() <= 1) )
+ rSet.DisableItem(SID_TABLE_DELETE_ROW);
+ break;
+ case SID_TABLE_DELETE_COL:
+ if( !mxTable.is() || !hasSelectedCells() || (!comphelper::LibreOfficeKit::isActive() && mxTable->getColumnCount() <= 1) )
+ rSet.DisableItem(SID_TABLE_DELETE_COL);
+ break;
+ case SID_TABLE_DELETE_TABLE:
+ if( !mxTable.is() )
+ rSet.DisableItem(SID_TABLE_DELETE_TABLE);
+ break;
+ case SID_TABLE_MERGE_CELLS:
+ if( !mxTable.is() || !hasSelectedCells() )
+ rSet.DisableItem(SID_TABLE_MERGE_CELLS);
+ break;
+ case SID_TABLE_SPLIT_CELLS:
+ if( !hasSelectedCells() || !mxTable.is() )
+ rSet.DisableItem(SID_TABLE_SPLIT_CELLS);
+ break;
+
+ case SID_TABLE_OPTIMAL_ROW_HEIGHT:
+ case SID_TABLE_DISTRIBUTE_COLUMNS:
+ case SID_TABLE_DISTRIBUTE_ROWS:
+ {
+ bool bDistributeColumns = false;
+ bool bDistributeRows = false;
+ if( mxTable.is() )
+ {
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+
+ bDistributeColumns = aStart.mnCol != aEnd.mnCol;
+ bDistributeRows = aStart.mnRow != aEnd.mnRow;
+ }
+ if( !bDistributeColumns )
+ rSet.DisableItem(SID_TABLE_DISTRIBUTE_COLUMNS);
+ if( !bDistributeRows )
+ {
+ rSet.DisableItem(SID_TABLE_OPTIMAL_ROW_HEIGHT);
+ rSet.DisableItem(SID_TABLE_DISTRIBUTE_ROWS);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+
+void SvxTableController::onInsert( sal_uInt16 nSId, const SfxItemSet* pArgs )
+{
+ if(!checkTableObject())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ bool bInsertAfter = true;
+ sal_uInt16 nCount = 0;
+
+ if( pArgs )
+ {
+ const SfxPoolItem* pItem = nullptr;
+ pArgs->GetItemState(nSId, false, &pItem);
+ if (pItem)
+ {
+ nCount = static_cast<const SfxInt16Item*>(pItem)->GetValue();
+ if(const SfxBoolItem* pItem2 = pArgs->GetItemIfSet(SID_TABLE_PARAM_INSERT_AFTER))
+ bInsertAfter = pItem2->GetValue();
+ }
+ }
+
+ CellPos aStart, aEnd;
+ if( hasSelectedCells() )
+ {
+ getSelectedCells( aStart, aEnd );
+ }
+ else
+ {
+ if( bInsertAfter )
+ {
+ aStart.mnCol = mxTable->getColumnCount() - 1;
+ aStart.mnRow = mxTable->getRowCount() - 1;
+ aEnd = aStart;
+ }
+ }
+
+ if( rTableObj.IsTextEditActive() )
+ mrView.SdrEndTextEdit(true);
+
+ RemoveSelection();
+
+ static const OUStringLiteral sSize( u"Size" );
+ const bool bUndo(rModel.IsUndoEnabled());
+
+ switch( nSId )
+ {
+ case SID_TABLE_INSERT_COL:
+ {
+ TableModelNotifyGuard aGuard( mxTable.get() );
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_TABLE_INSCOL) );
+ rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
+ }
+
+ Reference< XTableColumns > xCols( mxTable->getColumns() );
+ const sal_Int32 nNewColumns = (nCount == 0) ? (aEnd.mnCol - aStart.mnCol + 1) : nCount;
+ const sal_Int32 nNewStartColumn = aEnd.mnCol + (bInsertAfter ? 1 : 0);
+ xCols->insertByIndex( nNewStartColumn, nNewColumns );
+
+ for( sal_Int32 nOffset = 0; nOffset < nNewColumns; nOffset++ )
+ {
+ // Resolves fdo#61540
+ // On Insert before, the reference column whose size is going to be
+ // used for newly created column(s) is wrong. As the new columns are
+ // inserted before the reference column, the reference column moved
+ // to the new position by no., of new columns i.e (earlier+newcolumns).
+ Reference< XPropertySet >(xCols->getByIndex(nNewStartColumn+nOffset), UNO_QUERY_THROW )->
+ setPropertyValue( sSize,
+ Reference< XPropertySet >(xCols->getByIndex( bInsertAfter?nNewStartColumn-1:nNewStartColumn+nNewColumns ), UNO_QUERY_THROW )->
+ getPropertyValue( sSize ) );
+ }
+
+ // Copy cell properties
+ sal_Int32 nPropSrcCol = (bInsertAfter ? aEnd.mnCol : aStart.mnCol + nNewColumns);
+ sal_Int32 nRowSpan = 0;
+ bool bNewSpan = false;
+
+ for( sal_Int32 nRow = 0; nRow < mxTable->getRowCount(); ++nRow )
+ {
+ CellRef xSourceCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nPropSrcCol, nRow ).get() ) );
+
+ // When we insert new COLUMNs, we want to copy ROW spans.
+ if (xSourceCell.is() && nRowSpan == 0)
+ {
+ // we are not in a span yet. Let's find out if the current cell is in a span.
+ sal_Int32 nColSpan = sal_Int32();
+ sal_Int32 nSpanInfoCol = sal_Int32();
+
+ if( xSourceCell->getRowSpan() > 1 )
+ {
+ // The current cell is the top-left cell in a span.
+ // Get the span info and propagate it to the target.
+ nRowSpan = xSourceCell->getRowSpan();
+ nColSpan = xSourceCell->getColumnSpan();
+ nSpanInfoCol = nPropSrcCol;
+ }
+ else if( xSourceCell->isMerged() )
+ {
+ // The current cell is a middle cell in a 2D span.
+ // Look for the top-left cell in the span.
+ for( nSpanInfoCol = nPropSrcCol - 1; nSpanInfoCol >= 0; --nSpanInfoCol )
+ {
+ CellRef xMergeInfoCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nSpanInfoCol, nRow ).get() ) );
+ if (xMergeInfoCell.is() && !xMergeInfoCell->isMerged())
+ {
+ nRowSpan = xMergeInfoCell->getRowSpan();
+ nColSpan = xMergeInfoCell->getColumnSpan();
+ break;
+ }
+ }
+ if( nRowSpan == 1 )
+ nRowSpan = 0;
+ }
+
+ // The target columns are outside the span; Start a new span.
+ if( nRowSpan > 0 && ( nNewStartColumn < nSpanInfoCol || nSpanInfoCol + nColSpan <= nNewStartColumn ) )
+ bNewSpan = true;
+ }
+
+ // Now copy the properties from the source to the targets
+ for( sal_Int32 nOffset = 0; nOffset < nNewColumns; nOffset++ )
+ {
+ CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nNewStartColumn + nOffset, nRow ).get() ) );
+ if( xTargetCell.is() )
+ {
+ if( nRowSpan > 0 )
+ {
+ if( bNewSpan )
+ xTargetCell->merge( 1, nRowSpan );
+ else
+ xTargetCell->setMerged();
+ }
+ xTargetCell->copyFormatFrom( xSourceCell );
+ }
+ }
+
+ if( nRowSpan > 0 )
+ {
+ --nRowSpan;
+ bNewSpan = false;
+ }
+ }
+
+ if( bUndo )
+ rModel.EndUndo();
+
+ aStart.mnCol = nNewStartColumn;
+ aStart.mnRow = 0;
+ aEnd.mnCol = aStart.mnCol + nNewColumns - 1;
+ aEnd.mnRow = mxTable->getRowCount() - 1;
+ break;
+ }
+
+ case SID_TABLE_INSERT_ROW:
+ {
+ TableModelNotifyGuard aGuard( mxTable.get() );
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_TABLE_INSROW ) );
+ rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
+ }
+
+ Reference< XTableRows > xRows( mxTable->getRows() );
+ const sal_Int32 nNewRows = (nCount == 0) ? (aEnd.mnRow - aStart.mnRow + 1) : nCount;
+ const sal_Int32 nNewRowStart = aEnd.mnRow + (bInsertAfter ? 1 : 0);
+ xRows->insertByIndex( nNewRowStart, nNewRows );
+
+ for( sal_Int32 nOffset = 0; nOffset < nNewRows; nOffset++ )
+ {
+ Reference< XPropertySet >( xRows->getByIndex( aEnd.mnRow + nOffset + 1 ), UNO_QUERY_THROW )->
+ setPropertyValue( sSize,
+ Reference< XPropertySet >( xRows->getByIndex( aStart.mnRow + nOffset ), UNO_QUERY_THROW )->
+ getPropertyValue( sSize ) );
+ }
+
+ // Copy the cell properties
+ sal_Int32 nPropSrcRow = (bInsertAfter ? aEnd.mnRow : aStart.mnRow + nNewRows);
+ sal_Int32 nColSpan = 0;
+ bool bNewSpan = false;
+
+ for( sal_Int32 nCol = 0; nCol < mxTable->getColumnCount(); ++nCol )
+ {
+ CellRef xSourceCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nPropSrcRow ).get() ) );
+
+ if (!xSourceCell.is())
+ continue;
+
+ // When we insert new ROWs, we want to copy COLUMN spans.
+ if( nColSpan == 0 )
+ {
+ // we are not in a span yet. Let's find out if the current cell is in a span.
+ sal_Int32 nRowSpan = sal_Int32();
+ sal_Int32 nSpanInfoRow = sal_Int32();
+
+ if( xSourceCell->getColumnSpan() > 1 )
+ {
+ // The current cell is the top-left cell in a span.
+ // Get the span info and propagate it to the target.
+ nColSpan = xSourceCell->getColumnSpan();
+ nRowSpan = xSourceCell->getRowSpan();
+ nSpanInfoRow = nPropSrcRow;
+ }
+ else if( xSourceCell->isMerged() )
+ {
+ // The current cell is a middle cell in a 2D span.
+ // Look for the top-left cell in the span.
+ for( nSpanInfoRow = nPropSrcRow - 1; nSpanInfoRow >= 0; --nSpanInfoRow )
+ {
+ CellRef xMergeInfoCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nSpanInfoRow ).get() ) );
+ if (xMergeInfoCell.is() && !xMergeInfoCell->isMerged())
+ {
+ nColSpan = xMergeInfoCell->getColumnSpan();
+ nRowSpan = xMergeInfoCell->getRowSpan();
+ break;
+ }
+ }
+ if( nColSpan == 1 )
+ nColSpan = 0;
+ }
+
+ // Inserted rows are outside the span; Start a new span.
+ if( nColSpan > 0 && ( nNewRowStart < nSpanInfoRow || nSpanInfoRow + nRowSpan <= nNewRowStart ) )
+ bNewSpan = true;
+ }
+
+ // Now copy the properties from the source to the targets
+ for( sal_Int32 nOffset = 0; nOffset < nNewRows; ++nOffset )
+ {
+ CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nNewRowStart + nOffset ).get() ) );
+ if( xTargetCell.is() )
+ {
+ if( nColSpan > 0 )
+ {
+ if( bNewSpan )
+ xTargetCell->merge( nColSpan, 1 );
+ else
+ xTargetCell->setMerged();
+ }
+ xTargetCell->copyFormatFrom( xSourceCell );
+ }
+ }
+
+ if( nColSpan > 0 )
+ {
+ --nColSpan;
+ bNewSpan = false;
+ }
+ }
+
+ if( bUndo )
+ rModel.EndUndo();
+
+ aStart.mnCol = 0;
+ aStart.mnRow = nNewRowStart;
+ aEnd.mnCol = mxTable->getColumnCount() - 1;
+ aEnd.mnRow = aStart.mnRow + nNewRows - 1;
+ break;
+ }
+ }
+
+ StartSelection( aStart );
+ UpdateSelection( aEnd );
+}
+
+
+void SvxTableController::onDelete( sal_uInt16 nSId )
+{
+ sdr::table::SdrTableObj* pTableObj = mxTableObj.get();
+ if( !pTableObj || !mxTable.is() )
+ return;
+
+ if( nSId == SID_TABLE_DELETE_TABLE )
+ {
+ if( pTableObj->IsTextEditActive() )
+ mrView.SdrEndTextEdit(true);
+
+ mrView.DeleteMarkedObj();
+ }
+ else if( hasSelectedCells() )
+ {
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+
+ if( pTableObj->IsTextEditActive() )
+ mrView.SdrEndTextEdit(true);
+
+ RemoveSelection();
+
+ bool bDeleteTable = false;
+ switch( nSId )
+ {
+ case SID_TABLE_DELETE_COL:
+ {
+ const sal_Int32 nRemovedColumns = aEnd.mnCol - aStart.mnCol + 1;
+ if( nRemovedColumns == mxTable->getColumnCount() )
+ {
+ bDeleteTable = true;
+ }
+ else
+ {
+ Reference< XTableColumns > xCols( mxTable->getColumns() );
+ xCols->removeByIndex( aStart.mnCol, nRemovedColumns );
+ EditCell(aStart, nullptr, TblAction::NONE);
+ }
+ break;
+ }
+
+ case SID_TABLE_DELETE_ROW:
+ {
+ const sal_Int32 nRemovedRows = aEnd.mnRow - aStart.mnRow + 1;
+ if( nRemovedRows == mxTable->getRowCount() )
+ {
+ bDeleteTable = true;
+ }
+ else
+ {
+ Reference< XTableRows > xRows( mxTable->getRows() );
+ xRows->removeByIndex( aStart.mnRow, nRemovedRows );
+ EditCell(aStart, nullptr, TblAction::NONE);
+ }
+ break;
+ }
+ }
+
+ if( bDeleteTable )
+ mrView.DeleteMarkedObj();
+ else
+ UpdateTableShape();
+ }
+}
+
+
+void SvxTableController::onSelect( sal_uInt16 nSId )
+{
+ if( !mxTable.is() )
+ return;
+
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+ const sal_Int32 nColCount = mxTable->getColumnCount();
+ if( !(nRowCount && nColCount) )
+ return;
+
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+
+ switch( nSId )
+ {
+ case SID_TABLE_SELECT_ALL:
+ aEnd.mnCol = 0; aEnd.mnRow = 0;
+ aStart.mnCol = nColCount - 1; aStart.mnRow = nRowCount - 1;
+ break;
+ case SID_TABLE_SELECT_COL:
+ aEnd.mnRow = nRowCount - 1;
+ aStart.mnRow = 0;
+ break;
+ case SID_TABLE_SELECT_ROW:
+ aEnd.mnCol = nColCount - 1;
+ aStart.mnCol = 0;
+ break;
+ }
+
+ StartSelection( aEnd );
+ gotoCell( aStart, true, nullptr );
+}
+
+namespace
+{
+ SvxBoxItem mergeDrawinglayerTextDistancesAndSvxBoxItem(const SfxItemSet& rAttrSet)
+ {
+ // merge drawing layer text distance items into SvxBoxItem used by the dialog
+ SvxBoxItem aBoxItem( rAttrSet.Get( SDRATTR_TABLE_BORDER ) );
+ aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( rAttrSet.Get(SDRATTR_TEXT_LEFTDIST).GetValue()), SvxBoxItemLine::LEFT );
+ aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( rAttrSet.Get(SDRATTR_TEXT_RIGHTDIST).GetValue()), SvxBoxItemLine::RIGHT );
+ aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( rAttrSet.Get(SDRATTR_TEXT_UPPERDIST).GetValue()), SvxBoxItemLine::TOP );
+ aBoxItem.SetDistance( sal::static_int_cast< sal_uInt16 >( rAttrSet.Get(SDRATTR_TEXT_LOWERDIST).GetValue()), SvxBoxItemLine::BOTTOM );
+ return aBoxItem;
+ }
+}
+
+void SvxTableController::onFormatTable(const SfxRequest& rReq)
+{
+ if(!mxTableObj.is())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if(pArgs)
+ return;
+
+ SfxItemSet aNewAttr(rModel.GetItemPool());
+
+ // merge drawing layer text distance items into SvxBoxItem used by the dialog
+ SvxBoxItem aBoxItem(mergeDrawinglayerTextDistancesAndSvxBoxItem(aNewAttr));
+
+ SvxBoxInfoItem aBoxInfoItem( aNewAttr.Get( SDRATTR_TABLE_BORDER_INNER ) );
+
+ MergeAttrFromSelectedCells(aNewAttr, false);
+ FillCommonBorderAttrFromSelectedCells( aBoxItem, aBoxInfoItem );
+ aNewAttr.Put( aBoxItem );
+ aNewAttr.Put( aBoxInfoItem );
+
+ // Fill in shadow properties.
+ const SfxItemSet& rTableItemSet = rTableObj.GetMergedItemSet();
+ for (sal_uInt16 nWhich = SDRATTR_SHADOW_FIRST; nWhich <= SDRATTR_SHADOW_LAST; ++nWhich)
+ {
+ if (rTableItemSet.GetItemState(nWhich, false) != SfxItemState::SET)
+ {
+ continue;
+ }
+
+ aNewAttr.Put(rTableItemSet.Get(nWhich));
+ }
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ VclPtr<SfxAbstractTabDialog> xDlg( pFact->CreateSvxFormatCellsDialog(
+ rReq.GetFrameWeld(),
+ &aNewAttr,
+ rModel) );
+
+ // Even Cancel Button is returning positive(101) value,
+ xDlg->StartExecuteAsync([xDlg, this, aBoxItem, aBoxInfoItem](int nResult){
+ if (nResult == RET_OK)
+ {
+ SfxItemSet aNewSet(*(xDlg->GetOutputItemSet()));
+
+ //Only properties that were unchanged by the dialog appear in this
+ //itemset. We had constructed these two properties from other
+ //ones, so if they were not changed, then forcible set them back to
+ //their originals in the new result set so we can decompose that
+ //unchanged state back to their input properties
+ if (aNewSet.GetItemState(SDRATTR_TABLE_BORDER, false) != SfxItemState::SET)
+ {
+ aNewSet.Put(aBoxItem);
+ }
+ if (aNewSet.GetItemState(SDRATTR_TABLE_BORDER_INNER, false) != SfxItemState::SET)
+ {
+ aNewSet.Put(aBoxInfoItem);
+ }
+
+ SvxBoxItem aNewBoxItem( aNewSet.Get( SDRATTR_TABLE_BORDER ) );
+
+ if( aNewBoxItem.GetDistance( SvxBoxItemLine::LEFT ) != aBoxItem.GetDistance( SvxBoxItemLine::LEFT ) )
+ aNewSet.Put(makeSdrTextLeftDistItem( aNewBoxItem.GetDistance( SvxBoxItemLine::LEFT ) ) );
+
+ if( aNewBoxItem.GetDistance( SvxBoxItemLine::RIGHT ) != aBoxItem.GetDistance( SvxBoxItemLine::RIGHT ) )
+ aNewSet.Put(makeSdrTextRightDistItem( aNewBoxItem.GetDistance( SvxBoxItemLine::RIGHT ) ) );
+
+ if( aNewBoxItem.GetDistance( SvxBoxItemLine::TOP ) != aBoxItem.GetDistance( SvxBoxItemLine::TOP ) )
+ aNewSet.Put(makeSdrTextUpperDistItem( aNewBoxItem.GetDistance( SvxBoxItemLine::TOP ) ) );
+
+ if( aNewBoxItem.GetDistance( SvxBoxItemLine::BOTTOM ) != aBoxItem.GetDistance( SvxBoxItemLine::BOTTOM ) )
+ aNewSet.Put(makeSdrTextLowerDistItem( aNewBoxItem.GetDistance( SvxBoxItemLine::BOTTOM ) ) );
+
+ if (checkTableObject() && mxTable.is())
+ {
+ // Create a single undo action when applying the result of the dialog.
+ SdrTableObj& rTableObject(*mxTableObj);
+ SdrModel& rSdrModel(rTableObject.getSdrModelFromSdrObject());
+ bool bUndo = rSdrModel.IsUndoEnabled() && !mrView.IsTextEdit();
+ if (bUndo)
+ {
+ rSdrModel.BegUndo(SvxResId(STR_TABLE_NUMFORMAT));
+ }
+
+ this->SetAttrToSelectedCells(aNewSet, false);
+
+ this->SetAttrToSelectedShape(aNewSet);
+
+ if (bUndo)
+ {
+ rSdrModel.EndUndo();
+ }
+ }
+ }
+
+ xDlg->disposeOnce();
+ });
+}
+
+void SvxTableController::Execute( SfxRequest& rReq )
+{
+ const sal_uInt16 nSId = rReq.GetSlot();
+ switch( nSId )
+ {
+ case SID_TABLE_INSERT_ROW:
+ case SID_TABLE_INSERT_COL:
+ onInsert( nSId, rReq.GetArgs() );
+ break;
+ case SID_TABLE_DELETE_ROW:
+ case SID_TABLE_DELETE_COL:
+ case SID_TABLE_DELETE_TABLE:
+ onDelete( nSId );
+ break;
+ case SID_TABLE_SELECT_ALL:
+ case SID_TABLE_SELECT_COL:
+ case SID_TABLE_SELECT_ROW:
+ onSelect( nSId );
+ break;
+ case SID_FORMAT_TABLE_DLG:
+ onFormatTable( rReq );
+ break;
+
+ case SID_FRAME_LINESTYLE:
+ case SID_FRAME_LINECOLOR:
+ case SID_ATTR_BORDER:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if( pArgs )
+ ApplyBorderAttr( *pArgs );
+ }
+ break;
+
+ case SID_ATTR_FILL_STYLE:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if( pArgs )
+ SetAttributes( *pArgs, false );
+ }
+ break;
+
+ case SID_TABLE_MERGE_CELLS:
+ MergeMarkedCells();
+ break;
+
+ case SID_TABLE_SPLIT_CELLS:
+ SplitMarkedCells(rReq);
+ break;
+
+ case SID_TABLE_MINIMAL_COLUMN_WIDTH:
+ DistributeColumns(/*bOptimize=*/true, /*bMinimize=*/true);
+ break;
+
+ case SID_TABLE_OPTIMAL_COLUMN_WIDTH:
+ DistributeColumns(/*bOptimize=*/true, /*bMinimize=*/false);
+ break;
+
+ case SID_TABLE_DISTRIBUTE_COLUMNS:
+ DistributeColumns(/*bOptimize=*/false, /*bMinimize=*/false);
+ break;
+
+ case SID_TABLE_MINIMAL_ROW_HEIGHT:
+ DistributeRows(/*bOptimize=*/true, /*bMinimize=*/true);
+ break;
+
+ case SID_TABLE_OPTIMAL_ROW_HEIGHT:
+ DistributeRows(/*bOptimize=*/true, /*bMinimize=*/false);
+ break;
+
+ case SID_TABLE_DISTRIBUTE_ROWS:
+ DistributeRows(/*bOptimize=*/false, /*bMinimize=*/false);
+ break;
+
+ case SID_TABLE_VERT_BOTTOM:
+ case SID_TABLE_VERT_CENTER:
+ case SID_TABLE_VERT_NONE:
+ SetVertical( nSId );
+ break;
+
+ case SID_AUTOFORMAT:
+ case SID_TABLE_SORT_DIALOG:
+ case SID_TABLE_AUTOSUM:
+ default:
+ break;
+
+ case SID_TABLE_STYLE:
+ SetTableStyle( rReq.GetArgs() );
+ break;
+
+ case SID_TABLE_STYLE_SETTINGS:
+ SetTableStyleSettings( rReq.GetArgs() );
+ break;
+ case SID_TABLE_CHANGE_CURRENT_BORDER_POSITION:
+ changeTableEdge(rReq);
+ break;
+ }
+}
+
+void SvxTableController::SetTableStyle( const SfxItemSet* pArgs )
+{
+ if(!checkTableObject())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+
+ if(!pArgs || (SfxItemState::SET != pArgs->GetItemState(SID_TABLE_STYLE, false)))
+ return;
+
+ const SfxStringItem* pArg = dynamic_cast< const SfxStringItem* >( &pArgs->Get( SID_TABLE_STYLE ) );
+ if( !(pArg && mxTable.is()) )
+ return;
+
+ try
+ {
+ Reference< XStyleFamiliesSupplier > xSFS( rModel.getUnoModel(), UNO_QUERY_THROW );
+ Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), UNO_SET_THROW );
+ Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( "table" ), UNO_QUERY_THROW );
+
+ if( xTableFamilyAccess->hasByName( pArg->GetValue() ) )
+ {
+ // found table style with the same name
+ Reference< XIndexAccess > xNewTableStyle( xTableFamilyAccess->getByName( pArg->GetValue() ), UNO_QUERY_THROW );
+
+ const bool bUndo = rModel.IsUndoEnabled();
+
+ if( bUndo )
+ {
+ rModel.BegUndo(SvxResId(STR_TABLE_STYLE));
+ rModel.AddUndo(std::make_unique<TableStyleUndo>(rTableObj));
+ }
+
+ rTableObj.setTableStyle( xNewTableStyle );
+
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+ const sal_Int32 nColCount = mxTable->getColumnCount();
+ for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
+ {
+ for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) try
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xCell.is() )
+ {
+ SfxItemSet aSet( xCell->GetItemSet() );
+ bool bChanges = false;
+ SfxStyleSheet *pStyleSheet = xCell->GetStyleSheet();
+ SAL_WARN_IF(!pStyleSheet, "svx", "no stylesheet for table cell?");
+ if (pStyleSheet)
+ {
+ const SfxItemSet& rStyleAttribs = pStyleSheet->GetItemSet();
+
+ for ( sal_uInt16 nWhich = SDRATTR_START; nWhich <= SDRATTR_TABLE_LAST; nWhich++ )
+ {
+ if( (rStyleAttribs.GetItemState( nWhich ) == SfxItemState::SET) && (aSet.GetItemState( nWhich ) == SfxItemState::SET) )
+ {
+ aSet.ClearItem( nWhich );
+ bChanges = true;
+ }
+ }
+ }
+
+ if( bChanges )
+ {
+ if( bUndo )
+ xCell->AddUndo();
+
+ xCell->SetMergedItemSetAndBroadcast( aSet, true );
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+ }
+
+ if( bUndo )
+ rModel.EndUndo();
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+}
+
+void SvxTableController::SetTableStyleSettings( const SfxItemSet* pArgs )
+{
+ if(!checkTableObject())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+
+ TableStyleSettings aSettings(rTableObj.getTableStyleSettings() );
+ const SfxBoolItem *pPoolItem=nullptr;
+
+ if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USEFIRSTROWSTYLE, false)) )
+ aSettings.mbUseFirstRow = pPoolItem->GetValue();
+
+ if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USELASTROWSTYLE, false)) )
+ aSettings.mbUseLastRow = pPoolItem->GetValue();
+
+ if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USEBANDINGROWSTYLE, false)) )
+ aSettings.mbUseRowBanding = pPoolItem->GetValue();
+
+ if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USEFIRSTCOLUMNSTYLE, false)) )
+ aSettings.mbUseFirstColumn = pPoolItem->GetValue();
+
+ if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USELASTCOLUMNSTYLE, false)) )
+ aSettings.mbUseLastColumn = pPoolItem->GetValue();
+
+ if( (pPoolItem = pArgs->GetItemIfSet(ID_VAL_USEBANDINGCOLUMNSTYLE, false)) )
+ aSettings.mbUseColumnBanding = pPoolItem->GetValue();
+
+ if( aSettings == rTableObj.getTableStyleSettings() )
+ return;
+
+ const bool bUndo(rModel.IsUndoEnabled());
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_TABLE_STYLE_SETTINGS) );
+ rModel.AddUndo(std::make_unique<TableStyleUndo>(rTableObj));
+ }
+
+ rTableObj.setTableStyleSettings( aSettings );
+
+ if( bUndo )
+ rModel.EndUndo();
+}
+
+void SvxTableController::SetVertical( sal_uInt16 nSId )
+{
+ if(!checkTableObject())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+
+ TableModelNotifyGuard aGuard( mxTable.get() );
+ const bool bUndo(rModel.IsUndoEnabled());
+
+ if (bUndo)
+ {
+ rModel.BegUndo(SvxResId(STR_TABLE_NUMFORMAT));
+ rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoAttrObject(rTableObj));
+ }
+
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+
+ SdrTextVertAdjust eAdj = SDRTEXTVERTADJUST_TOP;
+
+ switch( nSId )
+ {
+ case SID_TABLE_VERT_BOTTOM:
+ eAdj = SDRTEXTVERTADJUST_BOTTOM;
+ break;
+ case SID_TABLE_VERT_CENTER:
+ eAdj = SDRTEXTVERTADJUST_CENTER;
+ break;
+ //case SID_TABLE_VERT_NONE:
+ default:
+ break;
+ }
+
+ SdrTextVertAdjustItem aItem( eAdj );
+
+ for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
+ {
+ for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xCell.is() )
+ {
+ if (bUndo)
+ xCell->AddUndo();
+ SfxItemSet aSet(xCell->GetItemSet());
+ aSet.Put(aItem);
+ xCell->SetMergedItemSetAndBroadcast(aSet, /*bClearAllItems=*/false);
+ }
+ }
+ }
+
+ UpdateTableShape();
+
+ if (bUndo)
+ rModel.EndUndo();
+}
+
+void SvxTableController::MergeMarkedCells()
+{
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+ SdrTableObj* pTableObj = mxTableObj.get();
+ if( pTableObj )
+ {
+ if( pTableObj->IsTextEditActive() )
+ mrView.SdrEndTextEdit(true);
+
+ TableModelNotifyGuard aGuard( mxTable.get() );
+ MergeRange( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow );
+ }
+}
+
+void SvxTableController::SplitMarkedCells(const SfxRequest& rReq)
+{
+ if(!checkTableObject() || !mxTable.is())
+ return;
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ VclPtr<SvxAbstractSplitTableDialog> xDlg(pFact->CreateSvxSplitTableDialog(rReq.GetFrameWeld(), false, 99));
+
+ xDlg->StartExecuteAsync([xDlg, this](int) {
+ const sal_Int32 nCount = xDlg->GetCount() - 1;
+
+ if( nCount < 1 )
+ return;
+
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+ Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow ) ), UNO_QUERY_THROW );
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+ const sal_Int32 nColCount = mxTable->getColumnCount();
+ SdrTableObj& rTableObj(*mxTableObj);
+
+ if( rTableObj.IsTextEditActive() )
+ mrView.SdrEndTextEdit(true);
+
+ TableModelNotifyGuard aGuard( mxTable.get() );
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ const bool bUndo(rModel.IsUndoEnabled());
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_TABLE_SPLIT) );
+ rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
+ }
+
+ if( xDlg->IsHorizontal() )
+ {
+ xRange->split( 0, nCount );
+ }
+ else
+ {
+ xRange->split( nCount, 0 );
+ }
+
+ if( bUndo )
+ rModel.EndUndo();
+
+ aEnd.mnRow += mxTable->getRowCount() - nRowCount;
+ aEnd.mnCol += mxTable->getColumnCount() - nColCount;
+
+ setSelectedCells( aStart, aEnd );
+
+ xDlg->disposeOnce();
+ });
+}
+
+void SvxTableController::DistributeColumns(const bool bOptimize, const bool bMinimize)
+{
+ if(!checkTableObject())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ const bool bUndo(rModel.IsUndoEnabled());
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_TABLE_DISTRIBUTE_COLUMNS) );
+ rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
+ }
+
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+ rTableObj.DistributeColumns( aStart.mnCol, aEnd.mnCol, bOptimize, bMinimize );
+
+ if( bUndo )
+ rModel.EndUndo();
+}
+
+void SvxTableController::DistributeRows(const bool bOptimize, const bool bMinimize)
+{
+ if(!checkTableObject())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ const bool bUndo(rModel.IsUndoEnabled());
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_TABLE_DISTRIBUTE_ROWS) );
+ rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
+ }
+
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+ rTableObj.DistributeRows( aStart.mnRow, aEnd.mnRow, bOptimize, bMinimize );
+
+ if( bUndo )
+ rModel.EndUndo();
+}
+
+bool SvxTableController::HasMarked() const
+{
+ return mbCellSelectionMode && mxTable.is();
+}
+
+bool SvxTableController::DeleteMarked()
+{
+ if(!checkTableObject() || !HasMarked())
+ return false;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ const bool bUndo(rModel.IsUndoEnabled());
+ bool bDeleteTable = false;
+
+ if (bUndo)
+ rModel.BegUndo(SvxResId(STR_TABLE_DELETE_CELL_CONTENTS));
+
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+ const sal_Int32 nRemovedColumns = aEnd.mnCol - aStart.mnCol + 1;
+ const sal_Int32 nRemovedRows = aEnd.mnRow - aStart.mnRow + 1;
+ if( nRemovedColumns == mxTable->getColumnCount() && nRemovedRows == mxTable->getRowCount())
+ {
+ bDeleteTable = true;
+ }
+ else
+ {
+ for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
+ {
+ for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if (xCell.is() && xCell->hasText())
+ {
+ if (bUndo)
+ xCell->AddUndo();
+ xCell->SetOutlinerParaObject(std::nullopt);
+ }
+ }
+ }
+ }
+
+ if (bDeleteTable)
+ mrView.DeleteMarkedObj();
+
+ if (bUndo)
+ rModel.EndUndo();
+
+ if (!bDeleteTable)
+ UpdateTableShape();
+ return true;
+}
+
+bool SvxTableController::GetStyleSheet( SfxStyleSheet*& rpStyleSheet ) const
+{
+ if( hasSelectedCells() )
+ {
+ rpStyleSheet = nullptr;
+
+ if( mxTable.is() )
+ {
+ SfxStyleSheet* pRet=nullptr;
+ bool b1st=true;
+
+ CellPos aStart, aEnd;
+ const_cast<SvxTableController&>(*this).getSelectedCells( aStart, aEnd );
+
+ for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
+ {
+ for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xCell.is() )
+ {
+ SfxStyleSheet* pSS=xCell->GetStyleSheet();
+ if(b1st)
+ {
+ pRet=pSS;
+ }
+ else if(pRet != pSS)
+ {
+ return true;
+ }
+ b1st=false;
+ }
+ }
+ }
+ rpStyleSheet = pRet;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SvxTableController::SetStyleSheet( SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr )
+{
+ if( hasSelectedCells() && (!pStyleSheet || pStyleSheet->GetFamily() == SfxStyleFamily::Frame) )
+ {
+ if( mxTable.is() )
+ {
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+
+ for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
+ {
+ for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xCell.is() )
+ xCell->SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
+ }
+ }
+
+ UpdateTableShape();
+ return true;
+ }
+ }
+ return false;
+}
+
+void SvxTableController::changeTableEdge(const SfxRequest& rReq)
+{
+ if (!checkTableObject())
+ return;
+
+ const auto* pType = rReq.GetArg<SfxStringItem>(SID_TABLE_BORDER_TYPE);
+ const auto* pIndex = rReq.GetArg<SfxUInt16Item>(SID_TABLE_BORDER_INDEX);
+ const auto* pOffset = rReq.GetArg<SfxInt32Item>(SID_TABLE_BORDER_OFFSET);
+
+ if (!(pType && pIndex && pOffset))
+ return;
+
+ const OUString sType = pType->GetValue();
+ const sal_uInt16 nIndex = pIndex->GetValue();
+ const sal_Int32 nOffset = convertTwipToMm100(pOffset->GetValue());
+
+ SdrTableObj& rTableObj(*mxTableObj);
+
+ sal_Int32 nEdgeIndex = -1;
+ bool bHorizontal = sType.startsWith("row");
+
+ if (sType == "column-left" || sType == "row-left")
+ {
+ nEdgeIndex = 0;
+ }
+ else if (sType == "column-right")
+ {
+ // Number of edges = number of columns + 1
+ nEdgeIndex = rTableObj.getColumnCount();
+ }
+ else if (sType == "row-right")
+ {
+ // Number of edges = number of rows + 1
+ nEdgeIndex = rTableObj.getRowCount();
+ }
+ else if (sType == "column-middle" || sType == "row-middle")
+ {
+ nEdgeIndex = nIndex + 1;
+ }
+
+ if (nEdgeIndex < 0)
+ return;
+
+ TableModelNotifyGuard aGuard(mxTable.get());
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ const bool bUndo(rModel.IsUndoEnabled());
+ if (bUndo)
+ {
+ auto pUndoObject = rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj);
+ rModel.BegUndo(pUndoObject->GetComment());
+
+ auto* pGeoUndo = static_cast<SdrUndoGeoObj*>(pUndoObject.get());
+ if (pGeoUndo)
+ pGeoUndo->SetSkipChangeLayout(true);
+
+ rModel.AddUndo(std::move(pUndoObject));
+ }
+ tools::Rectangle aBoundRect;
+ if (rTableObj.GetUserCall())
+ aBoundRect = rTableObj.GetLastBoundRect();
+ rTableObj.changeEdge(bHorizontal, nEdgeIndex, nOffset);
+ rTableObj.SetChanged();
+ rTableObj.SendUserCall(SdrUserCallType::Resize, aBoundRect);
+ if (bUndo)
+ rModel.EndUndo();
+}
+
+// internals
+
+
+bool SvxTableController::checkTableObject()
+{
+ return mxTableObj.is();
+}
+
+
+SvxTableController::TblAction SvxTableController::getKeyboardAction(const KeyEvent& rKEvt)
+{
+ const bool bMod1 = rKEvt.GetKeyCode().IsMod1(); // ctrl
+ const bool bMod2 = rKEvt.GetKeyCode().IsMod2(); // Alt
+ const bool bTextEdit = mrView.IsTextEdit();
+
+ TblAction nAction = TblAction::HandledByView;
+
+ sdr::table::SdrTableObj* pTableObj = mxTableObj.get();
+ if( !pTableObj )
+ return nAction;
+
+ // handle special keys
+ const sal_Int16 nCode = rKEvt.GetKeyCode().GetCode();
+ switch( nCode )
+ {
+ case awt::Key::ESCAPE: // handle escape
+ {
+ if( bTextEdit )
+ {
+ // escape during text edit ends text edit
+ nAction = TblAction::StopTextEdit;
+ }
+ if( mbCellSelectionMode )
+ {
+ // escape with selected cells removes selection
+ nAction = TblAction::RemoveSelection;
+ }
+ break;
+ }
+ case awt::Key::RETURN: // handle return
+ {
+ if( !bMod1 && !bMod2 && !bTextEdit )
+ {
+ // when not already editing, return starts text edit
+ setSelectionStart( SdrTableObj::getFirstCell() );
+ nAction = TblAction::EditCell;
+ }
+ break;
+ }
+ case awt::Key::F2: // f2 toggles text edit
+ {
+ if( bMod1 || bMod2 ) // f2 with modifiers is handled by the view
+ {
+ }
+ else if( bTextEdit )
+ {
+ // f2 during text edit stops text edit
+ nAction = TblAction::StopTextEdit;
+ }
+ else if( mbCellSelectionMode )
+ {
+ // f2 with selected cells removes selection
+ nAction = TblAction::RemoveSelection;
+ }
+ else
+ {
+ // f2 with no selection and no text edit starts text edit
+ setSelectionStart( SdrTableObj::getFirstCell() );
+ nAction = TblAction::EditCell;
+ }
+ break;
+ }
+ case awt::Key::HOME:
+ case awt::Key::NUM7:
+ {
+ if( (bMod1 || bMod2) && (bTextEdit || mbCellSelectionMode) )
+ {
+ if( bMod1 && !bMod2 )
+ {
+ // ctrl + home jumps to first cell
+ nAction = TblAction::GotoFirstCell;
+ }
+ else if( !bMod1 && bMod2 )
+ {
+ // alt + home jumps to first column
+ nAction = TblAction::GotoFirstColumn;
+ }
+ }
+ break;
+ }
+ case awt::Key::END:
+ case awt::Key::NUM1:
+ {
+ if( (bMod1 || bMod2) && (bTextEdit || mbCellSelectionMode) )
+ {
+ if( bMod1 && !bMod2 )
+ {
+ // ctrl + end jumps to last cell
+ nAction = TblAction::GotoLastCell;
+ }
+ else if( !bMod1 && bMod2 )
+ {
+ // alt + home jumps to last column
+ nAction = TblAction::GotoLastColumn;
+ }
+ }
+ break;
+ }
+
+ case awt::Key::TAB:
+ {
+ if( bTextEdit || mbCellSelectionMode )
+ nAction = TblAction::Tab;
+ break;
+ }
+
+ case awt::Key::UP:
+ case awt::Key::NUM8:
+ case awt::Key::DOWN:
+ case awt::Key::NUM2:
+ case awt::Key::LEFT:
+ case awt::Key::NUM4:
+ case awt::Key::RIGHT:
+ case awt::Key::NUM6:
+ {
+
+ if( !bMod1 && bMod2 )
+ {
+ if(bTextEdit || mbCellSelectionMode)
+ {
+ if( (nCode == awt::Key::UP) || (nCode == awt::Key::NUM8) )
+ {
+ nAction = TblAction::GotoLeftCell;
+ break;
+ }
+ else if( (nCode == awt::Key::DOWN) || (nCode == awt::Key::NUM2) )
+ {
+ nAction = TblAction::GotoRightCell;
+ break;
+ }
+ }
+ }
+
+ bool bTextMove = false;
+ OutlinerView* pOLV = mrView.GetTextEditOutlinerView();
+ if( pOLV )
+ {
+ RemoveSelection();
+ // during text edit, check if we navigate out of the cell
+ ESelection aOldSelection = pOLV->GetSelection();
+ pOLV->PostKeyEvent(rKEvt);
+ bTextMove = aOldSelection == pOLV->GetSelection();
+ if( !bTextMove )
+ {
+ nAction = TblAction::NONE;
+ }
+ }
+
+ if( mbCellSelectionMode || bTextMove )
+ {
+ // no text edit, navigate in cells if selection active
+ switch( nCode )
+ {
+ case awt::Key::LEFT:
+ case awt::Key::NUM4:
+ nAction = TblAction::GotoLeftCell;
+ break;
+ case awt::Key::RIGHT:
+ case awt::Key::NUM6:
+ nAction = TblAction::GotoRightCell;
+ break;
+ case awt::Key::DOWN:
+ case awt::Key::NUM2:
+ nAction = TblAction::GotoDownCell;
+ break;
+ case awt::Key::UP:
+ case awt::Key::NUM8:
+ nAction = TblAction::GotoUpCell;
+ break;
+ }
+ }
+ break;
+ }
+ case awt::Key::PAGEUP:
+ if( bMod2 )
+ nAction = TblAction::GotoFirstRow;
+ break;
+
+ case awt::Key::PAGEDOWN:
+ if( bMod2 )
+ nAction = TblAction::GotoLastRow;
+ break;
+ }
+ return nAction;
+}
+
+bool SvxTableController::executeAction(TblAction nAction, bool bSelect, vcl::Window* pWindow)
+{
+ sdr::table::SdrTableObj* pTableObj = mxTableObj.get();
+ if( !pTableObj )
+ return false;
+
+ switch( nAction )
+ {
+ case TblAction::GotoFirstCell:
+ {
+ gotoCell( SdrTableObj::getFirstCell(), bSelect, pWindow, nAction );
+ break;
+ }
+
+ case TblAction::GotoLeftCell:
+ {
+ gotoCell( pTableObj->getLeftCell( getSelectionEnd(), !bSelect ), bSelect, pWindow, nAction );
+ break;
+ }
+
+ case TblAction::GotoRightCell:
+ {
+ gotoCell( pTableObj->getRightCell( getSelectionEnd(), !bSelect ), bSelect, pWindow, nAction);
+ break;
+ }
+
+ case TblAction::GotoLastCell:
+ {
+ gotoCell( pTableObj->getLastCell(), bSelect, pWindow, nAction );
+ break;
+ }
+
+ case TblAction::GotoFirstColumn:
+ {
+ CellPos aPos( SdrTableObj::getFirstCell().mnCol, getSelectionEnd().mnRow );
+ gotoCell( aPos, bSelect, pWindow, nAction );
+ break;
+ }
+
+ case TblAction::GotoLastColumn:
+ {
+ CellPos aPos( pTableObj->getLastCell().mnCol, getSelectionEnd().mnRow );
+ gotoCell( aPos, bSelect, pWindow, nAction );
+ break;
+ }
+
+ case TblAction::GotoFirstRow:
+ {
+ CellPos aPos( getSelectionEnd().mnCol, SdrTableObj::getFirstCell().mnRow );
+ gotoCell( aPos, bSelect, pWindow, nAction );
+ break;
+ }
+
+ case TblAction::GotoUpCell:
+ {
+ gotoCell( pTableObj->getUpCell(getSelectionEnd(), !bSelect), bSelect, pWindow, nAction );
+ break;
+ }
+
+ case TblAction::GotoDownCell:
+ {
+ gotoCell( pTableObj->getDownCell(getSelectionEnd(), !bSelect), bSelect, pWindow, nAction );
+ break;
+ }
+
+ case TblAction::GotoLastRow:
+ {
+ CellPos aPos( getSelectionEnd().mnCol, pTableObj->getLastCell().mnRow );
+ gotoCell( aPos, bSelect, pWindow, nAction );
+ break;
+ }
+
+ case TblAction::EditCell:
+ EditCell( getSelectionStart(), pWindow, nAction );
+ break;
+
+ case TblAction::StopTextEdit:
+ StopTextEdit();
+ break;
+
+ case TblAction::RemoveSelection:
+ RemoveSelection();
+ break;
+
+ case TblAction::Tab:
+ {
+ if( bSelect )
+ gotoCell( pTableObj->getPreviousCell( getSelectionEnd(), true ), false, pWindow, nAction );
+ else
+ {
+ CellPos aSelectionEnd( getSelectionEnd() );
+ CellPos aNextCell( pTableObj->getNextCell( aSelectionEnd, true ) );
+ if( aSelectionEnd == aNextCell )
+ {
+ onInsert( SID_TABLE_INSERT_ROW );
+ aNextCell = pTableObj->getNextCell( aSelectionEnd, true );
+ }
+ gotoCell( aNextCell, false, pWindow, nAction );
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return nAction != TblAction::HandledByView;
+}
+
+
+void SvxTableController::gotoCell(const CellPos& rPos, bool bSelect, vcl::Window* pWindow, TblAction nAction /*= TblAction::NONE */)
+{
+ if( mxTableObj.is() && mxTableObj->IsTextEditActive() )
+ mrView.SdrEndTextEdit(true);
+
+ if( bSelect )
+ {
+ maCursorLastPos = rPos;
+ if( mxTableObj.is() )
+ mxTableObj->setActiveCell( rPos );
+
+ if( !mbCellSelectionMode )
+ {
+ setSelectedCells( maCursorFirstPos, rPos );
+ }
+ else
+ {
+ UpdateSelection( rPos );
+ }
+ }
+ else
+ {
+ RemoveSelection();
+ EditCell( rPos, pWindow, nAction );
+ }
+}
+
+
+const CellPos& SvxTableController::getSelectionStart()
+{
+ checkCell( maCursorFirstPos );
+ return maCursorFirstPos;
+}
+
+
+void SvxTableController::setSelectionStart( const CellPos& rPos )
+{
+ maCursorFirstPos = rPos;
+}
+
+
+const CellPos& SvxTableController::getSelectionEnd()
+{
+ checkCell( maCursorLastPos );
+ return maCursorLastPos;
+}
+
+
+void SvxTableController::MergeRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
+{
+ if(!checkTableObject() || !mxTable.is())
+ return;
+
+ try
+ {
+ Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( nFirstCol, nFirstRow,nLastCol, nLastRow ) ), UNO_QUERY_THROW );
+
+ if( xRange->isMergeable() )
+ {
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ const bool bUndo(rModel.IsUndoEnabled());
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_TABLE_MERGE) );
+ rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoGeoObject(rTableObj));
+ }
+
+ xRange->merge();
+ mbHasJustMerged = true;
+ setSelectedCells( maCursorFirstPos, maCursorFirstPos );
+
+ if( bUndo )
+ rModel.EndUndo();
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.table", "" );
+ }
+}
+
+
+void SvxTableController::checkCell( CellPos& rPos ) const
+{
+ if( !mxTable.is() )
+ return;
+
+ try
+ {
+ if( rPos.mnCol >= mxTable->getColumnCount() )
+ rPos.mnCol = mxTable->getColumnCount()-1;
+
+ if( rPos.mnRow >= mxTable->getRowCount() )
+ rPos.mnRow = mxTable->getRowCount()-1;
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+}
+
+
+void SvxTableController::findMergeOrigin( CellPos& rPos )
+{
+ if( !mxTable.is() )
+ return;
+
+ try
+ {
+ Reference< XMergeableCell > xCell( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ), UNO_QUERY_THROW );
+ if( xCell->isMerged() )
+ {
+ ::findMergeOrigin( mxTable, rPos.mnCol, rPos.mnRow, rPos.mnCol, rPos.mnRow );
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx.table", "");
+ }
+}
+
+
+void SvxTableController::EditCell(const CellPos& rPos, vcl::Window* pWindow, TblAction nAction /*= TblAction::NONE */)
+{
+ SdrPageView* pPV(mrView.GetSdrPageView());
+
+ if(nullptr == pPV || !checkTableObject())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+
+ if(rTableObj.getSdrPageFromSdrObject() != pPV->GetPage())
+ return;
+
+ bool bEmptyOutliner = false;
+
+ if(!rTableObj.GetOutlinerParaObject() && mrView.GetTextEditOutliner())
+ {
+ ::Outliner* pOutl = mrView.GetTextEditOutliner();
+ sal_Int32 nParaCnt = pOutl->GetParagraphCount();
+ Paragraph* p1stPara = pOutl->GetParagraph( 0 );
+
+ if(nParaCnt==1 && p1stPara)
+ {
+ // with only one paragraph
+ if (pOutl->GetText(p1stPara).isEmpty())
+ {
+ bEmptyOutliner = true;
+ }
+ }
+ }
+
+ CellPos aPos( rPos );
+ findMergeOrigin( aPos );
+
+ if( &rTableObj == mrView.GetTextEditObject() && !bEmptyOutliner && rTableObj.IsTextEditActive( aPos ) )
+ return;
+
+ if( rTableObj.IsTextEditActive() )
+ mrView.SdrEndTextEdit(true);
+
+ rTableObj.setActiveCell( aPos );
+
+ // create new outliner, owner will be the SdrObjEditView
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ std::unique_ptr<SdrOutliner> pOutl(SdrMakeOutliner(OutlinerMode::OutlineObject, rModel));
+
+ if (pOutl && rTableObj.IsVerticalWriting())
+ pOutl->SetVertical( true );
+
+ if (!mrView.SdrBeginTextEdit(&rTableObj, pPV, pWindow, true, pOutl.release()))
+ return;
+
+ maCursorLastPos = maCursorFirstPos = rPos;
+
+ OutlinerView* pOLV = mrView.GetTextEditOutlinerView();
+
+ // Move cursor to end of text
+ ESelection aNewSelection;
+
+ const WritingMode eMode = rTableObj.GetWritingMode();
+ if (((nAction == TblAction::GotoLeftCell) || (nAction == TblAction::GotoRightCell)) && (eMode != WritingMode_TB_RL))
+ {
+ const bool bLast = ((nAction == TblAction::GotoLeftCell) && (eMode == WritingMode_LR_TB)) ||
+ ((nAction == TblAction::GotoRightCell) && (eMode == WritingMode_RL_TB));
+
+ if( bLast )
+ aNewSelection = ESelection(EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND, EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND);
+ }
+ pOLV->SetSelection(aNewSelection);
+}
+
+
+void SvxTableController::StopTextEdit()
+{
+ if(mrView.IsTextEdit())
+ {
+ mrView.SdrEndTextEdit();
+ mrView.SetCurrentObj(SdrObjKind::Table);
+ mrView.SetEditMode(SdrViewEditMode::Edit);
+ }
+}
+
+
+void SvxTableController::getSelectedCells( CellPos& rFirst, CellPos& rLast )
+{
+ if( mbCellSelectionMode )
+ {
+ checkCell( maCursorFirstPos );
+ checkCell( maCursorLastPos );
+
+ rFirst.mnCol = std::min( maCursorFirstPos.mnCol, maCursorLastPos.mnCol );
+ rFirst.mnRow = std::min( maCursorFirstPos.mnRow, maCursorLastPos.mnRow );
+ rLast.mnCol = std::max( maCursorFirstPos.mnCol, maCursorLastPos.mnCol );
+ rLast.mnRow = std::max( maCursorFirstPos.mnRow, maCursorLastPos.mnRow );
+
+ if( !mxTable.is() )
+ return;
+
+ bool bExt = false;
+ do
+ {
+ bExt = false;
+ for( sal_Int32 nRow = rFirst.mnRow; nRow <= rLast.mnRow && !bExt; nRow++ )
+ {
+ for( sal_Int32 nCol = rFirst.mnCol; nCol <= rLast.mnCol && !bExt; nCol++ )
+ {
+ Reference< XMergeableCell > xCell( mxTable->getCellByPosition( nCol, nRow ), UNO_QUERY );
+ if( !xCell.is() )
+ continue;
+
+ if( xCell->isMerged() )
+ {
+ CellPos aPos( nCol, nRow );
+ findMergeOrigin( aPos );
+ if( (aPos.mnCol < rFirst.mnCol) || (aPos.mnRow < rFirst.mnRow) )
+ {
+ rFirst.mnCol = std::min( rFirst.mnCol, aPos.mnCol );
+ rFirst.mnRow = std::min( rFirst.mnRow, aPos.mnRow );
+ bExt = true;
+ }
+ }
+ else
+ {
+ if( ((nCol + xCell->getColumnSpan() - 1) > rLast.mnCol) || (nRow + xCell->getRowSpan() - 1 ) > rLast.mnRow )
+ {
+ rLast.mnCol = std::max( rLast.mnCol, nCol + xCell->getColumnSpan() - 1 );
+ rLast.mnRow = std::max( rLast.mnRow, nRow + xCell->getRowSpan() - 1 );
+ bExt = true;
+ }
+ }
+ }
+ }
+ }
+ while(bExt);
+ }
+ else if(mrView.IsTextEdit())
+ {
+ rFirst = getSelectionStart();
+ findMergeOrigin( rFirst );
+ rLast = rFirst;
+
+ if( mxTable.is() )
+ {
+ Reference< XMergeableCell > xCell( mxTable->getCellByPosition( rLast.mnCol, rLast.mnRow ), UNO_QUERY );
+ if( xCell.is() )
+ {
+ rLast.mnCol += xCell->getColumnSpan() - 1;
+ rLast.mnRow += xCell->getRowSpan() - 1;
+ }
+ }
+ }
+ else
+ {
+ rFirst.mnCol = 0;
+ rFirst.mnRow = 0;
+ if( mxTable.is() )
+ {
+ rLast.mnRow = mxTable->getRowCount()-1;
+ rLast.mnCol = mxTable->getColumnCount()-1;
+ }
+ else
+ {
+ rLast.mnRow = 0;
+ rLast.mnCol = 0;
+ }
+ }
+}
+
+
+void SvxTableController::StartSelection( const CellPos& rPos )
+{
+ StopTextEdit();
+ mbCellSelectionMode = true;
+ maCursorLastPos = maCursorFirstPos = rPos;
+ mrView.MarkListHasChanged();
+}
+
+
+void SvxTableController::setSelectedCells( const CellPos& rStart, const CellPos& rEnd )
+{
+ StopTextEdit();
+ mbCellSelectionMode = true;
+ maCursorFirstPos = rStart;
+ UpdateSelection( rEnd );
+}
+
+
+bool SvxTableController::ChangeFontSize(bool bGrow, const FontList* pFontList)
+{
+ if(!checkTableObject() || !mxTable.is())
+ return false;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+
+ if (mrView.IsTextEdit())
+ return true;
+
+ CellPos aStart, aEnd;
+
+ if(hasSelectedCells())
+ {
+ getSelectedCells(aStart, aEnd);
+ }
+ else
+ {
+ aStart.mnRow = 0;
+ aStart.mnCol = 0;
+ aEnd.mnRow = mxTable->getRowCount() - 1;
+ aEnd.mnCol = mxTable->getColumnCount() - 1;
+ }
+
+ for (sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++)
+ {
+ for (sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++)
+ {
+ CellRef xCell(dynamic_cast< Cell* >(mxTable->getCellByPosition(nCol, nRow).get()));
+ if (xCell.is())
+ {
+ if (rModel.IsUndoEnabled())
+ xCell->AddUndo();
+
+ SfxItemSet aCellSet(xCell->GetItemSet());
+ if (EditView::ChangeFontSize(bGrow, aCellSet, pFontList))
+ {
+ xCell->SetMergedItemSetAndBroadcast(aCellSet, false);
+ }
+ }
+ }
+ }
+
+ UpdateTableShape();
+
+ return true;
+}
+
+
+void SvxTableController::UpdateSelection( const CellPos& rPos )
+{
+ maCursorLastPos = rPos;
+ mrView.MarkListHasChanged();
+}
+
+
+void SvxTableController::clearSelection()
+{
+ RemoveSelection();
+}
+
+
+void SvxTableController::selectAll()
+{
+ if( mxTable.is() )
+ {
+ CellPos aPos2( mxTable->getColumnCount()-1, mxTable->getRowCount()-1 );
+ if( (aPos2.mnCol >= 0) && (aPos2.mnRow >= 0) )
+ {
+ CellPos aPos1;
+ setSelectedCells( aPos1, aPos2 );
+ }
+ }
+}
+
+
+void SvxTableController::RemoveSelection()
+{
+ if( mbCellSelectionMode )
+ {
+ mbCellSelectionMode = false;
+ mrView.MarkListHasChanged();
+ }
+}
+
+
+void SvxTableController::onTableModified()
+{
+ if( mnUpdateEvent == nullptr )
+ mnUpdateEvent = Application::PostUserEvent( LINK( this, SvxTableController, UpdateHdl ) );
+}
+
+
+void SvxTableController::updateSelectionOverlay()
+{
+ // There is no need to update selection overlay after merging cells
+ // since the selection overlay should remain the same
+ if ( mbHasJustMerged )
+ return;
+
+ destroySelectionOverlay();
+ if( !mbCellSelectionMode )
+ return;
+
+ sdr::table::SdrTableObj* pTableObj = mxTableObj.get();
+ if( !pTableObj )
+ return;
+
+ sdr::overlay::OverlayObjectCell::RangeVector aRanges;
+
+ tools::Rectangle aStartRect, aEndRect;
+ CellPos aStart,aEnd;
+ getSelectedCells( aStart, aEnd );
+ pTableObj->getCellBounds( aStart, aStartRect );
+
+ basegfx::B2DRange a2DRange( basegfx::B2DPoint(aStartRect.Left(), aStartRect.Top()) );
+ a2DRange.expand( basegfx::B2DPoint(aStartRect.Right(), aStartRect.Bottom()) );
+
+ findMergeOrigin( aEnd );
+ pTableObj->getCellBounds( aEnd, aEndRect );
+ a2DRange.expand( basegfx::B2DPoint(aEndRect.Left(), aEndRect.Top()) );
+ a2DRange.expand( basegfx::B2DPoint(aEndRect.Right(), aEndRect.Bottom()) );
+ aRanges.push_back( a2DRange );
+
+ ::Color aHighlight( COL_BLUE );
+ OutputDevice* pOutDev = mrView.GetFirstOutputDevice();
+ if( pOutDev )
+ aHighlight = pOutDev->GetSettings().GetStyleSettings().GetHighlightColor();
+
+ const sal_uInt32 nCount = mrView.PaintWindowCount();
+ for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ SdrPaintWindow* pPaintWindow = mrView.GetPaintWindow(nIndex);
+ if( pPaintWindow )
+ {
+ const rtl::Reference < sdr::overlay::OverlayManager >& xOverlayManager = pPaintWindow->GetOverlayManager();
+ if( xOverlayManager.is() )
+ {
+ std::unique_ptr<sdr::overlay::OverlayObjectCell> pOverlay(new sdr::overlay::OverlayObjectCell( aHighlight, std::vector(aRanges) ));
+
+ xOverlayManager->add(*pOverlay);
+ mpSelectionOverlay.emplace();
+ mpSelectionOverlay->append(std::move(pOverlay));
+ }
+ }
+ }
+
+ // If tiled rendering, emit callbacks for sdr table selection.
+ if (!(pOutDev && comphelper::LibreOfficeKit::isActive()))
+ return;
+
+ tools::Rectangle aSelection(a2DRange.getMinX(), a2DRange.getMinY(), a2DRange.getMaxX(), a2DRange.getMaxY());
+
+ if (pOutDev->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ aSelection = o3tl::toTwips(aSelection, o3tl::Length::mm100);
+
+ if(SfxViewShell* pViewShell = SfxViewShell::Current())
+ {
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, aSelection.toString().getStr());
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, aSelection.toString().getStr());
+ }
+}
+
+
+void SvxTableController::destroySelectionOverlay()
+{
+ if( !mpSelectionOverlay )
+ return;
+
+ mpSelectionOverlay.reset();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // Clear the LOK text selection so far provided by this table.
+ if(SfxViewShell* pViewShell = SfxViewShell::Current())
+ {
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, "EMPTY");
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_START, "EMPTY");
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_END, "EMPTY");
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "EMPTY");
+ }
+ }
+}
+
+
+void SvxTableController::MergeAttrFromSelectedCells(SfxItemSet& rAttr, bool bOnlyHardAttr) const
+{
+ if( !mxTable.is() )
+ return;
+
+ CellPos aStart, aEnd;
+ const_cast<SvxTableController&>(*this).getSelectedCells( aStart, aEnd );
+
+ for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
+ {
+ for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xCell.is() && !xCell->isMerged() )
+ {
+ const SfxItemSet& rSet = xCell->GetItemSet();
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+ while(nWhich)
+ {
+ SfxItemState nState = aIter.GetItemState(false);
+ if(!bOnlyHardAttr)
+ {
+ if(SfxItemState::DONTCARE == nState)
+ rAttr.InvalidateItem(nWhich);
+ else
+ rAttr.MergeValue(rSet.Get(nWhich), true);
+ }
+ else if(SfxItemState::SET == nState)
+ {
+ const SfxPoolItem& rItem = rSet.Get(nWhich);
+ rAttr.MergeValue(rItem, true);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+ }
+ }
+}
+
+
+static void ImplSetLinePreserveColor( SvxBoxItem& rNewFrame, const SvxBorderLine* pNew, SvxBoxItemLine nLine )
+{
+ if( pNew )
+ {
+ const SvxBorderLine* pOld = rNewFrame.GetLine(nLine);
+ if( pOld )
+ {
+ SvxBorderLine aNewLine( *pNew );
+ aNewLine.SetColor( pOld->GetColor() );
+ rNewFrame.SetLine( &aNewLine, nLine );
+ return;
+ }
+ }
+ rNewFrame.SetLine( pNew, nLine );
+}
+
+
+static void ImplApplyBoxItem( CellPosFlag nCellPosFlags, const SvxBoxItem* pBoxItem, const SvxBoxInfoItem* pBoxInfoItem, SvxBoxItem& rNewFrame )
+{
+ if (nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After|CellPosFlag::Upper|CellPosFlag::Lower))
+ {
+ // current cell is outside the selection
+
+ if (!(nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After))) // check if it's not any corner
+ {
+ if (nCellPosFlags & CellPosFlag::Upper)
+ {
+ if( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::TOP) )
+ rNewFrame.SetLine(nullptr, SvxBoxItemLine::BOTTOM );
+ }
+ else if (nCellPosFlags & CellPosFlag::Lower)
+ {
+ if( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::BOTTOM) )
+ rNewFrame.SetLine( nullptr, SvxBoxItemLine::TOP );
+ }
+ }
+ else if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Lower))) // check if it's not any corner
+ {
+ if (nCellPosFlags & CellPosFlag::Before)
+ {
+ if( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) )
+ rNewFrame.SetLine( nullptr, SvxBoxItemLine::RIGHT );
+ }
+ else if (nCellPosFlags & CellPosFlag::After)
+ {
+ if( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) )
+ rNewFrame.SetLine( nullptr, SvxBoxItemLine::LEFT );
+ }
+ }
+ }
+ else
+ {
+ // current cell is inside the selection
+
+ if ((nCellPosFlags & CellPosFlag::Left) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT)
+ : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT))
+ rNewFrame.SetLine( (nCellPosFlags & CellPosFlag::Left) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(), SvxBoxItemLine::LEFT );
+
+ if( (nCellPosFlags & CellPosFlag::Right) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) )
+ rNewFrame.SetLine( (nCellPosFlags & CellPosFlag::Right) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(), SvxBoxItemLine::RIGHT );
+
+ if( (nCellPosFlags & CellPosFlag::Top) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::TOP) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
+ rNewFrame.SetLine( (nCellPosFlags & CellPosFlag::Top) ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(), SvxBoxItemLine::TOP );
+
+ if( (nCellPosFlags & CellPosFlag::Bottom) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::BOTTOM) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) )
+ rNewFrame.SetLine( (nCellPosFlags & CellPosFlag::Bottom) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(), SvxBoxItemLine::BOTTOM );
+
+ // apply distance to borders
+ if( pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::DISTANCE ) )
+ for( SvxBoxItemLine nLine : o3tl::enumrange<SvxBoxItemLine>() )
+ rNewFrame.SetDistance( pBoxItem->GetDistance( nLine ), nLine );
+ }
+}
+
+
+static void ImplSetLineColor( SvxBoxItem& rNewFrame, SvxBoxItemLine nLine, const Color& rColor )
+{
+ const SvxBorderLine* pSourceLine = rNewFrame.GetLine( nLine );
+ if( pSourceLine )
+ {
+ SvxBorderLine aLine( *pSourceLine );
+ aLine.SetColor( rColor );
+ rNewFrame.SetLine( &aLine, nLine );
+ }
+}
+
+
+static void ImplApplyLineColorItem( CellPosFlag nCellPosFlags, const SvxColorItem* pLineColorItem, SvxBoxItem& rNewFrame )
+{
+ const Color aColor( pLineColorItem->GetValue() );
+
+ if (!(nCellPosFlags & (CellPosFlag::Lower|CellPosFlag::Before|CellPosFlag::After)))
+ ImplSetLineColor( rNewFrame, SvxBoxItemLine::BOTTOM, aColor );
+
+ if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Before|CellPosFlag::After)))
+ ImplSetLineColor( rNewFrame, SvxBoxItemLine::TOP, aColor );
+
+ if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Lower|CellPosFlag::After)))
+ ImplSetLineColor( rNewFrame, SvxBoxItemLine::RIGHT, aColor );
+
+ if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Lower|CellPosFlag::Before)))
+ ImplSetLineColor( rNewFrame, SvxBoxItemLine::LEFT, aColor );
+}
+
+
+static void ImplApplyBorderLineItem( CellPosFlag nCellPosFlags, const SvxBorderLine* pBorderLineItem, SvxBoxItem& rNewFrame )
+{
+ if (nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After|CellPosFlag::Upper|CellPosFlag::Lower))
+ {
+ if (!(nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After))) // check if it's not any corner
+ {
+ if (nCellPosFlags & CellPosFlag::Upper)
+ {
+ if( rNewFrame.GetBottom() )
+ ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::BOTTOM );
+ }
+ else if (nCellPosFlags & CellPosFlag::Lower)
+ {
+ if( rNewFrame.GetTop() )
+ ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::TOP );
+ }
+ }
+ else if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Lower))) // check if it's not any corner
+ {
+ if (nCellPosFlags & CellPosFlag::Before)
+ {
+ if( rNewFrame.GetRight() )
+ ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::RIGHT );
+ }
+ else if (nCellPosFlags & CellPosFlag::After)
+ {
+ if( rNewFrame.GetLeft() )
+ ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::LEFT );
+ }
+ }
+ }
+ else
+ {
+ if( rNewFrame.GetBottom() )
+ ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::BOTTOM );
+ if( rNewFrame.GetTop() )
+ ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::TOP );
+ if( rNewFrame.GetRight() )
+ ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::RIGHT );
+ if( rNewFrame.GetLeft() )
+ ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, SvxBoxItemLine::LEFT );
+ }
+}
+
+
+void SvxTableController::ApplyBorderAttr( const SfxItemSet& rAttr )
+{
+ if( !mxTable.is() )
+ return;
+
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+ const sal_Int32 nColCount = mxTable->getColumnCount();
+ if( !(nRowCount && nColCount) )
+ return;
+
+ const SvxBoxItem* pBoxItem = nullptr;
+ if(SfxItemState::SET == rAttr.GetItemState(SDRATTR_TABLE_BORDER, false) )
+ pBoxItem = &rAttr.Get( SDRATTR_TABLE_BORDER );
+
+ const SvxBoxInfoItem* pBoxInfoItem = nullptr;
+ if(SfxItemState::SET == rAttr.GetItemState(SDRATTR_TABLE_BORDER_INNER, false) )
+ pBoxInfoItem = &rAttr.Get( SDRATTR_TABLE_BORDER_INNER );
+
+ const SvxColorItem* pLineColorItem = nullptr;
+ if(SfxItemState::SET == rAttr.GetItemState(SID_FRAME_LINECOLOR, false) )
+ pLineColorItem = &rAttr.Get( SID_FRAME_LINECOLOR );
+
+ const SvxBorderLine* pBorderLineItem = nullptr;
+ if(SfxItemState::SET == rAttr.GetItemState(SID_FRAME_LINESTYLE, false) )
+ pBorderLineItem = rAttr.Get( SID_FRAME_LINESTYLE ).GetLine();
+
+ if( pBoxInfoItem && !pBoxItem )
+ {
+ const static SvxBoxItem gaEmptyBoxItem( SDRATTR_TABLE_BORDER );
+ pBoxItem = &gaEmptyBoxItem;
+ }
+ else if( pBoxItem && !pBoxInfoItem )
+ {
+ const static SvxBoxInfoItem gaEmptyBoxInfoItem( SDRATTR_TABLE_BORDER_INNER );
+ pBoxInfoItem = &gaEmptyBoxInfoItem;
+ }
+
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+
+ const sal_Int32 nLastRow = std::min( aEnd.mnRow + 2, nRowCount );
+ const sal_Int32 nLastCol = std::min( aEnd.mnCol + 2, nColCount );
+
+ for( sal_Int32 nRow = std::max( aStart.mnRow - 1, sal_Int32(0) ); nRow < nLastRow; nRow++ )
+ {
+ CellPosFlag nRowFlags = CellPosFlag::NONE;
+ nRowFlags |= (nRow == aStart.mnRow) ? CellPosFlag::Top : CellPosFlag::NONE;
+ nRowFlags |= (nRow == aEnd.mnRow) ? CellPosFlag::Bottom : CellPosFlag::NONE;
+ nRowFlags |= (nRow < aStart.mnRow) ? CellPosFlag::Upper : CellPosFlag::NONE;
+ nRowFlags |= (nRow > aEnd.mnRow) ? CellPosFlag::Lower : CellPosFlag::NONE;
+
+ for( sal_Int32 nCol = std::max( aStart.mnCol - 1, sal_Int32(0) ); nCol < nLastCol; nCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( !xCell.is() )
+ continue;
+
+ const SfxItemSet& rSet = xCell->GetItemSet();
+ const SvxBoxItem* pOldOuter = &rSet.Get( SDRATTR_TABLE_BORDER );
+
+ SvxBoxItem aNewFrame( *pOldOuter );
+
+ CellPosFlag nCellPosFlags = nRowFlags;
+ nCellPosFlags |= (nCol == aStart.mnCol) ? CellPosFlag::Left : CellPosFlag::NONE;
+ nCellPosFlags |= (nCol == aEnd.mnCol) ? CellPosFlag::Right : CellPosFlag::NONE;
+ nCellPosFlags |= (nCol < aStart.mnCol) ? CellPosFlag::Before : CellPosFlag::NONE;
+ nCellPosFlags |= (nCol > aEnd.mnCol) ? CellPosFlag::After : CellPosFlag::NONE;
+
+ if( pBoxItem && pBoxInfoItem )
+ ImplApplyBoxItem( nCellPosFlags, pBoxItem, pBoxInfoItem, aNewFrame );
+
+ if( pLineColorItem )
+ ImplApplyLineColorItem( nCellPosFlags, pLineColorItem, aNewFrame );
+
+ if( pBorderLineItem )
+ ImplApplyBorderLineItem( nCellPosFlags, pBorderLineItem, aNewFrame );
+
+ if (aNewFrame != *pOldOuter)
+ {
+ SfxItemSet aAttr(*rSet.GetPool(), rSet.GetRanges());
+ aAttr.Put(aNewFrame);
+ xCell->SetMergedItemSetAndBroadcast( aAttr, false );
+ }
+ }
+ }
+}
+
+
+void SvxTableController::UpdateTableShape()
+{
+ SdrObject* pTableObj = mxTableObj.get();
+ if( pTableObj )
+ {
+ pTableObj->ActionChanged();
+ pTableObj->BroadcastObjectChange();
+ }
+ updateSelectionOverlay();
+}
+
+
+void SvxTableController::SetAttrToSelectedCells(const SfxItemSet& rAttr, bool bReplaceAll)
+{
+ if(!checkTableObject() || !mxTable.is())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ const bool bUndo(rModel.IsUndoEnabled());
+
+ if( bUndo )
+ rModel.BegUndo( SvxResId(STR_TABLE_NUMFORMAT) );
+
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+
+ SfxItemSet aAttr(*rAttr.GetPool(), rAttr.GetRanges());
+ aAttr.Put(rAttr);
+
+ const bool bFrame = (rAttr.GetItemState( SDRATTR_TABLE_BORDER ) == SfxItemState::SET) || (rAttr.GetItemState( SDRATTR_TABLE_BORDER_INNER ) == SfxItemState::SET);
+
+ if( bFrame )
+ {
+ aAttr.ClearItem( SDRATTR_TABLE_BORDER );
+ aAttr.ClearItem( SDRATTR_TABLE_BORDER_INNER );
+ }
+
+ for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
+ {
+ for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xCell.is() )
+ {
+ if( bUndo )
+ xCell->AddUndo();
+ xCell->SetMergedItemSetAndBroadcast(aAttr, bReplaceAll);
+ }
+ }
+ }
+
+ if( bFrame )
+ {
+ ApplyBorderAttr( rAttr );
+ }
+
+ UpdateTableShape();
+
+ if( bUndo )
+ rModel.EndUndo();
+}
+
+void SvxTableController::SetAttrToSelectedShape(const SfxItemSet& rAttr)
+{
+ if (!checkTableObject() || !mxTable.is())
+ return;
+
+ // Filter out non-shadow items from rAttr.
+ SfxItemSetFixed<SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST> aSet(*rAttr.GetPool());
+ aSet.Put(rAttr);
+
+ if (!aSet.Count())
+ {
+ // If there are no items to be applied on the shape, then don't set anything, it would
+ // terminate text edit without a good reason, which affects undo/redo.
+ return;
+ }
+
+ // Set shadow items on the marked shape.
+ mrView.SetAttrToMarked(aSet, /*bReplaceAll=*/false);
+}
+
+bool SvxTableController::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
+{
+ if( mxTableObj.is() && hasSelectedCells() )
+ {
+ MergeAttrFromSelectedCells( rTargetSet, bOnlyHardAttr );
+
+ if( mrView.IsTextEdit() )
+ {
+ OutlinerView* pTextEditOutlinerView = mrView.GetTextEditOutlinerView();
+ if(pTextEditOutlinerView)
+ {
+ // FALSE= consider InvalidItems not as the default, but as "holes"
+ rTargetSet.Put(pTextEditOutlinerView->GetAttribs(), false);
+ }
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+bool SvxTableController::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
+{
+ if( mbCellSelectionMode || mrView.IsTextEdit() )
+ {
+ SetAttrToSelectedCells( rSet, bReplaceAll );
+ return true;
+ }
+ return false;
+}
+
+SdrObject* SvxTableController::GetMarkedSdrObjClone(SdrModel& rTargetModel)
+{
+ SdrTableObj* pRetval(nullptr);
+ sdr::table::SdrTableObj* pCurrentSdrTableObj(GetTableObj());
+
+ if(nullptr == pCurrentSdrTableObj)
+ {
+ return pRetval;
+ }
+
+ if(!mxTableObj.is())
+ {
+ return pRetval;
+ }
+
+ // get selection and create full selection
+ CellPos aStart, aEnd;
+ const CellPos aFullStart, aFullEnd(mxTable->getColumnCount()-1, mxTable->getRowCount()-1);
+
+ getSelectedCells(aStart, aEnd);
+
+ // compare to see if we have a partial selection
+ if(aStart != aFullStart || aEnd != aFullEnd)
+ {
+ // create full clone
+ pRetval = pCurrentSdrTableObj->CloneSdrObject(rTargetModel);
+
+ // limit SdrObject's TableModel to partial selection
+ pRetval->CropTableModelToSelection(aStart, aEnd);
+ }
+
+ return pRetval;
+}
+
+bool SvxTableController::PasteObjModel( const SdrModel& rModel )
+{
+ if( mxTableObj.is() && (rModel.GetPageCount() >= 1) )
+ {
+ const SdrPage* pPastePage = rModel.GetPage(0);
+ if( pPastePage && pPastePage->GetObjCount() == 1 )
+ {
+ SdrTableObj* pPasteTableObj = dynamic_cast< SdrTableObj* >( pPastePage->GetObj(0) );
+ if( pPasteTableObj )
+ {
+ return PasteObject( pPasteTableObj );
+ }
+ }
+ }
+
+ return false;
+}
+
+
+bool SvxTableController::PasteObject( SdrTableObj const * pPasteTableObj )
+{
+ if( !pPasteTableObj )
+ return false;
+
+ Reference< XTable > xPasteTable( pPasteTableObj->getTable() );
+ if( !xPasteTable.is() )
+ return false;
+
+ if( !mxTable.is() )
+ return false;
+
+ sal_Int32 nPasteColumns = xPasteTable->getColumnCount();
+ sal_Int32 nPasteRows = xPasteTable->getRowCount();
+
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+
+ if( mrView.IsTextEdit() )
+ mrView.SdrEndTextEdit(true);
+
+ sal_Int32 nColumns = mxTable->getColumnCount();
+ sal_Int32 nRows = mxTable->getRowCount();
+
+ const sal_Int32 nMissing = nPasteRows - ( nRows - aStart.mnRow );
+ if( nMissing > 0 )
+ {
+ Reference< XTableRows > xRows( mxTable->getRows() );
+ xRows->insertByIndex( nRows, nMissing );
+ nRows = mxTable->getRowCount();
+ }
+
+ nPasteRows = std::min( nPasteRows, nRows - aStart.mnRow );
+ nPasteColumns = std::min( nPasteColumns, nColumns - aStart.mnCol );
+
+ // copy cell contents
+ for( sal_Int32 nRow = 0; nRow < nPasteRows; ++nRow )
+ {
+ for( sal_Int32 nCol = 0, nTargetCol = aStart.mnCol; nCol < nPasteColumns; ++nCol )
+ {
+ CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nTargetCol, aStart.mnRow + nRow ).get() ) );
+ if( xTargetCell.is() && !xTargetCell->isMerged() )
+ {
+ CellRef xSourceCell(dynamic_cast<Cell*>(xPasteTable->getCellByPosition(nCol, nRow).get()));
+ if (xSourceCell.is())
+ {
+ xTargetCell->AddUndo();
+ // Prevent cell span exceeding the pasting range.
+ if (nColumns < nTargetCol + xSourceCell->getColumnSpan())
+ xTargetCell->replaceContentAndFormatting(xSourceCell);
+ else
+ xTargetCell->cloneFrom(xSourceCell);
+
+ nCol += xSourceCell->getColumnSpan() - 1;
+ nTargetCol += xTargetCell->getColumnSpan();
+ }
+ }
+ }
+ }
+
+ UpdateTableShape();
+
+ return true;
+}
+
+bool SvxTableController::ApplyFormatPaintBrush( SfxItemSet& rFormatSet, bool bNoCharacterFormats, bool bNoParagraphFormats )
+{
+ if(!mbCellSelectionMode)
+ {
+ return false;
+ }
+
+ if(!checkTableObject())
+ return false;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ const bool bUndo(rModel.IsUndoEnabled());
+
+ if( bUndo )
+ rModel.BegUndo(SvxResId(STR_TABLE_NUMFORMAT));
+
+ CellPos aStart, aEnd;
+ getSelectedCells( aStart, aEnd );
+ const bool bFrame = (rFormatSet.GetItemState( SDRATTR_TABLE_BORDER ) == SfxItemState::SET) || (rFormatSet.GetItemState( SDRATTR_TABLE_BORDER_INNER ) == SfxItemState::SET);
+
+ for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ )
+ {
+ for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xCell.is() )
+ {
+ if (bUndo)
+ xCell->AddUndo();
+ SdrText* pText = xCell.get();
+ SdrObjEditView::ApplyFormatPaintBrushToText( rFormatSet, rTableObj, pText, bNoCharacterFormats, bNoParagraphFormats );
+ }
+ }
+ }
+
+ if( bFrame )
+ {
+ ApplyBorderAttr( rFormatSet );
+ }
+
+ UpdateTableShape();
+
+ if( bUndo )
+ rModel.EndUndo();
+
+ return true;
+}
+
+
+IMPL_LINK_NOARG(SvxTableController, UpdateHdl, void*, void)
+{
+ mnUpdateEvent = nullptr;
+
+ if( mbCellSelectionMode )
+ {
+ CellPos aStart( maCursorFirstPos );
+ CellPos aEnd( maCursorLastPos );
+ checkCell(aStart);
+ checkCell(aEnd);
+ if( aStart != maCursorFirstPos || aEnd != maCursorLastPos )
+ {
+ setSelectedCells( aStart, aEnd );
+ }
+ }
+
+ updateSelectionOverlay();
+ mbHasJustMerged = false;
+}
+
+namespace
+{
+
+struct LinesState
+{
+ LinesState(SvxBoxItem& rBoxItem_, SvxBoxInfoItem& rBoxInfoItem_)
+ : rBoxItem(rBoxItem_)
+ , rBoxInfoItem(rBoxInfoItem_)
+ , bDistanceIndeterminate(false)
+ {
+ aBorderSet.fill(false);
+ aInnerLineSet.fill(false);
+ aBorderIndeterminate.fill(false);
+ aInnerLineIndeterminate.fill(false);
+ aDistanceSet.fill(false);
+ aDistance.fill(0);
+ }
+
+ SvxBoxItem& rBoxItem;
+ SvxBoxInfoItem& rBoxInfoItem;
+ o3tl::enumarray<SvxBoxItemLine, bool> aBorderSet;
+ o3tl::enumarray<SvxBoxInfoItemLine, bool> aInnerLineSet;
+ o3tl::enumarray<SvxBoxItemLine, bool> aBorderIndeterminate;
+ o3tl::enumarray<SvxBoxInfoItemLine, bool> aInnerLineIndeterminate;
+ o3tl::enumarray<SvxBoxItemLine, bool> aDistanceSet;
+ o3tl::enumarray<SvxBoxItemLine, sal_uInt16> aDistance;
+ bool bDistanceIndeterminate;
+};
+
+class BoxItemWrapper
+{
+public:
+ BoxItemWrapper(SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem, SvxBoxItemLine nBorderLine, SvxBoxInfoItemLine nInnerLine, bool bBorder);
+
+ const SvxBorderLine* getLine() const;
+ void setLine(const SvxBorderLine* pLine);
+
+private:
+ SvxBoxItem& m_rBoxItem;
+ SvxBoxInfoItem& m_rBoxInfoItem;
+ const SvxBoxItemLine m_nBorderLine;
+ const SvxBoxInfoItemLine m_nInnerLine;
+ const bool m_bBorder;
+};
+
+BoxItemWrapper::BoxItemWrapper(
+ SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem,
+ const SvxBoxItemLine nBorderLine, const SvxBoxInfoItemLine nInnerLine, const bool bBorder)
+ : m_rBoxItem(rBoxItem)
+ , m_rBoxInfoItem(rBoxInfoItem)
+ , m_nBorderLine(nBorderLine)
+ , m_nInnerLine(nInnerLine)
+ , m_bBorder(bBorder)
+{
+}
+
+const SvxBorderLine* BoxItemWrapper::getLine() const
+{
+ if (m_bBorder)
+ return m_rBoxItem.GetLine(m_nBorderLine);
+ else
+ return (m_nInnerLine == SvxBoxInfoItemLine::HORI) ? m_rBoxInfoItem.GetHori() : m_rBoxInfoItem.GetVert();
+}
+
+void BoxItemWrapper::setLine(const SvxBorderLine* pLine)
+{
+ if (m_bBorder)
+ m_rBoxItem.SetLine(pLine, m_nBorderLine);
+ else
+ m_rBoxInfoItem.SetLine(pLine, m_nInnerLine);
+}
+
+void lcl_MergeBorderLine(
+ LinesState& rLinesState, const SvxBorderLine* const pLine, const SvxBoxItemLine nLine,
+ SvxBoxInfoItemValidFlags nValidFlag, const bool bBorder = true)
+{
+ const SvxBoxInfoItemLine nInnerLine(bBorder ? SvxBoxInfoItemLine::HORI : ((nValidFlag & SvxBoxInfoItemValidFlags::HORI) ? SvxBoxInfoItemLine::HORI : SvxBoxInfoItemLine::VERT));
+ BoxItemWrapper aBoxItem(rLinesState.rBoxItem, rLinesState.rBoxInfoItem, nLine, nInnerLine, bBorder);
+ bool& rbSet(bBorder ? rLinesState.aBorderSet[nLine] : rLinesState.aInnerLineSet[nInnerLine]);
+
+ if (rbSet)
+ {
+ bool& rbIndeterminate(bBorder ? rLinesState.aBorderIndeterminate[nLine] : rLinesState.aInnerLineIndeterminate[nInnerLine]);
+ if (!rbIndeterminate)
+ {
+ const SvxBorderLine* const pMergedLine(aBoxItem.getLine());
+ if ((pLine && !pMergedLine) || (!pLine && pMergedLine) || (pLine && (*pLine != *pMergedLine)))
+ {
+ aBoxItem.setLine(nullptr);
+ rbIndeterminate = true;
+ }
+ }
+ }
+ else
+ {
+ aBoxItem.setLine(pLine);
+ rbSet = true;
+ }
+}
+
+void lcl_MergeBorderOrInnerLine(
+ LinesState& rLinesState, const SvxBorderLine* const pLine, const SvxBoxItemLine nLine,
+ SvxBoxInfoItemValidFlags nValidFlag, const bool bBorder)
+{
+ if (bBorder)
+ lcl_MergeBorderLine(rLinesState, pLine, nLine, nValidFlag);
+ else
+ {
+ const bool bVertical = (nLine == SvxBoxItemLine::LEFT) || (nLine == SvxBoxItemLine::RIGHT);
+ lcl_MergeBorderLine(rLinesState, pLine, nLine, bVertical ? SvxBoxInfoItemValidFlags::VERT : SvxBoxInfoItemValidFlags::HORI, false);
+ }
+}
+
+void lcl_MergeDistance(
+ LinesState& rLinesState, const SvxBoxItemLine nIndex, const sal_uInt16 nDistance)
+{
+ if (rLinesState.aDistanceSet[nIndex])
+ {
+ if (!rLinesState.bDistanceIndeterminate)
+ rLinesState.bDistanceIndeterminate = nDistance != rLinesState.aDistance[nIndex];
+ }
+ else
+ {
+ rLinesState.aDistance[nIndex] = nDistance;
+ rLinesState.aDistanceSet[nIndex] = true;
+ }
+}
+
+void lcl_MergeCommonBorderAttr(LinesState& rLinesState, const SvxBoxItem& rCellBoxItem, const CellPosFlag nCellPosFlags)
+{
+ if (nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After|CellPosFlag::Upper|CellPosFlag::Lower))
+ {
+ // current cell is outside the selection
+
+ if (!(nCellPosFlags & (CellPosFlag::Before|CellPosFlag::After))) // check if it's not any corner
+ {
+ if (nCellPosFlags & CellPosFlag::Upper)
+ lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetBottom(), SvxBoxItemLine::TOP, SvxBoxInfoItemValidFlags::TOP);
+ else if (nCellPosFlags & CellPosFlag::Lower)
+ lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetTop(), SvxBoxItemLine::BOTTOM, SvxBoxInfoItemValidFlags::BOTTOM);
+ }
+ else if (!(nCellPosFlags & (CellPosFlag::Upper|CellPosFlag::Lower))) // check if it's not any corner
+ {
+ if (nCellPosFlags & CellPosFlag::Before)
+ lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetRight(), SvxBoxItemLine::LEFT, SvxBoxInfoItemValidFlags::LEFT);
+ else if (nCellPosFlags & CellPosFlag::After)
+ lcl_MergeBorderLine(rLinesState, rCellBoxItem.GetLeft(), SvxBoxItemLine::RIGHT, SvxBoxInfoItemValidFlags::RIGHT);
+ }
+
+ // NOTE: inner distances for cells outside the selected range
+ // are not relevant -> we ignore them.
+ }
+ else
+ {
+ // current cell is inside the selection
+
+ lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetTop(), SvxBoxItemLine::TOP, SvxBoxInfoItemValidFlags::TOP, static_cast<bool>(nCellPosFlags & CellPosFlag::Top));
+ lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetBottom(), SvxBoxItemLine::BOTTOM, SvxBoxInfoItemValidFlags::BOTTOM, static_cast<bool>(nCellPosFlags & CellPosFlag::Bottom));
+ lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetLeft(), SvxBoxItemLine::LEFT, SvxBoxInfoItemValidFlags::LEFT, static_cast<bool>(nCellPosFlags & CellPosFlag::Left));
+ lcl_MergeBorderOrInnerLine(rLinesState, rCellBoxItem.GetRight(), SvxBoxItemLine::RIGHT, SvxBoxInfoItemValidFlags::RIGHT, static_cast<bool>(nCellPosFlags & CellPosFlag::Right));
+
+ lcl_MergeDistance(rLinesState, SvxBoxItemLine::TOP, rCellBoxItem.GetDistance(SvxBoxItemLine::TOP));
+ lcl_MergeDistance(rLinesState, SvxBoxItemLine::BOTTOM, rCellBoxItem.GetDistance(SvxBoxItemLine::BOTTOM));
+ lcl_MergeDistance(rLinesState, SvxBoxItemLine::LEFT, rCellBoxItem.GetDistance(SvxBoxItemLine::LEFT));
+ lcl_MergeDistance(rLinesState, SvxBoxItemLine::RIGHT, rCellBoxItem.GetDistance(SvxBoxItemLine::RIGHT));
+ }
+}
+
+}
+
+void SvxTableController::FillCommonBorderAttrFromSelectedCells( SvxBoxItem& rBoxItem, SvxBoxInfoItem& rBoxInfoItem ) const
+{
+ if( !mxTable.is() )
+ return;
+
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+ const sal_Int32 nColCount = mxTable->getColumnCount();
+ if( !(nRowCount && nColCount) )
+ return;
+
+ CellPos aStart, aEnd;
+ const_cast< SvxTableController* >( this )->getSelectedCells( aStart, aEnd );
+
+ // We are adding one more row/column around the block of selected cells.
+ // We will be checking the adjoining border of these too.
+ const sal_Int32 nLastRow = std::min( aEnd.mnRow + 2, nRowCount );
+ const sal_Int32 nLastCol = std::min( aEnd.mnCol + 2, nColCount );
+
+ rBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::ALL, false );
+ LinesState aLinesState( rBoxItem, rBoxInfoItem );
+
+ /* Here we go through all the selected cells (enhanced by
+ * the adjoining row/column on each side) and determine the
+ * lines for presentation. The algorithm is simple:
+ * 1. if a border or inner line is set (or unset) in all
+ * cells to the same value, it will be used.
+ * 2. if a border or inner line is set only in some cells,
+ * it will be set to indeterminate state (SetValid() on
+ * rBoxInfoItem).
+ */
+ for( sal_Int32 nRow = std::max( aStart.mnRow - 1, sal_Int32(0) ); nRow < nLastRow; nRow++ )
+ {
+ CellPosFlag nRowFlags = CellPosFlag::NONE;
+ nRowFlags |= (nRow == aStart.mnRow) ? CellPosFlag::Top : CellPosFlag::NONE;
+ nRowFlags |= (nRow == aEnd.mnRow) ? CellPosFlag::Bottom : CellPosFlag::NONE;
+ nRowFlags |= (nRow < aStart.mnRow) ? CellPosFlag::Upper : CellPosFlag::NONE;
+ nRowFlags |= (nRow > aEnd.mnRow) ? CellPosFlag::Lower : CellPosFlag::NONE;
+
+ for( sal_Int32 nCol = std::max( aStart.mnCol - 1, sal_Int32(0) ); nCol < nLastCol; nCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( !xCell.is() )
+ continue;
+
+ CellPosFlag nCellPosFlags = nRowFlags;
+ nCellPosFlags |= (nCol == aStart.mnCol) ? CellPosFlag::Left : CellPosFlag::NONE;
+ nCellPosFlags |= (nCol == aEnd.mnCol) ? CellPosFlag::Right : CellPosFlag::NONE;
+ nCellPosFlags |= (nCol < aStart.mnCol) ? CellPosFlag::Before : CellPosFlag::NONE;
+ nCellPosFlags |= (nCol > aEnd.mnCol) ? CellPosFlag::After : CellPosFlag::NONE;
+
+ const SfxItemSet& rSet = xCell->GetItemSet();
+ SvxBoxItem aCellBoxItem(mergeDrawinglayerTextDistancesAndSvxBoxItem(rSet));
+ lcl_MergeCommonBorderAttr( aLinesState, aCellBoxItem, nCellPosFlags );
+ }
+ }
+
+ if (!aLinesState.aBorderIndeterminate[SvxBoxItemLine::TOP])
+ aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::TOP);
+ if (!aLinesState.aBorderIndeterminate[SvxBoxItemLine::BOTTOM])
+ aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::BOTTOM);
+ if (!aLinesState.aBorderIndeterminate[SvxBoxItemLine::LEFT])
+ aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::LEFT);
+ if (!aLinesState.aBorderIndeterminate[SvxBoxItemLine::RIGHT])
+ aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::RIGHT);
+ if (!aLinesState.aInnerLineIndeterminate[SvxBoxInfoItemLine::HORI])
+ aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::HORI);
+ if (!aLinesState.aInnerLineIndeterminate[SvxBoxInfoItemLine::VERT])
+ aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::VERT);
+
+ if (!aLinesState.bDistanceIndeterminate)
+ {
+ if (aLinesState.aDistanceSet[SvxBoxItemLine::TOP])
+ aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[SvxBoxItemLine::TOP], SvxBoxItemLine::TOP);
+ if (aLinesState.aDistanceSet[SvxBoxItemLine::BOTTOM])
+ aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[SvxBoxItemLine::BOTTOM], SvxBoxItemLine::BOTTOM);
+ if (aLinesState.aDistanceSet[SvxBoxItemLine::LEFT])
+ aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[SvxBoxItemLine::LEFT], SvxBoxItemLine::LEFT);
+ if (aLinesState.aDistanceSet[SvxBoxItemLine::RIGHT])
+ aLinesState.rBoxItem.SetDistance(aLinesState.aDistance[SvxBoxItemLine::RIGHT], SvxBoxItemLine::RIGHT);
+ aLinesState.rBoxInfoItem.SetValid(SvxBoxInfoItemValidFlags::DISTANCE);
+ }
+}
+
+bool SvxTableController::selectRow( sal_Int32 row )
+{
+ if( !mxTable.is() )
+ return false;
+ CellPos aStart( 0, row ), aEnd( mxTable->getColumnCount() - 1, row );
+ StartSelection( aEnd );
+ gotoCell( aStart, true, nullptr );
+ return true;
+}
+
+bool SvxTableController::selectColumn( sal_Int32 column )
+{
+ if( !mxTable.is() )
+ return false;
+ CellPos aStart( column, 0 ), aEnd( column, mxTable->getRowCount() - 1 );
+ StartSelection( aEnd );
+ gotoCell( aStart, true, nullptr );
+ return true;
+}
+
+bool SvxTableController::deselectRow( sal_Int32 row )
+{
+ if( !mxTable.is() )
+ return false;
+ CellPos aStart( 0, row ), aEnd( mxTable->getColumnCount() - 1, row );
+ StartSelection( aEnd );
+ gotoCell( aStart, false, nullptr );
+ return true;
+}
+
+bool SvxTableController::deselectColumn( sal_Int32 column )
+{
+ if( !mxTable.is() )
+ return false;
+ CellPos aStart( column, 0 ), aEnd( column, mxTable->getRowCount() - 1 );
+ StartSelection( aEnd );
+ gotoCell( aStart, false, nullptr );
+ return true;
+}
+
+bool SvxTableController::isRowSelected( sal_Int32 nRow )
+{
+ if( hasSelectedCells() )
+ {
+ CellPos aFirstPos, aLastPos;
+ getSelectedCells( aFirstPos, aLastPos );
+ if( (aFirstPos.mnCol == 0) && (nRow >= aFirstPos.mnRow && nRow <= aLastPos.mnRow) && (mxTable->getColumnCount() - 1 == aLastPos.mnCol) )
+ return true;
+ }
+ return false;
+}
+
+bool SvxTableController::isColumnSelected( sal_Int32 nColumn )
+{
+ if( hasSelectedCells() )
+ {
+ CellPos aFirstPos, aLastPos;
+ getSelectedCells( aFirstPos, aLastPos );
+ if( (aFirstPos.mnRow == 0) && (nColumn >= aFirstPos.mnCol && nColumn <= aLastPos.mnCol) && (mxTable->getRowCount() - 1 == aLastPos.mnRow) )
+ return true;
+ }
+ return false;
+}
+
+bool SvxTableController::isRowHeader()
+{
+ if(!checkTableObject())
+ return false;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ TableStyleSettings aSettings(rTableObj.getTableStyleSettings());
+
+ return aSettings.mbUseFirstRow;
+}
+
+bool SvxTableController::isColumnHeader()
+{
+ if(!checkTableObject())
+ return false;
+
+ SdrTableObj& rTableObj(*mxTableObj);
+ TableStyleSettings aSettings(rTableObj.getTableStyleSettings());
+
+ return aSettings.mbUseFirstColumn;
+}
+
+bool SvxTableController::setCursorLogicPosition(const Point& rPosition, bool bPoint)
+{
+ if (mxTableObj->GetObjIdentifier() != SdrObjKind::Table)
+ return false;
+
+ SdrTableObj* pTableObj = mxTableObj.get();
+ CellPos aCellPos;
+ if (pTableObj->CheckTableHit(rPosition, aCellPos.mnCol, aCellPos.mnRow) != TableHitKind::NONE)
+ {
+ // Position is a table cell.
+ if (mbCellSelectionMode)
+ {
+ // We have a table selection already: adjust the point or the mark.
+ if (bPoint)
+ setSelectedCells(maCursorFirstPos, aCellPos);
+ else
+ setSelectedCells(aCellPos, maCursorLastPos);
+ return true;
+ }
+ else if (aCellPos != maMouseDownPos)
+ {
+ // No selection, but rPosition is at another cell: start table selection.
+ StartSelection(maMouseDownPos);
+ // Update graphic selection, should be hidden now.
+ mrView.AdjustMarkHdl();
+ }
+ }
+
+ return false;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tabledesign.cxx b/svx/source/table/tabledesign.cxx
new file mode 100644
index 000000000..03b16250f
--- /dev/null
+++ b/svx/source/table/tabledesign.cxx
@@ -0,0 +1,705 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+
+#include <vcl/svapp.hxx>
+
+#include <comphelper/compbase.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <svx/sdr/table/tabledesign.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+#include <celltypes.hxx>
+
+#include <vector>
+#include <map>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::style;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::container;
+
+namespace sdr::table {
+
+typedef std::map< OUString, sal_Int32 > CellStyleNameMap;
+
+typedef ::comphelper::WeakComponentImplHelper< XStyle, XNameReplace, XServiceInfo, XIndexAccess, XModifyBroadcaster, XModifyListener > TableDesignStyleBase;
+
+namespace {
+
+class TableDesignStyle : public TableDesignStyleBase
+{
+public:
+ TableDesignStyle();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XStyle
+ virtual sal_Bool SAL_CALL isUserDefined() override;
+ virtual sal_Bool SAL_CALL isInUse() override;
+ virtual OUString SAL_CALL getParentStyle() override;
+ virtual void SAL_CALL setParentStyle( const OUString& aParentStyle ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+
+ // XNameAccess
+ virtual Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const Any& aElement ) override;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const Reference< XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const Reference< XModifyListener >& aListener ) override;
+
+ // XModifyListener
+ virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ void notifyModifyListener();
+
+ // this function is called upon disposing the component
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ static const CellStyleNameMap& getCellStyleNameMap();
+
+ OUString msName;
+ Reference< XStyle > maCellStyles[style_count];
+ comphelper::OInterfaceContainerHelper4<XModifyListener> maModifyListeners;
+};
+
+}
+
+typedef std::vector< Reference< XStyle > > TableDesignStyleVector;
+
+namespace {
+
+class TableDesignFamily : public ::cppu::WeakImplHelper< XNameContainer, XNamed, XIndexAccess, XSingleServiceFactory, XServiceInfo, XComponent, XPropertySet >
+{
+public:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+
+ // XNameAccess
+ virtual Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& aName, const Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& Name ) override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const Any& aElement ) override;
+
+ // XSingleServiceFactory
+ virtual Reference< XInterface > SAL_CALL createInstance( ) override;
+ virtual Reference< XInterface > SAL_CALL createInstanceWithArguments( const Sequence< Any >& aArguments ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override;
+
+ // XPropertySet
+ virtual Reference<XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) override;
+ virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference<XPropertyChangeListener>& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener>& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName,const Reference<XVetoableChangeListener>&aListener ) override;
+
+ TableDesignStyleVector maDesigns;
+};
+
+}
+
+TableDesignStyle::TableDesignStyle()
+{
+}
+
+const CellStyleNameMap& TableDesignStyle::getCellStyleNameMap()
+{
+ static CellStyleNameMap const aMap
+ {
+ { OUString( "first-row" ) , first_row_style },
+ { OUString( "last-row" ) , last_row_style },
+ { OUString( "first-column" ) , first_column_style },
+ { OUString( "last-column" ) , last_column_style },
+ { OUString( "body" ) , body_style },
+ { OUString( "even-rows" ) , even_rows_style },
+ { OUString( "odd-rows" ) , odd_rows_style },
+ { OUString( "even-columns" ) , even_columns_style },
+ { OUString( "odd-columns" ) , odd_columns_style },
+ { OUString( "background" ) , background_style },
+ };
+
+ return aMap;
+}
+
+// XServiceInfo
+OUString SAL_CALL TableDesignStyle::getImplementationName()
+{
+ return "TableDesignStyle";
+}
+
+sal_Bool SAL_CALL TableDesignStyle::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+Sequence< OUString > SAL_CALL TableDesignStyle::getSupportedServiceNames()
+{
+ return { "com.sun.star.style.Style" };
+}
+
+// XStyle
+sal_Bool SAL_CALL TableDesignStyle::isUserDefined()
+{
+ return false;
+}
+
+sal_Bool SAL_CALL TableDesignStyle::isInUse()
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (maModifyListeners.getLength(aGuard))
+ {
+ comphelper::OInterfaceIteratorHelper4 it(aGuard, maModifyListeners);
+ while ( it.hasMoreElements() )
+ {
+ TableDesignUser* pUser = dynamic_cast< TableDesignUser* >( it.next().get() );
+ if( pUser && pUser->isInUse() )
+ return true;
+ }
+ }
+ return false;
+}
+
+
+OUString SAL_CALL TableDesignStyle::getParentStyle()
+{
+ return OUString();
+}
+
+
+void SAL_CALL TableDesignStyle::setParentStyle( const OUString& )
+{
+}
+
+
+// XNamed
+
+
+OUString SAL_CALL TableDesignStyle::getName()
+{
+ return msName;
+}
+
+
+void SAL_CALL TableDesignStyle::setName( const OUString& rName )
+{
+ msName = rName;
+}
+
+
+// XNameAccess
+
+
+Any SAL_CALL TableDesignStyle::getByName( const OUString& rName )
+{
+ const CellStyleNameMap& rMap = getCellStyleNameMap();
+
+ CellStyleNameMap::const_iterator iter = rMap.find( rName );
+ if( iter == rMap.end() )
+ throw NoSuchElementException();
+
+ return Any( maCellStyles[(*iter).second] );
+}
+
+
+Sequence< OUString > SAL_CALL TableDesignStyle::getElementNames()
+{
+ return comphelper::mapKeysToSequence( getCellStyleNameMap() );
+}
+
+
+sal_Bool SAL_CALL TableDesignStyle::hasByName( const OUString& rName )
+{
+ const CellStyleNameMap& rMap = getCellStyleNameMap();
+
+ CellStyleNameMap::const_iterator iter = rMap.find( rName );
+ return iter != rMap.end();
+}
+
+
+// XElementAccess
+
+
+Type SAL_CALL TableDesignStyle::getElementType()
+{
+ return cppu::UnoType<XStyle>::get();
+}
+
+
+sal_Bool SAL_CALL TableDesignStyle::hasElements()
+{
+ return true;
+}
+
+
+// XIndexAccess
+
+
+sal_Int32 SAL_CALL TableDesignStyle::getCount()
+{
+ return style_count;
+}
+
+
+Any SAL_CALL TableDesignStyle::getByIndex( sal_Int32 Index )
+{
+ if( (Index < 0) || (Index >= style_count) )
+ throw IndexOutOfBoundsException();
+
+ std::unique_lock aGuard( m_aMutex );
+ return Any( maCellStyles[Index] );
+}
+
+
+// XNameReplace
+
+
+void SAL_CALL TableDesignStyle::replaceByName( const OUString& rName, const Any& aElement )
+{
+ const CellStyleNameMap& rMap = getCellStyleNameMap();
+ CellStyleNameMap::const_iterator iter = rMap.find( rName );
+ if( iter == rMap.end() )
+ throw NoSuchElementException();
+
+
+ Reference< XStyle > xNewStyle;
+ if( !(aElement >>= xNewStyle) )
+ throw IllegalArgumentException();
+
+ const sal_Int32 nIndex = (*iter).second;
+
+ std::unique_lock aGuard( m_aMutex );
+
+ Reference< XStyle > xOldStyle( maCellStyles[nIndex] );
+
+ if( xNewStyle == xOldStyle )
+ return;
+
+ Reference< XModifyListener > xListener( this );
+
+ // end listening to old style, if possible
+ Reference< XModifyBroadcaster > xOldBroadcaster( xOldStyle, UNO_QUERY );
+ if( xOldBroadcaster.is() )
+ xOldBroadcaster->removeModifyListener( xListener );
+
+ // start listening to new style, if possible
+ Reference< XModifyBroadcaster > xNewBroadcaster( xNewStyle, UNO_QUERY );
+ if( xNewBroadcaster.is() )
+ xNewBroadcaster->addModifyListener( xListener );
+
+ maCellStyles[nIndex] = xNewStyle;
+}
+
+
+// XComponent
+
+
+void TableDesignStyle::disposing(std::unique_lock<std::mutex>&)
+{
+ for(Reference<XStyle> & rCellStyle : maCellStyles)
+ rCellStyle.clear();
+}
+
+
+// XModifyBroadcaster
+
+
+void SAL_CALL TableDesignStyle::addModifyListener( const Reference< XModifyListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if (m_bDisposed)
+ {
+ aGuard.unlock();
+ EventObject aEvt( static_cast< OWeakObject * >( this ) );
+ xListener->disposing( aEvt );
+ }
+ else
+ {
+ maModifyListeners.addInterface( aGuard, xListener );
+ }
+}
+
+
+void SAL_CALL TableDesignStyle::removeModifyListener( const Reference< XModifyListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+ maModifyListeners.removeInterface( aGuard, xListener );
+}
+
+
+void TableDesignStyle::notifyModifyListener()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( maModifyListeners.getLength(aGuard) )
+ {
+ EventObject aEvt( static_cast< OWeakObject * >( this ) );
+ maModifyListeners.forEach(aGuard,
+ [&] (Reference<XModifyListener> const& xListener)
+ { return xListener->modified(aEvt); });
+ }
+}
+
+
+// XModifyListener
+
+
+// if we get a modify hint from a style, notify all registered XModifyListener
+void SAL_CALL TableDesignStyle::modified( const css::lang::EventObject& )
+{
+ notifyModifyListener();
+}
+
+
+void SAL_CALL TableDesignStyle::disposing( const css::lang::EventObject& )
+{
+}
+
+
+// TableStyle
+
+
+// XServiceInfo
+OUString SAL_CALL TableDesignFamily::getImplementationName()
+{
+ return "TableDesignFamily";
+}
+
+sal_Bool SAL_CALL TableDesignFamily::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+Sequence< OUString > SAL_CALL TableDesignFamily::getSupportedServiceNames()
+{
+ return { "com.sun.star.style.StyleFamily" };
+}
+
+// XNamed
+OUString SAL_CALL TableDesignFamily::getName()
+{
+ return "table";
+}
+
+void SAL_CALL TableDesignFamily::setName( const OUString& )
+{
+}
+
+// XNameAccess
+Any SAL_CALL TableDesignFamily::getByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+
+ auto iter = std::find_if(maDesigns.begin(), maDesigns.end(),
+ [&rName](const Reference<XStyle>& rpStyle) { return rpStyle->getName() == rName; });
+ if (iter != maDesigns.end())
+ return Any( (*iter) );
+
+ throw NoSuchElementException();
+}
+
+
+Sequence< OUString > SAL_CALL TableDesignFamily::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ Sequence< OUString > aRet( maDesigns.size() );
+ OUString* pNames = aRet.getArray();
+
+ for( const auto& rpStyle : maDesigns )
+ *pNames++ = rpStyle->getName();
+
+ return aRet;
+}
+
+
+sal_Bool SAL_CALL TableDesignFamily::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ return std::any_of(maDesigns.begin(), maDesigns.end(),
+ [&aName](const Reference<XStyle>& rpStyle) { return rpStyle->getName() == aName; });
+}
+
+
+// XElementAccess
+
+
+Type SAL_CALL TableDesignFamily::getElementType()
+{
+ return cppu::UnoType<XStyle>::get();
+}
+
+
+sal_Bool SAL_CALL TableDesignFamily::hasElements()
+{
+ SolarMutexGuard aGuard;
+
+ return !maDesigns.empty();
+}
+
+
+// XIndexAccess
+
+
+sal_Int32 SAL_CALL TableDesignFamily::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ return sal::static_int_cast< sal_Int32 >( maDesigns.size() );
+}
+
+
+Any SAL_CALL TableDesignFamily::getByIndex( sal_Int32 Index )
+{
+ SolarMutexGuard aGuard;
+
+ if( (Index >= 0) && (Index < sal::static_int_cast< sal_Int32 >( maDesigns.size() ) ) )
+ return Any( maDesigns[Index] );
+
+ throw IndexOutOfBoundsException();
+}
+
+
+// XNameContainer
+
+
+void SAL_CALL TableDesignFamily::insertByName( const OUString& rName, const Any& rElement )
+{
+ SolarMutexGuard aGuard;
+
+ Reference< XStyle > xStyle( rElement, UNO_QUERY );
+ if( !xStyle.is() )
+ throw IllegalArgumentException();
+
+ xStyle->setName( rName );
+ if (std::any_of(maDesigns.begin(), maDesigns.end(),
+ [&rName](const Reference<XStyle>& rpStyle) { return rpStyle->getName() == rName; }))
+ throw ElementExistException();
+
+ maDesigns.push_back( xStyle );
+}
+
+
+void SAL_CALL TableDesignFamily::removeByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+
+ auto iter = std::find_if(maDesigns.begin(), maDesigns.end(),
+ [&rName](const Reference<XStyle>& rpStyle) { return rpStyle->getName() == rName; });
+ if (iter != maDesigns.end())
+ {
+ maDesigns.erase( iter );
+ return;
+ }
+
+ throw NoSuchElementException();
+}
+
+
+// XNameReplace
+
+
+void SAL_CALL TableDesignFamily::replaceByName( const OUString& rName, const Any& aElement )
+{
+ SolarMutexGuard aGuard;
+
+ Reference< XStyle > xStyle( aElement, UNO_QUERY );
+ if( !xStyle.is() )
+ throw IllegalArgumentException();
+
+ auto iter = std::find_if(maDesigns.begin(), maDesigns.end(),
+ [&rName](const Reference<XStyle>& rpStyle) { return rpStyle->getName() == rName; });
+ if (iter != maDesigns.end())
+ {
+ (*iter) = xStyle;
+ xStyle->setName( rName );
+ return;
+ }
+
+ throw NoSuchElementException();
+}
+
+
+// XSingleServiceFactory
+
+
+Reference< XInterface > SAL_CALL TableDesignFamily::createInstance()
+{
+ return Reference< XInterface >( static_cast< XStyle* >( new TableDesignStyle ) );
+}
+
+
+Reference< XInterface > SAL_CALL TableDesignFamily::createInstanceWithArguments( const Sequence< Any >& )
+{
+ return createInstance();
+}
+
+
+// XComponent
+
+
+void SAL_CALL TableDesignFamily::dispose( )
+{
+ TableDesignStyleVector aDesigns;
+ aDesigns.swap( maDesigns );
+
+ for( const auto& rStyle : aDesigns )
+ {
+ Reference< XComponent > xComp( rStyle, UNO_QUERY );
+ if( xComp.is() )
+ xComp->dispose();
+ }
+}
+
+
+void SAL_CALL TableDesignFamily::addEventListener( const Reference< XEventListener >& )
+{
+}
+
+
+void SAL_CALL TableDesignFamily::removeEventListener( const Reference< XEventListener >& )
+{
+}
+
+
+// XPropertySet
+
+
+Reference<XPropertySetInfo> TableDesignFamily::getPropertySetInfo()
+{
+ OSL_FAIL( "###unexpected!" );
+ return Reference<XPropertySetInfo>();
+}
+
+
+void TableDesignFamily::setPropertyValue( const OUString& , const Any& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+
+Any TableDesignFamily::getPropertyValue( const OUString& PropertyName )
+{
+ if ( PropertyName != "DisplayName" )
+ {
+ throw UnknownPropertyException( "unknown property: " + PropertyName, static_cast<OWeakObject *>(this) );
+ }
+
+ OUString sDisplayName( SvxResId( RID_SVXSTR_STYLEFAMILY_TABLEDESIGN ) );
+ return Any( sDisplayName );
+}
+
+
+void TableDesignFamily::addPropertyChangeListener( const OUString& , const Reference<XPropertyChangeListener>& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+
+void TableDesignFamily::removePropertyChangeListener( const OUString& , const Reference<XPropertyChangeListener>& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+
+void TableDesignFamily::addVetoableChangeListener( const OUString& , const Reference<XVetoableChangeListener>& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+
+void TableDesignFamily::removeVetoableChangeListener( const OUString& , const Reference<XVetoableChangeListener>& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+
+Reference< XNameAccess > CreateTableDesignFamily()
+{
+ return new TableDesignFamily;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablehandles.cxx b/svx/source/table/tablehandles.cxx
new file mode 100644
index 000000000..a776c579e
--- /dev/null
+++ b/svx/source/table/tablehandles.cxx
@@ -0,0 +1,313 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "tablehandles.hxx"
+
+#include <vcl/outdev.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <svx/sdr/overlay/overlayobject.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svdmrkv.hxx>
+#include <svx/svdpagv.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHairlinePrimitive2D.hxx>
+#include <sdr/overlay/overlayrectangle.hxx>
+#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <osl/diagnose.h>
+
+namespace sdr::table {
+
+namespace {
+
+class OverlayTableEdge : public sdr::overlay::OverlayObject
+{
+protected:
+ basegfx::B2DPolyPolygon maPolyPolygon;
+ bool mbVisible;
+
+ // geometry creation for OverlayObject
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+public:
+ OverlayTableEdge( const basegfx::B2DPolyPolygon& rPolyPolygon, bool bVisible );
+};
+
+}
+
+TableEdgeHdl::TableEdgeHdl( const Point& rPnt, bool bHorizontal, sal_Int32 nMin, sal_Int32 nMax, sal_Int32 nEdges )
+: SdrHdl( rPnt, SdrHdlKind::User )
+, mbHorizontal( bHorizontal )
+, mnMin( nMin )
+, mnMax( nMax )
+, maEdges(nEdges)
+{
+}
+
+void TableEdgeHdl::SetEdge( sal_Int32 nEdge, sal_Int32 nStart, sal_Int32 nEnd, TableEdgeState eState )
+{
+ if( (nEdge >= 0) && (nEdge <= sal::static_int_cast<sal_Int32>(maEdges.size())) )
+ {
+ maEdges[nEdge].mnStart = nStart;
+ maEdges[nEdge].mnEnd = nEnd;
+ maEdges[nEdge].meState = eState;
+ }
+ else
+ {
+ OSL_FAIL( "sdr::table::TableEdgeHdl::SetEdge(), invalid edge!" );
+ }
+}
+
+PointerStyle TableEdgeHdl::GetPointer() const
+{
+ if( mbHorizontal )
+ return PointerStyle::VSplit;
+ else
+ return PointerStyle::HSplit;
+}
+
+sal_Int32 TableEdgeHdl::GetValidDragOffset( const SdrDragStat& rDrag ) const
+{
+ return std::clamp( static_cast<sal_Int32>(mbHorizontal ? rDrag.GetDY() : rDrag.GetDX()), mnMin, mnMax );
+}
+
+basegfx::B2DPolyPolygon TableEdgeHdl::getSpecialDragPoly(const SdrDragStat& rDrag) const
+{
+ basegfx::B2DPolyPolygon aVisible;
+ basegfx::B2DPolyPolygon aInvisible;
+
+ // create and return visible and non-visible parts for drag
+ getPolyPolygon(aVisible, aInvisible, &rDrag);
+ aVisible.append(aInvisible);
+
+ return aVisible;
+}
+
+void TableEdgeHdl::getPolyPolygon(basegfx::B2DPolyPolygon& rVisible, basegfx::B2DPolyPolygon& rInvisible, const SdrDragStat* pDrag) const
+{
+ // changed method to create visible and invisible partial polygons in one run in
+ // separate PolyPolygons; both kinds are used
+ basegfx::B2DPoint aOffset(aPos.X(), aPos.Y());
+ rVisible.clear();
+ rInvisible.clear();
+
+ if( pDrag )
+ {
+ basegfx::Axis2D eDragAxis = mbHorizontal ? basegfx::Axis2D::Y : basegfx::Axis2D::X;
+ aOffset.set(eDragAxis, aOffset.get(eDragAxis) + GetValidDragOffset( *pDrag ));
+ }
+
+ basegfx::B2DPoint aStart(aOffset), aEnd(aOffset);
+ basegfx::Axis2D eAxis = mbHorizontal ? basegfx::Axis2D::X : basegfx::Axis2D::Y;
+
+ for( const TableEdge& aEdge : maEdges )
+ {
+ aStart.set(eAxis, aOffset.get(eAxis) + aEdge.mnStart);
+ aEnd.set(eAxis, aOffset.get(eAxis) + aEdge.mnEnd);
+
+ basegfx::B2DPolygon aPolygon;
+ aPolygon.append( aStart );
+ aPolygon.append( aEnd );
+
+ if(aEdge.meState == Visible)
+ {
+ rVisible.append(aPolygon);
+ }
+ else
+ {
+ rInvisible.append(aPolygon);
+ }
+ }
+}
+
+void TableEdgeHdl::CreateB2dIAObject()
+{
+ GetRidOfIAObject();
+
+ if(!pHdlList || !pHdlList->GetView() || pHdlList->GetView()->areMarkHandlesHidden())
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ basegfx::B2DPolyPolygon aVisible;
+ basegfx::B2DPolyPolygon aInvisible;
+
+ // get visible and invisible parts
+ getPolyPolygon(aVisible, aInvisible, nullptr);
+
+ if(!(aVisible.count() || aInvisible.count()))
+ return;
+
+ for(sal_uInt32 nWindow = 0; nWindow < pPageView->PageWindowCount(); nWindow++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(nWindow);
+
+ if(rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
+ if (xManager.is())
+ {
+ if(aVisible.count())
+ {
+ // create overlay object for visible parts
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject(new OverlayTableEdge(aVisible, true));
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+
+ if(aInvisible.count())
+ {
+ // also create overlay object for invisible parts to allow
+ // a standard HitTest using the primitives from that overlay object
+ // (see OverlayTableEdge implementation)
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject(new OverlayTableEdge(aInvisible, false));
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+ }
+}
+
+
+OverlayTableEdge::OverlayTableEdge( const basegfx::B2DPolyPolygon& rPolyPolygon, bool bVisible )
+: OverlayObject(COL_GRAY)
+, maPolyPolygon( rPolyPolygon )
+, mbVisible(bVisible)
+{
+}
+
+drawinglayer::primitive2d::Primitive2DContainer OverlayTableEdge::createOverlayObjectPrimitive2DSequence()
+{
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(maPolyPolygon.count())
+ {
+ // Discussed with CL. Currently i will leave the transparence out since this
+ // a little bit expensive. We may check the look with drag polygons later
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::PolyPolygonHairlinePrimitive2D(
+ maPolyPolygon,
+ getBaseColor().getBColor()));
+
+ if(mbVisible)
+ {
+ // visible, just return as sequence
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+ else
+ {
+ // embed in HiddenGeometryPrimitive2D to support HitTest of this invisible
+ // overlay object
+ drawinglayer::primitive2d::Primitive2DContainer aSequence { aReference };
+ const drawinglayer::primitive2d::Primitive2DReference aNewReference(
+ new drawinglayer::primitive2d::HiddenGeometryPrimitive2D(std::move(aSequence)));
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aNewReference };
+ }
+ }
+
+ return aRetval;
+}
+
+
+TableBorderHdl::TableBorderHdl(
+ const tools::Rectangle& rRect,
+ bool bAnimate)
+: SdrHdl(rRect.TopLeft(), SdrHdlKind::Move),
+ maRectangle(rRect),
+ mbAnimate(bAnimate)
+{
+}
+
+PointerStyle TableBorderHdl::GetPointer() const
+{
+ return PointerStyle::Move;
+}
+
+// create marker for this kind
+void TableBorderHdl::CreateB2dIAObject()
+{
+ GetRidOfIAObject();
+
+ if (!pHdlList || !pHdlList->GetView() || pHdlList->GetView()->areMarkHandlesHidden())
+ return;
+
+ SdrMarkView* pView = pHdlList->GetView();
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if (!pPageView)
+ return;
+
+ for(sal_uInt32 nWindow = 0; nWindow < pPageView->PageWindowCount(); nWindow++)
+ {
+ const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(nWindow);
+
+ if (rPageWindow.GetPaintWindow().OutputToWindow())
+ {
+ const rtl::Reference<sdr::overlay::OverlayManager>& xManager = rPageWindow.GetOverlayManager();
+
+ if (xManager.is())
+ {
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(maRectangle);
+ const Color aHilightColor(SvtOptionsDrawinglayer::getHilightColor());
+ const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
+ // make animation dependent from text edit active, because for tables
+ // this handle is also used when text edit *is* active for it. This
+ // interferes too much concerning repaint stuff (at least as long as
+ // text edit is not yet on the overlay)
+
+ OutputDevice& rOutDev = rPageWindow.GetPaintWindow().GetOutputDevice();
+ float fScaleFactor = rOutDev.GetDPIScaleFactor();
+ double fWidth = fScaleFactor * 6.0;
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject(
+ new sdr::overlay::OverlayRectangle(aRange.getMinimum(), aRange.getMaximum(),
+ aHilightColor, fTransparence,
+ fWidth, 0.0, 0.0, mbAnimate));
+
+ // OVERLAYMANAGER
+ insertNewlyCreatedOverlayObjectForSdrHdl(
+ std::move(pOverlayObject),
+ rPageWindow.GetObjectContact(),
+ *xManager);
+ }
+ }
+ }
+}
+
+
+} // end of namespace sdr::table
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablehandles.hxx b/svx/source/table/tablehandles.hxx
new file mode 100644
index 000000000..095edb0b5
--- /dev/null
+++ b/svx/source/table/tablehandles.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_TABLEHANDLES_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_TABLEHANDLES_HXX
+
+#include <svx/svdhdl.hxx>
+
+
+namespace sdr::table {
+
+enum TableEdgeState { Empty, Invisible, Visible };
+
+struct TableEdge
+{
+ sal_Int32 mnStart;
+ sal_Int32 mnEnd;
+ TableEdgeState meState;
+
+ TableEdge() : mnStart(0), mnEnd(0), meState(Empty) {}
+};
+
+class TableEdgeHdl : public SdrHdl
+{
+public:
+ TableEdgeHdl( const Point& rPnt, bool bHorizontal, sal_Int32 nMin, sal_Int32 nMax, sal_Int32 nEdges );
+
+ sal_Int32 GetValidDragOffset( const SdrDragStat& rDrag ) const;
+
+ virtual PointerStyle GetPointer() const override;
+
+ void SetEdge( sal_Int32 nEdge, sal_Int32 nStart, sal_Int32 nEnd, TableEdgeState nState );
+
+ bool IsHorizontalEdge() const { return mbHorizontal; }
+
+ basegfx::B2DPolyPolygon getSpecialDragPoly(const SdrDragStat& rDrag) const;
+ void getPolyPolygon(basegfx::B2DPolyPolygon& rVisible, basegfx::B2DPolyPolygon& rInvisible, const SdrDragStat* pDrag) const;
+
+protected:
+ // create marker for this kind
+ virtual void CreateB2dIAObject() override;
+
+private:
+ bool mbHorizontal;
+ sal_Int32 mnMin, mnMax;
+ std::vector< TableEdge > maEdges;
+};
+
+class TableBorderHdl : public SdrHdl
+{
+public:
+ TableBorderHdl(
+ const tools::Rectangle& rRect,
+ bool bAnimate);
+
+ virtual PointerStyle GetPointer() const override;
+
+protected:
+ // create marker for this kind
+ virtual void CreateB2dIAObject() override;
+
+private:
+ tools::Rectangle maRectangle;
+
+ bool mbAnimate : 1;
+};
+
+} // end of namespace sdr::table
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablelayouter.cxx b/svx/source/table/tablelayouter.cxx
new file mode 100644
index 000000000..d846a719c
--- /dev/null
+++ b/svx/source/table/tablelayouter.cxx
@@ -0,0 +1,1311 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/table/XMergeableCell.hpp>
+
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/gen.hxx>
+#include <libxml/xmlwriter.h>
+
+#include <cell.hxx>
+#include <o3tl/safeint.hxx>
+#include <tablemodel.hxx>
+#include "tablelayouter.hxx"
+#include <svx/svdotable.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/boxitem.hxx>
+
+using ::editeng::SvxBorderLine;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::text;
+
+
+namespace sdr::table {
+
+
+static SvxBorderLine gEmptyBorder;
+
+constexpr OUStringLiteral gsSize( u"Size" );
+
+TableLayouter::TableLayouter( const TableModelRef& xTableModel )
+: mxTable( xTableModel )
+{
+}
+
+
+TableLayouter::~TableLayouter()
+{
+ ClearBorderLayout();
+}
+
+
+basegfx::B2ITuple TableLayouter::getCellSize( const CellRef& xCell, const CellPos& rPos ) const
+{
+ sal_Int32 width = 0;
+ sal_Int32 height = 0;
+
+ try
+ {
+ if( xCell.is() && !xCell->isMerged() )
+ {
+ CellPos aPos( rPos );
+
+ sal_Int32 nRowCount = getRowCount();
+ sal_Int32 nRowSpan = std::max( xCell->getRowSpan(), sal_Int32(1) );
+ while( nRowSpan && (aPos.mnRow < nRowCount) )
+ {
+ if( static_cast<sal_Int32>(maRows.size()) <= aPos.mnRow )
+ break;
+
+ height = o3tl::saturating_add(height, maRows[aPos.mnRow++].mnSize);
+ nRowSpan--;
+ }
+
+ sal_Int32 nColCount = getColumnCount();
+ sal_Int32 nColSpan = std::max( xCell->getColumnSpan(), sal_Int32(1) );
+ while( nColSpan && (aPos.mnCol < nColCount ) )
+ {
+ if( static_cast<sal_Int32>(maColumns.size()) <= aPos.mnCol )
+ break;
+
+ width = o3tl::saturating_add(width, maColumns[aPos.mnCol++].mnSize);
+ nColSpan--;
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+
+ return basegfx::B2ITuple( width, height );
+}
+
+
+bool TableLayouter::getCellArea( const CellRef& xCell, const CellPos& rPos, basegfx::B2IRectangle& rArea ) const
+{
+ try
+ {
+ if( xCell.is() && !xCell->isMerged() && isValid(rPos) )
+ {
+ const basegfx::B2ITuple aCellSize( getCellSize( xCell, rPos ) );
+ const bool bRTL = (mxTable->getSdrTableObj()->GetWritingMode() == WritingMode_RL_TB);
+
+ if( (rPos.mnCol < static_cast<sal_Int32>(maColumns.size())) && (rPos.mnRow < static_cast<sal_Int32>(maRows.size()) ) )
+ {
+ const sal_Int32 y = maRows[rPos.mnRow].mnPos;
+
+ sal_Int32 endy;
+ if (o3tl::checked_add(y, aCellSize.getY(), endy))
+ return false;
+
+ if(bRTL)
+ {
+ ///For RTL Table Calculate the Right End of cell instead of Left
+ const sal_Int32 x = maColumns[rPos.mnCol].mnPos + maColumns[rPos.mnCol].mnSize;
+ sal_Int32 startx;
+ if (o3tl::checked_sub(x, aCellSize.getX(), startx))
+ return false;
+ rArea = basegfx::B2IRectangle(startx, y, x, endy);
+ }
+ else
+ {
+ const sal_Int32 x = maColumns[rPos.mnCol].mnPos;
+ sal_Int32 endx;
+ if (o3tl::checked_add(x, aCellSize.getX(), endx))
+ return false;
+ rArea = basegfx::B2IRectangle(x, y, endx, endy);
+ }
+ return true;
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+ return false;
+}
+
+
+sal_Int32 TableLayouter::getRowHeight( sal_Int32 nRow ) const
+{
+ if( isValidRow(nRow) )
+ return maRows[nRow].mnSize;
+ else
+ return 0;
+}
+
+
+sal_Int32 TableLayouter::getColumnWidth( sal_Int32 nColumn ) const
+{
+ if( isValidColumn(nColumn) )
+ return maColumns[nColumn].mnSize;
+ else
+ return 0;
+}
+
+sal_Int32 TableLayouter::calcPreferredColumnWidth( sal_Int32 nColumn, Size aSize ) const
+{
+ sal_Int32 nRet = 0;
+ for ( sal_uInt32 nRow = 0; nRow < static_cast<sal_uInt32>(maRows.size()); ++nRow )
+ {
+ // Account for the space desired by spanned columns.
+ // Only the last spanned cell will try to ensure sufficient space,
+ // by looping through the previous columns, subtracting their portion.
+ sal_Int32 nWish = 0;
+ sal_Int32 nSpannedColumn = nColumn;
+ bool bFindSpan = true;
+ while ( bFindSpan && isValidColumn(nSpannedColumn) )
+ {
+ // recursive function call gets earlier portion of spanned column.
+ if ( nSpannedColumn < nColumn )
+ nWish -= calcPreferredColumnWidth( nSpannedColumn, aSize );
+
+ CellRef xCell( getCell( CellPos( nSpannedColumn, nRow ) ) );
+ if ( xCell.is() && !xCell->isMerged()
+ && (xCell->getColumnSpan() == 1 || nSpannedColumn < nColumn) )
+ {
+ nWish += xCell->calcPreferredWidth(aSize);
+ bFindSpan = false;
+ }
+ else if ( xCell.is() && xCell->isMerged()
+ && nColumn == nSpannedColumn
+ && isValidColumn(nColumn + 1) )
+ {
+ xCell = getCell( CellPos( nColumn + 1, nRow ) );
+ bFindSpan = xCell.is() && !xCell->isMerged();
+ }
+ nSpannedColumn--;
+ }
+ nRet = std::max( nRet, nWish );
+ }
+ return nRet;
+}
+
+
+bool TableLayouter::isEdgeVisible( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal ) const
+{
+ const BorderLineMap& rMap = bHorizontal ? maHorizontalBorders : maVerticalBorders;
+
+ if( (nEdgeX >= 0) && (nEdgeX < sal::static_int_cast<sal_Int32>(rMap.size())) &&
+ (nEdgeY >= 0) && (nEdgeY < sal::static_int_cast<sal_Int32>(rMap[nEdgeX].size())) )
+ {
+ return rMap[nEdgeX][nEdgeY] != nullptr;
+ }
+ else
+ {
+ OSL_FAIL( "sdr::table::TableLayouter::getBorderLine(), invalid edge!" );
+ }
+
+ return false;
+}
+
+
+/** returns the requested borderline in rpBorderLine or a null pointer if there is no border at this edge */
+SvxBorderLine* TableLayouter::getBorderLine( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal )const
+{
+ SvxBorderLine* pLine = nullptr;
+
+ const BorderLineMap& rMap = bHorizontal ? maHorizontalBorders : maVerticalBorders;
+
+ if( (nEdgeX >= 0) && (nEdgeX < sal::static_int_cast<sal_Int32>(rMap.size())) &&
+ (nEdgeY >= 0) && (nEdgeY < sal::static_int_cast<sal_Int32>(rMap[nEdgeX].size())) )
+ {
+ pLine = rMap[nEdgeX][nEdgeY];
+ if( pLine == &gEmptyBorder )
+ pLine = nullptr;
+ }
+ else
+ {
+ OSL_FAIL( "sdr::table::TableLayouter::getBorderLine(), invalid edge!" );
+ }
+
+ return pLine;
+}
+
+std::vector<EdgeInfo> TableLayouter::getHorizontalEdges()
+{
+ std::vector<EdgeInfo> aReturn;
+ sal_Int32 nRowSize = sal_Int32(maRows.size());
+ for (sal_Int32 i = 0; i <= nRowSize; i++)
+ {
+ sal_Int32 nEdgeMin = 0;
+ sal_Int32 nEdgeMax = 0;
+ sal_Int32 nEdge = getHorizontalEdge(i, &nEdgeMin, &nEdgeMax);
+ nEdgeMin -= nEdge;
+ nEdgeMax -= nEdge;
+ aReturn.emplace_back(i, nEdge, nEdgeMin, nEdgeMax);
+ }
+ return aReturn;
+}
+
+std::vector<EdgeInfo> TableLayouter::getVerticalEdges()
+{
+ std::vector<EdgeInfo> aReturn;
+ sal_Int32 nColumnSize = sal_Int32(maColumns.size());
+ for (sal_Int32 i = 0; i <= nColumnSize; i++)
+ {
+ sal_Int32 nEdgeMin = 0;
+ sal_Int32 nEdgeMax = 0;
+ sal_Int32 nEdge = getVerticalEdge(i, &nEdgeMin, &nEdgeMax);
+ nEdgeMin -= nEdge;
+ nEdgeMax -= nEdge;
+ aReturn.emplace_back(i, nEdge, nEdgeMin, nEdgeMax);
+ }
+ return aReturn;
+}
+
+sal_Int32 TableLayouter::getHorizontalEdge( int nEdgeY, sal_Int32* pnMin /*= 0*/, sal_Int32* pnMax /*= 0*/ )
+{
+ sal_Int32 nRet = 0;
+ const sal_Int32 nRowCount = getRowCount();
+ if( (nEdgeY >= 0) && (nEdgeY <= nRowCount ) )
+ nRet = maRows[std::min(static_cast<sal_Int32>(nEdgeY),nRowCount-1)].mnPos;
+
+ if( nEdgeY == nRowCount )
+ nRet += maRows[nEdgeY - 1].mnSize;
+
+ if( pnMin )
+ {
+ if( (nEdgeY > 0) && (nEdgeY <= nRowCount ) )
+ {
+ *pnMin = maRows[nEdgeY-1].mnPos + 600; // todo
+ }
+ else
+ {
+ *pnMin = nRet;
+ }
+ }
+
+ if( pnMax )
+ {
+ *pnMax = 0x0fffffff;
+ }
+ return nRet;
+}
+
+
+sal_Int32 TableLayouter::getVerticalEdge( int nEdgeX, sal_Int32* pnMin /*= 0*/, sal_Int32* pnMax /*= 0*/ )
+{
+ sal_Int32 nRet = 0;
+
+ const sal_Int32 nColCount = getColumnCount();
+ if( (nEdgeX >= 0) && (nEdgeX <= nColCount ) )
+ nRet = maColumns[std::min(static_cast<sal_Int32>(nEdgeX),nColCount-1)].mnPos;
+
+ const bool bRTL = (mxTable->getSdrTableObj()->GetWritingMode() == WritingMode_RL_TB);
+ if( bRTL )
+ {
+ if( (nEdgeX >= 0) && (nEdgeX < nColCount) )
+ nRet += maColumns[nEdgeX].mnSize;
+ }
+ else
+ {
+ if( nEdgeX == nColCount )
+ nRet += maColumns[nEdgeX - 1].mnSize;
+ }
+
+ if( pnMin )
+ {
+ *pnMin = nRet;
+ if( bRTL )
+ {
+ if( nEdgeX < nColCount )
+ *pnMin = nRet - maColumns[nEdgeX].mnSize + getMinimumColumnWidth(nEdgeX);
+ }
+ else
+ {
+ if( (nEdgeX > 0) && (nEdgeX <= nColCount ) )
+ *pnMin = maColumns[nEdgeX-1].mnPos + getMinimumColumnWidth( nEdgeX-1 );
+ }
+ }
+
+ if( pnMax )
+ {
+ *pnMax = 0x0fffffff; // todo
+ if( bRTL )
+ {
+ if( nEdgeX > 0 )
+ *pnMax = nRet + maColumns[nEdgeX-1].mnSize - getMinimumColumnWidth( nEdgeX-1 );
+ }
+ else
+ {
+ if( (nEdgeX >= 0) && (nEdgeX < nColCount ) )
+ *pnMax = maColumns[nEdgeX].mnPos + maColumns[nEdgeX].mnSize - getMinimumColumnWidth( nEdgeX );
+ }
+ }
+
+ return nRet;
+}
+
+
+static bool checkMergeOrigin( const TableModelRef& xTable, sal_Int32 nMergedX, sal_Int32 nMergedY, sal_Int32 nCellX, sal_Int32 nCellY, bool& bRunning )
+{
+ Reference< XMergeableCell > xCell( xTable->getCellByPosition( nCellX, nCellY ), UNO_QUERY );
+ if( xCell.is() && !xCell->isMerged() )
+ {
+ const sal_Int32 nRight = xCell->getColumnSpan() + nCellX;
+ const sal_Int32 nBottom = xCell->getRowSpan() + nCellY;
+ if( (nMergedX < nRight) && (nMergedY < nBottom) )
+ return true;
+
+ bRunning = false;
+ }
+ return false;
+}
+
+/** returns true if the cell(nMergedX,nMergedY) is merged with other cells.
+ the returned cell( rOriginX, rOriginY ) is the origin( top left cell ) of the merge.
+*/
+bool findMergeOrigin( const TableModelRef& xTable, sal_Int32 nMergedX, sal_Int32 nMergedY, sal_Int32& rOriginX, sal_Int32& rOriginY )
+{
+ rOriginX = nMergedX;
+ rOriginY = nMergedY;
+
+ if( xTable.is() ) try
+ {
+ // check if this cell already the origin or not merged at all
+ Reference< XMergeableCell > xCell( xTable->getCellByPosition( nMergedX, nMergedY ), UNO_QUERY_THROW );
+ if( !xCell->isMerged() )
+ return true;
+
+ bool bCheckVert = true;
+ bool bCheckHorz = true;
+
+ sal_Int32 nMinCol = 0;
+ sal_Int32 nMinRow = 0;
+
+ sal_Int32 nStep = 1, i;
+
+ sal_Int32 nRow, nCol;
+ do
+ {
+ if( bCheckVert )
+ {
+ nRow = nMergedY - nStep;
+ if( nRow >= nMinRow )
+ {
+ nCol = nMergedX;
+ for( i = 0; (i <= nStep) && (nCol >= nMinCol); i++, nCol-- )
+ {
+ if( checkMergeOrigin( xTable, nMergedX, nMergedY, nCol, nRow, bCheckVert ) )
+ {
+ rOriginX = nCol; rOriginY = nRow;
+ return true;
+ }
+
+ if( !bCheckVert )
+ {
+ if( nCol == nMergedX )
+ {
+ nMinRow = nRow+1;
+ }
+ else
+ {
+ bCheckVert = true;
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ bCheckVert = false;
+ }
+ }
+
+ if( bCheckHorz )
+ {
+ nCol = nMergedX - nStep;
+ if( nCol >= nMinCol )
+ {
+ nRow = nMergedY;
+ for( i = 0; (i < nStep) && (nRow >= nMinRow); i++, nRow-- )
+ {
+ if( checkMergeOrigin( xTable, nMergedX, nMergedY, nCol, nRow, bCheckHorz ) )
+ {
+ rOriginX = nCol; rOriginY = nRow;
+ return true;
+ }
+
+ if( !bCheckHorz )
+ {
+ if( nRow == nMergedY )
+ {
+ nMinCol = nCol+1;
+ }
+ else
+ {
+ bCheckHorz = true;
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ bCheckHorz = false;
+ }
+ }
+ nStep++;
+ }
+ while( bCheckVert || bCheckHorz );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+ return false;
+}
+
+
+sal_Int32 TableLayouter::getMinimumColumnWidth( sal_Int32 nColumn )
+{
+ if( isValidColumn( nColumn ) )
+ {
+ return maColumns[nColumn].mnMinSize;
+ }
+ else
+ {
+ OSL_FAIL( "TableLayouter::getMinimumColumnWidth(), column out of range!" );
+ return 0;
+ }
+}
+
+
+sal_Int32 TableLayouter::distribute( LayoutVector& rLayouts, sal_Int32 nDistribute )
+{
+ // break loops after 100 runs to avoid freezing office due to developer error
+ sal_Int32 nSafe = 100;
+
+ const std::size_t nCount = rLayouts.size();
+ std::size_t nIndex;
+
+ bool bConstrainsBroken = false;
+
+ do
+ {
+ bConstrainsBroken = false;
+
+ // first enforce minimum size constrains on all entities
+ for( nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ Layout& rLayout = rLayouts[nIndex];
+ if( rLayout.mnSize < rLayout.mnMinSize )
+ {
+ sal_Int32 nDiff(0);
+ bConstrainsBroken |= o3tl::checked_sub(rLayout.mnMinSize, rLayout.mnSize, nDiff);
+ bConstrainsBroken |= o3tl::checked_sub(nDistribute, nDiff, nDistribute);
+ rLayout.mnSize = rLayout.mnMinSize;
+ }
+ }
+
+ // calculate current width
+ // if nDistribute is < 0 (shrinking), entities that are already
+ // at minimum width are not counted
+ sal_Int32 nCurrentWidth = 0;
+ for( nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ Layout& rLayout = rLayouts[nIndex];
+ if( (nDistribute > 0) || (rLayout.mnSize > rLayout.mnMinSize) )
+ nCurrentWidth = o3tl::saturating_add(nCurrentWidth, rLayout.mnSize);
+ }
+
+ // now distribute over entities
+ if( (nCurrentWidth != 0) && (nDistribute != 0) )
+ {
+ sal_Int32 nDistributed = nDistribute;
+ for( nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ Layout& rLayout = rLayouts[nIndex];
+ if( (nDistribute > 0) || (rLayout.mnSize > rLayout.mnMinSize) )
+ {
+ sal_Int32 n(nDistributed); // for last entity use up rest
+ if (nIndex != (nCount-1))
+ {
+ bConstrainsBroken |= o3tl::checked_multiply(nDistribute, rLayout.mnSize, n);
+ n /= nCurrentWidth;
+ }
+
+ bConstrainsBroken |= o3tl::checked_add(rLayout.mnSize, n, rLayout.mnSize);
+ nDistributed -= n;
+
+ if( rLayout.mnSize < rLayout.mnMinSize )
+ bConstrainsBroken = true;
+ }
+ }
+ }
+ } while( bConstrainsBroken && --nSafe );
+
+ sal_Int32 nSize = 0;
+ for( nIndex = 0; nIndex < nCount; ++nIndex )
+ nSize = o3tl::saturating_add(nSize, rLayouts[nIndex].mnSize);
+
+ return nSize;
+}
+
+
+typedef std::vector< CellRef > MergeableCellVector;
+typedef std::vector< MergeableCellVector > MergeVector;
+
+
+void TableLayouter::LayoutTableWidth( tools::Rectangle& rArea, bool bFit )
+{
+ const sal_Int32 nColCount = getColumnCount();
+ const sal_Int32 nRowCount = getRowCount();
+ if( nColCount == 0 )
+ return;
+
+ MergeVector aMergedCells( nColCount );
+ std::vector<sal_Int32> aOptimalColumns;
+
+ static const OUStringLiteral sOptimalSize(u"OptimalSize");
+
+ if( sal::static_int_cast< sal_Int32 >( maColumns.size() ) != nColCount )
+ maColumns.resize( nColCount );
+
+ Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_SET_THROW );
+
+ // first calculate current width and initial minimum width per column,
+ // merged cells will be counted later
+ sal_Int32 nCurrentWidth = 0;
+ sal_Int32 nCol = 0, nRow = 0;
+ for( nCol = 0; nCol < nColCount; nCol++ )
+ {
+ sal_Int32 nMinWidth = 0;
+
+ bool bIsEmpty = true; // check if all cells in this column are merged
+
+ for( nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ CellRef xCell( getCell( CellPos( nCol, nRow ) ) );
+ if( xCell.is() && !xCell->isMerged() )
+ {
+ bIsEmpty = false;
+
+ sal_Int32 nColSpan = xCell->getColumnSpan();
+ if( nColSpan > 1 )
+ {
+ // merged cells will be evaluated later
+ aMergedCells[nCol+nColSpan-1].push_back( xCell );
+ }
+ else
+ {
+ nMinWidth = std::max( nMinWidth, xCell->getMinimumWidth() );
+ }
+ }
+ }
+
+ maColumns[nCol].mnMinSize = nMinWidth;
+
+ if( bIsEmpty )
+ {
+ maColumns[nCol].mnSize = 0;
+ }
+ else
+ {
+ sal_Int32 nColWidth = 0;
+ Reference< XPropertySet > xColSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW );
+ bool bOptimal = false;
+ xColSet->getPropertyValue( sOptimalSize ) >>= bOptimal;
+ if( bOptimal )
+ {
+ aOptimalColumns.push_back(nCol);
+ }
+ else
+ {
+ xColSet->getPropertyValue( gsSize ) >>= nColWidth;
+ }
+
+ maColumns[nCol].mnSize = std::max( nColWidth, nMinWidth);
+
+ nCurrentWidth = o3tl::saturating_add(nCurrentWidth, maColumns[nCol].mnSize);
+ }
+ }
+
+ // if we have optimal sized rows, distribute what is given (left)
+ if( !bFit && !aOptimalColumns.empty() && (nCurrentWidth < rArea.getWidth()) )
+ {
+ sal_Int32 nLeft = rArea.getWidth() - nCurrentWidth;
+ sal_Int32 nDistribute = nLeft / aOptimalColumns.size();
+
+ auto iter( aOptimalColumns.begin() );
+ while( iter != aOptimalColumns.end() )
+ {
+ sal_Int32 nOptCol = *iter++;
+ if( iter == aOptimalColumns.end() )
+ nDistribute = nLeft;
+
+ maColumns[nOptCol].mnSize += nDistribute;
+ nLeft -= nDistribute;
+ }
+
+ DBG_ASSERT( nLeft == 0, "svx::TableLayouter::LayoutTableWidtht(), layouting failed!" );
+ }
+
+ // now check if merged cells fit
+ for( nCol = 1; nCol < nColCount; ++nCol )
+ {
+ bool bChanges = false;
+
+ const sal_Int32 nOldSize = maColumns[nCol].mnSize;
+
+ for( const CellRef& xCell : aMergedCells[nCol] )
+ {
+ sal_Int32 nMinWidth = xCell->getMinimumWidth();
+
+ for( sal_Int32 nMCol = nCol - xCell->getColumnSpan() + 1; (nMCol > 0) && (nMCol < nCol); ++nMCol )
+ nMinWidth -= maColumns[nMCol].mnSize;
+
+ if( nMinWidth > maColumns[nCol].mnMinSize )
+ maColumns[nCol].mnMinSize = nMinWidth;
+
+ if( nMinWidth > maColumns[nCol].mnSize )
+ {
+ maColumns[nCol].mnSize = nMinWidth;
+ bChanges = true;
+ }
+ }
+
+ if( bChanges )
+ {
+ nCurrentWidth = o3tl::saturating_add(nCurrentWidth, maColumns[nCol].mnSize - nOldSize);
+ }
+ }
+
+ // now scale if wanted and needed
+ if( bFit && (nCurrentWidth != rArea.getWidth()) )
+ distribute( maColumns, rArea.getWidth() - nCurrentWidth );
+
+ // last step, update left edges
+ sal_Int32 nNewWidth = 0;
+
+ const bool bRTL = (mxTable->getSdrTableObj()->GetWritingMode() == WritingMode_RL_TB);
+ RangeIterator<sal_Int32> coliter( 0, nColCount, !bRTL );
+ while( coliter.next(nCol ) )
+ {
+ maColumns[nCol].mnPos = nNewWidth;
+ nNewWidth = o3tl::saturating_add(nNewWidth, maColumns[nCol].mnSize);
+ if( bFit )
+ {
+ Reference< XPropertySet > xColSet( xCols->getByIndex(nCol), UNO_QUERY_THROW );
+ xColSet->setPropertyValue( gsSize, Any( maColumns[nCol].mnSize ) );
+ }
+ }
+
+ rArea.SetSize( Size( nNewWidth, rArea.GetHeight() ) );
+ updateCells( rArea );
+}
+
+
+void TableLayouter::LayoutTableHeight( tools::Rectangle& rArea, bool bFit )
+{
+ const sal_Int32 nColCount = getColumnCount();
+ const sal_Int32 nRowCount = getRowCount();
+
+ if( nRowCount == 0 )
+ return;
+
+ Reference< XTableRows > xRows( mxTable->getRows() );
+
+ MergeVector aMergedCells( nRowCount );
+ std::vector<sal_Int32> aOptimalRows;
+
+ static const OUStringLiteral sOptimalSize(u"OptimalSize");
+
+ // first calculate current height and initial minimum size per column,
+ // merged cells will be counted later
+ sal_Int32 nCurrentHeight = 0;
+ sal_Int32 nCol, nRow;
+ for( nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ sal_Int32 nMinHeight = 0;
+
+ bool bIsEmpty = true; // check if all cells in this row are merged
+
+ for( nCol = 0; nCol < nColCount; ++nCol )
+ {
+ CellRef xCell( getCell( CellPos( nCol, nRow ) ) );
+ if( xCell.is() && !xCell->isMerged() )
+ {
+ bIsEmpty = false;
+
+ sal_Int32 nRowSpan = xCell->getRowSpan();
+ if( nRowSpan > 1 )
+ {
+ // merged cells will be evaluated later
+ aMergedCells[nRow+nRowSpan-1].push_back( xCell );
+ }
+ else
+ {
+ nMinHeight = std::max( nMinHeight, xCell->getMinimumHeight() );
+ }
+ }
+ }
+
+ maRows[nRow].mnMinSize = nMinHeight;
+
+ if( bIsEmpty )
+ {
+ maRows[nRow].mnSize = 0;
+ }
+ else
+ {
+ sal_Int32 nRowHeight = 0;
+ Reference<XPropertySet> xRowSet(xRows->getByIndex(nRow), UNO_QUERY_THROW);
+
+ bool bOptimal = false;
+ xRowSet->getPropertyValue( sOptimalSize ) >>= bOptimal;
+ if( bOptimal )
+ {
+ aOptimalRows.push_back( nRow );
+ }
+ else
+ {
+ xRowSet->getPropertyValue( gsSize ) >>= nRowHeight;
+ }
+
+ maRows[nRow].mnSize = nRowHeight;
+
+ if( maRows[nRow].mnSize < nMinHeight )
+ maRows[nRow].mnSize = nMinHeight;
+
+ nCurrentHeight = o3tl::saturating_add(nCurrentHeight, maRows[nRow].mnSize);
+ }
+ }
+
+ // if we have optimal sized rows, distribute what is given (left)
+ if( !bFit && !aOptimalRows.empty() && (nCurrentHeight < rArea.getHeight()) )
+ {
+ sal_Int32 nLeft = rArea.getHeight() - nCurrentHeight;
+ sal_Int32 nDistribute = nLeft / aOptimalRows.size();
+
+ auto iter( aOptimalRows.begin() );
+ while( iter != aOptimalRows.end() )
+ {
+ sal_Int32 nOptRow = *iter++;
+ if( iter == aOptimalRows.end() )
+ nDistribute = nLeft;
+
+ maRows[nOptRow].mnSize += nDistribute;
+ nLeft -= nDistribute;
+
+ }
+
+ DBG_ASSERT( nLeft == 0, "svx::TableLayouter::LayoutTableHeight(), layouting failed!" );
+ }
+
+ // now check if merged cells fit
+ for( nRow = 1; nRow < nRowCount; ++nRow )
+ {
+ bool bChanges = false;
+ sal_Int32 nOldSize = maRows[nRow].mnSize;
+
+ for( const CellRef& xCell : aMergedCells[nRow] )
+ {
+ sal_Int32 nMinHeight = xCell->getMinimumHeight();
+
+ for( sal_Int32 nMRow = nRow - xCell->getRowSpan() + 1; (nMRow > 0) && (nMRow < nRow); ++nMRow )
+ nMinHeight -= maRows[nMRow].mnSize;
+
+ if( nMinHeight > maRows[nRow].mnMinSize )
+ maRows[nRow].mnMinSize = nMinHeight;
+
+ if( nMinHeight > maRows[nRow].mnSize )
+ {
+ maRows[nRow].mnSize = nMinHeight;
+ bChanges = true;
+ }
+ }
+ if( bChanges )
+ nCurrentHeight = o3tl::saturating_add(nCurrentHeight, maRows[nRow].mnSize - nOldSize);
+ }
+
+ // now scale if wanted and needed
+ if( bFit && nCurrentHeight != rArea.getHeight() )
+ distribute(maRows, o3tl::saturating_sub<sal_Int32>(rArea.getHeight(), nCurrentHeight));
+
+ // last step, update left edges
+ sal_Int32 nNewHeight = 0;
+ for( nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ maRows[nRow].mnPos = nNewHeight;
+ nNewHeight = o3tl::saturating_add(nNewHeight, maRows[nRow].mnSize);
+
+ if( bFit )
+ {
+ Reference< XPropertySet > xRowSet( xRows->getByIndex(nRow), UNO_QUERY_THROW );
+ xRowSet->setPropertyValue( gsSize, Any( maRows[nRow].mnSize ) );
+ }
+ }
+
+ rArea.SetSize( Size( rArea.GetWidth(), nNewHeight ) );
+ updateCells( rArea );
+}
+
+
+/** try to fit the table into the given rectangle.
+ If the rectangle is too small, it will be grown to fit the table. */
+void TableLayouter::LayoutTable( tools::Rectangle& rRectangle, bool bFitWidth, bool bFitHeight )
+{
+ if( !mxTable.is() )
+ return;
+
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+ const sal_Int32 nColCount = mxTable->getColumnCount();
+
+ if( (nRowCount != getRowCount()) || (nColCount != getColumnCount()) )
+ {
+ if( static_cast< sal_Int32 >( maRows.size() ) != nRowCount )
+ maRows.resize( nRowCount );
+
+ for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
+ maRows[nRow].clear();
+
+ if( static_cast< sal_Int32 >( maColumns.size() ) != nColCount )
+ maColumns.resize( nColCount );
+
+ for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ )
+ maColumns[nCol].clear();
+ }
+
+ LayoutTableWidth( rRectangle, bFitWidth );
+ LayoutTableHeight( rRectangle, bFitHeight );
+ UpdateBorderLayout();
+}
+
+
+void TableLayouter::updateCells( tools::Rectangle const & rRectangle )
+{
+ const sal_Int32 nColCount = getColumnCount();
+ const sal_Int32 nRowCount = getRowCount();
+
+ CellPos aPos;
+ for( aPos.mnRow = 0; aPos.mnRow < nRowCount; aPos.mnRow++ )
+ {
+ for( aPos.mnCol = 0; aPos.mnCol < nColCount; aPos.mnCol++ )
+ {
+ CellRef xCell( getCell( aPos ) );
+ if( xCell.is() )
+ {
+ basegfx::B2IRectangle aCellArea;
+ if( getCellArea( xCell, aPos, aCellArea ) )
+ {
+ tools::Rectangle aCellRect;
+ aCellRect.SetLeft( aCellArea.getMinX() );
+ aCellRect.SetRight( aCellArea.getMaxX() );
+ aCellRect.SetTop( aCellArea.getMinY() );
+ aCellRect.SetBottom( aCellArea.getMaxY() );
+ aCellRect.Move( rRectangle.Left(), rRectangle.Top() );
+ xCell->setCellRect( aCellRect );
+ }
+ }
+ }
+ }
+}
+
+
+CellRef TableLayouter::getCell( const CellPos& rPos ) const
+{
+ CellRef xCell;
+ if( mxTable.is() ) try
+ {
+ xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+ return xCell;
+}
+
+
+bool TableLayouter::HasPriority( const SvxBorderLine* pThis, const SvxBorderLine* pOther )
+{
+ if (!pThis || ((pThis == &gEmptyBorder) && (pOther != nullptr)))
+ return false;
+ if (!pOther || (pOther == &gEmptyBorder))
+ return true;
+
+ sal_uInt16 nThisSize = pThis->GetScaledWidth();
+ sal_uInt16 nOtherSize = pOther->GetScaledWidth();
+
+ if (nThisSize > nOtherSize)
+ return true;
+
+ else if (nThisSize < nOtherSize)
+ {
+ return false;
+ }
+ else
+ {
+ if ( pOther->GetInWidth() && !pThis->GetInWidth() )
+ {
+ return true;
+ }
+ else if ( pThis->GetInWidth() && !pOther->GetInWidth() )
+ {
+ return false;
+ }
+ else
+ {
+ return true; //! ???
+ }
+ }
+}
+
+void TableLayouter::SetBorder( sal_Int32 nCol, sal_Int32 nRow, bool bHorizontal, const SvxBorderLine* pLine )
+{
+ if (!pLine)
+ pLine = &gEmptyBorder;
+
+ BorderLineMap& rMap = bHorizontal ? maHorizontalBorders : maVerticalBorders;
+
+ if( (nCol >= 0) && (nCol < sal::static_int_cast<sal_Int32>(rMap.size())) &&
+ (nRow >= 0) && (nRow < sal::static_int_cast<sal_Int32>(rMap[nCol].size())) )
+ {
+ SvxBorderLine *pOld = rMap[nCol][nRow];
+
+ if (HasPriority(pLine, pOld))
+ {
+ if (pOld && pOld != &gEmptyBorder)
+ delete pOld;
+
+ SvxBorderLine* pNew = (pLine != &gEmptyBorder) ? new SvxBorderLine(*pLine) : &gEmptyBorder;
+
+ rMap[nCol][nRow] = pNew;
+ }
+ }
+ else
+ {
+ OSL_FAIL( "sdr::table::TableLayouter::SetBorder(), invalid border!" );
+ }
+}
+
+void TableLayouter::ClearBorderLayout()
+{
+ ClearBorderLayout(maHorizontalBorders);
+ ClearBorderLayout(maVerticalBorders);
+}
+
+void TableLayouter::ClearBorderLayout(BorderLineMap& rMap)
+{
+ const sal_Int32 nColCount = rMap.size();
+
+ for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ )
+ {
+ const sal_Int32 nRowCount = rMap[nCol].size();
+ for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
+ {
+ SvxBorderLine* pLine = rMap[nCol][nRow];
+ if( pLine )
+ {
+ if( pLine != &gEmptyBorder )
+ delete pLine;
+
+ rMap[nCol][nRow] = nullptr;
+ }
+ }
+ }
+}
+
+void TableLayouter::ResizeBorderLayout()
+{
+ ClearBorderLayout();
+ ResizeBorderLayout(maHorizontalBorders);
+ ResizeBorderLayout(maVerticalBorders);
+}
+
+
+void TableLayouter::ResizeBorderLayout( BorderLineMap& rMap )
+{
+ const sal_Int32 nColCount = getColumnCount() + 1;
+ const sal_Int32 nRowCount = getRowCount() + 1;
+
+ if( sal::static_int_cast<sal_Int32>(rMap.size()) != nColCount )
+ rMap.resize( nColCount );
+
+ for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ )
+ {
+ if( sal::static_int_cast<sal_Int32>(rMap[nCol].size()) != nRowCount )
+ rMap[nCol].resize( nRowCount );
+ }
+}
+
+
+void TableLayouter::UpdateBorderLayout()
+{
+ // make sure old border layout is cleared and border maps have correct size
+ ResizeBorderLayout();
+
+ const sal_Int32 nColCount = getColumnCount();
+ const sal_Int32 nRowCount = getRowCount();
+
+ CellPos aPos;
+ for( aPos.mnRow = 0; aPos.mnRow < nRowCount; aPos.mnRow++ )
+ {
+ for( aPos.mnCol = 0; aPos.mnCol < nColCount; aPos.mnCol++ )
+ {
+ CellRef xCell( getCell( aPos ) );
+ if( !xCell.is() )
+ continue;
+
+ const SvxBoxItem* pThisAttr = xCell->GetItemSet().GetItem<SvxBoxItem>( SDRATTR_TABLE_BORDER );
+ OSL_ENSURE(pThisAttr,"sdr::table::TableLayouter::UpdateBorderLayout(), no border attribute?");
+
+ if( !pThisAttr )
+ continue;
+
+ const sal_Int32 nLastRow = xCell->getRowSpan() + aPos.mnRow;
+ const sal_Int32 nLastCol = xCell->getColumnSpan() + aPos.mnCol;
+
+ for( sal_Int32 nRow = aPos.mnRow; nRow < nLastRow; nRow++ )
+ {
+ SetBorder( aPos.mnCol, nRow, false, pThisAttr->GetLeft() );
+ SetBorder( nLastCol, nRow, false, pThisAttr->GetRight() );
+ }
+
+ for( sal_Int32 nCol = aPos.mnCol; nCol < nLastCol; nCol++ )
+ {
+ SetBorder( nCol, aPos.mnRow, true, pThisAttr->GetTop() );
+ SetBorder( nCol, nLastRow, true, pThisAttr->GetBottom() );
+ }
+ }
+ }
+}
+
+
+void TableLayouter::DistributeColumns( ::tools::Rectangle& rArea,
+ sal_Int32 nFirstCol,
+ sal_Int32 nLastCol,
+ const bool bOptimize,
+ const bool bMinimize )
+{
+ if( !mxTable.is() )
+ return;
+
+ try
+ {
+ const sal_Int32 nColCount = getColumnCount();
+ Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_SET_THROW );
+ const Size aSize(0xffffff, 0xffffff);
+
+ //special case - optimize a single column
+ if ( (bOptimize || bMinimize) && nFirstCol == nLastCol )
+ {
+ const sal_Int32 nWish = calcPreferredColumnWidth(nFirstCol, aSize);
+ if ( nWish < getColumnWidth(nFirstCol) )
+ {
+ Reference< XPropertySet > xColSet( xCols->getByIndex(nFirstCol), UNO_QUERY_THROW );
+ xColSet->setPropertyValue( gsSize, Any( nWish ) );
+
+ //FitWidth automatically distributes the new excess space
+ LayoutTable( rArea, /*bFitWidth=*/!bMinimize, /*bFitHeight=*/false );
+ }
+ }
+
+ if( (nFirstCol < 0) || (nFirstCol>= nLastCol) || (nLastCol >= nColCount) )
+ return;
+
+ sal_Int32 nAllWidth = 0;
+ float fAllWish = 0;
+ sal_Int32 nUnused = 0;
+ std::vector<sal_Int32> aWish(nColCount);
+
+ for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
+ nAllWidth += getColumnWidth(nCol);
+
+ const sal_Int32 nEqualWidth = nAllWidth / (nLastCol-nFirstCol+1);
+
+ //pass 1 - collect unneeded space (from an equal width perspective)
+ if ( bMinimize || bOptimize )
+ {
+ for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
+ {
+ const sal_Int32 nIndex = nCol - nFirstCol;
+ aWish[nIndex] = calcPreferredColumnWidth(nCol, aSize);
+ fAllWish += aWish[nIndex];
+ if ( aWish[nIndex] < nEqualWidth )
+ nUnused += nEqualWidth - aWish[nIndex];
+ }
+ }
+ const sal_Int32 nDistributeExcess = nAllWidth - fAllWish;
+
+ sal_Int32 nWidth = nEqualWidth;
+ for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
+ {
+ if ( !bMinimize && nCol == nLastCol )
+ nWidth = nAllWidth; // last column gets rounding/logic errors
+ else if ( (bMinimize || bOptimize) && fAllWish )
+ {
+ //pass 2 - first come, first served when requesting from the
+ // unneeded pool, or proportionally allocate excess.
+ const sal_Int32 nIndex = nCol - nFirstCol;
+ if ( aWish[nIndex] > nEqualWidth + nUnused )
+ {
+ nWidth = nEqualWidth + nUnused;
+ nUnused = 0;
+ }
+ else
+ {
+ nWidth = aWish[nIndex];
+ if ( aWish[nIndex] > nEqualWidth )
+ nUnused -= aWish[nIndex] - nEqualWidth;
+
+ if ( !bMinimize && nDistributeExcess > 0 )
+ nWidth += nWidth / fAllWish * nDistributeExcess;
+ }
+ }
+
+ Reference< XPropertySet > xColSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW );
+ xColSet->setPropertyValue( gsSize, Any( nWidth ) );
+
+ nAllWidth -= nWidth;
+ }
+
+ LayoutTable( rArea, !bMinimize, false );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+}
+
+
+void TableLayouter::DistributeRows( ::tools::Rectangle& rArea,
+ sal_Int32 nFirstRow,
+ sal_Int32 nLastRow,
+ const bool bOptimize,
+ const bool bMinimize )
+{
+ if( !mxTable.is() )
+ return;
+
+ try
+ {
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+ Reference< XTableRows > xRows( mxTable->getRows(), UNO_SET_THROW );
+ sal_Int32 nMinHeight = 0;
+
+ //special case - minimize a single row
+ if ( bMinimize && nFirstRow == nLastRow )
+ {
+ const sal_Int32 nWish = std::max( maRows[nFirstRow].mnMinSize, nMinHeight );
+ if ( nWish < getRowHeight(nFirstRow) )
+ {
+ Reference< XPropertySet > xRowSet( xRows->getByIndex( nFirstRow ), UNO_QUERY_THROW );
+ xRowSet->setPropertyValue( gsSize, Any( nWish ) );
+
+ LayoutTable( rArea, /*bFitWidth=*/false, /*bFitHeight=*/!bMinimize );
+ }
+ }
+
+ if( (nFirstRow < 0) || (nFirstRow>= nLastRow) || (nLastRow >= nRowCount) )
+ return;
+
+ sal_Int32 nAllHeight = 0;
+ sal_Int32 nMaxHeight = 0;
+
+ for( sal_Int32 nRow = nFirstRow; nRow <= nLastRow; ++nRow )
+ {
+ nMinHeight = std::max( maRows[nRow].mnMinSize, nMinHeight );
+ nMaxHeight = std::max( maRows[nRow].mnSize, nMaxHeight );
+ nAllHeight += maRows[nRow].mnSize;
+ }
+
+ const sal_Int32 nRows = nLastRow-nFirstRow+1;
+ sal_Int32 nHeight = nAllHeight / nRows;
+
+ if ( !bMinimize && nHeight < nMaxHeight )
+ {
+ if ( !bOptimize )
+ {
+ sal_Int32 nNeededHeight = nRows * nMaxHeight;
+ rArea.AdjustBottom(nNeededHeight - nAllHeight );
+ nHeight = nMaxHeight;
+ nAllHeight = nRows * nMaxHeight;
+ }
+ else if ( nHeight < nMinHeight )
+ {
+ sal_Int32 nNeededHeight = nRows * nMinHeight;
+ rArea.AdjustBottom(nNeededHeight - nAllHeight );
+ nHeight = nMinHeight;
+ nAllHeight = nRows * nMinHeight;
+ }
+ }
+
+ for( sal_Int32 nRow = nFirstRow; nRow <= nLastRow; ++nRow )
+ {
+ if ( bMinimize )
+ nHeight = maRows[nRow].mnMinSize;
+ else if ( nRow == nLastRow )
+ nHeight = nAllHeight; // last row get round errors
+
+ Reference< XPropertySet > xRowSet( xRows->getByIndex( nRow ), UNO_QUERY_THROW );
+ xRowSet->setPropertyValue( gsSize, Any( nHeight ) );
+
+ nAllHeight -= nHeight;
+ }
+
+ LayoutTable( rArea, false, !bMinimize );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+}
+
+void TableLayouter::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("TableLayouter"));
+
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("columns"));
+ for (const auto& rColumn : maColumns)
+ rColumn.dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("rows"));
+ for (const auto& rRow : maRows)
+ rRow.dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+void TableLayouter::Layout::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("TableLayouter_Layout"));
+
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("pos"), BAD_CAST(OString::number(mnPos).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("size"), BAD_CAST(OString::number(mnSize).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("minSize"), BAD_CAST(OString::number(mnMinSize).getStr()));
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablelayouter.hxx b/svx/source/table/tablelayouter.hxx
new file mode 100644
index 000000000..2ff69598e
--- /dev/null
+++ b/svx/source/table/tablelayouter.hxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_TABLELAYOUTER_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_TABLELAYOUTER_HXX
+
+#include <sal/types.h>
+#include <basegfx/range/b2irectangle.hxx>
+#include <basegfx/tuple/b2ituple.hxx>
+#include <o3tl/safeint.hxx>
+#include <vector>
+
+#include <svx/svdotable.hxx>
+#include <celltypes.hxx>
+
+namespace tools { class Rectangle; }
+
+
+namespace editeng {
+ class SvxBorderLine;
+}
+
+namespace sdr::table {
+
+/** returns true if the cell(nMergedCol,nMergedRow) is merged with other cells.
+ the returned cell( rOriginCol, rOriginRow ) is the origin( top left cell ) of the merge.
+*/
+bool findMergeOrigin( const TableModelRef& xTable, sal_Int32 nMergedCol, sal_Int32 nMergedRow, sal_Int32& rOriginCol, sal_Int32& rOriginRow );
+
+typedef std::vector< editeng::SvxBorderLine* > BorderLineVector;
+typedef std::vector< BorderLineVector > BorderLineMap;
+
+
+// TableModel
+
+struct EdgeInfo final
+{
+ sal_Int32 nIndex;
+ sal_Int32 nPosition;
+ sal_Int32 nMin;
+ sal_Int32 nMax;
+
+ EdgeInfo(sal_Int32 nInIndex, sal_Int32 nInPosition, sal_Int32 nInMin, sal_Int32 nInMax)
+ : nIndex(nInIndex)
+ , nPosition(nInPosition)
+ , nMin(nInMin)
+ , nMax(nInMax)
+ {}
+};
+
+class TableLayouter final
+{
+public:
+ explicit TableLayouter( const TableModelRef& xTableModel );
+ ~TableLayouter();
+
+ /** try to fit the table into the given rectangle.
+ If the rectangle is too small, it will be grown to fit the table.
+
+ if bFitWidth or bFitHeight is set, the layouter tries to scale
+ the rows and/or columns to the given area. The result my be bigger
+ to fulfill constrains.
+
+ if bFitWidth or bFitHeight is set, the model is changed.
+ */
+ void LayoutTable( ::tools::Rectangle& rRectangle, bool bFitWidth, bool bFitHeight );
+
+ void UpdateBorderLayout();
+
+ bool getCellArea( const CellRef& xCell, const CellPos& rPos, basegfx::B2IRectangle& rArea ) const;
+
+ ::sal_Int32 getRowCount() const { return static_cast< ::sal_Int32 >( maRows.size() ); }
+ ::sal_Int32 getColumnCount() const { return static_cast< ::sal_Int32 >( maColumns.size() ); }
+ sal_Int32 getRowHeight( sal_Int32 nRow ) const;
+
+ sal_Int32 getColumnWidth( sal_Int32 nColumn ) const;
+ sal_Int32 calcPreferredColumnWidth( sal_Int32 nColumn, Size aSize ) const;
+
+ sal_Int32 getMinimumColumnWidth( sal_Int32 nColumn );
+
+ /** checks if the given edge is visible.
+ Edges between merged cells are not visible.
+ */
+ bool isEdgeVisible( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal ) const;
+
+ /** returns the requested borderline in rpBorderLine or a null pointer if there is no border at this edge */
+ editeng::SvxBorderLine* getBorderLine( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal )const;
+
+ void updateCells( ::tools::Rectangle const & rRectangle );
+
+ std::vector<EdgeInfo> getHorizontalEdges();
+ sal_Int32 getHorizontalEdge( int nEdgeY, sal_Int32* pnMin, sal_Int32* pnMax );
+
+ std::vector<EdgeInfo> getVerticalEdges();
+ sal_Int32 getVerticalEdge( int nEdgeX , sal_Int32* pnMin, sal_Int32* pnMax);
+
+
+ void DistributeColumns( ::tools::Rectangle& rArea,
+ sal_Int32 nFirstCol,
+ sal_Int32 nLastCol,
+ const bool bOptimize,
+ const bool bMinimize );
+ void DistributeRows( ::tools::Rectangle& rArea,
+ sal_Int32 nFirstRow,
+ sal_Int32 nLastRow,
+ const bool bOptimize,
+ const bool bMinimize );
+ void dumpAsXml(xmlTextWriterPtr pWriter) const;
+
+ void LayoutTableWidth(::tools::Rectangle& rArea, bool bFit);
+ void LayoutTableHeight(::tools::Rectangle& rArea, bool bFit);
+
+private:
+ CellRef getCell( const CellPos& rPos ) const;
+ basegfx::B2ITuple getCellSize( const CellRef& xCell, const CellPos& rPos ) const;
+
+ bool isValidColumn( sal_Int32 nColumn ) const { return (nColumn >= 0) && (o3tl::make_unsigned(nColumn) < maColumns.size()); }
+ bool isValidRow( sal_Int32 nRow ) const { return (nRow >= 0) && (o3tl::make_unsigned(nRow) < maRows.size()); }
+ bool isValid( const CellPos& rPos ) const { return isValidColumn( rPos.mnCol ) && isValidRow( rPos.mnRow ); }
+
+ void ClearBorderLayout();
+ static void ClearBorderLayout(BorderLineMap& rMap);
+ void ResizeBorderLayout();
+ void ResizeBorderLayout( BorderLineMap& rMap );
+
+ void SetBorder( sal_Int32 nCol, sal_Int32 nRow, bool bHorizontal, const editeng::SvxBorderLine* pLine );
+
+ static bool HasPriority( const editeng::SvxBorderLine* pThis, const editeng::SvxBorderLine* pOther );
+
+ struct Layout
+ {
+ sal_Int32 mnPos;
+ sal_Int32 mnSize;
+ sal_Int32 mnMinSize;
+
+ Layout() : mnPos( 0 ), mnSize( 0 ), mnMinSize( 0 ) {}
+ void clear() { mnPos = 0; mnSize = 0; mnMinSize = 0; }
+ void dumpAsXml(xmlTextWriterPtr pWriter) const;
+ };
+ typedef std::vector< Layout > LayoutVector;
+
+ static sal_Int32 distribute( LayoutVector& rLayouts, sal_Int32 nDistribute );
+
+ TableModelRef mxTable;
+ LayoutVector maRows;
+ LayoutVector maColumns;
+
+ BorderLineMap maHorizontalBorders;
+ BorderLineMap maVerticalBorders;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablemodel.cxx b/svx/source/table/tablemodel.cxx
new file mode 100644
index 000000000..9104a0a2d
--- /dev/null
+++ b/svx/source/table/tablemodel.cxx
@@ -0,0 +1,1127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/table/XMergeableCell.hpp>
+
+#include <algorithm>
+
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+#include <libxml/xmlwriter.h>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <cell.hxx>
+#include "cellcursor.hxx"
+#include <tablemodel.hxx>
+#include "tablerow.hxx"
+#include "tablerows.hxx"
+#include "tablecolumn.hxx"
+#include "tablecolumns.hxx"
+#include "tableundo.hxx"
+#include <o3tl/safeint.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+
+
+namespace sdr::table {
+
+
+// removes the given range from a vector
+template< class Vec, class Iter > static void remove_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
+{
+ const sal_Int32 nSize = static_cast<sal_Int32>(rVector.size());
+ if( nCount && (nIndex >= 0) && (nIndex < nSize) )
+ {
+ if( (nIndex + nCount) >= nSize )
+ {
+ // remove at end
+ rVector.resize( nIndex );
+ }
+ else
+ {
+ rVector.erase(rVector.begin() + nIndex, rVector.begin() + nIndex + nCount);
+ }
+ }
+}
+
+
+/** inserts a range into a vector */
+template< class Vec, class Iter, class Entry > static sal_Int32 insert_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
+{
+ if( nCount )
+ {
+ if( nIndex >= static_cast< sal_Int32 >( rVector.size() ) )
+ {
+ // append at end
+ nIndex = static_cast< sal_Int32 >( rVector.size() ); // cap to end
+ rVector.resize( nIndex + nCount );
+ }
+ else
+ {
+ // insert
+ Iter aIter( rVector.begin() );
+ std::advance( aIter, nIndex );
+
+ Entry aEmpty;
+ rVector.insert( aIter, nCount, aEmpty );
+ }
+ }
+ return nIndex;
+}
+
+
+TableModel::TableModel( SdrTableObj* pTableObj )
+: TableModelBase( m_aMutex )
+, mpTableObj( pTableObj )
+, mbModified( false )
+, mbNotifyPending( false )
+, mnNotifyLock( 0 )
+{
+}
+
+TableModel::TableModel( SdrTableObj* pTableObj, const TableModelRef& xSourceTable )
+: TableModelBase( m_aMutex )
+, mpTableObj( pTableObj )
+, mbModified( false )
+, mbNotifyPending( false )
+, mnNotifyLock( 0 )
+{
+ if( !xSourceTable.is() )
+ return;
+
+ const sal_Int32 nColCount = xSourceTable->getColumnCountImpl();
+ const sal_Int32 nRowCount = xSourceTable->getRowCountImpl();
+
+ init( nColCount, nRowCount );
+
+ sal_Int32 nRows = nRowCount;
+ while( nRows-- )
+ (*maRows[nRows]) = *xSourceTable->maRows[nRows];
+
+ sal_Int32 nColumns = nColCount;
+ while( nColumns-- )
+ (*maColumns[nColumns]) = *xSourceTable->maColumns[nColumns];
+
+ // copy cells
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ CellRef xTargetCell( getCell( nCol, nRow ) );
+ if( xTargetCell.is() )
+ xTargetCell->cloneFrom( xSourceTable->getCell( nCol, nRow ) );
+ }
+ }
+}
+
+
+TableModel::~TableModel()
+{
+}
+
+
+void TableModel::init( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ if( nRows < 20 )
+ maRows.reserve( 20 );
+
+ if( nColumns < 20 )
+ maColumns.reserve( 20 );
+
+ if( nRows && nColumns )
+ {
+ maColumns.resize( nColumns );
+ maRows.resize( nRows );
+
+ while( nRows-- )
+ maRows[nRows].set( new TableRow( this, nRows, nColumns ) );
+
+ while( nColumns-- )
+ maColumns[nColumns].set( new TableColumn( this, nColumns ) );
+ }
+}
+
+
+// ICellRange
+
+
+sal_Int32 TableModel::getLeft()
+{
+ return 0;
+}
+
+
+sal_Int32 TableModel::getTop()
+{
+ return 0;
+}
+
+
+sal_Int32 TableModel::getRight()
+{
+ return getColumnCount();
+}
+
+
+sal_Int32 TableModel::getBottom()
+{
+ return getRowCount();
+}
+
+
+Reference< XTable > TableModel::getTable()
+{
+ return this;
+}
+
+
+void TableModel::UndoInsertRows( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ TableModelNotifyGuard aGuard( this );
+
+ // remove the rows
+ remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
+ updateRows();
+ setModified(true);
+}
+
+
+void TableModel::UndoRemoveRows( sal_Int32 nIndex, RowVector& aRows )
+{
+ TableModelNotifyGuard aGuard( this );
+
+ const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aRows.size() );
+
+ nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
+
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ maRows[nIndex+nOffset] = aRows[nOffset];
+
+ updateRows();
+ setModified(true);
+}
+
+
+void TableModel::UndoInsertColumns( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ TableModelNotifyGuard aGuard( this );
+
+ // now remove the columns
+ remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
+ sal_Int32 nRows = getRowCountImpl();
+ while( nRows-- )
+ maRows[nRows]->removeColumns( nIndex, nCount );
+
+ updateColumns();
+ setModified(true);
+}
+
+
+void TableModel::UndoRemoveColumns( sal_Int32 nIndex, ColumnVector& aCols, CellVector& aCells )
+{
+ TableModelNotifyGuard aGuard( this );
+
+ const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aCols.size() );
+
+ // assert if there are not enough cells saved
+ DBG_ASSERT( (aCols.size() * maRows.size()) == aCells.size(), "sdr::table::TableModel::UndoRemoveColumns(), invalid undo data!" );
+
+ nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ maColumns[nIndex+nOffset] = aCols[nOffset];
+
+ CellVector::iterator aIter( aCells.begin() );
+
+ sal_Int32 nRows = getRowCountImpl();
+ for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
+ {
+ CellVector::iterator aIter2 = aIter + nRow * nCount;
+ OSL_ENSURE(aIter2 < aCells.end(), "invalid iterator!");
+ maRows[nRow]->insertColumns( nIndex, nCount, &aIter2 );
+ }
+
+ updateColumns();
+ setModified(true);
+}
+
+
+// XTable
+
+
+Reference< XCellCursor > SAL_CALL TableModel::createCursor()
+{
+ ::SolarMutexGuard aGuard;
+ return createCursorByRange( Reference< XCellRange >( this ) );
+}
+
+
+Reference< XCellCursor > SAL_CALL TableModel::createCursorByRange( const Reference< XCellRange >& rRange )
+{
+ ::SolarMutexGuard aGuard;
+
+ ICellRange* pRange = dynamic_cast< ICellRange* >( rRange.get() );
+ if( (pRange == nullptr) || (pRange->getTable().get() != this) )
+ throw IllegalArgumentException();
+
+ TableModelRef xModel( this );
+ return new CellCursor( xModel, pRange->getLeft(), pRange->getTop(), pRange->getRight(), pRange->getBottom() );
+}
+
+
+sal_Int32 SAL_CALL TableModel::getRowCount()
+{
+ ::SolarMutexGuard aGuard;
+ return getRowCountImpl();
+}
+
+sal_Int32 SAL_CALL TableModel::getColumnCount()
+{
+ ::SolarMutexGuard aGuard;
+ return getColumnCountImpl();
+}
+
+std::vector<sal_Int32> TableModel::getColumnWidths()
+{
+ std::vector<sal_Int32> aRet;
+ for (const TableColumnRef& xColumn : maColumns)
+ aRet.push_back(xColumn->getWidth());
+ return aRet;
+}
+
+// XComponent
+
+
+void TableModel::dispose()
+{
+ ::SolarMutexGuard aGuard;
+ TableModelBase::dispose();
+}
+
+
+// XModifiable
+
+
+sal_Bool SAL_CALL TableModel::isModified( )
+{
+ ::SolarMutexGuard aGuard;
+ return mbModified;
+}
+
+
+void SAL_CALL TableModel::setModified( sal_Bool bModified )
+{
+ {
+ ::SolarMutexGuard aGuard;
+ mbModified = bModified;
+ }
+ if( bModified )
+ notifyModification();
+}
+
+
+// XModifyBroadcaster
+
+
+void SAL_CALL TableModel::addModifyListener( const Reference< XModifyListener >& xListener )
+{
+ rBHelper.addListener( cppu::UnoType<XModifyListener>::get() , xListener );
+}
+
+
+void SAL_CALL TableModel::removeModifyListener( const Reference< XModifyListener >& xListener )
+{
+ rBHelper.removeListener( cppu::UnoType<XModifyListener>::get() , xListener );
+}
+
+
+// XColumnRowRange
+
+
+Reference< XTableColumns > SAL_CALL TableModel::getColumns()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( !mxTableColumns.is() )
+ mxTableColumns.set( new TableColumns( this ) );
+ return mxTableColumns;
+}
+
+
+Reference< XTableRows > SAL_CALL TableModel::getRows()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( !mxTableRows.is() )
+ mxTableRows.set( new TableRows( this ) );
+ return mxTableRows;
+}
+
+
+// XCellRange
+
+
+Reference< XCell > SAL_CALL TableModel::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow )
+{
+ ::SolarMutexGuard aGuard;
+
+ CellRef xCell( getCell( nColumn, nRow ) );
+ if( xCell.is() )
+ return xCell;
+
+ throw IndexOutOfBoundsException();
+}
+
+
+Reference< XCellRange > SAL_CALL TableModel::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( (nLeft >= 0) && (nTop >= 0) && (nRight >= nLeft) && (nBottom >= nTop) && (nRight < getColumnCountImpl()) && (nBottom < getRowCountImpl() ) )
+ {
+ TableModelRef xModel( this );
+ return new CellRange( xModel, nLeft, nTop, nRight, nBottom );
+ }
+
+ throw IndexOutOfBoundsException();
+}
+
+
+Reference< XCellRange > SAL_CALL TableModel::getCellRangeByName( const OUString& /*aRange*/ )
+{
+ return Reference< XCellRange >();
+}
+
+
+// XPropertySet
+
+
+Reference< XPropertySetInfo > SAL_CALL TableModel::getPropertySetInfo( )
+{
+ Reference< XPropertySetInfo > xInfo;
+ return xInfo;
+}
+
+
+void SAL_CALL TableModel::setPropertyValue( const OUString& /*aPropertyName*/, const Any& /*aValue*/ )
+{
+}
+
+
+Any SAL_CALL TableModel::getPropertyValue( const OUString& /*PropertyName*/ )
+{
+ return Any();
+}
+
+
+void SAL_CALL TableModel::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ )
+{
+}
+
+
+void SAL_CALL TableModel::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ )
+{
+}
+
+
+void SAL_CALL TableModel::addVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ )
+{
+}
+
+
+void SAL_CALL TableModel::removeVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ )
+{
+}
+
+
+// XFastPropertySet
+
+
+void SAL_CALL TableModel::setFastPropertyValue( ::sal_Int32 /*nHandle*/, const Any& /*aValue*/ )
+{
+}
+
+
+Any SAL_CALL TableModel::getFastPropertyValue( ::sal_Int32 /*nHandle*/ )
+{
+ Any aAny;
+ return aAny;
+}
+
+
+// internals
+
+
+sal_Int32 TableModel::getRowCountImpl() const
+{
+ return static_cast< sal_Int32 >( maRows.size() );
+}
+
+
+sal_Int32 TableModel::getColumnCountImpl() const
+{
+ return static_cast< sal_Int32 >( maColumns.size() );
+}
+
+
+void TableModel::disposing()
+{
+ if( !maRows.empty() )
+ {
+ for( auto& rpRow : maRows )
+ rpRow->dispose();
+ RowVector().swap(maRows);
+ }
+
+ if( !maColumns.empty() )
+ {
+ for( auto& rpCol : maColumns )
+ rpCol->dispose();
+ ColumnVector().swap(maColumns);
+ }
+
+ if( mxTableColumns.is() )
+ {
+ mxTableColumns->dispose();
+ mxTableColumns.clear();
+ }
+
+ if( mxTableRows.is() )
+ {
+ mxTableRows->dispose();
+ mxTableRows.clear();
+ }
+
+ mpTableObj = nullptr;
+}
+
+
+// XBroadcaster
+
+
+void TableModel::lockBroadcasts()
+{
+ ::SolarMutexGuard aGuard;
+ ++mnNotifyLock;
+}
+
+
+void TableModel::unlockBroadcasts()
+{
+ ::SolarMutexGuard aGuard;
+ --mnNotifyLock;
+ if( mnNotifyLock <= 0 )
+ {
+ mnNotifyLock = 0;
+ if( mbNotifyPending )
+ notifyModification();
+ }
+}
+
+
+void TableModel::notifyModification()
+{
+ ::osl::MutexGuard guard( m_aMutex );
+ if( (mnNotifyLock == 0) && mpTableObj )
+ {
+ mbNotifyPending = false;
+
+ ::cppu::OInterfaceContainerHelper * pModifyListeners = rBHelper.getContainer( cppu::UnoType<XModifyListener>::get() );
+ if( pModifyListeners )
+ {
+ EventObject aSource;
+ aSource.Source = static_cast< ::cppu::OWeakObject* >(this);
+ pModifyListeners->notifyEach( &XModifyListener::modified, aSource);
+ }
+ }
+ else
+ {
+ mbNotifyPending = true;
+ }
+}
+
+
+CellRef TableModel::getCell( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ if( ((nRow >= 0) && (nRow < getRowCountImpl())) && (nCol >= 0) && (nCol < getColumnCountImpl()) )
+ {
+ return maRows[nRow]->maCells[nCol];
+ }
+ else
+ {
+ CellRef xRet;
+ return xRet;
+ }
+}
+
+
+CellRef TableModel::createCell()
+{
+ CellRef xCell;
+ if( mpTableObj )
+ mpTableObj->createCell( xCell );
+ return xCell;
+}
+
+
+void TableModel::insertColumns( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ if( !(nCount && mpTableObj) )
+ return;
+
+ try
+ {
+ SdrModel& rModel(mpTableObj->getSdrModelFromSdrObject());
+ TableModelNotifyGuard aGuard( this );
+ nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
+
+ sal_Int32 nRows = getRowCountImpl();
+ while( nRows-- )
+ maRows[nRows]->insertColumns( nIndex, nCount, nullptr );
+
+ ColumnVector aNewColumns(nCount);
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ {
+ TableColumnRef xNewCol( new TableColumn( this, nIndex+nOffset ) );
+ maColumns[nIndex+nOffset] = xNewCol;
+ aNewColumns[nOffset] = xNewCol;
+ }
+
+ const bool bUndo(mpTableObj->IsInserted() && rModel.IsUndoEnabled());
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_TABLE_INSCOL) );
+ rModel.AddUndo( rModel.GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
+
+ TableModelRef xThis( this );
+
+ nRows = getRowCountImpl();
+ CellVector aNewCells( nCount * nRows );
+ CellVector::iterator aCellIter( aNewCells.begin() );
+
+ nRows = getRowCountImpl();
+ for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
+ {
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ (*aCellIter++) = getCell( nIndex + nOffset, nRow );
+ }
+
+ rModel.AddUndo( std::make_unique<InsertColUndo>( xThis, nIndex, aNewColumns, aNewCells ) );
+ }
+
+ const sal_Int32 nRowCount = getRowCountImpl();
+ // check if cells merge over new columns
+ for( sal_Int32 nCol = 0; nCol < nIndex; ++nCol )
+ {
+ for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ CellRef xCell( getCell( nCol, nRow ) );
+ sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
+ if( (nColSpan != 1) && ((nColSpan + nCol ) > nIndex) )
+ {
+ // cell merges over newly created columns, so add the new columns to the merged cell
+ const sal_Int32 nRowSpan = xCell->getRowSpan();
+ nColSpan += nCount;
+ merge( nCol, nRow, nColSpan, nRowSpan );
+ }
+ }
+ }
+
+ if( bUndo )
+ rModel.EndUndo();
+
+ rModel.SetChanged();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+ updateColumns();
+ setModified(true);
+}
+
+
+void TableModel::removeColumns( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ sal_Int32 nColCount = getColumnCountImpl();
+
+ if( !(mpTableObj && nCount && (nIndex >= 0) && (nIndex < nColCount)) )
+ return;
+
+ try
+ {
+ TableModelNotifyGuard aGuard( this );
+
+ // clip removed columns to columns actually available
+ if( (nIndex + nCount) > nColCount )
+ nCount = nColCount - nIndex;
+
+ sal_Int32 nRows = getRowCountImpl();
+ SdrModel& rModel(mpTableObj->getSdrModelFromSdrObject());
+ const bool bUndo(mpTableObj->IsInserted() && rModel.IsUndoEnabled());
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_UNDO_COL_DELETE) );
+ rModel.AddUndo( rModel.GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
+ }
+
+ // only rows before and inside the removed rows are considered
+ nColCount = nIndex + nCount + 1;
+
+ const sal_Int32 nRowCount = getRowCountImpl();
+
+ // first check merged cells before and inside the removed rows
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ CellRef xCell( getCell( nCol, nRow ) );
+ sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
+ if( nColSpan <= 1 )
+ continue;
+
+ if( nCol >= nIndex )
+ {
+ // current cell is inside the removed columns
+ if( (nCol + nColSpan) > ( nIndex + nCount ) )
+ {
+ // current cells merges with columns after the removed columns
+ const sal_Int32 nRemove = nCount - nCol + nIndex;
+
+ CellRef xTargetCell( getCell( nIndex + nCount, nRow ) );
+ if( xTargetCell.is() )
+ {
+ if( bUndo )
+ xTargetCell->AddUndo();
+ xTargetCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
+ xTargetCell->replaceContentAndFormatting( xCell );
+ }
+ }
+ }
+ else if( nColSpan > (nIndex - nCol) )
+ {
+ // current cells spans inside the removed columns, so adjust
+ const sal_Int32 nRemove = ::std::min( nCount, nCol + nColSpan - nIndex );
+ if( bUndo )
+ xCell->AddUndo();
+ xCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
+ }
+ }
+ }
+
+ // We must not add RemoveColUndo before we make cell spans correct, otherwise we
+ // get invalid cell span after undo.
+ if( bUndo )
+ {
+ TableModelRef xThis( this );
+ ColumnVector aRemovedCols( nCount );
+ sal_Int32 nOffset;
+ for( nOffset = 0; nOffset < nCount; ++nOffset )
+ {
+ aRemovedCols[nOffset] = maColumns[nIndex+nOffset];
+ }
+
+ CellVector aRemovedCells( nCount * nRows );
+ CellVector::iterator aCellIter( aRemovedCells.begin() );
+ for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
+ {
+ for( nOffset = 0; nOffset < nCount; ++nOffset )
+ (*aCellIter++) = getCell( nIndex + nOffset, nRow );
+ }
+
+ rModel.AddUndo( std::make_unique<RemoveColUndo>( xThis, nIndex, aRemovedCols, aRemovedCells ) );
+ }
+
+ // now remove the columns
+ remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
+ while( nRows-- )
+ maRows[nRows]->removeColumns( nIndex, nCount );
+
+ if( bUndo )
+ rModel.EndUndo();
+
+ rModel.SetChanged();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+
+ updateColumns();
+ setModified(true);
+}
+
+
+void TableModel::insertRows( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ if( !(nCount && mpTableObj) )
+ return;
+
+ SdrModel& rModel(mpTableObj->getSdrModelFromSdrObject());
+ const bool bUndo(mpTableObj->IsInserted() && rModel.IsUndoEnabled());
+
+ try
+ {
+ TableModelNotifyGuard aGuard( this );
+
+ nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
+
+ RowVector aNewRows(nCount);
+ const sal_Int32 nColCount = getColumnCountImpl();
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ {
+ TableRowRef xNewRow( new TableRow( this, nIndex+nOffset, nColCount ) );
+ maRows[nIndex+nOffset] = xNewRow;
+ aNewRows[nOffset] = xNewRow;
+ }
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_TABLE_INSROW) );
+ rModel.AddUndo( rModel.GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
+ TableModelRef xThis( this );
+ rModel.AddUndo( std::make_unique<InsertRowUndo>( xThis, nIndex, aNewRows ) );
+ }
+
+ // check if cells merge over new columns
+ for( sal_Int32 nRow = 0; nRow < nIndex; ++nRow )
+ {
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ CellRef xCell( getCell( nCol, nRow ) );
+ sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
+ if( (nRowSpan > 1) && ((nRowSpan + nRow) > nIndex) )
+ {
+ // cell merges over newly created columns, so add the new columns to the merged cell
+ const sal_Int32 nColSpan = xCell->getColumnSpan();
+ nRowSpan += nCount;
+ merge( nCol, nRow, nColSpan, nRowSpan );
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+ if( bUndo )
+ rModel.EndUndo();
+
+ rModel.SetChanged();
+
+ updateRows();
+ setModified(true);
+}
+
+
+void TableModel::removeRows( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ sal_Int32 nRowCount = getRowCountImpl();
+
+ if( !(mpTableObj && nCount && (nIndex >= 0) && (nIndex < nRowCount)) )
+ return;
+
+ SdrModel& rModel(mpTableObj->getSdrModelFromSdrObject());
+ const bool bUndo(mpTableObj->IsInserted() && rModel.IsUndoEnabled());
+
+ try
+ {
+ TableModelNotifyGuard aGuard( this );
+
+ // clip removed rows to rows actually available
+ if( (nIndex + nCount) > nRowCount )
+ nCount = nRowCount - nIndex;
+
+ if( bUndo )
+ {
+ rModel.BegUndo( SvxResId(STR_UNDO_ROW_DELETE) );
+ rModel.AddUndo( rModel.GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
+ }
+
+ // only rows before and inside the removed rows are considered
+ nRowCount = nIndex + nCount + 1;
+
+ const sal_Int32 nColCount = getColumnCountImpl();
+
+ // first check merged cells before and inside the removed rows
+ for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
+ {
+ CellRef xCell( getCell( nCol, nRow ) );
+ sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
+ if( nRowSpan <= 1 )
+ continue;
+
+ if( nRow >= nIndex )
+ {
+ // current cell is inside the removed rows
+ if( (nRow + nRowSpan) > (nIndex + nCount) )
+ {
+ // current cells merges with rows after the removed rows
+ const sal_Int32 nRemove = nCount - nRow + nIndex;
+
+ CellRef xTargetCell( getCell( nCol, nIndex + nCount ) );
+ if( xTargetCell.is() )
+ {
+ if( bUndo )
+ xTargetCell->AddUndo();
+ xTargetCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
+ xTargetCell->replaceContentAndFormatting( xCell );
+ }
+ }
+ }
+ else if( nRowSpan > (nIndex - nRow) )
+ {
+ // current cells spans inside the removed rows, so adjust
+ const sal_Int32 nRemove = ::std::min( nCount, nRow + nRowSpan - nIndex );
+ if( bUndo )
+ xCell->AddUndo();
+ xCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
+ }
+ }
+ }
+
+ if( bUndo )
+ {
+ TableModelRef xThis( this );
+
+ RowVector aRemovedRows( nCount );
+ for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
+ aRemovedRows[nOffset] = maRows[nIndex+nOffset];
+
+ // We must not RemoveRowUndo before we make cell spans correct, otherwise we
+ // get invalid cell span after undo.
+ rModel.AddUndo( std::make_unique<RemoveRowUndo>( xThis, nIndex, aRemovedRows ) );
+ }
+ // now remove the rows
+ remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
+
+ if( bUndo )
+ rModel.EndUndo();
+
+ rModel.SetChanged();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+
+ updateRows();
+ setModified(true);
+}
+
+
+TableRowRef const & TableModel::getRow( sal_Int32 nRow ) const
+{
+ if( (nRow >= 0) && (nRow < getRowCountImpl()) )
+ return maRows[nRow];
+
+ throw IndexOutOfBoundsException();
+}
+
+
+TableColumnRef const & TableModel::getColumn( sal_Int32 nColumn ) const
+{
+ if( (nColumn >= 0) && (nColumn < getColumnCountImpl()) )
+ return maColumns[nColumn];
+
+ throw IndexOutOfBoundsException();
+}
+
+
+/** deletes rows and columns that are completely merged. Must be called between BegUndo/EndUndo! */
+void TableModel::optimize()
+{
+ TableModelNotifyGuard aGuard( this );
+
+ bool bWasModified = false;
+
+ if( !maRows.empty() && !maColumns.empty() )
+ {
+ sal_Int32 nCol = getColumnCountImpl() - 1;
+ sal_Int32 nRows = getRowCountImpl();
+ while( nCol > 0 )
+ {
+ bool bEmpty = true;
+ for( sal_Int32 nRow = 0; (nRow < nRows) && bEmpty; nRow++ )
+ {
+ Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
+ if( xCell.is() && !xCell->isMerged() )
+ bEmpty = false;
+ }
+
+ if( bEmpty )
+ {
+ try
+ {
+ static const OUStringLiteral sWidth(u"Width");
+ sal_Int32 nWidth1 = 0, nWidth2 = 0;
+ Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maColumns[nCol].get() ), UNO_QUERY_THROW );
+ Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maColumns[nCol-1].get() ), UNO_QUERY_THROW );
+ xSet1->getPropertyValue( sWidth ) >>= nWidth1;
+ xSet2->getPropertyValue( sWidth ) >>= nWidth2;
+ nWidth1 = o3tl::saturating_add(nWidth1, nWidth2);
+ xSet2->setPropertyValue( sWidth, Any( nWidth1 ) );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+
+ removeColumns( nCol, 1 );
+ bWasModified = true;
+ }
+
+ nCol--;
+ }
+
+ sal_Int32 nRow = getRowCountImpl() - 1;
+ sal_Int32 nCols = getColumnCountImpl();
+ while( nRow > 0 )
+ {
+ bool bEmpty = true;
+ for( nCol = 0; (nCol < nCols) && bEmpty; nCol++ )
+ {
+ Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
+ if( xCell.is() && !xCell->isMerged() )
+ bEmpty = false;
+ }
+
+ if( bEmpty )
+ {
+ try
+ {
+ static const OUStringLiteral sHeight(u"Height");
+ sal_Int32 nHeight1 = 0, nHeight2 = 0;
+ Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maRows[nRow].get() ), UNO_QUERY_THROW );
+ Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maRows[nRow-1].get() ), UNO_QUERY_THROW );
+ xSet1->getPropertyValue( sHeight ) >>= nHeight1;
+ xSet2->getPropertyValue( sHeight ) >>= nHeight2;
+ nHeight1 = o3tl::saturating_add(nHeight1, nHeight2);
+ xSet2->setPropertyValue( sHeight, Any( nHeight1 ) );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+
+ removeRows( nRow, 1 );
+ bWasModified = true;
+ }
+
+ nRow--;
+ }
+ }
+ if( bWasModified )
+ setModified(true);
+}
+
+
+void TableModel::merge( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan )
+{
+ if(nullptr == mpTableObj)
+ return;
+
+ SdrModel& rModel(mpTableObj->getSdrModelFromSdrObject());
+ const bool bUndo(mpTableObj->IsInserted() && rModel.IsUndoEnabled());
+ const sal_Int32 nLastRow = nRow + nRowSpan;
+ const sal_Int32 nLastCol = nCol + nColSpan;
+
+ if( (nLastRow > getRowCount()) || (nLastCol > getColumnCount() ) )
+ {
+ OSL_FAIL("TableModel::merge(), merge beyond the table!");
+ }
+
+ // merge first cell
+ CellRef xOriginCell( dynamic_cast< Cell* >( getCellByPosition( nCol, nRow ).get() ) );
+ if(!xOriginCell.is())
+ return;
+
+ if( bUndo )
+ xOriginCell->AddUndo();
+ xOriginCell->merge( nColSpan, nRowSpan );
+
+ sal_Int32 nTempCol = nCol + 1;
+
+ // merge remaining cells
+ for( ; nRow < nLastRow; nRow++ )
+ {
+ for( ; nTempCol < nLastCol; nTempCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( getCellByPosition( nTempCol, nRow ).get() ) );
+ if( xCell.is() && !xCell->isMerged() )
+ {
+ if( bUndo )
+ xCell->AddUndo();
+ xCell->setMerged();
+ xOriginCell->mergeContent( xCell );
+ }
+ }
+ nTempCol = nCol;
+ }
+}
+
+void TableModel::updateRows()
+{
+ sal_Int32 nRow = 0;
+ for( auto& rpRow : maRows )
+ {
+ rpRow->mnRow = nRow++;
+ }
+}
+
+void TableModel::updateColumns()
+{
+ sal_Int32 nColumn = 0;
+ for( auto& rpCol : maColumns )
+ {
+ rpCol->mnColumn = nColumn++;
+ }
+}
+
+void TableModel::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("TableModel"));
+ for (sal_Int32 nRow = 0; nRow < getRowCountImpl(); ++nRow)
+ for (sal_Int32 nCol = 0; nCol < getColumnCountImpl(); ++nCol)
+ {
+ maRows[nRow]->maCells[nCol]->dumpAsXml(pWriter, nRow, nCol);
+ }
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablerow.cxx b/svx/source/table/tablerow.cxx
new file mode 100644
index 000000000..71b51a653
--- /dev/null
+++ b/svx/source/table/tablerow.cxx
@@ -0,0 +1,351 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <cell.hxx>
+#include "tablerow.hxx"
+#include "tableundo.hxx"
+#include <svx/svdmodel.hxx>
+#include <svx/svdotable.hxx>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::beans;
+
+
+namespace sdr::table {
+
+const sal_Int32 Property_Height = 0;
+const sal_Int32 Property_OptimalHeight = 1;
+const sal_Int32 Property_IsVisible = 2;
+const sal_Int32 Property_IsStartOfNewPage = 3;
+
+TableRow::TableRow( const TableModelRef& xTableModel, sal_Int32 nRow, sal_Int32 nColumns )
+: TableRowBase( getStaticPropertySetInfo() )
+, mxTableModel( xTableModel )
+, mnRow( nRow )
+, mnHeight( 0 )
+, mbOptimalHeight( true )
+, mbIsVisible( true )
+, mbIsStartOfNewPage( false )
+{
+ if( nColumns < 20 )
+ maCells.reserve( 20 );
+
+ if( nColumns )
+ {
+ maCells.resize( nColumns );
+ while( nColumns-- )
+ maCells[ nColumns ] = mxTableModel->createCell();
+ }
+}
+
+
+TableRow::~TableRow()
+{
+}
+
+
+void TableRow::dispose()
+{
+ mxTableModel.clear();
+ if( !maCells.empty() )
+ {
+ for( auto& rpCell : maCells )
+ rpCell->dispose();
+ CellVector().swap(maCells);
+ }
+}
+
+
+void TableRow::throwIfDisposed() const
+{
+ if( !mxTableModel.is() )
+ throw DisposedException();
+}
+
+
+TableRow& TableRow::operator=( const TableRow& r )
+{
+ mnHeight = r.mnHeight;
+ mbOptimalHeight = r.mbOptimalHeight;
+ mbIsVisible = r.mbIsVisible;
+ mbIsStartOfNewPage = r.mbIsStartOfNewPage;
+ maName = r.maName;
+ mnRow = r.mnRow;
+
+ return *this;
+}
+
+
+void TableRow::insertColumns( sal_Int32 nIndex, sal_Int32 nCount, CellVector::iterator const * pIter /* = 0 */ )
+{
+ throwIfDisposed();
+ if( !nCount )
+ return;
+
+ if( nIndex >= static_cast< sal_Int32 >( maCells.size() ) )
+ nIndex = static_cast< sal_Int32 >( maCells.size() );
+ if ( pIter )
+ maCells.insert( maCells.begin() + nIndex, *pIter, (*pIter) + nCount );
+ else
+ {
+ maCells.reserve( maCells.size() + nCount );
+ for ( sal_Int32 i = 0; i < nCount; i++ )
+ maCells.insert( maCells.begin() + nIndex + i, mxTableModel->createCell() );
+ }
+}
+
+
+void TableRow::removeColumns( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ throwIfDisposed();
+ if( (nCount < 0) || ( nIndex < 0))
+ return;
+
+ if( (nIndex + nCount) < static_cast< sal_Int32 >( maCells.size() ) )
+ {
+ CellVector::iterator aBegin( maCells.begin() );
+ std::advance(aBegin, nIndex);
+
+ if( nCount > 1 )
+ {
+ CellVector::iterator aEnd( aBegin );
+ while( nCount-- && (aEnd != maCells.end()) )
+ ++aEnd;
+ maCells.erase( aBegin, aEnd );
+ }
+ else
+ {
+ maCells.erase( aBegin );
+ }
+ }
+ else
+ {
+ maCells.resize( nIndex );
+ }
+}
+
+const TableModelRef& TableRow::getModel() const
+{
+ return mxTableModel;
+}
+
+// XCellRange
+
+
+Reference< XCell > SAL_CALL TableRow::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow )
+{
+ throwIfDisposed();
+ if( nRow != 0 )
+ throw IndexOutOfBoundsException();
+
+ return mxTableModel->getCellByPosition( nColumn, mnRow );
+}
+
+
+Reference< XCellRange > SAL_CALL TableRow::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ throwIfDisposed();
+ if( (nLeft >= 0 ) && (nTop == 0) && (nRight >= nLeft) && (nBottom == 0) )
+ {
+ return mxTableModel->getCellRangeByPosition( nLeft, mnRow, nRight, mnRow );
+ }
+ throw IndexOutOfBoundsException();
+}
+
+
+Reference< XCellRange > SAL_CALL TableRow::getCellRangeByName( const OUString& /*aRange*/ )
+{
+ throwIfDisposed();
+ return Reference< XCellRange >();
+}
+
+
+// XNamed
+
+
+OUString SAL_CALL TableRow::getName()
+{
+ return maName;
+}
+
+
+void SAL_CALL TableRow::setName( const OUString& aName )
+{
+ maName = aName;
+}
+
+
+// XFastPropertySet
+
+
+void SAL_CALL TableRow::setFastPropertyValue( sal_Int32 nHandle, const Any& aValue )
+{
+ if(!mxTableModel.is() || nullptr == mxTableModel->getSdrTableObj())
+ return;
+
+ SdrTableObj& rTableObj(*mxTableModel->getSdrTableObj());
+ SdrModel& rModel(rTableObj.getSdrModelFromSdrObject());
+ bool bOk(false);
+ bool bChange(false);
+ std::unique_ptr<TableRowUndo> pUndo;
+ const bool bUndo(rTableObj.IsInserted() && rModel.IsUndoEnabled());
+
+ if( bUndo )
+ {
+ TableRowRef xThis( this );
+ pUndo.reset(new TableRowUndo( xThis ));
+ }
+
+ switch( nHandle )
+ {
+ case Property_Height:
+ {
+ sal_Int32 nHeight = mnHeight;
+ bOk = aValue >>= nHeight;
+ if( bOk && (mnHeight != nHeight) )
+ {
+ mnHeight = nHeight;
+ mbOptimalHeight = mnHeight == 0;
+ bChange = true;
+ }
+ break;
+ }
+
+ case Property_OptimalHeight:
+ {
+ bool bOptimalHeight = mbOptimalHeight;
+ bOk = aValue >>= bOptimalHeight;
+ if( bOk && (mbOptimalHeight != bOptimalHeight) )
+ {
+ mbOptimalHeight = bOptimalHeight;
+ if( bOptimalHeight )
+ mnHeight = 0;
+ bChange = true;
+ }
+ break;
+ }
+ case Property_IsVisible:
+ {
+ bool bIsVisible = mbIsVisible;
+ bOk = aValue >>= bIsVisible;
+ if( bOk && (mbIsVisible != bIsVisible) )
+ {
+ mbIsVisible = bIsVisible;
+ bChange = true;
+ }
+ break;
+ }
+
+ case Property_IsStartOfNewPage:
+ {
+ bool bIsStartOfNewPage = mbIsStartOfNewPage;
+ bOk = aValue >>= bIsStartOfNewPage;
+ if( bOk && (mbIsStartOfNewPage != bIsStartOfNewPage) )
+ {
+ mbIsStartOfNewPage = bIsStartOfNewPage;
+ bChange = true;
+ }
+ break;
+ }
+ default:
+ throw UnknownPropertyException( OUString::number(nHandle), static_cast<cppu::OWeakObject*>(this));
+ }
+
+ if( !bOk )
+ {
+ throw IllegalArgumentException();
+ }
+
+ if( bChange )
+ {
+ if( pUndo )
+ {
+ rModel.AddUndo( std::move(pUndo) );
+ }
+ mxTableModel->setModified(true);
+ }
+}
+
+
+Any SAL_CALL TableRow::getFastPropertyValue( sal_Int32 nHandle )
+{
+ switch( nHandle )
+ {
+ case Property_Height: return Any( mnHeight );
+ case Property_OptimalHeight: return Any( mbOptimalHeight );
+ case Property_IsVisible: return Any( mbIsVisible );
+ case Property_IsStartOfNewPage: return Any( mbIsStartOfNewPage );
+ default: throw UnknownPropertyException( OUString::number(nHandle), static_cast<cppu::OWeakObject*>(this));
+ }
+}
+
+
+rtl::Reference< FastPropertySetInfo > TableRow::getStaticPropertySetInfo()
+{
+ static rtl::Reference<FastPropertySetInfo> xInfo = []() {
+ PropertyVector aProperties(6);
+
+ aProperties[0].Name = "Height";
+ aProperties[0].Handle = Property_Height;
+ aProperties[0].Type = ::cppu::UnoType<sal_Int32>::get();
+ aProperties[0].Attributes = 0;
+
+ aProperties[1].Name = "OptimalHeight";
+ aProperties[1].Handle = Property_OptimalHeight;
+ aProperties[1].Type = cppu::UnoType<bool>::get();
+ aProperties[1].Attributes = 0;
+
+ aProperties[2].Name = "IsVisible";
+ aProperties[2].Handle = Property_IsVisible;
+ aProperties[2].Type = cppu::UnoType<bool>::get();
+ aProperties[2].Attributes = 0;
+
+ aProperties[3].Name = "IsStartOfNewPage";
+ aProperties[3].Handle = Property_IsStartOfNewPage;
+ aProperties[3].Type = cppu::UnoType<bool>::get();
+ aProperties[3].Attributes = 0;
+
+ aProperties[4].Name = "Size";
+ aProperties[4].Handle = Property_Height;
+ aProperties[4].Type = ::cppu::UnoType<sal_Int32>::get();
+ aProperties[4].Attributes = 0;
+
+ aProperties[5].Name = "OptimalSize";
+ aProperties[5].Handle = Property_OptimalHeight;
+ aProperties[5].Type = cppu::UnoType<bool>::get();
+ aProperties[5].Attributes = 0;
+
+ return rtl::Reference<FastPropertySetInfo>(new FastPropertySetInfo(aProperties));
+ }();
+
+ return xInfo;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablerow.hxx b/svx/source/table/tablerow.hxx
new file mode 100644
index 000000000..9548e317f
--- /dev/null
+++ b/svx/source/table/tablerow.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_TABLEROW_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_TABLEROW_HXX
+
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include "propertyset.hxx"
+#include <celltypes.hxx>
+
+
+namespace sdr::table {
+
+typedef ::cppu::ImplInheritanceHelper< FastPropertySet, css::table::XCellRange, css::container::XNamed > TableRowBase;
+
+class TableRow : public TableRowBase
+{
+ friend class TableModel;
+ friend class TableRowUndo;
+public:
+ TableRow( const TableModelRef& xTableModel, sal_Int32 nRow, sal_Int32 nColumns );
+ virtual ~TableRow() override;
+
+ void dispose();
+ /// @throws css::uno::RuntimeException
+ void throwIfDisposed() const;
+
+ TableRow& operator=( const TableRow& );
+
+ void insertColumns( sal_Int32 nIndex, sal_Int32 nCount, CellVector::iterator const * pIter );
+ void removeColumns( sal_Int32 nIndex, sal_Int32 nCount );
+ /// Reference to the table model containing this row.
+ const TableModelRef& getModel() const;
+
+ // XCellRange
+ virtual css::uno::Reference< css::table::XCell > SAL_CALL getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) override;
+ virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) override;
+ virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByName( const OUString& aRange ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+
+ // XFastPropertySet
+ virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) override;
+
+private:
+ static rtl::Reference< FastPropertySetInfo > getStaticPropertySetInfo();
+
+ TableModelRef mxTableModel;
+ CellVector maCells;
+ sal_Int32 mnRow;
+ sal_Int32 mnHeight;
+ bool mbOptimalHeight;
+ bool mbIsVisible;
+ bool mbIsStartOfNewPage;
+ OUString maName;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablerows.cxx b/svx/source/table/tablerows.cxx
new file mode 100644
index 000000000..8698f72f4
--- /dev/null
+++ b/svx/source/table/tablerows.cxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include <tablemodel.hxx>
+#include "tablerow.hxx"
+#include "tablerows.hxx"
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::table;
+
+
+namespace sdr::table {
+
+TableRows::TableRows( const TableModelRef& xTableModel )
+: mxTableModel( xTableModel )
+{
+}
+
+
+TableRows::~TableRows()
+{
+ dispose();
+}
+
+
+void TableRows::dispose()
+{
+ mxTableModel.clear();
+}
+
+
+void TableRows::throwIfDisposed() const
+{
+ if( !mxTableModel.is() )
+ throw DisposedException();
+}
+
+
+// XTableRows
+
+
+void SAL_CALL TableRows::insertByIndex( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ throwIfDisposed();
+ mxTableModel->insertRows( nIndex, nCount );
+}
+
+
+void SAL_CALL TableRows::removeByIndex( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ throwIfDisposed();
+ mxTableModel->removeRows( nIndex, nCount );
+}
+
+
+// XIndexAccess
+
+
+sal_Int32 SAL_CALL TableRows::getCount()
+{
+ throwIfDisposed();
+ return mxTableModel->getRowCount();
+}
+
+
+Any SAL_CALL TableRows::getByIndex( sal_Int32 Index )
+{
+ throwIfDisposed();
+ return Any( Reference< XCellRange >( static_cast< XCellRange* >( mxTableModel->getRow( Index ).get() ) ) );
+}
+
+
+// XElementAccess
+
+
+Type SAL_CALL TableRows::getElementType()
+{
+ throwIfDisposed();
+ return cppu::UnoType<XCellRange>::get();
+}
+
+
+sal_Bool SAL_CALL TableRows::hasElements()
+{
+ throwIfDisposed();
+ return mxTableModel->getRowCount() != 0;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablerows.hxx b/svx/source/table/tablerows.hxx
new file mode 100644
index 000000000..3b25d3d9e
--- /dev/null
+++ b/svx/source/table/tablerows.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_TABLEROWS_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_TABLEROWS_HXX
+
+#include <com/sun/star/table/XTableRows.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+#include <celltypes.hxx>
+
+namespace sdr::table
+{
+class TableRows : public ::cppu::WeakAggImplHelper1<css::table::XTableRows>
+{
+public:
+ explicit TableRows(const TableModelRef& xTableModel);
+ virtual ~TableRows() override;
+
+ void dispose();
+ /// @throws css::uno::RuntimeException
+ void throwIfDisposed() const;
+
+ // XTableRows
+ virtual void SAL_CALL insertByIndex(sal_Int32 nIndex, sal_Int32 nCount) override;
+ virtual void SAL_CALL removeByIndex(sal_Int32 nIndex, sal_Int32 nCount) override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual css::uno::Any SAL_CALL getByIndex(sal_Int32 Index) override;
+
+ // Methods
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+private:
+ TableModelRef mxTableModel;
+};
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablertfexporter.cxx b/svx/source/table/tablertfexporter.cxx
new file mode 100644
index 000000000..c298d5d1a
--- /dev/null
+++ b/svx/source/table/tablertfexporter.cxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <vector>
+
+#include <com/sun/star/table/XTable.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <tools/stream.hxx>
+#include <svtools/rtfkeywd.hxx>
+#include <svtools/rtfout.hxx>
+
+#include <editeng/eeitem.hxx>
+#include <svx/sdtaitm.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+
+#include <cell.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/outlobj.hxx>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+
+namespace sdr::table {
+
+class SdrTableRtfExporter
+{
+public:
+ SdrTableRtfExporter( SvStream& rStrmP, SdrTableObj& rObj );
+ void Write();
+ void WriteRow( const Reference< XPropertySet >& xRowSet, sal_Int32 nRow, const std::vector< sal_Int32 >& aColumnStart );
+ void WriteCell( sal_Int32 nCol, sal_Int32 nRow );
+
+private:
+ SvStream& mrStrm;
+ SdrTableObj& mrObj;
+ Reference< XTable > mxTable;
+};
+
+void ExportAsRTF( SvStream& rStrm, SdrTableObj& rObj )
+{
+ SdrTableRtfExporter aEx( rStrm, rObj );
+ aEx.Write();
+}
+
+constexpr OUStringLiteral gsSize( u"Size" );
+
+SdrTableRtfExporter::SdrTableRtfExporter( SvStream& rStrm, SdrTableObj& rObj )
+: mrStrm( rStrm )
+, mrObj( rObj )
+, mxTable( rObj.getTable() )
+{
+}
+
+void SdrTableRtfExporter::Write()
+{
+ mrStrm.WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RTF );
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ANSI ).WriteCharPtr( SAL_NEWLINE_STRING );
+
+ Reference< XTableColumns > xColumns( mxTable->getColumns() );
+ const sal_Int32 nColCount = xColumns->getCount();
+
+ std::vector< sal_Int32 > aColumnStart;
+ aColumnStart.reserve( nColCount );
+
+ // determine right offset of cells
+ sal_Int32 nPos = 0;
+ for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) try
+ {
+ Reference< XPropertySet > xSet( xColumns->getByIndex(nCol), UNO_QUERY_THROW );
+ sal_Int32 nWidth = 0;
+ xSet->getPropertyValue( gsSize ) >>= nWidth;
+ nPos += o3tl::toTwips(nWidth, o3tl::Length::mm100);
+ aColumnStart.push_back( nPos );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+
+ // export rows
+ Reference< XTableRows > xRows( mxTable->getRows() );
+ const sal_Int32 nRowCount = xRows->getCount();
+
+ for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ ) try
+ {
+ Reference< XPropertySet > xRowSet( xRows->getByIndex(nRow), UNO_QUERY_THROW );
+ WriteRow( xRowSet, nRow, aColumnStart );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+
+ mrStrm.WriteChar( '}' ).WriteCharPtr( SAL_NEWLINE_STRING );
+}
+
+void SdrTableRtfExporter::WriteRow( const Reference< XPropertySet >& xRowSet, sal_Int32 nRow, const std::vector< sal_Int32 >& aColumnStart )
+{
+ sal_Int32 nRowHeight = 0;
+ xRowSet->getPropertyValue( gsSize ) >>= nRowHeight;
+
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH ).WriteCharPtr( "30" ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRLEFT ).WriteCharPtr( "-30" );
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRRH ).WriteOString( OString::number(nRowHeight) );
+
+ const sal_Int32 nColCount = mxTable->getColumnCount();
+ for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ )
+ {
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+
+ if( !xCell.is() )
+ continue;
+
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELLX ).WriteOString( OString::number(aColumnStart[nCol]) );
+ if ( (nCol & 0x0F) == 0x0F )
+ mrStrm.WriteCharPtr( SAL_NEWLINE_STRING ); // prevent long lines
+ }
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PLAIN ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL ).WriteCharPtr( SAL_NEWLINE_STRING );
+
+ sal_uInt64 nStrmPos = mrStrm.Tell();
+ for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ )
+ {
+ WriteCell( nCol, nRow );
+ if ( mrStrm.Tell() - nStrmPos > 255 )
+ {
+ mrStrm.WriteCharPtr( SAL_NEWLINE_STRING );
+ nStrmPos = mrStrm.Tell();
+ }
+ }
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW ).WriteCharPtr( SAL_NEWLINE_STRING );
+}
+
+
+void SdrTableRtfExporter::WriteCell( sal_Int32 nCol, sal_Int32 nRow )
+{
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+
+ if( !xCell.is() || xCell->isMerged() )
+ {
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL );
+ return ;
+ }
+
+ OUString aContent;
+
+ std::optional<OutlinerParaObject> pParaObj = xCell->CreateEditOutlinerParaObject();
+
+ if( !pParaObj && xCell->GetOutlinerParaObject() )
+ pParaObj = *xCell->GetOutlinerParaObject();
+
+ if(pParaObj)
+ {
+ // handle outliner attributes
+ SdrOutliner& rOutliner = mrObj.ImpGetDrawOutliner();
+ rOutliner.SetText(*pParaObj);
+
+ aContent = rOutliner.GetEditEngine().GetText();
+
+ rOutliner.Clear();
+ }
+
+ bool bResetAttr = false;
+
+ SdrTextHorzAdjust eHAdj = xCell->GetTextHorizontalAdjust();
+
+ const SfxItemSet& rCellSet = xCell->GetItemSet();
+
+ const SvxWeightItem& rWeightItem = rCellSet.Get( EE_CHAR_WEIGHT );
+ const SvxPostureItem& rPostureItem = rCellSet.Get( EE_CHAR_ITALIC );
+ const SvxUnderlineItem& rUnderlineItem = rCellSet.Get( EE_CHAR_UNDERLINE );
+
+ const char* pChar;
+
+ switch( eHAdj )
+ {
+ case SDRTEXTHORZADJUST_CENTER: pChar = OOO_STRING_SVTOOLS_RTF_QC; break;
+ case SDRTEXTHORZADJUST_BLOCK: pChar = OOO_STRING_SVTOOLS_RTF_QJ; break;
+ case SDRTEXTHORZADJUST_RIGHT: pChar = OOO_STRING_SVTOOLS_RTF_QR; break;
+ case SDRTEXTHORZADJUST_LEFT:
+ default: pChar = OOO_STRING_SVTOOLS_RTF_QL; break;
+ }
+ mrStrm.WriteCharPtr( pChar );
+
+ if ( rWeightItem.GetWeight() >= WEIGHT_BOLD )
+ { // bold
+ bResetAttr = true;
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B );
+ }
+ if ( rPostureItem.GetPosture() != ITALIC_NONE )
+ { // italic
+ bResetAttr = true;
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I );
+ }
+ if ( rUnderlineItem.GetLineStyle() != LINESTYLE_NONE )
+ { // underline
+ bResetAttr = true;
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL );
+ }
+
+ mrStrm.WriteChar( ' ' );
+ RTFOutFuncs::Out_String( mrStrm, aContent );
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL );
+
+ if ( bResetAttr )
+ mrStrm.WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PLAIN );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablertfimporter.cxx b/svx/source/table/tablertfimporter.cxx
new file mode 100644
index 000000000..8f6e1c649
--- /dev/null
+++ b/svx/source/table/tablertfimporter.cxx
@@ -0,0 +1,503 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <memory>
+#include <vector>
+
+#include <com/sun/star/table/XTable.hpp>
+#include <com/sun/star/table/XMergeableCellRange.hpp>
+
+#include <tools/stream.hxx>
+#include <tools/UnitConversion.hxx>
+#include <svtools/rtftoken.h>
+
+#include <svx/svdetc.hxx>
+#include <editeng/outlobj.hxx>
+
+#include <cell.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editdata.hxx>
+#include <svx/svdmodel.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/svxrtf.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+
+namespace sdr::table {
+
+namespace {
+
+struct RTFCellDefault
+{
+ SfxItemSet maItemSet;
+ sal_Int32 mnRowSpan;
+ sal_Int32 mnColSpan; // MergeCell if >1, merged cells if 0
+ sal_Int32 mnCellX;
+
+ explicit RTFCellDefault( SfxItemPool* pPool ) : maItemSet( *pPool ), mnRowSpan(1), mnColSpan(1), mnCellX(0) {}
+};
+
+}
+
+typedef std::vector< std::shared_ptr< RTFCellDefault > > RTFCellDefaultVector;
+
+namespace {
+
+struct RTFCellInfo
+{
+ SfxItemSet maItemSet;
+ sal_Int32 mnStartPara;
+ sal_Int32 mnParaCount;
+ sal_Int32 mnCellX;
+ sal_Int32 mnRowSpan;
+ std::shared_ptr< RTFCellInfo > mxVMergeCell;
+
+ explicit RTFCellInfo( SfxItemPool& rPool ) : maItemSet( rPool ), mnStartPara(0), mnParaCount(0), mnCellX(0), mnRowSpan(1) {}
+};
+
+}
+
+typedef std::shared_ptr< RTFCellInfo > RTFCellInfoPtr;
+typedef std::vector< RTFCellInfoPtr > RTFColumnVector;
+
+typedef std::shared_ptr< RTFColumnVector > RTFColumnVectorPtr;
+
+class SdrTableRTFParser
+{
+public:
+ explicit SdrTableRTFParser( SdrTableObj& rTableObj );
+
+ void Read( SvStream& rStream );
+
+ void ProcToken( RtfImportInfo* pInfo );
+
+ void NextRow();
+ void NextColumn();
+ void NewCellRow();
+
+ void InsertCell( RtfImportInfo const * pInfo );
+ void InsertColumnEdge( sal_Int32 nEdge );
+
+ void FillTable();
+
+ DECL_LINK( RTFImportHdl, RtfImportInfo&, void );
+
+private:
+ SdrTableObj& mrTableObj;
+ std::unique_ptr<SdrOutliner> mpOutliner;
+ SfxItemPool& mrItemPool;
+
+ RTFCellDefaultVector maDefaultList;
+ RTFCellDefaultVector::iterator maDefaultIterator;
+
+ int mnLastToken;
+ bool mbNewDef;
+
+ sal_Int32 mnStartPara;
+
+ sal_Int32 mnRowCnt;
+ sal_Int32 mnLastEdge;
+ sal_Int32 mnVMergeIdx;
+
+ std::vector< sal_Int32 > maColumnEdges;
+ std::vector< sal_Int32 >::iterator maLastEdge;
+ std::vector< RTFColumnVectorPtr > maRows;
+
+ std::unique_ptr<RTFCellDefault> mpInsDefault;
+ RTFCellDefault* mpActDefault;
+ RTFCellDefault* mpDefMerge;
+
+ Reference< XTable > mxTable;
+
+ RTFColumnVectorPtr mxLastRow;
+ // Copy assignment is forbidden and not implemented.
+ SdrTableRTFParser (const SdrTableRTFParser &) = delete;
+ SdrTableRTFParser & operator= (const SdrTableRTFParser &) = delete;
+};
+
+SdrTableRTFParser::SdrTableRTFParser( SdrTableObj& rTableObj )
+: mrTableObj( rTableObj )
+, mpOutliner( SdrMakeOutliner( OutlinerMode::TextObject, rTableObj.getSdrModelFromSdrObject() ) )
+, mrItemPool( rTableObj.getSdrModelFromSdrObject().GetItemPool() )
+, mnLastToken( 0 )
+, mbNewDef( false )
+, mnStartPara( 0 )
+, mnRowCnt( 0 )
+, mnLastEdge( 0 )
+, mnVMergeIdx ( 0 )
+, mpActDefault( nullptr )
+, mpDefMerge( nullptr )
+, mxTable( rTableObj.getTable() )
+{
+ mpOutliner->SetUpdateLayout(true);
+ mpOutliner->SetStyleSheet( 0, mrTableObj.GetStyleSheet() );
+ mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
+}
+
+void SdrTableRTFParser::Read( SvStream& rStream )
+{
+ EditEngine& rEdit = const_cast< EditEngine& >( mpOutliner->GetEditEngine() );
+
+ Link<RtfImportInfo&,void> aOldLink( rEdit.GetRtfImportHdl() );
+ rEdit.SetRtfImportHdl( LINK( this, SdrTableRTFParser, RTFImportHdl ) );
+ mpOutliner->Read( rStream, OUString(), EETextFormat::Rtf );
+ rEdit.SetRtfImportHdl( aOldLink );
+
+ FillTable();
+}
+
+IMPL_LINK( SdrTableRTFParser, RTFImportHdl, RtfImportInfo&, rInfo, void )
+{
+ switch ( rInfo.eState )
+ {
+ case RtfImportState::NextToken:
+ ProcToken( &rInfo );
+ break;
+ case RtfImportState::UnknownAttr:
+ ProcToken( &rInfo );
+ break;
+ case RtfImportState::Start:
+ {
+ SvxRTFParser* pParser = static_cast<SvxRTFParser*>(rInfo.pParser);
+ pParser->SetAttrPool( &mrItemPool );
+ pParser->SetPardMap(SID_ATTR_BORDER_OUTER, SDRATTR_TABLE_BORDER);
+ }
+ break;
+ case RtfImportState::End:
+ if ( rInfo.aSelection.nEndPos )
+ {
+ mpActDefault = nullptr;
+ rInfo.nToken = RTF_PAR;
+ rInfo.aSelection.nEndPara++;
+ ProcToken( &rInfo );
+ }
+ break;
+ case RtfImportState::SetAttr:
+ case RtfImportState::InsertText:
+ case RtfImportState::InsertPara:
+ break;
+ default:
+ SAL_WARN( "svx.table","unknown ImportInfo.eState");
+ }
+}
+
+void SdrTableRTFParser::NextRow()
+{
+ mxLastRow = maRows.back();
+ mnVMergeIdx = 0;
+ ++mnRowCnt;
+}
+
+void SdrTableRTFParser::InsertCell( RtfImportInfo const * pInfo )
+{
+
+ RTFCellInfoPtr xCellInfo = std::make_shared<RTFCellInfo>(mrItemPool);
+
+ xCellInfo->mnStartPara = mnStartPara;
+ xCellInfo->mnParaCount = pInfo->aSelection.nEndPara - 1 - mnStartPara;
+ xCellInfo->mnCellX = mpActDefault->mnCellX;
+ xCellInfo->mnRowSpan = mpActDefault->mnRowSpan;
+
+
+ if ( mxLastRow != nullptr )
+ {
+ sal_Int32 nSize = mxLastRow->size();
+ while( mnVMergeIdx < nSize &&
+ (*mxLastRow)[mnVMergeIdx]->mnCellX < xCellInfo->mnCellX )
+ ++mnVMergeIdx;
+
+ if ( xCellInfo->mnRowSpan == 0 && mnVMergeIdx < nSize )
+ {
+ RTFCellInfoPtr xLastCell( (*mxLastRow)[mnVMergeIdx] );
+ if (xLastCell->mnRowSpan)
+ xCellInfo->mxVMergeCell = xLastCell;
+ else
+ xCellInfo->mxVMergeCell = xLastCell->mxVMergeCell;
+ }
+ }
+
+ if( !maRows.empty() )
+ {
+ RTFColumnVectorPtr xColumn( maRows.back() );
+ if ( xCellInfo->mxVMergeCell )
+ {
+ if ( xColumn->empty() ||
+ xColumn->back()->mxVMergeCell != xCellInfo->mxVMergeCell )
+ xCellInfo->mxVMergeCell->mnRowSpan++;
+ }
+
+ xColumn->push_back( xCellInfo );
+ }
+
+ mnStartPara = pInfo->aSelection.nEndPara - 1;
+}
+
+void SdrTableRTFParser::InsertColumnEdge( sal_Int32 nEdge )
+{
+ auto aNextEdge = std::lower_bound( maLastEdge, maColumnEdges.end(), nEdge );
+
+ if ( aNextEdge == maColumnEdges.end() || nEdge != *aNextEdge )
+ {
+ maLastEdge = maColumnEdges.insert( aNextEdge , nEdge );
+ mnLastEdge = nEdge;
+ }
+}
+
+void SdrTableRTFParser::FillTable()
+{
+ try
+ {
+ sal_Int32 nColCount = mxTable->getColumnCount();
+ Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_SET_THROW );
+ sal_Int32 nColMax = maColumnEdges.size();
+ if( nColCount < nColMax )
+ {
+ xCols->insertByIndex( nColCount, nColMax - nColCount );
+ nColCount = mxTable->getColumnCount();
+ }
+
+ static const OUStringLiteral sWidth(u"Width");
+ sal_Int32 nCol, nLastEdge = 0;
+ for( nCol = 0; nCol < nColCount; nCol++ )
+ {
+ Reference< XPropertySet > xSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW );
+ sal_Int32 nWidth = maColumnEdges[nCol] - nLastEdge;
+
+ xSet->setPropertyValue( sWidth, Any( nWidth ) );
+ nLastEdge += nWidth;
+ }
+
+ const sal_Int32 nRowCount = mxTable->getRowCount();
+ if( nRowCount < mnRowCnt )
+ {
+ Reference< XTableRows > xRows( mxTable->getRows(), UNO_SET_THROW );
+ xRows->insertByIndex( nRowCount, mnRowCnt - nRowCount );
+ }
+
+ for( sal_Int32 nRow = 0; nRow < static_cast<sal_Int32>(maRows.size()); nRow++ )
+ {
+ RTFColumnVectorPtr xColumn( maRows[nRow] );
+ nCol = 0;
+ auto aEdge = maColumnEdges.begin();
+ for( sal_Int32 nIdx = 0; nCol < nColMax && nIdx < static_cast<sal_Int32>(xColumn->size()); nIdx++ )
+ {
+ RTFCellInfoPtr xCellInfo( (*xColumn)[nIdx] );
+
+ CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
+ if( xCell.is() && xCellInfo )
+ {
+ const SfxPoolItem *pPoolItem = nullptr;
+ if( xCellInfo->maItemSet.GetItemState(SDRATTR_TABLE_BORDER,false,&pPoolItem)==SfxItemState::SET)
+ xCell->SetMergedItem( *pPoolItem );
+
+ std::optional<OutlinerParaObject> pTextObject(mpOutliner->CreateParaObject( xCellInfo->mnStartPara, xCellInfo->mnParaCount ));
+ if( pTextObject )
+ {
+ SdrOutliner& rOutliner=mrTableObj.ImpGetDrawOutliner();
+ rOutliner.SetUpdateLayout(true);
+ rOutliner.SetText( *pTextObject );
+ mrTableObj.NbcSetOutlinerParaObjectForText( rOutliner.CreateParaObject(), xCell.get() );
+ }
+
+ sal_Int32 nLastRow = nRow;
+ if ( xCellInfo->mnRowSpan )
+ nLastRow += xCellInfo->mnRowSpan - 1;
+
+ aEdge = std::lower_bound( aEdge, maColumnEdges.end(), xCellInfo->mnCellX );
+ sal_Int32 nLastCol = nCol;
+ if ( aEdge != maColumnEdges.end() )
+ {
+ nLastCol = std::distance( maColumnEdges.begin(), aEdge);
+ ++aEdge;
+ }
+
+ if ( nLastCol > nCol || nLastRow > nRow )
+ {
+ Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( nCol, nRow, nLastCol, nLastRow ) ), UNO_QUERY_THROW );
+ if( xRange->isMergeable() )
+ xRange->merge();
+ }
+ nCol = nLastCol + 1;
+ }
+ }
+ }
+
+ tools::Rectangle aRect( mrTableObj.GetSnapRect() );
+ aRect.SetRight( aRect.Left() + nLastEdge );
+ mrTableObj.NbcSetSnapRect( aRect );
+
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+}
+
+void SdrTableRTFParser::NewCellRow()
+{
+ if( mbNewDef )
+ {
+ mbNewDef = false;
+
+ maRows.push_back( std::make_shared<std::vector<std::shared_ptr<RTFCellInfo>>>( ) );
+ }
+ mpDefMerge = nullptr;
+ maDefaultIterator = maDefaultList.begin();
+
+ NextColumn();
+
+ DBG_ASSERT( mpActDefault, "NewCellRow: pActDefault==0" );
+}
+
+void SdrTableRTFParser::NextColumn()
+{
+ if( maDefaultIterator != maDefaultList.end() )
+ mpActDefault = (*maDefaultIterator++).get();
+ else
+ mpActDefault = nullptr;
+}
+
+void SdrTableRTFParser::ProcToken( RtfImportInfo* pInfo )
+{
+ switch ( pInfo->nToken )
+ {
+ case RTF_TROWD: // denotes table row default, before RTF_CELLX
+ {
+ maDefaultList.clear();
+ mpDefMerge = nullptr;
+ mnLastToken = pInfo->nToken;
+ maLastEdge = maColumnEdges.begin();
+ mnLastEdge = 0;
+ }
+ break;
+ case RTF_CLMGF: // The first cell of cells to be merged
+ {
+ mpDefMerge = mpInsDefault.get();
+ mnLastToken = pInfo->nToken;
+ }
+ break;
+ case RTF_CLMRG: // A cell to be merged with the preceding cell
+ {
+ if ( !mpDefMerge )
+ mpDefMerge = maDefaultList.back().get();
+ DBG_ASSERT( mpDefMerge, "RTF_CLMRG: pDefMerge==0" );
+ if( mpDefMerge )
+ mpDefMerge->mnColSpan++;
+ mpInsDefault->mnColSpan = 0;
+ mnLastToken = pInfo->nToken;
+ }
+ break;
+ case RTF_CLVMGF:
+ {
+ mnLastToken = pInfo->nToken;
+ }
+ break;
+ case RTF_CLVMRG:
+ {
+ mpInsDefault->mnRowSpan = 0;
+ mnLastToken = pInfo->nToken;
+ }
+ break;
+ case RTF_CELLX: // closes cell default
+ {
+ mbNewDef = true;
+ std::shared_ptr<RTFCellDefault> pDefault( mpInsDefault.release() );
+ maDefaultList.push_back( pDefault );
+
+
+ const sal_Int32 nSize = convertTwipToMm100(pInfo->nTokenValue);
+ if ( nSize > mnLastEdge )
+ InsertColumnEdge( nSize );
+
+ pDefault->mnCellX = nSize;
+ // Record cellx in the first merged cell.
+ if ( mpDefMerge && pDefault->mnColSpan == 0 )
+ mpDefMerge->mnCellX = nSize;
+
+ mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
+
+ mnLastToken = pInfo->nToken;
+ }
+ break;
+ case RTF_INTBL: // before the first RTF_CELL
+ {
+ if ( mnLastToken != RTF_INTBL && mnLastToken != RTF_CELL && mnLastToken != RTF_PAR )
+ {
+ NewCellRow();
+ mnLastToken = pInfo->nToken;
+ }
+ }
+ break;
+ case RTF_CELL: // denotes the end of a cell.
+ {
+ DBG_ASSERT( mpActDefault, "RTF_CELL: pActDefault==0" );
+ if ( mbNewDef || !mpActDefault )
+ NewCellRow();
+ if ( !mpActDefault )
+ mpActDefault = mpInsDefault.get();
+ if ( mpActDefault->mnColSpan > 0 )
+ {
+ InsertCell(pInfo);
+ }
+ NextColumn();
+ mnLastToken = pInfo->nToken;
+ }
+ break;
+ case RTF_ROW: // means the end of a row
+ {
+ NextRow();
+ mnLastToken = pInfo->nToken;
+ }
+ break;
+ case RTF_PAR: // Paragraph
+ mnLastToken = pInfo->nToken;
+ break;
+ default:
+ { // do not set nLastToken
+ switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) )
+ {
+ case RTF_SHADINGDEF:
+// ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(pInfo->nToken, mpInsDefault->maItemSet, sal_True );
+ break;
+ case RTF_BRDRDEF:
+ static_cast<SvxRTFParser*>(pInfo->pParser)->ReadBorderAttr(pInfo->nToken, mpInsDefault->maItemSet, true );
+ break;
+ }
+ }
+ }
+}
+
+void ImportAsRTF( SvStream& rStream, SdrTableObj& rObj )
+{
+ SdrTableRTFParser aParser( rObj );
+ aParser.Read( rStream );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tableundo.cxx b/svx/source/table/tableundo.cxx
new file mode 100644
index 000000000..66641469d
--- /dev/null
+++ b/svx/source/table/tableundo.cxx
@@ -0,0 +1,516 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/properties/textproperties.hxx>
+#include <editeng/outlobj.hxx>
+
+#include <cell.hxx>
+#include "tableundo.hxx"
+#include <svx/svdotable.hxx>
+#include "tablerow.hxx"
+#include "tablecolumn.hxx"
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::table;
+
+
+namespace sdr::table {
+
+CellUndo::CellUndo( SdrObject* pObjRef, const CellRef& xCell )
+: SdrUndoAction(xCell->GetObject().getSdrModelFromSdrObject())
+ ,mxObjRef( pObjRef )
+ ,mxCell( xCell )
+ ,mbUndo( true )
+{
+ if( mxCell.is() && mxObjRef.is() )
+ {
+ getDataFromCell( maUndoData );
+ mxObjRef->AddObjectUser( *this );
+ }
+}
+
+CellUndo::~CellUndo()
+{
+ if( mxObjRef.is() )
+ mxObjRef->RemoveObjectUser( *this );
+ dispose();
+}
+
+void CellUndo::dispose()
+{
+ mxCell.clear();
+ delete maUndoData.mpProperties;
+ maUndoData.mpProperties = nullptr;
+ delete maRedoData.mpProperties;
+ maRedoData.mpProperties = nullptr;
+ maUndoData.mpOutlinerParaObject.reset();
+ maRedoData.mpOutlinerParaObject.reset();
+}
+
+void CellUndo::ObjectInDestruction(const SdrObject& )
+{
+ dispose();
+}
+
+void CellUndo::Undo()
+{
+ if( mxCell.is() && mbUndo )
+ {
+ if( maRedoData.mpProperties == nullptr )
+ getDataFromCell( maRedoData );
+
+ setDataToCell( maUndoData );
+ mbUndo = false;
+ }
+}
+
+void CellUndo::Redo()
+{
+ if( mxCell.is() && !mbUndo )
+ {
+ setDataToCell( maRedoData );
+ mbUndo = true;
+ }
+}
+
+bool CellUndo::Merge( SfxUndoAction *pNextAction )
+{
+ CellUndo* pNext = dynamic_cast< CellUndo* >( pNextAction );
+ return pNext && pNext->mxCell.get() == mxCell.get();
+}
+
+void CellUndo::setDataToCell( const Data& rData )
+{
+ if( rData.mpProperties )
+ mxCell->mpProperties.reset(Cell::CloneProperties( rData.mpProperties, *mxObjRef, *mxCell ));
+ else
+ mxCell->mpProperties.reset();
+
+ if( rData.mpOutlinerParaObject )
+ mxCell->SetOutlinerParaObject( *rData.mpOutlinerParaObject );
+ else
+ mxCell->RemoveOutlinerParaObject();
+
+ mxCell->msFormula = rData.msFormula;
+ mxCell->mfValue = rData.mfValue;
+ mxCell->mnError = rData.mnError;
+ mxCell->mbMerged = rData.mbMerged;
+ mxCell->mnRowSpan = rData.mnRowSpan;
+ mxCell->mnColSpan = rData.mnColSpan;
+
+ if(mxObjRef.is())
+ {
+ // #i120201# ActionChanged is not enough, we need to trigger TableLayouter::UpdateBorderLayout()
+ // and this is done best using ReformatText() for table objects
+ mxObjRef->ActionChanged();
+ mxObjRef->NbcReformatText();
+ }
+}
+
+void CellUndo::getDataFromCell( Data& rData )
+{
+ if( !(mxObjRef.is() && mxCell.is()) )
+ return;
+
+ if( mxCell->mpProperties )
+ rData.mpProperties = mxCell->CloneProperties( *mxObjRef, *mxCell);
+
+ if( mxCell->GetOutlinerParaObject() )
+ rData.mpOutlinerParaObject = *mxCell->GetOutlinerParaObject();
+ else
+ rData.mpOutlinerParaObject.reset();
+
+ rData.msFormula = mxCell->msFormula;
+ rData.mfValue = mxCell->mfValue;
+ rData.mnError = mxCell->mnError;
+ rData.mbMerged = mxCell->mbMerged;
+ rData.mnRowSpan = mxCell->mnRowSpan;
+ rData.mnColSpan = mxCell->mnColSpan;
+}
+
+
+// class InsertRowUndo : public SdrUndoAction
+
+
+static void Dispose( RowVector& rRows )
+{
+ for( auto& rpRow : rRows )
+ rpRow->dispose();
+}
+
+
+InsertRowUndo::InsertRowUndo( const TableModelRef& xTable, sal_Int32 nIndex, RowVector& aNewRows )
+: SdrUndoAction(xTable->getSdrTableObj()->getSdrModelFromSdrObject())
+ ,mxTable( xTable )
+ ,mnIndex( nIndex )
+ ,mbUndo( true )
+{
+ maRows.swap( aNewRows );
+}
+
+
+InsertRowUndo::~InsertRowUndo()
+{
+ if( !mbUndo )
+ Dispose( maRows );
+}
+
+
+void InsertRowUndo::Undo()
+{
+ if( mxTable.is() )
+ {
+ mxTable->UndoInsertRows( mnIndex, sal::static_int_cast< sal_Int32 >( maRows.size() ) );
+ mbUndo = false;
+ }
+}
+
+
+void InsertRowUndo::Redo()
+{
+ if( mxTable.is() )
+ {
+ mxTable->UndoRemoveRows( mnIndex, maRows );
+ mbUndo = true;
+ }
+}
+
+
+// class RemoveRowUndo : public SdrUndoAction
+
+
+RemoveRowUndo::RemoveRowUndo( const TableModelRef& xTable, sal_Int32 nIndex, RowVector& aRemovedRows )
+: SdrUndoAction(xTable->getSdrTableObj()->getSdrModelFromSdrObject())
+ ,mxTable( xTable )
+ ,mnIndex( nIndex )
+ ,mbUndo( true )
+{
+ maRows.swap( aRemovedRows );
+}
+
+
+RemoveRowUndo::~RemoveRowUndo()
+{
+ if( mbUndo )
+ Dispose( maRows );
+}
+
+
+void RemoveRowUndo::Undo()
+{
+ if( mxTable.is() )
+ {
+ mxTable->UndoRemoveRows( mnIndex, maRows );
+ mbUndo = false;
+ }
+}
+
+
+void RemoveRowUndo::Redo()
+{
+ if( mxTable.is() )
+ {
+ mxTable->UndoInsertRows( mnIndex, sal::static_int_cast< sal_Int32 >( maRows.size() ) );
+ mbUndo = true;
+ }
+}
+
+
+// class InsertColUndo : public SdrUndoAction
+
+
+static void Dispose( ColumnVector& rCols )
+{
+ for( auto& rpCol : rCols )
+ rpCol->dispose();
+}
+
+
+static void Dispose( CellVector& rCells )
+{
+ for( auto& rpCell : rCells )
+ rpCell->dispose();
+}
+
+
+InsertColUndo::InsertColUndo( const TableModelRef& xTable, sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells )
+: SdrUndoAction(xTable->getSdrTableObj()->getSdrModelFromSdrObject())
+ ,mxTable( xTable )
+ ,mnIndex( nIndex )
+ ,mbUndo( true )
+{
+ maColumns.swap( aNewCols );
+ maCells.swap( aCells );
+}
+
+
+InsertColUndo::~InsertColUndo()
+{
+ if( !mbUndo )
+ {
+ Dispose( maColumns );
+ Dispose( maCells );
+ }
+}
+
+
+void InsertColUndo::Undo()
+{
+ if( mxTable.is() )
+ {
+ mxTable->UndoInsertColumns( mnIndex, sal::static_int_cast< sal_Int32 >( maColumns.size() ) );
+ mbUndo = false;
+ }
+}
+
+
+void InsertColUndo::Redo()
+{
+ if( mxTable.is() )
+ {
+ mxTable->UndoRemoveColumns( mnIndex, maColumns, maCells );
+ mbUndo = true;
+ }
+}
+
+
+// class RemoveColUndo : public SdrUndoAction
+
+
+RemoveColUndo::RemoveColUndo( const TableModelRef& xTable, sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells )
+: SdrUndoAction(xTable->getSdrTableObj()->getSdrModelFromSdrObject())
+ ,mxTable( xTable )
+ ,mnIndex( nIndex )
+ ,mbUndo( true )
+{
+ maColumns.swap( aNewCols );
+ maCells.swap( aCells );
+}
+
+
+RemoveColUndo::~RemoveColUndo()
+{
+ if( mbUndo )
+ {
+ Dispose( maColumns );
+ Dispose( maCells );
+ }
+}
+
+
+void RemoveColUndo::Undo()
+{
+ if( mxTable.is() )
+ {
+ mxTable->UndoRemoveColumns( mnIndex, maColumns, maCells );
+ mbUndo = false;
+ }
+}
+
+
+void RemoveColUndo::Redo()
+{
+ if( mxTable.is() )
+ {
+ mxTable->UndoInsertColumns( mnIndex, sal::static_int_cast< sal_Int32 >( maColumns.size() ) );
+ mbUndo = true;
+ }
+}
+
+
+// class TableColumnUndo : public SdrUndoAction
+
+
+TableColumnUndo::TableColumnUndo( const TableColumnRef& xCol )
+: SdrUndoAction(xCol->mxTableModel->getSdrTableObj()->getSdrModelFromSdrObject())
+ ,mxCol( xCol )
+ ,mbHasRedoData( false )
+{
+ getData( maUndoData );
+}
+
+
+TableColumnUndo::~TableColumnUndo()
+{
+}
+
+
+void TableColumnUndo::Undo()
+{
+ if( !mbHasRedoData )
+ {
+ getData( maRedoData );
+ mbHasRedoData = true;
+ }
+ setData( maUndoData );
+}
+
+
+void TableColumnUndo::Redo()
+{
+ setData( maRedoData );
+}
+
+
+bool TableColumnUndo::Merge( SfxUndoAction *pNextAction )
+{
+ TableColumnUndo* pNext = dynamic_cast< TableColumnUndo* >( pNextAction );
+ return pNext && pNext->mxCol == mxCol;
+}
+
+
+void TableColumnUndo::setData( const Data& rData )
+{
+ mxCol->mnColumn = rData.mnColumn;
+ mxCol->mnWidth = rData.mnWidth;
+ mxCol->mbOptimalWidth = rData.mbOptimalWidth;
+ mxCol->mbIsVisible = rData.mbIsVisible;
+ mxCol->mbIsStartOfNewPage = rData.mbIsStartOfNewPage;
+ mxCol->maName = rData.maName;
+
+ // Trigger re-layout of the table.
+ mxCol->getModel()->setModified(true);
+}
+
+
+void TableColumnUndo::getData( Data& rData )
+{
+ rData.mnColumn = mxCol->mnColumn;
+ rData.mnWidth = mxCol->mnWidth;
+ rData.mbOptimalWidth = mxCol->mbOptimalWidth;
+ rData.mbIsVisible = mxCol->mbIsVisible;
+ rData.mbIsStartOfNewPage = mxCol->mbIsStartOfNewPage;
+ rData.maName = mxCol->maName;
+}
+
+
+// class TableRowUndo : public SdrUndoAction
+
+
+TableRowUndo::TableRowUndo( const TableRowRef& xRow )
+: SdrUndoAction(xRow->mxTableModel->getSdrTableObj()->getSdrModelFromSdrObject())
+ , mxRow( xRow )
+ , mbHasRedoData( false )
+{
+ getData( maUndoData );
+}
+
+
+TableRowUndo::~TableRowUndo()
+{
+}
+
+
+void TableRowUndo::Undo()
+{
+ if( !mbHasRedoData )
+ {
+ getData( maRedoData );
+ mbHasRedoData = true;
+ }
+ setData( maUndoData );
+}
+
+
+void TableRowUndo::Redo()
+{
+ setData( maRedoData );
+}
+
+
+bool TableRowUndo::Merge( SfxUndoAction *pNextAction )
+{
+ TableRowUndo* pNext = dynamic_cast< TableRowUndo* >( pNextAction );
+ return pNext && pNext->mxRow == mxRow;
+}
+
+
+void TableRowUndo::setData( const Data& rData )
+{
+ mxRow->mnRow = rData.mnRow;
+ mxRow->mnHeight = rData.mnHeight;
+ mxRow->mbOptimalHeight = rData.mbOptimalHeight;
+ mxRow->mbIsVisible = rData.mbIsVisible;
+ mxRow->mbIsStartOfNewPage = rData.mbIsStartOfNewPage;
+ mxRow->maName = rData.maName;
+
+ // Trigger re-layout of the table.
+ mxRow->getModel()->setModified(true);
+ }
+
+
+void TableRowUndo::getData( Data& rData )
+{
+ rData.mnRow = mxRow->mnRow;
+ rData.mnHeight = mxRow->mnHeight;
+ rData.mbOptimalHeight = mxRow->mbOptimalHeight;
+ rData.mbIsVisible = mxRow->mbIsVisible;
+ rData.mbIsStartOfNewPage = mxRow->mbIsStartOfNewPage;
+ rData.maName = mxRow->maName;
+}
+
+
+TableStyleUndo::TableStyleUndo( const SdrTableObj& rTableObj )
+: SdrUndoAction(rTableObj.getSdrModelFromSdrObject())
+ ,mxObjRef( const_cast< sdr::table::SdrTableObj*>( &rTableObj ) )
+ ,mbHasRedoData(false)
+{
+ getData( maUndoData );
+}
+
+void TableStyleUndo::Undo()
+{
+ if( !mbHasRedoData )
+ {
+ getData( maRedoData );
+ mbHasRedoData = true;
+ }
+ setData( maUndoData );
+}
+
+void TableStyleUndo::Redo()
+{
+ setData( maRedoData );
+}
+
+void TableStyleUndo::setData( const Data& rData )
+{
+ SdrTableObj* pTableObj = mxObjRef.get();
+ if( pTableObj )
+ {
+ pTableObj->setTableStyle( rData.mxTableStyle );
+ pTableObj->setTableStyleSettings( rData.maSettings );
+ }
+}
+
+void TableStyleUndo::getData( Data& rData )
+{
+ SdrTableObj* pTableObj = mxObjRef.get();
+ if( pTableObj )
+ {
+ rData.maSettings = pTableObj->getTableStyleSettings();
+ rData.mxTableStyle = pTableObj->getTableStyle();
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tableundo.hxx b/svx/source/table/tableundo.hxx
new file mode 100644
index 000000000..822f5ec64
--- /dev/null
+++ b/svx/source/table/tableundo.hxx
@@ -0,0 +1,258 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_TABLEUNDO_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_TABLEUNDO_HXX
+
+#include <com/sun/star/container/XIndexAccess.hpp>
+
+#include <svx/svdotable.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/sdrobjectuser.hxx>
+
+#include <celltypes.hxx>
+
+namespace sdr::properties {
+ class TextProperties;
+}
+
+class OutlinerParaObject;
+
+
+namespace sdr::table {
+
+class CellUndo : public SdrUndoAction, public sdr::ObjectUser
+{
+public:
+ CellUndo( SdrObject* pObj, const CellRef& xCell );
+ virtual ~CellUndo() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual bool Merge( SfxUndoAction *pNextAction ) override;
+
+ void dispose();
+ virtual void ObjectInDestruction(const SdrObject& rObject) override;
+
+private:
+ struct Data
+ {
+ sdr::properties::TextProperties* mpProperties;
+ std::optional<OutlinerParaObject> mpOutlinerParaObject;
+
+ OUString msFormula;
+ double mfValue;
+ ::sal_Int32 mnError;
+ bool mbMerged;
+ ::sal_Int32 mnRowSpan;
+ ::sal_Int32 mnColSpan;
+
+ Data()
+ : mpProperties(nullptr)
+ , mfValue(0)
+ , mnError(0)
+ , mbMerged(false)
+ , mnRowSpan(0)
+ , mnColSpan(0)
+ {
+ }
+ };
+
+ void setDataToCell( const Data& rData );
+ void getDataFromCell( Data& rData );
+
+ tools::WeakReference<SdrObject> mxObjRef;
+ CellRef mxCell;
+ Data maUndoData;
+ Data maRedoData;
+ bool mbUndo;
+};
+
+
+class InsertRowUndo : public SdrUndoAction
+{
+public:
+ InsertRowUndo( const TableModelRef& xTable, sal_Int32 nIndex, RowVector& aNewRows );
+ virtual ~InsertRowUndo() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+private:
+ TableModelRef mxTable;
+ sal_Int32 mnIndex;
+ RowVector maRows;
+ bool mbUndo;
+};
+
+
+class RemoveRowUndo : public SdrUndoAction
+{
+public:
+ RemoveRowUndo( const TableModelRef& xTable, sal_Int32 nIndex, RowVector& aRemovedRows );
+ virtual ~RemoveRowUndo() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+private:
+ TableModelRef mxTable;
+ sal_Int32 mnIndex;
+ RowVector maRows;
+ bool mbUndo;
+};
+
+
+class InsertColUndo : public SdrUndoAction
+{
+public:
+ InsertColUndo( const TableModelRef& xTable, sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells );
+ virtual ~InsertColUndo() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+private:
+ TableModelRef mxTable;
+ sal_Int32 mnIndex;
+ ColumnVector maColumns;
+ CellVector maCells;
+ bool mbUndo;
+};
+
+
+class RemoveColUndo : public SdrUndoAction
+{
+public:
+ RemoveColUndo( const TableModelRef& xTable, sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells );
+ virtual ~RemoveColUndo() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+private:
+ TableModelRef mxTable;
+ sal_Int32 mnIndex;
+ ColumnVector maColumns;
+ CellVector maCells;
+ bool mbUndo;
+};
+
+
+class TableColumnUndo : public SdrUndoAction
+{
+public:
+ explicit TableColumnUndo( const TableColumnRef& xCol );
+ virtual ~TableColumnUndo() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual bool Merge( SfxUndoAction *pNextAction ) override;
+
+private:
+ struct Data
+ {
+ sal_Int32 mnColumn;
+ sal_Int32 mnWidth;
+ bool mbOptimalWidth;
+ bool mbIsVisible;
+ bool mbIsStartOfNewPage;
+ OUString maName;
+
+ Data()
+ : mnColumn(0)
+ , mnWidth(0)
+ , mbOptimalWidth(false)
+ , mbIsVisible(false)
+ , mbIsStartOfNewPage(false)
+ {
+ }
+ };
+
+ void setData( const Data& rData );
+ void getData( Data& rData );
+
+ TableColumnRef mxCol;
+ Data maUndoData;
+ Data maRedoData;
+ bool mbHasRedoData;
+};
+
+
+class TableRowUndo : public SdrUndoAction
+{
+public:
+ explicit TableRowUndo( const TableRowRef& xRow );
+ virtual ~TableRowUndo() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual bool Merge( SfxUndoAction *pNextAction ) override;
+
+private:
+ struct Data
+ {
+ sal_Int32 mnRow;
+ sal_Int32 mnHeight;
+ bool mbOptimalHeight;
+ bool mbIsVisible;
+ bool mbIsStartOfNewPage;
+ OUString maName;
+ };
+
+ void setData( const Data& rData );
+ void getData( Data& rData );
+
+ TableRowRef mxRow;
+ Data maUndoData;
+ Data maRedoData;
+ bool mbHasRedoData;
+};
+
+class TableStyleUndo : public SdrUndoAction
+{
+public:
+ explicit TableStyleUndo( const SdrTableObj& rTableObj );
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+private:
+ tools::WeakReference<SdrTableObj> mxObjRef;
+
+ struct Data
+ {
+ TableStyleSettings maSettings;
+ css::uno::Reference< css::container::XIndexAccess > mxTableStyle;
+ };
+
+ void setData( const Data& rData );
+ void getData( Data& rData );
+
+ Data maUndoData;
+ Data maRedoData;
+ bool mbHasRedoData;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx
new file mode 100644
index 000000000..c550c5ec2
--- /dev/null
+++ b/svx/source/table/viewcontactoftableobj.cxx
@@ -0,0 +1,547 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "viewcontactoftableobj.hxx"
+#include <svx/svdotable.hxx>
+#include <com/sun/star/table/XTable.hpp>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <editeng/borderline.hxx>
+#include <sdr/attribute/sdrfilltextattribute.hxx>
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <drawinglayer/attribute/sdrlineattribute.hxx>
+#include <drawinglayer/attribute/sdrshadowattribute.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/framelink.hxx>
+#include <svx/framelinkarray.hxx>
+#include <svx/sdooitm.hxx>
+#include <vcl/canvastools.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <svx/xfltrit.hxx>
+
+#include <cell.hxx>
+#include "tablelayouter.hxx"
+
+
+using editeng::SvxBorderLine;
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ namespace {
+
+ class SdrCellPrimitive2D : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ basegfx::B2DHomMatrix maTransform;
+ attribute::SdrFillTextAttribute maSdrFTAttribute;
+
+ protected:
+ // local decomposition.
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
+
+ public:
+ SdrCellPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrFillTextAttribute& rSdrFTAttribute)
+ : maTransform(rTransform),
+ maSdrFTAttribute(rSdrFTAttribute)
+ {
+ }
+
+ // data access
+ const basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
+ const attribute::SdrFillTextAttribute& getSdrFTAttribute() const { return maSdrFTAttribute; }
+
+ // compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+
+ }
+
+ void SdrCellPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ // prepare unit polygon
+ const basegfx::B2DPolyPolygon aUnitPolyPolygon(basegfx::utils::createUnitPolygon());
+
+ // add fill
+ if(!getSdrFTAttribute().getFill().isDefault())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitPolyPolygon);
+
+ aTransformed.transform(getTransform());
+ rContainer.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrFTAttribute().getFill(),
+ getSdrFTAttribute().getFillFloatTransGradient()));
+ }
+ else
+ {
+ // if no fill create one for HitTest and BoundRect fallback
+ rContainer.push_back(
+ createHiddenGeometryPrimitives2D(
+ true,
+ aUnitPolyPolygon,
+ getTransform()));
+ }
+
+ // add text
+ if(!getSdrFTAttribute().getText().isDefault())
+ {
+ rContainer.push_back(
+ createTextPrimitive(
+ aUnitPolyPolygon,
+ getTransform(),
+ getSdrFTAttribute().getText(),
+ attribute::SdrLineAttribute(),
+ true,
+ false));
+ }
+ }
+
+ bool SdrCellPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrCellPrimitive2D& rCompare = static_cast<const SdrCellPrimitive2D&>(rPrimitive);
+
+ return (getTransform() == rCompare.getTransform()
+ && getSdrFTAttribute() == rCompare.getSdrFTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrCellPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCELLPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+namespace sdr::contact
+{
+
+ namespace {
+ class ViewObjectContactOfTableObj : public ViewObjectContactOfSdrObj
+ {
+ public:
+ ViewObjectContactOfTableObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+ {
+ }
+
+ protected:
+ virtual void createPrimitive2DSequence(DisplayInfo const& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ };
+ } // namespace
+
+ static svx::frame::Style impGetLineStyle(
+ const sdr::table::TableLayouter& rLayouter,
+ sal_Int32 nX,
+ sal_Int32 nY,
+ bool bHorizontal,
+ sal_Int32 nColCount,
+ sal_Int32 nRowCount,
+ bool bIsRTL)
+ {
+ if(nX >= 0 && nX <= nColCount && nY >= 0 && nY <= nRowCount)
+ {
+ const SvxBorderLine* pLine = rLayouter.getBorderLine(nX, nY, bHorizontal);
+
+ if(pLine)
+ {
+ // copy line content
+ SvxBorderLine aLine(*pLine);
+
+ // check for mirroring. This shall always be done when it is
+ // not a top- or rightmost line
+ bool bMirror(aLine.isDouble());
+
+ if(bMirror)
+ {
+ if(bHorizontal)
+ {
+ // mirror all bottom lines
+ bMirror = (0 != nY);
+ }
+ else
+ {
+ // mirror all left lines
+ bMirror = (bIsRTL ? 0 != nX : nX != nColCount);
+ }
+ }
+
+ if(bMirror)
+ {
+ aLine.SetMirrorWidths( );
+ }
+
+ constexpr double fTwipsToMM(
+ o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100));
+ return svx::frame::Style(&aLine, fTwipsToMM);
+ }
+ }
+
+ // no success, copy empty line
+ return svx::frame::Style();
+ }
+
+ static void createPrimitive2DSequenceImpl(
+ sdr::table::SdrTableObj const& rTableObj,
+ bool const isTaggedPDF,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+ {
+ const uno::Reference< css::table::XTable > xTable = rTableObj.getTable();
+
+ if(xTable.is())
+ {
+ // create primitive representation for table. Cell info goes
+ // directly to aRetval, Border info to aBorderSequence and added
+ // later to get the correct overlapping
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+ drawinglayer::primitive2d::Primitive2DContainer aRetvalForShadow;
+ const sal_Int32 nRowCount(xTable->getRowCount());
+ const sal_Int32 nColCount(xTable->getColumnCount());
+ const sal_Int32 nAllCount(nRowCount * nColCount);
+ SdrPage const*const pPage(rTableObj.getSdrPageFromSdrObject());
+
+ if(nAllCount)
+ {
+ const sdr::table::TableLayouter& rTableLayouter(rTableObj.getTableLayouter());
+ const bool bIsRTL(css::text::WritingMode_RL_TB == rTableObj.GetWritingMode());
+ sdr::table::CellPos aCellPos;
+ sdr::table::CellRef xCurrentCell;
+ basegfx::B2IRectangle aCellArea;
+
+ // create range using the model data directly. This is in SdrTextObj::aRect which i will access using
+ // GetGeoRect() to not trigger any calculations. It's the unrotated geometry.
+ const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(rTableObj.GetGeoRect());
+
+ // To create the CellBorderPrimitives, use the tooling from svx::frame::Array
+ // which is capable of creating the needed visualization. Fill it during the
+ // anyways needed run over the table.
+ svx::frame::Array aArray;
+
+ // initialize CellBorderArray for primitive creation
+ aArray.Initialize(nColCount, nRowCount);
+
+ // create single primitives per cell
+ for(aCellPos.mnRow = 0; aCellPos.mnRow < nRowCount; aCellPos.mnRow++)
+ {
+ drawinglayer::primitive2d::Primitive2DContainer row;
+ // add RowHeight to CellBorderArray for primitive creation
+ aArray.SetRowHeight(aCellPos.mnRow, rTableLayouter.getRowHeight(aCellPos.mnRow));
+
+ for(aCellPos.mnCol = 0; aCellPos.mnCol < nColCount; aCellPos.mnCol++)
+ {
+ drawinglayer::primitive2d::Primitive2DContainer cell;
+ // add ColWidth to CellBorderArray for primitive creation, only
+ // needs to be done in the 1st run
+ if(0 == aCellPos.mnRow)
+ {
+ aArray.SetColWidth(aCellPos.mnCol, rTableLayouter.getColumnWidth(aCellPos.mnCol));
+ }
+
+ // access the cell
+ xCurrentCell.set(dynamic_cast< sdr::table::Cell* >(xTable->getCellByPosition(aCellPos.mnCol, aCellPos.mnRow).get()));
+
+ if(xCurrentCell.is())
+ {
+ // copy styles for current cell to CellBorderArray for primitive creation
+ aArray.SetCellStyleLeft(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow, false, nColCount, nRowCount, bIsRTL));
+ aArray.SetCellStyleRight(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol + 1, aCellPos.mnRow, false, nColCount, nRowCount, bIsRTL));
+ aArray.SetCellStyleTop(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow, true, nColCount, nRowCount, bIsRTL));
+ aArray.SetCellStyleBottom(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow + 1, true, nColCount, nRowCount, bIsRTL));
+
+ // ignore merged cells (all except the top-left of a merged cell)
+ if(!xCurrentCell->isMerged())
+ {
+ // check if we are the top-left of a merged cell
+ const sal_Int32 nXSpan(xCurrentCell->getColumnSpan());
+ const sal_Int32 nYSpan(xCurrentCell->getRowSpan());
+
+ if(nXSpan > 1 || nYSpan > 1)
+ {
+ // if merged, set so at CellBorderArray for primitive creation
+ aArray.SetMergedRange(aCellPos.mnCol, aCellPos.mnRow, aCellPos.mnCol + nXSpan - 1, aCellPos.mnRow + nYSpan - 1);
+ }
+ }
+ }
+
+ if(xCurrentCell.is() && !xCurrentCell->isMerged())
+ {
+ if(rTableLayouter.getCellArea(xCurrentCell, aCellPos, aCellArea))
+ {
+ // create cell transformation matrix
+ basegfx::B2DHomMatrix aCellMatrix;
+ aCellMatrix.set(0, 0, static_cast<double>(aCellArea.getWidth()));
+ aCellMatrix.set(1, 1, static_cast<double>(aCellArea.getHeight()));
+ aCellMatrix.set(0, 2, static_cast<double>(aCellArea.getMinX()) + aObjectRange.getMinX());
+ aCellMatrix.set(1, 2, static_cast<double>(aCellArea.getMinY()) + aObjectRange.getMinY());
+
+ // handle cell fillings and text
+ const SfxItemSet& rCellItemSet = xCurrentCell->GetItemSet();
+ const sal_uInt32 nTextIndex(nColCount * aCellPos.mnRow + aCellPos.mnCol);
+ const SdrText* pSdrText = rTableObj.getText(nTextIndex);
+ drawinglayer::attribute::SdrFillTextAttribute aAttribute;
+
+ if(pSdrText)
+ {
+ // #i101508# take cell's local text frame distances into account
+ const sal_Int32 nLeft(xCurrentCell->GetTextLeftDistance());
+ const sal_Int32 nRight(xCurrentCell->GetTextRightDistance());
+ const sal_Int32 nUpper(xCurrentCell->GetTextUpperDistance());
+ const sal_Int32 nLower(xCurrentCell->GetTextLowerDistance());
+
+ aAttribute = drawinglayer::primitive2d::createNewSdrFillTextAttribute(
+ rCellItemSet,
+ pSdrText,
+ &nLeft,
+ &nUpper,
+ &nRight,
+ &nLower);
+ }
+ else
+ {
+ aAttribute = drawinglayer::primitive2d::createNewSdrFillTextAttribute(
+ rCellItemSet,
+ pSdrText);
+ }
+
+ // always create cell primitives for BoundRect and HitTest
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xCellReference(
+ new drawinglayer::primitive2d::SdrCellPrimitive2D(
+ aCellMatrix, aAttribute));
+ cell.append(xCellReference);
+ }
+
+ // Create cell primitive without text.
+ aAttribute
+ = drawinglayer::primitive2d::createNewSdrFillTextAttribute(
+ rCellItemSet, nullptr);
+ rtl::Reference pCellReference
+ = new drawinglayer::primitive2d::SdrCellPrimitive2D(
+ aCellMatrix, aAttribute);
+
+ sal_uInt16 nTransparence(
+ rCellItemSet.Get(XATTR_FILLTRANSPARENCE).GetValue());
+ if (nTransparence != 0)
+ {
+ pCellReference->setTransparenceForShadow(nTransparence);
+ }
+
+ const drawinglayer::primitive2d::Primitive2DReference
+ xCellReference(pCellReference);
+ aRetvalForShadow.append(xCellReference);
+ }
+ }
+ if (isTaggedPDF && pPage)
+ {
+ // heuristic: if there's a special formatting on
+ // first row, assume that it's a header row
+ auto const eType(
+ aCellPos.mnRow == 0 && rTableObj.getTableStyleSettings().mbUseFirstRow
+ ? vcl::PDFWriter::TableHeader
+ : vcl::PDFWriter::TableData);
+ cell = drawinglayer::primitive2d::Primitive2DContainer {
+ new drawinglayer::primitive2d::StructureTagPrimitive2D(
+ eType,
+ pPage->IsMasterPage(),
+ false,
+ std::move(cell)) };
+ }
+ row.append(cell);
+ }
+
+ if (isTaggedPDF && pPage)
+ {
+ row = drawinglayer::primitive2d::Primitive2DContainer {
+ new drawinglayer::primitive2d::StructureTagPrimitive2D(
+ vcl::PDFWriter::TableRow,
+ pPage->IsMasterPage(),
+ false,
+ std::move(row)) };
+ }
+ aRetval.append(row);
+ }
+
+ // now create all CellBorderPrimitives
+ drawinglayer::primitive2d::Primitive2DContainer aCellBorderPrimitives(aArray.CreateB2DPrimitiveArray());
+
+ if(!aCellBorderPrimitives.empty())
+ {
+ // this is already scaled (due to Table in non-uniform coordinates), so
+ // first transform removing scale
+ basegfx::B2DHomMatrix aTransform(
+ basegfx::utils::createScaleB2DHomMatrix(
+ 1.0 / aObjectRange.getWidth(),
+ 1.0 / aObjectRange.getHeight()));
+
+ // If RTL, mirror the whole unified table in X and move right.
+ // This is much easier than taking this into account for the whole
+ // index calculations
+ if(bIsRTL)
+ {
+ aTransform.scale(-1.0, 1.0);
+ aTransform.translate(1.0, 0.0);
+ }
+
+ // create object matrix
+ const GeoStat& rGeoStat(rTableObj.GetGeoStat());
+ const double fShearX(-rGeoStat.mfTanShearAngle);
+ const double fRotate(rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0);
+ const basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(), fShearX, fRotate,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // add object matrix to transform. By doing so theoretically
+ // CellBorders could be also rotated/sheared for the first time ever.
+ // To completely make that work, the primitives already created in
+ // aRetval would also have to be based on ObjectMatrix, not only on
+ // ObjectRange as it currently is.
+ aTransform *= aObjectMatrix;
+
+ // create a transform primitive with this and embed CellBorders
+ // and append to retval
+ aRetval.append(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aTransform,
+ drawinglayer::primitive2d::Primitive2DContainer(aCellBorderPrimitives)));
+
+ // Borders are always the same for shadow as well.
+ aRetvalForShadow.append(new drawinglayer::primitive2d::TransformPrimitive2D(
+ aTransform, std::move(aCellBorderPrimitives)));
+ }
+ }
+
+ if(!aRetval.empty())
+ {
+ // check and create evtl. shadow for created content
+ const SfxItemSet& rObjectItemSet = rTableObj.GetMergedItemSet();
+ const drawinglayer::attribute::SdrShadowAttribute aNewShadowAttribute(
+ drawinglayer::primitive2d::createNewSdrShadowAttribute(rObjectItemSet));
+
+ if(!aNewShadowAttribute.isDefault())
+ {
+ bool bDirectShadow
+ = rObjectItemSet.Get(SDRATTR_SHADOW, /*bSrchInParent=*/false)
+ .GetValue();
+ if (bDirectShadow)
+ {
+ // Shadow as direct formatting: no shadow for text, to be compatible
+ // with PowerPoint.
+ basegfx::B2DHomMatrix aMatrix;
+ aRetval = drawinglayer::primitive2d::createEmbeddedShadowPrimitive(
+ std::move(aRetval), aNewShadowAttribute, aMatrix, &aRetvalForShadow);
+ }
+ else
+ {
+ // Shadow as style: shadow for text, to be backwards-compatible.
+ aRetval = drawinglayer::primitive2d::createEmbeddedShadowPrimitive(
+ std::move(aRetval), aNewShadowAttribute);
+ }
+ }
+ }
+
+ rVisitor.visit(std::move(aRetval));
+ }
+ else
+ {
+ // take unrotated snap rect (direct model data) for position and size
+ const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(rTableObj.GetGeoRect());
+
+ // create object matrix
+ const GeoStat& rGeoStat(rTableObj.GetGeoStat());
+ const double fShearX(-rGeoStat.mfTanShearAngle);
+ const double fRotate(rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0);
+ const basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(), fShearX, fRotate,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // created an invisible outline for the cases where no visible content exists
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ aObjectMatrix));
+
+ rVisitor.visit(xReference);
+ }
+ }
+
+ void ViewObjectContactOfTableObj::createPrimitive2DSequence(
+ DisplayInfo const& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ bool const isTaggedPDF(GetObjectContact().isExportTaggedPDF());
+ if (isTaggedPDF)
+ {
+ // this will be unbuffered and contain structure tags
+ const sdr::table::SdrTableObj& rTableObj =
+ static_cast<const sdr::table::SdrTableObj&>(*GetViewContact().TryToGetSdrObject());
+ return createPrimitive2DSequenceImpl(rTableObj, true, rVisitor);
+ }
+ else
+ {
+ // call it via the base class - this is supposed to be buffered
+ return sdr::contact::ViewObjectContactOfSdrObj::createPrimitive2DSequence(rDisplayInfo, rVisitor);
+ }
+ }
+
+ void ViewContactOfTableObj::createViewIndependentPrimitive2DSequence(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const sdr::table::SdrTableObj& rTableObj =
+ static_cast<const sdr::table::SdrTableObj&>(GetSdrObject());
+ return createPrimitive2DSequenceImpl(rTableObj, false, rVisitor);
+ }
+
+ ViewObjectContact& ViewContactOfTableObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+ {
+ return *new ViewObjectContactOfTableObj(rObjectContact, *this);
+ }
+
+ ViewContactOfTableObj::ViewContactOfTableObj(sdr::table::SdrTableObj& rTableObj)
+ : ViewContactOfSdrObj(rTableObj)
+ {
+ }
+
+ ViewContactOfTableObj::~ViewContactOfTableObj()
+ {
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/viewcontactoftableobj.hxx b/svx/source/table/viewcontactoftableobj.hxx
new file mode 100644
index 000000000..fbdd80538
--- /dev/null
+++ b/svx/source/table/viewcontactoftableobj.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_TABLE_VIEWCONTACTOFTABLEOBJ_HXX
+#define INCLUDED_SVX_SOURCE_TABLE_VIEWCONTACTOFTABLEOBJ_HXX
+
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+#include <svx/svdotable.hxx>
+
+namespace sdr::contact
+ {
+ class ViewContactOfTableObj : public ViewContactOfSdrObj
+ {
+ protected:
+ // This method is responsible for creating the graphical visualisation data derived ONLY from
+ // the model data
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
+
+ public:
+ // basic constructor, used from SdrObject.
+ explicit ViewContactOfTableObj(sdr::table::SdrTableObj& rTextObj);
+ virtual ~ViewContactOfTableObj() override;
+ };
+} // end of namespace sdr::contact
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/Palette.cxx b/svx/source/tbxctrls/Palette.cxx
new file mode 100644
index 000000000..84858c2eb
--- /dev/null
+++ b/svx/source/tbxctrls/Palette.cxx
@@ -0,0 +1,377 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/Palette.hxx>
+#include <tools/stream.hxx>
+
+#include <palettes.hxx>
+
+Palette::~Palette()
+{
+}
+
+PaletteASE::~PaletteASE()
+{
+}
+
+PaletteASE::PaletteASE( const OUString &rFPath, const OUString &rFName ) :
+ mbValidPalette( false ),
+ maFPath ( rFPath ),
+ maASEPaletteName ( rFName )
+{
+ LoadPalette();
+}
+
+void PaletteASE::LoadColorSet(SvxColorValueSet& rColorSet)
+{
+ rColorSet.Clear();
+ int nIx = 1;
+ for (const auto& rColor : maColors)
+ {
+ rColorSet.InsertItem(nIx, rColor.first, rColor.second);
+ ++nIx;
+ }
+}
+
+const OUString& PaletteASE::GetName()
+{
+ return maASEPaletteName;
+}
+
+const OUString& PaletteASE::GetPath()
+{
+ return maFPath;
+}
+
+bool PaletteASE::IsValid()
+{
+ return mbValidPalette;
+}
+
+// CMYK values from 0 to 1
+// TODO: Deduplicate me (taken from core/cui/source/dialogs/colorpicker.cxx)
+static void lcl_CMYKtoRGB( float fCyan, float fMagenta, float fYellow, float fKey, float& dR, float& dG, float& dB )
+{
+ fCyan = (fCyan * ( 1.0 - fKey )) + fKey;
+ fMagenta = (fMagenta * ( 1.0 - fKey )) + fKey;
+ fYellow = (fYellow * ( 1.0 - fKey )) + fKey;
+
+ dR = std::clamp( 1.0 - fCyan, 0.0, 1.0 );
+ dG = std::clamp( 1.0 - fMagenta, 0.0, 1.0 );
+ dB = std::clamp( 1.0 - fYellow, 0.0, 1.0 );
+}
+
+void PaletteASE::LoadPalette()
+{
+ SvFileStream aFile(maFPath, StreamMode::READ);
+ aFile.SetEndian(SvStreamEndian::BIG);
+
+ // Verify magic first 4 characters
+ char cMagic[5] = {0};
+ if ((aFile.ReadBytes(cMagic, 4) != 4) || (strncmp(cMagic, "ASEF", 4) != 0))
+ {
+ mbValidPalette = false;
+ return;
+ }
+
+ // Ignore the version number
+ aFile.SeekRel(4);
+
+ sal_uInt32 nBlocks = 0;
+ aFile.ReadUInt32(nBlocks);
+ for (sal_uInt32 nI = 0; nI < nBlocks; nI++) {
+ sal_uInt32 nChunkType = 0;
+ aFile.ReadUInt32(nChunkType);
+ // End chunk
+ if (nChunkType == 0)
+ break;
+
+ // Grab chunk size, name length
+ sal_uInt16 nChunkSize = 0;
+ sal_uInt16 nChars = 0;
+ aFile.ReadUInt16(nChunkSize);
+ aFile.ReadUInt16(nChars);
+
+ OUString aPaletteName("");
+ if (nChars > 1)
+ aPaletteName = read_uInt16s_ToOUString(aFile, nChars);
+ else
+ aFile.SeekRel(2);
+
+ if (nChunkType == 0xC0010000)
+ {
+ // Got a start chunk, so set palette name
+ maASEPaletteName = aPaletteName;
+ // Is there color data? (shouldn't happen in a start block, but check anyway)
+ if (nChunkSize > ((nChars * 2) + 2))
+ aPaletteName.clear();
+ else
+ continue;
+ }
+
+ char cColorModel[5] = {0};
+ aFile.ReadBytes(cColorModel, 4);
+ OString aColorModel(cColorModel);
+ // r, g, and b are floats ranging from 0 to 1
+ float r = 0, g = 0, b = 0;
+
+ if (aColorModel.equalsIgnoreAsciiCase("cmyk"))
+ {
+ float c = 0, m = 0, y = 0, k = 0;
+ aFile.ReadFloat(c);
+ aFile.ReadFloat(m);
+ aFile.ReadFloat(y);
+ aFile.ReadFloat(k);
+ lcl_CMYKtoRGB(c, m, y, k, r, g, b);
+ }
+ else if (aColorModel.equalsIgnoreAsciiCase("rgb "))
+ {
+ aFile.ReadFloat(r);
+ aFile.ReadFloat(g);
+ aFile.ReadFloat(b);
+ }
+ else if (aColorModel.equalsIgnoreAsciiCase("gray"))
+ {
+ float nVal = 0;
+ aFile.ReadFloat(nVal);
+ r = g = b = nVal;
+ }
+ else
+ {
+ float nL = 0, nA = 0, nB = 0;
+ aFile.ReadFloat(nL);
+ aFile.ReadFloat(nA);
+ aFile.ReadFloat(nB);
+ // TODO: How to convert LAB to RGB?
+ r = g = b = 0;
+ }
+
+ // Ignore color type
+ aFile.SeekRel(2);
+ maColors.emplace_back(Color(r * 255, g * 255, b * 255), aPaletteName);
+ }
+
+ mbValidPalette = true;
+}
+
+// PaletteGPL ------------------------------------------------------------------
+
+static OString lcl_getToken(OStringBuffer& rStr, sal_Int32& index);
+
+PaletteGPL::PaletteGPL( const OUString &rFPath, const OUString &rFName ) :
+ mbLoadedPalette( false ),
+ mbValidPalette( false ),
+ maFName( rFName ),
+ maFPath( rFPath )
+{
+ LoadPaletteHeader();
+}
+
+PaletteGPL::~PaletteGPL()
+{
+}
+
+const OUString& PaletteGPL::GetName()
+{
+ return maGPLPaletteName;
+}
+
+const OUString& PaletteGPL::GetPath()
+{
+ return maFPath;
+}
+
+void PaletteGPL::LoadColorSet(SvxColorValueSet& rColorSet)
+{
+ LoadPalette();
+
+ rColorSet.Clear();
+ int nIx = 1;
+ for (const auto& rColor : maColors)
+ {
+ rColorSet.InsertItem(nIx, rColor.first, rColor.second);
+ ++nIx;
+ }
+}
+
+bool PaletteGPL::IsValid()
+{
+ return mbValidPalette;
+}
+
+bool PaletteGPL::ReadPaletteHeader(SvFileStream& rFileStream)
+{
+ OString aLine;
+ OString aPaletteName;
+
+ rFileStream.ReadLine(aLine);
+ if( !aLine.startsWith("GIMP Palette") ) return false;
+ rFileStream.ReadLine(aLine);
+ if( aLine.startsWith("Name: ", &aPaletteName) )
+ {
+ maGPLPaletteName = OStringToOUString(aPaletteName, RTL_TEXTENCODING_ASCII_US);
+ rFileStream.ReadLine(aLine);
+ if( aLine.startsWith("Columns: "))
+ rFileStream.ReadLine(aLine); // we can ignore this
+ }
+ else
+ {
+ maGPLPaletteName = maFName;
+ }
+ return true;
+}
+
+void PaletteGPL::LoadPaletteHeader()
+{
+ SvFileStream aFile(maFPath, StreamMode::READ);
+ mbValidPalette = ReadPaletteHeader( aFile );
+}
+
+void PaletteGPL::LoadPalette()
+{
+ if( mbLoadedPalette ) return;
+ mbLoadedPalette = true;
+
+ // TODO add error handling!!!
+ SvFileStream aFile(maFPath, StreamMode::READ);
+ mbValidPalette = ReadPaletteHeader( aFile );
+
+ if( !mbValidPalette ) return;
+
+ OStringBuffer aLine;
+ do {
+ if (aLine[0] != '#' && aLine[0] != '\n')
+ {
+ // TODO check if r,g,b are 0<= x <=255, or just clamp?
+ sal_Int32 nIndex = 0;
+ OString token;
+
+ token = lcl_getToken(aLine, nIndex);
+ if(token.isEmpty() || nIndex == -1) continue;
+ sal_Int32 r = token.toInt32();
+
+ token = lcl_getToken(aLine, nIndex);
+ if(token.isEmpty() || nIndex == -1) continue;
+ sal_Int32 g = token.toInt32();
+
+ token = lcl_getToken(aLine, nIndex);
+ if(token.isEmpty()) continue;
+ sal_Int32 b = token.toInt32();
+
+ std::string_view name;
+ if(nIndex != -1)
+ name = std::string_view(aLine).substr(nIndex);
+
+ maColors.emplace_back(
+ Color(r, g, b),
+ OStringToOUString(name, RTL_TEXTENCODING_ASCII_US));
+ }
+ } while (aFile.ReadLine(aLine));
+}
+
+// finds first token in rStr from index, separated by whitespace
+// returns position of next token in index
+static OString lcl_getToken(OStringBuffer& rStr, sal_Int32& index)
+{
+ sal_Int32 substart, toklen = 0;
+ OUString aWhitespaceChars( " \n\t" );
+
+ while(index < rStr.getLength() &&
+ aWhitespaceChars.indexOf( rStr[index] ) != -1)
+ ++index;
+ if(index == rStr.getLength())
+ {
+ index = -1;
+ return OString();
+ }
+ substart = index;
+
+ //counts length of token
+ while(index < rStr.getLength() &&
+ aWhitespaceChars.indexOf( rStr[index] ) == -1 )
+ {
+ ++index;
+ ++toklen;
+ }
+
+ //counts to position of next token
+ while(index < rStr.getLength() &&
+ aWhitespaceChars.indexOf( rStr[index] ) != -1 )
+ ++index;
+ if(index == rStr.getLength())
+ index = -1;
+
+ return OString(std::string_view(rStr).substr(substart, toklen));
+}
+
+// PaletteSOC ------------------------------------------------------------------
+
+PaletteSOC::PaletteSOC( const OUString &rFPath, const OUString &rFName ) :
+ mbLoadedPalette( false ),
+ maFPath( rFPath ),
+ maSOCPaletteName( rFName )
+{
+}
+
+PaletteSOC::~PaletteSOC()
+{
+}
+
+const OUString& PaletteSOC::GetName()
+{
+ return maSOCPaletteName;
+}
+
+const OUString& PaletteSOC::GetPath()
+{
+ return maFPath;
+}
+
+void PaletteSOC::LoadColorSet(SvxColorValueSet& rColorSet)
+{
+ if( !mbLoadedPalette )
+ {
+ mbLoadedPalette = true;
+ mpColorList = XPropertyList::AsColorList(XPropertyList::CreatePropertyListFromURL(XPropertyListType::Color, maFPath));
+ (void)mpColorList->Load();
+ }
+ rColorSet.Clear();
+ if( mpColorList.is() )
+ rColorSet.addEntriesForXColorList( *mpColorList );
+}
+
+bool PaletteSOC::IsValid()
+{
+ return true;
+}
+
+namespace svx
+{
+NamedColor NamedThemedColor::ToNamedColor() const { return { m_aColor, m_aName }; }
+
+NamedThemedColor NamedThemedColor::FromNamedColor(const NamedColor& rNamedColor)
+{
+ NamedThemedColor aColor;
+ aColor.m_aColor = rNamedColor.first;
+ aColor.m_aName = rNamedColor.second;
+ return aColor;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/PaletteManager.cxx b/svx/source/tbxctrls/PaletteManager.cxx
new file mode 100644
index 000000000..55b2fdbd8
--- /dev/null
+++ b/svx/source/tbxctrls/PaletteManager.cxx
@@ -0,0 +1,442 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <svx/PaletteManager.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <tools/urlobj.hxx>
+#include <osl/file.hxx>
+#include <unotools/pathoptions.hxx>
+#include <sfx2/objsh.hxx>
+#include <svx/drawitem.hxx>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <svx/dialmgr.hxx>
+#include <tbxcolorupdate.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <comphelper/sequence.hxx>
+#include <stack>
+#include <set>
+#include <officecfg/Office/Common.hxx>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+
+#include <palettes.hxx>
+
+namespace
+{
+// Luminance modulation for the 6 effect presets.
+// 10000 is the default.
+sal_Int16 g_aLumMods[] = { 10000, 2000, 4000, 6000, 7500, 5000 };
+
+// Luminance offset for the 6 effect presets.
+// 0 is the default.
+sal_Int16 g_aLumOffs[] = { 0, 8000, 6000, 4000, 0, 0 };
+}
+
+PaletteManager::PaletteManager() :
+ mnMaxRecentColors(Application::GetSettings().GetStyleSettings().GetColorValueSetColumnCount()),
+ mnNumOfPalettes(3),
+ mnCurrentPalette(0),
+ mnColorCount(0),
+ mpBtnUpdater(nullptr),
+ maColorSelectFunction(PaletteManager::DispatchColorCommand)
+{
+ SfxObjectShell* pDocSh = SfxObjectShell::Current();
+ if(pDocSh)
+ {
+ const SfxPoolItem* pItem = nullptr;
+ if( nullptr != ( pItem = pDocSh->GetItem(SID_COLOR_TABLE) ) )
+ pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList();
+ }
+ if(!pColorList.is())
+ pColorList = XColorList::CreateStdColorList();
+ LoadPalettes();
+ mnNumOfPalettes += m_Palettes.size();
+
+}
+
+PaletteManager::~PaletteManager()
+{
+}
+
+void PaletteManager::LoadPalettes()
+{
+ m_Palettes.clear();
+ OUString aPalPaths = SvtPathOptions().GetPalettePath();
+
+ std::stack<OUString> aDirs;
+ sal_Int32 nIndex = 0;
+ do
+ {
+ aDirs.push(aPalPaths.getToken(0, ';', nIndex));
+ }
+ while (nIndex >= 0);
+
+ std::set<OUString> aNames;
+ //try all entries palette path list user first, then
+ //system, ignoring duplicate file names
+ while (!aDirs.empty())
+ {
+ OUString aPalPath = aDirs.top();
+ aDirs.pop();
+
+ osl::Directory aDir(aPalPath);
+ osl::DirectoryItem aDirItem;
+ osl::FileStatus aFileStat( osl_FileStatus_Mask_FileName |
+ osl_FileStatus_Mask_FileURL |
+ osl_FileStatus_Mask_Type );
+ if( aDir.open() == osl::FileBase::E_None )
+ {
+ while( aDir.getNextItem(aDirItem) == osl::FileBase::E_None )
+ {
+ aDirItem.getFileStatus(aFileStat);
+ if(aFileStat.isRegular() || aFileStat.isLink())
+ {
+ OUString aFName = aFileStat.getFileName();
+ INetURLObject aURLObj( aFileStat.getFileURL() );
+ OUString aFNameWithoutExt = aURLObj.GetBase();
+ if (aNames.find(aFName) == aNames.end())
+ {
+ std::unique_ptr<Palette> pPalette;
+ if( aFName.endsWithIgnoreAsciiCase(".gpl") )
+ pPalette.reset(new PaletteGPL(aFileStat.getFileURL(), aFNameWithoutExt));
+ else if( aFName.endsWithIgnoreAsciiCase(".soc") )
+ pPalette.reset(new PaletteSOC(aFileStat.getFileURL(), aFNameWithoutExt));
+ else if ( aFName.endsWithIgnoreAsciiCase(".ase") )
+ pPalette.reset(new PaletteASE(aFileStat.getFileURL(), aFNameWithoutExt));
+
+ if( pPalette && pPalette->IsValid() )
+ m_Palettes.push_back( std::move(pPalette) );
+ aNames.insert(aFNameWithoutExt);
+ }
+ }
+ }
+ }
+ }
+}
+
+bool PaletteManager::IsThemePaletteSelected() const
+{
+ return mnCurrentPalette == mnNumOfPalettes - 2;
+}
+
+void PaletteManager::GetThemeIndexLumModOff(sal_uInt16 nItemId, sal_Int16& rThemeIndex,
+ sal_Int16& rLumMod, sal_Int16& rLumOff)
+{
+ // Each column is the same color with different effects.
+ rThemeIndex = nItemId % 12;
+
+ // Each row is the same effect with different colors.
+ rLumMod = g_aLumMods[nItemId / 12];
+ rLumOff = g_aLumOffs[nItemId / 12];
+}
+
+void PaletteManager::ReloadColorSet(SvxColorValueSet &rColorSet)
+{
+ if( mnCurrentPalette == 0)
+ {
+ rColorSet.Clear();
+ css::uno::Sequence< sal_Int32 > CustomColorList( officecfg::Office::Common::UserColors::CustomColor::get() );
+ css::uno::Sequence< OUString > CustomColorNameList( officecfg::Office::Common::UserColors::CustomColorName::get() );
+ int nIx = 1;
+ for (int i = 0; i < CustomColorList.getLength(); ++i)
+ {
+ Color aColor(ColorTransparency, CustomColorList[i]);
+ rColorSet.InsertItem(nIx, aColor, CustomColorNameList[i]);
+ ++nIx;
+ }
+ }
+ else if (IsThemePaletteSelected())
+ {
+ SfxObjectShell* pObjectShell = SfxObjectShell::Current();
+ if (pObjectShell)
+ {
+ std::vector<Color> aColors = pObjectShell->GetThemeColors();
+ mnColorCount = aColors.size();
+ rColorSet.Clear();
+ if (aColors.size() >= 12)
+ {
+ std::vector<OUString> aEffectNames = {
+ SvxResId(RID_SVXSTR_THEME_EFFECT1), SvxResId(RID_SVXSTR_THEME_EFFECT2),
+ SvxResId(RID_SVXSTR_THEME_EFFECT3), SvxResId(RID_SVXSTR_THEME_EFFECT4),
+ SvxResId(RID_SVXSTR_THEME_EFFECT5),
+ };
+
+ std::vector<OUString> aColorNames = {
+ SvxResId(RID_SVXSTR_THEME_COLOR1), SvxResId(RID_SVXSTR_THEME_COLOR2),
+ SvxResId(RID_SVXSTR_THEME_COLOR3), SvxResId(RID_SVXSTR_THEME_COLOR4),
+ SvxResId(RID_SVXSTR_THEME_COLOR5), SvxResId(RID_SVXSTR_THEME_COLOR6),
+ SvxResId(RID_SVXSTR_THEME_COLOR7), SvxResId(RID_SVXSTR_THEME_COLOR8),
+ SvxResId(RID_SVXSTR_THEME_COLOR9), SvxResId(RID_SVXSTR_THEME_COLOR10),
+ SvxResId(RID_SVXSTR_THEME_COLOR11), SvxResId(RID_SVXSTR_THEME_COLOR12),
+ };
+
+ sal_uInt16 nItemId = 0;
+ // Each row is one effect type (no effect + each type).
+ for (size_t nEffect = 0; nEffect < aEffectNames.size() + 1; ++nEffect)
+ {
+ // Each column is one color type.
+ for (size_t nColor = 0; nColor < aColorNames.size(); ++nColor)
+ {
+ Color aColor = aColors[nColor];
+ aColor.ApplyLumModOff(g_aLumMods[nEffect], g_aLumOffs[nEffect]);
+ OUString aColorName;
+ if (nEffect == 0)
+ {
+ aColorName = aColorNames[nColor];
+ }
+ else
+ {
+ aColorName = aEffectNames[nEffect - 1].replaceAll("%1", aColorNames[nColor]);
+ }
+ rColorSet.InsertItem(nItemId++, aColor, aColorName);
+ }
+ }
+ }
+ }
+ }
+ else if( mnCurrentPalette == mnNumOfPalettes - 1 )
+ {
+ // Add doc colors to palette
+ SfxObjectShell* pDocSh = SfxObjectShell::Current();
+ if (pDocSh)
+ {
+ std::set<Color> aColors = pDocSh->GetDocColors();
+ mnColorCount = aColors.size();
+ rColorSet.Clear();
+ rColorSet.addEntriesForColorSet(aColors, SvxResId( RID_SVXSTR_DOC_COLOR_PREFIX ) + " " );
+ }
+ }
+ else
+ {
+ m_Palettes[mnCurrentPalette - 1]->LoadColorSet( rColorSet );
+ mnColorCount = rColorSet.GetItemCount();
+ }
+}
+
+void PaletteManager::ReloadRecentColorSet(SvxColorValueSet& rColorSet)
+{
+ maRecentColors.clear();
+ rColorSet.Clear();
+ css::uno::Sequence< sal_Int32 > Colorlist(officecfg::Office::Common::UserColors::RecentColor::get());
+ css::uno::Sequence< OUString > ColorNamelist(officecfg::Office::Common::UserColors::RecentColorName::get());
+ int nIx = 1;
+ const bool bHasColorNames = Colorlist.getLength() == ColorNamelist.getLength();
+ for (int i = 0; i < Colorlist.getLength(); ++i)
+ {
+ Color aColor(ColorTransparency, Colorlist[i]);
+ OUString sColorName = bHasColorNames ? ColorNamelist[i] : ("#" + aColor.AsRGBHexString().toAsciiUpperCase());
+ maRecentColors.emplace_back(aColor, sColorName);
+ rColorSet.InsertItem(nIx, aColor, sColorName);
+ ++nIx;
+ }
+}
+
+std::vector<OUString> PaletteManager::GetPaletteList()
+{
+ std::vector<OUString> aPaletteNames
+ {
+ SvxResId( RID_SVXSTR_CUSTOM_PAL )
+ };
+ for (auto const& it : m_Palettes)
+ {
+ aPaletteNames.push_back( (*it).GetName() );
+ }
+ aPaletteNames.push_back(SvxResId(RID_SVXSTR_THEME_COLORS));
+ aPaletteNames.push_back( SvxResId ( RID_SVXSTR_DOC_COLORS ) );
+
+ return aPaletteNames;
+}
+
+void PaletteManager::SetPalette( sal_Int32 nPos )
+{
+ mnCurrentPalette = nPos;
+ if( nPos != mnNumOfPalettes - 1 && nPos != 0)
+ {
+ pColorList = XPropertyList::AsColorList(
+ XPropertyList::CreatePropertyListFromURL(
+ XPropertyListType::Color, GetSelectedPalettePath()));
+ auto name = GetPaletteName(); // may change pColorList
+ pColorList->SetName(name);
+ if(pColorList->Load())
+ {
+ SfxObjectShell* pShell = SfxObjectShell::Current();
+ if (pShell != nullptr)
+ {
+ SvxColorListItem aColorItem(pColorList, SID_COLOR_TABLE);
+ pShell->PutItem( aColorItem );
+ }
+ }
+ }
+ OUString aPaletteName(officecfg::Office::Common::UserColors::PaletteName::get());
+ if (aPaletteName != GetPaletteName())
+ {
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::UserColors::PaletteName::set(GetPaletteName(), batch);
+ batch->commit();
+ }
+}
+
+sal_Int32 PaletteManager::GetPalette() const
+{
+ return mnCurrentPalette;
+}
+
+OUString PaletteManager::GetPaletteName()
+{
+ std::vector<OUString> aNames(GetPaletteList());
+ if(mnCurrentPalette != mnNumOfPalettes - 1 && mnCurrentPalette != 0)
+ {
+ SfxObjectShell* pDocSh = SfxObjectShell::Current();
+ if(pDocSh)
+ {
+ const SfxPoolItem* pItem = nullptr;
+ if( nullptr != ( pItem = pDocSh->GetItem(SID_COLOR_TABLE) ) )
+ pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList();
+ }
+ }
+ return aNames[mnCurrentPalette];
+}
+
+OUString PaletteManager::GetSelectedPalettePath()
+{
+ if (mnCurrentPalette < m_Palettes.size() && mnCurrentPalette != 0)
+ return m_Palettes[mnCurrentPalette - 1]->GetPath();
+ else
+ return OUString();
+}
+
+tools::Long PaletteManager::GetColorCount() const
+{
+ return mnColorCount;
+}
+
+tools::Long PaletteManager::GetRecentColorCount() const
+{
+ return maRecentColors.size();
+}
+
+void PaletteManager::AddRecentColor(const Color& rRecentColor, const OUString& rName, bool bFront)
+{
+ auto itColor = std::find_if(maRecentColors.begin(),
+ maRecentColors.end(),
+ [rRecentColor] (const NamedColor &a) { return a.first == rRecentColor; });
+ // if recent color to be added is already in list, remove it
+ if( itColor != maRecentColors.end() )
+ maRecentColors.erase( itColor );
+
+ if (maRecentColors.size() == mnMaxRecentColors)
+ maRecentColors.pop_back();
+ if (bFront)
+ maRecentColors.push_front(std::make_pair(rRecentColor, rName));
+ else
+ maRecentColors.emplace_back(rRecentColor, rName);
+ css::uno::Sequence< sal_Int32 > aColorList(maRecentColors.size());
+ auto aColorListRange = asNonConstRange(aColorList);
+ css::uno::Sequence< OUString > aColorNameList(maRecentColors.size());
+ auto aColorNameListRange = asNonConstRange(aColorNameList);
+ for (size_t i = 0; i < maRecentColors.size(); ++i)
+ {
+ aColorListRange[i] = static_cast<sal_Int32>(maRecentColors[i].first);
+ aColorNameListRange[i] = maRecentColors[i].second;
+ }
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::UserColors::RecentColor::set(aColorList, batch);
+ officecfg::Office::Common::UserColors::RecentColorName::set(aColorNameList, batch);
+ batch->commit();
+}
+
+void PaletteManager::SetBtnUpdater(svx::ToolboxButtonColorUpdaterBase* pBtnUpdater)
+{
+ mpBtnUpdater = pBtnUpdater;
+}
+
+void PaletteManager::SetColorSelectFunction(const ColorSelectFunction& aColorSelectFunction)
+{
+ maColorSelectFunction = aColorSelectFunction;
+}
+
+void PaletteManager::PopupColorPicker(weld::Window* pParent, const OUString& aCommand, const Color& rInitialColor)
+{
+ // The calling object goes away during aColorDlg.Execute(), so we must copy this
+ OUString aCommandCopy = aCommand;
+ m_pColorDlg = std::make_unique<SvColorDialog>();
+ m_pColorDlg->SetColor(rInitialColor);
+ m_pColorDlg->SetMode(svtools::ColorPickerMode::Modify);
+ m_pColorDlg->ExecuteAsync(pParent, [this, aCommandCopy] (sal_Int32 nResult) {
+ if (nResult == RET_OK)
+ {
+ Color aLastColor = m_pColorDlg->GetColor();
+ OUString sColorName = "#" + aLastColor.AsRGBHexString().toAsciiUpperCase();
+ NamedColor aNamedColor = std::make_pair(aLastColor, sColorName);
+ if (mpBtnUpdater)
+ mpBtnUpdater->Update(aNamedColor);
+ AddRecentColor(aLastColor, sColorName);
+ maColorSelectFunction(aCommandCopy, svx::NamedThemedColor::FromNamedColor(aNamedColor));
+ }
+ });
+}
+
+void PaletteManager::DispatchColorCommand(const OUString& aCommand, const svx::NamedThemedColor& rColor)
+{
+ using namespace css::uno;
+ using namespace css::frame;
+ using namespace css::beans;
+ using namespace css::util;
+
+ Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
+ Reference<XDesktop2> xDesktop = Desktop::create(xContext);
+ Reference<XFrame> xFrame(xDesktop->getCurrentFrame());
+ Reference<XDispatchProvider> xDispatchProvider(xFrame, UNO_QUERY);
+ if (!xDispatchProvider.is())
+ return;
+
+ INetURLObject aObj( aCommand );
+
+ std::vector<PropertyValue> aArgs{
+ comphelper::makePropertyValue(aObj.GetURLPath(), sal_Int32(rColor.m_aColor)),
+ };
+ if (rColor.m_nThemeIndex != -1)
+ {
+ aArgs.push_back(comphelper::makePropertyValue("ColorThemeIndex", rColor.m_nThemeIndex));
+ aArgs.push_back(comphelper::makePropertyValue("ColorLumMod", rColor.m_nLumMod));
+ aArgs.push_back(comphelper::makePropertyValue("ColorLumOff", rColor.m_nLumOff));
+ }
+
+ URL aTargetURL;
+ aTargetURL.Complete = aCommand;
+ Reference<XURLTransformer> xURLTransformer(URLTransformer::create(comphelper::getProcessComponentContext()));
+ xURLTransformer->parseStrict(aTargetURL);
+
+ Reference<XDispatch> xDispatch = xDispatchProvider->queryDispatch(aTargetURL, OUString(), 0);
+ if (xDispatch.is())
+ {
+ xDispatch->dispatch(aTargetURL, comphelper::containerToSequence(aArgs));
+ if (xFrame->getContainerWindow().is())
+ xFrame->getContainerWindow()->setFocus();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx b/svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx
new file mode 100644
index 000000000..64e6ed782
--- /dev/null
+++ b/svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <StylesPreviewToolBoxControl.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <vcl/svapp.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+StylesPreviewToolBoxControl::StylesPreviewToolBoxControl() {}
+
+StylesPreviewToolBoxControl::~StylesPreviewToolBoxControl() {}
+
+void SAL_CALL
+StylesPreviewToolBoxControl::initialize(const css::uno::Sequence<css::uno::Any>& rArguments)
+{
+ svt::ToolboxController::initialize(rArguments);
+
+ if (m_xFrame.is())
+ {
+ InitializeStyles(m_xFrame->getController()->getModel());
+
+ m_xDispatchProvider = css::uno::Reference<css::frame::XDispatchProvider>(
+ m_xFrame->getController(), css::uno::UNO_QUERY);
+ }
+}
+
+void SAL_CALL StylesPreviewToolBoxControl::dispose()
+{
+ svt::ToolboxController::dispose();
+
+ SolarMutexGuard aSolarMutexGuard;
+ m_xVclBox.disposeAndClear();
+ m_xWeldBox.reset();
+}
+
+void StylesPreviewToolBoxControl::InitializeStyles(
+ const css::uno::Reference<css::frame::XModel>& xModel)
+{
+ m_aDefaultStyles.clear();
+
+ //now convert the default style names to the localized names
+ try
+ {
+ css::uno::Reference<css::style::XStyleFamiliesSupplier> xStylesSupplier(
+ xModel, css::uno::UNO_QUERY_THROW);
+ css::uno::Reference<css::lang::XServiceInfo> xServices(xModel, css::uno::UNO_QUERY_THROW);
+ if (xServices->supportsService("com.sun.star.text.TextDocument"))
+ {
+ css::uno::Reference<css::container::XNameAccess> xParaStyles;
+ xStylesSupplier->getStyleFamilies()->getByName("ParagraphStyles") >>= xParaStyles;
+ static const std::vector<OUString> aWriterStyles
+ = { "Standard", "Text body", "Heading 1", "Heading 2", "Heading 3",
+ "Heading 4", "Title", "Subtitle", "Quotations", "Preformatted Text" };
+ for (const OUString& aStyle : aWriterStyles)
+ {
+ try
+ {
+ css::uno::Reference<css::beans::XPropertySet> xStyle;
+ xParaStyles->getByName(aStyle) >>= xStyle;
+ OUString sName;
+ xStyle->getPropertyValue("DisplayName") >>= sName;
+ if (!sName.isEmpty())
+ m_aDefaultStyles.push_back(std::pair<OUString, OUString>(aStyle, sName));
+ }
+ catch (const css::container::NoSuchElementException&)
+ {
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+ }
+ }
+ else if (xServices->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
+ {
+ static const char* aCalcStyles[] = { "Default", "Accent 1", "Accent 2", "Accent 3",
+ "Heading 1", "Heading 2", "Result" };
+ css::uno::Reference<css::container::XNameAccess> xCellStyles;
+ xStylesSupplier->getStyleFamilies()->getByName("CellStyles") >>= xCellStyles;
+ for (const char* pCalcStyle : aCalcStyles)
+ {
+ try
+ {
+ const OUString sStyleName(OUString::createFromAscii(pCalcStyle));
+ if (xCellStyles->hasByName(sStyleName))
+ {
+ css::uno::Reference<css::beans::XPropertySet> xStyle(
+ xCellStyles->getByName(sStyleName), css::uno::UNO_QUERY_THROW);
+ OUString sName;
+ xStyle->getPropertyValue("DisplayName") >>= sName;
+ if (!sName.isEmpty())
+ {
+ m_aDefaultStyles.push_back(
+ std::pair<OUString, OUString>(sStyleName, sName));
+ }
+ }
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ catch (const css::uno::Exception&)
+ {
+ OSL_FAIL("error while initializing style names");
+ }
+}
+
+void SAL_CALL StylesPreviewToolBoxControl::update() {}
+
+void StylesPreviewToolBoxControl::statusChanged(const css::frame::FeatureStateEvent& /*rEvent*/) {}
+
+css::uno::Reference<css::awt::XWindow>
+StylesPreviewToolBoxControl::createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ css::uno::Reference<css::awt::XWindow> xItemWindow;
+
+ /* TODO
+ if (m_pBuilder)
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ std::unique_ptr<weld::Container> xWidget(*m_pBuilder);
+
+ xItemWindow
+ = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get()));
+
+ m_xWeldBox.reset(new StylesPreviewWindow_Base(std::move(xWidget)));
+ m_pBox = m_xWeldBox.get();
+ }
+ else
+ */
+ {
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent);
+ if (pParent)
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ m_xVclBox = VclPtr<StylesPreviewWindow_Impl>::Create(
+ pParent, std::vector(m_aDefaultStyles), m_xDispatchProvider);
+ xItemWindow = VCLUnoHelper::GetInterface(m_xVclBox);
+ }
+ }
+
+ return xItemWindow;
+}
+
+OUString StylesPreviewToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.StylesPreviewToolBoxControl";
+}
+
+sal_Bool StylesPreviewToolBoxControl::supportsService(const OUString& rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+css::uno::Sequence<OUString> StylesPreviewToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_StylesPreviewToolBoxControl_get_implementation(
+ css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new StylesPreviewToolBoxControl());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/tbxctrls/StylesPreviewWindow.cxx b/svx/source/tbxctrls/StylesPreviewWindow.cxx
new file mode 100644
index 000000000..e786c7b60
--- /dev/null
+++ b/svx/source/tbxctrls/StylesPreviewWindow.cxx
@@ -0,0 +1,520 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <StylesPreviewWindow.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/itemset.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/tplpitem.hxx>
+#include <sfx2/viewsh.hxx>
+#include <vcl/glyphitemcache.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/settings.hxx>
+
+#include <editeng/editids.hrc>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/svxfont.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/cmapitem.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <editeng/brushitem.hxx>
+
+#include <i18nlangtag/mslangid.hxx>
+
+#include <svx/xfillit0.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xflclit.hxx>
+
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <vcl/commandevent.hxx>
+
+StyleStatusListener::StyleStatusListener(
+ StylesPreviewWindow_Base* pPreviewControl,
+ const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider)
+ : SfxStatusListener(xDispatchProvider, SID_STYLE_FAMILY2, ".uno:ParaStyle")
+ , m_pPreviewControl(pPreviewControl)
+{
+ ReBind();
+}
+
+void StyleStatusListener::StateChangedAtStatusListener(SfxItemState /*eState*/,
+ const SfxPoolItem* pState)
+{
+ const SfxTemplateItem* pStateItem = dynamic_cast<const SfxTemplateItem*>(pState);
+ if (pStateItem)
+ {
+ if (pStateItem->GetStyleIdentifier().isEmpty())
+ m_pPreviewControl->Select(pStateItem->GetStyleName());
+ else
+ m_pPreviewControl->Select(pStateItem->GetStyleIdentifier());
+ }
+}
+
+StylePoolChangeListener::StylePoolChangeListener(StylesPreviewWindow_Base* pPreviewControl)
+ : m_pPreviewControl(pPreviewControl)
+{
+ SfxObjectShell* pDocShell = SfxObjectShell::Current();
+
+ m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
+
+ if (m_pStyleSheetPool)
+ {
+ StartListening(*m_pStyleSheetPool);
+ }
+}
+
+StylePoolChangeListener::~StylePoolChangeListener()
+{
+ if (m_pStyleSheetPool)
+ EndListening(*m_pStyleSheetPool);
+}
+
+void StylePoolChangeListener::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& /*rHint*/)
+{
+ m_pPreviewControl->RequestStylesListUpdate();
+}
+
+StyleItemController::StyleItemController(const std::pair<OUString, OUString>& aStyleName)
+ : m_eStyleFamily(SfxStyleFamily::Para)
+ , m_aStyleName(aStyleName)
+{
+}
+
+void StyleItemController::Paint(vcl::RenderContext& rRenderContext)
+{
+ rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT
+ | vcl::PushFlags::TEXTCOLOR);
+
+ DrawEntry(rRenderContext);
+
+ rRenderContext.Pop();
+}
+
+bool StylesPreviewWindow_Base::Command(const CommandEvent& rEvent)
+{
+ if (rEvent.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ std::unique_ptr<weld::Builder> xBuilder(
+ Application::CreateBuilder(m_xStylesView.get(), "svx/ui/stylemenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+ OString rIdent = xMenu->popup_at_rect(m_xStylesView.get(),
+ tools::Rectangle(rEvent.GetMousePosPixel(), Size(1, 1)));
+ if (rIdent == "update" || rIdent == "edit")
+ {
+ css::uno::Sequence<css::beans::PropertyValue> aArgs(0);
+
+ SfxToolBoxControl::Dispatch(m_xDispatchProvider,
+ rIdent == "update" ? OUString(".uno:StyleUpdateByExample")
+ : OUString(".uno:EditStyle"),
+ aArgs);
+
+ return true;
+ }
+
+ return false;
+}
+
+static Color GetTextColorFromItemSet(std::optional<SfxItemSet> const& pItemSet)
+{
+ const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_CHAR_COLOR);
+ if (pItem)
+ return static_cast<const SvxColorItem*>(pItem)->GetValue();
+
+ return COL_AUTO;
+}
+
+static Color GetHighlightColorFromItemSet(std::optional<SfxItemSet> const& pItemSet)
+{
+ const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_BRUSH_CHAR);
+ if (pItem)
+ return static_cast<const SvxBrushItem*>(pItem)->GetColor();
+
+ return COL_AUTO;
+}
+
+static Color GetBackgroundColorFromItemSet(std::optional<SfxItemSet> const& pItemSet)
+{
+ const SfxPoolItem* pItem = pItemSet->GetItem(XATTR_FILLCOLOR);
+ if (pItem)
+ return static_cast<const XFillColorItem*>(pItem)->GetColorValue();
+
+ return COL_AUTO;
+}
+
+static css::drawing::FillStyle GetFillStyleFromItemSet(std::optional<SfxItemSet> const& pItemSet)
+{
+ const SfxPoolItem* pItem = pItemSet->GetItem(XATTR_FILLSTYLE);
+ if (pItem)
+ return static_cast<const XFillStyleItem*>(pItem)->GetValue();
+
+ return css::drawing::FillStyle_NONE;
+}
+
+static SvxFont GetFontFromItems(const SvxFontItem* pFontItem, Size aPixelFontSize,
+ std::optional<SfxItemSet> const& pItemSet)
+{
+ SvxFont aFont;
+
+ aFont.SetFamilyName(pFontItem->GetFamilyName());
+ aFont.SetStyleName(pFontItem->GetStyleName());
+ aFont.SetFontSize(aPixelFontSize);
+
+ const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_CHAR_WEIGHT);
+ if (pItem)
+ aFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight());
+
+ pItem = pItemSet->GetItem(SID_ATTR_CHAR_POSTURE);
+ if (pItem)
+ aFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture());
+
+ pItem = pItemSet->GetItem(SID_ATTR_CHAR_CONTOUR);
+ if (pItem)
+ aFont.SetOutline(static_cast<const SvxContourItem*>(pItem)->GetValue());
+
+ pItem = pItemSet->GetItem(SID_ATTR_CHAR_SHADOWED);
+ if (pItem)
+ aFont.SetShadow(static_cast<const SvxShadowedItem*>(pItem)->GetValue());
+
+ pItem = pItemSet->GetItem(SID_ATTR_CHAR_RELIEF);
+ if (pItem)
+ aFont.SetRelief(static_cast<const SvxCharReliefItem*>(pItem)->GetValue());
+
+ pItem = pItemSet->GetItem(SID_ATTR_CHAR_UNDERLINE);
+ if (pItem)
+ aFont.SetUnderline(static_cast<const SvxUnderlineItem*>(pItem)->GetLineStyle());
+
+ pItem = pItemSet->GetItem(SID_ATTR_CHAR_OVERLINE);
+ if (pItem)
+ aFont.SetOverline(static_cast<const SvxOverlineItem*>(pItem)->GetValue());
+
+ pItem = pItemSet->GetItem(SID_ATTR_CHAR_STRIKEOUT);
+ if (pItem)
+ aFont.SetStrikeout(static_cast<const SvxCrossedOutItem*>(pItem)->GetStrikeout());
+
+ pItem = pItemSet->GetItem(SID_ATTR_CHAR_CASEMAP);
+ if (pItem)
+ aFont.SetCaseMap(static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap());
+
+ pItem = pItemSet->GetItem(SID_ATTR_CHAR_EMPHASISMARK);
+ if (pItem)
+ aFont.SetEmphasisMark(static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark());
+
+ return aFont;
+}
+
+void StyleItemController::DrawEntry(vcl::RenderContext& rRenderContext)
+{
+ SfxObjectShell* pShell = SfxObjectShell::Current();
+ if (!pShell)
+ return;
+
+ SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyle = nullptr;
+
+ if (!pPool)
+ return;
+
+ pStyle = pPool->First(m_eStyleFamily);
+ while (pStyle && pStyle->GetName() != m_aStyleName.first
+ && pStyle->GetName() != m_aStyleName.second)
+ pStyle = pPool->Next();
+
+ if (!pStyle)
+ return;
+
+ Size aSize(rRenderContext.GetOutputSizePixel());
+ tools::Rectangle aFullRect(Point(0, 0), aSize);
+ tools::Rectangle aContentRect(aFullRect);
+
+ Color aOriginalColor = rRenderContext.GetFillColor();
+ Color aOriginalLineColor = rRenderContext.GetLineColor();
+
+ DrawContentBackground(rRenderContext, aContentRect, aOriginalColor);
+
+ std::optional<SfxItemSet> const pItemSet(pStyle->GetItemSetForPreview());
+ if (!pItemSet)
+ return;
+
+ Color aFontHighlight = COL_AUTO;
+
+ sal_Int16 nScriptType
+ = MsLangId::getScriptType(Application::GetSettings().GetUILanguageTag().getLanguageType());
+
+ sal_uInt16 nFontSlot = SID_ATTR_CHAR_FONT;
+ if (nScriptType == css::i18n::ScriptType::ASIAN)
+ nFontSlot = SID_ATTR_CHAR_CJK_FONT;
+ else if (nScriptType == css::i18n::ScriptType::COMPLEX)
+ nFontSlot = SID_ATTR_CHAR_CTL_FONT;
+
+ const SvxFontItem* const pFontItem = pItemSet->GetItem<SvxFontItem>(nFontSlot);
+ const SvxFontHeightItem* const pFontHeightItem
+ = pItemSet->GetItem<SvxFontHeightItem>(SID_ATTR_CHAR_FONTHEIGHT);
+
+ if (pFontItem && pFontHeightItem)
+ {
+ Size aFontSize(0, pFontHeightItem->GetHeight());
+ Size aPixelSize(rRenderContext.LogicToPixel(aFontSize, MapMode(pShell->GetMapUnit())));
+
+ SvxFont aFont = GetFontFromItems(pFontItem, aPixelSize, pItemSet);
+ rRenderContext.SetFont(aFont);
+
+ Color aFontCol = GetTextColorFromItemSet(pItemSet);
+ if (aFontCol != COL_AUTO)
+ rRenderContext.SetTextColor(aFontCol);
+
+ aFontHighlight = GetHighlightColorFromItemSet(pItemSet);
+
+ css::drawing::FillStyle style = GetFillStyleFromItemSet(pItemSet);
+
+ switch (style)
+ {
+ case css::drawing::FillStyle_SOLID:
+ {
+ Color aBackCol = GetBackgroundColorFromItemSet(pItemSet);
+ if (aBackCol != COL_AUTO)
+ DrawContentBackground(rRenderContext, aContentRect, aBackCol);
+ }
+ break;
+
+ default:
+ break;
+ //TODO Draw the other background styles: gradient, hatching and bitmap
+ }
+ }
+
+ if (aFontHighlight != COL_AUTO)
+ DrawHighlight(rRenderContext, aFontHighlight);
+
+ DrawText(rRenderContext);
+
+ rRenderContext.SetFillColor(aOriginalColor);
+ rRenderContext.SetLineColor(aOriginalLineColor);
+}
+
+void StyleItemController::DrawContentBackground(vcl::RenderContext& rRenderContext,
+ const tools::Rectangle& aContentRect,
+ const Color& aColor)
+{
+ rRenderContext.SetLineColor(aColor);
+ rRenderContext.SetFillColor(aColor);
+ rRenderContext.DrawRect(aContentRect);
+}
+
+void StyleItemController::DrawHighlight(vcl::RenderContext& rRenderContext, Color aFontBack)
+{
+ tools::Rectangle aTextRect;
+ rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second);
+
+ Size aSize = aTextRect.GetSize();
+ aSize.AdjustHeight(aSize.getHeight());
+ aTextRect.SetSize(aSize);
+
+ Point aPos(0, 0);
+ aPos.AdjustX(LEFT_MARGIN);
+ aPos.AdjustY((rRenderContext.GetOutputHeightPixel() - aTextRect.Bottom()) / 2);
+ aTextRect.SetPos(aPos);
+
+ rRenderContext.SetLineColor(aFontBack);
+ rRenderContext.SetFillColor(aFontBack);
+
+ rRenderContext.DrawRect(aTextRect);
+}
+
+void StyleItemController::DrawText(vcl::RenderContext& rRenderContext)
+{
+ const SalLayoutGlyphs* layoutGlyphs
+ = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(&rRenderContext, m_aStyleName.second);
+ tools::Rectangle aTextRect;
+ rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second, 0, 0, -1, 0, {}, layoutGlyphs);
+
+ Point aPos(0, 0);
+ aPos.AdjustX(LEFT_MARGIN);
+ aPos.AdjustY((rRenderContext.GetOutputHeightPixel() - aTextRect.Bottom()) / 2);
+
+ rRenderContext.DrawText(aPos, m_aStyleName.second, 0, -1, nullptr, nullptr, layoutGlyphs);
+}
+
+StylesPreviewWindow_Base::StylesPreviewWindow_Base(
+ weld::Builder& xBuilder, std::vector<std::pair<OUString, OUString>>&& aDefaultStyles,
+ const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider)
+ : m_xDispatchProvider(xDispatchProvider)
+ , m_xStylesView(xBuilder.weld_icon_view("stylesview"))
+ , m_aUpdateTask(*this)
+ , m_aDefaultStyles(std::move(aDefaultStyles))
+{
+ m_xStylesView->connect_selection_changed(LINK(this, StylesPreviewWindow_Base, Selected));
+ m_xStylesView->connect_item_activated(LINK(this, StylesPreviewWindow_Base, DoubleClick));
+ m_xStylesView->connect_command(LINK(this, StylesPreviewWindow_Base, DoCommand));
+
+ m_xStatusListener = new StyleStatusListener(this, xDispatchProvider);
+
+ m_pStylePoolChangeListener.reset(new StylePoolChangeListener(this));
+
+ RequestStylesListUpdate();
+}
+
+IMPL_LINK(StylesPreviewWindow_Base, Selected, weld::IconView&, rIconView, void)
+{
+ OUString sStyleName = rIconView.get_selected_text();
+
+ css::uno::Sequence<css::beans::PropertyValue> aArgs{
+ comphelper::makePropertyValue("Template", sStyleName),
+ comphelper::makePropertyValue("Family", sal_Int16(SfxStyleFamily::Para))
+ };
+ SfxToolBoxControl::Dispatch(m_xDispatchProvider, ".uno:StyleApply", aArgs);
+}
+
+IMPL_LINK(StylesPreviewWindow_Base, DoubleClick, weld::IconView&, rIconView, bool)
+{
+ OUString sStyleName = rIconView.get_selected_text();
+
+ css::uno::Sequence<css::beans::PropertyValue> aArgs{
+ comphelper::makePropertyValue("Param", sStyleName),
+ comphelper::makePropertyValue("Family", sal_Int16(SfxStyleFamily::Para))
+ };
+ SfxToolBoxControl::Dispatch(m_xDispatchProvider, ".uno:EditStyle", aArgs);
+
+ return true;
+}
+
+IMPL_LINK(StylesPreviewWindow_Base, DoCommand, const CommandEvent&, rPos, bool)
+{
+ return Command(rPos);
+}
+
+StylesPreviewWindow_Base::~StylesPreviewWindow_Base()
+{
+ m_xStatusListener->UnBind();
+
+ m_aUpdateTask.Stop();
+
+ try
+ {
+ m_xStatusListener->dispose();
+ }
+ catch (css::uno::Exception&)
+ {
+ }
+
+ m_xStatusListener = nullptr;
+}
+
+void StylesPreviewWindow_Base::Select(const OUString& rStyleName)
+{
+ m_sSelectedStyle = rStyleName;
+
+ UpdateSelection();
+}
+
+void StylesPreviewWindow_Base::UpdateSelection()
+{
+ for (std::vector<std::pair<OUString, OUString>>::size_type i = 0; i < m_aAllStyles.size(); ++i)
+ {
+ if (m_aAllStyles[i].first == m_sSelectedStyle || m_aAllStyles[i].second == m_sSelectedStyle)
+ {
+ m_xStylesView->select(i);
+ break;
+ }
+ }
+}
+
+void StylesPreviewWindow_Base::RequestStylesListUpdate() { m_aUpdateTask.Start(); }
+
+void StylesListUpdateTask::Invoke()
+{
+ m_rStylesList.UpdateStylesList();
+ m_rStylesList.UpdateSelection();
+}
+
+void StylesPreviewWindow_Base::UpdateStylesList()
+{
+ m_aAllStyles = m_aDefaultStyles;
+
+ SfxObjectShell* pDocShell = SfxObjectShell::Current();
+ SfxStyleSheetBasePool* pStyleSheetPool = nullptr;
+
+ if (pDocShell)
+ pStyleSheetPool = pDocShell->GetStyleSheetPool();
+
+ if (pStyleSheetPool)
+ {
+ auto xIter = pStyleSheetPool->CreateIterator(SfxStyleFamily::Para,
+ SfxStyleSearchBits::UserDefined);
+
+ SfxStyleSheetBase* pStyle = xIter->First();
+
+ while (pStyle)
+ {
+ m_aAllStyles.push_back(std::pair<OUString, OUString>("", pStyle->GetName()));
+ pStyle = xIter->Next();
+ }
+ }
+
+ m_xStylesView->clear();
+ for (const auto& rStyle : m_aAllStyles)
+ {
+ ScopedVclPtr<VirtualDevice> pImg = VclPtr<VirtualDevice>::Create();
+ const Size aSize(100, 30);
+ pImg->SetOutputSizePixel(aSize);
+
+ StyleItemController aStyleController(rStyle);
+ aStyleController.Paint(*pImg);
+
+ m_xStylesView->append(rStyle.first, rStyle.second, pImg);
+ }
+}
+
+StylesPreviewWindow_Impl::StylesPreviewWindow_Impl(
+ vcl::Window* pParent, std::vector<std::pair<OUString, OUString>>&& aDefaultStyles,
+ const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider)
+ : InterimItemWindow(pParent, "svx/ui/stylespreview.ui", "ApplyStyleBox", true,
+ reinterpret_cast<sal_uInt64>(SfxViewShell::Current()))
+ , StylesPreviewWindow_Base(*m_xBuilder, std::move(aDefaultStyles), xDispatchProvider)
+{
+ SetOptimalSize();
+}
+
+StylesPreviewWindow_Impl::~StylesPreviewWindow_Impl() { disposeOnce(); }
+
+void StylesPreviewWindow_Impl::dispose()
+{
+ m_xStylesView.reset();
+
+ InterimItemWindow::dispose();
+}
+
+void StylesPreviewWindow_Impl::SetOptimalSize() { SetSizePixel(get_preferred_size()); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/tbxctrls/SvxColorChildWindow.cxx b/svx/source/tbxctrls/SvxColorChildWindow.cxx
new file mode 100644
index 000000000..c7fb9a683
--- /dev/null
+++ b/svx/source/tbxctrls/SvxColorChildWindow.cxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/SvxColorChildWindow.hxx>
+#include <svx/svxids.hrc>
+#include <colrctrl.hxx>
+
+SFX_IMPL_DOCKINGWINDOW_WITHID( SvxColorChildWindow, SID_COLOR_CONTROL )
+
+// Derivation from SfxChildWindow as "container" for animator
+SvxColorChildWindow::SvxColorChildWindow( vcl::Window* _pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo ) :
+ SfxChildWindow( _pParent, nId )
+{
+ VclPtr<SvxColorDockingWindow> pWin = VclPtr<SvxColorDockingWindow>::Create( pBindings, this,
+ _pParent );
+
+ SetWindow(pWin);
+
+ SetAlignment(SfxChildAlignment::RIGHT);
+
+ pWin->Initialize( pInfo );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/SvxColorValueSet.cxx b/svx/source/tbxctrls/SvxColorValueSet.cxx
new file mode 100644
index 000000000..4b4547dfc
--- /dev/null
+++ b/svx/source/tbxctrls/SvxColorValueSet.cxx
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/SvxColorValueSet.hxx>
+#include <svx/xtable.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <osl/diagnose.h>
+
+#include <svx/uiobject.hxx>
+
+SvxColorValueSet::SvxColorValueSet(std::unique_ptr<weld::ScrolledWindow> pWindow)
+ : ValueSet(std::move(pWindow))
+{
+ SetEdgeBlending(true);
+}
+
+FactoryFunction SvxColorValueSet::GetUITestFactory() const
+{
+ return SvxColorValueSetUIObject::create;
+}
+
+sal_uInt32 SvxColorValueSet::getEntryEdgeLength()
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ return rStyleSettings.GetListBoxPreviewDefaultPixelSize().Height() + 1;
+}
+
+sal_uInt32 SvxColorValueSet::getColumnCount()
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ return rStyleSettings.GetColorValueSetColumnCount();
+}
+
+void SvxColorValueSet::addEntriesForXColorList(const XColorList& rXColorList, sal_uInt32 nStartIndex)
+{
+ const sal_uInt32 nColorCount(rXColorList.Count());
+
+ for(sal_uInt32 nIndex(0); nIndex < nColorCount; nIndex++, nStartIndex++)
+ {
+ const XColorEntry* pEntry = rXColorList.GetColor(nIndex);
+
+ if(pEntry)
+ {
+ InsertItem(nStartIndex, pEntry->GetColor(), pEntry->GetName());
+ }
+ else
+ {
+ OSL_ENSURE(false, "OOps, XColorList with empty entries (!)");
+ }
+ }
+}
+
+void SvxColorValueSet::addEntriesForColorSet(const std::set<Color>& rColorSet, const OUString& rNamePrefix)
+{
+ sal_uInt32 nStartIndex = 1;
+ if(rNamePrefix.getLength() != 0)
+ {
+ for(const auto& rColor : rColorSet)
+ {
+ InsertItem(nStartIndex, rColor, rNamePrefix + OUString::number(nStartIndex));
+ nStartIndex++;
+ }
+ }
+ else
+ {
+ for(const auto& rColor : rColorSet)
+ {
+ InsertItem(nStartIndex, rColor, "");
+ nStartIndex++;
+ }
+ }
+}
+
+Size SvxColorValueSet::layoutAllVisible(sal_uInt32 nEntryCount)
+{
+ if(!nEntryCount)
+ {
+ nEntryCount++;
+ }
+
+ const sal_uInt32 nRowCount(ceil(double(nEntryCount)/SvxColorValueSet::getColumnCount()));
+ const Size aItemSize(SvxColorValueSet::getEntryEdgeLength() - 2, SvxColorValueSet::getEntryEdgeLength() - 2);
+ const WinBits aWinBits(GetStyle() & ~WB_VSCROLL);
+
+ if (nRowCount > SvxColorValueSet::getMaxRowCount())
+ {
+ SetStyle(aWinBits|WB_VSCROLL);
+ }
+ else
+ {
+ SetStyle(aWinBits);
+ }
+
+ SetColCount(SvxColorValueSet::getColumnCount());
+ SetLineCount(std::min(nRowCount, SvxColorValueSet::getMaxRowCount()));
+ SetItemWidth(aItemSize.Width());
+ SetItemHeight(aItemSize.Height());
+
+ return CalcWindowSizePixel(aItemSize);
+}
+
+void SvxColorValueSet::Resize()
+{
+ layoutToGivenHeight(GetOutputSizePixel().Height(), GetItemCount());
+ ValueSet::Resize();
+}
+
+void SvxColorValueSet::layoutToGivenHeight(sal_uInt32 nHeight, sal_uInt32 nEntryCount)
+{
+ if(!nEntryCount)
+ {
+ nEntryCount++;
+ }
+
+ const Size aItemSize(SvxColorValueSet::getEntryEdgeLength() - 2, SvxColorValueSet::getEntryEdgeLength() - 2);
+ const WinBits aWinBits(GetStyle() & ~WB_VSCROLL);
+
+ // get size with all fields disabled
+ const WinBits aWinBitsNoScrollNoFields(GetStyle() & ~(WB_VSCROLL|WB_NAMEFIELD|WB_NONEFIELD));
+ SetStyle(aWinBitsNoScrollNoFields);
+ const Size aSizeNoScrollNoFields(CalcWindowSizePixel(aItemSize, SvxColorValueSet::getColumnCount()));
+
+ // get size with all needed fields
+ SetStyle(aWinBits);
+ Size aNewSize(CalcWindowSizePixel(aItemSize, SvxColorValueSet::getColumnCount()));
+
+ const Size aItemSizePixel(CalcItemSizePixel(aItemSize));
+ // calculate field height and available height for requested height
+ const sal_uInt32 nFieldHeight(aNewSize.Height() - aSizeNoScrollNoFields.Height());
+ const sal_uInt32 nAvailableHeight(nHeight >= nFieldHeight ? nHeight - nFieldHeight + aItemSizePixel.Height() - 1 : 0);
+
+ // calculate how many lines can be shown there
+ const sal_uInt32 nLineCount(nAvailableHeight / aItemSizePixel.Height());
+ const sal_uInt32 nLineMax(ceil(double(nEntryCount)/SvxColorValueSet::getColumnCount()));
+
+ if(nLineMax > nLineCount)
+ {
+ SetStyle(aWinBits|WB_VSCROLL);
+ }
+
+ SetItemWidth(aItemSize.Width());
+ SetItemHeight(aItemSize.Height());
+ SetColCount(SvxColorValueSet::getColumnCount());
+ SetLineCount(nLineCount);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/SvxPresetListBox.cxx b/svx/source/tbxctrls/SvxPresetListBox.cxx
new file mode 100644
index 000000000..5cda71a8c
--- /dev/null
+++ b/svx/source/tbxctrls/SvxPresetListBox.cxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/SvxPresetListBox.hxx>
+#include <svx/xtable.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/image.hxx>
+#include <vcl/svapp.hxx>
+
+SvxPresetListBox::SvxPresetListBox(std::unique_ptr<weld::ScrolledWindow> pWindow)
+ : ValueSet(std::move(pWindow))
+ , aIconSize(60, 64)
+{
+ SetEdgeBlending(true);
+}
+
+void SvxPresetListBox::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ValueSet::SetDrawingArea(pDrawingArea);
+ SetStyle(GetStyle() | WB_ITEMBORDER);
+}
+
+void SvxPresetListBox::Resize()
+{
+ DrawLayout();
+ WinBits aWinBits(GetStyle());
+ aWinBits |= WB_VSCROLL;
+ SetStyle(aWinBits);
+ ValueSet::Resize();
+}
+
+bool SvxPresetListBox::Command(const CommandEvent& rEvent)
+{
+ if (rEvent.GetCommand() != CommandEventId::ContextMenu)
+ return CustomWidgetController::Command(rEvent);
+ const sal_uInt16 nIndex = GetSelectedItemId();
+ if (nIndex > 0)
+ {
+ std::unique_ptr<weld::Builder> xBuilder(
+ Application::CreateBuilder(GetDrawingArea(), "svx/ui/presetmenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+ OnMenuItemSelected(xMenu->popup_at_rect(
+ GetDrawingArea(), tools::Rectangle(rEvent.GetMousePosPixel(), Size(1, 1))));
+ return true;
+ }
+ return false;
+}
+
+void SvxPresetListBox::DrawLayout()
+{
+ SetColCount(nColCount);
+ SetLineCount(5);
+}
+
+template <typename ListType, typename EntryType>
+void SvxPresetListBox::FillPresetListBoxImpl(ListType& pList, sal_uInt32 nStartIndex)
+{
+ const Size aSize(GetIconSize());
+ BitmapEx aBitmap;
+ for (tools::Long nIndex = 0; nIndex < pList.Count(); nIndex++, nStartIndex++)
+ {
+ aBitmap = pList.GetBitmapForPreview(nIndex, aSize);
+ EntryType* pItem = static_cast<EntryType*>(pList.Get(nIndex));
+ InsertItem(nStartIndex, Image(aBitmap), pItem->GetName());
+ }
+}
+
+void SvxPresetListBox::FillPresetListBox(XGradientList& pList, sal_uInt32 nStartIndex)
+{
+ FillPresetListBoxImpl<XGradientList, XGradientEntry>(pList, nStartIndex);
+}
+
+void SvxPresetListBox::FillPresetListBox(XHatchList& pList, sal_uInt32 nStartIndex)
+{
+ FillPresetListBoxImpl<XHatchList, XHatchEntry>(pList, nStartIndex);
+}
+
+void SvxPresetListBox::FillPresetListBox(XBitmapList& pList, sal_uInt32 nStartIndex)
+{
+ FillPresetListBoxImpl<XBitmapList, XBitmapEntry>(pList, nStartIndex);
+}
+
+void SvxPresetListBox::FillPresetListBox(XPatternList& pList, sal_uInt32 nStartIndex)
+{
+ FillPresetListBoxImpl<XPatternList, XBitmapEntry>(pList, nStartIndex);
+}
+
+void SvxPresetListBox::OnMenuItemSelected(std::string_view rIdent)
+{
+ if (rIdent == "rename")
+ maRenameHdl.Call(this);
+ else if (rIdent == "delete")
+ maDeleteHdl.Call(this);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/bulletsnumbering.cxx b/svx/source/tbxctrls/bulletsnumbering.cxx
new file mode 100644
index 000000000..8bf832761
--- /dev/null
+++ b/svx/source/tbxctrls/bulletsnumbering.cxx
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <com/sun/star/text/DefaultNumberingProvider.hpp>
+#include <com/sun/star/text/XNumberingFormatter.hpp>
+
+#include <comphelper/propertysequence.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <svtools/popupwindowcontroller.hxx>
+#include <svtools/toolbarmenu.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/numvset.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+namespace {
+
+class NumberingToolBoxControl;
+
+class NumberingPopup : public WeldToolbarPopup
+{
+ NumberingPageType mePageType;
+ NumberingToolBoxControl& mrController;
+ std::unique_ptr<SvxNumValueSet> mxValueSet;
+ std::unique_ptr<weld::CustomWeld> mxValueSetWin;
+ std::unique_ptr<weld::Button> mxMoreButton;
+ DECL_LINK(VSSelectValueSetHdl, ValueSet*, void);
+ DECL_LINK(VSButtonClickSetHdl, weld::Button&, void);
+
+ virtual void GrabFocus() override;
+
+public:
+ NumberingPopup(NumberingToolBoxControl& rController, weld::Widget* pParent, NumberingPageType ePageType);
+
+ virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+};
+
+class NumberingToolBoxControl : public svt::PopupWindowController
+{
+ NumberingPageType mePageType;
+
+public:
+ explicit NumberingToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+ std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+}
+
+NumberingPopup::NumberingPopup(NumberingToolBoxControl& rController,
+ weld::Widget* pParent, NumberingPageType ePageType)
+ : WeldToolbarPopup(rController.getFrameInterface(), pParent, "svx/ui/numberingwindow.ui", "NumberingWindow")
+ , mePageType(ePageType)
+ , mrController(rController)
+ , mxValueSet(new SvxNumValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true)))
+ , mxValueSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxValueSet))
+ , mxMoreButton(m_xBuilder->weld_button("more"))
+{
+ mxValueSet->SetStyle(WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NO_DIRECTSELECT);
+ mxValueSet->init(mePageType);
+
+ if ( mePageType != NumberingPageType::BULLET )
+ {
+ css::uno::Reference< css::text::XDefaultNumberingProvider > xDefNum = css::text::DefaultNumberingProvider::create( mrController.getContext() );
+ if ( xDefNum.is() )
+ {
+ css::lang::Locale aLocale = Application::GetSettings().GetLanguageTag().getLocale();
+ css::uno::Reference< css::text::XNumberingFormatter > xFormat( xDefNum, css::uno::UNO_QUERY );
+
+ if ( mePageType == NumberingPageType::SINGLENUM )
+ {
+ css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aNumberings(
+ xDefNum->getDefaultContinuousNumberingLevels( aLocale ) );
+ mxValueSet->SetNumberingSettings( aNumberings, xFormat, aLocale );
+ }
+ else if ( mePageType == NumberingPageType::OUTLINE )
+ {
+ css::uno::Sequence< css::uno::Reference< css::container::XIndexAccess > > aOutline(
+ xDefNum->getDefaultOutlineNumberings( aLocale ) );
+ mxValueSet->SetOutlineNumberingSettings( aOutline, xFormat, aLocale );
+ }
+ }
+ }
+
+ weld::DrawingArea* pDrawingArea = mxValueSet->GetDrawingArea();
+ OutputDevice& rRefDevice = pDrawingArea->get_ref_device();
+ Size aItemSize(rRefDevice.LogicToPixel(Size(30, 42), MapMode(MapUnit::MapAppFont)));
+ mxValueSet->SetExtraSpacing( 2 );
+ Size aSize(mxValueSet->CalcWindowSizePixel(aItemSize));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ mxValueSet->SetOutputSizePixel(aSize);
+ mxValueSet->SetColor(Application::GetSettings().GetStyleSettings().GetFieldColor());
+
+ OUString aMoreItemText;
+ if ( mePageType == NumberingPageType::BULLET )
+ {
+ aMoreItemText = SvxResId( RID_SVXSTR_MOREBULLETS );
+ AddStatusListener( ".uno:CurrentBulletListType" );
+ }
+ else if ( mePageType == NumberingPageType::SINGLENUM )
+ {
+ aMoreItemText = SvxResId( RID_SVXSTR_MORENUMBERING );
+ AddStatusListener( ".uno:CurrentNumListType" );
+ }
+ else
+ {
+ aMoreItemText = SvxResId( RID_SVXSTR_MORE );
+ AddStatusListener( ".uno:CurrentOutlineType" );
+ }
+
+ auto xImage = vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:OutlineBullet", mrController.getFrameInterface());
+ mxMoreButton->set_image(xImage);
+ mxMoreButton->set_label(aMoreItemText);
+ mxMoreButton->connect_clicked(LINK(this, NumberingPopup, VSButtonClickSetHdl));
+
+ mxValueSet->SetSelectHdl(LINK(this, NumberingPopup, VSSelectValueSetHdl));
+}
+
+void NumberingPopup::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ mxValueSet->SetNoSelection();
+
+ sal_Int32 nSelItem;
+ if ( rEvent.State >>= nSelItem )
+ mxValueSet->SelectItem( nSelItem );
+}
+
+IMPL_LINK_NOARG(NumberingPopup, VSSelectValueSetHdl, ValueSet*, void)
+{
+ sal_uInt16 nSelItem = mxValueSet->GetSelectedItemId();
+ if ( mePageType == NumberingPageType::BULLET )
+ {
+ auto aArgs( comphelper::InitPropertySequence( { { "SetBullet", css::uno::Any( nSelItem ) } } ) );
+ mrController.dispatchCommand( ".uno:SetBullet", aArgs );
+ }
+ else if ( mePageType == NumberingPageType::SINGLENUM )
+ {
+ auto aArgs( comphelper::InitPropertySequence( { { "SetNumber", css::uno::Any( nSelItem ) } } ) );
+ mrController.dispatchCommand( ".uno:SetNumber", aArgs );
+ }
+ else
+ {
+ auto aArgs( comphelper::InitPropertySequence( { { "SetOutline", css::uno::Any( nSelItem ) } } ) );
+ mrController.dispatchCommand( ".uno:SetOutline", aArgs );
+ }
+ mrController.EndPopupMode();
+}
+
+void NumberingPopup::GrabFocus()
+{
+ mxValueSet->GrabFocus();
+}
+
+IMPL_LINK_NOARG(NumberingPopup, VSButtonClickSetHdl, weld::Button&, void)
+{
+ auto aArgs( comphelper::InitPropertySequence( { { "Page", css::uno::Any( OUString("customize") ) } } ) );
+ mrController.dispatchCommand( ".uno:OutlineBullet", aArgs );
+
+ mrController.EndPopupMode();
+}
+
+NumberingToolBoxControl::NumberingToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext ):
+ svt::PopupWindowController( rxContext, css::uno::Reference< css::frame::XFrame >(), OUString() ),
+ mePageType( NumberingPageType::SINGLENUM )
+{
+}
+
+std::unique_ptr<WeldToolbarPopup> NumberingToolBoxControl::weldPopupWindow()
+{
+ return std::make_unique<NumberingPopup>(*this, m_pToolbar, mePageType);
+}
+
+VclPtr<vcl::Window> NumberingToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<NumberingPopup>(*this, pParent->GetFrameWeld(), mePageType));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+void SAL_CALL NumberingToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::PopupWindowController::initialize( aArguments );
+
+ if ( m_aCommandURL == ".uno:DefaultBullet" )
+ mePageType = NumberingPageType::BULLET;
+ else if ( m_aCommandURL == ".uno:SetOutline" )
+ mePageType = NumberingPageType::OUTLINE;
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
+ return;
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ {
+ ToolBoxItemBits nBits = ( mePageType == NumberingPageType::OUTLINE ) ? ToolBoxItemBits::DROPDOWNONLY : ToolBoxItemBits::DROPDOWN;
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | nBits );
+ }
+}
+
+OUString SAL_CALL NumberingToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.NumberingToolBoxControl";
+}
+
+css::uno::Sequence< OUString > SAL_CALL NumberingToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_NumberingToolBoxControl_get_implementation(
+ css::uno::XComponentContext *rxContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new NumberingToolBoxControl( rxContext ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/colrctrl.cxx b/svx/source/tbxctrls/colrctrl.cxx
new file mode 100644
index 000000000..d3bc9ae24
--- /dev/null
+++ b/svx/source/tbxctrls/colrctrl.cxx
@@ -0,0 +1,423 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sot/exchange.hxx>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+
+#include <sfx2/viewsh.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/image.hxx>
+#include <vcl/transfer.hxx>
+
+#include <colrctrl.hxx>
+
+#include <svx/svdview.hxx>
+#include <svx/drawitem.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <editeng/colritem.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xtable.hxx>
+#include <svx/dialmgr.hxx>
+#include <helpids.h>
+#include <vcl/virdev.hxx>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+
+using namespace com::sun::star;
+
+class SvxColorValueSetData final : public TransferDataContainer
+{
+private:
+ uno::Sequence<beans::NamedValue> m_Data;
+
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData(const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc) override;
+
+public:
+ SvxColorValueSetData()
+ {
+ }
+
+ void SetData(const uno::Sequence<beans::NamedValue>& rData)
+ {
+ m_Data = rData;
+ ClearFormats(); // invalidate m_aAny so new data will take effect
+ }
+};
+
+void SvxColorValueSetData::AddSupportedFormats()
+{
+ AddFormat( SotClipboardFormatId::XFA );
+}
+
+bool SvxColorValueSetData::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+{
+ bool bRet = false;
+
+ if( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::XFA )
+ {
+ SetAny(uno::Any(m_Data));
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+void SvxColorValueSet_docking::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ SvxColorValueSet::SetDrawingArea(pDrawingArea);
+ SetAccessibleName(SvxResId(STR_COLORTABLE));
+ SetStyle(GetStyle() | WB_ITEMBORDER);
+
+ m_xHelper.set(new SvxColorValueSetData);
+ rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
+ SetDragDataTransferrable(xHelper, DND_ACTION_COPY);
+}
+
+SvxColorValueSet_docking::SvxColorValueSet_docking(std::unique_ptr<weld::ScrolledWindow> xWindow)
+ : SvxColorValueSet(std::move(xWindow))
+ , mbLeftButton(true)
+{
+}
+
+bool SvxColorValueSet_docking::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ bool bRet;
+
+ // For Mac still handle differently!
+ if( rMEvt.IsLeft() )
+ {
+ mbLeftButton = true;
+ bRet = SvxColorValueSet::MouseButtonDown( rMEvt );
+ }
+ else
+ {
+ mbLeftButton = false;
+ MouseEvent aMEvt( rMEvt.GetPosPixel(),
+ rMEvt.GetClicks(),
+ rMEvt.GetMode(),
+ MOUSE_LEFT,
+ rMEvt.GetModifier() );
+ bRet = SvxColorValueSet::MouseButtonDown( aMEvt );
+ }
+
+ return bRet;
+}
+
+bool SvxColorValueSet_docking::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ bool bRet;
+
+ // For Mac still handle differently!
+ if( rMEvt.IsLeft() )
+ {
+ mbLeftButton = true;
+ bRet = SvxColorValueSet::MouseButtonUp( rMEvt );
+ }
+ else
+ {
+ mbLeftButton = false;
+ MouseEvent aMEvt( rMEvt.GetPosPixel(),
+ rMEvt.GetClicks(),
+ rMEvt.GetMode(),
+ MOUSE_LEFT,
+ rMEvt.GetModifier() );
+ bRet = SvxColorValueSet::MouseButtonUp( aMEvt );
+ }
+ SetNoSelection();
+
+ return bRet;
+}
+
+bool SvxColorValueSet_docking::StartDrag()
+{
+ sal_uInt16 nPos = GetSelectedItemId();
+ Color aItemColor( GetItemColor( nPos ) );
+ OUString sItemText( GetItemText( nPos ) );
+
+ drawing::FillStyle eStyle = ((1 == nPos)
+ ? drawing::FillStyle_NONE
+ : drawing::FillStyle_SOLID);
+
+ XFillColorItem const color(sItemText, aItemColor);
+ XFillStyleItem const style(eStyle);
+ uno::Any c, s;
+ color.QueryValue(c, 0);
+ style.QueryValue(s, 0);
+
+ uno::Sequence<beans::NamedValue> props{ { "FillColor", std::move(c) },
+ { "FillStyle", std::move(s) } };
+ m_xHelper->SetData(props);
+
+ return false;
+}
+
+constexpr sal_uInt16 gnLeftSlot = SID_ATTR_FILL_COLOR;
+constexpr sal_uInt16 gnRightSlot = SID_ATTR_LINE_COLOR;
+
+SvxColorDockingWindow::SvxColorDockingWindow(SfxBindings* _pBindings, SfxChildWindow* pCW, vcl::Window* _pParent)
+ : SfxDockingWindow(_pBindings, pCW, _pParent,
+ "DockingColorWindow", "svx/ui/dockingcolorwindow.ui")
+ , xColorSet(new SvxColorValueSet_docking(m_xBuilder->weld_scrolled_window("valuesetwin", true)))
+ , xColorSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *xColorSet))
+{
+ SetText(SvxResId(STR_COLORTABLE));
+ SetQuickHelpText(SvxResId(RID_SVXSTR_COLORBAR));
+ SetSizePixel(LogicToPixel(Size(150, 22), MapMode(MapUnit::MapAppFont)));
+ SetHelpId(HID_CTRL_COLOR);
+
+ xColorSet->SetSelectHdl( LINK( this, SvxColorDockingWindow, SelectHdl ) );
+ xColorSet->SetHelpId(HID_COLOR_CTL_COLORS);
+
+ // Get the model from the view shell. Using SfxObjectShell::Current()
+ // is unreliable when called at the wrong times.
+ SfxObjectShell* pDocSh = nullptr;
+ if (_pBindings != nullptr)
+ {
+ SfxDispatcher* pDispatcher = _pBindings->GetDispatcher();
+ if (pDispatcher != nullptr)
+ {
+ SfxViewFrame* pFrame = pDispatcher->GetFrame();
+ if (pFrame != nullptr)
+ {
+ SfxViewShell* pViewShell = pFrame->GetViewShell();
+ if (pViewShell != nullptr)
+ pDocSh = pViewShell->GetObjectShell();
+ }
+ }
+ }
+
+ if ( pDocSh )
+ {
+ const SfxPoolItem* pItem = pDocSh->GetItem( SID_COLOR_TABLE );
+ if( pItem )
+ {
+ pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList();
+ FillValueSet();
+ }
+ }
+
+ Size aItemSize = xColorSet->CalcItemSizePixel(Size(SvxColorValueSet::getEntryEdgeLength(), SvxColorValueSet::getEntryEdgeLength()));
+ aItemSize.setWidth( aItemSize.Width() + SvxColorValueSet::getEntryEdgeLength() );
+ aItemSize.setWidth( aItemSize.Width() / 2 );
+ aItemSize.setHeight( aItemSize.Height() + SvxColorValueSet::getEntryEdgeLength() );
+ aItemSize.setHeight( aItemSize.Height() / 2 );
+
+ if (_pBindings != nullptr)
+ StartListening(*_pBindings, DuplicateHandling::Prevent);
+}
+
+SvxColorDockingWindow::~SvxColorDockingWindow()
+{
+ disposeOnce();
+}
+
+void SvxColorDockingWindow::dispose()
+{
+ EndListening( GetBindings() );
+ xColorSetWin.reset();
+ xColorSet.reset();
+ SfxDockingWindow::dispose();
+}
+
+void SvxColorDockingWindow::Notify( SfxBroadcaster& , const SfxHint& rHint )
+{
+ const SfxPoolItemHint* pPoolItemHint = dynamic_cast<const SfxPoolItemHint*>(&rHint);
+ if ( pPoolItemHint )
+ if (auto pColorListItem = dynamic_cast<const SvxColorListItem*>(pPoolItemHint->GetObject()))
+ {
+ // The list of colors has changed
+ pColorList = pColorListItem->GetColorList();
+ FillValueSet();
+ }
+}
+
+void SvxColorDockingWindow::FillValueSet()
+{
+ if( !pColorList.is() )
+ return;
+
+ xColorSet->Clear();
+
+ xColorSet->addEntriesForXColorList(*pColorList, 2);
+
+ // create the last entry for 'invisible/none'
+ const Size aColorSize(SvxColorValueSet::getEntryEdgeLength(), SvxColorValueSet::getEntryEdgeLength());
+ tools::Long nPtX = aColorSize.Width() - 1;
+ tools::Long nPtY = aColorSize.Height() - 1;
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ pVD->SetOutputSizePixel( aColorSize );
+ pVD->SetLineColor( COL_BLACK );
+ pVD->SetBackground( Wallpaper( COL_WHITE ) );
+ pVD->DrawLine( Point(), Point( nPtX, nPtY ) );
+ pVD->DrawLine( Point( 0, nPtY ), Point( nPtX, 0 ) );
+
+ BitmapEx aBmp( pVD->GetBitmapEx( Point(), aColorSize ) );
+
+ xColorSet->InsertItem( sal_uInt16(1), Image(aBmp), SvxResId( RID_SVXSTR_INVISIBLE ) );
+}
+
+bool SvxColorDockingWindow::Close()
+{
+ SfxBoolItem aItem( SID_COLOR_CONTROL, false );
+ GetBindings().GetDispatcher()->ExecuteList(SID_COLOR_CONTROL,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+ SfxDockingWindow::Close();
+ return true;
+}
+
+IMPL_LINK_NOARG(SvxColorDockingWindow, SelectHdl, ValueSet*, void)
+{
+ SfxDispatcher* pDispatcher = GetBindings().GetDispatcher();
+ sal_uInt16 nPos = xColorSet->GetSelectedItemId();
+ Color aColor( xColorSet->GetItemColor( nPos ) );
+ OUString aStr( xColorSet->GetItemText( nPos ) );
+
+ if (xColorSet->IsLeftButton())
+ {
+ if ( gnLeftSlot == SID_ATTR_FILL_COLOR )
+ {
+ if ( nPos == 1 ) // invisible
+ {
+ XFillStyleItem aXFillStyleItem( drawing::FillStyle_NONE );
+ pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD,
+ { &aXFillStyleItem });
+ }
+ else
+ {
+ bool bDone = false;
+
+ // If we have a DrawView and we are in TextEdit mode, then
+ // not the area color but the text color is assigned
+ SfxViewShell* pViewSh = SfxViewShell::Current();
+ if ( pViewSh )
+ {
+ SdrView* pView = pViewSh->GetDrawView();
+ if ( pView && pView->IsTextEdit() )
+ {
+ SvxColorItem aTextColorItem( aColor, SID_ATTR_CHAR_COLOR );
+ pDispatcher->ExecuteList(SID_ATTR_CHAR_COLOR,
+ SfxCallMode::RECORD, { &aTextColorItem });
+ bDone = true;
+ }
+ }
+ if ( !bDone )
+ {
+ XFillStyleItem aXFillStyleItem( drawing::FillStyle_SOLID );
+ XFillColorItem aXFillColorItem( aStr, aColor );
+ pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD,
+ { &aXFillColorItem, &aXFillStyleItem });
+ }
+ }
+ }
+ else if ( nPos != 1 ) // invisible
+ {
+ SvxColorItem aLeftColorItem( aColor, gnLeftSlot );
+ pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD,
+ { &aLeftColorItem });
+ }
+ }
+ else
+ {
+ if ( gnRightSlot == SID_ATTR_LINE_COLOR )
+ {
+ if( nPos == 1 ) // invisible
+ {
+ XLineStyleItem aXLineStyleItem( drawing::LineStyle_NONE );
+ pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD,
+ { &aXLineStyleItem });
+ }
+ else
+ {
+ // If the LineStyle is invisible, it is set to SOLID
+ SfxViewShell* pViewSh = SfxViewShell::Current();
+ if ( pViewSh )
+ {
+ SdrView* pView = pViewSh->GetDrawView();
+ if ( pView )
+ {
+ SfxItemSet aAttrSet( pView->GetModel()->GetItemPool() );
+ pView->GetAttributes( aAttrSet );
+ if ( aAttrSet.GetItemState( XATTR_LINESTYLE ) != SfxItemState::DONTCARE )
+ {
+ drawing::LineStyle eXLS =
+ aAttrSet.Get( XATTR_LINESTYLE ).GetValue();
+ if ( eXLS == drawing::LineStyle_NONE )
+ {
+ XLineStyleItem aXLineStyleItem( drawing::LineStyle_SOLID );
+ pDispatcher->ExecuteList(gnRightSlot,
+ SfxCallMode::RECORD, { &aXLineStyleItem });
+ }
+ }
+ }
+ }
+
+ XLineColorItem aXLineColorItem( aStr, aColor );
+ pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD,
+ { &aXLineColorItem });
+ }
+ }
+ else if ( nPos != 1 ) // invisible
+ {
+ SvxColorItem aRightColorItem( aColor, gnRightSlot );
+ pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD,
+ { &aRightColorItem });
+ }
+ }
+}
+
+void SvxColorDockingWindow::GetFocus()
+{
+ SfxDockingWindow::GetFocus();
+ if (xColorSet)
+ {
+ // Grab the focus to the color value set so that it can be controlled
+ // with the keyboard.
+ xColorSet->GrabFocus();
+ }
+}
+
+bool SvxColorDockingWindow::EventNotify( NotifyEvent& rNEvt )
+{
+ bool bRet = false;
+ if( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
+ {
+ KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
+ sal_uInt16 nKeyCode = aKeyEvt.GetKeyCode().GetCode();
+ switch( nKeyCode )
+ {
+ case KEY_ESCAPE:
+ GrabFocusToDocument();
+ bRet = true;
+ break;
+ }
+ }
+
+ return bRet || SfxDockingWindow::EventNotify(rNEvt);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/extrusioncontrols.cxx b/svx/source/tbxctrls/extrusioncontrols.cxx
new file mode 100644
index 000000000..9affab6d7
--- /dev/null
+++ b/svx/source/tbxctrls/extrusioncontrols.cxx
@@ -0,0 +1,968 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <svtools/toolbarmenu.hxx>
+#include <vcl/toolbox.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/svdtrans.hxx>
+#include <svx/dialmgr.hxx>
+
+#include <helpids.h>
+#include "extrusioncontrols.hxx"
+#include <extrusiondepthdialog.hxx>
+
+#include <bitmaps.hlst>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::graphic;
+
+namespace svx
+{
+
+const sal_Int32 gSkewList[] = { 135, 90, 45, 180, 0, -360, -135, -90, -45 };
+constexpr OUStringLiteral g_sExtrusionDirection = u".uno:ExtrusionDirection";
+constexpr OUStringLiteral g_sExtrusionProjection = u".uno:ExtrusionProjection";
+constexpr OUStringLiteral EMPTY = u"";
+
+constexpr rtl::OUStringConstExpr aLightOffBmps[] =
+{
+ RID_SVXBMP_LIGHT_OFF_FROM_TOP_LEFT,
+ RID_SVXBMP_LIGHT_OFF_FROM_TOP,
+ RID_SVXBMP_LIGHT_OFF_FROM_TOP_RIGHT,
+ RID_SVXBMP_LIGHT_OFF_FROM_LEFT,
+ EMPTY,
+ RID_SVXBMP_LIGHT_OFF_FROM_RIGHT,
+ RID_SVXBMP_LIGHT_OFF_FROM_BOTTOM_LEFT,
+ RID_SVXBMP_LIGHT_OFF_FROM_BOTTOM,
+ RID_SVXBMP_LIGHT_OFF_FROM_BOTTOM_RIGHT
+};
+
+constexpr rtl::OUStringConstExpr aLightOnBmps[] =
+{
+ RID_SVXBMP_LIGHT_ON_FROM_TOP_LEFT,
+ RID_SVXBMP_LIGHT_ON_FROM_TOP,
+ RID_SVXBMP_LIGHT_ON_FROM_TOP_RIGHT,
+ RID_SVXBMP_LIGHT_ON_FROM_LEFT,
+ EMPTY,
+ RID_SVXBMP_LIGHT_ON_FROM_RIGHT,
+ RID_SVXBMP_LIGHT_ON_FROM_BOTTOM_LEFT,
+ RID_SVXBMP_LIGHT_ON_FROM_BOTTOM,
+ RID_SVXBMP_LIGHT_ON_FROM_BOTTOM_RIGHT
+};
+
+constexpr rtl::OUStringConstExpr aLightPreviewBmps[] =
+{
+ RID_SVXBMP_LIGHT_PREVIEW_FROM_TOP_LEFT,
+ RID_SVXBMP_LIGHT_PREVIEW_FROM_TOP,
+ RID_SVXBMP_LIGHT_PREVIEW_FROM_TOP_RIGHT,
+ RID_SVXBMP_LIGHT_PREVIEW_FROM_LEFT,
+ RID_SVXBMP_LIGHT_PREVIEW_FROM_FRONT,
+ RID_SVXBMP_LIGHT_PREVIEW_FROM_RIGHT,
+ RID_SVXBMP_LIGHT_PREVIEW_FROM_BOTTOM_LEFT,
+ RID_SVXBMP_LIGHT_PREVIEW_FROM_BOTTOM,
+ RID_SVXBMP_LIGHT_PREVIEW_FROM_BOTTOM_RIGHT
+};
+
+constexpr rtl::OUStringConstExpr aDirectionBmps[] =
+{
+ RID_SVXBMP_DIRECTION_DIRECTION_NW,
+ RID_SVXBMP_DIRECTION_DIRECTION_N,
+ RID_SVXBMP_DIRECTION_DIRECTION_NE,
+ RID_SVXBMP_DIRECTION_DIRECTION_W,
+ RID_SVXBMP_DIRECTION_DIRECTION_NONE,
+ RID_SVXBMP_DIRECTION_DIRECTION_E,
+ RID_SVXBMP_DIRECTION_DIRECTION_SW,
+ RID_SVXBMP_DIRECTION_DIRECTION_S,
+ RID_SVXBMP_DIRECTION_DIRECTION_SE
+};
+
+static TranslateId aDirectionStrs[] =
+{
+ RID_SVXSTR_DIRECTION_NW,
+ RID_SVXSTR_DIRECTION_N,
+ RID_SVXSTR_DIRECTION_NE,
+ RID_SVXSTR_DIRECTION_W,
+ RID_SVXSTR_DIRECTION_NONE,
+ RID_SVXSTR_DIRECTION_E,
+ RID_SVXSTR_DIRECTION_SW,
+ RID_SVXSTR_DIRECTION_S,
+ RID_SVXSTR_DIRECTION_SE
+};
+
+ExtrusionDirectionWindow::ExtrusionDirectionWindow(
+ svt::PopupWindowController* pControl,
+ weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/directionwindow.ui", "DirectionWindow")
+ , mxControl(pControl)
+ , mxDirectionSet(new ValueSet(nullptr))
+ , mxDirectionSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxDirectionSet))
+ , mxPerspective(m_xBuilder->weld_radio_button("perspective"))
+ , mxParallel(m_xBuilder->weld_radio_button("parallel"))
+{
+ mxDirectionSet->SetStyle(WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT);
+
+ for (sal_uInt16 i = DIRECTION_NW; i <= DIRECTION_SE; ++i)
+ {
+ maImgDirection[i] = Image(StockImage::Yes, OUString(aDirectionBmps[i]));
+ }
+
+ mxDirectionSet->SetSelectHdl( LINK( this, ExtrusionDirectionWindow, SelectValueSetHdl ) );
+ mxDirectionSet->SetColCount( 3 );
+ mxDirectionSet->EnableFullItemMode( false );
+
+ for (sal_uInt16 i = DIRECTION_NW; i <= DIRECTION_SE; ++i)
+ {
+ mxDirectionSet->InsertItem(i + 1, maImgDirection[i], SvxResId(aDirectionStrs[i]));
+ }
+
+ Size aSize(72, 72);
+ mxDirectionSet->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height());
+ mxDirectionSet->SetOutputSizePixel(aSize);
+
+ mxPerspective->connect_toggled(LINK(this, ExtrusionDirectionWindow, SelectToolbarMenuHdl));
+
+ AddStatusListener( g_sExtrusionDirection );
+ AddStatusListener( g_sExtrusionProjection );
+}
+
+void ExtrusionDirectionWindow::GrabFocus()
+{
+ mxDirectionSet->GrabFocus();
+}
+
+ExtrusionDirectionWindow::~ExtrusionDirectionWindow()
+{
+}
+
+void ExtrusionDirectionWindow::implSetDirection( sal_Int32 nSkew, bool bEnabled )
+{
+ sal_uInt16 nItemId;
+ for( nItemId = DIRECTION_NW; nItemId <= DIRECTION_SE; nItemId++ )
+ {
+ if( gSkewList[nItemId] == nSkew )
+ break;
+ }
+
+ if( nItemId <= DIRECTION_SE )
+ {
+ mxDirectionSet->SelectItem( nItemId+1 );
+ }
+ else
+ {
+ mxDirectionSet->SetNoSelection();
+ }
+
+ if (bEnabled)
+ mxDirectionSet->Enable();
+ else
+ mxDirectionSet->Disable();
+}
+
+void ExtrusionDirectionWindow::implSetProjection( sal_Int32 nProjection, bool bEnabled )
+{
+ mxPerspective->set_active(nProjection == 0 && bEnabled);
+ mxParallel->set_active(nProjection == 1 && bEnabled);
+ mxPerspective->set_sensitive(bEnabled);
+ mxParallel->set_sensitive(bEnabled);
+}
+
+void ExtrusionDirectionWindow::statusChanged(
+ const css::frame::FeatureStateEvent& Event
+)
+{
+ if( Event.FeatureURL.Main == g_sExtrusionDirection )
+ {
+ if( !Event.IsEnabled )
+ {
+ implSetDirection( -1, false );
+ }
+ else
+ {
+ sal_Int32 nValue = 0;
+ if( Event.State >>= nValue )
+ implSetDirection( nValue, true );
+ }
+ }
+ else if( Event.FeatureURL.Main == g_sExtrusionProjection )
+ {
+ if( !Event.IsEnabled )
+ {
+ implSetProjection( -1, false );
+ }
+ else
+ {
+ sal_Int32 nValue = 0;
+ if( Event.State >>= nValue )
+ implSetProjection( nValue, true );
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ExtrusionDirectionWindow, SelectValueSetHdl, ValueSet*, void)
+{
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
+ OUString(g_sExtrusionDirection).copy(5),
+ gSkewList[mxDirectionSet->GetSelectedItemId()-1]) };
+
+ mxControl->dispatchCommand( g_sExtrusionDirection, aArgs );
+
+ mxControl->EndPopupMode();
+}
+
+IMPL_LINK_NOARG(ExtrusionDirectionWindow, SelectToolbarMenuHdl, weld::Toggleable&, void)
+{
+ int nProjection = mxPerspective->get_active() ? 0 : 1;
+
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
+ OUString(g_sExtrusionProjection).copy(5), static_cast<sal_Int32>(nProjection)) };
+
+ mxControl->dispatchCommand( g_sExtrusionProjection, aArgs );
+ implSetProjection( nProjection, true );
+
+ mxControl->EndPopupMode();
+}
+
+ExtrusionDirectionControl::ExtrusionDirectionControl(
+ const Reference< XComponentContext >& rxContext
+) : svt::PopupWindowController(
+ rxContext,
+ Reference< css::frame::XFrame >(),
+ ".uno:ExtrusionDirectionFloater"
+ )
+{
+}
+
+std::unique_ptr<WeldToolbarPopup> ExtrusionDirectionControl::weldPopupWindow()
+{
+ return std::make_unique<ExtrusionDirectionWindow>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> ExtrusionDirectionControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<ExtrusionDirectionWindow>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+// XInitialization
+void SAL_CALL ExtrusionDirectionControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::PopupWindowController::initialize( aArguments );
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if ( getToolboxId( nId, &pToolBox ) )
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+}
+
+// XServiceInfo
+
+
+OUString ExtrusionDirectionControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.ExtrusionDirectionController";
+}
+
+
+Sequence< OUString > ExtrusionDirectionControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_ExtrusionDirectionControl_get_implementation(
+ css::uno::XComponentContext* xContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ExtrusionDirectionControl(xContext));
+}
+
+
+ExtrusionDepthDialog::ExtrusionDepthDialog(weld::Window* pParent, double fDepth, FieldUnit eDefaultUnit)
+ : GenericDialogController(pParent, "svx/ui/extrustiondepthdialog.ui", "ExtrustionDepthDialog")
+ , m_xMtrDepth(m_xBuilder->weld_metric_spin_button("depth", eDefaultUnit))
+{
+ m_xMtrDepth->set_value(static_cast<int>(fDepth) * 100, FieldUnit::MM_100TH);
+}
+
+ExtrusionDepthDialog::~ExtrusionDepthDialog()
+{
+}
+
+double ExtrusionDepthDialog::getDepth() const
+{
+ return static_cast<double>(m_xMtrDepth->get_value(FieldUnit::MM_100TH)) / 100.0;
+}
+
+double const aDepthListInch[] = { 0, 1270,2540,5080,10160 };
+double const aDepthListMM[] = { 0, 1000, 2500, 5000, 10000 };
+
+constexpr OUStringLiteral gsExtrusionDepth( u".uno:ExtrusionDepth" );
+constexpr OUStringLiteral gsMetricUnit( u".uno:MetricUnit" );
+
+ExtrusionDepthWindow::ExtrusionDepthWindow(svt::PopupWindowController* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/depthwindow.ui", "DepthWindow")
+ , mxControl(pControl)
+ , mxDepth0(m_xBuilder->weld_radio_button("depth0"))
+ , mxDepth1(m_xBuilder->weld_radio_button("depth1"))
+ , mxDepth2(m_xBuilder->weld_radio_button("depth2"))
+ , mxDepth3(m_xBuilder->weld_radio_button("depth3"))
+ , mxDepth4(m_xBuilder->weld_radio_button("depth4"))
+ , mxInfinity(m_xBuilder->weld_radio_button("infinity"))
+ , mxCustom(m_xBuilder->weld_radio_button("custom"))
+ , meUnit(FieldUnit::NONE)
+ , mfDepth( -1.0 )
+ , mbSettingValue(false)
+ , mbCommandDispatched(false)
+{
+ mxDepth0->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl));
+ mxDepth1->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl));
+ mxDepth2->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl));
+ mxDepth3->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl));
+ mxDepth4->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl));
+ mxInfinity->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl));
+ mxCustom->connect_toggled(LINK(this, ExtrusionDepthWindow, SelectHdl));
+ mxCustom->connect_mouse_release(LINK(this, ExtrusionDepthWindow, MouseReleaseHdl));
+
+ AddStatusListener( gsExtrusionDepth );
+ AddStatusListener( gsMetricUnit );
+}
+
+void ExtrusionDepthWindow::GrabFocus()
+{
+ mxDepth0->grab_focus();
+}
+
+void ExtrusionDepthWindow::implSetDepth( double fDepth )
+{
+ mfDepth = fDepth;
+
+ bool bSettingValue = mbSettingValue;
+ mbSettingValue = true;
+
+ mxCustom->set_active(true);
+ bool bIsMetric = IsMetric(meUnit);
+ mxDepth0->set_active(fDepth == (bIsMetric ? aDepthListMM[0] : aDepthListInch[0]));
+ mxDepth1->set_active(fDepth == (bIsMetric ? aDepthListMM[1] : aDepthListInch[1]));
+ mxDepth2->set_active(fDepth == (bIsMetric ? aDepthListMM[2] : aDepthListInch[2]));
+ mxDepth3->set_active(fDepth == (bIsMetric ? aDepthListMM[3] : aDepthListInch[3]));
+ mxDepth4->set_active(fDepth == (bIsMetric ? aDepthListMM[4] : aDepthListInch[4]));
+ mxInfinity->set_active(fDepth >= 338666);
+
+ mbSettingValue = bSettingValue;
+}
+
+void ExtrusionDepthWindow::implFillStrings( FieldUnit eUnit )
+{
+ meUnit = eUnit;
+
+ const TranslateId aDepths[] =
+ {
+ RID_SVXSTR_DEPTH_0,
+ RID_SVXSTR_DEPTH_1,
+ RID_SVXSTR_DEPTH_2,
+ RID_SVXSTR_DEPTH_3,
+ RID_SVXSTR_DEPTH_4
+ };
+
+ const TranslateId aDepthsInch[] =
+ {
+ RID_SVXSTR_DEPTH_0_INCH,
+ RID_SVXSTR_DEPTH_1_INCH,
+ RID_SVXSTR_DEPTH_2_INCH,
+ RID_SVXSTR_DEPTH_3_INCH,
+ RID_SVXSTR_DEPTH_4_INCH
+ };
+
+ static_assert(SAL_N_ELEMENTS(aDepths) == SAL_N_ELEMENTS(aDepthsInch));
+
+ const TranslateId* pResource = IsMetric(eUnit) ? aDepths : aDepthsInch;
+
+ mxDepth0->set_label(SvxResId(pResource[0]));
+ mxDepth1->set_label(SvxResId(pResource[1]));
+ mxDepth2->set_label(SvxResId(pResource[2]));
+ mxDepth3->set_label(SvxResId(pResource[3]));
+ mxDepth4->set_label(SvxResId(pResource[4]));
+}
+
+void ExtrusionDepthWindow::statusChanged(
+ const css::frame::FeatureStateEvent& Event
+)
+{
+ if( Event.FeatureURL.Main == gsExtrusionDepth )
+ {
+ if( !Event.IsEnabled )
+ {
+ implSetDepth( 0 );
+ }
+ else
+ {
+ double fValue = 0.0;
+ if( Event.State >>= fValue )
+ implSetDepth( fValue );
+ }
+ }
+ else if( Event.FeatureURL.Main == gsMetricUnit )
+ {
+ if( Event.IsEnabled )
+ {
+ sal_Int32 nValue = 0;
+ if( Event.State >>= nValue )
+ {
+ implFillStrings( static_cast<FieldUnit>(nValue) );
+ if( mfDepth >= 0.0 )
+ implSetDepth( mfDepth );
+ }
+ }
+ }
+}
+
+void ExtrusionDepthWindow::DispatchDepthDialog()
+{
+ Sequence< PropertyValue > aArgs{
+ comphelper::makePropertyValue("Depth", mfDepth),
+ comphelper::makePropertyValue("Metric", static_cast<sal_Int32>( meUnit ))
+ };
+
+ rtl::Reference<svt::PopupWindowController> xControl(mxControl);
+ xControl->EndPopupMode();
+ xControl->dispatchCommand(".uno:ExtrusionDepthDialog", aArgs);
+ mbCommandDispatched = true;
+}
+
+IMPL_LINK(ExtrusionDepthWindow, SelectHdl, weld::Toggleable&, rButton, void)
+{
+ if (mbSettingValue || !rButton.get_active())
+ return;
+
+ // see MouseReleaseHdl for mbCommandDispatched check, there's no guarantee
+ // this toggle will happen before that mouse release though it does in
+ // practice for vcl and gtk
+ if (mbCommandDispatched)
+ return;
+
+ if (mxCustom->get_active())
+ DispatchDepthDialog();
+ else
+ {
+ double fDepth;
+
+ if (mxInfinity->get_active())
+ {
+ fDepth = 338666.6;
+ }
+ else
+ {
+ int nSelected;
+ if (mxDepth0->get_active())
+ nSelected = 0;
+ else if (mxDepth1->get_active())
+ nSelected = 1;
+ else if (mxDepth2->get_active())
+ nSelected = 2;
+ else if (mxDepth3->get_active())
+ nSelected = 3;
+ else
+ nSelected = 4;
+
+ fDepth = IsMetric( meUnit ) ? aDepthListMM[nSelected] : aDepthListInch[nSelected];
+ }
+
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
+ OUString(gsExtrusionDepth).copy(5), fDepth) };
+
+ mxControl->dispatchCommand( gsExtrusionDepth, aArgs );
+ mbCommandDispatched = true;
+ implSetDepth( fDepth );
+
+ mxControl->EndPopupMode();
+ }
+}
+
+IMPL_LINK_NOARG(ExtrusionDepthWindow, MouseReleaseHdl, const MouseEvent&, bool)
+{
+ /*
+ tdf#145296 if the "custom" radiobutton was presented preselected as
+ toggled on and the user clicked on it then there's no toggled signal sent
+ because the item was already toggled on and didn't change state.
+
+ So if that happens launch the custom spacing dialog explicitly here on
+ mouse release.
+ */
+ if (mxCustom->get_active() && !mbCommandDispatched)
+ {
+ DispatchDepthDialog();
+ return true;
+ }
+ return false;
+}
+
+// ExtrusionDirectionControl
+ExtrusionDepthController::ExtrusionDepthController(
+ const Reference< XComponentContext >& rxContext
+) : svt::PopupWindowController(
+ rxContext,
+ Reference< css::frame::XFrame >(),
+ ".uno:ExtrusionDepthFloater"
+ )
+{
+}
+
+std::unique_ptr<WeldToolbarPopup> ExtrusionDepthController::weldPopupWindow()
+{
+ return std::make_unique<ExtrusionDepthWindow>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> ExtrusionDepthController::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<ExtrusionDepthWindow>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+// XInitialization
+void SAL_CALL ExtrusionDepthController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::PopupWindowController::initialize( aArguments );
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if ( getToolboxId( nId, &pToolBox ) )
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+}
+
+// XServiceInfo
+
+
+OUString ExtrusionDepthController::getImplementationName()
+{
+ return "com.sun.star.comp.svx.ExtrusionDepthController";
+}
+
+
+Sequence< OUString > ExtrusionDepthController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_ExtrusionDepthController_get_implementation(
+ css::uno::XComponentContext* xContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ExtrusionDepthController(xContext));
+}
+
+
+constexpr OUStringLiteral g_sExtrusionLightingDirection = u".uno:ExtrusionLightingDirection";
+constexpr OUStringLiteral g_sExtrusionLightingIntensity = u".uno:ExtrusionLightingIntensity";
+
+ExtrusionLightingWindow::ExtrusionLightingWindow(svt::PopupWindowController* pControl,
+ weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/lightingwindow.ui", "LightingWindow")
+ , mxControl(pControl)
+ , mxLightingSet(new ValueSet(nullptr))
+ , mxLightingSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxLightingSet))
+ , mxBright(m_xBuilder->weld_radio_button("bright"))
+ , mxNormal(m_xBuilder->weld_radio_button("normal"))
+ , mxDim(m_xBuilder->weld_radio_button("dim"))
+{
+ mxLightingSet->SetStyle(WB_TABSTOP | WB_MENUSTYLEVALUESET | WB_FLATVALUESET | WB_NOBORDER | WB_NO_DIRECTSELECT);
+
+ for (sal_uInt16 i = FROM_TOP_LEFT; i <= FROM_BOTTOM_RIGHT; ++i)
+ {
+ if( i != FROM_FRONT )
+ {
+ maImgLightingOff[i] = Image(StockImage::Yes, OUString(aLightOffBmps[i]));
+ maImgLightingOn[i] = Image(StockImage::Yes, OUString(aLightOnBmps[i]));
+ }
+ maImgLightingPreview[i] = Image(StockImage::Yes, OUString(aLightPreviewBmps[i]));
+ }
+
+ mxLightingSet->SetHelpId( HID_VALUESET_EXTRUSION_LIGHTING );
+
+ mxLightingSet->SetSelectHdl( LINK( this, ExtrusionLightingWindow, SelectValueSetHdl ) );
+ mxLightingSet->SetColCount( 3 );
+ mxLightingSet->EnableFullItemMode( false );
+
+ for (sal_uInt16 i = FROM_TOP_LEFT; i <= FROM_BOTTOM_RIGHT; ++i)
+ {
+ if( i != FROM_FRONT )
+ {
+ mxLightingSet->InsertItem( i+1, maImgLightingOff[i] );
+ }
+ else
+ {
+ mxLightingSet->InsertItem( 5, maImgLightingPreview[FROM_FRONT] );
+ }
+ }
+ Size aSize(72, 72);
+ mxLightingSet->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height());
+ mxLightingSet->SetOutputSizePixel(aSize);
+
+ mxBright->connect_toggled(LINK(this, ExtrusionLightingWindow, SelectToolbarMenuHdl));
+ mxNormal->connect_toggled(LINK(this, ExtrusionLightingWindow, SelectToolbarMenuHdl));
+ mxDim->connect_toggled(LINK(this, ExtrusionLightingWindow, SelectToolbarMenuHdl));
+
+ AddStatusListener( g_sExtrusionLightingDirection );
+ AddStatusListener( g_sExtrusionLightingIntensity );
+}
+
+void ExtrusionLightingWindow::GrabFocus()
+{
+ mxLightingSet->GrabFocus();
+}
+
+ExtrusionLightingWindow::~ExtrusionLightingWindow()
+{
+}
+
+void ExtrusionLightingWindow::implSetIntensity( int nLevel, bool bEnabled )
+{
+ mxBright->set_sensitive(bEnabled);
+ mxBright->set_active(nLevel == 0 && bEnabled);
+ mxNormal->set_sensitive(bEnabled);
+ mxNormal->set_active(nLevel == 1 && bEnabled);
+ mxDim->set_sensitive(bEnabled);
+ mxDim->set_active(nLevel == 2 && bEnabled);
+}
+
+void ExtrusionLightingWindow::implSetDirection( int nDirection, bool bEnabled )
+{
+ if( !bEnabled )
+ nDirection = FROM_FRONT;
+
+ sal_uInt16 nItemId;
+ for( nItemId = FROM_TOP_LEFT; nItemId <= FROM_BOTTOM_RIGHT; nItemId++ )
+ {
+ if( nItemId == FROM_FRONT )
+ {
+ mxLightingSet->SetItemImage( nItemId + 1, maImgLightingPreview[ nDirection ] );
+ }
+ else
+ {
+ mxLightingSet->SetItemImage(
+ nItemId + 1,
+ static_cast<sal_uInt16>(nDirection) == nItemId ? maImgLightingOn[nItemId] : maImgLightingOff[nItemId]
+ );
+ }
+ }
+
+ if (bEnabled)
+ mxLightingSet->Enable();
+ else
+ mxLightingSet->Disable();
+}
+
+void ExtrusionLightingWindow::statusChanged(
+ const css::frame::FeatureStateEvent& Event
+)
+{
+ if( Event.FeatureURL.Main == g_sExtrusionLightingIntensity )
+ {
+ if( !Event.IsEnabled )
+ {
+ implSetIntensity( 0, false );
+ }
+ else
+ {
+ sal_Int32 nValue = 0;
+ if( Event.State >>= nValue )
+ implSetIntensity( nValue, true );
+ }
+ }
+ else if( Event.FeatureURL.Main == g_sExtrusionLightingDirection )
+ {
+ if( !Event.IsEnabled )
+ {
+ implSetDirection( 0, false );
+ }
+ else
+ {
+ sal_Int32 nValue = 0;
+ if( Event.State >>= nValue )
+ implSetDirection( nValue, true );
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ExtrusionLightingWindow, SelectValueSetHdl, ValueSet*, void)
+{
+ sal_Int32 nDirection = mxLightingSet->GetSelectedItemId();
+
+ if( (nDirection > 0) && (nDirection < 10) )
+ {
+ nDirection--;
+
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
+ OUString(g_sExtrusionLightingDirection).copy(5), nDirection) };
+
+ mxControl->dispatchCommand( g_sExtrusionLightingDirection, aArgs );
+
+ implSetDirection( nDirection, true );
+ }
+
+ mxControl->EndPopupMode();
+}
+
+IMPL_LINK(ExtrusionLightingWindow, SelectToolbarMenuHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+
+ int nLevel;
+ if (mxBright->get_active())
+ nLevel = 0;
+ else if (mxNormal->get_active())
+ nLevel = 1;
+ else
+ nLevel = 2;
+
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
+ OUString(g_sExtrusionLightingIntensity).copy(5), static_cast<sal_Int32>(nLevel)) };
+
+ mxControl->dispatchCommand( g_sExtrusionLightingIntensity, aArgs );
+
+ implSetIntensity( nLevel, true );
+
+ mxControl->EndPopupMode();
+}
+
+ExtrusionLightingControl::ExtrusionLightingControl(
+ const Reference< XComponentContext >& rxContext
+) : svt::PopupWindowController( rxContext,
+ Reference< css::frame::XFrame >(),
+ ".uno:ExtrusionDirectionFloater"
+ )
+{
+}
+
+std::unique_ptr<WeldToolbarPopup> ExtrusionLightingControl::weldPopupWindow()
+{
+ return std::make_unique<ExtrusionLightingWindow>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> ExtrusionLightingControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<ExtrusionLightingWindow>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+// XInitialization
+void SAL_CALL ExtrusionLightingControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::PopupWindowController::initialize( aArguments );
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if ( getToolboxId( nId, &pToolBox ) )
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+}
+
+// XServiceInfo
+
+
+OUString ExtrusionLightingControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.ExtrusionLightingController";
+}
+
+
+Sequence< OUString > ExtrusionLightingControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_ExtrusionLightingControl_get_implementation(
+ css::uno::XComponentContext* xContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ExtrusionLightingControl(xContext));
+}
+
+
+constexpr OUStringLiteral g_sExtrusionSurface = u".uno:ExtrusionSurface";
+
+ExtrusionSurfaceWindow::ExtrusionSurfaceWindow(svt::PopupWindowController* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/surfacewindow.ui", "SurfaceWindow")
+ , mxControl(pControl)
+ , mxWireFrame(m_xBuilder->weld_radio_button("wireframe"))
+ , mxMatt(m_xBuilder->weld_radio_button("matt"))
+ , mxPlastic(m_xBuilder->weld_radio_button("plastic"))
+ , mxMetal(m_xBuilder->weld_radio_button("metal"))
+ , mxMetalMSO(m_xBuilder->weld_radio_button("metalMSO"))
+{
+ mxWireFrame->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl));
+ mxMatt->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl));
+ mxPlastic->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl));
+ mxMetal->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl));
+ mxMetalMSO->connect_toggled(LINK(this, ExtrusionSurfaceWindow, SelectHdl));
+
+ AddStatusListener( g_sExtrusionSurface );
+}
+
+void ExtrusionSurfaceWindow::GrabFocus()
+{
+ mxWireFrame->grab_focus();
+}
+
+void ExtrusionSurfaceWindow::implSetSurface( int nSurface, bool bEnabled )
+{
+ mxWireFrame->set_active(nSurface == 0 && bEnabled);
+ mxWireFrame->set_sensitive(bEnabled);
+ mxMatt->set_active(nSurface == 1 && bEnabled);
+ mxMatt->set_sensitive(bEnabled);
+ mxPlastic->set_active(nSurface == 2 && bEnabled);
+ mxPlastic->set_sensitive(bEnabled);
+ mxMetal->set_active(nSurface == 3 && bEnabled);
+ mxMetal->set_sensitive(bEnabled);
+ mxMetalMSO->set_active(nSurface == 4 && bEnabled);
+ mxMetalMSO->set_sensitive(bEnabled);
+}
+
+void ExtrusionSurfaceWindow::statusChanged(
+ const css::frame::FeatureStateEvent& Event
+)
+{
+ if( Event.FeatureURL.Main != g_sExtrusionSurface )
+ return;
+
+ if( !Event.IsEnabled )
+ {
+ implSetSurface( 0, false );
+ }
+ else
+ {
+ sal_Int32 nValue = 0;
+ if( Event.State >>= nValue )
+ implSetSurface( nValue, true );
+ }
+}
+
+IMPL_LINK(ExtrusionSurfaceWindow, SelectHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+
+ sal_Int32 nSurface;
+ if (mxWireFrame->get_active())
+ nSurface = 0;
+ else if (mxMatt->get_active())
+ nSurface = 1;
+ else if (mxPlastic->get_active())
+ nSurface = 2;
+ else if (mxMetal->get_active())
+ nSurface = 3;
+ else
+ nSurface = 4;
+
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
+ OUString(g_sExtrusionSurface).copy(5), nSurface) };
+
+ mxControl->dispatchCommand( g_sExtrusionSurface, aArgs );
+
+ implSetSurface( nSurface, true );
+
+ mxControl->EndPopupMode();
+}
+
+ExtrusionSurfaceControl::ExtrusionSurfaceControl(
+ const Reference< XComponentContext >& rxContext
+)
+: svt::PopupWindowController(
+ rxContext,
+ Reference< css::frame::XFrame >(),
+ ".uno:ExtrusionSurfaceFloater"
+ )
+{
+}
+
+std::unique_ptr<WeldToolbarPopup> ExtrusionSurfaceControl::weldPopupWindow()
+{
+ return std::make_unique<ExtrusionSurfaceWindow>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> ExtrusionSurfaceControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<ExtrusionSurfaceWindow>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+// XInitialization
+void SAL_CALL ExtrusionSurfaceControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::PopupWindowController::initialize( aArguments );
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if ( getToolboxId( nId, &pToolBox ) )
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+}
+
+// XServiceInfo
+
+
+OUString ExtrusionSurfaceControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.ExtrusionSurfaceController";
+}
+
+
+Sequence< OUString > ExtrusionSurfaceControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_ExtrusionSurfaceControl_get_implementation(
+ css::uno::XComponentContext* xContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ExtrusionSurfaceControl(xContext));
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/extrusioncontrols.hxx b/svx/source/tbxctrls/extrusioncontrols.hxx
new file mode 100644
index 000000000..8b7c2e8af
--- /dev/null
+++ b/svx/source/tbxctrls/extrusioncontrols.hxx
@@ -0,0 +1,224 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_TBXCTRLS_EXTRUSIONCONTROLS_HXX
+#define INCLUDED_SVX_SOURCE_TBXCTRLS_EXTRUSIONCONTROLS_HXX
+
+#include <svtools/toolbarmenu.hxx>
+#include <svtools/popupwindowcontroller.hxx>
+#include <svtools/valueset.hxx>
+#include <vcl/customweld.hxx>
+
+// enum to index light images
+#define FROM_TOP_LEFT 0
+#define FROM_TOP 1
+#define FROM_TOP_RIGHT 2
+#define FROM_LEFT 3
+#define FROM_FRONT 4
+#define FROM_RIGHT 5
+#define FROM_BOTTOM_LEFT 6
+#define FROM_BOTTOM 7
+#define FROM_BOTTOM_RIGHT 8
+
+#define DIRECTION_NW 0
+#define DIRECTION_N 1
+#define DIRECTION_NE 2
+#define DIRECTION_W 3
+#define DIRECTION_NONE 4
+#define DIRECTION_E 5
+#define DIRECTION_SW 6
+#define DIRECTION_S 7
+#define DIRECTION_SE 8
+
+namespace svx
+{
+class ExtrusionDirectionWindow final : public WeldToolbarPopup
+{
+public:
+ ExtrusionDirectionWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow);
+ virtual void GrabFocus() override;
+ virtual ~ExtrusionDirectionWindow() override;
+
+ virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+
+private:
+ rtl::Reference<svt::PopupWindowController> mxControl;
+ std::unique_ptr<ValueSet> mxDirectionSet;
+ std::unique_ptr<weld::CustomWeld> mxDirectionSetWin;
+ std::unique_ptr<weld::RadioButton> mxPerspective;
+ std::unique_ptr<weld::RadioButton> mxParallel;
+
+ Image maImgDirection[9];
+
+ DECL_LINK( SelectToolbarMenuHdl, weld::Toggleable&, void );
+ DECL_LINK( SelectValueSetHdl, ValueSet*, void );
+
+ void implSetDirection( sal_Int32 nSkew, bool bEnabled );
+ void implSetProjection( sal_Int32 nProjection, bool bEnabled );
+
+};
+
+class ExtrusionDirectionControl : public svt::PopupWindowController
+{
+public:
+ explicit ExtrusionDirectionControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+class ExtrusionDepthWindow final : public WeldToolbarPopup
+{
+private:
+ rtl::Reference<svt::PopupWindowController> mxControl;
+ std::unique_ptr<weld::RadioButton> mxDepth0;
+ std::unique_ptr<weld::RadioButton> mxDepth1;
+ std::unique_ptr<weld::RadioButton> mxDepth2;
+ std::unique_ptr<weld::RadioButton> mxDepth3;
+ std::unique_ptr<weld::RadioButton> mxDepth4;
+ std::unique_ptr<weld::RadioButton> mxInfinity;
+ std::unique_ptr<weld::RadioButton> mxCustom;
+
+ FieldUnit meUnit;
+ double mfDepth;
+ bool mbSettingValue;
+ bool mbCommandDispatched;
+
+ DECL_LINK( SelectHdl, weld::Toggleable&, void );
+ DECL_LINK( MouseReleaseHdl, const MouseEvent&, bool );
+
+ void implFillStrings( FieldUnit eUnit );
+ void implSetDepth( double fDepth );
+
+ void DispatchDepthDialog();
+
+public:
+ ExtrusionDepthWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow);
+ virtual void GrabFocus() override;
+
+ virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+};
+
+class ExtrusionDepthController : public svt::PopupWindowController
+{
+public:
+ explicit ExtrusionDepthController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+class ExtrusionLightingWindow final : public WeldToolbarPopup
+{
+private:
+ rtl::Reference<svt::PopupWindowController> mxControl;
+ std::unique_ptr<ValueSet> mxLightingSet;
+ std::unique_ptr<weld::CustomWeld> mxLightingSetWin;
+ std::unique_ptr<weld::RadioButton> mxBright;
+ std::unique_ptr<weld::RadioButton> mxNormal;
+ std::unique_ptr<weld::RadioButton> mxDim;
+
+ Image maImgLightingOff[9];
+ Image maImgLightingOn[9];
+ Image maImgLightingPreview[9];
+
+ void implSetIntensity( int nLevel, bool bEnabled );
+ void implSetDirection( int nDirection, bool bEnabled );
+
+ DECL_LINK( SelectToolbarMenuHdl, weld::Toggleable&, void );
+ DECL_LINK( SelectValueSetHdl, ValueSet*, void );
+public:
+ ExtrusionLightingWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow);
+ virtual void GrabFocus() override;
+ virtual ~ExtrusionLightingWindow() override;
+
+ virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+};
+
+class ExtrusionLightingControl : public svt::PopupWindowController
+{
+public:
+ explicit ExtrusionLightingControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+class ExtrusionSurfaceWindow final : public WeldToolbarPopup
+{
+private:
+ rtl::Reference<svt::PopupWindowController> mxControl;
+ std::unique_ptr<weld::RadioButton> mxWireFrame;
+ std::unique_ptr<weld::RadioButton> mxMatt;
+ std::unique_ptr<weld::RadioButton> mxPlastic;
+ std::unique_ptr<weld::RadioButton> mxMetal;
+ std::unique_ptr<weld::RadioButton> mxMetalMSO;
+
+ DECL_LINK( SelectHdl, weld::Toggleable&, void );
+
+ void implSetSurface( int nSurface, bool bEnabled );
+
+public:
+ ExtrusionSurfaceWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow);
+ virtual void GrabFocus() override;
+
+ virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+};
+
+
+class ExtrusionSurfaceControl : public svt::PopupWindowController
+{
+public:
+ explicit ExtrusionSurfaceControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/fillctrl.cxx b/svx/source/tbxctrls/fillctrl.cxx
new file mode 100644
index 000000000..cfb7583be
--- /dev/null
+++ b/svx/source/tbxctrls/fillctrl.cxx
@@ -0,0 +1,1087 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewsh.hxx>
+#include <rtl/ustring.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/svxids.hrc>
+#include <tools/json_writer.hxx>
+
+constexpr OUStringLiteral TMP_STR_BEGIN = u"[";
+constexpr OUStringLiteral TMP_STR_END = u"]";
+
+#include <svx/drawitem.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xtable.hxx>
+#include <svx/fillctrl.hxx>
+#include <svx/itemwin.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+
+namespace {
+
+enum eFillStyle
+{
+ NONE,
+ SOLID,
+ GRADIENT,
+ HATCH,
+ BITMAP,
+ PATTERN
+};
+
+drawing::FillStyle toCssFillStyle( eFillStyle eXFS )
+{
+ if (eXFS == PATTERN)
+ {
+ return drawing::FillStyle_BITMAP;
+ }
+
+ return static_cast<drawing::FillStyle>(eXFS);
+}
+
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxFillToolBoxControl, XFillStyleItem );
+
+SvxFillToolBoxControl::SvxFillToolBoxControl(
+ sal_uInt16 nSlotId,
+ ToolBoxItemId nId,
+ ToolBox& rTbx )
+ : SfxToolBoxControl( nSlotId, nId, rTbx )
+ , mxFillControl(nullptr)
+ , mpLbFillType(nullptr)
+ , mpToolBoxColor(nullptr)
+ , mpLbFillAttr(nullptr)
+ , mnLastXFS(-1)
+ , mnLastPosGradient(0)
+ , mnLastPosHatch(0)
+ , mnLastPosBitmap(0)
+ , mnLastPosPattern(0)
+{
+ addStatusListener( ".uno:FillColor");
+ addStatusListener( ".uno:FillGradient");
+ addStatusListener( ".uno:FillHatch");
+ addStatusListener( ".uno:FillBitmap");
+ addStatusListener( ".uno:ColorTableState");
+ addStatusListener( ".uno:GradientListState");
+ addStatusListener( ".uno:HatchListState");
+ addStatusListener( ".uno:BitmapListState");
+}
+
+SvxFillToolBoxControl::~SvxFillToolBoxControl()
+{
+}
+
+void SvxFillToolBoxControl::StateChangedAtToolBoxControl(
+ sal_uInt16 nSID,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ const bool bDisabled(SfxItemState::DISABLED == eState);
+
+ switch(nSID)
+ {
+ case SID_ATTR_FILL_STYLE:
+ {
+ if(bDisabled)
+ {
+ mpLbFillType->set_sensitive(false);
+ mpLbFillType->set_active(-1);
+ mpLbFillAttr->show();
+ mpLbFillAttr->set_sensitive(false);
+ mpLbFillAttr->set_active(-1);
+ mpToolBoxColor->hide();
+ mnLastXFS = -1;
+ mpStyleItem.reset();
+ }
+
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ const XFillStyleItem* pItem = dynamic_cast< const XFillStyleItem* >(pState);
+
+ if(pItem)
+ {
+ mpStyleItem.reset(pItem->Clone());
+ mpLbFillType->set_sensitive(true);
+ drawing::FillStyle eXFS = mpStyleItem->GetValue();
+ mnLastXFS = sal::static_int_cast< sal_Int32 >(eXFS);
+ mpLbFillType->set_active(mnLastXFS);
+
+ if(drawing::FillStyle_NONE == eXFS)
+ {
+ mpLbFillAttr->set_active(-1);
+ mpLbFillAttr->set_sensitive(false);
+ }
+
+ Update();
+ break;
+ }
+ }
+
+ mpLbFillType->set_active(-1);
+ mpLbFillAttr->show();
+ mpLbFillAttr->set_sensitive(false);
+ mpLbFillAttr->set_active(-1);
+ mpToolBoxColor->hide();
+ mnLastXFS = -1;
+ mpStyleItem.reset();
+ mxFillControl->Resize();
+ break;
+ }
+ case SID_ATTR_FILL_COLOR:
+ {
+ if(SfxItemState::DEFAULT == eState)
+ {
+ mpColorItem.reset(pState ? static_cast<XFillColorItem*>(pState->Clone()) : nullptr);
+ }
+
+ if(mpStyleItem && drawing::FillStyle_SOLID == mpStyleItem->GetValue())
+ {
+ mpLbFillAttr->hide();
+ mpToolBoxColor->show();
+ mxFillControl->Resize();
+
+ Update();
+ }
+ break;
+ }
+ case SID_ATTR_FILL_GRADIENT:
+ {
+ if(SfxItemState::DEFAULT == eState)
+ {
+ mpFillGradientItem.reset(pState ? static_cast<XFillGradientItem*>(pState->Clone()) : nullptr);
+ }
+
+ if(mpStyleItem && drawing::FillStyle_GRADIENT == mpStyleItem->GetValue())
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+ mxFillControl->Resize();
+
+ if(SfxItemState::DEFAULT == eState)
+ {
+ mpLbFillAttr->set_sensitive(true);
+ Update();
+ }
+ else if(SfxItemState::DISABLED == eState )
+ {
+ mpLbFillAttr->set_sensitive(false);
+ mpLbFillAttr->set_active(-1);
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ }
+ break;
+ }
+ case SID_ATTR_FILL_HATCH:
+ {
+ if(SfxItemState::DEFAULT == eState)
+ {
+ mpHatchItem.reset(pState ? static_cast<XFillHatchItem*>(pState->Clone()) : nullptr);
+ }
+
+ if(mpStyleItem && drawing::FillStyle_HATCH == mpStyleItem->GetValue())
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+ mxFillControl->Resize();
+
+ if(SfxItemState::DEFAULT == eState)
+ {
+ mpLbFillAttr->set_sensitive(true);
+ Update();
+ }
+ else if(SfxItemState::DISABLED == eState )
+ {
+ mpLbFillAttr->set_sensitive(false);
+ mpLbFillAttr->set_active(-1);
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ }
+ break;
+ }
+ case SID_ATTR_FILL_BITMAP:
+ {
+ if(SfxItemState::DEFAULT == eState)
+ {
+ mpBitmapItem.reset(pState ? static_cast<XFillBitmapItem*>(pState->Clone()) : nullptr);
+ }
+
+ if(mpStyleItem && drawing::FillStyle_BITMAP == mpStyleItem->GetValue())
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+ mxFillControl->Resize();
+
+ if(SfxItemState::DEFAULT == eState)
+ {
+ mpLbFillAttr->set_sensitive(true);
+ Update();
+ }
+ else if(SfxItemState::DISABLED == eState )
+ {
+ mpLbFillAttr->set_sensitive(false);
+ mpLbFillAttr->set_active(-1);
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ }
+ break;
+ }
+ case SID_GRADIENT_LIST:
+ {
+ if(SfxItemState::DEFAULT == eState)
+ {
+ if(mpStyleItem && drawing::FillStyle_GRADIENT == mpStyleItem->GetValue())
+ {
+ if(mpFillGradientItem)
+ {
+ const OUString aString( mpFillGradientItem->GetName() );
+ mpLbFillAttr->clear();
+ if (const SfxObjectShell* pSh = SfxObjectShell::Current())
+ {
+ mpLbFillAttr->set_sensitive(true);
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_GRADIENT_LIST)->GetGradientList());
+ }
+ mpLbFillAttr->set_active_text(aString);
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ }
+ }
+ break;
+ }
+ case SID_HATCH_LIST:
+ {
+ if(SfxItemState::DEFAULT == eState)
+ {
+ if(mpStyleItem && drawing::FillStyle_HATCH == mpStyleItem->GetValue())
+ {
+ if(mpHatchItem)
+ {
+ const OUString aString( mpHatchItem->GetName() );
+ mpLbFillAttr->clear();
+ if (const SfxObjectShell* pSh = SfxObjectShell::Current())
+ {
+ mpLbFillAttr->set_sensitive(true);
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_HATCH_LIST)->GetHatchList());
+ }
+ mpLbFillAttr->set_active_text(aString);
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ }
+ }
+ break;
+ }
+ case SID_BITMAP_LIST:
+ {
+ if(SfxItemState::DEFAULT == eState)
+ {
+ if(mpStyleItem && drawing::FillStyle_BITMAP == mpStyleItem->GetValue())
+ {
+ if(mpBitmapItem)
+ {
+ const OUString aString( mpBitmapItem->GetName() );
+ mpLbFillAttr->clear();
+ if (const SfxObjectShell* pSh = SfxObjectShell::Current())
+ {
+ mpLbFillAttr->set_sensitive(true);
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_BITMAP_LIST)->GetBitmapList());
+ }
+ mpLbFillAttr->set_active_text(aString);
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+void SvxFillToolBoxControl::Update()
+{
+ if(!mpStyleItem)
+ return;
+
+ const drawing::FillStyle eXFS = mpStyleItem->GetValue();
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+
+ switch( eXFS )
+ {
+ case drawing::FillStyle_NONE:
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+ mxFillControl->Resize();
+ break;
+ }
+ case drawing::FillStyle_SOLID:
+ {
+ if(mpColorItem)
+ {
+ mpLbFillAttr->hide();
+ mpToolBoxColor->show();
+ mxFillControl->Resize();
+ }
+ break;
+ }
+ case drawing::FillStyle_GRADIENT:
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+ mxFillControl->Resize();
+
+ if(pSh && pSh->GetItem(SID_GRADIENT_LIST))
+ {
+ mpLbFillAttr->set_sensitive(true);
+ mpLbFillAttr->clear();
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_GRADIENT_LIST)->GetGradientList());
+
+ if(mpFillGradientItem)
+ {
+ const OUString aString(mpFillGradientItem->GetName());
+
+ mpLbFillAttr->set_active_text(aString);
+
+ // Check if the entry is not in the list
+ if (mpLbFillAttr->get_active_text() != aString)
+ {
+ sal_Int32 nCount = mpLbFillAttr->get_count();
+ OUString aTmpStr;
+ if( nCount > 0 )
+ {
+ // Last entry gets tested against temporary entry
+ aTmpStr = mpLbFillAttr->get_text( nCount - 1 );
+ if( aTmpStr.startsWith(TMP_STR_BEGIN) &&
+ aTmpStr.endsWith(TMP_STR_END) )
+ {
+ mpLbFillAttr->remove(nCount - 1);
+ }
+ }
+ aTmpStr = TMP_STR_BEGIN + aString + TMP_STR_END;
+
+ rtl::Reference<XGradientList> xGradientList = new XGradientList( "", ""/*TODO?*/ );
+ xGradientList->Insert(std::make_unique<XGradientEntry>(mpFillGradientItem->GetGradientValue(), aTmpStr));
+ xGradientList->SetDirty( false );
+ const BitmapEx aBmp = xGradientList->GetUiBitmap( 0 );
+
+ if (!aBmp.IsEmpty())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ const Size aBmpSize(aBmp.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), aBmp);
+ mpLbFillAttr->append("", xGradientList->Get(0)->GetName(), *pVD);
+ mpLbFillAttr->set_active(mpLbFillAttr->get_count() - 1);
+ }
+ }
+
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ break;
+ }
+ case drawing::FillStyle_HATCH:
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+ mxFillControl->Resize();
+
+ if(pSh && pSh->GetItem(SID_HATCH_LIST))
+ {
+ mpLbFillAttr->set_sensitive(true);
+ mpLbFillAttr->clear();
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_HATCH_LIST)->GetHatchList());
+
+ if(mpHatchItem)
+ {
+ const OUString aString(mpHatchItem->GetName());
+
+ mpLbFillAttr->set_active_text( aString );
+
+ // Check if the entry is not in the list
+ if( mpLbFillAttr->get_active_text() != aString )
+ {
+ const sal_Int32 nCount = mpLbFillAttr->get_count();
+ OUString aTmpStr;
+ if( nCount > 0 )
+ {
+ // Last entry gets tested against temporary entry
+ aTmpStr = mpLbFillAttr->get_text( nCount - 1 );
+ if( aTmpStr.startsWith(TMP_STR_BEGIN) &&
+ aTmpStr.endsWith(TMP_STR_END) )
+ {
+ mpLbFillAttr->remove( nCount - 1 );
+ }
+ }
+ aTmpStr = TMP_STR_BEGIN + aString + TMP_STR_END;
+
+ rtl::Reference<XHatchList> xHatchList = new XHatchList( "", ""/*TODO?*/ );
+ xHatchList->Insert(std::make_unique<XHatchEntry>(mpHatchItem->GetHatchValue(), aTmpStr));
+ xHatchList->SetDirty( false );
+ const BitmapEx & aBmp = xHatchList->GetUiBitmap( 0 );
+
+ if( !aBmp.IsEmpty() )
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ const Size aBmpSize(aBmp.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), aBmp);
+ mpLbFillAttr->append("", xHatchList->GetHatch(0)->GetName(), *pVD);
+ mpLbFillAttr->set_active(mpLbFillAttr->get_count() - 1);
+ }
+ }
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ break;
+ }
+ case drawing::FillStyle_BITMAP:
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+ mxFillControl->Resize();
+
+ if(pSh)
+ {
+ mpLbFillAttr->set_sensitive(true);
+ mpLbFillAttr->clear();
+
+ if(mpBitmapItem && !mpBitmapItem->isPattern() && pSh->GetItem(SID_BITMAP_LIST))
+ {
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_BITMAP_LIST)->GetBitmapList());
+
+ const OUString aString(mpBitmapItem->GetName());
+
+ mpLbFillAttr->set_active_text(aString);
+
+ // Check if the entry is not in the list
+ if (mpLbFillAttr->get_active_text() != aString)
+ {
+ sal_Int32 nCount = mpLbFillAttr->get_count();
+ OUString aTmpStr;
+ if( nCount > 0 )
+ {
+ // Last entry gets tested against temporary entry
+ aTmpStr = mpLbFillAttr->get_text(nCount - 1);
+ if( aTmpStr.startsWith(TMP_STR_BEGIN) &&
+ aTmpStr.endsWith(TMP_STR_END) )
+ {
+ mpLbFillAttr->remove(nCount - 1);
+ }
+ }
+ aTmpStr = TMP_STR_BEGIN + aString + TMP_STR_END;
+
+ XBitmapListRef xBitmapList =
+ XPropertyList::AsBitmapList(
+ XPropertyList::CreatePropertyList(
+ XPropertyListType::Bitmap, "TmpList", ""/*TODO?*/));
+ xBitmapList->Insert(std::make_unique<XBitmapEntry>(mpBitmapItem->GetGraphicObject(), aTmpStr));
+ xBitmapList->SetDirty( false );
+ SvxFillAttrBox::Fill(*mpLbFillAttr, xBitmapList);
+ mpLbFillAttr->set_active(mpLbFillAttr->get_count() - 1);
+ }
+
+ }
+ else if (mpBitmapItem && mpBitmapItem->isPattern() && pSh->GetItem(SID_PATTERN_LIST))
+ {
+ mnLastXFS = sal::static_int_cast<sal_Int32>(PATTERN);
+ mpLbFillType->set_active(mnLastXFS);
+
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_PATTERN_LIST)->GetPatternList());
+ const OUString aString(mpBitmapItem->GetName());
+
+ mpLbFillAttr->set_active_text(aString);
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ }
+ else
+ {
+ mpLbFillAttr->set_active(-1);
+ }
+ break;
+ }
+ default:
+ OSL_ENSURE(false, "Non supported FillType (!)");
+ break;
+ }
+
+}
+
+VclPtr<InterimItemWindow> SvxFillToolBoxControl::CreateItemWindow(vcl::Window *pParent)
+{
+ if(GetSlotId() == SID_ATTR_FILL_STYLE)
+ {
+ mxFillControl.reset(VclPtr<FillControl>::Create(pParent, m_xFrame));
+
+ mpLbFillType = mxFillControl->mxLbFillType.get();
+ mpLbFillAttr = mxFillControl->mxLbFillAttr.get();
+ mpToolBoxColor = mxFillControl->mxToolBoxColor.get();
+
+ mpLbFillType->connect_changed(LINK(this,SvxFillToolBoxControl,SelectFillTypeHdl));
+ mpLbFillAttr->connect_changed(LINK(this,SvxFillToolBoxControl,SelectFillAttrHdl));
+
+
+ return mxFillControl;
+ }
+ return VclPtr<InterimItemWindow>();
+}
+
+FillControl::FillControl(vcl::Window* pParent, const css::uno::Reference<css::frame::XFrame>& rFrame)
+ : InterimItemWindow(pParent, "svx/ui/fillctrlbox.ui", "FillCtrlBox")
+ , mxLbFillType(m_xBuilder->weld_combo_box("type"))
+ , mxToolBoxColor(m_xBuilder->weld_toolbar("color"))
+ , mxColorDispatch(new ToolbarUnoDispatcher(*mxToolBoxColor, *m_xBuilder, rFrame))
+ , mxLbFillAttr(m_xBuilder->weld_combo_box("attr"))
+ , mnTypeCurPos(0)
+ , mnAttrCurPos(0)
+{
+ InitControlBase(mxLbFillType.get());
+
+ mxLbFillAttr->connect_key_press(LINK(this, FillControl, AttrKeyInputHdl));
+ mxLbFillType->connect_key_press(LINK(this, FillControl, TypeKeyInputHdl));
+ mxToolBoxColor->connect_key_press(LINK(this, FillControl, ColorKeyInputHdl));
+
+ mxLbFillType->connect_get_property_tree(LINK(this, FillControl, DumpAsPropertyTreeHdl));
+
+ mxLbFillType->connect_focus_in(LINK(this, FillControl, TypeFocusHdl));
+ mxLbFillAttr->connect_focus_in(LINK(this, FillControl, AttrFocusHdl));
+
+ SvxFillTypeBox::Fill(*mxLbFillType);
+
+ SetOptimalSize();
+}
+
+IMPL_STATIC_LINK(FillControl, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void)
+{
+ rJsonWriter.put("command", ".uno:FillStyle");
+}
+
+void FillControl::ReleaseFocus_Impl()
+{
+ SfxViewShell* pCurSh = SfxViewShell::Current();
+ if (pCurSh)
+ {
+ vcl::Window* pShellWnd = pCurSh->GetWindow();
+ if (pShellWnd)
+ pShellWnd->GrabFocus();
+ }
+}
+
+IMPL_LINK(FillControl, TypeKeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ sal_uInt16 nCode = rKeyCode.GetCode();
+
+ if (nCode == KEY_ESCAPE)
+ {
+ mxLbFillType->set_active(mnTypeCurPos);
+ ReleaseFocus_Impl();
+ return true;
+ }
+
+ if (nCode != KEY_TAB)
+ return false;
+ if (rKeyCode.IsShift())
+ return ChildKeyInput(rKEvt);
+ if (mxLbFillAttr->get_visible() && !mxLbFillAttr->get_sensitive())
+ return ChildKeyInput(rKEvt);
+ return false;
+}
+
+IMPL_LINK_NOARG(FillControl, TypeFocusHdl, weld::Widget&, void)
+{
+ mnTypeCurPos = mxLbFillType->get_active();
+}
+
+IMPL_LINK_NOARG(FillControl, AttrFocusHdl, weld::Widget&, void)
+{
+ mnAttrCurPos = mxLbFillAttr->get_active();
+}
+
+IMPL_LINK(FillControl, AttrKeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ sal_uInt16 nCode = rKeyCode.GetCode();
+
+ if (nCode == KEY_ESCAPE)
+ {
+ mxLbFillAttr->set_active(mnAttrCurPos);
+ ReleaseFocus_Impl();
+ return true;
+ }
+
+ return ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK(FillControl, ColorKeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return ChildKeyInput(rKEvt);
+}
+
+FillControl::~FillControl()
+{
+ disposeOnce();
+}
+
+void FillControl::dispose()
+{
+ mxLbFillAttr.reset();
+ mxColorDispatch.reset();
+ mxToolBoxColor.reset();
+ mxLbFillType.reset();
+ InterimItemWindow::dispose();
+}
+
+IMPL_LINK_NOARG(SvxFillToolBoxControl, SelectFillTypeHdl, weld::ComboBox&, void)
+{
+ sal_Int32 nXFS = mpLbFillType->get_active();
+
+ if(mnLastXFS == nXFS)
+ return;
+
+ eFillStyle eXFS = static_cast<eFillStyle>(nXFS);
+ mpLbFillAttr->clear();
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ const XFillStyleItem aXFillStyleItem(toCssFillStyle(eXFS));
+
+ // #i122676# Do no longer trigger two Execute calls, one for SID_ATTR_FILL_STYLE
+ // and one for setting the fill attribute itself, but add two SfxPoolItems to the
+ // call to get just one action at the SdrObject and to create only one Undo action, too.
+ // Checked that this works in all apps.
+ switch( eXFS )
+ {
+ default:
+ case NONE:
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+ mpLbFillAttr->set_sensitive(false);
+ if (pSh)
+ {
+ // #i122676# need to call a single SID_ATTR_FILL_STYLE change
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_STYLE, SfxCallMode::RECORD,
+ { &aXFillStyleItem });
+ }
+ break;
+ }
+ case SOLID:
+ {
+ mpLbFillAttr->hide();
+ mpToolBoxColor->show();
+ if (pSh)
+ {
+ const ::Color aColor = mpColorItem ? mpColorItem->GetColorValue() : COL_AUTO;
+ const XFillColorItem aXFillColorItem( "", aColor );
+
+ // #i122676# change FillStyle and Color in one call
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_COLOR, SfxCallMode::RECORD,
+ { &aXFillColorItem, &aXFillStyleItem });
+ }
+ break;
+ }
+ case GRADIENT:
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+
+ if(pSh && pSh->GetItem(SID_GRADIENT_LIST))
+ {
+ if(!mpLbFillAttr->get_count())
+ {
+ mpLbFillAttr->set_sensitive(true);
+ mpLbFillAttr->clear();
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_GRADIENT_LIST)->GetGradientList());
+ }
+
+ if (mnLastPosGradient != -1)
+ {
+ const SvxGradientListItem * pItem = pSh->GetItem(SID_GRADIENT_LIST);
+
+ if(mnLastPosGradient < pItem->GetGradientList()->Count())
+ {
+ const XGradient aGradient = pItem->GetGradientList()->GetGradient(mnLastPosGradient)->GetGradient();
+ const XFillGradientItem aXFillGradientItem(mpLbFillAttr->get_text(mnLastPosGradient), aGradient);
+
+ // #i122676# change FillStyle and Gradient in one call
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_GRADIENT, SfxCallMode::RECORD,
+ { &aXFillGradientItem, &aXFillStyleItem });
+ mpLbFillAttr->set_active(mnLastPosGradient);
+ }
+ }
+ }
+ else
+ {
+ mpLbFillAttr->set_sensitive(false);
+ }
+ break;
+ }
+ case HATCH:
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+
+ if(pSh && pSh->GetItem(SID_HATCH_LIST))
+ {
+ if(!mpLbFillAttr->get_count())
+ {
+ mpLbFillAttr->set_sensitive(true);
+ mpLbFillAttr->clear();
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_HATCH_LIST)->GetHatchList());
+ }
+
+ if (mnLastPosHatch != -1)
+ {
+ const SvxHatchListItem * pItem = pSh->GetItem(SID_HATCH_LIST);
+
+ if(mnLastPosHatch < pItem->GetHatchList()->Count())
+ {
+ const XHatch aHatch = pItem->GetHatchList()->GetHatch(mnLastPosHatch)->GetHatch();
+ const XFillHatchItem aXFillHatchItem(mpLbFillAttr->get_active_text(), aHatch);
+
+ // #i122676# change FillStyle and Hatch in one call
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_HATCH, SfxCallMode::RECORD,
+ { &aXFillHatchItem, &aXFillStyleItem });
+ mpLbFillAttr->set_active(mnLastPosHatch);
+ }
+ }
+ }
+ else
+ {
+ mpLbFillAttr->set_sensitive(false);
+ }
+ break;
+ }
+ case BITMAP:
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+
+ if(pSh && pSh->GetItem(SID_BITMAP_LIST))
+ {
+ if(!mpLbFillAttr->get_count())
+ {
+ mpLbFillAttr->set_sensitive(true);
+ mpLbFillAttr->clear();
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_BITMAP_LIST)->GetBitmapList());
+ }
+
+ if (mnLastPosBitmap != -1)
+ {
+ const SvxBitmapListItem * pItem = pSh->GetItem(SID_BITMAP_LIST);
+
+ if(mnLastPosBitmap < pItem->GetBitmapList()->Count())
+ {
+ const XBitmapEntry* pXBitmapEntry = pItem->GetBitmapList()->GetBitmap(mnLastPosBitmap);
+ const XFillBitmapItem aXFillBitmapItem(mpLbFillAttr->get_active_text(), pXBitmapEntry->GetGraphicObject());
+
+ // #i122676# change FillStyle and Bitmap in one call
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_BITMAP, SfxCallMode::RECORD,
+ { &aXFillBitmapItem, &aXFillStyleItem });
+ mpLbFillAttr->set_active(mnLastPosBitmap);
+ }
+ }
+ }
+ else
+ {
+ mpLbFillAttr->set_sensitive(false);
+ }
+ break;
+ }
+ case PATTERN:
+ {
+ mpLbFillAttr->show();
+ mpToolBoxColor->hide();
+
+ if(pSh && pSh->GetItem(SID_PATTERN_LIST))
+ {
+ if(!mpLbFillAttr->get_count())
+ {
+ mpLbFillAttr->set_sensitive(true);
+ mpLbFillAttr->clear();
+ SvxFillAttrBox::Fill(*mpLbFillAttr, pSh->GetItem(SID_PATTERN_LIST)->GetPatternList());
+ }
+
+ if (mnLastPosPattern != -1)
+ {
+ const SvxPatternListItem * pItem = pSh->GetItem(SID_PATTERN_LIST);
+
+ if(mnLastPosPattern < pItem->GetPatternList()->Count())
+ {
+ const XBitmapEntry* pXBitmapEntry = pItem->GetPatternList()->GetBitmap(mnLastPosPattern);
+ const XFillBitmapItem aXFillBitmapItem(mpLbFillAttr->get_active_text(), pXBitmapEntry->GetGraphicObject());
+
+ // #i122676# change FillStyle and Bitmap in one call
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_BITMAP, SfxCallMode::RECORD,
+ { &aXFillBitmapItem, &aXFillStyleItem });
+ mpLbFillAttr->set_active(mnLastPosPattern);
+ }
+ }
+ }
+ else
+ {
+ mpLbFillAttr->set_sensitive(false);
+ }
+ break;
+ }
+
+ }
+
+ mnLastXFS = nXFS;
+
+ mxFillControl->Resize();
+}
+
+IMPL_LINK_NOARG(SvxFillToolBoxControl, SelectFillAttrHdl, weld::ComboBox&, void)
+{
+ sal_Int32 nXFS = mpLbFillType->get_active();
+ eFillStyle eXFS = static_cast<eFillStyle>(nXFS);
+
+ const XFillStyleItem aXFillStyleItem(toCssFillStyle(eXFS));
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+
+ // #i122676# dependent from bFillStyleChange, do execute a single or two
+ // changes in one Execute call
+ const bool bFillStyleChange(mnLastXFS != nXFS);
+
+ switch (eXFS)
+ {
+ case SOLID:
+ {
+ if (bFillStyleChange && pSh)
+ {
+ // #i122676# Single FillStyle change call needed here
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_STYLE, SfxCallMode::RECORD,
+ { &aXFillStyleItem });
+ }
+ break;
+ }
+ case GRADIENT:
+ {
+ sal_Int32 nPos = mpLbFillAttr->get_active();
+
+ if (nPos == -1)
+ {
+ nPos = mnLastPosGradient;
+ }
+
+ if (nPos != -1 && pSh && pSh->GetItem(SID_GRADIENT_LIST))
+ {
+ const SvxGradientListItem * pItem = pSh->GetItem(SID_GRADIENT_LIST);
+
+ if(nPos < pItem->GetGradientList()->Count())
+ {
+ const XGradient aGradient = pItem->GetGradientList()->GetGradient(nPos)->GetGradient();
+ const XFillGradientItem aXFillGradientItem(mpLbFillAttr->get_active_text(), aGradient);
+
+ // #i122676# Change FillStyle and Gradient in one call
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_GRADIENT, SfxCallMode::RECORD,
+ bFillStyleChange
+ ? std::initializer_list<SfxPoolItem const*>{ &aXFillGradientItem, &aXFillStyleItem }
+ : std::initializer_list<SfxPoolItem const*>{ &aXFillGradientItem });
+ }
+ }
+
+ if (nPos != -1)
+ {
+ mnLastPosGradient = nPos;
+ }
+ break;
+ }
+ case HATCH:
+ {
+ sal_Int32 nPos = mpLbFillAttr->get_active();
+
+ if (nPos == -1)
+ {
+ nPos = mnLastPosHatch;
+ }
+
+ if (nPos != -1 && pSh && pSh->GetItem(SID_HATCH_LIST))
+ {
+ const SvxHatchListItem * pItem = pSh->GetItem(SID_HATCH_LIST);
+
+ if(nPos < pItem->GetHatchList()->Count())
+ {
+ const XHatch aHatch = pItem->GetHatchList()->GetHatch(nPos)->GetHatch();
+ const XFillHatchItem aXFillHatchItem( mpLbFillAttr->get_active_text(), aHatch);
+
+ // #i122676# Change FillStyle and Hatch in one call
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_HATCH, SfxCallMode::RECORD,
+ bFillStyleChange
+ ? std::initializer_list<SfxPoolItem const*>{ &aXFillHatchItem, &aXFillStyleItem }
+ : std::initializer_list<SfxPoolItem const*>{ &aXFillHatchItem });
+ }
+ }
+
+ if (nPos != -1)
+ {
+ mnLastPosHatch = nPos;
+ }
+ break;
+ }
+ case BITMAP:
+ {
+ sal_Int32 nPos = mpLbFillAttr->get_active();
+
+ if (nPos == -1)
+ {
+ nPos = mnLastPosBitmap;
+ }
+
+ if (nPos != -1 && pSh && pSh->GetItem(SID_BITMAP_LIST))
+ {
+ const SvxBitmapListItem * pItem = pSh->GetItem(SID_BITMAP_LIST);
+
+ if(nPos < pItem->GetBitmapList()->Count())
+ {
+ const XBitmapEntry* pXBitmapEntry = pItem->GetBitmapList()->GetBitmap(nPos);
+ const XFillBitmapItem aXFillBitmapItem(mpLbFillAttr->get_active_text(), pXBitmapEntry->GetGraphicObject());
+
+ // #i122676# Change FillStyle and Bitmap in one call
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_BITMAP, SfxCallMode::RECORD,
+ bFillStyleChange
+ ? std::initializer_list<SfxPoolItem const*>{ &aXFillBitmapItem, &aXFillStyleItem }
+ : std::initializer_list<SfxPoolItem const*>{ &aXFillBitmapItem });
+ }
+ }
+
+ if (nPos != -1)
+ {
+ mnLastPosBitmap = nPos;
+ }
+ break;
+ }
+ case PATTERN:
+ {
+ sal_Int32 nPos = mpLbFillAttr->get_active();
+
+ if (nPos == -1)
+ {
+ nPos = mnLastPosPattern;
+ }
+
+ if (nPos != -1 && pSh && pSh->GetItem(SID_PATTERN_LIST))
+ {
+ const SvxPatternListItem * pItem = pSh->GetItem(SID_PATTERN_LIST);
+
+ if(nPos < pItem->GetPatternList()->Count())
+ {
+ const XBitmapEntry* pXBitmapEntry = pItem->GetPatternList()->GetBitmap(nPos);
+ const XFillBitmapItem aXFillBitmapItem(mpLbFillAttr->get_active_text(), pXBitmapEntry->GetGraphicObject());
+
+ // #i122676# Change FillStyle and Bitmap in one call
+ pSh->GetDispatcher()->ExecuteList(
+ SID_ATTR_FILL_BITMAP, SfxCallMode::RECORD,
+ bFillStyleChange
+ ? std::initializer_list<SfxPoolItem const*>{ &aXFillBitmapItem, &aXFillStyleItem }
+ : std::initializer_list<SfxPoolItem const*>{ &aXFillBitmapItem });
+ }
+ }
+
+ if (nPos != -1)
+ {
+ mnLastPosPattern = nPos;
+ }
+ break;
+ }
+
+ default: break;
+ }
+}
+
+void FillControl::SetOptimalSize()
+{
+ Size aSize(mxLbFillType->get_preferred_size());
+ Size aFirstSize(mxToolBoxColor->get_preferred_size());
+ auto nWidth = std::max(aFirstSize.Width(), LogicToPixel(Size(55, 0), MapMode(MapUnit::MapAppFont)).Width());
+ auto nHeight = std::max(aSize.Height(), aFirstSize.Height());
+ mxToolBoxColor->set_size_request(nWidth, -1);
+ mxLbFillAttr->set_size_request(42, -1); //something narrow so the toolbar sets the overall size of this column
+ SetSizePixel(Size(m_xContainer->get_preferred_size().Width(), nHeight));
+}
+
+void FillControl::DataChanged(const DataChangedEvent& rDCEvt)
+{
+ if((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
+ {
+ SetOptimalSize();
+ }
+ InterimItemWindow::DataChanged(rDCEvt);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/fontworkgallery.cxx b/svx/source/tbxctrls/fontworkgallery.cxx
new file mode 100644
index 000000000..802cc1f4f
--- /dev/null
+++ b/svx/source/tbxctrls/fontworkgallery.cxx
@@ -0,0 +1,799 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/text/WritingMode.hpp>
+
+#include <comphelper/lok.hxx>
+#include <comphelper/propertyvalue.hxx>
+
+#include <vcl/toolbox.hxx>
+#include <vcl/virdev.hxx>
+
+#include <sfx2/viewsh.hxx>
+
+#include <svl/itempool.hxx>
+
+#include <svtools/toolbarmenu.hxx>
+#include <svtools/popupwindowcontroller.hxx>
+
+#include <svx/fmmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdview.hxx>
+
+#include <svx/gallery.hxx>
+#include <svx/fontworkgallery.hxx>
+
+#include <tools/UnitConversion.hxx>
+
+#include <algorithm>
+#include <memory>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+
+namespace svx
+{
+
+FontWorkGalleryDialog::FontWorkGalleryDialog(weld::Window* pParent, SdrView& rSdrView)
+ : GenericDialogController(pParent, "svx/ui/fontworkgallerydialog.ui", "FontworkGalleryDialog")
+ , mnThemeId(0xffff)
+ , mrSdrView(rSdrView)
+ , mbInsertIntoPage(true)
+ , mpSdrObject(nullptr)
+ , mpDestModel(nullptr)
+ , maCtlFavorites(m_xBuilder->weld_icon_view("ctlFavoriteswin"))
+ , mxOKButton(m_xBuilder->weld_button("ok"))
+{
+ Size aSize(530, 400);
+ maCtlFavorites->set_size_request(aSize.Width(), aSize.Height());
+
+ maCtlFavorites->connect_item_activated( LINK( this, FontWorkGalleryDialog, DoubleClickFavoriteHdl ) );
+ mxOKButton->connect_clicked(LINK(this, FontWorkGalleryDialog, ClickOKHdl));
+
+ initFavorites( GALLERY_THEME_FONTWORK );
+ fillFavorites( GALLERY_THEME_FONTWORK );
+}
+
+FontWorkGalleryDialog::~FontWorkGalleryDialog()
+{
+}
+
+void FontWorkGalleryDialog::initFavorites(sal_uInt16 nThemeId)
+{
+ // the favorites are read via the gallery
+ sal_uInt32 nFavCount = GalleryExplorer::GetSdrObjCount( nThemeId );
+
+ // lock gallery theme
+ GalleryExplorer::BeginLocking(nThemeId);
+
+ sal_uInt32 nModelPos;
+ FmFormModel *pModel = nullptr;
+
+ for( nModelPos = 0; nModelPos < nFavCount; nModelPos++ )
+ {
+ BitmapEx aThumb;
+
+ if (GalleryExplorer::GetSdrObj(nThemeId, nModelPos, pModel, &aThumb) && !aThumb.IsEmpty())
+ {
+ VclPtr< VirtualDevice > pVDev = VclPtr<VirtualDevice>::Create();
+ const Point aNull(0, 0);
+
+ if (pVDev->GetDPIScaleFactor() > 1)
+ aThumb.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor());
+
+ const Size aSize(aThumb.GetSizePixel());
+
+ pVDev->SetOutputSizePixel(aSize);
+
+ static const sal_uInt32 nLen(8);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+
+ pVDev->DrawCheckered(aNull, aSize, nLen, aW, aG);
+
+ pVDev->DrawBitmapEx(aNull, aThumb);
+ maFavoritesHorizontal.emplace_back(pVDev);
+ }
+ }
+
+ // release gallery theme
+ GalleryExplorer::EndLocking(nThemeId);
+}
+
+void FontWorkGalleryDialog::fillFavorites(sal_uInt16 nThemeId)
+{
+ mnThemeId = nThemeId;
+
+ auto nFavCount = maFavoritesHorizontal.size();
+
+ maCtlFavorites->clear();
+
+ for( size_t nFavorite = 1; nFavorite <= nFavCount; nFavorite++ )
+ {
+ OUString sId = OUString::number(static_cast<sal_uInt16>(nFavorite));
+ maCtlFavorites->insert(-1, nullptr, &sId, maFavoritesHorizontal[nFavorite - 1], nullptr);
+ }
+
+ if (maCtlFavorites->n_children())
+ maCtlFavorites->select(0);
+}
+
+void FontWorkGalleryDialog::SetSdrObjectRef( SdrModel* pModel)
+{
+ mbInsertIntoPage = false;
+ mpDestModel = pModel;
+}
+
+void FontWorkGalleryDialog::insertSelectedFontwork()
+{
+ OUString sItemId = maCtlFavorites->get_selected_id();
+ if (sItemId.isEmpty())
+ return;
+
+ sal_Int32 nItemId = sItemId.toInt32();
+
+ if (nItemId == 0)
+ return;
+
+ FmFormModel aModel;
+ aModel.GetItemPool().FreezeIdRanges();
+
+ if( !GalleryExplorer::GetSdrObj( mnThemeId, nItemId-1, &aModel ) )
+ return;
+
+ SdrPage* pPage = aModel.GetPage(0);
+ if( !(pPage && pPage->GetObjCount()) )
+ return;
+
+ // tdf#116993 Calc uses a 'special' mode for this dialog in being the
+ // only caller of ::SetSdrObjectRef. Only in that case mpDestModel seems
+ // to be the correct target SdrModel.
+ // If this is not used, the correct SdrModel seems to be the one from
+ // the mrSdrView that is used to insert (InsertObjectAtView below) the
+ // cloned SdrObject.
+ const bool bUseSpecialCalcMode(!mbInsertIntoPage && nullptr != mpDestModel);
+
+ // center shape on current view
+ OutputDevice* pOutDev(mrSdrView.GetFirstOutputDevice());
+
+ if (!pOutDev)
+ return;
+
+ // Clone directly to target SdrModel (may be different due to user/caller (!))
+ SdrObject* pNewObject(
+ pPage->GetObj(0)->CloneSdrObject(
+ bUseSpecialCalcMode ? *mpDestModel : mrSdrView.getSdrModelFromSdrView()));
+
+ pNewObject->MakeNameUnique();
+
+ // tdf#117629
+ // Since the 'old' ::CloneSdrObject also copies the SdrPage* the
+ // SdrObject::getUnoShape() *will* create the wrong UNO API object
+ // early. This IS one of the reasons I do change these things - this
+ // error does not happen with my next change I am working on already
+ // ARGH! For now, reset the SdrPage* to nullptr.
+ // What sense does it have to copy the SdrPage* of the original SdrObject ?!?
+ // TTTT: This also *might* be the hidden reason for the strange code at the
+ // end of SdrObject::SetPage that tries to delete the SvxShape under some
+ // circumstances...
+ // pNewObject->SetPage(nullptr);
+
+ tools::Rectangle aObjRect( pNewObject->GetLogicRect() );
+ Point aPagePos;
+ Size aFontworkSize = aObjRect.GetSize();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+
+ aPagePos = pViewShell->getLOKVisibleArea().Center();
+
+ aPagePos.setX(convertTwipToMm100(aPagePos.X()));
+ aPagePos.setY(convertTwipToMm100(aPagePos.Y()));
+
+ sal_Int32 nLOKViewWidth = 0.8 * convertTwipToMm100(pViewShell->getLOKVisibleArea().getWidth());
+ if (aFontworkSize.getWidth() > nLOKViewWidth)
+ {
+ double fScale = static_cast<double>(aFontworkSize.getWidth()) / nLOKViewWidth;
+ aFontworkSize.setWidth(aFontworkSize.getWidth() / fScale);
+ aFontworkSize.setHeight(aFontworkSize.getHeight() / fScale);
+ }
+ }
+ else
+ {
+ Size aSize = pOutDev->GetOutputSizePixel();
+ tools::Rectangle aPixelVisRect(Point(0,0), aSize);
+ tools::Rectangle aVisArea = pOutDev->PixelToLogic(aPixelVisRect);
+
+ aPagePos = aVisArea.Center();
+ }
+
+ if (aPagePos.getX() > aFontworkSize.getWidth() / 2)
+ aPagePos.AdjustX( -(aFontworkSize.getWidth() / 2) );
+ if (aPagePos.getY() > aFontworkSize.getHeight() / 2)
+ aPagePos.AdjustY( -(aFontworkSize.getHeight() / 2) );
+
+ tools::Rectangle aNewObjectRectangle(aPagePos, aFontworkSize);
+ pNewObject->SetLogicRect(aNewObjectRectangle);
+
+ if (bUseSpecialCalcMode)
+ {
+ mpSdrObject = pNewObject;
+ }
+ else
+ {
+ SdrPageView* pPV(mrSdrView.GetSdrPageView());
+
+ if (nullptr != pPV)
+ {
+ mrSdrView.InsertObjectAtView( pNewObject, *pPV );
+ }
+ else
+ {
+ // tdf#116993 no target -> delete clone
+ SdrObject::Free(pNewObject);
+ }
+ }
+}
+
+IMPL_LINK_NOARG(FontWorkGalleryDialog, ClickOKHdl, weld::Button&, void)
+{
+ insertSelectedFontwork();
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(FontWorkGalleryDialog, DoubleClickFavoriteHdl, weld::IconView&, bool)
+{
+ insertSelectedFontwork();
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+namespace {
+
+class FontworkAlignmentWindow final : public WeldToolbarPopup
+{
+public:
+ FontworkAlignmentWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow);
+ virtual void GrabFocus() override
+ {
+ mxLeft->grab_focus();
+ }
+ virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+
+private:
+ rtl::Reference<svt::PopupWindowController> mxControl;
+ std::unique_ptr<weld::RadioButton> mxLeft;
+ std::unique_ptr<weld::RadioButton> mxCenter;
+ std::unique_ptr<weld::RadioButton> mxRight;
+ std::unique_ptr<weld::RadioButton> mxStretch;
+ bool mbSettingValue;
+
+ DECL_LINK( SelectHdl, weld::Toggleable&, void );
+
+ void implSetAlignment( int nAlignmentMode, bool bEnabled );
+};
+
+}
+
+constexpr OUStringLiteral gsFontworkAlignment(u".uno:FontworkAlignment");
+
+FontworkAlignmentWindow::FontworkAlignmentWindow(svt::PopupWindowController* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/fontworkalignmentcontrol.ui", "FontworkAlignmentControl")
+ , mxControl(pControl)
+ , mxLeft(m_xBuilder->weld_radio_button("left"))
+ , mxCenter(m_xBuilder->weld_radio_button("center"))
+ , mxRight(m_xBuilder->weld_radio_button("right"))
+ , mxStretch(m_xBuilder->weld_radio_button("stretch"))
+ , mbSettingValue(false)
+{
+ mxLeft->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
+ mxCenter->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
+ mxRight->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
+ mxStretch->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
+
+ AddStatusListener( gsFontworkAlignment );
+}
+
+void FontworkAlignmentWindow::implSetAlignment( int nSurface, bool bEnabled )
+{
+ bool bSettingValue = mbSettingValue;
+ mbSettingValue = true;
+ mxLeft->set_active(nSurface == 0 && bEnabled);
+ mxLeft->set_sensitive(bEnabled);
+ mxCenter->set_active(nSurface == 1 && bEnabled);
+ mxCenter->set_sensitive(bEnabled);
+ mxRight->set_active(nSurface == 2 && bEnabled);
+ mxRight->set_sensitive(bEnabled);
+ //Refer https://bugs.documentfoundation.org/show_bug.cgi?id=145092 for why following lines are commented
+ //mxWord->set_active(nSurface == 3 && bEnabled);
+ //mxWord->set_sensitive(bEnabled);
+ mxStretch->set_active(nSurface == 4 && bEnabled);
+ mxStretch->set_sensitive(bEnabled);
+ mbSettingValue = bSettingValue;
+}
+
+void FontworkAlignmentWindow::statusChanged( const css::frame::FeatureStateEvent& Event )
+{
+ if( Event.FeatureURL.Main != gsFontworkAlignment )
+ return;
+
+ if( !Event.IsEnabled )
+ {
+ implSetAlignment( 0, false );
+ }
+ else
+ {
+ sal_Int32 nValue = 0;
+ if( Event.State >>= nValue )
+ implSetAlignment( nValue, true );
+ }
+}
+
+IMPL_LINK(FontworkAlignmentWindow, SelectHdl, weld::Toggleable&, rButton, void)
+{
+ if (mbSettingValue || !rButton.get_active())
+ return;
+
+ sal_Int32 nAlignment;
+ if (mxLeft->get_active())
+ nAlignment = 0;
+ else if (mxCenter->get_active())
+ nAlignment = 1;
+ else if (mxRight->get_active())
+ nAlignment = 2;
+ //Refer https://bugs.documentfoundation.org/show_bug.cgi?id=145092 for why following lines are commented
+ //else if (mxWord->get_active())
+ // nAlignment = 3;
+ else
+ nAlignment = 4;
+
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
+ OUString(gsFontworkAlignment).copy(5), nAlignment) };
+
+ mxControl->dispatchCommand( gsFontworkAlignment, aArgs );
+
+ implSetAlignment( nAlignment, true );
+
+ mxControl->EndPopupMode();
+}
+
+namespace {
+
+class FontworkAlignmentControl : public svt::PopupWindowController
+{
+public:
+ explicit FontworkAlignmentControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+}
+
+FontworkAlignmentControl::FontworkAlignmentControl( const Reference< XComponentContext >& rxContext )
+: svt::PopupWindowController( rxContext, Reference< css::frame::XFrame >(), ".uno:FontworkAlignment" )
+{
+}
+
+std::unique_ptr<WeldToolbarPopup> FontworkAlignmentControl::weldPopupWindow()
+{
+ return std::make_unique<FontworkAlignmentWindow>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> FontworkAlignmentControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<FontworkAlignmentWindow>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+// XInitialization
+void SAL_CALL FontworkAlignmentControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::PopupWindowController::initialize( aArguments );
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if ( getToolboxId( nId, &pToolBox ) )
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+}
+
+// XServiceInfo
+
+
+OUString FontworkAlignmentControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.FontworkAlignmentController";
+}
+
+
+Sequence< OUString > FontworkAlignmentControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_FontworkAlignmentControl_get_implementation(
+ css::uno::XComponentContext* xContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new FontworkAlignmentControl(xContext));
+}
+
+namespace {
+
+class FontworkCharacterSpacingWindow final : public WeldToolbarPopup
+{
+public:
+ FontworkCharacterSpacingWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow);
+ virtual void GrabFocus() override;
+
+ virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+private:
+ rtl::Reference<svt::PopupWindowController> mxControl;
+ std::unique_ptr<weld::RadioButton> mxVeryTight;
+ std::unique_ptr<weld::RadioButton> mxTight;
+ std::unique_ptr<weld::RadioButton> mxNormal;
+ std::unique_ptr<weld::RadioButton> mxLoose;
+ std::unique_ptr<weld::RadioButton> mxVeryLoose;
+ std::unique_ptr<weld::RadioButton> mxCustom;
+ std::unique_ptr<weld::CheckButton> mxKernPairs;
+ sal_Int32 mnCharacterSpacing;
+ bool mbSettingValue;
+ bool mbCommandDispatched;
+
+ DECL_LINK( KernSelectHdl, weld::Toggleable&, void );
+ DECL_LINK( SelectHdl, weld::Toggleable&, void );
+ DECL_LINK( MouseReleaseHdl, const MouseEvent&, bool );
+
+ void implSetCharacterSpacing( sal_Int32 nCharacterSpacing, bool bEnabled );
+ void implSetKernCharacterPairs(bool bKernOnOff, bool bEnabled);
+ void DispatchSpacingDialog();
+};
+
+}
+
+constexpr OUStringLiteral gsFontworkCharacterSpacing(u".uno:FontworkCharacterSpacing");
+constexpr OUStringLiteral gsFontworkKernCharacterPairs(u".uno:FontworkKernCharacterPairs");
+
+FontworkCharacterSpacingWindow::FontworkCharacterSpacingWindow(svt::PopupWindowController* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/fontworkcharacterspacingcontrol.ui", "FontworkCharacterSpacingControl")
+ , mxControl(pControl)
+ , mxVeryTight(m_xBuilder->weld_radio_button("verytight"))
+ , mxTight(m_xBuilder->weld_radio_button("tight"))
+ , mxNormal(m_xBuilder->weld_radio_button("normal"))
+ , mxLoose(m_xBuilder->weld_radio_button("loose"))
+ , mxVeryLoose(m_xBuilder->weld_radio_button("veryloose"))
+ , mxCustom(m_xBuilder->weld_radio_button("custom"))
+ , mxKernPairs(m_xBuilder->weld_check_button("kernpairs"))
+ , mnCharacterSpacing(0)
+ , mbSettingValue(false)
+ , mbCommandDispatched(false)
+{
+ mxVeryTight->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
+ mxTight->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
+ mxNormal->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
+ mxLoose->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
+ mxVeryLoose->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
+ mxCustom->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
+ mxCustom->connect_mouse_release(LINK(this, FontworkCharacterSpacingWindow, MouseReleaseHdl));
+
+ mxKernPairs->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, KernSelectHdl));
+
+ AddStatusListener( gsFontworkCharacterSpacing );
+ AddStatusListener( gsFontworkKernCharacterPairs );
+
+ // See TODO in svx/source/toolbars/fontworkbar.cxx for SID_FONTWORK_KERN_CHARACTER_PAIRS,
+ // the kernpairs setting is ignored, so hide the widget entirely
+ mxKernPairs->hide();
+}
+
+void FontworkCharacterSpacingWindow::GrabFocus()
+{
+ mxVeryTight->grab_focus();
+}
+
+void FontworkCharacterSpacingWindow::implSetCharacterSpacing( sal_Int32 nCharacterSpacing, bool bEnabled )
+{
+ bool bSettingValue = mbSettingValue;
+ mbSettingValue = true;
+
+ mxVeryTight->set_sensitive(bEnabled);
+ mxTight->set_sensitive(bEnabled);
+ mxNormal->set_sensitive(bEnabled);
+ mxLoose->set_sensitive(bEnabled);
+ mxVeryLoose->set_sensitive(bEnabled);
+ mxCustom->set_sensitive(bEnabled);
+
+ mxVeryTight->set_active(false);
+ mxTight->set_active(false);
+ mxNormal->set_active(false);
+ mxLoose->set_active(false);
+ mxVeryLoose->set_active(false);
+ mxCustom->set_active(true);
+
+ switch(nCharacterSpacing)
+ {
+ case 80:
+ mxVeryTight->set_active(true);
+ break;
+ case 90:
+ mxTight->set_active(true);
+ break;
+ case 100:
+ mxNormal->set_active(true);
+ break;
+ case 120:
+ mxLoose->set_active(true);
+ break;
+ case 150:
+ mxVeryLoose->set_active(true);
+ break;
+ }
+
+ mnCharacterSpacing = nCharacterSpacing;
+
+ mbSettingValue = bSettingValue;
+}
+
+void FontworkCharacterSpacingWindow::implSetKernCharacterPairs(bool bKernOnOff, bool bEnabled)
+{
+ mxKernPairs->set_sensitive(bEnabled);
+ mxKernPairs->set_active(bKernOnOff);
+}
+
+void FontworkCharacterSpacingWindow::statusChanged( const css::frame::FeatureStateEvent& Event )
+{
+ if( Event.FeatureURL.Main == gsFontworkCharacterSpacing )
+ {
+ if( !Event.IsEnabled )
+ {
+ implSetCharacterSpacing( 0, false );
+ }
+ else
+ {
+ sal_Int32 nValue = 0;
+ if( Event.State >>= nValue )
+ implSetCharacterSpacing( nValue, true );
+ }
+ }
+ else if( Event.FeatureURL.Main == gsFontworkKernCharacterPairs )
+ {
+ if( !Event.IsEnabled )
+ {
+ implSetKernCharacterPairs(false, false);
+ }
+ else
+ {
+ bool bValue = false;
+ if( Event.State >>= bValue )
+ implSetKernCharacterPairs(bValue, true);
+ }
+ }
+}
+
+IMPL_LINK_NOARG(FontworkCharacterSpacingWindow, KernSelectHdl, weld::Toggleable&, void)
+{
+ if (mbSettingValue)
+ return;
+
+ bool bKernOnOff = mxKernPairs->get_active();
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
+ OUString(gsFontworkKernCharacterPairs).copy(5), bKernOnOff) };
+
+ mxControl->dispatchCommand( gsFontworkKernCharacterPairs, aArgs );
+ mbCommandDispatched = true;
+
+ implSetKernCharacterPairs(bKernOnOff, true);
+
+ mxControl->EndPopupMode();
+}
+
+void FontworkCharacterSpacingWindow::DispatchSpacingDialog()
+{
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
+ OUString(gsFontworkCharacterSpacing).copy(5), mnCharacterSpacing) };
+
+ rtl::Reference<svt::PopupWindowController> xControl(mxControl);
+ xControl->EndPopupMode();
+ xControl->dispatchCommand(".uno:FontworkCharacterSpacingDialog", aArgs);
+ mbCommandDispatched = true;
+}
+
+IMPL_LINK(FontworkCharacterSpacingWindow, SelectHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+
+ if (mbSettingValue)
+ return;
+
+ // see MouseReleaseHdl for mbCommandDispatched check, there's no guarantee
+ // this toggle will happen before that mouse release though it does in
+ // practice for vcl and gtk
+ if (mbCommandDispatched)
+ return;
+
+ if (mxCustom->get_active())
+ DispatchSpacingDialog();
+ else
+ {
+ sal_Int32 nCharacterSpacing;
+ if (mxVeryTight->get_active())
+ nCharacterSpacing = 80;
+ else if (mxTight->get_active())
+ nCharacterSpacing = 90;
+ else if (mxLoose->get_active())
+ nCharacterSpacing = 120;
+ else if (mxVeryLoose->get_active())
+ nCharacterSpacing = 150;
+ else
+ nCharacterSpacing = 100;
+
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
+ OUString(gsFontworkCharacterSpacing).copy(5), nCharacterSpacing) };
+
+ mxControl->dispatchCommand( gsFontworkCharacterSpacing, aArgs );
+ mbCommandDispatched = true;
+
+ implSetCharacterSpacing( nCharacterSpacing, true );
+ }
+
+ mxControl->EndPopupMode();
+}
+
+IMPL_LINK_NOARG(FontworkCharacterSpacingWindow, MouseReleaseHdl, const MouseEvent&, bool)
+{
+ /*
+ tdf#145296 if the "custom" radiobutton was presented preselected as
+ toggled on and the user clicked on it then there's no toggled signal sent
+ because the item was already toggled on and didn't change state.
+
+ So if that happens launch the custom spacing dialog explicitly here on
+ mouse release.
+ */
+ if (mxCustom->get_active() && !mbCommandDispatched)
+ {
+ DispatchSpacingDialog();
+ return true;
+ }
+ return false;
+}
+
+namespace {
+
+class FontworkCharacterSpacingControl : public svt::PopupWindowController
+{
+public:
+ explicit FontworkCharacterSpacingControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+}
+
+FontworkCharacterSpacingControl::FontworkCharacterSpacingControl( const Reference< XComponentContext >& rxContext )
+: svt::PopupWindowController( rxContext, Reference< css::frame::XFrame >(), ".uno:FontworkCharacterSpacingFloater" )
+{
+}
+
+std::unique_ptr<WeldToolbarPopup> FontworkCharacterSpacingControl::weldPopupWindow()
+{
+ return std::make_unique<FontworkCharacterSpacingWindow>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> FontworkCharacterSpacingControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<FontworkCharacterSpacingWindow>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+// XInitialization
+void SAL_CALL FontworkCharacterSpacingControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::PopupWindowController::initialize( aArguments );
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if ( getToolboxId( nId, &pToolBox ) )
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+}
+
+// XServiceInfo
+
+
+OUString FontworkCharacterSpacingControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.FontworkCharacterSpacingController";
+}
+
+
+Sequence< OUString > FontworkCharacterSpacingControl::getSupportedServiceNames()
+{
+ Sequence<OUString> aSNS { "com.sun.star.frame.ToolbarController" };
+ return aSNS;
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_FontworkCharacterSpacingControl_get_implementation(
+ css::uno::XComponentContext* xContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new FontworkCharacterSpacingControl(xContext));
+}
+
+FontworkCharacterSpacingDialog::FontworkCharacterSpacingDialog(weld::Window* pParent, sal_Int32 nScale)
+ : GenericDialogController(pParent, "svx/ui/fontworkspacingdialog.ui", "FontworkSpacingDialog")
+ , m_xMtrScale(m_xBuilder->weld_metric_spin_button("entry", FieldUnit::PERCENT))
+{
+ m_xMtrScale->set_value(nScale, FieldUnit::PERCENT);
+}
+
+FontworkCharacterSpacingDialog::~FontworkCharacterSpacingDialog()
+{
+}
+
+sal_Int32 FontworkCharacterSpacingDialog::getScale() const
+{
+ return static_cast<sal_Int32>(m_xMtrScale->get_value(FieldUnit::PERCENT));
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/formatpaintbrushctrl.cxx b/svx/source/tbxctrls/formatpaintbrushctrl.cxx
new file mode 100644
index 000000000..f67efd12c
--- /dev/null
+++ b/svx/source/tbxctrls/formatpaintbrushctrl.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/formatpaintbrushctrl.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <svl/eitem.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/settings.hxx>
+
+
+namespace svx
+{
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+
+SFX_IMPL_TOOLBOX_CONTROL( FormatPaintBrushToolBoxControl, SfxBoolItem );
+
+FormatPaintBrushToolBoxControl::FormatPaintBrushToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx )
+ : SfxToolBoxControl( nSlotId, nId, rTbx )
+ , m_bPersistentCopy(false)
+ , m_aDoubleClickTimer("FormatPaintBrushToolBoxControl m_aDoubleClickTimer")
+{
+ sal_uInt64 nDblClkTime = rTbx.GetSettings().GetMouseSettings().GetDoubleClickTime();
+
+ m_aDoubleClickTimer.SetInvokeHandler( LINK(this, FormatPaintBrushToolBoxControl, WaitDoubleClickHdl) );
+ m_aDoubleClickTimer.SetTimeout(nDblClkTime);
+}
+
+
+FormatPaintBrushToolBoxControl::~FormatPaintBrushToolBoxControl()
+{
+ m_aDoubleClickTimer.Stop();
+}
+
+
+void FormatPaintBrushToolBoxControl::impl_executePaintBrush()
+{
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("PersistentCopy",
+ m_bPersistentCopy) };
+ Dispatch( ".uno:FormatPaintbrush"
+ , aArgs );
+}
+
+
+void FormatPaintBrushToolBoxControl::DoubleClick()
+{
+ m_aDoubleClickTimer.Stop();
+
+ m_bPersistentCopy = true;
+ impl_executePaintBrush();
+}
+
+
+void FormatPaintBrushToolBoxControl::Click()
+{
+ m_bPersistentCopy = false;
+ m_aDoubleClickTimer.Start();
+}
+
+
+IMPL_LINK_NOARG(FormatPaintBrushToolBoxControl, WaitDoubleClickHdl, Timer *, void)
+{
+ //there was no second click during waiting
+ impl_executePaintBrush();
+}
+
+
+void FormatPaintBrushToolBoxControl::Select(sal_uInt16 /*nSelectModifier*/)
+{
+}
+
+
+void FormatPaintBrushToolBoxControl::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ if( eState != SfxItemState::DEFAULT && eState != SfxItemState::SET )
+ m_bPersistentCopy = false;
+ SfxToolBoxControl::StateChangedAtToolBoxControl( nSID, eState, pState );
+}
+
+
+} //namespace svx
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/grafctrl.cxx b/svx/source/tbxctrls/grafctrl.cxx
new file mode 100644
index 000000000..733cfb3af
--- /dev/null
+++ b/svx/source/tbxctrls/grafctrl.cxx
@@ -0,0 +1,961 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <o3tl/string_view.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/idle.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+#include <svl/eitem.hxx>
+#include <svl/whiter.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <tools/urlobj.hxx>
+
+#include <svx/dialogs.hrc>
+#include <svx/svxids.hrc>
+#include <svx/strings.hrc>
+#include <editeng/brushitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <svx/sdgcpitm.hxx>
+
+#include <svx/dialmgr.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/grafctrl.hxx>
+#include <svx/tbxcolor.hxx>
+#include <sdgcoitm.hxx>
+#include <svx/sdggaitm.hxx>
+#include <svx/sdgluitm.hxx>
+#include <svx/sdgmoitm.hxx>
+#include <sdgtritm.hxx>
+#include <bitmaps.hlst>
+
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+
+constexpr OUStringLiteral TOOLBOX_NAME = u"colorbar";
+#define RID_SVXSTR_UNDO_GRAFCROP RID_SVXSTR_GRAFCROP
+
+namespace {
+
+class ImplGrafControl final : public InterimItemWindow
+{
+private:
+ OUString maCommand;
+ Reference<XFrame> mxFrame;
+ std::unique_ptr<weld::Image> mxImage;
+ std::unique_ptr<weld::MetricSpinButton> mxField;
+
+ DECL_LINK(ValueChangedHdl, weld::MetricSpinButton&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ void ImplModify();
+
+public:
+ ImplGrafControl( vcl::Window* pParent, const OUString& rCmd, const Reference< XFrame >& rFrame );
+ virtual ~ImplGrafControl() override;
+ virtual void dispose() override;
+
+ void Update( const SfxPoolItem* pItem );
+ void set_field_text(const OUString& rStr) { mxField->set_text(rStr); }
+ void set_sensitive(bool bSensitive)
+ {
+ Enable(bSensitive);
+ mxImage->set_sensitive(bSensitive);
+ mxField->set_sensitive(bSensitive);
+ }
+};
+
+}
+
+IMPL_LINK_NOARG(ImplGrafControl, ValueChangedHdl, weld::MetricSpinButton&, void)
+{
+ ImplModify();
+}
+
+void ImplGrafControl::ImplModify()
+{
+ const sal_Int64 nVal = mxField->get_value(FieldUnit::NONE);
+
+ // Convert value to an any to be usable with dispatch API
+ Any a;
+ if ( maCommand == ".uno:GrafRed" ||
+ maCommand == ".uno:GrafGreen" ||
+ maCommand == ".uno:GrafBlue" ||
+ maCommand == ".uno:GrafLuminance" ||
+ maCommand == ".uno:GrafContrast" )
+ a <<= sal_Int16( nVal );
+ else if ( maCommand == ".uno:GrafGamma" ||
+ maCommand == ".uno:GrafTransparence" )
+ a <<= sal_Int32( nVal );
+
+ if ( !a.hasValue() )
+ return;
+
+ INetURLObject aObj( maCommand );
+
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(aObj.GetURLPath(), a) };
+
+ SfxToolBoxControl::Dispatch(
+ Reference< XDispatchProvider >( mxFrame->getController(), UNO_QUERY ),
+ maCommand,
+ aArgs );
+}
+
+void ImplGrafControl::Update( const SfxPoolItem* pItem )
+{
+ if( pItem )
+ {
+ tools::Long nValue;
+
+ if ( maCommand == ".uno:GrafTransparence" )
+ nValue = static_cast<const SfxUInt16Item*>( pItem )->GetValue();
+ else if ( maCommand == ".uno:GrafGamma" )
+ nValue = static_cast<const SfxUInt32Item*>( pItem )->GetValue();
+ else
+ nValue = static_cast<const SfxInt16Item*>( pItem )->GetValue();
+
+ mxField->set_value(nValue, FieldUnit::NONE);
+ }
+ else
+ mxField->set_text(OUString());
+}
+
+namespace {
+
+struct CommandToRID
+{
+ const char* pCommand;
+ rtl::OUStringConstExpr sResId;
+};
+
+}
+
+static OUString ImplGetRID( std::u16string_view aCommand )
+{
+ static constexpr OUStringLiteral EMPTY = u"";
+ static const CommandToRID aImplCommandToResMap[] =
+ {
+ { ".uno:GrafRed", RID_SVXBMP_GRAF_RED },
+ { ".uno:GrafGreen", RID_SVXBMP_GRAF_GREEN },
+ { ".uno:GrafBlue", RID_SVXBMP_GRAF_BLUE },
+ { ".uno:GrafLuminance", RID_SVXBMP_GRAF_LUMINANCE },
+ { ".uno:GrafContrast", RID_SVXBMP_GRAF_CONTRAST },
+ { ".uno:GrafGamma", RID_SVXBMP_GRAF_GAMMA },
+ { ".uno:GrafTransparence", RID_SVXBMP_GRAF_TRANSPARENCE },
+ { nullptr, EMPTY }
+ };
+
+ OUString sRID;
+
+ sal_Int32 i( 0 );
+ while ( aImplCommandToResMap[ i ].pCommand )
+ {
+ if ( o3tl::equalsAscii( aCommand, aImplCommandToResMap[ i ].pCommand ))
+ {
+ sRID = aImplCommandToResMap[i].sResId;
+ break;
+ }
+ ++i;
+ }
+
+ return sRID;
+}
+
+ImplGrafControl::ImplGrafControl(
+ vcl::Window* pParent,
+ const OUString& rCmd,
+ const Reference< XFrame >& rFrame)
+ : InterimItemWindow(pParent, "svx/ui/grafctrlbox.ui", "GrafCtrlBox")
+ , maCommand(rCmd)
+ , mxFrame(rFrame)
+ , mxImage(m_xBuilder->weld_image("image"))
+ , mxField(m_xBuilder->weld_metric_spin_button("spinfield", FieldUnit::NONE))
+{
+ InitControlBase(&mxField->get_widget());
+
+ OUString sResId(ImplGetRID(rCmd));
+ mxImage->set_from_icon_name(sResId);
+ mxImage->set_toolbar_background();
+
+ SetBackground( Wallpaper() ); // transparent background
+
+ mxField->set_help_id(OUStringToOString(rCmd, RTL_TEXTENCODING_UTF8));
+ mxField->get_widget().connect_key_press(LINK(this, ImplGrafControl, KeyInputHdl));
+ mxField->connect_value_changed(LINK(this, ImplGrafControl, ValueChangedHdl));
+
+ if (maCommand == ".uno:GrafGamma")
+ {
+ mxField->set_digits(2);
+
+ mxField->set_range(10, 1000, FieldUnit::NONE);
+ mxField->set_increments(10, 100, FieldUnit::NONE);
+ }
+ else
+ {
+ const tools::Long nMinVal = maCommand == ".uno:GrafTransparence" ? 0 : -100;
+
+ mxField->set_unit(FieldUnit::PERCENT);
+ mxField->set_digits(0);
+
+ mxField->set_range(nMinVal, 100, FieldUnit::PERCENT);
+ mxField->set_increments(1, 10, FieldUnit::PERCENT);
+ }
+
+ SetSizePixel(m_xContainer->get_preferred_size());
+}
+
+IMPL_LINK(ImplGrafControl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return ChildKeyInput(rKEvt);
+}
+
+ImplGrafControl::~ImplGrafControl()
+{
+ disposeOnce();
+}
+
+void ImplGrafControl::dispose()
+{
+ mxImage.reset();
+ mxField.reset();
+ InterimItemWindow::dispose();
+}
+
+namespace {
+
+class ImplGrafModeControl final : public InterimItemWindow
+{
+private:
+ sal_uInt16 mnCurPos;
+ Reference< XFrame > mxFrame;
+ std::unique_ptr<weld::ComboBox> m_xWidget;
+
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(FocusInHdl, weld::Widget&, void);
+
+ static void ImplReleaseFocus();
+
+public:
+ ImplGrafModeControl( vcl::Window* pParent, const Reference< XFrame >& rFrame );
+ virtual void dispose() override;
+ virtual ~ImplGrafModeControl() override;
+
+ void set_sensitive(bool bSensitive)
+ {
+ Enable(bSensitive);
+ m_xWidget->set_sensitive(true);
+ }
+
+ void set_active(int nActive)
+ {
+ m_xWidget->set_active(nActive);
+ }
+
+ void Update( const SfxPoolItem* pItem );
+};
+
+}
+
+ImplGrafModeControl::ImplGrafModeControl(vcl::Window* pParent, const Reference<XFrame>& rFrame)
+ : InterimItemWindow(pParent, "svx/ui/grafmodebox.ui", "GrafModeBox")
+ , mnCurPos(0)
+ , mxFrame(rFrame)
+ , m_xWidget(m_xBuilder->weld_combo_box("grafmode"))
+{
+ InitControlBase(m_xWidget.get());
+
+ m_xWidget->append_text( SvxResId( RID_SVXSTR_GRAFMODE_STANDARD ) );
+ m_xWidget->append_text( SvxResId( RID_SVXSTR_GRAFMODE_GREYS ) );
+ m_xWidget->append_text( SvxResId( RID_SVXSTR_GRAFMODE_MONO ) );
+ m_xWidget->append_text( SvxResId( RID_SVXSTR_GRAFMODE_WATERMARK ) );
+
+ m_xWidget->connect_changed(LINK(this, ImplGrafModeControl, SelectHdl));
+ m_xWidget->connect_key_press(LINK(this, ImplGrafModeControl, KeyInputHdl));
+ m_xWidget->connect_focus_in(LINK(this, ImplGrafModeControl, FocusInHdl));
+
+ SetSizePixel(m_xWidget->get_preferred_size());
+}
+
+void ImplGrafModeControl::dispose()
+{
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+}
+
+ImplGrafModeControl::~ImplGrafModeControl()
+{
+ disposeOnce();
+}
+
+IMPL_LINK(ImplGrafModeControl, SelectHdl, weld::ComboBox&, rBox, void)
+{
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("GrafMode",
+ sal_Int16(rBox.get_active())) };
+
+ /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
+ This instance may be deleted in the meantime (i.e. when a dialog is opened
+ while in Dispatch()), accessing members will crash in this case. */
+ ImplReleaseFocus();
+
+ SfxToolBoxControl::Dispatch(
+ Reference< XDispatchProvider >( mxFrame->getController(), UNO_QUERY ),
+ ".uno:GrafMode",
+ aArgs );
+}
+
+IMPL_LINK(ImplGrafModeControl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled(false);
+
+ if (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)
+ {
+ m_xWidget->set_active(mnCurPos);
+ ImplReleaseFocus();
+ bHandled = true;
+ }
+
+ return bHandled || ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(ImplGrafModeControl, FocusInHdl, weld::Widget&, void)
+{
+ mnCurPos = m_xWidget->get_active();
+}
+
+void ImplGrafModeControl::ImplReleaseFocus()
+{
+ if( SfxViewShell::Current() )
+ {
+ vcl::Window* pShellWnd = SfxViewShell::Current()->GetWindow();
+
+ if( pShellWnd )
+ pShellWnd->GrabFocus();
+ }
+}
+
+void ImplGrafModeControl::Update( const SfxPoolItem* pItem )
+{
+ if( pItem )
+ m_xWidget->set_active(static_cast<const SfxUInt16Item*>(pItem)->GetValue());
+ else
+ m_xWidget->set_active(-1);
+}
+
+SvxGrafToolBoxControl::SvxGrafToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx) :
+ SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+ rTbx.SetItemBits( nId, ToolBoxItemBits::DROPDOWN | rTbx.GetItemBits( nId ) );
+ rTbx.Invalidate();
+}
+
+SvxGrafToolBoxControl::~SvxGrafToolBoxControl()
+{
+}
+
+void SvxGrafToolBoxControl::StateChangedAtToolBoxControl( sal_uInt16, SfxItemState eState, const SfxPoolItem* pState )
+{
+ ImplGrafControl* pCtrl = static_cast<ImplGrafControl*>( GetToolBox().GetItemWindow( GetId() ) );
+ DBG_ASSERT( pCtrl, "Control not found" );
+
+ if( eState == SfxItemState::DISABLED )
+ {
+ pCtrl->set_sensitive(false);
+ pCtrl->set_field_text( OUString() );
+ }
+ else
+ {
+ pCtrl->set_sensitive(true);
+
+ if( eState == SfxItemState::DEFAULT )
+ pCtrl->Update( pState );
+ else
+ pCtrl->Update( nullptr );
+ }
+}
+
+VclPtr<InterimItemWindow> SvxGrafToolBoxControl::CreateItemWindow( vcl::Window *pParent )
+{
+ return VclPtr<ImplGrafControl>::Create( pParent, m_aCommandURL, m_xFrame ).get();
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxGrafRedToolBoxControl, SfxInt16Item );
+
+SvxGrafRedToolBoxControl::SvxGrafRedToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SvxGrafToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxGrafGreenToolBoxControl, SfxInt16Item );
+
+SvxGrafGreenToolBoxControl::SvxGrafGreenToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SvxGrafToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxGrafBlueToolBoxControl, SfxInt16Item );
+
+SvxGrafBlueToolBoxControl::SvxGrafBlueToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SvxGrafToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxGrafLuminanceToolBoxControl, SfxInt16Item );
+
+SvxGrafLuminanceToolBoxControl::SvxGrafLuminanceToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SvxGrafToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxGrafContrastToolBoxControl, SfxInt16Item );
+
+SvxGrafContrastToolBoxControl::SvxGrafContrastToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SvxGrafToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxGrafGammaToolBoxControl, SfxUInt32Item );
+
+SvxGrafGammaToolBoxControl::SvxGrafGammaToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SvxGrafToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxGrafTransparenceToolBoxControl, SfxUInt16Item );
+
+SvxGrafTransparenceToolBoxControl::SvxGrafTransparenceToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SvxGrafToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxGrafModeToolBoxControl, SfxUInt16Item );
+
+SvxGrafModeToolBoxControl::SvxGrafModeToolBoxControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+}
+
+SvxGrafModeToolBoxControl::~SvxGrafModeToolBoxControl()
+{
+}
+
+void SvxGrafModeToolBoxControl::StateChangedAtToolBoxControl( sal_uInt16, SfxItemState eState, const SfxPoolItem* pState )
+
+{
+ ImplGrafModeControl* pCtrl = static_cast<ImplGrafModeControl*>( GetToolBox().GetItemWindow( GetId() ) );
+ DBG_ASSERT( pCtrl, "Control not found" );
+
+ if( eState == SfxItemState::DISABLED )
+ {
+ pCtrl->set_sensitive(false);
+ pCtrl->set_active(-1);
+ }
+ else
+ {
+ pCtrl->set_sensitive(true);
+
+ if( eState == SfxItemState::DEFAULT )
+ pCtrl->Update( pState );
+ else
+ pCtrl->Update( nullptr );
+ }
+}
+
+VclPtr<InterimItemWindow> SvxGrafModeToolBoxControl::CreateItemWindow( vcl::Window *pParent )
+{
+ return VclPtr<ImplGrafModeControl>::Create( pParent, m_xFrame ).get();
+}
+
+void SvxGrafAttrHelper::ExecuteGrafAttr( SfxRequest& rReq, SdrView& rView )
+{
+ SfxItemPool& rPool = rView.GetModel()->GetItemPool();
+ SfxItemSetFixed<SDRATTR_GRAF_FIRST, SDRATTR_GRAF_LAST> aSet( rPool );
+ OUString aUndoStr;
+ const bool bUndo = rView.IsUndoEnabled();
+
+ if( bUndo )
+ {
+ aUndoStr = rView.GetDescriptionOfMarkedObjects() + " ";
+ }
+
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ const SfxPoolItem* pItem;
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ if( !pArgs || SfxItemState::SET != pArgs->GetItemState( nSlot, false, &pItem ))
+ pItem = nullptr;
+
+ switch( nSlot )
+ {
+ case SID_ATTR_GRAF_RED:
+ {
+ if( pItem )
+ {
+ aSet.Put( SdrGrafRedItem( static_cast<const SfxInt16Item*>(pItem)->GetValue() ));
+ if( bUndo )
+ aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFRED );
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_GREEN:
+ {
+ if( pItem )
+ {
+ aSet.Put( SdrGrafGreenItem( static_cast<const SfxInt16Item*>(pItem)->GetValue() ));
+ if( bUndo )
+ aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFGREEN );
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_BLUE:
+ {
+ if( pItem )
+ {
+ aSet.Put( SdrGrafBlueItem( static_cast<const SfxInt16Item*>(pItem)->GetValue() ));
+ if( bUndo )
+ aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFBLUE );
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_LUMINANCE:
+ {
+ if( pItem )
+ {
+ aSet.Put( SdrGrafLuminanceItem( static_cast<const SfxInt16Item*>(pItem)->GetValue() ));
+ if( bUndo )
+ aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFLUMINANCE );
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_CONTRAST:
+ {
+ if( pItem )
+ {
+ aSet.Put( SdrGrafContrastItem( static_cast<const SfxInt16Item*>(pItem)->GetValue() ));
+ if( bUndo )
+ aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFCONTRAST );
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_GAMMA:
+ {
+ if( pItem )
+ {
+ aSet.Put( SdrGrafGamma100Item( static_cast<const SfxUInt32Item*>(pItem)->GetValue() ));
+ if( bUndo )
+ aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFGAMMA );
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_TRANSPARENCE:
+ {
+ if( pItem )
+ {
+ aSet.Put( SdrGrafTransparenceItem( static_cast<const SfxUInt16Item*>(pItem)->GetValue() ));
+ if( bUndo )
+ aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFTRANSPARENCY );
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_MODE:
+ {
+ if( pItem )
+ {
+ aSet.Put( SdrGrafModeItem( static_cast<GraphicDrawMode>(static_cast<const SfxUInt16Item*>(pItem)->GetValue()) ));
+ if( bUndo )
+ aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFMODE );
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_CROP:
+ {
+ const SdrMarkList& rMarkList = rView.GetMarkedObjectList();
+
+ if( 0 < rMarkList.GetMarkCount() )
+ {
+ SdrGrafObj* pObj = static_cast<SdrGrafObj*>( rMarkList.GetMark( 0 )->GetMarkedSdrObj() );
+
+ if( ( pObj->GetGraphicType() != GraphicType::NONE ) &&
+ ( pObj->GetGraphicType() != GraphicType::Default ) )
+ {
+ SfxItemSetFixed<SDRATTR_GRAFCROP, SDRATTR_GRAFCROP> aGrfAttr( rPool );
+ const MapUnit eOldMetric = rPool.GetMetric( 0 );
+
+ aGrfAttr.Put(pObj->GetMergedItemSet());
+ rPool.SetDefaultMetric( MapUnit::MapTwip );
+
+ SfxItemSetFixed<
+ SDRATTR_GRAFCROP, SDRATTR_GRAFCROP,
+ SID_ATTR_PAGE_SIZE, SID_ATTR_PAGE_SIZE,
+ SID_ATTR_GRAF_CROP, SID_ATTR_GRAF_FRMSIZE,
+ SID_ATTR_GRAF_GRAPHIC, SID_ATTR_GRAF_GRAPHIC>
+ aCropDlgAttr(rPool);
+
+ aCropDlgAttr.Put( SvxBrushItem( pObj->GetGraphic(), GPOS_MM, SID_ATTR_GRAF_GRAPHIC ) );
+ aCropDlgAttr.Put( SvxSizeItem( SID_ATTR_PAGE_SIZE,
+ o3tl::convert(Size(200000, 200000), o3tl::Length::mm100, o3tl::Length::twip)));
+ aCropDlgAttr.Put( SvxSizeItem( SID_ATTR_GRAF_FRMSIZE,
+ o3tl::convert(pObj->GetLogicRect().GetSize(), o3tl::Length::mm100, o3tl::Length::twip)));
+
+ const SdrGrafCropItem& rCrop = aGrfAttr.Get( SDRATTR_GRAFCROP );
+ Size aLTSize = o3tl::convert(Size(rCrop.GetLeft(), rCrop.GetTop()), o3tl::Length::mm100, o3tl::Length::twip);
+ Size aRBSize = o3tl::convert(Size(rCrop.GetRight(), rCrop.GetBottom()), o3tl::Length::mm100, o3tl::Length::twip);
+
+ aCropDlgAttr.Put( SdrGrafCropItem( aLTSize.Width(), aLTSize.Height(),
+ aRBSize.Width(), aRBSize.Height() ) );
+
+ vcl::Window* pParent(SfxViewShell::Current() ? SfxViewShell::Current()->GetWindow() : nullptr);
+ SfxSingleTabDialogController aCropDialog(pParent ? pParent->GetFrameWeld() : nullptr,
+ &aCropDlgAttr);
+ const OUString aCropStr(SvxResId(RID_SVXSTR_GRAFCROP));
+
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc( RID_SVXPAGE_GRFCROP );
+ std::unique_ptr<SfxTabPage> xTabPage = (*fnCreatePage)(aCropDialog.get_content_area(), &aCropDialog, &aCropDlgAttr);
+ sal_Int32 nPreferredDPI = rView.getSdrModelFromSdrView().getImagePreferredDPI();
+ xTabPage->getAdditionalProperties().emplace("PreferredDPI", css::uno::Any(nPreferredDPI));
+ xTabPage->SetPageTitle(aCropStr);
+ aCropDialog.SetTabPage(std::move(xTabPage));
+
+ if (aCropDialog.run() == RET_OK)
+ {
+ const SfxItemSet* pOutAttr = aCropDialog.GetOutputItemSet();
+
+ if( pOutAttr )
+ {
+ aUndoStr += SvxResId( RID_SVXSTR_UNDO_GRAFCROP );
+
+ // set crop attributes
+ if( SfxItemState::SET <= pOutAttr->GetItemState( SDRATTR_GRAFCROP ) )
+ {
+ const SdrGrafCropItem& rNewCrop = pOutAttr->Get( SDRATTR_GRAFCROP );
+
+ aLTSize = o3tl::convert(Size(rNewCrop.GetLeft(), rNewCrop.GetTop()), o3tl::Length::twip, o3tl::Length::mm100);
+ aRBSize = o3tl::convert(Size(rNewCrop.GetRight(), rNewCrop.GetBottom()), o3tl::Length::twip, o3tl::Length::mm100);
+ aSet.Put( SdrGrafCropItem( aLTSize.Width(), aLTSize.Height(), aRBSize.Width(), aRBSize.Height() ) );
+ }
+
+ // set new logic rect
+ if( SfxItemState::SET <= pOutAttr->GetItemState( SID_ATTR_GRAF_FRMSIZE ) )
+ {
+ Point aNewOrigin( pObj->GetLogicRect().TopLeft() );
+ const Size& rGrfSize = pOutAttr->Get( SID_ATTR_GRAF_FRMSIZE ).GetSize();
+ Size aNewGrfSize = o3tl::convert(rGrfSize, o3tl::Length::twip, o3tl::Length::mm100);
+ Size aOldGrfSize( pObj->GetLogicRect().GetSize() );
+
+ tools::Rectangle aNewRect( aNewOrigin, aNewGrfSize );
+ Point aOffset( (aNewGrfSize.Width() - aOldGrfSize.Width()) >> 1,
+ (aNewGrfSize.Height() - aOldGrfSize.Height()) >> 1 );
+
+ // #106181# rotate snap rect before setting it
+ const GeoStat& aGeo = pObj->GetGeoStat();
+
+ if (aGeo.nRotationAngle || aGeo.nShearAngle)
+ {
+ tools::Polygon aPol(aNewRect);
+
+ // also transform origin offset
+ if (aGeo.nShearAngle)
+ {
+ ShearPoly(aPol,
+ aNewRect.TopLeft(),
+ aGeo.mfTanShearAngle);
+ ShearPoint(aOffset, Point(0,0), aGeo.mfTanShearAngle);
+ }
+ if (aGeo.nRotationAngle)
+ {
+ RotatePoly(aPol,
+ aNewRect.TopLeft(),
+ aGeo.mfSinRotationAngle,aGeo.mfCosRotationAngle);
+ RotatePoint(aOffset, Point(0,0), aGeo.mfSinRotationAngle,aGeo.mfCosRotationAngle);
+ }
+
+ // apply offset
+ aPol.Move( -aOffset.X(), -aOffset.Y() );
+ aNewRect=aPol.GetBoundRect();
+ }
+ else
+ {
+ aNewRect.Move( -aOffset.X(), -aOffset.Y() );
+ }
+
+ if( !aSet.Count() )
+ rView.SetMarkedObjRect( aNewRect );
+ else
+ {
+ if( bUndo )
+ {
+ rView.BegUndo( aUndoStr );
+ rView.AddUndo( rView.GetModel()->GetSdrUndoFactory().CreateUndoGeoObject( *pObj ) );
+ }
+ pObj->SetSnapRect( aNewRect );
+ rView.SetAttributes( aSet );
+
+ if( bUndo )
+ rView.EndUndo();
+ aSet.ClearItem();
+ }
+ }
+ }
+ }
+
+ rPool.SetDefaultMetric( eOldMetric );
+ }
+ }
+ }
+ break;
+
+ case SID_COLOR_SETTINGS:
+ {
+ svx::ToolboxAccess aToolboxAccess( TOOLBOX_NAME );
+ aToolboxAccess.toggleToolbox();
+ rReq.Done();
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if( aSet.Count() )
+ {
+ if( bUndo )
+ rView.BegUndo( aUndoStr );
+
+ rView.SetAttributes( aSet );
+
+ if( bUndo )
+ rView.EndUndo();
+ }
+}
+
+void SvxGrafAttrHelper::GetGrafAttrState( SfxItemSet& rSet, SdrView const & rView )
+{
+ SfxItemPool& rPool = rView.GetModel()->GetItemPool();
+ SfxItemSet aAttrSet( rPool );
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ const SdrMarkList& rMarkList = rView.GetMarkedObjectList();
+ bool bEnableColors = true;
+ bool bEnableTransparency = true;
+ bool bEnableCrop = ( 1 == rMarkList.GetMarkCount() );
+
+ for( size_t i = 0, nCount = rMarkList.GetMarkCount(); i < nCount; ++i )
+ {
+ SdrGrafObj* pGrafObj = dynamic_cast< SdrGrafObj* >( rMarkList.GetMark( i )->GetMarkedSdrObj() );
+
+ if( !pGrafObj ||
+ ( pGrafObj->GetGraphicType() == GraphicType::NONE ) ||
+ ( pGrafObj->GetGraphicType() == GraphicType::Default ))
+ {
+ bEnableColors = bEnableTransparency = bEnableCrop = false;
+ break;
+ }
+ else if( bEnableTransparency && ( pGrafObj->HasGDIMetaFile() || pGrafObj->IsAnimated() ) )
+ {
+ bEnableTransparency = false;
+ }
+ }
+
+ rView.GetAttributes( aAttrSet );
+
+ while( nWhich )
+ {
+ sal_uInt16 nSlotId = SfxItemPool::IsWhich( nWhich ) ? rPool.GetSlotId( nWhich ) : nWhich;
+
+ switch( nSlotId )
+ {
+ case SID_ATTR_GRAF_MODE:
+ {
+ if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFMODE ) )
+ {
+ if( bEnableColors )
+ {
+ rSet.Put( SfxUInt16Item( nSlotId,
+ sal::static_int_cast< sal_uInt16 >( aAttrSet.Get(SDRATTR_GRAFMODE).GetValue() ) ) );
+ }
+ else
+ {
+ rSet.DisableItem( SID_ATTR_GRAF_MODE );
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_RED:
+ {
+ if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFRED ) )
+ {
+ if( bEnableColors )
+ {
+ rSet.Put( SfxInt16Item( nSlotId, aAttrSet.Get(SDRATTR_GRAFRED).GetValue() ) );
+ }
+ else
+ {
+ rSet.DisableItem( SID_ATTR_GRAF_RED );
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_GREEN:
+ {
+ if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFGREEN ) )
+ {
+ if( bEnableColors )
+ {
+ rSet.Put( SfxInt16Item( nSlotId, aAttrSet.Get(SDRATTR_GRAFGREEN).GetValue()) );
+ }
+ else
+ {
+ rSet.DisableItem( SID_ATTR_GRAF_GREEN );
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_BLUE:
+ {
+ if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFBLUE ) )
+ {
+ if( bEnableColors )
+ {
+ rSet.Put( SfxInt16Item( nSlotId, aAttrSet.Get(SDRATTR_GRAFBLUE).GetValue()) );
+ }
+ else
+ {
+ rSet.DisableItem( SID_ATTR_GRAF_BLUE );
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_LUMINANCE:
+ {
+ if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFLUMINANCE ) )
+ {
+ if( bEnableColors )
+ {
+ rSet.Put( SfxInt16Item( nSlotId, aAttrSet.Get(SDRATTR_GRAFLUMINANCE).GetValue()) );
+ }
+ else
+ {
+ rSet.DisableItem( SID_ATTR_GRAF_LUMINANCE );
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_CONTRAST:
+ {
+ if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFCONTRAST ) )
+ {
+ if( bEnableColors )
+ {
+ rSet.Put( SfxInt16Item( nSlotId,
+ aAttrSet.Get(SDRATTR_GRAFCONTRAST).GetValue()) );
+ }
+ else
+ {
+ rSet.DisableItem( SID_ATTR_GRAF_CONTRAST );
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_GAMMA:
+ {
+ if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFGAMMA ) )
+ {
+ if( bEnableColors )
+ {
+ rSet.Put( SfxUInt32Item( nSlotId,
+ aAttrSet.Get(SDRATTR_GRAFGAMMA).GetValue() ) );
+ }
+ else
+ {
+ rSet.DisableItem( SID_ATTR_GRAF_GAMMA );
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_TRANSPARENCE:
+ {
+ if( SfxItemState::DEFAULT <= aAttrSet.GetItemState( SDRATTR_GRAFTRANSPARENCE ) )
+ {
+ if( bEnableTransparency )
+ {
+ rSet.Put( SfxUInt16Item( nSlotId,
+ aAttrSet.Get(SDRATTR_GRAFTRANSPARENCE).GetValue() ) );
+ }
+ else
+ {
+ rSet.DisableItem( SID_ATTR_GRAF_TRANSPARENCE );
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_GRAF_CROP:
+ {
+ if( !bEnableCrop )
+ rSet.DisableItem( nSlotId );
+ }
+ break;
+
+ case SID_COLOR_SETTINGS :
+ {
+ svx::ToolboxAccess aToolboxAccess( TOOLBOX_NAME );
+ rSet.Put( SfxBoolItem( nWhich, aToolboxAccess.isToolboxVisible() ) );
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/itemwin.cxx b/svx/source/tbxctrls/itemwin.cxx
new file mode 100644
index 000000000..1a9b6d3bc
--- /dev/null
+++ b/svx/source/tbxctrls/itemwin.cxx
@@ -0,0 +1,347 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/module.hxx>
+
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+#include <svx/xlnwtit.hxx>
+#include <svx/xtable.hxx>
+#include <svx/itemwin.hxx>
+#include <svtools/unitconv.hxx>
+#include "linemetricbox.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+
+SvxMetricField::SvxMetricField(
+ vcl::Window* pParent, const Reference< XFrame >& rFrame )
+ : InterimItemWindow(pParent, "svx/ui/metricfieldbox.ui", "MetricFieldBox")
+ , m_xWidget(m_xBuilder->weld_metric_spin_button("metricfield", FieldUnit::MM))
+ , nCurValue(0)
+ , eDestPoolUnit(MapUnit::Map100thMM)
+ , eDlgUnit(SfxModule::GetModuleFieldUnit(rFrame))
+ , mxFrame(rFrame)
+{
+ InitControlBase(&m_xWidget->get_widget());
+
+ m_xWidget->set_range(0, 5000, FieldUnit::NONE);
+ m_xWidget->connect_value_changed(LINK(this, SvxMetricField, ModifyHdl));
+ m_xWidget->connect_focus_in(LINK(this, SvxMetricField, FocusInHdl));
+ m_xWidget->get_widget().connect_key_press(LINK(this, SvxMetricField, KeyInputHdl));
+
+ SetFieldUnit(*m_xWidget, eDlgUnit);
+
+ SetSizePixel(m_xWidget->get_preferred_size());
+}
+
+void SvxMetricField::dispose()
+{
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+}
+
+SvxMetricField::~SvxMetricField()
+{
+ disposeOnce();
+}
+
+void SvxMetricField::set_sensitive(bool bSensitive)
+{
+ Enable(bSensitive);
+ m_xWidget->set_sensitive(bSensitive);
+ if (!bSensitive)
+ m_xWidget->set_text("");
+}
+
+void SvxMetricField::Update( const XLineWidthItem* pItem )
+{
+ if ( pItem )
+ {
+ // tdf#132169 we always get the value in MapUnit::Map100thMM but have
+ // to set it in the core metric of the target application
+ if (pItem->GetValue() != GetCoreValue(*m_xWidget, MapUnit::Map100thMM))
+ SetMetricValue(*m_xWidget, pItem->GetValue(), MapUnit::Map100thMM);
+ }
+ else
+ m_xWidget->set_text("");
+}
+
+IMPL_LINK_NOARG(SvxMetricField, ModifyHdl, weld::MetricSpinButton&, void)
+{
+ auto nTmp = GetCoreValue(*m_xWidget, eDestPoolUnit);
+ XLineWidthItem aLineWidthItem( nTmp );
+
+ Any a;
+ aLineWidthItem.QueryValue( a );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("LineWidth", a) };
+ SfxToolBoxControl::Dispatch( Reference< XDispatchProvider >( mxFrame->getController(), UNO_QUERY ),
+ ".uno:LineWidth",
+ aArgs );
+}
+
+void SvxMetricField::ReleaseFocus_Impl()
+{
+ if( SfxViewShell::Current() )
+ {
+ vcl::Window* pShellWnd = SfxViewShell::Current()->GetWindow();
+ if ( pShellWnd )
+ pShellWnd->GrabFocus();
+ }
+}
+
+void SvxMetricField::SetDestCoreUnit( MapUnit eUnit )
+{
+ eDestPoolUnit = eUnit;
+}
+
+void SvxMetricField::RefreshDlgUnit()
+{
+ FieldUnit eTmpUnit = SfxModule::GetModuleFieldUnit( mxFrame );
+ if ( eDlgUnit != eTmpUnit )
+ {
+ eDlgUnit = eTmpUnit;
+ SetFieldUnit(*m_xWidget, eDlgUnit);
+ }
+}
+
+IMPL_LINK_NOARG(SvxMetricField, FocusInHdl, weld::Widget&, void)
+{
+ nCurValue = m_xWidget->get_value(FieldUnit::NONE);
+}
+
+IMPL_LINK(SvxMetricField, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+
+ if (nCode == KEY_ESCAPE)
+ {
+ m_xWidget->set_value(nCurValue, FieldUnit::NONE);
+ ModifyHdl(*m_xWidget);
+ ReleaseFocus_Impl();
+ bHandled = true;
+ }
+
+ return bHandled || ChildKeyInput(rKEvt);
+}
+
+void SvxMetricField::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ SetSizePixel(m_xWidget->get_preferred_size());
+ }
+
+ InterimItemWindow::DataChanged( rDCEvt );
+}
+
+void SvxFillTypeBox::Fill(weld::ComboBox& rListBox)
+{
+ rListBox.freeze();
+
+ rListBox.append_text(SvxResId(RID_SVXSTR_INVISIBLE));
+ rListBox.append_text(SvxResId(RID_SVXSTR_COLOR));
+ rListBox.append_text(SvxResId(RID_SVXSTR_GRADIENT));
+ rListBox.append_text(SvxResId(RID_SVXSTR_HATCH));
+ rListBox.append_text(SvxResId(RID_SVXSTR_BITMAP));
+ rListBox.append_text(SvxResId(RID_SVXSTR_PATTERN));
+ rListBox.append_text(SvxResId(RID_SVXSTR_USE_BACKGROUND));
+
+ rListBox.thaw();
+
+ rListBox.set_active(1); // solid color
+}
+
+namespace
+{
+ void formatBitmapExToSize(BitmapEx& rBitmapEx, const Size& rSize)
+ {
+ if(rBitmapEx.IsEmpty() || rSize.IsEmpty())
+ return;
+
+ ScopedVclPtrInstance< VirtualDevice > pVirtualDevice;
+ pVirtualDevice->SetOutputSizePixel(rSize);
+
+ if(rBitmapEx.IsAlpha())
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ if(rStyleSettings.GetPreviewUsesCheckeredBackground())
+ {
+ const Point aNull(0, 0);
+ static const sal_uInt32 nLen(8);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+
+ pVirtualDevice->DrawCheckered(aNull, rSize, nLen, aW, aG);
+ }
+ else
+ {
+ pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor());
+ pVirtualDevice->Erase();
+ }
+ }
+
+ if(rBitmapEx.GetSizePixel().Width() >= rSize.Width() && rBitmapEx.GetSizePixel().Height() >= rSize.Height())
+ {
+ rBitmapEx.Scale(rSize);
+ pVirtualDevice->DrawBitmapEx(Point(0, 0), rBitmapEx);
+ }
+ else
+ {
+ const Size aBitmapSize(rBitmapEx.GetSizePixel());
+
+ for(tools::Long y(0); y < rSize.Height(); y += aBitmapSize.Height())
+ {
+ for(tools::Long x(0); x < rSize.Width(); x += aBitmapSize.Width())
+ {
+ pVirtualDevice->DrawBitmapEx(
+ Point(x, y),
+ rBitmapEx);
+ }
+ }
+ }
+
+ rBitmapEx = pVirtualDevice->GetBitmapEx(Point(0, 0), rSize);
+ }
+} // end of anonymous namespace
+
+void SvxFillAttrBox::Fill(weld::ComboBox& rBox, const XHatchListRef &pList)
+{
+ if( !pList.is() )
+ return;
+
+ tools::Long nCount = pList->Count();
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ rBox.freeze();
+
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ const XHatchEntry* pEntry = pList->GetHatch(i);
+ const BitmapEx aBitmapEx = pList->GetUiBitmap( i );
+ if( !aBitmapEx.IsEmpty() )
+ {
+ const Size aBmpSize(aBitmapEx.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), aBitmapEx);
+ rBox.append("", pEntry->GetName(), *pVD);
+ }
+ else
+ rBox.append_text(pEntry->GetName());
+ }
+
+ rBox.thaw();
+}
+
+void SvxFillAttrBox::Fill(weld::ComboBox& rBox, const XGradientListRef &pList)
+{
+ if( !pList.is() )
+ return;
+
+ tools::Long nCount = pList->Count();
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ rBox.freeze();
+
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ const XGradientEntry* pEntry = pList->GetGradient(i);
+ const BitmapEx aBitmapEx = pList->GetUiBitmap( i );
+ if( !aBitmapEx.IsEmpty() )
+ {
+ const Size aBmpSize(aBitmapEx.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), aBitmapEx);
+ rBox.append("", pEntry->GetName(), *pVD);
+ }
+ else
+ rBox.append_text(pEntry->GetName());
+ }
+
+ rBox.thaw();
+}
+
+void SvxFillAttrBox::Fill(weld::ComboBox& rBox, const XBitmapListRef &pList)
+{
+ if( !pList.is() )
+ return;
+
+ tools::Long nCount = pList->Count();
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Size aSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize());
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ pVD->SetOutputSizePixel(aSize, false);
+ rBox.freeze();
+
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ const XBitmapEntry* pEntry = pList->GetBitmap( i );
+ BitmapEx aBitmapEx = pEntry->GetGraphicObject().GetGraphic().GetBitmapEx();
+ formatBitmapExToSize(aBitmapEx, aSize);
+ pVD->DrawBitmapEx(Point(), aBitmapEx);
+ rBox.append("", pEntry->GetName(), *pVD);
+ }
+
+ rBox.thaw();
+}
+
+void SvxFillAttrBox::Fill(weld::ComboBox& rBox, const XPatternListRef &pList)
+{
+ if( !pList.is() )
+ return;
+
+ tools::Long nCount = pList->Count();
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Size aSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize());
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ pVD->SetOutputSizePixel(aSize, false);
+ rBox.freeze();
+
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ const XBitmapEntry* pEntry = pList->GetBitmap( i );
+ BitmapEx aBitmapEx = pEntry->GetGraphicObject().GetGraphic().GetBitmapEx();
+ formatBitmapExToSize(aBitmapEx, aSize);
+ pVD->DrawBitmapEx(Point(), aBitmapEx);
+ rBox.append("", pEntry->GetName(), *pVD);
+ }
+
+ rBox.thaw();
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/layctrl.cxx b/svx/source/tbxctrls/layctrl.cxx
new file mode 100644
index 000000000..79dd794fd
--- /dev/null
+++ b/svx/source/tbxctrls/layctrl.cxx
@@ -0,0 +1,798 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/customweld.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/toolbox.hxx>
+
+#include <svx/strings.hrc>
+#include <layctrl.hxx>
+#include <svx/dialmgr.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svtools/toolbarmenu.hxx>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+
+// namespaces
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::frame;
+
+namespace {
+
+class TableWidget final : public weld::CustomWidgetController
+{
+private:
+ rtl::Reference<SvxTableToolBoxControl> mxControl;
+ OUString maCommand;
+
+ tools::Long nCol;
+ tools::Long nLine;
+
+ static const tools::Long TABLE_CELLS_HORIZ;
+ static const tools::Long TABLE_CELLS_VERT;
+
+ tools::Long mnTableCellWidth;
+ tools::Long mnTableCellHeight;
+
+ tools::Long mnTableWidth;
+ tools::Long mnTableHeight;
+
+ ::Color aFontColor;
+ ::Color aLineColor;
+ ::Color aFillColor;
+ ::Color aHighlightFillColor;
+ ::Color aBackgroundColor;
+
+ void Update(tools::Long nNewCol, tools::Long nNewLine);
+ void InsertTable();
+
+public:
+ TableWidget(SvxTableToolBoxControl* pControl, const OUString& rCommand);
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+ virtual bool KeyInput(const KeyEvent&) override;
+ virtual bool MouseButtonDown(const MouseEvent&) override;
+ virtual bool MouseMove(const MouseEvent&) override;
+ virtual bool MouseButtonUp(const MouseEvent&) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+};
+
+class TableWindow final : public WeldToolbarPopup
+{
+private:
+ std::unique_ptr<weld::Button> mxTableButton;
+ std::unique_ptr<TableWidget> mxTableWidget;
+ std::unique_ptr<weld::CustomWeld> mxTableWidgetWin;
+ rtl::Reference<SvxTableToolBoxControl> mxControl;
+
+ DECL_LINK(SelectHdl, weld::Button&, void);
+
+public:
+ TableWindow( SvxTableToolBoxControl* pControl, weld::Widget* pParent,
+ const OUString& rCmd);
+ virtual void GrabFocus() override
+ {
+ mxTableWidget->GrabFocus();
+ }
+};
+
+}
+
+const tools::Long TableWidget::TABLE_CELLS_HORIZ = 10;
+const tools::Long TableWidget::TABLE_CELLS_VERT = 15;
+
+IMPL_LINK_NOARG(TableWindow, SelectHdl, weld::Button&, void)
+{
+ mxControl->CloseAndShowTableDialog();
+}
+
+TableWindow::TableWindow(SvxTableToolBoxControl* pControl, weld::Widget* pParent, const OUString& rCmd)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/tablewindow.ui", "TableWindow")
+ , mxTableButton(m_xBuilder->weld_button("moreoptions"))
+ , mxTableWidget(new TableWidget(pControl, rCmd))
+ , mxTableWidgetWin(new weld::CustomWeld(*m_xBuilder, "table", *mxTableWidget))
+ , mxControl(pControl)
+{
+ mxTableButton->set_label( SvxResId( RID_SVXSTR_MORE ) );
+ mxTableButton->connect_clicked( LINK( this, TableWindow, SelectHdl ) );
+ mxTableButton->show();
+}
+
+TableWidget::TableWidget(SvxTableToolBoxControl* pControl, const OUString& rCommand)
+ : mxControl(pControl)
+ , maCommand(rCommand)
+ , nCol(0)
+ , nLine(0)
+ , mnTableCellWidth(0)
+ , mnTableCellHeight(0)
+ , mnTableWidth(0)
+ , mnTableHeight(0)
+{
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ aFontColor = rStyles.GetLabelTextColor();
+ aLineColor = rStyles.GetShadowColor();
+ aFillColor = rStyles.GetWindowColor();
+ aHighlightFillColor = rStyles.GetHighlightColor();
+ aBackgroundColor = rStyles.GetFaceColor();
+}
+
+void TableWidget::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ float fScaleFactor = pDrawingArea->get_ref_device().GetDPIScaleFactor();
+
+ mnTableCellWidth = 15 * fScaleFactor;
+ mnTableCellHeight = 15 * fScaleFactor;
+
+ mnTableWidth = TABLE_CELLS_HORIZ*mnTableCellWidth;
+ mnTableHeight = TABLE_CELLS_VERT*mnTableCellHeight;
+
+ // + 1 to leave space to draw the right/bottom borders
+ Size aSize(mnTableWidth + 1, mnTableHeight + 1);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ SetOutputSizePixel(aSize);
+}
+
+bool TableWidget::MouseMove(const MouseEvent& rMEvt)
+{
+ Point aPos = rMEvt.GetPosPixel();
+ Point aMousePos( aPos );
+
+ tools::Long nNewCol = ( aMousePos.X() + mnTableCellWidth ) / mnTableCellWidth;
+ tools::Long nNewLine = ( aMousePos.Y() + mnTableCellHeight ) / mnTableCellHeight;
+
+ Update( nNewCol, nNewLine );
+
+ return true;
+}
+
+bool TableWidget::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bHandled = false;
+ sal_uInt16 nModifier = rKEvt.GetKeyCode().GetModifier();
+ sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
+ if ( !nModifier )
+ {
+ bHandled = true;
+ tools::Long nNewCol = nCol;
+ tools::Long nNewLine = nLine;
+ switch(nKey)
+ {
+ case KEY_UP:
+ if ( nNewLine > 1 )
+ nNewLine--;
+ else
+ mxControl->EndPopupMode();
+ break;
+ case KEY_DOWN:
+ if ( nNewLine < TABLE_CELLS_VERT )
+ {
+ nNewLine++;
+ if ( nNewCol == 0 )
+ nNewCol = 1;
+ }
+ else
+ mxControl->CloseAndShowTableDialog();
+ break;
+ case KEY_LEFT:
+ if ( nNewCol > 1 )
+ nNewCol--;
+ else
+ mxControl->EndPopupMode();
+ break;
+ case KEY_RIGHT:
+ if ( nNewCol < TABLE_CELLS_HORIZ )
+ {
+ nNewCol++;
+ if ( nNewLine == 0 )
+ nNewLine = 1;
+ }
+ else
+ mxControl->CloseAndShowTableDialog();
+ break;
+ case KEY_ESCAPE:
+ mxControl->EndPopupMode();
+ break;
+ case KEY_RETURN:
+ InsertTable();
+ mxControl->EndPopupMode();
+ return true;
+ default:
+ bHandled = false;
+ }
+ if ( bHandled )
+ {
+ Update( nNewCol, nNewLine );
+ }
+ }
+ else if (KEY_MOD1 == nModifier && KEY_RETURN == nKey)
+ {
+ InsertTable();
+ mxControl->EndPopupMode();
+ return true;
+ }
+
+ return bHandled;
+}
+
+bool TableWidget::MouseButtonUp(const MouseEvent&)
+{
+ InsertTable();
+ mxControl->EndPopupMode();
+ return true;
+}
+
+bool TableWidget::MouseButtonDown(const MouseEvent&)
+{
+ return true;
+}
+
+void TableWidget::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::FONT);
+
+ rRenderContext.SetBackground( aBackgroundColor );
+ vcl::Font aFont = rRenderContext.GetFont();
+ aFont.SetColor( aFontColor );
+ aFont.SetFillColor( aBackgroundColor );
+ aFont.SetTransparent( false );
+ rRenderContext.SetFont( aFont );
+
+ const tools::Long nSelectionWidth = nCol * mnTableCellWidth;
+ const tools::Long nSelectionHeight = nLine * mnTableCellHeight;
+
+ // the non-selected parts of the table
+ rRenderContext.SetLineColor(aLineColor);
+ rRenderContext.SetFillColor(aFillColor);
+ rRenderContext.DrawRect(tools::Rectangle(nSelectionWidth, 0, mnTableWidth, nSelectionHeight));
+ rRenderContext.DrawRect(tools::Rectangle(0, nSelectionHeight, nSelectionWidth, mnTableHeight));
+ rRenderContext.DrawRect(tools::Rectangle(nSelectionWidth, nSelectionHeight, mnTableWidth, mnTableHeight));
+
+ // the selection
+ if (nCol > 0 && nLine > 0)
+ {
+ rRenderContext.SetFillColor(aHighlightFillColor);
+ rRenderContext.DrawRect(tools::Rectangle(0, 0, nSelectionWidth, nSelectionHeight));
+ }
+
+ // lines inside of the table
+ rRenderContext.SetLineColor(aLineColor);
+ for (tools::Long i = 1; i < TABLE_CELLS_VERT; ++i)
+ {
+ rRenderContext.DrawLine(Point(0, i*mnTableCellHeight),
+ Point(mnTableWidth, i*mnTableCellHeight));
+ }
+
+ for (tools::Long i = 1; i < TABLE_CELLS_HORIZ; ++i)
+ {
+ rRenderContext.DrawLine(Point( i*mnTableCellWidth, 0),
+ Point( i*mnTableCellWidth, mnTableHeight));
+ }
+
+ // the text near the mouse cursor telling the table dimensions
+ if (!nCol || !nLine)
+ {
+ rRenderContext.Pop();
+ return;
+ }
+
+ OUString aText = OUString::number( nCol ) + " x " + OUString::number( nLine );
+ if (maCommand == ".uno:ShowMultiplePages")
+ {
+ aText += " " + SvxResId(RID_SVXSTR_PAGES);
+ }
+
+ Size aTextSize(rRenderContext.GetTextWidth(aText), rRenderContext.GetTextHeight());
+
+ tools::Long nTextX = nSelectionWidth + mnTableCellWidth;
+ tools::Long nTextY = nSelectionHeight + mnTableCellHeight;
+ const tools::Long nTipBorder = 2;
+
+ if (aTextSize.Width() + mnTableCellWidth + 2 * nTipBorder < nSelectionWidth)
+ nTextX = nSelectionWidth - mnTableCellWidth - aTextSize.Width();
+
+ if (aTextSize.Height() + mnTableCellHeight + 2 * nTipBorder < nSelectionHeight)
+ nTextY = nSelectionHeight - mnTableCellHeight - aTextSize.Height();
+
+ rRenderContext.SetLineColor(aLineColor);
+ rRenderContext.SetFillColor(aBackgroundColor);
+ rRenderContext.DrawRect(tools::Rectangle(nTextX - 2 * nTipBorder,
+ nTextY - 2 * nTipBorder,
+ nTextX + aTextSize.Width() + nTipBorder,
+ nTextY + aTextSize.Height() + nTipBorder));
+
+ // #i95350# force RTL output
+ if (IsRTLEnabled())
+ aText = u"\u202D" + aText;
+
+ rRenderContext.DrawText(Point(nTextX, nTextY), aText);
+
+ rRenderContext.Pop();
+}
+
+void TableWidget::InsertTable()
+{
+ if (nCol && nLine)
+ {
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("Columns", sal_Int16( nCol )),
+ comphelper::makePropertyValue("Rows", sal_Int16( nLine )) };
+
+ mxControl->TableDialog( aArgs );
+ }
+}
+
+void TableWidget::Update( tools::Long nNewCol, tools::Long nNewLine )
+{
+ if ( nNewCol < 0 || nNewCol > TABLE_CELLS_HORIZ )
+ nNewCol = 0;
+
+ if ( nNewLine < 0 || nNewLine > TABLE_CELLS_VERT )
+ nNewLine = 0;
+
+ if ( nNewCol != nCol || nNewLine != nLine )
+ {
+ nCol = nNewCol;
+ nLine = nNewLine;
+ Invalidate(tools::Rectangle(0, 0, mnTableWidth, mnTableHeight));
+ }
+}
+
+void SvxTableToolBoxControl::TableDialog( const Sequence< PropertyValue >& rArgs )
+{
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ if ( xDispatchProvider.is() )
+ {
+ css::util::URL aTargetURL;
+ Reference < XURLTransformer > xTrans( URLTransformer::create(::comphelper::getProcessComponentContext()) );
+ aTargetURL.Complete = m_aCommandURL;
+ xTrans->parseStrict( aTargetURL );
+
+ Reference< XDispatch > xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+ if ( xDispatch.is() )
+ xDispatch->dispatch( aTargetURL, rArgs );
+ }
+}
+
+void SvxTableToolBoxControl::CloseAndShowTableDialog()
+{
+ // close the toolbar tool
+ EndPopupMode();
+
+ // and open the table dialog instead
+ TableDialog( Sequence< PropertyValue >() );
+}
+
+namespace {
+
+class ColumnsWidget final : public weld::CustomWidgetController
+{
+private:
+ static constexpr tools::Long WIDTH = 5;
+
+ rtl::Reference<SvxColumnsToolBoxControl> mxControl;
+ weld::SpinButton& mrSpinButton;
+
+ ::Color aLineColor;
+ ::Color aHighlightLineColor;
+ ::Color aFillColor;
+ ::Color aHighlightFillColor;
+ ::Color aFaceColor;
+ tools::Long nCol;
+ tools::Long nMX;
+ bool m_bMod1;
+
+ DECL_LINK(ValueChangedHdl, weld::SpinButton&, void);
+ DECL_LINK(ActivateHdl, weld::Entry&, bool);
+
+ void InsertColumns();
+ void UpdateSize_Impl( tools::Long nNewCol );
+public:
+ ColumnsWidget(SvxColumnsToolBoxControl* pControl, weld::SpinButton& rSpinButton);
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+ virtual bool KeyInput(const KeyEvent&) override;
+ virtual bool MouseButtonDown(const MouseEvent&) override;
+ virtual bool MouseMove(const MouseEvent&) override;
+ virtual bool MouseButtonUp(const MouseEvent&) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+};
+
+
+class ColumnsWindow final : public WeldToolbarPopup
+{
+private:
+ std::unique_ptr<weld::SpinButton> mxSpinButton;
+ std::unique_ptr<ColumnsWidget> mxColumnsWidget;
+ std::unique_ptr<weld::CustomWeld> mxColumnsWidgetWin;
+ rtl::Reference<SvxColumnsToolBoxControl> mxControl;
+
+public:
+ ColumnsWindow(SvxColumnsToolBoxControl* pControl, weld::Widget* pParent);
+
+ virtual void GrabFocus() override
+ {
+ mxColumnsWidget->GrabFocus();
+ }
+};
+
+}
+
+ColumnsWindow::ColumnsWindow(SvxColumnsToolBoxControl* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/columnswindow.ui", "ColumnsWindow")
+ , mxSpinButton(m_xBuilder->weld_spin_button("spinbutton"))
+ , mxColumnsWidget(new ColumnsWidget(pControl, *mxSpinButton))
+ , mxColumnsWidgetWin(new weld::CustomWeld(*m_xBuilder, "columns", *mxColumnsWidget))
+ , mxControl(pControl)
+{
+}
+
+ColumnsWidget::ColumnsWidget(SvxColumnsToolBoxControl* pControl, weld::SpinButton& rSpinButton)
+ : mxControl(pControl)
+ , mrSpinButton(rSpinButton)
+ , nCol(1)
+ , nMX(0)
+ , m_bMod1(false)
+{
+ mrSpinButton.connect_value_changed(LINK(this, ColumnsWidget, ValueChangedHdl));
+ mrSpinButton.connect_activate(LINK(this, ColumnsWidget, ActivateHdl));
+
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ aLineColor = rStyles.GetLabelTextColor();
+ aHighlightLineColor = rStyles.GetHighlightTextColor();
+ aFillColor = rStyles.GetWindowColor();
+ aHighlightFillColor = rStyles.GetHighlightColor();
+ aFaceColor = rStyles.GetFaceColor();
+}
+
+IMPL_LINK_NOARG(ColumnsWidget, ValueChangedHdl, weld::SpinButton&, void)
+{
+ UpdateSize_Impl(mrSpinButton.get_value());
+}
+
+IMPL_LINK_NOARG(ColumnsWidget, ActivateHdl, weld::Entry&, bool)
+{
+ InsertColumns();
+ mxControl->EndPopupMode();
+ return true;
+}
+
+void ColumnsWidget::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ OutputDevice& rDevice = pDrawingArea->get_ref_device();
+ Size aLogicSize = rDevice.LogicToPixel( Size( 95, 155 ), MapMode( MapUnit::Map10thMM ) );
+ nMX = aLogicSize.Width();
+ Size aSize(nMX*WIDTH-1, aLogicSize.Height());
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ SetOutputSizePixel(aSize);
+}
+
+bool ColumnsWidget::MouseMove(const MouseEvent& rMEvt)
+{
+ Point aPos = rMEvt.GetPosPixel();
+
+ tools::Long nNewCol = 1;
+ if ( aPos.X() > 0 )
+ nNewCol = aPos.X() / nMX + 1;
+ if ( nNewCol > 20 )
+ nNewCol = 20;
+ UpdateSize_Impl( nNewCol );
+
+ return true;
+}
+
+void ColumnsWidget::UpdateSize_Impl( tools::Long nNewCol )
+{
+ if ( nNewCol == nCol )
+ return;
+
+ Size aWinSize = GetOutputSizePixel();
+
+ Invalidate( tools::Rectangle( 0, aWinSize.Height() - 2,
+ aWinSize.Width(), aWinSize.Height() ) );
+
+ tools::Long nMinCol = 0, nMaxCol = 0;
+
+ if ( nNewCol < nCol )
+ {
+ nMinCol = nNewCol;
+ nMaxCol = nCol;
+ }
+ else
+ {
+ nMinCol = nCol;
+ nMaxCol = nNewCol;
+ }
+
+ Invalidate( tools::Rectangle( nMinCol*nMX-1, 0,
+ nMaxCol*nMX+1, aWinSize.Height() - 2 ) );
+ nCol = nNewCol;
+ mrSpinButton.set_value(nCol);
+}
+
+bool ColumnsWidget::MouseButtonDown(const MouseEvent&)
+{
+ return true;
+}
+
+bool ColumnsWidget::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bHandled = false;
+ sal_uInt16 nModifier = rKEvt.GetKeyCode().GetModifier();
+ sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
+ if(!nModifier)
+ {
+ if( KEY_LEFT == nKey || KEY_RIGHT == nKey ||
+ KEY_RETURN == nKey ||KEY_ESCAPE == nKey ||
+ KEY_UP == nKey)
+ {
+ bHandled = true;
+ tools::Long nNewCol = nCol;
+ switch(nKey)
+ {
+ case KEY_LEFT :
+ if(nNewCol)
+ nNewCol--;
+ break;
+ case KEY_RIGHT :
+ nNewCol++;
+ break;
+ case KEY_RETURN :
+ InsertColumns();
+ mxControl->EndPopupMode();
+ break;
+ case KEY_ESCAPE :
+ case KEY_UP :
+ mxControl->EndPopupMode();
+ break;
+ }
+ UpdateSize_Impl( nNewCol );
+ }
+ }
+ else if(KEY_MOD1 == nModifier && KEY_RETURN == nKey)
+ {
+ m_bMod1 = true;
+ InsertColumns();
+ mxControl->EndPopupMode();
+ }
+ return bHandled;
+}
+
+bool ColumnsWidget::MouseButtonUp(const MouseEvent&)
+{
+ InsertColumns();
+ mxControl->EndPopupMode();
+ return true;
+}
+
+void ColumnsWidget::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::FONT);
+
+ rRenderContext.SetBackground();
+ vcl::Font aFont( rRenderContext.GetFont() );
+ aFont.SetColor( aLineColor );
+ aFont.SetFillColor( aFaceColor );
+ aFont.SetTransparent( false );
+ rRenderContext.SetFont( aFont );
+
+ tools::Long i;
+ tools::Long nLineWidth;
+ Size aSize(GetOutputSizePixel());
+
+ for (i = 0; i < WIDTH; i++)
+ {
+ if (i < nCol)
+ {
+ rRenderContext.SetLineColor(aHighlightLineColor);
+ rRenderContext.SetFillColor(aHighlightFillColor);
+ }
+ else
+ {
+ rRenderContext.SetLineColor(aLineColor);
+ rRenderContext.SetFillColor(aFillColor);
+ }
+
+ rRenderContext.DrawRect(tools::Rectangle(i * nMX - 1, -1, i * nMX + nMX, aSize.Height() - 1));
+
+ tools::Long j = 4;
+ while (j < aSize.Height() - 4)
+ {
+ if (!(j % 16))
+ nLineWidth = 10;
+ else
+ nLineWidth = 4;
+ rRenderContext.DrawLine(Point(i * nMX + 4, j), Point(i * nMX + nMX - nLineWidth - 4, j));
+ j += 4;
+ }
+ }
+
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(aFaceColor);
+
+ rRenderContext.DrawRect(tools::Rectangle(0,
+ aSize.Height() - 2,
+ aSize.Width() / 2 - 1,
+ aSize.Height()));
+
+ rRenderContext.DrawRect(tools::Rectangle(aSize.Width() / 2,
+ aSize.Height() - 2,
+ aSize.Width(),
+ aSize.Height()));
+
+ rRenderContext.SetLineColor(aLineColor);
+ rRenderContext.SetFillColor();
+ rRenderContext.DrawRect(tools::Rectangle( 0, 0, aSize.Width() - 1, aSize.Height() - 1));
+
+ rRenderContext.Pop();
+}
+
+void SvxColumnsToolBoxControl::InsertColumns(const Sequence< PropertyValue >& rArgs)
+{
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ if ( xDispatchProvider.is() )
+ {
+ css::util::URL aTargetURL;
+ Reference < XURLTransformer > xTrans( URLTransformer::create(::comphelper::getProcessComponentContext()) );
+ aTargetURL.Complete = m_aCommandURL;
+ xTrans->parseStrict( aTargetURL );
+
+ Reference< XDispatch > xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+ if ( xDispatch.is() )
+ xDispatch->dispatch( aTargetURL, rArgs );
+ }
+}
+
+void ColumnsWidget::InsertColumns()
+{
+ if (nCol)
+ {
+ Sequence< PropertyValue > aArgs{
+ comphelper::makePropertyValue("Columns", sal_Int16( nCol )),
+ comphelper::makePropertyValue("Modifier", sal_Int16( m_bMod1 ? KEY_MOD1 : 0 ))
+ };
+ mxControl->InsertColumns(aArgs);
+ }
+}
+
+SvxTableToolBoxControl::SvxTableToolBoxControl(const css::uno::Reference<css::uno::XComponentContext>& rContext)
+ : PopupWindowController(rContext, nullptr, OUString())
+{
+}
+
+void SvxTableToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
+{
+ PopupWindowController::initialize(rArguments);
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWNONLY | pToolBox->GetItemBits(nId));
+}
+
+SvxTableToolBoxControl::~SvxTableToolBoxControl()
+{
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxTableToolBoxControl::weldPopupWindow()
+{
+ return std::make_unique<TableWindow>(this, m_pToolbar, m_aCommandURL);
+}
+
+VclPtr<vcl::Window> SvxTableToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ bool bToolBox = getToolboxId(nId, &pToolBox);
+
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<TableWindow>(this, pParent->GetFrameWeld(), m_aCommandURL));
+
+ mxInterimPopover->SetText(bToolBox ? pToolBox->GetItemText(nId) : OUString());
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+OUString SvxTableToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.TableToolBoxControl";
+}
+
+css::uno::Sequence<OUString> SvxTableToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_TableToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire(new SvxTableToolBoxControl(rContext));
+}
+
+SvxColumnsToolBoxControl::SvxColumnsToolBoxControl(const css::uno::Reference<css::uno::XComponentContext>& rContext)
+ : PopupWindowController(rContext, nullptr, OUString())
+{
+}
+
+void SvxColumnsToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
+{
+ PopupWindowController::initialize(rArguments);
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWNONLY | pToolBox->GetItemBits(nId));
+}
+
+SvxColumnsToolBoxControl::~SvxColumnsToolBoxControl()
+{
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxColumnsToolBoxControl::weldPopupWindow()
+{
+ return std::make_unique<ColumnsWindow>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> SvxColumnsToolBoxControl::createVclPopupWindow(vcl::Window* pParent)
+{
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ bool bToolBox = getToolboxId(nId, &pToolBox);
+
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<ColumnsWindow>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->SetText(bToolBox ? pToolBox->GetItemText(nId) : OUString());
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+OUString SvxColumnsToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.ColumnsToolBoxControl";
+}
+
+css::uno::Sequence<OUString> SvxColumnsToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_ColumnsToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire(new SvxColumnsToolBoxControl(rContext));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/lboxctrl.cxx b/svx/source/tbxctrls/lboxctrl.cxx
new file mode 100644
index 000000000..8f628876f
--- /dev/null
+++ b/svx/source/tbxctrls/lboxctrl.cxx
@@ -0,0 +1,347 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+#include <vcl/event.hxx>
+#include <vcl/toolbox.hxx>
+#include <sfx2/bindings.hxx>
+#include <svtools/toolbarmenu.hxx>
+#include <svx/dialmgr.hxx>
+#include <lboxctrl.hxx>
+#include <tools/urlobj.hxx>
+
+#include <svx/strings.hrc>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::frame;
+
+class SvxPopupWindowListBox final : public WeldToolbarPopup
+{
+ rtl::Reference<SvxUndoRedoControl> m_xControl;
+ std::unique_ptr<weld::TreeView> m_xListBox;
+ std::unique_ptr<weld::TreeIter> m_xScratchIter;
+ int m_nSelectedRows;
+ int m_nVisRows;
+
+ void UpdateRow(int nRow);
+
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ActivateHdl, weld::TreeView&, bool);
+ DECL_LINK(MouseMoveHdl, const MouseEvent&, bool);
+ DECL_LINK(MousePressHdl, const MouseEvent&, bool);
+ DECL_LINK(MouseReleaseHdl, const MouseEvent&, bool);
+
+public:
+ SvxPopupWindowListBox(SvxUndoRedoControl* pControl, weld::Widget* pParent,
+ const std::vector<OUString>& rUndoRedoList);
+
+ virtual void GrabFocus() override
+ {
+ m_xListBox->grab_focus();
+ }
+};
+
+SvxPopupWindowListBox::SvxPopupWindowListBox(SvxUndoRedoControl* pControl, weld::Widget* pParent,
+ const std::vector<OUString>& rUndoRedoList)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingundoredo.ui", "FloatingUndoRedo")
+ , m_xControl(pControl)
+ , m_xListBox(m_xBuilder->weld_tree_view("treeview"))
+ , m_xScratchIter(m_xListBox->make_iterator())
+ , m_nVisRows(10)
+{
+ m_xListBox->set_selection_mode(SelectionMode::Multiple);
+
+ for (const OUString& s : rUndoRedoList)
+ m_xListBox->append_text(s);
+ if (!rUndoRedoList.empty())
+ {
+ m_xListBox->set_cursor(0);
+ m_xListBox->select(0);
+ m_nSelectedRows = 1;
+ }
+ else
+ m_nSelectedRows = 0;
+
+ m_xListBox->set_size_request(m_xListBox->get_approximate_digit_width() * 25,
+ m_xListBox->get_height_rows(m_nVisRows) + 2);
+
+ m_xListBox->connect_row_activated(LINK(this, SvxPopupWindowListBox, ActivateHdl));
+ m_xListBox->connect_mouse_move(LINK(this, SvxPopupWindowListBox, MouseMoveHdl));
+ m_xListBox->connect_mouse_press(LINK(this, SvxPopupWindowListBox, MousePressHdl));
+ m_xListBox->connect_mouse_release(LINK(this, SvxPopupWindowListBox, MouseReleaseHdl));
+ m_xListBox->connect_key_press(LINK(this, SvxPopupWindowListBox, KeyInputHdl));
+}
+
+void SvxUndoRedoControl::SetInfo( sal_Int32 nCount )
+{
+ TranslateId pId;
+ if (nCount == 1)
+ pId = getCommandURL() == ".uno:Undo" ? RID_SVXSTR_NUM_UNDO_ACTION : RID_SVXSTR_NUM_REDO_ACTION;
+ else
+ pId = getCommandURL() == ".uno:Undo" ? RID_SVXSTR_NUM_UNDO_ACTIONS : RID_SVXSTR_NUM_REDO_ACTIONS;
+ OUString aActionStr = SvxResId(pId);
+ OUString aText = aActionStr.replaceAll("$(ARG1)", OUString::number(nCount));
+ SetText(aText);
+}
+
+void SvxPopupWindowListBox::UpdateRow(int nRow)
+{
+ int nOldSelectedRows = m_nSelectedRows;
+ while (m_nSelectedRows < nRow + 1)
+ {
+ m_xListBox->select(m_nSelectedRows++);
+ }
+ while (m_nSelectedRows - 1 > nRow)
+ {
+ m_xListBox->unselect(--m_nSelectedRows);
+ }
+ if (nOldSelectedRows != m_nSelectedRows)
+ m_xControl->SetInfo(m_nSelectedRows);
+}
+
+IMPL_LINK(SvxPopupWindowListBox, MouseMoveHdl, const MouseEvent&, rMEvt, bool)
+{
+ if (m_xListBox->get_dest_row_at_pos(rMEvt.GetPosPixel(), m_xScratchIter.get(), false))
+ UpdateRow(m_xListBox->get_iter_index_in_parent(*m_xScratchIter));
+ return false;
+}
+
+IMPL_LINK(SvxPopupWindowListBox, MousePressHdl, const MouseEvent&, rMEvt, bool)
+{
+ if (m_xListBox->get_dest_row_at_pos(rMEvt.GetPosPixel(), m_xScratchIter.get(), false))
+ {
+ UpdateRow(m_xListBox->get_iter_index_in_parent(*m_xScratchIter));
+ ActivateHdl(*m_xListBox);
+ }
+ return true;
+}
+
+IMPL_LINK(SvxPopupWindowListBox, MouseReleaseHdl, const MouseEvent&, rMEvt, bool)
+{
+ if (m_xListBox->get_dest_row_at_pos(rMEvt.GetPosPixel(), m_xScratchIter.get(), false))
+ UpdateRow(m_xListBox->get_iter_index_in_parent(*m_xScratchIter));
+ return true;
+}
+
+IMPL_LINK(SvxPopupWindowListBox, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode& rKCode = rKEvt.GetKeyCode();
+ if (rKCode.GetModifier()) // only with no modifiers held
+ return true;
+
+ sal_uInt16 nCode = rKCode.GetCode();
+
+ if (nCode == KEY_UP || nCode == KEY_PAGEUP ||
+ nCode == KEY_DOWN || nCode == KEY_PAGEDOWN)
+ {
+ sal_Int32 nIndex = m_nSelectedRows - 1;
+ sal_Int32 nOrigIndex = nIndex;
+ sal_Int32 nCount = m_xListBox->n_children();
+
+ if (nCode == KEY_UP)
+ --nIndex;
+ else if (nCode == KEY_DOWN)
+ ++nIndex;
+ else if (nCode == KEY_PAGEUP)
+ nIndex -= m_nVisRows;
+ else if (nCode == KEY_PAGEDOWN)
+ nIndex += m_nVisRows;
+
+ if (nIndex < 0)
+ nIndex = 0;
+ if (nIndex >= nCount)
+ nIndex = nCount - 1;
+
+ if (nIndex != nOrigIndex)
+ {
+ m_xListBox->scroll_to_row(nIndex);
+ if (nIndex > nOrigIndex)
+ {
+ for (int i = nOrigIndex + 1; i <= nIndex; ++i)
+ UpdateRow(i);
+ }
+ else
+ {
+ for (int i = nOrigIndex - 1; i >= nIndex; --i)
+ UpdateRow(i);
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+IMPL_LINK_NOARG(SvxPopupWindowListBox, ActivateHdl, weld::TreeView&, bool)
+{
+ m_xControl->Do(m_nSelectedRows);
+ m_xControl->EndPopupMode();
+ return true;
+}
+
+void SvxUndoRedoControl::Do(sal_Int16 nCount)
+{
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
+ if ( !xDispatchProvider.is() )
+ return;
+
+ css::util::URL aTargetURL;
+ Reference < XURLTransformer > xTrans( URLTransformer::create(::comphelper::getProcessComponentContext()) );
+ aTargetURL.Complete = m_aCommandURL;
+ xTrans->parseStrict( aTargetURL );
+
+ Reference< XDispatch > xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
+ if ( xDispatch.is() )
+ {
+ INetURLObject aObj( m_aCommandURL );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(aObj.GetURLPath(), nCount) };
+ xDispatch->dispatch(aTargetURL, aArgs);
+ }
+}
+
+SvxUndoRedoControl::SvxUndoRedoControl(const css::uno::Reference<css::uno::XComponentContext>& rContext)
+ : PopupWindowController(rContext, nullptr, OUString())
+{
+}
+
+void SvxUndoRedoControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
+{
+ PopupWindowController::initialize(rArguments);
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId(nId, &pToolBox) && !m_pToolbar)
+ return;
+
+ if (getModuleName() != "com.sun.star.script.BasicIDE")
+ {
+ if (pToolBox)
+ pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWN | pToolBox->GetItemBits(nId));
+ if (m_pToolbar)
+ aDefaultTooltip = m_pToolbar->get_item_tooltip_text(m_aCommandURL.toUtf8());
+ else
+ aDefaultTooltip = pToolBox->GetQuickHelpText(nId);
+ }
+}
+
+SvxUndoRedoControl::~SvxUndoRedoControl()
+{
+}
+
+void SvxUndoRedoControl::SetText(const OUString& rText)
+{
+ mxInterimPopover->SetText(rText);
+}
+
+// XStatusListener
+void SAL_CALL SvxUndoRedoControl::statusChanged(const css::frame::FeatureStateEvent& rEvent)
+{
+ if (rEvent.FeatureURL.Main == ".uno:GetUndoStrings" || rEvent.FeatureURL.Main == ".uno:GetRedoStrings")
+ {
+ css::uno::Sequence<OUString> aStrings;
+ rEvent.State >>= aStrings;
+ aUndoRedoList = comphelper::sequenceToContainer<std::vector<OUString>>(aStrings);
+ return;
+ }
+
+ PopupWindowController::statusChanged(rEvent);
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId(nId, &pToolBox) && !m_pToolbar)
+ return;
+
+ if (!rEvent.IsEnabled)
+ {
+ if (m_pToolbar)
+ m_pToolbar->set_item_tooltip_text(m_aCommandURL.toUtf8(), aDefaultTooltip);
+ else
+ pToolBox->SetQuickHelpText(nId, aDefaultTooltip);
+ return;
+ }
+
+ OUString aQuickHelpText;
+ if (rEvent.State >>= aQuickHelpText)
+ {
+ if (m_pToolbar)
+ m_pToolbar->set_item_tooltip_text(m_aCommandURL.toUtf8(), aQuickHelpText);
+ else
+ pToolBox->SetQuickHelpText(nId, aQuickHelpText);
+ }
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxUndoRedoControl::weldPopupWindow()
+{
+ if ( m_aCommandURL == ".uno:Undo" )
+ updateStatus( ".uno:GetUndoStrings");
+ else
+ updateStatus( ".uno:GetRedoStrings");
+
+ return std::make_unique<SvxPopupWindowListBox>(this, m_pToolbar, aUndoRedoList);
+}
+
+VclPtr<vcl::Window> SvxUndoRedoControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ if ( m_aCommandURL == ".uno:Undo" )
+ updateStatus( ".uno:GetUndoStrings");
+ else
+ updateStatus( ".uno:GetRedoStrings");
+
+ auto xPopupWin = std::make_unique<SvxPopupWindowListBox>(this, pParent->GetFrameWeld(), aUndoRedoList);
+
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::move(xPopupWin));
+
+ SetInfo(1); // count of selected rows
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+OUString SvxUndoRedoControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.UndoRedoToolBoxControl";
+}
+
+css::uno::Sequence<OUString> SvxUndoRedoControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_UndoRedoToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire(new SvxUndoRedoControl(rContext));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/linectrl.cxx b/svx/source/tbxctrls/linectrl.cxx
new file mode 100644
index 000000000..9fcaeb22b
--- /dev/null
+++ b/svx/source/tbxctrls/linectrl.cxx
@@ -0,0 +1,650 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/debug.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/virdev.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <svtools/toolbarmenu.hxx>
+#include <svtools/popupwindowcontroller.hxx>
+#include <svtools/valueset.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <helpids.h>
+
+#include <svx/drawitem.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xtable.hxx>
+#include <svx/linectrl.hxx>
+#include <svx/itemwin.hxx>
+#include <svx/dialmgr.hxx>
+#include <tbxcolorupdate.hxx>
+
+#include <memory>
+
+#include <comphelper/lok.hxx>
+#include <comphelper/propertyvalue.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star;
+
+// For End Line Controller
+#define MAX_LINES 12
+
+SvxLineStyleToolBoxControl::SvxLineStyleToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext )
+ : svt::PopupWindowController( rContext, nullptr, OUString() )
+{
+ addStatusListener(".uno:LineDash");
+}
+
+SvxLineStyleToolBoxControl::~SvxLineStyleToolBoxControl()
+{
+}
+
+void SAL_CALL SvxLineStyleToolBoxControl::statusChanged( const frame::FeatureStateEvent& rEvent )
+{
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId(nId, &pToolBox) && !m_pToolbar)
+ return;
+
+ OString sId(m_aCommandURL.toUtf8());
+
+ if ( rEvent.FeatureURL.Complete == m_aCommandURL )
+ {
+ if (m_pToolbar)
+ m_pToolbar->set_item_sensitive(sId, rEvent.IsEnabled);
+ else
+ pToolBox->EnableItem( nId, rEvent.IsEnabled );
+ }
+
+ m_xBtnUpdater->Update(rEvent);
+
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ if (!pSh)
+ return;
+
+ const SvxDashListItem* pItem = pSh->GetItem( SID_DASH_LIST );
+ if (!pItem)
+ return;
+
+ XDashListRef xList = pItem->GetDashList();
+ int nIndex = m_xBtnUpdater->GetStyleIndex();
+ bool bNoneLineStyle = false;
+ switch (nIndex)
+ {
+ case -1:
+ case 0:
+ {
+ BitmapEx aEmpty(xList->GetBitmapForUISolidLine());
+ aEmpty.Erase(Application::GetSettings().GetStyleSettings().GetFieldColor());
+ if (m_pToolbar)
+ {
+ Graphic aGraf(aEmpty);
+ m_pToolbar->set_item_image(sId, aGraf.GetXGraphic());
+ }
+ else
+ pToolBox->SetItemImage(nId, Image(aEmpty));
+ bNoneLineStyle = true;
+ break;
+ }
+ case 1:
+ if (m_pToolbar)
+ {
+ Graphic aGraf(xList->GetBitmapForUISolidLine());
+ m_pToolbar->set_item_image(sId, aGraf.GetXGraphic());
+ }
+ else
+ pToolBox->SetItemImage(nId, Image(xList->GetBitmapForUISolidLine()));
+ break;
+ default:
+ if (m_pToolbar)
+ {
+ Graphic aGraf(xList->GetUiBitmap(nIndex - 2));
+ m_pToolbar->set_item_image(sId, aGraf.GetXGraphic());
+ }
+ else
+ pToolBox->SetItemImage(nId, Image(xList->GetUiBitmap(nIndex - 2)));
+ break;
+ }
+ if (m_aLineStyleIsNoneFunction)
+ m_aLineStyleIsNoneFunction(bNoneLineStyle);
+}
+
+void SAL_CALL SvxLineStyleToolBoxControl::execute(sal_Int16 /*KeyModifier*/)
+{
+ if (m_pToolbar)
+ {
+ // Toggle the popup also when toolbutton is activated
+ const OString aId(m_aCommandURL.toUtf8());
+ m_pToolbar->set_menu_item_active(aId, !m_pToolbar->get_menu_item_active(aId));
+ }
+ else
+ {
+ // Open the popup also when Enter key is pressed.
+ createPopupWindow();
+ }
+}
+
+void SvxLineStyleToolBoxControl::initialize( const css::uno::Sequence<css::uno::Any>& rArguments )
+{
+ svt::PopupWindowController::initialize( rArguments );
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if ( getToolboxId( nId, &pToolBox ) )
+ {
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+ }
+
+ m_xBtnUpdater.reset(new svx::ToolboxButtonLineStyleUpdater);
+}
+
+void SvxLineStyleToolBoxControl::setLineStyleSelectFunction(const LineStyleSelectFunction& rLineStyleSelectFunction)
+{
+ m_aLineStyleSelectFunction = rLineStyleSelectFunction;
+}
+
+void SvxLineStyleToolBoxControl::setLineStyleIsNoneFunction(const LineStyleIsNoneFunction& rLineStyleIsNoneFunction)
+{
+ m_aLineStyleIsNoneFunction = rLineStyleIsNoneFunction;
+}
+
+void SvxLineStyleToolBoxControl::dispatchLineStyleCommand(const OUString& rCommand, const Sequence<PropertyValue>& rArgs)
+{
+ if (m_aLineStyleSelectFunction && m_aLineStyleSelectFunction(rCommand, rArgs[0].Value))
+ return;
+
+ dispatchCommand(rCommand, rArgs);
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxLineStyleToolBoxControl::weldPopupWindow()
+{
+ return std::make_unique<SvxLineBox>(this, m_pToolbar, m_xBtnUpdater->GetStyleIndex());
+}
+
+VclPtr<vcl::Window> SvxLineStyleToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<SvxLineBox>(this, pParent->GetFrameWeld(), m_xBtnUpdater->GetStyleIndex()));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+OUString SvxLineStyleToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.LineStyleToolBoxControl";
+}
+
+css::uno::Sequence<OUString> SvxLineStyleToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_LineStyleToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxLineStyleToolBoxControl( rContext ) );
+}
+
+namespace {
+
+class SvxLineEndToolBoxControl final : public svt::PopupWindowController
+{
+public:
+ explicit SvxLineEndToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext );
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence<css::uno::Any>& rArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ virtual void SAL_CALL execute(sal_Int16 nKeyModifier) override;
+
+private:
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+};
+
+class SvxLineEndWindow final : public WeldToolbarPopup
+{
+private:
+ XLineEndListRef mpLineEndList;
+ rtl::Reference<SvxLineEndToolBoxControl> mxControl;
+ std::unique_ptr<ValueSet> mxLineEndSet;
+ std::unique_ptr<weld::CustomWeld> mxLineEndSetWin;
+ sal_uInt16 mnLines;
+ Size maBmpSize;
+
+ DECL_LINK( SelectHdl, ValueSet*, void );
+ void FillValueSet();
+ void SetSize();
+
+ virtual void GrabFocus() override
+ {
+ mxLineEndSet->GrabFocus();
+ }
+
+public:
+ SvxLineEndWindow(SvxLineEndToolBoxControl* pControl, weld::Widget* pParent);
+ virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+};
+
+}
+
+constexpr sal_uInt16 gnCols = 2;
+
+SvxLineEndWindow::SvxLineEndWindow(SvxLineEndToolBoxControl* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatinglineend.ui", "FloatingLineEnd")
+ , mxControl(pControl)
+ , mxLineEndSet(new ValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true)))
+ , mxLineEndSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxLineEndSet))
+ , mnLines(12)
+{
+ mxLineEndSet->SetStyle(mxLineEndSet->GetStyle() | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT);
+ mxLineEndSet->SetHelpId(HID_POPUP_LINEEND_CTRL);
+ m_xTopLevel->set_help_id(HID_POPUP_LINEEND);
+
+ SfxObjectShell* pDocSh = SfxObjectShell::Current();
+ if ( pDocSh )
+ {
+ const SfxPoolItem* pItem = pDocSh->GetItem( SID_LINEEND_LIST );
+ if( pItem )
+ mpLineEndList = static_cast<const SvxLineEndListItem*>( pItem )->GetLineEndList();
+ }
+ DBG_ASSERT( mpLineEndList.is(), "LineEndList not found" );
+
+ mxLineEndSet->SetSelectHdl( LINK( this, SvxLineEndWindow, SelectHdl ) );
+ mxLineEndSet->SetColCount( gnCols );
+
+ // ValueSet fill with entries of LineEndList
+ FillValueSet();
+
+ AddStatusListener( ".uno:LineEndListState");
+}
+
+IMPL_LINK_NOARG(SvxLineEndWindow, SelectHdl, ValueSet*, void)
+{
+ std::unique_ptr<XLineEndItem> pLineEndItem;
+ std::unique_ptr<XLineStartItem> pLineStartItem;
+ sal_uInt16 nId = mxLineEndSet->GetSelectedItemId();
+
+ if( nId == 1 )
+ {
+ pLineStartItem.reset(new XLineStartItem());
+ }
+ else if( nId == 2 )
+ {
+ pLineEndItem.reset(new XLineEndItem());
+ }
+ else if( nId % 2 ) // beginning of line
+ {
+ const XLineEndEntry* pEntry = mpLineEndList->GetLineEnd( (nId - 1) / 2 - 1 );
+ pLineStartItem.reset(new XLineStartItem(pEntry->GetName(), pEntry->GetLineEnd()));
+ }
+ else // end of line
+ {
+ const XLineEndEntry* pEntry = mpLineEndList->GetLineEnd( nId / 2 - 2 );
+ pLineEndItem.reset(new XLineEndItem(pEntry->GetName(), pEntry->GetLineEnd()));
+ }
+
+ OUString name;
+ Any a;
+
+ if ( pLineStartItem )
+ {
+ name = "LineStart";
+ pLineStartItem->QueryValue( a );
+ }
+ else
+ {
+ name = "LineEnd";
+ pLineEndItem->QueryValue( a );
+ }
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(name, a) };
+
+ /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
+ This instance may be deleted in the meantime (i.e. when a dialog is opened
+ while in Dispatch()), accessing members will crash in this case. */
+ mxLineEndSet->SetNoSelection();
+
+ mxControl->dispatchCommand(mxControl->getCommandURL(), aArgs);
+
+ mxControl->EndPopupMode();
+}
+
+void SvxLineEndWindow::FillValueSet()
+{
+ if( !mpLineEndList.is() )
+ return;
+
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ tools::Long nCount = mpLineEndList->Count();
+
+ // First entry: no line end.
+ // An entry is temporarily added to get the UI bitmap
+ basegfx::B2DPolyPolygon aNothing;
+ mpLineEndList->Insert(std::make_unique<XLineEndEntry>(aNothing,
+ comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE)
+ : SvxResId(RID_SVXSTR_NONE)));
+ const XLineEndEntry* pEntry = mpLineEndList->GetLineEnd(nCount);
+ BitmapEx aBmp = mpLineEndList->GetUiBitmap( nCount );
+ OSL_ENSURE( !aBmp.IsEmpty(), "UI bitmap was not created" );
+
+ maBmpSize = aBmp.GetSizePixel();
+ pVD->SetOutputSizePixel( maBmpSize, false );
+ maBmpSize.setWidth( maBmpSize.Width() / 2 );
+ Point aPt0( 0, 0 );
+ Point aPt1( maBmpSize.Width(), 0 );
+
+ pVD->DrawBitmapEx( Point(), aBmp );
+ mxLineEndSet->InsertItem(1, Image(pVD->GetBitmapEx(aPt0, maBmpSize)), pEntry->GetName());
+ mxLineEndSet->InsertItem(2, Image(pVD->GetBitmapEx(aPt1, maBmpSize)), pEntry->GetName());
+
+ mpLineEndList->Remove(nCount);
+
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ pEntry = mpLineEndList->GetLineEnd( i );
+ DBG_ASSERT( pEntry, "Could not access LineEndEntry" );
+ aBmp = mpLineEndList->GetUiBitmap( i );
+ OSL_ENSURE( !aBmp.IsEmpty(), "UI bitmap was not created" );
+
+ pVD->DrawBitmapEx( aPt0, aBmp );
+ mxLineEndSet->InsertItem(static_cast<sal_uInt16>((i+1)*2L+1),
+ Image(pVD->GetBitmapEx(aPt0, maBmpSize)), pEntry->GetName());
+ mxLineEndSet->InsertItem(static_cast<sal_uInt16>((i+2)*2L),
+ Image(pVD->GetBitmapEx(aPt1, maBmpSize)), pEntry->GetName());
+ }
+ mnLines = std::min( static_cast<sal_uInt16>(nCount + 1), sal_uInt16(MAX_LINES) );
+ mxLineEndSet->SetLineCount( mnLines );
+
+ SetSize();
+}
+
+void SvxLineEndWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ if ( rEvent.FeatureURL.Complete != ".uno:LineEndListState" )
+ return;
+
+ // The list of line ends (LineEndList) has changed
+ css::uno::Reference< css::uno::XWeak > xWeak;
+ if ( rEvent.State >>= xWeak )
+ {
+ mpLineEndList.set( static_cast< XLineEndList* >( xWeak.get() ) );
+ DBG_ASSERT( mpLineEndList.is(), "LineEndList not found" );
+
+ mxLineEndSet->Clear();
+ FillValueSet();
+ }
+}
+
+void SvxLineEndWindow::SetSize()
+{
+ sal_uInt16 nItemCount = mxLineEndSet->GetItemCount();
+ sal_uInt16 nMaxLines = nItemCount / gnCols;
+
+ WinBits nBits = mxLineEndSet->GetStyle();
+ if ( mnLines == nMaxLines )
+ nBits &= ~WB_VSCROLL;
+ else
+ nBits |= WB_VSCROLL;
+ mxLineEndSet->SetStyle( nBits );
+
+ Size aSize( maBmpSize );
+ aSize.AdjustWidth(6 );
+ aSize.AdjustHeight(6 );
+ aSize = mxLineEndSet->CalcWindowSizePixel( aSize );
+ mxLineEndSet->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height());
+ mxLineEndSet->SetOutputSizePixel(aSize);
+}
+
+SvxLineEndToolBoxControl::SvxLineEndToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext )
+ : svt::PopupWindowController( rContext, nullptr, OUString() )
+{
+}
+
+void SAL_CALL SvxLineEndToolBoxControl::execute(sal_Int16 /*KeyModifier*/)
+{
+ if (m_pToolbar)
+ {
+ // Toggle the popup also when toolbutton is activated
+ const OString aId(m_aCommandURL.toUtf8());
+ m_pToolbar->set_menu_item_active(aId, !m_pToolbar->get_menu_item_active(aId));
+ }
+ else
+ {
+ // Open the popup also when Enter key is pressed.
+ createPopupWindow();
+ }
+}
+
+void SvxLineEndToolBoxControl::initialize( const css::uno::Sequence<css::uno::Any>& rArguments )
+{
+ svt::PopupWindowController::initialize( rArguments );
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if ( getToolboxId( nId, &pToolBox ) )
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxLineEndToolBoxControl::weldPopupWindow()
+{
+ return std::make_unique<SvxLineEndWindow>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> SvxLineEndToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<SvxLineEndWindow>(this, pParent->GetFrameWeld()));
+
+ mxInterimPopover->Show();
+
+ mxInterimPopover->SetText(SvxResId(RID_SVXSTR_LINEEND));
+
+ return mxInterimPopover;
+}
+
+OUString SvxLineEndToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.LineEndToolBoxControl";
+}
+
+css::uno::Sequence<OUString> SvxLineEndToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_LineEndToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxLineEndToolBoxControl( rContext ) );
+}
+
+SvxLineBox::SvxLineBox(SvxLineStyleToolBoxControl* pControl, weld::Widget* pParent, int nInitialIndex)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatinglinestyle.ui", "FloatingLineStyle")
+ , mxControl(pControl)
+ , mxLineStyleSet(new ValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true)))
+ , mxLineStyleSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxLineStyleSet))
+{
+ mxLineStyleSet->SetStyle(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT);
+
+ FillControl();
+
+ mxLineStyleSet->SelectItem(nInitialIndex + 1);
+
+ mxLineStyleSet->SetSelectHdl( LINK( this, SvxLineBox, SelectHdl ) );
+}
+
+void SvxLineBox::GrabFocus()
+{
+ mxLineStyleSet->GrabFocus();
+}
+
+SvxLineBox::~SvxLineBox()
+{
+}
+
+// Fills the listbox (provisional) with strings
+
+void SvxLineBox::Fill( const XDashListRef &pList )
+{
+ mxLineStyleSet->Clear();
+
+ if( !pList.is() )
+ return;
+
+ // entry for 'none'
+ mxLineStyleSet->InsertItem(1, Image(), pList->GetStringForUiNoLine());
+
+ // entry for solid line
+ auto aBmp = pList->GetBitmapForUISolidLine();
+ Size aBmpSize = aBmp.GetSizePixel();
+ mxLineStyleSet->InsertItem(2, Image(aBmp), pList->GetStringForUiSolidLine());
+
+ // entries for dashed lines
+ tools::Long nCount = pList->Count();
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ const XDashEntry* pEntry = pList->GetDash(i);
+ const BitmapEx aBitmap = pList->GetUiBitmap(i);
+
+ mxLineStyleSet->InsertItem(i + 3, Image(aBitmap), pEntry->GetName());
+ }
+
+ sal_uInt16 nLines = std::min( static_cast<sal_uInt16>(nCount + 2), sal_uInt16(MAX_LINES) );
+ mxLineStyleSet->SetLineCount(nLines);
+
+ WinBits nBits = mxLineStyleSet->GetStyle();
+ if ( nLines == mxLineStyleSet->GetItemCount() )
+ nBits &= ~WB_VSCROLL;
+ else
+ nBits |= WB_VSCROLL;
+ mxLineStyleSet->SetStyle( nBits );
+
+ Size aSize(aBmpSize);
+ aSize.AdjustWidth(6);
+ aSize.AdjustHeight(6);
+ aSize = mxLineStyleSet->CalcWindowSizePixel(aSize);
+ mxLineStyleSet->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height());
+ mxLineStyleSet->SetOutputSizePixel(aSize);
+}
+
+IMPL_LINK_NOARG(SvxLineBox, SelectHdl, ValueSet*, void)
+{
+ drawing::LineStyle eXLS;
+ sal_Int32 nPos = mxLineStyleSet->GetSelectedItemId();
+ --nPos; // ids start at 1, get the pos of the id
+
+ switch ( nPos )
+ {
+ case 0:
+ eXLS = drawing::LineStyle_NONE;
+ break;
+
+ case 1:
+ eXLS = drawing::LineStyle_SOLID;
+ break;
+
+ default:
+ {
+ eXLS = drawing::LineStyle_DASH;
+ const SfxObjectShell* pObjSh = SfxObjectShell::Current();
+ if (nPos != -1 && pObjSh && pObjSh->GetItem(SID_DASH_LIST))
+ {
+ // LineDashItem will only be sent if it also has a dash.
+ // Notify cares!
+ SvxDashListItem const * pItem = pObjSh->GetItem( SID_DASH_LIST );
+ const XDashEntry* pEntry = pItem->GetDashList()->GetDash(nPos - 2);
+ XLineDashItem aLineDashItem(pEntry->GetName(), pEntry->GetDash());
+
+ Any a;
+ aLineDashItem.QueryValue ( a );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("LineDash", a) };
+ mxControl->dispatchLineStyleCommand(".uno:LineDash", aArgs);
+
+ // set also cap style using the toolbar line style selection popup
+ css::drawing::DashStyle eStyle = pEntry->GetDash().GetDashStyle();
+ XLineCapItem aLineCapItem(
+ eStyle == drawing::DashStyle_RECT || eStyle == drawing::DashStyle_RECTRELATIVE
+ ? css::drawing::LineCap_BUTT
+ : css::drawing::LineCap_ROUND );
+ aLineCapItem.QueryValue ( a );
+ Sequence< PropertyValue > aArgs2{ comphelper::makePropertyValue("LineCap", a) };
+ mxControl->dispatchLineStyleCommand(".uno:LineCap", aArgs2);
+ }
+ }
+ break;
+ }
+
+ XLineStyleItem aLineStyleItem( eXLS );
+ Any a;
+ aLineStyleItem.QueryValue ( a );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("XLineStyle", a) };
+ mxControl->dispatchLineStyleCommand(".uno:XLineStyle", aArgs);
+
+ mxControl->EndPopupMode();
+}
+
+void SvxLineBox::FillControl()
+{
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ if (pSh)
+ {
+ const SvxDashListItem* pItem = pSh->GetItem( SID_DASH_LIST );
+ if (pItem)
+ Fill(pItem->GetDashList());
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/linemetricbox.hxx b/svx/source/tbxctrls/linemetricbox.hxx
new file mode 100644
index 000000000..81f19a1c6
--- /dev/null
+++ b/svx/source/tbxctrls/linemetricbox.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vcl/InterimItemWindow.hxx>
+#include <com/sun/star/frame/XFrame.hpp>
+
+class XLineWidthItem;
+
+class SvxMetricField final : public InterimItemWindow
+{
+private:
+ std::unique_ptr<weld::MetricSpinButton> m_xWidget;
+ int nCurValue;
+ MapUnit eDestPoolUnit;
+ FieldUnit eDlgUnit;
+ css::uno::Reference< css::frame::XFrame > mxFrame;
+
+ DECL_LINK(ModifyHdl, weld::MetricSpinButton&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(FocusInHdl, weld::Widget&, void);
+
+ static void ReleaseFocus_Impl();
+
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+
+public:
+ SvxMetricField( vcl::Window* pParent,
+ const css::uno::Reference< css::frame::XFrame >& rFrame );
+ virtual void dispose() override;
+ virtual ~SvxMetricField() override;
+
+ void Update( const XLineWidthItem* pItem );
+ void SetDestCoreUnit( MapUnit eUnit );
+ void RefreshDlgUnit();
+
+ void set_sensitive(bool bSensitive);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/linewidthctrl.cxx b/svx/source/tbxctrls/linewidthctrl.cxx
new file mode 100644
index 000000000..166f4bb45
--- /dev/null
+++ b/svx/source/tbxctrls/linewidthctrl.cxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/toolbox.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/itempool.hxx>
+#include <svx/svxids.hrc>
+#include <svx/xlnwtit.hxx>
+#include <svx/linectrl.hxx>
+#include "linemetricbox.hxx"
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star;
+
+SFX_IMPL_TOOLBOX_CONTROL( SvxLineWidthToolBoxControl, XLineWidthItem );
+
+SvxLineWidthToolBoxControl::SvxLineWidthToolBoxControl(
+ sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+ addStatusListener( ".uno:MetricUnit");
+}
+
+
+SvxLineWidthToolBoxControl::~SvxLineWidthToolBoxControl()
+{
+}
+
+void SvxLineWidthToolBoxControl::StateChangedAtToolBoxControl(
+ sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState )
+{
+ SvxMetricField* pFld = static_cast<SvxMetricField*>(
+ GetToolBox().GetItemWindow( GetId() ));
+ DBG_ASSERT( pFld, "Window not found" );
+
+ if ( nSID == SID_ATTR_METRIC )
+ {
+ pFld->RefreshDlgUnit();
+ }
+ else
+ {
+ if ( eState == SfxItemState::DISABLED )
+ {
+ pFld->set_sensitive(false);
+ }
+ else
+ {
+ pFld->set_sensitive(true);
+
+ if ( eState == SfxItemState::DEFAULT )
+ {
+ DBG_ASSERT( dynamic_cast<const XLineWidthItem*>( pState) != nullptr, "wrong ItemType" );
+
+ pFld->SetDestCoreUnit(GetCoreMetric());
+
+ pFld->Update( static_cast<const XLineWidthItem*>(pState) );
+ }
+ else
+ pFld->Update( nullptr );
+ }
+ }
+}
+
+MapUnit SvxLineWidthToolBoxControl::GetCoreMetric()
+{
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ SfxItemPool& rPool = pSh ? pSh->GetPool() : SfxGetpApp()->GetPool();
+ sal_uInt16 nWhich = rPool.GetWhich(SID_ATTR_LINE_WIDTH);
+ return rPool.GetMetric(nWhich);
+}
+
+VclPtr<InterimItemWindow> SvxLineWidthToolBoxControl::CreateItemWindow(vcl::Window *pParent)
+{
+ VclPtr<SvxMetricField> pWindow = VclPtr<SvxMetricField>::Create(pParent, m_xFrame);
+ pWindow->Show();
+
+ return pWindow;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/tbcontrl.cxx b/svx/source/tbxctrls/tbcontrl.cxx
new file mode 100644
index 000000000..ff1d519e5
--- /dev/null
+++ b/svx/source/tbxctrls/tbcontrl.cxx
@@ -0,0 +1,4186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <utility>
+
+#include <comphelper/configurationlistener.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <tools/color.hxx>
+#include <svl/numformat.hxx>
+#include <svl/poolitem.hxx>
+#include <svl/itemset.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/event.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/weldutils.hxx>
+#include <svtools/valueset.hxx>
+#include <svtools/ctrlbox.hxx>
+#include <svl/style.hxx>
+#include <svtools/ctrltool.hxx>
+#include <svtools/borderhelper.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <sfx2/tbxctrl.hxx>
+#include <sfx2/tplpitem.hxx>
+#include <sfx2/sfxstatuslistener.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <helpids.h>
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <svx/xtable.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <editeng/flstitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/svxfont.hxx>
+#include <editeng/cmapitem.hxx>
+#include <svx/colorwindow.hxx>
+#include <svx/colorbox.hxx>
+#include <svx/tbcontrl.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/PaletteManager.hxx>
+#include <memory>
+
+#include <tbxcolorupdate.hxx>
+#include <editeng/eerdll.hxx>
+#include <editeng/editrids.hrc>
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svl/currencytable.hxx>
+#include <svtools/langtab.hxx>
+#include <cppu/unotype.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <bitmaps.hlst>
+#include <sal/log.hxx>
+#include <unotools/collatorwrapper.hxx>
+
+#include <comphelper/lok.hxx>
+#include <tools/json_writer.hxx>
+
+#define MAX_MRU_FONTNAME_ENTRIES 5
+
+#define COMBO_WIDTH_IN_CHARS 18
+
+// namespaces
+using namespace ::editeng;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+
+namespace
+{
+class SvxStyleBox_Base
+{
+public:
+ SvxStyleBox_Base(std::unique_ptr<weld::ComboBox> xWidget, const OUString& rCommand, SfxStyleFamily eFamily,
+ const Reference<XDispatchProvider>& rDispatchProvider,
+ const Reference<XFrame>& _xFrame,const OUString& rClearFormatKey,
+ const OUString& rMoreKey, bool bInSpecialMode, SvxStyleToolBoxControl& rCtrl);
+
+ virtual ~SvxStyleBox_Base()
+ {
+ }
+
+ void SetFamily( SfxStyleFamily eNewFamily );
+
+ void SetDefaultStyle( const OUString& rDefault ) { sDefaultStyle = rDefault; }
+
+ int get_count() const { return m_xWidget->get_count(); }
+ OUString get_text(int nIndex) const { return m_xWidget->get_text(nIndex); }
+ OUString get_active_text() const { return m_xWidget->get_active_text(); }
+
+ void append_text(const OUString& rStr)
+ {
+ OUString sId(OUString::number(m_xWidget->get_count()));
+ m_xWidget->append(sId, rStr);
+ }
+
+ void insert_separator(int pos, const OUString& rId)
+ {
+ m_xWidget->insert_separator(pos, rId);
+ }
+
+ void set_active_or_entry_text(const OUString& rText)
+ {
+ const int nFound = m_xWidget->find_text(rText);
+ if (nFound != -1)
+ m_xWidget->set_active(nFound);
+ else
+ m_xWidget->set_entry_text(rText);
+ }
+
+ void set_active(int nActive)
+ {
+ m_xWidget->set_active(nActive);
+ }
+
+ void freeze()
+ {
+ m_xWidget->freeze();
+ }
+
+ void save_value()
+ {
+ m_xWidget->save_value();
+ }
+
+ void clear()
+ {
+ m_xWidget->clear();
+ m_nMaxUserDrawFontWidth = 0;
+ }
+
+ void thaw()
+ {
+ m_xWidget->thaw();
+ }
+
+ virtual bool DoKeyInput(const KeyEvent& rKEvt);
+
+private:
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+ DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void);
+ DECL_LINK(CustomRenderHdl, weld::ComboBox::render_args, void);
+ DECL_LINK(CustomGetSizeHdl, OutputDevice&, Size);
+
+ /// Calculate the optimal width of the dropdown. Very expensive operation, triggers lots of font measurement.
+ void CalcOptimalExtraUserWidth(vcl::RenderContext& rRenderContext);
+
+ void Select(bool bNonTravelSelect);
+
+protected:
+ SvxStyleToolBoxControl& m_rCtrl;
+
+ std::unique_ptr<weld::Builder> m_xMenuBuilder;
+ std::unique_ptr<weld::Menu> m_xMenu;
+ std::unique_ptr<weld::ComboBox> m_xWidget;
+
+ SfxStyleFamily eStyleFamily;
+ int m_nMaxUserDrawFontWidth;
+ int m_nLastItemWithMenu;
+ bool bRelease;
+ Reference< XDispatchProvider > m_xDispatchProvider;
+ Reference< XFrame > m_xFrame;
+ OUString m_aCommand;
+ OUString aClearFormatKey;
+ OUString aMoreKey;
+ OUString sDefaultStyle;
+ bool bInSpecialMode;
+
+ void ReleaseFocus();
+ static Color TestColorsVisible(const Color &FontCol, const Color &BackCol);
+ static void UserDrawEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const OUString &rStyleName);
+ void SetupEntry(vcl::RenderContext& rRenderContext, sal_Int32 nItem, const tools::Rectangle& rRect, std::u16string_view rStyleName, bool bIsNotSelected);
+ static bool AdjustFontForItemHeight(OutputDevice& rDevice, tools::Rectangle const & rTextRect, tools::Long nHeight);
+ DECL_LINK(MenuSelectHdl, const OString&, void);
+ DECL_STATIC_LINK(SvxStyleBox_Base, ShowMoreHdl, void*, void);
+};
+
+class SvxStyleBox_Impl final : public InterimItemWindow
+ , public SvxStyleBox_Base
+{
+public:
+ SvxStyleBox_Impl(vcl::Window* pParent, const OUString& rCommand, SfxStyleFamily eFamily, const Reference< XDispatchProvider >& rDispatchProvider,
+ const Reference< XFrame >& _xFrame,const OUString& rClearFormatKey, const OUString& rMoreKey, bool bInSpecialMode, SvxStyleToolBoxControl& rCtrl);
+
+ virtual ~SvxStyleBox_Impl() override
+ {
+ disposeOnce();
+ }
+
+ virtual void dispose() override
+ {
+ m_xWidget.reset();
+ m_xMenu.reset();
+ m_xMenuBuilder.reset();
+ InterimItemWindow::dispose();
+ }
+
+ virtual bool DoKeyInput(const KeyEvent& rKEvt) override;
+
+private:
+
+ virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
+ void SetOptimalSize();
+};
+
+class SvxFontNameBox_Impl;
+class SvxFontNameBox_Base;
+
+class SvxFontNameToolBoxControl final : public cppu::ImplInheritanceHelper<svt::ToolboxController,
+ css::lang::XServiceInfo>
+{
+public:
+ SvxFontNameToolBoxControl();
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+
+ // XToolbarController
+ virtual css::uno::Reference<css::awt::XWindow> SAL_CALL createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+private:
+ VclPtr<SvxFontNameBox_Impl> m_xVclBox;
+ std::unique_ptr<SvxFontNameBox_Base> m_xWeldBox;
+ SvxFontNameBox_Base* m_pBox;
+};
+
+class FontOptionsListener final : public comphelper::ConfigurationListenerProperty<bool>
+{
+private:
+ SvxFontNameBox_Base& m_rBox;
+
+ virtual void setProperty(const css::uno::Any &rProperty) override;
+public:
+ FontOptionsListener(const rtl::Reference<comphelper::ConfigurationListener>& rListener, const OUString& rProp, SvxFontNameBox_Base& rBox)
+ : comphelper::ConfigurationListenerProperty<bool>(rListener, rProp)
+ , m_rBox(rBox)
+ {
+ }
+};
+
+class SvxFontNameBox_Base
+{
+private:
+ rtl::Reference<comphelper::ConfigurationListener> m_xListener;
+ FontOptionsListener m_aWYSIWYG;
+ FontOptionsListener m_aHistory;
+
+protected:
+ SvxFontNameToolBoxControl& m_rCtrl;
+
+ std::unique_ptr<FontNameBox> m_xWidget;
+ const FontList* pFontList;
+ ::std::unique_ptr<FontList> m_aOwnFontList;
+ vcl::Font aCurFont;
+ sal_uInt16 nFtCount;
+ bool bRelease;
+ Reference< XDispatchProvider > m_xDispatchProvider;
+ Reference< XFrame > m_xFrame;
+ bool mbCheckingUnknownFont;
+
+ void ReleaseFocus_Impl();
+
+ void Select(bool bNonTravelSelect);
+
+ void EndPreview()
+ {
+ Sequence< PropertyValue > aArgs;
+ SfxToolBoxControl::Dispatch( m_xDispatchProvider,
+ ".uno:CharEndPreviewFontName",
+ aArgs );
+ }
+ void CheckAndMarkUnknownFont();
+
+public:
+ SvxFontNameBox_Base(std::unique_ptr<weld::ComboBox> xWidget, const Reference<XDispatchProvider>& rDispatchProvider,
+ const Reference<XFrame>& rFrame, SvxFontNameToolBoxControl& rCtrl);
+ virtual ~SvxFontNameBox_Base()
+ {
+ m_xListener->dispose();
+ }
+
+ void FillList();
+ void Update( const css::awt::FontDescriptor* pFontDesc );
+ sal_uInt16 GetListCount() const { return nFtCount; }
+ void Clear() { m_xWidget->clear(); nFtCount = 0; }
+ void Fill( const FontList* pList )
+ {
+ m_xWidget->Fill(pList);
+ nFtCount = pList->GetFontNameCount();
+ }
+
+ void SetOwnFontList(::std::unique_ptr<FontList> && _aOwnFontList) { m_aOwnFontList = std::move(_aOwnFontList); }
+
+ virtual void set_sensitive(bool bSensitive)
+ {
+ m_xWidget->set_sensitive(bSensitive);
+ }
+
+ void set_active_or_entry_text(const OUString& rText);
+
+ void statusChanged_Impl(const css::frame::FeatureStateEvent& rEvent);
+
+ virtual bool DoKeyInput(const KeyEvent& rKEvt);
+
+ void EnableControls();
+
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+ DECL_LINK(FocusInHdl, weld::Widget&, void);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+ DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void);
+};
+
+void FontOptionsListener::setProperty(const css::uno::Any &rProperty)
+{
+ comphelper::ConfigurationListenerProperty<bool>::setProperty(rProperty);
+ m_rBox.EnableControls();
+}
+
+class SvxFontNameBox_Impl final : public InterimItemWindow
+ , public SvxFontNameBox_Base
+{
+private:
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+ virtual void GetFocus() override
+ {
+ if (m_xWidget)
+ m_xWidget->grab_focus();
+ InterimItemWindow::GetFocus();
+ }
+
+ void SetOptimalSize();
+
+ virtual bool DoKeyInput(const KeyEvent& rKEvt) override;
+
+public:
+ SvxFontNameBox_Impl(vcl::Window* pParent, const Reference<XDispatchProvider>& rDispatchProvider,
+ const Reference<XFrame>& rFrame, SvxFontNameToolBoxControl& rCtrl);
+
+ virtual void dispose() override
+ {
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+ }
+
+ virtual ~SvxFontNameBox_Impl() override
+ {
+ disposeOnce();
+ }
+
+ virtual Reference< css::accessibility::XAccessible > CreateAccessible() override;
+
+ virtual void set_sensitive(bool bSensitive) override
+ {
+ m_xWidget->set_sensitive(bSensitive);
+ if (bSensitive)
+ InterimItemWindow::Enable();
+ else
+ InterimItemWindow::Disable();
+ }
+};
+
+
+// SelectHdl needs the Modifiers, get them in MouseButtonUp
+class SvxFrmValueSet_Impl final : public ValueSet
+{
+private:
+ sal_uInt16 nModifier;
+
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override
+ {
+ nModifier = rMEvt.GetModifier();
+ return ValueSet::MouseButtonUp(rMEvt);
+ }
+
+public:
+ SvxFrmValueSet_Impl()
+ : ValueSet(nullptr)
+ , nModifier(0)
+ {
+ }
+ sal_uInt16 GetModifier() const {return nModifier;}
+};
+
+}
+
+namespace {
+
+class SvxFrameToolBoxControl;
+
+class SvxFrameWindow_Impl final : public WeldToolbarPopup
+{
+private:
+ rtl::Reference<SvxFrameToolBoxControl> mxControl;
+ std::unique_ptr<SvxFrmValueSet_Impl> mxFrameSet;
+ std::unique_ptr<weld::CustomWeld> mxFrameSetWin;
+ std::vector<std::pair<BitmapEx, OUString>> aImgVec;
+ bool bParagraphMode;
+ bool m_bIsWriter;
+
+ void InitImageList();
+ void CalcSizeValueSet();
+ DECL_LINK( SelectHdl, ValueSet*, void );
+
+ void SetDiagonalDownBorder(const SvxLineItem& dDownLineItem);
+ void SetDiagonalUpBorder(const SvxLineItem& dUpLineItem);
+
+public:
+ SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent);
+ virtual void GrabFocus() override
+ {
+ mxFrameSet->GrabFocus();
+ }
+
+ virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+};
+
+class SvxFrameToolBoxControl : public svt::PopupWindowController
+{
+public:
+ explicit SvxFrameToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rContext );
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& rArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ virtual void SAL_CALL execute(sal_Int16 nKeyModifier) override;
+private:
+ virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
+ virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
+};
+
+ class LineListBox final : public ValueSet
+ {
+ public:
+ typedef Color (*ColorFunc)(Color);
+ typedef Color (*ColorDistFunc)(Color, Color);
+
+ LineListBox();
+
+ /** Set the width in Twips */
+ Size SetWidth( tools::Long nWidth )
+ {
+ tools::Long nOldWidth = m_nWidth;
+ m_nWidth = nWidth;
+ return UpdateEntries( nOldWidth );
+ }
+
+ void SetNone( const OUString& sNone )
+ {
+ m_sNone = sNone;
+ }
+
+ /** Insert a listbox entry with all widths in Twips. */
+ void InsertEntry(const BorderWidthImpl& rWidthImpl,
+ SvxBorderLineStyle nStyle, tools::Long nMinWidth = 0,
+ ColorFunc pColor1Fn = &sameColor,
+ ColorFunc pColor2Fn = &sameColor,
+ ColorDistFunc pColorDistFn = &sameDistColor);
+
+ SvxBorderLineStyle GetEntryStyle( sal_Int32 nPos ) const;
+
+ SvxBorderLineStyle GetSelectEntryStyle() const;
+
+ void SetSourceUnit( FieldUnit eNewUnit ) { eSourceUnit = eNewUnit; }
+
+ const Color& GetColor() const { return aColor; }
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ private:
+
+ void ImpGetLine(tools::Long nLine1, tools::Long nLine2, tools::Long nDistance,
+ Color nColor1, Color nColor2, Color nColorDist,
+ SvxBorderLineStyle nStyle, BitmapEx& rBmp);
+
+ void UpdatePaintLineColor(); // returns sal_True if maPaintCol has changed
+
+ Size UpdateEntries( tools::Long nOldWidth );
+ sal_Int32 GetStylePos( sal_Int32 nListPos, tools::Long nWidth );
+
+ const Color& GetPaintColor() const
+ {
+ return maPaintCol;
+ }
+
+ Color GetColorLine1( sal_Int32 nPos );
+ Color GetColorLine2( sal_Int32 nPos );
+ Color GetColorDist( sal_Int32 nPos );
+
+ LineListBox( const LineListBox& ) = delete;
+ LineListBox& operator =( const LineListBox& ) = delete;
+
+ std::vector<std::unique_ptr<ImpLineListData>> m_vLineList;
+ tools::Long m_nWidth;
+ OUString m_sNone;
+ ScopedVclPtr<VirtualDevice> aVirDev;
+ Size aTxtSize;
+ Color const aColor;
+ Color maPaintCol;
+ FieldUnit eSourceUnit;
+ };
+
+ SvxBorderLineStyle LineListBox::GetSelectEntryStyle() const
+ {
+ SvxBorderLineStyle nStyle = SvxBorderLineStyle::SOLID;
+ size_t nPos = GetSelectItemPos();
+ if (nPos != VALUESET_ITEM_NOTFOUND)
+ {
+ if (!m_sNone.isEmpty())
+ --nPos;
+ nStyle = GetEntryStyle( nPos );
+ }
+
+ return nStyle;
+ }
+
+ void LineListBox::ImpGetLine( tools::Long nLine1, tools::Long nLine2, tools::Long nDistance,
+ Color aColor1, Color aColor2, Color aColorDist,
+ SvxBorderLineStyle nStyle, BitmapEx& rBmp )
+ {
+ auto nMinWidth = GetDrawingArea()->get_ref_device().approximate_digit_width() * COMBO_WIDTH_IN_CHARS;
+ Size aSize(nMinWidth, aTxtSize.Height());
+ aSize.AdjustWidth( -(aTxtSize.Width()) );
+ aSize.AdjustWidth( -6 );
+
+ // SourceUnit to Twips
+ if ( eSourceUnit == FieldUnit::POINT )
+ {
+ nLine1 /= 5;
+ nLine2 /= 5;
+ nDistance /= 5;
+ }
+
+ // Paint the lines
+ aSize = aVirDev->PixelToLogic( aSize );
+ tools::Long nPix = aVirDev->PixelToLogic( Size( 0, 1 ) ).Height();
+ sal_uInt32 n1 = nLine1;
+ sal_uInt32 n2 = nLine2;
+ tools::Long nDist = nDistance;
+ n1 += nPix-1;
+ n1 -= n1%nPix;
+ if ( n2 )
+ {
+ nDist += nPix-1;
+ nDist -= nDist%nPix;
+ n2 += nPix-1;
+ n2 -= n2%nPix;
+ }
+ tools::Long nVirHeight = n1+nDist+n2;
+ if ( nVirHeight > aSize.Height() )
+ aSize.setHeight( nVirHeight );
+ // negative width should not be drawn
+ if ( aSize.Width() <= 0 )
+ return;
+
+ Size aVirSize = aVirDev->LogicToPixel( aSize );
+ if ( aVirDev->GetOutputSizePixel() != aVirSize )
+ aVirDev->SetOutputSizePixel( aVirSize );
+ aVirDev->SetFillColor( aColorDist );
+ aVirDev->DrawRect( tools::Rectangle( Point(), aSize ) );
+
+ aVirDev->SetFillColor( aColor1 );
+
+ double y1 = double( n1 ) / 2;
+ svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y1 ), basegfx::B2DPoint( aSize.Width( ), y1 ), n1, nStyle );
+
+ if ( n2 )
+ {
+ double y2 = n1 + nDist + double( n2 ) / 2;
+ aVirDev->SetFillColor( aColor2 );
+ svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y2 ), basegfx::B2DPoint( aSize.Width(), y2 ), n2, SvxBorderLineStyle::SOLID );
+ }
+ rBmp = aVirDev->GetBitmapEx( Point(), Size( aSize.Width(), n1+nDist+n2 ) );
+ }
+
+ LineListBox::LineListBox()
+ : ValueSet(nullptr)
+ , m_nWidth( 5 )
+ , aVirDev(VclPtr<VirtualDevice>::Create())
+ , aColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor())
+ , maPaintCol(COL_BLACK)
+ , eSourceUnit(FieldUnit::POINT)
+ {
+ aVirDev->SetLineColor();
+ aVirDev->SetMapMode( MapMode( MapUnit::MapTwip ) );
+ }
+
+ void LineListBox::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+ {
+ ValueSet::SetDrawingArea(pDrawingArea);
+
+ OutputDevice& rDevice = pDrawingArea->get_ref_device();
+
+ aTxtSize.setWidth( rDevice.approximate_digit_width() );
+ aTxtSize.setHeight( rDevice.GetTextHeight() );
+
+ UpdatePaintLineColor();
+ }
+
+ sal_Int32 LineListBox::GetStylePos( sal_Int32 nListPos, tools::Long nWidth )
+ {
+ sal_Int32 nPos = -1;
+ if (!m_sNone.isEmpty())
+ nListPos--;
+
+ sal_Int32 n = 0;
+ size_t i = 0;
+ size_t nCount = m_vLineList.size();
+ while ( nPos == -1 && i < nCount )
+ {
+ auto& pData = m_vLineList[ i ];
+ if ( pData->GetMinWidth() <= nWidth )
+ {
+ if ( nListPos == n )
+ nPos = static_cast<sal_Int32>(i);
+ n++;
+ }
+ i++;
+ }
+
+ return nPos;
+ }
+
+ void LineListBox::InsertEntry(
+ const BorderWidthImpl& rWidthImpl, SvxBorderLineStyle nStyle, tools::Long nMinWidth,
+ ColorFunc pColor1Fn, ColorFunc pColor2Fn, ColorDistFunc pColorDistFn )
+ {
+ m_vLineList.emplace_back(new ImpLineListData(
+ rWidthImpl, nStyle, nMinWidth, pColor1Fn, pColor2Fn, pColorDistFn));
+ }
+
+ SvxBorderLineStyle LineListBox::GetEntryStyle( sal_Int32 nPos ) const
+ {
+ ImpLineListData* pData = (0 <= nPos && o3tl::make_unsigned(nPos) < m_vLineList.size()) ? m_vLineList[ nPos ].get() : nullptr;
+ return pData ? pData->GetStyle() : SvxBorderLineStyle::NONE;
+ }
+
+ void LineListBox::UpdatePaintLineColor()
+ {
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ Color aNewCol( rSettings.GetWindowColor().IsDark()? rSettings.GetLabelTextColor() : aColor );
+
+ bool bRet = aNewCol != maPaintCol;
+
+ if( bRet )
+ maPaintCol = aNewCol;
+ }
+
+ Size LineListBox::UpdateEntries( tools::Long nOldWidth )
+ {
+ Size aSize;
+
+ UpdatePaintLineColor( );
+
+ sal_Int32 nSelEntry = GetSelectItemPos();
+ sal_Int32 nTypePos = GetStylePos( nSelEntry, nOldWidth );
+
+ // Remove the old entries
+ Clear();
+
+ sal_uInt16 nId(1);
+
+ // Add the new entries based on the defined width
+ if (!m_sNone.isEmpty())
+ InsertItem(nId++, Image(), m_sNone);
+
+ sal_uInt16 n = 0;
+ sal_uInt16 nCount = m_vLineList.size( );
+ while ( n < nCount )
+ {
+ auto& pData = m_vLineList[ n ];
+ if ( pData->GetMinWidth() <= m_nWidth )
+ {
+ BitmapEx aBmp;
+ ImpGetLine( pData->GetLine1ForWidth( m_nWidth ),
+ pData->GetLine2ForWidth( m_nWidth ),
+ pData->GetDistForWidth( m_nWidth ),
+ GetColorLine1( GetItemCount( ) ),
+ GetColorLine2( GetItemCount( ) ),
+ GetColorDist( GetItemCount( ) ),
+ pData->GetStyle(), aBmp );
+ InsertItem(nId, Image(aBmp), SvtLineListBox::GetLineStyleName(pData->GetStyle()));
+ Size aBmpSize = aBmp.GetSizePixel();
+ if (aBmpSize.Width() > aSize.Width())
+ aSize.setWidth(aBmpSize.getWidth());
+ if (aBmpSize.Height() > aSize.Height())
+ aSize.setHeight(aBmpSize.getHeight());
+ if ( n == nTypePos )
+ SelectItem(nId);
+ }
+ else if ( n == nTypePos )
+ SetNoSelection();
+ n++;
+ ++nId;
+ }
+
+ Invalidate();
+
+ return aSize;
+ }
+
+ Color LineListBox::GetColorLine1( sal_Int32 nPos )
+ {
+ sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
+ if (nStyle == -1)
+ return GetPaintColor( );
+ auto& pData = m_vLineList[ nStyle ];
+ return pData->GetColorLine1( GetColor( ) );
+ }
+
+ Color LineListBox::GetColorLine2( sal_Int32 nPos )
+ {
+ sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
+ if (nStyle == -1)
+ return GetPaintColor( );
+ auto& pData = m_vLineList[ nStyle ];
+ return pData->GetColorLine2( GetColor( ) );
+ }
+
+ Color LineListBox::GetColorDist( sal_Int32 nPos )
+ {
+ Color rResult = Application::GetSettings().GetStyleSettings().GetFieldColor();
+
+ sal_Int32 nStyle = GetStylePos( nPos, m_nWidth );
+ if (nStyle == -1)
+ return rResult;
+ auto& pData = m_vLineList[ nStyle ];
+ return pData->GetColorDist( GetColor( ), rResult );
+ }
+}
+
+namespace {
+
+class SvxLineWindow_Impl final : public WeldToolbarPopup
+{
+private:
+ rtl::Reference<SvxFrameToolBoxControl> m_xControl;
+ std::unique_ptr<LineListBox> m_xLineStyleLb;
+ std::unique_ptr<weld::CustomWeld> m_xLineStyleLbWin;
+ bool m_bIsWriter;
+
+ DECL_LINK( SelectHdl, ValueSet*, void );
+
+public:
+ SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent);
+ virtual void GrabFocus() override
+ {
+ m_xLineStyleLb->GrabFocus();
+ }
+};
+
+}
+
+class SvxStyleToolBoxControl;
+
+class SfxStyleControllerItem_Impl : public SfxStatusListener
+{
+ public:
+ SfxStyleControllerItem_Impl( const Reference< XDispatchProvider >& rDispatchProvider,
+ sal_uInt16 nSlotId,
+ const OUString& rCommand,
+ SvxStyleToolBoxControl& rTbxCtl );
+
+ protected:
+ virtual void StateChangedAtStatusListener( SfxItemState eState, const SfxPoolItem* pState ) override;
+
+ private:
+ SvxStyleToolBoxControl& rControl;
+};
+
+#define BUTTON_PADDING 10
+#define ITEM_HEIGHT 30
+
+SvxStyleBox_Base::SvxStyleBox_Base(std::unique_ptr<weld::ComboBox> xWidget,
+ const OUString& rCommand,
+ SfxStyleFamily eFamily,
+ const Reference< XDispatchProvider >& rDispatchProvider,
+ const Reference< XFrame >& _xFrame,
+ const OUString& rClearFormatKey,
+ const OUString& rMoreKey,
+ bool bInSpec, SvxStyleToolBoxControl& rCtrl)
+ : m_rCtrl(rCtrl)
+ , m_xMenuBuilder(Application::CreateBuilder(nullptr, "svx/ui/stylemenu.ui"))
+ , m_xMenu(m_xMenuBuilder->weld_menu("menu"))
+ , m_xWidget(std::move(xWidget))
+ , eStyleFamily( eFamily )
+ , m_nMaxUserDrawFontWidth(0)
+ , m_nLastItemWithMenu(-1)
+ , bRelease( true )
+ , m_xDispatchProvider( rDispatchProvider )
+ , m_xFrame(_xFrame)
+ , m_aCommand( rCommand )
+ , aClearFormatKey( rClearFormatKey )
+ , aMoreKey( rMoreKey )
+ , bInSpecialMode( bInSpec )
+{
+ m_xWidget->connect_changed(LINK(this, SvxStyleBox_Base, SelectHdl));
+ m_xWidget->connect_key_press(LINK(this, SvxStyleBox_Base, KeyInputHdl));
+ m_xWidget->connect_entry_activate(LINK(this, SvxStyleBox_Base, ActivateHdl));
+ m_xWidget->connect_focus_out(LINK(this, SvxStyleBox_Base, FocusOutHdl));
+ m_xWidget->connect_get_property_tree(LINK(this, SvxStyleBox_Base, DumpAsPropertyTreeHdl));
+ m_xWidget->set_help_id(HID_STYLE_LISTBOX);
+ m_xWidget->set_entry_completion(true);
+ m_xMenu->connect_activate(LINK(this, SvxStyleBox_Base, MenuSelectHdl));
+
+ m_xWidget->connect_custom_get_size(LINK(this, SvxStyleBox_Base, CustomGetSizeHdl));
+ m_xWidget->connect_custom_render(LINK(this, SvxStyleBox_Base, CustomRenderHdl));
+ m_xWidget->set_custom_renderer(true);
+
+ m_xWidget->set_entry_width_chars(COMBO_WIDTH_IN_CHARS + 3);
+}
+
+IMPL_LINK(SvxStyleBox_Base, CustomGetSizeHdl, OutputDevice&, rArg, Size)
+{
+ CalcOptimalExtraUserWidth(rArg);
+ return Size(m_nMaxUserDrawFontWidth, ITEM_HEIGHT);
+}
+
+SvxStyleBox_Impl::SvxStyleBox_Impl(vcl::Window* pParent,
+ const OUString& rCommand,
+ SfxStyleFamily eFamily,
+ const Reference< XDispatchProvider >& rDispatchProvider,
+ const Reference< XFrame >& _xFrame,
+ const OUString& rClearFormatKey,
+ const OUString& rMoreKey,
+ bool bInSpec, SvxStyleToolBoxControl& rCtrl)
+ : InterimItemWindow(pParent, "svx/ui/applystylebox.ui", "ApplyStyleBox")
+ , SvxStyleBox_Base(m_xBuilder->weld_combo_box("applystyle"), rCommand, eFamily,
+ rDispatchProvider, _xFrame, rClearFormatKey, rMoreKey, bInSpec, rCtrl)
+{
+ InitControlBase(m_xWidget.get());
+
+ set_id("applystyle");
+ SetOptimalSize();
+}
+
+void SvxStyleBox_Base::ReleaseFocus()
+{
+ if ( !bRelease )
+ {
+ bRelease = true;
+ return;
+ }
+ if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() )
+ m_xFrame->getContainerWindow()->setFocus();
+}
+
+IMPL_LINK(SvxStyleBox_Base, MenuSelectHdl, const OString&, rMenuIdent, void)
+{
+ if (m_nLastItemWithMenu < 0 || m_nLastItemWithMenu >= m_xWidget->get_count())
+ return;
+
+ OUString sEntry = m_xWidget->get_text(m_nLastItemWithMenu);
+
+ ReleaseFocus(); // It must be after getting entry pos!
+ Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("Param", sEntry),
+ comphelper::makePropertyValue("Family",
+ sal_Int16( eStyleFamily )) };
+
+ if (rMenuIdent == "update")
+ {
+ SfxToolBoxControl::Dispatch( m_xDispatchProvider,
+ ".uno:StyleUpdateByExample", aArgs );
+ }
+ else if (rMenuIdent == "edit")
+ {
+ SfxToolBoxControl::Dispatch( m_xDispatchProvider,
+ ".uno:EditStyle", aArgs );
+ }
+}
+
+IMPL_STATIC_LINK_NOARG(SvxStyleBox_Base, ShowMoreHdl, void*, void)
+{
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ DBG_ASSERT( pViewFrm, "SvxStyleBox_Base::Select(): no viewframe" );
+ if (!pViewFrm)
+ return;
+ pViewFrm->ShowChildWindow(SID_SIDEBAR);
+ ::sfx2::sidebar::Sidebar::ShowPanel(u"StyleListPanel", pViewFrm->GetFrame().GetFrameInterface(), true);
+}
+
+IMPL_LINK(SvxStyleBox_Base, SelectHdl, weld::ComboBox&, rCombo, void)
+{
+ Select(rCombo.changed_by_direct_pick()); // only when picked from the list
+}
+
+IMPL_LINK_NOARG(SvxStyleBox_Base, ActivateHdl, weld::ComboBox&, bool)
+{
+ Select(true);
+ return true;
+}
+
+void SvxStyleBox_Base::Select(bool bNonTravelSelect)
+{
+ if (!bNonTravelSelect)
+ return;
+
+ OUString aSearchEntry(m_xWidget->get_active_text());
+ bool bDoIt = true, bClear = false;
+ if( bInSpecialMode )
+ {
+ if( aSearchEntry == aClearFormatKey && m_xWidget->get_active() == 0 )
+ {
+ aSearchEntry = sDefaultStyle;
+ bClear = true;
+ //not only apply default style but also call 'ClearFormatting'
+ Sequence< PropertyValue > aEmptyVals;
+ SfxToolBoxControl::Dispatch( m_xDispatchProvider, ".uno:ResetAttributes",
+ aEmptyVals);
+ }
+ else if (aSearchEntry == aMoreKey && m_xWidget->get_active() == (m_xWidget->get_count() - 1))
+ {
+ Application::PostUserEvent(LINK(nullptr, SvxStyleBox_Base, ShowMoreHdl));
+ //tdf#113214 change text back to previous entry
+ set_active_or_entry_text(m_xWidget->get_saved_value());
+ bDoIt = false;
+ }
+ }
+
+ //Do we need to create a new style?
+ SfxObjectShell *pShell = SfxObjectShell::Current();
+ SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyle = nullptr;
+
+ bool bCreateNew = false;
+
+ if ( pPool )
+ {
+ pStyle = pPool->First(eStyleFamily);
+ while ( pStyle && pStyle->GetName() != aSearchEntry )
+ pStyle = pPool->Next();
+ }
+
+ if ( !pStyle )
+ {
+ // cannot find the style for whatever reason
+ // therefore create a new style
+ bCreateNew = true;
+ }
+
+ /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
+ This instance may be deleted in the meantime (i.e. when a dialog is opened
+ while in Dispatch()), accessing members will crash in this case. */
+ ReleaseFocus();
+
+ if( !bDoIt )
+ return;
+
+ if ( bClear )
+ set_active_or_entry_text(aSearchEntry);
+ m_xWidget->save_value();
+
+ Sequence< PropertyValue > aArgs( 2 );
+ auto pArgs = aArgs.getArray();
+ pArgs[0].Value <<= aSearchEntry;
+ pArgs[1].Name = "Family";
+ pArgs[1].Value <<= sal_Int16( eStyleFamily );
+ if( bCreateNew )
+ {
+ pArgs[0].Name = "Param";
+ SfxToolBoxControl::Dispatch( m_xDispatchProvider, ".uno:StyleNewByExample", aArgs);
+ }
+ else
+ {
+ pArgs[0].Name = "Template";
+ SfxToolBoxControl::Dispatch( m_xDispatchProvider, m_aCommand, aArgs );
+ }
+}
+
+void SvxStyleBox_Base::SetFamily( SfxStyleFamily eNewFamily )
+{
+ eStyleFamily = eNewFamily;
+}
+
+IMPL_LINK_NOARG(SvxStyleBox_Base, FocusOutHdl, weld::Widget&, void)
+{
+ if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
+ set_active_or_entry_text(m_xWidget->get_saved_value());
+}
+
+IMPL_LINK(SvxStyleBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return DoKeyInput(rKEvt);
+}
+
+bool SvxStyleBox_Base::DoKeyInput(const KeyEvent& rKEvt)
+{
+ bool bHandled = false;
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+
+ switch (nCode)
+ {
+ case KEY_TAB:
+ bRelease = false;
+ Select(true);
+ break;
+ case KEY_ESCAPE:
+ set_active_or_entry_text(m_xWidget->get_saved_value());
+ if (!m_rCtrl.IsInSidebar())
+ {
+ ReleaseFocus();
+ bHandled = true;
+ }
+ break;
+ }
+
+ return bHandled;
+}
+
+bool SvxStyleBox_Impl::DoKeyInput(const KeyEvent& rKEvt)
+{
+ return SvxStyleBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt);
+}
+
+void SvxStyleBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ SetOptimalSize();
+ }
+
+ InterimItemWindow::DataChanged( rDCEvt );
+}
+
+bool SvxStyleBox_Base::AdjustFontForItemHeight(OutputDevice& rDevice, tools::Rectangle const & rTextRect, tools::Long nHeight)
+{
+ if (rTextRect.Bottom() > nHeight)
+ {
+ // the text does not fit, adjust the font size
+ double ratio = static_cast< double >( nHeight ) / rTextRect.Bottom();
+ vcl::Font aFont(rDevice.GetFont());
+ Size aPixelSize(aFont.GetFontSize());
+ aPixelSize.setWidth( aPixelSize.Width() * ratio );
+ aPixelSize.setHeight( aPixelSize.Height() * ratio );
+ aFont.SetFontSize(aPixelSize);
+ rDevice.SetFont(aFont);
+ return true;
+ }
+ return false;
+}
+
+void SvxStyleBox_Impl::SetOptimalSize()
+{
+ // set width in chars low so the size request will not be overridden
+ m_xWidget->set_entry_width_chars(1);
+ // tdf#132338 purely using this calculation to keep things their traditional width
+ Size aSize(LogicToPixel(Size((COMBO_WIDTH_IN_CHARS + 3) * 4, 0), MapMode(MapUnit::MapAppFont)));
+ m_xWidget->set_size_request(aSize.Width(), -1);
+
+ SetSizePixel(get_preferred_size());
+}
+
+void SvxStyleBox_Base::UserDrawEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const OUString &rStyleName)
+{
+ // IMG_TXT_DISTANCE in ilstbox.hxx is 6, then 1 is added as
+ // nBorder, and we are adding 1 in order to look better when
+ // italics is present
+ const int nLeftDistance = 8;
+
+ tools::Rectangle aTextRect;
+ rRenderContext.GetTextBoundRect(aTextRect, rStyleName);
+
+ Point aPos(rRect.TopLeft());
+ aPos.AdjustX(nLeftDistance );
+
+ if (!AdjustFontForItemHeight(rRenderContext, aTextRect, rRect.GetHeight()))
+ aPos.AdjustY((rRect.GetHeight() - aTextRect.Bottom() ) / 2);
+
+ rRenderContext.DrawText(aPos, rStyleName);
+}
+
+void SvxStyleBox_Base::SetupEntry(vcl::RenderContext& rRenderContext, sal_Int32 nItem, const tools::Rectangle& rRect, std::u16string_view rStyleName, bool bIsNotSelected)
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ if (!bIsNotSelected)
+ rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
+ else
+ rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
+
+ // handle the push-button
+ if (!bIsNotSelected)
+ {
+ if (nItem == 0 || nItem == m_xWidget->get_count() - 1)
+ m_xWidget->set_item_menu(OString::number(nItem), nullptr);
+ else
+ {
+ m_nLastItemWithMenu = nItem;
+ m_xWidget->set_item_menu(OString::number(nItem), m_xMenu.get());
+ }
+ }
+
+ if (nItem <= 0 || nItem >= m_xWidget->get_count() - 1)
+ return;
+
+ SfxObjectShell *pShell = SfxObjectShell::Current();
+ if (!pShell)
+ return;
+
+ SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool();
+ if (!pPool)
+ return;
+
+ SfxStyleSheetBase* pStyle = pPool->First(eStyleFamily);
+ while (pStyle && pStyle->GetName() != rStyleName)
+ pStyle = pPool->Next();
+
+ if (!pStyle )
+ return;
+
+ std::optional<SfxItemSet> const pItemSet(pStyle->GetItemSetForPreview());
+ if (!pItemSet) return;
+
+ const SvxFontItem * const pFontItem =
+ pItemSet->GetItem<SvxFontItem>(SID_ATTR_CHAR_FONT);
+ const SvxFontHeightItem * const pFontHeightItem =
+ pItemSet->GetItem<SvxFontHeightItem>(SID_ATTR_CHAR_FONTHEIGHT);
+
+ if ( !(pFontItem && pFontHeightItem) )
+ return;
+
+ Size aFontSize( 0, pFontHeightItem->GetHeight() );
+ Size aPixelSize(rRenderContext.LogicToPixel(aFontSize, MapMode(pShell->GetMapUnit())));
+
+ // setup the font properties
+ SvxFont aFont;
+ aFont.SetFamilyName(pFontItem->GetFamilyName());
+ aFont.SetStyleName(pFontItem->GetStyleName());
+ aFont.SetFontSize(aPixelSize);
+
+ const SfxPoolItem *pItem = pItemSet->GetItem( SID_ATTR_CHAR_WEIGHT );
+ if ( pItem )
+ aFont.SetWeight( static_cast< const SvxWeightItem* >( pItem )->GetWeight() );
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_POSTURE );
+ if ( pItem )
+ aFont.SetItalic( static_cast< const SvxPostureItem* >( pItem )->GetPosture() );
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_CONTOUR );
+ if ( pItem )
+ aFont.SetOutline( static_cast< const SvxContourItem* >( pItem )->GetValue() );
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_SHADOWED );
+ if ( pItem )
+ aFont.SetShadow( static_cast< const SvxShadowedItem* >( pItem )->GetValue() );
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_RELIEF );
+ if ( pItem )
+ aFont.SetRelief( static_cast< const SvxCharReliefItem* >( pItem )->GetValue() );
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_UNDERLINE );
+ if ( pItem )
+ aFont.SetUnderline( static_cast< const SvxUnderlineItem* >( pItem )->GetLineStyle() );
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_OVERLINE );
+ if ( pItem )
+ aFont.SetOverline( static_cast< const SvxOverlineItem* >( pItem )->GetValue() );
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_STRIKEOUT );
+ if ( pItem )
+ aFont.SetStrikeout( static_cast< const SvxCrossedOutItem* >( pItem )->GetStrikeout() );
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_CASEMAP );
+ if ( pItem )
+ aFont.SetCaseMap(static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap());
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_EMPHASISMARK );
+ if ( pItem )
+ aFont.SetEmphasisMark( static_cast< const SvxEmphasisMarkItem* >( pItem )->GetEmphasisMark() );
+
+ // setup the device & draw
+ Color aFontCol = COL_AUTO, aBackCol = COL_AUTO;
+
+ rRenderContext.SetFont(aFont);
+
+ pItem = pItemSet->GetItem( SID_ATTR_CHAR_COLOR );
+ // text color, when nothing is selected
+ if ( (nullptr != pItem) && bIsNotSelected)
+ aFontCol = static_cast< const SvxColorItem* >( pItem )->GetValue();
+
+ drawing::FillStyle style = drawing::FillStyle_NONE;
+ // which kind of Fill style is selected
+ pItem = pItemSet->GetItem( XATTR_FILLSTYLE );
+ // only when ok and not selected
+ if ( (nullptr != pItem) && bIsNotSelected)
+ style = static_cast< const XFillStyleItem* >( pItem )->GetValue();
+
+ switch(style)
+ {
+ case drawing::FillStyle_SOLID:
+ {
+ // set background color
+ pItem = pItemSet->GetItem( XATTR_FILLCOLOR );
+ if ( nullptr != pItem )
+ aBackCol = static_cast< const XFillColorItem* >( pItem )->GetColorValue();
+
+ if ( aBackCol != COL_AUTO )
+ {
+ rRenderContext.SetFillColor(aBackCol);
+ rRenderContext.DrawRect(rRect);
+ }
+ }
+ break;
+
+ default: break;
+ //TODO Draw the other background styles: gradient, hatching and bitmap
+ }
+
+ // when the font and background color are too similar, adjust the Font-Color
+ if( (aFontCol != COL_AUTO) || (aBackCol != COL_AUTO) )
+ aFontCol = TestColorsVisible(aFontCol, (aBackCol != COL_AUTO) ? aBackCol : rRenderContext.GetBackground().GetColor());
+
+ // set text color
+ if ( aFontCol != COL_AUTO )
+ rRenderContext.SetTextColor(aFontCol);
+}
+
+IMPL_LINK(SvxStyleBox_Base, CustomRenderHdl, weld::ComboBox::render_args, aPayload, void)
+{
+ vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
+ const ::tools::Rectangle& rRect = std::get<1>(aPayload);
+ bool bSelected = std::get<2>(aPayload);
+ const OUString& rId = std::get<3>(aPayload);
+
+ sal_uInt32 nIndex = rId.toUInt32();
+
+ OUString aStyleName(m_xWidget->get_text(nIndex));
+
+ rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
+
+ SetupEntry(rRenderContext, nIndex, rRect, aStyleName, !bSelected);
+
+ UserDrawEntry(rRenderContext, rRect, aStyleName);
+
+ rRenderContext.Pop();
+}
+
+void SvxStyleBox_Base::CalcOptimalExtraUserWidth(vcl::RenderContext& rRenderContext)
+{
+ if (m_nMaxUserDrawFontWidth)
+ return;
+
+ tools::Long nMaxNormalFontWidth = 0;
+ sal_Int32 nEntryCount = m_xWidget->get_count();
+ for (sal_Int32 i = 0; i < nEntryCount; ++i)
+ {
+ OUString sStyleName(get_text(i));
+ tools::Rectangle aTextRectForDefaultFont;
+ rRenderContext.GetTextBoundRect(aTextRectForDefaultFont, sStyleName);
+
+ const tools::Long nWidth = aTextRectForDefaultFont.GetWidth();
+
+ nMaxNormalFontWidth = std::max(nWidth, nMaxNormalFontWidth);
+ }
+
+ m_nMaxUserDrawFontWidth = nMaxNormalFontWidth;
+ for (sal_Int32 i = 1; i < nEntryCount-1; ++i)
+ {
+ OUString sStyleName(get_text(i));
+
+ rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
+ SetupEntry(rRenderContext, i, tools::Rectangle(0, 0, RECT_MAX, ITEM_HEIGHT), sStyleName, true);
+ tools::Rectangle aTextRectForActualFont;
+ rRenderContext.GetTextBoundRect(aTextRectForActualFont, sStyleName);
+ if (AdjustFontForItemHeight(rRenderContext, aTextRectForActualFont, ITEM_HEIGHT))
+ {
+ //Font didn't fit, so it was changed, refetch with final font size
+ rRenderContext.GetTextBoundRect(aTextRectForActualFont, sStyleName);
+ }
+ rRenderContext.Pop();
+
+ const int nWidth = aTextRectForActualFont.GetWidth() + m_xWidget->get_menu_button_width() + BUTTON_PADDING;
+
+ m_nMaxUserDrawFontWidth = std::max(nWidth, m_nMaxUserDrawFontWidth);
+ }
+}
+
+// test is the color between Font- and background-color to be identify
+// return is always the Font-Color
+// when both light or dark, change the Contrast
+// in other case do not change the origin color
+// when the color is R=G=B=128 the DecreaseContrast make 128 the need an exception
+Color SvxStyleBox_Base::TestColorsVisible(const Color &FontCol, const Color &BackCol)
+{
+ constexpr sal_uInt8 ChgVal = 60; // increase/decrease the Contrast
+
+ Color retCol = FontCol;
+ if ((FontCol.IsDark() == BackCol.IsDark()) && (FontCol.IsBright() == BackCol.IsBright()))
+ {
+ sal_uInt8 lumi = retCol.GetLuminance();
+
+ if((lumi > 120) && (lumi < 140))
+ retCol.DecreaseLuminance(ChgVal / 2);
+ else
+ retCol.DecreaseContrast(ChgVal);
+ }
+
+ return retCol;
+}
+
+IMPL_LINK(SvxStyleBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void)
+{
+ {
+ auto entriesNode = rJsonWriter.startNode("entries");
+ for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i)
+ {
+ auto entryNode = rJsonWriter.startNode("");
+ rJsonWriter.put("", m_xWidget->get_text(i));
+ }
+ }
+
+ int nActive = m_xWidget->get_active();
+ rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nActive == -1 ? 0 : 1));
+
+ {
+ auto selectedNode = rJsonWriter.startNode("selectedEntries");
+ if (nActive != -1)
+ {
+ auto node = rJsonWriter.startNode("");
+ rJsonWriter.put("", static_cast<sal_Int32>(nActive));
+ }
+ }
+
+ rJsonWriter.put("command", ".uno:StyleApply");
+}
+
+static bool lcl_GetDocFontList(const FontList** ppFontList, SvxFontNameBox_Base* pBox)
+{
+ bool bChanged = false;
+ const SfxObjectShell* pDocSh = SfxObjectShell::Current();
+ const SvxFontListItem* pFontListItem = nullptr;
+
+ if ( pDocSh )
+ pFontListItem =
+ static_cast<const SvxFontListItem*>(pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST ));
+ else
+ {
+ ::std::unique_ptr<FontList> aFontList(new FontList(Application::GetDefaultDevice()));
+ *ppFontList = aFontList.get();
+ pBox->SetOwnFontList(std::move(aFontList));
+ bChanged = true;
+ }
+
+ if ( pFontListItem )
+ {
+ const FontList* pNewFontList = pFontListItem->GetFontList();
+ DBG_ASSERT( pNewFontList, "Doc-FontList not available!" );
+
+ // No old list, but a new list
+ if ( !*ppFontList && pNewFontList )
+ {
+ // => take over
+ *ppFontList = pNewFontList;
+ bChanged = true;
+ }
+ else
+ {
+ // Comparing the font lists is not perfect.
+ // When you change the font list in the Doc, you can track
+ // changes here only on the Listbox, because ppFontList
+ // has already been updated.
+ bChanged =
+ ( ( *ppFontList != pNewFontList ) ||
+ pBox->GetListCount() != pNewFontList->GetFontNameCount() );
+ // HACK: Comparing is incomplete
+
+ if ( bChanged )
+ *ppFontList = pNewFontList;
+ }
+
+ if ( pBox )
+ pBox->set_sensitive(true);
+ }
+ else if ( pBox && ( pDocSh || !ppFontList ))
+ {
+ // Disable box only when we have a SfxObjectShell and didn't get a font list OR
+ // we don't have a SfxObjectShell and no current font list.
+ // It's possible that we currently have no SfxObjectShell, but a current font list.
+ // See #i58471: When a user set the focus into the font name combo box and opens
+ // the help window with F1. After closing the help window, we disable the font name
+ // combo box. The SfxObjectShell::Current() method returns in that case zero. But the
+ // font list hasn't changed and therefore the combo box shouldn't be disabled!
+ pBox->set_sensitive(false);
+ }
+
+ // Fill the FontBox, also the new list if necessary
+ if ( pBox && bChanged )
+ {
+ if ( *ppFontList )
+ pBox->Fill( *ppFontList );
+ else
+ pBox->Clear();
+ }
+ return bChanged;
+}
+
+SvxFontNameBox_Base::SvxFontNameBox_Base(std::unique_ptr<weld::ComboBox> xWidget,
+ const Reference<XDispatchProvider>& rDispatchProvider,
+ const Reference<XFrame>& rFrame,
+ SvxFontNameToolBoxControl& rCtrl)
+ : m_xListener(new comphelper::ConfigurationListener("/org.openoffice.Office.Common/Font/View"))
+ , m_aWYSIWYG(m_xListener, "ShowFontBoxWYSIWYG", *this)
+ , m_aHistory(m_xListener, "History", *this)
+ , m_rCtrl(rCtrl)
+ , m_xWidget(new FontNameBox(std::move(xWidget)))
+ , pFontList(nullptr)
+ , nFtCount(0)
+ , bRelease(true)
+ , m_xDispatchProvider(rDispatchProvider)
+ , m_xFrame(rFrame)
+ , mbCheckingUnknownFont(false)
+{
+ EnableControls();
+
+ m_xWidget->connect_changed(LINK(this, SvxFontNameBox_Base, SelectHdl));
+ m_xWidget->connect_key_press(LINK(this, SvxFontNameBox_Base, KeyInputHdl));
+ m_xWidget->connect_entry_activate(LINK(this, SvxFontNameBox_Base, ActivateHdl));
+ m_xWidget->connect_focus_in(LINK(this, SvxFontNameBox_Base, FocusInHdl));
+ m_xWidget->connect_focus_out(LINK(this, SvxFontNameBox_Base, FocusOutHdl));
+ m_xWidget->connect_get_property_tree(LINK(this, SvxFontNameBox_Base, DumpAsPropertyTreeHdl));
+
+ m_xWidget->set_entry_width_chars(COMBO_WIDTH_IN_CHARS + 5);
+}
+
+SvxFontNameBox_Impl::SvxFontNameBox_Impl(vcl::Window* pParent, const Reference<XDispatchProvider>& rDispatchProvider,
+ const Reference<XFrame>& rFrame, SvxFontNameToolBoxControl& rCtrl)
+ : InterimItemWindow(pParent, "svx/ui/fontnamebox.ui", "FontNameBox")
+ , SvxFontNameBox_Base(m_xBuilder->weld_combo_box("fontnamecombobox"), rDispatchProvider, rFrame, rCtrl)
+{
+ set_id("fontnamecombobox");
+ SetOptimalSize();
+}
+
+void SvxFontNameBox_Base::FillList()
+{
+ if (!m_xWidget) // e.g. disposed
+ return;
+ // Save old Selection, set back in the end
+ int nStartPos, nEndPos;
+ m_xWidget->get_entry_selection_bounds(nStartPos, nEndPos);
+
+ // Did Doc-Fontlist change?
+ lcl_GetDocFontList(&pFontList, this);
+
+ m_xWidget->select_entry_region(nStartPos, nEndPos);
+}
+
+void SvxFontNameBox_Base::CheckAndMarkUnknownFont()
+{
+ if (mbCheckingUnknownFont) //tdf#117537 block rentry
+ return;
+ mbCheckingUnknownFont = true;
+ OUString fontname = m_xWidget->get_active_text();
+ lcl_GetDocFontList( &pFontList, this );
+ // If the font is unknown, show it in italic.
+ vcl::Font font = m_xWidget->get_entry_font();
+ if( pFontList != nullptr && pFontList->IsAvailable( fontname ))
+ {
+ if( font.GetItalic() != ITALIC_NONE )
+ {
+ font.SetItalic( ITALIC_NONE );
+ m_xWidget->set_entry_font(font);
+ m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME));
+ }
+ }
+ else
+ {
+ if( font.GetItalic() != ITALIC_NORMAL )
+ {
+ font.SetItalic( ITALIC_NORMAL );
+ m_xWidget->set_entry_font(font);
+ m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME_NOTAVAILABLE));
+ }
+ }
+ mbCheckingUnknownFont = false;
+}
+
+void SvxFontNameBox_Base::Update( const css::awt::FontDescriptor* pFontDesc )
+{
+ if ( pFontDesc )
+ {
+ aCurFont.SetFamilyName ( pFontDesc->Name );
+ aCurFont.SetFamily ( FontFamily( pFontDesc->Family ) );
+ aCurFont.SetStyleName ( pFontDesc->StyleName );
+ aCurFont.SetPitch ( FontPitch( pFontDesc->Pitch ) );
+ aCurFont.SetCharSet ( rtl_TextEncoding( pFontDesc->CharSet ) );
+ }
+ OUString aCurName = aCurFont.GetFamilyName();
+ OUString aText = m_xWidget->get_active_text();
+ if (aText != aCurName)
+ set_active_or_entry_text(aCurName);
+}
+
+void SvxFontNameBox_Base::set_active_or_entry_text(const OUString& rText)
+{
+ m_xWidget->set_active_or_entry_text(rText);
+ CheckAndMarkUnknownFont();
+}
+
+IMPL_LINK_NOARG(SvxFontNameBox_Base, FocusInHdl, weld::Widget&, void)
+{
+ FillList();
+}
+
+IMPL_LINK(SvxFontNameBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return DoKeyInput(rKEvt);
+}
+
+bool SvxFontNameBox_Base::DoKeyInput(const KeyEvent& rKEvt)
+{
+ bool bHandled = false;
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+
+ switch (nCode)
+ {
+ case KEY_TAB:
+ bRelease = false;
+ Select(true);
+ break;
+
+ case KEY_ESCAPE:
+ set_active_or_entry_text(m_xWidget->get_saved_value());
+ if (!m_rCtrl.IsInSidebar())
+ {
+ ReleaseFocus_Impl();
+ bHandled = true;
+ }
+ EndPreview();
+ break;
+ }
+
+ return bHandled;
+}
+
+bool SvxFontNameBox_Impl::DoKeyInput(const KeyEvent& rKEvt)
+{
+ return SvxFontNameBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(SvxFontNameBox_Base, FocusOutHdl, weld::Widget&, void)
+{
+ if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
+ {
+ set_active_or_entry_text(m_xWidget->get_saved_value());
+ // send EndPreview
+ EndPreview();
+ }
+}
+
+void SvxFontNameBox_Impl::SetOptimalSize()
+{
+ // set width in chars low so the size request will not be overridden
+ m_xWidget->set_entry_width_chars(1);
+ // tdf#132338 purely using this calculation to keep things their traditional width
+ Size aSize(LogicToPixel(Size((COMBO_WIDTH_IN_CHARS +5) * 4, 0), MapMode(MapUnit::MapAppFont)));
+ m_xWidget->set_size_request(aSize.Width(), -1);
+
+ SetSizePixel(get_preferred_size());
+}
+
+void SvxFontNameBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ SetOptimalSize();
+ }
+ else if ( ( rDCEvt.GetType() == DataChangedEventType::FONTS ) ||
+ ( rDCEvt.GetType() == DataChangedEventType::DISPLAY ) )
+ {
+ // The old font list in shell has likely been destroyed at this point, so we need to get
+ // the new one before doing anything further.
+ lcl_GetDocFontList( &pFontList, this );
+ }
+}
+
+void SvxFontNameBox_Base::ReleaseFocus_Impl()
+{
+ if ( !bRelease )
+ {
+ bRelease = true;
+ return;
+ }
+ if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() )
+ m_xFrame->getContainerWindow()->setFocus();
+}
+
+void SvxFontNameBox_Base::EnableControls()
+{
+ bool bEnableMRU = m_aHistory.get();
+ sal_uInt16 nEntries = bEnableMRU ? MAX_MRU_FONTNAME_ENTRIES : 0;
+
+ bool bNewWYSIWYG = m_aWYSIWYG.get();
+ bool bOldWYSIWYG = m_xWidget->IsWYSIWYGEnabled();
+
+ if (m_xWidget->get_max_mru_count() != nEntries || bNewWYSIWYG != bOldWYSIWYG)
+ {
+ // refill in the next GetFocus-Handler
+ pFontList = nullptr;
+ Clear();
+ m_xWidget->set_max_mru_count(nEntries);
+ }
+
+ if (bNewWYSIWYG != bOldWYSIWYG)
+ m_xWidget->EnableWYSIWYG(bNewWYSIWYG);
+}
+
+IMPL_LINK(SvxFontNameBox_Base, SelectHdl, weld::ComboBox&, rCombo, void)
+{
+ Select(rCombo.changed_by_direct_pick()); // only when picked from the list
+}
+
+IMPL_LINK_NOARG(SvxFontNameBox_Base, ActivateHdl, weld::ComboBox&, bool)
+{
+ Select(true);
+ return true;
+}
+
+void SvxFontNameBox_Base::Select(bool bNonTravelSelect)
+{
+ Sequence< PropertyValue > aArgs( 1 );
+ auto pArgs = aArgs.getArray();
+ std::unique_ptr<SvxFontItem> pFontItem;
+ if ( pFontList )
+ {
+ FontMetric aFontMetric( pFontList->Get(m_xWidget->get_active_text(),
+ aCurFont.GetWeight(),
+ aCurFont.GetItalic() ) );
+ aCurFont = aFontMetric;
+
+ pFontItem.reset( new SvxFontItem( aFontMetric.GetFamilyType(),
+ aFontMetric.GetFamilyName(),
+ aFontMetric.GetStyleName(),
+ aFontMetric.GetPitch(),
+ aFontMetric.GetCharSet(),
+ SID_ATTR_CHAR_FONT ) );
+
+ Any a;
+ pFontItem->QueryValue( a );
+ pArgs[0].Value = a;
+ }
+
+ if (bNonTravelSelect)
+ {
+ CheckAndMarkUnknownFont();
+ // #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
+ // This instance may be deleted in the meantime (i.e. when a dialog is opened
+ // while in Dispatch()), accessing members will crash in this case.
+ ReleaseFocus_Impl();
+ EndPreview();
+ if (pFontItem)
+ {
+ pArgs[0].Name = "CharFontName";
+ SfxToolBoxControl::Dispatch( m_xDispatchProvider,
+ ".uno:CharFontName",
+ aArgs );
+ }
+ }
+ else
+ {
+ if (pFontItem)
+ {
+ pArgs[0].Name = "CharPreviewFontName";
+ SfxToolBoxControl::Dispatch( m_xDispatchProvider,
+ ".uno:CharPreviewFontName",
+ aArgs );
+ }
+ }
+}
+
+IMPL_LINK(SvxFontNameBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void)
+{
+ {
+ auto entriesNode = rJsonWriter.startNode("entries");
+ for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i)
+ {
+ auto entryNode = rJsonWriter.startNode("");
+ rJsonWriter.put("", m_xWidget->get_text(i));
+ }
+ }
+
+ int nSelectedEntry = m_xWidget->get_active();
+ rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nSelectedEntry == -1 ? 0 : 1));
+
+ {
+ auto selectedNode = rJsonWriter.startNode("selectedEntries");
+ if (nSelectedEntry != -1)
+ {
+ auto entryNode = rJsonWriter.startNode("");
+ rJsonWriter.put("", m_xWidget->get_text(nSelectedEntry));
+ }
+ }
+
+ rJsonWriter.put("command", ".uno:CharFontName");
+}
+
+ColorWindow::ColorWindow(const OUString& rCommand,
+ std::shared_ptr<PaletteManager> const & rPaletteManager,
+ ColorStatus& rColorStatus,
+ sal_uInt16 nSlotId,
+ const Reference< XFrame >& rFrame,
+ const MenuOrToolMenuButton& rMenuButton,
+ TopLevelParentFunction const& rTopLevelParentFunction,
+ ColorSelectFunction const & rColorSelectFunction)
+ : WeldToolbarPopup(rFrame, rMenuButton.get_widget(), "svx/ui/colorwindow.ui", "palette_popup_window")
+ , theSlotId(nSlotId)
+ , maCommand(rCommand)
+ , maMenuButton(rMenuButton)
+ , mxPaletteManager(rPaletteManager)
+ , mrColorStatus(rColorStatus)
+ , maTopLevelParentFunction(rTopLevelParentFunction)
+ , maColorSelectFunction(rColorSelectFunction)
+ , mxColorSet(new SvxColorValueSet(m_xBuilder->weld_scrolled_window("colorsetwin", true)))
+ , mxRecentColorSet(new SvxColorValueSet(nullptr))
+ , mxPaletteListBox(m_xBuilder->weld_combo_box("palette_listbox"))
+ , mxButtonAutoColor(m_xBuilder->weld_button("auto_color_button"))
+ , mxButtonNoneColor(m_xBuilder->weld_button("none_color_button"))
+ , mxButtonPicker(m_xBuilder->weld_button("color_picker_button"))
+ , mxAutomaticSeparator(m_xBuilder->weld_widget("separator4"))
+ , mxColorSetWin(new weld::CustomWeld(*m_xBuilder, "colorset", *mxColorSet))
+ , mxRecentColorSetWin(new weld::CustomWeld(*m_xBuilder, "recent_colorset", *mxRecentColorSet))
+ , mpDefaultButton(nullptr)
+{
+ mxColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
+ mxRecentColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
+
+ switch ( theSlotId )
+ {
+ case SID_ATTR_CHAR_COLOR_BACKGROUND:
+ case SID_BACKGROUND_COLOR:
+ case SID_ATTR_CHAR_BACK_COLOR:
+ case SID_TABLE_CELL_BACKGROUND_COLOR:
+ {
+ mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_NOFILL ) );
+ break;
+ }
+ case SID_AUTHOR_COLOR:
+ {
+ mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_BY_AUTHOR ) );
+ break;
+ }
+ case SID_BMPMASK_COLOR:
+ {
+ mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_TRANSPARENT ) );
+ break;
+ }
+ case SID_ATTR_CHAR_COLOR:
+ case SID_ATTR_CHAR_COLOR2:
+ case SID_EXTRUSION_3D_COLOR:
+ {
+ mxButtonAutoColor->set_label(EditResId(RID_SVXSTR_AUTOMATIC));
+ break;
+ }
+ case SID_FM_CTL_PROPERTIES:
+ {
+ mxButtonAutoColor->set_label( SvxResId( RID_SVXSTR_DEFAULT ) );
+ break;
+ }
+ default:
+ {
+ mxButtonAutoColor->hide();
+ mxAutomaticSeparator->hide();
+ break;
+ }
+ }
+
+ mxPaletteListBox->connect_changed(LINK(this, ColorWindow, SelectPaletteHdl));
+ std::vector<OUString> aPaletteList = mxPaletteManager->GetPaletteList();
+ mxPaletteListBox->freeze();
+ for (const auto& rPalette : aPaletteList)
+ mxPaletteListBox->append_text(rPalette);
+ mxPaletteListBox->thaw();
+ OUString aPaletteName( officecfg::Office::Common::UserColors::PaletteName::get() );
+ mxPaletteListBox->set_active_text(aPaletteName);
+ const int nSelectedEntry(mxPaletteListBox->get_active());
+ if (nSelectedEntry != -1)
+ mxPaletteManager->SetPalette(nSelectedEntry);
+
+ mxButtonAutoColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl));
+ mxButtonNoneColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl));
+ mxButtonPicker->connect_clicked(LINK(this, ColorWindow, OpenPickerClickHdl));
+
+ mxColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl));
+ mxRecentColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl));
+ m_xTopLevel->set_help_id(HID_POPUP_COLOR);
+ mxColorSet->SetHelpId(HID_POPUP_COLOR_CTRL);
+
+ mxPaletteManager->ReloadColorSet(*mxColorSet);
+ const sal_uInt32 nMaxItems(SvxColorValueSet::getMaxRowCount() * SvxColorValueSet::getColumnCount());
+ Size aSize = mxColorSet->layoutAllVisible(nMaxItems);
+ mxColorSet->set_size_request(aSize.Width(), aSize.Height());
+
+ mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
+ aSize = mxRecentColorSet->layoutAllVisible(mxPaletteManager->GetRecentColorCount());
+ mxRecentColorSet->set_size_request(aSize.Width(), aSize.Height());
+
+ AddStatusListener( ".uno:ColorTableState" );
+ AddStatusListener( maCommand );
+ if ( maCommand == ".uno:FrameLineColor" )
+ {
+ AddStatusListener( ".uno:BorderTLBR" );
+ AddStatusListener( ".uno:BorderBLTR" );
+ }
+}
+
+void ColorWindow::GrabFocus()
+{
+ if (mxColorSet->IsNoSelection() && mpDefaultButton)
+ mpDefaultButton->grab_focus();
+ else
+ mxColorSet->GrabFocus();
+}
+
+void ColorWindow::ShowNoneButton()
+{
+ mxButtonNoneColor->show();
+}
+
+ColorWindow::~ColorWindow()
+{
+}
+
+NamedColor ColorWindow::GetSelectEntryColor(ValueSet const * pColorSet)
+{
+ Color aColor = pColorSet->GetItemColor(pColorSet->GetSelectedItemId());
+ OUString sColorName = pColorSet->GetItemText(pColorSet->GetSelectedItemId());
+ return std::make_pair(aColor, sColorName);
+}
+
+namespace
+{
+ NamedColor GetAutoColor(sal_uInt16 nSlotId)
+ {
+ Color aColor;
+ OUString sColorName;
+ switch (nSlotId)
+ {
+ case SID_ATTR_CHAR_COLOR_BACKGROUND:
+ case SID_BACKGROUND_COLOR:
+ case SID_ATTR_CHAR_BACK_COLOR:
+ case SID_TABLE_CELL_BACKGROUND_COLOR:
+ aColor = COL_TRANSPARENT;
+ sColorName = SvxResId(RID_SVXSTR_NOFILL);
+ break;
+ case SID_AUTHOR_COLOR:
+ aColor = COL_TRANSPARENT;
+ sColorName = SvxResId(RID_SVXSTR_BY_AUTHOR);
+ break;
+ case SID_BMPMASK_COLOR:
+ aColor = COL_TRANSPARENT;
+ sColorName = SvxResId(RID_SVXSTR_TRANSPARENT);
+ break;
+ case SID_FM_CTL_PROPERTIES:
+ aColor = COL_TRANSPARENT;
+ sColorName = SvxResId(RID_SVXSTR_DEFAULT);
+ break;
+ case SID_ATTR_CHAR_COLOR:
+ case SID_ATTR_CHAR_COLOR2:
+ case SID_EXTRUSION_3D_COLOR:
+ default:
+ aColor = COL_AUTO;
+ sColorName = EditResId(RID_SVXSTR_AUTOMATIC);
+ break;
+ }
+
+ return std::make_pair(aColor, sColorName);
+ }
+
+ NamedColor GetNoneColor()
+ {
+ return std::make_pair(COL_NONE_COLOR, comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE)
+ : SvxResId(RID_SVXSTR_NONE));
+ }
+}
+
+NamedColor ColorWindow::GetSelectEntryColor() const
+{
+ if (!mxColorSet->IsNoSelection())
+ return GetSelectEntryColor(mxColorSet.get());
+ if (!mxRecentColorSet->IsNoSelection())
+ return GetSelectEntryColor(mxRecentColorSet.get());
+ if (mxButtonNoneColor.get() == mpDefaultButton)
+ return GetNoneColor();
+ return GetAutoColor();
+}
+
+IMPL_LINK(ColorWindow, SelectHdl, ValueSet*, pColorSet, void)
+{
+ NamedColor aNamedColor = GetSelectEntryColor(pColorSet);
+
+ if (pColorSet != mxRecentColorSet.get())
+ {
+ mxPaletteManager->AddRecentColor(aNamedColor.first, aNamedColor.second);
+ if (!maMenuButton.get_active())
+ mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
+ }
+
+ maSelectedLink.Call(aNamedColor);
+
+ // deliberate take a copy here in case maMenuButton.set_inactive
+ // triggers a callback that destroys ourself
+ ColorSelectFunction aColorSelectFunction(maColorSelectFunction);
+ OUString sCommand(maCommand);
+ // Same for querying IsTheme early.
+ bool bThemePaletteSelected = mxPaletteManager->IsThemePaletteSelected();
+ sal_uInt16 nSelectedItemId = pColorSet->GetSelectedItemId();
+
+ maMenuButton.set_inactive();
+
+ auto aNamedThemedColor = svx::NamedThemedColor::FromNamedColor(aNamedColor);
+ if (bThemePaletteSelected)
+ {
+ PaletteManager::GetThemeIndexLumModOff(nSelectedItemId, aNamedThemedColor.m_nThemeIndex,
+ aNamedThemedColor.m_nLumMod,
+ aNamedThemedColor.m_nLumOff);
+ }
+ aColorSelectFunction(sCommand, aNamedThemedColor);
+}
+
+IMPL_LINK_NOARG(ColorWindow, SelectPaletteHdl, weld::ComboBox&, void)
+{
+ int nPos = mxPaletteListBox->get_active();
+ mxPaletteManager->SetPalette( nPos );
+ mxPaletteManager->ReloadColorSet(*mxColorSet);
+ mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount());
+}
+
+NamedColor ColorWindow::GetAutoColor() const
+{
+ return ::GetAutoColor(theSlotId);
+}
+
+IMPL_LINK(ColorWindow, AutoColorClickHdl, weld::Button&, rButton, void)
+{
+ NamedColor aNamedColor = &rButton == mxButtonAutoColor.get() ? GetAutoColor() : GetNoneColor();
+
+ mxColorSet->SetNoSelection();
+ mxRecentColorSet->SetNoSelection();
+ mpDefaultButton = &rButton;
+
+ maSelectedLink.Call(aNamedColor);
+
+ // deliberate take a copy here in case maMenuButton.set_inactive
+ // triggers a callback that destroys ourself
+ ColorSelectFunction aColorSelectFunction(maColorSelectFunction);
+ OUString sCommand(maCommand);
+
+ maMenuButton.set_inactive();
+
+ aColorSelectFunction(sCommand, svx::NamedThemedColor::FromNamedColor(aNamedColor));
+}
+
+IMPL_LINK_NOARG(ColorWindow, OpenPickerClickHdl, weld::Button&, void)
+{
+ // copy before set_inactive
+ auto nColor = GetSelectEntryColor().first;
+ auto pParentWindow = maTopLevelParentFunction();
+ OUString sCommand = maCommand;
+ std::shared_ptr<PaletteManager> xPaletteManager(mxPaletteManager);
+
+ maMenuButton.set_inactive();
+
+ xPaletteManager->PopupColorPicker(pParentWindow, sCommand, nColor);
+}
+
+void ColorWindow::SetNoSelection()
+{
+ mxColorSet->SetNoSelection();
+ mxRecentColorSet->SetNoSelection();
+ mpDefaultButton = nullptr;
+}
+
+bool ColorWindow::IsNoSelection() const
+{
+ if (!mxColorSet->IsNoSelection())
+ return false;
+ if (!mxRecentColorSet->IsNoSelection())
+ return false;
+ return !mxButtonAutoColor->get_visible() && !mxButtonNoneColor->get_visible();
+}
+
+void ColorWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ if (rEvent.FeatureURL.Complete == ".uno:ColorTableState")
+ {
+ if (rEvent.IsEnabled && mxPaletteManager->GetPalette() == 0)
+ {
+ mxPaletteManager->ReloadColorSet(*mxColorSet);
+ mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount());
+ }
+ }
+ else
+ {
+ mrColorStatus.statusChanged(rEvent);
+ SelectEntry(mrColorStatus.GetColor());
+ }
+}
+
+bool ColorWindow::SelectValueSetEntry(SvxColorValueSet* pColorSet, const Color& rColor)
+{
+ for (size_t i = 1; i <= pColorSet->GetItemCount(); ++i)
+ {
+ if (rColor == pColorSet->GetItemColor(i))
+ {
+ pColorSet->SelectItem(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void ColorWindow::SelectEntry(const NamedColor& rNamedColor)
+{
+ SetNoSelection();
+
+ const Color &rColor = rNamedColor.first;
+
+ if (mxButtonAutoColor->get_visible() && (rColor == COL_TRANSPARENT || rColor == COL_AUTO))
+ {
+ mpDefaultButton = mxButtonAutoColor.get();
+ return;
+ }
+
+ if (mxButtonNoneColor->get_visible() && rColor == COL_NONE_COLOR)
+ {
+ mpDefaultButton = mxButtonNoneColor.get();
+ return;
+ }
+
+ // try current palette
+ bool bFoundColor = SelectValueSetEntry(mxColorSet.get(), rColor);
+ // try recently used
+ if (!bFoundColor)
+ bFoundColor = SelectValueSetEntry(mxRecentColorSet.get(), rColor);
+ // if it's not there, add it there now to the end of the recently used
+ // so its available somewhere handy, but not without trashing the
+ // whole recently used
+ if (!bFoundColor)
+ {
+ const OUString& rColorName = rNamedColor.second;
+ mxPaletteManager->AddRecentColor(rColor, rColorName, false);
+ mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet);
+ SelectValueSetEntry(mxRecentColorSet.get(), rColor);
+ }
+}
+
+void ColorWindow::SelectEntry(const Color& rColor)
+{
+ OUString sColorName = "#" + rColor.AsRGBHexString().toAsciiUpperCase();
+ ColorWindow::SelectEntry(std::make_pair(rColor, sColorName));
+}
+
+ColorStatus::ColorStatus() :
+ maColor( COL_TRANSPARENT ),
+ maTLBRColor( COL_TRANSPARENT ),
+ maBLTRColor( COL_TRANSPARENT )
+{
+}
+
+void ColorStatus::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ Color aColor( COL_TRANSPARENT );
+ css::table::BorderLine2 aTable;
+
+ if ( rEvent.State >>= aTable )
+ {
+ SvxBorderLine aLine;
+ SvxBoxItem::LineToSvxLine( aTable, aLine, false );
+ if ( !aLine.isEmpty() )
+ aColor = aLine.GetColor();
+ }
+ else
+ rEvent.State >>= aColor;
+
+ if ( rEvent.FeatureURL.Path == "BorderTLBR" )
+ maTLBRColor = aColor;
+ else if ( rEvent.FeatureURL.Path == "BorderBLTR" )
+ maBLTRColor = aColor;
+ else
+ maColor = aColor;
+}
+
+Color ColorStatus::GetColor()
+{
+ Color aColor( maColor );
+
+ if ( maTLBRColor != COL_TRANSPARENT )
+ {
+ if ( aColor != maTLBRColor && aColor != COL_TRANSPARENT )
+ return COL_TRANSPARENT;
+ aColor = maTLBRColor;
+ }
+
+ if ( maBLTRColor != COL_TRANSPARENT )
+ {
+ if ( aColor != maBLTRColor && aColor != COL_TRANSPARENT )
+ return COL_TRANSPARENT;
+ return maBLTRColor;
+ }
+
+ return aColor;
+}
+
+
+SvxFrameWindow_Impl::SvxFrameWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingframeborder.ui", "FloatingFrameBorder")
+ , mxControl(pControl)
+ , mxFrameSet(new SvxFrmValueSet_Impl)
+ , mxFrameSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *mxFrameSet))
+ , bParagraphMode(false)
+ , m_bIsWriter(false)
+{
+
+ // check whether the document is Writer or not
+ if (Reference<lang::XServiceInfo> xSI{ m_xFrame->getController()->getModel(), UNO_QUERY })
+ m_bIsWriter = xSI->supportsService("com.sun.star.text.TextDocument");
+
+ mxFrameSet->SetStyle(WB_ITEMBORDER | WB_DOUBLEBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT);
+ AddStatusListener(".uno:BorderReducedMode");
+ InitImageList();
+
+ /*
+ * 1 2 3 4 5
+ * ------------------------------------------------------
+ * NONE LEFT RIGHT LEFTRIGHT DIAGONALDOWN
+ * TOP BOTTOM TOPBOTTOM OUTER DIAGONALUP
+ * ------------------------------------------------------
+ * HOR HORINNER VERINNER ALL CRISSCROSS <- can be switched of via bParagraphMode
+ */
+
+ sal_uInt16 i = 0;
+
+ // diagonal borders available only for Calc.
+ // Therefore, Calc uses 10 border types while
+ // Writer uses 8 of them - for a single cell.
+ for ( i=1; i < (m_bIsWriter ? 9 : 11); i++ )
+ mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
+
+ //bParagraphMode should have been set in StateChanged
+ if ( !bParagraphMode )
+ // when multiple cell selected:
+ // Writer has 12 border types and Calc has 15 of them.
+ for ( i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
+ mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
+
+ // adjust frame column for Writer
+ sal_uInt16 colCount = m_bIsWriter ? 4 : 5;
+ mxFrameSet->SetColCount( colCount );
+ mxFrameSet->SetSelectHdl( LINK( this, SvxFrameWindow_Impl, SelectHdl ) );
+ CalcSizeValueSet();
+
+ mxFrameSet->SetHelpId( HID_POPUP_FRAME );
+ mxFrameSet->SetAccessibleName( SvxResId(RID_SVXSTR_FRAME) );
+}
+
+namespace {
+
+enum class FrmValidFlags {
+ NONE = 0x00,
+ Left = 0x01,
+ Right = 0x02,
+ Top = 0x04,
+ Bottom = 0x08,
+ HInner = 0x10,
+ VInner = 0x20,
+ AllMask = 0x3f,
+};
+
+}
+
+namespace o3tl {
+ template<> struct typed_flags<FrmValidFlags> : is_typed_flags<FrmValidFlags, 0x3f> {};
+}
+
+// By default unset lines remain unchanged.
+// Via Shift unset lines are reset
+
+IMPL_LINK_NOARG(SvxFrameWindow_Impl, SelectHdl, ValueSet*, void)
+{
+ SvxBoxItem aBorderOuter( SID_ATTR_BORDER_OUTER );
+ SvxBoxInfoItem aBorderInner( SID_ATTR_BORDER_INNER );
+ SvxBorderLine theDefLine;
+
+ // diagonal down border
+ SvxBorderLine dDownBorderLine(nullptr, SvxBorderLineWidth::Hairline);
+ SvxLineItem dDownLineItem(SID_ATTR_BORDER_DIAG_TLBR);
+
+ // diagonal up border
+ SvxBorderLine dUpBorderLine(nullptr, SvxBorderLineWidth::Hairline);
+ SvxLineItem dUpLineItem(SID_ATTR_BORDER_DIAG_BLTR);
+
+ bool bIsDiagonalBorder = false;
+
+ SvxBorderLine *pLeft = nullptr,
+ *pRight = nullptr,
+ *pTop = nullptr,
+ *pBottom = nullptr;
+ sal_uInt16 nSel = mxFrameSet->GetSelectedItemId();
+ sal_uInt16 nModifier = mxFrameSet->GetModifier();
+ FrmValidFlags nValidFlags = FrmValidFlags::NONE;
+
+ // tdf#48622, tdf#145828 use correct default to create intended 0.75pt
+ // cell border using the border formatting tool in the standard toolbar
+ theDefLine.GuessLinesWidths(theDefLine.GetBorderLineStyle(), SvxBorderLineWidth::Thin);
+
+ // nSel has 15 cases which means 15 border
+ // types for Calc. But Writer uses only 12
+ // of them - when diagonal borders excluded.
+ if (m_bIsWriter)
+ {
+ // add appropriate increments
+ // to match the correct borders.
+ if (nSel > 8) { nSel += 2; }
+ else if (nSel > 4) { nSel++; }
+ }
+
+ switch ( nSel )
+ {
+ case 1: nValidFlags |= FrmValidFlags::AllMask;
+ // set nullptr to remove diagonal lines
+ dDownLineItem.SetLine(nullptr);
+ dUpLineItem.SetLine(nullptr);
+ SetDiagonalDownBorder(dDownLineItem);
+ SetDiagonalUpBorder(dUpLineItem);
+ break; // NONE
+ case 2: pLeft = &theDefLine;
+ nValidFlags |= FrmValidFlags::Left;
+ break; // LEFT
+ case 3: pRight = &theDefLine;
+ nValidFlags |= FrmValidFlags::Right;
+ break; // RIGHT
+ case 4: pLeft = pRight = &theDefLine;
+ nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left;
+ break; // LEFTRIGHT
+ case 5: dDownLineItem.SetLine(&dDownBorderLine);
+ SetDiagonalDownBorder(dDownLineItem);
+ bIsDiagonalBorder = true;
+ break; // DIAGONAL DOWN
+ case 6: pTop = &theDefLine;
+ nValidFlags |= FrmValidFlags::Top;
+ break; // TOP
+ case 7: pBottom = &theDefLine;
+ nValidFlags |= FrmValidFlags::Bottom;
+ break; // BOTTOM
+ case 8: pTop = pBottom = &theDefLine;
+ nValidFlags |= FrmValidFlags::Bottom|FrmValidFlags::Top;
+ break; // TOPBOTTOM
+ case 9: pLeft = pRight = pTop = pBottom = &theDefLine;
+ nValidFlags |= FrmValidFlags::Left | FrmValidFlags::Right | FrmValidFlags::Top | FrmValidFlags::Bottom;
+ break; // OUTER
+ case 10:
+ dUpLineItem.SetLine(&dUpBorderLine);
+ SetDiagonalUpBorder(dUpLineItem);
+ bIsDiagonalBorder = true;
+ break; // DIAGONAL UP
+
+ // Inner Table:
+ case 11: // HOR
+ pTop = pBottom = &theDefLine;
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
+ aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
+ nValidFlags |= FrmValidFlags::HInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
+ break;
+
+ case 12: // HORINNER
+ pLeft = pRight = pTop = pBottom = &theDefLine;
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
+ aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
+ nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left|FrmValidFlags::HInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
+ break;
+
+ case 13: // VERINNER
+ pLeft = pRight = pTop = pBottom = &theDefLine;
+ aBorderInner.SetLine( nullptr, SvxBoxInfoItemLine::HORI );
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT );
+ nValidFlags |= FrmValidFlags::Right|FrmValidFlags::Left|FrmValidFlags::VInner|FrmValidFlags::Top|FrmValidFlags::Bottom;
+ break;
+
+ case 14: // ALL
+ pLeft = pRight = pTop = pBottom = &theDefLine;
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT );
+ nValidFlags |= FrmValidFlags::AllMask;
+ break;
+
+ case 15:
+ // set both diagonal lines to draw criss-cross line
+ dDownLineItem.SetLine(&dDownBorderLine);
+ dUpLineItem.SetLine(&dUpBorderLine);
+
+ SetDiagonalDownBorder(dDownLineItem);
+ SetDiagonalUpBorder(dUpLineItem);
+ bIsDiagonalBorder = true;
+ break; // CRISS-CROSS
+
+ default:
+ break;
+ }
+
+ // if diagonal borders selected,
+ // no need to execute this block
+ if (!bIsDiagonalBorder)
+ {
+ aBorderOuter.SetLine( pLeft, SvxBoxItemLine::LEFT );
+ aBorderOuter.SetLine( pRight, SvxBoxItemLine::RIGHT );
+ aBorderOuter.SetLine( pTop, SvxBoxItemLine::TOP );
+ aBorderOuter.SetLine( pBottom, SvxBoxItemLine::BOTTOM );
+
+ if(nModifier == KEY_SHIFT)
+ nValidFlags |= FrmValidFlags::AllMask;
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::TOP, bool(nValidFlags&FrmValidFlags::Top ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, bool(nValidFlags&FrmValidFlags::Bottom ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, bool(nValidFlags&FrmValidFlags::Left));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, bool(nValidFlags&FrmValidFlags::Right ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::HORI, bool(nValidFlags&FrmValidFlags::HInner ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::VERT, bool(nValidFlags&FrmValidFlags::VInner));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISABLE, false );
+
+ Any a1, a2;
+ aBorderOuter.QueryValue( a1 );
+ aBorderInner.QueryValue( a2 );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("OuterBorder", a1),
+ comphelper::makePropertyValue("InnerBorder", a2) };
+
+ mxControl->dispatchCommand( ".uno:SetBorderStyle", aArgs );
+ }
+
+ if (mxFrameSet)
+ {
+ /* #i33380# Moved the following line above the Dispatch() call.
+ This instance may be deleted in the meantime (i.e. when a dialog is opened
+ while in Dispatch()), accessing members will crash in this case. */
+ mxFrameSet->SetNoSelection();
+ }
+
+ mxControl->EndPopupMode();
+}
+
+void SvxFrameWindow_Impl::SetDiagonalDownBorder(const SvxLineItem& dDownLineItem)
+{
+ // apply diagonal down border
+ Any a;
+ dDownLineItem.QueryValue(a);
+ Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("BorderTLBR", a) };
+
+ mxControl->dispatchCommand(".uno:BorderTLBR", aArgs);
+}
+
+void SvxFrameWindow_Impl::SetDiagonalUpBorder(const SvxLineItem& dUpLineItem)
+{
+ // apply diagonal up border
+ Any a;
+ dUpLineItem.QueryValue(a);
+ Sequence<PropertyValue> aArgs{ comphelper::makePropertyValue("BorderBLTR", a) };
+
+ mxControl->dispatchCommand(".uno:BorderBLTR", aArgs);
+}
+
+void SvxFrameWindow_Impl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ if ( rEvent.FeatureURL.Complete != ".uno:BorderReducedMode" )
+ return;
+
+ bool bValue;
+ if ( !(rEvent.State >>= bValue) )
+ return;
+
+ bParagraphMode = bValue;
+ //initial calls mustn't insert or remove elements
+ if(!mxFrameSet->GetItemCount())
+ return;
+
+ // set 12 border types for Writer, otherwise 15 for Calc.
+ bool bTableMode = ( mxFrameSet->GetItemCount() == static_cast<size_t>(m_bIsWriter ? 12 : 15) );
+ bool bResize = false;
+
+ if ( bTableMode && bParagraphMode )
+ {
+ for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
+ mxFrameSet->RemoveItem(i);
+ bResize = true;
+ }
+ else if ( !bTableMode && !bParagraphMode )
+ {
+ for ( sal_uInt16 i = (m_bIsWriter ? 9 : 11); i < (m_bIsWriter ? 13 : 16); i++ )
+ mxFrameSet->InsertItem(i, Image(aImgVec[i-1].first), aImgVec[i-1].second);
+ bResize = true;
+ }
+
+ if ( bResize )
+ {
+ CalcSizeValueSet();
+ }
+}
+
+void SvxFrameWindow_Impl::CalcSizeValueSet()
+{
+ weld::DrawingArea* pDrawingArea = mxFrameSet->GetDrawingArea();
+ const OutputDevice& rDevice = pDrawingArea->get_ref_device();
+ Size aItemSize( 20 * rDevice.GetDPIScaleFactor(), 20 * rDevice.GetDPIScaleFactor() );
+ Size aSize = mxFrameSet->CalcWindowSizePixel( aItemSize );
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ mxFrameSet->SetOutputSizePixel(aSize);
+}
+
+void SvxFrameWindow_Impl::InitImageList()
+{
+ if (m_bIsWriter)
+ {
+ // Writer-specific aImgVec.
+ // Since Writer doesn't have diagonal borders,
+ // we have to use 12 border types here.
+ aImgVec = {
+ {BitmapEx(RID_SVXBMP_FRAME1), SvxResId(RID_SVXSTR_TABLE_PRESET_NONE)},
+ {BitmapEx(RID_SVXBMP_FRAME2), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYLEFT)},
+ {BitmapEx(RID_SVXBMP_FRAME3), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYRIGHT)},
+ {BitmapEx(RID_SVXBMP_FRAME4), SvxResId(RID_SVXSTR_PARA_PRESET_LEFTRIGHT)},
+
+ {BitmapEx(RID_SVXBMP_FRAME5), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTOP)},
+ {BitmapEx(RID_SVXBMP_FRAME6), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTBOTTOM)},
+ {BitmapEx(RID_SVXBMP_FRAME7), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOM)},
+ {BitmapEx(RID_SVXBMP_FRAME8), SvxResId(RID_SVXSTR_TABLE_PRESET_ONLYOUTER)},
+
+ {BitmapEx(RID_SVXBMP_FRAME9), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOMHORI)},
+ {BitmapEx(RID_SVXBMP_FRAME10), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERHORI)},
+ {BitmapEx(RID_SVXBMP_FRAME11), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERVERI)},
+ {BitmapEx(RID_SVXBMP_FRAME12), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERALL)}
+ };
+ }
+ else
+ {
+ // Calc has diagonal borders feature.
+ // Therefore use additional 3 diagonal border types,
+ // which make border types 15 in total.
+ aImgVec = {
+ {BitmapEx(RID_SVXBMP_FRAME1), SvxResId(RID_SVXSTR_TABLE_PRESET_NONE)},
+ {BitmapEx(RID_SVXBMP_FRAME2), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYLEFT)},
+ {BitmapEx(RID_SVXBMP_FRAME3), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYRIGHT)},
+ {BitmapEx(RID_SVXBMP_FRAME4), SvxResId(RID_SVXSTR_PARA_PRESET_LEFTRIGHT)},
+ {BitmapEx(RID_SVXBMP_FRAME14), SvxResId(RID_SVXSTR_PARA_PRESET_DIAGONALDOWN)}, // diagonal down border
+
+ {BitmapEx(RID_SVXBMP_FRAME5), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTOP)},
+ {BitmapEx(RID_SVXBMP_FRAME6), SvxResId(RID_SVXSTR_PARA_PRESET_ONLYTBOTTOM)},
+ {BitmapEx(RID_SVXBMP_FRAME7), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOM)},
+ {BitmapEx(RID_SVXBMP_FRAME8), SvxResId(RID_SVXSTR_TABLE_PRESET_ONLYOUTER)},
+ {BitmapEx(RID_SVXBMP_FRAME13), SvxResId(RID_SVXSTR_PARA_PRESET_DIAGONALUP)}, // diagonal up border
+
+ {BitmapEx(RID_SVXBMP_FRAME9), SvxResId(RID_SVXSTR_PARA_PRESET_TOPBOTTOMHORI)},
+ {BitmapEx(RID_SVXBMP_FRAME10), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERHORI)},
+ {BitmapEx(RID_SVXBMP_FRAME11), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERVERI)},
+ {BitmapEx(RID_SVXBMP_FRAME12), SvxResId(RID_SVXSTR_TABLE_PRESET_OUTERALL)},
+ {BitmapEx(RID_SVXBMP_FRAME15), SvxResId(RID_SVXSTR_PARA_PRESET_CRISSCROSS)} // criss-cross border
+ };
+ }
+}
+
+static Color lcl_mediumColor( Color aMain, Color /*aDefault*/ )
+{
+ return SvxBorderLine::threeDMediumColor( aMain );
+}
+
+SvxLineWindow_Impl::SvxLineWindow_Impl(SvxFrameToolBoxControl* pControl, weld::Widget* pParent)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/floatingframeborder.ui", "FloatingFrameBorder")
+ , m_xControl(pControl)
+ , m_xLineStyleLb(new LineListBox)
+ , m_xLineStyleLbWin(new weld::CustomWeld(*m_xBuilder, "valueset", *m_xLineStyleLb))
+ , m_bIsWriter(false)
+{
+ try
+ {
+ Reference< lang::XServiceInfo > xServices(m_xFrame->getController()->getModel(), UNO_QUERY_THROW);
+ m_bIsWriter = xServices->supportsService("com.sun.star.text.TextDocument");
+ }
+ catch(const uno::Exception& )
+ {
+ }
+
+ m_xLineStyleLb->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) );
+
+ m_xLineStyleLb->SetSourceUnit( FieldUnit::TWIP );
+ m_xLineStyleLb->SetNone( comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE)
+ :SvxResId(RID_SVXSTR_NONE) );
+
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::SOLID ), SvxBorderLineStyle::SOLID );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DOTTED ), SvxBorderLineStyle::DOTTED );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DASHED ), SvxBorderLineStyle::DASHED );
+
+ // Double lines
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::DOUBLE ), SvxBorderLineStyle::DOUBLE );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_SMALLGAP ), SvxBorderLineStyle::THINTHICK_SMALLGAP, 20 );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_MEDIUMGAP ), SvxBorderLineStyle::THINTHICK_MEDIUMGAP );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THINTHICK_LARGEGAP ), SvxBorderLineStyle::THINTHICK_LARGEGAP );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_SMALLGAP ), SvxBorderLineStyle::THICKTHIN_SMALLGAP, 20 );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_MEDIUMGAP ), SvxBorderLineStyle::THICKTHIN_MEDIUMGAP );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::THICKTHIN_LARGEGAP ), SvxBorderLineStyle::THICKTHIN_LARGEGAP );
+
+ // Engraved / Embossed
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::EMBOSSED ), SvxBorderLineStyle::EMBOSSED, 15,
+ &SvxBorderLine::threeDLightColor, &SvxBorderLine::threeDDarkColor,
+ &lcl_mediumColor );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::ENGRAVED ), SvxBorderLineStyle::ENGRAVED, 15,
+ &SvxBorderLine::threeDDarkColor, &SvxBorderLine::threeDLightColor,
+ &lcl_mediumColor );
+
+ // Inset / Outset
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::OUTSET ), SvxBorderLineStyle::OUTSET, 10,
+ &SvxBorderLine::lightColor, &SvxBorderLine::darkColor );
+ m_xLineStyleLb->InsertEntry( SvxBorderLine::getWidthImpl( SvxBorderLineStyle::INSET ), SvxBorderLineStyle::INSET, 10,
+ &SvxBorderLine::darkColor, &SvxBorderLine::lightColor );
+ Size aSize = m_xLineStyleLb->SetWidth( 20 ); // 1pt by default
+
+ m_xLineStyleLb->SetSelectHdl( LINK( this, SvxLineWindow_Impl, SelectHdl ) );
+
+ m_xContainer->set_help_id(HID_POPUP_LINE);
+
+ aSize.AdjustWidth(6);
+ aSize.AdjustHeight(6);
+ aSize = m_xLineStyleLb->CalcWindowSizePixel(aSize);
+ m_xLineStyleLb->GetDrawingArea()->set_size_request(aSize.Width(), aSize.Height());
+ m_xLineStyleLb->SetOutputSizePixel(aSize);
+}
+
+IMPL_LINK_NOARG(SvxLineWindow_Impl, SelectHdl, ValueSet*, void)
+{
+ SvxLineItem aLineItem( SID_FRAME_LINESTYLE );
+ SvxBorderLineStyle nStyle = m_xLineStyleLb->GetSelectEntryStyle();
+
+ if ( m_xLineStyleLb->GetSelectItemPos( ) > 0 )
+ {
+ SvxBorderLine aTmp;
+ aTmp.SetBorderLineStyle( nStyle );
+ aTmp.SetWidth( SvxBorderLineWidth::Thin ); // TODO Make it depend on a width field
+ aLineItem.SetLine( &aTmp );
+ }
+ else
+ aLineItem.SetLine( nullptr );
+
+ Any a;
+ aLineItem.QueryValue( a, m_bIsWriter ? CONVERT_TWIPS : 0 );
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("LineStyle", a) };
+
+ m_xControl->dispatchCommand( ".uno:LineStyle", aArgs );
+
+ m_xControl->EndPopupMode();
+}
+
+SfxStyleControllerItem_Impl::SfxStyleControllerItem_Impl(
+ const Reference< XDispatchProvider >& rDispatchProvider,
+ sal_uInt16 nSlotId, // Family-ID
+ const OUString& rCommand, // .uno: command bound to this item
+ SvxStyleToolBoxControl& rTbxCtl ) // controller instance, which the item is assigned to.
+ : SfxStatusListener( rDispatchProvider, nSlotId, rCommand ),
+ rControl( rTbxCtl )
+{
+}
+
+void SfxStyleControllerItem_Impl::StateChangedAtStatusListener(
+ SfxItemState eState, const SfxPoolItem* pState )
+{
+ switch ( GetId() )
+ {
+ case SID_STYLE_FAMILY1:
+ case SID_STYLE_FAMILY2:
+ case SID_STYLE_FAMILY3:
+ case SID_STYLE_FAMILY4:
+ case SID_STYLE_FAMILY5:
+ {
+ const sal_uInt16 nIdx = GetId() - SID_STYLE_FAMILY_START;
+
+ if ( SfxItemState::DEFAULT == eState )
+ {
+ const SfxTemplateItem* pStateItem =
+ dynamic_cast<const SfxTemplateItem*>( pState );
+ DBG_ASSERT( pStateItem != nullptr, "SfxTemplateItem expected" );
+ rControl.SetFamilyState( nIdx, pStateItem );
+ }
+ else
+ rControl.SetFamilyState( nIdx, nullptr );
+ break;
+ }
+ }
+}
+
+struct SvxStyleToolBoxControl::Impl
+{
+ OUString aClearForm;
+ OUString aMore;
+ ::std::vector< std::pair< OUString, OUString > > aDefaultStyles;
+ bool bSpecModeWriter;
+ bool bSpecModeCalc;
+
+ VclPtr<SvxStyleBox_Impl> m_xVclBox;
+ std::unique_ptr<SvxStyleBox_Base> m_xWeldBox;
+ SvxStyleBox_Base* m_pBox;
+
+ Impl()
+ :aClearForm ( SvxResId( RID_SVXSTR_CLEARFORM ) )
+ ,aMore ( SvxResId( RID_SVXSTR_MORE_STYLES ) )
+ ,bSpecModeWriter ( false )
+ ,bSpecModeCalc ( false )
+ ,m_pBox ( nullptr )
+ {
+
+
+ }
+ void InitializeStyles(const Reference < frame::XModel >& xModel)
+ {
+ aDefaultStyles.clear();
+
+ //now convert the default style names to the localized names
+ try
+ {
+ Reference< style::XStyleFamiliesSupplier > xStylesSupplier( xModel, UNO_QUERY_THROW );
+ Reference< lang::XServiceInfo > xServices( xModel, UNO_QUERY_THROW );
+ bSpecModeWriter = xServices->supportsService("com.sun.star.text.TextDocument");
+ if(bSpecModeWriter)
+ {
+ Reference<container::XNameAccess> xParaStyles;
+ xStylesSupplier->getStyleFamilies()->getByName("ParagraphStyles") >>=
+ xParaStyles;
+ static const std::vector<OUString> aWriterStyles =
+ {
+ "Standard",
+ "Text body",
+ "Title",
+ "Subtitle",
+ "Heading 1",
+ "Heading 2",
+ "Heading 3",
+ "Heading 4",
+ "Quotations",
+ "Preformatted Text"
+ };
+ for( const OUString& aStyle: aWriterStyles )
+ {
+ try
+ {
+ Reference< beans::XPropertySet > xStyle;
+ xParaStyles->getByName( aStyle ) >>= xStyle;
+ OUString sName;
+ xStyle->getPropertyValue("DisplayName") >>= sName;
+ if( !sName.isEmpty() )
+ aDefaultStyles.push_back(
+ std::pair<OUString, OUString>(aStyle, sName) );
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+
+ }
+ else if( (
+ bSpecModeCalc = xServices->supportsService(
+ "com.sun.star.sheet.SpreadsheetDocument")))
+ {
+ static const char* aCalcStyles[] =
+ {
+ "Default",
+ "Accent 1",
+ "Accent 2",
+ "Accent 3",
+ "Heading 1",
+ "Heading 2",
+ "Result"
+ };
+ Reference<container::XNameAccess> xCellStyles;
+ xStylesSupplier->getStyleFamilies()->getByName("CellStyles") >>= xCellStyles;
+ for(const char* pCalcStyle : aCalcStyles)
+ {
+ try
+ {
+ const OUString sStyleName( OUString::createFromAscii( pCalcStyle ) );
+ if( xCellStyles->hasByName( sStyleName ) )
+ {
+ Reference< beans::XPropertySet > xStyle( xCellStyles->getByName( sStyleName), UNO_QUERY_THROW );
+ OUString sName;
+ xStyle->getPropertyValue("DisplayName") >>= sName;
+ if( !sName.isEmpty() )
+ aDefaultStyles.push_back(
+ std::pair<OUString, OUString>(sStyleName, sName) );
+ }
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+ }
+ }
+ catch(const uno::Exception& )
+ {
+ OSL_FAIL("error while initializing style names");
+ }
+ }
+};
+
+// mapping table from bound items. BE CAREFUL this table must be in the
+// same order as the uno commands bound to the slots SID_STYLE_FAMILY1..n
+// MAX_FAMILIES must also be correctly set!
+static const char* StyleSlotToStyleCommand[MAX_FAMILIES] =
+{
+ ".uno:CharStyle",
+ ".uno:ParaStyle",
+ ".uno:FrameStyle",
+ ".uno:PageStyle",
+ ".uno:TemplateFamily5"
+};
+
+SvxStyleToolBoxControl::SvxStyleToolBoxControl()
+ : pImpl(new Impl)
+ , pStyleSheetPool(nullptr)
+ , nActFamily(0xffff)
+{
+ for (sal_uInt16 i = 0; i < MAX_FAMILIES; ++i)
+ {
+ m_xBoundItems[i].clear();
+ pFamilyState[i] = nullptr;
+ }
+}
+
+SvxStyleToolBoxControl::~SvxStyleToolBoxControl()
+{
+}
+
+void SAL_CALL SvxStyleToolBoxControl::initialize(const Sequence<Any>& rArguments)
+{
+ svt::ToolboxController::initialize(rArguments);
+
+ // After initialize we should have a valid frame member where we can retrieve our
+ // dispatch provider.
+ if ( !m_xFrame.is() )
+ return;
+
+ pImpl->InitializeStyles(m_xFrame->getController()->getModel());
+ Reference< XDispatchProvider > xDispatchProvider( m_xFrame->getController(), UNO_QUERY );
+ for ( sal_uInt16 i=0; i<MAX_FAMILIES; i++ )
+ {
+ m_xBoundItems[i] = new SfxStyleControllerItem_Impl( xDispatchProvider,
+ SID_STYLE_FAMILY_START + i,
+ OUString::createFromAscii( StyleSlotToStyleCommand[i] ),
+ *this );
+ pFamilyState[i] = nullptr;
+ }
+}
+
+// XComponent
+void SAL_CALL SvxStyleToolBoxControl::dispose()
+{
+ svt::ToolboxController::dispose();
+
+ SolarMutexGuard aSolarMutexGuard;
+ pImpl->m_xVclBox.disposeAndClear();
+ pImpl->m_xWeldBox.reset();
+ pImpl->m_pBox = nullptr;
+
+ for (rtl::Reference<SfxStyleControllerItem_Impl>& pBoundItem : m_xBoundItems)
+ {
+ if (!pBoundItem)
+ continue;
+ pBoundItem->UnBind();
+ }
+ unbindListener();
+
+ for( sal_uInt16 i=0; i<MAX_FAMILIES; i++ )
+ {
+ if ( m_xBoundItems[i].is() )
+ {
+ try
+ {
+ m_xBoundItems[i]->dispose();
+ }
+ catch ( Exception& )
+ {
+ }
+
+ m_xBoundItems[i].clear();
+ }
+ pFamilyState[i].reset();
+ }
+ pStyleSheetPool = nullptr;
+ pImpl.reset();
+}
+
+OUString SvxStyleToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.StyleToolBoxControl";
+}
+
+sal_Bool SvxStyleToolBoxControl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService( this, rServiceName );
+}
+
+css::uno::Sequence< OUString > SvxStyleToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_StyleToolBoxControl_get_implementation(
+ css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxStyleToolBoxControl() );
+}
+
+void SAL_CALL SvxStyleToolBoxControl::update()
+{
+ for (rtl::Reference<SfxStyleControllerItem_Impl>& pBoundItem : m_xBoundItems)
+ pBoundItem->ReBind();
+ bindListener();
+}
+
+SfxStyleFamily SvxStyleToolBoxControl::GetActFamily() const
+{
+ switch ( nActFamily-1 + SID_STYLE_FAMILY_START )
+ {
+ case SID_STYLE_FAMILY1: return SfxStyleFamily::Char;
+ case SID_STYLE_FAMILY2: return SfxStyleFamily::Para;
+ case SID_STYLE_FAMILY3: return SfxStyleFamily::Frame;
+ case SID_STYLE_FAMILY4: return SfxStyleFamily::Page;
+ case SID_STYLE_FAMILY5: return SfxStyleFamily::Pseudo;
+ default:
+ OSL_FAIL( "unknown style family" );
+ break;
+ }
+ return SfxStyleFamily::Para;
+}
+
+void SvxStyleToolBoxControl::FillStyleBox()
+{
+ SvxStyleBox_Base* pBox = pImpl->m_pBox;
+
+ DBG_ASSERT( pStyleSheetPool, "StyleSheetPool not found!" );
+ DBG_ASSERT( pBox, "Control not found!" );
+
+ if ( !(pStyleSheetPool && pBox && nActFamily!=0xffff) )
+ return;
+
+ const SfxStyleFamily eFamily = GetActFamily();
+ SfxStyleSheetBase* pStyle = nullptr;
+ bool bDoFill = false;
+
+ auto xIter = pStyleSheetPool->CreateIterator(eFamily, SfxStyleSearchBits::Used);
+ sal_uInt16 nCount = xIter->Count();
+
+ // Check whether fill is necessary
+ pStyle = xIter->First();
+ //!!! TODO: This condition isn't right any longer, because we always show some default entries
+ //!!! so the list doesn't show the count
+ if ( nCount != pBox->get_count() )
+ {
+ bDoFill = true;
+ }
+ else
+ {
+ sal_uInt16 i= 0;
+ while ( pStyle && !bDoFill )
+ {
+ bDoFill = ( pBox->get_text(i) != pStyle->GetName() );
+ pStyle = xIter->Next();
+ i++;
+ }
+ }
+
+ if ( !bDoFill )
+ return;
+
+ OUString aStrSel(pBox->get_active_text());
+ pBox->freeze();
+ pBox->clear();
+
+ std::vector<OUString> aStyles;
+
+ {
+ pStyle = xIter->Next();
+
+ if( pImpl->bSpecModeWriter || pImpl->bSpecModeCalc )
+ {
+ while ( pStyle )
+ {
+ // sort out default styles
+ bool bInsert = true;
+ OUString aName( pStyle->GetName() );
+ for( auto const & _i: pImpl->aDefaultStyles )
+ {
+ if( _i.first == aName || _i.second == aName )
+ {
+ bInsert = false;
+ break;
+ }
+ }
+
+ if( bInsert )
+ aStyles.push_back(aName);
+ pStyle = xIter->Next();
+ }
+ }
+ else
+ {
+ while ( pStyle )
+ {
+ aStyles.push_back(pStyle->GetName());
+ pStyle = xIter->Next();
+ }
+ }
+ }
+
+ if (pImpl->bSpecModeWriter || pImpl->bSpecModeCalc)
+ {
+ pBox->append_text(pImpl->aClearForm);
+ pBox->insert_separator(1, "separator");
+
+ // insert default styles
+ for (const auto &rStyle : pImpl->aDefaultStyles)
+ pBox->append_text(rStyle.second);
+ }
+
+ std::sort(aStyles.begin(), aStyles.end());
+
+ for (const auto& rStyle : aStyles)
+ pBox->append_text(rStyle);
+
+ if ((pImpl->bSpecModeWriter || pImpl->bSpecModeCalc) && !comphelper::LibreOfficeKit::isActive())
+ pBox->append_text(pImpl->aMore);
+
+ pBox->thaw();
+ pBox->set_active_or_entry_text(aStrSel);
+ pBox->SetFamily( eFamily );
+}
+
+void SvxStyleToolBoxControl::SelectStyle( const OUString& rStyleName )
+{
+ SvxStyleBox_Base* pBox = pImpl->m_pBox;
+ DBG_ASSERT( pBox, "Control not found!" );
+
+ if ( !pBox )
+ return;
+
+ OUString aStrSel(pBox->get_active_text());
+
+ if ( !rStyleName.isEmpty() )
+ {
+ OUString aNewStyle = rStyleName;
+
+ auto aFound = std::find_if(pImpl->aDefaultStyles.begin(), pImpl->aDefaultStyles.end(),
+ [rStyleName] (auto it) { return it.first == rStyleName || it.second == rStyleName; }
+ );
+
+ if (aFound != pImpl->aDefaultStyles.end())
+ aNewStyle = aFound->second;
+
+ if ( aNewStyle != aStrSel )
+ pBox->set_active_or_entry_text( aNewStyle );
+ }
+ else
+ pBox->set_active(-1);
+ pBox->save_value();
+}
+
+void SvxStyleToolBoxControl::Update()
+{
+ SfxStyleSheetBasePool* pPool = nullptr;
+ SfxObjectShell* pDocShell = SfxObjectShell::Current();
+
+ if ( pDocShell )
+ pPool = pDocShell->GetStyleSheetPool();
+
+ sal_uInt16 i;
+ for ( i=0; i<MAX_FAMILIES; i++ )
+ if( pFamilyState[i] )
+ break;
+
+ if ( i==MAX_FAMILIES || !pPool )
+ {
+ pStyleSheetPool = pPool;
+ return;
+ }
+
+
+ const SfxTemplateItem* pItem = nullptr;
+
+ if ( nActFamily == 0xffff || nullptr == (pItem = pFamilyState[nActFamily-1].get()) )
+ // Current range not within allowed ranges or default
+ {
+ pStyleSheetPool = pPool;
+ nActFamily = 2;
+
+ pItem = pFamilyState[nActFamily-1].get();
+ if ( !pItem )
+ {
+ nActFamily++;
+ pItem = pFamilyState[nActFamily-1].get();
+ }
+ }
+ else if ( pPool != pStyleSheetPool )
+ pStyleSheetPool = pPool;
+
+ FillStyleBox(); // Decides by itself whether Fill is needed
+
+ if ( pItem )
+ SelectStyle( pItem->GetStyleName() );
+}
+
+void SvxStyleToolBoxControl::SetFamilyState( sal_uInt16 nIdx,
+ const SfxTemplateItem* pItem )
+{
+ pFamilyState[nIdx].reset( pItem == nullptr ? nullptr : new SfxTemplateItem( *pItem ) );
+ Update();
+}
+
+void SvxStyleToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+
+ if (m_pToolbar)
+ m_pToolbar->set_item_sensitive(m_aCommandURL.toUtf8(), rEvent.IsEnabled);
+ else
+ {
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId( nId, &pToolBox ) )
+ return;
+ pToolBox->EnableItem( nId, rEvent.IsEnabled );
+ }
+
+ if (rEvent.IsEnabled)
+ Update();
+}
+
+css::uno::Reference<css::awt::XWindow> SvxStyleToolBoxControl::createItemWindow(const css::uno::Reference< css::awt::XWindow>& rParent)
+{
+ uno::Reference< awt::XWindow > xItemWindow;
+
+ if (m_pBuilder)
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("applystyle"));
+
+ xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get()));
+
+ pImpl->m_xWeldBox.reset(new SvxStyleBox_Base(std::move(xWidget),
+ ".uno:StyleApply",
+ SfxStyleFamily::Para,
+ Reference< XDispatchProvider >( m_xFrame->getController(), UNO_QUERY ),
+ m_xFrame,
+ pImpl->aClearForm,
+ pImpl->aMore,
+ pImpl->bSpecModeWriter || pImpl->bSpecModeCalc, *this));
+ pImpl->m_pBox = pImpl->m_xWeldBox.get();
+ }
+ else
+ {
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent);
+ if ( pParent )
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ pImpl->m_xVclBox = VclPtr<SvxStyleBox_Impl>::Create(pParent,
+ ".uno:StyleApply",
+ SfxStyleFamily::Para,
+ Reference< XDispatchProvider >( m_xFrame->getController(), UNO_QUERY ),
+ m_xFrame,
+ pImpl->aClearForm,
+ pImpl->aMore,
+ pImpl->bSpecModeWriter || pImpl->bSpecModeCalc, *this);
+ pImpl->m_pBox = pImpl->m_xVclBox.get();
+ xItemWindow = VCLUnoHelper::GetInterface(pImpl->m_xVclBox);
+ }
+ }
+
+ if (pImpl->m_pBox && !pImpl->aDefaultStyles.empty())
+ pImpl->m_pBox->SetDefaultStyle(pImpl->aDefaultStyles[0].second);
+
+ return xItemWindow;
+}
+
+SvxFontNameToolBoxControl::SvxFontNameToolBoxControl()
+ : m_pBox(nullptr)
+{
+}
+
+void SvxFontNameBox_Base::statusChanged_Impl( const css::frame::FeatureStateEvent& rEvent )
+{
+ if ( !rEvent.IsEnabled )
+ {
+ set_sensitive(false);
+ Update( nullptr );
+ }
+ else
+ {
+ set_sensitive(true);
+
+ css::awt::FontDescriptor aFontDesc;
+ if ( rEvent.State >>= aFontDesc )
+ Update(&aFontDesc);
+ else {
+ // no active element; delete value in the display
+ m_xWidget->set_active(-1);
+ set_active_or_entry_text("");
+ }
+ m_xWidget->save_value();
+ }
+}
+
+void SvxFontNameToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+ m_pBox->statusChanged_Impl(rEvent);
+
+ if (m_pToolbar)
+ m_pToolbar->set_item_sensitive(m_aCommandURL.toUtf8(), rEvent.IsEnabled);
+ else
+ {
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId( nId, &pToolBox ) )
+ return;
+ pToolBox->EnableItem( nId, rEvent.IsEnabled );
+ }
+}
+
+css::uno::Reference<css::awt::XWindow> SvxFontNameToolBoxControl::createItemWindow(const css::uno::Reference<css::awt::XWindow>& rParent)
+{
+ uno::Reference< awt::XWindow > xItemWindow;
+
+ if (m_pBuilder)
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("fontnamecombobox"));
+
+ xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get()));
+
+ m_xWeldBox.reset(new SvxFontNameBox_Base(std::move(xWidget),
+ Reference<XDispatchProvider>(m_xFrame->getController(), UNO_QUERY),
+ m_xFrame, *this));
+ m_pBox = m_xWeldBox.get();
+ }
+ else
+ {
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(rParent);
+ if ( pParent )
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ m_xVclBox = VclPtr<SvxFontNameBox_Impl>::Create(pParent,
+ Reference<XDispatchProvider>(m_xFrame->getController(), UNO_QUERY),
+ m_xFrame, *this);
+ m_pBox = m_xVclBox.get();
+ xItemWindow = VCLUnoHelper::GetInterface(m_xVclBox);
+ }
+ }
+
+ return xItemWindow;
+}
+
+void SvxFontNameToolBoxControl::dispose()
+{
+ ToolboxController::dispose();
+
+ SolarMutexGuard aSolarMutexGuard;
+ m_xVclBox.disposeAndClear();
+ m_xWeldBox.reset();
+ m_pBox = nullptr;
+}
+
+OUString SvxFontNameToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.FontNameToolBoxControl";
+}
+
+sal_Bool SvxFontNameToolBoxControl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService( this, rServiceName );
+}
+
+css::uno::Sequence< OUString > SvxFontNameToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_FontNameToolBoxControl_get_implementation(
+ css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxFontNameToolBoxControl() );
+}
+
+SvxColorToolBoxControl::SvxColorToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) :
+ ImplInheritanceHelper( rContext, nullptr, OUString() ),
+ m_bSplitButton(true),
+ m_nSlotId(0),
+ m_aColorSelectFunction(PaletteManager::DispatchColorCommand)
+{
+}
+
+namespace {
+
+sal_uInt16 MapCommandToSlotId(const OUString& rCommand)
+{
+ if (rCommand == ".uno:Color")
+ return SID_ATTR_CHAR_COLOR;
+ else if (rCommand == ".uno:FontColor")
+ return SID_ATTR_CHAR_COLOR2;
+ else if (rCommand == ".uno:BackColor")
+ return SID_ATTR_CHAR_COLOR_BACKGROUND;
+ else if (rCommand == ".uno:CharBackColor")
+ return SID_ATTR_CHAR_BACK_COLOR;
+ else if (rCommand == ".uno:BackgroundColor")
+ return SID_BACKGROUND_COLOR;
+ else if (rCommand == ".uno:TableCellBackgroundColor")
+ return SID_TABLE_CELL_BACKGROUND_COLOR;
+ else if (rCommand == ".uno:Extrusion3DColor")
+ return SID_EXTRUSION_3D_COLOR;
+ else if (rCommand == ".uno:XLineColor")
+ return SID_ATTR_LINE_COLOR;
+ else if (rCommand == ".uno:FillColor")
+ return SID_ATTR_FILL_COLOR;
+ else if (rCommand == ".uno:FrameLineColor")
+ return SID_FRAME_LINECOLOR;
+
+ SAL_WARN("svx.tbxcrtls", "Unknown color command: " << rCommand);
+ return 0;
+}
+
+}
+
+void SvxColorToolBoxControl::initialize( const css::uno::Sequence<css::uno::Any>& rArguments )
+{
+ PopupWindowController::initialize( rArguments );
+
+ m_nSlotId = MapCommandToSlotId( m_aCommandURL );
+
+ if ( m_nSlotId == SID_ATTR_LINE_COLOR || m_nSlotId == SID_ATTR_FILL_COLOR ||
+ m_nSlotId == SID_FRAME_LINECOLOR || m_nSlotId == SID_BACKGROUND_COLOR )
+ {
+ // Sidebar uses wide buttons for those.
+ m_bSplitButton = !m_bSidebar;
+ }
+
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(getCommandURL(), getModuleName());
+ OUString aCommandLabel = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
+
+ OString aId(m_aCommandURL.toUtf8());
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(aId, mxPopoverContainer->getTopLevel());
+ m_xBtnUpdater.reset(new svx::ToolboxButtonColorUpdater(m_nSlotId, aId, m_pToolbar, !m_bSplitButton, aCommandLabel, m_xFrame));
+ return;
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ {
+ m_xBtnUpdater.reset( new svx::VclToolboxButtonColorUpdater( m_nSlotId, nId, pToolBox, !m_bSplitButton, aCommandLabel, m_aCommandURL, m_xFrame ) );
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ( m_bSplitButton ? ToolBoxItemBits::DROPDOWN : ToolBoxItemBits::DROPDOWNONLY ) );
+ }
+}
+
+void SvxColorToolBoxControl::update()
+{
+ PopupWindowController::update();
+
+ switch( m_nSlotId )
+ {
+ case SID_ATTR_CHAR_COLOR2:
+ addStatusListener( ".uno:CharColorExt");
+ break;
+
+ case SID_ATTR_CHAR_COLOR_BACKGROUND:
+ addStatusListener( ".uno:CharBackgroundExt");
+ break;
+
+ case SID_FRAME_LINECOLOR:
+ addStatusListener( ".uno:BorderTLBR");
+ addStatusListener( ".uno:BorderBLTR");
+ break;
+ }
+}
+
+void SvxColorToolBoxControl::EnsurePaletteManager()
+{
+ if (!m_xPaletteManager)
+ {
+ m_xPaletteManager = std::make_shared<PaletteManager>();
+ m_xPaletteManager->SetBtnUpdater(m_xBtnUpdater.get());
+ }
+}
+
+SvxColorToolBoxControl::~SvxColorToolBoxControl()
+{
+ if (m_xPaletteManager)
+ m_xPaletteManager->SetBtnUpdater(nullptr);
+}
+
+void SvxColorToolBoxControl::setColorSelectFunction(const ColorSelectFunction& aColorSelectFunction)
+{
+ m_aColorSelectFunction = aColorSelectFunction;
+ if (m_xPaletteManager)
+ m_xPaletteManager->SetColorSelectFunction(aColorSelectFunction);
+}
+
+weld::Window* SvxColorToolBoxControl::GetParentFrame() const
+{
+ const css::uno::Reference<css::awt::XWindow> xParent = m_xFrame->getContainerWindow();
+ return Application::GetFrameWeld(xParent);
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxColorToolBoxControl::weldPopupWindow()
+{
+ EnsurePaletteManager();
+
+ const OString aId(m_aCommandURL.toUtf8());
+
+ auto xPopover = std::make_unique<ColorWindow>(
+ m_aCommandURL,
+ m_xPaletteManager,
+ m_aColorStatus,
+ m_nSlotId,
+ m_xFrame,
+ MenuOrToolMenuButton(m_pToolbar, aId),
+ [this] { return GetParentFrame(); },
+ m_aColorSelectFunction);
+
+ if ( m_bSplitButton )
+ xPopover->SetSelectedHdl( LINK( this, SvxColorToolBoxControl, SelectedHdl ) );
+
+ return xPopover;
+}
+
+VclPtr<vcl::Window> SvxColorToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId(nId, &pToolBox))
+ return nullptr;
+
+ EnsurePaletteManager();
+
+ auto xPopover = std::make_unique<ColorWindow>(
+ m_aCommandURL,
+ m_xPaletteManager,
+ m_aColorStatus,
+ m_nSlotId,
+ m_xFrame,
+ MenuOrToolMenuButton(this, pToolBox, nId),
+ [this] { return GetParentFrame(); },
+ m_aColorSelectFunction);
+
+ if ( m_bSplitButton )
+ xPopover->SetSelectedHdl( LINK( this, SvxColorToolBoxControl, SelectedHdl ) );
+
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::move(xPopover), true);
+
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(m_aCommandURL, m_sModuleName);
+ OUString aWindowTitle = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
+ mxInterimPopover->SetText(aWindowTitle);
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+IMPL_LINK(SvxColorToolBoxControl, SelectedHdl, const NamedColor&, rColor, void)
+{
+ m_xBtnUpdater->Update(rColor);
+}
+
+void SvxColorToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (!getToolboxId(nId, &pToolBox) && !m_pToolbar)
+ return;
+
+ if ( rEvent.FeatureURL.Complete == m_aCommandURL )
+ {
+ if (m_pToolbar)
+ m_pToolbar->set_item_sensitive(m_aCommandURL.toUtf8(), rEvent.IsEnabled);
+ else
+ pToolBox->EnableItem( nId, rEvent.IsEnabled );
+ }
+
+ bool bValue;
+ if ( !m_bSplitButton )
+ {
+ m_aColorStatus.statusChanged( rEvent );
+ m_xBtnUpdater->Update( m_aColorStatus.GetColor() );
+ }
+ else if ( rEvent.State >>= bValue )
+ {
+ if (m_pToolbar)
+ m_pToolbar->set_item_active(m_aCommandURL.toUtf8(), bValue);
+ else if (pToolBox)
+ pToolBox->CheckItem( nId, bValue );
+ }
+}
+
+void SvxColorToolBoxControl::execute(sal_Int16 /*nSelectModifier*/)
+{
+ if ( !m_bSplitButton )
+ {
+ if (m_pToolbar)
+ {
+ // Toggle the popup also when toolbutton is activated
+ const OString aId(m_aCommandURL.toUtf8());
+ m_pToolbar->set_menu_item_active(aId, !m_pToolbar->get_menu_item_active(aId));
+ }
+ else
+ {
+ // Open the popup also when Enter key is pressed.
+ createPopupWindow();
+ }
+ return;
+ }
+
+ OUString aCommand = m_aCommandURL;
+ Color aColor = m_xBtnUpdater->GetCurrentColor();
+
+ switch( m_nSlotId )
+ {
+ case SID_ATTR_CHAR_COLOR2 :
+ aCommand = ".uno:CharColorExt";
+ break;
+
+ case SID_ATTR_CHAR_COLOR_BACKGROUND :
+ aCommand = ".uno:CharBackgroundExt";
+ break;
+ }
+
+ auto aArgs( comphelper::InitPropertySequence( {
+ { m_aCommandURL.copy(5), css::uno::Any(aColor) }
+ } ) );
+ dispatchCommand( aCommand, aArgs );
+
+ EnsurePaletteManager();
+ OUString sColorName = m_xBtnUpdater->GetCurrentColorName();
+ m_xPaletteManager->AddRecentColor(aColor, sColorName);
+}
+
+sal_Bool SvxColorToolBoxControl::opensSubToolbar()
+{
+ // We mark this controller as a sub-toolbar controller, so we get notified
+ // (through updateImage method) on button image changes, and could redraw
+ // the last used color on top of it.
+ return true;
+}
+
+void SvxColorToolBoxControl::updateImage()
+{
+ m_xBtnUpdater->Update(m_xBtnUpdater->GetCurrentColor(), true);
+}
+
+OUString SvxColorToolBoxControl::getSubToolbarName()
+{
+ return OUString();
+}
+
+void SvxColorToolBoxControl::functionSelected( const OUString& /*rCommand*/ )
+{
+}
+
+OUString SvxColorToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.ColorToolBoxControl";
+}
+
+css::uno::Sequence<OUString> SvxColorToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_ColorToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxColorToolBoxControl( rContext ) );
+}
+
+SvxFrameToolBoxControl::SvxFrameToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rContext )
+ : svt::PopupWindowController( rContext, nullptr, OUString() )
+{
+}
+
+void SAL_CALL SvxFrameToolBoxControl::execute(sal_Int16 /*KeyModifier*/)
+{
+ if (m_pToolbar)
+ {
+ // Toggle the popup also when toolbutton is activated
+ const OString aId(m_aCommandURL.toUtf8());
+ m_pToolbar->set_menu_item_active(aId, !m_pToolbar->get_menu_item_active(aId));
+ }
+ else
+ {
+ // Open the popup also when Enter key is pressed.
+ createPopupWindow();
+ }
+}
+
+void SvxFrameToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
+{
+ svt::PopupWindowController::initialize( rArguments );
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxFrameToolBoxControl::weldPopupWindow()
+{
+ if ( m_aCommandURL == ".uno:LineStyle" )
+ return std::make_unique<SvxLineWindow_Impl>(this, m_pToolbar);
+ return std::make_unique<SvxFrameWindow_Impl>(this, m_pToolbar);
+}
+
+VclPtr<vcl::Window> SvxFrameToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ if ( m_aCommandURL == ".uno:LineStyle" )
+ {
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<SvxLineWindow_Impl>(this, pParent->GetFrameWeld()), true);
+
+ mxInterimPopover->Show();
+
+ mxInterimPopover->SetText(SvxResId(RID_SVXSTR_FRAME_STYLE));
+
+ return mxInterimPopover;
+ }
+
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<SvxFrameWindow_Impl>(this, pParent->GetFrameWeld()), true);
+
+ mxInterimPopover->Show();
+
+ mxInterimPopover->SetText(SvxResId(RID_SVXSTR_FRAME));
+
+ return mxInterimPopover;
+}
+
+OUString SvxFrameToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.FrameToolBoxControl";
+}
+
+css::uno::Sequence< OUString > SvxFrameToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_FrameToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxFrameToolBoxControl( rContext ) );
+}
+
+SvxCurrencyToolBoxControl::SvxCurrencyToolBoxControl( const css::uno::Reference<css::uno::XComponentContext>& rContext ) :
+ PopupWindowController( rContext, nullptr, OUString() ),
+ m_eLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ),
+ m_nFormatKey( NUMBERFORMAT_ENTRY_NOT_FOUND )
+{
+}
+
+SvxCurrencyToolBoxControl::~SvxCurrencyToolBoxControl() {}
+
+namespace
+{
+ class SvxCurrencyList_Impl : public WeldToolbarPopup
+ {
+ private:
+ rtl::Reference<SvxCurrencyToolBoxControl> m_xControl;
+ std::unique_ptr<weld::Label> m_xLabel;
+ std::unique_ptr<weld::TreeView> m_xCurrencyLb;
+ std::unique_ptr<weld::Button> m_xOkBtn;
+ OUString& m_rSelectedFormat;
+ LanguageType& m_eSelectedLanguage;
+
+ std::vector<OUString> m_aFormatEntries;
+ LanguageType m_eFormatLanguage;
+ DECL_LINK(RowActivatedHdl, weld::TreeView&, bool);
+ DECL_LINK(OKHdl, weld::Button&, void);
+
+ virtual void GrabFocus() override;
+
+ public:
+ SvxCurrencyList_Impl(SvxCurrencyToolBoxControl* pControl, weld::Widget* pParent, OUString& rSelectedFormat, LanguageType& eSelectedLanguage)
+ : WeldToolbarPopup(pControl->getFrameInterface(), pParent, "svx/ui/currencywindow.ui", "CurrencyWindow")
+ , m_xControl(pControl)
+ , m_xLabel(m_xBuilder->weld_label("label"))
+ , m_xCurrencyLb(m_xBuilder->weld_tree_view("currency"))
+ , m_xOkBtn(m_xBuilder->weld_button("ok"))
+ , m_rSelectedFormat(rSelectedFormat)
+ , m_eSelectedLanguage(eSelectedLanguage)
+ {
+ std::vector< OUString > aList;
+ std::vector< sal_uInt16 > aCurrencyList;
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+ sal_uInt16 nLen = rCurrencyTable.size();
+
+ SvNumberFormatter aFormatter( m_xControl->getContext(), LANGUAGE_SYSTEM );
+ m_eFormatLanguage = aFormatter.GetLanguage();
+
+ SvxCurrencyToolBoxControl::GetCurrencySymbols( aList, true, aCurrencyList );
+
+ sal_uInt16 nPos = 0, nCount = 0;
+ sal_Int32 nSelectedPos = -1;
+ bool bIsSymbol;
+ NfWSStringsDtor aStringsDtor;
+
+ OUString sLongestString;
+
+ m_xCurrencyLb->freeze();
+ for( const auto& rItem : aList )
+ {
+ sal_uInt16& rCurrencyIndex = aCurrencyList[ nCount ];
+ if ( rCurrencyIndex < nLen )
+ {
+ m_xCurrencyLb->append_text(rItem);
+
+ if (rItem.getLength() > sLongestString.getLength())
+ sLongestString = rItem;
+
+ bIsSymbol = nPos >= nLen;
+
+ sal_uInt16 nDefaultFormat;
+ const NfCurrencyEntry& rCurrencyEntry = rCurrencyTable[ rCurrencyIndex ];
+ if (rCurrencyIndex == 0)
+ {
+ // Stored with system locale, but we want the resolved
+ // full LCID format string. For example
+ // "[$$-409]#,##0.00" instead of "[$$]#,##0.00".
+ NfCurrencyEntry aCurrencyEntry( rCurrencyEntry);
+ aCurrencyEntry.SetLanguage( LanguageTag( aCurrencyEntry.GetLanguage()).getLanguageType());
+ nDefaultFormat = aFormatter.GetCurrencyFormatStrings( aStringsDtor, aCurrencyEntry, bIsSymbol);
+ }
+ else
+ {
+ nDefaultFormat = aFormatter.GetCurrencyFormatStrings( aStringsDtor, rCurrencyEntry, bIsSymbol);
+ }
+ const OUString& rFormatStr = aStringsDtor[ nDefaultFormat ];
+ m_aFormatEntries.push_back( rFormatStr );
+ if( rFormatStr == m_rSelectedFormat )
+ nSelectedPos = nPos;
+ ++nPos;
+ }
+ ++nCount;
+ }
+ m_xCurrencyLb->thaw();
+ // enable multiple selection enabled so we can start with nothing selected
+ m_xCurrencyLb->set_selection_mode(SelectionMode::Multiple);
+ m_xCurrencyLb->connect_row_activated( LINK( this, SvxCurrencyList_Impl, RowActivatedHdl ) );
+ m_xLabel->set_label(SvxResId(RID_SVXSTR_TBLAFMT_CURRENCY));
+ m_xCurrencyLb->select( nSelectedPos );
+ m_xOkBtn->connect_clicked(LINK(this, SvxCurrencyList_Impl, OKHdl));
+
+ // gtk will initially make a best guess depending on the first few entries, so copy the probable
+ // longest entry to the start temporarily and force in the width at this point
+ m_xCurrencyLb->insert_text(0, sLongestString);
+ m_xCurrencyLb->set_size_request(m_xCurrencyLb->get_preferred_size().Width(), m_xCurrencyLb->get_height_rows(12));
+ m_xCurrencyLb->remove(0);
+ }
+ };
+
+ void SvxCurrencyList_Impl::GrabFocus()
+ {
+ m_xCurrencyLb->grab_focus();
+ }
+
+ IMPL_LINK_NOARG(SvxCurrencyList_Impl, OKHdl, weld::Button&, void)
+ {
+ RowActivatedHdl(*m_xCurrencyLb);
+ }
+
+ IMPL_LINK_NOARG(SvxCurrencyList_Impl, RowActivatedHdl, weld::TreeView&, bool)
+ {
+ if (!m_xControl.is())
+ return true;
+
+ // multiple selection enabled so we can start with nothing selected,
+ // so force single selection after something is picked
+ int nSelected = m_xCurrencyLb->get_selected_index();
+ if (nSelected == -1)
+ return true;
+
+ m_xCurrencyLb->set_selection_mode(SelectionMode::Single);
+
+ m_rSelectedFormat = m_aFormatEntries[nSelected];
+ m_eSelectedLanguage = m_eFormatLanguage;
+
+ m_xControl->execute(nSelected + 1);
+
+ m_xControl->EndPopupMode();
+
+ return true;
+ }
+}
+
+void SvxCurrencyToolBoxControl::initialize( const css::uno::Sequence< css::uno::Any >& rArguments )
+{
+ PopupWindowController::initialize(rArguments);
+
+ if (m_pToolbar)
+ {
+ mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
+ m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
+ return;
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox) && pToolBox->GetItemCommand(nId) == m_aCommandURL)
+ pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWN | pToolBox->GetItemBits(nId));
+}
+
+std::unique_ptr<WeldToolbarPopup> SvxCurrencyToolBoxControl::weldPopupWindow()
+{
+ return std::make_unique<SvxCurrencyList_Impl>(this, m_pToolbar, m_aFormatString, m_eLanguage);
+}
+
+VclPtr<vcl::Window> SvxCurrencyToolBoxControl::createVclPopupWindow( vcl::Window* pParent )
+{
+ mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
+ std::make_unique<SvxCurrencyList_Impl>(this, pParent->GetFrameWeld(), m_aFormatString, m_eLanguage));
+
+ mxInterimPopover->Show();
+
+ return mxInterimPopover;
+}
+
+void SvxCurrencyToolBoxControl::execute( sal_Int16 nSelectModifier )
+{
+ sal_uInt32 nFormatKey;
+ if (m_aFormatString.isEmpty())
+ nFormatKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
+ else
+ {
+ if ( nSelectModifier > 0 )
+ {
+ try
+ {
+ uno::Reference< util::XNumberFormatsSupplier > xRef( m_xFrame->getController()->getModel(), uno::UNO_QUERY );
+ uno::Reference< util::XNumberFormats > rxNumberFormats( xRef->getNumberFormats(), uno::UNO_SET_THROW );
+ css::lang::Locale aLocale = LanguageTag::convertToLocale( m_eLanguage );
+ nFormatKey = rxNumberFormats->queryKey( m_aFormatString, aLocale, false );
+ if ( nFormatKey == NUMBERFORMAT_ENTRY_NOT_FOUND )
+ nFormatKey = rxNumberFormats->addNew( m_aFormatString, aLocale );
+ }
+ catch( const uno::Exception& )
+ {
+ nFormatKey = m_nFormatKey;
+ }
+ }
+ else
+ nFormatKey = m_nFormatKey;
+ }
+
+ if( nFormatKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
+ {
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("NumberFormatCurrency",
+ nFormatKey) };
+ dispatchCommand( m_aCommandURL, aArgs );
+ m_nFormatKey = nFormatKey;
+ }
+ else
+ PopupWindowController::execute( nSelectModifier );
+}
+
+OUString SvxCurrencyToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.CurrencyToolBoxControl";
+}
+
+css::uno::Sequence<OUString> SvxCurrencyToolBoxControl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_CurrencyToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const & )
+{
+ return cppu::acquire( new SvxCurrencyToolBoxControl( rContext ) );
+}
+
+Reference< css::accessibility::XAccessible > SvxFontNameBox_Impl::CreateAccessible()
+{
+ FillList();
+ return InterimItemWindow::CreateAccessible();
+}
+
+//static
+void SvxCurrencyToolBoxControl::GetCurrencySymbols( std::vector<OUString>& rList, bool bFlag,
+ std::vector<sal_uInt16>& rCurrencyList )
+{
+ rCurrencyList.clear();
+
+ const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
+ sal_uInt16 nCount = rCurrencyTable.size();
+
+ sal_uInt16 nStart = 1;
+
+ OUString aString( ApplyLreOrRleEmbedding( rCurrencyTable[0].GetSymbol() ) + " " );
+ aString += ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString(
+ rCurrencyTable[0].GetLanguage() ) );
+
+ rList.push_back( aString );
+ rCurrencyList.push_back( sal_uInt16(-1) ); // nAuto
+
+ if( bFlag )
+ {
+ rList.push_back( aString );
+ rCurrencyList.push_back( 0 );
+ ++nStart;
+ }
+
+ CollatorWrapper aCollator( ::comphelper::getProcessComponentContext() );
+ aCollator.loadDefaultCollator( Application::GetSettings().GetLanguageTag().getLocale(), 0 );
+
+ static const OUStringLiteral aTwoSpace(u" ");
+
+ for( sal_uInt16 i = 1; i < nCount; ++i )
+ {
+ OUString aStr( ApplyLreOrRleEmbedding( rCurrencyTable[i].GetBankSymbol() ) );
+ aStr += aTwoSpace;
+ aStr += ApplyLreOrRleEmbedding( rCurrencyTable[i].GetSymbol() );
+ aStr += aTwoSpace;
+ aStr += ApplyLreOrRleEmbedding( SvtLanguageTable::GetLanguageString(
+ rCurrencyTable[i].GetLanguage() ) );
+
+ std::vector<OUString>::size_type j = nStart;
+ for( ; j < rList.size(); ++j )
+ if ( aCollator.compareString( aStr, rList[j] ) < 0 )
+ break; // insert before first greater than
+
+ rList.insert( rList.begin() + j, aStr );
+ rCurrencyList.insert( rCurrencyList.begin() + j, i );
+ }
+
+ // Append ISO codes to symbol list.
+ // XXX If this is to be changed, various other places would had to be
+ // adapted that assume this order!
+ std::vector<OUString>::size_type nCont = rList.size();
+
+ for ( sal_uInt16 i = 1; i < nCount; ++i )
+ {
+ bool bInsert = true;
+ OUString aStr( ApplyLreOrRleEmbedding( rCurrencyTable[i].GetBankSymbol() ) );
+
+ std::vector<OUString>::size_type j = nCont;
+ for ( ; j < rList.size() && bInsert; ++j )
+ {
+ if( rList[j] == aStr )
+ bInsert = false;
+ else if ( aCollator.compareString( aStr, rList[j] ) < 0 )
+ break; // insert before first greater than
+ }
+ if ( bInsert )
+ {
+ rList.insert( rList.begin() + j, aStr );
+ rCurrencyList.insert( rCurrencyList.begin() + j, i );
+ }
+ }
+}
+
+ListBoxColorWrapper::ListBoxColorWrapper(ColorListBox* pControl)
+ : mpControl(pControl)
+{
+}
+
+void ListBoxColorWrapper::operator()(
+ [[maybe_unused]] const OUString& /*rCommand*/, const svx::NamedThemedColor& rColor)
+{
+ mpControl->Selected(rColor);
+}
+
+void ColorListBox::EnsurePaletteManager()
+{
+ if (!m_xPaletteManager)
+ {
+ m_xPaletteManager = std::make_shared<PaletteManager>();
+ m_xPaletteManager->SetColorSelectFunction(std::ref(m_aColorWrapper));
+ }
+}
+
+void ColorListBox::SetSlotId(sal_uInt16 nSlotId, bool bShowNoneButton)
+{
+ m_nSlotId = nSlotId;
+ m_bShowNoneButton = bShowNoneButton;
+ m_xButton->set_popover(nullptr);
+ m_xColorWindow.reset();
+ m_aSelectedColor = svx::NamedThemedColor::FromNamedColor(bShowNoneButton ? GetNoneColor() : GetAutoColor(m_nSlotId));
+ ShowPreview(m_aSelectedColor.ToNamedColor());
+ createColorWindow();
+}
+
+ColorListBox::ColorListBox(std::unique_ptr<weld::MenuButton> pControl, TopLevelParentFunction const& rTopLevelParentFunction)
+ : m_xButton(std::move(pControl))
+ , m_aColorWrapper(this)
+ , m_aAutoDisplayColor(Application::GetSettings().GetStyleSettings().GetDialogColor())
+ , m_nSlotId(0)
+ , m_bShowNoneButton(false)
+ , m_aTopLevelParentFunction(rTopLevelParentFunction)
+{
+ m_xButton->connect_toggled(LINK(this, ColorListBox, ToggleHdl));
+ m_aSelectedColor = svx::NamedThemedColor::FromNamedColor(GetAutoColor(m_nSlotId));
+ LockWidthRequest();
+ ShowPreview(m_aSelectedColor.ToNamedColor());
+}
+
+IMPL_LINK(ColorListBox, ToggleHdl, weld::Toggleable&, rButton, void)
+{
+ if (rButton.get_active())
+ {
+ ColorWindow* pColorWindow = getColorWindow();
+ if (pColorWindow && !comphelper::LibreOfficeKit::isActive())
+ pColorWindow->GrabFocus();
+ }
+}
+
+ColorListBox::~ColorListBox()
+{
+}
+
+ColorWindow* ColorListBox::getColorWindow() const
+{
+ if (!m_xColorWindow)
+ const_cast<ColorListBox*>(this)->createColorWindow();
+ return m_xColorWindow.get();
+}
+
+void ColorListBox::createColorWindow()
+{
+ const SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ const SfxFrame* pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr;
+ css::uno::Reference<css::frame::XFrame> xFrame(pFrame ? pFrame->GetFrameInterface() : uno::Reference<css::frame::XFrame>());
+
+ EnsurePaletteManager();
+
+ m_xColorWindow.reset(new ColorWindow(
+ OUString() /*m_aCommandURL*/,
+ m_xPaletteManager,
+ m_aColorStatus,
+ m_nSlotId,
+ xFrame,
+ m_xButton.get(),
+ m_aTopLevelParentFunction,
+ m_aColorWrapper));
+
+ SetNoSelection();
+ m_xButton->set_popover(m_xColorWindow->getTopLevel());
+ if (m_bShowNoneButton)
+ m_xColorWindow->ShowNoneButton();
+ m_xColorWindow->SelectEntry(m_aSelectedColor.ToNamedColor());
+}
+
+void ColorListBox::SelectEntry(const NamedColor& rColor)
+{
+ if (rColor.second.trim().isEmpty())
+ {
+ SelectEntry(rColor.first);
+ return;
+ }
+ ColorWindow* pColorWindow = getColorWindow();
+ pColorWindow->SelectEntry(rColor);
+ m_aSelectedColor = svx::NamedThemedColor::FromNamedColor(pColorWindow->GetSelectEntryColor());
+ ShowPreview(m_aSelectedColor.ToNamedColor());
+}
+
+void ColorListBox::SelectEntry(const Color& rColor)
+{
+ ColorWindow* pColorWindow = getColorWindow();
+ pColorWindow->SelectEntry(rColor);
+ m_aSelectedColor = svx::NamedThemedColor::FromNamedColor(pColorWindow->GetSelectEntryColor());
+ ShowPreview(m_aSelectedColor.ToNamedColor());
+}
+
+void ColorListBox::Selected(const svx::NamedThemedColor& rColor)
+{
+ ShowPreview(rColor.ToNamedColor());
+ m_aSelectedColor = rColor;
+ if (m_aSelectedLink.IsSet())
+ m_aSelectedLink.Call(*this);
+}
+
+//to avoid the box resizing every time the color is changed to
+//the optimal size of the individual color, get the longest
+//standard color and stick with that as the size for all
+void ColorListBox::LockWidthRequest()
+{
+ NamedColor aLongestColor;
+ tools::Long nMaxStandardColorTextWidth = 0;
+ XColorListRef const xColorTable = XColorList::CreateStdColorList();
+ for (tools::Long i = 0; i != xColorTable->Count(); ++i)
+ {
+ XColorEntry& rEntry = *xColorTable->GetColor(i);
+ auto nColorTextWidth = m_xButton->get_pixel_size(rEntry.GetName()).Width();
+ if (nColorTextWidth > nMaxStandardColorTextWidth)
+ {
+ nMaxStandardColorTextWidth = nColorTextWidth;
+ aLongestColor.second = rEntry.GetName();
+ }
+ }
+ ShowPreview(aLongestColor);
+ m_xButton->set_size_request(m_xButton->get_preferred_size().Width(), -1);
+}
+
+void ColorListBox::ShowPreview(const NamedColor &rColor)
+{
+ // ScGridWindow::UpdateAutoFilterFromMenu is similar
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Size aImageSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize());
+
+ ScopedVclPtrInstance<VirtualDevice> xDevice;
+ xDevice->SetOutputSize(aImageSize);
+ const tools::Rectangle aRect(Point(0, 0), aImageSize);
+ if (m_bShowNoneButton && rColor.first == COL_NONE_COLOR)
+ {
+ const Color aW(COL_WHITE);
+ const Color aG(0xef, 0xef, 0xef);
+ int nMinDim = std::min(aImageSize.Width(), aImageSize.Height()) + 1;
+ int nCheckSize = nMinDim / 3;
+ xDevice->DrawCheckered(aRect.TopLeft(), aRect.GetSize(), std::min(nCheckSize, 8), aW, aG);
+ xDevice->SetFillColor();
+ }
+ else
+ {
+ if (rColor.first == COL_AUTO)
+ xDevice->SetFillColor(m_aAutoDisplayColor);
+ else
+ xDevice->SetFillColor(rColor.first);
+ }
+
+ xDevice->SetLineColor(rStyleSettings.GetDisableColor());
+ xDevice->DrawRect(aRect);
+
+ m_xButton->set_image(xDevice.get());
+ m_xButton->set_label(rColor.second);
+}
+
+MenuOrToolMenuButton::MenuOrToolMenuButton(weld::MenuButton* pMenuButton)
+ : m_pMenuButton(pMenuButton)
+ , m_pToolbar(nullptr)
+ , m_pControl(nullptr)
+ , m_nId(0)
+{
+}
+
+MenuOrToolMenuButton::MenuOrToolMenuButton(weld::Toolbar* pToolbar, const OString& rIdent)
+ : m_pMenuButton(nullptr)
+ , m_pToolbar(pToolbar)
+ , m_aIdent(rIdent)
+ , m_pControl(nullptr)
+ , m_nId(0)
+{
+}
+
+MenuOrToolMenuButton::MenuOrToolMenuButton(SvxColorToolBoxControl* pControl, ToolBox* pToolbar, ToolBoxItemId nId)
+ : m_pMenuButton(nullptr)
+ , m_pToolbar(nullptr)
+ , m_pControl(pControl)
+ , m_xToolBox(pToolbar)
+ , m_nId(nId)
+{
+}
+
+MenuOrToolMenuButton::~MenuOrToolMenuButton()
+{
+}
+
+bool MenuOrToolMenuButton::get_active() const
+{
+ if (m_pMenuButton)
+ return m_pMenuButton->get_active();
+ if (m_pToolbar)
+ return m_pToolbar->get_menu_item_active(m_aIdent);
+ return m_xToolBox->GetDownItemId() == m_nId;
+}
+
+void MenuOrToolMenuButton::set_inactive() const
+{
+ if (m_pMenuButton)
+ {
+ if (m_pMenuButton->get_active())
+ m_pMenuButton->set_active(false);
+ return;
+ }
+ if (m_pToolbar)
+ {
+ if (m_pToolbar->get_menu_item_active(m_aIdent))
+ m_pToolbar->set_menu_item_active(m_aIdent, false);
+ return;
+ }
+ m_pControl->EndPopupMode();
+}
+
+weld::Widget* MenuOrToolMenuButton::get_widget() const
+{
+ if (m_pMenuButton)
+ return m_pMenuButton;
+ if (m_pToolbar)
+ return m_pToolbar;
+ return m_xToolBox->GetFrameWeld();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/tbunocontroller.cxx b/svx/source/tbxctrls/tbunocontroller.cxx
new file mode 100644
index 000000000..a8073a1a7
--- /dev/null
+++ b/svx/source/tbxctrls/tbunocontroller.cxx
@@ -0,0 +1,538 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/status/FontHeight.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <rtl/math.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
+#include <vcl/window.hxx>
+#include <vcl/settings.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <svtools/ctrltool.hxx>
+#include <svtools/ctrlbox.hxx>
+#include <svtools/toolboxcontroller.hxx>
+#include <tools/json_writer.hxx>
+#include <vcl/toolbox.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <memory>
+
+#include <vcl/InterimItemWindow.hxx>
+
+using namespace ::com::sun::star;
+
+namespace {
+
+class SvxFontSizeBox_Base;
+class SvxFontSizeBox_Impl;
+
+class FontHeightToolBoxControl : public svt::ToolboxController,
+ public lang::XServiceInfo
+{
+ public:
+ explicit FontHeightToolBoxControl(
+ const css::uno::Reference< css::uno::XComponentContext >& rServiceManager );
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+
+ // XToolbarController
+ virtual void SAL_CALL execute( sal_Int16 KeyModifier ) override;
+ virtual void SAL_CALL click() override;
+ virtual void SAL_CALL doubleClick() override;
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createPopupWindow() override;
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override;
+
+ void dispatchCommand( const css::uno::Sequence< css::beans::PropertyValue >& rArgs );
+ using svt::ToolboxController::dispatchCommand;
+
+ private:
+ VclPtr<SvxFontSizeBox_Impl> m_xVclBox;
+ std::unique_ptr<SvxFontSizeBox_Base> m_xWeldBox;
+ SvxFontSizeBox_Base* m_pBox;
+};
+
+class SvxFontSizeBox_Base
+{
+public:
+ SvxFontSizeBox_Base(std::unique_ptr<weld::ComboBox> xWidget,
+ const uno::Reference< frame::XFrame >& _xFrame,
+ FontHeightToolBoxControl& rCtrl);
+
+ virtual ~SvxFontSizeBox_Base()
+ {
+ }
+
+ virtual void set_sensitive(bool bSensitive)
+ {
+ m_xWidget->set_sensitive(bSensitive);
+ }
+
+ void statusChanged_Impl(tools::Long nHeight, bool bErase);
+ void UpdateFont();
+
+protected:
+ FontHeightToolBoxControl& m_rCtrl;
+ OUString m_aCurText;
+ bool m_bRelease;
+ uno::Reference<frame::XFrame> m_xFrame;
+ std::unique_ptr<FontSizeBox> m_xWidget;
+
+ void ReleaseFocus_Impl();
+ void Select();
+
+ virtual bool DoKeyInput(const KeyEvent& rKEvt);
+
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+ DECL_LINK(DumpAsPropertyTreeHdl, tools::JsonWriter&, void);
+};
+
+class SvxFontSizeBox_Impl final : public InterimItemWindow
+ , public SvxFontSizeBox_Base
+{
+public:
+ SvxFontSizeBox_Impl(vcl::Window* pParent,
+ const uno::Reference< frame::XFrame >& _xFrame,
+ FontHeightToolBoxControl& rCtrl);
+
+ virtual void dispose() override
+ {
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+ }
+
+ virtual void GetFocus() override
+ {
+ if (m_xWidget)
+ m_xWidget->grab_focus();
+ InterimItemWindow::GetFocus();
+ }
+
+ virtual ~SvxFontSizeBox_Impl() override
+ {
+ disposeOnce();
+ }
+
+ void SetOptimalSize();
+
+ virtual void DataChanged(const DataChangedEvent& rDCEvt) override;
+
+ virtual void set_sensitive(bool bSensitive) override
+ {
+ m_xWidget->set_sensitive(bSensitive);
+ if (bSensitive)
+ InterimItemWindow::Enable();
+ else
+ InterimItemWindow::Disable();
+ }
+
+private:
+ virtual bool DoKeyInput(const KeyEvent& rKEvt) override;
+};
+
+SvxFontSizeBox_Base::SvxFontSizeBox_Base(std::unique_ptr<weld::ComboBox> xWidget,
+ const uno::Reference<frame::XFrame>& rFrame,
+ FontHeightToolBoxControl& rCtrl)
+ : m_rCtrl(rCtrl)
+ , m_bRelease(true)
+ , m_xFrame(rFrame)
+ , m_xWidget(new FontSizeBox(std::move(xWidget)))
+{
+ m_xWidget->set_value(0);
+ m_xWidget->set_active_or_entry_text("");
+ m_xWidget->disable_entry_completion();
+
+ m_xWidget->connect_changed(LINK(this, SvxFontSizeBox_Base, SelectHdl));
+ m_xWidget->connect_key_press(LINK(this, SvxFontSizeBox_Base, KeyInputHdl));
+ m_xWidget->connect_entry_activate(LINK(this, SvxFontSizeBox_Base, ActivateHdl));
+ m_xWidget->connect_focus_out(LINK(this, SvxFontSizeBox_Base, FocusOutHdl));
+ m_xWidget->connect_get_property_tree(LINK(this, SvxFontSizeBox_Base, DumpAsPropertyTreeHdl));
+}
+
+void SvxFontSizeBox_Base::ReleaseFocus_Impl()
+{
+ if ( !m_bRelease )
+ {
+ m_bRelease = true;
+ return;
+ }
+
+ if ( m_xFrame.is() && m_xFrame->getContainerWindow().is() )
+ m_xFrame->getContainerWindow()->setFocus();
+}
+
+IMPL_LINK(SvxFontSizeBox_Base, SelectHdl, weld::ComboBox&, rCombo, void)
+{
+ if (rCombo.changed_by_direct_pick()) // only when picked from the list
+ Select();
+}
+
+IMPL_LINK_NOARG(SvxFontSizeBox_Base, ActivateHdl, weld::ComboBox&, bool)
+{
+ Select();
+ return true;
+}
+
+void SvxFontSizeBox_Base::Select()
+{
+ sal_Int64 nSelVal = m_xWidget->get_value();
+ float fSelVal = float( nSelVal ) / 10;
+
+ uno::Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue("FontHeight.Height",
+ fSelVal) };
+
+ /* #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
+ This instance may be deleted in the meantime (i.e. when a dialog is opened
+ while in Dispatch()), accessing members will crash in this case. */
+ ReleaseFocus_Impl();
+
+ m_rCtrl.dispatchCommand( aArgs );
+}
+
+void SvxFontSizeBox_Base::statusChanged_Impl( tools::Long nPoint, bool bErase )
+{
+ if ( !bErase )
+ {
+ // convert the metric
+ tools::Long nVal = nPoint;
+
+ // changed => set new value
+ if (m_xWidget->get_value() != nVal)
+ m_xWidget->set_value(nVal);
+ }
+ else
+ {
+ // delete value in the display
+ m_xWidget->set_value(-1L);
+ m_xWidget->set_active_or_entry_text("");
+ }
+ m_aCurText = m_xWidget->get_active_text();
+}
+
+void SvxFontSizeBox_Base::UpdateFont()
+{
+ // filling up the sizes list
+ auto nOldVal = m_xWidget->get_value(); // memorize old value
+ FontList aFontList(Application::GetDefaultDevice());
+
+ m_xWidget->Fill(&aFontList);
+
+ m_xWidget->set_value(nOldVal); // restore old value
+ m_aCurText = m_xWidget->get_active_text(); // memorize to reset at ESC
+}
+
+IMPL_LINK(SvxFontSizeBox_Base, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return DoKeyInput(rKEvt);
+}
+
+bool SvxFontSizeBox_Base::DoKeyInput(const KeyEvent& rKEvt)
+{
+ bool bHandled = false;
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+
+ switch (nCode)
+ {
+ case KEY_TAB:
+ m_bRelease = false;
+ Select();
+ break;
+
+ case KEY_ESCAPE:
+ m_xWidget->set_active_or_entry_text(m_aCurText);
+ if (!m_rCtrl.IsInSidebar())
+ {
+ ReleaseFocus_Impl();
+ bHandled = true;
+ }
+ break;
+ }
+
+ return bHandled;
+}
+
+bool SvxFontSizeBox_Impl::DoKeyInput(const KeyEvent& rKEvt)
+{
+ return SvxFontSizeBox_Base::DoKeyInput(rKEvt) || ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(SvxFontSizeBox_Base, FocusOutHdl, weld::Widget&, void)
+{
+ if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
+ m_xWidget->set_active_or_entry_text(m_aCurText);
+}
+
+void SvxFontSizeBox_Impl::SetOptimalSize()
+{
+ SetSizePixel(get_preferred_size());
+}
+
+SvxFontSizeBox_Impl::SvxFontSizeBox_Impl(vcl::Window* pParent,
+ const uno::Reference<frame::XFrame>& rFrame,
+ FontHeightToolBoxControl& rCtrl)
+ : InterimItemWindow(pParent, "svx/ui/fontsizebox.ui", "FontSizeBox")
+ , SvxFontSizeBox_Base(m_xBuilder->weld_combo_box("fontsizecombobox"), rFrame, rCtrl)
+{
+}
+
+void SvxFontSizeBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ SetOptimalSize();
+ }
+}
+
+IMPL_LINK(SvxFontSizeBox_Base, DumpAsPropertyTreeHdl, tools::JsonWriter&, rJsonWriter, void)
+{
+ {
+ auto entriesNode = rJsonWriter.startNode("entries");
+ for (int i = 0, nCount = m_xWidget->get_count(); i < nCount; ++i)
+ {
+ auto entryNode = rJsonWriter.startNode("");
+ rJsonWriter.put("", m_xWidget->get_text(i));
+ }
+ }
+
+ int nActive = m_xWidget->get_active();
+ rJsonWriter.put("selectedCount", static_cast<sal_Int32>(nActive == -1 ? 0 : 1));
+ {
+ auto selectedNode = rJsonWriter.startNode("selectedEntries");
+ if (nActive != -1)
+ {
+ auto node = rJsonWriter.startNode("");
+ rJsonWriter.put("", static_cast<sal_Int32>(nActive));
+ }
+ }
+
+ rJsonWriter.put("command", ".uno:FontHeight");
+}
+
+FontHeightToolBoxControl::FontHeightToolBoxControl( const uno::Reference< uno::XComponentContext >& rxContext )
+ : svt::ToolboxController( rxContext,
+ uno::Reference< frame::XFrame >(),
+ ".uno:FontHeight" ),
+ m_pBox( nullptr )
+{
+ addStatusListener( ".uno:CharFontName");
+}
+
+// XInterface
+css::uno::Any SAL_CALL FontHeightToolBoxControl::queryInterface( const css::uno::Type& aType )
+{
+ uno::Any a = ToolboxController::queryInterface( aType );
+ if ( a.hasValue() )
+ return a;
+
+ return ::cppu::queryInterface( aType, static_cast< lang::XServiceInfo* >( this ));
+}
+
+void SAL_CALL FontHeightToolBoxControl::acquire() noexcept
+{
+ ToolboxController::acquire();
+}
+
+void SAL_CALL FontHeightToolBoxControl::release() noexcept
+{
+ ToolboxController::release();
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL FontHeightToolBoxControl::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+OUString SAL_CALL FontHeightToolBoxControl::getImplementationName()
+{
+ return "com.sun.star.svx.FontHeightToolBoxController";
+}
+
+uno::Sequence< OUString > SAL_CALL FontHeightToolBoxControl::getSupportedServiceNames( )
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+// XComponent
+void SAL_CALL FontHeightToolBoxControl::dispose()
+{
+ svt::ToolboxController::dispose();
+
+ SolarMutexGuard aSolarMutexGuard;
+ m_xVclBox.disposeAndClear();
+ m_xWeldBox.reset();
+ m_pBox = nullptr;
+}
+
+// XStatusListener
+void SAL_CALL FontHeightToolBoxControl::statusChanged(
+ const frame::FeatureStateEvent& rEvent )
+{
+ if ( !m_pBox )
+ return;
+
+ SolarMutexGuard aSolarMutexGuard;
+ if (rEvent.FeatureURL.Path == "FontHeight")
+ {
+ if ( rEvent.IsEnabled )
+ {
+ m_pBox->set_sensitive(true);
+ frame::status::FontHeight aFontHeight;
+ if ( rEvent.State >>= aFontHeight )
+ {
+ // tdf#83090 - correctly round the height of the font
+ aFontHeight.Height = rtl::math::round(10. * aFontHeight.Height);
+ m_pBox->statusChanged_Impl(tools::Long(aFontHeight.Height), false);
+ }
+ else
+ m_pBox->statusChanged_Impl( tools::Long( -1 ), true );
+ }
+ else
+ {
+ m_pBox->set_sensitive(false);
+ m_pBox->statusChanged_Impl( tools::Long( -1 ), true );
+ }
+
+ if (m_pToolbar)
+ m_pToolbar->set_item_sensitive(m_aCommandURL.toUtf8(), rEvent.IsEnabled);
+ else
+ {
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ pToolBox->EnableItem(nId, rEvent.IsEnabled);
+ }
+ }
+ else if ( rEvent.FeatureURL.Path == "CharFontName" )
+ {
+ m_pBox->UpdateFont();
+ }
+}
+
+// XToolbarController
+void SAL_CALL FontHeightToolBoxControl::execute( sal_Int16 /*KeyModifier*/ )
+{
+}
+
+void SAL_CALL FontHeightToolBoxControl::click()
+{
+}
+
+void SAL_CALL FontHeightToolBoxControl::doubleClick()
+{
+}
+
+uno::Reference< awt::XWindow > SAL_CALL FontHeightToolBoxControl::createPopupWindow()
+{
+ return uno::Reference< awt::XWindow >();
+}
+
+uno::Reference< awt::XWindow > SAL_CALL FontHeightToolBoxControl::createItemWindow(
+ const uno::Reference< awt::XWindow >& xParent )
+{
+ uno::Reference< awt::XWindow > xItemWindow;
+
+ if (m_pBuilder)
+ {
+ SolarMutexGuard aSolarMutexGuard;
+
+ std::unique_ptr<weld::ComboBox> xWidget(m_pBuilder->weld_combo_box("fontsizecombobox"));
+
+ xItemWindow = css::uno::Reference<css::awt::XWindow>(new weld::TransportAsXWindow(xWidget.get()));
+
+ m_xWeldBox.reset(new SvxFontSizeBox_Base(std::move(xWidget), m_xFrame, *this));
+ m_pBox = m_xWeldBox.get();
+ //Get the box to fill itself with all its sizes
+ m_pBox->UpdateFont();
+ }
+ else
+ {
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent );
+ if ( pParent )
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ m_xVclBox = VclPtr<SvxFontSizeBox_Impl>::Create( pParent, m_xFrame, *this );
+ m_pBox = m_xVclBox.get();
+ //Get the box to fill itself with all its sizes
+ m_pBox->UpdateFont();
+ //Make it size itself to its optimal size re above sizes
+ m_xVclBox->SetOptimalSize();
+ xItemWindow = VCLUnoHelper::GetInterface(m_xVclBox);
+ }
+ }
+
+ return xItemWindow;
+}
+
+void FontHeightToolBoxControl::dispatchCommand(
+ const uno::Sequence< beans::PropertyValue >& rArgs )
+{
+ uno::Reference< frame::XDispatchProvider > xDispatchProvider( m_xFrame, uno::UNO_QUERY );
+ if ( xDispatchProvider.is() )
+ {
+ util::URL aURL;
+ uno::Reference< frame::XDispatch > xDispatch;
+ uno::Reference< util::XURLTransformer > xURLTransformer = getURLTransformer();
+
+ aURL.Complete = ".uno:FontHeight";
+ xURLTransformer->parseStrict( aURL );
+ xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 );
+ if ( xDispatch.is() )
+ xDispatch->dispatch( aURL, rArgs );
+ }
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_svx_FontHeightToolBoxController_get_implementation(
+ css::uno::XComponentContext *rxContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new FontHeightToolBoxControl(rxContext));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/tbunosearchcontrollers.cxx b/svx/source/tbxctrls/tbunosearchcontrollers.cxx
new file mode 100644
index 000000000..487168285
--- /dev/null
+++ b/svx/source/tbxctrls/tbunosearchcontrollers.cxx
@@ -0,0 +1,1662 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <map>
+#include <vector>
+
+#include <config_feature_desktop.h>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/DispatchDescriptor.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/ui/XUIElement.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/SearchAlgorithms.hpp>
+#include <com/sun/star/util/SearchAlgorithms2.hpp>
+
+#include <vcl/InterimItemWindow.hxx>
+#include <svl/ctloptions.hxx>
+#include <svl/srchitem.hxx>
+#include <svtools/acceleratorexecute.hxx>
+#include <svtools/toolboxcontroller.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/labelitemwindow.hxx>
+#include <svx/srchdlg.hxx>
+#include <vcl/event.hxx>
+
+#include <findtextfield.hxx>
+
+using namespace css;
+
+namespace {
+
+constexpr OUStringLiteral COMMAND_FINDTEXT = u".uno:FindText";
+constexpr OUStringLiteral COMMAND_DOWNSEARCH = u".uno:DownSearch";
+constexpr OUStringLiteral COMMAND_UPSEARCH = u".uno:UpSearch";
+constexpr OUStringLiteral COMMAND_FINDALL = u".uno:FindAll";
+constexpr OUStringLiteral COMMAND_MATCHCASE = u".uno:MatchCase";
+constexpr OUStringLiteral COMMAND_SEARCHFORMATTED = u".uno:SearchFormattedDisplayString";
+
+const sal_Int32 REMEMBER_SIZE = 10;
+
+class CheckButtonItemWindow final : public InterimItemWindow
+{
+public:
+ CheckButtonItemWindow(vcl::Window* pParent, const OUString& rLabel)
+ : InterimItemWindow(pParent, "svx/ui/checkbuttonbox.ui", "CheckButtonBox")
+ , m_xWidget(m_xBuilder->weld_check_button("checkbutton"))
+ {
+ InitControlBase(m_xWidget.get());
+
+ m_xWidget->connect_key_press(LINK(this, CheckButtonItemWindow, KeyInputHdl));
+ m_xWidget->set_label(rLabel);
+ SetSizePixel(m_xWidget->get_preferred_size());
+ }
+
+ bool get_active() const
+ {
+ return m_xWidget->get_active();
+ }
+
+ virtual void dispose() override
+ {
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+ }
+
+ virtual ~CheckButtonItemWindow() override
+ {
+ disposeOnce();
+ }
+
+private:
+ std::unique_ptr<weld::CheckButton> m_xWidget;
+
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+};
+
+IMPL_LINK(CheckButtonItemWindow, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
+{
+ return ChildKeyInput(rKeyEvent);
+}
+
+void impl_executeSearch( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference< css::frame::XFrame >& xFrame,
+ const ToolBox* pToolBox,
+ const bool aSearchBackwards,
+ const bool aFindAll = false )
+{
+ css::uno::Reference< css::util::XURLTransformer > xURLTransformer( css::util::URLTransformer::create( rxContext ) );
+ css::util::URL aURL;
+ aURL.Complete = ".uno:ExecuteSearch";
+ xURLTransformer->parseStrict(aURL);
+
+ OUString sFindText;
+ bool aMatchCase = false;
+ bool bSearchFormatted = false;
+ if ( pToolBox )
+ {
+ ToolBox::ImplToolItems::size_type nItemCount = pToolBox->GetItemCount();
+ for ( ToolBox::ImplToolItems::size_type i=0; i<nItemCount; ++i )
+ {
+ ToolBoxItemId id = pToolBox->GetItemId(i);
+ OUString sItemCommand = pToolBox->GetItemCommand(id);
+ if ( sItemCommand == COMMAND_FINDTEXT )
+ {
+ FindTextFieldControl* pItemWin = static_cast<FindTextFieldControl*>(pToolBox->GetItemWindow(id));
+ if (pItemWin)
+ {
+ sFindText = pItemWin->get_active_text();
+ if (aFindAll && !pItemWin->ControlHasFocus())
+ pItemWin->GetFocus();
+ }
+ } else if ( sItemCommand == COMMAND_MATCHCASE )
+ {
+ CheckButtonItemWindow* pItemWin = static_cast<CheckButtonItemWindow*>(pToolBox->GetItemWindow(id));
+ if (pItemWin)
+ aMatchCase = pItemWin->get_active();
+ } else if ( sItemCommand == COMMAND_SEARCHFORMATTED )
+ {
+ CheckButtonItemWindow* pItemWin = static_cast<CheckButtonItemWindow*>(pToolBox->GetItemWindow(id));
+ if (pItemWin)
+ bSearchFormatted = pItemWin->get_active();
+ }
+ }
+ }
+
+ SvtCTLOptions aCTLOptions;
+ TransliterationFlags nFlags = TransliterationFlags::NONE;
+ if (!aMatchCase)
+ nFlags |= TransliterationFlags::IGNORE_CASE;
+ if (aCTLOptions.IsCTLFontEnabled())
+ nFlags |= TransliterationFlags::IGNORE_DIACRITICS_CTL
+ | TransliterationFlags::IGNORE_KASHIDA_CTL;
+
+ auto aArgs( comphelper::InitPropertySequence( {
+ { "SearchItem.SearchString", css::uno::Any( sFindText ) },
+ // Related tdf#102506: make Find Bar Ctrl+F searching by value by default
+ { "SearchItem.CellType", css::uno::Any( sal_Int16(SvxSearchCellType::VALUE) ) },
+ { "SearchItem.Backward", css::uno::Any( aSearchBackwards ) },
+ { "SearchItem.SearchFlags", css::uno::Any( sal_Int32(0) ) },
+ { "SearchItem.TransliterateFlags", css::uno::Any( static_cast<sal_Int32>(nFlags) ) },
+ { "SearchItem.Command", css::uno::Any( static_cast<sal_Int16>(aFindAll ?SvxSearchCmd::FIND_ALL : SvxSearchCmd::FIND ) ) },
+ { "SearchItem.AlgorithmType", css::uno::Any( sal_Int16(css::util::SearchAlgorithms_ABSOLUTE) ) },
+ { "SearchItem.AlgorithmType2", css::uno::Any( sal_Int16(css::util::SearchAlgorithms2::ABSOLUTE) ) },
+ { "SearchItem.SearchFormatted", css::uno::Any( bSearchFormatted ) }
+ } ) );
+
+ css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider(xFrame, css::uno::UNO_QUERY);
+ if ( xDispatchProvider.is() )
+ {
+ css::uno::Reference< css::frame::XDispatch > xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 );
+ if ( xDispatch.is() && !aURL.Complete.isEmpty() )
+ xDispatch->dispatch( aURL, aArgs );
+ }
+}
+
+}
+
+FindTextFieldControl::FindTextFieldControl( vcl::Window* pParent,
+ css::uno::Reference< css::frame::XFrame > const & xFrame,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext) :
+ InterimItemWindow(pParent, "svx/ui/findbox.ui", "FindBox"),
+ m_nAsyncGetFocusId(nullptr),
+ m_xWidget(m_xBuilder->weld_combo_box("find")),
+ m_xFrame(xFrame),
+ m_xContext(xContext),
+ m_pAcc(svt::AcceleratorExecute::createAcceleratorHelper())
+{
+ InitControlBase(m_xWidget.get());
+
+ m_xWidget->set_entry_placeholder_text(SvxResId(RID_SVXSTR_FINDBAR_FIND));
+ m_xWidget->set_entry_completion(true, true);
+ m_pAcc->init(m_xContext, m_xFrame);
+
+ m_xWidget->connect_focus_in(LINK(this, FindTextFieldControl, FocusInHdl));
+ m_xWidget->connect_key_press(LINK(this, FindTextFieldControl, KeyInputHdl));
+ m_xWidget->connect_entry_activate(LINK(this, FindTextFieldControl, ActivateHdl));
+
+ m_xWidget->set_size_request(250, -1);
+ SetSizePixel(m_xWidget->get_preferred_size());
+}
+
+void FindTextFieldControl::Remember_Impl(const OUString& rStr)
+{
+ const sal_Int32 nCount = m_xWidget->get_count();
+
+ for (sal_Int32 i=0; i<nCount; ++i)
+ {
+ if (rStr == m_xWidget->get_text(i))
+ return;
+ }
+
+ if (nCount == REMEMBER_SIZE)
+ m_xWidget->remove(REMEMBER_SIZE-1);
+
+ m_xWidget->insert_text(0, rStr);
+}
+
+void FindTextFieldControl::SetTextToSelected_Impl()
+{
+ OUString aString;
+
+ try
+ {
+ css::uno::Reference<css::frame::XController> xController(m_xFrame->getController(), css::uno::UNO_SET_THROW);
+ css::uno::Reference<css::frame::XModel> xModel(xController->getModel(), css::uno::UNO_SET_THROW);
+ css::uno::Reference<css::container::XIndexAccess> xIndexAccess(xModel->getCurrentSelection(), css::uno::UNO_QUERY_THROW);
+ if (xIndexAccess->getCount() > 0)
+ {
+ css::uno::Reference<css::text::XTextRange> xTextRange(xIndexAccess->getByIndex(0), css::uno::UNO_QUERY_THROW);
+ aString = xTextRange->getString();
+ }
+ }
+ catch ( ... )
+ {
+ }
+
+ if ( !aString.isEmpty() )
+ {
+ // If something is selected in the document, prepopulate with this
+ m_xWidget->set_entry_text(aString);
+ m_aChangeHdl.Call(*m_xWidget);
+ }
+ else if (get_count() > 0)
+ {
+ // Else, prepopulate with last search word (fdo#84256)
+ m_xWidget->set_entry_text(m_xWidget->get_text(0));
+ }
+}
+
+IMPL_LINK(FindTextFieldControl, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
+{
+ if (isDisposed())
+ return true;
+
+ bool bRet = false;
+
+ bool bShift = rKeyEvent.GetKeyCode().IsShift();
+ bool bMod1 = rKeyEvent.GetKeyCode().IsMod1();
+ sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode();
+
+ // Close the search bar on Escape
+ if ( KEY_ESCAPE == nCode )
+ {
+ bRet = true;
+ GrabFocusToDocument();
+
+ // hide the findbar
+ css::uno::Reference< css::beans::XPropertySet > xPropSet(m_xFrame, css::uno::UNO_QUERY);
+ if (xPropSet.is())
+ {
+ css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
+ aValue >>= xLayoutManager;
+ if (xLayoutManager.is())
+ {
+ static const OUStringLiteral sResourceURL( u"private:resource/toolbar/findbar" );
+ xLayoutManager->hideElement( sResourceURL );
+ xLayoutManager->destroyElement( sResourceURL );
+ }
+ }
+ }
+ else
+ {
+ auto awtKey = svt::AcceleratorExecute::st_VCLKey2AWTKey(rKeyEvent.GetKeyCode());
+ const OUString aCommand(m_pAcc->findCommand(awtKey));
+
+ // Select text in the search box when Ctrl-F pressed
+ if ( bMod1 && nCode == KEY_F )
+ m_xWidget->select_entry_region(0, -1);
+ // Execute the search when Ctrl-G, F3 and Shift-RETURN pressed (in addition to ActivateHdl condition which handles bare RETURN)
+ else if ( (bMod1 && KEY_G == nCode) || (bShift && KEY_RETURN == nCode) || (KEY_F3 == nCode) )
+ {
+ ActivateFind(bShift);
+ bRet = true;
+ }
+ else if (aCommand == ".uno:SearchDialog")
+ bRet = m_pAcc->execute(awtKey);
+
+ // find-shortcut called with focus already in find
+ if (aCommand == "vnd.sun.star.findbar:FocusToFindbar")
+ {
+ m_xWidget->call_attention_to();
+ bRet = true;
+ }
+ }
+
+ return bRet || ChildKeyInput(rKeyEvent);
+}
+
+void FindTextFieldControl::ActivateFind(bool bShift)
+{
+ Remember_Impl(m_xWidget->get_active_text());
+
+ vcl::Window* pWindow = GetParent();
+ ToolBox* pToolBox = static_cast<ToolBox*>(pWindow);
+
+ impl_executeSearch(m_xContext, m_xFrame, pToolBox, bShift);
+
+ m_xWidget->grab_focus();
+}
+
+// Execute the search when activated, typically due to "Return"
+IMPL_LINK_NOARG(FindTextFieldControl, ActivateHdl, weld::ComboBox&, bool)
+{
+ if (isDisposed())
+ return true;
+
+ ActivateFind(false);
+
+ return true;
+}
+
+IMPL_LINK_NOARG(FindTextFieldControl, OnAsyncGetFocus, void*, void)
+{
+ m_nAsyncGetFocusId = nullptr;
+ m_xWidget->select_entry_region(0, -1);
+}
+
+void FindTextFieldControl::FocusIn()
+{
+ if (m_nAsyncGetFocusId || !m_xWidget)
+ return;
+
+ // do it async to defeat entry in combobox having its own ideas about the focus
+ m_nAsyncGetFocusId = Application::PostUserEvent(LINK(this, FindTextFieldControl, OnAsyncGetFocus));
+
+ GrabFocus(); // tdf#137993 ensure the toplevel vcl::Window is activated so SfxViewFrame::Current is valid
+}
+
+IMPL_LINK_NOARG(FindTextFieldControl, FocusInHdl, weld::Widget&, void)
+{
+ FocusIn();
+}
+
+void FindTextFieldControl::dispose()
+{
+ if (m_nAsyncGetFocusId)
+ {
+ Application::RemoveUserEvent(m_nAsyncGetFocusId);
+ m_nAsyncGetFocusId = nullptr;
+ }
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+}
+
+FindTextFieldControl::~FindTextFieldControl()
+{
+ disposeOnce();
+}
+
+void FindTextFieldControl::connect_changed(const Link<weld::ComboBox&, void>& rLink)
+{
+ m_aChangeHdl = rLink;
+ m_xWidget->connect_changed(rLink);
+}
+
+int FindTextFieldControl::get_count() const
+{
+ return m_xWidget->get_count();
+}
+
+OUString FindTextFieldControl::get_text(int nIndex) const
+{
+ return m_xWidget->get_text(nIndex);
+}
+
+OUString FindTextFieldControl::get_active_text() const
+{
+ return m_xWidget->get_active_text();
+}
+
+void FindTextFieldControl::append_text(const OUString& rText)
+{
+ m_xWidget->append_text(rText);
+}
+
+void FindTextFieldControl::set_entry_message_type(weld::EntryMessageType eType)
+{
+ m_xWidget->set_entry_message_type(eType);
+}
+
+namespace {
+
+class SearchToolbarControllersManager
+{
+public:
+
+ SearchToolbarControllersManager();
+
+ static SearchToolbarControllersManager& createControllersManager();
+
+ void registryController( const css::uno::Reference< css::frame::XFrame >& xFrame, const css::uno::Reference< css::frame::XStatusListener >& xStatusListener, const OUString& sCommandURL );
+ void freeController ( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& sCommandURL );
+ css::uno::Reference< css::frame::XStatusListener > findController( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& sCommandURL );
+
+ void saveSearchHistory(const FindTextFieldControl* m_pFindTextFieldControl);
+ void loadSearchHistory(FindTextFieldControl* m_pFindTextFieldControl);
+
+private:
+
+ typedef ::std::vector< css::beans::PropertyValue > SearchToolbarControllersVec;
+ typedef ::std::map< css::uno::Reference< css::frame::XFrame >, SearchToolbarControllersVec > SearchToolbarControllersMap;
+ SearchToolbarControllersMap aSearchToolbarControllersMap;
+ std::vector<OUString> m_aSearchStrings;
+
+};
+
+SearchToolbarControllersManager::SearchToolbarControllersManager()
+{
+}
+
+SearchToolbarControllersManager& SearchToolbarControllersManager::createControllersManager()
+{
+ static SearchToolbarControllersManager theSearchToolbarControllersManager;
+ return theSearchToolbarControllersManager;
+}
+
+void SearchToolbarControllersManager::saveSearchHistory(const FindTextFieldControl* pFindTextFieldControl)
+{
+ const sal_Int32 nECount( pFindTextFieldControl->get_count() );
+ m_aSearchStrings.resize( nECount );
+ for( sal_Int32 i=0; i<nECount; ++i )
+ {
+ m_aSearchStrings[i] = pFindTextFieldControl->get_text(i);
+ }
+}
+
+void SearchToolbarControllersManager::loadSearchHistory(FindTextFieldControl* pFindTextFieldControl)
+{
+ for( size_t i=0; i<m_aSearchStrings.size(); ++i )
+ {
+ pFindTextFieldControl->append_text(m_aSearchStrings[i]);
+ }
+}
+
+void SearchToolbarControllersManager::registryController( const css::uno::Reference< css::frame::XFrame >& xFrame, const css::uno::Reference< css::frame::XStatusListener >& xStatusListener, const OUString& sCommandURL )
+{
+ SearchToolbarControllersMap::iterator pIt = aSearchToolbarControllersMap.find(xFrame);
+ if (pIt == aSearchToolbarControllersMap.end())
+ {
+ SearchToolbarControllersVec lControllers(1);
+ lControllers[0].Name = sCommandURL;
+ lControllers[0].Value <<= xStatusListener;
+ aSearchToolbarControllersMap.emplace(xFrame, lControllers);
+ }
+ else
+ {
+ sal_Int32 nSize = pIt->second.size();
+ for (sal_Int32 i=0; i<nSize; ++i)
+ {
+ if (pIt->second[i].Name == sCommandURL)
+ return;
+ }
+
+ pIt->second.resize(nSize+1);
+ pIt->second[nSize].Name = sCommandURL;
+ pIt->second[nSize].Value <<= xStatusListener;
+ }
+}
+
+void SearchToolbarControllersManager::freeController( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& sCommandURL )
+{
+ SearchToolbarControllersMap::iterator pIt = aSearchToolbarControllersMap.find(xFrame);
+ if (pIt != aSearchToolbarControllersMap.end())
+ {
+ auto pItCtrl = std::find_if(pIt->second.begin(), pIt->second.end(),
+ [&sCommandURL](const css::beans::PropertyValue& rCtrl) { return rCtrl.Name == sCommandURL; });
+ if (pItCtrl != pIt->second.end())
+ pIt->second.erase(pItCtrl);
+
+ if (pIt->second.empty())
+ aSearchToolbarControllersMap.erase(pIt);
+ }
+}
+
+css::uno::Reference< css::frame::XStatusListener > SearchToolbarControllersManager::findController( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& sCommandURL )
+{
+ css::uno::Reference< css::frame::XStatusListener > xStatusListener;
+
+ SearchToolbarControllersMap::iterator pIt = aSearchToolbarControllersMap.find(xFrame);
+ if (pIt != aSearchToolbarControllersMap.end())
+ {
+ auto pItCtrl = std::find_if(pIt->second.begin(), pIt->second.end(),
+ [&sCommandURL](const css::beans::PropertyValue& rCtrl) { return rCtrl.Name == sCommandURL; });
+ if (pItCtrl != pIt->second.end())
+ pItCtrl->Value >>= xStatusListener;
+ }
+
+ return xStatusListener;
+}
+
+class FindTextToolbarController : public svt::ToolboxController,
+ public css::lang::XServiceInfo
+{
+public:
+
+ FindTextToolbarController( const css::uno::Reference< css::uno::XComponentContext > & rxContext );
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XToolbarController
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+
+ DECL_LINK(EditModifyHdl, weld::ComboBox&, void);
+
+private:
+
+ void textfieldChanged();
+
+ VclPtr<FindTextFieldControl> m_pFindTextFieldControl;
+
+ ToolBoxItemId m_nDownSearchId;
+ ToolBoxItemId m_nUpSearchId;
+ ToolBoxItemId m_nFindAllId;
+
+};
+
+FindTextToolbarController::FindTextToolbarController( const css::uno::Reference< css::uno::XComponentContext >& rxContext )
+ : svt::ToolboxController(rxContext, css::uno::Reference< css::frame::XFrame >(), COMMAND_FINDTEXT)
+ , m_pFindTextFieldControl(nullptr)
+ , m_nDownSearchId(0)
+ , m_nUpSearchId(0)
+ , m_nFindAllId(0)
+{
+}
+
+// XInterface
+css::uno::Any SAL_CALL FindTextToolbarController::queryInterface( const css::uno::Type& aType )
+{
+ css::uno::Any a = ToolboxController::queryInterface( aType );
+ if ( a.hasValue() )
+ return a;
+
+ return ::cppu::queryInterface( aType, static_cast< css::lang::XServiceInfo* >( this ) );
+}
+
+void SAL_CALL FindTextToolbarController::acquire() noexcept
+{
+ ToolboxController::acquire();
+}
+
+void SAL_CALL FindTextToolbarController::release() noexcept
+{
+ ToolboxController::release();
+}
+
+// XServiceInfo
+OUString SAL_CALL FindTextToolbarController::getImplementationName()
+{
+ return "com.sun.star.svx.FindTextToolboxController";
+}
+
+sal_Bool SAL_CALL FindTextToolbarController::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL FindTextToolbarController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+// XComponent
+void SAL_CALL FindTextToolbarController::dispose()
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL);
+
+ svt::ToolboxController::dispose();
+ if (m_pFindTextFieldControl != nullptr) {
+ SearchToolbarControllersManager::createControllersManager()
+ .saveSearchHistory(m_pFindTextFieldControl);
+ m_pFindTextFieldControl.disposeAndClear();
+ }
+}
+
+// XInitialization
+void SAL_CALL FindTextToolbarController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::ToolboxController::initialize(aArguments);
+
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( getParent() );
+ ToolBox* pToolBox = static_cast<ToolBox*>(pWindow.get());
+ if ( pToolBox )
+ {
+ m_nDownSearchId = pToolBox->GetItemId(COMMAND_DOWNSEARCH);
+ m_nUpSearchId = pToolBox->GetItemId(COMMAND_UPSEARCH);
+ m_nFindAllId = pToolBox->GetItemId(COMMAND_FINDALL);
+ }
+
+ SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL);
+}
+
+css::uno::Reference< css::awt::XWindow > SAL_CALL FindTextToolbarController::createItemWindow( const css::uno::Reference< css::awt::XWindow >& xParent )
+{
+ css::uno::Reference< css::awt::XWindow > xItemWindow;
+
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent );
+ if ( pParent )
+ {
+ ToolBox* pToolbar = static_cast<ToolBox*>(pParent.get());
+ m_pFindTextFieldControl = VclPtr<FindTextFieldControl>::Create(pToolbar, m_xFrame, m_xContext);
+
+ m_pFindTextFieldControl->connect_changed(LINK(this, FindTextToolbarController, EditModifyHdl));
+ SearchToolbarControllersManager::createControllersManager().loadSearchHistory(m_pFindTextFieldControl);
+ }
+ xItemWindow = VCLUnoHelper::GetInterface( m_pFindTextFieldControl );
+
+ return xItemWindow;
+}
+
+// XStatusListener
+void SAL_CALL FindTextToolbarController::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ SolarMutexGuard aSolarMutexGuard;
+ if ( m_bDisposed )
+ return;
+
+ OUString aFeatureURL = rEvent.FeatureURL.Complete;
+ if ( aFeatureURL == "AppendSearchHistory" )
+ {
+ m_pFindTextFieldControl->Remember_Impl(m_pFindTextFieldControl->get_active_text());
+ }
+ // enable up/down buttons in case there is already text (from the search history)
+ textfieldChanged();
+}
+
+IMPL_LINK_NOARG(FindTextToolbarController, EditModifyHdl, weld::ComboBox&, void)
+{
+ // Clear SearchLabel when search string altered
+ #if HAVE_FEATURE_DESKTOP
+ SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty);
+ #endif
+
+ textfieldChanged();
+}
+
+void FindTextToolbarController::textfieldChanged() {
+ // enable or disable item DownSearch/UpSearch/FindAll of findbar
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( getParent() );
+ ToolBox* pToolBox = static_cast<ToolBox*>(pWindow.get());
+ if ( pToolBox && m_pFindTextFieldControl )
+ {
+ bool enableButtons = !m_pFindTextFieldControl->get_active_text().isEmpty();
+ pToolBox->EnableItem(m_nDownSearchId, enableButtons);
+ pToolBox->EnableItem(m_nUpSearchId, enableButtons);
+ pToolBox->EnableItem(m_nFindAllId, enableButtons);
+ }
+}
+
+class UpDownSearchToolboxController : public svt::ToolboxController,
+ public css::lang::XServiceInfo
+{
+public:
+ enum Type { UP, DOWN };
+
+ UpDownSearchToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext, Type eType );
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XToolbarController
+ virtual void SAL_CALL execute( sal_Int16 KeyModifier ) override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+
+private:
+ Type meType;
+};
+
+UpDownSearchToolboxController::UpDownSearchToolboxController( const css::uno::Reference< css::uno::XComponentContext > & rxContext, Type eType )
+ : svt::ToolboxController( rxContext,
+ css::uno::Reference< css::frame::XFrame >(),
+ (eType == UP) ? OUString( COMMAND_UPSEARCH ): OUString( COMMAND_DOWNSEARCH ) ),
+ meType( eType )
+{
+}
+
+// XInterface
+css::uno::Any SAL_CALL UpDownSearchToolboxController::queryInterface( const css::uno::Type& aType )
+{
+ css::uno::Any a = ToolboxController::queryInterface( aType );
+ if ( a.hasValue() )
+ return a;
+
+ return ::cppu::queryInterface( aType, static_cast< css::lang::XServiceInfo* >( this ) );
+}
+
+void SAL_CALL UpDownSearchToolboxController::acquire() noexcept
+{
+ ToolboxController::acquire();
+}
+
+void SAL_CALL UpDownSearchToolboxController::release() noexcept
+{
+ ToolboxController::release();
+}
+
+// XServiceInfo
+OUString SAL_CALL UpDownSearchToolboxController::getImplementationName()
+{
+ return meType == UpDownSearchToolboxController::UP?
+ OUString( "com.sun.star.svx.UpSearchToolboxController" ) :
+ OUString( "com.sun.star.svx.DownSearchToolboxController" );
+}
+
+sal_Bool SAL_CALL UpDownSearchToolboxController::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL UpDownSearchToolboxController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+// XComponent
+void SAL_CALL UpDownSearchToolboxController::dispose()
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL);
+
+ svt::ToolboxController::dispose();
+}
+
+// XInitialization
+void SAL_CALL UpDownSearchToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::ToolboxController::initialize( aArguments );
+ SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL);
+}
+
+// XToolbarController
+void SAL_CALL UpDownSearchToolboxController::execute( sal_Int16 /*KeyModifier*/ )
+{
+ if ( m_bDisposed )
+ throw css::lang::DisposedException();
+
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( getParent() );
+ ToolBox* pToolBox = static_cast<ToolBox*>(pWindow.get());
+
+ impl_executeSearch(m_xContext, m_xFrame, pToolBox, meType == UP );
+
+ css::frame::FeatureStateEvent aEvent;
+ aEvent.FeatureURL.Complete = "AppendSearchHistory";
+ css::uno::Reference< css::frame::XStatusListener > xStatusListener = SearchToolbarControllersManager::createControllersManager().findController(m_xFrame, COMMAND_FINDTEXT);
+ if (xStatusListener.is())
+ xStatusListener->statusChanged( aEvent );
+}
+
+// XStatusListener
+void SAL_CALL UpDownSearchToolboxController::statusChanged( const css::frame::FeatureStateEvent& /*rEvent*/ )
+{
+}
+
+class MatchCaseToolboxController : public svt::ToolboxController,
+ public css::lang::XServiceInfo
+{
+public:
+ MatchCaseToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XToolbarController
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+
+private:
+ VclPtr<CheckButtonItemWindow> m_xMatchCaseControl;
+};
+
+MatchCaseToolboxController::MatchCaseToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext )
+ : svt::ToolboxController( rxContext,
+ css::uno::Reference< css::frame::XFrame >(),
+ COMMAND_MATCHCASE )
+ , m_xMatchCaseControl(nullptr)
+{
+}
+
+// XInterface
+css::uno::Any SAL_CALL MatchCaseToolboxController::queryInterface( const css::uno::Type& aType )
+{
+ css::uno::Any a = ToolboxController::queryInterface( aType );
+ if ( a.hasValue() )
+ return a;
+
+ return ::cppu::queryInterface( aType, static_cast< css::lang::XServiceInfo* >( this ) );
+}
+
+void SAL_CALL MatchCaseToolboxController::acquire() noexcept
+{
+ ToolboxController::acquire();
+}
+
+void SAL_CALL MatchCaseToolboxController::release() noexcept
+{
+ ToolboxController::release();
+}
+
+// XServiceInfo
+OUString SAL_CALL MatchCaseToolboxController::getImplementationName()
+{
+ return "com.sun.star.svx.MatchCaseToolboxController";
+}
+
+sal_Bool SAL_CALL MatchCaseToolboxController::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL MatchCaseToolboxController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+// XComponent
+void SAL_CALL MatchCaseToolboxController::dispose()
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL);
+
+ svt::ToolboxController::dispose();
+
+ m_xMatchCaseControl.disposeAndClear();
+}
+
+// XInitialization
+void SAL_CALL MatchCaseToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::ToolboxController::initialize(aArguments);
+
+ SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL);
+}
+
+css::uno::Reference< css::awt::XWindow > SAL_CALL MatchCaseToolboxController::createItemWindow( const css::uno::Reference< css::awt::XWindow >& xParent )
+{
+ css::uno::Reference< css::awt::XWindow > xItemWindow;
+
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent );
+ if ( pParent )
+ {
+ ToolBox* pToolbar = static_cast<ToolBox*>(pParent.get());
+ m_xMatchCaseControl = VclPtr<CheckButtonItemWindow>::Create(pToolbar, SvxResId(RID_SVXSTR_FINDBAR_MATCHCASE));
+ }
+ xItemWindow = VCLUnoHelper::GetInterface(m_xMatchCaseControl);
+
+ return xItemWindow;
+}
+
+// XStatusListener
+void SAL_CALL MatchCaseToolboxController::statusChanged( const css::frame::FeatureStateEvent& )
+{
+}
+
+class SearchFormattedToolboxController : public svt::ToolboxController,
+ public css::lang::XServiceInfo
+{
+public:
+ SearchFormattedToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XToolbarController
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+
+private:
+ VclPtr<CheckButtonItemWindow> m_xSearchFormattedControl;
+};
+
+SearchFormattedToolboxController::SearchFormattedToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext )
+ : svt::ToolboxController( rxContext,
+ css::uno::Reference< css::frame::XFrame >(),
+ COMMAND_SEARCHFORMATTED )
+ , m_xSearchFormattedControl(nullptr)
+{
+}
+
+// XInterface
+css::uno::Any SAL_CALL SearchFormattedToolboxController::queryInterface( const css::uno::Type& aType )
+{
+ css::uno::Any a = ToolboxController::queryInterface( aType );
+ if ( a.hasValue() )
+ return a;
+
+ return ::cppu::queryInterface( aType, static_cast< css::lang::XServiceInfo* >( this ) );
+}
+
+void SAL_CALL SearchFormattedToolboxController::acquire() noexcept
+{
+ ToolboxController::acquire();
+}
+
+void SAL_CALL SearchFormattedToolboxController::release() noexcept
+{
+ ToolboxController::release();
+}
+
+// XServiceInfo
+OUString SAL_CALL SearchFormattedToolboxController::getImplementationName()
+{
+ return "com.sun.star.svx.SearchFormattedToolboxController";
+}
+
+sal_Bool SAL_CALL SearchFormattedToolboxController::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL SearchFormattedToolboxController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+// XComponent
+void SAL_CALL SearchFormattedToolboxController::dispose()
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL);
+
+ svt::ToolboxController::dispose();
+
+ m_xSearchFormattedControl.disposeAndClear();
+}
+
+// XInitialization
+void SAL_CALL SearchFormattedToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::ToolboxController::initialize(aArguments);
+
+ SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL);
+}
+
+css::uno::Reference< css::awt::XWindow > SAL_CALL SearchFormattedToolboxController::createItemWindow( const css::uno::Reference< css::awt::XWindow >& xParent )
+{
+ css::uno::Reference< css::awt::XWindow > xItemWindow;
+
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent );
+ if ( pParent )
+ {
+ ToolBox* pToolbar = static_cast<ToolBox*>(pParent.get());
+ m_xSearchFormattedControl = VclPtr<CheckButtonItemWindow>::Create(pToolbar, SvxResId(RID_SVXSTR_FINDBAR_SEARCHFORMATTED));
+ }
+ xItemWindow = VCLUnoHelper::GetInterface(m_xSearchFormattedControl);
+
+ return xItemWindow;
+}
+
+// XStatusListener
+void SAL_CALL SearchFormattedToolboxController::statusChanged( const css::frame::FeatureStateEvent& )
+{
+}
+
+class FindAllToolboxController : public svt::ToolboxController,
+ public css::lang::XServiceInfo
+{
+public:
+ FindAllToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XToolbarController
+ virtual void SAL_CALL execute( sal_Int16 KeyModifier ) override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+};
+
+FindAllToolboxController::FindAllToolboxController( const css::uno::Reference< css::uno::XComponentContext > & rxContext )
+ : svt::ToolboxController( rxContext,
+ css::uno::Reference< css::frame::XFrame >(),
+ ".uno:FindAll" )
+{
+}
+
+// XInterface
+css::uno::Any SAL_CALL FindAllToolboxController::queryInterface( const css::uno::Type& aType )
+{
+ css::uno::Any a = ToolboxController::queryInterface( aType );
+ if ( a.hasValue() )
+ return a;
+
+ return ::cppu::queryInterface( aType, static_cast< css::lang::XServiceInfo* >( this ) );
+}
+
+void SAL_CALL FindAllToolboxController::acquire() noexcept
+{
+ ToolboxController::acquire();
+}
+
+void SAL_CALL FindAllToolboxController::release() noexcept
+{
+ ToolboxController::release();
+}
+
+// XServiceInfo
+OUString SAL_CALL FindAllToolboxController::getImplementationName()
+{
+ return "com.sun.star.svx.FindAllToolboxController";
+}
+
+
+sal_Bool SAL_CALL FindAllToolboxController::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL FindAllToolboxController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+// XComponent
+void SAL_CALL FindAllToolboxController::dispose()
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL);
+
+ svt::ToolboxController::dispose();
+}
+
+// XInitialization
+void SAL_CALL FindAllToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::ToolboxController::initialize( aArguments );
+ SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL);
+}
+
+// XToolbarController
+void SAL_CALL FindAllToolboxController::execute( sal_Int16 /*KeyModifier*/ )
+{
+ if ( m_bDisposed )
+ throw css::lang::DisposedException();
+
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( getParent() );
+ ToolBox* pToolBox = static_cast<ToolBox*>(pWindow.get());
+
+ impl_executeSearch(m_xContext, m_xFrame, pToolBox, false, true);
+}
+
+// XStatusListener
+void SAL_CALL FindAllToolboxController::statusChanged( const css::frame::FeatureStateEvent& /*rEvent*/ )
+{
+}
+
+class ExitSearchToolboxController : public svt::ToolboxController,
+ public css::lang::XServiceInfo
+{
+public:
+ ExitSearchToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XToolbarController
+ virtual void SAL_CALL execute( sal_Int16 KeyModifier ) override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+};
+
+ExitSearchToolboxController::ExitSearchToolboxController( const css::uno::Reference< css::uno::XComponentContext > & rxContext )
+ : svt::ToolboxController( rxContext,
+ css::uno::Reference< css::frame::XFrame >(),
+ ".uno:ExitSearch" )
+{
+}
+
+// XInterface
+css::uno::Any SAL_CALL ExitSearchToolboxController::queryInterface( const css::uno::Type& aType )
+{
+ css::uno::Any a = ToolboxController::queryInterface( aType );
+ if ( a.hasValue() )
+ return a;
+
+ return ::cppu::queryInterface( aType, static_cast< css::lang::XServiceInfo* >( this ) );
+}
+
+void SAL_CALL ExitSearchToolboxController::acquire() noexcept
+{
+ ToolboxController::acquire();
+}
+
+void SAL_CALL ExitSearchToolboxController::release() noexcept
+{
+ ToolboxController::release();
+}
+
+// XServiceInfo
+OUString SAL_CALL ExitSearchToolboxController::getImplementationName()
+{
+ return "com.sun.star.svx.ExitFindbarToolboxController";
+}
+
+
+sal_Bool SAL_CALL ExitSearchToolboxController::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL ExitSearchToolboxController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+// XComponent
+void SAL_CALL ExitSearchToolboxController::dispose()
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL);
+
+ svt::ToolboxController::dispose();
+}
+
+// XInitialization
+void SAL_CALL ExitSearchToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::ToolboxController::initialize( aArguments );
+ SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL);
+}
+
+// XToolbarController
+void SAL_CALL ExitSearchToolboxController::execute( sal_Int16 /*KeyModifier*/ )
+{
+ vcl::Window *pFocusWindow = Application::GetFocusWindow();
+ if ( pFocusWindow )
+ pFocusWindow->GrabFocusToDocument();
+
+ // hide the findbar
+ css::uno::Reference< css::beans::XPropertySet > xPropSet(m_xFrame, css::uno::UNO_QUERY);
+ if (xPropSet.is())
+ {
+ css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
+ aValue >>= xLayoutManager;
+ if (xLayoutManager.is())
+ {
+ static const OUStringLiteral sResourceURL( u"private:resource/toolbar/findbar" );
+ xLayoutManager->hideElement( sResourceURL );
+ xLayoutManager->destroyElement( sResourceURL );
+ }
+ }
+}
+
+// XStatusListener
+void SAL_CALL ExitSearchToolboxController::statusChanged( const css::frame::FeatureStateEvent& /*rEvent*/ )
+{
+}
+
+class SearchLabelToolboxController : public svt::ToolboxController,
+ public css::lang::XServiceInfo
+{
+public:
+ SearchLabelToolboxController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XToolbarController
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
+
+private:
+ VclPtr<LabelItemWindow> m_xSL;
+};
+
+SearchLabelToolboxController::SearchLabelToolboxController( const css::uno::Reference< css::uno::XComponentContext > & rxContext )
+ : svt::ToolboxController( rxContext,
+ css::uno::Reference< css::frame::XFrame >(),
+ ".uno:SearchLabel" )
+{
+}
+
+// XInterface
+css::uno::Any SAL_CALL SearchLabelToolboxController::queryInterface( const css::uno::Type& aType )
+{
+ css::uno::Any a = ToolboxController::queryInterface( aType );
+ if ( a.hasValue() )
+ return a;
+
+ return ::cppu::queryInterface( aType, static_cast< css::lang::XServiceInfo* >( this ) );
+}
+
+void SAL_CALL SearchLabelToolboxController::acquire() noexcept
+{
+ ToolboxController::acquire();
+}
+
+void SAL_CALL SearchLabelToolboxController::release() noexcept
+{
+ ToolboxController::release();
+}
+
+// XServiceInfo
+OUString SAL_CALL SearchLabelToolboxController::getImplementationName()
+{
+ return "com.sun.star.svx.SearchLabelToolboxController";
+}
+
+
+sal_Bool SAL_CALL SearchLabelToolboxController::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL SearchLabelToolboxController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+// XComponent
+void SAL_CALL SearchLabelToolboxController::dispose()
+{
+ SolarMutexGuard aSolarMutexGuard;
+
+ SearchToolbarControllersManager::createControllersManager().freeController(m_xFrame, m_aCommandURL);
+
+ svt::ToolboxController::dispose();
+ m_xSL.disposeAndClear();
+}
+
+// XInitialization
+void SAL_CALL SearchLabelToolboxController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::ToolboxController::initialize( aArguments );
+ SearchToolbarControllersManager::createControllersManager().registryController(m_xFrame, css::uno::Reference< css::frame::XStatusListener >(this), m_aCommandURL);
+}
+
+// XStatusListener
+void SAL_CALL SearchLabelToolboxController::statusChanged( const css::frame::FeatureStateEvent& )
+{
+ if (m_xSL)
+ {
+ OUString aStr = SvxSearchDialogWrapper::GetSearchLabel();
+ m_xSL->set_label(aStr);
+ m_xSL->SetOptimalSize();
+ Size aSize(m_xSL->GetSizePixel());
+ tools::Long nWidth = !aStr.isEmpty() ? aSize.getWidth() : 16;
+ m_xSL->SetSizePixel(Size(nWidth, aSize.Height()));
+ }
+}
+
+css::uno::Reference< css::awt::XWindow > SAL_CALL SearchLabelToolboxController::createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent )
+{
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nId;
+ if (getToolboxId(nId, &pToolBox))
+ pToolBox->SetItemWindowNonInteractive(nId, true);
+
+ m_xSL = VclPtr<LabelItemWindow>::Create(VCLUnoHelper::GetWindow(Parent), "");
+ m_xSL->SetSizePixel(Size(16, m_xSL->GetSizePixel().Height()));
+ return VCLUnoHelper::GetInterface(m_xSL);
+}
+
+// protocol handler for "vnd.sun.star.findbar:*" URLs
+// The dispatch object will be used for shortcut commands for findbar
+class FindbarDispatcher : public css::lang::XServiceInfo,
+ public css::lang::XInitialization,
+ public css::frame::XDispatchProvider,
+ public css::frame::XDispatch,
+ public ::cppu::OWeakObject
+{
+public:
+
+ FindbarDispatcher();
+ virtual ~FindbarDispatcher() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XDispatchProvider
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch( const css::util::URL& aURL, const OUString& sTargetFrameName , sal_Int32 nSearchFlags ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptions ) override;
+
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override;
+ virtual void SAL_CALL addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xListener, const css::util::URL& aURL ) override;
+ virtual void SAL_CALL removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xListener, const css::util::URL& aURL ) override;
+
+private:
+
+ css::uno::Reference< css::frame::XFrame > m_xFrame;
+
+};
+
+FindbarDispatcher::FindbarDispatcher()
+{
+}
+
+FindbarDispatcher::~FindbarDispatcher()
+{
+ m_xFrame = nullptr;
+}
+
+// XInterface
+css::uno::Any SAL_CALL FindbarDispatcher::queryInterface( const css::uno::Type& aType )
+{
+ css::uno::Any aReturn( ::cppu::queryInterface( aType,
+ static_cast< css::lang::XServiceInfo* >(this),
+ static_cast< css::lang::XInitialization* >(this),
+ static_cast< css::frame::XDispatchProvider* >(this),
+ static_cast< css::frame::XDispatch* >(this)) );
+
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ return OWeakObject::queryInterface( aType );
+}
+
+void SAL_CALL FindbarDispatcher::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL FindbarDispatcher::release() noexcept
+{
+ OWeakObject::release();
+}
+
+// XServiceInfo
+OUString SAL_CALL FindbarDispatcher::getImplementationName()
+{
+ return "com.sun.star.comp.svx.Impl.FindbarDispatcher";
+}
+
+sal_Bool SAL_CALL FindbarDispatcher::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL FindbarDispatcher::getSupportedServiceNames()
+{
+ return { "com.sun.star.comp.svx.FindbarDispatcher", "com.sun.star.frame.ProtocolHandler" };
+}
+
+// XInitialization
+void SAL_CALL FindbarDispatcher::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ if ( aArguments.hasElements() )
+ aArguments[0] >>= m_xFrame;
+}
+
+// XDispatchProvider
+css::uno::Reference< css::frame::XDispatch > SAL_CALL FindbarDispatcher::queryDispatch( const css::util::URL& aURL, const OUString& /*sTargetFrameName*/, sal_Int32 /*nSearchFlags*/ )
+{
+ css::uno::Reference< css::frame::XDispatch > xDispatch;
+
+ if ( aURL.Protocol == "vnd.sun.star.findbar:" )
+ xDispatch = this;
+
+ return xDispatch;
+}
+
+css::uno::Sequence < css::uno::Reference< css::frame::XDispatch > > SAL_CALL FindbarDispatcher::queryDispatches( const css::uno::Sequence < css::frame::DispatchDescriptor >& seqDescripts )
+{
+ sal_Int32 nCount = seqDescripts.getLength();
+ css::uno::Sequence < css::uno::Reference < XDispatch > > lDispatcher( nCount );
+
+ std::transform(seqDescripts.begin(), seqDescripts.end(), lDispatcher.getArray(),
+ [this](const css::frame::DispatchDescriptor& rDescript) -> css::uno::Reference < XDispatch > {
+ return queryDispatch( rDescript.FeatureURL, rDescript.FrameName, rDescript.SearchFlags ); });
+
+ return lDispatcher;
+}
+
+// XDispatch
+void SAL_CALL FindbarDispatcher::dispatch( const css::util::URL& aURL, const css::uno::Sequence < css::beans::PropertyValue >& /*lArgs*/ )
+{
+ //vnd.sun.star.findbar:FocusToFindbar - set cursor to the FindTextFieldControl of the findbar
+ if ( aURL.Path != "FocusToFindbar" )
+ return;
+
+ css::uno::Reference< css::beans::XPropertySet > xPropSet(m_xFrame, css::uno::UNO_QUERY);
+ if(!xPropSet.is())
+ return;
+
+ css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
+ aValue >>= xLayoutManager;
+ if (!xLayoutManager.is())
+ return;
+
+ static const OUStringLiteral sResourceURL( u"private:resource/toolbar/findbar" );
+ css::uno::Reference< css::ui::XUIElement > xUIElement = xLayoutManager->getElement(sResourceURL);
+ if (!xUIElement.is())
+ {
+ // show the findbar if necessary
+ xLayoutManager->createElement( sResourceURL );
+ xLayoutManager->showElement( sResourceURL );
+ xUIElement = xLayoutManager->getElement( sResourceURL );
+ if ( !xUIElement.is() )
+ return;
+ }
+
+ css::uno::Reference< css::awt::XWindow > xWindow(xUIElement->getRealInterface(), css::uno::UNO_QUERY);
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ ToolBox* pToolBox = static_cast<ToolBox*>(pWindow.get());
+ pToolBox->set_id("FindBar");
+ if ( !pToolBox )
+ return;
+
+ ToolBox::ImplToolItems::size_type nItemCount = pToolBox->GetItemCount();
+ for ( ToolBox::ImplToolItems::size_type i=0; i<nItemCount; ++i )
+ {
+ ToolBoxItemId id = pToolBox->GetItemId(i);
+ OUString sItemCommand = pToolBox->GetItemCommand(id);
+ if ( sItemCommand == COMMAND_FINDTEXT )
+ {
+ vcl::Window* pItemWin = pToolBox->GetItemWindow( id );
+ if ( pItemWin )
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ FindTextFieldControl* pFindTextFieldControl = dynamic_cast<FindTextFieldControl*>(pItemWin);
+ if ( pFindTextFieldControl )
+ pFindTextFieldControl->SetTextToSelected_Impl();
+ pItemWin->GrabFocus();
+ return;
+ }
+ }
+ }
+}
+
+void SAL_CALL FindbarDispatcher::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xControl*/, const css::util::URL& /*aURL*/ )
+{
+}
+
+void SAL_CALL FindbarDispatcher::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xControl*/, const css::util::URL& /*aURL*/ )
+{
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_svx_FindTextToolboxController_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new FindTextToolbarController(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_svx_ExitFindbarToolboxController_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ExitSearchToolboxController(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_svx_UpSearchToolboxController_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new UpDownSearchToolboxController(context, UpDownSearchToolboxController::UP));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_svx_DownSearchToolboxController_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new UpDownSearchToolboxController(context, UpDownSearchToolboxController::DOWN));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_svx_MatchCaseToolboxController_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new MatchCaseToolboxController(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_svx_SearchFormattedToolboxController_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SearchFormattedToolboxController(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_svx_FindAllToolboxController_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new FindAllToolboxController(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_svx_SearchLabelToolboxController_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SearchLabelToolboxController(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_Impl_FindbarDispatcher_get_implementation(
+ SAL_UNUSED_PARAMETER css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new FindbarDispatcher);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/tbxcolor.cxx b/svx/source/tbxctrls/tbxcolor.cxx
new file mode 100644
index 000000000..f3dbbe096
--- /dev/null
+++ b/svx/source/tbxctrls/tbxcolor.cxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/tbxcolor.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+
+namespace svx
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::beans;
+
+ ToolboxAccess::ToolboxAccess( std::u16string_view rToolboxName ) :
+ m_sToolboxResName ( "private:resource/toolbar/" )
+ {
+ m_sToolboxResName += rToolboxName;
+
+ // the layout manager
+ if ( !SfxViewFrame::Current() )
+ return;
+
+ try
+ {
+ Reference< XFrame > xFrame = SfxViewFrame::Current()->GetFrame().GetFrameInterface();
+ Reference< XPropertySet > xFrameProps( xFrame, UNO_QUERY );
+ if ( xFrameProps.is() )
+ xFrameProps->getPropertyValue( "LayoutManager" ) >>= m_xLayouter;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION( "svx.tbxcrtls", "ToolboxAccess::Ctor()" );
+ }
+ }
+
+
+ void ToolboxAccess::toggleToolbox() const
+ {
+ try
+ {
+ Reference< XLayoutManager > xManager( m_xLayouter );
+ OSL_ENSURE( xManager. is(), "ToolboxAccess::toggleToolbox: couldn't obtain the layout manager!" );
+ if ( xManager. is() )
+ {
+ if ( xManager->isElementVisible( m_sToolboxResName ) )
+ {
+ xManager->hideElement( m_sToolboxResName );
+ xManager->destroyElement( m_sToolboxResName );
+ }
+ else
+ {
+ xManager->createElement( m_sToolboxResName );
+ xManager->showElement( m_sToolboxResName );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "svx", "ToolboxAccess::toggleToolbox" );
+ }
+ }
+
+
+ bool ToolboxAccess::isToolboxVisible() const
+ {
+ return ( m_xLayouter.is() && m_xLayouter->isElementVisible( m_sToolboxResName ) );
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/tbxcolorupdate.cxx b/svx/source/tbxctrls/tbxcolorupdate.cxx
new file mode 100644
index 000000000..4e6ec87f3
--- /dev/null
+++ b/svx/source/tbxctrls/tbxcolorupdate.cxx
@@ -0,0 +1,355 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/objsh.hxx>
+#include <svx/drawitem.hxx>
+#include <tbxcolorupdate.hxx>
+#include <svx/svxids.hrc>
+#include <svx/xdef.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlndsit.hxx>
+
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/settings.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+namespace svx
+{
+ ToolboxButtonColorUpdaterBase::ToolboxButtonColorUpdaterBase(bool bWideButton, const OUString& rCommandLabel,
+ const OUString& rCommandURL,
+ const css::uno::Reference<css::frame::XFrame>& rFrame)
+ : mbWideButton(bWideButton)
+ , mbWasHiContrastMode(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ , maCurColor(COL_TRANSPARENT)
+ , meImageType(vcl::ImageType::Size16)
+ , maCommandLabel(rCommandLabel)
+ , maCommandURL(rCommandURL)
+ , mxFrame(rFrame)
+ {
+ }
+
+ void ToolboxButtonColorUpdaterBase::Init(sal_uInt16 nSlotId)
+ {
+ switch (nSlotId)
+ {
+ case SID_ATTR_CHAR_COLOR:
+ case SID_ATTR_CHAR_COLOR2:
+ Update(NamedColor(COL_DEFAULT_FONT, SvxResId(RID_SVXSTR_COLOR_DEFAULT_FONT)));
+ break;
+ case SID_FRAME_LINECOLOR:
+ Update(NamedColor(COL_DEFAULT_FRAMELINE, SvxResId(RID_SVXSTR_COLOR_DEFAULT_FRAMELINE)));
+ break;
+ case SID_ATTR_CHAR_COLOR_BACKGROUND:
+ case SID_ATTR_CHAR_BACK_COLOR:
+ case SID_BACKGROUND_COLOR:
+ case SID_TABLE_CELL_BACKGROUND_COLOR:
+ Update(NamedColor(COL_DEFAULT_HIGHLIGHT, SvxResId(RID_SVXSTR_COLOR_DEFAULT_HIGHLIGHT)));
+ break;
+ case SID_ATTR_LINE_COLOR:
+ Update(NamedColor(COL_DEFAULT_SHAPE_STROKE, SvxResId(RID_SVXSTR_COLOR_DEFAULT_SHAPE_STROKE)));
+ break;
+ case SID_ATTR_FILL_COLOR:
+ Update(NamedColor(COL_DEFAULT_SHAPE_FILLING, SvxResId(RID_SVXSTR_COLOR_DEFAULT_SHAPE_FILLING)));
+ break;
+ default:
+ Update(COL_TRANSPARENT);
+ }
+ }
+
+ VclToolboxButtonColorUpdater::VclToolboxButtonColorUpdater(
+ sal_uInt16 nSlotId, ToolBoxItemId nTbxBtnId, ToolBox* pToolBox, bool bWideButton,
+ const OUString& rCommandLabel, const OUString& rCommandURL,
+ const css::uno::Reference<css::frame::XFrame>& rFrame)
+ : ToolboxButtonColorUpdaterBase(bWideButton, rCommandLabel, rCommandURL, rFrame)
+ , mnBtnId(nTbxBtnId)
+ , mpTbx(pToolBox)
+ {
+ Init(nSlotId);
+ }
+
+ void VclToolboxButtonColorUpdater::SetQuickHelpText(const OUString& rText)
+ {
+ mpTbx->SetQuickHelpText(mnBtnId, rText);
+ }
+
+ OUString VclToolboxButtonColorUpdater::GetQuickHelpText() const
+ {
+ return mpTbx->GetQuickHelpText(mnBtnId);
+ }
+
+ void VclToolboxButtonColorUpdater::SetImage(VirtualDevice* pVirDev)
+ {
+ GDIMetaFile* pMtf = pVirDev->GetConnectMetaFile();
+
+ assert(pMtf && "should have been set in ToolboxButtonColorUpdaterBase::Update");
+
+ pMtf->Stop();
+ pMtf->WindStart();
+
+ Graphic aGraphic(*pMtf);
+
+ mpTbx->SetItemImage(mnBtnId, Image(aGraphic.GetXGraphic()));
+ }
+
+ VclPtr<VirtualDevice> VclToolboxButtonColorUpdater::CreateVirtualDevice() const
+ {
+ return VclPtr<VirtualDevice>::Create(*mpTbx->GetOutDev());
+ }
+
+ vcl::ImageType VclToolboxButtonColorUpdater::GetImageSize() const
+ {
+ return mpTbx->GetImageSize();
+ }
+
+ Size VclToolboxButtonColorUpdater::GetItemSize(const Size& rImageSize) const
+ {
+ if (mbWideButton)
+ return mpTbx->GetItemContentSize(mnBtnId);
+ return rImageSize;
+ }
+
+ ToolboxButtonColorUpdaterBase::~ToolboxButtonColorUpdaterBase()
+ {}
+
+ void ToolboxButtonColorUpdaterBase::Update(const NamedColor &rNamedColor)
+ {
+ Update(rNamedColor.first);
+ if (!mbWideButton)
+ {
+ // Also show the current color as QuickHelpText
+ OUString colorSuffix = OUString(" (%1)").replaceFirst("%1", rNamedColor.second);
+ OUString colorHelpText = maCommandLabel + colorSuffix;
+
+ SetQuickHelpText(colorHelpText);
+ }
+ }
+
+ void ToolboxButtonColorUpdaterBase::Update(const Color& rColor, bool bForceUpdate)
+ {
+ vcl::ImageType eImageType = GetImageSize();
+
+#ifdef IOS // tdf#126966
+ eImageType = vcl::ImageType::Size32;
+#endif
+
+ const bool bSizeChanged = (meImageType != eImageType);
+ meImageType = eImageType;
+ const bool bDisplayModeChanged = (mbWasHiContrastMode != Application::GetSettings().GetStyleSettings().GetHighContrastMode());
+ Color aColor(rColor);
+
+ // !!! #109290# Workaround for SetFillColor with COL_AUTO
+ if (aColor == COL_AUTO)
+ aColor = COL_TRANSPARENT;
+
+ if ((maCurColor == aColor) && !bSizeChanged && !bDisplayModeChanged && !bForceUpdate)
+ return;
+
+ auto xImage = vcl::CommandInfoProvider::GetXGraphicForCommand(maCommandURL, mxFrame, meImageType);
+ Image aImage(xImage);
+
+ Size aItemSize = GetItemSize(aImage.GetSizePixel());
+ if (!aItemSize.Width() || !aItemSize.Height())
+ return;
+
+ ScopedVclPtr<VirtualDevice> pVirDev(CreateVirtualDevice());
+ pVirDev->SetOutputSizePixel(aItemSize);
+ maBmpSize = aItemSize;
+
+ std::unique_ptr<GDIMetaFile> xMetaFile;
+ if (RecordVirtualDevice())
+ {
+ xMetaFile.reset(new GDIMetaFile);
+ xMetaFile->SetPrefSize(pVirDev->GetOutputSize());
+ xMetaFile->SetPrefMapMode(pVirDev->GetMapMode());
+ xMetaFile->Record(pVirDev.get());
+ pVirDev->EnableOutput(false);
+ }
+
+ if (maBmpSize.Width() == maBmpSize.Height())
+ // tdf#84985 align color bar with icon bottom edge; integer arithmetic e.g. 26 - 26/4 <> 26 * 3/4
+ maUpdRect = tools::Rectangle(Point( 0, maBmpSize.Height() - maBmpSize.Height() / 4), Size(maBmpSize.Width(), maBmpSize.Height() / 4));
+ else
+ maUpdRect = tools::Rectangle(Point( maBmpSize.Height() + 2, 2), Point(maBmpSize.Width() - 3, maBmpSize.Height() - 3));
+
+ pVirDev->Push(vcl::PushFlags::CLIPREGION);
+
+ // tdf#135121 don't include the part of the image which we will
+ // overwrite with the target color so that for the transparent color
+ // case the original background of the device is shown
+ vcl::Region aRegion(tools::Rectangle(Point(0, 0), maBmpSize));
+ aRegion.Exclude(maUpdRect);
+ pVirDev->SetClipRegion(aRegion);
+
+ pVirDev->DrawImage(Point(0, 0), aImage);
+
+ pVirDev->Pop();
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ mbWasHiContrastMode = rStyleSettings.GetHighContrastMode();
+
+ if ((COL_TRANSPARENT != aColor) && (maBmpSize.Width() == maBmpSize.Height()))
+ pVirDev->SetLineColor(aColor);
+ else
+ pVirDev->SetLineColor(rStyleSettings.GetDisableColor());
+
+ // use not only COL_TRANSPARENT for detection of transparence,
+ // but the method/way which is designed to do that
+ const bool bIsFullyTransparent(aColor.IsFullyTransparent());
+ maCurColor = aColor;
+
+ if (bIsFullyTransparent)
+ {
+ pVirDev->SetFillColor();
+ }
+ else
+ {
+ pVirDev->SetFillColor(maCurColor);
+ }
+
+ pVirDev->DrawRect(maUpdRect);
+
+ SetImage(pVirDev.get());
+ }
+
+ OUString ToolboxButtonColorUpdaterBase::GetCurrentColorName() const
+ {
+ OUString sColorName = GetQuickHelpText();
+ // The obtained string is of format: color context (color name)
+ // Generate a substring which contains only the color name
+ sal_Int32 nStart = sColorName.indexOf('(');
+ sColorName = sColorName.copy( nStart + 1 );
+ sal_Int32 nLength = sColorName.getLength();
+ if(nLength > 0)
+ sColorName = sColorName.copy( 0, nLength - 1);
+ return sColorName;
+ }
+
+ ToolboxButtonColorUpdater::ToolboxButtonColorUpdater(sal_uInt16 nSlotId, const OString& rTbxBtnId, weld::Toolbar* ptrTbx, bool bWideButton,
+ const OUString& rCommandLabel, const css::uno::Reference<css::frame::XFrame>& rFrame)
+ : ToolboxButtonColorUpdaterBase(bWideButton, rCommandLabel, OUString::fromUtf8(rTbxBtnId), rFrame)
+ , msBtnId(rTbxBtnId)
+ , mpTbx(ptrTbx)
+ {
+ Init(nSlotId);
+ }
+
+ void ToolboxButtonColorUpdater::SetQuickHelpText(const OUString& rText)
+ {
+ mpTbx->set_item_tooltip_text(msBtnId, rText);
+ }
+
+ OUString ToolboxButtonColorUpdater::GetQuickHelpText() const
+ {
+ return mpTbx->get_item_tooltip_text(msBtnId);
+ }
+
+ void ToolboxButtonColorUpdater::SetImage(VirtualDevice* pVirDev)
+ {
+ mpTbx->set_item_image(msBtnId, pVirDev);
+ }
+
+ VclPtr<VirtualDevice> ToolboxButtonColorUpdater::CreateVirtualDevice() const
+ {
+ return mpTbx->create_virtual_device();
+ }
+
+ vcl::ImageType ToolboxButtonColorUpdater::GetImageSize() const
+ {
+ return mpTbx->get_icon_size();
+ }
+
+ Size ToolboxButtonColorUpdater::GetItemSize(const Size& rImageSize) const
+ {
+ auto nWidth = rImageSize.Width();
+ if (mbWideButton)
+ nWidth = nWidth * 5;
+ return Size(nWidth, rImageSize.Height());
+ }
+
+ ToolboxButtonLineStyleUpdater::ToolboxButtonLineStyleUpdater()
+ : m_eXLS(css::drawing::LineStyle_NONE)
+ , m_nDashStyleIndex(-1)
+ {
+ }
+
+ void ToolboxButtonLineStyleUpdater::Update(const com::sun::star::frame::FeatureStateEvent& rEvent)
+ {
+ if (rEvent.FeatureURL.Complete == ".uno:LineDash")
+ {
+ m_nDashStyleIndex = -1;
+
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ if (!pSh)
+ return;
+ const SvxDashListItem* pItem = pSh->GetItem( SID_DASH_LIST );
+ if (!pItem)
+ return;
+
+ XLineDashItem aDashItem;
+ aDashItem.PutValue(rEvent.State, 0);
+ const XDash& rDash = aDashItem.GetDashValue();
+
+ XDashListRef xLineStyleList = pItem->GetDashList();
+ for (tools::Long i = 0; i < xLineStyleList->Count(); ++i)
+ {
+ const XDashEntry* pEntry = xLineStyleList->GetDash(i);
+ const XDash& rEntry = pEntry->GetDash();
+ if (rDash == rEntry)
+ {
+ m_nDashStyleIndex = i;
+ break;
+ }
+ }
+ }
+ else if (rEvent.FeatureURL.Complete == ".uno:XLineStyle")
+ {
+ XLineStyleItem aLineStyleItem;
+ aLineStyleItem.PutValue(rEvent.State, 0);
+
+ m_eXLS = aLineStyleItem.GetValue();
+ }
+ }
+
+ int ToolboxButtonLineStyleUpdater::GetStyleIndex() const
+ {
+ int nRet;
+ switch (m_eXLS)
+ {
+ case css::drawing::LineStyle_NONE:
+ nRet = 0;
+ break;
+ case css::drawing::LineStyle_SOLID:
+ nRet = 1;
+ break;
+ default:
+ nRet = m_nDashStyleIndex + 2;
+ break;
+ }
+ return nRet;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/tbxdrctl.cxx b/svx/source/tbxctrls/tbxdrctl.cxx
new file mode 100644
index 000000000..7eb116161
--- /dev/null
+++ b/svx/source/tbxctrls/tbxdrctl.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svl/eitem.hxx>
+#include <vcl/toolbox.hxx>
+
+#include <svx/tbxctl.hxx>
+
+#include <com/sun/star/frame/XLayoutManager.hpp>
+
+SFX_IMPL_TOOLBOX_CONTROL(SvxTbxCtlDraw, SfxBoolItem);
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+
+
+SvxTbxCtlDraw::SvxTbxCtlDraw( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx ) :
+ SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+ rTbx.SetItemBits( nId, ToolBoxItemBits::CHECKABLE | rTbx.GetItemBits( nId ) );
+ rTbx.Invalidate();
+}
+
+void SAL_CALL SvxTbxCtlDraw::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ svt::ToolboxController::initialize(aArguments);
+ /*
+ * Toolbar name is defined as "private:resource/toolbar/drawbar" in writer and calc,
+ * "private:resource/toolbar/toolbar" in draw and impress. Control is added for this
+ * difference.
+ */
+ if( m_aCommandURL==".uno:TrackChangesBar")
+ m_sToolboxName="private:resource/toolbar/changes";
+ else if ( m_sModuleName == "com.sun.star.presentation.PresentationDocument" || m_sModuleName == "com.sun.star.drawing.DrawingDocument" )
+ m_sToolboxName="private:resource/toolbar/toolbar";
+ else
+ m_sToolboxName="private:resource/toolbar/drawbar";
+}
+
+
+void SvxTbxCtlDraw::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ GetToolBox().EnableItem( GetId(), ( eState != SfxItemState::DISABLED ) );
+ SfxToolBoxControl::StateChangedAtToolBoxControl( nSID, eState, pState );
+
+ Reference< XLayoutManager > xLayoutMgr = getLayoutManager();
+ if ( xLayoutMgr.is() )
+ GetToolBox().CheckItem(
+ GetId(), xLayoutMgr->isElementVisible( m_sToolboxName ) );
+}
+
+
+void SvxTbxCtlDraw::toggleToolbox()
+{
+ Reference< XLayoutManager > xLayoutMgr = getLayoutManager();
+ if ( !xLayoutMgr.is() )
+ return;
+
+ bool bCheck = false;
+ if ( xLayoutMgr->isElementVisible( m_sToolboxName ) )
+ {
+ xLayoutMgr->hideElement( m_sToolboxName );
+ xLayoutMgr->destroyElement( m_sToolboxName );
+ }
+ else
+ {
+ bCheck = true;
+ xLayoutMgr->createElement( m_sToolboxName );
+ xLayoutMgr->showElement( m_sToolboxName );
+ }
+
+ GetToolBox().CheckItem( GetId(), bCheck );
+}
+
+
+void SvxTbxCtlDraw::Select(sal_uInt16 /*nSelectModifier*/)
+{
+ toggleToolbox();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/tbxctrls/verttexttbxctrl.cxx b/svx/source/tbxctrls/verttexttbxctrl.cxx
new file mode 100644
index 000000000..d15a276fe
--- /dev/null
+++ b/svx/source/tbxctrls/verttexttbxctrl.cxx
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cppuhelper/supportsservice.hxx>
+#include <verttexttbxctrl.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/weld.hxx>
+#include <rtl/ustring.hxx>
+
+SvxCTLTextTbxCtrl::SvxCTLTextTbxCtrl(
+ const css::uno::Reference<css::uno::XComponentContext>& rContext)
+ : SvxVertCTLTextTbxCtrl(rContext)
+{
+ addStatusListener(".uno:CTLFontState");
+}
+
+OUString SvxCTLTextTbxCtrl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.CTLToolBoxControl";
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_CTLToolBoxControl_get_implementation(css::uno::XComponentContext* rContext,
+ css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new SvxCTLTextTbxCtrl(rContext));
+}
+
+SvxVertTextTbxCtrl::SvxVertTextTbxCtrl(
+ const css::uno::Reference<css::uno::XComponentContext>& rContext)
+ : SvxVertCTLTextTbxCtrl(rContext)
+{
+ addStatusListener(".uno:VerticalTextState");
+}
+
+OUString SvxVertTextTbxCtrl::getImplementationName()
+{
+ return "com.sun.star.comp.svx.VertTextToolBoxControl";
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_svx_VertTextToolBoxControl_get_implementation(
+ css::uno::XComponentContext* rContext, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new SvxVertTextTbxCtrl(rContext));
+}
+
+SvxVertCTLTextTbxCtrl::SvxVertCTLTextTbxCtrl(
+ const css::uno::Reference<css::uno::XComponentContext>& rContext)
+ : SvxVertCTLTextTbxCtrl_Base(rContext, nullptr, OUString())
+ , m_bVisible(false)
+{
+}
+
+SvxVertCTLTextTbxCtrl::~SvxVertCTLTextTbxCtrl() {}
+
+void SAL_CALL SvxVertCTLTextTbxCtrl::initialize(const css::uno::Sequence<css::uno::Any>& rArguments)
+{
+ SvxVertCTLTextTbxCtrl_Base::initialize(rArguments);
+ // fdo#83320 Hide vertical text commands early
+ setFastPropertyValue_NoBroadcast(1, css::uno::Any(true));
+
+ if (m_pToolbar)
+ {
+ m_bVisible = m_pToolbar->get_item_visible(m_aCommandURL.toUtf8());
+ return;
+ }
+
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nItemId;
+ if (getToolboxId(nItemId, &pToolBox))
+ m_bVisible = pToolBox->IsItemVisible(nItemId);
+}
+
+void SAL_CALL SvxVertCTLTextTbxCtrl::statusChanged(const css::frame::FeatureStateEvent& rEvent)
+{
+ ToolBox* pToolBox = nullptr;
+ ToolBoxItemId nItemId;
+ bool bVclToolBox = getToolboxId(nItemId, &pToolBox);
+
+ bool bEnabled = false;
+ if (rEvent.FeatureURL.Complete == ".uno:VerticalTextState")
+ {
+ bEnabled = m_bVisible && SvtCJKOptions::IsVerticalTextEnabled();
+ }
+ else if (rEvent.FeatureURL.Complete == ".uno:CTLFontState")
+ {
+ SvtCTLOptions aLangOptions;
+ bEnabled = m_bVisible && aLangOptions.IsCTLFontEnabled();
+ }
+ else
+ {
+ // normal command
+ bool bValue = false;
+ rEvent.State >>= bValue;
+
+ if (m_pToolbar)
+ {
+ OString sId = m_aCommandURL.toUtf8();
+ m_pToolbar->set_item_active(sId, bValue);
+ m_pToolbar->set_item_sensitive(sId, rEvent.IsEnabled);
+ }
+
+ if (bVclToolBox)
+ {
+ pToolBox->CheckItem(nItemId, bValue);
+ pToolBox->EnableItem(nItemId, rEvent.IsEnabled);
+ }
+
+ return;
+ }
+
+ if (m_pToolbar)
+ {
+ m_pToolbar->set_item_visible(m_aCommandURL.toUtf8(), bEnabled);
+ return;
+ }
+
+ if (bVclToolBox)
+ {
+ pToolBox->ShowItem(nItemId, bEnabled);
+
+ vcl::Window* pParent = pToolBox->GetParent();
+ if (WindowType::FLOATINGWINDOW == pParent->GetType())
+ {
+ Size aSize(pToolBox->CalcWindowSizePixel());
+ pToolBox->SetPosSizePixel(Point(), aSize);
+ pParent->SetOutputSizePixel(aSize);
+ }
+ }
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL SvxVertCTLTextTbxCtrl::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> SvxVertCTLTextTbxCtrl::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/toolbars/extrusionbar.cxx b/svx/source/toolbars/extrusionbar.cxx
new file mode 100644
index 000000000..3e0273c28
--- /dev/null
+++ b/svx/source/toolbars/extrusionbar.cxx
@@ -0,0 +1,1338 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
+#include <com/sun/star/drawing/ShadeMode.hpp>
+#include <com/sun/star/drawing/Position3D.hpp>
+#include <com/sun/star/drawing/Direction3D.hpp>
+#include <com/sun/star/drawing/ProjectionMode.hpp>
+#include <svx/svxids.hrc>
+#include <svx/svdundo.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/bindings.hxx>
+#include <svx/xsflclit.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdview.hxx>
+#include <editeng/colritem.hxx>
+#include <svx/chrtitem.hxx>
+#include <svx/sdasitm.hxx>
+#include <svl/intitem.hxx>
+#include <rtl/math.hxx>
+#include <basegfx/numeric/ftools.hxx>
+
+#include <svx/extrusionbar.hxx>
+#include <extrusiondepthdialog.hxx>
+
+using namespace ::svx;
+using namespace ::cppu;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::uno;
+
+// Declare the default interface. (The slotmap must not be empty, so
+// we enter something which never occurs here (hopefully).)
+static SfxSlot aExtrusionBarSlots_Impl[] =
+{
+ { 0, SfxGroupId::NONE, SfxSlotMode::NONE, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, 0, SfxDisableFlags::NONE, nullptr }
+};
+
+SFX_IMPL_INTERFACE(ExtrusionBar, SfxShell)
+
+void ExtrusionBar::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Invisible, ToolbarId::Svx_Extrusion_Bar);
+}
+
+
+ExtrusionBar::ExtrusionBar(SfxViewShell* pViewShell )
+: SfxShell(pViewShell)
+{
+ DBG_ASSERT( pViewShell, "svx::ExtrusionBar::ExtrusionBar(), I need a viewshell!" );
+ if( pViewShell )
+ SetPool(&pViewShell->GetPool());
+
+ SetName(SvxResId(RID_SVX_EXTRUSION_BAR));
+}
+
+ExtrusionBar::~ExtrusionBar()
+{
+ SetRepeatTarget(nullptr);
+}
+
+static void getLightingDirectionDefaults( const Direction3D **pLighting1Defaults, const Direction3D **pLighting2Defaults )
+{
+
+ static const Direction3D aLighting1Defaults[9] =
+ {
+ Direction3D( -50000, -50000, 10000 ),
+ Direction3D( 0, -50000, 10000 ),
+ Direction3D( 50000, -50000, 10000 ),
+ Direction3D( -50000, 0, 10000 ),
+ Direction3D( 0, 0, 10000 ),
+ Direction3D( 50000, 0, 10000 ),
+ Direction3D( -50000, 50000, 10000 ),
+ Direction3D( 0, 50000, 10000 ),
+ Direction3D( 50000, 50000, 10000 )
+ };
+
+ static const Direction3D aLighting2Defaults[9] =
+ {
+ Direction3D( 50000,0, 10000 ),
+ Direction3D( 0, 50000, 10000 ),
+ Direction3D( -50000, 0, 10000 ),
+ Direction3D( 50000, 0, 10000 ),
+ Direction3D( 0, 0, 10000 ),
+ Direction3D( -50000, 0, 10000 ),
+ Direction3D( 50000, 0, 10000 ),
+ Direction3D( 0, -50000, 10000 ),
+ Direction3D( -50000, 0, 10000 )
+ };
+
+ *pLighting1Defaults = aLighting1Defaults;
+ *pLighting2Defaults = aLighting2Defaults;
+};
+
+static void impl_execute( SfxRequest const & rReq, SdrCustomShapeGeometryItem& rGeometryItem, SdrObject* pObj )
+{
+ static constexpr OUStringLiteral sExtrusion = u"Extrusion";
+ static constexpr OUStringLiteral sRotateAngle = u"RotateAngle";
+
+ sal_uInt16 nSID = rReq.GetSlot();
+ switch( nSID )
+ {
+ case SID_EXTRUSION_TOGGLE:
+ {
+ bool bOn(false);
+ css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
+ if ( pAny )
+ {
+ (*pAny) >>= bOn;
+ bOn = !bOn;
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = sExtrusion;
+ aPropValue.Value <<= bOn;
+ rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
+ }
+ else
+ {
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = sExtrusion;
+ aPropValue.Value <<= true;
+ rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
+ bOn = true;
+ }
+
+ // draw:extrusion-diffusion has default 0% and c3DDiffuseAmt has default 100%. We set property
+ // "Diffusion" with value 100% here if it does not exist already. This forces, that the
+ // property is written to file in case an extrusion is newly created, and users of old
+ // documents, which usually do not have this property, can force the value to 100% by toggling
+ // the extrusion off and on.
+ if (bOn)
+ {
+ pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"Diffusion");
+ if (!pAny)
+ {
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = u"Diffusion";
+ aPropValue.Value <<= 100.0;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+ }
+ }
+ }
+ break;
+
+ case SID_EXTRUSION_TILT_DOWN:
+ case SID_EXTRUSION_TILT_UP:
+ case SID_EXTRUSION_TILT_LEFT:
+ case SID_EXTRUSION_TILT_RIGHT:
+ {
+ bool bHorizontal = ( nSID == SID_EXTRUSION_TILT_DOWN ) || ( nSID == SID_EXTRUSION_TILT_UP );
+ sal_Int32 nDiff = ( nSID == SID_EXTRUSION_TILT_LEFT ) || ( nSID == SID_EXTRUSION_TILT_UP ) ? 5 : -5;
+ EnhancedCustomShapeParameterPair aRotateAnglePropPair;
+ double fX = 0.0;
+ double fY = 0.0;
+ aRotateAnglePropPair.First.Value <<= fX;
+ aRotateAnglePropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aRotateAnglePropPair.Second.Value <<= fY;
+ aRotateAnglePropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
+ css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, sRotateAngle );
+ if( pAny && ( *pAny >>= aRotateAnglePropPair ) )
+ {
+ aRotateAnglePropPair.First.Value >>= fX;
+ aRotateAnglePropPair.Second.Value >>= fY;
+ }
+ if ( bHorizontal )
+ fX += nDiff;
+ else
+ fY += nDiff;
+ aRotateAnglePropPair.First.Value <<= fX;
+ aRotateAnglePropPair.Second.Value <<= fY;
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = sRotateAngle;
+ aPropValue.Value <<= aRotateAnglePropPair;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+ }
+ break;
+
+ case SID_EXTRUSION_DIRECTION:
+ {
+ if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_DIRECTION ) == SfxItemState::SET )
+ {
+ sal_Int32 nSkew = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_DIRECTION)->GetValue();
+
+ Position3D aViewPoint( 3472, -3472, 25000 );
+ double fOriginX = 0.50;
+ double fOriginY = -0.50;
+ double fSkewAngle = nSkew;
+ double fSkew = 50.0;
+
+ switch( nSkew )
+ {
+ case 135:
+ aViewPoint.PositionY = 3472;
+ fOriginY = 0.50;
+ break;
+ case 90:
+ aViewPoint.PositionX = 0;
+ aViewPoint.PositionY = 3472;
+ fOriginX = 0;
+ fOriginY = 0.50;
+ break;
+ case 45:
+ aViewPoint.PositionX = -3472;
+ aViewPoint.PositionY = 3472;
+ fOriginX = -0.50;
+ fOriginY = 0.50;
+ break;
+ case 180:
+ aViewPoint.PositionY = 0;
+ fOriginY = 0;
+ break;
+ case 0:
+ aViewPoint.PositionX = 0;
+ aViewPoint.PositionY = 0;
+ fOriginX = 0;
+ fOriginY = 0;
+ fSkew = 0.0;
+ break;
+ case -360:
+ aViewPoint.PositionX = -3472;
+ aViewPoint.PositionY = 0;
+ fOriginX = -0.50;
+ fOriginY = 0;
+ break;
+ case -90:
+ aViewPoint.PositionX = 0;
+ fOriginX = 0;
+ break;
+ case -45:
+ aViewPoint.PositionX = -3472;
+ fOriginX = -0.50;
+ break;
+ }
+
+ css::beans::PropertyValue aPropValue;
+
+ aPropValue.Name = "ViewPoint";
+ aPropValue.Value <<= aViewPoint;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+
+
+ EnhancedCustomShapeParameterPair aOriginPropPair;
+ aOriginPropPair.First.Value <<= fOriginX;
+ aOriginPropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aOriginPropPair.Second.Value <<= fOriginY;
+ aOriginPropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aPropValue.Name = "Origin";
+ aPropValue.Value <<= aOriginPropPair;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+
+ EnhancedCustomShapeParameterPair aSkewPropPair;
+ aSkewPropPair.First.Value <<= fSkew;
+ aSkewPropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aSkewPropPair.Second.Value <<= fSkewAngle;
+ aSkewPropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aPropValue.Name = "Skew";
+ aPropValue.Value <<= aSkewPropPair;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+ }
+ }
+ break;
+ case SID_EXTRUSION_PROJECTION:
+ {
+ if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_PROJECTION ) == SfxItemState::SET )
+ {
+ sal_Int32 nProjection = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_PROJECTION)->GetValue();
+ ProjectionMode eProjectionMode = nProjection == 1 ? ProjectionMode_PARALLEL : ProjectionMode_PERSPECTIVE;
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = "ProjectionMode";
+ aPropValue.Value <<= eProjectionMode;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+ }
+ }
+ break;
+ case SID_EXTRUSION_DEPTH:
+ {
+ if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_DEPTH ) == SfxItemState::SET)
+ {
+ double fDepth = rReq.GetArgs()->GetItem<SvxDoubleItem>(SID_EXTRUSION_DEPTH)->GetValue();
+ EnhancedCustomShapeParameterPair aDepthPropPair;
+ aDepthPropPair.First.Value <<= fDepth;
+ aDepthPropPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aDepthPropPair.Second.Value <<= 0.0; // fraction
+ aDepthPropPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
+
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = "Depth";
+ aPropValue.Value <<= aDepthPropPair;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+ }
+ }
+ break;
+ case SID_EXTRUSION_3D_COLOR:
+ {
+ if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_3D_COLOR ) == SfxItemState::SET)
+ {
+ Color aColor( static_cast<const SvxColorItem&>(rReq.GetArgs()->Get(SID_EXTRUSION_3D_COLOR)).GetValue() );
+
+ const bool bAuto = aColor == COL_AUTO;
+
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = "Color";
+ aPropValue.Value <<= !bAuto;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+
+ if( bAuto )
+ {
+ pObj->ClearMergedItem( XATTR_SECONDARYFILLCOLOR );
+ }
+ else
+ {
+ pObj->SetMergedItem( XSecondaryFillColorItem( "", aColor ) );
+ }
+ pObj->BroadcastObjectChange();
+ }
+ }
+ break;
+ case SID_EXTRUSION_SURFACE:
+ {
+ if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_SURFACE ) == SfxItemState::SET)
+ {
+ sal_Int32 nSurface = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_SURFACE)->GetValue();
+
+ // Set ShadeMode only when changing from or to wireframe, otherwise keep existing value.
+ ShadeMode eOldShadeMode(ShadeMode_FLAT);
+ css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"ShadeMode");
+ if (pAny)
+ *pAny >>= eOldShadeMode;
+ ShadeMode eShadeMode(eOldShadeMode);
+ switch (nSurface)
+ {
+ case 0: // wireframe
+ eShadeMode = ShadeMode_DRAFT;
+ break;
+ case 1: // matte
+ case 2: // plastic
+ case 3: // metal ODF
+ case 4: // metal MS Office
+ if (eOldShadeMode == ShadeMode_DRAFT)
+ eShadeMode = ShadeMode_FLAT; // ODF default
+ break;
+ }
+
+ // ODF has no dedicated property for 'surface'. MS Office binary format uses attribute
+ // c3DSpecularAmt to distinguish between 'matte' (=0) and 'plastic'.
+ // We do the same.
+ double fOldSpecularity = 0.0;
+ pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"Specularity");
+ if (pAny)
+ *pAny >>= fOldSpecularity;
+ double fSpecularity = fOldSpecularity;
+ switch( nSurface )
+ {
+ case 0: // wireframe
+ break;
+ case 1: // matte
+ fSpecularity = 0.0;
+ break;
+ case 2: // plastic
+ case 3: // metal ODF
+ case 4: // metal MS Office
+ if (basegfx::fTools::equalZero(fOldSpecularity, 0.0001))
+ // MS Office uses 80000/65536. That is currently not allowed in ODF.
+ // But the ODF error will be caught in xmloff.
+ fSpecularity = 80000.0 / 655.36; // interpreted as %
+ break;
+ }
+
+ // MS Office binary format uses attribute c3DDiffuseAmt with value =43712 (Fixed 16.16) in
+ // addition to the 'metal' flag. For other surface kinds default = 65536 is used.
+ // We toggle between 100 and 43712.0 / 655.36 here, to get better ODF -> MSO binary.
+ // We keep other values, those might be set outside regular UI, e.g by macro.
+ double fOldDiffusion = 100.0;
+ pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"Diffusion");
+ if (pAny)
+ *pAny >>= fOldDiffusion;
+ double fDiffusion = fOldDiffusion;
+ if (nSurface == 4)
+ {
+ if (fOldDiffusion == 100.0)
+ fDiffusion = 43712.0 / 655.36; // interpreted as %
+ }
+ else
+ {
+ if (basegfx::fTools::equalZero(fOldDiffusion - 43712.0 / 655.36, 0.0001))
+ fDiffusion = 100.0;
+ }
+
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = "ShadeMode";
+ aPropValue.Value <<= eShadeMode;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+
+ aPropValue.Name = "Metal";
+ aPropValue.Value <<= nSurface == 3 || nSurface == 4;
+ rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
+
+ if (nSurface == 3 || nSurface == 4)
+ {
+ aPropValue.Name = "MetalType";
+ aPropValue.Value <<= nSurface == 4
+ ? EnhancedCustomShapeMetalType::MetalMSCompatible
+ : EnhancedCustomShapeMetalType::MetalODF;
+ rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
+ }
+
+ if (!basegfx::fTools::equalZero(fOldSpecularity - fSpecularity, 0.0001))
+ {
+ aPropValue.Name = "Specularity";
+ aPropValue.Value <<= fSpecularity;
+ rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
+ }
+
+ if (!basegfx::fTools::equalZero(fOldDiffusion - fDiffusion, 0.0001))
+ {
+ aPropValue.Name = "Diffusion";
+ aPropValue.Value <<= fDiffusion;
+ rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
+ }
+ }
+ }
+ break;
+ case SID_EXTRUSION_LIGHTING_INTENSITY:
+ {
+ if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_LIGHTING_INTENSITY ) == SfxItemState::SET)
+ {
+ sal_Int32 nLevel = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_LIGHTING_INTENSITY)->GetValue();
+
+ double fBrightness; // c3DAmbientIntensity in MS Office
+ double fLevel1; // c3DKeyIntensity in MS Office
+ double fLevel2; // c3DFillIntensity in MS Office
+
+ // ToDo: "bright" values are different from MS Office. Should they be kept?
+ switch( nLevel )
+ {
+ case 0: // bright
+ fBrightness = 33.0; // ODF default.
+ fLevel1 = 66.0; // ODF default
+ fLevel2 = 66.0; // ODF default
+ break;
+ case 1: // normal
+ fBrightness = 15.0;
+ fLevel1 = 67.0;
+ fLevel2 = 37.0;
+ break;
+ case 2: // dim
+ fBrightness = 6.0;
+ fLevel1 = 79.0;
+ fLevel2 = 21.0;
+ break;
+ }
+
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = "Brightness";
+ aPropValue.Value <<= fBrightness;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+
+ aPropValue.Name = "FirstLightLevel";
+ aPropValue.Value <<= fLevel1;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+
+ aPropValue.Name = "SecondLightLevel";
+ aPropValue.Value <<= fLevel2;
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+
+ // If a user sets light preset 'Dim' in MS Office, MS Office sets second light to harsh.
+ // In other cases it is soft.
+ aPropValue.Name = "SecondLightHarsh";
+ aPropValue.Value <<= nLevel == 2;
+ rGeometryItem.SetPropertyValue(sExtrusion, aPropValue);
+ }
+ }
+ break;
+ case SID_EXTRUSION_LIGHTING_DIRECTION:
+ {
+ if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_EXTRUSION_LIGHTING_DIRECTION ) == SfxItemState::SET)
+ {
+ sal_Int32 nDirection = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_LIGHTING_DIRECTION)->GetValue();
+
+ if((nDirection >= 0) && (nDirection < 9))
+ {
+ const Direction3D * pLighting1Defaults;
+ const Direction3D * pLighting2Defaults;
+
+ getLightingDirectionDefaults( &pLighting1Defaults, &pLighting2Defaults );
+
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = "FirstLightDirection";
+ aPropValue.Value <<= pLighting1Defaults[nDirection];
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+
+ aPropValue.Name = "SecondLightDirection";
+ aPropValue.Value <<= pLighting2Defaults[nDirection];
+ rGeometryItem.SetPropertyValue( sExtrusion, aPropValue );
+ }
+ }
+ }
+ break;
+
+ }
+}
+
+void ExtrusionBar::execute( SdrView* pSdrView, SfxRequest const & rReq, SfxBindings& rBindings )
+{
+ sal_uInt16 nSID = rReq.GetSlot();
+ TranslateId pStrResId;
+
+ const bool bUndo = pSdrView && pSdrView->IsUndoEnabled();
+
+ switch( nSID )
+ {
+ case SID_EXTRUSION_TOGGLE:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ON_OFF;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_TILT_DOWN:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_DOWN;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_TILT_UP:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_UP;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_TILT_LEFT:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_LEFT;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_TILT_RIGHT:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ROTATE_RIGHT;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_DIRECTION:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_ORIENTATION;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_PROJECTION:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_PROJECTION;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_DEPTH:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_DEPTH;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_3D_COLOR:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_COLOR;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_SURFACE:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_SURFACE;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_LIGHTING_INTENSITY:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_BRIGHTNESS;
+ [[fallthrough]];
+ }
+ case SID_EXTRUSION_LIGHTING_DIRECTION:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_EXTRUSION_LIGHTING;
+
+ if (pSdrView)
+ {
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ for(size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ if( bUndo )
+ {
+ OUString aStr( SvxResId( pStrResId ) );
+ pSdrView->BegUndo( aStr );
+ pSdrView->AddUndo( pSdrView->GetModel()->GetSdrUndoFactory().CreateUndoAttrObject( *pObj ) );
+ }
+ SdrCustomShapeGeometryItem aGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ impl_execute( rReq, aGeometryItem, pObj );
+ pObj->SetMergedItem( aGeometryItem );
+ pObj->BroadcastObjectChange();
+ if( bUndo )
+ pSdrView->EndUndo();
+
+ // simulate a context change:
+ // force SelectionHasChanged() being called
+ // so that extrusion bar will be visible/hidden
+ pSdrView->MarkListHasChanged();
+ }
+ }
+ }
+ }
+ break;
+
+ case SID_EXTRUSION_DEPTH_DIALOG:
+ if( rReq.GetArgs() &&
+ (rReq.GetArgs()->GetItemState( SID_EXTRUSION_DEPTH ) == SfxItemState::SET) &&
+ (rReq.GetArgs()->GetItemState( SID_ATTR_METRIC ) == SfxItemState::SET))
+ {
+ double fDepth = rReq.GetArgs()->GetItem<SvxDoubleItem>(SID_EXTRUSION_DEPTH)->GetValue();
+ FieldUnit eUnit = static_cast<FieldUnit>(rReq.GetArgs()->GetItem<SfxUInt16Item>(SID_ATTR_METRIC)->GetValue());
+
+ ExtrusionDepthDialog aDlg(rReq.GetFrameWeld(), fDepth, eUnit);
+ sal_uInt16 nRet = aDlg.run();
+ if (nRet == RET_OK)
+ {
+ fDepth = aDlg.getDepth();
+
+ SvxDoubleItem aItem( fDepth, SID_EXTRUSION_DEPTH );
+ SfxPoolItem* aItems[] = { &aItem, nullptr };
+ rBindings.Execute( SID_EXTRUSION_DEPTH, const_cast<const SfxPoolItem**>(aItems) );
+ }
+ }
+ break;
+ }
+
+ if( nSID != SID_EXTRUSION_TOGGLE )
+ return;
+
+ static const sal_uInt16 SidArray[] = {
+ SID_EXTRUSION_TILT_DOWN,
+ SID_EXTRUSION_TILT_UP,
+ SID_EXTRUSION_TILT_LEFT,
+ SID_EXTRUSION_TILT_RIGHT,
+ SID_EXTRUSION_DEPTH_FLOATER,
+ SID_EXTRUSION_DIRECTION_FLOATER,
+ SID_EXTRUSION_LIGHTING_FLOATER,
+ SID_EXTRUSION_SURFACE_FLOATER,
+ SID_EXTRUSION_3D_COLOR,
+ SID_EXTRUSION_DEPTH,
+ SID_EXTRUSION_DIRECTION,
+ SID_EXTRUSION_PROJECTION,
+ SID_EXTRUSION_LIGHTING_DIRECTION,
+ SID_EXTRUSION_LIGHTING_INTENSITY,
+ SID_EXTRUSION_SURFACE,
+ 0 };
+
+ rBindings.Invalidate( SidArray );
+}
+
+static void getExtrusionDirectionState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ static constexpr OUStringLiteral sExtrusion = u"Extrusion";
+
+ const css::uno::Any* pAny;
+
+ double fFinalSkewAngle = -1;
+ bool bHasCustomShape = false;
+
+ for(size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+
+ // see if this is an extruded customshape
+ if( !bHasCustomShape )
+ {
+ const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
+ if( pAny_ )
+ *pAny_ >>= bHasCustomShape;
+
+ if( !bHasCustomShape )
+ continue;
+ }
+
+ bool bParallel = true;
+ Position3D aViewPoint( 3472, -3472, 25000 ); // MSO default
+ double fSkewAngle = -135; // MSO default
+
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "ProjectionMode" );
+ sal_Int16 nProjectionMode = sal_Int16();
+ if( pAny && ( *pAny >>= nProjectionMode ) )
+ bParallel = static_cast<ProjectionMode>(nProjectionMode) == ProjectionMode_PARALLEL;
+
+ if( bParallel )
+ {
+ double fSkew = 50.0;
+ EnhancedCustomShapeParameterPair aSkewPropPair;
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "Skew" );
+ if( pAny && ( *pAny >>= aSkewPropPair ) )
+ {
+ aSkewPropPair.First.Value >>= fSkew;
+ aSkewPropPair.Second.Value >>= fSkewAngle;
+ }
+ if ( fSkew == 0.0 )
+ fSkewAngle = 0.0;
+ else if ( fSkewAngle == 0.0 )
+ fSkewAngle = -360.0;
+ }
+ else
+ {
+ double fOriginX = 0.50;
+ double fOriginY = -0.50;
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "ViewPoint" );
+ if( pAny )
+ *pAny >>= aViewPoint;
+
+ EnhancedCustomShapeParameterPair aOriginPropPair;
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "Origin" );
+ if( pAny && ( *pAny >>= aOriginPropPair ) )
+ {
+ aOriginPropPair.First.Value >>= fOriginX;
+ aOriginPropPair.Second.Value >>= fOriginY;
+ }
+ fSkewAngle = -1;
+ const double e = 0.0001;
+ if( aViewPoint.PositionX > e )
+ {
+ if( aViewPoint.PositionY > e )
+ {
+ if( (fOriginX > e ) && ( fOriginY > e ) )
+ fSkewAngle = 135.0;
+ }
+ else if( aViewPoint.PositionY < -e )
+ {
+ if( ( fOriginX > e ) && ( fOriginY < -e ) )
+ fSkewAngle = -135.0;
+ }
+ else
+ {
+ if( ( fOriginX > e ) && ( fOriginY > -e ) && ( fOriginY < e ) )
+ fSkewAngle = 180.0;
+ }
+ }
+ else if( aViewPoint.PositionX < -e )
+ {
+ if( aViewPoint.PositionY < -e )
+ {
+ if( ( fOriginX < -e ) && ( fOriginY < -e ) )
+ fSkewAngle = -45.0;
+ }
+ else if( aViewPoint.PositionY > e )
+ {
+ if( ( fOriginX < -e ) && ( fOriginY > e ) )
+ fSkewAngle = 45.0;
+ }
+ else
+ {
+ if( ( fOriginX < e ) && ( fOriginY > -e ) && ( fOriginY < e ) )
+ fSkewAngle = -360.0;
+ }
+ }
+ else
+ {
+ if( aViewPoint.PositionY < -e )
+ {
+ if( ( fOriginX > -e ) && ( fOriginX < e ) && ( fOriginY < -e ) )
+ fSkewAngle = -90.0;
+ }
+ else if( aViewPoint.PositionY > e )
+ {
+ if( ( fOriginX > -e ) && ( fOriginX < e ) && ( fOriginY > e ) )
+ fSkewAngle = 90.0;
+ }
+ else
+ {
+ if( ( fOriginX > -e ) && ( fOriginX < e ) && ( fOriginY > -e ) && ( fOriginY < e ) )
+ fSkewAngle = 0.0;
+ }
+ }
+ }
+
+ if( rtl::math::approxEqual(fFinalSkewAngle, -1.0) )
+ {
+ fFinalSkewAngle = fSkewAngle;
+ }
+ else if( !rtl::math::approxEqual(fSkewAngle, fFinalSkewAngle) )
+ {
+ fFinalSkewAngle = -1.0;
+ }
+
+ if( rtl::math::approxEqual(fFinalSkewAngle, -1.0) )
+ break;
+ }
+ }
+
+ if( bHasCustomShape )
+ rSet.Put( SfxInt32Item( SID_EXTRUSION_DIRECTION, static_cast<sal_Int32>(fFinalSkewAngle) ) );
+ else
+ rSet.DisableItem( SID_EXTRUSION_DIRECTION );
+}
+
+static void getExtrusionProjectionState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ static constexpr OUStringLiteral sExtrusion = u"Extrusion";
+
+ const css::uno::Any* pAny;
+
+ sal_Int32 nFinalProjection = -1;
+ bool bHasCustomShape = false;
+
+ for(size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ // see if this is an extruded customshape
+ if( !bHasCustomShape )
+ {
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
+ if( pAny_ )
+ *pAny_ >>= bHasCustomShape;
+
+ if( !bHasCustomShape )
+ continue;
+ }
+
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+
+ bool bParallel = true;
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "ProjectionMode" );
+ ProjectionMode eProjectionMode;
+ if( pAny && ( *pAny >>= eProjectionMode ) )
+ bParallel = eProjectionMode == ProjectionMode_PARALLEL;
+
+ if( nFinalProjection == -1 )
+ {
+ nFinalProjection = bParallel ? 1 : 0;
+ }
+ else if( nFinalProjection != (bParallel ? 1 : 0) )
+ {
+ nFinalProjection = -1;
+ break;
+ }
+ }
+ }
+
+ if( bHasCustomShape )
+ rSet.Put( SfxInt32Item( SID_EXTRUSION_PROJECTION, nFinalProjection ) );
+ else
+ rSet.DisableItem( SID_EXTRUSION_PROJECTION );
+}
+
+static void getExtrusionSurfaceState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ static constexpr OUStringLiteral sExtrusion = u"Extrusion";
+
+ const css::uno::Any* pAny;
+
+ sal_Int32 nFinalSurface = -1;
+ bool bHasCustomShape = false;
+
+ for(size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+
+ // see if this is an extruded customshape
+ if( !bHasCustomShape )
+ {
+ const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
+ if( pAny_ )
+ *pAny_ >>= bHasCustomShape;
+
+ if( !bHasCustomShape )
+ continue;
+ }
+
+ sal_Int32 nSurface = 0; // wire frame
+
+ ShadeMode eShadeMode( ShadeMode_FLAT );
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"ShadeMode" );
+ if( pAny )
+ *pAny >>= eShadeMode;
+
+ if (eShadeMode != ShadeMode_DRAFT)
+ {
+ bool bMetal = false;
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Metal" );
+ if( pAny )
+ *pAny >>= bMetal;
+
+ if( bMetal )
+ {
+ nSurface = 3; // metal ODF
+ sal_Int16 eMetalType = EnhancedCustomShapeMetalType::MetalODF;
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"MetalType" );
+ if (pAny)
+ {
+ *pAny >>= eMetalType;
+ if (eMetalType == EnhancedCustomShapeMetalType::MetalMSCompatible)
+ nSurface = 4; // metal MS Office
+ }
+ }
+ else
+ {
+ double fSpecularity = 0;
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, u"Specularity" );
+ if( pAny )
+ *pAny >>= fSpecularity;
+
+ const double e = 0.0001;
+ if( (fSpecularity > -e) && (fSpecularity < e) )
+ {
+ nSurface = 1; // matte
+ }
+ else
+ {
+ nSurface = 2; // plastic
+ }
+ }
+ }
+
+ if( nFinalSurface == -1 )
+ {
+ nFinalSurface = nSurface;
+ }
+ else if( nFinalSurface != nSurface )
+ {
+ nFinalSurface = -1;
+ break;
+ }
+ }
+ }
+
+ if( bHasCustomShape )
+ rSet.Put( SfxInt32Item( SID_EXTRUSION_SURFACE, nFinalSurface ) );
+ else
+ rSet.DisableItem( SID_EXTRUSION_SURFACE );
+}
+
+static void getExtrusionDepthState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ static constexpr OUStringLiteral sExtrusion = u"Extrusion";
+
+ const css::uno::Any* pAny;
+
+ double fFinalDepth = -1;
+ bool bHasCustomShape = false;
+
+ for(size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+
+ // see if this is an extruded customshape
+ if( !bHasCustomShape )
+ {
+ const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
+ if( pAny_ )
+ *pAny_ >>= bHasCustomShape;
+
+ if( !bHasCustomShape )
+ continue;
+ }
+
+ double fDepth = 1270.0; // =36pt ODF default
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "Depth" );
+ if( pAny )
+ {
+ EnhancedCustomShapeParameterPair aDepthPropPair;
+ if ( *pAny >>= aDepthPropPair )
+ aDepthPropPair.First.Value >>= fDepth;
+ }
+
+ if( fFinalDepth == -1 )
+ {
+ fFinalDepth = fDepth;
+ }
+ else if( !rtl::math::approxEqual(fFinalDepth, fDepth) )
+ {
+ fFinalDepth = -1;
+ break;
+ }
+ }
+ }
+
+ if( pSdrView->GetModel() )
+ {
+ FieldUnit eUnit = pSdrView->GetModel()->GetUIUnit();
+ rSet.Put( SfxUInt16Item( SID_ATTR_METRIC, static_cast<sal_uInt16>(eUnit) ) );
+ }
+
+ if( bHasCustomShape )
+ rSet.Put( SvxDoubleItem( fFinalDepth, SID_EXTRUSION_DEPTH ) );
+ else
+ rSet.DisableItem( SID_EXTRUSION_DEPTH );
+}
+
+static bool compare_direction( const Direction3D& d1, const Direction3D& d2 )
+{
+ if( ((d1.DirectionX < 0) && (d2.DirectionX < 0)) || ((d1.DirectionX == 0) && (d2.DirectionX == 0)) || ((d1.DirectionX > 0) && (d2.DirectionX > 0)) )
+ {
+ if( ((d1.DirectionY < 0) && (d2.DirectionY < 0)) || ((d1.DirectionY == 0) && (d2.DirectionY == 0)) || ((d1.DirectionY > 0) && (d2.DirectionY > 0)) )
+ {
+ if( ((d1.DirectionZ < 0) && (d2.DirectionZ < 0)) || ((d1.DirectionZ == 0) && (d2.DirectionZ == 0)) || ((d1.DirectionZ > 0) && (d2.DirectionZ > 0)) )
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static void getExtrusionLightingDirectionState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ static constexpr OUStringLiteral sExtrusion = u"Extrusion";
+
+ const Direction3D * pLighting1Defaults;
+ const Direction3D * pLighting2Defaults;
+
+ getLightingDirectionDefaults( &pLighting1Defaults, &pLighting2Defaults );
+
+ const css::uno::Any* pAny;
+
+ int nFinalDirection = -1;
+ bool bHasCustomShape = false;
+
+ for(size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+
+ // see if this is an extruded customshape
+ if( !bHasCustomShape )
+ {
+ const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
+ if( pAny_ )
+ *pAny_ >>= bHasCustomShape;
+
+ if( !bHasCustomShape )
+ continue;
+ }
+
+ Direction3D aFirstLightDirection( 50000, 0, 10000 );
+ Direction3D aSecondLightDirection( -50000, 0, 10000 );
+
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "FirstLightDirection" );
+ if( pAny )
+ *pAny >>= aFirstLightDirection;
+
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "SecondLightDirection" );
+ if( pAny )
+ *pAny >>= aSecondLightDirection;
+
+ int nDirection = -1;
+
+ int j;
+ for( j = 0; j < 9; j++ )
+ {
+ if( compare_direction( aFirstLightDirection, pLighting1Defaults[j] ) &&
+ compare_direction( aSecondLightDirection, pLighting2Defaults[j] ))
+ {
+ nDirection = j;
+ break;
+ }
+ }
+
+ if( nFinalDirection == -1 )
+ {
+ nFinalDirection = nDirection;
+ }
+ else if( nDirection != nFinalDirection )
+ {
+ nFinalDirection = -1;
+ }
+
+ if( nFinalDirection == -1 )
+ break;
+ }
+ }
+
+ if( bHasCustomShape )
+ rSet.Put( SfxInt32Item( SID_EXTRUSION_LIGHTING_DIRECTION, static_cast<sal_Int32>(nFinalDirection) ) );
+ else
+ rSet.DisableItem( SID_EXTRUSION_LIGHTING_DIRECTION );
+}
+
+static void getExtrusionLightingIntensityState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ static constexpr OUStringLiteral sExtrusion = u"Extrusion";
+
+ const css::uno::Any* pAny;
+
+ int nFinalLevel = -1;
+ bool bHasCustomShape = false;
+
+ for(size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+
+ // see if this is an extruded customshape
+ if( !bHasCustomShape )
+ {
+ const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
+ if( pAny_ )
+ *pAny_ >>= bHasCustomShape;
+
+ if( !bHasCustomShape )
+ continue;
+ }
+
+ double fBrightness = 22178.0 / 655.36;
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "Brightness" );
+ if( pAny )
+ *pAny >>= fBrightness;
+
+ int nLevel;
+ if( fBrightness >= 30.0 )
+ {
+ nLevel = 0; // Bright
+ }
+ else if( fBrightness >= 10.0 )
+ {
+ nLevel = 1; // Normal;
+ }
+ else
+ {
+ nLevel = 2; // Dim
+ }
+
+ if( nFinalLevel == -1 )
+ {
+ nFinalLevel = nLevel;
+ }
+ else if( nFinalLevel != nLevel )
+ {
+ nFinalLevel = -1;
+ break;
+ }
+ }
+ }
+
+ if( bHasCustomShape )
+ rSet.Put( SfxInt32Item( SID_EXTRUSION_LIGHTING_INTENSITY, nFinalLevel ) );
+ else
+ rSet.DisableItem( SID_EXTRUSION_LIGHTING_INTENSITY );
+}
+
+static void getExtrusionColorState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ static constexpr OUStringLiteral sExtrusion = u"Extrusion";
+
+ const css::uno::Any* pAny;
+
+ bool bInit = false;
+ bool bAmbigius = false;
+ Color aFinalColor;
+ bool bHasCustomShape = false;
+
+ for(size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+
+ // see if this is an extruded customshape
+ if( !bHasCustomShape )
+ {
+ const Any* pAny_ = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
+ if( pAny_ )
+ *pAny_ >>= bHasCustomShape;
+
+ if( !bHasCustomShape )
+ continue;
+ }
+
+ Color aColor;
+
+ bool bUseColor = false;
+ pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "Color" );
+ if( pAny )
+ *pAny >>= bUseColor;
+
+ if( bUseColor )
+ {
+ const XSecondaryFillColorItem& rItem = pObj->GetMergedItem( XATTR_SECONDARYFILLCOLOR );
+ aColor = rItem.GetColorValue();
+ }
+ else
+ {
+ aColor = COL_AUTO;
+ }
+
+ if( !bInit )
+ {
+ aFinalColor = aColor;
+ bInit = true;
+ }
+ else if( aFinalColor != aColor )
+ {
+ bAmbigius = true;
+ break;
+ }
+ }
+ }
+
+ if( bAmbigius )
+ aFinalColor = COL_AUTO;
+
+ if( bHasCustomShape )
+ rSet.Put( SvxColorItem( aFinalColor, SID_EXTRUSION_3D_COLOR ) );
+ else
+ rSet.DisableItem( SID_EXTRUSION_3D_COLOR );
+}
+
+namespace svx {
+bool checkForSelectedCustomShapes( SdrView const * pSdrView, bool bOnlyExtruded )
+{
+ static constexpr OUStringLiteral sExtrusion = u"Extrusion";
+
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+ bool bFound = false;
+
+ for(size_t i=0;(i<nCount) && !bFound ; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ if( bOnlyExtruded )
+ {
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ const Any* pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, sExtrusion );
+ if( pAny )
+ *pAny >>= bFound;
+ }
+ else
+ {
+ bFound = true;
+ }
+ }
+ }
+
+ return bFound;
+}
+}
+
+void ExtrusionBar::getState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ getExtrusionDirectionState( pSdrView, rSet );
+ getExtrusionProjectionState( pSdrView, rSet );
+
+ const bool bOnlyExtrudedCustomShapes(checkForSelectedCustomShapes( pSdrView, true ));
+
+ if (! bOnlyExtrudedCustomShapes)
+ {
+ rSet.DisableItem( SID_EXTRUSION_TILT_DOWN );
+ rSet.DisableItem( SID_EXTRUSION_TILT_DOWN );
+ rSet.DisableItem( SID_EXTRUSION_TILT_UP );
+ rSet.DisableItem( SID_EXTRUSION_TILT_LEFT );
+ rSet.DisableItem( SID_EXTRUSION_TILT_RIGHT );
+ rSet.DisableItem( SID_EXTRUSION_3D_COLOR );
+ rSet.DisableItem( SID_EXTRUSION_DEPTH_FLOATER );
+ rSet.DisableItem( SID_EXTRUSION_DIRECTION_FLOATER );
+ rSet.DisableItem( SID_EXTRUSION_LIGHTING_FLOATER );
+ rSet.DisableItem( SID_EXTRUSION_SURFACE_FLOATER );
+ }
+
+ if( !checkForSelectedCustomShapes( pSdrView, false ) )
+ rSet.DisableItem( SID_EXTRUSION_TOGGLE );
+
+ getExtrusionDepthState( pSdrView, rSet );
+ getExtrusionSurfaceState( pSdrView, rSet );
+ getExtrusionLightingIntensityState( pSdrView, rSet );
+ getExtrusionLightingDirectionState( pSdrView, rSet );
+ getExtrusionColorState( pSdrView, rSet );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/toolbars/fontworkbar.cxx b/svx/source/toolbars/fontworkbar.cxx
new file mode 100644
index 000000000..7b2e8653b
--- /dev/null
+++ b/svx/source/toolbars/fontworkbar.cxx
@@ -0,0 +1,566 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdundo.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svx/unoapi.hxx>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
+#include <sal/log.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdpage.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sdasitm.hxx>
+#include <svx/gallery.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svl/itempool.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/bindings.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <editeng/kernitem.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/fontworkbar.hxx>
+#include <svx/fontworkgallery.hxx>
+
+
+using namespace ::svx;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+
+static void SetAlignmentState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ sal_Int32 nAlignment = -1;
+ for( size_t i = 0; i < nCount; ++i )
+ {
+ SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ sal_Int32 nOldAlignment = nAlignment;
+ const SdrTextHorzAdjustItem& rTextHorzAdjustItem = pObj->GetMergedItem( SDRATTR_TEXT_HORZADJUST );
+ const SdrTextFitToSizeTypeItem& rTextFitToSizeTypeItem = pObj->GetMergedItem( SDRATTR_TEXT_FITTOSIZE );
+ switch ( rTextHorzAdjustItem.GetValue() )
+ {
+ case SDRTEXTHORZADJUST_LEFT : nAlignment = 0; break;
+ case SDRTEXTHORZADJUST_CENTER : nAlignment = 1; break;
+ case SDRTEXTHORZADJUST_RIGHT : nAlignment = 2; break;
+ case SDRTEXTHORZADJUST_BLOCK :
+ {
+ auto const fit(rTextFitToSizeTypeItem.GetValue());
+ if (fit == drawing::TextFitToSizeType_NONE)
+ {
+ nAlignment = 3;
+ }
+ else if (fit == drawing::TextFitToSizeType_ALLLINES ||
+ fit == drawing::TextFitToSizeType_PROPORTIONAL)
+ {
+ nAlignment = 4;
+ }
+ }
+ }
+ if ( ( nOldAlignment != -1 ) && ( nOldAlignment != nAlignment ) )
+ {
+ nAlignment = -1;
+ break;
+ }
+ }
+ }
+ rSet.Put( SfxInt32Item( SID_FONTWORK_ALIGNMENT, nAlignment ) );
+}
+
+static void SetCharacterSpacingState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ sal_Int32 nCharacterSpacing = -1;
+ for( size_t i = 0; i < nCount; ++i )
+ {
+ SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ sal_Int32 nOldCharacterSpacing = nCharacterSpacing;
+ const SvxCharScaleWidthItem& rCharScaleWidthItem = pObj->GetMergedItem( EE_CHAR_FONTWIDTH );
+ nCharacterSpacing = rCharScaleWidthItem.GetValue();
+ if ( ( nOldCharacterSpacing != -1 ) && ( nOldCharacterSpacing != nCharacterSpacing ) )
+ {
+ nCharacterSpacing = -1;
+ break;
+ }
+ }
+ }
+ rSet.Put( SfxInt32Item( SID_FONTWORK_CHARACTER_SPACING, nCharacterSpacing ) );
+}
+
+
+static void SetKernCharacterPairsState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ bool bChecked = false;
+ for( size_t i = 0; i < nCount; ++i )
+ {
+ SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ const SvxKerningItem& rKerningItem = pObj->GetMergedItem( EE_CHAR_KERNING );
+ if ( rKerningItem.GetValue() )
+ bChecked = true;
+ }
+ }
+ rSet.Put( SfxBoolItem( SID_FONTWORK_KERN_CHARACTER_PAIRS, bChecked ) );
+}
+
+static void SetFontWorkShapeTypeState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+
+ OUString aFontWorkShapeType;
+
+ for( size_t i = 0; i < nCount; ++i )
+ {
+ SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ const Any* pAny = rGeometryItem.GetPropertyValueByName( "Type" );
+ if( pAny )
+ {
+ OUString aType;
+ if ( *pAny >>= aType )
+ {
+ if ( !aFontWorkShapeType.isEmpty() )
+ {
+ if ( aFontWorkShapeType != aType ) // different FontWorkShapeTypes selected ?
+ {
+ aFontWorkShapeType.clear();
+ break;
+ }
+ }
+ aFontWorkShapeType = aType;
+ }
+ }
+ }
+ }
+ rSet.Put( SfxStringItem( SID_FONTWORK_SHAPE_TYPE, aFontWorkShapeType ) );
+}
+
+// Declare the default interface. (The slotmap must not be empty, so
+// we enter something which never occurs here (hopefully).)
+static SfxSlot aFontworkBarSlots_Impl[] =
+{
+ { 0, SfxGroupId::NONE, SfxSlotMode::NONE, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, 0, SfxDisableFlags::NONE, nullptr }
+};
+
+SFX_IMPL_INTERFACE(FontworkBar, SfxShell)
+
+void FontworkBar::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Invisible, ToolbarId::Svx_Fontwork_Bar);
+}
+
+
+FontworkBar::FontworkBar(SfxViewShell* pViewShell )
+: SfxShell(pViewShell)
+{
+ DBG_ASSERT( pViewShell, "svx::FontworkBar::FontworkBar(), I need a viewshell!" );
+ if( pViewShell )
+ SetPool(&pViewShell->GetPool());
+
+ SetName( SvxResId( RID_SVX_FONTWORK_BAR ));
+}
+
+FontworkBar::~FontworkBar()
+{
+ SetRepeatTarget(nullptr);
+}
+
+namespace svx {
+bool checkForFontWork( const SdrObject* pObj )
+{
+ static constexpr OUStringLiteral sTextPath = u"TextPath";
+ bool bFound = false;
+
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ const SdrCustomShapeGeometryItem & rGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ const Any* pAny = rGeometryItem.GetPropertyValueByName( sTextPath, sTextPath );
+ if( pAny )
+ *pAny >>= bFound;
+ }
+
+ return bFound;
+}
+
+bool checkForSelectedFontWork( SdrView const * pSdrView )
+{
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+ bool bFound = false;
+ for(size_t i=0; (i<nCount) && !bFound ; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ bFound = checkForFontWork(pObj);
+ }
+ return bFound;
+}
+
+static void impl_execute( SfxRequest const & rReq, SdrCustomShapeGeometryItem& rGeometryItem, SdrObject* pObj )
+{
+ sal_uInt16 nSID = rReq.GetSlot();
+ switch( nSID )
+ {
+ case SID_FONTWORK_SAME_LETTER_HEIGHTS:
+ {
+ css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "TextPath", "SameLetterHeights" );
+ if( pAny )
+ {
+ bool bOn = false;
+ (*pAny) >>= bOn;
+ bOn = !bOn;
+ css::beans::PropertyValue aPropValue;
+ aPropValue.Name = "SameLetterHeights";
+ aPropValue.Value <<= bOn;
+ rGeometryItem.SetPropertyValue("TextPath", aPropValue);
+ }
+ }
+ break;
+
+ case SID_FONTWORK_ALIGNMENT:
+ {
+ if( rReq.GetArgs() && rReq.GetArgs()->GetItemState( SID_FONTWORK_ALIGNMENT ) == SfxItemState::SET )
+ {
+ sal_Int32 nValue = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_FONTWORK_ALIGNMENT)->GetValue();
+ if ( ( nValue >= 0 ) && ( nValue < 5 ) )
+ {
+ drawing::TextFitToSizeType eFTS = drawing::TextFitToSizeType_NONE;
+ SdrTextHorzAdjust eHorzAdjust;
+ switch ( nValue )
+ {
+ case 4 : eFTS = drawing::TextFitToSizeType_ALLLINES; [[fallthrough]];
+ case 3 : eHorzAdjust = SDRTEXTHORZADJUST_BLOCK; break;
+ default: eHorzAdjust = SDRTEXTHORZADJUST_LEFT; break;
+ case 1 : eHorzAdjust = SDRTEXTHORZADJUST_CENTER; break;
+ case 2 : eHorzAdjust = SDRTEXTHORZADJUST_RIGHT; break;
+ }
+ pObj->SetMergedItem( SdrTextHorzAdjustItem( eHorzAdjust ) );
+ pObj->SetMergedItem( SdrTextFitToSizeTypeItem( eFTS ) );
+ pObj->BroadcastObjectChange();
+ }
+ }
+ }
+ break;
+
+ case SID_FONTWORK_CHARACTER_SPACING:
+ {
+ if( rReq.GetArgs() && ( rReq.GetArgs()->GetItemState( SID_FONTWORK_CHARACTER_SPACING ) == SfxItemState::SET ) )
+ {
+ sal_Int32 nCharSpacing = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_FONTWORK_CHARACTER_SPACING)->GetValue();
+ pObj->SetMergedItem( SvxCharScaleWidthItem( static_cast<sal_uInt16>(nCharSpacing), EE_CHAR_FONTWIDTH ) );
+ pObj->BroadcastObjectChange();
+ }
+ }
+ break;
+
+ case SID_FONTWORK_KERN_CHARACTER_PAIRS:
+ {
+ if( rReq.GetArgs() && ( rReq.GetArgs()->GetItemState( SID_FONTWORK_KERN_CHARACTER_PAIRS ) == SfxItemState::SET ) )
+ {
+ // sal_Bool bKernCharacterPairs = ((const SfxBoolItem*)rReq.GetArgs()->GetItem(SID_FONTWORK_KERN_CHARACTER_PAIRS))->GetValue();
+//TODO: pObj->SetMergedItem( SvxCharScaleWidthItem( (sal_uInt16)nCharSpacing, EE_CHAR_FONTWIDTH ) );
+ pObj->BroadcastObjectChange();
+ }
+ }
+ break;
+ }
+}
+
+static void GetGeometryForCustomShape( SdrCustomShapeGeometryItem& rGeometryItem, const OUString& rCustomShape )
+{
+ static const OUStringLiteral sType( u"Type" );
+
+ css::beans::PropertyValue aPropVal;
+ aPropVal.Name = sType;
+ aPropVal.Value <<= rCustomShape;
+ rGeometryItem.SetPropertyValue( aPropVal );
+
+ static const OUStringLiteral sAdjustmentValues( u"AdjustmentValues" );
+ static const OUStringLiteral sCoordinateOrigin( u"CoordinateOrigin" );
+ static const OUStringLiteral sCoordinateSize( u"CoordinateSize" );
+ static const OUStringLiteral sEquations( u"Equations" );
+ static const OUStringLiteral sHandles( u"Handles" );
+ static const OUStringLiteral sPath( u"Path" );
+ rGeometryItem.ClearPropertyValue( sAdjustmentValues );
+ rGeometryItem.ClearPropertyValue( sCoordinateOrigin );
+ rGeometryItem.ClearPropertyValue( sCoordinateSize );
+ rGeometryItem.ClearPropertyValue( sEquations );
+ rGeometryItem.ClearPropertyValue( sHandles );
+ rGeometryItem.ClearPropertyValue( sPath );
+
+ /* SJ: CustomShapes that are available in the gallery are having the highest
+ priority, so we will take a look there before taking the internal default */
+
+ if ( !GalleryExplorer::GetSdrObjCount( GALLERY_THEME_POWERPOINT ) )
+ return;
+
+ std::vector< OUString > aObjList;
+ if ( !GalleryExplorer::FillObjListTitle( GALLERY_THEME_POWERPOINT, aObjList ) )
+ return;
+
+ for ( std::vector<OUString>::size_type i = 0; i < aObjList.size(); i++ )
+ {
+ if ( aObjList[ i ].equalsIgnoreAsciiCase( rCustomShape ) )
+ {
+ FmFormModel aFormModel;
+ SfxItemPool& rPool(aFormModel.GetItemPool());
+ rPool.FreezeIdRanges();
+
+ if ( GalleryExplorer::GetSdrObj( GALLERY_THEME_POWERPOINT, i, &aFormModel ) )
+ {
+ const SdrObject* pSourceObj = nullptr;
+ if (aFormModel.GetPageCount() > 0)
+ pSourceObj = aFormModel.GetPage( 0 )->GetObj( 0 );
+ SAL_WARN_IF(!pSourceObj, "svx.form", "No content in gallery custom shape '" << rCustomShape << "'" );
+ if( pSourceObj )
+ {
+ PropertyValue aPropVal_;
+ const SdrCustomShapeGeometryItem& rSourceGeometry = pSourceObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+ const css::uno::Any* pAny = rSourceGeometry.GetPropertyValueByName( sType );
+ if ( pAny )
+ {
+ aPropVal_.Name = sType;
+ aPropVal_.Value = *pAny;
+ rGeometryItem.SetPropertyValue( aPropVal_ );
+ }
+ pAny = rSourceGeometry.GetPropertyValueByName( sAdjustmentValues );
+ if ( pAny )
+ {
+ aPropVal_.Name = sAdjustmentValues;
+ aPropVal_.Value = *pAny;
+ rGeometryItem.SetPropertyValue( aPropVal_ );
+ }
+ pAny = rSourceGeometry.GetPropertyValueByName( sCoordinateOrigin );
+ if ( pAny )
+ {
+ aPropVal_.Name = sCoordinateOrigin;
+ aPropVal_.Value = *pAny;
+ rGeometryItem.SetPropertyValue( aPropVal_ );
+ }
+ pAny = rSourceGeometry.GetPropertyValueByName( sCoordinateSize );
+ if ( pAny )
+ {
+ aPropVal_.Name = sCoordinateSize;
+ aPropVal_.Value = *pAny;
+ rGeometryItem.SetPropertyValue( aPropVal_ );
+ }
+ pAny = rSourceGeometry.GetPropertyValueByName( sEquations );
+ if ( pAny )
+ {
+ aPropVal_.Name = sEquations;
+ aPropVal_.Value = *pAny;
+ rGeometryItem.SetPropertyValue( aPropVal_ );
+ }
+ pAny = rSourceGeometry.GetPropertyValueByName( sHandles );
+ if ( pAny )
+ {
+ aPropVal_.Name = sHandles;
+ aPropVal_.Value = *pAny;
+ rGeometryItem.SetPropertyValue( aPropVal_ );
+ }
+ pAny = rSourceGeometry.GetPropertyValueByName( sPath );
+ if ( pAny )
+ {
+ aPropVal_.Name = sPath;
+ aPropVal_.Value = *pAny;
+ rGeometryItem.SetPropertyValue( aPropVal_ );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void FontworkBar::execute( SdrView& rSdrView, SfxRequest const & rReq, SfxBindings& rBindings )
+{
+ TranslateId pStrResId;
+
+ sal_uInt16 nSID = rReq.GetSlot();
+ switch( nSID )
+ {
+ case SID_FONTWORK_GALLERY_FLOATER:
+ {
+ std::shared_ptr<FontWorkGalleryDialog> pDlg = std::make_shared<FontWorkGalleryDialog>(rReq.GetFrameWeld(), rSdrView);
+ weld::DialogController::runAsync(pDlg, [](int){});
+ }
+ break;
+
+ case SID_FONTWORK_SHAPE_TYPE:
+ {
+ OUString aCustomShape;
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if ( pArgs )
+ {
+ const SfxStringItem& rItm = static_cast<const SfxStringItem&>(pArgs->Get( rReq.GetSlot() ));
+ aCustomShape = rItm.GetValue();
+ }
+ if ( !aCustomShape.isEmpty() )
+ {
+ const SdrMarkList& rMarkList = rSdrView.GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+ for( size_t i = 0; i < nCount; ++i )
+ {
+ SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
+ if( auto pCustomShape = dynamic_cast<SdrObjCustomShape*>( pObj) )
+ {
+ const bool bUndo = rSdrView.IsUndoEnabled();
+
+ if( bUndo )
+ {
+ OUString aStr( SvxResId( RID_SVXSTR_UNDO_APPLY_FONTWORK_SHAPE ) );
+ rSdrView.BegUndo(aStr);
+ rSdrView.AddUndo(rSdrView.GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
+ }
+ SdrCustomShapeGeometryItem aGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ GetGeometryForCustomShape( aGeometryItem, aCustomShape );
+ pObj->SetMergedItem( aGeometryItem );
+
+ Reference< drawing::XShape > aXShape = GetXShapeForSdrObject( pCustomShape );
+ if ( aXShape.is() )
+ {
+ Reference< drawing::XEnhancedCustomShapeDefaulter > xDefaulter( aXShape, UNO_QUERY );
+ if( xDefaulter.is() )
+ xDefaulter->createCustomShapeDefaults( aCustomShape );
+ }
+
+ pObj->BroadcastObjectChange();
+ if (bUndo)
+ rSdrView.EndUndo();
+ rSdrView.AdjustMarkHdl(); //HMH sal_True );
+ rBindings.Invalidate( SID_FONTWORK_SHAPE_TYPE );
+ }
+ }
+ }
+ }
+ break;
+
+ case SID_FONTWORK_CHARACTER_SPACING_DIALOG :
+ {
+ if( rReq.GetArgs() && ( rReq.GetArgs()->GetItemState( SID_FONTWORK_CHARACTER_SPACING ) == SfxItemState::SET ) )
+ {
+ sal_Int32 nCharSpacing = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_FONTWORK_CHARACTER_SPACING)->GetValue();
+ FontworkCharacterSpacingDialog aDlg(rReq.GetFrameWeld(), nCharSpacing);
+ sal_uInt16 nRet = aDlg.run();
+ if (nRet != RET_CANCEL)
+ {
+ SfxInt32Item aItem(SID_FONTWORK_CHARACTER_SPACING, aDlg.getScale());
+ SfxPoolItem* aItems[] = { &aItem, nullptr };
+ rBindings.Execute( SID_FONTWORK_CHARACTER_SPACING, const_cast<const SfxPoolItem**>(aItems) );
+ }
+ }
+ }
+ break;
+
+ case SID_FONTWORK_SHAPE:
+ case SID_FONTWORK_ALIGNMENT:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_FONTWORK_ALIGNMENT;
+ [[fallthrough]];
+ }
+ case SID_FONTWORK_CHARACTER_SPACING:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_FONTWORK_CHARACTER_SPACING;
+ [[fallthrough]];
+ }
+ case SID_FONTWORK_KERN_CHARACTER_PAIRS:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_FONTWORK_CHARACTER_SPACING;
+ [[fallthrough]];
+ }
+ case SID_FONTWORK_SAME_LETTER_HEIGHTS:
+ {
+ if ( !pStrResId )
+ pStrResId = RID_SVXSTR_UNDO_APPLY_FONTWORK_SAME_LETTER_HEIGHT;
+
+ const SdrMarkList& rMarkList = rSdrView.GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+ for( size_t i = 0; i < nCount; ++i )
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if( dynamic_cast<const SdrObjCustomShape*>( pObj) != nullptr )
+ {
+ const bool bUndo = rSdrView.IsUndoEnabled();
+ if( bUndo )
+ {
+ OUString aStr( SvxResId( pStrResId ) );
+ rSdrView.BegUndo(aStr);
+ rSdrView.AddUndo(rSdrView.GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
+ }
+ SdrCustomShapeGeometryItem aGeometryItem( pObj->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ impl_execute( rReq, aGeometryItem, pObj );
+ pObj->SetMergedItem( aGeometryItem );
+ pObj->BroadcastObjectChange();
+ if (bUndo)
+ rSdrView.EndUndo();
+ }
+ }
+ }
+ break;
+ }
+}
+
+void FontworkBar::getState( SdrView const * pSdrView, SfxItemSet& rSet )
+{
+ if ( checkForSelectedFontWork( pSdrView ) )
+ {
+ SetAlignmentState( pSdrView, rSet );
+ SetCharacterSpacingState( pSdrView, rSet );
+ SetKernCharacterPairsState( pSdrView, rSet );
+ SetFontWorkShapeTypeState( pSdrView, rSet );
+ }
+ else
+ {
+ rSet.DisableItem( SID_FONTWORK_ALIGNMENT_FLOATER );
+ rSet.DisableItem( SID_FONTWORK_ALIGNMENT );
+ rSet.DisableItem( SID_FONTWORK_CHARACTER_SPACING_FLOATER );
+ rSet.DisableItem( SID_FONTWORK_CHARACTER_SPACING );
+ rSet.DisableItem( SID_FONTWORK_KERN_CHARACTER_PAIRS );
+ rSet.DisableItem( SID_FONTWORK_SAME_LETTER_HEIGHTS );
+ rSet.DisableItem( SID_FONTWORK_SHAPE_TYPE );
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/uitest/sdrobject.cxx b/svx/source/uitest/sdrobject.cxx
new file mode 100644
index 000000000..bc72ee2a8
--- /dev/null
+++ b/svx/source/uitest/sdrobject.cxx
@@ -0,0 +1,206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <svx/uiobject.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/SvxColorValueSet.hxx>
+#include <tools/fract.hxx>
+#include <vcl/window.hxx>
+#include <memory>
+
+SdrUIObject::~SdrUIObject() {}
+
+StringMap SdrUIObject::get_state()
+{
+ StringMap aMap;
+ SdrObject* pObject = get_object();
+
+ if (!pObject)
+ return aMap;
+
+ aMap["Name"] = pObject->GetName();
+ aMap["Description"] = pObject->GetDescription();
+ aMap["Title"] = pObject->GetTitle();
+ aMap["Z-Order"] = OUString::number(pObject->GetOrdNum());
+ aMap["Layer"] = OUString::number(pObject->GetLayer().get());
+ aMap["IsGroupObject"] = OUString::boolean(pObject->IsGroupObject());
+ aMap["IsPolyObject"] = OUString::boolean(pObject->IsPolyObj());
+ aMap["PointCount"] = OUString::number(pObject->GetPointCount());
+ aMap["HasTextEdit"] = OUString::boolean(pObject->HasTextEdit());
+ aMap["HasMacro"] = OUString::boolean(pObject->HasMacro());
+ aMap["IsClosed"] = OUString::boolean(pObject->IsClosedObj());
+ aMap["IsEdgeObject"] = OUString::boolean(pObject->IsEdgeObj());
+ aMap["Is3DObject"] = OUString::boolean(pObject->Is3DObj());
+ aMap["IsUNOObject"] = OUString::boolean(pObject->IsUnoObj());
+ aMap["MoveProtected"] = OUString::boolean(pObject->IsMoveProtect());
+ aMap["ResizeProtected"] = OUString::boolean(pObject->IsResizeProtect());
+ aMap["Printable"] = OUString::boolean(pObject->IsPrintable());
+ aMap["Visible"] = OUString::boolean(pObject->IsVisible());
+ aMap["HasText"] = OUString::boolean(pObject->HasText());
+
+ return aMap;
+}
+
+void SdrUIObject::execute(const OUString& rAction, const StringMap& rParameters)
+{
+ SdrObject* pObj = get_object();
+ if (!pObj)
+ return;
+
+ if (rAction == "MOVE")
+ {
+ auto itrNX = rParameters.find("X");
+ if (itrNX == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter X");
+
+ auto itrNY = rParameters.find("Y");
+ if (itrNY == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter Y");
+
+ tools::Long nX = itrNX->second.toInt32();
+ tools::Long nY = itrNY->second.toInt32();
+ Size aMoveRange(nX, nY);
+ pObj->Move(aMoveRange);
+ }
+ else if (rAction == "RESIZE")
+ {
+ auto itrNX = rParameters.find("X");
+ if (itrNX == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter X");
+
+ auto itrNY = rParameters.find("Y");
+ if (itrNY == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter Y");
+
+ tools::Long nX = itrNX->second.toInt32();
+ tools::Long nY = itrNY->second.toInt32();
+ Point aPos(nX, nY);
+
+ auto itrFracX = rParameters.find("FRAC_X");
+ if (itrFracX == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter FRAC_X");
+ double nFracX = itrFracX->second.toDouble();
+ Fraction aFracX(nFracX);
+
+ auto itrFracY = rParameters.find("FRAC_Y");
+ if (itrFracY == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter FRAC_Y");
+ double nFracY = itrFracY->second.toDouble();
+ Fraction aFracY(nFracY);
+ pObj->Resize(aPos, aFracX, aFracY, true /*bRelative*/);
+ }
+ else if (rAction == "CROP")
+ {
+ // RotateFlyFrame3: Note: Crop does nothing at SdrObject
+ // anymore, see comment at SdrObject::NbcCrop
+ auto itrNX = rParameters.find("X");
+ if (itrNX == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter X");
+
+ auto itrNY = rParameters.find("Y");
+ if (itrNY == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter Y");
+
+ const double fX(itrNX->second.toDouble());
+ const double fY(itrNY->second.toDouble());
+ const basegfx::B2DPoint aPos(fX, fY);
+
+ auto itrFracX = rParameters.find("FRAC_X");
+ if (itrFracX == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter FRAC_X");
+ const double fFracX(itrFracX->second.toDouble());
+
+ auto itrFracY = rParameters.find("FRAC_Y");
+ if (itrFracY == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter FRAC_Y");
+ const double fFracY(itrFracY->second.toDouble());
+
+ pObj->Crop(aPos, fFracX, fFracY);
+ }
+ else if (rAction == "ROTATE")
+ {
+ auto itrNX = rParameters.find("X");
+ if (itrNX == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter X");
+
+ auto itrNY = rParameters.find("Y");
+ if (itrNY == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter Y");
+
+ tools::Long nX = itrNX->second.toInt32();
+ tools::Long nY = itrNY->second.toInt32();
+ Point aPos(nX, nY);
+
+ auto itrAngle = rParameters.find("ANGLE");
+ if (itrAngle == rParameters.end())
+ throw css::uno::RuntimeException("missing parameter ANGLE");
+
+ double nAngle = itrAngle->second.toDouble();
+ pObj->Rotate(aPos, Degree100(sal_Int32(nAngle)), 0, 0);
+ }
+ else if (rAction == "Mirror")
+ {
+ pObj->Mirror(Point(), Point());
+ }
+ else if (rAction == "SHEAR")
+ {
+ pObj->Shear(Point(), 0_deg100 /*nAngle*/, 0, false);
+ }
+}
+
+OUString SdrUIObject::get_type() const { return "SdrUIObject"; }
+
+SvxColorValueSetUIObject::SvxColorValueSetUIObject(vcl::Window* pColorSetWin)
+ : DrawingAreaUIObject(pColorSetWin)
+ , mpColorSet(static_cast<SvxColorValueSet*>(mpController))
+{
+}
+
+void SvxColorValueSetUIObject::execute(const OUString& rAction, const StringMap& rParameters)
+{
+ if (rAction == "CHOOSE")
+ {
+ if (rParameters.find("POS") != rParameters.end())
+ {
+ OUString aIndexStr = rParameters.find("POS")->second;
+ sal_Int32 nIndex = aIndexStr.toInt32();
+ mpColorSet->SelectItem(nIndex);
+ mpColorSet->Select();
+ }
+ }
+ else
+ DrawingAreaUIObject::execute(rAction, rParameters);
+}
+
+std::unique_ptr<UIObject> SvxColorValueSetUIObject::create(vcl::Window* pWindow)
+{
+ return std::unique_ptr<UIObject>(new SvxColorValueSetUIObject(pWindow));
+}
+
+OUString SvxColorValueSetUIObject::get_name() const { return "SvxColorValueSetUIObject"; }
+
+StringMap SvxColorValueSetUIObject::get_state()
+{
+ StringMap aMap = DrawingAreaUIObject::get_state();
+ aMap["CurrColorId"] = OUString::number(mpColorSet->GetSelectedItemId());
+ aMap["CurrColorPos"] = OUString::number(mpColorSet->GetSelectItemPos());
+ aMap["ColorsCount"] = OUString::number(mpColorSet->GetItemCount());
+ aMap["ColCount"] = OUString::number(mpColorSet->GetColCount());
+ aMap["ColorText"] = mpColorSet->GetItemText(mpColorSet->GetSelectedItemId());
+ Color currColor = mpColorSet->GetItemColor(mpColorSet->GetSelectedItemId());
+ aMap["R"] = OUString::number(currColor.GetRed());
+ aMap["G"] = OUString::number(currColor.GetGreen());
+ aMap["B"] = OUString::number(currColor.GetBlue());
+ aMap["RGB"] = "(" + OUString::number(currColor.GetRed()) + ","
+ + OUString::number(currColor.GetGreen()) + ","
+ + OUString::number(currColor.GetBlue()) + ")";
+ return aMap;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/uitest/uiobject.cxx b/svx/source/uitest/uiobject.cxx
new file mode 100644
index 000000000..1c56b9b61
--- /dev/null
+++ b/svx/source/uitest/uiobject.cxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <memory>
+#include <uiobject.hxx>
+#include <svx/charmap.hxx>
+#include <svx/numvset.hxx>
+#include <vcl/window.hxx>
+
+SvxShowCharSetUIObject::SvxShowCharSetUIObject(const VclPtr<vcl::Window>& rCharSetWin)
+ : DrawingAreaUIObject(rCharSetWin)
+ , mpCharSet(static_cast<SvxShowCharSet*>(mpController))
+{
+}
+
+void SvxShowCharSetUIObject::execute(const OUString& rAction,
+ const StringMap& rParameters)
+{
+ if (rAction == "SELECT")
+ {
+ if (rParameters.find("INDEX") != rParameters.end())
+ {
+ OUString aIndexStr = rParameters.find("INDEX")->second;
+
+ sal_Int32 nIndex = aIndexStr.toInt32();
+ mpCharSet->OutputIndex(nIndex);
+ }
+ else if (rParameters.find("COLUMN") != rParameters.end() &&
+ rParameters.find("ROW") != rParameters.end())
+ {
+ OUString aColStr = rParameters.find("COLUMN")->second;
+ OUString aRowStr = rParameters.find("ROW")->second;
+
+ sal_Int32 nColumn = aColStr.toInt32();
+ sal_Int32 nRow = aRowStr.toInt32();
+
+ sal_Int32 nIndex = nColumn * COLUMN_COUNT + nRow;
+ mpCharSet->OutputIndex(nIndex);
+ }
+ }
+ else
+ WindowUIObject::execute(rAction, rParameters);
+}
+
+std::unique_ptr<UIObject> SvxShowCharSetUIObject::create(vcl::Window* pWindow)
+{
+ return std::unique_ptr<UIObject>(new SvxShowCharSetUIObject(pWindow));
+}
+
+OUString SvxShowCharSetUIObject::get_name() const
+{
+ return "SvxShowCharSetUIObject";
+}
+
+
+SvxNumValueSetUIObject::SvxNumValueSetUIObject(vcl::Window* pNumValueSetWin)
+ : DrawingAreaUIObject(pNumValueSetWin)
+ , mpNumValueSet(static_cast<SvxNumValueSet*>(mpController))
+{
+}
+
+void SvxNumValueSetUIObject::execute(const OUString& rAction,
+ const StringMap& rParameters)
+{
+ if (rAction == "CHOOSE")
+ {
+ if (rParameters.find("POS") != rParameters.end())
+ {
+ OUString aIndexStr = rParameters.find("POS")->second;
+ sal_Int32 nIndex = aIndexStr.toInt32();
+ mpNumValueSet->SelectItem(nIndex);
+ mpNumValueSet->Select();
+ }
+ }
+ else
+ DrawingAreaUIObject::execute(rAction, rParameters);
+}
+
+std::unique_ptr<UIObject> SvxNumValueSetUIObject::create(vcl::Window* pWindow)
+{
+ return std::unique_ptr<UIObject>(new SvxNumValueSetUIObject(pWindow));
+}
+
+OUString SvxNumValueSetUIObject::get_name() const
+{
+ return "SvxNumValueSetUIObject";
+}
+
+StringMap SvxNumValueSetUIObject::get_state()
+{
+ StringMap aMap = WindowUIObject::get_state();
+ aMap["SelectedItemId"] = OUString::number( mpNumValueSet->GetSelectedItemId() );
+ aMap["SelectedItemPos"] = OUString::number( mpNumValueSet->GetSelectItemPos() );
+ aMap["ItemsCount"] = OUString::number(mpNumValueSet->GetItemCount());
+ aMap["ItemText"] = mpNumValueSet->GetItemText(mpNumValueSet->GetSelectedItemId());
+ return aMap;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.cxx b/svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.cxx
new file mode 100644
index 000000000..ed81ba92f
--- /dev/null
+++ b/svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.cxx
@@ -0,0 +1,676 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "chinese_dictionarydialog.hxx"
+#include <cppuhelper/bootstrap.hxx>
+#include <com/sun/star/i18n/TextConversionOption.hpp>
+#include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
+#include <com/sun/star/linguistic2/ConversionPropertyType.hpp>
+#include <com/sun/star/linguistic2/ConversionDictionaryList.hpp>
+#include <com/sun/star/linguistic2/XConversionPropertyType.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <o3tl/safeint.hxx>
+#include <unotools/lingucfg.hxx>
+#include <unotools/linguprops.hxx>
+#include <osl/diagnose.h>
+
+namespace textconversiondlgs
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+DictionaryList::DictionaryList(std::unique_ptr<weld::TreeView> xControl)
+ : m_xControl(std::move(xControl))
+ , m_xIter(m_xControl->make_iterator())
+ , m_pED_Term(nullptr)
+ , m_pED_Mapping(nullptr)
+ , m_pLB_Property(nullptr)
+{
+ m_xControl->make_sorted();
+}
+
+OUString DictionaryList::getPropertyTypeName( sal_Int16 nConversionPropertyType ) const
+{
+ if (!m_pLB_Property || !m_pLB_Property->get_count())
+ return OUString();
+
+ sal_uInt16 nPos = static_cast<sal_uInt16>( nConversionPropertyType )-1;
+ if (nPos < m_pLB_Property->get_count())
+ return m_pLB_Property->get_text(nPos);
+ return m_pLB_Property->get_text(0);
+}
+
+void DictionaryList::save()
+{
+ if (!m_xDictionary.is())
+ return;
+
+ Reference< linguistic2::XConversionPropertyType > xPropertyType( m_xDictionary, uno::UNO_QUERY );
+
+ sal_Int32 nN;
+ DictionaryEntry* pE;
+
+ for( nN = m_aToBeDeleted.size(); nN--; )
+ {
+ pE = m_aToBeDeleted[nN];
+ m_xDictionary->removeEntry( pE->m_aTerm, pE->m_aMapping );
+ }
+ int nRowCount = m_xControl->n_children();
+ for( nN = nRowCount; nN--; )
+ {
+ pE = getEntryOnPos( nN );
+ if(pE->m_bNewEntry)
+ {
+ try
+ {
+ m_xDictionary->addEntry( pE->m_aTerm, pE->m_aMapping );
+ xPropertyType->setPropertyType( pE->m_aTerm, pE->m_aMapping, pE->m_nConversionPropertyType );
+ }
+ catch( uno::Exception& )
+ {
+
+ }
+ }
+ }
+ Reference< util::XFlushable > xFlush( m_xDictionary, uno::UNO_QUERY );
+ if( xFlush.is() )
+ xFlush->flush();
+}
+
+void DictionaryList::deleteAll()
+{
+ sal_Int32 nN;
+ int nRowCount = m_xControl->n_children();
+ for( nN = nRowCount; nN--; )
+ deleteEntryOnPos( nN );
+ for( nN = m_aToBeDeleted.size(); nN--; )
+ {
+ DictionaryEntry* pE = m_aToBeDeleted[nN];
+ delete pE;
+ }
+ m_aToBeDeleted.clear();
+}
+
+void DictionaryList::refillFromDictionary( sal_Int32 nTextConversionOptions )
+{
+ deleteAll();
+
+ if(!m_xDictionary.is())
+ return;
+
+ const Sequence< OUString > aLeftList( m_xDictionary->getConversionEntries( linguistic2::ConversionDirection_FROM_LEFT ) );
+
+ Reference< linguistic2::XConversionPropertyType > xPropertyType( m_xDictionary, uno::UNO_QUERY );
+
+ OUString aRight;
+ sal_Int16 nConversionPropertyType;
+
+ for(const OUString& aLeft : aLeftList)
+ {
+ Sequence< OUString > aRightList( m_xDictionary->getConversions(
+ aLeft, 0, aLeft.getLength()
+ , linguistic2::ConversionDirection_FROM_LEFT, nTextConversionOptions ) );
+
+ if(aRightList.getLength()!=1)
+ {
+ OSL_FAIL("The Chinese Translation Dictionary should have exactly one Mapping for each term.");
+ continue;
+ }
+
+ aRight = aRightList[0];
+ nConversionPropertyType = linguistic2::ConversionPropertyType::OTHER;
+ if(xPropertyType.is())
+ nConversionPropertyType = xPropertyType->getPropertyType(aLeft, aRight);
+
+ DictionaryEntry* pEntry = new DictionaryEntry( aLeft, aRight, nConversionPropertyType );
+
+ m_xControl->append(m_xIter.get());
+ m_xControl->set_text(*m_xIter, pEntry->m_aTerm, 0);
+ m_xControl->set_text(*m_xIter, pEntry->m_aMapping, 1);
+ m_xControl->set_text(*m_xIter, getPropertyTypeName(pEntry->m_nConversionPropertyType), 2);
+ m_xControl->set_id(*m_xIter, weld::toId(pEntry));
+ }
+}
+
+DictionaryEntry* DictionaryList::getFirstSelectedEntry() const
+{
+ DictionaryEntry* pRet=nullptr;
+ int nN = m_xControl->get_selected_index();
+ if (nN != -1)
+ pRet = getEntryOnPos( nN );
+ return pRet;
+}
+
+DictionaryEntry* DictionaryList::getEntryOnPos(sal_Int32 nPos) const
+{
+ OUString sLBEntry = m_xControl->get_id(nPos);
+ return weld::fromId<DictionaryEntry*>(sLBEntry);
+}
+
+DictionaryEntry* DictionaryList::getTermEntry( std::u16string_view rTerm ) const
+{
+ int nRowCount = m_xControl->n_children();
+ for( sal_Int32 nN = nRowCount; nN--; )
+ {
+ DictionaryEntry* pE = getEntryOnPos( nN );
+ if( pE && rTerm == pE->m_aTerm )
+ return pE;
+ }
+ return nullptr;
+}
+
+bool DictionaryList::hasTerm( std::u16string_view rTerm ) const
+{
+ return getTermEntry(rTerm) !=nullptr ;
+}
+
+void DictionaryList::addEntry(const OUString& rTerm, const OUString& rMapping,
+ sal_Int16 nConversionPropertyType, int nPos)
+{
+ if( hasTerm( rTerm ) )
+ return;
+
+ DictionaryEntry* pEntry = new DictionaryEntry( rTerm, rMapping, nConversionPropertyType, true );
+ m_xControl->insert(nPos, m_xIter.get());
+ m_xControl->set_text(*m_xIter, pEntry->m_aTerm, 0);
+ m_xControl->set_text(*m_xIter, pEntry->m_aMapping, 1);
+ m_xControl->set_text(*m_xIter, getPropertyTypeName(pEntry->m_nConversionPropertyType), 2);
+ m_xControl->set_id(*m_xIter, weld::toId(pEntry));
+ m_xControl->select(*m_xIter);
+}
+
+void DictionaryList::deleteEntryOnPos( sal_Int32 nPos )
+{
+ DictionaryEntry* pEntry = getEntryOnPos( nPos );
+ m_xControl->remove(nPos);
+ if (pEntry)
+ {
+ if( pEntry->m_bNewEntry )
+ delete pEntry;
+ else
+ m_aToBeDeleted.push_back( pEntry );
+ }
+}
+
+int DictionaryList::deleteEntries( std::u16string_view rTerm )
+{
+ int nPos = -1;
+ int nRowCount = m_xControl->n_children();
+ for (sal_Int32 nN = nRowCount; nN--;)
+ {
+ DictionaryEntry* pCurEntry = getEntryOnPos( nN );
+ if( rTerm == pCurEntry->m_aTerm )
+ {
+ nPos = nN;
+ m_xControl->remove(nN);
+ if( pCurEntry->m_bNewEntry )
+ delete pCurEntry;
+ else
+ m_aToBeDeleted.push_back( pCurEntry );
+ }
+ }
+ return nPos;
+}
+
+DictionaryEntry::DictionaryEntry( const OUString& rTerm, const OUString& rMapping
+ , sal_Int16 nConversionPropertyType
+ , bool bNewEntry )
+ : m_aTerm( rTerm )
+ , m_aMapping( rMapping )
+ , m_nConversionPropertyType( nConversionPropertyType )
+ , m_bNewEntry( bNewEntry )
+{
+ if( m_nConversionPropertyType == 0 )
+ m_nConversionPropertyType = 1;
+}
+
+DictionaryEntry::~DictionaryEntry()
+{
+}
+
+IMPL_LINK_NOARG(ChineseDictionaryDialog, SizeAllocHdl, const Size&, void)
+{
+ DictionaryList* pControl = m_xCT_DictionaryToTraditional->get_visible() ?
+ m_xCT_DictionaryToTraditional.get() :
+ m_xCT_DictionaryToSimplified.get();
+ std::vector<int> aWidths;
+ int x1, x2, y, width, height;
+ if (!m_xED_Mapping->get_extents_relative_to(pControl->get_widget(), x1, y, width, height))
+ return;
+ aWidths.push_back(x1);
+ if (!m_xLB_Property->get_extents_relative_to(pControl->get_widget(), x2, y, width, height))
+ return;
+ aWidths.push_back(x2 - x1);
+ m_xCT_DictionaryToTraditional->get_widget().set_column_fixed_widths(aWidths);
+ m_xCT_DictionaryToSimplified->get_widget().set_column_fixed_widths(aWidths);
+}
+
+void DictionaryList::init(const Reference< linguistic2::XConversionDictionary>& xDictionary,
+ weld::Entry *pED_Term, weld::Entry *pED_Mapping, weld::ComboBox *pLB_Property)
+{
+ if (m_xDictionary.is())
+ return;
+
+ m_xDictionary = xDictionary;
+
+ m_pED_Term = pED_Term;
+ m_pED_Mapping = pED_Mapping;
+ m_pLB_Property = pLB_Property;
+
+ m_xControl->set_sort_column(0);
+ m_xControl->set_sort_indicator(TRISTATE_TRUE, 0);
+
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(m_pED_Term->get_preferred_size().Width()),
+ o3tl::narrowing<int>(m_pED_Mapping->get_preferred_size().Width())
+ };
+ m_xControl->set_column_fixed_widths(aWidths);
+}
+
+void ChineseDictionaryDialog::initDictionaryControl(DictionaryList *pList,
+ const Reference< linguistic2::XConversionDictionary>& xDictionary)
+{
+ //set widgets to track the width of for columns
+ pList->init(xDictionary,
+ m_xED_Term.get(), m_xED_Mapping.get(), m_xLB_Property.get());
+}
+
+ChineseDictionaryDialog::ChineseDictionaryDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "svx/ui/chinesedictionary.ui", "ChineseDictionaryDialog")
+ , m_nTextConversionOptions(i18n::TextConversionOption::NONE)
+ , m_xRB_To_Simplified(m_xBuilder->weld_radio_button("tradtosimple"))
+ , m_xRB_To_Traditional(m_xBuilder->weld_radio_button("simpletotrad"))
+ , m_xCB_Reverse(m_xBuilder->weld_check_button("reverse"))
+ , m_xFT_Term(m_xBuilder->weld_label("termft"))
+ , m_xED_Term(m_xBuilder->weld_entry("term"))
+ , m_xFT_Mapping(m_xBuilder->weld_label("mappingft"))
+ , m_xED_Mapping(m_xBuilder->weld_entry("mapping"))
+ , m_xFT_Property(m_xBuilder->weld_label("propertyft"))
+ , m_xLB_Property(m_xBuilder->weld_combo_box("property"))
+ , m_xCT_DictionaryToSimplified(new DictionaryList(m_xBuilder->weld_tree_view("tradtosimpleview")))
+ , m_xCT_DictionaryToTraditional(new DictionaryList(m_xBuilder->weld_tree_view("simpletotradview")))
+ , m_xPB_Add(m_xBuilder->weld_button("add"))
+ , m_xPB_Modify(m_xBuilder->weld_button("modify"))
+ , m_xPB_Delete(m_xBuilder->weld_button("delete"))
+{
+ m_xCT_DictionaryToSimplified->set_size_request(-1, m_xCT_DictionaryToSimplified->get_height_rows(8));
+ m_xCT_DictionaryToTraditional->set_size_request(-1, m_xCT_DictionaryToTraditional->get_height_rows(8));
+
+ SvtLinguConfig aLngCfg;
+ bool bValue;
+ Any aAny( aLngCfg.GetProperty( UPN_IS_REVERSE_MAPPING ) );
+ if( aAny >>= bValue )
+ m_xCB_Reverse->set_active( bValue );
+
+ m_xLB_Property->set_active(0);
+
+ Reference< linguistic2::XConversionDictionary > xDictionary_To_Simplified;
+ Reference< linguistic2::XConversionDictionary > xDictionary_To_Traditional;
+ //get dictionaries
+ {
+ if(!m_xContext.is())
+ m_xContext.set( ::cppu::defaultBootstrap_InitialComponentContext() );
+ if(m_xContext.is())
+ {
+ Reference< linguistic2::XConversionDictionaryList > xDictionaryList = linguistic2::ConversionDictionaryList::create(m_xContext);
+ Reference< container::XNameContainer > xContainer( xDictionaryList->getDictionaryContainer() );
+ if(xContainer.is())
+ {
+ try
+ {
+ OUString aNameTo_Simplified("ChineseT2S");
+ OUString aNameTo_Traditional("ChineseS2T");
+ lang::Locale aLocale;
+ aLocale.Language = "zh";
+
+ if( xContainer->hasByName( aNameTo_Simplified ) )
+ xDictionary_To_Simplified.set(
+ xContainer->getByName( aNameTo_Simplified ), UNO_QUERY );
+ else
+ {
+ aLocale.Country = "TW";
+ xDictionary_To_Simplified =
+ xDictionaryList->addNewDictionary( aNameTo_Simplified
+ , aLocale, linguistic2::ConversionDictionaryType::SCHINESE_TCHINESE
+ );
+ }
+ if (xDictionary_To_Simplified.is())
+ xDictionary_To_Simplified->setActive( true );
+
+
+ if( xContainer->hasByName( aNameTo_Traditional ) )
+ xDictionary_To_Traditional.set(
+ xContainer->getByName( aNameTo_Traditional ), UNO_QUERY );
+ else
+ {
+ aLocale.Country = "CN";
+ xDictionary_To_Traditional =
+ xDictionaryList->addNewDictionary( aNameTo_Traditional
+ ,aLocale, linguistic2::ConversionDictionaryType::SCHINESE_TCHINESE);
+ }
+ if (xDictionary_To_Traditional.is())
+ xDictionary_To_Traditional->setActive( true );
+
+ }
+ catch(const uno::Exception& )
+ {
+ }
+ }
+ }
+ }
+
+ //init dictionary controls
+ initDictionaryControl(m_xCT_DictionaryToSimplified.get(), xDictionary_To_Simplified);
+ initDictionaryControl(m_xCT_DictionaryToTraditional.get(), xDictionary_To_Traditional);
+
+ //set hdl
+ m_xCT_DictionaryToSimplified->connect_column_clicked(LINK(this, ChineseDictionaryDialog, ToSimplifiedHeaderBarClick));
+ m_xCT_DictionaryToTraditional->connect_column_clicked(LINK(this, ChineseDictionaryDialog, ToTraditionalHeaderBarClick));
+
+ updateAfterDirectionChange();
+
+ m_xED_Term->connect_changed( LINK( this, ChineseDictionaryDialog, EditFieldsHdl ) );
+ m_xED_Mapping->connect_changed( LINK( this, ChineseDictionaryDialog, EditFieldsHdl ) );
+ m_xLB_Property->connect_changed( LINK( this, ChineseDictionaryDialog, EditFieldsListBoxHdl ) );
+
+ m_xRB_To_Simplified->connect_toggled( LINK( this, ChineseDictionaryDialog, DirectionHdl ) );
+
+ m_xCT_DictionaryToSimplified->connect_changed( LINK( this, ChineseDictionaryDialog, MappingSelectHdl ));
+ m_xCT_DictionaryToTraditional->connect_changed( LINK( this, ChineseDictionaryDialog, MappingSelectHdl ));
+
+ m_xPB_Add->connect_clicked( LINK( this, ChineseDictionaryDialog, AddHdl ) );
+ m_xPB_Modify->connect_clicked( LINK( this, ChineseDictionaryDialog, ModifyHdl ) );
+ m_xPB_Delete->connect_clicked( LINK( this, ChineseDictionaryDialog, DeleteHdl ) );
+
+ m_xED_Mapping->connect_size_allocate(LINK(this, ChineseDictionaryDialog, SizeAllocHdl));
+ m_xLB_Property->connect_size_allocate(LINK(this, ChineseDictionaryDialog, SizeAllocHdl));
+}
+
+ChineseDictionaryDialog::~ChineseDictionaryDialog()
+{
+}
+
+void ChineseDictionaryDialog::setDirectionAndTextConversionOptions( bool bDirectionToSimplified, sal_Int32 nTextConversionOptions /*i18n::TextConversionOption*/ )
+{
+ if( bDirectionToSimplified == m_xRB_To_Simplified->get_active()
+ && nTextConversionOptions == m_nTextConversionOptions )
+ return;
+
+ m_nTextConversionOptions = nTextConversionOptions;
+
+ if (bDirectionToSimplified)
+ m_xRB_To_Simplified->set_active(true);
+ else
+ m_xRB_To_Traditional->set_active(true);
+ updateAfterDirectionChange();
+}
+
+IMPL_LINK_NOARG(ChineseDictionaryDialog, DirectionHdl, weld::Toggleable&, void)
+{
+ updateAfterDirectionChange();
+}
+
+void ChineseDictionaryDialog::updateAfterDirectionChange()
+{
+ Reference< linguistic2::XConversionDictionary > xDictionary;
+
+ if (m_xRB_To_Simplified->get_active())
+ {
+ m_xCT_DictionaryToTraditional->hide();
+ m_xCT_DictionaryToSimplified->show();
+ xDictionary = m_xCT_DictionaryToSimplified->m_xDictionary;
+ }
+ else
+ {
+ m_xCT_DictionaryToSimplified->hide();
+ m_xCT_DictionaryToTraditional->show();
+ xDictionary = m_xCT_DictionaryToTraditional->m_xDictionary;
+ }
+
+ updateButtons();
+}
+
+IMPL_LINK_NOARG(ChineseDictionaryDialog, EditFieldsListBoxHdl, weld::ComboBox&, void)
+{
+ updateButtons();
+}
+
+IMPL_LINK_NOARG(ChineseDictionaryDialog, EditFieldsHdl, weld::Entry&, void)
+{
+ updateButtons();
+}
+
+IMPL_LINK_NOARG(ChineseDictionaryDialog, MappingSelectHdl, weld::TreeView&, void)
+{
+ DictionaryEntry* pE = getActiveDictionary().getFirstSelectedEntry();
+ if (pE)
+ {
+ m_xED_Term->set_text( pE->m_aTerm );
+ m_xED_Mapping->set_text( pE->m_aMapping );
+ sal_Int16 nPos = pE->m_nConversionPropertyType-1;
+ if (nPos<0 || nPos>=m_xLB_Property->get_count())
+ nPos=0;
+ if (m_xLB_Property->get_count())
+ m_xLB_Property->set_active(nPos);
+ }
+
+ updateButtons();
+}
+
+bool ChineseDictionaryDialog::isEditFieldsHaveContent() const
+{
+ return !m_xED_Term->get_text().isEmpty() && !m_xED_Mapping->get_text().isEmpty();
+}
+
+bool ChineseDictionaryDialog::isEditFieldsContentEqualsSelectedListContent() const
+{
+ DictionaryEntry* pE = getActiveDictionary().getFirstSelectedEntry();
+ if( pE )
+ {
+ if (pE->m_aTerm != m_xED_Term->get_text())
+ return false;
+ if (pE->m_aMapping != m_xED_Mapping->get_text())
+ return false;
+ if (pE->m_nConversionPropertyType != m_xLB_Property->get_active() + 1)
+ return false;
+ return true;
+ }
+ return false;
+}
+
+const DictionaryList& ChineseDictionaryDialog::getActiveDictionary() const
+{
+ if( m_xRB_To_Traditional->get_active() )
+ return *m_xCT_DictionaryToTraditional;
+ return *m_xCT_DictionaryToSimplified;
+}
+
+DictionaryList& ChineseDictionaryDialog::getActiveDictionary()
+{
+ if( m_xRB_To_Traditional->get_active() )
+ return *m_xCT_DictionaryToTraditional;
+ return *m_xCT_DictionaryToSimplified;
+}
+
+const DictionaryList& ChineseDictionaryDialog::getReverseDictionary() const
+{
+ if( m_xRB_To_Traditional->get_active() )
+ return *m_xCT_DictionaryToSimplified;
+ return *m_xCT_DictionaryToTraditional;
+}
+
+DictionaryList& ChineseDictionaryDialog::getReverseDictionary()
+{
+ if( m_xRB_To_Traditional->get_active() )
+ return *m_xCT_DictionaryToSimplified;
+ return *m_xCT_DictionaryToTraditional;
+}
+
+void ChineseDictionaryDialog::updateButtons()
+{
+ bool bAdd = isEditFieldsHaveContent() && !getActiveDictionary().hasTerm(m_xED_Term->get_text());
+ m_xPB_Add->set_sensitive( bAdd );
+
+ m_xPB_Delete->set_sensitive(!bAdd && getActiveDictionary().get_selected_index() != -1);
+
+ bool bModify = false;
+ {
+ DictionaryEntry* pFirstSelectedEntry = getActiveDictionary().getFirstSelectedEntry();
+ bModify = !bAdd && pFirstSelectedEntry && pFirstSelectedEntry->m_aTerm == m_xED_Term->get_text();
+ if( bModify && isEditFieldsContentEqualsSelectedListContent() )
+ bModify = false;
+ }
+ m_xPB_Modify->set_sensitive( bModify );
+}
+
+IMPL_LINK_NOARG(ChineseDictionaryDialog, AddHdl, weld::Button&, void)
+{
+ if( !isEditFieldsHaveContent() )
+ return;
+
+ sal_Int16 nConversionPropertyType = m_xLB_Property->get_active() + 1;
+
+ getActiveDictionary().addEntry( m_xED_Term->get_text(), m_xED_Mapping->get_text(), nConversionPropertyType );
+
+ if( m_xCB_Reverse->get_active() )
+ {
+ getReverseDictionary().deleteEntries( m_xED_Mapping->get_text() );
+ getReverseDictionary().addEntry( m_xED_Mapping->get_text(), m_xED_Term->get_text(), nConversionPropertyType );
+ }
+
+ updateButtons();
+}
+
+IMPL_LINK_NOARG(ChineseDictionaryDialog, ModifyHdl, weld::Button&, void)
+{
+ OUString aTerm( m_xED_Term->get_text() );
+ OUString aMapping( m_xED_Mapping->get_text() );
+ sal_Int16 nConversionPropertyType = m_xLB_Property->get_active() + 1;
+
+ DictionaryList& rActive = getActiveDictionary();
+ DictionaryList& rReverse = getReverseDictionary();
+
+ DictionaryEntry* pE = rActive.getFirstSelectedEntry();
+ if( pE && pE->m_aTerm != aTerm )
+ return;
+
+ if( pE )
+ {
+ if( pE->m_aMapping != aMapping || pE->m_nConversionPropertyType != nConversionPropertyType )
+ {
+ if( m_xCB_Reverse->get_active() )
+ {
+ rReverse.deleteEntries( pE->m_aMapping );
+ int nPos = rReverse.deleteEntries( aMapping );
+ rReverse.addEntry( aMapping, aTerm, nConversionPropertyType, nPos );
+ }
+
+ int nPos = rActive.deleteEntries( aTerm );
+ rActive.addEntry( aTerm, aMapping, nConversionPropertyType, nPos );
+ }
+ }
+
+ updateButtons();
+}
+
+IMPL_LINK_NOARG(ChineseDictionaryDialog, DeleteHdl, weld::Button&, void)
+{
+ DictionaryList& rActive = getActiveDictionary();
+ DictionaryList& rReverse = getReverseDictionary();
+
+ int nEntry = rActive.get_selected_index();
+ if (nEntry != -1)
+ {
+ DictionaryEntry* pEntry = rActive.getEntryOnPos(nEntry);
+ if (pEntry)
+ {
+ OUString aMapping = pEntry->m_aMapping;
+ rActive.deleteEntryOnPos(nEntry);
+ if (m_xCB_Reverse->get_active())
+ rReverse.deleteEntries(aMapping);
+ }
+ }
+
+ updateButtons();
+}
+
+short ChineseDictionaryDialog::run()
+{
+ sal_Int32 nTextConversionOptions = m_nTextConversionOptions;
+ if(m_nTextConversionOptions & i18n::TextConversionOption::USE_CHARACTER_VARIANTS )
+ nTextConversionOptions = nTextConversionOptions^i18n::TextConversionOption::USE_CHARACTER_VARIANTS ;
+
+ m_xCT_DictionaryToSimplified->refillFromDictionary( nTextConversionOptions );
+ m_xCT_DictionaryToTraditional->refillFromDictionary( m_nTextConversionOptions );
+
+ short nRet = GenericDialogController::run();
+
+ if( nRet == RET_OK )
+ {
+ //save settings to configuration
+ SvtLinguConfig aLngCfg;
+ aLngCfg.SetProperty( UPN_IS_REVERSE_MAPPING, uno::Any(m_xCB_Reverse->get_active()) );
+
+ m_xCT_DictionaryToSimplified->save();
+ m_xCT_DictionaryToTraditional->save();
+ }
+
+ m_xCT_DictionaryToSimplified->deleteAll();
+ m_xCT_DictionaryToTraditional->deleteAll();
+
+ return nRet;
+}
+
+void ChineseDictionaryDialog::HeaderBarClick(DictionaryList& rList, int nColumn)
+{
+ bool bSortAtoZ = rList.get_sort_order();
+
+ //set new arrow positions in headerbar
+ if (nColumn == rList.get_sort_column())
+ {
+ bSortAtoZ = !bSortAtoZ;
+ rList.set_sort_order(bSortAtoZ);
+ }
+ else
+ {
+ rList.set_sort_indicator(TRISTATE_INDET, rList.get_sort_column());
+ rList.set_sort_column(nColumn);
+ }
+
+ //sort lists
+ rList.set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
+}
+
+IMPL_LINK(ChineseDictionaryDialog, ToSimplifiedHeaderBarClick, int, nColumn, void)
+{
+ HeaderBarClick(*m_xCT_DictionaryToSimplified, nColumn);
+}
+
+IMPL_LINK(ChineseDictionaryDialog, ToTraditionalHeaderBarClick, int, nColumn, void)
+{
+ HeaderBarClick(*m_xCT_DictionaryToTraditional, nColumn);
+}
+
+} //end namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.hxx b/svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.hxx
new file mode 100644
index 000000000..0213c53da
--- /dev/null
+++ b/svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.hxx
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/linguistic2/XConversionDictionary.hpp>
+
+#include <vector>
+
+namespace textconversiondlgs
+{
+
+struct DictionaryEntry final
+{
+ DictionaryEntry( const OUString& rTerm, const OUString& rMapping
+ , sal_Int16 nConversionPropertyType //linguistic2::ConversionPropertyType
+ , bool bNewEntry = false );
+
+ ~DictionaryEntry();
+
+ OUString m_aTerm;
+ OUString m_aMapping;
+ sal_Int16 m_nConversionPropertyType; //linguistic2::ConversionPropertyType
+
+ bool m_bNewEntry;
+};
+
+class DictionaryList
+{
+public:
+ DictionaryList(std::unique_ptr<weld::TreeView> xTreeView);
+
+ void init(const css::uno::Reference< css::linguistic2::XConversionDictionary>& xDictionary,
+ weld::Entry *pED_Term, weld::Entry *pED_Mapping, weld::ComboBox *pLB_Property);
+
+ void deleteAll();
+ void refillFromDictionary( sal_Int32 nTextConversionOptions /*i18n::TextConversionOption*/ );
+ void save();
+
+ DictionaryEntry* getTermEntry( std::u16string_view rTerm ) const;
+ bool hasTerm( std::u16string_view rTerm ) const;
+
+ void addEntry( const OUString& rTerm, const OUString& rMapping
+ , sal_Int16 nConversionPropertyType /*linguistic2::ConversionPropertyType*/, int nPos = -1);
+ int deleteEntries( std::u16string_view rTerm ); //return lowest position of deleted entries or -1 if no entry was deleted
+ void deleteEntryOnPos( sal_Int32 nPos );
+ DictionaryEntry* getEntryOnPos( sal_Int32 nPos ) const;
+ DictionaryEntry* getFirstSelectedEntry() const;
+
+ void set_size_request(int nWidth, int nHeight) { m_xControl->set_size_request(nWidth, nHeight); }
+ void hide() { m_xControl->hide(); }
+ void show() { m_xControl->show(); }
+ void connect_changed(const Link<weld::TreeView&, void>& rLink) { m_xControl->connect_changed(rLink); }
+ void connect_column_clicked(const Link<int, void>& rLink) { m_xControl->connect_column_clicked(rLink); }
+ bool get_sort_order() const { return m_xControl->get_sort_order(); }
+ void set_sort_order(bool bAscending) { return m_xControl->set_sort_order(bAscending); }
+ void set_sort_column(int nColumn) { return m_xControl->set_sort_column(nColumn); }
+ int get_sort_column() const { return m_xControl->get_sort_column(); }
+ int get_selected_index() const { return m_xControl->get_selected_index(); }
+ int get_height_rows(int nRows) const { return m_xControl->get_height_rows(nRows); }
+ bool get_visible() const { return m_xControl->get_visible(); }
+ void set_sort_indicator(TriState eState, int nColumn) { m_xControl->set_sort_indicator(eState, nColumn); }
+ weld::TreeView& get_widget() const { return *m_xControl; }
+
+private:
+ OUString getPropertyTypeName( sal_Int16 nConversionPropertyType /*linguistic2::ConversionPropertyType*/ ) const;
+
+public:
+ css::uno::Reference<css::linguistic2::XConversionDictionary> m_xDictionary;
+
+private:
+ std::unique_ptr<weld::TreeView> m_xControl;
+ std::unique_ptr<weld::TreeIter> m_xIter;
+ weld::Entry* m_pED_Term;
+ weld::Entry* m_pED_Mapping;
+ weld::ComboBox* m_pLB_Property;
+
+ std::vector< DictionaryEntry* > m_aToBeDeleted;
+};
+
+class ChineseDictionaryDialog : public weld::GenericDialogController
+{
+public:
+ explicit ChineseDictionaryDialog(weld::Window* pParent);
+ virtual ~ChineseDictionaryDialog() override;
+
+ //this method should be called once before calling execute
+ void setDirectionAndTextConversionOptions( bool bDirectionToSimplified, sal_Int32 nTextConversionOptions /*i18n::TextConversionOption*/ );
+
+ virtual short run() override;
+
+private:
+ DECL_LINK( DirectionHdl, weld::Toggleable&, void );
+ DECL_LINK( EditFieldsHdl, weld::Entry&, void );
+ DECL_LINK( EditFieldsListBoxHdl, weld::ComboBox&, void );
+ DECL_LINK( MappingSelectHdl, weld::TreeView&, void );
+ DECL_LINK( AddHdl, weld::Button&, void );
+ DECL_LINK( ModifyHdl, weld::Button&, void );
+ DECL_LINK( DeleteHdl, weld::Button&, void );
+ static void HeaderBarClick(DictionaryList& rList, int nColumn);
+ DECL_LINK(ToSimplifiedHeaderBarClick, int, void);
+ DECL_LINK(ToTraditionalHeaderBarClick, int, void);
+ DECL_LINK(SizeAllocHdl, const Size&, void);
+
+ void initDictionaryControl(DictionaryList *pList,
+ const css::uno::Reference< css::linguistic2::XConversionDictionary>& xDictionary);
+
+ void updateAfterDirectionChange();
+ void updateButtons();
+
+ bool isEditFieldsHaveContent() const;
+ bool isEditFieldsContentEqualsSelectedListContent() const;
+
+ DictionaryList& getActiveDictionary();
+ DictionaryList& getReverseDictionary();
+
+ const DictionaryList& getActiveDictionary() const;
+ const DictionaryList& getReverseDictionary() const;
+
+private:
+ sal_Int32 m_nTextConversionOptions; //i18n::TextConversionOption
+
+ css::uno::Reference<css::uno::XComponentContext> m_xContext;
+
+ std::unique_ptr<weld::RadioButton> m_xRB_To_Simplified;
+ std::unique_ptr<weld::RadioButton> m_xRB_To_Traditional;
+
+ std::unique_ptr<weld::CheckButton> m_xCB_Reverse;
+
+ std::unique_ptr<weld::Label> m_xFT_Term;
+ std::unique_ptr<weld::Entry> m_xED_Term;
+
+ std::unique_ptr<weld::Label> m_xFT_Mapping;
+ std::unique_ptr<weld::Entry> m_xED_Mapping;
+
+ std::unique_ptr<weld::Label> m_xFT_Property;
+ std::unique_ptr<weld::ComboBox> m_xLB_Property;
+
+ std::unique_ptr<DictionaryList> m_xCT_DictionaryToSimplified;
+ std::unique_ptr<DictionaryList> m_xCT_DictionaryToTraditional;
+
+ std::unique_ptr<weld::Button> m_xPB_Add;
+ std::unique_ptr<weld::Button> m_xPB_Modify;
+ std::unique_ptr<weld::Button> m_xPB_Delete;
+};
+
+
+} //end namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog.cxx b/svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog.cxx
new file mode 100644
index 000000000..466a4efca
--- /dev/null
+++ b/svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog.cxx
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "chinese_translation_unodialog.hxx"
+#include "chinese_translationdialog.hxx"
+#include <vcl/svapp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+
+namespace textconversiondlgs
+{
+using namespace ::com::sun::star;
+
+ChineseTranslation_UnoDialog::ChineseTranslation_UnoDialog()
+ : m_bDisposed(false)
+ , m_bInDispose(false)
+{
+}
+
+ChineseTranslation_UnoDialog::~ChineseTranslation_UnoDialog()
+{
+ SolarMutexGuard aSolarGuard;
+ impl_DeleteDialog();
+}
+
+void ChineseTranslation_UnoDialog::impl_DeleteDialog()
+{
+ if (m_xDialog)
+ {
+ m_xDialog->response(RET_CANCEL);
+ m_xDialog.reset();
+ }
+}
+
+// lang::XServiceInfo
+OUString SAL_CALL ChineseTranslation_UnoDialog::getImplementationName()
+{
+ return "com.sun.star.comp.linguistic2.ChineseTranslationDialog";
+}
+
+sal_Bool SAL_CALL ChineseTranslation_UnoDialog::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL ChineseTranslation_UnoDialog::getSupportedServiceNames()
+{
+ return { "com.sun.star.linguistic2.ChineseTranslationDialog" };
+}
+
+// ui::dialogs::XExecutableDialog
+void SAL_CALL ChineseTranslation_UnoDialog::setTitle( const OUString& )
+{
+ //not implemented - fell free to do so, if you do need this
+}
+
+
+void SAL_CALL ChineseTranslation_UnoDialog::initialize( const uno::Sequence< uno::Any >& aArguments )
+{
+ SolarMutexGuard aSolarGuard;
+ if( m_bDisposed || m_bInDispose )
+ return;
+
+ for(const uno::Any& rArgument : aArguments)
+ {
+ beans::PropertyValue aProperty;
+ if(rArgument >>= aProperty)
+ {
+ if( aProperty.Name == "ParentWindow" )
+ {
+ aProperty.Value >>= m_xParentWindow;
+ }
+ }
+ }
+}
+
+sal_Int16 SAL_CALL ChineseTranslation_UnoDialog::execute()
+{
+ sal_Int16 nRet = ui::dialogs::ExecutableDialogResults::CANCEL;
+ {
+ SolarMutexGuard aSolarGuard;
+ if (m_bDisposed || m_bInDispose)
+ return nRet;
+ if (!m_xDialog)
+ m_xDialog.reset(new ChineseTranslationDialog(Application::GetFrameWeld(m_xParentWindow)));
+ nRet = m_xDialog->run();
+ if (nRet == RET_OK)
+ nRet=ui::dialogs::ExecutableDialogResults::OK;
+ }
+ return nRet;
+}
+
+// lang::XComponent
+void SAL_CALL ChineseTranslation_UnoDialog::dispose()
+{
+ lang::EventObject aEvt;
+ {
+ SolarMutexGuard aSolarGuard;
+ if( m_bDisposed || m_bInDispose )
+ return;
+ m_bInDispose = true;
+
+ impl_DeleteDialog();
+ m_xParentWindow = nullptr;
+ m_bDisposed = true;
+
+ aEvt.Source = static_cast< XComponent * >( this );
+ }
+ std::unique_lock aGuard(m_aContainerMutex);
+ m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt );
+}
+
+void SAL_CALL ChineseTranslation_UnoDialog::addEventListener( const uno::Reference< lang::XEventListener > & xListener )
+{
+ SolarMutexGuard aSolarGuard;
+ if( m_bDisposed || m_bInDispose )
+ return;
+ std::unique_lock aGuard(m_aContainerMutex);
+ m_aDisposeEventListeners.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL ChineseTranslation_UnoDialog::removeEventListener( const uno::Reference< lang::XEventListener > & xListener )
+{
+ SolarMutexGuard aSolarGuard;
+ if( m_bDisposed || m_bInDispose )
+ return;
+ std::unique_lock aGuard(m_aContainerMutex);
+ m_aDisposeEventListeners.removeInterface( aGuard, xListener );
+}
+
+
+// XPropertySet
+
+uno::Reference< beans::XPropertySetInfo > SAL_CALL ChineseTranslation_UnoDialog::getPropertySetInfo( )
+{
+ return nullptr;
+}
+
+void SAL_CALL ChineseTranslation_UnoDialog::setPropertyValue( const OUString&, const uno::Any& )
+{
+ //only read only properties
+ throw beans::PropertyVetoException();
+}
+
+uno::Any SAL_CALL ChineseTranslation_UnoDialog::getPropertyValue( const OUString& rPropertyName )
+{
+ uno::Any aRet;
+
+ bool bDirectionToSimplified = true;
+ bool bTranslateCommonTerms = false;
+
+ {
+ SolarMutexGuard aSolarGuard;
+ if (m_bDisposed || m_bInDispose || !m_xDialog)
+ return aRet;
+ m_xDialog->getSettings(bDirectionToSimplified, bTranslateCommonTerms);
+ }
+
+ if( rPropertyName == "IsDirectionToSimplified" )
+ {
+ aRet <<= bDirectionToSimplified;
+ }
+ else if( rPropertyName == "IsUseCharacterVariants" )
+ {
+ aRet <<= false;
+ }
+ else if( rPropertyName == "IsTranslateCommonTerms" )
+ {
+ aRet <<= bTranslateCommonTerms;
+ }
+ else
+ {
+ throw beans::UnknownPropertyException( rPropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+ return aRet;
+
+}
+
+void SAL_CALL ChineseTranslation_UnoDialog::addPropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& )
+{
+ //only not bound properties -> ignore listener
+}
+
+void SAL_CALL ChineseTranslation_UnoDialog::removePropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& )
+{
+ //only not bound properties -> ignore listener
+}
+
+void SAL_CALL ChineseTranslation_UnoDialog::addVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& )
+{
+ //only not bound properties -> ignore listener
+}
+
+void SAL_CALL ChineseTranslation_UnoDialog::removeVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& )
+{
+ //only not bound properties -> ignore listener
+}
+
+} //end namespace
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+svx_ChineseTranslation_UnoDialog_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new textconversiondlgs::ChineseTranslation_UnoDialog());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog.hxx b/svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog.hxx
new file mode 100644
index 000000000..0d40e1227
--- /dev/null
+++ b/svx/source/unodialogs/textconversiondlgs/chinese_translation_unodialog.hxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <mutex>
+
+
+namespace textconversiondlgs
+{
+
+
+/** This class provides the chinese translation dialog as a uno component.
+
+It can be created via lang::XMultiComponentFactory::createInstanceWithContext
+with servicename "com.sun.star.linguistic2.ChineseTranslationDialog"
+or implementation name "com.sun.star.comp.linguistic2.ChineseTranslationDialog"
+
+It can be initialized via the XInitialization interface with the following single parameter:
+PropertyValue-Parameter: Name="ParentWindow" Type="awt::XWindow".
+
+It can be executed via the ui::dialogs::XExecutableDialog interface.
+
+Made settings can be retrieved via beans::XPropertySet interface.
+Following properties are available (read only and not bound):
+1) Name="IsDirectionToSimplified" Type="sal_Bool"
+2) Name="IsUseCharacterVariants" Type="sal_Bool"
+3) Name="IsTranslateCommonTerms" Type="sal_Bool"
+
+The dialog gets this information from the registry on execute and writes it back to the registry if ended with OK.
+*/
+
+class ChineseTranslationDialog;
+
+class ChineseTranslation_UnoDialog : public ::cppu::WeakImplHelper <
+ css::ui::dialogs::XExecutableDialog
+ , css::lang::XInitialization
+ , css::beans::XPropertySet
+ , css::lang::XComponent
+ , css::lang::XServiceInfo
+ >
+{
+public:
+ ChineseTranslation_UnoDialog();
+ virtual ~ChineseTranslation_UnoDialog() override;
+
+ // lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // lang::XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // ui::dialogs::XExecutableDialog
+ virtual void SAL_CALL setTitle( const OUString& aTitle ) override;
+ virtual sal_Int16 SAL_CALL execute( ) override;
+
+ // beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // lang::XComponent
+ virtual void SAL_CALL dispose() override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener > & xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener > & xListener ) override;
+
+private:
+
+ void impl_DeleteDialog();
+
+private:
+ css::uno::Reference<
+ css::awt::XWindow > m_xParentWindow;
+
+ std::unique_ptr<ChineseTranslationDialog> m_xDialog;
+
+ bool m_bDisposed; ///Dispose call ready.
+ bool m_bInDispose;///In dispose call
+ std::mutex m_aContainerMutex;
+ comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_aDisposeEventListeners;
+};
+
+
+} //end namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodialogs/textconversiondlgs/chinese_translationdialog.cxx b/svx/source/unodialogs/textconversiondlgs/chinese_translationdialog.cxx
new file mode 100644
index 000000000..9bef507b7
--- /dev/null
+++ b/svx/source/unodialogs/textconversiondlgs/chinese_translationdialog.cxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "chinese_translationdialog.hxx"
+#include "chinese_dictionarydialog.hxx"
+#include <com/sun/star/i18n/TextConversionOption.hpp>
+#include <unotools/lingucfg.hxx>
+#include <unotools/linguprops.hxx>
+
+namespace textconversiondlgs
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+ChineseTranslationDialog::ChineseTranslationDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "svx/ui/chineseconversiondialog.ui", "ChineseConversionDialog")
+ , m_xBP_OK(m_xBuilder->weld_button("ok"))
+ , m_xPB_Editterms(m_xBuilder->weld_button("editterms"))
+ , m_xRB_To_Simplified(m_xBuilder->weld_radio_button("tosimplified"))
+ , m_xRB_To_Traditional(m_xBuilder->weld_radio_button("totraditional"))
+ , m_xCB_Translate_Commonterms(m_xBuilder->weld_check_button("commonterms"))
+{
+ SvtLinguConfig aLngCfg;
+ bool bValue = false;
+ Any aAny( aLngCfg.GetProperty( UPN_IS_DIRECTION_TO_SIMPLIFIED ) );
+ aAny >>= bValue;
+ if( bValue )
+ m_xRB_To_Simplified->set_active(true);
+ else
+ m_xRB_To_Traditional->set_active(true);
+
+ aAny = aLngCfg.GetProperty( UPN_IS_TRANSLATE_COMMON_TERMS );
+ if( aAny >>= bValue )
+ m_xCB_Translate_Commonterms->set_active( bValue );
+
+ m_xPB_Editterms->connect_clicked( LINK( this, ChineseTranslationDialog, DictionaryHdl ) );
+ m_xBP_OK->connect_clicked( LINK( this, ChineseTranslationDialog, OkHdl ) );
+}
+
+ChineseTranslationDialog::~ChineseTranslationDialog()
+{
+}
+
+void ChineseTranslationDialog::getSettings( bool& rbDirectionToSimplified
+ , bool& rbTranslateCommonTerms ) const
+{
+ rbDirectionToSimplified = m_xRB_To_Simplified->get_active();
+ rbTranslateCommonTerms = m_xCB_Translate_Commonterms->get_active();
+}
+
+IMPL_LINK_NOARG(ChineseTranslationDialog, OkHdl, weld::Button&, void)
+{
+ //save settings to configuration
+ SvtLinguConfig aLngCfg;
+ Any aAny;
+ aAny <<= m_xRB_To_Simplified->get_active();
+ aLngCfg.SetProperty( UPN_IS_DIRECTION_TO_SIMPLIFIED, aAny );
+ aAny <<= m_xCB_Translate_Commonterms->get_active();
+ aLngCfg.SetProperty( UPN_IS_TRANSLATE_COMMON_TERMS, aAny );
+
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ChineseTranslationDialog, DictionaryHdl, weld::Button&, void)
+{
+ if( !m_xDictionaryDialog )
+ m_xDictionaryDialog.reset(new ChineseDictionaryDialog(m_xDialog.get()));
+ sal_Int32 nTextConversionOptions = i18n::TextConversionOption::NONE;
+ if (!m_xCB_Translate_Commonterms->get_active())
+ nTextConversionOptions = nTextConversionOptions | i18n::TextConversionOption::CHARACTER_BY_CHARACTER;
+ m_xDictionaryDialog->setDirectionAndTextConversionOptions(m_xRB_To_Simplified->get_active(), nTextConversionOptions);
+ m_xDictionaryDialog->run();
+}
+
+
+} //end namespace
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodialogs/textconversiondlgs/chinese_translationdialog.hxx b/svx/source/unodialogs/textconversiondlgs/chinese_translationdialog.hxx
new file mode 100644
index 000000000..d6a9c312d
--- /dev/null
+++ b/svx/source/unodialogs/textconversiondlgs/chinese_translationdialog.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+namespace textconversiondlgs
+{
+class ChineseDictionaryDialog;
+
+class ChineseTranslationDialog : public weld::GenericDialogController
+{
+public:
+ explicit ChineseTranslationDialog(weld::Window* pParent);
+ virtual ~ChineseTranslationDialog() override;
+
+ void getSettings(bool& rbDirectionToSimplified, bool& rbTranslateCommonTerms) const;
+
+private:
+ DECL_LINK(DictionaryHdl, weld::Button&, void);
+ DECL_LINK(OkHdl, weld::Button&, void);
+
+private:
+ std::unique_ptr<weld::Button> m_xBP_OK;
+ std::unique_ptr<weld::Button> m_xPB_Editterms;
+ std::unique_ptr<weld::RadioButton> m_xRB_To_Simplified;
+ std::unique_ptr<weld::RadioButton> m_xRB_To_Traditional;
+ std::unique_ptr<weld::CheckButton> m_xCB_Translate_Commonterms;
+ std::unique_ptr<ChineseDictionaryDialog> m_xDictionaryDialog;
+};
+
+} //end namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/SvxXTextColumns.cxx b/svx/source/unodraw/SvxXTextColumns.cxx
new file mode 100644
index 000000000..a0e399bd4
--- /dev/null
+++ b/svx/source/unodraw/SvxXTextColumns.cxx
@@ -0,0 +1,338 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyVetoException.hpp>
+#include <com/sun/star/beans/UnknownPropertyException.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+#include <com/sun/star/text/ColumnSeparatorStyle.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/util/Color.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/safeint.hxx>
+#include <svl/itemprop.hxx>
+#include <svx/SvxXTextColumns.hxx>
+#include <tools/UnitConversion.hxx>
+#include <vcl/svapp.hxx>
+
+#include <numeric>
+
+namespace
+{
+enum : sal_uInt16
+{
+ WID_TXTCOL_IS_AUTOMATIC,
+ WID_TXTCOL_AUTO_DISTANCE,
+ WID_TXTCOL_LINE_WIDTH,
+ WID_TXTCOL_LINE_COLOR,
+ WID_TXTCOL_LINE_REL_HGT,
+ WID_TXTCOL_LINE_ALIGN,
+ WID_TXTCOL_LINE_IS_ON,
+ WID_TXTCOL_LINE_STYLE,
+};
+
+SfxItemPropertyMapEntry const saTextColumns_Impl[] = {
+ { u"IsAutomatic", WID_TXTCOL_IS_AUTOMATIC, cppu::UnoType<bool>::get(),
+ css::beans::PropertyAttribute::READONLY, 0 },
+ { u"AutomaticDistance", WID_TXTCOL_AUTO_DISTANCE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"SeparatorLineWidth", WID_TXTCOL_LINE_WIDTH, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"SeparatorLineColor", WID_TXTCOL_LINE_COLOR,
+ cppu::UnoType<com::sun::star::util::Color>::get(), 0, 0 },
+ { u"SeparatorLineRelativeHeight", WID_TXTCOL_LINE_REL_HGT, cppu::UnoType<sal_Int32>::get(), 0,
+ 0 },
+ { u"SeparatorLineVerticalAlignment", WID_TXTCOL_LINE_ALIGN,
+ cppu::UnoType<css::style::VerticalAlignment>::get(), 0, 0 },
+ { u"SeparatorLineIsOn", WID_TXTCOL_LINE_IS_ON, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"SeparatorLineStyle", WID_TXTCOL_LINE_STYLE, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 },
+};
+
+class SvxXTextColumns final
+ : public cppu::WeakImplHelper<css::beans::XPropertySet, css::text::XTextColumns,
+ css::lang::XServiceInfo>
+{
+public:
+ SvxXTextColumns() = default;
+
+ // XTextColumns
+ virtual sal_Int32 SAL_CALL getReferenceValue() override;
+ virtual sal_Int16 SAL_CALL getColumnCount() override;
+ virtual void SAL_CALL setColumnCount(sal_Int16 nColumns) override;
+ virtual css::uno::Sequence<css::text::TextColumn> SAL_CALL getColumns() override;
+ virtual void SAL_CALL
+ setColumns(const css::uno::Sequence<css::text::TextColumn>& Columns) override;
+
+ // XPropertySet
+ virtual css::uno::Reference<css::beans::XPropertySetInfo>
+ SAL_CALL getPropertySetInfo() override;
+ virtual void SAL_CALL setPropertyValue(const OUString& aPropertyName,
+ const css::uno::Any& aValue) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& PropertyName) override;
+ virtual void SAL_CALL addPropertyChangeListener(
+ const OUString& aPropertyName,
+ const css::uno::Reference<css::beans::XPropertyChangeListener>& xListener) override;
+ virtual void SAL_CALL removePropertyChangeListener(
+ const OUString& aPropertyName,
+ const css::uno::Reference<css::beans::XPropertyChangeListener>& aListener) override;
+ virtual void SAL_CALL addVetoableChangeListener(
+ const OUString& PropertyName,
+ const css::uno::Reference<css::beans::XVetoableChangeListener>& aListener) override;
+ virtual void SAL_CALL removeVetoableChangeListener(
+ const OUString& PropertyName,
+ const css::uno::Reference<css::beans::XVetoableChangeListener>& aListener) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+private:
+ sal_Int32 m_nReference = USHRT_MAX;
+ css::uno::Sequence<css::text::TextColumn> m_aTextColumns;
+ bool m_bIsAutomaticWidth = true;
+ sal_Int32 m_nAutoDistance = 0;
+
+ const SfxItemPropertySet m_aPropSet = { saTextColumns_Impl };
+
+ //separator line
+ sal_Int32 m_nSepLineWidth = 0;
+ com::sun::star::util::Color m_nSepLineColor = 0; // black
+ sal_Int32 m_nSepLineHeightRelative = 100; // full height
+ css::style::VerticalAlignment m_nSepLineVertAlign = css::style::VerticalAlignment_MIDDLE;
+ bool m_bSepLineIsOn = false;
+ sal_Int16 m_nSepLineStyle = css::text::ColumnSeparatorStyle::NONE;
+};
+
+OUString SvxXTextColumns::getImplementationName() { return "com.sun.star.comp.svx.TextColumns"; }
+
+sal_Bool SvxXTextColumns::supportsService(const OUString& rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+css::uno::Sequence<OUString> SvxXTextColumns::getSupportedServiceNames()
+{
+ return { "com.sun.star.text.TextColumns" };
+}
+
+sal_Int32 SvxXTextColumns::getReferenceValue()
+{
+ SolarMutexGuard aGuard;
+ return m_nReference;
+}
+
+sal_Int16 SvxXTextColumns::getColumnCount()
+{
+ SolarMutexGuard aGuard;
+ return o3tl::narrowing<sal_Int16>(m_aTextColumns.getLength());
+}
+
+void SvxXTextColumns::setColumnCount(sal_Int16 nColumns)
+{
+ SolarMutexGuard aGuard;
+ if (nColumns <= 0)
+ throw css::uno::RuntimeException();
+ m_bIsAutomaticWidth = true;
+ m_aTextColumns.realloc(nColumns);
+ css::text::TextColumn* pCols = m_aTextColumns.getArray();
+ m_nReference = USHRT_MAX;
+ sal_Int32 nWidth = m_nReference / nColumns;
+ sal_Int32 nDiff = m_nReference - nWidth * nColumns;
+ sal_Int32 nDist = m_nAutoDistance / 2;
+ for (sal_Int16 i = 0; i < nColumns; i++)
+ {
+ pCols[i].Width = nWidth;
+ pCols[i].LeftMargin = i == 0 ? 0 : nDist;
+ pCols[i].RightMargin = i == nColumns - 1 ? 0 : nDist;
+ }
+ pCols[nColumns - 1].Width += nDiff;
+}
+
+css::uno::Sequence<css::text::TextColumn> SvxXTextColumns::getColumns()
+{
+ SolarMutexGuard aGuard;
+ return m_aTextColumns;
+}
+
+void SvxXTextColumns::setColumns(const css::uno::Sequence<css::text::TextColumn>& rColumns)
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nReferenceTemp = std::accumulate(
+ rColumns.begin(), rColumns.end(), sal_Int32(0),
+ [](const sal_Int32 nSum, const css::text::TextColumn& rCol) { return nSum + rCol.Width; });
+ m_bIsAutomaticWidth = false;
+ m_nReference = !nReferenceTemp ? USHRT_MAX : nReferenceTemp;
+ m_aTextColumns = rColumns;
+}
+
+css::uno::Reference<css::beans::XPropertySetInfo> SvxXTextColumns::getPropertySetInfo()
+{
+ return m_aPropSet.getPropertySetInfo();
+}
+
+void SvxXTextColumns::setPropertyValue(const OUString& rPropertyName, const css::uno::Any& aValue)
+{
+ const SfxItemPropertyMapEntry* pEntry = m_aPropSet.getPropertyMap().getByName(rPropertyName);
+ if (!pEntry)
+ throw css::beans::UnknownPropertyException("Unknown property: " + rPropertyName,
+ static_cast<cppu::OWeakObject*>(this));
+ if (pEntry->nFlags & css::beans::PropertyAttribute::READONLY)
+ throw css::beans::PropertyVetoException("Property is read-only: " + rPropertyName,
+ static_cast<cppu::OWeakObject*>(this));
+
+ switch (pEntry->nWID)
+ {
+ case WID_TXTCOL_LINE_WIDTH:
+ {
+ sal_Int32 nTmp;
+ if (!(aValue >>= nTmp) || nTmp < 0)
+ throw css::lang::IllegalArgumentException();
+ m_nSepLineWidth = nTmp;
+ break;
+ }
+ case WID_TXTCOL_LINE_COLOR:
+ if (!(aValue >>= m_nSepLineColor))
+ throw css::lang::IllegalArgumentException();
+ break;
+ case WID_TXTCOL_LINE_STYLE:
+ if (!(aValue >>= m_nSepLineStyle))
+ throw css::lang::IllegalArgumentException();
+ break;
+ case WID_TXTCOL_LINE_REL_HGT:
+ {
+ sal_Int32 nTmp;
+ if (!(aValue >>= nTmp) || nTmp < 0)
+ throw css::lang::IllegalArgumentException();
+ m_nSepLineHeightRelative = nTmp;
+ break;
+ }
+ case WID_TXTCOL_LINE_ALIGN:
+ if (css::style::VerticalAlignment eAlign; aValue >>= eAlign)
+ m_nSepLineVertAlign = eAlign;
+ else if (sal_Int8 nTmp; aValue >>= nTmp)
+ m_nSepLineVertAlign = static_cast<css::style::VerticalAlignment>(nTmp);
+ else
+ throw css::lang::IllegalArgumentException();
+ break;
+ case WID_TXTCOL_LINE_IS_ON:
+ if (!(aValue >>= m_bSepLineIsOn))
+ throw css::lang::IllegalArgumentException();
+ break;
+ case WID_TXTCOL_AUTO_DISTANCE:
+ {
+ sal_Int32 nTmp;
+ if (!(aValue >>= nTmp) || nTmp < 0 || nTmp >= m_nReference)
+ throw css::lang::IllegalArgumentException();
+ m_nAutoDistance = nTmp;
+ sal_Int32 nColumns = m_aTextColumns.getLength();
+ css::text::TextColumn* pCols = m_aTextColumns.getArray();
+ sal_Int32 nDist = m_nAutoDistance / 2;
+ for (sal_Int32 i = 0; i < nColumns; i++)
+ {
+ pCols[i].LeftMargin = i == 0 ? 0 : nDist;
+ pCols[i].RightMargin = i == nColumns - 1 ? 0 : nDist;
+ }
+ break;
+ }
+ }
+}
+
+css::uno::Any SvxXTextColumns::getPropertyValue(const OUString& rPropertyName)
+{
+ const SfxItemPropertyMapEntry* pEntry = m_aPropSet.getPropertyMap().getByName(rPropertyName);
+ if (!pEntry)
+ throw css::beans::UnknownPropertyException("Unknown property: " + rPropertyName,
+ static_cast<cppu::OWeakObject*>(this));
+
+ css::uno::Any aRet;
+ switch (pEntry->nWID)
+ {
+ case WID_TXTCOL_LINE_WIDTH:
+ aRet <<= m_nSepLineWidth;
+ break;
+ case WID_TXTCOL_LINE_COLOR:
+ aRet <<= m_nSepLineColor;
+ break;
+ case WID_TXTCOL_LINE_STYLE:
+ aRet <<= m_nSepLineStyle;
+ break;
+ case WID_TXTCOL_LINE_REL_HGT:
+ aRet <<= m_nSepLineHeightRelative;
+ break;
+ case WID_TXTCOL_LINE_ALIGN:
+ aRet <<= m_nSepLineVertAlign;
+ break;
+ case WID_TXTCOL_LINE_IS_ON:
+ aRet <<= m_bSepLineIsOn;
+ break;
+ case WID_TXTCOL_IS_AUTOMATIC:
+ aRet <<= m_bIsAutomaticWidth;
+ break;
+ case WID_TXTCOL_AUTO_DISTANCE:
+ aRet <<= m_nAutoDistance;
+ break;
+ }
+ return aRet;
+}
+
+void SvxXTextColumns::addPropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const css::uno::Reference<css::beans::XPropertyChangeListener>& /*xListener*/)
+{
+}
+
+void SvxXTextColumns::removePropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const css::uno::Reference<css::beans::XPropertyChangeListener>& /*xListener*/)
+{
+}
+
+void SvxXTextColumns::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const css::uno::Reference<css::beans::XVetoableChangeListener>& /*xListener*/)
+{
+}
+
+void SvxXTextColumns::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const css::uno::Reference<css::beans::XVetoableChangeListener>& /*xListener*/)
+{
+}
+}
+
+css::uno::Reference<css::uno::XInterface> SvxXTextColumns_createInstance() noexcept
+{
+ return static_cast<cppu::OWeakObject*>(new SvxXTextColumns);
+}
+
+extern "C" SVXCORE_DLLPUBLIC css::uno::XInterface*
+com_sun_star_comp_svx_TextColumns_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new SvxXTextColumns);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/unodraw/UnoGraphicExporter.cxx b/svx/source/unodraw/UnoGraphicExporter.cxx
new file mode 100644
index 000000000..0cc43ce70
--- /dev/null
+++ b/svx/source/unodraw/UnoGraphicExporter.cxx
@@ -0,0 +1,1318 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vector>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/drawing/XGraphicExportFilter.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/graphic/XGraphicRenderer.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/task/XInteractionContinuation.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <comphelper/interaction.hxx>
+#include <framework/interaction.hxx>
+#include <com/sun/star/drawing/GraphicFilterRequest.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <svl/outstrm.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <editeng/numitem.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/xoutbmp.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/fmview.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/unopage.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/xlineit0.hxx>
+#include <editeng/flditem.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
+#include "UnoGraphicExporter.hxx"
+#include <memory>
+
+#define MAX_EXT_PIX 2048
+
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::task;
+
+// #i102251#
+#include <editeng/editstat.hxx>
+
+namespace {
+
+ struct ExportSettings
+ {
+ OUString maFilterName;
+ OUString maMediaType;
+ URL maURL;
+ css::uno::Reference< css::io::XOutputStream > mxOutputStream;
+ css::uno::Reference< css::graphic::XGraphicRenderer > mxGraphicRenderer;
+ css::uno::Reference< css::task::XStatusIndicator > mxStatusIndicator;
+ css::uno::Reference< css::task::XInteractionHandler > mxInteractionHandler;
+
+ sal_Int32 mnWidth;
+ sal_Int32 mnHeight;
+ bool mbExportOnlyBackground;
+ bool mbScrollText;
+ bool mbUseHighContrast;
+ bool mbTranslucent;
+
+ Sequence< PropertyValue > maFilterData;
+
+ Fraction maScaleX;
+ Fraction maScaleY;
+
+ TriState meAntiAliasing = TRISTATE_INDET;
+
+ explicit ExportSettings(const SdrModel* pSdrModel);
+ };
+
+ ExportSettings::ExportSettings(const SdrModel* pSdrModel)
+ : mnWidth( 0 )
+ ,mnHeight( 0 )
+ ,mbExportOnlyBackground( false )
+ ,mbScrollText( false )
+ ,mbUseHighContrast( false )
+ ,mbTranslucent( false )
+ ,maScaleX( 1, 1 )
+ ,maScaleY( 1, 1 )
+ {
+ if (pSdrModel)
+ {
+ maScaleX = pSdrModel->GetScaleFraction();
+ maScaleY = pSdrModel->GetScaleFraction();
+ }
+ }
+
+ /** implements a component to export shapes or pages to external graphic formats.
+
+ @implements com.sun.star.drawing.GraphicExportFilter
+ */
+ class GraphicExporter : public WeakImplHelper< XGraphicExportFilter, XServiceInfo >
+ {
+ public:
+ GraphicExporter();
+
+ // XFilter
+ virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) override;
+ virtual void SAL_CALL cancel( ) override;
+
+ // XExporter
+ virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XMimeTypeInfo
+ virtual sal_Bool SAL_CALL supportsMimeType( const OUString& MimeTypeName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedMimeTypeNames( ) override;
+
+ VclPtr<VirtualDevice> CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const;
+
+ DECL_LINK( CalcFieldValueHdl, EditFieldInfo*, void );
+
+ void ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings );
+ bool GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType );
+
+ private:
+ Reference< XShape > mxShape;
+ Reference< XDrawPage > mxPage;
+ Reference< XShapes > mxShapes;
+ Graphic maGraphic;
+
+ SvxDrawPage* mpUnoPage;
+
+ Link<EditFieldInfo*,void> maOldCalcFieldValueHdl;
+ sal_Int32 mnPageNumber;
+ SdrPage* mpCurrentPage;
+ SdrModel* mpDoc;
+ };
+
+ /** creates a bitmap that is optionally transparent from a metafile
+ */
+ BitmapEx GetBitmapFromMetaFile( const GDIMetaFile& rMtf, const Size* pSize )
+ {
+ // use new primitive conversion tooling
+ basegfx::B2DRange aRange(basegfx::B2DPoint(0.0, 0.0));
+ sal_uInt32 nMaximumQuadraticPixels(500000);
+
+ if(pSize)
+ {
+ // use 100th mm for primitive bitmap converter tool, input is pixel
+ // use a real OutDev to get the correct DPI, the static LogicToLogic assumes 72dpi which is wrong (!)
+ const Size aSize100th(Application::GetDefaultDevice()->PixelToLogic(*pSize, MapMode(MapUnit::Map100thMM)));
+
+ aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
+
+ // when explicitly pixels are requested from the GraphicExporter, use a *very* high limit
+ // of 16gb (4096x4096 pixels), else use the default for the converters
+ nMaximumQuadraticPixels = std::min(sal_uInt32(4096 * 4096), sal_uInt32(pSize->Width() * pSize->Height()));
+ }
+ else
+ {
+ // use 100th mm for primitive bitmap converter tool
+ const Size aSize100th(OutputDevice::LogicToLogic(rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)));
+
+ aRange.expand(basegfx::B2DPoint(aSize100th.Width(), aSize100th.Height()));
+ }
+
+ return convertMetafileToBitmapEx(rMtf, aRange, nMaximumQuadraticPixels);
+ }
+
+ Size* CalcSize( sal_Int32 nWidth, sal_Int32 nHeight, const Size& aBoundSize, Size& aOutSize )
+ {
+ if( (nWidth == 0) && (nHeight == 0) )
+ return nullptr;
+
+ if( (nWidth == 0) && (nHeight != 0) && (aBoundSize.Height() != 0) )
+ {
+ nWidth = ( nHeight * aBoundSize.Width() ) / aBoundSize.Height();
+ }
+ else if( (nWidth != 0) && (nHeight == 0) && (aBoundSize.Width() != 0) )
+ {
+ nHeight = ( nWidth * aBoundSize.Height() ) / aBoundSize.Width();
+ }
+
+ aOutSize.setWidth( nWidth );
+ aOutSize.setHeight( nHeight );
+
+ return &aOutSize;
+ }
+
+class ImplExportCheckVisisbilityRedirector : public sdr::contact::ViewObjectContactRedirector
+{
+public:
+ explicit ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage );
+
+ virtual void createRedirectedPrimitive2DSequence(
+ const sdr::contact::ViewObjectContact& rOriginal,
+ const sdr::contact::DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) override;
+
+private:
+ SdrPage* mpCurrentPage;
+};
+
+ImplExportCheckVisisbilityRedirector::ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage )
+: mpCurrentPage( pCurrentPage )
+{
+}
+
+void ImplExportCheckVisisbilityRedirector::createRedirectedPrimitive2DSequence(
+ const sdr::contact::ViewObjectContact& rOriginal,
+ const sdr::contact::DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+{
+ SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
+
+ if(pObject)
+ {
+ SdrPage* pPage = mpCurrentPage;
+
+ if(nullptr == pPage)
+ {
+ pPage = pObject->getSdrPageFromSdrObject();
+ }
+
+ if( (pPage == nullptr) || pPage->checkVisibility(rOriginal, rDisplayInfo, false) )
+ {
+ return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor);
+ }
+
+ return;
+ }
+ else
+ {
+ // not an object, maybe a page
+ sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor);
+ }
+}
+
+GraphicExporter::GraphicExporter()
+: mpUnoPage( nullptr ), mnPageNumber(-1), mpCurrentPage(nullptr), mpDoc( nullptr )
+{
+}
+
+IMPL_LINK(GraphicExporter, CalcFieldValueHdl, EditFieldInfo*, pInfo, void)
+{
+ if( pInfo )
+ {
+ if( mpCurrentPage )
+ {
+ pInfo->SetSdrPage( mpCurrentPage );
+ }
+ else if( mnPageNumber != -1 )
+ {
+ const SvxFieldData* pField = pInfo->GetField().GetField();
+ if( dynamic_cast<const SvxPageField*>( pField) )
+ {
+ OUString aPageNumValue;
+ bool bUpper = false;
+
+ switch(mpDoc->GetPageNumType())
+ {
+ case css::style::NumberingType::CHARS_UPPER_LETTER:
+ aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'A') );
+ break;
+ case css::style::NumberingType::CHARS_LOWER_LETTER:
+ aPageNumValue += OUStringChar( sal_Unicode((mnPageNumber - 1) % 26 + 'a') );
+ break;
+ case css::style::NumberingType::ROMAN_UPPER:
+ bUpper = true;
+ [[fallthrough]];
+ case css::style::NumberingType::ROMAN_LOWER:
+ aPageNumValue += SvxNumberFormat::CreateRomanString(mnPageNumber, bUpper);
+ break;
+ case css::style::NumberingType::NUMBER_NONE:
+ aPageNumValue = " ";
+ break;
+ default:
+ aPageNumValue += OUString::number( mnPageNumber );
+ }
+
+ pInfo->SetRepresentation( aPageNumValue );
+
+ return;
+ }
+ }
+ }
+
+ maOldCalcFieldValueHdl.Call( pInfo );
+
+ if( pInfo && mpCurrentPage )
+ pInfo->SetSdrPage( nullptr );
+}
+
+/** creates a virtual device for the given page
+
+ @return the returned VirtualDevice is owned by the caller
+*/
+VclPtr<VirtualDevice> GraphicExporter::CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const
+{
+ VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create();
+ MapMode aMM( MapUnit::Map100thMM );
+
+ Point aPoint( 0, 0 );
+ Size aPageSize(pPage->GetSize());
+
+ // use scaling?
+ if( nWidthPixel != 0 )
+ {
+ const Fraction aFrac( nWidthPixel, pVDev->LogicToPixel( aPageSize, aMM ).Width() );
+
+ aMM.SetScaleX( aFrac );
+
+ if( nHeightPixel == 0 )
+ aMM.SetScaleY( aFrac );
+ }
+
+ if( nHeightPixel != 0 )
+ {
+ const Fraction aFrac( nHeightPixel, pVDev->LogicToPixel( aPageSize, aMM ).Height() );
+
+ if( nWidthPixel == 0 )
+ aMM.SetScaleX( aFrac );
+
+ aMM.SetScaleY( aFrac );
+ }
+
+ pVDev->SetMapMode( aMM );
+ bool bSuccess(false);
+
+ // #i122820# If available, use pixel size directly
+ if(nWidthPixel && nHeightPixel)
+ {
+ bSuccess = pVDev->SetOutputSizePixel(Size(nWidthPixel, nHeightPixel));
+ }
+ else
+ {
+ bSuccess = pVDev->SetOutputSize(aPageSize);
+ }
+
+ if(bSuccess)
+ {
+ SdrView aView(*mpDoc, pVDev);
+
+ aView.SetPageVisible( false );
+ aView.SetBordVisible( false );
+ aView.SetGridVisible( false );
+ aView.SetHlplVisible( false );
+ aView.SetGlueVisible( false );
+ aView.ShowSdrPage(pPage);
+
+ vcl::Region aRegion (tools::Rectangle( aPoint, aPageSize ) );
+
+ ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
+
+ aView.CompleteRedraw(pVDev, aRegion, &aRedirector);
+ }
+ else
+ {
+ OSL_ENSURE(false, "Could not get a VirtualDevice of requested size (!)");
+ }
+
+ return pVDev;
+}
+
+void GraphicExporter::ParseSettings(const Sequence<PropertyValue>& rDescriptor,
+ ExportSettings& rSettings)
+{
+ Sequence<PropertyValue> aDescriptor = rDescriptor;
+ if (aDescriptor.hasElements())
+ {
+ comphelper::SequenceAsHashMap aMap(aDescriptor);
+ Sequence<PropertyValue> aFilterData;
+ OUString aFilterOptions;
+ auto it = aMap.find("FilterData");
+ if (it != aMap.end())
+ {
+ it->second >>= aFilterData;
+ }
+ it = aMap.find("FilterOptions");
+ if (it != aMap.end())
+ {
+ it->second >>= aFilterOptions;
+ }
+ if (!aFilterData.hasElements() && !aFilterOptions.isEmpty())
+ {
+ // Allow setting filter data keys from the cmdline.
+ std::vector<PropertyValue> aData
+ = comphelper::JsonToPropertyValues(aFilterOptions.toUtf8());
+ aFilterData = comphelper::containerToSequence(aData);
+ if (aFilterData.hasElements())
+ {
+ aMap["FilterData"] <<= aFilterData;
+ aDescriptor = aMap.getAsConstPropertyValueList();
+ }
+ }
+ }
+
+ for( const PropertyValue& rValue : aDescriptor )
+ {
+ if ( rValue.Name == "FilterName" )
+ {
+ rValue.Value >>= rSettings.maFilterName;
+ }
+ else if ( rValue.Name == "MediaType" )
+ {
+ rValue.Value >>= rSettings.maMediaType;
+ }
+ else if ( rValue.Name == "URL" )
+ {
+ if( !( rValue.Value >>= rSettings.maURL ) )
+ {
+ rValue.Value >>= rSettings.maURL.Complete;
+ }
+ }
+ else if ( rValue.Name == "OutputStream" )
+ {
+ rValue.Value >>= rSettings.mxOutputStream;
+ }
+ else if ( rValue.Name == "GraphicRenderer" )
+ {
+ rValue.Value >>= rSettings.mxGraphicRenderer;
+ }
+ else if ( rValue.Name == "StatusIndicator" )
+ {
+ rValue.Value >>= rSettings.mxStatusIndicator;
+ }
+ else if ( rValue.Name == "InteractionHandler" )
+ {
+ rValue.Value >>= rSettings.mxInteractionHandler;
+ }
+ else if( rValue.Name == "Width" ) // for compatibility reasons, deprecated
+ {
+ rValue.Value >>= rSettings.mnWidth;
+ }
+ else if( rValue.Name == "Height" ) // for compatibility reasons, deprecated
+ {
+ rValue.Value >>= rSettings.mnHeight;
+ }
+ else if( rValue.Name == "ExportOnlyBackground" ) // for compatibility reasons, deprecated
+ {
+ rValue.Value >>= rSettings.mbExportOnlyBackground;
+ }
+ else if ( rValue.Name == "FilterData" )
+ {
+ rValue.Value >>= rSettings.maFilterData;
+
+ for( PropertyValue& rDataValue : asNonConstRange(rSettings.maFilterData) )
+ {
+ if ( rDataValue.Name == "Translucent" )
+ {
+ if ( !( rDataValue.Value >>= rSettings.mbTranslucent ) ) // SJ: TODO: The GIF Transparency is stored as int32 in
+ { // configuration files, this has to be changed to boolean
+ sal_Int32 nTranslucent = 0;
+ if ( rDataValue.Value >>= nTranslucent )
+ rSettings.mbTranslucent = nTranslucent != 0;
+ }
+ }
+ else if ( rDataValue.Name == "PixelWidth" )
+ {
+ rDataValue.Value >>= rSettings.mnWidth;
+ }
+ else if ( rDataValue.Name == "PixelHeight" )
+ {
+ rDataValue.Value >>= rSettings.mnHeight;
+ }
+ else if( rDataValue.Name == "Width" ) // for compatibility reasons, deprecated
+ {
+ rDataValue.Value >>= rSettings.mnWidth;
+ rDataValue.Name = "PixelWidth";
+ }
+ else if( rDataValue.Name == "Height" ) // for compatibility reasons, deprecated
+ {
+ rDataValue.Value >>= rSettings.mnHeight;
+ rDataValue.Name = "PixelHeight";
+ }
+ else if ( rDataValue.Name == "ExportOnlyBackground" )
+ {
+ rDataValue.Value >>= rSettings.mbExportOnlyBackground;
+ }
+ else if ( rDataValue.Name == "HighContrast" )
+ {
+ rDataValue.Value >>= rSettings.mbUseHighContrast;
+ }
+ else if ( rDataValue.Name == "PageNumber" )
+ {
+ rDataValue.Value >>= mnPageNumber;
+ }
+ else if ( rDataValue.Name == "ScrollText" )
+ {
+ // #110496# Read flag solitary scroll text metafile
+ rDataValue.Value >>= rSettings.mbScrollText;
+ }
+ else if ( rDataValue.Name == "CurrentPage" )
+ {
+ Reference< XDrawPage > xPage;
+ rDataValue.Value >>= xPage;
+ if( xPage.is() )
+ {
+ SvxDrawPage* pUnoPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
+ if( pUnoPage && pUnoPage->GetSdrPage() )
+ mpCurrentPage = pUnoPage->GetSdrPage();
+ }
+ }
+ else if ( rDataValue.Name == "ScaleXNumerator" )
+ {
+ sal_Int32 nVal = 1;
+ if( rDataValue.Value >>= nVal )
+ rSettings.maScaleX = Fraction( nVal, rSettings.maScaleX.GetDenominator() );
+ }
+ else if ( rDataValue.Name == "ScaleXDenominator" )
+ {
+ sal_Int32 nVal = 1;
+ if( rDataValue.Value >>= nVal )
+ rSettings.maScaleX = Fraction( rSettings.maScaleX.GetNumerator(), nVal );
+ }
+ else if ( rDataValue.Name == "ScaleYNumerator" )
+ {
+ sal_Int32 nVal = 1;
+ if( rDataValue.Value >>= nVal )
+ rSettings.maScaleY = Fraction( nVal, rSettings.maScaleY.GetDenominator() );
+ }
+ else if ( rDataValue.Name == "ScaleYDenominator" )
+ {
+ sal_Int32 nVal = 1;
+ if( rDataValue.Value >>= nVal )
+ rSettings.maScaleY = Fraction( rSettings.maScaleY.GetNumerator(), nVal );
+ }
+ else if (rDataValue.Name == "AntiAliasing")
+ {
+ bool bAntiAliasing;
+ if (rDataValue.Value >>= bAntiAliasing)
+ rSettings.meAntiAliasing = bAntiAliasing ? TRISTATE_TRUE : TRISTATE_FALSE;
+ }
+ }
+ }
+ }
+
+ // putting the StatusIndicator that we got from the MediaDescriptor into our local FilterData copy
+ if ( rSettings.mxStatusIndicator.is() )
+ {
+ int i = rSettings.maFilterData.getLength();
+ rSettings.maFilterData.realloc( i + 1 );
+ auto pFilterData = rSettings.maFilterData.getArray();
+ pFilterData[ i ].Name = "StatusIndicator";
+ pFilterData[ i ].Value <<= rSettings.mxStatusIndicator;
+ }
+}
+
+bool GraphicExporter::GetGraphic( ExportSettings const & rSettings, Graphic& aGraphic, bool bVectorType )
+{
+ if( !mpDoc || !mpUnoPage )
+ return false;
+
+ SdrPage* pPage = mpUnoPage->GetSdrPage();
+ if( !pPage )
+ return false;
+
+ ScopedVclPtrInstance< VirtualDevice > aVDev;
+ const MapMode aMap( mpDoc->GetScaleUnit(), Point(), rSettings.maScaleX, rSettings.maScaleY );
+
+ SdrOutliner& rOutl=mpDoc->GetDrawOutliner();
+ maOldCalcFieldValueHdl = rOutl.GetCalcFieldValueHdl();
+ rOutl.SetCalcFieldValueHdl( LINK(this, GraphicExporter, CalcFieldValueHdl) );
+ rOutl.SetBackgroundColor( pPage->GetPageBackgroundColor() );
+
+ // #i102251#
+ const EEControlBits nOldCntrl(rOutl.GetControlWord());
+ EEControlBits nCntrl = nOldCntrl & ~EEControlBits::ONLINESPELLING;
+ rOutl.SetControlWord(nCntrl);
+
+ SdrObject* pTempBackgroundShape = nullptr;
+ std::vector< SdrObject* > aShapes;
+ bool bRet = true;
+
+ // export complete page?
+ if ( !mxShape.is() )
+ {
+ if( rSettings.mbExportOnlyBackground )
+ {
+ const SdrPageProperties* pCorrectProperties = pPage->getCorrectSdrPageProperties();
+
+ if(pCorrectProperties)
+ {
+ pTempBackgroundShape = new SdrRectObj(
+ *mpDoc,
+ tools::Rectangle(Point(0,0), pPage->GetSize()));
+ pTempBackgroundShape->SetMergedItemSet(pCorrectProperties->GetItemSet());
+ pTempBackgroundShape->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pTempBackgroundShape->NbcSetStyleSheet(pCorrectProperties->GetStyleSheet(), true);
+ aShapes.push_back(pTempBackgroundShape);
+ }
+ }
+ else
+ {
+ const Size aSize( pPage->GetSize() );
+
+ // generate a bitmap to convert it to a pixel format.
+ // For gif pictures there can also be a vector format used (bTranslucent)
+ if ( !bVectorType && !rSettings.mbTranslucent )
+ {
+ tools::Long nWidthPix = 0;
+ tools::Long nHeightPix = 0;
+ if ( rSettings.mnWidth > 0 && rSettings.mnHeight > 0 )
+ {
+ nWidthPix = rSettings.mnWidth;
+ nHeightPix = rSettings.mnHeight;
+ }
+ else
+ {
+ const Size aSizePix( Application::GetDefaultDevice()->LogicToPixel( aSize, aMap ) );
+ if (aSizePix.Width() > MAX_EXT_PIX || aSizePix.Height() > MAX_EXT_PIX)
+ {
+ if (aSizePix.Width() > MAX_EXT_PIX)
+ nWidthPix = MAX_EXT_PIX;
+ else
+ nWidthPix = aSizePix.Width();
+ if (aSizePix.Height() > MAX_EXT_PIX)
+ nHeightPix = MAX_EXT_PIX;
+ else
+ nHeightPix = aSizePix.Height();
+
+ double fWidthDif = static_cast<double>(aSizePix.Width()) / nWidthPix;
+ double fHeightDif = static_cast<double>(aSizePix.Height()) / nHeightPix;
+
+ if (fWidthDif > fHeightDif)
+ nHeightPix = static_cast<tools::Long>(aSizePix.Height() / fWidthDif);
+ else
+ nWidthPix = static_cast<tools::Long>(aSizePix.Width() / fHeightDif);
+ }
+ else
+ {
+ nWidthPix = aSizePix.Width();
+ nHeightPix = aSizePix.Height();
+ }
+ }
+
+ std::unique_ptr<SdrView> xLocalView;
+
+ if (FmFormModel* pFormModel = dynamic_cast<FmFormModel*>(mpDoc))
+ {
+ xLocalView.reset(new FmFormView(*pFormModel, aVDev));
+ }
+ else
+ {
+ xLocalView.reset(new SdrView(*mpDoc, aVDev));
+ }
+
+ ScopedVclPtr<VirtualDevice> pVDev(CreatePageVDev( pPage, nWidthPix, nHeightPix ));
+
+ if( pVDev )
+ {
+ aGraphic = pVDev->GetBitmapEx( Point(), pVDev->GetOutputSize() );
+ aGraphic.SetPrefMapMode( aMap );
+ aGraphic.SetPrefSize( aSize );
+ }
+ }
+ // create a metafile to export a vector format
+ else
+ {
+ GDIMetaFile aMtf;
+
+ aVDev->SetMapMode( aMap );
+ if( rSettings.mbUseHighContrast )
+ aVDev->SetDrawMode( aVDev->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
+ aVDev->EnableOutput( false );
+ aMtf.Record( aVDev );
+ Size aNewSize;
+
+ // create a view
+ std::unique_ptr< SdrView > pView;
+
+ if (FmFormModel *pFormModel = dynamic_cast<FmFormModel*>(mpDoc))
+ {
+ pView.reset(new FmFormView(*pFormModel, aVDev));
+ }
+ else
+ {
+ pView.reset(new SdrView(*mpDoc, aVDev));
+ }
+
+ pView->SetBordVisible( false );
+ pView->SetPageVisible( false );
+ pView->ShowSdrPage( pPage );
+
+ // tdf#96922 completely deactivate EditView PageVisualization, including
+ // PageBackground (formerly 'wiese').
+ pView->SetPagePaintingAllowed(false);
+
+ const Point aNewOrg( pPage->GetLeftBorder(), pPage->GetUpperBorder() );
+ aNewSize = Size( aSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder(),
+ aSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder() );
+ const tools::Rectangle aClipRect( aNewOrg, aNewSize );
+ MapMode aVMap( aMap );
+
+ aVDev->Push();
+ aVMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) );
+ aVDev->SetRelativeMapMode( aVMap );
+ aVDev->IntersectClipRegion( aClipRect );
+
+ // Use new StandardCheckVisisbilityRedirector
+ ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage );
+
+ pView->CompleteRedraw(aVDev, vcl::Region(tools::Rectangle(aNewOrg, aNewSize)), &aRedirector);
+
+ aVDev->Pop();
+
+ aMtf.Stop();
+ aMtf.WindStart();
+ aMtf.SetPrefMapMode( aMap );
+ aMtf.SetPrefSize( aNewSize );
+
+ // AW: Here the current version was filtering out the MetaActionType::CLIPREGIONs
+ // from the metafile. I asked some other developers why this was done, but no
+ // one knew a direct reason. Since it's in for long time, it may be an old
+ // piece of code. MetaFiles save and load ClipRegions with polygons with preserving
+ // the polygons, so a resolution-independent roundtrip is supported. Removed this
+ // code since it destroys some MetaFiles where ClipRegions are used. Anyways,
+ // just filtering them out is a hack, at least the encapsulated content would need
+ // to be clipped geometrically.
+ aGraphic = Graphic(aMtf);
+
+ pView->HideSdrPage();
+
+ if( rSettings.mbTranslucent )
+ {
+ Size aOutSize;
+ aGraphic = GetBitmapFromMetaFile( aGraphic.GetGDIMetaFile(), CalcSize( rSettings.mnWidth, rSettings.mnHeight, aNewSize, aOutSize ) );
+ }
+ }
+ }
+ }
+
+ // export only single shape or shape collection
+ else
+ {
+ // build list of SdrObject
+ if( mxShapes.is() )
+ {
+ Reference< XShape > xShape;
+ const sal_Int32 nCount = mxShapes->getCount();
+
+ for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ mxShapes->getByIndex( nIndex ) >>= xShape;
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
+ if( pObj )
+ aShapes.push_back( pObj );
+ }
+ }
+ else
+ {
+ // only one shape
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
+ if( pObj )
+ aShapes.push_back( pObj );
+ }
+
+ if( aShapes.empty() )
+ bRet = false;
+ }
+
+ if( bRet && !aShapes.empty() )
+ {
+ // special treatment for only one SdrGrafObj that has text
+ bool bSingleGraphic = false;
+
+ if( 1 == aShapes.size() )
+ {
+ if( !bVectorType )
+ {
+ if( auto pGrafObj = dynamic_cast<const SdrGrafObj*>(aShapes.front()) )
+ if (pGrafObj->HasText() )
+ {
+ aGraphic = pGrafObj->GetTransformedGraphic();
+ if ( aGraphic.GetType() == GraphicType::Bitmap )
+ {
+ Size aSizePixel( aGraphic.GetSizePixel() );
+ if( rSettings.mnWidth && rSettings.mnHeight &&
+ ( ( rSettings.mnWidth != aSizePixel.Width() ) ||
+ ( rSettings.mnHeight != aSizePixel.Height() ) ) )
+ {
+ BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
+ // export: use highest quality
+ aBmpEx.Scale( Size( rSettings.mnWidth, rSettings.mnHeight ), BmpScaleFlag::Lanczos );
+ aGraphic = aBmpEx;
+ }
+
+ // #118804# only accept for bitmap graphics, else the
+ // conversion to bitmap will happen anywhere without size control
+ // as evtl. defined in rSettings.mnWidth/mnHeight
+ bSingleGraphic = true;
+ }
+ }
+ }
+ else if( rSettings.mbScrollText )
+ {
+ SdrObject* pObj = aShapes.front();
+ auto pTextObj = dynamic_cast<SdrTextObj*>( pObj);
+ if( pTextObj && pTextObj->HasText() )
+ {
+ tools::Rectangle aScrollRectangle;
+ tools::Rectangle aPaintRectangle;
+
+ const std::unique_ptr< GDIMetaFile > pMtf(
+ pTextObj->GetTextScrollMetaFileAndRectangle(
+ aScrollRectangle, aPaintRectangle ) );
+
+ // take the larger one of the two rectangles (that
+ // should be the bound rect of the retrieved
+ // metafile)
+ tools::Rectangle aTextRect;
+
+ if( aScrollRectangle.Contains( aPaintRectangle ) )
+ aTextRect = aScrollRectangle;
+ else
+ aTextRect = aPaintRectangle;
+
+ // setup pref size and mapmode
+ pMtf->SetPrefSize( aTextRect.GetSize() );
+
+ // set actual origin (mtf is at actual shape
+ // output position)
+ MapMode aLocalMapMode( aMap );
+ aLocalMapMode.SetOrigin(
+ Point( -aPaintRectangle.Left(),
+ -aPaintRectangle.Top() ) );
+ pMtf->SetPrefMapMode( aLocalMapMode );
+
+ pMtf->AddAction( new MetaCommentAction(
+ "XTEXT_SCROLLRECT", 0,
+ reinterpret_cast<sal_uInt8 const*>(&aScrollRectangle),
+ sizeof( tools::Rectangle ) ) );
+ pMtf->AddAction( new MetaCommentAction(
+ "XTEXT_PAINTRECT", 0,
+ reinterpret_cast<sal_uInt8 const*>(&aPaintRectangle),
+ sizeof( tools::Rectangle ) ) );
+
+ aGraphic = Graphic( *pMtf );
+
+ bSingleGraphic = true;
+ }
+ }
+ }
+
+ if( !bSingleGraphic )
+ {
+ // create a metafile for all shapes
+ ScopedVclPtrInstance< VirtualDevice > aOut;
+
+ // calculate bound rect for all shapes
+ // tdf#126319 I did not convert all rendering to primities,
+ // that would be to much for this fix. But I did so for the
+ // range calculation to get a valid high quality range.
+ // Based on that the conversion is reliable. With the BoundRect
+ // fetched from the Metafile it was just not possible to get the
+ // examples from the task handled in a way to fit all cases -
+ // due to bad-quality range data from it.
+ basegfx::B2DRange aBound;
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+
+ {
+ for( SdrObject* pObj : aShapes )
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aSequence;
+ pObj->GetViewContact().getViewIndependentPrimitive2DContainer(aSequence);
+ aBound.expand(aSequence.getB2DRange(aViewInformation2D));
+ }
+ }
+
+ aOut->EnableOutput( false );
+ aOut->SetMapMode( aMap );
+ if( rSettings.mbUseHighContrast )
+ aOut->SetDrawMode( aOut->GetDrawMode() | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
+
+ GDIMetaFile aMtf;
+ aMtf.Clear();
+ aMtf.Record( aOut );
+
+ MapMode aOutMap( aMap );
+ const Size aOnePixelInMtf(
+ Application::GetDefaultDevice()->PixelToLogic(
+ Size(1, 1),
+ aMap));
+ const Size aHalfPixelInMtf(
+ (aOnePixelInMtf.getWidth() + 1) / 2,
+ (aOnePixelInMtf.getHeight() + 1) / 2);
+
+ // tdf#126319 Immediately add needed offset to create metafile,
+ // that avoids to do it later by Metafile::Move what would be expensive
+ aOutMap.SetOrigin(
+ Point(
+ basegfx::fround(-aBound.getMinX() - aHalfPixelInMtf.getWidth()),
+ basegfx::fround(-aBound.getMinY() - aHalfPixelInMtf.getHeight()) ) );
+ aOut->SetRelativeMapMode( aOutMap );
+
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ if(mpCurrentPage)
+ {
+ if(mpCurrentPage->TRG_HasMasterPage() && pPage->IsMasterPage())
+ {
+ // MasterPage is processed as another page's SubContent
+ aDisplayInfo.SetProcessLayers(mpCurrentPage->TRG_GetMasterPageVisibleLayers());
+ aDisplayInfo.SetSubContentActive(true);
+ }
+ }
+
+ if(!aShapes.empty())
+ {
+ // more effective way to paint a vector of SdrObjects. Hand over the processed page
+ // to have it in the
+ ImplExportCheckVisisbilityRedirector aCheckVisibilityRedirector(mpCurrentPage);
+ sdr::contact::ObjectContactOfObjListPainter aMultiObjectPainter(*aOut, std::move(aShapes), mpCurrentPage);
+ aMultiObjectPainter.SetViewObjectContactRedirector(&aCheckVisibilityRedirector);
+
+ aMultiObjectPainter.ProcessDisplay(aDisplayInfo);
+ }
+
+ aMtf.Stop();
+ aMtf.WindStart();
+
+ // tdf#126319 Immediately add needed size to target's PrefSize
+ const Size aBoundSize(
+ basegfx::fround(aBound.getWidth() + aHalfPixelInMtf.getWidth()),
+ basegfx::fround(aBound.getHeight() + aHalfPixelInMtf.getHeight()));
+
+ aMtf.SetPrefMapMode( aMap );
+ aMtf.SetPrefSize( aBoundSize );
+
+ if( !bVectorType )
+ {
+ Size aOutSize;
+ aGraphic = GetBitmapFromMetaFile( aMtf, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aBoundSize, aOutSize ) );
+ }
+ else
+ {
+ aGraphic = aMtf;
+ }
+ }
+ }
+
+ if(pTempBackgroundShape)
+ {
+ SdrObject::Free(pTempBackgroundShape);
+ }
+
+ rOutl.SetCalcFieldValueHdl( maOldCalcFieldValueHdl );
+
+ // #i102251#
+ rOutl.SetControlWord(nOldCntrl);
+
+ return bRet;
+
+}
+
+// XFilter
+sal_Bool SAL_CALL GraphicExporter::filter( const Sequence< PropertyValue >& aDescriptor )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( maGraphic.IsNone() && nullptr == mpUnoPage )
+ return false;
+
+ if( maGraphic.IsNone() && ( nullptr == mpUnoPage->GetSdrPage() || nullptr == mpDoc ) )
+ return false;
+
+ GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
+
+ // get the arguments from the descriptor
+ ExportSettings aSettings(mpDoc);
+ ParseSettings(aDescriptor, aSettings);
+
+ const sal_uInt16 nFilter = !aSettings.maMediaType.isEmpty()
+ ? rFilter.GetExportFormatNumberForMediaType( aSettings.maMediaType )
+ : rFilter.GetExportFormatNumberForShortName( aSettings.maFilterName );
+ bool bVectorType = !rFilter.IsExportPixelFormat( nFilter );
+
+ // create the output stuff
+ Graphic aGraphic = maGraphic;
+
+ ErrCode nStatus = ERRCODE_NONE;
+ if (maGraphic.IsNone())
+ {
+ bool bAntiAliasing = SvtOptionsDrawinglayer::IsAntiAliasing();
+ AllSettings aAllSettings = Application::GetSettings();
+ StyleSettings aStyleSettings = aAllSettings.GetStyleSettings();
+ bool bUseFontAAFromSystem = aStyleSettings.GetUseFontAAFromSystem();
+ if (aSettings.meAntiAliasing != TRISTATE_INDET)
+ {
+ // This is safe to do globally as we own the solar mutex.
+ SvtOptionsDrawinglayer::SetAntiAliasing(aSettings.meAntiAliasing == TRISTATE_TRUE, /*bTemporary*/true);
+ // Opt in to have AA affect font rendering as well.
+ aStyleSettings.SetUseFontAAFromSystem(false);
+ aAllSettings.SetStyleSettings(aStyleSettings);
+ Application::SetSettings(aAllSettings);
+ }
+ nStatus = GetGraphic( aSettings, aGraphic, bVectorType ) ? ERRCODE_NONE : ERRCODE_GRFILTER_FILTERERROR;
+ if (aSettings.meAntiAliasing != TRISTATE_INDET)
+ {
+ SvtOptionsDrawinglayer::SetAntiAliasing(bAntiAliasing, /*bTemporary*/true);
+ aStyleSettings.SetUseFontAAFromSystem(bUseFontAAFromSystem);
+ aAllSettings.SetStyleSettings(aStyleSettings);
+ Application::SetSettings(aAllSettings);
+ }
+ }
+
+ if( nStatus == ERRCODE_NONE )
+ {
+ // export graphic only if it has a size
+ const Size aGraphSize( aGraphic.GetPrefSize() );
+ if ( aGraphSize.IsEmpty() )
+ {
+ nStatus = ERRCODE_GRFILTER_FILTERERROR;
+ }
+ else
+ {
+ // now we have a graphic, so export it
+ if( aSettings.mxGraphicRenderer.is() )
+ {
+ // render graphic directly into given renderer
+ aSettings.mxGraphicRenderer->render( aGraphic.GetXGraphic() );
+ }
+ else if( aSettings.mxOutputStream.is() )
+ {
+ // TODO: Either utilize optional XSeekable functionality for the
+ // SvOutputStream, or adapt the graphic filter to not seek anymore.
+ SvMemoryStream aStream( 1024, 1024 );
+
+ nStatus = rFilter.ExportGraphic( aGraphic, u"", aStream, nFilter, &aSettings.maFilterData );
+
+ // copy temp stream to XOutputStream
+ SvOutputStream aOutputStream( aSettings.mxOutputStream );
+ aStream.Seek(0);
+ aOutputStream.WriteStream( aStream );
+ }
+ else
+ {
+ INetURLObject aURLObject( aSettings.maURL.Complete );
+ DBG_ASSERT( aURLObject.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+
+ nStatus = XOutBitmap::ExportGraphic( aGraphic, aURLObject, rFilter, nFilter, &aSettings.maFilterData );
+ }
+ }
+ }
+
+ if ( aSettings.mxInteractionHandler.is() && ( nStatus != ERRCODE_NONE ) )
+ {
+ Any aInteraction;
+ Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations{
+ new ::comphelper::OInteractionApprove()
+ };
+
+ GraphicFilterRequest aErrorCode;
+ aErrorCode.ErrCode = sal_uInt32(nStatus);
+ aInteraction <<= aErrorCode;
+ aSettings.mxInteractionHandler->handle( framework::InteractionRequest::CreateRequest( aInteraction, lContinuations ) );
+ }
+ return nStatus == ERRCODE_NONE;
+}
+
+void SAL_CALL GraphicExporter::cancel()
+{
+}
+
+// XExporter
+
+/** the source 'document' could be a XDrawPage, a XShape or a generic XShapes */
+void SAL_CALL GraphicExporter::setSourceDocument( const Reference< lang::XComponent >& xComponent )
+{
+ ::SolarMutexGuard aGuard;
+
+ mxShapes = nullptr;
+ mpUnoPage = nullptr;
+
+ try
+ {
+ // any break inside this one loop while will throw an IllegalArgumentException
+ do
+ {
+ mxPage.set( xComponent, UNO_QUERY );
+ mxShapes.set( xComponent, UNO_QUERY );
+ mxShape.set( xComponent, UNO_QUERY );
+
+ // Step 1: try a generic XShapes
+ if( !mxPage.is() && !mxShape.is() && mxShapes.is() )
+ {
+ // we do not support empty shape collections
+ if( 0 == mxShapes->getCount() )
+ break;
+
+ // get first shape to detect corresponding page and model
+ mxShapes->getByIndex(0) >>= mxShape;
+ }
+ else
+ {
+ mxShapes = nullptr;
+ }
+
+ // Step 2: try a shape
+ if( mxShape.is() )
+ {
+ if (nullptr == SdrObject::getSdrObjectFromXShape(mxShape))
+ {
+ // This is not a Draw shape, let's see if it's a Writer one.
+ uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
+ if (!xPropertySet.is())
+ break;
+ uno::Reference<graphic::XGraphic> xGraphic(
+ xPropertySet->getPropertyValue("Graphic"), uno::UNO_QUERY);
+ if (!xGraphic.is())
+ break;
+
+ maGraphic = Graphic(xGraphic);
+ if (!maGraphic.IsNone())
+ return;
+ else
+ break;
+ }
+
+ // get page for this shape
+ Reference< XChild > xChild( mxShape, UNO_QUERY );
+ if( !xChild.is() )
+ break;
+
+ Reference< XInterface > xInt;
+ do
+ {
+ xInt = xChild->getParent();
+ mxPage.set( xInt, UNO_QUERY );
+ if( !mxPage.is() )
+ xChild.set( xInt, UNO_QUERY );
+ }
+ while( !mxPage.is() && xChild.is() );
+
+ if( !mxPage.is() )
+ break;
+ }
+
+ // Step 3: check the page
+ if( !mxPage.is() )
+ break;
+
+ mpUnoPage = comphelper::getFromUnoTunnel<SvxDrawPage>( mxPage );
+
+ if( nullptr == mpUnoPage || nullptr == mpUnoPage->GetSdrPage() )
+ break;
+
+ mpDoc = &mpUnoPage->GetSdrPage()->getSdrModelFromSdrPage();
+
+ // Step 4: If we got a generic XShapes test all contained shapes
+ // if they belong to the same XDrawPage
+
+ if( mxShapes.is() )
+ {
+ SdrPage* pPage = mpUnoPage->GetSdrPage();
+ SdrObject* pObj;
+ Reference< XShape > xShape;
+
+ bool bOk = true;
+
+ const sal_Int32 nCount = mxShapes->getCount();
+
+ // test all but the first shape if they have the same page than
+ // the first shape
+ for( sal_Int32 nIndex = 1; bOk && ( nIndex < nCount ); nIndex++ )
+ {
+ mxShapes->getByIndex( nIndex ) >>= xShape;
+ pObj = SdrObject::getSdrObjectFromXShape(xShape);
+ bOk = pObj && pObj->getSdrPageFromSdrObject() == pPage;
+ }
+
+ if( !bOk )
+ break;
+ }
+
+ // no errors so far
+ return;
+ }
+ while( false );
+ }
+ catch( Exception& )
+ {
+ }
+
+ throw IllegalArgumentException();
+}
+
+// XServiceInfo
+OUString SAL_CALL GraphicExporter::getImplementationName( )
+{
+ return "com.sun.star.comp.Draw.GraphicExporter";
+}
+
+sal_Bool SAL_CALL GraphicExporter::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL GraphicExporter::getSupportedServiceNames( )
+{
+ Sequence< OUString > aSupportedServiceNames { "com.sun.star.drawing.GraphicExportFilter" };
+ return aSupportedServiceNames;
+}
+
+// XMimeTypeInfo
+sal_Bool SAL_CALL GraphicExporter::supportsMimeType( const OUString& rMimeTypeName )
+{
+ GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
+ sal_uInt16 nCount = rFilter.GetExportFormatCount();
+ sal_uInt16 nFilter;
+ for( nFilter = 0; nFilter < nCount; nFilter++ )
+ {
+ if( rMimeTypeName == rFilter.GetExportFormatMediaType( nFilter ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Sequence< OUString > SAL_CALL GraphicExporter::getSupportedMimeTypeNames( )
+{
+ GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
+ sal_uInt16 nCount = rFilter.GetExportFormatCount();
+ sal_uInt16 nFilter;
+ sal_uInt16 nFound = 0;
+
+ Sequence< OUString > aSeq( nCount );
+ OUString* pStr = aSeq.getArray();
+
+ for( nFilter = 0; nFilter < nCount; nFilter++ )
+ {
+ OUString aMimeType( rFilter.GetExportFormatMediaType( nFilter ) );
+ if( !aMimeType.isEmpty() )
+ {
+ *pStr++ = aMimeType;
+ nFound++;
+ }
+ }
+
+ if( nFound < nCount )
+ aSeq.realloc( nFound );
+
+ return aSeq;
+}
+
+}
+
+Graphic SvxGetGraphicForShape( SdrObject& rShape )
+{
+ Graphic aGraphic;
+ try
+ {
+ rtl::Reference< GraphicExporter > xExporter( new GraphicExporter() );
+ Reference< XComponent > xComp( rShape.getUnoShape(), UNO_QUERY_THROW );
+ xExporter->setSourceDocument( xComp );
+ ExportSettings aSettings(&rShape.getSdrModelFromSdrObject());
+ xExporter->GetGraphic( aSettings, aGraphic, true/*bVector*/ );
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+ return aGraphic;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_Draw_GraphicExporter_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new GraphicExporter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/UnoGraphicExporter.hxx b/svx/source/unodraw/UnoGraphicExporter.hxx
new file mode 100644
index 000000000..ace0db252
--- /dev/null
+++ b/svx/source/unodraw/UnoGraphicExporter.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_UNODRAW_UNOGRAPHICEXPORTER_HXX
+#define INCLUDED_SVX_SOURCE_UNODRAW_UNOGRAPHICEXPORTER_HXX
+
+#include <sal/config.h>
+
+#include <vcl/graph.hxx>
+
+class SdrObject;
+
+Graphic SvxGetGraphicForShape(SdrObject& rShape);
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/UnoNameItemTable.cxx b/svx/source/unodraw/UnoNameItemTable.cxx
new file mode 100644
index 000000000..67b1dcc7d
--- /dev/null
+++ b/svx/source/unodraw/UnoNameItemTable.cxx
@@ -0,0 +1,282 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <set>
+
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <comphelper/profilezone.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <svx/svdmodel.hxx>
+#include "UnoNameItemTable.hxx"
+#include <vcl/svapp.hxx>
+
+#include <svx/unoapi.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::cppu;
+
+namespace
+{
+ // We need to override operator== here and specifically bypass the assert
+ // in SfxPoolItem::operator== in order to make the FindItemSurrogate call
+ // in SvxUnoNameItemTable::hasByName safe.
+ class SampleItem : public NameOrIndex
+ {
+ public:
+ SampleItem(sal_uInt16 nWhich, const OUString& rName) : NameOrIndex(TypedWhichId<NameOrIndex>(nWhich), rName) {}
+
+ bool operator==(const SfxPoolItem& rCmp) const
+ {
+ assert(dynamic_cast<const NameOrIndex*>(&rCmp) && "comparing different pool item subclasses");
+ auto const & rOther = static_cast<const NameOrIndex&>(rCmp);
+ return GetName() == rOther.GetName() && GetPalIndex() == rOther.GetPalIndex();
+ }
+ };
+
+}
+
+
+SvxUnoNameItemTable::SvxUnoNameItemTable( SdrModel* pModel, sal_uInt16 nWhich, sal_uInt8 nMemberId ) noexcept
+: mpModel( pModel ),
+ mpModelPool( pModel ? &pModel->GetItemPool() : nullptr ),
+ mnWhich( nWhich ), mnMemberId( nMemberId )
+{
+ if( pModel )
+ StartListening( *pModel );
+}
+
+SvxUnoNameItemTable::~SvxUnoNameItemTable() noexcept
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel )
+ EndListening( *mpModel );
+ dispose();
+}
+
+bool SvxUnoNameItemTable::isValid( const NameOrIndex* pItem ) const
+{
+ return pItem && !pItem->GetName().isEmpty();
+}
+
+void SvxUnoNameItemTable::dispose()
+{
+ maItemSetVector.clear();
+}
+
+void SvxUnoNameItemTable::Notify( SfxBroadcaster&, const SfxHint& rHint ) noexcept
+{
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ if( SdrHintKind::ModelCleared == pSdrHint->GetKind() )
+ dispose();
+}
+
+sal_Bool SAL_CALL SvxUnoNameItemTable::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+void SvxUnoNameItemTable::ImplInsertByName( const OUString& aName, const uno::Any& aElement )
+{
+ maItemSetVector.push_back( std::make_unique< SfxItemSet >( *mpModelPool, mnWhich, mnWhich ) );
+
+ std::unique_ptr<NameOrIndex> xNewItem(createItem());
+ xNewItem->SetName(aName);
+ xNewItem->PutValue(aElement, mnMemberId);
+ xNewItem->SetWhich(mnWhich);
+ maItemSetVector.back()->Put(std::move(xNewItem));
+}
+
+// XNameContainer
+void SAL_CALL SvxUnoNameItemTable::insertByName( const OUString& aApiName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ comphelper::ProfileZone aZone("SvxUnoNameItemTable::insertByName");
+
+ if( hasByName( aApiName ) )
+ throw container::ElementExistException();
+
+ OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName);
+
+ ImplInsertByName( aName, aElement );
+}
+
+void SAL_CALL SvxUnoNameItemTable::cancel()
+{
+ SolarMutexGuard aGuard;
+ // drop all items that are owned by this service and not the document
+ // (i.e. they are unused)
+ dispose();
+}
+
+void SAL_CALL SvxUnoNameItemTable::removeByName( const OUString& aApiName )
+{
+ SolarMutexGuard aGuard;
+ comphelper::ProfileZone aZone("SvxUnoNameItemTable::removeByName");
+
+ OUString sName = SvxUnogetInternalNameForItem(mnWhich, aApiName);
+
+ auto aIter = std::find_if(maItemSetVector.begin(), maItemSetVector.end(),
+ [&](const std::unique_ptr<SfxItemSet>& rpItem) {
+ const NameOrIndex *pItem = static_cast<const NameOrIndex *>(&(rpItem->Get( mnWhich ) ));
+ return sName == pItem->GetName();
+ });
+ if (aIter != maItemSetVector.end())
+ {
+ maItemSetVector.erase( aIter );
+ return;
+ }
+
+ if (!hasByName(sName))
+ throw container::NoSuchElementException();
+}
+
+// XNameReplace
+void SAL_CALL SvxUnoNameItemTable::replaceByName( const OUString& aApiName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+
+ OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName);
+
+ auto aIter = std::find_if(maItemSetVector.begin(), maItemSetVector.end(),
+ [&](const std::unique_ptr<SfxItemSet>& rpItem) {
+ const NameOrIndex *pItem = static_cast<const NameOrIndex *>(&(rpItem->Get( mnWhich ) ));
+ return aName == pItem->GetName();
+ });
+ if (aIter != maItemSetVector.end())
+ {
+ std::unique_ptr<NameOrIndex> xNewItem(createItem());
+ xNewItem->SetName(aName);
+ if (!xNewItem->PutValue(aElement, mnMemberId) || !isValid(xNewItem.get()))
+ throw lang::IllegalArgumentException();
+ (*aIter)->Put(std::move(xNewItem));
+ return;
+ }
+
+ // if it is not in our own sets, modify the pool!
+ bool bFound = false;
+
+ if (mpModelPool)
+ {
+ SampleItem aSample(mnWhich, aName);
+ for (const SfxPoolItem* pNameOrIndex : mpModelPool->FindItemSurrogate(mnWhich, aSample))
+ if (isValid(static_cast<const NameOrIndex*>(pNameOrIndex)))
+ {
+ const_cast<SfxPoolItem*>(pNameOrIndex)->PutValue( aElement, mnMemberId );
+ bFound = true;
+ }
+ }
+
+ if( !bFound )
+ throw container::NoSuchElementException();
+
+ ImplInsertByName( aName, aElement );
+
+ if( !hasByName( aName ) )
+ throw container::NoSuchElementException();
+}
+
+// XNameAccess
+uno::Any SAL_CALL SvxUnoNameItemTable::getByName( const OUString& aApiName )
+{
+ SolarMutexGuard aGuard;
+ comphelper::ProfileZone aZone("SvxUnoNameItemTable::getByName");
+
+ OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName);
+
+ if (mpModelPool && !aName.isEmpty())
+ {
+ SampleItem aSample(mnWhich, aName);
+ for (const SfxPoolItem* pFindItem : mpModelPool->FindItemSurrogate(mnWhich, aSample))
+ if (isValid(static_cast<const NameOrIndex*>(pFindItem)))
+ {
+ uno::Any aAny;
+ pFindItem->QueryValue( aAny, mnMemberId );
+ return aAny;
+ }
+ }
+
+ throw container::NoSuchElementException();
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoNameItemTable::getElementNames( )
+{
+ SolarMutexGuard aGuard;
+
+ std::set< OUString > aNameSet;
+
+
+ if (mpModelPool)
+ for (const SfxPoolItem* pItem : mpModelPool->GetItemSurrogates(mnWhich))
+ {
+ const NameOrIndex *pNameOrIndex = static_cast<const NameOrIndex*>(pItem);
+
+ if( !isValid( pNameOrIndex ) )
+ continue;
+
+ OUString aApiName = SvxUnogetApiNameForItem(mnWhich, pNameOrIndex->GetName());
+ aNameSet.insert(aApiName);
+ }
+
+ return comphelper::containerToSequence(aNameSet);
+}
+
+sal_Bool SAL_CALL SvxUnoNameItemTable::hasByName( const OUString& aApiName )
+{
+ SolarMutexGuard aGuard;
+
+ OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName);
+
+ if (aName.isEmpty())
+ return false;
+
+ if (!mpModelPool)
+ return false;
+
+ SampleItem aSample(mnWhich, aName);
+ for (const SfxPoolItem* pFindItem : mpModelPool->FindItemSurrogate(mnWhich, aSample))
+ if (isValid(static_cast<const NameOrIndex*>(pFindItem)))
+ return true;
+ return false;
+}
+
+sal_Bool SAL_CALL SvxUnoNameItemTable::hasElements( )
+{
+ SolarMutexGuard aGuard;
+
+ if (mpModelPool)
+ for (const SfxPoolItem* pItem : mpModelPool->GetItemSurrogates(mnWhich))
+ {
+ const NameOrIndex *pNameOrIndex = static_cast<const NameOrIndex*>(pItem);
+
+ if( isValid( pNameOrIndex ) )
+ return true;
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/UnoNameItemTable.hxx b/svx/source/unodraw/UnoNameItemTable.hxx
new file mode 100644
index 000000000..c1c798869
--- /dev/null
+++ b/svx/source/unodraw/UnoNameItemTable.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_UNODRAW_UNONAMEITEMTABLE_HXX
+#define INCLUDED_SVX_SOURCE_UNODRAW_UNONAMEITEMTABLE_HXX
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+#include <vector>
+#include <svl/lstner.hxx>
+#include <svx/xit.hxx>
+
+class SdrModel;
+class SfxItemPool;
+class SfxItemSet;
+
+typedef std::vector< std::unique_ptr< SfxItemSet > > ItemPoolVector;
+class SvxUnoNameItemTable
+ : public cppu::WeakImplHelper<
+ css::util::XCancellable,
+ css::container::XNameContainer,
+ css::lang::XServiceInfo >
+ , public SfxListener
+{
+private:
+ SdrModel* mpModel;
+ SfxItemPool* mpModelPool;
+ sal_uInt16 mnWhich;
+ sal_uInt8 mnMemberId;
+
+ /// vector contains all items that were created by this service and will
+ /// keep them alive even if nothing in the document references them
+ ItemPoolVector maItemSetVector;
+
+ void ImplInsertByName( const OUString& aName, const css::uno::Any& aElement );
+
+public:
+ SvxUnoNameItemTable( SdrModel* pModel, sal_uInt16 nWhich, sal_uInt8 nMemberId ) noexcept;
+ virtual ~SvxUnoNameItemTable() noexcept override;
+
+ virtual NameOrIndex* createItem() const = 0;
+ virtual bool isValid( const NameOrIndex* pItem ) const;
+
+ void dispose();
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) noexcept override;
+
+ // XServiceInfo
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+
+ // XCancellable
+ virtual void SAL_CALL cancel() override;
+
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& aName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& Name ) override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+};
+
+#endif // INCLUDED_SVX_SOURCE_UNODRAW_UNONAMEITEMTABLE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/UnoNamespaceMap.cxx b/svx/source/unodraw/UnoNamespaceMap.cxx
new file mode 100644
index 000000000..cd49cc0a6
--- /dev/null
+++ b/svx/source/unodraw/UnoNamespaceMap.cxx
@@ -0,0 +1,275 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <climits>
+#include <set>
+
+#include <svx/UnoNamespaceMap.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <svl/itempool.hxx>
+#include <editeng/xmlcnitm.hxx>
+
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+namespace svx
+{
+ namespace {
+
+ /** implements a component to export namespaces of all SvXMLAttrContainerItem inside
+ one or two pools with a variable count of which ids.
+ */
+ class NamespaceMap : public WeakImplHelper< XNameAccess, XServiceInfo >
+ {
+ private:
+ sal_uInt16* mpWhichIds;
+ SfxItemPool* mpPool;
+
+ public:
+ NamespaceMap( sal_uInt16* pWhichIds, SfxItemPool* pPool );
+
+ // XNameAccess
+ virtual Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ };
+
+ }
+
+ Reference< XInterface > NamespaceMap_createInstance( sal_uInt16* pWhichIds, SfxItemPool* pPool )
+ {
+ return static_cast<XWeak*>(new NamespaceMap( pWhichIds, pPool ));
+ }
+
+ static Sequence< OUString > NamespaceMap_getSupportedServiceNames()
+ noexcept
+ {
+ Sequence<OUString> aSupportedServiceNames { "com.sun.star.xml.NamespaceMap" };
+ return aSupportedServiceNames;
+ }
+
+ static OUString NamespaceMap_getImplementationName()
+ noexcept
+ {
+ return "com.sun.star.comp.Svx.NamespaceMap";
+ }
+
+ namespace {
+
+ class NamespaceIteratorImpl
+ {
+ private:
+ SfxItemPool* mpPool;
+
+ sal_uInt16* mpWhichId;
+
+ std::vector<const SvXMLAttrContainerItem*> mvItems;
+ sal_Int32 mnItem;
+
+ const SvXMLAttrContainerItem* mpCurrentAttr;
+ sal_uInt16 mnCurrentAttr;
+
+ public:
+
+ NamespaceIteratorImpl( sal_uInt16* pWhichIds, SfxItemPool* pPool );
+
+ bool next( OUString& rPrefix, OUString& rURL );
+ };
+
+ }
+}
+
+using namespace ::svx;
+
+
+NamespaceIteratorImpl::NamespaceIteratorImpl( sal_uInt16* pWhichIds, SfxItemPool* pPool )
+{
+ mpPool = pPool;
+ mpCurrentAttr = nullptr;
+ mnCurrentAttr = 0;
+
+ mpWhichId = pWhichIds;
+
+ mnItem = -1;
+ if (mpWhichId && (0 != *mpWhichId) && mpPool)
+ {
+ mvItems.reserve(mpPool->GetItemCount2( *mpWhichId ));
+ for (const SfxPoolItem* pItem : mpPool->GetItemSurrogates( *mpWhichId ))
+ mvItems.push_back(static_cast<const SvXMLAttrContainerItem*>(pItem));
+ }
+}
+
+bool NamespaceIteratorImpl::next( OUString& rPrefix, OUString& rURL )
+{
+ // we still need to process the current attribute
+ if( mpCurrentAttr && (mnCurrentAttr != USHRT_MAX) )
+ {
+ rPrefix = mpCurrentAttr->GetPrefix( mnCurrentAttr );
+ rURL = mpCurrentAttr->GetNamespace( mnCurrentAttr );
+
+ mnCurrentAttr = mpCurrentAttr->GetNextNamespaceIndex( mnCurrentAttr );
+ return true;
+ }
+
+ // we need the next namespace item
+ mpCurrentAttr = nullptr;
+ mnItem++;
+
+ // are we finished with the current whichid?
+ if( mnItem == static_cast<sal_Int32>(mvItems.size()) )
+ {
+ mpWhichId++;
+
+ // are we finished with the current pool?
+ if( 0 == *mpWhichId )
+ return false;
+
+ mnItem = -1;
+ mvItems.clear();
+ if (mpPool)
+ {
+ mvItems.reserve(mpPool->GetItemCount2( *mpWhichId ));
+ for (const SfxPoolItem* pItem2 : mpPool->GetItemSurrogates( *mpWhichId ))
+ mvItems.push_back(static_cast<const SvXMLAttrContainerItem*>(pItem2));
+ }
+ return next( rPrefix, rURL );
+ }
+
+ auto pItem = mvItems[mnItem];
+ // get that item and see if there namespaces inside
+ if( pItem->GetAttrCount() > 0 )
+ {
+ mpCurrentAttr = pItem;
+ mnCurrentAttr = pItem->GetFirstNamespaceIndex();
+ }
+ return next( rPrefix, rURL );
+}
+
+
+NamespaceMap::NamespaceMap( sal_uInt16* pWhichIds, SfxItemPool* pPool )
+: mpWhichIds( pWhichIds ), mpPool( pPool )
+{
+}
+
+// XNameAccess
+Any SAL_CALL NamespaceMap::getByName( const OUString& aName )
+{
+ NamespaceIteratorImpl aIter( mpWhichIds, mpPool );
+
+ OUString aPrefix;
+ OUString aURL;
+
+ bool bFound;
+
+ do
+ {
+ bFound = aIter.next( aPrefix, aURL );
+ }
+ while( bFound && (aPrefix != aName ) );
+
+ if( !bFound )
+ throw NoSuchElementException();
+
+ return Any( aURL );
+}
+
+Sequence< OUString > SAL_CALL NamespaceMap::getElementNames()
+{
+ NamespaceIteratorImpl aIter( mpWhichIds, mpPool );
+
+ OUString aPrefix;
+ OUString aURL;
+
+ std::set< OUString > aPrefixSet;
+
+ while( aIter.next( aPrefix, aURL ) )
+ aPrefixSet.insert( aPrefix );
+
+ return comphelper::containerToSequence(aPrefixSet);
+}
+
+sal_Bool SAL_CALL NamespaceMap::hasByName( const OUString& aName )
+{
+ NamespaceIteratorImpl aIter( mpWhichIds, mpPool );
+
+ OUString aPrefix;
+ OUString aURL;
+
+ bool bFound;
+
+ do
+ {
+ bFound = aIter.next( aPrefix, aURL );
+ }
+ while( bFound && (aPrefix != aName ) );
+
+ return bFound;
+}
+
+// XElementAccess
+Type SAL_CALL NamespaceMap::getElementType()
+{
+ return ::cppu::UnoType<OUString>::get();
+}
+
+sal_Bool SAL_CALL NamespaceMap::hasElements()
+{
+ NamespaceIteratorImpl aIter( mpWhichIds, mpPool );
+
+ OUString aPrefix;
+ OUString aURL;
+
+ return aIter.next( aPrefix, aURL );
+}
+
+// XServiceInfo
+OUString SAL_CALL NamespaceMap::getImplementationName( )
+{
+ return NamespaceMap_getImplementationName();
+}
+
+sal_Bool SAL_CALL NamespaceMap::supportsService( const OUString& serviceName )
+{
+ return cppu::supportsService( this, serviceName );
+}
+
+Sequence< OUString > SAL_CALL NamespaceMap::getSupportedServiceNames( )
+{
+ return NamespaceMap_getSupportedServiceNames();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/XPropertyTable.cxx b/svx/source/unodraw/XPropertyTable.cxx
new file mode 100644
index 000000000..56bb13523
--- /dev/null
+++ b/svx/source/unodraw/XPropertyTable.cxx
@@ -0,0 +1,663 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <memory>
+#include <XPropertyTable.hxx>
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/drawing/LineDash.hpp>
+#include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/drawing/Hatch.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <o3tl/any.hxx>
+#include <vcl/svapp.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <svx/xdef.hxx>
+
+#include <svx/unoapi.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+using namespace com::sun::star;
+using namespace ::cppu;
+
+namespace {
+
+class SvxUnoXPropertyTable : public WeakImplHelper< container::XNameContainer, lang::XServiceInfo >
+{
+private:
+ XPropertyList& mrList;
+ sal_Int16 mnWhich;
+
+ tools::Long getCount() const { return mrList.Count(); }
+ const XPropertyEntry* get(tools::Long index) const;
+public:
+ SvxUnoXPropertyTable( sal_Int16 nWhich, XPropertyList& rList ) noexcept;
+
+ /// @throws uno::RuntimeException
+ virtual uno::Any getAny( const XPropertyEntry* pEntry ) const = 0;
+ /// @throws uno::RuntimeException
+ /// @throws lang::IllegalArgumentException
+ virtual std::unique_ptr<XPropertyEntry> createEntry(const OUString& rName, const uno::Any& rAny) const = 0;
+
+ // XServiceInfo
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& Name ) override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override;
+
+ // XNameAccess
+ virtual uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+};
+
+}
+
+SvxUnoXPropertyTable::SvxUnoXPropertyTable( sal_Int16 nWhich, XPropertyList& rList ) noexcept
+: mrList( rList ), mnWhich( nWhich )
+{
+}
+
+const XPropertyEntry* SvxUnoXPropertyTable::get(tools::Long index) const
+{
+ return mrList.Get(index);
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL SvxUnoXPropertyTable::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XNameContainer
+void SAL_CALL SvxUnoXPropertyTable::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+
+ if( hasByName( aName ) )
+ throw container::ElementExistException();
+
+ OUString aInternalName = SvxUnogetInternalNameForItem(mnWhich, aName);
+
+ std::unique_ptr<XPropertyEntry> pNewEntry(createEntry(aInternalName, aElement));
+ if (!pNewEntry)
+ throw lang::IllegalArgumentException();
+
+ mrList.Insert(std::move(pNewEntry));
+}
+
+void SAL_CALL SvxUnoXPropertyTable::removeByName( const OUString& Name )
+{
+ SolarMutexGuard aGuard;
+
+ OUString aInternalName = SvxUnogetInternalNameForItem(mnWhich, Name);
+
+ const tools::Long nCount = getCount();
+ tools::Long i;
+ for( i = 0; i < nCount; i++ )
+ {
+ const XPropertyEntry* pEntry = get(i);
+ if (pEntry && aInternalName == pEntry->GetName())
+ {
+ mrList.Remove(i);
+ return;
+ }
+ }
+
+ throw container::NoSuchElementException();
+}
+
+// XNameReplace
+void SAL_CALL SvxUnoXPropertyTable::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+
+ OUString aInternalName = SvxUnogetInternalNameForItem(mnWhich, aName);
+
+ const tools::Long nCount = getCount();
+ tools::Long i;
+ for( i = 0; i < nCount; i++ )
+ {
+ const XPropertyEntry* pEntry = get(i);
+ if (pEntry && aInternalName == pEntry->GetName())
+ {
+ std::unique_ptr<XPropertyEntry> pNewEntry(createEntry(aInternalName, aElement));
+ if (!pNewEntry)
+ throw lang::IllegalArgumentException();
+
+ mrList.Replace(std::move(pNewEntry), i);
+ return;
+ }
+ }
+
+ throw container::NoSuchElementException();
+}
+
+// XNameAccess
+uno::Any SAL_CALL SvxUnoXPropertyTable::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ OUString aInternalName = SvxUnogetInternalNameForItem(mnWhich, aName);
+
+ const tools::Long nCount = getCount();
+ tools::Long i;
+ for( i = 0; i < nCount; i++ )
+ {
+ const XPropertyEntry* pEntry = get(i);
+
+ if (pEntry && aInternalName == pEntry->GetName())
+ return getAny( pEntry );
+ }
+
+ throw container::NoSuchElementException();
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoXPropertyTable::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ const tools::Long nCount = getCount();
+ uno::Sequence< OUString > aNames( nCount );
+ OUString* pNames = aNames.getArray();
+ tools::Long i;
+ for( i = 0; i < nCount; i++ )
+ {
+ const XPropertyEntry* pEntry = get(i);
+
+ if (pEntry)
+ *pNames++ = SvxUnogetApiNameForItem(mnWhich, pEntry->GetName());
+ }
+
+ return aNames;
+}
+
+sal_Bool SAL_CALL SvxUnoXPropertyTable::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ OUString aInternalName = SvxUnogetInternalNameForItem(mnWhich, aName);
+
+ const tools::Long nCount = mrList.Count();
+ tools::Long i;
+ for( i = 0; i < nCount; i++ )
+ {
+ const XPropertyEntry* pEntry = get(i);
+ if (pEntry && aInternalName == pEntry->GetName())
+ return true;
+ }
+
+ return false;
+}
+
+// XElementAccess
+sal_Bool SAL_CALL SvxUnoXPropertyTable::hasElements( )
+{
+ SolarMutexGuard aGuard;
+
+ return getCount() != 0;
+}
+
+namespace {
+
+class SvxUnoXColorTable : public SvxUnoXPropertyTable
+{
+public:
+ explicit SvxUnoXColorTable( XPropertyList& rList ) noexcept : SvxUnoXPropertyTable( XATTR_LINECOLOR, rList ) {};
+
+ // SvxUnoXPropertyTable
+ virtual uno::Any getAny( const XPropertyEntry* pEntry ) const noexcept override;
+ virtual std::unique_ptr<XPropertyEntry> createEntry(const OUString& rName, const uno::Any& rAny) const override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+}
+
+uno::Reference< container::XNameContainer > SvxUnoXColorTable_createInstance( XPropertyList& rList ) noexcept
+{
+ return new SvxUnoXColorTable( rList );
+}
+
+// SvxUnoXPropertyTable
+uno::Any SvxUnoXColorTable::getAny( const XPropertyEntry* pEntry ) const noexcept
+{
+ return uno::Any( static_cast<sal_Int32>(static_cast<const XColorEntry*>(pEntry)->GetColor()) );
+}
+
+std::unique_ptr<XPropertyEntry> SvxUnoXColorTable::createEntry(const OUString& rName, const uno::Any& rAny) const
+{
+ Color aColor;
+ if( !(rAny >>= aColor) )
+ return std::unique_ptr<XPropertyEntry>();
+
+ return std::make_unique<XColorEntry>(aColor, rName);
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoXColorTable::getElementType()
+{
+ return ::cppu::UnoType<sal_Int32>::get();
+}
+
+// XServiceInfo
+OUString SAL_CALL SvxUnoXColorTable::getImplementationName( )
+{
+ return "SvxUnoXColorTable";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoXColorTable::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.ColorTable" };
+}
+
+namespace {
+
+class SvxUnoXLineEndTable : public SvxUnoXPropertyTable
+{
+public:
+ explicit SvxUnoXLineEndTable( XPropertyList& rTable ) noexcept : SvxUnoXPropertyTable( XATTR_LINEEND, rTable ) {};
+
+ // SvxUnoXPropertyTable
+ virtual uno::Any getAny( const XPropertyEntry* pEntry ) const noexcept override;
+ virtual std::unique_ptr<XPropertyEntry> createEntry(const OUString& rName, const uno::Any& rAny) const override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+}
+
+uno::Reference< container::XNameContainer > SvxUnoXLineEndTable_createInstance( XPropertyList& rTable ) noexcept
+{
+ return new SvxUnoXLineEndTable( rTable );
+}
+
+// SvxUnoXPropertyTable
+uno::Any SvxUnoXLineEndTable::getAny( const XPropertyEntry* pEntry ) const noexcept
+{
+ drawing::PolyPolygonBezierCoords aBezier;
+ basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( static_cast<const XLineEndEntry*>(pEntry)->GetLineEnd(),
+ aBezier );
+ return uno::Any(aBezier);
+}
+
+std::unique_ptr<XPropertyEntry> SvxUnoXLineEndTable::createEntry(const OUString& rName, const uno::Any& rAny) const
+{
+ auto pCoords = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(rAny);
+ if( !pCoords )
+ return std::unique_ptr<XLineEndEntry>();
+
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ if( pCoords->Coordinates.getLength() > 0 )
+ aPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( *pCoords );
+
+ // #86265# make sure polygon is closed
+ aPolyPolygon.setClosed(true);
+
+ return std::make_unique<XLineEndEntry>(aPolyPolygon, rName);
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoXLineEndTable::getElementType()
+{
+ return cppu::UnoType<drawing::PolyPolygonBezierCoords>::get();
+}
+
+// XServiceInfo
+OUString SAL_CALL SvxUnoXLineEndTable::getImplementationName( )
+{
+ return "SvxUnoXLineEndTable";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoXLineEndTable::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.LineEndTable" };
+}
+
+namespace {
+
+class SvxUnoXDashTable : public SvxUnoXPropertyTable
+{
+public:
+ explicit SvxUnoXDashTable( XPropertyList& rTable ) noexcept : SvxUnoXPropertyTable( XATTR_LINEDASH, rTable ) {};
+
+ // SvxUnoXPropertyTable
+ virtual uno::Any getAny( const XPropertyEntry* pEntry ) const noexcept override;
+ virtual std::unique_ptr<XPropertyEntry> createEntry(const OUString& rName, const uno::Any& rAny) const override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+}
+
+uno::Reference< container::XNameContainer > SvxUnoXDashTable_createInstance( XPropertyList& rTable ) noexcept
+{
+ return new SvxUnoXDashTable( rTable );
+}
+
+// SvxUnoXPropertyTable
+uno::Any SvxUnoXDashTable::getAny( const XPropertyEntry* pEntry ) const noexcept
+{
+ const XDash& rXD = static_cast<const XDashEntry*>(pEntry)->GetDash();
+
+ drawing::LineDash aLineDash;
+
+ aLineDash.Style = static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(rXD.GetDashStyle()));
+ aLineDash.Dots = rXD.GetDots();
+ aLineDash.DotLen = rXD.GetDotLen();
+ aLineDash.Dashes = rXD.GetDashes();
+ aLineDash.DashLen = rXD.GetDashLen();
+ aLineDash.Distance = rXD.GetDistance();
+
+ return uno::Any(aLineDash);
+}
+
+std::unique_ptr<XPropertyEntry> SvxUnoXDashTable::createEntry(const OUString& rName, const uno::Any& rAny) const
+{
+ drawing::LineDash aLineDash;
+ if(!(rAny >>= aLineDash))
+ return std::unique_ptr<XDashEntry>();
+
+ XDash aXDash;
+
+ aXDash.SetDashStyle(static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(aLineDash.Style)));
+ aXDash.SetDots(aLineDash.Dots);
+ aXDash.SetDotLen(aLineDash.DotLen);
+ aXDash.SetDashes(aLineDash.Dashes);
+ aXDash.SetDashLen(aLineDash.DashLen);
+ aXDash.SetDistance(aLineDash.Distance);
+
+ return std::make_unique<XDashEntry>(aXDash, rName);
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoXDashTable::getElementType()
+{
+ return cppu::UnoType<drawing::LineDash>::get();
+}
+
+// XServiceInfo
+OUString SAL_CALL SvxUnoXDashTable::getImplementationName( )
+{
+ return "SvxUnoXDashTable";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoXDashTable::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.DashTable" };
+}
+
+namespace {
+
+class SvxUnoXHatchTable : public SvxUnoXPropertyTable
+{
+public:
+ explicit SvxUnoXHatchTable( XPropertyList& rTable ) noexcept : SvxUnoXPropertyTable( XATTR_FILLHATCH, rTable ) {};
+
+ // SvxUnoXPropertyTable
+ virtual uno::Any getAny( const XPropertyEntry* pEntry ) const noexcept override;
+ virtual std::unique_ptr<XPropertyEntry> createEntry(const OUString& rName, const uno::Any& rAny) const override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+}
+
+uno::Reference< container::XNameContainer > SvxUnoXHatchTable_createInstance( XPropertyList& rTable ) noexcept
+{
+ return new SvxUnoXHatchTable( rTable );
+}
+
+// SvxUnoXPropertyTable
+uno::Any SvxUnoXHatchTable::getAny( const XPropertyEntry* pEntry ) const noexcept
+{
+ const XHatch& aHatch = static_cast<const XHatchEntry*>(pEntry)->GetHatch();
+
+ drawing::Hatch aUnoHatch;
+
+ aUnoHatch.Style = aHatch.GetHatchStyle();
+ aUnoHatch.Color = sal_Int32(aHatch.GetColor());
+ aUnoHatch.Distance = aHatch.GetDistance();
+ aUnoHatch.Angle = aHatch.GetAngle().get();
+
+ return uno::Any(aUnoHatch);
+}
+
+std::unique_ptr<XPropertyEntry> SvxUnoXHatchTable::createEntry(const OUString& rName, const uno::Any& rAny) const
+{
+ drawing::Hatch aUnoHatch;
+ if(!(rAny >>= aUnoHatch))
+ return std::unique_ptr<XHatchEntry>();
+
+ XHatch aXHatch;
+ aXHatch.SetHatchStyle( aUnoHatch.Style );
+ aXHatch.SetColor( Color(ColorTransparency, aUnoHatch.Color) );
+ aXHatch.SetDistance( aUnoHatch.Distance );
+ aXHatch.SetAngle( Degree10(aUnoHatch.Angle) );
+
+ return std::make_unique<XHatchEntry>(aXHatch, rName);
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoXHatchTable::getElementType()
+{
+ return cppu::UnoType<drawing::Hatch>::get();
+}
+
+// XServiceInfo
+OUString SAL_CALL SvxUnoXHatchTable::getImplementationName( )
+{
+ return "SvxUnoXHatchTable";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoXHatchTable::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.HatchTable" };
+}
+
+namespace {
+
+class SvxUnoXGradientTable : public SvxUnoXPropertyTable
+{
+public:
+ explicit SvxUnoXGradientTable( XPropertyList& rTable ) noexcept : SvxUnoXPropertyTable( XATTR_FILLGRADIENT, rTable ) {};
+
+ // SvxUnoXPropertyTable
+ virtual uno::Any getAny( const XPropertyEntry* pEntry ) const noexcept override;
+ virtual std::unique_ptr<XPropertyEntry> createEntry(const OUString& rName, const uno::Any& rAny) const override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+}
+
+uno::Reference< container::XNameContainer > SvxUnoXGradientTable_createInstance( XPropertyList& rTable ) noexcept
+{
+ return new SvxUnoXGradientTable( rTable );
+}
+
+// SvxUnoXPropertyTable
+uno::Any SvxUnoXGradientTable::getAny( const XPropertyEntry* pEntry ) const noexcept
+{
+ const XGradient& aXGradient = static_cast<const XGradientEntry*>(pEntry)->GetGradient();
+ awt::Gradient aGradient;
+
+ aGradient.Style = aXGradient.GetGradientStyle();
+ aGradient.StartColor = static_cast<sal_Int32>(aXGradient.GetStartColor());
+ aGradient.EndColor = static_cast<sal_Int32>(aXGradient.GetEndColor());
+ aGradient.Angle = static_cast<short>(aXGradient.GetAngle());
+ aGradient.Border = aXGradient.GetBorder();
+ aGradient.XOffset = aXGradient.GetXOffset();
+ aGradient.YOffset = aXGradient.GetYOffset();
+ aGradient.StartIntensity = aXGradient.GetStartIntens();
+ aGradient.EndIntensity = aXGradient.GetEndIntens();
+ aGradient.StepCount = aXGradient.GetSteps();
+
+ return uno::Any(aGradient);
+}
+
+std::unique_ptr<XPropertyEntry> SvxUnoXGradientTable::createEntry(const OUString& rName, const uno::Any& rAny) const
+{
+ awt::Gradient aGradient;
+ if(!(rAny >>= aGradient))
+ return std::unique_ptr<XPropertyEntry>();
+
+ XGradient aXGradient;
+
+ aXGradient.SetGradientStyle( aGradient.Style );
+ aXGradient.SetStartColor( Color(ColorTransparency, aGradient.StartColor) );
+ aXGradient.SetEndColor( Color(ColorTransparency, aGradient.EndColor) );
+ aXGradient.SetAngle( Degree10(aGradient.Angle) );
+ aXGradient.SetBorder( aGradient.Border );
+ aXGradient.SetXOffset( aGradient.XOffset );
+ aXGradient.SetYOffset( aGradient.YOffset );
+ aXGradient.SetStartIntens( aGradient.StartIntensity );
+ aXGradient.SetEndIntens( aGradient.EndIntensity );
+ aXGradient.SetSteps( aGradient.StepCount );
+
+ return std::make_unique<XGradientEntry>(aXGradient, rName);
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoXGradientTable::getElementType()
+{
+ return cppu::UnoType<awt::Gradient>::get();
+}
+
+// XServiceInfo
+OUString SAL_CALL SvxUnoXGradientTable::getImplementationName( )
+{
+ return "SvxUnoXGradientTable";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoXGradientTable::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.GradientTable" };
+}
+
+namespace {
+
+class SvxUnoXBitmapTable : public SvxUnoXPropertyTable
+{
+public:
+ explicit SvxUnoXBitmapTable( XPropertyList& rTable ) noexcept : SvxUnoXPropertyTable( XATTR_FILLBITMAP, rTable ) {};
+
+ // SvxUnoXPropertyTable
+ virtual uno::Any getAny( const XPropertyEntry* pEntry ) const override;
+ virtual std::unique_ptr<XPropertyEntry> createEntry(const OUString& rName, const uno::Any& rAny) const override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+}
+
+uno::Reference< container::XNameContainer > SvxUnoXBitmapTable_createInstance( XPropertyList& rTable ) noexcept
+{
+ return new SvxUnoXBitmapTable( rTable );
+}
+
+// SvxUnoXPropertyTable
+uno::Any SvxUnoXBitmapTable::getAny( const XPropertyEntry* pEntry ) const
+{
+ auto xBitmapEntry = static_cast<const XBitmapEntry*>(pEntry);
+ css::uno::Reference<css::awt::XBitmap> xBitmap(xBitmapEntry->GetGraphicObject().GetGraphic().GetXGraphic(), uno::UNO_QUERY);
+ return uno::Any(xBitmap);
+}
+
+std::unique_ptr<XPropertyEntry> SvxUnoXBitmapTable::createEntry(const OUString& rName, const uno::Any& rAny) const
+{
+ if (!rAny.has<uno::Reference<awt::XBitmap>>())
+ return std::unique_ptr<XPropertyEntry>();
+
+ auto xBitmap = rAny.get<uno::Reference<awt::XBitmap>>();
+ if (!xBitmap.is())
+ return nullptr;
+
+ uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
+ if (!xGraphic.is())
+ return nullptr;
+
+ Graphic aGraphic(xGraphic);
+ if (aGraphic.IsNone())
+ return nullptr;
+
+ GraphicObject aGraphicObject(aGraphic);
+ return std::make_unique<XBitmapEntry>(aGraphicObject, rName);
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoXBitmapTable::getElementType()
+{
+ return ::cppu::UnoType<awt::XBitmap>::get();
+}
+
+// XServiceInfo
+OUString SAL_CALL SvxUnoXBitmapTable::getImplementationName( )
+{
+ return "SvxUnoXBitmapTable";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoXBitmapTable::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.BitmapTable" };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/gluepts.cxx b/svx/source/unodraw/gluepts.cxx
new file mode 100644
index 000000000..584effb73
--- /dev/null
+++ b/svx/source/unodraw/gluepts.cxx
@@ -0,0 +1,513 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/container/XIdentifierContainer.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/drawing/GluePoint2.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <tools/weakbase.hxx>
+
+#include <svx/svdobj.hxx>
+#include <svx/svdglue.hxx>
+
+#include "gluepts.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::cppu;
+
+const sal_uInt16 NON_USER_DEFINED_GLUE_POINTS = 4;
+
+namespace {
+
+class SvxUnoGluePointAccess : public WeakImplHelper< container::XIndexContainer, container::XIdentifierContainer >
+{
+private:
+ tools::WeakReference<SdrObject> mpObject;
+
+public:
+ explicit SvxUnoGluePointAccess( SdrObject* pObject ) noexcept;
+
+ // XIdentifierContainer
+ virtual sal_Int32 SAL_CALL insert( const uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByIdentifier( sal_Int32 Identifier ) override;
+
+ // XIdentifierReplace
+ virtual void SAL_CALL replaceByIdentifer( sal_Int32 Identifier, const uno::Any& aElement ) override;
+
+ // XIdentifierReplace
+ virtual uno::Any SAL_CALL getByIdentifier( sal_Int32 Identifier ) override;
+ virtual uno::Sequence< sal_Int32 > SAL_CALL getIdentifiers( ) override;
+
+ /* deprecated */
+ // XIndexContainer
+ virtual void SAL_CALL insertByIndex( sal_Int32 Index, const uno::Any& Element ) override;
+ virtual void SAL_CALL removeByIndex( sal_Int32 Index ) override;
+
+ /* deprecated */
+ // XIndexReplace
+ virtual void SAL_CALL replaceByIndex( sal_Int32 Index, const uno::Any& Element ) override;
+
+ /* deprecated */
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+};
+
+}
+
+static void convert( const SdrGluePoint& rSdrGlue, drawing::GluePoint2& rUnoGlue ) noexcept
+{
+ rUnoGlue.Position.X = rSdrGlue.GetPos().X();
+ rUnoGlue.Position.Y = rSdrGlue.GetPos().Y();
+ rUnoGlue.IsRelative = rSdrGlue.IsPercent();
+
+ SdrAlign eAlign = rSdrGlue.GetAlign();
+ if (eAlign == (SdrAlign::VERT_TOP|SdrAlign::HORZ_LEFT))
+ rUnoGlue.PositionAlignment = drawing::Alignment_TOP_LEFT;
+ else if (eAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP))
+ rUnoGlue.PositionAlignment = drawing::Alignment_TOP;
+ else if (eAlign == (SdrAlign::VERT_TOP|SdrAlign::HORZ_RIGHT))
+ rUnoGlue.PositionAlignment = drawing::Alignment_TOP_RIGHT;
+ else if (eAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
+ rUnoGlue.PositionAlignment = drawing::Alignment_CENTER;
+ else if (eAlign == (SdrAlign::HORZ_RIGHT|SdrAlign::VERT_CENTER))
+ rUnoGlue.PositionAlignment = drawing::Alignment_RIGHT;
+ else if (eAlign == (SdrAlign::HORZ_LEFT|SdrAlign::VERT_BOTTOM))
+ rUnoGlue.PositionAlignment = drawing::Alignment_BOTTOM_LEFT;
+ else if (eAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM))
+ rUnoGlue.PositionAlignment = drawing::Alignment_BOTTOM;
+ else if (eAlign == (SdrAlign::HORZ_RIGHT|SdrAlign::VERT_BOTTOM))
+ rUnoGlue.PositionAlignment = drawing::Alignment_BOTTOM_RIGHT;
+ else {
+ rUnoGlue.PositionAlignment = drawing::Alignment_LEFT;
+ }
+
+ switch( rSdrGlue.GetEscDir() )
+ {
+ case SdrEscapeDirection::LEFT:
+ rUnoGlue.Escape = drawing::EscapeDirection_LEFT;
+ break;
+ case SdrEscapeDirection::RIGHT:
+ rUnoGlue.Escape = drawing::EscapeDirection_RIGHT;
+ break;
+ case SdrEscapeDirection::TOP:
+ rUnoGlue.Escape = drawing::EscapeDirection_UP;
+ break;
+ case SdrEscapeDirection::BOTTOM:
+ rUnoGlue.Escape = drawing::EscapeDirection_DOWN;
+ break;
+ case SdrEscapeDirection::HORZ:
+ rUnoGlue.Escape = drawing::EscapeDirection_HORIZONTAL;
+ break;
+ case SdrEscapeDirection::VERT:
+ rUnoGlue.Escape = drawing::EscapeDirection_VERTICAL;
+ break;
+// case SdrEscapeDirection::SMART:
+ default:
+ rUnoGlue.Escape = drawing::EscapeDirection_SMART;
+ break;
+ }
+}
+
+static void convert( const drawing::GluePoint2& rUnoGlue, SdrGluePoint& rSdrGlue ) noexcept
+{
+ rSdrGlue.SetPos( Point( rUnoGlue.Position.X, rUnoGlue.Position.Y ) );
+ rSdrGlue.SetPercent( rUnoGlue.IsRelative );
+
+ switch( rUnoGlue.PositionAlignment )
+ {
+ case drawing::Alignment_TOP_LEFT:
+ rSdrGlue.SetAlign( SdrAlign::VERT_TOP|SdrAlign::HORZ_LEFT );
+ break;
+ case drawing::Alignment_TOP:
+ rSdrGlue.SetAlign( SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP );
+ break;
+ case drawing::Alignment_TOP_RIGHT:
+ rSdrGlue.SetAlign( SdrAlign::VERT_TOP|SdrAlign::HORZ_RIGHT );
+ break;
+ case drawing::Alignment_CENTER:
+ rSdrGlue.SetAlign( SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER );
+ break;
+ case drawing::Alignment_RIGHT:
+ rSdrGlue.SetAlign( SdrAlign::HORZ_RIGHT|SdrAlign::VERT_CENTER );
+ break;
+ case drawing::Alignment_BOTTOM_LEFT:
+ rSdrGlue.SetAlign( SdrAlign::HORZ_LEFT|SdrAlign::VERT_BOTTOM );
+ break;
+ case drawing::Alignment_BOTTOM:
+ rSdrGlue.SetAlign( SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM );
+ break;
+ case drawing::Alignment_BOTTOM_RIGHT:
+ rSdrGlue.SetAlign( SdrAlign::HORZ_RIGHT|SdrAlign::VERT_BOTTOM );
+ break;
+// case SdrAlign::HORZ_LEFT:
+ default:
+ rSdrGlue.SetAlign( SdrAlign::HORZ_LEFT );
+ break;
+ }
+ switch( rUnoGlue.Escape )
+ {
+ case drawing::EscapeDirection_LEFT:
+ rSdrGlue.SetEscDir(SdrEscapeDirection::LEFT);
+ break;
+ case drawing::EscapeDirection_RIGHT:
+ rSdrGlue.SetEscDir(SdrEscapeDirection::RIGHT);
+ break;
+ case drawing::EscapeDirection_UP:
+ rSdrGlue.SetEscDir(SdrEscapeDirection::TOP);
+ break;
+ case drawing::EscapeDirection_DOWN:
+ rSdrGlue.SetEscDir(SdrEscapeDirection::BOTTOM);
+ break;
+ case drawing::EscapeDirection_HORIZONTAL:
+ rSdrGlue.SetEscDir(SdrEscapeDirection::HORZ);
+ break;
+ case drawing::EscapeDirection_VERTICAL:
+ rSdrGlue.SetEscDir(SdrEscapeDirection::VERT);
+ break;
+// case drawing::EscapeDirection_SMART:
+ default:
+ rSdrGlue.SetEscDir(SdrEscapeDirection::SMART);
+ break;
+ }
+}
+
+SvxUnoGluePointAccess::SvxUnoGluePointAccess( SdrObject* pObject ) noexcept
+: mpObject( pObject )
+{
+}
+
+// XIdentifierContainer
+sal_Int32 SAL_CALL SvxUnoGluePointAccess::insert( const uno::Any& aElement )
+{
+ if( mpObject.is() )
+ {
+ SdrGluePointList* pList = mpObject->ForceGluePointList();
+ if( pList )
+ {
+ // second, insert the new gluepoint
+ drawing::GluePoint2 aUnoGlue;
+
+ if( aElement >>= aUnoGlue )
+ {
+ SdrGluePoint aSdrGlue;
+ convert( aUnoGlue, aSdrGlue );
+ sal_uInt16 nId = pList->Insert( aSdrGlue );
+
+ // only repaint, no objectchange
+ mpObject->ActionChanged();
+ // mpObject->BroadcastObjectChange();
+
+ return static_cast<sal_Int32>((*pList)[nId].GetId() + NON_USER_DEFINED_GLUE_POINTS) - 1;
+ }
+
+ throw lang::IllegalArgumentException();
+ }
+ }
+
+ return -1;
+}
+
+void SAL_CALL SvxUnoGluePointAccess::removeByIdentifier( sal_Int32 Identifier )
+{
+ if( mpObject.is() && ( Identifier >= NON_USER_DEFINED_GLUE_POINTS ))
+ {
+ const sal_uInt16 nId = static_cast<sal_uInt16>(Identifier - NON_USER_DEFINED_GLUE_POINTS) + 1;
+
+ SdrGluePointList* pList = const_cast<SdrGluePointList*>(mpObject->GetGluePointList());
+ const sal_uInt16 nCount = pList ? pList->GetCount() : 0;
+ sal_uInt16 i;
+
+ for( i = 0; i < nCount; i++ )
+ {
+ if( (*pList)[i].GetId() == nId )
+ {
+ pList->Delete( i );
+
+ // only repaint, no objectchange
+ mpObject->ActionChanged();
+ // mpObject->BroadcastObjectChange();
+
+ return;
+ }
+ }
+ }
+
+ throw container::NoSuchElementException();
+}
+
+// XIdentifierReplace
+void SAL_CALL SvxUnoGluePointAccess::replaceByIdentifer( sal_Int32 Identifier, const uno::Any& aElement )
+{
+ if( !mpObject.is() )
+ return;
+
+ struct drawing::GluePoint2 aGluePoint;
+ if( (Identifier < NON_USER_DEFINED_GLUE_POINTS) || !(aElement >>= aGluePoint))
+ throw lang::IllegalArgumentException();
+
+ const sal_uInt16 nId = static_cast<sal_uInt16>( Identifier - NON_USER_DEFINED_GLUE_POINTS ) + 1;
+
+ SdrGluePointList* pList = const_cast< SdrGluePointList* >( mpObject->GetGluePointList() );
+ const sal_uInt16 nCount = pList ? pList->GetCount() : 0;
+ sal_uInt16 i;
+ for( i = 0; i < nCount; i++ )
+ {
+ if( (*pList)[i].GetId() == nId )
+ {
+ // change the gluepoint
+ SdrGluePoint& rTempPoint = (*pList)[i];
+ convert( aGluePoint, rTempPoint );
+
+ // only repaint, no objectchange
+ mpObject->ActionChanged();
+ // mpObject->BroadcastObjectChange();
+
+ return;
+ }
+ }
+
+ throw container::NoSuchElementException();
+}
+
+// XIdentifierAccess
+uno::Any SAL_CALL SvxUnoGluePointAccess::getByIdentifier( sal_Int32 Identifier )
+{
+ if( mpObject.is() )
+ {
+ struct drawing::GluePoint2 aGluePoint;
+
+ if( Identifier < NON_USER_DEFINED_GLUE_POINTS ) // default gluepoint?
+ {
+ SdrGluePoint aTempPoint = mpObject->GetVertexGluePoint( static_cast<sal_uInt16>(Identifier) );
+ aGluePoint.IsUserDefined = false;
+ convert( aTempPoint, aGluePoint );
+ return uno::Any( aGluePoint );
+ }
+ else
+ {
+ const sal_uInt16 nId = static_cast<sal_uInt16>( Identifier - NON_USER_DEFINED_GLUE_POINTS ) + 1;
+
+ const SdrGluePointList* pList = mpObject->GetGluePointList();
+ const sal_uInt16 nCount = pList ? pList->GetCount() : 0;
+ for( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ const SdrGluePoint& rTempPoint = (*pList)[i];
+ if( rTempPoint.GetId() == nId )
+ {
+ // #i38892#
+ if(rTempPoint.IsUserDefined())
+ {
+ aGluePoint.IsUserDefined = true;
+ }
+
+ convert( rTempPoint, aGluePoint );
+ return uno::Any( aGluePoint );
+ }
+ }
+ }
+ }
+
+ throw container::NoSuchElementException();
+}
+
+uno::Sequence< sal_Int32 > SAL_CALL SvxUnoGluePointAccess::getIdentifiers()
+{
+ if( mpObject.is() )
+ {
+ const SdrGluePointList* pList = mpObject->GetGluePointList();
+ const sal_uInt16 nCount = pList ? pList->GetCount() : 0;
+
+ sal_uInt16 i;
+
+ uno::Sequence< sal_Int32 > aIdSequence( nCount + NON_USER_DEFINED_GLUE_POINTS );
+ sal_Int32 *pIdentifier = aIdSequence.getArray();
+
+ for( i = 0; i < NON_USER_DEFINED_GLUE_POINTS; i++ )
+ *pIdentifier++ = static_cast<sal_Int32>(i);
+
+ for( i = 0; i < nCount; i++ )
+ *pIdentifier++ = static_cast<sal_Int32>( (*pList)[i].GetId() + NON_USER_DEFINED_GLUE_POINTS ) - 1;
+
+ return aIdSequence;
+ }
+ else
+ {
+ uno::Sequence< sal_Int32 > aEmpty;
+ return aEmpty;
+ }
+}
+
+/* deprecated */
+
+// XIndexContainer
+void SAL_CALL SvxUnoGluePointAccess::insertByIndex( sal_Int32, const uno::Any& Element )
+{
+ if( mpObject.is() )
+ {
+ SdrGluePointList* pList = mpObject->ForceGluePointList();
+ if( pList )
+ {
+ drawing::GluePoint2 aUnoGlue;
+
+ if( Element >>= aUnoGlue )
+ {
+ SdrGluePoint aSdrGlue;
+ convert( aUnoGlue, aSdrGlue );
+ pList->Insert( aSdrGlue );
+
+ // only repaint, no objectchange
+ mpObject->ActionChanged();
+ // mpObject->BroadcastObjectChange();
+
+ return;
+ }
+
+ throw lang::IllegalArgumentException();
+ }
+ }
+
+ throw lang::IndexOutOfBoundsException();
+}
+
+void SAL_CALL SvxUnoGluePointAccess::removeByIndex( sal_Int32 Index )
+{
+ if( mpObject.is() )
+ {
+ SdrGluePointList* pList = mpObject->ForceGluePointList();
+ if( pList )
+ {
+ Index -= 4;
+ if( Index >= 0 && Index < pList->GetCount() )
+ {
+ pList->Delete( static_cast<sal_uInt16>(Index) );
+
+ // only repaint, no objectchange
+ mpObject->ActionChanged();
+ // mpObject->BroadcastObjectChange();
+
+ return;
+ }
+ }
+ }
+
+ throw lang::IndexOutOfBoundsException();
+}
+
+// XIndexReplace
+void SAL_CALL SvxUnoGluePointAccess::replaceByIndex( sal_Int32 Index, const uno::Any& Element )
+{
+ drawing::GluePoint2 aUnoGlue;
+ if(!(Element >>= aUnoGlue))
+ throw lang::IllegalArgumentException();
+
+ Index -= 4;
+ if( mpObject.is() && Index >= 0 )
+ {
+ SdrGluePointList* pList = const_cast< SdrGluePointList* >( mpObject->GetGluePointList() );
+ if( pList && Index < pList->GetCount() )
+ {
+ SdrGluePoint& rGlue = (*pList)[static_cast<sal_uInt16>(Index)];
+ convert( aUnoGlue, rGlue );
+
+ // only repaint, no objectchange
+ mpObject->ActionChanged();
+ // mpObject->BroadcastObjectChange();
+ }
+ }
+
+ throw lang::IndexOutOfBoundsException();
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SvxUnoGluePointAccess::getCount()
+{
+ sal_Int32 nCount = 0;
+ if( mpObject.is() )
+ {
+ // each node has a default of 4 gluepoints
+ // and any number of user defined gluepoints
+ nCount += 4;
+
+ const SdrGluePointList* pList = mpObject->GetGluePointList();
+ if( pList )
+ nCount += pList->GetCount();
+ }
+
+ return nCount;
+}
+
+uno::Any SAL_CALL SvxUnoGluePointAccess::getByIndex( sal_Int32 Index )
+{
+ if( Index >= 0 && mpObject.is() )
+ {
+ struct drawing::GluePoint2 aGluePoint;
+
+ if( Index < 4 ) // default gluepoint?
+ {
+ SdrGluePoint aTempPoint = mpObject->GetVertexGluePoint( static_cast<sal_uInt16>(Index) );
+ aGluePoint.IsUserDefined = false;
+ convert( aTempPoint, aGluePoint );
+ return uno::Any(aGluePoint);
+ }
+ else
+ {
+ Index -= 4;
+ const SdrGluePointList* pList = mpObject->GetGluePointList();
+ if( pList && Index < pList->GetCount() )
+ {
+ const SdrGluePoint& rTempPoint = (*pList)[static_cast<sal_uInt16>(Index)];
+ aGluePoint.IsUserDefined = true;
+ convert( rTempPoint, aGluePoint );
+ return uno::Any(aGluePoint);
+ }
+ }
+ }
+
+ throw lang::IndexOutOfBoundsException();
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoGluePointAccess::getElementType()
+{
+ return cppu::UnoType<drawing::GluePoint2>::get();
+}
+
+sal_Bool SAL_CALL SvxUnoGluePointAccess::hasElements()
+{
+ return mpObject.is();
+}
+
+/**
+ * Create a SvxUnoGluePointAccess
+ */
+uno::Reference< uno::XInterface > SvxUnoGluePointAccess_createInstance( SdrObject* pObject )
+{
+ return *new SvxUnoGluePointAccess(pObject);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/gluepts.hxx b/svx/source/unodraw/gluepts.hxx
new file mode 100644
index 000000000..303f7213e
--- /dev/null
+++ b/svx/source/unodraw/gluepts.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_UNODRAW_GLUEPTS_HXX
+#define INCLUDED_SVX_SOURCE_UNODRAW_GLUEPTS_HXX
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace com::sun::star::uno
+{
+class XInterface;
+}
+class SdrObject;
+
+css::uno::Reference<css::uno::XInterface> SvxUnoGluePointAccess_createInstance(SdrObject* pObject);
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/recoveryui.cxx b/svx/source/unodraw/recoveryui.cxx
new file mode 100644
index 000000000..56550fd7f
--- /dev/null
+++ b/svx/source/unodraw/recoveryui.cxx
@@ -0,0 +1,331 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_folders.h>
+
+#include <docrecovery.hxx>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XSynchronousDispatch.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <osl/file.hxx>
+#include <rtl/bootstrap.hxx>
+#include <rtl/ref.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <vcl/svapp.hxx>
+
+namespace svxdr = svx::DocRecovery;
+using namespace ::osl;
+
+namespace {
+
+class RecoveryUI : public ::cppu::WeakImplHelper< css::lang::XServiceInfo ,
+ css::frame::XSynchronousDispatch > // => XDispatch!
+{
+
+ // const, types, etcpp.
+ private:
+
+ /** @short TODO */
+ enum EJob
+ {
+ E_JOB_UNKNOWN,
+ E_DO_EMERGENCY_SAVE,
+ E_DO_RECOVERY,
+ E_DO_BRINGTOFRONT,
+ };
+
+
+ // member
+ private:
+
+ /** @short TODO */
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ /** @short TODO */
+ weld::Window* m_pParentWindow;
+
+ /** @short TODO */
+ RecoveryUI::EJob m_eJob;
+
+ // Active dialog
+ weld::Dialog* m_pDialog;
+
+ // interface
+ public:
+
+
+ /** @short TODO */
+ explicit RecoveryUI(const css::uno::Reference< css::uno::XComponentContext >& xContext);
+
+ // css.lang.XServiceInfo
+
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(const OUString& sServiceName) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+
+ virtual css::uno::Any SAL_CALL dispatchWithReturnValue(const css::util::URL& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override;
+
+ void SetActiveDialog(weld::Dialog* pDialog)
+ {
+ m_pDialog = pDialog;
+ }
+
+ // helper
+ private:
+
+ EJob impl_classifyJob(const css::util::URL& aURL);
+
+ bool impl_doEmergencySave();
+
+ bool impl_doRecovery();
+
+ void impl_showAllRecoveredDocs();
+
+ bool impl_doBringToFront();
+};
+
+RecoveryUI::RecoveryUI(const css::uno::Reference< css::uno::XComponentContext >& xContext)
+ : m_xContext(xContext)
+ , m_pParentWindow(nullptr)
+ , m_eJob(RecoveryUI::E_JOB_UNKNOWN)
+ , m_pDialog(nullptr)
+{
+}
+
+OUString SAL_CALL RecoveryUI::getImplementationName()
+{
+ return "com.sun.star.comp.svx.RecoveryUI";
+}
+
+sal_Bool SAL_CALL RecoveryUI::supportsService(const OUString& sServiceName)
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL RecoveryUI::getSupportedServiceNames()
+{
+ return { "com.sun.star.dialog.RecoveryUI" };
+}
+
+css::uno::Any SAL_CALL RecoveryUI::dispatchWithReturnValue(const css::util::URL& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& )
+{
+ // Internally we use VCL ... every call into vcl based code must
+ // be guarded by locking the global solar mutex.
+ ::SolarMutexGuard aSolarLock;
+
+ css::uno::Any aRet;
+ RecoveryUI::EJob eJob = impl_classifyJob(aURL);
+ // TODO think about outside arguments
+
+ switch(eJob)
+ {
+ case RecoveryUI::E_DO_EMERGENCY_SAVE:
+ {
+ bool bRet = impl_doEmergencySave();
+ aRet <<= bRet;
+ break;
+ }
+
+ case RecoveryUI::E_DO_RECOVERY:
+ {
+ bool bRet = impl_doRecovery();
+ aRet <<= bRet;
+ break;
+ }
+
+ case RecoveryUI::E_DO_BRINGTOFRONT:
+ {
+ bool bRet = impl_doBringToFront();
+ aRet <<= bRet;
+ break;
+ }
+
+ default:
+ {
+ aRet <<= false;
+ break;
+ }
+ }
+
+ return aRet;
+}
+
+
+OUString GetCrashConfigDir()
+{
+
+#if defined(_WIN32)
+ OUString ustrValue = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/bootstrap.ini:UserInstallation}";
+#elif defined(MACOSX)
+ OUString ustrValue = "~";
+#else
+ OUString ustrValue = "$SYSUSERCONFIG";
+#endif
+ rtl::Bootstrap::expandMacros( ustrValue );
+
+#if defined(_WIN32)
+ ustrValue += "/user/crashdata";
+#endif
+ return ustrValue;
+}
+
+
+#if defined(_WIN32)
+#define LCKFILE "crashdat.lck"
+#else
+#define LCKFILE ".crash_report_unsent"
+#endif
+
+
+OUString GetUnsentURL()
+{
+ OUString aURL = GetCrashConfigDir() + "/" LCKFILE;
+ return aURL;
+}
+
+
+bool delete_pending_crash()
+{
+ OUString aUnsentURL = GetUnsentURL();
+ return ( FileBase::E_None == File::remove( aUnsentURL ) );
+}
+
+RecoveryUI::EJob RecoveryUI::impl_classifyJob(const css::util::URL& aURL)
+{
+ m_eJob = RecoveryUI::E_JOB_UNKNOWN;
+ if (aURL.Protocol == RECOVERY_CMDPART_PROTOCOL)
+ {
+ if (aURL.Path == RECOVERY_CMDPART_DO_EMERGENCY_SAVE)
+ m_eJob = RecoveryUI::E_DO_EMERGENCY_SAVE;
+ else if (aURL.Path == RECOVERY_CMDPART_DO_RECOVERY)
+ m_eJob = RecoveryUI::E_DO_RECOVERY;
+ else if (aURL.Path == RECOVERY_CMDPART_DO_BRINGTOFRONT)
+ m_eJob = RecoveryUI::E_DO_BRINGTOFRONT;
+ }
+
+ return m_eJob;
+}
+
+struct DialogReleaseGuard
+{
+ RecoveryUI& m_rRecoveryUI;
+
+ DialogReleaseGuard(RecoveryUI& rRecoveryUI, weld::Dialog* p)
+ : m_rRecoveryUI(rRecoveryUI)
+ {
+ m_rRecoveryUI.SetActiveDialog(p);
+ }
+ ~DialogReleaseGuard()
+ {
+ m_rRecoveryUI.SetActiveDialog(nullptr);
+ }
+};
+
+bool RecoveryUI::impl_doEmergencySave()
+{
+ // create core service, which implements the real "emergency save" algorithm.
+ rtl::Reference<svxdr::RecoveryCore> pCore = new svxdr::RecoveryCore(m_xContext, true);
+
+ // create dialog for this operation and bind it to the used core service
+ std::unique_ptr<svxdr::SaveDialog> xDialog(new svxdr::SaveDialog(m_pParentWindow, pCore.get()));
+ DialogReleaseGuard dialogReleaseGuard(*this, xDialog->getDialog());
+
+ // start the dialog
+ short nRet = xDialog->run();
+ return (nRet==DLG_RET_OK_AUTOLUNCH);
+}
+
+bool RecoveryUI::impl_doRecovery()
+{
+ // create core service, which implements the real "emergency save" algorithm.
+ rtl::Reference<svxdr::RecoveryCore> pCore = new svxdr::RecoveryCore(m_xContext, false);
+
+ // create all needed dialogs for this operation
+ // and bind it to the used core service
+ std::unique_ptr<svxdr::RecoveryDialog> xDialog(new svxdr::RecoveryDialog(m_pParentWindow, pCore.get()));
+ DialogReleaseGuard dialogReleaseGuard(*this, xDialog->getDialog());
+
+ // start the dialog
+ short nRet = xDialog->run();
+
+ impl_showAllRecoveredDocs();
+
+ delete_pending_crash();
+
+ return nRet != RET_CANCEL;
+}
+
+void RecoveryUI::impl_showAllRecoveredDocs()
+{
+ css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext );
+
+ css::uno::Reference< css::container::XIndexAccess > xTaskContainer(
+ xDesktop->getFrames(),
+ css::uno::UNO_QUERY_THROW);
+
+ sal_Int32 c = xTaskContainer->getCount();
+ sal_Int32 i = 0;
+ for (i=0; i<c; ++i)
+ {
+ try
+ {
+ css::uno::Reference< css::frame::XFrame > xTask;
+ xTaskContainer->getByIndex(i) >>= xTask;
+ if (!xTask.is())
+ continue;
+
+ css::uno::Reference< css::awt::XWindow > xWindow = xTask->getContainerWindow();
+ if (!xWindow.is())
+ continue;
+
+ xWindow->setVisible(true);
+ }
+ catch(const css::uno::RuntimeException&)
+ { throw; }
+ catch(const css::uno::Exception&)
+ { continue; }
+ }
+}
+
+bool RecoveryUI::impl_doBringToFront()
+{
+ if (!m_pDialog || !m_pDialog->get_visible())
+ return false;
+ m_pDialog->present();
+ return true;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_RecoveryUI_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new RecoveryUI(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/shapeimpl.hxx b/svx/source/unodraw/shapeimpl.hxx
new file mode 100644
index 000000000..68189814f
--- /dev/null
+++ b/svx/source/unodraw/shapeimpl.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_UNODRAW_SHAPEIMPL_HXX
+#define INCLUDED_SVX_SOURCE_UNODRAW_SHAPEIMPL_HXX
+
+#include <svx/unoprov.hxx>
+#include <svx/unoshape.hxx>
+
+class SvxShapeCaption : public SvxShapeText
+{
+public:
+ explicit SvxShapeCaption(SdrObject* pObj);
+ virtual ~SvxShapeCaption() noexcept override;
+};
+class SvxPluginShape : public SvxOle2Shape
+{
+protected:
+ // override these for special property handling in subcasses. Return true if property is handled
+ virtual bool setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue ) override;
+ virtual bool getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue ) override;
+
+public:
+ explicit SvxPluginShape(SdrObject* pObj);
+ virtual ~SvxPluginShape() noexcept override;
+
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ using SvxUnoTextRangeBase::setPropertyValue;
+
+ virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override;
+
+ virtual void Create( SdrObject* pNewOpj, SvxDrawPage* pNewPage ) override;
+};
+class SvxAppletShape : public SvxOle2Shape
+{
+protected:
+ // override these for special property handling in subcasses. Return true if property is handled
+ virtual bool setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue ) override;
+ virtual bool getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue ) override;
+
+public:
+ explicit SvxAppletShape(SdrObject* pObj);
+ virtual ~SvxAppletShape() noexcept override;
+
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ using SvxUnoTextRangeBase::setPropertyValue;
+
+ virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override;
+
+ virtual void Create( SdrObject* pNewOpj, SvxDrawPage* pNewPage ) override;
+};
+
+class SvxFrameShape : public SvxOle2Shape
+{
+private:
+ OUString m_sInitialFrameURL;
+protected:
+ // override these for special property handling in subcasses. Return true if property is handled
+ virtual bool setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue ) override;
+ virtual bool getPropertyValueImpl(const OUString& rName, const SfxItemPropertyMapEntry* pProperty,
+ css::uno::Any& rValue) override;
+
+public:
+ explicit SvxFrameShape(SdrObject* pObj);
+ virtual ~SvxFrameShape() noexcept override;
+
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ using SvxUnoTextRangeBase::setPropertyValue;
+
+ virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override;
+
+ virtual void Create( SdrObject* pNewOpj, SvxDrawPage* pNewPage ) override;
+
+ virtual OUString GetAndClearInitialFrameURL() override;
+};
+
+SvxUnoPropertyMapProvider& getSvxMapProvider();
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/shapepropertynotifier.cxx b/svx/source/unodraw/shapepropertynotifier.cxx
new file mode 100644
index 000000000..a19a5fd96
--- /dev/null
+++ b/svx/source/unodraw/shapepropertynotifier.cxx
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/shapepropertynotifier.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <cppuhelper/weak.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace
+{
+
+}
+
+
+namespace svx
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+ using ::com::sun::star::beans::XPropertyChangeListener;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::beans::XPropertySet;
+
+ PropertyValueProvider::~PropertyValueProvider()
+ {
+ }
+
+ //= PropertyValueProvider
+
+
+ const OUString & PropertyValueProvider::getPropertyName() const
+ {
+ return m_sPropertyName;
+ }
+
+
+ void PropertyValueProvider::getCurrentValue( Any& _out_rValue ) const
+ {
+ Reference< XPropertySet > xContextProps( const_cast< PropertyValueProvider* >( this )->m_rContext, UNO_QUERY_THROW );
+ _out_rValue = xContextProps->getPropertyValue( getPropertyName() );
+ }
+
+ PropertyChangeNotifier::PropertyChangeNotifier( ::cppu::OWeakObject& _rOwner, ::osl::Mutex& _rMutex )
+ :m_rContext( _rOwner )
+ ,m_aPropertyChangeListeners( _rMutex )
+ {
+ }
+
+ PropertyChangeNotifier::~PropertyChangeNotifier()
+ {
+ }
+
+ void PropertyChangeNotifier::registerProvider(const ShapePropertyProviderId _eProperty, std::unique_ptr<PropertyValueProvider> _rProvider)
+ {
+ assert( _rProvider && "NULL factory not allowed." );
+
+ assert( ! m_aProviders[_eProperty] &&
+ "PropertyChangeNotifier::registerProvider: factory for this ID already present!" );
+
+ m_aProviders[ _eProperty ] = std::move(_rProvider);
+ }
+
+ void PropertyChangeNotifier::notifyPropertyChange( const ShapePropertyProviderId _eProperty ) const
+ {
+ auto & provPos = m_aProviders[ _eProperty ];
+ OSL_ENSURE( provPos, "PropertyChangeNotifier::notifyPropertyChange: no factory!" );
+ if (!provPos)
+ return;
+
+ const OUString & sPropertyName( provPos->getPropertyName() );
+
+ ::comphelper::OInterfaceContainerHelper3<XPropertyChangeListener>* pPropListeners = m_aPropertyChangeListeners.getContainer( sPropertyName );
+ ::comphelper::OInterfaceContainerHelper3<XPropertyChangeListener>* pAllListeners = m_aPropertyChangeListeners.getContainer( OUString() );
+ if ( !pPropListeners && !pAllListeners )
+ return;
+
+ try
+ {
+ PropertyChangeEvent aEvent;
+ aEvent.Source = m_rContext;
+ // Handle/OldValue not supported
+ aEvent.PropertyName = provPos->getPropertyName();
+ provPos->getCurrentValue( aEvent.NewValue );
+
+ if ( pPropListeners )
+ pPropListeners->notifyEach( &XPropertyChangeListener::propertyChange, aEvent );
+ if ( pAllListeners )
+ pAllListeners->notifyEach( &XPropertyChangeListener::propertyChange, aEvent );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void PropertyChangeNotifier::addPropertyChangeListener( const OUString& _rPropertyName, const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ m_aPropertyChangeListeners.addInterface( _rPropertyName, _rxListener );
+ }
+
+
+ void PropertyChangeNotifier::removePropertyChangeListener( const OUString& _rPropertyName, const Reference< XPropertyChangeListener >& _rxListener )
+ {
+ m_aPropertyChangeListeners.removeInterface( _rPropertyName, _rxListener );
+ }
+
+
+ void PropertyChangeNotifier::disposing()
+ {
+ EventObject aEvent;
+ aEvent.Source = m_rContext;
+ m_aPropertyChangeListeners.disposeAndClear( aEvent );
+ }
+
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/tableshape.cxx b/svx/source/unodraw/tableshape.cxx
new file mode 100644
index 000000000..b92205164
--- /dev/null
+++ b/svx/source/unodraw/tableshape.cxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "UnoGraphicExporter.hxx"
+#include "shapeimpl.hxx"
+#include <svx/unodraw/SvxTableShape.hxx>
+#include <svx/unoshprp.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/svdpool.hxx>
+
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace sdr::table;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+
+SvxTableShape::SvxTableShape(SdrObject* pObj)
+: SvxShape( pObj, getSvxMapProvider().GetMap(SVXMAP_TABLE), getSvxMapProvider().GetPropertySet(SVXMAP_TABLE, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+ SetShapeType( "com.sun.star.drawing.TableShape" );
+}
+
+SvxTableShape::~SvxTableShape() noexcept
+{
+}
+
+bool SvxTableShape::setPropertyValueImpl(
+ const OUString& rName,
+ const SfxItemPropertyMapEntry* pProperty,
+ const css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_TABLETEMPLATE:
+ {
+ Reference< XIndexAccess > xTemplate;
+
+ if( !(rValue >>= xTemplate) )
+ throw IllegalArgumentException();
+
+ if( HasSdrObject() )
+ static_cast< sdr::table::SdrTableObj* >( GetSdrObject() )->setTableStyle(xTemplate);
+
+ return true;
+ }
+ case OWN_ATTR_TABLETEMPLATE_FIRSTROW:
+ case OWN_ATTR_TABLETEMPLATE_LASTROW:
+ case OWN_ATTR_TABLETEMPLATE_FIRSTCOLUMN:
+ case OWN_ATTR_TABLETEMPLATE_LASTCOLUMN:
+ case OWN_ATTR_TABLETEMPLATE_BANDINGROWS:
+ case OWN_ATTR_TABLETEMPLATE_BANDINGCOLUMNS:
+ {
+ if( HasSdrObject() )
+ {
+ TableStyleSettings aSettings( static_cast< sdr::table::SdrTableObj* >( GetSdrObject() )->getTableStyleSettings() );
+
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_TABLETEMPLATE_FIRSTROW: rValue >>= aSettings.mbUseFirstRow; break;
+ case OWN_ATTR_TABLETEMPLATE_LASTROW: rValue >>= aSettings.mbUseLastRow; break;
+ case OWN_ATTR_TABLETEMPLATE_FIRSTCOLUMN: rValue >>= aSettings.mbUseFirstColumn; break;
+ case OWN_ATTR_TABLETEMPLATE_LASTCOLUMN: rValue >>= aSettings.mbUseLastColumn; break;
+ case OWN_ATTR_TABLETEMPLATE_BANDINGROWS: rValue >>= aSettings.mbUseRowBanding; break;
+ case OWN_ATTR_TABLETEMPLATE_BANDINGCOLUMNS: rValue >>= aSettings.mbUseColumnBanding; break;
+ }
+
+ static_cast< sdr::table::SdrTableObj* >( GetSdrObject() )->setTableStyleSettings(aSettings);
+ }
+
+ return true;
+ }
+ default:
+ {
+ return SvxShape::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+ }
+}
+
+bool SvxTableShape::getPropertyValueImpl(
+ const OUString& rName,
+ const SfxItemPropertyMapEntry* pProperty,
+ css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_OLEMODEL:
+ {
+ if( HasSdrObject() )
+ {
+ rValue <<= static_cast< sdr::table::SdrTableObj* >( GetSdrObject() )->getTable();
+ }
+ return true;
+ }
+ case OWN_ATTR_TABLETEMPLATE:
+ {
+ if( HasSdrObject() )
+ {
+ rValue <<= static_cast< sdr::table::SdrTableObj* >( GetSdrObject() )->getTableStyle();
+ }
+ return true;
+ }
+ case OWN_ATTR_REPLACEMENT_GRAPHIC:
+ {
+ if( HasSdrObject() )
+ {
+ Graphic aGraphic( SvxGetGraphicForShape( *GetSdrObject() ) );
+ rValue <<= aGraphic.GetXGraphic();
+ }
+ return true;
+ }
+ case OWN_ATTR_TABLETEMPLATE_FIRSTROW:
+ case OWN_ATTR_TABLETEMPLATE_LASTROW:
+ case OWN_ATTR_TABLETEMPLATE_FIRSTCOLUMN:
+ case OWN_ATTR_TABLETEMPLATE_LASTCOLUMN:
+ case OWN_ATTR_TABLETEMPLATE_BANDINGROWS:
+ case OWN_ATTR_TABLETEMPLATE_BANDINGCOLUMNS:
+ {
+ if( HasSdrObject() )
+ {
+ TableStyleSettings aSettings( static_cast< sdr::table::SdrTableObj* >( GetSdrObject() )->getTableStyleSettings() );
+
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_TABLETEMPLATE_FIRSTROW: rValue <<= aSettings.mbUseFirstRow; break;
+ case OWN_ATTR_TABLETEMPLATE_LASTROW: rValue <<= aSettings.mbUseLastRow; break;
+ case OWN_ATTR_TABLETEMPLATE_FIRSTCOLUMN: rValue <<= aSettings.mbUseFirstColumn; break;
+ case OWN_ATTR_TABLETEMPLATE_LASTCOLUMN: rValue <<= aSettings.mbUseLastColumn; break;
+ case OWN_ATTR_TABLETEMPLATE_BANDINGROWS: rValue <<= aSettings.mbUseRowBanding; break;
+ case OWN_ATTR_TABLETEMPLATE_BANDINGCOLUMNS: rValue <<= aSettings.mbUseColumnBanding; break;
+ }
+ }
+
+ return true;
+ }
+ default:
+ {
+ return SvxShape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+ }
+}
+
+void SvxTableShape::lock()
+{
+ SvxShape::lock();
+ if( HasSdrObject() )
+ static_cast< sdr::table::SdrTableObj* >( GetSdrObject() )->uno_lock();
+}
+
+void SvxTableShape::unlock()
+{
+ if( HasSdrObject() )
+ static_cast< sdr::table::SdrTableObj* >( GetSdrObject() )->uno_unlock();
+ SvxShape::unlock();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unobrushitemhelper.cxx b/svx/source/unodraw/unobrushitemhelper.cxx
new file mode 100644
index 000000000..bc9d04747
--- /dev/null
+++ b/svx/source/unodraw/unobrushitemhelper.cxx
@@ -0,0 +1,342 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+
+#include <osl/diagnose.h>
+#include <svl/itemset.hxx>
+#include <svx/unobrushitemhelper.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflbmpit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflbckit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfltrit.hxx>
+
+using namespace com::sun::star;
+
+void setSvxBrushItemAsFillAttributesToTargetSet(const SvxBrushItem& rBrush, SfxItemSet& rToSet)
+{
+ // Clear all items from the DrawingLayer FillStyle range (if we have any). All
+ // items that need to be set will be set as hard attributes
+ for(sal_uInt16 a(XATTR_FILL_FIRST); rToSet.Count() && a < XATTR_FILL_LAST; a++)
+ {
+ rToSet.ClearItem(a);
+ }
+
+ const sal_uInt8 nTransparency(255 - rBrush.GetColor().GetAlpha());
+
+ // tdf#89478 check for image first
+ if (GPOS_NONE != rBrush.GetGraphicPos())
+ {
+ // we have a graphic fill, set fill style
+ rToSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP));
+
+ // set graphic (if available)
+ const Graphic* pGraphic = rBrush.GetGraphic();
+
+ if(pGraphic)
+ {
+ rToSet.Put(XFillBitmapItem(OUString(), *pGraphic));
+ }
+ else
+ {
+ OSL_ENSURE(false, "Could not get Graphic from SvxBrushItem (!)");
+ }
+
+ if(GPOS_AREA == rBrush.GetGraphicPos())
+ {
+ // stretch, also means no tile (both items are defaulted to true)
+ rToSet.Put(XFillBmpStretchItem(true));
+ rToSet.Put(XFillBmpTileItem(false));
+
+ // default for stretch is also top-left, but this will not be visible
+ rToSet.Put(XFillBmpPosItem(RectPoint::LT));
+ }
+ else if(GPOS_TILED == rBrush.GetGraphicPos())
+ {
+ // tiled, also means no stretch (both items are defaulted to true)
+ rToSet.Put(XFillBmpStretchItem(false));
+ rToSet.Put(XFillBmpTileItem(true));
+
+ // default for tiled is top-left
+ rToSet.Put(XFillBmpPosItem(RectPoint::LT));
+ }
+ else
+ {
+ // everything else means no tile and no stretch
+ rToSet.Put(XFillBmpStretchItem(false));
+ rToSet.Put(XFillBmpTileItem(false));
+
+ RectPoint aRectPoint(RectPoint::MM);
+
+ switch(rBrush.GetGraphicPos())
+ {
+ case GPOS_LT: aRectPoint = RectPoint::LT; break;
+ case GPOS_MT: aRectPoint = RectPoint::MT; break;
+ case GPOS_RT: aRectPoint = RectPoint::RT; break;
+ case GPOS_LM: aRectPoint = RectPoint::LM; break;
+ case GPOS_MM: aRectPoint = RectPoint::MM; break;
+ case GPOS_RM: aRectPoint = RectPoint::RM; break;
+ case GPOS_LB: aRectPoint = RectPoint::LB; break;
+ case GPOS_MB: aRectPoint = RectPoint::MB; break;
+ case GPOS_RB: aRectPoint = RectPoint::RB; break;
+ default: break; // GPOS_NONE, GPOS_AREA and GPOS_TILED already handled
+ }
+
+ rToSet.Put(XFillBmpPosItem(aRectPoint));
+ }
+
+ // check for graphic's transparency
+ const sal_Int8 nGraphicTransparency(rBrush.getGraphicTransparency());
+
+ if(0 != nGraphicTransparency)
+ {
+ // nGraphicTransparency is in range [0..100]
+ rToSet.Put(XFillTransparenceItem(nGraphicTransparency));
+ }
+ }
+ else if (0xff != nTransparency)
+ {
+ // we have a color fill
+ const Color aColor(rBrush.GetColor().GetRGBColor());
+
+ rToSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ rToSet.Put(XFillColorItem(OUString(), aColor));
+
+ // #125189# nTransparency is in range [0..254], convert to [0..100] which is used in
+ // XFillTransparenceItem (caution with the range which is in an *item-specific* range)
+ rToSet.Put(XFillTransparenceItem(((static_cast<sal_Int32>(nTransparency) * 100) + 127) / 254));
+ }
+ else
+ {
+ // GPOS_NONE == rBrush.GetGraphicPos() && 0xff == rBrush.GetColor().GetTransparency(),
+ // still need to rescue the color used. There are sequences used on the UNO API at
+ // import time (OLE. e.g. chart) which first set RGB color (MID_BACK_COLOR_R_G_B,
+ // color stays transparent) and then set transparency (MID_BACK_COLOR_TRANSPARENCY)
+ // to zero later. When not saving the color, it will be lost.
+ // Also need to set the FillStyle to NONE to express the 0xff transparency flag; this
+ // is needed when e.g. first transparency is set to 0xff and then a Graphic gets set.
+ // When not changing the FillStyle, the next getSvxBrushItemFromSourceSet *will* return
+ // to drawing::FillStyle_SOLID with the rescued color.
+ const Color aColor(rBrush.GetColor().GetRGBColor());
+
+ rToSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ rToSet.Put(XFillColorItem(OUString(), aColor));
+ }
+}
+
+static sal_uInt16 getTransparenceForSvxBrushItem(const SfxItemSet& rSourceSet, bool bSearchInParents)
+{
+ sal_uInt16 nFillTransparence(rSourceSet.Get(XATTR_FILLTRANSPARENCE, bSearchInParents).GetValue());
+ const XFillFloatTransparenceItem* pGradientItem = nullptr;
+
+ if((pGradientItem = rSourceSet.GetItemIfSet(XATTR_FILLFLOATTRANSPARENCE, bSearchInParents))
+ && pGradientItem->IsEnabled())
+ {
+ const XGradient& rGradient = pGradientItem->GetGradientValue();
+ const sal_uInt16 nStartLuminance(rGradient.GetStartColor().GetLuminance());
+ const sal_uInt16 nEndLuminance(rGradient.GetEndColor().GetLuminance());
+
+ // luminance is [0..255], transparence needs to be in [0..100].Maximum is 51200, thus sal_uInt16 is okay to use
+ nFillTransparence = static_cast< sal_uInt16 >(((nStartLuminance + nEndLuminance) * 100) / 512);
+ }
+
+ return nFillTransparence;
+}
+
+static std::unique_ptr<SvxBrushItem> getSvxBrushItemForSolid(const SfxItemSet& rSourceSet, bool bSearchInParents, sal_uInt16 nBackgroundID)
+{
+ Color aFillColor(rSourceSet.Get(XATTR_FILLCOLOR, bSearchInParents).GetColorValue());
+
+ // get evtl. mixed transparence
+ const sal_uInt16 nFillTransparence(getTransparenceForSvxBrushItem(rSourceSet, bSearchInParents));
+
+ if(0 != nFillTransparence)
+ {
+ // #i125189# nFillTransparence is in range [0..100] and needs to be in [0..254] unsigned
+ // It is necessary to use the maximum of 0xfe for transparence for the SvxBrushItem
+ // since the oxff value is used for special purposes (like no fill and derive from parent)
+ const sal_uInt8 aTargetTrans(std::min(sal_uInt8(0xfe), static_cast< sal_uInt8 >((nFillTransparence * 254) / 100)));
+
+ aFillColor.SetAlpha(255 - aTargetTrans);
+ }
+
+ return std::make_unique<SvxBrushItem>(aFillColor, nBackgroundID);
+}
+
+std::unique_ptr<SvxBrushItem> getSvxBrushItemFromSourceSet(const SfxItemSet& rSourceSet, sal_uInt16 nBackgroundID, bool bSearchInParents, bool bXMLImportHack)
+{
+ const XFillStyleItem* pXFillStyleItem(rSourceSet.GetItem<XFillStyleItem>(XATTR_FILLSTYLE, bSearchInParents));
+
+ if(!pXFillStyleItem || drawing::FillStyle_NONE == pXFillStyleItem->GetValue())
+ {
+ // no fill, still need to rescue the evtl. set RGB color, but use as transparent color (we have drawing::FillStyle_NONE)
+ Color aFillColor(rSourceSet.Get(XATTR_FILLCOLOR, bSearchInParents).GetColorValue());
+
+ // for writerfilter: when fill style is none, then don't allow anything other than 0 or auto.
+ if (!bXMLImportHack && aFillColor != Color(0))
+ aFillColor = COL_AUTO;
+
+ aFillColor.SetAlpha(0);
+
+ return std::make_unique<SvxBrushItem>(aFillColor, nBackgroundID);
+ }
+
+ std::unique_ptr<SvxBrushItem> xRetval;
+
+ switch(pXFillStyleItem->GetValue())
+ {
+ case drawing::FillStyle_NONE:
+ {
+ // already handled above, can not happen again
+ break;
+ }
+ case drawing::FillStyle_SOLID:
+ {
+ // create SvxBrushItem with fill color
+ xRetval = getSvxBrushItemForSolid(rSourceSet, bSearchInParents, nBackgroundID);
+ break;
+ }
+ case drawing::FillStyle_GRADIENT:
+ {
+ // cannot be directly supported, but do the best possible
+ const XGradient aXGradient(rSourceSet.Get(XATTR_FILLGRADIENT).GetGradientValue());
+ const basegfx::BColor aStartColor(aXGradient.GetStartColor().getBColor() * (aXGradient.GetStartIntens() * 0.01));
+ const basegfx::BColor aEndColor(aXGradient.GetEndColor().getBColor() * (aXGradient.GetEndIntens() * 0.01));
+
+ // use half/half mixed color from gradient start and end
+ Color aMixedColor((aStartColor + aEndColor) * 0.5);
+
+ // get evtl. mixed transparence
+ const sal_uInt16 nFillTransparence(getTransparenceForSvxBrushItem(rSourceSet, bSearchInParents));
+
+ if(0 != nFillTransparence)
+ {
+ // #i125189# nFillTransparence is in range [0..100] and needs to be in [0..254] unsigned
+ // It is necessary to use the maximum of 0xfe for transparence for the SvxBrushItem
+ // since the oxff value is used for special purposes (like no fill and derive from parent)
+ const sal_uInt8 aTargetTrans(std::min(sal_uInt8(0xfe), static_cast< sal_uInt8 >((nFillTransparence * 254) / 100)));
+
+ aMixedColor.SetAlpha(255 - aTargetTrans);
+ }
+
+ xRetval = std::make_unique<SvxBrushItem>(aMixedColor, nBackgroundID);
+ break;
+ }
+ case drawing::FillStyle_HATCH:
+ {
+ // cannot be directly supported, but do the best possible
+ const XHatch& rHatch(rSourceSet.Get(XATTR_FILLHATCH).GetHatchValue());
+ const bool bFillBackground(rSourceSet.Get(XATTR_FILLBACKGROUND).GetValue());
+
+ if(bFillBackground)
+ {
+ // hatch is background-filled, use FillColor as if drawing::FillStyle_SOLID
+ xRetval = getSvxBrushItemForSolid(rSourceSet, bSearchInParents, nBackgroundID);
+ }
+ else
+ {
+ // hatch is not background-filled and using hatch color would be too dark; compensate
+ // somewhat by making it more transparent
+ Color aHatchColor(rHatch.GetColor());
+
+ // get evtl. mixed transparence
+ sal_uInt16 nFillTransparence(getTransparenceForSvxBrushItem(rSourceSet, bSearchInParents));
+
+ // take half orig transparence, add half transparent, clamp result
+ nFillTransparence = std::clamp(static_cast<sal_uInt16>((nFillTransparence / 2) + 50), sal_uInt16(0), sal_uInt16(255));
+
+ // #i125189# nFillTransparence is in range [0..100] and needs to be in [0..254] unsigned
+ // It is necessary to use the maximum of 0xfe for transparence for the SvxBrushItem
+ // since the oxff value is used for special purposes (like no fill and derive from parent)
+ const sal_uInt8 aTargetTrans(std::min(sal_uInt8(0xfe), static_cast< sal_uInt8 >((nFillTransparence * 254) / 100)));
+
+ aHatchColor.SetAlpha(255 - aTargetTrans);
+ xRetval = std::make_unique<SvxBrushItem>(aHatchColor, nBackgroundID);
+ }
+
+ break;
+ }
+ case drawing::FillStyle_BITMAP:
+ {
+ // create SvxBrushItem with bitmap info and flags
+ const XFillBitmapItem& rBmpItm = rSourceSet.Get(XATTR_FILLBITMAP, bSearchInParents);
+ const Graphic aGraphic(rBmpItm.GetGraphicObject().GetGraphic());
+
+ // continue independent of evtl. GraphicType::NONE as aGraphic.GetType(), we still need to rescue positions
+ SvxGraphicPosition aSvxGraphicPosition(GPOS_NONE);
+ const XFillBmpStretchItem& rStretchItem = rSourceSet.Get(XATTR_FILLBMP_STRETCH, bSearchInParents);
+ const XFillBmpTileItem& rTileItem = rSourceSet.Get(XATTR_FILLBMP_TILE, bSearchInParents);
+
+ if(rTileItem.GetValue())
+ {
+ aSvxGraphicPosition = GPOS_TILED;
+ }
+ else if(rStretchItem.GetValue())
+ {
+ aSvxGraphicPosition = GPOS_AREA;
+ }
+ else
+ {
+ const XFillBmpPosItem& rPosItem = rSourceSet.Get(XATTR_FILLBMP_POS, bSearchInParents);
+
+ switch(rPosItem.GetValue())
+ {
+ case RectPoint::LT: aSvxGraphicPosition = GPOS_LT; break;
+ case RectPoint::MT: aSvxGraphicPosition = GPOS_MT; break;
+ case RectPoint::RT: aSvxGraphicPosition = GPOS_RT; break;
+ case RectPoint::LM: aSvxGraphicPosition = GPOS_LM; break;
+ case RectPoint::MM: aSvxGraphicPosition = GPOS_MM; break;
+ case RectPoint::RM: aSvxGraphicPosition = GPOS_RM; break;
+ case RectPoint::LB: aSvxGraphicPosition = GPOS_LB; break;
+ case RectPoint::MB: aSvxGraphicPosition = GPOS_MB; break;
+ case RectPoint::RB: aSvxGraphicPosition = GPOS_RB; break;
+ }
+ }
+
+ // create with given graphic and position
+ xRetval = std::make_unique<SvxBrushItem>(aGraphic, aSvxGraphicPosition, nBackgroundID);
+
+ // get evtl. mixed transparence
+ const sal_uInt16 nFillTransparence(getTransparenceForSvxBrushItem(rSourceSet, bSearchInParents));
+
+ if(0 != nFillTransparence)
+ {
+ // #i125189# nFillTransparence is in range [0..100] and needs to be in [0..100] signed
+ xRetval->setGraphicTransparency(static_cast< sal_Int8 >(nFillTransparence));
+ }
+
+ break;
+ }
+ default:
+ xRetval = std::make_unique<SvxBrushItem>(nBackgroundID);
+ break;
+ }
+
+ return xRetval;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unobtabl.cxx b/svx/source/unodraw/unobtabl.cxx
new file mode 100644
index 000000000..bba7bdbff
--- /dev/null
+++ b/svx/source/unodraw/unobtabl.cxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/xit.hxx>
+#include "UnoNameItemTable.hxx"
+
+#include <svx/xbtmpit.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/unomid.hxx>
+#include <svx/unofill.hxx>
+#include <com/sun/star/awt/XBitmap.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::cppu;
+
+namespace {
+
+class SvxUnoBitmapTable : public SvxUnoNameItemTable
+{
+public:
+ explicit SvxUnoBitmapTable( SdrModel* pModel ) noexcept;
+
+ virtual NameOrIndex* createItem() const override;
+ virtual bool isValid( const NameOrIndex* pItem ) const override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType( ) override;
+};
+
+}
+
+SvxUnoBitmapTable::SvxUnoBitmapTable( SdrModel* pModel ) noexcept
+: SvxUnoNameItemTable( pModel, XATTR_FILLBITMAP, MID_BITMAP )
+{
+}
+
+bool SvxUnoBitmapTable::isValid( const NameOrIndex* pItem ) const
+{
+ if( SvxUnoNameItemTable::isValid( pItem ) )
+ {
+ const XFillBitmapItem* pBitmapItem = dynamic_cast< const XFillBitmapItem* >( pItem );
+ if( pBitmapItem )
+ {
+ const Graphic& rGraphic = pBitmapItem->GetGraphicObject().GetGraphic();
+
+ return rGraphic.GetSizeBytes() > 0;
+ }
+ }
+
+ return false;
+}
+
+OUString SAL_CALL SvxUnoBitmapTable::getImplementationName()
+{
+ return "SvxUnoBitmapTable";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoBitmapTable::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.BitmapTable" };
+}
+
+NameOrIndex* SvxUnoBitmapTable::createItem() const
+{
+ return new XFillBitmapItem();
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoBitmapTable::getElementType( )
+{
+ return ::cppu::UnoType<awt::XBitmap>::get();
+}
+
+/**
+ * Create a bitmaptable
+ */
+uno::Reference< uno::XInterface > SvxUnoBitmapTable_createInstance( SdrModel* pModel )
+{
+ return *new SvxUnoBitmapTable(pModel);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unoctabl.cxx b/svx/source/unodraw/unoctabl.cxx
new file mode 100644
index 000000000..1d50a7c32
--- /dev/null
+++ b/svx/source/unodraw/unoctabl.cxx
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unotools/pathoptions.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ref.hxx>
+#include <svx/xtable.hxx>
+
+using namespace ::com::sun::star;
+
+namespace {
+
+class SvxUnoColorTable : public cppu::WeakImplHelper< container::XNameContainer, lang::XServiceInfo >
+{
+private:
+ XColorListRef pList;
+
+public:
+ SvxUnoColorTable();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& Name ) override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override;
+
+ // XNameAccess
+ virtual uno::Any SAL_CALL getByName( const OUString& aName ) override;
+
+ virtual uno::Sequence< OUString > SAL_CALL getElementNames() override;
+
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+};
+
+SvxUnoColorTable::SvxUnoColorTable()
+ : pList(XPropertyList::AsColorList(
+ XPropertyList::CreatePropertyList(
+ XPropertyListType::Color, SvtPathOptions().GetPalettePath(), "")))
+{
+}
+
+sal_Bool SAL_CALL SvxUnoColorTable::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+OUString SAL_CALL SvxUnoColorTable::getImplementationName()
+{
+ return "com.sun.star.drawing.SvxUnoColorTable";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoColorTable::getSupportedServiceNames()
+{
+ uno::Sequence<OUString> aSNS { "com.sun.star.drawing.ColorTable" };
+ return aSNS;
+}
+
+// XNameContainer
+void SAL_CALL SvxUnoColorTable::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ if( hasByName( aName ) )
+ throw container::ElementExistException();
+
+ Color aColor;
+ if( !(aElement >>= aColor) )
+ throw lang::IllegalArgumentException();
+
+ if( pList.is() )
+ {
+ pList->Insert(std::make_unique<XColorEntry>(aColor, aName));
+ }
+}
+
+void SAL_CALL SvxUnoColorTable::removeByName( const OUString& Name )
+{
+ tools::Long nIndex = pList.is() ? pList->GetIndex( Name ) : -1;
+ if( nIndex == -1 )
+ throw container::NoSuchElementException();
+
+ pList->Remove( nIndex );
+}
+
+// XNameReplace
+void SAL_CALL SvxUnoColorTable::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ Color nColor;
+ if( !(aElement >>= nColor) )
+ throw lang::IllegalArgumentException();
+
+ tools::Long nIndex = pList.is() ? pList->GetIndex( aName ) : -1;
+ if( nIndex == -1 )
+ throw container::NoSuchElementException();
+
+ pList->Replace(nIndex, std::make_unique<XColorEntry>(nColor, aName ));
+}
+
+// XNameAccess
+uno::Any SAL_CALL SvxUnoColorTable::getByName( const OUString& aName )
+{
+ tools::Long nIndex = pList.is() ? pList->GetIndex( aName ) : -1;
+ if( nIndex == -1 )
+ throw container::NoSuchElementException();
+
+ const XColorEntry* pEntry = pList->GetColor(nIndex);
+ return uno::Any( static_cast<sal_Int32>(pEntry->GetColor().GetRGBColor()) );
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoColorTable::getElementNames()
+{
+ const tools::Long nCount = pList.is() ? pList->Count() : 0;
+
+ uno::Sequence< OUString > aSeq( nCount );
+ OUString* pStrings = aSeq.getArray();
+
+ for( tools::Long nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ const XColorEntry* pEntry = pList->GetColor(nIndex);
+ pStrings[nIndex] = pEntry->GetName();
+ }
+
+ return aSeq;
+}
+
+sal_Bool SAL_CALL SvxUnoColorTable::hasByName( const OUString& aName )
+{
+ tools::Long nIndex = pList.is() ? pList->GetIndex( aName ) : -1;
+ return nIndex != -1;
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoColorTable::getElementType()
+{
+ return ::cppu::UnoType<sal_Int32>::get();
+}
+
+sal_Bool SAL_CALL SvxUnoColorTable::hasElements()
+{
+ return pList.is() && pList->Count() != 0;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_drawing_SvxUnoColorTable_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SvxUnoColorTable);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unodtabl.cxx b/svx/source/unodraw/unodtabl.cxx
new file mode 100644
index 000000000..c460bbd7c
--- /dev/null
+++ b/svx/source/unodraw/unodtabl.cxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/LineDash.hpp>
+
+#include "UnoNameItemTable.hxx"
+#include <svx/xlndsit.hxx>
+#include <svx/unomid.hxx>
+
+#include <svx/svdmodel.hxx>
+#include <svx/unofill.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::cppu;
+
+namespace
+{
+class SvxUnoDashTable : public SvxUnoNameItemTable
+{
+public:
+ explicit SvxUnoDashTable(SdrModel* pModel) noexcept;
+
+ virtual NameOrIndex* createItem() const override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+};
+}
+
+SvxUnoDashTable::SvxUnoDashTable(SdrModel* pModel) noexcept
+ : SvxUnoNameItemTable(pModel, XATTR_LINEDASH, MID_LINEDASH)
+{
+}
+
+OUString SAL_CALL SvxUnoDashTable::getImplementationName() { return "SvxUnoDashTable"; }
+
+uno::Sequence<OUString> SAL_CALL SvxUnoDashTable::getSupportedServiceNames()
+{
+ return { "com.sun.star.drawing.DashTable" };
+}
+
+NameOrIndex* SvxUnoDashTable::createItem() const
+{
+ XLineDashItem* pNewItem = new XLineDashItem();
+ pNewItem->SetWhich(XATTR_LINEDASH); // set which id for pooling
+ return pNewItem;
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoDashTable::getElementType()
+{
+ return cppu::UnoType<drawing::LineDash>::get();
+}
+
+/**
+ * Create a gradienttable
+ */
+uno::Reference<uno::XInterface> SvxUnoDashTable_createInstance(SdrModel* pModel)
+{
+ return *new SvxUnoDashTable(pModel);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unogtabl.cxx b/svx/source/unodraw/unogtabl.cxx
new file mode 100644
index 000000000..7939ccfd0
--- /dev/null
+++ b/svx/source/unodraw/unogtabl.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/awt/Gradient.hpp>
+#include "UnoNameItemTable.hxx"
+
+#include <svx/svdmodel.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/unofill.hxx>
+#include <svx/unomid.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::cppu;
+
+namespace
+{
+class SvxUnoGradientTable : public SvxUnoNameItemTable
+{
+public:
+ explicit SvxUnoGradientTable(SdrModel* pModel) noexcept;
+
+ virtual NameOrIndex* createItem() const override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+};
+}
+
+SvxUnoGradientTable::SvxUnoGradientTable(SdrModel* pModel) noexcept
+ : SvxUnoNameItemTable(pModel, XATTR_FILLGRADIENT, MID_FILLGRADIENT)
+{
+}
+
+OUString SAL_CALL SvxUnoGradientTable::getImplementationName() { return "SvxUnoGradientTable"; }
+
+uno::Sequence<OUString> SAL_CALL SvxUnoGradientTable::getSupportedServiceNames()
+{
+ return { "com.sun.star.drawing.GradientTable" };
+}
+
+// XNameContainer
+NameOrIndex* SvxUnoGradientTable::createItem() const { return new XFillGradientItem(); }
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoGradientTable::getElementType()
+{
+ return cppu::UnoType<awt::Gradient>::get();
+}
+
+/**
+ * Create a gradienttable
+ */
+uno::Reference<uno::XInterface> SvxUnoGradientTable_createInstance(SdrModel* pModel)
+{
+ return *new SvxUnoGradientTable(pModel);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unohtabl.cxx b/svx/source/unodraw/unohtabl.cxx
new file mode 100644
index 000000000..cb36192bd
--- /dev/null
+++ b/svx/source/unodraw/unohtabl.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/Hatch.hpp>
+#include "UnoNameItemTable.hxx"
+
+#include <svx/svdmodel.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/unomid.hxx>
+#include <svx/unofill.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::cppu;
+
+namespace {
+
+class SvxUnoHatchTable : public SvxUnoNameItemTable
+{
+public:
+ explicit SvxUnoHatchTable( SdrModel* pModel ) noexcept;
+
+ virtual NameOrIndex* createItem() const override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType( ) override;
+};
+
+}
+
+SvxUnoHatchTable::SvxUnoHatchTable( SdrModel* pModel ) noexcept
+: SvxUnoNameItemTable( pModel, XATTR_FILLHATCH, MID_FILLHATCH )
+{
+}
+
+OUString SAL_CALL SvxUnoHatchTable::getImplementationName()
+{
+ return "SvxUnoHatchTable";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoHatchTable::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.HatchTable" };
+}
+
+NameOrIndex* SvxUnoHatchTable::createItem() const
+{
+ return new XFillHatchItem();
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoHatchTable::getElementType( )
+{
+ return cppu::UnoType<drawing::Hatch>::get();
+}
+
+/**
+ * Create a hatchtable
+ */
+uno::Reference< uno::XInterface > SvxUnoHatchTable_createInstance( SdrModel* pModel )
+{
+ return *new SvxUnoHatchTable(pModel);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unomlstr.cxx b/svx/source/unodraw/unomlstr.cxx
new file mode 100644
index 000000000..781b3dc38
--- /dev/null
+++ b/svx/source/unodraw/unomlstr.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdobj.hxx>
+#include <vcl/svapp.hxx>
+
+#include <unomlstr.hxx>
+
+using namespace ::com::sun::star;
+
+SvxUnoShapeModifyListener::SvxUnoShapeModifyListener( SdrObject* pObj ) noexcept
+{
+ mpObj = pObj;
+}
+
+SvxUnoShapeModifyListener::~SvxUnoShapeModifyListener() noexcept
+{
+}
+
+// css::util::XModifyListener
+void SAL_CALL SvxUnoShapeModifyListener::modified(const lang::EventObject& )
+{
+ SolarMutexGuard aGuard;
+ if( mpObj )
+ {
+ mpObj->SetChanged();
+ mpObj->BroadcastObjectChange();
+ }
+}
+
+// css::lang::XEventListener
+void SvxUnoShapeModifyListener::disposing(const lang::EventObject& )
+{
+ invalidate();
+}
+
+// internal
+void SvxUnoShapeModifyListener::invalidate() noexcept
+{
+ mpObj = nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unomod.cxx b/svx/source/unodraw/unomod.cxx
new file mode 100644
index 000000000..b36eb09a5
--- /dev/null
+++ b/svx/source/unodraw/unomod.cxx
@@ -0,0 +1,670 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <vcl/svapp.hxx>
+#include <svl/itempool.hxx>
+#include <svtools/unoevent.hxx>
+#include <comphelper/sequence.hxx>
+#include <o3tl/string_view.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <svx/unofill.hxx>
+#include <editeng/unonrule.hxx>
+#include <svtools/unoimap.hxx>
+#include <sfx2/event.hxx>
+#include <svx/fmdpage.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/unoapi.hxx>
+
+#include <svx/svdmodel.hxx>
+#include <svx/unoprov.hxx>
+#include <svx/unopage.hxx>
+#include <editeng/unofield.hxx>
+#include <svx/unomod.hxx>
+#include <svx/unomodel.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/SvxXTextColumns.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/xmlgrhlp.hxx>
+
+#include <com/sun/star/text/textfield/Type.hpp>
+
+//-
+
+using namespace ::com::sun::star;
+
+//-
+
+#define QUERYINT( xint ) \
+ if( rType == cppu::UnoType<xint>::get() ) \
+ aAny <<= uno::Reference< xint >(this)
+
+//-
+
+class SvxUnoDrawPagesAccess : public ::cppu::WeakImplHelper< css::drawing::XDrawPages, css::lang::XServiceInfo >
+{
+private:
+ SvxUnoDrawingModel& mrModel;
+
+public:
+ explicit SvxUnoDrawPagesAccess( SvxUnoDrawingModel& rMyModel ) noexcept;
+
+ // XDrawPages
+ virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL insertNewByIndex( sal_Int32 nIndex ) override;
+ virtual void SAL_CALL remove( const css::uno::Reference< css::drawing::XDrawPage >& xPage ) override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+//-
+
+static const SvEventDescription* ImplGetSupportedMacroItems()
+{
+ static const SvEventDescription aMacroDescriptionsImpl[] =
+ {
+ { SvMacroItemId::OnMouseOver, "OnMouseOver" },
+ { SvMacroItemId::OnMouseOut, "OnMouseOut" },
+ { SvMacroItemId::NONE, nullptr }
+ };
+
+ return aMacroDescriptionsImpl;
+}
+
+//-
+
+/** fills the given EventObject from the given SdrHint.
+ @returns
+ true if the SdrHint could be translated to an EventObject<br>
+ false if not
+*/
+bool SvxUnoDrawMSFactory::createEvent( const SdrModel* pDoc, const SdrHint* pSdrHint, css::document::EventObject& aEvent )
+{
+ const SdrObject* pObj = nullptr;
+ const SdrPage* pPage = nullptr;
+
+ switch( pSdrHint->GetKind() )
+ {
+// case SdrHintKind::LayerChange: // layer definition changed
+// case SdrHintKind::LayerOrderChange: // layer order changed (Insert/Remove/ChangePos)
+// case HINT_LAYERSETCHG: // layer set changed
+// case HINT_LAYERSETORDERCHG: // layer set order changed (Insert/Remove/ChangePos)
+
+// case HINT_PAGECHG: // page changed
+// aEvent.EventName = "PageModified";
+// pPage = pSdrHint->GetPage();
+// break;
+ case SdrHintKind::PageOrderChange: // draw or master page order changed (Insert/Remove/ChangePos)
+ aEvent.EventName = "PageOrderModified";
+ pPage = pSdrHint->GetPage();
+ break;
+ case SdrHintKind::ObjectChange: // object changed
+ aEvent.EventName = "ShapeModified";
+ pObj = pSdrHint->GetObject();
+ break;
+ case SdrHintKind::ObjectInserted: // add new draw object
+ aEvent.EventName = "ShapeInserted";
+ pObj = pSdrHint->GetObject();
+ break;
+ case SdrHintKind::ObjectRemoved: // removed draw object from list
+ aEvent.EventName = "ShapeRemoved";
+ pObj = pSdrHint->GetObject();
+ break;
+// SdrHintKind::DefaultTabChange, // default tab width changed
+// SdrHintKind::SwitchToPage, // #94278# UNDO/REDO at an object evtl. on another page
+// HINT_OBJLISTCLEAR // Is called before an SdrObjList will be cleared
+ default:
+ return false;
+ }
+
+ if( pObj )
+ aEvent.Source = const_cast<SdrObject*>(pObj)->getUnoShape();
+ else if( pPage )
+ aEvent.Source = const_cast<SdrPage*>(pPage)->getUnoPage();
+ else
+ aEvent.Source = const_cast<SdrModel*>(pDoc)->getUnoModel();
+
+ return true;
+}
+
+namespace {
+
+css::uno::Reference<css::uno::XInterface> create(
+ OUString const & rServiceSpecifier, OUString const & referer)
+{
+ if( rServiceSpecifier.startsWith("com.sun.star.drawing.") )
+ {
+ std::optional<SdrObjKind> nType = UHashMap::getId( rServiceSpecifier );
+ if( nType )
+ {
+ SdrInventor nI = IsInventorE3D(*nType) ? SdrInventor::E3d : SdrInventor::Default;
+
+ return uno::Reference< uno::XInterface >( static_cast<drawing::XShape*>(SvxDrawPage::CreateShapeByTypeAndInventor( *nType, nI, nullptr, nullptr, referer ).get()) );
+ }
+ }
+ else if (rServiceSpecifier == "com.sun.star.document.ImportGraphicStorageHandler")
+ {
+ rtl::Reference<SvXMLGraphicHelper> pGraphicHelper = SvXMLGraphicHelper::Create( SvXMLGraphicHelperMode::Read );
+ uno::Reference< uno::XInterface> xRet( static_cast< ::cppu::OWeakObject* >( pGraphicHelper.get() ) );
+ return xRet;
+ }
+ else if (rServiceSpecifier == "com.sun.star.text.TextColumns")
+ {
+ return SvxXTextColumns_createInstance();
+ }
+
+ uno::Reference< uno::XInterface > xRet( SvxUnoDrawMSFactory::createTextField( rServiceSpecifier ) );
+ if( !xRet.is() )
+ throw lang::ServiceNotRegisteredException("unknown service: " + rServiceSpecifier);
+
+ return xRet;
+}
+
+}
+
+uno::Reference< uno::XInterface > SAL_CALL SvxUnoDrawMSFactory::createInstance( const OUString& rServiceSpecifier )
+{
+ return create(rServiceSpecifier, "");
+}
+
+uno::Reference< uno::XInterface > SvxUnoDrawMSFactory::createTextField( std::u16string_view ServiceSpecifier )
+{
+ return SvxUnoTextCreateTextField( ServiceSpecifier );
+}
+
+uno::Reference< uno::XInterface > SAL_CALL SvxUnoDrawMSFactory::createInstanceWithArguments( const OUString& ServiceSpecifier, const uno::Sequence< css::uno::Any >& Arguments )
+{
+ OUString arg;
+ if ((ServiceSpecifier == "com.sun.star.drawing.GraphicObjectShape"
+ || ServiceSpecifier == "com.sun.star.drawing.MediaShape")
+ && Arguments.getLength() == 1 && (Arguments[0] >>= arg))
+ {
+ return create(ServiceSpecifier, arg);
+ }
+ throw lang::NoSupportException();
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoDrawMSFactory::getAvailableServiceNames()
+{
+ return UHashMap::getServiceNames();
+}
+
+SdrModel& SvxUnoDrawingModel::getSdrModelFromUnoModel() const
+{
+ OSL_ENSURE(mpDoc, "No SdrModel in UnoDrawingModel, should not happen");
+ return *mpDoc;
+}
+
+SvxUnoDrawingModel::SvxUnoDrawingModel(SdrModel* pDoc) noexcept
+: SfxBaseModel(nullptr),
+ mpDoc(pDoc)
+{
+}
+
+SvxUnoDrawingModel::~SvxUnoDrawingModel() noexcept
+{
+}
+
+uno::Any SAL_CALL SvxUnoDrawingModel::queryInterface( const uno::Type & rType )
+{
+ uno::Any aAny;
+
+ QUERYINT(lang::XServiceInfo);
+ else QUERYINT(lang::XMultiServiceFactory);
+ else QUERYINT(drawing::XDrawPagesSupplier);
+ else QUERYINT(css::ucb::XAnyCompareFactory);
+ else
+ return SfxBaseModel::queryInterface( rType );
+
+ return aAny;
+}
+
+// XTypeProvider
+uno::Sequence< uno::Type > SAL_CALL SvxUnoDrawingModel::getTypes( )
+{
+ if( !maTypeSequence.hasElements() )
+ {
+ maTypeSequence = comphelper::concatSequences( SfxBaseModel::getTypes(),
+ uno::Sequence {
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XMultiServiceFactory>::get(),
+ cppu::UnoType<drawing::XDrawPagesSupplier>::get(),
+ cppu::UnoType<css::ucb::XAnyCompareFactory>::get() });
+ }
+ return maTypeSequence;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL SvxUnoDrawingModel::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void SAL_CALL SvxUnoDrawingModel::lockControllers( )
+{
+ if( mpDoc )
+ mpDoc->setLock(true);
+}
+
+void SAL_CALL SvxUnoDrawingModel::unlockControllers( )
+{
+ if( mpDoc && mpDoc->isLocked() )
+ {
+ mpDoc->setLock(false);
+ }
+}
+
+sal_Bool SAL_CALL SvxUnoDrawingModel::hasControllersLocked( )
+{
+ return mpDoc && mpDoc->isLocked();
+}
+
+// XDrawPagesSupplier
+uno::Reference< drawing::XDrawPages > SAL_CALL SvxUnoDrawingModel::getDrawPages()
+{
+ ::SolarMutexGuard aGuard;
+
+ uno::Reference< drawing::XDrawPages > xDrawPages( mxDrawPagesAccess );
+
+ if( !xDrawPages.is() )
+ mxDrawPagesAccess = xDrawPages = new SvxUnoDrawPagesAccess(*this);
+
+ return xDrawPages;
+}
+
+// XMultiServiceFactory ( SvxFmMSFactory )
+uno::Reference< uno::XInterface > SAL_CALL SvxUnoDrawingModel::createInstance( const OUString& aServiceSpecifier )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( aServiceSpecifier == "com.sun.star.drawing.DashTable" )
+ {
+ if( !mxDashTable.is() )
+ mxDashTable = SvxUnoDashTable_createInstance( mpDoc );
+ return mxDashTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.GradientTable" )
+ {
+ if( !mxGradientTable.is() )
+ mxGradientTable = SvxUnoGradientTable_createInstance( mpDoc );
+ return mxGradientTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.HatchTable" )
+ {
+ if( !mxHatchTable.is() )
+ mxHatchTable = SvxUnoHatchTable_createInstance( mpDoc );
+ return mxHatchTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.BitmapTable" )
+ {
+ if( !mxBitmapTable.is() )
+ mxBitmapTable = SvxUnoBitmapTable_createInstance( mpDoc );
+ return mxBitmapTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.TransparencyGradientTable" )
+ {
+ if( !mxTransGradientTable.is() )
+ mxTransGradientTable = SvxUnoTransGradientTable_createInstance( mpDoc );
+ return mxTransGradientTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.drawing.MarkerTable" )
+ {
+ if( !mxMarkerTable.is() )
+ mxMarkerTable = SvxUnoMarkerTable_createInstance( mpDoc );
+ return mxMarkerTable;
+ }
+ if( aServiceSpecifier == "com.sun.star.text.NumberingRules" )
+ {
+ return uno::Reference< uno::XInterface >( SvxCreateNumRule( mpDoc ), uno::UNO_QUERY );
+ }
+
+ if ( aServiceSpecifier == "com.sun.star.image.ImageMapRectangleObject" )
+ {
+ return SvUnoImageMapRectangleObject_createInstance( ImplGetSupportedMacroItems() );
+ }
+
+ if ( aServiceSpecifier == "com.sun.star.image.ImageMapCircleObject" )
+ {
+ return SvUnoImageMapCircleObject_createInstance( ImplGetSupportedMacroItems() );
+ }
+
+ if ( aServiceSpecifier == "com.sun.star.image.ImageMapPolygonObject" )
+ {
+ return SvUnoImageMapPolygonObject_createInstance( ImplGetSupportedMacroItems() );
+ }
+
+ if( aServiceSpecifier == "com.sun.star.text.TextField.DateTime" )
+ {
+ return static_cast<cppu::OWeakObject *>(new SvxUnoTextField(text::textfield::Type::DATE));
+ }
+
+ uno::Reference< uno::XInterface > xRet;
+
+ static const OUStringLiteral aPackagePrefix( u"com.sun.star.presentation." );
+ if( aServiceSpecifier.startsWith( aPackagePrefix ) )
+ {
+ SvxShape* pShape = nullptr;
+
+ SdrObjKind nType = SdrObjKind::Text;
+ std::u16string_view aTypeName = aServiceSpecifier.subView( aPackagePrefix.getLength() );
+ // create a shape wrapper
+ if( o3tl::starts_with(aTypeName, u"TitleTextShape") )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aTypeName, u"OutlinerShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aTypeName, u"SubtitleShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aTypeName, u"GraphicObjectShape" ) )
+ {
+ nType = SdrObjKind::Graphic;
+ }
+ else if( o3tl::starts_with(aTypeName, u"PageShape" ) )
+ {
+ nType = SdrObjKind::Page;
+ }
+ else if( o3tl::starts_with(aTypeName, u"OLE2Shape" ) )
+ {
+ nType = SdrObjKind::OLE2;
+ }
+ else if( o3tl::starts_with(aTypeName, u"ChartShape" ) )
+ {
+ nType = SdrObjKind::OLE2;
+ }
+ else if( o3tl::starts_with(aTypeName, u"OrgChartShape" ) )
+ {
+ nType = SdrObjKind::OLE2;
+ }
+ else if( o3tl::starts_with(aTypeName, u"NotesShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aTypeName, u"HandoutShape" ) )
+ {
+ nType = SdrObjKind::Page;
+ }
+ else if( o3tl::starts_with(aTypeName, u"FooterShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aTypeName, u"HeaderShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aTypeName, u"SlideNumberShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aTypeName, u"DateTimeShape" ) )
+ {
+ nType = SdrObjKind::Text;
+ }
+ else if( o3tl::starts_with(aTypeName, u"TableShape" ) )
+ {
+ nType = SdrObjKind::Table;
+ }
+ else
+ {
+ throw lang::ServiceNotRegisteredException();
+ }
+
+ // create the API wrapper
+ rtl::Reference<SvxShape> xNewShape = CreateSvxShapeByTypeAndInventor( nType, SdrInventor::Default, "" );
+ pShape = xNewShape.get();
+
+ // set shape type
+ if( pShape )
+ pShape->SetShapeType(aServiceSpecifier);
+
+ xRet = static_cast<uno::XWeak*>(pShape);
+ }
+ else
+ {
+ xRet = SvxFmMSFactory::createInstance( aServiceSpecifier );
+ }
+
+ return xRet;
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoDrawingModel::getAvailableServiceNames()
+{
+ const uno::Sequence< OUString > aSNS_ORG( SvxFmMSFactory::getAvailableServiceNames() );
+
+ uno::Sequence< OUString > aSNS{
+ "com.sun.star.drawing.DashTable",
+ "com.sun.star.drawing.GradientTable",
+ "com.sun.star.drawing.HatchTable",
+ "com.sun.star.drawing.BitmapTable",
+ "com.sun.star.drawing.TransparencyGradientTable",
+ "com.sun.star.drawing.MarkerTable",
+ "com.sun.star.text.NumberingRules",
+ "com.sun.star.image.ImageMapRectangleObject",
+ "com.sun.star.image.ImageMapCircleObject",
+ "com.sun.star.image.ImageMapPolygonObject",
+
+ "com.sun.star.presentation.TitleTextShape",
+ "com.sun.star.presentation.OutlinerShape",
+ "com.sun.star.presentation.SubtitleShape",
+ "com.sun.star.presentation.GraphicObjectShape",
+ "com.sun.star.presentation.ChartShape",
+ "com.sun.star.presentation.PageShape",
+ "com.sun.star.presentation.OLE2Shape",
+ "com.sun.star.presentation.TableShape",
+ "com.sun.star.presentation.OrgChartShape",
+ "com.sun.star.presentation.NotesShape",
+ "com.sun.star.presentation.HandoutShape"
+ };
+
+ return comphelper::concatSequences( aSNS_ORG, aSNS );
+}
+
+// lang::XServiceInfo
+OUString SAL_CALL SvxUnoDrawingModel::getImplementationName()
+{
+ return "SvxUnoDrawingModel";
+}
+
+sal_Bool SAL_CALL SvxUnoDrawingModel::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoDrawingModel::getSupportedServiceNames()
+{
+ return { "com.sun.star.drawing.DrawingDocument" };
+}
+
+// XAnyCompareFactory
+uno::Reference< css::ucb::XAnyCompare > SAL_CALL SvxUnoDrawingModel::createAnyCompareByName( const OUString& )
+{
+ return SvxCreateNumRuleCompare();
+}
+
+SvxUnoDrawPagesAccess::SvxUnoDrawPagesAccess( SvxUnoDrawingModel& rMyModel ) noexcept
+: mrModel(rMyModel)
+{
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL SvxUnoDrawPagesAccess::getCount()
+{
+ ::SolarMutexGuard aGuard;
+
+ sal_Int32 nCount = 0;
+
+ if( mrModel.mpDoc )
+ nCount = mrModel.mpDoc->GetPageCount();
+
+ return nCount;
+}
+
+uno::Any SAL_CALL SvxUnoDrawPagesAccess::getByIndex( sal_Int32 Index )
+{
+ ::SolarMutexGuard aGuard;
+
+ uno::Any aAny;
+
+ if( mrModel.mpDoc )
+ {
+ if( (Index < 0) || (Index >= mrModel.mpDoc->GetPageCount() ) )
+ throw lang::IndexOutOfBoundsException();
+
+ SdrPage* pPage = mrModel.mpDoc->GetPage( static_cast<sal_uInt16>(Index) );
+ if( pPage )
+ {
+ uno::Reference< uno::XInterface > xPage( pPage->mxUnoPage );
+
+ if( !xPage.is() )
+ {
+ if( dynamic_cast<FmFormModel*>( mrModel.mpDoc ) )
+ xPage = static_cast<drawing::XDrawPage*>(new SvxFmDrawPage( pPage ));
+ else
+ xPage = static_cast<drawing::XDrawPage*>(new SvxDrawPage( pPage ));
+
+ pPage->mxUnoPage = xPage;
+ }
+
+ aAny <<= xPage;
+ }
+ }
+ return aAny;
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoDrawPagesAccess::getElementType()
+{
+ return cppu::UnoType<drawing::XDrawPage>::get();
+}
+
+sal_Bool SAL_CALL SvxUnoDrawPagesAccess::hasElements()
+{
+ return getCount() > 0;
+}
+
+// XDrawPages
+
+// create a new page with model at given position
+// and return corresponding SdDrawPage
+uno::Reference< drawing::XDrawPage > SAL_CALL SvxUnoDrawPagesAccess::insertNewByIndex( sal_Int32 nIndex )
+{
+ ::SolarMutexGuard aGuard;
+
+ uno::Reference< drawing::XDrawPage > xDrawPage;
+
+ if( mrModel.mpDoc )
+ {
+ rtl::Reference<SdrPage> pPage;
+
+ if( auto pFormModel = dynamic_cast<FmFormModel*>( mrModel.mpDoc ) )
+ pPage = new FmFormPage(*pFormModel);
+ else
+ pPage = new SdrPage(*mrModel.mpDoc);
+
+ mrModel.mpDoc->InsertPage( pPage.get(), static_cast<sal_uInt16>(nIndex) );
+ xDrawPage.set( pPage->getUnoPage(), uno::UNO_QUERY );
+ }
+
+ return xDrawPage;
+}
+
+void SAL_CALL SvxUnoDrawPagesAccess::remove( const uno::Reference< drawing::XDrawPage >& xPage )
+{
+ ::SolarMutexGuard aGuard;
+
+ sal_uInt16 nPageCount = mrModel.mpDoc->GetPageCount();
+ if( nPageCount <= 1 )
+ return;
+
+ // get pPage from xPage and get Id (nPos)
+ SvxDrawPage* pSvxPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
+ if( pSvxPage )
+ {
+ SdrPage* pPage = pSvxPage->GetSdrPage();
+ if(pPage)
+ {
+ sal_uInt16 nPage = pPage->GetPageNum();
+ mrModel.mpDoc->DeletePage( nPage );
+ }
+ }
+}
+
+// XServiceInfo
+
+OUString SAL_CALL SvxUnoDrawPagesAccess::getImplementationName( )
+{
+ return "SvxUnoDrawPagesAccess";
+}
+
+sal_Bool SAL_CALL SvxUnoDrawPagesAccess::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoDrawPagesAccess::getSupportedServiceNames( )
+{
+ return { "com.sun.star.drawing.DrawPages" };
+}
+
+css::uno::Reference< css::container::XIndexReplace > SvxCreateNumRule(SdrModel* pModel)
+{
+ const SvxNumRule* pDefaultRule = nullptr;
+ if( pModel )
+ {
+ const SvxNumBulletItem* pItem = pModel->GetItemPool().GetSecondaryPool()->GetPoolDefaultItem(EE_PARA_NUMBULLET);
+ if( pItem )
+ {
+ pDefaultRule = &pItem->GetNumRule();
+ }
+ }
+
+ if( pDefaultRule )
+ {
+ return SvxCreateNumRule( *pDefaultRule );
+ }
+ else
+ {
+ SvxNumRule aTempRule( SvxNumRuleFlags::NONE, 10, false );
+ return SvxCreateNumRule( aTempRule );
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unomtabl.cxx b/svx/source/unodraw/unomtabl.cxx
new file mode 100644
index 000000000..60b858f38
--- /dev/null
+++ b/svx/source/unodraw/unomtabl.cxx
@@ -0,0 +1,423 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+#include <set>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/drawing/PointSequence.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <svl/lstner.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/xdef.hxx>
+
+#include <vector>
+#include <vcl/svapp.hxx>
+
+
+#include <svx/unofill.hxx>
+
+#include <svx/unoapi.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::cppu;
+
+typedef std::vector<std::unique_ptr<SfxItemSet>> ItemPoolVector;
+
+namespace {
+
+class SvxUnoMarkerTable
+ : public WeakImplHelper<
+ util::XCancellable,
+ container::XNameContainer,
+ lang::XServiceInfo>
+ , public SfxListener
+{
+private:
+ SdrModel* mpModel;
+ SfxItemPool* mpModelPool;
+
+ ItemPoolVector maItemSetVector;
+
+public:
+ explicit SvxUnoMarkerTable( SdrModel* pModel ) noexcept;
+ virtual ~SvxUnoMarkerTable() noexcept override;
+
+ void dispose();
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) noexcept override;
+
+ void ImplInsertByName( const OUString& aName, const uno::Any& aElement );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XCancellable
+ virtual void SAL_CALL cancel() override;
+
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& Name ) override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override;
+
+ // XNameAccess
+ virtual uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+};
+
+}
+
+SvxUnoMarkerTable::SvxUnoMarkerTable( SdrModel* pModel ) noexcept
+: mpModel( pModel ),
+ mpModelPool( pModel ? &pModel->GetItemPool() : nullptr )
+{
+ if( pModel )
+ StartListening( *pModel );
+}
+
+SvxUnoMarkerTable::~SvxUnoMarkerTable() noexcept
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel )
+ EndListening( *mpModel );
+ dispose();
+}
+
+void SvxUnoMarkerTable::dispose()
+{
+ maItemSetVector.clear();
+}
+
+// SfxListener
+void SvxUnoMarkerTable::Notify( SfxBroadcaster&, const SfxHint& rHint ) noexcept
+{
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ if( SdrHintKind::ModelCleared == pSdrHint->GetKind() )
+ dispose();
+ }
+}
+
+sal_Bool SAL_CALL SvxUnoMarkerTable::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+OUString SAL_CALL SvxUnoMarkerTable::getImplementationName()
+{
+ return "SvxUnoMarkerTable";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoMarkerTable::getSupportedServiceNames( )
+{
+ uno::Sequence<OUString> aSNS { "com.sun.star.drawing.MarkerTable" };
+ return aSNS;
+}
+
+void SvxUnoMarkerTable::ImplInsertByName( const OUString& aName, const uno::Any& aElement )
+{
+ maItemSetVector.push_back(
+ std::make_unique<SfxItemSetFixed<XATTR_LINESTART, XATTR_LINEEND>>( *mpModelPool ));
+ auto pInSet = maItemSetVector.back().get();
+
+ XLineEndItem aEndMarker(XATTR_LINEEND);
+ aEndMarker.SetName( aName );
+ aEndMarker.PutValue( aElement, 0 );
+
+ pInSet->Put( aEndMarker );
+
+ XLineStartItem aStartMarker(XATTR_LINESTART);
+ aStartMarker.SetName( aName );
+ aStartMarker.PutValue( aElement, 0 );
+
+ pInSet->Put( aStartMarker );
+}
+
+// XNameContainer
+void SAL_CALL SvxUnoMarkerTable::insertByName( const OUString& aApiName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+
+ if( hasByName( aApiName ) )
+ throw container::ElementExistException();
+
+ OUString aName = SvxUnogetInternalNameForItem(XATTR_LINEEND, aApiName);
+
+ ImplInsertByName( aName, aElement );
+}
+
+void SAL_CALL SvxUnoMarkerTable::cancel()
+{
+ SolarMutexGuard aGuard;
+ // drop all items that are owned by this service and not the document
+ // (i.e. they are unused)
+ dispose();
+}
+
+void SAL_CALL SvxUnoMarkerTable::removeByName( const OUString& aApiName )
+{
+ SolarMutexGuard aGuard;
+
+ OUString aName = SvxUnogetInternalNameForItem(XATTR_LINEEND, aApiName);
+
+ auto aIter = std::find_if(maItemSetVector.begin(), maItemSetVector.end(),
+ [&aName](const std::unique_ptr<SfxItemSet>& rpItem) {
+ const NameOrIndex *pItem = &(rpItem->Get( XATTR_LINEEND ) );
+ return pItem->GetName() == aName;
+ });
+ if (aIter != maItemSetVector.end())
+ {
+ maItemSetVector.erase( aIter );
+ return;
+ }
+
+ if( !hasByName( aName ) )
+ throw container::NoSuchElementException();
+}
+
+// XNameReplace
+void SAL_CALL SvxUnoMarkerTable::replaceByName( const OUString& aApiName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+
+ const OUString aName = SvxUnogetInternalNameForItem(XATTR_LINEEND, aApiName);
+
+ auto aIter = std::find_if(maItemSetVector.begin(), maItemSetVector.end(),
+ [&aName](const std::unique_ptr<SfxItemSet>& rpItem) {
+ const NameOrIndex *pItem = &(rpItem->Get( XATTR_LINEEND ) );
+ return pItem->GetName() == aName;
+ });
+ if (aIter != maItemSetVector.end())
+ {
+ XLineEndItem aEndMarker(XATTR_LINEEND);
+ aEndMarker.SetName( aName );
+ if( !aEndMarker.PutValue( aElement, 0 ) )
+ throw lang::IllegalArgumentException();
+
+ (*aIter)->Put( aEndMarker );
+
+ XLineStartItem aStartMarker(XATTR_LINESTART);
+ aStartMarker.SetName( aName );
+ aStartMarker.PutValue( aElement, 0 );
+
+ (*aIter)->Put( aStartMarker );
+ return;
+ }
+
+ // if it is not in our own sets, modify the pool!
+ bool bFound = false;
+
+ if (mpModelPool)
+ for (const SfxPoolItem* p : mpModelPool->GetItemSurrogates(XATTR_LINESTART))
+ {
+ NameOrIndex *pItem = const_cast<NameOrIndex*>(static_cast<const NameOrIndex*>(p));
+ if( pItem && pItem->GetName() == aName )
+ {
+ pItem->PutValue( aElement, 0 );
+ bFound = true;
+ break;
+ }
+ }
+
+ if (mpModelPool)
+ for (const SfxPoolItem* p : mpModelPool->GetItemSurrogates(XATTR_LINEEND))
+ {
+ NameOrIndex *pItem = const_cast<NameOrIndex*>(static_cast<const NameOrIndex*>(p));
+ if( pItem && pItem->GetName() == aName )
+ {
+ pItem->PutValue( aElement, 0 );
+ bFound = true;
+ break;
+ }
+ }
+
+ if( !bFound )
+ throw container::NoSuchElementException();
+
+ ImplInsertByName( aName, aElement );
+}
+
+static bool getByNameFromPool( std::u16string_view rSearchName, SfxItemPool const * pPool, sal_uInt16 nWhich, uno::Any& rAny )
+{
+ if (pPool)
+ for (const SfxPoolItem* p : pPool->GetItemSurrogates(nWhich))
+ {
+ const NameOrIndex *pItem = static_cast<const NameOrIndex*>(p);
+
+ if( pItem && pItem->GetName() == rSearchName )
+ {
+ pItem->QueryValue( rAny );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// XNameAccess
+uno::Any SAL_CALL SvxUnoMarkerTable::getByName( const OUString& aApiName )
+{
+ SolarMutexGuard aGuard;
+
+ OUString aName = SvxUnogetInternalNameForItem(XATTR_LINEEND, aApiName);
+
+ uno::Any aAny;
+
+ if (mpModelPool && !aName.isEmpty())
+ {
+ do
+ {
+ if (getByNameFromPool(aName, mpModelPool, XATTR_LINESTART, aAny))
+ break;
+
+ if (getByNameFromPool(aName, mpModelPool, XATTR_LINEEND, aAny))
+ break;
+
+ throw container::NoSuchElementException();
+ }
+ while(false);
+ }
+
+ return aAny;
+}
+
+static void createNamesForPool( SfxItemPool const * pPool, sal_uInt16 nWhich, std::set< OUString >& rNameSet )
+{
+ for (const SfxPoolItem* p : pPool->GetItemSurrogates(nWhich))
+ {
+ const NameOrIndex* pItem = static_cast<const NameOrIndex*>(p);
+
+ if( pItem == nullptr || pItem->GetName().isEmpty() )
+ continue;
+
+ OUString aName = SvxUnogetApiNameForItem(XATTR_LINEEND, pItem->GetName());
+ rNameSet.insert( aName );
+ }
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoMarkerTable::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ std::set< OUString > aNameSet;
+
+ // search model pool for line starts
+ createNamesForPool( mpModelPool, XATTR_LINESTART, aNameSet );
+
+ // search model pool for line ends
+ createNamesForPool( mpModelPool, XATTR_LINEEND, aNameSet );
+
+ return comphelper::containerToSequence(aNameSet);
+}
+
+sal_Bool SAL_CALL SvxUnoMarkerTable::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ if( aName.isEmpty() )
+ return false;
+
+ OUString aSearchName;
+
+ const NameOrIndex *pItem;
+
+ aSearchName = SvxUnogetInternalNameForItem(XATTR_LINESTART, aName);
+ if (mpModelPool)
+ for (const SfxPoolItem* p : mpModelPool->GetItemSurrogates(XATTR_LINESTART))
+ {
+ pItem = static_cast<const NameOrIndex*>(p);
+ if( pItem && pItem->GetName() == aSearchName )
+ return true;
+ }
+
+ aSearchName = SvxUnogetInternalNameForItem(XATTR_LINEEND, aName);
+ if (mpModelPool)
+ for (const SfxPoolItem* p : mpModelPool->GetItemSurrogates(XATTR_LINEEND))
+ {
+ pItem = static_cast<const NameOrIndex*>(p);
+ if( pItem && pItem->GetName() == aSearchName )
+ return true;
+ }
+
+ return false;
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoMarkerTable::getElementType( )
+{
+ return cppu::UnoType<drawing::PointSequence>::get();
+}
+
+sal_Bool SAL_CALL SvxUnoMarkerTable::hasElements( )
+{
+ SolarMutexGuard aGuard;
+
+ const NameOrIndex *pItem;
+
+ if (mpModelPool)
+ for (const SfxPoolItem* p : mpModelPool->GetItemSurrogates(XATTR_LINESTART))
+ {
+ pItem = static_cast<const NameOrIndex*>(p);
+ if( pItem && !pItem->GetName().isEmpty() )
+ return true;
+ }
+
+ if (mpModelPool)
+ for (const SfxPoolItem* p : mpModelPool->GetItemSurrogates(XATTR_LINEEND))
+ {
+ pItem = static_cast<const NameOrIndex*>(p);
+ if( pItem && !pItem->GetName().isEmpty() )
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Create a hatchtable
+ */
+uno::Reference< uno::XInterface > SvxUnoMarkerTable_createInstance( SdrModel* pModel )
+{
+ return *new SvxUnoMarkerTable(pModel);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unopage.cxx b/svx/source/unodraw/unopage.cxx
new file mode 100644
index 000000000..ee91c36c9
--- /dev/null
+++ b/svx/source/unodraw/unopage.cxx
@@ -0,0 +1,898 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <com/sun/star/document/EventObject.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <o3tl/safeint.hxx>
+#include <osl/mutex.hxx>
+#include <comphelper/classids.hxx>
+#include <comphelper/embeddedobjectcontainer.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <svx/svdpool.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdview.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/unopage.hxx>
+#include "shapeimpl.hxx"
+#include <svx/unodraw/SvxTableShape.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdobjkind.hxx>
+#include <svx/unoprov.hxx>
+#include <svx/unoapi.hxx>
+#include <extrud3d.hxx>
+#include <svx/lathe3d.hxx>
+#include <svx/scene3d.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/globname.hxx>
+#include <sal/log.hxx>
+
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::drawing;
+
+UNO3_GETIMPLEMENTATION_IMPL( SvxDrawPage );
+
+SvxDrawPage::SvxDrawPage(SdrPage* pInPage) // TTTT should be reference
+: mrBHelper(m_aMutex)
+ ,mpPage(pInPage)
+ ,mpModel(&pInPage->getSdrModelFromSdrPage()) // register at broadcaster
+ ,mpView(new SdrView(pInPage->getSdrModelFromSdrPage())) // create (hidden) view
+{
+ mpView->SetDesignMode();
+}
+
+SvxDrawPage::~SvxDrawPage() noexcept
+{
+ if( !mrBHelper.bDisposed )
+ {
+ assert(!"SvxDrawPage must be disposed!");
+ acquire();
+ dispose();
+ }
+}
+
+// XInterface
+void SvxDrawPage::release() noexcept
+{
+ OWeakAggObject::release();
+}
+
+// XComponent
+void SvxDrawPage::disposing() noexcept
+{
+ if( mpModel )
+ {
+ mpModel = nullptr;
+ }
+
+ mpView.reset();
+ mpPage = nullptr;
+}
+
+// XComponent
+void SvxDrawPage::dispose()
+{
+ SolarMutexGuard aSolarGuard;
+
+ // An frequently programming error is to release the last
+ // reference to this object in the disposing message.
+ // Make it robust, hold a self Reference.
+ uno::Reference< lang::XComponent > xSelf( this );
+
+ // Guard dispose against multiple threading
+ // Remark: It is an error to call dispose more than once
+ bool bDoDispose = false;
+ {
+ osl::MutexGuard aGuard( mrBHelper.rMutex );
+ if( !mrBHelper.bDisposed && !mrBHelper.bInDispose )
+ {
+ // only one call go into this section
+ mrBHelper.bInDispose = true;
+ bDoDispose = true;
+ }
+ }
+
+ // Do not hold the mutex because we are broadcasting
+ if( !bDoDispose )
+ return;
+
+ // Create an event with this as sender
+ try
+ {
+ uno::Reference< uno::XInterface > xSource( uno::Reference< uno::XInterface >::query( static_cast<lang::XComponent *>(this) ) );
+ css::document::EventObject aEvt;
+ aEvt.Source = xSource;
+ // inform all listeners to release this object
+ // The listener container are automatically cleared
+ mrBHelper.aLC.disposeAndClear( aEvt );
+ // notify subclasses to do their dispose
+ disposing();
+ }
+ catch(const css::uno::Exception&)
+ {
+ // catch exception and throw again but signal that
+ // the object was disposed. Dispose should be called
+ // only once.
+ osl::MutexGuard aGuard( mrBHelper.rMutex );
+ mrBHelper.bDisposed = true;
+ mrBHelper.bInDispose = false;
+ throw;
+ }
+
+ osl::MutexGuard aGuard( mrBHelper.rMutex );
+ mrBHelper.bDisposed = true;
+ mrBHelper.bInDispose = false;
+
+}
+
+void SAL_CALL SvxDrawPage::addEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel == nullptr )
+ throw lang::DisposedException();
+
+ mrBHelper.addListener( cppu::UnoType<decltype(aListener)>::get() , aListener );
+}
+
+void SAL_CALL SvxDrawPage::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ if( mpModel == nullptr )
+ throw lang::DisposedException();
+
+ mrBHelper.removeListener( cppu::UnoType<decltype(aListener)>::get() , aListener );
+}
+
+void SAL_CALL SvxDrawPage::add( const uno::Reference< drawing::XShape >& xShape )
+{
+ SolarMutexGuard aGuard;
+
+ if ( ( mpModel == nullptr ) || ( mpPage == nullptr ) )
+ throw lang::DisposedException();
+
+ SvxShape* pShape = comphelper::getFromUnoTunnel<SvxShape>( xShape );
+
+ if( nullptr == pShape )
+ return;
+
+ SdrObject *pObj = pShape->GetSdrObject();
+ bool bNeededToClone(false);
+
+ if(nullptr != pObj && &pObj->getSdrModelFromSdrObject() != &mpPage->getSdrModelFromSdrPage())
+ {
+ // TTTT UNO API tries to add an existing SvxShape to this SvxDrawPage,
+ // but these use different SdrModels. It was possible before to completely
+ // 'change' a SdrObject to another SdrModel (including dangerous MigrateItemPool
+ // stuff), but is no longer. We need to Clone the SdrObject to the target model
+ // and ::Create a new SvxShape (set SdrObject there, take obver values, ...)
+ SdrObject* pClonedSdrShape(pObj->CloneSdrObject(mpPage->getSdrModelFromSdrPage()));
+ pObj->setUnoShape(nullptr);
+ pClonedSdrShape->setUnoShape(xShape);
+ // pShape->InvalidateSdrObject();
+ // pShape->Create(pClonedSdrShape, this);
+ SdrObject::Free(pObj);
+ pObj = pClonedSdrShape;
+ bNeededToClone = true;
+ }
+
+ if(!pObj)
+ {
+ pObj = CreateSdrObject( xShape );
+ ENSURE_OR_RETURN_VOID( pObj != nullptr, "SvxDrawPage::add: no SdrObject was created!" );
+ }
+ else if ( !pObj->IsInserted() )
+ {
+ mpPage->InsertObject( pObj );
+
+ if(bNeededToClone)
+ {
+ // TTTT Unfortunately in SdrObject::SetPage (see there) the
+ // xShape/UnoShape at the newly cloned SDrObject is *removed* again,
+ // so re-set it here, the caller *may need it* (e.g. Writer)
+ uno::Reference< uno::XInterface > xShapeCheck(pObj->getWeakUnoShape());
+
+ if( !xShapeCheck.is() )
+ {
+ pObj->setUnoShape(xShape);
+ }
+ }
+ }
+
+ pShape->Create( pObj, this );
+ OSL_ENSURE( pShape->GetSdrObject() == pObj, "SvxDrawPage::add: shape does not know about its newly created SdrObject!" );
+
+ if ( !pObj->IsInserted() )
+ {
+ mpPage->InsertObject( pObj );
+ }
+
+ mpModel->SetChanged();
+}
+
+void SAL_CALL SvxDrawPage::addTop( const uno::Reference< drawing::XShape >& xShape )
+{
+ add(xShape);
+}
+
+void SAL_CALL SvxDrawPage::addBottom( const uno::Reference< drawing::XShape >& xShape )
+{
+ SolarMutexGuard aGuard;
+
+ if ( ( mpModel == nullptr ) || ( mpPage == nullptr ) )
+ throw lang::DisposedException();
+
+ SvxShape* pShape = comphelper::getFromUnoTunnel<SvxShape>( xShape );
+
+ if( nullptr == pShape )
+ return;
+
+ SdrObject *pObj = pShape->GetSdrObject();
+
+ if(!pObj)
+ {
+ pObj = CreateSdrObject( xShape, true );
+ ENSURE_OR_RETURN_VOID( pObj != nullptr, "SvxDrawPage::add: no SdrObject was created!" );
+ }
+ else if ( !pObj->IsInserted() )
+ {
+ mpPage->InsertObject( pObj, 0 );
+ }
+
+ pShape->Create( pObj, this );
+ OSL_ENSURE( pShape->GetSdrObject() == pObj, "SvxDrawPage::add: shape does not know about its newly created SdrObject!" );
+
+ if ( !pObj->IsInserted() )
+ {
+ mpPage->InsertObject( pObj, 0 );
+ }
+
+ mpModel->SetChanged();
+}
+
+void SAL_CALL SvxDrawPage::remove( const Reference< drawing::XShape >& xShape )
+{
+ SolarMutexGuard aGuard;
+
+ if( (mpModel == nullptr) || (mpPage == nullptr) )
+ throw lang::DisposedException();
+
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape( xShape );
+ if (!pObj)
+ return;
+
+ // remove SdrObject from page
+ const size_t nCount = mpPage->GetObjCount();
+ for( size_t nNum = 0; nNum < nCount; ++nNum )
+ {
+ if(mpPage->GetObj(nNum) == pObj)
+ {
+ const bool bUndoEnabled = mpModel->IsUndoEnabled();
+
+ if (bUndoEnabled)
+ {
+ mpModel->BegUndo(SvxResId(STR_EditDelete),
+ pObj->TakeObjNameSingul(), SdrRepeatFunc::Delete);
+
+ mpModel->AddUndo(mpModel->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
+ }
+
+ OSL_VERIFY( mpPage->RemoveObject( nNum ) == pObj );
+
+ if (!bUndoEnabled)
+ SdrObject::Free(pObj);
+
+ if (bUndoEnabled)
+ mpModel->EndUndo();
+
+ break;
+ }
+ }
+
+ mpModel->SetChanged();
+}
+
+void SvxDrawPage::sort( const css::uno::Sequence< sal_Int32 >& sortOrder )
+{
+ SolarMutexGuard aGuard;
+
+ if ((mpModel == nullptr) || (mpPage == nullptr))
+ throw lang::DisposedException();
+
+ auto newOrder = comphelper::sequenceToContainer<std::vector<sal_Int32>>(sortOrder);
+ mpPage->sort(newOrder);
+}
+
+// css::container::XIndexAccess
+sal_Int32 SAL_CALL SvxDrawPage::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ if( (mpModel == nullptr) || (mpPage == nullptr) )
+ throw lang::DisposedException();
+
+ return static_cast<sal_Int32>( mpPage->GetObjCount() );
+}
+
+uno::Any SAL_CALL SvxDrawPage::getByIndex( sal_Int32 Index )
+{
+ SolarMutexGuard aGuard;
+
+ if( (mpModel == nullptr) || (mpPage == nullptr) )
+ throw lang::DisposedException("Model or Page was already disposed!");
+
+ if ( Index < 0 || o3tl::make_unsigned(Index) >= mpPage->GetObjCount() )
+ throw lang::IndexOutOfBoundsException("Index (" + OUString::number(Index)
+ + ") needs to be a positive integer smaller than the shape count ("
+ + OUString::number(mpPage->GetObjCount()) + ")!");
+
+ SdrObject* pObj = mpPage->GetObj( Index );
+ if( pObj == nullptr )
+ throw uno::RuntimeException("Runtime exception thrown while getting a ref to the SdrObject at index: "
+ + OUString::number(Index));
+
+
+ return Any(Reference< drawing::XShape >( pObj->getUnoShape(), uno::UNO_QUERY ));
+}
+
+// css::container::XElementAccess
+uno::Type SAL_CALL SvxDrawPage::getElementType()
+{
+ return cppu::UnoType<drawing::XShape>::get();
+}
+
+sal_Bool SAL_CALL SvxDrawPage::hasElements()
+{
+ SolarMutexGuard aGuard;
+
+ if( (mpModel == nullptr) || (mpPage == nullptr) )
+ throw lang::DisposedException();
+
+ return mpPage && mpPage->GetObjCount()>0;
+}
+
+namespace
+{
+ void lcl_markSdrObjectOfShape( const Reference< drawing::XShape >& _rxShape, SdrView& _rView, SdrPageView& _rPageView )
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape( _rxShape );
+ if ( !pObj )
+ return;
+
+ _rView.MarkObj( pObj, &_rPageView );
+ }
+}
+
+// ATTENTION: SelectObjectsInView selects the css::drawing::Shapes
+// only in the given SdrPageView. It hasn't to be the visible SdrPageView.
+void SvxDrawPage::SelectObjectsInView( const Reference< drawing::XShapes > & aShapes, SdrPageView* pPageView ) noexcept
+{
+ SAL_WARN_IF(!pPageView, "svx", "SdrPageView is NULL!");
+ SAL_WARN_IF(!mpView, "svx", "SdrView is NULL!");
+
+ if(pPageView==nullptr || mpView==nullptr)
+ return;
+
+ mpView->UnmarkAllObj( pPageView );
+
+ tools::Long nCount = aShapes->getCount();
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ uno::Any aAny( aShapes->getByIndex(i) );
+ Reference< drawing::XShape > xShape;
+ if( aAny >>= xShape )
+ lcl_markSdrObjectOfShape( xShape, *mpView, *pPageView );
+ }
+}
+
+// ATTENTION: SelectObjectInView selects the shape only in the given SdrPageView.
+// It hasn't to be the visible SdrPageView.
+void SvxDrawPage::SelectObjectInView( const Reference< drawing::XShape > & xShape, SdrPageView* pPageView ) noexcept
+{
+ SAL_WARN_IF(!pPageView, "svx", "SdrPageView is NULL!");
+ SAL_WARN_IF(!mpView, "svx", "SdrView is NULL!");
+
+ if(pPageView!=nullptr && mpView != nullptr)
+ {
+ mpView->UnmarkAllObj( pPageView );
+ lcl_markSdrObjectOfShape( xShape, *mpView, *pPageView );
+ }
+}
+
+Reference< drawing::XShapeGroup > SAL_CALL SvxDrawPage::group( const Reference< drawing::XShapes >& xShapes )
+{
+ SolarMutexGuard aGuard;
+
+ if( (mpModel == nullptr) || (mpPage == nullptr) )
+ throw lang::DisposedException();
+
+ SAL_WARN_IF(!mpPage , "svx", "SdrPage is NULL!");
+ SAL_WARN_IF(!mpView, "svx", "SdrView is NULL!");
+
+ Reference< css::drawing::XShapeGroup > xShapeGroup;
+ if(mpPage==nullptr||mpView==nullptr||!xShapes.is())
+ return xShapeGroup;
+
+ SdrPageView* pPageView = mpView->ShowSdrPage( mpPage );
+
+ SelectObjectsInView( xShapes, pPageView );
+
+ mpView->GroupMarked();
+
+ mpView->AdjustMarkHdl();
+ const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if( pObj )
+ xShapeGroup.set( pObj->getUnoShape(), UNO_QUERY );
+ }
+
+ mpView->HideSdrPage();
+
+ if( mpModel )
+ mpModel->SetChanged();
+
+ return xShapeGroup;
+}
+
+void SAL_CALL SvxDrawPage::ungroup( const Reference< drawing::XShapeGroup >& aGroup )
+{
+ SolarMutexGuard aGuard;
+
+ if( (mpModel == nullptr) || (mpPage == nullptr) )
+ throw lang::DisposedException();
+
+ SAL_WARN_IF(!mpPage, "svx", "SdrPage is NULL!");
+ SAL_WARN_IF(!mpView, "svx", "SdrView is NULL!");
+
+ if(mpPage==nullptr||mpView==nullptr||!aGroup.is())
+ return;
+
+ SdrPageView* pPageView = mpView->ShowSdrPage( mpPage );
+
+ SelectObjectInView( aGroup, pPageView );
+ mpView->UnGroupMarked();
+
+ mpView->HideSdrPage();
+
+ if( mpModel )
+ mpModel->SetChanged();
+}
+
+SdrObject* SvxDrawPage::CreateSdrObject_(const Reference< drawing::XShape > & xShape)
+{
+ SdrObjKind nType = SdrObjKind::NONE;
+ SdrInventor nInventor;
+
+ GetTypeAndInventor( nType, nInventor, xShape->getShapeType() );
+ if (nType == SdrObjKind::NONE)
+ return nullptr;
+
+ awt::Size aSize = xShape->getSize();
+ aSize.Width += 1;
+ aSize.Height += 1;
+ awt::Point aPos = xShape->getPosition();
+ tools::Rectangle aRect( Point( aPos.X, aPos.Y ), Size( aSize.Width, aSize.Height ) );
+
+ SdrObject* pNewObj = SdrObjFactory::MakeNewObject(
+ *mpModel,
+ nInventor,
+ nType,
+ &aRect);
+
+ if (!pNewObj)
+ return nullptr;
+
+ if( auto pScene = dynamic_cast<E3dScene* >(pNewObj) )
+ {
+ // initialise scene
+
+ double fW = static_cast<double>(aSize.Width);
+ double fH = static_cast<double>(aSize.Height);
+
+ Camera3D aCam(pScene->GetCamera());
+ aCam.SetAutoAdjustProjection(false);
+ aCam.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
+ basegfx::B3DPoint aLookAt;
+ basegfx::B3DPoint aCamPos(0.0, 0.0, 10000.0);
+ aCam.SetPosAndLookAt(aCamPos, aLookAt);
+ aCam.SetFocalLength(100.0);
+ pScene->SetCamera(aCam);
+
+ pScene->SetBoundAndSnapRectsDirty();
+ }
+ else if(auto pObj = dynamic_cast<E3dExtrudeObj* >(pNewObj))
+ {
+ basegfx::B2DPolygon aNewPolygon;
+ aNewPolygon.append(basegfx::B2DPoint(0.0, 0.0));
+ aNewPolygon.append(basegfx::B2DPoint(0.0, 1.0));
+ aNewPolygon.append(basegfx::B2DPoint(1.0, 0.0));
+ aNewPolygon.setClosed(true);
+ pObj->SetExtrudePolygon(basegfx::B2DPolyPolygon(aNewPolygon));
+
+ // #107245# pObj->SetExtrudeCharacterMode(sal_True);
+ pObj->SetMergedItem(Svx3DCharacterModeItem(true));
+ }
+ else if(auto pLatheObj = dynamic_cast<E3dLatheObj* >(pNewObj))
+ {
+ basegfx::B2DPolygon aNewPolygon;
+ aNewPolygon.append(basegfx::B2DPoint(0.0, 0.0));
+ aNewPolygon.append(basegfx::B2DPoint(0.0, 1.0));
+ aNewPolygon.append(basegfx::B2DPoint(1.0, 0.0));
+ aNewPolygon.setClosed(true);
+ pLatheObj->SetPolyPoly2D(basegfx::B2DPolyPolygon(aNewPolygon));
+
+ // #107245# pObj->SetLatheCharacterMode(sal_True);
+ pLatheObj->SetMergedItem(Svx3DCharacterModeItem(true));
+ }
+
+ return pNewObj;
+}
+
+void SvxDrawPage::GetTypeAndInventor( SdrObjKind& rType, SdrInventor& rInventor, const OUString& aName ) noexcept
+{
+ std::optional<SdrObjKind> nTempType = UHashMap::getId( aName );
+
+ if( !nTempType )
+ {
+ if( aName == "com.sun.star.drawing.TableShape" ||
+ aName == "com.sun.star.presentation.TableShape" )
+ {
+ rInventor = SdrInventor::Default;
+ rType = SdrObjKind::Table;
+ }
+#if HAVE_FEATURE_AVMEDIA
+ else if ( aName == "com.sun.star.presentation.MediaShape" )
+ {
+ rInventor = SdrInventor::Default;
+ rType = SdrObjKind::Media;
+ }
+#endif
+ }
+ else if( IsInventorE3D(*nTempType) )
+ {
+ rInventor = SdrInventor::E3d;
+ rType = *nTempType;
+ }
+ else
+ {
+ rInventor = SdrInventor::Default;
+ rType = *nTempType;
+
+ switch( rType )
+ {
+ case SdrObjKind::OLEPluginFrame:
+ case SdrObjKind::OLE2Plugin:
+ case SdrObjKind::OLE2Applet:
+ rType = SdrObjKind::OLE2;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+rtl::Reference<SvxShape> SvxDrawPage::CreateShapeByTypeAndInventor( SdrObjKind nType, SdrInventor nInventor, SdrObject *pObj, SvxDrawPage *mpPage, OUString const & referer )
+{
+ rtl::Reference<SvxShape> pRet;
+
+ switch( nInventor )
+ {
+ case SdrInventor::E3d:
+ {
+ switch( nType )
+ {
+ case SdrObjKind::E3D_Scene :
+ pRet = new Svx3DSceneObject( pObj, mpPage );
+ break;
+ case SdrObjKind::E3D_Cube :
+ pRet = new Svx3DCubeObject( pObj );
+ break;
+ case SdrObjKind::E3D_Sphere :
+ pRet = new Svx3DSphereObject( pObj );
+ break;
+ case SdrObjKind::E3D_Lathe :
+ pRet = new Svx3DLatheObject( pObj );
+ break;
+ case SdrObjKind::E3D_Extrusion :
+ pRet = new Svx3DExtrudeObject( pObj );
+ break;
+ case SdrObjKind::E3D_Polygon :
+ pRet = new Svx3DPolygonObject( pObj );
+ break;
+ default: // unknown 3D-object on page
+ assert(false && "the IsInventor3D function must be wrong");
+ pRet = new SvxShape( pObj );
+ break;
+ }
+ break;
+ }
+ case SdrInventor::Default:
+ {
+ switch( nType )
+ {
+ case SdrObjKind::Group:
+ pRet = new SvxShapeGroup( pObj, mpPage );
+ break;
+ case SdrObjKind::Line:
+ pRet = new SvxShapePolyPolygon( pObj );
+ break;
+ case SdrObjKind::Rectangle:
+ pRet = new SvxShapeRect( pObj );
+ break;
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::CircleSection:
+ case SdrObjKind::CircleArc:
+ case SdrObjKind::CircleCut:
+ pRet = new SvxShapeCircle( pObj );
+ break;
+ case SdrObjKind::Polygon:
+ pRet = new SvxShapePolyPolygon( pObj );
+ break;
+ case SdrObjKind::PolyLine:
+ pRet = new SvxShapePolyPolygon( pObj );
+ break;
+ case SdrObjKind::SplineLine:
+ case SdrObjKind::PathLine:
+ pRet = new SvxShapePolyPolygon( pObj );
+ break;
+ case SdrObjKind::SplineFill:
+ case SdrObjKind::PathFill:
+ pRet = new SvxShapePolyPolygon( pObj );
+ break;
+ case SdrObjKind::FreehandLine:
+ pRet = new SvxShapePolyPolygon( pObj );
+ break;
+ case SdrObjKind::FreehandFill:
+ pRet = new SvxShapePolyPolygon( pObj );
+ break;
+ case SdrObjKind::Caption:
+ pRet = new SvxShapeCaption( pObj );
+ break;
+ case SdrObjKind::TitleText:
+ case SdrObjKind::OutlineText:
+ case SdrObjKind::Text:
+ pRet = new SvxShapeText( pObj );
+ break;
+ case SdrObjKind::Graphic:
+ pRet = new SvxGraphicObject( pObj );
+ break;
+ case SdrObjKind::OLEPluginFrame:
+ pRet = new SvxFrameShape( pObj );
+ break;
+ case SdrObjKind::OLE2Applet:
+ pRet = new SvxAppletShape( pObj );
+ break;
+ case SdrObjKind::OLE2Plugin:
+ pRet = new SvxPluginShape( pObj );
+ break;
+ case SdrObjKind::OLE2:
+ {
+ if( pObj && !pObj->IsEmptyPresObj() && mpPage )
+ {
+ SdrPage* pSdrPage = mpPage->GetSdrPage();
+ if( pSdrPage )
+ {
+ SdrModel& rSdrModel(pSdrPage->getSdrModelFromSdrPage());
+ ::comphelper::IEmbeddedHelper *pPersist = rSdrModel.GetPersist();
+
+ if( pPersist )
+ {
+ uno::Reference < embed::XEmbeddedObject > xObject = pPersist->getEmbeddedObjectContainer().
+ GetEmbeddedObject( static_cast< SdrOle2Obj* >( pObj )->GetPersistName() );
+
+ // TODO CL->KA: Why is this not working anymore?
+ if( xObject.is() )
+ {
+ SvGlobalName aClassId( xObject->getClassID() );
+
+ const SvGlobalName aAppletClassId( SO3_APPLET_CLASSID );
+ const SvGlobalName aPluginClassId( SO3_PLUGIN_CLASSID );
+ const SvGlobalName aIFrameClassId( SO3_IFRAME_CLASSID );
+
+ if( aPluginClassId == aClassId )
+ {
+ pRet = new SvxPluginShape( pObj );
+ nType = SdrObjKind::OLE2Plugin;
+ }
+ else if( aAppletClassId == aClassId )
+ {
+ pRet = new SvxAppletShape( pObj );
+ nType = SdrObjKind::OLE2Applet;
+ }
+ else if( aIFrameClassId == aClassId )
+ {
+ pRet = new SvxFrameShape( pObj );
+ nType = SdrObjKind::OLEPluginFrame;
+ }
+ }
+ }
+ }
+ }
+ if( pRet == nullptr )
+ {
+ SvxUnoPropertyMapProvider& rSvxMapProvider = getSvxMapProvider();
+ pRet = new SvxOle2Shape( pObj, rSvxMapProvider.GetMap(SVXMAP_OLE2), rSvxMapProvider.GetPropertySet(SVXMAP_OLE2, SdrObject::GetGlobalDrawObjectItemPool()) );
+ }
+ }
+ break;
+ case SdrObjKind::Edge:
+ pRet = new SvxShapeConnector( pObj );
+ break;
+ case SdrObjKind::PathPoly:
+ pRet = new SvxShapePolyPolygon( pObj );
+ break;
+ case SdrObjKind::PathPolyLine:
+ pRet = new SvxShapePolyPolygon( pObj );
+ break;
+ case SdrObjKind::Page:
+ {
+ SvxUnoPropertyMapProvider& rSvxMapProvider = getSvxMapProvider();
+ pRet = new SvxShape( pObj, rSvxMapProvider.GetMap(SVXMAP_PAGE), rSvxMapProvider.GetPropertySet(SVXMAP_PAGE, SdrObject::GetGlobalDrawObjectItemPool()) );
+ }
+ break;
+ case SdrObjKind::Measure:
+ pRet = new SvxShapeDimensioning( pObj );
+ break;
+ case SdrObjKind::UNO:
+ pRet = new SvxShapeControl( pObj );
+ break;
+ case SdrObjKind::CustomShape:
+ pRet = new SvxCustomShape( pObj );
+ break;
+ case SdrObjKind::Media:
+ pRet = new SvxMediaShape( pObj, referer );
+ break;
+ case SdrObjKind::Table:
+ pRet = new SvxTableShape( pObj );
+ break;
+ default: // unknown 2D-object on page
+ assert(false && "Not implemented Starone-Shape created");
+ pRet = new SvxShapeText( pObj );
+ break;
+ }
+ break;
+ }
+ default: // unknown inventor
+ {
+ assert(false && "Unknown Inventor in SvxDrawPage::CreateShape()");
+ break;
+ }
+ }
+
+ if(pRet)
+ {
+ SdrObjKind nObjId = nType;
+
+ switch(nObjId)
+ {
+ case SdrObjKind::CircleCut: // segment of circle
+ case SdrObjKind::CircleArc: // arc of circle
+ case SdrObjKind::CircleSection: // sector
+ nObjId = SdrObjKind::CircleOrEllipse;
+ break;
+
+ case SdrObjKind::TitleText:
+ case SdrObjKind::OutlineText:
+ nObjId = SdrObjKind::Text;
+ break;
+ default: ;
+ }
+
+ pRet->setShapeKind(nObjId);
+ }
+
+ return pRet;
+}
+
+Reference< drawing::XShape > SvxDrawPage::CreateShape( SdrObject *pObj ) const
+{
+ Reference< drawing::XShape > xShape( CreateShapeByTypeAndInventor(pObj->GetObjIdentifier(),
+ pObj->GetObjInventor(),
+ pObj,
+ const_cast<SvxDrawPage*>(this)));
+ return xShape;
+}
+
+SdrObject *SvxDrawPage::CreateSdrObject( const Reference< drawing::XShape > & xShape, bool bBeginning ) noexcept
+{
+ SdrObject* pObj = CreateSdrObject_( xShape );
+ if( pObj)
+ {
+ if ( !pObj->IsInserted() && !pObj->IsDoNotInsertIntoPageAutomatically() )
+ {
+ if(bBeginning)
+ mpPage->InsertObject( pObj, 0 );
+ else
+ mpPage->InsertObject( pObj );
+ }
+ }
+
+ return pObj;
+}
+
+// css::lang::XServiceInfo
+OUString SAL_CALL SvxDrawPage::getImplementationName()
+{
+ return "SvxDrawPage";
+}
+
+sal_Bool SAL_CALL SvxDrawPage::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL SvxDrawPage::getSupportedServiceNames()
+{
+ uno::Sequence<OUString> aSeq { "com.sun.star.drawing.ShapeCollection" };
+ return aSeq;
+}
+
+rtl::Reference<SvxShape> CreateSvxShapeByTypeAndInventor(SdrObjKind nType, SdrInventor nInventor, OUString const & referer)
+{
+ return SvxDrawPage::CreateShapeByTypeAndInventor( nType, nInventor, nullptr, nullptr, referer );
+}
+
+/** returns a StarOffice API wrapper for the given SdrPage */
+uno::Reference< drawing::XDrawPage > GetXDrawPageForSdrPage( SdrPage* pPage ) noexcept
+{
+ if(pPage)
+ {
+ uno::Reference< drawing::XDrawPage > xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
+
+ return xDrawPage;
+ }
+
+ return uno::Reference< drawing::XDrawPage >();
+}
+
+/** returns the SdrObject from the given StarOffice API wrapper */
+SdrPage* GetSdrPageFromXDrawPage( const uno::Reference< drawing::XDrawPage >& xDrawPage ) noexcept
+{
+ if(xDrawPage.is())
+ {
+ SvxDrawPage* pDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>( xDrawPage );
+
+ if(pDrawPage)
+ {
+ return pDrawPage->GetSdrPage();
+ }
+ }
+
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unopool.cxx b/svx/source/unodraw/unopool.cxx
new file mode 100644
index 000000000..59c19c702
--- /dev/null
+++ b/svx/source/unodraw/unopool.cxx
@@ -0,0 +1,375 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+
+#include <comphelper/propertysetinfo.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/unopool.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/unoprov.hxx>
+#include <svx/unoshprp.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/svdetc.hxx>
+#include <editeng/editeng.hxx>
+#include <tools/debug.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::cppu;
+
+SvxUnoDrawPool::SvxUnoDrawPool(SdrModel* pModel, sal_Int32 nServiceId)
+: PropertySetHelper( SvxPropertySetInfoPool::getOrCreate( nServiceId ) ), mpModel( pModel )
+{
+ init();
+}
+
+/* deprecated */
+SvxUnoDrawPool::SvxUnoDrawPool(SdrModel* pModel)
+: PropertySetHelper( SvxPropertySetInfoPool::getOrCreate( SVXUNO_SERVICEID_COM_SUN_STAR_DRAWING_DEFAULTS ) ), mpModel( pModel )
+{
+ init();
+}
+
+SvxUnoDrawPool::~SvxUnoDrawPool() noexcept
+{
+}
+
+void SvxUnoDrawPool::init()
+{
+ mpDefaultsPool = new SdrItemPool();
+ rtl::Reference<SfxItemPool> pOutlPool = EditEngine::CreatePool();
+ mpDefaultsPool->SetSecondaryPool(pOutlPool.get());
+
+ SdrModel::SetTextDefaults( mpDefaultsPool.get(), SdrEngineDefaults::GetFontHeight() );
+ mpDefaultsPool->SetDefaultMetric(SdrEngineDefaults::GetMapUnit());
+ mpDefaultsPool->FreezeIdRanges();
+}
+
+SfxItemPool* SvxUnoDrawPool::getModelPool( bool bReadOnly ) noexcept
+{
+ if( mpModel )
+ {
+ return &mpModel->GetItemPool();
+ }
+ else
+ {
+ if( bReadOnly )
+ return mpDefaultsPool.get();
+ else
+ return nullptr;
+ }
+}
+
+void SvxUnoDrawPool::getAny( SfxItemPool const * pPool, const comphelper::PropertyMapEntry* pEntry, uno::Any& rValue )
+{
+ switch( pEntry->mnHandle )
+ {
+ case OWN_ATTR_FILLBMP_MODE:
+ {
+ if (pPool->GetDefaultItem(XATTR_FILLBMP_TILE).GetValue())
+ {
+ rValue <<= drawing::BitmapMode_REPEAT;
+ }
+ else if (pPool->GetDefaultItem(XATTR_FILLBMP_STRETCH).GetValue())
+ {
+ rValue <<= drawing::BitmapMode_STRETCH;
+ }
+ else
+ {
+ rValue <<= drawing::BitmapMode_NO_REPEAT;
+ }
+ break;
+ }
+ default:
+ {
+ const MapUnit eMapUnit = pPool->GetMetric(static_cast<sal_uInt16>(pEntry->mnHandle));
+
+ sal_uInt8 nMemberId = pEntry->mnMemberId;
+ if( eMapUnit == MapUnit::Map100thMM )
+ nMemberId &= (~CONVERT_TWIPS);
+
+ // Assure, that ID is a Which-ID (it could be a Slot-ID.)
+ // Thus, convert handle to Which-ID.
+ pPool->GetDefaultItem( pPool->GetWhich( static_cast<sal_uInt16>(pEntry->mnHandle) ) ).QueryValue( rValue, nMemberId );
+ }
+ }
+
+
+ // check for needed metric translation
+ const MapUnit eMapUnit = pPool->GetMetric(static_cast<sal_uInt16>(pEntry->mnHandle));
+ if(pEntry->mnMoreFlags & PropertyMoreFlags::METRIC_ITEM && eMapUnit != MapUnit::Map100thMM)
+ {
+ SvxUnoConvertToMM( eMapUnit, rValue );
+ }
+ // convert int32 to correct enum type if needed
+ else if ( pEntry->maType.getTypeClass() == uno::TypeClass_ENUM && rValue.getValueType() == ::cppu::UnoType<sal_Int32>::get() )
+ {
+ sal_Int32 nEnum;
+ rValue >>= nEnum;
+
+ rValue.setValue( &nEnum, pEntry->maType );
+ }
+}
+
+void SvxUnoDrawPool::putAny( SfxItemPool* pPool, const comphelper::PropertyMapEntry* pEntry, const uno::Any& rValue )
+{
+ uno::Any aValue( rValue );
+
+ const MapUnit eMapUnit = pPool->GetMetric(static_cast<sal_uInt16>(pEntry->mnHandle));
+ if(pEntry->mnMoreFlags & PropertyMoreFlags::METRIC_ITEM && eMapUnit != MapUnit::Map100thMM)
+ {
+ SvxUnoConvertFromMM( eMapUnit, aValue );
+ }
+
+ // Assure, that ID is a Which-ID (it could be a Slot-ID.)
+ // Thus, convert handle to Which-ID.
+ const sal_uInt16 nWhich = pPool->GetWhich( static_cast<sal_uInt16>(pEntry->mnHandle) );
+ switch( nWhich )
+ {
+ case OWN_ATTR_FILLBMP_MODE:
+ do
+ {
+ drawing::BitmapMode eMode;
+ if(!(aValue >>= eMode) )
+ {
+ sal_Int32 nMode = 0;
+ if(!(aValue >>= nMode))
+ throw lang::IllegalArgumentException();
+
+ eMode = static_cast<drawing::BitmapMode>(nMode);
+ }
+
+ pPool->SetPoolDefaultItem( XFillBmpStretchItem( eMode == drawing::BitmapMode_STRETCH ) );
+ pPool->SetPoolDefaultItem( XFillBmpTileItem( eMode == drawing::BitmapMode_REPEAT ) );
+ return;
+ }
+ while(false);
+
+ default:
+ {
+ std::unique_ptr<SfxPoolItem> pNewItem( pPool->GetDefaultItem( nWhich ).Clone() );
+ sal_uInt8 nMemberId = pEntry->mnMemberId;
+ if( pPool->GetMetric(nWhich) == MapUnit::Map100thMM )
+ nMemberId &= (~CONVERT_TWIPS);
+
+ if( !pNewItem->PutValue( aValue, nMemberId ) )
+ throw lang::IllegalArgumentException();
+
+ pPool->SetPoolDefaultItem( *pNewItem );
+ }
+ }
+}
+
+void SvxUnoDrawPool::_setPropertyValues( const comphelper::PropertyMapEntry** ppEntries, const uno::Any* pValues )
+{
+ SolarMutexGuard aGuard;
+
+ SfxItemPool* pPool = getModelPool( false );
+
+ DBG_ASSERT( pPool, "I need a SfxItemPool!" );
+ if( nullptr == pPool )
+ throw beans::UnknownPropertyException( "no pool, no properties..", static_cast<cppu::OWeakObject*>(this));
+
+ while( *ppEntries )
+ putAny( pPool, *ppEntries++, *pValues++ );
+}
+
+void SvxUnoDrawPool::_getPropertyValues( const comphelper::PropertyMapEntry** ppEntries, uno::Any* pValue )
+{
+ SolarMutexGuard aGuard;
+
+ SfxItemPool* pPool = getModelPool( true );
+
+ DBG_ASSERT( pPool, "I need a SfxItemPool!" );
+ if( nullptr == pPool )
+ throw beans::UnknownPropertyException( "no pool, no properties..", static_cast<cppu::OWeakObject*>(this));
+
+ while( *ppEntries )
+ getAny( pPool, *ppEntries++, *pValue++ );
+}
+
+void SvxUnoDrawPool::_getPropertyStates( const comphelper::PropertyMapEntry** ppEntries, beans::PropertyState* pStates )
+{
+ SolarMutexGuard aGuard;
+
+ SfxItemPool* pPool = getModelPool( true );
+
+ if( pPool && pPool != mpDefaultsPool.get() )
+ {
+ while( *ppEntries )
+ {
+ //Assure, that ID is a Which-ID (it could be a Slot-ID.)
+ // Thus, convert handle to Which-ID.
+ const sal_uInt16 nWhich = pPool->GetWhich( static_cast<sal_uInt16>((*ppEntries)->mnHandle) );
+
+ switch( nWhich )
+ {
+ case OWN_ATTR_FILLBMP_MODE:
+ {
+ // use method <IsStaticDefaultItem(..)> instead of using
+ // probably incompatible item pool <mpDefaultPool>.
+ if ( IsStaticDefaultItem( &(pPool->GetDefaultItem( XATTR_FILLBMP_STRETCH )) ) ||
+ IsStaticDefaultItem( &(pPool->GetDefaultItem( XATTR_FILLBMP_TILE )) ) )
+ {
+ *pStates = beans::PropertyState_DEFAULT_VALUE;
+ }
+ else
+ {
+ *pStates = beans::PropertyState_DIRECT_VALUE;
+ }
+ }
+ break;
+ case OWN_ATTR_TEXTCOLUMNS:
+ if (IsStaticDefaultItem(&pPool->GetDefaultItem(sal_uInt16(SDRATTR_TEXTCOLUMNS_NUMBER)))
+ && IsStaticDefaultItem(&pPool->GetDefaultItem(sal_uInt16(SDRATTR_TEXTCOLUMNS_SPACING))))
+ *pStates = beans::PropertyState_DEFAULT_VALUE;
+ else
+ *pStates = beans::PropertyState_DIRECT_VALUE;
+ break;
+ default:
+ //#i18732# - correction:
+ // use method <IsStaticDefaultItem(..)> instead of using probably
+ // incompatible item pool <mpDefaultPool>.
+ const SfxPoolItem& r1 = pPool->GetDefaultItem( nWhich );
+ //const SfxPoolItem& r2 = mpDefaultPool->GetDefaultItem( nWhich );
+
+ if ( IsStaticDefaultItem( &r1 ) )
+ {
+ *pStates = beans::PropertyState_DEFAULT_VALUE;
+ }
+ else
+ {
+ *pStates = beans::PropertyState_DIRECT_VALUE;
+ }
+ }
+
+ pStates++;
+ ppEntries++;
+ }
+ }
+ else
+ {
+ // as long as we have no model, all properties are default
+ while( *ppEntries++ )
+ *pStates++ = beans::PropertyState_DEFAULT_VALUE;
+ return;
+ }
+}
+
+void SvxUnoDrawPool::_setPropertyToDefault( const comphelper::PropertyMapEntry* pEntry )
+{
+ SolarMutexGuard aGuard;
+
+ SfxItemPool* pPool = getModelPool( true );
+
+ // Assure, that ID is a Which-ID (it could be a Slot-ID.)
+ // Thus, convert handle to Which-ID.
+ const sal_uInt16 nWhich = pPool->GetWhich( static_cast<sal_uInt16>(pEntry->mnHandle) );
+ if ( pPool && pPool != mpDefaultsPool.get() )
+ {
+ // use method <ResetPoolDefaultItem(..)> instead of using probably incompatible item pool <mpDefaultsPool>.
+ pPool->ResetPoolDefaultItem( nWhich );
+ }
+}
+
+uno::Any SvxUnoDrawPool::_getPropertyDefault( const comphelper::PropertyMapEntry* pEntry )
+{
+ SolarMutexGuard aGuard;
+ //#i18732# - use method <GetPoolDefaultItem(..)> instead of
+ // using probably incompatible item pool <mpDefaultsPool>
+ uno::Any aAny;
+ SfxItemPool* pPool = getModelPool( true );
+ const sal_uInt16 nWhich = pPool->GetWhich( static_cast<sal_uInt16>(pEntry->mnHandle) );
+ const SfxPoolItem *pItem = pPool->GetPoolDefaultItem ( nWhich );
+ if (pItem)
+ {
+ pItem->QueryValue( aAny, pEntry->mnMemberId );
+ }
+
+ return aAny;
+}
+
+// XInterface
+
+uno::Any SAL_CALL SvxUnoDrawPool::queryInterface( const uno::Type & rType )
+{
+ return OWeakAggObject::queryInterface( rType );
+}
+
+uno::Any SAL_CALL SvxUnoDrawPool::queryAggregation( const uno::Type & rType )
+{
+ uno::Any aAny;
+
+ if( rType == cppu::UnoType<lang::XServiceInfo>::get())
+ aAny <<= uno::Reference< lang::XServiceInfo >(this);
+ else if( rType == cppu::UnoType<lang::XTypeProvider>::get())
+ aAny <<= uno::Reference< lang::XTypeProvider >(this);
+ else if( rType == cppu::UnoType<beans::XPropertySet>::get())
+ aAny <<= uno::Reference< beans::XPropertySet >(this);
+ else if( rType == cppu::UnoType<beans::XPropertyState>::get())
+ aAny <<= uno::Reference< beans::XPropertyState >(this);
+ else if( rType == cppu::UnoType<beans::XMultiPropertySet>::get())
+ aAny <<= uno::Reference< beans::XMultiPropertySet >(this);
+ else
+ aAny = OWeakAggObject::queryAggregation( rType );
+
+ return aAny;
+}
+
+uno::Sequence< uno::Type > SAL_CALL SvxUnoDrawPool::getTypes()
+{
+ static const uno::Sequence aTypes {
+ cppu::UnoType<uno::XAggregation>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<beans::XPropertyState>::get(),
+ cppu::UnoType<beans::XMultiPropertySet>::get() };
+ return aTypes;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL SvxUnoDrawPool::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL SvxUnoDrawPool::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+OUString SAL_CALL SvxUnoDrawPool::getImplementationName()
+{
+ return "SvxUnoDrawPool";
+}
+
+uno::Sequence< OUString > SAL_CALL SvxUnoDrawPool::getSupportedServiceNames( )
+{
+ uno::Sequence<OUString> aSNS { "com.sun.star.drawing.Defaults" };
+ return aSNS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unoprov.cxx b/svx/source/unodraw/unoprov.cxx
new file mode 100644
index 000000000..9936a4df9
--- /dev/null
+++ b/svx/source/unodraw/unoprov.cxx
@@ -0,0 +1,2107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <sal/macros.h>
+#include <com/sun/star/table/XTable.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/util/MeasureUnit.hpp>
+#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <com/sun/star/media/ZoomLevel.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <tools/fldunit.hxx>
+#include <vcl/svapp.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <comphelper/sequence.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/unoshprp.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svdobjkind.hxx>
+#include <svx/strings.hrc>
+#include <o3tl/string_view.hxx>
+#include <strings.hxx>
+
+#include "shapeimpl.hxx"
+#include <unordered_map>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans::PropertyAttribute;
+using ::com::sun::star::drawing::TextVerticalAdjust;
+
+static SfxItemPropertyMapEntry const * ImplGetSvxShapePropertyMap()
+{
+ static SfxItemPropertyMapEntry const aShapePropertyMap_Impl[] =
+ {
+ EDGERADIUS_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ TEXT_PROPERTIES
+ // #FontWork#
+ FONTWORK_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aShapePropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxTextShapePropertyMap()
+{
+ static SfxItemPropertyMapEntry const aTextShapePropertyMap_Impl[] =
+ {
+ EDGERADIUS_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES_NO_SHEAR
+ LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ TEXT_PROPERTIES
+ // #FontWork#
+ FONTWORK_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aTextShapePropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxConnectorPropertyMap()
+{
+ static SfxItemPropertyMapEntry const aConnectorPropertyMap_Impl[] =
+ {
+ SPECIAL_CONNECTOR_PROPERTIES
+ EDGERADIUS_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ TEXT_PROPERTIES
+ // #FontWork#
+ FONTWORK_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aConnectorPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxDimensioningPropertyMap()
+{
+ static SfxItemPropertyMapEntry const aDimensioningPropertyMap_Impl[] =
+ {
+ SPECIAL_DIMENSIONING_PROPERTIES
+ EDGERADIUS_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ TEXT_PROPERTIES
+ // #FontWork#
+ FONTWORK_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aDimensioningPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxCirclePropertyMap()
+{
+ static SfxItemPropertyMapEntry const aCirclePropertyMap_Impl[] =
+ {
+ SPECIAL_CIRCLE_PROPERTIES
+ EDGERADIUS_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ TEXT_PROPERTIES
+ // #FontWork#
+ FONTWORK_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aCirclePropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxPolyPolygonPropertyMap()
+{
+ static SfxItemPropertyMapEntry const aPolyPolygonPropertyMap_Impl[] =
+ {
+ { u"Geometry", OWN_ATTR_BASE_GEOMETRY, cppu::UnoType<css::drawing::PointSequenceSequence>::get(), 0, 0 },
+ SPECIAL_POLYGON_PROPERTIES
+ SPECIAL_POLYPOLYGON_PROPERTIES
+ SPECIAL_POLYPOLYGONBEZIER_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ TEXT_PROPERTIES
+ // #FontWork#
+ FONTWORK_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aPolyPolygonPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxGraphicObjectPropertyMap()
+{
+ static SfxItemPropertyMapEntry const aGraphicObjectPropertyMap_Impl[] =
+ {
+ SPECIAL_GRAPHOBJ_PROPERTIES
+
+ // #i25616#
+ FILL_PROPERTIES
+
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+
+ // #i118485# Full properties now, shear included
+ MISC_OBJ_PROPERTIES
+
+ LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ TEXT_PROPERTIES
+ // #FontWork#
+ FONTWORK_PROPERTIES
+ { u"IsMirrored", OWN_ATTR_MIRRORED, cppu::UnoType<bool>::get(), 0, 0},
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"GraphicStream", OWN_ATTR_GRAPHIC_STREAM, cppu::UnoType<css::io::XInputStream>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aGraphicObjectPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvx3DSceneObjectPropertyMap()
+{
+ static SfxItemPropertyMapEntry const a3DSceneObjectPropertyMap_Impl[] =
+ {
+ SPECIAL_3DSCENEOBJECT_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ SHADOW_PROPERTIES
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return a3DSceneObjectPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvx3DCubeObjectPropertyMap()
+{
+ static SfxItemPropertyMapEntry const a3DCubeObjectPropertyMap_Impl[] =
+ {
+ SPECIAL_3DCUBEOBJECT_PROPERTIES
+ MISC_3D_OBJ_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ SHADOW_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return a3DCubeObjectPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvx3DSphereObjectPropertyMap()
+{
+ static SfxItemPropertyMapEntry const a3DSphereObjectPropertyMap_Impl[] =
+ {
+ SPECIAL_3DSPHEREOBJECT_PROPERTIES
+ MISC_3D_OBJ_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ SHADOW_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return a3DSphereObjectPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvx3DLatheObjectPropertyMap()
+{
+ static SfxItemPropertyMapEntry const a3DLatheObjectPropertyMap_Impl[] =
+ {
+ SPECIAL_3DLATHEOBJECT_PROPERTIES
+
+ // #107245# New 3D properties which are possible for lathe and extrude 3d objects
+ SPECIAL_3DLATHEANDEXTRUDEOBJ_PROPERTIES
+
+ SPECIAL_3DBACKSCALE_PROPERTIES
+ MISC_3D_OBJ_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ SHADOW_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return a3DLatheObjectPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvx3DExtrudeObjectPropertyMap()
+{
+ static SfxItemPropertyMapEntry const a3DExtrudeObjectPropertyMap_Impl[] =
+ {
+ SPECIAL_3DEXTRUDEOBJECT_PROPERTIES
+
+ // #107245# New 3D properties which are possible for lathe and extrude 3d objects
+ SPECIAL_3DLATHEANDEXTRUDEOBJ_PROPERTIES
+
+ SPECIAL_3DBACKSCALE_PROPERTIES
+ MISC_3D_OBJ_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ SHADOW_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return a3DExtrudeObjectPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvx3DPolygonObjectPropertyMap()
+{
+ static SfxItemPropertyMapEntry const a3DPolygonObjectPropertyMap_Impl[] =
+ {
+ SPECIAL_3DPOLYGONOBJECT_PROPERTIES
+ MISC_3D_OBJ_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ SHADOW_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return a3DPolygonObjectPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxAllPropertyMap()
+{
+ static SfxItemPropertyMapEntry const aAllPropertyMap_Impl[] =
+ {
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ FILL_PROPERTIES
+ EDGERADIUS_PROPERTIES
+ TEXT_PROPERTIES
+ // #FontWork#
+ FONTWORK_PROPERTIES
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ SPECIAL_CONNECTOR_PROPERTIES
+ SPECIAL_DIMENSIONING_PROPERTIES
+ SPECIAL_CIRCLE_PROPERTIES
+ SPECIAL_POLYGON_PROPERTIES
+ SPECIAL_POLYPOLYGON_PROPERTIES
+ SPECIAL_POLYPOLYGONBEZIER_PROPERTIES
+ SPECIAL_GRAPHOBJ_PROPERTIES
+ SPECIAL_3DSCENEOBJECT_PROPERTIES
+ MISC_3D_OBJ_PROPERTIES
+ SPECIAL_3DCUBEOBJECT_PROPERTIES
+ SPECIAL_3DSPHEREOBJECT_PROPERTIES
+ SPECIAL_3DLATHEOBJECT_PROPERTIES
+ SPECIAL_3DEXTRUDEOBJECT_PROPERTIES
+
+ // #107245# New 3D properties which are possible for lathe and extrude 3d objects
+ SPECIAL_3DLATHEANDEXTRUDEOBJ_PROPERTIES
+
+ SPECIAL_3DBACKSCALE_PROPERTIES
+ SPECIAL_3DPOLYGONOBJECT_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aAllPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxGroupPropertyMap()
+{
+ static SfxItemPropertyMapEntry const aGroupPropertyMap_Impl[] =
+ {
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aGroupPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxOle2PropertyMap()
+{
+ static SfxItemPropertyMapEntry const aOle2PropertyMap_Impl[] =
+ {
+ // #i118485# Adding properties for line, fill, text, shadow, fontwork, rotate, shear
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ TEXT_PROPERTIES
+ FONTWORK_PROPERTIES
+
+ { u"ThumbnailGraphic", OWN_ATTR_THUMBNAIL , cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0 },
+ { u"Model", OWN_ATTR_OLEMODEL , cppu::UnoType<css::frame::XModel>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"EmbeddedObject", OWN_ATTR_OLE_EMBEDDED_OBJECT, cppu::UnoType<css::embed::XEmbeddedObject>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"EmbeddedObjectNoNewClient",OWN_ATTR_OLE_EMBEDDED_OBJECT_NONEWCLIENT, cppu::UnoType<css::embed::XEmbeddedObject>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"OriginalSize", OWN_ATTR_OLESIZE , cppu::UnoType<css::awt::Size>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"CLSID", OWN_ATTR_CLSID , cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"IsInternal", OWN_ATTR_INTERNAL_OLE , cppu::UnoType<bool>::get() , css::beans::PropertyAttribute::READONLY, 0},
+ { u"VisibleArea", OWN_ATTR_OLE_VISAREA , cppu::UnoType<css::awt::Rectangle>::get(), 0, 0},
+ { u"Aspect", OWN_ATTR_OLE_ASPECT , cppu::UnoType<sal_Int64>::get(), 0, 0},
+ { UNO_NAME_OLE2_PERSISTNAME, OWN_ATTR_PERSISTNAME , cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"LinkURL", OWN_ATTR_OLE_LINKURL , cppu::UnoType<OUString>::get(), 0, 0 },
+ { UNO_NAME_GRAPHOBJ_GRAPHIC, OWN_ATTR_VALUE_GRAPHIC , cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aOle2PropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxPluginPropertyMap()
+{
+ static SfxItemPropertyMapEntry const aPluginPropertyMap_Impl[] =
+ {
+ { u"PluginMimeType", OWN_ATTR_PLUGIN_MIMETYPE , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"PluginURL", OWN_ATTR_PLUGIN_URL , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"PluginCommands", OWN_ATTR_PLUGIN_COMMANDS , cppu::UnoType<css::uno::Sequence< css::beans::PropertyValue >>::get(), 0, 0},
+ { u"Transformation", OWN_ATTR_TRANSFORMATION , cppu::UnoType<css::drawing::HomogenMatrix3>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_ZORDER, OWN_ATTR_ZORDER , cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERID, SDRATTR_LAYERID , cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERNAME,SDRATTR_LAYERNAME , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_LINKDISPLAYBITMAP, OWN_ATTR_LDBITMAP , cppu::UnoType<css::awt::XBitmap>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_LINKDISPLAYNAME, OWN_ATTR_LDNAME , cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_OLE2_METAFILE, OWN_ATTR_METAFILE , cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"ThumbnailGraphic", OWN_ATTR_THUMBNAIL , cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_MOVEPROTECT, SDRATTR_OBJMOVEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_MISC_OBJ_SIZEPROTECT, SDRATTR_OBJSIZEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_OLE2_PERSISTNAME, OWN_ATTR_PERSISTNAME , cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"LinkURL", OWN_ATTR_OLE_LINKURL , cppu::UnoType<OUString>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_BOUNDRECT, OWN_ATTR_BOUNDRECT, cppu::UnoType<css::awt::Rectangle>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"VisibleArea", OWN_ATTR_OLE_VISAREA , cppu::UnoType<css::awt::Rectangle>::get(), 0, 0},
+ { u"UINameSingular", OWN_ATTR_UINAME_SINGULAR , ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ // #i68101#
+ { UNO_NAME_MISC_OBJ_TITLE, OWN_ATTR_MISC_OBJ_TITLE , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_DESCRIPTION, OWN_ATTR_MISC_OBJ_DESCRIPTION , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aPluginPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxFramePropertyMap()
+{
+ //TODO/LATER: new properties for ScrollingMode and DefaultBorder
+ static SfxItemPropertyMapEntry const aFramePropertyMap_Impl[] =
+ {
+ { u"FrameURL", OWN_ATTR_FRAME_URL , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"FrameName", OWN_ATTR_FRAME_NAME , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"FrameIsAutoScroll", OWN_ATTR_FRAME_ISAUTOSCROLL , cppu::UnoType<bool>::get() , css::beans::PropertyAttribute::MAYBEVOID, 0},
+ { u"FrameIsBorder", OWN_ATTR_FRAME_ISBORDER , cppu::UnoType<bool>::get() , 0, 0},
+ { u"FrameMarginWidth", OWN_ATTR_FRAME_MARGIN_WIDTH , cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"FrameMarginHeight", OWN_ATTR_FRAME_MARGIN_HEIGHT, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"Transformation", OWN_ATTR_TRANSFORMATION , cppu::UnoType<css::drawing::HomogenMatrix3>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_ZORDER, OWN_ATTR_ZORDER , cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERID, SDRATTR_LAYERID , cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERNAME,SDRATTR_LAYERNAME , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_LINKDISPLAYBITMAP, OWN_ATTR_LDBITMAP , cppu::UnoType<css::awt::XBitmap>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_LINKDISPLAYNAME, OWN_ATTR_LDNAME , cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_OLE2_METAFILE, OWN_ATTR_METAFILE , cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"ThumbnailGraphic", OWN_ATTR_THUMBNAIL , cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_MOVEPROTECT, SDRATTR_OBJMOVEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_MISC_OBJ_SIZEPROTECT, SDRATTR_OBJSIZEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_OLE2_PERSISTNAME, OWN_ATTR_PERSISTNAME , cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"LinkURL", OWN_ATTR_OLE_LINKURL , cppu::UnoType<OUString>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_BOUNDRECT, OWN_ATTR_BOUNDRECT, cppu::UnoType<css::awt::Rectangle>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"VisibleArea", OWN_ATTR_OLE_VISAREA , cppu::UnoType<css::awt::Rectangle>::get(), 0, 0},
+ { u"UINameSingular", OWN_ATTR_UINAME_SINGULAR , ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ // #i68101#
+ { UNO_NAME_MISC_OBJ_TITLE, OWN_ATTR_MISC_OBJ_TITLE , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_DESCRIPTION, OWN_ATTR_MISC_OBJ_DESCRIPTION , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aFramePropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxAppletPropertyMap()
+{
+ static SfxItemPropertyMapEntry const aAppletPropertyMap_Impl[] =
+ {
+ { u"AppletCodeBase", OWN_ATTR_APPLET_CODEBASE , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"AppletName", OWN_ATTR_APPLET_NAME , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"AppletCode", OWN_ATTR_APPLET_CODE , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"AppletCommands", OWN_ATTR_APPLET_COMMANDS , cppu::UnoType<css::uno::Sequence< css::beans::PropertyValue >>::get(), 0, 0},
+ { u"AppletDocBase", OWN_ATTR_APPLET_DOCBASE , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"AppletIsScript", OWN_ATTR_APPLET_ISSCRIPT , cppu::UnoType<bool>::get(), 0, 0 },
+ { u"Transformation", OWN_ATTR_TRANSFORMATION , cppu::UnoType<css::drawing::HomogenMatrix3>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_ZORDER, OWN_ATTR_ZORDER , cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERID, SDRATTR_LAYERID , cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERNAME,SDRATTR_LAYERNAME , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_LINKDISPLAYBITMAP, OWN_ATTR_LDBITMAP , cppu::UnoType<css::awt::XBitmap>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_LINKDISPLAYNAME, OWN_ATTR_LDNAME , cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_OLE2_METAFILE, OWN_ATTR_METAFILE , cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"ThumbnailGraphic", OWN_ATTR_THUMBNAIL , cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_MOVEPROTECT, SDRATTR_OBJMOVEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_MISC_OBJ_SIZEPROTECT, SDRATTR_OBJSIZEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_OLE2_PERSISTNAME, OWN_ATTR_PERSISTNAME , cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"LinkURL", OWN_ATTR_OLE_LINKURL , cppu::UnoType<OUString>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_BOUNDRECT, OWN_ATTR_BOUNDRECT, cppu::UnoType<css::awt::Rectangle>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"VisibleArea", OWN_ATTR_OLE_VISAREA , cppu::UnoType<css::awt::Rectangle>::get(), 0, 0},
+ { u"UINameSingular", OWN_ATTR_UINAME_SINGULAR , ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ // #i68101#
+ { UNO_NAME_MISC_OBJ_TITLE, OWN_ATTR_MISC_OBJ_TITLE , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_DESCRIPTION, OWN_ATTR_MISC_OBJ_DESCRIPTION , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aAppletPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxControlShapePropertyMap()
+{
+ static SfxItemPropertyMapEntry const aControlPropertyMap_Impl[] =
+ {
+ // the following properties are mapped to the XControl Model of this shape
+ { UNO_NAME_EDIT_CHAR_FONTNAME, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_FONTSTYLENAME, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_FONTFAMILY, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_FONTCHARSET, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_HEIGHT, 0, cppu::UnoType<float>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_FONTPITCH, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_POSTURE, 0, cppu::UnoType<css::awt::FontSlant>::get(),0, 0 },
+ { UNO_NAME_EDIT_CHAR_WEIGHT, 0, cppu::UnoType<float>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_UNDERLINE, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_STRIKEOUT, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { UNO_NAME_EDIT_CHAR_CASEMAP, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_COLOR, 0, cppu::UnoType<sal_Int32>::get(), 0, MID_COLOR_RGB },
+ { UNO_NAME_EDIT_CHAR_COLOR_THEME, 0, cppu::UnoType<sal_Int16>::get(), 0, MID_COLOR_THEME_INDEX },
+ { UNO_NAME_EDIT_CHAR_COLOR_TINT_OR_SHADE, 0, cppu::UnoType<sal_Int16>::get(), 0, MID_COLOR_TINT_OR_SHADE },
+ { u"CharBackColor", 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"CharBackTransparent", 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"CharRelief", 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { u"CharUnderlineColor", 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"CharKerning", 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { u"CharWordMode", 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { UNO_NAME_EDIT_PARA_ADJUST, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { u"TextVerticalAdjust", 0, cppu::UnoType<TextVerticalAdjust>::get(), MAYBEVOID, 0 },
+ { u"ControlBackground", 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"ControlBorder", 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { u"ControlBorderColor", 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"ControlSymbolColor", 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { u"ImageScaleMode", 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_MOVEPROTECT, SDRATTR_OBJMOVEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_MISC_OBJ_SIZEPROTECT, SDRATTR_OBJSIZEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { u"ControlTextEmphasis", 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { u"ControlWritingMode", 0, cppu::UnoType< sal_Int16 >::get(), 0, 0},
+ // the following properties are handled by SvxShape
+ { u"Transformation", OWN_ATTR_TRANSFORMATION , cppu::UnoType<css::drawing::HomogenMatrix3>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_ZORDER, OWN_ATTR_ZORDER , cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERID, SDRATTR_LAYERID , cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERNAME,SDRATTR_LAYERNAME , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_LINKDISPLAYBITMAP, OWN_ATTR_LDBITMAP , cppu::UnoType<css::awt::XBitmap>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_LINKDISPLAYNAME, OWN_ATTR_LDNAME , cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ {u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_BOUNDRECT, OWN_ATTR_BOUNDRECT, cppu::UnoType<css::awt::Rectangle>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"UINameSingular", OWN_ATTR_UINAME_SINGULAR , ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ // #i68101#
+ { UNO_NAME_MISC_OBJ_TITLE, OWN_ATTR_MISC_OBJ_TITLE , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_DESCRIPTION, OWN_ATTR_MISC_OBJ_DESCRIPTION , cppu::UnoType<OUString>::get(), 0, 0},
+ // #i112587#
+ { UNO_NAME_MISC_OBJ_PRINTABLE, SDRATTR_OBJPRINTABLE , cppu::UnoType<bool>::get(), 0, 0},
+ { u"Visible", SDRATTR_OBJVISIBLE , cppu::UnoType<bool>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_INTEROPGRABBAG, OWN_ATTR_INTEROPGRABBAG, cppu::UnoType<css::uno::Sequence< css::beans::PropertyValue >>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aControlPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxPageShapePropertyMap()
+{
+ static SfxItemPropertyMapEntry const aPageShapePropertyMap_Impl[] =
+ {
+ { u"PageNumber", OWN_ATTR_PAGE_NUMBER , cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"Transformation", OWN_ATTR_TRANSFORMATION , cppu::UnoType<css::drawing::HomogenMatrix3>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_ZORDER, OWN_ATTR_ZORDER , cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERID, SDRATTR_LAYERID , cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERNAME,SDRATTR_LAYERNAME , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_LINKDISPLAYBITMAP, OWN_ATTR_LDBITMAP , cppu::UnoType<css::awt::XBitmap>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_LINKDISPLAYNAME, OWN_ATTR_LDNAME , cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_MISC_OBJ_MOVEPROTECT, SDRATTR_OBJMOVEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_MISC_OBJ_SIZEPROTECT, SDRATTR_OBJSIZEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_MISC_OBJ_BOUNDRECT, OWN_ATTR_BOUNDRECT, cppu::UnoType<css::awt::Rectangle>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ // #i68101#
+ { UNO_NAME_MISC_OBJ_TITLE, OWN_ATTR_MISC_OBJ_TITLE , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_DESCRIPTION, OWN_ATTR_MISC_OBJ_DESCRIPTION , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aPageShapePropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxCaptionPropertyMap()
+{
+ static SfxItemPropertyMapEntry const aCaptionPropertyMap_Impl[] =
+ {
+ { u"CaptionPoint", OWN_ATTR_CAPTION_POINT, cppu::UnoType<css::awt::Point>::get(), 0, 0 },
+ { u"CaptionType", SDRATTR_CAPTIONTYPE, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { u"CaptionIsFixedAngle", SDRATTR_CAPTIONFIXEDANGLE, cppu::UnoType<bool>::get(), 0, 0},
+ { u"CaptionAngle", SDRATTR_CAPTIONANGLE, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"CaptionGap", SDRATTR_CAPTIONGAP, cppu::UnoType<sal_Int32>::get(), 0, 0, PropertyMoreFlags::METRIC_ITEM},
+ { u"CaptionEscapeDirection", SDRATTR_CAPTIONESCDIR, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"CaptionIsEscapeRelative", SDRATTR_CAPTIONESCISREL, cppu::UnoType<bool>::get(), 0, 0},
+ { u"CaptionEscapeRelative", SDRATTR_CAPTIONESCREL, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"CaptionEscapeAbsolute", SDRATTR_CAPTIONESCABS, cppu::UnoType<sal_Int32>::get(), 0, 0, PropertyMoreFlags::METRIC_ITEM},
+ { u"CaptionLineLength", SDRATTR_CAPTIONLINELEN, cppu::UnoType<sal_Int32>::get(), 0, 0, PropertyMoreFlags::METRIC_ITEM},
+ { u"CaptionIsFitLineLength", SDRATTR_CAPTIONFITLINELEN, cppu::UnoType<bool>::get(), 0, 0},
+ EDGERADIUS_PROPERTIES
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ SHADOW_PROPERTIES
+ TEXT_PROPERTIES
+ // #FontWork#
+ FONTWORK_PROPERTIES
+ { u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ {u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aCaptionPropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxCustomShapePropertyMap()
+{
+ static SfxItemPropertyMapEntry const aCustomShapePropertyMap_Impl[] =
+ {
+ { u"CustomShapeEngine", SDRATTR_CUSTOMSHAPE_ENGINE, cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"CustomShapeData", SDRATTR_CUSTOMSHAPE_DATA, cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"CustomShapeGeometry", SDRATTR_CUSTOMSHAPE_GEOMETRY,
+ cppu::UnoType<css::uno::Sequence< css::beans::PropertyValue >>::get(), 0, 0 },
+ FILL_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ SHAPE_DESCRIPTOR_PROPERTIES
+ MISC_OBJ_PROPERTIES
+ LINKTARGET_PROPERTIES
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ TEXT_PROPERTIES
+ {u"UserDefinedAttributes", SDRATTR_XMLATTRIBUTES, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ {u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aCustomShapePropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxMediaShapePropertyMap()
+{
+ static SfxItemPropertyMapEntry const aMediaShapePropertyMap_Impl[] =
+ {
+ { UNO_NAME_MISC_OBJ_ZORDER, OWN_ATTR_ZORDER, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERID, SDRATTR_LAYERID, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERNAME, SDRATTR_LAYERNAME, cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_LINKDISPLAYBITMAP, OWN_ATTR_LDBITMAP, cppu::UnoType<css::awt::XBitmap>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_LINKDISPLAYNAME, OWN_ATTR_LDNAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"Transformation", OWN_ATTR_TRANSFORMATION, cppu::UnoType<css::drawing::HomogenMatrix3>::get(), 0, 0 },
+ { u"MediaURL", OWN_ATTR_MEDIA_URL, cppu::UnoType<OUString>::get(), 0, 0},
+ { u"PreferredSize", OWN_ATTR_MEDIA_PREFERREDSIZE, cppu::UnoType<css::awt::Size>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"Loop", OWN_ATTR_MEDIA_LOOP, cppu::UnoType<sal_Bool>::get(), 0, 0},
+ { u"Mute", OWN_ATTR_MEDIA_MUTE, cppu::UnoType<sal_Bool>::get(), 0, 0},
+ { u"VolumeDB", OWN_ATTR_MEDIA_VOLUMEDB, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { u"Zoom", OWN_ATTR_MEDIA_ZOOM, cppu::UnoType<css::media::ZoomLevel>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_MOVEPROTECT, SDRATTR_OBJMOVEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_MISC_OBJ_SIZEPROTECT, SDRATTR_OBJSIZEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_MISC_OBJ_BOUNDRECT, OWN_ATTR_BOUNDRECT, cppu::UnoType<css::awt::Rectangle>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"UINameSingular", OWN_ATTR_UINAME_SINGULAR , ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ // #i68101#
+ { UNO_NAME_MISC_OBJ_TITLE, OWN_ATTR_MISC_OBJ_TITLE , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_DESCRIPTION, OWN_ATTR_MISC_OBJ_DESCRIPTION , cppu::UnoType<OUString>::get(), 0, 0},
+ {u"PrivateStream", OWN_ATTR_MEDIA_STREAM, cppu::UnoType<css::io::XInputStream>::get(), 0, 0},
+ {u"PrivateTempFileURL", OWN_ATTR_MEDIA_TEMPFILEURL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"MediaMimeType", OWN_ATTR_MEDIA_MIMETYPE, cppu::UnoType<OUString>::get(), 0, 0},
+ { u"FallbackGraphic", OWN_ATTR_FALLBACK_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_GRAPHOBJ_GRAPHIC, OWN_ATTR_VALUE_GRAPHIC , cppu::UnoType<css::graphic::XGraphic>::get(), 0, 0},
+ { UNO_NAME_GRAPHIC_GRAPHICCROP, SDRATTR_GRAFCROP , cppu::UnoType<css::text::GraphicCrop>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aMediaShapePropertyMap_Impl;
+}
+
+static SfxItemPropertyMapEntry const * ImplGetSvxTableShapePropertyMap()
+{
+ static SfxItemPropertyMapEntry const aTableShapePropertyMap_Impl[] =
+ {
+ SHADOW_PROPERTIES
+ { UNO_NAME_MISC_OBJ_ZORDER, OWN_ATTR_ZORDER, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERID, SDRATTR_LAYERID, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_LAYERNAME, SDRATTR_LAYERNAME, cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_LINKDISPLAYBITMAP, OWN_ATTR_LDBITMAP, cppu::UnoType<css::awt::XBitmap>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_LINKDISPLAYNAME, OWN_ATTR_LDNAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"Transformation", OWN_ATTR_TRANSFORMATION, cppu::UnoType<css::drawing::HomogenMatrix3>::get(), 0, 0 },
+ { UNO_NAME_MISC_OBJ_MOVEPROTECT, SDRATTR_OBJMOVEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_MISC_OBJ_SIZEPROTECT, SDRATTR_OBJSIZEPROTECT, cppu::UnoType<bool>::get(),0, 0},
+ { UNO_NAME_MISC_OBJ_BOUNDRECT, OWN_ATTR_BOUNDRECT, cppu::UnoType<css::awt::Rectangle>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_MISC_OBJ_NAME, SDRATTR_OBJECTNAME, cppu::UnoType<OUString>::get(), 0, 0},
+ { u"UINameSingular", OWN_ATTR_UINAME_SINGULAR , ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { UNO_NAME_MISC_OBJ_TITLE, OWN_ATTR_MISC_OBJ_TITLE , cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_MISC_OBJ_DESCRIPTION, OWN_ATTR_MISC_OBJ_DESCRIPTION , cppu::UnoType<OUString>::get(), 0, 0},
+ { u"Model", OWN_ATTR_OLEMODEL , cppu::UnoType<css::table::XTable>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"TableTemplate", OWN_ATTR_TABLETEMPLATE , cppu::UnoType<css::container::XIndexAccess>::get(), 0, 0},
+ { u"UseFirstRowStyle", OWN_ATTR_TABLETEMPLATE_FIRSTROW, cppu::UnoType<bool>::get(),0, 0},
+ { u"UseLastRowStyle", OWN_ATTR_TABLETEMPLATE_LASTROW, cppu::UnoType<bool>::get(),0, 0},
+ { u"UseFirstColumnStyle", OWN_ATTR_TABLETEMPLATE_FIRSTCOLUMN, cppu::UnoType<bool>::get(),0, 0},
+ { u"UseLastColumnStyle", OWN_ATTR_TABLETEMPLATE_LASTCOLUMN, cppu::UnoType<bool>::get(),0, 0},
+ { u"UseBandingRowStyle", OWN_ATTR_TABLETEMPLATE_BANDINGROWS, cppu::UnoType<bool>::get(),0, 0},
+ { u"UseBandingColumnStyle", OWN_ATTR_TABLETEMPLATE_BANDINGCOLUMNS, cppu::UnoType<bool>::get(),0, 0},
+ { u"ReplacementGraphic", OWN_ATTR_REPLACEMENT_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get(), css::beans::PropertyAttribute::READONLY, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ return aTableShapePropertyMap_Impl;
+}
+
+static o3tl::span<comphelper::PropertyMapEntry const> ImplGetSvxDrawingDefaultsPropertyMap()
+{
+ static comphelper::PropertyMapEntry const aSvxDrawingDefaultsPropertyMap_Impl[] =
+ {
+ GLOW_PROPERTIES
+ SOFTEDGE_PROPERTIES
+ SHADOW_PROPERTIES
+ LINE_PROPERTIES_DEFAULTS
+ FILL_PROPERTIES_BMP
+ FILL_PROPERTIES_DEFAULTS
+ EDGERADIUS_PROPERTIES
+ TEXT_PROPERTIES_DEFAULTS
+ CONNECTOR_PROPERTIES
+ SPECIAL_DIMENSIONING_PROPERTIES_DEFAULTS
+ MISC_3D_OBJ_PROPERTIES
+ SPECIAL_3DBACKSCALE_PROPERTIES
+ };
+
+ return aSvxDrawingDefaultsPropertyMap_Impl;
+}
+
+static o3tl::span<comphelper::PropertyMapEntry const> ImplGetAdditionalWriterDrawingDefaultsPropertyMap()
+{
+ static comphelper::PropertyMapEntry const aSvxAdditionalDefaultsPropertyMap_Impl[] =
+ {
+ { "IsFollowingTextFlow", SID_SW_FOLLOW_TEXT_FLOW, cppu::UnoType<bool>::get(), 0, 0},
+ };
+
+ return aSvxAdditionalDefaultsPropertyMap_Impl;
+}
+
+typedef std::unordered_map< OUString, SdrObjKind > UHashMapImpl;
+
+namespace {
+
+const UHashMapImpl& GetUHashImpl()
+{
+ static UHashMapImpl const aImpl
+ {
+ { "com.sun.star.drawing.RectangleShape", SdrObjKind::Rectangle },
+ { "com.sun.star.drawing.EllipseShape", SdrObjKind::CircleOrEllipse },
+ { "com.sun.star.drawing.ControlShape", SdrObjKind::UNO },
+ { "com.sun.star.drawing.ConnectorShape", SdrObjKind::Edge },
+ { "com.sun.star.drawing.MeasureShape", SdrObjKind::Measure },
+ { "com.sun.star.drawing.LineShape", SdrObjKind::Line },
+ { "com.sun.star.drawing.PolyPolygonShape", SdrObjKind::Polygon },
+ { "com.sun.star.drawing.PolyLineShape", SdrObjKind::PolyLine },
+ { "com.sun.star.drawing.OpenBezierShape", SdrObjKind::PathLine },
+ { "com.sun.star.drawing.ClosedBezierShape", SdrObjKind::PathFill },
+ { "com.sun.star.drawing.OpenFreeHandShape", SdrObjKind::FreehandLine },
+ { "com.sun.star.drawing.ClosedFreeHandShape", SdrObjKind::FreehandFill },
+ { "com.sun.star.drawing.PolyPolygonPathShape", SdrObjKind::PathPoly },
+ { "com.sun.star.drawing.PolyLinePathShape", SdrObjKind::PathPolyLine },
+ { "com.sun.star.drawing.GraphicObjectShape", SdrObjKind::Graphic },
+ { "com.sun.star.drawing.GroupShape", SdrObjKind::Group },
+ { "com.sun.star.drawing.TextShape", SdrObjKind::Text },
+ { "com.sun.star.drawing.OLE2Shape", SdrObjKind::OLE2 },
+ { "com.sun.star.drawing.PageShape", SdrObjKind::Page },
+ { "com.sun.star.drawing.CaptionShape", SdrObjKind::Caption },
+ { "com.sun.star.drawing.FrameShape", SdrObjKind::OLEPluginFrame },
+ { "com.sun.star.drawing.PluginShape", SdrObjKind::OLE2Plugin },
+ { "com.sun.star.drawing.AppletShape", SdrObjKind::OLE2Applet },
+ { "com.sun.star.drawing.CustomShape", SdrObjKind::CustomShape },
+ { "com.sun.star.drawing.MediaShape", SdrObjKind::Media },
+
+ { "com.sun.star.drawing.Shape3DSceneObject", SdrObjKind::E3D_Scene },
+ { "com.sun.star.drawing.Shape3DCubeObject", SdrObjKind::E3D_Cube },
+ { "com.sun.star.drawing.Shape3DSphereObject", SdrObjKind::E3D_Sphere },
+ { "com.sun.star.drawing.Shape3DLatheObject", SdrObjKind::E3D_Lathe },
+ { "com.sun.star.drawing.Shape3DExtrudeObject", SdrObjKind::E3D_Extrusion },
+ { "com.sun.star.drawing.Shape3DPolygonObject", SdrObjKind::E3D_Polygon },
+ };
+
+ return aImpl;
+}
+
+}
+
+
+OUString UHashMap::getNameFromId(SdrObjKind nId)
+{
+ const UHashMapImpl &rMap = GetUHashImpl();
+
+ auto it = std::find_if(rMap.begin(), rMap.end(),
+ [nId](const UHashMapImpl::value_type& rEntry) { return rEntry.second == nId; });
+ if (it != rMap.end())
+ return it->first;
+ OSL_FAIL("[CL] unknown SdrObject identifier");
+ return OUString();
+}
+
+uno::Sequence< OUString > UHashMap::getServiceNames()
+{
+ return comphelper::mapKeysToSequence( GetUHashImpl() );
+}
+
+std::optional<SdrObjKind> UHashMap::getId( const OUString& rCompareString )
+{
+ const UHashMapImpl &rMap = GetUHashImpl();
+ UHashMapImpl::const_iterator it = rMap.find( rCompareString );
+ if( it == rMap.end() )
+ return {};
+ else
+ return it->second;
+}
+
+SvxUnoPropertyMapProvider& getSvxMapProvider()
+{
+ static SvxUnoPropertyMapProvider theSvxMapProvider;
+ return theSvxMapProvider;
+}
+
+
+SvxUnoPropertyMapProvider::SvxUnoPropertyMapProvider()
+{
+ for(sal_uInt16 i=0;i<SVXMAP_END; i++)
+ {
+ aSetArr[i] = nullptr;
+ aMapArr[i] = nullptr;
+ }
+}
+
+SvxUnoPropertyMapProvider::~SvxUnoPropertyMapProvider()
+{
+}
+
+
+const SfxItemPropertyMapEntry* SvxUnoPropertyMapProvider::GetMap(sal_uInt16 nPropertyId)
+{
+ assert(nPropertyId < SVXMAP_END);
+ if(!aMapArr[nPropertyId]) {
+ switch(nPropertyId) {
+ case SVXMAP_SHAPE: aMapArr[SVXMAP_SHAPE]=ImplGetSvxShapePropertyMap(); break;
+ case SVXMAP_CONNECTOR: aMapArr[SVXMAP_CONNECTOR]=ImplGetSvxConnectorPropertyMap(); break;
+ case SVXMAP_DIMENSIONING: aMapArr[SVXMAP_DIMENSIONING]=ImplGetSvxDimensioningPropertyMap(); break;
+ case SVXMAP_CIRCLE: aMapArr[SVXMAP_CIRCLE]=ImplGetSvxCirclePropertyMap(); break;
+ case SVXMAP_POLYPOLYGON: aMapArr[SVXMAP_POLYPOLYGON]=ImplGetSvxPolyPolygonPropertyMap(); break;
+ case SVXMAP_GRAPHICOBJECT: aMapArr[SVXMAP_GRAPHICOBJECT]=ImplGetSvxGraphicObjectPropertyMap(); break;
+ case SVXMAP_3DSCENEOBJECT: aMapArr[SVXMAP_3DSCENEOBJECT]=ImplGetSvx3DSceneObjectPropertyMap(); break;
+ case SVXMAP_3DCUBEOBJECT: aMapArr[SVXMAP_3DCUBEOBJECT]=ImplGetSvx3DCubeObjectPropertyMap(); break;
+ case SVXMAP_3DSPHEREOBJECT: aMapArr[SVXMAP_3DSPHEREOBJECT]=ImplGetSvx3DSphereObjectPropertyMap(); break;
+ case SVXMAP_3DLATHEOBJECT: aMapArr[SVXMAP_3DLATHEOBJECT]=ImplGetSvx3DLatheObjectPropertyMap(); break;
+ case SVXMAP_3DEXTRUDEOBJECT: aMapArr[SVXMAP_3DEXTRUDEOBJECT]=ImplGetSvx3DExtrudeObjectPropertyMap(); break;
+ case SVXMAP_3DPOLYGONOBJECT: aMapArr[SVXMAP_3DPOLYGONOBJECT]=ImplGetSvx3DPolygonObjectPropertyMap(); break;
+ case SVXMAP_ALL: aMapArr[SVXMAP_ALL]=ImplGetSvxAllPropertyMap(); break;
+ case SVXMAP_GROUP: aMapArr[SVXMAP_GROUP]=ImplGetSvxGroupPropertyMap(); break;
+ case SVXMAP_CAPTION: aMapArr[SVXMAP_CAPTION]=ImplGetSvxCaptionPropertyMap(); break;
+ case SVXMAP_OLE2: aMapArr[SVXMAP_OLE2]=ImplGetSvxOle2PropertyMap(); break;
+ case SVXMAP_PLUGIN: aMapArr[SVXMAP_PLUGIN]=ImplGetSvxPluginPropertyMap(); break;
+ case SVXMAP_FRAME: aMapArr[SVXMAP_FRAME]=ImplGetSvxFramePropertyMap(); break;
+ case SVXMAP_APPLET: aMapArr[SVXMAP_APPLET]=ImplGetSvxAppletPropertyMap(); break;
+ case SVXMAP_CONTROL: aMapArr[SVXMAP_CONTROL]=ImplGetSvxControlShapePropertyMap(); break;
+ case SVXMAP_TEXT: aMapArr[SVXMAP_TEXT]=ImplGetSvxTextShapePropertyMap(); break;
+ case SVXMAP_CUSTOMSHAPE: aMapArr[SVXMAP_CUSTOMSHAPE]=ImplGetSvxCustomShapePropertyMap(); break;
+ case SVXMAP_MEDIA: aMapArr[SVXMAP_MEDIA]=ImplGetSvxMediaShapePropertyMap(); break;
+ case SVXMAP_TABLE: aMapArr[SVXMAP_TABLE]=ImplGetSvxTableShapePropertyMap(); break;
+ case SVXMAP_PAGE: aMapArr[SVXMAP_PAGE] = ImplGetSvxPageShapePropertyMap(); break;
+
+ default:
+ OSL_FAIL( "Unknown property map for SvxUnoPropertyMapProvider!" );
+ }
+// Sort(nPropertyId);
+ }
+ return aMapArr[nPropertyId];
+}
+const SvxItemPropertySet* SvxUnoPropertyMapProvider::GetPropertySet(sal_uInt16 nPropertyId, SfxItemPool& rPool)
+{
+ if( !aSetArr[nPropertyId] )
+ aSetArr[nPropertyId].reset(new SvxItemPropertySet( GetMap( nPropertyId ), rPool ));
+ return aSetArr[nPropertyId].get();
+}
+
+/** maps the vcl MapUnit enum to an API constant MeasureUnit.
+ Returns false if conversion is not supported.
+*/
+bool SvxMapUnitToMeasureUnit( const MapUnit eVcl, short& eApi ) noexcept
+{
+ switch( eVcl )
+ {
+ case MapUnit::Map100thMM: eApi = util::MeasureUnit::MM_100TH; break;
+ case MapUnit::Map10thMM: eApi = util::MeasureUnit::MM_10TH; break;
+ case MapUnit::MapMM: eApi = util::MeasureUnit::MM; break;
+ case MapUnit::MapCM: eApi = util::MeasureUnit::CM; break;
+ case MapUnit::Map1000thInch: eApi = util::MeasureUnit::INCH_1000TH; break;
+ case MapUnit::Map100thInch: eApi = util::MeasureUnit::INCH_100TH; break;
+ case MapUnit::Map10thInch: eApi = util::MeasureUnit::INCH_10TH; break;
+ case MapUnit::MapInch: eApi = util::MeasureUnit::INCH; break;
+ case MapUnit::MapPoint: eApi = util::MeasureUnit::POINT; break;
+ case MapUnit::MapTwip: eApi = util::MeasureUnit::TWIP; break;
+ case MapUnit::MapRelative: eApi = util::MeasureUnit::PERCENT; break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/** maps the API constant MeasureUnit to a vcl MapUnit enum.
+ Returns false if conversion is not supported.
+*/
+
+bool SvxMeasureUnitToFieldUnit( const short eApi, FieldUnit& eVcl ) noexcept
+{
+ switch( eApi )
+ {
+ case util::MeasureUnit::MM: eVcl = FieldUnit::MM; break;
+ case util::MeasureUnit::CM: eVcl = FieldUnit::CM; break;
+ case util::MeasureUnit::M: eVcl = FieldUnit::M; break;
+ case util::MeasureUnit::KM: eVcl = FieldUnit::KM; break;
+ case util::MeasureUnit::TWIP: eVcl = FieldUnit::TWIP; break;
+ case util::MeasureUnit::POINT: eVcl = FieldUnit::POINT; break;
+ case util::MeasureUnit::PICA: eVcl = FieldUnit::PICA; break;
+ case util::MeasureUnit::INCH: eVcl = FieldUnit::INCH; break;
+ case util::MeasureUnit::FOOT: eVcl = FieldUnit::FOOT; break;
+ case util::MeasureUnit::MILE: eVcl = FieldUnit::MILE; break;
+ case util::MeasureUnit::PERCENT: eVcl = FieldUnit::PERCENT; break;
+ case util::MeasureUnit::MM_100TH: eVcl = FieldUnit::MM_100TH; break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/** maps the vcl MapUnit enum to an API constant MeasureUnit.
+ Returns false if conversion is not supported.
+*/
+bool SvxFieldUnitToMeasureUnit( const FieldUnit eVcl, short& eApi ) noexcept
+{
+ switch( eVcl )
+ {
+ case FieldUnit::MM: eApi = util::MeasureUnit::MM; break;
+ case FieldUnit::CM: eApi = util::MeasureUnit::CM; break;
+ case FieldUnit::M: eApi = util::MeasureUnit::M; break;
+ case FieldUnit::KM: eApi = util::MeasureUnit::KM; break;
+ case FieldUnit::TWIP: eApi = util::MeasureUnit::TWIP; break;
+ case FieldUnit::POINT: eApi = util::MeasureUnit::POINT; break;
+ case FieldUnit::PICA: eApi = util::MeasureUnit::PICA; break;
+ case FieldUnit::INCH: eApi = util::MeasureUnit::INCH; break;
+ case FieldUnit::FOOT: eApi = util::MeasureUnit::FOOT; break;
+ case FieldUnit::MILE: eApi = util::MeasureUnit::MILE; break;
+ case FieldUnit::PERCENT: eApi = util::MeasureUnit::PERCENT; break;
+ case FieldUnit::MM_100TH: eApi = util::MeasureUnit::MM_100TH; break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+constexpr rtl::OUStringConstExpr RID_SVXSTR_BMP_DEF[] =
+{
+ RID_SVXSTR_BMP0_DEF,
+ RID_SVXSTR_BMP1_DEF,
+ RID_SVXSTR_BMP2_DEF,
+ RID_SVXSTR_BMP3_DEF,
+ RID_SVXSTR_BMP4_DEF,
+ RID_SVXSTR_BMP5_DEF,
+ RID_SVXSTR_BMP6_DEF,
+ RID_SVXSTR_BMP7_DEF,
+ RID_SVXSTR_BMP8_DEF,
+ RID_SVXSTR_BMP9_DEF,
+ RID_SVXSTR_BMP10_DEF,
+ RID_SVXSTR_BMP11_DEF,
+ RID_SVXSTR_BMP12_DEF,
+ RID_SVXSTR_BMP13_DEF,
+ RID_SVXSTR_BMP14_DEF,
+ RID_SVXSTR_BMP15_DEF,
+ RID_SVXSTR_BMP16_DEF,
+ RID_SVXSTR_BMP17_DEF,
+ RID_SVXSTR_BMP18_DEF,
+ RID_SVXSTR_BMP19_DEF,
+ RID_SVXSTR_BMP20_DEF,
+ RID_SVXSTR_BMP21_DEF,
+ RID_SVXSTR_BMP22_DEF,
+ RID_SVXSTR_BMP23_DEF,
+ RID_SVXSTR_BMP24_DEF,
+ RID_SVXSTR_BMP25_DEF,
+ RID_SVXSTR_BMP26_DEF,
+ RID_SVXSTR_BMP27_DEF,
+ RID_SVXSTR_BMP28_DEF,
+ RID_SVXSTR_BMP29_DEF,
+ RID_SVXSTR_BMP30_DEF,
+ RID_SVXSTR_BMP31_DEF,
+ RID_SVXSTR_BMP32_DEF,
+ RID_SVXSTR_BMP33_DEF,
+ RID_SVXSTR_BMP34_DEF,
+ RID_SVXSTR_BMP35_DEF,
+ RID_SVXSTR_BMP36_DEF,
+ RID_SVXSTR_BMP37_DEF,
+ RID_SVXSTR_BMP38_DEF,
+ RID_SVXSTR_BMP39_DEF,
+ RID_SVXSTR_BMP40_DEF,
+ RID_SVXSTR_BMP41_DEF,
+ RID_SVXSTR_BMP42_DEF,
+ RID_SVXSTR_BMP43_DEF,
+ RID_SVXSTR_BMP44_DEF,
+ RID_SVXSTR_BMP45_DEF,
+ RID_SVXSTR_BMP46_DEF,
+ RID_SVXSTR_BMP47_DEF,
+ RID_SVXSTR_BMP48_DEF,
+ RID_SVXSTR_BMP49_DEF,
+ RID_SVXSTR_BMP50_DEF,
+ RID_SVXSTR_BMP51_DEF,
+ RID_SVXSTR_BMP52_DEF,
+ RID_SVXSTR_BMP53_DEF,
+ RID_SVXSTR_BMP54_DEF,
+ RID_SVXSTR_BMP55_DEF,
+ RID_SVXSTR_BMP56_DEF,
+ RID_SVXSTR_BMP57_DEF,
+ RID_SVXSTR_BMP58_DEF,
+ RID_SVXSTR_BMP59_DEF,
+ RID_SVXSTR_BMP60_DEF,
+ RID_SVXSTR_BMP61_DEF,
+ RID_SVXSTR_BMP62_DEF,
+ RID_SVXSTR_BMP63_DEF,
+ RID_SVXSTR_BMP64_DEF,
+ RID_SVXSTR_BMP65_DEF,
+ RID_SVXSTR_BMP66_DEF,
+ RID_SVXSTR_BMP67_DEF,
+ RID_SVXSTR_BMP68_DEF,
+ RID_SVXSTR_BMP69_DEF,
+ RID_SVXSTR_BMP70_DEF,
+ RID_SVXSTR_BMP71_DEF,
+ RID_SVXSTR_BMP72_DEF,
+ RID_SVXSTR_BMP73_DEF,
+ RID_SVXSTR_BMP74_DEF,
+ RID_SVXSTR_BMP75_DEF,
+ RID_SVXSTR_BMP76_DEF,
+ RID_SVXSTR_BMP77_DEF,
+ RID_SVXSTR_BMP78_DEF,
+ RID_SVXSTR_BMP79_DEF,
+ RID_SVXSTR_BMP80_DEF,
+ RID_SVXSTR_BMP81_DEF,
+ RID_SVXSTR_BMP82_DEF,
+ RID_SVXSTR_BMP83_DEF,
+ RID_SVXSTR_BMP84_DEF,
+ RID_SVXSTR_BMP85_DEF,
+ RID_SVXSTR_BMP86_DEF,
+ RID_SVXSTR_BMP87_DEF,
+ RID_SVXSTR_BMP88_DEF,
+ RID_SVXSTR_BMP89_DEF,
+ RID_SVXSTR_BMP90_DEF,
+ RID_SVXSTR_BMP91_DEF,
+ RID_SVXSTR_BMP92_DEF
+};
+
+const TranslateId RID_SVXSTR_BMP[] =
+{
+ RID_SVXSTR_BMP0,
+ RID_SVXSTR_BMP1,
+ RID_SVXSTR_BMP2,
+ RID_SVXSTR_BMP3,
+ RID_SVXSTR_BMP4,
+ RID_SVXSTR_BMP5,
+ RID_SVXSTR_BMP6,
+ RID_SVXSTR_BMP7,
+ RID_SVXSTR_BMP8,
+ RID_SVXSTR_BMP9,
+ RID_SVXSTR_BMP10,
+ RID_SVXSTR_BMP11,
+ RID_SVXSTR_BMP12,
+ RID_SVXSTR_BMP13,
+ RID_SVXSTR_BMP14,
+ RID_SVXSTR_BMP15,
+ RID_SVXSTR_BMP16,
+ RID_SVXSTR_BMP17,
+ RID_SVXSTR_BMP18,
+ RID_SVXSTR_BMP19,
+ RID_SVXSTR_BMP20,
+ RID_SVXSTR_BMP21,
+ RID_SVXSTR_BMP22,
+ RID_SVXSTR_BMP23,
+ RID_SVXSTR_BMP24,
+ RID_SVXSTR_BMP25,
+ RID_SVXSTR_BMP26,
+ RID_SVXSTR_BMP27,
+ RID_SVXSTR_BMP28,
+ RID_SVXSTR_BMP29,
+ RID_SVXSTR_BMP30,
+ RID_SVXSTR_BMP31,
+ RID_SVXSTR_BMP32,
+ RID_SVXSTR_BMP33,
+ RID_SVXSTR_BMP34,
+ RID_SVXSTR_BMP35,
+ RID_SVXSTR_BMP36,
+ RID_SVXSTR_BMP37,
+ RID_SVXSTR_BMP38,
+ RID_SVXSTR_BMP39,
+ RID_SVXSTR_BMP40,
+ RID_SVXSTR_BMP41,
+ RID_SVXSTR_BMP42,
+ RID_SVXSTR_BMP43,
+ RID_SVXSTR_BMP44,
+ RID_SVXSTR_BMP45,
+ RID_SVXSTR_BMP46,
+ RID_SVXSTR_BMP47,
+ RID_SVXSTR_BMP48,
+ RID_SVXSTR_BMP49,
+ RID_SVXSTR_BMP50,
+ RID_SVXSTR_BMP51,
+ RID_SVXSTR_BMP52,
+ RID_SVXSTR_BMP53,
+ RID_SVXSTR_BMP54,
+ RID_SVXSTR_BMP55,
+ RID_SVXSTR_BMP56,
+ RID_SVXSTR_BMP57,
+ RID_SVXSTR_BMP58,
+ RID_SVXSTR_BMP59,
+ RID_SVXSTR_BMP60,
+ RID_SVXSTR_BMP61,
+ RID_SVXSTR_BMP62,
+ RID_SVXSTR_BMP63,
+ RID_SVXSTR_BMP64,
+ RID_SVXSTR_BMP65,
+ RID_SVXSTR_BMP66,
+ RID_SVXSTR_BMP67,
+ RID_SVXSTR_BMP68,
+ RID_SVXSTR_BMP69,
+ RID_SVXSTR_BMP70,
+ RID_SVXSTR_BMP71,
+ RID_SVXSTR_BMP72,
+ RID_SVXSTR_BMP73,
+ RID_SVXSTR_BMP74,
+ RID_SVXSTR_BMP75,
+ RID_SVXSTR_BMP76,
+ RID_SVXSTR_BMP77,
+ RID_SVXSTR_BMP78,
+ RID_SVXSTR_BMP79,
+ RID_SVXSTR_BMP80,
+ RID_SVXSTR_BMP81,
+ RID_SVXSTR_BMP82,
+ RID_SVXSTR_BMP83,
+ RID_SVXSTR_BMP84,
+ RID_SVXSTR_BMP85,
+ RID_SVXSTR_BMP86,
+ RID_SVXSTR_BMP87,
+ RID_SVXSTR_BMP88,
+ RID_SVXSTR_BMP89,
+ RID_SVXSTR_BMP90,
+ RID_SVXSTR_BMP91,
+ RID_SVXSTR_BMP92
+};
+
+constexpr rtl::OUStringConstExpr RID_SVXSTR_DASH_DEF[] =
+{
+ RID_SVXSTR_DASH0_DEF,
+ RID_SVXSTR_DASH1_DEF,
+ RID_SVXSTR_DASH2_DEF,
+ RID_SVXSTR_DASH3_DEF,
+ RID_SVXSTR_DASH4_DEF,
+ RID_SVXSTR_DASH5_DEF,
+ RID_SVXSTR_DASH6_DEF,
+ RID_SVXSTR_DASH7_DEF,
+ RID_SVXSTR_DASH8_DEF,
+ RID_SVXSTR_DASH9_DEF,
+ RID_SVXSTR_DASH10_DEF,
+ RID_SVXSTR_DASH11_DEF,
+ RID_SVXSTR_DASH12_DEF,
+ RID_SVXSTR_DASH13_DEF,
+ RID_SVXSTR_DASH14_DEF,
+ RID_SVXSTR_DASH15_DEF,
+ RID_SVXSTR_DASH16_DEF,
+ RID_SVXSTR_DASH17_DEF,
+ RID_SVXSTR_DASH18_DEF,
+ RID_SVXSTR_DASH19_DEF,
+ RID_SVXSTR_DASH20_DEF,
+ RID_SVXSTR_DASH21_DEF,
+ RID_SVXSTR_DASH22_DEF,
+ RID_SVXSTR_DASH23_DEF,
+ RID_SVXSTR_DASH24_DEF,
+ RID_SVXSTR_DASH25_DEF,
+ RID_SVXSTR_DASH26_DEF,
+ RID_SVXSTR_DASH27_DEF,
+ RID_SVXSTR_DASH28_DEF,
+ RID_SVXSTR_DASH29_DEF,
+ RID_SVXSTR_DASH30_DEF
+
+};
+
+const TranslateId RID_SVXSTR_DASH[] =
+{
+ RID_SVXSTR_DASH0,
+ RID_SVXSTR_DASH1,
+ RID_SVXSTR_DASH2,
+ RID_SVXSTR_DASH3,
+ RID_SVXSTR_DASH4,
+ RID_SVXSTR_DASH5,
+ RID_SVXSTR_DASH6,
+ RID_SVXSTR_DASH7,
+ RID_SVXSTR_DASH8,
+ RID_SVXSTR_DASH9,
+ RID_SVXSTR_DASH10,
+ RID_SVXSTR_DASH11,
+ RID_SVXSTR_DASH12,
+ RID_SVXSTR_DASH13,
+ RID_SVXSTR_DASH14,
+ RID_SVXSTR_DASH15,
+ RID_SVXSTR_DASH16,
+ RID_SVXSTR_DASH17,
+ RID_SVXSTR_DASH18,
+ RID_SVXSTR_DASH19,
+ RID_SVXSTR_DASH20,
+ RID_SVXSTR_DASH21,
+ RID_SVXSTR_DASH22,
+ RID_SVXSTR_DASH23,
+ RID_SVXSTR_DASH24,
+ RID_SVXSTR_DASH25,
+ RID_SVXSTR_DASH26,
+ RID_SVXSTR_DASH27,
+ RID_SVXSTR_DASH28,
+ RID_SVXSTR_DASH29,
+ RID_SVXSTR_DASH30
+};
+
+constexpr rtl::OUStringConstExpr RID_SVXSTR_LEND_DEF[] =
+{
+ RID_SVXSTR_LEND0_DEF,
+ RID_SVXSTR_LEND1_DEF,
+ RID_SVXSTR_LEND2_DEF,
+ RID_SVXSTR_LEND3_DEF,
+ RID_SVXSTR_LEND4_DEF,
+ RID_SVXSTR_LEND5_DEF,
+ RID_SVXSTR_LEND6_DEF,
+ RID_SVXSTR_LEND7_DEF,
+ RID_SVXSTR_LEND8_DEF,
+ RID_SVXSTR_LEND9_DEF,
+ RID_SVXSTR_LEND10_DEF,
+ RID_SVXSTR_LEND11_DEF,
+ RID_SVXSTR_LEND12_DEF,
+ RID_SVXSTR_LEND13_DEF,
+ RID_SVXSTR_LEND14_DEF,
+ RID_SVXSTR_LEND15_DEF,
+ RID_SVXSTR_LEND16_DEF,
+ RID_SVXSTR_LEND17_DEF,
+ RID_SVXSTR_LEND18_DEF,
+ RID_SVXSTR_LEND19_DEF,
+ RID_SVXSTR_LEND20_DEF,
+ RID_SVXSTR_LEND21_DEF,
+ RID_SVXSTR_LEND22_DEF,
+ RID_SVXSTR_LEND23_DEF,
+ RID_SVXSTR_LEND24_DEF,
+ RID_SVXSTR_LEND25_DEF,
+ RID_SVXSTR_LEND26_DEF,
+ RID_SVXSTR_LEND27_DEF,
+ RID_SVXSTR_LEND28_DEF,
+ RID_SVXSTR_LEND29_DEF,
+ RID_SVXSTR_LEND30_DEF,
+ RID_SVXSTR_LEND31_DEF
+};
+
+const TranslateId RID_SVXSTR_LEND[] =
+{
+ RID_SVXSTR_LEND0,
+ RID_SVXSTR_LEND1,
+ RID_SVXSTR_LEND2,
+ RID_SVXSTR_LEND3,
+ RID_SVXSTR_LEND4,
+ RID_SVXSTR_LEND5,
+ RID_SVXSTR_LEND6,
+ RID_SVXSTR_LEND7,
+ RID_SVXSTR_LEND8,
+ RID_SVXSTR_LEND9,
+ RID_SVXSTR_LEND10,
+ RID_SVXSTR_LEND11,
+ RID_SVXSTR_LEND12,
+ RID_SVXSTR_LEND13,
+ RID_SVXSTR_LEND14,
+ RID_SVXSTR_LEND15,
+ RID_SVXSTR_LEND16,
+ RID_SVXSTR_LEND17,
+ RID_SVXSTR_LEND18,
+ RID_SVXSTR_LEND19,
+ RID_SVXSTR_LEND20,
+ RID_SVXSTR_LEND21,
+ RID_SVXSTR_LEND22,
+ RID_SVXSTR_LEND23,
+ RID_SVXSTR_LEND24,
+ RID_SVXSTR_LEND25,
+ RID_SVXSTR_LEND26,
+ RID_SVXSTR_LEND27,
+ RID_SVXSTR_LEND28,
+ RID_SVXSTR_LEND29,
+ RID_SVXSTR_LEND30,
+ RID_SVXSTR_LEND31
+};
+
+constexpr rtl::OUStringConstExpr RID_SVXSTR_GRDT_DEF[] =
+{
+ RID_SVXSTR_GRDT0_DEF,
+ RID_SVXSTR_GRDT1_DEF,
+ RID_SVXSTR_GRDT2_DEF,
+ RID_SVXSTR_GRDT3_DEF,
+ RID_SVXSTR_GRDT4_DEF,
+ RID_SVXSTR_GRDT5_DEF,
+ RID_SVXSTR_GRDT6_DEF,
+ RID_SVXSTR_GRDT7_DEF,
+ RID_SVXSTR_GRDT8_DEF,
+ RID_SVXSTR_GRDT9_DEF,
+ RID_SVXSTR_GRDT10_DEF,
+ RID_SVXSTR_GRDT11_DEF,
+ RID_SVXSTR_GRDT12_DEF,
+ RID_SVXSTR_GRDT13_DEF,
+ RID_SVXSTR_GRDT14_DEF,
+ RID_SVXSTR_GRDT15_DEF,
+ RID_SVXSTR_GRDT16_DEF,
+ RID_SVXSTR_GRDT17_DEF,
+ RID_SVXSTR_GRDT18_DEF,
+ RID_SVXSTR_GRDT19_DEF,
+ RID_SVXSTR_GRDT20_DEF,
+ RID_SVXSTR_GRDT21_DEF,
+ RID_SVXSTR_GRDT22_DEF,
+ RID_SVXSTR_GRDT23_DEF,
+ RID_SVXSTR_GRDT24_DEF,
+ RID_SVXSTR_GRDT25_DEF,
+ RID_SVXSTR_GRDT26_DEF,
+ RID_SVXSTR_GRDT27_DEF,
+ RID_SVXSTR_GRDT28_DEF,
+ RID_SVXSTR_GRDT29_DEF,
+ RID_SVXSTR_GRDT30_DEF,
+ RID_SVXSTR_GRDT31_DEF,
+ RID_SVXSTR_GRDT32_DEF,
+ RID_SVXSTR_GRDT33_DEF,
+ RID_SVXSTR_GRDT34_DEF,
+ RID_SVXSTR_GRDT35_DEF,
+ RID_SVXSTR_GRDT36_DEF,
+ RID_SVXSTR_GRDT37_DEF,
+ RID_SVXSTR_GRDT38_DEF,
+ RID_SVXSTR_GRDT39_DEF,
+ RID_SVXSTR_GRDT40_DEF,
+ RID_SVXSTR_GRDT41_DEF,
+ RID_SVXSTR_GRDT42_DEF,
+ RID_SVXSTR_GRDT43_DEF,
+ RID_SVXSTR_GRDT44_DEF,
+ RID_SVXSTR_GRDT45_DEF,
+ RID_SVXSTR_GRDT46_DEF,
+ RID_SVXSTR_GRDT47_DEF,
+ RID_SVXSTR_GRDT48_DEF,
+ RID_SVXSTR_GRDT49_DEF,
+ RID_SVXSTR_GRDT50_DEF,
+ RID_SVXSTR_GRDT51_DEF,
+ RID_SVXSTR_GRDT52_DEF,
+ RID_SVXSTR_GRDT53_DEF,
+ RID_SVXSTR_GRDT54_DEF,
+ RID_SVXSTR_GRDT55_DEF,
+ RID_SVXSTR_GRDT56_DEF,
+ RID_SVXSTR_GRDT57_DEF,
+ RID_SVXSTR_GRDT58_DEF,
+ RID_SVXSTR_GRDT59_DEF,
+ RID_SVXSTR_GRDT60_DEF,
+ RID_SVXSTR_GRDT61_DEF,
+ RID_SVXSTR_GRDT62_DEF,
+ RID_SVXSTR_GRDT63_DEF,
+ RID_SVXSTR_GRDT64_DEF,
+ RID_SVXSTR_GRDT65_DEF,
+ RID_SVXSTR_GRDT66_DEF,
+ RID_SVXSTR_GRDT67_DEF,
+ RID_SVXSTR_GRDT68_DEF,
+ RID_SVXSTR_GRDT69_DEF,
+ RID_SVXSTR_GRDT70_DEF,
+ RID_SVXSTR_GRDT71_DEF,
+ RID_SVXSTR_GRDT72_DEF,
+ RID_SVXSTR_GRDT73_DEF,
+ RID_SVXSTR_GRDT74_DEF,
+ RID_SVXSTR_GRDT75_DEF,
+ RID_SVXSTR_GRDT76_DEF,
+ RID_SVXSTR_GRDT77_DEF,
+ RID_SVXSTR_GRDT78_DEF,
+ RID_SVXSTR_GRDT79_DEF,
+ RID_SVXSTR_GRDT80_DEF,
+ RID_SVXSTR_GRDT81_DEF,
+ RID_SVXSTR_GRDT82_DEF,
+ RID_SVXSTR_GRDT83_DEF,
+ RID_SVXSTR_GRDT84_DEF
+};
+
+const TranslateId RID_SVXSTR_GRDT[] =
+{
+ RID_SVXSTR_GRDT0,
+ RID_SVXSTR_GRDT1,
+ RID_SVXSTR_GRDT2,
+ RID_SVXSTR_GRDT3,
+ RID_SVXSTR_GRDT4,
+ RID_SVXSTR_GRDT5,
+ RID_SVXSTR_GRDT6,
+ RID_SVXSTR_GRDT7,
+ RID_SVXSTR_GRDT8,
+ RID_SVXSTR_GRDT9,
+ RID_SVXSTR_GRDT10,
+ RID_SVXSTR_GRDT11,
+ RID_SVXSTR_GRDT12,
+ RID_SVXSTR_GRDT13,
+ RID_SVXSTR_GRDT14,
+ RID_SVXSTR_GRDT15,
+ RID_SVXSTR_GRDT16,
+ RID_SVXSTR_GRDT17,
+ RID_SVXSTR_GRDT18,
+ RID_SVXSTR_GRDT19,
+ RID_SVXSTR_GRDT20,
+ RID_SVXSTR_GRDT21,
+ RID_SVXSTR_GRDT22,
+ RID_SVXSTR_GRDT23,
+ RID_SVXSTR_GRDT24,
+ RID_SVXSTR_GRDT25,
+ RID_SVXSTR_GRDT26,
+ RID_SVXSTR_GRDT27,
+ RID_SVXSTR_GRDT28,
+ RID_SVXSTR_GRDT29,
+ RID_SVXSTR_GRDT30,
+ RID_SVXSTR_GRDT31,
+ RID_SVXSTR_GRDT32,
+ RID_SVXSTR_GRDT33,
+ RID_SVXSTR_GRDT34,
+ RID_SVXSTR_GRDT35,
+ RID_SVXSTR_GRDT36,
+ RID_SVXSTR_GRDT37,
+ RID_SVXSTR_GRDT38,
+ RID_SVXSTR_GRDT39,
+ RID_SVXSTR_GRDT40,
+ RID_SVXSTR_GRDT41,
+ RID_SVXSTR_GRDT42,
+ RID_SVXSTR_GRDT43,
+ RID_SVXSTR_GRDT44,
+ RID_SVXSTR_GRDT45,
+ RID_SVXSTR_GRDT46,
+ RID_SVXSTR_GRDT47,
+ RID_SVXSTR_GRDT48,
+ RID_SVXSTR_GRDT49,
+ RID_SVXSTR_GRDT50,
+ RID_SVXSTR_GRDT51,
+ RID_SVXSTR_GRDT52,
+ RID_SVXSTR_GRDT53,
+ RID_SVXSTR_GRDT54,
+ RID_SVXSTR_GRDT55,
+ RID_SVXSTR_GRDT56,
+ RID_SVXSTR_GRDT57,
+ RID_SVXSTR_GRDT58,
+ RID_SVXSTR_GRDT59,
+ RID_SVXSTR_GRDT60,
+ RID_SVXSTR_GRDT61,
+ RID_SVXSTR_GRDT62,
+ RID_SVXSTR_GRDT63,
+ RID_SVXSTR_GRDT64,
+ RID_SVXSTR_GRDT65,
+ RID_SVXSTR_GRDT66,
+ RID_SVXSTR_GRDT67,
+ RID_SVXSTR_GRDT68,
+ RID_SVXSTR_GRDT69,
+ RID_SVXSTR_GRDT70,
+ RID_SVXSTR_GRDT71,
+ RID_SVXSTR_GRDT72,
+ RID_SVXSTR_GRDT73,
+ RID_SVXSTR_GRDT74,
+ RID_SVXSTR_GRDT75,
+ RID_SVXSTR_GRDT76,
+ RID_SVXSTR_GRDT77,
+ RID_SVXSTR_GRDT78,
+ RID_SVXSTR_GRDT79,
+ RID_SVXSTR_GRDT80,
+ RID_SVXSTR_GRDT81,
+ RID_SVXSTR_GRDT82,
+ RID_SVXSTR_GRDT83,
+ RID_SVXSTR_GRDT84
+};
+
+constexpr rtl::OUStringConstExpr RID_SVXSTR_HATCHS_DEF[] =
+{
+ RID_SVXSTR_HATCH0_DEF,
+ RID_SVXSTR_HATCH1_DEF,
+ RID_SVXSTR_HATCH2_DEF,
+ RID_SVXSTR_HATCH3_DEF,
+ RID_SVXSTR_HATCH4_DEF,
+ RID_SVXSTR_HATCH5_DEF,
+ RID_SVXSTR_HATCH6_DEF,
+ RID_SVXSTR_HATCH7_DEF,
+ RID_SVXSTR_HATCH8_DEF,
+ RID_SVXSTR_HATCH9_DEF,
+ RID_SVXSTR_HATCH10_DEF,
+ RID_SVXSTR_HATCH11_DEF,
+ RID_SVXSTR_HATCH12_DEF,
+ RID_SVXSTR_HATCH13_DEF,
+ RID_SVXSTR_HATCH14_DEF,
+ RID_SVXSTR_HATCH15_DEF
+};
+
+const TranslateId RID_SVXSTR_HATCHS[] =
+{
+ RID_SVXSTR_HATCH0,
+ RID_SVXSTR_HATCH1,
+ RID_SVXSTR_HATCH2,
+ RID_SVXSTR_HATCH3,
+ RID_SVXSTR_HATCH4,
+ RID_SVXSTR_HATCH5,
+ RID_SVXSTR_HATCH6,
+ RID_SVXSTR_HATCH7,
+ RID_SVXSTR_HATCH8,
+ RID_SVXSTR_HATCH9,
+ RID_SVXSTR_HATCH10,
+ RID_SVXSTR_HATCH11,
+ RID_SVXSTR_HATCH12,
+ RID_SVXSTR_HATCH13,
+ RID_SVXSTR_HATCH14,
+ RID_SVXSTR_HATCH15
+};
+
+constexpr rtl::OUStringConstExpr RID_SVXSTR_TRASNGR_DEF[] =
+{
+ RID_SVXSTR_TRASNGR0_DEF
+};
+
+const TranslateId RID_SVXSTR_TRASNGR[] =
+{
+ RID_SVXSTR_TRASNGR0
+};
+
+static bool SvxUnoGetResourceRanges( const sal_uInt16 nWhich, const rtl::OUStringConstExpr*& pApiResIds, const TranslateId*& pIntResIds, int& nCount ) noexcept
+{
+ switch( nWhich )
+ {
+ case XATTR_FILLBITMAP:
+ pApiResIds = RID_SVXSTR_BMP_DEF;
+ pIntResIds = RID_SVXSTR_BMP;
+ nCount = SAL_N_ELEMENTS(RID_SVXSTR_BMP_DEF);
+ break;
+ case XATTR_LINEDASH:
+ pApiResIds = RID_SVXSTR_DASH_DEF;
+ pIntResIds = RID_SVXSTR_DASH;
+ nCount = SAL_N_ELEMENTS(RID_SVXSTR_DASH_DEF);
+ break;
+
+ case XATTR_LINESTART:
+ case XATTR_LINEEND:
+ pApiResIds = RID_SVXSTR_LEND_DEF;
+ pIntResIds = RID_SVXSTR_LEND;
+ nCount = SAL_N_ELEMENTS(RID_SVXSTR_LEND_DEF);
+ break;
+
+ case XATTR_FILLGRADIENT:
+ pApiResIds = RID_SVXSTR_GRDT_DEF;
+ pIntResIds = RID_SVXSTR_GRDT;
+ nCount = SAL_N_ELEMENTS(RID_SVXSTR_GRDT_DEF);
+ break;
+
+ case XATTR_FILLHATCH:
+ pApiResIds = RID_SVXSTR_HATCHS_DEF;
+ pIntResIds = RID_SVXSTR_HATCHS;
+ nCount = SAL_N_ELEMENTS(RID_SVXSTR_HATCHS_DEF);
+ break;
+
+ case XATTR_FILLFLOATTRANSPARENCE:
+ pApiResIds = RID_SVXSTR_TRASNGR_DEF;
+ pIntResIds = RID_SVXSTR_TRASNGR;
+ nCount = SAL_N_ELEMENTS(RID_SVXSTR_TRASNGR_DEF);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+/// @throws std::exception
+static bool SvxUnoConvertResourceStringToApi(const TranslateId* pSourceResIds, const rtl::OUStringConstExpr* pDestResIds, int nCount, OUString& rString)
+{
+ // first, calculate the search string length without an optional number after the name
+ sal_Int32 nLength = rString.getLength();
+ while( nLength > 0 )
+ {
+ const sal_Unicode nChar = rString[ nLength - 1 ];
+ if( (nChar < '0') || (nChar > '9') )
+ break;
+
+ nLength--;
+ }
+
+ // if we cut off a number, also cut of some spaces
+ if( nLength != rString.getLength() )
+ {
+ while( nLength > 0 )
+ {
+ const sal_Unicode nChar = rString[ nLength - 1 ];
+ if( nChar != ' ' )
+ break;
+
+ nLength--;
+ }
+ }
+
+ const std::u16string_view aShortString( rString.subView( 0, nLength ) );
+
+ for (int i = 0; i < nCount; ++i)
+ {
+ const OUString & aCompare = SvxResId(pSourceResIds[i]);
+ if( aShortString == aCompare )
+ {
+ rString = rString.replaceAt( 0, aShortString.size(), OUString(pDestResIds[i]) );
+ return true;
+ }
+ else if( rString == aCompare )
+ {
+ rString = pDestResIds[i];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool SvxUnoConvertResourceStringFromApi(const rtl::OUStringConstExpr* pSourceResIds, const TranslateId* pDestResIds, int nCount, OUString& rString)
+{
+ // first, calculate the search string length without an optional number after the name
+ sal_Int32 nLength = rString.getLength();
+ while( nLength > 0 )
+ {
+ const sal_Unicode nChar = rString[ nLength - 1 ];
+ if( (nChar < '0') || (nChar > '9') )
+ break;
+
+ nLength--;
+ }
+
+ // if we cut off a number, also cut of some spaces
+ if( nLength != rString.getLength() )
+ {
+ while( nLength > 0 )
+ {
+ const sal_Unicode nChar = rString[ nLength - 1 ];
+ if( nChar != ' ' )
+ break;
+
+ nLength--;
+ }
+ }
+
+ const std::u16string_view aShortString( rString.subView( 0, nLength ) );
+
+ for (int i = 0; i < nCount; ++i)
+ {
+ auto pCompare = pSourceResIds[i];
+ if( aShortString == pCompare.asView() )
+ {
+ rString = rString.replaceAt( 0, aShortString.size(), SvxResId(pDestResIds[i]) );
+ return true;
+ }
+ else if( rString == pCompare )
+ {
+ rString = SvxResId(pDestResIds[i]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// #i122649# Some comments on the below arrays:
+// - They need to have the same order and count of items
+// - They are used to translate between translated and non-translated color names
+// - To make longer names be found which start with the same basic string,
+// these have to be in front of others
+
+// It would be nice to:
+// - evtl. organize these in a single array with 2-dimensional inner to eliminate
+// the possibility to define it wrong
+// - change the compare to also work when a shorter name is in front of a longer one
+
+constexpr rtl::OUStringConstExpr SvxUnoColorNameDefResId[] =
+{
+ RID_SVXSTR_COLOR_BLUEGREY_DEF,
+ RID_SVXSTR_COLOR_BLACK_DEF,
+ RID_SVXSTR_COLOR_BLUE_CLASSIC_DEF,
+ RID_SVXSTR_COLOR_BLUE_DEF,
+ RID_SVXSTR_COLOR_GREEN_DEF,
+ RID_SVXSTR_COLOR_RED_DEF,
+ RID_SVXSTR_COLOR_MAGENTA_DEF,
+ RID_SVXSTR_COLOR_GREY_DEF,
+ RID_SVXSTR_COLOR_YELLOWGREEN_DEF,
+ RID_SVXSTR_COLOR_YELLOW_DEF,
+ RID_SVXSTR_COLOR_WHITE_DEF,
+ RID_SVXSTR_COLOR_ORANGE_DEF,
+ RID_SVXSTR_COLOR_BORDEAUX_DEF,
+ RID_SVXSTR_COLOR_PALE_YELLOW_DEF,
+ RID_SVXSTR_COLOR_PALE_GREEN_DEF,
+ RID_SVXSTR_COLOR_DARKVIOLET_DEF,
+ RID_SVXSTR_COLOR_SALMON_DEF,
+ RID_SVXSTR_COLOR_SEABLUE_DEF,
+ RID_SVXSTR_COLOR_CHART_DEF,
+ RID_SVXSTR_COLOR_PURPLE_DEF,
+ RID_SVXSTR_COLOR_SKYBLUE_DEF,
+ RID_SVXSTR_COLOR_PINK_DEF,
+ RID_SVXSTR_COLOR_TURQUOISE_DEF,
+ RID_SVXSTR_COLOR_GOLD_DEF,
+ RID_SVXSTR_COLOR_BRICK_DEF,
+ RID_SVXSTR_COLOR_INDIGO_DEF,
+ RID_SVXSTR_COLOR_TEAL_DEF,
+ RID_SVXSTR_COLOR_LIME_DEF,
+ RID_SVXSTR_COLOR_LIGHTGRAY_DEF,
+ RID_SVXSTR_COLOR_LIGHTYELLOW_DEF,
+ RID_SVXSTR_COLOR_LIGHTGOLD_DEF,
+ RID_SVXSTR_COLOR_LIGHTORANGE_DEF,
+ RID_SVXSTR_COLOR_LIGHTBRICK_DEF,
+ RID_SVXSTR_COLOR_LIGHTRED_DEF,
+ RID_SVXSTR_COLOR_LIGHTMAGENTA_DEF,
+ RID_SVXSTR_COLOR_LIGHTPURPLE_DEF,
+ RID_SVXSTR_COLOR_LIGHTINDIGO_DEF,
+ RID_SVXSTR_COLOR_LIGHTBLUE_DEF,
+ RID_SVXSTR_COLOR_LIGHTTEAL_DEF,
+ RID_SVXSTR_COLOR_LIGHTGREEN_DEF,
+ RID_SVXSTR_COLOR_LIGHTLIME_DEF,
+ RID_SVXSTR_COLOR_DARKGRAY_DEF,
+ RID_SVXSTR_COLOR_DARKYELLOW_DEF,
+ RID_SVXSTR_COLOR_DARKGOLD_DEF,
+ RID_SVXSTR_COLOR_DARKORANGE_DEF,
+ RID_SVXSTR_COLOR_DARKBRICK_DEF,
+ RID_SVXSTR_COLOR_DARKRED_DEF,
+ RID_SVXSTR_COLOR_DARKMAGENTA_DEF,
+ RID_SVXSTR_COLOR_DARKPURPLE_DEF,
+ RID_SVXSTR_COLOR_DARKINDIGO_DEF,
+ RID_SVXSTR_COLOR_DARKBLUE_DEF,
+ RID_SVXSTR_COLOR_DARKTEAL_DEF,
+ RID_SVXSTR_COLOR_DARKGREEN_DEF,
+ RID_SVXSTR_COLOR_DARKLIME_DEF,
+ RID_SVXSTR_COLOR_VIOLET_DEF,
+ RID_SVXSTR_COLOR_VIOLET_OUG_DEF,
+ RID_SVXSTR_COLOR_BLUE_OUG_DEF,
+ RID_SVXSTR_COLOR_AZURE_OUG_DEF,
+ RID_SVXSTR_COLOR_SPRINGGREEN_OUG_DEF,
+ RID_SVXSTR_COLOR_GREEN_OUG_DEF,
+ RID_SVXSTR_COLOR_CHARTREUSEGREEN_OUG_DEF,
+ RID_SVXSTR_COLOR_ORANGE_OUG_DEF,
+ RID_SVXSTR_COLOR_RED_OUG_DEF,
+ RID_SVXSTR_COLOR_ROSE_OUG_DEF,
+ RID_SVXSTR_COLOR_AZURE_DEF,
+ RID_SVXSTR_COLOR_CYAN_DEF,
+ RID_SVXSTR_COLOR_SPRINGGREEN_DEF,
+ RID_SVXSTR_COLOR_CHARTREUSEGREEN_DEF,
+ RID_SVXSTR_COLOR_ROSE_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_GRAY_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_YELLOW_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_AMBER_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_AMBER_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_ORANGE_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_DEEP_ORANGE_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_DEEP_ORANGE_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_RED_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_PINK_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_PURPLE_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_DEEP_PURPLE_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_DEEP_PURPLE_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_INDIGO_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_BLUE_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_LIGHT_BLUE_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_CYAN_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_TEAL_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_GREEN_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_LIGHT_GREEN_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_LIME_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_BROWN_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_BROWN_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_BLUE_GRAY_A_DEF,
+ RID_SVXSTR_COLOR_MATERIAL_BLUE_GRAY_DEF,
+ RID_SVXSTR_COLOR_LIBRE_GREEN_1_DEF,
+ RID_SVXSTR_COLOR_LIBRE_GREEN_ACCENT_DEF,
+ RID_SVXSTR_COLOR_LIBRE_BLUE_ACCENT_DEF,
+ RID_SVXSTR_COLOR_LIBRE_ORANGE_ACCENT_DEF,
+ RID_SVXSTR_COLOR_LIBRE_PURPLE_DEF,
+ RID_SVXSTR_COLOR_LIBRE_PURPLE_ACCENT_DEF,
+ RID_SVXSTR_COLOR_LIBRE_YELLOW_ACCENT_DEF
+};
+
+const TranslateId SvxUnoColorNameResId[] =
+{
+ RID_SVXSTR_COLOR_BLUEGREY,
+ RID_SVXSTR_COLOR_BLACK,
+ RID_SVXSTR_COLOR_BLUE_CLASSIC,
+ RID_SVXSTR_COLOR_BLUE,
+ RID_SVXSTR_COLOR_GREEN,
+ RID_SVXSTR_COLOR_RED,
+ RID_SVXSTR_COLOR_MAGENTA,
+ RID_SVXSTR_COLOR_GREY,
+ RID_SVXSTR_COLOR_YELLOWGREEN,
+ RID_SVXSTR_COLOR_YELLOW,
+ RID_SVXSTR_COLOR_WHITE,
+ RID_SVXSTR_COLOR_ORANGE,
+ RID_SVXSTR_COLOR_BORDEAUX,
+ RID_SVXSTR_COLOR_PALE_YELLOW,
+ RID_SVXSTR_COLOR_PALE_GREEN,
+ RID_SVXSTR_COLOR_DARKVIOLET,
+ RID_SVXSTR_COLOR_SALMON,
+ RID_SVXSTR_COLOR_SEABLUE,
+ RID_SVXSTR_COLOR_CHART,
+ RID_SVXSTR_COLOR_PURPLE,
+ RID_SVXSTR_COLOR_SKYBLUE,
+ RID_SVXSTR_COLOR_PINK,
+ RID_SVXSTR_COLOR_TURQUOISE,
+ RID_SVXSTR_COLOR_GOLD,
+ RID_SVXSTR_COLOR_BRICK,
+ RID_SVXSTR_COLOR_INDIGO,
+ RID_SVXSTR_COLOR_TEAL,
+ RID_SVXSTR_COLOR_LIME,
+ RID_SVXSTR_COLOR_LIGHTGRAY,
+ RID_SVXSTR_COLOR_LIGHTYELLOW,
+ RID_SVXSTR_COLOR_LIGHTGOLD,
+ RID_SVXSTR_COLOR_LIGHTORANGE,
+ RID_SVXSTR_COLOR_LIGHTBRICK,
+ RID_SVXSTR_COLOR_LIGHTRED,
+ RID_SVXSTR_COLOR_LIGHTMAGENTA,
+ RID_SVXSTR_COLOR_LIGHTPURPLE,
+ RID_SVXSTR_COLOR_LIGHTINDIGO,
+ RID_SVXSTR_COLOR_LIGHTBLUE,
+ RID_SVXSTR_COLOR_LIGHTTEAL,
+ RID_SVXSTR_COLOR_LIGHTGREEN,
+ RID_SVXSTR_COLOR_LIGHTLIME,
+ RID_SVXSTR_COLOR_DARKGRAY,
+ RID_SVXSTR_COLOR_DARKYELLOW,
+ RID_SVXSTR_COLOR_DARKGOLD,
+ RID_SVXSTR_COLOR_DARKORANGE,
+ RID_SVXSTR_COLOR_DARKBRICK,
+ RID_SVXSTR_COLOR_DARKRED,
+ RID_SVXSTR_COLOR_DARKMAGENTA,
+ RID_SVXSTR_COLOR_DARKPURPLE,
+ RID_SVXSTR_COLOR_DARKINDIGO,
+ RID_SVXSTR_COLOR_DARKBLUE,
+ RID_SVXSTR_COLOR_DARKTEAL,
+ RID_SVXSTR_COLOR_DARKGREEN,
+ RID_SVXSTR_COLOR_DARKLIME,
+ RID_SVXSTR_COLOR_VIOLET,
+ RID_SVXSTR_COLOR_VIOLET_OUG,
+ RID_SVXSTR_COLOR_BLUE_OUG,
+ RID_SVXSTR_COLOR_AZURE_OUG,
+ RID_SVXSTR_COLOR_SPRINGGREEN_OUG,
+ RID_SVXSTR_COLOR_GREEN_OUG,
+ RID_SVXSTR_COLOR_CHARTREUSEGREEN_OUG,
+ RID_SVXSTR_COLOR_ORANGE_OUG,
+ RID_SVXSTR_COLOR_RED_OUG,
+ RID_SVXSTR_COLOR_ROSE_OUG,
+ RID_SVXSTR_COLOR_AZURE,
+ RID_SVXSTR_COLOR_CYAN,
+ RID_SVXSTR_COLOR_SPRINGGREEN,
+ RID_SVXSTR_COLOR_CHARTREUSEGREEN,
+ RID_SVXSTR_COLOR_ROSE,
+ RID_SVXSTR_COLOR_MATERIAL_GRAY_A,
+ RID_SVXSTR_COLOR_MATERIAL_YELLOW_A,
+ RID_SVXSTR_COLOR_MATERIAL_AMBER_A,
+ RID_SVXSTR_COLOR_MATERIAL_AMBER,
+ RID_SVXSTR_COLOR_MATERIAL_ORANGE_A,
+ RID_SVXSTR_COLOR_MATERIAL_DEEP_ORANGE_A,
+ RID_SVXSTR_COLOR_MATERIAL_DEEP_ORANGE,
+ RID_SVXSTR_COLOR_MATERIAL_RED_A,
+ RID_SVXSTR_COLOR_MATERIAL_PINK_A,
+ RID_SVXSTR_COLOR_MATERIAL_PURPLE_A,
+ RID_SVXSTR_COLOR_MATERIAL_DEEP_PURPLE_A,
+ RID_SVXSTR_COLOR_MATERIAL_DEEP_PURPLE,
+ RID_SVXSTR_COLOR_MATERIAL_INDIGO_A,
+ RID_SVXSTR_COLOR_MATERIAL_BLUE_A,
+ RID_SVXSTR_COLOR_MATERIAL_LIGHT_BLUE_A,
+ RID_SVXSTR_COLOR_MATERIAL_CYAN_A,
+ RID_SVXSTR_COLOR_MATERIAL_TEAL_A,
+ RID_SVXSTR_COLOR_MATERIAL_GREEN_A,
+ RID_SVXSTR_COLOR_MATERIAL_LIGHT_GREEN_A,
+ RID_SVXSTR_COLOR_MATERIAL_LIME_A,
+ RID_SVXSTR_COLOR_MATERIAL_BROWN_A,
+ RID_SVXSTR_COLOR_MATERIAL_BROWN,
+ RID_SVXSTR_COLOR_MATERIAL_BLUE_GRAY_A,
+ RID_SVXSTR_COLOR_MATERIAL_BLUE_GRAY,
+ RID_SVXSTR_COLOR_LIBRE_GREEN_1,
+ RID_SVXSTR_COLOR_LIBRE_GREEN_ACCENT,
+ RID_SVXSTR_COLOR_LIBRE_BLUE_ACCENT,
+ RID_SVXSTR_COLOR_LIBRE_ORANGE_ACCENT,
+ RID_SVXSTR_COLOR_LIBRE_PURPLE,
+ RID_SVXSTR_COLOR_LIBRE_PURPLE_ACCENT,
+ RID_SVXSTR_COLOR_LIBRE_YELLOW_ACCENT
+};
+
+/// @throws std::exception
+static bool SvxUnoConvertResourceStringBuiltInToApi(const TranslateId* pSourceResIds, rtl::OUStringConstExpr const *pDestResIds, int nCount, OUString& rString)
+{
+ //We replace e.g. "Gray 10%" with the translation of Gray, but we shouldn't
+ //replace "Red Hat 1" with the translation of Red :-)
+ sal_Int32 nLength = rString.getLength();
+ while( nLength > 0 )
+ {
+ const sal_Unicode nChar = rString[nLength-1];
+ if (nChar != '%' && (nChar < '0' || nChar > '9'))
+ break;
+ nLength--;
+ }
+ std::u16string_view sStr = o3tl::trim(rString.subView(0, nLength));
+
+ for(int i = 0; i < nCount; ++i )
+ {
+ OUString aStrDefName = SvxResId(pSourceResIds[i]);
+ if( sStr == aStrDefName )
+ {
+ OUString aReplace = pDestResIds[i];
+ rString = rString.replaceAt( 0, aStrDefName.getLength(), aReplace );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool SvxUnoConvertResourceStringBuiltInFromApi(rtl::OUStringConstExpr const *pSourceResIds, const TranslateId* pDestResIds, int nCount, OUString& rString)
+{
+ //We replace e.g. "Gray 10%" with the translation of Gray, but we shouldn't
+ //replace "Red Hat 1" with the translation of Red :-)
+ sal_Int32 nLength = rString.getLength();
+ while( nLength > 0 )
+ {
+ const sal_Unicode nChar = rString[nLength-1];
+ if (nChar != '%' && (nChar < '0' || nChar > '9'))
+ break;
+ nLength--;
+ }
+ std::u16string_view sStr = o3tl::trim(rString.subView(0, nLength));
+
+ for(int i = 0; i < nCount; ++i )
+ {
+ if( sStr == pSourceResIds[i].asView() )
+ {
+ OUString aReplace = SvxResId(pDestResIds[i]);
+ rString = aReplace + rString.subView( pSourceResIds[i].asView().size() );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** if the given name is a predefined name for the current language it is replaced by
+ the corresponding api name.
+*/
+OUString SvxUnogetApiNameForItem(const sal_uInt16 nWhich, const OUString& rInternalName)
+{
+ OUString aNew = rInternalName;
+
+ if( nWhich == sal_uInt16(XATTR_LINECOLOR) )
+ {
+ if (SvxUnoConvertResourceStringBuiltInToApi(SvxUnoColorNameResId, SvxUnoColorNameDefResId, SAL_N_ELEMENTS(SvxUnoColorNameResId), aNew))
+ {
+ return aNew;
+ }
+ }
+ else
+ {
+ const rtl::OUStringConstExpr* pApiResIds;
+ const TranslateId* pIntResIds;
+ int nCount;
+
+ if( SvxUnoGetResourceRanges(nWhich, pApiResIds, pIntResIds, nCount))
+ {
+ if (SvxUnoConvertResourceStringToApi(pIntResIds, pApiResIds, nCount, aNew))
+ {
+ return aNew;
+ }
+ }
+ }
+
+ // just use previous name, if nothing else was found.
+ return rInternalName;
+}
+
+/** if the given name is a predefined api name it is replaced by the predefined name
+ for the current language.
+*/
+OUString SvxUnogetInternalNameForItem(const sal_uInt16 nWhich, const OUString& rApiName)
+{
+ OUString aNew = rApiName;
+
+ if( nWhich == sal_uInt16(XATTR_LINECOLOR) )
+ {
+ if (SvxUnoConvertResourceStringBuiltInFromApi(SvxUnoColorNameDefResId, SvxUnoColorNameResId, SAL_N_ELEMENTS(SvxUnoColorNameResId), aNew))
+ {
+ return aNew;
+ }
+ }
+ else
+ {
+ const rtl::OUStringConstExpr* pApiResIds;
+ const TranslateId* pIntResIds;
+ int nCount;
+
+ if (SvxUnoGetResourceRanges(nWhich, pApiResIds, pIntResIds, nCount))
+ {
+ if (SvxUnoConvertResourceStringFromApi(pApiResIds, pIntResIds, nCount, aNew))
+ {
+ return aNew;
+ }
+ }
+ }
+
+ // just use previous name, if nothing else was found.
+ return rApiName;
+}
+
+
+rtl::Reference<comphelper::PropertySetInfo> const & SvxPropertySetInfoPool::getOrCreate( sal_Int32 nServiceId ) noexcept
+{
+ SolarMutexGuard aGuard;
+
+ assert( nServiceId <= SVXUNO_SERVICEID_LASTID );
+
+ if( !mxInfos[ nServiceId ].is() )
+ {
+ mxInfos[nServiceId] = new comphelper::PropertySetInfo();
+
+ switch( nServiceId )
+ {
+ case SVXUNO_SERVICEID_COM_SUN_STAR_DRAWING_DEFAULTS:
+ mxInfos[SVXUNO_SERVICEID_COM_SUN_STAR_DRAWING_DEFAULTS]->add( ImplGetSvxDrawingDefaultsPropertyMap() );
+ break;
+ case SVXUNO_SERVICEID_COM_SUN_STAR_DRAWING_DEFAULTS_WRITER:
+ mxInfos[SVXUNO_SERVICEID_COM_SUN_STAR_DRAWING_DEFAULTS_WRITER]->add( ImplGetSvxDrawingDefaultsPropertyMap() );
+ mxInfos[SVXUNO_SERVICEID_COM_SUN_STAR_DRAWING_DEFAULTS_WRITER]->remove( UNO_NAME_EDIT_PARA_IS_HANGING_PUNCTUATION );
+ // OD 13.10.2003 #i18732# - add property map for writer item 'IsFollowingTextFlow'
+ mxInfos[SVXUNO_SERVICEID_COM_SUN_STAR_DRAWING_DEFAULTS_WRITER]->add( ImplGetAdditionalWriterDrawingDefaultsPropertyMap() );
+ break;
+
+ default:
+ OSL_FAIL( "unknown service id!" );
+ }
+ }
+
+ return mxInfos[ nServiceId ];
+}
+
+rtl::Reference<comphelper::PropertySetInfo> SvxPropertySetInfoPool::mxInfos[SVXUNO_SERVICEID_LASTID+1] = { nullptr };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unoshap2.cxx b/svx/source/unodraw/unoshap2.cxx
new file mode 100644
index 000000000..6972819c3
--- /dev/null
+++ b/svx/source/unodraw/unoshap2.cxx
@@ -0,0 +1,1798 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
+#include <com/sun/star/awt/TextAlign.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/drawing/PointSequenceSequence.hpp>
+#include <com/sun/star/drawing/PointSequence.hpp>
+#include <com/sun/star/drawing/PolygonKind.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/drawing/BarCode.hpp>
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wmf.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/GraphicLoader.hxx>
+
+#include <svx/svdpool.hxx>
+
+#include <editeng/unoprnms.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/unopage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdouno.hxx>
+#include "shapeimpl.hxx"
+#include <svx/unoshprp.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/svdviter.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdopath.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <svx/svdograf.hxx>
+#include <sal/log.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <tools/stream.hxx>
+
+
+#include <memory>
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+
+#define QUERYINT( xint ) \
+ if( rType == cppu::UnoType<xint>::get() ) \
+ aAny <<= Reference< xint >(this)
+
+SvxShapeGroup::SvxShapeGroup(SdrObject* pObj, SvxDrawPage* pDrawPage)
+ : SvxShapeGroupAnyD(pObj, getSvxMapProvider().GetMap(SVXMAP_GROUP), getSvxMapProvider().GetPropertySet(SVXMAP_GROUP, SdrObject::GetGlobalDrawObjectItemPool()))
+ , mxPage(pDrawPage)
+{
+}
+
+SvxShapeGroup::~SvxShapeGroup() noexcept
+{
+}
+
+void SvxShapeGroup::Create( SdrObject* pNewObj, SvxDrawPage* pNewPage )
+{
+ SvxShape::Create( pNewObj, pNewPage );
+ mxPage = pNewPage;
+}
+
+
+uno::Any SAL_CALL SvxShapeGroup::queryInterface( const uno::Type & rType )
+{
+ return SvxShape::queryInterface( rType );
+}
+
+uno::Any SAL_CALL SvxShapeGroup::queryAggregation( const uno::Type & rType )
+{
+ uno::Any aAny;
+
+ QUERYINT( drawing::XShapeGroup );
+ else QUERYINT( drawing::XShapes );
+ else QUERYINT( drawing::XShapes2 );
+ else QUERYINT( container::XIndexAccess );
+ else QUERYINT( container::XElementAccess );
+ else
+ return SvxShape::queryAggregation( rType );
+
+ return aAny;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL SvxShapeGroup::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::drawing::XShape
+
+
+OUString SAL_CALL SvxShapeGroup::getShapeType()
+{
+ return SvxShape::getShapeType();
+}
+
+awt::Point SAL_CALL SvxShapeGroup::getPosition()
+{
+ return SvxShape::getPosition();
+}
+
+
+void SAL_CALL SvxShapeGroup::setPosition( const awt::Point& Position )
+{
+ SvxShape::setPosition(Position);
+}
+
+
+awt::Size SAL_CALL SvxShapeGroup::getSize()
+{
+ return SvxShape::getSize();
+}
+
+
+void SAL_CALL SvxShapeGroup::setSize( const awt::Size& rSize )
+{
+ SvxShape::setSize( rSize );
+}
+
+// drawing::XShapeGroup
+
+
+void SAL_CALL SvxShapeGroup::enterGroup( )
+{
+ // Todo
+// pDrView->EnterMarkedGroup();
+}
+
+
+void SAL_CALL SvxShapeGroup::leaveGroup( )
+{
+ // Todo
+// pDrView->LeaveOneGroup();
+}
+
+void SvxShapeGroup::addUnoShape( const uno::Reference< drawing::XShape >& xShape, size_t nPos )
+{
+ SvxShape* pShape = comphelper::getFromUnoTunnel<SvxShape>( xShape );
+ if (!pShape)
+ {
+ OSL_FAIL("could not add XShape to group shape!");
+ return;
+ }
+ addShape(*pShape, nPos);
+}
+
+void SvxShapeGroup::addShape( SvxShape& rShape )
+{
+ addShape(rShape, SAL_MAX_SIZE);
+}
+
+void SvxShapeGroup::addShape( SvxShape& rShape, size_t nPos )
+{
+ if (!HasSdrObject() || !mxPage.is())
+ {
+ OSL_FAIL("could not add XShape to group shape!");
+ return;
+ }
+
+ SdrObject* pSdrShape = rShape.GetSdrObject();
+ if( pSdrShape == nullptr )
+ pSdrShape = mxPage->CreateSdrObject_( &rShape );
+
+ if( pSdrShape->IsInserted() )
+ pSdrShape->getParentSdrObjListFromSdrObject()->RemoveObject( pSdrShape->GetOrdNum() );
+
+ GetSdrObject()->GetSubList()->InsertObject(pSdrShape, nPos);
+ // TTTT Was created using mpModel in CreateSdrObject_ above
+ // TTTT may be good to add an assertion here for the future
+ // pSdrShape->SetModel(GetSdrObject()->GetModel());
+
+ // #85922# It makes no sense to set the layer asked
+ // from the group object since this is an iteration
+ // over the contained objects. In consequence, this
+ // statement erases all layer information from the draw
+ // objects. Layers need to be set at draw objects directly
+ // and have nothing to do with grouping at all.
+ // pSdrShape->SetLayer(pObject->GetLayer());
+
+ // Establish connection between new SdrObject and its wrapper before
+ // inserting the new shape into the group. There a new wrapper
+ // would be created when this connection would not already exist.
+ rShape.Create( pSdrShape, mxPage.get() );
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+// XShapes
+void SAL_CALL SvxShapeGroup::add( const uno::Reference< drawing::XShape >& xShape )
+{
+ ::SolarMutexGuard aGuard;
+
+ // Add to the top of the stack (i.e. bottom of the list) by default.
+ addUnoShape(xShape, SAL_MAX_SIZE);
+}
+
+
+void SAL_CALL SvxShapeGroup::remove( const uno::Reference< drawing::XShape >& xShape )
+{
+ ::SolarMutexGuard aGuard;
+
+ SdrObject* pSdrShape = SdrObject::getSdrObjectFromXShape( xShape );
+
+ if( !HasSdrObject() || pSdrShape == nullptr || pSdrShape->getParentSdrObjectFromSdrObject() != GetSdrObject() )
+ throw uno::RuntimeException();
+
+ SdrObjList& rList = *pSdrShape->getParentSdrObjListFromSdrObject();
+
+ const size_t nObjCount = rList.GetObjCount();
+ size_t nObjNum = 0;
+ while( nObjNum < nObjCount )
+ {
+ if(rList.GetObj( nObjNum ) == pSdrShape )
+ break;
+ nObjNum++;
+ }
+
+ if( nObjNum < nObjCount )
+ {
+ // #i29181#
+ // If the SdrObject which is about to be deleted is in any selection,
+ // deselect it first.
+ SdrViewIter aIter( pSdrShape );
+
+ for ( SdrView* pView = aIter.FirstView(); pView; pView = aIter.NextView() )
+ {
+ if(SAL_MAX_SIZE != pView->TryToFindMarkedObject(pSdrShape))
+ {
+ pView->MarkObj(pSdrShape, pView->GetSdrPageView(), true);
+ }
+ }
+
+ SdrObject* pObject = rList.NbcRemoveObject( nObjNum );
+ SdrObject::Free( pObject );
+ }
+ else
+ {
+ SAL_WARN( "svx", "Fatality! SdrObject is not belonging to its SdrObjList! [CL]" );
+ }
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+void SAL_CALL SvxShapeGroup::addTop( const uno::Reference< drawing::XShape >& xShape )
+{
+ SolarMutexGuard aGuard;
+
+ // Add to the top of the stack (i.e. bottom of the list).
+ addUnoShape(xShape, SAL_MAX_SIZE);
+}
+
+void SAL_CALL SvxShapeGroup::addBottom( const uno::Reference< drawing::XShape >& xShape )
+{
+ SolarMutexGuard aGuard;
+
+ // Add to the bottom of the stack (i.e. top of the list).
+ addUnoShape(xShape, 0);
+}
+
+// XIndexAccess
+
+
+sal_Int32 SAL_CALL SvxShapeGroup::getCount()
+{
+ ::SolarMutexGuard aGuard;
+
+ if(!HasSdrObject() || !GetSdrObject()->GetSubList())
+ throw uno::RuntimeException();
+
+ sal_Int32 nRetval = GetSdrObject()->GetSubList()->GetObjCount();
+ return nRetval;
+}
+
+
+uno::Any SAL_CALL SvxShapeGroup::getByIndex( sal_Int32 Index )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( !HasSdrObject() || GetSdrObject()->GetSubList() == nullptr )
+ throw uno::RuntimeException();
+
+ if( Index<0 || GetSdrObject()->GetSubList()->GetObjCount() <= o3tl::make_unsigned(Index) )
+ throw lang::IndexOutOfBoundsException();
+
+ SdrObject* pDestObj = GetSdrObject()->GetSubList()->GetObj( Index );
+
+ if(pDestObj == nullptr)
+ throw lang::IndexOutOfBoundsException();
+
+ Reference< drawing::XShape > xShape( pDestObj->getUnoShape(), uno::UNO_QUERY );
+ return uno::Any( xShape );
+}
+
+// css::container::XElementAccess
+
+
+uno::Type SAL_CALL SvxShapeGroup::getElementType()
+{
+ return cppu::UnoType<drawing::XShape>::get();
+}
+
+
+sal_Bool SAL_CALL SvxShapeGroup::hasElements()
+{
+ ::SolarMutexGuard aGuard;
+
+ return HasSdrObject() && GetSdrObject()->GetSubList() && (GetSdrObject()->GetSubList()->GetObjCount() > 0);
+}
+
+SvxShapeConnector::SvxShapeConnector(SdrObject* pObj)
+ : SvxShapeText( pObj, getSvxMapProvider().GetMap(SVXMAP_CONNECTOR), getSvxMapProvider().GetPropertySet(SVXMAP_CONNECTOR, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+
+SvxShapeConnector::~SvxShapeConnector() noexcept
+{
+}
+
+
+uno::Any SAL_CALL SvxShapeConnector::queryInterface( const uno::Type & rType )
+{
+ return SvxShapeText::queryInterface( rType );
+}
+
+uno::Any SAL_CALL SvxShapeConnector::queryAggregation( const uno::Type & rType )
+{
+ uno::Any aAny;
+
+ QUERYINT( drawing::XConnectorShape );
+ else
+ return SvxShapeText::queryAggregation( rType );
+
+ return aAny;
+}
+
+// XTypeProvider
+
+uno::Sequence< uno::Type > SAL_CALL SvxShapeConnector::getTypes()
+{
+ return SvxShape::getTypes();
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL SvxShapeConnector::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::drawing::XShape
+
+
+OUString SAL_CALL SvxShapeConnector::getShapeType()
+{
+ return SvxShapeText::getShapeType();
+}
+
+awt::Point SAL_CALL SvxShapeConnector::getPosition()
+{
+ return SvxShapeText::getPosition();
+}
+
+
+void SAL_CALL SvxShapeConnector::setPosition( const awt::Point& Position )
+{
+ SvxShapeText::setPosition(Position);
+}
+
+
+awt::Size SAL_CALL SvxShapeConnector::getSize()
+{
+ return SvxShapeText::getSize();
+}
+
+
+void SAL_CALL SvxShapeConnector::setSize( const awt::Size& rSize )
+{
+ SvxShapeText::setSize( rSize );
+}
+
+
+// XConnectorShape
+
+void SAL_CALL SvxShapeConnector::connectStart( const uno::Reference< drawing::XConnectableShape >& xShape, drawing::ConnectionType )
+{
+ ::SolarMutexGuard aGuard;
+
+ Reference< drawing::XShape > xRef( xShape, UNO_QUERY );
+ SdrObject* pSdrObject = SdrObject::getSdrObjectFromXShape( xRef );
+
+ if( pSdrObject )
+ GetSdrObject()->ConnectToNode( true, pSdrObject );
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+
+void SAL_CALL SvxShapeConnector::connectEnd( const uno::Reference< drawing::XConnectableShape >& xShape, drawing::ConnectionType )
+{
+ ::SolarMutexGuard aGuard;
+
+ Reference< drawing::XShape > xRef( xShape, UNO_QUERY );
+ SdrObject* pSdrObject = SdrObject::getSdrObjectFromXShape( xRef );
+
+ if( HasSdrObject() && pSdrObject )
+ GetSdrObject()->ConnectToNode( false, pSdrObject );
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+
+void SAL_CALL SvxShapeConnector::disconnectBegin( const uno::Reference< drawing::XConnectableShape >& )
+{
+ ::SolarMutexGuard aGuard;
+
+ if(HasSdrObject())
+ GetSdrObject()->DisconnectFromNode( true );
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+
+void SAL_CALL SvxShapeConnector::disconnectEnd( const uno::Reference< drawing::XConnectableShape >& )
+{
+ ::SolarMutexGuard aGuard;
+
+ if(HasSdrObject())
+ GetSdrObject()->DisconnectFromNode( false );
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+SvxShapeControl::SvxShapeControl(SdrObject* pObj)
+ : SvxShapeText( pObj, getSvxMapProvider().GetMap(SVXMAP_CONTROL), getSvxMapProvider().GetPropertySet(SVXMAP_CONTROL, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+ setShapeKind( SdrObjKind::UNO );
+}
+
+
+SvxShapeControl::~SvxShapeControl() noexcept
+{
+}
+
+
+uno::Any SAL_CALL SvxShapeControl::queryInterface( const uno::Type & rType )
+{
+ return SvxShapeText::queryInterface( rType );
+}
+
+uno::Any SAL_CALL SvxShapeControl::queryAggregation( const uno::Type & rType )
+{
+ uno::Any aAny;
+
+ QUERYINT( drawing::XControlShape );
+ else
+ return SvxShapeText::queryAggregation( rType );
+
+ return aAny;
+}
+
+// XTypeProvider
+
+uno::Sequence< uno::Type > SAL_CALL SvxShapeControl::getTypes()
+{
+ return SvxShape::getTypes();
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL SvxShapeControl::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::drawing::XShape
+
+
+OUString SAL_CALL SvxShapeControl::getShapeType()
+{
+ return SvxShapeText::getShapeType();
+}
+
+awt::Point SAL_CALL SvxShapeControl::getPosition()
+{
+ return SvxShapeText::getPosition();
+}
+
+
+void SAL_CALL SvxShapeControl::setPosition( const awt::Point& Position )
+{
+ SvxShapeText::setPosition(Position);
+}
+
+
+awt::Size SAL_CALL SvxShapeControl::getSize()
+{
+ return SvxShapeText::getSize();
+}
+
+
+void SAL_CALL SvxShapeControl::setSize( const awt::Size& rSize )
+{
+ SvxShapeText::setSize( rSize );
+}
+
+
+// XControlShape
+
+Reference< awt::XControlModel > SAL_CALL SvxShapeControl::getControl()
+{
+ ::SolarMutexGuard aGuard;
+
+ Reference< awt::XControlModel > xModel;
+
+ SdrUnoObj* pUnoObj = dynamic_cast< SdrUnoObj * >(GetSdrObject());
+ if( pUnoObj )
+ xModel = pUnoObj->GetUnoControlModel();
+
+ return xModel;
+}
+
+
+void SAL_CALL SvxShapeControl::setControl( const Reference< awt::XControlModel >& xControl )
+{
+ ::SolarMutexGuard aGuard;
+
+ SdrUnoObj* pUnoObj = dynamic_cast< SdrUnoObj * >(GetSdrObject());
+ if( pUnoObj )
+ pUnoObj->SetUnoControlModel( xControl );
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+struct
+{
+ OUString msAPIName;
+ OUString msFormName;
+}
+const SvxShapeControlPropertyMapping[] =
+{
+ // Warning: The first entry must be FontSlant because the any needs to be converted
+ { UNO_NAME_EDIT_CHAR_POSTURE, "FontSlant" }, // const sal_Int16 => css::awt::FontSlant
+ { UNO_NAME_EDIT_CHAR_FONTNAME, "FontName" },
+ { UNO_NAME_EDIT_CHAR_FONTSTYLENAME, "FontStyleName" },
+ { UNO_NAME_EDIT_CHAR_FONTFAMILY, "FontFamily" },
+ { UNO_NAME_EDIT_CHAR_FONTCHARSET, "FontCharset" },
+ { UNO_NAME_EDIT_CHAR_HEIGHT, "FontHeight" },
+ { UNO_NAME_EDIT_CHAR_FONTPITCH, "FontPitch" },
+ { UNO_NAME_EDIT_CHAR_WEIGHT, "FontWeight" },
+ { UNO_NAME_EDIT_CHAR_UNDERLINE, "FontUnderline" },
+ { UNO_NAME_EDIT_CHAR_STRIKEOUT, "FontStrikeout" },
+ { "CharKerning", "FontKerning" },
+ { "CharWordMode", "FontWordLineMode" },
+ { UNO_NAME_EDIT_CHAR_COLOR, "TextColor" },
+ { "CharBackColor", "CharBackColor" },
+ { "CharBackTransparent", "CharBackTransparent" },
+ { UNO_NAME_TEXT_CHAINNEXTNAME, UNO_NAME_TEXT_CHAINNEXTNAME },
+ { "CharRelief", "FontRelief" },
+ { "CharUnderlineColor", "TextLineColor" },
+ { UNO_NAME_EDIT_PARA_ADJUST, "Align" },
+ { "TextVerticalAdjust", "VerticalAlign" },
+ { "ControlBackground", "BackgroundColor" },
+ { "ControlSymbolColor", "SymbolColor" },
+ { "ControlBorder", "Border" },
+ { "ControlBorderColor", "BorderColor" },
+ { "ControlTextEmphasis", "FontEmphasisMark" },
+ { "ImageScaleMode", "ScaleMode" },
+ { "ControlWritingMode", "WritingMode" },
+ //added for exporting OCX control
+ { "ControlTypeinMSO", "ControlTypeinMSO" },
+ { "ObjIDinMSO", "ObjIDinMSO" },
+ { "CharCaseMap", "CharCaseMap" },
+ { "CharColorTheme", "CharColorTheme" },
+ { "CharColorTintOrShade", "CharColorTintOrShade" },
+};
+
+namespace
+{
+ bool lcl_convertPropertyName( const OUString& rApiName, OUString& rInternalName )
+ {
+ for( const auto & rEntry : SvxShapeControlPropertyMapping )
+ {
+ if( rApiName.reverseCompareTo( rEntry.msAPIName ) == 0 )
+ {
+ rInternalName = rEntry.msFormName;
+ }
+ }
+ return !rInternalName.isEmpty();
+ }
+
+ struct EnumConversionMap
+ {
+ style::ParagraphAdjust nAPIValue;
+ sal_Int16 nFormValue;
+ };
+
+ EnumConversionMap const aMapAdjustToAlign[] =
+ {
+ // note that order matters:
+ // lcl_convertTextAlignmentToParaAdjustment and lcl_convertParaAdjustmentToTextAlignment search this map from the _beginning_
+ // and use the first matching entry
+ {style::ParagraphAdjust_LEFT, sal_Int16(awt::TextAlign::LEFT)},
+ {style::ParagraphAdjust_CENTER, sal_Int16(awt::TextAlign::CENTER)},
+ {style::ParagraphAdjust_RIGHT, sal_Int16(awt::TextAlign::RIGHT)},
+ {style::ParagraphAdjust_BLOCK, sal_Int16(awt::TextAlign::RIGHT)},
+ {style::ParagraphAdjust_STRETCH, sal_Int16(awt::TextAlign::LEFT)},
+ {style::ParagraphAdjust(-1),-1}
+ };
+
+ void lcl_convertTextAlignmentToParaAdjustment( Any& _rValue )
+ {
+ sal_Int16 nValue = sal_Int16();
+ OSL_VERIFY( _rValue >>= nValue );
+
+ for ( auto const & rEntry : aMapAdjustToAlign )
+ if ( nValue == rEntry.nFormValue )
+ {
+ _rValue <<= static_cast<sal_uInt16>(rEntry.nAPIValue);
+ return;
+ }
+ }
+
+ void lcl_convertParaAdjustmentToTextAlignment( Any& _rValue )
+ {
+ sal_Int32 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+
+ for ( auto const & rEntry : aMapAdjustToAlign )
+ if ( static_cast<style::ParagraphAdjust>(nValue) == rEntry.nAPIValue )
+ {
+ _rValue <<= rEntry.nFormValue;
+ return;
+ }
+ }
+
+ void convertVerticalAdjustToVerticalAlign( Any& _rValue )
+ {
+ if ( !_rValue.hasValue() )
+ return;
+
+ drawing::TextVerticalAdjust eAdjust = drawing::TextVerticalAdjust_TOP;
+ style::VerticalAlignment eAlign = style::VerticalAlignment_TOP;
+ if ( !( _rValue >>= eAdjust ) )
+ throw lang::IllegalArgumentException();
+ switch ( eAdjust )
+ {
+ case drawing::TextVerticalAdjust_TOP: eAlign = style::VerticalAlignment_TOP; break;
+ case drawing::TextVerticalAdjust_BOTTOM: eAlign = style::VerticalAlignment_BOTTOM; break;
+ default: eAlign = style::VerticalAlignment_MIDDLE; break;
+ }
+ _rValue <<= eAlign;
+ }
+
+ void convertVerticalAlignToVerticalAdjust( Any& _rValue )
+ {
+ if ( !_rValue.hasValue() )
+ return;
+ style::VerticalAlignment eAlign = style::VerticalAlignment_TOP;
+ drawing::TextVerticalAdjust eAdjust = drawing::TextVerticalAdjust_TOP;
+ OSL_VERIFY( _rValue >>= eAlign );
+ switch ( eAlign )
+ {
+ case style::VerticalAlignment_TOP: eAdjust = drawing::TextVerticalAdjust_TOP; break;
+ case style::VerticalAlignment_BOTTOM: eAdjust = drawing::TextVerticalAdjust_BOTTOM; break;
+ default: eAdjust = drawing::TextVerticalAdjust_CENTER; break;
+ }
+ _rValue <<= eAdjust;
+ }
+}
+
+void SAL_CALL SvxShapeControl::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
+{
+ OUString aFormsName;
+ if ( lcl_convertPropertyName( aPropertyName, aFormsName ) )
+ {
+ uno::Reference< beans::XPropertySet > xControl( getControl(), uno::UNO_QUERY );
+ if( xControl.is() )
+ {
+ uno::Reference< beans::XPropertySetInfo > xInfo( xControl->getPropertySetInfo() );
+ if( xInfo.is() && xInfo->hasPropertyByName( aFormsName ) )
+ {
+ uno::Any aConvertedValue( aValue );
+ if ( aFormsName == "FontSlant" )
+ {
+ awt::FontSlant nSlant;
+ if( !(aValue >>= nSlant ) )
+ throw lang::IllegalArgumentException();
+ aConvertedValue <<= static_cast<sal_Int16>(nSlant);
+ }
+ else if ( aFormsName == "Align" )
+ {
+ lcl_convertParaAdjustmentToTextAlignment( aConvertedValue );
+ }
+ else if ( aFormsName == "VerticalAlign" )
+ {
+ convertVerticalAdjustToVerticalAlign( aConvertedValue );
+ }
+
+ xControl->setPropertyValue( aFormsName, aConvertedValue );
+ }
+ }
+ }
+ else
+ {
+ SvxShape::setPropertyValue( aPropertyName, aValue );
+ }
+}
+
+uno::Any SAL_CALL SvxShapeControl::getPropertyValue( const OUString& aPropertyName )
+{
+ OUString aFormsName;
+ if ( lcl_convertPropertyName( aPropertyName, aFormsName ) )
+ {
+ uno::Reference< beans::XPropertySet > xControl( getControl(), uno::UNO_QUERY );
+
+ uno::Any aValue;
+ if( xControl.is() )
+ {
+ uno::Reference< beans::XPropertySetInfo > xInfo( xControl->getPropertySetInfo() );
+ if( xInfo.is() && xInfo->hasPropertyByName( aFormsName ) )
+ {
+ aValue = xControl->getPropertyValue( aFormsName );
+ if ( aFormsName == "FontSlant" )
+ {
+ awt::FontSlant eSlant = awt::FontSlant_NONE;
+ sal_Int16 nSlant = sal_Int16();
+ if ( aValue >>= nSlant )
+ {
+ eSlant = static_cast<awt::FontSlant>(nSlant);
+ }
+ else
+ {
+ OSL_VERIFY( aValue >>= eSlant );
+ }
+ aValue <<= eSlant;
+ }
+ else if ( aFormsName == "Align" )
+ {
+ lcl_convertTextAlignmentToParaAdjustment( aValue );
+ }
+ else if ( aFormsName == "VerticalAlign" )
+ {
+ convertVerticalAlignToVerticalAdjust( aValue );
+ }
+ }
+ }
+
+ return aValue;
+ }
+ else
+ {
+ return SvxShape::getPropertyValue( aPropertyName );
+ }
+
+}
+
+// XPropertyState
+beans::PropertyState SAL_CALL SvxShapeControl::getPropertyState( const OUString& PropertyName )
+{
+ OUString aFormsName;
+ if ( lcl_convertPropertyName( PropertyName, aFormsName ) )
+ {
+ uno::Reference< beans::XPropertyState > xControl( getControl(), uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySet > xPropSet( getControl(), uno::UNO_QUERY );
+
+ if( xControl.is() && xPropSet.is() )
+ {
+ uno::Reference< beans::XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() );
+ if( xInfo.is() && xInfo->hasPropertyByName( aFormsName ) )
+ {
+ return xControl->getPropertyState( aFormsName );
+ }
+ }
+
+ return beans::PropertyState_DEFAULT_VALUE;
+ }
+ else
+ {
+ return SvxShape::getPropertyState( PropertyName );
+ }
+}
+
+void SAL_CALL SvxShapeControl::setPropertyToDefault( const OUString& PropertyName )
+{
+ OUString aFormsName;
+ if ( lcl_convertPropertyName( PropertyName, aFormsName ) )
+ {
+ uno::Reference< beans::XPropertyState > xControl( getControl(), uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySet > xPropSet( getControl(), uno::UNO_QUERY );
+
+ if( xControl.is() && xPropSet.is() )
+ {
+ uno::Reference< beans::XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() );
+ if( xInfo.is() && xInfo->hasPropertyByName( aFormsName ) )
+ {
+ xControl->setPropertyToDefault( aFormsName );
+ }
+ }
+ }
+ else
+ {
+ SvxShape::setPropertyToDefault( PropertyName );
+ }
+}
+
+uno::Any SAL_CALL SvxShapeControl::getPropertyDefault( const OUString& aPropertyName )
+{
+ OUString aFormsName;
+ if ( lcl_convertPropertyName( aPropertyName, aFormsName ) )
+ {
+ uno::Reference< beans::XPropertyState > xControl( getControl(), uno::UNO_QUERY );
+
+ if( xControl.is() )
+ {
+ Any aDefault( xControl->getPropertyDefault( aFormsName ) );
+ if ( aFormsName == "FontSlant" )
+ {
+ sal_Int16 nSlant( 0 );
+ aDefault >>= nSlant;
+ aDefault <<= static_cast<awt::FontSlant>(nSlant);
+ }
+ else if ( aFormsName == "Align" )
+ {
+ lcl_convertTextAlignmentToParaAdjustment( aDefault );
+ }
+ else if ( aFormsName == "VerticalAlign" )
+ {
+ convertVerticalAlignToVerticalAdjust( aDefault );
+ }
+ return aDefault;
+ }
+
+ throw beans::UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+ else
+ {
+ return SvxShape::getPropertyDefault( aPropertyName );
+ }
+}
+
+SvxShapeDimensioning::SvxShapeDimensioning(SdrObject* pObj)
+ : SvxShapeText( pObj, getSvxMapProvider().GetMap(SVXMAP_DIMENSIONING), getSvxMapProvider().GetPropertySet(SVXMAP_DIMENSIONING, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+SvxShapeDimensioning::~SvxShapeDimensioning() noexcept
+{
+}
+
+SvxShapeCircle::SvxShapeCircle(SdrObject* pObj)
+ : SvxShapeText( pObj, getSvxMapProvider().GetMap(SVXMAP_CIRCLE), getSvxMapProvider().GetPropertySet(SVXMAP_CIRCLE, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+SvxShapeCircle::~SvxShapeCircle() noexcept
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+SvxShapePolyPolygon::SvxShapePolyPolygon(
+ SdrObject* pObj)
+: SvxShapeText(
+ pObj,
+ getSvxMapProvider().GetMap(SVXMAP_POLYPOLYGON),
+ getSvxMapProvider().GetPropertySet(SVXMAP_POLYPOLYGON, SdrObject::GetGlobalDrawObjectItemPool()))
+{
+}
+
+SvxShapePolyPolygon::~SvxShapePolyPolygon() noexcept
+{
+}
+
+bool SvxShapePolyPolygon::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_VALUE_POLYPOLYGONBEZIER:
+ {
+ if( auto s = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(rValue) )
+ {
+ basegfx::B2DPolyPolygon aNewPolyPolygon(
+ basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*s));
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ ForceMetricToItemPoolMetric(aNewPolyPolygon);
+
+ SetPolygon(aNewPolyPolygon);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_VALUE_POLYPOLYGON:
+ {
+ if( auto s = o3tl::tryAccess<drawing::PointSequenceSequence>(rValue) )
+ {
+ basegfx::B2DPolyPolygon aNewPolyPolygon(
+ basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*s));
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ ForceMetricToItemPoolMetric(aNewPolyPolygon);
+
+ SetPolygon(aNewPolyPolygon);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_BASE_GEOMETRY:
+ {
+ drawing::PointSequenceSequence aPointSequenceSequence;
+ drawing::PolyPolygonBezierCoords aPolyPolygonBezierCoords;
+
+ if( rValue >>= aPointSequenceSequence)
+ {
+ if( HasSdrObject() )
+ {
+ basegfx::B2DPolyPolygon aNewPolyPolygon;
+ basegfx::B2DHomMatrix aNewHomogenMatrix;
+
+ GetSdrObject()->TRGetBaseGeometry(aNewHomogenMatrix, aNewPolyPolygon);
+ aNewPolyPolygon = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(aPointSequenceSequence);
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ // Need to adapt aNewPolyPolygon from 100thmm to app-specific
+ ForceMetricToItemPoolMetric(aNewPolyPolygon);
+
+ GetSdrObject()->TRSetBaseGeometry(aNewHomogenMatrix, aNewPolyPolygon);
+ }
+ return true;
+ }
+ else if( rValue >>= aPolyPolygonBezierCoords)
+ {
+ if( HasSdrObject() )
+ {
+ basegfx::B2DPolyPolygon aNewPolyPolygon;
+ basegfx::B2DHomMatrix aNewHomogenMatrix;
+
+ GetSdrObject()->TRGetBaseGeometry(aNewHomogenMatrix, aNewPolyPolygon);
+ aNewPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(aPolyPolygonBezierCoords);
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ ForceMetricToItemPoolMetric(aNewPolyPolygon);
+
+ GetSdrObject()->TRSetBaseGeometry(aNewHomogenMatrix, aNewPolyPolygon);
+ }
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_VALUE_POLYGON:
+ {
+ if( auto pSequence = o3tl::tryAccess<drawing::PointSequence>(rValue) )
+ {
+ // prepare new polygon
+ basegfx::B2DPolygon aNewPolygon;
+
+ // get pointer to arrays
+ const awt::Point* pArray = pSequence->getConstArray();
+ const awt::Point* pArrayEnd = pArray + pSequence->getLength();
+
+ for(;pArray != pArrayEnd;++pArray)
+ {
+ aNewPolygon.append(basegfx::B2DPoint(pArray->X, pArray->Y));
+ }
+
+ // check for closed state flag
+ basegfx::utils::checkClosed(aNewPolygon);
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ basegfx::B2DPolyPolygon aNewPolyPolygon(aNewPolygon);
+ ForceMetricToItemPoolMetric(aNewPolyPolygon);
+
+ // set polygon
+ SetPolygon(aNewPolyPolygon);
+ return true;
+ }
+ break;
+ }
+ default:
+ return SvxShapeText::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ throw lang::IllegalArgumentException();
+}
+
+bool SvxShapePolyPolygon::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty,
+ css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_VALUE_POLYPOLYGONBEZIER:
+ {
+ // pack a tools::PolyPolygon in a struct tools::PolyPolygon
+ basegfx::B2DPolyPolygon aPolyPoly(GetPolygon());
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ ForceMetricTo100th_mm(aPolyPoly);
+
+ drawing::PolyPolygonBezierCoords aRetval;
+ basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords(aPolyPoly, aRetval);
+
+ rValue <<= aRetval;
+ break;
+ }
+ case OWN_ATTR_VALUE_POLYPOLYGON:
+ {
+ // pack a tools::PolyPolygon in a struct tools::PolyPolygon
+ basegfx::B2DPolyPolygon aPolyPoly(GetPolygon());
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ ForceMetricTo100th_mm(aPolyPoly);
+
+ drawing::PointSequenceSequence aRetval( aPolyPoly.count() );
+ basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence(aPolyPoly, aRetval);
+
+ rValue <<= aRetval;
+ break;
+ }
+ case OWN_ATTR_BASE_GEOMETRY:
+ {
+ // pack a tools::PolyPolygon in struct PolyPolygon
+ basegfx::B2DPolyPolygon aPolyPoly;
+ basegfx::B2DHomMatrix aNewHomogenMatrix;
+
+ if(HasSdrObject())
+ {
+ GetSdrObject()->TRGetBaseGeometry(aNewHomogenMatrix, aPolyPoly);
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ ForceMetricTo100th_mm(aPolyPoly);
+ }
+
+ if(aPolyPoly.areControlPointsUsed())
+ {
+ drawing::PolyPolygonBezierCoords aRetval;
+ basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords(aPolyPoly, aRetval);
+ rValue <<= aRetval;
+ }
+ else
+ {
+ drawing::PointSequenceSequence aRetval(aPolyPoly.count());
+ basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence(aPolyPoly, aRetval);
+ rValue <<= aRetval;
+ }
+ break;
+ }
+ case OWN_ATTR_VALUE_POLYGON:
+ {
+ // pack a tools::PolyPolygon in a struct tools::PolyPolygon
+ basegfx::B2DPolyPolygon aPolyPoly(GetPolygon());
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ ForceMetricTo100th_mm(aPolyPoly);
+
+ const sal_Int32 nCount(0 == aPolyPoly.count() ? 0 : aPolyPoly.getB2DPolygon(0).count());
+ drawing::PointSequence aRetval( nCount );
+
+ if( nCount > 0 )
+ {
+ // get single polygon
+ const basegfx::B2DPolygon& aPoly(aPolyPoly.getB2DPolygon(0));
+
+ // get pointer to arrays
+ awt::Point* pSequence = aRetval.getArray();
+
+ for(sal_Int32 b=0;b<nCount;b++)
+ {
+ const basegfx::B2DPoint aPoint(aPoly.getB2DPoint(b));
+ *pSequence++ = awt::Point( basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY()) );
+ }
+ }
+
+ rValue <<= aRetval;
+ break;
+ }
+ case OWN_ATTR_VALUE_POLYGONKIND:
+ {
+ rValue <<= GetPolygonKind();
+ break;
+ }
+ default:
+ return SvxShapeText::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ return true;
+}
+
+drawing::PolygonKind SvxShapePolyPolygon::GetPolygonKind() const
+{
+ ::SolarMutexGuard aGuard;
+ drawing::PolygonKind aRetval(drawing::PolygonKind_LINE);
+
+ if(HasSdrObject())
+ {
+ switch(GetSdrObject()->GetObjIdentifier())
+ {
+ case SdrObjKind::Polygon: aRetval = drawing::PolygonKind_POLY; break;
+ case SdrObjKind::PolyLine: aRetval = drawing::PolygonKind_PLIN; break;
+ case SdrObjKind::SplineLine:
+ case SdrObjKind::PathLine: aRetval = drawing::PolygonKind_PATHLINE; break;
+ case SdrObjKind::SplineFill:
+ case SdrObjKind::PathFill: aRetval = drawing::PolygonKind_PATHFILL; break;
+ case SdrObjKind::FreehandLine: aRetval = drawing::PolygonKind_FREELINE; break;
+ case SdrObjKind::FreehandFill: aRetval = drawing::PolygonKind_FREEFILL; break;
+ default: break;
+ }
+ }
+
+ return aRetval;
+}
+
+void SvxShapePolyPolygon::SetPolygon(const basegfx::B2DPolyPolygon& rNew)
+{
+ ::SolarMutexGuard aGuard;
+
+ if(HasSdrObject())
+ static_cast<SdrPathObj*>(GetSdrObject())->SetPathPoly(rNew);
+}
+
+
+basegfx::B2DPolyPolygon SvxShapePolyPolygon::GetPolygon() const noexcept
+{
+ ::SolarMutexGuard aGuard;
+
+ if(HasSdrObject())
+ {
+ return static_cast<SdrPathObj*>(GetSdrObject())->GetPathPoly();
+ }
+ else
+ {
+ return basegfx::B2DPolyPolygon();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+SvxGraphicObject::SvxGraphicObject(SdrObject* pObj)
+ : SvxShapeText( pObj, getSvxMapProvider().GetMap(SVXMAP_GRAPHICOBJECT), getSvxMapProvider().GetPropertySet(SVXMAP_GRAPHICOBJECT, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+SvxGraphicObject::~SvxGraphicObject() noexcept
+{
+}
+
+bool SvxGraphicObject::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ bool bOk = false;
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_VALUE_FILLBITMAP:
+ {
+ if( auto pSeq = o3tl::tryAccess<uno::Sequence<sal_Int8>>(rValue) )
+ {
+ SvMemoryStream aMemStm;
+ Graphic aGraphic;
+
+ aMemStm.SetBuffer( const_cast<css::uno::Sequence<sal_Int8> *>(pSeq)->getArray(), pSeq->getLength(), pSeq->getLength() );
+
+ if( GraphicConverter::Import( aMemStm, aGraphic ) == ERRCODE_NONE )
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->SetGraphic(aGraphic);
+ bOk = true;
+ }
+ }
+ else if (rValue.getValueType() == cppu::UnoType<graphic::XGraphic>::get())
+ {
+ auto xGraphic = rValue.get<uno::Reference<graphic::XGraphic>>();
+ if (xGraphic.is())
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->SetGraphic(Graphic(xGraphic));
+ bOk = true;
+ }
+ }
+ else if (rValue.getValueType() == cppu::UnoType<awt::XBitmap>::get())
+ {
+ auto xBitmap = rValue.get<uno::Reference<awt::XBitmap>>();
+ if (xBitmap.is())
+ {
+ uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
+ Graphic aGraphic(xGraphic);
+ static_cast<SdrGrafObj*>(GetSdrObject())->SetGraphic(aGraphic);
+ bOk = true;
+ }
+ }
+ break;
+ }
+
+ case OWN_ATTR_GRAFSTREAMURL:
+ {
+ OUString aStreamURL;
+
+ if( rValue >>= aStreamURL )
+ {
+ if( !aStreamURL.startsWith( UNO_NAME_GRAPHOBJ_URLPKGPREFIX ) )
+ aStreamURL.clear();
+
+ if( HasSdrObject() )
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->SetGrafStreamURL( aStreamURL );
+ }
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_GRAPHIC_URL:
+ {
+ OUString aURL;
+ uno::Reference<awt::XBitmap> xBitmap;
+ if (rValue >>= aURL)
+ {
+ Graphic aGraphic = vcl::graphic::loadFromURL(aURL);
+ if (!aGraphic.IsNone())
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->SetGraphic(aGraphic);
+ bOk = true;
+ }
+ }
+ else if (rValue >>= xBitmap)
+ {
+ uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
+ if (xGraphic.is())
+ {
+ Graphic aGraphic = xGraphic;
+ if (!aGraphic.IsNone())
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->SetGraphic(aGraphic);
+ bOk = true;
+ }
+ }
+ }
+ break;
+ }
+
+ case OWN_ATTR_VALUE_GRAPHIC:
+ {
+ Reference< graphic::XGraphic > xGraphic( rValue, uno::UNO_QUERY );
+ if( xGraphic.is() )
+ {
+ static_cast< SdrGrafObj*>( GetSdrObject() )->SetGraphic( xGraphic );
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_IS_SIGNATURELINE:
+ {
+ bool bIsSignatureLine;
+ if (rValue >>= bIsSignatureLine)
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setIsSignatureLine(bIsSignatureLine);
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_ID:
+ {
+ OUString aSignatureLineId;
+ if (rValue >>= aSignatureLineId)
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setSignatureLineId(aSignatureLineId);
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_SUGGESTED_SIGNER_NAME:
+ {
+ OUString aSuggestedSignerName;
+ if (rValue >>= aSuggestedSignerName)
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setSignatureLineSuggestedSignerName(aSuggestedSignerName);
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_SUGGESTED_SIGNER_TITLE:
+ {
+ OUString aSuggestedSignerTitle;
+ if (rValue >>= aSuggestedSignerTitle)
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setSignatureLineSuggestedSignerTitle(aSuggestedSignerTitle);
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_SUGGESTED_SIGNER_EMAIL:
+ {
+ OUString aSuggestedSignerEmail;
+ if (rValue >>= aSuggestedSignerEmail)
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setSignatureLineSuggestedSignerEmail(aSuggestedSignerEmail);
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_SIGNING_INSTRUCTIONS:
+ {
+ OUString aSigningInstructions;
+ if (rValue >>= aSigningInstructions)
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setSignatureLineSigningInstructions(aSigningInstructions);
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_SHOW_SIGN_DATE:
+ {
+ bool bShowSignDate;
+ if (rValue >>= bShowSignDate)
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setSignatureLineShowSignDate(bShowSignDate);
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_CAN_ADD_COMMENT:
+ {
+ bool bCanAddComment;
+ if (rValue >>= bCanAddComment)
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setSignatureLineCanAddComment(bCanAddComment);
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_UNSIGNED_IMAGE:
+ {
+ Reference<graphic::XGraphic> xGraphic(rValue, uno::UNO_QUERY);
+ if (xGraphic.is())
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setSignatureLineUnsignedGraphic(xGraphic);
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_IS_SIGNED:
+ {
+ bool bIsSigned;
+ if (rValue >>= bIsSigned)
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setSignatureLineIsSigned(bIsSigned);
+ bOk = true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_QRCODE:
+ {
+ css::drawing::BarCode aBarCode;
+ if (rValue >>= aBarCode)
+ {
+ static_cast<SdrGrafObj*>(GetSdrObject())->setQrCode(aBarCode);
+ bOk = true;
+ }
+ break;
+ }
+
+ default:
+ return SvxShapeText::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ if( !bOk )
+ throw lang::IllegalArgumentException();
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+
+ return true;
+}
+
+bool SvxGraphicObject::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_VALUE_FILLBITMAP:
+ {
+ const Graphic& rGraphic = static_cast<SdrGrafObj*>(GetSdrObject())->GetGraphic();
+
+ if (rGraphic.GetType() != GraphicType::GdiMetafile)
+ {
+ uno::Reference<awt::XBitmap> xBitmap(rGraphic.GetXGraphic(), uno::UNO_QUERY);
+ rValue <<= xBitmap;
+ }
+ else
+ {
+ SvMemoryStream aDestStrm( 65535, 65535 );
+
+ ConvertGDIMetaFileToWMF( rGraphic.GetGDIMetaFile(), aDestStrm, nullptr, false );
+ const uno::Sequence<sal_Int8> aSeq(
+ static_cast< const sal_Int8* >(aDestStrm.GetData()),
+ aDestStrm.GetEndOfData());
+ rValue <<= aSeq;
+ }
+ break;
+ }
+
+ case OWN_ATTR_REPLACEMENT_GRAPHIC:
+ {
+ const GraphicObject* pGrafObj = static_cast< SdrGrafObj* >(GetSdrObject())->GetReplacementGraphicObject();
+
+ if (pGrafObj)
+ {
+ rValue <<= pGrafObj->GetGraphic().GetXGraphic();
+ }
+
+ break;
+ }
+
+ case OWN_ATTR_GRAFSTREAMURL:
+ {
+ const OUString aStreamURL( static_cast<SdrGrafObj*>( GetSdrObject() )->GetGrafStreamURL() );
+ if( !aStreamURL.isEmpty() )
+ rValue <<= aStreamURL;
+ break;
+ }
+
+ case OWN_ATTR_GRAPHIC_URL:
+ case OWN_ATTR_VALUE_GRAPHIC:
+ {
+ if (pProperty->nWID == OWN_ATTR_GRAPHIC_URL)
+ {
+ SAL_WARN("svx", "Getting Graphic by URL is not supported, getting it by value");
+ }
+
+ Reference<graphic::XGraphic> xGraphic;
+ auto pSdrGraphicObject = static_cast<SdrGrafObj*>(GetSdrObject());
+ if (pSdrGraphicObject
+ && pSdrGraphicObject->GetGraphicObject().GetType() != GraphicType::NONE)
+ xGraphic = pSdrGraphicObject->GetGraphic().GetXGraphic();
+ rValue <<= xGraphic;
+ break;
+ }
+
+ case OWN_ATTR_GRAPHIC_STREAM:
+ {
+ rValue <<= static_cast< SdrGrafObj* >( GetSdrObject() )->getInputStream();
+ break;
+ }
+
+ case OWN_ATTR_IS_SIGNATURELINE:
+ {
+ rValue <<= static_cast<SdrGrafObj*>(GetSdrObject())->isSignatureLine();
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_ID:
+ {
+ rValue <<= static_cast<SdrGrafObj*>(GetSdrObject())->getSignatureLineId();
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_SUGGESTED_SIGNER_NAME:
+ {
+ rValue <<= static_cast<SdrGrafObj*>(GetSdrObject())->getSignatureLineSuggestedSignerName();
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_SUGGESTED_SIGNER_TITLE:
+ {
+ rValue <<= static_cast<SdrGrafObj*>(GetSdrObject())->getSignatureLineSuggestedSignerTitle();
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_SUGGESTED_SIGNER_EMAIL:
+ {
+ rValue <<= static_cast<SdrGrafObj*>(GetSdrObject())->getSignatureLineSuggestedSignerEmail();
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_SIGNING_INSTRUCTIONS:
+ {
+ rValue <<= static_cast<SdrGrafObj*>(GetSdrObject())->getSignatureLineSigningInstructions();
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_SHOW_SIGN_DATE:
+ {
+ rValue <<= static_cast<SdrGrafObj*>(GetSdrObject())->isSignatureLineShowSignDate();
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_CAN_ADD_COMMENT:
+ {
+ rValue <<= static_cast<SdrGrafObj*>(GetSdrObject())->isSignatureLineCanAddComment();
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_UNSIGNED_IMAGE:
+ {
+ Reference<graphic::XGraphic> xGraphic(
+ static_cast<SdrGrafObj*>(GetSdrObject())->getSignatureLineUnsignedGraphic());
+ rValue <<= xGraphic;
+ break;
+ }
+
+ case OWN_ATTR_SIGNATURELINE_IS_SIGNED:
+ {
+ rValue <<= static_cast<SdrGrafObj*>(GetSdrObject())->isSignatureLineSigned();
+ break;
+ }
+
+ case OWN_ATTR_QRCODE:
+ {
+ css::drawing::BarCode* ptr = static_cast<SdrGrafObj*>(GetSdrObject())->getQrCode();
+ if(ptr)
+ {
+ rValue <<= *ptr;
+ }
+ break;
+ }
+
+ default:
+ return SvxShapeText::getPropertyValueImpl(rName, pProperty,rValue);
+ }
+
+ return true;
+}
+
+
+SvxShapeCaption::SvxShapeCaption(SdrObject* pObj)
+: SvxShapeText( pObj, getSvxMapProvider().GetMap(SVXMAP_CAPTION), getSvxMapProvider().GetPropertySet(SVXMAP_CAPTION, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+SvxShapeCaption::~SvxShapeCaption() noexcept
+{
+}
+
+SvxCustomShape::SvxCustomShape(SdrObject* pObj)
+ : SvxShapeText( pObj, getSvxMapProvider().GetMap( SVXMAP_CUSTOMSHAPE ), getSvxMapProvider().GetPropertySet(SVXMAP_CUSTOMSHAPE, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+SvxCustomShape::~SvxCustomShape() noexcept
+{
+}
+
+uno::Any SAL_CALL SvxCustomShape::queryInterface( const uno::Type & rType )
+{
+ return SvxShapeText::queryInterface( rType );
+}
+
+uno::Any SAL_CALL SvxCustomShape::queryAggregation( const uno::Type & rType )
+{
+ css::uno::Any aReturn = SvxShapeText::queryAggregation( rType );
+ if ( !aReturn.hasValue() )
+ aReturn = ::cppu::queryInterface(rType, static_cast<drawing::XEnhancedCustomShapeDefaulter*>(this) );
+ return aReturn;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL SvxCustomShape::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::drawing::XShape
+
+
+awt::Point SAL_CALL SvxCustomShape::getPosition()
+{
+ ::SolarMutexGuard aGuard;
+ if ( HasSdrObject() )
+ {
+ SdrAShapeObjGeoData aCustomShapeGeoData;
+ static_cast<SdrObjCustomShape*>(GetSdrObject())->SaveGeoData( aCustomShapeGeoData );
+
+ bool bMirroredX = false;
+ bool bMirroredY = false;
+
+ if ( HasSdrObject() )
+ {
+ bMirroredX = static_cast<SdrObjCustomShape*>(GetSdrObject())->IsMirroredX();
+ bMirroredY = static_cast<SdrObjCustomShape*>(GetSdrObject())->IsMirroredY();
+ }
+ // get aRect, this is the unrotated snaprect
+ tools::Rectangle aRect(static_cast<SdrObjCustomShape*>(GetSdrObject())->GetLogicRect());
+ tools::Rectangle aRectangle( aRect );
+
+ if ( bMirroredX || bMirroredY )
+ { // we have to retrieve the unmirrored rect
+
+ GeoStat aNewGeo(aCustomShapeGeoData.maGeo);
+ if ( bMirroredX )
+ {
+ tools::Polygon aPol( Rect2Poly( aRect, aNewGeo ) );
+ tools::Rectangle aBoundRect( aPol.GetBoundRect() );
+
+ Point aRef1( ( aBoundRect.Left() + aBoundRect.Right() ) >> 1, aBoundRect.Top() );
+ Point aRef2( aRef1.X(), aRef1.Y() + 1000 );
+ sal_uInt16 i;
+ sal_uInt16 nPointCount=aPol.GetSize();
+ for (i=0; i<nPointCount; i++)
+ {
+ MirrorPoint(aPol[i],aRef1,aRef2);
+ }
+ // turn and move polygon
+ tools::Polygon aPol0(aPol);
+ aPol[0]=aPol0[1];
+ aPol[1]=aPol0[0];
+ aPol[2]=aPol0[3];
+ aPol[3]=aPol0[2];
+ aPol[4]=aPol0[1];
+ Poly2Rect(aPol,aRectangle,aNewGeo);
+ }
+ if ( bMirroredY )
+ {
+ tools::Polygon aPol( Rect2Poly( aRectangle, aNewGeo ) );
+ tools::Rectangle aBoundRect( aPol.GetBoundRect() );
+
+ Point aRef1( aBoundRect.Left(), ( aBoundRect.Top() + aBoundRect.Bottom() ) >> 1 );
+ Point aRef2( aRef1.X() + 1000, aRef1.Y() );
+ sal_uInt16 i;
+ sal_uInt16 nPointCount=aPol.GetSize();
+ for (i=0; i<nPointCount; i++)
+ {
+ MirrorPoint(aPol[i],aRef1,aRef2);
+ }
+ // turn and move polygon
+ tools::Polygon aPol0(aPol);
+ aPol[0]=aPol0[1];
+ aPol[1]=aPol0[0];
+ aPol[2]=aPol0[3];
+ aPol[3]=aPol0[2];
+ aPol[4]=aPol0[1];
+ Poly2Rect( aPol, aRectangle, aNewGeo );
+ }
+ }
+ Point aPt( aRectangle.TopLeft() );
+
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ aPt -= GetSdrObject()->GetAnchorPos();
+
+ ForceMetricTo100th_mm(aPt);
+ return css::awt::Point( aPt.X(), aPt.Y() );
+ }
+ else
+ return SvxShape::getPosition();
+}
+
+
+void SAL_CALL SvxCustomShape::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
+{
+ ::SolarMutexGuard aGuard;
+
+ SdrObject* pObject = GetSdrObject();
+
+ // tdf#98163 Use a custom slot to have filter code flush the UNO
+ // API implementations of SdrObjCustomShape. Used e.g. by
+ // ~SdXMLCustomShapeContext, see there for more information
+ if("FlushCustomShapeUnoApiObjects" == aPropertyName)
+ {
+ SdrObjCustomShape* pTarget = dynamic_cast< SdrObjCustomShape* >(pObject);
+ if(pTarget)
+ {
+ // Luckily, the object causing problems in tdf#93994 is not the
+ // UNO API object, but the XCustomShapeEngine involved. This
+ // object is on-demand replaceable and can be reset here. This
+ // will free the involved EditEngine and VirtualDevice.
+ pTarget->mxCustomShapeEngine.set(nullptr);
+ }
+ // since this case is only for the application cores
+ // we should return from this function now
+ return;
+ }
+
+ bool bCustomShapeGeometry = pObject && aPropertyName == "CustomShapeGeometry";
+
+ bool bMirroredX = false;
+ bool bMirroredY = false;
+
+ if ( bCustomShapeGeometry )
+ {
+ bMirroredX = static_cast<SdrObjCustomShape*>(pObject)->IsMirroredX();
+ bMirroredY = static_cast<SdrObjCustomShape*>(pObject)->IsMirroredY();
+ }
+
+ SvxShape::setPropertyValue( aPropertyName, aValue );
+
+ if ( !bCustomShapeGeometry )
+ return;
+
+ static_cast<SdrObjCustomShape*>(pObject)->MergeDefaultAttributes();
+ tools::Rectangle aRect( pObject->GetSnapRect() );
+
+ // #i38892#
+ bool bNeedsMirrorX = static_cast<SdrObjCustomShape*>(pObject)->IsMirroredX() != bMirroredX;
+ bool bNeedsMirrorY = static_cast<SdrObjCustomShape*>(pObject)->IsMirroredY() != bMirroredY;
+
+ std::unique_ptr< SdrGluePointList > pListCopy;
+ if( bNeedsMirrorX || bNeedsMirrorY )
+ {
+ const SdrGluePointList* pList = pObject->GetGluePointList();
+ if( pList )
+ pListCopy.reset( new SdrGluePointList(*pList) );
+ }
+
+ if ( bNeedsMirrorX )
+ {
+ Point aTop( ( aRect.Left() + aRect.Right() ) >> 1, aRect.Top() );
+ Point aBottom( aTop.X(), aTop.Y() + 1000 );
+ pObject->NbcMirror( aTop, aBottom );
+ // NbcMirroring is flipping the current mirror state,
+ // so we have to set the correct state again
+ static_cast<SdrObjCustomShape*>(pObject)->SetMirroredX( !bMirroredX );
+ }
+ if ( bNeedsMirrorY )
+ {
+ Point aLeft( aRect.Left(), ( aRect.Top() + aRect.Bottom() ) >> 1 );
+ Point aRight( aLeft.X() + 1000, aLeft.Y() );
+ pObject->NbcMirror( aLeft, aRight );
+ // NbcMirroring is flipping the current mirror state,
+ // so we have to set the correct state again
+ static_cast<SdrObjCustomShape*>(pObject)->SetMirroredY( !bMirroredY );
+ }
+
+ if( pListCopy )
+ {
+ SdrGluePointList* pNewList = const_cast< SdrGluePointList* >( pObject->GetGluePointList() );
+ if(pNewList)
+ *pNewList = *pListCopy;
+ }
+}
+
+bool SvxCustomShape::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case SDRATTR_ROTATEANGLE:
+ {
+ double fAngle = static_cast<SdrObjCustomShape*>(GetSdrObject())->GetObjectRotation();
+ fAngle *= 100;
+ rValue <<= static_cast<sal_Int32>(fAngle);
+ return true;
+ }
+ default:
+ return SvxShape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+}
+
+void SvxCustomShape::createCustomShapeDefaults( const OUString& rValueType )
+{
+ if (!HasSdrObject())
+ {
+ OSL_FAIL("could not create Custom Shape Defaults!");
+ return;
+ }
+
+ static_cast<SdrObjCustomShape*>(GetSdrObject())->MergeDefaultAttributes( &rValueType );
+}
+
+SvxShapeGroupAnyD::SvxShapeGroupAnyD( SdrObject* pObject, const SfxItemPropertyMapEntry* pEntries, const SvxItemPropertySet* pPropertySet )
+ : SvxShape(pObject, pEntries, pPropertySet)
+{}
+
+SvxShapeGroupAnyD::~SvxShapeGroupAnyD() noexcept
+{}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unoshap3.cxx b/svx/source/unodraw/unoshap3.cxx
new file mode 100644
index 000000000..0704a4e5c
--- /dev/null
+++ b/svx/source/unodraw/unoshap3.cxx
@@ -0,0 +1,1052 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <initializer_list>
+#include <string_view>
+
+#include <com/sun/star/drawing/HomogenMatrix.hpp>
+#include <com/sun/star/drawing/Position3D.hpp>
+#include <com/sun/star/drawing/Direction3D.hpp>
+#include <com/sun/star/drawing/DoubleSequence.hpp>
+#include <com/sun/star/drawing/CameraGeometry.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <o3tl/safeint.hxx>
+#include <vcl/svapp.hxx>
+#include <comphelper/sequence.hxx>
+#include <sal/log.hxx>
+
+#include <svx/svdpool.hxx>
+#include <svx/svditer.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/unopage.hxx>
+#include <svx/cube3d.hxx>
+#include <svx/sphere3d.hxx>
+#include <svx/lathe3d.hxx>
+#include <extrud3d.hxx>
+#include <polygn3d.hxx>
+#include <svx/unoshprp.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/scene3d.hxx>
+#include <basegfx/polygon/b3dpolygon.hxx>
+#include <basegfx/polygon/b3dpolygontools.hxx>
+#include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/matrix/b3dhommatrixtools.hxx>
+#include "shapeimpl.hxx"
+
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+
+#define QUERYINT( xint ) \
+ if( rType == cppu::UnoType<xint>::get() ) \
+ aAny <<= Reference< xint >(this)
+
+Svx3DSceneObject::Svx3DSceneObject(SdrObject* pObj, SvxDrawPage* pDrawPage)
+: SvxShapeGroupAnyD( pObj, getSvxMapProvider().GetMap(SVXMAP_3DSCENEOBJECT), getSvxMapProvider().GetPropertySet(SVXMAP_3DSCENEOBJECT, SdrObject::GetGlobalDrawObjectItemPool()) )
+, mxPage( pDrawPage )
+{
+}
+
+
+Svx3DSceneObject::~Svx3DSceneObject() noexcept
+{
+}
+
+
+void Svx3DSceneObject::Create( SdrObject* pNewObj, SvxDrawPage* pNewPage )
+{
+ SvxShape::Create( pNewObj, pNewPage );
+ mxPage = pNewPage;
+}
+
+
+uno::Any SAL_CALL Svx3DSceneObject::queryAggregation( const uno::Type & rType )
+{
+ uno::Any aAny;
+
+ QUERYINT( drawing::XShapes );
+ else QUERYINT( container::XIndexAccess );
+ else QUERYINT( container::XElementAccess );
+ else
+ return SvxShape::queryAggregation( rType );
+
+ return aAny;
+}
+
+uno::Any SAL_CALL Svx3DSceneObject::queryInterface( const uno::Type & rType )
+{
+ return SvxShape::queryInterface( rType );
+}
+
+// XTypeProvider
+
+uno::Sequence< sal_Int8 > SAL_CALL Svx3DSceneObject::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+
+void SAL_CALL Svx3DSceneObject::add( const Reference< drawing::XShape >& xShape )
+{
+ SolarMutexGuard aGuard;
+
+ SvxShape* pShape = comphelper::getFromUnoTunnel<SvxShape>( xShape );
+
+ if(!HasSdrObject() || !mxPage.is() || pShape == nullptr || nullptr != pShape->GetSdrObject() )
+ throw uno::RuntimeException();
+
+ SdrObject* pSdrShape = mxPage->CreateSdrObject_( xShape );
+ if( dynamic_cast<const E3dObject* >(pSdrShape) != nullptr )
+ {
+ GetSdrObject()->GetSubList()->NbcInsertObject( pSdrShape );
+ pShape->Create(pSdrShape, mxPage.get());
+ }
+ else
+ {
+ SdrObject::Free( pSdrShape );
+ throw uno::RuntimeException();
+ }
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+void Svx3DSceneObject::addShape( SvxShape& rShape )
+{
+ SolarMutexGuard aGuard;
+
+ if(!HasSdrObject() || !mxPage.is() || nullptr != rShape.GetSdrObject() )
+ throw uno::RuntimeException();
+
+ SdrObject* pSdrShape = mxPage->CreateSdrObject_( &rShape );
+ if( dynamic_cast<const E3dObject* >(pSdrShape) != nullptr )
+ {
+ GetSdrObject()->GetSubList()->NbcInsertObject( pSdrShape );
+ rShape.Create(pSdrShape, mxPage.get());
+ }
+ else
+ {
+ SdrObject::Free( pSdrShape );
+ throw uno::RuntimeException();
+ }
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+void SAL_CALL Svx3DSceneObject::remove( const Reference< drawing::XShape >& xShape )
+{
+ SolarMutexGuard aGuard;
+
+ SdrObject* pSdrShape = SdrObject::getSdrObjectFromXShape( xShape );
+
+ if(!HasSdrObject() || !pSdrShape ||
+ pSdrShape->getParentSdrObjectFromSdrObject() != GetSdrObject())
+ throw uno::RuntimeException();
+
+ SdrObjList& rList = *pSdrShape->getParentSdrObjListFromSdrObject();
+
+ const size_t nObjCount = rList.GetObjCount();
+ size_t nObjNum = 0;
+ while( nObjNum < nObjCount )
+ {
+ if(rList.GetObj( nObjNum ) == pSdrShape )
+ break;
+ nObjNum++;
+ }
+
+ if( nObjNum < nObjCount )
+ {
+ SdrObject* pObject = rList.NbcRemoveObject( nObjNum );
+ SdrObject::Free( pObject );
+ }
+ else
+ {
+ SAL_WARN( "svx", "Fatality! SdrObject is not belonging to its SdrObjList! [CL]" );
+ }
+}
+
+
+sal_Int32 SAL_CALL Svx3DSceneObject::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nRetval = 0;
+
+ if(HasSdrObject() && dynamic_cast<const E3dScene* >(GetSdrObject()) != nullptr && GetSdrObject()->GetSubList())
+ nRetval = GetSdrObject()->GetSubList()->GetObjCount();
+ return nRetval;
+}
+
+
+uno::Any SAL_CALL Svx3DSceneObject::getByIndex( sal_Int32 Index )
+{
+ SolarMutexGuard aGuard;
+
+ if( !HasSdrObject() || GetSdrObject()->GetSubList() == nullptr )
+ throw uno::RuntimeException();
+
+ if( Index<0 || GetSdrObject()->GetSubList()->GetObjCount() <= o3tl::make_unsigned(Index) )
+ throw lang::IndexOutOfBoundsException();
+
+ SdrObject* pDestObj = GetSdrObject()->GetSubList()->GetObj( Index );
+ if(pDestObj == nullptr)
+ throw lang::IndexOutOfBoundsException();
+
+ Reference< drawing::XShape > xShape( pDestObj->getUnoShape(), uno::UNO_QUERY );
+ return uno::Any(xShape);
+}
+
+
+// css::container::XElementAccess
+
+uno::Type SAL_CALL Svx3DSceneObject::getElementType()
+{
+ return cppu::UnoType<drawing::XShape>::get();
+}
+
+
+sal_Bool SAL_CALL Svx3DSceneObject::hasElements()
+{
+ SolarMutexGuard aGuard;
+
+ return HasSdrObject() && GetSdrObject()->GetSubList() && (GetSdrObject()->GetSubList()->GetObjCount() > 0);
+}
+
+
+static bool ConvertHomogenMatrixToObject( E3dObject* pObject, const Any& rValue )
+{
+ drawing::HomogenMatrix aMat;
+ if( rValue >>= aMat )
+ {
+ pObject->SetTransform(basegfx::utils::UnoHomogenMatrixToB3DHomMatrix(aMat));
+ return true;
+ }
+ return false;
+}
+
+static void ConvertObjectToHomogenMatric( E3dObject const * pObject, Any& rValue )
+{
+ drawing::HomogenMatrix aHomMat;
+ const basegfx::B3DHomMatrix& rMat = pObject->GetTransform();
+ basegfx::utils::B3DHomMatrixToUnoHomogenMatrix(rMat, aHomMat);
+ rValue <<= aHomMat;
+}
+
+namespace {
+
+struct ImpRememberTransAndRect
+{
+ basegfx::B3DHomMatrix maMat;
+ tools::Rectangle maRect;
+};
+
+}
+
+bool Svx3DSceneObject::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // patch transformation matrix to the object
+ if( ConvertHomogenMatrixToObject( static_cast< E3dObject* >( GetSdrObject() ), rValue ) )
+ return true;
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_CAMERA_GEOMETRY:
+ {
+ // set CameraGeometry at scene
+ E3dScene* pScene = static_cast< E3dScene* >( GetSdrObject() );
+ drawing::CameraGeometry aCamGeo;
+
+ if(rValue >>= aCamGeo)
+ {
+ basegfx::B3DPoint aVRP(aCamGeo.vrp.PositionX, aCamGeo.vrp.PositionY, aCamGeo.vrp.PositionZ);
+ basegfx::B3DVector aVPN(aCamGeo.vpn.DirectionX, aCamGeo.vpn.DirectionY, aCamGeo.vpn.DirectionZ);
+ basegfx::B3DVector aVUP(aCamGeo.vup.DirectionX, aCamGeo.vup.DirectionY, aCamGeo.vup.DirectionZ);
+
+ // rescue scene transformation
+ ImpRememberTransAndRect aSceneTAR;
+ aSceneTAR.maMat = pScene->GetTransform();
+ aSceneTAR.maRect = pScene->GetSnapRect();
+
+ // rescue object transformations
+ SdrObjListIter aIter(pScene->GetSubList(), SdrIterMode::DeepWithGroups);
+ std::vector<basegfx::B3DHomMatrix*> aObjTrans;
+ while(aIter.IsMore())
+ {
+ E3dObject* p3DObj = static_cast<E3dObject*>(aIter.Next());
+ basegfx::B3DHomMatrix* pNew = new basegfx::B3DHomMatrix;
+ *pNew = p3DObj->GetTransform();
+ aObjTrans.push_back(pNew);
+ }
+
+ // reset object transformations
+ aIter.Reset();
+ while(aIter.IsMore())
+ {
+ E3dObject* p3DObj = static_cast<E3dObject*>(aIter.Next());
+ p3DObj->NbcSetTransform(basegfx::B3DHomMatrix());
+ }
+
+ // reset scene transformation and make a complete recalc
+ pScene->NbcSetTransform(basegfx::B3DHomMatrix());
+
+ // fill old camera from new parameters
+ Camera3D aCam(pScene->GetCamera());
+ const basegfx::B3DRange& rVolume = pScene->GetBoundVolume();
+ double fW = rVolume.getWidth();
+ double fH = rVolume.getHeight();
+
+ const SfxItemSet& rSceneSet = pScene->GetMergedItemSet();
+ double fCamPosZ =
+ static_cast<double>(rSceneSet.Get(SDRATTR_3DSCENE_DISTANCE).GetValue());
+ double fCamFocal =
+ static_cast<double>(rSceneSet.Get(SDRATTR_3DSCENE_FOCAL_LENGTH).GetValue());
+
+ aCam.SetAutoAdjustProjection(false);
+ aCam.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
+ basegfx::B3DPoint aLookAt;
+ basegfx::B3DPoint aCamPos(0.0, 0.0, fCamPosZ);
+ aCam.SetPosAndLookAt(aCamPos, aLookAt);
+ aCam.SetFocalLength(fCamFocal / 100.0);
+ aCam.SetDeviceWindow(tools::Rectangle(0, 0, static_cast<tools::Long>(fW), static_cast<tools::Long>(fH)));
+
+ // set at scene
+ pScene->SetCamera(aCam);
+
+ // #91047# use imported VRP, VPN and VUP (if used)
+ bool bVRPUsed(!aVRP.equal(basegfx::B3DPoint(0.0, 0.0, 1.0)));
+ bool bVPNUsed(!aVPN.equal(basegfx::B3DVector(0.0, 0.0, 1.0)));
+ bool bVUPUsed(!aVUP.equal(basegfx::B3DVector(0.0, 1.0, 0.0)));
+
+ if(bVRPUsed || bVPNUsed || bVUPUsed)
+ {
+ pScene->GetCameraSet().SetViewportValues(aVRP, aVPN, aVUP);
+ }
+
+ // set object transformations again at objects
+ aIter.Reset();
+ sal_uInt32 nIndex(0);
+ while(aIter.IsMore())
+ {
+ E3dObject* p3DObj = static_cast<E3dObject*>(aIter.Next());
+ basegfx::B3DHomMatrix* pMat = aObjTrans[nIndex++];
+ p3DObj->NbcSetTransform(*pMat);
+ delete pMat;
+ }
+
+ // set scene transformation again at scene
+ pScene->NbcSetTransform(aSceneTAR.maMat);
+ pScene->NbcSetSnapRect(aSceneTAR.maRect);
+
+ return true;
+ }
+ break;
+ }
+ default:
+ return SvxShape::setPropertyValueImpl(rName, pProperty, rValue);
+ }
+
+ throw IllegalArgumentException();
+}
+
+
+bool Svx3DSceneObject::getPropertyValueImpl(const OUString& rName, const SfxItemPropertyMapEntry* pProperty,
+ css::uno::Any& rValue)
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // patch object to a homogeneous 4x4 matrix
+ ConvertObjectToHomogenMatric( static_cast< E3dObject* >( GetSdrObject() ), rValue );
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_CAMERA_GEOMETRY:
+ {
+ // get CameraGeometry from scene
+ E3dScene* pScene = static_cast< E3dScene* >( GetSdrObject() );
+ drawing::CameraGeometry aCamGeo;
+
+ // fill Vectors from scene camera
+ B3dCamera& aCameraSet = pScene->GetCameraSet();
+ basegfx::B3DPoint aVRP(aCameraSet.GetVRP());
+ basegfx::B3DVector aVPN(aCameraSet.GetVPN());
+ basegfx::B3DVector aVUP(aCameraSet.GetVUV());
+
+ // transfer to structure
+ aCamGeo.vrp.PositionX = aVRP.getX();
+ aCamGeo.vrp.PositionY = aVRP.getY();
+ aCamGeo.vrp.PositionZ = aVRP.getZ();
+ aCamGeo.vpn.DirectionX = aVPN.getX();
+ aCamGeo.vpn.DirectionY = aVPN.getY();
+ aCamGeo.vpn.DirectionZ = aVPN.getZ();
+ aCamGeo.vup.DirectionX = aVUP.getX();
+ aCamGeo.vup.DirectionY = aVUP.getY();
+ aCamGeo.vup.DirectionZ = aVUP.getZ();
+
+ rValue <<= aCamGeo;
+ break;
+ }
+ default:
+ return SvxShape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ return true;
+}
+
+// css::lang::XServiceInfo
+uno::Sequence< OUString > SAL_CALL Svx3DSceneObject::getSupportedServiceNames()
+{
+ return comphelper::concatSequences(
+ SvxShape::getSupportedServiceNames(),
+ std::initializer_list<std::u16string_view>{ u"com.sun.star.drawing.Shape3DScene" });
+}
+
+Svx3DCubeObject::Svx3DCubeObject(SdrObject* pObj)
+: SvxShape( pObj, getSvxMapProvider().GetMap(SVXMAP_3DCUBEOBJECT), getSvxMapProvider().GetPropertySet(SVXMAP_3DCUBEOBJECT, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+Svx3DCubeObject::~Svx3DCubeObject() noexcept
+{
+}
+
+bool Svx3DCubeObject::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ SolarMutexGuard aGuard;
+
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // pack transformationmatrix to the object
+ if( ConvertHomogenMatrixToObject( static_cast< E3dObject* >( GetSdrObject() ), rValue ) )
+ return true;
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_POSITION:
+ {
+ // pack position to the object
+ drawing::Position3D aUnoPos;
+ if( rValue >>= aUnoPos )
+ {
+ basegfx::B3DPoint aPos(aUnoPos.PositionX, aUnoPos.PositionY, aUnoPos.PositionZ);
+ static_cast< E3dCubeObj* >( GetSdrObject() )->SetCubePos(aPos);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_SIZE:
+ {
+ // pack size to the object
+ drawing::Direction3D aDirection;
+ if( rValue >>= aDirection )
+ {
+ basegfx::B3DVector aSize(aDirection.DirectionX, aDirection.DirectionY, aDirection.DirectionZ);
+ static_cast< E3dCubeObj* >( GetSdrObject() )->SetCubeSize(aSize);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_POS_IS_CENTER:
+ {
+ bool bNew = false;
+ // pack sal_Bool bPosIsCenter to the object
+ if( rValue >>= bNew )
+ {
+ static_cast< E3dCubeObj* >( GetSdrObject() )->SetPosIsCenter(bNew);
+ return true;
+ }
+ break;
+ }
+ default:
+ return SvxShape::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ throw IllegalArgumentException();
+}
+
+bool Svx3DCubeObject::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // pack transformation to a homogeneous matrix
+ ConvertObjectToHomogenMatric( static_cast< E3dObject* >( GetSdrObject() ), rValue );
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_POSITION:
+ {
+ // pack position
+ const basegfx::B3DPoint& rPos = static_cast<E3dCubeObj*>(GetSdrObject())->GetCubePos();
+ drawing::Position3D aPos;
+
+ aPos.PositionX = rPos.getX();
+ aPos.PositionY = rPos.getY();
+ aPos.PositionZ = rPos.getZ();
+
+ rValue <<= aPos;
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_SIZE:
+ {
+ // pack size
+ const basegfx::B3DVector& rSize = static_cast<E3dCubeObj*>(GetSdrObject())->GetCubeSize();
+ drawing::Direction3D aDir;
+
+ aDir.DirectionX = rSize.getX();
+ aDir.DirectionY = rSize.getY();
+ aDir.DirectionZ = rSize.getZ();
+
+ rValue <<= aDir;
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_POS_IS_CENTER:
+ {
+ rValue <<= static_cast<E3dCubeObj*>(GetSdrObject())->GetPosIsCenter();
+ break;
+ }
+ default:
+ return SvxShape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ return true;
+}
+
+// css::lang::XServiceInfo
+uno::Sequence< OUString > SAL_CALL Svx3DCubeObject::getSupportedServiceNames()
+{
+ return comphelper::concatSequences(
+ SvxShape::getSupportedServiceNames(),
+ std::initializer_list<std::u16string_view>{ u"com.sun.star.drawing.Shape3D",
+ u"com.sun.star.drawing.Shape3DCube" });
+}
+
+Svx3DSphereObject::Svx3DSphereObject(SdrObject* pObj)
+ : SvxShape( pObj, getSvxMapProvider().GetMap(SVXMAP_3DSPHEREOBJECT), getSvxMapProvider().GetPropertySet(SVXMAP_3DSPHEREOBJECT, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+Svx3DSphereObject::~Svx3DSphereObject() noexcept
+{
+}
+
+bool Svx3DSphereObject::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // pack transformation matrix to the object
+ if( ConvertHomogenMatrixToObject( static_cast< E3dObject* >( GetSdrObject() ), rValue ) )
+ return true;
+ break;
+ }
+
+ case OWN_ATTR_3D_VALUE_POSITION:
+ {
+ // pack position to the object
+ drawing::Position3D aUnoPos;
+ if( rValue >>= aUnoPos )
+ {
+ basegfx::B3DPoint aPos(aUnoPos.PositionX, aUnoPos.PositionY, aUnoPos.PositionZ);
+ static_cast<E3dSphereObj*>(GetSdrObject())->SetCenter(aPos);
+ return true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_3D_VALUE_SIZE:
+ {
+ // pack size to the object
+ drawing::Direction3D aDir;
+ if( rValue >>= aDir )
+ {
+ basegfx::B3DVector aPos(aDir.DirectionX, aDir.DirectionY, aDir.DirectionZ);
+ static_cast<E3dSphereObj*>(GetSdrObject())->SetSize(aPos);
+ return true;
+ }
+ break;
+ }
+ default:
+ return SvxShape::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ throw IllegalArgumentException();
+}
+
+bool Svx3DSphereObject::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // pack transformation to a homogeneous matrix
+ ConvertObjectToHomogenMatric( static_cast< E3dObject* >( GetSdrObject() ), rValue );
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_POSITION:
+ {
+ // pack position
+ const basegfx::B3DPoint& rPos = static_cast<E3dSphereObj*>(GetSdrObject())->Center();
+ drawing::Position3D aPos;
+
+ aPos.PositionX = rPos.getX();
+ aPos.PositionY = rPos.getY();
+ aPos.PositionZ = rPos.getZ();
+
+ rValue <<= aPos;
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_SIZE:
+ {
+ // pack size
+ const basegfx::B3DVector& rSize = static_cast<E3dSphereObj*>(GetSdrObject())->Size();
+ drawing::Direction3D aDir;
+
+ aDir.DirectionX = rSize.getX();
+ aDir.DirectionY = rSize.getY();
+ aDir.DirectionZ = rSize.getZ();
+
+ rValue <<= aDir;
+ break;
+ }
+ default:
+ return SvxShape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ return true;
+}
+
+// css::lang::XServiceInfo
+uno::Sequence< OUString > SAL_CALL Svx3DSphereObject::getSupportedServiceNames()
+{
+ return comphelper::concatSequences(
+ SvxShape::getSupportedServiceNames(),
+ std::initializer_list<std::u16string_view>{ u"com.sun.star.drawing.Shape3D",
+ u"com.sun.star.drawing.Shape3DSphere" });
+}
+
+Svx3DLatheObject::Svx3DLatheObject(SdrObject* pObj)
+: SvxShape( pObj, getSvxMapProvider().GetMap(SVXMAP_3DLATHEOBJECT), getSvxMapProvider().GetPropertySet(SVXMAP_3DLATHEOBJECT, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+Svx3DLatheObject::~Svx3DLatheObject() noexcept
+{
+}
+
+static bool PolyPolygonShape3D_to_B3dPolyPolygon(
+ const Any& rValue,
+ basegfx::B3DPolyPolygon& rResultPolygon,
+ bool bCorrectPolygon)
+{
+ drawing::PolyPolygonShape3D aSourcePolyPolygon;
+ if( !(rValue >>= aSourcePolyPolygon) )
+ return false;
+
+ sal_Int32 nOuterSequenceCount = aSourcePolyPolygon.SequenceX.getLength();
+ if(nOuterSequenceCount != aSourcePolyPolygon.SequenceY.getLength() || nOuterSequenceCount != aSourcePolyPolygon.SequenceZ.getLength())
+ return false;
+
+ const drawing::DoubleSequence* pInnerSequenceX = aSourcePolyPolygon.SequenceX.getConstArray();
+ const drawing::DoubleSequence* pInnerSequenceY = aSourcePolyPolygon.SequenceY.getConstArray();
+ const drawing::DoubleSequence* pInnerSequenceZ = aSourcePolyPolygon.SequenceZ.getConstArray();
+ for(sal_Int32 a(0);a<nOuterSequenceCount;a++)
+ {
+ sal_Int32 nInnerSequenceCount = pInnerSequenceX->getLength();
+ if(nInnerSequenceCount != pInnerSequenceY->getLength() || nInnerSequenceCount != pInnerSequenceZ->getLength())
+ {
+ return false;
+ }
+ basegfx::B3DPolygon aNewPolygon;
+ const double* pArrayX = pInnerSequenceX->getConstArray();
+ const double* pArrayY = pInnerSequenceY->getConstArray();
+ const double* pArrayZ = pInnerSequenceZ->getConstArray();
+ for(sal_Int32 b(0);b<nInnerSequenceCount;b++)
+ {
+ aNewPolygon.append(basegfx::B3DPoint(*pArrayX++,*pArrayY++,*pArrayZ++));
+ }
+ pInnerSequenceX++;
+ pInnerSequenceY++;
+ pInnerSequenceZ++;
+
+ // #i101520# correction is needed for imported polygons of old format,
+ // see callers
+ if(bCorrectPolygon)
+ {
+ basegfx::utils::checkClosed(aNewPolygon);
+ }
+
+ rResultPolygon.append(aNewPolygon);
+ }
+ return true;
+}
+
+static void B3dPolyPolygon_to_PolyPolygonShape3D( const basegfx::B3DPolyPolygon& rSourcePolyPolygon, Any& rValue )
+{
+ drawing::PolyPolygonShape3D aRetval;
+ aRetval.SequenceX.realloc(rSourcePolyPolygon.count());
+ aRetval.SequenceY.realloc(rSourcePolyPolygon.count());
+ aRetval.SequenceZ.realloc(rSourcePolyPolygon.count());
+ drawing::DoubleSequence* pOuterSequenceX = aRetval.SequenceX.getArray();
+ drawing::DoubleSequence* pOuterSequenceY = aRetval.SequenceY.getArray();
+ drawing::DoubleSequence* pOuterSequenceZ = aRetval.SequenceZ.getArray();
+ for(sal_uInt32 a(0);a<rSourcePolyPolygon.count();a++)
+ {
+ const basegfx::B3DPolygon& aPoly(rSourcePolyPolygon.getB3DPolygon(a));
+ sal_Int32 nPointCount(aPoly.count());
+ if(aPoly.isClosed()) nPointCount++;
+ pOuterSequenceX->realloc(nPointCount);
+ pOuterSequenceY->realloc(nPointCount);
+ pOuterSequenceZ->realloc(nPointCount);
+ double* pInnerSequenceX = pOuterSequenceX->getArray();
+ double* pInnerSequenceY = pOuterSequenceY->getArray();
+ double* pInnerSequenceZ = pOuterSequenceZ->getArray();
+ for(sal_uInt32 b(0);b<aPoly.count();b++)
+ {
+ const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(b));
+ *pInnerSequenceX++ = aPoint.getX();
+ *pInnerSequenceY++ = aPoint.getY();
+ *pInnerSequenceZ++ = aPoint.getZ();
+ }
+ if(aPoly.isClosed())
+ {
+ const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(0));
+ *pInnerSequenceX++ = aPoint.getX();
+ *pInnerSequenceY++ = aPoint.getY();
+ *pInnerSequenceZ++ = aPoint.getZ();
+ }
+ pOuterSequenceX++;
+ pOuterSequenceY++;
+ pOuterSequenceZ++;
+ }
+ rValue <<= aRetval;
+}
+
+bool Svx3DLatheObject::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // pack transformation matrix to the object
+ if( ConvertHomogenMatrixToObject( static_cast< E3dObject* >( GetSdrObject() ), rValue ) )
+ return true;
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_POLYPOLYGON3D:
+ {
+ // pack polygon definition to the object
+ basegfx::B3DPolyPolygon aNewB3DPolyPolygon;
+
+ // #i101520# Probably imported
+ if( PolyPolygonShape3D_to_B3dPolyPolygon( rValue, aNewB3DPolyPolygon, true ) )
+ {
+ // #105127# SetPolyPoly3D sets the Svx3DVerticalSegmentsItem to the number
+ // of points of the polygon. Thus, value gets lost. To avoid this, rescue
+ // item here and re-set after setting the polygon.
+ const sal_uInt32 nPrevVerticalSegs(static_cast<E3dLatheObj*>(GetSdrObject())->GetVerticalSegments());
+
+ // set polygon
+ const basegfx::B3DHomMatrix aIdentity;
+ const basegfx::B2DPolyPolygon aB2DPolyPolygon(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aNewB3DPolyPolygon, aIdentity));
+ static_cast<E3dLatheObj*>(GetSdrObject())->SetPolyPoly2D(aB2DPolyPolygon);
+ const sal_uInt32 nPostVerticalSegs(static_cast<E3dLatheObj*>(GetSdrObject())->GetVerticalSegments());
+
+ if(nPrevVerticalSegs != nPostVerticalSegs)
+ {
+ // restore the vertical segment count
+ static_cast<E3dLatheObj*>(GetSdrObject())->SetMergedItem(makeSvx3DVerticalSegmentsItem(nPrevVerticalSegs));
+ }
+ return true;
+ }
+ break;
+ }
+ default:
+ return SvxShape::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ throw IllegalArgumentException();
+}
+
+bool Svx3DLatheObject::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // pack transformation to a homogeneous matrix
+ drawing::HomogenMatrix aHomMat;
+ basegfx::B3DHomMatrix aMat = static_cast<E3dObject*>(GetSdrObject())->GetTransform();
+ basegfx::utils::B3DHomMatrixToUnoHomogenMatrix(aMat, aHomMat);
+ rValue <<= aHomMat;
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_POLYPOLYGON3D:
+ {
+ const basegfx::B2DPolyPolygon& rPolyPoly = static_cast<E3dLatheObj*>(GetSdrObject())->GetPolyPoly2D();
+ const basegfx::B3DPolyPolygon aB3DPolyPolygon(basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon(rPolyPoly));
+
+ B3dPolyPolygon_to_PolyPolygonShape3D(aB3DPolyPolygon, rValue);
+ break;
+ }
+ default:
+ return SvxShape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ return true;
+}
+
+// css::lang::XServiceInfo
+uno::Sequence< OUString > SAL_CALL Svx3DLatheObject::getSupportedServiceNames()
+{
+ return comphelper::concatSequences(
+ SvxShape::getSupportedServiceNames(),
+ std::initializer_list<std::u16string_view>{ u"com.sun.star.drawing.Shape3D",
+ u"com.sun.star.drawing.Shape3DLathe" });
+}
+
+Svx3DExtrudeObject::Svx3DExtrudeObject(SdrObject* pObj)
+: SvxShape( pObj, getSvxMapProvider().GetMap(SVXMAP_3DEXTRUDEOBJECT), getSvxMapProvider().GetPropertySet(SVXMAP_3DEXTRUDEOBJECT, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+Svx3DExtrudeObject::~Svx3DExtrudeObject() noexcept
+{
+}
+
+bool Svx3DExtrudeObject::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // pack transformation matrix to the object
+ if( ConvertHomogenMatrixToObject( static_cast< E3dObject* >( GetSdrObject() ), rValue ) )
+ return true;
+ break;
+ }
+
+ case OWN_ATTR_3D_VALUE_POLYPOLYGON3D:
+ {
+ // pack polygon definition to the object
+ basegfx::B3DPolyPolygon aNewB3DPolyPolygon;
+
+ // #i101520# Probably imported
+ if( PolyPolygonShape3D_to_B3dPolyPolygon( rValue, aNewB3DPolyPolygon, true ) )
+ {
+ // set polygon
+ const basegfx::B3DHomMatrix aIdentity;
+ const basegfx::B2DPolyPolygon aB2DPolyPolygon(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aNewB3DPolyPolygon, aIdentity));
+ static_cast<E3dExtrudeObj*>(GetSdrObject())->SetExtrudePolygon(aB2DPolyPolygon);
+ return true;
+ }
+ break;
+ }
+ default:
+ return SvxShape::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ throw IllegalArgumentException();
+}
+
+bool Svx3DExtrudeObject::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // pack transformation to a homogeneous matrix
+ drawing::HomogenMatrix aHomMat;
+ basegfx::B3DHomMatrix aMat = static_cast<E3dObject*>(GetSdrObject())->GetTransform();
+ basegfx::utils::B3DHomMatrixToUnoHomogenMatrix(aMat, aHomMat);
+ rValue <<= aHomMat;
+ break;
+ }
+
+ case OWN_ATTR_3D_VALUE_POLYPOLYGON3D:
+ {
+ // pack polygon definition
+ const basegfx::B2DPolyPolygon& rPolyPoly = static_cast<E3dExtrudeObj*>(GetSdrObject())->GetExtrudePolygon();
+ const basegfx::B3DPolyPolygon aB3DPolyPolygon(basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon(rPolyPoly));
+
+ B3dPolyPolygon_to_PolyPolygonShape3D(aB3DPolyPolygon, rValue);
+ break;
+ }
+ default:
+ return SvxShape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ return true;
+}
+
+// css::lang::XServiceInfo
+uno::Sequence< OUString > SAL_CALL Svx3DExtrudeObject::getSupportedServiceNames()
+{
+ return comphelper::concatSequences(
+ SvxShape::getSupportedServiceNames(),
+ std::initializer_list<std::u16string_view>{ u"com.sun.star.drawing.Shape3D",
+ u"com.sun.star.drawing.Shape3DExtrude" });
+}
+
+Svx3DPolygonObject::Svx3DPolygonObject(SdrObject* pObj)
+: SvxShape( pObj, getSvxMapProvider().GetMap(SVXMAP_3DPOLYGONOBJECT), getSvxMapProvider().GetPropertySet(SVXMAP_3DPOLYGONOBJECT, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+Svx3DPolygonObject::~Svx3DPolygonObject() noexcept
+{
+}
+
+bool Svx3DPolygonObject::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ // pack transformation matrix to the object
+ if( ConvertHomogenMatrixToObject( static_cast< E3dObject* >( GetSdrObject() ), rValue ) )
+ return true;
+ break;
+ }
+
+ case OWN_ATTR_3D_VALUE_POLYPOLYGON3D:
+ {
+ // pack polygon definition to the object
+ basegfx::B3DPolyPolygon aNewB3DPolyPolygon;
+
+ // #i101520# Direct API data (e.g. from chart)
+ if( PolyPolygonShape3D_to_B3dPolyPolygon( rValue, aNewB3DPolyPolygon, false ) )
+ {
+ // set polygon
+ static_cast<E3dPolygonObj*>(GetSdrObject())->SetPolyPolygon3D(aNewB3DPolyPolygon);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_NORMALSPOLYGON3D:
+ {
+ // pack perpendicular definition to the object
+ basegfx::B3DPolyPolygon aNewB3DPolyPolygon;
+
+ // #i101520# Direct API data (e.g. from chart)
+ if( PolyPolygonShape3D_to_B3dPolyPolygon( rValue, aNewB3DPolyPolygon, false ) )
+ {
+ // set polygon
+ static_cast<E3dPolygonObj*>(GetSdrObject())->SetPolyNormals3D(aNewB3DPolyPolygon);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_TEXTUREPOLYGON3D:
+ {
+ // pack texture definition to the object
+ basegfx::B3DPolyPolygon aNewB3DPolyPolygon;
+
+ // #i101520# Direct API data (e.g. from chart)
+ if( PolyPolygonShape3D_to_B3dPolyPolygon( rValue, aNewB3DPolyPolygon, false ) )
+ {
+ // set polygon
+ const basegfx::B3DHomMatrix aIdentity;
+ const basegfx::B2DPolyPolygon aB2DPolyPolygon(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aNewB3DPolyPolygon, aIdentity));
+ static_cast<E3dPolygonObj*>(GetSdrObject())->SetPolyTexture2D(aB2DPolyPolygon);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_3D_VALUE_LINEONLY:
+ {
+ bool bNew = false;
+ if( rValue >>= bNew )
+ {
+ static_cast<E3dPolygonObj*>(GetSdrObject())->SetLineOnly(bNew);
+ return true;
+ }
+ break;
+ }
+ default:
+ return SvxShape::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ throw IllegalArgumentException();
+}
+
+bool Svx3DPolygonObject::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_3D_VALUE_TRANSFORM_MATRIX:
+ {
+ ConvertObjectToHomogenMatric( static_cast< E3dObject* >( GetSdrObject() ), rValue );
+ break;
+ }
+
+ case OWN_ATTR_3D_VALUE_POLYPOLYGON3D:
+ {
+ B3dPolyPolygon_to_PolyPolygonShape3D(static_cast<E3dPolygonObj*>(GetSdrObject())->GetPolyPolygon3D(),rValue);
+ break;
+ }
+
+ case OWN_ATTR_3D_VALUE_NORMALSPOLYGON3D:
+ {
+ B3dPolyPolygon_to_PolyPolygonShape3D(static_cast<E3dPolygonObj*>(GetSdrObject())->GetPolyNormals3D(),rValue);
+ break;
+ }
+
+ case OWN_ATTR_3D_VALUE_TEXTUREPOLYGON3D:
+ {
+ // pack texture definition
+ const basegfx::B2DPolyPolygon& rPolyPoly = static_cast<E3dPolygonObj*>(GetSdrObject())->GetPolyTexture2D();
+ const basegfx::B3DPolyPolygon aB3DPolyPolygon(basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon(rPolyPoly));
+
+ B3dPolyPolygon_to_PolyPolygonShape3D(aB3DPolyPolygon,rValue);
+ break;
+ }
+
+ case OWN_ATTR_3D_VALUE_LINEONLY:
+ {
+ rValue <<= static_cast<E3dPolygonObj*>(GetSdrObject())->GetLineOnly();
+ break;
+ }
+
+ default:
+ return SvxShape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ return true;
+}
+
+// css::lang::XServiceInfo
+uno::Sequence< OUString > SAL_CALL Svx3DPolygonObject::getSupportedServiceNames()
+{
+ return comphelper::concatSequences(
+ SvxShape::getSupportedServiceNames(),
+ std::initializer_list<std::u16string_view>{ u"com.sun.star.drawing.Shape3D",
+ u"com.sun.star.drawing.Shape3DPolygon" });
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unoshap4.cxx b/svx/source/unodraw/unoshap4.cxx
new file mode 100644
index 000000000..18ce14f5e
--- /dev/null
+++ b/svx/source/unodraw/unoshap4.cxx
@@ -0,0 +1,1115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XLinkageSupport.hpp>
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/ucb/CommandFailedException.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+
+#include <svx/svdoole2.hxx>
+#include <svx/svdomedia.hxx>
+#include <svx/svdpool.hxx>
+#include <comphelper/classids.hxx>
+#include <comphelper/embeddedobjectcontainer.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <sot/exchange.hxx>
+
+#include <svx/svdmodel.hxx>
+#include "shapeimpl.hxx"
+
+#include <svx/unoshprp.hxx>
+
+#include <vcl/gdimtf.hxx>
+#include <vcl/wmf.hxx>
+#include <svtools/embedhlp.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <tools/globname.hxx>
+#include <tools/stream.hxx>
+
+#include <config_features.h>
+
+
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+
+
+SvxOle2Shape::SvxOle2Shape(SdrObject* pObject)
+: SvxShapeText( pObject, getSvxMapProvider().GetMap(SVXMAP_OLE2),
+ getSvxMapProvider().GetPropertySet(SVXMAP_OLE2,SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+}
+
+SvxOle2Shape::SvxOle2Shape(SdrObject* pObject, const SfxItemPropertyMapEntry* pPropertyMap, const SvxItemPropertySet* pPropertySet)
+: SvxShapeText( pObject, pPropertyMap, pPropertySet )
+{
+}
+
+SvxOle2Shape::~SvxOle2Shape() noexcept
+{
+}
+
+//XPropertySet
+bool SvxOle2Shape::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_OLE_VISAREA:
+ {
+ // TODO/LATER: seems to make no sense for iconified object
+
+ awt::Rectangle aVisArea;
+ if( !(rValue >>= aVisArea))
+ break;
+ if( auto pOle2Obj = dynamic_cast<SdrOle2Obj* >(GetSdrObject()) )
+ {
+ Size aTmp( aVisArea.X + aVisArea.Width, aVisArea.Y + aVisArea.Height );
+ uno::Reference < embed::XEmbeddedObject > xObj = pOle2Obj->GetObjRef();
+ if( xObj.is() )
+ {
+ try
+ {
+ // the API handles with MapUnit::Map100thMM map mode
+ MapUnit aObjUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( embed::Aspects::MSOLE_CONTENT ) );
+ aTmp = OutputDevice::LogicToLogic(aTmp, MapMode(MapUnit::Map100thMM), MapMode(aObjUnit));
+ xObj->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, awt::Size( aTmp.Width(), aTmp.Height() ) );
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( "Couldn't set the visual area for the object!" );
+ }
+ }
+
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_OLE_ASPECT:
+ {
+ sal_Int64 nAspect = 0;
+ if( rValue >>= nAspect )
+ {
+ static_cast<SdrOle2Obj*>(GetSdrObject())->SetAspect( nAspect );
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_CLSID:
+ {
+ OUString aCLSID;
+ if( rValue >>= aCLSID )
+ {
+ // init an OLE object with a global name
+ SvGlobalName aClassName;
+ if( aClassName.MakeId( aCLSID ) )
+ {
+ if( createObject( aClassName ) )
+ return true;
+ }
+ }
+ break;
+ }
+ case OWN_ATTR_THUMBNAIL:
+ {
+ uno::Reference< graphic::XGraphic > xGraphic( rValue, uno::UNO_QUERY );
+ if( xGraphic.is() )
+ {
+ const Graphic aGraphic(xGraphic);
+ static_cast<SdrOle2Obj*>(GetSdrObject())->SetGraphic(aGraphic);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_VALUE_GRAPHIC:
+ {
+ uno::Reference< graphic::XGraphic > xGraphic( rValue, uno::UNO_QUERY );
+ if( xGraphic.is() )
+ {
+ SdrOle2Obj* pOle = dynamic_cast< SdrOle2Obj* >( GetSdrObject() );
+ if( pOle )
+ {
+ GraphicObject aGrafObj( xGraphic );
+ const Graphic& aGraphic( aGrafObj.GetGraphic() );
+ pOle->SetGraphicToObj( aGraphic );
+ }
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_PERSISTNAME:
+ {
+ OUString aPersistName;
+ if( rValue >>= aPersistName )
+ {
+ SdrOle2Obj *pOle;
+#if OSL_DEBUG_LEVEL > 0
+ pOle = dynamic_cast<SdrOle2Obj*>(GetSdrObject());
+ assert(pOle);
+#else
+ pOle = static_cast<SdrOle2Obj*>(GetSdrObject());
+#endif
+ pOle->SetPersistName( aPersistName, this );
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_OLE_LINKURL:
+ {
+ OUString aLinkURL;
+ if( rValue >>= aLinkURL )
+ {
+ createLink( aLinkURL );
+ return true;
+ }
+ break;
+ }
+ default:
+ return SvxShapeText::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ throw IllegalArgumentException();
+}
+
+bool SvxOle2Shape::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_CLSID:
+ {
+ OUString aCLSID;
+ GetClassName_Impl(aCLSID);
+ rValue <<= aCLSID;
+ break;
+ }
+
+ case OWN_ATTR_INTERNAL_OLE:
+ {
+ OUString sCLSID;
+ rValue <<= SotExchange::IsInternal( GetClassName_Impl(sCLSID) );
+ break;
+ }
+
+ case OWN_ATTR_METAFILE:
+ {
+ SdrOle2Obj* pObj = dynamic_cast<SdrOle2Obj*>(GetSdrObject());
+ if( pObj )
+ {
+ const Graphic* pGraphic = pObj->GetGraphic();
+ if( pGraphic )
+ {
+ bool bIsWMF = false;
+ if ( pGraphic->IsGfxLink() )
+ {
+ GfxLink aLnk = pGraphic->GetGfxLink();
+ if ( aLnk.GetType() == GfxLinkType::NativeWmf )
+ {
+ bIsWMF = true;
+ uno::Sequence<sal_Int8> aSeq(reinterpret_cast<sal_Int8 const *>(aLnk.GetData()), static_cast<sal_Int32>(aLnk.GetDataSize()));
+ rValue <<= aSeq;
+ }
+ }
+ if ( !bIsWMF )
+ {
+ // #i119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
+ GDIMetaFile aMtf(pObj->GetGraphic()->GetGDIMetaFile());
+ SvMemoryStream aDestStrm( 65535, 65535 );
+ ConvertGDIMetaFileToWMF( aMtf, aDestStrm, nullptr, false );
+ const uno::Sequence<sal_Int8> aSeq(
+ static_cast< const sal_Int8* >(aDestStrm.GetData()),
+ aDestStrm.GetEndOfData());
+ rValue <<= aSeq;
+ }
+ }
+ }
+ else
+ {
+ rValue = GetBitmap( true );
+ }
+ break;
+ }
+
+ case OWN_ATTR_OLE_VISAREA:
+ {
+ awt::Rectangle aVisArea;
+ if( dynamic_cast<const SdrOle2Obj* >(GetSdrObject()) != nullptr)
+ {
+ MapMode aMapMode( MapUnit::Map100thMM ); // the API uses this map mode
+ Size aTmp = static_cast<SdrOle2Obj*>(GetSdrObject())->GetOrigObjSize( &aMapMode ); // get the size in the requested map mode
+ aVisArea = awt::Rectangle( 0, 0, aTmp.Width(), aTmp.Height() );
+ }
+
+ rValue <<= aVisArea;
+ break;
+ }
+
+ case OWN_ATTR_OLESIZE:
+ {
+ Size aTmp( static_cast<SdrOle2Obj*>(GetSdrObject())->GetOrigObjSize() );
+ rValue <<= awt::Size( aTmp.Width(), aTmp.Height() );
+ break;
+ }
+
+ case OWN_ATTR_OLE_ASPECT:
+ {
+ rValue <<= static_cast<SdrOle2Obj*>(GetSdrObject())->GetAspect();
+ break;
+ }
+
+ case OWN_ATTR_OLEMODEL:
+ case OWN_ATTR_OLE_EMBEDDED_OBJECT:
+ case OWN_ATTR_OLE_EMBEDDED_OBJECT_NONEWCLIENT:
+ {
+ SdrOle2Obj* pObj = dynamic_cast<SdrOle2Obj*>( GetSdrObject() );
+ if( pObj )
+ {
+ uno::Reference < embed::XEmbeddedObject > xObj( pObj->GetObjRef() );
+ if ( xObj.is()
+ && ( pProperty->nWID == OWN_ATTR_OLE_EMBEDDED_OBJECT || pProperty->nWID == OWN_ATTR_OLE_EMBEDDED_OBJECT_NONEWCLIENT || svt::EmbeddedObjectRef::TryRunningState( xObj ) ) )
+ {
+ // Discussed with CL fue to the before GetPaintingPageView
+ // usage. Removed it, former fallback is used now
+ if ( pProperty->nWID == OWN_ATTR_OLEMODEL || pProperty->nWID == OWN_ATTR_OLE_EMBEDDED_OBJECT )
+ {
+ const bool bSuccess(pObj->AddOwnLightClient());
+ SAL_WARN_IF(!bSuccess, "svx.svdraw", "An object without client is provided!");
+ }
+
+ if ( pProperty->nWID == OWN_ATTR_OLEMODEL )
+ rValue <<= pObj->GetObjRef()->getComponent();
+ else
+ rValue <<= xObj;
+ }
+ }
+ break;
+ }
+
+ case OWN_ATTR_VALUE_GRAPHIC:
+ {
+ uno::Reference< graphic::XGraphic > xGraphic;
+ const Graphic* pGraphic = static_cast<SdrOle2Obj*>( GetSdrObject() )->GetGraphic();
+ if( pGraphic )
+ xGraphic = pGraphic->GetXGraphic();
+ rValue <<= xGraphic;
+ break;
+ }
+
+ case OWN_ATTR_THUMBNAIL:
+ {
+ uno::Reference< graphic::XGraphic > xGraphic;
+ const Graphic* pGraphic = static_cast<SdrOle2Obj*>( GetSdrObject() )->GetGraphic();
+ if( pGraphic )
+ xGraphic = pGraphic->GetXGraphic();
+ rValue <<= xGraphic;
+ break;
+ }
+ case OWN_ATTR_PERSISTNAME:
+ {
+ OUString aPersistName;
+ SdrOle2Obj* pOle = dynamic_cast< SdrOle2Obj* >( GetSdrObject() );
+
+ if( pOle )
+ {
+ aPersistName = pOle->GetPersistName();
+ if( !aPersistName.isEmpty() )
+ {
+ ::comphelper::IEmbeddedHelper* pPersist(GetSdrObject()->getSdrModelFromSdrObject().GetPersist());
+ if( (nullptr == pPersist) || !pPersist->getEmbeddedObjectContainer().HasEmbeddedObject( pOle->GetPersistName() ) )
+ aPersistName.clear();
+ }
+ }
+
+ rValue <<= aPersistName;
+ break;
+ }
+ case OWN_ATTR_OLE_LINKURL:
+ {
+ OUString aLinkURL;
+ SdrOle2Obj* pOle = dynamic_cast< SdrOle2Obj* >( GetSdrObject() );
+
+ if( pOle )
+ {
+ uno::Reference< embed::XLinkageSupport > xLink( pOle->GetObjRef(), uno::UNO_QUERY );
+ if ( xLink.is() && xLink->isLink() )
+ aLinkURL = xLink->getLinkURL();
+ }
+
+ rValue <<= aLinkURL;
+ break;
+ }
+ default:
+ return SvxShapeText::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ return true;
+}
+
+bool SvxOle2Shape::createObject( const SvGlobalName &aClassName )
+{
+ DBG_TESTSOLARMUTEX();
+
+ SdrOle2Obj* pOle2Obj = dynamic_cast< SdrOle2Obj* >( GetSdrObject() );
+ if ( !pOle2Obj || !pOle2Obj->IsEmpty() )
+ return false;
+
+ // create storage and inplace object
+ ::comphelper::IEmbeddedHelper* pPersist = GetSdrObject()->getSdrModelFromSdrObject().GetPersist();
+ OUString aPersistName;
+ OUString aTmpStr;
+ if( SvxShape::getPropertyValue( UNO_NAME_OLE2_PERSISTNAME ) >>= aTmpStr )
+ aPersistName = aTmpStr;
+
+ uno::Sequence<beans::PropertyValue> objArgs( comphelper::InitPropertySequence({
+ { "DefaultParentBaseURL", Any(pPersist->getDocumentBaseURL()) }
+ }));
+ //TODO/LATER: how to cope with creation failure?!
+ uno::Reference<embed::XEmbeddedObject> xObj(
+ pPersist->getEmbeddedObjectContainer().CreateEmbeddedObject(
+ aClassName.GetByteSequence(), objArgs, aPersistName));
+ if( xObj.is() )
+ {
+ tools::Rectangle aRect = pOle2Obj->GetLogicRect();
+ if ( aRect.GetWidth() == 101 && aRect.GetHeight() == 101 )
+ {
+ // TODO/LATER: is it possible that this method is used to create an iconified object?
+ // default size
+ try
+ {
+ awt::Size aSz = xObj->getVisualAreaSize( pOle2Obj->GetAspect() );
+ aRect.SetSize( Size( aSz.Width, aSz.Height ) );
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {}
+ pOle2Obj->SetLogicRect( aRect );
+ }
+ else
+ {
+ awt::Size aSz;
+ Size aSize = aRect.GetSize();
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+ if (aSz.Width != 0 || aSz.Height != 0)
+ {
+ //HACK: can aSz legally be empty?
+ xObj->setVisualAreaSize( pOle2Obj->GetAspect(), aSz );
+ }
+ }
+
+ // connect the object after the visual area is set
+ aTmpStr = aPersistName;
+ SvxShape::setPropertyValue( UNO_NAME_OLE2_PERSISTNAME, Any( aTmpStr ) );
+
+ // the object is inserted during setting of PersistName property usually
+ if( pOle2Obj->IsEmpty() )
+ pOle2Obj->SetObjRef( xObj );
+ }
+
+ return xObj.is();
+}
+
+void SvxOle2Shape::createLink( const OUString& aLinkURL )
+{
+ DBG_TESTSOLARMUTEX();
+
+ SdrOle2Obj* pOle2Obj = dynamic_cast< SdrOle2Obj* >( GetSdrObject() );
+ if ( !pOle2Obj || !pOle2Obj->IsEmpty() )
+ return;
+
+ OUString aPersistName;
+
+ ::comphelper::IEmbeddedHelper* pPersist = GetSdrObject()->getSdrModelFromSdrObject().GetPersist();
+
+ uno::Sequence< beans::PropertyValue > aMediaDescr{ comphelper::makePropertyValue("URL",
+ aLinkURL) };
+
+ uno::Reference< task::XInteractionHandler > xInteraction = pPersist->getInteractionHandler();
+ if ( xInteraction.is() )
+ {
+ aMediaDescr.realloc( 2 );
+ auto pMediaDescr = aMediaDescr.getArray();
+ pMediaDescr[1].Name = "InteractionHandler";
+ pMediaDescr[1].Value <<= xInteraction;
+ }
+
+ //TODO/LATER: how to cope with creation failure?!
+ uno::Reference< embed::XEmbeddedObject > xObj =
+ pPersist->getEmbeddedObjectContainer().InsertEmbeddedLink( aMediaDescr , aPersistName );
+
+ if( !xObj.is() )
+ return;
+
+ tools::Rectangle aRect = pOle2Obj->GetLogicRect();
+ if ( aRect.GetWidth() == 101 && aRect.GetHeight() == 101 )
+ {
+ // default size
+ try
+ {
+ awt::Size aSz = xObj->getVisualAreaSize( pOle2Obj->GetAspect() );
+ aRect.SetSize( Size( aSz.Width, aSz.Height ) );
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {}
+ pOle2Obj->SetLogicRect( aRect );
+ }
+ else
+ {
+ awt::Size aSz;
+ Size aSize = pOle2Obj->GetLogicRect().GetSize();
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+ xObj->setVisualAreaSize( pOle2Obj->GetAspect(), aSz );
+ }
+
+ // connect the object after the visual area is set
+ SvxShape::setPropertyValue( UNO_NAME_OLE2_PERSISTNAME, uno::Any( aPersistName ) );
+
+ // the object is inserted during setting of PersistName property usually
+ if ( pOle2Obj->IsEmpty() )
+ pOle2Obj->SetObjRef( xObj );
+}
+
+void SvxOle2Shape::resetModifiedState()
+{
+ SdrObject* pObject = GetSdrObject();
+ ::comphelper::IEmbeddedHelper* pPersist = pObject ? pObject->getSdrModelFromSdrObject().GetPersist() : nullptr;
+ if( pPersist && !pPersist->isEnableSetModified() )
+ {
+ SdrOle2Obj* pOle = dynamic_cast< SdrOle2Obj* >(pObject);
+ if( pOle && !pOle->IsEmpty() )
+ {
+ uno::Reference < util::XModifiable > xMod( pOle->GetObjRef(), uno::UNO_QUERY );
+ if( xMod.is() )
+ // TODO/MBA: what's this?!
+ xMod->setModified( false );
+ }
+ }
+}
+
+SvGlobalName SvxOle2Shape::GetClassName_Impl(OUString& rHexCLSID)
+{
+ DBG_TESTSOLARMUTEX();
+ SvGlobalName aClassName;
+ SdrOle2Obj* pOle2Obj = dynamic_cast< SdrOle2Obj* >( GetSdrObject() );
+
+ if( pOle2Obj )
+ {
+ rHexCLSID.clear();
+
+ if( pOle2Obj->IsEmpty() )
+ {
+ ::comphelper::IEmbeddedHelper* pPersist = GetSdrObject()->getSdrModelFromSdrObject().GetPersist();
+ if( pPersist )
+ {
+ uno::Reference < embed::XEmbeddedObject > xObj =
+ pPersist->getEmbeddedObjectContainer().GetEmbeddedObject( pOle2Obj->GetPersistName() );
+ if ( xObj.is() )
+ {
+ aClassName = SvGlobalName( xObj->getClassID() );
+ rHexCLSID = aClassName.GetHexName();
+ }
+ }
+ }
+
+ if (rHexCLSID.isEmpty())
+ {
+ const uno::Reference < embed::XEmbeddedObject >& xObj( pOle2Obj->GetObjRef() );
+ if ( xObj.is() )
+ {
+ aClassName = SvGlobalName( xObj->getClassID() );
+ rHexCLSID = aClassName.GetHexName();
+ }
+ }
+ }
+
+ return aClassName;
+}
+
+OUString SvxOle2Shape::GetAndClearInitialFrameURL()
+{
+ return OUString();
+}
+
+SvxAppletShape::SvxAppletShape(SdrObject* pObject)
+ : SvxOle2Shape( pObject, getSvxMapProvider().GetMap(SVXMAP_APPLET), getSvxMapProvider().GetPropertySet(SVXMAP_APPLET, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+ SetShapeType( "com.sun.star.drawing.AppletShape" );
+}
+
+SvxAppletShape::~SvxAppletShape() noexcept
+{
+}
+
+void SvxAppletShape::Create( SdrObject* pNewObj, SvxDrawPage* pNewPage )
+{
+ SvxShape::Create( pNewObj, pNewPage );
+ const SvGlobalName aAppletClassId( SO3_APPLET_CLASSID );
+ createObject(aAppletClassId);
+ SetShapeType( "com.sun.star.drawing.AppletShape" );
+}
+
+void SAL_CALL SvxAppletShape::setPropertyValue( const OUString& aPropertyName, const css::uno::Any& rValue )
+{
+ SvxShape::setPropertyValue( aPropertyName, rValue );
+ resetModifiedState();
+}
+
+void SAL_CALL SvxAppletShape::setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& rValues )
+{
+ SvxShape::setPropertyValues( aPropertyNames, rValues );
+ resetModifiedState();
+}
+
+bool SvxAppletShape::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ if( (pProperty->nWID >= OWN_ATTR_APPLET_DOCBASE) && (pProperty->nWID <= OWN_ATTR_APPLET_ISSCRIPT) )
+ {
+ if ( svt::EmbeddedObjectRef::TryRunningState( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef()->getComponent(), uno::UNO_QUERY );
+ if( xSet.is() )
+ {
+ // allow exceptions to pass through
+ xSet->setPropertyValue( rName, rValue );
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return SvxOle2Shape::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+}
+
+bool SvxAppletShape::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ if( (pProperty->nWID >= OWN_ATTR_APPLET_DOCBASE) && (pProperty->nWID <= OWN_ATTR_APPLET_ISSCRIPT) )
+ {
+ if ( svt::EmbeddedObjectRef::TryRunningState( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef()->getComponent(), uno::UNO_QUERY );
+ if( xSet.is() )
+ {
+ rValue = xSet->getPropertyValue( rName );
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return SvxOle2Shape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+}
+
+SvxPluginShape::SvxPluginShape(SdrObject* pObject)
+ : SvxOle2Shape( pObject, getSvxMapProvider().GetMap(SVXMAP_PLUGIN), getSvxMapProvider().GetPropertySet(SVXMAP_PLUGIN, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+ SetShapeType( "com.sun.star.drawing.PluginShape" );
+}
+
+SvxPluginShape::~SvxPluginShape() noexcept
+{
+}
+
+void SvxPluginShape::Create( SdrObject* pNewObj, SvxDrawPage* pNewPage )
+{
+ SvxShape::Create( pNewObj, pNewPage );
+ const SvGlobalName aPluginClassId( SO3_PLUGIN_CLASSID );
+ createObject(aPluginClassId);
+ SetShapeType( "com.sun.star.drawing.PluginShape" );
+}
+
+void SAL_CALL SvxPluginShape::setPropertyValue( const OUString& aPropertyName, const css::uno::Any& rValue )
+{
+ SvxShape::setPropertyValue( aPropertyName, rValue );
+ resetModifiedState();
+}
+
+void SAL_CALL SvxPluginShape::setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& rValues )
+{
+ SvxShape::setPropertyValues( aPropertyNames, rValues );
+ resetModifiedState();
+}
+
+bool SvxPluginShape::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ if( (pProperty->nWID >= OWN_ATTR_PLUGIN_MIMETYPE) && (pProperty->nWID <= OWN_ATTR_PLUGIN_COMMANDS) )
+ {
+ if( svt::EmbeddedObjectRef::TryRunningState( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef()->getComponent(), uno::UNO_QUERY );
+ if( xSet.is() )
+ {
+ // allow exceptions to pass through
+ xSet->setPropertyValue( rName, rValue );
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return SvxOle2Shape::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+}
+
+bool SvxPluginShape::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ if( (pProperty->nWID >= OWN_ATTR_PLUGIN_MIMETYPE) && (pProperty->nWID <= OWN_ATTR_PLUGIN_COMMANDS) )
+ {
+ if( svt::EmbeddedObjectRef::TryRunningState( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef()->getComponent(), uno::UNO_QUERY );
+ if( xSet.is() )
+ {
+ rValue = xSet->getPropertyValue( rName );
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return SvxOle2Shape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+}
+
+
+SvxFrameShape::SvxFrameShape(SdrObject* pObject)
+: SvxOle2Shape( pObject, getSvxMapProvider().GetMap(SVXMAP_FRAME), getSvxMapProvider().GetPropertySet(SVXMAP_FRAME, SdrObject::GetGlobalDrawObjectItemPool()) )
+{
+ SetShapeType( "com.sun.star.drawing.FrameShape" );
+}
+
+SvxFrameShape::~SvxFrameShape() noexcept
+{
+}
+
+OUString SvxFrameShape::GetAndClearInitialFrameURL()
+{
+ OUString sRet(m_sInitialFrameURL);
+ m_sInitialFrameURL.clear();
+ return sRet;
+}
+
+void SvxFrameShape::Create( SdrObject* pNewObj, SvxDrawPage* pNewPage )
+{
+ uno::Reference<beans::XPropertySet> xSet(static_cast<OWeakObject *>(this), uno::UNO_QUERY);
+ if (xSet)
+ xSet->getPropertyValue("FrameURL") >>= m_sInitialFrameURL;
+
+ SvxShape::Create( pNewObj, pNewPage );
+ const SvGlobalName aIFrameClassId( SO3_IFRAME_CLASSID );
+ createObject(aIFrameClassId);
+ SetShapeType( "com.sun.star.drawing.FrameShape" );
+}
+
+void SAL_CALL SvxFrameShape::setPropertyValue( const OUString& aPropertyName, const css::uno::Any& rValue )
+{
+ SvxShape::setPropertyValue( aPropertyName, rValue );
+ resetModifiedState();
+}
+
+void SAL_CALL SvxFrameShape::setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& rValues )
+{
+ SvxShape::setPropertyValues( aPropertyNames, rValues );
+ resetModifiedState();
+}
+
+bool SvxFrameShape::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ if( (pProperty->nWID >= OWN_ATTR_FRAME_URL) && (pProperty->nWID <= OWN_ATTR_FRAME_MARGIN_HEIGHT) )
+ {
+ if( svt::EmbeddedObjectRef::TryRunningState( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef()->getComponent(), uno::UNO_QUERY );
+ if( xSet.is() )
+ {
+ // allow exceptions to pass through
+ xSet->setPropertyValue( rName, rValue );
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return SvxOle2Shape::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+}
+
+bool SvxFrameShape::getPropertyValueImpl(const OUString& rName, const SfxItemPropertyMapEntry* pProperty,
+ css::uno::Any& rValue)
+{
+ if( (pProperty->nWID >= OWN_ATTR_FRAME_URL) && (pProperty->nWID <= OWN_ATTR_FRAME_MARGIN_HEIGHT) )
+ {
+ if( svt::EmbeddedObjectRef::TryRunningState( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( static_cast<SdrOle2Obj*>(GetSdrObject())->GetObjRef()->getComponent(), uno::UNO_QUERY );
+ if( xSet.is() )
+ {
+ rValue = xSet->getPropertyValue( rName );
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return SvxOle2Shape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+}
+SvxMediaShape::SvxMediaShape(SdrObject* pObj, OUString const & referer)
+: SvxShape( pObj, getSvxMapProvider().GetMap(SVXMAP_MEDIA), getSvxMapProvider().GetPropertySet(SVXMAP_MEDIA, SdrObject::GetGlobalDrawObjectItemPool()) ),
+ referer_(referer)
+{
+ SetShapeType( "com.sun.star.drawing.MediaShape" );
+}
+
+
+SvxMediaShape::~SvxMediaShape() noexcept
+{
+}
+
+
+bool SvxMediaShape::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ if( ((pProperty->nWID >= OWN_ATTR_MEDIA_URL) && (pProperty->nWID <= OWN_ATTR_MEDIA_ZOOM))
+ || (pProperty->nWID == OWN_ATTR_MEDIA_STREAM)
+ || (pProperty->nWID == OWN_ATTR_MEDIA_MIMETYPE)
+ || (pProperty->nWID == OWN_ATTR_VALUE_GRAPHIC)
+ || (pProperty->nWID == SDRATTR_GRAFCROP))
+ {
+#if HAVE_FEATURE_AVMEDIA
+ SdrMediaObj* pMedia = static_cast< SdrMediaObj* >( GetSdrObject() );
+ ::avmedia::MediaItem aItem;
+ bool bOk = false;
+#endif
+
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_MEDIA_URL:
+#if HAVE_FEATURE_AVMEDIA
+ {
+ OUString aURL;
+ if( rValue >>= aURL )
+ {
+ bOk = true;
+ aItem.setURL( aURL, "", referer_ );
+ }
+ }
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_LOOP:
+#if HAVE_FEATURE_AVMEDIA
+ {
+ bool bLoop;
+
+ if( rValue >>= bLoop )
+ {
+ bOk = true;
+ aItem.setLoop( bLoop );
+ }
+ }
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_MUTE:
+#if HAVE_FEATURE_AVMEDIA
+ {
+ bool bMute;
+
+ if( rValue >>= bMute )
+ {
+ bOk = true;
+ aItem.setMute( bMute );
+ }
+ }
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_VOLUMEDB:
+#if HAVE_FEATURE_AVMEDIA
+ {
+ sal_Int16 nVolumeDB = sal_Int16();
+
+ if( rValue >>= nVolumeDB )
+ {
+ bOk = true;
+ aItem.setVolumeDB( nVolumeDB );
+ }
+ }
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_ZOOM:
+#if HAVE_FEATURE_AVMEDIA
+ {
+ css::media::ZoomLevel eLevel;
+
+ if( rValue >>= eLevel )
+ {
+ bOk = true;
+ aItem.setZoom( eLevel );
+ }
+ }
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_MIMETYPE:
+#if HAVE_FEATURE_AVMEDIA
+ {
+ OUString sMimeType;
+ if( rValue >>= sMimeType )
+ {
+ bOk = true;
+ aItem.setMimeType( sMimeType );
+ }
+ }
+#endif
+ break;
+
+ case OWN_ATTR_VALUE_GRAPHIC:
+#if HAVE_FEATURE_AVMEDIA
+ {
+ uno::Reference<graphic::XGraphic> xGraphic(rValue, uno::UNO_QUERY);
+ if (xGraphic.is())
+ {
+ bOk = true;
+ aItem.setGraphic(Graphic(xGraphic));
+ }
+ }
+#endif
+ break;
+
+ case SDRATTR_GRAFCROP:
+#if HAVE_FEATURE_AVMEDIA
+ {
+ text::GraphicCrop aCrop;
+ if (rValue >>= aCrop)
+ {
+ bOk = true;
+ aItem.setCrop(aCrop);
+ }
+ }
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_STREAM:
+#if HAVE_FEATURE_AVMEDIA
+ try
+ {
+ uno::Reference<io::XInputStream> xStream;
+ if (rValue >>= xStream)
+ {
+ pMedia->SetInputStream(xStream);
+ }
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ css::uno::Any exc = cppu::getCaughtException();
+ throw css::lang::WrappedTargetException(
+ "ContentCreationException Setting InputStream!",
+ static_cast<OWeakObject *>(this),
+ exc);
+ }
+ catch (const css::ucb::CommandFailedException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetException(
+ "CommandFailedException Setting InputStream!",
+ static_cast<OWeakObject *>(this),
+ anyEx);
+ }
+#endif
+ break;
+
+ default:
+ OSL_FAIL("SvxMediaShape::setPropertyValueImpl(), unknown argument!");
+ }
+
+#if HAVE_FEATURE_AVMEDIA
+ if( bOk )
+ {
+ pMedia->setMediaProperties( aItem );
+ return true;
+ }
+#endif
+ }
+ else
+ {
+ return SvxShape::setPropertyValueImpl( rName, pProperty, rValue );
+ }
+
+ throw IllegalArgumentException();
+}
+
+
+bool SvxMediaShape::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ if ( ((pProperty->nWID >= OWN_ATTR_MEDIA_URL) &&
+ (pProperty->nWID <= OWN_ATTR_MEDIA_ZOOM))
+ || (pProperty->nWID == OWN_ATTR_MEDIA_STREAM)
+ || (pProperty->nWID == OWN_ATTR_MEDIA_TEMPFILEURL)
+ || (pProperty->nWID == OWN_ATTR_MEDIA_MIMETYPE)
+ || (pProperty->nWID == OWN_ATTR_FALLBACK_GRAPHIC)
+ || (pProperty->nWID == OWN_ATTR_VALUE_GRAPHIC)
+ || (pProperty->nWID == SDRATTR_GRAFCROP))
+ {
+ SdrMediaObj* pMedia = static_cast< SdrMediaObj* >( GetSdrObject() );
+#if HAVE_FEATURE_AVMEDIA
+ const ::avmedia::MediaItem aItem( pMedia->getMediaProperties() );
+#endif
+
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_MEDIA_URL:
+#if HAVE_FEATURE_AVMEDIA
+ rValue <<= aItem.getURL();
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_LOOP:
+#if HAVE_FEATURE_AVMEDIA
+ rValue <<= aItem.isLoop();
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_MUTE:
+#if HAVE_FEATURE_AVMEDIA
+ rValue <<= aItem.isMute();
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_VOLUMEDB:
+#if HAVE_FEATURE_AVMEDIA
+ rValue <<= aItem.getVolumeDB();
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_ZOOM:
+#if HAVE_FEATURE_AVMEDIA
+ rValue <<= aItem.getZoom();
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_STREAM:
+ try
+ {
+ rValue <<= pMedia->GetInputStream();
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetException(
+ "ContentCreationException Getting InputStream!",
+ static_cast < OWeakObject * > ( this ), anyEx );
+ }
+ catch (const css::ucb::CommandFailedException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetException(
+ "CommandFailedException Getting InputStream!",
+ static_cast < OWeakObject * > ( this ), anyEx );
+ }
+
+ break;
+
+ case OWN_ATTR_MEDIA_TEMPFILEURL:
+#if HAVE_FEATURE_AVMEDIA
+ rValue <<= aItem.getTempURL();
+#endif
+ break;
+
+ case OWN_ATTR_MEDIA_MIMETYPE:
+#if HAVE_FEATURE_AVMEDIA
+ rValue <<= aItem.getMimeType();
+#endif
+ break;
+
+ case OWN_ATTR_VALUE_GRAPHIC:
+#if HAVE_FEATURE_AVMEDIA
+ {
+ Graphic aGraphic = aItem.getGraphic();
+ if (!aGraphic.IsNone())
+ {
+ rValue <<= aGraphic.GetXGraphic();
+ }
+ }
+#endif
+ break;
+
+ case SDRATTR_GRAFCROP:
+#if HAVE_FEATURE_AVMEDIA
+ {
+ text::GraphicCrop aCrop = aItem.getCrop();
+ rValue <<= aCrop;
+ }
+#endif
+ break;
+
+ case OWN_ATTR_FALLBACK_GRAPHIC:
+ rValue <<= pMedia->getSnapshot();
+ break;
+
+ default:
+ OSL_FAIL("SvxMediaShape::getPropertyValueImpl(), unknown property!");
+ }
+ return true;
+ }
+ else
+ {
+ return SvxShape::getPropertyValueImpl( rName, pProperty, rValue );
+ }
+}
+
+bool SvxMediaShape::getPropertyStateImpl(const SfxItemPropertyMapEntry* pProperty,
+ css::beans::PropertyState& rState)
+{
+#if HAVE_FEATURE_AVMEDIA
+ if (pProperty->nWID == SDRATTR_GRAFCROP)
+ {
+ auto pMedia = static_cast<SdrMediaObj*>(GetSdrObject());
+ const avmedia::MediaItem& rItem = pMedia->getMediaProperties();
+ const text::GraphicCrop& rCrop = rItem.getCrop();
+ if (rCrop.Bottom > 0 || rCrop.Left > 0 || rCrop.Right > 0 || rCrop.Top > 0)
+ {
+ // The media has a crop, expose it to UNO-based export filters.
+ rState = beans::PropertyState_DIRECT_VALUE;
+ }
+ else
+ {
+ rState = beans::PropertyState_AMBIGUOUS_VALUE;
+ }
+ return true;
+ }
+#endif
+
+ return SvxShape::getPropertyStateImpl(pProperty, rState);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unoshape.cxx b/svx/source/unodraw/unoshape.cxx
new file mode 100644
index 000000000..a0c81180d
--- /dev/null
+++ b/svx/source/unodraw/unoshape.cxx
@@ -0,0 +1,4042 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/drawing/CircleKind.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <vcl/svapp.hxx>
+#include <svl/itemprop.hxx>
+#include <o3tl/any.hxx>
+#include <osl/mutex.hxx>
+#include <editeng/unotext.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/shapepropertynotifier.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/gfxlink.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/sdangitm.hxx>
+#include <svx/svdlayer.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdobjkind.hxx>
+#include <svx/unopage.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/unoshtxt.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unoshprp.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svdomeas.hxx>
+#include <svx/svdpool.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/stream.hxx>
+#include <tools/gen.hxx>
+#include <tools/UnitConversion.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xtable.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/unomaster.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include "gluepts.hxx"
+#include "shapeimpl.hxx"
+#include <sal/log.hxx>
+
+#include <svx/lathe3d.hxx>
+#include <extrud3d.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <drawinglayer/converters.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+
+#include <vcl/gdimtf.hxx>
+#include <vcl/wmf.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/SvxXTextColumns.hxx>
+#include <svx/xflclit.hxx>
+
+#include <memory>
+#include <optional>
+#include <vector>
+#include <iostream>
+
+#include <bitmaps.hlst>
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using svx::PropertyValueProvider;
+
+class GDIMetaFile;
+
+struct SvxShapeImpl
+{
+ std::optional<SfxItemSet> mxItemSet;
+ SdrObjKind mnObjId;
+ SvxShapeMaster* mpMaster;
+ bool mbHasSdrObjectOwnership;
+ bool mbDisposing;
+
+ /** CL, OD 2005-07-19 #i52126# - this is initially 0 and set when
+ * a SvxShape::Create() call is executed. It is then set to the created
+ * SdrObject so a multiple call to SvxShape::Create() with same SdrObject
+ * is prohibited.
+ */
+ ::tools::WeakReference< SdrObject > mpCreatedObj;
+
+ // for xComponent
+ ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener> maDisposeListeners;
+ svx::PropertyChangeNotifier maPropertyNotifier;
+
+ SvxShapeImpl( SvxShape& _rAntiImpl, ::osl::Mutex& _rMutex )
+ :mnObjId( SdrObjKind::NONE )
+ ,mpMaster( nullptr )
+ ,mbHasSdrObjectOwnership( false )
+ ,mbDisposing( false )
+ ,maDisposeListeners( _rMutex )
+ ,maPropertyNotifier( _rAntiImpl, _rMutex )
+ {
+ }
+};
+
+namespace {
+
+class ShapePositionProvider : public PropertyValueProvider
+{
+public:
+ explicit ShapePositionProvider( SvxShape& _shape )
+ :PropertyValueProvider( _shape, "Position" )
+ {
+ }
+
+protected:
+ virtual void getCurrentValue( Any& _out_rCurrentValue ) const override
+ {
+ _out_rCurrentValue <<= static_cast< SvxShape& >( getContext() ).getPosition();
+ }
+};
+
+
+class ShapeSizeProvider : public PropertyValueProvider
+{
+public:
+ static constexpr OUStringLiteral sSize = u"Size";
+ explicit ShapeSizeProvider( SvxShape& _shape )
+ :PropertyValueProvider( _shape, sSize )
+ {
+ }
+
+protected:
+ virtual void getCurrentValue( Any& _out_rCurrentValue ) const override
+ {
+ _out_rCurrentValue <<= static_cast< SvxShape& >( getContext() ).getSize();
+ }
+};
+
+/// Calculates what scaling factor will be used for autofit text scaling of this shape.
+sal_Int16 GetTextFitToSizeScale(SdrObject* pObject)
+{
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(pObject);
+ if (!pTextObj)
+ {
+ return 0;
+ }
+
+ const SfxItemSet& rTextObjSet = pTextObj->GetMergedItemSet();
+ if (rTextObjSet.GetItem<SdrTextFitToSizeTypeItem>(SDRATTR_TEXT_FITTOSIZE)->GetValue()
+ != drawing::TextFitToSizeType_AUTOFIT)
+ {
+ return 0;
+ }
+
+ return pTextObj->GetFontScaleY();
+}
+}
+
+SvxShape::SvxShape( SdrObject* pObject )
+: maSize(100,100)
+, mpImpl( new SvxShapeImpl( *this, m_aMutex ) )
+, mbIsMultiPropertyCall(false)
+, mpPropSet(getSvxMapProvider().GetPropertySet(SVXMAP_SHAPE, SdrObject::GetGlobalDrawObjectItemPool()))
+, maPropMapEntries(getSvxMapProvider().GetMap(SVXMAP_SHAPE))
+, mpSdrObjectWeakReference(pObject)
+, mnLockCount(0)
+{
+ impl_construct();
+}
+
+
+SvxShape::SvxShape( SdrObject* pObject, const SfxItemPropertyMapEntry* pEntries, const SvxItemPropertySet* pPropertySet )
+: maSize(100,100)
+, mpImpl( new SvxShapeImpl( *this, m_aMutex ) )
+, mbIsMultiPropertyCall(false)
+, mpPropSet(pPropertySet)
+, maPropMapEntries(pEntries)
+, mpSdrObjectWeakReference(pObject)
+, mnLockCount(0)
+{
+ impl_construct();
+}
+
+
+SvxShape::~SvxShape() noexcept
+{
+ ::SolarMutexGuard aGuard;
+
+ DBG_ASSERT( mnLockCount == 0, "Locked shape was disposed!" );
+
+ if ( mpImpl->mpMaster )
+ mpImpl->mpMaster->dispose();
+
+ if ( HasSdrObject() )
+ {
+ EndListening(GetSdrObject()->getSdrModelFromSdrObject());
+ GetSdrObject()->setUnoShape(nullptr);
+ }
+
+ if( HasSdrObjectOwnership() && HasSdrObject() )
+ {
+ mpImpl->mbHasSdrObjectOwnership = false;
+ SdrObject* pObject = GetSdrObject();
+ SdrObject::Free( pObject );
+ }
+
+ EndListeningAll(); // call explicitly within SolarMutexGuard
+}
+
+
+void SvxShape::TakeSdrObjectOwnership()
+{
+ mpImpl->mbHasSdrObjectOwnership = true;
+}
+
+
+void SvxShape::InvalidateSdrObject()
+{
+ if(HasSdrObject())
+ {
+ EndListening(GetSdrObject()->getSdrModelFromSdrObject());
+ }
+
+ if (HasSdrObjectOwnership())
+ return;
+
+ mpSdrObjectWeakReference.reset(nullptr);
+};
+
+bool SvxShape::HasSdrObjectOwnership() const
+{
+ if ( !mpImpl->mbHasSdrObjectOwnership )
+ return false;
+
+ OSL_ENSURE( HasSdrObject(), "SvxShape::HasSdrObjectOwnership: have the ownership of an object which I don't know!" );
+ return HasSdrObject();
+}
+
+
+void SvxShape::setShapeKind( SdrObjKind nKind )
+{
+ mpImpl->mnObjId = nKind;
+}
+
+
+SdrObjKind SvxShape::getShapeKind() const
+{
+ return mpImpl->mnObjId;
+}
+
+
+void SvxShape::setMaster( SvxShapeMaster* pMaster )
+{
+ mpImpl->mpMaster = pMaster;
+}
+
+
+uno::Any SAL_CALL SvxShape::queryAggregation( const uno::Type& rType )
+{
+ if( mpImpl->mpMaster )
+ {
+ uno::Any aAny;
+ if( mpImpl->mpMaster->queryAggregation( rType, aAny ) )
+ return aAny;
+ }
+
+ return SvxShape_UnoImplHelper::queryAggregation(rType);
+}
+
+const css::uno::Sequence< sal_Int8 > & SvxShape::getUnoTunnelId() noexcept
+{
+ static const comphelper::UnoIdInit theSvxShapeUnoTunnelId;
+ return theSvxShapeUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL SvxShape::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+
+svx::PropertyChangeNotifier& SvxShape::getShapePropertyChangeNotifier()
+{
+ return mpImpl->maPropertyNotifier;
+}
+
+
+void SvxShape::impl_construct()
+{
+ mpImpl->maPropertyNotifier.registerProvider( svx::ShapePropertyProviderId::Position,
+ std::make_unique<ShapePositionProvider>( *this ) );
+ mpImpl->maPropertyNotifier.registerProvider( svx::ShapePropertyProviderId::Size,
+ std::make_unique<ShapeSizeProvider>( *this ) );
+
+ if ( HasSdrObject() )
+ {
+ StartListening(GetSdrObject()->getSdrModelFromSdrObject());
+ impl_initFromSdrObject();
+ }
+}
+
+
+void SvxShape::impl_initFromSdrObject()
+{
+ DBG_TESTSOLARMUTEX();
+ OSL_PRECOND( HasSdrObject(), "SvxShape::impl_initFromSdrObject: not to be called without SdrObject!" );
+ if ( !HasSdrObject() )
+ return;
+
+ osl_atomic_increment( &m_refCount );
+ {
+ GetSdrObject()->setUnoShape(this);
+ }
+ osl_atomic_decrement( &m_refCount );
+
+ // #i40944#
+ // Do not simply return when no model but do the type corrections
+ // following below.
+ const SdrInventor nInventor = GetSdrObject()->GetObjInventor();
+
+ // is it one of ours (svx) ?
+ if( !(nInventor == SdrInventor::Default || nInventor == SdrInventor::E3d || nInventor == SdrInventor::FmForm) )
+ return;
+
+ if(nInventor == SdrInventor::FmForm)
+ {
+ mpImpl->mnObjId = SdrObjKind::UNO;
+ }
+ else
+ {
+ mpImpl->mnObjId = GetSdrObject()->GetObjIdentifier();
+ }
+
+ switch(mpImpl->mnObjId)
+ {
+ case SdrObjKind::CircleCut: // segment of circle
+ case SdrObjKind::CircleArc: // arc of circle
+ case SdrObjKind::CircleSection: // sector
+ mpImpl->mnObjId = SdrObjKind::CircleOrEllipse;
+ break;
+ default: ;
+ }
+}
+
+
+void SvxShape::Create( SdrObject* pNewObj, SvxDrawPage* /*pNewPage*/ )
+{
+ DBG_TESTSOLARMUTEX();
+
+ assert( pNewObj && "SvxShape::Create: invalid new object!" );
+ if ( !pNewObj )
+ return;
+
+ SdrObject* pCreatedObj = mpImpl->mpCreatedObj.get();
+ assert( ( !pCreatedObj || ( pCreatedObj == pNewObj ) ) &&
+ "SvxShape::Create: the same shape used for two different objects?! Strange ..." );
+
+ // Correct condition (#i52126#)
+ if ( pCreatedObj == pNewObj )
+ return;
+
+ // Correct condition (#i52126#)
+ mpImpl->mpCreatedObj = pNewObj;
+
+ if( HasSdrObject() )
+ {
+ EndListening( GetSdrObject()->getSdrModelFromSdrObject() );
+ }
+
+ mpSdrObjectWeakReference.reset( pNewObj );
+
+ if( HasSdrObject() )
+ {
+ StartListening( GetSdrObject()->getSdrModelFromSdrObject() );
+ }
+
+ OSL_ENSURE( !mbIsMultiPropertyCall, "SvxShape::Create: hmm?" );
+ // this was previously set in impl_initFromSdrObject, but I think it was superfluous
+ // (it definitely was in the other context where it was called, but I strongly suppose
+ // it was also superfluous when called from here)
+ impl_initFromSdrObject();
+
+ ObtainSettingsFromPropertySet( *mpPropSet );
+
+ // save user call
+ SdrObjUserCall* pUser = GetSdrObject()->GetUserCall();
+ GetSdrObject()->SetUserCall(nullptr);
+
+ setPosition( maPosition );
+ setSize( maSize );
+
+ // restore user call after we set the initial size
+ GetSdrObject()->SetUserCall( pUser );
+
+ // if this shape was already named, use this name
+ if( !maShapeName.isEmpty() )
+ {
+ GetSdrObject()->SetName( maShapeName );
+ maShapeName.clear();
+ }
+}
+
+void SvxShape::ForceMetricToItemPoolMetric(Pair& rPoint) const noexcept
+{
+ DBG_TESTSOLARMUTEX();
+ if(!HasSdrObject())
+ return;
+
+ MapUnit eMapUnit(GetSdrObject()->getSdrModelFromSdrObject().GetItemPool().GetMetric(0));
+ if(eMapUnit == MapUnit::Map100thMM)
+ return;
+
+ if (const auto eTo = MapToO3tlLength(eMapUnit); eTo != o3tl::Length::invalid)
+ {
+ rPoint.A() = o3tl::convert(rPoint.A(), o3tl::Length::mm100, eTo);
+ rPoint.B() = o3tl::convert(rPoint.B(), o3tl::Length::mm100, eTo);
+ }
+ else
+ {
+ OSL_FAIL("AW: Missing unit translation to PoolMetric!");
+ }
+}
+
+void SvxShape::ForceMetricToItemPoolMetric(basegfx::B2DPolyPolygon& rPolyPolygon) const noexcept
+{
+ DBG_TESTSOLARMUTEX();
+ if(!HasSdrObject())
+ return;
+
+ GetSdrObject()->ForceMetricToItemPoolMetric(rPolyPolygon);
+}
+
+void SvxShape::ForceMetricToItemPoolMetric(basegfx::B2DHomMatrix& rB2DHomMatrix) const noexcept
+{
+ DBG_TESTSOLARMUTEX();
+ if(!HasSdrObject())
+ return;
+
+ MapUnit eMapUnit(GetSdrObject()->getSdrModelFromSdrObject().GetItemPool().GetMetric(0));
+ if(eMapUnit == MapUnit::Map100thMM)
+ return;
+
+ if (const auto eTo = MapToO3tlLength(eMapUnit); eTo != o3tl::Length::invalid)
+ {
+ const double fConvert(o3tl::convert(1.0, o3tl::Length::mm100, eTo));
+ const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomposedTransform(rB2DHomMatrix);
+ rB2DHomMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aDecomposedTransform.getScale() * fConvert,
+ aDecomposedTransform.getShearX(),
+ aDecomposedTransform.getRotate(),
+ aDecomposedTransform.getTranslate() * fConvert);
+ }
+ else
+ {
+ OSL_FAIL("Missing unit translation to PoolMetric!");
+ }
+}
+
+void SvxShape::ForceMetricTo100th_mm(Pair& rPoint) const noexcept
+{
+ DBG_TESTSOLARMUTEX();
+ if(!HasSdrObject())
+ return;
+
+ MapUnit eMapUnit = GetSdrObject()->getSdrModelFromSdrObject().GetItemPool().GetMetric(0);
+ if(eMapUnit == MapUnit::Map100thMM)
+ return;
+
+ if (const auto eFrom = MapToO3tlLength(eMapUnit); eFrom != o3tl::Length::invalid)
+ {
+ rPoint.A() = o3tl::convert(rPoint.A(), eFrom, o3tl::Length::mm100);
+ rPoint.B() = o3tl::convert(rPoint.B(), eFrom, o3tl::Length::mm100);
+ }
+ else
+ {
+ OSL_FAIL("AW: Missing unit translation to 100th mm!");
+ }
+}
+
+void SvxShape::ForceMetricTo100th_mm(basegfx::B2DPolyPolygon& rPolyPolygon) const noexcept
+{
+ DBG_TESTSOLARMUTEX();
+ if(!HasSdrObject())
+ return;
+
+ MapUnit eMapUnit = GetSdrObject()->getSdrModelFromSdrObject().GetItemPool().GetMetric(0);
+ if(eMapUnit == MapUnit::Map100thMM)
+ return;
+
+ if (const auto eFrom = MapToO3tlLength(eMapUnit); eFrom != o3tl::Length::invalid)
+ {
+ const double fConvert(o3tl::convert(1.0, eFrom, o3tl::Length::mm100));
+ rPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(fConvert, fConvert));
+ }
+ else
+ {
+ OSL_FAIL("Missing unit translation to 100th mm!");
+ }
+}
+
+void SvxShape::ForceMetricTo100th_mm(basegfx::B2DHomMatrix& rB2DHomMatrix) const noexcept
+{
+ DBG_TESTSOLARMUTEX();
+ if(!HasSdrObject())
+ return;
+
+ MapUnit eMapUnit = GetSdrObject()->getSdrModelFromSdrObject().GetItemPool().GetMetric(0);
+ if(eMapUnit == MapUnit::Map100thMM)
+ return;
+
+ if (const auto eFrom = MapToO3tlLength(eMapUnit); eFrom != o3tl::Length::invalid)
+ {
+ const double fConvert(o3tl::convert(1.0, eFrom, o3tl::Length::mm100));
+ const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomposedTransform(rB2DHomMatrix);
+ rB2DHomMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aDecomposedTransform.getScale() * fConvert,
+ aDecomposedTransform.getShearX(),
+ aDecomposedTransform.getRotate(),
+ aDecomposedTransform.getTranslate() * fConvert);
+ }
+ else
+ {
+ OSL_FAIL("Missing unit translation to 100th mm!");
+ }
+}
+
+static void SvxItemPropertySet_ObtainSettingsFromPropertySet(const SvxItemPropertySet& rPropSet, SvxItemPropertySetUsrAnys& rAnys,
+ SfxItemSet& rSet, const uno::Reference< beans::XPropertySet >& xSet, const SfxItemPropertyMap* pMap )
+{
+ if(!rAnys.AreThereOwnUsrAnys())
+ return;
+
+ const SfxItemPropertyMap& rSrc = rPropSet.getPropertyMap();
+
+ for(const SfxItemPropertyMapEntry* pSrcProp : rSrc.getPropertyEntries())
+ {
+ const sal_uInt16 nWID = pSrcProp->nWID;
+ if(SfxItemPool::IsWhich(nWID)
+ && (nWID < OWN_ATTR_VALUE_START || nWID > OWN_ATTR_VALUE_END)
+ && rAnys.GetUsrAnyForID(*pSrcProp))
+ rSet.Put(rSet.GetPool()->GetDefaultItem(nWID));
+ }
+
+ for(const SfxItemPropertyMapEntry* pSrcProp : rSrc.getPropertyEntries())
+ {
+ if(pSrcProp->nWID)
+ {
+ uno::Any* pUsrAny = rAnys.GetUsrAnyForID(*pSrcProp);
+ if(pUsrAny)
+ {
+ // search for equivalent entry in pDst
+ const SfxItemPropertyMapEntry* pEntry = pMap->getByName( pSrcProp->aName );
+ if(pEntry)
+ {
+ // entry found
+ if(pEntry->nWID >= OWN_ATTR_VALUE_START && pEntry->nWID <= OWN_ATTR_VALUE_END)
+ {
+ // special ID in PropertySet, can only be set
+ // directly at the object
+ xSet->setPropertyValue( pSrcProp->aName, *pUsrAny);
+ }
+ else
+ {
+ SvxItemPropertySet_setPropertyValue(pEntry, *pUsrAny, rSet);
+ }
+ }
+ }
+ }
+ }
+ rAnys.ClearAllUsrAny();
+}
+
+
+void SvxShape::ObtainSettingsFromPropertySet(const SvxItemPropertySet& rPropSet)
+{
+ DBG_TESTSOLARMUTEX();
+ if(HasSdrObject() && maUrsAnys.AreThereOwnUsrAnys())
+ {
+ SfxItemSetFixed<SDRATTR_START, SDRATTR_END> aSet( GetSdrObject()->getSdrModelFromSdrObject().GetItemPool() );
+ Reference< beans::XPropertySet > xShape(this);
+ SvxItemPropertySet_ObtainSettingsFromPropertySet(rPropSet, maUrsAnys, aSet, xShape, &mpPropSet->getPropertyMap() );
+
+ GetSdrObject()->SetMergedItemSetAndBroadcast(aSet);
+
+ GetSdrObject()->ApplyNotPersistAttr( aSet );
+ }
+}
+
+uno::Any SvxShape::GetBitmap( bool bMetaFile /* = false */ ) const
+{
+ DBG_TESTSOLARMUTEX();
+ uno::Any aAny;
+
+ if(!HasSdrObject() || nullptr == GetSdrObject()->getSdrPageFromSdrObject())
+ {
+ return aAny;
+ }
+
+ // tdf#118662 Emulate old behaviour of XclObjComment (see there)
+ const SdrCaptionObj* pSdrCaptionObj(dynamic_cast<SdrCaptionObj*>(GetSdrObject()));
+ if(nullptr != pSdrCaptionObj && pSdrCaptionObj->isSuppressGetBitmap())
+ {
+ return aAny;
+ }
+
+ // tdf#119180 If we do not ask for Metafile and we access a SdrGrafObj,
+ // and content exists and is a Bitmap, take the shortcut.
+ // Do *not* do this for Metafile - as can be seen, requested in that case
+ // is a byte-sequence of a saved WMF format file (see below)
+ if(!bMetaFile)
+ {
+ const SdrGrafObj* pSdrGrafObj(dynamic_cast<SdrGrafObj*>(GetSdrObject()));
+
+ if(nullptr != pSdrGrafObj)
+ {
+ const Graphic& rGraphic(pSdrGrafObj->GetGraphic());
+
+ if(GraphicType::Bitmap == rGraphic.GetType())
+ {
+ Reference< awt::XBitmap > xBmp( rGraphic.GetXGraphic(), UNO_QUERY );
+ aAny <<= xBmp;
+
+ return aAny;
+ }
+ }
+ }
+
+ // tdf#118662 instead of creating an E3dView instance every time to paint
+ // a single SdrObject, use the existing SdrObject::SingleObjectPainter to
+ // use less resources and runtime
+ if(bMetaFile)
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ const tools::Rectangle aBoundRect(GetSdrObject()->GetCurrentBoundRect());
+ GDIMetaFile aMtf;
+
+ pVDev->SetMapMode(MapMode(MapUnit::Map100thMM));
+ pVDev->EnableOutput(false);
+ aMtf.Record(pVDev);
+ GetSdrObject()->SingleObjectPainter(*pVDev);
+ aMtf.Stop();
+ aMtf.WindStart();
+ aMtf.Move(-aBoundRect.Left(), -aBoundRect.Top());
+ aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
+ aMtf.SetPrefSize(aBoundRect.GetSize());
+
+ SvMemoryStream aDestStrm(65535, 65535);
+
+ ConvertGDIMetaFileToWMF(
+ aMtf,
+ aDestStrm,
+ nullptr,
+ false);
+
+ const uno::Sequence<sal_Int8> aSeq(
+ static_cast< const sal_Int8* >(aDestStrm.GetData()),
+ aDestStrm.GetEndOfData());
+
+ aAny <<= aSeq;
+ }
+ else
+ {
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitives;
+ GetSdrObject()->GetViewContact().getViewIndependentPrimitive2DContainer(xPrimitives);
+
+ if(!xPrimitives.empty())
+ {
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ basegfx::B2DRange aRange(
+ xPrimitives.getB2DRange(aViewInformation2D));
+
+ if(!aRange.isEmpty())
+ {
+ const MapUnit aSourceMapUnit(GetSdrObject()->getSdrModelFromSdrObject().GetScaleUnit());
+
+ if(MapUnit::Map100thMM != aSourceMapUnit)
+ {
+ // tdf#119180 This is UNO API and thus works in 100th_mm,
+ // so if the MapMode from the used SdrModel is *not* equal
+ // to Map100thMM we need to embed the primitives to an adapting
+ // homogen transformation for correct values
+ const basegfx::B2DHomMatrix aMapTransform(
+ OutputDevice::LogicToLogic(
+ MapMode(aSourceMapUnit),
+ MapMode(MapUnit::Map100thMM)));
+
+ // Embed primitives to get them in 100th mm
+ drawinglayer::primitive2d::Primitive2DReference xEmbedRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aMapTransform,
+ std::move(xPrimitives)));
+
+ xPrimitives = drawinglayer::primitive2d::Primitive2DContainer { xEmbedRef };
+
+ // Update basegfx::B2DRange aRange, too. Here we have the
+ // choice of transforming the existing value or get newly by
+ // again using 'xPrimitives.getB2DRange(aViewInformation2D)'
+ aRange.transform(aMapTransform);
+ }
+
+ const BitmapEx aBmp(
+ drawinglayer::convertPrimitive2DContainerToBitmapEx(
+ std::move(xPrimitives),
+ aRange));
+
+ Graphic aGraph(aBmp);
+
+ aGraph.SetPrefSize(aBmp.GetPrefSize());
+ aGraph.SetPrefMapMode(aBmp.GetPrefMapMode());
+
+ Reference< awt::XBitmap > xBmp( aGraph.GetXGraphic(), UNO_QUERY );
+ aAny <<= xBmp;
+ }
+ }
+ }
+
+ return aAny;
+}
+
+uno::Sequence< uno::Type > SAL_CALL SvxShape::getTypes()
+{
+ if( mpImpl->mpMaster )
+ {
+ return mpImpl->mpMaster->getTypes();
+ }
+ else
+ {
+ return _getTypes();
+ }
+}
+
+
+uno::Sequence< uno::Type > const & SvxShape::_getTypes()
+{
+ switch( mpImpl->mnObjId )
+ {
+ // shapes without text
+ case SdrObjKind::Page:
+ case SdrObjKind::OLEPluginFrame:
+ case SdrObjKind::OLE2Plugin:
+ case SdrObjKind::OLE2Applet:
+ case SdrObjKind::E3D_Cube:
+ case SdrObjKind::E3D_Sphere:
+ case SdrObjKind::E3D_Lathe:
+ case SdrObjKind::E3D_Extrusion:
+ case SdrObjKind::E3D_Polygon:
+ case SdrObjKind::Media:
+ case SdrObjKind::Table:
+ {
+ static uno::Sequence<uno::Type> aTypeSequence{
+ cppu::UnoType<drawing::XShape>::get(),
+ cppu::UnoType<lang::XComponent>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<beans::XMultiPropertySet>::get(),
+ cppu::UnoType<beans::XPropertyState>::get(),
+ cppu::UnoType<beans::XMultiPropertyStates>::get(),
+ cppu::UnoType<drawing::XGluePointsSupplier>::get(),
+ cppu::UnoType<container::XChild>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<container::XNamed>::get(),
+ };
+
+ return aTypeSequence;
+ }
+ // group shape
+ case SdrObjKind::Group:
+ {
+ static uno::Sequence<uno::Type> aTypeSequence{
+ cppu::UnoType<drawing::XShape>::get(),
+ cppu::UnoType<lang::XComponent>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<beans::XMultiPropertySet>::get(),
+ cppu::UnoType<beans::XPropertyState>::get(),
+ cppu::UnoType<beans::XMultiPropertyStates>::get(),
+ cppu::UnoType<drawing::XGluePointsSupplier>::get(),
+ cppu::UnoType<container::XChild>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<container::XNamed>::get(),
+ cppu::UnoType<drawing::XShapes>::get(),
+ cppu::UnoType<drawing::XShapeGroup>::get(),
+ };
+
+ return aTypeSequence;
+ }
+ // connector shape
+ case SdrObjKind::Edge:
+ {
+ static uno::Sequence<uno::Type> aTypeSequence{
+ cppu::UnoType<drawing::XShape>::get(),
+ cppu::UnoType<lang::XComponent>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<beans::XMultiPropertySet>::get(),
+ cppu::UnoType<beans::XPropertyState>::get(),
+ cppu::UnoType<beans::XMultiPropertyStates>::get(),
+ cppu::UnoType<drawing::XGluePointsSupplier>::get(),
+ cppu::UnoType<container::XChild>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<container::XNamed>::get(),
+ cppu::UnoType<drawing::XConnectorShape>::get(),
+ // from SvxUnoTextBase::getTypes()
+ cppu::UnoType<text::XTextAppend>::get(),
+ cppu::UnoType<text::XTextCopy>::get(),
+ cppu::UnoType<container::XEnumerationAccess>::get(),
+ cppu::UnoType<text::XTextRangeMover>::get(),
+ };
+
+ return aTypeSequence;
+ }
+ // control shape
+ case SdrObjKind::UNO:
+ {
+ static uno::Sequence<uno::Type> aTypeSequence{
+ cppu::UnoType<drawing::XShape>::get(),
+ cppu::UnoType<lang::XComponent>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<beans::XMultiPropertySet>::get(),
+ cppu::UnoType<beans::XPropertyState>::get(),
+ cppu::UnoType<beans::XMultiPropertyStates>::get(),
+ cppu::UnoType<drawing::XGluePointsSupplier>::get(),
+ cppu::UnoType<container::XChild>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<container::XNamed>::get(),
+ cppu::UnoType<drawing::XControlShape>::get(),
+ };
+
+ return aTypeSequence;
+ }
+ // 3d scene shape
+ case SdrObjKind::E3D_Scene:
+ {
+ static uno::Sequence<uno::Type> aTypeSequence{
+ cppu::UnoType<drawing::XShape>::get(),
+ cppu::UnoType<lang::XComponent>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<beans::XMultiPropertySet>::get(),
+ cppu::UnoType<beans::XPropertyState>::get(),
+ cppu::UnoType<beans::XMultiPropertyStates>::get(),
+ cppu::UnoType<drawing::XGluePointsSupplier>::get(),
+ cppu::UnoType<container::XChild>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<container::XNamed>::get(),
+ cppu::UnoType<drawing::XShapes>::get(),
+ };
+
+ return aTypeSequence;
+ }
+ case SdrObjKind::CustomShape:
+ {
+ static uno::Sequence<uno::Type> aTypeSequence{
+ cppu::UnoType<drawing::XShape>::get(),
+ cppu::UnoType<lang::XComponent>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<beans::XMultiPropertySet>::get(),
+ cppu::UnoType<beans::XPropertyState>::get(),
+ cppu::UnoType<beans::XMultiPropertyStates>::get(),
+ cppu::UnoType<drawing::XGluePointsSupplier>::get(),
+ cppu::UnoType<container::XChild>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<container::XNamed>::get(),
+ // from SvxUnoTextBase::getTypes()
+ cppu::UnoType<text::XText>::get(),
+ cppu::UnoType<container::XEnumerationAccess>::get(),
+ cppu::UnoType<text::XTextRangeMover>::get(),
+ cppu::UnoType<drawing::XEnhancedCustomShapeDefaulter>::get(),
+ };
+
+ return aTypeSequence;
+ }
+ // shapes with text
+ case SdrObjKind::Rectangle:
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::Measure:
+ case SdrObjKind::Line:
+ case SdrObjKind::Polygon:
+ case SdrObjKind::PolyLine:
+ case SdrObjKind::PathLine:
+ case SdrObjKind::PathFill:
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathPoly:
+ case SdrObjKind::PathPolyLine:
+ case SdrObjKind::Graphic:
+ case SdrObjKind::Text:
+ case SdrObjKind::Caption:
+ case SdrObjKind::OLE2: // #i118485# Moved to shapes with text
+ default:
+ {
+ static uno::Sequence<uno::Type> aTypeSequence{
+ cppu::UnoType<drawing::XShape>::get(),
+ cppu::UnoType<lang::XComponent>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<beans::XMultiPropertySet>::get(),
+ cppu::UnoType<beans::XPropertyState>::get(),
+ cppu::UnoType<beans::XMultiPropertyStates>::get(),
+ cppu::UnoType<drawing::XGluePointsSupplier>::get(),
+ cppu::UnoType<container::XChild>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<container::XNamed>::get(),
+ // from SvxUnoTextBase::getTypes()
+ cppu::UnoType<text::XTextAppend>::get(),
+ cppu::UnoType<text::XTextCopy>::get(),
+ cppu::UnoType<container::XEnumerationAccess>::get(),
+ cppu::UnoType<text::XTextRangeMover>::get(),
+ };
+
+ return aTypeSequence;
+ }
+ }
+}
+
+
+uno::Sequence< sal_Int8 > SAL_CALL SvxShape::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void SvxShape::Notify( SfxBroadcaster&, const SfxHint& rHint ) noexcept
+{
+ DBG_TESTSOLARMUTEX();
+
+ // do cheap checks first, this method is hot
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ SdrObject* pSdrObject(mpSdrObjectWeakReference.get());
+ if( !pSdrObject )
+ return;
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ // #i55919# SdrHintKind::ObjectChange is only interesting if it's for this object
+ if ((pSdrHint->GetKind() != SdrHintKind::ModelCleared) &&
+ (pSdrHint->GetKind() != SdrHintKind::ObjectChange || pSdrHint->GetObject() != pSdrObject ))
+ return;
+
+ uno::Reference< uno::XInterface > xSelf( pSdrObject->getWeakUnoShape() );
+ if( !xSelf.is() )
+ {
+ EndListening(pSdrObject->getSdrModelFromSdrObject());
+ mpSdrObjectWeakReference.reset(nullptr);
+ return;
+ }
+
+ bool bClearMe = false;
+
+ switch( pSdrHint->GetKind() )
+ {
+ case SdrHintKind::ObjectChange:
+ {
+ updateShapeKind();
+ break;
+ }
+ case SdrHintKind::ModelCleared:
+ {
+ bClearMe = true;
+ break;
+ }
+ default:
+ break;
+ };
+
+ if( !bClearMe )
+ return;
+
+ if(!HasSdrObjectOwnership())
+ {
+ if(nullptr != pSdrObject)
+ {
+ EndListening(pSdrObject->getSdrModelFromSdrObject());
+ pSdrObject->setUnoShape(nullptr);
+ }
+
+ mpSdrObjectWeakReference.reset(nullptr);
+
+ // SdrModel *is* going down, try to Free SdrObject even
+ // when !HasSdrObjectOwnership
+ if(nullptr != pSdrObject && !pSdrObject->IsInserted())
+ {
+ SdrObject::Free(pSdrObject);
+ }
+ }
+
+ if(!mpImpl->mbDisposing)
+ {
+ dispose();
+ }
+}
+
+// XShape
+
+
+// The "*LogicRectHack" functions also existed in sch, and those
+// duplicate symbols cause Bad Things To Happen (TM) #i9462#.
+// Prefixing with 'svx' and marking static to make sure name collisions
+// do not occur.
+
+static bool svx_needLogicRectHack( SdrObject const * pObj )
+{
+ if( pObj->GetObjInventor() == SdrInventor::Default)
+ {
+ switch(pObj->GetObjIdentifier())
+ {
+ case SdrObjKind::Group:
+ case SdrObjKind::Line:
+ case SdrObjKind::Polygon:
+ case SdrObjKind::PolyLine:
+ case SdrObjKind::PathLine:
+ case SdrObjKind::PathFill:
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::SplineLine:
+ case SdrObjKind::SplineFill:
+ case SdrObjKind::Edge:
+ case SdrObjKind::PathPoly:
+ case SdrObjKind::PathPolyLine:
+ case SdrObjKind::Measure:
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+
+static tools::Rectangle svx_getLogicRectHack( SdrObject const * pObj )
+{
+ if(svx_needLogicRectHack(pObj))
+ {
+ return pObj->GetSnapRect();
+ }
+ else
+ {
+ return pObj->GetLogicRect();
+ }
+}
+
+
+static void svx_setLogicRectHack( SdrObject* pObj, const tools::Rectangle& rRect )
+{
+ if(svx_needLogicRectHack(pObj))
+ {
+ pObj->SetSnapRect( rRect );
+ }
+ else
+ {
+ pObj->SetLogicRect( rRect );
+ }
+}
+
+
+awt::Point SAL_CALL SvxShape::getPosition()
+{
+ ::SolarMutexGuard aGuard;
+
+ if(HasSdrObject())
+ {
+ tools::Rectangle aRect( svx_getLogicRectHack(GetSdrObject()) );
+ Point aPt( aRect.Left(), aRect.Top() );
+
+ // Position is relative to anchor, so recalc to absolute position
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ aPt -= GetSdrObject()->GetAnchorPos();
+
+ ForceMetricTo100th_mm(aPt);
+ return css::awt::Point( aPt.X(), aPt.Y() );
+ }
+ else
+ {
+ return maPosition;
+ }
+}
+
+
+void SAL_CALL SvxShape::setPosition( const awt::Point& Position )
+{
+ ::SolarMutexGuard aGuard;
+
+ if(HasSdrObject())
+ {
+ // do NOT move 3D objects, this would change the homogen
+ // transformation matrix
+ if(dynamic_cast<const E3dCompoundObject* >(GetSdrObject()) == nullptr)
+ {
+ tools::Rectangle aRect( svx_getLogicRectHack(GetSdrObject()) );
+ Point aLocalPos( Position.X, Position.Y );
+ ForceMetricToItemPoolMetric(aLocalPos);
+
+ // Position is absolute, so recalc to position relative to anchor
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ aLocalPos += GetSdrObject()->GetAnchorPos();
+
+ tools::Long nDX = aLocalPos.X() - aRect.Left();
+ tools::Long nDY = aLocalPos.Y() - aRect.Top();
+
+ GetSdrObject()->Move( Size( nDX, nDY ) );
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+ }
+ }
+
+ maPosition = Position;
+}
+
+
+awt::Size SAL_CALL SvxShape::getSize()
+{
+ ::SolarMutexGuard aGuard;
+
+ if(HasSdrObject())
+ {
+ tools::Rectangle aRect( svx_getLogicRectHack(GetSdrObject()) );
+ Size aObjSize( aRect.getWidth(), aRect.getHeight() );
+ ForceMetricTo100th_mm(aObjSize);
+ return css::awt::Size( aObjSize.getWidth(), aObjSize.getHeight() );
+ }
+ else
+ return maSize;
+}
+
+
+void SAL_CALL SvxShape::setSize( const awt::Size& rSize )
+{
+ ::SolarMutexGuard aGuard;
+
+ if(HasSdrObject())
+ {
+ tools::Rectangle aRect( svx_getLogicRectHack(GetSdrObject()) );
+ Size aLocalSize( rSize.Width, rSize.Height );
+ ForceMetricToItemPoolMetric(aLocalSize);
+
+ if(GetSdrObject()->GetObjInventor() == SdrInventor::Default && GetSdrObject()->GetObjIdentifier() == SdrObjKind::Measure )
+ {
+ Fraction aWdt(aLocalSize.Width(),aRect.Right()-aRect.Left());
+ Fraction aHgt(aLocalSize.Height(),aRect.Bottom()-aRect.Top());
+ Point aPt = GetSdrObject()->GetSnapRect().TopLeft();
+ GetSdrObject()->Resize(aPt,aWdt,aHgt);
+ }
+ else
+ {
+ //aRect.SetSize(aLocalSize); // this call subtract 1 // https://bz.apache.org/ooo/show_bug.cgi?id=83193
+ if ( !aLocalSize.Width() )
+ {
+ aRect.SetWidthEmpty();
+ }
+ else
+ aRect.setWidth(aLocalSize.Width());
+ if ( !aLocalSize.Height() )
+ {
+ aRect.SetHeightEmpty();
+ }
+ else
+ aRect.setHeight(aLocalSize.Height());
+
+ svx_setLogicRectHack( GetSdrObject(), aRect );
+ }
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+ }
+ maSize = rSize;
+}
+
+
+// XNamed
+OUString SAL_CALL SvxShape::getName( )
+{
+ ::SolarMutexGuard aGuard;
+ if( HasSdrObject() )
+ {
+ return GetSdrObject()->GetName();
+ }
+ else
+ {
+ return maShapeName;
+ }
+}
+
+
+void SAL_CALL SvxShape::setName( const OUString& aName )
+{
+ ::SolarMutexGuard aGuard;
+ if( HasSdrObject() )
+ {
+ GetSdrObject()->SetName( aName );
+ }
+ else
+ {
+ maShapeName = aName;
+ }
+}
+
+// XShapeDescriptor
+
+
+OUString SAL_CALL SvxShape::getShapeType()
+{
+ if( !maShapeType.getLength() )
+ return UHashMap::getNameFromId( mpImpl->mnObjId );
+ else
+ return maShapeType;
+}
+
+// XComponent
+
+
+void SAL_CALL SvxShape::dispose()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( mpImpl->mbDisposing )
+ return; // caught a recursion
+
+ mpImpl->mbDisposing = true;
+
+ lang::EventObject aEvt;
+ aEvt.Source = *static_cast<OWeakAggObject*>(this);
+ mpImpl->maDisposeListeners.disposeAndClear(aEvt);
+ mpImpl->maPropertyNotifier.disposing();
+
+ if ( !HasSdrObject() )
+ return;
+
+ SdrObject* pObject = GetSdrObject();
+
+ EndListening( pObject->getSdrModelFromSdrObject() );
+ bool bFreeSdrObject = false;
+
+ if ( pObject->IsInserted() && pObject->getSdrPageFromSdrObject() )
+ {
+ SdrPage* pPage = pObject->getSdrPageFromSdrObject();
+ // delete the SdrObject from the page
+ const size_t nCount = pPage->GetObjCount();
+ for ( size_t nNum = 0; nNum < nCount; ++nNum )
+ {
+ if ( pPage->GetObj( nNum ) == pObject )
+ {
+ OSL_VERIFY( pPage->RemoveObject( nNum ) == pObject );
+ if (HasSdrObjectOwnership())
+ {
+ bFreeSdrObject = true;
+ }
+ break;
+ }
+ }
+ }
+
+ pObject->setUnoShape(nullptr);
+
+ if ( bFreeSdrObject )
+ {
+ // in case we have the ownership of the SdrObject, a Free
+ // would do nothing. So ensure the ownership is reset.
+ mpImpl->mbHasSdrObjectOwnership = false;
+ SdrObject::Free( pObject );
+ }
+}
+
+
+void SAL_CALL SvxShape::addEventListener( const Reference< lang::XEventListener >& xListener )
+{
+ mpImpl->maDisposeListeners.addInterface(xListener);
+}
+
+
+void SAL_CALL SvxShape::removeEventListener( const Reference< lang::XEventListener >& aListener )
+{
+ mpImpl->maDisposeListeners.removeInterface(aListener);
+}
+
+// XPropertySet
+
+
+Reference< beans::XPropertySetInfo > SAL_CALL
+ SvxShape::getPropertySetInfo()
+{
+ if( mpImpl->mpMaster )
+ {
+ return mpImpl->mpMaster->getPropertySetInfo();
+ }
+ else
+ {
+ return _getPropertySetInfo();
+ }
+}
+
+Reference< beans::XPropertySetInfo > const &
+ SvxShape::_getPropertySetInfo()
+{
+ return mpPropSet->getPropertySetInfo();
+}
+
+
+void SAL_CALL SvxShape::addPropertyChangeListener( const OUString& _propertyName, const Reference< beans::XPropertyChangeListener >& _listener )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ mpImpl->maPropertyNotifier.addPropertyChangeListener( _propertyName, _listener );
+}
+
+
+void SAL_CALL SvxShape::removePropertyChangeListener( const OUString& _propertyName, const Reference< beans::XPropertyChangeListener >& _listener )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ mpImpl->maPropertyNotifier.removePropertyChangeListener( _propertyName, _listener );
+}
+
+
+void SAL_CALL SvxShape::addVetoableChangeListener( const OUString& , const Reference< beans::XVetoableChangeListener >& )
+{
+ OSL_FAIL( "SvxShape::addVetoableChangeListener: don't have any vetoable properties, so why ...?" );
+}
+
+
+void SAL_CALL SvxShape::removeVetoableChangeListener( const OUString& , const Reference< beans::XVetoableChangeListener >& )
+{
+ OSL_FAIL( "SvxShape::removeVetoableChangeListener: don't have any vetoable properties, so why ...?" );
+}
+
+
+bool SvxShape::SetFillAttribute( sal_uInt16 nWID, const OUString& rName )
+{
+ if(HasSdrObject())
+ {
+ SfxItemSet aSet( GetSdrObject()->getSdrModelFromSdrObject().GetItemPool(), nWID, nWID );
+
+ if( SetFillAttribute( nWID, rName, aSet, &GetSdrObject()->getSdrModelFromSdrObject() ) )
+ {
+ //GetSdrObject()->SetItemSetAndBroadcast(aSet);
+ GetSdrObject()->SetMergedItemSetAndBroadcast(aSet);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool SvxShape::SetFillAttribute( sal_uInt16 nWID, const OUString& rName, SfxItemSet& rSet, SdrModel const * pModel )
+{
+ // check if an item with the given name and which id is inside the models
+ // pool or the stylesheet pool, if found it's put in the itemset
+ if( !SetFillAttribute( nWID, rName, rSet ) )
+ {
+ // we did not find such item in one of the pools, so we check
+ // the property lists that are loaded for the model for items
+ // that support such.
+ OUString aStrName = SvxUnogetInternalNameForItem(nWID, rName);
+
+ switch( nWID )
+ {
+ case XATTR_FILLBITMAP:
+ {
+ XBitmapListRef pBitmapList = pModel->GetBitmapList();
+
+ if( !pBitmapList.is() )
+ return false;
+
+ tools::Long nPos = pBitmapList->GetIndex(aStrName);
+ if( nPos == -1 )
+ return false;
+
+ const XBitmapEntry* pEntry = pBitmapList->GetBitmap(nPos);
+ XFillBitmapItem aBmpItem(rName, pEntry->GetGraphicObject());
+ rSet.Put(aBmpItem);
+ break;
+ }
+ case XATTR_FILLGRADIENT:
+ {
+ XGradientListRef pGradientList = pModel->GetGradientList();
+
+ if( !pGradientList.is() )
+ return false;
+
+ tools::Long nPos = pGradientList->GetIndex(aStrName);
+ if( nPos == -1 )
+ return false;
+
+ const XGradientEntry* pEntry = pGradientList->GetGradient(nPos);
+ XFillGradientItem aGrdItem(rName, pEntry->GetGradient());
+ rSet.Put( aGrdItem );
+ break;
+ }
+ case XATTR_FILLHATCH:
+ {
+ XHatchListRef pHatchList = pModel->GetHatchList();
+
+ if( !pHatchList.is() )
+ return false;
+
+ tools::Long nPos = pHatchList->GetIndex(aStrName);
+ if( nPos == -1 )
+ return false;
+
+ const XHatchEntry* pEntry = pHatchList->GetHatch( nPos );
+ XFillHatchItem aHatchItem(rName, pEntry->GetHatch());
+ rSet.Put( aHatchItem );
+ break;
+ }
+ case XATTR_LINEEND:
+ case XATTR_LINESTART:
+ {
+ XLineEndListRef pLineEndList = pModel->GetLineEndList();
+
+ if( !pLineEndList.is() )
+ return false;
+
+ tools::Long nPos = pLineEndList->GetIndex(aStrName);
+ if( nPos == -1 )
+ return false;
+
+ const XLineEndEntry* pEntry = pLineEndList->GetLineEnd(nPos);
+ if( sal_uInt16(XATTR_LINEEND) == nWID )
+ {
+ XLineEndItem aLEItem(rName, pEntry->GetLineEnd());
+ rSet.Put( aLEItem );
+ }
+ else
+ {
+ XLineStartItem aLSItem(rName, pEntry->GetLineEnd());
+ rSet.Put( aLSItem );
+ }
+
+ break;
+ }
+ case XATTR_LINEDASH:
+ {
+ XDashListRef pDashList = pModel->GetDashList();
+
+ if( !pDashList.is() )
+ return false;
+
+ tools::Long nPos = pDashList->GetIndex(aStrName);
+ if( nPos == -1 )
+ return false;
+
+ const XDashEntry* pEntry = pDashList->GetDash(nPos);
+ XLineDashItem aDashItem(rName, pEntry->GetDash());
+ rSet.Put( aDashItem );
+ break;
+ }
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+bool SvxShape::SetFillAttribute( sal_uInt16 nWID, const OUString& rName, SfxItemSet& rSet )
+{
+ OUString aName = SvxUnogetInternalNameForItem(nWID, rName);
+
+ if (aName.isEmpty())
+ {
+ switch( nWID )
+ {
+ case XATTR_LINEEND:
+ case XATTR_LINESTART:
+ {
+ const basegfx::B2DPolyPolygon aEmptyPoly;
+ if( nWID == sal_uInt16(XATTR_LINEEND) )
+ rSet.Put( XLineEndItem( "", aEmptyPoly ) );
+ else
+ rSet.Put( XLineStartItem( "", aEmptyPoly ) );
+
+ return true;
+ }
+ case XATTR_FILLFLOATTRANSPARENCE:
+ {
+ // #85953# Set a disabled XFillFloatTransparenceItem
+ rSet.Put(XFillFloatTransparenceItem());
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ for (const SfxPoolItem* p : rSet.GetPool()->GetItemSurrogates(nWID))
+ {
+ const NameOrIndex* pItem = static_cast<const NameOrIndex*>(p);
+ if( pItem->GetName() == aName )
+ {
+ rSet.Put( *pItem );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+void SAL_CALL SvxShape::setPropertyValue( const OUString& rPropertyName, const uno::Any& rVal )
+{
+ if( mpImpl->mpMaster )
+ {
+ mpImpl->mpMaster->setPropertyValue( rPropertyName, rVal );
+ }
+ else
+ {
+ _setPropertyValue( rPropertyName, rVal );
+ }
+}
+
+void SvxShape::_setPropertyValue( const OUString& rPropertyName, const uno::Any& rVal )
+{
+ ::SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(rPropertyName);
+
+ if (!HasSdrObject())
+ {
+ // Since we have no actual sdr object right now, remember all
+ // properties in a list. These properties will be set when the sdr
+ // object is created.
+
+ if (pMap && pMap->nWID)
+ {
+ // FIXME: We should throw a UnknownPropertyException here.
+ // But since this class is aggregated from classes that
+ // support additional properties that we don't know here we
+ // silently store *all* properties, even if they may be not
+ // supported after creation.
+ SvxItemPropertySet::setPropertyValue( pMap, rVal, maUrsAnys );
+ }
+
+ return;
+ }
+
+ if (rPropertyName == "HandlePathObjScale")
+ {
+ auto pPathObj = dynamic_cast<SdrPathObj*>(GetSdrObject());
+ if (pPathObj)
+ {
+ bool bHandleScale{};
+ if (rVal >>= bHandleScale)
+ {
+ pPathObj->SetHandleScale(bHandleScale);
+ }
+ }
+ return;
+ }
+
+ if (!pMap)
+ {
+ // reduce log noise by ignoring two properties that higher level code queries for on all objects
+ SAL_WARN_IF(rPropertyName != "FromWordArt" && rPropertyName != "GraphicColorMode",
+ "svx.uno", "Unknown Property: " << rPropertyName);
+ throw beans::UnknownPropertyException( rPropertyName, static_cast<cppu::OWeakObject*>(this));
+ }
+
+ if ((pMap->nFlags & beans::PropertyAttribute::READONLY) != 0)
+ throw beans::PropertyVetoException(
+ "Readonly property can't be set: " + rPropertyName,
+ uno::Reference<drawing::XShape>(this));
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+
+ if (setPropertyValueImpl(rPropertyName, pMap, rVal))
+ return;
+
+ DBG_ASSERT( pMap->nWID == SDRATTR_TEXTDIRECTION || pMap->nWID < SDRATTR_NOTPERSIST_FIRST || pMap->nWID > SDRATTR_NOTPERSIST_LAST, "Not persist item not handled!" );
+ DBG_ASSERT( pMap->nWID < OWN_ATTR_VALUE_START || pMap->nWID > OWN_ATTR_VALUE_END, "Not item property not handled!" );
+
+ bool bIsNotPersist = pMap->nWID >= SDRATTR_NOTPERSIST_FIRST && pMap->nWID <= SDRATTR_NOTPERSIST_LAST && pMap->nWID != SDRATTR_TEXTDIRECTION;
+
+ if( pMap->nWID == SDRATTR_CORNER_RADIUS )
+ {
+ sal_Int32 nCornerRadius = 0;
+ if( !(rVal >>= nCornerRadius) || (nCornerRadius < 0) || (nCornerRadius > 5000000))
+ throw IllegalArgumentException();
+ }
+
+ std::optional<SfxItemSet> xLocalSet;
+ SfxItemSet* pSet;
+ if( mbIsMultiPropertyCall && !bIsNotPersist )
+ {
+ if( !mpImpl->mxItemSet )
+ {
+ mpImpl->mxItemSet.emplace( GetSdrObject()->GetProperties().CreateObjectSpecificItemSet( GetSdrObject()->getSdrModelFromSdrObject().GetItemPool() ) );
+ }
+ pSet = &*mpImpl->mxItemSet;
+ }
+ else
+ {
+ xLocalSet.emplace( GetSdrObject()->getSdrModelFromSdrObject().GetItemPool(), pMap->nWID, pMap->nWID);
+ pSet = &*xLocalSet;
+ }
+
+ if( pSet->GetItemState( pMap->nWID ) != SfxItemState::SET )
+ pSet->Put(GetSdrObject()->GetMergedItem(pMap->nWID));
+
+ if( !SvxUnoTextRangeBase::SetPropertyValueHelper( pMap, rVal, *pSet ))
+ {
+ if( pSet->GetItemState( pMap->nWID ) != SfxItemState::SET )
+ {
+ if(bIsNotPersist)
+ {
+ // not-persistent attribute, get those extra
+ GetSdrObject()->TakeNotPersistAttr(*pSet);
+ }
+ }
+
+ if( pSet->GetItemState( pMap->nWID ) != SfxItemState::SET )
+ {
+ // get default from ItemPool
+ if(SfxItemPool::IsWhich(pMap->nWID))
+ pSet->Put(GetSdrObject()->getSdrModelFromSdrObject().GetItemPool().GetDefaultItem(pMap->nWID));
+ }
+
+ if( pSet->GetItemState( pMap->nWID ) == SfxItemState::SET )
+ {
+ SvxItemPropertySet_setPropertyValue( pMap, rVal, *pSet );
+ }
+ }
+
+ if(bIsNotPersist)
+ {
+ // set not-persistent attribute extra
+ GetSdrObject()->ApplyNotPersistAttr( *pSet );
+ }
+ else
+ {
+ // if we have a XMultiProperty call then the item set
+ // will be set in setPropertyValues later
+ if( !mbIsMultiPropertyCall )
+ GetSdrObject()->SetMergedItemSetAndBroadcast( *pSet );
+ }
+}
+
+
+uno::Any SAL_CALL SvxShape::getPropertyValue( const OUString& PropertyName )
+{
+ if ( mpImpl->mpMaster )
+ return mpImpl->mpMaster->getPropertyValue( PropertyName );
+ else
+ return _getPropertyValue( PropertyName );
+}
+
+
+uno::Any SvxShape::_getPropertyValue( const OUString& PropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName);
+
+ uno::Any aAny;
+ if(HasSdrObject())
+ {
+ if(pMap == nullptr )
+ throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+
+ if( !getPropertyValueImpl( PropertyName, pMap, aAny ) )
+ {
+ DBG_ASSERT( pMap->nWID == SDRATTR_TEXTDIRECTION || (pMap->nWID < SDRATTR_NOTPERSIST_FIRST || pMap->nWID > SDRATTR_NOTPERSIST_LAST), "Not persist item not handled!" );
+ DBG_ASSERT( pMap->nWID < OWN_ATTR_VALUE_START || pMap->nWID > OWN_ATTR_VALUE_END, "Not item property not handled!" );
+
+ SfxItemSet aSet( GetSdrObject()->getSdrModelFromSdrObject().GetItemPool(), pMap->nWID, pMap->nWID );
+ aSet.Put(GetSdrObject()->GetMergedItem(pMap->nWID));
+
+ if(SvxUnoTextRangeBase::GetPropertyValueHelper( aSet, pMap, aAny ))
+ return aAny;
+
+ if(!aSet.Count())
+ {
+ if(pMap->nWID >= SDRATTR_NOTPERSIST_FIRST && pMap->nWID <= SDRATTR_NOTPERSIST_LAST)
+ {
+ // not-persistent attribute, get those extra
+ GetSdrObject()->TakeNotPersistAttr(aSet);
+ }
+ }
+
+ if(!aSet.Count())
+ {
+ // get default from ItemPool
+ if(SfxItemPool::IsWhich(pMap->nWID))
+ aSet.Put(GetSdrObject()->getSdrModelFromSdrObject().GetItemPool().GetDefaultItem(pMap->nWID));
+ }
+
+ if(aSet.Count())
+ aAny = GetAnyForItem( aSet, pMap );
+ }
+ }
+ else
+ {
+
+// Fixme: we should return default values for OWN_ATTR !
+
+ if(pMap && pMap->nWID)
+// FixMe: see setPropertyValue
+ aAny = mpPropSet->getPropertyValue( pMap, maUrsAnys );
+
+ }
+ return aAny;
+}
+
+
+// XMultiPropertySet
+void SAL_CALL SvxShape::setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues )
+{
+ ::SolarMutexGuard aSolarGuard;
+
+ const sal_Int32 nCount = aPropertyNames.getLength();
+ const OUString* pNames = aPropertyNames.getConstArray();
+
+ const uno::Any* pValues = aValues.getConstArray();
+
+ // make sure mbIsMultiPropertyCall and mpImpl->mpItemSet are
+ // reset even when an exception is thrown
+ const ::comphelper::ScopeGuard aGuard( [this] () { return this->endSetPropertyValues(); } );
+
+ mbIsMultiPropertyCall = true;
+
+ if( mpImpl->mpMaster )
+ {
+ for( sal_Int32 nIdx = 0; nIdx < nCount; nIdx++, pNames++, pValues++ )
+ {
+ try
+ {
+ setPropertyValue( *pNames, *pValues );
+ }
+ catch (beans::UnknownPropertyException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ catch (uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+ else
+ {
+ uno::Reference< beans::XPropertySet > xSet;
+ queryInterface( cppu::UnoType<beans::XPropertySet>::get()) >>= xSet;
+
+ for( sal_Int32 nIdx = 0; nIdx < nCount; nIdx++, pNames++, pValues++ )
+ {
+ try
+ {
+ xSet->setPropertyValue( *pNames, *pValues );
+ }
+ catch (beans::UnknownPropertyException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ catch (uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+ }
+
+ if( mpImpl->mxItemSet && HasSdrObject() )
+ GetSdrObject()->SetMergedItemSetAndBroadcast( *mpImpl->mxItemSet );
+}
+
+
+void SvxShape::endSetPropertyValues()
+{
+ mbIsMultiPropertyCall = false;
+ mpImpl->mxItemSet.reset();
+}
+
+
+css::uno::Sequence< css::uno::Any > SAL_CALL SvxShape::getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames )
+{
+ const sal_Int32 nCount = aPropertyNames.getLength();
+ const OUString* pNames = aPropertyNames.getConstArray();
+
+ uno::Sequence< uno::Any > aRet( nCount );
+ uno::Any* pValue = aRet.getArray();
+
+ if( mpImpl->mpMaster )
+ {
+ for( sal_Int32 nIdx = 0; nIdx < nCount; nIdx++, pValue++, pNames++ )
+ {
+ try
+ {
+ *pValue = getPropertyValue( *pNames );
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( "SvxShape::getPropertyValues, unknown property asked" );
+ }
+ }
+ }
+ else
+ {
+ uno::Reference< beans::XPropertySet > xSet;
+ queryInterface( cppu::UnoType<beans::XPropertySet>::get()) >>= xSet;
+
+ for( sal_Int32 nIdx = 0; nIdx < nCount; nIdx++, pValue++, pNames++ )
+ {
+ try
+ {
+ *pValue = xSet->getPropertyValue( *pNames );
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( "SvxShape::getPropertyValues, unknown property asked" );
+ }
+ }
+ }
+
+ return aRet;
+}
+
+void SAL_CALL SvxShape::addPropertiesChangeListener( const css::uno::Sequence< OUString >& , const css::uno::Reference< css::beans::XPropertiesChangeListener >& )
+{
+}
+
+void SAL_CALL SvxShape::removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& )
+{
+}
+
+void SAL_CALL SvxShape::firePropertiesChangeEvent( const css::uno::Sequence< OUString >& , const css::uno::Reference< css::beans::XPropertiesChangeListener >& )
+{
+}
+
+
+uno::Any SvxShape::GetAnyForItem( SfxItemSet const & aSet, const SfxItemPropertyMapEntry* pMap ) const
+{
+ DBG_TESTSOLARMUTEX();
+ uno::Any aAny;
+
+ switch(pMap->nWID)
+ {
+ case SDRATTR_CIRCSTARTANGLE:
+ {
+ if(const SdrAngleItem* pPoolItem = aSet.GetItemIfSet(SDRATTR_CIRCSTARTANGLE,false))
+ {
+ Degree100 nAngle = pPoolItem->GetValue();
+ aAny <<= nAngle.get();
+ }
+ break;
+ }
+
+ case SDRATTR_CIRCENDANGLE:
+ {
+ if (const SdrAngleItem* pPoolItem = aSet.GetItemIfSet(SDRATTR_CIRCENDANGLE,false))
+ {
+ Degree100 nAngle = pPoolItem->GetValue();
+ aAny <<= nAngle.get();
+ }
+ break;
+ }
+
+ case SDRATTR_CIRCKIND:
+ {
+ if( GetSdrObject()->GetObjInventor() == SdrInventor::Default)
+ {
+ drawing::CircleKind eKind;
+ switch(GetSdrObject()->GetObjIdentifier())
+ {
+ case SdrObjKind::CircleOrEllipse: // circle, ellipse
+ eKind = drawing::CircleKind_FULL;
+ break;
+ case SdrObjKind::CircleCut: // segment of circle
+ eKind = drawing::CircleKind_CUT;
+ break;
+ case SdrObjKind::CircleArc: // arc of circle
+ eKind = drawing::CircleKind_ARC;
+ break;
+ case SdrObjKind::CircleSection: // sector
+ eKind = drawing::CircleKind_SECTION;
+ break;
+ default:
+ break;
+ }
+ aAny <<= eKind;
+ }
+ break;
+ }
+ default:
+ {
+ // get value from ItemSet
+ aAny = SvxItemPropertySet_getPropertyValue( pMap, aSet );
+
+ if( pMap->aType != aAny.getValueType() )
+ {
+ // since the sfx uint16 item now exports a sal_Int32, we may have to fix this here
+ if( ( pMap->aType == ::cppu::UnoType<sal_Int16>::get()) && aAny.getValueType() == ::cppu::UnoType<sal_Int32>::get() )
+ {
+ sal_Int32 nValue = 0;
+ aAny >>= nValue;
+ aAny <<= static_cast<sal_Int16>(nValue);
+ }
+ else
+ {
+ OSL_FAIL("SvxShape::GetAnyForItem() Returnvalue has wrong Type!" );
+ }
+ }
+
+ }
+ }
+
+ return aAny;
+}
+
+
+// XPropertyState
+beans::PropertyState SAL_CALL SvxShape::getPropertyState( const OUString& PropertyName )
+{
+ if( mpImpl->mpMaster )
+ {
+ return mpImpl->mpMaster->getPropertyState( PropertyName );
+ }
+ else
+ {
+ return _getPropertyState( PropertyName );
+ }
+}
+
+beans::PropertyState SvxShape::_getPropertyState( const OUString& PropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName);
+
+ if( !HasSdrObject() || pMap == nullptr )
+ throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+
+ beans::PropertyState eState;
+ if( !getPropertyStateImpl( pMap, eState ) )
+ {
+ const SfxItemSet& rSet = GetSdrObject()->GetMergedItemSet();
+
+ switch( rSet.GetItemState( pMap->nWID, false ) )
+ {
+ case SfxItemState::SET:
+ eState = beans::PropertyState_DIRECT_VALUE;
+ break;
+ case SfxItemState::DEFAULT:
+ eState = beans::PropertyState_DEFAULT_VALUE;
+ break;
+ default:
+ eState = beans::PropertyState_AMBIGUOUS_VALUE;
+ break;
+ }
+
+ // if an item is set, this doesn't mean we want it :)
+ if( beans::PropertyState_DIRECT_VALUE == eState )
+ {
+ switch( pMap->nWID )
+ {
+ // the following items are disabled by changing the
+ // fill style or the line style. so there is no need
+ // to export items without names which should be empty
+ case XATTR_FILLBITMAP:
+ case XATTR_FILLGRADIENT:
+ case XATTR_FILLHATCH:
+ case XATTR_LINEDASH:
+ {
+ const NameOrIndex* pItem = rSet.GetItem<NameOrIndex>(pMap->nWID);
+ if( ( pItem == nullptr ) || pItem->GetName().isEmpty() )
+ eState = beans::PropertyState_DEFAULT_VALUE;
+ }
+ break;
+
+ // #i36115#
+ // If e.g. the LineStart is on NONE and thus the string has length 0, it still
+ // may be a hard attribute covering the set LineStart of the parent (Style).
+ // #i37644#
+ // same is for fill float transparency
+ case XATTR_LINEEND:
+ case XATTR_LINESTART:
+ case XATTR_FILLFLOATTRANSPARENCE:
+ {
+ const NameOrIndex* pItem = rSet.GetItem<NameOrIndex>(pMap->nWID);
+ if ( pItem == nullptr )
+ eState = beans::PropertyState_DEFAULT_VALUE;
+ }
+ break;
+ case XATTR_FILLCOLOR:
+ if (pMap->nMemberId == MID_COLOR_THEME_INDEX)
+ {
+ const XFillColorItem* pColor = rSet.GetItem<XFillColorItem>(pMap->nWID);
+ if (pColor->GetThemeColor().GetThemeIndex() == -1)
+ {
+ eState = beans::PropertyState_DEFAULT_VALUE;
+ }
+ }
+ else if (pMap->nMemberId == MID_COLOR_LUM_MOD)
+ {
+ const XFillColorItem* pColor = rSet.GetItem<XFillColorItem>(pMap->nWID);
+ if (pColor->GetThemeColor().GetLumMod() == 10000)
+ {
+ eState = beans::PropertyState_DEFAULT_VALUE;
+ }
+ }
+ else if (pMap->nMemberId == MID_COLOR_LUM_OFF)
+ {
+ const XFillColorItem* pColor = rSet.GetItem<XFillColorItem>(pMap->nWID);
+ if (pColor->GetThemeColor().GetLumOff() == 0)
+ {
+ eState = beans::PropertyState_DEFAULT_VALUE;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return eState;
+}
+
+bool SvxShape::setPropertyValueImpl( const OUString&, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_CAPTION_POINT:
+ {
+ awt::Point aPnt;
+ if( rValue >>= aPnt )
+ {
+ Point aVclPoint( aPnt.X, aPnt.Y );
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ // Need to adapt aVclPoint from 100thmm to app-specific
+ ForceMetricToItemPoolMetric(aVclPoint);
+
+ // #90763# position is relative to top left, make it absolute
+ basegfx::B2DPolyPolygon aNewPolyPolygon;
+ basegfx::B2DHomMatrix aNewHomogenMatrix;
+ GetSdrObject()->TRGetBaseGeometry(aNewHomogenMatrix, aNewPolyPolygon);
+
+ aVclPoint.AdjustX(basegfx::fround(aNewHomogenMatrix.get(0, 2)) );
+ aVclPoint.AdjustY(basegfx::fround(aNewHomogenMatrix.get(1, 2)) );
+
+ // #88491# position relative to anchor
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ {
+ aVclPoint += GetSdrObject()->GetAnchorPos();
+ }
+
+ static_cast<SdrCaptionObj*>(GetSdrObject())->SetTailPos(aVclPoint);
+
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_TRANSFORMATION:
+ {
+ drawing::HomogenMatrix3 aMatrix;
+ if(rValue >>= aMatrix)
+ {
+ basegfx::B2DPolyPolygon aNewPolyPolygon;
+ basegfx::B2DHomMatrix aNewHomogenMatrix;
+
+ // tdf#117145 SdrModel data is app-specific
+ GetSdrObject()->TRGetBaseGeometry(aNewHomogenMatrix, aNewPolyPolygon);
+
+ aNewHomogenMatrix.set(0, 0, aMatrix.Line1.Column1);
+ aNewHomogenMatrix.set(0, 1, aMatrix.Line1.Column2);
+ aNewHomogenMatrix.set(0, 2, aMatrix.Line1.Column3);
+ aNewHomogenMatrix.set(1, 0, aMatrix.Line2.Column1);
+ aNewHomogenMatrix.set(1, 1, aMatrix.Line2.Column2);
+ aNewHomogenMatrix.set(1, 2, aMatrix.Line2.Column3);
+ aNewHomogenMatrix.set(2, 0, aMatrix.Line3.Column1);
+ aNewHomogenMatrix.set(2, 1, aMatrix.Line3.Column2);
+ aNewHomogenMatrix.set(2, 2, aMatrix.Line3.Column3);
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ // Need to adapt aNewHomogenMatrix from 100thmm to app-specific
+ ForceMetricToItemPoolMetric(aNewHomogenMatrix);
+
+ GetSdrObject()->TRSetBaseGeometry(aNewHomogenMatrix, aNewPolyPolygon);
+ return true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_ZORDER:
+ {
+ sal_Int32 nNewOrdNum = 0;
+ if(rValue >>= nNewOrdNum)
+ {
+ SdrObjList* pObjList = GetSdrObject()->getParentSdrObjListFromSdrObject();
+ if( pObjList )
+ pObjList->SetExistingObjectOrdNum( GetSdrObject(), static_cast<size_t>(nNewOrdNum) );
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_FRAMERECT:
+ {
+ awt::Rectangle aUnoRect;
+ if(rValue >>= aUnoRect)
+ {
+ Point aTopLeft( aUnoRect.X, aUnoRect.Y );
+ Size aObjSize( aUnoRect.Width, aUnoRect.Height );
+ ForceMetricToItemPoolMetric(aTopLeft);
+ ForceMetricToItemPoolMetric(aObjSize);
+ tools::Rectangle aRect;
+ aRect.SetPos(aTopLeft);
+ aRect.SetSize(aObjSize);
+ GetSdrObject()->SetSnapRect(aRect);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_MIRRORED:
+ {
+ bool bMirror;
+ if(rValue >>= bMirror )
+ {
+ SdrGrafObj* pObj = dynamic_cast< SdrGrafObj* >( GetSdrObject() );
+ if( pObj )
+ pObj->SetMirrored(bMirror);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_EDGE_START_OBJ:
+ case OWN_ATTR_EDGE_END_OBJ:
+ case OWN_ATTR_GLUEID_HEAD:
+ case OWN_ATTR_GLUEID_TAIL:
+ case OWN_ATTR_EDGE_START_POS:
+ case OWN_ATTR_EDGE_END_POS:
+ case OWN_ATTR_EDGE_POLYPOLYGONBEZIER:
+ {
+ SdrEdgeObj* pEdgeObj = dynamic_cast< SdrEdgeObj* >(GetSdrObject());
+ if(pEdgeObj)
+ {
+ switch(pProperty->nWID)
+ {
+ case OWN_ATTR_EDGE_START_OBJ:
+ case OWN_ATTR_EDGE_END_OBJ:
+ {
+ Reference< drawing::XShape > xShape;
+ if( rValue >>= xShape )
+ {
+ SdrObject* pNode = SdrObject::getSdrObjectFromXShape(xShape);
+ if( pNode )
+ {
+ pEdgeObj->ConnectToNode( pProperty->nWID == OWN_ATTR_EDGE_START_OBJ, pNode );
+ pEdgeObj->setGluePointIndex( pProperty->nWID == OWN_ATTR_EDGE_START_OBJ );
+ return true;
+ }
+ }
+ break;
+ }
+
+ case OWN_ATTR_EDGE_START_POS:
+ case OWN_ATTR_EDGE_END_POS:
+ {
+ awt::Point aUnoPoint;
+ if( rValue >>= aUnoPoint )
+ {
+ Point aPoint( aUnoPoint.X, aUnoPoint.Y );
+
+ // Reintroduction of fix for issue i59051 (#i108851#)
+ // perform metric change before applying anchor position,
+ // because the anchor position is in pool metric.
+ ForceMetricToItemPoolMetric( aPoint );
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ aPoint += GetSdrObject()->GetAnchorPos();
+
+ pEdgeObj->SetTailPoint( pProperty->nWID == OWN_ATTR_EDGE_START_POS, aPoint );
+ return true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_GLUEID_HEAD:
+ case OWN_ATTR_GLUEID_TAIL:
+ {
+ sal_Int32 nId = 0;
+ if( rValue >>= nId )
+ {
+ pEdgeObj->setGluePointIndex( pProperty->nWID == OWN_ATTR_GLUEID_HEAD, nId );
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_EDGE_POLYPOLYGONBEZIER:
+ {
+ basegfx::B2DPolyPolygon aNewPolyPolygon;
+
+ // #123616# be a little bit more flexible regarding the data type used
+ if( auto s = o3tl::tryAccess<drawing::PointSequenceSequence>(rValue) )
+ {
+ // get polygpon data from PointSequenceSequence
+ aNewPolyPolygon = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(
+ *s);
+ }
+ else if( auto cs = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(rValue) )
+ {
+ // get polygpon data from PolyPolygonBezierCoords
+ aNewPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
+ *cs);
+ }
+
+ if(aNewPolyPolygon.count())
+ {
+ // Reintroduction of fix for issue i59051 (#i108851#)
+ ForceMetricToItemPoolMetric( aNewPolyPolygon );
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ {
+ Point aPoint( GetSdrObject()->GetAnchorPos() );
+ aNewPolyPolygon.transform(basegfx::utils::createTranslateB2DHomMatrix(aPoint.X(), aPoint.Y()));
+ }
+ pEdgeObj->SetEdgeTrackPath( aNewPolyPolygon );
+ return true;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case OWN_ATTR_MEASURE_START_POS:
+ case OWN_ATTR_MEASURE_END_POS:
+ {
+ SdrMeasureObj* pMeasureObj = dynamic_cast< SdrMeasureObj* >(GetSdrObject());
+ awt::Point aUnoPoint;
+ if(pMeasureObj && ( rValue >>= aUnoPoint ) )
+ {
+ Point aPoint( aUnoPoint.X, aUnoPoint.Y );
+
+ // Reintroduction of fix for issue #i59051# (#i108851#)
+ ForceMetricToItemPoolMetric( aPoint );
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ aPoint += GetSdrObject()->GetAnchorPos();
+
+ pMeasureObj->NbcSetPoint( aPoint, pProperty->nWID == OWN_ATTR_MEASURE_START_POS ? 0 : 1 );
+ pMeasureObj->SetChanged();
+ pMeasureObj->BroadcastObjectChange();
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_FILLBMP_MODE:
+ {
+ drawing::BitmapMode eMode;
+ if(!(rValue >>= eMode) )
+ {
+ sal_Int32 nMode = 0;
+ if(!(rValue >>= nMode))
+ break;
+
+ eMode = static_cast<drawing::BitmapMode>(nMode);
+ }
+ GetSdrObject()->SetMergedItem( XFillBmpStretchItem( eMode == drawing::BitmapMode_STRETCH ) );
+ GetSdrObject()->SetMergedItem( XFillBmpTileItem( eMode == drawing::BitmapMode_REPEAT ) );
+ return true;
+ }
+
+ case SDRATTR_LAYERID:
+ {
+ sal_Int16 nLayerId = sal_Int16();
+ if( rValue >>= nLayerId )
+ {
+ SdrLayer* pLayer = GetSdrObject()->getSdrModelFromSdrObject().GetLayerAdmin().GetLayerPerID(SdrLayerID(nLayerId));
+ if( pLayer )
+ {
+ GetSdrObject()->SetLayer(SdrLayerID(nLayerId));
+ return true;
+ }
+ }
+ break;
+ }
+
+ case SDRATTR_LAYERNAME:
+ {
+ OUString aLayerName;
+ if( rValue >>= aLayerName )
+ {
+ const SdrLayer* pLayer = GetSdrObject()->getSdrModelFromSdrObject().GetLayerAdmin().GetLayer(aLayerName);
+ if( pLayer != nullptr )
+ {
+ GetSdrObject()->SetLayer( pLayer->GetID() );
+ return true;
+ }
+ }
+ break;
+ }
+ case SDRATTR_ROTATEANGLE:
+ {
+ sal_Int32 nTmp = 0;
+ if( rValue >>= nTmp )
+ {
+ Degree100 nAngle(nTmp);
+ Point aRef1(GetSdrObject()->GetSnapRect().Center());
+ nAngle -= GetSdrObject()->GetRotateAngle();
+ if (nAngle)
+ {
+ double nSin = sin(toRadians(nAngle));
+ double nCos = cos(toRadians(nAngle));
+ GetSdrObject()->Rotate(aRef1,nAngle,nSin,nCos);
+ }
+ return true;
+ }
+
+ break;
+ }
+
+ case SDRATTR_SHEARANGLE:
+ {
+ sal_Int32 nTmp = 0;
+ if( rValue >>= nTmp )
+ {
+ Degree100 nShear(nTmp);
+ nShear -= GetSdrObject()->GetShearAngle();
+ if(nShear)
+ {
+ Point aRef1(GetSdrObject()->GetSnapRect().Center());
+ double nTan = tan(toRadians(nShear));
+ GetSdrObject()->Shear(aRef1,nShear,nTan,false);
+ return true;
+ }
+ }
+
+ break;
+ }
+
+ case OWN_ATTR_INTEROPGRABBAG:
+ {
+ GetSdrObject()->SetGrabBagItem(rValue);
+ return true;
+ }
+
+ case SDRATTR_OBJMOVEPROTECT:
+ {
+ bool bMoveProtect;
+ if( rValue >>= bMoveProtect )
+ {
+ GetSdrObject()->SetMoveProtect(bMoveProtect);
+ return true;
+ }
+ break;
+ }
+ case SDRATTR_OBJECTNAME:
+ {
+ OUString aName;
+ if( rValue >>= aName )
+ {
+ GetSdrObject()->SetName( aName );
+ return true;
+ }
+ break;
+ }
+
+ case OWN_ATTR_TEXTFITTOSIZESCALE:
+ {
+ sal_Int16 nMaxScale = 0;
+ if (rValue >>= nMaxScale)
+ {
+ SdrTextFitToSizeTypeItem aItem(GetSdrObject()->GetMergedItem(SDRATTR_TEXT_FITTOSIZE));
+ aItem.SetMaxScale(nMaxScale);
+ GetSdrObject()->SetMergedItem(aItem);
+ return true;
+ }
+ break;
+ }
+
+ // #i68101#
+ case OWN_ATTR_MISC_OBJ_TITLE:
+ {
+ OUString aTitle;
+ if( rValue >>= aTitle )
+ {
+ GetSdrObject()->SetTitle( aTitle );
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_MISC_OBJ_DESCRIPTION:
+ {
+ OUString aDescription;
+ if( rValue >>= aDescription )
+ {
+ GetSdrObject()->SetDescription( aDescription );
+ return true;
+ }
+ break;
+ }
+
+ case SDRATTR_OBJPRINTABLE:
+ {
+ bool bPrintable;
+ if( rValue >>= bPrintable )
+ {
+ GetSdrObject()->SetPrintable(bPrintable);
+ return true;
+ }
+ break;
+ }
+ case SDRATTR_OBJVISIBLE:
+ {
+ bool bVisible;
+ if( rValue >>= bVisible )
+ {
+ GetSdrObject()->SetVisible(bVisible);
+ return true;
+ }
+ break;
+ }
+ case SDRATTR_OBJSIZEPROTECT:
+ {
+ bool bResizeProtect;
+ if( rValue >>= bResizeProtect )
+ {
+ GetSdrObject()->SetResizeProtect(bResizeProtect);
+ return true;
+ }
+ break;
+ }
+ case OWN_ATTR_PAGE_NUMBER:
+ {
+ sal_Int32 nPageNum = 0;
+ if( (rValue >>= nPageNum) && ( nPageNum >= 0 ) && ( nPageNum <= 0xffff ) )
+ {
+ SdrPageObj* pPageObj = dynamic_cast< SdrPageObj* >(GetSdrObject());
+ if( pPageObj )
+ {
+ SdrModel& rModel(pPageObj->getSdrModelFromSdrObject());
+ SdrPage* pNewPage = nullptr;
+ const sal_uInt16 nDestinationPageNum(static_cast<sal_uInt16>((nPageNum << 1) - 1));
+
+ if(nDestinationPageNum < rModel.GetPageCount())
+ {
+ pNewPage = rModel.GetPage(nDestinationPageNum);
+ }
+
+ pPageObj->SetReferencedPage(pNewPage);
+ }
+
+ return true;
+ }
+ break;
+ }
+ case XATTR_FILLBITMAP:
+ case XATTR_FILLGRADIENT:
+ case XATTR_FILLHATCH:
+ case XATTR_FILLFLOATTRANSPARENCE:
+ case XATTR_LINEEND:
+ case XATTR_LINESTART:
+ case XATTR_LINEDASH:
+ {
+ if( pProperty->nMemberId == MID_NAME )
+ {
+ OUString aApiName;
+ if( rValue >>= aApiName )
+ {
+ if( SetFillAttribute( pProperty->nWID, aApiName ) )
+ return true;
+ }
+ break;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ case OWN_ATTR_TEXTCOLUMNS:
+ {
+ if (auto pTextObj = dynamic_cast<SdrTextObj*>(GetSdrObject()))
+ {
+ css::uno::Reference<css::text::XTextColumns> xTextColumns;
+ if (rValue >>= xTextColumns)
+ {
+ pTextObj->SetTextColumnsNumber(xTextColumns->getColumnCount());
+ if (css::uno::Reference<css::beans::XPropertySet> xPropSet{ xTextColumns,
+ css::uno::UNO_QUERY })
+ {
+ auto aVal = xPropSet->getPropertyValue("AutomaticDistance");
+ if (sal_Int32 nSpacing; aVal >>= nSpacing)
+ pTextObj->SetTextColumnsSpacing(nSpacing);
+ }
+ }
+ }
+ return true;
+ }
+
+ case OWN_ATTR_HYPERLINK:
+ {
+ OUString sHyperlink;
+ if (rValue >>= sHyperlink)
+ {
+ GetSdrObject()->setHyperlink(sHyperlink);
+ return true;
+ }
+ break;
+ }
+
+ default:
+ {
+ return false;
+ }
+ }
+
+ OUString sExceptionMessage ("IllegalArgumentException in SvxShape::setPropertyValueImpl."
+ " Property Type: " + pProperty->aType.getTypeName() + " Property nWID: " + OUString::number(pProperty->nWID)
+ + " Value Type: " + (rValue.hasValue() ? rValue.getValueTypeName() : "void (no value)"));
+
+ throw lang::IllegalArgumentException(sExceptionMessage, nullptr, 1);
+}
+
+
+bool SvxShape::getPropertyValueImpl( const OUString&, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ switch( pProperty->nWID )
+ {
+ case OWN_ATTR_CAPTION_POINT:
+ {
+ Point aVclPoint = static_cast<SdrCaptionObj*>(GetSdrObject())->GetTailPos();
+
+ // #88491# make pos relative to anchor
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ {
+ aVclPoint -= GetSdrObject()->GetAnchorPos();
+ }
+
+ // #90763# pos is absolute, make it relative to top left
+ basegfx::B2DPolyPolygon aNewPolyPolygon;
+ basegfx::B2DHomMatrix aNewHomogenMatrix;
+ GetSdrObject()->TRGetBaseGeometry(aNewHomogenMatrix, aNewPolyPolygon);
+
+ aVclPoint.AdjustX( -(basegfx::fround(aNewHomogenMatrix.get(0, 2))) );
+ aVclPoint.AdjustY( -(basegfx::fround(aNewHomogenMatrix.get(1, 2))) );
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ // Need to adapt aVclPoint from app-specific to 100thmm
+ ForceMetricTo100th_mm(aVclPoint);
+
+ awt::Point aPnt( aVclPoint.X(), aVclPoint.Y() );
+ rValue <<= aPnt;
+ break;
+ }
+
+ case OWN_ATTR_TRANSFORMATION:
+ {
+ basegfx::B2DPolyPolygon aNewPolyPolygon;
+ basegfx::B2DHomMatrix aNewHomogenMatrix;
+ GetSdrObject()->TRGetBaseGeometry(aNewHomogenMatrix, aNewPolyPolygon);
+ drawing::HomogenMatrix3 aMatrix;
+
+ // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm
+ // Need to adapt aNewHomogenMatrix from app-specific to 100thmm
+ ForceMetricTo100th_mm(aNewHomogenMatrix);
+
+ aMatrix.Line1.Column1 = aNewHomogenMatrix.get(0, 0);
+ aMatrix.Line1.Column2 = aNewHomogenMatrix.get(0, 1);
+ aMatrix.Line1.Column3 = aNewHomogenMatrix.get(0, 2);
+ aMatrix.Line2.Column1 = aNewHomogenMatrix.get(1, 0);
+ aMatrix.Line2.Column2 = aNewHomogenMatrix.get(1, 1);
+ aMatrix.Line2.Column3 = aNewHomogenMatrix.get(1, 2);
+ aMatrix.Line3.Column1 = aNewHomogenMatrix.get(2, 0);
+ aMatrix.Line3.Column2 = aNewHomogenMatrix.get(2, 1);
+ aMatrix.Line3.Column3 = aNewHomogenMatrix.get(2, 2);
+
+ rValue <<= aMatrix;
+
+ break;
+ }
+
+ case OWN_ATTR_ZORDER:
+ {
+ rValue <<= static_cast<sal_Int32>(GetSdrObject()->GetOrdNum());
+ break;
+ }
+
+ case OWN_ATTR_BITMAP:
+ {
+ rValue = GetBitmap();
+ if(!rValue.hasValue())
+ throw uno::RuntimeException();
+
+ break;
+ }
+
+ case OWN_ATTR_ISFONTWORK:
+ {
+ bool bIsFontwork = false;
+ if (const SdrTextObj* pTextObj = dynamic_cast<const SdrTextObj*>(GetSdrObject()))
+ bIsFontwork = pTextObj->IsFontwork();
+ rValue <<= bIsFontwork;
+ break;
+ }
+
+ case OWN_ATTR_FRAMERECT:
+ {
+ tools::Rectangle aRect( GetSdrObject()->GetSnapRect() );
+ Point aTopLeft( aRect.TopLeft() );
+ Size aObjSize( aRect.GetWidth(), aRect.GetHeight() );
+ ForceMetricTo100th_mm(aTopLeft);
+ ForceMetricTo100th_mm(aObjSize);
+ css::awt::Rectangle aUnoRect(
+ aTopLeft.X(), aTopLeft.Y(),
+ aObjSize.getWidth(), aObjSize.getHeight() );
+ rValue <<= aUnoRect;
+ break;
+ }
+
+ case OWN_ATTR_BOUNDRECT:
+ {
+ tools::Rectangle aRect( GetSdrObject()->GetCurrentBoundRect() );
+ Point aTopLeft( aRect.TopLeft() );
+ Size aObjSize( aRect.GetWidth(), aRect.GetHeight() );
+ ForceMetricTo100th_mm(aTopLeft);
+ ForceMetricTo100th_mm(aObjSize);
+ css::awt::Rectangle aUnoRect(
+ aTopLeft.X(), aTopLeft.Y(),
+ aObjSize.getWidth(), aObjSize.getHeight() );
+ rValue <<= aUnoRect;
+ break;
+ }
+
+ case OWN_ATTR_LDNAME:
+ {
+ OUString aName( GetSdrObject()->GetName() );
+ rValue <<= aName;
+ break;
+ }
+
+ case OWN_ATTR_LDBITMAP:
+ {
+ OUString sId;
+ if( GetSdrObject()->GetObjInventor() == SdrInventor::Default && GetSdrObject()->GetObjIdentifier() == SdrObjKind::OLE2 )
+ {
+ sId = RID_UNODRAW_OLE2;
+ }
+ else if( GetSdrObject()->GetObjInventor() == SdrInventor::Default && GetSdrObject()->GetObjIdentifier() == SdrObjKind::Graphic )
+ {
+ sId = RID_UNODRAW_GRAPHICS;
+ }
+ else
+ {
+ sId = RID_UNODRAW_OBJECTS;
+ }
+
+ BitmapEx aBmp(sId);
+ Reference<awt::XBitmap> xBmp(VCLUnoHelper::CreateBitmap(aBmp));
+
+ rValue <<= xBmp;
+ break;
+ }
+
+ case OWN_ATTR_MIRRORED:
+ {
+ bool bMirror = false;
+ if( HasSdrObject() )
+ if (auto pGrafObj = dynamic_cast<SdrGrafObj*>(GetSdrObject()) )
+ bMirror = pGrafObj->IsMirrored();
+
+ rValue <<= bMirror;
+ break;
+ }
+
+ case OWN_ATTR_EDGE_START_OBJ:
+ case OWN_ATTR_EDGE_START_POS:
+ case OWN_ATTR_EDGE_END_POS:
+ case OWN_ATTR_EDGE_END_OBJ:
+ case OWN_ATTR_GLUEID_HEAD:
+ case OWN_ATTR_GLUEID_TAIL:
+ case OWN_ATTR_EDGE_POLYPOLYGONBEZIER:
+ {
+ SdrEdgeObj* pEdgeObj = dynamic_cast<SdrEdgeObj*>(GetSdrObject());
+ if(pEdgeObj)
+ {
+ switch(pProperty->nWID)
+ {
+ case OWN_ATTR_EDGE_START_OBJ:
+ case OWN_ATTR_EDGE_END_OBJ:
+ {
+ SdrObject* pNode = pEdgeObj->GetConnectedNode(pProperty->nWID == OWN_ATTR_EDGE_START_OBJ);
+ if(pNode)
+ {
+ Reference< drawing::XShape > xShape( GetXShapeForSdrObject( pNode ) );
+ if(xShape.is())
+ rValue <<= xShape;
+
+ }
+ break;
+ }
+
+ case OWN_ATTR_EDGE_START_POS:
+ case OWN_ATTR_EDGE_END_POS:
+ {
+ Point aPoint( pEdgeObj->GetTailPoint( pProperty->nWID == OWN_ATTR_EDGE_START_POS ) );
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ aPoint -= GetSdrObject()->GetAnchorPos();
+
+ ForceMetricTo100th_mm( aPoint );
+ awt::Point aUnoPoint( aPoint.X(), aPoint.Y() );
+
+ rValue <<= aUnoPoint;
+ break;
+ }
+ case OWN_ATTR_GLUEID_HEAD:
+ case OWN_ATTR_GLUEID_TAIL:
+ {
+ rValue <<= pEdgeObj->getGluePointIndex( pProperty->nWID == OWN_ATTR_GLUEID_HEAD );
+ break;
+ }
+ case OWN_ATTR_EDGE_POLYPOLYGONBEZIER:
+ {
+ basegfx::B2DPolyPolygon aPolyPoly( pEdgeObj->GetEdgeTrackPath() );
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ {
+ Point aPoint( GetSdrObject()->GetAnchorPos() );
+ aPolyPoly.transform(basegfx::utils::createTranslateB2DHomMatrix(-aPoint.X(), -aPoint.Y()));
+ }
+ // Reintroduction of fix for issue #i59051# (#i108851#)
+ ForceMetricTo100th_mm( aPolyPoly );
+ drawing::PolyPolygonBezierCoords aRetval;
+ basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( aPolyPoly, aRetval);
+ rValue <<= aRetval;
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ case OWN_ATTR_MEASURE_START_POS:
+ case OWN_ATTR_MEASURE_END_POS:
+ {
+ SdrMeasureObj* pMeasureObj = dynamic_cast<SdrMeasureObj*>(GetSdrObject());
+ if(pMeasureObj)
+ {
+ Point aPoint( pMeasureObj->GetPoint( pProperty->nWID == OWN_ATTR_MEASURE_START_POS ? 0 : 1 ) );
+ if( GetSdrObject()->getSdrModelFromSdrObject().IsWriter() )
+ aPoint -= GetSdrObject()->GetAnchorPos();
+
+ // Reintroduction of fix for issue #i59051# (#i108851#)
+ ForceMetricTo100th_mm( aPoint );
+ awt::Point aUnoPoint( aPoint.X(), aPoint.Y() );
+
+ rValue <<= aUnoPoint;
+ break;
+ }
+ break;
+ }
+
+ case OWN_ATTR_FILLBMP_MODE:
+ {
+ const SfxItemSet& rObjItemSet = GetSdrObject()->GetMergedItemSet();
+
+ if (rObjItemSet.Get(XATTR_FILLBMP_TILE).GetValue())
+ {
+ rValue <<= drawing::BitmapMode_REPEAT;
+ }
+ else if (rObjItemSet.Get(XATTR_FILLBMP_STRETCH).GetValue())
+ {
+ rValue <<= drawing::BitmapMode_STRETCH;
+ }
+ else
+ {
+ rValue <<= drawing::BitmapMode_NO_REPEAT;
+ }
+ break;
+ }
+ case SDRATTR_LAYERID:
+ rValue <<= GetSdrObject()->GetLayer().get();
+ break;
+
+ case SDRATTR_LAYERNAME:
+ {
+ SdrLayer* pLayer = GetSdrObject()->getSdrModelFromSdrObject().GetLayerAdmin().GetLayerPerID(GetSdrObject()->GetLayer());
+ if( pLayer )
+ {
+ rValue <<= pLayer->GetName();
+ }
+ break;
+ }
+
+ case SDRATTR_ROTATEANGLE:
+ rValue <<= static_cast<sal_Int32>(GetSdrObject()->GetRotateAngle());
+ break;
+
+ case SDRATTR_SHEARANGLE:
+ rValue <<= static_cast<sal_Int32>(GetSdrObject()->GetShearAngle());
+ break;
+
+ case OWN_ATTR_INTEROPGRABBAG:
+ {
+ GetSdrObject()->GetGrabBagItem(rValue);
+ break;
+ }
+
+ case SDRATTR_OBJMOVEPROTECT:
+ rValue <<= GetSdrObject()->IsMoveProtect();
+ break;
+
+ case SDRATTR_OBJECTNAME:
+ {
+ OUString aName( GetSdrObject()->GetName() );
+ rValue <<= aName;
+ break;
+ }
+
+ // #i68101#
+ case OWN_ATTR_MISC_OBJ_TITLE:
+ {
+ OUString aTitle( GetSdrObject()->GetTitle() );
+ rValue <<= aTitle;
+ break;
+ }
+
+ case OWN_ATTR_MISC_OBJ_DESCRIPTION:
+ {
+ OUString aDescription( GetSdrObject()->GetDescription() );
+ rValue <<= aDescription;
+ break;
+ }
+
+ case SDRATTR_OBJPRINTABLE:
+ rValue <<= GetSdrObject()->IsPrintable();
+ break;
+
+ case SDRATTR_OBJVISIBLE:
+ rValue <<= GetSdrObject()->IsVisible();
+ break;
+
+ case SDRATTR_OBJSIZEPROTECT:
+ rValue <<= GetSdrObject()->IsResizeProtect();
+ break;
+
+ case OWN_ATTR_PAGE_NUMBER:
+ {
+ SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(GetSdrObject());
+ if(pPageObj)
+ {
+ SdrPage* pPage = pPageObj->GetReferencedPage();
+ sal_Int32 nPageNumber = pPage ? pPage->GetPageNum() : 0;
+ nPageNumber++;
+ nPageNumber >>= 1;
+ rValue <<= nPageNumber;
+ }
+ break;
+ }
+
+ case OWN_ATTR_UINAME_SINGULAR:
+ {
+ rValue <<= GetSdrObject()->TakeObjNameSingul();
+ break;
+ }
+
+ case OWN_ATTR_TEXTFITTOSIZESCALE:
+ {
+ rValue <<= GetTextFitToSizeScale(GetSdrObject());
+ break;
+ }
+
+ case OWN_ATTR_UINAME_PLURAL:
+ {
+ rValue <<= GetSdrObject()->TakeObjNamePlural();
+ break;
+ }
+ case OWN_ATTR_METAFILE:
+ {
+ SdrOle2Obj* pObj = dynamic_cast<SdrOle2Obj*>(GetSdrObject());
+ if( pObj )
+ {
+ const Graphic* pGraphic = pObj->GetGraphic();
+ if( pGraphic )
+ {
+ bool bIsWMF = false;
+ if ( pGraphic->IsGfxLink() )
+ {
+ GfxLink aLnk = pGraphic->GetGfxLink();
+ if ( aLnk.GetType() == GfxLinkType::NativeWmf )
+ {
+ bIsWMF = true;
+ uno::Sequence<sal_Int8> aSeq(reinterpret_cast<sal_Int8 const *>(aLnk.GetData()), static_cast<sal_Int32>(aLnk.GetDataSize()));
+ rValue <<= aSeq;
+ }
+ }
+ if ( !bIsWMF )
+ {
+ // #119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
+ GDIMetaFile aMtf(pObj->GetGraphic()->GetGDIMetaFile());
+ SvMemoryStream aDestStrm( 65535, 65535 );
+ ConvertGDIMetaFileToWMF( aMtf, aDestStrm, nullptr, false );
+ const uno::Sequence<sal_Int8> aSeq(
+ static_cast< const sal_Int8* >(aDestStrm.GetData()),
+ aDestStrm.GetEndOfData());
+ rValue <<= aSeq;
+ }
+ }
+ }
+ else
+ {
+ rValue = GetBitmap( true );
+ }
+ break;
+ }
+
+ case OWN_ATTR_TEXTCOLUMNS:
+ {
+ if (auto pTextObj = dynamic_cast<const SdrTextObj*>(GetSdrObject()))
+ {
+ if (pTextObj->HasTextColumnsNumber() || pTextObj->HasTextColumnsSpacing())
+ {
+ auto xIf = SvxXTextColumns_createInstance();
+ css::uno::Reference<css::text::XTextColumns> xCols(xIf, css::uno::UNO_QUERY_THROW);
+ xCols->setColumnCount(pTextObj->GetTextColumnsNumber());
+ css::uno::Reference<css::beans::XPropertySet> xProp(xIf, css::uno::UNO_QUERY_THROW);
+ xProp->setPropertyValue("AutomaticDistance",
+ css::uno::Any(pTextObj->GetTextColumnsSpacing()));
+ rValue <<= xIf;
+ }
+ }
+ break;
+ }
+
+ case OWN_ATTR_HYPERLINK:
+ {
+ rValue <<= GetSdrObject()->getHyperlink();
+ break;
+ }
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool SvxShape::getPropertyStateImpl( const SfxItemPropertyMapEntry* pProperty, css::beans::PropertyState& rState )
+{
+ if( pProperty->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ const SfxItemSet& rSet = GetSdrObject()->GetMergedItemSet();
+
+ if( rSet.GetItemState( XATTR_FILLBMP_STRETCH, false ) == SfxItemState::SET ||
+ rSet.GetItemState( XATTR_FILLBMP_TILE, false ) == SfxItemState::SET )
+ {
+ rState = beans::PropertyState_DIRECT_VALUE;
+ }
+ else
+ {
+ rState = beans::PropertyState_AMBIGUOUS_VALUE;
+ }
+ }
+ else if((( pProperty->nWID >= OWN_ATTR_VALUE_START && pProperty->nWID <= OWN_ATTR_VALUE_END ) ||
+ ( pProperty->nWID >= SDRATTR_NOTPERSIST_FIRST && pProperty->nWID <= SDRATTR_NOTPERSIST_LAST )) && ( pProperty->nWID != SDRATTR_TEXTDIRECTION ) )
+ {
+ rState = beans::PropertyState_DIRECT_VALUE;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+bool SvxShape::setPropertyToDefaultImpl( const SfxItemPropertyMapEntry* pProperty )
+{
+ if( pProperty->nWID == OWN_ATTR_FILLBMP_MODE )
+ {
+ GetSdrObject()->ClearMergedItem( XATTR_FILLBMP_STRETCH );
+ GetSdrObject()->ClearMergedItem( XATTR_FILLBMP_TILE );
+ return true;
+ }
+ else if((pProperty->nWID >= OWN_ATTR_VALUE_START && pProperty->nWID <= OWN_ATTR_VALUE_END ) ||
+ ( pProperty->nWID >= SDRATTR_NOTPERSIST_FIRST && pProperty->nWID <= SDRATTR_NOTPERSIST_LAST ))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+uno::Sequence< beans::PropertyState > SAL_CALL SvxShape::getPropertyStates( const uno::Sequence< OUString >& aPropertyName )
+{
+ const sal_Int32 nCount = aPropertyName.getLength();
+ uno::Sequence< beans::PropertyState > aRet( nCount );
+
+ std::transform(aPropertyName.begin(), aPropertyName.end(), aRet.getArray(),
+ [this](const OUString& rName) -> beans::PropertyState { return getPropertyState(rName); });
+
+ return aRet;
+}
+
+
+void SAL_CALL SvxShape::setPropertyToDefault( const OUString& PropertyName )
+{
+ if( mpImpl->mpMaster )
+ {
+ mpImpl->mpMaster->setPropertyToDefault( PropertyName );
+ }
+ else
+ {
+ _setPropertyToDefault( PropertyName );
+ }
+}
+
+void SvxShape::_setPropertyToDefault( const OUString& PropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pProperty = mpPropSet->getPropertyMapEntry(PropertyName);
+
+ if( !HasSdrObject() || pProperty == nullptr )
+ throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
+
+ if( !setPropertyToDefaultImpl( pProperty ) )
+ {
+ GetSdrObject()->ClearMergedItem( pProperty->nWID );
+ }
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+
+uno::Any SAL_CALL SvxShape::getPropertyDefault( const OUString& aPropertyName )
+{
+ if( mpImpl->mpMaster )
+ {
+ return mpImpl->mpMaster->getPropertyDefault( aPropertyName );
+ }
+ else
+ {
+ return _getPropertyDefault( aPropertyName );
+ }
+}
+
+uno::Any SvxShape::_getPropertyDefault( const OUString& aPropertyName )
+{
+ ::SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(aPropertyName);
+
+ if( !HasSdrObject() || pMap == nullptr )
+ throw beans::UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
+
+ if(( pMap->nWID >= OWN_ATTR_VALUE_START && pMap->nWID <= OWN_ATTR_VALUE_END ) ||
+ ( pMap->nWID >= SDRATTR_NOTPERSIST_FIRST && pMap->nWID <= SDRATTR_NOTPERSIST_LAST ))
+ {
+ return getPropertyValue( aPropertyName );
+ }
+
+ // get default from ItemPool
+ if(!SfxItemPool::IsWhich(pMap->nWID))
+ throw beans::UnknownPropertyException( "No WhichID " + OUString::number(pMap->nWID) + " for " + aPropertyName, static_cast<cppu::OWeakObject*>(this));
+
+ SfxItemSet aSet( GetSdrObject()->getSdrModelFromSdrObject().GetItemPool(), pMap->nWID, pMap->nWID );
+ aSet.Put(GetSdrObject()->getSdrModelFromSdrObject().GetItemPool().GetDefaultItem(pMap->nWID));
+
+ return GetAnyForItem( aSet, pMap );
+}
+
+// XMultiPropertyStates
+void SvxShape::setAllPropertiesToDefault()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( !HasSdrObject() )
+ throw lang::DisposedException();
+ GetSdrObject()->ClearMergedItem(); // nWhich == 0 => all
+
+ if(dynamic_cast<const SdrGrafObj*>(GetSdrObject()) != nullptr)
+ {
+ // defaults for graphic objects have changed:
+ GetSdrObject()->SetMergedItem( XFillStyleItem( drawing::FillStyle_NONE ) );
+ GetSdrObject()->SetMergedItem( XLineStyleItem( drawing::LineStyle_NONE ) );
+ }
+
+ // #i68523# special handling for Svx3DCharacterModeItem, this is not saved
+ // but needs to be sal_True in svx, pool default (false) in sch. Since sch
+ // does not load lathe or extrude objects, it is possible to set the items
+ // here.
+ // For other solution possibilities, see task description.
+ if( dynamic_cast<const E3dLatheObj* >(GetSdrObject()) != nullptr|| dynamic_cast<const E3dExtrudeObj* >(GetSdrObject()) != nullptr)
+ {
+ GetSdrObject()->SetMergedItem(Svx3DCharacterModeItem(true));
+ }
+
+ GetSdrObject()->getSdrModelFromSdrObject().SetChanged();
+}
+
+void SvxShape::setPropertiesToDefault(
+ const uno::Sequence<OUString>& aPropertyNames )
+{
+ for ( const auto& rPropertyName : aPropertyNames )
+ setPropertyToDefault( rPropertyName );
+}
+
+uno::Sequence<uno::Any> SvxShape::getPropertyDefaults(
+ const uno::Sequence<OUString>& aPropertyNames )
+{
+ ::std::vector<uno::Any> ret;
+ ret.reserve(aPropertyNames.getLength());
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), std::back_inserter(ret),
+ [this](const OUString& rName) -> uno::Any { return getPropertyDefault(rName); });
+ return uno::Sequence<uno::Any>( ret.data(), ret.size() );
+}
+
+
+// XServiceInfo
+
+OUString SAL_CALL SvxShape::getImplementationName()
+{
+ return "SvxShape";
+}
+
+constexpr OUStringLiteral sUNO_service_style_ParagraphProperties = u"com.sun.star.style.ParagraphProperties";
+constexpr OUStringLiteral sUNO_service_style_ParagraphPropertiesComplex = u"com.sun.star.style.ParagraphPropertiesComplex";
+constexpr OUStringLiteral sUNO_service_style_ParagraphPropertiesAsian = u"com.sun.star.style.ParagraphPropertiesAsian";
+constexpr OUStringLiteral sUNO_service_style_CharacterProperties = u"com.sun.star.style.CharacterProperties";
+constexpr OUStringLiteral sUNO_service_style_CharacterPropertiesComplex = u"com.sun.star.style.CharacterPropertiesComplex";
+constexpr OUStringLiteral sUNO_service_style_CharacterPropertiesAsian = u"com.sun.star.style.CharacterPropertiesAsian";
+
+constexpr OUStringLiteral sUNO_service_drawing_FillProperties = u"com.sun.star.drawing.FillProperties";
+constexpr OUStringLiteral sUNO_service_drawing_TextProperties = u"com.sun.star.drawing.TextProperties";
+constexpr OUStringLiteral sUNO_service_drawing_LineProperties = u"com.sun.star.drawing.LineProperties";
+constexpr OUStringLiteral sUNO_service_drawing_ConnectorProperties = u"com.sun.star.drawing.ConnectorProperties";
+constexpr OUStringLiteral sUNO_service_drawing_MeasureProperties = u"com.sun.star.drawing.MeasureProperties";
+constexpr OUStringLiteral sUNO_service_drawing_ShadowProperties = u"com.sun.star.drawing.ShadowProperties";
+
+constexpr OUStringLiteral sUNO_service_drawing_RotationDescriptor = u"com.sun.star.drawing.RotationDescriptor";
+
+constexpr OUStringLiteral sUNO_service_drawing_Text = u"com.sun.star.drawing.Text";
+constexpr OUStringLiteral sUNO_service_drawing_GroupShape = u"com.sun.star.drawing.GroupShape";
+
+constexpr OUStringLiteral sUNO_service_drawing_CustomShapeProperties = u"com.sun.star.drawing.CustomShapeProperties";
+constexpr OUStringLiteral sUNO_service_drawing_CustomShape = u"com.sun.star.drawing.CustomShape";
+
+constexpr OUStringLiteral sUNO_service_drawing_PolyPolygonDescriptor = u"com.sun.star.drawing.PolyPolygonDescriptor";
+constexpr OUStringLiteral sUNO_service_drawing_PolyPolygonBezierDescriptor= u"com.sun.star.drawing.PolyPolygonBezierDescriptor";
+
+constexpr OUStringLiteral sUNO_service_drawing_LineShape = u"com.sun.star.drawing.LineShape";
+constexpr OUStringLiteral sUNO_service_drawing_Shape = u"com.sun.star.drawing.Shape";
+constexpr OUStringLiteral sUNO_service_drawing_RectangleShape = u"com.sun.star.drawing.RectangleShape";
+constexpr OUStringLiteral sUNO_service_drawing_EllipseShape = u"com.sun.star.drawing.EllipseShape";
+constexpr OUStringLiteral sUNO_service_drawing_PolyPolygonShape = u"com.sun.star.drawing.PolyPolygonShape";
+constexpr OUStringLiteral sUNO_service_drawing_PolyLineShape = u"com.sun.star.drawing.PolyLineShape";
+constexpr OUStringLiteral sUNO_service_drawing_OpenBezierShape = u"com.sun.star.drawing.OpenBezierShape";
+constexpr OUStringLiteral sUNO_service_drawing_ClosedBezierShape = u"com.sun.star.drawing.ClosedBezierShape";
+constexpr OUStringLiteral sUNO_service_drawing_TextShape = u"com.sun.star.drawing.TextShape";
+constexpr OUStringLiteral sUNO_service_drawing_GraphicObjectShape = u"com.sun.star.drawing.GraphicObjectShape";
+constexpr OUStringLiteral sUNO_service_drawing_OLE2Shape = u"com.sun.star.drawing.OLE2Shape";
+constexpr OUStringLiteral sUNO_service_drawing_PageShape = u"com.sun.star.drawing.PageShape";
+constexpr OUStringLiteral sUNO_service_drawing_CaptionShape = u"com.sun.star.drawing.CaptionShape";
+constexpr OUStringLiteral sUNO_service_drawing_MeasureShape = u"com.sun.star.drawing.MeasureShape";
+constexpr OUStringLiteral sUNO_service_drawing_FrameShape = u"com.sun.star.drawing.FrameShape";
+constexpr OUStringLiteral sUNO_service_drawing_ControlShape = u"com.sun.star.drawing.ControlShape";
+constexpr OUStringLiteral sUNO_service_drawing_ConnectorShape = u"com.sun.star.drawing.ConnectorShape";
+constexpr OUStringLiteral sUNO_service_drawing_MediaShape = u"com.sun.star.drawing.MediaShape";
+
+
+uno::Sequence< OUString > SAL_CALL SvxShape::getSupportedServiceNames()
+{
+ if( mpImpl->mpMaster )
+ {
+ return mpImpl->mpMaster->getSupportedServiceNames();
+ }
+ else
+ {
+ return _getSupportedServiceNames();
+ }
+}
+
+uno::Sequence< OUString > SvxShape::_getSupportedServiceNames()
+{
+ ::SolarMutexGuard aGuard;
+
+ if( HasSdrObject() && GetSdrObject()->GetObjInventor() == SdrInventor::Default)
+ {
+ const SdrObjKind nIdent = GetSdrObject()->GetObjIdentifier();
+
+ switch(nIdent)
+ {
+ case SdrObjKind::Group:
+ {
+ static const uno::Sequence<OUString> aSvxShape_GroupServices
+ = { sUNO_service_drawing_GroupShape,
+ sUNO_service_drawing_Shape };
+ return aSvxShape_GroupServices;
+ }
+ case SdrObjKind::CustomShape:
+ {
+ static const uno::Sequence<OUString> aSvxShape_CustomShapeServices
+ = { sUNO_service_drawing_CustomShape,
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_CustomShapeProperties,
+ sUNO_service_drawing_FillProperties,
+ sUNO_service_drawing_LineProperties,
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_CustomShapeServices;
+ }
+ case SdrObjKind::Line:
+ {
+ static const uno::Sequence<OUString> aSvxShape_LineServices
+ = { sUNO_service_drawing_LineShape,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_LineProperties,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_PolyPolygonDescriptor,
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_LineServices;
+ }
+
+ case SdrObjKind::Rectangle:
+ {
+ static const uno::Sequence<OUString> aSvxShape_RectServices
+ = { sUNO_service_drawing_RectangleShape,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_FillProperties,
+ sUNO_service_drawing_LineProperties,
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_RectServices;
+ }
+
+ case SdrObjKind::CircleOrEllipse:
+ case SdrObjKind::CircleSection:
+ case SdrObjKind::CircleArc:
+ case SdrObjKind::CircleCut:
+ {
+ static const uno::Sequence<OUString> aSvxShape_CircServices
+ = { sUNO_service_drawing_EllipseShape,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_FillProperties,
+ sUNO_service_drawing_LineProperties,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_CircServices;
+ }
+
+ case SdrObjKind::PathPolyLine:
+ case SdrObjKind::PolyLine:
+ {
+ static const uno::Sequence<OUString> aSvxShape_PathServices
+ = { sUNO_service_drawing_PolyLineShape,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_LineProperties,
+
+ sUNO_service_drawing_PolyPolygonDescriptor,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_PathServices;
+ }
+
+ case SdrObjKind::PathPoly:
+ case SdrObjKind::Polygon:
+ {
+ static const uno::Sequence<OUString> aSvxShape_PolyServices
+ = { sUNO_service_drawing_PolyPolygonShape,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_LineProperties,
+ sUNO_service_drawing_FillProperties,
+
+ sUNO_service_drawing_PolyPolygonDescriptor,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_PolyServices;
+ }
+
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::PathLine:
+ {
+ static const uno::Sequence<OUString> aSvxShape_FreeLineServices
+ = { sUNO_service_drawing_OpenBezierShape,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_LineProperties,
+ sUNO_service_drawing_FillProperties,
+
+ sUNO_service_drawing_PolyPolygonBezierDescriptor,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_FreeLineServices;
+ }
+
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathFill:
+ {
+ static const uno::Sequence<OUString> aSvxShape_FreeFillServices
+ = { sUNO_service_drawing_ClosedBezierShape,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_LineProperties,
+ sUNO_service_drawing_FillProperties,
+
+ sUNO_service_drawing_PolyPolygonBezierDescriptor,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_FreeFillServices;
+ }
+
+ case SdrObjKind::OutlineText:
+ case SdrObjKind::TitleText:
+ case SdrObjKind::Text:
+ {
+ static const uno::Sequence<OUString> aSvxShape_TextServices
+ = { sUNO_service_drawing_TextShape,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_FillProperties,
+ sUNO_service_drawing_LineProperties,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_TextServices;
+ }
+
+ case SdrObjKind::Graphic:
+ {
+ static const uno::Sequence<OUString> aSvxShape_GrafServices
+ = { sUNO_service_drawing_GraphicObjectShape,
+
+ sUNO_service_drawing_Shape,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor};
+ return aSvxShape_GrafServices;
+ }
+
+ case SdrObjKind::OLE2:
+ {
+ static const uno::Sequence<OUString> aSvxShape_Ole2Services
+ = { sUNO_service_drawing_OLE2Shape,
+ sUNO_service_drawing_Shape,
+
+ // #i118485# Added Text, Shadow and Rotation
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_Ole2Services;
+ }
+
+ case SdrObjKind::Caption:
+ {
+ static const uno::Sequence<OUString> aSvxShape_CaptionServices
+ = { sUNO_service_drawing_CaptionShape,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_FillProperties,
+ sUNO_service_drawing_LineProperties,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_CaptionServices;
+ }
+
+ case SdrObjKind::Page:
+ {
+ static const uno::Sequence<OUString> aSvxShape_PageServices
+ = { sUNO_service_drawing_PageShape,
+ sUNO_service_drawing_Shape };
+ return aSvxShape_PageServices;
+ }
+
+ case SdrObjKind::Measure:
+ {
+ static const uno::Sequence<OUString> aSvxShape_MeasureServices
+ = { sUNO_service_drawing_MeasureShape,
+
+ sUNO_service_drawing_MeasureProperties,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_LineProperties,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_PolyPolygonDescriptor,
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_MeasureServices;
+ }
+
+ case SdrObjKind::OLEPluginFrame:
+ {
+ static const uno::Sequence<OUString> aSvxShape_FrameServices
+ = { sUNO_service_drawing_FrameShape,
+ sUNO_service_drawing_Shape };
+ return aSvxShape_FrameServices;
+ }
+
+ case SdrObjKind::UNO:
+ {
+ static const uno::Sequence<OUString> aSvxShape_UnoServices
+ = { sUNO_service_drawing_ControlShape,
+ sUNO_service_drawing_Shape };
+ return aSvxShape_UnoServices;
+ }
+
+ case SdrObjKind::Edge:
+ {
+ static const uno::Sequence<OUString> aSvxShape_EdgeServices
+ = { sUNO_service_drawing_ConnectorShape,
+ sUNO_service_drawing_ConnectorProperties,
+
+ sUNO_service_drawing_Shape,
+ sUNO_service_drawing_LineProperties,
+
+ sUNO_service_drawing_Text,
+ sUNO_service_drawing_TextProperties,
+ sUNO_service_style_ParagraphProperties,
+ sUNO_service_style_ParagraphPropertiesComplex,
+ sUNO_service_style_ParagraphPropertiesAsian,
+ sUNO_service_style_CharacterProperties,
+ sUNO_service_style_CharacterPropertiesComplex,
+ sUNO_service_style_CharacterPropertiesAsian,
+
+ sUNO_service_drawing_PolyPolygonDescriptor,
+ sUNO_service_drawing_ShadowProperties,
+ sUNO_service_drawing_RotationDescriptor };
+ return aSvxShape_EdgeServices;
+ }
+ case SdrObjKind::Media:
+ {
+ static const uno::Sequence<OUString> aSvxShape_MediaServices
+ = { sUNO_service_drawing_MediaShape,
+ sUNO_service_drawing_Shape };
+ return aSvxShape_MediaServices;
+ }
+ default: ;
+ }
+ }
+ else if( HasSdrObject() && GetSdrObject()->GetObjInventor() == SdrInventor::FmForm)
+ {
+#if OSL_DEBUG_LEVEL > 0
+ const SdrObjKind nIdent = GetSdrObject()->GetObjIdentifier();
+ OSL_ENSURE( nIdent == SdrObjKind::UNO, "SvxShape::_getSupportedServiceNames: SdrInventor::FmForm, but no UNO object?" );
+#endif
+ static const uno::Sequence<OUString> aSvxShape_UnoServices
+ = { sUNO_service_drawing_ControlShape,
+ sUNO_service_drawing_Shape };
+ return aSvxShape_UnoServices;
+ }
+ OSL_FAIL( "SvxShape::_getSupportedServiceNames: could not determine object type!" );
+ uno::Sequence< OUString > aSeq;
+ return aSeq;
+}
+
+sal_Bool SAL_CALL SvxShape::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XGluePointsSupplier
+uno::Reference< container::XIndexContainer > SAL_CALL SvxShape::getGluePoints()
+{
+ ::SolarMutexGuard aGuard;
+ uno::Reference< container::XIndexContainer > xGluePoints( mxGluePoints );
+
+ if( HasSdrObject() && !xGluePoints.is() )
+ {
+ uno::Reference< container::XIndexContainer > xNew( SvxUnoGluePointAccess_createInstance( GetSdrObject() ), uno::UNO_QUERY );
+ mxGluePoints = xGluePoints = xNew;
+ }
+
+ return xGluePoints;
+}
+
+// XChild
+uno::Reference<uno::XInterface> SAL_CALL SvxShape::getParent()
+{
+ ::SolarMutexGuard aGuard;
+ const SdrObject* pSdrObject(GetSdrObject());
+
+ if(nullptr != pSdrObject)
+ {
+ const SdrObjList* pParentSdrObjList(GetSdrObject()->getParentSdrObjListFromSdrObject());
+
+ if(nullptr != pParentSdrObjList)
+ {
+ // SdrObject is member of a SdrObjList. That may be a SdrObject
+ // (SdrObjGroup or E3dScene) or a SdrPage.
+ // Check for SdrObject first - using getSdrPageFromSdrObjList
+ // *will* get the SdrPage even when the SdrObject is deep buried
+ // in a construct of SdrObjGroup.
+ // We want to ask for the direct parent here...
+ SdrObject* pParentSdrObject(pParentSdrObjList->getSdrObjectFromSdrObjList());
+
+ if(nullptr != pParentSdrObject)
+ {
+ // SdrObject is member of a SdrObject-based Group (SdrObjGroup or E3dScene).
+ return pParentSdrObject->getUnoShape();
+ }
+ else
+ {
+ SdrPage* pParentSdrPage(pParentSdrObjList->getSdrPageFromSdrObjList());
+
+ if(nullptr != pParentSdrPage)
+ {
+ // SdrObject is inserted to a SdrPage. Since
+ // we checked for getSdrObjectFromSdrObjList first,
+ // we can even say that it is directly member of that
+ // SdrPage.
+ return pParentSdrPage->getUnoPage();
+ }
+ }
+
+ // not member of any SdrObjList, no parent
+ OSL_FAIL( "SvxShape::getParent( ): unexpected Parent SdrObjList" );
+ }
+ }
+
+ // no SdrObject, no parent
+ return uno::Reference<uno::XInterface>();
+}
+
+void SAL_CALL SvxShape::setParent( const css::uno::Reference< css::uno::XInterface >& )
+{
+ throw lang::NoSupportException();
+}
+
+
+/** called from the XActionLockable interface methods on initial locking */
+void SvxShape::lock()
+{
+}
+
+
+/** called from the XActionLockable interface methods on final unlock */
+void SvxShape::unlock()
+{
+}
+
+
+// XActionLockable
+sal_Bool SAL_CALL SvxShape::isActionLocked( )
+{
+ ::SolarMutexGuard aGuard;
+
+ return mnLockCount != 0;
+}
+
+
+void SAL_CALL SvxShape::addActionLock( )
+{
+ ::SolarMutexGuard aGuard;
+
+ DBG_ASSERT( mnLockCount < 0xffff, "lock overflow in SvxShape!" );
+ mnLockCount++;
+
+ if( mnLockCount == 1 )
+ lock();
+}
+
+
+void SAL_CALL SvxShape::removeActionLock( )
+{
+ ::SolarMutexGuard aGuard;
+
+ DBG_ASSERT( mnLockCount > 0, "lock underflow in SvxShape!" );
+ mnLockCount--;
+
+ if( mnLockCount == 0 )
+ unlock();
+}
+
+
+void SAL_CALL SvxShape::setActionLocks( sal_Int16 nLock )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( (mnLockCount == 0) && (nLock != 0) )
+ unlock();
+
+ if( (mnLockCount != 0) && (nLock == 0) )
+ lock();
+
+ mnLockCount = static_cast<sal_uInt16>(nLock);
+}
+
+
+sal_Int16 SAL_CALL SvxShape::resetActionLocks( )
+{
+ ::SolarMutexGuard aGuard;
+
+ if( mnLockCount != 0 )
+ unlock();
+
+ sal_Int16 nOldLocks = static_cast<sal_Int16>(mnLockCount);
+ mnLockCount = 0;
+
+ return nOldLocks;
+}
+
+
+/** since polygon shapes can change their kind during editing, we have
+ to recheck it here.
+ Circle shapes also change their kind, but they are all treated equal
+ so no update is necessary.
+*/
+void SvxShape::updateShapeKind()
+{
+ switch( mpImpl->mnObjId )
+ {
+ case SdrObjKind::Line:
+ case SdrObjKind::Polygon:
+ case SdrObjKind::PolyLine:
+ case SdrObjKind::PathLine:
+ case SdrObjKind::PathFill:
+ case SdrObjKind::FreehandLine:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathPoly:
+ case SdrObjKind::PathPolyLine:
+ {
+ const SdrObjKind nId = GetSdrObject()->GetObjIdentifier();
+
+ if( nId != mpImpl->mnObjId )
+ {
+ mpImpl->mnObjId = nId;
+
+ }
+ break;
+ }
+ default: ;
+ }
+}
+
+SvxShapeText::SvxShapeText(SdrObject* pObject)
+: SvxShape( pObject, getSvxMapProvider().GetMap(SVXMAP_TEXT), getSvxMapProvider().GetPropertySet(SVXMAP_TEXT, SdrObject::GetGlobalDrawObjectItemPool()) ), SvxUnoTextBase( ImplGetSvxUnoOutlinerTextCursorSvxPropertySet() )
+{
+ if( pObject )
+ SetEditSource( new SvxTextEditSource( pObject, nullptr ) );
+}
+
+
+SvxShapeText::SvxShapeText(SdrObject* pObject, const SfxItemPropertyMapEntry* pPropertyMap, const SvxItemPropertySet* pPropertySet)
+: SvxShape( pObject, pPropertyMap, pPropertySet ), SvxUnoTextBase( ImplGetSvxUnoOutlinerTextCursorSvxPropertySet() )
+{
+ if( pObject )
+ SetEditSource( new SvxTextEditSource( pObject, nullptr ) );
+}
+
+
+SvxShapeText::~SvxShapeText() noexcept
+{
+ // check if only this instance is registered at the ranges
+ DBG_ASSERT( (nullptr == GetEditSource()) || (GetEditSource()->getRanges().size()==1),
+ "svx::SvxShapeText::~SvxShapeText(), text shape with living text ranges destroyed!");
+}
+
+void SvxShapeText::Create( SdrObject* pNewObj, SvxDrawPage* pNewPage )
+{
+ if( pNewObj && (nullptr == GetEditSource()))
+ SetEditSource( new SvxTextEditSource( pNewObj, nullptr ) );
+ SvxShape::Create( pNewObj, pNewPage );
+}
+
+// XInterface
+
+uno::Any SAL_CALL SvxShapeText::queryInterface( const uno::Type & rType )
+{
+ return SvxShape::queryInterface( rType );
+}
+
+
+uno::Any SAL_CALL SvxShapeText::queryAggregation( const uno::Type & rType )
+{
+ uno::Any aAny( SvxShape::queryAggregation( rType ) );
+ if( aAny.hasValue() )
+ return aAny;
+
+ return SvxUnoTextBase::queryAggregation( rType );
+}
+
+
+// XServiceInfo
+
+OUString SAL_CALL SvxShapeText::getImplementationName()
+{
+ return "SvxShapeText";
+}
+
+
+uno::Sequence< OUString > SAL_CALL SvxShapeText::getSupportedServiceNames()
+{
+ return SvxShape::getSupportedServiceNames();
+}
+
+
+sal_Bool SAL_CALL SvxShapeText::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(static_cast<SvxShape*>(this), ServiceName);
+}
+
+ // XTypeProvider
+
+uno::Sequence< uno::Type > SAL_CALL SvxShapeText::getTypes()
+{
+ return SvxShape::getTypes();
+}
+
+sal_Int64 SAL_CALL SvxShapeText::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ const sal_Int64 nReturn = SvxShape::getSomething( rId );
+ if( nReturn )
+ return nReturn;
+
+ return SvxUnoTextBase::getSomething( rId );
+}
+
+
+uno::Sequence< sal_Int8 > SAL_CALL SvxShapeText::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+
+/** called from the XActionLockable interface methods on initial locking */
+void SvxShapeText::lock()
+{
+ SvxTextEditSource* pEditSource = static_cast<SvxTextEditSource*>(GetEditSource());
+ if( pEditSource )
+ pEditSource->lock();
+}
+
+
+/** called from the XActionLockable interface methods on final unlock */
+void SvxShapeText::unlock()
+{
+ SvxTextEditSource* pEditSource = static_cast<SvxTextEditSource*>(GetEditSource());
+ if( pEditSource )
+ pEditSource->unlock();
+}
+
+// css::text::XTextRange
+uno::Reference< text::XTextRange > SAL_CALL SvxShapeText::getStart()
+{
+ ::SolarMutexGuard aGuard;
+ SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr;
+ if( pForwarder )
+ ::GetSelection( maSelection, pForwarder );
+ return SvxUnoTextBase::getStart();
+
+}
+
+uno::Reference< text::XTextRange > SAL_CALL SvxShapeText::getEnd()
+{
+ ::SolarMutexGuard aGuard;
+ SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr;
+ if( pForwarder )
+ ::GetSelection( maSelection, pForwarder );
+ return SvxUnoTextBase::getEnd();
+}
+
+OUString SAL_CALL SvxShapeText::getString()
+{
+ ::SolarMutexGuard aGuard;
+ SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr;
+ if( pForwarder )
+ ::GetSelection( maSelection, pForwarder );
+ return SvxUnoTextBase::getString();
+}
+
+
+void SAL_CALL SvxShapeText::setString( const OUString& aString )
+{
+ ::SolarMutexGuard aGuard;
+ SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr;
+ if( pForwarder )
+ ::GetSelection( maSelection, pForwarder );
+ SvxUnoTextBase::setString( aString );
+}
+
+// override these for special property handling in subcasses. Return true if property is handled
+bool SvxShapeText::setPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, const css::uno::Any& rValue )
+{
+ // HACK-fix #99090#
+ // since SdrTextObj::SetVerticalWriting exchanges
+ // SDRATTR_TEXT_AUTOGROWWIDTH and SDRATTR_TEXT_AUTOGROWHEIGHT,
+ // we have to set the textdirection here
+
+ if( pProperty->nWID == SDRATTR_TEXTDIRECTION )
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( GetSdrObject() );
+ if( pTextObj )
+ {
+ css::text::WritingMode eMode;
+ if( rValue >>= eMode )
+ {
+ pTextObj->SetVerticalWriting( eMode == css::text::WritingMode_TB_RL );
+ }
+ }
+ return true;
+ }
+ return SvxShape::setPropertyValueImpl( rName, pProperty, rValue );
+}
+
+bool SvxShapeText::getPropertyValueImpl( const OUString& rName, const SfxItemPropertyMapEntry* pProperty, css::uno::Any& rValue )
+{
+ if( pProperty->nWID == SDRATTR_TEXTDIRECTION )
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( GetSdrObject() );
+ if( pTextObj && pTextObj->IsVerticalWriting() )
+ rValue <<= css::text::WritingMode_TB_RL;
+ else
+ rValue <<= css::text::WritingMode_LR_TB;
+ return true;
+ }
+
+ return SvxShape::getPropertyValueImpl( rName, pProperty, rValue );
+}
+
+bool SvxShapeText::getPropertyStateImpl( const SfxItemPropertyMapEntry* pProperty, css::beans::PropertyState& rState )
+{
+ return SvxShape::getPropertyStateImpl( pProperty, rState );
+}
+
+bool SvxShapeText::setPropertyToDefaultImpl( const SfxItemPropertyMapEntry* pProperty )
+{
+ return SvxShape::setPropertyToDefaultImpl( pProperty );
+}
+
+SvxShapeRect::SvxShapeRect(SdrObject* pObj)
+: SvxShapeText( pObj, getSvxMapProvider().GetMap(SVXMAP_SHAPE), getSvxMapProvider().GetPropertySet(SVXMAP_SHAPE, SdrObject::GetGlobalDrawObjectItemPool()))
+{
+}
+
+SvxShapeRect::~SvxShapeRect() noexcept
+{
+}
+
+uno::Any SAL_CALL SvxShapeRect::queryInterface( const uno::Type & rType )
+{
+ return SvxShapeText::queryInterface( rType );
+}
+
+uno::Any SAL_CALL SvxShapeRect::queryAggregation( const uno::Type & rType )
+{
+ return SvxShapeText::queryAggregation( rType );
+}
+
+// XServiceInfo
+
+uno::Sequence< OUString > SvxShapeRect::getSupportedServiceNames()
+{
+ return SvxShape::getSupportedServiceNames();
+}
+
+/** returns a StarOffice API wrapper for the given SdrObject */
+uno::Reference< drawing::XShape > GetXShapeForSdrObject( SdrObject* pObj ) noexcept
+{
+ uno::Reference< drawing::XShape > xShape( pObj->getUnoShape(), uno::UNO_QUERY );
+ return xShape;
+}
+
+
+SdrObject* SdrObject::getSdrObjectFromXShape( const css::uno::Reference< css::uno::XInterface >& xInt )
+{
+ SvxShape* pSvxShape = comphelper::getFromUnoTunnel<SvxShape>( xInt );
+ return pSvxShape ? pSvxShape->GetSdrObject() : nullptr;
+}
+
+uno::Any SvxItemPropertySet_getPropertyValue( const SfxItemPropertyMapEntry* pMap, const SfxItemSet& rSet )
+{
+ if(!pMap || !pMap->nWID)
+ return uno::Any();
+
+ // Check is for items that store either metric values if they are positive or percentage if they are negative.
+ bool bDontConvertNegativeValues = ( pMap->nWID == XATTR_FILLBMP_SIZEX || pMap->nWID == XATTR_FILLBMP_SIZEY );
+ return SvxItemPropertySet::getPropertyValue( pMap, rSet, (pMap->nWID != SDRATTR_XMLATTRIBUTES), bDontConvertNegativeValues );
+}
+
+void SvxItemPropertySet_setPropertyValue( const SfxItemPropertyMapEntry* pMap, const uno::Any& rVal, SfxItemSet& rSet )
+{
+ if(!pMap || !pMap->nWID)
+ return;
+
+ bool bDontConvertNegativeValues = ( pMap->nWID == XATTR_FILLBMP_SIZEX || pMap->nWID == XATTR_FILLBMP_SIZEY );
+ SvxItemPropertySet::setPropertyValue( pMap, rVal, rSet, bDontConvertNegativeValues );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unoshcol.cxx b/svx/source/unodraw/unoshcol.cxx
new file mode 100644
index 000000000..105ca6523
--- /dev/null
+++ b/svx/source/unodraw/unoshcol.cxx
@@ -0,0 +1,252 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/document/EventObject.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <cppuhelper/interfacecontainer.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <osl/mutex.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+class SvxShapeCollection :
+ public cppu::BaseMutex,
+ public cppu::WeakAggImplHelper3<drawing::XShapes, lang::XServiceInfo, lang::XComponent>
+{
+private:
+ comphelper::OInterfaceContainerHelper3<drawing::XShape> maShapeContainer;
+
+ cppu::OBroadcastHelper mrBHelper;
+
+public:
+ SvxShapeCollection() noexcept;
+
+ // XInterface
+ virtual void SAL_CALL release() noexcept override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override ;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XShapes
+ virtual void SAL_CALL add( const css::uno::Reference< css::drawing::XShape >& xShape ) override;
+ virtual void SAL_CALL remove( const css::uno::Reference< css::drawing::XShape >& xShape ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+SvxShapeCollection::SvxShapeCollection() noexcept
+: maShapeContainer( m_aMutex ), mrBHelper( m_aMutex )
+{
+}
+
+// XInterface
+void SvxShapeCollection::release() noexcept
+{
+ uno::Reference< uno::XInterface > x( xDelegator );
+ if (! x.is())
+ {
+ if (osl_atomic_decrement( &m_refCount ) == 0)
+ {
+ if (! mrBHelper.bDisposed)
+ {
+ uno::Reference< uno::XInterface > xHoldAlive( static_cast<uno::XWeak*>(this) );
+ // First dispose
+ try
+ {
+ dispose();
+ }
+ catch(css::uno::Exception&)
+ {
+ // release should not throw exceptions
+ }
+
+ // only the alive ref holds the object
+ OSL_ASSERT( m_refCount == 1 );
+ // destroy the object if xHoldAlive decrement the refcount to 0
+ return;
+ }
+ }
+ // restore the reference count
+ osl_atomic_increment( &m_refCount );
+ }
+ OWeakAggObject::release();
+}
+
+// XComponent
+void SvxShapeCollection::dispose()
+{
+ // An frequently programming error is to release the last
+ // reference to this object in the disposing message.
+ // Make it robust, hold a self Reference.
+ uno::Reference< lang::XComponent > xSelf( this );
+
+ // Guard dispose against multiple threading
+ // Remark: It is an error to call dispose more than once
+ bool bDoDispose = false;
+ {
+ osl::MutexGuard aGuard( mrBHelper.rMutex );
+ if( !mrBHelper.bDisposed && !mrBHelper.bInDispose )
+ {
+ // only one call go into this section
+ mrBHelper.bInDispose = true;
+ bDoDispose = true;
+ }
+ }
+
+ // Do not hold the mutex because we are broadcasting
+ if( bDoDispose )
+ {
+ // Create an event with this as sender
+ try
+ {
+ uno::Reference< uno::XInterface > xSource( uno::Reference< uno::XInterface >::query( static_cast<lang::XComponent *>(this) ) );
+ document::EventObject aEvt;
+ aEvt.Source = xSource;
+ // inform all listeners to release this object
+ // The listener container are automatically cleared
+ mrBHelper.aLC.disposeAndClear( aEvt );
+ maShapeContainer.clear();
+ }
+ catch(const css::uno::Exception&)
+ {
+ // catch exception and throw again but signal that
+ // the object was disposed. Dispose should be called
+ // only once.
+ mrBHelper.bDisposed = true;
+ mrBHelper.bInDispose = false;
+ throw;
+ }
+
+ // the values bDispose and bInDisposing must set in this order.
+ // No multithread call overcome the "!rBHelper.bDisposed && !rBHelper.bInDispose" guard.
+ mrBHelper.bDisposed = true;
+ mrBHelper.bInDispose = false;
+ }
+ else
+ {
+ // in a multithreaded environment, it can't be avoided, that dispose is called twice.
+ // However this condition is traced, because it MAY indicate an error.
+ SAL_INFO("svx", "dispose called twice" );
+ }
+}
+
+// XComponent
+void SAL_CALL SvxShapeCollection::addEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener )
+{
+ mrBHelper.addListener( cppu::UnoType<decltype(aListener)>::get() , aListener );
+}
+
+// XComponent
+void SAL_CALL SvxShapeCollection::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener )
+{
+ mrBHelper.removeListener( cppu::UnoType<decltype(aListener)>::get() , aListener );
+}
+
+// XShapes
+
+void SAL_CALL SvxShapeCollection::add( const Reference< drawing::XShape >& xShape )
+{
+ maShapeContainer.addInterface( xShape );
+}
+
+
+void SAL_CALL SvxShapeCollection::remove( const uno::Reference< drawing::XShape >& xShape )
+{
+ maShapeContainer.removeInterface( xShape );
+}
+
+
+sal_Int32 SAL_CALL SvxShapeCollection::getCount()
+{
+ return maShapeContainer.getLength();
+}
+
+
+uno::Any SAL_CALL SvxShapeCollection::getByIndex( sal_Int32 Index )
+{
+ if( Index < 0 || Index >= getCount() )
+ throw lang::IndexOutOfBoundsException();
+
+ Reference<drawing::XShape> xShape = maShapeContainer.getInterface(Index);
+ return uno::Any( xShape );
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxShapeCollection::getElementType()
+{
+ return cppu::UnoType<drawing::XShape>::get();
+}
+
+sal_Bool SAL_CALL SvxShapeCollection::hasElements()
+{
+ return getCount() != 0;
+}
+
+// XServiceInfo
+OUString SAL_CALL SvxShapeCollection::getImplementationName()
+{
+ return "com.sun.star.drawing.SvxShapeCollection";
+}
+
+sal_Bool SAL_CALL SvxShapeCollection::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL SvxShapeCollection::getSupportedServiceNames()
+{
+ return { "com.sun.star.drawing.Shapes", "com.sun.star.drawing.ShapeCollection" };
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_drawing_SvxShapeCollection_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SvxShapeCollection);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unoshtxt.cxx b/svx/source/unodraw/unoshtxt.cxx
new file mode 100644
index 000000000..71e63997e
--- /dev/null
+++ b/svx/source/unodraw/unoshtxt.cxx
@@ -0,0 +1,1009 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <vcl/svapp.hxx>
+
+#include <svx/unoshtxt.hxx>
+#include <editeng/unoedhlp.hxx>
+#include <svl/lstner.hxx>
+#include <rtl/ref.hxx>
+#include <tools/debug.hxx>
+#include <svl/hint.hxx>
+#include <svl/style.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdview.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/unoforou.hxx>
+#include <editeng/unoviwou.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdpage.hxx>
+#include <editeng/editeng.hxx>
+
+#include <editeng/unotext.hxx>
+#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
+#include <comphelper/processfactory.hxx>
+#include <svx/svdotable.hxx>
+#include <cell.hxx>
+#include <unotools/configmgr.hxx>
+
+
+// SvxTextEditSourceImpl
+
+
+/** @descr
+ <p>This class essentially provides the text and view forwarders. If
+ no SdrView is given, this class handles the UNO objects, which are
+ currently not concerned with view issues. In this case,
+ GetViewForwarder() always returns NULL and the underlying
+ EditEngine of the SvxTextForwarder is a background one (i.e. not
+ the official DrawOutliner, but one created exclusively for this
+ object, with no relation to a view).
+ </p>
+
+ <p>If a SdrView is given at construction time, the caller is
+ responsible for destroying this object when the view becomes
+ invalid (the views cannot notify). If GetViewForwarder(sal_True)
+ is called, the underlying shape is put into edit mode, the view
+ forwarder returned encapsulates the OutlinerView and the next call
+ to GetTextForwarder() yields a forwarder encapsulating the actual
+ DrawOutliner. Thus, changes on that Outliner are immediately
+ reflected on the screen. If the object leaves edit mode, the old
+ behaviour is restored.</p>
+ */
+class SvxTextEditSourceImpl : public SfxListener, public SfxBroadcaster, public sdr::ObjectUser
+{
+private:
+ oslInterlockedCount maRefCount;
+
+ SdrObject* mpObject; // TTTT could be reference (?)
+ SdrText* mpText;
+ SdrView* mpView;
+ VclPtr<const OutputDevice> mpWindow;
+ SdrModel* mpModel; // TTTT probably not needed -> use SdrModel from SdrObject (?)
+ std::unique_ptr<SdrOutliner> mpOutliner;
+ std::unique_ptr<SvxOutlinerForwarder> mpTextForwarder;
+ std::unique_ptr<SvxDrawOutlinerViewForwarder> mpViewForwarder; // if non-NULL, use GetViewModeTextForwarder text forwarder
+ css::uno::Reference< css::linguistic2::XLinguServiceManager2 > m_xLinguServiceManager;
+ Point maTextOffset;
+ bool mbDataValid;
+ bool mbIsLocked;
+ bool mbNeedsUpdate;
+ bool mbOldUndoMode;
+ bool mbForwarderIsEditMode; // have to reflect that, since ENDEDIT can happen more often
+ bool mbShapeIsEditMode; // only true, if SdrHintKind::BeginEdit was received
+ bool mbNotificationsDisabled; // prevent EditEngine/Outliner notifications (e.g. when setting up forwarder)
+ bool mbNotifyEditOutlinerSet;
+
+ SvxUnoTextRangeBaseVec mvTextRanges;
+
+ SvxTextForwarder* GetBackgroundTextForwarder();
+ SvxTextForwarder* GetEditModeTextForwarder();
+ std::unique_ptr<SvxDrawOutlinerViewForwarder> CreateViewForwarder();
+
+ void SetupOutliner();
+
+ bool HasView() const { return mpView != nullptr; }
+ bool IsEditMode() const
+ {
+ if (!mbShapeIsEditMode)
+ return false;
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
+ return pTextObj && pTextObj->IsTextEditActive();
+ }
+
+ void dispose();
+
+public:
+ SvxTextEditSourceImpl( SdrObject* pObject, SdrText* pText );
+ SvxTextEditSourceImpl( SdrObject& rObject, SdrText* pText, SdrView& rView, const OutputDevice& rWindow );
+ virtual ~SvxTextEditSourceImpl() override;
+
+ void acquire();
+ void release();
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ SvxTextForwarder* GetTextForwarder();
+ SvxEditViewForwarder* GetEditViewForwarder( bool );
+ void UpdateData();
+
+ void addRange( SvxUnoTextRangeBase* pNewRange );
+ void removeRange( SvxUnoTextRangeBase* pOldRange );
+ const SvxUnoTextRangeBaseVec& getRanges() const { return mvTextRanges;}
+
+ void lock();
+ void unlock();
+
+ bool IsValid() const;
+
+ Point LogicToPixel( const Point&, const MapMode& rMapMode );
+ Point PixelToLogic( const Point&, const MapMode& rMapMode );
+
+ DECL_LINK( NotifyHdl, EENotify&, void );
+
+ virtual void ObjectInDestruction(const SdrObject& rObject) override;
+
+ void UpdateOutliner();
+};
+
+
+SvxTextEditSourceImpl::SvxTextEditSourceImpl( SdrObject* pObject, SdrText* pText )
+ : maRefCount ( 0 ),
+ mpObject ( pObject ),
+ mpText ( pText ),
+ mpView ( nullptr ),
+ mpWindow ( nullptr ),
+ mpModel ( pObject ? &pObject->getSdrModelFromSdrObject() : nullptr ), // TTTT should be reference
+ mbDataValid ( false ),
+ mbIsLocked ( false ),
+ mbNeedsUpdate ( false ),
+ mbOldUndoMode ( false ),
+ mbForwarderIsEditMode ( false ),
+ mbShapeIsEditMode ( false ),
+ mbNotificationsDisabled ( false ),
+ mbNotifyEditOutlinerSet ( false )
+{
+ DBG_ASSERT( mpObject, "invalid pObject!" );
+
+ if( !mpText )
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mpObject );
+ if( pTextObj )
+ mpText = pTextObj->getText( 0 );
+ }
+
+ if( mpModel )
+ StartListening( *mpModel );
+
+ if( mpObject )
+ mpObject->AddObjectUser( *this );
+}
+
+
+SvxTextEditSourceImpl::SvxTextEditSourceImpl( SdrObject& rObject, SdrText* pText, SdrView& rView, const OutputDevice& rWindow )
+ : maRefCount ( 0 ),
+ mpObject ( &rObject ),
+ mpText ( pText ),
+ mpView ( &rView ),
+ mpWindow ( &rWindow ),
+ mpModel ( &rObject.getSdrModelFromSdrObject() ), // TTTT should be reference
+ mbDataValid ( false ),
+ mbIsLocked ( false ),
+ mbNeedsUpdate ( false ),
+ mbOldUndoMode ( false ),
+ mbForwarderIsEditMode ( false ),
+ mbShapeIsEditMode ( true ),
+ mbNotificationsDisabled ( false ),
+ mbNotifyEditOutlinerSet ( false )
+{
+ if( !mpText )
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mpObject );
+ if( pTextObj )
+ mpText = pTextObj->getText( 0 );
+ }
+
+ StartListening( *mpModel );
+ StartListening( *mpView );
+ mpObject->AddObjectUser( *this );
+
+ // Init edit mode state from shape info (IsTextEditActive())
+ mbShapeIsEditMode = IsEditMode();
+}
+
+
+SvxTextEditSourceImpl::~SvxTextEditSourceImpl()
+{
+ DBG_ASSERT( !mbIsLocked, "text edit source was not unlocked before dispose!" );
+ if( mpObject )
+ mpObject->RemoveObjectUser( *this );
+
+ dispose();
+}
+
+
+void SvxTextEditSourceImpl::addRange( SvxUnoTextRangeBase* pNewRange )
+{
+ if( pNewRange )
+ if( std::find( mvTextRanges.begin(), mvTextRanges.end(), pNewRange ) == mvTextRanges.end() )
+ mvTextRanges.push_back( pNewRange );
+}
+
+
+void SvxTextEditSourceImpl::removeRange( SvxUnoTextRangeBase* pOldRange )
+{
+ if( pOldRange )
+ mvTextRanges.erase( std::remove(mvTextRanges.begin(), mvTextRanges.end(), pOldRange), mvTextRanges.end() );
+}
+
+
+void SvxTextEditSourceImpl::acquire()
+{
+ osl_atomic_increment( &maRefCount );
+}
+
+
+void SvxTextEditSourceImpl::release()
+{
+ if( ! osl_atomic_decrement( &maRefCount ) )
+ delete this;
+}
+
+void SvxTextEditSourceImpl::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ // #i105988 keep reference to this object
+ rtl::Reference< SvxTextEditSourceImpl > xThis( this );
+
+ if (SfxHintId::Dying == rHint.GetId())
+ {
+ if (&rBC == mpView)
+ {
+ mpView = nullptr;
+ mpViewForwarder.reset();
+ }
+ }
+ else if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ switch( pSdrHint->GetKind() )
+ {
+ case SdrHintKind::ObjectChange:
+ {
+ mbDataValid = false; // Text has to be get again
+
+ if( HasView() )
+ {
+ // Update maTextOffset, object has changed
+ // Cannot call that here, since TakeTextRect() (called from there)
+ // changes outliner content.
+ // UpdateOutliner();
+
+ // Broadcast object changes, as they might change visible attributes
+ SvxViewChangedHint aHint;
+ Broadcast( aHint );
+ }
+ break;
+ }
+
+ case SdrHintKind::BeginEdit:
+ if( mpObject == pSdrHint->GetObject() )
+ {
+ // Once SdrHintKind::BeginEdit is broadcast, each EditSource of
+ // AccessibleCell will handle it here and call below:
+ // mpView->GetTextEditOutliner()->SetNotifyHdl(), which
+ // will replace the Notifier for current editable cell. It
+ // is totally wrong. So add check here to avoid the
+ // incorrect replacement of notifier.
+
+ // Currently it only happens on the editsource of
+ // AccessibleCell
+ if (mpObject && mpText)
+ {
+ sdr::table::SdrTableObj* pTableObj = dynamic_cast< sdr::table::SdrTableObj* >( mpObject );
+ if(pTableObj)
+ {
+ const sdr::table::CellRef& xCell = pTableObj->getActiveCell();
+ if (xCell.is())
+ {
+ sdr::table::Cell* pCellObj = dynamic_cast< sdr::table::Cell* >( mpText );
+ if (pCellObj && xCell.get() != pCellObj)
+ break;
+ }
+ }
+ }
+ // invalidate old forwarder
+ if( !mbForwarderIsEditMode )
+ {
+ mpTextForwarder.reset();
+ }
+
+ // register as listener - need to broadcast state change messages
+ if( mpView && mpView->GetTextEditOutliner() )
+ {
+ mpView->GetTextEditOutliner()->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) );
+ mbNotifyEditOutlinerSet = true;
+ }
+
+ // Only now we're really in edit mode
+ mbShapeIsEditMode = true;
+
+ Broadcast( *pSdrHint );
+ }
+ break;
+
+ case SdrHintKind::EndEdit:
+ if( mpObject == pSdrHint->GetObject() )
+ {
+ Broadcast( *pSdrHint );
+
+ // We're no longer in edit mode
+ mbShapeIsEditMode = false;
+
+ // remove as listener - outliner might outlive ourselves
+ if( mpView && mpView->GetTextEditOutliner() )
+ {
+ mpView->GetTextEditOutliner()->SetNotifyHdl( Link<EENotify&,void>() );
+ mbNotifyEditOutlinerSet = false;
+ }
+
+ // destroy view forwarder, OutlinerView no longer
+ // valid (no need for UpdateData(), it's been
+ // synched on SdrEndTextEdit)
+ mpViewForwarder.reset();
+
+ // Invalidate text forwarder, we might
+ // not be called again before entering edit mode a
+ // second time! Then, the old outliner might be
+ // invalid.
+ if( mbForwarderIsEditMode )
+ {
+ mbForwarderIsEditMode = false;
+ mpTextForwarder.reset();
+ }
+ }
+ break;
+
+ case SdrHintKind::ModelCleared:
+ dispose();
+ break;
+ default:
+ break;
+ }
+ }
+ else if (const SvxViewChangedHint* pViewHint = dynamic_cast<const SvxViewChangedHint*>(&rHint))
+ {
+ Broadcast( *pViewHint );
+ }
+}
+
+/* this is a callback from the attached SdrObject when it is actually deleted */
+void SvxTextEditSourceImpl::ObjectInDestruction(const SdrObject&)
+{
+ mpObject = nullptr;
+ dispose();
+ Broadcast( SfxHint( SfxHintId::Dying ) );
+}
+
+/* unregister at all objects and set all references to 0 */
+void SvxTextEditSourceImpl::dispose()
+{
+ mpTextForwarder.reset();
+ mpViewForwarder.reset();
+
+ if( mpOutliner )
+ {
+ if( mpModel )
+ {
+ mpModel->disposeOutliner( std::move(mpOutliner) );
+ }
+ else
+ {
+ mpOutliner.reset();
+ }
+ }
+
+ if( mpModel )
+ {
+ EndListening( *mpModel );
+ mpModel = nullptr;
+ }
+
+ if( mpView )
+ {
+ // remove as listener - outliner might outlive ourselves
+ if (mbNotifyEditOutlinerSet && mpView->GetTextEditOutliner())
+ {
+ mpView->GetTextEditOutliner()->SetNotifyHdl(Link<EENotify&,void>());
+ mbNotifyEditOutlinerSet = false;
+ }
+ EndListening( *mpView );
+ mpView = nullptr;
+ }
+
+ if( mpObject )
+ {
+ mpObject->RemoveObjectUser( *this );
+ mpObject = nullptr;
+ }
+ mpWindow = nullptr;
+}
+
+
+void SvxTextEditSourceImpl::SetupOutliner()
+{
+ // only for UAA edit source: setup outliner equivalently as in
+ // SdrTextObj::Paint(), such that formatting equals screen
+ // layout
+ if( !(mpObject && mpOutliner) )
+ return;
+
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
+ if( pTextObj )
+ {
+ tools::Rectangle aPaintRect;
+ tools::Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() );
+ pTextObj->SetupOutlinerFormatting( *mpOutliner, aPaintRect );
+
+ // calc text offset from shape anchor
+ maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft();
+ }
+}
+
+
+void SvxTextEditSourceImpl::UpdateOutliner()
+{
+ // only for UAA edit source: update outliner equivalently as in
+ // SdrTextObj::Paint(), such that formatting equals screen
+ // layout
+ if( !(mpObject && mpOutliner) )
+ return;
+
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
+ if( pTextObj )
+ {
+ tools::Rectangle aPaintRect;
+ tools::Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() );
+ pTextObj->UpdateOutlinerFormatting( *mpOutliner, aPaintRect );
+
+ // calc text offset from shape anchor
+ maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft();
+ }
+}
+
+
+SvxTextForwarder* SvxTextEditSourceImpl::GetBackgroundTextForwarder()
+{
+ bool bCreated = false;
+
+ // prevent EE/Outliner notifications during setup
+ mbNotificationsDisabled = true;
+
+ if (!mpTextForwarder)
+ {
+ if( mpOutliner == nullptr )
+ {
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
+ OutlinerMode nOutlMode = OutlinerMode::TextObject;
+ if( pTextObj && pTextObj->IsTextFrame() && pTextObj->GetTextKind() == SdrObjKind::OutlineText )
+ nOutlMode = OutlinerMode::OutlineObject;
+
+ mpOutliner = mpModel->createOutliner( nOutlMode );
+
+ // Do the setup after outliner creation, would be useless otherwise
+ if( HasView() )
+ {
+ // Setup outliner _before_ filling it
+ SetupOutliner();
+ }
+
+ mpOutliner->SetTextObjNoInit( pTextObj );
+ if( mbIsLocked )
+ {
+ const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->SetUpdateLayout( false );
+ mbOldUndoMode = mpOutliner->GetEditEngine().IsUndoEnabled();
+ const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->EnableUndo( false );
+ }
+
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ if ( !m_xLinguServiceManager.is() )
+ {
+ css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ m_xLinguServiceManager.set(css::linguistic2::LinguServiceManager::create(xContext));
+ }
+
+ css::uno::Reference< css::linguistic2::XHyphenator > xHyphenator = m_xLinguServiceManager->getHyphenator();
+ if( xHyphenator.is() )
+ mpOutliner->SetHyphenator( xHyphenator );
+ }
+ }
+
+
+ mpTextForwarder.reset(new SvxOutlinerForwarder( *mpOutliner, (mpObject->GetObjInventor() == SdrInventor::Default) && (mpObject->GetObjIdentifier() == SdrObjKind::OutlineText) ));
+ // delay listener subscription and UAA initialization until Outliner is fully setup
+ bCreated = true;
+
+ mbForwarderIsEditMode = false;
+ mbDataValid = false;
+ }
+
+ if( mpObject && mpText && !mbDataValid && mpObject->IsInserted() && mpObject->getSdrPageFromSdrObject() )
+ {
+ mpTextForwarder->flushCache();
+
+ std::optional<OutlinerParaObject> pOutlinerParaObject;
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
+ if( pTextObj && pTextObj->getActiveText() == mpText )
+ pOutlinerParaObject = pTextObj->CreateEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active
+ bool bOwnParaObj(false);
+
+ if( pOutlinerParaObject )
+ bOwnParaObj = true; // text edit active
+ else if (mpText->GetOutlinerParaObject())
+ pOutlinerParaObject = *mpText->GetOutlinerParaObject();
+
+ if( pOutlinerParaObject && ( bOwnParaObj || !mpObject->IsEmptyPresObj() || mpObject->getSdrPageFromSdrObject()->IsMasterPage() ) )
+ {
+ mpOutliner->SetText( *pOutlinerParaObject );
+
+ // put text to object and set EmptyPresObj to FALSE
+ if( mpText && bOwnParaObj && mpObject->IsEmptyPresObj() && pTextObj->IsReallyEdited() )
+ {
+ mpObject->SetEmptyPresObj( false );
+ static_cast< SdrTextObj* >( mpObject)->NbcSetOutlinerParaObjectForText( pOutlinerParaObject, mpText );
+
+ // #i103982# Here, due to mpObject->NbcSetOutlinerParaObjectForText, we LOSE ownership of the
+ // OPO, so do NOT delete it when leaving this method (!)
+ bOwnParaObj = false;
+ }
+ }
+ else
+ {
+ bool bVertical = pOutlinerParaObject && pOutlinerParaObject->IsEffectivelyVertical();
+
+ // set objects style sheet on empty outliner
+ SfxStyleSheetPool* pPool = static_cast<SfxStyleSheetPool*>(mpObject->getSdrModelFromSdrObject().GetStyleSheetPool());
+ if( pPool )
+ mpOutliner->SetStyleSheetPool( pPool );
+
+ SfxStyleSheet* pStyleSheet = mpObject->getSdrPageFromSdrObject()->GetTextStyleSheetForObject( mpObject );
+ if( pStyleSheet )
+ mpOutliner->SetStyleSheet( 0, pStyleSheet );
+
+ if( bVertical )
+ {
+ mpOutliner->SetVertical( pOutlinerParaObject->GetVertical());
+ mpOutliner->SetRotation( pOutlinerParaObject->GetRotation());
+ }
+ }
+
+ // maybe we have to set the border attributes
+ if (mpOutliner->GetParagraphCount()==1)
+ {
+ // if we only have one paragraph we check if it is empty
+ OUString aStr(mpOutliner->GetText(mpOutliner->GetParagraph(0)));
+
+ if (aStr.isEmpty())
+ {
+ // its empty, so we have to force the outliner to initialise itself
+ mpOutliner->SetText( "", mpOutliner->GetParagraph( 0 ) );
+
+ if(mpObject->GetStyleSheet())
+ mpOutliner->SetStyleSheet( 0, mpObject->GetStyleSheet());
+ }
+ }
+
+ mbDataValid = true;
+ }
+
+ if( bCreated && mpOutliner && HasView() )
+ {
+ // register as listener - need to broadcast state change messages
+ // registration delayed until outliner is completely set up
+ mpOutliner->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) );
+ }
+
+ // prevent EE/Outliner notifications during setup
+ mbNotificationsDisabled = false;
+
+ return mpTextForwarder.get();
+}
+
+
+SvxTextForwarder* SvxTextEditSourceImpl::GetEditModeTextForwarder()
+{
+ if( !mpTextForwarder && HasView() )
+ {
+ SdrOutliner* pEditOutliner = mpView->GetTextEditOutliner();
+
+ if( pEditOutliner )
+ {
+ mpTextForwarder.reset(new SvxOutlinerForwarder( *pEditOutliner, (mpObject->GetObjInventor() == SdrInventor::Default) && (mpObject->GetObjIdentifier() == SdrObjKind::OutlineText) ));
+ mbForwarderIsEditMode = true;
+ }
+ }
+
+ return mpTextForwarder.get();
+}
+
+
+SvxTextForwarder* SvxTextEditSourceImpl::GetTextForwarder()
+{
+ if( mpObject == nullptr )
+ return nullptr;
+
+ if( mpModel == nullptr )
+ mpModel = &mpObject->getSdrModelFromSdrObject();
+
+ // distinguish the cases
+ // a) connected to view, maybe edit mode is active, can work directly on the EditOutliner
+ // b) background Outliner, reflect changes into ParaOutlinerObject (this is exactly the old UNO code)
+ if( HasView() )
+ {
+ if( IsEditMode() != mbForwarderIsEditMode )
+ {
+ // forwarder mismatch - create new
+ mpTextForwarder.reset();
+ }
+
+ if( IsEditMode() )
+ return GetEditModeTextForwarder();
+ else
+ return GetBackgroundTextForwarder();
+ }
+ else
+ {
+ // tdf#123470 if the text edit mode of the shape is active, then we
+ // cannot trust a previously cached TextForwarder state as the text may
+ // be out of date, so force a refetch in that case, unless locked against
+ // changes
+ if (IsEditMode() && mpTextForwarder && !mbIsLocked)
+ {
+ assert(!mbForwarderIsEditMode); // because without a view there is no other option except !mbForwarderIsEditMode
+ bool bTextEditActive = false;
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(mpObject);
+ // similar to the GetBackgroundTextForwarder check, see if the text edit is active
+ if (pTextObj && pTextObj->getActiveText() == mpText && pTextObj->CanCreateEditOutlinerParaObject())
+ bTextEditActive = true; // text edit active
+ if (bTextEditActive)
+ mbDataValid = false;
+ }
+
+ return GetBackgroundTextForwarder();
+ }
+}
+
+std::unique_ptr<SvxDrawOutlinerViewForwarder> SvxTextEditSourceImpl::CreateViewForwarder()
+{
+ if( mpView->GetTextEditOutlinerView() && mpObject )
+ {
+ // register as listener - need to broadcast state change messages
+ mpView->GetTextEditOutliner()->SetNotifyHdl( LINK(this, SvxTextEditSourceImpl, NotifyHdl) );
+ mbNotifyEditOutlinerSet = true;
+
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
+ if( pTextObj )
+ {
+ tools::Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() );
+ OutlinerView& rOutlView = *mpView->GetTextEditOutlinerView();
+
+ return std::unique_ptr<SvxDrawOutlinerViewForwarder>(new SvxDrawOutlinerViewForwarder( rOutlView, aBoundRect.TopLeft() ));
+ }
+ }
+
+ return nullptr;
+}
+
+SvxEditViewForwarder* SvxTextEditSourceImpl::GetEditViewForwarder( bool bCreate )
+{
+ if( mpObject == nullptr )
+ return nullptr;
+
+ if( mpModel == nullptr )
+ mpModel = &mpObject->getSdrModelFromSdrObject();
+
+ // shall we delete?
+ if( mpViewForwarder )
+ {
+ if( !IsEditMode() )
+ {
+ // destroy all forwarders (no need for UpdateData(),
+ // it's been synched on SdrEndTextEdit)
+ mpViewForwarder.reset();
+ }
+ }
+ // which to create? Directly in edit mode, create new, or none?
+ else if( mpView )
+ {
+ if( IsEditMode() )
+ {
+ // create new view forwarder
+ mpViewForwarder = CreateViewForwarder();
+ }
+ else if( bCreate )
+ {
+ // dispose old text forwarder
+ UpdateData();
+
+ mpTextForwarder.reset();
+
+ // enter edit mode
+ mpView->SdrEndTextEdit();
+
+ if(mpView->SdrBeginTextEdit(mpObject))
+ {
+ SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( mpObject );
+ if (pTextObj && pTextObj->IsTextEditActive())
+ {
+ // create new view forwarder
+ mpViewForwarder = CreateViewForwarder();
+ }
+ else
+ {
+ // failure. Somehow, SdrBeginTextEdit did not set
+ // our SdrTextObj into edit mode
+ mpView->SdrEndTextEdit();
+ }
+ }
+ }
+ }
+
+ return mpViewForwarder.get();
+}
+
+
+void SvxTextEditSourceImpl::UpdateData()
+{
+ // if we have a view and in edit mode, we're working with the
+ // DrawOutliner. Thus, all changes made on the text forwarder are
+ // reflected on the view and committed to the model on
+ // SdrEndTextEdit(). Thus, no need for explicit updates here.
+ if( HasView() && IsEditMode() )
+ return;
+
+ if( mbIsLocked )
+ {
+ mbNeedsUpdate = true;
+ }
+ else
+ {
+ if( mpOutliner && mpObject && mpText )
+ {
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mpObject );
+ if( pTextObj )
+ {
+ if( (mpOutliner->GetParagraphCount() == 1 && mpOutliner->GetEditEngine().GetTextLen( 0 ) == 0 )
+ || (mpOutliner->GetParagraphCount() == 2 && mpOutliner->GetEditEngine().GetTextLen( 0 ) == 0
+ && mpOutliner->GetEditEngine().GetTextLen( 1 ) == 0) )
+ {
+ pTextObj->NbcSetOutlinerParaObjectForText( std::nullopt, mpText );
+ }
+ else
+ {
+ pTextObj->NbcSetOutlinerParaObjectForText( mpOutliner->CreateParaObject(), mpText );
+ }
+ }
+
+ if( mpObject->IsEmptyPresObj() )
+ mpObject->SetEmptyPresObj(false);
+ }
+ }
+}
+
+void SvxTextEditSourceImpl::lock()
+{
+ // if this assert ever fires, we will need to make this a counter instead of a boolean
+ assert(!mbIsLocked && "cannot nest these loc() calls");
+ mbIsLocked = true;
+ if( mpOutliner )
+ {
+ const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->SetUpdateLayout( false );
+ mbOldUndoMode = mpOutliner->GetEditEngine().IsUndoEnabled();
+ const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->EnableUndo( false );
+ }
+}
+
+void SvxTextEditSourceImpl::unlock()
+{
+ mbIsLocked = false;
+
+ if( mbNeedsUpdate )
+ {
+ UpdateData();
+ mbNeedsUpdate = false;
+ }
+
+ if( mpOutliner )
+ {
+ const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->SetUpdateLayout( true );
+ const_cast<EditEngine*>(&(mpOutliner->GetEditEngine()))->EnableUndo( mbOldUndoMode );
+ }
+}
+
+bool SvxTextEditSourceImpl::IsValid() const
+{
+ return mpView && mpWindow;
+}
+
+Point SvxTextEditSourceImpl::LogicToPixel( const Point& rPoint, const MapMode& rMapMode )
+{
+ // The responsibilities of ViewForwarder happen to be
+ // somewhat mixed in this case. On the one hand, we need the
+ // different interface queries on the SvxEditSource interface,
+ // since we need both VisAreas. On the other hand, if an
+ // EditViewForwarder exists, maTextOffset does not remain static,
+ // but may change with every key press.
+ if( IsEditMode() )
+ {
+ SvxEditViewForwarder* pForwarder = GetEditViewForwarder(false);
+
+ if( pForwarder )
+ return pForwarder->LogicToPixel( rPoint, rMapMode );
+ }
+ else if( IsValid() && mpModel )
+ {
+ Point aPoint1( rPoint );
+ aPoint1.AdjustX(maTextOffset.X() );
+ aPoint1.AdjustY(maTextOffset.Y() );
+
+ Point aPoint2( OutputDevice::LogicToLogic( aPoint1, rMapMode,
+ MapMode(mpModel->GetScaleUnit()) ) );
+ MapMode aMapMode(mpWindow->GetMapMode());
+ aMapMode.SetOrigin(Point());
+ return mpWindow->LogicToPixel( aPoint2, aMapMode );
+ }
+
+ return Point();
+}
+
+Point SvxTextEditSourceImpl::PixelToLogic( const Point& rPoint, const MapMode& rMapMode )
+{
+ // The responsibilities of ViewForwarder happen to be
+ // somewhat mixed in this case. On the one hand, we need the
+ // different interface queries on the SvxEditSource interface,
+ // since we need both VisAreas. On the other hand, if an
+ // EditViewForwarder exists, maTextOffset does not remain static,
+ // but may change with every key press.
+ if( IsEditMode() )
+ {
+ SvxEditViewForwarder* pForwarder = GetEditViewForwarder(false);
+
+ if( pForwarder )
+ return pForwarder->PixelToLogic( rPoint, rMapMode );
+ }
+ else if( IsValid() && mpModel )
+ {
+ MapMode aMapMode(mpWindow->GetMapMode());
+ aMapMode.SetOrigin(Point());
+ Point aPoint1( mpWindow->PixelToLogic( rPoint, aMapMode ) );
+ Point aPoint2( OutputDevice::LogicToLogic( aPoint1,
+ MapMode(mpModel->GetScaleUnit()),
+ rMapMode ) );
+ aPoint2.AdjustX( -(maTextOffset.X()) );
+ aPoint2.AdjustY( -(maTextOffset.Y()) );
+
+ return aPoint2;
+ }
+
+ return Point();
+}
+
+IMPL_LINK(SvxTextEditSourceImpl, NotifyHdl, EENotify&, rNotify, void)
+{
+ if( !mbNotificationsDisabled )
+ {
+ std::unique_ptr< SfxHint > aHint( SvxEditSourceHelper::EENotification2Hint( &rNotify) );
+
+ if (aHint)
+ Broadcast(*aHint);
+ }
+}
+
+SvxTextEditSource::SvxTextEditSource( SdrObject* pObject, SdrText* pText )
+{
+ mpImpl = new SvxTextEditSourceImpl( pObject, pText );
+}
+
+
+SvxTextEditSource::SvxTextEditSource( SdrObject& rObj, SdrText* pText, SdrView& rView, const OutputDevice& rWindow )
+{
+ mpImpl = new SvxTextEditSourceImpl( rObj, pText, rView, rWindow );
+}
+
+
+SvxTextEditSource::SvxTextEditSource( SvxTextEditSourceImpl* pImpl )
+{
+ mpImpl = pImpl;
+}
+
+
+SvxTextEditSource::~SvxTextEditSource()
+{
+ ::SolarMutexGuard aGuard;
+ mpImpl.clear();
+}
+
+
+std::unique_ptr<SvxEditSource> SvxTextEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new SvxTextEditSource( mpImpl.get() ));
+}
+
+
+SvxTextForwarder* SvxTextEditSource::GetTextForwarder()
+{
+ return mpImpl->GetTextForwarder();
+}
+
+
+SvxEditViewForwarder* SvxTextEditSource::GetEditViewForwarder( bool bCreate )
+{
+ return mpImpl->GetEditViewForwarder( bCreate );
+}
+
+
+SvxViewForwarder* SvxTextEditSource::GetViewForwarder()
+{
+ return this;
+}
+
+
+void SvxTextEditSource::UpdateData()
+{
+ mpImpl->UpdateData();
+}
+
+SfxBroadcaster& SvxTextEditSource::GetBroadcaster() const
+{
+ return *mpImpl;
+}
+
+void SvxTextEditSource::lock()
+{
+ mpImpl->lock();
+}
+
+void SvxTextEditSource::unlock()
+{
+ mpImpl->unlock();
+}
+
+bool SvxTextEditSource::IsValid() const
+{
+ return mpImpl->IsValid();
+}
+
+Point SvxTextEditSource::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ return mpImpl->LogicToPixel( rPoint, rMapMode );
+}
+
+Point SvxTextEditSource::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ return mpImpl->PixelToLogic( rPoint, rMapMode );
+}
+
+void SvxTextEditSource::addRange( SvxUnoTextRangeBase* pNewRange )
+{
+ mpImpl->addRange( pNewRange );
+}
+
+void SvxTextEditSource::removeRange( SvxUnoTextRangeBase* pOldRange )
+{
+ mpImpl->removeRange( pOldRange );
+}
+
+const SvxUnoTextRangeBaseVec& SvxTextEditSource::getRanges() const
+{
+ return mpImpl->getRanges();
+}
+
+void SvxTextEditSource::UpdateOutliner()
+{
+ mpImpl->UpdateOutliner();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unodraw/unottabl.cxx b/svx/source/unodraw/unottabl.cxx
new file mode 100644
index 000000000..6233bccb9
--- /dev/null
+++ b/svx/source/unodraw/unottabl.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/awt/Gradient.hpp>
+#include <svx/xflftrit.hxx>
+
+#include <svx/svdmodel.hxx>
+#include <svx/unofill.hxx>
+#include <svx/unomid.hxx>
+#include "UnoNameItemTable.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::cppu;
+
+namespace
+{
+class SvxUnoTransGradientTable : public SvxUnoNameItemTable
+{
+public:
+ explicit SvxUnoTransGradientTable(SdrModel* pModel) noexcept;
+
+ virtual NameOrIndex* createItem() const override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+};
+}
+
+SvxUnoTransGradientTable::SvxUnoTransGradientTable(SdrModel* pModel) noexcept
+ : SvxUnoNameItemTable(pModel, XATTR_FILLFLOATTRANSPARENCE, MID_FILLGRADIENT)
+{
+}
+
+OUString SAL_CALL SvxUnoTransGradientTable::getImplementationName()
+{
+ return "SvxUnoTransGradientTable";
+}
+
+uno::Sequence<OUString> SAL_CALL SvxUnoTransGradientTable::getSupportedServiceNames()
+{
+ return { "com.sun.star.drawing.TransparencyGradientTable" };
+}
+
+NameOrIndex* SvxUnoTransGradientTable::createItem() const
+{
+ XFillFloatTransparenceItem* pNewItem = new XFillFloatTransparenceItem();
+ pNewItem->SetEnabled(true);
+ return pNewItem;
+}
+
+// XElementAccess
+uno::Type SAL_CALL SvxUnoTransGradientTable::getElementType()
+{
+ return cppu::UnoType<awt::Gradient>::get();
+}
+
+/**
+ * Create a hatchtable
+ */
+uno::Reference<uno::XInterface> SvxUnoTransGradientTable_createInstance(SdrModel* pModel)
+{
+ return *new SvxUnoTransGradientTable(pModel);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unogallery/unogalitem.cxx b/svx/source/unogallery/unogalitem.cxx
new file mode 100644
index 000000000..5addd3226
--- /dev/null
+++ b/svx/source/unogallery/unogalitem.cxx
@@ -0,0 +1,368 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "unogalitem.hxx"
+#include "unogaltheme.hxx"
+#include <svx/galtheme.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/fmmodel.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/graph.hxx>
+#include <svl/itempool.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <galobj.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/gallery/GalleryItemType.hpp>
+#include <memory>
+
+#define UNOGALLERY_GALLERYITEMTYPE 1
+#define UNOGALLERY_URL 2
+#define UNOGALLERY_TITLE 3
+#define UNOGALLERY_THUMBNAIL 4
+#define UNOGALLERY_GRAPHIC 5
+#define UNOGALLERY_DRAWING 6
+
+using namespace ::com::sun::star;
+
+namespace unogallery {
+
+
+GalleryItem::GalleryItem( ::unogallery::GalleryTheme& rTheme, const GalleryObject& rObject ) :
+ ::comphelper::PropertySetHelper( createPropertySetInfo() ),
+ mpTheme( &rTheme ),
+ mpGalleryObject( &rObject )
+{
+ mpTheme->implRegisterGalleryItem( *this );
+}
+
+
+GalleryItem::~GalleryItem()
+ noexcept
+{
+ if( mpTheme )
+ mpTheme->implDeregisterGalleryItem( *this );
+}
+
+
+bool GalleryItem::isValid() const
+{
+ return( mpTheme != nullptr );
+}
+
+
+uno::Any SAL_CALL GalleryItem::queryAggregation( const uno::Type & rType )
+{
+ uno::Any aAny;
+
+ if( rType == cppu::UnoType<lang::XServiceInfo>::get())
+ aAny <<= uno::Reference< lang::XServiceInfo >(this);
+ else if( rType == cppu::UnoType<lang::XTypeProvider>::get())
+ aAny <<= uno::Reference< lang::XTypeProvider >(this);
+ else if( rType == cppu::UnoType<gallery::XGalleryItem>::get())
+ aAny <<= uno::Reference< gallery::XGalleryItem >(this);
+ else if( rType == cppu::UnoType<beans::XPropertySet>::get())
+ aAny <<= uno::Reference< beans::XPropertySet >(this);
+ else if( rType == cppu::UnoType<beans::XPropertyState>::get())
+ aAny <<= uno::Reference< beans::XPropertyState >(this);
+ else if( rType == cppu::UnoType<beans::XMultiPropertySet>::get())
+ aAny <<= uno::Reference< beans::XMultiPropertySet >(this);
+ else
+ aAny = OWeakAggObject::queryAggregation( rType );
+
+ return aAny;
+}
+
+
+uno::Any SAL_CALL GalleryItem::queryInterface( const uno::Type & rType )
+{
+ return OWeakAggObject::queryInterface( rType );
+}
+
+
+void SAL_CALL GalleryItem::acquire()
+ noexcept
+{
+ OWeakAggObject::acquire();
+}
+
+
+void SAL_CALL GalleryItem::release()
+ noexcept
+{
+ OWeakAggObject::release();
+}
+
+
+OUString SAL_CALL GalleryItem::getImplementationName()
+{
+ return "com.sun.star.comp.gallery.GalleryItem";
+}
+
+sal_Bool SAL_CALL GalleryItem::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL GalleryItem::getSupportedServiceNames()
+{
+ return { "com.sun.star.gallery.GalleryItem" };
+}
+
+uno::Sequence< uno::Type > SAL_CALL GalleryItem::getTypes()
+{
+ static const uno::Sequence aTypes {
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<gallery::XGalleryItem>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<beans::XPropertyState>::get(),
+ cppu::UnoType<beans::XMultiPropertySet>::get() };
+ return aTypes;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL GalleryItem::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+
+sal_Int8 SAL_CALL GalleryItem::getType()
+{
+ const SolarMutexGuard aGuard;
+ sal_Int8 nRet = gallery::GalleryItemType::EMPTY;
+
+ if( isValid() )
+ {
+ switch( implGetObject()->eObjKind )
+ {
+ case SgaObjKind::Sound:
+ nRet = gallery::GalleryItemType::MEDIA;
+ break;
+
+ case SgaObjKind::SvDraw:
+ nRet = gallery::GalleryItemType::DRAWING;
+ break;
+
+ default:
+ nRet = gallery::GalleryItemType::GRAPHIC;
+ break;
+ }
+ }
+
+ return nRet;
+}
+
+
+rtl::Reference<::comphelper::PropertySetInfo> GalleryItem::createPropertySetInfo()
+{
+ static ::comphelper::PropertyMapEntry const aEntries[] =
+ {
+ { OUString("GalleryItemType"), UNOGALLERY_GALLERYITEMTYPE, cppu::UnoType<sal_Int8>::get(),
+ beans::PropertyAttribute::READONLY, 0 },
+
+ { OUString("URL"), UNOGALLERY_URL, ::cppu::UnoType<OUString>::get(),
+ beans::PropertyAttribute::READONLY, 0 },
+
+ { OUString("Title"), UNOGALLERY_TITLE, ::cppu::UnoType<OUString>::get(),
+ 0, 0 },
+
+ { OUString("Thumbnail"), UNOGALLERY_THUMBNAIL, cppu::UnoType<graphic::XGraphic>::get(),
+ beans::PropertyAttribute::READONLY, 0 },
+
+ { OUString("Graphic"), UNOGALLERY_GRAPHIC, cppu::UnoType<graphic::XGraphic>::get(),
+ beans::PropertyAttribute::READONLY, 0 },
+
+ { OUString("Drawing"), UNOGALLERY_DRAWING, cppu::UnoType<lang::XComponent>::get(),
+ beans::PropertyAttribute::READONLY, 0 },
+ };
+
+ return rtl::Reference<::comphelper::PropertySetInfo>( new ::comphelper::PropertySetInfo( aEntries ) );
+}
+
+void GalleryItem::_setPropertyValues( const comphelper::PropertyMapEntry** ppEntries, const uno::Any* pValues )
+{
+ const SolarMutexGuard aGuard;
+
+ while( *ppEntries )
+ {
+ if( UNOGALLERY_TITLE == (*ppEntries)->mnHandle )
+ {
+ OUString aNewTitle;
+
+ if( !(*pValues >>= aNewTitle) )
+ {
+ throw lang::IllegalArgumentException();
+ }
+
+ ::GalleryTheme* pGalTheme = ( isValid() ? mpTheme->implGetTheme() : nullptr );
+
+ if( pGalTheme )
+ {
+ std::unique_ptr<SgaObject> pObj(pGalTheme->getGalleryStorageEngine()->implReadSgaObject( implGetObject() ));
+
+ if( pObj )
+ {
+ if( pObj->GetTitle() != aNewTitle )
+ {
+ pObj->SetTitle( aNewTitle );
+ pGalTheme->InsertObject( *pObj );
+ }
+ }
+ }
+
+ }
+
+ ++ppEntries;
+ ++pValues;
+ }
+}
+
+void GalleryItem::_getPropertyValues( const comphelper::PropertyMapEntry** ppEntries, uno::Any* pValue )
+{
+ const SolarMutexGuard aGuard;
+
+ while( *ppEntries )
+ {
+ switch( (*ppEntries)->mnHandle )
+ {
+ case UNOGALLERY_GALLERYITEMTYPE:
+ {
+ *pValue <<= getType();
+ }
+ break;
+
+ case UNOGALLERY_URL:
+ {
+ ::GalleryTheme* pGalTheme = ( isValid() ? mpTheme->implGetTheme() : nullptr );
+
+ if( pGalTheme )
+ *pValue <<= implGetObject()->getURL().GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+ break;
+
+ case UNOGALLERY_TITLE:
+ {
+ ::GalleryTheme* pGalTheme = ( isValid() ? mpTheme->implGetTheme() : nullptr );
+
+ if( pGalTheme )
+ {
+ std::unique_ptr<SgaObject> pObj = pGalTheme->AcquireObject( pGalTheme->maGalleryObjectCollection.searchPosWithObject( implGetObject() ) );
+
+ if( pObj )
+ {
+ *pValue <<= pObj->GetTitle();
+ }
+ }
+ }
+ break;
+
+ case UNOGALLERY_THUMBNAIL:
+ {
+ ::GalleryTheme* pGalTheme = ( isValid() ? mpTheme->implGetTheme() : nullptr );
+
+ if( pGalTheme )
+ {
+ std::unique_ptr<SgaObject> pObj = pGalTheme->AcquireObject( pGalTheme->maGalleryObjectCollection.searchPosWithObject( implGetObject() ) );
+
+ if( pObj )
+ {
+ Graphic aThumbnail;
+
+ if( pObj->IsThumbBitmap() )
+ aThumbnail = pObj->GetThumbBmp();
+ else
+ aThumbnail = pObj->GetThumbMtf();
+
+ *pValue <<= aThumbnail.GetXGraphic();
+ }
+ }
+ }
+ break;
+
+ case UNOGALLERY_GRAPHIC:
+ {
+ ::GalleryTheme* pGalTheme = ( isValid() ? mpTheme->implGetTheme() : nullptr );
+ Graphic aGraphic;
+
+ if( pGalTheme && pGalTheme->GetGraphic( pGalTheme->maGalleryObjectCollection.searchPosWithObject( implGetObject() ), aGraphic ) )
+ *pValue <<= aGraphic.GetXGraphic();
+ }
+ break;
+
+ case UNOGALLERY_DRAWING:
+ {
+ if( gallery::GalleryItemType::DRAWING == getType() )
+ {
+ ::GalleryTheme* pGalTheme = ( isValid() ? mpTheme->implGetTheme() : nullptr );
+ FmFormModel* pModel = new FmFormModel();
+
+ pModel->GetItemPool().FreezeIdRanges();
+
+ if( pGalTheme && pGalTheme->GetModel( pGalTheme->maGalleryObjectCollection.searchPosWithObject( implGetObject() ), *pModel ) )
+ {
+ uno::Reference< lang::XComponent > xDrawing( new GalleryDrawingModel( pModel ) );
+
+ pModel->setUnoModel( uno::Reference< uno::XInterface >::query( xDrawing ) );
+ *pValue <<= xDrawing;
+ }
+ else
+ delete pModel;
+ }
+ }
+ break;
+ }
+
+ ++ppEntries;
+ ++pValue;
+ }
+}
+
+
+void GalleryItem::implSetInvalid()
+{
+ if( mpTheme )
+ {
+ mpTheme = nullptr;
+ mpGalleryObject = nullptr;
+ }
+}
+
+
+GalleryDrawingModel::GalleryDrawingModel( SdrModel* pDoc )
+ noexcept :
+ SvxUnoDrawingModel( pDoc )
+{
+}
+
+
+GalleryDrawingModel::~GalleryDrawingModel()
+ noexcept
+{
+ delete GetDoc();
+}
+
+
+UNO3_GETIMPLEMENTATION_IMPL( GalleryDrawingModel );
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unogallery/unogalitem.hxx b/svx/source/unogallery/unogalitem.hxx
new file mode 100644
index 000000000..42bc0ba60
--- /dev/null
+++ b/svx/source/unogallery/unogalitem.hxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_UNOGALLERY_UNOGALITEM_HXX
+#define INCLUDED_SVX_SOURCE_UNOGALLERY_UNOGALITEM_HXX
+
+#include <svx/unomodel.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/gallery/XGalleryItem.hpp>
+#include <comphelper/propertysethelper.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <cppuhelper/weakagg.hxx>
+
+class GalleryTheme;
+struct GalleryObject;
+namespace unogallery { class GalleryTheme; }
+
+namespace unogallery {
+
+
+class GalleryItem final : public ::cppu::OWeakAggObject,
+ public css::lang::XServiceInfo,
+ public css::lang::XTypeProvider,
+ public css::gallery::XGalleryItem,
+ public ::comphelper::PropertySetHelper
+{
+ friend class ::unogallery::GalleryTheme;
+
+public:
+
+ GalleryItem( ::unogallery::GalleryTheme& rTheme, const GalleryObject& rObject );
+ virtual ~GalleryItem() noexcept override;
+
+ bool isValid() const;
+
+private:
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type & rType ) override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // XGalleryItem
+ virtual ::sal_Int8 SAL_CALL getType( ) override;
+
+ // PropertySetHelper
+ virtual void _setPropertyValues( const comphelper::PropertyMapEntry** ppEntries, const css::uno::Any* pValues ) override;
+ virtual void _getPropertyValues( const comphelper::PropertyMapEntry** ppEntries, css::uno::Any* pValue ) override;
+
+ static rtl::Reference<::comphelper::PropertySetInfo> createPropertySetInfo();
+
+ const ::GalleryObject* implGetObject() const { return mpGalleryObject;}
+ void implSetInvalid();
+
+ GalleryItem( const GalleryItem& ) = delete;
+ GalleryItem& operator=( const GalleryItem& ) = delete;
+
+ ::unogallery::GalleryTheme* mpTheme;
+ const ::GalleryObject* mpGalleryObject;
+};
+
+
+class GalleryDrawingModel : public SvxUnoDrawingModel
+{
+public:
+
+ explicit GalleryDrawingModel( SdrModel* pDoc ) noexcept;
+ virtual ~GalleryDrawingModel() noexcept override;
+
+ UNO3_GETIMPLEMENTATION_DECL( GalleryDrawingModel )
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unogallery/unogaltheme.cxx b/svx/source/unogallery/unogaltheme.cxx
new file mode 100644
index 000000000..b40cbc365
--- /dev/null
+++ b/svx/source/unogallery/unogaltheme.cxx
@@ -0,0 +1,362 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <algorithm>
+
+#include "unogaltheme.hxx"
+#include "unogalitem.hxx"
+#include <svx/galtheme.hxx>
+#include <svx/gallery1.hxx>
+#include <svx/galmisc.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unopage.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::com::sun::star;
+
+namespace unogallery {
+
+
+GalleryTheme::GalleryTheme( std::u16string_view rThemeName )
+{
+ mpGallery = ::Gallery::GetGalleryInstance();
+ mpTheme = ( mpGallery ? mpGallery->AcquireTheme( rThemeName, *this ) : nullptr );
+
+ if( mpGallery )
+ StartListening( *mpGallery );
+}
+
+
+GalleryTheme::~GalleryTheme()
+{
+ const SolarMutexGuard aGuard;
+
+ DBG_ASSERT( !mpTheme || mpGallery, "Theme is living without Gallery" );
+
+ implReleaseItems( nullptr );
+
+ if( mpGallery )
+ {
+ EndListening( *mpGallery );
+
+ if( mpTheme )
+ mpGallery->ReleaseTheme( mpTheme, *this );
+ }
+}
+
+
+OUString SAL_CALL GalleryTheme::getImplementationName()
+{
+ return "com.sun.star.comp.gallery.GalleryTheme";
+}
+
+sal_Bool SAL_CALL GalleryTheme::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL GalleryTheme::getSupportedServiceNames()
+{
+ return { "com.sun.star.gallery.GalleryTheme" };
+}
+
+uno::Sequence< uno::Type > SAL_CALL GalleryTheme::getTypes()
+{
+ static const uno::Sequence aTypes {
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<container::XElementAccess>::get(),
+ cppu::UnoType<container::XIndexAccess>::get(),
+ cppu::UnoType<gallery::XGalleryTheme>::get(),
+ };
+ return aTypes;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL GalleryTheme::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+
+uno::Type SAL_CALL GalleryTheme::getElementType()
+{
+ return cppu::UnoType<gallery::XGalleryItem>::get();
+}
+
+
+sal_Bool SAL_CALL GalleryTheme::hasElements()
+{
+ const SolarMutexGuard aGuard;
+
+ return( ( mpTheme != nullptr ) && ( mpTheme->GetObjectCount() > 0 ) );
+}
+
+
+sal_Int32 SAL_CALL GalleryTheme::getCount()
+{
+ const SolarMutexGuard aGuard;
+
+ return( mpTheme ? mpTheme->GetObjectCount() : 0 );
+}
+
+
+uno::Any SAL_CALL GalleryTheme::getByIndex( ::sal_Int32 nIndex )
+{
+ const SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if( mpTheme )
+ {
+ if( ( nIndex < 0 ) || ( nIndex >= getCount() ) )
+ {
+ throw lang::IndexOutOfBoundsException();
+ }
+ const GalleryObject* pObj = mpTheme->maGalleryObjectCollection.getForPosition( nIndex );
+
+ if( pObj )
+ aRet <<= uno::Reference< gallery::XGalleryItem >( new GalleryItem( *this, *pObj ) );
+ }
+
+ return aRet;
+}
+
+
+OUString SAL_CALL GalleryTheme::getName( )
+{
+ const SolarMutexGuard aGuard;
+ OUString aRet;
+
+ if( mpTheme )
+ aRet = mpTheme->GetName();
+
+ return aRet;
+}
+
+
+void SAL_CALL GalleryTheme::update( )
+{
+ const SolarMutexGuard aGuard;
+
+ if( mpTheme )
+ {
+ const Link<const INetURLObject&, void> aDummyLink;
+ mpTheme->Actualize( aDummyLink );
+ }
+}
+
+
+::sal_Int32 SAL_CALL GalleryTheme::insertURLByIndex(
+ const OUString& rURL, ::sal_Int32 nIndex )
+{
+ const SolarMutexGuard aGuard;
+ sal_Int32 nRet = -1;
+
+ if( mpTheme )
+ {
+ try
+ {
+ const INetURLObject aURL( rURL );
+
+ nIndex = std::clamp( nIndex, sal_Int32(0), getCount() );
+
+ if( ( aURL.GetProtocol() != INetProtocol::NotValid ) && mpTheme->InsertURL( aURL, nIndex ) )
+ {
+ const GalleryObject* pObj = mpTheme->maGalleryObjectCollection.searchObjectWithURL( aURL );
+
+ if( pObj )
+ nRet = mpTheme->maGalleryObjectCollection.searchPosWithObject( pObj );
+ }
+ }
+ catch( ... )
+ {
+ }
+ }
+
+ return nRet;
+}
+
+
+::sal_Int32 SAL_CALL GalleryTheme::insertGraphicByIndex(
+ const uno::Reference< graphic::XGraphic >& rxGraphic, sal_Int32 nIndex )
+{
+ const SolarMutexGuard aGuard;
+ sal_Int32 nRet = -1;
+
+ if( mpTheme )
+ {
+ try
+ {
+ const Graphic aGraphic( rxGraphic );
+
+ nIndex = std::clamp( nIndex, sal_Int32(0), getCount() );
+
+ if( mpTheme->InsertGraphic( aGraphic, nIndex ) )
+ nRet = nIndex;
+ }
+ catch( ... )
+ {
+ }
+ }
+
+ return nRet;
+}
+
+
+::sal_Int32 SAL_CALL GalleryTheme::insertDrawingByIndex(
+ const uno::Reference< lang::XComponent >& Drawing, sal_Int32 nIndex )
+{
+ const SolarMutexGuard aGuard;
+ sal_Int32 nRet = -1;
+
+ if( mpTheme )
+ {
+ GalleryDrawingModel* pModel = comphelper::getFromUnoTunnel<GalleryDrawingModel>( Drawing );
+
+ if( pModel && dynamic_cast<const FmFormModel*>(pModel->GetDoc()) )
+ {
+ // Here we're inserting something that's already a gallery theme drawing
+ nIndex = std::clamp( nIndex, sal_Int32(0), getCount() );
+
+ if( mpTheme->InsertModel( *static_cast< FmFormModel* >( pModel->GetDoc() ), nIndex ) )
+ nRet = nIndex;
+ }
+ else if (!pModel)
+ {
+ // #i80184# Try to do the right thing and make a Gallery drawing out
+ // of an ordinary Drawing if possible.
+ try
+ {
+ uno::Reference< drawing::XDrawPagesSupplier > xDrawPagesSupplier( Drawing, uno::UNO_QUERY_THROW );
+ uno::Reference< drawing::XDrawPages > xDrawPages( xDrawPagesSupplier->getDrawPages(), uno::UNO_SET_THROW );
+ uno::Reference< drawing::XDrawPage > xPage( xDrawPages->getByIndex( 0 ), uno::UNO_QUERY_THROW );
+ SvxDrawPage* pUnoPage = xPage.is() ? comphelper::getFromUnoTunnel<SvxDrawPage>( xPage ) : nullptr;
+ SdrModel* pOrigModel = pUnoPage ? &pUnoPage->GetSdrPage()->getSdrModelFromSdrPage() : nullptr;
+ SdrPage* pOrigPage = pUnoPage ? pUnoPage->GetSdrPage() : nullptr;
+
+ if (pOrigPage && pOrigModel)
+ {
+ FmFormModel* pTmpModel = new FmFormModel(&pOrigModel->GetItemPool());
+ // Clone to new target SdrModel
+ rtl::Reference<SdrPage> pNewPage = pOrigPage->CloneSdrPage(*pTmpModel);
+ pTmpModel->InsertPage(pNewPage.get(), 0);
+
+ uno::Reference< lang::XComponent > xDrawing( new GalleryDrawingModel( pTmpModel ) );
+ pTmpModel->setUnoModel( uno::Reference< uno::XInterface >::query( xDrawing ) );
+
+ nRet = insertDrawingByIndex( xDrawing, nIndex );
+ return nRet;
+ }
+ }
+ catch (...)
+ {
+ }
+ }
+ }
+
+ return nRet;
+}
+
+
+void SAL_CALL GalleryTheme::removeByIndex( sal_Int32 nIndex )
+{
+ const SolarMutexGuard aGuard;
+
+ if( mpTheme )
+ {
+ if( ( nIndex < 0 ) || ( nIndex >= getCount() ) )
+ throw lang::IndexOutOfBoundsException();
+ mpTheme->RemoveObject( nIndex );
+ }
+}
+
+
+void GalleryTheme::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const SolarMutexGuard aGuard;
+ const GalleryHint& rGalleryHint = static_cast< const GalleryHint& >( rHint );
+
+ switch( rGalleryHint.GetType() )
+ {
+ case GalleryHintType::CLOSE_THEME:
+ {
+ DBG_ASSERT( !mpTheme || mpGallery, "Theme is living without Gallery" );
+
+ implReleaseItems( nullptr );
+
+ if( mpGallery && mpTheme )
+ {
+ mpGallery->ReleaseTheme( mpTheme, *this );
+ mpTheme = nullptr;
+ }
+ }
+ break;
+
+ case GalleryHintType::CLOSE_OBJECT:
+ {
+ GalleryObject* pObj = static_cast< GalleryObject* >( rGalleryHint.GetData1() );
+
+ if( pObj )
+ implReleaseItems( pObj );
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void GalleryTheme::implReleaseItems( GalleryObject const * pObj )
+{
+ const SolarMutexGuard aGuard;
+
+ for( GalleryItemVector::iterator aIter = maItemVector.begin(); aIter != maItemVector.end(); )
+ {
+ if( !pObj || ( (*aIter)->implGetObject() == pObj ) )
+ {
+ (*aIter)->implSetInvalid();
+ aIter = maItemVector.erase( aIter );
+ }
+ else
+ ++aIter;
+ }
+}
+
+
+void GalleryTheme::implRegisterGalleryItem( ::unogallery::GalleryItem& rItem )
+{
+ const SolarMutexGuard aGuard;
+
+ maItemVector.push_back( &rItem );
+}
+
+
+void GalleryTheme::implDeregisterGalleryItem( ::unogallery::GalleryItem& rItem )
+{
+ const SolarMutexGuard aGuard;
+
+ maItemVector.erase(std::remove(maItemVector.begin(), maItemVector.end(), &rItem), maItemVector.end());
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unogallery/unogaltheme.hxx b/svx/source/unogallery/unogaltheme.hxx
new file mode 100644
index 000000000..31cde7003
--- /dev/null
+++ b/svx/source/unogallery/unogaltheme.hxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_UNOGALLERY_UNOGALTHEME_HXX
+#define INCLUDED_SVX_SOURCE_UNOGALLERY_UNOGALTHEME_HXX
+
+#include <vector>
+
+#include <cppuhelper/implbase.hxx>
+#include <svl/lstner.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/gallery/XGalleryTheme.hpp>
+
+class Gallery;
+class GalleryTheme;
+struct GalleryObject;
+namespace unogallery { class GalleryItem; }
+
+namespace unogallery {
+
+
+class GalleryTheme : public ::cppu::WeakImplHelper<
+ css::gallery::XGalleryTheme,
+ css::lang::XServiceInfo >,
+ public SfxListener
+{
+ friend class ::unogallery::GalleryItem;
+
+public:
+
+ explicit GalleryTheme( std::u16string_view rThemeName );
+ virtual ~GalleryTheme() override;
+
+protected:
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XIndexAccess
+ virtual ::sal_Int32 SAL_CALL getCount( ) override;
+ virtual css::uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override;
+
+ // XGalleryThemes
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL update( ) override;
+ virtual ::sal_Int32 SAL_CALL insertURLByIndex( const OUString& URL, ::sal_Int32 Index ) override;
+ virtual ::sal_Int32 SAL_CALL insertGraphicByIndex( const css::uno::Reference< css::graphic::XGraphic >& Graphic, ::sal_Int32 Index ) override;
+ virtual ::sal_Int32 SAL_CALL insertDrawingByIndex( const css::uno::Reference< css::lang::XComponent >& Drawing, ::sal_Int32 Index ) override;
+ virtual void SAL_CALL removeByIndex( ::sal_Int32 Index ) override;
+
+ // SfxListener
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+private:
+
+ typedef ::std::vector< ::unogallery::GalleryItem* > GalleryItemVector;
+
+ GalleryItemVector maItemVector;
+ ::Gallery* mpGallery;
+ ::GalleryTheme* mpTheme;
+
+ ::GalleryTheme* implGetTheme() const { return mpTheme;}
+
+ void implReleaseItems( GalleryObject const * pObj );
+
+ void implRegisterGalleryItem( ::unogallery::GalleryItem& rItem );
+ void implDeregisterGalleryItem( ::unogallery::GalleryItem& rItem );
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/unogallery/unogalthemeprovider.cxx b/svx/source/unogallery/unogalthemeprovider.cxx
new file mode 100644
index 000000000..638406e4d
--- /dev/null
+++ b/svx/source/unogallery/unogalthemeprovider.cxx
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "unogaltheme.hxx"
+#include <svx/gallery1.hxx>
+#include <vcl/svapp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/gallery/XGalleryTheme.hpp>
+#include <com/sun/star/gallery/XGalleryThemeProvider.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+using namespace ::com::sun::star;
+
+namespace {
+
+class GalleryThemeProvider : public ::cppu::WeakImplHelper< css::lang::XInitialization,
+ css::gallery::XGalleryThemeProvider,
+ css::lang::XServiceInfo >
+{
+public:
+
+ GalleryThemeProvider();
+
+protected:
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XGalleryThemeProvider
+ virtual css::uno::Reference< css::gallery::XGalleryTheme > SAL_CALL insertNewByName( const OUString& ThemeName ) override;
+ virtual void SAL_CALL removeByName( const OUString& ThemeName ) override;
+
+private:
+
+ Gallery* mpGallery;
+ bool mbHiddenThemes;
+};
+
+GalleryThemeProvider::GalleryThemeProvider() :
+ mbHiddenThemes( false )
+{
+ mpGallery = ::Gallery::GetGalleryInstance();
+}
+
+OUString SAL_CALL GalleryThemeProvider::getImplementationName()
+{
+ return "com.sun.star.comp.gallery.GalleryThemeProvider";
+}
+
+sal_Bool SAL_CALL GalleryThemeProvider::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL GalleryThemeProvider::getSupportedServiceNames()
+{
+ uno::Sequence<OUString> aSeq { "com.sun.star.gallery.GalleryThemeProvider" };
+ return aSeq;
+}
+
+uno::Sequence< uno::Type > SAL_CALL GalleryThemeProvider::getTypes()
+{
+ static const uno::Sequence aTypes {
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<lang::XInitialization>::get(),
+ cppu::UnoType<container::XElementAccess>::get(),
+ cppu::UnoType<container::XNameAccess>::get(),
+ cppu::UnoType<gallery::XGalleryThemeProvider>::get() };
+
+ return aTypes;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL GalleryThemeProvider::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void SAL_CALL GalleryThemeProvider::initialize( const uno::Sequence< uno::Any >& rArguments )
+{
+ uno::Sequence< beans::PropertyValue > aParams;
+
+ for( const auto& rArgument : rArguments )
+ {
+ if( rArgument >>= aParams )
+ break;
+ }
+
+ for( const beans::PropertyValue& rProp : std::as_const(aParams) )
+ {
+ if ( rProp.Name == "ProvideHiddenThemes" )
+ rProp.Value >>= mbHiddenThemes;
+ }
+}
+
+
+uno::Type SAL_CALL GalleryThemeProvider::getElementType()
+{
+ return cppu::UnoType<gallery::XGalleryTheme>::get();
+}
+
+
+sal_Bool SAL_CALL GalleryThemeProvider::hasElements()
+{
+ const SolarMutexGuard aGuard;
+
+ return( ( mpGallery != nullptr ) && ( mpGallery->GetThemeCount() > 0 ) );
+}
+
+
+uno::Any SAL_CALL GalleryThemeProvider::getByName( const OUString& rName )
+{
+ const SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if( !mpGallery || !mpGallery->HasTheme( rName ) )
+ {
+ throw container::NoSuchElementException();
+ }
+
+ aRet <<= uno::Reference< gallery::XGalleryTheme >( new ::unogallery::GalleryTheme( rName ) );
+
+ return aRet;
+}
+
+
+uno::Sequence< OUString > SAL_CALL GalleryThemeProvider::getElementNames()
+{
+ const SolarMutexGuard aGuard;
+ sal_uInt32 i = 0, nCount = ( mpGallery ? mpGallery->GetThemeCount() : 0 ), nRealCount = 0;
+ uno::Sequence< OUString > aSeq( nCount );
+ auto aSeqRange = asNonConstRange(aSeq);
+
+ for( ; i < nCount; ++i )
+ {
+ const GalleryThemeEntry* pEntry = mpGallery->GetThemeInfo( i );
+
+ if( mbHiddenThemes || !pEntry->IsHidden() )
+ aSeqRange[ nRealCount++ ] = pEntry->GetThemeName();
+ }
+
+ aSeq.realloc( nRealCount );
+
+ return aSeq;
+}
+
+
+sal_Bool SAL_CALL GalleryThemeProvider::hasByName( const OUString& rName )
+{
+ const SolarMutexGuard aGuard;
+
+ bool bRet = false;
+
+ if( mpGallery && mpGallery->HasTheme( rName ) )
+ bRet = ( mbHiddenThemes || !mpGallery->GetThemeInfo( rName )->IsHidden() );
+
+ return bRet;
+}
+
+
+uno::Reference< gallery::XGalleryTheme > SAL_CALL GalleryThemeProvider::insertNewByName( const OUString& rThemeName )
+{
+ const SolarMutexGuard aGuard;
+ uno::Reference< gallery::XGalleryTheme > xRet;
+
+ if( mpGallery )
+ {
+ if( mpGallery->HasTheme( rThemeName ) )
+ {
+ throw container::ElementExistException();
+ }
+ else if( mpGallery->CreateTheme( rThemeName ) )
+ {
+ xRet = new ::unogallery::GalleryTheme( rThemeName );
+ }
+ }
+
+ return xRet;
+}
+
+
+void SAL_CALL GalleryThemeProvider::removeByName( const OUString& rName )
+{
+ const SolarMutexGuard aGuard;
+
+ if( !mpGallery ||
+ !mpGallery->HasTheme( rName ) ||
+ ( !mbHiddenThemes && mpGallery->GetThemeInfo( rName )->IsHidden() ) )
+ {
+ throw container::NoSuchElementException();
+ }
+
+ mpGallery->RemoveTheme( rName );
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_gallery_GalleryThemeProvider_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new GalleryThemeProvider);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xml/xmleohlp.cxx b/svx/source/xml/xmleohlp.cxx
new file mode 100644
index 000000000..7fd88e492
--- /dev/null
+++ b/svx/source/xml/xmleohlp.cxx
@@ -0,0 +1,717 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <osl/diagnose.h>
+#include <sot/storage.hxx>
+#include <tools/debug.hxx>
+#include <sal/log.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/tempfile.hxx>
+
+#include <svtools/embedhlp.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/embeddedobjectcontainer.hxx>
+
+#include <comphelper/fileformat.h>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <svx/xmleohlp.hxx>
+#include <map>
+#include <memory>
+#include <mutex>
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::utl;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+
+constexpr OUStringLiteral XML_CONTAINERSTORAGE_NAME_60 = u"Pictures";
+constexpr OUStringLiteral XML_CONTAINERSTORAGE_NAME = u"ObjectReplacements";
+constexpr OUStringLiteral XML_EMBEDDEDOBJECT_URL_BASE = u"vnd.sun.star.EmbeddedObject:";
+constexpr OUStringLiteral XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE = u"vnd.sun.star.GraphicObject:";
+
+
+class OutputStorageWrapper_Impl : public ::cppu::WeakImplHelper<XOutputStream>
+{
+ std::mutex maMutex;
+ Reference < XOutputStream > xOut;
+ TempFile aTempFile;
+ bool bStreamClosed : 1;
+ SvStream* pStream;
+
+public:
+ OutputStorageWrapper_Impl();
+
+// css::io::XOutputStream
+ virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) override;
+ virtual void SAL_CALL flush() override;
+ virtual void SAL_CALL closeOutput() override;
+
+ SvStream* GetStream();
+};
+
+OutputStorageWrapper_Impl::OutputStorageWrapper_Impl()
+ : bStreamClosed( false )
+ , pStream(nullptr)
+{
+ aTempFile.EnableKillingFile();
+ pStream = aTempFile.GetStream( StreamMode::READWRITE );
+ xOut = new OOutputStreamWrapper( *pStream );
+}
+
+SvStream *OutputStorageWrapper_Impl::GetStream()
+{
+ if( bStreamClosed )
+ return pStream;
+ return nullptr;
+}
+
+void SAL_CALL OutputStorageWrapper_Impl::writeBytes(
+ const Sequence< sal_Int8 >& aData)
+{
+ std::scoped_lock aGuard( maMutex );
+ xOut->writeBytes( aData );
+}
+
+void SAL_CALL OutputStorageWrapper_Impl::flush()
+{
+ std::scoped_lock aGuard( maMutex );
+ xOut->flush();
+}
+
+void SAL_CALL OutputStorageWrapper_Impl::closeOutput()
+{
+ std::scoped_lock aGuard( maMutex );
+ xOut->closeOutput();
+ bStreamClosed = true;
+}
+
+SvXMLEmbeddedObjectHelper::SvXMLEmbeddedObjectHelper() :
+ mpDocPersist( nullptr ),
+ meCreateMode( SvXMLEmbeddedObjectHelperMode::Read )
+{
+}
+
+SvXMLEmbeddedObjectHelper::SvXMLEmbeddedObjectHelper( ::comphelper::IEmbeddedHelper& rDocPersist, SvXMLEmbeddedObjectHelperMode eCreateMode ) :
+ mpDocPersist( nullptr ),
+ meCreateMode( SvXMLEmbeddedObjectHelperMode::Read )
+{
+ Init( nullptr, rDocPersist, eCreateMode );
+}
+
+SvXMLEmbeddedObjectHelper::~SvXMLEmbeddedObjectHelper()
+{
+}
+
+void SvXMLEmbeddedObjectHelper::disposing(std::unique_lock<std::mutex>&)
+{
+ if( mxTempStorage.is() )
+ {
+ mxTempStorage->dispose();
+ mxTempStorage.clear();
+ }
+}
+
+void SvXMLEmbeddedObjectHelper::splitObjectURL(const OUString& _aURLNoPar,
+ OUString& rContainerStorageName,
+ OUString& rObjectStorageName)
+{
+ DBG_ASSERT(_aURLNoPar.isEmpty() || '#' != _aURLNoPar[0], "invalid object URL" );
+ OUString aURLNoPar = _aURLNoPar;
+
+ sal_Int32 _nPos = aURLNoPar.lastIndexOf( '/' );
+ if( -1 == _nPos )
+ {
+ rContainerStorageName.clear();
+ rObjectStorageName = aURLNoPar;
+ }
+ else
+ {
+ //eliminate 'superfluous' slashes at start and end
+ //#i103076# load objects with all allowed xlink:href syntaxes
+ {
+ //eliminate './' at start
+ sal_Int32 nStart = 0;
+ sal_Int32 nCount = aURLNoPar.getLength();
+ if( aURLNoPar.startsWith( "./" ) )
+ {
+ nStart = 2;
+ nCount -= 2;
+ }
+
+ //eliminate '/' at end
+ sal_Int32 nEnd = aURLNoPar.lastIndexOf( '/' );
+ if( nEnd == aURLNoPar.getLength()-1 && nEnd != (nStart-1) )
+ nCount--;
+
+ aURLNoPar = aURLNoPar.copy( nStart, nCount );
+ }
+
+ _nPos = aURLNoPar.lastIndexOf( '/' );
+ if( _nPos >= 0 )
+ rContainerStorageName = aURLNoPar.copy( 0, _nPos );
+ rObjectStorageName = aURLNoPar.copy( _nPos+1 );
+ }
+}
+
+bool SvXMLEmbeddedObjectHelper::ImplGetStorageNames(
+ const OUString& rURLStr,
+ OUString& rContainerStorageName,
+ OUString& rObjectStorageName,
+ bool bInternalToExternal,
+ bool *pGraphicRepl,
+ bool *pOasisFormat ) const
+{
+ // internal URL: vnd.sun.star.EmbeddedObject:<object-name>
+ // or: vnd.sun.star.EmbeddedObject:<path>/<object-name>
+ // internal replacement images:
+ // vnd.sun.star.EmbeddedObjectGraphic:<object-name>
+ // or: vnd.sun.star.EmbeddedObjectGraphic:<path>/<object-name>
+ // external URL: ./<path>/<object-name>
+ // or: <path>/<object-name>
+ // or: <object-name>
+ // currently, path may only consist of a single directory name
+ // it is also possible to have additional arguments at the end of URL: <main URL>[?<name>=<value>[,<name>=<value>]*]
+
+ if( pGraphicRepl )
+ *pGraphicRepl = false;
+
+ if( pOasisFormat )
+ *pOasisFormat = true; // the default value
+
+ if( rURLStr.isEmpty() )
+ return false;
+
+ // get rid of arguments
+ sal_Int32 nPos = rURLStr.indexOf( '?' );
+ OUString aURLNoPar;
+ if ( nPos == -1 )
+ aURLNoPar = rURLStr;
+ else
+ {
+ aURLNoPar = rURLStr.copy( 0, nPos );
+
+ // check the arguments
+ nPos++;
+ while( nPos >= 0 && nPos < rURLStr.getLength() )
+ {
+ OUString aToken = rURLStr.getToken( 0, ',', nPos );
+ if ( aToken.equalsIgnoreAsciiCase( "oasis=false" ) )
+ {
+ if ( pOasisFormat )
+ *pOasisFormat = false;
+ break;
+ }
+ else
+ {
+ SAL_WARN( "svx", "invalid arguments was found in URL!" );
+ }
+ }
+ }
+
+ if( bInternalToExternal )
+ {
+ nPos = aURLNoPar.indexOf( ':' );
+ if( -1 == nPos )
+ return false;
+ bool bObjUrl = aURLNoPar.startsWith( XML_EMBEDDEDOBJECT_URL_BASE );
+ bool bGrUrl = !bObjUrl &&
+ aURLNoPar.startsWith( XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE );
+ if( !(bObjUrl || bGrUrl) )
+ return false;
+
+ sal_Int32 nPathStart = nPos + 1;
+ nPos = aURLNoPar.lastIndexOf( '/' );
+ if( -1 == nPos )
+ {
+ rContainerStorageName.clear();
+ rObjectStorageName = aURLNoPar.copy( nPathStart );
+ }
+ else if( nPos > nPathStart )
+ {
+ rContainerStorageName = aURLNoPar.copy( nPathStart, nPos-nPathStart);
+ rObjectStorageName = aURLNoPar.copy( nPos+1 );
+ }
+ else
+ return false;
+
+ if( bGrUrl )
+ {
+ bool bOASIS = mxRootStorage.is() &&
+ ( SotStorage::GetVersion( mxRootStorage ) > SOFFICE_FILEFORMAT_60 );
+ if (bOASIS)
+ rContainerStorageName = XML_CONTAINERSTORAGE_NAME;
+ else
+ rContainerStorageName = XML_CONTAINERSTORAGE_NAME_60;
+
+ if( pGraphicRepl )
+ *pGraphicRepl = true;
+ }
+
+
+ }
+ else
+ {
+ splitObjectURL(aURLNoPar, rContainerStorageName, rObjectStorageName);
+ }
+
+ if( -1 != rContainerStorageName.indexOf( '/' ) )
+ {
+ OSL_FAIL( "SvXMLEmbeddedObjectHelper: invalid path name" );
+ return false;
+ }
+
+ return true;
+}
+
+uno::Reference < embed::XStorage > const & SvXMLEmbeddedObjectHelper::ImplGetContainerStorage(
+ const OUString& rStorageName )
+{
+ DBG_ASSERT( -1 == rStorageName.indexOf( '/' ) &&
+ -1 == rStorageName.indexOf( '\\' ),
+ "nested embedded storages aren't supported" );
+ if( !mxContainerStorage.is() ||
+ ( rStorageName != maCurContainerStorageName ) )
+ {
+ if( mxContainerStorage.is() &&
+ !maCurContainerStorageName.isEmpty() &&
+ SvXMLEmbeddedObjectHelperMode::Write == meCreateMode )
+ {
+ uno::Reference < embed::XTransactedObject > xTrans( mxContainerStorage, uno::UNO_QUERY );
+ if ( xTrans.is() )
+ xTrans->commit();
+ }
+
+ if( !rStorageName.isEmpty() && mxRootStorage.is() )
+ {
+ sal_Int32 nMode = SvXMLEmbeddedObjectHelperMode::Write == meCreateMode
+ ? ::embed::ElementModes::READWRITE
+ : ::embed::ElementModes::READ;
+ mxContainerStorage = mxRootStorage->openStorageElement( rStorageName,
+ nMode );
+ }
+ else
+ {
+ mxContainerStorage = mxRootStorage;
+ }
+ maCurContainerStorageName = rStorageName;
+ }
+
+ return mxContainerStorage;
+}
+
+void SvXMLEmbeddedObjectHelper::ImplReadObject(
+ const OUString& rContainerStorageName,
+ OUString& rObjName,
+ const SvGlobalName *, // pClassId, see "TODO/LATER" below
+ SvStream* pTemp )
+{
+ uno::Reference < embed::XStorage > xDocStor( mpDocPersist->getStorage() );
+ uno::Reference < embed::XStorage > xCntnrStor( ImplGetContainerStorage( rContainerStorageName ) );
+
+ if( !xCntnrStor.is() && !pTemp )
+ return;
+
+ OUString aSrcObjName( rObjName );
+ comphelper::EmbeddedObjectContainer& rContainer = mpDocPersist->getEmbeddedObjectContainer();
+
+ // Is the object name unique?
+ // if the object is already instantiated by GetEmbeddedObject
+ // that means that the duplication is being loaded
+ bool bDuplicate = rContainer.HasInstantiatedEmbeddedObject( rObjName );
+ DBG_ASSERT( !bDuplicate, "An object in the document is referenced twice!" );
+
+ if( xDocStor != xCntnrStor || pTemp || bDuplicate )
+ {
+ // TODO/LATER: make this altogether a method in the EmbeddedObjectContainer
+
+ // create a unique name for the duplicate object
+ if( bDuplicate )
+ rObjName = rContainer.CreateUniqueObjectName();
+
+ if( pTemp )
+ {
+ try
+ {
+ pTemp->Seek( 0 );
+ uno::Reference < io::XStream > xStm = xDocStor->openStreamElement( rObjName,
+ embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
+ std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( xStm ));
+ pTemp->ReadStream( *pStream );
+ pStream.reset();
+
+ // TODO/LATER: what to do when other types of objects are based on substream persistence?
+ // This is an ole object
+ uno::Reference< beans::XPropertySet > xProps( xStm, uno::UNO_QUERY_THROW );
+ xProps->setPropertyValue(
+ "MediaType",
+ uno::Any( OUString( "application/vnd.sun.star.oleobject" ) ) );
+
+ xStm->getOutputStream()->closeOutput();
+ }
+ catch ( uno::Exception& )
+ {
+ return;
+ }
+ }
+ else
+ {
+ try
+ {
+ xCntnrStor->copyElementTo( aSrcObjName, xDocStor, rObjName );
+ }
+ catch ( uno::Exception& )
+ {
+ return;
+ }
+ }
+ }
+
+ // make object known to the container
+ // TODO/LATER: could be done a little bit more efficient!
+ OUString aName( rObjName );
+
+ // TODO/LATER: The provided pClassId is ignored for now.
+ // The stream contains OLE storage internally and this storage already has a class id specifying the
+ // server that was used to create the object. pClassId could be used to specify the server that should
+ // be used for the next opening, but this information seems to be out of the file format responsibility
+ // area.
+ OUString const baseURL(mpDocPersist->getDocumentBaseURL());
+ rContainer.GetEmbeddedObject(aName, &baseURL);
+}
+
+OUString SvXMLEmbeddedObjectHelper::ImplInsertEmbeddedObjectURL(
+ const OUString& rURLStr )
+{
+ OUString sRetURL;
+
+ OUString aContainerStorageName, aObjectStorageName;
+ if( !ImplGetStorageNames( rURLStr, aContainerStorageName,
+ aObjectStorageName,
+ SvXMLEmbeddedObjectHelperMode::Write == meCreateMode ) )
+ return sRetURL;
+
+ if( SvXMLEmbeddedObjectHelperMode::Read == meCreateMode )
+ {
+ OutputStorageWrapper_Impl *pOut = nullptr;
+ std::map< OUString, rtl::Reference<OutputStorageWrapper_Impl> >::iterator aIter;
+
+ if( mxStreamMap )
+ {
+ aIter = mxStreamMap->find( rURLStr );
+ if( aIter != mxStreamMap->end() && aIter->second.is() )
+ pOut = aIter->second.get();
+ }
+
+ SvGlobalName aClassId, *pClassId = nullptr;
+ sal_Int32 nPos = aObjectStorageName.lastIndexOf( '!' );
+ if( -1 != nPos && aClassId.MakeId( aObjectStorageName.subView( nPos+1 ) ) )
+ {
+ aObjectStorageName = aObjectStorageName.copy( 0, nPos );
+ pClassId = &aClassId;
+ }
+
+ ImplReadObject( aContainerStorageName, aObjectStorageName, pClassId, pOut ? pOut->GetStream() : nullptr );
+ sRetURL = XML_EMBEDDEDOBJECT_URL_BASE + aObjectStorageName;
+
+ if( pOut )
+ {
+ mxStreamMap->erase( aIter );
+ }
+ }
+ else
+ {
+ // Objects are written using ::comphelper::IEmbeddedHelper::SaveAs
+ sRetURL = "./";
+ if( !aContainerStorageName.isEmpty() )
+ {
+ sRetURL += aContainerStorageName + "/";
+ }
+ sRetURL += aObjectStorageName;
+ }
+
+ return sRetURL;
+}
+
+uno::Reference< io::XInputStream > SvXMLEmbeddedObjectHelper::ImplGetReplacementImage(
+ const uno::Reference< embed::XEmbeddedObject >& xObj )
+{
+ uno::Reference< io::XInputStream > xStream;
+
+ if( xObj.is() )
+ {
+ try
+ {
+ bool bSwitchBackToLoaded = false;
+ sal_Int32 nCurState = xObj->getCurrentState();
+ if ( nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING )
+ {
+ // means that the object is not active
+ // copy replacement image from old to new container
+ OUString aMediaType;
+ xStream = mpDocPersist->getEmbeddedObjectContainer().GetGraphicStream( xObj, &aMediaType );
+ }
+
+ if ( !xStream.is() )
+ {
+ // the image must be regenerated
+ // TODO/LATER: another aspect could be used
+ if ( nCurState == embed::EmbedStates::LOADED )
+ bSwitchBackToLoaded = true;
+
+ OUString aMediaType;
+ xStream = svt::EmbeddedObjectRef::GetGraphicReplacementStream(
+ embed::Aspects::MSOLE_CONTENT,
+ xObj,
+ &aMediaType );
+ }
+
+ if ( bSwitchBackToLoaded )
+ // switch back to loaded state; that way we have a minimum cache confusion
+ xObj->changeState( embed::EmbedStates::LOADED );
+ }
+ catch( uno::Exception& )
+ {}
+ }
+
+ return xStream;
+}
+
+void SvXMLEmbeddedObjectHelper::Init(
+ const uno::Reference < embed::XStorage >& rRootStorage,
+ ::comphelper::IEmbeddedHelper& rPersist,
+ SvXMLEmbeddedObjectHelperMode eCreateMode )
+{
+ mxRootStorage = rRootStorage;
+ mpDocPersist = &rPersist;
+ meCreateMode = eCreateMode;
+}
+
+rtl::Reference<SvXMLEmbeddedObjectHelper> SvXMLEmbeddedObjectHelper::Create(
+ const uno::Reference < embed::XStorage >& rRootStorage,
+ ::comphelper::IEmbeddedHelper& rDocPersist,
+ SvXMLEmbeddedObjectHelperMode eCreateMode )
+{
+ rtl::Reference<SvXMLEmbeddedObjectHelper> pThis(new SvXMLEmbeddedObjectHelper);
+
+ pThis->Init( rRootStorage, rDocPersist, eCreateMode );
+
+ return pThis;
+}
+
+rtl::Reference<SvXMLEmbeddedObjectHelper> SvXMLEmbeddedObjectHelper::Create(
+ ::comphelper::IEmbeddedHelper& rDocPersist,
+ SvXMLEmbeddedObjectHelperMode eCreateMode )
+{
+ rtl::Reference<SvXMLEmbeddedObjectHelper> pThis(new SvXMLEmbeddedObjectHelper);
+
+ pThis->Init( nullptr, rDocPersist, eCreateMode );
+
+ return pThis;
+}
+
+OUString SAL_CALL SvXMLEmbeddedObjectHelper::resolveEmbeddedObjectURL(const OUString& rURL)
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ OUString sRet;
+ try
+ {
+ sRet = ImplInsertEmbeddedObjectURL(rURL);
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const Exception&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw WrappedTargetRuntimeException(
+ "SvXMLEmbeddedObjectHelper::resolveEmbeddedObjectURL non-RuntimeException",
+ static_cast<uno::XWeak*>(this), anyEx);
+ }
+ return sRet;
+}
+
+// XNameAccess: alien objects!
+Any SAL_CALL SvXMLEmbeddedObjectHelper::getByName(
+ const OUString& rURLStr )
+{
+ std::unique_lock aGuard( m_aMutex );
+ Any aRet;
+ if( SvXMLEmbeddedObjectHelperMode::Read == meCreateMode )
+ {
+ Reference < XOutputStream > xStrm;
+ if( mxStreamMap )
+ {
+ auto aIter = mxStreamMap->find( rURLStr );
+ if( aIter != mxStreamMap->end() && aIter->second.is() )
+ xStrm = aIter->second.get();
+ }
+ if( !xStrm.is() )
+ {
+ rtl::Reference<OutputStorageWrapper_Impl> xOut = new OutputStorageWrapper_Impl;
+ if( !mxStreamMap )
+ mxStreamMap.emplace();
+ (*mxStreamMap)[rURLStr] = xOut;
+ xStrm = xOut.get();
+ }
+
+ aRet <<= xStrm;
+ }
+ else
+ {
+ bool bGraphicRepl = false;
+ bool bOasisFormat = true;
+ Reference < XInputStream > xStrm;
+ OUString aContainerStorageName, aObjectStorageName;
+ if( ImplGetStorageNames( rURLStr, aContainerStorageName,
+ aObjectStorageName,
+ true,
+ &bGraphicRepl,
+ &bOasisFormat ) )
+ {
+ try
+ {
+ comphelper::EmbeddedObjectContainer& rContainer =
+ mpDocPersist->getEmbeddedObjectContainer();
+
+ Reference < embed::XEmbeddedObject > xObj = rContainer.GetEmbeddedObject( aObjectStorageName );
+ DBG_ASSERT( xObj.is(), "Didn't get object" );
+
+ if( xObj.is() )
+ {
+ if( bGraphicRepl )
+ {
+ xStrm = ImplGetReplacementImage( xObj );
+ }
+ else
+ {
+ Reference < embed::XEmbedPersist > xPersist( xObj, UNO_QUERY );
+ if( xPersist.is() )
+ {
+ if( !mxTempStorage.is() )
+ mxTempStorage =
+ comphelper::OStorageHelper::GetTemporaryStorage();
+ Sequence < beans::PropertyValue > aDummy,
+ aEmbDescr{ comphelper::makePropertyValue("StoreVisualReplacement",
+ !bOasisFormat) };
+ if ( !bOasisFormat )
+ {
+ uno::Reference< io::XInputStream > xGrInStream = ImplGetReplacementImage( xObj );
+ if ( xGrInStream.is() )
+ {
+ aEmbDescr.realloc( 2 );
+ auto pEmbDescr = aEmbDescr.getArray();
+ pEmbDescr[1].Name = "VisualReplacement";
+ pEmbDescr[1].Value <<= xGrInStream;
+ }
+ }
+
+ xPersist->storeToEntry( mxTempStorage, aObjectStorageName,
+ aDummy, aEmbDescr );
+ Reference < io::XStream > xStream =
+ mxTempStorage->openStreamElement(
+ aObjectStorageName,
+ embed::ElementModes::READ);
+ if( xStream.is() )
+ xStrm = xStream->getInputStream();
+ }
+ }
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+
+ aRet <<= xStrm;
+ }
+
+ return aRet;
+}
+
+Sequence< OUString > SAL_CALL SvXMLEmbeddedObjectHelper::getElementNames()
+{
+ return {};
+}
+
+sal_Bool SAL_CALL SvXMLEmbeddedObjectHelper::hasByName( const OUString& rURLStr )
+{
+ std::unique_lock aGuard( m_aMutex );
+ if( SvXMLEmbeddedObjectHelperMode::Read == meCreateMode )
+ {
+ return true;
+ }
+ else
+ {
+ OUString aContainerStorageName, aObjectStorageName;
+ if( !ImplGetStorageNames( rURLStr, aContainerStorageName,
+ aObjectStorageName,
+ true ) )
+ return false;
+
+ comphelper::EmbeddedObjectContainer& rContainer = mpDocPersist->getEmbeddedObjectContainer();
+ return !aObjectStorageName.isEmpty() &&
+ rContainer.HasEmbeddedObject( aObjectStorageName );
+ }
+}
+
+// XNameAccess
+Type SAL_CALL SvXMLEmbeddedObjectHelper::getElementType()
+{
+ std::unique_lock aGuard( m_aMutex );
+ if( SvXMLEmbeddedObjectHelperMode::Read == meCreateMode )
+ return cppu::UnoType<XOutputStream>::get();
+ else
+ return cppu::UnoType<XInputStream>::get();
+}
+
+sal_Bool SAL_CALL SvXMLEmbeddedObjectHelper::hasElements()
+{
+ std::unique_lock aGuard( m_aMutex );
+ if( SvXMLEmbeddedObjectHelperMode::Read == meCreateMode )
+ {
+ return true;
+ }
+ else
+ {
+ comphelper::EmbeddedObjectContainer& rContainer = mpDocPersist->getEmbeddedObjectContainer();
+ return rContainer.HasEmbeddedObjects();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xml/xmlexport.cxx b/svx/source/xml/xmlexport.cxx
new file mode 100644
index 000000000..1900a9e0b
--- /dev/null
+++ b/svx/source/xml/xmlexport.cxx
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/xml/sax/XFastParser.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <comphelper/processfactory.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/xmleohlp.hxx>
+#include <svx/xmlgrhlp.hxx>
+
+#include <svx/unomodel.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+bool SvxDrawingLayerExport( SdrModel* pModel, const uno::Reference<io::XOutputStream>& xOut, const Reference< lang::XComponent >& xComponent )
+{
+ return SvxDrawingLayerExport( pModel, xOut, xComponent, "com.sun.star.comp.DrawingLayer.XMLExporter" );
+}
+
+bool SvxDrawingLayerExport( SdrModel* pModel, const uno::Reference<io::XOutputStream>& xOut, const Reference< lang::XComponent >& xComponent, const char* pExportService )
+{
+ bool bDocRet = xOut.is();
+
+ uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
+ rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
+
+ Reference< document::XEmbeddedObjectResolver > xObjectResolver;
+ rtl::Reference<SvXMLEmbeddedObjectHelper> xObjectHelper;
+
+ Reference< lang::XComponent > xSourceDoc( xComponent );
+ try
+ {
+ if( !xSourceDoc.is() )
+ {
+ xSourceDoc = new SvxUnoDrawingModel( pModel );
+ pModel->setUnoModel( Reference< XInterface >::query( xSourceDoc ) );
+ }
+
+ uno::Reference< uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+
+ if( bDocRet )
+ {
+ uno::Reference< xml::sax::XWriter > xWriter = xml::sax::Writer::create( xContext );
+
+ ::comphelper::IEmbeddedHelper *pPersist = pModel->GetPersist();
+ if( pPersist )
+ {
+ xObjectHelper = SvXMLEmbeddedObjectHelper::Create( *pPersist, SvXMLEmbeddedObjectHelperMode::Write );
+ xObjectResolver = xObjectHelper.get();
+ }
+
+ xGraphicHelper = SvXMLGraphicHelper::Create( SvXMLGraphicHelperMode::Write );
+ xGraphicStorageHandler = xGraphicHelper.get();
+
+ uno::Reference<xml::sax::XDocumentHandler> xHandler = xWriter;
+
+ // doc export
+ xWriter->setOutputStream( xOut );
+
+ uno::Sequence< uno::Any > aArgs( xObjectResolver.is() ? 3 : 2 );
+ auto pArgs = aArgs.getArray();
+ pArgs[0] <<= xHandler;
+ pArgs[1] <<= xGraphicStorageHandler;
+ if( xObjectResolver.is() )
+ pArgs[2] <<= xObjectResolver;
+
+ uno::Reference< document::XFilter > xFilter( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii( pExportService ), aArgs, xContext ), uno::UNO_QUERY );
+ if( !xFilter.is() )
+ {
+ OSL_FAIL( "com.sun.star.comp.Draw.XMLExporter service missing" );
+ bDocRet = false;
+ }
+
+ if( bDocRet )
+ {
+ uno::Reference< document::XExporter > xExporter( xFilter, uno::UNO_QUERY );
+ if( xExporter.is() )
+ {
+ xExporter->setSourceDocument( xSourceDoc );
+
+ uno::Sequence< beans::PropertyValue > aDescriptor( 0 );
+ bDocRet = xFilter->filter( aDescriptor );
+ }
+ }
+ }
+ }
+ catch(uno::Exception const&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ bDocRet = false;
+ }
+
+ if( xGraphicHelper )
+ xGraphicHelper->dispose();
+ xGraphicHelper.clear();
+ xGraphicStorageHandler = nullptr;
+
+ if( xObjectHelper.is() )
+ xObjectHelper->dispose();
+
+ return bDocRet;
+}
+
+bool SvxDrawingLayerExport( SdrModel* pModel, const uno::Reference<io::XOutputStream>& xOut )
+{
+ Reference< lang::XComponent > xComponent;
+ return SvxDrawingLayerExport( pModel, xOut, xComponent );
+}
+
+//-
+
+bool SvxDrawingLayerImport( SdrModel* pModel, const uno::Reference<io::XInputStream>& xInputStream, const Reference< lang::XComponent >& xComponent )
+{
+ return SvxDrawingLayerImport( pModel, xInputStream, xComponent, "com.sun.star.comp.Draw.XMLOasisImporter" );
+}
+
+bool SvxDrawingLayerImport( SdrModel* pModel, const uno::Reference<io::XInputStream>& xInputStream, const Reference< lang::XComponent >& xComponent, const char* pImportService )
+{
+ bool bRet = true;
+
+ uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
+ rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
+
+ Reference< document::XEmbeddedObjectResolver > xObjectResolver;
+ rtl::Reference<SvXMLEmbeddedObjectHelper> xObjectHelper;
+
+ Reference< lang::XComponent > xTargetDocument( xComponent );
+ if( !xTargetDocument.is() )
+ {
+ xTargetDocument = new SvxUnoDrawingModel( pModel );
+ pModel->setUnoModel( Reference< XInterface >::query( xTargetDocument ) );
+ }
+
+ Reference< frame::XModel > xTargetModel( xTargetDocument, UNO_QUERY );
+
+ try
+ {
+ // Get service factory
+ Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
+
+ if ( xTargetModel.is() )
+ xTargetModel->lockControllers();
+
+
+ xGraphicHelper = SvXMLGraphicHelper::Create( SvXMLGraphicHelperMode::Read );
+ xGraphicStorageHandler = xGraphicHelper.get();
+
+ ::comphelper::IEmbeddedHelper *pPersist = pModel->GetPersist();
+ if( pPersist )
+ {
+ xObjectHelper = SvXMLEmbeddedObjectHelper::Create(
+ *pPersist,
+ SvXMLEmbeddedObjectHelperMode::Read );
+ xObjectResolver = xObjectHelper.get();
+ }
+
+ // parse
+ // prepare ParserInputSource
+ xml::sax::InputSource aParserInput;
+ aParserInput.aInputStream = xInputStream;
+
+ // prepare filter arguments
+ Sequence<Any> aFilterArgs( 2 );
+ Any *pArgs = aFilterArgs.getArray();
+ *pArgs++ <<= xGraphicStorageHandler;
+ *pArgs++ <<= xObjectResolver;
+
+ // get filter
+ Reference< XInterface > xFilter = xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii( pImportService ), aFilterArgs, xContext);
+ SAL_WARN_IF( !xFilter, "svx", "Can't instantiate filter component " << pImportService);
+ uno::Reference< xml::sax::XFastParser > xFastParser( xFilter, UNO_QUERY );
+ assert(xFastParser);
+
+ bRet = false;
+ if( xFastParser.is() )
+ {
+ // connect model and filter
+ uno::Reference < document::XImporter > xImporter( xFilter, UNO_QUERY );
+ xImporter->setTargetDocument( xTargetDocument );
+
+ // finally, parser the stream
+ xFastParser->parseStream( aParserInput );
+
+ bRet = true;
+ }
+ }
+ catch( uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ if( xGraphicHelper )
+ xGraphicHelper->dispose();
+ xGraphicHelper.clear();
+ xGraphicStorageHandler = nullptr;
+
+ if( xObjectHelper.is() )
+ xObjectHelper->dispose();
+ xObjectHelper.clear();
+ xObjectResolver = nullptr;
+
+ if ( xTargetModel.is() )
+ xTargetModel->unlockControllers();
+
+ return bRet;
+}
+
+bool SvxDrawingLayerImport( SdrModel* pModel, const uno::Reference<io::XInputStream>& xInputStream )
+{
+ Reference< lang::XComponent > xComponent;
+ return SvxDrawingLayerImport( pModel, xInputStream, xComponent );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xml/xmlgrhlp.cxx b/svx/source/xml/xmlgrhlp.cxx
new file mode 100644
index 000000000..4815c9e8a
--- /dev/null
+++ b/svx/source/xml/xmlgrhlp.cxx
@@ -0,0 +1,1190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/io/NotConnectedException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
+#include <comphelper/fileformat.h>
+#include <comphelper/graphicmimetype.hxx>
+#include <comphelper/compbase.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <rtl/ref.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/saveopt.hxx>
+#include <vcl/filter/SvmWriter.hxx>
+#include <vcl/gfxlink.hxx>
+#include <vcl/metaact.hxx>
+#include <tools/zcodec.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <vcl/GraphicObject.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <svx/xmlgrhlp.hxx>
+#include <svx/xmleohlp.hxx>
+
+#include <algorithm>
+#include <memory>
+#include <string_view>
+#include <utility>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::io;
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+constexpr OUStringLiteral XML_GRAPHICSTORAGE_NAME = u"Pictures";
+constexpr OUStringLiteral XML_GRAPHICOBJECT_URL_BASE = u"vnd.sun.star.GraphicObject:";
+
+namespace {
+
+const MetaCommentAction* ImplCheckForEPS( GDIMetaFile const & rMtf )
+{
+ const MetaCommentAction* pComment = nullptr;
+
+ if ( rMtf.GetActionSize() >= 2
+ && rMtf.GetAction(0)->GetType() == MetaActionType::EPS
+ && rMtf.GetAction(1)->GetType() == MetaActionType::COMMENT
+ && ( static_cast<const MetaCommentAction*>(rMtf.GetAction( 1 ))->GetComment() == "EPSReplacementGraphic" ) )
+ pComment = static_cast<const MetaCommentAction*>(rMtf.GetAction( 1 ));
+
+ return pComment;
+}
+
+class GraphicInputStream : public cppu::WeakImplHelper<XInputStream>
+{
+private:
+ virtual sal_Int32 SAL_CALL readBytes(Sequence<sal_Int8> & aData, sal_Int32 nBytesToRead) override;
+ virtual sal_Int32 SAL_CALL readSomeBytes(Sequence<sal_Int8> & aData, sal_Int32 nMaxBytesToRead) override;
+ virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
+ virtual sal_Int32 SAL_CALL available() override;
+ virtual void SAL_CALL closeInput() override;
+
+private:
+ utl::TempFile maTempFile;
+ Reference<XInputStream> mxStreamWrapper;
+
+public:
+
+ explicit GraphicInputStream(GraphicObject const & raGraphicObject, const OUString & rMimeType);
+ GraphicInputStream(const GraphicInputStream&) = delete;
+
+ GraphicInputStream& operator=(const GraphicInputStream&) = delete;
+
+ bool exists() const
+ {
+ return mxStreamWrapper.is();
+ }
+};
+
+
+GraphicInputStream::GraphicInputStream(GraphicObject const & aGraphicObject, const OUString & rMimeType)
+{
+ maTempFile.EnableKillingFile();
+
+ if (aGraphicObject.GetType() == GraphicType::NONE)
+ return;
+
+ std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream(maTempFile.GetURL(), StreamMode::WRITE | StreamMode::TRUNC);
+
+ if (!pStream)
+ return;
+
+ const Graphic& aGraphic(aGraphicObject.GetGraphic());
+ const GfxLink aGfxLink(aGraphic.GetGfxLink());
+ bool bRet = false;
+
+ if (aGfxLink.GetDataSize() && aGfxLink.GetData())
+ {
+ if (rMimeType.isEmpty())
+ {
+ pStream->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
+ bRet = (pStream->GetError() == ERRCODE_NONE);
+ }
+ else
+ {
+ GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
+ bRet = (rFilter.ExportGraphic(aGraphic, u"", *pStream, rFilter.GetExportFormatNumberForMediaType(rMimeType)) == ERRCODE_NONE);
+ }
+ }
+ else
+ {
+ if (aGraphic.GetType() == GraphicType::Bitmap)
+ {
+ GraphicFilter & rFilter = GraphicFilter::GetGraphicFilter();
+ OUString aFormat = rMimeType;
+
+ if (aGraphic.IsAnimated())
+ aFormat = "image/gif";
+ else if (aFormat.isEmpty())
+ aFormat = "image/png";
+
+ bRet = (rFilter.ExportGraphic(aGraphic, u"", *pStream, rFilter.GetExportFormatNumberForMediaType(aFormat)) == ERRCODE_NONE);
+ }
+ else if (rMimeType.isEmpty() && aGraphic.GetType() == GraphicType::GdiMetafile)
+ {
+ pStream->SetVersion(SOFFICE_FILEFORMAT_8);
+ pStream->SetCompressMode(SvStreamCompressFlags::ZBITMAP);
+ SvmWriter aWriter(*pStream);
+ aWriter.Write(aGraphic.GetGDIMetaFile());
+ bRet = (pStream->GetError() == ERRCODE_NONE);
+ }
+ else if (!rMimeType.isEmpty())
+ {
+ GraphicFilter & rFilter = GraphicFilter::GetGraphicFilter();
+ bRet = ( rFilter.ExportGraphic( aGraphic, u"", *pStream, rFilter.GetExportFormatNumberForMediaType( rMimeType ) ) == ERRCODE_NONE );
+ }
+ }
+
+ if (bRet)
+ {
+ pStream->Seek( 0 );
+ mxStreamWrapper = new ::utl::OInputStreamWrapper(std::move(pStream));
+ }
+}
+
+sal_Int32 SAL_CALL GraphicInputStream::readBytes(Sequence<sal_Int8> & rData, sal_Int32 nBytesToRead)
+{
+ if (!mxStreamWrapper.is())
+ throw NotConnectedException();
+
+ return mxStreamWrapper->readBytes(rData, nBytesToRead);
+}
+
+sal_Int32 SAL_CALL GraphicInputStream::readSomeBytes(Sequence<sal_Int8>& rData, sal_Int32 nMaxBytesToRead )
+{
+ if (!mxStreamWrapper.is())
+ throw NotConnectedException() ;
+
+ return mxStreamWrapper->readSomeBytes(rData, nMaxBytesToRead);
+}
+
+void SAL_CALL GraphicInputStream::skipBytes(sal_Int32 nBytesToSkip)
+{
+ if (!mxStreamWrapper.is())
+ throw NotConnectedException();
+
+ mxStreamWrapper->skipBytes(nBytesToSkip);
+}
+
+sal_Int32 SAL_CALL GraphicInputStream::available()
+{
+ if (!mxStreamWrapper.is())
+ throw NotConnectedException();
+
+ return mxStreamWrapper->available();
+}
+
+void SAL_CALL GraphicInputStream::closeInput()
+{
+ if (!mxStreamWrapper.is())
+ throw NotConnectedException();
+
+ mxStreamWrapper->closeInput();
+}
+
+class SvXMLGraphicOutputStream:
+ public cppu::WeakImplHelper<XOutputStream>
+{
+private:
+
+ // XOutputStream
+ virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& rData ) override;
+ virtual void SAL_CALL flush() override;
+ virtual void SAL_CALL closeOutput() override;
+
+private:
+
+ std::unique_ptr<::utl::TempFile> mpTmp;
+ std::unique_ptr<SvStream> mpOStm;
+ Reference< XOutputStream > mxStmWrapper;
+ std::unique_ptr<GraphicObject> mxGrfObj;
+ bool mbClosed;
+
+public:
+
+ SvXMLGraphicOutputStream();
+ virtual ~SvXMLGraphicOutputStream() override;
+ SvXMLGraphicOutputStream(const SvXMLGraphicOutputStream&) = delete;
+ SvXMLGraphicOutputStream& operator=(const SvXMLGraphicOutputStream&) = delete;
+
+ bool Exists() const { return mxStmWrapper.is(); }
+ const GraphicObject& GetGraphicObject();
+ Graphic GetGraphic();
+};
+
+SvXMLGraphicOutputStream::SvXMLGraphicOutputStream()
+ : mpTmp(new ::utl::TempFile)
+ , mxGrfObj(new GraphicObject)
+ , mbClosed(false)
+{
+ mpTmp->EnableKillingFile();
+
+ mpOStm = ::utl::UcbStreamHelper::CreateStream( mpTmp->GetURL(), StreamMode::WRITE | StreamMode::TRUNC );
+
+ if( mpOStm )
+ mxStmWrapper = new ::utl::OOutputStreamWrapper( *mpOStm );
+}
+
+SvXMLGraphicOutputStream::~SvXMLGraphicOutputStream()
+{
+ mpTmp.reset();
+ mpOStm.reset();
+}
+
+void SAL_CALL SvXMLGraphicOutputStream::writeBytes( const Sequence< sal_Int8 >& rData )
+{
+ if( !mxStmWrapper.is() )
+ throw NotConnectedException() ;
+
+ mxStmWrapper->writeBytes( rData );
+}
+
+void SAL_CALL SvXMLGraphicOutputStream::flush()
+{
+ if( !mxStmWrapper.is() )
+ throw NotConnectedException() ;
+
+ mxStmWrapper->flush();
+}
+
+void SAL_CALL SvXMLGraphicOutputStream::closeOutput()
+{
+ if( !mxStmWrapper.is() )
+ throw NotConnectedException() ;
+
+ mxStmWrapper->closeOutput();
+ mxStmWrapper.clear();
+
+ mbClosed = true;
+}
+
+Graphic SvXMLGraphicOutputStream::GetGraphic()
+{
+ Graphic aGraphic;
+
+ if (mbClosed && mxGrfObj->GetType() == GraphicType::NONE && mpOStm)
+ {
+ mpOStm->Seek( 0 );
+ sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
+ sal_uInt16 nDeterminedFormat = GRFILTER_FORMAT_DONTKNOW;
+ GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, u"", *mpOStm ,nFormat,&nDeterminedFormat);
+
+ if (nDeterminedFormat == GRFILTER_FORMAT_DONTKNOW)
+ {
+ //Read the first two byte to check whether it is a gzipped stream, is so it may be in wmz or emz format
+ //unzip them and try again
+
+ sal_uInt8 sFirstBytes[ 2 ];
+
+ sal_uInt64 nStreamLen = mpOStm->TellEnd();
+ mpOStm->Seek( 0 );
+
+ if ( nStreamLen == 0 )
+ {
+ SvLockBytes* pLockBytes = mpOStm->GetLockBytes();
+ if ( pLockBytes )
+ pLockBytes->SetSynchronMode();
+
+ nStreamLen = mpOStm->TellEnd();
+ mpOStm->Seek( 0 );
+ }
+ if( nStreamLen >= 2 )
+ {
+ //read two byte
+ mpOStm->ReadBytes(sFirstBytes, 2);
+
+ if( sFirstBytes[0] == 0x1f && sFirstBytes[1] == 0x8b )
+ {
+ SvMemoryStream aDest;
+ ZCodec aZCodec( 0x8000, 0x8000 );
+ aZCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
+ mpOStm->Seek( 0 );
+ aZCodec.Decompress( *mpOStm, aDest );
+
+ if (aZCodec.EndCompression())
+ {
+ sal_uInt64 nStreamLen_ = aDest.TellEnd();
+ if (nStreamLen_ > 0)
+ {
+ aDest.Seek(0);
+ GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, u"", aDest ,nFormat,&nDeterminedFormat );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (aGraphic.GetType() != GraphicType::NONE)
+ {
+ mpOStm.reset();
+ mpTmp.reset();
+ }
+ return aGraphic;
+}
+
+const GraphicObject& SvXMLGraphicOutputStream::GetGraphicObject()
+{
+ Graphic aGraphic(GetGraphic());
+ if (aGraphic.GetType() != GraphicType::NONE)
+ {
+ mxGrfObj.reset(new GraphicObject(aGraphic));
+ }
+ return *mxGrfObj;
+}
+
+}
+
+SvXMLGraphicHelper::SvXMLGraphicHelper(SvXMLGraphicHelperMode eCreateMode)
+{
+ Init( nullptr, eCreateMode );
+}
+
+SvXMLGraphicHelper::SvXMLGraphicHelper()
+ : meCreateMode(SvXMLGraphicHelperMode::Read)
+{
+}
+
+SvXMLGraphicHelper::~SvXMLGraphicHelper()
+{
+}
+
+bool SvXMLGraphicHelper::ImplGetStreamNames( const OUString& rURLStr,
+ OUString& rPictureStorageName,
+ OUString& rPictureStreamName )
+{
+ if (rURLStr.isEmpty())
+ return false;
+
+ const OUString aURLStr {rURLStr.copy(rURLStr.lastIndexOf(':')+1)};
+
+ if( !aURLStr.isEmpty() && aURLStr.indexOf('/')<0 ) // just one token?
+ {
+ rPictureStorageName = OUString();
+ rPictureStreamName = aURLStr;
+ }
+ else
+ SvXMLEmbeddedObjectHelper::splitObjectURL(aURLStr, rPictureStorageName, rPictureStreamName);
+
+ SAL_WARN_IF(rPictureStreamName.isEmpty(), "svx", "SvXMLGraphicHelper::ImplInsertGraphicURL: invalid scheme: " << rURLStr);
+
+ return !rPictureStreamName.isEmpty();
+}
+
+uno::Reference < embed::XStorage > SvXMLGraphicHelper::ImplGetGraphicStorage( const OUString& rStorageName )
+{
+ uno::Reference < embed::XStorage > xRetStorage;
+ if( mxRootStorage.is() )
+ {
+ try
+ {
+ maCurStorageName = rStorageName;
+ xRetStorage = mxRootStorage->openStorageElement(
+ maCurStorageName,
+ ( SvXMLGraphicHelperMode::Write == meCreateMode )
+ ? embed::ElementModes::READWRITE
+ : embed::ElementModes::READ );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ //#i43196# try again to open the storage element - this time readonly
+ if(!xRetStorage.is())
+ {
+ try
+ {
+ maCurStorageName = rStorageName;
+ xRetStorage = mxRootStorage->openStorageElement( maCurStorageName, embed::ElementModes::READ );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ }
+
+ return xRetStorage;
+}
+
+SvxGraphicHelperStream_Impl SvXMLGraphicHelper::ImplGetGraphicStream( const OUString& rPictureStorageName,
+ const OUString& rPictureStreamName )
+{
+ SvxGraphicHelperStream_Impl aRet;
+ if (!rPictureStorageName.isEmpty())
+ aRet.xStorage = ImplGetGraphicStorage(rPictureStorageName);
+ else
+ aRet.xStorage = mxRootStorage;
+
+ sal_Int32 nMode = embed::ElementModes::READ;
+ if (SvXMLGraphicHelperMode::Write == meCreateMode)
+ {
+ nMode = embed::ElementModes::READWRITE;
+ }
+
+ if (aRet.xStorage.is())
+ {
+ aRet.xStream = aRet.xStorage->openStreamElement( rPictureStreamName, nMode );
+ }
+ else if (rPictureStorageName.indexOf('/') != -1)
+ {
+ uno::Reference<embed::XHierarchicalStorageAccess> xHierRootStorage(mxRootStorage,
+ uno::UNO_QUERY);
+ if (xHierRootStorage.is())
+ {
+ try
+ {
+ aRet.xStream = xHierRootStorage->openStreamElementByHierarchicalName(
+ rPictureStorageName + "/" + rPictureStreamName, nMode);
+ aRet.xStorage = mxRootStorage;
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx",
+ "SvXMLGraphicHelper::ImplGetGraphicStream: failed to open "
+ << rPictureStreamName);
+ }
+ }
+ }
+
+ if (aRet.xStream.is() && (SvXMLGraphicHelperMode::Write == meCreateMode))
+ {
+ uno::Reference<beans::XPropertySet> xProps(aRet.xStream, uno::UNO_QUERY);
+ xProps->setPropertyValue("UseCommonStoragePasswordEncryption", uno::Any(true));
+ }
+
+ return aRet;
+}
+
+OUString SvXMLGraphicHelper::ImplGetGraphicMimeType( const OUString& rFileName )
+{
+ if( ( rFileName.getLength() >= 4 ) && ( rFileName[ rFileName.getLength() - 4 ] == '.' ) )
+ {
+ const OString aExt(OUStringToOString(rFileName.subView(rFileName.getLength() - 3),
+ RTL_TEXTENCODING_ASCII_US));
+ return comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension( aExt );
+ }
+
+ return OUString();
+}
+
+Graphic SvXMLGraphicHelper::ImplReadGraphic( const OUString& rPictureStorageName,
+ const OUString& rPictureStreamName )
+{
+ Graphic aReturnGraphic;
+ SvxGraphicHelperStream_Impl aStream( ImplGetGraphicStream( rPictureStorageName, rPictureStreamName ) );
+ if (aStream.xStream.is())
+ {
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(aStream.xStream));
+ Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(*pStream);
+ if (!aGraphic.IsNone())
+ aReturnGraphic = aGraphic;
+ else
+ rGraphicFilter.ImportGraphic(aReturnGraphic, u"", *pStream);
+ }
+
+ return aReturnGraphic;
+}
+
+void SvXMLGraphicHelper::Init( const uno::Reference < embed::XStorage >& rXMLStorage,
+ SvXMLGraphicHelperMode eCreateMode,
+ const OUString& rGraphicMimeType )
+{
+ mxRootStorage = rXMLStorage;
+ meCreateMode = eCreateMode;
+ maOutputMimeType = rGraphicMimeType;
+}
+
+rtl::Reference<SvXMLGraphicHelper> SvXMLGraphicHelper::Create( const uno::Reference < embed::XStorage >& rXMLStorage,
+ SvXMLGraphicHelperMode eCreateMode )
+{
+ rtl::Reference<SvXMLGraphicHelper> pThis = new SvXMLGraphicHelper;
+ pThis->Init( rXMLStorage, eCreateMode, OUString() );
+
+ return pThis;
+}
+
+rtl::Reference<SvXMLGraphicHelper> SvXMLGraphicHelper::Create( SvXMLGraphicHelperMode eCreateMode,
+ const OUString& rGraphicMimeType )
+{
+ rtl::Reference<SvXMLGraphicHelper> pThis = new SvXMLGraphicHelper;
+
+ pThis->Init( nullptr, eCreateMode, rGraphicMimeType );
+
+ return pThis;
+}
+
+namespace
+{
+
+void splitUserDataFromURL(OUString const & rWholeURL, OUString & rJustURL, OUString & rUserData)
+{
+ sal_Int32 nUser = rWholeURL.indexOf('?');
+ if (nUser >= 0)
+ {
+ rJustURL = rWholeURL.copy(0, nUser);
+ nUser++;
+ rUserData = rWholeURL.copy(nUser);
+ }
+ else
+ {
+ rJustURL = rWholeURL;
+ }
+}
+
+} // end anonymous namespace
+
+// XGraphicObjectResolver
+OUString SAL_CALL SvXMLGraphicHelper::resolveGraphicObjectURL( const OUString& /*rURL*/ )
+{
+ throw uno::RuntimeException("XGraphicObjectResolver has been removed in LibreOffice 6.1");
+}
+
+// XGraphicStorageHandler
+uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicHelper::loadGraphic(OUString const & rURL)
+{
+ std::unique_lock aGuard(m_aMutex);
+
+ uno::Reference<graphic::XGraphic> xGraphic;
+
+ OUString aURLOnly;
+ OUString aUserData;
+ splitUserDataFromURL(rURL, aURLOnly, aUserData);
+
+ auto aIterator = maGraphicObjects.find(aURLOnly);
+ if (aIterator != maGraphicObjects.end())
+ {
+ return aIterator->second;
+ }
+
+ OUString aPictureStorageName, aPictureStreamName;
+
+ if (ImplGetStreamNames(aURLOnly, aPictureStorageName, aPictureStreamName))
+ {
+ const GraphicObject aGraphicObject(ImplReadGraphic(aPictureStorageName, aPictureStreamName));
+
+ if (aGraphicObject.GetType() != GraphicType::NONE)
+ {
+ xGraphic = aGraphicObject.GetGraphic().GetXGraphic();
+ maGraphicObjects[aURLOnly] = xGraphic;
+ }
+ }
+
+ return xGraphic;
+}
+
+uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicHelper::loadGraphicFromOutputStream(uno::Reference<io::XOutputStream> const & rxOutputStream)
+{
+ std::unique_lock aGuard(m_aMutex);
+
+ uno::Reference<graphic::XGraphic> xGraphic;
+
+ if ((SvXMLGraphicHelperMode::Read == meCreateMode) && rxOutputStream.is())
+ {
+
+ SvXMLGraphicOutputStream* pGraphicOutputStream = static_cast<SvXMLGraphicOutputStream*>(rxOutputStream.get());
+ if (pGraphicOutputStream)
+ {
+ xGraphic = pGraphicOutputStream->GetGraphic().GetXGraphic();
+ }
+ }
+ return xGraphic;
+}
+
+OUString SAL_CALL SvXMLGraphicHelper::saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
+ OUString & rOutSavedMimeType, OUString const & rRequestName)
+{
+ return implSaveGraphic(rxGraphic, rOutSavedMimeType, rRequestName);
+}
+
+OUString SAL_CALL SvXMLGraphicHelper::saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic)
+{
+ OUString aOutMimeType;
+ return implSaveGraphic(rxGraphic, aOutMimeType, std::u16string_view());
+}
+
+OUString SvXMLGraphicHelper::implSaveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
+ OUString & rOutSavedMimeType, std::u16string_view rRequestName)
+{
+ Graphic aGraphic(rxGraphic);
+
+ auto aIterator = maExportGraphics.find(aGraphic);
+ if (aIterator != maExportGraphics.end())
+ {
+ auto const & aURLAndMimePair = aIterator->second;
+ rOutSavedMimeType = aURLAndMimePair.second;
+ return aURLAndMimePair.first;
+ }
+
+ GraphicObject aGraphicObject(aGraphic);
+
+ if (aGraphicObject.GetType() != GraphicType::NONE)
+ {
+ const GfxLink aGfxLink(aGraphic.GetGfxLink());
+ OUString aExtension;
+ bool bUseGfxLink = true;
+
+ if (aGfxLink.GetDataSize())
+ {
+ switch (aGfxLink.GetType())
+ {
+ case GfxLinkType::EpsBuffer: aExtension = ".eps"; break;
+ case GfxLinkType::NativeGif: aExtension = ".gif"; break;
+ // #i15508# added BMP type for better exports (checked, works)
+ case GfxLinkType::NativeBmp: aExtension = ".bmp"; break;
+ case GfxLinkType::NativeJpg: aExtension = ".jpg"; break;
+ case GfxLinkType::NativePng: aExtension = ".png"; break;
+ case GfxLinkType::NativeTif: aExtension = ".tif"; break;
+ case GfxLinkType::NativeWmf:
+ if (aGfxLink.IsEMF())
+ aExtension = ".emf";
+ else
+ aExtension = ".wmf";
+ break;
+ case GfxLinkType::NativeMet: aExtension = ".met"; break;
+ case GfxLinkType::NativePct: aExtension = ".pct"; break;
+ case GfxLinkType::NativeSvg:
+ {
+ // backward-compat kludge: since no released OOo
+ // version to date can handle svg properly, wrap it up
+ // into an svm. slight catch22 here, since strict ODF
+ // conformance _recommends_ svg - then again, most old
+ // ODF consumers are believed to be OOo
+ auto nSaneVersion = GetODFSaneDefaultVersion();
+ if ( nSaneVersion < SvtSaveOptions::ODFSVER_012
+ || nSaneVersion == SvtSaveOptions::ODFSVER_012_EXT_COMPAT)
+ {
+ bUseGfxLink = false;
+ aExtension = ".svm";
+ }
+ else
+ {
+ aExtension = ".svg";
+ }
+ break;
+ }
+ case GfxLinkType::NativePdf: aExtension = ".pdf"; break;
+ case GfxLinkType::NativeWebp: aExtension = ".webp"; break;
+
+ default:
+ aExtension = ".grf";
+ break;
+ }
+ }
+ else
+ {
+ if (aGraphicObject.GetType() == GraphicType::Bitmap)
+ {
+ if (aGraphicObject.IsAnimated())
+ aExtension = ".gif";
+ else
+ aExtension = ".png";
+ }
+ else if (aGraphicObject.GetType() == GraphicType::GdiMetafile)
+ {
+ // SJ: first check if this metafile is just an eps file, then we will store the eps instead of svm
+ GDIMetaFile& rMetafile(const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()));
+
+ if (ImplCheckForEPS(rMetafile))
+ aExtension = ".eps";
+ else
+ aExtension = ".svm";
+ }
+ }
+
+ OUString rPictureStreamName;
+ if (!rRequestName.empty())
+ {
+ rPictureStreamName = rRequestName + aExtension;
+ }
+ else
+ {
+ OUString sId = OStringToOUString(aGraphicObject.GetUniqueID(), RTL_TEXTENCODING_ASCII_US);
+ rPictureStreamName = sId + aExtension;
+ }
+
+ SvxGraphicHelperStream_Impl aStream(ImplGetGraphicStream(XML_GRAPHICSTORAGE_NAME, rPictureStreamName));
+
+ if (aStream.xStream.is())
+ {
+ const OUString aMimeType(ImplGetGraphicMimeType(rPictureStreamName));
+ uno::Reference<beans::XPropertySet> xProps(aStream.xStream, uno::UNO_QUERY);
+
+ // set stream properties (MediaType/Compression)
+ if (!aMimeType.isEmpty())
+ {
+ xProps->setPropertyValue("MediaType", uno::Any(aMimeType));
+ }
+
+ // picture formats that actually _do_ benefit from zip
+ // storage compression
+ // .svm pics gets compressed via ZBITMAP old-style stream
+ // option below
+ static const char* aCompressiblePics[] =
+ {
+ "image/svg+xml",
+ "image/x-emf",
+ "image/x-wmf",
+ "image/tiff",
+ "image/x-eps",
+ "image/bmp",
+ "image/x-pict"
+ };
+
+ bool bSuccess = false;
+
+ bool bCompressed = aMimeType.isEmpty();
+ if( !bCompressed )
+ {
+ for(const char* p : aCompressiblePics)
+ {
+ if( aMimeType.equalsIgnoreAsciiCaseAscii(p) )
+ {
+ bCompressed = true;
+ break;
+ }
+ }
+ }
+
+ xProps->setPropertyValue("Compressed", Any(bCompressed));
+
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(aStream.xStream));
+ if (bUseGfxLink && aGfxLink.GetDataSize() && aGfxLink.GetData())
+ {
+ pStream->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
+ rOutSavedMimeType = aMimeType;
+ bSuccess = (pStream->GetError() == ERRCODE_NONE);
+ }
+ else
+ {
+ if (aGraphic.GetType() == GraphicType::Bitmap)
+ {
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ OUString aFormat;
+
+ if (aGraphic.IsAnimated())
+ {
+ aFormat = "gif";
+ }
+ else
+ {
+ aFormat = "png";
+ }
+ rOutSavedMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(aFormat.toUtf8());
+
+ bSuccess = (rFilter.ExportGraphic(aGraphic, u"", *pStream, rFilter.GetExportFormatNumberForShortName(aFormat)) == ERRCODE_NONE);
+ }
+ else if (aGraphic.GetType() == GraphicType::GdiMetafile)
+ {
+ pStream->SetVersion(SOFFICE_FILEFORMAT_8);
+ pStream->SetCompressMode(SvStreamCompressFlags::ZBITMAP);
+ rOutSavedMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension("svm");
+
+ // SJ: first check if this metafile is just an eps file, then we will store the eps instead of svm
+ GDIMetaFile& rMtf(const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()));
+ const MetaCommentAction* pComment = ImplCheckForEPS(rMtf);
+ if (pComment)
+ {
+ sal_uInt32 nSize = pComment->GetDataSize();
+ const sal_uInt8* pData = pComment->GetData();
+ if (nSize && pData)
+ pStream->WriteBytes(pData, nSize);
+
+ const MetaEPSAction* pAct = static_cast<const MetaEPSAction*>(rMtf.FirstAction());
+ const GfxLink& rLink = pAct->GetLink();
+
+ pStream->WriteBytes(rLink.GetData(), rLink.GetDataSize());
+ }
+ else
+ {
+ SvmWriter aWriter(*pStream);
+ aWriter.Write(rMtf);
+ }
+
+ bSuccess = (pStream->GetError() == ERRCODE_NONE);
+ }
+ }
+
+ if (!bSuccess)
+ return OUString();
+
+ uno::Reference<embed::XTransactedObject> xStorage(aStream.xStorage, uno::UNO_QUERY);
+ pStream.reset();
+ aStream.xStream->getOutputStream()->closeOutput();
+ if (xStorage.is())
+ xStorage->commit();
+
+ OUString aStoragePath = "Pictures/" + rPictureStreamName;
+
+ // put into cache
+ maExportGraphics[aGraphic] = std::make_pair(aStoragePath, rOutSavedMimeType);
+
+ return aStoragePath;
+ }
+ }
+
+ return OUString();
+}
+
+uno::Reference<io::XInputStream> SAL_CALL SvXMLGraphicHelper::createInputStream(uno::Reference<graphic::XGraphic> const & rxGraphic)
+{
+ Reference<XInputStream> xInputStream;
+
+ Graphic aGraphic(rxGraphic);
+ GraphicObject aGraphicObject(aGraphic);
+
+ if (SvXMLGraphicHelperMode::Write == meCreateMode)
+ {
+ OUString sMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(OUStringToOString(maOutputMimeType, RTL_TEXTENCODING_ASCII_US));
+ rtl::Reference<GraphicInputStream> pInputStream(new GraphicInputStream(aGraphicObject, sMimeType));
+
+ // We release the pointer from unique_ptr and assign it to the input stream return type.
+ // In case the stream doesn't exists, unique_ptr will delete the pointer when we go out of scope.
+ if (pInputStream->exists())
+ xInputStream = pInputStream.get();
+ }
+
+ return xInputStream;
+}
+
+// XBinaryStreamResolver
+Reference< XInputStream > SAL_CALL SvXMLGraphicHelper::getInputStream( const OUString& /*rURL*/ )
+{
+ Reference<XInputStream> xRet;
+ return xRet;
+}
+
+Reference< XOutputStream > SAL_CALL SvXMLGraphicHelper::createOutputStream()
+{
+ Reference< XOutputStream > xRet;
+
+ if( SvXMLGraphicHelperMode::Read == meCreateMode )
+ {
+ rtl::Reference<SvXMLGraphicOutputStream> pOutputStream(new SvXMLGraphicOutputStream);
+
+ if( pOutputStream->Exists() )
+ {
+ xRet = pOutputStream.get();
+ maGrfStms.push_back( xRet );
+ }
+ }
+
+ return xRet;
+}
+
+OUString SAL_CALL SvXMLGraphicHelper::resolveOutputStream( const Reference< XOutputStream >& rxBinaryStream )
+{
+ OUString aRet;
+
+ if( ( SvXMLGraphicHelperMode::Read == meCreateMode ) && rxBinaryStream.is() )
+ {
+ if( ::std::find( maGrfStms.begin(), maGrfStms.end(), rxBinaryStream ) != maGrfStms.end() )
+ {
+ SvXMLGraphicOutputStream* pOStm = static_cast< SvXMLGraphicOutputStream* >( rxBinaryStream.get() );
+
+ if( pOStm )
+ {
+ const GraphicObject& rGrfObj = pOStm->GetGraphicObject();
+ const OUString aId(OStringToOUString(
+ rGrfObj.GetUniqueID(), RTL_TEXTENCODING_ASCII_US));
+
+ if( !aId.isEmpty() )
+ {
+ aRet = XML_GRAPHICOBJECT_URL_BASE + aId;
+ }
+ }
+ }
+ }
+
+ return aRet;
+}
+
+// for instantiation via service manager
+namespace {
+
+namespace impl
+{
+typedef comphelper::WeakComponentImplHelper<lang::XInitialization,
+ document::XGraphicObjectResolver,
+ document::XGraphicStorageHandler,
+ document::XBinaryStreamResolver,
+ lang::XServiceInfo>
+ SvXMLGraphicImportExportHelper_Base;
+
+} // namespace impl
+
+class SvXMLGraphicImportExportHelper :
+ public impl::SvXMLGraphicImportExportHelper_Base
+{
+public:
+ explicit SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode );
+
+protected:
+ // is called from WeakComponentImplHelper when XComponent::dispose() was
+ // called from outside
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // ____ XInitialization ____
+ // one argument is allowed, which is the XStorage
+ virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ // ____ XGraphicObjectResolver ____
+ virtual OUString SAL_CALL resolveGraphicObjectURL( const OUString& aURL ) override;
+
+ // ____ XGraphicStorageHandler ____
+ virtual css::uno::Reference<css::graphic::XGraphic> SAL_CALL
+ loadGraphic(const OUString& aURL) override;
+
+ virtual css::uno::Reference<css::graphic::XGraphic> SAL_CALL
+ loadGraphicFromOutputStream(css::uno::Reference<css::io::XOutputStream> const & rxOutputStream) override;
+
+ virtual OUString SAL_CALL
+ saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic) override;
+
+ virtual OUString SAL_CALL
+ saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic, OUString & rOutSavedMimeType, OUString const & rRequestName) override;
+
+ virtual css::uno::Reference<css::io::XInputStream> SAL_CALL
+ createInputStream(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic) override;
+
+ // ____ XBinaryStreamResolver ____
+ virtual Reference< io::XInputStream > SAL_CALL getInputStream( const OUString& aURL ) override;
+ virtual Reference< io::XOutputStream > SAL_CALL createOutputStream() override;
+ virtual OUString SAL_CALL resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream ) override;
+
+ // ____ XServiceInfo ____
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+private:
+ SvXMLGraphicHelperMode m_eGraphicHelperMode;
+ rtl::Reference<SvXMLGraphicHelper> m_xXMLGraphicHelper;
+};
+
+SvXMLGraphicImportExportHelper::SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode ) :
+ m_eGraphicHelperMode( eMode )
+{}
+
+void SvXMLGraphicImportExportHelper::disposing(std::unique_lock<std::mutex>&)
+{
+ if (m_xXMLGraphicHelper)
+ {
+ m_xXMLGraphicHelper->dispose();
+ m_xXMLGraphicHelper.clear();
+ }
+}
+
+// ____ XInitialization ____
+void SAL_CALL SvXMLGraphicImportExportHelper::initialize(
+ const Sequence< Any >& aArguments )
+{
+ Reference< embed::XStorage > xStorage;
+ if( aArguments.hasElements() )
+ aArguments[0] >>= xStorage;
+
+ m_xXMLGraphicHelper = SvXMLGraphicHelper::Create( xStorage, m_eGraphicHelperMode );
+}
+
+// ____ XGraphicObjectResolver ____
+OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveGraphicObjectURL( const OUString& aURL )
+{
+ return m_xXMLGraphicHelper->resolveGraphicObjectURL( aURL );
+}
+
+// ____ XGraphicStorageHandler ____
+uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicImportExportHelper::loadGraphic(OUString const & rURL)
+{
+ return m_xXMLGraphicHelper->loadGraphic(rURL);
+}
+
+uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicImportExportHelper::loadGraphicFromOutputStream(uno::Reference<io::XOutputStream> const & rxOutputStream)
+{
+ return m_xXMLGraphicHelper->loadGraphicFromOutputStream(rxOutputStream);
+}
+
+OUString SAL_CALL SvXMLGraphicImportExportHelper::saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic)
+{
+ return m_xXMLGraphicHelper->saveGraphic(rxGraphic);
+}
+
+OUString SAL_CALL SvXMLGraphicImportExportHelper::saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
+ OUString & rOutSavedMimeType, OUString const & rRequestName)
+{
+ return m_xXMLGraphicHelper->saveGraphicByName(rxGraphic, rOutSavedMimeType, rRequestName);
+}
+
+uno::Reference<io::XInputStream> SAL_CALL SvXMLGraphicImportExportHelper::createInputStream(uno::Reference<graphic::XGraphic> const & rxGraphic)
+{
+ return m_xXMLGraphicHelper->createInputStream(rxGraphic);
+}
+
+// ____ XBinaryStreamResolver ____
+Reference< io::XInputStream > SAL_CALL SvXMLGraphicImportExportHelper::getInputStream( const OUString& aURL )
+{
+ return m_xXMLGraphicHelper->getInputStream( aURL );
+}
+Reference< io::XOutputStream > SAL_CALL SvXMLGraphicImportExportHelper::createOutputStream()
+{
+ return m_xXMLGraphicHelper->createOutputStream();
+}
+OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream )
+{
+ return m_xXMLGraphicHelper->resolveOutputStream( aBinaryStream );
+}
+
+// ____ XServiceInfo ____
+OUString SAL_CALL SvXMLGraphicImportExportHelper::getImplementationName()
+{
+ if( m_eGraphicHelperMode == SvXMLGraphicHelperMode::Read )
+ return "com.sun.star.comp.Svx.GraphicImportHelper";
+ return "com.sun.star.comp.Svx.GraphicExportHelper";
+}
+
+sal_Bool SAL_CALL SvXMLGraphicImportExportHelper::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL SvXMLGraphicImportExportHelper::getSupportedServiceNames()
+{
+ return { "com.sun.star.document.GraphicObjectResolver",
+ "com.sun.star.document.GraphicStorageHandler",
+ "com.sun.star.document.BinaryStreamResolver" };
+}
+
+}
+
+/** Create this with createInstanceWithArguments. service name
+ "com.sun.star.comp.Svx.GraphicImportHelper", one argument which is the
+ XStorage. Without arguments no helper class is created. With an empty
+ argument the helper class is created and initialized like in the CTOR to
+ SvXMLGraphicHelper that only gets the create mode.
+
+ You should call dispose after you no longer need this component.
+
+ uses eCreateMode == SvXMLGraphicHelperMode::Read, bDirect == sal_True in
+ SvXMLGraphicHelper
+ */
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_Svx_GraphicImportHelper_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SvXMLGraphicImportExportHelper(SvXMLGraphicHelperMode::Read));
+}
+
+/** Create this with createInstanceWithArguments. service name
+ "com.sun.star.comp.Svx.GraphicExportHelper", one argument which is the
+ XStorage. Without arguments no helper class is created. With an empty
+ argument the helper class is created and initialized like in the CTOR to
+ SvXMLGraphicHelper that only gets the create mode
+
+ To write the Pictures stream, you have to call dispose at this component.
+ Make sure you call dispose before you commit the parent storage.
+
+ uses eCreateMode == SvXMLGraphicHelperMode::Write, bDirect == sal_True in
+ SvXMLGraphicHelper
+ */
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_Svx_GraphicExportHelper_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SvXMLGraphicImportExportHelper(SvXMLGraphicHelperMode::Write));
+}
+
+namespace svx {
+
+ void DropUnusedNamedItems(css::uno::Reference<css::uno::XInterface> const& xModel)
+ {
+ uno::Reference<lang::XMultiServiceFactory> const xModelFactory(xModel, uno::UNO_QUERY);
+ assert(xModelFactory.is());
+ try
+ {
+ uno::Reference<util::XCancellable> const xGradient(
+ xModelFactory->createInstance("com.sun.star.drawing.GradientTable"),
+ uno::UNO_QUERY );
+ if (xGradient.is())
+ {
+ xGradient->cancel();
+ }
+
+ uno::Reference<util::XCancellable> const xHatch(
+ xModelFactory->createInstance("com.sun.star.drawing.HatchTable"),
+ uno::UNO_QUERY );
+ if (xHatch.is())
+ {
+ xHatch->cancel();
+ }
+
+ uno::Reference<util::XCancellable> const xBitmap(
+ xModelFactory->createInstance("com.sun.star.drawing.BitmapTable"),
+ uno::UNO_QUERY );
+ if (xBitmap.is())
+ {
+ xBitmap->cancel();
+ }
+
+ uno::Reference<util::XCancellable> const xTransGradient(
+ xModelFactory->createInstance("com.sun.star.drawing.TransparencyGradientTable"),
+ uno::UNO_QUERY );
+ if (xTransGradient.is())
+ {
+ xTransGradient->cancel();
+ }
+
+ uno::Reference<util::XCancellable> const xMarker(
+ xModelFactory->createInstance("com.sun.star.drawing.MarkerTable"),
+ uno::UNO_QUERY );
+ if (xMarker.is())
+ {
+ xMarker->cancel();
+ }
+
+ uno::Reference<util::XCancellable> const xDashes(
+ xModelFactory->createInstance("com.sun.star.drawing.DashTable"),
+ uno::UNO_QUERY );
+ if (xDashes.is())
+ {
+ xDashes->cancel();
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "dropUnusedNamedItems(): exception during clearing of unused named items");
+ }
+ }
+
+} // namespace svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xml/xmlxtexp.cxx b/svx/source/xml/xmlxtexp.cxx
new file mode 100644
index 000000000..103752b05
--- /dev/null
+++ b/svx/source/xml/xmlxtexp.cxx
@@ -0,0 +1,485 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/drawing/LineDash.hpp>
+#include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/drawing/Hatch.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+
+#include <sax/tools/converter.hxx>
+#include <sfx2/docfile.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/namespacemap.hxx>
+
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlmetae.hxx>
+#include <xmloff/DashStyle.hxx>
+#include <xmloff/GradientStyle.hxx>
+#include <xmloff/HatchStyle.hxx>
+#include <xmloff/ImageStyle.hxx>
+#include <xmloff/MarkerStyle.hxx>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <comphelper/processfactory.hxx>
+#include <unotools/streamwrap.hxx>
+#include <svx/xmlgrhlp.hxx>
+
+#include <xmlxtexp.hxx>
+
+#include <comphelper/storagehelper.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+using namespace com::sun::star::container;
+using namespace com::sun::star::document;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::xml::sax;
+using namespace ::xmloff::token;
+using namespace cppu;
+
+using com::sun::star::embed::XTransactedObject;
+
+namespace {
+
+class SvxXMLTableEntryExporter
+{
+public:
+ explicit SvxXMLTableEntryExporter( SvXMLExport& rExport ) : mrExport( rExport ) {}
+ virtual ~SvxXMLTableEntryExporter();
+
+ virtual void exportEntry( const OUString& rStrName, const Any& rValue ) = 0;
+
+protected:
+ SvXMLExport& mrExport;
+};
+
+class SvxXMLColorEntryExporter : public SvxXMLTableEntryExporter
+{
+public:
+ explicit SvxXMLColorEntryExporter( SvXMLExport& rExport );
+
+ virtual void exportEntry( const OUString& rStrName, const Any& rValue ) override;
+};
+
+class SvxXMLLineEndEntryExporter : public SvxXMLTableEntryExporter
+{
+public:
+ explicit SvxXMLLineEndEntryExporter( SvXMLExport& rExport );
+
+ virtual void exportEntry( const OUString& rStrName, const Any& rValue ) override;
+private:
+ XMLMarkerStyleExport maMarkerStyle;
+};
+
+class SvxXMLDashEntryExporter : public SvxXMLTableEntryExporter
+{
+public:
+ explicit SvxXMLDashEntryExporter( SvXMLExport& rExport );
+
+ virtual void exportEntry( const OUString& rStrName, const Any& rValue ) override;
+
+private:
+ XMLDashStyleExport maDashStyle;
+};
+
+class SvxXMLHatchEntryExporter : public SvxXMLTableEntryExporter
+{
+public:
+ explicit SvxXMLHatchEntryExporter( SvXMLExport& rExport );
+
+ virtual void exportEntry( const OUString& rStrName, const Any& rValue ) override;
+private:
+ XMLHatchStyleExport maHatchStyle;
+};
+
+class SvxXMLGradientEntryExporter : public SvxXMLTableEntryExporter
+{
+public:
+ explicit SvxXMLGradientEntryExporter( SvXMLExport& rExport );
+
+ virtual void exportEntry( const OUString& rStrName, const Any& rValue ) override;
+private:
+ XMLGradientStyleExport maGradientStyle;
+};
+
+class SvxXMLBitmapEntryExporter : public SvxXMLTableEntryExporter
+{
+public:
+ explicit SvxXMLBitmapEntryExporter( SvXMLExport& rExport );
+
+ virtual void exportEntry( const OUString& rStrName, const Any& rValue ) override;
+};
+
+}
+
+SvxXMLXTableExportComponent::SvxXMLXTableExportComponent(
+ const css::uno::Reference< css::uno::XComponentContext >& rContext,
+ const uno::Reference<xml::sax::XDocumentHandler> & rHandler,
+ const uno::Reference<container::XNameContainer >& xTable,
+ uno::Reference<document::XGraphicStorageHandler> const & xGraphicStorageHandler)
+: SvXMLExport(rContext, "", /*rFileName*/"", rHandler, nullptr, FieldUnit::MM_100TH, SvXMLExportFlags::NONE),
+ mxTable( xTable )
+{
+
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_OOO), GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO );
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE );
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_DRAW), GetXMLToken(XML_N_DRAW), XML_NAMESPACE_DRAW );
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK );
+ GetNamespaceMap_().Add( GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG), XML_NAMESPACE_SVG );
+ SetGraphicStorageHandler(xGraphicStorageHandler);
+}
+
+SvxXMLXTableExportComponent::~SvxXMLXTableExportComponent()
+{
+}
+
+static void initializeStreamMetadata( const uno::Reference< uno::XInterface > &xOut )
+{
+ uno::Reference< beans::XPropertySet > xProps( xOut, uno::UNO_QUERY );
+ if( !xProps.is() )
+ {
+ OSL_FAIL( "Missing stream metadata interface" );
+ return;
+ }
+
+ try
+ {
+ xProps->setPropertyValue("MediaType", uno::Any( OUString( "text/xml" ) ) );
+
+ // use stock encryption
+ xProps->setPropertyValue("UseCommonStoragePasswordEncryption", uno::Any( true ) );
+ } catch ( const uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION("svx", "exception setting stream metadata");
+ }
+}
+
+static void createStorageStream( uno::Reference < io::XOutputStream > *xOut,
+ rtl::Reference<SvXMLGraphicHelper>& rxGraphicHelper,
+ const uno::Reference < embed::XStorage >& xSubStorage )
+{
+ uno::Reference < io::XStream > xStream = xSubStorage->openStreamElement(
+ "Content.xml",
+ embed::ElementModes::WRITE );
+ rxGraphicHelper = SvXMLGraphicHelper::Create( xSubStorage, SvXMLGraphicHelperMode::Write );
+ initializeStreamMetadata( xStream );
+ *xOut = xStream->getOutputStream();
+}
+
+bool SvxXMLXTableExportComponent::save(
+ const OUString& rURL,
+ const uno::Reference<container::XNameContainer >& xTable,
+ const uno::Reference<embed::XStorage >& xStorage,
+ OUString *pOptName )
+{
+ bool bRet = false;
+ std::unique_ptr<SfxMedium> pMedium;
+ rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
+
+ INetURLObject aURLObj( rURL );
+ bool bToStorage = aURLObj.GetProtocol() == INetProtocol::NotValid; // a relative path
+ bool bSaveAsStorage = xTable->getElementType() == cppu::UnoType<awt::XBitmap>::get();
+
+ if( pOptName )
+ *pOptName = rURL;
+
+ try
+ {
+ uno::Reference< uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+
+ uno::Reference< xml::sax::XWriter > xWriter = xml::sax::Writer::create( xContext );
+
+ uno::Reference < io::XStream > xStream;
+ uno::Reference < io::XOutputStream > xOut;
+ uno::Reference<embed::XStorage > xSubStorage;
+ uno::Reference<XGraphicStorageHandler> xGraphicStorageHandler;
+ const sal_Int32 eCreate = embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE;
+
+ if( !bToStorage || !xStorage.is() )
+ { // local URL -> SfxMedium route
+ if( bSaveAsStorage )
+ xSubStorage = ::comphelper::OStorageHelper::GetStorageFromURL( rURL, eCreate );
+ else
+ {
+ pMedium.reset(new SfxMedium( rURL, StreamMode::WRITE | StreamMode::TRUNC ));
+
+ SvStream* pStream = pMedium->GetOutStream();
+ if( !pStream )
+ {
+ OSL_FAIL( "no output stream!" );
+ return false;
+ }
+
+ xOut = new utl::OOutputStreamWrapper( *pStream );
+ }
+ }
+ else // save into the xSubStorage
+ {
+ OUString aPath = rURL;
+
+ if( bSaveAsStorage )
+ {
+ try {
+ xSubStorage = xStorage->openStorageElement( aPath, eCreate );
+ } catch (uno::Exception &) {
+ OSL_FAIL( "no output storage!" );
+ return false;
+ }
+ }
+ else
+ {
+ aPath += ".xml";
+ try {
+ xStream = xStorage->openStreamElement( aPath, eCreate );
+ if( !xStream.is() )
+ return false;
+ initializeStreamMetadata( xStream );
+ xOut = xStream->getOutputStream();
+ } catch (uno::Exception &) {
+ OSL_FAIL( "no output stream!" );
+ return false;
+ }
+ if( pOptName )
+ *pOptName = aPath;
+ }
+ }
+
+ if( !xOut.is() && xSubStorage.is() )
+ createStorageStream( &xOut, xGraphicHelper, xSubStorage );
+ if( !xOut.is() )
+ return false;
+
+ xWriter->setOutputStream( xOut );
+ if( xGraphicHelper.is() )
+ xGraphicStorageHandler = xGraphicHelper.get();
+
+ // Finally do the export
+ rtl::Reference< SvxXMLXTableExportComponent > xExporter( new SvxXMLXTableExportComponent( xContext, xWriter, xTable, xGraphicStorageHandler ) );
+ bRet = xExporter->exportTable();
+
+ if( xGraphicHelper )
+ xGraphicHelper->dispose();
+ xGraphicHelper.clear();
+
+ if( xSubStorage.is() )
+ {
+ uno::Reference< XTransactedObject > xTrans( xSubStorage, UNO_QUERY );
+ if( xTrans.is() )
+ xTrans->commit();
+
+ xSubStorage->dispose();
+ }
+ }
+ catch( uno::Exception& )
+ {
+ bRet = false;
+ }
+
+ if( pMedium )
+ pMedium->Commit();
+
+ return bRet;
+}
+
+bool SvxXMLXTableExportComponent::exportTable() noexcept
+{
+ bool bRet = false;
+
+ try
+ {
+ GetDocHandler()->startDocument();
+
+ addChaffWhenEncryptedStorage();
+
+ // export namespaces
+ sal_uInt16 nPos = GetNamespaceMap().GetFirstKey();
+ while( USHRT_MAX != nPos )
+ {
+ GetAttrList().AddAttribute( GetNamespaceMap().GetAttrNameByKey( nPos ), GetNamespaceMap().GetNameByKey( nPos ) );
+ nPos = GetNamespaceMap().GetNextKey( nPos );
+ }
+
+ do
+ {
+ if( !mxTable.is() )
+ break;
+
+ char const* pEleName;
+ Type aExportType = mxTable->getElementType();
+ std::unique_ptr<SvxXMLTableEntryExporter> pExporter;
+
+ if( aExportType == cppu::UnoType<sal_Int32>::get() )
+ {
+ pExporter.reset(new SvxXMLColorEntryExporter(*this));
+ pEleName = "color-table";
+ }
+ else if( aExportType == cppu::UnoType< drawing::PolyPolygonBezierCoords >::get() )
+ {
+ pExporter.reset(new SvxXMLLineEndEntryExporter(*this));
+ pEleName = "marker-table";
+ }
+ else if( aExportType == cppu::UnoType< drawing::LineDash >::get() )
+ {
+ pExporter.reset(new SvxXMLDashEntryExporter(*this));
+ pEleName = "dash-table";
+ }
+ else if( aExportType == cppu::UnoType< drawing::Hatch >::get() )
+ {
+ pExporter.reset(new SvxXMLHatchEntryExporter(*this));
+ pEleName = "hatch-table";
+ }
+ else if( aExportType == cppu::UnoType< awt::Gradient >::get() )
+ {
+ pExporter.reset(new SvxXMLGradientEntryExporter(*this));
+ pEleName = "gradient-table";
+ }
+ else if( aExportType == cppu::UnoType<awt::XBitmap>::get())
+ {
+ pExporter.reset(new SvxXMLBitmapEntryExporter(*this));
+ pEleName = "bitmap-table";
+ }
+ else
+ {
+ OSL_FAIL( "unknown type for export");
+ break;
+ }
+
+ SvXMLElementExport aElem( *this, XML_NAMESPACE_OOO, pEleName, true, true );
+
+ const Sequence< OUString > aNames = mxTable->getElementNames();
+ Any aAny;
+
+ for( const OUString& rName : aNames )
+ {
+ aAny = mxTable->getByName( rName );
+ pExporter->exportEntry( rName, aAny );
+ }
+
+ bRet = true;
+ }
+ while(false);
+
+ GetDocHandler()->endDocument();
+ }
+ catch( Exception const& )
+ {
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+// methods without content:
+void SvxXMLXTableExportComponent::ExportAutoStyles_() {}
+void SvxXMLXTableExportComponent::ExportMasterStyles_() {}
+void SvxXMLXTableExportComponent::ExportContent_() {}
+
+
+SvxXMLTableEntryExporter::~SvxXMLTableEntryExporter()
+{
+}
+
+
+SvxXMLColorEntryExporter::SvxXMLColorEntryExporter( SvXMLExport& rExport )
+: SvxXMLTableEntryExporter( rExport )
+{
+}
+
+void SvxXMLColorEntryExporter::exportEntry( const OUString& rStrName, const Any& rValue )
+{
+ mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rStrName );
+
+ sal_Int32 nColor = 0;
+ rValue >>= nColor;
+
+ OUStringBuffer aOut;
+ ::sax::Converter::convertColor( aOut, nColor );
+ mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_COLOR, aOut.makeStringAndClear() );
+
+ SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_COLOR, true, true );
+}
+
+
+SvxXMLLineEndEntryExporter::SvxXMLLineEndEntryExporter( SvXMLExport& rExport )
+: SvxXMLTableEntryExporter( rExport ), maMarkerStyle( rExport )
+{
+}
+
+void SvxXMLLineEndEntryExporter::exportEntry( const OUString& rStrName, const Any& rValue )
+{
+ maMarkerStyle.exportXML( rStrName, rValue );
+}
+
+
+SvxXMLDashEntryExporter::SvxXMLDashEntryExporter( SvXMLExport& rExport )
+: SvxXMLTableEntryExporter( rExport ), maDashStyle( rExport )
+{
+}
+
+void SvxXMLDashEntryExporter::exportEntry( const OUString& rStrName, const Any& rValue )
+{
+ maDashStyle.exportXML( rStrName, rValue );
+}
+
+
+SvxXMLHatchEntryExporter::SvxXMLHatchEntryExporter( SvXMLExport& rExport )
+: SvxXMLTableEntryExporter( rExport ), maHatchStyle( rExport )
+{
+}
+
+void SvxXMLHatchEntryExporter::exportEntry( const OUString& rStrName, const Any& rValue )
+{
+ maHatchStyle.exportXML( rStrName, rValue );
+}
+
+
+SvxXMLGradientEntryExporter::SvxXMLGradientEntryExporter( SvXMLExport& rExport )
+: SvxXMLTableEntryExporter( rExport ), maGradientStyle( rExport )
+{
+}
+
+void SvxXMLGradientEntryExporter::exportEntry( const OUString& rStrName, const Any& rValue )
+{
+ maGradientStyle.exportXML( rStrName, rValue );
+}
+
+
+SvxXMLBitmapEntryExporter::SvxXMLBitmapEntryExporter( SvXMLExport& rExport )
+: SvxXMLTableEntryExporter( rExport )
+{
+}
+
+void SvxXMLBitmapEntryExporter::exportEntry( const OUString& rStrName, const Any& rValue )
+{
+ XMLImageStyle::exportXML(rStrName, rValue, mrExport);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xml/xmlxtimp.cxx b/svx/source/xml/xmlxtimp.cxx
new file mode 100644
index 000000000..9fd5481d5
--- /dev/null
+++ b/svx/source/xml/xmlxtimp.cxx
@@ -0,0 +1,461 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/urlobj.hxx>
+#include <com/sun/star/document/XGraphicStorageHandler.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/drawing/LineDash.hpp>
+#include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/drawing/Hatch.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <sax/tools/converter.hxx>
+#include <sfx2/docfile.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/namespacemap.hxx>
+
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/DashStyle.hxx>
+#include <xmloff/GradientStyle.hxx>
+#include <xmloff/HatchStyle.hxx>
+#include <xmloff/ImageStyle.hxx>
+#include <xmloff/MarkerStyle.hxx>
+#include <xmloff/xmlictxt.hxx>
+#include <svx/xmlgrhlp.hxx>
+
+#include <xmlxtimp.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace com::sun::star;
+using namespace com::sun::star::container;
+using namespace com::sun::star::document;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::xml::sax;
+using namespace ::xmloff::token;
+using namespace cppu;
+
+namespace {
+
+enum class SvxXMLTableImportContextEnum { Color, Marker, Dash, Hatch, Gradient, Bitmap };
+
+class SvxXMLTableImportContext : public SvXMLImportContext
+{
+public:
+ SvxXMLTableImportContext( SvXMLImport& rImport, SvxXMLTableImportContextEnum eContext, const uno::Reference< XNameContainer >& xTable,
+ bool bOOoFormat );
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL
+ createFastChildContext(sal_Int32 Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+protected:
+ static void importColor( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName );
+ void importMarker( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName );
+ void importDash( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName );
+ void importHatch( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName );
+ void importGradient( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName );
+ void importBitmap( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName );
+
+private:
+ uno::Reference< XNameContainer > mxTable;
+ SvxXMLTableImportContextEnum meContext;
+ bool mbOOoFormat;
+};
+
+}
+
+SvxXMLTableImportContext::SvxXMLTableImportContext( SvXMLImport& rImport, SvxXMLTableImportContextEnum eContext, const uno::Reference< XNameContainer >& xTable, bool bOOoFormat )
+: SvXMLImportContext( rImport ), mxTable( xTable ), meContext( eContext ),
+ mbOOoFormat( bOOoFormat )
+{
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler >
+ SvxXMLTableImportContext::createFastChildContext(sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & rAttrList)
+{
+ if( !(IsTokenInNamespace(nElement, XML_NAMESPACE_DRAW) ||
+ IsTokenInNamespace(nElement, XML_NAMESPACE_DRAW_OOO) ))
+ return nullptr;
+
+ std::vector<std::pair<sal_Int32, OString>> aTmpAttrList;
+ for (auto& aIter : sax_fastparser::castToFastAttributeList( rAttrList ))
+ aTmpAttrList.push_back({aIter.getToken(), OString(aIter.toCString())});
+ if( mbOOoFormat &&
+ (SvxXMLTableImportContextEnum::Dash == meContext || SvxXMLTableImportContextEnum::Hatch == meContext ||
+ SvxXMLTableImportContextEnum::Bitmap == meContext) )
+ {
+ for( auto & aIter : aTmpAttrList )
+ {
+ sal_Int32 aLocalAttr = aIter.first & TOKEN_MASK;
+ if( aIter.first == XML_ELEMENT(XLINK, XML_HREF) &&
+ SvxXMLTableImportContextEnum::Bitmap == meContext )
+ {
+ OString& rValue = aIter.second;
+ if( !rValue.isEmpty() && '#' == rValue[0] )
+ rValue = rValue.copy( 1 );
+ }
+ else if( (IsTokenInNamespace(aIter.first, XML_NAMESPACE_DRAW) || IsTokenInNamespace(aIter.first, XML_NAMESPACE_DRAW_OOO)) &&
+ ( ( SvxXMLTableImportContextEnum::Dash == meContext &&
+ ( aLocalAttr == XML_DOTS1_LENGTH ||
+ aLocalAttr == XML_DOTS2_LENGTH ||
+ aLocalAttr == XML_DISTANCE ) ) ||
+ ( SvxXMLTableImportContextEnum::Hatch == meContext &&
+ ( aLocalAttr == XML_DISTANCE ) ) ) )
+ {
+ OString& rValue = aIter.second;
+ sal_Int32 nPos = rValue.getLength();
+ while( nPos && rValue[nPos-1] <= ' ' )
+ --nPos;
+ if( nPos > 2 &&
+ ('c'==rValue[nPos-2] || 'C'==rValue[nPos-2]) &&
+ ('h'==rValue[nPos-1] || 'H'==rValue[nPos-1]) )
+ {
+ rValue = rValue.copy( 0, nPos-2 );
+ }
+ }
+ }
+ }
+ try
+ {
+ rtl::Reference<sax_fastparser::FastAttributeList> xFastList = new sax_fastparser::FastAttributeList(nullptr);
+ for (const auto& aIter : aTmpAttrList)
+ xFastList->add(aIter.first, aIter.second);
+
+ Any aAny;
+ OUString aName;
+
+ switch( meContext )
+ {
+ case SvxXMLTableImportContextEnum::Color:
+ importColor( xFastList, aAny, aName );
+ break;
+ case SvxXMLTableImportContextEnum::Marker:
+ importMarker( xFastList, aAny, aName );
+ break;
+ case SvxXMLTableImportContextEnum::Dash:
+ importDash( xFastList, aAny, aName );
+ break;
+ case SvxXMLTableImportContextEnum::Hatch:
+ importHatch( xFastList, aAny, aName );
+ break;
+ case SvxXMLTableImportContextEnum::Gradient:
+ importGradient( xFastList, aAny, aName );
+ break;
+ case SvxXMLTableImportContextEnum::Bitmap:
+ importBitmap( xFastList, aAny, aName );
+ break;
+ }
+
+ if( !aName.isEmpty() && aAny.hasValue() )
+ {
+ if( mxTable->hasByName( aName ) )
+ {
+ mxTable->replaceByName( aName, aAny );
+ }
+ else
+ {
+ mxTable->insertByName( aName, aAny );
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return new SvXMLImportContext( GetImport() );
+}
+
+void SvxXMLTableImportContext::importColor( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName )
+{
+ for (auto& aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
+ {
+ switch (aIter.getToken())
+ {
+ case XML_ELEMENT(DRAW, XML_NAME):
+ case XML_ELEMENT(DRAW_OOO, XML_NAME):
+ rName = aIter.toString();
+ break;
+ case XML_ELEMENT(DRAW, XML_COLOR):
+ case XML_ELEMENT(DRAW_OOO, XML_COLOR):
+ {
+ sal_Int32 nColor(0);
+ ::sax::Converter::convertColor(nColor, aIter.toView());
+ rAny <<= nColor;
+ break;
+ }
+ default:
+ XMLOFF_WARN_UNKNOWN("xmloff", aIter);
+ }
+ }
+}
+
+void SvxXMLTableImportContext::importMarker( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName )
+{
+ try
+ {
+ XMLMarkerStyleImport aMarkerStyle( GetImport() );
+ aMarkerStyle.importXML( xAttrList, rAny, rName );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+}
+
+void SvxXMLTableImportContext::importDash( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName )
+{
+ try
+ {
+ XMLDashStyleImport aDashStyle( GetImport() );
+ aDashStyle.importXML( xAttrList, rAny, rName );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+}
+
+void SvxXMLTableImportContext::importHatch( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName )
+{
+ try
+ {
+ XMLHatchStyleImport aHatchStyle( GetImport() );
+ aHatchStyle.importXML( xAttrList, rAny, rName );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+}
+
+void SvxXMLTableImportContext::importGradient( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName )
+{
+ try
+ {
+ XMLGradientStyleImport aGradientStyle( GetImport() );
+ aGradientStyle.importXML( xAttrList, rAny, rName );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+}
+
+void SvxXMLTableImportContext::importBitmap( const uno::Reference< XFastAttributeList >& xAttrList, Any& rAny, OUString& rName )
+{
+ try
+ {
+ uno::Any aGraphicAny;
+ XMLImageStyle::importXML(xAttrList, aGraphicAny, rName, GetImport());
+ if (aGraphicAny.has<uno::Reference<graphic::XGraphic>>())
+ {
+ auto xGraphic = aGraphicAny.get<uno::Reference<graphic::XGraphic>>();
+ uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY);
+ if (xBitmap.is())
+ rAny <<= xBitmap;
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "");
+ }
+}
+
+
+SvxXMLXTableImport::SvxXMLXTableImport(
+ const css::uno::Reference< css::uno::XComponentContext >& rContext,
+ const uno::Reference< XNameContainer > & rTable,
+ uno::Reference<XGraphicStorageHandler> const & xGraphicStorageHandler)
+: SvXMLImport(rContext, "", SvXMLImportFlags::NONE),
+ mrTable( rTable )
+{
+ SetGraphicStorageHandler(xGraphicStorageHandler);
+
+ GetNamespaceMap().Add( GetXMLToken(XML_NP_OOO), GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO);
+ GetNamespaceMap().Add( GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE);
+ GetNamespaceMap().Add( GetXMLToken(XML_NP_DRAW), GetXMLToken(XML_N_DRAW), XML_NAMESPACE_DRAW);
+ GetNamespaceMap().Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK);
+
+ GetNamespaceMap().Add( "__ooo", GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO );
+ GetNamespaceMap().Add( "__xlink", GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK );
+
+ // OOo namespaces for reading OOo 1.1 files
+ GetNamespaceMap().Add( "___office",
+ GetXMLToken(XML_N_OFFICE_OOO),
+ XML_NAMESPACE_OFFICE );
+ GetNamespaceMap().Add( "___draw",
+ GetXMLToken(XML_N_DRAW_OOO),
+ XML_NAMESPACE_DRAW );
+}
+
+SvxXMLXTableImport::~SvxXMLXTableImport() noexcept
+{
+}
+
+static void openStorageStream( xml::sax::InputSource *pParserInput,
+ rtl::Reference<SvXMLGraphicHelper>& rxGraphicHelper,
+ const uno::Reference < embed::XStorage >& xStorage )
+{
+ uno::Reference < io::XStream > xIStm( xStorage->openStreamElement( "Content.xml", embed::ElementModes::READ ), uno::UNO_SET_THROW );
+ pParserInput->aInputStream = xIStm->getInputStream();
+ rxGraphicHelper = SvXMLGraphicHelper::Create( xStorage, SvXMLGraphicHelperMode::Read );
+}
+
+bool SvxXMLXTableImport::load( const OUString &rPath, const OUString &rReferer,
+ const uno::Reference < embed::XStorage > &xStorage,
+ const uno::Reference< XNameContainer >& xTable,
+ bool *bOptLoadedFromStorage ) noexcept
+{
+ bool bRet = true;
+ rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
+
+ INetURLObject aURLObj( rPath );
+ bool bUseStorage = aURLObj.GetProtocol() == INetProtocol::NotValid; // a relative path
+
+ try
+ {
+ uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+
+ xml::sax::InputSource aParserInput;
+ comphelper::LifecycleProxy aNasty;
+
+ if( !bUseStorage || !xStorage.is() )
+ {
+ SfxMedium aMedium( rPath, rReferer, StreamMode::READ | StreamMode::NOCREATE );
+ aParserInput.sSystemId = aMedium.GetName();
+
+ if( aMedium.IsStorage() )
+ {
+ uno::Reference < embed::XStorage > xMediumStorage( aMedium.GetStorage( false ), uno::UNO_SET_THROW );
+ openStorageStream( &aParserInput, xGraphicHelper, xMediumStorage );
+ }
+ else
+ aParserInput.aInputStream = aMedium.GetInputStream();
+ }
+ else // relative URL into a storage
+ {
+ uno::Reference< embed::XStorage > xSubStorage;
+ try
+ {
+ xSubStorage = comphelper::OStorageHelper::GetStorageAtPath(
+ xStorage, rPath, embed::ElementModes::READ, aNasty );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ if( xSubStorage.is() )
+ openStorageStream( &aParserInput, xGraphicHelper, xSubStorage );
+ else
+ {
+ css::uno::Reference< css::io::XStream > xStream = comphelper::OStorageHelper::GetStreamAtPath(
+ xStorage, rPath, embed::ElementModes::READ, aNasty );
+ if( !xStream.is() )
+ return false;
+ aParserInput.aInputStream = xStream->getInputStream();
+ }
+ if( bOptLoadedFromStorage )
+ *bOptLoadedFromStorage = true;
+ }
+
+ uno::Reference<XGraphicStorageHandler> xGraphicStorageHandler;
+ if (xGraphicHelper.is())
+ xGraphicStorageHandler = xGraphicHelper.get();
+
+ try
+ {
+ uno::Reference< io::XSeekable > xSeek( aParserInput.aInputStream, uno::UNO_QUERY_THROW );
+ xSeek->seek( 0 );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ rtl::Reference<SvxXMLXTableImport> xImport(new SvxXMLXTableImport(xContext, xTable, xGraphicStorageHandler));
+ xImport->parseStream( aParserInput );
+
+ if( xGraphicHelper )
+ xGraphicHelper->dispose();
+ }
+ catch (...)
+ {
+// thrown each time you load a document with property tables that are not
+// on the current machine. FIXME: would be better to check a file exists
+// before importing ...
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+SvXMLImportContext *SvxXMLXTableImport::CreateFastContext( sal_Int32 nElement,
+ const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& /*xAttrList*/ )
+{
+ if( IsTokenInNamespace(nElement, XML_NAMESPACE_OOO) ||
+ IsTokenInNamespace(nElement, XML_NAMESPACE_OFFICE) ||
+ IsTokenInNamespace(nElement, XML_NAMESPACE_OFFICE_OOO) )
+ {
+ bool bOOoFormat = IsTokenInNamespace(nElement, XML_NAMESPACE_OFFICE) ||
+ IsTokenInNamespace(nElement, XML_NAMESPACE_OFFICE_OOO);
+ Type aType = mrTable->getElementType();
+ sal_Int32 nToken = nElement & TOKEN_MASK;
+
+ if ( nToken == XML_COLOR_TABLE )
+ {
+ if( aType == ::cppu::UnoType<sal_Int32>::get() )
+ return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Color, mrTable, bOOoFormat );
+ }
+ else if ( nToken == XML_MARKER_TABLE )
+ {
+ if( aType == cppu::UnoType<drawing::PolyPolygonBezierCoords>::get())
+ return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Marker, mrTable, bOOoFormat );
+ }
+ else if ( nToken == XML_DASH_TABLE )
+ {
+ if( aType == cppu::UnoType<drawing::LineDash>::get())
+ return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Dash, mrTable, bOOoFormat );
+ }
+ else if ( nToken == XML_HATCH_TABLE )
+ {
+ if( aType == cppu::UnoType<drawing::Hatch>::get())
+ return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Hatch, mrTable, bOOoFormat );
+ }
+ else if ( nToken == XML_GRADIENT_TABLE )
+ {
+ if( aType == cppu::UnoType<awt::Gradient>::get())
+ return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Gradient, mrTable, bOOoFormat );
+ }
+ else if ( nToken == XML_BITMAP_TABLE )
+ {
+ if( aType == ::cppu::UnoType<awt::XBitmap>::get())
+ return new SvxXMLTableImportContext( *this, SvxXMLTableImportContextEnum::Bitmap, mrTable, bOOoFormat );
+ }
+ }
+
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/XPropertyEntry.cxx b/svx/source/xoutdev/XPropertyEntry.cxx
new file mode 100644
index 000000000..0c3d140e8
--- /dev/null
+++ b/svx/source/xoutdev/XPropertyEntry.cxx
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/XPropertyEntry.hxx>
+
+XPropertyEntry::XPropertyEntry(const OUString& rPropEntryName)
+ : maPropEntryName(rPropEntryName)
+{
+}
+
+XPropertyEntry::~XPropertyEntry() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/_xoutbmp.cxx b/svx/source/xoutdev/_xoutbmp.cxx
new file mode 100644
index 000000000..cb690df32
--- /dev/null
+++ b/svx/source/xoutdev/_xoutbmp.cxx
@@ -0,0 +1,389 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <comphelper/base64.hxx>
+#include <comphelper/graphicmimetype.hxx>
+#include <tools/debug.hxx>
+#include <vcl/virdev.hxx>
+#include <sfx2/docfile.hxx>
+#include <svx/xoutbmp.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <memory>
+
+constexpr OUStringLiteral FORMAT_BMP = u"bmp";
+constexpr OUStringLiteral FORMAT_GIF = u"gif";
+constexpr OUStringLiteral FORMAT_JPG = u"jpg";
+constexpr OUStringLiteral FORMAT_PNG = u"png";
+constexpr OUStringLiteral FORMAT_WEBP = u"webp";
+
+using namespace com::sun::star;
+
+Animation XOutBitmap::MirrorAnimation( const Animation& rAnimation, bool bHMirr, bool bVMirr )
+{
+ Animation aNewAnim( rAnimation );
+
+ if( bHMirr || bVMirr )
+ {
+ const Size& rGlobalSize = aNewAnim.GetDisplaySizePixel();
+ BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE;
+
+ if( bHMirr )
+ nMirrorFlags |= BmpMirrorFlags::Horizontal;
+
+ if( bVMirr )
+ nMirrorFlags |= BmpMirrorFlags::Vertical;
+
+ for( sal_uInt16 i = 0, nCount = aNewAnim.Count(); i < nCount; i++ )
+ {
+ AnimationBitmap aAnimationBitmap( aNewAnim.Get( i ) );
+
+ // mirror the BitmapEx
+ aAnimationBitmap.maBitmapEx.Mirror( nMirrorFlags );
+
+ // Adjust the positions inside the whole bitmap
+ if( bHMirr )
+ aAnimationBitmap.maPositionPixel.setX(rGlobalSize.Width() - aAnimationBitmap.maPositionPixel.X() -
+ aAnimationBitmap.maSizePixel.Width());
+
+ if( bVMirr )
+ aAnimationBitmap.maPositionPixel.setY(rGlobalSize.Height() - aAnimationBitmap.maPositionPixel.Y() -
+ aAnimationBitmap.maSizePixel.Height());
+
+ aNewAnim.Replace(aAnimationBitmap, i);
+ }
+ }
+
+ return aNewAnim;
+}
+
+Graphic XOutBitmap::MirrorGraphic( const Graphic& rGraphic, const BmpMirrorFlags nMirrorFlags )
+{
+ Graphic aRetGraphic;
+
+ if( nMirrorFlags != BmpMirrorFlags::NONE )
+ {
+ if( rGraphic.IsAnimated() )
+ {
+ aRetGraphic = MirrorAnimation( rGraphic.GetAnimation(),
+ bool( nMirrorFlags & BmpMirrorFlags::Horizontal ),
+ bool( nMirrorFlags & BmpMirrorFlags::Vertical ) );
+ }
+ else
+ {
+ BitmapEx aBmp( rGraphic.GetBitmapEx() );
+ aBmp.Mirror( nMirrorFlags );
+ aRetGraphic = aBmp;
+ }
+ }
+ else
+ aRetGraphic = rGraphic;
+
+ return aRetGraphic;
+}
+
+ErrCode XOutBitmap::WriteGraphic( const Graphic& rGraphic, OUString& rFileName,
+ const OUString& rFilterName, const XOutFlags nFlags,
+ const Size* pMtfSize_100TH_MM,
+ const css::uno::Sequence< css::beans::PropertyValue >* pFilterData )
+{
+ if( rGraphic.GetType() == GraphicType::NONE )
+ return ERRCODE_NONE;
+
+ INetURLObject aURL( rFileName );
+ Graphic aGraphic;
+ OUString aExt;
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ ErrCode nErr = ERRCODE_GRFILTER_FILTERERROR;
+ bool bTransparent = rGraphic.IsTransparent(), bAnimated = rGraphic.IsAnimated();
+
+ DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "XOutBitmap::WriteGraphic(...): invalid URL" );
+
+ // calculate correct file name
+ if( !( nFlags & XOutFlags::DontExpandFilename ) )
+ {
+ OUString aStr( OUString::number( rGraphic.GetChecksum(), 16 ) );
+ if ( aStr[0] == '-' )
+ aStr = OUString::Concat("m") + aStr.subView(1);
+ OUString aName = aURL.getBase() + "_" + aURL.getExtension() + "_" + aStr;
+ aURL.setBase( aName );
+ }
+
+ // #i121128# use shortcut to write Vector Graphic Data data in original form (if possible)
+ auto const & rVectorGraphicDataPtr(rGraphic.getVectorGraphicData());
+
+ if (rVectorGraphicDataPtr && rVectorGraphicDataPtr->getBinaryDataContainer().getSize())
+ {
+ // Does the filter name match the original format?
+ const bool bIsSvg(rFilterName.equalsIgnoreAsciiCase("svg") && VectorGraphicDataType::Svg == rVectorGraphicDataPtr->getType());
+ const bool bIsWmf(rFilterName.equalsIgnoreAsciiCase("wmf") && VectorGraphicDataType::Wmf == rVectorGraphicDataPtr->getType());
+ bool bIsEmf(rFilterName.equalsIgnoreAsciiCase("emf") && VectorGraphicDataType::Emf == rVectorGraphicDataPtr->getType());
+ if (!bIsEmf)
+ {
+ bIsEmf = rFilterName.equalsIgnoreAsciiCase("emf") && rGraphic.GetGfxLink().IsEMF();
+ }
+ const bool bIsPdf(rFilterName.equalsIgnoreAsciiCase("pdf") && VectorGraphicDataType::Pdf == rVectorGraphicDataPtr->getType());
+
+ if (bIsSvg || bIsWmf || bIsEmf || bIsPdf)
+ {
+ if (!(nFlags & XOutFlags::DontAddExtension))
+ {
+ aURL.setExtension(rFilterName);
+ }
+
+ rFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ SfxMedium aMedium(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::WRITE | StreamMode::SHARE_DENYNONE | StreamMode::TRUNC);
+ SvStream* pOStm = aMedium.GetOutStream();
+
+ if (pOStm)
+ {
+ auto & rDataContainer = rVectorGraphicDataPtr->getBinaryDataContainer();
+ pOStm->WriteBytes(rDataContainer.getData(), rDataContainer.getSize());
+ aMedium.Commit();
+
+ if (!aMedium.GetError())
+ return ERRCODE_NONE;
+ }
+ }
+ }
+
+ if( ( nFlags & XOutFlags::UseNativeIfPossible ) &&
+ !( nFlags & XOutFlags::MirrorHorz ) &&
+ !( nFlags & XOutFlags::MirrorVert ) &&
+ ( rGraphic.GetType() != GraphicType::GdiMetafile ) && rGraphic.IsGfxLink() )
+ {
+ // try to write native link
+ const GfxLink aGfxLink( rGraphic.GetGfxLink() );
+
+ switch( aGfxLink.GetType() )
+ {
+ case GfxLinkType::NativeGif: aExt = FORMAT_GIF; break;
+
+ // #i15508# added BMP type for better exports (no call/trigger found, prob used in HTML export)
+ case GfxLinkType::NativeBmp: aExt = FORMAT_BMP; break;
+
+ case GfxLinkType::NativeJpg: aExt = FORMAT_JPG; break;
+ case GfxLinkType::NativePng: aExt = FORMAT_PNG; break;
+ case GfxLinkType::NativeWebp: aExt = FORMAT_WEBP; break;
+
+ default:
+ break;
+ }
+
+ // tdf#60684: use native format if possible but it must correspond to filter name
+ // or no specific format has been required
+ // without this, you may save for example file with png extension but jpg content
+ if( !aExt.isEmpty() && (aExt == rFilterName || rFilterName.isEmpty()) )
+ {
+ if( !(nFlags & XOutFlags::DontAddExtension) )
+ aURL.setExtension( aExt );
+ rFileName = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ SfxMedium aMedium(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::WRITE | StreamMode::SHARE_DENYNONE | StreamMode::TRUNC);
+ SvStream* pOStm = aMedium.GetOutStream();
+
+ if( pOStm && aGfxLink.GetDataSize() && aGfxLink.GetData() )
+ {
+ pOStm->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
+ aMedium.Commit();
+
+ if( !aMedium.GetError() )
+ return ERRCODE_NONE;
+ }
+ }
+ }
+
+ OUString aFilter( rFilterName );
+ bool bWriteTransGrf = ( aFilter.equalsIgnoreAsciiCase( "transgrf" ) ) ||
+ ( aFilter.equalsIgnoreAsciiCase( "gif" ) ) ||
+ ( nFlags & XOutFlags::UseGifIfPossible ) ||
+ ( ( nFlags & XOutFlags::UseGifIfSensible ) && ( bAnimated || bTransparent ) );
+
+ // get filter and extension
+ if( bWriteTransGrf )
+ aFilter = FORMAT_GIF;
+
+ sal_uInt16 nFilter = rFilter.GetExportFormatNumberForShortName( aFilter );
+
+ if( GRFILTER_FORMAT_NOTFOUND == nFilter )
+ {
+ nFilter = rFilter.GetExportFormatNumberForShortName( FORMAT_PNG );
+
+ if( GRFILTER_FORMAT_NOTFOUND == nFilter )
+ nFilter = rFilter.GetExportFormatNumberForShortName( FORMAT_BMP );
+ }
+
+ if( GRFILTER_FORMAT_NOTFOUND != nFilter )
+ {
+ aExt = rFilter.GetExportFormatShortName( nFilter ).toAsciiLowerCase();
+
+ if( bWriteTransGrf )
+ {
+ if( bAnimated )
+ aGraphic = rGraphic;
+ else
+ {
+ if( pMtfSize_100TH_MM && ( rGraphic.GetType() != GraphicType::Bitmap ) )
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ const Size aSize(pVDev->LogicToPixel(*pMtfSize_100TH_MM, MapMode(MapUnit::Map100thMM)));
+
+ if( pVDev->SetOutputSizePixel( aSize ) )
+ {
+ const Wallpaper aWallpaper( pVDev->GetBackground() );
+ const Point aPt;
+
+ pVDev->SetBackground( Wallpaper( COL_BLACK ) );
+ pVDev->Erase();
+ rGraphic.Draw(*pVDev, aPt, aSize);
+
+ const Bitmap aBitmap( pVDev->GetBitmap( aPt, aSize ) );
+
+ pVDev->SetBackground( aWallpaper );
+ pVDev->Erase();
+ rGraphic.Draw(*pVDev, aPt, aSize);
+
+ pVDev->SetRasterOp( RasterOp::Xor );
+ pVDev->DrawBitmap( aPt, aSize, aBitmap );
+ aGraphic = BitmapEx( aBitmap, pVDev->GetBitmap( aPt, aSize ) );
+ }
+ else
+ aGraphic = rGraphic.GetBitmapEx();
+ }
+ else
+ aGraphic = rGraphic.GetBitmapEx();
+ }
+ }
+ else
+ {
+ if( pMtfSize_100TH_MM && ( rGraphic.GetType() != GraphicType::Bitmap ) )
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ const Size aSize(pVDev->LogicToPixel(*pMtfSize_100TH_MM, MapMode(MapUnit::Map100thMM)));
+
+ if( pVDev->SetOutputSizePixel( aSize ) )
+ {
+ rGraphic.Draw(*pVDev, Point(), aSize);
+ aGraphic = BitmapEx(pVDev->GetBitmap(Point(), aSize));
+ }
+ else
+ aGraphic = rGraphic.GetBitmapEx();
+ }
+ else
+ aGraphic = rGraphic.GetBitmapEx();
+ }
+
+ // mirror?
+ if( ( nFlags & XOutFlags::MirrorHorz ) || ( nFlags & XOutFlags::MirrorVert ) )
+ {
+ BmpMirrorFlags nBmpMirrorFlags = BmpMirrorFlags::NONE;
+ if( nFlags & XOutFlags::MirrorHorz )
+ nBmpMirrorFlags |= BmpMirrorFlags::Horizontal;
+ if( nFlags & XOutFlags::MirrorVert )
+ nBmpMirrorFlags |= BmpMirrorFlags::Vertical;
+ aGraphic = MirrorGraphic( aGraphic, nBmpMirrorFlags );
+ }
+
+ if (aGraphic.GetType() != GraphicType::NONE)
+ {
+ if( !(nFlags & XOutFlags::DontAddExtension) )
+ aURL.setExtension( aExt );
+ rFileName = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ nErr = ExportGraphic( aGraphic, aURL, rFilter, nFilter, pFilterData );
+ }
+ }
+
+ return nErr;
+}
+
+bool XOutBitmap::GraphicToBase64(const Graphic& rGraphic, OUString& rOUString, bool bAddPrefix,
+ ConvertDataFormat aTargetFormat)
+{
+ SvMemoryStream aOStm;
+ GfxLink aLink = rGraphic.GetGfxLink();
+
+ if (aTargetFormat == ConvertDataFormat::Unknown)
+ {
+ switch (aLink.GetType())
+ {
+ case GfxLinkType::NativeJpg:
+ aTargetFormat = ConvertDataFormat::JPG;
+ break;
+ case GfxLinkType::NativePng:
+ aTargetFormat = ConvertDataFormat::PNG;
+ break;
+ case GfxLinkType::NativeSvg:
+ aTargetFormat = ConvertDataFormat::SVG;
+ break;
+ default:
+ // save everything else (including gif) into png
+ aTargetFormat = ConvertDataFormat::PNG;
+ break;
+ }
+ }
+
+ ErrCode nErr = GraphicConverter::Export(aOStm,rGraphic,aTargetFormat);
+ if ( nErr )
+ {
+ SAL_WARN("svx", "XOutBitmap::GraphicToBase64() invalid Graphic? error: " << nErr );
+ return false;
+ }
+ css::uno::Sequence<sal_Int8> aOStmSeq( static_cast<sal_Int8 const *>(aOStm.GetData()),aOStm.TellEnd() );
+ OUStringBuffer aStrBuffer;
+ ::comphelper::Base64::encode(aStrBuffer,aOStmSeq);
+ rOUString = aStrBuffer.makeStringAndClear();
+
+ if (bAddPrefix)
+ {
+ OUString aMimeType
+ = comphelper::GraphicMimeTypeHelper::GetMimeTypeForConvertDataFormat(aTargetFormat);
+ rOUString = aMimeType + ";base64," + rOUString;
+ }
+
+ return true;
+}
+
+ErrCode XOutBitmap::ExportGraphic( const Graphic& rGraphic, const INetURLObject& rURL,
+ GraphicFilter& rFilter, const sal_uInt16 nFormat,
+ const css::uno::Sequence< css::beans::PropertyValue >* pFilterData )
+{
+ DBG_ASSERT( rURL.GetProtocol() != INetProtocol::NotValid, "XOutBitmap::ExportGraphic(...): invalid URL" );
+
+ SfxMedium aMedium( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::SHARE_DENYNONE | StreamMode::TRUNC );
+ SvStream* pOStm = aMedium.GetOutStream();
+ ErrCode nRet = ERRCODE_GRFILTER_IOERROR;
+
+ if( pOStm )
+ {
+ nRet = rFilter.ExportGraphic( rGraphic, rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), *pOStm, nFormat, pFilterData );
+
+ aMedium.Commit();
+
+ if( aMedium.GetError() && ( ERRCODE_NONE == nRet ) )
+ nRet = ERRCODE_GRFILTER_IOERROR;
+ }
+
+ return nRet;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/_xpoly.cxx b/svx/source/xoutdev/_xpoly.cxx
new file mode 100644
index 000000000..4d556b1f9
--- /dev/null
+++ b/svx/source/xoutdev/_xpoly.cxx
@@ -0,0 +1,947 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+
+#include <tools/debug.hxx>
+#include <tools/poly.hxx>
+#include <tools/helpers.hxx>
+#include <tools/gen.hxx>
+
+#include <svx/xpoly.hxx>
+#include <xpolyimp.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/range/b2drange.hxx>
+
+
+ImpXPolygon::ImpXPolygon(sal_uInt16 nInitSize, sal_uInt16 _nResize)
+ : pOldPointAry(nullptr)
+ , bDeleteOldPoints(false)
+ , nSize(0)
+ , nResize(_nResize)
+ , nPoints(0)
+{
+ Resize(nInitSize);
+}
+
+ImpXPolygon::ImpXPolygon( const ImpXPolygon& rImpXPoly )
+ : pOldPointAry(nullptr)
+ , bDeleteOldPoints(false)
+ , nSize(0)
+ , nResize(rImpXPoly.nResize)
+ , nPoints(0)
+{
+ rImpXPoly.CheckPointDelete();
+
+ Resize( rImpXPoly.nSize );
+
+ // copy
+ nPoints = rImpXPoly.nPoints;
+ memcpy( pPointAry.get(), rImpXPoly.pPointAry.get(), nSize*sizeof( Point ) );
+ memcpy( pFlagAry.get(), rImpXPoly.pFlagAry.get(), nSize );
+}
+
+ImpXPolygon::~ImpXPolygon()
+{
+ pPointAry.reset();
+ if ( bDeleteOldPoints )
+ {
+ delete[] pOldPointAry;
+ pOldPointAry = nullptr;
+ }
+}
+
+bool ImpXPolygon::operator==(const ImpXPolygon& rImpXPoly) const
+{
+ return nPoints==rImpXPoly.nPoints &&
+ (nPoints==0 ||
+ (memcmp(pPointAry.get(), rImpXPoly.pPointAry.get(), nPoints*sizeof(Point))==0 &&
+ memcmp(pFlagAry.get(), rImpXPoly.pFlagAry.get(), nPoints)==0));
+}
+
+/** Change polygon size
+ *
+ * @param nNewSize the new size of the polygon
+ * @param bDeletePoints if FALSE, do not delete the point array directly but
+ * wait for the next call before doing so. This prevents
+ * errors with XPoly[n] = XPoly[0] where a resize might
+ * destroy the right side point array too early.
+ */
+void ImpXPolygon::Resize( sal_uInt16 nNewSize, bool bDeletePoints )
+{
+ if( nNewSize == nSize )
+ return;
+
+ PolyFlags* pOldFlagAry = pFlagAry.release();
+ sal_uInt16 nOldSize = nSize;
+
+ CheckPointDelete();
+ pOldPointAry = pPointAry.release();
+
+ // Round the new size to a multiple of nResize, if
+ // the object was not newly created (nSize != 0)
+ if ( nSize != 0 && nNewSize > nSize )
+ {
+ DBG_ASSERT(nResize, "Trying to resize but nResize = 0 !");
+ nNewSize = nSize + ((nNewSize-nSize-1) / nResize + 1) * nResize;
+ }
+ // create point array
+ nSize = nNewSize;
+ pPointAry.reset( new Point[ nSize ] );
+
+ // create flag array
+ pFlagAry.reset( new PolyFlags[ nSize ] );
+ memset( pFlagAry.get(), 0, nSize );
+
+ // copy if needed
+ if (nOldSize)
+ {
+ if( nOldSize < nSize )
+ {
+ memcpy( pPointAry.get(), pOldPointAry, nOldSize*sizeof( Point ) );
+ memcpy( pFlagAry.get(), pOldFlagAry, nOldSize );
+ }
+ else
+ {
+ memcpy( pPointAry.get(), pOldPointAry, nSize*sizeof( Point ) );
+ memcpy( pFlagAry.get(), pOldFlagAry, nSize );
+
+ // adjust number of valid points
+ if( nPoints > nSize )
+ nPoints = nSize;
+ }
+ }
+ if ( bDeletePoints )
+ {
+ delete[] pOldPointAry;
+ pOldPointAry = nullptr;
+ }
+ else
+ bDeleteOldPoints = true;
+ delete[] pOldFlagAry;
+}
+
+void ImpXPolygon::InsertSpace( sal_uInt16 nPos, sal_uInt16 nCount )
+{
+ CheckPointDelete();
+
+ if ( nPos > nPoints )
+ nPos = nPoints;
+
+ // if the polygon is too small then enlarge it
+ if( (nPoints + nCount) > nSize )
+ Resize( nPoints + nCount );
+
+ // If the insert is not at the last position, move everything after backwards
+ if( nPos < nPoints )
+ {
+ sal_uInt16 nMove = nPoints - nPos;
+ memmove( &pPointAry[nPos+nCount], &pPointAry[nPos],
+ nMove * sizeof(Point) );
+ memmove( &pFlagAry[nPos+nCount], &pFlagAry[nPos], nMove );
+ }
+ std::fill(pPointAry.get() + nPos, pPointAry.get() + nPos + nCount, Point());
+ memset( &pFlagAry [nPos], 0, nCount );
+
+ nPoints = nPoints + nCount;
+}
+
+void ImpXPolygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount )
+{
+ CheckPointDelete();
+
+ if( (nPos + nCount) > nPoints )
+ return;
+
+ sal_uInt16 nMove = nPoints - nPos - nCount;
+
+ if( nMove )
+ {
+ memmove( &pPointAry[nPos], &pPointAry[nPos+nCount],
+ nMove * sizeof(Point) );
+ memmove( &pFlagAry[nPos], &pFlagAry[nPos+nCount], nMove );
+ }
+ std::fill(pPointAry.get() + (nPoints - nCount), pPointAry.get() + nPoints, Point());
+ memset( &pFlagAry [nPoints - nCount], 0, nCount );
+ nPoints = nPoints - nCount;
+}
+
+void ImpXPolygon::CheckPointDelete() const
+{
+ if ( bDeleteOldPoints )
+ {
+ delete[] pOldPointAry;
+ const_cast< ImpXPolygon* >(this)->pOldPointAry = nullptr;
+ const_cast< ImpXPolygon* >(this)->bDeleteOldPoints = false;
+ }
+}
+
+XPolygon::XPolygon( sal_uInt16 nSize )
+ : pImpXPolygon( ImpXPolygon( nSize, 16 ) )
+{
+}
+
+XPolygon::XPolygon( const XPolygon& ) = default;
+
+XPolygon::XPolygon( XPolygon&& ) = default;
+
+/// create a XPolygon out of a standard polygon
+XPolygon::XPolygon( const tools::Polygon& rPoly )
+ : pImpXPolygon( rPoly.GetSize() )
+{
+ sal_uInt16 nSize = rPoly.GetSize();
+ pImpXPolygon->nPoints = nSize;
+
+ for( sal_uInt16 i = 0; i < nSize; i++ )
+ {
+ pImpXPolygon->pPointAry[i] = rPoly[i];
+ pImpXPolygon->pFlagAry[i] = rPoly.GetFlags( i );
+ }
+}
+
+/// create a rectangle (also with rounded corners) as a Bézier polygon
+XPolygon::XPolygon(const tools::Rectangle& rRect, tools::Long nRx, tools::Long nRy)
+ : pImpXPolygon( 17 )
+{
+ tools::Long nWh = (rRect.GetWidth() - 1) / 2;
+ tools::Long nHh = (rRect.GetHeight() - 1) / 2;
+
+ if ( nRx > nWh ) nRx = nWh;
+ if ( nRy > nHh ) nRy = nHh;
+
+ // negate Rx => circle clockwise
+ nRx = -nRx;
+
+ // factor for control points of the Bézier curve: 8/3 * (sin(45g) - 0.5)
+ tools::Long nXHdl = static_cast<tools::Long>(0.552284749 * nRx);
+ tools::Long nYHdl = static_cast<tools::Long>(0.552284749 * nRy);
+ sal_uInt16 nPos = 0;
+
+ if ( nRx && nRy )
+ {
+ Point aCenter;
+
+ for (sal_uInt16 nQuad = 0; nQuad < 4; nQuad++)
+ {
+ switch ( nQuad )
+ {
+ case 0: aCenter = rRect.TopLeft();
+ aCenter.AdjustX( -nRx );
+ aCenter.AdjustY(nRy );
+ break;
+ case 1: aCenter = rRect.TopRight();
+ aCenter.AdjustX(nRx );
+ aCenter.AdjustY(nRy );
+ break;
+ case 2: aCenter = rRect.BottomRight();
+ aCenter.AdjustX(nRx );
+ aCenter.AdjustY( -nRy );
+ break;
+ case 3: aCenter = rRect.BottomLeft();
+ aCenter.AdjustX( -nRx );
+ aCenter.AdjustY( -nRy );
+ break;
+ }
+ GenBezArc(aCenter, nRx, nRy, nXHdl, nYHdl, 0_deg100, 9000_deg100, nQuad, nPos);
+ pImpXPolygon->pFlagAry[nPos ] = PolyFlags::Smooth;
+ pImpXPolygon->pFlagAry[nPos+3] = PolyFlags::Smooth;
+ nPos += 4;
+ }
+ }
+ else
+ {
+ pImpXPolygon->pPointAry[nPos++] = rRect.TopLeft();
+ pImpXPolygon->pPointAry[nPos++] = rRect.TopRight();
+ pImpXPolygon->pPointAry[nPos++] = rRect.BottomRight();
+ pImpXPolygon->pPointAry[nPos++] = rRect.BottomLeft();
+ }
+ pImpXPolygon->pPointAry[nPos] = pImpXPolygon->pPointAry[0];
+ pImpXPolygon->nPoints = nPos + 1;
+}
+
+/// create an ellipse (curve) as Bézier polygon
+XPolygon::XPolygon(const Point& rCenter, tools::Long nRx, tools::Long nRy,
+ Degree100 nStartAngle, Degree100 nEndAngle, bool bClose)
+ : pImpXPolygon( 17 )
+{
+ nStartAngle %= 36000_deg100;
+ if ( nEndAngle > 36000_deg100 ) nEndAngle %= 36000_deg100;
+ bool bFull = (nStartAngle == 0_deg100 && nEndAngle == 36000_deg100);
+
+ // factor for control points of the Bézier curve: 8/3 * (sin(45g) - 0.5)
+ tools::Long nXHdl = static_cast<tools::Long>(0.552284749 * nRx);
+ tools::Long nYHdl = static_cast<tools::Long>(0.552284749 * nRy);
+ sal_uInt16 nPos = 0;
+ bool bLoopEnd = false;
+
+ do
+ {
+ Degree100 nA1, nA2;
+ sal_uInt16 nQuad = nStartAngle.get() / 9000;
+ if ( nQuad == 4 ) nQuad = 0;
+ bLoopEnd = CheckAngles(nStartAngle, nEndAngle, nA1, nA2);
+ GenBezArc(rCenter, nRx, nRy, nXHdl, nYHdl, nA1, nA2, nQuad, nPos);
+ nPos += 3;
+ if ( !bLoopEnd )
+ pImpXPolygon->pFlagAry[nPos] = PolyFlags::Smooth;
+
+ } while ( !bLoopEnd );
+
+ // if not a full circle then connect edges with center point if necessary
+ if ( !bFull && bClose )
+ pImpXPolygon->pPointAry[++nPos] = rCenter;
+
+ if ( bFull )
+ {
+ pImpXPolygon->pFlagAry[0 ] = PolyFlags::Smooth;
+ pImpXPolygon->pFlagAry[nPos] = PolyFlags::Smooth;
+ }
+ pImpXPolygon->nPoints = nPos + 1;
+}
+
+XPolygon::~XPolygon() = default;
+
+void XPolygon::SetPointCount( sal_uInt16 nPoints )
+{
+ std::as_const(pImpXPolygon)->CheckPointDelete();
+
+ if( pImpXPolygon->nSize < nPoints )
+ pImpXPolygon->Resize( nPoints );
+
+ if ( nPoints < pImpXPolygon->nPoints )
+ {
+ sal_uInt16 nSize = pImpXPolygon->nPoints - nPoints;
+ std::fill(
+ pImpXPolygon->pPointAry.get() + nPoints, pImpXPolygon->pPointAry.get() + nPoints + nSize, Point());
+ memset( &pImpXPolygon->pFlagAry [nPoints], 0, nSize );
+ }
+ pImpXPolygon->nPoints = nPoints;
+}
+
+sal_uInt16 XPolygon::GetSize() const
+{
+ pImpXPolygon->CheckPointDelete();
+ return pImpXPolygon->nSize;
+}
+
+sal_uInt16 XPolygon::GetPointCount() const
+{
+ pImpXPolygon->CheckPointDelete();
+ return pImpXPolygon->nPoints;
+}
+
+void XPolygon::Insert( sal_uInt16 nPos, const Point& rPt, PolyFlags eFlags )
+{
+ if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints;
+ pImpXPolygon->InsertSpace( nPos, 1 );
+ pImpXPolygon->pPointAry[nPos] = rPt;
+ pImpXPolygon->pFlagAry[nPos] = eFlags;
+}
+
+void XPolygon::Insert( sal_uInt16 nPos, const XPolygon& rXPoly )
+{
+ if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints;
+
+ sal_uInt16 nPoints = rXPoly.GetPointCount();
+
+ pImpXPolygon->InsertSpace( nPos, nPoints );
+
+ memcpy( &(pImpXPolygon->pPointAry[nPos]),
+ rXPoly.pImpXPolygon->pPointAry.get(),
+ nPoints*sizeof( Point ) );
+ memcpy( &(pImpXPolygon->pFlagAry[nPos]),
+ rXPoly.pImpXPolygon->pFlagAry.get(),
+ nPoints );
+}
+
+void XPolygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount )
+{
+ pImpXPolygon->Remove( nPos, nCount );
+}
+
+void XPolygon::Move( tools::Long nHorzMove, tools::Long nVertMove )
+{
+ if ( !nHorzMove && !nVertMove )
+ return;
+
+ // move points
+ sal_uInt16 nCount = pImpXPolygon->nPoints;
+ for ( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ Point* pPt = &(pImpXPolygon->pPointAry[i]);
+ pPt->AdjustX( nHorzMove );
+ pPt->AdjustY( nVertMove );
+ }
+}
+
+tools::Rectangle XPolygon::GetBoundRect() const
+{
+ pImpXPolygon->CheckPointDelete();
+ tools::Rectangle aRetval;
+
+ if(pImpXPolygon->nPoints)
+ {
+ // #i37709#
+ // For historical reasons the control points are not part of the
+ // BoundRect. This makes it necessary to subdivide the polygon to
+ // get a relatively correct BoundRect. Numerically, this is not
+ // correct and never was.
+
+ const basegfx::B2DRange aPolygonRange(basegfx::utils::getRange(getB2DPolygon()));
+ aRetval = tools::Rectangle(
+ FRound(aPolygonRange.getMinX()), FRound(aPolygonRange.getMinY()),
+ FRound(aPolygonRange.getMaxX()), FRound(aPolygonRange.getMaxY()));
+ }
+
+ return aRetval;
+}
+
+const Point& XPolygon::operator[]( sal_uInt16 nPos ) const
+{
+ DBG_ASSERT(nPos < pImpXPolygon->nPoints, "Invalid index at const array access to XPolygon");
+
+ pImpXPolygon->CheckPointDelete();
+ return pImpXPolygon->pPointAry[nPos];
+}
+
+Point& XPolygon::operator[]( sal_uInt16 nPos )
+{
+ std::as_const(pImpXPolygon)->CheckPointDelete();
+
+ if( nPos >= pImpXPolygon->nSize )
+ {
+ DBG_ASSERT(pImpXPolygon->nResize, "Invalid index at array access to XPolygon");
+ pImpXPolygon->Resize(nPos + 1, false);
+ }
+ if( nPos >= pImpXPolygon->nPoints )
+ pImpXPolygon->nPoints = nPos + 1;
+
+ return pImpXPolygon->pPointAry[nPos];
+}
+
+XPolygon& XPolygon::operator=( const XPolygon& ) = default;
+
+XPolygon& XPolygon::operator=( XPolygon&& ) = default;
+
+bool XPolygon::operator==( const XPolygon& rXPoly ) const
+{
+ pImpXPolygon->CheckPointDelete();
+ return rXPoly.pImpXPolygon == pImpXPolygon;
+}
+
+/// get the flags for the point at the given position
+PolyFlags XPolygon::GetFlags( sal_uInt16 nPos ) const
+{
+ pImpXPolygon->CheckPointDelete();
+ return pImpXPolygon->pFlagAry[nPos];
+}
+
+/// set the flags for the point at the given position
+void XPolygon::SetFlags( sal_uInt16 nPos, PolyFlags eFlags )
+{
+ std::as_const(pImpXPolygon)->CheckPointDelete();
+ pImpXPolygon->pFlagAry[nPos] = eFlags;
+}
+
+/// short path to read the CONTROL flag directly (TODO: better explain what the sense behind this flag is!)
+bool XPolygon::IsControl(sal_uInt16 nPos) const
+{
+ return pImpXPolygon->pFlagAry[nPos] == PolyFlags::Control;
+}
+
+/// short path to read the SMOOTH and SYMMTR flag directly (TODO: better explain what the sense behind these flags is!)
+bool XPolygon::IsSmooth(sal_uInt16 nPos) const
+{
+ PolyFlags eFlag = pImpXPolygon->pFlagAry[nPos];
+ return ( eFlag == PolyFlags::Smooth || eFlag == PolyFlags::Symmetric );
+}
+
+/** calculate the euclidean distance between two points
+ *
+ * @param nP1 The first point
+ * @param nP2 The second point
+ */
+double XPolygon::CalcDistance(sal_uInt16 nP1, sal_uInt16 nP2)
+{
+ const Point& rP1 = pImpXPolygon->pPointAry[nP1];
+ const Point& rP2 = pImpXPolygon->pPointAry[nP2];
+ double fDx = rP2.X() - rP1.X();
+ double fDy = rP2.Y() - rP1.Y();
+ return std::hypot(fDx, fDy);
+}
+
+void XPolygon::SubdivideBezier(sal_uInt16 nPos, bool bCalcFirst, double fT)
+{
+ Point* pPoints = pImpXPolygon->pPointAry.get();
+ double fT2 = fT * fT;
+ double fT3 = fT * fT2;
+ double fU = 1.0 - fT;
+ double fU2 = fU * fU;
+ double fU3 = fU * fU2;
+ sal_uInt16 nIdx = nPos;
+ short nPosInc, nIdxInc;
+
+ if ( bCalcFirst )
+ {
+ nPos += 3;
+ nPosInc = -1;
+ nIdxInc = 0;
+ }
+ else
+ {
+ nPosInc = 1;
+ nIdxInc = 1;
+ }
+ pPoints[nPos].setX( static_cast<tools::Long>(fU3 * pPoints[nIdx ].X() +
+ fT * fU2 * pPoints[nIdx+1].X() * 3 +
+ fT2 * fU * pPoints[nIdx+2].X() * 3 +
+ fT3 * pPoints[nIdx+3].X()) );
+ pPoints[nPos].setY( static_cast<tools::Long>(fU3 * pPoints[nIdx ].Y() +
+ fT * fU2 * pPoints[nIdx+1].Y() * 3 +
+ fT2 * fU * pPoints[nIdx+2].Y() * 3 +
+ fT3 * pPoints[nIdx+3].Y()) );
+ nPos = nPos + nPosInc;
+ nIdx = nIdx + nIdxInc;
+ pPoints[nPos].setX( static_cast<tools::Long>(fU2 * pPoints[nIdx ].X() +
+ fT * fU * pPoints[nIdx+1].X() * 2 +
+ fT2 * pPoints[nIdx+2].X()) );
+ pPoints[nPos].setY( static_cast<tools::Long>(fU2 * pPoints[nIdx ].Y() +
+ fT * fU * pPoints[nIdx+1].Y() * 2 +
+ fT2 * pPoints[nIdx+2].Y()) );
+ nPos = nPos + nPosInc;
+ nIdx = nIdx + nIdxInc;
+ pPoints[nPos].setX( static_cast<tools::Long>(fU * pPoints[nIdx ].X() +
+ fT * pPoints[nIdx+1].X()) );
+ pPoints[nPos].setY( static_cast<tools::Long>(fU * pPoints[nIdx ].Y() +
+ fT * pPoints[nIdx+1].Y()) );
+}
+
+/// Generate a Bézier arc
+void XPolygon::GenBezArc(const Point& rCenter, tools::Long nRx, tools::Long nRy,
+ tools::Long nXHdl, tools::Long nYHdl, Degree100 nStart, Degree100 nEnd,
+ sal_uInt16 nQuad, sal_uInt16 nFirst)
+{
+ Point* pPoints = pImpXPolygon->pPointAry.get();
+ pPoints[nFirst ] = rCenter;
+ pPoints[nFirst+3] = rCenter;
+
+ if ( nQuad == 1 || nQuad == 2 )
+ {
+ nRx = -nRx; nXHdl = -nXHdl;
+ }
+ if ( nQuad == 0 || nQuad == 1 )
+ {
+ nRy = -nRy; nYHdl = -nYHdl;
+ }
+
+ if ( nQuad == 0 || nQuad == 2 )
+ {
+ pPoints[nFirst].AdjustX( nRx );
+ pPoints[nFirst+3].AdjustY( nRy );
+ }
+ else
+ {
+ pPoints[nFirst].AdjustY( nRy );
+ pPoints[nFirst+3].AdjustX( nRx );
+ }
+ pPoints[nFirst+1] = pPoints[nFirst];
+ pPoints[nFirst+2] = pPoints[nFirst+3];
+
+ if ( nQuad == 0 || nQuad == 2 )
+ {
+ pPoints[nFirst+1].AdjustY( nYHdl );
+ pPoints[nFirst+2].AdjustX( nXHdl );
+ }
+ else
+ {
+ pPoints[nFirst+1].AdjustX( nXHdl );
+ pPoints[nFirst+2].AdjustY( nYHdl );
+ }
+ if ( nStart > 0_deg100 )
+ SubdivideBezier(nFirst, false, static_cast<double>(nStart.get()) / 9000);
+ if ( nEnd < 9000_deg100 )
+ SubdivideBezier(nFirst, true, static_cast<double>((nEnd-nStart).get()) / (9000_deg100-nStart).get());
+ SetFlags(nFirst+1, PolyFlags::Control);
+ SetFlags(nFirst+2, PolyFlags::Control);
+}
+
+bool XPolygon::CheckAngles(Degree100& nStart, Degree100 nEnd, Degree100& nA1, Degree100& nA2)
+{
+ if ( nStart == 36000_deg100 ) nStart = 0_deg100;
+ if ( nEnd == 0_deg100 ) nEnd = 36000_deg100;
+ Degree100 nStPrev = nStart;
+ Degree100 nMax((nStart.get() / 9000 + 1) * 9000);
+ Degree100 nMin = nMax - 9000_deg100;
+
+ if ( nEnd >= nMax || nEnd <= nStart ) nA2 = 9000_deg100;
+ else nA2 = nEnd - nMin;
+ nA1 = nStart - nMin;
+ nStart = nMax;
+
+ // returns true when the last segment was calculated
+ return (nStPrev < nEnd && nStart >= nEnd);
+}
+
+/** Calculate a smooth transition to connect two Bézier curves
+ *
+ * This is done by projecting the corresponding point onto a line between
+ * two other points.
+ *
+ * @param nCenter The point at the end or beginning of the curve.
+ * If nCenter is at the end of the polygon the point is moved
+ * to the opposite side.
+ * @param nDrag The moved point that specifies the relocation.
+ * @param nPnt The point to modify.
+ */
+void XPolygon::CalcSmoothJoin(sal_uInt16 nCenter, sal_uInt16 nDrag, sal_uInt16 nPnt)
+{
+ // If nPoint is no control point, i.e. cannot be moved, then
+ // move nDrag instead on the line between nCenter and nPnt
+ if ( !IsControl(nPnt) )
+ {
+ sal_uInt16 nTmp = nDrag;
+ nDrag = nPnt;
+ nPnt = nTmp;
+ }
+ Point* pPoints = pImpXPolygon->pPointAry.get();
+ Point aDiff = pPoints[nDrag] - pPoints[nCenter];
+ double fDiv = CalcDistance(nCenter, nDrag);
+
+ if ( fDiv )
+ {
+ double fRatio = CalcDistance(nCenter, nPnt) / fDiv;
+ // keep the length if SMOOTH
+ if ( GetFlags(nCenter) == PolyFlags::Smooth || !IsControl(nDrag) )
+ {
+ aDiff.setX( static_cast<tools::Long>(fRatio * aDiff.X()) );
+ aDiff.setY( static_cast<tools::Long>(fRatio * aDiff.Y()) );
+ }
+ pPoints[nPnt] = pPoints[nCenter] - aDiff;
+ }
+}
+
+/** Calculate tangent between two Bézier curves
+ *
+ * @param nCenter start or end point of the curves
+ * @param nPrev previous reference point
+ * @param nNext next reference point
+ */
+void XPolygon::CalcTangent(sal_uInt16 nCenter, sal_uInt16 nPrev, sal_uInt16 nNext)
+{
+ double fAbsLen = CalcDistance(nNext, nPrev);
+
+ if ( !fAbsLen )
+ return;
+
+ const Point& rCenter = pImpXPolygon->pPointAry[nCenter];
+ Point& rNext = pImpXPolygon->pPointAry[nNext];
+ Point& rPrev = pImpXPolygon->pPointAry[nPrev];
+ Point aDiff = rNext - rPrev;
+ double fNextLen = CalcDistance(nCenter, nNext) / fAbsLen;
+ double fPrevLen = CalcDistance(nCenter, nPrev) / fAbsLen;
+
+ // same length for both sides if SYMMTR
+ if ( GetFlags(nCenter) == PolyFlags::Symmetric )
+ {
+ fPrevLen = (fNextLen + fPrevLen) / 2;
+ fNextLen = fPrevLen;
+ }
+ rNext.setX( rCenter.X() + static_cast<tools::Long>(fNextLen * aDiff.X()) );
+ rNext.setY( rCenter.Y() + static_cast<tools::Long>(fNextLen * aDiff.Y()) );
+ rPrev.setX( rCenter.X() - static_cast<tools::Long>(fPrevLen * aDiff.X()) );
+ rPrev.setY( rCenter.Y() - static_cast<tools::Long>(fPrevLen * aDiff.Y()) );
+}
+
+/// convert four polygon points into a Bézier curve
+void XPolygon::PointsToBezier(sal_uInt16 nFirst)
+{
+ double nFullLength, nPart1Length, nPart2Length;
+ double fX0, fY0, fX1, fY1, fX2, fY2, fX3, fY3;
+ double fTx1, fTx2, fTy1, fTy2;
+ double fT1, fU1, fT2, fU2, fV;
+ Point* pPoints = pImpXPolygon->pPointAry.get();
+
+ if ( nFirst > pImpXPolygon->nPoints - 4 || IsControl(nFirst) ||
+ IsControl(nFirst+1) || IsControl(nFirst+2) || IsControl(nFirst+3) )
+ return;
+
+ fTx1 = pPoints[nFirst+1].X();
+ fTy1 = pPoints[nFirst+1].Y();
+ fTx2 = pPoints[nFirst+2].X();
+ fTy2 = pPoints[nFirst+2].Y();
+ fX0 = pPoints[nFirst ].X();
+ fY0 = pPoints[nFirst ].Y();
+ fX3 = pPoints[nFirst+3].X();
+ fY3 = pPoints[nFirst+3].Y();
+
+ nPart1Length = CalcDistance(nFirst, nFirst+1);
+ nPart2Length = nPart1Length + CalcDistance(nFirst+1, nFirst+2);
+ nFullLength = nPart2Length + CalcDistance(nFirst+2, nFirst+3);
+ if ( nFullLength < 20 )
+ return;
+
+ if ( nPart2Length == nFullLength )
+ nPart2Length -= 1;
+ if ( nPart1Length == nFullLength )
+ nPart1Length = nPart2Length - 1;
+ if ( nPart1Length <= 0 )
+ nPart1Length = 1;
+ if ( nPart2Length <= 0 || nPart2Length == nPart1Length )
+ nPart2Length = nPart1Length + 1;
+
+ fT1 = nPart1Length / nFullLength;
+ fU1 = 1.0 - fT1;
+ fT2 = nPart2Length / nFullLength;
+ fU2 = 1.0 - fT2;
+ fV = 3 * (1.0 - (fT1 * fU2) / (fT2 * fU1));
+
+ fX1 = fTx1 / (fT1 * fU1 * fU1) - fTx2 * fT1 / (fT2 * fT2 * fU1 * fU2);
+ fX1 /= fV;
+ fX1 -= fX0 * ( fU1 / fT1 + fU2 / fT2) / 3;
+ fX1 += fX3 * ( fT1 * fT2 / (fU1 * fU2)) / 3;
+
+ fY1 = fTy1 / (fT1 * fU1 * fU1) - fTy2 * fT1 / (fT2 * fT2 * fU1 * fU2);
+ fY1 /= fV;
+ fY1 -= fY0 * ( fU1 / fT1 + fU2 / fT2) / 3;
+ fY1 += fY3 * ( fT1 * fT2 / (fU1 * fU2)) / 3;
+
+ fX2 = fTx2 / (fT2 * fT2 * fU2 * 3) - fX0 * fU2 * fU2 / ( fT2 * fT2 * 3);
+ fX2 -= fX1 * fU2 / fT2;
+ fX2 -= fX3 * fT2 / (fU2 * 3);
+
+ fY2 = fTy2 / (fT2 * fT2 * fU2 * 3) - fY0 * fU2 * fU2 / ( fT2 * fT2 * 3);
+ fY2 -= fY1 * fU2 / fT2;
+ fY2 -= fY3 * fT2 / (fU2 * 3);
+
+ pPoints[nFirst+1] = Point(static_cast<tools::Long>(fX1), static_cast<tools::Long>(fY1));
+ pPoints[nFirst+2] = Point(static_cast<tools::Long>(fX2), static_cast<tools::Long>(fY2));
+ SetFlags(nFirst+1, PolyFlags::Control);
+ SetFlags(nFirst+2, PolyFlags::Control);
+}
+
+/// scale in X- and/or Y-direction
+void XPolygon::Scale(double fSx, double fSy)
+{
+ std::as_const(pImpXPolygon)->CheckPointDelete();
+
+ sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
+
+ for (sal_uInt16 i = 0; i < nPntCnt; i++)
+ {
+ Point& rPnt = pImpXPolygon->pPointAry[i];
+ rPnt.setX( static_cast<tools::Long>(fSx * rPnt.X()) );
+ rPnt.setY( static_cast<tools::Long>(fSy * rPnt.Y()) );
+ }
+}
+
+/**
+ * Distort a polygon by scaling its coordinates relative to a reference
+ * rectangle into an arbitrary rectangle.
+ *
+ * Mapping between polygon corners and reference rectangle:
+ * 0: top left 0----1
+ * 1: top right | |
+ * 2: bottom right 3----2
+ * 3: bottom left
+ */
+void XPolygon::Distort(const tools::Rectangle& rRefRect,
+ const XPolygon& rDistortedRect)
+{
+ std::as_const(pImpXPolygon)->CheckPointDelete();
+
+ tools::Long Xr, Wr;
+ tools::Long Yr, Hr;
+
+ Xr = rRefRect.Left();
+ Yr = rRefRect.Top();
+ Wr = rRefRect.GetWidth();
+ Hr = rRefRect.GetHeight();
+
+ if ( !Wr || !Hr )
+ return;
+
+ tools::Long X1, X2, X3, X4;
+ tools::Long Y1, Y2, Y3, Y4;
+ DBG_ASSERT(rDistortedRect.pImpXPolygon->nPoints >= 4,
+ "Distort: rectangle too small");
+
+ X1 = rDistortedRect[0].X();
+ Y1 = rDistortedRect[0].Y();
+ X2 = rDistortedRect[1].X();
+ Y2 = rDistortedRect[1].Y();
+ X3 = rDistortedRect[3].X();
+ Y3 = rDistortedRect[3].Y();
+ X4 = rDistortedRect[2].X();
+ Y4 = rDistortedRect[2].Y();
+
+ sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
+
+ for (sal_uInt16 i = 0; i < nPntCnt; i++)
+ {
+ double fTx, fTy, fUx, fUy;
+ Point& rPnt = pImpXPolygon->pPointAry[i];
+
+ fTx = static_cast<double>(rPnt.X() - Xr) / Wr;
+ fTy = static_cast<double>(rPnt.Y() - Yr) / Hr;
+ fUx = 1.0 - fTx;
+ fUy = 1.0 - fTy;
+
+ rPnt.setX( static_cast<tools::Long>( fUy * (fUx * X1 + fTx * X2) +
+ fTy * (fUx * X3 + fTx * X4) ) );
+ rPnt.setY( static_cast<tools::Long>( fUx * (fUy * Y1 + fTy * Y3) +
+ fTx * (fUy * Y2 + fTy * Y4) ) );
+ }
+}
+
+basegfx::B2DPolygon XPolygon::getB2DPolygon() const
+{
+ // #i74631# use tools Polygon class for conversion to not have the code doubled
+ // here. This needs one more conversion but avoids different converters in
+ // the long run
+ const tools::Polygon aSource(GetPointCount(), pImpXPolygon->pPointAry.get(), pImpXPolygon->pFlagAry.get());
+
+ return aSource.getB2DPolygon();
+}
+
+XPolygon::XPolygon(const basegfx::B2DPolygon& rPolygon)
+ : pImpXPolygon( tools::Polygon( rPolygon ).GetSize() )
+{
+ // #i74631# use tools Polygon class for conversion to not have the code doubled
+ // here. This needs one more conversion but avoids different converters in
+ // the long run
+
+ const tools::Polygon aSource(rPolygon);
+ sal_uInt16 nSize = aSource.GetSize();
+ pImpXPolygon->nPoints = nSize;
+
+ for( sal_uInt16 i = 0; i < nSize; i++ )
+ {
+ pImpXPolygon->pPointAry[i] = aSource[i];
+ pImpXPolygon->pFlagAry[i] = aSource.GetFlags( i );
+ }
+}
+
+// XPolyPolygon
+XPolyPolygon::XPolyPolygon() = default;
+
+XPolyPolygon::XPolyPolygon( const XPolyPolygon& ) = default;
+
+XPolyPolygon::XPolyPolygon( XPolyPolygon&& ) = default;
+
+XPolyPolygon::XPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon)
+{
+ for(auto const& rCandidate : rPolyPolygon)
+ {
+ Insert(XPolygon(rCandidate));
+ }
+}
+
+XPolyPolygon::~XPolyPolygon() = default;
+
+void XPolyPolygon::Insert( XPolygon&& rXPoly )
+{
+ pImpXPolyPolygon->aXPolyList.emplace_back( std::move(rXPoly) );
+}
+
+/// insert all XPolygons of a XPolyPolygon
+void XPolyPolygon::Insert( const XPolyPolygon& rXPolyPoly )
+{
+ for ( size_t i = 0; i < rXPolyPoly.Count(); i++)
+ {
+ pImpXPolyPolygon->aXPolyList.emplace_back( rXPolyPoly[i] );
+ }
+}
+
+void XPolyPolygon::Remove( sal_uInt16 nPos )
+{
+ pImpXPolyPolygon->aXPolyList.erase( pImpXPolyPolygon->aXPolyList.begin() + nPos );
+}
+
+const XPolygon& XPolyPolygon::GetObject( sal_uInt16 nPos ) const
+{
+ return pImpXPolyPolygon->aXPolyList[ nPos ];
+}
+
+void XPolyPolygon::Clear()
+{
+ pImpXPolyPolygon->aXPolyList.clear();
+}
+
+sal_uInt16 XPolyPolygon::Count() const
+{
+ return static_cast<sal_uInt16>(pImpXPolyPolygon->aXPolyList.size());
+}
+
+tools::Rectangle XPolyPolygon::GetBoundRect() const
+{
+ size_t nXPoly = pImpXPolyPolygon->aXPolyList.size();
+ tools::Rectangle aRect;
+
+ for ( size_t n = 0; n < nXPoly; n++ )
+ {
+ XPolygon const & rXPoly = pImpXPolyPolygon->aXPolyList[ n ];
+ aRect.Union( rXPoly.GetBoundRect() );
+ }
+
+ return aRect;
+}
+
+XPolygon& XPolyPolygon::operator[]( sal_uInt16 nPos )
+{
+ return pImpXPolyPolygon->aXPolyList[ nPos ];
+}
+
+XPolyPolygon& XPolyPolygon::operator=( const XPolyPolygon& ) = default;
+
+XPolyPolygon& XPolyPolygon::operator=( XPolyPolygon&& ) = default;
+
+/**
+ * Distort a polygon by scaling its coordinates relative to a reference
+ * rectangle into an arbitrary rectangle.
+ *
+ * Mapping between polygon corners and reference rectangle:
+ * 0: top left 0----1
+ * 1: top right | |
+ * 2: bottom right 3----2
+ * 3: bottom left
+ */
+void XPolyPolygon::Distort(const tools::Rectangle& rRefRect,
+ const XPolygon& rDistortedRect)
+{
+ for (size_t i = 0; i < Count(); i++)
+ pImpXPolyPolygon->aXPolyList[ i ].Distort(rRefRect, rDistortedRect);
+}
+
+basegfx::B2DPolyPolygon XPolyPolygon::getB2DPolyPolygon() const
+{
+ basegfx::B2DPolyPolygon aRetval;
+
+ for(sal_uInt16 a(0); a < Count(); a++)
+ {
+ const XPolygon& rPoly = (*this)[a];
+ aRetval.append(rPoly.getB2DPolygon());
+ }
+
+ return aRetval;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xattr.cxx b/svx/source/xoutdev/xattr.cxx
new file mode 100644
index 000000000..aceba42bb
--- /dev/null
+++ b/svx/source/xoutdev/xattr.cxx
@@ -0,0 +1,3118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <utility>
+
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/drawing/Hatch.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/LineDash.hpp>
+#include <com/sun/star/drawing/DashStyle.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <o3tl/string_view.hxx>
+#include <o3tl/any.hxx>
+#include <svl/itempool.hxx>
+#include <editeng/memberids.h>
+#include <tools/mapunit.hxx>
+#include <tools/UnitConversion.hxx>
+#include <osl/diagnose.h>
+
+#include <svx/unoapi.hxx>
+#include <svl/style.hxx>
+
+#include <tools/bigint.hxx>
+#include <svl/itemset.hxx>
+#include <svx/strings.hrc>
+#include <svx/xfillit0.hxx>
+#include <svx/xflasit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnasit.hxx>
+#include <svx/xtextit0.hxx>
+#include <svx/xtable.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xsflclit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnedcit.hxx>
+#include <editeng/itemtype.hxx>
+#include <editeng/eerdll.hxx>
+#include <svx/xdef.hxx>
+#include <svx/unomid.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/xftdiit.hxx>
+#include <svx/xftstit.hxx>
+#include <svx/xftmrit.hxx>
+#include <svx/xftouit.hxx>
+#include <svx/xftshit.hxx>
+#include <svx/xftshcit.hxx>
+#include <svx/xftshxy.hxx>
+#include <svx/xftadit.hxx>
+#include <svx/svddef.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <unotools/intlwrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <string>
+
+#include <boost/property_tree/json_parser.hpp>
+#include <libxml/xmlwriter.h>
+
+using namespace ::com::sun::star;
+
+typedef std::map<OUString, OUString> StringMap;
+
+NameOrIndex::NameOrIndex(TypedWhichId<NameOrIndex> _nWhich, sal_Int32 nIndex) :
+ SfxStringItem(_nWhich, OUString()),
+ nPalIndex(nIndex)
+{
+}
+
+NameOrIndex::NameOrIndex(TypedWhichId<NameOrIndex> _nWhich, const OUString& rName) :
+ SfxStringItem(_nWhich, rName),
+ nPalIndex(-1)
+{
+}
+
+NameOrIndex::NameOrIndex(const NameOrIndex& rNameOrIndex) :
+ SfxStringItem(rNameOrIndex),
+ nPalIndex(rNameOrIndex.nPalIndex)
+{
+}
+
+bool NameOrIndex::operator==(const SfxPoolItem& rItem) const
+{
+ return ( SfxStringItem::operator==(rItem) &&
+ static_cast<const NameOrIndex&>(rItem).nPalIndex == nPalIndex );
+}
+
+NameOrIndex* NameOrIndex::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new NameOrIndex(*this);
+}
+
+/** this static checks if the given NameOrIndex item has a unique name for its value.
+ The returned String is a unique name for an item with this value in both given pools.
+ Argument pPool2 can be null.
+ If returned string equals NameOrIndex->GetName(), the name was already unique.
+*/
+OUString NameOrIndex::CheckNamedItem( const NameOrIndex* pCheckItem, const sal_uInt16 nWhich, const SfxItemPool* pPool1, SvxCompareValueFunc pCompareValueFunc, TranslateId pPrefixResId, const XPropertyListRef &pDefaults )
+{
+ bool bForceNew = false;
+
+ OUString aUniqueName = SvxUnogetInternalNameForItem(nWhich, pCheckItem->GetName());
+
+ // 2. if we have a name check if there is already an item with the
+ // same name in the documents pool with a different line end or start
+
+ if (!aUniqueName.isEmpty() && pPool1)
+ {
+ for (const SfxPoolItem* pItem : pPool1->GetItemSurrogates(nWhich))
+ {
+ const NameOrIndex *pNameOrIndex = static_cast<const NameOrIndex*>(pItem);
+
+ if( pNameOrIndex->GetName() == pCheckItem->GetName() )
+ {
+ // if there is already an item with the same name and the same
+ // value it's ok to set it
+ if( !pCompareValueFunc( pNameOrIndex, pCheckItem ) )
+ {
+ // same name but different value, we need a new name for this item
+ aUniqueName.clear();
+ bForceNew = true;
+ }
+ break;
+ }
+ }
+ }
+
+ // if we have no name yet, find existing item with same content or
+ // create a unique name
+ if (aUniqueName.isEmpty())
+ {
+ sal_Int32 nUserIndex = 1;
+ const OUString aUser(SvxResId(pPrefixResId) + " ");
+
+ if( pDefaults )
+ {
+ const int nCount = pDefaults->Count();
+ int nIndex;
+ for( nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ const XPropertyEntry* pEntry = pDefaults->Get(nIndex);
+ if( pEntry )
+ {
+ bool bFound = false;
+
+ switch( nWhich )
+ {
+ case XATTR_FILLBITMAP:
+ {
+ const GraphicObject& rGraphicObjectA(static_cast<const XFillBitmapItem*>(pCheckItem)->GetGraphicObject());
+ const GraphicObject& rGraphicObjectB(static_cast<const XBitmapEntry*>(pEntry)->GetGraphicObject());
+
+ bFound = (rGraphicObjectA == rGraphicObjectB);
+ break;
+ }
+ case XATTR_LINEDASH:
+ bFound = static_cast<const XLineDashItem*>(pCheckItem)->GetDashValue() == static_cast<const XDashEntry*>(pEntry)->GetDash();
+ break;
+ case XATTR_LINESTART:
+ bFound = static_cast<const XLineStartItem*>(pCheckItem)->GetLineStartValue() == static_cast<const XLineEndEntry*>(pEntry)->GetLineEnd();
+ break;
+ case XATTR_LINEEND:
+ bFound = static_cast<const XLineEndItem*>(pCheckItem)->GetLineEndValue() == static_cast<const XLineEndEntry*>(pEntry)->GetLineEnd();
+ break;
+ case XATTR_FILLGRADIENT:
+ bFound = static_cast<const XFillGradientItem*>(pCheckItem)->GetGradientValue() == static_cast<const XGradientEntry*>(pEntry)->GetGradient();
+ break;
+ case XATTR_FILLHATCH:
+ bFound = static_cast<const XFillHatchItem*>(pCheckItem)->GetHatchValue() == static_cast<const XHatchEntry*>(pEntry)->GetHatch();
+ break;
+ }
+
+ if( bFound )
+ {
+ aUniqueName = pEntry->GetName();
+ break;
+ }
+ else
+ {
+ const OUString& aEntryName = pEntry->GetName();
+ if(aEntryName.getLength() >= aUser.getLength())
+ {
+ sal_Int32 nThisIndex = o3tl::toInt32(aEntryName.subView( aUser.getLength() ));
+ if( nThisIndex >= nUserIndex )
+ nUserIndex = nThisIndex + 1;
+ }
+ }
+ }
+ }
+ }
+
+ if (aUniqueName.isEmpty() && pPool1)
+ {
+ for (const SfxPoolItem* pItem : pPool1->GetItemSurrogates(nWhich))
+ {
+ const NameOrIndex *pNameOrIndex = static_cast<const NameOrIndex*>(pItem);
+
+ if( !pNameOrIndex->GetName().isEmpty() )
+ {
+ if( !bForceNew && pCompareValueFunc( pNameOrIndex, pCheckItem ) )
+ return pNameOrIndex->GetName();
+
+ if( pNameOrIndex->GetName().startsWith( aUser ) )
+ {
+ sal_Int32 nThisIndex = o3tl::toInt32(pNameOrIndex->GetName().subView( aUser.getLength() ));
+ if( nThisIndex >= nUserIndex )
+ nUserIndex = nThisIndex + 1;
+ }
+ }
+ }
+ aUniqueName = aUser + OUString::number( nUserIndex );
+ }
+ }
+
+ return aUniqueName;
+}
+
+void NameOrIndex::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("NameOrIndex"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("isIndex"), BAD_CAST(OString::boolean(IsIndex()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("name"), BAD_CAST(GetName().toUtf8().getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("index"), BAD_CAST(OString::number(nPalIndex).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+SfxPoolItem* XColorItem::CreateDefault() { return new XColorItem; }
+
+XColorItem::XColorItem(TypedWhichId<XColorItem> _nWhich, sal_Int32 nIndex, const Color& rTheColor) :
+ NameOrIndex(_nWhich, nIndex),
+ aColor(rTheColor)
+{
+}
+
+XColorItem::XColorItem(TypedWhichId<XColorItem> _nWhich, const OUString& rName, const Color& rTheColor) :
+ NameOrIndex(_nWhich, rName),
+ aColor(rTheColor)
+{
+}
+
+XColorItem::XColorItem(TypedWhichId<XColorItem> _nWhich, const Color& rTheColor)
+ : NameOrIndex(_nWhich, OUString())
+ , aColor(rTheColor)
+{
+}
+
+XColorItem::XColorItem(const XColorItem& rItem) :
+ NameOrIndex(rItem),
+ aColor(rItem.aColor),
+ maThemeColor(rItem.maThemeColor)
+{
+}
+
+XColorItem* XColorItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XColorItem(*this);
+}
+
+bool XColorItem::operator==(const SfxPoolItem& rItem) const
+{
+ return ( NameOrIndex::operator==(rItem) &&
+ static_cast<const XColorItem&>(rItem).aColor == aColor ) &&
+ static_cast<const XColorItem&>(rItem).maThemeColor == maThemeColor;
+}
+
+const Color& XColorItem::GetColorValue() const
+{
+ assert(!IsIndex());
+ return aColor;
+
+}
+
+bool XColorItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= GetColorValue().GetRGBColor();
+ return true;
+}
+
+bool XColorItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ Color nValue;
+ rVal >>= nValue;
+ SetColorValue( nValue );
+
+ return true;
+}
+
+void XColorItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XColorItem"));
+ if (Which() == SDRATTR_SHADOWCOLOR)
+ {
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST("SDRATTR_SHADOWCOLOR"));
+ }
+ else if (Which() == XATTR_FILLCOLOR)
+ {
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST("XATTR_FILLCOLOR"));
+ }
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("aColor"),
+ BAD_CAST(aColor.AsRGBHexString().toUtf8().getStr()));
+
+ NameOrIndex::dumpAsXml(pWriter);
+
+ maThemeColor.dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+// --- line attributes ---
+
+
+SfxPoolItem* XLineStyleItem::CreateDefault() { return new XLineStyleItem; }
+
+XLineStyleItem::XLineStyleItem(css::drawing::LineStyle eTheLineStyle) :
+ SfxEnumItem(XATTR_LINESTYLE, eTheLineStyle)
+{
+}
+
+XLineStyleItem* XLineStyleItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineStyleItem( *this );
+}
+
+bool XLineStyleItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+
+ TranslateId pId;
+
+ switch( GetValue() )
+ {
+ case css::drawing::LineStyle_NONE:
+ pId = RID_SVXSTR_INVISIBLE;
+ break;
+ case css::drawing::LineStyle_SOLID:
+ pId = RID_SVXSTR_SOLID;
+ break;
+ default: break;
+ }
+
+ if (pId)
+ rText = SvxResId(pId);
+ return true;
+}
+
+bool XLineStyleItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ css::drawing::LineStyle eLS = GetValue();
+ rVal <<= eLS;
+ return true;
+}
+
+bool XLineStyleItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ css::drawing::LineStyle eLS;
+ if(!(rVal >>= eLS ))
+ {
+ // also try an int (for Basic)
+ sal_Int32 nLS = 0;
+ if(!(rVal >>= nLS))
+ return false;
+ eLS = static_cast<css::drawing::LineStyle>(nLS);
+ }
+
+ SetValue( eLS );
+ return true;
+}
+
+sal_uInt16 XLineStyleItem::GetValueCount() const
+{
+ return 3;
+}
+
+XDash::XDash(css::drawing::DashStyle eTheDash, sal_uInt16 nTheDots, double nTheDotLen,
+ sal_uInt16 nTheDashes, double nTheDashLen, double nTheDistance) :
+ eDash(eTheDash),
+ nDots(nTheDots),
+ nDashes(nTheDashes),
+ nDotLen(nTheDotLen),
+ nDashLen(nTheDashLen),
+ nDistance(nTheDistance)
+{
+}
+
+bool XDash::operator==(const XDash& rDash) const
+{
+ return ( eDash == rDash.eDash &&
+ nDots == rDash.nDots &&
+ nDotLen == rDash.nDotLen &&
+ nDashes == rDash.nDashes &&
+ nDashLen == rDash.nDashLen &&
+ nDistance == rDash.nDistance );
+}
+
+// XDash is translated into an array of doubles which describe the lengths of the
+// dashes, dots and empty passages. It returns the complete length of the full DashDot
+// sequence and fills the given vetor of doubles accordingly (also resizing, so deleting it).
+const double SMALLEST_DASH_WIDTH(26.95);
+
+double XDash::CreateDotDashArray(::std::vector< double >& rDotDashArray, double fLineWidth) const
+{
+ double fFullDotDashLen(0.0);
+ const sal_uInt16 nNumDotDashArray = (GetDots() + GetDashes()) * 2;
+ rDotDashArray.resize( nNumDotDashArray, 0.0 );
+ sal_uInt16 a;
+ sal_uInt16 nIns(0);
+ double fDashDotDistance = GetDistance();
+ double fSingleDashLen = GetDashLen();
+ double fSingleDotLen = GetDotLen();
+
+ if (fLineWidth == 0.0)
+ fLineWidth = SMALLEST_DASH_WIDTH;
+
+ if(GetDashStyle() == css::drawing::DashStyle_RECTRELATIVE || GetDashStyle() == css::drawing::DashStyle_ROUNDRELATIVE)
+ {
+ double fFactor = fLineWidth / 100.0;
+
+ if(GetDashes())
+ {
+ if(GetDashLen())
+ {
+ // is a dash
+ fSingleDashLen *= fFactor;
+ }
+ else
+ {
+ // is a dot
+ fSingleDashLen = fLineWidth;
+ }
+ }
+
+ if(GetDots())
+ {
+ if(GetDotLen())
+ {
+ // is a dash
+ fSingleDotLen *= fFactor;
+ }
+ else
+ {
+ // is a dot
+ fSingleDotLen = fLineWidth;
+ }
+ }
+
+ if(GetDashes() || GetDots())
+ {
+ if(GetDistance())
+ {
+ // dash as distance
+ fDashDotDistance *= fFactor;
+ }
+ else
+ {
+ // dot as distance
+ fDashDotDistance = fLineWidth;
+ }
+ }
+ }
+ else
+ {
+ // absolute values
+ if(GetDashes())
+ {
+ if(GetDashLen())
+ {
+ // is a dash
+ if(fSingleDashLen < SMALLEST_DASH_WIDTH)
+ {
+ fSingleDashLen = SMALLEST_DASH_WIDTH;
+ }
+ }
+ else
+ {
+ // is a dot
+ if(fSingleDashLen < fLineWidth)
+ {
+ fSingleDashLen = fLineWidth;
+ }
+ }
+ }
+
+ if(GetDots())
+ {
+ if(GetDotLen())
+ {
+ // is a dash
+ if(fSingleDotLen < SMALLEST_DASH_WIDTH)
+ {
+ fSingleDotLen = SMALLEST_DASH_WIDTH;
+ }
+ }
+ else
+ {
+ // is a dot
+ if(fSingleDotLen < fLineWidth)
+ {
+ fSingleDotLen = fLineWidth;
+ }
+ }
+ }
+
+ if(GetDashes() || GetDots())
+ {
+ if(GetDistance())
+ {
+ // dash as distance
+ if(fDashDotDistance < SMALLEST_DASH_WIDTH)
+ {
+ fDashDotDistance = SMALLEST_DASH_WIDTH;
+ }
+ }
+ else
+ {
+ // dot as distance
+ if(fDashDotDistance < fLineWidth)
+ {
+ fDashDotDistance = fLineWidth;
+ }
+ }
+ }
+ }
+
+ for(a=0;a<GetDots();a++)
+ {
+ rDotDashArray[nIns++] = fSingleDotLen;
+ fFullDotDashLen += fSingleDotLen;
+ rDotDashArray[nIns++] = fDashDotDistance;
+ fFullDotDashLen += fDashDotDistance;
+ }
+
+ for(a=0;a<GetDashes();a++)
+ {
+ rDotDashArray[nIns++] = fSingleDashLen;
+ fFullDotDashLen += fSingleDashLen;
+ rDotDashArray[nIns++] = fDashDotDistance;
+ fFullDotDashLen += fDashDotDistance;
+ }
+
+ return fFullDotDashLen;
+}
+
+SfxPoolItem* XLineDashItem::CreateDefault() {return new XLineDashItem;}
+
+XLineDashItem::XLineDashItem(const OUString& rName, const XDash& rTheDash) :
+ NameOrIndex(XATTR_LINEDASH, rName),
+ aDash(rTheDash)
+{
+}
+
+XLineDashItem::XLineDashItem(const XLineDashItem& rItem) :
+ NameOrIndex(rItem),
+ aDash(rItem.aDash)
+{
+}
+
+XLineDashItem::XLineDashItem(const XDash& rTheDash)
+: NameOrIndex( XATTR_LINEDASH, -1 ),
+ aDash(rTheDash)
+{
+}
+
+XLineDashItem* XLineDashItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineDashItem(*this);
+}
+
+bool XLineDashItem::operator==(const SfxPoolItem& rItem) const
+{
+ return ( NameOrIndex::operator==(rItem) &&
+ aDash == static_cast<const XLineDashItem&>(rItem).aDash );
+}
+
+bool XLineDashItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = GetName();
+ return true;
+}
+
+bool XLineDashItem::HasMetrics() const
+{
+ return true;
+}
+
+void XLineDashItem::ScaleMetrics(tools::Long nMul, tools::Long nDiv)
+{
+ aDash.SetDotLen( BigInt::Scale( aDash.GetDotLen(), nMul, nDiv ) );
+ aDash.SetDashLen( BigInt::Scale( aDash.GetDashLen(), nMul, nDiv ) );
+ aDash.SetDistance( BigInt::Scale( aDash.GetDistance(), nMul, nDiv ) );
+}
+
+bool XLineDashItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ switch ( nMemberId )
+ {
+ case 0:
+ {
+ css::drawing::LineDash aLineDash;
+
+ const XDash& rXD = GetDashValue();
+ aLineDash.Style = static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(rXD.GetDashStyle()));
+ aLineDash.Dots = rXD.GetDots();
+ aLineDash.DotLen = rXD.GetDotLen();
+ aLineDash.Dashes = rXD.GetDashes();
+ aLineDash.DashLen = rXD.GetDashLen();
+ aLineDash.Distance = rXD.GetDistance();
+
+ uno::Sequence< beans::PropertyValue > aPropSeq{
+ comphelper::makePropertyValue("Name", SvxUnogetApiNameForItem(Which(), GetName())),
+ comphelper::makePropertyValue("LineDash", aLineDash)
+ };
+ rVal <<= aPropSeq;
+ break;
+ }
+
+ case MID_NAME:
+ {
+ rVal <<= SvxUnogetApiNameForItem(Which(), GetName());
+ break;
+ }
+
+ case MID_LINEDASH:
+ {
+ const XDash& rXD = GetDashValue();
+
+ css::drawing::LineDash aLineDash;
+
+ aLineDash.Style = static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(rXD.GetDashStyle()));
+ aLineDash.Dots = rXD.GetDots();
+ aLineDash.DotLen = rXD.GetDotLen();
+ aLineDash.Dashes = rXD.GetDashes();
+ aLineDash.DashLen = rXD.GetDashLen();
+ aLineDash.Distance = rXD.GetDistance();
+
+ rVal <<= aLineDash;
+ break;
+ }
+
+ case MID_LINEDASH_STYLE:
+ {
+ const XDash& rXD = GetDashValue();
+ rVal <<= static_cast<css::drawing::DashStyle>(static_cast<sal_Int16>(rXD.GetDashStyle()));
+ break;
+ }
+
+ case MID_LINEDASH_DOTS:
+ {
+ const XDash& rXD = GetDashValue();
+ rVal <<= rXD.GetDots();
+ break;
+ }
+
+ case MID_LINEDASH_DOTLEN:
+ {
+ const XDash& rXD = GetDashValue();
+ rVal <<= rXD.GetDotLen();
+ break;
+ }
+
+ case MID_LINEDASH_DASHES:
+ {
+ const XDash& rXD = GetDashValue();
+ rVal <<= rXD.GetDashes();
+ break;
+ }
+
+ case MID_LINEDASH_DASHLEN:
+ {
+ const XDash& rXD = GetDashValue();
+ rVal <<= rXD.GetDashLen();
+ break;
+ }
+
+ case MID_LINEDASH_DISTANCE:
+ {
+ const XDash& rXD = GetDashValue();
+ rVal <<= rXD.GetDistance();
+ break;
+ }
+
+ default: OSL_FAIL("Wrong MemberId!"); return false;
+ }
+
+ return true;
+}
+
+bool XLineDashItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ switch ( nMemberId )
+ {
+ case 0:
+ {
+ uno::Sequence< beans::PropertyValue > aPropSeq;
+
+ if ( rVal >>= aPropSeq )
+ {
+ css::drawing::LineDash aLineDash;
+ OUString aName;
+ bool bLineDash( false );
+ for ( const auto& rProp : std::as_const(aPropSeq) )
+ {
+ if ( rProp.Name == "Name" )
+ rProp.Value >>= aName;
+ else if ( rProp.Name == "LineDash" )
+ {
+ if ( rProp.Value >>= aLineDash )
+ bLineDash = true;
+ }
+ }
+
+ SetName( aName );
+ if ( bLineDash )
+ {
+ XDash aXDash;
+
+ aXDash.SetDashStyle(static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(aLineDash.Style)));
+ aXDash.SetDots(aLineDash.Dots);
+ aXDash.SetDotLen(aLineDash.DotLen);
+ aXDash.SetDashes(aLineDash.Dashes);
+ aXDash.SetDashLen(aLineDash.DashLen);
+ aXDash.SetDistance(aLineDash.Distance);
+
+ if((0 == aXDash.GetDots()) && (0 == aXDash.GetDashes()))
+ aXDash.SetDots(1);
+
+ SetDashValue( aXDash );
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ case MID_NAME:
+ {
+ OUString aName;
+ if (!(rVal >>= aName))
+ return false;
+ SetName( aName );
+ break;
+ }
+
+ case MID_LINEDASH:
+ {
+ css::drawing::LineDash aLineDash;
+ if(!(rVal >>= aLineDash))
+ return false;
+
+ XDash aXDash;
+
+ aXDash.SetDashStyle(static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(aLineDash.Style)));
+ aXDash.SetDots(aLineDash.Dots);
+ aXDash.SetDotLen(aLineDash.DotLen);
+ aXDash.SetDashes(aLineDash.Dashes);
+ aXDash.SetDashLen(aLineDash.DashLen);
+ aXDash.SetDistance(aLineDash.Distance);
+
+ if((0 == aXDash.GetDots()) && (0 == aXDash.GetDashes()))
+ aXDash.SetDots(1);
+
+ SetDashValue( aXDash );
+ break;
+ }
+
+ case MID_LINEDASH_STYLE:
+ {
+ sal_Int16 nVal = sal_Int16();
+ if(!(rVal >>= nVal))
+ return false;
+
+ XDash aXDash = GetDashValue();
+ aXDash.SetDashStyle(static_cast<css::drawing::DashStyle>(static_cast<sal_uInt16>(nVal)));
+
+ if((0 == aXDash.GetDots()) && (0 == aXDash.GetDashes()))
+ aXDash.SetDots(1);
+
+ SetDashValue( aXDash );
+
+ break;
+ }
+
+ case MID_LINEDASH_DOTS:
+ case MID_LINEDASH_DASHES:
+ {
+ sal_Int16 nVal = sal_Int16();
+ if(!(rVal >>= nVal))
+ return false;
+
+ XDash aXDash = GetDashValue();
+ if ( nMemberId == MID_LINEDASH_DOTS )
+ aXDash.SetDots( nVal );
+ else
+ aXDash.SetDashes( nVal );
+
+ if((0 == aXDash.GetDots()) && (0 == aXDash.GetDashes()))
+ aXDash.SetDots(1);
+
+ SetDashValue( aXDash );
+ break;
+ }
+
+ case MID_LINEDASH_DOTLEN:
+ case MID_LINEDASH_DASHLEN:
+ case MID_LINEDASH_DISTANCE:
+ {
+ sal_uInt32 nVal = 0;
+ if(!(rVal >>= nVal))
+ return false;
+
+ XDash aXDash = GetDashValue();
+ if ( nMemberId == MID_LINEDASH_DOTLEN )
+ aXDash.SetDotLen( nVal );
+ else if ( nMemberId == MID_LINEDASH_DASHLEN )
+ aXDash.SetDashLen( nVal );
+ else
+ aXDash.SetDistance( nVal );
+
+ if((0 == aXDash.GetDots()) && (0 == aXDash.GetDashes()))
+ aXDash.SetDots(1);
+
+ SetDashValue( aXDash );
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool XLineDashItem::CompareValueFunc( const NameOrIndex* p1, const NameOrIndex* p2 )
+{
+ return static_cast<const XLineDashItem*>(p1)->GetDashValue() == static_cast<const XLineDashItem*>(p2)->GetDashValue();
+}
+
+std::unique_ptr<XLineDashItem> XLineDashItem::checkForUniqueItem( SdrModel* pModel ) const
+{
+ if( pModel )
+ {
+ const OUString aUniqueName = NameOrIndex::CheckNamedItem(
+ this, XATTR_LINEDASH, &pModel->GetItemPool(),
+ XLineDashItem::CompareValueFunc, RID_SVXSTR_DASH20,
+ pModel->GetPropertyList( XPropertyListType::Dash ) );
+
+ // if the given name is not valid, replace it!
+ if( aUniqueName != GetName() )
+ return std::make_unique<XLineDashItem>( aUniqueName, aDash );
+ }
+
+ return nullptr;
+}
+
+SfxPoolItem* XLineWidthItem::CreateDefault() {return new XLineWidthItem;}
+
+XLineWidthItem::XLineWidthItem(tools::Long nWidth) :
+ SfxMetricItem(XATTR_LINEWIDTH, nWidth)
+{
+}
+
+XLineWidthItem* XLineWidthItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineWidthItem(*this);
+}
+
+bool XLineWidthItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit eCoreUnit,
+ MapUnit ePresUnit,
+ OUString& rText, const IntlWrapper& rIntl
+) const
+{
+ rText = GetMetricText( static_cast<tools::Long>(GetValue()),
+ eCoreUnit, ePresUnit, &rIntl) +
+ " " + EditResId( GetMetricId( ePresUnit) );
+ return true;
+}
+
+bool XLineWidthItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ sal_Int32 nValue = GetValue();
+ if( 0 != (nMemberId&CONVERT_TWIPS) )
+ nValue = convertTwipToMm100(nValue);
+
+ rVal <<= nValue;
+ return true;
+}
+
+bool XLineWidthItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ sal_Int32 nValue = 0;
+ rVal >>= nValue;
+ if( 0 != (nMemberId&CONVERT_TWIPS) )
+ nValue = o3tl::toTwips(nValue, o3tl::Length::mm100);
+
+ SetValue( nValue );
+ return true;
+}
+
+SfxPoolItem* XLineColorItem::CreateDefault() { return new XLineColorItem; }
+
+XLineColorItem::XLineColorItem(sal_Int32 nIndex, const Color& rTheColor) :
+ XColorItem(XATTR_LINECOLOR, nIndex, rTheColor)
+{
+}
+
+XLineColorItem::XLineColorItem(const OUString& rName, const Color& rTheColor) :
+ XColorItem(XATTR_LINECOLOR, rName, rTheColor)
+{
+}
+
+XLineColorItem* XLineColorItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineColorItem(*this);
+}
+
+bool XLineColorItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = GetName();
+ return true;
+}
+
+bool XLineColorItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= GetColorValue().GetRGBColor();
+ return true;
+}
+
+bool XLineColorItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nValue = 0;
+ if(!(rVal >>= nValue))
+ return false;
+
+ SetColorValue( Color(ColorTransparency, nValue) );
+ return true;
+}
+
+
+SfxPoolItem* XLineStartItem::CreateDefault() {return new XLineStartItem;}
+
+XLineStartItem::XLineStartItem(sal_Int32 nIndex)
+: NameOrIndex(XATTR_LINESTART, nIndex)
+{
+}
+
+XLineStartItem::XLineStartItem(const OUString& rName, const basegfx::B2DPolyPolygon& rPolyPolygon)
+: NameOrIndex(XATTR_LINESTART, rName),
+ maPolyPolygon(rPolyPolygon)
+{
+}
+
+XLineStartItem::XLineStartItem(const XLineStartItem& rItem)
+: NameOrIndex(rItem),
+ maPolyPolygon(rItem.maPolyPolygon)
+{
+}
+
+XLineStartItem::XLineStartItem(const basegfx::B2DPolyPolygon& rPolyPolygon)
+: NameOrIndex( XATTR_LINESTART, -1 ),
+ maPolyPolygon(rPolyPolygon)
+{
+}
+
+XLineStartItem* XLineStartItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineStartItem(*this);
+}
+
+bool XLineStartItem::operator==(const SfxPoolItem& rItem) const
+{
+ return ( NameOrIndex::operator==(rItem) && static_cast<const XLineStartItem&>(rItem).maPolyPolygon == maPolyPolygon );
+}
+
+bool XLineStartItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = GetName();
+ return true;
+}
+
+bool XLineStartItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ if( nMemberId == MID_NAME )
+ {
+ rVal <<= SvxUnogetApiNameForItem(Which(), GetName());
+ }
+ else
+ {
+ css::drawing::PolyPolygonBezierCoords aBezier;
+ basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( maPolyPolygon, aBezier );
+ rVal <<= aBezier;
+ }
+
+ return true;
+}
+
+bool XLineStartItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ if( nMemberId == MID_NAME )
+ {
+ return false;
+ }
+ else
+ {
+ maPolyPolygon.clear();
+
+ if( rVal.hasValue() )
+ {
+ auto pCoords = o3tl::tryAccess<css::drawing::PolyPolygonBezierCoords>(
+ rVal);
+ if( !pCoords )
+ return false;
+
+ if( pCoords->Coordinates.getLength() > 0 )
+ {
+ maPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( *pCoords );
+ // #i72807# close line start/end polygons hard
+ // maPolyPolygon.setClosed(true);
+ }
+ }
+ }
+
+ return true;
+}
+
+/** this function searches in both the models pool and the styles pool for XLineStartItem
+ and XLineEndItem with the same value or name and returns an item with the value of
+ this item and a unique name for an item with this value. */
+std::unique_ptr<XLineStartItem> XLineStartItem::checkForUniqueItem( SdrModel* pModel ) const
+{
+ if( pModel )
+ {
+ std::unique_ptr<XLineStartItem> pTempItem;
+ const XLineStartItem* pLineStartItem = this;
+
+ OUString aUniqueName( GetName() );
+
+ if( !maPolyPolygon.count() )
+ {
+ // if the polygon is empty, check if the name is empty
+ if( aUniqueName.isEmpty() )
+ return nullptr;
+
+ // force empty name for empty polygons
+ return std::make_unique<XLineStartItem>( "", maPolyPolygon );
+ }
+
+ if( maPolyPolygon.count() > 1 )
+ {
+ // check if the polygon is closed
+ if(!maPolyPolygon.isClosed())
+ {
+ // force a closed polygon
+ basegfx::B2DPolyPolygon aNew(maPolyPolygon);
+ aNew.setClosed(true);
+ pTempItem.reset(new XLineStartItem( aUniqueName, aNew ));
+ pLineStartItem = pTempItem.get();
+ }
+ }
+
+ bool bForceNew = false;
+
+ // 2. if we have a name check if there is already an item with the
+ // same name in the documents pool with a different line end or start
+
+ const SfxItemPool& rPool1 = pModel->GetItemPool();
+ if (!aUniqueName.isEmpty())
+ {
+ for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINESTART))
+ {
+ auto pItem = dynamic_cast<const XLineStartItem*>(p);
+
+ if( pItem && ( pItem->GetName() == pLineStartItem->GetName() ) )
+ {
+ // if there is already an item with the same name and the same
+ // value it's ok to set it
+ if( pItem->GetLineStartValue() != pLineStartItem->GetLineStartValue() )
+ {
+ // same name but different value, we need a new name for this item
+ aUniqueName.clear();
+ bForceNew = true;
+ }
+ break;
+ }
+ }
+
+ if( !bForceNew )
+ {
+ for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINEEND))
+ {
+ auto pItem = dynamic_cast<const XLineEndItem*>(p);
+
+ if( pItem && ( pItem->GetName() == pLineStartItem->GetName() ) )
+ {
+ // if there is already an item with the same name and the same
+ // value it's ok to set it
+ if( pItem->GetLineEndValue() != pLineStartItem->GetLineStartValue() )
+ {
+ // same name but different value, we need a new name for this item
+ aUniqueName.clear();
+ bForceNew = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ const SfxItemPool* pPool2 = pModel->GetStyleSheetPool() ? &pModel->GetStyleSheetPool()->GetPool() : nullptr;
+ if( !aUniqueName.isEmpty() && pPool2)
+ {
+ for (const SfxPoolItem* p : pPool2->GetItemSurrogates(XATTR_LINESTART))
+ {
+ auto pItem = dynamic_cast<const XLineStartItem*>(p);
+
+ if( pItem && ( pItem->GetName() == pLineStartItem->GetName() ) )
+ {
+ // if there is already an item with the same name and the same
+ // value it's ok to set it
+ if( pItem->GetLineStartValue() != pLineStartItem->GetLineStartValue() )
+ {
+ // same name but different value, we need a new name for this item
+ aUniqueName.clear();
+ bForceNew = true;
+ }
+ break;
+ }
+ }
+
+ if( !bForceNew )
+ {
+ for (const SfxPoolItem* p : pPool2->GetItemSurrogates(XATTR_LINEEND))
+ {
+ auto pItem = dynamic_cast<const XLineEndItem*>(p);
+
+ if( pItem && ( pItem->GetName() == pLineStartItem->GetName() ) )
+ {
+ // if there is already an item with the same name and the same
+ // value it's ok to set it
+ if( pItem->GetLineEndValue() != pLineStartItem->GetLineStartValue() )
+ {
+ // same name but different value, we need a new name for this item
+ aUniqueName.clear();
+ bForceNew = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // if we have no name yet, find existing item with same content or
+ // create a unique name
+ if( aUniqueName.isEmpty() )
+ {
+ bool bFoundExisting = false;
+
+ sal_Int32 nUserIndex = 1;
+ const OUString aUser(SvxResId(RID_SVXSTR_LINEEND));
+
+ for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINESTART))
+ {
+ auto pItem = dynamic_cast<const XLineStartItem*>(p);
+
+ if (pItem && !pItem->GetName().isEmpty())
+ {
+ if (!bForceNew && pItem->GetLineStartValue() == pLineStartItem->GetLineStartValue())
+ {
+ aUniqueName = pItem->GetName();
+ bFoundExisting = true;
+ break;
+ }
+
+ if (pItem->GetName().startsWith(aUser))
+ {
+ sal_Int32 nThisIndex = o3tl::toInt32(pItem->GetName().subView(aUser.getLength()));
+ if (nThisIndex >= nUserIndex)
+ nUserIndex = nThisIndex + 1;
+ }
+ }
+ }
+
+ for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINEEND))
+ {
+ auto pItem = dynamic_cast<const XLineEndItem*>(p);
+
+ if (pItem && !pItem->GetName().isEmpty())
+ {
+ if (!bForceNew && pItem->GetLineEndValue() == pLineStartItem->GetLineStartValue())
+ {
+ aUniqueName = pItem->GetName();
+ bFoundExisting = true;
+ break;
+ }
+
+ if (pItem->GetName().startsWith(aUser))
+ {
+ sal_Int32 nThisIndex = o3tl::toInt32(pItem->GetName().subView(aUser.getLength()));
+ if (nThisIndex >= nUserIndex)
+ nUserIndex = nThisIndex + 1;
+ }
+ }
+ }
+
+ if( !bFoundExisting )
+ {
+ aUniqueName = aUser + " " + OUString::number( nUserIndex );
+ }
+ }
+
+ // if the given name is not valid, replace it!
+ if( aUniqueName != GetName() || pTempItem )
+ {
+ if( pTempItem )
+ {
+ pTempItem->SetName( aUniqueName );
+ return pTempItem;
+ }
+ else
+ {
+ return std::make_unique<XLineStartItem>( aUniqueName, maPolyPolygon );
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+SfxPoolItem* XLineEndItem::CreateDefault() {return new XLineEndItem;}
+
+XLineEndItem::XLineEndItem(sal_Int32 nIndex)
+: NameOrIndex(XATTR_LINEEND, nIndex)
+{
+}
+
+XLineEndItem::XLineEndItem(const OUString& rName, const basegfx::B2DPolyPolygon& rPolyPolygon)
+: NameOrIndex(XATTR_LINEEND, rName),
+ maPolyPolygon(rPolyPolygon)
+{
+}
+
+XLineEndItem::XLineEndItem(const XLineEndItem& rItem)
+: NameOrIndex(rItem),
+ maPolyPolygon(rItem.maPolyPolygon)
+{
+}
+
+XLineEndItem::XLineEndItem(const basegfx::B2DPolyPolygon& rPolyPolygon)
+: NameOrIndex( XATTR_LINEEND, -1 ),
+ maPolyPolygon(rPolyPolygon)
+{
+}
+
+XLineEndItem* XLineEndItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineEndItem(*this);
+}
+
+bool XLineEndItem::operator==(const SfxPoolItem& rItem) const
+{
+ return ( NameOrIndex::operator==(rItem) && static_cast<const XLineEndItem&>(rItem).maPolyPolygon == maPolyPolygon );
+}
+
+
+/** this function searches in both the models pool and the styles pool for XLineStartItem
+ and XLineEndItem with the same value or name and returns an item with the value of
+ this item and a unique name for an item with this value. */
+std::unique_ptr<XLineEndItem> XLineEndItem::checkForUniqueItem( SdrModel* pModel ) const
+{
+ if( pModel )
+ {
+ std::unique_ptr<XLineEndItem> pTempItem;
+ const XLineEndItem* pLineEndItem = this;
+
+ OUString aUniqueName( GetName() );
+
+ if( !maPolyPolygon.count() )
+ {
+ // if the polygon is empty, check if the name is empty
+ if( aUniqueName.isEmpty() )
+ return nullptr;
+
+ // force empty name for empty polygons
+ return std::make_unique<XLineEndItem>( "", maPolyPolygon );
+ }
+
+ if( maPolyPolygon.count() > 1 )
+ {
+ // check if the polygon is closed
+ if(!maPolyPolygon.isClosed())
+ {
+ // force a closed polygon
+ basegfx::B2DPolyPolygon aNew(maPolyPolygon);
+ aNew.setClosed(true);
+ pTempItem.reset(new XLineEndItem( aUniqueName, aNew ));
+ pLineEndItem = pTempItem.get();
+ }
+ }
+
+ bool bForceNew = false;
+
+ // 2. if we have a name check if there is already an item with the
+ // same name in the documents pool with a different line end or start
+
+ const SfxItemPool& rPool1 = pModel->GetItemPool();
+ if (!aUniqueName.isEmpty())
+ {
+ for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINESTART))
+ {
+ auto pItem = dynamic_cast<const XLineStartItem*>(p);
+
+ if( pItem && ( pItem->GetName() == pLineEndItem->GetName() ) )
+ {
+ // if there is already an item with the same name and the same
+ // value it's ok to set it
+ if( pItem->GetLineStartValue() != pLineEndItem->GetLineEndValue() )
+ {
+ // same name but different value, we need a new name for this item
+ aUniqueName.clear();
+ bForceNew = true;
+ }
+ break;
+ }
+ }
+
+ if( !bForceNew )
+ {
+ for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINEEND))
+ {
+ auto pItem = dynamic_cast<const XLineEndItem*>(p);
+
+ if( pItem && ( pItem->GetName() == pLineEndItem->GetName() ) )
+ {
+ // if there is already an item with the same name and the same
+ // value it's ok to set it
+ if( pItem->GetLineEndValue() != pLineEndItem->GetLineEndValue() )
+ {
+ // same name but different value, we need a new name for this item
+ aUniqueName.clear();
+ bForceNew = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ const SfxItemPool* pPool2 = pModel->GetStyleSheetPool() ? &pModel->GetStyleSheetPool()->GetPool() : nullptr;
+ if( !aUniqueName.isEmpty() && pPool2)
+ {
+ for (const SfxPoolItem* p : pPool2->GetItemSurrogates(XATTR_LINESTART))
+ {
+ auto pItem = dynamic_cast<const XLineStartItem*>(p);
+
+ if( pItem && ( pItem->GetName() == pLineEndItem->GetName() ) )
+ {
+ // if there is already an item with the same name and the same
+ // value it's ok to set it
+ if( pItem->GetLineStartValue() != pLineEndItem->GetLineEndValue() )
+ {
+ // same name but different value, we need a new name for this item
+ aUniqueName.clear();
+ bForceNew = true;
+ }
+ break;
+ }
+ }
+
+ if( !bForceNew )
+ {
+ for (const SfxPoolItem* p : pPool2->GetItemSurrogates(XATTR_LINEEND))
+ {
+ auto pItem = dynamic_cast<const XLineEndItem*>(p);
+
+ if( pItem && ( pItem->GetName() == pLineEndItem->GetName() ) )
+ {
+ // if there is already an item with the same name and the same
+ // value it's ok to set it
+ if( pItem->GetLineEndValue() != pLineEndItem->GetLineEndValue() )
+ {
+ // same name but different value, we need a new name for this item
+ aUniqueName.clear();
+ bForceNew = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // if we have no name yet, find existing item with same content or
+ // create a unique name
+ if( aUniqueName.isEmpty() )
+ {
+ bool bFoundExisting = false;
+
+ sal_Int32 nUserIndex = 1;
+ const OUString aUser(SvxResId(RID_SVXSTR_LINEEND));
+
+ for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINESTART))
+ {
+ auto pItem = dynamic_cast<const XLineStartItem*>(p);
+
+ if (pItem && !pItem->GetName().isEmpty())
+ {
+ if (!bForceNew && pItem->GetLineStartValue() == pLineEndItem->GetLineEndValue())
+ {
+ aUniqueName = pItem->GetName();
+ bFoundExisting = true;
+ break;
+ }
+
+ if (pItem->GetName().startsWith(aUser))
+ {
+ sal_Int32 nThisIndex = o3tl::toInt32(pItem->GetName().subView(aUser.getLength()));
+ if (nThisIndex >= nUserIndex)
+ nUserIndex = nThisIndex + 1;
+ }
+ }
+ }
+
+ for (const SfxPoolItem* p : rPool1.GetItemSurrogates(XATTR_LINEEND))
+ {
+ auto pItem = dynamic_cast<const XLineEndItem*>(p);
+
+ if (pItem && !pItem->GetName().isEmpty())
+ {
+ if (!bForceNew && pItem->GetLineEndValue() == pLineEndItem->GetLineEndValue())
+ {
+ aUniqueName = pItem->GetName();
+ bFoundExisting = true;
+ break;
+ }
+
+ if (pItem->GetName().startsWith(aUser))
+ {
+ sal_Int32 nThisIndex = o3tl::toInt32(pItem->GetName().subView(aUser.getLength()));
+ if (nThisIndex >= nUserIndex)
+ nUserIndex = nThisIndex + 1;
+ }
+ }
+ }
+
+ if( !bFoundExisting )
+ {
+ aUniqueName = aUser + " " + OUString::number( nUserIndex );
+ }
+ }
+
+ // if the given name is not valid, replace it!
+ if( aUniqueName != GetName() || pTempItem )
+ {
+ if( pTempItem )
+ {
+ pTempItem->SetName( aUniqueName );
+ return pTempItem;
+ }
+ else
+ {
+ return std::make_unique<XLineEndItem>( aUniqueName, maPolyPolygon );
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+bool XLineEndItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = GetName();
+ return true;
+}
+
+bool XLineEndItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ if( nMemberId == MID_NAME )
+ {
+ rVal <<= SvxUnogetApiNameForItem(Which(), GetName());
+ }
+ else
+ {
+ css::drawing::PolyPolygonBezierCoords aBezier;
+ basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( maPolyPolygon, aBezier );
+ rVal <<= aBezier;
+ }
+ return true;
+}
+
+bool XLineEndItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ if( nMemberId == MID_NAME )
+ {
+ return false;
+ }
+ else
+ {
+ maPolyPolygon.clear();
+
+ if( rVal.hasValue() )
+ {
+ auto pCoords = o3tl::tryAccess<css::drawing::PolyPolygonBezierCoords>(
+ rVal);
+ if( !pCoords )
+ return false;
+
+ if( pCoords->Coordinates.getLength() > 0 )
+ {
+ maPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( *pCoords );
+ // #i72807# close line start/end polygons hard
+ // maPolyPolygon.setClosed(true);
+ }
+ }
+ }
+
+ return true;
+}
+
+XLineStartWidthItem::XLineStartWidthItem(tools::Long nWidth) :
+ SfxMetricItem(XATTR_LINESTARTWIDTH, nWidth)
+{
+}
+
+XLineStartWidthItem* XLineStartWidthItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineStartWidthItem(*this);
+}
+
+bool XLineStartWidthItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit eCoreUnit,
+ MapUnit ePresUnit,
+ OUString& rText, const IntlWrapper& rIntl
+) const
+{
+ rText = GetMetricText( static_cast<tools::Long>(GetValue()),
+ eCoreUnit, ePresUnit, &rIntl) +
+ " " + EditResId( GetMetricId( ePresUnit) );
+ return true;
+}
+
+bool XLineStartWidthItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= GetValue();
+ return true;
+}
+
+bool XLineStartWidthItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nValue = 0;
+ rVal >>= nValue;
+ SetValue( nValue );
+ return true;
+}
+
+XLineEndWidthItem::XLineEndWidthItem(tools::Long nWidth) :
+ SfxMetricItem(XATTR_LINEENDWIDTH, nWidth)
+{
+}
+
+XLineEndWidthItem* XLineEndWidthItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineEndWidthItem(*this);
+}
+
+bool XLineEndWidthItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit eCoreUnit,
+ MapUnit ePresUnit,
+ OUString& rText, const IntlWrapper& rIntl
+) const
+{
+ rText = GetMetricText( static_cast<tools::Long>(GetValue()),
+ eCoreUnit, ePresUnit, &rIntl) +
+ " " + EditResId( GetMetricId( ePresUnit) );
+ return true;
+}
+
+bool XLineEndWidthItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= GetValue();
+ return true;
+}
+
+bool XLineEndWidthItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nValue = 0;
+ rVal >>= nValue;
+ SetValue( nValue );
+ return true;
+}
+
+XLineStartCenterItem::XLineStartCenterItem(bool bStartCenter) :
+ SfxBoolItem(XATTR_LINESTARTCENTER, bStartCenter)
+{
+}
+
+XLineStartCenterItem* XLineStartCenterItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineStartCenterItem(*this);
+}
+
+bool XLineStartCenterItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = SvxResId(GetValue() ? RID_SVXSTR_CENTERED : RID_SVXSTR_NOTCENTERED);
+ return true;
+}
+
+bool XLineStartCenterItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ bool bValue = GetValue();
+ rVal <<= bValue;
+ return true;
+}
+
+bool XLineStartCenterItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ auto b = o3tl::tryAccess<bool>(rVal);
+ if( !b )
+ return false;
+
+ SetValue( *b );
+ return true;
+}
+
+XLineEndCenterItem::XLineEndCenterItem(bool bEndCenter) :
+ SfxBoolItem(XATTR_LINEENDCENTER, bEndCenter)
+{
+}
+
+XLineEndCenterItem* XLineEndCenterItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineEndCenterItem(*this);
+}
+
+bool XLineEndCenterItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = SvxResId(GetValue() ? RID_SVXSTR_CENTERED : RID_SVXSTR_NOTCENTERED);
+ return true;
+}
+
+bool XLineEndCenterItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ bool bValue = GetValue();
+ rVal <<= bValue;
+ return true;
+}
+
+bool XLineEndCenterItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ auto b = o3tl::tryAccess<bool>(rVal);
+ if( !b )
+ return false;
+
+ SetValue( *b );
+ return true;
+}
+
+// --- fill attributes ---
+
+
+SfxPoolItem* XFillStyleItem::CreateDefault() { return new XFillStyleItem; }
+
+XFillStyleItem::XFillStyleItem(drawing::FillStyle eFillStyle) :
+ SfxEnumItem(XATTR_FILLSTYLE, eFillStyle)
+{
+}
+
+XFillStyleItem* XFillStyleItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFillStyleItem( *this );
+}
+
+bool XFillStyleItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+
+ TranslateId pId;
+
+ switch( GetValue() )
+ {
+ case drawing::FillStyle_NONE:
+ pId = RID_SVXSTR_INVISIBLE;
+ break;
+ case drawing::FillStyle_SOLID:
+ pId = RID_SVXSTR_SOLID;
+ break;
+ case drawing::FillStyle_GRADIENT:
+ pId = RID_SVXSTR_GRADIENT;
+ break;
+ case drawing::FillStyle_HATCH:
+ pId = RID_SVXSTR_HATCH;
+ break;
+ case drawing::FillStyle_BITMAP:
+ pId = RID_SVXSTR_BITMAP;
+ break;
+ default: break;
+ }
+
+ if (pId)
+ rText = SvxResId(pId);
+ return true;
+}
+
+sal_uInt16 XFillStyleItem::GetValueCount() const
+{
+ return 5;
+}
+
+bool XFillStyleItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ css::drawing::FillStyle eFS = GetValue();
+
+ rVal <<= eFS;
+
+ return true;
+}
+
+bool XFillStyleItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ css::drawing::FillStyle eFS;
+ if(!(rVal >>= eFS))
+ {
+ // also try an int (for Basic)
+ sal_Int32 nFS = 0;
+ if(!(rVal >>= nFS))
+ return false;
+ eFS = static_cast<css::drawing::FillStyle>(nFS);
+ }
+
+ SetValue( eFS );
+
+ return true;
+}
+
+void XFillStyleItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillStyleItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::number(static_cast<sal_Int16>(GetValue())).getStr()));
+
+ OUString aPresentation;
+ IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag());
+ GetPresentation(SfxItemPresentation::Nameless, MapUnit::Map100thMM, MapUnit::Map100thMM, aPresentation, aIntlWrapper);
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("presentation"), BAD_CAST(aPresentation.toUtf8().getStr()));
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+boost::property_tree::ptree XFillStyleItem::dumpAsJSON() const
+{
+ boost::property_tree::ptree aTree = SfxPoolItem::dumpAsJSON();
+
+ if (Which() == XATTR_FILLSTYLE)
+ aTree.put("commandName", ".uno:FillStyle");
+
+ OUString sValue;
+
+ switch( GetValue() )
+ {
+ case drawing::FillStyle_NONE:
+ sValue = "NONE";
+ break;
+ case drawing::FillStyle_SOLID:
+ sValue = "SOLID";
+ break;
+ case drawing::FillStyle_GRADIENT:
+ sValue = "GRADIENT";
+ break;
+ case drawing::FillStyle_HATCH:
+ sValue = "HATCH";
+ break;
+ case drawing::FillStyle_BITMAP:
+ sValue = "BITMAP";
+ break;
+ default: break;
+ }
+
+ aTree.put("state", sValue);
+
+ return aTree;
+}
+
+
+SfxPoolItem* XFillColorItem::CreateDefault() { return new XFillColorItem; }
+
+XFillColorItem::XFillColorItem(sal_Int32 nIndex, const Color& rTheColor) :
+ XColorItem(XATTR_FILLCOLOR, nIndex, rTheColor)
+{
+}
+
+XFillColorItem::XFillColorItem(const OUString& rName, const Color& rTheColor) :
+ XColorItem(XATTR_FILLCOLOR, rName, rTheColor)
+{
+}
+
+XFillColorItem* XFillColorItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFillColorItem(*this);
+}
+
+bool XFillColorItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = GetName();
+ return true;
+}
+
+bool XFillColorItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch (nMemberId)
+ {
+ case MID_COLOR_THEME_INDEX:
+ {
+ rVal <<= GetThemeColor().GetThemeIndex();
+ break;
+ }
+ case MID_COLOR_LUM_MOD:
+ {
+ rVal <<= GetThemeColor().GetLumMod();
+ break;
+ }
+ case MID_COLOR_LUM_OFF:
+ {
+ rVal <<= GetThemeColor().GetLumOff();
+ break;
+ }
+ default:
+ {
+ rVal <<= GetColorValue().GetRGBColor();
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool XFillColorItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch(nMemberId)
+ {
+ case MID_COLOR_THEME_INDEX:
+ {
+ sal_Int16 nIndex = -1;
+ if (!(rVal >>= nIndex))
+ return false;
+ GetThemeColor().SetThemeIndex(nIndex);
+ break;
+ }
+ case MID_COLOR_LUM_MOD:
+ {
+ sal_Int16 nLumMod = -1;
+ if (!(rVal >>= nLumMod))
+ return false;
+ GetThemeColor().SetLumMod(nLumMod);
+ }
+ break;
+ case MID_COLOR_LUM_OFF:
+ {
+ sal_Int16 nLumOff = -1;
+ if (!(rVal >>= nLumOff))
+ return false;
+ GetThemeColor().SetLumOff(nLumOff);
+ }
+ break;
+ default:
+ {
+ Color nValue;
+ if(!(rVal >>= nValue ))
+ return false;
+
+ SetColorValue( nValue );
+ break;
+ }
+ }
+ return true;
+}
+
+void XFillColorItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillColorItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+
+ XColorItem::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+boost::property_tree::ptree XFillColorItem::dumpAsJSON() const
+{
+ boost::property_tree::ptree aTree = SfxPoolItem::dumpAsJSON();
+
+ if (Which() == XATTR_FILLCOLOR)
+ aTree.put("commandName", ".uno:FillPageColor");
+
+ aTree.put("state", GetColorValue().AsRGBHexString());
+
+ return aTree;
+}
+
+XSecondaryFillColorItem::XSecondaryFillColorItem(const OUString& rName, const Color& rTheColor) :
+ XColorItem(XATTR_SECONDARYFILLCOLOR, rName, rTheColor)
+{
+}
+
+XSecondaryFillColorItem* XSecondaryFillColorItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XSecondaryFillColorItem(*this);
+}
+
+bool XSecondaryFillColorItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = GetName();
+ return true;
+}
+
+std::string XGradient::GradientStyleToString(css::awt::GradientStyle eStyle)
+{
+ switch (eStyle)
+ {
+ case css::awt::GradientStyle::GradientStyle_LINEAR:
+ return "LINEAR";
+
+ case css::awt::GradientStyle::GradientStyle_AXIAL:
+ return "AXIAL";
+
+ case css::awt::GradientStyle::GradientStyle_RADIAL:
+ return "RADIAL";
+
+ case css::awt::GradientStyle::GradientStyle_ELLIPTICAL:
+ return "ELLIPTICAL";
+
+ case css::awt::GradientStyle::GradientStyle_SQUARE:
+ return "SQUARE";
+
+ case css::awt::GradientStyle::GradientStyle_RECT:
+ return "RECT";
+
+ case css::awt::GradientStyle::GradientStyle_MAKE_FIXED_SIZE:
+ return "MAKE_FIXED_SIZE";
+ }
+
+ return "";
+}
+
+namespace
+{
+ css::awt::GradientStyle lcl_getStyleFromString(std::u16string_view rStyle)
+ {
+ if (rStyle == u"LINEAR")
+ return css::awt::GradientStyle_LINEAR;
+ else if (rStyle == u"AXIAL")
+ return css::awt::GradientStyle_AXIAL;
+ else if (rStyle == u"RADIAL")
+ return css::awt::GradientStyle_RADIAL;
+ else if (rStyle == u"ELLIPTICAL")
+ return css::awt::GradientStyle_ELLIPTICAL;
+ else if (rStyle == u"SQUARE")
+ return css::awt::GradientStyle_SQUARE;
+ else if (rStyle == u"RECT")
+ return css::awt::GradientStyle_RECT;
+
+ return css::awt::GradientStyle_LINEAR;
+ }
+
+ StringMap lcl_jsonToStringMap(const OUString& rJSON)
+ {
+ StringMap aArgs;
+ if (rJSON.getLength() && rJSON[0] != '\0')
+ {
+ std::stringstream aStream(OUStringToOString(rJSON, RTL_TEXTENCODING_ASCII_US).getStr());
+ boost::property_tree::ptree aTree;
+ boost::property_tree::read_json(aStream, aTree);
+
+ for (const auto& rPair : aTree)
+ {
+ aArgs[OUString::fromUtf8(rPair.first.c_str())] = OUString::fromUtf8(rPair.second.get_value<std::string>(".").c_str());
+ }
+ }
+ return aArgs;
+ }
+
+ XGradient lcl_buildGradientFromStringMap(StringMap& rMap)
+ {
+ XGradient aGradient;
+
+ aGradient.SetStartColor(Color(ColorTransparency, rMap["startcolor"].toInt32(16)));
+ aGradient.SetEndColor(Color(ColorTransparency, rMap["endcolor"].toInt32(16)));
+ aGradient.SetGradientStyle(lcl_getStyleFromString(rMap["style"]));
+ aGradient.SetAngle(Degree10(rMap["angle"].toInt32()));
+
+ return aGradient;
+ }
+}
+
+XGradient XGradient::fromJSON(const OUString& rJSON)
+{
+ StringMap aMap(lcl_jsonToStringMap(rJSON));
+ return lcl_buildGradientFromStringMap(aMap);
+}
+
+css::awt::Gradient XGradient::toGradientUNO() const
+{
+ css::awt::Gradient aGradient;
+
+ aGradient.Style = this->GetGradientStyle();
+ aGradient.StartColor = static_cast<sal_Int32>(this->GetStartColor());
+ aGradient.EndColor = static_cast<sal_Int32>(this->GetEndColor());
+ aGradient.Angle = static_cast<short>(this->GetAngle());
+ aGradient.Border = this->GetBorder();
+ aGradient.XOffset = this->GetXOffset();
+ aGradient.YOffset = this->GetYOffset();
+ aGradient.StartIntensity = this->GetStartIntens();
+ aGradient.EndIntensity = this->GetEndIntens();
+ aGradient.StepCount = this->GetSteps();
+
+ return aGradient;
+}
+
+XGradient::XGradient() :
+ eStyle( css::awt::GradientStyle_LINEAR ),
+ aStartColor( COL_BLACK ),
+ aEndColor( COL_WHITE ),
+ nAngle( 0 ),
+ nBorder( 0 ),
+ nOfsX( 50 ),
+ nOfsY( 50 ),
+ nIntensStart( 100 ),
+ nIntensEnd( 100 ),
+ nStepCount( 0 )
+{
+}
+
+XGradient::XGradient(const Color& rStart, const Color& rEnd,
+ css::awt::GradientStyle eTheStyle, Degree10 nTheAngle, sal_uInt16 nXOfs,
+ sal_uInt16 nYOfs, sal_uInt16 nTheBorder,
+ sal_uInt16 nStartIntens, sal_uInt16 nEndIntens,
+ sal_uInt16 nSteps) :
+ eStyle(eTheStyle),
+ aStartColor(rStart),
+ aEndColor(rEnd),
+ nAngle(nTheAngle),
+ nBorder(nTheBorder),
+ nOfsX(nXOfs),
+ nOfsY(nYOfs),
+ nIntensStart(nStartIntens),
+ nIntensEnd(nEndIntens),
+ nStepCount(nSteps)
+{
+}
+
+bool XGradient::operator==(const XGradient& rGradient) const
+{
+ return ( eStyle == rGradient.eStyle &&
+ aStartColor == rGradient.aStartColor &&
+ aEndColor == rGradient.aEndColor &&
+ nAngle == rGradient.nAngle &&
+ nBorder == rGradient.nBorder &&
+ nOfsX == rGradient.nOfsX &&
+ nOfsY == rGradient.nOfsY &&
+ nIntensStart == rGradient.nIntensStart &&
+ nIntensEnd == rGradient.nIntensEnd &&
+ nStepCount == rGradient.nStepCount );
+}
+
+boost::property_tree::ptree XGradient::dumpAsJSON() const
+{
+ boost::property_tree::ptree aTree;
+
+ aTree.put("style", XGradient::GradientStyleToString(eStyle));
+ aTree.put("startcolor",aStartColor.AsRGBHexString());
+ aTree.put("endcolor", aEndColor.AsRGBHexString());
+ aTree.put("angle", std::to_string(nAngle.get()));
+ aTree.put("border", std::to_string(nBorder));
+ aTree.put("x", std::to_string(nOfsX));
+ aTree.put("y", std::to_string(nOfsY));
+ aTree.put("intensstart", std::to_string(nIntensStart));
+ aTree.put("intensend", std::to_string(nIntensEnd));
+ aTree.put("stepcount", std::to_string(nStepCount));
+
+ return aTree;
+}
+
+SfxPoolItem* XFillGradientItem::CreateDefault() { return new XFillGradientItem; }
+
+XFillGradientItem::XFillGradientItem(sal_Int32 nIndex,
+ const XGradient& rTheGradient) :
+ NameOrIndex(XATTR_FILLGRADIENT, nIndex),
+ aGradient(rTheGradient)
+{
+}
+
+XFillGradientItem::XFillGradientItem(const OUString& rName,
+ const XGradient& rTheGradient, TypedWhichId<XFillGradientItem> nWhich)
+ : NameOrIndex(nWhich, rName)
+ , aGradient(rTheGradient)
+{
+}
+
+XFillGradientItem::XFillGradientItem(const XFillGradientItem& rItem) :
+ NameOrIndex(rItem),
+ aGradient(rItem.aGradient)
+{
+}
+
+XFillGradientItem::XFillGradientItem( const XGradient& rTheGradient )
+: NameOrIndex( XATTR_FILLGRADIENT, -1 ),
+ aGradient(rTheGradient)
+{
+}
+
+XFillGradientItem* XFillGradientItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFillGradientItem(*this);
+}
+
+bool XFillGradientItem::operator==(const SfxPoolItem& rItem) const
+{
+ return ( NameOrIndex::operator==(rItem) &&
+ aGradient == static_cast<const XFillGradientItem&>(rItem).aGradient );
+}
+
+const XGradient& XFillGradientItem::GetGradientValue() const // GetValue -> GetGradientValue
+{
+ if (!IsIndex())
+ return aGradient;
+ // ToDo: This should fail. We never called this code with a table so this should always
+ // have failed. Thus, I'm thinking that XFillGradientItem can't be an Index.
+ return aGradient;
+}
+
+bool XFillGradientItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = GetName();
+ return true;
+}
+
+bool XFillGradientItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch ( nMemberId )
+ {
+ case 0:
+ {
+ css::awt::Gradient aGradient2;
+
+ const XGradient& aXGradient = GetGradientValue();
+ aGradient2.Style = aXGradient.GetGradientStyle();
+ aGradient2.StartColor = static_cast<sal_Int32>(aXGradient.GetStartColor());
+ aGradient2.EndColor = static_cast<sal_Int32>(aXGradient.GetEndColor());
+ aGradient2.Angle = static_cast<short>(aXGradient.GetAngle());
+ aGradient2.Border = aXGradient.GetBorder();
+ aGradient2.XOffset = aXGradient.GetXOffset();
+ aGradient2.YOffset = aXGradient.GetYOffset();
+ aGradient2.StartIntensity = aXGradient.GetStartIntens();
+ aGradient2.EndIntensity = aXGradient.GetEndIntens();
+ aGradient2.StepCount = aXGradient.GetSteps();
+
+ uno::Sequence< beans::PropertyValue > aPropSeq{
+ comphelper::makePropertyValue("Name", SvxUnogetApiNameForItem(Which(), GetName())),
+ comphelper::makePropertyValue("FillGradient", aGradient2)
+ };
+ rVal <<= aPropSeq;
+ break;
+ }
+
+ case MID_FILLGRADIENT:
+ {
+ const XGradient& aXGradient = GetGradientValue();
+ css::awt::Gradient aGradient2;
+
+ aGradient2.Style = aXGradient.GetGradientStyle();
+ aGradient2.StartColor = static_cast<sal_Int32>(aXGradient.GetStartColor());
+ aGradient2.EndColor = static_cast<sal_Int32>(aXGradient.GetEndColor());
+ aGradient2.Angle = static_cast<short>(aXGradient.GetAngle());
+ aGradient2.Border = aXGradient.GetBorder();
+ aGradient2.XOffset = aXGradient.GetXOffset();
+ aGradient2.YOffset = aXGradient.GetYOffset();
+ aGradient2.StartIntensity = aXGradient.GetStartIntens();
+ aGradient2.EndIntensity = aXGradient.GetEndIntens();
+ aGradient2.StepCount = aXGradient.GetSteps();
+
+ rVal <<= aGradient2;
+ break;
+ }
+
+ case MID_NAME:
+ {
+ rVal <<= SvxUnogetApiNameForItem(Which(), GetName());
+ break;
+ }
+
+ case MID_GRADIENT_STYLE: rVal <<= static_cast<sal_Int16>(GetGradientValue().GetGradientStyle()); break;
+ case MID_GRADIENT_STARTCOLOR: rVal <<= GetGradientValue().GetStartColor(); break;
+ case MID_GRADIENT_ENDCOLOR: rVal <<= GetGradientValue().GetEndColor(); break;
+ case MID_GRADIENT_ANGLE: rVal <<= static_cast<sal_Int16>(GetGradientValue().GetAngle()); break;
+ case MID_GRADIENT_BORDER: rVal <<= GetGradientValue().GetBorder(); break;
+ case MID_GRADIENT_XOFFSET: rVal <<= GetGradientValue().GetXOffset(); break;
+ case MID_GRADIENT_YOFFSET: rVal <<= GetGradientValue().GetYOffset(); break;
+ case MID_GRADIENT_STARTINTENSITY: rVal <<= GetGradientValue().GetStartIntens(); break;
+ case MID_GRADIENT_ENDINTENSITY: rVal <<= GetGradientValue().GetEndIntens(); break;
+ case MID_GRADIENT_STEPCOUNT: rVal <<= GetGradientValue().GetSteps(); break;
+
+ default: OSL_FAIL("Wrong MemberId!"); return false;
+ }
+
+ return true;
+}
+
+bool XFillGradientItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ switch ( nMemberId )
+ {
+ case 0:
+ {
+ uno::Sequence< beans::PropertyValue > aPropSeq;
+
+ if ( rVal >>= aPropSeq )
+ {
+ css::awt::Gradient aGradient2;
+ OUString aName;
+ bool bGradient( false );
+ for ( const auto& rProp : std::as_const(aPropSeq) )
+ {
+ if ( rProp.Name == "Name" )
+ rProp.Value >>= aName;
+ else if ( rProp.Name == "FillGradient" )
+ {
+ if ( rProp.Value >>= aGradient2 )
+ bGradient = true;
+ }
+ }
+
+ SetName( aName );
+ if ( bGradient )
+ {
+ XGradient aXGradient;
+
+ aXGradient.SetGradientStyle( aGradient2.Style );
+ aXGradient.SetStartColor( Color(ColorTransparency, aGradient2.StartColor) );
+ aXGradient.SetEndColor( Color(ColorTransparency, aGradient2.EndColor) );
+ aXGradient.SetAngle( Degree10(aGradient2.Angle) );
+ aXGradient.SetBorder( aGradient2.Border );
+ aXGradient.SetXOffset( aGradient2.XOffset );
+ aXGradient.SetYOffset( aGradient2.YOffset );
+ aXGradient.SetStartIntens( aGradient2.StartIntensity );
+ aXGradient.SetEndIntens( aGradient2.EndIntensity );
+ aXGradient.SetSteps( aGradient2.StepCount );
+
+ SetGradientValue( aXGradient );
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ case MID_NAME:
+ {
+ OUString aName;
+ if (!(rVal >>= aName ))
+ return false;
+ SetName( aName );
+ break;
+ }
+
+ case MID_FILLGRADIENT:
+ {
+ css::awt::Gradient aGradient2;
+ if(!(rVal >>= aGradient2))
+ return false;
+
+ XGradient aXGradient;
+
+ aXGradient.SetGradientStyle( aGradient2.Style );
+ aXGradient.SetStartColor( Color(ColorTransparency, aGradient2.StartColor) );
+ aXGradient.SetEndColor( Color(ColorTransparency, aGradient2.EndColor) );
+ aXGradient.SetAngle( Degree10(aGradient2.Angle) );
+ aXGradient.SetBorder( aGradient2.Border );
+ aXGradient.SetXOffset( aGradient2.XOffset );
+ aXGradient.SetYOffset( aGradient2.YOffset );
+ aXGradient.SetStartIntens( aGradient2.StartIntensity );
+ aXGradient.SetEndIntens( aGradient2.EndIntensity );
+ aXGradient.SetSteps( aGradient2.StepCount );
+
+ SetGradientValue( aXGradient );
+ break;
+ }
+
+ case MID_GRADIENT_STARTCOLOR:
+ case MID_GRADIENT_ENDCOLOR:
+ {
+ Color nVal;
+ if(!(rVal >>= nVal ))
+ return false;
+
+ XGradient aXGradient = GetGradientValue();
+
+ if ( nMemberId == MID_GRADIENT_STARTCOLOR )
+ aXGradient.SetStartColor( nVal );
+ else
+ aXGradient.SetEndColor( nVal );
+ SetGradientValue( aXGradient );
+ break;
+ }
+
+ case MID_GRADIENT_STYLE:
+ case MID_GRADIENT_ANGLE:
+ case MID_GRADIENT_BORDER:
+ case MID_GRADIENT_STARTINTENSITY:
+ case MID_GRADIENT_ENDINTENSITY:
+ case MID_GRADIENT_STEPCOUNT:
+ case MID_GRADIENT_XOFFSET:
+ case MID_GRADIENT_YOFFSET:
+ {
+ sal_Int16 nVal = sal_Int16();
+ if(!(rVal >>= nVal ))
+ return false;
+
+ XGradient aXGradient = GetGradientValue();
+
+ switch ( nMemberId )
+ {
+ case MID_GRADIENT_STYLE:
+ aXGradient.SetGradientStyle( static_cast<css::awt::GradientStyle>(nVal) ); break;
+ case MID_GRADIENT_ANGLE:
+ aXGradient.SetAngle( Degree10(nVal) ); break;
+ case MID_GRADIENT_BORDER:
+ aXGradient.SetBorder( nVal ); break;
+ case MID_GRADIENT_STARTINTENSITY:
+ aXGradient.SetStartIntens( nVal ); break;
+ case MID_GRADIENT_ENDINTENSITY:
+ aXGradient.SetEndIntens( nVal ); break;
+ case MID_GRADIENT_STEPCOUNT:
+ aXGradient.SetSteps( nVal ); break;
+ case MID_GRADIENT_XOFFSET:
+ aXGradient.SetXOffset( nVal ); break;
+ case MID_GRADIENT_YOFFSET:
+ aXGradient.SetYOffset( nVal ); break;
+ }
+
+ SetGradientValue( aXGradient );
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool XFillGradientItem::CompareValueFunc( const NameOrIndex* p1, const NameOrIndex* p2 )
+{
+ return static_cast<const XFillGradientItem*>(p1)->GetGradientValue() == static_cast<const XFillGradientItem*>(p2)->GetGradientValue();
+}
+
+std::unique_ptr<XFillGradientItem> XFillGradientItem::checkForUniqueItem( SdrModel* pModel ) const
+{
+ if( pModel )
+ {
+ const OUString aUniqueName = NameOrIndex::CheckNamedItem(
+ this, Which(), &pModel->GetItemPool(),
+ XFillGradientItem::CompareValueFunc, RID_SVXSTR_GRADIENT,
+ pModel->GetPropertyList( XPropertyListType::Gradient ) );
+
+ // if the given name is not valid, replace it!
+ if( aUniqueName != GetName() )
+ return std::make_unique<XFillGradientItem>( aUniqueName, aGradient, TypedWhichId<XFillGradientItem>(Which()) );
+ }
+
+ return nullptr;
+}
+
+boost::property_tree::ptree XFillGradientItem::dumpAsJSON() const
+{
+ boost::property_tree::ptree aTree = SfxPoolItem::dumpAsJSON();
+
+ if (Which() == XATTR_FILLGRADIENT)
+ aTree.put("commandName", ".uno:FillGradient");
+
+ aTree.push_back(std::make_pair("state", GetGradientValue().dumpAsJSON()));
+
+ return aTree;
+}
+
+
+SfxPoolItem* XFillFloatTransparenceItem::CreateDefault() { return new XFillFloatTransparenceItem; }
+
+XFillFloatTransparenceItem::XFillFloatTransparenceItem() :
+ bEnabled( false )
+{
+ SetWhich( XATTR_FILLFLOATTRANSPARENCE );
+}
+
+XFillFloatTransparenceItem::XFillFloatTransparenceItem(const OUString& rName, const XGradient& rGradient, bool bEnable ) :
+ XFillGradientItem ( rName, rGradient ),
+ bEnabled ( bEnable )
+{
+ SetWhich( XATTR_FILLFLOATTRANSPARENCE );
+}
+
+XFillFloatTransparenceItem::XFillFloatTransparenceItem( const XFillFloatTransparenceItem& rItem ) :
+ XFillGradientItem ( rItem ),
+ bEnabled ( rItem.bEnabled )
+{
+ SetWhich( XATTR_FILLFLOATTRANSPARENCE );
+}
+
+XFillFloatTransparenceItem::XFillFloatTransparenceItem(const XGradient& rTheGradient, bool bEnable )
+: XFillGradientItem ( -1, rTheGradient ),
+ bEnabled ( bEnable )
+{
+ SetWhich( XATTR_FILLFLOATTRANSPARENCE );
+}
+
+bool XFillFloatTransparenceItem::operator==( const SfxPoolItem& rItem ) const
+{
+ return ( NameOrIndex::operator==(rItem) ) &&
+ ( GetGradientValue() == static_cast<const XFillGradientItem&>(rItem).GetGradientValue() ) &&
+ ( bEnabled == static_cast<const XFillFloatTransparenceItem&>(rItem).bEnabled );
+}
+
+XFillFloatTransparenceItem* XFillFloatTransparenceItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillFloatTransparenceItem( *this );
+}
+
+bool XFillFloatTransparenceItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ return XFillGradientItem::QueryValue( rVal, nMemberId );
+}
+
+bool XFillFloatTransparenceItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ return XFillGradientItem::PutValue( rVal, nMemberId );
+}
+
+bool XFillFloatTransparenceItem::GetPresentation( SfxItemPresentation ePres,
+ MapUnit eCoreUnit, MapUnit ePresUnit,
+ OUString& rText,
+ const IntlWrapper& rIntlWrapper ) const
+{
+ return XFillGradientItem::GetPresentation( ePres, eCoreUnit, ePresUnit, rText, rIntlWrapper );
+}
+
+bool XFillFloatTransparenceItem::CompareValueFunc( const NameOrIndex* p1, const NameOrIndex* p2 )
+{
+ return static_cast<const XFillFloatTransparenceItem*>(p1)->IsEnabled() == static_cast<const XFillFloatTransparenceItem*>(p2)->IsEnabled() &&
+ static_cast<const XFillFloatTransparenceItem*>(p1)->GetGradientValue() == static_cast<const XFillFloatTransparenceItem*>(p2)->GetGradientValue();
+}
+
+std::unique_ptr<XFillFloatTransparenceItem> XFillFloatTransparenceItem::checkForUniqueItem( SdrModel* pModel ) const
+{
+ // #85953# unique name only necessary when enabled
+ if(IsEnabled())
+ {
+ if( pModel )
+ {
+ const OUString aUniqueName = NameOrIndex::CheckNamedItem( this,
+ XATTR_FILLFLOATTRANSPARENCE,
+ &pModel->GetItemPool(),
+ XFillFloatTransparenceItem::CompareValueFunc,
+ RID_SVXSTR_TRASNGR0,
+ XPropertyListRef() );
+
+ // if the given name is not valid, replace it!
+ if( aUniqueName != GetName() )
+ {
+ return std::make_unique<XFillFloatTransparenceItem>( aUniqueName, GetGradientValue(), true );
+ }
+ }
+ }
+ else
+ {
+ // #85953# if disabled, force name to empty string
+ if( !GetName().isEmpty() )
+ {
+ return std::make_unique<XFillFloatTransparenceItem>(OUString(), GetGradientValue(), false);
+ }
+ }
+
+ return nullptr;
+}
+
+boost::property_tree::ptree XFillFloatTransparenceItem::dumpAsJSON() const
+{
+ boost::property_tree::ptree aTree = XFillGradientItem::dumpAsJSON();
+ aTree.put("commandName", ".uno:FillFloatTransparence");
+
+ if (!bEnabled)
+ {
+ boost::property_tree::ptree& rState = aTree.get_child("state");
+ // When gradient fill is disabled, the intensity fields contain the
+ // constant encoded percent-transparency. However we use that here to just
+ // distinguish between 'None' and 'Solid' types and correct the 'style'
+ // property appropriately.
+ if (GetGradientValue().GetStartIntens() == 100)
+ rState.put("style", "NONE");
+ else
+ rState.put("style", "SOLID");
+ }
+
+ return aTree;
+}
+
+XHatch::XHatch(const Color& rCol, css::drawing::HatchStyle eTheStyle, tools::Long nTheDistance,
+ Degree10 nTheAngle) :
+ eStyle(eTheStyle),
+ aColor(rCol),
+ nDistance(nTheDistance),
+ nAngle(nTheAngle)
+{
+}
+
+bool XHatch::operator==(const XHatch& rHatch) const
+{
+ return ( eStyle == rHatch.eStyle &&
+ aColor == rHatch.aColor &&
+ nDistance == rHatch.nDistance &&
+ nAngle == rHatch.nAngle );
+}
+
+
+SfxPoolItem* XFillHatchItem::CreateDefault() { return new XFillHatchItem; }
+
+XFillHatchItem::XFillHatchItem(const OUString& rName,
+ const XHatch& rTheHatch) :
+ NameOrIndex(XATTR_FILLHATCH, rName),
+ aHatch(rTheHatch)
+{
+}
+
+XFillHatchItem::XFillHatchItem(const XFillHatchItem& rItem) :
+ NameOrIndex(rItem),
+ aHatch(rItem.aHatch)
+{
+}
+
+XFillHatchItem::XFillHatchItem(const XHatch& rTheHatch)
+: NameOrIndex( XATTR_FILLHATCH, -1 ),
+ aHatch(rTheHatch)
+{
+}
+
+XFillHatchItem* XFillHatchItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFillHatchItem(*this);
+}
+
+bool XFillHatchItem::operator==(const SfxPoolItem& rItem) const
+{
+ return ( NameOrIndex::operator==(rItem) &&
+ aHatch == static_cast<const XFillHatchItem&>(rItem).aHatch );
+}
+
+bool XFillHatchItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = GetName();
+ return true;
+}
+
+bool XFillHatchItem::HasMetrics() const
+{
+ return true;
+}
+
+void XFillHatchItem::ScaleMetrics(tools::Long nMul, tools::Long nDiv)
+{
+ aHatch.SetDistance( BigInt::Scale( aHatch.GetDistance(), nMul, nDiv ) );
+}
+
+bool XFillHatchItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ switch ( nMemberId )
+ {
+ case 0:
+ {
+ css::drawing::Hatch aUnoHatch;
+
+ aUnoHatch.Style = aHatch.GetHatchStyle();
+ aUnoHatch.Color = sal_Int32(aHatch.GetColor());
+ aUnoHatch.Distance = aHatch.GetDistance();
+ aUnoHatch.Angle = aHatch.GetAngle().get();
+
+ uno::Sequence< beans::PropertyValue > aPropSeq{
+ comphelper::makePropertyValue("Name", SvxUnogetApiNameForItem(Which(), GetName())),
+ comphelper::makePropertyValue("FillHatch", aUnoHatch)
+ };
+ rVal <<= aPropSeq;
+ break;
+ }
+
+ case MID_FILLHATCH:
+ {
+ css::drawing::Hatch aUnoHatch;
+
+ aUnoHatch.Style = aHatch.GetHatchStyle();
+ aUnoHatch.Color = sal_Int32(aHatch.GetColor());
+ aUnoHatch.Distance = aHatch.GetDistance();
+ aUnoHatch.Angle = aHatch.GetAngle().get();
+ rVal <<= aUnoHatch;
+ break;
+ }
+
+ case MID_NAME:
+ {
+ rVal <<= SvxUnogetApiNameForItem(Which(), GetName());
+ break;
+ }
+
+ case MID_HATCH_STYLE:
+ rVal <<= aHatch.GetHatchStyle(); break;
+ case MID_HATCH_COLOR:
+ rVal <<= aHatch.GetColor(); break;
+ case MID_HATCH_DISTANCE:
+ rVal <<= aHatch.GetDistance(); break;
+ case MID_HATCH_ANGLE:
+ rVal <<= aHatch.GetAngle().get(); break;
+
+ default: OSL_FAIL("Wrong MemberId!"); return false;
+ }
+
+ return true;
+}
+
+bool XFillHatchItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ switch ( nMemberId )
+ {
+ case 0:
+ {
+ uno::Sequence< beans::PropertyValue > aPropSeq;
+ if ( rVal >>= aPropSeq )
+ {
+ css::drawing::Hatch aUnoHatch;
+ OUString aName;
+ bool bHatch( false );
+ for ( const auto& rProp : std::as_const(aPropSeq) )
+ {
+ if ( rProp.Name == "Name" )
+ rProp.Value >>= aName;
+ else if ( rProp.Name == "FillHatch" )
+ {
+ if ( rProp.Value >>= aUnoHatch )
+ bHatch = true;
+ }
+ }
+
+ SetName( aName );
+ if ( bHatch )
+ {
+ aHatch.SetHatchStyle( aUnoHatch.Style );
+ aHatch.SetColor( Color(ColorTransparency, aUnoHatch.Color) );
+ aHatch.SetDistance( aUnoHatch.Distance );
+ aHatch.SetAngle( Degree10(aUnoHatch.Angle) );
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ case MID_FILLHATCH:
+ {
+ css::drawing::Hatch aUnoHatch;
+ if(!(rVal >>= aUnoHatch))
+ return false;
+
+ aHatch.SetHatchStyle( aUnoHatch.Style );
+ aHatch.SetColor( Color(ColorTransparency, aUnoHatch.Color) );
+ aHatch.SetDistance( aUnoHatch.Distance );
+ aHatch.SetAngle( Degree10(aUnoHatch.Angle) );
+ break;
+ }
+
+ case MID_NAME:
+ {
+ OUString aName;
+ if (!(rVal >>= aName ))
+ return false;
+ SetName( aName );
+ break;
+ }
+
+ case MID_HATCH_STYLE:
+ {
+ sal_Int16 nVal = sal_Int16();
+ if (!(rVal >>= nVal ))
+ return false;
+ aHatch.SetHatchStyle( static_cast<css::drawing::HatchStyle>(nVal) );
+ break;
+ }
+
+ case MID_HATCH_COLOR:
+ case MID_HATCH_DISTANCE:
+ case MID_HATCH_ANGLE:
+ {
+ sal_Int32 nVal = 0;
+ if (!(rVal >>= nVal ))
+ return false;
+
+ if ( nMemberId == MID_HATCH_COLOR )
+ aHatch.SetColor( Color(ColorTransparency, nVal) );
+ else if ( nMemberId == MID_HATCH_DISTANCE )
+ aHatch.SetDistance( nVal );
+ else
+ aHatch.SetAngle( Degree10(nVal) );
+ break;
+ }
+
+ default: OSL_FAIL("Wrong MemberId!"); return false;
+ }
+
+ return true;
+}
+
+bool XFillHatchItem::CompareValueFunc( const NameOrIndex* p1, const NameOrIndex* p2 )
+{
+ return static_cast<const XFillHatchItem*>(p1)->GetHatchValue() == static_cast<const XFillHatchItem*>(p2)->GetHatchValue();
+}
+
+std::unique_ptr<XFillHatchItem> XFillHatchItem::checkForUniqueItem( SdrModel* pModel ) const
+{
+ if( pModel )
+ {
+ const OUString aUniqueName = NameOrIndex::CheckNamedItem(
+ this, XATTR_FILLHATCH, &pModel->GetItemPool(),
+ XFillHatchItem::CompareValueFunc, RID_SVXSTR_HATCH10,
+ pModel->GetPropertyList( XPropertyListType::Hatch ) );
+
+ // if the given name is not valid, replace it!
+ if( aUniqueName != GetName() )
+ return std::make_unique<XFillHatchItem>( aUniqueName, aHatch );
+ }
+
+ return nullptr;
+}
+
+// --- form text attributes ---
+
+
+SfxPoolItem* XFormTextStyleItem::CreateDefault() { return new XFormTextStyleItem; }
+
+XFormTextStyleItem::XFormTextStyleItem(XFormTextStyle eTheStyle) :
+ SfxEnumItem(XATTR_FORMTXTSTYLE, eTheStyle)
+{
+}
+
+XFormTextStyleItem* XFormTextStyleItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextStyleItem( *this );
+}
+
+sal_uInt16 XFormTextStyleItem::GetValueCount() const
+{
+ return 5;
+}
+
+bool XFormTextStyleItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<sal_Int32>(GetValue());
+ return true;
+}
+
+bool XFormTextStyleItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nValue = 0;
+ rVal >>= nValue;
+ SetValue(static_cast<XFormTextStyle>(nValue));
+
+ return true;
+}
+
+
+SfxPoolItem* XFormTextAdjustItem::CreateDefault() { return new XFormTextAdjustItem; }
+
+XFormTextAdjustItem::XFormTextAdjustItem(XFormTextAdjust eTheAdjust) :
+ SfxEnumItem(XATTR_FORMTXTADJUST, eTheAdjust)
+{
+}
+
+XFormTextAdjustItem* XFormTextAdjustItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextAdjustItem( *this );
+}
+
+sal_uInt16 XFormTextAdjustItem::GetValueCount() const
+{
+ return 4;
+}
+
+bool XFormTextAdjustItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<sal_Int32>(GetValue());
+ return true;
+}
+
+bool XFormTextAdjustItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nValue = 0;
+ rVal >>= nValue;
+ SetValue(static_cast<XFormTextAdjust>(nValue));
+
+ return true;
+}
+
+
+SfxPoolItem* XFormTextDistanceItem::CreateDefault() { return new XFormTextDistanceItem; }
+
+XFormTextDistanceItem::XFormTextDistanceItem(tools::Long nDist) :
+ SfxMetricItem(XATTR_FORMTXTDISTANCE, nDist)
+{
+}
+
+XFormTextDistanceItem* XFormTextDistanceItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextDistanceItem(*this);
+}
+
+SfxPoolItem* XFormTextStartItem::CreateDefault() { return new XFormTextStartItem; }
+
+XFormTextStartItem::XFormTextStartItem(tools::Long nStart) :
+ SfxMetricItem(XATTR_FORMTXTSTART, nStart)
+{
+}
+
+XFormTextStartItem* XFormTextStartItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextStartItem(*this);
+}
+
+SfxPoolItem* XFormTextMirrorItem::CreateDefault() { return new XFormTextMirrorItem; }
+
+XFormTextMirrorItem::XFormTextMirrorItem(bool bMirror) :
+ SfxBoolItem(XATTR_FORMTXTMIRROR, bMirror)
+{
+}
+
+XFormTextMirrorItem* XFormTextMirrorItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextMirrorItem(*this);
+}
+
+SfxPoolItem* XFormTextOutlineItem::CreateDefault() { return new XFormTextOutlineItem; }
+
+XFormTextOutlineItem::XFormTextOutlineItem(bool bOutline) :
+ SfxBoolItem(XATTR_FORMTXTOUTLINE, bOutline)
+{
+}
+
+XFormTextOutlineItem* XFormTextOutlineItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextOutlineItem(*this);
+}
+
+SfxPoolItem* XFormTextShadowItem::CreateDefault() { return new XFormTextShadowItem; }
+
+XFormTextShadowItem::XFormTextShadowItem(XFormTextShadow eFormTextShadow) :
+ SfxEnumItem(XATTR_FORMTXTSHADOW, eFormTextShadow)
+{
+}
+
+XFormTextShadowItem* XFormTextShadowItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextShadowItem( *this );
+}
+
+sal_uInt16 XFormTextShadowItem::GetValueCount() const
+{
+ return 3;
+}
+
+bool XFormTextShadowItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<sal_Int32>(GetValue());
+ return true;
+}
+
+bool XFormTextShadowItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ sal_Int32 nValue = 0;
+ rVal >>= nValue;
+ SetValue(static_cast<XFormTextShadow>(nValue));
+
+ return true;
+}
+
+
+SfxPoolItem* XFormTextShadowColorItem::CreateDefault() { return new XFormTextShadowColorItem; }
+
+XFormTextShadowColorItem::XFormTextShadowColorItem(const OUString& rName,
+ const Color& rTheColor) :
+ XColorItem(XATTR_FORMTXTSHDWCOLOR, rName, rTheColor)
+{
+}
+
+XFormTextShadowColorItem* XFormTextShadowColorItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextShadowColorItem(*this);
+}
+
+SfxPoolItem* XFormTextShadowXValItem::CreateDefault() { return new XFormTextShadowXValItem; }
+
+XFormTextShadowXValItem::XFormTextShadowXValItem(tools::Long nVal) :
+ SfxMetricItem(XATTR_FORMTXTSHDWXVAL, nVal)
+{
+}
+
+XFormTextShadowXValItem* XFormTextShadowXValItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextShadowXValItem(*this);
+}
+
+SfxPoolItem* XFormTextShadowYValItem::CreateDefault() { return new XFormTextShadowYValItem; }
+
+XFormTextShadowYValItem::XFormTextShadowYValItem(tools::Long nVal) :
+ SfxMetricItem(XATTR_FORMTXTSHDWYVAL, nVal)
+{
+}
+
+XFormTextShadowYValItem* XFormTextShadowYValItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextShadowYValItem(*this);
+}
+
+SfxPoolItem* XFormTextHideFormItem::CreateDefault() { return new XFormTextHideFormItem; }
+
+XFormTextHideFormItem::XFormTextHideFormItem(bool bHide) :
+ SfxBoolItem(XATTR_FORMTXTHIDEFORM, bHide)
+{
+}
+
+XFormTextHideFormItem* XFormTextHideFormItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextHideFormItem(*this);
+}
+
+// --- SetItems ---
+
+
+/// a line attribute set item
+XLineAttrSetItem::XLineAttrSetItem( SfxItemSet&& pItemSet ) :
+ SfxSetItem( XATTRSET_LINE, std::move(pItemSet))
+{
+}
+
+XLineAttrSetItem::XLineAttrSetItem( SfxItemPool* pItemPool ) :
+ SfxSetItem( XATTRSET_LINE,
+ SfxItemSetFixed<XATTR_LINE_FIRST, XATTR_LINE_LAST>( *pItemPool ))
+{
+}
+
+XLineAttrSetItem::XLineAttrSetItem( const XLineAttrSetItem& rLineAttr ) :
+ SfxSetItem( rLineAttr )
+{
+}
+
+XLineAttrSetItem::XLineAttrSetItem( const XLineAttrSetItem& rLineAttr,
+ SfxItemPool* pItemPool) :
+ SfxSetItem( rLineAttr, pItemPool )
+{
+}
+
+XLineAttrSetItem* XLineAttrSetItem::Clone( SfxItemPool* pPool ) const
+{
+ return new XLineAttrSetItem( *this, pPool );
+}
+
+/// fill attribute set item
+XFillAttrSetItem::XFillAttrSetItem( SfxItemSet&& pItemSet ) :
+ SfxSetItem( XATTRSET_FILL, std::move(pItemSet))
+{
+}
+
+XFillAttrSetItem::XFillAttrSetItem( SfxItemPool* pItemPool ) :
+ SfxSetItem( XATTRSET_FILL,
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>( *pItemPool ))
+{
+}
+
+XFillAttrSetItem::XFillAttrSetItem( const XFillAttrSetItem& rFillAttr ) :
+ SfxSetItem( rFillAttr )
+{
+}
+
+XFillAttrSetItem::XFillAttrSetItem( const XFillAttrSetItem& rFillAttr,
+ SfxItemPool* pItemPool ) :
+ SfxSetItem( rFillAttr, pItemPool )
+{
+}
+
+XFillAttrSetItem* XFillAttrSetItem::Clone( SfxItemPool* pPool ) const
+{
+ return new XFillAttrSetItem( *this, pPool );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xattr2.cxx b/svx/source/xoutdev/xattr2.cxx
new file mode 100644
index 000000000..ad1b3b295
--- /dev/null
+++ b/svx/source/xoutdev/xattr2.cxx
@@ -0,0 +1,731 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/LineJoint.hpp>
+#include <com/sun/star/drawing/LineCap.hpp>
+#include <com/sun/star/uno/Any.hxx>
+
+#include <osl/diagnose.h>
+#include <i18nutil/unicode.hxx>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <svx/xlinjoit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xfltrit.hxx>
+#include <xftshtit.hxx>
+#include <svx/xgrscit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflbmpit.hxx>
+#include <svx/xflbmsxy.hxx>
+#include <svx/xflbmsli.hxx>
+#include <svx/xflbtoxy.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflboxy.hxx>
+#include <svx/xflbckit.hxx>
+#include <svx/xfilluseslidebackgrounditem.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/xdef.hxx>
+#include <AffineMatrixItem.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <comphelper/lok.hxx>
+
+#include <libxml/xmlwriter.h>
+
+XLineTransparenceItem::XLineTransparenceItem(sal_uInt16 nLineTransparence) :
+ SfxUInt16Item(XATTR_LINETRANSPARENCE, nLineTransparence)
+{
+}
+
+XLineTransparenceItem* XLineTransparenceItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineTransparenceItem(*this);
+}
+
+bool XLineTransparenceItem::GetPresentation
+(
+ SfxItemPresentation ePres,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+
+ switch ( ePres )
+ {
+ case SfxItemPresentation::Complete:
+ rText = SvxResId(RID_SVXSTR_TRANSPARENCE) + ": ";
+ [[fallthrough]];
+ case SfxItemPresentation::Nameless:
+ rText += unicode::formatPercent(GetValue(),
+ Application::GetSettings().GetUILanguageTag());
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+SfxPoolItem* XLineJointItem::CreateDefault() { return new XLineJointItem; }
+
+XLineJointItem::XLineJointItem( css::drawing::LineJoint eLineJoint ) :
+ SfxEnumItem(XATTR_LINEJOINT, eLineJoint)
+{
+}
+
+XLineJointItem* XLineJointItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineJointItem( *this );
+}
+
+bool XLineJointItem::GetPresentation( SfxItemPresentation /*ePres*/, MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/, OUString& rText, const IntlWrapper&) const
+{
+ rText.clear();
+
+ TranslateId pId;
+
+ switch( GetValue() )
+ {
+ case css::drawing::LineJoint::LineJoint_MAKE_FIXED_SIZE:
+ case css::drawing::LineJoint_NONE:
+ pId = comphelper::LibreOfficeKit::isActive() ? RID_SVXSTR_INVISIBLE : RID_SVXSTR_NONE;
+ break;
+
+ case css::drawing::LineJoint_MIDDLE:
+ pId = RID_SVXSTR_LINEJOINT_MIDDLE;
+ break;
+
+
+ case css::drawing::LineJoint_BEVEL:
+ pId = RID_SVXSTR_LINEJOINT_BEVEL;
+ break;
+
+
+ case css::drawing::LineJoint_MITER:
+ pId = RID_SVXSTR_LINEJOINT_MITER;
+ break;
+
+
+ case css::drawing::LineJoint_ROUND:
+ pId = RID_SVXSTR_LINEJOINT_ROUND;
+ break;
+ }
+
+ if (pId)
+ rText = SvxResId(pId);
+
+ return true;
+}
+
+bool XLineJointItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ const css::drawing::LineJoint eJoint = GetValue();
+ rVal <<= eJoint;
+ return true;
+}
+
+bool XLineJointItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ css::drawing::LineJoint eUnoJoint;
+
+ if(!(rVal >>= eUnoJoint))
+ {
+ // also try an int (for Basic)
+ sal_Int32 nLJ = 0;
+ if(!(rVal >>= nLJ))
+ return false;
+ eUnoJoint = static_cast<css::drawing::LineJoint>(nLJ);
+ }
+
+ SetValue( eUnoJoint );
+
+ return true;
+}
+
+sal_uInt16 XLineJointItem::GetValueCount() const
+{
+ // don't forget to update the api interface also
+ return 5;
+}
+
+
+AffineMatrixItem::AffineMatrixItem(const css::geometry::AffineMatrix2D* pMatrix)
+: SfxPoolItem(SID_ATTR_TRANSFORM_MATRIX)
+{
+ if(pMatrix)
+ {
+ maMatrix = *pMatrix;
+ }
+ else
+ {
+ maMatrix.m00 = 1.0;
+ maMatrix.m01 = 0.0;
+ maMatrix.m02 = 0.0;
+ maMatrix.m10 = 0.0;
+ maMatrix.m11 = 1.0;
+ maMatrix.m12 = 0.0;
+ }
+}
+
+AffineMatrixItem::AffineMatrixItem(const AffineMatrixItem& rRef)
+: SfxPoolItem(rRef)
+{
+ maMatrix = rRef.maMatrix;
+}
+
+AffineMatrixItem::~AffineMatrixItem()
+{
+}
+
+bool AffineMatrixItem::operator==(const SfxPoolItem& rRef) const
+{
+ if(!SfxPoolItem::operator==(rRef))
+ {
+ return false;
+ }
+
+ const AffineMatrixItem* pRef = static_cast< const AffineMatrixItem* >(&rRef);
+
+ if(!pRef)
+ {
+ return false;
+ }
+
+ return (maMatrix.m00 == pRef->maMatrix.m00
+ && maMatrix.m01 == pRef->maMatrix.m01
+ && maMatrix.m02 == pRef->maMatrix.m02
+ && maMatrix.m10 == pRef->maMatrix.m10
+ && maMatrix.m11 == pRef->maMatrix.m11
+ && maMatrix.m12 == pRef->maMatrix.m12);
+}
+
+AffineMatrixItem* AffineMatrixItem::Clone( SfxItemPool* /*pPool*/ ) const
+{
+ return new AffineMatrixItem(*this);
+}
+
+bool AffineMatrixItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ rVal <<= maMatrix;
+ return true;
+}
+
+bool AffineMatrixItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
+{
+ if (rVal >>= maMatrix)
+ {
+ return true;
+ }
+
+ OSL_ENSURE(false, "AffineMatrixItem::PutValue - Wrong type!");
+ return false;
+}
+
+
+SfxPoolItem* XLineCapItem::CreateDefault() { return new XLineCapItem; }
+
+XLineCapItem::XLineCapItem(css::drawing::LineCap eLineCap)
+: SfxEnumItem(XATTR_LINECAP, eLineCap)
+{
+}
+
+XLineCapItem* XLineCapItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineCapItem( *this );
+}
+
+bool XLineCapItem::GetPresentation( SfxItemPresentation /*ePres*/, MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/, OUString& rText, const IntlWrapper&) const
+{
+ TranslateId pId;
+
+ switch( GetValue() )
+ {
+ default: /*css::drawing::LineCap_BUTT*/
+ pId = RID_SVXSTR_LINECAP_BUTT;
+ break;
+
+ case css::drawing::LineCap_ROUND:
+ pId = RID_SVXSTR_LINECAP_ROUND;
+ break;
+
+ case css::drawing::LineCap_SQUARE:
+ pId = RID_SVXSTR_LINECAP_SQUARE;
+ break;
+ }
+
+ rText = SvxResId(pId);
+
+ return true;
+}
+
+bool XLineCapItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ const css::drawing::LineCap eCap(GetValue());
+ rVal <<= eCap;
+ return true;
+}
+
+bool XLineCapItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ css::drawing::LineCap eUnoCap;
+
+ if(!(rVal >>= eUnoCap))
+ {
+ // also try an int (for Basic)
+ sal_Int32 nLJ(0);
+
+ if(!(rVal >>= nLJ))
+ {
+ return false;
+ }
+
+ eUnoCap = static_cast<css::drawing::LineCap>(nLJ);
+ }
+
+ OSL_ENSURE(css::drawing::LineCap_BUTT == eUnoCap
+ || css::drawing::LineCap_ROUND == eUnoCap
+ || css::drawing::LineCap_SQUARE == eUnoCap, "Unknown enum value in XATTR_LINECAP (!)");
+
+ SetValue(eUnoCap);
+
+ return true;
+}
+
+sal_uInt16 XLineCapItem::GetValueCount() const
+{
+ // don't forget to update the api interface also
+ return 3;
+}
+
+css::drawing::LineCap XLineCapItem::GetValue() const
+{
+ const css::drawing::LineCap eRetval(SfxEnumItem::GetValue());
+ OSL_ENSURE(css::drawing::LineCap_BUTT == eRetval
+ || css::drawing::LineCap_ROUND == eRetval
+ || css::drawing::LineCap_SQUARE == eRetval, "Unknown enum value in XATTR_LINECAP (!)");
+
+ return eRetval;
+}
+
+XFillTransparenceItem::XFillTransparenceItem(sal_uInt16 nFillTransparence) :
+ SfxUInt16Item(XATTR_FILLTRANSPARENCE, nFillTransparence)
+{
+}
+
+XFillTransparenceItem* XFillTransparenceItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFillTransparenceItem(*this);
+}
+
+bool XFillTransparenceItem::GetPresentation
+(
+ SfxItemPresentation ePres,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+
+ switch ( ePres )
+ {
+ case SfxItemPresentation::Complete:
+ rText = SvxResId(RID_SVXSTR_TRANSPARENCE) + ": ";
+ [[fallthrough]];
+ case SfxItemPresentation::Nameless:
+ rText += unicode::formatPercent(GetValue(),
+ Application::GetSettings().GetUILanguageTag());
+ return true;
+ default:
+ return false;
+ }
+}
+
+void XFillTransparenceItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillTransparenceItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::number(GetValue()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+
+XFormTextShadowTranspItem::XFormTextShadowTranspItem(sal_uInt16 nShdwTransparence) :
+ SfxUInt16Item(XATTR_FORMTXTSHDWTRANSP, nShdwTransparence)
+{
+}
+
+XFormTextShadowTranspItem* XFormTextShadowTranspItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFormTextShadowTranspItem(*this);
+}
+
+
+XGradientStepCountItem::XGradientStepCountItem( sal_uInt16 nStepCount ) :
+ SfxUInt16Item( XATTR_GRADIENTSTEPCOUNT, nStepCount )
+{
+}
+
+XGradientStepCountItem* XGradientStepCountItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XGradientStepCountItem( *this );
+}
+
+bool XGradientStepCountItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+
+ rText += OUString::number(GetValue());
+ return true;
+}
+
+
+XFillBmpTileItem::XFillBmpTileItem( bool bTile ) :
+ SfxBoolItem( XATTR_FILLBMP_TILE, bTile )
+{
+}
+
+XFillBmpTileItem* XFillBmpTileItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBmpTileItem( *this );
+}
+
+bool XFillBmpTileItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return true;
+}
+
+void XFillBmpTileItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillBmpTileItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+
+
+XFillBmpPosItem::XFillBmpPosItem( RectPoint eRP ) :
+ SfxEnumItem( XATTR_FILLBMP_POS, eRP )
+{
+}
+
+XFillBmpPosItem* XFillBmpPosItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBmpPosItem( *this );
+}
+
+bool XFillBmpPosItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return true;
+}
+
+sal_uInt16 XFillBmpPosItem::GetValueCount() const
+{
+ return 9;
+}
+
+void XFillBmpPosItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillBmpPosItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::number(static_cast<int>(GetValue())).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+
+XFillBmpSizeXItem::XFillBmpSizeXItem( tools::Long nSizeX ) :
+ SfxMetricItem( XATTR_FILLBMP_SIZEX, nSizeX )
+{
+}
+
+XFillBmpSizeXItem* XFillBmpSizeXItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBmpSizeXItem( *this );
+}
+
+bool XFillBmpSizeXItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return true;
+}
+
+bool XFillBmpSizeXItem::HasMetrics() const
+{
+ return GetValue() > 0;
+}
+
+
+
+XFillBmpSizeYItem::XFillBmpSizeYItem( tools::Long nSizeY ) :
+ SfxMetricItem( XATTR_FILLBMP_SIZEY, nSizeY )
+{
+}
+
+XFillBmpSizeYItem* XFillBmpSizeYItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBmpSizeYItem( *this );
+}
+
+bool XFillBmpSizeYItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return true;
+}
+
+bool XFillBmpSizeYItem::HasMetrics() const
+{
+ return GetValue() > 0;
+}
+
+
+XFillBmpSizeLogItem::XFillBmpSizeLogItem( bool bLog ) :
+ SfxBoolItem( XATTR_FILLBMP_SIZELOG, bLog )
+{
+}
+
+XFillBmpSizeLogItem* XFillBmpSizeLogItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBmpSizeLogItem( *this );
+}
+
+bool XFillBmpSizeLogItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return true;
+}
+
+
+
+XFillBmpTileOffsetXItem::XFillBmpTileOffsetXItem( sal_uInt16 nOffX ) :
+ SfxUInt16Item( XATTR_FILLBMP_TILEOFFSETX, nOffX )
+{
+}
+
+XFillBmpTileOffsetXItem* XFillBmpTileOffsetXItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBmpTileOffsetXItem( *this );
+}
+
+bool XFillBmpTileOffsetXItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return true;
+}
+
+
+XFillBmpTileOffsetYItem::XFillBmpTileOffsetYItem( sal_uInt16 nOffY ) :
+ SfxUInt16Item( XATTR_FILLBMP_TILEOFFSETY, nOffY )
+{
+}
+
+XFillBmpTileOffsetYItem* XFillBmpTileOffsetYItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBmpTileOffsetYItem( *this );
+}
+
+bool XFillBmpTileOffsetYItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return true;
+}
+
+XFillBmpStretchItem::XFillBmpStretchItem( bool bStretch ) :
+ SfxBoolItem( XATTR_FILLBMP_STRETCH, bStretch )
+{
+}
+
+XFillBmpStretchItem* XFillBmpStretchItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBmpStretchItem( *this );
+}
+
+bool XFillBmpStretchItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return true;
+}
+
+void XFillBmpStretchItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillBmpStretchItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+
+XFillBmpPosOffsetXItem::XFillBmpPosOffsetXItem( sal_uInt16 nOffPosX ) :
+ SfxUInt16Item( XATTR_FILLBMP_POSOFFSETX, nOffPosX )
+{
+}
+
+XFillBmpPosOffsetXItem* XFillBmpPosOffsetXItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBmpPosOffsetXItem( *this );
+}
+
+bool XFillBmpPosOffsetXItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return true;
+}
+
+
+XFillBmpPosOffsetYItem::XFillBmpPosOffsetYItem( sal_uInt16 nOffPosY ) :
+ SfxUInt16Item( XATTR_FILLBMP_POSOFFSETY, nOffPosY )
+{
+}
+
+XFillBmpPosOffsetYItem* XFillBmpPosOffsetYItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBmpPosOffsetYItem( *this );
+}
+
+bool XFillBmpPosOffsetYItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText.clear();
+ return true;
+}
+
+XFillBackgroundItem::XFillBackgroundItem( bool bFill ) :
+ SfxBoolItem( XATTR_FILLBACKGROUND, bFill )
+{
+}
+
+XFillBackgroundItem* XFillBackgroundItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillBackgroundItem( *this );
+}
+
+bool XFillBackgroundItem::GetPresentation( SfxItemPresentation /*ePres*/, MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/, OUString& rText, const IntlWrapper&) const
+{
+ rText.clear();
+ return true;
+}
+
+void XFillBackgroundItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillBackgroundItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+XFillUseSlideBackgroundItem::XFillUseSlideBackgroundItem( bool bFill ) :
+ SfxBoolItem( XATTR_FILLUSESLIDEBACKGROUND, bFill )
+{
+}
+
+XFillUseSlideBackgroundItem* XFillUseSlideBackgroundItem::Clone( SfxItemPool* /*pPool*/) const
+{
+ return new XFillUseSlideBackgroundItem( *this );
+}
+
+bool XFillUseSlideBackgroundItem::GetPresentation( SfxItemPresentation /*ePres*/, MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/, OUString& rText, const IntlWrapper&) const
+{
+ rText.clear();
+ return true;
+}
+
+void XFillUseSlideBackgroundItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillUseSlideBackgroundItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::boolean(GetValue()).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xattrbmp.cxx b/svx/source/xoutdev/xattrbmp.cxx
new file mode 100644
index 000000000..2401bb361
--- /dev/null
+++ b/svx/source/xoutdev/xattrbmp.cxx
@@ -0,0 +1,342 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <tools/debug.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/bitmapex.hxx>
+#include <svl/style.hxx>
+#include <editeng/memberids.h>
+#include <svx/strings.hrc>
+#include <svx/xtable.hxx>
+#include <svx/xdef.hxx>
+#include <svx/unomid.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/xbitmap.hxx>
+#include <svx/xbtmpit.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <vcl/BitmapTools.hxx>
+#include <vcl/GraphicLoader.hxx>
+
+#include <libxml/xmlwriter.h>
+
+using namespace ::com::sun::star;
+
+XOBitmap::XOBitmap( const BitmapEx& rBmp ) :
+ xGraphicObject (new GraphicObject(rBmp)),
+ bGraphicDirty ( false )
+{
+}
+
+XOBitmap::~XOBitmap()
+{
+}
+
+BitmapEx XOBitmap::GetBitmap() const
+{
+ return GetGraphicObject().GetGraphic().GetBitmapEx();
+}
+
+const GraphicObject& XOBitmap::GetGraphicObject() const
+{
+ if( bGraphicDirty )
+ const_cast<XOBitmap*>(this)->Array2Bitmap();
+
+ return *xGraphicObject;
+}
+
+void XOBitmap::Bitmap2Array()
+{
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ bool bPixelColor = false;
+ const BitmapEx aBitmap( GetBitmap() );
+ const sal_Int32 nLines = 8; // type dependent
+
+ if( !pPixelArray )
+ pPixelArray.reset( new sal_uInt16[ nLines * nLines ] );
+
+ pVDev->SetOutputSizePixel( aBitmap.GetSizePixel() );
+ pVDev->DrawBitmapEx( Point(), aBitmap );
+ aPixelColor = aBckgrColor = pVDev->GetPixel( Point() );
+
+ // create array and determine foreground and background color
+ for (sal_Int32 i = 0; i < nLines; ++i)
+ {
+ for (sal_Int32 j = 0; j < nLines; ++j)
+ {
+ if ( pVDev->GetPixel( Point( j, i ) ) == aBckgrColor )
+ pPixelArray[ j + i * nLines ] = 0;
+ else
+ {
+ pPixelArray[ j + i * nLines ] = 1;
+ if( !bPixelColor )
+ {
+ aPixelColor = pVDev->GetPixel( Point( j, i ) );
+ bPixelColor = true;
+ }
+ }
+ }
+ }
+}
+
+/// convert array, fore- and background color into a bitmap
+void XOBitmap::Array2Bitmap()
+{
+ if (!pPixelArray)
+ return;
+
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ const sal_Int32 nLines = 8; // type dependent
+
+ pVDev->SetOutputSizePixel( Size( nLines, nLines ) );
+
+ // create bitmap
+ for (sal_Int32 i = 0; i < nLines; ++i)
+ {
+ for (sal_Int32 j = 0; j < nLines; ++j)
+ {
+ if( pPixelArray[ j + i * nLines ] == 0 )
+ pVDev->DrawPixel( Point( j, i ), aBckgrColor );
+ else
+ pVDev->DrawPixel( Point( j, i ), aPixelColor );
+ }
+ }
+
+ xGraphicObject.reset(new GraphicObject(pVDev->GetBitmapEx(Point(), Size(nLines, nLines))));
+ bGraphicDirty = false;
+}
+
+
+SfxPoolItem* XFillBitmapItem::CreateDefault() { return new XFillBitmapItem; }
+
+XFillBitmapItem::XFillBitmapItem(const OUString& rName, const GraphicObject& rGraphicObject)
+: NameOrIndex(XATTR_FILLBITMAP, rName),
+ maGraphicObject(rGraphicObject)
+{
+}
+
+XFillBitmapItem::XFillBitmapItem(const XFillBitmapItem& rItem)
+: NameOrIndex(rItem),
+ maGraphicObject(rItem.maGraphicObject)
+{
+}
+
+XFillBitmapItem::XFillBitmapItem(const GraphicObject& rGraphicObject)
+ : NameOrIndex(XATTR_FILLBITMAP, -1)
+ , maGraphicObject(rGraphicObject)
+{
+}
+
+XFillBitmapItem* XFillBitmapItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XFillBitmapItem(*this);
+}
+
+bool XFillBitmapItem::operator==(const SfxPoolItem& rItem) const
+{
+ return (NameOrIndex::operator==(rItem)
+ && maGraphicObject == static_cast<const XFillBitmapItem&>(rItem).maGraphicObject);
+}
+
+
+bool XFillBitmapItem::isPattern() const
+{
+ Color aBack, aFront;
+ return vcl::bitmap::isHistorical8x8(GetGraphicObject().GetGraphic().GetBitmapEx(), aBack, aFront);
+}
+
+bool XFillBitmapItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText,
+ const IntlWrapper&) const
+{
+ rText += GetName();
+ return true;
+}
+
+bool XFillBitmapItem::QueryValue(css::uno::Any& rVal, sal_uInt8 nMemberId) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ // needed for MID_NAME
+ OUString aApiName;
+ // needed for complete item (MID 0)
+ OUString aInternalName;
+
+ css::uno::Reference< css::awt::XBitmap > xBmp;
+
+ if( nMemberId == MID_NAME )
+ {
+ aApiName = SvxUnogetApiNameForItem(Which(), GetName());
+ }
+ else if( nMemberId == 0 )
+ {
+ aInternalName = GetName();
+ }
+
+ if (nMemberId == MID_BITMAP ||
+ nMemberId == 0)
+ {
+ xBmp.set(GetGraphicObject().GetGraphic().GetXGraphic(), uno::UNO_QUERY);
+ }
+
+ if( nMemberId == MID_NAME )
+ rVal <<= aApiName;
+ else if( nMemberId == MID_BITMAP )
+ rVal <<= xBmp;
+ else
+ {
+ // member-id 0 => complete item (e.g. for toolbars)
+ DBG_ASSERT( nMemberId == 0, "invalid member-id" );
+ uno::Sequence< beans::PropertyValue > aPropSeq{
+ comphelper::makePropertyValue("Name", aInternalName),
+ comphelper::makePropertyValue("Bitmap", xBmp)
+ };
+
+ rVal <<= aPropSeq;
+ }
+
+ return true;
+}
+
+bool XFillBitmapItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ OUString aName;
+ OUString aURL;
+ css::uno::Reference< css::awt::XBitmap > xBmp;
+ css::uno::Reference< css::graphic::XGraphic > xGraphic;
+
+ bool bSetURL = false;
+ bool bSetName = false;
+ bool bSetBitmap = false;
+
+ if( nMemberId == MID_NAME )
+ bSetName = (rVal >>= aName);
+ else if( nMemberId == MID_BITMAP )
+ {
+ if (rVal.has<OUString>())
+ {
+ bSetURL = true;
+ aURL = rVal.get<OUString>();
+ }
+ else if (rVal.has<uno::Reference<awt::XBitmap>>())
+ {
+ bSetBitmap = true;
+ xBmp = rVal.get<uno::Reference<awt::XBitmap>>();
+ }
+ else if (rVal.has<uno::Reference<graphic::XGraphic>>())
+ {
+ bSetBitmap = true;
+ xGraphic = rVal.get<uno::Reference<graphic::XGraphic>>();
+ }
+ }
+ else
+ {
+ DBG_ASSERT( nMemberId == 0, "invalid member-id" );
+ uno::Sequence< beans::PropertyValue > aPropSeq;
+ if( rVal >>= aPropSeq )
+ {
+ for ( const auto& rProp : std::as_const(aPropSeq) )
+ {
+ if ( rProp.Name == "Name" )
+ bSetName = (rProp.Value >>= aName);
+ else if ( rProp.Name == "Bitmap" )
+ bSetBitmap = (rProp.Value >>= xBmp);
+ else if ( rProp.Name == "FillBitmapURL" )
+ bSetURL = (rProp.Value >>= aURL);
+ }
+ }
+ }
+
+ if( bSetName )
+ {
+ SetName( aName );
+ }
+ if (bSetURL && !aURL.isEmpty())
+ {
+ Graphic aGraphic = vcl::graphic::loadFromURL(aURL);
+ if (!aGraphic.IsNone())
+ {
+ maGraphicObject.SetGraphic(aGraphic.GetXGraphic());
+ }
+ }
+ else if( bSetBitmap )
+ {
+ if (xBmp.is())
+ {
+ xGraphic.set(xBmp, uno::UNO_QUERY);
+ }
+ if (xGraphic.is())
+ {
+ maGraphicObject.SetGraphic(xGraphic);
+ }
+ }
+
+ return (bSetURL || bSetName || bSetBitmap);
+}
+
+bool XFillBitmapItem::CompareValueFunc( const NameOrIndex* p1, const NameOrIndex* p2 )
+{
+ const GraphicObject& aGraphicObjectA(static_cast<const XFillBitmapItem*>(p1)->GetGraphicObject());
+ const GraphicObject& aGraphicObjectB(static_cast<const XFillBitmapItem*>(p2)->GetGraphicObject());
+
+ return aGraphicObjectA == aGraphicObjectB;
+}
+
+std::unique_ptr<XFillBitmapItem> XFillBitmapItem::checkForUniqueItem( SdrModel* pModel ) const
+{
+ if( pModel )
+ {
+ XPropertyListType aListType = XPropertyListType::Bitmap;
+ if(isPattern())
+ aListType = XPropertyListType::Pattern;
+ const OUString aUniqueName = NameOrIndex::CheckNamedItem(
+ this, XATTR_FILLBITMAP, &pModel->GetItemPool(),
+ XFillBitmapItem::CompareValueFunc, RID_SVXSTR_BMP21,
+ pModel->GetPropertyList( aListType ) );
+
+ // if the given name is not valid, replace it!
+ if( aUniqueName != GetName() )
+ {
+ return std::make_unique<XFillBitmapItem>(aUniqueName, maGraphicObject);
+ }
+ }
+
+ return nullptr;
+}
+
+void XFillBitmapItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("XFillBitmapItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+
+ NameOrIndex::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xpool.cxx b/svx/source/xoutdev/xpool.cxx
new file mode 100644
index 000000000..b3e044e83
--- /dev/null
+++ b/svx/source/xoutdev/xpool.cxx
@@ -0,0 +1,219 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <svx/xflbckit.hxx>
+#include <xftshtit.hxx>
+#include <svx/xflboxy.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xsflclit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xgrscit.hxx>
+#include <svx/xflasit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflbmpit.hxx>
+#include <svx/xflbmsxy.hxx>
+#include <svx/xflbmsli.hxx>
+#include <svx/xflbtoxy.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xfilluseslidebackgrounditem.hxx>
+#include <svx/xtextit0.hxx>
+#include <svx/xlnasit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnedcit.hxx>
+#include <svx/xpool.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svxids.hrc>
+#include <svl/itemset.hxx>
+#include <svx/xftadit.hxx>
+#include <svx/xftdiit.hxx>
+#include <svx/xftstit.hxx>
+#include <svx/xftmrit.hxx>
+#include <svx/xftouit.hxx>
+#include <svx/xftshit.hxx>
+#include <svx/xftshcit.hxx>
+#include <svx/xftshxy.hxx>
+
+XOutdevItemPool::XOutdevItemPool(SfxItemPool* _pMaster)
+ : SfxItemPool("XOutdevItemPool", SDRATTR_START, SDRATTR_END, nullptr, nullptr)
+ , mpLocalPoolDefaults(new std::vector<SfxPoolItem*>(SDRATTR_END - SDRATTR_START + 1))
+ , mpLocalItemInfos(new SfxItemInfo[SDRATTR_END - SDRATTR_START + 1])
+{
+ // prepare some defaults
+ const OUString aNullStr;
+ const Graphic aNullGraphic;
+ const basegfx::B2DPolyPolygon aNullPol;
+ const Color aNullLineCol(COL_DEFAULT_SHAPE_STROKE); // #i121448# Use defined default color
+ const Color aNullFillCol(COL_DEFAULT_SHAPE_FILLING); // #i121448# Use defined default color
+ const Color aNullShadowCol(COL_LIGHTGRAY);
+ const XDash aNullDash;
+ const XHatch aNullHatch(aNullLineCol);
+
+ // get master pointer, evtl. add myself to the end of the pools
+ if(!_pMaster)
+ {
+ _pMaster = this;
+ }
+ else
+ {
+ _pMaster->GetLastPoolInChain()->SetSecondaryPool(this);
+ }
+
+ // prepare PoolDefaults
+ std::vector<SfxPoolItem*>& rPoolDefaults = *mpLocalPoolDefaults;
+ rPoolDefaults[XATTR_LINESTYLE -XATTR_START] = new XLineStyleItem;
+ rPoolDefaults[XATTR_LINEDASH -XATTR_START] = new XLineDashItem(aNullDash);
+ rPoolDefaults[XATTR_LINEWIDTH -XATTR_START] = new XLineWidthItem;
+ rPoolDefaults[XATTR_LINECOLOR -XATTR_START] = new XLineColorItem(aNullStr,aNullLineCol);
+ rPoolDefaults[XATTR_LINESTART -XATTR_START] = new XLineStartItem(aNullPol);
+ rPoolDefaults[XATTR_LINEEND -XATTR_START] = new XLineEndItem (aNullPol);
+ rPoolDefaults[XATTR_LINESTARTWIDTH -XATTR_START] = new XLineStartWidthItem;
+ rPoolDefaults[XATTR_LINEENDWIDTH -XATTR_START] = new XLineEndWidthItem;
+ rPoolDefaults[XATTR_LINESTARTCENTER -XATTR_START] = new XLineStartCenterItem;
+ rPoolDefaults[XATTR_LINEENDCENTER -XATTR_START] = new XLineEndCenterItem;
+ rPoolDefaults[XATTR_LINETRANSPARENCE -XATTR_START] = new XLineTransparenceItem;
+ rPoolDefaults[XATTR_LINEJOINT -XATTR_START] = new XLineJointItem;
+ rPoolDefaults[XATTR_LINECAP -XATTR_START] = new XLineCapItem;
+ rPoolDefaults[XATTR_FILLSTYLE -XATTR_START] = new XFillStyleItem;
+ rPoolDefaults[XATTR_FILLCOLOR -XATTR_START] = new XFillColorItem (aNullStr,aNullFillCol);
+ rPoolDefaults[XATTR_FILLGRADIENT -XATTR_START] = new XFillGradientItem(XGradient(COL_BLACK, COL_WHITE));
+ rPoolDefaults[XATTR_FILLHATCH -XATTR_START] = new XFillHatchItem (aNullHatch);
+ rPoolDefaults[XATTR_FILLBITMAP -XATTR_START] = new XFillBitmapItem (aNullGraphic);
+ rPoolDefaults[XATTR_FILLTRANSPARENCE -XATTR_START] = new XFillTransparenceItem;
+ rPoolDefaults[XATTR_GRADIENTSTEPCOUNT -XATTR_START] = new XGradientStepCountItem;
+ rPoolDefaults[XATTR_FILLBMP_TILE -XATTR_START] = new XFillBmpTileItem;
+ rPoolDefaults[XATTR_FILLBMP_POS -XATTR_START] = new XFillBmpPosItem;
+ rPoolDefaults[XATTR_FILLBMP_SIZEX -XATTR_START] = new XFillBmpSizeXItem;
+ rPoolDefaults[XATTR_FILLBMP_SIZEY -XATTR_START] = new XFillBmpSizeYItem;
+ rPoolDefaults[XATTR_FILLBMP_SIZELOG -XATTR_START] = new XFillBmpSizeLogItem;
+ rPoolDefaults[XATTR_FILLBMP_TILEOFFSETX -XATTR_START] = new XFillBmpTileOffsetXItem;
+ rPoolDefaults[XATTR_FILLBMP_TILEOFFSETY -XATTR_START] = new XFillBmpTileOffsetYItem;
+ rPoolDefaults[XATTR_FILLBMP_STRETCH -XATTR_START] = new XFillBmpStretchItem;
+ rPoolDefaults[XATTR_FILLBMP_POSOFFSETX -XATTR_START] = new XFillBmpPosOffsetXItem;
+ rPoolDefaults[XATTR_FILLBMP_POSOFFSETY -XATTR_START] = new XFillBmpPosOffsetYItem;
+ rPoolDefaults[XATTR_FILLFLOATTRANSPARENCE -XATTR_START] = new XFillFloatTransparenceItem( XGradient(COL_BLACK, COL_BLACK), false );
+ rPoolDefaults[XATTR_SECONDARYFILLCOLOR -XATTR_START] = new XSecondaryFillColorItem(aNullStr, aNullFillCol);
+ rPoolDefaults[XATTR_FILLBACKGROUND -XATTR_START] = new XFillBackgroundItem;
+ rPoolDefaults[XATTR_FILLUSESLIDEBACKGROUND -XATTR_START] = new XFillUseSlideBackgroundItem;
+ rPoolDefaults[XATTR_FORMTXTSTYLE -XATTR_START] = new XFormTextStyleItem;
+ rPoolDefaults[XATTR_FORMTXTADJUST -XATTR_START] = new XFormTextAdjustItem;
+ rPoolDefaults[XATTR_FORMTXTDISTANCE -XATTR_START] = new XFormTextDistanceItem;
+ rPoolDefaults[XATTR_FORMTXTSTART -XATTR_START] = new XFormTextStartItem;
+ rPoolDefaults[XATTR_FORMTXTMIRROR -XATTR_START] = new XFormTextMirrorItem;
+ rPoolDefaults[XATTR_FORMTXTOUTLINE -XATTR_START] = new XFormTextOutlineItem;
+ rPoolDefaults[XATTR_FORMTXTSHADOW -XATTR_START] = new XFormTextShadowItem;
+ rPoolDefaults[XATTR_FORMTXTSHDWCOLOR -XATTR_START] = new XFormTextShadowColorItem(aNullStr,aNullShadowCol);
+ rPoolDefaults[XATTR_FORMTXTSHDWXVAL -XATTR_START] = new XFormTextShadowXValItem;
+ rPoolDefaults[XATTR_FORMTXTSHDWYVAL -XATTR_START] = new XFormTextShadowYValItem;
+ rPoolDefaults[XATTR_FORMTXTHIDEFORM -XATTR_START] = new XFormTextHideFormItem;
+ rPoolDefaults[XATTR_FORMTXTSHDWTRANSP -XATTR_START] = new XFormTextShadowTranspItem;
+
+ // create SetItems
+ rPoolDefaults[XATTRSET_LINE - XATTR_START] = new XLineAttrSetItem(
+ SfxItemSetFixed<XATTR_LINE_FIRST, XATTR_LINE_LAST>( *_pMaster ) );
+ rPoolDefaults[XATTRSET_FILL - XATTR_START] = new XFillAttrSetItem(
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>( *_pMaster ) );
+
+ // create ItemInfos
+ for(sal_uInt16 i(GetFirstWhich()); i <= GetLastWhich(); i++)
+ {
+ mpLocalItemInfos[i - XATTR_START]._nSID = 0;
+ mpLocalItemInfos[i - XATTR_START]._bPoolable = true;
+ }
+
+ mpLocalItemInfos[XATTR_LINESTYLE -XATTR_START]._nSID = SID_ATTR_LINE_STYLE;
+ mpLocalItemInfos[XATTR_LINEDASH -XATTR_START]._nSID = SID_ATTR_LINE_DASH;
+ mpLocalItemInfos[XATTR_LINEWIDTH -XATTR_START]._nSID = SID_ATTR_LINE_WIDTH;
+ mpLocalItemInfos[XATTR_LINECOLOR -XATTR_START]._nSID = SID_ATTR_LINE_COLOR;
+ mpLocalItemInfos[XATTR_LINESTART -XATTR_START]._nSID = SID_ATTR_LINE_START;
+ mpLocalItemInfos[XATTR_LINEEND -XATTR_START]._nSID = SID_ATTR_LINE_END;
+ mpLocalItemInfos[XATTR_LINESTARTWIDTH -XATTR_START]._nSID = SID_ATTR_LINE_STARTWIDTH;
+ mpLocalItemInfos[XATTR_LINEENDWIDTH -XATTR_START]._nSID = SID_ATTR_LINE_ENDWIDTH;
+ mpLocalItemInfos[XATTR_LINESTARTCENTER -XATTR_START]._nSID = SID_ATTR_LINE_STARTCENTER;
+ mpLocalItemInfos[XATTR_LINEENDCENTER -XATTR_START]._nSID = SID_ATTR_LINE_ENDCENTER;
+ mpLocalItemInfos[XATTR_FILLSTYLE -XATTR_START]._nSID = SID_ATTR_FILL_STYLE;
+ mpLocalItemInfos[XATTR_FILLCOLOR -XATTR_START]._nSID = SID_ATTR_FILL_COLOR;
+ mpLocalItemInfos[XATTR_FILLGRADIENT -XATTR_START]._nSID = SID_ATTR_FILL_GRADIENT;
+ mpLocalItemInfos[XATTR_FILLHATCH -XATTR_START]._nSID = SID_ATTR_FILL_HATCH;
+ mpLocalItemInfos[XATTR_FILLBITMAP -XATTR_START]._nSID = SID_ATTR_FILL_BITMAP;
+ mpLocalItemInfos[XATTR_FORMTXTSTYLE -XATTR_START]._nSID = SID_FORMTEXT_STYLE;
+ mpLocalItemInfos[XATTR_FORMTXTADJUST -XATTR_START]._nSID = SID_FORMTEXT_ADJUST;
+ mpLocalItemInfos[XATTR_FORMTXTDISTANCE -XATTR_START]._nSID = SID_FORMTEXT_DISTANCE;
+ mpLocalItemInfos[XATTR_FORMTXTSTART -XATTR_START]._nSID = SID_FORMTEXT_START;
+ mpLocalItemInfos[XATTR_FORMTXTMIRROR -XATTR_START]._nSID = SID_FORMTEXT_MIRROR;
+ mpLocalItemInfos[XATTR_FORMTXTOUTLINE -XATTR_START]._nSID = SID_FORMTEXT_OUTLINE;
+ mpLocalItemInfos[XATTR_FORMTXTSHADOW -XATTR_START]._nSID = SID_FORMTEXT_SHADOW;
+ mpLocalItemInfos[XATTR_FORMTXTSHDWCOLOR -XATTR_START]._nSID = SID_FORMTEXT_SHDWCOLOR;
+ mpLocalItemInfos[XATTR_FORMTXTSHDWXVAL -XATTR_START]._nSID = SID_FORMTEXT_SHDWXVAL;
+ mpLocalItemInfos[XATTR_FORMTXTSHDWYVAL -XATTR_START]._nSID = SID_FORMTEXT_SHDWYVAL;
+ mpLocalItemInfos[XATTR_FORMTXTHIDEFORM -XATTR_START]._nSID = SID_FORMTEXT_HIDEFORM;
+
+ // associate new slots for panels with known items
+ mpLocalItemInfos[XATTR_FILLUSESLIDEBACKGROUND - XATTR_START]._nSID = SID_ATTR_FILL_USE_SLIDE_BACKGROUND;
+ mpLocalItemInfos[XATTR_FILLTRANSPARENCE - XATTR_START]._nSID = SID_ATTR_FILL_TRANSPARENCE;
+ mpLocalItemInfos[XATTR_FILLFLOATTRANSPARENCE - XATTR_START]._nSID = SID_ATTR_FILL_FLOATTRANSPARENCE;
+ mpLocalItemInfos[XATTR_LINETRANSPARENCE - XATTR_START]._nSID = SID_ATTR_LINE_TRANSPARENCE;
+ mpLocalItemInfos[XATTR_LINEJOINT - XATTR_START]._nSID = SID_ATTR_LINE_JOINT;
+ mpLocalItemInfos[XATTR_LINECAP - XATTR_START]._nSID = SID_ATTR_LINE_CAP;
+
+ // if it's my own creation level, set Defaults and ItemInfos
+ if(XATTR_START == GetFirstWhich() && XATTR_END == GetLastWhich())
+ {
+ SetDefaults(mpLocalPoolDefaults);
+ SetItemInfos(mpLocalItemInfos.get());
+ }
+}
+
+// copy ctor, clones all static defaults
+XOutdevItemPool::XOutdevItemPool(const XOutdevItemPool& rPool)
+: SfxItemPool(rPool, true),
+ mpLocalPoolDefaults(nullptr)
+{
+}
+
+rtl::Reference<SfxItemPool> XOutdevItemPool::Clone() const
+{
+ return new XOutdevItemPool(*this);
+}
+
+XOutdevItemPool::~XOutdevItemPool()
+{
+ Delete();
+ // release and delete static pool default items
+ ReleaseDefaults(true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xtabbtmp.cxx b/svx/source/xoutdev/xtabbtmp.cxx
new file mode 100644
index 000000000..178ba8ab2
--- /dev/null
+++ b/svx/source/xoutdev/xtabbtmp.cxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <XPropertyTable.hxx>
+
+#include <osl/diagnose.h>
+#include <vcl/virdev.hxx>
+#include <svx/xtable.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace com::sun::star;
+
+XBitmapEntry* XBitmapList::GetBitmap(tools::Long nIndex) const
+{
+ return static_cast<XBitmapEntry*>( XPropertyList::Get(nIndex) );
+}
+
+uno::Reference< container::XNameContainer > XBitmapList::createInstance()
+{
+ return SvxUnoXBitmapTable_createInstance( *this );
+}
+
+bool XBitmapList::Create()
+{
+ return true;
+}
+
+BitmapEx XBitmapList::CreateBitmap( tools::Long nIndex, const Size& rSize ) const
+{
+ OSL_ENSURE( nIndex < Count(), "Access out of range" );
+
+ if(nIndex < Count())
+ {
+ BitmapEx rBitmapEx = GetBitmap( nIndex )->GetGraphicObject().GetGraphic().GetBitmapEx();
+ ScopedVclPtrInstance< VirtualDevice > pVirtualDevice;
+ pVirtualDevice->SetOutputSizePixel(rSize);
+
+ if(rBitmapEx.IsAlpha())
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ if(rStyleSettings.GetPreviewUsesCheckeredBackground())
+ {
+ const Point aNull(0, 0);
+ static const sal_uInt32 nLen(8);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+
+ pVirtualDevice->DrawCheckered(aNull, rSize, nLen, aW, aG);
+ }
+ else
+ {
+ pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor());
+ pVirtualDevice->Erase();
+ }
+ }
+
+ if(rBitmapEx.GetSizePixel().Width() >= rSize.Width() && rBitmapEx.GetSizePixel().Height() >= rSize.Height())
+ {
+ rBitmapEx.Scale(rSize);
+ pVirtualDevice->DrawBitmapEx(Point(0, 0), rBitmapEx);
+ }
+ else
+ {
+ const Size aBitmapSize(rBitmapEx.GetSizePixel());
+
+ for(tools::Long y(0); y < rSize.Height(); y += aBitmapSize.Height())
+ {
+ for(tools::Long x(0); x < rSize.Width(); x += aBitmapSize.Width())
+ {
+ pVirtualDevice->DrawBitmapEx(
+ Point(x, y),
+ rBitmapEx);
+ }
+ }
+ }
+ rBitmapEx = pVirtualDevice->GetBitmapEx(Point(0, 0), rSize);
+ return rBitmapEx;
+ }
+ else
+ return BitmapEx();
+}
+
+BitmapEx XBitmapList::CreateBitmapForUI( tools::Long nIndex )
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
+ return CreateBitmap(nIndex, rSize);
+}
+
+BitmapEx XBitmapList::GetBitmapForPreview( tools::Long nIndex, const Size& rSize )
+{
+ return CreateBitmap(nIndex, rSize);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xtabcolr.cxx b/svx/source/xoutdev/xtabcolr.cxx
new file mode 100644
index 000000000..e952d6f8a
--- /dev/null
+++ b/svx/source/xoutdev/xtabcolr.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <XPropertyTable.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/pathoptions.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/xtable.hxx>
+
+using namespace com::sun::star;
+
+XColorListRef XColorList::CreateStdColorList()
+{
+ return XPropertyList::AsColorList(
+ XPropertyList::CreatePropertyList(
+ XPropertyListType::Color, !utl::ConfigManager::IsFuzzing() ?
+ SvtPathOptions().GetPalettePath() :
+ "", ""));
+}
+
+XColorListRef XColorList::GetStdColorList()
+{
+ XColorListRef aTable( CreateStdColorList() );
+ return aTable;
+}
+
+void XColorList::Replace(tools::Long nIndex, std::unique_ptr<XColorEntry> pEntry)
+{
+ XPropertyList::Replace(std::move(pEntry), nIndex);
+}
+XColorEntry* XColorList::GetColor(tools::Long nIndex) const
+{
+ return static_cast<XColorEntry*>( XPropertyList::Get(nIndex) );
+}
+
+uno::Reference< container::XNameContainer > XColorList::createInstance()
+{
+ return SvxUnoXColorTable_createInstance( *this );
+}
+
+bool XColorList::Create()
+{
+ sal_uInt32 a(0);
+ sal_uInt32 b(0);
+
+ // <!-- Gray palette from white to black -->
+ const OUString aStrGrey( SvxResId( RID_SVXSTR_COLOR_GREY ) );
+
+ Insert( std::make_unique<XColorEntry>( Color( 0xff, 0xff, 0xff ), SvxResId( RID_SVXSTR_COLOR_WHITE ) ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xee, 0xee, 0xee ), aStrGrey + " 1" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xdd, 0xdd, 0xdd ), aStrGrey + " 2" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xcc, 0xcc, 0xcc ), aStrGrey + " 3" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xb2, 0xb2, 0xb2 ), aStrGrey + " 4" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x99, 0x99, 0x99 ), aStrGrey + " 5" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x80, 0x80, 0x80 ), aStrGrey + " 6" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x66, 0x66, 0x66 ), aStrGrey + " 7" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x33, 0x33, 0x33 ), aStrGrey + " 8" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x1c, 0x1c, 0x1c ), aStrGrey + " 9" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x11, 0x11, 0x11 ), aStrGrey + " 10") );
+ Insert( std::make_unique<XColorEntry>( Color( 0x00, 0x00, 0x00 ), SvxResId( RID_SVXSTR_COLOR_BLACK ) ) );
+
+ // <!-- Base colors step 0 to 10 -->
+ const sal_uInt32 nNumColorsInGroup(12);
+ const sal_uInt32 nNumGroups(11);
+ const OUString aStrCol[nNumColorsInGroup] = {
+ SvxResId(RID_SVXSTR_COLOR_YELLOW),
+ SvxResId(RID_SVXSTR_COLOR_ORANGE),
+ SvxResId(RID_SVXSTR_COLOR_RED),
+ SvxResId(RID_SVXSTR_COLOR_PINK),
+ SvxResId(RID_SVXSTR_COLOR_MAGENTA),
+ SvxResId(RID_SVXSTR_COLOR_PURPLE),
+ SvxResId(RID_SVXSTR_COLOR_BLUE),
+ SvxResId(RID_SVXSTR_COLOR_SKYBLUE),
+ SvxResId(RID_SVXSTR_COLOR_CYAN),
+ SvxResId(RID_SVXSTR_COLOR_TURQUOISE),
+ SvxResId(RID_SVXSTR_COLOR_GREEN),
+ SvxResId(RID_SVXSTR_COLOR_YELLOWGREEN) };
+ static const sal_uInt32 aStdCol[nNumColorsInGroup * nNumGroups] = {
+ 0xffff99, 0xff6600, 0xff3333, 0xff00cc, 0xff33ff, 0x9900ff, 0x6666ff, 0x00ccff, 0x66ffff, 0x33ff99, 0x99ff66, 0xccff00,
+ 0xffff66, 0xffcc00, 0xff9999, 0xff66cc, 0xff99ff, 0xcc66ff, 0x9999ff, 0x9999ff, 0x99ffff, 0x66ff99, 0x99ff99, 0xccff66,
+ 0xffff00, 0xff9900, 0xff6666, 0xff3399, 0xff66ff, 0x9933ff, 0x3333ff, 0x3399ff, 0x00ffff, 0x00ff66, 0x66ff66, 0x99ff33,
+ 0xcc9900, 0xff3300, 0xff0000, 0xff0066, 0xff00ff, 0x6600ff, 0x0000ff, 0x0066ff, 0x00cccc, 0x00cc33, 0x00cc00, 0x66ff00,
+ 0x996600, 0xcc3300, 0xcc0000, 0xcc0066, 0xcc00cc, 0x6600cc, 0x0000cc, 0x0066cc, 0x009999, 0x009933, 0x009900, 0x66cc00,
+ 0x663300, 0x801900, 0x990000, 0x990066, 0x990099, 0x330099, 0x000099, 0x006699, 0x006666, 0x007826, 0x006600, 0x669900,
+ 0x333300, 0x461900, 0x330000, 0x330033, 0x660066, 0x000033, 0x000066, 0x000080, 0x003333, 0x00331a, 0x003300, 0x193300,
+ 0x666633, 0x661900, 0x663333, 0x660033, 0x663366, 0x330066, 0x333366, 0x003366, 0x336666, 0x006633, 0x336633, 0x336600,
+ 0x999966, 0x996633, 0x996666, 0x993366, 0x996699, 0x663399, 0x666699, 0x336699, 0x669999, 0x339966, 0x669966, 0x669933,
+ 0xcccc99, 0xcc9966, 0xcc9999, 0xcc6699, 0xcc99cc, 0x9966cc, 0x9999cc, 0x6699cc, 0x99cccc, 0x66cc99, 0x99cc99, 0x99cc66,
+ 0xffffcc, 0xffcc99, 0xffcccc, 0xff99cc, 0xffccff, 0xcc99ff, 0xccccff, 0x99ccff, 0xccffff, 0x99ffcc, 0xccffcc, 0xccff99 };
+
+ for(a = 0; a < nNumGroups; a++)
+ {
+ OUString aSuffix;
+ if (a > 0) aSuffix = OUString::number(a);
+
+ const sal_uInt32 nOffset(a * nNumColorsInGroup);
+
+ for(b = 0; b < nNumColorsInGroup; b++)
+ {
+ Insert( std::make_unique<XColorEntry>( Color(ColorTransparency, aStdCol[nOffset + b]), aStrCol[b] + aSuffix ) );
+ }
+ }
+
+ // <!-- use some 'nice' colors from original palette -->
+ Insert( std::make_unique<XColorEntry>( Color( 0xe6, 0xe6, 0xff ), SvxResId( RID_SVXSTR_COLOR_BLUEGREY) ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xCF, 0xE7, 0xF5 ), SvxResId( RID_SVXSTR_COLOR_BLUE_CLASSIC ) ) );
+
+ // <!-- add 'pale' colors from original palette -->
+ Insert( std::make_unique<XColorEntry>( Color( 0x99, 0x99, 0xff ), SvxResId( RID_SVXSTR_COLOR_VIOLET ) ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x99, 0x33, 0x66 ), SvxResId( RID_SVXSTR_COLOR_BORDEAUX ) ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xff, 0xff, 0xcc ), SvxResId( RID_SVXSTR_COLOR_PALE_YELLOW ) ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xcc, 0xff, 0xff ), SvxResId( RID_SVXSTR_COLOR_PALE_GREEN ) ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x66, 0x00, 0x66 ), SvxResId( RID_SVXSTR_COLOR_DARKVIOLET ) ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xff, 0x80, 0x80 ), SvxResId( RID_SVXSTR_COLOR_SALMON ) ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x00, 0x66, 0xcc ), SvxResId( RID_SVXSTR_COLOR_SEABLUE ) ) );
+
+ // <!-- add Chart colors from original palette (also 12, coincidence?) -->
+ const OUString aStrChart( SvxResId( RID_SVXSTR_COLOR_CHART ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x00, 0x45, 0x86 ), aStrChart + " 1" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xff, 0x42, 0x0e ), aStrChart + " 2" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xff, 0xd3, 0x20 ), aStrChart + " 3" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x57, 0x9d, 0x1c ), aStrChart + " 4" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x7e, 0x00, 0x21 ), aStrChart + " 5" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x83, 0xca, 0xff ), aStrChart + " 6" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x31, 0x40, 0x04 ), aStrChart + " 7" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xae, 0xcf, 0x00 ), aStrChart + " 8" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x4b, 0x1f, 0x6f ), aStrChart + " 9" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xff, 0x95, 0x0e ), aStrChart + " 10" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0xc5, 0x00, 0x0b ), aStrChart + " 11" ) );
+ Insert( std::make_unique<XColorEntry>( Color( 0x00, 0x84, 0xd1 ), aStrChart + " 12" ) );
+
+ return(165 == Count());
+}
+
+BitmapEx XColorList::CreateBitmapForUI( tools::Long /*nIndex*/ )
+{
+ return BitmapEx();
+}
+
+tools::Long XColorList::GetIndexOfColor( const Color& rColor ) const
+{
+ for( tools::Long i = 0, n = maList.size(); i < n; ++i )
+ {
+ const Color aColor = static_cast<XColorEntry*>( maList[i].get() )->GetColor();
+
+ if (aColor == rColor )
+ return i;
+ }
+
+ return -1;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xtabdash.cxx b/svx/source/xoutdev/xtabdash.cxx
new file mode 100644
index 000000000..da5ec20a3
--- /dev/null
+++ b/svx/source/xoutdev/xtabdash.cxx
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <XPropertyTable.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <vcl/virdev.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/xtable.hxx>
+
+#include <comphelper/lok.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+#include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+
+XDashList::XDashList(const OUString& rPath, const OUString& rReferer)
+ : XPropertyList(XPropertyListType::Dash, rPath, rReferer)
+{
+}
+
+XDashList::~XDashList()
+{
+}
+
+void XDashList::Replace(std::unique_ptr<XDashEntry> pEntry, tools::Long nIndex)
+{
+ XPropertyList::Replace(std::move(pEntry), nIndex);
+}
+
+XDashEntry* XDashList::GetDash(tools::Long nIndex) const
+{
+ return static_cast<XDashEntry*>( XPropertyList::Get(nIndex) );
+}
+
+uno::Reference< container::XNameContainer > XDashList::createInstance()
+{
+ return SvxUnoXDashTable_createInstance( *this );
+}
+
+bool XDashList::Create()
+{
+ const OUString aStr(SvxResId(RID_SVXSTR_LINESTYLE));
+
+ Insert(std::make_unique<XDashEntry>(XDash(css::drawing::DashStyle_RECT,1, 50,1, 50, 50),aStr + " 1"));
+ Insert(std::make_unique<XDashEntry>(XDash(css::drawing::DashStyle_RECT,1,500,1,500,500),aStr + " 2"));
+ Insert(std::make_unique<XDashEntry>(XDash(css::drawing::DashStyle_RECT,2, 50,3,250,120),aStr + " 3"));
+
+ return true;
+}
+
+BitmapEx XDashList::ImpCreateBitmapForXDash(const XDash* pDash)
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
+ const sal_uInt32 nFactor(2);
+ const Size aSize((rSize.Width() * 5 * 2) / 2, rSize.Height() * nFactor);
+
+ // prepare polygon geometry for line
+ basegfx::B2DPolygon aLine;
+
+ aLine.append(basegfx::B2DPoint(0.0, aSize.Height() / 2.0));
+ aLine.append(basegfx::B2DPoint(aSize.Width(), aSize.Height() / 2.0));
+
+ // prepare LineAttribute
+ const basegfx::BColor aLineColor(rStyleSettings.GetFieldTextColor().getBColor());
+ const double fLineWidth(StyleSettings::GetListBoxPreviewDefaultLineWidth() * (nFactor * 1.1));
+ const drawinglayer::attribute::LineAttribute aLineAttribute(
+ aLineColor,
+ fLineWidth);
+
+ // prepare StrokeAttribute
+ ::std::vector< double > aDotDashArray;
+ double fFullDotDashLen(0.0);
+
+ if(pDash && (pDash->GetDots() || pDash->GetDashes()))
+ {
+ const basegfx::B2DHomMatrix aScaleMatrix(OutputDevice::LogicToLogic(MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapPixel)));
+ const basegfx::B2DVector aScaleVector(aScaleMatrix * basegfx::B2DVector(1.0, 0.0));
+ const double fScaleValue(aScaleVector.getLength() * (nFactor * (1.4 / 2.0)));
+ const double fLineWidthInUnits(fLineWidth / fScaleValue);
+
+ fFullDotDashLen = pDash->CreateDotDashArray(aDotDashArray, fLineWidthInUnits);
+
+ if(!aDotDashArray.empty())
+ {
+ for(double & a : aDotDashArray)
+ {
+ a *= fScaleValue;
+ // ~zero length dash is a dot-like dot (with line width size round cap), so show it
+ if (a < 0.1)
+ a += 1.0;
+ }
+
+ fFullDotDashLen *= fScaleValue;
+ }
+ }
+
+ const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(
+ std::move(aDotDashArray),
+ fFullDotDashLen);
+
+ // create LinePrimitive
+ const drawinglayer::primitive2d::Primitive2DReference aLinePrimitive(
+ new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
+ aLine,
+ aLineAttribute,
+ aStrokeAttribute));
+
+ // prepare VirtualDevice
+ ScopedVclPtrInstance< VirtualDevice > pVirtualDevice;
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
+
+ pVirtualDevice->SetOutputSizePixel(aSize);
+ pVirtualDevice->SetDrawMode(rStyleSettings.GetHighContrastMode()
+ ? DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient
+ : DrawModeFlags::Default);
+
+ if(rStyleSettings.GetPreviewUsesCheckeredBackground())
+ {
+ const Point aNull(0, 0);
+ static const sal_uInt32 nLen(8 * nFactor);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+
+ pVirtualDevice->DrawCheckered(aNull, aSize, nLen, aW, aG);
+ }
+ else
+ {
+ pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor());
+ pVirtualDevice->Erase();
+ }
+
+ // create processor and draw primitives
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
+ *pVirtualDevice,
+ aNewViewInformation2D));
+
+ const drawinglayer::primitive2d::Primitive2DContainer aSequence { aLinePrimitive };
+
+ pProcessor2D->process(aSequence);
+ pProcessor2D.reset();
+
+ // get result bitmap and scale
+ BitmapEx aRetval(pVirtualDevice->GetBitmapEx(Point(0, 0), pVirtualDevice->GetOutputSizePixel()));
+
+ if(1 != nFactor)
+ {
+ aRetval.Scale(Size((rSize.Width() * 5) / 2, rSize.Height()));
+ }
+
+ return aRetval;
+}
+
+BitmapEx XDashList::CreateBitmapForUI( tools::Long nIndex )
+{
+ const XDash& rDash = GetDash(nIndex)->GetDash();
+
+ return ImpCreateBitmapForXDash(&rDash);
+}
+
+BitmapEx const & XDashList::GetBitmapForUISolidLine() const
+{
+ if(maBitmapSolidLine.IsEmpty())
+ {
+ const_cast< XDashList* >(this)->maBitmapSolidLine = XDashList::ImpCreateBitmapForXDash(nullptr);
+ }
+
+ return maBitmapSolidLine;
+}
+
+OUString const & XDashList::GetStringForUiSolidLine() const
+{
+ if(maStringSolidLine.isEmpty())
+ {
+ const_cast< XDashList* >(this)->maStringSolidLine = SvxResId(RID_SVXSTR_SOLID);
+ }
+
+ return maStringSolidLine;
+}
+
+OUString const & XDashList::GetStringForUiNoLine() const
+{
+ if(maStringNoLine.isEmpty())
+ {
+ // formerly was RID_SVXSTR_INVISIBLE, but to make equal
+ // everywhere, use RID_SVXSTR_NONE
+ const_cast< XDashList* >(this)->maStringNoLine = comphelper::LibreOfficeKit::isActive() ? SvxResId(RID_SVXSTR_INVISIBLE) :
+ SvxResId(RID_SVXSTR_NONE);
+ }
+
+ return maStringNoLine;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xtabgrdt.cxx b/svx/source/xoutdev/xtabgrdt.cxx
new file mode 100644
index 000000000..3d2acb574
--- /dev/null
+++ b/svx/source/xoutdev/xtabgrdt.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <XPropertyTable.hxx>
+
+#include <vcl/virdev.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/xtable.hxx>
+
+#include <rtl/ustrbuf.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <osl/diagnose.h>
+
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+
+XGradientList::XGradientList( const OUString& rPath, const OUString& rReferer )
+: XPropertyList( XPropertyListType::Gradient, rPath, rReferer )
+{
+}
+
+XGradientList::~XGradientList()
+{
+}
+
+void XGradientList::Replace(std::unique_ptr<XGradientEntry> pEntry, tools::Long nIndex)
+{
+ XPropertyList::Replace(std::move(pEntry), nIndex);
+}
+
+XGradientEntry* XGradientList::GetGradient(tools::Long nIndex) const
+{
+ return static_cast<XGradientEntry*>( XPropertyList::Get( nIndex ) );
+}
+
+uno::Reference< container::XNameContainer > XGradientList::createInstance()
+{
+ return SvxUnoXGradientTable_createInstance( *this );
+}
+
+bool XGradientList::Create()
+{
+ OUStringBuffer aStr(SvxResId(RID_SVXSTR_GRADIENT));
+ aStr.append(" 1");
+ sal_Int32 nLen = aStr.getLength() - 1;
+ Insert(std::make_unique<XGradientEntry>(XGradient(COL_BLACK, COL_WHITE, css::awt::GradientStyle_LINEAR , 0_deg10,10,10, 0,100,100),aStr.toString()));
+ aStr[nLen] = '2';
+ Insert(std::make_unique<XGradientEntry>(XGradient(COL_BLUE, COL_RED, css::awt::GradientStyle_AXIAL , 300_deg10,20,20,10,100,100),aStr.toString()));
+ aStr[nLen] = '3';
+ Insert(std::make_unique<XGradientEntry>(XGradient(COL_RED, COL_YELLOW,css::awt::GradientStyle_RADIAL , 600_deg10,30,30,20,100,100),aStr.toString()));
+ aStr[nLen] = '4';
+ Insert(std::make_unique<XGradientEntry>(XGradient(COL_YELLOW , COL_GREEN, css::awt::GradientStyle_ELLIPTICAL, 900_deg10,40,40,30,100,100),aStr.toString()));
+ aStr[nLen] = '5';
+ Insert(std::make_unique<XGradientEntry>(XGradient(COL_GREEN , COL_MAGENTA,css::awt::GradientStyle_SQUARE , 1200_deg10,50,50,40,100,100),aStr.toString()));
+ aStr[nLen] = '6';
+ Insert(std::make_unique<XGradientEntry>(XGradient(COL_MAGENTA, COL_YELLOW ,css::awt::GradientStyle_RECT , 1900_deg10,60,60,50,100,100),aStr.toString()));
+
+ return true;
+}
+
+BitmapEx XGradientList::CreateBitmap( tools::Long nIndex, const Size& rSize ) const
+{
+ BitmapEx aRetval;
+
+ OSL_ENSURE(nIndex < Count(), "OOps, access out of range (!)");
+
+ if(nIndex < Count())
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ // prepare polygon geometry for rectangle
+ const basegfx::B2DPolygon aRectangle(
+ basegfx::utils::createPolygonFromRect(
+ basegfx::B2DRange(0.0, 0.0, rSize.Width(), rSize.Height())));
+
+ const XGradient& rGradient = GetGradient(nIndex)->GetGradient();
+ const sal_uInt16 nStartIntens(rGradient.GetStartIntens());
+ basegfx::BColor aStart(rGradient.GetStartColor().getBColor());
+
+ if(nStartIntens != 100)
+ {
+ const basegfx::BColor aBlack;
+ aStart = interpolate(aBlack, aStart, static_cast<double>(nStartIntens) * 0.01);
+ }
+
+ const sal_uInt16 nEndIntens(rGradient.GetEndIntens());
+ basegfx::BColor aEnd(rGradient.GetEndColor().getBColor());
+
+ if(nEndIntens != 100)
+ {
+ const basegfx::BColor aBlack;
+ aEnd = interpolate(aBlack, aEnd, static_cast<double>(nEndIntens) * 0.01);
+ }
+
+ drawinglayer::attribute::GradientStyle aGradientStyle(drawinglayer::attribute::GradientStyle::Rect);
+
+ switch(rGradient.GetGradientStyle())
+ {
+ case css::awt::GradientStyle_LINEAR :
+ {
+ aGradientStyle = drawinglayer::attribute::GradientStyle::Linear;
+ break;
+ }
+ case css::awt::GradientStyle_AXIAL :
+ {
+ aGradientStyle = drawinglayer::attribute::GradientStyle::Axial;
+ break;
+ }
+ case css::awt::GradientStyle_RADIAL :
+ {
+ aGradientStyle = drawinglayer::attribute::GradientStyle::Radial;
+ break;
+ }
+ case css::awt::GradientStyle_ELLIPTICAL :
+ {
+ aGradientStyle = drawinglayer::attribute::GradientStyle::Elliptical;
+ break;
+ }
+ case css::awt::GradientStyle_SQUARE :
+ {
+ aGradientStyle = drawinglayer::attribute::GradientStyle::Square;
+ break;
+ }
+ default :
+ {
+ aGradientStyle = drawinglayer::attribute::GradientStyle::Rect; // css::awt::GradientStyle_RECT
+ break;
+ }
+ }
+
+ const drawinglayer::attribute::FillGradientAttribute aFillGradient(
+ aGradientStyle,
+ static_cast<double>(rGradient.GetBorder()) * 0.01,
+ static_cast<double>(rGradient.GetXOffset()) * 0.01,
+ static_cast<double>(rGradient.GetYOffset()) * 0.01,
+ toRadians(rGradient.GetAngle()),
+ aStart,
+ aEnd);
+
+ const drawinglayer::primitive2d::Primitive2DReference aGradientPrimitive(
+ new drawinglayer::primitive2d::PolyPolygonGradientPrimitive2D(
+ basegfx::B2DPolyPolygon(aRectangle),
+ aFillGradient));
+
+ const basegfx::BColor aBlack(0.0, 0.0, 0.0);
+ const drawinglayer::primitive2d::Primitive2DReference aBlackRectanglePrimitive(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ aRectangle,
+ aBlack));
+
+ // prepare VirtualDevice
+ ScopedVclPtrInstance< VirtualDevice > pVirtualDevice;
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
+
+ pVirtualDevice->SetOutputSizePixel(rSize);
+ pVirtualDevice->SetDrawMode(rStyleSettings.GetHighContrastMode()
+ ? DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient
+ : DrawModeFlags::Default);
+
+ // create processor and draw primitives
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
+ *pVirtualDevice,
+ aNewViewInformation2D));
+
+ drawinglayer::primitive2d::Primitive2DContainer aSequence(2);
+
+ aSequence[0] = aGradientPrimitive;
+ aSequence[1] = aBlackRectanglePrimitive;
+
+ pProcessor2D->process(aSequence);
+ pProcessor2D.reset();
+
+ // get result bitmap and scale
+ aRetval = pVirtualDevice->GetBitmapEx(Point(0, 0), pVirtualDevice->GetOutputSizePixel());
+ }
+
+ return aRetval;
+}
+
+BitmapEx XGradientList::CreateBitmapForUI(tools::Long nIndex)
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
+ return CreateBitmap(nIndex, rSize);
+}
+
+BitmapEx XGradientList::GetBitmapForPreview(tools::Long nIndex, const Size& rSize)
+{
+ return CreateBitmap(nIndex, rSize);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xtabhtch.cxx b/svx/source/xoutdev/xtabhtch.cxx
new file mode 100644
index 000000000..4fc97727b
--- /dev/null
+++ b/svx/source/xoutdev/xtabhtch.cxx
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <XPropertyTable.hxx>
+#include <vcl/svapp.hxx>
+
+#include <vcl/virdev.hxx>
+#include <vcl/settings.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+
+#include <drawinglayer/attribute/fillhatchattribute.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHatchPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+
+XHatchList::XHatchList(const OUString& rPath, const OUString& rReferer)
+ : XPropertyList( XPropertyListType::Hatch, rPath, rReferer )
+{
+}
+
+XHatchList::~XHatchList()
+{
+}
+
+void XHatchList::Replace(std::unique_ptr<XHatchEntry> pEntry, tools::Long nIndex)
+{
+ XPropertyList::Replace(std::move(pEntry), nIndex);
+}
+
+XHatchEntry* XHatchList::GetHatch(tools::Long nIndex) const
+{
+ return static_cast<XHatchEntry*>( XPropertyList::Get(nIndex) );
+}
+
+uno::Reference< container::XNameContainer > XHatchList::createInstance()
+{
+ return SvxUnoXHatchTable_createInstance( *this );
+}
+
+bool XHatchList::Create()
+{
+ OUStringBuffer aStr(SvxResId(RID_SVXSTR_HATCH));
+ aStr.append(" 1");
+
+ sal_Int32 nLen = aStr.getLength() - 1;
+ Insert(std::make_unique<XHatchEntry>(XHatch(COL_BLACK,css::drawing::HatchStyle_SINGLE,100, 0_deg10),aStr.toString()));
+ aStr[nLen] = '2';
+ Insert(std::make_unique<XHatchEntry>(XHatch(COL_RED ,css::drawing::HatchStyle_DOUBLE, 80,450_deg10),aStr.toString()));
+ aStr[nLen] = '3';
+ Insert(std::make_unique<XHatchEntry>(XHatch(COL_BLUE ,css::drawing::HatchStyle_TRIPLE,120, 0_deg10),aStr.toString()));
+
+ return true;
+}
+
+BitmapEx XHatchList::CreateBitmap( tools::Long nIndex, const Size& rSize) const
+{
+ BitmapEx aRetval;
+ OSL_ENSURE(nIndex < Count(), "OOps, access out of range (!)");
+
+ if(nIndex < Count())
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ // prepare polygon geometry for rectangle
+ const basegfx::B2DPolygon aRectangle(
+ basegfx::utils::createPolygonFromRect(
+ basegfx::B2DRange(0.0, 0.0, rSize.Width(), rSize.Height())));
+
+ const XHatch& rHatch = GetHatch(nIndex)->GetHatch();
+ drawinglayer::attribute::HatchStyle aHatchStyle(drawinglayer::attribute::HatchStyle::Triple);
+
+ switch(rHatch.GetHatchStyle())
+ {
+ case css::drawing::HatchStyle_SINGLE :
+ {
+ aHatchStyle = drawinglayer::attribute::HatchStyle::Single;
+ break;
+ }
+ case css::drawing::HatchStyle_DOUBLE :
+ {
+ aHatchStyle = drawinglayer::attribute::HatchStyle::Double;
+ break;
+ }
+ default :
+ {
+ aHatchStyle = drawinglayer::attribute::HatchStyle::Triple; // css::drawing::HatchStyle_TRIPLE
+ break;
+ }
+ }
+
+ const basegfx::B2DHomMatrix aScaleMatrix(OutputDevice::LogicToLogic(MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapPixel)));
+ const basegfx::B2DVector aScaleVector(aScaleMatrix * basegfx::B2DVector(1.0, 0.0));
+ const double fScaleValue(aScaleVector.getLength());
+
+ const drawinglayer::attribute::FillHatchAttribute aFillHatch(
+ aHatchStyle,
+ static_cast<double>(rHatch.GetDistance()) * fScaleValue,
+ toRadians(rHatch.GetAngle()),
+ rHatch.GetColor().getBColor(),
+ 3, // same default as VCL, a minimum of three discrete units (pixels) offset
+ false);
+
+ const basegfx::BColor aBlack(0.0, 0.0, 0.0);
+ const drawinglayer::primitive2d::Primitive2DReference aHatchPrimitive(
+ new drawinglayer::primitive2d::PolyPolygonHatchPrimitive2D(
+ basegfx::B2DPolyPolygon(aRectangle),
+ aBlack,
+ aFillHatch));
+
+ const drawinglayer::primitive2d::Primitive2DReference aBlackRectanglePrimitive(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ aRectangle,
+ aBlack));
+
+ // prepare VirtualDevice
+ ScopedVclPtrInstance< VirtualDevice > pVirtualDevice;
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
+
+ pVirtualDevice->SetOutputSizePixel(rSize);
+ pVirtualDevice->SetDrawMode(rStyleSettings.GetHighContrastMode()
+ ? DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient
+ : DrawModeFlags::Default);
+
+ if(rStyleSettings.GetPreviewUsesCheckeredBackground())
+ {
+ const Point aNull(0, 0);
+ static const sal_uInt32 nLen(8);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+ pVirtualDevice->DrawCheckered(aNull, rSize, nLen, aW, aG);
+ }
+ else
+ {
+ pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor());
+ pVirtualDevice->Erase();
+ }
+
+ // create processor and draw primitives
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
+ *pVirtualDevice,
+ aNewViewInformation2D));
+
+ drawinglayer::primitive2d::Primitive2DContainer aSequence(2);
+
+ aSequence[0] = aHatchPrimitive;
+ aSequence[1] = aBlackRectanglePrimitive;
+ pProcessor2D->process(aSequence);
+ pProcessor2D.reset();
+
+ // get result bitmap and scale
+ aRetval = pVirtualDevice->GetBitmapEx(Point(0, 0), pVirtualDevice->GetOutputSizePixel());
+ }
+
+ return aRetval;
+}
+
+BitmapEx XHatchList::CreateBitmapForUI(tools::Long nIndex)
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
+ BitmapEx aRetVal = CreateBitmap(nIndex, rSize);
+ return aRetVal;
+}
+
+BitmapEx XHatchList::GetBitmapForPreview(tools::Long nIndex, const Size& rSize)
+{
+ return CreateBitmap(nIndex, rSize);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xtable.cxx b/svx/source/xoutdev/xtable.cxx
new file mode 100644
index 000000000..016dd261b
--- /dev/null
+++ b/svx/source/xoutdev/xtable.cxx
@@ -0,0 +1,392 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <xmlxtexp.hxx>
+#include <xmlxtimp.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <tools/urlobj.hxx>
+#include <svx/xtable.hxx>
+#include <tools/debug.hxx>
+#include <stack>
+
+using namespace com::sun::star;
+
+XColorEntry::XColorEntry(const Color& rColor, const OUString& rName)
+: XPropertyEntry(rName),
+ aColor(rColor)
+{
+}
+
+XLineEndEntry::XLineEndEntry(const basegfx::B2DPolyPolygon& rB2DPolyPolygon, const OUString& rName)
+: XPropertyEntry(rName),
+ aB2DPolyPolygon(rB2DPolyPolygon)
+{
+}
+
+XLineEndEntry::XLineEndEntry(const XLineEndEntry& rOther)
+: XPropertyEntry(rOther),
+ aB2DPolyPolygon(rOther.aB2DPolyPolygon)
+{
+}
+
+XDashEntry::XDashEntry(const XDash& rDash, const OUString& rName)
+: XPropertyEntry(rName),
+ aDash(rDash)
+{
+}
+
+XDashEntry::XDashEntry(const XDashEntry& rOther)
+: XPropertyEntry(rOther),
+aDash(rOther.aDash)
+{
+}
+
+XHatchEntry::XHatchEntry(const XHatch& rHatch, const OUString& rName)
+: XPropertyEntry(rName),
+ aHatch(rHatch)
+{
+}
+
+XHatchEntry::XHatchEntry(const XHatchEntry& rOther)
+: XPropertyEntry(rOther),
+ aHatch(rOther.aHatch)
+{
+}
+
+XGradientEntry::XGradientEntry(const XGradient& rGradient, const OUString& rName)
+: XPropertyEntry(rName),
+ aGradient(rGradient)
+{
+}
+
+XGradientEntry::XGradientEntry(const XGradientEntry& rOther)
+: XPropertyEntry(rOther),
+ aGradient(rOther.aGradient)
+{
+}
+
+XBitmapEntry::XBitmapEntry(const GraphicObject& rGraphicObject, const OUString& rName)
+: XPropertyEntry(rName),
+ maGraphicObject(rGraphicObject)
+{
+}
+
+XBitmapEntry::XBitmapEntry(const XBitmapEntry& rOther)
+: XPropertyEntry(rOther),
+ maGraphicObject(rOther.maGraphicObject)
+{
+}
+
+XPropertyList::XPropertyList(
+ XPropertyListType type,
+ const OUString& rPath, const OUString& rReferer
+) : meType ( type ),
+ maName ( "standard" ),
+ maPath ( rPath ),
+ maReferer ( rReferer ),
+ mbListDirty ( true ),
+ mbEmbedInDocument( false )
+{
+// fprintf (stderr, "Create type %d count %d\n", (int)meType, count++);
+}
+
+bool XPropertyList::isValidIdx(tools::Long nIndex) const
+{
+ return (nIndex >= 0 && o3tl::make_unsigned(nIndex) < maList.size());
+}
+
+
+XPropertyList::~XPropertyList()
+{
+}
+
+tools::Long XPropertyList::Count() const
+{
+ if( mbListDirty )
+ {
+ if( !const_cast<XPropertyList*>(this)->Load() )
+ const_cast<XPropertyList*>(this)->Create();
+ }
+ return maList.size();
+}
+
+XPropertyEntry* XPropertyList::Get( tools::Long nIndex ) const
+{
+ if( mbListDirty )
+ {
+ if( !const_cast<XPropertyList*>(this)->Load() )
+ const_cast<XPropertyList*>(this)->Create();
+ }
+ if (!isValidIdx(nIndex))
+ return nullptr;
+
+ return maList[nIndex].get();
+}
+
+tools::Long XPropertyList::GetIndex(std::u16string_view rName) const
+{
+ if( mbListDirty )
+ {
+ if( !const_cast<XPropertyList*>(this)->Load() )
+ const_cast<XPropertyList*>(this)->Create();
+ }
+
+ for( tools::Long i = 0, n = maList.size(); i < n; ++i ) {
+ if (rName == maList[ i ]->GetName()) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+BitmapEx XPropertyList::GetUiBitmap( tools::Long nIndex ) const
+{
+ BitmapEx aRetval;
+ if (!isValidIdx(nIndex))
+ return aRetval;
+
+ XPropertyEntry* pEntry = maList[nIndex].get();
+ aRetval = pEntry->GetUiBitmap();
+
+ if(aRetval.IsEmpty())
+ {
+ aRetval = const_cast< XPropertyList* >(this)->CreateBitmapForUI(nIndex);
+ pEntry->SetUiBitmap(aRetval);
+ }
+ return aRetval;
+}
+
+void XPropertyList::Insert(std::unique_ptr<XPropertyEntry> pEntry, tools::Long nIndex)
+{
+ if (!pEntry)
+ {
+ assert(!"empty XPropertyEntry not allowed in XPropertyList");
+ return;
+ }
+
+ if (isValidIdx(nIndex)) {
+ maList.insert( maList.begin()+nIndex, std::move(pEntry) );
+ } else {
+ maList.push_back( std::move(pEntry) );
+ }
+}
+
+void XPropertyList::Replace(std::unique_ptr<XPropertyEntry> pEntry, tools::Long nIndex)
+{
+ if (!pEntry)
+ {
+ assert(!"empty XPropertyEntry not allowed in XPropertyList");
+ return;
+ }
+ if (!isValidIdx(nIndex))
+ {
+ assert(!"trying to replace invalid entry in XPropertyList");
+ return;
+ }
+
+ maList[nIndex] = std::move(pEntry);
+}
+
+void XPropertyList::Remove(tools::Long nIndex)
+{
+ if (!isValidIdx(nIndex))
+ {
+ assert(!"trying to remove invalid entry in XPropertyList");
+ return;
+ }
+
+ maList.erase(maList.begin() + nIndex);
+}
+
+void XPropertyList::SetName( const OUString& rString )
+{
+ if(!rString.isEmpty())
+ {
+ maName = rString;
+ }
+}
+
+bool XPropertyList::Load()
+{
+ if( mbListDirty )
+ {
+ mbListDirty = false;
+ std::stack<OUString> aDirs;
+
+ sal_Int32 nIndex = 0;
+ do
+ {
+ aDirs.push(maPath.getToken(0, ';', nIndex));
+ }
+ while (nIndex >= 0);
+
+ //try all entries palette path list working back to front until one
+ //succeeds
+ while (!aDirs.empty())
+ {
+ OUString aPath(aDirs.top());
+ aDirs.pop();
+
+ INetURLObject aURL(aPath);
+
+ if( INetProtocol::NotValid == aURL.GetProtocol() )
+ {
+ DBG_ASSERT( aPath.isEmpty(), "invalid URL" );
+ return false;
+ }
+
+ aURL.Append( maName );
+
+ if( aURL.getExtension().isEmpty() )
+ aURL.setExtension( GetDefaultExt() );
+
+ bool bRet = SvxXMLXTableImport::load(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ maReferer, uno::Reference < embed::XStorage >(),
+ createInstance(), nullptr );
+ if (bRet)
+ return bRet;
+ }
+ }
+ return false;
+}
+
+bool XPropertyList::LoadFrom( const uno::Reference < embed::XStorage > &xStorage,
+ const OUString &rURL, const OUString &rReferer )
+{
+ if( !mbListDirty )
+ return false;
+ mbListDirty = false;
+ return SvxXMLXTableImport::load( rURL, rReferer, xStorage, createInstance(), &mbEmbedInDocument );
+}
+
+bool XPropertyList::Save()
+{
+ //save to the last path in the palette path list
+ OUString aLastDir;
+ sal_Int32 nIndex = 0;
+ do
+ {
+ aLastDir = maPath.getToken(0, ';', nIndex);
+ }
+ while (nIndex >= 0);
+
+ INetURLObject aURL(aLastDir);
+
+ if( INetProtocol::NotValid == aURL.GetProtocol() )
+ {
+ DBG_ASSERT( aLastDir.isEmpty(), "invalid URL" );
+ return false;
+ }
+
+ aURL.Append( maName );
+
+ if( aURL.getExtension().isEmpty() )
+ aURL.setExtension( GetDefaultExt() );
+
+ return SvxXMLXTableExportComponent::save( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ createInstance(),
+ uno::Reference< embed::XStorage >(), nullptr );
+}
+
+bool XPropertyList::SaveTo( const uno::Reference< embed::XStorage > &xStorage,
+ const OUString &rURL, OUString *pOptName )
+{
+ return SvxXMLXTableExportComponent::save( rURL, createInstance(), xStorage, pOptName );
+}
+
+XPropertyListRef XPropertyList::CreatePropertyList( XPropertyListType aType,
+ const OUString& rPath,
+ const OUString& rReferer )
+{
+ XPropertyListRef pRet;
+
+ switch (aType) {
+ case XPropertyListType::Color:
+ pRet = XPropertyListRef(new XColorList(rPath, rReferer));
+ break;
+ case XPropertyListType::LineEnd:
+ pRet = XPropertyListRef(new XLineEndList(rPath, rReferer));
+ break;
+ case XPropertyListType::Dash:
+ pRet = XPropertyListRef(new XDashList(rPath, rReferer));
+ break;
+ case XPropertyListType::Hatch:
+ pRet = XPropertyListRef(new XHatchList(rPath, rReferer));
+ break;
+ case XPropertyListType::Gradient:
+ pRet = XPropertyListRef(new XGradientList(rPath, rReferer));
+ break;
+ case XPropertyListType::Bitmap:
+ pRet = XPropertyListRef(new XBitmapList(rPath, rReferer));
+ break;
+ case XPropertyListType::Pattern:
+ pRet = XPropertyListRef(new XPatternList(rPath, rReferer));
+ break;
+ default:
+ OSL_FAIL("unknown xproperty type");
+ break;
+ }
+ OSL_ASSERT( !pRet.is() || pRet->meType == aType );
+
+ return pRet;
+}
+
+XPropertyListRef
+XPropertyList::CreatePropertyListFromURL( XPropertyListType t,
+ std::u16string_view rURLStr )
+{
+ INetURLObject aURL( rURLStr );
+ INetURLObject aPathURL( aURL );
+
+ aPathURL.removeSegment();
+ aPathURL.removeFinalSlash();
+
+ XPropertyListRef pList = XPropertyList::CreatePropertyList(
+ t, aPathURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), "" );
+ pList->SetName( aURL.getName() );
+
+ return pList;
+}
+
+struct {
+ XPropertyListType t;
+ const char *pExt;
+} const pExtnMap[] = {
+ { XPropertyListType::Color, "soc" },
+ { XPropertyListType::LineEnd, "soe" },
+ { XPropertyListType::Dash, "sod" },
+ { XPropertyListType::Hatch, "soh" },
+ { XPropertyListType::Gradient, "sog" },
+ { XPropertyListType::Bitmap, "sob" },
+ { XPropertyListType::Pattern, "sop"}
+};
+
+OUString XPropertyList::GetDefaultExt( XPropertyListType t )
+{
+ for (const auto & i : pExtnMap)
+ {
+ if( i.t == t )
+ return OUString::createFromAscii( i.pExt );
+ }
+ return OUString();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xtablend.cxx b/svx/source/xoutdev/xtablend.cxx
new file mode 100644
index 000000000..fcca05960
--- /dev/null
+++ b/svx/source/xoutdev/xtablend.cxx
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <XPropertyTable.hxx>
+#include <vcl/virdev.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <osl/diagnose.h>
+
+#include <svx/xtable.hxx>
+#include <drawinglayer/attribute/linestartendattribute.hxx>
+#include <drawinglayer/primitive2d/PolygonStrokeArrowPrimitive2D.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+
+XLineEndList::XLineEndList( const OUString& rPath, const OUString& rReferer )
+ : XPropertyList( XPropertyListType::LineEnd, rPath, rReferer )
+{
+}
+
+XLineEndList::~XLineEndList()
+{
+}
+
+XLineEndEntry* XLineEndList::GetLineEnd(tools::Long nIndex) const
+{
+ return static_cast<XLineEndEntry*>( XPropertyList::Get(nIndex) );
+}
+
+uno::Reference< container::XNameContainer > XLineEndList::createInstance()
+{
+ return SvxUnoXLineEndTable_createInstance( *this );
+}
+
+bool XLineEndList::Create()
+{
+ basegfx::B2DPolygon aTriangle;
+ aTriangle.append(basegfx::B2DPoint(10.0, 0.0));
+ aTriangle.append(basegfx::B2DPoint(0.0, 30.0));
+ aTriangle.append(basegfx::B2DPoint(20.0, 30.0));
+ aTriangle.setClosed(true);
+ Insert( std::make_unique<XLineEndEntry>( basegfx::B2DPolyPolygon(aTriangle), SvxResId( RID_SVXSTR_ARROW ) ) );
+
+ basegfx::B2DPolygon aSquare;
+ aSquare.append(basegfx::B2DPoint(0.0, 0.0));
+ aSquare.append(basegfx::B2DPoint(10.0, 0.0));
+ aSquare.append(basegfx::B2DPoint(10.0, 10.0));
+ aSquare.append(basegfx::B2DPoint(0.0, 10.0));
+ aSquare.setClosed(true);
+ Insert( std::make_unique<XLineEndEntry>( basegfx::B2DPolyPolygon(aSquare), SvxResId( RID_SVXSTR_SQUARE ) ) );
+
+ basegfx::B2DPolygon aCircle(basegfx::utils::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), 100.0));
+ Insert( std::make_unique<XLineEndEntry>( basegfx::B2DPolyPolygon(aCircle), SvxResId( RID_SVXSTR_CIRCLE ) ) );
+
+ return true;
+}
+
+BitmapEx XLineEndList::CreateBitmapForUI( tools::Long nIndex )
+{
+ BitmapEx aRetval;
+ OSL_ENSURE(nIndex < Count(), "OOps, access out of range (!)");
+
+ if(nIndex < Count())
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
+
+ const Size aSize(rSize.Width() * 2, rSize.Height());
+
+ // prepare line geometry
+ basegfx::B2DPolygon aLine;
+ const double fBorderDistance(aSize.Height() * 0.1);
+
+ aLine.append(basegfx::B2DPoint(fBorderDistance, aSize.Height() / 2));
+ aLine.append(basegfx::B2DPoint(aSize.Width() - fBorderDistance, aSize.Height() / 2));
+
+ // prepare LineAttribute
+ const basegfx::BColor aLineColor(rStyleSettings.GetFieldTextColor().getBColor());
+ const double fLineWidth(StyleSettings::GetListBoxPreviewDefaultLineWidth() * 1.1);
+ const drawinglayer::attribute::LineAttribute aLineAttribute(
+ aLineColor,
+ fLineWidth);
+
+ const basegfx::B2DPolyPolygon aLineEnd(GetLineEnd(nIndex)->GetLineEnd());
+ const double fArrowHeight(aSize.Height() - (2.0 * fBorderDistance));
+ const drawinglayer::attribute::LineStartEndAttribute aLineStartEndAttribute(
+ fArrowHeight,
+ aLineEnd,
+ false);
+
+ // prepare line primitive
+ const drawinglayer::primitive2d::Primitive2DReference aLineStartEndPrimitive(
+ new drawinglayer::primitive2d::PolygonStrokeArrowPrimitive2D(
+ aLine,
+ aLineAttribute,
+ aLineStartEndAttribute,
+ aLineStartEndAttribute));
+
+ // prepare VirtualDevice
+ ScopedVclPtrInstance< VirtualDevice > pVirtualDevice;
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
+
+ pVirtualDevice->SetOutputSizePixel(aSize);
+ pVirtualDevice->SetDrawMode(rStyleSettings.GetHighContrastMode()
+ ? DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient
+ : DrawModeFlags::Default);
+
+ if(rStyleSettings.GetPreviewUsesCheckeredBackground())
+ {
+ const Point aNull(0, 0);
+ static const sal_uInt32 nLen(8);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+ pVirtualDevice->DrawCheckered(aNull, aSize, nLen, aW, aG);
+ }
+ else
+ {
+ pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor());
+ pVirtualDevice->Erase();
+ }
+
+ // create processor and draw primitives
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
+ *pVirtualDevice,
+ aNewViewInformation2D));
+
+ const drawinglayer::primitive2d::Primitive2DContainer aSequence { aLineStartEndPrimitive };
+
+ pProcessor2D->process(aSequence);
+ pProcessor2D.reset();
+
+ // get result bitmap and scale
+ aRetval = pVirtualDevice->GetBitmapEx(Point(0, 0), pVirtualDevice->GetOutputSizePixel());
+ }
+
+ return aRetval;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/xoutdev/xtabptrn.cxx b/svx/source/xoutdev/xtabptrn.cxx
new file mode 100644
index 000000000..29697880f
--- /dev/null
+++ b/svx/source/xoutdev/xtabptrn.cxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <XPropertyTable.hxx>
+
+#include <vcl/virdev.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/xtable.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/BitmapTools.hxx>
+
+using namespace com::sun::star;
+
+XBitmapEntry* XPatternList::GetBitmap(tools::Long nIndex) const
+{
+ return static_cast<XBitmapEntry*>( XPropertyList::Get(nIndex) );
+}
+
+uno::Reference< container::XNameContainer > XPatternList::createInstance()
+{
+ return SvxUnoXBitmapTable_createInstance( *this );
+}
+
+bool XPatternList::Create()
+{
+ OUStringBuffer aStr(SvxResId(RID_SVXSTR_PATTERN));
+ std::array<sal_uInt8,64> aArray;
+ BitmapEx aBitmap;
+ const sal_Int32 nLen(aStr.getLength() - 1);
+
+ aArray.fill(0);
+
+ // white/white bitmap
+ aStr.append(" 1");
+ aBitmap = vcl::bitmap::createHistorical8x8FromArray(aArray, COL_WHITE, COL_WHITE);
+ Insert(std::make_unique<XBitmapEntry>(Graphic(aBitmap), aStr.toString()));
+
+ // black/white bitmap
+ aArray[ 0] = 1; aArray[ 9] = 1; aArray[18] = 1; aArray[27] = 1;
+ aArray[36] = 1; aArray[45] = 1; aArray[54] = 1; aArray[63] = 1;
+ aStr[nLen] = '2';
+ aBitmap = vcl::bitmap::createHistorical8x8FromArray(aArray, COL_BLACK, COL_WHITE);
+ Insert(std::make_unique<XBitmapEntry>(Graphic(aBitmap), aStr.toString()));
+
+ // lightred/white bitmap
+ aArray[ 7] = 1; aArray[14] = 1; aArray[21] = 1; aArray[28] = 1;
+ aArray[35] = 1; aArray[42] = 1; aArray[49] = 1; aArray[56] = 1;
+ aStr[nLen] = '3';
+ aBitmap = vcl::bitmap::createHistorical8x8FromArray(aArray, COL_LIGHTRED, COL_WHITE);
+ Insert(std::make_unique<XBitmapEntry>(Graphic(aBitmap), aStr.toString()));
+
+ // lightblue/white bitmap
+ aArray[24] = 1; aArray[25] = 1; aArray[26] = 1;
+ aArray[29] = 1; aArray[30] = 1; aArray[31] = 1;
+ aStr[nLen] = '4';
+ aBitmap = vcl::bitmap::createHistorical8x8FromArray(aArray, COL_LIGHTBLUE, COL_WHITE);
+ Insert(std::make_unique<XBitmapEntry>(Graphic(aBitmap), aStr.toString()));
+
+ return true;
+}
+
+BitmapEx XPatternList::CreateBitmap( tools::Long nIndex, const Size& rSize ) const
+{
+ assert( nIndex < Count() );
+
+ if(nIndex < Count())
+ {
+ BitmapEx rBitmapEx = GetBitmap( nIndex )->GetGraphicObject().GetGraphic().GetBitmapEx();
+ ScopedVclPtrInstance< VirtualDevice > pVirtualDevice;
+ pVirtualDevice->SetOutputSizePixel(rSize);
+
+ if(rBitmapEx.IsAlpha())
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ if(rStyleSettings.GetPreviewUsesCheckeredBackground())
+ {
+ const Point aNull(0, 0);
+ static const sal_uInt32 nLen(8);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+
+ pVirtualDevice->DrawCheckered(aNull, rSize, nLen, aW, aG);
+ }
+ else
+ {
+ pVirtualDevice->SetBackground(rStyleSettings.GetFieldColor());
+ pVirtualDevice->Erase();
+ }
+ }
+
+ if(rBitmapEx.GetSizePixel().Width() >= rSize.Width() && rBitmapEx.GetSizePixel().Height() >= rSize.Height())
+ {
+ rBitmapEx.Scale(rSize);
+ pVirtualDevice->DrawBitmapEx(Point(0, 0), rBitmapEx);
+ }
+ else
+ {
+ const Size aBitmapSize(rBitmapEx.GetSizePixel());
+
+ for(tools::Long y(0); y < rSize.Height(); y += aBitmapSize.Height())
+ {
+ for(tools::Long x(0); x < rSize.Width(); x += aBitmapSize.Width())
+ {
+ pVirtualDevice->DrawBitmapEx(
+ Point(x, y),
+ rBitmapEx);
+ }
+ }
+ }
+ rBitmapEx = pVirtualDevice->GetBitmapEx(Point(0, 0), rSize);
+ return rBitmapEx;
+ }
+ else
+ return BitmapEx();
+}
+
+BitmapEx XPatternList::CreateBitmapForUI( tools::Long nIndex )
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Size& rSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
+ return CreateBitmap(nIndex, rSize);
+}
+
+BitmapEx XPatternList::GetBitmapForPreview( tools::Long nIndex, const Size& rSize )
+{
+ return CreateBitmap(nIndex, rSize);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/uiconfig/ui/absrecbox.ui b/svx/uiconfig/ui/absrecbox.ui
new file mode 100644
index 000000000..2062570af
--- /dev/null
+++ b/svx/uiconfig/ui/absrecbox.ui
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="AbsRecBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkEntry" id="entry-frame">
+ <property name="can_focus">True</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="width_chars">4</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entry-noframe">
+ <property name="can_focus">True</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="has_frame">False</property>
+ <property name="width_chars">4</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/acceptrejectchangesdialog.ui b/svx/uiconfig/ui/acceptrejectchangesdialog.ui
new file mode 100644
index 000000000..58d1e10bd
--- /dev/null
+++ b/svx/uiconfig/ui/acceptrejectchangesdialog.ui
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="AcceptRejectChangesDialog">
+ <property name="can-focus">False</property>
+ <property name="border-width">6</property>
+ <property name="title" translatable="yes" context="acceptrejectchangesdialog|AcceptRejectChangesDialog">Manage Changes</property>
+ <property name="default-width">0</property>
+ <property name="default-height">0</property>
+ <property name="type-hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can-focus">False</property>
+ <property name="layout-style">end</property>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="close">
+ <property name="label" translatable="yes" context="stock">_Close</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="can-default">True</property>
+ <property name="has-default">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">help</action-widget>
+ <action-widget response="-7">close</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkMenu" id="calcmenu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="calcedit">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|calcedit">Edit Comment...</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="calcedit-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="acceptrejectchangesdialog|extended_tip|calcedit">Edit the comment for the selected change.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="calcsort">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|calcsort">Sorting</property>
+ <property name="use-underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="calcsortmenu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkRadioMenuItem" id="calcsort0">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|calcaction">Action</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="calcsort1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|calcposition">Position</property>
+ <property name="use-underline">True</property>
+ <property name="group">calcsort0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="calcsort2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|calcauthor">Author</property>
+ <property name="use-underline">True</property>
+ <property name="group">calcsort0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="calcsort3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|calcdate">Date</property>
+ <property name="use-underline">True</property>
+ <property name="group">calcsort0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="calcsort4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|calcdesc">Description</property>
+ <property name="use-underline">True</property>
+ <property name="group">calcsort0</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkMenu" id="writermenu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="writeredit">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|writeredit">Edit Comment...</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="writeredit-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="acceptrejectchangesdialog|extended_tip|writeredit">Edit the comment for the selected change.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="writersort">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|writersort">Sort By</property>
+ <property name="use-underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="writersortmenu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkRadioMenuItem" id="writersort0">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|writeraction">Action</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="writersort1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|writerauthor">Author</property>
+ <property name="use-underline">True</property>
+ <property name="group">writersort0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="writersort2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|writerdate">Date</property>
+ <property name="use-underline">True</property>
+ <property name="group">writersort0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="writersort3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|writerdesc">Comment</property>
+ <property name="use-underline">True</property>
+ <property name="group">writersort0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="writersort4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|writerposition">Document Position</property>
+ <property name="use-underline">True</property>
+ <property name="group">writersort0</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/accessibilitycheckdialog.ui b/svx/uiconfig/ui/accessibilitycheckdialog.ui
new file mode 100644
index 000000000..a725948a3
--- /dev/null
+++ b/svx/uiconfig/ui/accessibilitycheckdialog.ui
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="AccessibilityCheckDialog">
+ <property name="width_request">640</property>
+ <property name="height_request">480</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="accessibilitycheckdialog|AccessibilityCheckDialog">Accessibility Check</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialogBox1">
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialogButtons">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkBox" id="accessibilityCheckBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/accessibilitycheckentry.ui b/svx/uiconfig/ui/accessibilitycheckentry.ui
new file mode 100644
index 000000000..0fe33322b
--- /dev/null
+++ b/svx/uiconfig/ui/accessibilitycheckentry.ui
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="accessibilityCheckEntryBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">3</property>
+ <child>
+ <object class="GtkLabel" id="accessibilityCheckEntryLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <child internal-child="accessible">
+ <object class="AtkObject">
+ <property name="AtkObject::accessible-role">static</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="accessibilityCheckEntryGotoButton">
+ <property name="label" translatable="yes" context="accessibilitycheckentry|accessibilityCheckEntryGotoButton">Go to Issue</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/addconditiondialog.ui b/svx/uiconfig/ui/addconditiondialog.ui
new file mode 100644
index 000000000..d66401519
--- /dev/null
+++ b/svx/uiconfig/ui/addconditiondialog.ui
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="AddConditionDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="addconditiondialog|AddConditionDialog">Add Condition</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addconditiondialog|label1">_Condition:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">condition</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTextView" id="condition">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="wrap_mode">word</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="condition-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="addconditiondialog|extended_tip|condition">Enter a condition.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addconditiondialog|label2">_Result:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">result</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="edit">
+ <property name="label" translatable="yes" context="addconditiondialog|edit">_Edit Namespaces...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">end</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="edit-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="addconditiondialog|extended_tip|edit">Opens the Form Namespaces dialog where you can add, edit, or delete namespaces.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTextView" id="result">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="editable">False</property>
+ <property name="wrap_mode">word</property>
+ <property name="cursor_visible">False</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="result-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="addconditiondialog|extended_tip|result">Displays a preview of the result.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="AddConditionDialog-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="addconditiondialog|extended_tip|AddConditionDialog">Add a condition in this subdialog of the Add Item / Edit Item dialog of the Data Navigator.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/adddataitemdialog.ui b/svx/uiconfig/ui/adddataitemdialog.ui
new file mode 100644
index 000000000..1d1fe45ce
--- /dev/null
+++ b/svx/uiconfig/ui/adddataitemdialog.ui
@@ -0,0 +1,462 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="AddDataItemDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="itemframe">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkEntry" id="name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">center</property>
+ <property name="activates_default">True</property>
+ <property name="width_chars">46</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="name-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|name">Enter the name of the item.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="nameft">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="adddataitemdialog|nameft">_Name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">name</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="valueft">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="adddataitemdialog|valueft">_Default value:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">value</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="browse">
+ <property name="label" translatable="yes" context="adddataitemdialog|browse">_Add...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="valign">center</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="value">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">center</property>
+ <property name="activates_default">True</property>
+ <property name="width_chars">46</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="value-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|value">Enter a default value for the selected item.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="adddataitemdialog|label1">Item</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="settingsframe">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkLabel" id="datatypeft">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="adddataitemdialog|datatypeft">_Data type:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">datatype</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="datatype">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="datatype-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|datatype">Select the data type for the selected item.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="required">
+ <property name="label" translatable="yes" context="adddataitemdialog|required">_Required</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="required-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|required">Specifies if the item must be included on the XForm.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="requiredcond">
+ <property name="label" translatable="yes" context="adddataitemdialog|requiredcond">Condition</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">start</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="requiredcond-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|requiredcond">The Condition button opens the Add Condition dialog where you can enter used namespaces and full XPath expressions.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="relevant">
+ <property name="label" translatable="yes" context="adddataitemdialog|relevant">R_elevant</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="relevant-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|relevant">Declares the item as relevant.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="relevantcond">
+ <property name="label" translatable="yes" context="adddataitemdialog|relevantcond">Condition</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">start</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="relevantcond-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|relevantcond">Declares the item as a constraint.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="constraint">
+ <property name="label" translatable="yes" context="adddataitemdialog|constraint">_Constraint</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="constraint-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|constraint">Declares the item as a constraint.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="readonly">
+ <property name="label" translatable="yes" context="adddataitemdialog|readonly">Read-_only</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="readonly-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|readonly">Declares the item as read-only.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="calculate">
+ <property name="label" translatable="yes" context="adddataitemdialog|calculate">Calc_ulate</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="calculate-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|calculate">Declares that the item is calculated.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="constraintcond">
+ <property name="label" translatable="yes" context="adddataitemdialog|constraintcond">Condition</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">start</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="constraintcond-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|constraintcond">The Condition button opens the Add Condition dialog where you can specify the constraint condition.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="readonlycond">
+ <property name="label" translatable="yes" context="adddataitemdialog|readonlycond">Condition</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">start</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="readonlycond-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|readonlycond">Declares that the item is calculated.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="calculatecond">
+ <property name="label" translatable="yes" context="adddataitemdialog|calculatecond">Condition</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">start</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="calculatecond-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|calculatecond">The Condition button opens the Add Condition dialog where you can enter the calculation.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">5</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="adddataitemdialog|label4">Settings</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="AddDataItemDialog-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="adddataitemdialog|extended_tip|AddDataItemDialog">Adds a new item or edits the selected item in the XForms Data Navigator.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/addinstancedialog.ui b/svx/uiconfig/ui/addinstancedialog.ui
new file mode 100644
index 000000000..ebde11851
--- /dev/null
+++ b/svx/uiconfig/ui/addinstancedialog.ui
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="AddInstanceDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="addinstancedialog|AddInstanceDialog">Add Instance</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkEntry" id="name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="width_chars">46</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addinstancedialog|label2">_Name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">name</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="alttitle">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes" context="addinstancedialog|alttitle">Edit Instance</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="urlft">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addinstancedialog|urlft">_URL:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">url</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="url">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="has_entry">True</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="truncate-multiline">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="browse">
+ <property name="label" translatable="yes" context="addinstancedialog|browse">_Browse...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="link">
+ <property name="label" translatable="yes" context="addinstancedialog|link">_Link instance</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/addmodeldialog.ui b/svx/uiconfig/ui/addmodeldialog.ui
new file mode 100644
index 000000000..2746b262e
--- /dev/null
+++ b/svx/uiconfig/ui/addmodeldialog.ui
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="AddModelDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="addmodeldialog|AddModelDialog">Add Model</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="modify">
+ <property name="label" translatable="yes" context="addmodeldialog|modify">Model data updates change document's modification status</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="modify-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="addmodeldialog|extended_tip|modify">When enabled, the document status will be set to "modified" when you change any form control that is bound to any data in the model. When not enabled, such a change does not set the document status to "modified".</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="name-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="addmodeldialog|extended_tip|name">Enter the name.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addmodeldialog|label2">_Name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">name</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="alttitle">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes" context="addmodeldialog|alttitle">Edit Model</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/addnamespacedialog.ui b/svx/uiconfig/ui/addnamespacedialog.ui
new file mode 100644
index 000000000..74725e63c
--- /dev/null
+++ b/svx/uiconfig/ui/addnamespacedialog.ui
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="AddNamespaceDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="addnamespacedialog|AddNamespaceDialog">Add Namespace</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addnamespacedialog|label1">_Prefix:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">prefix</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="prefix">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="width_chars">12</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="url">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="width_chars">34</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addnamespacedialog|label2">_URL:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">url</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="alttitle">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes" context="addnamespacedialog|alttitle">Edit Namespace</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/addsubmissiondialog.ui b/svx/uiconfig/ui/addsubmissiondialog.ui
new file mode 100644
index 000000000..ed708a477
--- /dev/null
+++ b/svx/uiconfig/ui/addsubmissiondialog.ui
@@ -0,0 +1,279 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="AddSubmissionDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="addsubmissiondialog|AddSubmissionDialog">Add Submission</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkEntry" id="name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">center</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="width_chars">46</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addsubmissiondialog|label2">_Name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">name</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="urlft">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addsubmissiondialog|urlft">Binding e_xpression:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">expression</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="browse">
+ <property name="label" translatable="yes" context="addsubmissiondialog|browse">_Add...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="valign">center</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addsubmissiondialog|label3">_Action:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">action</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="action">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">center</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="width_chars">46</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addsubmissiondialog|label4">_Method:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">method</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="method">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="expression">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">center</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="width_chars">46</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addsubmissiondialog|label5">_Binding:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">binding</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="addsubmissiondialog|label6">_Replace:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">replace</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="binding">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="replace">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">5</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/applystylebox.ui b/svx/uiconfig/ui/applystylebox.ui
new file mode 100644
index 000000000..8a404740e
--- /dev/null
+++ b/svx/uiconfig/ui/applystylebox.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="ApplyStyleBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBoxText" id="applystyle">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="has_entry">True</property>
+ <property name="popup_fixed_width">False</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="truncate-multiline">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/asianphoneticguidedialog.ui b/svx/uiconfig/ui/asianphoneticguidedialog.ui
new file mode 100644
index 000000000..b70aee741
--- /dev/null
+++ b/svx/uiconfig/ui/asianphoneticguidedialog.ui
@@ -0,0 +1,507 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="AsianPhoneticGuideDialog">
+ <property name="can-focus">False</property>
+ <property name="border-width">6</property>
+ <property name="title" translatable="yes" context="asianphoneticguidedialog|AsianPhoneticGuideDialog">Asian Phonetic Guide</property>
+ <property name="default-width">0</property>
+ <property name="default-height">0</property>
+ <property name="type-hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can-focus">False</property>
+ <property name="layout-style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_Apply</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="can-default">True</property>
+ <property name="has-default">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="close">
+ <property name="label" translatable="yes" context="stock">_Close</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="column-spacing">12</property>
+ <property name="column-homogeneous">True</property>
+ <child>
+ <object class="GtkLabel" id="basetextft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|basetextft">Base text</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="rubytextft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|rubytextft">Ruby text</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">always</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <!-- n-columns=2 n-rows=4 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border-width">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkEntry" id="Left2ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Left2ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Left2ED-atkobject">Base text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left2ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="Left1ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Left1ED-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left1ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="Right1ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Right1ED-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right1ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="Right2ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Right2ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Right2ED-atkobject">Ruby text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right2ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="Left3ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Left3ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Left3ED-atkobject">Base text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left3ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="Right3ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Right3ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Right3ED-atkobject">Ruby text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right3ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="Right4ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Right4ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Right4ED-atkobject">Ruby text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right4ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="Left4ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Left4ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Left4ED-atkobject">Base text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left4ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=4 n-rows=2 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-top">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|label4">Alignment:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">adjustlb</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|label5">Position:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">positionlb</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="styleft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|styleft">Character style for ruby text:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">stylelb</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="stylelb">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="stylelb-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|stylelb">Select a character style for the ruby text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="styles">
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|styles">Styles</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="styles-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|styles">Opens the Styles deck of the Sidebar where you can select a character style for the ruby text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="adjustlb">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <items>
+ <item translatable="yes" context="asianphoneticguidedialog|adjustlb">Left</item>
+ <item translatable="yes" context="asianphoneticguidedialog|adjustlb">Center</item>
+ <item translatable="yes" context="asianphoneticguidedialog|adjustlb">Right</item>
+ <item translatable="yes" context="asianphoneticguidedialog|adjustlb">0 1 0</item>
+ <item translatable="yes" context="asianphoneticguidedialog|adjustlb">1 2 1</item>
+ </items>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="adjustlb-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|adjustlb">Select the horizontal alignment for the ruby text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="positionlb">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <items>
+ <item translatable="yes" context="asianphoneticguidedialog|positionlb">Top</item>
+ <item translatable="yes" context="asianphoneticguidedialog|positionlb">Bottom</item>
+ <item translatable="yes" context="asianphoneticguidedialog|positionlb">Right</item>
+ </items>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="positionlb-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|positionlb">Select where you want to place the ruby text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-top">6</property>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|label1">Preview:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">preview</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="ctlFavoriteswin">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">never</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="preview">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-7">close</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="AsianPhoneticGuideDialog-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|AsianPhoneticGuideDialog">Allows you to add comments next to Asian characters to serve as a pronunciation guide.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/cellmenu.ui b/svx/uiconfig/ui/cellmenu.ui
new file mode 100644
index 000000000..8b68c4438
--- /dev/null
+++ b/svx/uiconfig/ui/cellmenu.ui
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="copy">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="cellmenu|copy">_Copy</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/charsetmenu.ui b/svx/uiconfig/ui/charsetmenu.ui
new file mode 100644
index 000000000..5afd1137c
--- /dev/null
+++ b/svx/uiconfig/ui/charsetmenu.ui
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="charsetmenu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="insert">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="charviewmenu|STR_CLEAR_CHAR">Insert into document</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="add">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="charviewmenu|STR_CLEAR_ALL_CHAR">Add to favorites</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="remove">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="charviewmenu|STR_CLEAR_ALL_CHAR">Remove from favorites</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="copy">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="charviewmenu|STR_CLEAR_ALL_CHAR">Copy to clipboard</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/checkbuttonbox.ui b/svx/uiconfig/ui/checkbuttonbox.ui
new file mode 100644
index 000000000..06a59de76
--- /dev/null
+++ b/svx/uiconfig/ui/checkbuttonbox.ui
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="CheckButtonBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/chineseconversiondialog.ui b/svx/uiconfig/ui/chineseconversiondialog.ui
new file mode 100644
index 000000000..10f2428f4
--- /dev/null
+++ b/svx/uiconfig/ui/chineseconversiondialog.ui
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="ChineseConversionDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="chineseconversiondialog|ChineseConversionDialog">Chinese Conversion</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkRadioButton" id="tosimplified">
+ <property name="label" translatable="yes" context="chineseconversiondialog|tosimplified">_Traditional Chinese to simplified Chinese</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="tosimplified-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chineseconversiondialog|extended_tip|tosimplified">Converts traditional Chinese text characters to simplified Chinese text characters. Click OK to convert the selected text. If no text is selected, the whole document is converted.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="totraditional">
+ <property name="label" translatable="yes" context="chineseconversiondialog|totraditional">_Simplified Chinese to traditional Chinese</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">tosimplified</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="totraditional-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chineseconversiondialog|extended_tip|totraditional">Converts simplified Chinese text characters to traditional Chinese text characters. Click OK to convert the selected text. If no text is selected, the whole document is converted.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="chineseconversiondialog|label1">Conversion Direction</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkCheckButton" id="commonterms">
+ <property name="label" translatable="yes" context="chineseconversiondialog|commonterms">Translate _common terms</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="commonterms-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chineseconversiondialog|extended_tip|commonterms">Converts words with two or more characters that are in the list of common terms. After the list is scanned, the remaining text is converted character by character.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="editterms">
+ <property name="label" translatable="yes" context="chineseconversiondialog|editterms">_Edit Terms...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="editterms-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chineseconversiondialog|extended_tip|editterms">Opens the Edit Dictionary dialog where you can edit the list of conversion terms.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="chineseconversiondialog|label2">Common Terms</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="ChineseConversionDialog-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chineseconversiondialog|extended_tip|ChineseConversionDialog">Converts the selected Chinese text from one Chinese writing system to the other. If no text is selected, the entire document is converted.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/chinesedictionary.ui b/svx/uiconfig/ui/chinesedictionary.ui
new file mode 100644
index 000000000..465ea0862
--- /dev/null
+++ b/svx/uiconfig/ui/chinesedictionary.ui
@@ -0,0 +1,581 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore2">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name text2 -->
+ <column type="gchararray"/>
+ <!-- column-name text3 -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkTreeStore" id="liststore3">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name text2 -->
+ <column type="gchararray"/>
+ <!-- column-name text3 -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="ChineseDictionaryDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="chinesedictionary|ChineseDictionaryDialog">Edit Dictionary</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">12</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="tradtosimple">
+ <property name="label" translatable="yes" context="chinesedictionary|tradtosimple">_Traditional Chinese to simplified Chinese</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="tradtosimple-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chinesedictionary|extended_tip|tradtosimple">Converts traditional Chinese to simplified Chinese.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="simpletotrad">
+ <property name="label" translatable="yes" context="chinesedictionary|simpletotrad">_Simplified Chinese to traditional Chinese</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">tradtosimple</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="simpletotrad-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chinesedictionary|extended_tip|simpletotrad">Converts simplified Chinese to traditional Chinese.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="reverse">
+ <property name="label" translatable="yes" context="chinesedictionary|reverse">Reverse mapping</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="reverse-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chinesedictionary|extended_tip|reverse">Automatically adds the reverse mapping direction to the list for each modification that you enter.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="termft">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="chinesedictionary|termft">Term</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">term</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="mappingft">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="chinesedictionary|mappingft">Mapping</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">mapping</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButtonBox" id="buttonbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">start</property>
+ <child>
+ <object class="GtkButton" id="add">
+ <property name="label" translatable="yes" context="stock">_Add</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="add-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chinesedictionary|extended_tip|add">Adds the term to the conversion dictionary. If the term is already in the dictionary, the new term receives precedence.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="modify">
+ <property name="label" translatable="yes" context="chinesedictionary|modify">_Modify</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="modify-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chinesedictionary|extended_tip|modify">Saves the modified entry to the database file.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="delete">
+ <property name="label" translatable="yes" context="stock">_Delete</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="delete-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chinesedictionary|extended_tip|delete">Removes the selected user-defined entry from the dictionary.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="height">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="propertyft">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="chinesedictionary|propertyft">Property</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">property</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="property">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <items>
+ <item translatable="yes" context="chinesedictionary|property">Other</item>
+ <item translatable="yes" context="chinesedictionary|property">Foreign</item>
+ <item translatable="yes" context="chinesedictionary|property">First name</item>
+ <item translatable="yes" context="chinesedictionary|property">Last name</item>
+ <item translatable="yes" context="chinesedictionary|property">Title</item>
+ <item translatable="yes" context="chinesedictionary|property">Status</item>
+ <item translatable="yes" context="chinesedictionary|property">Place name</item>
+ <item translatable="yes" context="chinesedictionary|property">Business</item>
+ <item translatable="yes" context="chinesedictionary|property">Adjective</item>
+ <item translatable="yes" context="chinesedictionary|property">Idiom</item>
+ <item translatable="yes" context="chinesedictionary|property">Abbreviation</item>
+ <item translatable="yes" context="chinesedictionary|property">Numerical</item>
+ <item translatable="yes" context="chinesedictionary|property">Noun</item>
+ <item translatable="yes" context="chinesedictionary|property">Verb</item>
+ <item translatable="yes" context="chinesedictionary|property">Brand name</item>
+ </items>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="property-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chinesedictionary|extended_tip|property">Defines the class of the selected term.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="mapping">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="mapping-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chinesedictionary|extended_tip|mapping">Enter the text that you want to replace the Term with.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="term">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="term-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chinesedictionary|extended_tip|term">Enter the text that you want to replace with the Mapping term.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="tradtosimpleview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore3</property>
+ <property name="search_column">0</property>
+ <property name="show_expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="chinesedictionary|termft">Term</property>
+ <property name="clickable">True</property>
+ <property name="sort_indicator">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn4">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="chinesedictionary|mappingft">Mapping</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer2"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn5">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="chinesedictionary|propertyft">Property</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer3"/>
+ <attributes>
+ <attribute name="text">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="can_focus">True</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="simpletotradview">
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore2</property>
+ <property name="search_column">0</property>
+ <property name="show_expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn33">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="chinesedictionary|termft">Term</property>
+ <property name="reorderable">True</property>
+ <property name="sort_indicator">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer11"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn44">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="chinesedictionary|mappingft">Mapping</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer22"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn55">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="chinesedictionary|propertyft">Property</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer33"/>
+ <attributes>
+ <attribute name="text">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">3</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="ChineseDictionaryDialog-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="chinesedictionary|extended_tip|ChineseDictionaryDialog">Edit the Chinese conversion terms.</property>
+ </object>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup1">
+ <property name="mode">both</property>
+ <widgets>
+ <widget name="tradtosimpleview"/>
+ <widget name="simpletotradview"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup2">
+ <widgets>
+ <widget name="termft"/>
+ <widget name="term"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup3">
+ <widgets>
+ <widget name="mappingft"/>
+ <widget name="mapping"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup4">
+ <widgets>
+ <widget name="propertyft"/>
+ <widget name="property"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/classificationdialog.ui b/svx/uiconfig/ui/classificationdialog.ui
new file mode 100644
index 000000000..e0f40e1ed
--- /dev/null
+++ b/svx/uiconfig/ui/classificationdialog.ui
@@ -0,0 +1,630 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">cmd/lc_bold.png</property>
+ </object>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkTreeStore" id="liststore2">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkTreeStore" id="liststore3">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="AdvancedDocumentClassificationDialog">
+ <property name="can-focus">False</property>
+ <property name="border-width">6</property>
+ <property name="title" translatable="yes" context="classificationdialog|dialogname">Classification</property>
+ <property name="modal">True</property>
+ <property name="default-width">0</property>
+ <property name="default-height">0</property>
+ <property name="type-hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can-focus">False</property>
+ <property name="layout-style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="can-default">True</property>
+ <property name="has-default">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=2 n-rows=2 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">6</property>
+ <child>
+ <!-- n-columns=2 n-rows=5 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="classificationLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="classificationdialog|label-Classification">Classification:</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="classificationCB"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="internationalClassificationLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="classificationdialog|label-InternationalClassification">International:</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="internationalClassificationCB"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="classificationCB">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="classificationLabel"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="classificationCB-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|classiticationCB">Lists the translated document and paragraph classification levels of your installation.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="internationalClassificationCB">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <accessibility>
+ <relation type="labelled-by" target="internationalClassificationLabel"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="internationalClassificationCB-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|internationalclassiticationCB">Lists the international document and paragraph classification levels of your installation.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="markingLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="classificationdialog|label-Marking">Marking:</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="markingLB"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="recentlyUsedLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="classificationdialog|label-Classification">Recently Used:</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="recentlyUsedCB"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="recentlyUsedCB">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="recentlyUsedLabel"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="recentlyUsedCB-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|recentlyUsedCB">Lists the most recently used classification terms.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkTreeView" id="markingLB">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers-visible">False</property>
+ <property name="headers-clickable">False</property>
+ <property name="show-expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <accessibility>
+ <relation type="labelled-by" target="markingLabel"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="markingLB-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|markingLB">Lists the specific classification markings for document and paragraph classification of your installation.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">4</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=3 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row-spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="classificationContentLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="classificationdialog|label-Content">Content</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="classificationEditWindow"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkToggleButton" id="toolbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes" context="classificationdialog|boldButton">Bold</property>
+ <property name="image">image1</property>
+ <property name="use-underline">True</property>
+ <property name="always-show-image">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="toolbox-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|toolboxCB">Applies bold character style to the classification contents.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="signButton">
+ <property name="label" translatable="yes" context="classificationdialog|signButton">Sign Paragraph</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="signButton-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|signButton">Opens the Select Certificate dialog to select a digital certificate for paragraph signature.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="border-width">0</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="classificationEditWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="classificationContentLabel"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="classificationEditWindow-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|classiticationEditWindow">Displays the current classification terms of the document or paragraph.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkExpander" id="intellectualPropertyExpander">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="resize-toplevel">True</property>
+ <child>
+ <!-- n-columns=3 n-rows=4 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="intellectualPropertyPartLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="classificationdialog|label-PartNumber">License:</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="intellectualPropertyPartLB"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="intellectualPropertyPartNumberLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="classificationdialog|label-PartNumber">Part Number:</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="intellectualPropertyPartNumberLB"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="intellectualPropertyPartEntryLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="classificationdialog|label-PartNumber">Part text:</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="intellectualPropertyPartEntry"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="intellectualPropertyPartEntry">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="intellectualPropertyPartEntryLabel"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="intellectualPropertyPartEntry-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|intellectualPropertyPartEntry">Enter a custom intellectual property text for the document.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkTreeView" id="intellectualPropertyPartLB">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore3</property>
+ <property name="headers-visible">False</property>
+ <property name="headers-clickable">False</property>
+ <property name="show-expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn6">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer6"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <accessibility>
+ <relation type="labelled-by" target="intellectualPropertyPartLabel"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="intellectualPropertyPartLB-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|intellectualPropertyPartLB">Lists the available intellectual property licenses defined for your installation.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkTreeView" id="intellectualPropertyPartNumberLB">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore2</property>
+ <property name="headers-visible">False</property>
+ <property name="headers-clickable">False</property>
+ <property name="show-expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn4">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer5"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <accessibility>
+ <relation type="labelled-by" target="intellectualPropertyPartNumberLabel"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="intellectualPropertyPartNumberLB-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|intellectual PropertyPartNumberLB">Lists the available intellectual property part numbers of your installation.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="intellectualPropertyPartAddButton">
+ <property name="label" translatable="yes" context="classificationdialog|intellectualPropertyPartAddButton">Add</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="intellectualPropertyPartAddButton-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="classificationdialog|extended_tip|intelectualPropertyPartAddButton">Click to add the part text to the intellectual property classification content.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="classificationdialog|label-IntellectualProperty">Intellectual Property</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/clipboardmenu.ui b/svx/uiconfig/ui/clipboardmenu.ui
new file mode 100644
index 000000000..ae9032b68
--- /dev/null
+++ b/svx/uiconfig/ui/clipboardmenu.ui
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/colorwindow.ui b/svx/uiconfig/ui/colorwindow.ui
new file mode 100644
index 000000000..7f7cf5fa9
--- /dev/null
+++ b/svx/uiconfig/ui/colorwindow.ui
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="auto_icon">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">cmd/sc_square_unfilled.png</property>
+ </object>
+ <object class="GtkImage" id="custom_color_icon">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin-end">6</property>
+ <property name="icon_name">cmd/sc_colorsettings.png</property>
+ </object>
+ <object class="GtkImage" id="none_icon">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">cmd/sc_square_unfilled.png</property>
+ </object>
+ <object class="GtkPopover" id="palette_popup_window">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkButton" id="auto_color_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="image">auto_icon</property>
+ <property name="relief">none</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="none_color_button">
+ <property name="label" translatable="yes" context="colorwindow|none_color_button">None</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="image">none_icon</property>
+ <property name="relief">none</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="separator4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="palette_listbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="colorsetwin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="colorset">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="separator1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="colorwindow|label1">Recent</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">recent_colorset</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkDrawingArea" id="recent_colorset">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="separator3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="color_picker_button">
+ <property name="label" translatable="yes" context="colorwindow|color_picker_button">Custom Color…</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">custom_color_icon</property>
+ <property name="relief">none</property>
+ <property name="xalign">0</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">9</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/colsmenu.ui b/svx/uiconfig/ui/colsmenu.ui
new file mode 100644
index 000000000..af3be2f6c
--- /dev/null
+++ b/svx/uiconfig/ui/colsmenu.ui
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="insert">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="colsmenu|insert">Insert _Column</property>
+ <property name="use-underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="insertmenu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="change">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="colsmenu|change">_Replace with</property>
+ <property name="use-underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="changemenu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="colsmenu|delete">Delete column</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="hide">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="colsmenu|hide">_Hide Column</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="show">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="colsmenu|show">_Show Columns</property>
+ <property name="use-underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="showmenu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="more">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="colsmenu|more">_More...</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="all">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="colsmenu|all">_All</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="column">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="colsmenu|column">Column...</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/columnswindow.ui b/svx/uiconfig/ui/columnswindow.ui
new file mode 100644
index 000000000..71ddc1ede
--- /dev/null
+++ b/svx/uiconfig/ui/columnswindow.ui
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="lower">1</property>
+ <property name="upper">1000</property>
+ <property name="value">1</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkPopover" id="ColumnsWindow">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkDrawingArea" id="columns">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment2</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/compressgraphicdialog.ui b/svx/uiconfig/ui/compressgraphicdialog.ui
new file mode 100644
index 000000000..727191ecb
--- /dev/null
+++ b/svx/uiconfig/ui/compressgraphicdialog.ui
@@ -0,0 +1,731 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.4 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="compression-adjustment-spin">
+ <property name="lower">1</property>
+ <property name="upper">9</property>
+ <property name="value">6</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">1</property>
+ </object>
+ <object class="GtkAdjustment" id="compression-adjustment-scale">
+ <property name="lower">1</property>
+ <property name="upper">9</property>
+ <property name="value">6</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">1</property>
+ </object>
+ <object class="GtkAdjustment" id="height-adjustment">
+ <property name="lower">1</property>
+ <property name="upper">20000</property>
+ <property name="value">1</property>
+ <property name="step_increment">100</property>
+ <property name="page_increment">100</property>
+ </object>
+ <object class="GtkAdjustment" id="quality-adjustment-spin">
+ <property name="lower">1</property>
+ <property name="upper">99</property>
+ <property name="value">80</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">5</property>
+ </object>
+ <object class="GtkAdjustment" id="quality-adjustment-scale">
+ <property name="lower">1</property>
+ <property name="upper">99</property>
+ <property name="value">80</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">5</property>
+ </object>
+ <object class="GtkAdjustment" id="width-adjustment">
+ <property name="lower">1</property>
+ <property name="upper">20000</property>
+ <property name="value">1</property>
+ <property name="step_increment">100</property>
+ <property name="page_increment">100</property>
+ </object>
+ <object class="GtkDialog" id="CompressGraphicDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="compressgraphicdialog|CompressGraphicDialog">Compress Image</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">9</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkRadioButton" id="radio-jpeg">
+ <property name="label" translatable="yes" context="compressgraphicdialog|radio-jpeg">JPEG Quality</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes" context="compressgraphicdialog|radio-jpeg|tooltip_text">Lossy compression</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radio-lossless</property>
+ <accessibility>
+ <relation type="label-for" target="scale-quality"/>
+ <relation type="label-for" target="spin-quality"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radio-lossless">
+ <property name="label" translatable="yes" context="compressgraphicdialog|radio-lossless">PNG Compression</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes" context="compressgraphicdialog|radio-lossless|tooltip_text">Lossless compression</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <accessibility>
+ <relation type="label-for" target="scale-compression"/>
+ <relation type="label-for" target="spin-compression"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">6</property>
+ <property name="margin-start">12</property>
+ <child>
+ <object class="GtkScale" id="scale-quality">
+ <property name="width_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">quality-adjustment-scale</property>
+ <property name="digits">0</property>
+ <property name="draw_value">False</property>
+ <property name="value_pos">right</property>
+ <accessibility>
+ <relation type="labelled-by" target="radio-jpeg"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spin-quality">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">quality-adjustment-spin</property>
+ <property name="numeric">True</property>
+ <property name="truncate-multiline">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="radio-jpeg"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">6</property>
+ <property name="margin-start">12</property>
+ <child>
+ <object class="GtkScale" id="scale-compression">
+ <property name="width_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">compression-adjustment-scale</property>
+ <property name="digits">0</property>
+ <property name="draw_value">False</property>
+ <property name="value_pos">right</property>
+ <accessibility>
+ <relation type="labelled-by" target="radio-lossless"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spin-compression">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="text">6</property>
+ <property name="adjustment">compression-adjustment-spin</property>
+ <property name="numeric">True</property>
+ <property name="value">6</property>
+ <property name="truncate-multiline">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="radio-lossless"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label2">Compression</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkbox-reduce-resolution">
+ <property name="label" translatable="yes" context="compressgraphicdialog|checkbox-reduce-resolution">Reduce image resolution to:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label3">Width:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">spin-new-width</property>
+ <property name="width_chars">14</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label4">Height:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">spin-new-height</property>
+ <property name="width_chars">14</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label5">Resolution:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">combo-resolution</property>
+ <property name="width_chars">14</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label12">Interpolation:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">interpolation-method-combo</property>
+ <property name="width_chars">14</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spin-new-width">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="text">1</property>
+ <property name="adjustment">width-adjustment</property>
+ <property name="numeric">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="value">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spin-new-height">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="text">1</property>
+ <property name="adjustment">height-adjustment</property>
+ <property name="numeric">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="value">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="combo-resolution">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="has_entry">True</property>
+ <items>
+ <item>96</item>
+ <item>150</item>
+ <item>200</item>
+ <item>300</item>
+ <item>600</item>
+ </items>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="can_focus">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="interpolation-method-combo">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <items>
+ <item translatable="yes" context="compressgraphicdialog|interpolation-method-store">None</item>
+ <item translatable="yes" context="compressgraphicdialog|interpolation-method-store">Bilinear</item>
+ <item translatable="yes" context="compressgraphicdialog|interpolation-method-store">Bicubic</item>
+ <item translatable="yes" context="compressgraphicdialog|interpolation-method-store">Lanczos</item>
+ </items>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label13">px</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label14">px</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label16">DPI</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label22">Resolution</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <property name="margin-start">16</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label15">Type:</property>
+ <property name="single_line_mode">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="label-graphic-type"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label-graphic-type">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label">???</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="label15"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label7">Actual dimensions:</property>
+ <property name="single_line_mode">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="label-original-size"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label-original-size">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label">???</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="label7"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label8">Apparent dimensions:</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="label-view-size"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label-view-size">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label">???</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="label8"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label9">Image size:</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="label-image-capacity"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label-image-capacity">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label">???</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="label9"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="calculate">
+ <property name="label" translatable="yes" context="compressgraphicdialog|calculate">Calculate New Size:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">start</property>
+ <accessibility>
+ <relation type="label-for" target="label-new-capacity"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label-new-capacity">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label">???</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="labelled-by" target="calculate"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="compressgraphicdialog|label1">Image Information</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/crashreportdlg.ui b/svx/uiconfig/ui/crashreportdlg.ui
new file mode 100644
index 000000000..3b661706c
--- /dev/null
+++ b/svx/uiconfig/ui/crashreportdlg.ui
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTextBuffer" id="textbuffer1">
+ <property name="text" translatable="yes" context="crashreportdlg|ed_post">The crash report was successfully uploaded.
+You can soon find the report at:
+https://crashreport.libreoffice.org/stats/crash_details/%CRASHID</property>
+ </object>
+ <object class="GtkTextBuffer" id="textbuffer2">
+ <property name="text" translatable="yes" context="crashreportdlg|ed_bugreport">Please check the report and if no bug report is connected to the crash report yet, open a new bug report at bugs.documentfoundation.org.
+Add detailed instructions on how to reproduce the crash and the shown crash ID into the crash report field.
+Thank you for your help in improving %PRODUCTNAME.</property>
+ </object>
+ <object class="GtkDialog" id="CrashReportDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="crashreportdlg|CrashReportDialog">Crash Report</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="btn_send">
+ <property name="label" translatable="yes" context="crashreportdlg|btn_send">_Send Crash Report</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="btn_cancel">
+ <property name="label" translatable="yes" context="crashreportdlg|btn_cancel">Do _Not Send</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="btn_close">
+ <property name="label" translatable="yes" context="crashreportdlg|btn_close">Close</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="ed_pre">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="crashreportdlg|ed_pre">Unfortunately it seems that %PRODUCTNAME crashed when it was last run.
+
+You can help us to fix this issue by sending an anonymous crash report to the %PRODUCTNAME crash reporting server.</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">80</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTextView" id="ed_post">
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="editable">False</property>
+ <property name="wrap_mode">word</property>
+ <property name="cursor_visible">False</property>
+ <property name="buffer">textbuffer1</property>
+ <property name="accepts_tab">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTextView" id="ed_bugreport">
+ <property name="can_focus">False</property>
+ <property name="editable">False</property>
+ <property name="wrap_mode">word</property>
+ <property name="cursor_visible">False</property>
+ <property name="buffer">textbuffer2</property>
+ <property name="accepts_tab">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="check_safemode">
+ <property name="label" translatable="yes" context="crashreportdlg|check_safemode">Restart %PRODUCTNAME to enter safe mode</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLinkButton" id="btnPrivacyPolicy">
+ <property name="label" translatable="yes" context="crashreportdlg|privacy">Privacy Policy</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/currencywindow.ui b/svx/uiconfig/ui/currencywindow.ui
new file mode 100644
index 000000000..c58a0c492
--- /dev/null
+++ b/svx/uiconfig/ui/currencywindow.ui
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkPopover" id="CurrencyWindow">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">currency</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="currency">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">False</property>
+ <property name="search_column">0</property>
+ <property name="show_expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="selection"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/datanavigator.ui b/svx/uiconfig/ui/datanavigator.ui
new file mode 100644
index 000000000..87cc66e01
--- /dev/null
+++ b/svx/uiconfig/ui/datanavigator.ui
@@ -0,0 +1,372 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="instancesmenu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="instancesadd">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="datanavigator|instancesadd">_Add...</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="instancesadd-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|instancesadd">Opens a dialog where you can add a new instance.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="instancesedit">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="datanavigator|instancesedit">_Edit...</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="instancesedit-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|instancesedit">Opens a dialog where you can modify the current instance.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="instancesremove">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="datanavigator|instancesremove">_Remove...</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="instancesremove-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|instancesremove">Deletes the current instance. You cannot delete the last instance.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="instancesdetails">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="datanavigator|instancesdetails">_Show Details</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="instancesdetails-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|instancesdetails">Switches the display to show or hide details.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkMenu" id="modelsmenu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="modelsadd">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="datanavigator|modelsadd">_Add...</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="modelsadd-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|modelsadd">Opens the Add Model dialog where you can add an XForm model.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="modelsedit">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="datanavigator|modelsedit">_Edit...</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="modelsedit-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|modelsedit">Renames the selected XForms model.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="modelsremove">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="datanavigator|modelsremove">_Remove</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="modelsremove-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|modelsremove">Deletes the selected XForm model. You cannot delete the last model.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkBox" id="DataNavigator">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">0</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkComboBoxText" id="modelslist">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="modelslist-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|modelslist">Selects the XForms model that you want to use.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="modelsbutton">
+ <property name="label" translatable="yes" context="datanavigator|modelsbutton">_Models</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="popup">modelsmenu</property>
+ <property name="use_popover">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="modelsbutton-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|modelsbutton">Adds, renames, and removes XForms models.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="tabcontrol">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="scrollable">True</property>
+ <property name="enable_popup">True</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="instance">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="datanavigator|instance">Instance</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="submissions">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="datanavigator|submissions">Submissions</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="bindings">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="datanavigator|bindings">Bindings</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="instances">
+ <property name="label" translatable="yes" context="datanavigator|instances">_Instances</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">end</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="popup">instancesmenu</property>
+ <property name="use_popover">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="instances-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|instances">This button has submenus to add, edit or remove instances.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="DataNavigator-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="datanavigator|extended_tip|DataNavigator">Specifies the data structure of the current XForms document.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/defaultshapespanel.ui b/svx/uiconfig/ui/defaultshapespanel.ui
new file mode 100644
index 000000000..df4707616
--- /dev/null
+++ b/svx/uiconfig/ui/defaultshapespanel.ui
@@ -0,0 +1,358 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="DefaultShapesPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkFrame" id="LinesFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkDrawingArea" id="LinesArrows">
+ <property name="height_request">50</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="defaultshapespanel|label1">Lines and Arrows</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="CurveFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkDrawingArea" id="Curves">
+ <property name="height_request">50</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="defaultshapespanel|label2">Curves and Polygons</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="ConnectorFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkDrawingArea" id="Connectors">
+ <property name="height_request">50</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="defaultshapespanel|label3">Connectors</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="BasicShapesFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkDrawingArea" id="BasicShapes">
+ <property name="height_request">100</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="defaultshapespanel|label4">Basic Shapes</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="Symbols">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkDrawingArea" id="SymbolShapes">
+ <property name="height_request">75</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="defaultshapespanel|label5">Symbol Shapes</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="BlockArrowFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkDrawingArea" id="BlockArrows">
+ <property name="height_request">125</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="defaultshapespanel|label6">Block Arrows</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="FlowchartFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkDrawingArea" id="Flowcharts">
+ <property name="height_request">125</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="defaultshapespanel|label7">Flowchart</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="CalloutFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkDrawingArea" id="Callouts">
+ <property name="height_request">50</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="defaultshapespanel|label8">Callouts</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="StarsFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkDrawingArea" id="Stars">
+ <property name="height_request">50</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="defaultshapespanel|label9">Stars and Banners</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="3DObjectsFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkDrawingArea" id="3DObjects">
+ <property name="height_request">50</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="margin-start">12</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="defaultshapespanel|label10">3D Objects</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">9</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/deletefooterdialog.ui b/svx/uiconfig/ui/deletefooterdialog.ui
new file mode 100644
index 000000000..d86eed95b
--- /dev/null
+++ b/svx/uiconfig/ui/deletefooterdialog.ui
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="DeleteFooterDialog">
+ <property name="can-focus">False</property>
+ <property name="title" translatable="yes" context="deletefooterdialog|DeleteFooterDialog">Delete footer?</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type-hint">dialog</property>
+ <property name="skip-taskbar-hint">True</property>
+ <property name="message-type">warning</property>
+ <property name="text" translatable="yes" context="deletefooterdialog|DeleteFooterDialog">Are you sure you want to delete the footer?</property>
+ <property name="secondary-text" translatable="yes" context="deletefooterdialog|DeleteFooterDialog">All contents of the footer will be deleted and can not be restored.</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox">
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area">
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkButton" id="no">
+ <property name="label" translatable="yes" context="stock">_No</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="yes">
+ <property name="label" translatable="yes" context="stock">_Yes</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ <style>
+ <class name="destructive-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-9">no</action-widget>
+ <action-widget response="-8">yes</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/deleteheaderdialog.ui b/svx/uiconfig/ui/deleteheaderdialog.ui
new file mode 100644
index 000000000..dfa2dbda6
--- /dev/null
+++ b/svx/uiconfig/ui/deleteheaderdialog.ui
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="DeleteHeaderDialog">
+ <property name="can-focus">False</property>
+ <property name="title" translatable="yes" context="deleteheaderdialog|DeleteHeaderDialog">Delete header?</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type-hint">dialog</property>
+ <property name="skip-taskbar-hint">True</property>
+ <property name="message-type">warning</property>
+ <property name="text" translatable="yes" context="deleteheaderdialog|DeleteHeaderDialog">Are you sure you want to delete the header?</property>
+ <property name="secondary-text" translatable="yes" context="deleteheaderdialog|DeleteHeaderDialog">All contents of the header will be deleted and can not be restored.</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox">
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area">
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkButton" id="no">
+ <property name="label" translatable="yes" context="stock">_No</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="yes">
+ <property name="label" translatable="yes" context="stock">_Yes</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ <style>
+ <class name="destructive-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-9">no</action-widget>
+ <action-widget response="-8">yes</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/depthwindow.ui b/svx/uiconfig/ui/depthwindow.ui
new file mode 100644
index 000000000..3d083471d
--- /dev/null
+++ b/svx/uiconfig/ui/depthwindow.ui
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/extrusion1inch_16.png</property>
+ </object>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/extrusion05inch_16.png</property>
+ </object>
+ <object class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/extrusion2inch_16.png</property>
+ </object>
+ <object class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/extrusion0inch_16.png</property>
+ </object>
+ <object class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/extrusion4inch_16.png</property>
+ </object>
+ <object class="GtkImage" id="image6">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/extrusioninfinity_16.png</property>
+ </object>
+ <object class="GtkPopover" id="DepthWindow">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="border-width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="depth0">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="image">image4</property>
+ <property name="use-underline">True</property>
+ <property name="always-show-image">True</property>
+ <property name="active">True</property>
+ <property name="draw-indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="depth1">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="image">image2</property>
+ <property name="use-underline">True</property>
+ <property name="always-show-image">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">depth0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="depth2">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="image">image1</property>
+ <property name="use-underline">True</property>
+ <property name="always-show-image">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">depth0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="depth3">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="image">image3</property>
+ <property name="use-underline">True</property>
+ <property name="always-show-image">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">depth0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="depth4">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="image">image5</property>
+ <property name="use-underline">True</property>
+ <property name="always-show-image">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">depth0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="infinity">
+ <property name="label" translatable="yes" context="depthwindow|RID_SVXSTR_INFINITY">_Infinity</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="image">image6</property>
+ <property name="use-underline">True</property>
+ <property name="always-show-image">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">depth0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="custom">
+ <property name="label" translatable="yes" context="depthwindow|RID_SVXSTR_CUSTOM">_Custom...</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">depth0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/directionwindow.ui b/svx/uiconfig/ui/directionwindow.ui
new file mode 100644
index 000000000..80d1ffda9
--- /dev/null
+++ b/svx/uiconfig/ui/directionwindow.ui
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/perspective_16.png</property>
+ </object>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/parallel_16.png</property>
+ </object>
+ <object class="GtkPopover" id="DirectionWindow">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="valuesetwin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="valueset">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="perspective">
+ <property name="label" translatable="yes" context="directionwindow|RID_SVXSTR_PERSPECTIVE">_Perspective</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image1</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="parallel">
+ <property name="label" translatable="yes" context="dockingwindow|RID_SVXSTR_PARALLEL">P_arallel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image2</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">perspective</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/docking3deffects.ui b/svx/uiconfig/ui/docking3deffects.ui
new file mode 100644
index 000000000..e5203e18d
--- /dev/null
+++ b/svx/uiconfig/ui/docking3deffects.ui
@@ -0,0 +1,2519 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step-increment">5</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment10">
+ <property name="upper">100</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">10000</property>
+ <property name="step-increment">5</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">3600</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="upper">10000</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment5">
+ <property name="lower">2</property>
+ <property name="upper">256</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment6">
+ <property name="upper">90</property>
+ <property name="step-increment">5</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment7">
+ <property name="upper">100</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment8">
+ <property name="upper">100</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment9">
+ <property name="lower">1</property>
+ <property name="upper">256</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/3dgeo.png</property>
+ </object>
+ <object class="GtkImage" id="image10">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/normsphe.png</property>
+ </object>
+ <object class="GtkImage" id="image11">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/invert3d.png</property>
+ </object>
+ <object class="GtkImage" id="image12">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/lght2sid.png</property>
+ </object>
+ <object class="GtkImage" id="image13">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/doublesi.png</property>
+ </object>
+ <object class="GtkImage" id="image14">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/convrt3d.png</property>
+ </object>
+ <object class="GtkImage" id="image15">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/rotate3d.png</property>
+ </object>
+ <object class="GtkImage" id="image16">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/persp3d.png</property>
+ </object>
+ <object class="GtkImage" id="image17">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/shadow3d.png</property>
+ </object>
+ <object class="GtkImage" id="image18">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/colordlg.png</property>
+ </object>
+ <object class="GtkImage" id="image19">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/colordlg.png</property>
+ </object>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/3drepres.png</property>
+ </object>
+ <object class="GtkImage" id="image20">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/light.png</property>
+ </object>
+ <object class="GtkImage" id="image21">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/light.png</property>
+ </object>
+ <object class="GtkImage" id="image22">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/light.png</property>
+ </object>
+ <object class="GtkImage" id="image23">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/light.png</property>
+ </object>
+ <object class="GtkImage" id="image24">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/light.png</property>
+ </object>
+ <object class="GtkImage" id="image25">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/light.png</property>
+ </object>
+ <object class="GtkImage" id="image26">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/light.png</property>
+ </object>
+ <object class="GtkImage" id="image27">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/light.png</property>
+ </object>
+ <object class="GtkImage" id="image28">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/luminanc.png</property>
+ </object>
+ <object class="GtkImage" id="image29">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/color.png</property>
+ </object>
+ <object class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/3dlight.png</property>
+ </object>
+ <object class="GtkImage" id="image30">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/replac3d.png</property>
+ </object>
+ <object class="GtkImage" id="image31">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/modula3d.png</property>
+ </object>
+ <object class="GtkImage" id="image32">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/objspc3d.png</property>
+ </object>
+ <object class="GtkImage" id="image33">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/parallel.png</property>
+ </object>
+ <object class="GtkImage" id="image34">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/sphere3d.png</property>
+ </object>
+ <object class="GtkImage" id="image35">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/objspc3d.png</property>
+ </object>
+ <object class="GtkImage" id="image36">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/parallel.png</property>
+ </object>
+ <object class="GtkImage" id="image37">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/sphere3d.png</property>
+ </object>
+ <object class="GtkImage" id="image38">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/filter3d.png</property>
+ </object>
+ <object class="GtkImage" id="image39">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/colordlg.png</property>
+ </object>
+ <object class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/3dtextur.png</property>
+ </object>
+ <object class="GtkImage" id="image40">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/colordlg.png</property>
+ </object>
+ <object class="GtkImage" id="image41">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/colordlg.png</property>
+ </object>
+ <object class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/material.png</property>
+ </object>
+ <object class="GtkImage" id="image6">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">res/sc10350.png</property>
+ </object>
+ <object class="GtkImage" id="image7">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/apply.png</property>
+ </object>
+ <object class="GtkImage" id="image8">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/normobjs.png</property>
+ </object>
+ <object class="GtkImage" id="image9">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/normflat.png</property>
+ </object>
+ <object class="GtkBox" id="Docking3DEffects">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <!-- n-columns=1 n-rows=11 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">24</property>
+ <child>
+ <object class="GtkFrame" id="geoframe">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=2 n-rows=4 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="diagonalft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|diagonalft">R_ounded edges</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">diagonal</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="scaleddepthft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|scaleddepthft">_Scaled depth</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">scaleddepth</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="angleft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|angleft">_Rotation angle</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">angle</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="depthft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|depthft">_Depth</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">depth</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="diagonal">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment1</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="diagonal-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|diagonal">Enter the amount by which you want to round the corners of the selected 3D object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="scaleddepth">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="text">0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="scaleddepth-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|scaleddepth">Enter the amount by which to increase or decrease the area of the front side of the selected 3D object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="angle">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="text">0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="digits">1</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="angle-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|angle">Enter the angle in degrees to rotate the selected 3D rotation object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="depth">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="text">0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment4</property>
+ <property name="digits">2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="depth-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|depth">Enter the extrusion depth for the selected 3D object. This option is not valid for 3D rotation objects.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label1">Geometry</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="segmentsframe">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=2 n-rows=2 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label6">_Horizontal</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">hori</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label7">_Vertical</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">veri</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="veri">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="text">0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment9</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="veri-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|veri">Enter the number of vertical segments to use in the selected 3D rotation object</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="hori">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="text">0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment5</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="hori-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|hori">Enter the number of horizontal segments to use in the selected 3D rotation object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label10">Segments</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid" id="grid6">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-end">12</property>
+ <property name="margin-bottom">12</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <!-- n-columns=1 n-rows=2 -->
+ <object class="GtkGrid" id="grid7">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="normals">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=3 n-rows=3 -->
+ <object class="GtkGrid" id="grid8">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">start</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">6</property>
+ <property name="row-homogeneous">True</property>
+ <property name="column-homogeneous">True</property>
+ <child>
+ <object class="GtkToggleButton" id="objspecific">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|objspecific|tooltip_text">Object-Specific</property>
+ <property name="valign">center</property>
+ <property name="image">image8</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="objspecific-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|objspecific">Renders the 3D surface according to the shape of the object. For example, a circular shape is rendered with a spherical surface.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="flat">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|flat|tooltip_text">Flat</property>
+ <property name="valign">center</property>
+ <property name="image">image9</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="flat-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|flat">Renders the 3D surface as polygons.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="spherical">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|spherical|tooltip_text">Spherical</property>
+ <property name="valign">center</property>
+ <property name="image">image10</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="spherical-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|spherical">Renders a smooth 3D surface.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="invertnormals">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|invertnormals|tooltip_text">Invert Normals</property>
+ <property name="valign">center</property>
+ <property name="image">image11</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="invertnormals-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|invertnormals">Inverts the light source.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="doublesidedillum">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|doublesidedillum|tooltip_text">Double-Sided Illumination</property>
+ <property name="valign">center</property>
+ <property name="image">image12</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="doublesidedillum-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|doublesidedillum">Lights the object from the outside and the inside. To use an ambient light source, click this button, and then click the Invert Normals button.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="doublesided">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|doublesided|tooltip_text">Double-Sided</property>
+ <property name="valign">center</property>
+ <property name="image">image13</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="doublesided-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|doublesided">Closes the shape of a 3D object that was created by extruding a freeform line (Convert - To 3D).</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label11">Normals</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=3 n-rows=1 -->
+ <object class="GtkGrid" id="grid10">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">end</property>
+ <property name="margin-start">12</property>
+ <property name="vexpand">True</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">6</property>
+ <property name="row-homogeneous">True</property>
+ <property name="column-homogeneous">True</property>
+ <child>
+ <object class="GtkButton" id="to3d">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|to3d|tooltip_text">Convert to 3D</property>
+ <property name="image">image14</property>
+ <property name="always-show-image">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="to3d-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|to3d">Use this icon to convert a selected 2D object to a 3D object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="tolathe">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|tolathe|tooltip_text">Convert to Rotation Object</property>
+ <property name="image">image15</property>
+ <property name="always-show-image">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="tolathe-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|tolathe">Click here to convert a selected 2D object to a 3D rotation object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="perspective">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|perspective|tooltip_text">Perspective On/Off</property>
+ <property name="image">image16</property>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkDrawingArea" id="preview">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="halign">end</property>
+ <property name="valign">end</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="preview-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="docking3deffects|preview-atkobject">3D Preview</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="lightpreviewgrid">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="halign">end</property>
+ <property name="valign">end</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <!-- n-columns=2 n-rows=2 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="lightpreview">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="tooltip-text" translatable="yes" context="tp_3D_SceneIllumination|CTL_LIGHT_PREVIEW|tooltip_text">Light Preview</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="lightpreview-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="docking3deffects|lightpreview-atkobject">Color Light Preview</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="corner">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScale" id="horiscale">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="round-digits">1</property>
+ <property name="draw-value">False</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScale" id="vertscale">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="orientation">vertical</property>
+ <property name="round-digits">1</property>
+ <property name="draw-value">False</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">10</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="shadingframe">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid" id="grid11">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label8">_Mode</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">mode</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="mode">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <items>
+ <item translatable="yes" context="docking3deffects|mode">Flat</item>
+ <item translatable="yes" context="docking3deffects|mode">Phong</item>
+ <item translatable="yes" context="docking3deffects|mode">Gouraud</item>
+ </items>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="mode-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|mode">Select the shading method that you want to use. Flat shading assigns a single color to a single polygon on the surface of the object. Gouraud shading blends colors across the polygons. Phong shading averages the color of each pixel based on the pixels that surround it, and requires the most processing power.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label12">Shading</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="shadowframe">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid" id="grid9">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="hexpand">True</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkSpinButton" id="slant">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment6</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="slant-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|slant">Enter an angle from 0 to 90 degrees for casting the shadow.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkToggleButton" id="shadow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|shadow|tooltip_text">3D Shadowing On/Off</property>
+ <property name="image">image17</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="shadow-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|shadow">Adds or removes a shadow from the selected 3D object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="slantft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="label" translatable="yes" context="docking3deffects|slantft">S_urface angle</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">slant</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label13">Shadow</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="cameraframe">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=2 n-rows=2 -->
+ <object class="GtkGrid" id="grid12">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="hexpand">True</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkSpinButton" id="focal">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment10</property>
+ <property name="digits">2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="focal-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|focal">Enter the focal length of the camera, where a small value corresponds to a "fisheye" lens, and a large value to a telephoto lens.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="distance">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment7</property>
+ <property name="digits">2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="distance-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|distance">Enter the distance to leave between the camera and the center of the selected object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label15">_Focal length</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">focal</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label14">_Distance</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">distance</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label16">Camera</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="illumframe">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=3 n-rows=3 -->
+ <object class="GtkGrid" id="grid13">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label17">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="docking3deffects|label17">_Light source</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="light1"/>
+ <relation type="label-for" target="light2"/>
+ <relation type="label-for" target="light3"/>
+ <relation type="label-for" target="light4"/>
+ <relation type="label-for" target="light5"/>
+ <relation type="label-for" target="light6"/>
+ <relation type="label-for" target="light7"/>
+ <relation type="label-for" target="light8"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="colorbutton1">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|colorbutton1|tooltip_text">Colors Dialog</property>
+ <property name="valign">start</property>
+ <property name="image">image19</property>
+ <property name="always-show-image">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="colorbutton1-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|colorbutton1">Select a color for the ambient light.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="ambientcolor">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="valign">center</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="ambientcolor-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|ambientcolor">Select a color for the ambient light.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="colorbutton2">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|colorbutton2|tooltip_text">Colors Dialog</property>
+ <property name="valign">center</property>
+ <property name="image">image18</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label18">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label18">_Ambient light</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">ambientcolor</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=4 n-rows=2 -->
+ <object class="GtkGrid" id="grid14">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">6</property>
+ <child>
+ <object class="GtkToggleButton" id="light1">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|light1|tooltip_text">Light Source 1</property>
+ <property name="image">image20</property>
+ <accessibility>
+ <relation type="labelled-by" target="label17"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="light1-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|light1">Click twice to turn the light source on, and then select a color for the light from the list. If you want, you can also set the color of the surrounding light, by selecting a color from the Ambient light box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="light2">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|light2|tooltip_text">Light Source 2</property>
+ <property name="image">image21</property>
+ <accessibility>
+ <relation type="labelled-by" target="label17"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="light2-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|light2">Click twice to turn the light source on, and then select a color for the light from the list. If you want, you can also set the color of the surrounding light, by selecting a color from the Ambient light box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="light3">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|light3|tooltip_text">Light Source 3</property>
+ <property name="image">image22</property>
+ <accessibility>
+ <relation type="labelled-by" target="label17"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="light3-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|light3">Click twice to turn the light source on, and then select a color for the light from the list. If you want, you can also set the color of the surrounding light, by selecting a color from the Ambient light box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="light4">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|light4|tooltip_text">Light Source 4</property>
+ <property name="image">image23</property>
+ <accessibility>
+ <relation type="labelled-by" target="label17"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="light4-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|light4">Click twice to turn the light source on, and then select a color for the light from the list. If you want, you can also set the color of the surrounding light, by selecting a color from the Ambient light box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="light5">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|light5|tooltip_text">Light Source 5</property>
+ <property name="image">image24</property>
+ <accessibility>
+ <relation type="labelled-by" target="label17"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="light5-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|light5">Click twice to turn the light source on, and then select a color for the light from the list. If you want, you can also set the color of the surrounding light, by selecting a color from the Ambient light box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="light6">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|light6|tooltip_text">Light Source 6</property>
+ <property name="image">image25</property>
+ <accessibility>
+ <relation type="labelled-by" target="label17"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="light6-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|light6">Click twice to turn the light source on, and then select a color for the light from the list. If you want, you can also set the color of the surrounding light, by selecting a color from the Ambient light box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="light7">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|light7|tooltip_text">Light Source 7</property>
+ <property name="image">image26</property>
+ <accessibility>
+ <relation type="labelled-by" target="label17"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="light7-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|light7">Click twice to turn the light source on, and then select a color for the light from the list. If you want, you can also set the color of the surrounding light, by selecting a color from the Ambient light box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="light8">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|light8|tooltip_text">Light Source 8</property>
+ <property name="image">image27</property>
+ <accessibility>
+ <relation type="labelled-by" target="label17"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="light8-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|light8">Click twice to turn the light source on, and then select a color for the light from the list. If you want, you can also set the color of the surrounding light, by selecting a color from the Ambient light box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkMenuButton" id="lightcolor1">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|lightcolor1|tooltip_text">Light 1 color</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="lightcolor1-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|lightcolor1">Select a color for the current light source.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="lightcolor2">
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|lightcolor2|tooltip_text">Light 2 color</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="lightcolor3">
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|lightcolor3|tooltip_text">Light 3 color</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="lightcolor4">
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|lightcolor4|tooltip_text">Light 4 color</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="lightcolor5">
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|lightcolor5|tooltip_text">Light 5 color</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="lightcolor6">
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|lightcolor6|tooltip_text">Light 6 color</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="lightcolor7">
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|lightcolor7|tooltip_text">Light 7 color</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="lightcolor8">
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|lightcolor8|tooltip_text">Light 8 color</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">7</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label19">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label19">Illumination</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="textureframe">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=4 n-rows=5 -->
+ <object class="GtkGrid" id="grid15">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label20">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label20">_Type</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="textype"/>
+ <relation type="label-for" target="texcolor"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label22">_Mode</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="texreplace"/>
+ <relation type="label-for" target="texmodulate"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label23">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label23">_Projection X</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="texobjx"/>
+ <relation type="label-for" target="texparallelx"/>
+ <relation type="label-for" target="texcirclex"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label24">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label24">P_rojection Y</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="texobjy"/>
+ <relation type="label-for" target="texparallely"/>
+ <relation type="label-for" target="texcircley"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label25">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label25">_Filtering</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="texfilter"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="textype">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|textype|tooltip_text">Black &amp; White</property>
+ <property name="halign">center</property>
+ <property name="image">image28</property>
+ <accessibility>
+ <relation type="labelled-by" target="label20"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="textype-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|textype">Converts the texture to black and white.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texcolor">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texcolor|tooltip_text">Color</property>
+ <property name="halign">center</property>
+ <property name="image">image29</property>
+ <accessibility>
+ <relation type="labelled-by" target="label20"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texcolor-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texcolor">Converts the texture to color.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texreplace">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texreplace|tooltip_text">Only Texture</property>
+ <property name="halign">center</property>
+ <property name="image">image30</property>
+ <accessibility>
+ <relation type="labelled-by" target="label22"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texreplace-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texreplace">Applies the texture without shading.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texmodulate">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texmodulate|tooltip_text">Texture and Shading</property>
+ <property name="halign">center</property>
+ <property name="image">image31</property>
+ <accessibility>
+ <relation type="labelled-by" target="label22"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texmodulate-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texmodulate">Applies the texture with shading. To define the shading options for the texture, click the Shading button in this dialog.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texobjx">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texobjx|tooltip_text">Object-Specific</property>
+ <property name="halign">center</property>
+ <property name="image">image32</property>
+ <accessibility>
+ <relation type="labelled-by" target="label23"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texobjx-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texobjx">Automatically adjusts the texture based on the shape and size of the object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texparallelx">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texparallelx|tooltip_text">Parallel</property>
+ <property name="halign">center</property>
+ <property name="image">image33</property>
+ <accessibility>
+ <relation type="labelled-by" target="label23"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texparallelx-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texparallelx">Applies the texture parallel to the horizontal axis.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texcirclex">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texcirclex|tooltip_text">Circular</property>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="image">image34</property>
+ <accessibility>
+ <relation type="labelled-by" target="label23"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texcirclex-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texcirclex">Wraps the horizontal axis of the texture pattern around a sphere.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texobjy">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texobjy|tooltip_text">Object-Specific</property>
+ <property name="halign">center</property>
+ <property name="image">image35</property>
+ <accessibility>
+ <relation type="labelled-by" target="label24"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texobjy-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texobjy">Automatically adjusts the texture based on the shape and size of the object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texparallely">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texparallely|tooltip_text">Parallel</property>
+ <property name="halign">center</property>
+ <property name="image">image36</property>
+ <accessibility>
+ <relation type="labelled-by" target="label24"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texparallely-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texparallely">Applies the texture parallel to the vertical axis.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texcircley">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texcircley|tooltip_text">Circular</property>
+ <property name="halign">start</property>
+ <property name="image">image37</property>
+ <accessibility>
+ <relation type="labelled-by" target="label24"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texcircley-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texcircley">Wraps the vertical axis of the texture pattern around a sphere.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texfilter">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texfilter|tooltip_text">Filtering On/Off</property>
+ <property name="halign">center</property>
+ <property name="image">image38</property>
+ <accessibility>
+ <relation type="labelled-by" target="label25"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texfilter-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texfilter">Blurs the texture slightly to remove unwanted speckles.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label21">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label21">Textures</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="materialframe">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=3 n-rows=3 -->
+ <object class="GtkGrid" id="grid16">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label26">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label26">_Favorites</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="favorites"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label27">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label27">_Object color</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">objcolor</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label29">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label29">_Illumination color</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">illumcolor</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="objcolor">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="objcolor-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|objcolor">Select the color that you want to apply to the object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="illumcolor">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="illumcolor-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|illumcolor">Select the color to illuminate the object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="favorites">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <items>
+ <item translatable="yes" context="docking3deffects|favorites">User-defined</item>
+ <item translatable="yes" context="docking3deffects|favorites">Metal</item>
+ <item translatable="yes" context="docking3deffects|favorites">Gold</item>
+ <item translatable="yes" context="docking3deffects|favorites">Chrome</item>
+ <item translatable="yes" context="docking3deffects|favorites">Plastic</item>
+ <item translatable="yes" context="docking3deffects|favorites">Wood</item>
+ </items>
+ <accessibility>
+ <relation type="labelled-by" target="label26"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="favorites-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|favorites">Select a predefined color scheme, or select User-defined to define a custom color scheme.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="colorbutton3">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|colorbutton3|tooltip_text">Colors Dialog</property>
+ <property name="image">image39</property>
+ <property name="always-show-image">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="colorbutton3-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|colorbutton3">Select the color to illuminate the object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="colorbutton4">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|colorbutton4|tooltip_text">Colors Dialog</property>
+ <property name="image">image40</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label28">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label28">Material</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="specframe">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=3 n-rows=2 -->
+ <object class="GtkGrid" id="grid17">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label30">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label30">_Color</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">speccolor</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label31">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label31">I_ntensity</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">intensity</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="speccolor">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="speccolor-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|speccolor">Select the color that you want the object to reflect.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="colorbutton5">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|colorbutton5|tooltip_text">Colors Dialog</property>
+ <property name="image">image41</property>
+ <property name="always-show-image">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="colorbutton5-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|colorbutton5">Enter the intensity of the specular effect.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="intensity">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment8</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="intensity-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|intensity">Enter the intensity of the specular effect.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label32">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="docking3deffects|label32">Specular</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">9</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=7 n-rows=1 -->
+ <object class="GtkGrid" id="grid18">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="column-spacing">6</property>
+ <child>
+ <object class="GtkButton" id="assign">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|assign|tooltip_text">Assign</property>
+ <property name="image">image7</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">6</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="update">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|update|tooltip_text">Update</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="image">image6</property>
+ </object>
+ <packing>
+ <property name="left-attach">5</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="material">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|material|tooltip_text">Material</property>
+ <property name="image">image5</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="material-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|material">Changes the coloring of the selected 3D object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">4</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="texture">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|texture|tooltip_text">Textures</property>
+ <property name="image">image4</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="texture-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|texture">Sets the properties of the surface texture for the selected 3D object. This feature is only available after you apply a surface texture to the selected object. To quickly apply a surface texture, open the Gallery, hold down Shift+Ctrl, and then drag an image onto the selected 3D object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="light">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|light|tooltip_text">Illumination</property>
+ <property name="image">image3</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="light-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|light">Define the light source for the selected 3D object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="representation">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|representation|tooltip_text">Shading</property>
+ <property name="image">image2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="representation-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|representation">Sets the shading and shadow options for the selected 3D object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="geometry">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="docking3deffects|geometry|tooltip_text">Geometry</property>
+ <property name="image">image1</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="geometry-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|geometry">Adjusts the shape of the selected 3D object. You can only modify the shape of a 3D object that was created by converting a 2D object. To convert a 2D object to 3D, select the object, right-click, and then choose Convert - To 3D, or Convert - To 3D Rotation Object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="docking3deffects|extended_tip|Docking3DEffects">Specifies the properties of 3D object(s) in the current document or converts a 2D object to 3D.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroupLabel">
+ <widgets>
+ <widget name="diagonalft"/>
+ <widget name="scaleddepthft"/>
+ <widget name="angleft"/>
+ <widget name="depthft"/>
+ <widget name="label6"/>
+ <widget name="label7"/>
+ <widget name="label8"/>
+ <widget name="box3"/>
+ <widget name="label14"/>
+ <widget name="label15"/>
+ <widget name="label17"/>
+ <widget name="label18"/>
+ <widget name="label20"/>
+ <widget name="label22"/>
+ <widget name="label23"/>
+ <widget name="label24"/>
+ <widget name="label25"/>
+ <widget name="label26"/>
+ <widget name="label27"/>
+ <widget name="label29"/>
+ <widget name="label30"/>
+ <widget name="label31"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroupWidget">
+ <widgets>
+ <widget name="diagonal"/>
+ <widget name="scaleddepth"/>
+ <widget name="angle"/>
+ <widget name="depth"/>
+ <widget name="veri"/>
+ <widget name="hori"/>
+ <widget name="mode"/>
+ <widget name="slant"/>
+ <widget name="focal"/>
+ <widget name="distance"/>
+ <widget name="objcolor"/>
+ <widget name="illumcolor"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/dockingcolorreplace.ui b/svx/uiconfig/ui/dockingcolorreplace.ui
new file mode 100644
index 000000000..50724d15c
--- /dev/null
+++ b/svx/uiconfig/ui/dockingcolorreplace.ui
@@ -0,0 +1,572 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">99</property>
+ <property name="value">10</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">99</property>
+ <property name="value">10</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">99</property>
+ <property name="value">10</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="upper">99</property>
+ <property name="value">10</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkBox" id="DockingColorReplace">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">24</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="colorgrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="dockingcolorreplace|label2">Source color</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="dockingcolorreplace|label3">Tolerance</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="dockingcolorreplace|label4">Replace with...</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cbx2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="cbx2-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" comments="This string is used by the eyedropper dialog to denote a color in an image that will be replaced by another color." context="dockingcolorreplace|cbx2-atkobject">Source Color 2</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|cbx2">Select this checkbox to replace the current Source color with the color that you specify in the Replace with box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cbx3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="cbx3-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" comments="This string is used by the eyedropper dialog to denote a color in an image that will be replaced by another color." context="dockingcolorreplace|cbx3-atkobject">Source Color 3</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|cbx3">Select this checkbox to replace the current Source color with the color that you specify in the Replace with box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cbx4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="cbx4-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" comments="This string is used by the eyedropper dialog to denote a color in an image that will be replaced by another color." context="dockingcolorreplace|cbx4-atkobject">Source Color 4</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|cbx4">Select this checkbox to replace the current Source color with the color that you specify in the Replace with box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cbx1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="cbx1-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" comments="This string is used by the eyedropper dialog to denote a color in an image that will be replaced by another color." context="dockingcolorreplace|cbx1-atkobject">Source Color 1</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|cbx1">Select this checkbox to replace the current Source color with the color that you specify in the Replace with box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cbx5">
+ <property name="label" translatable="yes" context="dockingcolorreplace|cbx5">Tr_ansparency</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <accessibility>
+ <relation type="label-for" target="color5"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="cbx5-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|cbx5">Replaces transparent areas in the current image with the color that you select.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ <property name="width">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="tol1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="tol1-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="dockingcolorreplace|tol1-atkobject">Tolerance 1</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|tol1">Set the tolerance for replacing a source color in the source image. To replace colors that are similar to the color that you selected, enter a low value. To replace a wider range of colors, enter a higher value.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="tol2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="text">10</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="value">10</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="tol2-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="dockingcolorreplace|tol2-atkobject">Tolerance 2</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|tol2">Set the tolerance for replacing a source color in the source image. To replace colors that are similar to the color that you selected, enter a low value. To replace a wider range of colors, enter a higher value.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="tol3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="text">10</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="value">10</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="tol3-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="dockingcolorreplace|tol3-atkobject">Tolerance 3</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|tol3">Set the tolerance for replacing a source color in the source image. To replace colors that are similar to the color that you selected, enter a low value. To replace a wider range of colors, enter a higher value.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="tol4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="text">10</property>
+ <property name="adjustment">adjustment4</property>
+ <property name="value">10</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="tol4-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="dockingcolorreplace|tol4-atkobject">Tolerance 4</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|tol4">Set the tolerance for replacing a source color in the source image. To replace colors that are similar to the color that you selected, enter a low value. To replace a wider range of colors, enter a higher value.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="color1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="hexpand">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="color1-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="dockingcolorreplace|color1-atkobject">Replace with 1</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|color1">Lists the available replacement colors. To modify the current list of colors, deselect the image, choose Format - Area, and then click the Colors tab.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="color2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="hexpand">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="color2-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="dockingcolorreplace|color2-atkobject">Replace with 2</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|color2">Lists the available replacement colors. To modify the current list of colors, deselect the image, choose Format - Area, and then click the Colors tab.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="color3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="hexpand">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="color3-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="dockingcolorreplace|color3-atkobject">Replace with 3</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|color3">Lists the available replacement colors. To modify the current list of colors, deselect the image, choose Format - Area, and then click the Colors tab.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="color4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="hexpand">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="color4-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="dockingcolorreplace|color4-atkobject">Replace with 4</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|color4">Lists the available replacement colors. To modify the current list of colors, deselect the image, choose Format - Area, and then click the Colors tab.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="color5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <accessibility>
+ <relation type="labelled-by" target="cbx5"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="color5-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|color5">Select the color to replace the transparent areas in the current image.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkDrawingArea" id="qset1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkDrawingArea" id="qset2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkDrawingArea" id="qset3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkDrawingArea" id="qset4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="dockingcolorreplace|label1">Colors</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="column_spacing">24</property>
+ <child>
+ <object class="GtkButton" id="replace">
+ <property name="label" translatable="yes" context="dockingcolorreplace|replace">_Replace</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="replace-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|replace">Replaces the selected source colors in the current image with the colors that you specify in the Replace with boxes.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="toolgrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkToolbar" id="toolbar">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="show_arrow">False</property>
+ <child>
+ <object class="GtkToggleToolButton" id="pipette">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="dockingcolorreplace|pipette">Pipette</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">res/sc10350.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="pipette-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|pipette">Select one of the four source color boxes. Move the mouse pointer over the selected image, and then click the color that you want to replace.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="toolcolorborder">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="toolcolor">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="toolgrid-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|toolgrid">Displays the color in the selected image that directly underlies the current mouse pointer position. This features only works if the Color Replacer tool is selected.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="DockingColorReplace-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingcolorreplace|extended_tip|DockingColorReplace">Opens the Color Replacer dialog, where you can replace colors in bitmap and meta file graphics.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/dockingcolorwindow.ui b/svx/uiconfig/ui/dockingcolorwindow.ui
new file mode 100644
index 000000000..572082076
--- /dev/null
+++ b/svx/uiconfig/ui/dockingcolorwindow.ui
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="DockingColorWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkScrolledWindow" id="valuesetwin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="valueset">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/dockingfontwork.ui b/svx/uiconfig/ui/dockingfontwork.ui
new file mode 100644
index 000000000..0088ebfbf
--- /dev/null
+++ b/svx/uiconfig/ui/dockingfontwork.ui
@@ -0,0 +1,593 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="lower">-50000</property>
+ <property name="upper">50000</property>
+ <property name="step-increment">0.10</property>
+ <property name="page-increment">1</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="lower">-50000</property>
+ <property name="upper">50000</property>
+ <property name="step-increment">0.10</property>
+ <property name="page-increment">1</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="lower">-50000</property>
+ <property name="upper">50000</property>
+ <property name="step-increment">0.10</property>
+ <property name="page-increment">1</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="lower">-50000</property>
+ <property name="upper">50000</property>
+ <property name="step-increment">0.10</property>
+ <property name="page-increment">1</property>
+ </object>
+ <object class="GtkBox" id="DockingFontwork">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <!-- n-columns=1 n-rows=8 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">12</property>
+ <child>
+ <object class="GtkToolbar" id="style">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="show-arrow">False</property>
+ <child>
+ <object class="GtkRadioToolButton" id="off">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|off|tooltip_text">Off</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw01.png</property>
+ <property name="active">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="off-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|off">Removes baseline formatting.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="toolbutton1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="rotate">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|rotate|tooltip_text">Rotate</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw02.png</property>
+ <property name="group">off</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="rotate-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|rotate">Uses the top or the bottom edge of the selected object as the text baseline.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="upright">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|upright|tooltip_text">Upright</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw03.png</property>
+ <property name="group">off</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="upright-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|upright">Uses the top or the bottom edge of the selected object as the text baseline and preserves the original vertical alignment of the individual characters.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="hori">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|hori|tooltip_text">Slant Horizontal</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw04.png</property>
+ <property name="group">off</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="hori-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|hori">Horizontally slants the characters in the text object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="vert">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|vert|tooltip_text">Slant Vertical</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw05.png</property>
+ <property name="group">off</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="vert-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|vert">Vertically slants the characters in the text object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="adjust">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="show-arrow">False</property>
+ <child>
+ <object class="GtkToggleToolButton" id="orientation">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|orientation|tooltip_text">Orientation</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw06.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="orientation-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|orientation">Reverses the text flow direction, and flips the text horizontally or vertically. To use this command, you must first apply a different baseline to the text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="toolbutton2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="left">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|left|tooltip_text">Align Left</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw07.png</property>
+ <property name="group">autosize</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="left-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|left">Aligns the text to the left end of the text baseline.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="center">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|center|tooltip_text">Center</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw08.png</property>
+ <property name="group">autosize</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="center-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|center">Centers the text on the text baseline.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="right">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|right|tooltip_text">Align Right</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw09.png</property>
+ <property name="group">autosize</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="right-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|right">Aligns the text to the right end of the text baseline.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="autosize">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|autosize|tooltip_text">AutoSize Text</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw010.png</property>
+ <property name="active">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="autosize-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|autosize">Resizes the text to fit the length of the text baseline.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">center</property>
+ <property name="icon-name">svx/res/fw020.png</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="distance">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|distance|tooltip_text">Distance</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="digits">2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="distance-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|distance">Enter the amount of space that you want to leave between the text baseline and the base of the individual characters.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">center</property>
+ <property name="icon-name">svx/res/fw021.png</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="indent">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|indent|tooltip_text">Indent</property>
+ <property name="text">0.00</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="digits">2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="indent-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|indent">Enter the amount of space to leave between the beginning of the text baseline, and the beginning of the text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="shadow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="show-arrow">False</property>
+ <child>
+ <object class="GtkToggleToolButton" id="contour">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|contour|tooltip_text">Contour</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw011.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="contour-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|contour">Shows or hides the text baseline, or the edges of the selected object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="textcontour">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|textcontour|tooltip_text">Text Contour</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw012.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="textcontour-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|textcontour">Shows or hides the borders of the individual characters in the text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="toolbutton3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="noshadow">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|noshadow|tooltip_text">No Shadow</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw013.png</property>
+ <property name="active">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="noshadow-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|noshadow">Removes the shadow effects that you applied to the text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="vertical">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|vertical|tooltip_text">Vertical</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw014.png</property>
+ <property name="group">noshadow</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="vertical-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|vertical">Adds a shadow to the text in the selected object. Click this button, and then enter the dimensions of the shadow in the Distance X and the Distance Y boxes.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioToolButton" id="slant">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|slant|tooltip_text">Slant</property>
+ <property name="use-underline">True</property>
+ <property name="icon-name">svx/res/fw015.png</property>
+ <property name="group">noshadow</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="slant-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|slant">Adds a slant shadow to the text in the selected object. Click this button, and then enter the dimensions of the shadow in the Distance X and the Distance Y boxes.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid" id="grid4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkImage" id="shadowx">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">center</property>
+ <property name="icon-name">svx/res/fw018.png</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="distancex">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|distancex|tooltip_text">Distance X</property>
+ <property name="text">0.00</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="digits">2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="distancex-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|distancex">Enter the horizontal distance between the text characters and the edge of the shadow.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid" id="grid5">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">end</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkImage" id="shadowy">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">center</property>
+ <property name="icon-name">svx/res/fw019.png</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="distancey">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|distancey|tooltip_text">Distance Y</property>
+ <property name="text">0.00</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment4</property>
+ <property name="digits">2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="distancey-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|distancey">Enter the vertical distance between the text characters and the edge of the shadow.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="color">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes" context="dockingfontwork|color|tooltip_text">Shadow Color</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="draw-indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="color-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|color">Select a color for the text shadow.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">7</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="DockingFontwork-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="dockingfontwork|extended_tip|DockingFontwork">Simple tool for putting text along a curve without any fancy effects.</property>
+ </object>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup1">
+ <widgets>
+ <widget name="distance"/>
+ <widget name="indent"/>
+ <widget name="distancex"/>
+ <widget name="distancey"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/docrecoverybrokendialog.ui b/svx/uiconfig/ui/docrecoverybrokendialog.ui
new file mode 100644
index 000000000..de84d2f3a
--- /dev/null
+++ b/svx/uiconfig/ui/docrecoverybrokendialog.ui
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="DocRecoveryBrokenDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="docrecoverybrokendialog|DocRecoveryBrokenDialog">%PRODUCTNAME Document Recovery</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="docrecoverybrokendialog|save">_Save</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes" context="docrecoverybrokendialog|label1">The automatic recovery process was interrupted.
+
+The documents listed below will be saved in the folder noted below if you click 'Save'. Click 'Cancel' to close the wizard without saving the documents.</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">100</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="docrecoverybrokendialog|label3">Documents:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">filelist</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="filelist">
+ <property name="height_request">100</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">False</property>
+ <property name="search_column">0</property>
+ <property name="show_expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection2"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="docrecoverybrokendialog|label4">_Save to:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">savedir</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkEntry" id="savedir">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="change">
+ <property name="label" translatable="yes" context="docrecoverybrokendialog|change">Chan_ge...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/docrecoveryprogressdialog.ui b/svx/uiconfig/ui/docrecoveryprogressdialog.ui
new file mode 100644
index 000000000..14e1672c5
--- /dev/null
+++ b/svx/uiconfig/ui/docrecoveryprogressdialog.ui
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="DocRecoveryProgressDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="docrecoveryprogressdialog|DocRecoveryProgressDialog">Documents Are Being Saved</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="docrecoveryprogressdialog|label2">Progress of saving:</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="progress">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/docrecoveryrecoverdialog.ui b/svx/uiconfig/ui/docrecoveryrecoverdialog.ui
new file mode 100644
index 000000000..11bcc05a1
--- /dev/null
+++ b/svx/uiconfig/ui/docrecoveryrecoverdialog.ui
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name image -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name image2 -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name text1 -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="DocRecoveryRecoverDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="docrecoveryrecoverdialog|DocRecoveryRecoverDialog">%PRODUCTNAME %PRODUCTVERSION Document Recovery</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="docrecoveryrecoverdialog|cancel">_Discard</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="next">
+ <property name="label" translatable="yes" context="docrecoveryrecoverdialog|next">_Start</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">10</property>
+ <child>
+ <object class="GtkLabel" id="desc">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="docrecoveryrecoverdialog|desc">%PRODUCTNAME will attempt to recover the state of the files you were working on before it crashed. Click 'Start' to begin the process, or click 'Discard' to cancel the recovery.</property>
+ <property name="wrap">True</property>
+ <property name="width_chars">70</property>
+ <property name="max_width_chars">70</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="progress">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="docrecoveryrecoverdialog|label2">Status of recovered documents:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">filelist</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="filelist">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers_clickable">False</property>
+ <property name="headers_visible">True</property>
+ <property name="enable-search">False</property>
+ <property name="search-column">1</property>
+ <property name="show_expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection2"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn0">
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext9"/>
+ <attributes>
+ <attribute name="pixbuf">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <property name="title" translatable="yes" context="docrecoveryrecoverdialog|nameft">Document Name</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/>
+ <attributes>
+ <attribute name="pixbuf">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+ <property name="title" translatable="yes" context="docrecoveryrecoverdialog|statusft">Status</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext3"/>
+ <attributes>
+ <attribute name="text">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="101">next</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/docrecoverysavedialog.ui b/svx/uiconfig/ui/docrecoverysavedialog.ui
new file mode 100644
index 000000000..509b4f087
--- /dev/null
+++ b/svx/uiconfig/ui/docrecoverysavedialog.ui
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name image -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="DocRecoverySaveDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="docrecoverysavedialog|DocRecoverySaveDialog">%PRODUCTNAME %PRODUCTVERSION Document Recovery</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="bgrid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">12</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">24</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="docrecoverysavedialog|label1">Due to an error, %PRODUCTNAME crashed. All the files you were working on will now be saved. The next time %PRODUCTNAME is launched, your files will be recovered automatically.</property>
+ <property name="wrap">True</property>
+ <property name="width_chars">70</property>
+ <property name="max_width_chars">70</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="docrecoverysavedialog|label2">The following files will be recovered:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">filelist</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="filelist">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">False</property>
+ <property name="search_column">0</property>
+ <property name="show_expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection2"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext1"/>
+ <attributes>
+ <attribute name="pixbuf">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/extrustiondepthdialog.ui b/svx/uiconfig/ui/extrustiondepthdialog.ui
new file mode 100644
index 000000000..5d21c89c7
--- /dev/null
+++ b/svx/uiconfig/ui/extrustiondepthdialog.ui
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">338.666</property>
+ <property name="step_increment">0.1</property>
+ <property name="page_increment">1</property>
+ </object>
+ <object class="GtkDialog" id="ExtrustionDepthDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="extrustiondepthdialog|ExtrustionDepthDialog">Extrusion Depth</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkSpinButton" id="depth">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="extrustiondepthdialog|label1">_Value</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">depth</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="extrustiondepthdialog|label2">Depth</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="ExtrustionDepthDialog-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extrustiondepthdialog|extended_tip|ExtrustionDepthDialog">Enter an extrusion depth.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/fileexporteddialog.ui b/svx/uiconfig/ui/fileexporteddialog.ui
new file mode 100644
index 000000000..aa1f3d4ae
--- /dev/null
+++ b/svx/uiconfig/ui/fileexporteddialog.ui
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="FileExportedDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="fileexporteddialog|FileExportedDialog">File Exported</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="close">
+ <property name="label" translatable="yes" context="stock">_Close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="fileexporteddialog|openfolder">Open Containing _Folder</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="Filelabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="fileexporteddialog|Filelabel">File Name</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">80</property>
+ <property name="lines">2</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-7">close</action-widget>
+ <action-widget response="-5">ok</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/fillctrlbox.ui b/svx/uiconfig/ui/fillctrlbox.ui
new file mode 100644
index 000000000..6cbff1268
--- /dev/null
+++ b/svx/uiconfig/ui/fillctrlbox.ui
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkListStore" id="fillctrlboxattrmodel">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ <!-- column-name image -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name surface -->
+ <column type="CairoSurface"/>
+ </columns>
+ </object>
+ <object class="GtkBox" id="FillCtrlBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBoxText" id="type">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="margin-end">6</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkToolbar" id="color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:FillColor">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <style>
+ <class name="small-button"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="attr">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="entry_text_column">0</property>
+ <property name="model">fillctrlboxattrmodel</property>
+ <property name="id_column">1</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext5"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext6"/>
+ <attributes>
+ <attribute name="surface">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/filtermenu.ui b/svx/uiconfig/ui/filtermenu.ui
new file mode 100644
index 000000000..b8e90213f
--- /dev/null
+++ b/svx/uiconfig/ui/filtermenu.ui
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="delete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="filtermenu|delete">_Delete</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="edit">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="filtermenu|edit">_Edit</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="isnull">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="filtermenu|isnull">_Is Null</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="isnotnull">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="filtermenu|isnotnull">I_s not Null</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/filternavigator.ui b/svx/uiconfig/ui/filternavigator.ui
new file mode 100644
index 000000000..99297b0dc
--- /dev/null
+++ b/svx/uiconfig/ui/filternavigator.ui
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name expander -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ <!-- column-name weight -->
+ <column type="gint"/>
+ </columns>
+ </object>
+ <object class="GtkBox" id="FilterNavigator">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="treeview">
+ <property name="width_request">-1</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers_visible">False</property>
+ <property name="reorderable">True</property>
+ <property name="search_column">1</property>
+ <property name="enable_tree_lines">True</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/>
+ <attributes>
+ <attribute name="pixbuf">0</attribute>
+ </attributes>
+ </child>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2">
+ <property name="editable">True</property>
+ </object>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/findbox.ui b/svx/uiconfig/ui/findbox.ui
new file mode 100644
index 000000000..b01c199de
--- /dev/null
+++ b/svx/uiconfig/ui/findbox.ui
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="FindBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBoxText" id="find">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="has_entry">True</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="truncate-multiline">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/findreplacedialog-mobile.ui b/svx/uiconfig/ui/findreplacedialog-mobile.ui
new file mode 100644
index 000000000..3e025317f
--- /dev/null
+++ b/svx/uiconfig/ui/findreplacedialog-mobile.ui
@@ -0,0 +1,1117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="FindReplaceDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="findreplacedialog-mobile|FindReplaceDialog">Find &amp; Replace</property>
+ <property name="resizable">False</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox3">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area3">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="close">
+ <property name="label" translatable="yes" context="stock">_Close</property>
+ <property name="visible">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="parent _container_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkFrame" id="searchframe">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="search_grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid12">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="margin-end">6</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkComboBoxText" id="searchterm">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="has_entry">True</property>
+ <child internal-child="entry">
+ <object class="GtkEntry" id="combobox-entry">
+ <property name="can_focus">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="searchlist">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="height">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|label4">_Find:</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="searchdesc">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ <property name="wrap">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="searchlabel">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ <property name="wrap">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="searchlabel-atkobject">
+ <property name="AtkObject::accessible-role" translatable="no">static</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="checkboxrow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="matchcase">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|matchcase">Ma_tch case</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="searchformatted">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|searchformatted">For_matted display</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkCheckButton" id="wholewords">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|wholewords">Whole wor_ds only</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="entirecells">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|entirecells">_Entire cells</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="allsheets">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|allsheets">All _sheets</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|label1">_Search For</property>
+ <property name="use_underline">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="replaceframe">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="replace_grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid11">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="margin-end">6</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkComboBoxText" id="replaceterm">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="has_entry">True</property>
+ <child internal-child="entry">
+ <object class="GtkEntry" id="combobox-entry2">
+ <property name="can_focus">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="replacelist">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="height">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|label5">Re_place:</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="replacedesc">
+ <property name="width_request">1</property>
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ <property name="wrap">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|label2">Re_place With</property>
+ <property name="use_underline">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="controlbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="margin-start">10</property>
+ <property name="margin-end">10</property>
+ <property name="margin_top">15</property>
+ <property name="spacing">12</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkButton" id="searchall">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|searchall">Find _All</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="backsearch">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|backsearch">Find Pre_vious</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="search">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|search">Find Ne_xt</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="replace">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|replace">_Replace</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="replaceall">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|replaceall">Replace A_ll</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="hide-box">
+ <property name="visible">False</property>
+ <child>
+ <object class="GtkFrame" id="componentframe">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="margin_top">6</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkBox" id="component_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">18</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="can_focus">False</property>
+ <property name="label" translatable="no">Component Label</property>
+ <property name="use_underline">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkButton" id="component1">
+ <property name="label" translatable="no">component button 1</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="component2">
+ <property name="label" translatable="no">component button 2</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label6">
+ <property name="can_focus">False</property>
+ <property name="label" translatable="no">Component Label</property>
+ <property name="use_underline">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="optionsgrid">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">10</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkExpander" id="OptionsExpander">
+ <property name="visible">False</property>
+ <property name="can_focus">True</property>
+ <property name="margin-start">6</property>
+ <property name="margin_top">1</property>
+ <property name="margin_bottom">1</property>
+ <property name="hexpand">True</property>
+ <property name="resize_toplevel">True</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="column_homogeneous">True</property>
+ <child>
+ <object class="GtkCheckButton" id="selection">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|selection">C_urrent selection only</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="regexp">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|regexp">Re_gular expressions</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButtonBox" id="buttonbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">12</property>
+ <property name="layout_style">spread</property>
+ <child>
+ <object class="GtkButton" id="attributes">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|attributes">Attribut_es...</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="format">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|format">For_mat...</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="noformat">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|noformat">_No Format</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="layout">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|layout">Search for st_yles</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="includediacritics">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|includediacritics">Diac_ritic-sensitive</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="includekashida">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|includekashida">_Kashida-sensitive</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="matchcharwidth">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|matchcharwidth">Match character _width</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="similarity">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|similarity">S_imilarity search</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="similaritybtn">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|similaritybtn">Similarities...</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="soundslike">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|soundslike">Sounds like (_Japanese)</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="soundslikebtn">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|soundslikebtn">Sounds...</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkCheckButton" id="wildcard">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|wildcard">Wil_dcards</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="notes">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|notes">_Comments</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="replace_backwards">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|replace_backwards">Replace _backwards</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="calcgrid">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="column_homogeneous">True</property>
+ <child>
+ <object class="GtkBox" id="searchin_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">15</property>
+ <child>
+ <object class="GtkLabel" id="searchinlabel">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|searchinlabel">Search i_n:</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="calcsearchin">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <items>
+ <item translatable="yes" context="findreplacedialog-mobile|calcsearchin">Formulas</item>
+ <item translatable="yes" context="findreplacedialog-mobile|calcsearchin">Values</item>
+ <item translatable="yes" context="findreplacedialog-mobile|calcsearchin">Notes</item>
+ </items>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="searchdirection_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">4</property>
+ <property name="spacing">15</property>
+ <child>
+ <object class="GtkLabel" id="searchdir">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|searchdir">Direction:</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="rows"/>
+ <relation type="label-for" target="cols"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">15</property>
+ <child>
+ <object class="GtkRadioButton" id="rows">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|rows">Ro_ws</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="searchdir"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="cols">
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|cols">Colum_ns</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">rows</property>
+ <accessibility>
+ <relation type="labelled-by" target="searchdir"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="findreplacedialog-mobile|label3">Other _options</property>
+ <property name="use_underline">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">help</action-widget>
+ <action-widget response="-7">close</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup2">
+ <property name="ignore_hidden">True</property>
+ <widgets>
+ <widget name="label4"/>
+ <widget name="label5"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/findreplacedialog.ui b/svx/uiconfig/ui/findreplacedialog.ui
new file mode 100644
index 000000000..4c1e9d2bc
--- /dev/null
+++ b/svx/uiconfig/ui/findreplacedialog.ui
@@ -0,0 +1,1233 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="FindReplaceDialog">
+ <property name="can-focus">False</property>
+ <property name="border-width">6</property>
+ <property name="title" translatable="yes" context="findreplacedialog|FindReplaceDialog">Find and Replace</property>
+ <property name="resizable">False</property>
+ <property name="default-width">0</property>
+ <property name="default-height">0</property>
+ <property name="type-hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox3">
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area3">
+ <property name="can-focus">False</property>
+ <property name="layout-style">end</property>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="close">
+ <property name="label" translatable="yes" context="stock">_Close</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="parent _container_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkFrame" id="searchframe">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=2 n-rows=5 -->
+ <object class="GtkGrid" id="search_grid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="hexpand">True</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <!-- n-columns=1 n-rows=2 -->
+ <object class="GtkGrid" id="grid12">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">center</property>
+ <property name="margin-end">6</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkComboBoxText" id="searchterm">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="has-entry">True</property>
+ <child internal-child="entry">
+ <object class="GtkEntry" id="combobox-entry">
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="searchterm-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|searchterm">Enter the text that you want to find, or select a previous search from the list.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="searchlist">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="hexpand">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="searchlist-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|searchlist">Enter the text that you want to find, or select a previous search from the list.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ <property name="height">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="label" translatable="yes" context="findreplacedialog|label4">_Find:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">searchterm</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="searchdesc">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="hexpand">True</property>
+ <property name="wrap">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="searchlabel">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="hexpand">True</property>
+ <property name="wrap">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="searchlabel-atkobject">
+ <property name="AtkObject::accessible-role" translatable="no">static</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="checkboxrow">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="matchcase">
+ <property name="label" translatable="yes" context="findreplacedialog|matchcase">Ma_tch case</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="matchcase-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|matchcase">Distinguishes between uppercase and lowercase characters.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="searchformatted">
+ <property name="label" translatable="yes" context="findreplacedialog|searchformatted">For_matted display</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="searchformatted-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|searchformatted">Includes number formatting characters in the search.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box6">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkCheckButton" id="wholewords">
+ <property name="label" translatable="yes" context="findreplacedialog|wholewords">Whole wor_ds only</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="wholewords-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|wholewords">Searches for whole words or cells that are identical to the search text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="entirecells">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="label" translatable="yes" context="findreplacedialog|entirecells">_Entire cells</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="allsheets">
+ <property name="label" translatable="yes" context="findreplacedialog|allsheets">All _sheets</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="findreplacedialog|label1">Search For</property>
+ <property name="use-underline">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="replaceframe">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <!-- n-columns=2 n-rows=3 -->
+ <object class="GtkGrid" id="replace_grid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <!-- n-columns=1 n-rows=2 -->
+ <object class="GtkGrid" id="grid11">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">center</property>
+ <property name="margin-end">6</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkComboBoxText" id="replaceterm">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="has-entry">True</property>
+ <child internal-child="entry">
+ <object class="GtkEntry" id="combobox-entry2">
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="replaceterm-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|replaceterm">Enter the replacement text, or select a recent replacement text or style from the list.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="replacelist">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="hexpand">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="replacelist-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|replacelist">Enter the replacement text, or select a recent replacement text or style from the list.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ <property name="height">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="label" translatable="yes" context="findreplacedialog|label5">Re_place:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">replaceterm</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="replacedesc">
+ <property name="width-request">1</property>
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="hexpand">True</property>
+ <property name="wrap">True</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="findreplacedialog|label2">Re_place With</property>
+ <property name="use-underline">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="controlbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">center</property>
+ <property name="margin-start">10</property>
+ <property name="margin-end">10</property>
+ <property name="margin-top">15</property>
+ <property name="spacing">12</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkButton" id="searchall">
+ <property name="label" translatable="yes" context="findreplacedialog|searchall">Find _All</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="searchall-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|searchall">Finds and selects all instances of the text or the format that you are searching for in the document (only in Writer and Calc documents).</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="backsearch">
+ <property name="label" translatable="yes" context="findreplacedialog|backsearch">Find Pre_vious</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="backsearch-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|backsearch">Finds and selects the previous occurrence of the text or format that you are searching for in the document.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="search">
+ <property name="label" translatable="yes" context="findreplacedialog|search">Find Ne_xt</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="can-default">True</property>
+ <property name="has-default">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="search-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|search">Finds and selects the next occurrence of the text or format that you are searching for in the document.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="replace">
+ <property name="label" translatable="yes" context="findreplacedialog|replace">_Replace</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="replace-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|replace">Replaces the selected text or format that you searched for, and then searches for the next occurrence.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="replaceall">
+ <property name="label" translatable="yes" context="findreplacedialog|replaceall">Replace A_ll</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="replaceall-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|replaceall">Replaces all of the occurrences of the text or format that you want to replace.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="componentframe">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="margin-top">6</property>
+ <property name="hexpand">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <object class="GtkBox" id="component_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="can-focus">False</property>
+ <property name="label" translatable="no">Component Label</property>
+ <property name="use-underline">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkButton" id="component1">
+ <property name="label" translatable="no">component button 1</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="no-show-all">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="component2">
+ <property name="label" translatable="no">component button 2</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="no-show-all">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label6">
+ <property name="can-focus">False</property>
+ <property name="label" translatable="no">Component Label</property>
+ <property name="use-underline">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="optionsgrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-top">10</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkExpander" id="OptionsExpander">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="margin-start">6</property>
+ <property name="margin-top">1</property>
+ <property name="margin-bottom">1</property>
+ <property name="hexpand">True</property>
+ <property name="resize-toplevel">True</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <!-- n-columns=2 n-rows=6 -->
+ <object class="GtkGrid" id="grid4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <property name="column-homogeneous">True</property>
+ <child>
+ <object class="GtkCheckButton" id="selection">
+ <property name="label" translatable="yes" context="findreplacedialog|selection">C_urrent selection only</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="selection-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|selection">Searches only the selected text or cells.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="regexp">
+ <property name="label" translatable="yes" context="findreplacedialog|regexp">Re_gular expressions</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButtonBox" id="buttonbox1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">12</property>
+ <property name="layout-style">spread</property>
+ <child>
+ <object class="GtkButton" id="attributes">
+ <property name="label" translatable="yes" context="findreplacedialog|attributes">Attribut_es...</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="format">
+ <property name="label" translatable="yes" context="findreplacedialog|format">For_mat...</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="format-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|format">Finds specific text formatting features, such as font types, font effects, and text flow characteristics.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="noformat">
+ <property name="label" translatable="yes" context="findreplacedialog|noformat">_No Format</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">5</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="layout">
+ <property name="label" translatable="yes" context="findreplacedialog|layout">Search for st_yles</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="layout-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|layout">Searches for text formatted with the style that you specify. Select this checkbox, and then select a style from the Find list. To specify a replacement style, select a style from the Replace list.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="includediacritics">
+ <property name="label" translatable="yes" context="findreplacedialog|includediacritics">Diacritic-_sensitive</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="includekashida">
+ <property name="label" translatable="yes" context="findreplacedialog|includekashida">_Kashida-sensitive</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="matchcharwidth">
+ <property name="label" translatable="yes" context="findreplacedialog|matchcharwidth">Match character _width</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="matchcharwidth-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|matchcharwidth">Distinguishes between half-width and full-width character forms.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="similarity">
+ <property name="label" translatable="yes" context="findreplacedialog|similarity">S_imilarity search</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="similarity-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|similarity">Find terms that are similar to the Find text. Select this checkbox, and then click the Similarities button to define the similarity options.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="similaritybtn">
+ <property name="label" translatable="yes" context="findreplacedialog|similaritybtn">Similarities...</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="no-show-all">True</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="similaritybtn-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|similaritybtn">Set the options for the similarity search.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box5">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="soundslike">
+ <property name="label" translatable="yes" context="findreplacedialog|soundslike">Sounds like (_Japanese)</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="soundslike-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|soundslike">Lets you specify the search options for similar notation used in Japanese text. Select this checkbox, and then click the Sounds button to specify the search options.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="soundslikebtn">
+ <property name="label" translatable="yes" context="findreplacedialog|soundslikebtn">Sounds...</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="no-show-all">True</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="soundslikebtn-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|soundslikebtn">Sets the search options for similar notation used in Japanese text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box7">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkCheckButton" id="wildcard">
+ <property name="label" translatable="yes" context="findreplacedialog|wildcard">Wil_dcards</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="notes">
+ <property name="label" translatable="yes" context="findreplacedialog|notes">Comme_nts</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="notes-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|notes">In Writer, you can select to include the comment texts in your searches.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="replace_backwards">
+ <property name="label" translatable="yes" context="findreplacedialog|replace_backwards">Replace _backwards</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="replace_backwards-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|replace_backwards">Search starts at the current cursor position and goes backwards to the beginning of the file.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid" id="calcgrid">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <property name="column-homogeneous">True</property>
+ <child>
+ <object class="GtkBox" id="searchin_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">15</property>
+ <child>
+ <object class="GtkLabel" id="searchinlabel">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="label" translatable="yes" context="findreplacedialog|searchinlabel">Search i_n:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">calcsearchin</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="calcsearchin">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <items>
+ <item translatable="yes" context="findreplacedialog|calcsearchin">Formulas</item>
+ <item translatable="yes" context="findreplacedialog|calcsearchin">Values</item>
+ <item translatable="yes" context="findreplacedialog|calcsearchin">Comments</item>
+ </items>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="searchdirection_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">4</property>
+ <property name="spacing">15</property>
+ <child>
+ <object class="GtkLabel" id="searchdir">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="label" translatable="yes" context="findreplacedialog|searchdir">Direction:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">rows</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="rows"/>
+ <relation type="label-for" target="cols"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">15</property>
+ <child>
+ <object class="GtkRadioButton" id="rows">
+ <property name="label" translatable="yes" context="findreplacedialog|rows">Ro_ws</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <property name="active">True</property>
+ <property name="draw-indicator">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="searchdir"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="cols">
+ <property name="label" translatable="yes" context="findreplacedialog|cols">Colum_ns</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">rows</property>
+ <accessibility>
+ <relation type="labelled-by" target="searchdir"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="findreplacedialog|label3">Other _options</property>
+ <property name="use-underline">True</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="label3-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|label3">Shows more or fewer search options. Click this label again to hide the extended search options.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">help</action-widget>
+ <action-widget response="-7">close</action-widget>
+ </action-widgets>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="FindReplaceDialog-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="findreplacedialog|extended_tip|FindReplaceDialog">Finds or replaces text or formats in the current document.</property>
+ </object>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup2">
+ <property name="ignore-hidden">True</property>
+ <widgets>
+ <widget name="label4"/>
+ <widget name="label5"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/floatingareastyle.ui b/svx/uiconfig/ui/floatingareastyle.ui
new file mode 100644
index 000000000..2c9579e1f
--- /dev/null
+++ b/svx/uiconfig/ui/floatingareastyle.ui
@@ -0,0 +1,346 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">359</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="step_increment">5</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">100</property>
+ <property name="step_increment">5</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="upper">100</property>
+ <property name="step_increment">5</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment5">
+ <property name="upper">100</property>
+ <property name="step_increment">5</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment6">
+ <property name="upper">100</property>
+ <property name="step_increment">5</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkPopover" id="FloatingAreaStyle">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="row_spacing">12</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="anglegrid">
+ <property name="no-show-all">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="floatingareastyle|label1">_Angle:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">angle</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">12</property>
+ <property name="column_homogeneous">True</property>
+ <child>
+ <object class="GtkSpinButton" id="angle">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="floatingareastyle|angle|tooltip_text">Specify the angle of rotation for the gradient shading style.</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkToolbar" id="lefttoolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id="left">
+ <property name="visible">True</property>
+ <property name="tooltip_text" translatable="yes" context="floatingareastyle|left|tooltip_text">Rotate counterclockwise by 45 degrees.</property>
+ <property name="icon_name">svx/res/symphony/rotate_left.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="righttoolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id="right">
+ <property name="visible">True</property>
+ <property name="tooltip_text" translatable="yes" context="floatingareastyle|right|tooltip_text">Rotate clockwise by 45 degrees.</property>
+ <property name="icon_name">svx/res/symphony/rotate_right.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="floatingareastyle|label4">_Start value:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">start</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="floatingareastyle|label5">_End value:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="start">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="floatingareastyle|start|tooltip_text">Enter a transparency value for the beginning point of the gradient, where 0% is fully opaque and 100% is fully transparent.</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment4</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="end">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="floatingareastyle|end|tooltip_text">Enter a transparency value for the endpoint of the gradient, where 0% is fully opaque and 100% is fully transparent.</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment5</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="floatingareastyle|label6">_Border:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">border</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="border">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="floatingareastyle|border|tooltip_text">Specify the border value of gradient transparency.</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment6</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="centergrid">
+ <property name="no-show-all">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="floatingareastyle|label2">Center _X:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">centerx</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="floatingareastyle|label3">Center _Y:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">centery</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="centerx">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="floatingareastyle|centerx|tooltip_text">Specify the horizontal offset percentage from the center for the gradient shading style. 50% is the horizontal center.</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment2</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="centery">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="floatingareastyle|centery|tooltip_text">Specify the vertical offset percentage from the center for the gradient shading style. 50% is the vertical center.</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment3</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkSizeGroup">
+ <widgets>
+ <widget name="angle"/>
+ <widget name="start"/>
+ <widget name="end"/>
+ <widget name="border"/>
+ <widget name="centerx"/>
+ <widget name="centery"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/floatingcontour.ui b/svx/uiconfig/ui/floatingcontour.ui
new file mode 100644
index 000000000..c9e00822b
--- /dev/null
+++ b/svx/uiconfig/ui/floatingcontour.ui
@@ -0,0 +1,532 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">99</property>
+ <property name="value">10</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkDialog" id="FloatingContour">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="floatingcontour|FloatingContour">Contour Editor</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkStatusbar" id="statusbar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">end</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkDrawingArea" id="statuscolor">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes" context="floatingcontour|statuscolor">Color</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="separator1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="statussize">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label">100%</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="separator4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="statuspos">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label">100%</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="mainbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkToolbar" id="toolbar">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id="TBI_APPLY">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_APPLY">Apply</property>
+ <property name="icon_name">svx/res/cd01.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_APPLY-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_APPLY">Applies the contour to the selected object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separatortoolitem1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_WORKPLACE">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_WORKPLACE">Workspace</property>
+ <property name="icon_name">svx/res/cd02.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_WORKPLACE-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_WORKPLACE">Deletes the custom contour. Click here, and then click in the preview area.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separatortoolitem2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_SELECT">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_SELECT">Select</property>
+ <property name="icon_name">svx/res/cd05.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_SELECT-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_SELECT">Changes to selection mode, so that you can select the contour.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_RECT">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_RECT">Rectangle</property>
+ <property name="icon_name">svx/res/cd06.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_RECT-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_RECT">Draws a rectangular contour where you drag in the object preview. To draw a square, hold down Shift while you drag.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_CIRCLE">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_CIRCLE">Ellipse</property>
+ <property name="icon_name">svx/res/cd07.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_CIRCLE-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_CIRCLE">Draws an oval contour where you drag in the object preview.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_POLY">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_POLY">Polygon</property>
+ <property name="icon_name">svx/res/cd08.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_POLY-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_POLY">Draws a closed contour consisting of straight line segments. Click where you want to start the polygon, and drag to draw a line segment. Click again to define the end of the line segment, and continue clicking to define the remaining line segments of the polygon. Double-click to finish drawing the polygon. To constrain the polygon to angles of 45 degree, hold down Shift when you click.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separatortoolitem3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_POLYEDIT">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_POLYEDIT">Edit Points</property>
+ <property name="icon_name">svx/res/cd015.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_POLYEDIT-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_POLYEDIT">Lets you change the shape of the contour. Click here, and then drag the handles of the contour.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_POLYMOVE">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_POLYMOVE">Move Points</property>
+ <property name="icon_name">svx/res/cd016.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_POLYMOVE-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_POLYMOVE">Lets you drag the handles of the contour to change the shape of the contour.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_POLYINSERT">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_POLYINSERT">Insert Points</property>
+ <property name="icon_name">svx/res/cd017.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_POLYINSERT-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_POLYINSERT">Inserts a handle that you can drag to change the shape of the contour. Click here, and then click on the contour outline.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_POLYDELETE">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_POLYDELETE">Delete Points</property>
+ <property name="icon_name">svx/res/cd018.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_POLYDELETE-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_POLYDELETE">Removes a point from the contour outline. Click here, and then click the point that you want to delete.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separatortoolitem4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_AUTOCONTOUR">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_AUTOCONTOUR">AutoContour</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">svx/res/cd025.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_AUTOCONTOUR-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_AUTOCONTOUR">Automatically draws a contour around the object that you can edit.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separatortoolitem5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_UNDO">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_UNDO">Undo </property>
+ <property name="icon_name">svx/res/cd020.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_UNDO-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_UNDO">Reverses the last action.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_REDO">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_REDO">Redo</property>
+ <property name="icon_name">svx/res/cd021.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_REDO-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_REDO">Reverses the action of the last Undo command.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_PIPETTE">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="floatingcontour|TBI_PIPETTE">Pipette</property>
+ <property name="icon_name">svx/res/cd026.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_PIPETTE-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|TBI_PIPETTE">Selects the parts of the bitmap that are the same color. Click here, and then click a color in the bitmap. To increase the color range that is selected, increase the value in the Tolerance box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="floatingcontour|spinbutton|tooltip_text">Color Tolerance</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="spinbutton-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|spinbutton">Enter the color tolerance for the Color Replacer as a percentage. To increase the color range that the Color Replacer selects, enter a high percentage.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="container-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|container">Displays a preview of the contour.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="FloatingContour-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="floatingcontour|extended_tip|FloatingContour">Changes the contour of the selected object. The contour is used when determining the text wrap options for the object.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/floatingframeborder.ui b/svx/uiconfig/ui/floatingframeborder.ui
new file mode 100644
index 000000000..e86cf1c0a
--- /dev/null
+++ b/svx/uiconfig/ui/floatingframeborder.ui
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkPopover" id="FloatingFrameBorder">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="border-width">5</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="valuesetwin">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">never</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="valueset">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/floatinglineend.ui b/svx/uiconfig/ui/floatinglineend.ui
new file mode 100644
index 000000000..a83a2eb5c
--- /dev/null
+++ b/svx/uiconfig/ui/floatinglineend.ui
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkPopover" id="FloatingLineEnd">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="valuesetwin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="valueset">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/floatinglineproperty.ui b/svx/uiconfig/ui/floatinglineproperty.ui
new file mode 100644
index 000000000..d47e10b36
--- /dev/null
+++ b/svx/uiconfig/ui/floatinglineproperty.ui
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkPopover" id="FloatingLineProperty">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="valuesetwin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="lineset">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="floatinglineproperty|label1">Custom Line Width:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">spin</property>
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">500</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/floatinglinestyle.ui b/svx/uiconfig/ui/floatinglinestyle.ui
new file mode 100644
index 000000000..fcecff19e
--- /dev/null
+++ b/svx/uiconfig/ui/floatinglinestyle.ui
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkPopover" id="FloatingLineStyle">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="valuesetwin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="valueset">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/floatingundoredo.ui b/svx/uiconfig/ui/floatingundoredo.ui
new file mode 100644
index 000000000..1d3104f96
--- /dev/null
+++ b/svx/uiconfig/ui/floatingundoredo.ui
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkPopover" id="FloatingUndoRedo">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <child>
+ <object class="GtkTreeView" id="treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">False</property>
+ <property name="enable_search">False</property>
+ <property name="search_column">0</property>
+ <property name="show_expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection1"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/fontnamebox.ui b/svx/uiconfig/ui/fontnamebox.ui
new file mode 100644
index 000000000..db4dbf2dc
--- /dev/null
+++ b/svx/uiconfig/ui/fontnamebox.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="FontNameBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBoxText" id="fontnamecombobox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="has_entry">True</property>
+ <property name="popup_fixed_width">False</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="truncate-multiline">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/fontsizebox.ui b/svx/uiconfig/ui/fontsizebox.ui
new file mode 100644
index 000000000..ff1625704
--- /dev/null
+++ b/svx/uiconfig/ui/fontsizebox.ui
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="FontSizeBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBoxText" id="fontsizecombobox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="has_entry">True</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="truncate-multiline">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/fontworkalignmentcontrol.ui b/svx/uiconfig/ui/fontworkalignmentcontrol.ui
new file mode 100644
index 000000000..2a8e1c828
--- /dev/null
+++ b/svx/uiconfig/ui/fontworkalignmentcontrol.ui
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/fontworkalignleft_16.png</property>
+ </object>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/fontworkaligncentered_16.png</property>
+ </object>
+ <object class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/fontworkalignright_16.png</property>
+ </object>
+ <object class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/fontworkalignstretch_16.png</property>
+ </object>
+ <object class="GtkPopover" id="FontworkAlignmentControl">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="left">
+ <property name="label" translatable="yes" context="fontworkalignmentcontrol|RID_SVXSTR_ALIGN_LEFT">Align _Left</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image1</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="center">
+ <property name="label" translatable="yes" context="fontworkalignmentcontrol|RID_SVXSTR_ALIGN_CENTER">_Center</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image2</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">left</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="right">
+ <property name="label" translatable="yes" context="fontworkalignmentcontrol|RID_SVXSTR_ALIGN_RIGHT">Align _Right</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image3</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">left</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="stretch">
+ <property name="label" translatable="yes" context="fontworkalignmentcontrol|RID_SVXSTR_ALIGN_STRETCH">S_tretch Justify</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image5</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">left</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/fontworkcharacterspacingcontrol.ui b/svx/uiconfig/ui/fontworkcharacterspacingcontrol.ui
new file mode 100644
index 000000000..9f0492820
--- /dev/null
+++ b/svx/uiconfig/ui/fontworkcharacterspacingcontrol.ui
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkPopover" id="FontworkCharacterSpacingControl">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="border-width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=7 -->
+ <object class="GtkGrid" id="container">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row-spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="verytight">
+ <property name="label" translatable="yes" context="fontworkcharacterspacingcontrol|RID_SVXSTR_CHARS_SPACING_VERY_TIGHT">_Very Tight</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">normal</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="tight">
+ <property name="label" translatable="yes" context="fontworkcharacterspacingcontrol|RID_SVXSTR_CHARS_SPACING_TIGHT">_Tight</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">normal</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="normal">
+ <property name="label" translatable="yes" context="fontworkcharacterspacingcontrol|RID_SVXSTR_CHARS_SPACING_NORMAL">_Normal</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="active">True</property>
+ <property name="draw-indicator">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="loose">
+ <property name="label" translatable="yes" context="fontworkcharacterspacingcontrol|RID_SVXSTR_CHARS_SPACING_LOOSE">_Loose</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">normal</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="veryloose">
+ <property name="label" translatable="yes" context="fontworkcharacterspacingcontrol|RID_SVXSTR_CHARS_SPACING_VERY_LOOSE">Very _Loose</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">normal</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="custom">
+ <property name="label" translatable="yes" context="fontworkcharacterspacingcontrol|RID_SVXSTR_CHARS_SPACING_CUSTOM">_Custom...</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ <property name="group">normal</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="kernpairs">
+ <property name="label" translatable="yes" context="fontworkcharacterspacingcontrol|RID_SVXSTR_CHARS_SPACING_KERN_PAIRS">_Kern Character Pairs</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">6</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/fontworkgallerydialog.ui b/svx/uiconfig/ui/fontworkgallerydialog.ui
new file mode 100644
index 000000000..54fabdb5c
--- /dev/null
+++ b/svx/uiconfig/ui/fontworkgallerydialog.ui
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name expander -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="FontworkGalleryDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="fontworkgallerydialog|FontworkGalleryDialog">Fontwork Gallery</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="fontworkgallerydialog|label1">Select a Fontwork style:</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkIconView" id="ctlFavoriteswin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="margin">6</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="pixbuf-column">0</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/fontworkspacingdialog.ui b/svx/uiconfig/ui/fontworkspacingdialog.ui
new file mode 100644
index 000000000..137a8be9a
--- /dev/null
+++ b/svx/uiconfig/ui/fontworkspacingdialog.ui
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">500</property>
+ <property name="value">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkDialog" id="FontworkSpacingDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="fontworkspacingdialog|FontworkSpacingDialog">Fontwork Character Spacing</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="fontworkspacingdialog|label2">_Value:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">entry</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment1</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/formdatamenu.ui b/svx/uiconfig/ui/formdatamenu.ui
new file mode 100644
index 000000000..a24fa9ed2
--- /dev/null
+++ b/svx/uiconfig/ui/formdatamenu.ui
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="additem">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formdatamenu|additem">Add Item</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="addelement">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formdatamenu|addelement">Add Element</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="addattribute">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formdatamenu|addattribute">Add Attribute</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="edit">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formdatamenu|edit">Edit</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formdatamenu|delete">Delete</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/formfielddialog.ui b/svx/uiconfig/ui/formfielddialog.ui
new file mode 100644
index 000000000..370e30db7
--- /dev/null
+++ b/svx/uiconfig/ui/formfielddialog.ui
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="FormFieldDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">utility</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers_visible">False</property>
+ <property name="reorderable">True</property>
+ <property name="search_column">0</property>
+ <property name="show_expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="Macro Library List-selection2"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+ <property name="resizable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/formlinkwarndialog.ui b/svx/uiconfig/ui/formlinkwarndialog.ui
new file mode 100644
index 000000000..b7f169e12
--- /dev/null
+++ b/svx/uiconfig/ui/formlinkwarndialog.ui
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="FormLinkWarnDialog">
+ <property name="can_focus">False</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="text" translatable="yes" context="formlinkwarndialog|FormLinkWarnDialog">This instance is linked with the form.</property>
+ <property name="secondary_text" translatable="yes" context="formlinkwarndialog|FormLinkWarnDialog">The changes you make to this instance will be lost when the form is reloaded.
+
+How do you want to proceed?</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="formlinkwarndialog|ok">_Edit</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/formnavigator.ui b/svx/uiconfig/ui/formnavigator.ui
new file mode 100644
index 000000000..f47da690e
--- /dev/null
+++ b/svx/uiconfig/ui/formnavigator.ui
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name expander -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ <!-- column-name weight -->
+ <column type="gint"/>
+ <!-- column-name sensitive -->
+ <column type="gboolean"/>
+ </columns>
+ </object>
+ <object class="GtkBox" id="FormNavigator">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="treeview">
+ <property name="width_request">-1</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers_visible">False</property>
+ <property name="reorderable">True</property>
+ <property name="search_column">1</property>
+ <property name="enable_tree_lines">True</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/>
+ <attributes>
+ <attribute name="sensitive">4</attribute>
+ <attribute name="pixbuf">0</attribute>
+ </attributes>
+ </child>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2">
+ <property name="editable">True</property>
+ </object>
+ <attributes>
+ <attribute name="sensitive">4</attribute>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/formnavimenu.ui b/svx/uiconfig/ui/formnavimenu.ui
new file mode 100644
index 000000000..ee2d44311
--- /dev/null
+++ b/svx/uiconfig/ui/formnavimenu.ui
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="new">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|new">_New</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="submenu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="change">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|change">Replace with</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="changemenu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="cut">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|cut">Cu_t</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="copy">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|copy">_Copy</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="paste">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|paste">_Paste</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|delete">_Delete</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="taborder">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|taborder">Tab Order...</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="rename">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|rename">_Rename</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="props">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|props">Propert_ies</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="designmode">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|designmode">Open in Design Mode</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="controlfocus">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="formnavimenu|controlfocus">Automatic Control Focus</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/formpropertydialog.ui b/svx/uiconfig/ui/formpropertydialog.ui
new file mode 100644
index 000000000..cae48fc6c
--- /dev/null
+++ b/svx/uiconfig/ui/formpropertydialog.ui
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="FormPropertyDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="default_width">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/functionmenu.ui b/svx/uiconfig/ui/functionmenu.ui
new file mode 100644
index 000000000..91ffdcfbf
--- /dev/null
+++ b/svx/uiconfig/ui/functionmenu.ui
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkCheckMenuItem" id="avg">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="functionmenu|avg">Average</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="counta">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="functionmenu|counta">CountA</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="count">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="functionmenu|count">Count</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="max">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="functionmenu|max">Maximum</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="min">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="functionmenu|min">Minimum</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="sum">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="functionmenu|sum">Sum</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="selection">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="functionmenu|selection">Selection count</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="none">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="functionmenu|none">None</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/gallerymenu1.ui b/svx/uiconfig/ui/gallerymenu1.ui
new file mode 100644
index 000000000..5ecd56109
--- /dev/null
+++ b/svx/uiconfig/ui/gallerymenu1.ui
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="update">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu1|update">Update</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu1|delete">_Delete</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="rename">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu1|rename">_Rename</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="assign">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu1|assign">Assign _ID</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="properties">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu1|properties">Propert_ies...</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/gallerymenu2.ui b/svx/uiconfig/ui/gallerymenu2.ui
new file mode 100644
index 000000000..c78c57908
--- /dev/null
+++ b/svx/uiconfig/ui/gallerymenu2.ui
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="add">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu2|add">_Insert</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="background">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu2|background">Insert as Bac_kground</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="backgroundmenu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="preview">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu2|preview">_Preview</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="title">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu2|title">_Title</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu2|delete">_Delete</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="copy">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu2|copy">_Copy</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="paste">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="gallerymenu2|paste">_Paste</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/genericcheckdialog.ui b/svx/uiconfig/ui/genericcheckdialog.ui
new file mode 100644
index 000000000..232221c0a
--- /dev/null
+++ b/svx/uiconfig/ui/genericcheckdialog.ui
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="GenericCheckDialog">
+ <property name="width-request">850</property>
+ <property name="height-request">480</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border-width">6</property>
+ <property name="modal">True</property>
+ <property name="type-hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialogBox1">
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialogButtons">
+ <property name="can-focus">False</property>
+ <property name="layout-style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="can-default">True</property>
+ <property name="has-default">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkBox" id="checkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/genericcheckentry.ui b/svx/uiconfig/ui/genericcheckentry.ui
new file mode 100644
index 000000000..1b02ca13e
--- /dev/null
+++ b/svx/uiconfig/ui/genericcheckentry.ui
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="checkEntryBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">3</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="label-atkobject">
+ <property name="AtkObject::accessible-role">static</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="markButton">
+ <property name="label" translatable="yes" context="genericcheckentry|markButton">Mark</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="propertiesButton">
+ <property name="label" translatable="yes" context="genericcheckentry|propertiesButton">Properties</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/grafctrlbox.ui b/svx/uiconfig/ui/grafctrlbox.ui
new file mode 100644
index 000000000..c33e83cb2
--- /dev/null
+++ b/svx/uiconfig/ui/grafctrlbox.ui
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkBox" id="GrafCtrlBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkImage" id="image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon-name">missing-image</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinfield">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment1</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/grafmodebox.ui b/svx/uiconfig/ui/grafmodebox.ui
new file mode 100644
index 000000000..ef099da4b
--- /dev/null
+++ b/svx/uiconfig/ui/grafmodebox.ui
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="GrafModeBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBoxText" id="grafmode">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/headfootformatpage.ui b/svx/uiconfig/ui/headfootformatpage.ui
new file mode 100644
index 000000000..f54346756
--- /dev/null
+++ b/svx/uiconfig/ui/headfootformatpage.ui
@@ -0,0 +1,427 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">0.1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="lower">0.1</property>
+ <property name="upper">100</property>
+ <property name="value">0.5</property>
+ <property name="step_increment">0.1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">100</property>
+ <property name="step_increment">0.1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="upper">100</property>
+ <property name="step_increment">0.1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="HFFormatPage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkCheckButton" id="checkHeaderOn">
+ <property name="label" translatable="yes" context="headfootformatpage|checkHeaderOn">Hea_der on</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkFooterOn">
+ <property name="label" translatable="yes" context="headfootformatpage|checkFooterOn">_Footer on</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <child>
+ <object class="GtkCheckButton" id="checkSameLR">
+ <property name="label" translatable="yes" context="headfootformatpage|checkSameLR">Same _content on left and right pages</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkSameFP">
+ <property name="label" translatable="yes" context="headfootformatpage|checkSameFP">Same content on first page</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="labelLeftMarg">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes" context="headfootformatpage|labelLeftMarg">_Left margin:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">spinMargLeft</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinMargLeft">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">center</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="labelRightMarg">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes" context="headfootformatpage|labelRightMarg">R_ight margin:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">spinMargRight</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinMargRight">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">center</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="labelSpacing">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes" context="headfootformatpage|labelSpacing">_Spacing:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">spinSpacing</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinSpacing">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">center</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment4</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkDynSpacing">
+ <property name="label" translatable="yes" context="headfootformatpage|checkDynSpacing">Use d_ynamic spacing</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="labelHeight">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes" context="headfootformatpage|labelHeight">_Height:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">spinHeight</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinHeight">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">center</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkAutofit">
+ <property name="label" translatable="yes" context="headfootformatpage|checkAutofit">_AutoFit height</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">7</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButtonBox" id="buttonbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <property name="layout_style">start</property>
+ <child>
+ <object class="GtkButton" id="buttonMore">
+ <property name="label" translatable="yes" context="headfootformatpage|buttonMore">More...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="buttonEdit">
+ <property name="label" translatable="yes" context="headfootformatpage|buttonEdit">_Edit...</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">8</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkBox" id="box4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="labelHeaderFormat">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes" context="headfootformatpage|labelHeaderFormat">Header</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="labelFooterFormat">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes" context="headfootformatpage|labelFooterFormat">Footer</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="margin-start">6</property>
+ <child>
+ <object class="GtkDrawingArea" id="drawingareaPageHF">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup1">
+ <property name="ignore_hidden">True</property>
+ <widgets>
+ <widget name="spinMargLeft"/>
+ <widget name="spinMargRight"/>
+ <widget name="spinSpacing"/>
+ <widget name="spinHeight"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/imapdialog.ui b/svx/uiconfig/ui/imapdialog.ui
new file mode 100644
index 000000000..faea4d096
--- /dev/null
+++ b/svx/uiconfig/ui/imapdialog.ui
@@ -0,0 +1,629 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="ImapDialog">
+ <property name="can-focus">False</property>
+ <property name="border-width">6</property>
+ <property name="default-width">0</property>
+ <property name="default-height">0</property>
+ <property name="type-hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="layout-style">end</property>
+ <child>
+ <object class="GtkStatusbar" id="statusbar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">end</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="statusurl">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">100%</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="separator5">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="statuspos">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">100%</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="separator4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="statussize">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">100%</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="mainbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkToolbar" id="toolbar">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="no-show-all">True</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id="TBI_APPLY">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_APPLY">Apply</property>
+ <property name="icon-name">svx/res/id01.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_APPLY-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_APPLY">Applies the changes that you made to the image map.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_OPEN">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_OPEN">Open...</property>
+ <property name="icon-name">svx/res/id02.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_OPEN-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_OPEN">Loads an existing image map in the MAP-CERN, MAP-NCSA or SIP StarView ImageMap file format.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_SAVEAS">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_SAVEAS">Save...</property>
+ <property name="icon-name">svx/res/id03.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_SAVEAS-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_SAVEAS">Saves the image map in the MAP-CERN, MAP-NCSA or SIP StarView ImageMap file format.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_CLOSE">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_CLOSE">Close</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_SELECT">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_SELECT">Select</property>
+ <property name="icon-name">svx/res/id04.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_SELECT-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_SELECT">Selects a hotspot in the image map for editing.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_RECT">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_RECT">Rectangle</property>
+ <property name="icon-name">svx/res/id05.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_RECT-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_RECT">Draws a rectangular hotspot where you drag in the graphic. After, you can enter the Address and the Text for the hotspot, and then select the Frame where you want the URL to open.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_CIRCLE">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_CIRCLE">Ellipse</property>
+ <property name="icon-name">svx/res/id06.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_CIRCLE-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_CIRCLE">Draws an elliptical hotspot where you drag in the graphic. After, you can enter the Address and the Text for the hotspot, and then select the Frame where you want the URL to open.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_POLY">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_POLY">Polygon</property>
+ <property name="icon-name">svx/res/id07.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_POLY-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_POLY">Draws a polygonal hotspot in the graphic. Click this icon, drag in the graphic, and then click to define one side of the polygon. Move to where you want to place the end of the next side, and then click. Repeat until you have drawn all of the sides of the polygon. When you are finished, double-click to close the polygon. After, you can enter the Address and the Text for the hotspot, and then select the Frame where you want the URL to open.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_FREEPOLY">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_FREEPOLY">Freeform Polygon</property>
+ <property name="icon-name">svx/res/id08.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_FREEPOLY-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_FREEPOLY">Draws a hotspot that is based on a freeform polygon. Click this icon and move to where you want to draw the hotspot. Drag a freeform line and release to close the shape. After, you can enter the Address and the Text for the hotspot, and then select the Frame where you want the URL to open.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_POLYEDIT">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_POLYEDIT">Edit Points</property>
+ <property name="icon-name">svx/res/id030.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_POLYEDIT-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_POLYEDIT">Lets you change the shape of the selected hotspot by editing the anchor points.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_POLYMOVE">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_POLYMOVE">Move Points</property>
+ <property name="icon-name">svx/res/id031.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_POLYMOVE-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_POLYMOVE">Lets you move the individual anchor points of the selected hotspot.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_POLYINSERT">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_POLYINSERT">Insert Points</property>
+ <property name="icon-name">svx/res/id032.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_POLYINSERT-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_POLYINSERT">Adds an anchor point where you click on the outline of the hotspot.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_POLYDELETE">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_POLYDELETE">Delete Points</property>
+ <property name="icon-name">svx/res/id033.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_POLYDELETE-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_POLYDELETE">Deletes the selected anchor point.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_UNDO">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_UNDO">Undo </property>
+ <property name="icon-name">svx/res/id040.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_REDO">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_REDO">Redo</property>
+ <property name="icon-name">svx/res/id041.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="TBI_ACTIVE">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_ACTIVE">Active</property>
+ <property name="icon-name">svx/res/id016.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_ACTIVE-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_ACTIVE">Disables or enables the hyperlink for the selected hotspot. A disabled hotspot is transparent.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_MACRO">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_MACRO">Macro...</property>
+ <property name="icon-name">svx/res/id018.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_MACRO-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_MACRO">Lets you assign a macro that runs when you click the selected hotspot in a browser.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="TBI_PROPERTY">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|TBI_PROPERTY">Properties...</property>
+ <property name="icon-name">svx/res/id019.png</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="TBI_PROPERTY-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|TBI_PROPERTY">Allows you to define the properties of the selected hotspot.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=2 n-rows=2 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="urlft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|urlft">Address:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">url</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=3 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="targetft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|targetft">Frame:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">target</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="text">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="text-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|text">Enter the text that you want to display when the mouse rests on the hotspot in a browser. This text is also used by assistive technologies</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="target">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="has-entry">True</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="textft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="imapdialog|textft">_Text Alternative:</property>
+ <property name="tooltip_text" translatable="yes" context="imapdialog|textft">Enter a short description of essential features of the image map for persons who do not see the image.</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">text</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="url">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="has-entry">True</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="url-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|url">Enter the URL for the file that you want to open when you click the selected hotspot.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">never</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="container">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="container-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|container">Displays the image map, so that you can click and edit the hotspots.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="ImapDialog-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="imapdialog|extended_tip|ImapDialog">Allows you to attach URLs to specific areas, called hotspots, on a graphic or a group of graphics. An image map is a group of one or more hotspots.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/imapmenu.ui b/svx/uiconfig/ui/imapmenu.ui
new file mode 100644
index 000000000..7789ef1ba
--- /dev/null
+++ b/svx/uiconfig/ui/imapmenu.ui
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="url">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="imapmenu|url">Description...</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="macro">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="imapmenu|macro">_Macro...</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckMenuItem" id="active">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="imapmenu|active">Active</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="arrange">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="imapmenu|arrange">_Arrange</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="front">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="imapmenu|front">Bring to Front</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="forward">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="imapmenu|forward">Bring _Forward</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="backward">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="imapmenu|backward">Send Back_ward</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="back">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="imapmenu|back">_Send to Back</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="selectall">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="imapmenu|selectall">Select _All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="imapmenu|delete">_Delete</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/inspectortextpanel.ui b/svx/uiconfig/ui/inspectortextpanel.ui
new file mode 100644
index 000000000..11be8d368
--- /dev/null
+++ b/svx/uiconfig/ui/inspectortextpanel.ui
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.4 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore">
+ <columns>
+ <!-- column-name text1 -->
+ <column type="gchararray"/>
+ <!-- column-name text2 -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ <!-- column-name weight1 -->
+ <column type="gint"/>
+ <!-- column-name weight2 -->
+ <column type="gint"/>
+ <!-- column-name sensitive1 -->
+ <column type="gboolean"/>
+ <!-- column-name sensitive2 -->
+ <column type="gboolean"/>
+ </columns>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="InspectorTextPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="listbox_fonts">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore</property>
+ <property name="search_column">0</property>
+ <property name="enable_tree_lines">True</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <property name="resizable">True</property>
+ <property name="title" translatable="yes" context="inspectortextpanel|property">Properties</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1">
+ <property name="ellipsize">end</property>
+ </object>
+ <attributes>
+ <attribute name="sensitive">5</attribute>
+ <attribute name="text">0</attribute>
+ <attribute name="weight">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <property name="resizable">True</property>
+ <property name="title" translatable="yes" context="inspectortextpanel|value">Values</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="sensitive">6</attribute>
+ <attribute name="text">1</attribute>
+ <attribute name="weight">4</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/labelbox.ui b/svx/uiconfig/ui/labelbox.ui
new file mode 100644
index 000000000..eca99a463
--- /dev/null
+++ b/svx/uiconfig/ui/labelbox.ui
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="LabelBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/lightingwindow.ui b/svx/uiconfig/ui/lightingwindow.ui
new file mode 100644
index 000000000..a662c6867
--- /dev/null
+++ b/svx/uiconfig/ui/lightingwindow.ui
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/brightlit_16.png</property>
+ </object>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/normallit_16.png</property>
+ </object>
+ <object class="GtkPopover" id="LightingWindow">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="valuesetwin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="valueset">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="bright">
+ <property name="label" translatable="yes" context="lightingwindow|RID_SVXSTR_BRIGHT">_Bright</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image1</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="normal">
+ <property name="label" translatable="yes" context="lightingwindow|RID_SVXSTR_NORMAL">_Normal</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image2</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">bright</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="dim">
+ <property name="label" translatable="yes" context="lightingwindow|RID_SVXSTR_DIM">_Dim</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image3</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">bright</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/dimlit_16.png</property>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/linkwarndialog.ui b/svx/uiconfig/ui/linkwarndialog.ui
new file mode 100644
index 000000000..19173b3e8
--- /dev/null
+++ b/svx/uiconfig/ui/linkwarndialog.ui
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="LinkWarnDialog">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="linkwarndialog|LinkWarnDialog">Confirm Linked Graphic</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="text" translatable="yes" context="linkwarndialog|LinkWarnDialog">The file %FILENAME will not be stored along with your document, but only referenced as a link.</property>
+ <property name="secondary_text" translatable="yes" context="linkwarndialog|LinkWarnDialog">This is dangerous if you move and/or rename the files. Do you want to embed the graphic instead?</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="linkwarndialog|ok">_Keep Link</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ <property name="non_homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="linkwarndialog|cancel">_Embed Graphic</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ <property name="non_homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="ask">
+ <property name="label" translatable="yes" context="linkwarndialog|ask">_Ask when linking a graphic</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/measurewidthbar.ui b/svx/uiconfig/ui/measurewidthbar.ui
new file mode 100644
index 000000000..e65be9eab
--- /dev/null
+++ b/svx/uiconfig/ui/measurewidthbar.ui
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkToolbar" id="measurewidth1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:TableCellBackgroundColor">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:SetBorderStyle">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:InsertFormula">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="measurewidth2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:InsertRowsBefore">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:InsertRowsAfter">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:InsertColumnsBefore">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:InsertColumnsAfter">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/medialine.ui b/svx/uiconfig/ui/medialine.ui
new file mode 100644
index 000000000..2e86fe853
--- /dev/null
+++ b/svx/uiconfig/ui/medialine.ui
@@ -0,0 +1,287 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="MediaWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkToolbar" id="playtoolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">center</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <child>
+ <object class="GtkToolButton" id="open">
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="no">Open</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02048.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="apply">
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="no">Apply</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02053.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separator1">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="play">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Play</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02049.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="pause">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Pause</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02050.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="stop">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Stop</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02051.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separator2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="loop">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Repeat</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02052.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="timetoolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <child>
+ <object class="GtkToolItem">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkScale" id="timeslider">
+ <property name="width_request">128</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="digits">2</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="timeedit">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="truncate-multiline">True</property>
+ <property name="xalign">0.5</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="mutetoolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <child>
+ <object class="GtkToggleToolButton" id="mute">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Mute</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02054.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkScale" id="volumeslider">
+ <property name="width_request">50</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="opacity">0.9882352941176471</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="draw_value">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="zoomtoolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <child>
+ <object class="GtkToolItem">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkComboBoxText" id="zoombox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="url">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="ellipsize">middle</property>
+ <property name="width_chars">10</property>
+ <property name="max_width_chars">10</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">10</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/mediaplayback.ui b/svx/uiconfig/ui/mediaplayback.ui
new file mode 100644
index 000000000..e5622dec6
--- /dev/null
+++ b/svx/uiconfig/ui/mediaplayback.ui
@@ -0,0 +1,272 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="MediaPlaybackPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="row_spacing">3</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="mediaplayback|label1">Playback:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">playtoolbox</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="label" translatable="yes" context="mediaplayback|label2">Seek:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">timeslider</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="label" translatable="yes" context="mediaplayback|label3">Volume:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">volumeslider</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScale" id="timeslider">
+ <property name="width_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="digits">2</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScale" id="volumeslider">
+ <property name="width_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="opacity">0.9882352941176471</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="zoombox">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="timeedit">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="editable">False</property>
+ <property name="truncate-multiline">True</property>
+ <property name="xalign">0.5</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="mutetoolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToggleToolButton" id="mute">
+ <property name="visible">True</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="label" translatable="no">Mute</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02054.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="playtoolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">center</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id="open">
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="no">Open</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02048.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="apply">
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="no">Apply</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02053.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separator1">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="play">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Play</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02049.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="pause">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Pause</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02050.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="stop">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Stop</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02051.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separator2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="loop">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Repeat</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02052.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/mediawindow.ui b/svx/uiconfig/ui/mediawindow.ui
new file mode 100644
index 000000000..012ed9de3
--- /dev/null
+++ b/svx/uiconfig/ui/mediawindow.ui
@@ -0,0 +1,272 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="MediaWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="url">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="ellipsize">middle</property>
+ <property name="width_chars">10</property>
+ <property name="max_width_chars">10</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkScale" id="timeslider">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="digits">2</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="timeedit">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="truncate-multiline">True</property>
+ <property name="xalign">0.5</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkToolbar" id="playtoolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">center</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <child>
+ <object class="GtkToolButton" id="open">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Open</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02048.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="apply">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Apply</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02053.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separator1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="play">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Play</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02049.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="pause">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Pause</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02050.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="stop">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Stop</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02051.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separator2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id="loop">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Repeat</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02052.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkToolbar" id="mutetoolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <child>
+ <object class="GtkToggleToolButton" id="mute">
+ <property name="visible">True</property>
+ <property name="label" translatable="no">Mute</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">avmedia/res/av02054.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScale" id="volumeslider">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="opacity">0.9882352941176471</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="zoombox">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">7</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/metricfieldbox.ui b/svx/uiconfig/ui/metricfieldbox.ui
new file mode 100644
index 000000000..d0f34d81e
--- /dev/null
+++ b/svx/uiconfig/ui/metricfieldbox.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkBox" id="MetricFieldBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkSpinButton" id="metricfield">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/namespacedialog.ui b/svx/uiconfig/ui/namespacedialog.ui
new file mode 100644
index 000000000..8f7e2c057
--- /dev/null
+++ b/svx/uiconfig/ui/namespacedialog.ui
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name text2 -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="NamespaceDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="namespacedialog|NamespaceDialog">Namespaces for Forms</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkButtonBox" id="buttonbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">start</property>
+ <child>
+ <object class="GtkButton" id="add">
+ <property name="label" translatable="yes" context="namespacedialog|add">_Add...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="add-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="namespacedialog|extended_tip|add">Adds a new namespace to the list.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="edit">
+ <property name="label" translatable="yes" context="namespacedialog|edit">_Edit...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="edit-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="namespacedialog|extended_tip|edit">Edits the selected namespace.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="delete">
+ <property name="label" translatable="yes" context="stock">_Delete</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="delete-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="namespacedialog|extended_tip|delete">Deletes the selected namespace.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="namespaces">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="search_column">0</property>
+ <property name="show_expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="Macro Library List-selection2"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="namespacedialog|prefix">Prefix</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn4">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="namespacedialog|url">URL</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer2"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="namespaces-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="namespacedialog|extended_tip|namespaces">Lists the currently defined namespaces for the form.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="namespacedialog|label1">Namespaces</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/navigationbar.ui b/svx/uiconfig/ui/navigationbar.ui
new file mode 100644
index 000000000..86fd015ab
--- /dev/null
+++ b/svx/uiconfig/ui/navigationbar.ui
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon-name">go-first</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon-name">media-skip-backward</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon-name">media-skip-forward</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon-name">go-last</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon-name">document-new</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkBox" id="NavigationBar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkLabel" id="recordtext">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entry-noframe">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="has_frame">False</property>
+ <property name="width_chars">4</property>
+ <property name="xalign">0.5</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="recordof">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">3</property>
+ <property name="margin-end">3</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="recordcount">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="first">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="focus_on_click">False</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes" context="navigationbar|first">First</property>
+ <property name="image">image1</property>
+ <property name="always_show_image">True</property>
+ <style>
+ <class name="small-button"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="prev">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="focus_on_click">False</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="tooltip_text" translatable="yes" context="navigationbar|prev">Previous</property>
+ <property name="image">image2</property>
+ <property name="always_show_image">True</property>
+ <style>
+ <class name="small-button"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="next">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="focus_on_click">False</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="tooltip_text" translatable="yes" context="navigationbar|next">Next</property>
+ <property name="image">image3</property>
+ <property name="always_show_image">True</property>
+ <style>
+ <class name="small-button"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="last">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="focus_on_click">False</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes" context="navigationbar|last">Last</property>
+ <property name="image">image4</property>
+ <property name="always_show_image">True</property>
+ <style>
+ <class name="small-button"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">9</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="new">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="focus_on_click">False</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes" context="navigationbar|new">New</property>
+ <property name="image">image5</property>
+ <property name="always_show_image">True</property>
+ <style>
+ <class name="small-button"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">10</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/numberingwindow.ui b/svx/uiconfig/ui/numberingwindow.ui
new file mode 100644
index 000000000..e303830fc
--- /dev/null
+++ b/svx/uiconfig/ui/numberingwindow.ui
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">missing-image</property>
+ </object>
+ <object class="GtkPopover" id="NumberingWindow">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="border-width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="valuesetwin">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">never</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="valueset">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="more">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="image">image1</property>
+ <property name="use-underline">True</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/optgridpage.ui b/svx/uiconfig/ui/optgridpage.ui
new file mode 100644
index 000000000..b7ccd7ea9
--- /dev/null
+++ b/svx/uiconfig/ui/optgridpage.ui
@@ -0,0 +1,756 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="lower">0.01</property>
+ <property name="upper">10</property>
+ <property name="value">1</property>
+ <property name="step_increment">0.2</property>
+ <property name="page_increment">1</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="lower">1</property>
+ <property name="upper">99</property>
+ <property name="value">2</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="lower">1</property>
+ <property name="upper">50</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="upper">180</property>
+ <property name="step_increment">5</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment5">
+ <property name="upper">90</property>
+ <property name="step_increment">5</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment6">
+ <property name="lower">0.01</property>
+ <property name="upper">10</property>
+ <property name="step_increment">0.2</property>
+ <property name="page_increment">1</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment7">
+ <property name="lower">1</property>
+ <property name="upper">99</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkBox" id="OptGridPage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkCheckButton" id="usegridsnap">
+ <property name="label" translatable="yes" context="optgridpage|usegridsnap">_Snap to grid</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="usegridsnap-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|usegridsnap">Specifies whether to move frames, drawing elements, and controls only between grid points.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="gridvisible">
+ <property name="label" translatable="yes" context="optgridpage|gridvisible">_Visible grid</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="gridvisible-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|gridvisible">Specifies whether to display the grid.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|label1">Grid</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkSpinButton" id="mtrflddrawx">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="digits">2</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="mtrflddrawx-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|mtrflddrawx">Defines the unit of measure for the spacing between grid points on the X-axis.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="mtrflddrawy">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment6</property>
+ <property name="digits">2</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="mtrflddrawy-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|mtrflddrawy">Defines the grid points spacing in the currently selected unit of measurement on the Y-axis.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="flddrawx">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|flddrawx">H_orizontal:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">mtrflddrawx</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="flddrawy">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|flddrawy">_Vertical:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">mtrflddrawy</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="synchronize">
+ <property name="label" translatable="yes" context="optgridpage|synchronize">Synchronize a_xes</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="margin-start">12</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="synchronize-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|synchronize">Specifies whether to change the current grid settings symmetrically.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|label2">Resolution</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkSpinButton" id="numflddivisionx">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="numflddivisionx-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|numflddivisionx">Specify the number of intermediate spaces between grid points on the X-axis.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|label4">space(s)</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkSpinButton" id="numflddivisiony">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment7</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="numflddivisiony-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|numflddivisiony">Specify the number of intermediate spaces between grid points on the Y-axis.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|label5">space(s)</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="divisionx">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|divisionx">Horizont_al:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">numflddivisionx</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="divisiony">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|divisiony">V_ertical:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">numflddivisiony</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|label3">Subdivision</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="snapframes">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkFrame" id="frame4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkCheckButton" id="snaphelplines">
+ <property name="label" translatable="yes" context="optgridpage|snaphelplines">To snap lines</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="snaphelplines-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|snaphelplines">Snaps the edge of a dragged object to the nearest snap line when you release the mouse.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="snapborder">
+ <property name="label" translatable="yes" context="optgridpage|snapborder">To the _page margins</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="snapborder-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|snapborder">Specifies whether to align the contour of the graphic object to the nearest page margin.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="snapframe">
+ <property name="label" translatable="yes" context="optgridpage|snapframe">To object _frame</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="snapframe-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|snapframe">Specifies whether to align the contour of the graphic object to the border of the nearest graphic object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="snappoints">
+ <property name="label" translatable="yes" context="optgridpage|snappoints">To obje_ct points</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="snappoints-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|snappoints">Specifies whether to align the contour of the graphic object to the points of the nearest graphic object.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkSpinButton" id="mtrfldsnaparea">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="mtrfldsnaparea-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|mtrfldsnaparea">Defines the snap distance between the mouse pointer and the object contour. Impress snaps to a snap point if the mouse pointer is nearer than the distance selected in the Snap range control.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|label7">_Snap range:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">mtrfldsnaparea</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|label6">Snap</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkCheckButton" id="ortho">
+ <property name="label" translatable="yes" context="optgridpage|ortho">_When creating or moving objects</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="ortho-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|ortho">Specifies that graphic objects are restricted vertically, horizontally or diagonally (45°) when creating or moving them.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="bigortho">
+ <property name="label" translatable="yes" context="optgridpage|bigortho">_Extend edges</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="bigortho-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|bigortho">Specifies that a square is created based on the longer side of a rectangle when the Shift key is pressed before you release the mouse button. This also applies to an ellipse (a circle will be created based on the longest diameter of the ellipse). When the Extend edges box is not marked, a square or a circle will be created based on the shorter side or diameter.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkSpinButton" id="mtrfldangle">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment4</property>
+ <property name="digits">2</property>
+ <accessibility>
+ <relation type="labelled-by" target="rotate"/>
+ </accessibility>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="mtrfldangle-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|mtrfldangle">Specifies that graphic objects can only be rotated within the rotation angle that you selected in the When rotating control.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="rotate">
+ <property name="label" translatable="yes" context="optgridpage|rotate">When ro_tating:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <accessibility>
+ <relation type="label-for" target="mtrfldangle"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="rotate-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|rotate">Specifies that graphic objects can only be rotated within the rotation angle that you selected in the When rotating control.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="mtrfldbezangle">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment5</property>
+ <property name="digits">2</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="mtrfldbezangle-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|mtrfldbezangle">Defines the angle for point reduction.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|label9">Point reducti_on:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">mtrfldbezangle</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="optgridpage|label8">Constrain Objects</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="OptGridPage-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|OptGridPage">Specifies the settings for the configurable grid on your document pages. This grid helps you determine the exact position of your objects. You can also set this grid in line with the "magnetic" snap grid.</property>
+ </object>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup1">
+ <property name="ignore_hidden">True</property>
+ <widgets>
+ <widget name="frame2"/>
+ <widget name="frame4"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup2">
+ <property name="ignore_hidden">True</property>
+ <widgets>
+ <widget name="frame3"/>
+ <widget name="frame5"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/paralinespacingcontrol.ui b/svx/uiconfig/ui/paralinespacingcontrol.ui
new file mode 100644
index 000000000..cf2347f92
--- /dev/null
+++ b/svx/uiconfig/ui/paralinespacingcontrol.ui
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkPopover" id="ParaLineSpacingControl">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkButton" id="spacing_1">
+ <property name="label" translatable="yes" context="paralinespacingcontrol|spacing_1">Spacing: 1</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">image_spacing_1</property>
+ <property name="relief">none</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="spacing_115">
+ <property name="label" translatable="yes" context="paralinespacingcontrol|spacing_115">Spacing: 1.15</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">image_spacing_115</property>
+ <property name="relief">none</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="spacing_15">
+ <property name="label" translatable="yes" context="paralinespacingcontrol|spacing_15">Spacing: 1.5</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">image_spacing_15</property>
+ <property name="relief">none</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="spacing_2">
+ <property name="label" translatable="yes" context="paralinespacingcontrol|spacing_2">Spacing: 2</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">image_spacing_2</property>
+ <property name="relief">none</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">6</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="paralinespacingcontrol|label3">Line Spacing:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">line_dist</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="line_dist">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <items>
+ <item translatable="yes" context="paralinespacingcontrol|line_dist">Single</item>
+ <item translatable="yes" context="paralinespacingcontrol|line_dist">1.15 Lines</item>
+ <item translatable="yes" context="paralinespacingcontrol|line_dist">1.5 Lines</item>
+ <item translatable="yes" context="paralinespacingcontrol|line_dist">Double</item>
+ <item translatable="yes" context="paralinespacingcontrol|line_dist">Proportional</item>
+ <item translatable="yes" context="paralinespacingcontrol|line_dist">At least</item>
+ <item translatable="yes" context="paralinespacingcontrol|line_dist">Leading</item>
+ <item translatable="yes" context="paralinespacingcontrol|line_dist">Fixed</item>
+ </items>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="value_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="paralinespacingcontrol|value_label">Value:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">grid1</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkSpinButton" id="percent_box">
+ <property name="can_focus">True</property>
+ <property name="no-show-all">True</property>
+ <property name="hexpand">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="metric_box">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="no-show-all">True</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="paralinespacingcontrol|label2">Custom Value</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="lower">6</property>
+ <property name="upper">65535</property>
+ <property name="value">100</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">50</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="lower">0.01</property>
+ <property name="upper">9999</property>
+ <property name="value">0.5</property>
+ <property name="step_increment">0.1</property>
+ <property name="page_increment">1</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">cmd/lc_spacepara1.png</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_115">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">cmd/lc_spacepara1.png</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_15">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">cmd/lc_spacepara15.png</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">cmd/lc_spacepara2.png</property>
+ <property name="icon_size">1</property>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/paralrspacing.ui b/svx/uiconfig/ui/paralrspacing.ui
new file mode 100644
index 000000000..c0a7667d5
--- /dev/null
+++ b/svx/uiconfig/ui/paralrspacing.ui
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkBox" id="ParaLRSpacingWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkBox" id="before">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon_name">svx/res/symphony/Indent4.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="beforetextindent">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="paralrspacing|beforetextindent|tooltip_text">Before Text Indent</property>
+ <property name="hexpand">True</property>
+ <property name="text">0</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="after">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon_name">svx/res/symphony/Indent3.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="aftertextindent">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="paralrspacing|aftertextindent|tooltip_text">After Text Indent</property>
+ <property name="hexpand">True</property>
+ <property name="text">0</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="firstline">
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image11">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon_name">svx/res/symphony/Indent2.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="firstlineindent">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="paralrspacing|firstlineindent|tooltip_text">First Line Indent</property>
+ <property name="hexpand">True</property>
+ <property name="text">0</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/paraulspacing.ui b/svx/uiconfig/ui/paraulspacing.ui
new file mode 100644
index 000000000..0908d4bff
--- /dev/null
+++ b/svx/uiconfig/ui/paraulspacing.ui
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkBox" id="ParaULSpacingWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">1</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkBox" id="above">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon_name">svx/res/symphony/spacing1.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="aboveparaspacing">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="paraulspacing|aboveparaspacing|tooltip_text">Above Paragraph Spacing</property>
+ <property name="hexpand">True</property>
+ <property name="text">0</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="below">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon_name">svx/res/symphony/spacing2.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="belowparaspacing">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="paraulspacing|belowparaspacing|tooltip_text">Below Paragraph Spacing</property>
+ <property name="hexpand">True</property>
+ <property name="text">0</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="truncate-multiline">True</property>
+ <property name="digits">2</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/passwd.ui b/svx/uiconfig/ui/passwd.ui
new file mode 100644
index 000000000..9e3495734
--- /dev/null
+++ b/svx/uiconfig/ui/passwd.ui
@@ -0,0 +1,286 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="PasswordDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="passwd|PasswordDialog">Change Password</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkLabel" id="oldpassL">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="passwd|oldpassL">_Password:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">oldpassEntry</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="oldpassEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="visibility">False</property>
+ <property name="activates_default">True</property>
+ <property name="input_purpose">password</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="oldpassEntry-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="passwd|extended_tip|oldpassEntry">Enter the current password for the selected library.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="oldpass">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="passwd|oldpass">Old Password</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkEntry" id="newpassEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="visibility">False</property>
+ <property name="activates_default">True</property>
+ <property name="input_purpose">password</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="newpassEntry-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="passwd|extended_tip|newpassEntry">Enter a new password for the selected library.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="confirmpassEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="visibility">False</property>
+ <property name="activates_default">True</property>
+ <property name="input_purpose">password</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="confirmpassEntry-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="passwd|extended_tip|confirmpassEntry">Reenter the new password for the selected library.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="passwd|label4">Pa_ssword:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">newpassEntry</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="passwd|label5">Confi_rm:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">confirmpassEntry</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="passwd|label2">New Password</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="PasswordDialog-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="passwd|extended_tip|PasswordDialog">Protects the selected library with a password.</property>
+ </object>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup1">
+ <widgets>
+ <widget name="oldpassL"/>
+ <widget name="label4"/>
+ <widget name="label5"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/presetmenu.ui b/svx/uiconfig/ui/presetmenu.ui
new file mode 100644
index 000000000..0d9f45a2f
--- /dev/null
+++ b/svx/uiconfig/ui/presetmenu.ui
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="rename">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="presetmenu|rename">Rename</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="presetmenu|delete">Delete</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/querydeletecontourdialog.ui b/svx/uiconfig/ui/querydeletecontourdialog.ui
new file mode 100644
index 000000000..b97449128
--- /dev/null
+++ b/svx/uiconfig/ui/querydeletecontourdialog.ui
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="QueryDeleteContourDialog">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="querydeletecontourdialog|QueryDeleteContourDialog">Delete the contour?</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="buttons">yes-no</property>
+ <property name="text" translatable="yes" context="querydeletecontourdialog|QueryDeleteContourDialog">Setting a new workspace will
+cause the contour to be deleted.</property>
+ <property name="secondary_text" translatable="yes" context="querydeletecontourdialog|QueryDeleteContourDialog">Are you sure you want to continue?</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area">
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/querydeleteobjectdialog.ui b/svx/uiconfig/ui/querydeleteobjectdialog.ui
new file mode 100644
index 000000000..9e41600a7
--- /dev/null
+++ b/svx/uiconfig/ui/querydeleteobjectdialog.ui
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="QueryDeleteObjectDialog">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="querydeleteobjectdialog|QueryDeleteObjectDialog">Delete this object?</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="buttons">yes-no</property>
+ <property name="text" translatable="yes" context="querydeleteobjectdialog|QueryDeleteObjectDialog">Do you really want to delete this object?</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox4">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area4">
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/querydeletethemedialog.ui b/svx/uiconfig/ui/querydeletethemedialog.ui
new file mode 100644
index 000000000..96fc041b7
--- /dev/null
+++ b/svx/uiconfig/ui/querydeletethemedialog.ui
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="QueryDeleteThemeDialog">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="querydeletethemedialog|QueryDeleteThemeDialog">Delete this theme?</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="buttons">yes-no</property>
+ <property name="text" translatable="yes" context="querydeletethemedialog|QueryDeleteThemeDialog">Do you really want to delete this theme?</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox2">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area2">
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/querymodifyimagemapchangesdialog.ui b/svx/uiconfig/ui/querymodifyimagemapchangesdialog.ui
new file mode 100644
index 000000000..661328481
--- /dev/null
+++ b/svx/uiconfig/ui/querymodifyimagemapchangesdialog.ui
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="QueryModifyImageMapChangesDialog">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="querymodifyimagemapchangesdialog|QueryModifyImageMapChangesDialog">Save ImageMap changes?</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="buttons">yes-no</property>
+ <property name="text" translatable="yes" context="querymodifyimagemapchangesdialog|QueryModifyImageMapChangesDialog">The ImageMap has been modified.</property>
+ <property name="secondary_text" translatable="yes" context="querymodifyimagemapchangesdialog|QueryModifyImageMapChangesDialog">Do you want to save the changes?</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox5">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area5">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/querynewcontourdialog.ui b/svx/uiconfig/ui/querynewcontourdialog.ui
new file mode 100644
index 000000000..cee1bd6c5
--- /dev/null
+++ b/svx/uiconfig/ui/querynewcontourdialog.ui
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="QueryNewContourDialog">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="querynewcontourdialog|QueryNewContourDialog">Create a new contour?</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="buttons">yes-no</property>
+ <property name="text" translatable="yes" context="querynewcontourdialog|QueryNewContourDialog">Do you want to create a new contour?</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area">
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/querysavecontchangesdialog.ui b/svx/uiconfig/ui/querysavecontchangesdialog.ui
new file mode 100644
index 000000000..200bb0cd0
--- /dev/null
+++ b/svx/uiconfig/ui/querysavecontchangesdialog.ui
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="QuerySaveContourChangesDialog">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="querysavecontchangesdialog|QuerySaveContourChangesDialog">Save contour changes?</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="buttons">yes-no</property>
+ <property name="text" translatable="yes" context="querysavecontchangesdialog|QuerySaveContourChangesDialog">The contour has been modified.</property>
+ <property name="secondary_text" translatable="yes" context="querysavecontchangesdialog|QuerySaveContourChangesDialog">Do you want to save the changes?</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/querysaveimagemapchangesdialog.ui b/svx/uiconfig/ui/querysaveimagemapchangesdialog.ui
new file mode 100644
index 000000000..58a068c78
--- /dev/null
+++ b/svx/uiconfig/ui/querysaveimagemapchangesdialog.ui
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="QuerySaveImageMapChangesDialog">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="querysaveimagemapchangesdialog|QuerySaveImageMapChangesDialog">Save ImageMap changes?</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="buttons">yes-no</property>
+ <property name="text" translatable="yes" context="querysaveimagemapchangesdialog|QuerySaveImageMapChangesDialog">The ImageMap has been modified.</property>
+ <property name="secondary_text" translatable="yes" context="querysaveimagemapchangesdialog|QuerySaveImageMapChangesDialog">Do you want to save the changes?</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox4">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area4">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/queryunlinkgraphicsdialog.ui b/svx/uiconfig/ui/queryunlinkgraphicsdialog.ui
new file mode 100644
index 000000000..20de39c32
--- /dev/null
+++ b/svx/uiconfig/ui/queryunlinkgraphicsdialog.ui
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="QueryUnlinkGraphicsDialog">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="queryunlinkgraphicsdialog|QueryUnlinkGraphicsDialog">Unlink the graphics?</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="buttons">yes-no</property>
+ <property name="text" translatable="yes" context="queryunlinkgraphicsdialog|QueryUnlinkGraphicsDialog">This graphic object is linked to the document.</property>
+ <property name="secondary_text" translatable="yes" context="queryunlinkgraphicsdialog|QueryUnlinkGraphicsDialog">Do you want to unlink the graphics in order to edit it?</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area">
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/redlinecontrol.ui b/svx/uiconfig/ui/redlinecontrol.ui
new file mode 100644
index 000000000..d09e3ffec
--- /dev/null
+++ b/svx/uiconfig/ui/redlinecontrol.ui
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkNotebook" id="tabcontrol">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="scrollable">True</property>
+ <property name="enable_popup">True</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="view">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="redlinecontrol|view">List</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="filter">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="redlinecontrol|filter">Filter</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/redlinefilterpage.ui b/svx/uiconfig/ui/redlinefilterpage.ui
new file mode 100644
index 000000000..5207c5b76
--- /dev/null
+++ b/svx/uiconfig/ui/redlinefilterpage.ui
@@ -0,0 +1,448 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">86400000</property>
+ <property name="step_increment">1000</property>
+ <property name="page_increment">60000</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">86400000</property>
+ <property name="step_increment">1000</property>
+ <property name="page_increment">60000</property>
+ </object>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">cmd/sc_timefield.png</property>
+ </object>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">cmd/sc_timefield.png</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="RedlineFilterPage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="date">
+ <property name="label" translatable="yes" context="redlinefilterpage|date">_Date:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="date-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|date">Filters the list of changes according to the date and the time that you specify.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="author">
+ <property name="label" translatable="yes" context="redlinefilterpage|author">_Author:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="author-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|author">Filters the list of changes according to the name of the author that you select from the list.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="comment">
+ <property name="label" translatable="yes" context="redlinefilterpage|comment">C_omment:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <accessibility>
+ <relation type="label-for" target="commentedit"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="comment-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|comment">Filters the comments of the changes according to the keyword(s) that you enter.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="commentedit">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="margin-start">24</property>
+ <property name="hexpand">True</property>
+ <property name="activates_default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="commentedit-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlinefilterpage|commentedit-atkobject">Comment</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|commentedit">Filters the comments of the changes according to the keyword(s) that you enter.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">9</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="range">
+ <property name="label" translatable="yes" context="redlinefilterpage|range">_Range:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="range-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|range">Filters the list of changes according to the range of cells that you specify. To select a range of cells in your sheet, click the Set Reference button (...).</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="actionlist">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">24</property>
+ <property name="hexpand">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="action"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="actionlist-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlinefilterpage|actionlist-atkobject">Action</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|actionlist">Filters the list of changes according to the type of change that you select in the Action box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="action">
+ <property name="label" translatable="yes" context="redlinefilterpage|action">A_ction:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="action-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|action">Filters the list of changes according to the type of change that you select in the Action box.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="authorlist">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">24</property>
+ <property name="hexpand">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="author"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="authorlist-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlinefilterpage|authorlist-atkobject">Author</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|authorlist">Filters the list of changes according to the name of the author that you select from the list.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">24</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="rangeedit">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates_default">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="range"/>
+ </accessibility>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="rangeedit-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlinefilterpage|rangeedit-atkobject">Range</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|rangeedit">Filters the list of changes according to the range of cells that you specify. To select a range of cells in your sheet, click the Set Reference button (...).</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="dotdotdot">
+ <property name="label">...</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes" context="redlinefilterpage|dotdotdot|tooltip_text">Set reference</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">24</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBoxText" id="datecond">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <items>
+ <item translatable="yes" context="redlinefilterpage|datecond">earlier than</item>
+ <item translatable="yes" context="redlinefilterpage|datecond">since</item>
+ <item translatable="yes" context="redlinefilterpage|datecond">equal to</item>
+ <item translatable="yes" context="redlinefilterpage|datecond">not equal to</item>
+ <item translatable="yes" context="redlinefilterpage|datecond">between</item>
+ <item translatable="yes" context="redlinefilterpage|datecond">since saving</item>
+ </items>
+ <accessibility>
+ <relation type="labelled-by" target="date"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="datecond-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlinefilterpage|datecond-atkobject">Date Condition</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|datecond">Filters the list of changes according to the date and the time that you specify.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="and">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="redlinefilterpage|and">a_nd</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="startdate">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="startdate-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlinefilterpage|startdate-atkobject">Start Date</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|startdate">Filters the list of changes according to the date and the time that you specify.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="starttime">
+ <property name="width_request">70</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="starttime-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlinefilterpage|starttime-atkobject">Start Time</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|starttime">Filters the list of changes according to the date and the time that you specify.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="startclock">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes" context="redlinefilterpage|startclock|tooltip_text">Set current time and date</property>
+ <property name="image">image1</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="enddate">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="enddate-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlinefilterpage|enddate-atkobject">End Date</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|enddate">Filters the list of changes according to the date and the time that you specify.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="endtime">
+ <property name="width_request">75</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates_default">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="endtime-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlinefilterpage|endtime-atkobject">End Time</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|endtime">Filters the list of changes according to the date and the time that you specify.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="endclock">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes" context="redlinefilterpage|endclock|tooltip_text">Set current time and date</property>
+ <property name="image">image2</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="RedlineFilterPage-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlinefilterpage|extended_tip|RedlineFilterPage">Filters the list of changes according to the date and the time that you specify.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/redlineviewpage.ui b/svx/uiconfig/ui/redlineviewpage.ui
new file mode 100644
index 000000000..ee49056c0
--- /dev/null
+++ b/svx/uiconfig/ui/redlineviewpage.ui
@@ -0,0 +1,366 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name text2 -->
+ <column type="gchararray"/>
+ <!-- column-name text3 -->
+ <column type="gchararray"/>
+ <!-- column-name text4 -->
+ <column type="gchararray"/>
+ <!-- column-name text5 -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ <!-- column-name textcolor -->
+ <column type="GdkRGBA"/>
+ </columns>
+ </object>
+ <object class="GtkTreeStore" id="liststore2">
+ <columns>
+ <!-- column-name image -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name text2 -->
+ <column type="gchararray"/>
+ <!-- column-name text3 -->
+ <column type="gchararray"/>
+ <!-- column-name text4 -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ <!-- column-name textcolor -->
+ <column type="GdkRGBA"/>
+ </columns>
+ </object>
+ <object class="GtkBox" id="RedlineViewPage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border-width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkTreeView" id="writerchanges">
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore2</property>
+ <property name="search-column">0</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="Macro Library List-selection2"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn00">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="redlineviewpage|action">Action</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext45"/>
+ <attributes>
+ <attribute name="pixbuf">0</attribute>
+ </attributes>
+ </child>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext25"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn20">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="redlineviewpage|author">Author</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer29"/>
+ <attributes>
+ <attribute name="text">2</attribute>
+ <attribute name="foreground-rgba">6</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn30">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="redlineviewpage|date">Date</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer39"/>
+ <attributes>
+ <attribute name="text">3</attribute>
+ <attribute name="foreground-rgba">6</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn40">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="redlineviewpage|comment">Comment</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer49"/>
+ <attributes>
+ <attribute name="text">4</attribute>
+ <attribute name="foreground-rgba">6</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlineviewpage|writerchanges-atkobject">Changes</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkTreeView" id="calcchanges">
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="search-column">0</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="Macro Library List-selection1"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn0">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="redlineviewpage|action">Action</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer0"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ <attribute name="foreground-rgba">6</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="redlineviewpage|position">Position</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer1"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ <attribute name="foreground-rgba">6</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="redlineviewpage|author">Author</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer2"/>
+ <attributes>
+ <attribute name="text">2</attribute>
+ <attribute name="foreground-rgba">6</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="redlineviewpage|date">Date</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer3"/>
+ <attributes>
+ <attribute name="text">3</attribute>
+ <attribute name="foreground-rgba">6</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn4">
+ <property name="resizable">True</property>
+ <property name="spacing">6</property>
+ <property name="title" translatable="yes" context="redlineviewpage|comment">Comment</property>
+ <property name="clickable">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderer4"/>
+ <attributes>
+ <attribute name="text">4</attribute>
+ <attribute name="foreground-rgba">6</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="redlineviewpage|calcchanges-atkobject">Changes</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButtonBox" id="button_box_1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">3</property>
+ <property name="homogeneous">True</property>
+ <property name="layout-style">start</property>
+ <child>
+ <object class="GtkButton" id="accept">
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|accept">_Accept</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="accept-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="acceptrejectchangesdialog|extended_tip|accept">Accepts the selected change and removes the highlighting from the change in the document.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="reject">
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|reject">_Reject</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="reject-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="acceptrejectchangesdialog|extended_tip|reject">Rejects the selected change and removes the highlighting from the change in the document.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="acceptall">
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|acceptall">A_ccept All</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="acceptall-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="acceptrejectchangesdialog|extended_tip|acceptall">Accepts all of the changes and removes the highlighting from the document.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="rejectall">
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|rejectall">R_eject All</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="rejectall-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="acceptrejectchangesdialog|extended_tip|rejectall">Rejects all of the changes and removes the highlighting from the document.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="undo">
+ <property name="label" translatable="yes" context="acceptrejectchangesdialog|undo">_Undo</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="no-show-all">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="undo-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="acceptrejectchangesdialog|extended_tip|undo">Reverse the last Accept or Reject command.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="RedlineViewPage-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="redlineviewpage|extended_tip|RedlineViewPage">Accept or reject individual changes.</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/rowsmenu.ui b/svx/uiconfig/ui/rowsmenu.ui
new file mode 100644
index 000000000..4e3806de0
--- /dev/null
+++ b/svx/uiconfig/ui/rowsmenu.ui
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="delete">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="rowsmenu|delete">Delete Rows</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="save">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="rowsmenu|save">Save Record</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="undo">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="rowsmenu|undo">Undo: Data entry</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/rulermenu.ui b/svx/uiconfig/ui/rulermenu.ui
new file mode 100644
index 000000000..68f7c0592
--- /dev/null
+++ b/svx/uiconfig/ui/rulermenu.ui
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkRadioMenuItem" id="mm">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|mm">Millimeter</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="cm">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|cm">Centimeter</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="m">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|m">Meter</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="km">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|km">Kilometer</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="in">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|in">Inch</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="ft">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|ft">Foot</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="mile">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|mile">Miles</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="pt">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|pt">Point</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="pc">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|pc">Pica</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="ch">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|ch">Char</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="line">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="rulermenu|line">Line</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/safemodedialog.ui b/svx/uiconfig/ui/safemodedialog.ui
new file mode 100644
index 000000000..c4ec9a37f
--- /dev/null
+++ b/svx/uiconfig/ui/safemodedialog.ui
@@ -0,0 +1,477 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="SafeModeDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="safemodedialog|SafeModeDialog">Safe Mode</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="btn_continue">
+ <property name="label" translatable="yes" context="safemodedialog|btn_continue">_Continue in Safe Mode</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="btn_restart">
+ <property name="label" translatable="yes" context="safemodedialog|btn_restart">_Restart in Normal Mode</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="btn_apply">
+ <property name="label" translatable="yes" context="safemodedialog|btn_apply">_Apply Changes and Restart</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="safemodedialog|label1">%PRODUCTNAME is now running in safe mode which temporarily disables your user configuration and extensions.
+
+You can make one or more of the following changes to your user profile to return %PRODUCTNAME to a working state.</property>
+ <property name="wrap">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkRadioButton" id="radio_restore">
+ <property name="label" translatable="yes" context="safemodedialog|radio_restore">Restore from backup</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="group_restore">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">18</property>
+ <property name="margin_bottom">6</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkCheckButton" id="check_profilesafe_config">
+ <property name="label" translatable="yes" context="safemodedialog|check_profilesafe_config">Restore user configuration to the last known working state</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="check_profilesafe_extensions">
+ <property name="label" translatable="yes" context="safemodedialog|check_profilesafe_extensions">Restore state of installed user extensions to the last known working state</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radio_configure">
+ <property name="label" translatable="yes" context="safemodedialog|radio_configure">Configure</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radio_restore</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="group_configure">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">18</property>
+ <property name="margin_bottom">6</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkCheckButton" id="check_disable_all_extensions">
+ <property name="label" translatable="yes" context="safemodedialog|check_disable_all_extensions">Disable all user extensions</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="check_disable_hw_acceleration">
+ <property name="label" translatable="yes" context="safemodedialog|check_disable_hw_acceleration">Disable hardware acceleration (OpenGL, OpenCL, Vulkan)</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radio_extensions">
+ <property name="label" translatable="yes" context="safemodedialog|radio_extensions">Extensions</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radio_restore</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="group_deinstall">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">18</property>
+ <property name="margin_bottom">6</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkCheckButton" id="check_deinstall_user_extensions">
+ <property name="label" translatable="yes" context="safemodedialog|check_deinstall_user_extensions">Uninstall all user extensions</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="check_reset_shared_extensions">
+ <property name="label" translatable="yes" context="safemodedialog|check_reset_shared_extensions">Reset state of shared extensions</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="check_reset_bundled_extensions">
+ <property name="label" translatable="yes" context="safemodedialog|check_reset_bundled_extensions">Reset state of bundled extensions</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radio_reset">
+ <property name="label" translatable="yes" context="safemodedialog|radio_reset">Reset to factory settings</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radio_restore</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="group_reset">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">18</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkCheckButton" id="check_reset_customizations">
+ <property name="label" translatable="yes" context="safemodedialog|check_reset_customizations">Reset settings and user interface modifications</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="check_reset_whole_userprofile">
+ <property name="label" translatable="yes" context="safemodedialog|check_reset_whole_userprofile">Reset entire user profile</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">7</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkExpander" id="expander1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="resize_toplevel">True</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="safemodedialog|label3">If you experience problems that are not resolved by using safe mode, visit the following link to get help or report a bug.</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLinkButton" id="linkbutton_bugs">
+ <property name="label" translatable="yes" context="safemodedialog|linkbutton_bugs">Get Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="safemodedialog|label4">You can also include relevant parts of your user profile in the bugreport (be aware it might contain personal data).</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkButton" id="btn_create_zip">
+ <property name="label" translatable="yes" context="safemodedialog|btn_create_zip">Archive User Profile</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLinkButton" id="linkbutton_profile">
+ <property name="label" translatable="yes" context="safemodedialog|linkbutton_profile">Show User Profile</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_bottom">6</property>
+ <property name="label" translatable="yes" context="safemodedialog|label2">Advanced</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/savemodifieddialog.ui b/svx/uiconfig/ui/savemodifieddialog.ui
new file mode 100644
index 000000000..51877e552
--- /dev/null
+++ b/svx/uiconfig/ui/savemodifieddialog.ui
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMessageDialog" id="SaveModifiedDialog">
+ <property name="can_focus">False</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="message_type">question</property>
+ <property name="text" translatable="yes" context="savemodifieddialog|SaveModifiedDialog">Do you want to save your changes?</property>
+ <property name="secondary_text" translatable="yes" context="savemodifieddialog|SaveModifiedDialog">The content of the current form has been modified.</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="messagedialog-vbox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="messagedialog-action_area">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="no">
+ <property name="label" translatable="yes" context="stock">_No</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="yes">
+ <property name="label" translatable="yes" context="stock">_Yes</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-9">no</action-widget>
+ <action-widget response="-8">yes</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/selectionmenu.ui b/svx/uiconfig/ui/selectionmenu.ui
new file mode 100644
index 000000000..aa0989ad2
--- /dev/null
+++ b/svx/uiconfig/ui/selectionmenu.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkRadioMenuItem" id="standard">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="selectionmenu|standard">Standard selection</property>
+ <property name="use-underline">True</property>
+ <property name="draw-as-radio">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="extending">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="selectionmenu|extending">Extending selection</property>
+ <property name="use-underline">True</property>
+ <property name="draw-as-radio">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="adding">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="selectionmenu|adding">Adding selection</property>
+ <property name="use-underline">True</property>
+ <property name="draw-as-radio">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRadioMenuItem" id="block">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="selectionmenu|block">Block selection</property>
+ <property name="use-underline">True</property>
+ <property name="draw-as-radio">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebararea.ui b/svx/uiconfig/ui/sidebararea.ui
new file mode 100644
index 000000000..ff53e9a79
--- /dev/null
+++ b/svx/uiconfig/ui/sidebararea.ui
@@ -0,0 +1,372 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">5</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">360</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkListStore" id="liststore4">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ <!-- column-name image -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name surface -->
+ <column type="CairoSurface"/>
+ </columns>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="AreaPropertyPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="row_spacing">3</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScale" id="transparencyslider">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|transparencyslider|tooltip_text">Specify 0% for fully opaque through 100% for fully transparent.</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">adjustment4</property>
+ <property name="round_digits">1</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="settransparency">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|settransparency|tooltip_text">Specify 0% for fully opaque through 100% for fully transparent.</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="settransparency-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebararea|settransparency-atkobject">Transparency</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="filllabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|filllabel|tooltip_text">Fill:</property>
+ <property name="label" translatable="yes" context="sidebararea|filllabel">_Fill:</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="fillstylearea">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|fillstylearea|tooltip_text">Select the fill type to apply.</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="fillstylearea-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebararea|fillstylearea-atkobject">Fill Type</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkComboBoxText" id="gradientstyle">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|gradientstyle|tooltip_text">Select the gradient style.</property>
+ <items>
+ <item translatable="yes" context="sidebararea|gradientstyle">Linear</item>
+ <item translatable="yes" context="sidebararea|gradientstyle">Axial</item>
+ <item translatable="yes" context="sidebararea|gradientstyle">Radial</item>
+ <item translatable="yes" context="sidebararea|gradientstyle">Ellipsoid</item>
+ <item translatable="yes" context="sidebararea|gradientstyle">Quadratic</item>
+ <item translatable="yes" context="sidebararea|gradientstyle">Square</item>
+ </items>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="gradientstyle-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebararea|gradientstyle-atkobject">Gradient Type</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="bmpimport">
+ <property name="label" translatable="yes" context="sidebararea|bmpimport">_Import</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkToolbar" id="selectcolor">
+ <property name="can_focus">True</property>
+ <property name="halign">start</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:FillColor">
+ <property name="visible">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|color|tooltip_text">Select the color to apply.</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="fillattrhb">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|fillattrhb|tooltip_text">Select the effect to apply.</property>
+ <property name="hexpand">True</property>
+ <property name="model">liststore4</property>
+ <property name="entry_text_column">0</property>
+ <property name="id_column">1</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext3"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="fillattrhb-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebararea|fillattrhb-atkobject">Hatching/Bitmap</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="fillgrad1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|fillgrad1|tooltip_text">Fill gradient from.</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="gradangle">
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|gradangle|tooltip_text">Select the gradient angle.</property>
+ <property name="valign">center</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="gradangle-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebararea|gradangle-atkobject">Gradient angle</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="fillgrad2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|fillgrad2|tooltip_text">Fill gradient to.</property>
+ <property name="valign">center</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="transparencylabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|transparencylabel|tooltip_text">Transparency</property>
+ <property name="label" translatable="yes" context="sidebararea|transparencylabel">_Transparency:</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="transtype">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|transtype|tooltip_text">Select the type of transparency to apply.</property>
+ <items>
+ <item translatable="yes" context="sidebararea|transtype">None</item>
+ <item translatable="yes" context="sidebararea|transtype">Solid</item>
+ <item translatable="yes" context="sidebararea|transtype">Linear</item>
+ <item translatable="yes" context="sidebararea|transtype">Axial</item>
+ <item translatable="yes" context="sidebararea|transtype">Radial</item>
+ <item translatable="yes" context="sidebararea|transtype">Ellipsoid</item>
+ <item translatable="yes" context="sidebararea|transtype">Quadratic</item>
+ <item translatable="yes" context="sidebararea|transtype">Square</item>
+ </items>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="transtype-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebararea|transtype-atkobject">Transparency Type</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="selectgradient">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id="sidebargradient">
+ <property name="visible">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebararea|gradient|tooltip_text">Specify the variation of gradient transparency.</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebareffect.ui b/svx/uiconfig/ui/sidebareffect.ui
new file mode 100644
index 000000000..78dbb5233
--- /dev/null
+++ b/svx/uiconfig/ui/sidebareffect.ui
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">150</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">150</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="EffectPropertyPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border_width">6</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="glowframe">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="row_spacing">3</property>
+ <property name="column_spacing">6</property>
+ <property name="margin-start">12</property>
+ <child>
+ <object class="GtkLabel" id="radiusglow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarglow|radius">Radius:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">LB_GLOW_RADIUS</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="LB_GLOW_RADIUS">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment1</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="glowcolorlabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarglow|color">Color:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">LB_GLOW_COLOR</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="LB_GLOW_COLOR">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="valign">center</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="transparency">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarglow|transparency">Transparency:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">LB_GLOW_TRANSPARENCY</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="LB_GLOW_TRANSPARENCY">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment2</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarglow|glow">Glow</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="softedgeframe">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <property name="margin-start">12</property>
+ <child>
+ <object class="GtkLabel" id="radiussoftedge">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarsoftedge|radius">Radius:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">SB_SOFTEDGE_RADIUS</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="SB_SOFTEDGE_RADIUS">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment3</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarsoftedge|softedge">Soft Edge</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroupLabel">
+ <widgets>
+ <widget name="radiusglow"/>
+ <widget name="glowcolorlabel"/>
+ <widget name="transparency"/>
+ <widget name="radiussoftedge"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebarempty.ui b/svx/uiconfig/ui/sidebarempty.ui
new file mode 100644
index 000000000..671097625
--- /dev/null
+++ b/svx/uiconfig/ui/sidebarempty.ui
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="EmptyPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="message">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes" context="sidebarempty|RID_SIDEBAR_EMPTY_PANEL_TEXT">Properties for the task that you are performing are not available for the current selection.</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">12</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="message-atkobject">
+ <property name="AtkObject::accessible-role" translatable="no">static</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebarfontwork.ui b/svx/uiconfig/ui/sidebarfontwork.ui
new file mode 100644
index 000000000..5cc80fd18
--- /dev/null
+++ b/svx/uiconfig/ui/sidebarfontwork.ui
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.4 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkGrid" id="FontworkPropertyPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_homogeneous">True</property>
+ <property name="column_homogeneous">True</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkToolbar" id="fontwork-toolbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:FontworkShapeType">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:FontworkSameLetterHeights">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:FontworkAlignmentFloater">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:FontworkCharacterSpacingFloater">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:ExtrusionToggle">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebargallery.ui b/svx/uiconfig/ui/sidebargallery.ui
new file mode 100644
index 000000000..800f42476
--- /dev/null
+++ b/svx/uiconfig/ui/sidebargallery.ui
@@ -0,0 +1,501 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/galicon.png</property>
+ </object>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/galdetail.png</property>
+ </object>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name image -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkTreeStore" id="liststore2">
+ <columns>
+ <!-- column-name image -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="GalleryPanel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border-width">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="container">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row-spacing">3</property>
+ <property name="column-spacing">6</property>
+ <child>
+ <object class="GtkPaned" id="splitter">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="wide-handle">True</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkTreeView" id="themelist">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers-visible">False</property>
+ <property name="search-column">1</property>
+ <property name="show-expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection2"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn0">
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext9"/>
+ <attributes>
+ <attribute name="pixbuf">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="themelist-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebargallery|RID_SVXSTR_GALLERYPROPS_GALTHEME">Gallery Theme</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row-spacing">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkScrolledWindow" id="galleryscroll">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="vscrollbar-policy">never</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="gallery">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkTreeView" id="gallerylist">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore2</property>
+ <property name="headers-visible">False</property>
+ <property name="reorderable">True</property>
+ <property name="search-column">1</property>
+ <property name="show-expanders">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection3"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn10">
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext19"/>
+ <attributes>
+ <attribute name="pixbuf">0</attribute>
+ </attributes>
+ </child>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext12"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="previewscroll">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">never</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="preview">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="column-spacing">3</property>
+ <child>
+ <object class="GtkToggleButton" id="icon">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebargallery|RID_SVXSTR_GALLERY_ICONVIEW">Icon View</property>
+ <property name="image">image1</property>
+ <property name="always-show-image">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="icon-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebargallery|RID_SVXSTR_GALLERY_THEMEITEMS">Theme Items</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="list">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebargallery|RID_SVXSTR_GALLERY_LISTVIEW">Detailed View</property>
+ <property name="image">image2</property>
+ <property name="always-show-image">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="list-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebargallery|RID_SVXSTR_GALLERY_THEMEITEMS">Theme Items</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label">
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">gallery</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="insert">
+ <property name="label" translatable="yes" context="sidebargallery|RID_SVXSTR_GALLERY_CREATETHEME">New...</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="can-default">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="btnMoreGalleries">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebargallery|btnMoreGalleries">Add more galleries via extension</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebargraphic.ui b/svx/uiconfig/ui/sidebargraphic.ui
new file mode 100644
index 000000000..1a8c5d6c2
--- /dev/null
+++ b/svx/uiconfig/ui/sidebargraphic.ui
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="0to100adjustment">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="gammaadjustment">
+ <property name="lower">0.01</property>
+ <property name="upper">10</property>
+ <property name="value">1</property>
+ <property name="step_increment">0.1</property>
+ <property name="page_increment">1</property>
+ </object>
+ <object class="GtkAdjustment" id="plusminus100adjustment">
+ <property name="lower">-100</property>
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="plusminus100adjustment1">
+ <property name="lower">-100</property>
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="GraphicPropertyPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">3</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="brightnesslabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebargraphic|brightnesslabel">_Brightness:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">setbrightness</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="setbrightness">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebargraphic|setbrightness|tooltip_text">Specify the luminance of the graphic.</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">plusminus100adjustment</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="setbrightness-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebargraphic|setbrightness-atkobject">Brightness</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="contrastlabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebargraphic|contrastlabel">_Contrast:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">setcontrast</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="setcontrast">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebargraphic|setcontrast|tooltip_text">Specify the degree of difference between the lightest and darkest parts of the graphic.</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">plusminus100adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="setcontrast-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebargraphic|setcontrast-atkobject">Contrast</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="colorlmodelabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebargraphic|colorlmodelabel">Color _mode:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">setcolormode</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="setcolormode">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="setcolormode-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebargraphic|setcolormode-atkobject">Color mode</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="transparencylabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebargraphic|transparencylabel">_Transparency:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">setgraphtransparency</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="setgraphtransparency">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebargraphic|setgraphtransparency|tooltip_text">Specify the percentage of transparency; 0% is fully opaque and 100% is fully transparent.</property>
+ <property name="hexpand">True</property>
+ <property name="adjustment">0to100adjustment</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="setgraphtransparency-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebargraphic|setgraphtransparency-atkobject">Transparency</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="SizegroupLabels">
+ <widgets>
+ <widget name="transparencylabel"/>
+ <widget name="contrastlabel"/>
+ <widget name="brightnesslabel"/>
+ <widget name="colorlmodelabel"/>
+ </widgets>
+ </object>
+ <object class="GtkAdjustment" id="plusminus100adjustment2">
+ <property name="lower">-100</property>
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="plusminus100adjustment3">
+ <property name="lower">-100</property>
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="plusminus100adjustment4">
+ <property name="lower">-100</property>
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebarline.ui b/svx/uiconfig/ui/sidebarline.ui
new file mode 100644
index 000000000..f128363a8
--- /dev/null
+++ b/svx/uiconfig/ui/sidebarline.ui
@@ -0,0 +1,365 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">20</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="LinePropertyPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="linelabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarline|widthlabel">_Line:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">linestyle</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="linestyle">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:LineEndStyle">
+ <property name="visible">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarline|linestyle|tooltip_text">Select the style of the arrowheads.</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:XLineStyle">
+ <property name="visible">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarline|linestyle|tooltip_text">Select the style of the line.</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="lineproperties">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="row_spacing">3</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="widthlabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarline|widthlabel">_Width:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">width</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="width">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarline|width|tooltip_text">Select the width of the line.</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id="SelectWidth">
+ <property name="visible">True</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="colorlabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarline|colorlabel">_Color:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">color</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarline|color|tooltip_text">Select the color of the line.</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:XLineColor">
+ <property name="visible">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarline|setcolor|tooltip_text">Select the color of the line.</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="translabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarline|translabel">_Transparency:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">linetransparency</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="linetransparency">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarline|linetransparency|tooltip_text">Specify the transparency of the line.</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="linetransparency-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarline|linetransparency-atkobject">Transparency</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="arrowproperties">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">3</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="cornerlabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarline|cornerlabel">_Corner style:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">edgestyle</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="edgestyle">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarline|edgestyle|tooltip_text">Select the style of the edge connections.</property>
+ <property name="hexpand">True</property>
+ <items>
+ <item translatable="yes" context="sidebarline|edgestyle">Rounded</item>
+ <item translatable="yes" context="sidebarline|edgestyle">- none -</item>
+ <item translatable="yes" context="sidebarline|edgestyle">Mitered</item>
+ <item translatable="yes" context="sidebarline|edgestyle">Beveled</item>
+ </items>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="edgestyle-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarline|edgestyle-atkobject">Corner Style</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="caplabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarline|caplabel">Ca_p style:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">linecapstyle</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="linecapstyle">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarline|linecapstyle|tooltip_text">Select the style of the line caps.</property>
+ <property name="hexpand">True</property>
+ <items>
+ <item translatable="yes" context="sidebarline|linecapstyle">Flat</item>
+ <item translatable="yes" context="sidebarline|linecapstyle">Round</item>
+ <item translatable="yes" context="sidebarline|linecapstyle">Square</item>
+ </items>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="linecapstyle-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarline|linecapstyle-atkobject">Cap Style</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkSizeGroup">
+ <widgets>
+ <widget name="width"/>
+ <widget name="color"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
+ <widgets>
+ <widget name="linelabel"/>
+ <widget name="widthlabel"/>
+ <widget name="colorlabel"/>
+ <widget name="translabel"/>
+ <widget name="cornerlabel"/>
+ <widget name="caplabel"/>
+ </widgets>
+ </object>
+ <object class="GtkListStore" id="liststore5">
+ <columns>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ <!-- column-name image -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name surface -->
+ <column type="CairoSurface"/>
+ </columns>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebarlists.ui b/svx/uiconfig/ui/sidebarlists.ui
new file mode 100644
index 000000000..277f751fa
--- /dev/null
+++ b/svx/uiconfig/ui/sidebarlists.ui
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="ListsPropertyPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="column_spacing">6</property>
+ <property name="column_homogeneous">True</property>
+ <child>
+ <object class="GtkToolbar" id="numberbullet">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarlists|numberbullet|tooltip_text">Bullets and Numbering</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:DefaultBullet">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:DefaultNumbering">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkToolbar" id="outline">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:OutlineRight">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:OutlineLeft">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:OutlineDown">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:OutlineUp">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebarparagraph.ui b/svx/uiconfig/ui/sidebarparagraph.ui
new file mode 100644
index 000000000..a638dceac
--- /dev/null
+++ b/svx/uiconfig/ui/sidebarparagraph.ui
@@ -0,0 +1,719 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">100</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="upper">100</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment5">
+ <property name="upper">100</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="ParaPropertyPanel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <!-- n-columns=2 n-rows=4 -->
+ <object class="GtkGrid" id="grid4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border-width">6</property>
+ <property name="row-spacing">3</property>
+ <property name="column-spacing">6</property>
+ <property name="column-homogeneous">True</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkToolbar" id="horizontalalignment">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|horizontalalignment|tooltip_text">Horizontal Alignment</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:LeftPara">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:CenterPara">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:RightPara">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:JustifyPara">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="writedirection">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:ParaLeftToRight">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:ParaRightToLeft">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="verticalalignment">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|verticalalignment|tooltip_text">Vertical Alignment</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:CellVertTop">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:CellVertCenter">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:CellVertBottom">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="spacinglabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes" context="sidebarparagraph|spacinglabel">_Spacing:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">paraspacing</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="paraspacing">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|paraspacing|tooltip_text">Spacing</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:ParaspaceIncrease">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:ParaspaceDecrease">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="aboveparaspacingbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="aboveparaspacingimg">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="margin-start">6</property>
+ <property name="margin-end">3</property>
+ <property name="icon-name">svx/res/symphony/spacing1.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="aboveparaspacing">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|aboveparaspacing|tooltip_text">Above Paragraph Spacing</property>
+ <property name="hexpand">True</property>
+ <property name="text">0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment1</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="aboveparaspacing-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarparagraph|aboveparaspacing-atkobject">Above Paragraph Spacing</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="belowparaspacingbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="belowparaspacingimg">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="margin-start">6</property>
+ <property name="margin-end">3</property>
+ <property name="icon-name">svx/res/symphony/spacing2.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="belowparaspacing">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|belowparaspacing|tooltip_text">Below Paragraph Spacing</property>
+ <property name="hexpand">True</property>
+ <property name="text">0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="belowparaspacing-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarparagraph|belowparaspacing-atkobject">Below Paragraph Spacing</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="linespacing">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="margin-start">3</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:LineSpacing">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|setlinespacing|tooltip_text">Line Spacing</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="indentfieldbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="indentlabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes" context="sidebarparagraph|indentlabel">_Indent:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">indent</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="indent">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|indent|tooltip_text">Indent</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:IncrementIndent">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|increaseindent|tooltip_text">Increase Indent</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:DecrementIndent">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|decreaseindent|tooltip_text">Decrease Indent</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:HangingIndent">
+ <property name="visible">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|hangingindent|tooltip_text">Switch to Hanging Indent</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="beforetextindentbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="beforetextindentimg">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="margin-start">6</property>
+ <property name="margin-end">3</property>
+ <property name="icon-name">svx/res/symphony/Indent4.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="beforetextindent">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|beforetextindent|tooltip_text">Before Text Indent</property>
+ <property name="hexpand">True</property>
+ <property name="text">0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment3</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="beforetextindent-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarparagraph|beforetextindent-atkobject">Before Text Indent</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="aftertextindentbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="aftertextindentimg">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="margin-start">6</property>
+ <property name="margin-end">3</property>
+ <property name="icon-name">svx/res/symphony/Indent3.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="aftertextindent">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|aftertextindent|tooltip_text">After Text Indent</property>
+ <property name="hexpand">True</property>
+ <property name="text">0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment4</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="aftertextindent-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarparagraph|aftertextindent-atkobject">After Text Indent</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="firstlineindentbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="firstlineindentimg">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="margin-start">6</property>
+ <property name="margin-end">3</property>
+ <property name="icon-name">svx/res/symphony/Indent2.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="firstlineindent">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|firstlineindent|tooltip_text">First Line Indent</property>
+ <property name="hexpand">True</property>
+ <property name="text">0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment5</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="firstlineindent-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarparagraph|firstlineindent-atkobject">First Line Indent</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="separator1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">3</property>
+ <property name="margin-end">3</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkToolbar" id="numberbullet">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|numberbullet|tooltip_text">Bullets and Numbering</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:DefaultBullet">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:DefaultNumbering">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:RemoveBullets">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="backgroundcolor">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarparagraph|backgroundcolor|tooltip_text">Paragraph Background Color</property>
+ <property name="halign">end</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:BackgroundColor">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="sizegroup1">
+ <property name="mode">vertical</property>
+ <widgets>
+ <widget name="aboveparaspacingbox"/>
+ <widget name="belowparaspacingbox"/>
+ <widget name="linespacing"/>
+ <widget name="beforetextindentbox"/>
+ <widget name="aftertextindentbox"/>
+ <widget name="firstlineindentbox"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebarpossize.ui b/svx/uiconfig/ui/sidebarpossize.ui
new file mode 100644
index 000000000..471d7c4a2
--- /dev/null
+++ b/svx/uiconfig/ui/sidebarpossize.ui
@@ -0,0 +1,606 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustmentPOS">
+ <property name="lower">-120</property>
+ <property name="upper">240</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustmentPOS1">
+ <property name="lower">-120</property>
+ <property name="upper">240</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustmentSIZE">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustmentSIZE1">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustmentSpinDegrees">
+ <property name="upper">359</property>
+ <property name="step_increment">5</property>
+ <property name="page_increment">10</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="PosSizePropertyPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="row_spacing">3</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="horizontallabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarpossize|horizontallabel">Position _X:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">horizontalpos</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="horizontalpos">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|horizontalpos|tooltip_text">Enter the value for the horizontal position.</property>
+ <property name="adjustment">adjustmentPOS</property>
+ <property name="digits">2</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="horizontalpos-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarpossize|horizontalpos">Horizontal</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="verticallabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarpossize|verticallabel">Position _Y:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">verticalpos</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="verticalpos">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|verticalpos|tooltip_text">Enter the value for the vertical position.</property>
+ <property name="adjustment">adjustmentPOS1</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="verticalpos-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarpossize|verticalpos">Vertical</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="widthlabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarpossize|widthlabel">_Width:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">selectwidth</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="selectwidth">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|selectwidth|tooltip_text">Enter a width for the selected object.</property>
+ <property name="adjustment">adjustmentSIZE</property>
+ <property name="digits">2</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="selectwidth-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarpossize|selectwidth">Width</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="heightlabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarpossize|heightlabel">H_eight:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">selectheight</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="selectheight">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|selectheight|tooltip_text">Enter a height for the selected object.</property>
+ <property name="adjustment">adjustmentSIZE1</property>
+ <property name="digits">2</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="selectheight-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarpossize|selectheight">Height</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="ratio">
+ <property name="label" translatable="yes" context="sidebarpossize|ratio">_Keep ratio</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|ratio|tooltip_text">Maintain proportions when you resize the selected object.</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="arrangelabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarpossize|arrangelabel">_Arrange:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">arrangetoolbar</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="arrangetools">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkToolbar" id="arrangetoolbar">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|arrangetoolbar">Arrange</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:BringToFront">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:ObjectForwardOne">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:ObjectBackOne">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:SendToBack">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="arrangetoolbar2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|arrangetoolbar">Arrange</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:SetObjectToBackground">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:SetObjectToForeground">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="fliplabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarpossize|fliplabel">_Flip:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">selectrotationtype</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="rotationlabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarpossize|rotationlabel">_Rotation:</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <accessibility>
+ <relation type="label-for" target="orientationcontrol"/>
+ <relation type="label-for" target="rotation"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">3</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkDrawingArea" id="orientationcontrol">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="tooltip_text" translatable="yes" context="rotationtabpage|CTL_ANGLE|tooltip_text">Rotation Angle</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <accessibility>
+ <relation type="labelled-by" target="rotationlabel"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="orientationcontrol-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="sidebarpossize|orientationcontrol">Rotation</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="height">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="rotation">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|rotation|tooltip_text">Select the angle for rotation.</property>
+ <property name="hexpand">True</property>
+ <property name="digits">2</property>
+ <property name="adjustment">adjustmentSpinDegrees</property>
+ <property name="wrap">True</property>
+ <property name="truncate-multiline">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="rotationlabel"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="selectrotationtype">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:FlipVertical">
+ <property name="visible">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|flipvertical|tooltip_text">Flip the selected object vertically.</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:FlipHorizontal">
+ <property name="visible">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|fliphorizontal|tooltip_text">Flip the selected object horizontally.</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">5</property>
+ <property name="height">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkButton" id="btnEditObject">
+ <property name="label" translatable="yes" context="sidebarpossize|btnEditObject">Edit Object</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">start</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">9</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="alignlabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarpossize|alignlabel">Alig_n:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">aligntoolbar</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="aligntools">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkToolbar" id="aligntoolbar">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|arrangetoolbar">Arrange</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToggleToolButton" id=".uno:ObjectAlignLeft">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id=".uno:AlignCenter">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id=".uno:ObjectAlignRight">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="aligntoolbar2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes" context="sidebarpossize|arrangetoolbar">Arrange</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:AlignUp">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:AlignMiddle">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:AlignDown">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">8</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="SizeGroupLabel">
+ <widgets>
+ <widget name="horizontallabel"/>
+ <widget name="verticallabel"/>
+ <widget name="widthlabel"/>
+ <widget name="heightlabel"/>
+ <widget name="rotationlabel"/>
+ <widget name="fliplabel"/>
+ <widget name="arrangelabel"/>
+ <widget name="alignlabel"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup" id="SizeGroupLabel1">
+ <widgets>
+ <widget name="selectwidth"/>
+ <widget name="arrangetools"/>
+ <widget name="aligntools"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebarshadow.ui b/svx/uiconfig/ui/sidebarshadow.ui
new file mode 100644
index 000000000..2d24cc541
--- /dev/null
+++ b/svx/uiconfig/ui/sidebarshadow.ui
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="lower">-180</property>
+ <property name="upper">360</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">1000</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="lower">0</property>
+ <property name="upper">150</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="ShadowPropertyPanel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="angle">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarshadow|angle">Angle:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">LB_ANGLE</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="distance">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarshadow|distance">Distance:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">LB_DISTANCE</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="LB_DISTANCE">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment3</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="color">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarshadow|color">Color:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">LB_SHADOW_COLOR</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="LB_SHADOW_COLOR">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="hexpand">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="label" translatable="no"></property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="blur_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarshadow|blur_label">Blur:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">LB_SHADOW_BLUR</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="LB_SHADOW_BLUR">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment4</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="transparency_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="sidebarshadow|transparency_label">Transparency:</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="LB_ANGLE">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkSpinButton" id="FIELD_TRANSPARENCY">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="halign">end</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment2</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScale" id="transparency_slider">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="round_digits">1</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="SHOW_SHADOW">
+ <property name="label" translatable="yes" context="sidebarshadow|SHOW_SHADOW">Enable</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebarstylespanel.ui b/svx/uiconfig/ui/sidebarstylespanel.ui
new file mode 100644
index 000000000..52626654c
--- /dev/null
+++ b/svx/uiconfig/ui/sidebarstylespanel.ui
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="SidebarStylesPanel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border-width">6</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkToolbar" id="fontstyletoolbox">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <child>
+ <object class="GtkToolItem" id=".uno:StyleApply">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkComboBoxText" id="applystyle">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="has-entry">True</property>
+ <property name="popup-fixed-width">False</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="can-focus">True</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkToolbar" id="style">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="margin-start">3</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:FormatPaintbrush">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:StyleUpdateByExample">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:StyleNewByExample">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebartextcolumnspanel.ui b/svx/uiconfig/ui/sidebartextcolumnspanel.ui
new file mode 100644
index 000000000..47d6fd097
--- /dev/null
+++ b/svx/uiconfig/ui/sidebartextcolumnspanel.ui
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustmentColNumber">
+ <property name="lower">1</property>
+ <!-- MSO has an upper limit of 16 in UI -->
+ <property name="upper">16</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustmentColSpacing">
+ <property name="lower">0</property>
+ <property name="upper">2147483647</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">10</property>
+ </object>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="TextColumnsPropertyPanel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <!-- n-columns=2 n-rows=2 -->
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border-width">6</property>
+ <property name="row-spacing">3</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="labelColNumber">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="sidebartextcolumns|labelColNumber">_Number of columns:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">FLD_COL_NUMBER</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="labelColSpacing">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="sidebartextcolumns|labelColSpacing">_Spacing:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">MTR_FLD_COL_SPACING</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="FLD_COL_NUMBER">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustmentColNumber</property>
+ <property name="value">1</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="FLD_COL_NUMBER-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="sidebartextcolumns|extended_tip|FLD_COL_NUMBER">Enter the number of columns to use for the text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="MTR_FLD_COL_SPACING">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustmentColSpacing</property>
+ <property name="digits">2</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="MTR_FLD_COL_SPACING-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="sidebartextcolumns|extended_tip|MTR_FLD_COL_SPACING">Enter the amount of space to leave between the columns.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/sidebartextpanel.ui b/svx/uiconfig/ui/sidebartextpanel.ui
new file mode 100644
index 000000000..9858195e9
--- /dev/null
+++ b/svx/uiconfig/ui/sidebartextpanel.ui
@@ -0,0 +1,428 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="SidebarTextPanel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border-width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkToolbar" id="font">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolItem" id=".uno:CharFontName">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkComboBoxText" id="fontnamecombobox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="has-entry">True</property>
+ <property name="popup-fixed-width">False</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="can-focus">True</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="fontheight">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolItem" id=".uno:FontHeight">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkComboBoxText" id="fontsizecombobox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="has-entry">True</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="can-focus">True</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkToolbar" id="fonteffects">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToggleToolButton" id=".uno:Bold">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id=".uno:Italic">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:Underline">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id=".uno:Strikeout">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id=".uno:Shadowed">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="fontadjust">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:Grow">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id=".uno:Shrink">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkToolbar" id="colorbar_writer">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:FontColor">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:BackColor">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="colorbar_others">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:Color">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="colorbar_background">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:CharBackColor">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="defaultattr">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:SetDefault">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="position">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToggleToolButton" id=".uno:SuperScript">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleToolButton" id=".uno:SubScript">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="resetattr">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id=".uno:ResetAttributes">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="spacingbar">
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkMenuToolButton" id=".uno:Spacing">
+ <property name="visible">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/stylemenu.ui b/svx/uiconfig/ui/stylemenu.ui
new file mode 100644
index 000000000..e1eb233f8
--- /dev/null
+++ b/svx/uiconfig/ui/stylemenu.ui
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="update">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="stylemenu|update">Update to Match Selection</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="edit">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="stylemenu|edit">Edit Style...</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/stylespreview.ui b/svx/uiconfig/ui/stylespreview.ui
new file mode 100644
index 000000000..45d836da0
--- /dev/null
+++ b/svx/uiconfig/ui/stylespreview.ui
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.4 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name expander -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkBox" id="ApplyStyleBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="width_request">360</property>
+ <property name="height_request">65</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">center</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">always</property>
+ <property name="shadow_type">in</property>
+ <property name="min_content_width">70</property>
+ <child>
+ <object class="GtkIconView" id="stylesview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="margin">0</property>
+ <property name="model">liststore1</property>
+ <property name="columns">3</property>
+ <property name="item_width">70</property>
+ <property name="pixbuf-column">0</property>
+ <property name="text-column">1</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/surfacewindow.ui b/svx/uiconfig/ui/surfacewindow.ui
new file mode 100644
index 000000000..d611acbc0
--- /dev/null
+++ b/svx/uiconfig/ui/surfacewindow.ui
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/plastic_16.png</property>
+ </object>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/matte_16.png</property>
+ </object>
+ <object class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/metal_16.png</property>
+ </object>
+ <object class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/wireframe_16.png</property>
+ </object>
+ <object class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">svx/res/metal_16.png</property>
+ </object>
+ <object class="GtkPopover" id="SurfaceWindow">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="wireframe">
+ <property name="label" translatable="yes" context="surfacewindow|RID_SVXSTR_WIREFRAME">_Wire Frame</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image4</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="matt">
+ <property name="label" translatable="yes" context="surfacewindow|RID_SVXSTR_MATTE">_Matt</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image2</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">wireframe</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="plastic">
+ <property name="label" translatable="yes" context="surfacewindow|RID_SVXSTR_PLASTIC">_Plastic</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image1</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">wireframe</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="metal">
+ <property name="label" translatable="yes" context="surfacewindow|RID_SVXSTR_METAL">Me_tal (ODF)</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image3</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">wireframe</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="metalMSO">
+ <property name="label" translatable="yes" context="surfacewindow|RID_SVXSTR_METALMSO">Meta_l (MS-compatible)</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">image5</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">wireframe</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/tablewindow.ui b/svx/uiconfig/ui/tablewindow.ui
new file mode 100644
index 000000000..4fe15811c
--- /dev/null
+++ b/svx/uiconfig/ui/tablewindow.ui
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkPopover" id="TableWindow">
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="border_width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkDrawingArea" id="table">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="moreoptions">
+ <property name="label" translatable="yes" context="tablewindow|moreoptions">_More Options</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="tooltip_text" translatable="yes" context="tablewindow|moreoptions|tooltip_text">More Options</property>
+ <property name="relief">none</property>
+ <property name="use_underline">True</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">8</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/textcharacterspacingcontrol.ui b/svx/uiconfig/ui/textcharacterspacingcontrol.ui
new file mode 100644
index 000000000..8f2bde950
--- /dev/null
+++ b/svx/uiconfig/ui/textcharacterspacingcontrol.ui
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="lower">-1638</property>
+ <property name="upper">1638</property>
+ <property name="step-increment">0.10</property>
+ <property name="page-increment">1</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/spacing_very_tight.png</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_115">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/spacing_tight.png</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_15">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/spacing_normal.png</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/spacing_loose.png</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/spacing_very_loose.png</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/last_custom_common.png</property>
+ <property name="icon_size">1</property>
+ </object>
+ <object class="GtkPopover" id="TextCharacterSpacingControl">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="border-width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <!-- n-columns=1 n-rows=7 -->
+ <object class="GtkGrid" id="container">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkButton" id="very_tight">
+ <property name="label" translatable="yes" context="textcharacterspacingcontrol|very_tight">Very Tight</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="image">image_spacing_1</property>
+ <property name="relief">none</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="tight">
+ <property name="label" translatable="yes" context="textcharacterspacingcontrol|tight">Tight</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="image">image_spacing_115</property>
+ <property name="relief">none</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="normal">
+ <property name="label" translatable="yes" context="textcharacterspacingcontrol|normal">Normal</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="image">image_spacing_15</property>
+ <property name="relief">none</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="loose">
+ <property name="label" translatable="yes" context="textcharacterspacingcontrol|loose">Loose</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="image">image_spacing_2</property>
+ <property name="relief">none</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="very_loose">
+ <property name="label" translatable="yes" context="textcharacterspacingcontrol|very_loose">Very Loose</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="image">image_spacing_3</property>
+ <property name="relief">none</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="last_custom">
+ <property name="label" translatable="yes" context="textcharacterspacingcontrol|last_custom">Last Custom Value</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="image">image_spacing_4</property>
+ <property name="relief">none</property>
+ <property name="use-underline">True</property>
+ <property name="xalign">0</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-top">6</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <object class="GtkSpinButton" id="kerning">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="hexpand">True</property>
+ <property name="width-chars">0</property>
+ <property name="text" translatable="yes" context="textcharacterspacingcontrol|kerning">0.0</property>
+ <property name="truncate-multiline">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="digits">1</property>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="textcharacterspacingcontrol|label2">Custom Value</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">6</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/textcontrolchardialog.ui b/svx/uiconfig/ui/textcontrolchardialog.ui
new file mode 100644
index 000000000..d43fcf617
--- /dev/null
+++ b/svx/uiconfig/ui/textcontrolchardialog.ui
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="TextControlCharacterPropertiesDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="textcontrolchardialog|TextControlCharacterPropertiesDialog">Character</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="reset">
+ <property name="label" translatable="yes" context="stock">_Reset</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="tabcontrol">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="scrollable">True</property>
+ <property name="enable_popup">True</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="font">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="textcontrolchardialog|font">Font</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="fonteffects">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="textcontrolchardialog|fonteffects">Font Effects</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="position">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="textcontrolchardialog|position">Position</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="101">reset</action-widget>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/textcontrolparadialog.ui b/svx/uiconfig/ui/textcontrolparadialog.ui
new file mode 100644
index 000000000..19fce3e43
--- /dev/null
+++ b/svx/uiconfig/ui/textcontrolparadialog.ui
@@ -0,0 +1,303 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="TextControlParagraphPropertiesDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="textcontrolparadialog|TextControlParagraphPropertiesDialog">Paragraph</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="reset">
+ <property name="label" translatable="yes" context="stock">_Reset</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label" translatable="yes" context="stock">_Help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="tabcontrol">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="scrollable">True</property>
+ <property name="enable_popup">True</property>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="labelTP_PARA_STD">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="textcontrolparadialog|labelTP_PARA_STD">Indents &amp; Spacing</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="labelTP_PARA_ALIGN">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="textcontrolparadialog|labelTP_PARA_ALIGN">Alignment</property>
+ <property name="xalign">0.5</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="labelTP_PARA_ASIAN">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="textcontrolparadialog|labelTP_PARA_ASIAN">Asian Typography</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="labelTP_TABULATOR">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="textcontrolparadialog|labelTP_TABULATOR">Tabs</property>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="101">reset</action-widget>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-11">help</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/textunderlinecontrol.ui b/svx/uiconfig/ui/textunderlinecontrol.ui
new file mode 100644
index 000000000..cc77d634d
--- /dev/null
+++ b/svx/uiconfig/ui/textunderlinecontrol.ui
@@ -0,0 +1,265 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">9999</property>
+ <property name="step-increment">1</property>
+ <property name="page-increment">1</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_1">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/line1.png</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_10">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/line10.png</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_2">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/line2.png</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/line3.png</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/line4.png</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_5">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/line5.png</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_6">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/line6.png</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_7">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/line7.png</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_8">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/line8.png</property>
+ </object>
+ <object class="GtkImage" id="image_spacing_9">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">svx/res/symphony/line9.png</property>
+ </object>
+ <object class="GtkPopover" id="TextUnderlineControl">
+ <property name="can-focus">False</property>
+ <property name="no-show-all">True</property>
+ <property name="border-width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkButton" id="none">
+ <property name="label" translatable="yes" context="textunderlinecontrol|none">(Without)</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="single">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="textunderlinecontrol|single|tooltip_text">Single</property>
+ <property name="image">image_spacing_1</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="double">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="textunderlinecontrol|double|tooltip_text">Double</property>
+ <property name="image">image_spacing_2</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="bold">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="textunderlinecontrol|bold|tooltip_text">Bold</property>
+ <property name="image">image_spacing_3</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="dot">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="textunderlinecontrol|dot|tooltip_text">Dotted</property>
+ <property name="image">image_spacing_4</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="dotbold">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="textunderlinecontrol|dotbold|tooltip_text">Dotted (Bold)</property>
+ <property name="image">image_spacing_5</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="dash">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="textunderlinecontrol|dash|tooltip_text">Dash</property>
+ <property name="image">image_spacing_6</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="dashlong">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="textunderlinecontrol|dashlong|tooltip_text">Long Dash</property>
+ <property name="image">image_spacing_7</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="dashdot">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="textunderlinecontrol|dashdot|tooltip_text">Dot Dash</property>
+ <property name="image">image_spacing_8</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="dashdotdot">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="textunderlinecontrol|dashdotdot|tooltip_text">Dot Dot Dash</property>
+ <property name="image">image_spacing_9</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">9</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="wave">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="tooltip-text" translatable="yes" context="textunderlinecontrol|wave|tooltip_text">Wave</property>
+ <property name="image">image_spacing_10</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">10</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="moreoptions">
+ <property name="label" translatable="yes" context="textunderlinecontrol|moreoptions">_More Options...</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">11</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/toolbarpopover.ui b/svx/uiconfig/ui/toolbarpopover.ui
new file mode 100644
index 000000000..2c2b811c3
--- /dev/null
+++ b/svx/uiconfig/ui/toolbarpopover.ui
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkPopover" id="ToolbarPopover">
+ <property name="no-show-all">True</property>
+ <property name="border-width">4</property>
+ <property name="constrain-to">none</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/xformspage.ui b/svx/uiconfig/ui/xformspage.ui
new file mode 100644
index 000000000..69bd495ff
--- /dev/null
+++ b/svx/uiconfig/ui/xformspage.ui
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkTreeStore" id="liststore1">
+ <columns>
+ <!-- column-name expander -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name text -->
+ <column type="gchararray"/>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkBox" id="XFormsPage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkToolbar" id="toolbar">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="toolbar_style">icons</property>
+ <property name="show_arrow">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id="additem">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="xformspage|TBI_ITEM_ADD">Add Item</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">res/tb01.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="addelement">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="xformspage|TBI_ITEM_ADD_ELEMENT">Add Element</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">res/tb02.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="addattribute">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="xformspage|TBI_ITEM_ADD_ATTRIBUTE">Add Attribute</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">res/tb03.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="edit">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="xformspage|TBI_ITEM_EDIT">Edit</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">res/tb04.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separator">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="delete">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ <property name="label" translatable="yes" context="xformspage|TBI_ITEM_REMOVE">Delete</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">res/tb05.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="toolbar-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="xformspage|extended_tip|toolbar">Specifies the data structure of the current XForms document.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="items">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="model">liststore1</property>
+ <property name="headers_visible">False</property>
+ <property name="reorderable">True</property>
+ <property name="search_column">1</property>
+ <property name="enable_tree_lines">True</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="Macro Library List-selection1"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/>
+ <attributes>
+ <attribute name="pixbuf">0</attribute>
+ </attributes>
+ </child>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/xmlsecstatmenu.ui b/svx/uiconfig/ui/xmlsecstatmenu.ui
new file mode 100644
index 000000000..5ec0e03d4
--- /dev/null
+++ b/svx/uiconfig/ui/xmlsecstatmenu.ui
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="signatures">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="xmlsecstatmenu|signatures">Digital Signatures...</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/uiconfig/ui/zoommenu.ui b/svx/uiconfig/ui/zoommenu.ui
new file mode 100644
index 000000000..f8b1a3ffc
--- /dev/null
+++ b/svx/uiconfig/ui/zoommenu.ui
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="page">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="zoommenu|page">Entire Page</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="page-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="zoommenu|extended_tip|page">Displays the entire page on your screen.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="width">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="zoommenu|width">Page Width</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="width-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="zoommenu|extended_tip|width">Displays the complete width of the document page. The top and bottom edges of the page may not be visible.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="optimal">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="zoommenu|optimal">Optimal View</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="optimal-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="zoommenu|extended_tip|optimal">Resizes the display to fit the width of the text in the document at the moment the command is started.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="50">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="zoommenu|50">50%</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="75">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="zoommenu|75">75%</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="100">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="zoommenu|100">100%</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="100-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="zoommenu|extended_tip|100">Displays the document at its actual size.</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="150">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="zoommenu|150">150%</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="200">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="zoommenu|200">200%</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/svx/util/svx.component b/svx/util/svx.component
new file mode 100644
index 000000000..c655da210
--- /dev/null
+++ b/svx/util/svx.component
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.gallery.GalleryThemeProvider"
+ constructor="com_sun_star_comp_gallery_GalleryThemeProvider_get_implementation">
+ <service name="com.sun.star.gallery.GalleryThemeProvider"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.Impl.FindbarDispatcher"
+ constructor="com_sun_star_comp_svx_Impl_FindbarDispatcher_get_implementation">
+ <service name="com.sun.star.comp.svx.FindbarDispatcher"/>
+ <service name="com.sun.star.frame.ProtocolHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.RecoveryUI"
+ constructor="com_sun_star_comp_svx_RecoveryUI_get_implementation">
+ <service name="com.sun.star.dialog.RecoveryUI"/>
+ <optional/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.CrashReportUI"
+ constructor="com_sun_star_comp_svx_CrashReportUI_get_implementation">
+ <service name="com.sun.star.dialog.CrashReportUI"/>
+ <optional/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.SafeModeUI"
+ constructor="com_sun_star_comp_svx_SafeModeUI_get_implementation">
+ <service name="com.sun.star.dialog.SafeModeUI"/>
+ </implementation>
+ <implementation name="com.sun.star.drawing.EnhancedCustomShapeEngine"
+ constructor="com_sun_star_drawing_EnhancedCustomShapeEngine_get_implementation">
+ <service name="com.sun.star.drawing.CustomShapeEngine"/>
+ </implementation>
+ <implementation name="com.sun.star.drawing.SvxShapeCollection"
+ constructor="com_sun_star_drawing_SvxShapeCollection_get_implementation">
+ <service name="com.sun.star.drawing.ShapeCollection"/>
+ </implementation>
+ <implementation name="com.sun.star.drawing.SvxUnoColorTable"
+ constructor="com_sun_star_drawing_SvxUnoColorTable_get_implementation">
+ <service name="com.sun.star.drawing.ColorTable"/>
+ </implementation>
+ <implementation name="com.sun.star.svx.DownSearchToolboxController"
+ constructor="com_sun_star_svx_DownSearchToolboxController_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.svx.FindTextToolboxController"
+ constructor="com_sun_star_svx_FindTextToolboxController_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.svx.MatchCaseToolboxController"
+ constructor="com_sun_star_svx_MatchCaseToolboxController_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.svx.SearchFormattedToolboxController"
+ constructor="com_sun_star_svx_SearchFormattedToolboxController_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.svx.FindAllToolboxController"
+ constructor="com_sun_star_svx_FindAllToolboxController_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.svx.SearchLabelToolboxController"
+ constructor="com_sun_star_svx_SearchLabelToolboxController_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.svx.FontHeightToolBoxController"
+ constructor="com_sun_star_svx_FontHeightToolBoxController_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.svx.UpSearchToolboxController"
+ constructor="com_sun_star_svx_UpSearchToolboxController_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.svx.ExitFindbarToolboxController"
+ constructor="com_sun_star_svx_ExitFindbarToolboxController_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="org.apache.openoffice.comp.svx.sidebar.PanelFactory"
+ constructor="org_apache_openoffice_comp_svx_sidebar_PanelFactory_get_implementation">
+ <service name="com.sun.star.ui.UIElementFactory"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.NumberingToolBoxControl"
+ constructor="com_sun_star_comp_svx_NumberingToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.SmartTagMenuController"
+ constructor="com_sun_star_comp_svx_SmartTagMenuController_get_implementation">
+ <service name="com.sun.star.frame.PopupMenuController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.LineSpacingToolBoxControl"
+ constructor="com_sun_star_comp_svx_LineSpacingToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.CharacterSpacingToolBoxControl"
+ constructor="com_sun_star_comp_svx_CharacterSpacingToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.TableToolBoxControl"
+ constructor="com_sun_star_comp_svx_TableToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.ColumnsToolBoxControl"
+ constructor="com_sun_star_comp_svx_ColumnsToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.UnderlineToolBoxControl"
+ constructor="com_sun_star_comp_svx_UnderlineToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.UndoRedoToolBoxControl"
+ constructor="com_sun_star_comp_svx_UndoRedoToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.CTLToolBoxControl"
+ constructor="com_sun_star_comp_svx_CTLToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.VertTextToolBoxControl"
+ constructor="com_sun_star_comp_svx_VertTextToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+</component>
diff --git a/svx/util/svx.component.crashreport b/svx/util/svx.component.crashreport
new file mode 100644
index 000000000..8eedf929c
--- /dev/null
+++ b/svx/util/svx.component.crashreport
@@ -0,0 +1,7 @@
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+com.sun.star.comp.svx.CrashReportUI
diff --git a/svx/util/svx.component.recoveryui b/svx/util/svx.component.recoveryui
new file mode 100644
index 000000000..2a3f4b0ae
--- /dev/null
+++ b/svx/util/svx.component.recoveryui
@@ -0,0 +1,7 @@
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+com.sun.star.comp.svx.RecoveryUI
diff --git a/svx/util/svxcore.component b/svx/util/svxcore.component
new file mode 100644
index 000000000..d3b0942f4
--- /dev/null
+++ b/svx/util/svxcore.component
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.Draw.GraphicExporter"
+ constructor="com_sun_star_comp_Draw_GraphicExporter_get_implementation">
+ <service name="com.sun.star.drawing.GraphicExportFilter"/>
+ <optional/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.ExtrusionDepthController"
+ constructor="com_sun_star_comp_svx_ExtrusionDepthController_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.ExtrusionDirectionController"
+ constructor="com_sun_star_comp_svx_ExtrusionDirectionControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.ExtrusionLightingController"
+ constructor="com_sun_star_comp_svx_ExtrusionLightingControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.ExtrusionSurfaceController"
+ constructor="com_sun_star_comp_svx_ExtrusionSurfaceControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.FontworkAlignmentController"
+ constructor="com_sun_star_comp_svx_FontworkAlignmentControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.FontworkCharacterSpacingController"
+ constructor="com_sun_star_comp_svx_FontworkCharacterSpacingControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.FrameToolBoxControl"
+ constructor="com_sun_star_comp_svx_FrameToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.ColorToolBoxControl"
+ constructor="com_sun_star_comp_svx_ColorToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.CurrencyToolBoxControl"
+ constructor="com_sun_star_comp_svx_CurrencyToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.FontNameToolBoxControl"
+ constructor="com_sun_star_comp_svx_FontNameToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.StyleToolBoxControl"
+ constructor="com_sun_star_comp_svx_StyleToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.LineEndToolBoxControl"
+ constructor="com_sun_star_comp_svx_LineEndToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.LineStyleToolBoxControl"
+ constructor="com_sun_star_comp_svx_LineStyleToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.Svx.GraphicExportHelper"
+ constructor="com_sun_star_comp_Svx_GraphicExportHelper_get_implementation">
+ <service name="com.sun.star.document.BinaryStreamResolver"/>
+ <service name="com.sun.star.document.GraphicStorageHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.Svx.GraphicImportHelper"
+ constructor="com_sun_star_comp_Svx_GraphicImportHelper_get_implementation">
+ <service name="com.sun.star.document.BinaryStreamResolver"/>
+ <service name="com.sun.star.document.GraphicStorageHandler"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.graphic.PrimitiveFactory2D"
+ constructor="com_sun_star_comp_graphic_PrimitiveFactory2D_get_implementation">
+ <service name="com.sun.star.graphic.PrimitiveFactory2D"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.StylesPreviewToolBoxControl"
+ constructor="com_sun_star_comp_svx_StylesPreviewToolBoxControl_get_implementation">
+ <service name="com.sun.star.frame.ToolbarController"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.svx.TextColumns"
+ constructor="com_sun_star_comp_svx_TextColumns_get_implementation">
+ <service name="com.sun.star.text.TextColumns"/>
+ </implementation>
+</component>
diff --git a/svx/util/svxcore.component.draw b/svx/util/svxcore.component.draw
new file mode 100644
index 000000000..5192ae34f
--- /dev/null
+++ b/svx/util/svxcore.component.draw
@@ -0,0 +1,7 @@
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+com.sun.star.comp.Draw.GraphicExporter
diff --git a/svx/util/textconversiondlgs.component b/svx/util/textconversiondlgs.component
new file mode 100644
index 000000000..81798f2dd
--- /dev/null
+++ b/svx/util/textconversiondlgs.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.linguistic2.ChineseTranslationDialog"
+ constructor="svx_ChineseTranslation_UnoDialog_get_implementation">
+ <service name="com.sun.star.linguistic2.ChineseTranslationDialog"/>
+ </implementation>
+</component>